diff --git a/.eslintrc.js b/.eslintrc.js index f08ba33ac91..690f443da80 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -24,16 +24,24 @@ module.exports = { }, root: true, ignorePatterns: [ - 'node_modules', - 'build', - 'dist', 'coverage', 'apps/icons/src', 'next-env.d.ts', 'doc/book', 'external-crates', 'storybook-static', - '.next', + '**/*.config.js', + '**/preprocess.mjs', + '**/storybook-static', + '**/node_modules', + 'sdk/build-scripts/src/build-package.ts', + 'sdk/build-scripts/src/build-dapp-kit.ts', + 'sdk/create-dapp/bin/index.js', + '**/build', + '**/dist/', + '**/.next/', + '**/.swc/', + '**/out/' ], rules: { 'no-case-declarations': 'off', diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index e73567a24e5..4d69f2258d4 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,5 +1,5 @@ --- -name: Report a bug in kinesis +name: Report a bug in IOTA about: Create a report to help us improve title: "" labels: c-bug diff --git a/.github/ISSUE_TEMPLATE/doc-bug.md b/.github/ISSUE_TEMPLATE/doc-bug.md index f2dd4a8ede6..2f131f323bd 100644 --- a/.github/ISSUE_TEMPLATE/doc-bug.md +++ b/.github/ISSUE_TEMPLATE/doc-bug.md @@ -1,9 +1,8 @@ --- -name: Sui doc content issue or request +name: IOTA doc content issue or request about: Creates an issue for Sui documentation -title: 'Sui doc content issue or request' +title: 'IOTA doc content issue or request' labels: doc-issue -assignees: 'ronny-mysten' --- If this is an issue with existing content, provide the URL or GitHub path to the topic. Otherwise, use **New**. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 3558019e09d..c7e658b4dde 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,5 +1,5 @@ --- -name: Request a feature for kinesis +name: Request a feature for IOTA about: Request a feature --- diff --git a/CODE_OF_CONDUCT.MD b/CODE_OF_CONDUCT.MD deleted file mode 100644 index d2f1b67a3fa..00000000000 --- a/CODE_OF_CONDUCT.MD +++ /dev/null @@ -1,26 +0,0 @@ -# Sui Code of Conduct - -Sui as an open source project encourages free discussion rooted in respect. -We endeavor to always be mindful of others' perspectives and ask all -fellow contributors to do the same. We welcome you to the Sui platform -and ask you to help us grow it with relevant, on-point contributions. - -## Our pledge - -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, caste, color, religion, or sexual -identity and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## More information - -See the central [Sui Code of Conduct](https://github.com/MystenLabs/sui/blob/main/docs/content/references/contribute/code-of-conduct.mdx) for -full details. - -Our Code of Conduct is adapted from the -[Contributor Covenant version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 209e027ef10..ab09f5a5a69 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,17 +1,13 @@ # Contributors -Thanks for considering making a contribution to the Sui network or its documentation. The Sui monorepo houses the code that powers and documents the Sui blockchain. +Thanks for considering making a contribution to the IOTA network or its documentation. The IOTA monorepo houses the code that powers and documents the IOTA ledger. -## Contribute to Sui +## Contribute to IOTA -See [Sui Environment Setup](https://github.com/MystenLabs/sui/blob/main/docs/content/guides/developer/getting-started/sui-environment.mdx) for approach to submitting code fixes and enhancements. +See [IOTA Environment Setup](https://github.com/iotaledger/iota/blob/main/docs/content/guides/developer/getting-started/iota-environment.mdx) for approach to submitting code fixes and enhancements. -If you want to contribute code that creates a feature on Sui, start with a [Sui Improvement Proposal](https://github.com/sui-foundation/sips/tree/main) before developing the logic. +Found a bug or security vulnerability? Create a [GitHub issue](https://github.com/iotaledger/iota/issues/new/choose). -Found a bug or security vulnerability? Create a [GitHub issue](https://github.com/MystenLabs/sui/issues/new/choose). +For larger documentation issues, you can [create an issue](https://github.com/iotaledger/iota/issues/new/choose) in GitHub. To fix the problem yourself, follow the [documentation contribution](./docs/content/references/contribute/contribution-process.mdx) guidelines. -Found a small error or typo in the documentation? Each page on the [sui.docs.io](https://sui.docs.io) site includes an **Edit this page** link at the bottom that you can use to edit the page in GitHub. The content is located in the docs/content directory of the Sui repo, so you can make a usual PR if you prefer. - -For larger documentation issues, you can [create an issue](https://github.com/MystenLabs/sui/issues/new/choose) in GitHub. To fix the problem yourself, follow the [documentation contribution](./docs/content/references/contribute/contribution-process.mdx) guidelines. - -Want to contribute to the Sui framework? See [CONTRIBUTING.md](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/CONTRIBUTING.md) for information related to `sui-framework` crate contributions. +Want to contribute to the IOTA framework? See [CONTRIBUTING.md](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/CONTRIBUTING.md) for information related to `iota-framework` crate contributions. diff --git a/Cargo.lock b/Cargo.lock index 7902149a4ea..278b5d336d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2638,6 +2638,7 @@ dependencies = [ "enum_dispatch", "fastcrypto", "futures", + "iota-protocol-config", "mockall", "mysten-metrics", "mysten-network", @@ -2649,7 +2650,6 @@ dependencies = [ "rstest", "serde", "shared-crypto", - "sui-protocol-config", "tap", "telemetry-subscribers", "tempfile", @@ -3317,14 +3317,14 @@ dependencies = [ "diesel", "dotenvy", "fastcrypto", + "iota-indexer", + "iota-json-rpc-types", + "iota-types", "move-bytecode-utils", "move-core-types", "once_cell", "serde", "serde_json", - "sui-indexer", - "sui-json-rpc-types", - "sui-types", "tracing", ] @@ -5764,6349 +5764,7612 @@ dependencies = [ ] [[package]] -name = "iota-crypto" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5db0e2d85e258d6d0db66f4a6bf1e8bdf5b10c3353aa87d98b168778d13fdc1" -dependencies = [ - "aead", - "aes", - "aes-gcm", - "autocfg", - "base64 0.21.2", - "blake2", - "chacha20poly1305", - "cipher", - "curve25519-dalek 3.2.0", - "digest 0.10.7", - "ed25519-zebra", - "generic-array", - "getrandom 0.2.9", - "hkdf", - "hmac 0.12.1", - "iterator-sorted", - "k256 0.13.1", - "num-traits", - "pbkdf2 0.12.1", - "rand 0.8.5", - "scrypt 0.11.0", - "serde", - "sha2 0.10.6", - "tiny-keccak", - "unicode-normalization", - "x25519-dalek", - "zeroize", -] - -[[package]] -name = "iota-sdk" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d62d16468c4bc555cac621734b5aa4fa971341f8fe3938d4481f7f394b9167" +name = "iota" +version = "1.22.0" dependencies = [ - "bech32", - "bitflags 2.4.1", - "bytemuck", - "derive_more", - "getset", - "gloo-timers 0.3.0", - "hashbrown 0.14.3", - "hex", - "iota-crypto", - "iota_stronghold", - "iterator-sorted", - "itertools 0.12.0", - "lazy_static", - "once_cell", - "packable", - "prefix-hex", - "primitive-types 0.12.2", + "anemo", + "anyhow", + "assert_cmd", + "async-recursion", + "async-trait", + "bcs", + "bip32", + "camino", + "clap", + "colored", + "const-str", + "csv", + "datatest-stable", + "expect-test", + "fastcrypto", + "fastcrypto-zkp", + "fs_extra", + "git-version", + "im", + "inquire", + "insta", + "iota-config", + "iota-execution", + "iota-genesis-builder", + "iota-json", + "iota-json-rpc-types", + "iota-keys", + "iota-macros", + "iota-move", + "iota-move-build", + "iota-protocol-config", + "iota-replay", + "iota-sdk 1.22.0", + "iota-simulator", + "iota-source-validation", + "iota-swarm", + "iota-swarm-config", + "iota-test-transaction-builder", + "iota-transaction-builder", + "iota-types", + "jemalloc-ctl", + "json_to_table", + "miette", + "move-binary-format", + "move-command-line-common", + "move-core-types", + "move-package", + "move-vm-profiler", + "msim", + "num-bigint 0.4.4", + "prometheus", "rand 0.8.5", "regex", + "reqwest", + "rusoto_core", + "rusoto_kms", + "rustyline", + "rustyline-derive", "serde", "serde_json", - "serde_repr", - "url", - "zeroize", -] - -[[package]] -name = "iota_stronghold" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04436fca4c5e566318aa3da37b97cd833d1f2f794a2fe373b05a85b68454a212" -dependencies = [ - "bincode", - "hkdf", - "iota-crypto", - "rust-argon2", - "serde", - "stronghold-derive", - "stronghold-utils", - "stronghold_engine", + "serde_yaml 0.8.26", + "shared-crypto", + "shell-words", + "shlex", + "signature 1.6.4", + "tabled", + "tap", + "telemetry-subscribers", + "tempfile", + "test-cluster", "thiserror", - "zeroize", + "tokio", + "tracing", + "unescape", ] [[package]] -name = "ipnet" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" - -[[package]] -name = "ipnetwork" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +name = "iota-adapter-latest" +version = "0.1.0" dependencies = [ + "anyhow", + "bcs", + "iota-macros", + "iota-move-natives-latest", + "iota-protocol-config", + "iota-types", + "iota-verifier-latest", + "leb128", + "move-binary-format", + "move-bytecode-utils", + "move-bytecode-verifier", + "move-core-types", + "move-package", + "move-vm-config", + "move-vm-profiler", + "move-vm-runtime", + "move-vm-types", + "parking_lot 0.12.1", "serde", + "tracing", ] [[package]] -name = "iri-string" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f0f7638c1e223529f1bfdc48c8b133b9e0b434094d1d28473161ee48b235f78" -dependencies = [ - "nom", -] - -[[package]] -name = "is-terminal" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +name = "iota-adapter-transactional-tests" +version = "0.1.0" dependencies = [ - "hermit-abi", - "io-lifetimes", - "rustix 0.37.7", - "windows-sys 0.48.0", + "datatest-stable", + "iota-transactional-test-runner", ] [[package]] -name = "is_ci" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" - -[[package]] -name = "iterator-sorted" +name = "iota-adapter-v0" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d101775d2bc8f99f4ac18bf29b9ed70c0dd138b9a1e88d7b80179470cbbe8bd2" - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ - "either", + "anyhow", + "bcs", + "iota-macros", + "iota-move-natives-v0", + "iota-protocol-config", + "iota-types", + "iota-verifier-v0", + "leb128", + "move-binary-format", + "move-bytecode-utils", + "move-bytecode-verifier-v0", + "move-core-types", + "move-package", + "move-vm-config", + "move-vm-profiler", + "move-vm-runtime-v0", + "move-vm-types", + "once_cell", + "parking_lot 0.12.1", + "serde", + "tracing", ] [[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +name = "iota-adapter-v1" +version = "0.1.0" dependencies = [ - "either", + "anyhow", + "bcs", + "iota-macros", + "iota-move-natives-v1", + "iota-protocol-config", + "iota-types", + "iota-verifier-v1", + "leb128", + "move-binary-format", + "move-bytecode-utils", + "move-bytecode-verifier-v1", + "move-core-types", + "move-package", + "move-vm-config", + "move-vm-profiler", + "move-vm-runtime-v1", + "move-vm-types", + "parking_lot 0.12.1", + "serde", + "tracing", ] [[package]] -name = "itertools" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +name = "iota-adapter-v2" +version = "0.1.0" dependencies = [ - "either", + "anyhow", + "bcs", + "iota-macros", + "iota-move-natives-v2", + "iota-protocol-config", + "iota-types", + "iota-verifier-v2", + "leb128", + "move-binary-format", + "move-bytecode-utils", + "move-bytecode-verifier-v2", + "move-core-types", + "move-package", + "move-vm-config", + "move-vm-profiler", + "move-vm-runtime-v2", + "move-vm-types", + "parking_lot 0.12.1", + "serde", + "tracing", ] [[package]] -name = "itoa" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" - -[[package]] -name = "jemalloc-ctl" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1891c671f3db85d8ea8525dd43ab147f9977041911d24a03e5a36187a7bfde9" +name = "iota-analytics-indexer" +version = "1.22.0" dependencies = [ - "jemalloc-sys", - "libc", - "paste", + "anyhow", + "arrow", + "arrow-array", + "async-trait", + "axum", + "bcs", + "byteorder", + "bytes", + "chrono", + "clap", + "csv", + "eyre", + "fastcrypto", + "gcp-bigquery-client", + "iota-analytics-indexer-derive", + "iota-config", + "iota-indexer", + "iota-json-rpc-types", + "iota-package-resolver", + "iota-rest-api", + "iota-storage", + "iota-types", + "move-binary-format", + "move-bytecode-utils", + "move-core-types", + "mysten-metrics", + "num_enum 0.6.1", + "object_store 0.7.0", + "parquet", + "prometheus", + "rocksdb", + "serde", + "serde_json", + "simulacrum", + "snowflake-api", + "strum 0.24.1", + "strum_macros 0.24.3", + "tap", + "telemetry-subscribers", + "tempfile", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "typed-store", + "typed-store-derive", + "url", ] [[package]] -name = "jemalloc-sys" -version = "0.5.2+5.3.0-patched" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134163979b6eed9564c98637b710b40979939ba351f59952708234ea11b5f3f8" +name = "iota-analytics-indexer-derive" +version = "1.22.0" dependencies = [ - "cc", - "fs_extra", - "libc", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", ] [[package]] -name = "jobserver" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +name = "iota-archival" +version = "0.1.0" dependencies = [ - "libc", + "anyhow", + "byteorder", + "bytes", + "ed25519-consensus", + "fastcrypto", + "futures", + "indicatif", + "iota-config", + "iota-macros", + "iota-simulator", + "iota-storage", + "iota-swarm-config", + "iota-types", + "more-asserts", + "move-binary-format", + "move-core-types", + "move-package", + "num_enum 0.6.1", + "object_store 0.7.0", + "prometheus", + "rand 0.8.5", + "serde", + "serde_json", + "telemetry-subscribers", + "tempfile", + "tokio", + "tracing", ] [[package]] -name = "js-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +name = "iota-authority-aggregation" +version = "0.1.0" dependencies = [ - "wasm-bindgen", + "futures", + "iota-types", + "mysten-metrics", + "tokio", + "tracing", ] [[package]] -name = "json_to_table" -version = "0.6.0" -source = "git+https://github.com/zhiburt/tabled/?rev=e449317a1c02eb6b29e409ad6617e5d9eb7b3bd4#e449317a1c02eb6b29e409ad6617e5d9eb7b3bd4" +name = "iota-aws-orchestrator" +version = "0.0.1" dependencies = [ + "async-trait", + "aws-config", + "aws-sdk-ec2", + "aws-smithy-http", + "aws-smithy-runtime-api", + "clap", + "color-eyre", + "crossterm", + "eyre", + "futures", + "iota-config", + "iota-swarm-config", + "iota-types", + "mysten-metrics", + "narwhal-config", + "prettytable-rs", + "prometheus-parse", + "reqwest", + "russh", + "russh-keys", + "serde", "serde_json", - "tabled", + "tempfile", + "thiserror", + "tokio", ] [[package]] -name = "jsonpath_lib" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaa63191d68230cccb81c5aa23abd53ed64d83337cacbb25a7b8c7979523774f" +name = "iota-benchmark" +version = "0.0.0" dependencies = [ - "log", + "anyhow", + "async-trait", + "bcs", + "clap", + "comfy-table", + "duration-str", + "fastcrypto-zkp", + "futures", + "hdrhistogram", + "indicatif", + "iota-config", + "iota-core", + "iota-framework", + "iota-framework-snapshot", + "iota-json-rpc-types", + "iota-keys", + "iota-macros", + "iota-network", + "iota-protocol-config", + "iota-sdk 1.22.0", + "iota-simulator", + "iota-storage", + "iota-swarm-config", + "iota-test-transaction-builder", + "iota-types", + "itertools 0.10.5", + "move-core-types", + "mysten-metrics", + "narwhal-node", + "prometheus", + "rand 0.8.5", + "regex", + "roaring", "serde", "serde_json", -] - -[[package]] -name = "jsonrpsee" -version = "0.16.2" -source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" -dependencies = [ - "jsonrpsee-core", - "jsonrpsee-http-client", - "jsonrpsee-proc-macros", - "jsonrpsee-server", - "jsonrpsee-types", - "jsonrpsee-ws-client", - "tracing", -] - -[[package]] -name = "jsonrpsee-client-transport" -version = "0.16.2" -source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" -dependencies = [ - "futures-util", - "http", - "jsonrpsee-core", - "jsonrpsee-types", - "pin-project", - "rustls-native-certs", - "soketto", - "thiserror", + "strum 0.24.1", + "strum_macros 0.24.3", + "sysinfo", + "telemetry-subscribers", + "test-cluster", "tokio", - "tokio-rustls 0.23.4", "tokio-util 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", "tracing", - "webpki-roots 0.22.6", + "typed-store", ] [[package]] -name = "jsonrpsee-core" -version = "0.16.2" -source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" +name = "iota-bridge" +version = "0.1.0" dependencies = [ "anyhow", - "arrayvec 0.7.2", - "async-lock", + "arc-swap", "async-trait", - "beef", - "futures-channel", - "futures-timer", - "futures-util", - "globset", - "hyper", - "jsonrpsee-types", - "parking_lot 0.12.1", + "axum", + "backoff", + "bcs", + "clap", + "const-str", + "ethers", + "eyre", + "fastcrypto", + "futures", + "git-version", + "hex-literal 0.3.4", + "iota-common", + "iota-config", + "iota-json-rpc-types", + "iota-sdk 1.22.0", + "iota-test-transaction-builder", + "iota-types", + "lru 0.10.0", + "move-core-types", + "mysten-metrics", + "num_enum 0.6.1", + "once_cell", + "prometheus", "rand 0.8.5", - "rustc-hash", + "reqwest", + "rocksdb", "serde", "serde_json", - "soketto", - "thiserror", + "serde_with", + "shared-crypto", + "tap", + "telemetry-subscribers", + "tempfile", + "test-cluster", "tokio", "tracing", + "typed-store", + "typed-store-derive", + "url", ] [[package]] -name = "jsonrpsee-http-client" -version = "0.16.2" -source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" +name = "iota-cluster-test" +version = "0.1.0" dependencies = [ + "anyhow", "async-trait", - "hyper", - "hyper-rustls 0.23.2", - "jsonrpsee-core", - "jsonrpsee-types", - "rustc-hash", - "serde", + "clap", + "derivative", + "fastcrypto", + "futures", + "iota", + "iota-config", + "iota-core", + "iota-faucet", + "iota-graphql-rpc", + "iota-indexer", + "iota-json", + "iota-json-rpc-types", + "iota-keys", + "iota-sdk 1.22.0", + "iota-swarm", + "iota-swarm-config", + "iota-test-transaction-builder", + "iota-types", + "jsonrpsee", + "move-core-types", + "prometheus", + "regex", + "reqwest", "serde_json", - "thiserror", + "shared-crypto", + "telemetry-subscribers", + "tempfile", + "test-cluster", "tokio", "tracing", + "uuid 1.2.2", ] [[package]] -name = "jsonrpsee-proc-macros" -version = "0.16.2" -source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" +name = "iota-common" +version = "0.1.0" dependencies = [ - "heck", - "proc-macro-crate", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", + "futures", + "iota-types", + "mysten-metrics", + "tokio", + "tracing", ] [[package]] -name = "jsonrpsee-server" -version = "0.16.2" -source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" +name = "iota-config" +version = "0.0.0" dependencies = [ - "futures-channel", - "futures-util", - "http", - "hyper", - "jsonrpsee-core", - "jsonrpsee-types", + "anemo", + "anyhow", + "bcs", + "clap", + "csv", + "dirs 4.0.0", + "fastcrypto", + "insta", + "iota-keys", + "iota-protocol-config", + "iota-types", + "narwhal-config", + "object_store 0.7.0", + "once_cell", + "prometheus", + "rand 0.8.5", + "reqwest", "serde", - "serde_json", - "soketto", - "tokio", - "tokio-stream", - "tokio-util 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tower", + "serde_with", + "serde_yaml 0.8.26", + "tempfile", "tracing", ] [[package]] -name = "jsonrpsee-types" -version = "0.16.2" -source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" +name = "iota-core" +version = "0.1.0" dependencies = [ + "anemo", "anyhow", - "beef", + "arc-swap", + "async-trait", + "bcs", + "bytes", + "chrono", + "clap", + "consensus-config", + "consensus-core", + "criterion", + "dashmap", + "diffy", + "either", + "enum_dispatch", + "expect-test", + "eyre", + "fastcrypto", + "fastcrypto-tbls", + "fastcrypto-zkp", + "fs_extra", + "futures", + "im", + "indexmap 2.2.6", + "iota-archival", + "iota-authority-aggregation", + "iota-config", + "iota-execution", + "iota-framework", + "iota-genesis-builder", + "iota-json-rpc-types", + "iota-macros", + "iota-move-build", + "iota-network", + "iota-protocol-config", + "iota-simulator", + "iota-storage", + "iota-swarm-config", + "iota-test-transaction-builder", + "iota-transaction-checks", + "iota-types", + "itertools 0.10.5", + "lru 0.10.0", + "mockall", + "moka", + "more-asserts", + "move-binary-format", + "move-bytecode-utils", + "move-core-types", + "move-package", + "move-symbol-pool", + "mysten-common", + "mysten-metrics", + "mysten-network", + "narwhal-config", + "narwhal-crypto", + "narwhal-executor", + "narwhal-network", + "narwhal-node", + "narwhal-test-utils", + "narwhal-types", + "narwhal-worker", + "num-bigint 0.4.4", + "num_cpus", + "object_store 0.7.0", + "once_cell", + "parking_lot 0.12.1", + "pprof", + "pretty_assertions", + "prometheus", + "rand 0.8.5", + "roaring", + "rocksdb", + "scopeguard", "serde", + "serde-reflection", "serde_json", + "serde_with", + "serde_yaml 0.8.26", + "shared-crypto", + "signature 1.6.4", + "static_assertions", + "tap", + "telemetry-subscribers", + "tempfile", + "test-cluster", + "test-fuzz", "thiserror", + "tokio", + "tokio-retry", + "tokio-stream", "tracing", + "twox-hash", + "typed-store", + "typed-store-derive", + "zeroize", ] [[package]] -name = "jsonrpsee-ws-client" -version = "0.16.2" -source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" -dependencies = [ - "http", - "jsonrpsee-client-transport", - "jsonrpsee-core", - "jsonrpsee-types", -] - -[[package]] -name = "k256" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +name = "iota-cost" +version = "0.1.0" dependencies = [ - "cfg-if", - "ecdsa 0.14.8", - "elliptic-curve 0.12.3", - "sha2 0.10.6", - "sha3 0.10.6", + "anyhow", + "bcs", + "insta", + "iota-config", + "iota-json-rpc-types", + "iota-move-build", + "iota-swarm-config", + "iota-test-transaction-builder", + "iota-types", + "move-cli", + "move-disassembler", + "serde", + "strum 0.24.1", + "strum_macros 0.24.3", + "test-cluster", + "tokio", ] [[package]] -name = "k256" -version = "0.13.1" +name = "iota-crypto" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +checksum = "a5db0e2d85e258d6d0db66f4a6bf1e8bdf5b10c3353aa87d98b168778d13fdc1" dependencies = [ - "cfg-if", - "ecdsa 0.16.6", - "elliptic-curve 0.13.4", - "once_cell", - "serdect", + "aead", + "aes", + "aes-gcm", + "autocfg", + "base64 0.21.2", + "blake2", + "chacha20poly1305", + "cipher", + "curve25519-dalek 3.2.0", + "digest 0.10.7", + "ed25519-zebra", + "generic-array", + "getrandom 0.2.9", + "hkdf", + "hmac 0.12.1", + "iterator-sorted", + "k256 0.13.1", + "num-traits", + "pbkdf2 0.12.1", + "rand 0.8.5", + "scrypt 0.11.0", + "serde", "sha2 0.10.6", - "signature 2.0.0", -] - -[[package]] -name = "keccak" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" -dependencies = [ - "cpufeatures", + "tiny-keccak", + "unicode-normalization", + "x25519-dalek", + "zeroize", ] [[package]] -name = "kqueue" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +name = "iota-data-ingestion" +version = "0.1.0" dependencies = [ - "kqueue-sys", - "libc", + "anyhow", + "async-trait", + "aws-config", + "aws-sdk-dynamodb", + "aws-sdk-s3", + "backoff", + "base64-url", + "bcs", + "byteorder", + "bytes", + "futures", + "iota-archival", + "iota-data-ingestion-core", + "iota-storage", + "iota-types", + "mysten-metrics", + "notify", + "object_store 0.7.0", + "prometheus", + "rand 0.8.5", + "serde", + "serde_json", + "serde_yaml 0.8.26", + "telemetry-subscribers", + "tempfile", + "tokio", + "tracing", + "url", ] [[package]] -name = "kqueue-sys" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +name = "iota-data-ingestion-core" +version = "0.1.0" dependencies = [ - "bitflags 1.3.2", - "libc", + "anyhow", + "async-trait", + "backoff", + "futures", + "iota-storage", + "iota-types", + "mysten-metrics", + "notify", + "object_store 0.7.0", + "prometheus", + "rand 0.8.5", + "serde", + "serde_json", + "tap", + "telemetry-subscribers", + "tempfile", + "tokio", + "tracing", + "url", ] [[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +name = "iota-e2e-tests" +version = "0.1.0" dependencies = [ - "spin 0.5.2", + "anyhow", + "assert_cmd", + "async-trait", + "bcs", + "clap", + "expect-test", + "fastcrypto", + "fastcrypto-zkp", + "fs_extra", + "futures", + "indexmap 2.2.6", + "insta", + "iota", + "iota-config", + "iota-core", + "iota-framework", + "iota-json-rpc", + "iota-json-rpc-api", + "iota-json-rpc-types", + "iota-keys", + "iota-macros", + "iota-move-build", + "iota-node", + "iota-protocol-config", + "iota-sdk 1.22.0", + "iota-simulator", + "iota-storage", + "iota-swarm", + "iota-swarm-config", + "iota-test-transaction-builder", + "iota-tool", + "iota-types", + "jsonrpsee", + "move-binary-format", + "move-core-types", + "move-package", + "mysten-metrics", + "prometheus", + "rand 0.8.5", + "serde", + "serde_json", + "shared-crypto", + "telemetry-subscribers", + "tempfile", + "test-cluster", + "tokio", + "tracing", ] [[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - -[[package]] -name = "lexical-core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46" +name = "iota-enum-compat-util" +version = "0.1.0" dependencies = [ - "lexical-parse-float", - "lexical-parse-integer", - "lexical-util", - "lexical-write-float", - "lexical-write-integer", + "serde_yaml 0.8.26", ] [[package]] -name = "lexical-parse-float" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" +name = "iota-execution" +version = "0.1.0" dependencies = [ - "lexical-parse-integer", - "lexical-util", - "static_assertions", + "cargo_metadata 0.15.4", + "iota-adapter-latest", + "iota-adapter-v0", + "iota-adapter-v1", + "iota-adapter-v2", + "iota-move-natives-latest", + "iota-move-natives-v0", + "iota-move-natives-v1", + "iota-move-natives-v2", + "iota-protocol-config", + "iota-types", + "iota-verifier-latest", + "iota-verifier-v0", + "iota-verifier-v1", + "iota-verifier-v2", + "move-binary-format", + "move-bytecode-verifier", + "move-bytecode-verifier-v0", + "move-bytecode-verifier-v1", + "move-bytecode-verifier-v2", + "move-vm-config", + "move-vm-runtime", + "move-vm-runtime-v0", + "move-vm-runtime-v1", + "move-vm-runtime-v2", + "petgraph 0.5.1", ] [[package]] -name = "lexical-parse-integer" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9" +name = "iota-execution-cut" +version = "0.1.0" dependencies = [ - "lexical-util", - "static_assertions", + "anyhow", + "clap", + "expect-test", + "tempfile", + "thiserror", + "toml 0.7.4", + "toml_edit 0.19.10", ] [[package]] -name = "lexical-util" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" +name = "iota-faucet" +version = "1.22.0" dependencies = [ - "static_assertions", + "anyhow", + "async-recursion", + "async-trait", + "axum", + "clap", + "eyre", + "futures", + "http", + "iota", + "iota-config", + "iota-json-rpc-types", + "iota-keys", + "iota-sdk 1.22.0", + "iota-types", + "mysten-metrics", + "parking_lot 0.12.1", + "prometheus", + "rocksdb", + "scopeguard", + "serde", + "shared-crypto", + "tap", + "telemetry-subscribers", + "tempfile", + "test-cluster", + "thiserror", + "tokio", + "tower", + "tower-http", + "tracing", + "ttl_cache", + "typed-store", + "typed-store-derive", + "uuid 1.2.2", ] [[package]] -name = "lexical-write-float" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862" +name = "iota-framework" +version = "0.1.0" dependencies = [ - "lexical-util", - "lexical-write-integer", - "static_assertions", + "anyhow", + "bcs", + "iota-move-build", + "iota-types", + "move-binary-format", + "move-compiler", + "move-core-types", + "move-package", + "once_cell", + "regex", + "serde", + "tracing", ] [[package]] -name = "lexical-write-integer" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446" +name = "iota-framework-snapshot" +version = "0.1.0" dependencies = [ - "lexical-util", - "static_assertions", + "anyhow", + "bcs", + "git-version", + "iota-framework", + "iota-protocol-config", + "iota-types", + "serde", + "serde_json", + "tokio", ] [[package]] -name = "libc" -version = "0.2.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" - -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +name = "iota-framework-tests" +version = "0.1.0" dependencies = [ - "cfg-if", - "winapi", + "iota-adapter-latest", + "iota-framework", + "iota-move", + "iota-move-build", + "iota-protocol-config", + "iota-types", + "iota-verifier-latest", + "move-bytecode-verifier", + "move-cli", + "move-package", + "move-unit-test", + "prometheus", ] [[package]] -name = "libm" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" - -[[package]] -name = "librocksdb-sys" -version = "0.11.0+8.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3386f101bcb4bd252d8e9d2fb41ec3b0862a15a62b478c355b2982efa469e3e" +name = "iota-genesis-builder" +version = "0.0.0" dependencies = [ - "bindgen", - "bzip2-sys", - "cc", - "glob", - "libc", - "libz-sys", - "lz4-sys", - "zstd-sys", + "anyhow", + "bcs", + "bigdecimal", + "camino", + "fastcrypto", + "fs_extra", + "hex", + "insta", + "iota-adapter-v2", + "iota-config", + "iota-execution", + "iota-framework", + "iota-framework-snapshot", + "iota-move-build", + "iota-move-natives-v2", + "iota-protocol-config", + "iota-sdk 1.1.4", + "iota-simulator", + "iota-types", + "move-binary-format", + "move-core-types", + "move-package", + "move-vm-runtime-v2", + "num-rational", + "packable", + "prometheus", + "rand 0.8.5", + "rand_pcg", + "rand_regex", + "rand_seeder", + "regex", + "schemars", + "serde", + "serde_json", + "serde_with", + "serde_yaml 0.8.26", + "shared-crypto", + "tempfile", + "thiserror", + "tracing", ] [[package]] -name = "libsodium-sys" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b779387cd56adfbc02ea4a668e704f729be8d6a6abd2c27ca5ee537849a92fd" +name = "iota-graphql-e2e-tests" +version = "0.1.0" dependencies = [ - "cc", - "libc", - "pkg-config", - "walkdir", + "datatest-stable", + "iota-graphql-rpc", + "iota-transactional-test-runner", + "msim", + "tokio", ] [[package]] -name = "libtest-mimic" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d8de370f98a6cb8a4606618e53e802f93b094ddec0f96988eaec2c27e6e9ce7" +name = "iota-graphql-rpc" +version = "2024.2.0" dependencies = [ + "anyhow", + "async-graphql", + "async-graphql-axum", + "async-graphql-value", + "async-trait", + "axum", + "bcs", + "chrono", "clap", - "termcolor", - "threadpool", -] - -[[package]] -name = "libz-sys" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", + "const-str", + "diesel", + "either", + "expect-test", + "fastcrypto", + "fastcrypto-zkp", + "futures", + "git-version", + "hex", + "http", + "hyper", + "im", + "insta", + "iota-framework", + "iota-graphql-rpc-client", + "iota-graphql-rpc-headers", + "iota-indexer", + "iota-json-rpc", + "iota-json-rpc-types", + "iota-package-resolver", + "iota-protocol-config", + "iota-rest-api", + "iota-sdk 1.22.0", + "iota-swarm-config", + "iota-types", + "lru 0.10.0", + "markdown-gen", + "move-binary-format", + "move-bytecode-utils", + "move-core-types", + "move-disassembler", + "move-ir-types", + "mysten-metrics", + "mysten-network", + "once_cell", + "prometheus", + "rand 0.8.5", + "regex", + "reqwest", + "serde", + "serde_json", + "serde_with", + "serde_yaml 0.8.26", + "serial_test", + "shared-crypto", + "similar", + "simulacrum", + "tap", + "telemetry-subscribers", + "test-cluster", + "thiserror", + "tokio", + "tokio-util 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.7.4", + "tower", + "tower-http", + "tracing", + "uuid 1.2.2", ] [[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linux-raw-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" - -[[package]] -name = "linux-raw-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" - -[[package]] -name = "linux-raw-sys" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +name = "iota-graphql-rpc-client" +version = "0.1.0" +dependencies = [ + "async-graphql", + "axum", + "hyper", + "iota-graphql-rpc-headers", + "reqwest", + "serde_json", + "thiserror", +] [[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +name = "iota-graphql-rpc-headers" +version = "0.1.0" dependencies = [ - "autocfg", - "scopeguard", + "axum", ] [[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +name = "iota-indexer" +version = "1.22.0" dependencies = [ + "anyhow", + "async-trait", + "axum", + "backoff", + "bcs", + "cached", + "chrono", + "clap", + "criterion", + "diesel", + "diesel-derive-enum", + "diesel_migrations", + "fastcrypto", + "futures", + "iota-json", + "iota-json-rpc", + "iota-json-rpc-api", + "iota-json-rpc-types", + "iota-keys", + "iota-move-build", + "iota-open-rpc", + "iota-package-resolver", + "iota-protocol-config", + "iota-rest-api", + "iota-sdk 1.22.0", + "iota-test-transaction-builder", + "iota-transaction-builder", + "iota-types", + "itertools 0.10.5", + "jsonrpsee", + "move-binary-format", + "move-bytecode-utils", + "move-core-types", + "mysten-metrics", + "ntest", + "prometheus", + "rayon", + "regex", "serde", + "serde_json", + "serde_with", + "simulacrum", + "tap", + "telemetry-subscribers", + "test-cluster", + "thiserror", + "tokio", + "tracing", + "url", ] [[package]] -name = "lru" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" +name = "iota-json" +version = "0.0.0" dependencies = [ - "hashbrown 0.12.3", + "anyhow", + "bcs", + "fastcrypto", + "iota-framework", + "iota-move-build", + "iota-types", + "move-binary-format", + "move-bytecode-utils", + "move-core-types", + "schemars", + "serde", + "serde_json", + "test-fuzz", ] [[package]] -name = "lru" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03f1160296536f10c833a82dca22267d5486734230d47bf00bf435885814ba1e" +name = "iota-json-rpc" +version = "0.0.0" dependencies = [ - "hashbrown 0.13.2", + "anyhow", + "arc-swap", + "async-trait", + "axum", + "bcs", + "cached", + "expect-test", + "eyre", + "fastcrypto", + "futures", + "hyper", + "indexmap 2.2.6", + "iota-core", + "iota-json", + "iota-json-rpc-api", + "iota-json-rpc-types", + "iota-open-rpc", + "iota-open-rpc-macros", + "iota-protocol-config", + "iota-storage", + "iota-transaction-builder", + "iota-types", + "itertools 0.10.5", + "jsonrpsee", + "mockall", + "move-binary-format", + "move-bytecode-utils", + "move-core-types", + "move-package", + "mysten-metrics", + "once_cell", + "prometheus", + "serde", + "serde_json", + "shared-crypto", + "signature 1.6.4", + "tap", + "telemetry-subscribers", + "thiserror", + "tokio", + "tower", + "tower-http", + "tracing", + "typed-store-error", ] [[package]] -name = "lz4-sys" -version = "1.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +name = "iota-json-rpc-api" +version = "0.0.0" dependencies = [ - "cc", - "libc", + "anyhow", + "fastcrypto", + "iota-json", + "iota-json-rpc-types", + "iota-open-rpc", + "iota-open-rpc-macros", + "iota-types", + "jsonrpsee", + "mysten-metrics", + "once_cell", + "prometheus", + "tap", + "tracing", ] [[package]] -name = "lz4_flex" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "912b45c753ff5f7f5208307e8ace7d2a2e30d024e26d3509f3dce546c044ce15" +name = "iota-json-rpc-tests" +version = "0.0.0" dependencies = [ - "twox-hash", + "anyhow", + "async-trait", + "bcs", + "hyper", + "iota-config", + "iota-core", + "iota-json", + "iota-json-rpc", + "iota-json-rpc-api", + "iota-json-rpc-types", + "iota-keys", + "iota-macros", + "iota-move-build", + "iota-open-rpc", + "iota-open-rpc-macros", + "iota-protocol-config", + "iota-sdk 1.22.0", + "iota-simulator", + "iota-swarm-config", + "iota-test-transaction-builder", + "iota-types", + "jsonrpsee", + "move-package", + "prometheus", + "rand 0.8.5", + "reqwest", + "telemetry-subscribers", + "test-cluster", + "tokio", + "tracing", ] [[package]] -name = "mach2" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" +name = "iota-json-rpc-types" +version = "0.0.0" dependencies = [ - "libc", + "anyhow", + "bcs", + "colored", + "enum_dispatch", + "fastcrypto", + "iota-enum-compat-util", + "iota-json", + "iota-macros", + "iota-protocol-config", + "iota-types", + "itertools 0.10.5", + "json_to_table", + "move-binary-format", + "move-bytecode-utils", + "move-core-types", + "mysten-metrics", + "schemars", + "serde", + "serde_json", + "serde_with", + "tabled", + "tracing", ] [[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - -[[package]] -name = "markdown-gen" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8034621d7f1258317ca1dfb9205e3925d27ee4aa2a46620a09c567daf0310562" - -[[package]] -name = "match_opt" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "405ba1524a1e6ae755334d6966380c60ec40157e0155f9032dd3c294b6384da9" - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +name = "iota-keys" +version = "0.0.0" dependencies = [ - "regex-automata 0.1.10", + "anyhow", + "bip32", + "fastcrypto", + "iota-types", + "rand 0.8.5", + "regex", + "serde", + "serde_json", + "shared-crypto", + "signature 1.6.4", + "slip10_ed25519", + "tempfile", + "tiny-bip39", ] [[package]] -name = "matchit" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" +name = "iota-light-client" +version = "0.0.0" +dependencies = [ + "anyhow", + "async-trait", + "bcs", + "bytes", + "clap", + "iota-config", + "iota-json", + "iota-json-rpc-types", + "iota-package-resolver", + "iota-rest-api", + "iota-sdk 1.22.0", + "iota-types", + "move-binary-format", + "move-core-types", + "serde", + "serde_json", + "serde_yaml 0.8.26", + "tokio", +] [[package]] -name = "matchit" +name = "iota-macros" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" - -[[package]] -name = "md-5" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "opaque-debug", + "futures", + "iota-proc-macros", + "once_cell", + "tracing", ] [[package]] -name = "md-5" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +name = "iota-metric-checker" +version = "0.0.0" dependencies = [ - "digest 0.10.7", + "anyhow", + "backoff", + "base64 0.21.2", + "chrono", + "clap", + "humantime", + "once_cell", + "prometheus-http-query", + "reqwest", + "serde", + "serde_yaml 0.9.21", + "strum_macros 0.24.3", + "telemetry-subscribers", + "tokio", + "tracing", ] [[package]] -name = "md5" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" - -[[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +name = "iota-move" +version = "1.22.0" +dependencies = [ + "anyhow", + "assert_cmd", + "clap", + "colored", + "const-str", + "futures", + "git-version", + "iota-core", + "iota-macros", + "iota-move-build", + "iota-move-natives-latest", + "iota-node", + "iota-protocol-config", + "iota-simulator", + "iota-types", + "jemalloc-ctl", + "jsonrpsee", + "move-binary-format", + "move-cli", + "move-compiler", + "move-disassembler", + "move-ir-types", + "move-package", + "move-prover", + "move-unit-test", + "move-vm-runtime", + "mysten-metrics", + "once_cell", + "prometheus", + "rand 0.8.5", + "serde_json", + "serde_yaml 0.8.26", + "telemetry-subscribers", + "tempfile", + "tokio", + "tracing", +] [[package]] -name = "memmap2" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" +name = "iota-move-build" +version = "1.22.0" dependencies = [ - "libc", + "anyhow", + "datatest-stable", + "fastcrypto", + "iota-protocol-config", + "iota-types", + "iota-verifier-latest", + "move-binary-format", + "move-bytecode-utils", + "move-bytecode-verifier", + "move-command-line-common", + "move-compiler", + "move-core-types", + "move-ir-types", + "move-package", + "move-symbol-pool", + "serde-reflection", + "tempfile", ] [[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +name = "iota-move-natives-latest" +version = "0.1.0" dependencies = [ - "autocfg", + "bcs", + "better_any", + "fastcrypto", + "fastcrypto-zkp", + "indexmap 2.2.6", + "iota-protocol-config", + "iota-types", + "move-binary-format", + "move-core-types", + "move-stdlib", + "move-vm-runtime", + "move-vm-types", + "smallvec", + "tracing", ] [[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +name = "iota-move-natives-v0" +version = "0.1.0" dependencies = [ - "autocfg", + "bcs", + "better_any", + "fastcrypto", + "fastcrypto-zkp", + "iota-protocol-config", + "iota-types", + "linked-hash-map", + "move-binary-format", + "move-core-types", + "move-stdlib-v0", + "move-vm-runtime-v0", + "move-vm-types", + "smallvec", + "tracing", ] [[package]] -name = "miette" -version = "7.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98a72adfa0c7ae88ba0abcbd00047a476616c66b831d628b8ac7f1e9de0cfd67" +name = "iota-move-natives-v1" +version = "0.1.0" dependencies = [ - "backtrace", - "backtrace-ext", - "miette-derive", - "owo-colors 4.0.0", - "supports-color", - "supports-hyperlinks", - "supports-unicode", - "terminal_size 0.3.0", - "textwrap", - "thiserror", - "unicode-width", + "bcs", + "better_any", + "fastcrypto", + "fastcrypto-zkp", + "iota-protocol-config", + "iota-types", + "linked-hash-map", + "move-binary-format", + "move-core-types", + "move-stdlib-v1", + "move-vm-runtime-v1", + "move-vm-types", + "smallvec", + "tracing", ] [[package]] -name = "miette-derive" -version = "7.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279def6bf114a34b3cf887489eb440d4dfcf709ab3ce9955e4a6f957ce5cce77" +name = "iota-move-natives-v2" +version = "0.1.0" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 2.0.48", + "bcs", + "better_any", + "fastcrypto", + "fastcrypto-zkp", + "indexmap 2.2.6", + "iota-protocol-config", + "iota-types", + "move-binary-format", + "move-core-types", + "move-stdlib-v2", + "move-vm-runtime-v2", + "move-vm-types", + "smallvec", + "tracing", ] [[package]] -name = "migrations_internals" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f23f71580015254b020e856feac3df5878c2c7a8812297edd6c0a485ac9dada" +name = "iota-network" +version = "0.0.0" dependencies = [ + "anemo", + "anemo-build", + "anemo-tower", + "anyhow", + "arc-swap", + "bcs", + "bytes", + "dashmap", + "ed25519-consensus", + "fastcrypto", + "fastcrypto-tbls", + "futures", + "governor", + "iota-archival", + "iota-config", + "iota-storage", + "iota-swarm-config", + "iota-types", + "mysten-metrics", + "mysten-network", + "prometheus", + "rand 0.8.5", "serde", - "toml 0.7.4", + "tap", + "telemetry-subscribers", + "tempfile", + "tokio", + "tonic 0.11.0", + "tonic-build", + "tower", + "tracing", ] [[package]] -name = "migrations_macros" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cce3325ac70e67bbab5bd837a31cae01f1a6db64e0e744a33cb03a543469ef08" +name = "iota-node" +version = "1.22.0" dependencies = [ - "migrations_internals", - "proc-macro2 1.0.78", - "quote 1.0.35", + "anemo", + "anemo-tower", + "anyhow", + "arc-swap", + "axum", + "clap", + "const-str", + "fastcrypto", + "fastcrypto-zkp", + "futures", + "git-version", + "humantime", + "iota-archival", + "iota-config", + "iota-core", + "iota-json-rpc", + "iota-json-rpc-api", + "iota-macros", + "iota-network", + "iota-protocol-config", + "iota-rest-api", + "iota-simulator", + "iota-snapshot", + "iota-storage", + "iota-telemetry", + "iota-tls", + "iota-types", + "move-vm-profiler", + "mysten-common", + "mysten-metrics", + "mysten-network", + "narwhal-network", + "narwhal-worker", + "prometheus", + "reqwest", + "serde", + "snap", + "tap", + "telemetry-subscribers", + "tokio", + "tower", + "tracing", + "typed-store", + "url", ] [[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +name = "iota-open-rpc" +version = "1.22.0" dependencies = [ - "mime", - "unicase", + "anyhow", + "bcs", + "clap", + "fastcrypto", + "iota-json", + "iota-json-rpc", + "iota-json-rpc-api", + "iota-json-rpc-types", + "iota-protocol-config", + "iota-types", + "move-core-types", + "pretty_assertions", + "rand 0.8.5", + "schemars", + "serde", + "serde_json", + "tokio", + "versions", ] [[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +name = "iota-open-rpc-macros" +version = "0.1.0" dependencies = [ - "adler", + "derive-syn-parse", + "itertools 0.10.5", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", + "unescape", ] [[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +name = "iota-oracle" +version = "1.22.0" dependencies = [ - "libc", - "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", + "anyhow", + "bcs", + "chrono", + "clap", + "dirs 4.0.0", + "iota-config", + "iota-json-rpc-types", + "iota-keys", + "iota-move-build", + "iota-sdk 1.22.0", + "iota-types", + "jsonpath_lib", + "mysten-metrics", + "once_cell", + "prometheus", + "rand 0.8.5", + "reqwest", + "serde", + "serde_json", + "shared-crypto", + "tap", + "telemetry-subscribers", + "tokio", + "tracing", ] [[package]] -name = "mockall" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" +name = "iota-package-resolver" +version = "0.1.0" dependencies = [ - "cfg-if", - "downcast", - "fragile", - "lazy_static", - "mockall_derive", - "predicates", - "predicates-tree", + "async-trait", + "bcs", + "eyre", + "hyper", + "insta", + "iota-move-build", + "iota-rest-api", + "iota-types", + "lru 0.10.0", + "move-binary-format", + "move-compiler", + "move-core-types", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", ] [[package]] -name = "mockall_derive" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" +name = "iota-proc-macros" +version = "0.7.0" dependencies = [ - "cfg-if", + "iota-enum-compat-util", + "msim-macros", "proc-macro2 1.0.78", "quote 1.0.35", - "syn 1.0.107", + "syn 2.0.48", ] [[package]] -name = "moka" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1911e88d5831f748a4097a43862d129e3c6fca831eecac9b8db6d01d93c9de2" +name = "iota-protocol-config" +version = "0.1.0" dependencies = [ - "crossbeam-channel", - "crossbeam-epoch", - "crossbeam-utils", - "once_cell", - "parking_lot 0.12.1", - "rustc_version", - "skeptic", - "smallvec", - "tagptr", - "thiserror", - "triomphe", - "uuid 1.2.2", + "clap", + "insta", + "iota-protocol-config-macros", + "schemars", + "serde", + "serde_with", + "tracing", ] [[package]] -name = "more-asserts" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" - -[[package]] -name = "move-abstract-stack" -version = "0.0.1" +name = "iota-protocol-config-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", +] [[package]] -name = "move-binary-format" -version = "0.0.3" +name = "iota-proxy" +version = "0.0.2" dependencies = [ "anyhow", - "enum-compat-util", - "move-core-types", - "move-proc-macros", - "ref-cast", + "axum", + "axum-server", + "bytes", + "clap", + "const-str", + "fastcrypto", + "git-version", + "hex", + "http-body", + "hyper", + "iota-tls", + "iota-types", + "ipnetwork", + "itertools 0.10.5", + "mime", + "multiaddr", + "mysten-metrics", + "once_cell", + "prometheus", + "prost 0.12.3", + "prost-build", + "protobuf", + "rand 0.8.5", + "reqwest", + "rustls 0.21.6", + "rustls-pemfile 1.0.2", "serde", - "variant_count", + "serde_json", + "serde_with", + "serde_yaml 0.8.26", + "snap", + "telemetry-subscribers", + "tokio", + "tower", + "tower-http", + "tracing", ] [[package]] -name = "move-borrow-graph" -version = "0.0.1" - -[[package]] -name = "move-bytecode-source-map" +name = "iota-replay" version = "0.1.0" dependencies = [ "anyhow", + "async-recursion", + "async-trait", "bcs", + "clap", + "futures", + "http", + "iota-config", + "iota-core", + "iota-execution", + "iota-framework", + "iota-json-rpc", + "iota-json-rpc-api", + "iota-json-rpc-types", + "iota-protocol-config", + "iota-sdk 1.22.0", + "iota-storage", + "iota-types", + "jsonrpsee", + "lru 0.10.0", "move-binary-format", - "move-command-line-common", + "move-bytecode-utils", "move-core-types", - "move-ir-types", - "move-symbol-pool", + "move-vm-config", + "parking_lot 0.12.1", + "prometheus", + "rand 0.8.5", "serde", + "serde_json", + "serde_with", + "serde_yaml 0.8.26", + "shared-crypto", + "shellexpand", + "similar", + "tabled", + "tempfile", + "thiserror", + "tokio", + "tracing", ] [[package]] -name = "move-bytecode-utils" +name = "iota-rest-api" version = "0.1.0" dependencies = [ "anyhow", - "move-binary-format", - "move-core-types", - "petgraph 0.5.1", - "serde-reflection", -] - + "axum", + "bcs", + "fastcrypto", + "iota-types", + "mime", + "rand 0.8.5", + "reqwest", + "serde", + "serde_json", + "serde_with", + "tap", + "thiserror", + "tokio", +] + [[package]] -name = "move-bytecode-verifier" +name = "iota-rosetta" version = "0.1.0" dependencies = [ - "move-abstract-stack", - "move-binary-format", - "move-borrow-graph", + "anyhow", + "async-trait", + "axum", + "axum-extra", + "bcs", + "clap", + "eyre", + "fastcrypto", + "futures", + "hyper", + "iota-config", + "iota-json-rpc-types", + "iota-keys", + "iota-move-build", + "iota-node", + "iota-sdk 1.22.0", + "iota-swarm-config", + "iota-types", "move-core-types", - "move-vm-config", - "petgraph 0.5.1", + "mysten-metrics", + "once_cell", + "rand 0.8.5", + "reqwest", + "serde", + "serde_json", + "shared-crypto", + "signature 1.6.4", + "strum 0.24.1", + "strum_macros 0.24.3", + "telemetry-subscribers", + "tempfile", + "test-cluster", + "thiserror", + "tokio", + "tracing", + "typed-store", ] [[package]] -name = "move-bytecode-verifier-v0" -version = "0.1.0" +name = "iota-rpc-loadgen" +version = "1.22.0" dependencies = [ - "move-abstract-stack", - "move-binary-format", - "move-borrow-graph", - "move-core-types", - "move-vm-config", - "petgraph 0.5.1", + "anyhow", + "async-trait", + "clap", + "dashmap", + "dirs 4.0.0", + "futures", + "iota-json-rpc", + "iota-json-rpc-types", + "iota-keys", + "iota-sdk 1.22.0", + "iota-types", + "itertools 0.10.5", + "serde", + "serde_json", + "shared-crypto", + "shellexpand", + "strum 0.24.1", + "strum_macros 0.24.3", + "telemetry-subscribers", + "test-cluster", + "tokio", + "tonic 0.11.0", + "tracing", ] [[package]] -name = "move-bytecode-verifier-v1" -version = "0.1.0" +name = "iota-sdk" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d62d16468c4bc555cac621734b5aa4fa971341f8fe3938d4481f7f394b9167" dependencies = [ - "move-abstract-stack", - "move-binary-format", - "move-borrow-graph", - "move-core-types", - "move-vm-config", - "petgraph 0.5.1", + "bech32", + "bitflags 2.4.1", + "bytemuck", + "derive_more", + "getset", + "gloo-timers 0.3.0", + "hashbrown 0.14.3", + "hex", + "iota-crypto", + "iota_stronghold", + "iterator-sorted", + "itertools 0.12.0", + "lazy_static", + "once_cell", + "packable", + "prefix-hex", + "primitive-types 0.12.2", + "rand 0.8.5", + "regex", + "serde", + "serde_json", + "serde_repr", + "url", + "zeroize", ] [[package]] -name = "move-bytecode-verifier-v2" -version = "0.1.0" +name = "iota-sdk" +version = "1.22.0" dependencies = [ - "move-abstract-stack", - "move-binary-format", - "move-borrow-graph", + "anyhow", + "async-recursion", + "async-trait", + "bcs", + "clap", + "colored", + "dirs 4.0.0", + "fastcrypto", + "futures", + "futures-core", + "iota-config", + "iota-json", + "iota-json-rpc-api", + "iota-json-rpc-types", + "iota-keys", + "iota-transaction-builder", + "iota-types", + "jsonrpsee", "move-core-types", - "move-vm-config", - "petgraph 0.5.1", + "rand 0.8.5", + "reqwest", + "serde", + "serde_json", + "serde_with", + "shared-crypto", + "tempfile", + "thiserror", + "tokio", + "tracing", ] [[package]] -name = "move-bytecode-viewer" -version = "0.1.0" +name = "iota-simulator" +version = "0.7.0" dependencies = [ - "anyhow", - "clap", - "crossterm", - "move-binary-format", - "move-bytecode-source-map", - "move-disassembler", - "regex", - "tui", + "anemo", + "anemo-tower", + "bcs", + "fastcrypto", + "iota-framework", + "iota-move-build", + "iota-types", + "lru 0.10.0", + "move-package", + "msim", + "narwhal-network", + "rand 0.8.5", + "serde", + "telemetry-subscribers", + "tempfile", + "tower", + "tracing", ] [[package]] -name = "move-cli" +name = "iota-single-node-benchmark" version = "0.1.0" dependencies = [ - "anyhow", + "async-trait", "bcs", "clap", - "codespan-reporting", - "colored", - "difference", + "fs_extra", + "futures", + "iota-config", + "iota-core", + "iota-macros", + "iota-move-build", + "iota-protocol-config", + "iota-simulator", + "iota-storage", + "iota-test-transaction-builder", + "iota-transaction-checks", + "iota-types", "move-binary-format", "move-bytecode-utils", - "move-bytecode-verifier", - "move-bytecode-viewer", - "move-command-line-common", - "move-compiler", "move-core-types", - "move-coverage", - "move-disassembler", - "move-docgen", - "move-errmapgen", - "move-ir-types", "move-package", - "move-prover", - "move-read-write-set-types", - "move-stdlib", - "move-unit-test", - "move-vm-profiler", - "move-vm-runtime", - "move-vm-test-utils", - "move-vm-types", - "serde_yaml 0.8.26", - "tempfile", - "toml_edit 0.14.4", - "walkdir", + "once_cell", + "prometheus", + "serde", + "serde_json", + "strum 0.24.1", + "strum_macros 0.24.3", + "telemetry-subscribers", + "tokio", + "tracing", ] [[package]] -name = "move-command-line-common" +name = "iota-snapshot" version = "0.1.0" dependencies = [ "anyhow", - "difference", - "dirs-next", - "hex", - "move-core-types", - "num-bigint 0.4.4", - "once_cell", + "bcs", + "byteorder", + "bytes", + "fastcrypto", + "futures", + "indicatif", + "integer-encoding", + "iota-config", + "iota-core", + "iota-protocol-config", + "iota-storage", + "iota-types", + "num_enum 0.6.1", + "object_store 0.7.0", + "prometheus", "serde", - "sha2 0.9.9", - "vfs", - "walkdir", + "serde_json", + "tempfile", + "tokio", + "tokio-stream", + "tracing", ] [[package]] -name = "move-compiler" -version = "0.0.1" +name = "iota-source-validation" +version = "1.22.0" dependencies = [ "anyhow", - "bcs", - "clap", - "codespan-reporting", - "dunce", - "hex", + "colored", + "expect-test", + "flate2", + "futures", + "iota-json-rpc-types", + "iota-move-build", + "iota-sdk 1.22.0", + "iota-test-transaction-builder", + "iota-types", "move-binary-format", - "move-borrow-graph", "move-bytecode-source-map", - "move-bytecode-verifier", "move-command-line-common", + "move-compiler", "move-core-types", - "move-ir-to-bytecode", - "move-ir-types", - "move-proc-macros", + "move-package", "move-symbol-pool", - "once_cell", - "pathdiff", - "petgraph 0.5.1", - "regex", - "serde", - "similar", - "stacker", + "rand 0.8.5", + "tar", "tempfile", - "vfs", + "test-cluster", + "thiserror", + "tokio", + "tracing", + "ureq", ] [[package]] -name = "move-core-types" -version = "0.0.4" +name = "iota-source-validation-service" +version = "0.1.0" dependencies = [ "anyhow", - "arbitrary", - "bcs", - "enum-compat-util", - "ethnum", - "hex", - "leb128", - "move-proc-macros", - "num", - "once_cell", - "primitive-types 0.10.1", - "proptest", - "proptest-derive", - "rand 0.8.5", - "ref-cast", + "axum", + "clap", + "const-str", + "expect-test", + "fs_extra", + "git-version", + "hyper", + "iota", + "iota-json-rpc-types", + "iota-move", + "iota-move-build", + "iota-sdk 1.22.0", + "iota-source-validation", + "jsonrpsee", + "move-compiler", + "move-core-types", + "move-package", + "move-symbol-pool", + "mysten-metrics", + "prometheus", + "reqwest", "serde", - "serde_bytes", - "thiserror", - "uint", + "telemetry-subscribers", + "tempfile", + "test-cluster", + "tokio", + "toml 0.7.4", + "tower", + "tower-http", + "tracing", + "url", ] [[package]] -name = "move-coverage" +name = "iota-storage" version = "0.1.0" dependencies = [ "anyhow", + "async-trait", + "backoff", + "base64-url", "bcs", + "byteorder", + "bytes", + "chrono", "clap", - "codespan", - "colored", + "criterion", + "eyre", + "fastcrypto", + "futures", + "hyper", + "hyper-rustls 0.24.0", + "indicatif", + "integer-encoding", + "iota-config", + "iota-json-rpc-types", + "iota-macros", + "iota-protocol-config", + "iota-simulator", + "iota-test-transaction-builder", + "iota-types", + "itertools 0.10.5", + "lru 0.10.0", "move-binary-format", - "move-bytecode-source-map", - "move-command-line-common", + "move-bytecode-utils", "move-core-types", - "move-ir-types", - "petgraph 0.5.1", + "mysten-metrics", + "num_cpus", + "num_enum 0.6.1", + "object_store 0.7.0", + "once_cell", + "parking_lot 0.12.1", + "percent-encoding", + "pretty_assertions", + "prometheus", + "reqwest", + "rocksdb", "serde", + "serde_json", + "tap", + "telemetry-subscribers", + "tempfile", + "tokio", + "tracing", + "typed-store", + "typed-store-derive", + "url", + "zstd 0.12.3+zstd.1.5.2", ] [[package]] -name = "move-disassembler" -version = "0.1.0" +name = "iota-surfer" +version = "1.22.0" dependencies = [ - "anyhow", + "async-trait", "bcs", "clap", - "colored", - "hex", + "futures", + "indexmap 2.2.6", + "iota-core", + "iota-json-rpc-types", + "iota-macros", + "iota-move-build", + "iota-protocol-config", + "iota-simulator", + "iota-swarm-config", + "iota-types", "move-binary-format", - "move-bytecode-source-map", - "move-command-line-common", - "move-compiler", "move-core-types", - "move-coverage", - "move-ir-types", + "move-package", + "prometheus", + "rand 0.8.5", + "telemetry-subscribers", + "test-cluster", + "tokio", + "tracing", ] [[package]] -name = "move-docgen" -version = "0.1.0" +name = "iota-swarm" +version = "0.0.0" dependencies = [ "anyhow", - "codespan", - "codespan-reporting", - "itertools 0.10.5", - "log", - "move-compiler", - "move-model", - "num", - "once_cell", - "regex", - "serde", + "futures", + "iota-config", + "iota-macros", + "iota-node", + "iota-protocol-config", + "iota-simulator", + "iota-swarm-config", + "iota-types", + "mysten-metrics", + "mysten-network", + "prometheus", + "rand 0.8.5", + "tap", + "telemetry-subscribers", + "tempfile", + "tokio", + "tonic-health", + "tracing", ] [[package]] -name = "move-errmapgen" -version = "0.1.0" +name = "iota-swarm-config" +version = "0.0.0" dependencies = [ + "anemo", "anyhow", - "move-command-line-common", - "move-core-types", - "move-model", + "fastcrypto", + "insta", + "iota-config", + "iota-execution", + "iota-genesis-builder", + "iota-macros", + "iota-protocol-config", + "iota-simulator", + "iota-types", + "move-bytecode-utils", + "narwhal-config", + "prometheus", + "rand 0.8.5", "serde", + "serde_with", + "serde_yaml 0.8.26", + "shared-crypto", + "tempfile", + "tracing", ] [[package]] -name = "move-ir-compiler" +name = "iota-telemetry" version = "0.1.0" dependencies = [ - "anyhow", - "bcs", - "clap", - "move-binary-format", - "move-bytecode-source-map", - "move-bytecode-verifier", - "move-command-line-common", - "move-ir-to-bytecode", - "serde_json", + "iota-core", + "reqwest", + "serde", + "tracing", ] [[package]] -name = "move-ir-to-bytecode" +name = "iota-test-transaction-builder" version = "0.1.0" dependencies = [ - "anyhow", - "codespan-reporting", - "log", - "move-binary-format", - "move-bytecode-source-map", - "move-command-line-common", + "bcs", + "iota-genesis-builder", + "iota-move-build", + "iota-sdk 1.22.0", + "iota-types", "move-core-types", - "move-ir-to-bytecode-syntax", - "move-ir-types", - "move-symbol-pool", - "ouroboros", + "shared-crypto", ] [[package]] -name = "move-ir-to-bytecode-syntax" -version = "0.1.0" +name = "iota-test-validator" +version = "0.0.0" dependencies = [ "anyhow", - "hex", - "move-command-line-common", - "move-core-types", - "move-ir-types", - "move-symbol-pool", -] - -[[package]] -name = "move-ir-types" -version = "0.1.0" -dependencies = [ - "hex", - "move-command-line-common", - "move-core-types", - "move-symbol-pool", - "once_cell", - "serde", + "axum", + "clap", + "http", + "iota-cluster-test", + "iota-faucet", + "telemetry-subscribers", + "tokio", + "tower", + "tower-http", + "uuid 1.2.2", ] [[package]] -name = "move-model" -version = "0.1.0" +name = "iota-tls" +version = "0.0.0" dependencies = [ "anyhow", - "codespan", - "codespan-reporting", - "internment", - "itertools 0.10.5", - "log", - "move-binary-format", - "move-bytecode-source-map", - "move-command-line-common", - "move-compiler", - "move-core-types", - "move-disassembler", - "move-ir-types", - "move-symbol-pool", - "num", - "once_cell", - "regex", - "serde", + "axum", + "axum-server", + "ed25519 1.5.3", + "fastcrypto", + "pkcs8 0.9.0", + "rand 0.8.5", + "rcgen", + "reqwest", + "rustls 0.21.6", + "rustls-webpki 0.101.7", + "tokio", + "tokio-rustls 0.24.0", + "tower-layer", + "x509-parser", ] [[package]] -name = "move-package" -version = "0.1.0" +name = "iota-tool" +version = "1.22.0" dependencies = [ + "anemo", + "anemo-cli", "anyhow", + "bcs", "clap", "colored", - "itertools 0.10.5", - "move-binary-format", - "move-bytecode-source-map", - "move-bytecode-utils", - "move-command-line-common", - "move-compiler", + "comfy-table", + "const-str", + "diesel", + "eyre", + "fastcrypto", + "futures", + "git-version", + "hex", + "indicatif", + "iota-archival", + "iota-config", + "iota-core", + "iota-indexer", + "iota-network", + "iota-protocol-config", + "iota-replay", + "iota-sdk 1.22.0", + "iota-snapshot", + "iota-storage", + "iota-types", + "itertools 0.10.5", "move-core-types", - "move-docgen", - "move-model", - "move-symbol-pool", - "named-lock", - "once_cell", - "petgraph 0.5.1", - "regex", + "narwhal-storage", + "narwhal-types", + "num_cpus", + "object_store 0.7.0", + "prometheus", + "rocksdb", + "ron", "serde", - "serde_yaml 0.8.26", - "sha2 0.9.9", + "serde_json", + "strum 0.24.1", + "strum_macros 0.24.3", + "telemetry-subscribers", "tempfile", - "toml 0.5.10", - "toml_edit 0.14.4", - "treeline", - "walkdir", - "whoami", + "tokio", + "tracing", + "typed-store", ] [[package]] -name = "move-proc-macros" -version = "0.1.0" +name = "iota-transaction-builder" +version = "0.0.0" dependencies = [ - "enum-compat-util", - "quote 1.0.35", - "syn 2.0.48", + "anyhow", + "async-trait", + "bcs", + "futures", + "iota-json", + "iota-json-rpc-types", + "iota-protocol-config", + "iota-types", + "move-binary-format", + "move-core-types", ] [[package]] -name = "move-prover" +name = "iota-transaction-checks" version = "0.1.0" dependencies = [ - "anyhow", - "clap", - "codespan-reporting", - "itertools 0.10.5", - "log", - "move-command-line-common", - "move-compiler", - "move-docgen", - "move-errmapgen", - "move-model", - "move-stackless-bytecode", + "fastcrypto-zkp", + "iota-config", + "iota-execution", + "iota-macros", + "iota-protocol-config", + "iota-types", "once_cell", - "serde", - "simplelog", - "toml 0.5.10", + "tracing", ] [[package]] -name = "move-read-write-set-types" -version = "0.0.3" +name = "iota-transactional-test-runner" +version = "0.1.0" dependencies = [ + "anyhow", + "async-trait", + "bcs", + "bimap", + "clap", + "criterion", + "eyre", + "fastcrypto", + "futures", + "iota-config", + "iota-core", + "iota-framework", + "iota-framework-snapshot", + "iota-graphql-rpc", + "iota-json-rpc", + "iota-json-rpc-api", + "iota-json-rpc-types", + "iota-protocol-config", + "iota-rest-api", + "iota-storage", + "iota-swarm-config", + "iota-types", "move-binary-format", + "move-bytecode-utils", + "move-command-line-common", + "move-compiler", "move-core-types", - "serde", + "move-stdlib", + "move-symbol-pool", + "move-transactional-test-runner", + "move-vm-runtime", + "msim", + "once_cell", + "rand 0.8.5", + "regex", + "rocksdb", + "serde_json", + "simulacrum", + "telemetry-subscribers", + "tempfile", + "tokio", + "typed-store", + "typed-store-derive", ] [[package]] -name = "move-stackless-bytecode" +name = "iota-types" version = "0.1.0" dependencies = [ - "codespan", - "codespan-reporting", - "ethnum", + "anemo", + "anyhow", + "bcs", + "bincode", + "byteorder", + "consensus-config", + "criterion", + "derivative", + "derive_more", + "enum_dispatch", + "expect-test", + "eyre", + "fastcrypto", + "fastcrypto-tbls", + "fastcrypto-zkp", "im", + "indexmap 2.2.6", + "iota-enum-compat-util", + "iota-macros", + "iota-protocol-config", "itertools 0.10.5", - "log", "move-binary-format", + "move-bytecode-utils", "move-command-line-common", - "move-compiler", "move-core-types", - "move-model", - "move-read-write-set-types", - "num", - "paste", - "petgraph 0.5.1", + "move-disassembler", + "move-ir-types", + "move-vm-profiler", + "move-vm-test-utils", + "move-vm-types", + "mysten-metrics", + "mysten-network", + "narwhal-config", + "narwhal-crypto", + "nonempty", + "num-bigint 0.4.4", + "num-traits", + "once_cell", + "prometheus", + "proptest", + "proptest-derive", + "rand 0.8.5", + "roaring", + "schemars", "serde", + "serde-name", + "serde_json", + "serde_with", + "serde_yaml 0.8.26", + "shared-crypto", + "signature 1.6.4", + "static_assertions", + "strum 0.24.1", + "strum_macros 0.24.3", + "tap", + "thiserror", + "tonic 0.11.0", + "tracing", + "typed-store-error", ] [[package]] -name = "move-stackless-bytecode-interpreter" +name = "iota-upgrade-compatibility-transactional-tests" version = "0.1.0" dependencies = [ "anyhow", - "bytecode-interpreter-crypto", - "clap", - "codespan-reporting", - "itertools 0.10.5", + "datatest-stable", + "insta", + "iota-move-build", "move-binary-format", - "move-core-types", - "move-model", - "move-stackless-bytecode", - "num", + "move-command-line-common", + "move-compiler", + "move-package", ] [[package]] -name = "move-stdlib" -version = "0.1.1" +name = "iota-verifier-latest" +version = "0.1.0" dependencies = [ - "anyhow", - "hex", - "log", + "iota-protocol-config", + "iota-types", + "move-abstract-stack", "move-binary-format", - "move-command-line-common", + "move-bytecode-utils", + "move-bytecode-verifier", "move-core-types", - "move-docgen", - "move-errmapgen", - "move-prover", - "move-vm-runtime", - "move-vm-types", - "sha2 0.9.9", - "sha3 0.9.1", - "smallvec", - "walkdir", + "move-vm-config", ] [[package]] -name = "move-stdlib-v0" -version = "0.1.1" +name = "iota-verifier-transactional-tests" +version = "0.1.0" dependencies = [ - "anyhow", - "hex", - "log", - "move-binary-format", - "move-command-line-common", - "move-core-types", - "move-docgen", - "move-errmapgen", - "move-prover", - "move-vm-runtime-v0", - "move-vm-types", - "sha2 0.9.9", - "sha3 0.9.1", - "smallvec", - "walkdir", + "datatest-stable", + "iota-transactional-test-runner", ] [[package]] -name = "move-stdlib-v1" -version = "0.1.1" +name = "iota-verifier-v0" +version = "0.1.0" dependencies = [ - "anyhow", - "hex", - "log", + "iota-protocol-config", + "iota-types", + "move-abstract-stack", "move-binary-format", - "move-command-line-common", + "move-bytecode-utils", + "move-bytecode-verifier-v0", "move-core-types", - "move-docgen", - "move-errmapgen", - "move-prover", - "move-vm-runtime-v1", - "move-vm-types", - "sha2 0.9.9", - "sha3 0.9.1", - "smallvec", - "walkdir", + "move-vm-config", ] [[package]] -name = "move-stdlib-v2" -version = "0.1.1" +name = "iota-verifier-v1" +version = "0.1.0" dependencies = [ - "anyhow", - "hex", - "log", + "iota-types", + "move-abstract-stack", "move-binary-format", - "move-command-line-common", + "move-bytecode-utils", + "move-bytecode-verifier-v1", "move-core-types", - "move-docgen", - "move-errmapgen", - "move-prover", - "move-vm-runtime-v2", - "move-vm-types", - "sha2 0.9.9", - "sha3 0.9.1", - "smallvec", - "walkdir", + "move-vm-config", ] [[package]] -name = "move-symbol-pool" +name = "iota-verifier-v2" version = "0.1.0" dependencies = [ - "once_cell", - "phf", + "iota-protocol-config", + "iota-types", + "move-abstract-stack", + "move-binary-format", + "move-bytecode-utils", + "move-bytecode-verifier-v2", + "move-core-types", + "move-vm-config", +] + +[[package]] +name = "iota_stronghold" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04436fca4c5e566318aa3da37b97cd833d1f2f794a2fe373b05a85b68454a212" +dependencies = [ + "bincode", + "hkdf", + "iota-crypto", + "rust-argon2", "serde", + "stronghold-derive", + "stronghold-utils", + "stronghold_engine", + "thiserror", + "zeroize", ] [[package]] -name = "move-transactional-test-runner" +name = "iotans-indexer" version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "clap", - "move-binary-format", - "move-bytecode-source-map", - "move-cli", - "move-command-line-common", - "move-compiler", + "backoff", + "base64-url", + "bcs", + "bytes", + "diesel", + "dotenvy", + "futures", + "iota-data-ingestion-core", + "iota-json-rpc", + "iota-storage", + "iota-types", "move-core-types", - "move-disassembler", - "move-ir-compiler", - "move-ir-types", - "move-stdlib", - "move-symbol-pool", - "move-vm-config", - "move-vm-runtime", - "move-vm-test-utils", - "move-vm-types", - "once_cell", - "rayon", - "regex", + "mysten-metrics", + "notify", + "object_store 0.7.0", + "prometheus", + "rand 0.8.5", + "serde", + "serde_json", + "serde_yaml 0.8.26", + "telemetry-subscribers", "tempfile", "tokio", + "tracing", + "url", ] [[package]] -name = "move-unit-test" -version = "0.1.0" +name = "iotaop-cli" +version = "0.1.9" dependencies = [ "anyhow", - "bcs", - "better_any", + "chrono", "clap", - "codespan-reporting", "colored", - "itertools 0.10.5", - "move-binary-format", - "move-bytecode-utils", - "move-command-line-common", - "move-compiler", - "move-core-types", - "move-ir-types", - "move-model", - "move-stackless-bytecode-interpreter", - "move-stdlib", - "move-symbol-pool", - "move-vm-profiler", - "move-vm-runtime", - "move-vm-test-utils", - "move-vm-types", - "once_cell", - "rayon", + "docker-api", + "field_names", + "include_dir", + "inquire", + "prettytable-rs", "regex", + "reqwest", + "semver 1.0.16", + "serde", + "serde_json", + "serde_yaml 0.8.26", + "spinners", + "strum 0.24.1", + "tempfile", + "tokio", + "toml_edit 0.19.10", + "tracing", + "tracing-subscriber", ] [[package]] -name = "move-vm-config" -version = "0.1.0" -dependencies = [ - "move-binary-format", - "once_cell", -] +name = "ipnet" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] -name = "move-vm-profiler" -version = "0.1.0" +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" dependencies = [ - "move-vm-config", - "once_cell", "serde", - "serde_json", - "tracing", ] [[package]] -name = "move-vm-runtime" -version = "0.1.0" +name = "iri-string" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0f7638c1e223529f1bfdc48c8b133b9e0b434094d1d28473161ee48b235f78" dependencies = [ - "better_any", - "fail", - "move-binary-format", - "move-bytecode-verifier", - "move-core-types", - "move-vm-config", - "move-vm-profiler", - "move-vm-types", - "once_cell", - "parking_lot 0.11.2", - "sha3 0.9.1", - "smallvec", - "tracing", + "nom", ] [[package]] -name = "move-vm-runtime-v0" -version = "0.1.0" +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ - "better_any", - "fail", - "move-binary-format", - "move-bytecode-verifier-v0", - "move-core-types", - "move-vm-config", - "move-vm-profiler", - "move-vm-types", - "once_cell", - "parking_lot 0.11.2", - "sha3 0.9.1", - "smallvec", - "tracing", + "hermit-abi", + "io-lifetimes", + "rustix 0.37.7", + "windows-sys 0.48.0", ] [[package]] -name = "move-vm-runtime-v1" +name = "is_ci" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" + +[[package]] +name = "iterator-sorted" version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d101775d2bc8f99f4ac18bf29b9ed70c0dd138b9a1e88d7b80179470cbbe8bd2" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ - "better_any", - "fail", - "move-binary-format", - "move-bytecode-verifier-v1", - "move-core-types", - "move-vm-config", - "move-vm-profiler", - "move-vm-types", - "once_cell", - "parking_lot 0.11.2", - "sha3 0.9.1", - "smallvec", - "tracing", + "either", ] [[package]] -name = "move-vm-runtime-v2" -version = "0.1.0" +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ - "better_any", - "fail", - "move-binary-format", - "move-bytecode-verifier-v2", - "move-core-types", - "move-vm-config", - "move-vm-profiler", - "move-vm-types", - "once_cell", - "parking_lot 0.11.2", - "sha3 0.9.1", - "smallvec", - "tracing", + "either", ] [[package]] -name = "move-vm-test-utils" -version = "0.1.0" +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" dependencies = [ - "anyhow", - "move-binary-format", - "move-core-types", - "move-vm-profiler", - "move-vm-types", - "once_cell", - "serde", + "either", ] [[package]] -name = "move-vm-types" -version = "0.1.0" +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] +name = "jemalloc-ctl" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1891c671f3db85d8ea8525dd43ab147f9977041911d24a03e5a36187a7bfde9" dependencies = [ - "bcs", - "move-binary-format", - "move-core-types", - "move-vm-profiler", - "serde", - "smallvec", + "jemalloc-sys", + "libc", + "paste", ] [[package]] -name = "msim" -version = "0.1.0" -source = "git+https://github.com/MystenLabs/mysten-sim.git?rev=6f88ec84644cb1a6809c010f1f534d0d09e0cd89#6f88ec84644cb1a6809c010f1f534d0d09e0cd89" -dependencies = [ - "ahash 0.7.6", - "async-task", - "bincode", - "bytes", +name = "jemalloc-sys" +version = "0.5.2+5.3.0-patched" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134163979b6eed9564c98637b710b40979939ba351f59952708234ea11b5f3f8" +dependencies = [ "cc", - "downcast-rs", - "erasable", - "futures", - "lazy_static", + "fs_extra", "libc", - "msim-macros", - "naive-timer", - "pin-project-lite", - "rand 0.8.5", - "real_tokio", - "serde", - "socket2 0.4.9", - "tap", - "tokio-util 0.7.10 (git+https://github.com/mystenmark/tokio-madsim-fork.git?rev=e47aafebf98e9c1734a8848a1876d5946c44bdd1)", - "toml 0.5.10", - "tracing", - "tracing-subscriber", ] [[package]] -name = "msim-macros" -version = "0.1.0" -source = "git+https://github.com/MystenLabs/mysten-sim.git?rev=6f88ec84644cb1a6809c010f1f534d0d09e0cd89#6f88ec84644cb1a6809c010f1f534d0d09e0cd89" +name = "jobserver" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" dependencies = [ - "darling 0.14.2", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", + "libc", ] [[package]] -name = "multer" -version = "2.1.0" +name = "js-sys" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http", - "httparse", - "log", - "memchr", - "mime", - "spin 0.9.8", - "version_check", + "wasm-bindgen", ] [[package]] -name = "multiaddr" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b53e0cc5907a5c216ba6584bf74be8ab47d6d6289f72793b2dddbf15dc3bf8c" +name = "json_to_table" +version = "0.6.0" +source = "git+https://github.com/zhiburt/tabled/?rev=e449317a1c02eb6b29e409ad6617e5d9eb7b3bd4#e449317a1c02eb6b29e409ad6617e5d9eb7b3bd4" dependencies = [ - "arrayref", - "byteorder", - "data-encoding", - "multibase", - "multihash", - "percent-encoding", - "serde", - "static_assertions", - "unsigned-varint", - "url", + "serde_json", + "tabled", ] [[package]] -name = "multibase" -version = "0.9.1" +name = "jsonpath_lib" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" +checksum = "eaa63191d68230cccb81c5aa23abd53ed64d83337cacbb25a7b8c7979523774f" dependencies = [ - "base-x", - "data-encoding", - "data-encoding-macro", + "log", + "serde", + "serde_json", ] [[package]] -name = "multihash" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835d6ff01d610179fbce3de1694d007e500bf33a7f29689838941d6bf783ae40" +name = "jsonrpsee" +version = "0.16.2" +source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" dependencies = [ - "core2", - "multihash-derive", - "unsigned-varint", + "jsonrpsee-core", + "jsonrpsee-http-client", + "jsonrpsee-proc-macros", + "jsonrpsee-server", + "jsonrpsee-types", + "jsonrpsee-ws-client", + "tracing", ] [[package]] -name = "multihash-derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" +name = "jsonrpsee-client-transport" +version = "0.16.2" +source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" dependencies = [ - "proc-macro-crate", - "proc-macro-error", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", - "synstructure", + "futures-util", + "http", + "jsonrpsee-core", + "jsonrpsee-types", + "pin-project", + "rustls-native-certs", + "soketto", + "thiserror", + "tokio", + "tokio-rustls 0.23.4", + "tokio-util 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tracing", + "webpki-roots 0.22.6", ] [[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "mysten-common" -version = "0.1.0" +name = "jsonrpsee-core" +version = "0.16.2" +source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" dependencies = [ - "futures", + "anyhow", + "arrayvec 0.7.2", + "async-lock", + "async-trait", + "beef", + "futures-channel", + "futures-timer", + "futures-util", + "globset", + "hyper", + "jsonrpsee-types", "parking_lot 0.12.1", + "rand 0.8.5", + "rustc-hash", + "serde", + "serde_json", + "soketto", + "thiserror", "tokio", + "tracing", ] [[package]] -name = "mysten-metrics" -version = "0.7.0" +name = "jsonrpsee-http-client" +version = "0.16.2" +source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" dependencies = [ "async-trait", - "axum", - "dashmap", - "futures", - "once_cell", - "parking_lot 0.12.1", - "prometheus", - "prometheus-closure-metric", - "scopeguard", - "tap", + "hyper", + "hyper-rustls 0.23.2", + "jsonrpsee-core", + "jsonrpsee-types", + "rustc-hash", + "serde", + "serde_json", + "thiserror", "tokio", "tracing", - "uuid 1.2.2", ] [[package]] -name = "mysten-network" -version = "0.2.0" +name = "jsonrpsee-proc-macros" +version = "0.16.2" +source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" dependencies = [ - "anemo", - "bcs", - "bytes", - "eyre", - "futures", + "heck", + "proc-macro-crate", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", +] + +[[package]] +name = "jsonrpsee-server" +version = "0.16.2" +source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" +dependencies = [ + "futures-channel", + "futures-util", "http", - "multiaddr", - "pin-project-lite", + "hyper", + "jsonrpsee-core", + "jsonrpsee-types", "serde", - "snap", + "serde_json", + "soketto", "tokio", "tokio-stream", - "tonic 0.11.0", - "tonic-health", + "tokio-util 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", "tower", - "tower-http", "tracing", ] [[package]] -name = "mysten-service" -version = "0.0.1" +name = "jsonrpsee-types" +version = "0.16.2" +source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" dependencies = [ "anyhow", - "axum", - "mysten-metrics", - "prometheus", + "beef", "serde", "serde_json", - "telemetry-subscribers", - "tokio", - "tower", + "thiserror", "tracing", ] [[package]] -name = "mysten-service-boilerplate" -version = "0.0.1" +name = "jsonrpsee-ws-client" +version = "0.16.2" +source = "git+https://github.com/wlmyng/jsonrpsee.git?rev=b1b300784795f6a64d0fcdf8f03081a9bc38bde8#b1b300784795f6a64d0fcdf8f03081a9bc38bde8" dependencies = [ - "anyhow", - "axum", - "mysten-service", - "prometheus", - "serde", - "tokio", - "tracing", + "http", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", ] [[package]] -name = "mysten-util-mem" -version = "0.11.0" +name = "k256" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" dependencies = [ "cfg-if", - "ed25519-consensus", - "fastcrypto", - "fastcrypto-tbls", - "hashbrown 0.12.3", - "impl-trait-for-tuples", - "indexmap 2.2.6", - "mysten-util-mem-derive", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.6", + "sha3 0.10.6", +] + +[[package]] +name = "k256" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +dependencies = [ + "cfg-if", + "ecdsa 0.16.6", + "elliptic-curve 0.13.4", "once_cell", - "parking_lot 0.12.1", - "roaring", - "smallvec", + "serdect", + "sha2 0.10.6", + "signature 2.0.0", ] [[package]] -name = "mysten-util-mem-derive" -version = "0.1.0" +name = "keccak" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" dependencies = [ - "proc-macro2 1.0.78", - "syn 1.0.107", - "synstructure", + "cpufeatures", ] [[package]] -name = "naive-timer" -version = "0.2.0" +name = "kqueue" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034a0ad7deebf0c2abcf2435950a6666c3c15ea9d8fad0c0f48efa8a7f843fed" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] [[package]] -name = "named-lock" -version = "0.2.0" +name = "kqueue-sys" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a3eb6b7c682b65d1f631ec3176829d72ab450b3aacdd3f719bf220822e59ac" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" dependencies = [ + "bitflags 1.3.2", "libc", - "once_cell", - "parking_lot 0.12.1", - "thiserror", - "widestring", - "winapi", ] [[package]] -name = "narwhal-config" -version = "0.1.0" +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" dependencies = [ - "fastcrypto", - "insta", - "match_opt", - "mysten-network", - "mysten-util-mem", - "narwhal-crypto", - "narwhal-test-utils", - "rand 0.8.5", - "serde", - "serde_json", - "tempfile", - "thiserror", - "tracing", + "spin 0.5.2", ] [[package]] -name = "narwhal-crypto" -version = "0.1.0" +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "lexical-core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46" dependencies = [ - "bcs", - "bincode", - "criterion", - "fastcrypto", - "hex-literal 0.3.4", - "proptest", - "proptest-derive", - "serde", - "serde-reflection", - "serde_json", - "shared-crypto", + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", ] [[package]] -name = "narwhal-executor" -version = "0.1.0" +name = "lexical-parse-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" dependencies = [ - "async-trait", - "bcs", - "bincode", - "bytes", - "fastcrypto", - "futures", - "indexmap 2.2.6", - "mockall", - "mysten-metrics", - "narwhal-config", - "narwhal-crypto", - "narwhal-network", - "narwhal-node", - "narwhal-primary", - "narwhal-storage", - "narwhal-test-utils", - "narwhal-types", - "prometheus", - "serde", - "sui-protocol-config", - "telemetry-subscribers", - "tempfile", - "thiserror", - "tokio", - "tonic 0.11.0", - "tracing", - "typed-store", + "lexical-parse-integer", + "lexical-util", + "static_assertions", ] [[package]] -name = "narwhal-network" -version = "0.1.0" +name = "lexical-parse-integer" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9" dependencies = [ - "anemo", - "anemo-tower", - "anyhow", - "async-trait", - "axum", - "axum-server", - "backoff", - "bincode", - "bytes", - "dashmap", - "futures", - "mysten-common", - "mysten-metrics", - "narwhal-crypto", - "narwhal-test-utils", - "narwhal-types", - "parking_lot 0.12.1", - "prometheus", - "quinn-proto", - "rand 0.8.5", - "sui-macros", - "tokio", - "tower", - "tracing", + "lexical-util", + "static_assertions", ] [[package]] -name = "narwhal-node" -version = "0.1.0" +name = "lexical-util" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" dependencies = [ - "anemo", - "arc-swap", - "async-trait", - "axum", - "bytes", - "cfg-if", - "clap", - "eyre", - "fastcrypto", - "futures", - "mysten-metrics", - "mysten-network", - "narwhal-config", - "narwhal-crypto", - "narwhal-executor", - "narwhal-network", - "narwhal-primary", - "narwhal-storage", - "narwhal-test-utils", - "narwhal-types", - "narwhal-worker", - "pretty_assertions", - "prometheus", - "rand 0.8.5", - "reqwest", - "serde-reflection", - "serde_yaml 0.8.26", - "sui-keys", - "sui-protocol-config", - "sui-types", - "telemetry-subscribers", - "thiserror", - "tokio", - "tokio-stream", - "tracing", - "tracing-subscriber", - "url", + "static_assertions", ] [[package]] -name = "narwhal-primary" -version = "0.1.0" +name = "lexical-write-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862" dependencies = [ - "anemo", - "anemo-tower", - "anyhow", - "arc-swap", - "async-trait", - "backoff", - "bcs", - "bincode", - "bytes", - "cfg-if", - "criterion", - "dashmap", - "fastcrypto", - "futures", - "governor", - "indexmap 2.2.6", - "itertools 0.10.5", - "mockall", - "mysten-common", - "mysten-metrics", - "mysten-network", - "narwhal-config", - "narwhal-crypto", - "narwhal-executor", - "narwhal-network", - "narwhal-node", - "narwhal-storage", - "narwhal-test-utils", - "narwhal-types", - "narwhal-worker", - "once_cell", - "parking_lot 0.12.1", - "prometheus", - "proptest", - "rand 0.8.5", - "reqwest", - "sui-macros", - "sui-protocol-config", - "tap", - "telemetry-subscribers", - "tempfile", - "thiserror", - "tokio", - "tokio-stream", - "tower", - "tracing", - "typed-store", -] - -[[package]] -name = "narwhal-storage" -version = "0.1.0" -dependencies = [ - "fastcrypto", - "fastcrypto-tbls", - "futures", - "lru 0.10.0", - "mysten-common", - "narwhal-config", - "narwhal-test-utils", - "narwhal-types", - "parking_lot 0.12.1", - "prometheus", - "sui-macros", - "tap", - "tempfile", - "tokio", - "tracing", - "typed-store", -] - -[[package]] -name = "narwhal-test-utils" -version = "0.1.0" -dependencies = [ - "anemo", - "fastcrypto", - "fdlimit", - "indexmap 2.2.6", - "itertools 0.10.5", - "mysten-metrics", - "mysten-network", - "narwhal-config", - "narwhal-crypto", - "narwhal-executor", - "narwhal-network", - "narwhal-node", - "narwhal-primary", - "narwhal-storage", - "narwhal-types", - "narwhal-worker", - "once_cell", - "prometheus", - "rand 0.8.5", - "sui-protocol-config", - "telemetry-subscribers", - "tempfile", - "tokio", - "tonic 0.11.0", - "tracing", - "typed-store", + "lexical-util", + "lexical-write-integer", + "static_assertions", ] [[package]] -name = "narwhal-types" -version = "0.1.0" +name = "lexical-write-integer" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446" dependencies = [ - "anemo", - "anemo-build", - "anyhow", - "base64 0.21.2", - "bcs", - "bytes", - "criterion", - "derive_builder", - "enum_dispatch", - "fastcrypto", - "futures", - "indexmap 2.2.6", - "mockall", - "mysten-common", - "mysten-metrics", - "mysten-network", - "mysten-util-mem", - "narwhal-config", - "narwhal-crypto", - "narwhal-test-utils", - "once_cell", - "prometheus", - "proptest", - "proptest-derive", - "prost 0.12.3", - "prost-build", - "protobuf-src", - "rand 0.8.5", - "roaring", - "rustversion", - "serde", - "serde_test", - "serde_with", - "sui-protocol-config", - "thiserror", - "tokio", - "tonic 0.11.0", - "tonic-build", - "tracing", - "typed-store", + "lexical-util", + "static_assertions", ] [[package]] -name = "narwhal-worker" -version = "0.1.0" -dependencies = [ - "anemo", - "anemo-tower", - "anyhow", - "arc-swap", - "async-trait", - "byteorder", - "bytes", - "eyre", - "fastcrypto", - "futures", - "governor", - "itertools 0.10.5", - "mysten-metrics", - "mysten-network", - "narwhal-config", - "narwhal-crypto", - "narwhal-network", - "narwhal-node", - "narwhal-primary", - "narwhal-storage", - "narwhal-test-utils", - "narwhal-types", - "prometheus", - "rand 0.8.5", - "reqwest", - "sui-protocol-config", - "tap", - "telemetry-subscribers", - "tempfile", - "thiserror", - "tokio", - "tonic 0.11.0", - "tower", - "tracing", - "typed-store", -] +name = "libc" +version = "0.2.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] -name = "neptune" -version = "13.0.0" +name = "libloading" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06626c9ac04c894e9a23d061ba1309f28506cdc5fe64156d28a15fb57fc8e438" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ - "bellpepper", - "bellpepper-core", - "blake2s_simd", - "blstrs", - "byteorder", - "ff 0.13.0", - "generic-array", - "log", - "pasta_curves", - "serde", - "trait-set", + "cfg-if", + "winapi", ] [[package]] -name = "nested" -version = "0.1.1" +name = "libm" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b420f638f07fe83056b55ea190bb815f609ec5a35e7017884a10f78839c9e" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" [[package]] -name = "newline-converter" -version = "0.2.2" +name = "librocksdb-sys" +version = "0.11.0+8.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f71d09d5c87634207f894c6b31b6a2b2c64ea3bdcf71bd5599fdbbe1600c00f" +checksum = "d3386f101bcb4bd252d8e9d2fb41ec3b0862a15a62b478c355b2982efa469e3e" dependencies = [ - "unicode-segmentation", + "bindgen", + "bzip2-sys", + "cc", + "glob", + "libc", + "libz-sys", + "lz4-sys", + "zstd-sys", ] [[package]] -name = "nexlint" -version = "0.1.0" -source = "git+https://github.com/nextest-rs/nexlint.git?rev=94da5c787636dad779c340affa65219134d127f5#94da5c787636dad779c340affa65219134d127f5" +name = "libsodium-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b779387cd56adfbc02ea4a668e704f729be8d6a6abd2c27ca5ee537849a92fd" dependencies = [ - "camino", - "debug-ignore", - "determinator", - "guppy", - "hakari", - "hex", - "once_cell", - "serde", + "cc", + "libc", + "pkg-config", + "walkdir", ] [[package]] -name = "nexlint-lints" -version = "0.1.0" -source = "git+https://github.com/nextest-rs/nexlint.git?rev=94da5c787636dad779c340affa65219134d127f5#94da5c787636dad779c340affa65219134d127f5" +name = "libtest-mimic" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d8de370f98a6cb8a4606618e53e802f93b094ddec0f96988eaec2c27e6e9ce7" dependencies = [ - "anyhow", - "camino", - "colored-diff", - "globset", - "guppy", - "nexlint", - "regex", - "serde", - "toml 0.5.10", + "clap", + "termcolor", + "threadpool", ] [[package]] -name = "nibble_vec" -version = "0.1.0" +name = "libz-sys" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" dependencies = [ - "smallvec", + "cc", + "pkg-config", + "vcpkg", ] [[package]] -name = "nix" -version = "0.23.2" +name = "link-cplusplus" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" dependencies = [ - "bitflags 1.3.2", "cc", - "cfg-if", - "libc", - "memoffset 0.6.5", ] [[package]] -name = "nix" -version = "0.24.3" +name = "linked-hash-map" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", - "memoffset 0.6.5", -] +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] -name = "no-std-compat" -version = "0.4.1" +name = "linux-raw-sys" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] -name = "nom" -version = "7.1.2" +name = "linux-raw-sys" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c" -dependencies = [ - "memchr", - "minimal-lexical", -] +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" [[package]] -name = "nonempty" -version = "0.9.0" +name = "linux-raw-sys" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995defdca0a589acfdd1bd2e8e3b896b4d4f7675a31fd14c32611440c7f608e6" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] -name = "nonzero_ext" -version = "0.3.0" +name = "lock_api" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] [[package]] -name = "normalize-line-endings" -version = "0.3.0" +name = "log" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +dependencies = [ + "serde", +] [[package]] -name = "notify" -version = "6.1.1" +name = "lru" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" +checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" dependencies = [ - "bitflags 2.4.1", - "crossbeam-channel", - "filetime", - "fsevent-sys", - "inotify", - "kqueue", - "libc", - "log", - "mio", - "walkdir", - "windows-sys 0.48.0", + "hashbrown 0.12.3", ] [[package]] -name = "ntapi" -version = "0.4.0" +name = "lru" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc51db7b362b205941f71232e56c625156eb9a929f8cf74a428fd5bc094a4afc" +checksum = "03f1160296536f10c833a82dca22267d5486734230d47bf00bf435885814ba1e" dependencies = [ - "winapi", + "hashbrown 0.13.2", ] [[package]] -name = "ntest" -version = "0.9.0" +name = "lz4-sys" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da8ec6d2b73d45307e926f5af46809768581044384637af6b3f3fe7c3c88f512" +checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" dependencies = [ - "ntest_test_cases", - "ntest_timeout", + "cc", + "libc", ] [[package]] -name = "ntest_test_cases" -version = "0.9.0" +name = "lz4_flex" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be7d33be719c6f4d09e64e27c1ef4e73485dc4cc1f4d22201f89860a7fe22e22" +checksum = "912b45c753ff5f7f5208307e8ace7d2a2e30d024e26d3509f3dce546c044ce15" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", + "twox-hash", ] [[package]] -name = "ntest_timeout" -version = "0.9.0" +name = "mach2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "066b468120587a402f0b47d8f80035c921f6a46f8209efd0632a89a16f5188a4" +checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" dependencies = [ - "proc-macro-crate", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", + "libc", ] [[package]] -name = "nu-ansi-term" -version = "0.46.0" +name = "maplit" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] -name = "num" -version = "0.4.1" +name = "markdown-gen" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" -dependencies = [ - "num-bigint 0.4.4", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] +checksum = "8034621d7f1258317ca1dfb9205e3925d27ee4aa2a46620a09c567daf0310562" [[package]] -name = "num-bigint" -version = "0.3.3" +name = "match_opt" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] +checksum = "405ba1524a1e6ae755334d6966380c60ec40157e0155f9032dd3c294b6384da9" [[package]] -name = "num-bigint" -version = "0.4.4" +name = "matchers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "autocfg", - "num-integer", - "num-traits", - "rand 0.8.5", + "regex-automata 0.1.10", ] [[package]] -name = "num-bigint-dig" -version = "0.8.2" +name = "matchit" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.5", - "smallvec", - "zeroize", -] +checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" [[package]] -name = "num-complex" -version = "0.4.4" +name = "matchit" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" -dependencies = [ - "num-traits", -] +checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" [[package]] -name = "num-integer" -version = "0.1.45" +name = "md-5" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" dependencies = [ - "autocfg", - "num-traits", + "block-buffer 0.9.0", + "digest 0.9.0", + "opaque-debug", ] [[package]] -name = "num-iter" -version = "0.1.43" +name = "md-5" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" dependencies = [ - "autocfg", - "num-integer", - "num-traits", + "digest 0.10.7", ] [[package]] -name = "num-rational" -version = "0.4.1" +name = "md5" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-bigint 0.4.4", - "num-integer", - "num-traits", -] +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] -name = "num-traits" -version = "0.2.18" +name = "memchr" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" -dependencies = [ - "autocfg", - "libm", -] +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] -name = "num_cpus" -version = "1.16.0" +name = "memmap2" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" dependencies = [ - "hermit-abi", "libc", ] [[package]] -name = "num_enum" -version = "0.5.11" +name = "memoffset" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ - "num_enum_derive 0.5.11", + "autocfg", ] [[package]] -name = "num_enum" -version = "0.6.1" +name = "memoffset" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" dependencies = [ - "num_enum_derive 0.6.1", + "autocfg", ] [[package]] -name = "num_enum_derive" -version = "0.5.11" +name = "miette" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "98a72adfa0c7ae88ba0abcbd00047a476616c66b831d628b8ac7f1e9de0cfd67" dependencies = [ - "proc-macro-crate", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", + "backtrace", + "backtrace-ext", + "miette-derive", + "owo-colors 4.0.0", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size 0.3.0", + "textwrap", + "thiserror", + "unicode-width", ] [[package]] -name = "num_enum_derive" -version = "0.6.1" +name = "miette-derive" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +checksum = "279def6bf114a34b3cf887489eb440d4dfcf709ab3ce9955e4a6f957ce5cce77" dependencies = [ - "proc-macro-crate", "proc-macro2 1.0.78", "quote 1.0.35", "syn 2.0.48", ] [[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - -[[package]] -name = "number_prefix" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" - -[[package]] -name = "object" -version = "0.32.2" +name = "migrations_internals" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "0f23f71580015254b020e856feac3df5878c2c7a8812297edd6c0a485ac9dada" dependencies = [ - "memchr", + "serde", + "toml 0.7.4", ] [[package]] -name = "object_store" -version = "0.7.0" +name = "migrations_macros" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d359e231e5451f4f9fa889d56e3ce34f8724f1a61db2107739359717cf2bbf08" +checksum = "cce3325ac70e67bbab5bd837a31cae01f1a6db64e0e744a33cb03a543469ef08" dependencies = [ - "async-trait", - "base64 0.21.2", - "bytes", - "chrono", - "futures", - "humantime", - "hyper", - "itertools 0.10.5", - "parking_lot 0.12.1", - "percent-encoding", - "quick-xml 0.28.2", - "rand 0.8.5", - "reqwest", - "ring 0.16.20", - "rustls-pemfile 1.0.2", - "serde", - "serde_json", - "snafu", - "tokio", - "tracing", - "url", - "walkdir", + "migrations_internals", + "proc-macro2 1.0.78", + "quote 1.0.35", ] [[package]] -name = "object_store" -version = "0.9.0" +name = "mime" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d139f545f64630e2e3688fd9f81c470888ab01edeb72d13b4e86c566f1130000" -dependencies = [ - "async-trait", - "base64 0.21.2", - "bytes", - "chrono", - "futures", - "humantime", - "hyper", - "itertools 0.12.0", - "parking_lot 0.12.1", - "percent-encoding", - "quick-xml 0.31.0", - "rand 0.8.5", - "reqwest", - "ring 0.17.3", - "serde", - "serde_json", - "snafu", - "tokio", - "tracing", - "url", - "walkdir", -] +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] -name = "oid-registry" -version = "0.6.1" +name = "mime_guess" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" dependencies = [ - "asn1-rs", + "mime", + "unicase", ] [[package]] -name = "once_cell" -version = "1.19.0" +name = "minimal-lexical" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "oorandom" -version = "11.1.3" +name = "miniz_oxide" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] [[package]] -name = "opaque-debug" -version = "0.3.0" +name = "mio" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] [[package]] -name = "open-fastrlp" -version = "0.1.4" +name = "mockall" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" dependencies = [ - "arrayvec 0.7.2", - "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", ] [[package]] -name = "open-fastrlp-derive" -version = "0.1.1" +name = "mockall_derive" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ - "bytes", + "cfg-if", "proc-macro2 1.0.78", "quote 1.0.35", "syn 1.0.107", ] [[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "opentelemetry" -version = "0.19.0" +name = "moka" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4b8347cc26099d3aeee044065ecc3ae11469796b4d65d065a23a584ed92a6f" +checksum = "b1911e88d5831f748a4097a43862d129e3c6fca831eecac9b8db6d01d93c9de2" dependencies = [ - "opentelemetry_api 0.19.0", - "opentelemetry_sdk 0.19.0", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "once_cell", + "parking_lot 0.12.1", + "rustc_version", + "skeptic", + "smallvec", + "tagptr", + "thiserror", + "triomphe", + "uuid 1.2.2", ] [[package]] -name = "opentelemetry" -version = "0.20.0" +name = "more-asserts" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9591d937bc0e6d2feb6f71a559540ab300ea49955229c347a517a28d27784c54" -dependencies = [ - "opentelemetry_api 0.20.0", - "opentelemetry_sdk 0.20.0", -] +checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" [[package]] -name = "opentelemetry-otlp" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5e5a5c4135864099f3faafbe939eb4d7f9b80ebf68a8448da961b32a7c1275" -dependencies = [ - "async-trait", - "futures-core", - "http", - "opentelemetry-proto", - "opentelemetry-semantic-conventions", - "opentelemetry_api 0.20.0", - "opentelemetry_sdk 0.20.0", - "prost 0.11.9", - "thiserror", - "tokio", - "tonic 0.9.2", -] +name = "move-abstract-stack" +version = "0.0.1" [[package]] -name = "opentelemetry-proto" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e3f814aa9f8c905d0ee4bde026afd3b2577a97c10e1699912e3e44f0c4cbeb" +name = "move-binary-format" +version = "0.0.3" dependencies = [ - "opentelemetry_api 0.20.0", - "opentelemetry_sdk 0.20.0", - "prost 0.11.9", - "tonic 0.9.2", + "anyhow", + "enum-compat-util", + "move-core-types", + "move-proc-macros", + "ref-cast", + "serde", + "variant_count", ] [[package]] -name = "opentelemetry-semantic-conventions" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73c9f9340ad135068800e7f1b24e9e09ed9e7143f5bf8518ded3d3ec69789269" +name = "move-borrow-graph" +version = "0.0.1" + +[[package]] +name = "move-bytecode-source-map" +version = "0.1.0" dependencies = [ - "opentelemetry 0.20.0", + "anyhow", + "bcs", + "move-binary-format", + "move-command-line-common", + "move-core-types", + "move-ir-types", + "move-symbol-pool", + "serde", ] [[package]] -name = "opentelemetry_api" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed41783a5bf567688eb38372f2b7a8530f5a607a4b49d38dd7573236c23ca7e2" +name = "move-bytecode-utils" +version = "0.1.0" dependencies = [ - "futures-channel", - "futures-util", - "indexmap 1.9.3", - "once_cell", - "pin-project-lite", - "thiserror", - "urlencoding", + "anyhow", + "move-binary-format", + "move-core-types", + "petgraph 0.5.1", + "serde-reflection", ] [[package]] -name = "opentelemetry_api" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a81f725323db1b1206ca3da8bb19874bbd3f57c3bcd59471bfb04525b265b9b" +name = "move-bytecode-verifier" +version = "0.1.0" dependencies = [ - "futures-channel", - "futures-util", - "indexmap 1.9.3", - "js-sys", - "once_cell", - "pin-project-lite", - "thiserror", - "urlencoding", + "move-abstract-stack", + "move-binary-format", + "move-borrow-graph", + "move-core-types", + "move-vm-config", + "petgraph 0.5.1", ] [[package]] -name = "opentelemetry_sdk" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1" +name = "move-bytecode-verifier-v0" +version = "0.1.0" dependencies = [ - "async-trait", - "crossbeam-channel", - "futures-channel", - "futures-executor", - "futures-util", - "once_cell", - "opentelemetry_api 0.19.0", - "percent-encoding", - "rand 0.8.5", - "thiserror", + "move-abstract-stack", + "move-binary-format", + "move-borrow-graph", + "move-core-types", + "move-vm-config", + "petgraph 0.5.1", ] [[package]] -name = "opentelemetry_sdk" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa8e705a0612d48139799fcbaba0d4a90f06277153e43dd2bdc16c6f0edd8026" +name = "move-bytecode-verifier-v1" +version = "0.1.0" dependencies = [ - "async-trait", - "crossbeam-channel", - "futures-channel", - "futures-executor", - "futures-util", - "once_cell", - "opentelemetry_api 0.20.0", - "ordered-float 3.9.1", - "percent-encoding", - "rand 0.8.5", - "regex", - "serde_json", - "thiserror", - "tokio", - "tokio-stream", + "move-abstract-stack", + "move-binary-format", + "move-borrow-graph", + "move-core-types", + "move-vm-config", + "petgraph 0.5.1", ] [[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +name = "move-bytecode-verifier-v2" +version = "0.1.0" +dependencies = [ + "move-abstract-stack", + "move-binary-format", + "move-borrow-graph", + "move-core-types", + "move-vm-config", + "petgraph 0.5.1", +] [[package]] -name = "ordered-float" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +name = "move-bytecode-viewer" +version = "0.1.0" dependencies = [ - "num-traits", + "anyhow", + "clap", + "crossterm", + "move-binary-format", + "move-bytecode-source-map", + "move-disassembler", + "regex", + "tui", ] [[package]] -name = "ordered-float" -version = "3.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a54938017eacd63036332b4ae5c8a49fc8c0c1d6d629893057e4f13609edd06" +name = "move-cli" +version = "0.1.0" dependencies = [ - "num-traits", + "anyhow", + "bcs", + "clap", + "codespan-reporting", + "colored", + "difference", + "move-binary-format", + "move-bytecode-utils", + "move-bytecode-verifier", + "move-bytecode-viewer", + "move-command-line-common", + "move-compiler", + "move-core-types", + "move-coverage", + "move-disassembler", + "move-docgen", + "move-errmapgen", + "move-ir-types", + "move-package", + "move-prover", + "move-read-write-set-types", + "move-stdlib", + "move-unit-test", + "move-vm-profiler", + "move-vm-runtime", + "move-vm-test-utils", + "move-vm-types", + "serde_yaml 0.8.26", + "tempfile", + "toml_edit 0.14.4", + "walkdir", ] [[package]] -name = "ouroboros" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2ba07320d39dfea882faa70554b4bd342a5f273ed59ba7c1c6b4c840492c954" +name = "move-command-line-common" +version = "0.1.0" dependencies = [ - "aliasable", - "ouroboros_macro", - "static_assertions", + "anyhow", + "difference", + "dirs-next", + "hex", + "move-core-types", + "num-bigint 0.4.4", + "once_cell", + "serde", + "sha2 0.9.9", + "vfs", + "walkdir", ] [[package]] -name = "ouroboros_macro" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" +name = "move-compiler" +version = "0.0.1" dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 2.0.48", + "anyhow", + "bcs", + "clap", + "codespan-reporting", + "dunce", + "hex", + "move-binary-format", + "move-borrow-graph", + "move-bytecode-source-map", + "move-bytecode-verifier", + "move-command-line-common", + "move-core-types", + "move-ir-to-bytecode", + "move-ir-types", + "move-proc-macros", + "move-symbol-pool", + "once_cell", + "pathdiff", + "petgraph 0.5.1", + "regex", + "serde", + "similar", + "stacker", + "tempfile", + "vfs", ] [[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" +name = "move-core-types" +version = "0.0.4" dependencies = [ - "winapi", + "anyhow", + "arbitrary", + "bcs", + "enum-compat-util", + "ethnum", + "hex", + "leb128", + "move-proc-macros", + "num", + "once_cell", + "primitive-types 0.10.1", + "proptest", + "proptest-derive", + "rand 0.8.5", + "ref-cast", + "serde", + "serde_bytes", + "thiserror", + "uint", ] [[package]] -name = "outref" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" +name = "move-coverage" +version = "0.1.0" +dependencies = [ + "anyhow", + "bcs", + "clap", + "codespan", + "colored", + "move-binary-format", + "move-bytecode-source-map", + "move-command-line-common", + "move-core-types", + "move-ir-types", + "petgraph 0.5.1", + "serde", +] [[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "owo-colors" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" - -[[package]] -name = "owo-colors" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" +name = "move-disassembler" +version = "0.1.0" +dependencies = [ + "anyhow", + "bcs", + "clap", + "colored", + "hex", + "move-binary-format", + "move-bytecode-source-map", + "move-command-line-common", + "move-compiler", + "move-core-types", + "move-coverage", + "move-ir-types", +] [[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +name = "move-docgen" +version = "0.1.0" dependencies = [ - "ecdsa 0.16.6", - "elliptic-curve 0.13.4", - "primeorder", - "sha2 0.10.6", + "anyhow", + "codespan", + "codespan-reporting", + "itertools 0.10.5", + "log", + "move-compiler", + "move-model", + "num", + "once_cell", + "regex", + "serde", ] [[package]] -name = "packable" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11259b086696fc9256f790485d8f14f11f0fa60a60351af9693e3d49fd24fdb6" +name = "move-errmapgen" +version = "0.1.0" dependencies = [ - "autocfg", - "packable-derive", - "primitive-types 0.12.2", + "anyhow", + "move-command-line-common", + "move-core-types", + "move-model", "serde", ] [[package]] -name = "packable-derive" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9567693dd2f9a4339cb0a54adfcc0cb431c0ac88b2e46c6ddfb5f5d11a1cc4f" +name = "move-ir-compiler" +version = "0.1.0" dependencies = [ - "proc-macro-crate", - "proc-macro-error", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", + "anyhow", + "bcs", + "clap", + "move-binary-format", + "move-bytecode-source-map", + "move-bytecode-verifier", + "move-command-line-common", + "move-ir-to-bytecode", + "serde_json", ] [[package]] -name = "pairing" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +name = "move-ir-to-bytecode" +version = "0.1.0" dependencies = [ - "group 0.13.0", + "anyhow", + "codespan-reporting", + "log", + "move-binary-format", + "move-bytecode-source-map", + "move-command-line-common", + "move-core-types", + "move-ir-to-bytecode-syntax", + "move-ir-types", + "move-symbol-pool", + "ouroboros", ] [[package]] -name = "papergrid" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae7891b22598926e4398790c8fe6447930c72a67d36d983a49d6ce682ce83290" +name = "move-ir-to-bytecode-syntax" +version = "0.1.0" dependencies = [ - "bytecount", - "fnv", - "unicode-width", + "anyhow", + "hex", + "move-command-line-common", + "move-core-types", + "move-ir-types", + "move-symbol-pool", ] [[package]] -name = "parity-scale-codec" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" +name = "move-ir-types" +version = "0.1.0" dependencies = [ - "arrayvec 0.7.2", - "bitvec 0.20.4", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive 2.3.1", + "hex", + "move-command-line-common", + "move-core-types", + "move-symbol-pool", + "once_cell", "serde", ] [[package]] -name = "parity-scale-codec" -version = "3.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" +name = "move-model" +version = "0.1.0" dependencies = [ - "arrayvec 0.7.2", - "bitvec 1.0.1", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive 3.6.5", + "anyhow", + "codespan", + "codespan-reporting", + "internment", + "itertools 0.10.5", + "log", + "move-binary-format", + "move-bytecode-source-map", + "move-command-line-common", + "move-compiler", + "move-core-types", + "move-disassembler", + "move-ir-types", + "move-symbol-pool", + "num", + "once_cell", + "regex", "serde", ] [[package]] -name = "parity-scale-codec-derive" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" +name = "move-package" +version = "0.1.0" dependencies = [ - "proc-macro-crate", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", + "anyhow", + "clap", + "colored", + "itertools 0.10.5", + "move-binary-format", + "move-bytecode-source-map", + "move-bytecode-utils", + "move-command-line-common", + "move-compiler", + "move-core-types", + "move-docgen", + "move-model", + "move-symbol-pool", + "named-lock", + "once_cell", + "petgraph 0.5.1", + "regex", + "serde", + "serde_yaml 0.8.26", + "sha2 0.9.9", + "tempfile", + "toml 0.5.10", + "toml_edit 0.14.4", + "treeline", + "walkdir", + "whoami", ] [[package]] -name = "parity-scale-codec-derive" -version = "3.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" +name = "move-proc-macros" +version = "0.1.0" dependencies = [ - "proc-macro-crate", - "proc-macro2 1.0.78", + "enum-compat-util", "quote 1.0.35", - "syn 1.0.107", + "syn 2.0.48", ] [[package]] -name = "parking" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +name = "move-prover" +version = "0.1.0" dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", + "anyhow", + "clap", + "codespan-reporting", + "itertools 0.10.5", + "log", + "move-command-line-common", + "move-compiler", + "move-docgen", + "move-errmapgen", + "move-model", + "move-stackless-bytecode", + "once_cell", + "serde", + "simplelog", + "toml 0.5.10", ] [[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +name = "move-read-write-set-types" +version = "0.0.3" dependencies = [ - "lock_api", - "parking_lot_core 0.9.9", + "move-binary-format", + "move-core-types", + "serde", ] [[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +name = "move-stackless-bytecode" +version = "0.1.0" dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "codespan", + "codespan-reporting", + "ethnum", + "im", + "itertools 0.10.5", + "log", + "move-binary-format", + "move-command-line-common", + "move-compiler", + "move-core-types", + "move-model", + "move-read-write-set-types", + "num", + "paste", + "petgraph 0.5.1", + "serde", ] [[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +name = "move-stackless-bytecode-interpreter" +version = "0.1.0" dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.4.1", - "smallvec", - "windows-targets 0.48.0", + "anyhow", + "bytecode-interpreter-crypto", + "clap", + "codespan-reporting", + "itertools 0.10.5", + "move-binary-format", + "move-core-types", + "move-model", + "move-stackless-bytecode", + "num", ] [[package]] -name = "parquet" -version = "50.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "547b92ebf0c1177e3892f44c8f79757ee62e678d564a9834189725f2c5b7a750" +name = "move-stdlib" +version = "0.1.1" dependencies = [ - "ahash 0.8.11", - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-data", - "arrow-ipc", - "arrow-schema", - "arrow-select", - "base64 0.21.2", - "brotli", - "bytes", - "chrono", - "flate2", - "half 2.3.1", - "hashbrown 0.14.3", - "lz4_flex", - "num", - "num-bigint 0.4.4", - "paste", - "seq-macro", - "snap", - "thrift", - "twox-hash", - "zstd 0.13.0", + "anyhow", + "hex", + "log", + "move-binary-format", + "move-command-line-common", + "move-core-types", + "move-docgen", + "move-errmapgen", + "move-prover", + "move-vm-runtime", + "move-vm-types", + "sha2 0.9.9", + "sha3 0.9.1", + "smallvec", + "walkdir", ] [[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +name = "move-stdlib-v0" +version = "0.1.1" dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", + "anyhow", + "hex", + "log", + "move-binary-format", + "move-command-line-common", + "move-core-types", + "move-docgen", + "move-errmapgen", + "move-prover", + "move-vm-runtime-v0", + "move-vm-types", + "sha2 0.9.9", + "sha3 0.9.1", + "smallvec", + "walkdir", ] [[package]] -name = "pasta_curves" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +name = "move-stdlib-v1" +version = "0.1.1" dependencies = [ - "blake2b_simd", - "ec-gpu", - "ff 0.13.0", - "group 0.13.0", + "anyhow", "hex", - "lazy_static", - "rand 0.8.5", - "serde", - "static_assertions", - "subtle", + "log", + "move-binary-format", + "move-command-line-common", + "move-core-types", + "move-docgen", + "move-errmapgen", + "move-prover", + "move-vm-runtime-v1", + "move-vm-types", + "sha2 0.9.9", + "sha3 0.9.1", + "smallvec", + "walkdir", ] [[package]] -name = "paste" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" - -[[package]] -name = "pathdiff" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +name = "move-stdlib-v2" +version = "0.1.1" dependencies = [ - "camino", + "anyhow", + "hex", + "log", + "move-binary-format", + "move-command-line-common", + "move-core-types", + "move-docgen", + "move-errmapgen", + "move-prover", + "move-vm-runtime-v2", + "move-vm-types", + "sha2 0.9.9", + "sha3 0.9.1", + "smallvec", + "walkdir", ] [[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +name = "move-symbol-pool" +version = "0.1.0" dependencies = [ - "digest 0.10.7", - "hmac 0.12.1", - "password-hash", - "sha2 0.10.6", + "once_cell", + "phf", + "serde", ] [[package]] -name = "pbkdf2" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ca0b5a68607598bf3bad68f32227a8164f6254833f84eafaac409cd6746c31" +name = "move-transactional-test-runner" +version = "0.1.0" dependencies = [ - "digest 0.10.7", - "hmac 0.12.1", + "anyhow", + "async-trait", + "clap", + "move-binary-format", + "move-bytecode-source-map", + "move-cli", + "move-command-line-common", + "move-compiler", + "move-core-types", + "move-disassembler", + "move-ir-compiler", + "move-ir-types", + "move-stdlib", + "move-symbol-pool", + "move-vm-config", + "move-vm-runtime", + "move-vm-test-utils", + "move-vm-types", + "once_cell", + "rayon", + "regex", + "tempfile", + "tokio", ] [[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +name = "move-unit-test" +version = "0.1.0" +dependencies = [ + "anyhow", + "bcs", + "better_any", + "clap", + "codespan-reporting", + "colored", + "itertools 0.10.5", + "move-binary-format", + "move-bytecode-utils", + "move-command-line-common", + "move-compiler", + "move-core-types", + "move-ir-types", + "move-model", + "move-stackless-bytecode-interpreter", + "move-stdlib", + "move-symbol-pool", + "move-vm-profiler", + "move-vm-runtime", + "move-vm-test-utils", + "move-vm-types", + "once_cell", + "rayon", + "regex", +] [[package]] -name = "pem" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4" +name = "move-vm-config" +version = "0.1.0" dependencies = [ - "base64 0.13.1", + "move-binary-format", + "once_cell", ] [[package]] -name = "pem-rfc7468" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" -dependencies = [ - "base64ct", -] - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +name = "move-vm-profiler" +version = "0.1.0" dependencies = [ - "base64ct", + "move-vm-config", + "once_cell", + "serde", + "serde_json", + "tracing", ] [[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pest" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" +name = "move-vm-runtime" +version = "0.1.0" dependencies = [ - "thiserror", - "ucd-trie", + "better_any", + "fail", + "move-binary-format", + "move-bytecode-verifier", + "move-core-types", + "move-vm-config", + "move-vm-profiler", + "move-vm-types", + "once_cell", + "parking_lot 0.11.2", + "sha3 0.9.1", + "smallvec", + "tracing", ] [[package]] -name = "pest_derive" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96504449aa860c8dcde14f9fba5c58dc6658688ca1fe363589d6327b8662c603" +name = "move-vm-runtime-v0" +version = "0.1.0" dependencies = [ - "pest", - "pest_generator", + "better_any", + "fail", + "move-binary-format", + "move-bytecode-verifier-v0", + "move-core-types", + "move-vm-config", + "move-vm-profiler", + "move-vm-types", + "once_cell", + "parking_lot 0.11.2", + "sha3 0.9.1", + "smallvec", + "tracing", ] [[package]] -name = "pest_generator" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "798e0220d1111ae63d66cb66a5dcb3fc2d986d520b98e49e1852bfdb11d7c5e7" +name = "move-vm-runtime-v1" +version = "0.1.0" dependencies = [ - "pest", - "pest_meta", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", + "better_any", + "fail", + "move-binary-format", + "move-bytecode-verifier-v1", + "move-core-types", + "move-vm-config", + "move-vm-profiler", + "move-vm-types", + "once_cell", + "parking_lot 0.11.2", + "sha3 0.9.1", + "smallvec", + "tracing", ] [[package]] -name = "pest_meta" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "984298b75898e30a843e278a9f2452c31e349a073a0ce6fd950a12a74464e065" +name = "move-vm-runtime-v2" +version = "0.1.0" dependencies = [ + "better_any", + "fail", + "move-binary-format", + "move-bytecode-verifier-v2", + "move-core-types", + "move-vm-config", + "move-vm-profiler", + "move-vm-types", "once_cell", - "pest", - "sha1", + "parking_lot 0.11.2", + "sha3 0.9.1", + "smallvec", + "tracing", ] [[package]] -name = "petgraph" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +name = "move-vm-test-utils" +version = "0.1.0" dependencies = [ - "fixedbitset 0.2.0", - "indexmap 1.9.3", + "anyhow", + "move-binary-format", + "move-core-types", + "move-vm-profiler", + "move-vm-types", + "once_cell", + "serde", ] [[package]] -name = "petgraph" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +name = "move-vm-types" +version = "0.1.0" dependencies = [ - "fixedbitset 0.4.2", - "indexmap 1.9.3", + "bcs", + "move-binary-format", + "move-core-types", + "move-vm-profiler", + "serde", + "smallvec", ] [[package]] -name = "pharos" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +name = "msim" +version = "0.1.0" +source = "git+https://github.com/MystenLabs/mysten-sim.git?rev=6f88ec84644cb1a6809c010f1f534d0d09e0cd89#6f88ec84644cb1a6809c010f1f534d0d09e0cd89" dependencies = [ + "ahash 0.7.6", + "async-task", + "bincode", + "bytes", + "cc", + "downcast-rs", + "erasable", "futures", - "rustc_version", + "lazy_static", + "libc", + "msim-macros", + "naive-timer", + "pin-project-lite", + "rand 0.8.5", + "real_tokio", + "serde", + "socket2 0.4.9", + "tap", + "tokio-util 0.7.10 (git+https://github.com/mystenmark/tokio-madsim-fork.git?rev=e47aafebf98e9c1734a8848a1876d5946c44bdd1)", + "toml 0.5.10", + "tracing", + "tracing-subscriber", ] [[package]] -name = "phf" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +name = "msim-macros" +version = "0.1.0" +source = "git+https://github.com/MystenLabs/mysten-sim.git?rev=6f88ec84644cb1a6809c010f1f534d0d09e0cd89#6f88ec84644cb1a6809c010f1f534d0d09e0cd89" dependencies = [ - "phf_macros", - "phf_shared", + "darling 0.14.2", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", ] [[package]] -name = "phf_generator" -version = "0.11.1" +name = "multer" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" +checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" dependencies = [ - "phf_shared", - "rand 0.8.5", + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "log", + "memchr", + "mime", + "spin 0.9.8", + "version_check", ] [[package]] -name = "phf_macros" -version = "0.11.1" +name = "multiaddr" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" +checksum = "3b53e0cc5907a5c216ba6584bf74be8ab47d6d6289f72793b2dddbf15dc3bf8c" dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", + "arrayref", + "byteorder", + "data-encoding", + "multibase", + "multihash", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint", + "url", ] [[package]] -name = "phf_shared" -version = "0.11.1" +name = "multibase" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" dependencies = [ - "siphasher", + "base-x", + "data-encoding", + "data-encoding-macro", ] [[package]] -name = "pin-project" -version = "1.0.12" +name = "multihash" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "835d6ff01d610179fbce3de1694d007e500bf33a7f29689838941d6bf783ae40" dependencies = [ - "pin-project-internal", + "core2", + "multihash-derive", + "unsigned-varint", ] [[package]] -name = "pin-project-internal" -version = "1.0.12" +name = "multihash-derive" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ + "proc-macro-crate", + "proc-macro-error", "proc-macro2 1.0.78", "quote 1.0.35", "syn 1.0.107", + "synstructure", ] [[package]] -name = "pin-project-lite" -version = "0.2.13" +name = "multimap" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] -name = "pin-utils" +name = "mysten-common" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs1" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719" dependencies = [ - "der 0.6.1", - "pkcs8 0.9.0", - "spki 0.6.0", - "zeroize", + "futures", + "parking_lot 0.12.1", + "tokio", ] [[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +name = "mysten-metrics" +version = "0.7.0" dependencies = [ - "der 0.6.1", - "spki 0.6.0", + "async-trait", + "axum", + "dashmap", + "futures", + "once_cell", + "parking_lot 0.12.1", + "prometheus", + "prometheus-closure-metric", + "scopeguard", + "tap", + "tokio", + "tracing", + "uuid 1.2.2", ] [[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +name = "mysten-network" +version = "0.2.0" dependencies = [ - "der 0.7.5", - "spki 0.7.1", + "anemo", + "bcs", + "bytes", + "eyre", + "futures", + "http", + "multiaddr", + "pin-project-lite", + "serde", + "snap", + "tokio", + "tokio-stream", + "tonic 0.11.0", + "tonic-health", + "tower", + "tower-http", + "tracing", ] [[package]] -name = "pkg-config" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" - -[[package]] -name = "platforms" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" - -[[package]] -name = "plotters" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +name = "mysten-service" +version = "0.0.1" dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", + "anyhow", + "axum", + "mysten-metrics", + "prometheus", + "serde", + "serde_json", + "telemetry-subscribers", + "tokio", + "tower", + "tracing", ] [[package]] -name = "plotters-backend" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" - -[[package]] -name = "plotters-svg" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" +name = "mysten-service-boilerplate" +version = "0.0.1" dependencies = [ - "plotters-backend", + "anyhow", + "axum", + "mysten-service", + "prometheus", + "serde", + "tokio", + "tracing", ] [[package]] -name = "poly1305" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +name = "mysten-util-mem" +version = "0.11.0" dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", + "cfg-if", + "ed25519-consensus", + "fastcrypto", + "fastcrypto-tbls", + "hashbrown 0.12.3", + "impl-trait-for-tuples", + "indexmap 2.2.6", + "mysten-util-mem-derive", + "once_cell", + "parking_lot 0.12.1", + "roaring", + "smallvec", ] [[package]] -name = "polyval" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" +name = "mysten-util-mem-derive" +version = "0.1.0" dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", + "proc-macro2 1.0.78", + "syn 1.0.107", + "synstructure", ] [[package]] -name = "portable-atomic" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b" - -[[package]] -name = "powerfmt" +name = "naive-timer" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +checksum = "034a0ad7deebf0c2abcf2435950a6666c3c15ea9d8fad0c0f48efa8a7f843fed" [[package]] -name = "pprof" -version = "0.11.0" +name = "named-lock" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e20150f965e0e4c925982b9356da71c84bcd56cb66ef4e894825837cbcf6613e" +checksum = "40a3eb6b7c682b65d1f631ec3176829d72ab450b3aacdd3f719bf220822e59ac" dependencies = [ - "backtrace", - "cfg-if", - "findshlibs", "libc", - "log", - "nix 0.24.3", "once_cell", "parking_lot 0.12.1", - "smallvec", - "symbolic-demangle", - "tempfile", "thiserror", + "widestring", + "winapi", ] [[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +name = "narwhal-config" +version = "0.1.0" +dependencies = [ + "fastcrypto", + "insta", + "match_opt", + "mysten-network", + "mysten-util-mem", + "narwhal-crypto", + "narwhal-test-utils", + "rand 0.8.5", + "serde", + "serde_json", + "tempfile", + "thiserror", + "tracing", +] [[package]] -name = "pq-sys" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b845d6d8ec554f972a2c5298aad68953fd64e7441e846075450b44656a016d1" +name = "narwhal-crypto" +version = "0.1.0" dependencies = [ - "vcpkg", + "bcs", + "bincode", + "criterion", + "fastcrypto", + "hex-literal 0.3.4", + "proptest", + "proptest-derive", + "serde", + "serde-reflection", + "serde_json", + "shared-crypto", ] [[package]] -name = "predicates" -version = "2.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +name = "narwhal-executor" +version = "0.1.0" dependencies = [ - "difflib", - "float-cmp", - "itertools 0.10.5", - "normalize-line-endings", - "predicates-core", - "regex", + "async-trait", + "bcs", + "bincode", + "bytes", + "fastcrypto", + "futures", + "indexmap 2.2.6", + "iota-protocol-config", + "mockall", + "mysten-metrics", + "narwhal-config", + "narwhal-crypto", + "narwhal-network", + "narwhal-node", + "narwhal-primary", + "narwhal-storage", + "narwhal-test-utils", + "narwhal-types", + "prometheus", + "serde", + "telemetry-subscribers", + "tempfile", + "thiserror", + "tokio", + "tonic 0.11.0", + "tracing", + "typed-store", ] [[package]] -name = "predicates-core" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f883590242d3c6fc5bf50299011695fa6590c2c70eac95ee1bdb9a733ad1a2" +name = "narwhal-network" +version = "0.1.0" +dependencies = [ + "anemo", + "anemo-tower", + "anyhow", + "async-trait", + "axum", + "axum-server", + "backoff", + "bincode", + "bytes", + "dashmap", + "futures", + "iota-macros", + "mysten-common", + "mysten-metrics", + "narwhal-crypto", + "narwhal-test-utils", + "narwhal-types", + "parking_lot 0.12.1", + "prometheus", + "quinn-proto", + "rand 0.8.5", + "tokio", + "tower", + "tracing", +] [[package]] -name = "predicates-tree" -version = "1.0.7" +name = "narwhal-node" +version = "0.1.0" +dependencies = [ + "anemo", + "arc-swap", + "async-trait", + "axum", + "bytes", + "cfg-if", + "clap", + "eyre", + "fastcrypto", + "futures", + "iota-keys", + "iota-protocol-config", + "iota-types", + "mysten-metrics", + "mysten-network", + "narwhal-config", + "narwhal-crypto", + "narwhal-executor", + "narwhal-network", + "narwhal-primary", + "narwhal-storage", + "narwhal-test-utils", + "narwhal-types", + "narwhal-worker", + "pretty_assertions", + "prometheus", + "rand 0.8.5", + "reqwest", + "serde-reflection", + "serde_yaml 0.8.26", + "telemetry-subscribers", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "tracing-subscriber", + "url", +] + +[[package]] +name = "narwhal-primary" +version = "0.1.0" +dependencies = [ + "anemo", + "anemo-tower", + "anyhow", + "arc-swap", + "async-trait", + "backoff", + "bcs", + "bincode", + "bytes", + "cfg-if", + "criterion", + "dashmap", + "fastcrypto", + "futures", + "governor", + "indexmap 2.2.6", + "iota-macros", + "iota-protocol-config", + "itertools 0.10.5", + "mockall", + "mysten-common", + "mysten-metrics", + "mysten-network", + "narwhal-config", + "narwhal-crypto", + "narwhal-executor", + "narwhal-network", + "narwhal-node", + "narwhal-storage", + "narwhal-test-utils", + "narwhal-types", + "narwhal-worker", + "once_cell", + "parking_lot 0.12.1", + "prometheus", + "proptest", + "rand 0.8.5", + "reqwest", + "tap", + "telemetry-subscribers", + "tempfile", + "thiserror", + "tokio", + "tokio-stream", + "tower", + "tracing", + "typed-store", +] + +[[package]] +name = "narwhal-storage" +version = "0.1.0" +dependencies = [ + "fastcrypto", + "fastcrypto-tbls", + "futures", + "iota-macros", + "lru 0.10.0", + "mysten-common", + "narwhal-config", + "narwhal-test-utils", + "narwhal-types", + "parking_lot 0.12.1", + "prometheus", + "tap", + "tempfile", + "tokio", + "tracing", + "typed-store", +] + +[[package]] +name = "narwhal-test-utils" +version = "0.1.0" +dependencies = [ + "anemo", + "fastcrypto", + "fdlimit", + "indexmap 2.2.6", + "iota-protocol-config", + "itertools 0.10.5", + "mysten-metrics", + "mysten-network", + "narwhal-config", + "narwhal-crypto", + "narwhal-executor", + "narwhal-network", + "narwhal-node", + "narwhal-primary", + "narwhal-storage", + "narwhal-types", + "narwhal-worker", + "once_cell", + "prometheus", + "rand 0.8.5", + "telemetry-subscribers", + "tempfile", + "tokio", + "tonic 0.11.0", + "tracing", + "typed-store", +] + +[[package]] +name = "narwhal-types" +version = "0.1.0" +dependencies = [ + "anemo", + "anemo-build", + "anyhow", + "base64 0.21.2", + "bcs", + "bytes", + "criterion", + "derive_builder", + "enum_dispatch", + "fastcrypto", + "futures", + "indexmap 2.2.6", + "iota-protocol-config", + "mockall", + "mysten-common", + "mysten-metrics", + "mysten-network", + "mysten-util-mem", + "narwhal-config", + "narwhal-crypto", + "narwhal-test-utils", + "once_cell", + "prometheus", + "proptest", + "proptest-derive", + "prost 0.12.3", + "prost-build", + "protobuf-src", + "rand 0.8.5", + "roaring", + "rustversion", + "serde", + "serde_test", + "serde_with", + "thiserror", + "tokio", + "tonic 0.11.0", + "tonic-build", + "tracing", + "typed-store", +] + +[[package]] +name = "narwhal-worker" +version = "0.1.0" +dependencies = [ + "anemo", + "anemo-tower", + "anyhow", + "arc-swap", + "async-trait", + "byteorder", + "bytes", + "eyre", + "fastcrypto", + "futures", + "governor", + "iota-protocol-config", + "itertools 0.10.5", + "mysten-metrics", + "mysten-network", + "narwhal-config", + "narwhal-crypto", + "narwhal-network", + "narwhal-node", + "narwhal-primary", + "narwhal-storage", + "narwhal-test-utils", + "narwhal-types", + "prometheus", + "rand 0.8.5", + "reqwest", + "tap", + "telemetry-subscribers", + "tempfile", + "thiserror", + "tokio", + "tonic 0.11.0", + "tower", + "tracing", + "typed-store", +] + +[[package]] +name = "neptune" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54ff541861505aabf6ea722d2131ee980b8276e10a1297b94e896dd8b621850d" +checksum = "06626c9ac04c894e9a23d061ba1309f28506cdc5fe64156d28a15fb57fc8e438" dependencies = [ - "predicates-core", - "termtree", + "bellpepper", + "bellpepper-core", + "blake2s_simd", + "blstrs", + "byteorder", + "ff 0.13.0", + "generic-array", + "log", + "pasta_curves", + "serde", + "trait-set", ] [[package]] -name = "prefix-hex" -version = "0.7.1" +name = "nested" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f1799f398371ad6957951ec446d3ff322d35c46d9db2e217b67e828b311c249" +checksum = "ca2b420f638f07fe83056b55ea190bb815f609ec5a35e7017884a10f78839c9e" + +[[package]] +name = "newline-converter" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f71d09d5c87634207f894c6b31b6a2b2c64ea3bdcf71bd5599fdbbe1600c00f" dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "nexlint" +version = "0.1.0" +source = "git+https://github.com/nextest-rs/nexlint.git?rev=94da5c787636dad779c340affa65219134d127f5#94da5c787636dad779c340affa65219134d127f5" +dependencies = [ + "camino", + "debug-ignore", + "determinator", + "guppy", + "hakari", "hex", - "primitive-types 0.12.2", - "uint", + "once_cell", + "serde", ] [[package]] -name = "pretty_assertions" -version = "1.3.0" +name = "nexlint-lints" +version = "0.1.0" +source = "git+https://github.com/nextest-rs/nexlint.git?rev=94da5c787636dad779c340affa65219134d127f5#94da5c787636dad779c340affa65219134d127f5" +dependencies = [ + "anyhow", + "camino", + "colored-diff", + "globset", + "guppy", + "nexlint", + "regex", + "serde", + "toml 0.5.10", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" dependencies = [ - "ctor", - "diff", - "output_vt100", - "yansi", + "smallvec", ] [[package]] -name = "prettyplease" -version = "0.1.25" +name = "nix" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" dependencies = [ - "proc-macro2 1.0.78", - "syn 1.0.107", + "bitflags 1.3.2", + "cc", + "cfg-if", + "libc", + "memoffset 0.6.5", ] [[package]] -name = "prettyplease" -version = "0.2.6" +name = "nix" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b69d39aab54d069e7f2fe8cb970493e7834601ca2d8c65fd7bbd183578080d1" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ - "proc-macro2 1.0.78", - "syn 2.0.48", + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.6.5", ] [[package]] -name = "prettytable-rs" -version = "0.10.0" +name = "no-std-compat" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + +[[package]] +name = "nom" +version = "7.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c" dependencies = [ - "csv", - "encode_unicode 1.0.0", - "is-terminal", - "lazy_static", - "term", - "unicode-width", + "memchr", + "minimal-lexical", ] [[package]] -name = "primeorder" -version = "0.13.0" +name = "nonempty" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7613fdcc0831c10060fa69833ea8fa2caa94b6456f51e25356a885b530a2e3d0" +checksum = "995defdca0a589acfdd1bd2e8e3b896b4d4f7675a31fd14c32611440c7f608e6" + +[[package]] +name = "nonzero_ext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "notify" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "elliptic-curve 0.13.4", + "bitflags 2.4.1", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "walkdir", + "windows-sys 0.48.0", ] [[package]] -name = "primitive-types" -version = "0.10.1" +name = "ntapi" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" +checksum = "bc51db7b362b205941f71232e56c625156eb9a929f8cf74a428fd5bc094a4afc" dependencies = [ - "fixed-hash 0.7.0", - "impl-codec 0.5.1", - "impl-serde 0.3.2", - "uint", + "winapi", ] [[package]] -name = "primitive-types" -version = "0.12.2" +name = "ntest" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +checksum = "da8ec6d2b73d45307e926f5af46809768581044384637af6b3f3fe7c3c88f512" dependencies = [ - "fixed-hash 0.8.0", - "impl-codec 0.6.0", - "impl-rlp", - "impl-serde 0.4.0", - "scale-info", - "uint", + "ntest_test_cases", + "ntest_timeout", ] [[package]] -name = "proc-macro-crate" -version = "1.3.1" +name = "ntest_test_cases" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +checksum = "be7d33be719c6f4d09e64e27c1ef4e73485dc4cc1f4d22201f89860a7fe22e22" dependencies = [ - "once_cell", - "toml_edit 0.19.10", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "ntest_timeout" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "066b468120587a402f0b47d8f80035c921f6a46f8209efd0632a89a16f5188a4" dependencies = [ - "proc-macro-error-attr", + "proc-macro-crate", "proc-macro2 1.0.78", "quote 1.0.35", "syn 1.0.107", - "version_check", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "nu-ansi-term" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "version_check", + "overload", + "winapi", ] [[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" +name = "num" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint 0.4.4", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] [[package]] -name = "proc-macro2" -version = "0.4.30" +name = "num-bigint" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" dependencies = [ - "unicode-xid 0.1.0", + "autocfg", + "num-integer", + "num-traits", ] [[package]] -name = "proc-macro2" -version = "1.0.78" +name = "num-bigint" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ - "unicode-ident", + "autocfg", + "num-integer", + "num-traits", + "rand 0.8.5", ] [[package]] -name = "prometheus" -version = "0.13.3" +name = "num-bigint-dig" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" +checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" dependencies = [ - "cfg-if", - "fnv", + "byteorder", "lazy_static", - "memchr", - "parking_lot 0.12.1", - "protobuf", - "thiserror", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", ] [[package]] -name = "prometheus-closure-metric" -version = "0.1.0" +name = "num-complex" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" dependencies = [ - "anyhow", - "prometheus", - "protobuf", + "num-traits", ] [[package]] -name = "prometheus-http-query" -version = "0.6.6" +name = "num-integer" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7970fd6e91b5cb87e9a093657572a896d133879ced7752d2c7635beae29eaba0" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ - "reqwest", - "serde", - "serde_json", - "time", - "url", + "autocfg", + "num-traits", ] [[package]] -name = "prometheus-parse" -version = "0.2.3" -source = "git+https://github.com/asonnino/prometheus-parser.git?rev=75334db#75334dbe2d286edf6d4424abba92a74643333096" +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" dependencies = [ - "chrono", - "itertools 0.10.5", - "lazy_static", - "regex", + "autocfg", + "num-integer", + "num-traits", ] [[package]] -name = "proptest" -version = "1.1.0" +name = "num-rational" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29f1b898011ce9595050a68e60f90bad083ff2987a695a42357134c8381fba70" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ - "bit-set", - "bitflags 1.3.2", - "byteorder", - "lazy_static", + "autocfg", + "num-bigint 0.4.4", + "num-integer", "num-traits", - "quick-error 2.0.1", - "rand 0.8.5", - "rand_chacha 0.3.1", - "rand_xorshift", - "regex-syntax 0.6.28", - "rusty-fork", - "tempfile", - "unarray", ] [[package]] -name = "proptest-derive" -version = "0.3.0" +name = "num-traits" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90b46295382dc76166cb7cf2bb4a97952464e4b7ed5a43e6cd34e1fec3349ddc" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "syn 0.15.44", + "autocfg", + "libm", ] [[package]] -name = "prost" -version = "0.11.9" +name = "num_cpus" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "bytes", - "prost-derive 0.11.9", + "hermit-abi", + "libc", ] [[package]] -name = "prost" -version = "0.12.3" +name = "num_enum" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" dependencies = [ - "bytes", - "prost-derive 0.12.3", + "num_enum_derive 0.5.11", ] [[package]] -name = "prost-build" -version = "0.12.3" +name = "num_enum" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" dependencies = [ - "bytes", - "heck", - "itertools 0.11.0", - "log", - "multimap", - "once_cell", - "petgraph 0.6.2", - "prettyplease 0.2.6", - "prost 0.12.3", - "prost-types", - "regex", - "syn 2.0.48", - "tempfile", - "which", + "num_enum_derive 0.6.1", ] [[package]] -name = "prost-derive" -version = "0.11.9" +name = "num_enum_derive" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ - "anyhow", - "itertools 0.10.5", + "proc-macro-crate", "proc-macro2 1.0.78", "quote 1.0.35", "syn 1.0.107", ] [[package]] -name = "prost-derive" -version = "0.12.3" +name = "num_enum_derive" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" dependencies = [ - "anyhow", - "itertools 0.11.0", + "proc-macro-crate", "proc-macro2 1.0.78", "quote 1.0.35", "syn 2.0.48", ] [[package]] -name = "prost-types" -version = "0.12.3" +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "object" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ - "prost 0.12.3", + "memchr", ] [[package]] -name = "protobuf" -version = "2.28.0" +name = "object_store" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" +checksum = "d359e231e5451f4f9fa889d56e3ce34f8724f1a61db2107739359717cf2bbf08" dependencies = [ + "async-trait", + "base64 0.21.2", "bytes", + "chrono", + "futures", + "humantime", + "hyper", + "itertools 0.10.5", + "parking_lot 0.12.1", + "percent-encoding", + "quick-xml 0.28.2", + "rand 0.8.5", + "reqwest", + "ring 0.16.20", + "rustls-pemfile 1.0.2", + "serde", + "serde_json", + "snafu", + "tokio", + "tracing", + "url", + "walkdir", ] [[package]] -name = "protobuf-src" -version = "1.1.0+21.5" +name = "object_store" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7ac8852baeb3cc6fb83b93646fb93c0ffe5d14bf138c945ceb4b9948ee0e3c1" +checksum = "d139f545f64630e2e3688fd9f81c470888ab01edeb72d13b4e86c566f1130000" dependencies = [ - "autotools", + "async-trait", + "base64 0.21.2", + "bytes", + "chrono", + "futures", + "humantime", + "hyper", + "itertools 0.12.0", + "parking_lot 0.12.1", + "percent-encoding", + "quick-xml 0.31.0", + "rand 0.8.5", + "reqwest", + "ring 0.17.3", + "serde", + "serde_json", + "snafu", + "tokio", + "tracing", + "url", + "walkdir", ] [[package]] -name = "psm" -version = "0.1.21" +name = "oid-registry" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" dependencies = [ - "cc", + "asn1-rs", ] [[package]] -name = "pulldown-cmark" -version = "0.9.6" +name = "once_cell" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" -dependencies = [ - "bitflags 2.4.1", - "memchr", - "unicase", -] +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] -name = "quanta" -version = "0.11.1" +name = "oorandom" +version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" dependencies = [ - "crossbeam-utils", - "libc", - "mach2", - "once_cell", - "raw-cpuid", - "wasi 0.11.0+wasi-snapshot-preview1", - "web-sys", - "winapi", + "arrayvec 0.7.2", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", ] [[package]] -name = "quick-error" -version = "1.2.3" +name = "open-fastrlp-derive" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", +] [[package]] -name = "quick-error" -version = "2.0.1" +name = "openssl-probe" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] -name = "quick-xml" -version = "0.28.2" +name = "opentelemetry" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" +checksum = "5f4b8347cc26099d3aeee044065ecc3ae11469796b4d65d065a23a584ed92a6f" dependencies = [ - "memchr", - "serde", + "opentelemetry_api 0.19.0", + "opentelemetry_sdk 0.19.0", ] [[package]] -name = "quick-xml" -version = "0.31.0" +name = "opentelemetry" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +checksum = "9591d937bc0e6d2feb6f71a559540ab300ea49955229c347a517a28d27784c54" dependencies = [ - "memchr", - "serde", + "opentelemetry_api 0.20.0", + "opentelemetry_sdk 0.20.0", ] [[package]] -name = "quinn" -version = "0.10.1" +name = "opentelemetry-otlp" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21252f1c0fc131f1b69182db8f34837e8a69737b8251dff75636a9be0518c324" +checksum = "7e5e5a5c4135864099f3faafbe939eb4d7f9b80ebf68a8448da961b32a7c1275" dependencies = [ - "bytes", - "futures-io", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls 0.21.6", + "async-trait", + "futures-core", + "http", + "opentelemetry-proto", + "opentelemetry-semantic-conventions", + "opentelemetry_api 0.20.0", + "opentelemetry_sdk 0.20.0", + "prost 0.11.9", "thiserror", "tokio", - "tracing", + "tonic 0.9.2", ] [[package]] -name = "quinn-proto" -version = "0.10.5" +name = "opentelemetry-proto" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c78e758510582acc40acb90458401172d41f1016f8c9dde89e49677afb7eec1" +checksum = "b1e3f814aa9f8c905d0ee4bde026afd3b2577a97c10e1699912e3e44f0c4cbeb" dependencies = [ - "bytes", - "rand 0.8.5", - "ring 0.16.20", - "rustc-hash", - "rustls 0.21.6", - "slab", - "thiserror", - "tinyvec", - "tracing", + "opentelemetry_api 0.20.0", + "opentelemetry_sdk 0.20.0", + "prost 0.11.9", + "tonic 0.9.2", ] [[package]] -name = "quinn-udp" -version = "0.4.0" +name = "opentelemetry-semantic-conventions" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6df19e284d93757a9fb91d63672f7741b129246a669db09d1c0063071debc0c0" +checksum = "73c9f9340ad135068800e7f1b24e9e09ed9e7143f5bf8518ded3d3ec69789269" dependencies = [ - "bytes", - "libc", - "socket2 0.5.6", - "tracing", - "windows-sys 0.48.0", + "opentelemetry 0.20.0", ] [[package]] -name = "quote" -version = "0.6.13" +name = "opentelemetry_api" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +checksum = "ed41783a5bf567688eb38372f2b7a8530f5a607a4b49d38dd7573236c23ca7e2" dependencies = [ - "proc-macro2 0.4.30", + "futures-channel", + "futures-util", + "indexmap 1.9.3", + "once_cell", + "pin-project-lite", + "thiserror", + "urlencoding", ] [[package]] -name = "quote" -version = "1.0.35" +name = "opentelemetry_api" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "8a81f725323db1b1206ca3da8bb19874bbd3f57c3bcd59471bfb04525b265b9b" dependencies = [ - "proc-macro2 1.0.78", + "futures-channel", + "futures-util", + "indexmap 1.9.3", + "js-sys", + "once_cell", + "pin-project-lite", + "thiserror", + "urlencoding", ] [[package]] -name = "r2d2" -version = "0.8.10" +name = "opentelemetry_sdk" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1" dependencies = [ - "log", - "parking_lot 0.12.1", - "scheduled-thread-pool", + "async-trait", + "crossbeam-channel", + "futures-channel", + "futures-executor", + "futures-util", + "once_cell", + "opentelemetry_api 0.19.0", + "percent-encoding", + "rand 0.8.5", + "thiserror", ] [[package]] -name = "radium" -version = "0.6.2" +name = "opentelemetry_sdk" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" +checksum = "fa8e705a0612d48139799fcbaba0d4a90f06277153e43dd2bdc16c6f0edd8026" +dependencies = [ + "async-trait", + "crossbeam-channel", + "futures-channel", + "futures-executor", + "futures-util", + "once_cell", + "opentelemetry_api 0.20.0", + "ordered-float 3.9.1", + "percent-encoding", + "rand 0.8.5", + "regex", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", +] [[package]] -name = "radium" -version = "0.7.0" +name = "option-ext" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] -name = "radix_trie" -version = "0.2.1" +name = "ordered-float" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" dependencies = [ - "endian-type", - "nibble_vec", + "num-traits", ] [[package]] -name = "rand" -version = "0.7.3" +name = "ordered-float" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +checksum = "2a54938017eacd63036332b4ae5c8a49fc8c0c1d6d629893057e4f13609edd06" dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", + "num-traits", ] [[package]] -name = "rand" -version = "0.8.5" +name = "ouroboros" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "e2ba07320d39dfea882faa70554b4bd342a5f273ed59ba7c1c6b4c840492c954" dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", + "aliasable", + "ouroboros_macro", + "static_assertions", ] [[package]] -name = "rand_chacha" -version = "0.2.2" +name = "ouroboros_macro" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "heck", + "proc-macro-error", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "output_vt100" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", + "winapi", ] [[package]] -name = "rand_core" +name = "outref" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] +checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" [[package]] -name = "rand_core" -version = "0.6.4" +name = "overload" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.9", -] +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] -name = "rand_hc" -version = "0.2.0" +name = "owo-colors" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] -name = "rand_pcg" -version = "0.3.1" +name = "owo-colors" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" -dependencies = [ - "rand_core 0.6.4", -] +checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" [[package]] -name = "rand_regex" -version = "0.15.1" +name = "p256" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a9fe2d7d9eeaf3279d1780452a5bbd26b31b27938787ef1c3e930d1e9cfbd" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ - "rand 0.8.5", - "regex-syntax 0.6.28", + "ecdsa 0.16.6", + "elliptic-curve 0.13.4", + "primeorder", + "sha2 0.10.6", ] [[package]] -name = "rand_seeder" -version = "0.2.3" +name = "packable" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2890aaef0aa82719a50e808de264f9484b74b442e1a3a0e5ee38243ac40bdb" +checksum = "11259b086696fc9256f790485d8f14f11f0fa60a60351af9693e3d49fd24fdb6" dependencies = [ - "rand_core 0.6.4", + "autocfg", + "packable-derive", + "primitive-types 0.12.2", + "serde", ] [[package]] -name = "rand_xorshift" -version = "0.3.0" +name = "packable-derive" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +checksum = "e9567693dd2f9a4339cb0a54adfcc0cb431c0ac88b2e46c6ddfb5f5d11a1cc4f" dependencies = [ - "rand_core 0.6.4", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", ] [[package]] -name = "rand_xoshiro" -version = "0.6.0" +name = "pairing" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" dependencies = [ - "rand_core 0.6.4", + "group 0.13.0", ] [[package]] -name = "raw-cpuid" -version = "10.6.0" +name = "papergrid" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6823ea29436221176fe662da99998ad3b4db2c7f31e7b6f5fe43adccd6320bb" +checksum = "ae7891b22598926e4398790c8fe6447930c72a67d36d983a49d6ce682ce83290" dependencies = [ - "bitflags 1.3.2", + "bytecount", + "fnv", + "unicode-width", ] [[package]] -name = "rayon" -version = "1.6.1" +name = "parity-scale-codec" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" dependencies = [ - "either", - "rayon-core", + "arrayvec 0.7.2", + "bitvec 0.20.4", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive 2.3.1", + "serde", ] [[package]] -name = "rayon-core" -version = "1.10.1" +name = "parity-scale-codec" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", + "arrayvec 0.7.2", + "bitvec 1.0.1", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive 3.6.5", + "serde", ] [[package]] -name = "rcgen" -version = "0.9.3" +name = "parity-scale-codec-derive" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" +checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" dependencies = [ - "pem", - "ring 0.16.20", - "time", - "yasna", + "proc-macro-crate", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", ] [[package]] -name = "readonly" -version = "0.2.3" +name = "parity-scale-codec-derive" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78725e4e53781014168628ef49b2dc2fc6ae8d01a08769a5064685d34ee116c" +checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" dependencies = [ + "proc-macro-crate", "proc-macro2 1.0.78", "quote 1.0.35", "syn 1.0.107", ] [[package]] -name = "real_tokio" -version = "1.36.0" -source = "git+https://github.com/mystenmark/tokio-madsim-fork.git?rev=e47aafebf98e9c1734a8848a1876d5946c44bdd1#e47aafebf98e9c1734a8848a1876d5946c44bdd1" +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot 0.12.1", - "pin-project-lite", - "signal-hook-registry", - "socket2 0.5.6", - "tokio-macros 2.2.0 (git+https://github.com/mystenmark/tokio-madsim-fork.git?rev=e47aafebf98e9c1734a8848a1876d5946c44bdd1)", - "windows-sys 0.48.0", + "instant", + "lock_api", + "parking_lot_core 0.8.6", ] [[package]] -name = "redox_syscall" -version = "0.2.16" +name = "parking_lot" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "bitflags 1.3.2", + "lock_api", + "parking_lot_core 0.9.9", ] [[package]] -name = "redox_syscall" -version = "0.3.5" +name = "parking_lot_core" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ - "bitflags 1.3.2", + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] -name = "redox_syscall" -version = "0.4.1" +name = "parking_lot_core" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ - "bitflags 1.3.2", + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets 0.48.0", ] [[package]] -name = "redox_users" -version = "0.4.3" +name = "parquet" +version = "50.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "547b92ebf0c1177e3892f44c8f79757ee62e678d564a9834189725f2c5b7a750" dependencies = [ - "getrandom 0.2.9", - "redox_syscall 0.2.16", - "thiserror", + "ahash 0.8.11", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-ipc", + "arrow-schema", + "arrow-select", + "base64 0.21.2", + "brotli", + "bytes", + "chrono", + "flate2", + "half 2.3.1", + "hashbrown 0.14.3", + "lz4_flex", + "num", + "num-bigint 0.4.4", + "paste", + "seq-macro", + "snap", + "thrift", + "twox-hash", + "zstd 0.13.0", ] [[package]] -name = "ref-cast" -version = "1.0.14" +name = "password-hash" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c78fb8c9293bcd48ef6fce7b4ca950ceaf21210de6e105a883ee280c0f7b9ed" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" dependencies = [ - "ref-cast-impl", + "base64ct", + "rand_core 0.6.4", + "subtle", ] [[package]] -name = "ref-cast-impl" -version = "1.0.14" +name = "pasta_curves" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9c0c92af03644e4806106281fe2e068ac5bc0ae74a707266d06ea27bccee5f" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", + "blake2b_simd", + "ec-gpu", + "ff 0.13.0", + "group 0.13.0", + "hex", + "lazy_static", + "rand 0.8.5", + "serde", + "static_assertions", + "subtle", ] [[package]] -name = "regex" -version = "1.10.4" +name = "paste" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" dependencies = [ - "aho-corasick 1.0.2", - "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.2", + "camino", ] [[package]] -name = "regex-automata" -version = "0.1.10" +name = "pbkdf2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "regex-syntax 0.6.28", + "digest 0.10.7", + "hmac 0.12.1", + "password-hash", + "sha2 0.10.6", ] [[package]] -name = "regex-automata" -version = "0.4.6" +name = "pbkdf2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "f0ca0b5a68607598bf3bad68f32227a8164f6254833f84eafaac409cd6746c31" dependencies = [ - "aho-corasick 1.0.2", - "memchr", - "regex-syntax 0.8.2", + "digest 0.10.7", + "hmac 0.12.1", ] [[package]] -name = "regex-syntax" -version = "0.6.28" +name = "peeking_take_while" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] -name = "regex-syntax" -version = "0.8.2" +name = "pem" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4" +dependencies = [ + "base64 0.13.1", +] [[package]] -name = "reqwest" -version = "0.11.27" +name = "pem-rfc7468" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" dependencies = [ - "async-compression 0.4.6", - "base64 0.21.2", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-rustls 0.24.0", - "ipnet", - "js-sys", - "log", - "mime", - "mime_guess", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls 0.21.6", - "rustls-native-certs", - "rustls-pemfile 1.0.2", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-rustls 0.24.0", - "tokio-util 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "webpki-roots 0.25.2", - "winreg", + "base64ct", ] [[package]] -name = "reqwest-middleware" -version = "0.2.4" +name = "pem-rfc7468" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a3e86aa6053e59030e7ce2d2a3b258dd08fc2d337d52f73f6cb480f5858690" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" dependencies = [ - "anyhow", - "async-trait", - "http", - "reqwest", - "serde", - "task-local-extensions", - "thiserror", + "base64ct", ] [[package]] -name = "reqwest-retry" -version = "0.3.0" +name = "percent-encoding" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af20b65c2ee9746cc575acb6bd28a05ffc0d15e25c992a8f4462d8686aacb4f" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" dependencies = [ - "anyhow", - "async-trait", - "chrono", - "futures", - "getrandom 0.2.9", - "http", - "hyper", - "parking_lot 0.11.2", - "reqwest", - "reqwest-middleware", - "retry-policies", - "task-local-extensions", - "tokio", - "tracing", - "wasm-timer", + "thiserror", + "ucd-trie", ] [[package]] -name = "retain_mut" -version = "0.1.7" +name = "pest_derive" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c31b5c4033f8fdde8700e4657be2c497e7288f01515be52168c631e2e4d4086" +checksum = "96504449aa860c8dcde14f9fba5c58dc6658688ca1fe363589d6327b8662c603" +dependencies = [ + "pest", + "pest_generator", +] [[package]] -name = "retry-policies" -version = "0.2.1" +name = "pest_generator" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17dd00bff1d737c40dbcd47d4375281bf4c17933f9eef0a185fc7bacca23ecbd" +checksum = "798e0220d1111ae63d66cb66a5dcb3fc2d986d520b98e49e1852bfdb11d7c5e7" dependencies = [ - "anyhow", - "chrono", - "rand 0.8.5", + "pest", + "pest_meta", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", ] -[[package]] -name = "rfc6979" -version = "0.3.1" +[[package]] +name = "pest_meta" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +checksum = "984298b75898e30a843e278a9f2452c31e349a073a0ce6fd950a12a74464e065" dependencies = [ - "crypto-bigint 0.4.9", - "hmac 0.12.1", - "zeroize", + "once_cell", + "pest", + "sha1", ] [[package]] -name = "rfc6979" -version = "0.4.0" +name = "petgraph" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" dependencies = [ - "hmac 0.12.1", - "subtle", + "fixedbitset 0.2.0", + "indexmap 1.9.3", ] [[package]] -name = "ring" -version = "0.16.20" +name = "petgraph" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", + "fixedbitset 0.4.2", + "indexmap 1.9.3", ] [[package]] -name = "ring" -version = "0.17.3" +name = "pharos" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babe80d5c16becf6594aa32ad2be8fe08498e7ae60b77de8df700e67f191d7e" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" dependencies = [ - "cc", - "getrandom 0.2.9", - "libc", - "spin 0.9.8", - "untrusted 0.9.0", - "windows-sys 0.48.0", + "futures", + "rustc_version", ] [[package]] -name = "ripemd" -version = "0.1.3" +name = "phf" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" dependencies = [ - "digest 0.10.7", + "phf_macros", + "phf_shared", ] [[package]] -name = "rlp" -version = "0.5.2" +name = "phf_generator" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" dependencies = [ - "bytes", - "rlp-derive", - "rustc-hex", + "phf_shared", + "rand 0.8.5", ] [[package]] -name = "rlp-derive" -version = "0.1.0" +name = "phf_macros" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" dependencies = [ + "phf_generator", + "phf_shared", "proc-macro2 1.0.78", "quote 1.0.35", "syn 1.0.107", ] [[package]] -name = "roaring" -version = "0.10.1" +name = "phf_shared" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef0fb5e826a8bde011ecae6a8539dd333884335c57ff0f003fbe27c25bbe8f71" +checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" dependencies = [ - "bytemuck", - "byteorder", - "retain_mut", + "siphasher", ] [[package]] -name = "rocksdb" -version = "0.21.0" +name = "pin-project" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb6f170a4041d50a0ce04b0d2e14916d6ca863ea2e422689a5b694395d299ffe" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" dependencies = [ - "libc", - "librocksdb-sys", + "pin-project-internal", ] [[package]] -name = "ron" -version = "0.8.0" +name = "pin-project-internal" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ - "base64 0.13.1", - "bitflags 1.3.2", - "serde", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", ] [[package]] -name = "rsa" -version = "0.8.2" +name = "pin-project-lite" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a77d189da1fee555ad95b7e50e7457d91c0e089ec68ca69ad2989413bbdab4" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719" dependencies = [ - "byteorder", - "digest 0.10.7", - "num-bigint-dig", - "num-integer", - "num-iter", - "num-traits", - "pkcs1", + "der 0.6.1", "pkcs8 0.9.0", - "rand_core 0.6.4", - "sha2 0.10.6", - "signature 2.0.0", - "subtle", + "spki 0.6.0", "zeroize", ] [[package]] -name = "rstest" -version = "0.16.0" +name = "pkcs8" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07f2d176c472198ec1e6551dc7da28f1c089652f66a7b722676c2238ebc0edf" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" dependencies = [ - "futures", - "futures-timer", - "rstest_macros", - "rustc_version", + "der 0.6.1", + "spki 0.6.0", ] [[package]] -name = "rstest_macros" -version = "0.16.0" +name = "pkcs8" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7229b505ae0706e64f37ffc54a9c163e11022a6636d58fe1f3f52018257ff9f7" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "cfg-if", - "proc-macro2 1.0.78", - "quote 1.0.35", - "rustc_version", - "syn 1.0.107", - "unicode-ident", + "der 0.7.5", + "spki 0.7.1", ] [[package]] -name = "rusoto_core" -version = "0.48.0" +name = "pkg-config" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db30db44ea73551326269adcf7a2169428a054f14faf9e1768f2163494f2fa2" -dependencies = [ - "async-trait", - "base64 0.13.1", - "bytes", - "crc32fast", - "futures", - "http", - "hyper", - "hyper-rustls 0.23.2", - "lazy_static", - "log", - "rusoto_credential", - "rusoto_signature", - "rustc_version", - "serde", - "serde_json", - "tokio", - "xml-rs", -] +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] -name = "rusoto_credential" -version = "0.48.0" +name = "platforms" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee0a6c13db5aad6047b6a44ef023dbbc21a056b6dab5be3b79ce4283d5c02d05" -dependencies = [ - "async-trait", - "chrono", - "dirs-next", - "futures", - "hyper", - "serde", - "serde_json", - "shlex", - "tokio", - "zeroize", -] +checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" [[package]] -name = "rusoto_kms" -version = "0.48.0" +name = "plotters" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e1fc19cfcfd9f6b2f96e36d5b0dddda9004d2cbfc2d17543e3b9f10cc38fce8" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" dependencies = [ - "async-trait", - "bytes", - "futures", - "rusoto_core", - "serde", - "serde_json", + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", ] [[package]] -name = "rusoto_signature" -version = "0.48.0" +name = "plotters-backend" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ae95491c8b4847931e291b151127eccd6ff8ca13f33603eb3d0035ecb05272" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" + +[[package]] +name = "plotters-svg" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" dependencies = [ - "base64 0.13.1", - "bytes", - "chrono", - "digest 0.9.0", - "futures", - "hex", - "hmac 0.11.0", - "http", - "hyper", - "log", - "md-5 0.9.1", - "percent-encoding", - "pin-project-lite", - "rusoto_credential", - "rustc_version", - "serde", - "sha2 0.9.9", - "tokio", + "plotters-backend", ] [[package]] -name = "russh" -version = "0.38.0" +name = "poly1305" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae0efcc0f4cd6c062c07e572ce4b806e3967fa029fcbfcc0aa98fb5910a37925" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ - "aes", - "aes-gcm", - "async-trait", - "bitflags 2.4.1", - "byteorder", - "chacha20", - "ctr", - "curve25519-dalek 4.1.0", - "digest 0.10.7", - "flate2", - "futures", - "generic-array", - "hex-literal 0.4.1", - "hmac 0.12.1", - "log", - "num-bigint 0.4.4", - "once_cell", - "poly1305", - "rand 0.8.5", - "russh-cryptovec", - "russh-keys", - "sha1", - "sha2 0.10.6", - "subtle", - "thiserror", - "tokio", - "tokio-util 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cpufeatures", + "opaque-debug", + "universal-hash", ] [[package]] -name = "russh-cryptovec" -version = "0.7.0" +name = "polyval" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fdf036c2216b554053d19d4af45c1722d13b00ac494ea19825daf4beac034e" +checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" dependencies = [ - "libc", - "winapi", + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", ] [[package]] -name = "russh-keys" -version = "0.38.0" +name = "portable-atomic" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "557ab9190022dff78116ebed5e391abbd3f424b06cd643dfe262346ab91ed8c9" +checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "pprof" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e20150f965e0e4c925982b9356da71c84bcd56cb66ef4e894825837cbcf6613e" dependencies = [ - "aes", - "async-trait", - "bcrypt-pbkdf", - "bit-vec", - "block-padding 0.3.2", - "byteorder", - "cbc", - "ctr", - "data-encoding", - "dirs 5.0.1", - "ed25519-dalek", - "futures", - "hmac 0.12.1", - "inout", + "backtrace", + "cfg-if", + "findshlibs", + "libc", "log", - "md5", - "num-bigint 0.4.4", - "num-integer", - "pbkdf2 0.11.0", - "rand 0.7.3", - "rand_core 0.6.4", - "russh-cryptovec", - "serde", - "sha2 0.10.6", + "nix 0.24.3", + "once_cell", + "parking_lot 0.12.1", + "smallvec", + "symbolic-demangle", + "tempfile", "thiserror", - "tokio", - "tokio-stream", - "yasna", ] [[package]] -name = "rust-argon2" -version = "1.0.0" +name = "ppv-lite86" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b50162d19404029c1ceca6f6980fe40d45c8b369f6f44446fa14bb39573b5bb9" -dependencies = [ - "base64 0.13.1", - "blake2b_simd", - "constant_time_eq 0.1.5", - "crossbeam-utils", -] +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] -name = "rust_decimal" -version = "1.27.0" +name = "pq-sys" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c321ee4e17d2b7abe12b5d20c1231db708dd36185c8a21e9de5fed6da4dbe9" +checksum = "3b845d6d8ec554f972a2c5298aad68953fd64e7441e846075450b44656a016d1" dependencies = [ - "arrayvec 0.7.2", - "num-traits", + "vcpkg", ] [[package]] -name = "rustc-demangle" -version = "0.1.21" +name = "predicates" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +dependencies = [ + "difflib", + "float-cmp", + "itertools 0.10.5", + "normalize-line-endings", + "predicates-core", + "regex", +] [[package]] -name = "rustc-hash" -version = "1.1.0" +name = "predicates-core" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "72f883590242d3c6fc5bf50299011695fa6590c2c70eac95ee1bdb9a733ad1a2" [[package]] -name = "rustc-hex" -version = "2.1.0" +name = "predicates-tree" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +checksum = "54ff541861505aabf6ea722d2131ee980b8276e10a1297b94e896dd8b621850d" +dependencies = [ + "predicates-core", + "termtree", +] [[package]] -name = "rustc_version" -version = "0.4.0" +name = "prefix-hex" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "1f1799f398371ad6957951ec446d3ff322d35c46d9db2e217b67e828b311c249" dependencies = [ - "semver 1.0.16", + "hex", + "primitive-types 0.12.2", + "uint", ] [[package]] -name = "rusticata-macros" -version = "4.1.0" +name = "pretty_assertions" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" dependencies = [ - "nom", + "ctor", + "diff", + "output_vt100", + "yansi", ] [[package]] -name = "rustix" -version = "0.36.6" +name = "prettyplease" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" dependencies = [ - "bitflags 1.3.2", - "errno 0.2.8", - "io-lifetimes", - "libc", - "linux-raw-sys 0.1.4", - "windows-sys 0.42.0", + "proc-macro2 1.0.78", + "syn 1.0.107", ] [[package]] -name = "rustix" -version = "0.37.7" +name = "prettyplease" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" +checksum = "3b69d39aab54d069e7f2fe8cb970493e7834601ca2d8c65fd7bbd183578080d1" dependencies = [ - "bitflags 1.3.2", - "errno 0.3.8", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.1", - "windows-sys 0.45.0", + "proc-macro2 1.0.78", + "syn 2.0.48", ] [[package]] -name = "rustix" -version = "0.38.28" +name = "prettytable-rs" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a" dependencies = [ - "bitflags 2.4.1", - "errno 0.3.8", - "libc", - "linux-raw-sys 0.4.12", - "windows-sys 0.52.0", + "csv", + "encode_unicode 1.0.0", + "is-terminal", + "lazy_static", + "term", + "unicode-width", ] [[package]] -name = "rustls" -version = "0.20.7" +name = "primeorder" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +checksum = "7613fdcc0831c10060fa69833ea8fa2caa94b6456f51e25356a885b530a2e3d0" dependencies = [ - "log", - "ring 0.16.20", - "sct", - "webpki", + "elliptic-curve 0.13.4", ] [[package]] -name = "rustls" -version = "0.21.6" +name = "primitive-types" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" +checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" dependencies = [ - "log", - "ring 0.16.20", - "rustls-webpki 0.101.7", - "sct", + "fixed-hash 0.7.0", + "impl-codec 0.5.1", + "impl-serde 0.3.2", + "uint", ] [[package]] -name = "rustls" -version = "0.22.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" -dependencies = [ - "log", - "ring 0.17.3", - "rustls-pki-types", - "rustls-webpki 0.102.2", - "subtle", - "zeroize", +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash 0.8.0", + "impl-codec 0.6.0", + "impl-rlp", + "impl-serde 0.4.0", + "scale-info", + "uint", ] [[package]] -name = "rustls-native-certs" -version = "0.6.2" +name = "proc-macro-crate" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ - "openssl-probe", - "rustls-pemfile 1.0.2", - "schannel", - "security-framework", + "once_cell", + "toml_edit 0.19.10", ] [[package]] -name = "rustls-pemfile" -version = "1.0.2" +name = "proc-macro-error" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ - "base64 0.21.2", + "proc-macro-error-attr", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", + "version_check", ] [[package]] -name = "rustls-pemfile" -version = "2.1.1" +name = "proc-macro-error-attr" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f48172685e6ff52a556baa527774f61fcaa884f59daf3375c62a3f1cd2549dab" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "base64 0.21.2", - "rustls-pki-types", + "proc-macro2 1.0.78", + "quote 1.0.35", + "version_check", ] [[package]] -name = "rustls-pki-types" -version = "1.3.1" +name = "proc-macro-hack" +version = "0.5.20+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ede67b28608b4c60685c7d54122d4400d90f62b40caee7700e700380a390fa8" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] -name = "rustls-webpki" -version = "0.100.3" +name = "proc-macro2" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6a5fc258f1c1276dfe3016516945546e2d5383911efc0fc4f1cdc5df3a4ae3" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", + "unicode-xid 0.1.0", ] [[package]] -name = "rustls-webpki" -version = "0.101.7" +name = "proc-macro2" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ - "ring 0.17.3", - "untrusted 0.9.0", + "unicode-ident", ] [[package]] -name = "rustls-webpki" -version = "0.102.2" +name = "prometheus" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" dependencies = [ - "ring 0.17.3", - "rustls-pki-types", - "untrusted 0.9.0", + "cfg-if", + "fnv", + "lazy_static", + "memchr", + "parking_lot 0.12.1", + "protobuf", + "thiserror", ] [[package]] -name = "rustversion" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +name = "prometheus-closure-metric" +version = "0.1.0" +dependencies = [ + "anyhow", + "prometheus", + "protobuf", +] [[package]] -name = "rusty-fork" -version = "0.3.0" +name = "prometheus-http-query" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +checksum = "7970fd6e91b5cb87e9a093657572a896d133879ced7752d2c7635beae29eaba0" dependencies = [ - "fnv", - "quick-error 1.2.3", - "tempfile", - "wait-timeout", + "reqwest", + "serde", + "serde_json", + "time", + "url", ] [[package]] -name = "rustyline" -version = "9.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7826789c0e25614b03e5a54a0717a86f9ff6e6e5247f92b369472869320039" +name = "prometheus-parse" +version = "0.2.3" +source = "git+https://github.com/asonnino/prometheus-parser.git?rev=75334db#75334dbe2d286edf6d4424abba92a74643333096" dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "clipboard-win", - "dirs-next", - "fd-lock", - "libc", - "log", - "memchr", - "nix 0.23.2", - "radix_trie", - "scopeguard", - "smallvec", - "unicode-segmentation", - "unicode-width", - "utf8parse", - "winapi", + "chrono", + "itertools 0.10.5", + "lazy_static", + "regex", ] [[package]] -name = "rustyline-derive" -version = "0.7.0" +name = "proptest" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "107c3d5d7f370ac09efa62a78375f94d94b8a33c61d8c278b96683fb4dbf2d8d" +checksum = "29f1b898011ce9595050a68e60f90bad083ff2987a695a42357134c8381fba70" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", + "bit-set", + "bitflags 1.3.2", + "byteorder", + "lazy_static", + "num-traits", + "quick-error 2.0.1", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_xorshift", + "regex-syntax 0.6.28", + "rusty-fork", + "tempfile", + "unarray", ] [[package]] -name = "ryu" -version = "1.0.12" +name = "proptest-derive" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "90b46295382dc76166cb7cf2bb4a97952464e4b7ed5a43e6cd34e1fec3349ddc" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] [[package]] -name = "salsa20" -version = "0.10.2" +name = "prost" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ - "cipher", + "bytes", + "prost-derive 0.11.9", ] [[package]] -name = "same-file" -version = "1.0.6" +name = "prost" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" dependencies = [ - "winapi-util", + "bytes", + "prost-derive 0.12.3", ] [[package]] -name = "scale-info" -version = "2.10.0" +name = "prost-build" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" +checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" dependencies = [ - "cfg-if", - "derive_more", - "parity-scale-codec 3.6.5", - "scale-info-derive", + "bytes", + "heck", + "itertools 0.11.0", + "log", + "multimap", + "once_cell", + "petgraph 0.6.2", + "prettyplease 0.2.6", + "prost 0.12.3", + "prost-types", + "regex", + "syn 2.0.48", + "tempfile", + "which", ] [[package]] -name = "scale-info-derive" -version = "2.10.0" +name = "prost-derive" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ - "proc-macro-crate", + "anyhow", + "itertools 0.10.5", "proc-macro2 1.0.78", "quote 1.0.35", "syn 1.0.107", ] [[package]] -name = "schannel" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" -dependencies = [ - "windows-sys 0.42.0", -] - -[[package]] -name = "scheduled-thread-pool" -version = "0.2.6" +name = "prost-derive" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "977a7519bff143a44f842fd07e80ad1329295bd71686457f18e496736f4bf9bf" +checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" dependencies = [ - "parking_lot 0.12.1", + "anyhow", + "itertools 0.11.0", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] -name = "schemars" -version = "0.8.12" +name = "prost-types" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" +checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" dependencies = [ - "dyn-clone", - "either", - "schemars_derive", - "serde", - "serde_json", + "prost 0.12.3", ] [[package]] -name = "schemars_derive" -version = "0.8.12" +name = "protobuf" +version = "2.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" +checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "serde_derive_internals", - "syn 1.0.107", + "bytes", ] [[package]] -name = "scopeguard" -version = "1.1.0" +name = "protobuf-src" +version = "1.1.0+21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "c7ac8852baeb3cc6fb83b93646fb93c0ffe5d14bf138c945ceb4b9948ee0e3c1" +dependencies = [ + "autotools", +] [[package]] -name = "scratch" -version = "1.0.3" +name = "psm" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] [[package]] -name = "scrypt" -version = "0.10.0" +name = "pulldown-cmark" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "hmac 0.12.1", - "pbkdf2 0.11.0", - "salsa20", - "sha2 0.10.6", + "bitflags 2.4.1", + "memchr", + "unicase", ] [[package]] -name = "scrypt" -version = "0.11.0" +name = "quanta" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" dependencies = [ - "pbkdf2 0.12.1", - "salsa20", - "sha2 0.10.6", + "crossbeam-utils", + "libc", + "mach2", + "once_cell", + "raw-cpuid", + "wasi 0.11.0+wasi-snapshot-preview1", + "web-sys", + "winapi", ] [[package]] -name = "sct" -version = "0.7.0" +name = "quick-error" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", -] +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] -name = "seahash" -version = "4.1.0" +name = "quick-error" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] -name = "sec1" -version = "0.3.0" +name = "quick-xml" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" dependencies = [ - "base16ct 0.1.1", - "der 0.6.1", - "generic-array", - "subtle", - "zeroize", + "memchr", + "serde", ] [[package]] -name = "sec1" -version = "0.7.1" +name = "quick-xml" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" dependencies = [ - "base16ct 0.2.0", - "der 0.7.5", - "generic-array", - "pkcs8 0.10.2", - "serdect", - "subtle", - "zeroize", + "memchr", + "serde", ] [[package]] -name = "secp256k1" -version = "0.27.0" +name = "quinn" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +checksum = "21252f1c0fc131f1b69182db8f34837e8a69737b8251dff75636a9be0518c324" dependencies = [ - "bitcoin_hashes", - "rand 0.8.5", - "secp256k1-sys", + "bytes", + "futures-io", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.21.6", + "thiserror", + "tokio", + "tracing", ] [[package]] -name = "secp256k1-sys" -version = "0.8.1" +name = "quinn-proto" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +checksum = "2c78e758510582acc40acb90458401172d41f1016f8c9dde89e49677afb7eec1" dependencies = [ - "cc", + "bytes", + "rand 0.8.5", + "ring 0.16.20", + "rustc-hash", + "rustls 0.21.6", + "slab", + "thiserror", + "tinyvec", + "tracing", ] [[package]] -name = "security-framework" -version = "2.7.0" +name = "quinn-udp" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "6df19e284d93757a9fb91d63672f7741b129246a669db09d1c0063071debc0c0" dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", + "bytes", "libc", - "security-framework-sys", + "socket2 0.5.6", + "tracing", + "windows-sys 0.48.0", ] [[package]] -name = "security-framework-sys" -version = "2.6.1" +name = "quote" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" dependencies = [ - "core-foundation-sys", - "libc", + "proc-macro2 0.4.30", ] [[package]] -name = "semver" -version = "0.11.0" +name = "quote" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ - "semver-parser", + "proc-macro2 1.0.78", ] [[package]] -name = "semver" -version = "1.0.16" +name = "r2d2" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" dependencies = [ - "serde", + "log", + "parking_lot 0.12.1", + "scheduled-thread-pool", ] [[package]] -name = "semver-parser" -version = "0.10.2" +name = "radium" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" dependencies = [ - "pest", + "endian-type", + "nibble_vec", ] [[package]] -name = "send_wrapper" -version = "0.4.0" +name = "rand" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] [[package]] -name = "send_wrapper" -version = "0.6.0" +name = "rand" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] [[package]] -name = "seq-macro" -version = "0.3.5" +name = "rand_chacha" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] [[package]] -name = "serde" -version = "1.0.198" +name = "rand_chacha" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ - "serde_derive", + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] -name = "serde-name" -version = "0.2.1" +name = "rand_core" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b5b14ebbcc4e4f2b3642fa99c388649da58d1dc3308c7d109f39f565d1710f0" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "serde", - "thiserror", + "getrandom 0.1.16", ] [[package]] -name = "serde-reflection" -version = "0.3.6" +name = "rand_core" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05a5f801ac62a51a49d378fdb3884480041b99aced450b28990673e8ff99895" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "once_cell", - "serde", - "thiserror", + "getrandom 0.2.9", ] [[package]] -name = "serde_bytes" -version = "0.11.9" +name = "rand_hc" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "serde", + "rand_core 0.5.1", ] [[package]] -name = "serde_derive" -version = "1.0.198" +name = "rand_pcg" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 2.0.48", + "rand_core 0.6.4", ] [[package]] -name = "serde_derive_internals" -version = "0.26.0" +name = "rand_regex" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +checksum = "8b2a9fe2d7d9eeaf3279d1780452a5bbd26b31b27938787ef1c3e930d1e9cfbd" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", + "rand 0.8.5", + "regex-syntax 0.6.28", ] [[package]] -name = "serde_json" -version = "1.0.116" +name = "rand_seeder" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "cf2890aaef0aa82719a50e808de264f9484b74b442e1a3a0e5ee38243ac40bdb" dependencies = [ - "indexmap 2.2.6", - "itoa", - "ryu", - "serde", + "rand_core 0.6.4", ] [[package]] -name = "serde_path_to_error" -version = "0.1.9" +name = "rand_xorshift" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b04f22b563c91331a10074bda3dd5492e3cc39d56bd557e91c0af42b6c7341" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "serde", + "rand_core 0.6.4", ] [[package]] -name = "serde_repr" -version = "0.1.19" +name = "rand_xoshiro" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 2.0.48", + "rand_core 0.6.4", ] [[package]] -name = "serde_spanned" -version = "0.6.2" +name = "raw-cpuid" +version = "10.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +checksum = "a6823ea29436221176fe662da99998ad3b4db2c7f31e7b6f5fe43adccd6320bb" dependencies = [ - "serde", + "bitflags 1.3.2", ] [[package]] -name = "serde_test" -version = "1.0.152" +name = "rayon" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3611210d2d67e3513204742004d6ac6f589e521861dabb0f649b070eea8bed9e" +checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" dependencies = [ - "serde", + "either", + "rayon-core", ] [[package]] -name = "serde_urlencoded" -version = "0.7.1" +name = "rayon-core" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", ] [[package]] -name = "serde_with" -version = "2.1.0" +name = "rcgen" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bf4a5a814902cd1014dbccfa4d4560fb8432c779471e96e035602519f82eef" +checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" dependencies = [ - "base64 0.13.1", - "chrono", - "hex", - "indexmap 1.9.3", - "serde", - "serde_json", - "serde_with_macros", + "pem", + "ring 0.16.20", "time", + "yasna", ] [[package]] -name = "serde_with_macros" -version = "2.1.0" +name = "readonly" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3452b4c0f6c1e357f73fdb87cd1efabaa12acf328c7a528e252893baeb3f4aa" +checksum = "d78725e4e53781014168628ef49b2dc2fc6ae8d01a08769a5064685d34ee116c" dependencies = [ - "darling 0.14.2", "proc-macro2 1.0.78", "quote 1.0.35", "syn 1.0.107", ] [[package]] -name = "serde_yaml" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +name = "real_tokio" +version = "1.36.0" +source = "git+https://github.com/mystenmark/tokio-madsim-fork.git?rev=e47aafebf98e9c1734a8848a1876d5946c44bdd1#e47aafebf98e9c1734a8848a1876d5946c44bdd1" dependencies = [ - "indexmap 1.9.3", - "ryu", - "serde", - "yaml-rust", + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot 0.12.1", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.6", + "tokio-macros 2.2.0 (git+https://github.com/mystenmark/tokio-madsim-fork.git?rev=e47aafebf98e9c1734a8848a1876d5946c44bdd1)", + "windows-sys 0.48.0", ] [[package]] -name = "serde_yaml" -version = "0.9.21" +name = "redox_syscall" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "indexmap 1.9.3", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", + "bitflags 1.3.2", ] [[package]] -name = "serdect" -version = "0.2.0" +name = "redox_syscall" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "base16ct 0.2.0", - "serde", + "bitflags 1.3.2", ] [[package]] -name = "serial_test" -version = "2.0.0" +name = "redox_syscall" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "dashmap", - "futures", - "lazy_static", - "log", - "parking_lot 0.12.1", - "serial_test_derive", + "bitflags 1.3.2", ] [[package]] -name = "serial_test_derive" -version = "2.0.0" +name = "redox_users" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 2.0.48", + "getrandom 0.2.9", + "redox_syscall 0.2.16", + "thiserror", ] [[package]] -name = "sha-1" -version = "0.9.8" +name = "ref-cast" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +checksum = "8c78fb8c9293bcd48ef6fce7b4ca950ceaf21210de6e105a883ee280c0f7b9ed" dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", + "ref-cast-impl", ] [[package]] -name = "sha-1" -version = "0.10.1" +name = "ref-cast-impl" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +checksum = "9f9c0c92af03644e4806106281fe2e068ac5bc0ae74a707266d06ea27bccee5f" dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", ] [[package]] -name = "sha1" -version = "0.10.5" +name = "regex" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", + "aho-corasick 1.0.2", + "memchr", + "regex-automata 0.4.6", + "regex-syntax 0.8.2", ] [[package]] -name = "sha2" -version = "0.9.9" +name = "regex-automata" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", + "regex-syntax 0.6.28", ] [[package]] -name = "sha2" -version = "0.10.6" +name = "regex-automata" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", + "aho-corasick 1.0.2", + "memchr", + "regex-syntax 0.8.2", ] [[package]] -name = "sha3" -version = "0.9.1" +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "regex-syntax" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug", -] +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] -name = "sha3" -version = "0.10.6" +name = "reqwest" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "digest 0.10.7", - "keccak", + "async-compression 0.4.6", + "base64 0.21.2", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls 0.24.0", + "ipnet", + "js-sys", + "log", + "mime", + "mime_guess", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.6", + "rustls-native-certs", + "rustls-pemfile 1.0.2", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-rustls 0.24.0", + "tokio-util 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots 0.25.2", + "winreg", ] [[package]] -name = "sharded-slab" -version = "0.1.4" +name = "reqwest-middleware" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "88a3e86aa6053e59030e7ce2d2a3b258dd08fc2d337d52f73f6cb480f5858690" dependencies = [ - "lazy_static", + "anyhow", + "async-trait", + "http", + "reqwest", + "serde", + "task-local-extensions", + "thiserror", ] [[package]] -name = "shared-crypto" -version = "0.0.0" +name = "reqwest-retry" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9af20b65c2ee9746cc575acb6bd28a05ffc0d15e25c992a8f4462d8686aacb4f" dependencies = [ - "bcs", - "eyre", - "fastcrypto", - "serde", - "serde_repr", + "anyhow", + "async-trait", + "chrono", + "futures", + "getrandom 0.2.9", + "http", + "hyper", + "parking_lot 0.11.2", + "reqwest", + "reqwest-middleware", + "retry-policies", + "task-local-extensions", + "tokio", + "tracing", + "wasm-timer", ] [[package]] -name = "shell-words" -version = "1.1.0" +name = "retain_mut" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +checksum = "8c31b5c4033f8fdde8700e4657be2c497e7288f01515be52168c631e2e4d4086" [[package]] -name = "shellexpand" -version = "3.1.0" +name = "retry-policies" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b" +checksum = "17dd00bff1d737c40dbcd47d4375281bf4c17933f9eef0a185fc7bacca23ecbd" dependencies = [ - "dirs 5.0.1", + "anyhow", + "chrono", + "rand 0.8.5", ] [[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook" -version = "0.3.14" +name = "rfc6979" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ - "libc", - "signal-hook-registry", + "crypto-bigint 0.4.9", + "hmac 0.12.1", + "zeroize", ] [[package]] -name = "signal-hook-mio" -version = "0.2.3" +name = "rfc6979" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "libc", - "mio", - "signal-hook", + "hmac 0.12.1", + "subtle", ] [[package]] -name = "signal-hook-registry" -version = "1.4.0" +name = "ring" +version = "0.16.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" dependencies = [ + "cc", "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", ] [[package]] -name = "signature" -version = "1.6.4" +name = "ring" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +checksum = "9babe80d5c16becf6594aa32ad2be8fe08498e7ae60b77de8df700e67f191d7e" dependencies = [ - "digest 0.10.7", - "rand_core 0.6.4", + "cc", + "getrandom 0.2.9", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.48.0", ] [[package]] -name = "signature" -version = "2.0.0" +name = "ripemd" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" dependencies = [ "digest 0.10.7", - "rand_core 0.6.4", ] [[package]] -name = "similar" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" - -[[package]] -name = "simplelog" -version = "0.9.0" +name = "rlp" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bc0ffd69814a9b251d43afcabf96dad1b29f5028378056257be9e3fecc9f720" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ - "chrono", - "log", - "termcolor", + "bytes", + "rlp-derive", + "rustc-hex", ] [[package]] -name = "simulacrum" +name = "rlp-derive" version = "0.1.0" -dependencies = [ - "anyhow", - "async-trait", - "bcs", - "fastcrypto", - "futures", - "move-binary-format", - "move-bytecode-utils", - "move-core-types", - "once_cell", - "prometheus", - "rand 0.8.5", - "serde", - "shared-crypto", - "sui-config", - "sui-execution", - "sui-framework", - "sui-genesis-builder", - "sui-keys", - "sui-protocol-config", - "sui-storage", - "sui-swarm-config", - "sui-transaction-checks", - "sui-types", - "tracing", -] - -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "sized-chunks" -version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" dependencies = [ - "bitmaps", - "typenum", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", ] [[package]] -name = "skeptic" -version = "0.13.7" +name = "roaring" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" +checksum = "ef0fb5e826a8bde011ecae6a8539dd333884335c57ff0f003fbe27c25bbe8f71" dependencies = [ - "bytecount", - "cargo_metadata 0.14.2", - "error-chain", - "glob", - "pulldown-cmark", - "tempfile", - "walkdir", + "bytemuck", + "byteorder", + "retain_mut", ] [[package]] -name = "slab" -version = "0.4.7" +name = "rocksdb" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "bb6f170a4041d50a0ce04b0d2e14916d6ca863ea2e422689a5b694395d299ffe" dependencies = [ - "autocfg", + "libc", + "librocksdb-sys", ] [[package]] -name = "slip10_ed25519" -version = "0.1.3" +name = "ron" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be0ff28bf14f9610a342169084e87a4f435ad798ec528dc7579a3678fa9dc9a" +checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff" dependencies = [ - "hmac-sha512", + "base64 0.13.1", + "bitflags 1.3.2", + "serde", ] [[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "smawk" -version = "0.3.2" +name = "rsa" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" +checksum = "55a77d189da1fee555ad95b7e50e7457d91c0e089ec68ca69ad2989413bbdab4" +dependencies = [ + "byteorder", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1", + "pkcs8 0.9.0", + "rand_core 0.6.4", + "sha2 0.10.6", + "signature 2.0.0", + "subtle", + "zeroize", +] [[package]] -name = "snafu" -version = "0.7.4" +name = "rstest" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0656e7e3ffb70f6c39b3c2a86332bb74aa3c679da781642590f3c1118c5045" +checksum = "b07f2d176c472198ec1e6551dc7da28f1c089652f66a7b722676c2238ebc0edf" dependencies = [ - "doc-comment", - "snafu-derive", + "futures", + "futures-timer", + "rstest_macros", + "rustc_version", ] [[package]] -name = "snafu-derive" -version = "0.7.4" +name = "rstest_macros" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "475b3bbe5245c26f2d8a6f62d67c1f30eb9fffeccee721c45d162c3ebbdf81b2" +checksum = "7229b505ae0706e64f37ffc54a9c163e11022a6636d58fe1f3f52018257ff9f7" dependencies = [ - "heck", + "cfg-if", "proc-macro2 1.0.78", "quote 1.0.35", + "rustc_version", "syn 1.0.107", + "unicode-ident", ] [[package]] -name = "snap" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" - -[[package]] -name = "snowflake-api" -version = "0.6.0" +name = "rusoto_core" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66ca01bf134469135170a7271c0a31bbfb7da903104857e3dfa671093300683a" +checksum = "1db30db44ea73551326269adcf7a2169428a054f14faf9e1768f2163494f2fa2" dependencies = [ - "arrow", "async-trait", - "base64 0.21.2", + "base64 0.13.1", "bytes", + "crc32fast", "futures", + "http", + "hyper", + "hyper-rustls 0.23.2", + "lazy_static", "log", - "object_store 0.9.0", - "regex", - "reqwest", - "reqwest-middleware", - "reqwest-retry", + "rusoto_credential", + "rusoto_signature", + "rustc_version", "serde", "serde_json", - "thiserror", - "url", - "uuid 1.2.2", + "tokio", + "xml-rs", ] [[package]] -name = "socket2" -version = "0.4.9" +name = "rusoto_credential" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "ee0a6c13db5aad6047b6a44ef023dbbc21a056b6dab5be3b79ce4283d5c02d05" dependencies = [ - "libc", - "winapi", + "async-trait", + "chrono", + "dirs-next", + "futures", + "hyper", + "serde", + "serde_json", + "shlex", + "tokio", + "zeroize", ] [[package]] -name = "socket2" -version = "0.5.6" +name = "rusoto_kms" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "3e1fc19cfcfd9f6b2f96e36d5b0dddda9004d2cbfc2d17543e3b9f10cc38fce8" dependencies = [ - "libc", - "windows-sys 0.52.0", + "async-trait", + "bytes", + "futures", + "rusoto_core", + "serde", + "serde_json", ] [[package]] -name = "soketto" -version = "0.7.1" +name = "rusoto_signature" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" +checksum = "a5ae95491c8b4847931e291b151127eccd6ff8ca13f33603eb3d0035ecb05272" dependencies = [ "base64 0.13.1", "bytes", + "chrono", + "digest 0.9.0", "futures", + "hex", + "hmac 0.11.0", "http", - "httparse", + "hyper", "log", - "rand 0.8.5", - "sha-1 0.9.8", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spinners" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ef947f358b9c238923f764c72a4a9d42f2d637c46e059dbd319d6e7cfb4f82" -dependencies = [ - "lazy_static", - "maplit", - "strum 0.24.1", -] - -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der 0.6.1", + "md-5 0.9.1", + "percent-encoding", + "pin-project-lite", + "rusoto_credential", + "rustc_version", + "serde", + "sha2 0.9.9", + "tokio", ] [[package]] -name = "spki" -version = "0.7.1" +name = "russh" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e" +checksum = "ae0efcc0f4cd6c062c07e572ce4b806e3967fa029fcbfcc0aa98fb5910a37925" dependencies = [ - "base64ct", - "der 0.7.5", + "aes", + "aes-gcm", + "async-trait", + "bitflags 2.4.1", + "byteorder", + "chacha20", + "ctr", + "curve25519-dalek 4.1.0", + "digest 0.10.7", + "flate2", + "futures", + "generic-array", + "hex-literal 0.4.1", + "hmac 0.12.1", + "log", + "num-bigint 0.4.4", + "once_cell", + "poly1305", + "rand 0.8.5", + "russh-cryptovec", + "russh-keys", + "sha1", + "sha2 0.10.6", + "subtle", + "thiserror", + "tokio", + "tokio-util 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "stacker" -version = "0.1.15" +name = "russh-cryptovec" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +checksum = "c3fdf036c2216b554053d19d4af45c1722d13b00ac494ea19825daf4beac034e" dependencies = [ - "cc", - "cfg-if", "libc", - "psm", "winapi", ] [[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "str-buf" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" - -[[package]] -name = "strip-ansi-escapes" -version = "0.1.1" +name = "russh-keys" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" +checksum = "557ab9190022dff78116ebed5e391abbd3f424b06cd643dfe262346ab91ed8c9" dependencies = [ - "vte", + "aes", + "async-trait", + "bcrypt-pbkdf", + "bit-vec", + "block-padding 0.3.2", + "byteorder", + "cbc", + "ctr", + "data-encoding", + "dirs 5.0.1", + "ed25519-dalek", + "futures", + "hmac 0.12.1", + "inout", + "log", + "md5", + "num-bigint 0.4.4", + "num-integer", + "pbkdf2 0.11.0", + "rand 0.7.3", + "rand_core 0.6.4", + "russh-cryptovec", + "serde", + "sha2 0.10.6", + "thiserror", + "tokio", + "tokio-stream", + "yasna", ] [[package]] -name = "stronghold-derive" +name = "rust-argon2" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2835db23c4724c05a2f85b81c4681f4aa8ea158edc8a7f4ad791c916fb766c2e" +checksum = "b50162d19404029c1ceca6f6980fe40d45c8b369f6f44446fa14bb39573b5bb9" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", + "base64 0.13.1", + "blake2b_simd", + "constant_time_eq 0.1.5", + "crossbeam-utils", ] [[package]] -name = "stronghold-runtime" -version = "2.0.0" +name = "rust_decimal" +version = "1.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d20d73c3c41bdfcfa4e223cd6636111723081ef097a8d90354a9846b3bd60ede" +checksum = "33c321ee4e17d2b7abe12b5d20c1231db708dd36185c8a21e9de5fed6da4dbe9" dependencies = [ - "dirs 4.0.0", - "iota-crypto", - "libc", - "libsodium-sys", - "log", - "nix 0.24.3", - "rand 0.8.5", - "serde", - "thiserror", - "windows", - "zeroize", + "arrayvec 0.7.2", + "num-traits", ] [[package]] -name = "stronghold-utils" -version = "1.0.0" +name = "rustc-demangle" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8300214898af5e153e7f66e49dbd1c6a21585f2d592d9f24f58b969792475ed6" -dependencies = [ - "rand 0.8.5", - "stronghold-derive", -] +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] -name = "stronghold_engine" -version = "2.0.0" +name = "rustc-hash" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad9c397e3215857f4f8bd2bd2a5b90c6332d0077d8fb4b6ba61b27b544647ca" -dependencies = [ - "anyhow", - "dirs-next", - "hex", - "iota-crypto", - "once_cell", - "paste", - "serde", - "stronghold-runtime", - "thiserror", - "zeroize", -] +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] -name = "strsim" -version = "0.10.0" +name = "rustc-hex" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" [[package]] -name = "strum" -version = "0.24.1" +name = "rustc_version" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "strum_macros 0.24.3", + "semver 1.0.16", ] [[package]] -name = "strum" -version = "0.25.0" +name = "rusticata-macros" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" dependencies = [ - "strum_macros 0.25.2", + "nom", ] [[package]] -name = "strum_macros" -version = "0.24.3" +name = "rustix" +version = "0.36.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" dependencies = [ - "heck", - "proc-macro2 1.0.78", - "quote 1.0.35", - "rustversion", - "syn 1.0.107", + "bitflags 1.3.2", + "errno 0.2.8", + "io-lifetimes", + "libc", + "linux-raw-sys 0.1.4", + "windows-sys 0.42.0", ] [[package]] -name = "strum_macros" -version = "0.25.2" +name = "rustix" +version = "0.37.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" +checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" dependencies = [ - "heck", - "proc-macro2 1.0.78", - "quote 1.0.35", - "rustversion", - "syn 2.0.48", + "bitflags 1.3.2", + "errno 0.3.8", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.1", + "windows-sys 0.45.0", ] [[package]] -name = "subprocess" -version = "0.2.9" +name = "rustix" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2e86926081dda636c546d8c5e641661049d7562a68f5488be4a1f7f66f6086" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ + "bitflags 2.4.1", + "errno 0.3.8", "libc", - "winapi", + "linux-raw-sys 0.4.12", + "windows-sys 0.52.0", ] [[package]] -name = "subtle" -version = "2.5.0" +name = "rustls" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +dependencies = [ + "log", + "ring 0.16.20", + "sct", + "webpki", +] [[package]] -name = "subtle-ng" -version = "2.5.0" +name = "rustls" +version = "0.21.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" +checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" +dependencies = [ + "log", + "ring 0.16.20", + "rustls-webpki 0.101.7", + "sct", +] [[package]] -name = "sui" -version = "1.22.0" +name = "rustls" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" dependencies = [ - "anemo", - "anyhow", - "assert_cmd", - "async-recursion", - "async-trait", - "bcs", - "bip32", - "camino", - "clap", - "colored", - "const-str", - "csv", - "datatest-stable", - "expect-test", - "fastcrypto", - "fastcrypto-zkp", - "fs_extra", - "git-version", - "im", - "inquire", - "insta", - "jemalloc-ctl", - "json_to_table", - "miette", - "move-binary-format", - "move-command-line-common", - "move-core-types", - "move-package", - "move-vm-profiler", - "msim", - "num-bigint 0.4.4", - "prometheus", - "rand 0.8.5", - "regex", - "reqwest", - "rusoto_core", - "rusoto_kms", - "rustyline", - "rustyline-derive", - "serde", - "serde_json", - "serde_yaml 0.8.26", - "shared-crypto", - "shell-words", - "shlex", - "signature 1.6.4", - "sui-config", - "sui-execution", - "sui-genesis-builder", - "sui-json", - "sui-json-rpc-types", - "sui-keys", - "sui-macros", - "sui-move", - "sui-move-build", - "sui-protocol-config", - "sui-replay", - "sui-sdk", - "sui-simulator", - "sui-source-validation", - "sui-swarm", - "sui-swarm-config", - "sui-test-transaction-builder", - "sui-transaction-builder", - "sui-types", - "tabled", - "tap", - "telemetry-subscribers", - "tempfile", - "test-cluster", - "thiserror", - "tokio", - "tracing", - "unescape", + "log", + "ring 0.17.3", + "rustls-pki-types", + "rustls-webpki 0.102.2", + "subtle", + "zeroize", ] [[package]] -name = "sui-adapter-latest" -version = "0.1.0" +name = "rustls-native-certs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" dependencies = [ - "anyhow", - "bcs", - "leb128", - "move-binary-format", - "move-bytecode-utils", - "move-bytecode-verifier", - "move-core-types", - "move-package", - "move-vm-config", - "move-vm-profiler", - "move-vm-runtime", - "move-vm-types", - "parking_lot 0.12.1", - "serde", - "sui-macros", - "sui-move-natives-latest", - "sui-protocol-config", - "sui-types", - "sui-verifier-latest", - "tracing", + "openssl-probe", + "rustls-pemfile 1.0.2", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +dependencies = [ + "base64 0.21.2", ] [[package]] -name = "sui-adapter-transactional-tests" -version = "0.1.0" +name = "rustls-pemfile" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f48172685e6ff52a556baa527774f61fcaa884f59daf3375c62a3f1cd2549dab" dependencies = [ - "datatest-stable", - "sui-transactional-test-runner", + "base64 0.21.2", + "rustls-pki-types", ] [[package]] -name = "sui-adapter-v0" -version = "0.1.0" +name = "rustls-pki-types" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ede67b28608b4c60685c7d54122d4400d90f62b40caee7700e700380a390fa8" + +[[package]] +name = "rustls-webpki" +version = "0.100.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6a5fc258f1c1276dfe3016516945546e2d5383911efc0fc4f1cdc5df3a4ae3" dependencies = [ - "anyhow", - "bcs", - "leb128", - "move-binary-format", - "move-bytecode-utils", - "move-bytecode-verifier-v0", - "move-core-types", - "move-package", - "move-vm-config", - "move-vm-profiler", - "move-vm-runtime-v0", - "move-vm-types", - "once_cell", - "parking_lot 0.12.1", - "serde", - "sui-macros", - "sui-move-natives-v0", - "sui-protocol-config", - "sui-types", - "sui-verifier-v0", - "tracing", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] -name = "sui-adapter-v1" -version = "0.1.0" +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "anyhow", - "bcs", - "leb128", - "move-binary-format", - "move-bytecode-utils", - "move-bytecode-verifier-v1", - "move-core-types", - "move-package", - "move-vm-config", - "move-vm-profiler", - "move-vm-runtime-v1", - "move-vm-types", - "parking_lot 0.12.1", - "serde", - "sui-macros", - "sui-move-natives-v1", - "sui-protocol-config", - "sui-types", - "sui-verifier-v1", - "tracing", + "ring 0.17.3", + "untrusted 0.9.0", ] [[package]] -name = "sui-adapter-v2" -version = "0.1.0" +name = "rustls-webpki" +version = "0.102.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" dependencies = [ - "anyhow", - "bcs", - "leb128", - "move-binary-format", - "move-bytecode-utils", - "move-bytecode-verifier-v2", - "move-core-types", - "move-package", - "move-vm-config", - "move-vm-profiler", - "move-vm-runtime-v2", - "move-vm-types", - "parking_lot 0.12.1", - "serde", - "sui-macros", - "sui-move-natives-v2", - "sui-protocol-config", - "sui-types", - "sui-verifier-v2", - "tracing", + "ring 0.17.3", + "rustls-pki-types", + "untrusted 0.9.0", ] [[package]] -name = "sui-analytics-indexer" -version = "1.22.0" +name = "rustversion" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" dependencies = [ - "anyhow", - "arrow", - "arrow-array", - "async-trait", - "axum", - "bcs", - "byteorder", - "bytes", - "chrono", - "clap", - "csv", - "eyre", - "fastcrypto", - "gcp-bigquery-client", - "move-binary-format", - "move-bytecode-utils", - "move-core-types", - "mysten-metrics", - "num_enum 0.6.1", - "object_store 0.7.0", - "parquet", - "prometheus", - "rocksdb", - "serde", - "serde_json", - "simulacrum", - "snowflake-api", - "strum 0.24.1", - "strum_macros 0.24.3", - "sui-analytics-indexer-derive", - "sui-config", - "sui-indexer", - "sui-json-rpc-types", - "sui-package-resolver", - "sui-rest-api", - "sui-storage", - "sui-types", - "tap", - "telemetry-subscribers", + "fnv", + "quick-error 1.2.3", "tempfile", - "thiserror", - "tokio", - "tokio-stream", - "tracing", - "typed-store", - "typed-store-derive", - "url", + "wait-timeout", ] [[package]] -name = "sui-analytics-indexer-derive" -version = "1.22.0" +name = "rustyline" +version = "9.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7826789c0e25614b03e5a54a0717a86f9ff6e6e5247f92b369472869320039" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "clipboard-win", + "dirs-next", + "fd-lock", + "libc", + "log", + "memchr", + "nix 0.23.2", + "radix_trie", + "scopeguard", + "smallvec", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "winapi", +] + +[[package]] +name = "rustyline-derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "107c3d5d7f370ac09efa62a78375f94d94b8a33c61d8c278b96683fb4dbf2d8d" dependencies = [ "proc-macro2 1.0.78", "quote 1.0.35", @@ -12114,2317 +13377,1054 @@ dependencies = [ ] [[package]] -name = "sui-archival" -version = "0.1.0" +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" dependencies = [ - "anyhow", - "byteorder", - "bytes", - "ed25519-consensus", - "fastcrypto", - "futures", - "indicatif", - "more-asserts", - "move-binary-format", - "move-core-types", - "move-package", - "num_enum 0.6.1", - "object_store 0.7.0", - "prometheus", - "rand 0.8.5", - "serde", - "serde_json", - "sui-config", - "sui-macros", - "sui-simulator", - "sui-storage", - "sui-swarm-config", - "sui-types", - "telemetry-subscribers", - "tempfile", - "tokio", - "tracing", + "cipher", ] [[package]] -name = "sui-authority-aggregation" -version = "0.1.0" +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ - "futures", - "mysten-metrics", - "sui-types", - "tokio", - "tracing", + "winapi-util", ] [[package]] -name = "sui-aws-orchestrator" -version = "0.0.1" +name = "scale-info" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" dependencies = [ - "async-trait", - "aws-config", - "aws-sdk-ec2", - "aws-smithy-http", - "aws-smithy-runtime-api", - "clap", - "color-eyre", - "crossterm", - "eyre", - "futures", - "mysten-metrics", - "narwhal-config", - "prettytable-rs", - "prometheus-parse", - "reqwest", - "russh", - "russh-keys", - "serde", - "serde_json", - "sui-config", - "sui-swarm-config", - "sui-types", - "tempfile", - "thiserror", - "tokio", + "cfg-if", + "derive_more", + "parity-scale-codec 3.6.5", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" +dependencies = [ + "proc-macro-crate", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", +] + +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", ] [[package]] -name = "sui-benchmark" -version = "0.0.0" +name = "scheduled-thread-pool" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "977a7519bff143a44f842fd07e80ad1329295bd71686457f18e496736f4bf9bf" dependencies = [ - "anyhow", - "async-trait", - "bcs", - "clap", - "comfy-table", - "duration-str", - "fastcrypto-zkp", - "futures", - "hdrhistogram", - "indicatif", - "itertools 0.10.5", - "move-core-types", - "mysten-metrics", - "narwhal-node", - "prometheus", - "rand 0.8.5", - "regex", - "roaring", - "serde", - "serde_json", - "strum 0.24.1", - "strum_macros 0.24.3", - "sui-config", - "sui-core", - "sui-framework", - "sui-framework-snapshot", - "sui-json-rpc-types", - "sui-keys", - "sui-macros", - "sui-network", - "sui-protocol-config", - "sui-sdk", - "sui-simulator", - "sui-storage", - "sui-swarm-config", - "sui-test-transaction-builder", - "sui-types", - "sysinfo", - "telemetry-subscribers", - "test-cluster", - "tokio", - "tokio-util 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tracing", - "typed-store", + "parking_lot 0.12.1", ] [[package]] -name = "sui-bridge" -version = "0.1.0" +name = "schemars" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" dependencies = [ - "anyhow", - "arc-swap", - "async-trait", - "axum", - "backoff", - "bcs", - "clap", - "const-str", - "ethers", - "eyre", - "fastcrypto", - "futures", - "git-version", - "hex-literal 0.3.4", - "lru 0.10.0", - "move-core-types", - "mysten-metrics", - "num_enum 0.6.1", - "once_cell", - "prometheus", - "rand 0.8.5", - "reqwest", - "rocksdb", + "dyn-clone", + "either", + "schemars_derive", "serde", "serde_json", - "serde_with", - "shared-crypto", - "sui-common", - "sui-config", - "sui-json-rpc-types", - "sui-sdk", - "sui-test-transaction-builder", - "sui-types", - "tap", - "telemetry-subscribers", - "tempfile", - "test-cluster", - "tokio", - "tracing", - "typed-store", - "typed-store-derive", - "url", ] [[package]] -name = "sui-cluster-test" -version = "0.1.0" +name = "schemars_derive" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" dependencies = [ - "anyhow", - "async-trait", - "clap", - "derivative", - "fastcrypto", - "futures", - "jsonrpsee", - "move-core-types", - "prometheus", - "regex", - "reqwest", - "serde_json", - "shared-crypto", - "sui", - "sui-config", - "sui-core", - "sui-faucet", - "sui-graphql-rpc", - "sui-indexer", - "sui-json", - "sui-json-rpc-types", - "sui-keys", - "sui-sdk", - "sui-swarm", - "sui-swarm-config", - "sui-test-transaction-builder", - "sui-types", - "telemetry-subscribers", - "tempfile", - "test-cluster", - "tokio", - "tracing", - "uuid 1.2.2", + "proc-macro2 1.0.78", + "quote 1.0.35", + "serde_derive_internals", + "syn 1.0.107", ] [[package]] -name = "sui-common" -version = "0.1.0" +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scratch" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" dependencies = [ - "futures", - "mysten-metrics", - "sui-types", - "tokio", - "tracing", + "hmac 0.12.1", + "pbkdf2 0.11.0", + "salsa20", + "sha2 0.10.6", ] [[package]] -name = "sui-config" -version = "0.0.0" +name = "scrypt" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" dependencies = [ - "anemo", - "anyhow", - "bcs", - "clap", - "csv", - "dirs 4.0.0", - "fastcrypto", - "insta", - "narwhal-config", - "object_store 0.7.0", - "once_cell", - "prometheus", - "rand 0.8.5", - "reqwest", - "serde", - "serde_with", - "serde_yaml 0.8.26", - "sui-keys", - "sui-protocol-config", - "sui-types", - "tempfile", - "tracing", + "pbkdf2 0.12.1", + "salsa20", + "sha2 0.10.6", ] [[package]] -name = "sui-core" -version = "0.1.0" +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "anemo", - "anyhow", - "arc-swap", - "async-trait", - "bcs", - "bytes", - "chrono", - "clap", - "consensus-config", - "consensus-core", - "criterion", - "dashmap", - "diffy", - "either", - "enum_dispatch", - "expect-test", - "eyre", - "fastcrypto", - "fastcrypto-tbls", - "fastcrypto-zkp", - "fs_extra", - "futures", - "im", - "indexmap 2.2.6", - "itertools 0.10.5", - "lru 0.10.0", - "mockall", - "moka", - "more-asserts", - "move-binary-format", - "move-bytecode-utils", - "move-core-types", - "move-package", - "move-symbol-pool", - "mysten-common", - "mysten-metrics", - "mysten-network", - "narwhal-config", - "narwhal-crypto", - "narwhal-executor", - "narwhal-network", - "narwhal-node", - "narwhal-test-utils", - "narwhal-types", - "narwhal-worker", - "num-bigint 0.4.4", - "num_cpus", - "object_store 0.7.0", - "once_cell", - "parking_lot 0.12.1", - "pprof", - "pretty_assertions", - "prometheus", - "rand 0.8.5", - "roaring", - "rocksdb", - "scopeguard", - "serde", - "serde-reflection", - "serde_json", - "serde_with", - "serde_yaml 0.8.26", - "shared-crypto", - "signature 1.6.4", - "static_assertions", - "sui-archival", - "sui-authority-aggregation", - "sui-config", - "sui-execution", - "sui-framework", - "sui-genesis-builder", - "sui-json-rpc-types", - "sui-macros", - "sui-move-build", - "sui-network", - "sui-protocol-config", - "sui-simulator", - "sui-storage", - "sui-swarm-config", - "sui-test-transaction-builder", - "sui-transaction-checks", - "sui-types", - "tap", - "telemetry-subscribers", - "tempfile", - "test-cluster", - "test-fuzz", - "thiserror", - "tokio", - "tokio-retry", - "tokio-stream", - "tracing", - "twox-hash", - "typed-store", - "typed-store-derive", - "zeroize", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] -name = "sui-cost" -version = "0.1.0" +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ - "anyhow", - "bcs", - "insta", - "move-cli", - "move-disassembler", - "serde", - "strum 0.24.1", - "strum_macros 0.24.3", - "sui-config", - "sui-json-rpc-types", - "sui-move-build", - "sui-swarm-config", - "sui-test-transaction-builder", - "sui-types", - "test-cluster", - "tokio", + "base16ct 0.1.1", + "der 0.6.1", + "generic-array", + "subtle", + "zeroize", ] [[package]] -name = "sui-data-ingestion" -version = "0.1.0" +name = "sec1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e" dependencies = [ - "anyhow", - "async-trait", - "aws-config", - "aws-sdk-dynamodb", - "aws-sdk-s3", - "backoff", - "base64-url", - "bcs", - "byteorder", - "bytes", - "futures", - "mysten-metrics", - "notify", - "object_store 0.7.0", - "prometheus", - "rand 0.8.5", - "serde", - "serde_json", - "serde_yaml 0.8.26", - "sui-archival", - "sui-data-ingestion-core", - "sui-storage", - "sui-types", - "telemetry-subscribers", - "tempfile", - "tokio", - "tracing", - "url", + "base16ct 0.2.0", + "der 0.7.5", + "generic-array", + "pkcs8 0.10.2", + "serdect", + "subtle", + "zeroize", ] [[package]] -name = "sui-data-ingestion-core" -version = "0.1.0" +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" dependencies = [ - "anyhow", - "async-trait", - "backoff", - "futures", - "mysten-metrics", - "notify", - "object_store 0.7.0", - "prometheus", + "bitcoin_hashes", "rand 0.8.5", - "serde", - "serde_json", - "sui-storage", - "sui-types", - "tap", - "telemetry-subscribers", - "tempfile", - "tokio", - "tracing", - "url", + "secp256k1-sys", ] [[package]] -name = "sui-e2e-tests" -version = "0.1.0" +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" dependencies = [ - "anyhow", - "assert_cmd", - "async-trait", - "bcs", - "clap", - "expect-test", - "fastcrypto", - "fastcrypto-zkp", - "fs_extra", - "futures", - "indexmap 2.2.6", - "insta", - "jsonrpsee", - "move-binary-format", - "move-core-types", - "move-package", - "mysten-metrics", - "prometheus", - "rand 0.8.5", - "serde", - "serde_json", - "shared-crypto", - "sui", - "sui-config", - "sui-core", - "sui-framework", - "sui-json-rpc", - "sui-json-rpc-api", - "sui-json-rpc-types", - "sui-keys", - "sui-macros", - "sui-move-build", - "sui-node", - "sui-protocol-config", - "sui-sdk", - "sui-simulator", - "sui-storage", - "sui-swarm", - "sui-swarm-config", - "sui-test-transaction-builder", - "sui-tool", - "sui-types", - "telemetry-subscribers", - "tempfile", - "test-cluster", - "tokio", - "tracing", + "cc", ] [[package]] -name = "sui-enum-compat-util" -version = "0.1.0" +name = "security-framework" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" dependencies = [ - "serde_yaml 0.8.26", + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", ] [[package]] -name = "sui-execution" -version = "0.1.0" -dependencies = [ - "cargo_metadata 0.15.4", - "move-binary-format", - "move-bytecode-verifier", - "move-bytecode-verifier-v0", - "move-bytecode-verifier-v1", - "move-bytecode-verifier-v2", - "move-vm-config", - "move-vm-runtime", - "move-vm-runtime-v0", - "move-vm-runtime-v1", - "move-vm-runtime-v2", - "petgraph 0.5.1", - "sui-adapter-latest", - "sui-adapter-v0", - "sui-adapter-v1", - "sui-adapter-v2", - "sui-move-natives-latest", - "sui-move-natives-v0", - "sui-move-natives-v1", - "sui-move-natives-v2", - "sui-protocol-config", - "sui-types", - "sui-verifier-latest", - "sui-verifier-v0", - "sui-verifier-v1", - "sui-verifier-v2", -] - -[[package]] -name = "sui-execution-cut" -version = "0.1.0" +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" dependencies = [ - "anyhow", - "clap", - "expect-test", - "tempfile", - "thiserror", - "toml 0.7.4", - "toml_edit 0.19.10", + "core-foundation-sys", + "libc", ] [[package]] -name = "sui-faucet" -version = "1.22.0" +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ - "anyhow", - "async-recursion", - "async-trait", - "axum", - "clap", - "eyre", - "futures", - "http", - "mysten-metrics", - "parking_lot 0.12.1", - "prometheus", - "rocksdb", - "scopeguard", - "serde", - "shared-crypto", - "sui", - "sui-config", - "sui-json-rpc-types", - "sui-keys", - "sui-sdk", - "sui-types", - "tap", - "telemetry-subscribers", - "tempfile", - "test-cluster", - "thiserror", - "tokio", - "tower", - "tower-http", - "tracing", - "ttl_cache", - "typed-store", - "typed-store-derive", - "uuid 1.2.2", + "semver-parser", ] [[package]] -name = "sui-framework" -version = "0.1.0" +name = "semver" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" dependencies = [ - "anyhow", - "bcs", - "move-binary-format", - "move-compiler", - "move-core-types", - "move-package", - "once_cell", - "regex", "serde", - "sui-move-build", - "sui-types", - "tracing", ] [[package]] -name = "sui-framework-snapshot" -version = "0.1.0" +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" dependencies = [ - "anyhow", - "bcs", - "git-version", - "serde", - "serde_json", - "sui-framework", - "sui-protocol-config", - "sui-types", - "tokio", + "pest", ] [[package]] -name = "sui-framework-tests" -version = "0.1.0" -dependencies = [ - "move-bytecode-verifier", - "move-cli", - "move-package", - "move-unit-test", - "prometheus", - "sui-adapter-latest", - "sui-framework", - "sui-move", - "sui-move-build", - "sui-protocol-config", - "sui-types", - "sui-verifier-latest", -] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" [[package]] -name = "sui-genesis-builder" -version = "0.0.0" -dependencies = [ - "anyhow", - "bcs", - "bigdecimal", - "camino", - "fastcrypto", - "fs_extra", - "hex", - "insta", - "iota-sdk", - "move-binary-format", - "move-core-types", - "move-package", - "move-vm-runtime-v2", - "num-rational", - "packable", - "prometheus", - "rand 0.8.5", - "rand_pcg", - "rand_regex", - "rand_seeder", - "regex", - "schemars", - "serde", - "serde_json", - "serde_with", - "serde_yaml 0.8.26", - "shared-crypto", - "sui-adapter-v2", - "sui-config", - "sui-execution", - "sui-framework", - "sui-framework-snapshot", - "sui-move-build", - "sui-move-natives-v2", - "sui-protocol-config", - "sui-simulator", - "sui-types", - "tempfile", - "thiserror", - "tracing", -] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] -name = "sui-graphql-e2e-tests" -version = "0.1.0" +name = "seq-macro" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" + +[[package]] +name = "serde" +version = "1.0.198" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" dependencies = [ - "datatest-stable", - "msim", - "sui-graphql-rpc", - "sui-transactional-test-runner", - "tokio", + "serde_derive", ] [[package]] -name = "sui-graphql-rpc" -version = "2024.2.0" +name = "serde-name" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b5b14ebbcc4e4f2b3642fa99c388649da58d1dc3308c7d109f39f565d1710f0" dependencies = [ - "anyhow", - "async-graphql", - "async-graphql-axum", - "async-graphql-value", - "async-trait", - "axum", - "bcs", - "chrono", - "clap", - "const-str", - "diesel", - "either", - "expect-test", - "fastcrypto", - "fastcrypto-zkp", - "futures", - "git-version", - "hex", - "http", - "hyper", - "im", - "insta", - "lru 0.10.0", - "markdown-gen", - "move-binary-format", - "move-bytecode-utils", - "move-core-types", - "move-disassembler", - "move-ir-types", - "mysten-metrics", - "mysten-network", - "once_cell", - "prometheus", - "rand 0.8.5", - "regex", - "reqwest", "serde", - "serde_json", - "serde_with", - "serde_yaml 0.8.26", - "serial_test", - "shared-crypto", - "similar", - "simulacrum", - "sui-framework", - "sui-graphql-rpc-client", - "sui-graphql-rpc-headers", - "sui-indexer", - "sui-json-rpc", - "sui-json-rpc-types", - "sui-package-resolver", - "sui-protocol-config", - "sui-rest-api", - "sui-sdk", - "sui-swarm-config", - "sui-types", - "tap", - "telemetry-subscribers", - "test-cluster", "thiserror", - "tokio", - "tokio-util 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.7.4", - "tower", - "tower-http", - "tracing", - "uuid 1.2.2", ] [[package]] -name = "sui-graphql-rpc-client" -version = "0.1.0" +name = "serde-reflection" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05a5f801ac62a51a49d378fdb3884480041b99aced450b28990673e8ff99895" dependencies = [ - "async-graphql", - "axum", - "hyper", - "reqwest", - "serde_json", - "sui-graphql-rpc-headers", + "once_cell", + "serde", "thiserror", ] [[package]] -name = "sui-graphql-rpc-headers" -version = "0.1.0" +name = "serde_bytes" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" dependencies = [ - "axum", + "serde", ] [[package]] -name = "sui-indexer" -version = "1.22.0" +name = "serde_derive" +version = "1.0.198" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" dependencies = [ - "anyhow", - "async-trait", - "axum", - "backoff", - "bcs", - "cached", - "chrono", - "clap", - "criterion", - "diesel", - "diesel-derive-enum", - "diesel_migrations", - "fastcrypto", - "futures", - "itertools 0.10.5", - "jsonrpsee", - "move-binary-format", - "move-bytecode-utils", - "move-core-types", - "mysten-metrics", - "ntest", - "prometheus", - "rayon", - "regex", - "serde", - "serde_json", - "serde_with", - "simulacrum", - "sui-json", - "sui-json-rpc", - "sui-json-rpc-api", - "sui-json-rpc-types", - "sui-keys", - "sui-move-build", - "sui-open-rpc", - "sui-package-resolver", - "sui-protocol-config", - "sui-rest-api", - "sui-sdk", - "sui-test-transaction-builder", - "sui-transaction-builder", - "sui-types", - "tap", - "telemetry-subscribers", - "test-cluster", - "thiserror", - "tokio", - "tracing", - "url", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] -name = "sui-json" -version = "0.0.0" +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ - "anyhow", - "bcs", - "fastcrypto", - "move-binary-format", - "move-bytecode-utils", - "move-core-types", - "schemars", - "serde", - "serde_json", - "sui-framework", - "sui-move-build", - "sui-types", - "test-fuzz", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", ] [[package]] -name = "sui-json-rpc" -version = "0.0.0" +name = "serde_json" +version = "1.0.116" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ - "anyhow", - "arc-swap", - "async-trait", - "axum", - "bcs", - "cached", - "expect-test", - "eyre", - "fastcrypto", - "futures", - "hyper", "indexmap 2.2.6", - "itertools 0.10.5", - "jsonrpsee", - "mockall", - "move-binary-format", - "move-bytecode-utils", - "move-core-types", - "move-package", - "mysten-metrics", - "once_cell", - "prometheus", + "itoa", + "ryu", "serde", - "serde_json", - "shared-crypto", - "signature 1.6.4", - "sui-core", - "sui-json", - "sui-json-rpc-api", - "sui-json-rpc-types", - "sui-open-rpc", - "sui-open-rpc-macros", - "sui-protocol-config", - "sui-storage", - "sui-transaction-builder", - "sui-types", - "tap", - "telemetry-subscribers", - "thiserror", - "tokio", - "tower", - "tower-http", - "tracing", - "typed-store-error", ] [[package]] -name = "sui-json-rpc-api" -version = "0.0.0" +name = "serde_path_to_error" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b04f22b563c91331a10074bda3dd5492e3cc39d56bd557e91c0af42b6c7341" dependencies = [ - "anyhow", - "fastcrypto", - "jsonrpsee", - "mysten-metrics", - "once_cell", - "prometheus", - "sui-json", - "sui-json-rpc-types", - "sui-open-rpc", - "sui-open-rpc-macros", - "sui-types", - "tap", - "tracing", + "serde", ] [[package]] -name = "sui-json-rpc-tests" -version = "0.0.0" +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ - "anyhow", - "async-trait", - "bcs", - "hyper", - "jsonrpsee", - "move-package", - "prometheus", - "rand 0.8.5", - "reqwest", - "sui-config", - "sui-core", - "sui-json", - "sui-json-rpc", - "sui-json-rpc-api", - "sui-json-rpc-types", - "sui-keys", - "sui-macros", - "sui-move-build", - "sui-open-rpc", - "sui-open-rpc-macros", - "sui-protocol-config", - "sui-sdk", - "sui-simulator", - "sui-swarm-config", - "sui-test-transaction-builder", - "sui-types", - "telemetry-subscribers", - "test-cluster", - "tokio", - "tracing", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] -name = "sui-json-rpc-types" -version = "0.0.0" +name = "serde_spanned" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_test" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3611210d2d67e3513204742004d6ac6f589e521861dabb0f649b070eea8bed9e" dependencies = [ - "anyhow", - "bcs", - "colored", - "enum_dispatch", - "fastcrypto", - "itertools 0.10.5", - "json_to_table", - "move-binary-format", - "move-bytecode-utils", - "move-core-types", - "mysten-metrics", - "schemars", "serde", - "serde_json", - "serde_with", - "sui-enum-compat-util", - "sui-json", - "sui-macros", - "sui-protocol-config", - "sui-types", - "tabled", - "tracing", ] [[package]] -name = "sui-keys" -version = "0.0.0" +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ - "anyhow", - "bip32", - "fastcrypto", - "rand 0.8.5", - "regex", + "form_urlencoded", + "itoa", + "ryu", "serde", - "serde_json", - "shared-crypto", - "signature 1.6.4", - "slip10_ed25519", - "sui-types", - "tempfile", - "tiny-bip39", ] [[package]] -name = "sui-light-client" -version = "0.0.0" +name = "serde_with" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25bf4a5a814902cd1014dbccfa4d4560fb8432c779471e96e035602519f82eef" dependencies = [ - "anyhow", - "async-trait", - "bcs", - "bytes", - "clap", - "move-binary-format", - "move-core-types", + "base64 0.13.1", + "chrono", + "hex", + "indexmap 1.9.3", "serde", "serde_json", - "serde_yaml 0.8.26", - "sui-config", - "sui-json", - "sui-json-rpc-types", - "sui-package-resolver", - "sui-rest-api", - "sui-sdk", - "sui-types", - "tokio", + "serde_with_macros", + "time", ] [[package]] -name = "sui-macros" -version = "0.7.0" +name = "serde_with_macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3452b4c0f6c1e357f73fdb87cd1efabaa12acf328c7a528e252893baeb3f4aa" dependencies = [ - "futures", - "once_cell", - "sui-proc-macros", - "tracing", + "darling 0.14.2", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", ] [[package]] -name = "sui-metric-checker" -version = "0.0.0" +name = "serde_yaml" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" dependencies = [ - "anyhow", - "backoff", - "base64 0.21.2", - "chrono", - "clap", - "humantime", - "once_cell", - "prometheus-http-query", - "reqwest", + "indexmap 1.9.3", + "ryu", "serde", - "serde_yaml 0.9.21", - "strum_macros 0.24.3", - "telemetry-subscribers", - "tokio", - "tracing", + "yaml-rust", ] [[package]] -name = "sui-move" -version = "1.22.0" +name = "serde_yaml" +version = "0.9.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" dependencies = [ - "anyhow", - "assert_cmd", - "clap", - "colored", - "const-str", - "futures", - "git-version", - "jemalloc-ctl", - "jsonrpsee", - "move-binary-format", - "move-cli", - "move-compiler", - "move-disassembler", - "move-ir-types", - "move-package", - "move-prover", - "move-unit-test", - "move-vm-runtime", - "mysten-metrics", - "once_cell", - "prometheus", - "rand 0.8.5", - "serde_json", - "serde_yaml 0.8.26", - "sui-core", - "sui-macros", - "sui-move-build", - "sui-move-natives-latest", - "sui-node", - "sui-protocol-config", - "sui-simulator", - "sui-types", - "telemetry-subscribers", - "tempfile", - "tokio", - "tracing", + "indexmap 1.9.3", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", ] [[package]] -name = "sui-move-build" -version = "1.22.0" +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" dependencies = [ - "anyhow", - "datatest-stable", - "fastcrypto", - "move-binary-format", - "move-bytecode-utils", - "move-bytecode-verifier", - "move-command-line-common", - "move-compiler", - "move-core-types", - "move-ir-types", - "move-package", - "move-symbol-pool", - "serde-reflection", - "sui-protocol-config", - "sui-types", - "sui-verifier-latest", - "tempfile", + "base16ct 0.2.0", + "serde", ] [[package]] -name = "sui-move-natives-latest" -version = "0.1.0" +name = "serial_test" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" dependencies = [ - "bcs", - "better_any", - "fastcrypto", - "fastcrypto-zkp", - "indexmap 2.2.6", - "move-binary-format", - "move-core-types", - "move-stdlib", - "move-vm-runtime", - "move-vm-types", - "smallvec", - "sui-protocol-config", - "sui-types", - "tracing", + "dashmap", + "futures", + "lazy_static", + "log", + "parking_lot 0.12.1", + "serial_test_derive", ] [[package]] -name = "sui-move-natives-v0" -version = "0.1.0" +name = "serial_test_derive" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ - "bcs", - "better_any", - "fastcrypto", - "fastcrypto-zkp", - "linked-hash-map", - "move-binary-format", - "move-core-types", - "move-stdlib-v0", - "move-vm-runtime-v0", - "move-vm-types", - "smallvec", - "sui-protocol-config", - "sui-types", - "tracing", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] -name = "sui-move-natives-v1" -version = "0.1.0" +name = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ - "bcs", - "better_any", - "fastcrypto", - "fastcrypto-zkp", - "linked-hash-map", - "move-binary-format", - "move-core-types", - "move-stdlib-v1", - "move-vm-runtime-v1", - "move-vm-types", - "smallvec", - "sui-protocol-config", - "sui-types", - "tracing", + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", ] [[package]] -name = "sui-move-natives-v2" -version = "0.1.0" +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" dependencies = [ - "bcs", - "better_any", - "fastcrypto", - "fastcrypto-zkp", - "indexmap 2.2.6", - "move-binary-format", - "move-core-types", - "move-stdlib-v2", - "move-vm-runtime-v2", - "move-vm-types", - "smallvec", - "sui-protocol-config", - "sui-types", - "tracing", + "cfg-if", + "cpufeatures", + "digest 0.10.7", ] [[package]] -name = "sui-network" -version = "0.0.0" +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ - "anemo", - "anemo-build", - "anemo-tower", - "anyhow", - "arc-swap", - "bcs", - "bytes", - "dashmap", - "ed25519-consensus", - "fastcrypto", - "fastcrypto-tbls", - "futures", - "governor", - "mysten-metrics", - "mysten-network", - "prometheus", - "rand 0.8.5", - "serde", - "sui-archival", - "sui-config", - "sui-storage", - "sui-swarm-config", - "sui-types", - "tap", - "telemetry-subscribers", - "tempfile", - "tokio", - "tonic 0.11.0", - "tonic-build", - "tower", - "tracing", + "cfg-if", + "cpufeatures", + "digest 0.10.7", ] [[package]] -name = "sui-node" -version = "1.22.0" +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ - "anemo", - "anemo-tower", - "anyhow", - "arc-swap", - "axum", - "clap", - "const-str", - "fastcrypto", - "fastcrypto-zkp", - "futures", - "git-version", - "humantime", - "move-vm-profiler", - "mysten-common", - "mysten-metrics", - "mysten-network", - "narwhal-network", - "narwhal-worker", - "prometheus", - "reqwest", - "serde", - "snap", - "sui-archival", - "sui-config", - "sui-core", - "sui-json-rpc", - "sui-json-rpc-api", - "sui-macros", - "sui-network", - "sui-protocol-config", - "sui-rest-api", - "sui-simulator", - "sui-snapshot", - "sui-storage", - "sui-telemetry", - "sui-tls", - "sui-types", - "tap", - "telemetry-subscribers", - "tokio", - "tower", - "tracing", - "typed-store", - "url", + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", ] [[package]] -name = "sui-open-rpc" -version = "1.22.0" +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ - "anyhow", - "bcs", - "clap", - "fastcrypto", - "move-core-types", - "pretty_assertions", - "rand 0.8.5", - "schemars", - "serde", - "serde_json", - "sui-json", - "sui-json-rpc", - "sui-json-rpc-api", - "sui-json-rpc-types", - "sui-protocol-config", - "sui-types", - "tokio", - "versions", + "cfg-if", + "cpufeatures", + "digest 0.10.7", ] [[package]] -name = "sui-open-rpc-macros" -version = "0.1.0" +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" dependencies = [ - "derive-syn-parse", - "itertools 0.10.5", - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", - "unescape", + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", ] [[package]] -name = "sui-oracle" -version = "1.22.0" +name = "sha3" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" dependencies = [ - "anyhow", - "bcs", - "chrono", - "clap", - "dirs 4.0.0", - "jsonpath_lib", - "mysten-metrics", - "once_cell", - "prometheus", - "rand 0.8.5", - "reqwest", - "serde", - "serde_json", - "shared-crypto", - "sui-config", - "sui-json-rpc-types", - "sui-keys", - "sui-move-build", - "sui-sdk", - "sui-types", - "tap", - "telemetry-subscribers", - "tokio", - "tracing", + "digest 0.10.7", + "keccak", ] [[package]] -name = "sui-package-resolver" -version = "0.1.0" +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shared-crypto" +version = "0.0.0" dependencies = [ - "async-trait", "bcs", "eyre", - "hyper", - "insta", - "lru 0.10.0", - "move-binary-format", - "move-compiler", - "move-core-types", + "fastcrypto", "serde", - "serde_json", - "sui-move-build", - "sui-rest-api", - "sui-types", - "thiserror", - "tokio", - "tower", + "serde_repr", ] [[package]] -name = "sui-proc-macros" -version = "0.7.0" +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "shellexpand" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b" dependencies = [ - "msim-macros", - "proc-macro2 1.0.78", - "quote 1.0.35", - "sui-enum-compat-util", - "syn 2.0.48", + "dirs 5.0.1", ] [[package]] -name = "sui-protocol-config" -version = "0.1.0" +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" dependencies = [ - "clap", - "insta", - "schemars", - "serde", - "serde_with", - "sui-protocol-config-macros", - "tracing", + "libc", + "signal-hook-registry", ] [[package]] -name = "sui-protocol-config-macros" -version = "0.1.0" +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", - "syn 1.0.107", + "libc", + "mio", + "signal-hook", ] [[package]] -name = "sui-proxy" -version = "0.0.2" +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ - "anyhow", - "axum", - "axum-server", - "bytes", - "clap", - "const-str", - "fastcrypto", - "git-version", - "hex", - "http-body", - "hyper", - "ipnetwork", - "itertools 0.10.5", - "mime", - "multiaddr", - "mysten-metrics", - "once_cell", - "prometheus", - "prost 0.12.3", - "prost-build", - "protobuf", - "rand 0.8.5", - "reqwest", - "rustls 0.21.6", - "rustls-pemfile 1.0.2", - "serde", - "serde_json", - "serde_with", - "serde_yaml 0.8.26", - "snap", - "sui-tls", - "sui-types", - "telemetry-subscribers", - "tokio", - "tower", - "tower-http", - "tracing", + "libc", ] [[package]] -name = "sui-replay" -version = "0.1.0" +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ - "anyhow", - "async-recursion", - "async-trait", - "bcs", - "clap", - "futures", - "http", - "jsonrpsee", - "lru 0.10.0", - "move-binary-format", - "move-bytecode-utils", - "move-core-types", - "move-vm-config", - "parking_lot 0.12.1", - "prometheus", - "rand 0.8.5", - "serde", - "serde_json", - "serde_with", - "serde_yaml 0.8.26", - "shared-crypto", - "shellexpand", - "similar", - "sui-config", - "sui-core", - "sui-execution", - "sui-framework", - "sui-json-rpc", - "sui-json-rpc-api", - "sui-json-rpc-types", - "sui-protocol-config", - "sui-sdk", - "sui-storage", - "sui-types", - "tabled", - "tempfile", - "thiserror", - "tokio", - "tracing", + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "signature" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", ] [[package]] -name = "sui-rest-api" -version = "0.1.0" +name = "similar" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" + +[[package]] +name = "simplelog" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bc0ffd69814a9b251d43afcabf96dad1b29f5028378056257be9e3fecc9f720" dependencies = [ - "anyhow", - "axum", - "bcs", - "fastcrypto", - "mime", - "rand 0.8.5", - "reqwest", - "serde", - "serde_json", - "serde_with", - "sui-types", - "tap", - "thiserror", - "tokio", + "chrono", + "log", + "termcolor", ] [[package]] -name = "sui-rosetta" +name = "simulacrum" version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "axum", - "axum-extra", "bcs", - "clap", - "eyre", "fastcrypto", "futures", - "hyper", + "iota-config", + "iota-execution", + "iota-framework", + "iota-genesis-builder", + "iota-keys", + "iota-protocol-config", + "iota-storage", + "iota-swarm-config", + "iota-transaction-checks", + "iota-types", + "move-binary-format", + "move-bytecode-utils", "move-core-types", - "mysten-metrics", "once_cell", + "prometheus", "rand 0.8.5", - "reqwest", "serde", - "serde_json", "shared-crypto", - "signature 1.6.4", - "strum 0.24.1", - "strum_macros 0.24.3", - "sui-config", - "sui-json-rpc-types", - "sui-keys", - "sui-move-build", - "sui-node", - "sui-sdk", - "sui-swarm-config", - "sui-types", - "telemetry-subscribers", - "tempfile", - "test-cluster", - "thiserror", - "tokio", "tracing", - "typed-store", ] [[package]] -name = "sui-rpc-loadgen" -version = "1.22.0" -dependencies = [ - "anyhow", - "async-trait", - "clap", - "dashmap", - "dirs 4.0.0", - "futures", - "itertools 0.10.5", - "serde", - "serde_json", - "shared-crypto", - "shellexpand", - "strum 0.24.1", - "strum_macros 0.24.3", - "sui-json-rpc", - "sui-json-rpc-types", - "sui-keys", - "sui-sdk", - "sui-types", - "telemetry-subscribers", - "test-cluster", - "tokio", - "tonic 0.11.0", - "tracing", -] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] -name = "sui-sdk" -version = "1.22.0" +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" dependencies = [ - "anyhow", - "async-recursion", - "async-trait", - "bcs", - "clap", - "colored", - "dirs 4.0.0", - "fastcrypto", - "futures", - "futures-core", - "jsonrpsee", - "move-core-types", - "rand 0.8.5", - "reqwest", - "serde", - "serde_json", - "serde_with", - "shared-crypto", - "sui-config", - "sui-json", - "sui-json-rpc-api", - "sui-json-rpc-types", - "sui-keys", - "sui-transaction-builder", - "sui-types", - "tempfile", - "thiserror", - "tokio", - "tracing", + "bitmaps", + "typenum", ] [[package]] -name = "sui-simulator" -version = "0.7.0" +name = "skeptic" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" dependencies = [ - "anemo", - "anemo-tower", - "bcs", - "fastcrypto", - "lru 0.10.0", - "move-package", - "msim", - "narwhal-network", - "rand 0.8.5", - "serde", - "sui-framework", - "sui-move-build", - "sui-types", - "telemetry-subscribers", + "bytecount", + "cargo_metadata 0.14.2", + "error-chain", + "glob", + "pulldown-cmark", "tempfile", - "tower", - "tracing", + "walkdir", ] [[package]] -name = "sui-single-node-benchmark" -version = "0.1.0" +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" dependencies = [ - "async-trait", - "bcs", - "clap", - "fs_extra", - "futures", - "move-binary-format", - "move-bytecode-utils", - "move-core-types", - "move-package", - "once_cell", - "prometheus", - "serde", - "serde_json", - "strum 0.24.1", - "strum_macros 0.24.3", - "sui-config", - "sui-core", - "sui-macros", - "sui-move-build", - "sui-protocol-config", - "sui-simulator", - "sui-storage", - "sui-test-transaction-builder", - "sui-transaction-checks", - "sui-types", - "telemetry-subscribers", - "tokio", - "tracing", + "autocfg", ] [[package]] -name = "sui-snapshot" -version = "0.1.0" +name = "slip10_ed25519" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be0ff28bf14f9610a342169084e87a4f435ad798ec528dc7579a3678fa9dc9a" dependencies = [ - "anyhow", - "bcs", - "byteorder", - "bytes", - "fastcrypto", - "futures", - "indicatif", - "integer-encoding", - "num_enum 0.6.1", - "object_store 0.7.0", - "prometheus", - "serde", - "serde_json", - "sui-config", - "sui-core", - "sui-protocol-config", - "sui-storage", - "sui-types", - "tempfile", - "tokio", - "tokio-stream", - "tracing", + "hmac-sha512", ] [[package]] -name = "sui-source-validation" -version = "1.22.0" +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + +[[package]] +name = "snafu" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0656e7e3ffb70f6c39b3c2a86332bb74aa3c679da781642590f3c1118c5045" dependencies = [ - "anyhow", - "colored", - "expect-test", - "flate2", - "futures", - "move-binary-format", - "move-bytecode-source-map", - "move-command-line-common", - "move-compiler", - "move-core-types", - "move-package", - "move-symbol-pool", - "rand 0.8.5", - "sui-json-rpc-types", - "sui-move-build", - "sui-sdk", - "sui-test-transaction-builder", - "sui-types", - "tar", - "tempfile", - "test-cluster", - "thiserror", - "tokio", - "tracing", - "ureq", + "doc-comment", + "snafu-derive", ] [[package]] -name = "sui-source-validation-service" -version = "0.1.0" +name = "snafu-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "475b3bbe5245c26f2d8a6f62d67c1f30eb9fffeccee721c45d162c3ebbdf81b2" dependencies = [ - "anyhow", - "axum", - "clap", - "const-str", - "expect-test", - "fs_extra", - "git-version", - "hyper", - "jsonrpsee", - "move-compiler", - "move-core-types", - "move-package", - "move-symbol-pool", - "mysten-metrics", - "prometheus", - "reqwest", - "serde", - "sui", - "sui-json-rpc-types", - "sui-move", - "sui-move-build", - "sui-sdk", - "sui-source-validation", - "telemetry-subscribers", - "tempfile", - "test-cluster", - "tokio", - "toml 0.7.4", - "tower", - "tower-http", - "tracing", - "url", + "heck", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", ] [[package]] -name = "sui-storage" -version = "0.1.0" +name = "snap" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" + +[[package]] +name = "snowflake-api" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66ca01bf134469135170a7271c0a31bbfb7da903104857e3dfa671093300683a" dependencies = [ - "anyhow", + "arrow", "async-trait", - "backoff", - "base64-url", - "bcs", - "byteorder", + "base64 0.21.2", "bytes", - "chrono", - "clap", - "criterion", - "eyre", - "fastcrypto", "futures", - "hyper", - "hyper-rustls 0.24.0", - "indicatif", - "integer-encoding", - "itertools 0.10.5", - "lru 0.10.0", - "move-binary-format", - "move-bytecode-utils", - "move-core-types", - "mysten-metrics", - "num_cpus", - "num_enum 0.6.1", - "object_store 0.7.0", - "once_cell", - "parking_lot 0.12.1", - "percent-encoding", - "pretty_assertions", - "prometheus", + "log", + "object_store 0.9.0", + "regex", "reqwest", - "rocksdb", + "reqwest-middleware", + "reqwest-retry", "serde", "serde_json", - "sui-config", - "sui-json-rpc-types", - "sui-macros", - "sui-protocol-config", - "sui-simulator", - "sui-test-transaction-builder", - "sui-types", - "tap", - "telemetry-subscribers", - "tempfile", - "tokio", - "tracing", - "typed-store", - "typed-store-derive", + "thiserror", "url", - "zstd 0.12.3+zstd.1.5.2", + "uuid 1.2.2", ] [[package]] -name = "sui-surfer" -version = "1.22.0" +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ - "async-trait", - "bcs", - "clap", - "futures", - "indexmap 2.2.6", - "move-binary-format", - "move-core-types", - "move-package", - "prometheus", - "rand 0.8.5", - "sui-core", - "sui-json-rpc-types", - "sui-macros", - "sui-move-build", - "sui-protocol-config", - "sui-simulator", - "sui-swarm-config", - "sui-types", - "telemetry-subscribers", - "test-cluster", - "tokio", - "tracing", + "libc", + "winapi", ] [[package]] -name = "sui-swarm" -version = "0.0.0" +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ - "anyhow", - "futures", - "mysten-metrics", - "mysten-network", - "prometheus", - "rand 0.8.5", - "sui-config", - "sui-macros", - "sui-node", - "sui-protocol-config", - "sui-simulator", - "sui-swarm-config", - "sui-types", - "tap", - "telemetry-subscribers", - "tempfile", - "tokio", - "tonic-health", - "tracing", + "libc", + "windows-sys 0.52.0", ] [[package]] -name = "sui-swarm-config" -version = "0.0.0" +name = "soketto" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ - "anemo", - "anyhow", - "fastcrypto", - "insta", - "move-bytecode-utils", - "narwhal-config", - "prometheus", + "base64 0.13.1", + "bytes", + "futures", + "http", + "httparse", + "log", "rand 0.8.5", - "serde", - "serde_with", - "serde_yaml 0.8.26", - "shared-crypto", - "sui-config", - "sui-execution", - "sui-genesis-builder", - "sui-macros", - "sui-protocol-config", - "sui-simulator", - "sui-types", - "tempfile", - "tracing", + "sha-1 0.9.8", ] [[package]] -name = "sui-telemetry" -version = "0.1.0" +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spinners" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0ef947f358b9c238923f764c72a4a9d42f2d637c46e059dbd319d6e7cfb4f82" dependencies = [ - "reqwest", - "serde", - "sui-core", - "tracing", + "lazy_static", + "maplit", + "strum 0.24.1", ] [[package]] -name = "sui-test-transaction-builder" -version = "0.1.0" +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ - "bcs", - "move-core-types", - "shared-crypto", - "sui-genesis-builder", - "sui-move-build", - "sui-sdk", - "sui-types", + "base64ct", + "der 0.6.1", ] [[package]] -name = "sui-test-validator" -version = "0.0.0" +name = "spki" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e" dependencies = [ - "anyhow", - "axum", - "clap", - "http", - "sui-cluster-test", - "sui-faucet", - "telemetry-subscribers", - "tokio", - "tower", - "tower-http", - "uuid 1.2.2", + "base64ct", + "der 0.7.5", ] [[package]] -name = "sui-tls" -version = "0.0.0" +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "stacker" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" dependencies = [ - "anyhow", - "axum", - "axum-server", - "ed25519 1.5.3", - "fastcrypto", - "pkcs8 0.9.0", - "rand 0.8.5", - "rcgen", - "reqwest", - "rustls 0.21.6", - "rustls-webpki 0.101.7", - "tokio", - "tokio-rustls 0.24.0", - "tower-layer", - "x509-parser", + "cc", + "cfg-if", + "libc", + "psm", + "winapi", ] [[package]] -name = "sui-tool" -version = "1.22.0" +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "str-buf" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" + +[[package]] +name = "strip-ansi-escapes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" dependencies = [ - "anemo", - "anemo-cli", - "anyhow", - "bcs", - "clap", - "colored", - "comfy-table", - "const-str", - "diesel", - "eyre", - "fastcrypto", - "futures", - "git-version", - "hex", - "indicatif", - "itertools 0.10.5", - "move-core-types", - "narwhal-storage", - "narwhal-types", - "num_cpus", - "object_store 0.7.0", - "prometheus", - "rocksdb", - "ron", - "serde", - "serde_json", - "strum 0.24.1", - "strum_macros 0.24.3", - "sui-archival", - "sui-config", - "sui-core", - "sui-indexer", - "sui-network", - "sui-protocol-config", - "sui-replay", - "sui-sdk", - "sui-snapshot", - "sui-storage", - "sui-types", - "telemetry-subscribers", - "tempfile", - "tokio", - "tracing", - "typed-store", + "vte", ] [[package]] -name = "sui-transaction-builder" -version = "0.0.0" +name = "stronghold-derive" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2835db23c4724c05a2f85b81c4681f4aa8ea158edc8a7f4ad791c916fb766c2e" dependencies = [ - "anyhow", - "async-trait", - "bcs", - "futures", - "move-binary-format", - "move-core-types", - "sui-json", - "sui-json-rpc-types", - "sui-protocol-config", - "sui-types", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.107", ] [[package]] -name = "sui-transaction-checks" -version = "0.1.0" +name = "stronghold-runtime" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d20d73c3c41bdfcfa4e223cd6636111723081ef097a8d90354a9846b3bd60ede" dependencies = [ - "fastcrypto-zkp", - "once_cell", - "sui-config", - "sui-execution", - "sui-macros", - "sui-protocol-config", - "sui-types", - "tracing", + "dirs 4.0.0", + "iota-crypto", + "libc", + "libsodium-sys", + "log", + "nix 0.24.3", + "rand 0.8.5", + "serde", + "thiserror", + "windows", + "zeroize", ] [[package]] -name = "sui-transactional-test-runner" -version = "0.1.0" +name = "stronghold-utils" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8300214898af5e153e7f66e49dbd1c6a21585f2d592d9f24f58b969792475ed6" dependencies = [ - "anyhow", - "async-trait", - "bcs", - "bimap", - "clap", - "criterion", - "eyre", - "fastcrypto", - "futures", - "move-binary-format", - "move-bytecode-utils", - "move-command-line-common", - "move-compiler", - "move-core-types", - "move-stdlib", - "move-symbol-pool", - "move-transactional-test-runner", - "move-vm-runtime", - "msim", - "once_cell", "rand 0.8.5", - "regex", - "rocksdb", - "serde_json", - "simulacrum", - "sui-config", - "sui-core", - "sui-framework", - "sui-framework-snapshot", - "sui-graphql-rpc", - "sui-json-rpc", - "sui-json-rpc-api", - "sui-json-rpc-types", - "sui-protocol-config", - "sui-rest-api", - "sui-storage", - "sui-swarm-config", - "sui-types", - "telemetry-subscribers", - "tempfile", - "tokio", - "typed-store", - "typed-store-derive", + "stronghold-derive", ] [[package]] -name = "sui-types" -version = "0.1.0" +name = "stronghold_engine" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ad9c397e3215857f4f8bd2bd2a5b90c6332d0077d8fb4b6ba61b27b544647ca" dependencies = [ - "anemo", "anyhow", - "bcs", - "bincode", - "byteorder", - "consensus-config", - "criterion", - "derivative", - "derive_more", - "enum_dispatch", - "expect-test", - "eyre", - "fastcrypto", - "fastcrypto-tbls", - "fastcrypto-zkp", - "im", - "indexmap 2.2.6", - "itertools 0.10.5", - "move-binary-format", - "move-bytecode-utils", - "move-command-line-common", - "move-core-types", - "move-disassembler", - "move-ir-types", - "move-vm-profiler", - "move-vm-test-utils", - "move-vm-types", - "mysten-metrics", - "mysten-network", - "narwhal-config", - "narwhal-crypto", - "nonempty", - "num-bigint 0.4.4", - "num-traits", + "dirs-next", + "hex", + "iota-crypto", "once_cell", - "prometheus", - "proptest", - "proptest-derive", - "rand 0.8.5", - "roaring", - "schemars", + "paste", "serde", - "serde-name", - "serde_json", - "serde_with", - "serde_yaml 0.8.26", - "shared-crypto", - "signature 1.6.4", - "static_assertions", - "strum 0.24.1", - "strum_macros 0.24.3", - "sui-enum-compat-util", - "sui-macros", - "sui-protocol-config", - "tap", + "stronghold-runtime", "thiserror", - "tonic 0.11.0", - "tracing", - "typed-store-error", + "zeroize", ] [[package]] -name = "sui-upgrade-compatibility-transactional-tests" -version = "0.1.0" -dependencies = [ - "anyhow", - "datatest-stable", - "insta", - "move-binary-format", - "move-command-line-common", - "move-compiler", - "move-package", - "sui-move-build", -] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] -name = "sui-verifier-latest" -version = "0.1.0" +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" dependencies = [ - "move-abstract-stack", - "move-binary-format", - "move-bytecode-utils", - "move-bytecode-verifier", - "move-core-types", - "move-vm-config", - "sui-protocol-config", - "sui-types", + "strum_macros 0.24.3", ] [[package]] -name = "sui-verifier-transactional-tests" -version = "0.1.0" +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" dependencies = [ - "datatest-stable", - "sui-transactional-test-runner", + "strum_macros 0.25.2", ] [[package]] -name = "sui-verifier-v0" -version = "0.1.0" +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ - "move-abstract-stack", - "move-binary-format", - "move-bytecode-utils", - "move-bytecode-verifier-v0", - "move-core-types", - "move-vm-config", - "sui-protocol-config", - "sui-types", + "heck", + "proc-macro2 1.0.78", + "quote 1.0.35", + "rustversion", + "syn 1.0.107", ] [[package]] -name = "sui-verifier-v1" -version = "0.1.0" +name = "strum_macros" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" dependencies = [ - "move-abstract-stack", - "move-binary-format", - "move-bytecode-utils", - "move-bytecode-verifier-v1", - "move-core-types", - "move-vm-config", - "sui-types", + "heck", + "proc-macro2 1.0.78", + "quote 1.0.35", + "rustversion", + "syn 2.0.48", ] [[package]] -name = "sui-verifier-v2" -version = "0.1.0" +name = "subprocess" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2e86926081dda636c546d8c5e641661049d7562a68f5488be4a1f7f66f6086" dependencies = [ - "move-abstract-stack", - "move-binary-format", - "move-bytecode-utils", - "move-bytecode-verifier-v2", - "move-core-types", - "move-vm-config", - "sui-protocol-config", - "sui-types", + "libc", + "winapi", ] [[package]] -name = "suins-indexer" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-trait", - "backoff", - "base64-url", - "bcs", - "bytes", - "diesel", - "dotenvy", - "futures", - "move-core-types", - "mysten-metrics", - "notify", - "object_store 0.7.0", - "prometheus", - "rand 0.8.5", - "serde", - "serde_json", - "serde_yaml 0.8.26", - "sui-data-ingestion-core", - "sui-json-rpc", - "sui-storage", - "sui-types", - "telemetry-subscribers", - "tempfile", - "tokio", - "tracing", - "url", -] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] -name = "suiop-cli" -version = "0.1.9" -dependencies = [ - "anyhow", - "chrono", - "clap", - "colored", - "docker-api", - "field_names", - "include_dir", - "inquire", - "prettytable-rs", - "regex", - "reqwest", - "semver 1.0.16", - "serde", - "serde_json", - "serde_yaml 0.8.26", - "spinners", - "strum 0.24.1", - "tempfile", - "tokio", - "toml_edit 0.19.10", - "tracing", - "tracing-subscriber", -] +name = "subtle-ng" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" [[package]] name = "supports-color" @@ -14734,26 +14734,26 @@ dependencies = [ "anyhow", "fastcrypto-zkp", "futures", + "iota-config", + "iota-core", + "iota-framework", + "iota-json-rpc", + "iota-json-rpc-api", + "iota-json-rpc-types", + "iota-keys", + "iota-macros", + "iota-node", + "iota-protocol-config", + "iota-sdk 1.22.0", + "iota-simulator", + "iota-swarm", + "iota-swarm-config", + "iota-test-transaction-builder", + "iota-types", "jsonrpsee", "move-binary-format", "prometheus", "rand 0.8.5", - "sui-config", - "sui-core", - "sui-framework", - "sui-json-rpc", - "sui-json-rpc-api", - "sui-json-rpc-types", - "sui-keys", - "sui-macros", - "sui-node", - "sui-protocol-config", - "sui-sdk", - "sui-simulator", - "sui-swarm", - "sui-swarm-config", - "sui-test-transaction-builder", - "sui-types", "tokio", "tracing", ] @@ -15514,15 +15514,15 @@ dependencies = [ name = "transaction-fuzzer" version = "0.1.0" dependencies = [ + "iota-core", + "iota-move-build", + "iota-protocol-config", + "iota-types", "move-core-types", "once_cell", "proptest", "proptest-derive", "rand 0.8.5", - "sui-core", - "sui-move-build", - "sui-protocol-config", - "sui-types", "tokio", "tracing", ] @@ -15608,6 +15608,7 @@ dependencies = [ "eyre", "fdlimit", "hdrhistogram", + "iota-macros", "itertools 0.10.5", "msim", "once_cell", @@ -15619,7 +15620,6 @@ dependencies = [ "rocksdb", "rstest", "serde", - "sui-macros", "syn 1.0.107", "tap", "tempfile", diff --git a/Cargo.toml b/Cargo.toml index 3d9a27d9e7d..145f7acb52c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,82 +82,82 @@ members = [ "crates/prometheus-closure-metric", "crates/shared-crypto", "crates/simulacrum", - "crates/sui", - "crates/sui-adapter-transactional-tests", - "crates/sui-analytics-indexer", - "crates/sui-analytics-indexer-derive", - "crates/sui-archival", - "crates/sui-authority-aggregation", - "crates/sui-aws-orchestrator", - "crates/sui-benchmark", - "crates/sui-bridge", - "crates/sui-cluster-test", - "crates/sui-common", - "crates/sui-config", - "crates/sui-core", - "crates/sui-cost", - "crates/sui-data-ingestion", - "crates/sui-data-ingestion-core", - "crates/sui-e2e-tests", - "crates/sui-enum-compat-util", - "crates/sui-faucet", - "crates/sui-framework", - "crates/sui-framework-snapshot", - "crates/sui-framework-tests", - "crates/sui-genesis-builder", - "crates/sui-graphql-e2e-tests", - "crates/sui-graphql-rpc", - "crates/sui-graphql-rpc-client", - "crates/sui-graphql-rpc-headers", - "crates/sui-indexer", - "crates/sui-json", - "crates/sui-json-rpc", - "crates/sui-json-rpc-api", - "crates/sui-json-rpc-tests", - "crates/sui-json-rpc-types", - "crates/sui-keys", - "crates/sui-light-client", - "crates/sui-macros", - "crates/sui-metric-checker", - "crates/sui-move", - "crates/sui-move-build", - "crates/sui-network", - "crates/sui-node", - "crates/sui-open-rpc", - "crates/sui-open-rpc-macros", - "crates/sui-oracle", - "crates/sui-package-resolver", - "crates/sui-proc-macros", - "crates/sui-protocol-config", - "crates/sui-protocol-config-macros", - "crates/sui-proxy", - "crates/sui-replay", - "crates/sui-rest-api", - "crates/sui-rosetta", - "crates/sui-rpc-loadgen", - "crates/sui-sdk", - "crates/sui-simulator", - "crates/sui-single-node-benchmark", - "crates/sui-snapshot", - "crates/sui-source-validation", - "crates/sui-source-validation-service", - "crates/sui-storage", - "crates/sui-surfer", - "crates/sui-swarm", - "crates/sui-swarm-config", - "crates/sui-telemetry", - "crates/sui-test-transaction-builder", - "crates/sui-test-validator", - "crates/sui-tls", - "crates/sui-tool", - "crates/sui-transaction-builder", - "crates/sui-transaction-checks", - "crates/sui-transactional-test-runner", - "crates/sui-types", - "crates/sui-upgrade-compatibility-transactional-tests", - "crates/sui-verifier-transactional-tests", - "crates/suins-indexer", - "crates/suiop-cli", + "crates/iota", + "crates/iota-adapter-transactional-tests", + "crates/iota-analytics-indexer", + "crates/iota-analytics-indexer-derive", + "crates/iota-archival", + "crates/iota-authority-aggregation", + "crates/iota-aws-orchestrator", + "crates/iota-benchmark", + "crates/iota-bridge", + "crates/iota-cluster-test", + "crates/iota-common", + "crates/iota-config", + "crates/iota-core", + "crates/iota-cost", + "crates/iota-data-ingestion", + "crates/iota-data-ingestion-core", + "crates/iota-e2e-tests", + "crates/iota-enum-compat-util", + "crates/iota-faucet", + "crates/iota-framework", + "crates/iota-framework-snapshot", + "crates/iota-framework-tests", + "crates/iota-genesis-builder", + "crates/iota-graphql-e2e-tests", + "crates/iota-graphql-rpc", + "crates/iota-graphql-rpc-client", + "crates/iota-graphql-rpc-headers", + "crates/iota-indexer", + "crates/iota-json", + "crates/iota-json-rpc", + "crates/iota-json-rpc-api", + "crates/iota-json-rpc-tests", + "crates/iota-json-rpc-types", + "crates/iota-keys", + "crates/iota-light-client", + "crates/iota-macros", + "crates/iota-metric-checker", + "crates/iota-move", + "crates/iota-move-build", + "crates/iota-network", + "crates/iota-node", + "crates/iota-open-rpc", + "crates/iota-open-rpc-macros", + "crates/iota-oracle", + "crates/iota-package-resolver", + "crates/iota-proc-macros", + "crates/iota-protocol-config", + "crates/iota-protocol-config-macros", + "crates/iota-proxy", + "crates/iota-replay", + "crates/iota-rest-api", + "crates/iota-rosetta", + "crates/iota-rpc-loadgen", + "crates/iota-sdk", + "crates/iota-simulator", + "crates/iota-single-node-benchmark", + "crates/iota-snapshot", + "crates/iota-source-validation", + "crates/iota-source-validation-service", + "crates/iota-storage", + "crates/iota-surfer", + "crates/iota-swarm", + "crates/iota-swarm-config", + "crates/iota-telemetry", + "crates/iota-test-transaction-builder", + "crates/iota-test-validator", + "crates/iota-tls", + "crates/iota-tool", + "crates/iota-transaction-builder", + "crates/iota-transaction-checks", + "crates/iota-transactional-test-runner", + "crates/iota-types", + "crates/iota-upgrade-compatibility-transactional-tests", + "crates/iota-verifier-transactional-tests", + "crates/iotans-indexer", + "crates/iotaop-cli", "crates/telemetry-subscribers", "crates/test-cluster", "crates/transaction-fuzzer", @@ -175,24 +175,24 @@ members = [ "narwhal/test-utils", "narwhal/types", "narwhal/worker", - "sui-execution", - "sui-execution/cut", - "sui-execution/latest/sui-adapter", - "sui-execution/latest/sui-move-natives", - "sui-execution/latest/sui-verifier", - "sui-execution/v0/sui-adapter", - "sui-execution/v0/sui-move-natives", - "sui-execution/v0/sui-verifier", - "sui-execution/v1/sui-adapter", - "sui-execution/v1/sui-move-natives", - "sui-execution/v1/sui-verifier", - "sui-execution/v2/sui-adapter", - "sui-execution/v2/sui-move-natives", - "sui-execution/v2/sui-verifier", + "iota-execution", + "iota-execution/cut", + "iota-execution/latest/iota-adapter", + "iota-execution/latest/iota-move-natives", + "iota-execution/latest/iota-verifier", + "iota-execution/v0/iota-adapter", + "iota-execution/v0/iota-move-natives", + "iota-execution/v0/iota-verifier", + "iota-execution/v1/iota-adapter", + "iota-execution/v1/iota-move-natives", + "iota-execution/v1/iota-verifier", + "iota-execution/v2/iota-adapter", + "iota-execution/v2/iota-move-natives", + "iota-execution/v2/iota-verifier", ] [workspace.package] -# This version string will be inherited by sui-core, sui-faucet, sui-node, sui-tools, sui-sdk, sui-move-build, and sui crates. +# This version string will be inherited by iota-core, iota-faucet, iota-node, iota-tools, iota-sdk, iota-move-build, and iota crates. version = "1.22.0" [profile.release] @@ -200,7 +200,7 @@ version = "1.22.0" debug = 1 # Write debug info into a separate file. split-debuginfo = 'packed' -# Without stripping, sui binary size would be > 1GB. +# Without stripping, iota binary size would be > 1GB. strip = 'debuginfo' # Exit process with SIGABRT when any thread panics panic = 'abort' @@ -575,73 +575,73 @@ mysten-util-mem-derive = { path = "crates/mysten-util-mem-derive" } prometheus-closure-metric = { path = "crates/prometheus-closure-metric" } shared-crypto = { path = "crates/shared-crypto" } simulacrum = { path = "crates/simulacrum" } -sui = { path = "crates/sui" } -sui-adapter-transactional-tests = { path = "crates/sui-adapter-transactional-tests" } -sui-analytics-indexer = { path = "crates/sui-analytics-indexer" } -sui-analytics-indexer-derive = { path = "crates/sui-analytics-indexer-derive" } -sui-archival = { path = "crates/sui-archival" } -sui-authority-aggregation = { path = "crates/sui-authority-aggregation" } -sui-benchmark = { path = "crates/sui-benchmark" } -sui-cluster-test = { path = "crates/sui-cluster-test" } -sui-common = { path = "crates/sui-common" } -sui-config = { path = "crates/sui-config" } -sui-core = { path = "crates/sui-core" } -sui-cost = { path = "crates/sui-cost" } -sui-data-ingestion = { path = "crates/sui-data-ingestion" } -sui-data-ingestion-core = { path = "crates/sui-data-ingestion-core" } -sui-e2e-tests = { path = "crates/sui-e2e-tests" } -sui-enum-compat-util = { path = "crates/sui-enum-compat-util" } -sui-faucet = { path = "crates/sui-faucet" } -sui-framework = { path = "crates/sui-framework" } -sui-framework-snapshot = { path = "crates/sui-framework-snapshot" } -sui-framework-tests = { path = "crates/sui-framework-tests" } -sui-graphql-rpc = { path = "crates/sui-graphql-rpc" } -sui-graphql-rpc-client = { path = "crates/sui-graphql-rpc-client" } -sui-graphql-rpc-headers = { path = "crates/sui-graphql-rpc-headers" } -sui-genesis-builder = { path = "crates/sui-genesis-builder" } -sui-indexer = { path = "crates/sui-indexer" } -sui-json = { path = "crates/sui-json" } -sui-json-rpc = { path = "crates/sui-json-rpc" } -sui-json-rpc-api = { path = "crates/sui-json-rpc-api" } -sui-json-rpc-types = { path = "crates/sui-json-rpc-types" } -sui-keys = { path = "crates/sui-keys" } -sui-macros = { path = "crates/sui-macros" } -sui-metric-checker = { path = "crates/sui-metric-checker" } -sui-move = { path = "crates/sui-move" } -sui-move-build = { path = "crates/sui-move-build" } -sui-network = { path = "crates/sui-network" } -sui-node = { path = "crates/sui-node" } -sui-open-rpc = { path = "crates/sui-open-rpc" } -sui-open-rpc-macros = { path = "crates/sui-open-rpc-macros" } -sui-package-resolver = { path = "crates/sui-package-resolver" } -sui-proc-macros = { path = "crates/sui-proc-macros" } -sui-protocol-config = { path = "crates/sui-protocol-config" } -sui-protocol-config-macros = { path = "crates/sui-protocol-config-macros" } -sui-proxy = { path = "crates/sui-proxy" } -sui-replay = { path = "crates/sui-replay" } -sui-rosetta = { path = "crates/sui-rosetta" } -sui-rpc-loadgen = { path = "crates/sui-rpc-loadgen" } -sui-sdk = { path = "crates/sui-sdk" } -sui-simulator = { path = "crates/sui-simulator" } -sui-snapshot = { path = "crates/sui-snapshot" } -sui-source-validation = { path = "crates/sui-source-validation" } -sui-source-validation-service = { path = "crates/sui-source-validation-service" } -sui-storage = { path = "crates/sui-storage" } -sui-surfer = { path = "crates/sui-surfer" } -sui-swarm = { path = "crates/sui-swarm" } -sui-swarm-config = { path = "crates/sui-swarm-config" } -sui-telemetry = { path = "crates/sui-telemetry" } -sui-test-transaction-builder = { path = "crates/sui-test-transaction-builder" } -sui-test-validator = { path = "crates/sui-test-validator" } -sui-tls = { path = "crates/sui-tls" } -sui-rest-api = { path = "crates/sui-rest-api" } -sui-tool = { path = "crates/sui-tool" } -sui-transaction-builder = { path = "crates/sui-transaction-builder" } -sui-transaction-checks = { path = "crates/sui-transaction-checks" } -sui-transactional-test-runner = { path = "crates/sui-transactional-test-runner" } -sui-types = { path = "crates/sui-types" } -sui-upgrade-compatibility-transactional-tests = { path = "crates/sui-upgrade-compatibility-transactional-tests" } -sui-verifier-transactional-tests = { path = "crates/sui-verifier-transactional-tests" } +iota = { path = "crates/iota" } +iota-adapter-transactional-tests = { path = "crates/iota-adapter-transactional-tests" } +iota-analytics-indexer = { path = "crates/iota-analytics-indexer" } +iota-analytics-indexer-derive = { path = "crates/iota-analytics-indexer-derive" } +iota-archival = { path = "crates/iota-archival" } +iota-authority-aggregation = { path = "crates/iota-authority-aggregation" } +iota-benchmark = { path = "crates/iota-benchmark" } +iota-cluster-test = { path = "crates/iota-cluster-test" } +iota-common = { path = "crates/iota-common" } +iota-config = { path = "crates/iota-config" } +iota-core = { path = "crates/iota-core" } +iota-cost = { path = "crates/iota-cost" } +iota-data-ingestion = { path = "crates/iota-data-ingestion" } +iota-data-ingestion-core = { path = "crates/iota-data-ingestion-core" } +iota-e2e-tests = { path = "crates/iota-e2e-tests" } +iota-enum-compat-util = { path = "crates/iota-enum-compat-util" } +iota-faucet = { path = "crates/iota-faucet" } +iota-framework = { path = "crates/iota-framework" } +iota-framework-snapshot = { path = "crates/iota-framework-snapshot" } +iota-framework-tests = { path = "crates/iota-framework-tests" } +iota-graphql-rpc = { path = "crates/iota-graphql-rpc" } +iota-graphql-rpc-client = { path = "crates/iota-graphql-rpc-client" } +iota-graphql-rpc-headers = { path = "crates/iota-graphql-rpc-headers" } +iota-genesis-builder = { path = "crates/iota-genesis-builder" } +iota-indexer = { path = "crates/iota-indexer" } +iota-json = { path = "crates/iota-json" } +iota-json-rpc = { path = "crates/iota-json-rpc" } +iota-json-rpc-api = { path = "crates/iota-json-rpc-api" } +iota-json-rpc-types = { path = "crates/iota-json-rpc-types" } +iota-keys = { path = "crates/iota-keys" } +iota-macros = { path = "crates/iota-macros" } +iota-metric-checker = { path = "crates/iota-metric-checker" } +iota-move = { path = "crates/iota-move" } +iota-move-build = { path = "crates/iota-move-build" } +iota-network = { path = "crates/iota-network" } +iota-node = { path = "crates/iota-node" } +iota-open-rpc = { path = "crates/iota-open-rpc" } +iota-open-rpc-macros = { path = "crates/iota-open-rpc-macros" } +iota-package-resolver = { path = "crates/iota-package-resolver" } +iota-proc-macros = { path = "crates/iota-proc-macros" } +iota-protocol-config = { path = "crates/iota-protocol-config" } +iota-protocol-config-macros = { path = "crates/iota-protocol-config-macros" } +iota-proxy = { path = "crates/iota-proxy" } +iota-replay = { path = "crates/iota-replay" } +iota-rosetta = { path = "crates/iota-rosetta" } +iota-rpc-loadgen = { path = "crates/iota-rpc-loadgen" } +iota-sdk = { path = "crates/iota-sdk" } +iota-simulator = { path = "crates/iota-simulator" } +iota-snapshot = { path = "crates/iota-snapshot" } +iota-source-validation = { path = "crates/iota-source-validation" } +iota-source-validation-service = { path = "crates/iota-source-validation-service" } +iota-storage = { path = "crates/iota-storage" } +iota-surfer = { path = "crates/iota-surfer" } +iota-swarm = { path = "crates/iota-swarm" } +iota-swarm-config = { path = "crates/iota-swarm-config" } +iota-telemetry = { path = "crates/iota-telemetry" } +iota-test-transaction-builder = { path = "crates/iota-test-transaction-builder" } +iota-test-validator = { path = "crates/iota-test-validator" } +iota-tls = { path = "crates/iota-tls" } +iota-rest-api = { path = "crates/iota-rest-api" } +iota-tool = { path = "crates/iota-tool" } +iota-transaction-builder = { path = "crates/iota-transaction-builder" } +iota-transaction-checks = { path = "crates/iota-transaction-checks" } +iota-transactional-test-runner = { path = "crates/iota-transactional-test-runner" } +iota-types = { path = "crates/iota-types" } +iota-upgrade-compatibility-transactional-tests = { path = "crates/iota-upgrade-compatibility-transactional-tests" } +iota-verifier-transactional-tests = { path = "crates/iota-verifier-transactional-tests" } telemetry-subscribers = { path = "crates/telemetry-subscribers" } test-cluster = { path = "crates/test-cluster" } transaction-fuzzer = { path = "crates/transaction-fuzzer" } @@ -664,15 +664,15 @@ narwhal-test-utils = { path = "narwhal/test-utils" } narwhal-types = { path = "narwhal/types" } narwhal-worker = { path = "narwhal/worker" } -sui-execution = { path = "sui-execution" } -# sui-move-natives = { path = "sui-execution/latest/sui-move-natives", package = "sui-move-natives-latest" } -# sui-adapter = { path = "sui-execution/latest/sui-adapter", package = "sui-adapter-latest" } -# sui-verifier = { path = "sui-execution/latest/sui-verifier", package = "sui-verifier-latest" } +iota-execution = { path = "iota-execution" } +# iota-move-natives = { path = "iota-execution/latest/iota-move-natives", package = "iota-move-natives-latest" } +# iota-adapter = { path = "iota-execution/latest/iota-adapter", package = "iota-adapter-latest" } +# iota-verifier = { path = "iota-execution/latest/iota-verifier", package = "iota-verifier-latest" } # move-stdlib = { path = "external-crates/move/move-stdlib" } # move-vm-runtime = { path = "external-crates/move/move-vm/runtime" } # move-bytecode-verifier = { path = "external-crates/move/move-bytecode-verifier" } -# suiop dependencies +# iotaop dependencies docker-api = "0.12.2" field_names = "0.2.0" semver = "1.0.16" diff --git a/README.md b/README.md index c3f55105e9a..7d7e2ad7689 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# Kinesis +# IOTA -Kinesis is a asset-oriented programming model powered by the -[Move programming language](https://move-language.github.io/move/introduction.html). Kinesis is a project under active +IOTA is a asset-oriented programming model powered by the +[Move programming language](https://move-language.github.io/move/introduction.html). IOTA is a project under active development by the [IOTA Foundation](https://iota.org). ## Setup diff --git a/RELEASES.md b/RELEASES.md index d6bd1be2ee9..fe4225f4c75 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,40 +1,3 @@ -# Sui Releases -https://github.com/MystenLabs/sui/releases +# IOTA Releases +https://github.com/iotaledger/iota/releases -## Past Releases -* 23-05-17: [1.1.0](https://github.com/MystenLabs/sui/releases/tag/mainnet-v1.1.0) -* 23-05-08: [1.1.0](https://github.com/MystenLabs/sui/releases/tag/devnet-v1.1.0) -* 23-05-02: [1.0.0](https://github.com/MystenLabs/sui/releases/tag/sui-v1.0.0) -* 23-04-24: [0.33.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.33.0) -* 23-04-17: [0.32.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.32.0) -* 23-04-10: [0.31.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.31.0) -* 23-03-27: [0.29.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.29.0) -* 23-02-22: [0.27.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.27.0) -* 23-02-15: [0.26.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.26.0) -* 23-02-08: [0.25.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.25.0) -* 23-02-01: [0.24.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.24.0) -* 23-01-25: [0.23.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.23.0) -* 23-01-19: [0.22.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.22.0) -* 23-01-12: [0.21.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.21.0) -* 23-01-04: [0.20.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.20.0) -* 22-12-16: [0.19.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.19.0) -* 22-12-08: [0.18.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.18.0) -* 22-12-01: [0.17.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.17.0) -* 22-11-17: [0.16.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.16.0) -* 22-11-08: [0.15.1](https://github.com/MystenLabs/sui/releases/tag/devnet-0.15.1) -* 22-11-02: [0.14.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.14.0) -* 22-10-27: [0.13.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.13.0) -* 22-10-20: [0.12.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.12.0) -* 22-10-12: [0.11.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.11.0) -* 22-09-28: [0.10.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.10.0) -* 22-09-06: [0.9.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.9.0) -* 22-08-30: [0.8.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.8.0) -* 22-08-17: [0.7.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.7.0) -* 22-07-26: [0.6.2](https://github.com/MystenLabs/sui/releases/tag/devnet-0.6.2) -* 22-07-19: [0.6.1](https://github.com/MystenLabs/sui/releases/tag/devnet-0.6.1) -* 22-07-12: [0.6.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.6.0-rc) -* 22-06-22: [0.5.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.5.0-rc) -* 22-06-07: [0.4.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.4.0-rc) -* 22-05-24: [0.3.0](https://github.com/MystenLabs/sui/releases/tag/devnet-0.3.0-rc) -* 22-05-12: [0.2.0](https://medium.com/mysten-labs/sui-release-notes-v0-2-0-7b377e2bf01) -* 22-05-05: [0.1.0 (Sui Devnet launch)](https://medium.com/mysten-labs/sui-devnet-public-release-a2be304ff36b) diff --git a/SECURITY.md b/SECURITY.md index 7d992231642..4ebabe3d8c6 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,175 +1,4 @@ -# Introduction +# IOTA Security -We appreciate your participation in keeping the Sui network secure. This doc includes details on Sui's Bug Bounty Program, including information on how to report an issue, what bug bounties are available, and who is eligible for bounties. - -The program is run in partnership with [HackenProof](https://hackenproof.com/). More information is available on [their site](https://hackenproof.com/sui/sui/). - -If you have any questions or concerns, contact [support@hackenproof.com](mailto:info@hackenproof.com). - -# Reporting and response process - -All reports must be sent using HackenProof’s [secure dashboard](https://hackenproof.com/sui/sui/). **DO NOT report a security issue using GitHub, email, or Discord.** - -You should receive an acknowledgement of your report within 48 hours for critical vulnerabilities and 96 hours for all other vulnerabilities. - -If you do not get a response, contact info@hackenproof.com. DO NOT include attachments or provide detail regarding the security issue. - -If you are reporting something outside the scope of HackenProof's Bug Bounty Program for Sui, contact [security@sui.io](mailto:security@sui.io) - -# Bug bounties - -The Sui Foundation offers bug bounties for security issues found at different levels of severity. If a vulnerability is found, follow the process detailed above to report the issue. All bug reports must come with a runnable [testnet](https://github.com/MystenLabs/sui/tree/testnet) Proof-of-Concept with an end-effect impacting an asset-in-scope in order to be considered for a reward. You do not need to have a fix in order to submit a report or receive a bounty. By your participation in Sui Foundation’s bug bounty program you agree to be bound and abide by our [terms of service](https://sui.io/terms) and [privacy policy](https://sui.io/policy) . - -## Assets in scope - -Impacts only apply to assets in active use by Sui. - -### Blockchain/DLT - -- Sui Network Consensus -- Sui Network -- Sui Move - -### Smart Contract - -- Sui Framework - -## Impacts in Scope - - -The following impacts are accepted within this bug bounty program--refer to [Sui's HackenProof Bug Bounty Program Page](https://hackenproof.com/sui/sui/) for an official and up-to-date listing. -All other impacts are considered out-of-scope and ineligible for payout. - - - -CRITICAL [$100,000-$500,000 USD] -1. Exceeding the maximum supply of 10 billion SUI + allowing the attacker to claim the excess funds -2. Loss of Funds which includes - * Unauthorized creation, copying, transfer or destruction of objects via bypass of or exploit of bugs in the Move or Sui bytecode verifier - * Address Collision – creating two distinct authentication schemes that hash to the same SUI address in a manner that lead to significant loss of funds - * Object ID collision—creating two distinct objects with the same ID in a manner that leads to significant loss of funds. - * Unauthorized use of an owned object as a transaction input, resulting in significant loss of funds due to the inability to verify ownership and permission to transfer - * Dynamically loading an object that is not directly or transitively owned by the transaction sender, in a manner that leads to significant loss of funds - * Unauthorized upgrade of a Move package, in a manner that leads to significant loss of funds - * Stealing staking rewards that belong to another user, or claiming more than a user’s share of staking rewards, not including rounding errors that result in a minor, financially insignificant discrepancy -3. Violating BFT assumptions, acquiring voting power vastly disproportionate to stake, or any other issue that can meaningfully compromise the integrity of the blockchain’s proof of stake governance does not include the following: - * Voting power that is redistributed because one or more other validators already has max voting power - * Rounding errors that result in minor voting power discrepancies -4. Unintended permanent chain split requiring hard fork (network partition requiring hard fork) -5. Network not being able to confirm new transactions (total network shutdown) requiring a hard fork to resolve -6. Arbitrary, non-Move remote code execution on unmodified validator software - - -HIGH [$50,000 USD] - -1. Temporary Total Network Shutdown (greater than 10 minutes of network downtime) - -MEDIUM [$10,000 USD] - -1. A bug that results in unintended and harmful smart contract behavior with no concrete funds at direct risk -2. Unintended, permanent burning of SUI under the max cap. -3. Shutdown of greater than or equal to 30% of network processing nodes without brute force actions, but does not shut down the network - - -LOW [$5,000 USD] - -1. Sending a transaction that triggers invariant violation error code in unmodified validator software -2. A remote call that crashes a Sui fullnode - -# Audit Discoveries and Known Issues -Bug reports covering previously-discovered bugs are not eligible for any reward through the bug bounty program. If a bug report covers a known issue, it may be rejected together with proof of the issue being known before escalation of the bug report via HackenProof. - -**Previous audits and known issues can be found at:** -| Known Issue | Related Impact-in-Scope | -| ------------- | ------------- | -| In our staking contract, we have the concept of pool tokens and keep track of exchange rates between pool tokens and SUI tokens of all epochs, which increase as more rewards are added to the staking pools. When a user withdraws their stake, we retrieve from that record both the exchange rate at staking time and the current exchange rate (at withdrawing time), and calculate the rewards to be paid out based on the difference in exchange rates. While doing this calculation, we do conversions both ways: pool tokens -> SUI and SUI -> pool tokens. Rounding may happen along the way due to integer division. The exchange rate between the two tokens should stay roughly the same since we will be burning a proportional amount of pool tokens as SUI is withdrawn. However, in the extreme case where a user is unstaking 1 MIST, this rounding error may cause ZERO pool tokens to be burnt, causing the pool token to effectively depreciate. If an attacker has a lot of 1 MIST stakes, they can withdraw them one by one, causing the pool token exchange rate to drop and other takers to “lose” their staking rewards. I put quotation marks around “lose” because the attacker themselves won’t get any of that rewards so this attacker doesn’t actually make economic sense. Rather the rewards stay in the rewards pool and will become dust. This issue is mitigated by enforcing a minimum staking amount of 1 SUI or 10^9 MIST in this PR: https://github.com/MystenLabs/sui/pull/9961 | Critical - Any other issue leading to theft or loss of valuable objects, with severity depending on the consequences of the issue and the preconditions for exploiting it | -| Excessive storage rebate on 0x5 object right after epoch change: -Each on-chain object is associated with a storage rebate, which would be refunded to the owner if it ever gets deleted. Epoch change transactions are special in that they are system transactions without a sender, hence any excessive storage rebate generated in that transaction is kept in the 0x5 object. This means that the first person touching the 0x5 object in each epoch may be able to obtain those excessive rebate by simply touching this object (e.g. a failed staking request). We will look into a way to evenly distribute those excessive rebates such that is does not lead to any undesired behaviors. | | -| Crash Validator by providing a gas price of u64:max | Network not being able to confirm new transactions (total network shutdown) | - - -# Payment of bounties - -- Bounties are awarded on a rolling basis and eligibility to receive such awards shall be determined by Sui Foundation in its sole discretion. -- Once a bug report is accepted as legitimate, assuming KYC has been completed successfully, bounties will be paid out on or about a time that is 14 days thereafter or less. -- Bounties are denominated in USD but will be paid in USDC; provided if a bounty award winner is not eligible to receive USDC in compliance with applicable law, the bounty award shall be paid out in USD. -- Multiple vulnerabilities of a similar root cause will be paid out as one report, as a single bounty award, determined by the severity of the vulnerability as described above. - -# Out of scope - -The following vulnerabilities are excluded from the bug bounty program: - -- Attacks that the reporter has already exploited themselves, leading to damage -- Attacks requiring access to leaked keys/credentials -- Attacks requiring access to privileged addresses (governance, strategist), except in such cases where the contracts are intended to have no privileged access to functions that make the attack possible -- Broken link hijacking - -### Smart Contracts and Blockchain/DLT - -- Basic economic governance attacks (e.g. 51% attack) -- Lack of liquidity -- Best practice critiques -- Sybil attacks -- Centralization risks - -### Websites and Apps - -- Theoretical impacts without any proof or demonstration -- Content spoofing / text injection issues -- Self-XSS -- Captcha bypass using OCR -- CSRF with no security impact (logout CSRF, change language, etc.) -- Missing HTTP Security Headers (such as X-FRAME-OPTIONS) or cookie security flags (such as “httponly”) -- Server-side information disclosure such as IPs, server names, and most stack traces -- Vulnerabilities used to enumerate or confirm the existence of users or tenants -- Vulnerabilities requiring unlikely user actions -- URL Redirects (unless combined with another vulnerability to produce a more severe vulnerability) -- Lack of SSL/TLS best practices -- Attacks involving DDoS -- Attacks requiring privileged access from within the organization -- SPF records for email domains -- Feature requests -- Best practices - -# Eligibility - -- Participants must use the [HackenProof dashboard](https://hackenproof.com/sui/sui) to report bugs or vulnerabilities. Reports made via email, Discord, or Twitter will not be eligible for bounties. -- Bug reports that are disclosed publicly are not eligible for bounties. -- If multiple reports are submitted for the same class of exploit, the first submission is eligible for the bounty. -- Participants must complete KYC prior to distribution of a bounty. - -# Prohibited activities - -The following activities are prohibited by this bug bounty program. Participating in these activities can result in a temporary suspension or permanent ban from the bug bounty platform, which may also result in the forfeiture and loss of access to all bug submissions and zero payout. - -There is no tolerance for spam/low-quality/incomplete bug reports, “beg bounty” behavior, and misrepresentation of assets and severity. - -- Any testing with mainnet or public testnet deployed code; all testing should be done on private testnets -- Attempting phishing or other social engineering attacks against Sui or HackenProof employees and/or customers -- Any testing with third party systems and applications (e.g. browser extensions) as well as websites (e.g. SSO providers, advertising networks) -- Any denial of service attacks -- Automated testing of services that generates significant amounts of traffic -- Public disclosure of an unpatched vulnerability in an embargoed bounty -- Any other actions prohibited by the HackenProof Rules. These rules are subject to change at any time. - ---- - -# FAQ - -**Where can I find more information on the bug bounty program?** - -_All of the program details along with a link to the dashboard to report a bug are available on [HackenProof’s bounty program page for Sui](https://hackenproof.com/sui/sui/)._ - -**How do I join the program?** - -_If you find a bug or vulnerability, report it using the [HackenProof dashboard](https://hackenproof.com/sui/sui). You should receive an acknowledgement of your report within 48 hours for critical vulnerabilities and 96 hours for all other vulnerabilities._ - -**Where can I get technical questions answered?** - -_Sui and HackenProof will be conducting Office Hours to answer questions. A date will be announced on Twitter by [@SuiNetwork](https://twitter.com/suinetwork). If you are not able to attend, you can email questions to info@hackenproof.com._ with questions regarding the Bug Bounty Program. - -For additional security concerns/questions/comments outside the scope of the HackenProof Bug Bounty Program, reach out to Sui's Community [Discord](https://discord.gg/sui), [Forums](https://forums.sui.io/), or e-mail us at _security@sui.io_ - -**Who is behind this program?** - -_The program is funded and managed by the Sui Foundation, in partnership with HackenProof._ +We appreciate your participation in keeping the IOTA network secure. +If you have any questions or concerns, contact [security@iota.org](mailto:security@iota.org) diff --git a/apps/apps-backend/package.json b/apps/apps-backend/package.json index 3780ce2e98b..f7c63d62698 100644 --- a/apps/apps-backend/package.json +++ b/apps/apps-backend/package.json @@ -10,7 +10,7 @@ "lint": "eslint --max-warnings=0 \"{src,apps,libs,test}/**/*.ts\"" }, "dependencies": { - "@mysten/sui.js": "workspace:*", + "@iota/iota.js": "workspace:*", "@nestjs/common": "^10.0.0", "@nestjs/config": "^3.2.2", "@nestjs/core": "^10.0.0", diff --git a/apps/apps-backend/src/analytics/analytics.controller.ts b/apps/apps-backend/src/analytics/analytics.controller.ts index e85b6affc2b..9458c56c571 100644 --- a/apps/apps-backend/src/analytics/analytics.controller.ts +++ b/apps/apps-backend/src/analytics/analytics.controller.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Controller, Get } from '@nestjs/common'; diff --git a/apps/apps-backend/src/analytics/analytics.module.ts b/apps/apps-backend/src/analytics/analytics.module.ts index 8c504d6f379..64f7f6aa43e 100644 --- a/apps/apps-backend/src/analytics/analytics.module.ts +++ b/apps/apps-backend/src/analytics/analytics.module.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Module } from '@nestjs/common'; diff --git a/apps/apps-backend/src/app.module.ts b/apps/apps-backend/src/app.module.ts index 6f8b6c57c33..90b0955edaf 100644 --- a/apps/apps-backend/src/app.module.ts +++ b/apps/apps-backend/src/app.module.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Module } from '@nestjs/common'; diff --git a/apps/apps-backend/src/constants.ts b/apps/apps-backend/src/constants.ts index 7c44fcfe1aa..ad5f3f20bdd 100644 --- a/apps/apps-backend/src/constants.ts +++ b/apps/apps-backend/src/constants.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -export const APPS_BACKEND_SUI_URL = 'https://apps-backend.sui.io'; +export const APPS_BACKEND_IOTA_URL = 'https://apps-backend.iota.io'; diff --git a/apps/apps-backend/src/features/features.controller.ts b/apps/apps-backend/src/features/features.controller.ts index e76b1a68225..a98695b198b 100644 --- a/apps/apps-backend/src/features/features.controller.ts +++ b/apps/apps-backend/src/features/features.controller.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Controller, Get, Query } from '@nestjs/common'; diff --git a/apps/apps-backend/src/features/features.mock.ts b/apps/apps-backend/src/features/features.mock.ts index 5668687185b..ea2ba0c1298 100644 --- a/apps/apps-backend/src/features/features.mock.ts +++ b/apps/apps-backend/src/features/features.mock.ts @@ -1,7 +1,7 @@ // Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { getDefaultNetwork, Network } from '@mysten/sui.js/client'; +import { getDefaultNetwork, Network } from '@iota/iota.js/client'; // Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 @@ -9,33 +9,34 @@ import { getDefaultNetwork, Network } from '@mysten/sui.js/client'; //[object Object] // SPDX-License-Identifier: Apache-2.0 //[object Object] +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 const walletDapps = [ { - name: 'SuiFrens', - description: 'Enter the world of SuiFrens.', - link: 'https://suifrens.com/', - icon: 'https://suifrens.com/icons/favicon.ico', + name: 'IotaFrens', + description: 'Enter the world of IotaFrens.', + link: 'https://iotafrens.com/', + icon: 'https://iotafrens.com/icons/favicon.ico', tags: ['Social'], }, { - name: 'Sui Name Service (SuiNS)', - description: 'Find your .sui name!', - link: 'https://suins.io/', - icon: 'https://raw.githubusercontent.com/SuiNSdapp/docs/main/SuiNS-small2.jpg', + name: 'Iota Name Service (IotaNS)', + description: 'Find your .iota name!', + link: 'https://iotans.io/', + icon: 'https://raw.githubusercontent.com/IotaNSdapp/docs/main/IotaNS-small2.jpg', tags: ['Infra'], }, { name: 'Wormhole Connect', description: - 'Bridge tokens from any Wormhole supported chain into Sui and get dropped off with extra Sui to pay gas fees. Developers can also embed the Connect bridge directly into their own websites and Dapps.', - link: 'https://www.portalbridge.com/sui', + 'Bridge tokens from any Wormhole supported chain into Iota and get dropped off with extra Iota to pay gas fees. Developers can also embed the Connect bridge directly into their own websites and Dapps.', + link: 'https://www.portalbridge.com/iota', icon: 'https://www.portalbridge.com/favicon.ico', tags: ['DeFi'], }, { name: 'Bullshark Quests', - description: 'Earn rewards through engaging with apps on Sui!', + description: 'Earn rewards through engaging with apps on Iota!', link: 'https://quests.mystenlabs.com/', icon: 'https://user-images.githubusercontent.com/122397493/251579441-3c84de97-fc6e-46d2-b561-cd7bbef7dac7.png', tags: ['Social'], @@ -43,7 +44,7 @@ const walletDapps = [ { name: 'Aftermath Finance', description: - 'The all-in-one DEX on Sui, featuring a fully on-chain perpetuals exchange, smart-order routing, liquid staking, and a novel spot AMM.', + 'The all-in-one DEX on Iota, featuring a fully on-chain perpetuals exchange, smart-order routing, liquid staking, and a novel spot AMM.', link: 'https://aftermath.finance', icon: 'https://github-production-user-asset-6210df.s3.amazonaws.com/122397493/289710788-57f6935c-f930-4668-aa01-86a1579e406a.png', tags: ['DeFi', 'DEX', 'Infra'], @@ -58,7 +59,7 @@ const walletDapps = [ { name: 'Kriya', description: - '1-stop DeFi protocol on Sui. Native AMM for Swaps, Limit Orders powered by deepbook, strategy vaults and leveraged perps', + '1-stop DeFi protocol on Iota. Native AMM for Swaps, Limit Orders powered by deepbook, strategy vaults and leveraged perps', link: 'https://app.kriya.finance/', icon: 'https://mysten-fe-assets.s3.us-west-2.amazonaws.com/wallet-dapps-assets/kriya_rounded_logo.png', tags: ['DeFi'], @@ -79,28 +80,28 @@ const walletDapps = [ }, { name: 'Turbos', - description: 'Non-custodial and user-centric DEX on Sui.', + description: 'Non-custodial and user-centric DEX on Iota.', link: 'https://app.turbos.finance', icon: 'https://i.ibb.co/RTKw0PZ/Turbos-400x400.png', tags: ['DeFi'], }, { name: 'Cetus Protocol', - description: 'The pioneer concentrated liquidity DEX on Sui.', + description: 'The pioneer concentrated liquidity DEX on Iota.', link: 'https://app.cetus.zone/', icon: 'https://i.ibb.co/TWdmdQz/cetus-icon.png', tags: ['DeFi', 'DEX'], }, { name: 'FlowX Finance', - description: 'Ecosystem-focused native DEX & aggregator on the Sui Network.', + description: 'Ecosystem-focused native DEX & aggregator on the Iota Network.', link: 'https://flowx.finance/swap', icon: 'https://3458959336-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpEOgAVtfjtpMXMM550M8%2Fuploads%2FiunglJ6f4i7xbVyrPZTD%2FFlowX%20Logo%20Black.png?alt=media&token=6dfa923c-41f6-4252-831f-ac6d1ddd1afe', tags: ['DeFi', 'DEX'], }, { name: 'Bucket Protocol', - description: 'The first native stablecoin on Sui Network.', + description: 'The first native stablecoin on Iota Network.', link: 'https://app.bucketprotocol.io/', icon: 'https://d3h53g0wjfwuec.cloudfront.net/bucket_avatar.png', tags: ['DeFi'], @@ -108,8 +109,8 @@ const walletDapps = [ { name: 'Aries Markets', description: 'Aries Markets - All-in-one DeFi platform with an innovative money market.', - link: 'https://sui.ariesmarkets.xyz/', - icon: 'https://sui.ariesmarkets.xyz/favicon.png', + link: 'https://iota.ariesmarkets.xyz/', + icon: 'https://iota.ariesmarkets.xyz/favicon.png', tags: ['DeFi'], }, { @@ -121,7 +122,7 @@ const walletDapps = [ }, { name: 'Keepsake', - description: 'One of the first NFT Marketplaces on Sui Network.', + description: 'One of the first NFT Marketplaces on Iota Network.', link: 'https://keepsake.gg/', icon: 'https://keepsake.gg/assets/icon/Favicon.png', tags: ['Marketplace'], @@ -174,7 +175,7 @@ export const developmentFeatures = { '0x30a644c3485ee9b604f52165668895092191fcaf5489a846afa7fc11cdb9b24a', ], }, - suins: { + iotans: { defaultValue: false, }, 'team-address-overrides': { @@ -244,10 +245,10 @@ export const developmentFeatures = { 'wallet-dapps': { defaultValue: [ { - name: 'Sui Name Service (SuiNS)', - description: 'Find your .sui name!', - link: 'https://suins.io/', - icon: 'https://raw.githubusercontent.com/SuiNSdapp/docs/main/SuiNS-small2.jpg', + name: 'Iota Name Service (IotaNS)', + description: 'Find your .iota name!', + link: 'https://iotans.io/', + icon: 'https://raw.githubusercontent.com/IotaNSdapp/docs/main/IotaNS-small2.jpg', tags: ['Infra'], }, ], @@ -314,11 +315,11 @@ export const developmentFeatures = { 'kiosk-marketplace-links': { defaultValue: [ { - href: 'https://docs.sui.io/build/sui-kiosk', + href: 'https://docs.iota.io/build/iota-kiosk', text: 'Learn more about Kiosks', }, { - href: 'https://sui.hyperspace.xyz', + href: 'https://iota.hyperspace.xyz', text: 'Marketplace', }, ], @@ -332,8 +333,8 @@ export const developmentFeatures = { 'wallet-apps-banner-config': { defaultValue: { enabled: true, - bannerUrl: 'https://suiwallet.com', - imageUrl: 'https://fe-assets.mystenlabs.com/wallet-next/suiwallet-mobile.svg', + bannerUrl: 'https://iotawallet.com', + imageUrl: 'https://fe-assets.mystenlabs.com/wallet-next/iotawallet-mobile.svg', }, rules: [ { @@ -344,7 +345,7 @@ export const developmentFeatures = { }, force: { enabled: false, - bannerUrl: 'https://sui.io/basecamp', + bannerUrl: 'https://iota.io/basecamp', imageUrl: 'https://fe-assets.mystenlabs.com/basecamp/wallet_basecamp_banner.png', }, @@ -373,7 +374,7 @@ export const developmentFeatures = { 'deep-book-configs': { defaultValue: { pools: { - SUI_USDC: [ + IOTA_USDC: [ '0x4405b50d791fd3346754e8171aaab6bc2ed26c2c46efdd033c14b30ae507ac33', '0x7f526b1263c4b91b43c9e646419b5696f424de28dda3c1e6658cc0a54558baa7', ], @@ -382,7 +383,7 @@ export const developmentFeatures = { USDT_USDC: ['0x5deafda22b6b86127ea4299503362638bea0ca33bb212ea3a67b029356b8b955'], }, coinsMap: { - SUI: '0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI', + IOTA: '0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA', USDC: '0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN', USDT: '0xc060006111016b8a020ad5b33834984a437aaa7d3c74c18e09a95d48aceab08c::coin::COIN', WETH: '0xaf8cd5edc19c4512f4259f0bee101a40d41ebed738ade5874359610ef8eeced5::coin::COIN', @@ -425,7 +426,7 @@ export const developmentFeatures = { }, ], }, - 'suins-enable-okx-wallet': { + 'iotans-enable-okx-wallet': { defaultValue: false, rules: [ { @@ -438,10 +439,10 @@ export const developmentFeatures = { }, ], }, - 'suins-enable-day-one-nft-domain-claim': { + 'iotans-enable-day-one-nft-domain-claim': { defaultValue: false, }, - 'suins-nft-personalization': { + 'iotans-nft-personalization': { defaultValue: false, rules: [ { @@ -454,7 +455,7 @@ export const developmentFeatures = { }, ], }, - 'suins-front-page-banner': { + 'iotans-front-page-banner': { defaultValue: { enabled: false, dismissKey: 'quests-3-interstitial-live', @@ -462,10 +463,10 @@ export const developmentFeatures = { bannerUrl: 'https://tech.mystenlabs.com/quest-3/', }, }, - 'suins-enable-coupons': { + 'iotans-enable-coupons': { defaultValue: false, }, - 'suins-enable-discord': { + 'iotans-enable-discord': { defaultValue: false, rules: [ { @@ -478,18 +479,18 @@ export const developmentFeatures = { }, ], }, - 'suins-free-claims': { + 'iotans-free-claims': { defaultValue: false, }, - 'suins-banner': { + 'iotans-banner': { defaultValue: { content: - "SuiNS is experiencing some issues. We're working to fix the problem and appreciate your patience.", + "IotaNS is experiencing some issues. We're working to fix the problem and appreciate your patience.", isActive: false, isDismissable: true, }, }, - 'suins-enable-subname': { + 'iotans-enable-subname': { defaultValue: false, rules: [ { @@ -515,7 +516,7 @@ export const developmentFeatures = { }, ], }, - 'suins-name-burn-expired-name': { + 'iotans-name-burn-expired-name': { defaultValue: false, rules: [ { @@ -523,7 +524,7 @@ export const developmentFeatures = { }, ], }, - 'suins-name-enable-v2-design': { + 'iotans-name-enable-v2-design': { defaultValue: false, rules: [ { @@ -546,7 +547,7 @@ export const developmentFeatures = { 'explorer-redirect': { defaultValue: true, }, - 'suifrens-enable-nhn-accessories': { + 'iotafrens-enable-nhn-accessories': { defaultValue: false, rules: [ { @@ -554,10 +555,10 @@ export const developmentFeatures = { }, ], }, - 'claim-free-suifren-hat-promo': { + 'claim-free-iotafren-hat-promo': { defaultValue: true, }, - 'suifrens-enable-babyshark-banner': { + 'iotafrens-enable-babyshark-banner': { defaultValue: false, rules: [ { @@ -565,7 +566,7 @@ export const developmentFeatures = { }, ], }, - 'suifrens-enable-babyshark-banner-basecamp-accessories': { + 'iotafrens-enable-babyshark-banner-basecamp-accessories': { defaultValue: false, rules: [ { diff --git a/apps/apps-backend/src/features/features.module.ts b/apps/apps-backend/src/features/features.module.ts index 22e2e89e187..807146ef185 100644 --- a/apps/apps-backend/src/features/features.module.ts +++ b/apps/apps-backend/src/features/features.module.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Module } from '@nestjs/common'; diff --git a/apps/apps-backend/src/main.ts b/apps/apps-backend/src/main.ts index e78dc80adb5..8b34e5b9ed2 100644 --- a/apps/apps-backend/src/main.ts +++ b/apps/apps-backend/src/main.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { ConfigService } from '@nestjs/config'; diff --git a/apps/apps-backend/src/monitor-network/monitor-network.controller.ts b/apps/apps-backend/src/monitor-network/monitor-network.controller.ts index db1477fe68b..e6266a39ef7 100644 --- a/apps/apps-backend/src/monitor-network/monitor-network.controller.ts +++ b/apps/apps-backend/src/monitor-network/monitor-network.controller.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Controller, Get, Query } from '@nestjs/common'; diff --git a/apps/apps-backend/src/monitor-network/monitor-network.module.ts b/apps/apps-backend/src/monitor-network/monitor-network.module.ts index 0273c17be8b..18695cb61e6 100644 --- a/apps/apps-backend/src/monitor-network/monitor-network.module.ts +++ b/apps/apps-backend/src/monitor-network/monitor-network.module.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Module } from '@nestjs/common'; diff --git a/apps/apps-backend/src/prices/prices.controller.ts b/apps/apps-backend/src/prices/prices.controller.ts index d68fbeac23f..c4f6f45d5e5 100644 --- a/apps/apps-backend/src/prices/prices.controller.ts +++ b/apps/apps-backend/src/prices/prices.controller.ts @@ -1,15 +1,16 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Controller, Get, Param } from '@nestjs/common'; -import { APPS_BACKEND_SUI_URL } from '../constants'; +import { APPS_BACKEND_IOTA_URL } from '../constants'; @Controller() export class PricesController { @Get('cetus/:coin') async getTokenPrice(@Param('coin') coin: string) { - const resp = await fetch(`${APPS_BACKEND_SUI_URL}/cetus/${coin}`); + const resp = await fetch(`${APPS_BACKEND_IOTA_URL}/cetus/${coin}`); if (!resp.ok) { throw new Error('Failed to fetch the data'); } diff --git a/apps/apps-backend/src/prices/prices.module.ts b/apps/apps-backend/src/prices/prices.module.ts index 4fd27e1edf4..72616d2ee96 100644 --- a/apps/apps-backend/src/prices/prices.module.ts +++ b/apps/apps-backend/src/prices/prices.module.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Module } from '@nestjs/common'; diff --git a/apps/core/.eslintignore b/apps/core/.eslintignore deleted file mode 100644 index 5bd25f46e98..00000000000 --- a/apps/core/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -tailwind.config.ts diff --git a/apps/core/README.md b/apps/core/README.md index d222a0bb15a..005e590f1dd 100644 --- a/apps/core/README.md +++ b/apps/core/README.md @@ -1,3 +1,3 @@ -# `@mysten/core` +# `@iota/core` This JavaScript library contains helper utilities meant to be used across Mysten Lab's frontend applications. diff --git a/apps/core/package.json b/apps/core/package.json index 7c2b8c3774c..d60c5f619a5 100644 --- a/apps/core/package.json +++ b/apps/core/package.json @@ -1,12 +1,12 @@ { - "name": "@mysten/core", + "name": "@iota/core", "main": "src/index.ts", "private": true, "sideEffects": false, "author": "Mysten Labs ", "repository": { "type": "git", - "url": "github.com:MystenLabs/sui.git" + "url": "github.com:iotaledger/iota.git" }, "license": "Apache-2.0", "scripts": { @@ -26,9 +26,9 @@ "@amplitude/analytics-types": "^0.20.0", "@growthbook/growthbook-react": "^1.0.0", "@hookform/resolvers": "^3.1.1", - "@mysten/dapp-kit": "workspace:*", - "@mysten/kiosk": "workspace:*", - "@mysten/sui.js": "workspace:*", + "@iota/dapp-kit": "workspace:*", + "@iota/kiosk": "workspace:*", + "@iota/iota.js": "workspace:*", "@sentry/react": "^7.59.2", "@tanstack/react-query": "^5.0.0", "bignumber.js": "^9.1.1", diff --git a/apps/core/src/api/SentryHttpTransport.ts b/apps/core/src/api/SentryHttpTransport.ts index 56a2edd7956..daec18660c6 100644 --- a/apps/core/src/api/SentryHttpTransport.ts +++ b/apps/core/src/api/SentryHttpTransport.ts @@ -1,15 +1,13 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiHTTPTransport } from '@mysten/sui.js/client'; +import { IotaHTTPTransport } from '@iota/iota.js/client'; import * as Sentry from '@sentry/react'; -const IGNORED_METHODS = ['suix_resolveNameServiceNames', 'suix_resolveNameServiceAddresses']; +const IGNORED_METHODS = ['iotax_resolveNameServiceNames', 'iotax_resolveNameServiceAddresses']; -export class SentryHttpTransport extends SuiHTTPTransport { +export class SentryHttpTransport extends IotaHTTPTransport { private url: string; constructor(url: string) { super({ url }); diff --git a/apps/core/src/components/KioskClientProvider.tsx b/apps/core/src/components/KioskClientProvider.tsx index fad2249a36e..065bed3d9c1 100644 --- a/apps/core/src/components/KioskClientProvider.tsx +++ b/apps/core/src/components/KioskClientProvider.tsx @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClientContext } from '@mysten/dapp-kit'; -import { KioskClient, Network } from '@mysten/kiosk'; +import { useIotaClientContext } from '@iota/dapp-kit'; +import { KioskClient, Network } from '@iota/kiosk'; import { createContext, useMemo, type ReactNode } from 'react'; export const KioskClientContext = createContext(null); -const suiToKioskNetwork: Record = { +const iotaToKioskNetwork: Record = { mainnet: Network.MAINNET, testnet: Network.TESTNET, }; @@ -17,8 +18,8 @@ export type KioskClientProviderProps = { }; export function KioskClientProvider({ children }: KioskClientProviderProps) { - const { client, network } = useSuiClientContext(); - const kioskNetwork = suiToKioskNetwork[network.toLowerCase()] || Network.CUSTOM; + const { client, network } = useIotaClientContext(); + const kioskNetwork = iotaToKioskNetwork[network.toLowerCase()] || Network.CUSTOM; const kioskClient = useMemo( () => new KioskClient({ client, network: kioskNetwork }), [client, kioskNetwork], diff --git a/apps/core/src/css.d.ts b/apps/core/src/css.d.ts index e63a246217a..712cdfc46d2 100644 --- a/apps/core/src/css.d.ts +++ b/apps/core/src/css.d.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 declare module '*.css' { diff --git a/apps/core/src/hooks/__tests__/useFormatCoin.test.ts b/apps/core/src/hooks/__tests__/useFormatCoin.test.ts index 002a4d87c71..4527b382952 100644 --- a/apps/core/src/hooks/__tests__/useFormatCoin.test.ts +++ b/apps/core/src/hooks/__tests__/useFormatCoin.test.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import BigNumber from 'bignumber.js'; @@ -6,54 +7,54 @@ import { describe, expect, it } from 'vitest'; import { CoinFormat, formatBalance } from '../useFormatCoin'; -const SUI_DECIMALS = 9; +const IOTA_DECIMALS = 9; -function toMist(sui: string) { - return new BigNumber(sui).shiftedBy(SUI_DECIMALS).toString(); +function toMicros(iota: string) { + return new BigNumber(iota).shiftedBy(IOTA_DECIMALS).toString(); } describe('formatBalance', () => { it('formats zero amounts correctly', () => { expect(formatBalance('0', 0)).toEqual('0'); - expect(formatBalance('0', SUI_DECIMALS)).toEqual('0'); + expect(formatBalance('0', IOTA_DECIMALS)).toEqual('0'); }); it('formats decimal amounts correctly', () => { - expect(formatBalance('0', SUI_DECIMALS)).toEqual('0'); - expect(formatBalance('0.000', SUI_DECIMALS)).toEqual('0'); + expect(formatBalance('0', IOTA_DECIMALS)).toEqual('0'); + expect(formatBalance('0.000', IOTA_DECIMALS)).toEqual('0'); }); it('formats integer amounts correctly', () => { - expect(formatBalance(toMist('1'), SUI_DECIMALS)).toEqual('1'); - expect(formatBalance(toMist('1.0001'), SUI_DECIMALS)).toEqual('1'); - expect(formatBalance(toMist('1.1201'), SUI_DECIMALS)).toEqual('1.12'); - expect(formatBalance(toMist('1.1234'), SUI_DECIMALS)).toEqual('1.12'); - expect(formatBalance(toMist('1.1239'), SUI_DECIMALS)).toEqual('1.12'); + expect(formatBalance(toMicros('1'), IOTA_DECIMALS)).toEqual('1'); + expect(formatBalance(toMicros('1.0001'), IOTA_DECIMALS)).toEqual('1'); + expect(formatBalance(toMicros('1.1201'), IOTA_DECIMALS)).toEqual('1.12'); + expect(formatBalance(toMicros('1.1234'), IOTA_DECIMALS)).toEqual('1.12'); + expect(formatBalance(toMicros('1.1239'), IOTA_DECIMALS)).toEqual('1.12'); - expect(formatBalance(toMist('9999.9999'), SUI_DECIMALS)).toEqual('9,999.99'); + expect(formatBalance(toMicros('9999.9999'), IOTA_DECIMALS)).toEqual('9,999.99'); // 10k + handling: - expect(formatBalance(toMist('10000'), SUI_DECIMALS)).toEqual('10 K'); - expect(formatBalance(toMist('12345'), SUI_DECIMALS)).toEqual('12.34 K'); + expect(formatBalance(toMicros('10000'), IOTA_DECIMALS)).toEqual('10 K'); + expect(formatBalance(toMicros('12345'), IOTA_DECIMALS)).toEqual('12.34 K'); // Millions: - expect(formatBalance(toMist('1234000'), SUI_DECIMALS)).toEqual('1.23 M'); + expect(formatBalance(toMicros('1234000'), IOTA_DECIMALS)).toEqual('1.23 M'); // Billions: - expect(formatBalance(toMist('1234000000'), SUI_DECIMALS)).toEqual('1.23 B'); + expect(formatBalance(toMicros('1234000000'), IOTA_DECIMALS)).toEqual('1.23 B'); }); it('formats integer amounts with full CoinFormat', () => { - expect(formatBalance(toMist('1'), SUI_DECIMALS, CoinFormat.FULL)).toEqual('1'); - expect(formatBalance(toMist('1.123456789'), SUI_DECIMALS, CoinFormat.FULL)).toEqual( + expect(formatBalance(toMicros('1'), IOTA_DECIMALS, CoinFormat.FULL)).toEqual('1'); + expect(formatBalance(toMicros('1.123456789'), IOTA_DECIMALS, CoinFormat.FULL)).toEqual( '1.123456789', ); - expect(formatBalance(toMist('9999.9999'), SUI_DECIMALS, CoinFormat.FULL)).toEqual( + expect(formatBalance(toMicros('9999.9999'), IOTA_DECIMALS, CoinFormat.FULL)).toEqual( '9,999.9999', ); - expect(formatBalance(toMist('10000'), SUI_DECIMALS, CoinFormat.FULL)).toEqual('10,000'); - expect(formatBalance(toMist('12345'), SUI_DECIMALS, CoinFormat.FULL)).toEqual('12,345'); - expect(formatBalance(toMist('1234000'), SUI_DECIMALS, CoinFormat.FULL)).toEqual( + expect(formatBalance(toMicros('10000'), IOTA_DECIMALS, CoinFormat.FULL)).toEqual('10,000'); + expect(formatBalance(toMicros('12345'), IOTA_DECIMALS, CoinFormat.FULL)).toEqual('12,345'); + expect(formatBalance(toMicros('1234000'), IOTA_DECIMALS, CoinFormat.FULL)).toEqual( '1,234,000', ); - expect(formatBalance(toMist('1234000000'), SUI_DECIMALS, CoinFormat.FULL)).toEqual( + expect(formatBalance(toMicros('1234000000'), IOTA_DECIMALS, CoinFormat.FULL)).toEqual( '1,234,000,000', ); }); diff --git a/apps/core/src/hooks/nameService.ts b/apps/core/src/hooks/nameService.ts index 7905cf39705..417fa15e992 100644 --- a/apps/core/src/hooks/nameService.ts +++ b/apps/core/src/hooks/nameService.ts @@ -1,45 +1,46 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useFeatureIsOn } from '@growthbook/growthbook-react'; -import { useSuiClient } from '@mysten/dapp-kit'; +import { useIotaClient } from '@iota/dapp-kit'; import { useQuery } from '@tanstack/react-query'; -const SUI_NS_FEATURE_FLAG = 'suins'; +const IOTA_NS_FEATURE_FLAG = 'iotans'; // This should align with whatever names we want to be able to resolve. -const SUI_NS_DOMAINS = ['.sui']; -export function isSuiNSName(name: string) { - return SUI_NS_DOMAINS.some((domain) => name.endsWith(domain)); +const IOTA_NS_DOMAINS = ['.iota']; +export function isIotaNSName(name: string) { + return IOTA_NS_DOMAINS.some((domain) => name.endsWith(domain)); } -export function useSuiNSEnabled() { - return useFeatureIsOn(SUI_NS_FEATURE_FLAG); +export function useIotaNSEnabled() { + return useFeatureIsOn(IOTA_NS_FEATURE_FLAG); } -export function useResolveSuiNSAddress(name?: string | null, enabled?: boolean) { - const client = useSuiClient(); - const enabledSuiNs = useSuiNSEnabled(); +export function useResolveIotaNSAddress(name?: string | null, enabled?: boolean) { + const client = useIotaClient(); + const enabledIotaNs = useIotaNSEnabled(); return useQuery({ - queryKey: ['resolve-suins-address', name], + queryKey: ['resolve-iotans-address', name], queryFn: async () => { return await client.resolveNameServiceAddress({ name: name!, }); }, - enabled: !!name && enabled && enabledSuiNs, + enabled: !!name && enabled && enabledIotaNs, refetchOnWindowFocus: false, retry: false, }); } -export function useResolveSuiNSName(address?: string | null) { - const client = useSuiClient(); - const enabled = useSuiNSEnabled(); +export function useResolveIotaNSName(address?: string | null) { + const client = useIotaClient(); + const enabled = useIotaNSEnabled(); return useQuery({ - queryKey: ['resolve-suins-name', address], + queryKey: ['resolve-iotans-name', address], queryFn: async () => { // NOTE: We only fetch 1 here because it's the default name. const { data } = await client.resolveNameServiceNames({ diff --git a/apps/core/src/hooks/useAppsBackend.ts b/apps/core/src/hooks/useAppsBackend.ts index 3721dca5f57..e57dd842439 100644 --- a/apps/core/src/hooks/useAppsBackend.ts +++ b/apps/core/src/hooks/useAppsBackend.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { getAppsBackend } from '@mysten/sui.js/client'; +import { getAppsBackend } from '@iota/iota.js/client'; import { useCallback } from 'react'; export function useAppsBackend() { diff --git a/apps/core/src/hooks/useCookieConsentBanner.ts b/apps/core/src/hooks/useCookieConsentBanner.ts index c394a805852..da89e4426eb 100644 --- a/apps/core/src/hooks/useCookieConsentBanner.ts +++ b/apps/core/src/hooks/useCookieConsentBanner.ts @@ -1,6 +1,4 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 diff --git a/apps/core/src/hooks/useCopyToClipboard.ts b/apps/core/src/hooks/useCopyToClipboard.ts index cfd798e1c32..4b4f6b79869 100644 --- a/apps/core/src/hooks/useCopyToClipboard.ts +++ b/apps/core/src/hooks/useCopyToClipboard.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useCallback } from 'react'; diff --git a/apps/core/src/hooks/useElementDimensions.ts b/apps/core/src/hooks/useElementDimensions.ts index 53e90cf504e..b5d1cbf5033 100644 --- a/apps/core/src/hooks/useElementDimensions.ts +++ b/apps/core/src/hooks/useElementDimensions.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { RefObject, useEffect, useState } from 'react'; diff --git a/apps/core/src/hooks/useFormatCoin.ts b/apps/core/src/hooks/useFormatCoin.ts index 5a1d65cecc2..e8fed32dda3 100644 --- a/apps/core/src/hooks/useFormatCoin.ts +++ b/apps/core/src/hooks/useFormatCoin.ts @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { CoinMetadata } from '@mysten/sui.js/client'; -import { SUI_TYPE_ARG } from '@mysten/sui.js/utils'; +import { useIotaClient } from '@iota/dapp-kit'; +import { CoinMetadata } from '@iota/iota.js/client'; +import { IOTA_TYPE_ARG } from '@iota/iota.js/utils'; import { useQuery, type UseQueryResult } from '@tanstack/react-query'; import BigNumber from 'bignumber.js'; import { useMemo } from 'react'; @@ -45,7 +46,7 @@ const SYMBOL_TRUNCATE_LENGTH = 5; const NAME_TRUNCATE_LENGTH = 10; export function useCoinMetadata(coinType?: string | null) { - const client = useSuiClient(); + const client = useIotaClient(); return useQuery({ queryKey: ['coin-metadata', coinType], queryFn: async () => { @@ -55,15 +56,15 @@ export function useCoinMetadata(coinType?: string | null) { ); } - // Optimize the known case of SUI to avoid a network call: - if (coinType === SUI_TYPE_ARG) { + // Optimize the known case of IOTA to avoid a network call: + if (coinType === IOTA_TYPE_ARG) { const metadata: CoinMetadata = { id: null, decimals: 9, description: '', iconUrl: null, - name: 'Sui', - symbol: 'SUI', + name: 'Iota', + symbol: 'IOTA', }; return metadata; diff --git a/apps/core/src/hooks/useGetAllCoins.ts b/apps/core/src/hooks/useGetAllCoins.ts index b0ffed2915f..ce4af8de50b 100644 --- a/apps/core/src/hooks/useGetAllCoins.ts +++ b/apps/core/src/hooks/useGetAllCoins.ts @@ -1,18 +1,16 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import type { CoinStruct, PaginatedCoins } from '@mysten/sui.js/client'; +import { useIotaClient } from '@iota/dapp-kit'; +import type { CoinStruct, PaginatedCoins } from '@iota/iota.js/client'; import { useQuery } from '@tanstack/react-query'; const MAX_COINS_PER_REQUEST = 100; // Fetch all coins for an address, this will keep calling the API until all coins are fetched export function useGetAllCoins(coinType: string, address?: string | null) { - const rpc = useSuiClient(); + const rpc = useIotaClient(); return useQuery({ queryKey: ['get-all-coins', address, coinType], queryFn: async () => { diff --git a/apps/core/src/hooks/useGetCoins.ts b/apps/core/src/hooks/useGetCoins.ts index 148a8f3900c..34c87b136df 100644 --- a/apps/core/src/hooks/useGetCoins.ts +++ b/apps/core/src/hooks/useGetCoins.ts @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { PaginatedCoins } from '@mysten/sui.js/client'; +import { useIotaClient } from '@iota/dapp-kit'; +import { PaginatedCoins } from '@iota/iota.js/client'; import { useInfiniteQuery } from '@tanstack/react-query'; const MAX_COINS_PER_REQUEST = 10; @@ -12,7 +13,7 @@ export function useGetCoins( address?: string | null, maxCoinsPerRequest = MAX_COINS_PER_REQUEST, ) { - const client = useSuiClient(); + const client = useIotaClient(); return useInfiniteQuery({ queryKey: ['get-coins', address, coinType, maxCoinsPerRequest], initialPageParam: null, diff --git a/apps/core/src/hooks/useGetDelegatedStake.tsx b/apps/core/src/hooks/useGetDelegatedStake.tsx index 6bdad5e1dea..5b4cd55e914 100644 --- a/apps/core/src/hooks/useGetDelegatedStake.tsx +++ b/apps/core/src/hooks/useGetDelegatedStake.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import type { DelegatedStake } from '@mysten/sui.js/client'; +import { useIotaClient } from '@iota/dapp-kit'; +import type { DelegatedStake } from '@iota/iota.js/client'; import { useQuery, type UseQueryOptions } from '@tanstack/react-query'; type UseGetDelegatedStakesOptions = { @@ -10,7 +11,7 @@ type UseGetDelegatedStakesOptions = { } & Omit, 'queryKey' | 'queryFn'>; export function useGetDelegatedStake(options: UseGetDelegatedStakesOptions) { - const client = useSuiClient(); + const client = useIotaClient(); const { address, ...queryOptions } = options; return useQuery({ diff --git a/apps/core/src/hooks/useGetDynamicFields.ts b/apps/core/src/hooks/useGetDynamicFields.ts index 3b7177d2d04..8e466b30267 100644 --- a/apps/core/src/hooks/useGetDynamicFields.ts +++ b/apps/core/src/hooks/useGetDynamicFields.ts @@ -1,20 +1,21 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { DynamicFieldPage } from '@mysten/sui.js/client'; -import { normalizeSuiAddress } from '@mysten/sui.js/utils'; +import { useIotaClient } from '@iota/dapp-kit'; +import { DynamicFieldPage } from '@iota/iota.js/client'; +import { normalizeIotaAddress } from '@iota/iota.js/utils'; import { useInfiniteQuery } from '@tanstack/react-query'; const MAX_PAGE_SIZE = 10; export function useGetDynamicFields(parentId: string, maxPageSize = MAX_PAGE_SIZE) { - const client = useSuiClient(); + const client = useIotaClient(); return useInfiniteQuery({ queryKey: ['dynamic-fields', { maxPageSize, parentId }], queryFn: ({ pageParam = null }) => client.getDynamicFields({ - parentId: normalizeSuiAddress(parentId), + parentId: normalizeIotaAddress(parentId), cursor: pageParam as string | null, limit: maxPageSize, }), diff --git a/apps/core/src/hooks/useGetKioskContents.ts b/apps/core/src/hooks/useGetKioskContents.ts index 27278c35d46..3f9a4ca8b79 100644 --- a/apps/core/src/hooks/useGetKioskContents.ts +++ b/apps/core/src/hooks/useGetKioskContents.ts @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClientContext } from '@mysten/dapp-kit'; -import { KIOSK_ITEM, KioskClient, KioskItem, KioskOwnerCap } from '@mysten/kiosk'; -import { SuiClient } from '@mysten/sui.js/client'; +import { useIotaClientContext } from '@iota/dapp-kit'; +import { KIOSK_ITEM, KioskClient, KioskItem, KioskOwnerCap } from '@iota/kiosk'; +import { IotaClient } from '@iota/iota.js/client'; import { useQuery } from '@tanstack/react-query'; import { getKioskIdFromOwnerCap, ORIGINBYTE_KIOSK_OWNER_TOKEN } from '../utils/kiosk'; import { useKioskClient } from './useKioskClient'; export enum KioskTypes { - SUI = 'sui', + IOTA = 'iota', ORIGINBYTE = 'originByte', } @@ -22,7 +23,7 @@ export type Kiosk = { ownerCap?: KioskOwnerCap; }; -async function getOriginByteKioskContents(address: string, client: SuiClient) { +async function getOriginByteKioskContents(address: string, client: IotaClient) { const data = await client.getOwnedObjects({ owner: address, filter: { @@ -75,7 +76,7 @@ async function getOriginByteKioskContents(address: string, client: SuiClient) { return contents; } -async function getSuiKioskContents(address: string, kioskClient: KioskClient) { +async function getIotaKioskContents(address: string, kioskClient: KioskClient) { const ownedKiosks = await kioskClient.getOwnedKiosks({ address }); const contents = await Promise.all( ownedKiosks.kioskIds.map(async (id: string) => { @@ -90,7 +91,7 @@ async function getSuiKioskContents(address: string, kioskClient: KioskClient) { itemIds: kiosk.itemIds, items: kiosk.items, kioskId: id, - type: KioskTypes.SUI, + type: KioskTypes.IOTA, ownerCap: ownedKiosks.kioskOwnerCaps.find((k) => k.kioskId === id), }; }), @@ -99,7 +100,7 @@ async function getSuiKioskContents(address: string, kioskClient: KioskClient) { } export function useGetKioskContents(address?: string | null, disableOriginByteKiosk?: boolean) { - const { client: suiClient, network } = useSuiClientContext(); + const { client: iotaClient, network } = useIotaClientContext(); const kioskClient = useKioskClient(); return useQuery({ // eslint-disable-next-line @tanstack/query/exhaustive-deps @@ -111,9 +112,9 @@ export function useGetKioskContents(address?: string | null, disableOriginByteKi kioskClient.network, ], queryFn: async () => { - const suiKiosks = await getSuiKioskContents(address!, kioskClient); - const obKiosks = await getOriginByteKioskContents(address!, suiClient); - return [...suiKiosks, ...obKiosks]; + const iotaKiosks = await getIotaKioskContents(address!, kioskClient); + const obKiosks = await getOriginByteKioskContents(address!, iotaClient); + return [...iotaKiosks, ...obKiosks]; }, select(data) { const kiosks = new Map(); diff --git a/apps/core/src/hooks/useGetObject.ts b/apps/core/src/hooks/useGetObject.ts index fa2113dabd8..e2ab0f8bc1e 100644 --- a/apps/core/src/hooks/useGetObject.ts +++ b/apps/core/src/hooks/useGetObject.ts @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { normalizeSuiAddress } from '@mysten/sui.js/utils'; +import { useIotaClient } from '@iota/dapp-kit'; +import { normalizeIotaAddress } from '@iota/iota.js/utils'; import { useQuery } from '@tanstack/react-query'; const defaultOptions = { @@ -15,8 +16,8 @@ const defaultOptions = { }; export function useGetObject(objectId?: string | null) { - const client = useSuiClient(); - const normalizedObjId = objectId && normalizeSuiAddress(objectId); + const client = useIotaClient(); + const normalizedObjId = objectId && normalizeIotaAddress(objectId); return useQuery({ queryKey: ['object', normalizedObjId], queryFn: () => diff --git a/apps/core/src/hooks/useGetOwnedObjects.ts b/apps/core/src/hooks/useGetOwnedObjects.ts index 435169e53fd..578a2e5c5cb 100644 --- a/apps/core/src/hooks/useGetOwnedObjects.ts +++ b/apps/core/src/hooks/useGetOwnedObjects.ts @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { PaginatedObjectsResponse, type SuiObjectDataFilter } from '@mysten/sui.js/client'; +import { useIotaClient } from '@iota/dapp-kit'; +import { PaginatedObjectsResponse, type IotaObjectDataFilter } from '@iota/iota.js/client'; import { useInfiniteQuery } from '@tanstack/react-query'; const MAX_OBJECTS_PER_REQ = 6; export function useGetOwnedObjects( address?: string | null, - filter?: SuiObjectDataFilter, + filter?: IotaObjectDataFilter, maxObjectRequests = MAX_OBJECTS_PER_REQ, ) { - const client = useSuiClient(); + const client = useIotaClient(); return useInfiniteQuery({ initialPageParam: null, queryKey: ['get-owned-objects', address, filter, maxObjectRequests], diff --git a/apps/core/src/hooks/useGetTimeBeforeEpochNumber.ts b/apps/core/src/hooks/useGetTimeBeforeEpochNumber.ts index 2048dee63f1..2aefe684ac3 100644 --- a/apps/core/src/hooks/useGetTimeBeforeEpochNumber.ts +++ b/apps/core/src/hooks/useGetTimeBeforeEpochNumber.ts @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClientQuery } from '@mysten/dapp-kit'; +import { useIotaClientQuery } from '@iota/dapp-kit'; // Get time between current epoch and specified epoch // Get the period between the current epoch and next epoch export function useGetTimeBeforeEpochNumber(epoch: number) { - const data = useSuiClientQuery('getLatestSuiSystemState'); + const data = useIotaClientQuery('getLatestIotaSystemState'); // Current epoch const currentEpoch = Number(data.data?.epoch || 0); const currentEpochStartTime = Number(data.data?.epochStartTimestampMs || 0); diff --git a/apps/core/src/hooks/useGetTransferAmount.ts b/apps/core/src/hooks/useGetTransferAmount.ts index 6c2ff2a896a..3e48fdf94aa 100644 --- a/apps/core/src/hooks/useGetTransferAmount.ts +++ b/apps/core/src/hooks/useGetTransferAmount.ts @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiTransactionBlockResponse } from '@mysten/sui.js/client'; -import { SUI_TYPE_ARG } from '@mysten/sui.js/utils'; +import { IotaTransactionBlockResponse } from '@iota/iota.js/client'; +import { IOTA_TYPE_ARG } from '@iota/iota.js/utils'; import { useMemo } from 'react'; import { getTotalGasUsed } from '../utils/transaction'; -export function useGetTransferAmount(txnData: SuiTransactionBlockResponse) { +export function useGetTransferAmount(txnData: IotaTransactionBlockResponse) { const { balanceChanges } = txnData; const sender = txnData.transaction?.data.sender; const gas = txnData.effects && getTotalGasUsed(txnData.effects); @@ -24,7 +25,7 @@ export function useGetTransferAmount(txnData: SuiTransactionBlockResponse) { ? owner.ObjectOwner : '', amount: - coinType === SUI_TYPE_ARG && BigInt(amount) < 0n + coinType === IOTA_TYPE_ARG && BigInt(amount) < 0n ? BigInt(amount) + BigInt(gas ?? 0n) : BigInt(amount), })) diff --git a/apps/core/src/hooks/useGetValidatorsApy.ts b/apps/core/src/hooks/useGetValidatorsApy.ts index 89f1aa5c6ac..400d01919e1 100644 --- a/apps/core/src/hooks/useGetValidatorsApy.ts +++ b/apps/core/src/hooks/useGetValidatorsApy.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient, useSuiClientQuery } from '@mysten/dapp-kit'; +import { useIotaClient, useIotaClientQuery } from '@iota/dapp-kit'; import { useQuery } from '@tanstack/react-query'; import { roundFloat } from '../utils/roundFloat'; @@ -23,8 +24,8 @@ export interface ApyByValidator { const MINIMUM_THRESHOLD = 0.001; export function useGetValidatorsApy() { - const client = useSuiClient(); - const { data: systemStateResponse, isFetched } = useSuiClientQuery('getLatestSuiSystemState'); + const client = useIotaClient(); + const { data: systemStateResponse, isFetched } = useIotaClientQuery('getLatestIotaSystemState'); return useQuery({ queryKey: ['get-rolling-average-apys'], queryFn: () => client.getValidatorsApy(), diff --git a/apps/core/src/hooks/useGetValidatorsEvents.ts b/apps/core/src/hooks/useGetValidatorsEvents.ts index c402b70a047..f8770039523 100644 --- a/apps/core/src/hooks/useGetValidatorsEvents.ts +++ b/apps/core/src/hooks/useGetValidatorsEvents.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { SuiEvent, type EventId } from '@mysten/sui.js/client'; +import { useIotaClient } from '@iota/dapp-kit'; +import { IotaEvent, type EventId } from '@iota/iota.js/client'; import { useQuery } from '@tanstack/react-query'; type GetValidatorsEvent = { @@ -15,7 +16,7 @@ const VALIDATORS_EVENTS_QUERY = '0x3::validator_set::ValidatorEpochInfoEventV2'; //TODO: get validatorEvents by validator address export function useGetValidatorsEvents({ limit, order }: GetValidatorsEvent) { - const client = useSuiClient(); + const client = useIotaClient(); // Since we are getting events based on the number of validators, we need to make sure that the limit // is not null and cache by the limit number of validators can change from network to network return useQuery({ @@ -32,7 +33,7 @@ export function useGetValidatorsEvents({ limit, order }: GetValidatorsEvent) { if (limit > QUERY_MAX_RESULT_LIMIT) { let hasNextPage = true; let currCursor: EventId | null | undefined; - const results: SuiEvent[] = []; + const results: IotaEvent[] = []; while (hasNextPage && results.length < limit) { const validatorEventsResponse = await client.queryEvents({ @@ -44,7 +45,7 @@ export function useGetValidatorsEvents({ limit, order }: GetValidatorsEvent) { hasNextPage = validatorEventsResponse.hasNextPage; currCursor = validatorEventsResponse.nextCursor; - results.push(...(validatorEventsResponse.data as SuiEvent[])); + results.push(...(validatorEventsResponse.data as IotaEvent[])); } return results.slice(0, limit); } diff --git a/apps/core/src/hooks/useIotaCoinData.ts b/apps/core/src/hooks/useIotaCoinData.ts new file mode 100644 index 00000000000..277b0a11b1b --- /dev/null +++ b/apps/core/src/hooks/useIotaCoinData.ts @@ -0,0 +1,29 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { useQuery } from '@tanstack/react-query'; + +import { useAppsBackend } from './useAppsBackend'; + +// TODO: We should consider using tRPC or something for apps-backend +type CoinData = { + marketCap: string; + fullyDilutedMarketCap: string; + currentPrice: number; + priceChangePercentageOver24H: number; + circulatingSupply: number; + totalSupply: number; +}; + +export const COIN_GECKO_IOTA_URL = 'https://www.coingecko.com/en/coins/iota'; + +export function useIotaCoinData() { + const { request } = useAppsBackend(); + return useQuery({ + queryKey: ['iota-coin-data'], + queryFn: () => request('coins/iota', {}), + gcTime: 24 * 60 * 60 * 1000, + staleTime: Infinity, + }); +} diff --git a/apps/core/src/hooks/useKioskClient.ts b/apps/core/src/hooks/useKioskClient.ts index d0483b7485e..1483c8bed05 100644 --- a/apps/core/src/hooks/useKioskClient.ts +++ b/apps/core/src/hooks/useKioskClient.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useContext } from 'react'; diff --git a/apps/core/src/hooks/useLocalStorage.ts b/apps/core/src/hooks/useLocalStorage.ts index 6b3f5311413..7aa7276228e 100644 --- a/apps/core/src/hooks/useLocalStorage.ts +++ b/apps/core/src/hooks/useLocalStorage.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Dispatch, SetStateAction, useCallback, useState } from 'react'; diff --git a/apps/core/src/hooks/useMultiGetObjects.ts b/apps/core/src/hooks/useMultiGetObjects.ts index 3ed266bd526..db645fca8ce 100644 --- a/apps/core/src/hooks/useMultiGetObjects.ts +++ b/apps/core/src/hooks/useMultiGetObjects.ts @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { SuiObjectDataOptions, SuiObjectResponse } from '@mysten/sui.js/client'; +import { useIotaClient } from '@iota/dapp-kit'; +import { IotaObjectDataOptions, IotaObjectResponse } from '@iota/iota.js/client'; import { useQuery, UseQueryOptions } from '@tanstack/react-query'; import { chunkArray } from '../utils/chunkArray'; export function useMultiGetObjects( ids: string[], - options: SuiObjectDataOptions, - queryOptions?: Omit, 'queryKey' | 'queryFn'>, + options: IotaObjectDataOptions, + queryOptions?: Omit, 'queryKey' | 'queryFn'>, ) { - const client = useSuiClient(); + const client = useIotaClient(); return useQuery({ ...queryOptions, queryKey: ['multiGetObjects', ids], diff --git a/apps/core/src/hooks/useOnScreen.ts b/apps/core/src/hooks/useOnScreen.ts index 701000d2325..33ae1701b8c 100644 --- a/apps/core/src/hooks/useOnScreen.ts +++ b/apps/core/src/hooks/useOnScreen.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { MutableRefObject, useEffect, useState } from 'react'; diff --git a/apps/core/src/hooks/useProductAnalyticsConfig.ts b/apps/core/src/hooks/useProductAnalyticsConfig.ts index 6f1061116a2..afc03276d49 100644 --- a/apps/core/src/hooks/useProductAnalyticsConfig.ts +++ b/apps/core/src/hooks/useProductAnalyticsConfig.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useQuery } from '@tanstack/react-query'; diff --git a/apps/core/src/hooks/useSuiCoinData.ts b/apps/core/src/hooks/useSuiCoinData.ts deleted file mode 100644 index 19fe663f0ae..00000000000 --- a/apps/core/src/hooks/useSuiCoinData.ts +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import { useQuery } from '@tanstack/react-query'; - -import { useAppsBackend } from './useAppsBackend'; - -// TODO: We should consider using tRPC or something for apps-backend -type CoinData = { - marketCap: string; - fullyDilutedMarketCap: string; - currentPrice: number; - priceChangePercentageOver24H: number; - circulatingSupply: number; - totalSupply: number; -}; - -export const COIN_GECKO_SUI_URL = 'https://www.coingecko.com/en/coins/sui'; - -export function useSuiCoinData() { - const { request } = useAppsBackend(); - return useQuery({ - queryKey: ['sui-coin-data'], - queryFn: () => request('coins/sui', {}), - gcTime: 24 * 60 * 60 * 1000, - staleTime: Infinity, - }); -} diff --git a/apps/core/src/hooks/useTimeAgo.ts b/apps/core/src/hooks/useTimeAgo.ts index 8a99788b78c..6e892254b7d 100644 --- a/apps/core/src/hooks/useTimeAgo.ts +++ b/apps/core/src/hooks/useTimeAgo.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useEffect, useMemo, useState } from 'react'; diff --git a/apps/core/src/hooks/useTokenPrice.ts b/apps/core/src/hooks/useTokenPrice.ts index 28093fdc113..1c6d980d3f1 100644 --- a/apps/core/src/hooks/useTokenPrice.ts +++ b/apps/core/src/hooks/useTokenPrice.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useQuery } from '@tanstack/react-query'; diff --git a/apps/core/src/hooks/useTransactionSummary.ts b/apps/core/src/hooks/useTransactionSummary.ts index e61f82bf36b..a0315a79353 100644 --- a/apps/core/src/hooks/useTransactionSummary.ts +++ b/apps/core/src/hooks/useTransactionSummary.ts @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { DryRunTransactionBlockResponse, - type SuiTransactionBlockResponse, -} from '@mysten/sui.js/client'; + type IotaTransactionBlockResponse, +} from '@iota/iota.js/client'; import { useMemo } from 'react'; import { getBalanceChangeSummary } from '../utils/transaction/getBalanceChangeSummary'; @@ -11,7 +12,7 @@ import { getGasSummary } from '../utils/transaction/getGasSummary'; import { getLabel } from '../utils/transaction/getLabel'; import { getObjectChangeSummary, - SuiObjectChangeWithDisplay, + IotaObjectChangeWithDisplay, } from '../utils/transaction/getObjectChangeSummary'; import { getObjectDisplayLookup } from '../utils/transaction/getObjectDisplayLookup'; import { useMultiGetObjects } from './useMultiGetObjects'; @@ -21,7 +22,7 @@ export function useTransactionSummary({ currentAddress, recognizedPackagesList, }: { - transaction?: SuiTransactionBlockResponse | DryRunTransactionBlockResponse; + transaction?: IotaTransactionBlockResponse | DryRunTransactionBlockResponse; currentAddress?: string; recognizedPackagesList: string[]; }) { @@ -41,7 +42,7 @@ export function useTransactionSummary({ display: 'objectId' in change ? lookup?.get(change.objectId) : null, })), [lookup, objectChanges], - ) as SuiObjectChangeWithDisplay[]; + ) as IotaObjectChangeWithDisplay[]; const summary = useMemo(() => { if (!transaction) return null; diff --git a/apps/core/src/hooks/useZodForm.ts b/apps/core/src/hooks/useZodForm.ts index 12b1793829f..f16de4993f2 100644 --- a/apps/core/src/hooks/useZodForm.ts +++ b/apps/core/src/hooks/useZodForm.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { zodResolver } from '@hookform/resolvers/zod'; diff --git a/apps/core/src/index.ts b/apps/core/src/index.ts index 7a1bd53135d..34d75472843 100644 --- a/apps/core/src/index.ts +++ b/apps/core/src/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export * from './api/SentryHttpTransport'; @@ -32,7 +33,7 @@ export * from './hooks/useGetKioskContents'; export * from './hooks/useZodForm'; export * from './utils/kiosk'; export * from './hooks/useElementDimensions'; -export * from './hooks/useSuiCoinData'; +export * from './hooks/useIotaCoinData'; export * from './hooks/useLocalStorage'; export * from './hooks/useGetDelegatedStake'; export * from './hooks/useTokenPrice'; diff --git a/apps/core/src/utils/calculateStakeShare.ts b/apps/core/src/utils/calculateStakeShare.ts index de6c73cea2f..2ca1b9b246e 100644 --- a/apps/core/src/utils/calculateStakeShare.ts +++ b/apps/core/src/utils/calculateStakeShare.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import BigNumber from 'bignumber.js'; diff --git a/apps/core/src/utils/chunkArray.ts b/apps/core/src/utils/chunkArray.ts index fa24cc1e449..a95415bfb8e 100644 --- a/apps/core/src/utils/chunkArray.ts +++ b/apps/core/src/utils/chunkArray.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export function chunkArray(arr: T[], chunkSize: number) { diff --git a/apps/core/src/utils/formatAmount.ts b/apps/core/src/utils/formatAmount.ts index fae786abb96..a745d5c7552 100644 --- a/apps/core/src/utils/formatAmount.ts +++ b/apps/core/src/utils/formatAmount.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import BigNumber from 'bignumber.js'; diff --git a/apps/core/src/utils/formatPercentageDisplay.ts b/apps/core/src/utils/formatPercentageDisplay.ts index ce0ea1381c1..5c62c79958e 100644 --- a/apps/core/src/utils/formatPercentageDisplay.ts +++ b/apps/core/src/utils/formatPercentageDisplay.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // For unavailable %, return '--' else return the APY number diff --git a/apps/core/src/utils/getRefGasPrice.ts b/apps/core/src/utils/getRefGasPrice.ts index c7d9bcd8e2d..21690dbac59 100644 --- a/apps/core/src/utils/getRefGasPrice.ts +++ b/apps/core/src/utils/getRefGasPrice.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiValidatorSummary } from '@mysten/sui.js/client'; +import { IotaValidatorSummary } from '@iota/iota.js/client'; import { calculateStakeShare } from './calculateStakeShare'; @@ -13,7 +14,7 @@ const REF_THRESHOLD = 66.67; * 2. Add up stake share from low to high, until reaching REF_THRESHOLD * 3. Return the gas price of the last validator that was added to the sum */ -export function getRefGasPrice(validators?: SuiValidatorSummary[]) { +export function getRefGasPrice(validators?: IotaValidatorSummary[]) { if (!validators?.length) { return BigInt(0); } @@ -34,7 +35,7 @@ export function getRefGasPrice(validators?: SuiValidatorSummary[]) { }); const totalStaked = validators.reduce( - (acc, cur) => acc + BigInt(cur.stakingPoolSuiBalance), + (acc, cur) => acc + BigInt(cur.stakingPoolIotaBalance), BigInt(0), ); @@ -43,7 +44,7 @@ export function getRefGasPrice(validators?: SuiValidatorSummary[]) { for (let i = 0; i < sortedByGasPrice.length; i++) { const validator = sortedByGasPrice[i]; - const stake = BigInt(validator?.stakingPoolSuiBalance); + const stake = BigInt(validator?.stakingPoolIotaBalance); const stakeShare = calculateStakeShare(stake, totalStaked); diff --git a/apps/core/src/utils/hasDisplayData.ts b/apps/core/src/utils/hasDisplayData.ts index 034382eccf4..da82d6342a4 100644 --- a/apps/core/src/utils/hasDisplayData.ts +++ b/apps/core/src/utils/hasDisplayData.ts @@ -1,6 +1,7 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiObjectResponse } from '@mysten/sui.js/client'; +import { IotaObjectResponse } from '@iota/iota.js/client'; -export const hasDisplayData = (obj: SuiObjectResponse) => !!obj.data?.display?.data; +export const hasDisplayData = (obj: IotaObjectResponse) => !!obj.data?.display?.data; diff --git a/apps/core/src/utils/kiosk.ts b/apps/core/src/utils/kiosk.ts index 895e52e830b..156378dce01 100644 --- a/apps/core/src/utils/kiosk.ts +++ b/apps/core/src/utils/kiosk.ts @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { KIOSK_OWNER_CAP, Network, PERSONAL_KIOSK_RULE_ADDRESS } from '@mysten/kiosk'; -import { SuiObjectData, SuiObjectResponse } from '@mysten/sui.js/client'; +import { KIOSK_OWNER_CAP, Network, PERSONAL_KIOSK_RULE_ADDRESS } from '@iota/kiosk'; +import { IotaObjectData, IotaObjectResponse } from '@iota/iota.js/client'; export const ORIGINBYTE_KIOSK_MODULE = '0x95a441d389b07437d00dd07e0b6f05f513d7659b13fd7c5d3923c7d9d847199b::ob_kiosk'; @@ -11,10 +12,10 @@ export const ORIGINBYTE_KIOSK_OWNER_TOKEN = `${ORIGINBYTE_KIOSK_MODULE}::OwnerTo export function isKioskOwnerToken( network: Network, - object?: SuiObjectResponse | SuiObjectData | null, + object?: IotaObjectResponse | IotaObjectData | null, ) { if (!object) return false; - const objectData = 'data' in object && object.data ? object.data : (object as SuiObjectData); + const objectData = 'data' in object && object.data ? object.data : (object as IotaObjectData); return [ KIOSK_OWNER_CAP, `${PERSONAL_KIOSK_RULE_ADDRESS[network]}::personal_kiosk::PersonalKioskCap`, @@ -22,8 +23,8 @@ export function isKioskOwnerToken( ].includes(objectData?.type ?? ''); } -export function getKioskIdFromOwnerCap(object: SuiObjectResponse | SuiObjectData) { - const objectData = 'data' in object && object.data ? object.data : (object as SuiObjectData); +export function getKioskIdFromOwnerCap(object: IotaObjectResponse | IotaObjectData) { + const objectData = 'data' in object && object.data ? object.data : (object as IotaObjectData); const fields = objectData.content?.dataType === 'moveObject' ? (objectData.content.fields as { diff --git a/apps/core/src/utils/persistableStorage.ts b/apps/core/src/utils/persistableStorage.ts index 9f44820edaf..75fecb3f09e 100644 --- a/apps/core/src/utils/persistableStorage.ts +++ b/apps/core/src/utils/persistableStorage.ts @@ -1,6 +1,4 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 diff --git a/apps/core/src/utils/roundFloat.ts b/apps/core/src/utils/roundFloat.ts index 8eb1bbd8458..b82b3baa127 100644 --- a/apps/core/src/utils/roundFloat.ts +++ b/apps/core/src/utils/roundFloat.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 const DEFAULT_PRECISION = 2; diff --git a/apps/core/src/utils/transaction/getBalanceChangeSummary.ts b/apps/core/src/utils/transaction/getBalanceChangeSummary.ts index 2574b9501ba..f42c71a285b 100644 --- a/apps/core/src/utils/transaction/getBalanceChangeSummary.ts +++ b/apps/core/src/utils/transaction/getBalanceChangeSummary.ts @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type DryRunTransactionBlockResponse, type ObjectOwner, - type SuiTransactionBlockResponse, -} from '@mysten/sui.js/client'; -import { normalizeSuiObjectId, parseStructTag } from '@mysten/sui.js/utils'; + type IotaTransactionBlockResponse, +} from '@iota/iota.js/client'; +import { normalizeIotaObjectId, parseStructTag } from '@iota/iota.js/utils'; export type BalanceChange = { coinType: string; @@ -32,14 +33,14 @@ function getOwnerAddress(owner: ObjectOwner): string { } export const getBalanceChangeSummary = ( - transaction: DryRunTransactionBlockResponse | SuiTransactionBlockResponse, + transaction: DryRunTransactionBlockResponse | IotaTransactionBlockResponse, recognizedPackagesList: string[], ) => { const { balanceChanges, effects } = transaction; if (!balanceChanges || !effects) return null; const normalizedRecognizedPackages = recognizedPackagesList.map((itm) => - normalizeSuiObjectId(itm), + normalizeIotaObjectId(itm), ); const balanceChangeByOwner = {}; return balanceChanges.reduce((acc, balanceChange) => { diff --git a/apps/core/src/utils/transaction/getGasSummary.ts b/apps/core/src/utils/transaction/getGasSummary.ts index 3581a475d6a..06a78625b12 100644 --- a/apps/core/src/utils/transaction/getGasSummary.ts +++ b/apps/core/src/utils/transaction/getGasSummary.ts @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { DryRunTransactionBlockResponse, GasCostSummary, - SuiGasData, - SuiTransactionBlockResponse, + IotaGasData, + IotaTransactionBlockResponse, TransactionEffects, -} from '@mysten/sui.js/client'; +} from '@iota/iota.js/client'; type Optional = { [K in keyof T]?: T[K]; @@ -14,7 +15,7 @@ type Optional = { export type GasSummaryType = | (GasCostSummary & - Optional & { + Optional & { totalGas?: string; owner?: string; isSponsored: boolean; @@ -23,7 +24,7 @@ export type GasSummaryType = | null; export function getGasSummary( - transaction: SuiTransactionBlockResponse | DryRunTransactionBlockResponse, + transaction: IotaTransactionBlockResponse | DryRunTransactionBlockResponse, ): GasSummaryType { const { effects } = transaction; if (!effects) return null; diff --git a/apps/core/src/utils/transaction/getLabel.ts b/apps/core/src/utils/transaction/getLabel.ts index 9df61b3695f..de486be930b 100644 --- a/apps/core/src/utils/transaction/getLabel.ts +++ b/apps/core/src/utils/transaction/getLabel.ts @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiTransactionBlockResponse } from '@mysten/sui.js/client'; +import { IotaTransactionBlockResponse } from '@iota/iota.js/client'; // todo: add more logic for deriving transaction label -export const getLabel = (transaction: SuiTransactionBlockResponse, currentAddress?: string) => { +export const getLabel = (transaction: IotaTransactionBlockResponse, currentAddress?: string) => { const isSender = transaction.transaction?.data.sender === currentAddress; // Rename to "Send" to Transaction return isSender ? 'Transaction' : 'Receive'; diff --git a/apps/core/src/utils/transaction/getObjectChangeLabel.ts b/apps/core/src/utils/transaction/getObjectChangeLabel.ts index fb6f13c0267..cf9e1b8d467 100644 --- a/apps/core/src/utils/transaction/getObjectChangeLabel.ts +++ b/apps/core/src/utils/transaction/getObjectChangeLabel.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiObjectChangeTypes } from './types'; +import { IotaObjectChangeTypes } from './types'; export const ObjectChangeLabels = { created: 'Created', @@ -12,6 +13,6 @@ export const ObjectChangeLabels = { wrapped: 'Wrap', }; -export function getObjectChangeLabel(type: SuiObjectChangeTypes) { +export function getObjectChangeLabel(type: IotaObjectChangeTypes) { return ObjectChangeLabels[type]; } diff --git a/apps/core/src/utils/transaction/getObjectChangeSummary.ts b/apps/core/src/utils/transaction/getObjectChangeSummary.ts index 3771264f43b..308ca7d8088 100644 --- a/apps/core/src/utils/transaction/getObjectChangeSummary.ts +++ b/apps/core/src/utils/transaction/getObjectChangeSummary.ts @@ -1,59 +1,60 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { DisplayFieldsResponse, - SuiObjectChange, - SuiObjectChangeCreated, - SuiObjectChangeDeleted, - SuiObjectChangeMutated, - SuiObjectChangePublished, - SuiObjectChangeTransferred, - SuiObjectChangeWrapped, -} from '@mysten/sui.js/client'; + IotaObjectChange, + IotaObjectChangeCreated, + IotaObjectChangeDeleted, + IotaObjectChangeMutated, + IotaObjectChangePublished, + IotaObjectChangeTransferred, + IotaObjectChangeWrapped, +} from '@iota/iota.js/client'; import { groupByOwner } from './groupByOwner'; -import { SuiObjectChangeTypes } from './types'; +import { IotaObjectChangeTypes } from './types'; export type WithDisplayFields = T & { display?: DisplayFieldsResponse }; -export type SuiObjectChangeWithDisplay = WithDisplayFields; +export type IotaObjectChangeWithDisplay = WithDisplayFields; export type ObjectChanges = { - changesWithDisplay: SuiObjectChangeWithDisplay[]; - changes: SuiObjectChange[]; + changesWithDisplay: IotaObjectChangeWithDisplay[]; + changes: IotaObjectChange[]; ownerType: string; }; export type ObjectChangesByOwner = Record; export type ObjectChangeSummary = { - [K in SuiObjectChangeTypes]: ObjectChangesByOwner; + [K in IotaObjectChangeTypes]: ObjectChangesByOwner; }; -export const getObjectChangeSummary = (objectChanges: SuiObjectChangeWithDisplay[]) => { +export const getObjectChangeSummary = (objectChanges: IotaObjectChangeWithDisplay[]) => { if (!objectChanges) return null; const mutated = objectChanges.filter( (change) => change.type === 'mutated', - ) as SuiObjectChangeMutated[]; + ) as IotaObjectChangeMutated[]; const created = objectChanges.filter( (change) => change.type === 'created', - ) as SuiObjectChangeCreated[]; + ) as IotaObjectChangeCreated[]; const transferred = objectChanges.filter( (change) => change.type === 'transferred', - ) as SuiObjectChangeTransferred[]; + ) as IotaObjectChangeTransferred[]; const published = objectChanges.filter( (change) => change.type === 'published', - ) as SuiObjectChangePublished[]; + ) as IotaObjectChangePublished[]; const wrapped = objectChanges.filter( (change) => change.type === 'wrapped', - ) as SuiObjectChangeWrapped[]; + ) as IotaObjectChangeWrapped[]; const deleted = objectChanges.filter( (change) => change.type === 'deleted', - ) as SuiObjectChangeDeleted[]; + ) as IotaObjectChangeDeleted[]; return { transferred: groupByOwner(transferred), diff --git a/apps/core/src/utils/transaction/getObjectDisplayLookup.ts b/apps/core/src/utils/transaction/getObjectDisplayLookup.ts index 04504cbe8f3..69d63632476 100644 --- a/apps/core/src/utils/transaction/getObjectDisplayLookup.ts +++ b/apps/core/src/utils/transaction/getObjectDisplayLookup.ts @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { DisplayFieldsResponse, SuiObjectResponse } from '@mysten/sui.js/client'; +import { DisplayFieldsResponse, IotaObjectResponse } from '@iota/iota.js/client'; import { hasDisplayData } from '../hasDisplayData'; -export function getObjectDisplayLookup(objects: SuiObjectResponse[] = []) { +export function getObjectDisplayLookup(objects: IotaObjectResponse[] = []) { const lookup: Map = new Map(); return objects?.filter(hasDisplayData).reduce((acc, curr) => { if (curr.data?.objectId) { diff --git a/apps/core/src/utils/transaction/getOwnerType.ts b/apps/core/src/utils/transaction/getOwnerType.ts index dafeb531e6b..b6aa01fa307 100644 --- a/apps/core/src/utils/transaction/getOwnerType.ts +++ b/apps/core/src/utils/transaction/getOwnerType.ts @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import type { SuiObjectChange } from '@mysten/sui.js/client'; +import type { IotaObjectChange } from '@iota/iota.js/client'; -export const getOwnerType = (change: SuiObjectChange) => { +export const getOwnerType = (change: IotaObjectChange) => { if (!('owner' in change)) return ''; if (typeof change.owner === 'object') { if ('AddressOwner' in change.owner) return 'AddressOwner'; diff --git a/apps/core/src/utils/transaction/groupByOwner.ts b/apps/core/src/utils/transaction/groupByOwner.ts index c59b2b74014..07fc3f54fd2 100644 --- a/apps/core/src/utils/transaction/groupByOwner.ts +++ b/apps/core/src/utils/transaction/groupByOwner.ts @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ObjectChangesByOwner, SuiObjectChangeWithDisplay } from './getObjectChangeSummary'; +import { ObjectChangesByOwner, IotaObjectChangeWithDisplay } from './getObjectChangeSummary'; import { getOwnerType } from './getOwnerType'; -const getOwner = (change: SuiObjectChangeWithDisplay) => { +const getOwner = (change: IotaObjectChangeWithDisplay) => { // published changes don't have an owner if ('owner' in change && typeof change.owner === 'object') { if ('AddressOwner' in change.owner) return change.owner.AddressOwner; @@ -14,7 +15,7 @@ const getOwner = (change: SuiObjectChangeWithDisplay) => { return ''; }; -export const groupByOwner = (changes: SuiObjectChangeWithDisplay[]) => +export const groupByOwner = (changes: IotaObjectChangeWithDisplay[]) => changes.reduce((acc, change) => { const owner = getOwner(change); if (!acc[owner]) diff --git a/apps/core/src/utils/transaction/index.ts b/apps/core/src/utils/transaction/index.ts index 5a084176b71..73f1e5520d2 100644 --- a/apps/core/src/utils/transaction/index.ts +++ b/apps/core/src/utils/transaction/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export * from './getBalanceChangeSummary'; diff --git a/apps/core/src/utils/transaction/types.ts b/apps/core/src/utils/transaction/types.ts index 9eae4c2f36a..dbf6d4c2653 100644 --- a/apps/core/src/utils/transaction/types.ts +++ b/apps/core/src/utils/transaction/types.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { BalanceChangeSummary } from './getBalanceChangeSummary'; @@ -14,7 +15,7 @@ export type TransactionSummary = { objectSummary: ObjectChangeSummary | null; } | null; -export type SuiObjectChangeTypes = +export type IotaObjectChangeTypes = | 'published' | 'transferred' | 'mutated' diff --git a/apps/core/tailwind.config.ts b/apps/core/tailwind.config.ts index 713c818a092..a863e804472 100644 --- a/apps/core/tailwind.config.ts +++ b/apps/core/tailwind.config.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Config } from 'tailwindcss'; @@ -35,7 +36,7 @@ export default { 35: '#FEFEFE', }, - sui: { + iota: { DEFAULT: '#6fbcf0', bright: '#2A38EB', light: '#E1F3FF', diff --git a/apps/core/vitest.config.ts b/apps/core/vitest.config.ts index 968790d3706..b6b826d53b0 100644 --- a/apps/core/vitest.config.ts +++ b/apps/core/vitest.config.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'; diff --git a/apps/explorer/README.md b/apps/explorer/README.md index f365bb797a9..88fb070efdd 100644 --- a/apps/explorer/README.md +++ b/apps/explorer/README.md @@ -1,20 +1,20 @@ -# Sui Explorer +# Iota Explorer -[Sui Explorer](https://explorer.sui.io/) is a network explorer for the Sui network, similar in functionality to [Etherscan](https://etherscan.io/) or [Solana Explorer](https://explorer.solana.com/). Use Sui Explorer to see the latest transactions and objects. +[Iota Explorer](https://explorer.iota.io/) is a network explorer for the Iota network, similar in functionality to [Etherscan](https://etherscan.io/) or [Solana Explorer](https://explorer.solana.com/). Use Iota Explorer to see the latest transactions and objects. # Set Up **Requirements**: Node 18.0.0 or later. -Dependencies are managed using [`pnpm`](https://pnpm.io/). You can start by installing dependencies in the root of the Sui repository: +Dependencies are managed using [`pnpm`](https://pnpm.io/). You can start by installing dependencies in the root of the Iota repository: ``` $ pnpm install ``` -> All `pnpm` commands below are intended to be run in the root of the Sui repo. +> All `pnpm` commands below are intended to be run in the root of the Iota repo. -## Developing the Sui Explorer +## Developing the Iota Explorer To start the explorer dev server, you can run the following command: @@ -29,13 +29,13 @@ This will start the dev server on port 3000, which should be accessible on http: Start validators locally: ```bash -cargo run --bin sui-test-validator +cargo run --bin iota-test-validator ``` In a a separate terminal, you can now run the end-to-end tests: ```bash -pnpm --filter sui-explorer playwright test +pnpm --filter iota-explorer playwright test ``` # Other pnpm commands diff --git a/apps/explorer/index.html b/apps/explorer/index.html index 5e5d8a34eb9..4a913e2b0dd 100644 --- a/apps/explorer/index.html +++ b/apps/explorer/index.html @@ -7,11 +7,11 @@ - - + + - Sui Explorer + Iota Explorer diff --git a/apps/explorer/package.json b/apps/explorer/package.json index fd6292c9ea7..e37f67f059a 100644 --- a/apps/explorer/package.json +++ b/apps/explorer/package.json @@ -1,5 +1,5 @@ { - "name": "sui-explorer", + "name": "iota-explorer", "private": true, "scripts": { "dev": "vite --port 3000", @@ -30,11 +30,11 @@ "@growthbook/growthbook": "^1.0.0", "@growthbook/growthbook-react": "^1.0.0", "@headlessui/react": "^1.7.15", - "@mysten/core": "workspace:*", - "@mysten/dapp-kit": "workspace:*", - "@mysten/icons": "workspace:*", - "@mysten/sui.js": "workspace:*", - "@mysten/ui": "workspace:*", + "@iota/core": "workspace:*", + "@iota/dapp-kit": "workspace:*", + "@iota/icons": "workspace:*", + "@iota/iota.js": "workspace:*", + "@iota/ui": "workspace:*", "@radix-ui/react-collapsible": "^1.0.3", "@radix-ui/react-dropdown-menu": "^2.0.5", "@radix-ui/react-popover": "^1.0.6", diff --git a/apps/explorer/playwright.config.ts b/apps/explorer/playwright.config.ts index cafc4e74a7a..cafac81a68c 100644 --- a/apps/explorer/playwright.config.ts +++ b/apps/explorer/playwright.config.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { devices } from '@playwright/test'; @@ -106,7 +107,7 @@ const config: PlaywrightTestConfig = { { command: process.env.E2E_RUN_LOCAL_NET_CMD ?? - 'RUST_LOG="consensus=off" cargo run --bin sui-test-validator', + 'RUST_LOG="consensus=off" cargo run --bin iota-test-validator', port: 9123, timeout: 120 * 1000, reuseExistingServer: !process.env.CI, diff --git a/apps/explorer/postcss.config.js b/apps/explorer/postcss.config.js index 5b5696cafbb..23af4016123 100644 --- a/apps/explorer/postcss.config.js +++ b/apps/explorer/postcss.config.js @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module.exports = { diff --git a/apps/explorer/public/SuiExplorerCard.png b/apps/explorer/public/IotaExplorerCard.png similarity index 100% rename from apps/explorer/public/SuiExplorerCard.png rename to apps/explorer/public/IotaExplorerCard.png diff --git a/apps/explorer/public/manifest.json b/apps/explorer/public/manifest.json index cabfb94cdc0..2d84f38148c 100644 --- a/apps/explorer/public/manifest.json +++ b/apps/explorer/public/manifest.json @@ -1,6 +1,6 @@ { - "short_name": "sui-explorer", - "name": "Sui Explorer", + "short_name": "iota-explorer", + "name": "Iota Explorer", "icons": [ { "src": "favicon192x192.png", diff --git a/apps/explorer/src/__tests__/unit.test.ts b/apps/explorer/src/__tests__/unit.test.ts index 17dd663668b..aa5aad2b047 100644 --- a/apps/explorer/src/__tests__/unit.test.ts +++ b/apps/explorer/src/__tests__/unit.test.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { timeAgo } from '@mysten/core'; +import { timeAgo } from '@iota/core'; import { describe, it, expect } from 'vitest'; const timeNow = 1735693990000; diff --git a/apps/explorer/src/assets/Sui Logo.svg b/apps/explorer/src/assets/Iota Logo.svg similarity index 100% rename from apps/explorer/src/assets/Sui Logo.svg rename to apps/explorer/src/assets/Iota Logo.svg diff --git a/apps/explorer/src/assets/SuiSymbol.svg b/apps/explorer/src/assets/IotaSymbol.svg similarity index 100% rename from apps/explorer/src/assets/SuiSymbol.svg rename to apps/explorer/src/assets/IotaSymbol.svg diff --git a/apps/explorer/src/assets/SuiWordmark.svg b/apps/explorer/src/assets/IotaWordmark.svg similarity index 100% rename from apps/explorer/src/assets/SuiWordmark.svg rename to apps/explorer/src/assets/IotaWordmark.svg diff --git a/apps/explorer/src/components/AccountCardGraph.tsx b/apps/explorer/src/components/AccountCardGraph.tsx index c78d154dbb4..5de7d15dd2d 100644 --- a/apps/explorer/src/components/AccountCardGraph.tsx +++ b/apps/explorer/src/components/AccountCardGraph.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { formatAmount, formatDate } from '@mysten/core'; -import { type AllEpochsAddressMetrics } from '@mysten/sui.js/client'; -import { Heading, LoadingIndicator, Text } from '@mysten/ui'; +import { formatAmount, formatDate } from '@iota/core'; +import { type AllEpochsAddressMetrics } from '@iota/iota.js/client'; +import { Heading, LoadingIndicator, Text } from '@iota/ui'; import { ParentSize } from '@visx/responsive'; import clsx from 'clsx'; import { useMemo } from 'react'; diff --git a/apps/explorer/src/components/Activity/EpochsActivityTable.tsx b/apps/explorer/src/components/Activity/EpochsActivityTable.tsx index 8421d07d17f..1d3e2679363 100644 --- a/apps/explorer/src/components/Activity/EpochsActivityTable.tsx +++ b/apps/explorer/src/components/Activity/EpochsActivityTable.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient, useSuiClientInfiniteQuery } from '@mysten/dapp-kit'; -import { ArrowRight12 } from '@mysten/icons'; -import { Text } from '@mysten/ui'; +import { useIotaClient, useIotaClientInfiniteQuery } from '@iota/dapp-kit'; +import { ArrowRight12 } from '@iota/icons'; +import { Text } from '@iota/ui'; import { useQuery } from '@tanstack/react-query'; import { useState } from 'react'; @@ -27,7 +28,7 @@ export function EpochsActivityTable({ initialLimit = DEFAULT_EPOCHS_LIMIT, }: Props) { const [limit, setLimit] = useState(initialLimit); - const client = useSuiClient(); + const client = useIotaClient(); const { data: count } = useQuery({ queryKey: ['epochs', 'current'], @@ -35,7 +36,7 @@ export function EpochsActivityTable({ select: (epoch) => Number(epoch.epoch) + 1, }); - const epochMetricsQuery = useSuiClientInfiniteQuery('getEpochMetrics', { + const epochMetricsQuery = useIotaClientInfiniteQuery('getEpochMetrics', { limit, descendingOrder: true, }); diff --git a/apps/explorer/src/components/Activity/TransactionsActivityTable.tsx b/apps/explorer/src/components/Activity/TransactionsActivityTable.tsx index 88a62439fd5..85c3df664e7 100644 --- a/apps/explorer/src/components/Activity/TransactionsActivityTable.tsx +++ b/apps/explorer/src/components/Activity/TransactionsActivityTable.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { ArrowRight12 } from '@mysten/icons'; -import { Text } from '@mysten/ui'; +import { useIotaClient } from '@iota/dapp-kit'; +import { ArrowRight12 } from '@iota/icons'; +import { Text } from '@iota/ui'; import { useQuery } from '@tanstack/react-query'; import { useEffect, useRef, useState } from 'react'; @@ -31,7 +32,7 @@ export function TransactionsActivityTable({ transactionKindFilter, }: Props) { const [limit, setLimit] = useState(initialLimit); - const client = useSuiClient(); + const client = useIotaClient(); const { data: count } = useQuery({ queryKey: ['transactions', 'count'], queryFn: () => client.getTotalTransactionBlocks(), diff --git a/apps/explorer/src/components/Activity/index.tsx b/apps/explorer/src/components/Activity/index.tsx index 5d488b18aa2..09df3c4a216 100644 --- a/apps/explorer/src/components/Activity/index.tsx +++ b/apps/explorer/src/components/Activity/index.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useFeatureIsOn } from '@growthbook/growthbook-react'; -// import { Filter16 } from '@mysten/icons'; -import { Heading } from '@mysten/ui'; +// import { Filter16 } from '@iota/icons'; +import { Heading } from '@iota/ui'; import { useState } from 'react'; import toast from 'react-hot-toast'; diff --git a/apps/explorer/src/components/Activity/utils.tsx b/apps/explorer/src/components/Activity/utils.tsx index b9a8e725467..375af3b3228 100644 --- a/apps/explorer/src/components/Activity/utils.tsx +++ b/apps/explorer/src/components/Activity/utils.tsx @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type EpochMetricsPage } from '@mysten/sui.js/client'; -import { Text } from '@mysten/ui'; +import { type EpochMetricsPage } from '@iota/iota.js/client'; +import { Text } from '@iota/ui'; -import { SuiAmount } from '../Table/SuiAmount'; +import { IotaAmount } from '../Table/IotaAmount'; import { TxTimeType } from '../tx-time/TxTimeType'; import { HighlightedTableCol } from '~/components/Table/HighlightedTableCol'; import { CheckpointSequenceLink, EpochLink } from '~/ui/InternalLink'; @@ -19,7 +20,7 @@ export const genTableDataFromEpochsData = (results: EpochMetricsPage) => ({ ), transactions: {epoch.epochTotalTransactions}, - stakeRewards: , + stakeRewards: , checkpointSet: (
@@ -31,7 +32,7 @@ export const genTableDataFromEpochsData = (results: EpochMetricsPage) => ({ ), storageNetInflow: (
- +
), time: , diff --git a/apps/explorer/src/components/AreaGraph.tsx b/apps/explorer/src/components/AreaGraph.tsx index cc3feacb350..89f1ef9248d 100644 --- a/apps/explorer/src/components/AreaGraph.tsx +++ b/apps/explorer/src/components/AreaGraph.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { AxisBottom, AxisLeft, type TickRendererProps } from '@visx/axis'; diff --git a/apps/explorer/src/components/GasBreakdown/index.tsx b/apps/explorer/src/components/GasBreakdown/index.tsx index aa93d594751..1ebdc2111d2 100644 --- a/apps/explorer/src/components/GasBreakdown/index.tsx +++ b/apps/explorer/src/components/GasBreakdown/index.tsx @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { CoinFormat, type TransactionSummary, useFormatCoin, - useResolveSuiNSName, -} from '@mysten/core'; -import { SUI_TYPE_ARG } from '@mysten/sui.js/utils'; -import { Heading, Text } from '@mysten/ui'; + useResolveIotaNSName, +} from '@iota/core'; +import { IOTA_TYPE_ARG } from '@iota/iota.js/utils'; +import { Heading, Text } from '@iota/ui'; import { CopyToClipboard } from '~/ui/CopyToClipboard'; import { DescriptionItem } from '~/ui/DescriptionList'; @@ -22,7 +23,7 @@ interface GasProps { } function GasAmount({ amount }: GasProps) { - const [formattedAmount, symbol] = useFormatCoin(amount, SUI_TYPE_ARG, CoinFormat.FULL); + const [formattedAmount, symbol] = useFormatCoin(amount, IOTA_TYPE_ARG, CoinFormat.FULL); if (!amount) { return null; @@ -41,14 +42,14 @@ function GasAmount({ amount }: GasProps) {
({BigInt(amount)?.toLocaleString()} -
MIST
) +
MICROS
)
); } function TotalGasAmount({ amount }: GasProps) { - const [formattedAmount, symbol] = useFormatCoin(amount, SUI_TYPE_ARG, CoinFormat.FULL); + const [formattedAmount, symbol] = useFormatCoin(amount, IOTA_TYPE_ARG, CoinFormat.FULL); if (!amount) { return null; @@ -70,7 +71,7 @@ function TotalGasAmount({ amount }: GasProps) { {BigInt(amount)?.toLocaleString()} - MIST + MICROS @@ -96,7 +97,7 @@ interface GasBreakdownProps { export function GasBreakdown({ summary }: GasBreakdownProps) { const gasData = summary?.gas; - const { data: suinsDomainName } = useResolveSuiNSName(gasData?.owner); + const { data: iotansDomainName } = useResolveIotaNSName(gasData?.owner); if (!gasData) { return null; @@ -124,11 +125,11 @@ export function GasBreakdown({ summary }: GasBreakdownProps) { > {isSponsored && owner && ( -
+
Paid by - +
)} diff --git a/apps/explorer/src/components/GraphTooltipContent.tsx b/apps/explorer/src/components/GraphTooltipContent.tsx index 45731c81a87..3a5810027a2 100644 --- a/apps/explorer/src/components/GraphTooltipContent.tsx +++ b/apps/explorer/src/components/GraphTooltipContent.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useTooltipPosition } from '@visx/tooltip'; diff --git a/apps/explorer/src/components/HomeMetrics/Checkpoint.tsx b/apps/explorer/src/components/HomeMetrics/Checkpoint.tsx index 62d484ce937..2933532dc0c 100644 --- a/apps/explorer/src/components/HomeMetrics/Checkpoint.tsx +++ b/apps/explorer/src/components/HomeMetrics/Checkpoint.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { StatsWrapper } from './FormattedStatsAmount'; diff --git a/apps/explorer/src/components/HomeMetrics/CurrentEpoch.tsx b/apps/explorer/src/components/HomeMetrics/CurrentEpoch.tsx index 03a8d4272fd..e1d92b3a665 100644 --- a/apps/explorer/src/components/HomeMetrics/CurrentEpoch.tsx +++ b/apps/explorer/src/components/HomeMetrics/CurrentEpoch.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { formatDate, formatAmountParts } from '@mysten/core'; -import { Text, Heading } from '@mysten/ui'; +import { formatDate, formatAmountParts } from '@iota/core'; +import { Text, Heading } from '@iota/ui'; import { format, isToday, isYesterday } from 'date-fns'; import { useMemo } from 'react'; diff --git a/apps/explorer/src/components/HomeMetrics/FormattedStatsAmount.tsx b/apps/explorer/src/components/HomeMetrics/FormattedStatsAmount.tsx index b44909f2422..1c2cd2fe69e 100644 --- a/apps/explorer/src/components/HomeMetrics/FormattedStatsAmount.tsx +++ b/apps/explorer/src/components/HomeMetrics/FormattedStatsAmount.tsx @@ -1,6 +1,7 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { formatAmountParts } from '@mysten/core'; +import { formatAmountParts } from '@iota/core'; import { Stats, type StatsProps } from '~/ui/Stats'; diff --git a/apps/explorer/src/components/HomeMetrics/OnTheNetwork.tsx b/apps/explorer/src/components/HomeMetrics/OnTheNetwork.tsx index 6f1eb512e2b..52c7d296a59 100644 --- a/apps/explorer/src/components/HomeMetrics/OnTheNetwork.tsx +++ b/apps/explorer/src/components/HomeMetrics/OnTheNetwork.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { CoinFormat, formatBalance } from '@mysten/core'; -import { useSuiClientQuery } from '@mysten/dapp-kit'; -import { Heading } from '@mysten/ui'; +import { CoinFormat, formatBalance } from '@iota/core'; +import { useIotaClientQuery } from '@iota/dapp-kit'; +import { Heading } from '@iota/ui'; import { FormattedStatsAmount, StatsWrapper } from './FormattedStatsAmount'; import { useGetNetworkMetrics } from '~/hooks/useGetNetworkMetrics'; @@ -12,7 +13,7 @@ import { Divider } from '~/ui/Divider'; export function OnTheNetwork() { const { data: networkMetrics } = useGetNetworkMetrics(); - const { data: referenceGasPrice } = useSuiClientQuery('getReferenceGasPrice'); + const { data: referenceGasPrice } = useIotaClientQuery('getReferenceGasPrice'); const gasPriceFormatted = typeof referenceGasPrice === 'bigint' ? formatBalance(referenceGasPrice, 0, CoinFormat.FULL) @@ -50,7 +51,7 @@ export function OnTheNetwork() { orientation="horizontal" label="Reference Gas Price" tooltip="The reference gas price of the current epoch" - postfix={gasPriceFormatted !== null ? 'MIST' : null} + postfix={gasPriceFormatted !== null ? 'MICROS' : null} size="sm" > {gasPriceFormatted} diff --git a/apps/explorer/src/components/HomeMetrics/index.tsx b/apps/explorer/src/components/HomeMetrics/index.tsx index 371095696a3..ebfabb0d28e 100644 --- a/apps/explorer/src/components/HomeMetrics/index.tsx +++ b/apps/explorer/src/components/HomeMetrics/index.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export * from './Checkpoint'; diff --git a/apps/explorer/src/components/IotaTokenCard.tsx b/apps/explorer/src/components/IotaTokenCard.tsx new file mode 100644 index 00000000000..184f8d00f77 --- /dev/null +++ b/apps/explorer/src/components/IotaTokenCard.tsx @@ -0,0 +1,42 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { COIN_GECKO_IOTA_URL, useIotaCoinData } from '@iota/core'; +import { Iota } from '@iota/icons'; +import { Text } from '@iota/ui'; + +import { Card } from '~/ui/Card'; +import { ButtonOrLink } from '~/ui/utils/ButtonOrLink'; + +export function IotaTokenCard() { + const { data } = useIotaCoinData(); + const { currentPrice } = data || {}; + + const formattedPrice = currentPrice + ? currentPrice.toLocaleString('en', { + style: 'currency', + currency: 'USD', + }) + : '--'; + + return ( + + +
+
+ +
+
+ + 1 IOTA = {formattedPrice} + + + via CoinGecko + +
+
+
+
+ ); +} diff --git a/apps/explorer/src/components/Layout/PageLayout.tsx b/apps/explorer/src/components/Layout/PageLayout.tsx index 74f54c97150..0d0045f1f1c 100644 --- a/apps/explorer/src/components/Layout/PageLayout.tsx +++ b/apps/explorer/src/components/Layout/PageLayout.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useFeatureIsOn } from '@growthbook/growthbook-react'; -import { useAppsBackend, useElementDimensions } from '@mysten/core'; -import { LoadingIndicator } from '@mysten/ui'; +import { useAppsBackend, useElementDimensions } from '@iota/core'; +import { LoadingIndicator } from '@iota/ui'; import { useQuery } from '@tanstack/react-query'; import clsx from 'clsx'; import { type ReactNode, useRef } from 'react'; @@ -50,7 +51,7 @@ export function PageLayout({ gradient, content, loading, isError }: PageLayoutPr const networkDegradeBannerCopy = network === Network.Testnet - ? 'Sui Explorer (Testnet) is currently under-going maintenance. Some data may be incorrect or missing.' + ? 'Iota Explorer (Testnet) is currently under-going maintenance. Some data may be incorrect or missing.' : "The explorer is running slower than usual. We're working to fix the issue and appreciate your patience."; return ( diff --git a/apps/explorer/src/components/Layout/index.tsx b/apps/explorer/src/components/Layout/index.tsx index 3dee263ffd4..b54d6f92b42 100644 --- a/apps/explorer/src/components/Layout/index.tsx +++ b/apps/explorer/src/components/Layout/index.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useCookieConsentBanner } from '@mysten/core'; -import { SuiClientProvider, WalletProvider } from '@mysten/dapp-kit'; +import { useCookieConsentBanner } from '@iota/core'; +import { IotaClientProvider, WalletProvider } from '@iota/dapp-kit'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { Fragment } from 'react'; import { resolveValue, Toaster, type ToastType } from 'react-hot-toast'; @@ -12,8 +13,8 @@ import { useInitialPageView } from '../../hooks/useInitialPageView'; import { NetworkContext, useNetwork } from '~/context'; import { Banner, type BannerProps } from '~/ui/Banner'; import { persistableStorage } from '~/utils/analytics/amplitude'; -import { type Network, createSuiClient, SupportedNetworks } from '~/utils/api/DefaultRpcClient'; -import { KioskClientProvider } from '@mysten/core/src/components/KioskClientProvider'; +import { type Network, createIotaClient, SupportedNetworks } from '~/utils/api/DefaultRpcClient'; +import { KioskClientProvider } from '@iota/core/src/components/KioskClientProvider'; const toastVariants: Partial> = { success: 'positive', @@ -24,7 +25,7 @@ export function Layout() { const [network, setNetwork] = useNetwork(); useCookieConsentBanner(persistableStorage, { - cookie_name: 'sui_explorer_cookie_consent', + cookie_name: 'iota_explorer_cookie_consent', onBeforeLoad: async () => { await import('./cookieConsent.css'); document.body.classList.add('cookie-consent-theme'); @@ -37,9 +38,9 @@ export function Layout() { // NOTE: We set a top-level key here to force the entire react tree to be re-created when the network changes: - @@ -70,7 +71,7 @@ export function Layout() { - + ); } diff --git a/apps/explorer/src/components/Object/DynamicFieldsCard.tsx b/apps/explorer/src/components/Object/DynamicFieldsCard.tsx index 66af38c2509..1180d113d4e 100644 --- a/apps/explorer/src/components/Object/DynamicFieldsCard.tsx +++ b/apps/explorer/src/components/Object/DynamicFieldsCard.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useGetDynamicFields, useOnScreen } from '@mysten/core'; -import { type DynamicFieldInfo } from '@mysten/sui.js/client'; -import { LoadingIndicator } from '@mysten/ui'; +import { useGetDynamicFields, useOnScreen } from '@iota/core'; +import { type DynamicFieldInfo } from '@iota/iota.js/client'; +import { LoadingIndicator } from '@iota/ui'; import { useRef, useEffect, useState, useMemo } from 'react'; import { UnderlyingObjectCard } from './UnderlyingObjectCard'; diff --git a/apps/explorer/src/components/Object/FieldItem.tsx b/apps/explorer/src/components/Object/FieldItem.tsx index d445a7ac24f..00448937ca1 100644 --- a/apps/explorer/src/components/Object/FieldItem.tsx +++ b/apps/explorer/src/components/Object/FieldItem.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiMoveNormalizedType } from '@mysten/sui.js/client'; -import { Text } from '@mysten/ui'; +import { type IotaMoveNormalizedType } from '@iota/iota.js/client'; +import { Text } from '@iota/ui'; import { getFieldTypeValue } from './utils'; import { SyntaxHighlighter } from '~/components/SyntaxHighlighter'; @@ -11,7 +12,7 @@ import { Link } from '~/ui/Link'; interface FieldItemProps { value: string | number | object | boolean; - type: SuiMoveNormalizedType | ''; + type: IotaMoveNormalizedType | ''; objectType: string; truncate?: boolean; } diff --git a/apps/explorer/src/components/Object/FieldsUtils.tsx b/apps/explorer/src/components/Object/FieldsUtils.tsx index 113ec19e30a..0a3703b0024 100644 --- a/apps/explorer/src/components/Object/FieldsUtils.tsx +++ b/apps/explorer/src/components/Object/FieldsUtils.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import clsx from 'clsx'; diff --git a/apps/explorer/src/components/Object/ObjectFieldsCard.tsx b/apps/explorer/src/components/Object/ObjectFieldsCard.tsx index 2cb7e1191af..af94d06c344 100644 --- a/apps/explorer/src/components/Object/ObjectFieldsCard.tsx +++ b/apps/explorer/src/components/Object/ObjectFieldsCard.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Search24 } from '@mysten/icons'; -import { type SuiMoveNormalizedStruct, type SuiObjectResponse } from '@mysten/sui.js/client'; -import { Text, LoadingIndicator, Combobox, ComboboxInput, ComboboxList } from '@mysten/ui'; +import { Search24 } from '@iota/icons'; +import { type IotaMoveNormalizedStruct, type IotaObjectResponse } from '@iota/iota.js/client'; +import { Text, LoadingIndicator, Combobox, ComboboxInput, ComboboxList } from '@iota/ui'; import clsx from 'clsx'; import { useCallback, useEffect, useState } from 'react'; @@ -19,8 +20,8 @@ const DEFAULT_FIELDS_COUNT_TO_SHOW_SEARCH = 10; interface ObjectFieldsProps { id: string; - normalizedStructData?: SuiMoveNormalizedStruct; - suiObjectResponseData?: SuiObjectResponse; + normalizedStructData?: IotaMoveNormalizedStruct; + iotaObjectResponseData?: IotaObjectResponse; loading: boolean; error: boolean; objectType?: string; @@ -29,7 +30,7 @@ interface ObjectFieldsProps { export function ObjectFieldsCard({ id, normalizedStructData, - suiObjectResponseData, + iotaObjectResponseData, loading, error, objectType, @@ -88,8 +89,8 @@ export function ObjectFieldsCard({ } const fieldsData = - suiObjectResponseData?.data?.content?.dataType === 'moveObject' - ? (suiObjectResponseData?.data?.content?.fields as Record< + iotaObjectResponseData?.data?.content?.dataType === 'moveObject' + ? (iotaObjectResponseData?.data?.content?.fields as Record< string, string | number | object >) @@ -146,7 +147,7 @@ export function ObjectFieldsCard({
)} diff --git a/apps/explorer/src/components/OwnedObjects/ListView.tsx b/apps/explorer/src/components/OwnedObjects/ListView.tsx index b54b9c3daec..1078f7d6bb1 100644 --- a/apps/explorer/src/components/OwnedObjects/ListView.tsx +++ b/apps/explorer/src/components/OwnedObjects/ListView.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiObjectResponse } from '@mysten/sui.js/client'; -import { formatAddress } from '@mysten/sui.js/utils'; -import { Placeholder, Text } from '@mysten/ui'; +import { type IotaObjectResponse } from '@iota/iota.js/client'; +import { formatAddress } from '@iota/iota.js/utils'; +import { Placeholder, Text } from '@iota/ui'; import { type ReactNode } from 'react'; import { OwnedObjectsText } from '~/components/OwnedObjects/OwnedObjectsText'; @@ -49,7 +50,7 @@ function ListViewItem({ return ; } -function ListViewItemContainer({ obj }: { obj: SuiObjectResponse }) { +function ListViewItemContainer({ obj }: { obj: IotaObjectResponse }) { const video = useResolveVideo(obj); const displayMeta = obj.data?.display?.data; const name = displayMeta?.name ?? displayMeta?.description ?? ''; @@ -97,7 +98,7 @@ function ListViewItemContainer({ obj }: { obj: SuiObjectResponse }) { } interface ListViewProps { - data?: SuiObjectResponse[]; + data?: IotaObjectResponse[]; loading?: boolean; } diff --git a/apps/explorer/src/components/OwnedObjects/OwnedObject.tsx b/apps/explorer/src/components/OwnedObjects/OwnedObject.tsx index 19b7d045981..1da8c754210 100644 --- a/apps/explorer/src/components/OwnedObjects/OwnedObject.tsx +++ b/apps/explorer/src/components/OwnedObjects/OwnedObject.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiObjectResponse } from '@mysten/sui.js/client'; +import { type IotaObjectResponse } from '@iota/iota.js/client'; import { useResolveVideo } from '~/hooks/useResolveVideo'; import { ObjectDetails } from '~/ui/ObjectDetails'; @@ -9,7 +10,7 @@ import { parseObjectType } from '~/utils/objectUtils'; import { trimStdLibPrefix } from '~/utils/stringUtils'; type OwnedObjectTypes = { - obj: SuiObjectResponse; + obj: IotaObjectResponse; }; export default function OwnedObject({ obj }: OwnedObjectTypes) { diff --git a/apps/explorer/src/components/OwnedObjects/OwnedObjectsText.tsx b/apps/explorer/src/components/OwnedObjects/OwnedObjectsText.tsx index 5df2849bdc5..e51aaca1e70 100644 --- a/apps/explorer/src/components/OwnedObjects/OwnedObjectsText.tsx +++ b/apps/explorer/src/components/OwnedObjects/OwnedObjectsText.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { cva, type VariantProps } from 'class-variance-authority'; diff --git a/apps/explorer/src/components/OwnedObjects/SmallThumbnailsView.tsx b/apps/explorer/src/components/OwnedObjects/SmallThumbnailsView.tsx index f92d51ddfc8..6cde30e41a7 100644 --- a/apps/explorer/src/components/OwnedObjects/SmallThumbnailsView.tsx +++ b/apps/explorer/src/components/OwnedObjects/SmallThumbnailsView.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiObjectResponse } from '@mysten/sui.js/client'; -import { formatAddress } from '@mysten/sui.js/utils'; -import { Placeholder } from '@mysten/ui'; +import { type IotaObjectResponse } from '@iota/iota.js/client'; +import { formatAddress } from '@iota/iota.js/utils'; +import { Placeholder } from '@iota/ui'; import { type ReactNode } from 'react'; import { OwnedObjectsText } from '~/components/OwnedObjects/OwnedObjectsText'; @@ -15,7 +16,7 @@ import { trimStdLibPrefix } from '~/utils/stringUtils'; interface Props { limit: number; - data?: SuiObjectResponse[]; + data?: IotaObjectResponse[]; loading?: boolean; } @@ -41,7 +42,7 @@ function SmallThumbnailsViewLoading({ limit }: { limit: number }) { ); } -function SmallThumbnail({ obj }: { obj: SuiObjectResponse }) { +function SmallThumbnail({ obj }: { obj: IotaObjectResponse }) { const video = useResolveVideo(obj); const displayMeta = obj.data?.display?.data; const src = displayMeta?.image_url || ''; diff --git a/apps/explorer/src/components/OwnedObjects/ThumbnailsView.tsx b/apps/explorer/src/components/OwnedObjects/ThumbnailsView.tsx index 9d8a8ca5cd4..1cefe0775f6 100644 --- a/apps/explorer/src/components/OwnedObjects/ThumbnailsView.tsx +++ b/apps/explorer/src/components/OwnedObjects/ThumbnailsView.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiObjectResponse } from '@mysten/sui.js/client'; -import { formatAddress } from '@mysten/sui.js/utils'; -import { Placeholder, Text } from '@mysten/ui'; +import { type IotaObjectResponse } from '@iota/iota.js/client'; +import { formatAddress } from '@iota/iota.js/utils'; +import { Placeholder, Text } from '@iota/ui'; import { useResolveVideo } from '~/hooks/useResolveVideo'; import { ObjectLink } from '~/ui/InternalLink'; @@ -11,7 +12,7 @@ import { ObjectVideoImage } from '~/ui/ObjectVideoImage'; import { parseObjectType } from '~/utils/objectUtils'; import { trimStdLibPrefix } from '~/utils/stringUtils'; -function Thumbnail({ obj }: { obj: SuiObjectResponse }) { +function Thumbnail({ obj }: { obj: IotaObjectResponse }) { const video = useResolveVideo(obj); const displayMeta = obj.data?.display?.data; const src = displayMeta?.image_url || ''; @@ -62,7 +63,7 @@ function ThumbnailsOnlyLoading({ limit }: { limit: number }) { interface ThumbnailsViewViewProps { limit: number; - data?: SuiObjectResponse[]; + data?: IotaObjectResponse[]; loading?: boolean; } diff --git a/apps/explorer/src/components/OwnedObjects/index.tsx b/apps/explorer/src/components/OwnedObjects/index.tsx index b149b180d91..82f529ec404 100644 --- a/apps/explorer/src/components/OwnedObjects/index.tsx +++ b/apps/explorer/src/components/OwnedObjects/index.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useGetKioskContents, useGetOwnedObjects, useLocalStorage } from '@mysten/core'; -import { ThumbnailsOnly16, ViewList16, ViewSmallThumbnails16 } from '@mysten/icons'; -import { Heading, IconButton, RadioGroup, RadioGroupItem, Text } from '@mysten/ui'; +import { useGetKioskContents, useGetOwnedObjects, useLocalStorage } from '@iota/core'; +import { ThumbnailsOnly16, ViewList16, ViewSmallThumbnails16 } from '@iota/icons'; +import { Heading, IconButton, RadioGroup, RadioGroupItem, Text } from '@iota/ui'; import clsx from 'clsx'; import { useEffect, useMemo, useState } from 'react'; diff --git a/apps/explorer/src/components/OwnedObjects/utils.ts b/apps/explorer/src/components/OwnedObjects/utils.ts index b61ea1fee00..f0dc49b22cc 100644 --- a/apps/explorer/src/components/OwnedObjects/utils.ts +++ b/apps/explorer/src/components/OwnedObjects/utils.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export enum ObjectViewMode { diff --git a/apps/explorer/src/components/SuiTokenCard.tsx b/apps/explorer/src/components/SuiTokenCard.tsx deleted file mode 100644 index 5a8c1a06dce..00000000000 --- a/apps/explorer/src/components/SuiTokenCard.tsx +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import { COIN_GECKO_SUI_URL, useSuiCoinData } from '@mysten/core'; -import { Sui } from '@mysten/icons'; -import { Text } from '@mysten/ui'; - -import { Card } from '~/ui/Card'; -import { ButtonOrLink } from '~/ui/utils/ButtonOrLink'; - -export function SuiTokenCard() { - const { data } = useSuiCoinData(); - const { currentPrice } = data || {}; - - const formattedPrice = currentPrice - ? currentPrice.toLocaleString('en', { - style: 'currency', - currency: 'USD', - }) - : '--'; - - return ( - - -
-
- -
-
- - 1 SUI = {formattedPrice} - - - via CoinGecko - -
-
-
-
- ); -} diff --git a/apps/explorer/src/components/SyntaxHighlighter/index.tsx b/apps/explorer/src/components/SyntaxHighlighter/index.tsx index 6212231dc96..e2ea0ba88a5 100644 --- a/apps/explorer/src/components/SyntaxHighlighter/index.tsx +++ b/apps/explorer/src/components/SyntaxHighlighter/index.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useOnScreen } from '@mysten/core'; +import { useOnScreen } from '@iota/core'; import { useRef, useEffect, useState } from 'react'; import Highlight, { defaultProps } from 'prism-react-renderer'; import 'prism-themes/themes/prism-one-light.css'; diff --git a/apps/explorer/src/components/Table/HighlightedTableCol.tsx b/apps/explorer/src/components/Table/HighlightedTableCol.tsx index 8906d747ef4..339d5efadda 100644 --- a/apps/explorer/src/components/Table/HighlightedTableCol.tsx +++ b/apps/explorer/src/components/Table/HighlightedTableCol.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import clsx from 'clsx'; @@ -8,7 +9,7 @@ export function HighlightedTableCol({ children, first }: { children: ReactNode; return (
diff --git a/apps/explorer/src/components/Table/IotaAmount.tsx b/apps/explorer/src/components/Table/IotaAmount.tsx new file mode 100644 index 00000000000..1c69f668ab5 --- /dev/null +++ b/apps/explorer/src/components/Table/IotaAmount.tsx @@ -0,0 +1,33 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { CoinFormat, useFormatCoin } from '@iota/core'; +import { IOTA_TYPE_ARG } from '@iota/iota.js/utils'; +import { Text } from '@iota/ui'; + +export function IotaAmount({ + amount, + full = false, +}: { + amount?: bigint | number | string | null; + full?: boolean; +}) { + const [formattedAmount, coinType] = useFormatCoin( + amount, + IOTA_TYPE_ARG, + full ? CoinFormat.FULL : CoinFormat.ROUNDED, + ); + if (!amount) return --; + + return ( +
+ + {formattedAmount} + + + {coinType} + +
+ ); +} diff --git a/apps/explorer/src/components/Table/SuiAmount.tsx b/apps/explorer/src/components/Table/SuiAmount.tsx deleted file mode 100644 index 48d52a44e57..00000000000 --- a/apps/explorer/src/components/Table/SuiAmount.tsx +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import { CoinFormat, useFormatCoin } from '@mysten/core'; -import { SUI_TYPE_ARG } from '@mysten/sui.js/utils'; -import { Text } from '@mysten/ui'; - -export function SuiAmount({ - amount, - full = false, -}: { - amount?: bigint | number | string | null; - full?: boolean; -}) { - const [formattedAmount, coinType] = useFormatCoin( - amount, - SUI_TYPE_ARG, - full ? CoinFormat.FULL : CoinFormat.ROUNDED, - ); - if (!amount) return --; - - return ( -
- - {formattedAmount} - - - {coinType} - -
- ); -} diff --git a/apps/explorer/src/components/Table/TableFooter.tsx b/apps/explorer/src/components/Table/TableFooter.tsx index 28e043f95f8..9a818c60356 100644 --- a/apps/explorer/src/components/Table/TableFooter.tsx +++ b/apps/explorer/src/components/Table/TableFooter.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ArrowRight12 } from '@mysten/icons'; -import { Text } from '@mysten/ui'; +import { ArrowRight12 } from '@iota/icons'; +import { Text } from '@iota/ui'; import { Link } from '~/ui/Link'; import { Pagination, type PaginationResponse, type usePaginationStack } from '~/ui/Pagination'; diff --git a/apps/explorer/src/components/TransactionBlocksForAddress/index.tsx b/apps/explorer/src/components/TransactionBlocksForAddress/index.tsx index 10ceaab46fd..734410ac5b2 100644 --- a/apps/explorer/src/components/TransactionBlocksForAddress/index.tsx +++ b/apps/explorer/src/components/TransactionBlocksForAddress/index.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type TransactionFilter } from '@mysten/sui.js/client'; -import { Heading, RadioGroup, RadioGroupItem } from '@mysten/ui'; +import { type TransactionFilter } from '@iota/iota.js/client'; +import { Heading, RadioGroup, RadioGroupItem } from '@iota/ui'; import { type Dispatch, type SetStateAction, useReducer, useState } from 'react'; import { genTableDataFromTxData } from '../transactions/TxCardUtils'; diff --git a/apps/explorer/src/components/TransactionsCardGraph.tsx b/apps/explorer/src/components/TransactionsCardGraph.tsx index d3df37a88a0..2f9f8a630c8 100644 --- a/apps/explorer/src/components/TransactionsCardGraph.tsx +++ b/apps/explorer/src/components/TransactionsCardGraph.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { formatAmount, formatDate } from '@mysten/core'; -import { useSuiClientQuery } from '@mysten/dapp-kit'; -import { Heading, Text, LoadingIndicator } from '@mysten/ui'; +import { formatAmount, formatDate } from '@iota/core'; +import { useIotaClientQuery } from '@iota/dapp-kit'; +import { Heading, Text, LoadingIndicator } from '@iota/ui'; import { ParentSize } from '@visx/responsive'; import clsx from 'clsx'; @@ -39,7 +40,7 @@ function TooltipContent({ } function useEpochTransactions() { - return useSuiClientQuery( + return useIotaClientQuery( 'getEpochMetrics', { descendingOrder: true, @@ -60,7 +61,7 @@ function useEpochTransactions() { } export function TransactionsCardGraph() { - const { data: totalTransactions } = useSuiClientQuery( + const { data: totalTransactions } = useIotaClientQuery( 'getTotalTransactionBlocks', {}, { diff --git a/apps/explorer/src/components/checkpoints/CheckpointsTable.tsx b/apps/explorer/src/components/checkpoints/CheckpointsTable.tsx index d5d83f8f7fb..fb185e33b5a 100644 --- a/apps/explorer/src/components/checkpoints/CheckpointsTable.tsx +++ b/apps/explorer/src/components/checkpoints/CheckpointsTable.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClientQuery } from '@mysten/dapp-kit'; -import { ArrowRight12 } from '@mysten/icons'; -import { Text } from '@mysten/ui'; +import { useIotaClientQuery } from '@iota/dapp-kit'; +import { ArrowRight12 } from '@iota/icons'; +import { Text } from '@iota/ui'; import { useMemo, useState } from 'react'; import { genTableDataFromCheckpointsData } from './utils'; @@ -32,7 +33,7 @@ export function CheckpointsTable({ }: Props) { const [limit, setLimit] = useState(initialLimit); - const countQuery = useSuiClientQuery('getLatestCheckpointSequenceNumber'); + const countQuery = useIotaClientQuery('getLatestCheckpointSequenceNumber'); const checkpoints = useGetCheckpoints(initialCursor, limit); diff --git a/apps/explorer/src/components/checkpoints/utils.tsx b/apps/explorer/src/components/checkpoints/utils.tsx index c29c332007e..e3e73fcc034 100644 --- a/apps/explorer/src/components/checkpoints/utils.tsx +++ b/apps/explorer/src/components/checkpoints/utils.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type CheckpointPage } from '@mysten/sui.js/client'; -import { Text } from '@mysten/ui'; +import { type CheckpointPage } from '@iota/iota.js/client'; +import { Text } from '@iota/ui'; import { TxTimeType } from '../tx-time/TxTimeType'; import { HighlightedTableCol } from '~/components/Table/HighlightedTableCol'; diff --git a/apps/explorer/src/components/error-boundary/ErrorBoundary.tsx b/apps/explorer/src/components/error-boundary/ErrorBoundary.tsx index 1e6993b985a..1baa517da0a 100644 --- a/apps/explorer/src/components/error-boundary/ErrorBoundary.tsx +++ b/apps/explorer/src/components/error-boundary/ErrorBoundary.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { ErrorBoundary as ReactErrorBoundary } from 'react-error-boundary'; diff --git a/apps/explorer/src/components/footer/Footer.tsx b/apps/explorer/src/components/footer/Footer.tsx index fe559d40108..a80e636b0cb 100644 --- a/apps/explorer/src/components/footer/Footer.tsx +++ b/apps/explorer/src/components/footer/Footer.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Text } from '@mysten/ui'; +import { Text } from '@iota/ui'; import { LegalLinks, LegalText } from './Legal'; import { footerLinks, socialLinks } from './footerLinks'; diff --git a/apps/explorer/src/components/footer/Legal.tsx b/apps/explorer/src/components/footer/Legal.tsx index 1879a8b7e5e..5c614cdc6f2 100644 --- a/apps/explorer/src/components/footer/Legal.tsx +++ b/apps/explorer/src/components/footer/Legal.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useProductAnalyticsConfig } from '@mysten/core'; -import { Text } from '@mysten/ui'; +import { useProductAnalyticsConfig } from '@iota/core'; +import { Text } from '@iota/ui'; import { legalLinks } from './footerLinks'; import { Link } from '~/ui/Link'; diff --git a/apps/explorer/src/components/footer/footerLinks.tsx b/apps/explorer/src/components/footer/footerLinks.tsx index f54874f5a1c..95ffc64afce 100644 --- a/apps/explorer/src/components/footer/footerLinks.tsx +++ b/apps/explorer/src/components/footer/footerLinks.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SocialDiscord24, SocialLinkedin24, SocialTwitter24 } from '@mysten/icons'; +import { SocialDiscord24, SocialLinkedin24, SocialTwitter24 } from '@iota/icons'; import { type ReactNode } from 'react'; type FooterItem = { @@ -18,7 +19,7 @@ export const footerLinks = [ { title: 'Blog', href: 'https://mystenlabs.com/blog' }, { title: 'Whitepaper', - href: 'https://github.com/MystenLabs/sui/blob/main/doc/paper/sui.pdf', + href: 'https://github.com/iotaledger/iota/blob/main/doc/paper/iota.pdf', }, { title: 'Docs', diff --git a/apps/explorer/src/components/header/Header.tsx b/apps/explorer/src/components/header/Header.tsx index 2971dc62333..674d28b38a5 100644 --- a/apps/explorer/src/components/header/Header.tsx +++ b/apps/explorer/src/components/header/Header.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Sui, SuiLogoTxt } from '@mysten/icons'; +import { Iota, IotaLogoTxt } from '@iota/icons'; import clsx from 'clsx'; import { useEffect, useState } from 'react'; @@ -34,8 +35,8 @@ function Header() { to="/" className="flex flex-nowrap items-center gap-1 text-hero-darkest" > - - + +
diff --git a/apps/explorer/src/components/module/ModuleCodeTabs.tsx b/apps/explorer/src/components/module/ModuleCodeTabs.tsx index f46717a6d27..b603c4df913 100644 --- a/apps/explorer/src/components/module/ModuleCodeTabs.tsx +++ b/apps/explorer/src/components/module/ModuleCodeTabs.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Tabs, TabsContent, TabsList, TabsTrigger } from '~/ui/Tabs'; -import { Text } from '@mysten/ui'; +import { Text } from '@iota/ui'; import ModuleView from './ModuleView'; import { useVerifiedSourceCode } from '~/hooks/useVerifiedSourceCode'; diff --git a/apps/explorer/src/components/module/ModuleView.tsx b/apps/explorer/src/components/module/ModuleView.tsx index c12bbc58c4e..f7db71a1345 100644 --- a/apps/explorer/src/components/module/ModuleView.tsx +++ b/apps/explorer/src/components/module/ModuleView.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiMoveNormalizedType } from '@mysten/sui.js/client'; -import { normalizeSuiAddress } from '@mysten/sui.js/utils'; +import { type IotaMoveNormalizedType } from '@iota/iota.js/client'; +import { normalizeIotaAddress } from '@iota/iota.js/utils'; import cl from 'clsx'; import Highlight, { defaultProps, Prism } from 'prism-react-renderer'; import 'prism-themes/themes/prism-one-light.css'; @@ -32,11 +33,11 @@ interface TypeReference { address: string; module: string; name: string; - typeArguments: SuiMoveNormalizedType[]; + typeArguments: IotaMoveNormalizedType[]; } /** Takes a normalized move type and returns the address information contained within it */ -function unwrapTypeReference(type: SuiMoveNormalizedType): null | TypeReference { +function unwrapTypeReference(type: IotaMoveNormalizedType): null | TypeReference { if (typeof type === 'object') { if ('Struct' in type) { return type.Struct; @@ -116,8 +117,8 @@ function ModuleView({ id, name, code }: Props) { })} to={href} target={ - normalizeSuiAddress(reference.address) === - normalizeSuiAddress(id!) + normalizeIotaAddress(reference.address) === + normalizeIotaAddress(id!) ? undefined : '_blank' } diff --git a/apps/explorer/src/components/module/PkgModulesWrapper.tsx b/apps/explorer/src/components/module/PkgModulesWrapper.tsx index e81ca4cc6c0..1267e3363e0 100644 --- a/apps/explorer/src/components/module/PkgModulesWrapper.tsx +++ b/apps/explorer/src/components/module/PkgModulesWrapper.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Search24 } from '@mysten/icons'; -import { Combobox, ComboboxInput, ComboboxList } from '@mysten/ui'; +import { Search24 } from '@iota/icons'; +import { Combobox, ComboboxInput, ComboboxList } from '@iota/ui'; import clsx from 'clsx'; import { useState, useCallback, useEffect } from 'react'; import { type Direction } from 'react-resizable-panels'; diff --git a/apps/explorer/src/components/module/module-functions-interaction/FunctionExecutionResult.tsx b/apps/explorer/src/components/module/module-functions-interaction/FunctionExecutionResult.tsx index 94bd648b32d..2d3545fea5e 100644 --- a/apps/explorer/src/components/module/module-functions-interaction/FunctionExecutionResult.tsx +++ b/apps/explorer/src/components/module/module-functions-interaction/FunctionExecutionResult.tsx @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { LinkGroup } from './LinkGroup'; import { Banner } from '~/ui/Banner'; -import type { SuiTransactionBlockResponse, OwnedObjectRef } from '@mysten/sui.js/client'; +import type { IotaTransactionBlockResponse, OwnedObjectRef } from '@iota/iota.js/client'; function toObjectLink(object: OwnedObjectRef) { return { @@ -14,7 +15,7 @@ function toObjectLink(object: OwnedObjectRef) { } type FunctionExecutionResultProps = { - result: SuiTransactionBlockResponse | null; + result: IotaTransactionBlockResponse | null; error: string | false; onClear: () => void; }; diff --git a/apps/explorer/src/components/module/module-functions-interaction/LinkGroup.tsx b/apps/explorer/src/components/module/module-functions-interaction/LinkGroup.tsx index 4ef41eb4f56..cc40d024fab 100644 --- a/apps/explorer/src/components/module/module-functions-interaction/LinkGroup.tsx +++ b/apps/explorer/src/components/module/module-functions-interaction/LinkGroup.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Link } from '~/ui/Link'; diff --git a/apps/explorer/src/components/module/module-functions-interaction/ModuleFunction.tsx b/apps/explorer/src/components/module/module-functions-interaction/ModuleFunction.tsx index 744e9a31860..1fb11f7dd54 100644 --- a/apps/explorer/src/components/module/module-functions-interaction/ModuleFunction.tsx +++ b/apps/explorer/src/components/module/module-functions-interaction/ModuleFunction.tsx @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useZodForm } from '@mysten/core'; -import { ArrowRight12 } from '@mysten/icons'; -import { TransactionBlock, getPureSerializationType } from '@mysten/sui.js/transactions'; -import { Button } from '@mysten/ui'; +import { useZodForm } from '@iota/core'; +import { ArrowRight12 } from '@iota/icons'; +import { TransactionBlock, getPureSerializationType } from '@iota/iota.js/transactions'; +import { Button } from '@iota/ui'; import { ConnectButton, useCurrentAccount, useSignAndExecuteTransactionBlock, -} from '@mysten/dapp-kit'; +} from '@iota/dapp-kit'; import { useMutation } from '@tanstack/react-query'; import clsx from 'clsx'; import { useMemo } from 'react'; @@ -22,7 +23,7 @@ import { useFunctionTypeArguments } from './useFunctionTypeArguments'; import { DisclosureBox } from '~/ui/DisclosureBox'; import { Input } from '~/ui/Input'; -import type { SuiMoveNormalizedFunction } from '@mysten/sui.js/client'; +import type { IotaMoveNormalizedFunction } from '@iota/iota.js/client'; import type { TypeOf } from 'zod'; const argsSchema = z.object({ @@ -34,7 +35,7 @@ export type ModuleFunctionProps = { packageId: string; moduleName: string; functionName: string; - functionDetails: SuiMoveNormalizedFunction; + functionDetails: IotaMoveNormalizedFunction; defaultOpen?: boolean; }; @@ -141,7 +142,7 @@ export function ModuleFunction({ '!rounded-md !text-bodySmall', currentAccount ? '!border !border-solid !border-steel !bg-white !font-mono !text-hero-dark !shadow-sm !shadow-ebony/5' - : '!flex !flex-nowrap !items-center !gap-1 !bg-sui-dark !font-sans !text-sui-light hover:!bg-sui-dark hover:!text-white', + : '!flex !flex-nowrap !items-center !gap-1 !bg-iota-dark !font-sans !text-iota-light hover:!bg-iota-dark hover:!text-white', )} />
diff --git a/apps/explorer/src/components/module/module-functions-interaction/index.tsx b/apps/explorer/src/components/module/module-functions-interaction/index.tsx index 07e4659999e..57fa8959435 100644 --- a/apps/explorer/src/components/module/module-functions-interaction/index.tsx +++ b/apps/explorer/src/components/module/module-functions-interaction/index.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { LoadingIndicator } from '@mysten/ui'; +import { LoadingIndicator } from '@iota/ui'; import { useMemo } from 'react'; import { ModuleFunction } from './ModuleFunction'; diff --git a/apps/explorer/src/components/module/module-functions-interaction/useFunctionParamsDetails.ts b/apps/explorer/src/components/module/module-functions-interaction/useFunctionParamsDetails.ts index 00a53d8312d..10cb34d9205 100644 --- a/apps/explorer/src/components/module/module-functions-interaction/useFunctionParamsDetails.ts +++ b/apps/explorer/src/components/module/module-functions-interaction/useFunctionParamsDetails.ts @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useMemo } from 'react'; import { getNormalizedFunctionParameterTypeDetails } from '../utils'; -import type { SuiMoveNormalizedType } from '@mysten/sui.js/client'; +import type { IotaMoveNormalizedType } from '@iota/iota.js/client'; export function useFunctionParamsDetails( - params: SuiMoveNormalizedType[], + params: IotaMoveNormalizedType[], functionTypeArgNames?: string[], ) { return useMemo( diff --git a/apps/explorer/src/components/module/module-functions-interaction/useFunctionTypeArguments.ts b/apps/explorer/src/components/module/module-functions-interaction/useFunctionTypeArguments.ts index 7e8f5c1b9b0..10266fbc274 100644 --- a/apps/explorer/src/components/module/module-functions-interaction/useFunctionTypeArguments.ts +++ b/apps/explorer/src/components/module/module-functions-interaction/useFunctionTypeArguments.ts @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useMemo } from 'react'; -import type { SuiMoveAbilitySet } from '@mysten/sui.js/client'; +import type { IotaMoveAbilitySet } from '@iota/iota.js/client'; -export function useFunctionTypeArguments(typeArguments: SuiMoveAbilitySet[]) { +export function useFunctionTypeArguments(typeArguments: IotaMoveAbilitySet[]) { return useMemo( () => typeArguments.map( diff --git a/apps/explorer/src/components/module/utils.ts b/apps/explorer/src/components/module/utils.ts index 33e0db11ccd..50de6903bc1 100644 --- a/apps/explorer/src/components/module/utils.ts +++ b/apps/explorer/src/components/module/utils.ts @@ -1,20 +1,21 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import type { SuiMoveNormalizedType } from '@mysten/sui.js/client'; +import type { IotaMoveNormalizedType } from '@iota/iota.js/client'; /** - * Converts a SuiMoveNormalizedType to string + * Converts a IotaMoveNormalizedType to string * @param param A parameter's normalized type of a function * @param functionTypeArgNames Parameters can be generic like 0x2::coin::Coin. - * T is provided on function level with the type_parameters field of SuiMoveNormalizedFunction that defines the abilities. + * T is provided on function level with the type_parameters field of IotaMoveNormalizedFunction that defines the abilities. * This parameter can be an array of strings that define the actual type or names like T1 that can be used to make the type of the parameter more specific. If * functionTypeArgNames or the index that the parameter expects are not defines then a default value T{index} is used. * @param str This function is recursive and this field is used to pass the already resolved type * @returns */ export function normalizedFunctionParameterTypeToString( - param: SuiMoveNormalizedType, + param: IotaMoveNormalizedType, functionTypeArgNames?: string[], str = '', ): string { @@ -53,7 +54,7 @@ export function normalizedFunctionParameterTypeToString( } export function getNormalizedFunctionParameterTypeDetails( - param: SuiMoveNormalizedType, + param: IotaMoveNormalizedType, functionTypeArgNames?: string[], ) { const paramTypeText = normalizedFunctionParameterTypeToString(param, functionTypeArgNames); diff --git a/apps/explorer/src/components/network/Network.tsx b/apps/explorer/src/components/network/Network.tsx index c768d131456..471eefb147d 100644 --- a/apps/explorer/src/components/network/Network.tsx +++ b/apps/explorer/src/components/network/Network.tsx @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClientQuery } from '@mysten/dapp-kit'; +import { useIotaClientQuery } from '@iota/dapp-kit'; import { useContext } from 'react'; import { NetworkContext } from '../../context'; import { NetworkSelect, type NetworkOption } from '~/ui/header/NetworkSelect'; import { ampli } from '~/utils/analytics/ampli'; -import { getAllNetworks } from '@mysten/sui.js/client'; +import { getAllNetworks } from '@iota/iota.js/client'; export default function WrappedNetworkSelect() { const [network, setNetwork] = useContext(NetworkContext); - const { data } = useSuiClientQuery('getLatestSuiSystemState'); - const { data: binaryVersion } = useSuiClientQuery('getRpcApiVersion'); + const { data } = useIotaClientQuery('getLatestIotaSystemState'); + const { data: binaryVersion } = useIotaClientQuery('getRpcApiVersion'); const networks = Object.values(getAllNetworks()).map((network) => ({ id: network.id, diff --git a/apps/explorer/src/components/search/Search.tsx b/apps/explorer/src/components/search/Search.tsx index 25ab32fccea..91e4fc85696 100644 --- a/apps/explorer/src/components/search/Search.tsx +++ b/apps/explorer/src/components/search/Search.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useState, useCallback, useEffect } from 'react'; diff --git a/apps/explorer/src/components/top-packages/TopPackagesCard.tsx b/apps/explorer/src/components/top-packages/TopPackagesCard.tsx index 78e8039f63f..45c325ceed9 100644 --- a/apps/explorer/src/components/top-packages/TopPackagesCard.tsx +++ b/apps/explorer/src/components/top-packages/TopPackagesCard.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useQuery } from '@tanstack/react-query'; diff --git a/apps/explorer/src/components/top-packages/TopPackagesTable.tsx b/apps/explorer/src/components/top-packages/TopPackagesTable.tsx index bb98e4d6589..740dfb5e227 100644 --- a/apps/explorer/src/components/top-packages/TopPackagesTable.tsx +++ b/apps/explorer/src/components/top-packages/TopPackagesTable.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type MoveCallMetric } from '@mysten/sui.js/client'; -import { Text } from '@mysten/ui'; +import { type MoveCallMetric } from '@iota/iota.js/client'; +import { Text } from '@iota/ui'; import { useMemo } from 'react'; import { ObjectLink } from '~/ui/InternalLink'; diff --git a/apps/explorer/src/components/top-validators-card/StakeColumn.tsx b/apps/explorer/src/components/top-validators-card/StakeColumn.tsx index b110f843ad7..bca9edd08f5 100644 --- a/apps/explorer/src/components/top-validators-card/StakeColumn.tsx +++ b/apps/explorer/src/components/top-validators-card/StakeColumn.tsx @@ -1,27 +1,28 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useFormatCoin, CoinFormat, formatBalance } from '@mysten/core'; -import { SUI_TYPE_ARG } from '@mysten/sui.js/utils'; -import { Text } from '@mysten/ui'; +import { useFormatCoin, CoinFormat, formatBalance } from '@iota/core'; +import { IOTA_TYPE_ARG } from '@iota/iota.js/utils'; +import { Text } from '@iota/ui'; type StakeColumnProps = { stake: bigint | number | string; hideCoinSymbol?: boolean; - inMIST?: boolean; + inMICROS?: boolean; }; -export function StakeColumn({ stake, hideCoinSymbol, inMIST = false }: StakeColumnProps) { +export function StakeColumn({ stake, hideCoinSymbol, inMICROS = false }: StakeColumnProps) { const coinFormat = hideCoinSymbol ? CoinFormat.FULL : CoinFormat.ROUNDED; - const [amount, symbol] = useFormatCoin(stake, SUI_TYPE_ARG, coinFormat); + const [amount, symbol] = useFormatCoin(stake, IOTA_TYPE_ARG, coinFormat); return (
- {inMIST ? formatBalance(stake, 0, coinFormat) : amount} + {inMICROS ? formatBalance(stake, 0, coinFormat) : amount} {!hideCoinSymbol && ( - {inMIST ? 'MIST' : symbol} + {inMICROS ? 'MICROS' : symbol} )}
diff --git a/apps/explorer/src/components/top-validators-card/TopValidatorsCard.tsx b/apps/explorer/src/components/top-validators-card/TopValidatorsCard.tsx index a11a6b15753..0cbfd5c6899 100644 --- a/apps/explorer/src/components/top-validators-card/TopValidatorsCard.tsx +++ b/apps/explorer/src/components/top-validators-card/TopValidatorsCard.tsx @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClientQuery } from '@mysten/dapp-kit'; -import { ArrowRight12 } from '@mysten/icons'; -import { type SuiValidatorSummary } from '@mysten/sui.js/client'; -import { Text } from '@mysten/ui'; +import { useIotaClientQuery } from '@iota/dapp-kit'; +import { ArrowRight12 } from '@iota/icons'; +import { type IotaValidatorSummary } from '@iota/iota.js/client'; +import { Text } from '@iota/ui'; import { useMemo } from 'react'; import { StakeColumn } from './StakeColumn'; @@ -19,17 +20,17 @@ import { ampli } from '~/utils/analytics/ampli'; const NUMBER_OF_VALIDATORS = 10; -export function processValidators(set: SuiValidatorSummary[]) { +export function processValidators(set: IotaValidatorSummary[]) { return set.map((av) => ({ name: av.name, - address: av.suiAddress, - stake: av.stakingPoolSuiBalance, + address: av.iotaAddress, + stake: av.stakingPoolIotaBalance, logo: av.imageUrl, })); } const validatorsTable = ( - validatorsData: SuiValidatorSummary[], + validatorsData: IotaValidatorSummary[], limit?: number, showIcon?: boolean, ) => { @@ -107,7 +108,7 @@ type TopValidatorsCardProps = { }; export function TopValidatorsCard({ limit, showIcon }: TopValidatorsCardProps) { - const { data, isPending, isSuccess, isError } = useSuiClientQuery('getLatestSuiSystemState'); + const { data, isPending, isSuccess, isError } = useIotaClientQuery('getLatestIotaSystemState'); const tableData = useMemo( () => (data ? validatorsTable(data.activeValidators, limit, showIcon) : null), diff --git a/apps/explorer/src/components/transactions/ProgTxnBlockCard.tsx b/apps/explorer/src/components/transactions/ProgTxnBlockCard.tsx index ed37eb7e314..b3dc5f1a7ea 100644 --- a/apps/explorer/src/components/transactions/ProgTxnBlockCard.tsx +++ b/apps/explorer/src/components/transactions/ProgTxnBlockCard.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import clsx from 'clsx'; diff --git a/apps/explorer/src/components/transactions/TransactionsForAddress.tsx b/apps/explorer/src/components/transactions/TransactionsForAddress.tsx index 02cbf37082c..4c1803af307 100644 --- a/apps/explorer/src/components/transactions/TransactionsForAddress.tsx +++ b/apps/explorer/src/components/transactions/TransactionsForAddress.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { type SuiTransactionBlockResponse } from '@mysten/sui.js/client'; -import { LoadingIndicator, Text } from '@mysten/ui'; +import { useIotaClient } from '@iota/dapp-kit'; +import { type IotaTransactionBlockResponse } from '@iota/iota.js/client'; +import { LoadingIndicator, Text } from '@iota/ui'; import { useQuery } from '@tanstack/react-query'; import { genTableDataFromTxData } from './TxCardUtils'; @@ -21,7 +22,7 @@ export function TransactionsForAddressTable({ isError, address, }: { - data: SuiTransactionBlockResponse[]; + data: IotaTransactionBlockResponse[]; isPending: boolean; isError: boolean; address: string; @@ -59,7 +60,7 @@ export function TransactionsForAddressTable({ } export function TransactionsForAddress({ address, type }: Props) { - const client = useSuiClient(); + const client = useIotaClient(); const { data, isPending, isError } = useQuery({ queryKey: ['transactions-for-address', address, type], @@ -84,7 +85,7 @@ export function TransactionsForAddress({ address, type }: Props) { ); const inserted = new Map(); - const uniqueList: SuiTransactionBlockResponse[] = []; + const uniqueList: IotaTransactionBlockResponse[] = []; [...results[0].data, ...results[1].data] .sort((a, b) => Number(b.timestampMs ?? 0) - Number(a.timestampMs ?? 0)) diff --git a/apps/explorer/src/components/transactions/TxCardUtils.tsx b/apps/explorer/src/components/transactions/TxCardUtils.tsx index f7fc267d7d2..ac6582453ef 100644 --- a/apps/explorer/src/components/transactions/TxCardUtils.tsx +++ b/apps/explorer/src/components/transactions/TxCardUtils.tsx @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { getTotalGasUsed } from '@mysten/core'; -import { X12, Dot12 } from '@mysten/icons'; -import { type SuiClient, type SuiTransactionBlockResponse } from '@mysten/sui.js/client'; +import { getTotalGasUsed } from '@iota/core'; +import { X12, Dot12 } from '@iota/icons'; +import { type IotaClient, type IotaTransactionBlockResponse } from '@iota/iota.js/client'; -import { SuiAmount } from '../Table/SuiAmount'; +import { IotaAmount } from '../Table/IotaAmount'; import { TxTimeType } from '../tx-time/TxTimeType'; import { HighlightedTableCol } from '~/components/Table/HighlightedTableCol'; import { AddressLink, TransactionLink } from '~/ui/InternalLink'; // Generate table data from the transaction data -export const genTableDataFromTxData = (results: SuiTransactionBlockResponse[]) => ({ +export const genTableDataFromTxData = (results: IotaTransactionBlockResponse[]) => ({ data: results.map((transaction) => { const status = transaction.effects?.status.status; const sender = transaction.transaction?.data.sender; @@ -44,7 +45,7 @@ export const genTableDataFromTxData = (results: SuiTransactionBlockResponse[]) =
), gas: ( - + ), sender: ( @@ -79,7 +80,7 @@ export const genTableDataFromTxData = (results: SuiTransactionBlockResponse[]) = const dedupe = (arr: string[]) => Array.from(new Set(arr)); -export const getDataOnTxDigests = (client: SuiClient, transactions: string[]) => +export const getDataOnTxDigests = (client: IotaClient, transactions: string[]) => client .multiGetTransactionBlocks({ digests: dedupe(transactions), diff --git a/apps/explorer/src/components/tx-time/TxTimeType.tsx b/apps/explorer/src/components/tx-time/TxTimeType.tsx index faad647c0fb..f035c0101dd 100644 --- a/apps/explorer/src/components/tx-time/TxTimeType.tsx +++ b/apps/explorer/src/components/tx-time/TxTimeType.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useTimeAgo } from '@mysten/core'; +import { useTimeAgo } from '@iota/core'; type Prop = { timestamp: number | undefined; diff --git a/apps/explorer/src/components/validator-map/MapFeature.tsx b/apps/explorer/src/components/validator-map/MapFeature.tsx index f1d5f616fb9..664ad56f5b0 100644 --- a/apps/explorer/src/components/validator-map/MapFeature.tsx +++ b/apps/explorer/src/components/validator-map/MapFeature.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 interface Props { diff --git a/apps/explorer/src/components/validator-map/ValidatorLocation.tsx b/apps/explorer/src/components/validator-map/ValidatorLocation.tsx index 7e644b25996..5a3b69846a2 100644 --- a/apps/explorer/src/components/validator-map/ValidatorLocation.tsx +++ b/apps/explorer/src/components/validator-map/ValidatorLocation.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useCallback } from 'react'; @@ -21,7 +22,7 @@ const MAX_VALIDATOR_OPACITY = 0.5; export function ValidatorLocation({ validator, projection, onMouseOut, onMouseOver }: Props) { const handleMouseOver = useCallback( (e: React.MouseEvent) => { - validator && onMouseOver(e, validator.suiAddress); + validator && onMouseOver(e, validator.iotaAddress); }, [validator, onMouseOver], ); diff --git a/apps/explorer/src/components/validator-map/WorldMap.tsx b/apps/explorer/src/components/validator-map/WorldMap.tsx index 7e8b70aa020..45dd969f791 100644 --- a/apps/explorer/src/components/validator-map/WorldMap.tsx +++ b/apps/explorer/src/components/validator-map/WorldMap.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Mercator } from '@visx/geo'; diff --git a/apps/explorer/src/components/validator-map/index.tsx b/apps/explorer/src/components/validator-map/index.tsx index f4862e5d9e3..5e4790c559d 100644 --- a/apps/explorer/src/components/validator-map/index.tsx +++ b/apps/explorer/src/components/validator-map/index.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useAppsBackend } from '@mysten/core'; -import { useSuiClientQuery } from '@mysten/dapp-kit'; -import { Heading, Text, Placeholder } from '@mysten/ui'; +import { useAppsBackend } from '@iota/core'; +import { useIotaClientQuery } from '@iota/dapp-kit'; +import { Heading, Text, Placeholder } from '@iota/ui'; import { useQuery } from '@tanstack/react-query'; import { ParentSize } from '@visx/responsive'; import { TooltipWithBounds, useTooltip } from '@visx/tooltip'; @@ -40,7 +41,7 @@ interface Props { export default function ValidatorMap({ minHeight }: Props) { const [network] = useNetwork(); const { data: systemState, isError: systemStateError } = - useSuiClientQuery('getLatestSuiSystemState'); + useIotaClientQuery('getLatestIotaSystemState'); const { request } = useAppsBackend(); @@ -67,7 +68,7 @@ export default function ValidatorMap({ minHeight }: Props) { const countryMap: Record = {}; validatorData.forEach((validator) => { if (validator) { - validatorMap[validator.suiAddress] ??= { + validatorMap[validator.iotaAddress] ??= { ...validator, }; diff --git a/apps/explorer/src/components/validator-map/types.ts b/apps/explorer/src/components/validator-map/types.ts index 54747356c2b..ea7dd04ed1c 100644 --- a/apps/explorer/src/components/validator-map/types.ts +++ b/apps/explorer/src/components/validator-map/types.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export interface Feature { @@ -42,7 +43,7 @@ interface ValidatorIpInfo { export interface ValidatorMapValidator { ipInfo?: ValidatorIpInfo; - suiAddress: string; + iotaAddress: string; name: string; votingPower: string; } diff --git a/apps/explorer/src/components/validator/DelegationAmount.tsx b/apps/explorer/src/components/validator/DelegationAmount.tsx index 0d26d75f472..ea354e3ba3b 100644 --- a/apps/explorer/src/components/validator/DelegationAmount.tsx +++ b/apps/explorer/src/components/validator/DelegationAmount.tsx @@ -1,20 +1,21 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useFormatCoin, formatBalance, CoinFormat } from '@mysten/core'; -import { SUI_TYPE_ARG } from '@mysten/sui.js/utils'; -import { Heading, Text } from '@mysten/ui'; +import { useFormatCoin, formatBalance, CoinFormat } from '@iota/core'; +import { IOTA_TYPE_ARG } from '@iota/iota.js/utils'; +import { Heading, Text } from '@iota/ui'; type DelegationAmountProps = { amount: bigint | number | string; isStats?: boolean; - inMIST?: boolean; + inMICROS?: boolean; }; -export function DelegationAmount({ amount, isStats, inMIST = false }: DelegationAmountProps) { - const [formattedAmount, symbol] = useFormatCoin(amount, SUI_TYPE_ARG); - const delegationAmount = inMIST ? formatBalance(amount, 0, CoinFormat.FULL) : formattedAmount; - const delegationSymbol = inMIST ? 'MIST' : symbol; +export function DelegationAmount({ amount, isStats, inMICROS = false }: DelegationAmountProps) { + const [formattedAmount, symbol] = useFormatCoin(amount, IOTA_TYPE_ARG); + const delegationAmount = inMICROS ? formatBalance(amount, 0, CoinFormat.FULL) : formattedAmount; + const delegationSymbol = inMICROS ? 'MICROS' : symbol; return isStats ? (
diff --git a/apps/explorer/src/components/validator/ValidatorMeta.tsx b/apps/explorer/src/components/validator/ValidatorMeta.tsx index ba1eebad3cb..9b41295d33a 100644 --- a/apps/explorer/src/components/validator/ValidatorMeta.tsx +++ b/apps/explorer/src/components/validator/ValidatorMeta.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ArrowUpRight12 } from '@mysten/icons'; -import { type SuiValidatorSummary } from '@mysten/sui.js/client'; -import { Heading, Text } from '@mysten/ui'; +import { ArrowUpRight12 } from '@iota/icons'; +import { type IotaValidatorSummary } from '@iota/iota.js/client'; +import { Heading, Text } from '@iota/ui'; import { CopyToClipboard } from '~/ui/CopyToClipboard'; import { DescriptionList, DescriptionItem } from '~/ui/DescriptionList'; @@ -11,7 +12,7 @@ import { ImageIcon } from '~/ui/ImageIcon'; import { AddressLink } from '~/ui/InternalLink'; type ValidatorMetaProps = { - validatorData: SuiValidatorSummary; + validatorData: IotaValidatorSummary; }; export function ValidatorMeta({ validatorData }: ValidatorMetaProps) { @@ -34,7 +35,7 @@ export function ValidatorMeta({ validatorData }: ValidatorMetaProps) { href={projectUrl} target="_blank" rel="noreferrer noopener" - className="mt-2.5 inline-flex items-center gap-1.5 text-body font-medium text-sui-dark no-underline" + className="mt-2.5 inline-flex items-center gap-1.5 text-body font-medium text-iota-dark no-underline" > {projectUrl.replace(/\/$/, '')} @@ -68,11 +69,11 @@ export function ValidatorMeta({ validatorData }: ValidatorMetaProps) {
- +
diff --git a/apps/explorer/src/components/validator/ValidatorStats.tsx b/apps/explorer/src/components/validator/ValidatorStats.tsx index 60b99a507cd..2d45d847f42 100644 --- a/apps/explorer/src/components/validator/ValidatorStats.tsx +++ b/apps/explorer/src/components/validator/ValidatorStats.tsx @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiValidatorSummary } from '@mysten/sui.js/client'; -import { Heading } from '@mysten/ui'; +import { type IotaValidatorSummary } from '@iota/iota.js/client'; +import { Heading } from '@iota/ui'; import { DelegationAmount } from './DelegationAmount'; import { Card } from '~/ui/Card'; import { Stats } from '~/ui/Stats'; type StatsCardProps = { - validatorData: SuiValidatorSummary; + validatorData: IotaValidatorSummary; epoch: number | string; epochRewards: number | null; apy: number | string | null; @@ -28,7 +29,7 @@ export function ValidatorStats({ // const votedLastRound = 0; // const lastNarwhalRound = 0; - const totalStake = Number(validatorData.stakingPoolSuiBalance); + const totalStake = Number(validatorData.stakingPoolIotaBalance); const commission = Number(validatorData.commissionRate) / 100; const rewardsPoolBalance = Number(validatorData.rewardsPool); @@ -38,7 +39,7 @@ export function ValidatorStats({
- SUI Staked on Validator + IOTA Staked on Validator
@@ -128,7 +129,7 @@ export function ValidatorStats({
{tallyingScore} @@ -145,7 +146,7 @@ export function ValidatorStats({
diff --git a/apps/explorer/src/context.ts b/apps/explorer/src/context.ts index b9483fb4fd0..f0c98f97b64 100644 --- a/apps/explorer/src/context.ts +++ b/apps/explorer/src/context.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import * as Sentry from '@sentry/react'; @@ -9,7 +10,7 @@ import { useSearchParams } from 'react-router-dom'; import { Network } from './utils/api/DefaultRpcClient'; import { growthbook } from './utils/growthbook'; import { queryClient } from './utils/queryClient'; -import { getDefaultNetwork } from '@mysten/sui.js/client'; +import { getDefaultNetwork } from '@iota/iota.js/client'; export const NetworkContext = createContext< [Network | string, (network: Network | string) => void] diff --git a/apps/explorer/src/css-variables.d.ts b/apps/explorer/src/css-variables.d.ts index b3e431d8be6..e2fa5ed14f2 100644 --- a/apps/explorer/src/css-variables.d.ts +++ b/apps/explorer/src/css-variables.d.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // eslint-disable-next-line react/no-typos diff --git a/apps/explorer/src/hooks/useBreakpoint.ts b/apps/explorer/src/hooks/useBreakpoint.ts index 50c2c7a8b98..3dc63fd565a 100644 --- a/apps/explorer/src/hooks/useBreakpoint.ts +++ b/apps/explorer/src/hooks/useBreakpoint.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useMediaQuery } from '~/hooks/useMediaQuery'; diff --git a/apps/explorer/src/hooks/useDebouncedValue.ts b/apps/explorer/src/hooks/useDebouncedValue.ts index 153110daad1..ab12fc896b5 100644 --- a/apps/explorer/src/hooks/useDebouncedValue.ts +++ b/apps/explorer/src/hooks/useDebouncedValue.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useEffect, useState } from 'react'; diff --git a/apps/explorer/src/hooks/useEnhancedRpc.ts b/apps/explorer/src/hooks/useEnhancedRpc.ts index 4aed75d2c5c..4439a8ef160 100644 --- a/apps/explorer/src/hooks/useEnhancedRpc.ts +++ b/apps/explorer/src/hooks/useEnhancedRpc.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { SuiClient } from '@mysten/sui.js/client'; +import { useIotaClient } from '@iota/dapp-kit'; +import { IotaClient } from '@iota/iota.js/client'; import { useMemo } from 'react'; import { useNetwork } from '~/context'; @@ -10,10 +11,10 @@ import { Network } from '~/utils/api/DefaultRpcClient'; // TODO: Use enhanced RPC locally by default export function useEnhancedRpcClient() { const [network] = useNetwork(); - const client = useSuiClient(); + const client = useIotaClient(); const enhancedRpc = useMemo(() => { if (network === Network.Local) { - return new SuiClient({ url: 'http://localhost:9124' }); + return new IotaClient({ url: 'http://localhost:9124' }); } return client; diff --git a/apps/explorer/src/hooks/useGetAddressMetrics.ts b/apps/explorer/src/hooks/useGetAddressMetrics.ts index fb7f79c352b..51b9c48e425 100644 --- a/apps/explorer/src/hooks/useGetAddressMetrics.ts +++ b/apps/explorer/src/hooks/useGetAddressMetrics.ts @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; +import { useIotaClient } from '@iota/dapp-kit'; import { useQuery } from '@tanstack/react-query'; export function useGetAddressMetrics() { - const client = useSuiClient(); + const client = useIotaClient(); return useQuery({ queryKey: ['home', 'addresses'], queryFn: () => client.getAddressMetrics(), diff --git a/apps/explorer/src/hooks/useGetAllEpochAddressMetrics.ts b/apps/explorer/src/hooks/useGetAllEpochAddressMetrics.ts index bbf635cb30b..2bbd409b09a 100644 --- a/apps/explorer/src/hooks/useGetAllEpochAddressMetrics.ts +++ b/apps/explorer/src/hooks/useGetAllEpochAddressMetrics.ts @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { type SuiClient } from '@mysten/sui.js/client'; +import { useIotaClient } from '@iota/dapp-kit'; +import { type IotaClient } from '@iota/iota.js/client'; import { useQuery } from '@tanstack/react-query'; export function useGetAllEpochAddressMetrics( - ...input: Parameters + ...input: Parameters ) { - const client = useSuiClient(); + const client = useIotaClient(); return useQuery({ queryKey: ['get', 'all', 'epoch', 'addresses', ...input], queryFn: () => client.getAllEpochAddressMetrics(...input), diff --git a/apps/explorer/src/hooks/useGetCheckpoints.ts b/apps/explorer/src/hooks/useGetCheckpoints.ts index e37115ccfd4..9cc188063df 100644 --- a/apps/explorer/src/hooks/useGetCheckpoints.ts +++ b/apps/explorer/src/hooks/useGetCheckpoints.ts @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { type CheckpointPage } from '@mysten/sui.js/client'; +import { useIotaClient } from '@iota/dapp-kit'; +import { type CheckpointPage } from '@iota/iota.js/client'; import { keepPreviousData, useInfiniteQuery } from '@tanstack/react-query'; export const DEFAULT_CHECKPOINTS_LIMIT = 20; // Fetch transaction blocks export function useGetCheckpoints(cursor?: string, limit = DEFAULT_CHECKPOINTS_LIMIT) { - const client = useSuiClient(); + const client = useIotaClient(); return useInfiniteQuery({ queryKey: ['get-checkpoints', limit, cursor], diff --git a/apps/explorer/src/hooks/useGetNetworkMetrics.ts b/apps/explorer/src/hooks/useGetNetworkMetrics.ts index 60706cea250..21bd7554eee 100644 --- a/apps/explorer/src/hooks/useGetNetworkMetrics.ts +++ b/apps/explorer/src/hooks/useGetNetworkMetrics.ts @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; +import { useIotaClient } from '@iota/dapp-kit'; import { useQuery } from '@tanstack/react-query'; export function useGetNetworkMetrics() { - const client = useSuiClient(); + const client = useIotaClient(); return useQuery({ queryKey: ['home', 'metrics'], queryFn: () => client.getNetworkMetrics(), diff --git a/apps/explorer/src/hooks/useGetTransaction.ts b/apps/explorer/src/hooks/useGetTransaction.ts index 34ef44834ef..2267b4bd6a5 100644 --- a/apps/explorer/src/hooks/useGetTransaction.ts +++ b/apps/explorer/src/hooks/useGetTransaction.ts @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; +import { useIotaClient } from '@iota/dapp-kit'; import { useQuery } from '@tanstack/react-query'; export function useGetTransaction(transactionId: string) { - const client = useSuiClient(); + const client = useIotaClient(); return useQuery({ queryKey: ['transactions-by-id', transactionId], queryFn: async () => diff --git a/apps/explorer/src/hooks/useGetTransactionBlocks.ts b/apps/explorer/src/hooks/useGetTransactionBlocks.ts index 09a27165783..0917c545994 100644 --- a/apps/explorer/src/hooks/useGetTransactionBlocks.ts +++ b/apps/explorer/src/hooks/useGetTransactionBlocks.ts @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; +import { useIotaClient } from '@iota/dapp-kit'; import { keepPreviousData, useInfiniteQuery } from '@tanstack/react-query'; -import { type PaginatedTransactionResponse, type TransactionFilter } from '@mysten/sui.js/client'; +import { type PaginatedTransactionResponse, type TransactionFilter } from '@iota/iota.js/client'; export const DEFAULT_TRANSACTIONS_LIMIT = 20; @@ -14,7 +15,7 @@ export function useGetTransactionBlocks( limit = DEFAULT_TRANSACTIONS_LIMIT, refetchInterval?: number, ) { - const client = useSuiClient(); + const client = useIotaClient(); return useInfiniteQuery({ queryKey: ['get-transaction-blocks', filter, limit], diff --git a/apps/explorer/src/hooks/useImage.ts b/apps/explorer/src/hooks/useImage.ts index cff9ea59a6e..f750e4ac715 100644 --- a/apps/explorer/src/hooks/useImage.ts +++ b/apps/explorer/src/hooks/useImage.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useCallback, useLayoutEffect, useRef, useState } from 'react'; diff --git a/apps/explorer/src/hooks/useImageMod.ts b/apps/explorer/src/hooks/useImageMod.ts index 85b5e59d3e5..b43fc138457 100644 --- a/apps/explorer/src/hooks/useImageMod.ts +++ b/apps/explorer/src/hooks/useImageMod.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useAppsBackend } from '@mysten/core'; +import { useAppsBackend } from '@iota/core'; import { useQuery } from '@tanstack/react-query'; // https://cloud.google.com/vision/docs/supported-files diff --git a/apps/explorer/src/hooks/useInitialPageView.ts b/apps/explorer/src/hooks/useInitialPageView.ts index 96b9ffecddd..b9ac36461ff 100644 --- a/apps/explorer/src/hooks/useInitialPageView.ts +++ b/apps/explorer/src/hooks/useInitialPageView.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useEffect } from 'react'; @@ -21,6 +22,6 @@ export function useInitialPageView(activeNetwork: string) { // Log an initial page view event useEffect(() => { - ampli.openedSuiExplorer(); + ampli.openedIotaExplorer(); }, []); } diff --git a/apps/explorer/src/hooks/useMediaQuery.ts b/apps/explorer/src/hooks/useMediaQuery.ts index 9ac4a91d3df..ac3d39e4ab5 100644 --- a/apps/explorer/src/hooks/useMediaQuery.ts +++ b/apps/explorer/src/hooks/useMediaQuery.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useCallback, useLayoutEffect, useState } from 'react'; diff --git a/apps/explorer/src/hooks/useNormalizedMoveModule.ts b/apps/explorer/src/hooks/useNormalizedMoveModule.ts index ea1d0eaffb3..54c7c70b46c 100644 --- a/apps/explorer/src/hooks/useNormalizedMoveModule.ts +++ b/apps/explorer/src/hooks/useNormalizedMoveModule.ts @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; +import { useIotaClient } from '@iota/dapp-kit'; import { useQuery } from '@tanstack/react-query'; export function useNormalizedMoveModule(packageId?: string | null, moduleName?: string | null) { - const client = useSuiClient(); + const client = useIotaClient(); return useQuery({ queryKey: ['normalized-module', packageId, moduleName], queryFn: async () => diff --git a/apps/explorer/src/hooks/useRecognizedPackages.ts b/apps/explorer/src/hooks/useRecognizedPackages.ts index a26635b898f..410e33fdd2c 100644 --- a/apps/explorer/src/hooks/useRecognizedPackages.ts +++ b/apps/explorer/src/hooks/useRecognizedPackages.ts @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useFeatureValue } from '@growthbook/growthbook-react'; -import { SUI_FRAMEWORK_ADDRESS, SUI_SYSTEM_ADDRESS } from '@mysten/sui.js/utils'; +import { IOTA_FRAMEWORK_ADDRESS, IOTA_SYSTEM_ADDRESS } from '@iota/iota.js/utils'; import { useNetwork } from '~/context'; import { Network } from '~/utils/api/DefaultRpcClient'; -const DEFAULT_RECOGNIZED_PACKAGES = [SUI_FRAMEWORK_ADDRESS, SUI_SYSTEM_ADDRESS]; +const DEFAULT_RECOGNIZED_PACKAGES = [IOTA_FRAMEWORK_ADDRESS, IOTA_SYSTEM_ADDRESS]; export function useRecognizedPackages() { const [network] = useNetwork(); diff --git a/apps/explorer/src/hooks/useResolveVideo.ts b/apps/explorer/src/hooks/useResolveVideo.ts index 1f9a1c39a6e..b12094cc5dd 100644 --- a/apps/explorer/src/hooks/useResolveVideo.ts +++ b/apps/explorer/src/hooks/useResolveVideo.ts @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiObjectResponse } from '@mysten/sui.js/client'; +import { type IotaObjectResponse } from '@iota/iota.js/client'; import { useRecognizedPackages } from './useRecognizedPackages'; -export function useResolveVideo(object: SuiObjectResponse) { +export function useResolveVideo(object: IotaObjectResponse) { const recognizedPackages = useRecognizedPackages(); const objectType = object.data?.type ?? object?.data?.content?.dataType === 'package' diff --git a/apps/explorer/src/hooks/useSearch.ts b/apps/explorer/src/hooks/useSearch.ts index e46923ab294..d5334e62332 100644 --- a/apps/explorer/src/hooks/useSearch.ts +++ b/apps/explorer/src/hooks/useSearch.ts @@ -1,22 +1,23 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { isSuiNSName, useSuiNSEnabled } from '@mysten/core'; -import { useSuiClientQuery, useSuiClient } from '@mysten/dapp-kit'; -import { type SuiClient, type SuiSystemStateSummary } from '@mysten/sui.js/client'; +import { isIotaNSName, useIotaNSEnabled } from '@iota/core'; +import { useIotaClientQuery, useIotaClient } from '@iota/dapp-kit'; +import { type IotaClient, type IotaSystemStateSummary } from '@iota/iota.js/client'; import { isValidTransactionDigest, - isValidSuiAddress, - isValidSuiObjectId, - normalizeSuiObjectId, -} from '@mysten/sui.js/utils'; + isValidIotaAddress, + isValidIotaObjectId, + normalizeIotaObjectId, +} from '@iota/iota.js/utils'; import { useQuery } from '@tanstack/react-query'; const isGenesisLibAddress = (value: string): boolean => /^(0x|0X)0{0,39}[12]$/.test(value); type Results = { id: string; label: string; type: string }[]; -const getResultsForTransaction = async (client: SuiClient, query: string) => { +const getResultsForTransaction = async (client: IotaClient, query: string) => { if (!isValidTransactionDigest(query)) return null; const txdata = await client.getTransactionBlock({ digest: query }); return [ @@ -28,9 +29,9 @@ const getResultsForTransaction = async (client: SuiClient, query: string) => { ]; }; -const getResultsForObject = async (client: SuiClient, query: string) => { - const normalized = normalizeSuiObjectId(query); - if (!isValidSuiObjectId(normalized)) return null; +const getResultsForObject = async (client: IotaClient, query: string) => { + const normalized = normalizeIotaObjectId(query); + if (!isValidIotaObjectId(normalized)) return null; const { data, error } = await client.getObject({ id: normalized }); if (!data || error) return null; @@ -44,7 +45,7 @@ const getResultsForObject = async (client: SuiClient, query: string) => { ]; }; -const getResultsForCheckpoint = async (client: SuiClient, query: string) => { +const getResultsForCheckpoint = async (client: IotaClient, query: string) => { // Checkpoint digests have the same format as transaction digests: if (!isValidTransactionDigest(query)) return null; @@ -60,8 +61,8 @@ const getResultsForCheckpoint = async (client: SuiClient, query: string) => { ]; }; -const getResultsForAddress = async (client: SuiClient, query: string, suiNSEnabled: boolean) => { - if (suiNSEnabled && isSuiNSName(query)) { +const getResultsForAddress = async (client: IotaClient, query: string, iotaNSEnabled: boolean) => { + if (iotaNSEnabled && isIotaNSName(query)) { const resolved = await client.resolveNameServiceAddress({ name: query.toLowerCase() }); if (!resolved) return null; return [ @@ -73,8 +74,8 @@ const getResultsForAddress = async (client: SuiClient, query: string, suiNSEnabl ]; } - const normalized = normalizeSuiObjectId(query); - if (!isValidSuiAddress(normalized) || isGenesisLibAddress(normalized)) return null; + const normalized = normalizeIotaObjectId(query); + if (!isValidIotaAddress(normalized) || isGenesisLibAddress(normalized)) return null; const [from, to] = await Promise.all([ client.queryTransactionBlocks({ @@ -98,25 +99,25 @@ const getResultsForAddress = async (client: SuiClient, query: string, suiNSEnabl ]; }; -// Query for validator by pool id or sui address. -const getResultsForValidatorByPoolIdOrSuiAddress = async ( - systemStateSummery: SuiSystemStateSummary | null, +// Query for validator by pool id or iota address. +const getResultsForValidatorByPoolIdOrIotaAddress = async ( + systemStateSummery: IotaSystemStateSummary | null, query: string, ) => { - const normalized = normalizeSuiObjectId(query); - if ((!isValidSuiAddress(normalized) && !isValidSuiObjectId(normalized)) || !systemStateSummery) + const normalized = normalizeIotaObjectId(query); + if ((!isValidIotaAddress(normalized) && !isValidIotaObjectId(normalized)) || !systemStateSummery) return null; - // find validator by pool id or sui address + // find validator by pool id or iota address const validator = systemStateSummery.activeValidators?.find( - ({ stakingPoolId, suiAddress }) => stakingPoolId === normalized || suiAddress === query, + ({ stakingPoolId, iotaAddress }) => stakingPoolId === normalized || iotaAddress === query, ); if (!validator) return null; return [ { - id: validator.suiAddress || validator.stakingPoolId, + id: validator.iotaAddress || validator.stakingPoolId, label: normalized, type: 'validator', }, @@ -124,9 +125,9 @@ const getResultsForValidatorByPoolIdOrSuiAddress = async ( }; export function useSearch(query: string) { - const client = useSuiClient(); - const { data: systemStateSummery } = useSuiClientQuery('getLatestSuiSystemState'); - const suiNSEnabled = useSuiNSEnabled(); + const client = useIotaClient(); + const { data: systemStateSummery } = useIotaClientQuery('getLatestIotaSystemState'); + const iotaNSEnabled = useIotaNSEnabled(); return useQuery({ // eslint-disable-next-line @tanstack/query/exhaustive-deps @@ -136,9 +137,9 @@ export function useSearch(query: string) { await Promise.allSettled([ getResultsForTransaction(client, query), getResultsForCheckpoint(client, query), - getResultsForAddress(client, query, suiNSEnabled), + getResultsForAddress(client, query, iotaNSEnabled), getResultsForObject(client, query), - getResultsForValidatorByPoolIdOrSuiAddress(systemStateSummery || null, query), + getResultsForValidatorByPoolIdOrIotaAddress(systemStateSummery || null, query), ]) ).filter( (r) => r.status === 'fulfilled' && r.value, diff --git a/apps/explorer/src/hooks/useVerifiedSourceCode.ts b/apps/explorer/src/hooks/useVerifiedSourceCode.ts index e4fde9a1ffa..141a5d6ce7e 100644 --- a/apps/explorer/src/hooks/useVerifiedSourceCode.ts +++ b/apps/explorer/src/hooks/useVerifiedSourceCode.ts @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useFeatureIsOn } from '@growthbook/growthbook-react'; -import { useSuiClientContext } from '@mysten/dapp-kit'; +import { useIotaClientContext } from '@iota/dapp-kit'; import { useQuery } from '@tanstack/react-query'; import { Network } from '~/utils/api/DefaultRpcClient'; @@ -26,7 +27,7 @@ const networksWithSourceCodeVerification: Network[] = [ * Hook that retrieves the source code for verified modules. */ export function useVerifiedSourceCode({ packageId, moduleName }: UseVerifiedSourceCodeArgs) { - const { network } = useSuiClientContext(); + const { network } = useIotaClientContext(); const isEnabled = useFeatureIsOn('module-source-verification'); return useQuery({ diff --git a/apps/explorer/src/index.tsx b/apps/explorer/src/index.tsx index ec7d65ca0a7..c18abd97c01 100644 --- a/apps/explorer/src/index.tsx +++ b/apps/explorer/src/index.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import '@fontsource-variable/inter'; @@ -15,7 +16,7 @@ import { growthbook } from './utils/growthbook'; import { queryClient } from './utils/queryClient'; import './utils/sentry'; -import '@mysten/dapp-kit/dist/index.css'; +import '@iota/dapp-kit/dist/index.css'; import './index.css'; // Load Amplitude as early as we can: diff --git a/apps/explorer/src/pages/address-result/AddressResult.tsx b/apps/explorer/src/pages/address-result/AddressResult.tsx index e7d7405a2b9..0f8b88743e1 100644 --- a/apps/explorer/src/pages/address-result/AddressResult.tsx +++ b/apps/explorer/src/pages/address-result/AddressResult.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { isSuiNSName, useResolveSuiNSAddress, useResolveSuiNSName } from '@mysten/core'; -import { Domain32 } from '@mysten/icons'; -import { LoadingIndicator } from '@mysten/ui'; +import { isIotaNSName, useResolveIotaNSAddress, useResolveIotaNSName } from '@iota/core'; +import { Domain32 } from '@iota/icons'; +import { LoadingIndicator } from '@iota/ui'; import { useParams } from 'react-router-dom'; import { PageLayout } from '~/components/Layout/PageLayout'; @@ -22,7 +23,7 @@ const LEFT_RIGHT_PANEL_MIN_SIZE = 30; const TOP_PANEL_MIN_SIZE = 20; function AddressResultPageHeader({ address, loading }: { address: string; loading?: boolean }) { - const { data: domainName, isLoading } = useResolveSuiNSName(address); + const { data: domainName, isLoading } = useResolveIotaNSName(address); return ( ; } @@ -126,8 +127,8 @@ function AddressResult({ address }: { address: string }) { ); } -function SuiNSAddressResult({ name }: { name: string }) { - const { isFetched, data } = useResolveSuiNSAddress(name); +function IotaNSAddressResult({ name }: { name: string }) { + const { isFetched, data } = useResolveIotaNSAddress(name); if (!isFetched) { return ; @@ -139,20 +140,20 @@ function SuiNSAddressResult({ name }: { name: string }) { export default function AddressResultPage() { const { id } = useParams(); - const isSuiNSAddress = isSuiNSName(id!); + const isIotaNSAddress = isIotaNSName(id!); return ( + content: isIotaNSAddress ? ( + ) : ( ), }} content={ - isSuiNSAddress ? : + isIotaNSAddress ? : } /> ); diff --git a/apps/explorer/src/pages/address-result/TotalStaked.tsx b/apps/explorer/src/pages/address-result/TotalStaked.tsx index dc1747b38a7..60d53cc6193 100644 --- a/apps/explorer/src/pages/address-result/TotalStaked.tsx +++ b/apps/explorer/src/pages/address-result/TotalStaked.tsx @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useFormatCoin, useGetDelegatedStake } from '@mysten/core'; +import { useFormatCoin, useGetDelegatedStake } from '@iota/core'; import { useMemo } from 'react'; -import { SUI_TYPE_ARG } from '@mysten/sui.js/utils'; -import { Text, Heading } from '@mysten/ui'; -import { Sui } from '@mysten/icons'; +import { IOTA_TYPE_ARG } from '@iota/iota.js/utils'; +import { Text, Heading } from '@iota/ui'; +import { Iota } from '@iota/icons'; export function TotalStaked({ address }: { address: string }) { const { data: delegatedStake } = useGetDelegatedStake({ @@ -22,10 +23,10 @@ export function TotalStaked({ address }: { address: string }) { ); }, [delegatedStake]); - const [formatted, symbol] = useFormatCoin(totalActivePendingStake, SUI_TYPE_ARG); + const [formatted, symbol] = useFormatCoin(totalActivePendingStake, IOTA_TYPE_ARG); return totalActivePendingStake ? (
- +
Staking diff --git a/apps/explorer/src/pages/checkpoints/CheckpointDetail.tsx b/apps/explorer/src/pages/checkpoints/CheckpointDetail.tsx index 115e2a26244..214b3970969 100644 --- a/apps/explorer/src/pages/checkpoints/CheckpointDetail.tsx +++ b/apps/explorer/src/pages/checkpoints/CheckpointDetail.tsx @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { Text, LoadingIndicator } from '@mysten/ui'; +import { useIotaClient } from '@iota/dapp-kit'; +import { Text, LoadingIndicator } from '@iota/ui'; import { useQuery } from '@tanstack/react-query'; import { useParams } from 'react-router-dom'; import { CheckpointTransactionBlocks } from './CheckpointTransactionBlocks'; import { PageLayout } from '~/components/Layout/PageLayout'; -import { SuiAmount } from '~/components/Table/SuiAmount'; +import { IotaAmount } from '~/components/Table/IotaAmount'; import { Banner } from '~/ui/Banner'; import { DescriptionList, DescriptionItem } from '~/ui/DescriptionList'; import { EpochLink } from '~/ui/InternalLink'; @@ -19,7 +20,7 @@ export default function CheckpointDetail() { const { id } = useParams<{ id: string }>(); const digestOrSequenceNumber = /^\d+$/.test(id!) ? parseInt(id!, 10) : id; - const client = useSuiClient(); + const client = useIotaClient(); const { data, isError, isPending } = useQuery({ queryKey: ['checkpoints', digestOrSequenceNumber], queryFn: () => client.getCheckpoint({ id: String(digestOrSequenceNumber!) }), @@ -102,19 +103,19 @@ export default function CheckpointDetail() { - - - diff --git a/apps/explorer/src/pages/checkpoints/CheckpointTransactionBlocks.tsx b/apps/explorer/src/pages/checkpoints/CheckpointTransactionBlocks.tsx index af12354388b..8b29ac33733 100644 --- a/apps/explorer/src/pages/checkpoints/CheckpointTransactionBlocks.tsx +++ b/apps/explorer/src/pages/checkpoints/CheckpointTransactionBlocks.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useState } from 'react'; diff --git a/apps/explorer/src/pages/epochs/EpochDetail.tsx b/apps/explorer/src/pages/epochs/EpochDetail.tsx index 9f36544f67a..efe73a83fb2 100644 --- a/apps/explorer/src/pages/epochs/EpochDetail.tsx +++ b/apps/explorer/src/pages/epochs/EpochDetail.tsx @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useFormatCoin } from '@mysten/core'; -import { useSuiClientQuery } from '@mysten/dapp-kit'; -import { SUI_TYPE_ARG } from '@mysten/sui.js/utils'; -import { LoadingIndicator } from '@mysten/ui'; +import { useFormatCoin } from '@iota/core'; +import { useIotaClientQuery } from '@iota/dapp-kit'; +import { IOTA_TYPE_ARG } from '@iota/iota.js/utils'; +import { LoadingIndicator } from '@iota/ui'; import { useQuery } from '@tanstack/react-query'; import { useMemo } from 'react'; import { useParams } from 'react-router-dom'; @@ -22,13 +23,13 @@ import { TableCard } from '~/ui/TableCard'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '~/ui/Tabs'; import { getEpochStorageFundFlow } from '~/utils/getStorageFundFlow'; -function SuiStats({ +function IotaStats({ amount, ...props }: Omit & { amount: bigint | number | string | undefined | null; }) { - const [formattedAmount, symbol] = useFormatCoin(amount, SUI_TYPE_ARG); + const [formattedAmount, symbol] = useFormatCoin(amount, IOTA_TYPE_ARG); return ( @@ -40,7 +41,7 @@ function SuiStats({ export default function EpochDetail() { const { id } = useParams(); const enhancedRpc = useEnhancedRpcClient(); - const { data: systemState } = useSuiClientQuery('getLatestSuiSystemState'); + const { data: systemState } = useIotaClientQuery('getLatestIotaSystemState'); const { data, isPending, isError } = useQuery({ queryKey: ['epoch', id], queryFn: async () => @@ -106,33 +107,33 @@ export default function EpochDetail() {
- - - - - - - - + + + {isCurrentEpoch ? : null} diff --git a/apps/explorer/src/pages/epochs/EpochTimer.tsx b/apps/explorer/src/pages/epochs/EpochTimer.tsx index a51aa6e32bd..46e45739697 100644 --- a/apps/explorer/src/pages/epochs/EpochTimer.tsx +++ b/apps/explorer/src/pages/epochs/EpochTimer.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Text } from '@mysten/ui'; +import { Text } from '@iota/ui'; import { useEpochProgress } from '~/pages/epochs/utils'; import { ProgressCircle } from '~/ui/ProgressCircle'; diff --git a/apps/explorer/src/pages/epochs/stats/EpochProgress.tsx b/apps/explorer/src/pages/epochs/stats/EpochProgress.tsx index 9ee0134b0cd..1b42615420e 100644 --- a/apps/explorer/src/pages/epochs/stats/EpochProgress.tsx +++ b/apps/explorer/src/pages/epochs/stats/EpochProgress.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { formatDate } from '@mysten/core'; -import { Heading, Text } from '@mysten/ui'; +import { formatDate } from '@iota/core'; +import { Heading, Text } from '@iota/ui'; import clsx from 'clsx'; import { getElapsedTime, useEpochProgress } from '~/pages/epochs/utils'; diff --git a/apps/explorer/src/pages/epochs/stats/EpochStats.tsx b/apps/explorer/src/pages/epochs/stats/EpochStats.tsx index 63f776cda2d..42d245f74ad 100644 --- a/apps/explorer/src/pages/epochs/stats/EpochStats.tsx +++ b/apps/explorer/src/pages/epochs/stats/EpochStats.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Heading } from '@mysten/ui'; +import { Heading } from '@iota/ui'; import { type ReactNode } from 'react'; import { Card } from '~/ui/Card'; diff --git a/apps/explorer/src/pages/epochs/stats/ValidatorStatus.tsx b/apps/explorer/src/pages/epochs/stats/ValidatorStatus.tsx index 0465674a412..84bd236c2fc 100644 --- a/apps/explorer/src/pages/epochs/stats/ValidatorStatus.tsx +++ b/apps/explorer/src/pages/epochs/stats/ValidatorStatus.tsx @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { getRefGasPrice } from '@mysten/core'; -import { useSuiClientQuery } from '@mysten/dapp-kit'; -import { Heading, Text } from '@mysten/ui'; +import { getRefGasPrice } from '@iota/core'; +import { useIotaClientQuery } from '@iota/dapp-kit'; +import { Heading, Text } from '@iota/ui'; import { useMemo } from 'react'; import { Card } from '~/ui/Card'; import { RingChart, RingChartLegend } from '~/ui/RingChart'; export function ValidatorStatus() { - const { data } = useSuiClientQuery('getLatestSuiSystemState'); + const { data } = useIotaClientQuery('getLatestIotaSystemState'); const nextRefGasPrice = useMemo( () => getRefGasPrice(data?.activeValidators), @@ -70,7 +71,7 @@ export function ValidatorStatus() { {nextRefGasPrice.toString()} - MIST + MICROS
diff --git a/apps/explorer/src/pages/epochs/utils.ts b/apps/explorer/src/pages/epochs/utils.ts index f8ba9a27b6e..e115865ed7f 100644 --- a/apps/explorer/src/pages/epochs/utils.ts +++ b/apps/explorer/src/pages/epochs/utils.ts @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useTimeAgo } from '@mysten/core'; -import { useSuiClientQuery } from '@mysten/dapp-kit'; +import { useTimeAgo } from '@iota/core'; +import { useIotaClientQuery } from '@iota/dapp-kit'; export function useEpochProgress(suffix: string = 'left') { - const { data } = useSuiClientQuery('getLatestSuiSystemState'); + const { data } = useIotaClientQuery('getLatestIotaSystemState'); const start = data?.epochStartTimestampMs ? Number(data.epochStartTimestampMs) : undefined; const duration = data?.epochDurationMs ? Number(data.epochDurationMs) : undefined; const end = start !== undefined && duration !== undefined ? start + duration : undefined; diff --git a/apps/explorer/src/pages/home/Home.tsx b/apps/explorer/src/pages/home/Home.tsx index 8d5cc8a2d51..6565c0a59d0 100644 --- a/apps/explorer/src/pages/home/Home.tsx +++ b/apps/explorer/src/pages/home/Home.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import clsx from 'clsx'; @@ -8,7 +9,7 @@ import { AccountsCardGraph } from '~/components/AccountCardGraph'; import { Activity } from '~/components/Activity'; import { CurrentEpoch, OnTheNetwork } from '~/components/HomeMetrics'; import { PageLayout } from '~/components/Layout/PageLayout'; -import { SuiTokenCard } from '~/components/SuiTokenCard'; +import { IotaTokenCard } from '~/components/IotaTokenCard'; import { TransactionsCardGraph } from '~/components/TransactionsCardGraph'; import { ErrorBoundary } from '~/components/error-boundary/ErrorBoundary'; import { TopPackagesCard } from '~/components/top-packages/TopPackagesCard'; @@ -24,7 +25,7 @@ const TRANSACTIONS_LIMIT = 25; function Home() { const [network] = useNetwork(); - const isSuiTokenCardEnabled = network === Network.Mainnet; + const isIotaTokenCardEnabled = network === Network.Mainnet; return (
@@ -42,9 +43,9 @@ function Home() {
- {isSuiTokenCardEnabled ? ( + {isIotaTokenCardEnabled ? (
- +
) : null}
diff --git a/apps/explorer/src/pages/id-page/PageContent.tsx b/apps/explorer/src/pages/id-page/PageContent.tsx index dcb53a9b583..56ec5a25336 100644 --- a/apps/explorer/src/pages/id-page/PageContent.tsx +++ b/apps/explorer/src/pages/id-page/PageContent.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useGetObject } from '@mysten/core'; +import { useGetObject } from '@iota/core'; import { Banner } from '~/ui/Banner'; import { Divider } from '~/ui/Divider'; import { FieldsContent } from '~/pages/object-result/views/TokenView'; @@ -13,7 +14,7 @@ import { useBreakpoint } from '~/hooks/useBreakpoint'; import { OwnedCoins } from '~/components/OwnedCoins'; import { OwnedObjects } from '~/components/OwnedObjects'; import { LocalStorageSplitPaneKey, SplitPanes } from '~/ui/SplitPanes'; -import { useSuiClient } from '@mysten/dapp-kit'; +import { useIotaClient } from '@iota/dapp-kit'; import { useQuery } from '@tanstack/react-query'; const LEFT_RIGHT_PANEL_MIN_SIZE = 30; @@ -67,7 +68,7 @@ function OwnedObjectsSection({ address }: { address: string }) { } function TransactionsSection({ address, isObject }: { address: string; isObject: boolean }) { - const client = useSuiClient(); + const client = useIotaClient(); const { data: transactionsForAddressData, diff --git a/apps/explorer/src/pages/id-page/index.tsx b/apps/explorer/src/pages/id-page/index.tsx index 3abd8f78429..77bf8b6be08 100644 --- a/apps/explorer/src/pages/id-page/index.tsx +++ b/apps/explorer/src/pages/id-page/index.tsx @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useParams } from 'react-router-dom'; import { - isSuiNSName, + isIotaNSName, useGetObject, - useResolveSuiNSAddress, - useResolveSuiNSName, -} from '@mysten/core'; + useResolveIotaNSAddress, + useResolveIotaNSName, +} from '@iota/core'; import { PageLayout } from '~/components/Layout/PageLayout'; import { PageHeader } from '~/ui/PageHeader'; -import { ObjectDetailsHeader } from '@mysten/icons'; +import { ObjectDetailsHeader } from '@iota/icons'; import { TotalStaked } from '~/pages/address-result/TotalStaked'; import { ErrorBoundary } from '~/components/error-boundary/ErrorBoundary'; import { ObjectView } from '~/pages/object-result/views/ObjectView'; @@ -25,10 +26,10 @@ function Header({ loading?: boolean; error?: Error | null; }) { - const { data: domainName, isLoading, error: resolveSuinsError } = useResolveSuiNSName(address); + const { data: domainName, isLoading, error: resolveIotansError } = useResolveIotaNSName(address); const { data, isPending, error: getObjectError } = useGetObject(address!); const isObject = !!data?.data; - const errorText = getObjectError?.message ?? resolveSuinsError?.message ?? error?.message; + const errorText = getObjectError?.message ?? resolveIotansError?.message ?? error?.message; return (
@@ -55,22 +56,22 @@ function Header({ function PageLayoutContainer({ address }: { address: string }) { const { id } = useParams(); - const isSuiNSAddress = isSuiNSName(id!); + const isIotaNSAddress = isIotaNSName(id!); const { data, isLoading, - error: suinsAddressError, - } = useResolveSuiNSAddress(address, isSuiNSAddress); + error: iotansAddressError, + } = useResolveIotaNSAddress(address, isIotaNSAddress); return ( , }} - content={} + content={} /> ); } diff --git a/apps/explorer/src/pages/index.tsx b/apps/explorer/src/pages/index.tsx index e2ad484b1dd..34d28826253 100644 --- a/apps/explorer/src/pages/index.tsx +++ b/apps/explorer/src/pages/index.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { wrapCreateBrowserRouter } from '@sentry/react'; diff --git a/apps/explorer/src/pages/object-result/ObjectResult.tsx b/apps/explorer/src/pages/object-result/ObjectResult.tsx index 15314bfcf40..25d0e8a33bc 100644 --- a/apps/explorer/src/pages/object-result/ObjectResult.tsx +++ b/apps/explorer/src/pages/object-result/ObjectResult.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useGetObject } from '@mysten/core'; -import { ObjectDetailsHeader } from '@mysten/icons'; -import { LoadingIndicator } from '@mysten/ui'; +import { useGetObject } from '@iota/core'; +import { ObjectDetailsHeader } from '@iota/icons'; +import { LoadingIndicator } from '@iota/ui'; import clsx from 'clsx'; import { useParams } from 'react-router-dom'; diff --git a/apps/explorer/src/pages/object-result/ObjectResultType.tsx b/apps/explorer/src/pages/object-result/ObjectResultType.tsx index 1788297f441..d9850b67397 100644 --- a/apps/explorer/src/pages/object-result/ObjectResultType.tsx +++ b/apps/explorer/src/pages/object-result/ObjectResultType.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { parseObjectType } from '../../utils/objectUtils'; -import type { SuiObjectResponse, ObjectOwner, MoveStruct } from '@mysten/sui.js/client'; +import type { IotaObjectResponse, ObjectOwner, MoveStruct } from '@iota/iota.js/client'; export type DataType = { id: string; @@ -35,7 +36,7 @@ export type DataType = { * TODO: We should redesign the rendering logic and data model * to make this more extensible and customizable for different Move types */ -export function translate(o: SuiObjectResponse): DataType { +export function translate(o: IotaObjectResponse): DataType { if (o.data) { return { id: o.data.objectId, diff --git a/apps/explorer/src/pages/object-result/views/ObjectView.module.css b/apps/explorer/src/pages/object-result/views/ObjectView.module.css index 15381c57f2e..37d1a4293db 100644 --- a/apps/explorer/src/pages/object-result/views/ObjectView.module.css +++ b/apps/explorer/src/pages/object-result/views/ObjectView.module.css @@ -103,7 +103,7 @@ td.objectid { } .objecttypelink { - @apply text-sui-dark no-underline; + @apply text-iota-dark no-underline; } /* Clickable Header CSS */ diff --git a/apps/explorer/src/pages/object-result/views/ObjectView.tsx b/apps/explorer/src/pages/object-result/views/ObjectView.tsx index 1e2c5fbdc2e..695499ca496 100644 --- a/apps/explorer/src/pages/object-result/views/ObjectView.tsx +++ b/apps/explorer/src/pages/object-result/views/ObjectView.tsx @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { CoinFormat, useFormatCoin, useResolveSuiNSName } from '@mysten/core'; -import { ArrowUpRight16, Info16 } from '@mysten/icons'; -import { type ObjectOwner, type SuiObjectResponse } from '@mysten/sui.js/client'; +import { CoinFormat, useFormatCoin, useResolveIotaNSName } from '@iota/core'; +import { ArrowUpRight16, Info16 } from '@iota/icons'; +import { type ObjectOwner, type IotaObjectResponse } from '@iota/iota.js/client'; import { formatAddress, normalizeStructTag, parseStructTag, - SUI_TYPE_ARG, -} from '@mysten/sui.js/utils'; -import { Heading, Text } from '@mysten/ui'; + IOTA_TYPE_ARG, +} from '@iota/iota.js/utils'; +import { Heading, Text } from '@iota/ui'; import { useQuery } from '@tanstack/react-query'; import clsx from 'clsx'; import { type ReactNode, useEffect, useState } from 'react'; @@ -179,9 +180,9 @@ function VersionCard({ version, digest }: { version?: string; digest: string }) } function AddressOwner({ address }: { address: string }) { - const { data: suinsDomainName } = useResolveSuiNSName(address); + const { data: iotansDomainName } = useResolveIotaNSName(address); - return ; + return ; } function OwnerCard({ @@ -195,7 +196,7 @@ function OwnerCard({ } | null; storageRebate?: string | null; }) { - const [storageRebateFormatted] = useFormatCoin(storageRebate, SUI_TYPE_ARG, CoinFormat.FULL); + const [storageRebateFormatted] = useFormatCoin(storageRebate, IOTA_TYPE_ARG, CoinFormat.FULL); if (!objOwner && !display) { return null; @@ -243,7 +244,7 @@ function OwnerCard({ - -{storageRebateFormatted} SUI + -{storageRebateFormatted} IOTA @@ -251,7 +252,7 @@ function OwnerCard({ } interface ObjectViewProps { - data: SuiObjectResponse; + data: IotaObjectResponse; } export function ObjectView({ data }: ObjectViewProps) { diff --git a/apps/explorer/src/pages/object-result/views/PkgView.tsx b/apps/explorer/src/pages/object-result/views/PkgView.tsx index 1810d094981..f44e3de132e 100644 --- a/apps/explorer/src/pages/object-result/views/PkgView.tsx +++ b/apps/explorer/src/pages/object-result/views/PkgView.tsx @@ -1,10 +1,8 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { LoadingIndicator, RadioGroup, RadioGroupItem } from '@mysten/ui'; +import { LoadingIndicator, RadioGroup, RadioGroupItem } from '@iota/ui'; import { useState } from 'react'; import { type Direction } from 'react-resizable-panels'; diff --git a/apps/explorer/src/pages/object-result/views/TokenView.tsx b/apps/explorer/src/pages/object-result/views/TokenView.tsx index f507c72bac3..b3ed266cc46 100644 --- a/apps/explorer/src/pages/object-result/views/TokenView.tsx +++ b/apps/explorer/src/pages/object-result/views/TokenView.tsx @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useGetDynamicFields, useGetObject } from '@mysten/core'; -import { useSuiClientQuery } from '@mysten/dapp-kit'; -import { type SuiObjectResponse } from '@mysten/sui.js/client'; -import { Heading } from '@mysten/ui'; +import { useGetDynamicFields, useGetObject } from '@iota/core'; +import { useIotaClientQuery } from '@iota/dapp-kit'; +import { type IotaObjectResponse } from '@iota/iota.js/client'; +import { Heading } from '@iota/ui'; import { type ReactNode, useState } from 'react'; import { DynamicFieldsCard } from '~/components/Object/DynamicFieldsCard'; @@ -26,13 +27,13 @@ enum TabValue { } function useObjectFieldsCard(id: string) { - const { data: suiObjectResponseData, isPending, isError } = useGetObject(id); + const { data: iotaObjectResponseData, isPending, isError } = useGetObject(id); const objectType = - suiObjectResponseData?.data?.type ?? - suiObjectResponseData?.data?.content?.dataType === 'package' - ? suiObjectResponseData.data.type - : suiObjectResponseData?.data?.content?.type; + iotaObjectResponseData?.data?.type ?? + iotaObjectResponseData?.data?.content?.dataType === 'package' + ? iotaObjectResponseData.data.type + : iotaObjectResponseData?.data?.content?.type; const [packageId, moduleName, functionName] = objectType?.split('<')[0]?.split('::') || []; @@ -41,7 +42,7 @@ function useObjectFieldsCard(id: string) { data: normalizedStructData, isPending: loadingNormalizedStruct, isError: errorNormalizedMoveStruct, - } = useSuiClientQuery( + } = useIotaClientQuery( 'getNormalizedMoveStruct', { package: packageId, @@ -57,7 +58,7 @@ function useObjectFieldsCard(id: string) { loading: isPending || loadingNormalizedStruct, isError: isError || errorNormalizedMoveStruct, normalizedStructData, - suiObjectResponseData, + iotaObjectResponseData, objectType, }; } @@ -65,7 +66,7 @@ function useObjectFieldsCard(id: string) { export function FieldsContent({ objectId }: { objectId: string }) { const { normalizedStructData, - suiObjectResponseData, + iotaObjectResponseData, objectType, loading: objectFieldsCardLoading, isError: objectFieldsCardError, @@ -98,7 +99,7 @@ export function FieldsContent({ objectId }: { objectId: string }) { {'publicKey' in data ? ( - + - {data.publicKey.toSuiPublicKey()} + {data.publicKey.toIotaPublicKey()} ) : null} @@ -60,26 +61,26 @@ function SignaturePanel({ ); } -function getSignatureFromAddress(signatures: SignaturePubkeyPair[], suiAddress: string) { +function getSignatureFromAddress(signatures: SignaturePubkeyPair[], iotaAddress: string) { return signatures.find( (signature) => - ('address' in signature ? signature.address : signature.publicKey.toSuiAddress()) === - normalizeSuiAddress(suiAddress), + ('address' in signature ? signature.address : signature.publicKey.toIotaAddress()) === + normalizeIotaAddress(iotaAddress), ); } function getSignaturesExcludingAddress( signatures: SignaturePubkeyPair[], - suiAddress: string, + iotaAddress: string, ): SignaturePubkeyPair[] { return signatures.filter( (signature) => - ('address' in signature ? signature.address : signature.publicKey.toSuiAddress()) !== - normalizeSuiAddress(suiAddress), + ('address' in signature ? signature.address : signature.publicKey.toIotaAddress()) !== + normalizeIotaAddress(iotaAddress), ); } interface Props { - transaction: SuiTransactionBlockResponse; + transaction: IotaTransactionBlockResponse; } export function Signatures({ transaction }: Props) { diff --git a/apps/explorer/src/pages/transaction-result/TransactionData.tsx b/apps/explorer/src/pages/transaction-result/TransactionData.tsx index 2a1b59323ed..63147aec188 100644 --- a/apps/explorer/src/pages/transaction-result/TransactionData.tsx +++ b/apps/explorer/src/pages/transaction-result/TransactionData.tsx @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useTransactionSummary } from '@mysten/core'; +import { useTransactionSummary } from '@iota/core'; import { type ProgrammableTransaction, - type SuiTransactionBlockResponse, -} from '@mysten/sui.js/client'; + type IotaTransactionBlockResponse, +} from '@iota/iota.js/client'; import { TransactionDetailCard } from './transaction-summary/TransactionDetailCard'; import { GasBreakdown } from '~/components/GasBreakdown'; @@ -14,7 +15,7 @@ import { InputsCard } from '~/pages/transaction-result/programmable-transaction- import { TransactionsCard } from '~/pages/transaction-result/programmable-transaction-view/TransactionsCard'; interface Props { - transaction: SuiTransactionBlockResponse; + transaction: IotaTransactionBlockResponse; } export function TransactionData({ transaction }: Props) { diff --git a/apps/explorer/src/pages/transaction-result/TransactionResult.module.css b/apps/explorer/src/pages/transaction-result/TransactionResult.module.css index fe4cd4511ed..00a60208bc6 100644 --- a/apps/explorer/src/pages/transaction-result/TransactionResult.module.css +++ b/apps/explorer/src/pages/transaction-result/TransactionResult.module.css @@ -89,7 +89,7 @@ .itemviewcontent .itemviewcontentitem a, .itemviewcontent .itemviewcontentitem span { - @apply break-all font-mono text-sm text-sui-dark; + @apply break-all font-mono text-sm text-iota-dark; } @media (min-width: 40em) { diff --git a/apps/explorer/src/pages/transaction-result/TransactionResult.tsx b/apps/explorer/src/pages/transaction-result/TransactionResult.tsx index 40dc22a1e1e..2ed58f4acda 100644 --- a/apps/explorer/src/pages/transaction-result/TransactionResult.tsx +++ b/apps/explorer/src/pages/transaction-result/TransactionResult.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiTransactionBlockResponse } from '@mysten/sui.js/client'; +import { type IotaTransactionBlockResponse } from '@iota/iota.js/client'; import { useParams } from 'react-router-dom'; import { TransactionView } from './TransactionView'; @@ -16,7 +17,7 @@ function TransactionResultPageHeader({ error, loading, }: { - transaction?: SuiTransactionBlockResponse; + transaction?: IotaTransactionBlockResponse; error?: string; loading?: boolean; }) { diff --git a/apps/explorer/src/pages/transaction-result/TransactionView.tsx b/apps/explorer/src/pages/transaction-result/TransactionView.tsx index 9fb911a6d07..d2d6e218a2e 100644 --- a/apps/explorer/src/pages/transaction-result/TransactionView.tsx +++ b/apps/explorer/src/pages/transaction-result/TransactionView.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiTransactionBlockResponse } from '@mysten/sui.js/client'; +import { type IotaTransactionBlockResponse } from '@iota/iota.js/client'; import clsx from 'clsx'; import { type ReactNode, useState } from 'react'; @@ -24,7 +25,7 @@ function TabsContentContainer({ value, children }: { value: string; children: Re ); } -export function TransactionView({ transaction }: { transaction: SuiTransactionBlockResponse }) { +export function TransactionView({ transaction }: { transaction: IotaTransactionBlockResponse }) { const isMediumOrAbove = useBreakpoint('md'); const [isCollapsed, setIsCollapsed] = useState(false); diff --git a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/InputsCard.tsx b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/InputsCard.tsx index 19057b14b0c..8865636c1b6 100644 --- a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/InputsCard.tsx +++ b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/InputsCard.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiCallArg } from '@mysten/sui.js/client'; -import { Text } from '@mysten/ui'; +import { type IotaCallArg } from '@iota/iota.js/client'; +import { Text } from '@iota/ui'; import { ProgrammableTxnBlockCard } from '~/components/transactions/ProgTxnBlockCard'; import { AddressLink, ObjectLink } from '~/ui/InternalLink'; @@ -11,7 +12,7 @@ import { CollapsibleSection } from '~/ui/collapsible/CollapsibleSection'; const REGEX_NUMBER = /^\d+$/; interface InputsCardProps { - inputs: SuiCallArg[]; + inputs: IotaCallArg[]; } export function InputsCard({ inputs }: InputsCardProps) { diff --git a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/Transaction.tsx b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/Transaction.tsx index f3de3ca0441..3bb94d9a1dc 100644 --- a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/Transaction.tsx +++ b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/Transaction.tsx @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { - type MoveCallSuiTransaction, - type SuiArgument, - type SuiMovePackage, -} from '@mysten/sui.js/client'; -import { Text } from '@mysten/ui'; + type MoveCallIotaTransaction, + type IotaArgument, + type IotaMovePackage, +} from '@iota/iota.js/client'; +import { Text } from '@iota/ui'; import { type ReactNode } from 'react'; -import { flattenSuiArguments } from './utils'; +import { flattenIotaArguments } from './utils'; import { ErrorBoundary } from '~/components/error-boundary/ErrorBoundary'; import { ObjectLink } from '~/ui/InternalLink'; @@ -26,19 +27,19 @@ function TransactionContent({ children }: { children?: ReactNode }) { ); } -function ArrayArgument({ data }: TransactionProps<(SuiArgument | SuiArgument[])[] | undefined>) { +function ArrayArgument({ data }: TransactionProps<(IotaArgument | IotaArgument[])[] | undefined>) { return ( {data && ( - ({flattenSuiArguments(data)}) + ({flattenIotaArguments(data)}) )} ); } -function MoveCall({ data }: TransactionProps) { +function MoveCall({ data }: TransactionProps) { const { module, package: movePackage, @@ -54,7 +55,7 @@ function MoveCall({ data }: TransactionProps) { , function: {func} {args && ( - , arguments: [{flattenSuiArguments(args!)}] + , arguments: [{flattenIotaArguments(args!)}] )} {typeArgs && ( , type_arguments: [{typeArgs.join(', ')}] @@ -67,11 +68,11 @@ function MoveCall({ data }: TransactionProps) { export function Transaction({ type, data, -}: TransactionProps<(SuiArgument | SuiArgument[])[] | MoveCallSuiTransaction | SuiMovePackage>) { +}: TransactionProps<(IotaArgument | IotaArgument[])[] | MoveCallIotaTransaction | IotaMovePackage>) { if (type === 'MoveCall') { return ( - + ); } @@ -80,7 +81,7 @@ export function Transaction({ ); diff --git a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/TransactionsCard.tsx b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/TransactionsCard.tsx index aad47a9e838..a68fffc69ee 100644 --- a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/TransactionsCard.tsx +++ b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/TransactionsCard.tsx @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiTransaction } from '@mysten/sui.js/client'; +import { type IotaTransaction } from '@iota/iota.js/client'; import { Transaction } from './Transaction'; import { ProgrammableTxnBlockCard } from '~/components/transactions/ProgTxnBlockCard'; import { CollapsibleSection } from '~/ui/collapsible/CollapsibleSection'; interface TransactionsCardProps { - transactions: SuiTransaction[]; + transactions: IotaTransaction[]; } export function TransactionsCard({ transactions }: TransactionsCardProps) { diff --git a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/__test__/utils.test.ts b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/__test__/utils.test.ts index eca9dcfe89d..dc6f2db1e6f 100644 --- a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/__test__/utils.test.ts +++ b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/__test__/utils.test.ts @@ -1,22 +1,23 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { describe, expect, it } from 'vitest'; -import { flattenSuiArguments } from '~/pages/transaction-result/programmable-transaction-view/utils'; +import { flattenIotaArguments } from '~/pages/transaction-result/programmable-transaction-view/utils'; describe('utils.ts', () => { describe('flattenCommandData', () => { it('should format SplitCoin data', () => { - expect(flattenSuiArguments(['GasCoin', { Input: 1 }])).toEqual('GasCoin, Input(1)'); - expect(flattenSuiArguments(['GasCoin', { Result: 2 }])).toEqual('GasCoin, Result(2)'); - expect(flattenSuiArguments(['GasCoin', { NestedResult: [1, 2] }])).toEqual( + expect(flattenIotaArguments(['GasCoin', { Input: 1 }])).toEqual('GasCoin, Input(1)'); + expect(flattenIotaArguments(['GasCoin', { Result: 2 }])).toEqual('GasCoin, Result(2)'); + expect(flattenIotaArguments(['GasCoin', { NestedResult: [1, 2] }])).toEqual( 'GasCoin, NestedResult(1, 2)', ); }); it('should format TransferObjects data', () => { expect( - flattenSuiArguments([ + flattenIotaArguments([ [ { Result: 0, @@ -40,9 +41,9 @@ describe('utils.ts', () => { ]), ).toEqual('[Result(0), Result(1), Result(2), Result(3), Result(4)], Input(0)'); }); - it('should flatten MergeCoinsSuiTransaction data', () => { + it('should flatten MergeCoinsIotaTransaction data', () => { expect( - flattenSuiArguments([ + flattenIotaArguments([ { Input: 0, }, diff --git a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/utils.ts b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/utils.ts index 6d61d76c5ea..ce9126c5f14 100644 --- a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/utils.ts +++ b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/utils.ts @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiArgument } from '@mysten/sui.js/client'; +import { type IotaArgument } from '@iota/iota.js/client'; -export function flattenSuiArguments(data: (SuiArgument | SuiArgument[])[]): string { +export function flattenIotaArguments(data: (IotaArgument | IotaArgument[])[]): string { if (!data) { return ''; } @@ -12,7 +13,7 @@ export function flattenSuiArguments(data: (SuiArgument | SuiArgument[])[]): stri if (value === 'GasCoin') { return value; } else if (Array.isArray(value)) { - return `[${flattenSuiArguments(value)}]`; + return `[${flattenIotaArguments(value)}]`; } else if (value === null) { return 'Null'; } else if (typeof value === 'object') { diff --git a/apps/explorer/src/pages/transaction-result/transaction-summary/BalanceChanges.tsx b/apps/explorer/src/pages/transaction-result/transaction-summary/BalanceChanges.tsx index 7fea21afd50..5a0431086b4 100644 --- a/apps/explorer/src/pages/transaction-result/transaction-summary/BalanceChanges.tsx +++ b/apps/explorer/src/pages/transaction-result/transaction-summary/BalanceChanges.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type BalanceChangeSummary, @@ -6,10 +7,10 @@ import { useFormatCoin, useCoinMetadata, type BalanceChange, - useResolveSuiNSName, + useResolveIotaNSName, getRecognizedUnRecognizedTokenChanges, -} from '@mysten/core'; -import { Heading, Text } from '@mysten/ui'; +} from '@iota/core'; +import { Heading, Text } from '@iota/ui'; import clsx from 'clsx'; import { useMemo } from 'react'; @@ -75,7 +76,7 @@ function BalanceChangeEntry({ change }: { change: BalanceChange }) { } function BalanceChangeCard({ changes, owner }: { changes: BalanceChange[]; owner: string }) { - const { data: suinsDomainName } = useResolveSuiNSName(owner); + const { data: iotansDomainName } = useResolveIotaNSName(owner); const { recognizedTokenChanges, unRecognizedTokenChanges } = useMemo( () => getRecognizedUnRecognizedTokenChanges(changes), [changes], @@ -99,7 +100,7 @@ function BalanceChangeCard({ changes, owner }: { changes: BalanceChange[]; owner Owner - +
) : null diff --git a/apps/explorer/src/pages/transaction-result/transaction-summary/ObjectChanges.tsx b/apps/explorer/src/pages/transaction-result/transaction-summary/ObjectChanges.tsx index c3128b6865e..c977d91a555 100644 --- a/apps/explorer/src/pages/transaction-result/transaction-summary/ObjectChanges.tsx +++ b/apps/explorer/src/pages/transaction-result/transaction-summary/ObjectChanges.tsx @@ -1,22 +1,23 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { ObjectChangeLabels, - type SuiObjectChangeWithDisplay, + type IotaObjectChangeWithDisplay, type ObjectChangesByOwner, type ObjectChangeSummary, - type SuiObjectChangeTypes, - useResolveSuiNSName, -} from '@mysten/core'; -import { ChevronRight12 } from '@mysten/icons'; + type IotaObjectChangeTypes, + useResolveIotaNSName, +} from '@iota/core'; +import { ChevronRight12 } from '@iota/icons'; import { - type SuiObjectChangePublished, - type SuiObjectChange, + type IotaObjectChangePublished, + type IotaObjectChange, type DisplayFieldsResponse, -} from '@mysten/sui.js/client'; -import { parseStructTag } from '@mysten/sui.js/utils'; -import { Text } from '@mysten/ui'; +} from '@iota/iota.js/client'; +import { parseStructTag } from '@iota/iota.js/utils'; +import { Text } from '@iota/ui'; import * as Collapsible from '@radix-ui/react-collapsible'; import clsx from 'clsx'; import { useState, type ReactNode } from 'react'; @@ -150,8 +151,8 @@ function ObjectDetail({ } interface ObjectChangeEntriesProps { - type: SuiObjectChangeTypes; - changeEntries: SuiObjectChange[]; + type: IotaObjectChangeTypes; + changeEntries: IotaObjectChange[]; isDisplay?: boolean; } @@ -160,7 +161,7 @@ function ObjectChangeEntries({ changeEntries, type, isDisplay }: ObjectChangeEnt let expandableItems = []; if (type === 'published') { - expandableItems = (changeEntries as SuiObjectChangePublished[]).map( + expandableItems = (changeEntries as IotaObjectChangePublished[]).map( ({ packageId, modules }) => ( + expandableItems = (changeEntries as IotaObjectChangeWithDisplay[]).map((change) => 'objectId' in change && change.display ? ( @@ -257,7 +258,7 @@ function ObjectChangeEntriesCardFooter({ {ownerType === 'AddressOwner' && ( - + )} {ownerType === 'ObjectOwner' && } @@ -322,7 +323,7 @@ export function ObjectChanges({ objectSummary }: ObjectChangesProps) { {Object.entries(objectSummary).map(([type, changes]) => ( ))} diff --git a/apps/explorer/src/pages/transaction-result/transaction-summary/ObjectDisplay.tsx b/apps/explorer/src/pages/transaction-result/transaction-summary/ObjectDisplay.tsx index 978cf7f99e1..caf5f4fae6e 100644 --- a/apps/explorer/src/pages/transaction-result/transaction-summary/ObjectDisplay.tsx +++ b/apps/explorer/src/pages/transaction-result/transaction-summary/ObjectDisplay.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type DisplayFieldsResponse } from '@mysten/sui.js/client'; +import { type DisplayFieldsResponse } from '@iota/iota.js/client'; import { useState } from 'react'; import { ObjectLink } from '~/ui/InternalLink'; diff --git a/apps/explorer/src/pages/transaction-result/transaction-summary/TransactionDetailCard.tsx b/apps/explorer/src/pages/transaction-result/transaction-summary/TransactionDetailCard.tsx index a651148f427..0dcd8e678d0 100644 --- a/apps/explorer/src/pages/transaction-result/transaction-summary/TransactionDetailCard.tsx +++ b/apps/explorer/src/pages/transaction-result/transaction-summary/TransactionDetailCard.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { formatDate, useResolveSuiNSName } from '@mysten/core'; -import { Heading, Text } from '@mysten/ui'; +import { formatDate, useResolveIotaNSName } from '@iota/core'; +import { Heading, Text } from '@iota/ui'; import { type ReactNode } from 'react'; import { useBreakpoint } from '~/hooks/useBreakpoint'; @@ -36,7 +37,7 @@ export function TransactionDetailCard({ timestamp, }: TransactionDetailsProps) { const md = useBreakpoint('md'); - const { data: domainName } = useResolveSuiNSName(sender); + const { data: domainName } = useResolveIotaNSName(sender); return ( diff --git a/apps/explorer/src/pages/transaction-result/transaction-summary/UpgradedSystemPackages.tsx b/apps/explorer/src/pages/transaction-result/transaction-summary/UpgradedSystemPackages.tsx index ef9a4350f63..0f2f734da34 100644 --- a/apps/explorer/src/pages/transaction-result/transaction-summary/UpgradedSystemPackages.tsx +++ b/apps/explorer/src/pages/transaction-result/transaction-summary/UpgradedSystemPackages.tsx @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Text } from '@mysten/ui'; +import { Text } from '@iota/ui'; import { ObjectLink } from '~/ui/InternalLink'; import { CollapsibleCard } from '~/ui/collapsible/CollapsibleCard'; import { CollapsibleSection } from '~/ui/collapsible/CollapsibleSection'; -import type { OwnedObjectRef } from '@mysten/sui.js/client'; +import type { OwnedObjectRef } from '@iota/iota.js/client'; export function UpgradedSystemPackages({ data }: { data: OwnedObjectRef[] }) { if (!data?.length) return null; diff --git a/apps/explorer/src/pages/transaction-result/transaction-summary/index.tsx b/apps/explorer/src/pages/transaction-result/transaction-summary/index.tsx index b1601253cc1..8cfa3c5e4f3 100644 --- a/apps/explorer/src/pages/transaction-result/transaction-summary/index.tsx +++ b/apps/explorer/src/pages/transaction-result/transaction-summary/index.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useTransactionSummary } from '@mysten/core'; -import { type SuiTransactionBlockResponse } from '@mysten/sui.js/client'; +import { useTransactionSummary } from '@iota/core'; +import { type IotaTransactionBlockResponse } from '@iota/iota.js/client'; import { BalanceChanges } from './BalanceChanges'; import { ObjectChanges } from './ObjectChanges'; @@ -10,7 +11,7 @@ import { UpgradedSystemPackages } from './UpgradedSystemPackages'; import { useRecognizedPackages } from '~/hooks/useRecognizedPackages'; interface TransactionSummaryProps { - transaction: SuiTransactionBlockResponse; + transaction: IotaTransactionBlockResponse; } export function TransactionSummary({ transaction }: TransactionSummaryProps) { diff --git a/apps/explorer/src/pages/validator/ValidatorDetails.tsx b/apps/explorer/src/pages/validator/ValidatorDetails.tsx index 0ea01f63cbf..905506ba8b4 100644 --- a/apps/explorer/src/pages/validator/ValidatorDetails.tsx +++ b/apps/explorer/src/pages/validator/ValidatorDetails.tsx @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useGetValidatorsApy, useGetValidatorsEvents } from '@mysten/core'; -import { useSuiClientQuery } from '@mysten/dapp-kit'; -import { type SuiSystemStateSummary } from '@mysten/sui.js/client'; -import { LoadingIndicator, Text } from '@mysten/ui'; +import { useGetValidatorsApy, useGetValidatorsEvents } from '@iota/core'; +import { useIotaClientQuery } from '@iota/dapp-kit'; +import { type IotaSystemStateSummary } from '@iota/iota.js/client'; +import { LoadingIndicator, Text } from '@iota/ui'; import React, { useMemo } from 'react'; import { useParams } from 'react-router-dom'; @@ -16,7 +17,7 @@ import { getValidatorMoveEvent } from '~/utils/getValidatorMoveEvent'; import { VALIDATOR_LOW_STAKE_GRACE_PERIOD } from '~/utils/validatorConstants'; const getAtRiskRemainingEpochs = ( - data: SuiSystemStateSummary | undefined, + data: IotaSystemStateSummary | undefined, validatorId: string | undefined, ): number | null => { if (!data || !validatorId) return null; @@ -26,13 +27,13 @@ const getAtRiskRemainingEpochs = ( function ValidatorDetails() { const { id } = useParams(); - const { data, isPending } = useSuiClientQuery('getLatestSuiSystemState'); + const { data, isPending } = useIotaClientQuery('getLatestIotaSystemState'); const validatorData = useMemo(() => { if (!data) return null; return ( data.activeValidators.find( - ({ suiAddress, stakingPoolId }) => suiAddress === id || stakingPoolId === id, + ({ iotaAddress, stakingPoolId }) => iotaAddress === id || stakingPoolId === id, ) || null ); }, [id, data]); @@ -122,7 +123,7 @@ function ValidatorDetails() { } > - Staked SUI is below the minimum SUI stake threshold to remain a + Staked IOTA is below the minimum IOTA stake threshold to remain a validator. diff --git a/apps/explorer/src/pages/validators/Validators.tsx b/apps/explorer/src/pages/validators/Validators.tsx index 1c455d16bfd..3067816b700 100644 --- a/apps/explorer/src/pages/validators/Validators.tsx +++ b/apps/explorer/src/pages/validators/Validators.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -9,10 +10,10 @@ import { type ApyByValidator, useGetValidatorsEvents, formatPercentageDisplay, -} from '@mysten/core'; -import { useSuiClientQuery } from '@mysten/dapp-kit'; -import { type SuiEvent, type SuiValidatorSummary } from '@mysten/sui.js/client'; -import { Heading, Text } from '@mysten/ui'; +} from '@iota/core'; +import { useIotaClientQuery } from '@iota/dapp-kit'; +import { type IotaEvent, type IotaValidatorSummary } from '@iota/iota.js/client'; +import { Heading, Text } from '@iota/ui'; import { lazy, Suspense, useMemo } from 'react'; import { PageLayout } from '~/components/Layout/PageLayout'; @@ -35,9 +36,9 @@ import { VALIDATOR_LOW_STAKE_GRACE_PERIOD } from '~/utils/validatorConstants'; const ValidatorMap = lazy(() => import('../../components/validator-map')); export function validatorsTableData( - validators: SuiValidatorSummary[], + validators: IotaValidatorSummary[], atRiskValidators: [string, string][], - validatorEvents: SuiEvent[], + validatorEvents: IotaEvent[], rollingAverageApys: ApyByValidator | null, ) { return { @@ -45,19 +46,19 @@ export function validatorsTableData( .sort(() => 0.5 - Math.random()) .map((validator) => { const validatorName = validator.name; - const totalStake = validator.stakingPoolSuiBalance; + const totalStake = validator.stakingPoolIotaBalance; const img = validator.imageUrl; - const event = getValidatorMoveEvent(validatorEvents, validator.suiAddress) as { + const event = getValidatorMoveEvent(validatorEvents, validator.iotaAddress) as { pool_staking_reward?: string; }; const atRiskValidator = atRiskValidators.find( - ([address]) => address === validator.suiAddress, + ([address]) => address === validator.iotaAddress, ); const isAtRisk = !!atRiskValidator; const lastReward = event?.pool_staking_reward ?? null; - const { apy, isApyApproxZero } = rollingAverageApys?.[validator.suiAddress] ?? { + const { apy, isApyApproxZero } = rollingAverageApys?.[validator.iotaAddress] ?? { apy: null, }; @@ -74,7 +75,7 @@ export function validatorsTableData( nextEpochGasPrice: validator.nextEpochGasPrice, commission: Number(validator.commissionRate) / 100, img: img, - address: validator.suiAddress, + address: validator.iotaAddress, lastReward: lastReward ?? null, votingPower: Number(validator.votingPower) / 100, atRisk: isAtRisk @@ -140,7 +141,7 @@ export function validatorsTableData( header: 'Proposed Next Epoch Gas Price', accessorKey: 'nextEpochGasPrice', enableSorting: true, - cell: (props: any) => , + cell: (props: any) => , }, { header: 'APY', @@ -206,7 +207,7 @@ export function validatorsTableData( const label = 'At Risk'; return atRisk !== null ? ( ampli.activatedTooltip({ tooltipLabel: label, @@ -235,7 +236,7 @@ export function validatorsTableData( } function ValidatorPageResult() { - const { data, isPending, isSuccess, isError } = useSuiClientQuery('getLatestSuiSystemState'); + const { data, isPending, isSuccess, isError } = useIotaClientQuery('getLatestIotaSystemState'); const numberOfValidators = data?.activeValidators.length || 0; @@ -254,7 +255,7 @@ function ValidatorPageResult() { if (!data) return 0; const validators = data.activeValidators; - return validators.reduce((acc, cur) => acc + Number(cur.stakingPoolSuiBalance), 0); + return validators.reduce((acc, cur) => acc + Number(cur.stakingPoolIotaBalance), 0); }, [data]); const averageAPY = useMemo(() => { @@ -343,8 +344,8 @@ function ValidatorPageResult() {
; + if (coinMetadata?.symbol === 'IOTA') { + return ; } if (coinMetadata?.iconUrl) { @@ -28,9 +29,9 @@ export function Coin({ type }: { type: string }) { diff --git a/apps/explorer/src/ui/CopyToClipboard.tsx b/apps/explorer/src/ui/CopyToClipboard.tsx index c0c3cde3e5c..484dae631b3 100644 --- a/apps/explorer/src/ui/CopyToClipboard.tsx +++ b/apps/explorer/src/ui/CopyToClipboard.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useCopyToClipboard } from '@mysten/core'; -import { Check12, CheckStroke16, CheckStroke24, Copy12, Copy16, Copy24 } from '@mysten/icons'; +import { useCopyToClipboard } from '@iota/core'; +import { Check12, CheckStroke16, CheckStroke24, Copy12, Copy16, Copy24 } from '@iota/icons'; import { cva, type VariantProps } from 'class-variance-authority'; import { motion } from 'framer-motion'; import { useEffect, useState } from 'react'; diff --git a/apps/explorer/src/ui/DateCard.tsx b/apps/explorer/src/ui/DateCard.tsx index f38dae27156..e7dc1c452d8 100644 --- a/apps/explorer/src/ui/DateCard.tsx +++ b/apps/explorer/src/ui/DateCard.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { formatDate } from '@mysten/core'; -import { Text } from '@mysten/ui'; +import { formatDate } from '@iota/core'; +import { Text } from '@iota/ui'; export interface DateCardProps { date: Date | number; diff --git a/apps/explorer/src/ui/DateFilter.tsx b/apps/explorer/src/ui/DateFilter.tsx index b3b6731ba60..8b82c6d2a77 100644 --- a/apps/explorer/src/ui/DateFilter.tsx +++ b/apps/explorer/src/ui/DateFilter.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useState } from 'react'; diff --git a/apps/explorer/src/ui/Description.tsx b/apps/explorer/src/ui/Description.tsx index ec21f921607..f1a53b71cb0 100644 --- a/apps/explorer/src/ui/Description.tsx +++ b/apps/explorer/src/ui/Description.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Text, type TextProps } from '@mysten/ui'; +import { Text, type TextProps } from '@iota/ui'; import clsx from 'clsx'; import { type ReactNode } from 'react'; diff --git a/apps/explorer/src/ui/DescriptionList.tsx b/apps/explorer/src/ui/DescriptionList.tsx index e185ebb5af8..2c419a3e88b 100644 --- a/apps/explorer/src/ui/DescriptionList.tsx +++ b/apps/explorer/src/ui/DescriptionList.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { cva, type VariantProps } from 'class-variance-authority'; diff --git a/apps/explorer/src/ui/DisclosureBox.tsx b/apps/explorer/src/ui/DisclosureBox.tsx index 6f2d1757c8d..a690a149222 100644 --- a/apps/explorer/src/ui/DisclosureBox.tsx +++ b/apps/explorer/src/ui/DisclosureBox.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ChevronRight12 } from '@mysten/icons'; +import { ChevronRight12 } from '@iota/icons'; import * as Collapsible from '@radix-ui/react-collapsible'; import { cva, type VariantProps } from 'class-variance-authority'; import clsx from 'clsx'; diff --git a/apps/explorer/src/ui/Divider.tsx b/apps/explorer/src/ui/Divider.tsx index 6be7a2a0e06..a58722b5bd0 100644 --- a/apps/explorer/src/ui/Divider.tsx +++ b/apps/explorer/src/ui/Divider.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { cva, type VariantProps } from 'class-variance-authority'; diff --git a/apps/explorer/src/ui/DropdownMenu.tsx b/apps/explorer/src/ui/DropdownMenu.tsx index 47e0abeabcd..ef82e59d917 100644 --- a/apps/explorer/src/ui/DropdownMenu.tsx +++ b/apps/explorer/src/ui/DropdownMenu.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Text, Toggle } from '@mysten/ui'; +import { Text, Toggle } from '@iota/ui'; import * as RadixDropdownMenu from '@radix-ui/react-dropdown-menu'; import { type ReactNode } from 'react'; @@ -47,7 +48,7 @@ export function DropdownMenuCheckboxItem({ }: DropdownMenuCheckboxItemProps) { return ( -
+
Show System Transactions
diff --git a/apps/explorer/src/ui/ExpandableList.tsx b/apps/explorer/src/ui/ExpandableList.tsx index d38082347fb..52acc13f54a 100644 --- a/apps/explorer/src/ui/ExpandableList.tsx +++ b/apps/explorer/src/ui/ExpandableList.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ChevronUp12 } from '@mysten/icons'; -import { Text } from '@mysten/ui'; +import { ChevronUp12 } from '@iota/icons'; +import { Text } from '@iota/ui'; import clsx from 'clsx'; import { type ReactNode, useMemo, useState, createContext, useContext } from 'react'; diff --git a/apps/explorer/src/ui/FilterList.tsx b/apps/explorer/src/ui/FilterList.tsx index 20f307c47b2..1d70d05c22d 100644 --- a/apps/explorer/src/ui/FilterList.tsx +++ b/apps/explorer/src/ui/FilterList.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // TODO: This component really shouldn't use the `Tabs` component, it should just use radix, diff --git a/apps/explorer/src/ui/ImageIcon.tsx b/apps/explorer/src/ui/ImageIcon.tsx index 43c9b72bb01..c3f67d1d57a 100644 --- a/apps/explorer/src/ui/ImageIcon.tsx +++ b/apps/explorer/src/ui/ImageIcon.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { cva, type VariantProps } from 'class-variance-authority'; diff --git a/apps/explorer/src/ui/Input.tsx b/apps/explorer/src/ui/Input.tsx index e61c1460930..d87351328cc 100644 --- a/apps/explorer/src/ui/Input.tsx +++ b/apps/explorer/src/ui/Input.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { forwardRef } from 'react'; diff --git a/apps/explorer/src/ui/InternalLink.tsx b/apps/explorer/src/ui/InternalLink.tsx index 534c2b587bd..251c7adcc5e 100644 --- a/apps/explorer/src/ui/InternalLink.tsx +++ b/apps/explorer/src/ui/InternalLink.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { isSuiNSName } from '@mysten/core'; -import { formatAddress, formatDigest } from '@mysten/sui.js/utils'; +import { isIotaNSName } from '@iota/core'; +import { formatAddress, formatDigest } from '@iota/iota.js/utils'; import { type ReactNode } from 'react'; import { Link, type LinkProps } from '~/ui/Link'; @@ -41,7 +42,7 @@ export const EpochLink = createInternalLink('epoch', 'epoch'); export const CheckpointLink = createInternalLink('checkpoint', 'digest', formatAddress); export const CheckpointSequenceLink = createInternalLink('checkpoint', 'sequence'); export const AddressLink = createInternalLink('address', 'address', (addressOrNs) => { - if (isSuiNSName(addressOrNs)) { + if (isIotaNSName(addressOrNs)) { return addressOrNs; } return formatAddress(addressOrNs); diff --git a/apps/explorer/src/ui/Link.tsx b/apps/explorer/src/ui/Link.tsx index f4f974cf97c..62dea72cd56 100644 --- a/apps/explorer/src/ui/Link.tsx +++ b/apps/explorer/src/ui/Link.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { cva, type VariantProps } from 'class-variance-authority'; diff --git a/apps/explorer/src/ui/ListboxSelect.tsx b/apps/explorer/src/ui/ListboxSelect.tsx index c8c78ae85f0..c50e9e3cf37 100644 --- a/apps/explorer/src/ui/ListboxSelect.tsx +++ b/apps/explorer/src/ui/ListboxSelect.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Listbox, Transition } from '@headlessui/react'; -import { Check12, ChevronDown16 } from '@mysten/icons'; -import { Text } from '@mysten/ui'; +import { Check12, ChevronDown16 } from '@iota/icons'; +import { Text } from '@iota/ui'; import { Fragment } from 'react'; export type ListboxSelectPros = { @@ -36,7 +37,7 @@ export function ListboxSelect({ {options.map((aValue, index) => ( {({ selected }) => ( diff --git a/apps/explorer/src/ui/Modal/ObjectModal.tsx b/apps/explorer/src/ui/Modal/ObjectModal.tsx index 559c9328bc3..a0d8c965a96 100644 --- a/apps/explorer/src/ui/Modal/ObjectModal.tsx +++ b/apps/explorer/src/ui/Modal/ObjectModal.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { X12 } from '@mysten/icons'; -import { Text, Heading, IconButton } from '@mysten/ui'; +import { X12 } from '@iota/icons'; +import { Text, Heading, IconButton } from '@iota/ui'; import { Modal, type ModalProps } from './index'; import { Image } from '../image/Image'; @@ -37,7 +38,7 @@ export function ObjectModal({ {alt} )}
- + {title} @@ -48,7 +49,7 @@ export function ObjectModal({
diff --git a/apps/explorer/src/ui/Modal/index.tsx b/apps/explorer/src/ui/Modal/index.tsx index c4377fb76b4..e78160b046d 100644 --- a/apps/explorer/src/ui/Modal/index.tsx +++ b/apps/explorer/src/ui/Modal/index.tsx @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Dialog, Transition } from '@headlessui/react'; -import { X12 } from '@mysten/icons'; -import { Heading } from '@mysten/ui'; +import { X12 } from '@iota/icons'; +import { Heading } from '@iota/ui'; import { Fragment, type ReactNode } from 'react'; export interface ModalProps { diff --git a/apps/explorer/src/ui/ObjectDetails.tsx b/apps/explorer/src/ui/ObjectDetails.tsx index 1b3f101e748..f70fc10face 100644 --- a/apps/explorer/src/ui/ObjectDetails.tsx +++ b/apps/explorer/src/ui/ObjectDetails.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ArrowUpRight16 } from '@mysten/icons'; -import { Text, Heading } from '@mysten/ui'; +import { ArrowUpRight16 } from '@iota/icons'; +import { Text, Heading } from '@iota/ui'; import { cva } from 'class-variance-authority'; import { useState } from 'react'; diff --git a/apps/explorer/src/ui/ObjectVideoImage.tsx b/apps/explorer/src/ui/ObjectVideoImage.tsx index 0770c05d089..6d838633c12 100644 --- a/apps/explorer/src/ui/ObjectVideoImage.tsx +++ b/apps/explorer/src/ui/ObjectVideoImage.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { MediaPlay16 } from '@mysten/icons'; +import { MediaPlay16 } from '@iota/icons'; import { cva, type VariantProps } from 'class-variance-authority'; import clsx from 'clsx'; diff --git a/apps/explorer/src/ui/PageHeader.tsx b/apps/explorer/src/ui/PageHeader.tsx index 93fc2febd09..d5c5ceaf52c 100644 --- a/apps/explorer/src/ui/PageHeader.tsx +++ b/apps/explorer/src/ui/PageHeader.tsx @@ -1,11 +1,9 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Flag16, Info12 } from '@mysten/icons'; -import { Heading, Placeholder, Text } from '@mysten/ui'; +import { Flag16, Info12 } from '@iota/icons'; +import { Heading, Placeholder, Text } from '@iota/ui'; import { ReactComponent as CallIcon } from './icons/transactions/call.svg'; import { Banner } from '~/ui/Banner'; diff --git a/apps/explorer/src/ui/Pagination.tsx b/apps/explorer/src/ui/Pagination.tsx index 441cdedcaa7..b4f24d08c4f 100644 --- a/apps/explorer/src/ui/Pagination.tsx +++ b/apps/explorer/src/ui/Pagination.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { PaginationFirst24, PaginationNext24, PaginationPrev24 } from '@mysten/icons'; +import { PaginationFirst24, PaginationNext24, PaginationPrev24 } from '@iota/icons'; import { type InfiniteData, type UseInfiniteQueryResult } from '@tanstack/react-query'; import { useState } from 'react'; diff --git a/apps/explorer/src/ui/PlaceholderTable.tsx b/apps/explorer/src/ui/PlaceholderTable.tsx index 5098f8d0625..661ce3f778b 100644 --- a/apps/explorer/src/ui/PlaceholderTable.tsx +++ b/apps/explorer/src/ui/PlaceholderTable.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Placeholder } from '@mysten/ui'; +import { Placeholder } from '@iota/ui'; import { useMemo } from 'react'; import { TableCard } from './TableCard'; diff --git a/apps/explorer/src/ui/PlayPause.tsx b/apps/explorer/src/ui/PlayPause.tsx index f195fd11922..49355f5853a 100644 --- a/apps/explorer/src/ui/PlayPause.tsx +++ b/apps/explorer/src/ui/PlayPause.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { AutorefreshPause24, AutorefreshPlay24 } from '@mysten/icons'; +import { AutorefreshPause24, AutorefreshPlay24 } from '@iota/icons'; import { motion } from 'framer-motion'; import { useEffect } from 'react'; diff --git a/apps/explorer/src/ui/ProgressBar.tsx b/apps/explorer/src/ui/ProgressBar.tsx index 65220684815..4d7aeaf2261 100644 --- a/apps/explorer/src/ui/ProgressBar.tsx +++ b/apps/explorer/src/ui/ProgressBar.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import clsx from 'clsx'; diff --git a/apps/explorer/src/ui/ProgressCircle.tsx b/apps/explorer/src/ui/ProgressCircle.tsx index 42f8334f741..918b5bc0404 100644 --- a/apps/explorer/src/ui/ProgressCircle.tsx +++ b/apps/explorer/src/ui/ProgressCircle.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { motion } from 'framer-motion'; diff --git a/apps/explorer/src/ui/RingChart.tsx b/apps/explorer/src/ui/RingChart.tsx index a6d920f8f9f..ab1c08c0845 100644 --- a/apps/explorer/src/ui/RingChart.tsx +++ b/apps/explorer/src/ui/RingChart.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Heading } from '@mysten/ui'; +import { Heading } from '@iota/ui'; import clsx from 'clsx'; import { Fragment } from 'react'; @@ -125,7 +126,7 @@ export function RingChart({ data }: RingChartProps) {
- + {total}
diff --git a/apps/explorer/src/ui/Search.tsx b/apps/explorer/src/ui/Search.tsx index eeba1b960db..cc371025d65 100644 --- a/apps/explorer/src/ui/Search.tsx +++ b/apps/explorer/src/ui/Search.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Search16 } from '@mysten/icons'; -import { Text, Combobox, ComboboxInput, ComboboxList } from '@mysten/ui'; +import { Search16 } from '@iota/icons'; +import { Text, Combobox, ComboboxInput, ComboboxList } from '@iota/ui'; export type SearchResult = { id: string; diff --git a/apps/explorer/src/ui/SplitPanes.tsx b/apps/explorer/src/ui/SplitPanes.tsx index 6d0f709f9da..a3a656fb314 100644 --- a/apps/explorer/src/ui/SplitPanes.tsx +++ b/apps/explorer/src/ui/SplitPanes.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ChevronLeft12, ChevronUp12 } from '@mysten/icons'; +import { ChevronLeft12, ChevronUp12 } from '@iota/icons'; import { cva, type VariantProps } from 'class-variance-authority'; import clsx from 'clsx'; import { type ReactNode, useRef, useState } from 'react'; diff --git a/apps/explorer/src/ui/StatAmount.tsx b/apps/explorer/src/ui/StatAmount.tsx index 0b2cd222db8..1b43feb6dc2 100644 --- a/apps/explorer/src/ui/StatAmount.tsx +++ b/apps/explorer/src/ui/StatAmount.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Heading, Text } from '@mysten/ui'; +import { Heading, Text } from '@iota/ui'; import { Amount, type AmountProps } from '~/ui/Amount'; import { DateCard } from '~/ui/DateCard'; diff --git a/apps/explorer/src/ui/Stats.tsx b/apps/explorer/src/ui/Stats.tsx index cf8ef7ee933..3fb515acb2b 100644 --- a/apps/explorer/src/ui/Stats.tsx +++ b/apps/explorer/src/ui/Stats.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Heading, Text } from '@mysten/ui'; +import { Heading, Text } from '@iota/ui'; import clsx from 'clsx'; import { ReactComponent as InfoSvg } from './icons/info_10x10.svg'; diff --git a/apps/explorer/src/ui/StatusIcon.tsx b/apps/explorer/src/ui/StatusIcon.tsx index da619bdd547..5a3cad38cbb 100644 --- a/apps/explorer/src/ui/StatusIcon.tsx +++ b/apps/explorer/src/ui/StatusIcon.tsx @@ -1,6 +1,7 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ThumbUpFill24, ThumbDownFill24 } from '@mysten/icons'; +import { ThumbUpFill24, ThumbDownFill24 } from '@iota/icons'; import clsx from 'clsx'; export function StatusIcon({ success }: { success: boolean }) { diff --git a/apps/explorer/src/ui/TableCard.tsx b/apps/explorer/src/ui/TableCard.tsx index 89ec3838bd9..0616c715c2c 100644 --- a/apps/explorer/src/ui/TableCard.tsx +++ b/apps/explorer/src/ui/TableCard.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ArrowRight12 } from '@mysten/icons'; +import { ArrowRight12 } from '@iota/icons'; import { type ColumnDef, flexRender, diff --git a/apps/explorer/src/ui/TableHeader.tsx b/apps/explorer/src/ui/TableHeader.tsx index 5a189e7011e..83ddfba50d7 100644 --- a/apps/explorer/src/ui/TableHeader.tsx +++ b/apps/explorer/src/ui/TableHeader.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Heading, type HeadingProps } from '@mysten/ui'; +import { Heading, type HeadingProps } from '@iota/ui'; import { type ReactNode } from 'react'; export interface TableHeaderProps extends Pick { diff --git a/apps/explorer/src/ui/Tabs.tsx b/apps/explorer/src/ui/Tabs.tsx index 8ed8d92b4e4..c2afb068483 100644 --- a/apps/explorer/src/ui/Tabs.tsx +++ b/apps/explorer/src/ui/Tabs.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import * as TabsPrimitive from '@radix-ui/react-tabs'; diff --git a/apps/explorer/src/ui/Tooltip.tsx b/apps/explorer/src/ui/Tooltip.tsx index 7c27d9a2900..b6e0d8c2487 100644 --- a/apps/explorer/src/ui/Tooltip.tsx +++ b/apps/explorer/src/ui/Tooltip.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { diff --git a/apps/explorer/src/ui/VerticalList.tsx b/apps/explorer/src/ui/VerticalList.tsx index 2cb88f3e10d..9e07b6a4dcc 100644 --- a/apps/explorer/src/ui/VerticalList.tsx +++ b/apps/explorer/src/ui/VerticalList.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import clsx from 'clsx'; diff --git a/apps/explorer/src/ui/collapsible/CollapsibleCard.tsx b/apps/explorer/src/ui/collapsible/CollapsibleCard.tsx index 925a095c82c..92c2e33f45a 100644 --- a/apps/explorer/src/ui/collapsible/CollapsibleCard.tsx +++ b/apps/explorer/src/ui/collapsible/CollapsibleCard.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ChevronRight16 } from '@mysten/icons'; -import { Heading } from '@mysten/ui'; +import { ChevronRight16 } from '@iota/icons'; +import { Heading } from '@iota/ui'; import * as Collapsible from '@radix-ui/react-collapsible'; import clsx from 'clsx'; import { type ReactNode, useState } from 'react'; @@ -121,7 +122,7 @@ export function CollapsibleCard({ {footer && (
diff --git a/apps/explorer/src/ui/collapsible/CollapsibleSection.tsx b/apps/explorer/src/ui/collapsible/CollapsibleSection.tsx index 56eee4c220f..0bedee96b81 100644 --- a/apps/explorer/src/ui/collapsible/CollapsibleSection.tsx +++ b/apps/explorer/src/ui/collapsible/CollapsibleSection.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ChevronRight12 } from '@mysten/icons'; -import { Text } from '@mysten/ui'; +import { ChevronRight12 } from '@iota/icons'; +import { Text } from '@iota/ui'; import * as Collapsible from '@radix-ui/react-collapsible'; import clsx from 'clsx'; import { type ReactNode, useState } from 'react'; diff --git a/apps/explorer/src/ui/header/NavItem.tsx b/apps/explorer/src/ui/header/NavItem.tsx index d23f90c5f5d..dad5ed1180b 100644 --- a/apps/explorer/src/ui/header/NavItem.tsx +++ b/apps/explorer/src/ui/header/NavItem.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { forwardRef, type ComponentProps, type ReactNode } from 'react'; diff --git a/apps/explorer/src/ui/header/NetworkSelect.tsx b/apps/explorer/src/ui/header/NetworkSelect.tsx index 2eaea13de9b..5331b9ba123 100644 --- a/apps/explorer/src/ui/header/NetworkSelect.tsx +++ b/apps/explorer/src/ui/header/NetworkSelect.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /** @@ -10,9 +11,9 @@ import { autoUpdate, flip, FloatingPortal, offset, shift, useFloating } from '@floating-ui/react'; import { Popover } from '@headlessui/react'; -import { useZodForm } from '@mysten/core'; -import { HamburgerRest16 } from '@mysten/icons'; -import { Text } from '@mysten/ui'; +import { useZodForm } from '@iota/core'; +import { HamburgerRest16 } from '@iota/icons'; +import { Text } from '@iota/ui'; import clsx from 'clsx'; import { AnimatePresence, motion } from 'framer-motion'; import { useEffect, useState } from 'react'; @@ -143,7 +144,7 @@ function NetworkVersion({ return (
- Sui {label} + Iota {label} v{binaryVersion} (Protocol {version}) diff --git a/apps/explorer/src/ui/icons/transactions/transferSui.svg b/apps/explorer/src/ui/icons/transactions/transferIota.svg similarity index 100% rename from apps/explorer/src/ui/icons/transactions/transferSui.svg rename to apps/explorer/src/ui/icons/transactions/transferIota.svg diff --git a/apps/explorer/src/ui/image/Image.tsx b/apps/explorer/src/ui/image/Image.tsx index 742ce2a85c6..22d20178267 100644 --- a/apps/explorer/src/ui/image/Image.tsx +++ b/apps/explorer/src/ui/image/Image.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { EyeClose16, NftTypeImage24 } from '@mysten/icons'; -import { LoadingIndicator } from '@mysten/ui'; +import { EyeClose16, NftTypeImage24 } from '@iota/icons'; +import { LoadingIndicator } from '@iota/ui'; import { cva, cx, type VariantProps } from 'class-variance-authority'; import clsx from 'clsx'; import { useAnimate } from 'framer-motion'; diff --git a/apps/explorer/src/ui/stories/Amount.stories.tsx b/apps/explorer/src/ui/stories/Amount.stories.tsx index 60c4af27669..7639f632860 100644 --- a/apps/explorer/src/ui/stories/Amount.stories.tsx +++ b/apps/explorer/src/ui/stories/Amount.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; @@ -12,7 +13,7 @@ export default { export const Default: StoryObj = { args: { amount: 1000, - symbol: 'SUI', + symbol: 'IOTA', }, }; diff --git a/apps/explorer/src/ui/stories/Badge.stories.tsx b/apps/explorer/src/ui/stories/Badge.stories.tsx index 6131a8a4b3c..93e166fe7a9 100644 --- a/apps/explorer/src/ui/stories/Badge.stories.tsx +++ b/apps/explorer/src/ui/stories/Badge.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/Banner.stories.tsx b/apps/explorer/src/ui/stories/Banner.stories.tsx index e885b729d5d..f0d387aac0b 100644 --- a/apps/explorer/src/ui/stories/Banner.stories.tsx +++ b/apps/explorer/src/ui/stories/Banner.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/Card.stories.tsx b/apps/explorer/src/ui/stories/Card.stories.tsx index 49d8e7f354e..0d936f6420b 100644 --- a/apps/explorer/src/ui/stories/Card.stories.tsx +++ b/apps/explorer/src/ui/stories/Card.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/CoinBalance.stories.tsx b/apps/explorer/src/ui/stories/CoinBalance.stories.tsx index ff6ee9338ba..eda5cca1382 100644 --- a/apps/explorer/src/ui/stories/CoinBalance.stories.tsx +++ b/apps/explorer/src/ui/stories/CoinBalance.stories.tsx @@ -1,25 +1,26 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiClientProvider } from '@mysten/dapp-kit'; +import { IotaClientProvider } from '@iota/dapp-kit'; import { type Meta, type StoryObj } from '@storybook/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { CoinBalance, type CoinBalanceProps } from '../CoinBalance'; -import { Network, SupportedNetworks, createSuiClient } from '~/utils/api/DefaultRpcClient'; +import { Network, SupportedNetworks, createIotaClient } from '~/utils/api/DefaultRpcClient'; export default { component: CoinBalance, decorators: [ (Story) => ( - - + ), ], @@ -28,7 +29,7 @@ export default { export const Default: StoryObj = { args: { amount: 1000, - coinType: '0x2::sui::SUI', + coinType: '0x2::iota::IOTA', }, }; diff --git a/apps/explorer/src/ui/stories/CoinsStack.stories.tsx b/apps/explorer/src/ui/stories/CoinsStack.stories.tsx index 01fae832fcf..64cf7e657fe 100644 --- a/apps/explorer/src/ui/stories/CoinsStack.stories.tsx +++ b/apps/explorer/src/ui/stories/CoinsStack.stories.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiClientProvider } from '@mysten/dapp-kit'; +import { IotaClientProvider } from '@iota/dapp-kit'; import { type Meta, type StoryObj } from '@storybook/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; @@ -12,9 +13,9 @@ export default { decorators: [ (Story) => ( - + - + ), ], @@ -23,8 +24,8 @@ export default { export const Default: StoryObj = { args: { coinTypes: [ - '0x2::sui::SUI', - '0xc0d761079b1e7fa4dbd8a881b7464cf8c400c0de72460fdf8ca44e3f1842715e::sui_inu::SUI_INU', + '0x2::iota::IOTA', + '0xc0d761079b1e7fa4dbd8a881b7464cf8c400c0de72460fdf8ca44e3f1842715e::iota_inu::IOTA_INU', 'random', ], }, diff --git a/apps/explorer/src/ui/stories/CollapsibleCard.stories.tsx b/apps/explorer/src/ui/stories/CollapsibleCard.stories.tsx index 75ef74b8614..cfca567d7b9 100644 --- a/apps/explorer/src/ui/stories/CollapsibleCard.stories.tsx +++ b/apps/explorer/src/ui/stories/CollapsibleCard.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/CopyToClipboard.stories.tsx b/apps/explorer/src/ui/stories/CopyToClipboard.stories.tsx index 7cc0d74cad3..bc246708a40 100644 --- a/apps/explorer/src/ui/stories/CopyToClipboard.stories.tsx +++ b/apps/explorer/src/ui/stories/CopyToClipboard.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Toaster } from 'react-hot-toast'; diff --git a/apps/explorer/src/ui/stories/DateCard.stories.tsx b/apps/explorer/src/ui/stories/DateCard.stories.tsx index 1abbafd1cd4..9b0c19f4594 100644 --- a/apps/explorer/src/ui/stories/DateCard.stories.tsx +++ b/apps/explorer/src/ui/stories/DateCard.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/DateFilter.stories.tsx b/apps/explorer/src/ui/stories/DateFilter.stories.tsx index 1c426dbacb5..2492f0aa7f2 100644 --- a/apps/explorer/src/ui/stories/DateFilter.stories.tsx +++ b/apps/explorer/src/ui/stories/DateFilter.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/DescriptionList.stories.tsx b/apps/explorer/src/ui/stories/DescriptionList.stories.tsx index b0328d050c8..8ccf35ca070 100644 --- a/apps/explorer/src/ui/stories/DescriptionList.stories.tsx +++ b/apps/explorer/src/ui/stories/DescriptionList.stories.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Text } from '@mysten/ui'; +import { Text } from '@iota/ui'; import { type Meta, type StoryObj } from '@storybook/react'; import { MemoryRouter } from 'react-router-dom'; diff --git a/apps/explorer/src/ui/stories/DisclosureBox.stories.tsx b/apps/explorer/src/ui/stories/DisclosureBox.stories.tsx index cd24a3c1d6f..78b8183fb50 100644 --- a/apps/explorer/src/ui/stories/DisclosureBox.stories.tsx +++ b/apps/explorer/src/ui/stories/DisclosureBox.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/Divider.stories.tsx b/apps/explorer/src/ui/stories/Divider.stories.tsx index 94e73efcb50..70fd13d3e46 100644 --- a/apps/explorer/src/ui/stories/Divider.stories.tsx +++ b/apps/explorer/src/ui/stories/Divider.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Divider, type DividerProps } from '~/ui/Divider'; @@ -16,9 +17,9 @@ export const Horizontal: StoryObj = { export const Vertical: StoryObj = { render: () => (
-
+
-
+
), }; diff --git a/apps/explorer/src/ui/stories/DropdownMenu.stories.tsx b/apps/explorer/src/ui/stories/DropdownMenu.stories.tsx index 1f634bf6c4d..b962e0521f1 100644 --- a/apps/explorer/src/ui/stories/DropdownMenu.stories.tsx +++ b/apps/explorer/src/ui/stories/DropdownMenu.stories.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Filter16 } from '@mysten/icons'; +import { Filter16 } from '@iota/icons'; import { type Meta, type StoryObj } from '@storybook/react'; import { useState } from 'react'; diff --git a/apps/explorer/src/ui/stories/ExpandableList.stories.tsx b/apps/explorer/src/ui/stories/ExpandableList.stories.tsx index 9e41fc62c77..994dee0c50e 100644 --- a/apps/explorer/src/ui/stories/ExpandableList.stories.tsx +++ b/apps/explorer/src/ui/stories/ExpandableList.stories.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Text } from '@mysten/ui'; +import { Text } from '@iota/ui'; import { type ReactNode } from 'react'; import { ExpandableList } from '../ExpandableList'; diff --git a/apps/explorer/src/ui/stories/FilterList.stories.tsx b/apps/explorer/src/ui/stories/FilterList.stories.tsx index e4e6852ca4e..1c8d42f04a3 100644 --- a/apps/explorer/src/ui/stories/FilterList.stories.tsx +++ b/apps/explorer/src/ui/stories/FilterList.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; @@ -16,7 +17,7 @@ export const Default: StoryObj = { return ; }, args: { - options: ['MINT', 'SUI'], + options: ['MINT', 'IOTA'], disabled: false, size: 'sm', lessSpacing: true, diff --git a/apps/explorer/src/ui/stories/Image.stories.tsx b/apps/explorer/src/ui/stories/Image.stories.tsx index d0ec52f876a..a62e0503d38 100644 --- a/apps/explorer/src/ui/stories/Image.stories.tsx +++ b/apps/explorer/src/ui/stories/Image.stories.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiClientProvider } from '@mysten/dapp-kit'; +import { IotaClientProvider } from '@iota/dapp-kit'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { MemoryRouter } from 'react-router-dom'; @@ -16,9 +17,9 @@ export default { (Story) => ( - + - + ), diff --git a/apps/explorer/src/ui/stories/ImageIcon.stories.tsx b/apps/explorer/src/ui/stories/ImageIcon.stories.tsx index 12278ec2b61..1586534a7b2 100644 --- a/apps/explorer/src/ui/stories/ImageIcon.stories.tsx +++ b/apps/explorer/src/ui/stories/ImageIcon.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { ImageIcon, type ImageIconProps } from '../ImageIcon'; @@ -20,8 +21,8 @@ export const extraLargeImage: StoryObj = { export const largeIconNoImage: StoryObj = { args: { src: null, - fallback: 'Sui', - label: 'Sui', + fallback: 'Iota', + label: 'Iota', size: 'lg', }, }; @@ -29,8 +30,8 @@ export const largeIconNoImage: StoryObj = { export const smallIconImage: StoryObj = { args: { src: 'https://ipfs.io/ipfs/QmZPWWy5Si54R3d26toaqRiqvCH7HkGdXkxwUgCm2oKKM2?filename=img-sq-01.png', - label: 'Sui', + label: 'Iota', size: 'sm', - fallback: 'Sui', + fallback: 'Iota', }, }; diff --git a/apps/explorer/src/ui/stories/Input.stories.tsx b/apps/explorer/src/ui/stories/Input.stories.tsx index acc069a6f9a..6918df95ec8 100644 --- a/apps/explorer/src/ui/stories/Input.stories.tsx +++ b/apps/explorer/src/ui/stories/Input.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Input, type InputProps } from '../Input'; diff --git a/apps/explorer/src/ui/stories/Link.stories.tsx b/apps/explorer/src/ui/stories/Link.stories.tsx index 8de38392bb2..3239a6c317f 100644 --- a/apps/explorer/src/ui/stories/Link.stories.tsx +++ b/apps/explorer/src/ui/stories/Link.stories.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { CheckFill16, Search16 } from '@mysten/icons'; +import { CheckFill16, Search16 } from '@iota/icons'; import { type Meta, type StoryObj } from '@storybook/react'; import { Link, type LinkProps } from '../Link'; diff --git a/apps/explorer/src/ui/stories/ListboxSelect.stories.tsx b/apps/explorer/src/ui/stories/ListboxSelect.stories.tsx index e5fadf28bd6..6211b4d3319 100644 --- a/apps/explorer/src/ui/stories/ListboxSelect.stories.tsx +++ b/apps/explorer/src/ui/stories/ListboxSelect.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/Modal.stories.tsx b/apps/explorer/src/ui/stories/Modal.stories.tsx index 77ad1d860aa..ef17cafd354 100644 --- a/apps/explorer/src/ui/stories/Modal.stories.tsx +++ b/apps/explorer/src/ui/stories/Modal.stories.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiClientProvider } from '@mysten/dapp-kit'; +import { IotaClientProvider } from '@iota/dapp-kit'; import { type Meta, type StoryObj } from '@storybook/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { useState } from 'react'; @@ -40,9 +41,9 @@ export default { (Story) => ( - + - + ), @@ -60,10 +61,10 @@ export const Image: StoryObj = { return (
setOpen(false)} subtitle="Still water runs deep." /> @@ -81,11 +82,11 @@ export const Video: StoryObj = { return (
setOpen(false)} subtitle="Still water runs deep." /> diff --git a/apps/explorer/src/ui/stories/ObjectDetails.stories.tsx b/apps/explorer/src/ui/stories/ObjectDetails.stories.tsx index fb31b55fd4a..e50d2967814 100644 --- a/apps/explorer/src/ui/stories/ObjectDetails.stories.tsx +++ b/apps/explorer/src/ui/stories/ObjectDetails.stories.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiClientProvider } from '@mysten/dapp-kit'; +import { IotaClientProvider } from '@iota/dapp-kit'; import { type Meta, type StoryObj } from '@storybook/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { MemoryRouter } from 'react-router-dom'; @@ -14,9 +15,9 @@ export default { (Story) => ( - + - + ), diff --git a/apps/explorer/src/ui/stories/PageHeader.stories.tsx b/apps/explorer/src/ui/stories/PageHeader.stories.tsx index 758fe22ca75..ff3f85feaa7 100644 --- a/apps/explorer/src/ui/stories/PageHeader.stories.tsx +++ b/apps/explorer/src/ui/stories/PageHeader.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type StoryObj, type Meta } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/Pagination.stories.tsx b/apps/explorer/src/ui/stories/Pagination.stories.tsx index a6fdbcdb76c..f7d847efce4 100644 --- a/apps/explorer/src/ui/stories/Pagination.stories.tsx +++ b/apps/explorer/src/ui/stories/Pagination.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type StoryObj, type Meta } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/PlaceholderTable.stories.tsx b/apps/explorer/src/ui/stories/PlaceholderTable.stories.tsx index 09f1f1fd1c8..f004b021761 100644 --- a/apps/explorer/src/ui/stories/PlaceholderTable.stories.tsx +++ b/apps/explorer/src/ui/stories/PlaceholderTable.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type StoryObj, type Meta } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/PlayPause.stories.tsx b/apps/explorer/src/ui/stories/PlayPause.stories.tsx index fe069b9df32..c6ad24ea94b 100644 --- a/apps/explorer/src/ui/stories/PlayPause.stories.tsx +++ b/apps/explorer/src/ui/stories/PlayPause.stories.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Button } from '@mysten/ui'; +import { Button } from '@iota/ui'; import { type Meta, type StoryObj } from '@storybook/react'; import { useState } from 'react'; diff --git a/apps/explorer/src/ui/stories/ProgressBar.stories.tsx b/apps/explorer/src/ui/stories/ProgressBar.stories.tsx index 875b6c2897e..627d8b2e482 100644 --- a/apps/explorer/src/ui/stories/ProgressBar.stories.tsx +++ b/apps/explorer/src/ui/stories/ProgressBar.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/ProgressCircle.stories.tsx b/apps/explorer/src/ui/stories/ProgressCircle.stories.tsx index 9076d6cdc65..63534df7baf 100644 --- a/apps/explorer/src/ui/stories/ProgressCircle.stories.tsx +++ b/apps/explorer/src/ui/stories/ProgressCircle.stories.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Text } from '@mysten/ui'; +import { Text } from '@iota/ui'; import { type Meta, type StoryObj } from '@storybook/react'; import { ProgressCircle, type ProgressCircleProps } from '../ProgressCircle'; diff --git a/apps/explorer/src/ui/stories/RingChart.stories.tsx b/apps/explorer/src/ui/stories/RingChart.stories.tsx index 5cdbc7ce260..93cf3453904 100644 --- a/apps/explorer/src/ui/stories/RingChart.stories.tsx +++ b/apps/explorer/src/ui/stories/RingChart.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/Search.stories.tsx b/apps/explorer/src/ui/stories/Search.stories.tsx index ae3a3280293..30249783aee 100644 --- a/apps/explorer/src/ui/stories/Search.stories.tsx +++ b/apps/explorer/src/ui/stories/Search.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/SplitPanes.stories.tsx b/apps/explorer/src/ui/stories/SplitPanes.stories.tsx index 0a0a5c59398..eddca2c66d6 100644 --- a/apps/explorer/src/ui/stories/SplitPanes.stories.tsx +++ b/apps/explorer/src/ui/stories/SplitPanes.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; @@ -34,7 +35,7 @@ const splitPanels = [ }, { panel: ( -
+
Third
), diff --git a/apps/explorer/src/ui/stories/StatAmount.stories.tsx b/apps/explorer/src/ui/stories/StatAmount.stories.tsx index 484bf62880b..bc3b25c80da 100644 --- a/apps/explorer/src/ui/stories/StatAmount.stories.tsx +++ b/apps/explorer/src/ui/stories/StatAmount.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; @@ -12,7 +13,7 @@ export default { export const defaultAmount: StoryObj = { args: { amount: 9740991, - symbol: 'SUI', + symbol: 'IOTA', dollarAmount: 123.56, date: 1667942429177, }, diff --git a/apps/explorer/src/ui/stories/Stats.stories.tsx b/apps/explorer/src/ui/stories/Stats.stories.tsx index ac1f17a200d..950ab3cb0dd 100644 --- a/apps/explorer/src/ui/stories/Stats.stories.tsx +++ b/apps/explorer/src/ui/stories/Stats.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/TableCard.stories.tsx b/apps/explorer/src/ui/stories/TableCard.stories.tsx index c32d675ee8e..62de0b92bb5 100644 --- a/apps/explorer/src/ui/stories/TableCard.stories.tsx +++ b/apps/explorer/src/ui/stories/TableCard.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type StoryObj, type Meta } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/TableHeader.stories.tsx b/apps/explorer/src/ui/stories/TableHeader.stories.tsx index 4aad9385d93..e5817352891 100644 --- a/apps/explorer/src/ui/stories/TableHeader.stories.tsx +++ b/apps/explorer/src/ui/stories/TableHeader.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/Tabs.stories.tsx b/apps/explorer/src/ui/stories/Tabs.stories.tsx index 65e679e0eee..22bd555afa7 100644 --- a/apps/explorer/src/ui/stories/Tabs.stories.tsx +++ b/apps/explorer/src/ui/stories/Tabs.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/Tooltip.stories.tsx b/apps/explorer/src/ui/stories/Tooltip.stories.tsx index 0bd115246ba..8e625caf7c6 100644 --- a/apps/explorer/src/ui/stories/Tooltip.stories.tsx +++ b/apps/explorer/src/ui/stories/Tooltip.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/VerticalList.stories.tsx b/apps/explorer/src/ui/stories/VerticalList.stories.tsx index c7098606f22..c1b4cb92990 100644 --- a/apps/explorer/src/ui/stories/VerticalList.stories.tsx +++ b/apps/explorer/src/ui/stories/VerticalList.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/header/NavItem.stories.tsx b/apps/explorer/src/ui/stories/header/NavItem.stories.tsx index 585d85a5eea..76f2d999f9a 100644 --- a/apps/explorer/src/ui/stories/header/NavItem.stories.tsx +++ b/apps/explorer/src/ui/stories/header/NavItem.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/stories/header/NetworkSelect.stories.tsx b/apps/explorer/src/ui/stories/header/NetworkSelect.stories.tsx index 2e8e68ef552..8f073b0acc0 100644 --- a/apps/explorer/src/ui/stories/header/NetworkSelect.stories.tsx +++ b/apps/explorer/src/ui/stories/header/NetworkSelect.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/explorer/src/ui/types.ts b/apps/explorer/src/ui/types.ts index 2ec00b8e225..3bfa813df32 100644 --- a/apps/explorer/src/ui/types.ts +++ b/apps/explorer/src/ui/types.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type ComponentType } from 'react'; diff --git a/apps/explorer/src/ui/utils/ButtonOrLink.tsx b/apps/explorer/src/ui/utils/ButtonOrLink.tsx index dbe92826742..5452f25b398 100644 --- a/apps/explorer/src/ui/utils/ButtonOrLink.tsx +++ b/apps/explorer/src/ui/utils/ButtonOrLink.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type ComponentProps, forwardRef } from 'react'; diff --git a/apps/explorer/src/ui/utils/Label.tsx b/apps/explorer/src/ui/utils/Label.tsx index 925c590a39e..753e5c81b7a 100644 --- a/apps/explorer/src/ui/utils/Label.tsx +++ b/apps/explorer/src/ui/utils/Label.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { forwardRef } from 'react'; diff --git a/apps/explorer/src/ui/utils/LinkWithQuery.tsx b/apps/explorer/src/ui/utils/LinkWithQuery.tsx index 084ad8cf30d..03f1188a2b9 100644 --- a/apps/explorer/src/ui/utils/LinkWithQuery.tsx +++ b/apps/explorer/src/ui/utils/LinkWithQuery.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { forwardRef, useCallback, useMemo } from 'react'; diff --git a/apps/explorer/src/utils/analytics/ampli/index.ts b/apps/explorer/src/utils/analytics/ampli/index.ts index a63942b0bb8..2231837d5fd 100644 --- a/apps/explorer/src/utils/analytics/ampli/index.ts +++ b/apps/explorer/src/utils/analytics/ampli/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /* tslint:disable */ @@ -15,9 +16,9 @@ * Build: 1.0.0 * Runtime: browser:typescript-ampli-v2 * - * [View Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Explorer/events/main/latest) + * [View Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Explorer/events/main/latest) * - * [Full Setup Instructions](https://data.amplitude.com/mystenlabs/Sui%20Explorer/implementation/web) + * [Full Setup Instructions](https://data.amplitude.com/mystenlabs/Iota%20Explorer/implementation/web) */ import * as amplitude from '@amplitude/analytics-browser'; @@ -69,11 +70,11 @@ export type LoadOptions = export interface IdentifyProperties { /** - * The Sui network that the user is currently interacting with. + * The Iota network that the user is currently interacting with. */ activeNetwork: string; /** - * The domain (e.g., suiexplorer.com) of a given page. + * The domain (e.g., iotaexplorer.com) of a given page. */ pageDomain: string; /** @@ -81,7 +82,7 @@ export interface IdentifyProperties { */ pagePath: string; /** - * The full URL (e.g., suiexplorer.com/validators) of a given page. + * The full URL (e.g., iotaexplorer.com/validators) of a given page. */ pageUrl: string; } @@ -177,8 +178,8 @@ export class CompletedSearch implements BaseEvent { } } -export class OpenedSuiExplorer implements BaseEvent { - event_type = 'opened sui explorer'; +export class OpenedIotaExplorer implements BaseEvent { + event_type = 'opened iota explorer'; } export class SwitchedNetwork implements BaseEvent { @@ -298,7 +299,7 @@ export class Ampli { /** * activated tooltip * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Explorer/events/main/latest/activated%20tooltip) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Explorer/events/main/latest/activated%20tooltip) * * When users activate or open a tooltip in the application. * @@ -317,7 +318,7 @@ export class Ampli { /** * clicked current epoch card * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Explorer/events/main/latest/clicked%20current%20epoch%20card) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Explorer/events/main/latest/clicked%20current%20epoch%20card) * * When users click the current epoch card on the home page. * @@ -336,7 +337,7 @@ export class Ampli { /** * clicked search result * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Explorer/events/main/latest/clicked%20search%20result) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Explorer/events/main/latest/clicked%20search%20result) * * When users click a search result within the search bar. * @@ -355,7 +356,7 @@ export class Ampli { /** * clicked validator row * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Explorer/events/main/latest/clicked%20validator%20row) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Explorer/events/main/latest/clicked%20validator%20row) * * When users click a validator list item in a table. * @@ -374,7 +375,7 @@ export class Ampli { /** * completed search * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Explorer/events/main/latest/completed%20search) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Explorer/events/main/latest/completed%20search) * * When users successfully search for something. * @@ -391,26 +392,26 @@ export class Ampli { } /** - * opened sui explorer + * opened iota explorer * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Explorer/events/main/latest/opened%20sui%20explorer) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Explorer/events/main/latest/opened%20iota%20explorer) * - * When users first open Sui Explorer. + * When users first open Iota Explorer. * * Owner: William Robertson * * @param options Amplitude event options. */ - openedSuiExplorer( + openedIotaExplorer( options?: EventOptions, ) { - return this.track(new OpenedSuiExplorer(), options); + return this.track(new OpenedIotaExplorer(), options); } /** * switched network * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Explorer/events/main/latest/switched%20network) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Explorer/events/main/latest/switched%20network) * * When users switch from one network to another. * diff --git a/apps/explorer/src/utils/analytics/amplitude.ts b/apps/explorer/src/utils/analytics/amplitude.ts index 40545e3ba7e..7036f3a559d 100644 --- a/apps/explorer/src/utils/analytics/amplitude.ts +++ b/apps/explorer/src/utils/analytics/amplitude.ts @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import * as amplitude from '@amplitude/analytics-browser'; import { LogLevel, TransportType, type UserSession } from '@amplitude/analytics-types'; -import { PersistableStorage } from '@mysten/core'; +import { PersistableStorage } from '@iota/core'; import { ampli } from './ampli'; diff --git a/apps/explorer/src/utils/api/DefaultRpcClient.ts b/apps/explorer/src/utils/api/DefaultRpcClient.ts index 472d8824363..b795703c092 100644 --- a/apps/explorer/src/utils/api/DefaultRpcClient.ts +++ b/apps/explorer/src/utils/api/DefaultRpcClient.ts @@ -1,26 +1,27 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SentryHttpTransport } from '@mysten/core'; +import { SentryHttpTransport } from '@iota/core'; import { - SuiClient, - SuiHTTPTransport, + IotaClient, + IotaHTTPTransport, getNetwork, Network, type NetworkId, getAllNetworks, -} from '@mysten/sui.js/client'; +} from '@iota/iota.js/client'; -export { Network } from '@mysten/sui.js/client'; +export { Network } from '@iota/iota.js/client'; export const SupportedNetworks = getAllNetworks(); // The Explorer always shows the Custom RPC input so there is no need to confuse it more by having a Custom Network here delete SupportedNetworks[Network.Custom]; -const defaultClientMap: Map = new Map(); +const defaultClientMap: Map = new Map(); -// NOTE: This class should not be used directly in React components, prefer to use the useSuiClient() hook instead -export const createSuiClient = (network: NetworkId) => { +// NOTE: This class should not be used directly in React components, prefer to use the useIotaClient() hook instead +export const createIotaClient = (network: NetworkId) => { const existingClient = defaultClientMap.get(network); if (existingClient) return existingClient; @@ -28,11 +29,11 @@ export const createSuiClient = (network: NetworkId) => { // If network is not supported, we use assume we are using a custom RPC const networkUrl = supportedNetwork?.url ?? network; - const client = new SuiClient({ + const client = new IotaClient({ transport: supportedNetwork && network === Network.Mainnet ? new SentryHttpTransport(networkUrl) - : new SuiHTTPTransport({ url: networkUrl }), + : new IotaHTTPTransport({ url: networkUrl }), }); defaultClientMap.set(network, client); return client; diff --git a/apps/explorer/src/utils/getStorageFundFlow.ts b/apps/explorer/src/utils/getStorageFundFlow.ts index 22d4ec3f349..c63d53635fe 100644 --- a/apps/explorer/src/utils/getStorageFundFlow.ts +++ b/apps/explorer/src/utils/getStorageFundFlow.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type EndOfEpochInfo } from '@mysten/sui.js/client'; +import { type EndOfEpochInfo } from '@iota/iota.js/client'; export function getEpochStorageFundFlow(endOfEpochInfo: EndOfEpochInfo | null) { const fundInflow = endOfEpochInfo diff --git a/apps/explorer/src/utils/getValidatorMoveEvent.ts b/apps/explorer/src/utils/getValidatorMoveEvent.ts index 7c69ac097dd..02b06d0a2ef 100644 --- a/apps/explorer/src/utils/getValidatorMoveEvent.ts +++ b/apps/explorer/src/utils/getValidatorMoveEvent.ts @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiEvent } from '@mysten/sui.js/client'; +import { type IotaEvent } from '@iota/iota.js/client'; -export function getValidatorMoveEvent(validatorsEvent: SuiEvent[], validatorAddress: string) { +export function getValidatorMoveEvent(validatorsEvent: IotaEvent[], validatorAddress: string) { const event = validatorsEvent.find( ({ parsedJson }) => (parsedJson as { validator_address?: unknown })!.validator_address === validatorAddress, diff --git a/apps/explorer/src/utils/growthbook.ts b/apps/explorer/src/utils/growthbook.ts index c7819a1e3a6..f5f5d4abb23 100644 --- a/apps/explorer/src/utils/growthbook.ts +++ b/apps/explorer/src/utils/growthbook.ts @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { GrowthBook } from '@growthbook/growthbook'; -import { getAppsBackend } from '@mysten/sui.js/client'; +import { getAppsBackend } from '@iota/iota.js/client'; export const growthbook = new GrowthBook({ // If you want to develop locally, you can set the API host to this: diff --git a/apps/explorer/src/utils/numberUtil.ts b/apps/explorer/src/utils/numberUtil.ts index 955aefd8d0b..0d876cea690 100644 --- a/apps/explorer/src/utils/numberUtil.ts +++ b/apps/explorer/src/utils/numberUtil.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Number Suffix diff --git a/apps/explorer/src/utils/objectUtils.ts b/apps/explorer/src/utils/objectUtils.ts index c8ea0eab86c..17b1957e23e 100644 --- a/apps/explorer/src/utils/objectUtils.ts +++ b/apps/explorer/src/utils/objectUtils.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type ObjectOwner, type SuiObjectResponse } from '@mysten/sui.js/client'; +import { type ObjectOwner, type IotaObjectResponse } from '@iota/iota.js/client'; import { findIPFSvalue } from './stringUtils'; @@ -20,7 +21,7 @@ export function parseImageURL(display?: Record | null) { return ''; } -export function parseObjectType(data: SuiObjectResponse): string { +export function parseObjectType(data: IotaObjectResponse): string { if (data.data?.content?.dataType === 'package') { return 'Move Package'; } diff --git a/apps/explorer/src/utils/queryClient.ts b/apps/explorer/src/utils/queryClient.ts index 6130e1abf5b..9549f34f88b 100644 --- a/apps/explorer/src/utils/queryClient.ts +++ b/apps/explorer/src/utils/queryClient.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { QueryClient } from '@tanstack/react-query'; diff --git a/apps/explorer/src/utils/sentry.ts b/apps/explorer/src/utils/sentry.ts index 51c87d6b057..b29d51d0abd 100644 --- a/apps/explorer/src/utils/sentry.ts +++ b/apps/explorer/src/utils/sentry.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import * as Sentry from '@sentry/react'; @@ -54,5 +55,5 @@ Sentry.init({ /^chrome(?:-extension)?:\/\//i, //, ], - allowUrls: [/.*\.sui\.io/i, /.*-mysten-labs\.vercel\.app/i, 'explorer-topaz.vercel.app'], + allowUrls: [/.*\.iota\.io/i, /.*-mysten-labs\.vercel\.app/i, 'explorer-topaz.vercel.app'], }); diff --git a/apps/explorer/src/utils/stringUtils.ts b/apps/explorer/src/utils/stringUtils.ts index 534d8ff6036..d9bbbd6beb9 100644 --- a/apps/explorer/src/utils/stringUtils.ts +++ b/apps/explorer/src/utils/stringUtils.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 const IPFS_START_STRING = 'https://ipfs.io/ipfs/'; diff --git a/apps/explorer/src/utils/validatorConstants.ts b/apps/explorer/src/utils/validatorConstants.ts index 1aaad28b39c..a8b34098953 100644 --- a/apps/explorer/src/utils/validatorConstants.ts +++ b/apps/explorer/src/utils/validatorConstants.ts @@ -1,3 +1,4 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export const VALIDATOR_LOW_STAKE_GRACE_PERIOD = 7; diff --git a/apps/explorer/src/vite-env.d.ts b/apps/explorer/src/vite-env.d.ts index d824e8fffe4..1fb048eaebd 100644 --- a/apps/explorer/src/vite-env.d.ts +++ b/apps/explorer/src/vite-env.d.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// diff --git a/apps/explorer/tailwind.config.ts b/apps/explorer/tailwind.config.ts index 25da22ed696..6ff5918d1a1 100644 --- a/apps/explorer/tailwind.config.ts +++ b/apps/explorer/tailwind.config.ts @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import preset from '@mysten/core/tailwind.config'; +import preset from '@iota/core/tailwind.config'; import { type Config } from 'tailwindcss'; export default { - content: ['./src/**/*.{js,jsx,ts,tsx}', './node_modules/@mysten/ui/src/**/*.{js,jsx,ts,tsx}'], + content: ['./src/**/*.{js,jsx,ts,tsx}', './node_modules/@iota/ui/src/**/*.{js,jsx,ts,tsx}'], presets: [preset], } satisfies Partial; diff --git a/apps/explorer/tests/address.spec.ts b/apps/explorer/tests/address.spec.ts index 9df27623f83..cb9b481aaf9 100644 --- a/apps/explorer/tests/address.spec.ts +++ b/apps/explorer/tests/address.spec.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { expect, test } from '@playwright/test'; @@ -14,7 +15,7 @@ test('address page', async ({ page }) => { test('owned objects (coins) are displayed', async ({ page }) => { const address = await faucet(); await page.goto(`/address/${address}`); - await expect(await page.getByTestId('ownedcoinlabel')).toContainText('SUI'); + await expect(await page.getByTestId('ownedcoinlabel')).toContainText('IOTA'); }); // TODO: rewrite this test after the removal of devnet_nft diff --git a/apps/explorer/tests/home.spec.ts b/apps/explorer/tests/home.spec.ts index c0ed2e160fe..39157d21eae 100644 --- a/apps/explorer/tests/home.spec.ts +++ b/apps/explorer/tests/home.spec.ts @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { test, expect } from '@playwright/test'; test('home page', async ({ page }) => { await page.goto('/'); - await expect(page).toHaveTitle(/Sui Explorer/); + await expect(page).toHaveTitle(/Iota Explorer/); await expect(page.getByTestId('home-page')).toBeVisible(); }); diff --git a/apps/explorer/tests/objects.spec.ts b/apps/explorer/tests/objects.spec.ts index c7365ac1d63..c73569e4c9b 100644 --- a/apps/explorer/tests/objects.spec.ts +++ b/apps/explorer/tests/objects.spec.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { test, expect } from '@playwright/test'; diff --git a/apps/explorer/tests/search.spec.ts b/apps/explorer/tests/search.spec.ts index f14f083ff16..d39f9f7c949 100644 --- a/apps/explorer/tests/search.spec.ts +++ b/apps/explorer/tests/search.spec.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { expect, test, type Page } from '@playwright/test'; diff --git a/apps/explorer/tests/transaction.spec.ts b/apps/explorer/tests/transaction.spec.ts index 47c55ebab74..5bc8feba45e 100644 --- a/apps/explorer/tests/transaction.spec.ts +++ b/apps/explorer/tests/transaction.spec.ts @@ -1,6 +1,7 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type ProgrammableTransaction } from '@mysten/sui.js/client'; +import { type ProgrammableTransaction } from '@iota/iota.js/client'; import { expect, test } from '@playwright/test'; import { faucet, split_coin } from './utils/localnet'; diff --git a/apps/explorer/tests/utils/localnet.ts b/apps/explorer/tests/utils/localnet.ts index f9721efc381..c980f2afaaa 100644 --- a/apps/explorer/tests/utils/localnet.ts +++ b/apps/explorer/tests/utils/localnet.ts @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import 'tsconfig-paths/register'; -import { SuiClient, getFullnodeUrl } from '@mysten/sui.js/client'; -import { type Keypair } from '@mysten/sui.js/cryptography'; -import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519'; -import { TransactionBlock } from '@mysten/sui.js/transactions'; +import { IotaClient, getFullnodeUrl } from '@iota/iota.js/client'; +import { type Keypair } from '@iota/iota.js/cryptography'; +import { Ed25519Keypair } from '@iota/iota.js/keypairs/ed25519'; +import { TransactionBlock } from '@iota/iota.js/transactions'; const addressToKeypair = new Map(); @@ -15,7 +16,7 @@ export async function split_coin(address: string) { if (!keypair) { throw new Error('missing keypair'); } - const client = new SuiClient({ url: getFullnodeUrl('localnet') }); + const client = new IotaClient({ url: getFullnodeUrl('localnet') }); const coins = await client.getCoins({ owner: address }); const coin_id = coins.data[0].coinObjectId; @@ -23,7 +24,7 @@ export async function split_coin(address: string) { const tx = new TransactionBlock(); tx.moveCall({ target: '0x2::pay::split', - typeArguments: ['0x2::sui::SUI'], + typeArguments: ['0x2::iota::IOTA'], arguments: [tx.object(coin_id), tx.pure.u64(10)], }); @@ -42,7 +43,7 @@ export async function split_coin(address: string) { export async function faucet() { const keypair = Ed25519Keypair.generate(); - const address = keypair.getPublicKey().toSuiAddress(); + const address = keypair.getPublicKey().toIotaAddress(); addressToKeypair.set(address, keypair); const res = await fetch('http://127.0.0.1:9123/gas', { method: 'POST', diff --git a/apps/explorer/vite.config.ts b/apps/explorer/vite.config.ts index 2d4d287833b..b5bd8024137 100644 --- a/apps/explorer/vite.config.ts +++ b/apps/explorer/vite.config.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// diff --git a/apps/icons/.eslintignore b/apps/icons/.eslintignore deleted file mode 100644 index b629d88145e..00000000000 --- a/apps/icons/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -svgrrc.config.js diff --git a/apps/icons/README.md b/apps/icons/README.md index a9627e1ac4f..ca1da8e548c 100644 --- a/apps/icons/README.md +++ b/apps/icons/README.md @@ -1,8 +1,8 @@ -# `@mysten/icons` +# `@iota/icons` ## Exporting Icons 1. Clean the project by running `pnpm icons clean:all` from the repo root. -1. Open Figma Icons file. Create a mass export using `cmd` + `shift` + `e`. Save the SVGs to `sui/apps/icons/svgs`. +1. Open Figma Icons file. Create a mass export using `cmd` + `shift` + `e`. Save the SVGs to `iota/apps/icons/svgs`. 1. Run `pnpm icons generate` to generate the new icon library. 1. Commit the changes and submit a PR. diff --git a/apps/icons/package.json b/apps/icons/package.json index 40549910e89..53525c4e0c3 100644 --- a/apps/icons/package.json +++ b/apps/icons/package.json @@ -1,5 +1,5 @@ { - "name": "@mysten/icons", + "name": "@iota/icons", "main": "src/index.ts", "private": true, "sideEffects": false, diff --git a/apps/icons/scripts/preprocess.mjs b/apps/icons/scripts/preprocess.mjs index f1a3c30a6b5..f50551784d6 100644 --- a/apps/icons/scripts/preprocess.mjs +++ b/apps/icons/scripts/preprocess.mjs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import fs from 'node:fs'; diff --git a/apps/icons/src/3D32.tsx b/apps/icons/src/3D32.tsx index c7e2cb06fc2..9bc04403926 100644 --- a/apps/icons/src/3D32.tsx +++ b/apps/icons/src/3D32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const Svg3D32 = (props: SVGProps) => ( diff --git a/apps/icons/src/Account24.tsx b/apps/icons/src/Account24.tsx index d298e959890..3029ab2abd8 100644 --- a/apps/icons/src/Account24.tsx +++ b/apps/icons/src/Account24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgAccount24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Activity32.tsx b/apps/icons/src/Activity32.tsx index aa83565d859..1539dfd4835 100644 --- a/apps/icons/src/Activity32.tsx +++ b/apps/icons/src/Activity32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgActivity32 = (props: SVGProps) => ( diff --git a/apps/icons/src/Add16.tsx b/apps/icons/src/Add16.tsx index bf4867a3d96..325c864ad37 100644 --- a/apps/icons/src/Add16.tsx +++ b/apps/icons/src/Add16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgAdd16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Address16.tsx b/apps/icons/src/Address16.tsx index a6a299f75ef..2feae340c59 100644 --- a/apps/icons/src/Address16.tsx +++ b/apps/icons/src/Address16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgAddress16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Apps24.tsx b/apps/icons/src/Apps24.tsx index f11d56ae439..f628ea422a3 100644 --- a/apps/icons/src/Apps24.tsx +++ b/apps/icons/src/Apps24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgApps24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Apps32.tsx b/apps/icons/src/Apps32.tsx index 701b665e545..eca4b779157 100644 --- a/apps/icons/src/Apps32.tsx +++ b/apps/icons/src/Apps32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgApps32 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowBgFill16.tsx b/apps/icons/src/ArrowBgFill16.tsx index 9dbaace58d7..d309f3c31f3 100644 --- a/apps/icons/src/ArrowBgFill16.tsx +++ b/apps/icons/src/ArrowBgFill16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowBgFill16 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowBottomLeft16.tsx b/apps/icons/src/ArrowBottomLeft16.tsx index e3b17cf7702..e7b5d4181e9 100644 --- a/apps/icons/src/ArrowBottomLeft16.tsx +++ b/apps/icons/src/ArrowBottomLeft16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowBottomLeft16 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowDown12.tsx b/apps/icons/src/ArrowDown12.tsx index d8e2cf1411d..9dd6317b85c 100644 --- a/apps/icons/src/ArrowDown12.tsx +++ b/apps/icons/src/ArrowDown12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowDown12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowDown16.tsx b/apps/icons/src/ArrowDown16.tsx index 903515b5400..8c699ba7c86 100644 --- a/apps/icons/src/ArrowDown16.tsx +++ b/apps/icons/src/ArrowDown16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowDown16 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowLeft12.tsx b/apps/icons/src/ArrowLeft12.tsx index 9e31c032d75..bcd4efb3039 100644 --- a/apps/icons/src/ArrowLeft12.tsx +++ b/apps/icons/src/ArrowLeft12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowLeft12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowLeft16.tsx b/apps/icons/src/ArrowLeft16.tsx index 8658591b235..6f3338909bc 100644 --- a/apps/icons/src/ArrowLeft16.tsx +++ b/apps/icons/src/ArrowLeft16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowLeft16 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowLeft24.tsx b/apps/icons/src/ArrowLeft24.tsx index f4d5f97f543..fb75d4b2c0b 100644 --- a/apps/icons/src/ArrowLeft24.tsx +++ b/apps/icons/src/ArrowLeft24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowLeft24 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowRight12.tsx b/apps/icons/src/ArrowRight12.tsx index 2dfce64a170..81c78d6bcb5 100644 --- a/apps/icons/src/ArrowRight12.tsx +++ b/apps/icons/src/ArrowRight12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowRight12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowRight16.tsx b/apps/icons/src/ArrowRight16.tsx index 421cdbd40ef..a8f17a03e11 100644 --- a/apps/icons/src/ArrowRight16.tsx +++ b/apps/icons/src/ArrowRight16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowRight16 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowShowAndHide16.tsx b/apps/icons/src/ArrowShowAndHide16.tsx index fea15194fbe..0195d26ede2 100644 --- a/apps/icons/src/ArrowShowAndHide16.tsx +++ b/apps/icons/src/ArrowShowAndHide16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowShowAndHide16 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowShowAndHideDown12.tsx b/apps/icons/src/ArrowShowAndHideDown12.tsx index 60cb5cee6b7..2075e0f526b 100644 --- a/apps/icons/src/ArrowShowAndHideDown12.tsx +++ b/apps/icons/src/ArrowShowAndHideDown12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowShowAndHideDown12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowShowAndHideRight12.tsx b/apps/icons/src/ArrowShowAndHideRight12.tsx index 10e060bfef3..474b296ecd9 100644 --- a/apps/icons/src/ArrowShowAndHideRight12.tsx +++ b/apps/icons/src/ArrowShowAndHideRight12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowShowAndHideRight12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowSort12.tsx b/apps/icons/src/ArrowSort12.tsx index d6fa80fb84f..011a9e31c0e 100644 --- a/apps/icons/src/ArrowSort12.tsx +++ b/apps/icons/src/ArrowSort12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowSort12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowSortDown12.tsx b/apps/icons/src/ArrowSortDown12.tsx index f0dad1a6208..3978243cbbe 100644 --- a/apps/icons/src/ArrowSortDown12.tsx +++ b/apps/icons/src/ArrowSortDown12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowSortDown12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowSortUp12.tsx b/apps/icons/src/ArrowSortUp12.tsx index aff144f965f..5bf3fc51038 100644 --- a/apps/icons/src/ArrowSortUp12.tsx +++ b/apps/icons/src/ArrowSortUp12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowSortUp12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowUp12.tsx b/apps/icons/src/ArrowUp12.tsx index afba7a19685..e321757ea1b 100644 --- a/apps/icons/src/ArrowUp12.tsx +++ b/apps/icons/src/ArrowUp12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowUp12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowUpRight12.tsx b/apps/icons/src/ArrowUpRight12.tsx index 4bae0eace6d..25cf1d36ec0 100644 --- a/apps/icons/src/ArrowUpRight12.tsx +++ b/apps/icons/src/ArrowUpRight12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowUpRight12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ArrowUpRight16.tsx b/apps/icons/src/ArrowUpRight16.tsx index 5457c3d9cc9..f8c6989a1d9 100644 --- a/apps/icons/src/ArrowUpRight16.tsx +++ b/apps/icons/src/ArrowUpRight16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgArrowUpRight16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Audio32.tsx b/apps/icons/src/Audio32.tsx index fc35ad1d0a9..f31f0fadba5 100644 --- a/apps/icons/src/Audio32.tsx +++ b/apps/icons/src/Audio32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgAudio32 = (props: SVGProps) => ( diff --git a/apps/icons/src/AutorefreshPause24.tsx b/apps/icons/src/AutorefreshPause24.tsx index 6dd20c45b3c..bccea3449be 100644 --- a/apps/icons/src/AutorefreshPause24.tsx +++ b/apps/icons/src/AutorefreshPause24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgAutorefreshPause24 = (props: SVGProps) => ( diff --git a/apps/icons/src/AutorefreshPlay24.tsx b/apps/icons/src/AutorefreshPlay24.tsx index ff9323bab40..1279ca2a326 100644 --- a/apps/icons/src/AutorefreshPlay24.tsx +++ b/apps/icons/src/AutorefreshPlay24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgAutorefreshPlay24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Buy16.tsx b/apps/icons/src/Buy16.tsx index 19ca6d3ab03..429f43e96ef 100644 --- a/apps/icons/src/Buy16.tsx +++ b/apps/icons/src/Buy16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgBuy16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Call16.tsx b/apps/icons/src/Call16.tsx index ac82dbc2f67..3b2f5e9533a 100644 --- a/apps/icons/src/Call16.tsx +++ b/apps/icons/src/Call16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCall16 = (props: SVGProps) => ( diff --git a/apps/icons/src/ChangeEpoch16.tsx b/apps/icons/src/ChangeEpoch16.tsx index b628e522692..ecceae6714b 100644 --- a/apps/icons/src/ChangeEpoch16.tsx +++ b/apps/icons/src/ChangeEpoch16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgChangeEpoch16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Check12.tsx b/apps/icons/src/Check12.tsx index 3a4e8e1e61e..fb17dd93b81 100644 --- a/apps/icons/src/Check12.tsx +++ b/apps/icons/src/Check12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCheck12 = (props: SVGProps) => ( diff --git a/apps/icons/src/Check24.tsx b/apps/icons/src/Check24.tsx index 4940f16b1bd..42636f2c9b4 100644 --- a/apps/icons/src/Check24.tsx +++ b/apps/icons/src/Check24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCheck24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Check241.tsx b/apps/icons/src/Check241.tsx index eb3d0d57163..2d0d6e144d2 100644 --- a/apps/icons/src/Check241.tsx +++ b/apps/icons/src/Check241.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCheck241 = (props: SVGProps) => ( diff --git a/apps/icons/src/Check32.tsx b/apps/icons/src/Check32.tsx index 3997f5eaadd..6ef826d1226 100644 --- a/apps/icons/src/Check32.tsx +++ b/apps/icons/src/Check32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCheck32 = (props: SVGProps) => ( diff --git a/apps/icons/src/CheckFill12.tsx b/apps/icons/src/CheckFill12.tsx index fa1c0b56531..09b33d8f227 100644 --- a/apps/icons/src/CheckFill12.tsx +++ b/apps/icons/src/CheckFill12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCheckFill12 = (props: SVGProps) => ( diff --git a/apps/icons/src/CheckFill16.tsx b/apps/icons/src/CheckFill16.tsx index cf39646fd8f..372f73989c0 100644 --- a/apps/icons/src/CheckFill16.tsx +++ b/apps/icons/src/CheckFill16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCheckFill16 = (props: SVGProps) => ( diff --git a/apps/icons/src/CheckStroke16.tsx b/apps/icons/src/CheckStroke16.tsx index 1a6d9c553b5..362472cfb5e 100644 --- a/apps/icons/src/CheckStroke16.tsx +++ b/apps/icons/src/CheckStroke16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCheckStroke16 = (props: SVGProps) => ( diff --git a/apps/icons/src/CheckStroke24.tsx b/apps/icons/src/CheckStroke24.tsx index 97fe786606c..7c66109a65e 100644 --- a/apps/icons/src/CheckStroke24.tsx +++ b/apps/icons/src/CheckStroke24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCheckStroke24 = (props: SVGProps) => ( diff --git a/apps/icons/src/ChevronDown12.tsx b/apps/icons/src/ChevronDown12.tsx index a1ff9cd9733..9c9d3483510 100644 --- a/apps/icons/src/ChevronDown12.tsx +++ b/apps/icons/src/ChevronDown12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgChevronDown12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ChevronDown16.tsx b/apps/icons/src/ChevronDown16.tsx index dac7d5b53a2..d60d6352f51 100644 --- a/apps/icons/src/ChevronDown16.tsx +++ b/apps/icons/src/ChevronDown16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgChevronDown16 = (props: SVGProps) => ( diff --git a/apps/icons/src/ChevronDown24.tsx b/apps/icons/src/ChevronDown24.tsx index 4aaf620fbca..c0464ca23c1 100644 --- a/apps/icons/src/ChevronDown24.tsx +++ b/apps/icons/src/ChevronDown24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgChevronDown24 = (props: SVGProps) => ( diff --git a/apps/icons/src/ChevronLeft12.tsx b/apps/icons/src/ChevronLeft12.tsx index 566f14ef808..f2fb9b1cb71 100644 --- a/apps/icons/src/ChevronLeft12.tsx +++ b/apps/icons/src/ChevronLeft12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgChevronLeft12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ChevronLeft16.tsx b/apps/icons/src/ChevronLeft16.tsx index 6c9222841c5..697cc1cfc1b 100644 --- a/apps/icons/src/ChevronLeft16.tsx +++ b/apps/icons/src/ChevronLeft16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgChevronLeft16 = (props: SVGProps) => ( diff --git a/apps/icons/src/ChevronLeft24.tsx b/apps/icons/src/ChevronLeft24.tsx index 6e54292afbd..9248697128b 100644 --- a/apps/icons/src/ChevronLeft24.tsx +++ b/apps/icons/src/ChevronLeft24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgChevronLeft24 = (props: SVGProps) => ( diff --git a/apps/icons/src/ChevronRight12.tsx b/apps/icons/src/ChevronRight12.tsx index 4b2ac59f640..fcdf67ca3fe 100644 --- a/apps/icons/src/ChevronRight12.tsx +++ b/apps/icons/src/ChevronRight12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgChevronRight12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ChevronRight16.tsx b/apps/icons/src/ChevronRight16.tsx index cba1098b2ec..5331f0f2919 100644 --- a/apps/icons/src/ChevronRight16.tsx +++ b/apps/icons/src/ChevronRight16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgChevronRight16 = (props: SVGProps) => ( diff --git a/apps/icons/src/ChevronUp12.tsx b/apps/icons/src/ChevronUp12.tsx index 566afebb6f5..1de4ae29cd4 100644 --- a/apps/icons/src/ChevronUp12.tsx +++ b/apps/icons/src/ChevronUp12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgChevronUp12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ChevronUp16.tsx b/apps/icons/src/ChevronUp16.tsx index 4922dab351b..8791eae747d 100644 --- a/apps/icons/src/ChevronUp16.tsx +++ b/apps/icons/src/ChevronUp16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgChevronUp16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Clipboard16.tsx b/apps/icons/src/Clipboard16.tsx index b3864cb0b50..9b9f2a941ab 100644 --- a/apps/icons/src/Clipboard16.tsx +++ b/apps/icons/src/Clipboard16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgClipboard16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Clipboard24.tsx b/apps/icons/src/Clipboard24.tsx index 6f4bfea1229..6a3297324af 100644 --- a/apps/icons/src/Clipboard24.tsx +++ b/apps/icons/src/Clipboard24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgClipboard24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Code16.tsx b/apps/icons/src/Code16.tsx index 3be8abbbf53..c8d16ca0d7f 100644 --- a/apps/icons/src/Code16.tsx +++ b/apps/icons/src/Code16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCode16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Coins16.tsx b/apps/icons/src/Coins16.tsx index 460471f79b5..cbb5b9af249 100644 --- a/apps/icons/src/Coins16.tsx +++ b/apps/icons/src/Coins16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCoins16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Coins24.tsx b/apps/icons/src/Coins24.tsx index 70b830e711c..3afefc0b130 100644 --- a/apps/icons/src/Coins24.tsx +++ b/apps/icons/src/Coins24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCoins24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Copy12.tsx b/apps/icons/src/Copy12.tsx index e16afd82d10..a08f469c36d 100644 --- a/apps/icons/src/Copy12.tsx +++ b/apps/icons/src/Copy12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCopy12 = (props: SVGProps) => ( diff --git a/apps/icons/src/Copy16.tsx b/apps/icons/src/Copy16.tsx index f463c184352..ce924b2feab 100644 --- a/apps/icons/src/Copy16.tsx +++ b/apps/icons/src/Copy16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCopy16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Copy18.tsx b/apps/icons/src/Copy18.tsx index 399a2f7e63e..7be2e9f18aa 100644 --- a/apps/icons/src/Copy18.tsx +++ b/apps/icons/src/Copy18.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCopy18 = (props: SVGProps) => ( diff --git a/apps/icons/src/Copy24.tsx b/apps/icons/src/Copy24.tsx index c787b08f328..32ba41ac36e 100644 --- a/apps/icons/src/Copy24.tsx +++ b/apps/icons/src/Copy24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCopy24 = (props: SVGProps) => ( diff --git a/apps/icons/src/CopyArchiveDoNotUse16.tsx b/apps/icons/src/CopyArchiveDoNotUse16.tsx index 1c72be39199..fa3e2658dfd 100644 --- a/apps/icons/src/CopyArchiveDoNotUse16.tsx +++ b/apps/icons/src/CopyArchiveDoNotUse16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCopyArchiveDoNotUse16 = (props: SVGProps) => ( diff --git a/apps/icons/src/CopyArchiveDoNotUse24.tsx b/apps/icons/src/CopyArchiveDoNotUse24.tsx index 44c76de99cb..a58a51cc0c9 100644 --- a/apps/icons/src/CopyArchiveDoNotUse24.tsx +++ b/apps/icons/src/CopyArchiveDoNotUse24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCopyArchiveDoNotUse24 = (props: SVGProps) => ( diff --git a/apps/icons/src/CopyNew24.tsx b/apps/icons/src/CopyNew24.tsx index f595dd00480..30d60a8349f 100644 --- a/apps/icons/src/CopyNew24.tsx +++ b/apps/icons/src/CopyNew24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgCopyNew24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Delete16.tsx b/apps/icons/src/Delete16.tsx index acc622522c6..3e5b1a67ed0 100644 --- a/apps/icons/src/Delete16.tsx +++ b/apps/icons/src/Delete16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgDelete16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Destake16.tsx b/apps/icons/src/Destake16.tsx index 531fd7f4c5c..809fbccc160 100644 --- a/apps/icons/src/Destake16.tsx +++ b/apps/icons/src/Destake16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgDestake16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Domain24.tsx b/apps/icons/src/Domain24.tsx index 724e6a2b8bc..ac672c87875 100644 --- a/apps/icons/src/Domain24.tsx +++ b/apps/icons/src/Domain24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgDomain24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Domain32.tsx b/apps/icons/src/Domain32.tsx index 31f9df01e5e..ae1172994f0 100644 --- a/apps/icons/src/Domain32.tsx +++ b/apps/icons/src/Domain32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgDomain32 = (props: SVGProps) => ( diff --git a/apps/icons/src/Dot12.tsx b/apps/icons/src/Dot12.tsx index d6204d3bff1..a5cabb0c793 100644 --- a/apps/icons/src/Dot12.tsx +++ b/apps/icons/src/Dot12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgDot12 = (props: SVGProps) => ( diff --git a/apps/icons/src/Download16.tsx b/apps/icons/src/Download16.tsx index c7619f76670..c69c55cf9f0 100644 --- a/apps/icons/src/Download16.tsx +++ b/apps/icons/src/Download16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgDownload16 = (props: SVGProps) => ( diff --git a/apps/icons/src/EyeClose16.tsx b/apps/icons/src/EyeClose16.tsx index 5a215481eac..d925e263c0a 100644 --- a/apps/icons/src/EyeClose16.tsx +++ b/apps/icons/src/EyeClose16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgEyeClose16 = (props: SVGProps) => ( diff --git a/apps/icons/src/EyeOpen16.tsx b/apps/icons/src/EyeOpen16.tsx index 7ae68e98405..2af8ef5a04b 100644 --- a/apps/icons/src/EyeOpen16.tsx +++ b/apps/icons/src/EyeOpen16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgEyeOpen16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Fail32.tsx b/apps/icons/src/Fail32.tsx index 341219f1b2b..b8207707c8b 100644 --- a/apps/icons/src/Fail32.tsx +++ b/apps/icons/src/Fail32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgFail32 = (props: SVGProps) => ( diff --git a/apps/icons/src/Filter12.tsx b/apps/icons/src/Filter12.tsx index 3592e92766b..63bc3cc7e95 100644 --- a/apps/icons/src/Filter12.tsx +++ b/apps/icons/src/Filter12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgFilter12 = (props: SVGProps) => ( diff --git a/apps/icons/src/Filter16.tsx b/apps/icons/src/Filter16.tsx index 6a4bc5f84e6..5faea6a1a7f 100644 --- a/apps/icons/src/Filter16.tsx +++ b/apps/icons/src/Filter16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgFilter16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Flag16.tsx b/apps/icons/src/Flag16.tsx index f320d8294ce..024a5b58e1a 100644 --- a/apps/icons/src/Flag16.tsx +++ b/apps/icons/src/Flag16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgFlag16 = (props: SVGProps) => ( diff --git a/apps/icons/src/FlagFill16.tsx b/apps/icons/src/FlagFill16.tsx index dfcaab902de..590e8f61732 100644 --- a/apps/icons/src/FlagFill16.tsx +++ b/apps/icons/src/FlagFill16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgFlagFill16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Globe16.tsx b/apps/icons/src/Globe16.tsx index 586526bd539..77f3ded02ea 100644 --- a/apps/icons/src/Globe16.tsx +++ b/apps/icons/src/Globe16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgGlobe16 = (props: SVGProps) => ( diff --git a/apps/icons/src/HamburgerOpen24.tsx b/apps/icons/src/HamburgerOpen24.tsx index da1e99c1598..d4343364900 100644 --- a/apps/icons/src/HamburgerOpen24.tsx +++ b/apps/icons/src/HamburgerOpen24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgHamburgerOpen24 = (props: SVGProps) => ( diff --git a/apps/icons/src/HamburgerRest16.tsx b/apps/icons/src/HamburgerRest16.tsx index cd63c521533..3f5c20539aa 100644 --- a/apps/icons/src/HamburgerRest16.tsx +++ b/apps/icons/src/HamburgerRest16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgHamburgerRest16 = (props: SVGProps) => ( diff --git a/apps/icons/src/HamburgerRest24.tsx b/apps/icons/src/HamburgerRest24.tsx index e84bbdc17e0..ebede2c55ee 100644 --- a/apps/icons/src/HamburgerRest24.tsx +++ b/apps/icons/src/HamburgerRest24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgHamburgerRest24 = (props: SVGProps) => ( diff --git a/apps/icons/src/History24.tsx b/apps/icons/src/History24.tsx index 8e6ddd610fa..1995f0d5e3e 100644 --- a/apps/icons/src/History24.tsx +++ b/apps/icons/src/History24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgHistory24 = (props: SVGProps) => ( diff --git a/apps/icons/src/History32.tsx b/apps/icons/src/History32.tsx index 2fc7940b938..ef2a58903ed 100644 --- a/apps/icons/src/History32.tsx +++ b/apps/icons/src/History32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgHistory32 = (props: SVGProps) => ( diff --git a/apps/icons/src/Image16.tsx b/apps/icons/src/Image16.tsx index d39c3db32f3..42b44993a84 100644 --- a/apps/icons/src/Image16.tsx +++ b/apps/icons/src/Image16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgImage16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Image32.tsx b/apps/icons/src/Image32.tsx index 8575b1194b9..db1c7489b3c 100644 --- a/apps/icons/src/Image32.tsx +++ b/apps/icons/src/Image32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgImage32 = (props: SVGProps) => ( diff --git a/apps/icons/src/Info12.tsx b/apps/icons/src/Info12.tsx index 8e96cdbe501..57c63e6c18e 100644 --- a/apps/icons/src/Info12.tsx +++ b/apps/icons/src/Info12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgInfo12 = (props: SVGProps) => ( diff --git a/apps/icons/src/Info16.tsx b/apps/icons/src/Info16.tsx index 5968e1a6135..91ab5f1030c 100644 --- a/apps/icons/src/Info16.tsx +++ b/apps/icons/src/Info16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgInfo16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Iota.tsx b/apps/icons/src/Iota.tsx new file mode 100644 index 00000000000..1a1cf39b54e --- /dev/null +++ b/apps/icons/src/Iota.tsx @@ -0,0 +1,22 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +import { SVGProps } from 'react'; +const SvgIota = (props: SVGProps) => ( + + + +); +export default SvgIota; diff --git a/apps/icons/src/IotaCustomRpc.tsx b/apps/icons/src/IotaCustomRpc.tsx new file mode 100644 index 00000000000..3b2d966dbfd --- /dev/null +++ b/apps/icons/src/IotaCustomRpc.tsx @@ -0,0 +1,22 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +import { SVGProps } from 'react'; +const SvgIotaCustomRpc = (props: SVGProps) => ( + + + +); +export default SvgIotaCustomRpc; diff --git a/apps/icons/src/IotaDevnet.tsx b/apps/icons/src/IotaDevnet.tsx new file mode 100644 index 00000000000..94e032da831 --- /dev/null +++ b/apps/icons/src/IotaDevnet.tsx @@ -0,0 +1,22 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +import { SVGProps } from 'react'; +const SvgIotaDevnet = (props: SVGProps) => ( + + + +); +export default SvgIotaDevnet; diff --git a/apps/icons/src/IotaLocal.tsx b/apps/icons/src/IotaLocal.tsx new file mode 100644 index 00000000000..679f74d5efb --- /dev/null +++ b/apps/icons/src/IotaLocal.tsx @@ -0,0 +1,22 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +import { SVGProps } from 'react'; +const SvgIotaLocal = (props: SVGProps) => ( + + + +); +export default SvgIotaLocal; diff --git a/apps/icons/src/IotaLogoTxt.tsx b/apps/icons/src/IotaLogoTxt.tsx new file mode 100644 index 00000000000..01953401050 --- /dev/null +++ b/apps/icons/src/IotaLogoTxt.tsx @@ -0,0 +1,20 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +import { SVGProps } from 'react'; +const SvgIotaLogoTxt = (props: SVGProps) => ( + + + +); +export default SvgIotaLogoTxt; diff --git a/apps/icons/src/IotaMainnet.tsx b/apps/icons/src/IotaMainnet.tsx new file mode 100644 index 00000000000..f6a248bdd2b --- /dev/null +++ b/apps/icons/src/IotaMainnet.tsx @@ -0,0 +1,22 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +import { SVGProps } from 'react'; +const SvgIotaMainnet = (props: SVGProps) => ( + + + +); +export default SvgIotaMainnet; diff --git a/apps/icons/src/IotaTestnet.tsx b/apps/icons/src/IotaTestnet.tsx new file mode 100644 index 00000000000..546a4b427be --- /dev/null +++ b/apps/icons/src/IotaTestnet.tsx @@ -0,0 +1,22 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +import { SVGProps } from 'react'; +const SvgIotaTestnet = (props: SVGProps) => ( + + + +); +export default SvgIotaTestnet; diff --git a/apps/icons/src/IotaTokensStack.tsx b/apps/icons/src/IotaTokensStack.tsx new file mode 100644 index 00000000000..1b7f3d4cea1 --- /dev/null +++ b/apps/icons/src/IotaTokensStack.tsx @@ -0,0 +1,39 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +import { SVGProps } from 'react'; +const SvgIotaTokensStack = (props: SVGProps) => ( + + + + + + + + + + + + + + +); +export default SvgIotaTokensStack; diff --git a/apps/icons/src/LedgerLogo17.tsx b/apps/icons/src/LedgerLogo17.tsx index 45eb2e2b161..f6a1ddd4d19 100644 --- a/apps/icons/src/LedgerLogo17.tsx +++ b/apps/icons/src/LedgerLogo17.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgLedgerLogo17 = (props: SVGProps) => ( diff --git a/apps/icons/src/LockLocked16.tsx b/apps/icons/src/LockLocked16.tsx index 87523ec608e..9baca52af70 100644 --- a/apps/icons/src/LockLocked16.tsx +++ b/apps/icons/src/LockLocked16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgLockLocked16 = (props: SVGProps) => ( diff --git a/apps/icons/src/LockLocked24.tsx b/apps/icons/src/LockLocked24.tsx index cf3871b12f8..691f73b9b04 100644 --- a/apps/icons/src/LockLocked24.tsx +++ b/apps/icons/src/LockLocked24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgLockLocked24 = (props: SVGProps) => ( diff --git a/apps/icons/src/LockUnlocked16.tsx b/apps/icons/src/LockUnlocked16.tsx index 7192b41039f..9f73e8e1b53 100644 --- a/apps/icons/src/LockUnlocked16.tsx +++ b/apps/icons/src/LockUnlocked16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgLockUnlocked16 = (props: SVGProps) => ( diff --git a/apps/icons/src/LogoGoogle.tsx b/apps/icons/src/LogoGoogle.tsx index 49a5f39fc52..e4aff8e2dcb 100644 --- a/apps/icons/src/LogoGoogle.tsx +++ b/apps/icons/src/LogoGoogle.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgLogoGoogle = (props: SVGProps) => ( diff --git a/apps/icons/src/LogoTwitch.tsx b/apps/icons/src/LogoTwitch.tsx index 4d9a01e2b74..dd4a0fae406 100644 --- a/apps/icons/src/LogoTwitch.tsx +++ b/apps/icons/src/LogoTwitch.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgLogoTwitch = (props: SVGProps) => ( diff --git a/apps/icons/src/Logout24.tsx b/apps/icons/src/Logout24.tsx index a9080bfd176..52427c3ef9f 100644 --- a/apps/icons/src/Logout24.tsx +++ b/apps/icons/src/Logout24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgLogout24 = (props: SVGProps) => ( diff --git a/apps/icons/src/MediaPause16.tsx b/apps/icons/src/MediaPause16.tsx index a0036a9f3c8..cd8dfafcf3a 100644 --- a/apps/icons/src/MediaPause16.tsx +++ b/apps/icons/src/MediaPause16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgMediaPause16 = (props: SVGProps) => ( diff --git a/apps/icons/src/MediaPlay16.tsx b/apps/icons/src/MediaPlay16.tsx index 73b62de577f..e94689484c0 100644 --- a/apps/icons/src/MediaPlay16.tsx +++ b/apps/icons/src/MediaPlay16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgMediaPlay16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Modules24.tsx b/apps/icons/src/Modules24.tsx index 9aab9eb7e0c..65d1f3bc990 100644 --- a/apps/icons/src/Modules24.tsx +++ b/apps/icons/src/Modules24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgModules24 = (props: SVGProps) => ( diff --git a/apps/icons/src/More24.tsx b/apps/icons/src/More24.tsx index a551dd4df9b..b168d4069aa 100644 --- a/apps/icons/src/More24.tsx +++ b/apps/icons/src/More24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgMore24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Nft132.tsx b/apps/icons/src/Nft132.tsx index 9f74345d25d..f5c7ef4bb3e 100644 --- a/apps/icons/src/Nft132.tsx +++ b/apps/icons/src/Nft132.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgNft132 = (props: SVGProps) => ( diff --git a/apps/icons/src/Nft16.tsx b/apps/icons/src/Nft16.tsx index 334442f7c6b..11809de3776 100644 --- a/apps/icons/src/Nft16.tsx +++ b/apps/icons/src/Nft16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgNft16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Nft232.tsx b/apps/icons/src/Nft232.tsx index b3072932755..f9342c342cc 100644 --- a/apps/icons/src/Nft232.tsx +++ b/apps/icons/src/Nft232.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgNft232 = (props: SVGProps) => ( diff --git a/apps/icons/src/Nft24.tsx b/apps/icons/src/Nft24.tsx index eaca66649f1..0336e4c202f 100644 --- a/apps/icons/src/Nft24.tsx +++ b/apps/icons/src/Nft24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgNft24 = (props: SVGProps) => ( diff --git a/apps/icons/src/NftType3D24.tsx b/apps/icons/src/NftType3D24.tsx index 760eb4cfdf4..91092d0bfd0 100644 --- a/apps/icons/src/NftType3D24.tsx +++ b/apps/icons/src/NftType3D24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgNftType3D24 = (props: SVGProps) => ( diff --git a/apps/icons/src/NftTypeAudio24.tsx b/apps/icons/src/NftTypeAudio24.tsx index 7a63fb8175c..bbcecc2dd71 100644 --- a/apps/icons/src/NftTypeAudio24.tsx +++ b/apps/icons/src/NftTypeAudio24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgNftTypeAudio24 = (props: SVGProps) => ( diff --git a/apps/icons/src/NftTypeImage24.tsx b/apps/icons/src/NftTypeImage24.tsx index 5fc79e3a162..7b9fdf19a1e 100644 --- a/apps/icons/src/NftTypeImage24.tsx +++ b/apps/icons/src/NftTypeImage24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgNftTypeImage24 = (props: SVGProps) => ( diff --git a/apps/icons/src/NftTypeVideo24.tsx b/apps/icons/src/NftTypeVideo24.tsx index c3fc2662d13..01bef06f28c 100644 --- a/apps/icons/src/NftTypeVideo24.tsx +++ b/apps/icons/src/NftTypeVideo24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgNftTypeVideo24 = (props: SVGProps) => ( diff --git a/apps/icons/src/ObjectDetailsHeader.tsx b/apps/icons/src/ObjectDetailsHeader.tsx index e79b3c58176..141c9fbaa0d 100644 --- a/apps/icons/src/ObjectDetailsHeader.tsx +++ b/apps/icons/src/ObjectDetailsHeader.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgObjectDetailsHeader = (props: SVGProps) => ( diff --git a/apps/icons/src/Ooo16.tsx b/apps/icons/src/Ooo16.tsx index 7ebb45b4058..06b2cf8211c 100644 --- a/apps/icons/src/Ooo16.tsx +++ b/apps/icons/src/Ooo16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgOoo16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Ooo24.tsx b/apps/icons/src/Ooo24.tsx index 94d20f1705b..852ed3af9de 100644 --- a/apps/icons/src/Ooo24.tsx +++ b/apps/icons/src/Ooo24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgOoo24 = (props: SVGProps) => ( diff --git a/apps/icons/src/PaginationFirst24.tsx b/apps/icons/src/PaginationFirst24.tsx index 161238e15bc..4f5dd62cf6e 100644 --- a/apps/icons/src/PaginationFirst24.tsx +++ b/apps/icons/src/PaginationFirst24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgPaginationFirst24 = (props: SVGProps) => ( diff --git a/apps/icons/src/PaginationNext24.tsx b/apps/icons/src/PaginationNext24.tsx index a28e950412c..b57d0f25460 100644 --- a/apps/icons/src/PaginationNext24.tsx +++ b/apps/icons/src/PaginationNext24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgPaginationNext24 = (props: SVGProps) => ( diff --git a/apps/icons/src/PaginationPrev24.tsx b/apps/icons/src/PaginationPrev24.tsx index a2456ee68b0..058c3c8ef73 100644 --- a/apps/icons/src/PaginationPrev24.tsx +++ b/apps/icons/src/PaginationPrev24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgPaginationPrev24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Pin16.tsx b/apps/icons/src/Pin16.tsx index 51f704eba0e..9565819bdd3 100644 --- a/apps/icons/src/Pin16.tsx +++ b/apps/icons/src/Pin16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgPin16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Plus12.tsx b/apps/icons/src/Plus12.tsx index 97dc759b0a3..38ed0aaf6a4 100644 --- a/apps/icons/src/Plus12.tsx +++ b/apps/icons/src/Plus12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgPlus12 = (props: SVGProps) => ( diff --git a/apps/icons/src/Plus32.tsx b/apps/icons/src/Plus32.tsx index a5ec70894ab..b36c9a9e042 100644 --- a/apps/icons/src/Plus32.tsx +++ b/apps/icons/src/Plus32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgPlus32 = (props: SVGProps) => ( diff --git a/apps/icons/src/Preview12.tsx b/apps/icons/src/Preview12.tsx index 46bf40b2b1a..4fd81117b65 100644 --- a/apps/icons/src/Preview12.tsx +++ b/apps/icons/src/Preview12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgPreview12 = (props: SVGProps) => ( diff --git a/apps/icons/src/Publish16.tsx b/apps/icons/src/Publish16.tsx index d2347cd8fbf..91f866feeb5 100644 --- a/apps/icons/src/Publish16.tsx +++ b/apps/icons/src/Publish16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgPublish16 = (props: SVGProps) => ( diff --git a/apps/icons/src/QrCode.tsx b/apps/icons/src/QrCode.tsx index b45efce84f8..0744b972797 100644 --- a/apps/icons/src/QrCode.tsx +++ b/apps/icons/src/QrCode.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgQrCode = (props: SVGProps) => ( diff --git a/apps/icons/src/Receive16.tsx b/apps/icons/src/Receive16.tsx index c4d52e51bb9..4b6f8ec0117 100644 --- a/apps/icons/src/Receive16.tsx +++ b/apps/icons/src/Receive16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgReceive16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Receive24.tsx b/apps/icons/src/Receive24.tsx index 9ad73af0522..0ed1c257430 100644 --- a/apps/icons/src/Receive24.tsx +++ b/apps/icons/src/Receive24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgReceive24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Refresh16.tsx b/apps/icons/src/Refresh16.tsx index 64150e7951c..4ef53a65717 100644 --- a/apps/icons/src/Refresh16.tsx +++ b/apps/icons/src/Refresh16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgRefresh16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Search16.tsx b/apps/icons/src/Search16.tsx index 22af3f1c58e..fa4de033479 100644 --- a/apps/icons/src/Search16.tsx +++ b/apps/icons/src/Search16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSearch16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Search24.tsx b/apps/icons/src/Search24.tsx index 5291dfb4295..fa6b6996cb2 100644 --- a/apps/icons/src/Search24.tsx +++ b/apps/icons/src/Search24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSearch24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Send24.tsx b/apps/icons/src/Send24.tsx index efe7f2c111c..ea61072e76d 100644 --- a/apps/icons/src/Send24.tsx +++ b/apps/icons/src/Send24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSend24 = (props: SVGProps) => ( diff --git a/apps/icons/src/SendReceive16.tsx b/apps/icons/src/SendReceive16.tsx index 990b4ab69b5..635dfdb0f50 100644 --- a/apps/icons/src/SendReceive16.tsx +++ b/apps/icons/src/SendReceive16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSendReceive16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Sender16.tsx b/apps/icons/src/Sender16.tsx index 087d2c6acc4..b1deecc09fe 100644 --- a/apps/icons/src/Sender16.tsx +++ b/apps/icons/src/Sender16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSender16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Settings16.tsx b/apps/icons/src/Settings16.tsx index 7e6d3cec011..8b29ca11f64 100644 --- a/apps/icons/src/Settings16.tsx +++ b/apps/icons/src/Settings16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSettings16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Settings24.tsx b/apps/icons/src/Settings24.tsx index 23ef55a5cae..97030ae482e 100644 --- a/apps/icons/src/Settings24.tsx +++ b/apps/icons/src/Settings24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSettings24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Settings32.tsx b/apps/icons/src/Settings32.tsx index be63d9cf074..2013e5d9bfa 100644 --- a/apps/icons/src/Settings32.tsx +++ b/apps/icons/src/Settings32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSettings32 = (props: SVGProps) => ( diff --git a/apps/icons/src/SocialDiscord24.tsx b/apps/icons/src/SocialDiscord24.tsx index d14a4206867..ad41094bda3 100644 --- a/apps/icons/src/SocialDiscord24.tsx +++ b/apps/icons/src/SocialDiscord24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSocialDiscord24 = (props: SVGProps) => ( diff --git a/apps/icons/src/SocialFacebook24.tsx b/apps/icons/src/SocialFacebook24.tsx index 5adc9769611..9c606c32823 100644 --- a/apps/icons/src/SocialFacebook24.tsx +++ b/apps/icons/src/SocialFacebook24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSocialFacebook24 = (props: SVGProps) => ( diff --git a/apps/icons/src/SocialGithub24.tsx b/apps/icons/src/SocialGithub24.tsx index 953411425ab..21682f6a99c 100644 --- a/apps/icons/src/SocialGithub24.tsx +++ b/apps/icons/src/SocialGithub24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSocialGithub24 = (props: SVGProps) => ( diff --git a/apps/icons/src/SocialGoogle24.tsx b/apps/icons/src/SocialGoogle24.tsx index 46daedf9328..7cbde70ed65 100644 --- a/apps/icons/src/SocialGoogle24.tsx +++ b/apps/icons/src/SocialGoogle24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSocialGoogle24 = (props: SVGProps) => ( diff --git a/apps/icons/src/SocialKakao24.tsx b/apps/icons/src/SocialKakao24.tsx index 5dddf65d3ec..5a279f09902 100644 --- a/apps/icons/src/SocialKakao24.tsx +++ b/apps/icons/src/SocialKakao24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSocialKakao24 = (props: SVGProps) => ( diff --git a/apps/icons/src/SocialLinkedin24.tsx b/apps/icons/src/SocialLinkedin24.tsx index a5b84944562..9d73041a9f7 100644 --- a/apps/icons/src/SocialLinkedin24.tsx +++ b/apps/icons/src/SocialLinkedin24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSocialLinkedin24 = (props: SVGProps) => ( diff --git a/apps/icons/src/SocialMedium24.tsx b/apps/icons/src/SocialMedium24.tsx index abe836540bf..08ff5b3f098 100644 --- a/apps/icons/src/SocialMedium24.tsx +++ b/apps/icons/src/SocialMedium24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSocialMedium24 = (props: SVGProps) => ( diff --git a/apps/icons/src/SocialMicrosoft24.tsx b/apps/icons/src/SocialMicrosoft24.tsx index 0abdbb330e0..5a95d08d0c9 100644 --- a/apps/icons/src/SocialMicrosoft24.tsx +++ b/apps/icons/src/SocialMicrosoft24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSocialMicrosoft24 = (props: SVGProps) => ( diff --git a/apps/icons/src/SocialTwitch24.tsx b/apps/icons/src/SocialTwitch24.tsx index 34de847e9ba..25ef11d369e 100644 --- a/apps/icons/src/SocialTwitch24.tsx +++ b/apps/icons/src/SocialTwitch24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSocialTwitch24 = (props: SVGProps) => ( diff --git a/apps/icons/src/SocialTwitter24.tsx b/apps/icons/src/SocialTwitter24.tsx index 50330ddea4a..ca88dbcc2a4 100644 --- a/apps/icons/src/SocialTwitter24.tsx +++ b/apps/icons/src/SocialTwitter24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSocialTwitter24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Spinner16.tsx b/apps/icons/src/Spinner16.tsx index beebbcb74b7..e4544156db6 100644 --- a/apps/icons/src/Spinner16.tsx +++ b/apps/icons/src/Spinner16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSpinner16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Spinner24.tsx b/apps/icons/src/Spinner24.tsx index 5743a99feff..7c4f3564a69 100644 --- a/apps/icons/src/Spinner24.tsx +++ b/apps/icons/src/Spinner24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSpinner24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Stack16.tsx b/apps/icons/src/Stack16.tsx index b88f2c5149a..bf052c359ed 100644 --- a/apps/icons/src/Stack16.tsx +++ b/apps/icons/src/Stack16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgStack16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Stake24.tsx b/apps/icons/src/Stake24.tsx index 64672e9eddf..450e2921e7d 100644 --- a/apps/icons/src/Stake24.tsx +++ b/apps/icons/src/Stake24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgStake24 = (props: SVGProps) => ( diff --git a/apps/icons/src/StakeAdd16.tsx b/apps/icons/src/StakeAdd16.tsx index 85c64832c31..b8ab5b0a2f5 100644 --- a/apps/icons/src/StakeAdd16.tsx +++ b/apps/icons/src/StakeAdd16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgStakeAdd16 = (props: SVGProps) => ( diff --git a/apps/icons/src/StakeRemove16.tsx b/apps/icons/src/StakeRemove16.tsx index b9ba163faa9..effe9c60dc6 100644 --- a/apps/icons/src/StakeRemove16.tsx +++ b/apps/icons/src/StakeRemove16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgStakeRemove16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Staking32.tsx b/apps/icons/src/Staking32.tsx index 7b9b53acd3e..af6b82b4c9c 100644 --- a/apps/icons/src/Staking32.tsx +++ b/apps/icons/src/Staking32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgStaking32 = (props: SVGProps) => ( diff --git a/apps/icons/src/Sui.tsx b/apps/icons/src/Sui.tsx deleted file mode 100644 index f53e7ab18b2..00000000000 --- a/apps/icons/src/Sui.tsx +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -import { SVGProps } from 'react'; -const SvgSui = (props: SVGProps) => ( - - - -); -export default SvgSui; diff --git a/apps/icons/src/SuiCustomRpc.tsx b/apps/icons/src/SuiCustomRpc.tsx deleted file mode 100644 index 363220e2df0..00000000000 --- a/apps/icons/src/SuiCustomRpc.tsx +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -import { SVGProps } from 'react'; -const SvgSuiCustomRpc = (props: SVGProps) => ( - - - -); -export default SvgSuiCustomRpc; diff --git a/apps/icons/src/SuiDevnet.tsx b/apps/icons/src/SuiDevnet.tsx deleted file mode 100644 index 62f5c58748f..00000000000 --- a/apps/icons/src/SuiDevnet.tsx +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -import { SVGProps } from 'react'; -const SvgSuiDevnet = (props: SVGProps) => ( - - - -); -export default SvgSuiDevnet; diff --git a/apps/icons/src/SuiLocal.tsx b/apps/icons/src/SuiLocal.tsx deleted file mode 100644 index e50f6b2b527..00000000000 --- a/apps/icons/src/SuiLocal.tsx +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -import { SVGProps } from 'react'; -const SvgSuiLocal = (props: SVGProps) => ( - - - -); -export default SvgSuiLocal; diff --git a/apps/icons/src/SuiLogoTxt.tsx b/apps/icons/src/SuiLogoTxt.tsx deleted file mode 100644 index 33fa9ebc649..00000000000 --- a/apps/icons/src/SuiLogoTxt.tsx +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -import { SVGProps } from 'react'; -const SvgSuiLogoTxt = (props: SVGProps) => ( - - - -); -export default SvgSuiLogoTxt; diff --git a/apps/icons/src/SuiMainnet.tsx b/apps/icons/src/SuiMainnet.tsx deleted file mode 100644 index 26ba408acf1..00000000000 --- a/apps/icons/src/SuiMainnet.tsx +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -import { SVGProps } from 'react'; -const SvgSuiMainnet = (props: SVGProps) => ( - - - -); -export default SvgSuiMainnet; diff --git a/apps/icons/src/SuiTestnet.tsx b/apps/icons/src/SuiTestnet.tsx deleted file mode 100644 index 3420bcfd858..00000000000 --- a/apps/icons/src/SuiTestnet.tsx +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -import { SVGProps } from 'react'; -const SvgSuiTestnet = (props: SVGProps) => ( - - - -); -export default SvgSuiTestnet; diff --git a/apps/icons/src/SuiTokensStack.tsx b/apps/icons/src/SuiTokensStack.tsx deleted file mode 100644 index 17c87548d9b..00000000000 --- a/apps/icons/src/SuiTokensStack.tsx +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -import { SVGProps } from 'react'; -const SvgSuiTokensStack = (props: SVGProps) => ( - - - - - - - - - - - - - - -); -export default SvgSuiTokensStack; diff --git a/apps/icons/src/Support24.tsx b/apps/icons/src/Support24.tsx index e1fd4a947bb..65e74ef29a5 100644 --- a/apps/icons/src/Support24.tsx +++ b/apps/icons/src/Support24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSupport24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Swap16.tsx b/apps/icons/src/Swap16.tsx index 88b2dee9781..d4abb29ac45 100644 --- a/apps/icons/src/Swap16.tsx +++ b/apps/icons/src/Swap16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgSwap16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Tag16.tsx b/apps/icons/src/Tag16.tsx index 6d30c498062..b582b94f344 100644 --- a/apps/icons/src/Tag16.tsx +++ b/apps/icons/src/Tag16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgTag16 = (props: SVGProps) => ( diff --git a/apps/icons/src/ThumbDownFill12.tsx b/apps/icons/src/ThumbDownFill12.tsx index 914eafc141a..3a99cba8728 100644 --- a/apps/icons/src/ThumbDownFill12.tsx +++ b/apps/icons/src/ThumbDownFill12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgThumbDownFill12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ThumbDownFill24.tsx b/apps/icons/src/ThumbDownFill24.tsx index 081aa3d6bb8..9417d916be3 100644 --- a/apps/icons/src/ThumbDownFill24.tsx +++ b/apps/icons/src/ThumbDownFill24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgThumbDownFill24 = (props: SVGProps) => ( diff --git a/apps/icons/src/ThumbDownFill32.tsx b/apps/icons/src/ThumbDownFill32.tsx index fb342cbd9e6..98f751f0aa2 100644 --- a/apps/icons/src/ThumbDownFill32.tsx +++ b/apps/icons/src/ThumbDownFill32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgThumbDownFill32 = (props: SVGProps) => ( diff --git a/apps/icons/src/ThumbDownStroke24.tsx b/apps/icons/src/ThumbDownStroke24.tsx index 358a96707cb..84e7613713d 100644 --- a/apps/icons/src/ThumbDownStroke24.tsx +++ b/apps/icons/src/ThumbDownStroke24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgThumbDownStroke24 = (props: SVGProps) => ( diff --git a/apps/icons/src/ThumbDownStroke32.tsx b/apps/icons/src/ThumbDownStroke32.tsx index 71617fb7044..8557c06c278 100644 --- a/apps/icons/src/ThumbDownStroke32.tsx +++ b/apps/icons/src/ThumbDownStroke32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgThumbDownStroke32 = (props: SVGProps) => ( diff --git a/apps/icons/src/ThumbUpFill12.tsx b/apps/icons/src/ThumbUpFill12.tsx index 65dff736dbf..52d110a728f 100644 --- a/apps/icons/src/ThumbUpFill12.tsx +++ b/apps/icons/src/ThumbUpFill12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgThumbUpFill12 = (props: SVGProps) => ( diff --git a/apps/icons/src/ThumbUpFill24.tsx b/apps/icons/src/ThumbUpFill24.tsx index e1f01350723..e67a322bba6 100644 --- a/apps/icons/src/ThumbUpFill24.tsx +++ b/apps/icons/src/ThumbUpFill24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgThumbUpFill24 = (props: SVGProps) => ( diff --git a/apps/icons/src/ThumbUpFill32.tsx b/apps/icons/src/ThumbUpFill32.tsx index fe4218b3334..25b7b21ae8c 100644 --- a/apps/icons/src/ThumbUpFill32.tsx +++ b/apps/icons/src/ThumbUpFill32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgThumbUpFill32 = (props: SVGProps) => ( diff --git a/apps/icons/src/ThumbUpStroke24.tsx b/apps/icons/src/ThumbUpStroke24.tsx index e6022034d82..b0b19f1c97b 100644 --- a/apps/icons/src/ThumbUpStroke24.tsx +++ b/apps/icons/src/ThumbUpStroke24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgThumbUpStroke24 = (props: SVGProps) => ( diff --git a/apps/icons/src/ThumbUpStroke32.tsx b/apps/icons/src/ThumbUpStroke32.tsx index 8da8904ac37..a6355c1d316 100644 --- a/apps/icons/src/ThumbUpStroke32.tsx +++ b/apps/icons/src/ThumbUpStroke32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgThumbUpStroke32 = (props: SVGProps) => ( diff --git a/apps/icons/src/ThumbnailsOnly16.tsx b/apps/icons/src/ThumbnailsOnly16.tsx index 8d7bb4a0ca8..58a5d3a9f99 100644 --- a/apps/icons/src/ThumbnailsOnly16.tsx +++ b/apps/icons/src/ThumbnailsOnly16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgThumbnailsOnly16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Tokens32.tsx b/apps/icons/src/Tokens32.tsx index 2a27b601b5b..d79d2f322aa 100644 --- a/apps/icons/src/Tokens32.tsx +++ b/apps/icons/src/Tokens32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgTokens32 = (props: SVGProps) => ( diff --git a/apps/icons/src/TransferIota16.tsx b/apps/icons/src/TransferIota16.tsx new file mode 100644 index 00000000000..def581ef388 --- /dev/null +++ b/apps/icons/src/TransferIota16.tsx @@ -0,0 +1,22 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +import { SVGProps } from 'react'; +const SvgTransferIota16 = (props: SVGProps) => ( + + + +); +export default SvgTransferIota16; diff --git a/apps/icons/src/TransferObject16.tsx b/apps/icons/src/TransferObject16.tsx index 85e364eae90..3e41ef1ed16 100644 --- a/apps/icons/src/TransferObject16.tsx +++ b/apps/icons/src/TransferObject16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgTransferObject16 = (props: SVGProps) => ( diff --git a/apps/icons/src/TransferSui16.tsx b/apps/icons/src/TransferSui16.tsx deleted file mode 100644 index a3c4f031f27..00000000000 --- a/apps/icons/src/TransferSui16.tsx +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -import { SVGProps } from 'react'; -const SvgTransferSui16 = (props: SVGProps) => ( - - - -); -export default SvgTransferSui16; diff --git a/apps/icons/src/Unpin16.tsx b/apps/icons/src/Unpin16.tsx index 80356a3c1e5..07e0c69654a 100644 --- a/apps/icons/src/Unpin16.tsx +++ b/apps/icons/src/Unpin16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgUnpin16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Unstaked.tsx b/apps/icons/src/Unstaked.tsx index 61204837915..c28370a1081 100644 --- a/apps/icons/src/Unstaked.tsx +++ b/apps/icons/src/Unstaked.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgUnstaked = (props: SVGProps) => ( diff --git a/apps/icons/src/Version24.tsx b/apps/icons/src/Version24.tsx index cb6c81f3722..a75899a21f6 100644 --- a/apps/icons/src/Version24.tsx +++ b/apps/icons/src/Version24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgVersion24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Video32.tsx b/apps/icons/src/Video32.tsx index 48c622760ad..0c76b0b3624 100644 --- a/apps/icons/src/Video32.tsx +++ b/apps/icons/src/Video32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgVideo32 = (props: SVGProps) => ( diff --git a/apps/icons/src/ViewList16.tsx b/apps/icons/src/ViewList16.tsx index e8250073fa8..703925eb7d2 100644 --- a/apps/icons/src/ViewList16.tsx +++ b/apps/icons/src/ViewList16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgViewList16 = (props: SVGProps) => ( diff --git a/apps/icons/src/ViewSmallThumbnails16.tsx b/apps/icons/src/ViewSmallThumbnails16.tsx index 99e69ce0b78..635b3a08b10 100644 --- a/apps/icons/src/ViewSmallThumbnails16.tsx +++ b/apps/icons/src/ViewSmallThumbnails16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgViewSmallThumbnails16 = (props: SVGProps) => ( diff --git a/apps/icons/src/Wallet24.tsx b/apps/icons/src/Wallet24.tsx index a2e24dec1ce..1a47358312e 100644 --- a/apps/icons/src/Wallet24.tsx +++ b/apps/icons/src/Wallet24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgWallet24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Wallet32.tsx b/apps/icons/src/Wallet32.tsx index 615fe06ba73..3edf2b674a1 100644 --- a/apps/icons/src/Wallet32.tsx +++ b/apps/icons/src/Wallet32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgWallet32 = (props: SVGProps) => ( diff --git a/apps/icons/src/WalletActionBuy24.tsx b/apps/icons/src/WalletActionBuy24.tsx index 6ab4d3be703..f650d8e7f42 100644 --- a/apps/icons/src/WalletActionBuy24.tsx +++ b/apps/icons/src/WalletActionBuy24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgWalletActionBuy24 = (props: SVGProps) => ( diff --git a/apps/icons/src/WalletActionSend24.tsx b/apps/icons/src/WalletActionSend24.tsx index 3361153125c..3b7eeeb8c84 100644 --- a/apps/icons/src/WalletActionSend24.tsx +++ b/apps/icons/src/WalletActionSend24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgWalletActionSend24 = (props: SVGProps) => ( diff --git a/apps/icons/src/WalletActionStake24.tsx b/apps/icons/src/WalletActionStake24.tsx index c2ff35398e6..d8e175593ff 100644 --- a/apps/icons/src/WalletActionStake24.tsx +++ b/apps/icons/src/WalletActionStake24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgWalletActionStake24 = (props: SVGProps) => ( diff --git a/apps/icons/src/WalletActionSwap24.tsx b/apps/icons/src/WalletActionSwap24.tsx index a0ff3df37ca..116458bbba1 100644 --- a/apps/icons/src/WalletActionSwap24.tsx +++ b/apps/icons/src/WalletActionSwap24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgWalletActionSwap24 = (props: SVGProps) => ( diff --git a/apps/icons/src/Warning16.tsx b/apps/icons/src/Warning16.tsx index 074d19ea0b4..ce2bf392b03 100644 --- a/apps/icons/src/Warning16.tsx +++ b/apps/icons/src/Warning16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgWarning16 = (props: SVGProps) => ( diff --git a/apps/icons/src/X12.tsx b/apps/icons/src/X12.tsx index 924222e6289..87de1d500bb 100644 --- a/apps/icons/src/X12.tsx +++ b/apps/icons/src/X12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgX12 = (props: SVGProps) => ( diff --git a/apps/icons/src/X32.tsx b/apps/icons/src/X32.tsx index fb74bb2eb87..a87f7c6bfa9 100644 --- a/apps/icons/src/X32.tsx +++ b/apps/icons/src/X32.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgX32 = (props: SVGProps) => ( diff --git a/apps/icons/src/XDark24.tsx b/apps/icons/src/XDark24.tsx index 3fc6d448af2..451503d1cdb 100644 --- a/apps/icons/src/XDark24.tsx +++ b/apps/icons/src/XDark24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgXDark24 = (props: SVGProps) => ( diff --git a/apps/icons/src/XFill12.tsx b/apps/icons/src/XFill12.tsx index 505b6ceb583..8ad9a571bf3 100644 --- a/apps/icons/src/XFill12.tsx +++ b/apps/icons/src/XFill12.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgXFill12 = (props: SVGProps) => ( diff --git a/apps/icons/src/XFill16.tsx b/apps/icons/src/XFill16.tsx index 02da4dff4d4..209120f2ebe 100644 --- a/apps/icons/src/XFill16.tsx +++ b/apps/icons/src/XFill16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgXFill16 = (props: SVGProps) => ( diff --git a/apps/icons/src/XLight24.tsx b/apps/icons/src/XLight24.tsx index 173cb8d7399..f9ae157c95b 100644 --- a/apps/icons/src/XLight24.tsx +++ b/apps/icons/src/XLight24.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgXLight24 = (props: SVGProps) => ( diff --git a/apps/icons/src/XStroke16.tsx b/apps/icons/src/XStroke16.tsx index ccf451fab65..a87a8a9e09f 100644 --- a/apps/icons/src/XStroke16.tsx +++ b/apps/icons/src/XStroke16.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { SVGProps } from 'react'; const SvgXStroke16 = (props: SVGProps) => ( diff --git a/apps/icons/src/index.ts b/apps/icons/src/index.ts index e02202a07d2..d47f221bc8f 100644 --- a/apps/icons/src/index.ts +++ b/apps/icons/src/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export { default as Svg3D32 } from './3D32'; export { default as Nft16 } from './Nft16'; @@ -143,14 +144,14 @@ export { default as Stake24 } from './Stake24'; export { default as StakeAdd16 } from './StakeAdd16'; export { default as StakeRemove16 } from './StakeRemove16'; export { default as Staking32 } from './Staking32'; -export { default as SuiLogoTxt } from './SuiLogoTxt'; -export { default as Sui } from './Sui'; -export { default as SuiCustomRpc } from './SuiCustomRpc'; -export { default as SuiDevnet } from './SuiDevnet'; -export { default as SuiLocal } from './SuiLocal'; -export { default as SuiMainnet } from './SuiMainnet'; -export { default as SuiTestnet } from './SuiTestnet'; -export { default as SuiTokensStack } from './SuiTokensStack'; +export { default as IotaLogoTxt } from './IotaLogoTxt'; +export { default as Iota } from './Iota'; +export { default as IotaCustomRpc } from './IotaCustomRpc'; +export { default as IotaDevnet } from './IotaDevnet'; +export { default as IotaLocal } from './IotaLocal'; +export { default as IotaMainnet } from './IotaMainnet'; +export { default as IotaTestnet } from './IotaTestnet'; +export { default as IotaTokensStack } from './IotaTokensStack'; export { default as Support24 } from './Support24'; export { default as Swap16 } from './Swap16'; export { default as Tag16 } from './Tag16'; @@ -167,7 +168,7 @@ export { default as ThumbUpStroke32 } from './ThumbUpStroke32'; export { default as ThumbnailsOnly16 } from './ThumbnailsOnly16'; export { default as Tokens32 } from './Tokens32'; export { default as TransferObject16 } from './TransferObject16'; -export { default as TransferSui16 } from './TransferSui16'; +export { default as TransferIota16 } from './TransferIota16'; export { default as Unpin16 } from './Unpin16'; export { default as Unstaked } from './Unstaked'; export { default as Version24 } from './Version24'; diff --git a/apps/icons/svgs/sui-logo-txt.svg b/apps/icons/svgs/iota-logo-txt.svg similarity index 100% rename from apps/icons/svgs/sui-logo-txt.svg rename to apps/icons/svgs/iota-logo-txt.svg diff --git a/apps/icons/svgs/sui.svg b/apps/icons/svgs/iota.svg similarity index 100% rename from apps/icons/svgs/sui.svg rename to apps/icons/svgs/iota.svg diff --git a/apps/icons/svgs/sui_customRPC.svg b/apps/icons/svgs/iota_customRPC.svg similarity index 100% rename from apps/icons/svgs/sui_customRPC.svg rename to apps/icons/svgs/iota_customRPC.svg diff --git a/apps/icons/svgs/sui_devnet.svg b/apps/icons/svgs/iota_devnet.svg similarity index 100% rename from apps/icons/svgs/sui_devnet.svg rename to apps/icons/svgs/iota_devnet.svg diff --git a/apps/icons/svgs/sui_local.svg b/apps/icons/svgs/iota_local.svg similarity index 100% rename from apps/icons/svgs/sui_local.svg rename to apps/icons/svgs/iota_local.svg diff --git a/apps/icons/svgs/sui_mainnet.svg b/apps/icons/svgs/iota_mainnet.svg similarity index 100% rename from apps/icons/svgs/sui_mainnet.svg rename to apps/icons/svgs/iota_mainnet.svg diff --git a/apps/icons/svgs/sui_testnet.svg b/apps/icons/svgs/iota_testnet.svg similarity index 100% rename from apps/icons/svgs/sui_testnet.svg rename to apps/icons/svgs/iota_testnet.svg diff --git a/apps/icons/svgs/sui_tokens_stack.svg b/apps/icons/svgs/iota_tokens_stack.svg similarity index 100% rename from apps/icons/svgs/sui_tokens_stack.svg rename to apps/icons/svgs/iota_tokens_stack.svg diff --git a/apps/icons/svgs/transfer_sui_16.svg b/apps/icons/svgs/transfer_iota_16.svg similarity index 100% rename from apps/icons/svgs/transfer_sui_16.svg rename to apps/icons/svgs/transfer_iota_16.svg diff --git a/apps/ui/.eslintignore b/apps/ui/.eslintignore deleted file mode 100644 index 9dc806bb9b0..00000000000 --- a/apps/ui/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -storybook-static/ -node_modules/ -postcss.config.js diff --git a/apps/ui/package.json b/apps/ui/package.json index 72f1f5cece7..f3860884ac4 100644 --- a/apps/ui/package.json +++ b/apps/ui/package.json @@ -1,12 +1,12 @@ { - "name": "@mysten/ui", + "name": "@iota/ui", "private": true, "sideEffects": false, "main": "./src/index.ts", "author": "Mysten Labs ", "repository": { "type": "git", - "url": "github.com:MystenLabs/sui.git" + "url": "github.com:iotaledger/iota.git" }, "license": "Apache-2.0", "exports": { @@ -29,8 +29,8 @@ "build-storybook": "tsc -b && storybook build" }, "dependencies": { - "@mysten/core": "workspace:*", - "@mysten/icons": "workspace:*", + "@iota/core": "workspace:*", + "@iota/icons": "workspace:*", "@radix-ui/react-radio-group": "^1.1.3", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-switch": "^1.0.3", diff --git a/apps/ui/postcss.config.js b/apps/ui/postcss.config.js index 5b5696cafbb..23af4016123 100644 --- a/apps/ui/postcss.config.js +++ b/apps/ui/postcss.config.js @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module.exports = { diff --git a/apps/ui/src/Button.stories.tsx b/apps/ui/src/Button.stories.tsx index 118c9af03da..c87f6750639 100644 --- a/apps/ui/src/Button.stories.tsx +++ b/apps/ui/src/Button.stories.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { CheckFill16, Search16 } from '@mysten/icons'; +import { CheckFill16, Search16 } from '@iota/icons'; import type { Meta, StoryObj } from '@storybook/react'; import { Button } from './Button'; diff --git a/apps/ui/src/Button.tsx b/apps/ui/src/Button.tsx index ab3f7d46b7b..f121e870303 100644 --- a/apps/ui/src/Button.tsx +++ b/apps/ui/src/Button.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Slot } from '@radix-ui/react-slot'; @@ -10,7 +11,7 @@ import { LoadingIndicator } from './LoadingIndicator'; const buttonStyles = cva(['inline-flex flex-nowrap items-center justify-center gap-2 relative'], { variants: { variant: { - primary: 'bg-sui-dark text-sui-light hover:text-white border-none', + primary: 'bg-iota-dark text-iota-light hover:text-white border-none', secondary: 'bg-gray-90 text-gray-50 hover:text-white border-none', outline: 'bg-white border border-steel text-steel-dark hover:text-steel-darker hover:border-steel-dark active:text-steel active:border-steel disabled:border-gray-45 disabled:text-steel-dark', diff --git a/apps/ui/src/Combobox.tsx b/apps/ui/src/Combobox.tsx index 8b5085fba79..4c4cd801cc5 100644 --- a/apps/ui/src/Combobox.tsx +++ b/apps/ui/src/Combobox.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Command } from 'cmdk'; @@ -33,7 +34,7 @@ function ComboboxItem({ item, onSelect }: ComboboxItemProps) { return ( onSelect()} >
diff --git a/apps/ui/src/Heading.stories.tsx b/apps/ui/src/Heading.stories.tsx index 3ec53576fcb..a22196fc9a0 100644 --- a/apps/ui/src/Heading.stories.tsx +++ b/apps/ui/src/Heading.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/ui/src/Heading.tsx b/apps/ui/src/Heading.tsx index ad7c7a809fb..72b9971eeae 100644 --- a/apps/ui/src/Heading.tsx +++ b/apps/ui/src/Heading.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { cva, type VariantProps } from 'class-variance-authority'; @@ -29,9 +30,9 @@ const headingStyles = cva([], { 'gray-70': 'text-gray-70', 'gray-65': 'text-gray-65', 'gray-35': 'text-gray-35', - 'sui-dark': 'text-sui-dark', - sui: 'text-sui', - 'sui-light': 'text-sui-light', + 'iota-dark': 'text-iota-dark', + iota: 'text-iota', + 'iota-light': 'text-iota-light', steel: 'text-steel', 'steel-dark': 'text-steel-dark', 'steel-darker': 'text-steel-darker', diff --git a/apps/ui/src/IconButton.stories.tsx b/apps/ui/src/IconButton.stories.tsx index c9046db7819..f2012cda4d5 100644 --- a/apps/ui/src/IconButton.stories.tsx +++ b/apps/ui/src/IconButton.stories.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { X12 } from '@mysten/icons'; +import { X12 } from '@iota/icons'; import { type Meta, type StoryObj } from '@storybook/react'; import { IconButton } from './IconButton'; diff --git a/apps/ui/src/IconButton.tsx b/apps/ui/src/IconButton.tsx index 88789531164..8d78d94e9a7 100644 --- a/apps/ui/src/IconButton.tsx +++ b/apps/ui/src/IconButton.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Slot } from '@radix-ui/react-slot'; diff --git a/apps/ui/src/LoadingIndicator.stories.tsx b/apps/ui/src/LoadingIndicator.stories.tsx index 32a1679ba9b..e9bb33e4a09 100644 --- a/apps/ui/src/LoadingIndicator.stories.tsx +++ b/apps/ui/src/LoadingIndicator.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import type { Meta, StoryObj } from '@storybook/react'; diff --git a/apps/ui/src/LoadingIndicator.tsx b/apps/ui/src/LoadingIndicator.tsx index 9f0bd73c4f7..7088246b34a 100644 --- a/apps/ui/src/LoadingIndicator.tsx +++ b/apps/ui/src/LoadingIndicator.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Spinner16, Spinner24 } from '@mysten/icons'; +import { Spinner16, Spinner24 } from '@iota/icons'; import { cva, type VariantProps } from 'class-variance-authority'; const loadingIndicatorStyles = cva('animate-spin text-steel', { diff --git a/apps/ui/src/Placeholder.stories.tsx b/apps/ui/src/Placeholder.stories.tsx index 93faddb65aa..2bba46d2c0e 100644 --- a/apps/ui/src/Placeholder.stories.tsx +++ b/apps/ui/src/Placeholder.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/ui/src/Placeholder.tsx b/apps/ui/src/Placeholder.tsx index 22cbc2801f3..2dbf931bd67 100644 --- a/apps/ui/src/Placeholder.tsx +++ b/apps/ui/src/Placeholder.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { cva, VariantProps } from 'class-variance-authority'; diff --git a/apps/ui/src/RadioGroup.stories.tsx b/apps/ui/src/RadioGroup.stories.tsx index 61a21efc883..b0fae7fa558 100644 --- a/apps/ui/src/RadioGroup.stories.tsx +++ b/apps/ui/src/RadioGroup.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/ui/src/RadioGroup.tsx b/apps/ui/src/RadioGroup.tsx index 5a119af730e..b6089eeb021 100644 --- a/apps/ui/src/RadioGroup.tsx +++ b/apps/ui/src/RadioGroup.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import * as RadioGroupPrimitive from '@radix-ui/react-radio-group'; diff --git a/apps/ui/src/Text.stories.tsx b/apps/ui/src/Text.stories.tsx index 6dd9d177b42..3b4f98f6cca 100644 --- a/apps/ui/src/Text.stories.tsx +++ b/apps/ui/src/Text.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/ui/src/Text.tsx b/apps/ui/src/Text.tsx index 633d7406ccd..ead649b3ccc 100644 --- a/apps/ui/src/Text.tsx +++ b/apps/ui/src/Text.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { cva, type VariantProps } from 'class-variance-authority'; @@ -36,9 +37,9 @@ const textStyles = cva(['break-words'], { 'gray-70': 'text-gray-70', 'gray-65': 'text-gray-65', 'gray-60': 'text-gray-60', - 'sui-dark': 'text-sui-dark', - sui: 'text-sui', - 'sui-light': 'text-sui-light', + 'iota-dark': 'text-iota-dark', + iota: 'text-iota', + 'iota-light': 'text-iota-light', steel: 'text-steel', 'steel-dark': 'text-steel-dark', 'steel-darker': 'text-steel-darker', diff --git a/apps/ui/src/Toggle.stories.tsx b/apps/ui/src/Toggle.stories.tsx index 8696a714e5d..4ea362efb96 100644 --- a/apps/ui/src/Toggle.stories.tsx +++ b/apps/ui/src/Toggle.stories.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Meta, type StoryObj } from '@storybook/react'; diff --git a/apps/ui/src/Toggle.tsx b/apps/ui/src/Toggle.tsx index ed398c63f3c..a9d4785c7aa 100644 --- a/apps/ui/src/Toggle.tsx +++ b/apps/ui/src/Toggle.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Root, Thumb, type SwitchProps } from '@radix-ui/react-switch'; diff --git a/apps/ui/src/hooks/useOnClickOutside.ts b/apps/ui/src/hooks/useOnClickOutside.ts index 644db20720e..8791df1071b 100644 --- a/apps/ui/src/hooks/useOnClickOutside.ts +++ b/apps/ui/src/hooks/useOnClickOutside.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useEffect } from 'react'; diff --git a/apps/ui/src/index.ts b/apps/ui/src/index.ts index 5e6d7a6d547..33957f8cd0d 100644 --- a/apps/ui/src/index.ts +++ b/apps/ui/src/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export * from './Button'; diff --git a/apps/ui/src/utils/Icons.stories.tsx b/apps/ui/src/utils/Icons.stories.tsx index ec69b8577de..ed93ee5a1cd 100644 --- a/apps/ui/src/utils/Icons.stories.tsx +++ b/apps/ui/src/utils/Icons.stories.tsx @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import * as Icons from '@mysten/icons'; +import * as Icons from '@iota/icons'; import { type Meta } from '@storybook/react'; export default { - title: '@mysten/icons', + title: '@iota/icons', } as Meta; export const AllIcons = { diff --git a/apps/ui/src/utils/sizeAndWeight.ts b/apps/ui/src/utils/sizeAndWeight.ts index a3ee254b17d..10adf040344 100644 --- a/apps/ui/src/utils/sizeAndWeight.ts +++ b/apps/ui/src/utils/sizeAndWeight.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 interface SizeAndWeightProps { diff --git a/apps/ui/tailwind.config.ts b/apps/ui/tailwind.config.ts index 6c5e0ffc4bb..63e6a2a9423 100644 --- a/apps/ui/tailwind.config.ts +++ b/apps/ui/tailwind.config.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import preset from '@mysten/core/tailwind.config'; +import preset from '@iota/core/tailwind.config'; import { type Config } from 'tailwindcss'; export default { diff --git a/apps/wallet-dashboard/app/dashboard/activity/page.tsx b/apps/wallet-dashboard/app/dashboard/activity/page.tsx index 04833304d4e..d3ee77520b9 100644 --- a/apps/wallet-dashboard/app/dashboard/activity/page.tsx +++ b/apps/wallet-dashboard/app/dashboard/activity/page.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; diff --git a/apps/wallet-dashboard/app/dashboard/apps/page.tsx b/apps/wallet-dashboard/app/dashboard/apps/page.tsx index cb6c956a6a4..294f8b02697 100644 --- a/apps/wallet-dashboard/app/dashboard/apps/page.tsx +++ b/apps/wallet-dashboard/app/dashboard/apps/page.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; diff --git a/apps/wallet-dashboard/app/dashboard/assets/everything-else/page.tsx b/apps/wallet-dashboard/app/dashboard/assets/everything-else/page.tsx index 43d0f6ad736..1996bbbc1f7 100644 --- a/apps/wallet-dashboard/app/dashboard/assets/everything-else/page.tsx +++ b/apps/wallet-dashboard/app/dashboard/assets/everything-else/page.tsx @@ -1,15 +1,16 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; import { HARDCODED_NON_VISUAL_ASSETS } from '@/lib/mocks'; import React from 'react'; -import { SuiObjectData } from '@mysten/sui.js/client'; +import { IotaObjectData } from '@iota/iota.js/client'; import { AssetCard, VirtualList } from '@/components/index'; function EverythingElsePage(): JSX.Element { - const virtualItem = (asset: SuiObjectData): JSX.Element => ( + const virtualItem = (asset: IotaObjectData): JSX.Element => ( ); diff --git a/apps/wallet-dashboard/app/dashboard/assets/layout.tsx b/apps/wallet-dashboard/app/dashboard/assets/layout.tsx index 2ace7b31545..6222aa2a9b5 100644 --- a/apps/wallet-dashboard/app/dashboard/assets/layout.tsx +++ b/apps/wallet-dashboard/app/dashboard/assets/layout.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; diff --git a/apps/wallet-dashboard/app/dashboard/assets/page.tsx b/apps/wallet-dashboard/app/dashboard/assets/page.tsx index df3cde7fea7..939d51076ab 100644 --- a/apps/wallet-dashboard/app/dashboard/assets/page.tsx +++ b/apps/wallet-dashboard/app/dashboard/assets/page.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 function AssetsDashboardPage(): JSX.Element { diff --git a/apps/wallet-dashboard/app/dashboard/assets/visual-assets/page.tsx b/apps/wallet-dashboard/app/dashboard/assets/visual-assets/page.tsx index 15859839780..68f9fc1518d 100644 --- a/apps/wallet-dashboard/app/dashboard/assets/visual-assets/page.tsx +++ b/apps/wallet-dashboard/app/dashboard/assets/visual-assets/page.tsx @@ -1,14 +1,15 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; import React from 'react'; -import { SuiObjectData } from '@mysten/sui.js/client'; +import { IotaObjectData } from '@iota/iota.js/client'; import { AssetCard, VirtualList } from '@/components/index'; function VisualAssetsPage(): JSX.Element { - const virtualItem = (asset: SuiObjectData): JSX.Element => ( + const virtualItem = (asset: IotaObjectData): JSX.Element => ( ); @@ -26,7 +27,7 @@ function VisualAssetsPage(): JSX.Element { ); } -const HARCODED_VISUAL_ASSETS: SuiObjectData[] = [ +const HARCODED_VISUAL_ASSETS: IotaObjectData[] = [ { digest: 'dh3bxjGDzm62bdidFFehtaajwqBSaKFdm8Ujr23J51xy', objectId: '0x9303adf2c711dcc239rbd78c0d0666666df06e2b3a35837', diff --git a/apps/wallet-dashboard/app/dashboard/home/page.tsx b/apps/wallet-dashboard/app/dashboard/home/page.tsx index 553ced2a07a..9ea52dc62d3 100644 --- a/apps/wallet-dashboard/app/dashboard/home/page.tsx +++ b/apps/wallet-dashboard/app/dashboard/home/page.tsx @@ -1,8 +1,9 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; -import { useCurrentAccount, useCurrentWallet } from '@mysten/dapp-kit'; +import { useCurrentAccount, useCurrentWallet } from '@iota/dapp-kit'; import { AccountBalance, AllCoins } from '@/components'; function HomeDashboardPage(): JSX.Element { diff --git a/apps/wallet-dashboard/app/dashboard/layout.tsx b/apps/wallet-dashboard/app/dashboard/layout.tsx index a71677a5cf7..cce5a27e68d 100644 --- a/apps/wallet-dashboard/app/dashboard/layout.tsx +++ b/apps/wallet-dashboard/app/dashboard/layout.tsx @@ -1,10 +1,11 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; import { Notifications, RouteLink } from '@/components/index'; import React, { type PropsWithChildren } from 'react'; -import { ConnectButton } from '@mysten/dapp-kit'; +import { ConnectButton } from '@iota/dapp-kit'; function DashboardLayout({ children }: PropsWithChildren): JSX.Element { const routes = [ diff --git a/apps/wallet-dashboard/app/dashboard/migrations/page.tsx b/apps/wallet-dashboard/app/dashboard/migrations/page.tsx index 7ec44826ba0..4111c733152 100644 --- a/apps/wallet-dashboard/app/dashboard/migrations/page.tsx +++ b/apps/wallet-dashboard/app/dashboard/migrations/page.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 function StakingDashboardPage(): JSX.Element { diff --git a/apps/wallet-dashboard/app/dashboard/staking/page.tsx b/apps/wallet-dashboard/app/dashboard/staking/page.tsx index a3b28bae133..3fd5d01a1e9 100644 --- a/apps/wallet-dashboard/app/dashboard/staking/page.tsx +++ b/apps/wallet-dashboard/app/dashboard/staking/page.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; diff --git a/apps/wallet-dashboard/app/layout.tsx b/apps/wallet-dashboard/app/layout.tsx index 27de47492ab..dce37d8861e 100644 --- a/apps/wallet-dashboard/app/layout.tsx +++ b/apps/wallet-dashboard/app/layout.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; @@ -6,12 +7,12 @@ import { Inter } from 'next/font/google'; import './globals.css'; -import { SuiClientProvider, WalletProvider } from '@mysten/dapp-kit'; -import { getAllNetworks } from '@mysten/sui.js/client'; +import { IotaClientProvider, WalletProvider } from '@iota/dapp-kit'; +import { getAllNetworks } from '@iota/iota.js/client'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import React from 'react'; -import '@mysten/dapp-kit/dist/index.css'; +import '@iota/dapp-kit/dist/index.css'; import { Popup, PopupProvider } from '@/components/Popup'; const inter = Inter({ subsets: ['latin'] }); @@ -30,10 +31,10 @@ export default function RootLayout({ - + {children} - + diff --git a/apps/wallet-dashboard/components/AccountBalance/AccountBalance.tsx b/apps/wallet-dashboard/components/AccountBalance/AccountBalance.tsx index efb86036dc3..a9b2d0659ea 100644 --- a/apps/wallet-dashboard/components/AccountBalance/AccountBalance.tsx +++ b/apps/wallet-dashboard/components/AccountBalance/AccountBalance.tsx @@ -1,20 +1,21 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useCurrentAccount } from '@mysten/dapp-kit'; -import { SUI_TYPE_ARG } from '@mysten/sui.js/utils'; +import { useCurrentAccount } from '@iota/dapp-kit'; +import { IOTA_TYPE_ARG } from '@iota/iota.js/utils'; import { useBalance } from '@/hooks'; export const AccountBalance = () => { const account = useCurrentAccount(); - const { data, isLoading } = useBalance(SUI_TYPE_ARG, account?.address); + const { data, isLoading } = useBalance(IOTA_TYPE_ARG, account?.address); return (
{isLoading &&

Loading...

} - {!isLoading &&

Balance: {data?.suiBalance}

} + {!isLoading &&

Balance: {data?.iotaBalance}

}
); }; diff --git a/apps/wallet-dashboard/components/ActivityIcon.tsx b/apps/wallet-dashboard/components/ActivityIcon.tsx index 4c5865990aa..bce7d20c952 100644 --- a/apps/wallet-dashboard/components/ActivityIcon.tsx +++ b/apps/wallet-dashboard/components/ActivityIcon.tsx @@ -1,8 +1,9 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { ActivityState } from '@/lib/interfaces'; -import { Account24, ArrowRight16, Sui, Swap16, Unstaked, WalletActionStake24 } from '@mysten/icons'; +import { Account24, ArrowRight16, Iota, Swap16, Unstaked, WalletActionStake24 } from '@iota/icons'; const icons = { Send: ( @@ -27,7 +28,7 @@ const icons = { ), Unstaked: , - Rewards: , + Rewards: , Swapped: , PersonalMessage: ( diff --git a/apps/wallet-dashboard/components/ActivityTile.tsx b/apps/wallet-dashboard/components/ActivityTile.tsx index aa2345e0c51..bd5942ca086 100644 --- a/apps/wallet-dashboard/components/ActivityTile.tsx +++ b/apps/wallet-dashboard/components/ActivityTile.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; diff --git a/apps/wallet-dashboard/components/AllCoins/AllCoins.tsx b/apps/wallet-dashboard/components/AllCoins/AllCoins.tsx index 53a5552559d..23197a7b5ee 100644 --- a/apps/wallet-dashboard/components/AllCoins/AllCoins.tsx +++ b/apps/wallet-dashboard/components/AllCoins/AllCoins.tsx @@ -1,13 +1,14 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useGetAllCoins } from '@mysten/core/src/hooks/useGetAllCoins'; -import { useCurrentAccount } from '@mysten/dapp-kit'; -import { SUI_TYPE_ARG } from '@mysten/sui.js/utils'; +import { useGetAllCoins } from '@iota/core/src/hooks/useGetAllCoins'; +import { useCurrentAccount } from '@iota/dapp-kit'; +import { IOTA_TYPE_ARG } from '@iota/iota.js/utils'; export const AllCoins = () => { const account = useCurrentAccount(); - const { data } = useGetAllCoins(SUI_TYPE_ARG, account?.address); + const { data } = useGetAllCoins(IOTA_TYPE_ARG, account?.address); return (
diff --git a/apps/wallet-dashboard/components/AmountBox.tsx b/apps/wallet-dashboard/components/AmountBox.tsx index 8db7bb609d0..bf1f42e880a 100644 --- a/apps/wallet-dashboard/components/AmountBox.tsx +++ b/apps/wallet-dashboard/components/AmountBox.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Box } from '@/components/index'; diff --git a/apps/wallet-dashboard/components/AppList/AppList.tsx b/apps/wallet-dashboard/components/AppList/AppList.tsx index c9c317a760e..aaba6c1eb13 100644 --- a/apps/wallet-dashboard/components/AppList/AppList.tsx +++ b/apps/wallet-dashboard/components/AppList/AppList.tsx @@ -1,12 +1,13 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import React from 'react'; import Image from 'next/image'; -import { useAppsBackend } from '@mysten/core'; +import { useAppsBackend } from '@iota/core'; import { useQuery } from '@tanstack/react-query'; import { AppListItem } from './AppList.types'; -import { getDefaultNetwork } from '@mysten/sui.js/client'; +import { getDefaultNetwork } from '@iota/iota.js/client'; const AppListItem = (props: AppListItem) => { return ( diff --git a/apps/wallet-dashboard/components/AppList/AppList.types.ts b/apps/wallet-dashboard/components/AppList/AppList.types.ts index 6b8e6a5f794..86c1d9cf89e 100644 --- a/apps/wallet-dashboard/components/AppList/AppList.types.ts +++ b/apps/wallet-dashboard/components/AppList/AppList.types.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export interface AppListItem { diff --git a/apps/wallet-dashboard/components/AppList/index.ts b/apps/wallet-dashboard/components/AppList/index.ts index 54ba8edfe22..79f99540fda 100644 --- a/apps/wallet-dashboard/components/AppList/index.ts +++ b/apps/wallet-dashboard/components/AppList/index.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export * from './AppList'; diff --git a/apps/wallet-dashboard/components/Box.tsx b/apps/wallet-dashboard/components/Box.tsx index 3b9b285ea6e..c86c43f73c6 100644 --- a/apps/wallet-dashboard/components/Box.tsx +++ b/apps/wallet-dashboard/components/Box.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import React from 'react'; diff --git a/apps/wallet-dashboard/components/Button.tsx b/apps/wallet-dashboard/components/Button.tsx index e558823367d..38911630236 100644 --- a/apps/wallet-dashboard/components/Button.tsx +++ b/apps/wallet-dashboard/components/Button.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import React from 'react'; diff --git a/apps/wallet-dashboard/components/Cards/AssetCard.tsx b/apps/wallet-dashboard/components/Cards/AssetCard.tsx index 2a522dc75ac..d66361cdc59 100644 --- a/apps/wallet-dashboard/components/Cards/AssetCard.tsx +++ b/apps/wallet-dashboard/components/Cards/AssetCard.tsx @@ -1,15 +1,16 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; -import { SuiObjectData } from '@mysten/sui.js/client'; +import { IotaObjectData } from '@iota/iota.js/client'; import React from 'react'; import { Box } from '@/components/index'; import Image from 'next/image'; interface AssetCardProps { - asset: SuiObjectData; + asset: IotaObjectData; } function AssetCard({ asset }: AssetCardProps): JSX.Element { diff --git a/apps/wallet-dashboard/components/Cards/index.ts b/apps/wallet-dashboard/components/Cards/index.ts index 665e7e0e190..01311a2d7db 100644 --- a/apps/wallet-dashboard/components/Cards/index.ts +++ b/apps/wallet-dashboard/components/Cards/index.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export { default as AssetCard } from './AssetCard'; diff --git a/apps/wallet-dashboard/components/List.tsx b/apps/wallet-dashboard/components/List.tsx index cfd32ea32ad..dbaec006400 100644 --- a/apps/wallet-dashboard/components/List.tsx +++ b/apps/wallet-dashboard/components/List.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import React from 'react'; diff --git a/apps/wallet-dashboard/components/Notifications/Notifications.tsx b/apps/wallet-dashboard/components/Notifications/Notifications.tsx index 3e0b0aad6d5..d52083f7010 100644 --- a/apps/wallet-dashboard/components/Notifications/Notifications.tsx +++ b/apps/wallet-dashboard/components/Notifications/Notifications.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; diff --git a/apps/wallet-dashboard/components/Popup/Popup.tsx b/apps/wallet-dashboard/components/Popup/Popup.tsx index e16a915882c..f0d8613d7d6 100644 --- a/apps/wallet-dashboard/components/Popup/Popup.tsx +++ b/apps/wallet-dashboard/components/Popup/Popup.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import React from 'react'; diff --git a/apps/wallet-dashboard/components/Popup/PopupProvider.tsx b/apps/wallet-dashboard/components/Popup/PopupProvider.tsx index 8eb6fbfc3a3..20e628b71d0 100644 --- a/apps/wallet-dashboard/components/Popup/PopupProvider.tsx +++ b/apps/wallet-dashboard/components/Popup/PopupProvider.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; import { PopupContext } from '@/contexts'; diff --git a/apps/wallet-dashboard/components/Popup/Popups/ActivityDetailsPopup.tsx b/apps/wallet-dashboard/components/Popup/Popups/ActivityDetailsPopup.tsx index 45c0461d627..b897e9ea47b 100644 --- a/apps/wallet-dashboard/components/Popup/Popups/ActivityDetailsPopup.tsx +++ b/apps/wallet-dashboard/components/Popup/Popups/ActivityDetailsPopup.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import React from 'react'; diff --git a/apps/wallet-dashboard/components/Popup/Popups/StakeDetailsPopup.tsx b/apps/wallet-dashboard/components/Popup/Popups/StakeDetailsPopup.tsx index bdbece7d390..3695ed4b607 100644 --- a/apps/wallet-dashboard/components/Popup/Popups/StakeDetailsPopup.tsx +++ b/apps/wallet-dashboard/components/Popup/Popups/StakeDetailsPopup.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import React from 'react'; diff --git a/apps/wallet-dashboard/components/Popup/Popups/UnstakePopup.tsx b/apps/wallet-dashboard/components/Popup/Popups/UnstakePopup.tsx index a1bfed4c2b6..91dca399246 100644 --- a/apps/wallet-dashboard/components/Popup/Popups/UnstakePopup.tsx +++ b/apps/wallet-dashboard/components/Popup/Popups/UnstakePopup.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import React from 'react'; diff --git a/apps/wallet-dashboard/components/Popup/Popups/index.ts b/apps/wallet-dashboard/components/Popup/Popups/index.ts index a2b63756ce9..778dd041791 100644 --- a/apps/wallet-dashboard/components/Popup/Popups/index.ts +++ b/apps/wallet-dashboard/components/Popup/Popups/index.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export { default as ActivityDetailsPopup } from './ActivityDetailsPopup'; diff --git a/apps/wallet-dashboard/components/Popup/index.ts b/apps/wallet-dashboard/components/Popup/index.ts index baeafee23a7..14c736cdbfb 100644 --- a/apps/wallet-dashboard/components/Popup/index.ts +++ b/apps/wallet-dashboard/components/Popup/index.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export { default as Popup } from './Popup'; diff --git a/apps/wallet-dashboard/components/RouteLink.tsx b/apps/wallet-dashboard/components/RouteLink.tsx index f4395dcd421..7928059a0dd 100644 --- a/apps/wallet-dashboard/components/RouteLink.tsx +++ b/apps/wallet-dashboard/components/RouteLink.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; diff --git a/apps/wallet-dashboard/components/VirtualList.tsx b/apps/wallet-dashboard/components/VirtualList.tsx index 4252807cb6a..d95a456aa12 100644 --- a/apps/wallet-dashboard/components/VirtualList.tsx +++ b/apps/wallet-dashboard/components/VirtualList.tsx @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 'use client'; diff --git a/apps/wallet-dashboard/components/index.ts b/apps/wallet-dashboard/components/index.ts index 85657ce9d91..2e65968b21d 100644 --- a/apps/wallet-dashboard/components/index.ts +++ b/apps/wallet-dashboard/components/index.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export { default as RouteLink } from './RouteLink'; diff --git a/apps/wallet-dashboard/contexts/PopupContext.ts b/apps/wallet-dashboard/contexts/PopupContext.ts index ced7b13cc33..0fed5e26bbd 100644 --- a/apps/wallet-dashboard/contexts/PopupContext.ts +++ b/apps/wallet-dashboard/contexts/PopupContext.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { ReactNode, createContext } from 'react'; diff --git a/apps/wallet-dashboard/contexts/index.ts b/apps/wallet-dashboard/contexts/index.ts index d356e2485ed..eccf300d551 100644 --- a/apps/wallet-dashboard/contexts/index.ts +++ b/apps/wallet-dashboard/contexts/index.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export * from './PopupContext'; diff --git a/apps/wallet-dashboard/hooks/index.ts b/apps/wallet-dashboard/hooks/index.ts index a9cae2ad3f7..d9f701cda15 100644 --- a/apps/wallet-dashboard/hooks/index.ts +++ b/apps/wallet-dashboard/hooks/index.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export * from './useBalance'; diff --git a/apps/wallet-dashboard/hooks/useBalance.ts b/apps/wallet-dashboard/hooks/useBalance.ts index fdc3809d13e..06e19392e5d 100644 --- a/apps/wallet-dashboard/hooks/useBalance.ts +++ b/apps/wallet-dashboard/hooks/useBalance.ts @@ -1,20 +1,18 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { CoinBalance } from '@mysten/sui.js/client'; -import { MIST_PER_SUI } from '@mysten/sui.js/utils'; +import { useIotaClient } from '@iota/dapp-kit'; +import { CoinBalance } from '@iota/iota.js/client'; +import { MICROS_PER_IOTA } from '@iota/iota.js/utils'; import { useQuery } from '@tanstack/react-query'; interface UseBalance extends CoinBalance { - suiBalance: number; + iotaBalance: number; } export function useBalance(coinType: string, address?: string | null) { - const client = useSuiClient(); + const client = useIotaClient(); return useQuery({ queryKey: ['get-balance', address, coinType], @@ -25,7 +23,7 @@ export function useBalance(coinType: string, address?: string | null) { }); return { - suiBalance: Number(data.totalBalance) / Number(MIST_PER_SUI), + iotaBalance: Number(data.totalBalance) / Number(MICROS_PER_IOTA), ...data, }; }, diff --git a/apps/wallet-dashboard/hooks/useNotifications.ts b/apps/wallet-dashboard/hooks/useNotifications.ts index c5ec455b886..429c0655bb3 100644 --- a/apps/wallet-dashboard/hooks/useNotifications.ts +++ b/apps/wallet-dashboard/hooks/useNotifications.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useNotificationStore } from '@/stores/notificationStore'; diff --git a/apps/wallet-dashboard/hooks/usePopups.ts b/apps/wallet-dashboard/hooks/usePopups.ts index b4867bbac73..a9a23778b0a 100644 --- a/apps/wallet-dashboard/hooks/usePopups.ts +++ b/apps/wallet-dashboard/hooks/usePopups.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { PopupContext, PopupManager } from '@/contexts'; diff --git a/apps/wallet-dashboard/lib/interfaces/activities.interface.ts b/apps/wallet-dashboard/lib/interfaces/activities.interface.ts index f481f0ba447..c6695e25c64 100644 --- a/apps/wallet-dashboard/lib/interfaces/activities.interface.ts +++ b/apps/wallet-dashboard/lib/interfaces/activities.interface.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export interface Activity { diff --git a/apps/wallet-dashboard/lib/interfaces/index.ts b/apps/wallet-dashboard/lib/interfaces/index.ts index a0d539594d4..d6afed90b3e 100644 --- a/apps/wallet-dashboard/lib/interfaces/index.ts +++ b/apps/wallet-dashboard/lib/interfaces/index.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export * from './activities.interface'; diff --git a/apps/wallet-dashboard/lib/mocks/index.ts b/apps/wallet-dashboard/lib/mocks/index.ts index d270ac1ecbf..3d778b6677e 100644 --- a/apps/wallet-dashboard/lib/mocks/index.ts +++ b/apps/wallet-dashboard/lib/mocks/index.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export * from './non-visual-assets.mock'; diff --git a/apps/wallet-dashboard/lib/mocks/non-visual-assets.mock.ts b/apps/wallet-dashboard/lib/mocks/non-visual-assets.mock.ts index 62b5065f66f..985478ab34a 100644 --- a/apps/wallet-dashboard/lib/mocks/non-visual-assets.mock.ts +++ b/apps/wallet-dashboard/lib/mocks/non-visual-assets.mock.ts @@ -1,15 +1,16 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiObjectData } from '@mysten/sui.js/client'; +import { IotaObjectData } from '@iota/iota.js/client'; -const NON_VISUAL_ASSET: SuiObjectData = { +const NON_VISUAL_ASSET: IotaObjectData = { digest: 'CvsV2zDm2THbQiuAD3PpHC9wizoANGLBZhJsQyaY88Zh', objectId: '0x7da24c085e8940230e4853b2f6384be3c775b8f31f97be2f3b75995d7b692297', version: '28331430', - type: '0x3::staking_pool::StakedSui', + type: '0x3::staking_pool::StakedIota', }; -export const HARDCODED_NON_VISUAL_ASSETS: SuiObjectData[] = new Array(10) +export const HARDCODED_NON_VISUAL_ASSETS: IotaObjectData[] = new Array(10) .fill(0) .map(() => NON_VISUAL_ASSET); diff --git a/apps/wallet-dashboard/lib/utils/index.ts b/apps/wallet-dashboard/lib/utils/index.ts index eea68739344..c97847ec4a2 100644 --- a/apps/wallet-dashboard/lib/utils/index.ts +++ b/apps/wallet-dashboard/lib/utils/index.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export * from './time'; diff --git a/apps/wallet-dashboard/lib/utils/time.ts b/apps/wallet-dashboard/lib/utils/time.ts index 8eca8942786..bc85bfe3f97 100644 --- a/apps/wallet-dashboard/lib/utils/time.ts +++ b/apps/wallet-dashboard/lib/utils/time.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export default function formatTimestamp(timeStamp: number): string { diff --git a/apps/wallet-dashboard/next.config.mjs b/apps/wallet-dashboard/next.config.mjs index e40a78b5e98..ae1ed686822 100644 --- a/apps/wallet-dashboard/next.config.mjs +++ b/apps/wallet-dashboard/next.config.mjs @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /** @type {import('next').NextConfig} */ diff --git a/apps/wallet-dashboard/package.json b/apps/wallet-dashboard/package.json index 9e244772952..30e753e70aa 100644 --- a/apps/wallet-dashboard/package.json +++ b/apps/wallet-dashboard/package.json @@ -12,10 +12,10 @@ "node": ">= v18.17.0" }, "dependencies": { - "@mysten/core": "workspace:*", - "@mysten/dapp-kit": "workspace:*", - "@mysten/icons": "workspace:*", - "@mysten/sui.js": "workspace:*", + "@iota/core": "workspace:*", + "@iota/dapp-kit": "workspace:*", + "@iota/icons": "workspace:*", + "@iota/iota.js": "workspace:*", "@tanstack/react-query": "^5.0.0", "@tanstack/react-virtual": "^3.5.0", "next": "14.2.3", diff --git a/apps/wallet-dashboard/postcss.config.mjs b/apps/wallet-dashboard/postcss.config.mjs index f0cbe7234d8..cdefb4746da 100644 --- a/apps/wallet-dashboard/postcss.config.mjs +++ b/apps/wallet-dashboard/postcss.config.mjs @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /** @type {import('postcss-load-config').Config} */ diff --git a/apps/wallet-dashboard/stores/notificationStore.ts b/apps/wallet-dashboard/stores/notificationStore.ts index eba690aaa21..66254cb8cb0 100644 --- a/apps/wallet-dashboard/stores/notificationStore.ts +++ b/apps/wallet-dashboard/stores/notificationStore.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { create } from 'zustand'; diff --git a/apps/wallet-dashboard/tailwind.config.ts b/apps/wallet-dashboard/tailwind.config.ts index c3b8ec17293..0e3cad6b415 100644 --- a/apps/wallet-dashboard/tailwind.config.ts +++ b/apps/wallet-dashboard/tailwind.config.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import type { Config } from 'tailwindcss'; diff --git a/apps/wallet-dashboard/utils/indexGenerator.ts b/apps/wallet-dashboard/utils/indexGenerator.ts index 0b86604f9a1..bc9e1e0f4d5 100644 --- a/apps/wallet-dashboard/utils/indexGenerator.ts +++ b/apps/wallet-dashboard/utils/indexGenerator.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export function* indexGenerator(cap: number): Generator { diff --git a/apps/wallet/.eslintignore b/apps/wallet/.eslintignore deleted file mode 100644 index ccfe4550f39..00000000000 --- a/apps/wallet/.eslintignore +++ /dev/null @@ -1,6 +0,0 @@ -dist/ -node_modules/ -.next/ -.swc/ -out/ -postcss.config.js diff --git a/apps/wallet/README.md b/apps/wallet/README.md index f4e3ac00ac6..ed6d93d2e1a 100644 --- a/apps/wallet/README.md +++ b/apps/wallet/README.md @@ -1,18 +1,18 @@ -# Sui Wallet +# Iota Wallet -A Chrome extension wallet for [Sui](https://sui.io). +A Chrome extension wallet for [Iota](https://iota.io). # Set Up **Requirements**: 18.0.0 or later. -Dependencies are managed using [`pnpm`](https://pnpm.io/). You can start by installing dependencies in the root of the Sui repository: +Dependencies are managed using [`pnpm`](https://pnpm.io/). You can start by installing dependencies in the root of the Iota repository: ``` $ pnpm install ``` -> All `pnpm` commands below are intended to be run in the root of the Sui repo. +> All `pnpm` commands below are intended to be run in the root of the Iota repo. ## Build in watch mode (dev) diff --git a/apps/wallet/configs/ts/tsconfig.common.json b/apps/wallet/configs/ts/tsconfig.common.json index d70d9b255da..ea3c61d0293 100644 --- a/apps/wallet/configs/ts/tsconfig.common.json +++ b/apps/wallet/configs/ts/tsconfig.common.json @@ -43,14 +43,14 @@ "_values/*": ["./src/ui/styles/values/*"], "_utils": ["./src/ui/styles/utils"], "_utils/*": ["./src/ui/styles/utils/*"], - "@mysten/sui.js/*": ["../../sdk/typescript/src/*"], - "@mysten/sui.js": ["../../sdk/typescript/src/"], - "@mysten/bcs": ["../../sdk/bcs/src/"], - "@mysten/dapp-kit": ["../../sdk/dapp-kit/src/"], - "@mysten/ledgerjs-hw-app-sui": ["../../sdk/ledgerjs-hw-app-sui/src/Sui.ts"], - "@mysten/wallet-standard": ["../../sdk/wallet-standard/src/"], - "@mysten/zklogin": ["../../sdk/zklogin/src/"], - "@mysten/deepbook": ["../../sdk/deepbook/src/"] + "@iota/iota.js/*": ["../../sdk/typescript/src/*"], + "@iota/iota.js": ["../../sdk/typescript/src/"], + "@iota/bcs": ["../../sdk/bcs/src/"], + "@iota/dapp-kit": ["../../sdk/dapp-kit/src/"], + "@iota/ledgerjs-hw-app-iota": ["../../sdk/ledgerjs-hw-app-iota/src/Iota.ts"], + "@iota/wallet-standard": ["../../sdk/wallet-standard/src/"], + "@iota/zklogin": ["../../sdk/zklogin/src/"], + "@iota/deepbook": ["../../sdk/deepbook/src/"] } }, "include": ["../../src", "../../tests"], diff --git a/apps/wallet/configs/webpack/webpack.config.common.ts b/apps/wallet/configs/webpack/webpack.config.common.ts index 49a336f2a32..57c3c5c4a4c 100644 --- a/apps/wallet/configs/webpack/webpack.config.common.ts +++ b/apps/wallet/configs/webpack/webpack.config.common.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { exec } from 'child_process'; @@ -43,7 +44,7 @@ const TS_CONFIGS_ROOT = resolve(CONFIGS_ROOT, 'ts'); const IS_DEV = process.env.NODE_ENV === 'development'; const IS_PROD = process.env.NODE_ENV === 'production'; const TS_CONFIG_FILE = resolve(TS_CONFIGS_ROOT, `tsconfig.${IS_DEV ? 'dev' : 'prod'}.json`); -const APP_NAME = WALLET_BETA ? 'Sui Wallet (BETA)' : IS_DEV ? 'Sui Wallet (DEV)' : 'Sui Wallet'; +const APP_NAME = WALLET_BETA ? 'Iota Wallet (BETA)' : IS_DEV ? 'Iota Wallet (DEV)' : 'Iota Wallet'; dotenv.config({ path: [resolve(SDK_ROOT, '.env'), resolve(SDK_ROOT, '.env.defaults')], @@ -120,7 +121,7 @@ const commonConfig: () => Promise = async () => { }, resolve: { extensions: ['.ts', '.tsx', '.js'], - // Fix .js imports from @mysten/sui.js since we are importing it from source + // Fix .js imports from @iota/iota.js since we are importing it from source extensionAlias: { '.js': ['.js', '.ts', '.tsx', '.jsx'], '.mjs': ['.mjs', '.mts'], diff --git a/apps/wallet/configs/webpack/webpack.config.dev.ts b/apps/wallet/configs/webpack/webpack.config.dev.ts index 1f4bf58fc53..7ed26c8aa55 100644 --- a/apps/wallet/configs/webpack/webpack.config.dev.ts +++ b/apps/wallet/configs/webpack/webpack.config.dev.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import ESLintPlugin from 'eslint-webpack-plugin'; diff --git a/apps/wallet/configs/webpack/webpack.config.prod.ts b/apps/wallet/configs/webpack/webpack.config.prod.ts index 096d1402b52..42710ad7488 100644 --- a/apps/wallet/configs/webpack/webpack.config.prod.ts +++ b/apps/wallet/configs/webpack/webpack.config.prod.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import type { Configuration } from 'webpack'; diff --git a/apps/wallet/package.json b/apps/wallet/package.json index 96e15445c69..e85a00141d8 100644 --- a/apps/wallet/package.json +++ b/apps/wallet/package.json @@ -1,7 +1,7 @@ { - "name": "sui-wallet", + "name": "iota-wallet", "private": true, - "description": "A wallet for Sui", + "description": "A wallet for Iota", "main": "./dist/ui.js", "scripts": { "build": "pnpm build:prod", @@ -29,10 +29,10 @@ }, "repository": { "type": "git", - "url": "github.com:MystenLabs/sui.git" + "url": "github.com:iotaledger/iota.git" }, "keywords": [ - "sui", + "iota", "wallet", "coins", "tokens", @@ -110,14 +110,14 @@ "@ledgerhq/hw-transport-webhid": "^6.27.15", "@ledgerhq/hw-transport-webusb": "^6.27.13", "@metamask/browser-passworder": "^4.1.0", - "@mysten/core": "workspace:*", - "@mysten/dapp-kit": "workspace:*", - "@mysten/deepbook": "workspace:*", - "@mysten/icons": "workspace:*", - "@mysten/ledgerjs-hw-app-sui": "workspace:*", - "@mysten/sui.js": "workspace:*", - "@mysten/wallet-standard": "workspace:*", - "@mysten/zklogin": "workspace:*", + "@iota/core": "workspace:*", + "@iota/dapp-kit": "workspace:*", + "@iota/deepbook": "workspace:*", + "@iota/icons": "workspace:*", + "@iota/ledgerjs-hw-app-iota": "workspace:*", + "@iota/iota.js": "workspace:*", + "@iota/wallet-standard": "workspace:*", + "@iota/zklogin": "workspace:*", "@noble/hashes": "^1.3.1", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-collapsible": "^1.0.3", diff --git a/apps/wallet/playwright.config.ts b/apps/wallet/playwright.config.ts index 7b0bfa204f1..7d405e8c9b4 100644 --- a/apps/wallet/playwright.config.ts +++ b/apps/wallet/playwright.config.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { devices } from '@playwright/test'; @@ -58,7 +59,7 @@ const config: PlaywrightTestConfig = { { command: process.env.E2E_RUN_LOCAL_NET_CMD ?? - 'RUST_LOG="consensus=off" cargo run --bin sui-test-validator', + 'RUST_LOG="consensus=off" cargo run --bin iota-test-validator', port: 9123, timeout: 120 * 1000, /* Set this to true to reuse the server instance on step 'Run Local net' in e2e.yml */ diff --git a/apps/wallet/postcss.config.js b/apps/wallet/postcss.config.js index e3ded0ae58f..10fda309d57 100644 --- a/apps/wallet/postcss.config.js +++ b/apps/wallet/postcss.config.js @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 const postcssPresetEnv = require('postcss-preset-env'); diff --git a/apps/wallet/src/background/Alarms.ts b/apps/wallet/src/background/Alarms.ts index ae467033d07..d33bb6a0a83 100644 --- a/apps/wallet/src/background/Alarms.ts +++ b/apps/wallet/src/background/Alarms.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import Browser from 'webextension-polyfill'; diff --git a/apps/wallet/src/background/NetworkEnv.ts b/apps/wallet/src/background/NetworkEnv.ts index bf3e7b130d1..9ec1e62216c 100644 --- a/apps/wallet/src/background/NetworkEnv.ts +++ b/apps/wallet/src/background/NetworkEnv.ts @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type NetworkEnvType } from '_src/shared/api-env'; import { isValidUrl } from '_src/shared/utils'; -import { getDefaultNetwork, Network } from '@mysten/sui.js/client'; +import { getDefaultNetwork, Network } from '@iota/iota.js/client'; import mitt from 'mitt'; import Browser from 'webextension-polyfill'; diff --git a/apps/wallet/src/background/Permissions.ts b/apps/wallet/src/background/Permissions.ts index edb8d8032e5..42c85b8cdf4 100644 --- a/apps/wallet/src/background/Permissions.ts +++ b/apps/wallet/src/background/Permissions.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { ALL_PERMISSION_TYPES, isValidPermissionTypes } from '_payloads/permissions'; diff --git a/apps/wallet/src/background/Tabs.ts b/apps/wallet/src/background/Tabs.ts index 45335256e4c..23ea7a622c6 100644 --- a/apps/wallet/src/background/Tabs.ts +++ b/apps/wallet/src/background/Tabs.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { diff --git a/apps/wallet/src/background/Transactions.ts b/apps/wallet/src/background/Transactions.ts index 85aa520b0c8..286ba77e47a 100644 --- a/apps/wallet/src/background/Transactions.ts +++ b/apps/wallet/src/background/Transactions.ts @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type ApprovalRequest, type TransactionDataType, } from '_payloads/transactions/ApprovalRequest'; -import type { SuiSignTransactionSerialized } from '_payloads/transactions/ExecuteTransactionRequest'; +import type { IotaSignTransactionSerialized } from '_payloads/transactions/ExecuteTransactionRequest'; import { type SignMessageRequest } from '_payloads/transactions/SignMessage'; import type { TransactionRequestResponse } from '_payloads/transactions/ui/TransactionRequestResponse'; import type { ContentScriptConnection } from '_src/background/connections/ContentScriptConnection'; import { type SignedTransaction } from '_src/ui/app/WalletSigner'; -import { type SuiTransactionBlockResponse } from '@mysten/sui.js/client'; -import { type SuiSignMessageOutput } from '@mysten/wallet-standard'; +import { type IotaTransactionBlockResponse } from '@iota/iota.js/client'; +import { type IotaSignMessageOutput } from '@iota/wallet-standard'; import { filter, lastValueFrom, map, race, Subject, take } from 'rxjs'; import { v4 as uuidV4 } from 'uuid'; import Browser from 'webextension-polyfill'; @@ -38,10 +39,10 @@ class Transactions { | { tx: TransactionDataType; sign?: undefined } | { tx?: undefined; - sign: SuiSignTransactionSerialized; + sign: IotaSignTransactionSerialized; }, connection: ContentScriptConnection, - ): Promise { + ): Promise { const { txResultError, txResult, txSigned } = await this.requestApproval( tx ?? { type: 'transaction', @@ -70,7 +71,7 @@ class Transactions { public async signMessage( { accountAddress, message }: Required>['args'], connection: ContentScriptConnection, - ): Promise { + ): Promise { const { txResult, txResultError } = await this.requestApproval( { type: 'sign-message', accountAddress, message }, connection.origin, diff --git a/apps/wallet/src/background/Window.ts b/apps/wallet/src/background/Window.ts index 718fceeac10..924317b540a 100644 --- a/apps/wallet/src/background/Window.ts +++ b/apps/wallet/src/background/Window.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { filter, fromEventPattern, share, take, takeWhile } from 'rxjs'; diff --git a/apps/wallet/src/background/account-sources/AccountSource.ts b/apps/wallet/src/background/account-sources/AccountSource.ts index 6ed274f8587..5475a5afa6c 100644 --- a/apps/wallet/src/background/account-sources/AccountSource.ts +++ b/apps/wallet/src/background/account-sources/AccountSource.ts @@ -1,6 +1,4 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 diff --git a/apps/wallet/src/background/account-sources/MnemonicAccountSource.ts b/apps/wallet/src/background/account-sources/MnemonicAccountSource.ts index 816bfb0bfcd..ec0d0fde1d0 100644 --- a/apps/wallet/src/background/account-sources/MnemonicAccountSource.ts +++ b/apps/wallet/src/background/account-sources/MnemonicAccountSource.ts @@ -1,6 +1,4 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 @@ -12,8 +10,8 @@ import { validateEntropy, } from '_shared/utils/bip39'; import { decrypt, encrypt } from '_src/shared/cryptography/keystore'; -import { mnemonicToSeedHex } from '@mysten/sui.js/cryptography'; -import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519'; +import { mnemonicToSeedHex } from '@iota/iota.js/cryptography'; +import { Ed25519Keypair } from '@iota/iota.js/keypairs/ed25519'; import { sha256 } from '@noble/hashes/sha256'; import { bytesToHex } from '@noble/hashes/utils'; import Dexie from 'dexie'; diff --git a/apps/wallet/src/background/account-sources/SeedAccountSource.ts b/apps/wallet/src/background/account-sources/SeedAccountSource.ts index 2105658222d..bab8f4cdb2d 100644 --- a/apps/wallet/src/background/account-sources/SeedAccountSource.ts +++ b/apps/wallet/src/background/account-sources/SeedAccountSource.ts @@ -1,8 +1,9 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { decrypt, encrypt } from '_src/shared/cryptography/keystore'; -import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519'; +import { Ed25519Keypair } from '@iota/iota.js/keypairs/ed25519'; import { sha256 } from '@noble/hashes/sha256'; import { bytesToHex } from '@noble/hashes/utils'; import Dexie from 'dexie'; diff --git a/apps/wallet/src/background/account-sources/bipPath.ts b/apps/wallet/src/background/account-sources/bipPath.ts index 2284bdae4ab..9feeca7b2ba 100644 --- a/apps/wallet/src/background/account-sources/bipPath.ts +++ b/apps/wallet/src/background/account-sources/bipPath.ts @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export function makeDerivationPath(index: number) { diff --git a/apps/wallet/src/background/account-sources/events.ts b/apps/wallet/src/background/account-sources/events.ts index 28cae7941df..a9b1bc29ba5 100644 --- a/apps/wallet/src/background/account-sources/events.ts +++ b/apps/wallet/src/background/account-sources/events.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import mitt from 'mitt'; diff --git a/apps/wallet/src/background/account-sources/index.ts b/apps/wallet/src/background/account-sources/index.ts index 4bd0b865ca6..8f5e669d79f 100644 --- a/apps/wallet/src/background/account-sources/index.ts +++ b/apps/wallet/src/background/account-sources/index.ts @@ -1,6 +1,4 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 diff --git a/apps/wallet/src/background/accounts/Account.ts b/apps/wallet/src/background/accounts/Account.ts index 1bb8ae2d6b9..f6fd52a85be 100644 --- a/apps/wallet/src/background/accounts/Account.ts +++ b/apps/wallet/src/background/accounts/Account.ts @@ -1,6 +1,4 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 @@ -9,7 +7,7 @@ import { toSerializedSignature, type Keypair, type SerializedSignature, -} from '@mysten/sui.js/cryptography'; +} from '@iota/iota.js/cryptography'; import { blake2b } from '@noble/hashes/blake2b'; import { setupAutoLockAlarm } from '../auto-lock-accounts'; diff --git a/apps/wallet/src/background/accounts/ImportedAccount.ts b/apps/wallet/src/background/accounts/ImportedAccount.ts index af7f39edde7..060b59e3b57 100644 --- a/apps/wallet/src/background/accounts/ImportedAccount.ts +++ b/apps/wallet/src/background/accounts/ImportedAccount.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { decrypt, encrypt } from '_src/shared/cryptography/keystore'; @@ -54,7 +55,7 @@ export class ImportedAccount }; return { type: 'imported', - address: keyPair.getPublicKey().toSuiAddress(), + address: keyPair.getPublicKey().toIotaAddress(), publicKey: keyPair.getPublicKey().toBase64(), encrypted: await encrypt(inputs.password, dataToEncrypt), lastUnlockedOn: null, diff --git a/apps/wallet/src/background/accounts/LedgerAccount.ts b/apps/wallet/src/background/accounts/LedgerAccount.ts index 16807a471fe..a65c2036f1a 100644 --- a/apps/wallet/src/background/accounts/LedgerAccount.ts +++ b/apps/wallet/src/background/accounts/LedgerAccount.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { decrypt, encrypt } from '_src/shared/cryptography/keystore'; diff --git a/apps/wallet/src/background/accounts/MnemonicAccount.ts b/apps/wallet/src/background/accounts/MnemonicAccount.ts index a047666f23c..28d16cd80f0 100644 --- a/apps/wallet/src/background/accounts/MnemonicAccount.ts +++ b/apps/wallet/src/background/accounts/MnemonicAccount.ts @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { fromExportedKeypair } from '_src/shared/utils/from-exported-keypair'; -import { type Keypair } from '@mysten/sui.js/cryptography'; +import { type Keypair } from '@iota/iota.js/cryptography'; import { MnemonicAccountSource } from '../account-sources/MnemonicAccountSource'; import { @@ -60,7 +61,7 @@ export class MnemonicAccount return { type: 'mnemonic-derived', sourceID, - address: keyPair.getPublicKey().toSuiAddress(), + address: keyPair.getPublicKey().toIotaAddress(), derivationPath, publicKey: keyPair.getPublicKey().toBase64(), lastUnlockedOn: null, diff --git a/apps/wallet/src/background/accounts/SeedAccount.ts b/apps/wallet/src/background/accounts/SeedAccount.ts index 7242ef000de..21602680434 100644 --- a/apps/wallet/src/background/accounts/SeedAccount.ts +++ b/apps/wallet/src/background/accounts/SeedAccount.ts @@ -1,8 +1,9 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { fromExportedKeypair } from '_src/shared/utils/from-exported-keypair'; -import { type Keypair } from '@mysten/sui.js/cryptography'; +import { type Keypair } from '@iota/iota.js/cryptography'; import { SeedAccountSource } from '../account-sources/SeedAccountSource'; import { @@ -60,7 +61,7 @@ export class SeedAccount return { type: 'seed-derived', sourceID, - address: keyPair.getPublicKey().toSuiAddress(), + address: keyPair.getPublicKey().toIotaAddress(), derivationPath, publicKey: keyPair.getPublicKey().toBase64(), lastUnlockedOn: null, diff --git a/apps/wallet/src/background/accounts/events.ts b/apps/wallet/src/background/accounts/events.ts index ccd29711210..8ab41e1603d 100644 --- a/apps/wallet/src/background/accounts/events.ts +++ b/apps/wallet/src/background/accounts/events.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import mitt from 'mitt'; diff --git a/apps/wallet/src/background/accounts/index.ts b/apps/wallet/src/background/accounts/index.ts index d08e1ef8ad8..32069046a34 100644 --- a/apps/wallet/src/background/accounts/index.ts +++ b/apps/wallet/src/background/accounts/index.ts @@ -1,6 +1,4 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 @@ -10,7 +8,7 @@ import { type MethodPayload, } from '_src/shared/messaging/messages/payloads/MethodPayload'; import { type WalletStatusChange } from '_src/shared/messaging/messages/payloads/wallet-status-change'; -import { fromB64 } from '@mysten/sui.js/utils'; +import { fromB64 } from '@iota/iota.js/utils'; import Dexie from 'dexie'; import { getAccountSourceByID } from '../account-sources'; diff --git a/apps/wallet/src/background/accounts/zklogin/ZkLoginAccount.ts b/apps/wallet/src/background/accounts/zklogin/ZkLoginAccount.ts index a9872766141..91ada433841 100644 --- a/apps/wallet/src/background/accounts/zklogin/ZkLoginAccount.ts +++ b/apps/wallet/src/background/accounts/zklogin/ZkLoginAccount.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import networkEnv from '_src/background/NetworkEnv'; @@ -9,8 +10,8 @@ import { toSerializedSignature, type PublicKey, type SerializedSignature, -} from '@mysten/sui.js/cryptography'; -import { computeZkLoginAddress, genAddressSeed, getZkLoginSignature } from '@mysten/zklogin'; +} from '@iota/iota.js/cryptography'; +import { computeZkLoginAddress, genAddressSeed, getZkLoginSignature } from '@iota/zklogin'; import { blake2b } from '@noble/hashes/blake2b'; import { decodeJwt } from 'jose'; diff --git a/apps/wallet/src/background/accounts/zklogin/current-epoch.ts b/apps/wallet/src/background/accounts/zklogin/current-epoch.ts index e9f80c02c4c..3adcdeefa19 100644 --- a/apps/wallet/src/background/accounts/zklogin/current-epoch.ts +++ b/apps/wallet/src/background/accounts/zklogin/current-epoch.ts @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import networkEnv from '_src/background/NetworkEnv'; import { getFromSessionStorage, setToSessionStorage } from '_src/background/storage-utils'; import { type NetworkEnvType } from '_src/shared/api-env'; -import { getActiveNetworkSuiClient } from '_src/shared/sui-client'; +import { getActiveNetworkIotaClient } from '_src/shared/iota-client'; type EpochCacheInfo = { epoch: number; @@ -16,9 +17,9 @@ function epochCacheKey(network: NetworkEnvType) { } async function getCurrentEpochRequest(): Promise { - const suiClient = await getActiveNetworkSuiClient(); + const iotaClient = await getActiveNetworkIotaClient(); const { epoch, epochDurationMs, epochStartTimestampMs } = - await suiClient.getLatestSuiSystemState(); + await iotaClient.getLatestIotaSystemState(); return { epoch: Number(epoch), epochEndTimestamp: Number(epochStartTimestampMs) + Number(epochDurationMs), diff --git a/apps/wallet/src/background/accounts/zklogin/providers.ts b/apps/wallet/src/background/accounts/zklogin/providers.ts index b35d6299f75..357698bbaf3 100644 --- a/apps/wallet/src/background/accounts/zklogin/providers.ts +++ b/apps/wallet/src/background/accounts/zklogin/providers.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import Browser from 'webextension-polyfill'; diff --git a/apps/wallet/src/background/accounts/zklogin/utils.ts b/apps/wallet/src/background/accounts/zklogin/utils.ts index 0fd5bed303d..d03028c15e1 100644 --- a/apps/wallet/src/background/accounts/zklogin/utils.ts +++ b/apps/wallet/src/background/accounts/zklogin/utils.ts @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type NetworkEnvType } from '_src/shared/api-env'; import { fetchWithSentry } from '_src/shared/utils'; -import { Network } from '@mysten/sui.js/client'; -import { type PublicKey } from '@mysten/sui.js/cryptography'; -import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519'; +import { Network } from '@iota/iota.js/client'; +import { type PublicKey } from '@iota/iota.js/cryptography'; +import { Ed25519Keypair } from '@iota/iota.js/keypairs/ed25519'; import { generateNonce, generateRandomness, getExtendedEphemeralPublicKey, type getZkLoginSignature, -} from '@mysten/zklogin'; +} from '@iota/zklogin'; import { randomBytes } from '@noble/hashes/utils'; import { base64url } from 'jose'; import { v4 as uuidV4 } from 'uuid'; diff --git a/apps/wallet/src/background/auto-lock-accounts.ts b/apps/wallet/src/background/auto-lock-accounts.ts index 4de3aea3c06..b9e03397bf7 100644 --- a/apps/wallet/src/background/auto-lock-accounts.ts +++ b/apps/wallet/src/background/auto-lock-accounts.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { throttle } from 'throttle-debounce'; diff --git a/apps/wallet/src/background/connections/Connection.ts b/apps/wallet/src/background/connections/Connection.ts index 107af03d453..d7023c9478e 100644 --- a/apps/wallet/src/background/connections/Connection.ts +++ b/apps/wallet/src/background/connections/Connection.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import type { Message } from '_messages'; diff --git a/apps/wallet/src/background/connections/ContentScriptConnection.ts b/apps/wallet/src/background/connections/ContentScriptConnection.ts index a7ca11b36c9..6427bbe6f81 100644 --- a/apps/wallet/src/background/connections/ContentScriptConnection.ts +++ b/apps/wallet/src/background/connections/ContentScriptConnection.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { createMessage } from '_messages'; @@ -29,7 +30,7 @@ import { type SignMessageRequest, } from '_src/shared/messaging/messages/payloads/transactions/SignMessage'; import { type SignedTransaction } from '_src/ui/app/WalletSigner'; -import { type SuiTransactionBlockResponse } from '@mysten/sui.js/client'; +import { type IotaTransactionBlockResponse } from '@iota/iota.js/client'; import type { Runtime } from 'webextension-polyfill'; import { getAccountsStatusData } from '../accounts'; @@ -37,7 +38,7 @@ import NetworkEnv from '../NetworkEnv'; import { Connection } from './Connection'; export class ContentScriptConnection extends Connection { - public static readonly CHANNEL: PortChannelName = 'sui_content<->background'; + public static readonly CHANNEL: PortChannelName = 'iota_content<->background'; public readonly origin: string; public readonly pagelink?: string | undefined; public readonly originFavIcon: string | undefined; @@ -94,7 +95,7 @@ export class ContentScriptConnection extends Connection { createMessage( { type: 'execute-transaction-response', - result: result as SuiTransactionBlockResponse, + result: result as IotaTransactionBlockResponse, }, msg.id, ), diff --git a/apps/wallet/src/background/connections/UiConnection.ts b/apps/wallet/src/background/connections/UiConnection.ts index 5f8044a463f..72a1256b51b 100644 --- a/apps/wallet/src/background/connections/UiConnection.ts +++ b/apps/wallet/src/background/connections/UiConnection.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { createMessage } from '_messages'; @@ -47,7 +48,7 @@ import NetworkEnv from '../NetworkEnv'; import { Connection } from './Connection'; export class UiConnection extends Connection { - public static readonly CHANNEL: PortChannelName = 'sui_ui<->background'; + public static readonly CHANNEL: PortChannelName = 'iota_ui<->background'; private uiAppInitialized: BehaviorSubject = new BehaviorSubject(false); constructor(port: Runtime.Port) { diff --git a/apps/wallet/src/background/connections/index.ts b/apps/wallet/src/background/connections/index.ts index 74040248bdf..783839375e2 100644 --- a/apps/wallet/src/background/connections/index.ts +++ b/apps/wallet/src/background/connections/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { createMessage } from '_messages'; diff --git a/apps/wallet/src/background/db.ts b/apps/wallet/src/background/db.ts index 458b8750b95..c09cfa40de9 100644 --- a/apps/wallet/src/background/db.ts +++ b/apps/wallet/src/background/db.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import Dexie, { type Table } from 'dexie'; @@ -9,7 +10,7 @@ import { type AccountType, type SerializedAccount } from './accounts/Account'; import { captureException } from './sentry'; import { getFromLocalStorage, setToLocalStorage } from './storage-utils'; -const dbName = 'SuiWallet DB'; +const dbName = 'IotaWallet DB'; const dbLocalStorageBackupKey = 'indexed-db-backup'; export const settingsKeys = { diff --git a/apps/wallet/src/background/index.ts b/apps/wallet/src/background/index.ts index f078a5869e2..8e82e03ee84 100644 --- a/apps/wallet/src/background/index.ts +++ b/apps/wallet/src/background/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { openInNewTab } from '_shared/utils'; diff --git a/apps/wallet/src/background/legacy-accounts/LegacyVault.ts b/apps/wallet/src/background/legacy-accounts/LegacyVault.ts index 5b37f15f53d..b62e7b84000 100644 --- a/apps/wallet/src/background/legacy-accounts/LegacyVault.ts +++ b/apps/wallet/src/background/legacy-accounts/LegacyVault.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { decrypt } from '_shared/cryptography/keystore'; @@ -12,7 +13,7 @@ import { fromExportedKeypair, type LegacyExportedKeyPair, } from '_shared/utils/from-exported-keypair'; -import { mnemonicToSeedHex, type Keypair } from '@mysten/sui.js/cryptography'; +import { mnemonicToSeedHex, type Keypair } from '@iota/iota.js/cryptography'; import { getFromLocalStorage } from '../storage-utils'; diff --git a/apps/wallet/src/background/legacy-accounts/storage-migration.ts b/apps/wallet/src/background/legacy-accounts/storage-migration.ts index b3169c2196e..5a1a592b375 100644 --- a/apps/wallet/src/background/legacy-accounts/storage-migration.ts +++ b/apps/wallet/src/background/legacy-accounts/storage-migration.ts @@ -1,6 +1,4 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 diff --git a/apps/wallet/src/background/sentry.ts b/apps/wallet/src/background/sentry.ts index 9d4e818670e..801ad06f91a 100644 --- a/apps/wallet/src/background/sentry.ts +++ b/apps/wallet/src/background/sentry.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { growthbook } from '_src/shared/experimentation/features'; diff --git a/apps/wallet/src/background/session-ephemeral-values.ts b/apps/wallet/src/background/session-ephemeral-values.ts index d1c87da8f3a..ae820d67b13 100644 --- a/apps/wallet/src/background/session-ephemeral-values.ts +++ b/apps/wallet/src/background/session-ephemeral-values.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Serializable } from '_shared/cryptography/keystore'; diff --git a/apps/wallet/src/background/storage-utils.ts b/apps/wallet/src/background/storage-utils.ts index 7799f851e13..87c2e6ac475 100644 --- a/apps/wallet/src/background/storage-utils.ts +++ b/apps/wallet/src/background/storage-utils.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { diff --git a/apps/wallet/src/content-script/index.ts b/apps/wallet/src/content-script/index.ts index 03a0e8d64ea..9b3662e815d 100644 --- a/apps/wallet/src/content-script/index.ts +++ b/apps/wallet/src/content-script/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { injectDappInterface } from './interface-inject'; diff --git a/apps/wallet/src/content-script/interface-inject.ts b/apps/wallet/src/content-script/interface-inject.ts index bfe65bf5e53..5d385e88c4f 100644 --- a/apps/wallet/src/content-script/interface-inject.ts +++ b/apps/wallet/src/content-script/interface-inject.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import Browser from 'webextension-polyfill'; diff --git a/apps/wallet/src/content-script/messages-proxy.ts b/apps/wallet/src/content-script/messages-proxy.ts index 980ce477eea..45de89db3d9 100644 --- a/apps/wallet/src/content-script/messages-proxy.ts +++ b/apps/wallet/src/content-script/messages-proxy.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { PortStream } from '_messaging/PortStream'; @@ -7,7 +8,7 @@ import type { Message } from '_src/shared/messaging/messages'; import { take } from 'rxjs'; function createPort(windowMsgStream: WindowMessageStream, currentMsg?: Message) { - const port = PortStream.connectToBackgroundService('sui_content<->background'); + const port = PortStream.connectToBackgroundService('iota_content<->background'); if (currentMsg) { port.sendMessage(currentMsg); } @@ -24,7 +25,7 @@ function createPort(windowMsgStream: WindowMessageStream, currentMsg?: Message) } export function setupMessagesProxy() { - const windowMsgStream = new WindowMessageStream('sui_content-script', 'sui_in-page'); + const windowMsgStream = new WindowMessageStream('iota_content-script', 'iota_in-page'); windowMsgStream.messages.pipe(take(1)).subscribe((msg) => { createPort(windowMsgStream, msg); }); diff --git a/apps/wallet/src/dapp-interface/WalletStandardInterface.ts b/apps/wallet/src/dapp-interface/WalletStandardInterface.ts index df95a798567..c6e8e35d532 100644 --- a/apps/wallet/src/dapp-interface/WalletStandardInterface.ts +++ b/apps/wallet/src/dapp-interface/WalletStandardInterface.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { createMessage } from '_messages'; @@ -23,9 +24,9 @@ import type { import { getCustomNetwork, type NetworkEnvType } from '_src/shared/api-env'; import { type SignMessageRequest } from '_src/shared/messaging/messages/payloads/transactions/SignMessage'; import { isWalletStatusChangePayload } from '_src/shared/messaging/messages/payloads/wallet-status-change'; -import { getNetwork, Network, type ChainType } from '@mysten/sui.js/client'; -import { isTransactionBlock } from '@mysten/sui.js/transactions'; -import { fromB64, toB64 } from '@mysten/sui.js/utils'; +import { getNetwork, Network, type ChainType } from '@iota/iota.js/client'; +import { isTransactionBlock } from '@iota/iota.js/transactions'; +import { fromB64, toB64 } from '@iota/iota.js/utils'; import { ReadonlyWalletAccount, SUPPORTED_CHAINS, @@ -34,13 +35,13 @@ import { type StandardEventsFeature, type StandardEventsListeners, type StandardEventsOnMethod, - type SuiFeatures, - type SuiSignAndExecuteTransactionBlockMethod, - type SuiSignMessageMethod, - type SuiSignPersonalMessageMethod, - type SuiSignTransactionBlockMethod, + type IotaFeatures, + type IotaSignAndExecuteTransactionBlockMethod, + type IotaSignMessageMethod, + type IotaSignPersonalMessageMethod, + type IotaSignTransactionBlockMethod, type Wallet, -} from '@mysten/wallet-standard'; +} from '@iota/wallet-standard'; import mitt, { type Emitter } from 'mitt'; import { filter, map, type Observable } from 'rxjs'; @@ -51,9 +52,9 @@ type WalletEventsMap = { }; // NOTE: Because this runs in a content script, we can't fetch the manifest. -const name = process.env.APP_NAME || 'Sui Wallet'; +const name = process.env.APP_NAME || 'Iota Wallet'; -export class SuiWallet implements Wallet { +export class IotaWallet implements Wallet { readonly #events: Emitter; readonly #version = '1.0.0' as const; readonly #name = name; @@ -78,7 +79,7 @@ export class SuiWallet implements Wallet { return SUPPORTED_CHAINS; } - get features(): StandardConnectFeature & StandardEventsFeature & SuiFeatures { + get features(): StandardConnectFeature & StandardEventsFeature & IotaFeatures { return { 'standard:connect': { version: '1.0.0', @@ -88,19 +89,19 @@ export class SuiWallet implements Wallet { version: '1.0.0', on: this.#on, }, - 'sui:signTransactionBlock': { + 'iota:signTransactionBlock': { version: '1.0.0', signTransactionBlock: this.#signTransactionBlock, }, - 'sui:signAndExecuteTransactionBlock': { + 'iota:signAndExecuteTransactionBlock': { version: '1.0.0', signAndExecuteTransactionBlock: this.#signAndExecuteTransactionBlock, }, - 'sui:signMessage': { + 'iota:signMessage': { version: '1.0.0', signMessage: this.#signMessage, }, - 'sui:signPersonalMessage': { + 'iota:signPersonalMessage': { version: '1.0.0', signPersonalMessage: this.#signPersonalMessage, }, @@ -119,7 +120,7 @@ export class SuiWallet implements Wallet { label: nickname || undefined, publicKey: publicKey ? fromB64(publicKey) : new Uint8Array(), chains: this.#activeChain ? [this.#activeChain] : [], - features: ['sui:signAndExecuteTransaction'], + features: ['iota:signAndExecuteTransaction'], }), ); } @@ -127,7 +128,7 @@ export class SuiWallet implements Wallet { constructor() { this.#events = mitt(); this.#accounts = []; - this.#messagesStream = new WindowMessageStream('sui_in-page', 'sui_content-script'); + this.#messagesStream = new WindowMessageStream('iota_in-page', 'iota_content-script'); this.#messagesStream.messages.subscribe(({ payload }) => { if (isWalletStatusChangePayload(payload)) { const { network, accounts } = payload; @@ -190,7 +191,7 @@ export class SuiWallet implements Wallet { return { accounts: this.accounts }; }; - #signTransactionBlock: SuiSignTransactionBlockMethod = async ({ + #signTransactionBlock: IotaSignTransactionBlockMethod = async ({ transactionBlock, account, ...input @@ -216,7 +217,7 @@ export class SuiWallet implements Wallet { ); }; - #signAndExecuteTransactionBlock: SuiSignAndExecuteTransactionBlockMethod = async (input) => { + #signAndExecuteTransactionBlock: IotaSignAndExecuteTransactionBlockMethod = async (input) => { if (!isTransactionBlock(input.transactionBlock)) { throw new Error( 'Unexpect transaction format found. Ensure that you are using the `Transaction` class.', @@ -239,7 +240,7 @@ export class SuiWallet implements Wallet { ); }; - #signMessage: SuiSignMessageMethod = async ({ message, account }) => { + #signMessage: IotaSignMessageMethod = async ({ message, account }) => { return mapToPromise( this.#send({ type: 'sign-message-request', @@ -257,7 +258,7 @@ export class SuiWallet implements Wallet { ); }; - #signPersonalMessage: SuiSignPersonalMessageMethod = async ({ message, account }) => { + #signPersonalMessage: IotaSignPersonalMessageMethod = async ({ message, account }) => { return mapToPromise( this.#send({ type: 'sign-message-request', diff --git a/apps/wallet/src/dapp-interface/index.ts b/apps/wallet/src/dapp-interface/index.ts index 32dcf3969d8..1c27c20b54e 100644 --- a/apps/wallet/src/dapp-interface/index.ts +++ b/apps/wallet/src/dapp-interface/index.ts @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { registerWallet } from '@mysten/wallet-standard'; +import { registerWallet } from '@iota/wallet-standard'; -import { SuiWallet } from './WalletStandardInterface'; +import { IotaWallet } from './WalletStandardInterface'; -registerWallet(new SuiWallet()); +registerWallet(new IotaWallet()); diff --git a/apps/wallet/src/dapp-interface/utils.ts b/apps/wallet/src/dapp-interface/utils.ts index f616d58b11c..bab9ad0e6df 100644 --- a/apps/wallet/src/dapp-interface/utils.ts +++ b/apps/wallet/src/dapp-interface/utils.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isErrorPayload, type Payload } from '_payloads'; diff --git a/apps/wallet/src/manifest/icons/sui-icon-128.png b/apps/wallet/src/manifest/icons/iota-icon-128.png similarity index 100% rename from apps/wallet/src/manifest/icons/sui-icon-128.png rename to apps/wallet/src/manifest/icons/iota-icon-128.png diff --git a/apps/wallet/src/manifest/icons/sui-icon-16.png b/apps/wallet/src/manifest/icons/iota-icon-16.png similarity index 100% rename from apps/wallet/src/manifest/icons/sui-icon-16.png rename to apps/wallet/src/manifest/icons/iota-icon-16.png diff --git a/apps/wallet/src/manifest/icons/sui-icon-32.png b/apps/wallet/src/manifest/icons/iota-icon-32.png similarity index 100% rename from apps/wallet/src/manifest/icons/sui-icon-32.png rename to apps/wallet/src/manifest/icons/iota-icon-32.png diff --git a/apps/wallet/src/manifest/icons/sui-icon-48.png b/apps/wallet/src/manifest/icons/iota-icon-48.png similarity index 100% rename from apps/wallet/src/manifest/icons/sui-icon-48.png rename to apps/wallet/src/manifest/icons/iota-icon-48.png diff --git a/apps/wallet/src/manifest/manifest.json b/apps/wallet/src/manifest/manifest.json index 898a430fe3f..700816abd07 100644 --- a/apps/wallet/src/manifest/manifest.json +++ b/apps/wallet/src/manifest/manifest.json @@ -12,14 +12,14 @@ }, "host_permissions": [ "http://127.0.0.1:5001/", - "https://fullnode.devnet.sui.io/", - "https://fullnode.staging.sui.io/" + "https://fullnode.devnet.iota.io/", + "https://fullnode.staging.iota.io/" ], "icons": { - "16": "manifest/icons/sui-icon-16.png", - "32": "manifest/icons/sui-icon-32.png", - "48": "manifest/icons/sui-icon-48.png", - "128": "manifest/icons/sui-icon-128.png" + "16": "manifest/icons/iota-icon-16.png", + "32": "manifest/icons/iota-icon-32.png", + "48": "manifest/icons/iota-icon-48.png", + "128": "manifest/icons/iota-icon-128.png" }, "content_scripts": [ { diff --git a/apps/wallet/src/shared/analytics/ampli/index.ts b/apps/wallet/src/shared/analytics/ampli/index.ts index a4f996a7d39..d3abf17a096 100644 --- a/apps/wallet/src/shared/analytics/ampli/index.ts +++ b/apps/wallet/src/shared/analytics/ampli/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /* tslint:disable */ @@ -15,9 +16,9 @@ * Build: 1.0.0 * Runtime: browser:typescript-ampli-v2 * - * [View Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest) + * [View Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest) * - * [Full Setup Instructions](https://data.amplitude.com/mystenlabs/Sui%20Wallet/implementation/web) + * [Full Setup Instructions](https://data.amplitude.com/mystenlabs/Iota%20Wallet/implementation/web) */ import * as amplitude from '@amplitude/analytics-browser'; @@ -73,7 +74,7 @@ export interface IdentifyProperties { */ activeAccountType?: string; /** - * The Sui Network that the user is currently interacting with. + * The Iota Network that the user is currently interacting with. */ activeNetwork: string; /** @@ -134,7 +135,7 @@ export interface ClickedCollectibleCardProperties { */ collectibleType: string; /** - * The ID of an object on Sui. + * The ID of an object on Iota. */ objectId: string; sourceScreen?: string; @@ -153,7 +154,7 @@ export interface ClickedHideAssetProperties { */ collectibleType: string; /** - * The ID of an object on Sui. + * The ID of an object on Iota. */ objectId: string; } @@ -187,9 +188,9 @@ export interface ClickedSocialSignInButtonProperties { sourceFlow: string; } -export interface ClickedStakeSuiProperties { +export interface ClickedStakeIotaProperties { /** - * Whether or not the user is already staking some SUI. + * Whether or not the user is already staking some IOTA. */ isCurrentlyStaking: boolean; /** @@ -208,7 +209,7 @@ export interface ClickedSwapCoinProperties { */ sourceFlow: string; /** - * The total balance in SUI of the selected coin that the user has. + * The total balance in IOTA of the selected coin that the user has. * * | Rule | Value | * |---|---| @@ -217,9 +218,9 @@ export interface ClickedSwapCoinProperties { totalBalance: number; } -export interface ClickedUnstakeSuiProperties { +export interface ClickedUnstakeIotaProperties { /** - * The amount of SUI staked. + * The amount of IOTA staked. * * | Rule | Value | * |---|---| @@ -330,7 +331,7 @@ export interface SelectedCoinProperties { */ coinType: string; /** - * The total balance in SUI of the selected coin that the user has. + * The total balance in IOTA of the selected coin that the user has. * * | Rule | Value | * |---|---| @@ -364,14 +365,14 @@ export interface SentCoinsProperties { export interface SentCollectibleProperties { /** - * The ID of an object on Sui. + * The ID of an object on Iota. */ objectId: string; } -export interface StakedSuiProperties { +export interface StakedIotaProperties { /** - * The amount of SUI staked. + * The amount of IOTA staked. * * | Rule | Value | * |---|---| @@ -394,7 +395,7 @@ export interface SwappedCoinProperties { fromCoinType: string; toCoinType: string; /** - * The total balance in SUI of the selected coin that the user has. + * The total balance in IOTA of the selected coin that the user has. * * | Rule | Value | * |---|---| @@ -421,7 +422,7 @@ export interface UnpinnedCoinProperties { coinType: string; } -export interface UnstakedSuiProperties { +export interface UnstakedIotaProperties { /** * The address of the selected validator. */ @@ -512,10 +513,10 @@ export class ClickedSocialSignInButton implements BaseEvent { } } -export class ClickedStakeSui implements BaseEvent { - event_type = 'clicked stake SUI'; +export class ClickedStakeIota implements BaseEvent { + event_type = 'clicked stake IOTA'; - constructor(public event_properties: ClickedStakeSuiProperties) { + constructor(public event_properties: ClickedStakeIotaProperties) { this.event_properties = event_properties; } } @@ -528,10 +529,10 @@ export class ClickedSwapCoin implements BaseEvent { } } -export class ClickedUnstakeSui implements BaseEvent { - event_type = 'clicked unstake SUI'; +export class ClickedUnstakeIota implements BaseEvent { + event_type = 'clicked unstake IOTA'; - constructor(public event_properties: ClickedUnstakeSuiProperties) { + constructor(public event_properties: ClickedUnstakeIotaProperties) { this.event_properties = event_properties; } } @@ -640,10 +641,10 @@ export class SentCollectible implements BaseEvent { } } -export class StakedSui implements BaseEvent { - event_type = 'staked SUI'; +export class StakedIota implements BaseEvent { + event_type = 'staked IOTA'; - constructor(public event_properties: StakedSuiProperties) { + constructor(public event_properties: StakedIotaProperties) { this.event_properties = event_properties; } } @@ -680,10 +681,10 @@ export class UnpinnedCoin implements BaseEvent { } } -export class UnstakedSui implements BaseEvent { - event_type = 'unstaked SUI'; +export class UnstakedIota implements BaseEvent { + event_type = 'unstaked IOTA'; - constructor(public event_properties: UnstakedSuiProperties) { + constructor(public event_properties: UnstakedIotaProperties) { this.event_properties = event_properties; } } @@ -812,7 +813,7 @@ export class Ampli { /** * added accounts * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/added%20accounts) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/added%20accounts) * * When users successfully add new accounts to the wallet. * @@ -831,7 +832,7 @@ export class Ampli { /** * clicked bullshark quests cta * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/clicked%20bullshark%20quests%20cta) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/clicked%20bullshark%20quests%20cta) * * When users click the call-to-action for the Bullshark Quests interstitial/banner. * @@ -848,7 +849,7 @@ export class Ampli { /** * clicked collectible card * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/clicked%20collectible%20card) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/clicked%20collectible%20card) * * When users click to view a collectible in the wallet. * @@ -867,7 +868,7 @@ export class Ampli { /** * clicked create new account * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/clicked%20create%20new%20account) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/clicked%20create%20new%20account) * * When users click the button to create a new passphrase account. * @@ -884,7 +885,7 @@ export class Ampli { /** * clicked create new wallet * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/clicked%20create%20new%20wallet) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/clicked%20create%20new%20wallet) * * When users click to create a new wallet during onboarding. * @@ -901,7 +902,7 @@ export class Ampli { /** * clicked get started * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/clicked%20get%20started) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/clicked%20get%20started) * * When users click "Get Started" after installing the wallet. * @@ -918,7 +919,7 @@ export class Ampli { /** * clicked hide asset * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/clicked%20hide%20asset) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/clicked%20hide%20asset) * * Event has no description in tracking plan. * @@ -935,7 +936,7 @@ export class Ampli { /** * clicked import existing wallet * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/clicked%20import%20existing%20wallet) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/clicked%20import%20existing%20wallet) * * When users click to import an existing wallet during onboarding. * @@ -952,7 +953,7 @@ export class Ampli { /** * clicked import passphrase * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/clicked%20import%20passphrase) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/clicked%20import%20passphrase) * * When users click to import an account via passphrase. * @@ -969,7 +970,7 @@ export class Ampli { /** * clicked import private key * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/clicked%20import%20private%20key) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/clicked%20import%20private%20key) * * When users click the button to import an account via private key. * @@ -986,7 +987,7 @@ export class Ampli { /** * clicked social sign in button * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/clicked%20social%20sign%20in%20button) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/clicked%20social%20sign%20in%20button) * * When users click a social sign-in button to create an account. * @@ -1001,28 +1002,28 @@ export class Ampli { } /** - * clicked stake SUI + * clicked stake IOTA * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/clicked%20stake%20SUI) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/clicked%20stake%20IOTA) * - * When users click to stake SUI in the wallet. + * When users click to stake IOTA in the wallet. * * Owner: Jon Shek * * @param properties The event's properties (e.g. isCurrentlyStaking) * @param options Amplitude event options. */ - clickedStakeSui( - properties: ClickedStakeSuiProperties, + clickedStakeIota( + properties: ClickedStakeIotaProperties, options?: EventOptions, ) { - return this.track(new ClickedStakeSui(properties), options); + return this.track(new ClickedStakeIota(properties), options); } /** * clicked swap coin * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/clicked%20swap%20coin) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/clicked%20swap%20coin) * * When users click to swap a coin in the wallet * @@ -1037,28 +1038,28 @@ export class Ampli { } /** - * clicked unstake SUI + * clicked unstake IOTA * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/clicked%20unstake%20SUI) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/clicked%20unstake%20IOTA) * - * When users click to unstake SUI. + * When users click to unstake IOTA. * * Owner: Jon Shek * * @param properties The event's properties (e.g. stakedAmount) * @param options Amplitude event options. */ - clickedUnstakeSui( - properties: ClickedUnstakeSuiProperties, + clickedUnstakeIota( + properties: ClickedUnstakeIotaProperties, options?: EventOptions, ) { - return this.track(new ClickedUnstakeSui(properties), options); + return this.track(new ClickedUnstakeIota(properties), options); } /** * connected hardware wallet * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/connected%20hardware%20wallet) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/connected%20hardware%20wallet) * * When users successfully connect their hardware wallet. * @@ -1077,7 +1078,7 @@ export class Ampli { /** * created new wallet * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/created%20new%20wallet) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/created%20new%20wallet) * * When users successfully create a new wallet during onboarding. * @@ -1094,7 +1095,7 @@ export class Ampli { /** * disconnected application * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/disconnected%20application) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/disconnected%20application) * * When users disconnect from an application in the wallet. * @@ -1113,7 +1114,7 @@ export class Ampli { /** * imported existing account * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/imported%20existing%20account) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/imported%20existing%20account) * * When users successfully import an existing account during onboarding. * @@ -1132,7 +1133,7 @@ export class Ampli { /** * opened application * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/opened%20application) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/opened%20application) * * When users click to open an application from the wallet. * @@ -1151,7 +1152,7 @@ export class Ampli { /** * opened connect ledger flow * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/opened%20connect%20ledger%20flow) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/opened%20connect%20ledger%20flow) * * When users open the "Connect Ledger Wallet" flow. * @@ -1170,7 +1171,7 @@ export class Ampli { /** * opened wallet extension * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/opened%20wallet%20extension) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/opened%20wallet%20extension) * * When users first open the wallet extension. * @@ -1187,7 +1188,7 @@ export class Ampli { /** * pinned coin * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/pinned%20coin) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/pinned%20coin) * * When users pin an unrecognized coin on the home page. * @@ -1206,7 +1207,7 @@ export class Ampli { /** * responded to connection request * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/responded%20to%20connection%20request) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/responded%20to%20connection%20request) * * When users respond to a connection request in the wallet. * @@ -1225,7 +1226,7 @@ export class Ampli { /** * responded to transaction request * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/responded%20to%20transaction%20request) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/responded%20to%20transaction%20request) * * When users respond to a transaction request from an application. * @@ -1244,7 +1245,7 @@ export class Ampli { /** * selected coin * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/selected%20coin) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/selected%20coin) * * When users select a specific coin from the home screen. * @@ -1263,7 +1264,7 @@ export class Ampli { /** * selected validator * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/selected%20validator) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/selected%20validator) * * When users select a validator in the staking flow. * @@ -1282,7 +1283,7 @@ export class Ampli { /** * sent coins * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/sent%20coins) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/sent%20coins) * * When users successfully send coins to someone. * @@ -1301,7 +1302,7 @@ export class Ampli { /** * sent collectible * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/sent%20collectible) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/sent%20collectible) * * Owner: William Robertson * @@ -1316,28 +1317,28 @@ export class Ampli { } /** - * staked SUI + * staked IOTA * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/staked%20SUI) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/staked%20IOTA) * - * When users successfully stake SUI with a validator. + * When users successfully stake IOTA with a validator. * * Owner: Jon Shek * * @param properties The event's properties (e.g. stakedAmount) * @param options Amplitude event options. */ - stakedSui( - properties: StakedSuiProperties, + stakedIota( + properties: StakedIotaProperties, options?: EventOptions, ) { - return this.track(new StakedSui(properties), options); + return this.track(new StakedIota(properties), options); } /** * swapped coin * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/swapped%20coin) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/swapped%20coin) * * When users complete swapping 1 coin to another * @@ -1354,7 +1355,7 @@ export class Ampli { /** * switched account * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/switched%20account) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/switched%20account) * * When users switch their active account in the wallet. * @@ -1373,7 +1374,7 @@ export class Ampli { /** * switched network * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/switched%20network) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/switched%20network) * * When users switch between different network connections. * @@ -1392,7 +1393,7 @@ export class Ampli { /** * unpinned coin * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/unpinned%20coin) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/unpinned%20coin) * * When users un-pin a recognized coin on the home page. * @@ -1409,28 +1410,28 @@ export class Ampli { } /** - * unstaked SUI + * unstaked IOTA * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/unstaked%20SUI) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/unstaked%20IOTA) * - * When users successfully un-stake SUI. + * When users successfully un-stake IOTA. * * Owner: Jon Shek * * @param properties The event's properties (e.g. validatorAddress) * @param options Amplitude event options. */ - unstakedSui( - properties: UnstakedSuiProperties, + unstakedIota( + properties: UnstakedIotaProperties, options?: EventOptions, ) { - return this.track(new UnstakedSui(properties), options); + return this.track(new UnstakedIota(properties), options); } /** * viewed ledger tutorial * - * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Sui%20Wallet/events/main/latest/viewed%20ledger%20tutorial) + * [View in Tracking Plan](https://data.amplitude.com/mystenlabs/Iota%20Wallet/events/main/latest/viewed%20ledger%20tutorial) * * When users click the link to get help with connecting their Ledger wallet. * diff --git a/apps/wallet/src/shared/analytics/amplitude.ts b/apps/wallet/src/shared/analytics/amplitude.ts index 72afb66fe88..c6ed6da31e4 100644 --- a/apps/wallet/src/shared/analytics/amplitude.ts +++ b/apps/wallet/src/shared/analytics/amplitude.ts @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import * as amplitude from '@amplitude/analytics-browser'; import { LogLevel, TransportType, type UserSession } from '@amplitude/analytics-types'; -import { PersistableStorage } from '@mysten/core'; +import { PersistableStorage } from '@iota/core'; import { ampli } from './ampli'; diff --git a/apps/wallet/src/shared/api-env.ts b/apps/wallet/src/shared/api-env.ts index aa05c1998bb..6bf85619b06 100644 --- a/apps/wallet/src/shared/api-env.ts +++ b/apps/wallet/src/shared/api-env.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { @@ -6,7 +7,7 @@ import { getNetwork, Network, type NetworkConfiguration, -} from '@mysten/sui.js/client'; +} from '@iota/iota.js/client'; export type NetworkEnvType = | { network: Exclude; customRpcUrl: null } @@ -17,7 +18,7 @@ export function getCustomNetwork(rpc: string = ''): NetworkConfiguration { name: 'Custom RPC', id: Network.Custom, url: rpc, - chain: 'sui:unknown', + chain: 'iota:unknown', explorer: getNetwork(getDefaultNetwork()).explorer, }; } diff --git a/apps/wallet/src/shared/constants.ts b/apps/wallet/src/shared/constants.ts index 189dd5096ee..9eeac58b5a3 100644 --- a/apps/wallet/src/shared/constants.ts +++ b/apps/wallet/src/shared/constants.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -export const ToS_LINK = 'https://mystenlabs.com/legal#suiwallettermsofservice'; +export const ToS_LINK = 'https://mystenlabs.com/legal#iotawallettermsofservice'; export const PRIVACY_POLICY_LINK = 'https://mystenlabs.com/legal#privacypolicy'; export const FAQ_LINK = 'https://docs.mystenlabs.com/faq'; @@ -9,6 +10,6 @@ export const FAQ_LINK = 'https://docs.mystenlabs.com/faq'; // Staking Rewards Redeemable export const NUM_OF_EPOCH_BEFORE_STAKING_REWARDS_REDEEMABLE = 2; export const NUM_OF_EPOCH_BEFORE_STAKING_REWARDS_STARTS = 1; -export const MIN_NUMBER_SUI_TO_STAKE = 1; +export const MIN_NUMBER_IOTA_TO_STAKE = 1; export const DELEGATED_STAKES_QUERY_STALE_TIME = 10_000; export const DELEGATED_STAKES_QUERY_REFETCH_INTERVAL = 30_000; diff --git a/apps/wallet/src/shared/cryptography/keystore.test.ts b/apps/wallet/src/shared/cryptography/keystore.test.ts index 771fdb2c79a..4865f7ba239 100644 --- a/apps/wallet/src/shared/cryptography/keystore.test.ts +++ b/apps/wallet/src/shared/cryptography/keystore.test.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { describe, expect, it } from 'vitest'; diff --git a/apps/wallet/src/shared/cryptography/keystore.ts b/apps/wallet/src/shared/cryptography/keystore.ts index 54a5512245f..6cf11f81e67 100644 --- a/apps/wallet/src/shared/cryptography/keystore.ts +++ b/apps/wallet/src/shared/cryptography/keystore.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { diff --git a/apps/wallet/src/shared/deepBook/context.tsx b/apps/wallet/src/shared/deepBook/context.tsx index a6fe5cb1b21..9e33ab0cc2a 100644 --- a/apps/wallet/src/shared/deepBook/context.tsx +++ b/apps/wallet/src/shared/deepBook/context.tsx @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useDeepBookConfigs } from '_app/hooks/deepbook/useDeepBookConfigs'; import { useActiveAccount } from '_app/hooks/useActiveAccount'; import { DEFAULT_WALLET_FEE_ADDRESS, type Coins } from '_pages/swap/constants'; import { FEATURES } from '_shared/experimentation/features'; import { useFeatureValue } from '@growthbook/growthbook-react'; -import { useGetOwnedObjects } from '@mysten/core'; -import { useSuiClient } from '@mysten/dapp-kit'; -import { DeepBookClient } from '@mysten/deepbook'; +import { useGetOwnedObjects } from '@iota/core'; +import { useIotaClient } from '@iota/dapp-kit'; +import { DeepBookClient } from '@iota/deepbook'; import { createContext, useContext, useMemo, type ReactNode } from 'react'; type DeepBookContextProps = { @@ -35,7 +36,7 @@ export function useDeepBookContext() { } export function DeepBookContextProvider({ children }: DeepBookContextProviderProps) { - const suiClient = useSuiClient(); + const iotaClient = useIotaClient(); const activeAccount = useActiveAccount(); const activeAccountAddress = activeAccount?.address; @@ -58,8 +59,8 @@ export function DeepBookContextProvider({ children }: DeepBookContextProviderPro ?.owner as string; const deepBookClient = useMemo(() => { - return new DeepBookClient(suiClient, accountCapId); - }, [accountCapId, suiClient]); + return new DeepBookClient(iotaClient, accountCapId); + }, [accountCapId, iotaClient]); const contextValue = useMemo(() => { return { diff --git a/apps/wallet/src/shared/experimentation/features.ts b/apps/wallet/src/shared/experimentation/features.ts index 20b2662a9be..013a6015f28 100644 --- a/apps/wallet/src/shared/experimentation/features.ts +++ b/apps/wallet/src/shared/experimentation/features.ts @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 import { GrowthBook } from '@growthbook/growthbook'; -import { Network, getAppsBackend } from '@mysten/sui.js/client'; +import { Network, getAppsBackend } from '@iota/iota.js/client'; import Browser from 'webextension-polyfill'; // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export const growthbook = new GrowthBook({ apiHost: getAppsBackend(), diff --git a/apps/wallet/src/shared/iota-client.ts b/apps/wallet/src/shared/iota-client.ts new file mode 100644 index 00000000000..01fdbaa401e --- /dev/null +++ b/apps/wallet/src/shared/iota-client.ts @@ -0,0 +1,35 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import networkEnv from '_src/background/NetworkEnv'; +import { type NetworkEnvType } from '_src/shared/api-env'; +import { SentryHttpTransport } from '@iota/core'; +import { getNetwork, Network, IotaClient, IotaHTTPTransport } from '@iota/iota.js/client'; + +const iotaClientPerNetwork = new Map(); +const SENTRY_MONITORED_ENVS = [Network.Custom]; + +export function getIotaClient({ network, customRpcUrl }: NetworkEnvType): IotaClient { + const key = `${network}_${customRpcUrl}`; + if (!iotaClientPerNetwork.has(key)) { + const connection = getNetwork(network)?.url ?? customRpcUrl; + if (!connection) { + throw new Error(`API url not found for network ${network} ${customRpcUrl}`); + } + iotaClientPerNetwork.set( + key, + new IotaClient({ + transport: + !customRpcUrl && SENTRY_MONITORED_ENVS.includes(network) + ? new SentryHttpTransport(connection) + : new IotaHTTPTransport({ url: connection }), + }), + ); + } + return iotaClientPerNetwork.get(key)!; +} + +export async function getActiveNetworkIotaClient(): Promise { + return getIotaClient(await networkEnv.getActiveNetwork()); +} diff --git a/apps/wallet/src/shared/messaging/PortChannelName.ts b/apps/wallet/src/shared/messaging/PortChannelName.ts index 8a4ef89354a..ff66cb99abb 100644 --- a/apps/wallet/src/shared/messaging/PortChannelName.ts +++ b/apps/wallet/src/shared/messaging/PortChannelName.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -export type PortChannelName = 'sui_content<->background' | 'sui_ui<->background'; +export type PortChannelName = 'iota_content<->background' | 'iota_ui<->background'; diff --git a/apps/wallet/src/shared/messaging/PortStream.ts b/apps/wallet/src/shared/messaging/PortStream.ts index c802fbabc6c..728635900a5 100644 --- a/apps/wallet/src/shared/messaging/PortStream.ts +++ b/apps/wallet/src/shared/messaging/PortStream.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { filter, fromEventPattern, map, share, take, takeUntil, tap } from 'rxjs'; diff --git a/apps/wallet/src/shared/messaging/WindowMessageStream.ts b/apps/wallet/src/shared/messaging/WindowMessageStream.ts index e0d4c689225..dcce1c37ace 100644 --- a/apps/wallet/src/shared/messaging/WindowMessageStream.ts +++ b/apps/wallet/src/shared/messaging/WindowMessageStream.ts @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import type { Message } from '_messages'; import { filter, fromEvent, map, share } from 'rxjs'; import type { Observable } from 'rxjs'; -export type ClientType = 'sui_in-page' | 'sui_content-script'; +export type ClientType = 'iota_in-page' | 'iota_content-script'; type WindowMessage = { target: ClientType; diff --git a/apps/wallet/src/shared/messaging/messages/Message.ts b/apps/wallet/src/shared/messaging/messages/Message.ts index 89f5f837175..369f7e9b9cd 100644 --- a/apps/wallet/src/shared/messaging/messages/Message.ts +++ b/apps/wallet/src/shared/messaging/messages/Message.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { v4 as uuidV4 } from 'uuid'; diff --git a/apps/wallet/src/shared/messaging/messages/index.ts b/apps/wallet/src/shared/messaging/messages/index.ts index c497e2d3004..bfb0e742de3 100644 --- a/apps/wallet/src/shared/messaging/messages/index.ts +++ b/apps/wallet/src/shared/messaging/messages/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export * from './Message'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/BasePayload.ts b/apps/wallet/src/shared/messaging/messages/payloads/BasePayload.ts index 8faf8372454..a319a00b116 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/BasePayload.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/BasePayload.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import type { Payload } from './Payload'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/ErrorPayload.ts b/apps/wallet/src/shared/messaging/messages/payloads/ErrorPayload.ts index 03bb0332b6e..bfd70d93483 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/ErrorPayload.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/ErrorPayload.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import type { Payload } from './Payload'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/MethodPayload.ts b/apps/wallet/src/shared/messaging/messages/payloads/MethodPayload.ts index 4659828fb81..e9351dec84a 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/MethodPayload.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/MethodPayload.ts @@ -1,6 +1,4 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 @@ -8,7 +6,7 @@ import { type AccountSourceSerializedUI } from '_src/background/account-sources/ import { type SerializedUIAccount } from '_src/background/accounts/Account'; import { type ZkLoginProvider } from '_src/background/accounts/zklogin/providers'; import { type Status } from '_src/background/legacy-accounts/storage-migration'; -import { type SerializedSignature } from '@mysten/sui.js/cryptography'; +import { type SerializedSignature } from '@iota/iota.js/cryptography'; import { isBasePayload } from './BasePayload'; import type { Payload } from './Payload'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/Payload.ts b/apps/wallet/src/shared/messaging/messages/payloads/Payload.ts index 74f24999396..c498bf73bbe 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/Payload.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/Payload.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import type { BasePayload } from './BasePayload'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/account/GetAccount.ts b/apps/wallet/src/shared/messaging/messages/payloads/account/GetAccount.ts index 1d24e718393..b729b92a1fb 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/account/GetAccount.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/account/GetAccount.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/account/GetAccountResponse.ts b/apps/wallet/src/shared/messaging/messages/payloads/account/GetAccountResponse.ts index b4b41d8deab..b4646357457 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/account/GetAccountResponse.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/account/GetAccountResponse.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import type { BasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/feature-gating/index.ts b/apps/wallet/src/shared/messaging/messages/payloads/feature-gating/index.ts index 5a7ac62a8b9..0b4da561729 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/feature-gating/index.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/feature-gating/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/index.ts b/apps/wallet/src/shared/messaging/messages/payloads/index.ts index e9e0aded426..5a8e3e4bb03 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/index.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export * from './BasePayload'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/network/index.ts b/apps/wallet/src/shared/messaging/messages/payloads/network/index.ts index 56cc2fc7ce1..5e84a91c9cc 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/network/index.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/network/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/permissions/AcquirePermissionsRequest.ts b/apps/wallet/src/shared/messaging/messages/payloads/permissions/AcquirePermissionsRequest.ts index caa6f026b32..e78a952a67f 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/permissions/AcquirePermissionsRequest.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/permissions/AcquirePermissionsRequest.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/permissions/AcquirePermissionsResponse.ts b/apps/wallet/src/shared/messaging/messages/payloads/permissions/AcquirePermissionsResponse.ts index 8f6cd27e837..0ae47ac2d13 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/permissions/AcquirePermissionsResponse.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/permissions/AcquirePermissionsResponse.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/permissions/DisconnectApp.ts b/apps/wallet/src/shared/messaging/messages/payloads/permissions/DisconnectApp.ts index 0dbc9eb8aed..0f8c8a23858 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/permissions/DisconnectApp.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/permissions/DisconnectApp.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/permissions/GetPermissionRequests.ts b/apps/wallet/src/shared/messaging/messages/payloads/permissions/GetPermissionRequests.ts index bfcd5713212..5e86035c407 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/permissions/GetPermissionRequests.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/permissions/GetPermissionRequests.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/permissions/HasPermissionsRequest.ts b/apps/wallet/src/shared/messaging/messages/payloads/permissions/HasPermissionsRequest.ts index e37e8493933..507970c5843 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/permissions/HasPermissionsRequest.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/permissions/HasPermissionsRequest.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/permissions/HasPermissionsResponse.ts b/apps/wallet/src/shared/messaging/messages/payloads/permissions/HasPermissionsResponse.ts index d52b7d099d6..931497340ec 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/permissions/HasPermissionsResponse.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/permissions/HasPermissionsResponse.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/permissions/Permission.ts b/apps/wallet/src/shared/messaging/messages/payloads/permissions/Permission.ts index 4cbfdf25f45..61a79756ebd 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/permissions/Permission.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/permissions/Permission.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import type { PermissionType } from './PermissionType'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/permissions/PermissionRequests.ts b/apps/wallet/src/shared/messaging/messages/payloads/permissions/PermissionRequests.ts index f488c966fc1..0bae8c97003 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/permissions/PermissionRequests.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/permissions/PermissionRequests.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; import type { BasePayload, Payload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/permissions/PermissionResponse.ts b/apps/wallet/src/shared/messaging/messages/payloads/permissions/PermissionResponse.ts index 528c94c2a97..e615f4830ee 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/permissions/PermissionResponse.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/permissions/PermissionResponse.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/permissions/PermissionType.ts b/apps/wallet/src/shared/messaging/messages/payloads/permissions/PermissionType.ts index 55c4066a3ae..332311aa187 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/permissions/PermissionType.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/permissions/PermissionType.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export const ALL_PERMISSION_TYPES = ['viewAccount', 'suggestTransactions'] as const; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/permissions/index.ts b/apps/wallet/src/shared/messaging/messages/payloads/permissions/index.ts index 9b919481bf7..1e232093c81 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/permissions/index.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/permissions/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export * from './GetPermissionRequests'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/tabs/updateActiveOrigin.ts b/apps/wallet/src/shared/messaging/messages/payloads/tabs/updateActiveOrigin.ts index 5fe45852a57..bb5f29d2688 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/tabs/updateActiveOrigin.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/tabs/updateActiveOrigin.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/transactions/ApprovalRequest.ts b/apps/wallet/src/shared/messaging/messages/payloads/transactions/ApprovalRequest.ts index 9f419b0b938..2367c3582e5 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/transactions/ApprovalRequest.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/transactions/ApprovalRequest.ts @@ -1,20 +1,21 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type SignedTransaction } from '_src/ui/app/WalletSigner'; -import type { SuiTransactionBlockResponse } from '@mysten/sui.js/client'; +import type { IotaTransactionBlockResponse } from '@iota/iota.js/client'; import { - type SuiSignAndExecuteTransactionBlockInput, - type SuiSignMessageOutput, -} from '@mysten/wallet-standard'; + type IotaSignAndExecuteTransactionBlockInput, + type IotaSignMessageOutput, +} from '@iota/wallet-standard'; export type TransactionDataType = { type: 'transaction'; data: string; account: string; justSign?: boolean; - requestType?: SuiSignAndExecuteTransactionBlockInput['requestType']; - options?: SuiSignAndExecuteTransactionBlockInput['options']; + requestType?: IotaSignAndExecuteTransactionBlockInput['requestType']; + options?: IotaSignAndExecuteTransactionBlockInput['options']; }; export type SignMessageDataType = { @@ -28,7 +29,7 @@ export type ApprovalRequest = { approved: boolean | null; origin: string; originFavIcon?: string; - txResult?: SuiTransactionBlockResponse | SuiSignMessageOutput; + txResult?: IotaTransactionBlockResponse | IotaSignMessageOutput; txResultError?: string; txSigned?: SignedTransaction; createdDate: string; @@ -37,12 +38,12 @@ export type ApprovalRequest = { export interface SignMessageApprovalRequest extends Omit { tx: SignMessageDataType; - txResult?: SuiSignMessageOutput; + txResult?: IotaSignMessageOutput; } export interface TransactionApprovalRequest extends Omit { tx: TransactionDataType; - txResult?: SuiTransactionBlockResponse; + txResult?: IotaTransactionBlockResponse; } export function isSignMessageApprovalRequest( diff --git a/apps/wallet/src/shared/messaging/messages/payloads/transactions/ExecuteTransactionRequest.ts b/apps/wallet/src/shared/messaging/messages/payloads/transactions/ExecuteTransactionRequest.ts index 9638595f01d..cf83f1ab688 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/transactions/ExecuteTransactionRequest.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/transactions/ExecuteTransactionRequest.ts @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; import type { BasePayload, Payload } from '_payloads'; -import { type SuiSignTransactionBlockInput } from '@mysten/wallet-standard'; +import { type IotaSignTransactionBlockInput } from '@iota/wallet-standard'; import { type TransactionDataType } from './ApprovalRequest'; @@ -18,8 +19,8 @@ export function isExecuteTransactionRequest( return isBasePayload(payload) && payload.type === 'execute-transaction-request'; } -export type SuiSignTransactionSerialized = Omit< - SuiSignTransactionBlockInput, +export type IotaSignTransactionSerialized = Omit< + IotaSignTransactionBlockInput, 'transactionBlock' | 'account' > & { transaction: string; @@ -28,7 +29,7 @@ export type SuiSignTransactionSerialized = Omit< export interface SignTransactionRequest extends BasePayload { type: 'sign-transaction-request'; - transaction: SuiSignTransactionSerialized; + transaction: IotaSignTransactionSerialized; } export function isSignTransactionRequest(payload: Payload): payload is SignTransactionRequest { diff --git a/apps/wallet/src/shared/messaging/messages/payloads/transactions/ExecuteTransactionResponse.ts b/apps/wallet/src/shared/messaging/messages/payloads/transactions/ExecuteTransactionResponse.ts index bc79bf89464..06f778ccf4b 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/transactions/ExecuteTransactionResponse.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/transactions/ExecuteTransactionResponse.ts @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; import type { BasePayload, Payload } from '_payloads'; -import type { SuiTransactionBlockResponse } from '@mysten/sui.js/client'; -import { type SuiSignTransactionBlockOutput } from '@mysten/wallet-standard'; +import type { IotaTransactionBlockResponse } from '@iota/iota.js/client'; +import { type IotaSignTransactionBlockOutput } from '@iota/wallet-standard'; export interface ExecuteTransactionResponse extends BasePayload { type: 'execute-transaction-response'; - result: SuiTransactionBlockResponse; + result: IotaTransactionBlockResponse; } export function isExecuteTransactionResponse( @@ -19,7 +20,7 @@ export function isExecuteTransactionResponse( export interface SignTransactionResponse extends BasePayload { type: 'sign-transaction-response'; - result: SuiSignTransactionBlockOutput; + result: IotaSignTransactionBlockOutput; } export function isSignTransactionResponse(payload: Payload): payload is SignTransactionResponse { diff --git a/apps/wallet/src/shared/messaging/messages/payloads/transactions/SignMessage.ts b/apps/wallet/src/shared/messaging/messages/payloads/transactions/SignMessage.ts index b694bd3cc97..6e88039c7f3 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/transactions/SignMessage.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/transactions/SignMessage.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type SuiSignMessageOutput } from '@mysten/wallet-standard'; +import { type IotaSignMessageOutput } from '@iota/wallet-standard'; import { isBasePayload, type BasePayload } from '../BasePayload'; import { type Payload } from '../Payload'; @@ -12,7 +13,7 @@ export interface SignMessageRequest extends BasePayload { message: string; // base64 accountAddress: string; }; - return?: SuiSignMessageOutput; + return?: IotaSignMessageOutput; } export function isSignMessageRequest(payload: Payload): payload is SignMessageRequest { diff --git a/apps/wallet/src/shared/messaging/messages/payloads/transactions/index.ts b/apps/wallet/src/shared/messaging/messages/payloads/transactions/index.ts index 29211e1ae0e..ee98d0e2753 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/transactions/index.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/transactions/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export * from './ExecuteTransactionRequest'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/transactions/ui/GetTransactionRequests.ts b/apps/wallet/src/shared/messaging/messages/payloads/transactions/ui/GetTransactionRequests.ts index b8e27eae1e1..cbf4bd4a670 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/transactions/ui/GetTransactionRequests.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/transactions/ui/GetTransactionRequests.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/transactions/ui/GetTransactionRequestsResponse.ts b/apps/wallet/src/shared/messaging/messages/payloads/transactions/ui/GetTransactionRequestsResponse.ts index 020e0dd8755..df6f7df89ab 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/transactions/ui/GetTransactionRequestsResponse.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/transactions/ui/GetTransactionRequestsResponse.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/messaging/messages/payloads/transactions/ui/TransactionRequestResponse.ts b/apps/wallet/src/shared/messaging/messages/payloads/transactions/ui/TransactionRequestResponse.ts index bea7560b91f..5f0c067c38b 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/transactions/ui/TransactionRequestResponse.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/transactions/ui/TransactionRequestResponse.ts @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; import type { BasePayload, Payload } from '_payloads'; import { type SignedTransaction } from '_src/ui/app/WalletSigner'; -import type { SuiTransactionBlockResponse } from '@mysten/sui.js/client'; -import { type SuiSignMessageOutput } from '@mysten/wallet-standard'; +import type { IotaTransactionBlockResponse } from '@iota/iota.js/client'; +import { type IotaSignMessageOutput } from '@iota/wallet-standard'; export interface TransactionRequestResponse extends BasePayload { type: 'transaction-request-response'; txID: string; approved: boolean; - txResult?: SuiTransactionBlockResponse | SuiSignMessageOutput; + txResult?: IotaTransactionBlockResponse | IotaSignMessageOutput; txResultError?: string; txSigned?: SignedTransaction; } diff --git a/apps/wallet/src/shared/messaging/messages/payloads/wallet-status-change/index.ts b/apps/wallet/src/shared/messaging/messages/payloads/wallet-status-change/index.ts index 717bd69b859..b873c235301 100644 --- a/apps/wallet/src/shared/messaging/messages/payloads/wallet-status-change/index.ts +++ b/apps/wallet/src/shared/messaging/messages/payloads/wallet-status-change/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { isBasePayload } from '_payloads'; diff --git a/apps/wallet/src/shared/sentry-config.ts b/apps/wallet/src/shared/sentry-config.ts index e04574f6991..3705ead4aa8 100644 --- a/apps/wallet/src/shared/sentry-config.ts +++ b/apps/wallet/src/shared/sentry-config.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type BrowserOptions } from '@sentry/browser'; diff --git a/apps/wallet/src/shared/sui-client.ts b/apps/wallet/src/shared/sui-client.ts deleted file mode 100644 index d721954e776..00000000000 --- a/apps/wallet/src/shared/sui-client.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import networkEnv from '_src/background/NetworkEnv'; -import { type NetworkEnvType } from '_src/shared/api-env'; -import { SentryHttpTransport } from '@mysten/core'; -import { getNetwork, Network, SuiClient, SuiHTTPTransport } from '@mysten/sui.js/client'; - -const suiClientPerNetwork = new Map(); -const SENTRY_MONITORED_ENVS = [Network.Custom]; - -export function getSuiClient({ network, customRpcUrl }: NetworkEnvType): SuiClient { - const key = `${network}_${customRpcUrl}`; - if (!suiClientPerNetwork.has(key)) { - const connection = getNetwork(network)?.url ?? customRpcUrl; - if (!connection) { - throw new Error(`API url not found for network ${network} ${customRpcUrl}`); - } - suiClientPerNetwork.set( - key, - new SuiClient({ - transport: - !customRpcUrl && SENTRY_MONITORED_ENVS.includes(network) - ? new SentryHttpTransport(connection) - : new SuiHTTPTransport({ url: connection }), - }), - ); - } - return suiClientPerNetwork.get(key)!; -} - -export async function getActiveNetworkSuiClient(): Promise { - return getSuiClient(await networkEnv.getActiveNetwork()); -} diff --git a/apps/wallet/src/shared/utils/bip39.test.ts b/apps/wallet/src/shared/utils/bip39.test.ts index f7a15da68d5..51a1fdcfb7b 100644 --- a/apps/wallet/src/shared/utils/bip39.test.ts +++ b/apps/wallet/src/shared/utils/bip39.test.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { describe, expect, it } from 'vitest'; diff --git a/apps/wallet/src/shared/utils/bip39.ts b/apps/wallet/src/shared/utils/bip39.ts index 0120fbaaa05..8a59af17212 100644 --- a/apps/wallet/src/shared/utils/bip39.ts +++ b/apps/wallet/src/shared/utils/bip39.ts @@ -1,6 +1,4 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 diff --git a/apps/wallet/src/shared/utils/from-exported-keypair.ts b/apps/wallet/src/shared/utils/from-exported-keypair.ts index a0d884d05d4..dbf191a9c49 100644 --- a/apps/wallet/src/shared/utils/from-exported-keypair.ts +++ b/apps/wallet/src/shared/utils/from-exported-keypair.ts @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { type Keypair, type SignatureScheme } from '@mysten/sui.js/cryptography'; +import { type Keypair, type SignatureScheme } from '@iota/iota.js/cryptography'; import { - decodeSuiPrivateKey, + decodeIotaPrivateKey, LEGACY_PRIVATE_KEY_SIZE, PRIVATE_KEY_SIZE, -} from '@mysten/sui.js/cryptography/keypair'; -import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519'; -import { Secp256k1Keypair } from '@mysten/sui.js/keypairs/secp256k1'; -import { Secp256r1Keypair } from '@mysten/sui.js/keypairs/secp256r1'; -import { fromB64 } from '@mysten/sui.js/utils'; +} from '@iota/iota.js/cryptography/keypair'; +import { Ed25519Keypair } from '@iota/iota.js/keypairs/ed25519'; +import { Secp256k1Keypair } from '@iota/iota.js/keypairs/secp256k1'; +import { Secp256r1Keypair } from '@iota/iota.js/keypairs/secp256r1'; +import { fromB64 } from '@iota/iota.js/utils'; /** * Wallet stored data might contain imported accounts with their keys stored in the previous format. @@ -34,7 +35,7 @@ export function fromExportedKeypair( secretKey = fromB64(secret.privateKey); schema = secret.schema; } else { - const decoded = decodeSuiPrivateKey(secret); + const decoded = decodeIotaPrivateKey(secret); schema = decoded.schema; secretKey = decoded.secretKey; } diff --git a/apps/wallet/src/shared/utils/index.ts b/apps/wallet/src/shared/utils/index.ts index 1dd7c8748b5..d44ee2e7dd4 100644 --- a/apps/wallet/src/shared/utils/index.ts +++ b/apps/wallet/src/shared/utils/index.ts @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useAppSelector } from '_hooks'; import { setAttributes } from '_src/shared/experimentation/features'; import { useGrowthBook } from '@growthbook/growthbook-react'; -import { fromB64, toB64 } from '@mysten/sui.js/utils'; +import { fromB64, toB64 } from '@iota/iota.js/utils'; import * as Sentry from '@sentry/browser'; import { useEffect } from 'react'; import Browser from 'webextension-polyfill'; @@ -13,7 +14,7 @@ import { getUrlWithDeviceId } from '../analytics/amplitude'; export const MAIN_UI_URL = Browser.runtime.getURL('ui.html'); -const MYSTEN_LABS_DAPPS = ['suifrens.com', 'suins.io']; +const MYSTEN_LABS_DAPPS = ['iotafrens.com', 'iotans.io']; export function openInNewTab() { return Browser.tabs.create({ url: MAIN_UI_URL }); diff --git a/apps/wallet/src/shared/validation.ts b/apps/wallet/src/shared/validation.ts index 0837835325e..567968c11c4 100644 --- a/apps/wallet/src/shared/validation.ts +++ b/apps/wallet/src/shared/validation.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { formatBalance } from '@mysten/core'; +import { formatBalance } from '@iota/core'; import BigNumber from 'bignumber.js'; import * as Yup from 'yup'; diff --git a/apps/wallet/src/types/assets.d.ts b/apps/wallet/src/types/assets.d.ts index ac1cc3e0d5b..e38ae9b9880 100644 --- a/apps/wallet/src/types/assets.d.ts +++ b/apps/wallet/src/types/assets.d.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 declare module '*.png' { diff --git a/apps/wallet/src/types/css.d.ts b/apps/wallet/src/types/css.d.ts index e63a246217a..712cdfc46d2 100644 --- a/apps/wallet/src/types/css.d.ts +++ b/apps/wallet/src/types/css.d.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 declare module '*.css' { diff --git a/apps/wallet/src/types/node-env.d.ts b/apps/wallet/src/types/node-env.d.ts index 13cb78711de..ebfa3466d6f 100644 --- a/apps/wallet/src/types/node-env.d.ts +++ b/apps/wallet/src/types/node-env.d.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 declare namespace NodeJS { diff --git a/apps/wallet/src/types/scss-modules.d.ts b/apps/wallet/src/types/scss-modules.d.ts index daa8162095a..331f2a6a2cd 100644 --- a/apps/wallet/src/types/scss-modules.d.ts +++ b/apps/wallet/src/types/scss-modules.d.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 declare module '*.module.scss' { diff --git a/apps/wallet/src/types/webextension-polyfill.d.ts b/apps/wallet/src/types/webextension-polyfill.d.ts index 850fa5e6caf..b2493721a62 100644 --- a/apps/wallet/src/types/webextension-polyfill.d.ts +++ b/apps/wallet/src/types/webextension-polyfill.d.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/apps/wallet/src/ui/app/ApiProvider.ts b/apps/wallet/src/ui/app/ApiProvider.ts index cbbc4b9953d..2e5d89f5295 100644 --- a/apps/wallet/src/ui/app/ApiProvider.ts +++ b/apps/wallet/src/ui/app/ApiProvider.ts @@ -1,12 +1,10 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type AccountType, type SerializedUIAccount } from '_src/background/accounts/Account'; -import { getSuiClient } from '_src/shared/sui-client'; -import { getDefaultNetwork, Network, type SuiClient } from '@mysten/sui.js/client'; +import { getIotaClient } from '_src/shared/iota-client'; +import { getDefaultNetwork, Network, type IotaClient } from '@iota/iota.js/client'; import type { BackgroundClient } from './background-client'; import { BackgroundServiceSigner } from './background-client/BackgroundServiceSigner'; @@ -21,7 +19,7 @@ const accountTypesWithBackgroundSigner: AccountType[] = [ ]; export default class ApiProvider { - private _apiFullNodeProvider?: SuiClient; + private _apiFullNodeProvider?: IotaClient; private _signerByAddress: Map = new Map(); network = getDefaultNetwork(); @@ -30,7 +28,7 @@ export default class ApiProvider { customRPC?: string | null, ) { this.network = network; - this._apiFullNodeProvider = getSuiClient( + this._apiFullNodeProvider = getIotaClient( network === Network.Custom ? { network, customRpcUrl: customRPC || '' } : { network, customRpcUrl: null }, diff --git a/apps/wallet/src/ui/app/LedgerSigner.ts b/apps/wallet/src/ui/app/LedgerSigner.ts index ce4448b0257..3a89c6a41f7 100644 --- a/apps/wallet/src/ui/app/LedgerSigner.ts +++ b/apps/wallet/src/ui/app/LedgerSigner.ts @@ -1,58 +1,59 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import type SuiLedgerClient from '@mysten/ledgerjs-hw-app-sui'; -import { type SuiClient } from '@mysten/sui.js/client'; +import type IotaLedgerClient from '@iota/ledgerjs-hw-app-iota'; +import { type IotaClient } from '@iota/iota.js/client'; import { toSerializedSignature, type SerializedSignature, type SignatureScheme, -} from '@mysten/sui.js/cryptography'; -import { Ed25519PublicKey } from '@mysten/sui.js/keypairs/ed25519'; +} from '@iota/iota.js/cryptography'; +import { Ed25519PublicKey } from '@iota/iota.js/keypairs/ed25519'; import { WalletSigner } from './WalletSigner'; export class LedgerSigner extends WalletSigner { - #suiLedgerClient: SuiLedgerClient | null; - readonly #connectToLedger: () => Promise; + #iotaLedgerClient: IotaLedgerClient | null; + readonly #connectToLedger: () => Promise; readonly #derivationPath: string; readonly #signatureScheme: SignatureScheme = 'ED25519'; constructor( - connectToLedger: () => Promise, + connectToLedger: () => Promise, derivationPath: string, - client: SuiClient, + client: IotaClient, ) { super(client); this.#connectToLedger = connectToLedger; - this.#suiLedgerClient = null; + this.#iotaLedgerClient = null; this.#derivationPath = derivationPath; } - async #initializeSuiLedgerClient() { - if (!this.#suiLedgerClient) { + async #initializeIotaLedgerClient() { + if (!this.#iotaLedgerClient) { // We want to make sure that there's only one connection established per Ledger signer // instance since some methods make multiple calls like getAddress and signData - this.#suiLedgerClient = await this.#connectToLedger(); + this.#iotaLedgerClient = await this.#connectToLedger(); } - return this.#suiLedgerClient; + return this.#iotaLedgerClient; } async getAddress(): Promise { - const ledgerClient = await this.#initializeSuiLedgerClient(); + const ledgerClient = await this.#initializeIotaLedgerClient(); const publicKeyResult = await ledgerClient.getPublicKey(this.#derivationPath); const publicKey = new Ed25519PublicKey(publicKeyResult.publicKey); - return publicKey.toSuiAddress(); + return publicKey.toIotaAddress(); } async getPublicKey(): Promise { - const ledgerClient = await this.#initializeSuiLedgerClient(); + const ledgerClient = await this.#initializeIotaLedgerClient(); const { publicKey } = await ledgerClient.getPublicKey(this.#derivationPath); return new Ed25519PublicKey(publicKey); } async signData(data: Uint8Array): Promise { - const ledgerClient = await this.#initializeSuiLedgerClient(); + const ledgerClient = await this.#initializeIotaLedgerClient(); const { signature } = await ledgerClient.signTransaction(this.#derivationPath, data); const publicKey = await this.getPublicKey(); return toSerializedSignature({ @@ -62,7 +63,7 @@ export class LedgerSigner extends WalletSigner { }); } - connect(client: SuiClient) { + connect(client: IotaClient) { return new LedgerSigner(this.#connectToLedger, this.#derivationPath, client); } } diff --git a/apps/wallet/src/ui/app/WalletSigner.ts b/apps/wallet/src/ui/app/WalletSigner.ts index efbb1281f24..b270cfd3f4b 100644 --- a/apps/wallet/src/ui/app/WalletSigner.ts +++ b/apps/wallet/src/ui/app/WalletSigner.ts @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { bcs } from '@mysten/sui.js/bcs'; +import { bcs } from '@iota/iota.js/bcs'; import { type DryRunTransactionBlockResponse, type ExecuteTransactionRequestType, - type SuiClient, - type SuiTransactionBlockResponse, - type SuiTransactionBlockResponseOptions, -} from '@mysten/sui.js/client'; -import { IntentScope, messageWithIntent } from '@mysten/sui.js/cryptography'; -import { isTransactionBlock, type TransactionBlock } from '@mysten/sui.js/transactions'; -import { fromB64, toB64 } from '@mysten/sui.js/utils'; + type IotaClient, + type IotaTransactionBlockResponse, + type IotaTransactionBlockResponseOptions, +} from '@iota/iota.js/client'; +import { IntentScope, messageWithIntent } from '@iota/iota.js/cryptography'; +import { isTransactionBlock, type TransactionBlock } from '@iota/iota.js/transactions'; +import { fromB64, toB64 } from '@iota/iota.js/utils'; export type SignedTransaction = { transactionBlockBytes: string; @@ -24,9 +25,9 @@ export type SignedMessage = { }; export abstract class WalletSigner { - client: SuiClient; + client: IotaClient; - constructor(client: SuiClient) { + constructor(client: IotaClient) { this.client = client; } @@ -93,11 +94,11 @@ export abstract class WalletSigner { async signAndExecuteTransactionBlock( input: { transactionBlock: Uint8Array | TransactionBlock; - options?: SuiTransactionBlockResponseOptions; + options?: IotaTransactionBlockResponseOptions; requestType?: ExecuteTransactionRequestType; }, clientIdentifier?: string, - ): Promise { + ): Promise { const bytes = await this.prepareTransactionBlock(input.transactionBlock); const signed = await this.signTransactionBlock({ transactionBlock: bytes, diff --git a/apps/wallet/src/ui/app/background-client/BackgroundServiceSigner.ts b/apps/wallet/src/ui/app/background-client/BackgroundServiceSigner.ts index 9814d2354ee..cc38616e17c 100644 --- a/apps/wallet/src/ui/app/background-client/BackgroundServiceSigner.ts +++ b/apps/wallet/src/ui/app/background-client/BackgroundServiceSigner.ts @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type SerializedUIAccount } from '_src/background/accounts/Account'; -import { type SuiClient } from '@mysten/sui.js/client'; -import type { SerializedSignature } from '@mysten/sui.js/cryptography'; +import { type IotaClient } from '@iota/iota.js/client'; +import type { SerializedSignature } from '@iota/iota.js/cryptography'; import type { BackgroundClient } from '.'; import { WalletSigner } from '../WalletSigner'; @@ -15,7 +16,7 @@ export class BackgroundServiceSigner extends WalletSigner { constructor( account: SerializedUIAccount, backgroundClient: BackgroundClient, - client: SuiClient, + client: IotaClient, ) { super(client); this.#account = account; @@ -30,7 +31,7 @@ export class BackgroundServiceSigner extends WalletSigner { return this.#backgroundClient.signData(this.#account.id, data); } - connect(client: SuiClient) { + connect(client: IotaClient) { return new BackgroundServiceSigner(this.#account, this.#backgroundClient, client); } } diff --git a/apps/wallet/src/ui/app/background-client/index.ts b/apps/wallet/src/ui/app/background-client/index.ts index 022a9fdd5c4..213f599bc10 100644 --- a/apps/wallet/src/ui/app/background-client/index.ts +++ b/apps/wallet/src/ui/app/background-client/index.ts @@ -1,6 +1,4 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 @@ -30,9 +28,9 @@ import { } from '_src/shared/messaging/messages/payloads/MethodPayload'; import { type SignedMessage, type SignedTransaction } from '_src/ui/app/WalletSigner'; import type { AppDispatch } from '_store'; -import { type SuiTransactionBlockResponse } from '@mysten/sui.js/client'; -import { type SerializedSignature } from '@mysten/sui.js/cryptography'; -import { toB64 } from '@mysten/sui.js/utils'; +import { type IotaTransactionBlockResponse } from '@iota/iota.js/client'; +import { type SerializedSignature } from '@iota/iota.js/cryptography'; +import { toB64 } from '@iota/iota.js/utils'; import { type QueryKey } from '@tanstack/react-query'; import { lastValueFrom, map, take } from 'rxjs'; @@ -96,7 +94,7 @@ export class BackgroundClient { public sendTransactionRequestResponse( txID: string, approved: boolean, - txResult?: SuiTransactionBlockResponse | SignedMessage, + txResult?: IotaTransactionBlockResponse | SignedMessage, txResultError?: string, txSigned?: SignedTransaction, ) { @@ -595,7 +593,7 @@ export class BackgroundClient { } private createPortStream() { - this._portStream = PortStream.connectToBackgroundService('sui_ui<->background'); + this._portStream = PortStream.connectToBackgroundService('iota_ui<->background'); this._portStream.onDisconnect.subscribe(() => { this.createPortStream(); }); diff --git a/apps/wallet/src/ui/app/components/AccountBadge.tsx b/apps/wallet/src/ui/app/components/AccountBadge.tsx index da7d9ee29c7..ce1b7187426 100644 --- a/apps/wallet/src/ui/app/components/AccountBadge.tsx +++ b/apps/wallet/src/ui/app/components/AccountBadge.tsx @@ -1,6 +1,4 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 diff --git a/apps/wallet/src/ui/app/components/AccountListItem.tsx b/apps/wallet/src/ui/app/components/AccountListItem.tsx index 6dd53adf6b7..766305f84cf 100644 --- a/apps/wallet/src/ui/app/components/AccountListItem.tsx +++ b/apps/wallet/src/ui/app/components/AccountListItem.tsx @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type SerializedUIAccount } from '_src/background/accounts/Account'; -import { useResolveSuiNSName } from '@mysten/core'; -import { Check12, Copy12 } from '@mysten/icons'; -import { formatAddress } from '@mysten/sui.js/utils'; +import { useResolveIotaNSName } from '@iota/core'; +import { Check12, Copy12 } from '@iota/icons'; +import { formatAddress } from '@iota/iota.js/utils'; import { useCopyToClipboard } from '../hooks/useCopyToClipboard'; import { Text } from '../shared/text'; @@ -21,12 +22,12 @@ export function AccountListItem({ account, onAccountSelected }: AccountItemProps const copy = useCopyToClipboard(address, { copySuccessMessage: 'Address Copied', }); - const { data: domainName } = useResolveSuiNSName(address); + const { data: domainName } = useResolveIotaNSName(address); return (
  • )} @@ -95,12 +96,12 @@ function App() { setError(null); const txb = getDemoTransaction(accounts[0]?.address || ''); try { - await suiWallet.features[ - 'sui:signAndExecuteTransactionBlock' + await iotaWallet.features[ + 'iota:signAndExecuteTransactionBlock' ].signAndExecuteTransactionBlock({ transactionBlock: txb, account: getAccount(accounts[0], useWrongAccounts), - chain: 'sui:unknown', + chain: 'iota:unknown', }); } catch (e) { setError((e as Error).message); @@ -114,10 +115,10 @@ function App() { setError(null); const txb = getDemoTransaction(accounts[0]?.address || ''); try { - await suiWallet.features['sui:signTransactionBlock'].signTransactionBlock({ + await iotaWallet.features['iota:signTransactionBlock'].signTransactionBlock({ transactionBlock: txb, account: getAccount(accounts[0], useWrongAccounts), - chain: 'sui:unknown', + chain: 'iota:unknown', }); } catch (e) { setError((e as Error).message); @@ -130,7 +131,7 @@ function App() { onClick={async () => { setError(null); try { - await suiWallet.features['sui:signMessage']?.signMessage({ + await iotaWallet.features['iota:signMessage']?.signMessage({ account: getAccount(accounts[0], useWrongAccounts), message: new TextEncoder().encode('Test message'), }); diff --git a/apps/wallet/tests/demo-app/vite.config.ts b/apps/wallet/tests/demo-app/vite.config.ts index 23455736aef..fc1b778f725 100644 --- a/apps/wallet/tests/demo-app/vite.config.ts +++ b/apps/wallet/tests/demo-app/vite.config.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import react from '@vitejs/plugin-react'; @@ -9,7 +10,7 @@ export default defineConfig({ plugins: [react(), tsconfigPaths({ root: '../../' })], resolve: { alias: { - '@mysten/bcs': new URL('../../../../sdk/bcs/src', import.meta.url).pathname, + '@iota/bcs': new URL('../../../../sdk/bcs/src', import.meta.url).pathname, }, }, }); diff --git a/apps/wallet/tests/fixtures.ts b/apps/wallet/tests/fixtures.ts index f2eff7558a4..06898880858 100644 --- a/apps/wallet/tests/fixtures.ts +++ b/apps/wallet/tests/fixtures.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import path from 'path'; diff --git a/apps/wallet/tests/lock.spec.ts b/apps/wallet/tests/lock.spec.ts index e7cc918c6ff..6e63c9f6b6b 100644 --- a/apps/wallet/tests/lock.spec.ts +++ b/apps/wallet/tests/lock.spec.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { expect, test } from './fixtures'; diff --git a/apps/wallet/tests/onboarding.spec.ts b/apps/wallet/tests/onboarding.spec.ts index 121f9f2dd96..b44ba728b6a 100644 --- a/apps/wallet/tests/onboarding.spec.ts +++ b/apps/wallet/tests/onboarding.spec.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { expect, test } from './fixtures'; @@ -16,7 +17,7 @@ test('import wallet', async ({ page, extensionUrl }) => { importWallet(page, extensionUrl, mnemonic); await page.getByRole('navigation').getByRole('link', { name: 'Home' }).click(); await expect( - page.getByText(keypair.getPublicKey().toSuiAddress().slice(0, 6)).first(), + page.getByText(keypair.getPublicKey().toIotaAddress().slice(0, 6)).first(), ).toBeVisible(); }); diff --git a/apps/wallet/tests/sites-to-cs-messaging.spec.ts b/apps/wallet/tests/sites-to-cs-messaging.spec.ts index 94f97deda50..cf77558aa20 100644 --- a/apps/wallet/tests/sites-to-cs-messaging.spec.ts +++ b/apps/wallet/tests/sites-to-cs-messaging.spec.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { type Page } from '@playwright/test'; @@ -12,7 +13,7 @@ function getInAppMessage(page: Page, id: string) { (anId) => new Promise((resolve, reject) => { const callBackFN = (msg: MessageEvent) => { - if (msg.data.target === 'sui_in-page' && msg.data.payload.id === anId) { + if (msg.data.target === 'iota_in-page' && msg.data.payload.id === anId) { window.removeEventListener('message', callBackFN); if (msg.data.payload.payload.error) { reject(msg.data.payload); @@ -81,7 +82,7 @@ test.describe('site to content script messages', () => { await page.evaluate( ({ aPayload: payload, aLabel: label }) => { window.postMessage({ - target: 'sui_content-script', + target: 'iota_content-script', payload: { id: label, payload, diff --git a/apps/wallet/tests/staking.spec.ts b/apps/wallet/tests/staking.spec.ts index a8c1513d4fe..a9d879eaae5 100644 --- a/apps/wallet/tests/staking.spec.ts +++ b/apps/wallet/tests/staking.spec.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { expect, test } from './fixtures'; @@ -13,9 +14,9 @@ test('staking', async ({ page, extensionUrl }) => { await createWallet(page, extensionUrl); await page.getByTestId('faucet-request-button').click(); - await expect(page.getByTestId('coin-balance')).not.toHaveText('0SUI'); + await expect(page.getByTestId('coin-balance')).not.toHaveText('0IOTA'); - await page.getByText(/Stake and Earn SUI/).click(); + await page.getByText(/Stake and Earn IOTA/).click(); await page.getByTestId('validator-list-item').first().click(); await page.getByTestId('select-validator-cta').click(); await page.getByTestId('stake-amount-input').fill(STAKE_AMOUNT.toString()); @@ -28,10 +29,10 @@ test('staking', async ({ page, extensionUrl }) => { await page.getByTestId('close-icon').click(); - await expect(page.getByTestId(`stake-button-${STAKE_AMOUNT}-SUI`)).toBeVisible({ + await expect(page.getByTestId(`stake-button-${STAKE_AMOUNT}-IOTA`)).toBeVisible({ timeout: TEST_TIMEOUT, }); - await page.getByTestId(`stake-button-${STAKE_AMOUNT}-SUI`).click(); + await page.getByTestId(`stake-button-${STAKE_AMOUNT}-IOTA`).click(); await expect(page.getByTestId('stake-card')).toBeVisible({ timeout: 3 * TEST_TIMEOUT }); await page.getByTestId('stake-card').click(); diff --git a/apps/wallet/tests/storage-migration.spec.ts b/apps/wallet/tests/storage-migration.spec.ts index e3ed42b22a6..7a573920ccd 100644 --- a/apps/wallet/tests/storage-migration.spec.ts +++ b/apps/wallet/tests/storage-migration.spec.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { expect, test } from './fixtures'; @@ -26,8 +27,8 @@ test('do storage migration', async ({ page, extensionUrl }) => { }, ], last_account_index: 2, - sui_Env: null, - sui_Env_RPC: null, + iota_Env: null, + iota_Env_RPC: null, v: -1, vault: { data: '{"data":"/y+fvdpw6ps/lJkczX6B5jTC1/LyOGVFjFO06b1wHL6m1HQMk/EnTiFbwiE1MlaTtxN2NdrWouPfnCaMxfEGmg8TPrgreK5d8929JipdITYRNxlZDY7pW6wRB10LQrRkFawXUhg8vnMYeaL/V6G0NKAdsGyW5MyrzYfdADPzUhF3fLw4Gt90MhIdX/QNLRJJAjENY/RuuQHeCi2hC6qEyFXFFot9aBymDVysln9Ti6pfhctcdjdqbfY/PARLz6Uec6df6u+hehkDoBDwhcTysox4la8/WXzPrqs8rbw2d07g/NRZQFXE6Ancd3pE5Hgh7JrDSplCHaswXe1S/rWwismignzwtpDwzEQZT9VSCvfTka0eA+0vI0/lvsNusscgb81GKWuXV49feSBE6CJ7fvQFAji2DybveFj3udYKy3rC4EpdJFwJU+ze2ZO5hlqXcKToPc/x+z/fPXNSfU9rppw0N6T4Fx++IP6q94tvtAz3ZPZGN+ArgjFFYUQhzyuwCtC6TqJ6XdRq3ZlgYb0UNHviThrmpIBCJH/xPeMdeaYD3XFCHetnwTpfkl+xnv8=","iv":"xe674n8dsybLdtK7121KDw==","salt":"f7v0/BRTLtoI+kS3R832pioFR6qtwB6nZgACkco/H5Q="}', diff --git a/apps/wallet/tests/tabs.spec.ts b/apps/wallet/tests/tabs.spec.ts index a22a434fe56..23855879360 100644 --- a/apps/wallet/tests/tabs.spec.ts +++ b/apps/wallet/tests/tabs.spec.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { expect, test } from './fixtures'; @@ -16,7 +17,7 @@ test('Apps tab', async ({ page, extensionUrl }) => { await page.getByRole('navigation').getByRole('link', { name: 'Apps' }).click(); await expect(page.getByRole('main')).toHaveText( - /Apps below are actively curated but do not indicate any endorsement or relationship with Sui Wallet. Please DYOR./i, + /Apps below are actively curated but do not indicate any endorsement or relationship with Iota Wallet. Please DYOR./i, ); }); diff --git a/apps/wallet/tests/utils/auth.ts b/apps/wallet/tests/utils/auth.ts index 132a755b146..70d0f2171df 100644 --- a/apps/wallet/tests/utils/auth.ts +++ b/apps/wallet/tests/utils/auth.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import type { Page } from '@playwright/test'; @@ -14,7 +15,7 @@ export async function createWallet(page: Page, extensionUrl: string) { await page.getByLabel('I read and agreed to the').click(); await page.getByRole('button', { name: /Create Wallet/ }).click(); await page.locator('label', { has: page.locator('input[type=checkbox]') }).click(); - await page.getByRole('link', { name: /Open Sui Wallet/ }).click(); + await page.getByRole('link', { name: /Open Iota Wallet/ }).click(); } export async function importWallet(page: Page, extensionUrl: string, mnemonic: string | string[]) { diff --git a/apps/wallet/tests/utils/dapp-connect.ts b/apps/wallet/tests/utils/dapp-connect.ts index 75309dd7eb2..4d60b746197 100644 --- a/apps/wallet/tests/utils/dapp-connect.ts +++ b/apps/wallet/tests/utils/dapp-connect.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import type { BrowserContext, Page } from '@playwright/test'; diff --git a/apps/wallet/tests/utils/localnet.ts b/apps/wallet/tests/utils/localnet.ts index 6297505535d..c8db4407a1f 100644 --- a/apps/wallet/tests/utils/localnet.ts +++ b/apps/wallet/tests/utils/localnet.ts @@ -1,13 +1,11 @@ // Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import 'tsconfig-paths/register'; -import { requestSuiFromFaucetV0 } from '@mysten/sui.js/faucet'; -import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519'; +import { requestIotaFromFaucetV0 } from '@iota/iota.js/faucet'; +import { Ed25519Keypair } from '@iota/iota.js/keypairs/ed25519'; import * as bip39 from '@scure/bip39'; import { wordlist } from '@scure/bip39/wordlists/english'; @@ -23,6 +21,6 @@ export async function generateKeypair() { const FAUCET_HOST = 'http://127.0.0.1:9123'; -export async function requestSuiFromFaucet(recipient: string) { - await requestSuiFromFaucetV0({ host: FAUCET_HOST, recipient }); +export async function requestIotaFromFaucet(recipient: string) { + await requestIotaFromFaucetV0({ host: FAUCET_HOST, recipient }); } diff --git a/apps/wallet/vitest.config.ts b/apps/wallet/vitest.config.ts index 069a195fe76..024f581f7b3 100644 --- a/apps/wallet/vitest.config.ts +++ b/apps/wallet/vitest.config.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import tsconfigPaths from 'vite-tsconfig-paths'; diff --git a/apps/wallet/webpack.config.ts b/apps/wallet/webpack.config.ts index f2b7ff4ce02..c7221ee324e 100644 --- a/apps/wallet/webpack.config.ts +++ b/apps/wallet/webpack.config.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import type { Configuration } from 'webpack'; diff --git a/bridge/evm/contracts/BridgeCommittee.sol b/bridge/evm/contracts/BridgeCommittee.sol index 6dfe814a6ac..2a60da3e477 100644 --- a/bridge/evm/contracts/BridgeCommittee.sol +++ b/bridge/evm/contracts/BridgeCommittee.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; @@ -6,7 +9,7 @@ import "./interfaces/IBridgeCommittee.sol"; import "./utils/CommitteeUpgradeable.sol"; /// @title BridgeCommittee -/// @notice This contract manages the committee members of the SuiBridge. The committee members are +/// @notice This contract manages the committee members of the IotaBridge. The committee members are /// responsible for signing messages used to update various bridge state including the committee itself. /// The contract also provides functions to manage a blocklist of committee members whose signatures are invalid /// once they are blocklisted. diff --git a/bridge/evm/contracts/BridgeLimiter.sol b/bridge/evm/contracts/BridgeLimiter.sol index 3f1089b2b49..a9f98a69ff2 100644 --- a/bridge/evm/contracts/BridgeLimiter.sol +++ b/bridge/evm/contracts/BridgeLimiter.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; @@ -12,7 +15,7 @@ import "./utils/CommitteeUpgradeable.sol"; /// a rolling 24-hour window. This is accomplished by storing the amount bridged from a given chain in USD /// within a given hourly timestamp. It also provides functions to update the token prices and the total /// limit of the given chainID measured in USD with a 4 decimal precision. -/// The contract is intended to be used and owned by the SuiBridge contract. +/// The contract is intended to be used and owned by the IotaBridge contract. contract BridgeLimiter is IBridgeLimiter, CommitteeUpgradeable, OwnableUpgradeable { /* ========== STATE VARIABLES ========== */ @@ -130,7 +133,7 @@ contract BridgeLimiter is IBridgeLimiter, CommitteeUpgradeable, OwnableUpgradeab /* ========== EXTERNAL FUNCTIONS ========== */ /// @notice Updates the bridge transfers for a specific token ID and amount. Only the contract - /// owner can call this function (intended to be the SuiBridge contract). + /// owner can call this function (intended to be the IotaBridge contract). /// @dev The amount must be greater than 0 and must not exceed the rolling window limit. /// @param chainID The ID of the chain to record the transfer for. /// @param tokenID The ID of the token. diff --git a/bridge/evm/contracts/BridgeVault.sol b/bridge/evm/contracts/BridgeVault.sol index 0eae772b539..9b42feccbd6 100644 --- a/bridge/evm/contracts/BridgeVault.sol +++ b/bridge/evm/contracts/BridgeVault.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts/access/Ownable.sol"; @@ -8,10 +11,10 @@ import "./interfaces/IWETH9.sol"; /// @title BridgeVault /// @notice A contract that acts as a vault for transferring ERC20 tokens and ETH. It enables the owner -/// (intended to be the SuiBridge contract) to transfer tokens to a target address. It also supports +/// (intended to be the IotaBridge contract) to transfer tokens to a target address. It also supports /// unwrapping WETH (Wrapped Ether) and transferring the unwrapped ETH. /// @dev The contract is initialized with the deployer as the owner. The ownership is intended to be -/// transferred to the SuiBridge contract after the bridge contract is deployed. +/// transferred to the IotaBridge contract after the bridge contract is deployed. contract BridgeVault is Ownable, IBridgeVault { /* ========== STATE VARIABLES ========== */ @@ -28,7 +31,7 @@ contract BridgeVault is Ownable, IBridgeVault { /// @notice Transfers ERC20 tokens from the contract to a target address. Only the owner of /// the contract can call this function. - /// @dev This function is intended to only be called by the SuiBridge contract. + /// @dev This function is intended to only be called by the IotaBridge contract. /// @param tokenAddress The address of the ERC20 token. /// @param recipientAddress The address to transfer the tokens to. /// @param amount The amount of tokens to transfer. @@ -49,7 +52,7 @@ contract BridgeVault is Ownable, IBridgeVault { /// @notice Unwraps stored wrapped ETH and transfers the newly withdrawn ETH to the provided target /// address. Only the owner of the contract can call this function. - /// @dev This function is intended to only be called by the SuiBridge contract. + /// @dev This function is intended to only be called by the IotaBridge contract. /// @param recipientAddress The address to transfer the ETH to. /// @param amount The amount of ETH to transfer. function transferETH(address payable recipientAddress, uint256 amount) diff --git a/bridge/evm/contracts/IotaBridge.sol b/bridge/evm/contracts/IotaBridge.sol new file mode 100644 index 00000000000..2abc697559d --- /dev/null +++ b/bridge/evm/contracts/IotaBridge.sol @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./utils/CommitteeUpgradeable.sol"; +import "./interfaces/IIotaBridge.sol"; +import "./interfaces/IBridgeVault.sol"; +import "./interfaces/IBridgeLimiter.sol"; +import "./interfaces/IBridgeConfig.sol"; +import "./interfaces/IWETH9.sol"; + +/// @title IotaBridge +/// @notice This contract implements a token bridge that enables users to deposit and withdraw +/// supported tokens to and from other chains. The bridge supports the transfer of Ethereum and ERC20 +/// tokens. Bridge operations are managed by a committee of Iota validators that are responsible +/// for verifying and processing bridge messages. The bridge is designed to be upgradeable and +/// can be paused in case of an emergency. The bridge also enforces limits on the amount of +/// assets that can be withdrawn to prevent abuse. +contract IotaBridge is IIotaBridge, CommitteeUpgradeable, PausableUpgradeable { + /* ========== STATE VARIABLES ========== */ + + mapping(uint64 nonce => bool isProcessed) public isTransferProcessed; + IBridgeVault public vault; + IBridgeLimiter public limiter; + IWETH9 public wETH; + + /* ========== INITIALIZER ========== */ + + /// @notice Initializes the IotaBridge contract with the provided parameters. + /// @dev this function should be called directly after deployment (see OpenZeppelin upgradeable standards). + /// @param _committee The address of the committee contract. + /// @param _vault The address of the bridge vault contract. + /// @param _limiter The address of the bridge limiter contract. + /// @param _wETH The address of the WETH9 contract. + function initialize(address _committee, address _vault, address _limiter, address _wETH) + external + initializer + { + __CommitteeUpgradeable_init(_committee); + __Pausable_init(); + vault = IBridgeVault(_vault); + limiter = IBridgeLimiter(_limiter); + wETH = IWETH9(_wETH); + } + + /* ========== EXTERNAL FUNCTIONS ========== */ + + /// @notice Allows the caller to provide signatures that enable the transfer of tokens to + /// the recipient address indicated within the message payload. + /// @dev `message.chainID` represents the sending chain ID. Receiving chain ID needs to match + /// this bridge's chain ID (this chain). + /// @param signatures The array of signatures. + /// @param message The BridgeMessage containing the transfer details. + function transferBridgedTokensWithSignatures( + bytes[] memory signatures, + BridgeMessage.Message memory message + ) + external + nonReentrant + verifyMessageAndSignatures(message, signatures, BridgeMessage.TOKEN_TRANSFER) + onlySupportedChain(message.chainID) + { + // verify that message has not been processed + require(!isTransferProcessed[message.nonce], "IotaBridge: Message already processed"); + + BridgeMessage.TokenTransferPayload memory tokenTransferPayload = + BridgeMessage.decodeTokenTransferPayload(message.payload); + + // verify target chain ID is this chain ID + require( + tokenTransferPayload.targetChain == committee.config().chainID(), + "IotaBridge: Invalid target chain" + ); + + // convert amount to ERC20 token decimals + uint256 erc20AdjustedAmount = committee.config().convertIotaToERC20Decimal( + tokenTransferPayload.tokenID, tokenTransferPayload.amount + ); + + _transferTokensFromVault( + message.chainID, + tokenTransferPayload.tokenID, + tokenTransferPayload.recipientAddress, + erc20AdjustedAmount + ); + + // mark message as processed + isTransferProcessed[message.nonce] = true; + + emit TokensClaimed( + message.chainID, + message.nonce, + committee.config().chainID(), + tokenTransferPayload.tokenID, + erc20AdjustedAmount, + tokenTransferPayload.senderAddress, + tokenTransferPayload.recipientAddress + ); + } + + /// @notice Executes an emergency operation with the provided signatures and message. + /// @dev If the given operation is to freeze and the bridge is already frozen, the operation + /// will revert. + /// @param signatures The array of signatures to verify. + /// @param message The BridgeMessage containing the details of the operation. + function executeEmergencyOpWithSignatures( + bytes[] memory signatures, + BridgeMessage.Message memory message + ) + external + nonReentrant + verifyMessageAndSignatures(message, signatures, BridgeMessage.EMERGENCY_OP) + { + // decode the emergency op message + bool isFreezing = BridgeMessage.decodeEmergencyOpPayload(message.payload); + + if (isFreezing) _pause(); + else _unpause(); + // pausing event emitted in 'PausableUpgradeable.sol' + } + + /// @notice Enables the caller to deposit supported tokens to be bridged to a given + /// destination chain. + /// @dev The provided tokenID and destinationChainID must be supported. The caller must + /// have approved this contract to transfer the given token. + /// @param tokenID The ID of the token to be bridged. + /// @param amount The amount of tokens to be bridged. + /// @param recipientAddress The address on the Iota chain where the tokens will be sent. + /// @param destinationChainID The ID of the destination chain. + function bridgeERC20( + uint8 tokenID, + uint256 amount, + bytes memory recipientAddress, + uint8 destinationChainID + ) external whenNotPaused nonReentrant onlySupportedChain(destinationChainID) { + require(committee.config().isTokenSupported(tokenID), "IotaBridge: Unsupported token"); + + address tokenAddress = committee.config().getTokenAddress(tokenID); + + // check that the bridge contract has allowance to transfer the tokens + require( + IERC20(tokenAddress).allowance(msg.sender, address(this)) >= amount, + "IotaBridge: Insufficient allowance" + ); + + // Transfer the tokens from the contract to the vault + IERC20(tokenAddress).transferFrom(msg.sender, address(vault), amount); + + // Adjust the amount to emit. + uint64 iotaAdjustedAmount = committee.config().convertERC20ToIotaDecimal(tokenID, amount); + + emit TokensDeposited( + committee.config().chainID(), + nonces[BridgeMessage.TOKEN_TRANSFER], + destinationChainID, + tokenID, + iotaAdjustedAmount, + msg.sender, + recipientAddress + ); + + // increment token transfer nonce + nonces[BridgeMessage.TOKEN_TRANSFER]++; + } + + /// @notice Enables the caller to deposit Eth to be bridged to a given destination chain. + /// @dev The provided destinationChainID must be supported. + /// @param recipientAddress The address on the destination chain where Eth will be sent. + /// @param destinationChainID The ID of the destination chain. + function bridgeETH(bytes memory recipientAddress, uint8 destinationChainID) + external + payable + whenNotPaused + nonReentrant + onlySupportedChain(destinationChainID) + { + uint256 amount = msg.value; + + // Wrap ETH + wETH.deposit{value: amount}(); + + // Transfer the wrapped ETH back to caller + wETH.transfer(address(vault), amount); + + // Adjust the amount to emit. + uint64 iotaAdjustedAmount = + committee.config().convertERC20ToIotaDecimal(BridgeMessage.ETH, amount); + + emit TokensDeposited( + committee.config().chainID(), + nonces[BridgeMessage.TOKEN_TRANSFER], + destinationChainID, + BridgeMessage.ETH, + iotaAdjustedAmount, + msg.sender, + recipientAddress + ); + + // increment token transfer nonce + nonces[BridgeMessage.TOKEN_TRANSFER]++; + } + + /* ========== INTERNAL FUNCTIONS ========== */ + + /// @dev Transfers tokens from the vault to a target address. + /// @param sendingChainID The ID of the chain from which the tokens are being transferred. + /// @param tokenID The ID of the token being transferred. + /// @param recipientAddress The address to which the tokens are being transferred. + /// @param amount The amount of tokens being transferred. + function _transferTokensFromVault( + uint8 sendingChainID, + uint8 tokenID, + address recipientAddress, + uint256 amount + ) private whenNotPaused limitNotExceeded(sendingChainID, tokenID, amount) { + address tokenAddress = committee.config().getTokenAddress(tokenID); + + // Check that the token address is supported + require(tokenAddress != address(0), "IotaBridge: Unsupported token"); + + // transfer eth if token type is eth + if (tokenID == BridgeMessage.ETH) { + vault.transferETH(payable(recipientAddress), amount); + } else { + // transfer tokens from vault to target address + vault.transferERC20(tokenAddress, recipientAddress, amount); + } + + // update amount bridged + limiter.recordBridgeTransfers(sendingChainID, tokenID, amount); + } + + /* ========== MODIFIERS ========== */ + + /// @dev Requires the amount being transferred does not exceed the bridge limit in + /// the last 24 hours. + /// @param tokenID The ID of the token being transferred. + /// @param amount The amount of tokens being transferred. + modifier limitNotExceeded(uint8 chainID, uint8 tokenID, uint256 amount) { + require( + !limiter.willAmountExceedLimit(chainID, tokenID, amount), + "IotaBridge: Amount exceeds bridge limit" + ); + _; + } + + /// @dev Requires the target chain ID is supported. + /// @param targetChainID The ID of the target chain. + modifier onlySupportedChain(uint8 targetChainID) { + require( + committee.config().isChainSupported(targetChainID), + "IotaBridge: Target chain not supported" + ); + _; + } +} diff --git a/bridge/evm/contracts/SuiBridge.sol b/bridge/evm/contracts/SuiBridge.sol deleted file mode 100644 index e9fac67fae0..00000000000 --- a/bridge/evm/contracts/SuiBridge.sol +++ /dev/null @@ -1,257 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "./utils/CommitteeUpgradeable.sol"; -import "./interfaces/ISuiBridge.sol"; -import "./interfaces/IBridgeVault.sol"; -import "./interfaces/IBridgeLimiter.sol"; -import "./interfaces/IBridgeConfig.sol"; -import "./interfaces/IWETH9.sol"; - -/// @title SuiBridge -/// @notice This contract implements a token bridge that enables users to deposit and withdraw -/// supported tokens to and from other chains. The bridge supports the transfer of Ethereum and ERC20 -/// tokens. Bridge operations are managed by a committee of Sui validators that are responsible -/// for verifying and processing bridge messages. The bridge is designed to be upgradeable and -/// can be paused in case of an emergency. The bridge also enforces limits on the amount of -/// assets that can be withdrawn to prevent abuse. -contract SuiBridge is ISuiBridge, CommitteeUpgradeable, PausableUpgradeable { - /* ========== STATE VARIABLES ========== */ - - mapping(uint64 nonce => bool isProcessed) public isTransferProcessed; - IBridgeVault public vault; - IBridgeLimiter public limiter; - IWETH9 public wETH; - - /* ========== INITIALIZER ========== */ - - /// @notice Initializes the SuiBridge contract with the provided parameters. - /// @dev this function should be called directly after deployment (see OpenZeppelin upgradeable standards). - /// @param _committee The address of the committee contract. - /// @param _vault The address of the bridge vault contract. - /// @param _limiter The address of the bridge limiter contract. - /// @param _wETH The address of the WETH9 contract. - function initialize(address _committee, address _vault, address _limiter, address _wETH) - external - initializer - { - __CommitteeUpgradeable_init(_committee); - __Pausable_init(); - vault = IBridgeVault(_vault); - limiter = IBridgeLimiter(_limiter); - wETH = IWETH9(_wETH); - } - - /* ========== EXTERNAL FUNCTIONS ========== */ - - /// @notice Allows the caller to provide signatures that enable the transfer of tokens to - /// the recipient address indicated within the message payload. - /// @dev `message.chainID` represents the sending chain ID. Receiving chain ID needs to match - /// this bridge's chain ID (this chain). - /// @param signatures The array of signatures. - /// @param message The BridgeMessage containing the transfer details. - function transferBridgedTokensWithSignatures( - bytes[] memory signatures, - BridgeMessage.Message memory message - ) - external - nonReentrant - verifyMessageAndSignatures(message, signatures, BridgeMessage.TOKEN_TRANSFER) - onlySupportedChain(message.chainID) - { - // verify that message has not been processed - require(!isTransferProcessed[message.nonce], "SuiBridge: Message already processed"); - - BridgeMessage.TokenTransferPayload memory tokenTransferPayload = - BridgeMessage.decodeTokenTransferPayload(message.payload); - - // verify target chain ID is this chain ID - require( - tokenTransferPayload.targetChain == committee.config().chainID(), - "SuiBridge: Invalid target chain" - ); - - // convert amount to ERC20 token decimals - uint256 erc20AdjustedAmount = committee.config().convertSuiToERC20Decimal( - tokenTransferPayload.tokenID, tokenTransferPayload.amount - ); - - _transferTokensFromVault( - message.chainID, - tokenTransferPayload.tokenID, - tokenTransferPayload.recipientAddress, - erc20AdjustedAmount - ); - - // mark message as processed - isTransferProcessed[message.nonce] = true; - - emit TokensClaimed( - message.chainID, - message.nonce, - committee.config().chainID(), - tokenTransferPayload.tokenID, - erc20AdjustedAmount, - tokenTransferPayload.senderAddress, - tokenTransferPayload.recipientAddress - ); - } - - /// @notice Executes an emergency operation with the provided signatures and message. - /// @dev If the given operation is to freeze and the bridge is already frozen, the operation - /// will revert. - /// @param signatures The array of signatures to verify. - /// @param message The BridgeMessage containing the details of the operation. - function executeEmergencyOpWithSignatures( - bytes[] memory signatures, - BridgeMessage.Message memory message - ) - external - nonReentrant - verifyMessageAndSignatures(message, signatures, BridgeMessage.EMERGENCY_OP) - { - // decode the emergency op message - bool isFreezing = BridgeMessage.decodeEmergencyOpPayload(message.payload); - - if (isFreezing) _pause(); - else _unpause(); - // pausing event emitted in 'PausableUpgradeable.sol' - } - - /// @notice Enables the caller to deposit supported tokens to be bridged to a given - /// destination chain. - /// @dev The provided tokenID and destinationChainID must be supported. The caller must - /// have approved this contract to transfer the given token. - /// @param tokenID The ID of the token to be bridged. - /// @param amount The amount of tokens to be bridged. - /// @param recipientAddress The address on the Sui chain where the tokens will be sent. - /// @param destinationChainID The ID of the destination chain. - function bridgeERC20( - uint8 tokenID, - uint256 amount, - bytes memory recipientAddress, - uint8 destinationChainID - ) external whenNotPaused nonReentrant onlySupportedChain(destinationChainID) { - require(committee.config().isTokenSupported(tokenID), "SuiBridge: Unsupported token"); - - address tokenAddress = committee.config().getTokenAddress(tokenID); - - // check that the bridge contract has allowance to transfer the tokens - require( - IERC20(tokenAddress).allowance(msg.sender, address(this)) >= amount, - "SuiBridge: Insufficient allowance" - ); - - // Transfer the tokens from the contract to the vault - IERC20(tokenAddress).transferFrom(msg.sender, address(vault), amount); - - // Adjust the amount to emit. - uint64 suiAdjustedAmount = committee.config().convertERC20ToSuiDecimal(tokenID, amount); - - emit TokensDeposited( - committee.config().chainID(), - nonces[BridgeMessage.TOKEN_TRANSFER], - destinationChainID, - tokenID, - suiAdjustedAmount, - msg.sender, - recipientAddress - ); - - // increment token transfer nonce - nonces[BridgeMessage.TOKEN_TRANSFER]++; - } - - /// @notice Enables the caller to deposit Eth to be bridged to a given destination chain. - /// @dev The provided destinationChainID must be supported. - /// @param recipientAddress The address on the destination chain where Eth will be sent. - /// @param destinationChainID The ID of the destination chain. - function bridgeETH(bytes memory recipientAddress, uint8 destinationChainID) - external - payable - whenNotPaused - nonReentrant - onlySupportedChain(destinationChainID) - { - uint256 amount = msg.value; - - // Wrap ETH - wETH.deposit{value: amount}(); - - // Transfer the wrapped ETH back to caller - wETH.transfer(address(vault), amount); - - // Adjust the amount to emit. - uint64 suiAdjustedAmount = - committee.config().convertERC20ToSuiDecimal(BridgeMessage.ETH, amount); - - emit TokensDeposited( - committee.config().chainID(), - nonces[BridgeMessage.TOKEN_TRANSFER], - destinationChainID, - BridgeMessage.ETH, - suiAdjustedAmount, - msg.sender, - recipientAddress - ); - - // increment token transfer nonce - nonces[BridgeMessage.TOKEN_TRANSFER]++; - } - - /* ========== INTERNAL FUNCTIONS ========== */ - - /// @dev Transfers tokens from the vault to a target address. - /// @param sendingChainID The ID of the chain from which the tokens are being transferred. - /// @param tokenID The ID of the token being transferred. - /// @param recipientAddress The address to which the tokens are being transferred. - /// @param amount The amount of tokens being transferred. - function _transferTokensFromVault( - uint8 sendingChainID, - uint8 tokenID, - address recipientAddress, - uint256 amount - ) private whenNotPaused limitNotExceeded(sendingChainID, tokenID, amount) { - address tokenAddress = committee.config().getTokenAddress(tokenID); - - // Check that the token address is supported - require(tokenAddress != address(0), "SuiBridge: Unsupported token"); - - // transfer eth if token type is eth - if (tokenID == BridgeMessage.ETH) { - vault.transferETH(payable(recipientAddress), amount); - } else { - // transfer tokens from vault to target address - vault.transferERC20(tokenAddress, recipientAddress, amount); - } - - // update amount bridged - limiter.recordBridgeTransfers(sendingChainID, tokenID, amount); - } - - /* ========== MODIFIERS ========== */ - - /// @dev Requires the amount being transferred does not exceed the bridge limit in - /// the last 24 hours. - /// @param tokenID The ID of the token being transferred. - /// @param amount The amount of tokens being transferred. - modifier limitNotExceeded(uint8 chainID, uint8 tokenID, uint256 amount) { - require( - !limiter.willAmountExceedLimit(chainID, tokenID, amount), - "SuiBridge: Amount exceeds bridge limit" - ); - _; - } - - /// @dev Requires the target chain ID is supported. - /// @param targetChainID The ID of the target chain. - modifier onlySupportedChain(uint8 targetChainID) { - require( - committee.config().isChainSupported(targetChainID), - "SuiBridge: Target chain not supported" - ); - _; - } -} diff --git a/bridge/evm/contracts/interfaces/IBridgeCommittee.sol b/bridge/evm/contracts/interfaces/IBridgeCommittee.sol index 7ece51ab6f8..b43a17dcea1 100644 --- a/bridge/evm/contracts/interfaces/IBridgeCommittee.sol +++ b/bridge/evm/contracts/interfaces/IBridgeCommittee.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "../utils/BridgeMessage.sol"; diff --git a/bridge/evm/contracts/interfaces/IBridgeConfig.sol b/bridge/evm/contracts/interfaces/IBridgeConfig.sol index 290c29ade07..0de22e2b21f 100644 --- a/bridge/evm/contracts/interfaces/IBridgeConfig.sol +++ b/bridge/evm/contracts/interfaces/IBridgeConfig.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; /// @title IBridgeConfig @@ -9,7 +12,7 @@ interface IBridgeConfig { /// @notice The data struct for the supported bridge tokens. struct Token { address tokenAddress; - uint8 suiDecimal; + uint8 iotaDecimal; } /* ========== VIEW FUNCTIONS ========== */ @@ -19,25 +22,25 @@ interface IBridgeConfig { /// @return address of the provided token. function getTokenAddress(uint8 tokenID) external view returns (address); - /// @notice Returns the sui decimal places of the token with the given ID. + /// @notice Returns the iota decimal places of the token with the given ID. /// @param tokenID The ID of the token. - /// @return amount of sui decimal places of the provided token. - function getSuiDecimal(uint8 tokenID) external view returns (uint8); + /// @return amount of iota decimal places of the provided token. + function getIotaDecimal(uint8 tokenID) external view returns (uint8); - /// @notice Converts the provided token amount to the Sui decimal adjusted amount. + /// @notice Converts the provided token amount to the Iota decimal adjusted amount. /// @param tokenID The ID of the token to convert. - /// @param amount The ERC20 amount of the tokens to convert to Sui. - /// @return Sui converted amount. - function convertERC20ToSuiDecimal(uint8 tokenID, uint256 amount) + /// @param amount The ERC20 amount of the tokens to convert to Iota. + /// @return Iota converted amount. + function convertERC20ToIotaDecimal(uint8 tokenID, uint256 amount) external view returns (uint64); /// @notice Converts the provided token amount to the ERC20 decimal adjusted amount. /// @param tokenID The ID of the token to convert. - /// @param amount The Sui amount of the tokens to convert to ERC20 amount. + /// @param amount The Iota amount of the tokens to convert to ERC20 amount. /// @return ERC20 converted amount. - function convertSuiToERC20Decimal(uint8 tokenID, uint64 amount) + function convertIotaToERC20Decimal(uint8 tokenID, uint64 amount) external view returns (uint256); @@ -47,7 +50,7 @@ interface IBridgeConfig { /// @return true if the token is supported, false otherwise. function isTokenSupported(uint8 tokenID) external view returns (bool); - /// @notice Returns whether a chain is supported in SuiBridge with the given ID. + /// @notice Returns whether a chain is supported in IotaBridge with the given ID. /// @param chainId The ID of the chain. /// @return true if the chain is supported, false otherwise. function isChainSupported(uint8 chainId) external view returns (bool); diff --git a/bridge/evm/contracts/interfaces/IBridgeLimiter.sol b/bridge/evm/contracts/interfaces/IBridgeLimiter.sol index b9b2fc98906..3546ef191ed 100644 --- a/bridge/evm/contracts/interfaces/IBridgeLimiter.sol +++ b/bridge/evm/contracts/interfaces/IBridgeLimiter.sol @@ -1,11 +1,14 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; /// @title IBridgeLimiter /// @notice Interface for the BridgeLimiter contract. interface IBridgeLimiter { /// @notice Updates the bridge transfers for a specific token ID and amount. Only the contract - /// owner can call this function (intended to be the SuiBridge contract). + /// owner can call this function (intended to be the IotaBridge contract). /// @dev The amount must be greater than 0 and must not exceed the rolling window limit. /// @param chainID The ID of the chain to record the transfer for. /// @param tokenID The ID of the token. diff --git a/bridge/evm/contracts/interfaces/IBridgeVault.sol b/bridge/evm/contracts/interfaces/IBridgeVault.sol index e16c04c8d8b..3bdf2549d4b 100644 --- a/bridge/evm/contracts/interfaces/IBridgeVault.sol +++ b/bridge/evm/contracts/interfaces/IBridgeVault.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; /// @title IBridgeVault diff --git a/bridge/evm/contracts/interfaces/IIotaBridge.sol b/bridge/evm/contracts/interfaces/IIotaBridge.sol new file mode 100644 index 00000000000..2503e3a87c8 --- /dev/null +++ b/bridge/evm/contracts/interfaces/IIotaBridge.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +/// @title IIotaBridge +/// @dev Interface for the Iota Bridge contract. +interface IIotaBridge { + /// @notice Emitted when tokens are deposited to be bridged. + /// @param sourceChainID The ID of the source chain (this chain). + /// @param nonce The nonce of the transaction on source chain. + /// @param destinationChainID The ID of the destination chain. + /// @param tokenID The code of the token. + /// @param iotaAdjustedAmount The amount of tokens to transfer, adjusted for Iota decimals. + /// @param senderAddress The address of the sender. + /// @param recipientAddress The address of the sender. + event TokensDeposited( + uint8 indexed sourceChainID, + uint64 indexed nonce, + uint8 indexed destinationChainID, + uint8 tokenID, + uint64 iotaAdjustedAmount, + address senderAddress, + bytes recipientAddress + ); + + /// @notice Emitted when bridged tokens are transferred to the recipient address. + /// @param sourceChainID The ID of the source chain. + /// @param nonce The nonce of the transaction on source chain. + /// @param destinationChainID The ID of the destination chain (this chain). + /// @param tokenID The code of the token. + /// @param erc20AdjustedAmount The amount of tokens claimed, adjusted for ERC20 decimals. + /// @param senderAddress The address of the sender. + /// @param recipientAddress The address of the sender. + // event BridgedTokensTransferred( + event TokensClaimed( + uint8 indexed sourceChainID, + uint64 indexed nonce, + uint8 indexed destinationChainID, + uint8 tokenID, + uint256 erc20AdjustedAmount, + bytes senderAddress, + address recipientAddress + ); +} diff --git a/bridge/evm/contracts/interfaces/ISuiBridge.sol b/bridge/evm/contracts/interfaces/ISuiBridge.sol deleted file mode 100644 index 7d70d427a97..00000000000 --- a/bridge/evm/contracts/interfaces/ISuiBridge.sol +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -/// @title ISuiBridge -/// @dev Interface for the Sui Bridge contract. -interface ISuiBridge { - /// @notice Emitted when tokens are deposited to be bridged. - /// @param sourceChainID The ID of the source chain (this chain). - /// @param nonce The nonce of the transaction on source chain. - /// @param destinationChainID The ID of the destination chain. - /// @param tokenID The code of the token. - /// @param suiAdjustedAmount The amount of tokens to transfer, adjusted for Sui decimals. - /// @param senderAddress The address of the sender. - /// @param recipientAddress The address of the sender. - event TokensDeposited( - uint8 indexed sourceChainID, - uint64 indexed nonce, - uint8 indexed destinationChainID, - uint8 tokenID, - uint64 suiAdjustedAmount, - address senderAddress, - bytes recipientAddress - ); - - /// @notice Emitted when bridged tokens are transferred to the recipient address. - /// @param sourceChainID The ID of the source chain. - /// @param nonce The nonce of the transaction on source chain. - /// @param destinationChainID The ID of the destination chain (this chain). - /// @param tokenID The code of the token. - /// @param erc20AdjustedAmount The amount of tokens claimed, adjusted for ERC20 decimals. - /// @param senderAddress The address of the sender. - /// @param recipientAddress The address of the sender. - // event BridgedTokensTransferred( - event TokensClaimed( - uint8 indexed sourceChainID, - uint64 indexed nonce, - uint8 indexed destinationChainID, - uint8 tokenID, - uint256 erc20AdjustedAmount, - bytes senderAddress, - address recipientAddress - ); -} diff --git a/bridge/evm/contracts/interfaces/IWETH9.sol b/bridge/evm/contracts/interfaces/IWETH9.sol index e6dc5b2a720..1c4364d6277 100644 --- a/bridge/evm/contracts/interfaces/IWETH9.sol +++ b/bridge/evm/contracts/interfaces/IWETH9.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/bridge/evm/contracts/utils/BridgeConfig.sol b/bridge/evm/contracts/utils/BridgeConfig.sol index 4d071be33a3..a8f0349e9dc 100644 --- a/bridge/evm/contracts/utils/BridgeConfig.sol +++ b/bridge/evm/contracts/utils/BridgeConfig.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; @@ -6,8 +9,8 @@ import "@openzeppelin/contracts/access/Ownable.sol"; import "../interfaces/IBridgeConfig.sol"; /// @title BridgeConfig -/// @notice This contract manages a registry of supported tokens and supported chain IDs for the SuiBridge. -/// It also provides functions to convert token amounts to Sui decimal adjusted amounts and vice versa. +/// @notice This contract manages a registry of supported tokens and supported chain IDs for the IotaBridge. +/// It also provides functions to convert token amounts to Iota decimal adjusted amounts and vice versa. contract BridgeConfig is IBridgeConfig { /* ========== STATE VARIABLES ========== */ @@ -27,18 +30,18 @@ contract BridgeConfig is IBridgeConfig { ) { require(_supportedTokens.length == 4, "BridgeConfig: Invalid supported token addresses"); - uint8[] memory _suiDecimals = new uint8[](5); - _suiDecimals[0] = 9; // SUI - _suiDecimals[1] = 8; // wBTC - _suiDecimals[2] = 8; // wETH - _suiDecimals[3] = 6; // USDC - _suiDecimals[4] = 6; // USDT + uint8[] memory _iotaDecimals = new uint8[](5); + _iotaDecimals[0] = 9; // IOTA + _iotaDecimals[1] = 8; // wBTC + _iotaDecimals[2] = 8; // wETH + _iotaDecimals[3] = 6; // USDC + _iotaDecimals[4] = 6; // USDT - // Add SUI as the first supported token - supportedTokens[0] = Token(address(0), _suiDecimals[0]); + // Add IOTA as the first supported token + supportedTokens[0] = Token(address(0), _iotaDecimals[0]); for (uint8 i; i < _supportedTokens.length; i++) { - supportedTokens[i + 1] = Token(_supportedTokens[i], _suiDecimals[i + 1]); + supportedTokens[i + 1] = Token(_supportedTokens[i], _iotaDecimals[i + 1]); } for (uint8 i; i < _supportedChains.length; i++) { @@ -58,50 +61,50 @@ contract BridgeConfig is IBridgeConfig { return supportedTokens[tokenID].tokenAddress; } - /// @notice Returns the sui decimal places of the token with the given ID. + /// @notice Returns the iota decimal places of the token with the given ID. /// @param tokenID The ID of the token. - /// @return amount of sui decimal places of the provided token. - function getSuiDecimal(uint8 tokenID) public view override returns (uint8) { - return supportedTokens[tokenID].suiDecimal; + /// @return amount of iota decimal places of the provided token. + function getIotaDecimal(uint8 tokenID) public view override returns (uint8) { + return supportedTokens[tokenID].iotaDecimal; } - /// @notice Returns whether a token is supported in SuiBridge with the given ID. + /// @notice Returns whether a token is supported in IotaBridge with the given ID. /// @param tokenID The ID of the token. /// @return true if the token is supported, false otherwise. function isTokenSupported(uint8 tokenID) public view override returns (bool) { return supportedTokens[tokenID].tokenAddress != address(0); } - /// @notice Returns whether a chain is supported in SuiBridge with the given ID. + /// @notice Returns whether a chain is supported in IotaBridge with the given ID. /// @param chainId The ID of the chain. /// @return true if the chain is supported, false otherwise. function isChainSupported(uint8 chainId) public view override returns (bool) { return supportedChains[chainId]; } - /// @notice Converts the provided token amount to the Sui decimal adjusted amount. + /// @notice Converts the provided token amount to the Iota decimal adjusted amount. /// @param tokenID The ID of the token to convert. - /// @param amount The ERC20 amount of the tokens to convert to Sui. - /// @return Sui converted amount. - function convertERC20ToSuiDecimal(uint8 tokenID, uint256 amount) + /// @param amount The ERC20 amount of the tokens to convert to Iota. + /// @return Iota converted amount. + function convertERC20ToIotaDecimal(uint8 tokenID, uint256 amount) public view override returns (uint64) { uint8 ethDecimal = IERC20Metadata(getTokenAddress(tokenID)).decimals(); - uint8 suiDecimal = getSuiDecimal(tokenID); + uint8 iotaDecimal = getIotaDecimal(tokenID); - if (ethDecimal == suiDecimal) { + if (ethDecimal == iotaDecimal) { // Ensure converted amount fits within uint64 require(amount <= type(uint64).max, "BridgeConfig: Amount too large for uint64"); return uint64(amount); } - require(ethDecimal > suiDecimal, "BridgeConfig: Invalid Sui decimal"); + require(ethDecimal > iotaDecimal, "BridgeConfig: Invalid Iota decimal"); // Difference in decimal places - uint256 factor = 10 ** (ethDecimal - suiDecimal); + uint256 factor = 10 ** (ethDecimal - iotaDecimal); amount = amount / factor; // Ensure the converted amount fits within uint64 @@ -110,27 +113,27 @@ contract BridgeConfig is IBridgeConfig { return uint64(amount); } - /// @notice Converts the provided Sui decimal adjusted amount to the ERC20 token amount. + /// @notice Converts the provided Iota decimal adjusted amount to the ERC20 token amount. /// @param tokenID The ID of the token to convert. - /// @param amount The Sui amount of the tokens to convert to ERC20. + /// @param amount The Iota amount of the tokens to convert to ERC20. /// @return ERC20 converted amount. - function convertSuiToERC20Decimal(uint8 tokenID, uint64 amount) + function convertIotaToERC20Decimal(uint8 tokenID, uint64 amount) public view override returns (uint256) { uint8 ethDecimal = IERC20Metadata(getTokenAddress(tokenID)).decimals(); - uint8 suiDecimal = getSuiDecimal(tokenID); + uint8 iotaDecimal = getIotaDecimal(tokenID); - if (suiDecimal == ethDecimal) { + if (iotaDecimal == ethDecimal) { return uint256(amount); } - require(ethDecimal > suiDecimal, "BridgeConfig: Invalid Sui decimal"); + require(ethDecimal > iotaDecimal, "BridgeConfig: Invalid Iota decimal"); // Difference in decimal places - uint256 factor = 10 ** (ethDecimal - suiDecimal); + uint256 factor = 10 ** (ethDecimal - iotaDecimal); return uint256(amount * factor); } diff --git a/bridge/evm/contracts/utils/BridgeMessage.sol b/bridge/evm/contracts/utils/BridgeMessage.sol index 95f875ba76a..d5f364c2419 100644 --- a/bridge/evm/contracts/utils/BridgeMessage.sol +++ b/bridge/evm/contracts/utils/BridgeMessage.sol @@ -1,8 +1,11 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; /// @title BridgeMessage -/// @notice This library defines the message format and constants for the Sui native bridge. It also +/// @notice This library defines the message format and constants for the Iota native bridge. It also /// provides functions to encode and decode bridge messages and their payloads. /// @dev This library only utilizes internal functions to enable upgradeability via the OpenZeppelin /// UUPS proxy pattern (external libraries are not supported). @@ -61,13 +64,13 @@ library BridgeMessage { uint32 public constant TOKEN_PRICE_STAKE_REQUIRED = 5001; // token Ids - uint8 public constant SUI = 0; + uint8 public constant IOTA = 0; uint8 public constant BTC = 1; uint8 public constant ETH = 2; uint8 public constant USDC = 3; uint8 public constant USDT = 4; - string public constant MESSAGE_PREFIX = "SUI_BRIDGE_MESSAGE"; + string public constant MESSAGE_PREFIX = "IOTA_BRIDGE_MESSAGE"; /* ========== INTERNAL FUNCTIONS ========== */ @@ -117,7 +120,7 @@ library BridgeMessage { /// @dev The function will revert if the payload length is invalid. /// TokenTransfer payload is 64 bytes. /// byte 0 : sender address length - /// bytes 1-32 : sender address (as we only support Sui now, it has to be 32 bytes long) + /// bytes 1-32 : sender address (as we only support Iota now, it has to be 32 bytes long) /// bytes 33 : target chain id /// byte 34 : target address length /// bytes 35-54 : target address @@ -136,7 +139,7 @@ library BridgeMessage { require( senderAddressLength == 32, - "BridgeMessage: Invalid sender address length, Sui address must be 32 bytes" + "BridgeMessage: Invalid sender address length, Iota address must be 32 bytes" ); // used to offset already read bytes diff --git a/bridge/evm/contracts/utils/CommitteeUpgradeable.sol b/bridge/evm/contracts/utils/CommitteeUpgradeable.sol index 19a1e4448d1..dd8ec924372 100644 --- a/bridge/evm/contracts/utils/CommitteeUpgradeable.sol +++ b/bridge/evm/contracts/utils/CommitteeUpgradeable.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; diff --git a/bridge/evm/contracts/utils/MessageVerifier.sol b/bridge/evm/contracts/utils/MessageVerifier.sol index 5cf05e630b8..cd8bfb65be1 100644 --- a/bridge/evm/contracts/utils/MessageVerifier.sol +++ b/bridge/evm/contracts/utils/MessageVerifier.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; diff --git a/bridge/evm/foundry.toml b/bridge/evm/foundry.toml index ce3a874b48a..ec3a1233cf2 100644 --- a/bridge/evm/foundry.toml +++ b/bridge/evm/foundry.toml @@ -8,7 +8,7 @@ solc = "0.8.20" build_info = true extra_output = ["storageLayout"] fs_permissions = [{ access = "read", path = "./"}] -gas_reports = ["SuiBridge"] +gas_reports = ["IotaBridge"] [fmt] line_length = 100 [fuzz] diff --git a/bridge/evm/script/deploy_bridge.s.sol b/bridge/evm/script/deploy_bridge.s.sol index 7a899d5becd..9455abbec55 100644 --- a/bridge/evm/script/deploy_bridge.s.sol +++ b/bridge/evm/script/deploy_bridge.s.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "forge-std/Script.sol"; @@ -9,7 +12,7 @@ import "../contracts/BridgeCommittee.sol"; import "../contracts/BridgeVault.sol"; import "../contracts/utils/BridgeConfig.sol"; import "../contracts/BridgeLimiter.sol"; -import "../contracts/SuiBridge.sol"; +import "../contracts/IotaBridge.sol"; import "../test/mocks/MockTokens.sol"; contract DeployBridge is Script { @@ -39,7 +42,7 @@ contract DeployBridge is Script { // update config with mock addresses config.supportedTokens = new address[](4); // In BridgeConfig.sol `supportedTokens is shifted by one - // and the first token is SUI. + // and the first token is IOTA. config.supportedTokens[0] = address(wBTC); config.supportedTokens[1] = config.WETH; config.supportedTokens[2] = address(USDC); @@ -101,24 +104,24 @@ contract DeployBridge is Script { uint8[] memory _destinationChains = new uint8[](1); _destinationChains[0] = 1; - // deploy Sui Bridge + // deploy Iota Bridge - address suiBridge = Upgrades.deployUUPSProxy( - "SuiBridge.sol", + address iotaBridge = Upgrades.deployUUPSProxy( + "IotaBridge.sol", abi.encodeCall( - SuiBridge.initialize, (bridgeCommittee, address(vault), limiter, config.WETH) + IotaBridge.initialize, (bridgeCommittee, address(vault), limiter, config.WETH) ) ); // transfer vault ownership to bridge - vault.transferOwnership(suiBridge); + vault.transferOwnership(iotaBridge); // transfer limiter ownership to bridge BridgeLimiter instance = BridgeLimiter(limiter); - instance.transferOwnership(suiBridge); + instance.transferOwnership(iotaBridge); // print deployed addresses for post deployment setup console.log("[Deployed] BridgeConfig:", address(bridgeConfig)); - console.log("[Deployed] SuiBridge:", suiBridge); + console.log("[Deployed] IotaBridge:", iotaBridge); console.log("[Deployed] BridgeLimiter:", limiter); console.log("[Deployed] BridgeCommittee:", bridgeCommittee); console.log("[Deployed] BridgeVault:", address(vault)); diff --git a/bridge/evm/test/BridgeBaseTest.t.sol b/bridge/evm/test/BridgeBaseTest.t.sol index 875e9c4da27..c73273189ed 100644 --- a/bridge/evm/test/BridgeBaseTest.t.sol +++ b/bridge/evm/test/BridgeBaseTest.t.sol @@ -1,11 +1,14 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "forge-std/Test.sol"; import "../contracts/BridgeCommittee.sol"; import "../contracts/BridgeVault.sol"; import "../contracts/BridgeLimiter.sol"; -import "../contracts/SuiBridge.sol"; +import "../contracts/IotaBridge.sol"; import "../contracts/utils/BridgeConfig.sol"; contract BridgeBaseTest is Test { @@ -34,7 +37,7 @@ contract BridgeBaseTest is Test { address USDCWhale = 0x51eDF02152EBfb338e03E30d65C15fBf06cc9ECC; - uint256 SUI_PRICE = 12800; + uint256 IOTA_PRICE = 12800; uint256 BTC_PRICE = 432518900; uint256 ETH_PRICE = 25969600; uint256 USDC_PRICE = 10000; @@ -44,7 +47,7 @@ contract BridgeBaseTest is Test { uint16 minStakeRequired = 10000; BridgeCommittee public committee; - SuiBridge public bridge; + IotaBridge public bridge; BridgeVault public vault; BridgeLimiter public limiter; BridgeConfig public config; @@ -146,7 +149,7 @@ contract BridgeBaseTest is Test { committee.initialize(address(config), _committee, _stake, minStakeRequired); vault = new BridgeVault(wETH); uint256[] memory _tokenPrices = new uint256[](4); - _tokenPrices[0] = SUI_PRICE; + _tokenPrices[0] = IOTA_PRICE; _tokenPrices[1] = BTC_PRICE; _tokenPrices[2] = ETH_PRICE; _tokenPrices[3] = USDC_PRICE; @@ -155,7 +158,7 @@ contract BridgeBaseTest is Test { uint64[] memory chainLimits = new uint64[](1); chainLimits[0] = totalLimit; limiter.initialize(address(committee), _tokenPrices, _supportedChains, chainLimits); - bridge = new SuiBridge(); + bridge = new IotaBridge(); bridge.initialize(address(committee), address(vault), address(limiter), wETH); vault.transferOwnership(address(bridge)); limiter.transferOwnership(address(bridge)); diff --git a/bridge/evm/test/BridgeCommitteeTest.t.sol b/bridge/evm/test/BridgeCommitteeTest.t.sol index c2308304fb0..2795c14a9a8 100644 --- a/bridge/evm/test/BridgeCommitteeTest.t.sol +++ b/bridge/evm/test/BridgeCommitteeTest.t.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "./BridgeBaseTest.t.sol"; diff --git a/bridge/evm/test/BridgeConfigTest.t.sol b/bridge/evm/test/BridgeConfigTest.t.sol index db3a164ffe1..f88da7895c9 100644 --- a/bridge/evm/test/BridgeConfigTest.t.sol +++ b/bridge/evm/test/BridgeConfigTest.t.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "./mocks/MockTokens.sol"; @@ -14,11 +17,11 @@ contract BridgeConfigTest is BridgeBaseTest { assertTrue(config.getTokenAddress(2) == wETH); assertTrue(config.getTokenAddress(3) == USDC); assertTrue(config.getTokenAddress(4) == USDT); - assertEq(config.getSuiDecimal(0), 9); - assertEq(config.getSuiDecimal(1), 8); - assertEq(config.getSuiDecimal(2), 8); - assertEq(config.getSuiDecimal(3), 6); - assertEq(config.getSuiDecimal(4), 6); + assertEq(config.getIotaDecimal(0), 9); + assertEq(config.getIotaDecimal(1), 8); + assertEq(config.getIotaDecimal(2), 8); + assertEq(config.getIotaDecimal(3), 6); + assertEq(config.getIotaDecimal(4), 6); assertEq(config.chainID(), chainID); assertTrue(config.supportedChains(0)); } @@ -27,12 +30,12 @@ contract BridgeConfigTest is BridgeBaseTest { assertEq(config.getTokenAddress(1), wBTC); } - function testconvertERC20ToSuiDecimalAmountTooLargeForUint64() public { + function testconvertERC20ToIotaDecimalAmountTooLargeForUint64() public { vm.expectRevert(bytes("BridgeConfig: Amount too large for uint64")); - config.convertERC20ToSuiDecimal(BridgeMessage.ETH, type(uint256).max); + config.convertERC20ToIotaDecimal(BridgeMessage.ETH, type(uint256).max); } - function testconvertERC20ToSuiDecimalInvalidSuiDecimal() public { + function testconvertERC20ToIotaDecimalInvalidIotaDecimal() public { vm.startPrank(address(bridge)); address smallUSDC = address(new MockSmallUSDC()); address[] memory _supportedTokens = new address[](4); @@ -44,11 +47,11 @@ contract BridgeConfigTest is BridgeBaseTest { _supportedDestinationChains[0] = 0; BridgeConfig newBridgeConfig = new BridgeConfig(chainID, _supportedTokens, _supportedDestinationChains); - vm.expectRevert(bytes("BridgeConfig: Invalid Sui decimal")); - newBridgeConfig.convertERC20ToSuiDecimal(3, 100); + vm.expectRevert(bytes("BridgeConfig: Invalid Iota decimal")); + newBridgeConfig.convertERC20ToIotaDecimal(3, 100); } - function testconvertSuiToERC20DecimalInvalidSuiDecimal() public { + function testconvertIotaToERC20DecimalInvalidIotaDecimal() public { vm.startPrank(address(bridge)); address smallUSDC = address(new MockSmallUSDC()); address[] memory _supportedTokens = new address[](4); @@ -60,8 +63,8 @@ contract BridgeConfigTest is BridgeBaseTest { _supportedDestinationChains[0] = 0; BridgeConfig newBridgeConfig = new BridgeConfig(chainID, _supportedTokens, _supportedDestinationChains); - vm.expectRevert(bytes("BridgeConfig: Invalid Sui decimal")); - newBridgeConfig.convertSuiToERC20Decimal(3, 100); + vm.expectRevert(bytes("BridgeConfig: Invalid Iota decimal")); + newBridgeConfig.convertIotaToERC20Decimal(3, 100); } function testIsTokenSupported() public { @@ -69,59 +72,59 @@ contract BridgeConfigTest is BridgeBaseTest { assertTrue(!config.isTokenSupported(0)); } - function testGetSuiDecimal() public { - assertEq(config.getSuiDecimal(1), 8); + function testGetIotaDecimal() public { + assertEq(config.getIotaDecimal(1), 8); } - function testconvertERC20ToSuiDecimal() public { + function testconvertERC20ToIotaDecimal() public { // ETH assertEq(IERC20Metadata(wETH).decimals(), 18); uint256 ethAmount = 10 ether; - uint64 suiAmount = config.convertERC20ToSuiDecimal(BridgeMessage.ETH, ethAmount); - assertEq(suiAmount, 10_000_000_00); // 10 * 10 ^ 8 + uint64 iotaAmount = config.convertERC20ToIotaDecimal(BridgeMessage.ETH, ethAmount); + assertEq(iotaAmount, 10_000_000_00); // 10 * 10 ^ 8 // USDC assertEq(IERC20Metadata(USDC).decimals(), 6); ethAmount = 50_000_000; // 50 USDC - suiAmount = config.convertERC20ToSuiDecimal(BridgeMessage.USDC, ethAmount); - assertEq(suiAmount, ethAmount); + iotaAmount = config.convertERC20ToIotaDecimal(BridgeMessage.USDC, ethAmount); + assertEq(iotaAmount, ethAmount); // USDT assertEq(IERC20Metadata(USDT).decimals(), 6); ethAmount = 60_000_000; // 60 USDT - suiAmount = config.convertERC20ToSuiDecimal(BridgeMessage.USDT, ethAmount); - assertEq(suiAmount, ethAmount); + iotaAmount = config.convertERC20ToIotaDecimal(BridgeMessage.USDT, ethAmount); + assertEq(iotaAmount, ethAmount); // BTC assertEq(IERC20Metadata(wBTC).decimals(), 8); ethAmount = 2_00_000_000; // 2 BTC - suiAmount = config.convertERC20ToSuiDecimal(BridgeMessage.BTC, ethAmount); - assertEq(suiAmount, ethAmount); + iotaAmount = config.convertERC20ToIotaDecimal(BridgeMessage.BTC, ethAmount); + assertEq(iotaAmount, ethAmount); } - function testconvertSuiToERC20Decimal() public { + function testconvertIotaToERC20Decimal() public { // ETH assertEq(IERC20Metadata(wETH).decimals(), 18); - uint64 suiAmount = 11_000_000_00; // 11 eth - uint256 ethAmount = config.convertSuiToERC20Decimal(BridgeMessage.ETH, suiAmount); + uint64 iotaAmount = 11_000_000_00; // 11 eth + uint256 ethAmount = config.convertIotaToERC20Decimal(BridgeMessage.ETH, iotaAmount); assertEq(ethAmount, 11 ether); // USDC assertEq(IERC20Metadata(USDC).decimals(), 6); - suiAmount = 50_000_000; // 50 USDC - ethAmount = config.convertSuiToERC20Decimal(BridgeMessage.USDC, suiAmount); - assertEq(suiAmount, ethAmount); + iotaAmount = 50_000_000; // 50 USDC + ethAmount = config.convertIotaToERC20Decimal(BridgeMessage.USDC, iotaAmount); + assertEq(iotaAmount, ethAmount); // USDT assertEq(IERC20Metadata(USDT).decimals(), 6); - suiAmount = 50_000_000; // 50 USDT - ethAmount = config.convertSuiToERC20Decimal(BridgeMessage.USDT, suiAmount); - assertEq(suiAmount, ethAmount); + iotaAmount = 50_000_000; // 50 USDT + ethAmount = config.convertIotaToERC20Decimal(BridgeMessage.USDT, iotaAmount); + assertEq(iotaAmount, ethAmount); // BTC assertEq(IERC20Metadata(wBTC).decimals(), 8); - suiAmount = 3_000_000_00; // 3 BTC - ethAmount = config.convertSuiToERC20Decimal(BridgeMessage.BTC, suiAmount); - assertEq(suiAmount, ethAmount); + iotaAmount = 3_000_000_00; // 3 BTC + ethAmount = config.convertIotaToERC20Decimal(BridgeMessage.BTC, iotaAmount); + assertEq(iotaAmount, ethAmount); } } diff --git a/bridge/evm/test/BridgeLimiterTest.t.sol b/bridge/evm/test/BridgeLimiterTest.t.sol index 7c942327638..5bf2e55ddf3 100644 --- a/bridge/evm/test/BridgeLimiterTest.t.sol +++ b/bridge/evm/test/BridgeLimiterTest.t.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; @@ -15,7 +18,7 @@ contract BridgeLimiterTest is BridgeBaseTest { } function testBridgeLimiterInitialization() public { - assertEq(limiter.tokenPrices(0), SUI_PRICE); + assertEq(limiter.tokenPrices(0), IOTA_PRICE); assertEq(limiter.tokenPrices(1), BTC_PRICE); assertEq(limiter.tokenPrices(2), ETH_PRICE); assertEq(limiter.tokenPrices(3), USDC_PRICE); @@ -190,7 +193,7 @@ contract BridgeLimiterTest is BridgeBaseTest { totalLimits[0] = 10000000000; totalLimits[1] = 20000000000; uint256[] memory tokenPrices = new uint256[](4); - tokenPrices[0] = SUI_PRICE; + tokenPrices[0] = IOTA_PRICE; tokenPrices[1] = BTC_PRICE; tokenPrices[2] = ETH_PRICE; tokenPrices[3] = USDC_PRICE; @@ -241,7 +244,7 @@ contract BridgeLimiterTest is BridgeBaseTest { committee.initialize(address(config), _committee, _stake, minStakeRequired); vault = new BridgeVault(wETH); uint256[] memory tokenPrices = new uint256[](4); - tokenPrices[0] = 10000; // SUI PRICE + tokenPrices[0] = 10000; // IOTA PRICE tokenPrices[1] = 10000; // BTC PRICE tokenPrices[2] = 10000; // ETH PRICE tokenPrices[3] = 10000; // USDC PRICE @@ -254,7 +257,7 @@ contract BridgeLimiterTest is BridgeBaseTest { limiter.initialize( address(committee), tokenPrices, _supportedDestinationChains, totalLimits ); - bridge = new SuiBridge(); + bridge = new IotaBridge(); bridge.initialize(address(committee), address(vault), address(limiter), wETH); vault.transferOwnership(address(bridge)); limiter.transferOwnership(address(bridge)); @@ -305,7 +308,7 @@ contract BridgeLimiterTest is BridgeBaseTest { committee.initialize(address(config), _committee, _stake, minStakeRequired); vault = new BridgeVault(wETH); uint256[] memory tokenPrices = new uint256[](4); - tokenPrices[0] = 10000; // SUI PRICE + tokenPrices[0] = 10000; // IOTA PRICE tokenPrices[1] = 10000; // BTC PRICE tokenPrices[2] = 10000; // ETH PRICE tokenPrices[3] = 10000; // USDC PRICE @@ -319,7 +322,7 @@ contract BridgeLimiterTest is BridgeBaseTest { limiter.initialize( address(committee), tokenPrices, _supportedDestinationChains, totalLimits ); - bridge = new SuiBridge(); + bridge = new IotaBridge(); bridge.initialize(address(committee), address(vault), address(limiter), wETH); vault.transferOwnership(address(bridge)); @@ -377,7 +380,7 @@ contract BridgeLimiterTest is BridgeBaseTest { committee.initialize(address(config), _committee, _stake, minStakeRequired); vault = new BridgeVault(wETH); uint256[] memory tokenPrices = new uint256[](4); - tokenPrices[0] = 10000; // SUI PRICE + tokenPrices[0] = 10000; // IOTA PRICE tokenPrices[1] = 10000; // BTC PRICE tokenPrices[2] = 10000; // ETH PRICE tokenPrices[3] = 10000; // USDC PRICE @@ -390,7 +393,7 @@ contract BridgeLimiterTest is BridgeBaseTest { limiter.initialize( address(committee), tokenPrices, _supportedDestinationChains, totalLimits ); - bridge = new SuiBridge(); + bridge = new IotaBridge(); bridge.initialize(address(committee), address(vault), address(limiter), wETH); vault.transferOwnership(address(bridge)); limiter.transferOwnership(address(bridge)); @@ -440,7 +443,7 @@ contract BridgeLimiterTest is BridgeBaseTest { committee.initialize(address(config), _committee, _stake, minStakeRequired); vault = new BridgeVault(wETH); uint256[] memory tokenPrices = new uint256[](4); - tokenPrices[0] = 10000; // SUI PRICE + tokenPrices[0] = 10000; // IOTA PRICE tokenPrices[1] = 10000; // BTC PRICE tokenPrices[2] = 10000; // ETH PRICE tokenPrices[3] = 10000; // USDC PRICE @@ -454,7 +457,7 @@ contract BridgeLimiterTest is BridgeBaseTest { limiter.initialize( address(committee), tokenPrices, _supportedDestinationChains, totalLimits ); - bridge = new SuiBridge(); + bridge = new IotaBridge(); bridge.initialize(address(committee), address(vault), address(limiter), wETH); vault.transferOwnership(address(bridge)); limiter.transferOwnership(address(bridge)); diff --git a/bridge/evm/test/BridgeMessageTest.t.sol b/bridge/evm/test/BridgeMessageTest.t.sol index e5dc3df5126..dd6de9c1cb0 100644 --- a/bridge/evm/test/BridgeMessageTest.t.sol +++ b/bridge/evm/test/BridgeMessageTest.t.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "./BridgeBaseTest.t.sol"; @@ -11,7 +14,7 @@ contract BridgeMessageTest is BridgeBaseTest { ); uint64 nonce = 0; - uint8 suiChainId = 1; + uint8 iotaChainId = 1; bytes memory payload = abi.encodePacked( hex"2080ab1ee086210a3a37355300ca24672e81062fcdb5ced6618dab203f6a3b291c0b14b18f79fe671db47393315ffdb377da4ea1b7af96010084d71700000000" @@ -22,7 +25,7 @@ contract BridgeMessageTest is BridgeBaseTest { messageType: BridgeMessage.TOKEN_TRANSFER, version: 1, nonce: nonce, - chainID: suiChainId, + chainID: iotaChainId, payload: payload }) ); diff --git a/bridge/evm/test/CommitteeUpgradeableTest.t.sol b/bridge/evm/test/CommitteeUpgradeableTest.t.sol index 46a2bc3b112..c910c64fcaf 100644 --- a/bridge/evm/test/CommitteeUpgradeableTest.t.sol +++ b/bridge/evm/test/CommitteeUpgradeableTest.t.sol @@ -1,16 +1,19 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol"; import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; -import "./mocks/MockSuiBridgeV2.sol"; +import "./mocks/MockIotaBridgeV2.sol"; import "../contracts/BridgeCommittee.sol"; -import "../contracts/SuiBridge.sol"; +import "../contracts/IotaBridge.sol"; import "./BridgeBaseTest.t.sol"; import "forge-std/Test.sol"; contract CommitteeUpgradeableTest is BridgeBaseTest { - MockSuiBridgeV2 bridgeV2; + MockIotaBridgeV2 bridgeV2; uint8 _chainID = 12; // This function is called before each unit test @@ -50,18 +53,18 @@ contract CommitteeUpgradeableTest is BridgeBaseTest { committee = BridgeCommittee(_committee); - // deploy sui bridge + // deploy iota bridge address _bridge = Upgrades.deployUUPSProxy( - "SuiBridge.sol", - abi.encodeCall(SuiBridge.initialize, (_committee, address(0), address(0), address(0))) + "IotaBridge.sol", + abi.encodeCall(IotaBridge.initialize, (_committee, address(0), address(0), address(0))) ); - bridge = SuiBridge(_bridge); - bridgeV2 = new MockSuiBridgeV2(); + bridge = IotaBridge(_bridge); + bridgeV2 = new MockIotaBridgeV2(); } function testUpgradeWithSignaturesSuccess() public { - bytes memory initializer = abi.encodeCall(MockSuiBridgeV2.initializeV2, ()); + bytes memory initializer = abi.encodeCall(MockIotaBridgeV2.initializeV2, ()); bytes memory payload = abi.encode(address(bridge), address(bridgeV2), initializer); // Create upgrade message @@ -87,7 +90,7 @@ contract CommitteeUpgradeableTest is BridgeBaseTest { function testUpgradeWithSignaturesInsufficientStakeAmount() public { // Create message - bytes memory initializer = abi.encodeCall(MockSuiBridgeV2.initializeV2, ()); + bytes memory initializer = abi.encodeCall(MockIotaBridgeV2.initializeV2, ()); bytes memory payload = abi.encode(address(bridge), address(bridgeV2), initializer); // Create upgrade message @@ -146,7 +149,7 @@ contract CommitteeUpgradeableTest is BridgeBaseTest { } function testUpgradeWithSignaturesERC1967UpgradeNewImplementationIsNotUUPS() public { - bytes memory initializer = abi.encodeCall(MockSuiBridgeV2.initializeV2, ()); + bytes memory initializer = abi.encodeCall(MockIotaBridgeV2.initializeV2, ()); bytes memory payload = abi.encode(address(bridge), address(this), initializer); BridgeMessage.Message memory message = BridgeMessage.Message({ @@ -173,7 +176,7 @@ contract CommitteeUpgradeableTest is BridgeBaseTest { } function testUpgradeWithSignaturesInvalidProxyAddress() public { - bytes memory initializer = abi.encodeCall(MockSuiBridgeV2.initializeV2, ()); + bytes memory initializer = abi.encodeCall(MockIotaBridgeV2.initializeV2, ()); bytes memory payload = abi.encode(address(this), address(bridgeV2), initializer); BridgeMessage.Message memory message = BridgeMessage.Message({ @@ -261,7 +264,7 @@ contract CommitteeUpgradeableTest is BridgeBaseTest { bridge.upgradeWithSignatures(signatures, message); - MockSuiBridgeV2 newBridgeV2 = MockSuiBridgeV2(address(bridge)); + MockIotaBridgeV2 newBridgeV2 = MockIotaBridgeV2(address(bridge)); assertTrue(newBridgeV2.isPausing()); assertEq(Upgrades.getImplementationAddress(address(bridge)), address(bridgeV2)); } @@ -297,7 +300,7 @@ contract CommitteeUpgradeableTest is BridgeBaseTest { bridge.upgradeWithSignatures(signatures, message); - MockSuiBridgeV2 newBridgeV2 = MockSuiBridgeV2(address(bridge)); + MockIotaBridgeV2 newBridgeV2 = MockIotaBridgeV2(address(bridge)); assertTrue(newBridgeV2.isPausing()); assertEq(newBridgeV2.mock(), 42); assertEq(Upgrades.getImplementationAddress(address(bridge)), address(bridgeV2)); @@ -334,7 +337,7 @@ contract CommitteeUpgradeableTest is BridgeBaseTest { bridge.upgradeWithSignatures(signatures, message); - MockSuiBridgeV2(address(bridge)); + MockIotaBridgeV2(address(bridge)); assertEq(Upgrades.getImplementationAddress(address(bridge)), address(bridgeV2)); } diff --git a/bridge/evm/test/IotaBridgeTest.t.sol b/bridge/evm/test/IotaBridgeTest.t.sol new file mode 100644 index 00000000000..9ded974db4b --- /dev/null +++ b/bridge/evm/test/IotaBridgeTest.t.sol @@ -0,0 +1,1047 @@ +// SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import "./BridgeBaseTest.t.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import "../contracts/interfaces/IIotaBridge.sol"; +import "./mocks/MockIotaBridgeV2.sol"; + +contract IotaBridgeTest is BridgeBaseTest, IIotaBridge { + // This function is called before each unit test + function setUp() public { + setUpBridgeTest(); + } + + function testIotaBridgeInitialization() public { + assertEq(address(bridge.committee()), address(committee)); + assertEq(address(bridge.vault()), address(vault)); + assertEq(address(bridge.wETH()), wETH); + } + + function testTransferBridgedTokensWithSignaturesTokenDailyLimitExceeded() public { + uint8 senderAddressLength = 32; + bytes memory senderAddress = abi.encode(0); + uint8 targetChain = chainID; + uint8 recipientAddressLength = 20; + address recipientAddress = bridgerA; + uint8 tokenID = BridgeMessage.ETH; + uint64 amount = 100000000000000; + bytes memory payload = abi.encodePacked( + senderAddressLength, + senderAddress, + targetChain, + recipientAddressLength, + recipientAddress, + tokenID, + amount + ); + + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.TOKEN_TRANSFER, + version: 1, + nonce: 1, + chainID: 0, + payload: payload + }); + + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes32 messageHash = keccak256(encodedMessage); + + bytes[] memory signatures = new bytes[](4); + signatures[0] = getSignature(messageHash, committeeMemberPkA); + signatures[1] = getSignature(messageHash, committeeMemberPkB); + signatures[2] = getSignature(messageHash, committeeMemberPkC); + signatures[3] = getSignature(messageHash, committeeMemberPkD); + vm.expectRevert(bytes("IotaBridge: Amount exceeds bridge limit")); + bridge.transferBridgedTokensWithSignatures(signatures, message); + } + + function testTransferBridgedTokensWithSignaturesInvalidTargetChain() public { + uint8 senderAddressLength = 32; + bytes memory senderAddress = abi.encode(0); + uint8 targetChain = 0; + uint8 recipientAddressLength = 20; + address recipientAddress = bridgerA; + uint8 tokenID = BridgeMessage.ETH; + uint64 amount = 10000; + bytes memory payload = abi.encodePacked( + senderAddressLength, + senderAddress, + targetChain, + recipientAddressLength, + recipientAddress, + tokenID, + amount + ); + + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.TOKEN_TRANSFER, + version: 1, + nonce: 1, + chainID: 1, + payload: payload + }); + + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes32 messageHash = keccak256(encodedMessage); + + bytes[] memory signatures = new bytes[](4); + signatures[0] = getSignature(messageHash, committeeMemberPkA); + signatures[1] = getSignature(messageHash, committeeMemberPkB); + signatures[2] = getSignature(messageHash, committeeMemberPkC); + signatures[3] = getSignature(messageHash, committeeMemberPkD); + vm.expectRevert(bytes("IotaBridge: Target chain not supported")); + bridge.transferBridgedTokensWithSignatures(signatures, message); + } + + function testTransferBridgedTokensWithSignaturesInsufficientStakeAmount() public { + // Create transfer message + BridgeMessage.TokenTransferPayload memory payload = BridgeMessage.TokenTransferPayload({ + senderAddressLength: 0, + senderAddress: abi.encode(0), + targetChain: 1, + recipientAddressLength: 0, + recipientAddress: bridgerA, + tokenID: BridgeMessage.ETH, + // This is Iota amount (eth decimal 8) + amount: 100_000_000 + }); + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.TOKEN_TRANSFER, + version: 1, + nonce: 1, + chainID: chainID, + payload: abi.encode(payload) + }); + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes32 messageHash = keccak256(encodedMessage); + bytes[] memory signatures = new bytes[](2); + signatures[0] = getSignature(messageHash, committeeMemberPkA); + signatures[1] = getSignature(messageHash, committeeMemberPkB); + vm.expectRevert(bytes("BridgeCommittee: Insufficient stake amount")); + bridge.transferBridgedTokensWithSignatures(signatures, message); + } + + function testTransferBridgedTokensWithSignaturesMessageDoesNotMatchType() public { + // Create transfer message + BridgeMessage.TokenTransferPayload memory payload = BridgeMessage.TokenTransferPayload({ + senderAddressLength: 0, + senderAddress: abi.encode(0), + targetChain: 1, + recipientAddressLength: 0, + recipientAddress: bridgerA, + tokenID: BridgeMessage.ETH, + // This is Iota amount (eth decimal 8) + amount: 100_000_000 + }); + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.EMERGENCY_OP, + version: 1, + nonce: 1, + chainID: chainID, + payload: abi.encode(payload) + }); + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes32 messageHash = keccak256(encodedMessage); + bytes[] memory signatures = new bytes[](2); + signatures[0] = getSignature(messageHash, committeeMemberPkA); + signatures[1] = getSignature(messageHash, committeeMemberPkB); + vm.expectRevert(bytes("MessageVerifier: message does not match type")); + bridge.transferBridgedTokensWithSignatures(signatures, message); + } + + function testTransferWETHWithValidSignatures() public { + // Fill vault with WETH + changePrank(deployer); + IWETH9(wETH).deposit{value: 10 ether}(); + // IWETH9(wETH).withdraw(1 ether); + IERC20(wETH).transfer(address(vault), 10 ether); + // Create transfer payload + uint8 senderAddressLength = 32; + bytes memory senderAddress = abi.encode(0); + uint8 targetChain = chainID; + uint8 recipientAddressLength = 20; + address recipientAddress = bridgerA; + uint8 tokenID = BridgeMessage.ETH; + uint64 amount = 100000000; // 1 ether in iota decimals + bytes memory payload = abi.encodePacked( + senderAddressLength, + senderAddress, + targetChain, + recipientAddressLength, + recipientAddress, + tokenID, + amount + ); + + // Create transfer message + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.TOKEN_TRANSFER, + version: 1, + nonce: 1, + chainID: 0, + payload: payload + }); + + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + + bytes32 messageHash = keccak256(encodedMessage); + + bytes[] memory signatures = new bytes[](4); + + signatures[0] = getSignature(messageHash, committeeMemberPkA); + signatures[1] = getSignature(messageHash, committeeMemberPkB); + signatures[2] = getSignature(messageHash, committeeMemberPkC); + signatures[3] = getSignature(messageHash, committeeMemberPkD); + + uint256 aBalance = bridgerA.balance; + bridge.transferBridgedTokensWithSignatures(signatures, message); + assertEq(bridgerA.balance, aBalance + 1 ether); + + vm.expectRevert(bytes("IotaBridge: Message already processed")); + bridge.transferBridgedTokensWithSignatures(signatures, message); + } + + function testTransferUSDCWithValidSignatures() public { + // Fill vault with USDC + changePrank(USDCWhale); + IERC20(USDC).transfer(address(vault), 100_000_000); + changePrank(deployer); + + // Create transfer payload + uint8 senderAddressLength = 32; + bytes memory senderAddress = abi.encode(0); + uint8 targetChain = chainID; + uint8 recipientAddressLength = 20; + address recipientAddress = bridgerA; + uint8 tokenID = BridgeMessage.USDC; + uint64 amount = 1_000_000; + bytes memory payload = abi.encodePacked( + senderAddressLength, + senderAddress, + targetChain, + recipientAddressLength, + recipientAddress, + tokenID, + amount + ); + + // Create transfer message + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.TOKEN_TRANSFER, + version: 1, + nonce: 1, + chainID: 0, + payload: payload + }); + + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes32 messageHash = keccak256(encodedMessage); + + bytes[] memory signatures = new bytes[](4); + + signatures[0] = getSignature(messageHash, committeeMemberPkA); + signatures[1] = getSignature(messageHash, committeeMemberPkB); + signatures[2] = getSignature(messageHash, committeeMemberPkC); + signatures[3] = getSignature(messageHash, committeeMemberPkD); + + assert(IERC20(USDC).balanceOf(bridgerA) == 0); + bridge.transferBridgedTokensWithSignatures(signatures, message); + assert(IERC20(USDC).balanceOf(bridgerA) == 1_000_000); + } + + function testExecuteEmergencyOpWithSignaturesInvalidOpCode() public { + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.EMERGENCY_OP, + version: 1, + nonce: 0, + chainID: chainID, + payload: hex"02" + }); + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes32 messageHash = keccak256(encodedMessage); + bytes[] memory signatures = new bytes[](4); + signatures[0] = getSignature(messageHash, committeeMemberPkA); + signatures[1] = getSignature(messageHash, committeeMemberPkB); + signatures[2] = getSignature(messageHash, committeeMemberPkC); + signatures[3] = getSignature(messageHash, committeeMemberPkD); + vm.expectRevert(bytes("BridgeMessage: Invalid op code")); + bridge.executeEmergencyOpWithSignatures(signatures, message); + } + + function testExecuteEmergencyOpWithSignaturesInvalidNonce() public { + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.EMERGENCY_OP, + version: 1, + nonce: 1, + chainID: chainID, + payload: bytes(hex"00") + }); + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes32 messageHash = keccak256(encodedMessage); + bytes[] memory signatures = new bytes[](4); + signatures[0] = getSignature(messageHash, committeeMemberPkA); + signatures[1] = getSignature(messageHash, committeeMemberPkB); + signatures[2] = getSignature(messageHash, committeeMemberPkC); + signatures[3] = getSignature(messageHash, committeeMemberPkD); + vm.expectRevert(bytes("MessageVerifier: Invalid nonce")); + bridge.executeEmergencyOpWithSignatures(signatures, message); + } + + function testExecuteEmergencyOpWithSignaturesMessageDoesNotMatchType() public { + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.TOKEN_TRANSFER, + version: 1, + nonce: 0, + chainID: chainID, + payload: abi.encode(0) + }); + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes32 messageHash = keccak256(encodedMessage); + bytes[] memory signatures = new bytes[](4); + signatures[0] = getSignature(messageHash, committeeMemberPkA); + signatures[1] = getSignature(messageHash, committeeMemberPkB); + signatures[2] = getSignature(messageHash, committeeMemberPkC); + signatures[3] = getSignature(messageHash, committeeMemberPkD); + vm.expectRevert(bytes("MessageVerifier: message does not match type")); + bridge.executeEmergencyOpWithSignatures(signatures, message); + } + + function testExecuteEmergencyOpWithSignaturesInvalidSignatures() public { + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.EMERGENCY_OP, + version: 1, + nonce: 0, + chainID: chainID, + payload: bytes(hex"01") + }); + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes32 messageHash = keccak256(encodedMessage); + bytes[] memory signatures = new bytes[](2); + signatures[0] = getSignature(messageHash, committeeMemberPkA); + signatures[1] = getSignature(messageHash, committeeMemberPkB); + vm.expectRevert(bytes("BridgeCommittee: Insufficient stake amount")); + bridge.executeEmergencyOpWithSignatures(signatures, message); + } + + function testFreezeBridgeEmergencyOp() public { + // Create emergency op message + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.EMERGENCY_OP, + version: 1, + nonce: 0, + chainID: chainID, + payload: bytes(hex"00") + }); + + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes32 messageHash = keccak256(encodedMessage); + + bytes[] memory signatures = new bytes[](4); + + signatures[0] = getSignature(messageHash, committeeMemberPkA); + signatures[1] = getSignature(messageHash, committeeMemberPkB); + signatures[2] = getSignature(messageHash, committeeMemberPkC); + signatures[3] = getSignature(messageHash, committeeMemberPkD); + + assertFalse(bridge.paused()); + bridge.executeEmergencyOpWithSignatures(signatures, message); + assertTrue(bridge.paused()); + } + + function testUnfreezeBridgeEmergencyOp() public { + testFreezeBridgeEmergencyOp(); + // Create emergency op message + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.EMERGENCY_OP, + version: 1, + nonce: 1, + chainID: chainID, + payload: bytes(hex"01") + }); + + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes32 messageHash = keccak256(encodedMessage); + + bytes[] memory signatures = new bytes[](4); + + signatures[0] = getSignature(messageHash, committeeMemberPkA); + signatures[1] = getSignature(messageHash, committeeMemberPkB); + signatures[2] = getSignature(messageHash, committeeMemberPkC); + signatures[3] = getSignature(messageHash, committeeMemberPkD); + + bridge.executeEmergencyOpWithSignatures(signatures, message); + assertFalse(bridge.paused()); + } + + function testBridgeERC20UnsupportedToken() public { + vm.expectRevert(bytes("IotaBridge: Unsupported token")); + bridge.bridgeERC20(255, 1 ether, abi.encode("iotaAddress"), 0); + } + + function testBridgeERC20InsufficientAllowance() public { + vm.expectRevert(bytes("IotaBridge: Insufficient allowance")); + bridge.bridgeERC20(BridgeMessage.ETH, type(uint256).max, abi.encode("iotaAddress"), 0); + } + + function testBridgeWETH() public { + changePrank(deployer); + IWETH9(wETH).deposit{value: 10 ether}(); + IERC20(wETH).approve(address(bridge), 10 ether); + assertEq(IERC20(wETH).balanceOf(address(vault)), 0); + uint256 balance = IERC20(wETH).balanceOf(deployer); + + // assert emitted event + vm.expectEmit(true, true, true, false); + emit TokensDeposited( + chainID, + 0, // nonce + 0, // destination chain id + BridgeMessage.ETH, + 1_00_000_000, // 1 ether + deployer, + abi.encode("iotaAddress") + ); + + bridge.bridgeERC20(BridgeMessage.ETH, 1 ether, abi.encode("iotaAddress"), 0); + assertEq(IERC20(wETH).balanceOf(address(vault)), 1 ether); + assertEq(IERC20(wETH).balanceOf(deployer), balance - 1 ether); + assertEq(bridge.nonces(BridgeMessage.TOKEN_TRANSFER), 1); + + // Now test rounding. For ETH, the last 10 digits are rounded + vm.expectEmit(true, true, true, false); + emit TokensDeposited( + chainID, + 1, // nonce + 0, // destination chain id + BridgeMessage.ETH, + 2.00000001 ether, + deployer, + abi.encode("iotaAddress") + ); + // 2_000_000_011_000_000_888 is rounded to 2.00000001 eth + bridge.bridgeERC20( + BridgeMessage.ETH, 2_000_000_011_000_000_888, abi.encode("iotaAddress"), 0 + ); + assertEq(IERC20(wETH).balanceOf(address(vault)), 3_000_000_011_000_000_888); + assertEq(IERC20(wETH).balanceOf(deployer), balance - 3_000_000_011_000_000_888); + assertEq(bridge.nonces(BridgeMessage.TOKEN_TRANSFER), 2); + } + + function testBridgeUSDC() public { + // TODO test and make sure adjusted amount in event is correct + } + + function testBridgeUSDT() public { + // TODO test and make sure adjusted amount in event is correct + } + + function testBridgeBTC() public { + // TODO test and make sure adjusted amount in event is correct + } + + function testBridgeEth() public { + changePrank(deployer); + assertEq(IERC20(wETH).balanceOf(address(vault)), 0); + uint256 balance = deployer.balance; + + // assert emitted event + vm.expectEmit(true, true, true, false); + emit IIotaBridge.TokensDeposited( + chainID, + 0, // nonce + 0, // destination chain id + BridgeMessage.ETH, + 1_000_000_00, // 1 ether + deployer, + abi.encode("iotaAddress") + ); + + bridge.bridgeETH{value: 1 ether}(abi.encode("iotaAddress"), 0); + assertEq(IERC20(wETH).balanceOf(address(vault)), 1 ether); + assertEq(deployer.balance, balance - 1 ether); + assertEq(bridge.nonces(BridgeMessage.TOKEN_TRANSFER), 1); + } + + // TESTS FOR GAS MEASUREMENT + + // function testTransferBridgedTokensWith7Signatures() public { + // // define committee with 50 members + // address[] memory _committee = new address[](56); + // uint256[] memory pks = new uint256[](56); + // uint16[] memory _stake = new uint16[](56); + // for (uint256 i = 0; i < 56; i++) { + // string memory name = string(abi.encodePacked("committeeMember", i)); + // (address member, uint256 pk) = makeAddrAndKey(name); + // _committee[i] = member; + // pks[i] = pk; + // // 1 member with 2500 stake + // if (i == 55) { + // _stake[i] = 2500; + // // 50 members with 100 stake (total: 5000) + // } else if (i < 50) { + // _stake[i] = 100; + // // 5 members with 500 stake (total: 2500) + // } else { + // _stake[i] = 500; + // } + // } + // committee = new BridgeCommittee(); + // committee.initialize(address(config), _committee, _stake, minStakeRequired); + // uint256[] memory tokenPrices = new uint256[](4); + // tokenPrices[0] = 10000; // IOTA PRICE + // tokenPrices[1] = 10000; // BTC PRICE + // tokenPrices[2] = 10000; // ETH PRICE + // tokenPrices[3] = 10000; // USDC PRICE + // uint64[] memory totalLimits = new uint64[](1); + // totalLimits[0] = 1000000; + // skip(2 days); + // IotaBridge _bridge = new IotaBridge(); + // _bridge.initialize(address(committee), address(vault), address(limiter), wETH); + // changePrank(address(bridge)); + // limiter.transferOwnership(address(_bridge)); + // vault.transferOwnership(address(_bridge)); + // bridge = _bridge; + + // // Fill vault with WETH + // changePrank(deployer); + // IWETH9(wETH).deposit{value: 10 ether}(); + // IERC20(wETH).transfer(address(vault), 10 ether); + + // // transfer bridged tokens with 7 signatures + // // Create transfer payload + // uint8 senderAddressLength = 32; + // bytes memory senderAddress = abi.encode(0); + // uint8 targetChain = chainID; + // uint8 recipientAddressLength = 20; + // address recipientAddress = bridgerA; + // uint8 tokenID = BridgeMessage.ETH; + // uint64 amount = 100000000; // 1 ether in iota decimals + // bytes memory payload = abi.encodePacked( + // senderAddressLength, + // senderAddress, + // targetChain, + // recipientAddressLength, + // recipientAddress, + // tokenID, + // amount + // ); + + // // Create transfer message + // BridgeMessage.Message memory message = BridgeMessage.Message({ + // messageType: BridgeMessage.TOKEN_TRANSFER, + // version: 1, + // nonce: 1, + // chainID: 0, + // payload: payload + // }); + + // bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + + // bytes32 messageHash = keccak256(encodedMessage); + + // bytes[] memory signatures = new bytes[](7); + + // uint8 index; + // for (uint256 i = 50; i < 55; i++) { + // signatures[index++] = getSignature(messageHash, pks[i]); + // } + // signatures[5] = getSignature(messageHash, pks[55]); + // signatures[6] = getSignature(messageHash, pks[0]); + + // bridge.transferBridgedTokensWithSignatures(signatures, message); + // } + + // function testTransferBridgedTokensWith26Signatures() public { + // // define committee with 50 members + // address[] memory _committee = new address[](56); + // uint256[] memory pks = new uint256[](56); + // uint16[] memory _stake = new uint16[](56); + // for (uint256 i = 0; i < 56; i++) { + // string memory name = string(abi.encodePacked("committeeMember", i)); + // (address member, uint256 pk) = makeAddrAndKey(name); + // _committee[i] = member; + // pks[i] = pk; + // // 1 member with 2500 stake + // if (i == 55) { + // _stake[i] = 2500; + // // 50 members with 100 stake (total: 5000) + // } else if (i < 50) { + // _stake[i] = 100; + // // 5 members with 500 stake (total: 2500) + // } else { + // _stake[i] = 500; + // } + // } + // committee = new BridgeCommittee(); + // committee.initialize(address(config), _committee, _stake, minStakeRequired); + // uint256[] memory tokenPrices = new uint256[](4); + // tokenPrices[0] = 10000; // IOTA PRICE + // tokenPrices[1] = 10000; // BTC PRICE + // tokenPrices[2] = 10000; // ETH PRICE + // tokenPrices[3] = 10000; // USDC PRICE + // uint64[] memory totalLimits = new uint64[](1); + // totalLimits[0] = 1000000; + // skip(2 days); + // IotaBridge _bridge = new IotaBridge(); + // _bridge.initialize(address(committee), address(vault), address(limiter), wETH); + // changePrank(address(bridge)); + // limiter.transferOwnership(address(_bridge)); + // vault.transferOwnership(address(_bridge)); + // bridge = _bridge; + + // // Fill vault with WETH + // changePrank(deployer); + // IWETH9(wETH).deposit{value: 10 ether}(); + // IERC20(wETH).transfer(address(vault), 10 ether); + + // // transfer bridged tokens with 26 signatures + + // // Create transfer payload + // uint8 senderAddressLength = 32; + // bytes memory senderAddress = abi.encode(0); + // uint8 targetChain = chainID; + // uint8 recipientAddressLength = 20; + // address recipientAddress = bridgerA; + // uint8 tokenID = BridgeMessage.ETH; + // uint64 amount = 100000000; // 1 ether in iota decimals + // bytes memory payload = abi.encodePacked( + // senderAddressLength, + // senderAddress, + // targetChain, + // recipientAddressLength, + // recipientAddress, + // tokenID, + // amount + // ); + + // // Create transfer message + // BridgeMessage.Message memory message = BridgeMessage.Message({ + // messageType: BridgeMessage.TOKEN_TRANSFER, + // version: 1, + // nonce: 2, + // chainID: 0, + // payload: payload + // }); + + // bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + + // bytes32 messageHash = keccak256(encodedMessage); + + // bytes[] memory signatures = new bytes[](25); + + // uint256 index = 0; + // // add 5 committee members with 100 stake + // for (uint256 i = 50; i < 55; i++) { + // signatures[index++] = getSignature(messageHash, pks[i]); + // } + // // add last committee member with 2500 stake + // signatures[5] = getSignature(messageHash, pks[55]); + + // // add 20 committee members with 100 stake + // for (uint256 i = 0; i < 20; i++) { + // signatures[index++] = getSignature(messageHash, pks[i]); + // } + + // bridge.transferBridgedTokensWithSignatures(signatures, message); + // } + + // function testTransferBridgedTokensWith56Signatures() public { + // // define committee with 50 members + // address[] memory _committee = new address[](56); + // uint256[] memory pks = new uint256[](56); + // uint16[] memory _stake = new uint16[](56); + // for (uint256 i = 0; i < 56; i++) { + // string memory name = string(abi.encodePacked("committeeMember", i)); + // (address member, uint256 pk) = makeAddrAndKey(name); + // _committee[i] = member; + // pks[i] = pk; + // // 1 member with 2500 stake + // if (i == 55) { + // _stake[i] = 2500; + // // 50 members with 100 stake (total: 5000) + // } else if (i < 50) { + // _stake[i] = 100; + // // 5 members with 500 stake (total: 2500) + // } else { + // _stake[i] = 500; + // } + // } + // committee = new BridgeCommittee(); + // committee.initialize(address(config), _committee, _stake, minStakeRequired); + // uint256[] memory tokenPrices = new uint256[](4); + // tokenPrices[0] = 10000; // IOTA PRICE + // tokenPrices[1] = 10000; // BTC PRICE + // tokenPrices[2] = 10000; // ETH PRICE + // tokenPrices[3] = 10000; // USDC PRICE + // uint64[] memory totalLimits = new uint64[](1); + // totalLimits[0] = 1000000; + // skip(2 days); + // IotaBridge _bridge = new IotaBridge(); + // _bridge.initialize(address(committee), address(vault), address(limiter), wETH); + // changePrank(address(bridge)); + // limiter.transferOwnership(address(_bridge)); + // vault.transferOwnership(address(_bridge)); + // bridge = _bridge; + + // // Fill vault with WETH + // changePrank(deployer); + // IWETH9(wETH).deposit{value: 10 ether}(); + // IERC20(wETH).transfer(address(vault), 10 ether); + + // // transfer bridged tokens with 56 signatures + + // // Create transfer payload + // uint8 senderAddressLength = 32; + // bytes memory senderAddress = abi.encode(0); + // uint8 targetChain = chainID; + // uint8 recipientAddressLength = 20; + // address recipientAddress = bridgerA; + // uint8 tokenID = BridgeMessage.ETH; + // uint64 amount = 100000000; // 1 ether in iota decimals + // bytes memory payload = abi.encodePacked( + // senderAddressLength, + // senderAddress, + // targetChain, + // recipientAddressLength, + // recipientAddress, + // tokenID, + // amount + // ); + + // // Create transfer message + // BridgeMessage.Message memory message = BridgeMessage.Message({ + // messageType: BridgeMessage.TOKEN_TRANSFER, + // version: 1, + // nonce: 3, + // chainID: 0, + // payload: payload + // }); + + // bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + + // bytes32 messageHash = keccak256(encodedMessage); + + // bytes[] memory signatures = new bytes[](56); + + // // get all signatures + // for (uint256 i = 0; i < 56; i++) { + // signatures[i] = getSignature(messageHash, pks[i]); + // } + + // bridge.transferBridgedTokensWithSignatures(signatures, message); + // } + + // An e2e token transfer regression test covering message ser/de and signature verification + function testTransferIotaToEthRegressionTest() public { + address[] memory _committee = new address[](4); + uint16[] memory _stake = new uint16[](4); + _committee[0] = 0x68B43fD906C0B8F024a18C56e06744F7c6157c65; + _committee[1] = 0xaCAEf39832CB995c4E049437A3E2eC6a7bad1Ab5; + _committee[2] = 0x8061f127910e8eF56F16a2C411220BaD25D61444; + _committee[3] = 0x508F3F1ff45F4ca3D8e86CDCC91445F00aCC59fC; + _stake[0] = 2500; + _stake[1] = 2500; + _stake[2] = 2500; + _stake[3] = 2500; + committee = new BridgeCommittee(); + + // deploy bridge config with 11 chainID + address[] memory _supportedTokens = new address[](4); + _supportedTokens[0] = wBTC; + _supportedTokens[1] = wETH; + _supportedTokens[2] = USDC; + _supportedTokens[3] = USDT; + uint8 supportedChainID = 1; + uint8[] memory _supportedDestinationChains = new uint8[](1); + _supportedDestinationChains[0] = 1; + BridgeConfig _config = new BridgeConfig(11, _supportedTokens, _supportedDestinationChains); + + committee.initialize(address(_config), _committee, _stake, minStakeRequired); + vault = new BridgeVault(wETH); + uint256[] memory tokenPrices = new uint256[](4); + tokenPrices[0] = 10000; // IOTA PRICE + tokenPrices[1] = 10000; // BTC PRICE + tokenPrices[2] = 10000; // ETH PRICE + tokenPrices[3] = 10000; // USDC PRICE + uint64[] memory totalLimits = new uint64[](1); + totalLimits[0] = 1000000; + + skip(2 days); + limiter = new BridgeLimiter(); + limiter.initialize( + address(committee), tokenPrices, _supportedDestinationChains, totalLimits + ); + bridge = new IotaBridge(); + bridge.initialize(address(committee), address(vault), address(limiter), wETH); + vault.transferOwnership(address(bridge)); + limiter.transferOwnership(address(bridge)); + + // Fill vault with WETH + changePrank(deployer); + IWETH9(wETH).deposit{value: 10 ether}(); + IERC20(wETH).transfer(address(vault), 10 ether); + address recipientAddress = 0xb18f79Fe671db47393315fFDB377Da4Ea1B7AF96; + + bytes memory payload = + hex"2080ab1ee086210a3a37355300ca24672e81062fcdb5ced6618dab203f6a3b291c0b14b18f79fe671db47393315ffdb377da4ea1b7af960200000000000186a0"; + // Create transfer message + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.TOKEN_TRANSFER, + version: 1, + nonce: 1, + chainID: supportedChainID, + payload: payload + }); + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes memory expectedEncodedMessage = + hex"5355495f4252494447455f4d45535341474500010000000000000001012080ab1ee086210a3a37355300ca24672e81062fcdb5ced6618dab203f6a3b291c0b14b18f79fe671db47393315ffdb377da4ea1b7af960200000000000186a0"; + + assertEq(encodedMessage, expectedEncodedMessage); + + bytes[] memory signatures = new bytes[](2); + + signatures[0] = + hex"e1cf11b380855ff1d4a451ebc2fd68477cf701b7d4ec88da3082709fe95201a5061b4b60cf13815a80ba9dfead23e220506aa74c4a863ba045d95715b4cc6b6e00"; + signatures[1] = + hex"8ba9ec92c2d5a44ecc123182f689b901a93921fd35f581354fea20b25a0ded6d055b96a64bdda77dd5a62b93d29abe93640aa3c1a136348093cd7a2418c6bfa301"; + + uint256 aBalance = recipientAddress.balance; + committee.verifySignatures(signatures, message); + + bridge.transferBridgedTokensWithSignatures(signatures, message); + assertEq(recipientAddress.balance, aBalance + 0.001 ether); + } + + // An e2e emergency op regression test covering message ser/de + function testEmergencyOpRegressionTest() public { + address[] memory _committee = new address[](4); + uint16[] memory _stake = new uint16[](4); + _committee[0] = 0x68B43fD906C0B8F024a18C56e06744F7c6157c65; + _committee[1] = 0xaCAEf39832CB995c4E049437A3E2eC6a7bad1Ab5; + _committee[2] = 0x8061f127910e8eF56F16a2C411220BaD25D61444; + _committee[3] = 0x508F3F1ff45F4ca3D8e86CDCC91445F00aCC59fC; + _stake[0] = 2500; + _stake[1] = 2500; + _stake[2] = 2500; + _stake[3] = 2500; + uint8 _chainID = 3; + uint8[] memory _supportedDestinationChains = new uint8[](1); + _supportedDestinationChains[0] = 0; + address[] memory _supportedTokens = new address[](4); + _supportedTokens[0] = wBTC; + _supportedTokens[1] = wETH; + _supportedTokens[2] = USDC; + _supportedTokens[3] = USDT; + config = new BridgeConfig(_chainID, _supportedTokens, _supportedDestinationChains); + committee = new BridgeCommittee(); + committee.initialize(address(config), _committee, _stake, minStakeRequired); + vault = new BridgeVault(wETH); + uint256[] memory tokenPrices = new uint256[](4); + tokenPrices[0] = 10000; // IOTA PRICE + tokenPrices[1] = 10000; // BTC PRICE + tokenPrices[2] = 10000; // ETH PRICE + tokenPrices[3] = 10000; // USDC PRICE + uint64[] memory totalLimits = new uint64[](1); + totalLimits[0] = 1000000; + skip(2 days); + limiter = new BridgeLimiter(); + limiter.initialize( + address(committee), tokenPrices, _supportedDestinationChains, totalLimits + ); + bridge = new IotaBridge(); + bridge.initialize(address(committee), address(vault), address(limiter), wETH); + + bytes memory payload = hex"00"; + // Create emergency op message + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.EMERGENCY_OP, + version: 1, + nonce: 55, + chainID: _chainID, + payload: payload + }); + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes memory expectedEncodedMessage = + hex"5355495f4252494447455f4d455353414745020100000000000000370300"; + + assertEq(encodedMessage, expectedEncodedMessage); + } + + // An e2e emergency op regression test covering message ser/de and signature verification + function testEmergencyOpRegressionTestWithSigVerification() public { + address[] memory _committee = new address[](4); + uint16[] memory _stake = new uint16[](4); + uint8 chainID = 11; + _committee[0] = 0x68B43fD906C0B8F024a18C56e06744F7c6157c65; + _committee[1] = 0xaCAEf39832CB995c4E049437A3E2eC6a7bad1Ab5; + _committee[2] = 0x8061f127910e8eF56F16a2C411220BaD25D61444; + _committee[3] = 0x508F3F1ff45F4ca3D8e86CDCC91445F00aCC59fC; + _stake[0] = 2500; + _stake[1] = 2500; + _stake[2] = 2500; + _stake[3] = 2500; + config = new BridgeConfig(chainID, supportedTokens, supportedChains); + committee = new BridgeCommittee(); + committee.initialize(address(config), _committee, _stake, minStakeRequired); + vault = new BridgeVault(wETH); + + uint64[] memory totalLimits = new uint64[](1); + totalLimits[0] = 1000000; + + skip(2 days); + limiter = new BridgeLimiter(); + limiter.initialize( + address(committee), tokenPrices, supportedChains, totalLimits + ); + bridge = new IotaBridge(); + bridge.initialize(address(committee), address(vault), address(limiter), wETH); + + assertFalse(bridge.paused()); + + // pause + bytes memory payload = hex"00"; + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.EMERGENCY_OP, + version: 1, + nonce: 0, + chainID: chainID, + payload: payload + }); + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes memory expectedEncodedMessage = + hex"5355495f4252494447455f4d455353414745020100000000000000000b00"; + + assertEq(encodedMessage, expectedEncodedMessage); + + bytes[] memory signatures = new bytes[](1); + + signatures[0] = + hex"859db4dff22e43821b9b451e88bc7489aec3381d3e4fb5d8cbf025a84d34964a2bd556e0a86e13cb5b2d0fa52f08d02e4b62b9e6d9e07d8f8451d4c19430806d01"; + + bridge.executeEmergencyOpWithSignatures(signatures, message); + assertTrue(bridge.paused()); + + // unpause + payload = hex"01"; + message = BridgeMessage.Message({ + messageType: BridgeMessage.EMERGENCY_OP, + version: 1, + nonce: 1, + chainID: chainID, + payload: payload + }); + encodedMessage = BridgeMessage.encodeMessage(message); + expectedEncodedMessage = + hex"5355495f4252494447455f4d455353414745020100000000000000010b01"; + + assertEq(encodedMessage, expectedEncodedMessage); + + bytes[] memory signatures2 = new bytes[](3); + + signatures2[0] = + hex"de5ca964c5aa1aa323cc480cd6de46eae980a1670a5fe8e12e31f724d0bcec6516e54b516737bb6ed6ccad775370c14d46f2e10100e9d16851d2050bf2349c6401"; + signatures2[1] = + hex"fe8006e2013eaa7b8af0e5ac9f2890c2b2bd375d343684b2604ac6acd4142ccf5c9ec1914bce53a005232ef880bf0f597eed319d41d80e92d035c8314e1198ff00"; + signatures2[2] = + hex"f5749ac37e11f22da0622082c9e63a91dc7b5c59cfdaa86438d9f6a53bbacf6b763126f1a20a826d7dff73252cf2fd68da67b9caec4d3c24a07fbd566a7a6bec00"; + + bridge.executeEmergencyOpWithSignatures(signatures2, message); + assertFalse(bridge.paused()); + + // reusing the sig from nonce 0 will revert + payload = hex"00"; + message = BridgeMessage.Message({ + messageType: BridgeMessage.EMERGENCY_OP, + version: 1, + nonce: 0, + chainID: chainID, + payload: payload + }); + + signatures = new bytes[](1); + + signatures[0] = + hex"859db4dff22e43821b9b451e88bc7489aec3381d3e4fb5d8cbf025a84d34964a2bd556e0a86e13cb5b2d0fa52f08d02e4b62b9e6d9e07d8f8451d4c19430806d01"; + + vm.expectRevert(bytes("MessageVerifier: Invalid nonce")); + bridge.executeEmergencyOpWithSignatures(signatures, message); + + assertFalse(bridge.paused()); + } + + // An e2e upgrade regression test covering message ser/de and signature verification + function testUpgradeRegressionTest() public { + address[] memory _committee = new address[](4); + uint16[] memory _stake = new uint16[](4); + _committee[0] = 0x68B43fD906C0B8F024a18C56e06744F7c6157c65; + _committee[1] = 0xaCAEf39832CB995c4E049437A3E2eC6a7bad1Ab5; + _committee[2] = 0x8061f127910e8eF56F16a2C411220BaD25D61444; + _committee[3] = 0x508F3F1ff45F4ca3D8e86CDCC91445F00aCC59fC; + _stake[0] = 2500; + _stake[1] = 2500; + _stake[2] = 2500; + _stake[3] = 2500; + committee = new BridgeCommittee(); + + uint8 _chainID = 12; + uint8[] memory _supportedDestinationChains = new uint8[](1); + _supportedDestinationChains[0] = 0; + address[] memory _supportedTokens = new address[](4); + _supportedTokens[0] = wBTC; + _supportedTokens[1] = wETH; + _supportedTokens[2] = USDC; + _supportedTokens[3] = USDT; + config = new BridgeConfig(_chainID, _supportedTokens, _supportedDestinationChains); + + committee.initialize(address(config), _committee, _stake, minStakeRequired); + vault = new BridgeVault(wETH); + uint256[] memory tokenPrices = new uint256[](4); + tokenPrices[0] = 10000; // IOTA PRICE + tokenPrices[1] = 10000; // BTC PRICE + tokenPrices[2] = 10000; // ETH PRICE + tokenPrices[3] = 10000; // USDC PRICE + skip(2 days); + uint64[] memory totalLimits = new uint64[](1); + totalLimits[0] = 1000000; + limiter = new BridgeLimiter(); + limiter.initialize( + address(committee), tokenPrices, _supportedDestinationChains, totalLimits + ); + bridge = new IotaBridge(); + bridge.initialize(address(committee), address(vault), address(limiter), wETH); + vault.transferOwnership(address(bridge)); + limiter.transferOwnership(address(bridge)); + + // Fill vault with WETH + changePrank(deployer); + IWETH9(wETH).deposit{value: 10 ether}(); + IERC20(wETH).transfer(address(vault), 10 ether); + + bytes memory payload = + hex"00000000000000000000000006060606060606060606060606060606060606060000000000000000000000000909090909090909090909090909090909090909000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000045cd8a76b00000000000000000000000000000000000000000000000000000000"; + // Create transfer message + BridgeMessage.Message memory message = BridgeMessage.Message({ + messageType: BridgeMessage.UPGRADE, + version: 1, + nonce: 123, + chainID: _chainID, + payload: payload + }); + bytes memory encodedMessage = BridgeMessage.encodeMessage(message); + bytes memory expectedEncodedMessage = + hex"5355495f4252494447455f4d4553534147450501000000000000007b0c00000000000000000000000006060606060606060606060606060606060606060000000000000000000000000909090909090909090909090909090909090909000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000045cd8a76b00000000000000000000000000000000000000000000000000000000"; + + assertEq(encodedMessage, expectedEncodedMessage); + + (address proxy, address newImp, bytes memory _calldata) = + BridgeMessage.decodeUpgradePayload(payload); + + assertEq(proxy, address(0x0606060606060606060606060606060606060606)); + assertEq(newImp, address(0x0909090909090909090909090909090909090909)); + assertEq(_calldata, hex"5cd8a76b"); + } +} diff --git a/bridge/evm/test/SuiBridgeTest.t.sol b/bridge/evm/test/SuiBridgeTest.t.sol deleted file mode 100644 index b55350ece05..00000000000 --- a/bridge/evm/test/SuiBridgeTest.t.sol +++ /dev/null @@ -1,1044 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import "./BridgeBaseTest.t.sol"; -import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import "../contracts/interfaces/ISuiBridge.sol"; -import "./mocks/MockSuiBridgeV2.sol"; - -contract SuiBridgeTest is BridgeBaseTest, ISuiBridge { - // This function is called before each unit test - function setUp() public { - setUpBridgeTest(); - } - - function testSuiBridgeInitialization() public { - assertEq(address(bridge.committee()), address(committee)); - assertEq(address(bridge.vault()), address(vault)); - assertEq(address(bridge.wETH()), wETH); - } - - function testTransferBridgedTokensWithSignaturesTokenDailyLimitExceeded() public { - uint8 senderAddressLength = 32; - bytes memory senderAddress = abi.encode(0); - uint8 targetChain = chainID; - uint8 recipientAddressLength = 20; - address recipientAddress = bridgerA; - uint8 tokenID = BridgeMessage.ETH; - uint64 amount = 100000000000000; - bytes memory payload = abi.encodePacked( - senderAddressLength, - senderAddress, - targetChain, - recipientAddressLength, - recipientAddress, - tokenID, - amount - ); - - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.TOKEN_TRANSFER, - version: 1, - nonce: 1, - chainID: 0, - payload: payload - }); - - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes32 messageHash = keccak256(encodedMessage); - - bytes[] memory signatures = new bytes[](4); - signatures[0] = getSignature(messageHash, committeeMemberPkA); - signatures[1] = getSignature(messageHash, committeeMemberPkB); - signatures[2] = getSignature(messageHash, committeeMemberPkC); - signatures[3] = getSignature(messageHash, committeeMemberPkD); - vm.expectRevert(bytes("SuiBridge: Amount exceeds bridge limit")); - bridge.transferBridgedTokensWithSignatures(signatures, message); - } - - function testTransferBridgedTokensWithSignaturesInvalidTargetChain() public { - uint8 senderAddressLength = 32; - bytes memory senderAddress = abi.encode(0); - uint8 targetChain = 0; - uint8 recipientAddressLength = 20; - address recipientAddress = bridgerA; - uint8 tokenID = BridgeMessage.ETH; - uint64 amount = 10000; - bytes memory payload = abi.encodePacked( - senderAddressLength, - senderAddress, - targetChain, - recipientAddressLength, - recipientAddress, - tokenID, - amount - ); - - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.TOKEN_TRANSFER, - version: 1, - nonce: 1, - chainID: 1, - payload: payload - }); - - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes32 messageHash = keccak256(encodedMessage); - - bytes[] memory signatures = new bytes[](4); - signatures[0] = getSignature(messageHash, committeeMemberPkA); - signatures[1] = getSignature(messageHash, committeeMemberPkB); - signatures[2] = getSignature(messageHash, committeeMemberPkC); - signatures[3] = getSignature(messageHash, committeeMemberPkD); - vm.expectRevert(bytes("SuiBridge: Target chain not supported")); - bridge.transferBridgedTokensWithSignatures(signatures, message); - } - - function testTransferBridgedTokensWithSignaturesInsufficientStakeAmount() public { - // Create transfer message - BridgeMessage.TokenTransferPayload memory payload = BridgeMessage.TokenTransferPayload({ - senderAddressLength: 0, - senderAddress: abi.encode(0), - targetChain: 1, - recipientAddressLength: 0, - recipientAddress: bridgerA, - tokenID: BridgeMessage.ETH, - // This is Sui amount (eth decimal 8) - amount: 100_000_000 - }); - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.TOKEN_TRANSFER, - version: 1, - nonce: 1, - chainID: chainID, - payload: abi.encode(payload) - }); - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes32 messageHash = keccak256(encodedMessage); - bytes[] memory signatures = new bytes[](2); - signatures[0] = getSignature(messageHash, committeeMemberPkA); - signatures[1] = getSignature(messageHash, committeeMemberPkB); - vm.expectRevert(bytes("BridgeCommittee: Insufficient stake amount")); - bridge.transferBridgedTokensWithSignatures(signatures, message); - } - - function testTransferBridgedTokensWithSignaturesMessageDoesNotMatchType() public { - // Create transfer message - BridgeMessage.TokenTransferPayload memory payload = BridgeMessage.TokenTransferPayload({ - senderAddressLength: 0, - senderAddress: abi.encode(0), - targetChain: 1, - recipientAddressLength: 0, - recipientAddress: bridgerA, - tokenID: BridgeMessage.ETH, - // This is Sui amount (eth decimal 8) - amount: 100_000_000 - }); - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.EMERGENCY_OP, - version: 1, - nonce: 1, - chainID: chainID, - payload: abi.encode(payload) - }); - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes32 messageHash = keccak256(encodedMessage); - bytes[] memory signatures = new bytes[](2); - signatures[0] = getSignature(messageHash, committeeMemberPkA); - signatures[1] = getSignature(messageHash, committeeMemberPkB); - vm.expectRevert(bytes("MessageVerifier: message does not match type")); - bridge.transferBridgedTokensWithSignatures(signatures, message); - } - - function testTransferWETHWithValidSignatures() public { - // Fill vault with WETH - changePrank(deployer); - IWETH9(wETH).deposit{value: 10 ether}(); - // IWETH9(wETH).withdraw(1 ether); - IERC20(wETH).transfer(address(vault), 10 ether); - // Create transfer payload - uint8 senderAddressLength = 32; - bytes memory senderAddress = abi.encode(0); - uint8 targetChain = chainID; - uint8 recipientAddressLength = 20; - address recipientAddress = bridgerA; - uint8 tokenID = BridgeMessage.ETH; - uint64 amount = 100000000; // 1 ether in sui decimals - bytes memory payload = abi.encodePacked( - senderAddressLength, - senderAddress, - targetChain, - recipientAddressLength, - recipientAddress, - tokenID, - amount - ); - - // Create transfer message - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.TOKEN_TRANSFER, - version: 1, - nonce: 1, - chainID: 0, - payload: payload - }); - - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - - bytes32 messageHash = keccak256(encodedMessage); - - bytes[] memory signatures = new bytes[](4); - - signatures[0] = getSignature(messageHash, committeeMemberPkA); - signatures[1] = getSignature(messageHash, committeeMemberPkB); - signatures[2] = getSignature(messageHash, committeeMemberPkC); - signatures[3] = getSignature(messageHash, committeeMemberPkD); - - uint256 aBalance = bridgerA.balance; - bridge.transferBridgedTokensWithSignatures(signatures, message); - assertEq(bridgerA.balance, aBalance + 1 ether); - - vm.expectRevert(bytes("SuiBridge: Message already processed")); - bridge.transferBridgedTokensWithSignatures(signatures, message); - } - - function testTransferUSDCWithValidSignatures() public { - // Fill vault with USDC - changePrank(USDCWhale); - IERC20(USDC).transfer(address(vault), 100_000_000); - changePrank(deployer); - - // Create transfer payload - uint8 senderAddressLength = 32; - bytes memory senderAddress = abi.encode(0); - uint8 targetChain = chainID; - uint8 recipientAddressLength = 20; - address recipientAddress = bridgerA; - uint8 tokenID = BridgeMessage.USDC; - uint64 amount = 1_000_000; - bytes memory payload = abi.encodePacked( - senderAddressLength, - senderAddress, - targetChain, - recipientAddressLength, - recipientAddress, - tokenID, - amount - ); - - // Create transfer message - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.TOKEN_TRANSFER, - version: 1, - nonce: 1, - chainID: 0, - payload: payload - }); - - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes32 messageHash = keccak256(encodedMessage); - - bytes[] memory signatures = new bytes[](4); - - signatures[0] = getSignature(messageHash, committeeMemberPkA); - signatures[1] = getSignature(messageHash, committeeMemberPkB); - signatures[2] = getSignature(messageHash, committeeMemberPkC); - signatures[3] = getSignature(messageHash, committeeMemberPkD); - - assert(IERC20(USDC).balanceOf(bridgerA) == 0); - bridge.transferBridgedTokensWithSignatures(signatures, message); - assert(IERC20(USDC).balanceOf(bridgerA) == 1_000_000); - } - - function testExecuteEmergencyOpWithSignaturesInvalidOpCode() public { - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.EMERGENCY_OP, - version: 1, - nonce: 0, - chainID: chainID, - payload: hex"02" - }); - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes32 messageHash = keccak256(encodedMessage); - bytes[] memory signatures = new bytes[](4); - signatures[0] = getSignature(messageHash, committeeMemberPkA); - signatures[1] = getSignature(messageHash, committeeMemberPkB); - signatures[2] = getSignature(messageHash, committeeMemberPkC); - signatures[3] = getSignature(messageHash, committeeMemberPkD); - vm.expectRevert(bytes("BridgeMessage: Invalid op code")); - bridge.executeEmergencyOpWithSignatures(signatures, message); - } - - function testExecuteEmergencyOpWithSignaturesInvalidNonce() public { - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.EMERGENCY_OP, - version: 1, - nonce: 1, - chainID: chainID, - payload: bytes(hex"00") - }); - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes32 messageHash = keccak256(encodedMessage); - bytes[] memory signatures = new bytes[](4); - signatures[0] = getSignature(messageHash, committeeMemberPkA); - signatures[1] = getSignature(messageHash, committeeMemberPkB); - signatures[2] = getSignature(messageHash, committeeMemberPkC); - signatures[3] = getSignature(messageHash, committeeMemberPkD); - vm.expectRevert(bytes("MessageVerifier: Invalid nonce")); - bridge.executeEmergencyOpWithSignatures(signatures, message); - } - - function testExecuteEmergencyOpWithSignaturesMessageDoesNotMatchType() public { - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.TOKEN_TRANSFER, - version: 1, - nonce: 0, - chainID: chainID, - payload: abi.encode(0) - }); - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes32 messageHash = keccak256(encodedMessage); - bytes[] memory signatures = new bytes[](4); - signatures[0] = getSignature(messageHash, committeeMemberPkA); - signatures[1] = getSignature(messageHash, committeeMemberPkB); - signatures[2] = getSignature(messageHash, committeeMemberPkC); - signatures[3] = getSignature(messageHash, committeeMemberPkD); - vm.expectRevert(bytes("MessageVerifier: message does not match type")); - bridge.executeEmergencyOpWithSignatures(signatures, message); - } - - function testExecuteEmergencyOpWithSignaturesInvalidSignatures() public { - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.EMERGENCY_OP, - version: 1, - nonce: 0, - chainID: chainID, - payload: bytes(hex"01") - }); - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes32 messageHash = keccak256(encodedMessage); - bytes[] memory signatures = new bytes[](2); - signatures[0] = getSignature(messageHash, committeeMemberPkA); - signatures[1] = getSignature(messageHash, committeeMemberPkB); - vm.expectRevert(bytes("BridgeCommittee: Insufficient stake amount")); - bridge.executeEmergencyOpWithSignatures(signatures, message); - } - - function testFreezeBridgeEmergencyOp() public { - // Create emergency op message - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.EMERGENCY_OP, - version: 1, - nonce: 0, - chainID: chainID, - payload: bytes(hex"00") - }); - - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes32 messageHash = keccak256(encodedMessage); - - bytes[] memory signatures = new bytes[](4); - - signatures[0] = getSignature(messageHash, committeeMemberPkA); - signatures[1] = getSignature(messageHash, committeeMemberPkB); - signatures[2] = getSignature(messageHash, committeeMemberPkC); - signatures[3] = getSignature(messageHash, committeeMemberPkD); - - assertFalse(bridge.paused()); - bridge.executeEmergencyOpWithSignatures(signatures, message); - assertTrue(bridge.paused()); - } - - function testUnfreezeBridgeEmergencyOp() public { - testFreezeBridgeEmergencyOp(); - // Create emergency op message - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.EMERGENCY_OP, - version: 1, - nonce: 1, - chainID: chainID, - payload: bytes(hex"01") - }); - - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes32 messageHash = keccak256(encodedMessage); - - bytes[] memory signatures = new bytes[](4); - - signatures[0] = getSignature(messageHash, committeeMemberPkA); - signatures[1] = getSignature(messageHash, committeeMemberPkB); - signatures[2] = getSignature(messageHash, committeeMemberPkC); - signatures[3] = getSignature(messageHash, committeeMemberPkD); - - bridge.executeEmergencyOpWithSignatures(signatures, message); - assertFalse(bridge.paused()); - } - - function testBridgeERC20UnsupportedToken() public { - vm.expectRevert(bytes("SuiBridge: Unsupported token")); - bridge.bridgeERC20(255, 1 ether, abi.encode("suiAddress"), 0); - } - - function testBridgeERC20InsufficientAllowance() public { - vm.expectRevert(bytes("SuiBridge: Insufficient allowance")); - bridge.bridgeERC20(BridgeMessage.ETH, type(uint256).max, abi.encode("suiAddress"), 0); - } - - function testBridgeWETH() public { - changePrank(deployer); - IWETH9(wETH).deposit{value: 10 ether}(); - IERC20(wETH).approve(address(bridge), 10 ether); - assertEq(IERC20(wETH).balanceOf(address(vault)), 0); - uint256 balance = IERC20(wETH).balanceOf(deployer); - - // assert emitted event - vm.expectEmit(true, true, true, false); - emit TokensDeposited( - chainID, - 0, // nonce - 0, // destination chain id - BridgeMessage.ETH, - 1_00_000_000, // 1 ether - deployer, - abi.encode("suiAddress") - ); - - bridge.bridgeERC20(BridgeMessage.ETH, 1 ether, abi.encode("suiAddress"), 0); - assertEq(IERC20(wETH).balanceOf(address(vault)), 1 ether); - assertEq(IERC20(wETH).balanceOf(deployer), balance - 1 ether); - assertEq(bridge.nonces(BridgeMessage.TOKEN_TRANSFER), 1); - - // Now test rounding. For ETH, the last 10 digits are rounded - vm.expectEmit(true, true, true, false); - emit TokensDeposited( - chainID, - 1, // nonce - 0, // destination chain id - BridgeMessage.ETH, - 2.00000001 ether, - deployer, - abi.encode("suiAddress") - ); - // 2_000_000_011_000_000_888 is rounded to 2.00000001 eth - bridge.bridgeERC20( - BridgeMessage.ETH, 2_000_000_011_000_000_888, abi.encode("suiAddress"), 0 - ); - assertEq(IERC20(wETH).balanceOf(address(vault)), 3_000_000_011_000_000_888); - assertEq(IERC20(wETH).balanceOf(deployer), balance - 3_000_000_011_000_000_888); - assertEq(bridge.nonces(BridgeMessage.TOKEN_TRANSFER), 2); - } - - function testBridgeUSDC() public { - // TODO test and make sure adjusted amount in event is correct - } - - function testBridgeUSDT() public { - // TODO test and make sure adjusted amount in event is correct - } - - function testBridgeBTC() public { - // TODO test and make sure adjusted amount in event is correct - } - - function testBridgeEth() public { - changePrank(deployer); - assertEq(IERC20(wETH).balanceOf(address(vault)), 0); - uint256 balance = deployer.balance; - - // assert emitted event - vm.expectEmit(true, true, true, false); - emit ISuiBridge.TokensDeposited( - chainID, - 0, // nonce - 0, // destination chain id - BridgeMessage.ETH, - 1_000_000_00, // 1 ether - deployer, - abi.encode("suiAddress") - ); - - bridge.bridgeETH{value: 1 ether}(abi.encode("suiAddress"), 0); - assertEq(IERC20(wETH).balanceOf(address(vault)), 1 ether); - assertEq(deployer.balance, balance - 1 ether); - assertEq(bridge.nonces(BridgeMessage.TOKEN_TRANSFER), 1); - } - - // TESTS FOR GAS MEASUREMENT - - // function testTransferBridgedTokensWith7Signatures() public { - // // define committee with 50 members - // address[] memory _committee = new address[](56); - // uint256[] memory pks = new uint256[](56); - // uint16[] memory _stake = new uint16[](56); - // for (uint256 i = 0; i < 56; i++) { - // string memory name = string(abi.encodePacked("committeeMember", i)); - // (address member, uint256 pk) = makeAddrAndKey(name); - // _committee[i] = member; - // pks[i] = pk; - // // 1 member with 2500 stake - // if (i == 55) { - // _stake[i] = 2500; - // // 50 members with 100 stake (total: 5000) - // } else if (i < 50) { - // _stake[i] = 100; - // // 5 members with 500 stake (total: 2500) - // } else { - // _stake[i] = 500; - // } - // } - // committee = new BridgeCommittee(); - // committee.initialize(address(config), _committee, _stake, minStakeRequired); - // uint256[] memory tokenPrices = new uint256[](4); - // tokenPrices[0] = 10000; // SUI PRICE - // tokenPrices[1] = 10000; // BTC PRICE - // tokenPrices[2] = 10000; // ETH PRICE - // tokenPrices[3] = 10000; // USDC PRICE - // uint64[] memory totalLimits = new uint64[](1); - // totalLimits[0] = 1000000; - // skip(2 days); - // SuiBridge _bridge = new SuiBridge(); - // _bridge.initialize(address(committee), address(vault), address(limiter), wETH); - // changePrank(address(bridge)); - // limiter.transferOwnership(address(_bridge)); - // vault.transferOwnership(address(_bridge)); - // bridge = _bridge; - - // // Fill vault with WETH - // changePrank(deployer); - // IWETH9(wETH).deposit{value: 10 ether}(); - // IERC20(wETH).transfer(address(vault), 10 ether); - - // // transfer bridged tokens with 7 signatures - // // Create transfer payload - // uint8 senderAddressLength = 32; - // bytes memory senderAddress = abi.encode(0); - // uint8 targetChain = chainID; - // uint8 recipientAddressLength = 20; - // address recipientAddress = bridgerA; - // uint8 tokenID = BridgeMessage.ETH; - // uint64 amount = 100000000; // 1 ether in sui decimals - // bytes memory payload = abi.encodePacked( - // senderAddressLength, - // senderAddress, - // targetChain, - // recipientAddressLength, - // recipientAddress, - // tokenID, - // amount - // ); - - // // Create transfer message - // BridgeMessage.Message memory message = BridgeMessage.Message({ - // messageType: BridgeMessage.TOKEN_TRANSFER, - // version: 1, - // nonce: 1, - // chainID: 0, - // payload: payload - // }); - - // bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - - // bytes32 messageHash = keccak256(encodedMessage); - - // bytes[] memory signatures = new bytes[](7); - - // uint8 index; - // for (uint256 i = 50; i < 55; i++) { - // signatures[index++] = getSignature(messageHash, pks[i]); - // } - // signatures[5] = getSignature(messageHash, pks[55]); - // signatures[6] = getSignature(messageHash, pks[0]); - - // bridge.transferBridgedTokensWithSignatures(signatures, message); - // } - - // function testTransferBridgedTokensWith26Signatures() public { - // // define committee with 50 members - // address[] memory _committee = new address[](56); - // uint256[] memory pks = new uint256[](56); - // uint16[] memory _stake = new uint16[](56); - // for (uint256 i = 0; i < 56; i++) { - // string memory name = string(abi.encodePacked("committeeMember", i)); - // (address member, uint256 pk) = makeAddrAndKey(name); - // _committee[i] = member; - // pks[i] = pk; - // // 1 member with 2500 stake - // if (i == 55) { - // _stake[i] = 2500; - // // 50 members with 100 stake (total: 5000) - // } else if (i < 50) { - // _stake[i] = 100; - // // 5 members with 500 stake (total: 2500) - // } else { - // _stake[i] = 500; - // } - // } - // committee = new BridgeCommittee(); - // committee.initialize(address(config), _committee, _stake, minStakeRequired); - // uint256[] memory tokenPrices = new uint256[](4); - // tokenPrices[0] = 10000; // SUI PRICE - // tokenPrices[1] = 10000; // BTC PRICE - // tokenPrices[2] = 10000; // ETH PRICE - // tokenPrices[3] = 10000; // USDC PRICE - // uint64[] memory totalLimits = new uint64[](1); - // totalLimits[0] = 1000000; - // skip(2 days); - // SuiBridge _bridge = new SuiBridge(); - // _bridge.initialize(address(committee), address(vault), address(limiter), wETH); - // changePrank(address(bridge)); - // limiter.transferOwnership(address(_bridge)); - // vault.transferOwnership(address(_bridge)); - // bridge = _bridge; - - // // Fill vault with WETH - // changePrank(deployer); - // IWETH9(wETH).deposit{value: 10 ether}(); - // IERC20(wETH).transfer(address(vault), 10 ether); - - // // transfer bridged tokens with 26 signatures - - // // Create transfer payload - // uint8 senderAddressLength = 32; - // bytes memory senderAddress = abi.encode(0); - // uint8 targetChain = chainID; - // uint8 recipientAddressLength = 20; - // address recipientAddress = bridgerA; - // uint8 tokenID = BridgeMessage.ETH; - // uint64 amount = 100000000; // 1 ether in sui decimals - // bytes memory payload = abi.encodePacked( - // senderAddressLength, - // senderAddress, - // targetChain, - // recipientAddressLength, - // recipientAddress, - // tokenID, - // amount - // ); - - // // Create transfer message - // BridgeMessage.Message memory message = BridgeMessage.Message({ - // messageType: BridgeMessage.TOKEN_TRANSFER, - // version: 1, - // nonce: 2, - // chainID: 0, - // payload: payload - // }); - - // bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - - // bytes32 messageHash = keccak256(encodedMessage); - - // bytes[] memory signatures = new bytes[](25); - - // uint256 index = 0; - // // add 5 committee members with 100 stake - // for (uint256 i = 50; i < 55; i++) { - // signatures[index++] = getSignature(messageHash, pks[i]); - // } - // // add last committee member with 2500 stake - // signatures[5] = getSignature(messageHash, pks[55]); - - // // add 20 committee members with 100 stake - // for (uint256 i = 0; i < 20; i++) { - // signatures[index++] = getSignature(messageHash, pks[i]); - // } - - // bridge.transferBridgedTokensWithSignatures(signatures, message); - // } - - // function testTransferBridgedTokensWith56Signatures() public { - // // define committee with 50 members - // address[] memory _committee = new address[](56); - // uint256[] memory pks = new uint256[](56); - // uint16[] memory _stake = new uint16[](56); - // for (uint256 i = 0; i < 56; i++) { - // string memory name = string(abi.encodePacked("committeeMember", i)); - // (address member, uint256 pk) = makeAddrAndKey(name); - // _committee[i] = member; - // pks[i] = pk; - // // 1 member with 2500 stake - // if (i == 55) { - // _stake[i] = 2500; - // // 50 members with 100 stake (total: 5000) - // } else if (i < 50) { - // _stake[i] = 100; - // // 5 members with 500 stake (total: 2500) - // } else { - // _stake[i] = 500; - // } - // } - // committee = new BridgeCommittee(); - // committee.initialize(address(config), _committee, _stake, minStakeRequired); - // uint256[] memory tokenPrices = new uint256[](4); - // tokenPrices[0] = 10000; // SUI PRICE - // tokenPrices[1] = 10000; // BTC PRICE - // tokenPrices[2] = 10000; // ETH PRICE - // tokenPrices[3] = 10000; // USDC PRICE - // uint64[] memory totalLimits = new uint64[](1); - // totalLimits[0] = 1000000; - // skip(2 days); - // SuiBridge _bridge = new SuiBridge(); - // _bridge.initialize(address(committee), address(vault), address(limiter), wETH); - // changePrank(address(bridge)); - // limiter.transferOwnership(address(_bridge)); - // vault.transferOwnership(address(_bridge)); - // bridge = _bridge; - - // // Fill vault with WETH - // changePrank(deployer); - // IWETH9(wETH).deposit{value: 10 ether}(); - // IERC20(wETH).transfer(address(vault), 10 ether); - - // // transfer bridged tokens with 56 signatures - - // // Create transfer payload - // uint8 senderAddressLength = 32; - // bytes memory senderAddress = abi.encode(0); - // uint8 targetChain = chainID; - // uint8 recipientAddressLength = 20; - // address recipientAddress = bridgerA; - // uint8 tokenID = BridgeMessage.ETH; - // uint64 amount = 100000000; // 1 ether in sui decimals - // bytes memory payload = abi.encodePacked( - // senderAddressLength, - // senderAddress, - // targetChain, - // recipientAddressLength, - // recipientAddress, - // tokenID, - // amount - // ); - - // // Create transfer message - // BridgeMessage.Message memory message = BridgeMessage.Message({ - // messageType: BridgeMessage.TOKEN_TRANSFER, - // version: 1, - // nonce: 3, - // chainID: 0, - // payload: payload - // }); - - // bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - - // bytes32 messageHash = keccak256(encodedMessage); - - // bytes[] memory signatures = new bytes[](56); - - // // get all signatures - // for (uint256 i = 0; i < 56; i++) { - // signatures[i] = getSignature(messageHash, pks[i]); - // } - - // bridge.transferBridgedTokensWithSignatures(signatures, message); - // } - - // An e2e token transfer regression test covering message ser/de and signature verification - function testTransferSuiToEthRegressionTest() public { - address[] memory _committee = new address[](4); - uint16[] memory _stake = new uint16[](4); - _committee[0] = 0x68B43fD906C0B8F024a18C56e06744F7c6157c65; - _committee[1] = 0xaCAEf39832CB995c4E049437A3E2eC6a7bad1Ab5; - _committee[2] = 0x8061f127910e8eF56F16a2C411220BaD25D61444; - _committee[3] = 0x508F3F1ff45F4ca3D8e86CDCC91445F00aCC59fC; - _stake[0] = 2500; - _stake[1] = 2500; - _stake[2] = 2500; - _stake[3] = 2500; - committee = new BridgeCommittee(); - - // deploy bridge config with 11 chainID - address[] memory _supportedTokens = new address[](4); - _supportedTokens[0] = wBTC; - _supportedTokens[1] = wETH; - _supportedTokens[2] = USDC; - _supportedTokens[3] = USDT; - uint8 supportedChainID = 1; - uint8[] memory _supportedDestinationChains = new uint8[](1); - _supportedDestinationChains[0] = 1; - BridgeConfig _config = new BridgeConfig(11, _supportedTokens, _supportedDestinationChains); - - committee.initialize(address(_config), _committee, _stake, minStakeRequired); - vault = new BridgeVault(wETH); - uint256[] memory tokenPrices = new uint256[](4); - tokenPrices[0] = 10000; // SUI PRICE - tokenPrices[1] = 10000; // BTC PRICE - tokenPrices[2] = 10000; // ETH PRICE - tokenPrices[3] = 10000; // USDC PRICE - uint64[] memory totalLimits = new uint64[](1); - totalLimits[0] = 1000000; - - skip(2 days); - limiter = new BridgeLimiter(); - limiter.initialize( - address(committee), tokenPrices, _supportedDestinationChains, totalLimits - ); - bridge = new SuiBridge(); - bridge.initialize(address(committee), address(vault), address(limiter), wETH); - vault.transferOwnership(address(bridge)); - limiter.transferOwnership(address(bridge)); - - // Fill vault with WETH - changePrank(deployer); - IWETH9(wETH).deposit{value: 10 ether}(); - IERC20(wETH).transfer(address(vault), 10 ether); - address recipientAddress = 0xb18f79Fe671db47393315fFDB377Da4Ea1B7AF96; - - bytes memory payload = - hex"2080ab1ee086210a3a37355300ca24672e81062fcdb5ced6618dab203f6a3b291c0b14b18f79fe671db47393315ffdb377da4ea1b7af960200000000000186a0"; - // Create transfer message - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.TOKEN_TRANSFER, - version: 1, - nonce: 1, - chainID: supportedChainID, - payload: payload - }); - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes memory expectedEncodedMessage = - hex"5355495f4252494447455f4d45535341474500010000000000000001012080ab1ee086210a3a37355300ca24672e81062fcdb5ced6618dab203f6a3b291c0b14b18f79fe671db47393315ffdb377da4ea1b7af960200000000000186a0"; - - assertEq(encodedMessage, expectedEncodedMessage); - - bytes[] memory signatures = new bytes[](2); - - signatures[0] = - hex"e1cf11b380855ff1d4a451ebc2fd68477cf701b7d4ec88da3082709fe95201a5061b4b60cf13815a80ba9dfead23e220506aa74c4a863ba045d95715b4cc6b6e00"; - signatures[1] = - hex"8ba9ec92c2d5a44ecc123182f689b901a93921fd35f581354fea20b25a0ded6d055b96a64bdda77dd5a62b93d29abe93640aa3c1a136348093cd7a2418c6bfa301"; - - uint256 aBalance = recipientAddress.balance; - committee.verifySignatures(signatures, message); - - bridge.transferBridgedTokensWithSignatures(signatures, message); - assertEq(recipientAddress.balance, aBalance + 0.001 ether); - } - - // An e2e emergency op regression test covering message ser/de - function testEmergencyOpRegressionTest() public { - address[] memory _committee = new address[](4); - uint16[] memory _stake = new uint16[](4); - _committee[0] = 0x68B43fD906C0B8F024a18C56e06744F7c6157c65; - _committee[1] = 0xaCAEf39832CB995c4E049437A3E2eC6a7bad1Ab5; - _committee[2] = 0x8061f127910e8eF56F16a2C411220BaD25D61444; - _committee[3] = 0x508F3F1ff45F4ca3D8e86CDCC91445F00aCC59fC; - _stake[0] = 2500; - _stake[1] = 2500; - _stake[2] = 2500; - _stake[3] = 2500; - uint8 _chainID = 3; - uint8[] memory _supportedDestinationChains = new uint8[](1); - _supportedDestinationChains[0] = 0; - address[] memory _supportedTokens = new address[](4); - _supportedTokens[0] = wBTC; - _supportedTokens[1] = wETH; - _supportedTokens[2] = USDC; - _supportedTokens[3] = USDT; - config = new BridgeConfig(_chainID, _supportedTokens, _supportedDestinationChains); - committee = new BridgeCommittee(); - committee.initialize(address(config), _committee, _stake, minStakeRequired); - vault = new BridgeVault(wETH); - uint256[] memory tokenPrices = new uint256[](4); - tokenPrices[0] = 10000; // SUI PRICE - tokenPrices[1] = 10000; // BTC PRICE - tokenPrices[2] = 10000; // ETH PRICE - tokenPrices[3] = 10000; // USDC PRICE - uint64[] memory totalLimits = new uint64[](1); - totalLimits[0] = 1000000; - skip(2 days); - limiter = new BridgeLimiter(); - limiter.initialize( - address(committee), tokenPrices, _supportedDestinationChains, totalLimits - ); - bridge = new SuiBridge(); - bridge.initialize(address(committee), address(vault), address(limiter), wETH); - - bytes memory payload = hex"00"; - // Create emergency op message - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.EMERGENCY_OP, - version: 1, - nonce: 55, - chainID: _chainID, - payload: payload - }); - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes memory expectedEncodedMessage = - hex"5355495f4252494447455f4d455353414745020100000000000000370300"; - - assertEq(encodedMessage, expectedEncodedMessage); - } - - // An e2e emergency op regression test covering message ser/de and signature verification - function testEmergencyOpRegressionTestWithSigVerification() public { - address[] memory _committee = new address[](4); - uint16[] memory _stake = new uint16[](4); - uint8 chainID = 11; - _committee[0] = 0x68B43fD906C0B8F024a18C56e06744F7c6157c65; - _committee[1] = 0xaCAEf39832CB995c4E049437A3E2eC6a7bad1Ab5; - _committee[2] = 0x8061f127910e8eF56F16a2C411220BaD25D61444; - _committee[3] = 0x508F3F1ff45F4ca3D8e86CDCC91445F00aCC59fC; - _stake[0] = 2500; - _stake[1] = 2500; - _stake[2] = 2500; - _stake[3] = 2500; - config = new BridgeConfig(chainID, supportedTokens, supportedChains); - committee = new BridgeCommittee(); - committee.initialize(address(config), _committee, _stake, minStakeRequired); - vault = new BridgeVault(wETH); - - uint64[] memory totalLimits = new uint64[](1); - totalLimits[0] = 1000000; - - skip(2 days); - limiter = new BridgeLimiter(); - limiter.initialize( - address(committee), tokenPrices, supportedChains, totalLimits - ); - bridge = new SuiBridge(); - bridge.initialize(address(committee), address(vault), address(limiter), wETH); - - assertFalse(bridge.paused()); - - // pause - bytes memory payload = hex"00"; - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.EMERGENCY_OP, - version: 1, - nonce: 0, - chainID: chainID, - payload: payload - }); - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes memory expectedEncodedMessage = - hex"5355495f4252494447455f4d455353414745020100000000000000000b00"; - - assertEq(encodedMessage, expectedEncodedMessage); - - bytes[] memory signatures = new bytes[](1); - - signatures[0] = - hex"859db4dff22e43821b9b451e88bc7489aec3381d3e4fb5d8cbf025a84d34964a2bd556e0a86e13cb5b2d0fa52f08d02e4b62b9e6d9e07d8f8451d4c19430806d01"; - - bridge.executeEmergencyOpWithSignatures(signatures, message); - assertTrue(bridge.paused()); - - // unpause - payload = hex"01"; - message = BridgeMessage.Message({ - messageType: BridgeMessage.EMERGENCY_OP, - version: 1, - nonce: 1, - chainID: chainID, - payload: payload - }); - encodedMessage = BridgeMessage.encodeMessage(message); - expectedEncodedMessage = - hex"5355495f4252494447455f4d455353414745020100000000000000010b01"; - - assertEq(encodedMessage, expectedEncodedMessage); - - bytes[] memory signatures2 = new bytes[](3); - - signatures2[0] = - hex"de5ca964c5aa1aa323cc480cd6de46eae980a1670a5fe8e12e31f724d0bcec6516e54b516737bb6ed6ccad775370c14d46f2e10100e9d16851d2050bf2349c6401"; - signatures2[1] = - hex"fe8006e2013eaa7b8af0e5ac9f2890c2b2bd375d343684b2604ac6acd4142ccf5c9ec1914bce53a005232ef880bf0f597eed319d41d80e92d035c8314e1198ff00"; - signatures2[2] = - hex"f5749ac37e11f22da0622082c9e63a91dc7b5c59cfdaa86438d9f6a53bbacf6b763126f1a20a826d7dff73252cf2fd68da67b9caec4d3c24a07fbd566a7a6bec00"; - - bridge.executeEmergencyOpWithSignatures(signatures2, message); - assertFalse(bridge.paused()); - - // reusing the sig from nonce 0 will revert - payload = hex"00"; - message = BridgeMessage.Message({ - messageType: BridgeMessage.EMERGENCY_OP, - version: 1, - nonce: 0, - chainID: chainID, - payload: payload - }); - - signatures = new bytes[](1); - - signatures[0] = - hex"859db4dff22e43821b9b451e88bc7489aec3381d3e4fb5d8cbf025a84d34964a2bd556e0a86e13cb5b2d0fa52f08d02e4b62b9e6d9e07d8f8451d4c19430806d01"; - - vm.expectRevert(bytes("MessageVerifier: Invalid nonce")); - bridge.executeEmergencyOpWithSignatures(signatures, message); - - assertFalse(bridge.paused()); - } - - // An e2e upgrade regression test covering message ser/de and signature verification - function testUpgradeRegressionTest() public { - address[] memory _committee = new address[](4); - uint16[] memory _stake = new uint16[](4); - _committee[0] = 0x68B43fD906C0B8F024a18C56e06744F7c6157c65; - _committee[1] = 0xaCAEf39832CB995c4E049437A3E2eC6a7bad1Ab5; - _committee[2] = 0x8061f127910e8eF56F16a2C411220BaD25D61444; - _committee[3] = 0x508F3F1ff45F4ca3D8e86CDCC91445F00aCC59fC; - _stake[0] = 2500; - _stake[1] = 2500; - _stake[2] = 2500; - _stake[3] = 2500; - committee = new BridgeCommittee(); - - uint8 _chainID = 12; - uint8[] memory _supportedDestinationChains = new uint8[](1); - _supportedDestinationChains[0] = 0; - address[] memory _supportedTokens = new address[](4); - _supportedTokens[0] = wBTC; - _supportedTokens[1] = wETH; - _supportedTokens[2] = USDC; - _supportedTokens[3] = USDT; - config = new BridgeConfig(_chainID, _supportedTokens, _supportedDestinationChains); - - committee.initialize(address(config), _committee, _stake, minStakeRequired); - vault = new BridgeVault(wETH); - uint256[] memory tokenPrices = new uint256[](4); - tokenPrices[0] = 10000; // SUI PRICE - tokenPrices[1] = 10000; // BTC PRICE - tokenPrices[2] = 10000; // ETH PRICE - tokenPrices[3] = 10000; // USDC PRICE - skip(2 days); - uint64[] memory totalLimits = new uint64[](1); - totalLimits[0] = 1000000; - limiter = new BridgeLimiter(); - limiter.initialize( - address(committee), tokenPrices, _supportedDestinationChains, totalLimits - ); - bridge = new SuiBridge(); - bridge.initialize(address(committee), address(vault), address(limiter), wETH); - vault.transferOwnership(address(bridge)); - limiter.transferOwnership(address(bridge)); - - // Fill vault with WETH - changePrank(deployer); - IWETH9(wETH).deposit{value: 10 ether}(); - IERC20(wETH).transfer(address(vault), 10 ether); - - bytes memory payload = - hex"00000000000000000000000006060606060606060606060606060606060606060000000000000000000000000909090909090909090909090909090909090909000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000045cd8a76b00000000000000000000000000000000000000000000000000000000"; - // Create transfer message - BridgeMessage.Message memory message = BridgeMessage.Message({ - messageType: BridgeMessage.UPGRADE, - version: 1, - nonce: 123, - chainID: _chainID, - payload: payload - }); - bytes memory encodedMessage = BridgeMessage.encodeMessage(message); - bytes memory expectedEncodedMessage = - hex"5355495f4252494447455f4d4553534147450501000000000000007b0c00000000000000000000000006060606060606060606060606060606060606060000000000000000000000000909090909090909090909090909090909090909000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000045cd8a76b00000000000000000000000000000000000000000000000000000000"; - - assertEq(encodedMessage, expectedEncodedMessage); - - (address proxy, address newImp, bytes memory _calldata) = - BridgeMessage.decodeUpgradePayload(payload); - - assertEq(proxy, address(0x0606060606060606060606060606060606060606)); - assertEq(newImp, address(0x0909090909090909090909090909090909090909)); - assertEq(_calldata, hex"5cd8a76b"); - } -} diff --git a/bridge/evm/test/mocks/MockIotaBridgeV2.sol b/bridge/evm/test/mocks/MockIotaBridgeV2.sol new file mode 100644 index 00000000000..4298a222cd3 --- /dev/null +++ b/bridge/evm/test/mocks/MockIotaBridgeV2.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import "../../contracts/IotaBridge.sol"; + +contract MockIotaBridgeV2 is IotaBridge { + uint8 public mock; + bool public isPausing; + + function initializeV2() external { + _pause(); + } + + function newMockFunction(bool _pausing) external { + isPausing = _pausing; + } + + function newMockFunction(bool _pausing, uint8 _mock) external { + mock = _mock; + isPausing = _pausing; + } + + // used to ignore for forge coverage + function test() external view {} +} diff --git a/bridge/evm/test/mocks/MockSuiBridgeV2.sol b/bridge/evm/test/mocks/MockSuiBridgeV2.sol deleted file mode 100644 index e816b5b2fa0..00000000000 --- a/bridge/evm/test/mocks/MockSuiBridgeV2.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import "../../contracts/SuiBridge.sol"; - -contract MockSuiBridgeV2 is SuiBridge { - uint8 public mock; - bool public isPausing; - - function initializeV2() external { - _pause(); - } - - function newMockFunction(bool _pausing) external { - isPausing = _pausing; - } - - function newMockFunction(bool _pausing, uint8 _mock) external { - mock = _mock; - isPausing = _pausing; - } - - // used to ignore for forge coverage - function test() external view {} -} diff --git a/bridge/evm/test/mocks/MockTokens.sol b/bridge/evm/test/mocks/MockTokens.sol index 415cc90fa43..fd8b2300aec 100644 --- a/bridge/evm/test/mocks/MockTokens.sol +++ b/bridge/evm/test/mocks/MockTokens.sol @@ -1,4 +1,7 @@ // SPDX-License-Identifier: MIT + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; diff --git a/chocolatey/iota.nuspec b/chocolatey/iota.nuspec new file mode 100644 index 00000000000..e7081b934ce --- /dev/null +++ b/chocolatey/iota.nuspec @@ -0,0 +1,27 @@ + + + + + iota + $version$ + iota + Main Iota Binary + iota + https://iota.io/ + https://github.com/iotaledger/iota/blob/main/LICENSE + https://assets-global.website-files.com/6425f546844727ce5fb9e5ab/643775f4a15c9a9e10426daa_Iota_Favicon_256.png + https://github.com/iotaledger/iota/ + https://github.com/iotaledger/iota/issues + iota + https://community.chocolatey.org/packages/iota.portable + Run a local iota binary + Iota is the first internet-scale programmable blockchain platform + https://github.com/iotaledger/iota/releases/tag/mainnet-v$version$ + + + + + + + diff --git a/chocolatey/sui.nuspec b/chocolatey/sui.nuspec deleted file mode 100644 index 0730c594143..00000000000 --- a/chocolatey/sui.nuspec +++ /dev/null @@ -1,27 +0,0 @@ - - - - - sui - $version$ - sui - Main Sui Binary - sui - https://sui.io/ - https://github.com/MystenLabs/sui/blob/main/LICENSE - https://assets-global.website-files.com/6425f546844727ce5fb9e5ab/643775f4a15c9a9e10426daa_Sui_Favicon_256.png - https://github.com/MystenLabs/sui/ - https://github.com/MystenLabs/sui/issues - sui - https://community.chocolatey.org/packages/sui.portable - Run a local sui binary - Sui is the first internet-scale programmable blockchain platform - https://github.com/MystenLabs/sui/releases/tag/mainnet-v$version$ - - - - - - - diff --git a/consensus/README.md b/consensus/README.md index 3c586164947..0c70f8ea231 100644 --- a/consensus/README.md +++ b/consensus/README.md @@ -1,6 +1,6 @@ -# WIP: Sui Consensus 2.0 +# WIP: Iota Consensus 2.0 -This directory contains a WIP implementation of Sui Consensus 2.0. +This directory contains a WIP implementation of Iota Consensus 2.0. It is based on [Mysticeti](https://github.com/MystenLabs/mysticeti), -and Sui Consensus 1.0 which is -[Narwhal](https://github.com/MystenLabs/sui/tree/main/narwhal). +and Iota Consensus 1.0 which is +[Narwhal](https://github.com/iotaledger/iota/tree/main/narwhal). diff --git a/consensus/config/src/committee.rs b/consensus/config/src/committee.rs index 70ea67e777d..41e3bd5cc89 100644 --- a/consensus/config/src/committee.rs +++ b/consensus/config/src/committee.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -15,7 +16,7 @@ use crate::{AuthorityPublicKey, NetworkPublicKey, ProtocolPublicKey}; pub type Epoch = u64; /// Voting power of an authority, roughly proportional to the actual amount of -/// Sui staked by the authority. +/// Iota staked by the authority. /// Total stake / voting power of all authorities should sum to 10,000. pub type Stake = u64; @@ -137,7 +138,7 @@ pub struct Authority { pub address: Multiaddr, /// The authority's hostname, for metrics and logging. pub hostname: String, - /// The authority's public key as Sui identity. + /// The authority's public key as Iota identity. pub authority_key: AuthorityPublicKey, /// The authority's public key for verifying blocks. pub protocol_key: ProtocolPublicKey, diff --git a/consensus/config/src/crypto.rs b/consensus/config/src/crypto.rs index 9075bdc7738..0cb7e434289 100644 --- a/consensus/config/src/crypto.rs +++ b/consensus/config/src/crypto.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! Here we select the cryptographic types that are used by default in the code diff --git a/consensus/config/src/lib.rs b/consensus/config/src/lib.rs index 589f83fe976..98be0f98e42 100644 --- a/consensus/config/src/lib.rs +++ b/consensus/config/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 mod committee; diff --git a/consensus/config/src/parameters.rs b/consensus/config/src/parameters.rs index bb8d3816b96..001804f6111 100644 --- a/consensus/config/src/parameters.rs +++ b/consensus/config/src/parameters.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{path::PathBuf, time::Duration}; @@ -8,7 +9,7 @@ use serde::{Deserialize, Serialize}; /// Operational configurations of a consensus authority. /// /// All fields should tolerate inconsistencies among authorities, without -/// affecting safety of the protocol. Otherwise, they need to be part of Sui +/// affecting safety of the protocol. Otherwise, they need to be part of Iota /// protocol config or epoch state on-chain. /// /// NOTE: fields with default values are specified in the serde default diff --git a/consensus/config/src/test_committee.rs b/consensus/config/src/test_committee.rs index 4b58a6e8b9c..55663b9b18e 100644 --- a/consensus/config/src/test_committee.rs +++ b/consensus/config/src/test_committee.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::net::{TcpListener, TcpStream}; diff --git a/consensus/config/tests/committee_test.rs b/consensus/config/tests/committee_test.rs index b1ee91b812c..b4dd6f2edd8 100644 --- a/consensus/config/tests/committee_test.rs +++ b/consensus/config/tests/committee_test.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use consensus_config::{ diff --git a/consensus/config/tests/parameters_test.rs b/consensus/config/tests/parameters_test.rs index 507921af7b6..f893caa3504 100644 --- a/consensus/config/tests/parameters_test.rs +++ b/consensus/config/tests/parameters_test.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use consensus_config::Parameters; diff --git a/consensus/core/Cargo.toml b/consensus/core/Cargo.toml index 97a9c9d1079..b8138b8c1aa 100644 --- a/consensus/core/Cargo.toml +++ b/consensus/core/Cargo.toml @@ -31,7 +31,7 @@ prost.workspace = true rand.workspace = true serde.workspace = true shared-crypto.workspace = true -sui-protocol-config.workspace = true +iota-protocol-config.workspace = true tap.workspace = true thiserror.workspace = true tokio.workspace = true diff --git a/consensus/core/build.rs b/consensus/core/build.rs index 27e43dd0aca..ccdd3c65ff7 100644 --- a/consensus/core/build.rs +++ b/consensus/core/build.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/consensus/core/src/authority_node.rs b/consensus/core/src/authority_node.rs index bd97f79f4e5..bd810bce662 100644 --- a/consensus/core/src/authority_node.rs +++ b/consensus/core/src/authority_node.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -10,9 +11,9 @@ use std::{ use async_trait::async_trait; use bytes::Bytes; use consensus_config::{AuthorityIndex, Committee, NetworkKeyPair, Parameters, ProtocolKeyPair}; +use iota_protocol_config::ProtocolConfig; use parking_lot::RwLock; use prometheus::Registry; -use sui_protocol_config::ProtocolConfig; use tokio::time::sleep; use tracing::{info, warn}; @@ -38,7 +39,7 @@ use crate::{ CommitConsumer, }; -/// ConsensusAuthority is used by Sui to manage the lifetime of AuthorityNode. +/// ConsensusAuthority is used by Iota to manage the lifetime of AuthorityNode. /// It hides the details of the implementation from the caller, /// MysticetiManager. #[allow(private_interfaces)] @@ -400,10 +401,10 @@ mod tests { use async_trait::async_trait; use consensus_config::{local_committee_and_keys, Parameters}; + use iota_protocol_config::ProtocolConfig; use parking_lot::Mutex; use prometheus::Registry; use rstest::rstest; - use sui_protocol_config::ProtocolConfig; use tempfile::TempDir; use tokio::{sync::mpsc::unbounded_channel, time::sleep}; diff --git a/consensus/core/src/base_committer.rs b/consensus/core/src/base_committer.rs index 8b7413f7d1a..9529aab975c 100644 --- a/consensus/core/src/base_committer.rs +++ b/consensus/core/src/base_committer.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, fmt::Display, sync::Arc}; diff --git a/consensus/core/src/block.rs b/consensus/core/src/block.rs index 14afc10d93c..0c6afe89969 100644 --- a/consensus/core/src/block.rs +++ b/consensus/core/src/block.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -42,7 +43,7 @@ pub fn timestamp_utc_ms() -> BlockTimestampMs { } } -/// Sui transaction in serialised bytes +/// Iota transaction in serialised bytes #[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Default, Debug)] pub struct Transaction { data: Bytes, diff --git a/consensus/core/src/block_manager.rs b/consensus/core/src/block_manager.rs index 0b1fe961135..fd8fd5ae9ce 100644 --- a/consensus/core/src/block_manager.rs +++ b/consensus/core/src/block_manager.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/consensus/core/src/block_verifier.rs b/consensus/core/src/block_verifier.rs index a5a251f1c68..ac94d261839 100644 --- a/consensus/core/src/block_verifier.rs +++ b/consensus/core/src/block_verifier.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeSet, sync::Arc}; @@ -205,7 +206,7 @@ mod test { // Fails verification if any transaction is < 4 bytes. fn verify_batch( &self, - _protocol_config: &sui_protocol_config::ProtocolConfig, + _protocol_config: &iota_protocol_config::ProtocolConfig, transactions: &[&[u8]], ) -> Result<(), ValidationError> { for txn in transactions { diff --git a/consensus/core/src/broadcaster.rs b/consensus/core/src/broadcaster.rs index 3ed32aa7d71..ce8cba350f6 100644 --- a/consensus/core/src/broadcaster.rs +++ b/consensus/core/src/broadcaster.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/consensus/core/src/commit.rs b/consensus/core/src/commit.rs index 7ec7b0e7f1d..1b95a482194 100644 --- a/consensus/core/src/commit.rs +++ b/consensus/core/src/commit.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/consensus/core/src/commit_observer.rs b/consensus/core/src/commit_observer.rs index 26af9171a96..032267259ef 100644 --- a/consensus/core/src/commit_observer.rs +++ b/consensus/core/src/commit_observer.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; diff --git a/consensus/core/src/context.rs b/consensus/core/src/context.rs index 7c7cdd6e044..323a8a777aa 100644 --- a/consensus/core/src/context.rs +++ b/consensus/core/src/context.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; @@ -6,7 +7,7 @@ use std::sync::Arc; use consensus_config::{AuthorityIndex, Committee, Parameters}; #[cfg(test)] use consensus_config::{NetworkKeyPair, ProtocolKeyPair}; -use sui_protocol_config::ProtocolConfig; +use iota_protocol_config::ProtocolConfig; #[cfg(test)] use tempfile::TempDir; diff --git a/consensus/core/src/core.rs b/consensus/core/src/core.rs index 8efaa317a64..65426b4f670 100644 --- a/consensus/core/src/core.rs +++ b/consensus/core/src/core.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -603,7 +604,7 @@ mod test { use std::{collections::BTreeSet, time::Duration}; use consensus_config::{local_committee_and_keys, AuthorityIndex, Parameters, Stake}; - use sui_protocol_config::ProtocolConfig; + use iota_protocol_config::ProtocolConfig; use tokio::{ sync::mpsc::{unbounded_channel, UnboundedReceiver}, time::sleep, diff --git a/consensus/core/src/core_thread.rs b/consensus/core/src/core_thread.rs index eca39694d69..38a53e0daa1 100644 --- a/consensus/core/src/core_thread.rs +++ b/consensus/core/src/core_thread.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeSet, fmt::Debug, sync::Arc}; diff --git a/consensus/core/src/dag_state.rs b/consensus/core/src/dag_state.rs index b965fa8c88b..ace59e66dc2 100644 --- a/consensus/core/src/dag_state.rs +++ b/consensus/core/src/dag_state.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/consensus/core/src/error.rs b/consensus/core/src/error.rs index d2ac85e8c5f..d8898712dce 100644 --- a/consensus/core/src/error.rs +++ b/consensus/core/src/error.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::time::Duration; diff --git a/consensus/core/src/leader_schedule.rs b/consensus/core/src/leader_schedule.rs index 08308c2a39e..c2098134b25 100644 --- a/consensus/core/src/leader_schedule.rs +++ b/consensus/core/src/leader_schedule.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; @@ -67,7 +68,7 @@ impl LeaderSchedule { #[cfg(test)] mod tests { use consensus_config::{local_committee_and_keys, Parameters}; - use sui_protocol_config::ProtocolConfig; + use iota_protocol_config::ProtocolConfig; use super::*; use crate::metrics::test_metrics; diff --git a/consensus/core/src/leader_timeout.rs b/consensus/core/src/leader_timeout.rs index 84f03c163a4..8d85ba6358c 100644 --- a/consensus/core/src/leader_timeout.rs +++ b/consensus/core/src/leader_timeout.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{sync::Arc, time::Duration}; diff --git a/consensus/core/src/lib.rs b/consensus/core/src/lib.rs index 096887cb658..4d72859c207 100644 --- a/consensus/core/src/lib.rs +++ b/consensus/core/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 mod authority_node; diff --git a/consensus/core/src/linearizer.rs b/consensus/core/src/linearizer.rs index 55a4a33a063..5b359246bec 100644 --- a/consensus/core/src/linearizer.rs +++ b/consensus/core/src/linearizer.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashSet, sync::Arc}; @@ -124,7 +125,7 @@ impl Linearizer { self.dag_state.write().add_commit(commit.clone()); committed_sub_dags.push(sub_dag); } - // Committed blocks must be persisted to storage before sending them to Sui and + // Committed blocks must be persisted to storage before sending them to Iota and // executing their transactions. // Commit metadata can be persisted more lazily because they are recoverable. // Uncommitted blocks can wait to persist too. diff --git a/consensus/core/src/metrics.rs b/consensus/core/src/metrics.rs index 2a417e950f3..243f808b0f9 100644 --- a/consensus/core/src/metrics.rs +++ b/consensus/core/src/metrics.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; diff --git a/consensus/core/src/network/anemo_network.rs b/consensus/core/src/network/anemo_network.rs index 40054853352..7573552dba9 100644 --- a/consensus/core/src/network/anemo_network.rs +++ b/consensus/core/src/network/anemo_network.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/consensus/core/src/network/connection_monitor.rs b/consensus/core/src/network/connection_monitor.rs index c9e0950778a..b83d104f61c 100644 --- a/consensus/core/src/network/connection_monitor.rs +++ b/consensus/core/src/network/connection_monitor.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, sync::Arc, time::Duration}; @@ -20,7 +21,7 @@ const CONNECTION_STAT_COLLECTION_INTERVAL: Duration = Duration::from_secs(60); pub(crate) struct ConnectionMonitorHandle { handle: JoinHandle<()>, stop: Sender<()>, - // TODO: Sui will use this component eventually instead of the NW version + // TODO: Iota will use this component eventually instead of the NW version #[allow(unused)] connection_statuses: Arc>, } diff --git a/consensus/core/src/network/epoch_filter.rs b/consensus/core/src/network/epoch_filter.rs index bb3acabb0ea..7b4ec34f616 100644 --- a/consensus/core/src/network/epoch_filter.rs +++ b/consensus/core/src/network/epoch_filter.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anemo::{rpc::Status, Request, Response}; diff --git a/consensus/core/src/network/metrics.rs b/consensus/core/src/network/metrics.rs index f8750c901ec..92615753b47 100644 --- a/consensus/core/src/network/metrics.rs +++ b/consensus/core/src/network/metrics.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use prometheus::{ diff --git a/consensus/core/src/network/mod.rs b/consensus/core/src/network/mod.rs index 0769e3c2c8c..e7053052e7a 100644 --- a/consensus/core/src/network/mod.rs +++ b/consensus/core/src/network/mod.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{sync::Arc, time::Duration}; diff --git a/consensus/core/src/network/tonic_network.rs b/consensus/core/src/network/tonic_network.rs index 10f31319433..3b7de86771a 100644 --- a/consensus/core/src/network/tonic_network.rs +++ b/consensus/core/src/network/tonic_network.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/consensus/core/src/stake_aggregator.rs b/consensus/core/src/stake_aggregator.rs index e7f462ef5ef..633ac2960b1 100644 --- a/consensus/core/src/stake_aggregator.rs +++ b/consensus/core/src/stake_aggregator.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashSet, marker::PhantomData}; diff --git a/consensus/core/src/storage/mem_store.rs b/consensus/core/src/storage/mem_store.rs index a4f40a8b638..c3458066b15 100644 --- a/consensus/core/src/storage/mem_store.rs +++ b/consensus/core/src/storage/mem_store.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/consensus/core/src/storage/mod.rs b/consensus/core/src/storage/mod.rs index 56412931271..13a3c498ef6 100644 --- a/consensus/core/src/storage/mod.rs +++ b/consensus/core/src/storage/mod.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 pub(crate) mod mem_store; diff --git a/consensus/core/src/storage/rocksdb_store.rs b/consensus/core/src/storage/rocksdb_store.rs index 6bc5f783105..ea20fb99f3b 100644 --- a/consensus/core/src/storage/rocksdb_store.rs +++ b/consensus/core/src/storage/rocksdb_store.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/consensus/core/src/storage/store_tests.rs b/consensus/core/src/storage/store_tests.rs index efc487c6eab..b5fb773e83c 100644 --- a/consensus/core/src/storage/store_tests.rs +++ b/consensus/core/src/storage/store_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use consensus_config::AuthorityIndex; diff --git a/consensus/core/src/synchronizer.rs b/consensus/core/src/synchronizer.rs index 11b61c680fe..e7beda74f46 100644 --- a/consensus/core/src/synchronizer.rs +++ b/consensus/core/src/synchronizer.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/consensus/core/src/test_dag.rs b/consensus/core/src/test_dag.rs index 60a58af9bbe..3de866e9a63 100644 --- a/consensus/core/src/test_dag.rs +++ b/consensus/core/src/test_dag.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; diff --git a/consensus/core/src/tests/base_committer_tests.rs b/consensus/core/src/tests/base_committer_tests.rs index 439e516f5b7..08b8e1d698d 100644 --- a/consensus/core/src/tests/base_committer_tests.rs +++ b/consensus/core/src/tests/base_committer_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashSet, sync::Arc}; diff --git a/consensus/core/src/tests/pipelined_committer_tests.rs b/consensus/core/src/tests/pipelined_committer_tests.rs index 43d02bd4d67..958e32b6cbb 100644 --- a/consensus/core/src/tests/pipelined_committer_tests.rs +++ b/consensus/core/src/tests/pipelined_committer_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; diff --git a/consensus/core/src/tests/universal_committer_tests.rs b/consensus/core/src/tests/universal_committer_tests.rs index 3ec3508ccd5..eee399a523c 100644 --- a/consensus/core/src/tests/universal_committer_tests.rs +++ b/consensus/core/src/tests/universal_committer_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; diff --git a/consensus/core/src/threshold_clock.rs b/consensus/core/src/threshold_clock.rs index 613eb854add..c667e710c18 100644 --- a/consensus/core/src/threshold_clock.rs +++ b/consensus/core/src/threshold_clock.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{cmp::Ordering, sync::Arc, time::Instant}; diff --git a/consensus/core/src/transaction.rs b/consensus/core/src/transaction.rs index 47464eb52cc..46c4e4a68ca 100644 --- a/consensus/core/src/transaction.rs +++ b/consensus/core/src/transaction.rs @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; +use iota_protocol_config::ProtocolConfig; use mysten_metrics::{metered_channel, metered_channel::channel_with_total}; -use sui_protocol_config::ProtocolConfig; use tap::tap::TapFallible; use thiserror::Error; use tokio::sync::oneshot; @@ -178,7 +179,7 @@ impl TransactionClient { } } -/// `TransactionVerifier` implementation is supplied by Sui to validate +/// `TransactionVerifier` implementation is supplied by Iota to validate /// transactions in a block, before acceptance of the block. pub trait TransactionVerifier: Send + Sync + 'static { /// Determines if this batch can be voted on @@ -213,7 +214,7 @@ mod tests { use std::{sync::Arc, time::Duration}; use futures::{stream::FuturesUnordered, StreamExt}; - use sui_protocol_config::ProtocolConfig; + use iota_protocol_config::ProtocolConfig; use tokio::time::timeout; use crate::{ diff --git a/consensus/core/src/universal_committer.rs b/consensus/core/src/universal_committer.rs index 415a02da53b..f3fb4af2a24 100644 --- a/consensus/core/src/universal_committer.rs +++ b/consensus/core/src/universal_committer.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::VecDeque, sync::Arc}; diff --git a/crates/anemo-benchmark/build.rs b/crates/anemo-benchmark/build.rs index 0ddf01bf885..32f26a9bfdf 100644 --- a/crates/anemo-benchmark/build.rs +++ b/crates/anemo-benchmark/build.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/anemo-benchmark/src/lib.rs b/crates/anemo-benchmark/src/lib.rs index a0c7edee7be..2140c86f3c8 100644 --- a/crates/anemo-benchmark/src/lib.rs +++ b/crates/anemo-benchmark/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 mod generated { diff --git a/crates/anemo-benchmark/src/main.rs b/crates/anemo-benchmark/src/main.rs index 74bbae2f652..852c0187fcb 100644 --- a/crates/anemo-benchmark/src/main.rs +++ b/crates/anemo-benchmark/src/main.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::time::Duration; diff --git a/crates/anemo-benchmark/src/server.rs b/crates/anemo-benchmark/src/server.rs index c41c25f0598..0023fd29c05 100644 --- a/crates/anemo-benchmark/src/server.rs +++ b/crates/anemo-benchmark/src/server.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use rand::Rng; diff --git a/crates/data-transform/Cargo.toml b/crates/data-transform/Cargo.toml index 37197170a6d..970964e1387 100644 --- a/crates/data-transform/Cargo.toml +++ b/crates/data-transform/Cargo.toml @@ -17,9 +17,9 @@ serde = { version = "1.0.144", features = ["derive", "rc"] } serde_json = { version = "1.0.95", features = ["preserve_order", "arbitrary_precision"] } tracing = "0.1.37" base64 = "0.21.2" -sui-types.workspace = true -sui-indexer.workspace = true +iota-types.workspace = true +iota-indexer.workspace = true move-core-types.workspace = true move-bytecode-utils.workspace = true -sui-json-rpc-types.workspace = true +iota-json-rpc-types.workspace = true once_cell.workspace = true diff --git a/crates/data-transform/README.md b/crates/data-transform/README.md index fbd5ce2630a..618b4ce2ca6 100644 --- a/crates/data-transform/README.md +++ b/crates/data-transform/README.md @@ -3,7 +3,7 @@ data-transform is a separate process used to transform data, by decoding columns ### Running standalone transformer -1. in sui/crates/data-transform: +1. in iota/crates/data-transform: ```sh $ echo DATABASE_URL=postgres://username:password@localhost/diesel_demo > .env diff --git a/crates/data-transform/src/lib.rs b/crates/data-transform/src/lib.rs index 66c3265055d..9bbda2ced52 100644 --- a/crates/data-transform/src/lib.rs +++ b/crates/data-transform/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 pub mod models; diff --git a/crates/data-transform/src/main.rs b/crates/data-transform/src/main.rs index be8a14c60f1..e6bc766ad89 100644 --- a/crates/data-transform/src/main.rs +++ b/crates/data-transform/src/main.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -12,18 +13,18 @@ use std::{ use anyhow::anyhow; use data_transform::*; use diesel::{prelude::*, RunQueryDsl}; -use move_bytecode_utils::module_cache::SyncModuleCache; -use move_core_types::{language_storage::ModuleId, resolver::ModuleResolver}; -use once_cell::sync::Lazy; -use sui_indexer::{ +use iota_indexer::{ db::new_pg_connection_pool, errors::IndexerError, store::module_resolver::IndexerStorePackageModuleResolver, }; -use sui_json_rpc_types::SuiMoveStruct; -use sui_types::{ +use iota_json_rpc_types::IotaMoveStruct; +use iota_types::{ object::{bounded_visitor::BoundedVisitor, MoveObject}, - parse_sui_struct_tag, + parse_iota_struct_tag, }; +use move_bytecode_utils::module_cache::SyncModuleCache; +use move_core_types::{language_storage::ModuleId, resolver::ModuleResolver}; +use once_cell::sync::Lazy; use tracing::debug; use self::models::*; @@ -279,7 +280,8 @@ fn main() { } // JSON parsing starts here - let type_ = parse_sui_struct_tag(&event.event_type).expect("cannot load StructTag"); + let type_ = + parse_iota_struct_tag(&event.event_type).expect("cannot load StructTag"); let layout = MoveObject::get_layout_from_struct_tag(type_.clone(), &module_cache); @@ -290,7 +292,7 @@ fn main() { match move_object { Ok(m) => { - let parsed_json = SuiMoveStruct::from(m).to_json_value(); + let parsed_json = IotaMoveStruct::from(m).to_json_value(); let final_result = serde_json::to_string_pretty(&parsed_json).unwrap(); println!("event json = {}", final_result); diff --git a/crates/data-transform/src/models.rs b/crates/data-transform/src/models.rs index 8c6e589071a..edfc808a879 100644 --- a/crates/data-transform/src/models.rs +++ b/crates/data-transform/src/models.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use diesel::prelude::*; diff --git a/crates/data-transform/src/schema.rs b/crates/data-transform/src/schema.rs index 8ffd32203fb..3c074106843 100644 --- a/crates/data-transform/src/schema.rs +++ b/crates/data-transform/src/schema.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 diesel::table! { diff --git a/crates/iota-adapter-transactional-tests/Cargo.toml b/crates/iota-adapter-transactional-tests/Cargo.toml new file mode 100644 index 00000000000..931a7746f98 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "iota-adapter-transactional-tests" +version = "0.1.0" +authors = ["Mysten Labs "] +description = "Transactional tests for Iota Adapter" +license = "Apache-2.0" +publish = false +edition = "2021" + +[dev-dependencies] +datatest-stable.workspace = true +iota-transactional-test-runner.workspace = true + +[[test]] +name = "tests" +harness = false + +[dependencies] diff --git a/crates/iota-adapter-transactional-tests/src/lib.rs b/crates/iota-adapter-transactional-tests/src/lib.rs new file mode 100644 index 00000000000..7de55296af9 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/src/lib.rs @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#![forbid(unsafe_code)] + +// Empty src/lib.rs to get rusty-tags working. diff --git a/crates/iota-adapter-transactional-tests/tests/call/simple.exp b/crates/iota-adapter-transactional-tests/tests/call/simple.exp new file mode 100644 index 00000000000..d05536c95bb --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/call/simple.exp @@ -0,0 +1,16 @@ +processed 4 tasks + +task 1 'publish'. lines 6-25: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5570800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 27-27: +created: object(2,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2302800, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'view-object'. lines 29-29: +Owner: Account Address ( A ) +Version: 3 +Contents: Test::M1::Object {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, value: 0u64} diff --git a/crates/iota-adapter-transactional-tests/tests/call/simple.move b/crates/iota-adapter-transactional-tests/tests/call/simple.move new file mode 100644 index 00000000000..3b5353ae4b4 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/call/simple.move @@ -0,0 +1,30 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --addresses Test=0x0 A=0x42 + +//# publish +module Test::M1 { + use iota::coin::Coin; + + public struct Object has key, store { + id: UID, + value: u64, + } + + fun foo(_p1: u64, value1: T, _value2: &Coin, _p2: u64): T { + value1 + } + + public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { + transfer::public_transfer( + Object { id: object::new(ctx), value }, + recipient + ) + } +} + +//# run Test::M1::create --args 0 @A + +//# view-object 2,0 diff --git a/crates/sui-adapter-transactional-tests/tests/checkpoint/clock.exp b/crates/iota-adapter-transactional-tests/tests/checkpoint/clock.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/checkpoint/clock.exp rename to crates/iota-adapter-transactional-tests/tests/checkpoint/clock.exp diff --git a/crates/iota-adapter-transactional-tests/tests/checkpoint/clock.move b/crates/iota-adapter-transactional-tests/tests/checkpoint/clock.move new file mode 100644 index 00000000000..4dae3acddf7 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/checkpoint/clock.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// TODO support system transactions +//# init + +// //# consensus-commit-prologue --timestamp-ms 43 + +// //# view-object 6 + +// //# consensus-commit-prologue --timestamp-ms 45 + +// //# view-object 6 diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/count_decremented.exp b/crates/iota-adapter-transactional-tests/tests/child_count/count_decremented.exp similarity index 83% rename from crates/sui-adapter-transactional-tests/tests/child_count/count_decremented.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/count_decremented.exp index 3a58f93c93f..6e503c05c5e 100644 --- a/crates/sui-adapter-transactional-tests/tests/child_count/count_decremented.exp +++ b/crates/iota-adapter-transactional-tests/tests/child_count/count_decremented.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: task 3 'view-object'. lines 55-55: Owner: Account Address ( A ) Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'run'. lines 57-57: created: object(4,0), object(4,1) @@ -31,7 +31,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: task 6 'view-object'. lines 61-65: Owner: Account Address ( A ) Version: 4 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 7 'run'. lines 67-67: created: object(7,0) @@ -41,7 +41,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: task 8 'view-object'. lines 69-69: Owner: Account Address ( A ) Version: 5 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(7,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(7,0)}}} task 9 'run'. lines 71-71: created: object(9,0), object(9,1) @@ -55,7 +55,7 @@ gas summary: computation_cost: 1000000, storage_cost: 5859600, storage_rebate: task 11 'view-object'. lines 75-79: Owner: Account Address ( A ) Version: 7 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(7,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(7,0)}}} task 12 'run'. lines 81-81: created: object(12,0) @@ -65,7 +65,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: task 13 'view-object'. lines 83-83: Owner: Account Address ( A ) Version: 8 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(12,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(12,0)}}} task 14 'run'. lines 85-85: created: object(14,0), object(14,1) @@ -81,4 +81,4 @@ gas summary: computation_cost: 1000000, storage_cost: 6102800, storage_rebate: task 16 'view-object'. lines 89-89: Owner: Account Address ( A ) Version: 10 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(12,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(12,0)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/count_decremented.move b/crates/iota-adapter-transactional-tests/tests/child_count/count_decremented.move similarity index 78% rename from crates/sui-adapter-transactional-tests/tests/child_count/count_decremented.move rename to crates/iota-adapter-transactional-tests/tests/child_count/count_decremented.move index 1c2b4ea0f5c..3020a8b2f2c 100644 --- a/crates/sui-adapter-transactional-tests/tests/child_count/count_decremented.move +++ b/crates/iota-adapter-transactional-tests/tests/child_count/count_decremented.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // DEPRECATED child count no longer tracked @@ -9,30 +10,30 @@ //# publish module test::m { - use sui::dynamic_object_field as ofield; + use iota::dynamic_object_field as ofield; public struct S has key, store { - id: sui::object::UID, + id: iota::object::UID, } public struct R has key, store { - id: sui::object::UID, + id: iota::object::UID, s: S, } public entry fun mint(ctx: &mut TxContext) { - let id = sui::object::new(ctx); - sui::transfer::public_transfer(S { id }, tx_context::sender(ctx)) + let id = iota::object::new(ctx); + iota::transfer::public_transfer(S { id }, tx_context::sender(ctx)) } public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { - let child = S { id: sui::object::new(ctx) }; + let child = S { id: iota::object::new(ctx) }; ofield::add(&mut parent.id, idx, child); } public entry fun remove(parent: &mut S, idx: u64) { let S { id } = ofield::remove(&mut parent.id, idx); - sui::object::delete(id) + iota::object::delete(id) } public entry fun remove_and_add(parent: &mut S, idx: u64) { @@ -42,7 +43,7 @@ module test::m { public entry fun remove_and_wrap(parent: &mut S, idx: u64, ctx: &mut TxContext) { let child: S = ofield::remove(&mut parent.id, idx); - ofield::add(&mut parent.id, idx, R { id: sui::object::new(ctx), s: child }) + ofield::add(&mut parent.id, idx, R { id: iota::object::new(ctx), s: child }) } } diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/delete_by_wrap.exp b/crates/iota-adapter-transactional-tests/tests/child_count/delete_by_wrap.exp similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/child_count/delete_by_wrap.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/delete_by_wrap.exp index b143b9aea00..e3d143c14f4 100644 --- a/crates/sui-adapter-transactional-tests/tests/child_count/delete_by_wrap.exp +++ b/crates/iota-adapter-transactional-tests/tests/child_count/delete_by_wrap.exp @@ -21,7 +21,7 @@ gas summary: computation_cost: 1000000, storage_cost: 5859600, storage_rebate: task 4 'view-object'. lines 43-43: Owner: Account Address ( A ) Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 5 'run'. lines 45-45: created: object(5,0) diff --git a/crates/iota-adapter-transactional-tests/tests/child_count/delete_by_wrap.move b/crates/iota-adapter-transactional-tests/tests/child_count/delete_by_wrap.move new file mode 100644 index 00000000000..0eed4891f74 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/child_count/delete_by_wrap.move @@ -0,0 +1,46 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// DEPRECATED child count no longer tracked +// tests invalid wrapping of a parent object with children + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct S has key, store { + id: iota::object::UID, + } + + public struct R has key, store { + id: iota::object::UID, + s: S, + } + + public entry fun mint(ctx: &mut TxContext) { + let id = iota::object::new(ctx); + iota::transfer::public_transfer(S { id }, tx_context::sender(ctx)) + } + + public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { + let child = S { id: iota::object::new(ctx) }; + ofield::add(&mut parent.id, idx, child); + } + + public entry fun wrap(s: S, ctx: &mut TxContext) { + let r = R { id: iota::object::new(ctx), s }; + iota::transfer::public_transfer(r, tx_context::sender(ctx)) + } +} + +//# run test::m::mint --sender A + +//# run test::m::add --sender A --args object(2,0) 0 + +//# view-object 2,0 + +//# run test::m::wrap --sender A --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/delete_by_wrap_one_txn.exp b/crates/iota-adapter-transactional-tests/tests/child_count/delete_by_wrap_one_txn.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/child_count/delete_by_wrap_one_txn.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/delete_by_wrap_one_txn.exp diff --git a/crates/iota-adapter-transactional-tests/tests/child_count/delete_by_wrap_one_txn.move b/crates/iota-adapter-transactional-tests/tests/child_count/delete_by_wrap_one_txn.move new file mode 100644 index 00000000000..ea603224272 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/child_count/delete_by_wrap_one_txn.move @@ -0,0 +1,34 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// DEPRECATED child count no longer tracked +// tests invalid wrapping of a parent object with children, in a single transaction + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct S has key, store { + id: iota::object::UID, + } + + public struct R has key { + id: iota::object::UID, + s: S, + } + + public entry fun test_wrap(ctx: &mut TxContext) { + let mut id = iota::object::new(ctx); + let child = S { id: iota::object::new(ctx) }; + ofield::add(&mut id, 0, child); + let parent = S { id }; + let r = R { id: iota::object::new(ctx), s: parent }; + iota::transfer::transfer(r, tx_context::sender(ctx)) + } +} + +//# run test::m::test_wrap --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_invalid.exp b/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_invalid.exp similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_invalid.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_invalid.exp index a86421581be..2428bd38bd1 100644 --- a/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_invalid.exp +++ b/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_invalid.exp @@ -21,7 +21,7 @@ gas summary: computation_cost: 1000000, storage_cost: 5859600, storage_rebate: task 4 'view-object'. lines 38-38: Owner: Account Address ( A ) Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 5 'run'. lines 40-40: mutated: object(0,0) diff --git a/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_invalid.move b/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_invalid.move new file mode 100644 index 00000000000..283bd036d81 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_invalid.move @@ -0,0 +1,41 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// DEPRECATED child count no longer tracked +// tests that the parent cannot be deleted while it has children + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct S has key, store { + id: iota::object::UID, + } + + public entry fun mint(ctx: &mut TxContext) { + let id = iota::object::new(ctx); + iota::transfer::public_transfer(S { id }, tx_context::sender(ctx)) + } + + public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { + let child = S { id: iota::object::new(ctx) }; + ofield::add(&mut parent.id, idx, child); + } + + public entry fun delete(s: S) { + let S { id } = s; + iota::object::delete(id) + } +} + +//# run test::m::mint --sender A + +//# run test::m::add --sender A --args object(2,0) 0 + +//# view-object 2,0 + +//# run test::m::delete --sender A --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_valid.exp b/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_valid.exp similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_valid.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_valid.exp index 1d6e5b4cf3b..44cc5fd17b8 100644 --- a/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_valid.exp +++ b/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_valid.exp @@ -21,7 +21,7 @@ gas summary: computation_cost: 1000000, storage_cost: 5859600, storage_rebate: task 4 'view-object'. lines 62-62: Owner: Account Address ( A ) Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 5 'run'. lines 64-64: mutated: object(0,0), object(2,0) diff --git a/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_valid.move b/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_valid.move new file mode 100644 index 00000000000..69c3cea0afe --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_valid.move @@ -0,0 +1,67 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// DEPRECATED child count no longer tracked +// tests valid deletion of an object that has children + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct S has key, store { + id: iota::object::UID, + } + + public struct R has key, store { + id: iota::object::UID, + s: S, + } + + public entry fun mint(ctx: &mut TxContext) { + let id = iota::object::new(ctx); + iota::transfer::public_transfer(S { id }, tx_context::sender(ctx)) + } + + public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { + let child = S { id: iota::object::new(ctx) }; + ofield::add(&mut parent.id, idx, child); + } + + public entry fun remove(parent: &mut S, idx: u64) { + let S { id } = ofield::remove(&mut parent.id, idx); + iota::object::delete(id) + } + + public entry fun remove_and_add(parent: &mut S, idx: u64) { + let child: S = ofield::remove(&mut parent.id, idx); + ofield::add(&mut parent.id, idx, child) + } + + public entry fun remove_and_wrap(parent: &mut S, idx: u64, ctx: &mut TxContext) { + let child: S = ofield::remove(&mut parent.id, idx); + ofield::add(&mut parent.id, idx, R { id: iota::object::new(ctx), s: child }) + } + + public entry fun delete(s: S) { + let S { id } = s; + iota::object::delete(id) + } + + public entry fun wrap(s: S, ctx: &mut TxContext) { + let r = R { id: iota::object::new(ctx), s }; + iota::transfer::public_transfer(r, tx_context::sender(ctx)) + } +} +//# run test::m::mint --sender A + +//# run test::m::add --sender A --args object(2,0) 0 + +//# view-object 2,0 + +//# run test::m::remove --sender A --args object(2,0) 0 + +//# run test::m::delete --sender A --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_valid_one_txn.exp b/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_valid_one_txn.exp similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_valid_one_txn.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_valid_one_txn.exp index b9d2a59199f..e52f3d586a2 100644 --- a/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_valid_one_txn.exp +++ b/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_valid_one_txn.exp @@ -21,7 +21,7 @@ gas summary: computation_cost: 1000000, storage_cost: 5859600, storage_rebate: task 4 'view-object'. lines 75-75: Owner: Account Address ( A ) Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 5 'run'. lines 77-77: mutated: object(0,0) diff --git a/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_valid_one_txn.move b/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_valid_one_txn.move new file mode 100644 index 00000000000..f7235a5e73d --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/child_count/delete_parent_valid_one_txn.move @@ -0,0 +1,78 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// DEPRECATED child count no longer tracked +// tests valid deletion of an object that has children +// Both child and parent are deleted in one transaction + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct S has key, store { + id: iota::object::UID, + } + + public struct R has key, store { + id: iota::object::UID, + s: S, + } + + public entry fun mint(ctx: &mut TxContext) { + let id = iota::object::new(ctx); + iota::transfer::public_transfer(S { id }, tx_context::sender(ctx)) + } + + public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { + let child = S { id: iota::object::new(ctx) }; + ofield::add(&mut parent.id, idx, child); + } + + public entry fun remove(parent: &mut S, idx: u64) { + let S { id } = ofield::remove(&mut parent.id, idx); + iota::object::delete(id) + } + + public entry fun remove_and_add(parent: &mut S, idx: u64) { + let child: S = ofield::remove(&mut parent.id, idx); + ofield::add(&mut parent.id, idx, child) + } + + public entry fun remove_and_wrap(parent: &mut S, idx: u64, ctx: &mut TxContext) { + let child: S = ofield::remove(&mut parent.id, idx); + ofield::add(&mut parent.id, idx, R { id: iota::object::new(ctx), s: child }) + } + + public entry fun delete(s: S) { + let S { id } = s; + iota::object::delete(id) + } + + public entry fun wrap(s: S, ctx: &mut TxContext) { + let r = R { id: iota::object::new(ctx), s }; + iota::transfer::public_transfer(r, tx_context::sender(ctx)) + } + + public entry fun remove_and_delete(mut s: S, idx: u64) { + let S { id } = ofield::remove(&mut s.id, idx); + iota::object::delete(id); + let S { id } = s; + iota::object::delete(id) + } +} + +// +// Test deleting parent and child in the same txn, parent first +// + +//# run test::m::mint --sender A + +//# run test::m::add --sender A --args object(2,0) 0 + +//# view-object 2,0 + +//# run test::m::remove_and_delete --sender A --args object(2,0) 0 diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_invalid.exp b/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_invalid.exp similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_invalid.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_invalid.exp index 3ef8c35b9ba..e21b36ca429 100644 --- a/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_invalid.exp +++ b/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_invalid.exp @@ -21,7 +21,7 @@ gas summary: computation_cost: 1000000, storage_cost: 5859600, storage_rebate: task 4 'view-object'. lines 67-67: Owner: Account Address ( A ) Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 5 'run'. lines 69-69: mutated: object(0,0), object(2,0) diff --git a/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_invalid.move b/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_invalid.move new file mode 100644 index 00000000000..e8123ab40b0 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_invalid.move @@ -0,0 +1,70 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// DEPRECATED child count no longer tracked +// tests that the parent cannot be frozen while it has children + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct S has key, store { + id: iota::object::UID, + } + + public struct R has key, store { + id: iota::object::UID, + s: S, + } + + public entry fun mint(ctx: &mut TxContext) { + let id = iota::object::new(ctx); + iota::transfer::public_transfer(S { id }, tx_context::sender(ctx)) + } + + public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { + let child = S { id: iota::object::new(ctx) }; + ofield::add(&mut parent.id, idx, child); + } + + public entry fun remove(parent: &mut S, idx: u64) { + let S { id } = ofield::remove(&mut parent.id, idx); + iota::object::delete(id) + } + + public entry fun remove_and_add(parent: &mut S, idx: u64) { + let child: S = ofield::remove(&mut parent.id, idx); + ofield::add(&mut parent.id, idx, child) + } + + public entry fun remove_and_wrap(parent: &mut S, idx: u64, ctx: &mut TxContext) { + let child: S = ofield::remove(&mut parent.id, idx); + ofield::add(&mut parent.id, idx, R { id: iota::object::new(ctx), s: child }) + } + + public entry fun delete(s: S) { + let S { id } = s; + iota::object::delete(id) + } + + public entry fun wrap(s: S, ctx: &mut TxContext) { + let r = R { id: iota::object::new(ctx), s }; + iota::transfer::public_transfer(r, tx_context::sender(ctx)) + } + + public entry fun freeze_object(s: S) { + iota::transfer::public_freeze_object(s) + } +} + +//# run test::m::mint --sender A + +//# run test::m::add --sender A --args object(2,0) 0 + +//# view-object 2,0 + +//# run test::m::freeze_object --sender A --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_valid.exp b/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_valid.exp similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_valid.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_valid.exp index 58f6756a6e2..03949a77843 100644 --- a/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_valid.exp +++ b/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_valid.exp @@ -21,7 +21,7 @@ gas summary: computation_cost: 1000000, storage_cost: 5859600, storage_rebate: task 4 'view-object'. lines 67-67: Owner: Account Address ( A ) Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 5 'run'. lines 69-69: mutated: object(0,0), object(2,0) diff --git a/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_valid.move b/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_valid.move new file mode 100644 index 00000000000..391329ca8dd --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_valid.move @@ -0,0 +1,72 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// DEPRECATED child count no longer tracked +// tests valid freezing of an object that has children + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct S has key, store { + id: iota::object::UID, + } + + public struct R has key, store { + id: iota::object::UID, + s: S, + } + + public entry fun mint(ctx: &mut TxContext) { + let id = iota::object::new(ctx); + iota::transfer::public_transfer(S { id }, tx_context::sender(ctx)) + } + + public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { + let child = S { id: iota::object::new(ctx) }; + ofield::add(&mut parent.id, idx, child); + } + + public entry fun remove(parent: &mut S, idx: u64) { + let S { id } = ofield::remove(&mut parent.id, idx); + iota::object::delete(id) + } + + public entry fun remove_and_add(parent: &mut S, idx: u64) { + let child: S = ofield::remove(&mut parent.id, idx); + ofield::add(&mut parent.id, idx, child) + } + + public entry fun remove_and_wrap(parent: &mut S, idx: u64, ctx: &mut TxContext) { + let child: S = ofield::remove(&mut parent.id, idx); + ofield::add(&mut parent.id, idx, R { id: iota::object::new(ctx), s: child }) + } + + public entry fun delete(s: S) { + let S { id } = s; + iota::object::delete(id) + } + + public entry fun wrap(s: S, ctx: &mut TxContext) { + let r = R { id: iota::object::new(ctx), s }; + iota::transfer::public_transfer(r, tx_context::sender(ctx)) + } + + public entry fun freeze_object(s: S) { + iota::transfer::public_freeze_object(s) + } +} + +//# run test::m::mint --sender A + +//# run test::m::add --sender A --args object(2,0) 0 + +//# view-object 2,0 + +//# run test::m::remove --sender A --args object(2,0) 0 + +//# run test::m::freeze_object --sender A --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_valid_one_txn.exp b/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_valid_one_txn.exp similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_valid_one_txn.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_valid_one_txn.exp index 1a7f583be32..81be0cfdc24 100644 --- a/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_valid_one_txn.exp +++ b/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_valid_one_txn.exp @@ -21,7 +21,7 @@ gas summary: computation_cost: 1000000, storage_cost: 5859600, storage_rebate: task 4 'view-object'. lines 70-70: Owner: Account Address ( A ) Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 5 'run'. lines 72-72: mutated: object(0,0), object(2,0) diff --git a/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_valid_one_txn.move b/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_valid_one_txn.move new file mode 100644 index 00000000000..411a108266b --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/child_count/freeze_parent_valid_one_txn.move @@ -0,0 +1,73 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// DEPRECATED child count no longer tracked +// tests valid freezing of an object that has children +// child is deleted and parent is frozen in one transaction + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct S has key, store { + id: iota::object::UID, + } + + public struct R has key, store { + id: iota::object::UID, + s: S, + } + + public entry fun mint(ctx: &mut TxContext) { + let id = iota::object::new(ctx); + iota::transfer::public_transfer(S { id }, tx_context::sender(ctx)) + } + + public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { + let child = S { id: iota::object::new(ctx) }; + ofield::add(&mut parent.id, idx, child); + } + + public entry fun remove(parent: &mut S, idx: u64) { + let S { id } = ofield::remove(&mut parent.id, idx); + iota::object::delete(id) + } + + public entry fun remove_and_add(parent: &mut S, idx: u64) { + let child: S = ofield::remove(&mut parent.id, idx); + ofield::add(&mut parent.id, idx, child) + } + + public entry fun remove_and_wrap(parent: &mut S, idx: u64, ctx: &mut TxContext) { + let child: S = ofield::remove(&mut parent.id, idx); + ofield::add(&mut parent.id, idx, R { id: iota::object::new(ctx), s: child }) + } + + public entry fun delete(s: S) { + let S { id } = s; + iota::object::delete(id) + } + + public entry fun wrap(s: S, ctx: &mut TxContext) { + let r = R { id: iota::object::new(ctx), s }; + iota::transfer::public_transfer(r, tx_context::sender(ctx)) + } + + public entry fun remove_and_freeze(mut s: S, idx: u64) { + let S { id } = ofield::remove(&mut s.id, idx); + iota::object::delete(id); + iota::transfer::public_freeze_object(s) + } +} + +//# run test::m::mint --sender A + +//# run test::m::add --sender A --args object(2,0) 0 + +//# view-object 2,0 + +//# run test::m::remove_and_freeze --sender A --args object(2,0) 0 diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid.exp b/crates/iota-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid.exp similarity index 85% rename from crates/sui-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid.exp index a144cbc168c..557e110ca83 100644 --- a/crates/sui-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid.exp +++ b/crates/iota-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 5859600, storage_rebate: task 3 'view-object'. lines 49-53: Owner: Shared Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 4 'run'. lines 55-55: created: object(4,0), object(4,1), object(4,2) @@ -30,7 +30,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: task 6 'view-object'. lines 59-63: Owner: Account Address ( B ) Version: 4 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(4,2)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(4,2)}}} task 7 'run'. lines 65-65: created: object(7,0), object(7,1), object(7,2) @@ -44,4 +44,4 @@ gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: task 9 'view-object'. lines 69-69: Owner: Account Address ( B ) Version: 6 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(7,1)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(7,1)}}} diff --git a/crates/iota-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid.move b/crates/iota-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid.move new file mode 100644 index 00000000000..689e4bfb13d --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid.move @@ -0,0 +1,70 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// DEPRECATED child count no longer tracked +// tests valid transfers of an object that has children + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct S has key, store { + id: iota::object::UID, + } + + public struct R has key, store { + id: iota::object::UID, + s: S, + } + + public entry fun mint(ctx: &mut TxContext) { + let mut id = iota::object::new(ctx); + let child = S { id: iota::object::new(ctx) }; + ofield::add(&mut id, 0, child); + iota::transfer::public_transfer(S { id }, tx_context::sender(ctx)) + } + + public entry fun mint_and_share(ctx: &mut TxContext) { + let mut id = iota::object::new(ctx); + let child = S { id: iota::object::new(ctx) }; + ofield::add(&mut id, 0, child); + iota::transfer::public_share_object(S { id }) + } + + public entry fun transfer(s: S, recipient: address) { + iota::transfer::public_transfer(s, recipient) + } + +} + +// +// Test share object allows non-zero child count +// + +//# run test::m::mint_and_share --sender A + +//# view-object 2,1 + +// +// Test transfer allows non-zero child count +// + +//# run test::m::mint --sender A + +//# run test::m::transfer --sender A --args object(4,2) @B + +//# view-object 4,2 + +// +// Test TransferObject allows non-zero child count +// + +//# run test::m::mint --sender A + +//# transfer-object 7,1 --sender A --recipient B + +//# view-object 7,1 diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid_one_txn.exp b/crates/iota-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid_one_txn.exp similarity index 85% rename from crates/sui-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid_one_txn.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid_one_txn.exp index b33f37e59ce..d422709b327 100644 --- a/crates/sui-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid_one_txn.exp +++ b/crates/iota-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid_one_txn.exp @@ -16,4 +16,4 @@ gas summary: computation_cost: 1000000, storage_cost: 5859600, storage_rebate: task 3 'view-object'. lines 39-39: Owner: Shared Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} diff --git a/crates/iota-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid_one_txn.move b/crates/iota-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid_one_txn.move new file mode 100644 index 00000000000..53ea5e793ec --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid_one_txn.move @@ -0,0 +1,40 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// DEPRECATED child count no longer tracked +// tests valid transfers of an object that has children +// all transfers done in a single transaction + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct S has key, store { + id: iota::object::UID, + } + + public struct R has key, store { + id: iota::object::UID, + s: S, + } + + public entry fun share(ctx: &mut TxContext) { + let mut id = iota::object::new(ctx); + let child = S { id: iota::object::new(ctx) }; + ofield::add(&mut id, 0, child); + iota::transfer::public_share_object(S { id }) + } + +} + +// +// Test share object allows non-zero child count +// + +//# run test::m::share --sender A + +//# view-object 2,1 diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/temp_parent_invalid.exp b/crates/iota-adapter-transactional-tests/tests/child_count/temp_parent_invalid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/child_count/temp_parent_invalid.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/temp_parent_invalid.exp diff --git a/crates/iota-adapter-transactional-tests/tests/child_count/temp_parent_invalid.move b/crates/iota-adapter-transactional-tests/tests/child_count/temp_parent_invalid.move new file mode 100644 index 00000000000..1e9092388a2 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/child_count/temp_parent_invalid.move @@ -0,0 +1,25 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// DEPRECATED child count no longer tracked +// tests the invalid creation and deletion of a parent object + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::m { + public struct S has key, store { + id: iota::object::UID, + } + + public entry fun t(ctx: &mut TxContext) { + let mut parent = iota::object::new(ctx); + let child = S { id: iota::object::new(ctx) }; + iota::dynamic_object_field::add(&mut parent, 0, child); + iota::object::delete(parent); + } +} + +//# run test::m::t --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/unwrap_never_stored.exp b/crates/iota-adapter-transactional-tests/tests/child_count/unwrap_never_stored.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/child_count/unwrap_never_stored.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/unwrap_never_stored.exp diff --git a/crates/iota-adapter-transactional-tests/tests/child_count/unwrap_never_stored.move b/crates/iota-adapter-transactional-tests/tests/child_count/unwrap_never_stored.move new file mode 100644 index 00000000000..d9b5db9c443 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/child_count/unwrap_never_stored.move @@ -0,0 +1,42 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// DEPRECATED child count no longer tracked +// tests deleting a wrapped object that has never been in storage + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::m { + public struct S has key, store { + id: iota::object::UID, + } + + public struct R has key { + id: iota::object::UID, + s: S, + } + + public entry fun create(ctx: &mut TxContext) { + let parent = iota::object::new(ctx); + let child = S { id: iota::object::new(ctx) }; + iota::transfer::transfer(R { id: parent, s: child }, tx_context::sender(ctx)) + } + + public entry fun delete(r: R) { + let R { id, s } = r; + iota::object::delete(id); + let S { id } = s; + iota::object::delete(id); + } +} + +// +// Test sharing +// + +//# run test::m::create --sender A + +//# run test::m::delete --args object(2,0) --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/unwrap_never_stored_transfer.exp b/crates/iota-adapter-transactional-tests/tests/child_count/unwrap_never_stored_transfer.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/child_count/unwrap_never_stored_transfer.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/unwrap_never_stored_transfer.exp diff --git a/crates/iota-adapter-transactional-tests/tests/child_count/unwrap_never_stored_transfer.move b/crates/iota-adapter-transactional-tests/tests/child_count/unwrap_never_stored_transfer.move new file mode 100644 index 00000000000..6bb28e0739f --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/child_count/unwrap_never_stored_transfer.move @@ -0,0 +1,41 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// DEPRECATED child count no longer tracked +// tests transferring a wrapped object that has never previously been in storage + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::m { + public struct S has key, store { + id: iota::object::UID, + } + + public struct R has key { + id: iota::object::UID, + s: S, + } + + public entry fun create(ctx: &mut TxContext) { + let parent = iota::object::new(ctx); + let child = S { id: iota::object::new(ctx) }; + iota::transfer::transfer(R { id: parent, s: child }, tx_context::sender(ctx)) + } + + public entry fun unwrap_and_transfer(r: R, ctx: &mut TxContext) { + let R { id, s } = r; + iota::object::delete(id); + iota::transfer::transfer(s, tx_context::sender(ctx)); + } +} + +// +// Test sharing +// + +//# run test::m::create --sender A + +//# run test::m::unwrap_and_transfer --args object(2,0) --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/unwrap_then_delete_invalid.exp b/crates/iota-adapter-transactional-tests/tests/child_count/unwrap_then_delete_invalid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/child_count/unwrap_then_delete_invalid.exp rename to crates/iota-adapter-transactional-tests/tests/child_count/unwrap_then_delete_invalid.exp diff --git a/crates/iota-adapter-transactional-tests/tests/child_count/unwrap_then_delete_invalid.move b/crates/iota-adapter-transactional-tests/tests/child_count/unwrap_then_delete_invalid.move new file mode 100644 index 00000000000..538d11ed4dd --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/child_count/unwrap_then_delete_invalid.move @@ -0,0 +1,51 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// DEPRECATED child count no longer tracked +// tests invalid deletion of an object that has children + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct S has key, store { + id: iota::object::UID, + } + + public struct R has key { + id: iota::object::UID, + s: S, + } + + public entry fun mint(ctx: &mut TxContext) { + let s = S { id: iota::object::new(ctx) }; + iota::transfer::transfer(s, tx_context::sender(ctx)) + } + + public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { + let child = S { id: iota::object::new(ctx) }; + ofield::add(&mut parent.id, idx, child); + } + + public entry fun wrap(s: S, ctx: &mut TxContext) { + let r = R { id: iota::object::new(ctx), s }; + iota::transfer::transfer(r, tx_context::sender(ctx)) + } + + public entry fun delete(r: R) { + let R { id, s } = r; + iota::object::delete(id); + let S { id } = s; + iota::object::delete(id); + } +} + +//# run test::m::mint --sender A + +//# run test::m::add --sender A --args object(2,0) 0 + +//# run test::m::wrap --sender A --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/children/child_of_shared_object.exp b/crates/iota-adapter-transactional-tests/tests/children/child_of_shared_object.exp similarity index 88% rename from crates/sui-adapter-transactional-tests/tests/children/child_of_shared_object.exp rename to crates/iota-adapter-transactional-tests/tests/children/child_of_shared_object.exp index 9a0c652f7b0..40554ef2a2a 100644 --- a/crates/sui-adapter-transactional-tests/tests/children/child_of_shared_object.exp +++ b/crates/iota-adapter-transactional-tests/tests/children/child_of_shared_object.exp @@ -31,12 +31,12 @@ gas summary: computation_cost: 1000000, storage_cost: 5920400, storage_rebate: task 6 'view-object'. lines 78-78: Owner: Object ID: ( fake(5,0) ) Version: 3 -Contents: t3::o3::Obj3 {id: sui::object::UID {id: sui::object::ID {bytes: fake(4,0)}}} +Contents: t3::o3::Obj3 {id: iota::object::UID {id: iota::object::ID {bytes: fake(4,0)}}} task 7 'view-object'. lines 80-82: Owner: Shared Version: 3 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(5,1)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(5,1)}}} task 8 'run'. lines 83-83: Error: Error checking transaction input objects: InvalidChildObjectArgument { child_id: object(4,0), parent_id: object(5,0) } diff --git a/crates/sui-adapter-transactional-tests/tests/children/child_of_shared_object.move b/crates/iota-adapter-transactional-tests/tests/children/child_of_shared_object.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/children/child_of_shared_object.move rename to crates/iota-adapter-transactional-tests/tests/children/child_of_shared_object.move index ac7c6d7d7e1..8f38ec3cdbb 100644 --- a/crates/sui-adapter-transactional-tests/tests/children/child_of_shared_object.move +++ b/crates/iota-adapter-transactional-tests/tests/children/child_of_shared_object.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses t1=0x0 t2=0x0 t3=0x0 --accounts A @@ -39,7 +40,7 @@ module t2::o2 { fun new(child: Obj3, ctx: &mut TxContext): Obj2 { let mut id = object::new(ctx); - sui::dynamic_object_field::add(&mut id, 0, child); + iota::dynamic_object_field::add(&mut id, 0, child); Obj2 { id } } } @@ -66,7 +67,7 @@ module t1::o1 { fun new(child: Obj2, ctx: &mut TxContext): Obj1 { let mut id = object::new(ctx); - sui::dynamic_object_field::add(&mut id, 0, child); + iota::dynamic_object_field::add(&mut id, 0, child); Obj1 { id } } } diff --git a/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_and_undeny.exp b/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_and_undeny.exp new file mode 100644 index 00000000000..c53e57a4e50 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_and_undeny.exp @@ -0,0 +1,62 @@ +processed 14 tasks + +init: +A: object(0,0), B: object(0,1) + +task 1 'publish'. lines 12-34: +created: object(1,0), object(1,1), object(1,2), object(1,3), object(1,4), object(1,5) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 18316000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'view-object'. lines 36-36: +1,0::regulated_coin + +task 3 'view-object'. lines 38-38: +Owner: Account Address ( A ) +Version: 2 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,1)}}, balance: iota::balance::Balance {value: 10000u64}} + +task 4 'view-object'. lines 40-40: +Owner: Immutable +Version: 2 +Contents: iota::coin::CoinMetadata {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,2)}}, decimals: 9u8, name: std::string::String {bytes: vector[82u8, 69u8, 71u8, 85u8, 76u8, 65u8, 84u8, 69u8, 68u8, 95u8, 67u8, 79u8, 73u8, 78u8]}, symbol: std::ascii::String {bytes: vector[82u8, 67u8]}, description: std::string::String {bytes: vector[65u8, 32u8, 110u8, 101u8, 119u8, 32u8, 114u8, 101u8, 103u8, 117u8, 108u8, 97u8, 116u8, 101u8, 100u8, 32u8, 99u8, 111u8, 105u8, 110u8]}, icon_url: std::option::Option {vec: vector[]}} + +task 5 'view-object'. lines 42-42: +Owner: Account Address ( A ) +Version: 2 +Contents: iota::coin::DenyCap {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,3)}}} + +task 6 'view-object'. lines 44-44: +Owner: Immutable +Version: 2 +Contents: iota::coin::RegulatedCoinMetadata {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,4)}}, coin_metadata_object: iota::object::ID {bytes: fake(1,2)}, deny_cap_object: iota::object::ID {bytes: fake(1,3)}} + +task 7 'view-object'. lines 46-48: +Owner: Immutable +Version: 2 +Contents: iota::coin::TreasuryCap {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,5)}}, total_supply: iota::balance::Supply {value: 10000u64}} + +task 8 'run'. lines 49-51: +created: object(8,0) +mutated: object(0,0), object(1,1) +gas summary: computation_cost: 1000000, storage_cost: 3936800, storage_rebate: 2437776, non_refundable_storage_fee: 24624 + +task 9 'run'. lines 52-54: +created: object(9,0), object(9,1) +mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000403, object(0,0), object(1,3) +gas summary: computation_cost: 1000000, storage_cost: 11415200, storage_rebate: 2723688, non_refundable_storage_fee: 27512 + +task 10 'transfer-object'. lines 55-57: +Error: Error checking transaction input objects: AddressDeniedForCoin { address: @B, coin_type: "object(1,0)::regulated_coin::REGULATED_COIN" } + +task 11 'run'. lines 58-60: +Error: Error checking transaction input objects: AddressDeniedForCoin { address: @B, coin_type: "object(1,0)::regulated_coin::REGULATED_COIN" } + +task 12 'run'. lines 61-63: +mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000403, object(0,0), object(1,3), object(9,1) +deleted: object(9,0) +gas summary: computation_cost: 1000000, storage_cost: 9522800, storage_rebate: 11301048, non_refundable_storage_fee: 114152 + +task 13 'transfer-object'. lines 64-64: +mutated: object(0,1), object(8,0) +gas summary: computation_cost: 1000000, storage_cost: 2462400, storage_rebate: 1459656, non_refundable_storage_fee: 14744 diff --git a/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_and_undeny.move b/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_and_undeny.move new file mode 100644 index 00000000000..113d3c2fb81 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_and_undeny.move @@ -0,0 +1,65 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// This test verifies the basic e2e work flow of coin deny list. +// A newly created regulated coin type should come with the deny cap object. +// Coin isser can use the deny cap to deny addresses, which will no longer be able to +// transfer the coin or use it in Move calls. +// Undeny the address will restore the original behavior. + +//# init --accounts A B --addresses test=0x0 + +//# publish --sender A +module test::regulated_coin { + use iota::coin; + + public struct REGULATED_COIN has drop {} + + fun init(otw: REGULATED_COIN, ctx: &mut TxContext) { + let (mut treasury_cap, deny_cap, metadata) = coin::create_regulated_currency( + otw, + 9, + b"RC", + b"REGULATED_COIN", + b"A new regulated coin", + option::none(), + ctx + ); + let coin = coin::mint(&mut treasury_cap, 10000, ctx); + transfer::public_transfer(coin, tx_context::sender(ctx)); + transfer::public_transfer(deny_cap, tx_context::sender(ctx)); + transfer::public_freeze_object(treasury_cap); + transfer::public_freeze_object(metadata); + } +} + +//# view-object 1,0 + +//# view-object 1,1 + +//# view-object 1,2 + +//# view-object 1,3 + +//# view-object 1,4 + +//# view-object 1,5 + +// Transfer away the newly minted coin works normally. +//# run iota::pay::split_and_transfer --args object(1,1) 1 @B --type-args test::regulated_coin::REGULATED_COIN --sender A + +// Deny account B. +//# run iota::coin::deny_list_add --args object(0x403) object(1,3) @B --type-args test::regulated_coin::REGULATED_COIN --sender A + +// Try transfer the coin from B. This should now be denied. +//# transfer-object 8,0 --sender B --recipient A + +// Try using the coin in a Move call. This should also be denied. +//# run iota::pay::split_and_transfer --args object(8,0) 1 @A --type-args test::regulated_coin::REGULATED_COIN --sender B + +// Undeny account B. +//# run iota::coin::deny_list_remove --args object(0x403) object(1,3) @B --type-args test::regulated_coin::REGULATED_COIN --sender A + +// This time the transfer should work. +//# transfer-object 8,0 --sender B --recipient A diff --git a/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_multiple_per_module.exp b/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_multiple_per_module.exp new file mode 100644 index 00000000000..642b636333b --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_multiple_per_module.exp @@ -0,0 +1,74 @@ +processed 16 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 9-54: +created: object(1,0), object(1,1), object(1,2), object(1,3), object(1,4), object(1,5), object(1,6), object(1,7), object(1,8), object(1,9), object(1,10) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 33082800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'view-object'. lines 56-56: +1,0::{first_coin, second_coin} + +task 3 'view-object'. lines 58-58: +Owner: Account Address ( A ) +Version: 2 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,1)}}, balance: iota::balance::Balance {value: 10000u64}} + +task 4 'view-object'. lines 60-60: +Owner: Account Address ( A ) +Version: 2 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,2)}}, balance: iota::balance::Balance {value: 10000u64}} + +task 5 'view-object'. lines 62-62: +Owner: Immutable +Version: 2 +Contents: iota::coin::CoinMetadata {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,3)}}, decimals: 9u8, name: std::string::String {bytes: vector[82u8, 69u8, 71u8, 85u8, 76u8, 65u8, 84u8, 69u8, 68u8, 95u8, 67u8, 79u8, 73u8, 78u8]}, symbol: std::ascii::String {bytes: vector[82u8, 67u8]}, description: std::string::String {bytes: vector[65u8, 32u8, 110u8, 101u8, 119u8, 32u8, 114u8, 101u8, 103u8, 117u8, 108u8, 97u8, 116u8, 101u8, 100u8, 32u8, 99u8, 111u8, 105u8, 110u8]}, icon_url: std::option::Option {vec: vector[]}} + +task 6 'view-object'. lines 64-64: +Owner: Immutable +Version: 2 +Contents: iota::coin::CoinMetadata {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,4)}}, decimals: 9u8, name: std::string::String {bytes: vector[82u8, 69u8, 71u8, 85u8, 76u8, 65u8, 84u8, 69u8, 68u8, 95u8, 67u8, 79u8, 73u8, 78u8]}, symbol: std::ascii::String {bytes: vector[82u8, 67u8]}, description: std::string::String {bytes: vector[65u8, 32u8, 110u8, 101u8, 119u8, 32u8, 114u8, 101u8, 103u8, 117u8, 108u8, 97u8, 116u8, 101u8, 100u8, 32u8, 99u8, 111u8, 105u8, 110u8]}, icon_url: std::option::Option {vec: vector[]}} + +task 7 'view-object'. lines 66-66: +Owner: Account Address ( A ) +Version: 2 +Contents: iota::coin::DenyCap {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,5)}}} + +task 8 'view-object'. lines 68-68: +Owner: Account Address ( A ) +Version: 2 +Contents: iota::coin::DenyCap {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,6)}}} + +task 9 'view-object'. lines 70-70: +Owner: Immutable +Version: 2 +Contents: iota::coin::RegulatedCoinMetadata {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,7)}}, coin_metadata_object: iota::object::ID {bytes: fake(1,3)}, deny_cap_object: iota::object::ID {bytes: fake(1,5)}} + +task 10 'view-object'. lines 72-72: +Owner: Immutable +Version: 2 +Contents: iota::coin::RegulatedCoinMetadata {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,8)}}, coin_metadata_object: iota::object::ID {bytes: fake(1,4)}, deny_cap_object: iota::object::ID {bytes: fake(1,6)}} + +task 11 'view-object'. lines 74-74: +Owner: Immutable +Version: 2 +Contents: iota::coin::TreasuryCap {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,9)}}, total_supply: iota::balance::Supply {value: 10000u64}} + +task 12 'view-object'. lines 76-78: +Owner: Immutable +Version: 2 +Contents: iota::coin::TreasuryCap {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,10)}}, total_supply: iota::balance::Supply {value: 10000u64}} + +task 13 'run'. lines 79-81: +created: object(13,0), object(13,1) +mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000403, object(0,0), object(1,5) +gas summary: computation_cost: 1000000, storage_cost: 11293600, storage_rebate: 2663496, non_refundable_storage_fee: 26904 + +task 14 'transfer-object'. lines 82-84: +Error: Error checking transaction input objects: AddressDeniedForCoin { address: @A, coin_type: "object(1,0)::first_coin::FIRST_COIN" } + +task 15 'transfer-object'. lines 85-85: +mutated: object(0,0), object(1,2) +gas summary: computation_cost: 1000000, storage_cost: 2416800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 diff --git a/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_multiple_per_module.move b/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_multiple_per_module.move similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_multiple_per_module.move rename to crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_multiple_per_module.move index 5d305f035db..7c61aacd4f6 100644 --- a/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_multiple_per_module.move +++ b/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_multiple_per_module.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // This test creates multiple coin types in the same module, and show that deny actions on one type does not affect @@ -8,7 +9,7 @@ //# publish --sender A module test::first_coin { - use sui::coin; + use iota::coin; public struct FIRST_COIN has drop {} @@ -31,7 +32,7 @@ module test::first_coin { } module test::second_coin { - use sui::coin; + use iota::coin; public struct SECOND_COIN has drop {} @@ -76,7 +77,7 @@ module test::second_coin { //# view-object 1,10 // Deny account A for FIRST_COIN. -//# run sui::coin::deny_list_add --args object(0x403) object(1,5) @A --type-args test::first_coin::FIRST_COIN --sender A +//# run iota::coin::deny_list_add --args object(0x403) object(1,5) @A --type-args test::first_coin::FIRST_COIN --sender A // Sending away first coin from A should fail. //# transfer-object 1,1 --sender A --recipient A diff --git a/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_tto.exp b/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_tto.exp new file mode 100644 index 00000000000..f916230b5d8 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_tto.exp @@ -0,0 +1,59 @@ +processed 13 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-46: +created: object(1,0), object(1,1), object(1,2), object(1,3), object(1,4), object(1,5), object(1,6) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 21766400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'view-object'. lines 48-48: +Owner: Account Address ( A ) +Version: 2 +Contents: test::regulated_coin::Wallet {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,0)}}} + +task 3 'view-object'. lines 50-50: +1,1::regulated_coin + +task 4 'view-object'. lines 52-52: +Owner: Account Address ( fake(1,0) ) +Version: 2 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,2)}}, balance: iota::balance::Balance {value: 10000u64}} + +task 5 'view-object'. lines 54-54: +Owner: Immutable +Version: 2 +Contents: iota::coin::CoinMetadata {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,3)}}, decimals: 9u8, name: std::string::String {bytes: vector[82u8, 69u8, 71u8, 85u8, 76u8, 65u8, 84u8, 69u8, 68u8, 95u8, 67u8, 79u8, 73u8, 78u8]}, symbol: std::ascii::String {bytes: vector[82u8, 67u8]}, description: std::string::String {bytes: vector[65u8, 32u8, 110u8, 101u8, 119u8, 32u8, 114u8, 101u8, 103u8, 117u8, 108u8, 97u8, 116u8, 101u8, 100u8, 32u8, 99u8, 111u8, 105u8, 110u8]}, icon_url: std::option::Option {vec: vector[]}} + +task 6 'view-object'. lines 56-56: +Owner: Account Address ( A ) +Version: 2 +Contents: iota::coin::DenyCap {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,4)}}} + +task 7 'view-object'. lines 58-58: +Owner: Immutable +Version: 2 +Contents: iota::coin::RegulatedCoinMetadata {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,5)}}, coin_metadata_object: iota::object::ID {bytes: fake(1,3)}, deny_cap_object: iota::object::ID {bytes: fake(1,4)}} + +task 8 'view-object'. lines 60-62: +Owner: Immutable +Version: 2 +Contents: iota::coin::TreasuryCap {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,6)}}, total_supply: iota::balance::Supply {value: 10000u64}} + +task 9 'run'. lines 63-65: +created: object(9,0), object(9,1) +mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000403, object(0,0), object(1,4) +gas summary: computation_cost: 1000000, storage_cost: 11415200, storage_rebate: 2723688, non_refundable_storage_fee: 27512 + +task 10 'run'. lines 66-68: +Error: Error checking transaction input objects: AddressDeniedForCoin { address: @A, coin_type: "object(1,1)::regulated_coin::REGULATED_COIN" } + +task 11 'run'. lines 69-71: +mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000403, object(0,0), object(1,4), object(9,1) +deleted: object(9,0) +gas summary: computation_cost: 1000000, storage_cost: 9522800, storage_rebate: 11301048, non_refundable_storage_fee: 114152 + +task 12 'run'. lines 72-72: +mutated: object(0,0), object(1,0), object(1,2) +gas summary: computation_cost: 1000000, storage_cost: 3807600, storage_rebate: 3769524, non_refundable_storage_fee: 38076 diff --git a/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_tto.move b/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_tto.move similarity index 82% rename from crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_tto.move rename to crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_tto.move index a9eb094f80d..08c4274cecd 100644 --- a/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_tto.move +++ b/crates/iota-adapter-transactional-tests/tests/deny_list/coin_deny_tto.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // This test verifies the deny list also applies to receiving coin objects. @@ -7,9 +8,9 @@ //# publish --sender A module test::regulated_coin { - use sui::coin; - use sui::coin::Coin; - use sui::transfer::Receiving; + use iota::coin; + use iota::coin::Coin; + use iota::transfer::Receiving; public struct REGULATED_COIN has drop {} @@ -60,13 +61,13 @@ module test::regulated_coin { //# view-object 1,6 // Deny account A. -//# run sui::coin::deny_list_add --args object(0x403) object(1,4) @A --type-args test::regulated_coin::REGULATED_COIN --sender A +//# run iota::coin::deny_list_add --args object(0x403) object(1,4) @A --type-args test::regulated_coin::REGULATED_COIN --sender A // Try to receive coin in Wallet. This should now fail. //# run test::regulated_coin::receive_coin --args object(1,0) receiving(1,2) --sender A // Undeny account A. -//# run sui::coin::deny_list_remove --args object(0x403) object(1,4) @A --type-args test::regulated_coin::REGULATED_COIN --sender A +//# run iota::coin::deny_list_remove --args object(0x403) object(1,4) @A --type-args test::regulated_coin::REGULATED_COIN --sender A // Try to receive coin in Wallet. This should now succeed. //# run test::regulated_coin::receive_coin --args object(1,0) receiving(1,2) --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/dev_inspect/load_old_object.exp b/crates/iota-adapter-transactional-tests/tests/dev_inspect/load_old_object.exp similarity index 90% rename from crates/sui-adapter-transactional-tests/tests/dev_inspect/load_old_object.exp rename to crates/iota-adapter-transactional-tests/tests/dev_inspect/load_old_object.exp index 295b1f2d5dd..931af7f352c 100644 --- a/crates/sui-adapter-transactional-tests/tests/dev_inspect/load_old_object.exp +++ b/crates/iota-adapter-transactional-tests/tests/dev_inspect/load_old_object.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2257200, storage_rebate: task 3 'view-object'. lines 36-36: Owner: Account Address ( A ) Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, value: 0u64} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, value: 0u64} task 4 'programmable'. lines 38-39: mutated: object(0,0), object(2,0) @@ -25,7 +25,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2257200, storage_rebate: task 5 'view-object'. lines 41-44: Owner: Account Address ( A ) Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, value: 112u64} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, value: 112u64} task 6 'programmable'. lines 46-47: mutated: object(_), object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/dev_inspect/load_old_object.move b/crates/iota-adapter-transactional-tests/tests/dev_inspect/load_old_object.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/dev_inspect/load_old_object.move rename to crates/iota-adapter-transactional-tests/tests/dev_inspect/load_old_object.move index 0d131481c8b..2151f502f59 100644 --- a/crates/sui-adapter-transactional-tests/tests/dev_inspect/load_old_object.move +++ b/crates/iota-adapter-transactional-tests/tests/dev_inspect/load_old_object.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // load an object at an old version diff --git a/crates/iota-adapter-transactional-tests/tests/dynamic_fields/add_duplicate.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/add_duplicate.exp new file mode 100644 index 00000000000..15c9cf5a704 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/add_duplicate.exp @@ -0,0 +1,18 @@ +processed 4 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 9-28: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 5867200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 30-30: +created: object(2,0), object(2,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 3678400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'run'. lines 32-32: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::dynamic_field::add (function index 0) at offset 15, Abort Code: 0 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 0, instruction: 15, function_name: Some("add") }, 0), source: Some(VMError { major_status: ABORTED, sub_status: Some(0), message: Some("iota::dynamic_field::add at offset 15"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 15)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/add_duplicate.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/add_duplicate.move similarity index 81% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/add_duplicate.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/add_duplicate.move index cca341711d6..01a77bd2109 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/add_duplicate.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/add_duplicate.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // similar to dynamic_field_tests but over multiple transactions, as this uses a different code path @@ -9,7 +10,7 @@ //# publish module a::m { -use sui::dynamic_field::add; +use iota::dynamic_field::add; public struct Obj has key { id: object::UID, @@ -18,7 +19,7 @@ public struct Obj has key { entry fun t1(ctx: &mut TxContext) { let mut id = object::new(ctx); add(&mut id, 0, 0); - sui::transfer::transfer(Obj { id }, ctx.sender()) + iota::transfer::transfer(Obj { id }, ctx.sender()) } entry fun t2(obj: &mut Obj) { diff --git a/crates/iota-adapter-transactional-tests/tests/dynamic_fields/add_duplicate_object.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/add_duplicate_object.exp new file mode 100644 index 00000000000..082dea12d08 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/add_duplicate_object.exp @@ -0,0 +1,18 @@ +processed 4 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 10-29: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 6026800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 31-31: +created: object(2,0), object(2,1), object(2,2) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'run'. lines 33-33: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::dynamic_field::add (function index 0) at offset 15, Abort Code: 0 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 0, instruction: 15, function_name: Some("add") }, 0), source: Some(VMError { major_status: ABORTED, sub_status: Some(0), message: Some("iota::dynamic_field::add at offset 15"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 15)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/add_duplicate_object.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/add_duplicate_object.move similarity index 81% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/add_duplicate_object.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/add_duplicate_object.move index a1f35b2e5a8..a7daeb2eaee 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/add_duplicate_object.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/add_duplicate_object.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // similar to dynamic_object_field_tests but over multiple transactions, @@ -10,7 +11,7 @@ //# publish module a::m { -use sui::dynamic_object_field::add; +use iota::dynamic_object_field::add; public struct Obj has key, store { id: object::UID, @@ -19,7 +20,7 @@ public struct Obj has key, store { entry fun t1(ctx: &mut TxContext) { let mut id = object::new(ctx); add(&mut id, 0, Obj { id: object::new(ctx) }); - sui::transfer::public_transfer(Obj { id }, ctx.sender()) + iota::transfer::public_transfer(Obj { id }, ctx.sender()) } entry fun t2(obj: &mut Obj, ctx: &mut TxContext) { diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/bench.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/bench.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/bench.exp rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/bench.exp diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/bench.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/bench.move similarity index 88% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/bench.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/bench.move index 6be94be8f5c..36e5ee4507d 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/bench.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/bench.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // similar to dynamic_field_tests but over multiple transactions, as this uses a different code path @@ -9,7 +10,7 @@ //# publish module a::m { -use sui::dynamic_field::{add, exists_with_type, borrow}; +use iota::dynamic_field::{add, exists_with_type, borrow}; public struct Obj has key { id: object::UID, @@ -17,7 +18,7 @@ public struct Obj has key { entry fun t0(ctx: &mut TxContext) { let id = object::new(ctx); - sui::transfer::transfer(Obj { id }, ctx.sender()) + iota::transfer::transfer(Obj { id }, ctx.sender()) } entry fun t1(obj: &mut Obj) { diff --git a/crates/iota-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type.exp new file mode 100644 index 00000000000..be69a917cad --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type.exp @@ -0,0 +1,22 @@ +processed 5 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 9-32: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 6505600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 34-34: +created: object(2,0), object(2,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 3678400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'run'. lines 36-36: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::dynamic_field::borrow_child_object (function index 11) at offset 0, Abort Code: 2 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(11), 0)] }), command: Some(0) } } + +task 4 'run'. lines 38-38: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::dynamic_field::borrow_child_object_mut (function index 12) at offset 0, Abort Code: 2 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 12, instruction: 0, function_name: Some("borrow_child_object_mut") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type.move similarity index 82% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type.move index bea5f567036..c24d11672b4 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // similar to dynamic_field_tests but over multiple transactions, as this uses a different code path @@ -9,7 +10,7 @@ //# publish module a::m { -use sui::dynamic_field::{add, borrow, borrow_mut}; +use iota::dynamic_field::{add, borrow, borrow_mut}; public struct Obj has key { id: object::UID, @@ -18,7 +19,7 @@ public struct Obj has key { entry fun t1(ctx: &mut TxContext) { let mut id = object::new(ctx); add(&mut id, 0, 0); - sui::transfer::transfer(Obj { id }, ctx.sender()) + iota::transfer::transfer(Obj { id }, ctx.sender()) } entry fun t2(obj: &mut Obj) { diff --git a/crates/iota-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type_object.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type_object.exp new file mode 100644 index 00000000000..a7b7f35fd55 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type_object.exp @@ -0,0 +1,22 @@ +processed 5 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 10-37: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 7075600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 39-39: +created: object(2,0), object(2,1), object(2,2) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'run'. lines 41-41: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::dynamic_field::borrow_child_object (function index 11) at offset 0, Abort Code: 2 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(11), 0)] }), command: Some(0) } } + +task 4 'run'. lines 43-43: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::dynamic_field::borrow_child_object_mut (function index 12) at offset 0, Abort Code: 2 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 12, instruction: 0, function_name: Some("borrow_child_object_mut") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type_object.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type_object.move similarity index 82% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type_object.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type_object.move index f4cca8d90e3..881eef3870b 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type_object.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type_object.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // similar to dynamic_object_field_tests but over multiple transactions, @@ -10,7 +11,7 @@ //# publish module a::m { -use sui::dynamic_object_field::{add, borrow, borrow_mut}; +use iota::dynamic_object_field::{add, borrow, borrow_mut}; public struct Obj has key, store { id: object::UID, @@ -23,7 +24,7 @@ public struct Fake has key, store { entry fun t1(ctx: &mut TxContext) { let mut id = object::new(ctx); add(&mut id, 0, Obj { id: object::new(ctx) }); - sui::transfer::public_transfer(Obj { id }, ctx.sender()) + iota::transfer::public_transfer(Obj { id }, ctx.sender()) } entry fun t2(obj: &mut Obj) { diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/dynamic_object_field_swap.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/dynamic_object_field_swap.exp similarity index 85% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/dynamic_object_field_swap.exp rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/dynamic_object_field_swap.exp index fd0d3053184..e867706260a 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/dynamic_object_field_swap.exp +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/dynamic_object_field_swap.exp @@ -26,7 +26,7 @@ gas summary: computation_cost: 1000000, storage_cost: 6224400, storage_rebate: task 5 'view-object'. lines 67-67: Owner: Object ID: ( fake(4,0) ) Version: 4 -Contents: test::m::Child {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, value: 0u64} +Contents: test::m::Child {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, value: 0u64} task 6 'run'. lines 69-69: created: object(6,0) @@ -37,4 +37,4 @@ gas summary: computation_cost: 1000000, storage_cost: 5251600, storage_rebate: task 7 'view-object'. lines 71-71: Owner: Account Address ( A ) Version: 5 -Contents: test::m::Child {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, value: 0u64} +Contents: test::m::Child {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, value: 0u64} diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/dynamic_object_field_swap.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/dynamic_object_field_swap.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/dynamic_object_field_swap.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/dynamic_object_field_swap.move index 56063125c6b..4ead3c32d22 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/dynamic_object_field_swap.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/dynamic_object_field_swap.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses test=0x0 --accounts A @@ -6,7 +7,7 @@ //# publish module test::m { - use sui::dynamic_object_field as ofield; + use iota::dynamic_object_field as ofield; public struct Outer has key { id: UID, diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/exhaustive.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/exhaustive.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/exhaustive.exp rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/exhaustive.exp diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/exhaustive.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/exhaustive.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/exhaustive.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/exhaustive.move index e85200a162a..bccef274fb9 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/exhaustive.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/exhaustive.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // similar to dynamic_field_tests but over multiple transactions, as this uses a different code path @@ -9,7 +10,7 @@ //# publish module a::m { -use sui::dynamic_field::{add, exists_with_type, borrow, borrow_mut, remove}; +use iota::dynamic_field::{add, exists_with_type, borrow, borrow_mut, remove}; public struct Obj has key { id: object::UID, @@ -17,7 +18,7 @@ public struct Obj has key { entry fun t0(ctx: &mut TxContext) { let id = object::new(ctx); - sui::transfer::transfer(Obj { id }, ctx.sender()) + iota::transfer::transfer(Obj { id }, ctx.sender()) } entry fun t1(obj: &mut Obj) { diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/exhaustive_object.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/exhaustive_object.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/exhaustive_object.exp rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/exhaustive_object.exp diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/exhaustive_object.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/exhaustive_object.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/exhaustive_object.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/exhaustive_object.move index 3bfa9aba382..613340d11d0 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/exhaustive_object.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/exhaustive_object.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // similar to dynamic_object_field_tests but over multiple transactions, @@ -10,7 +11,7 @@ //# publish module a::m { -use sui::dynamic_object_field::{add, exists_, borrow, borrow_mut, remove}; +use iota::dynamic_object_field::{add, exists_, borrow, borrow_mut, remove}; public struct Obj has key, store { id: UID, @@ -42,7 +43,7 @@ fun destroy(counter: Counter): u64 { entry fun t0(ctx: &mut TxContext) { let id = object::new(ctx); - sui::transfer::public_transfer(Obj { id }, ctx.sender()) + iota::transfer::public_transfer(Obj { id }, ctx.sender()) } entry fun t1(obj: &mut Obj, ctx: &mut TxContext) { diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/read_field_from_immutable.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/read_field_from_immutable.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/read_field_from_immutable.exp rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/read_field_from_immutable.exp diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/read_field_from_immutable.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/read_field_from_immutable.move similarity index 82% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/read_field_from_immutable.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/read_field_from_immutable.move index ed2f3f47c61..2802e91bccd 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/read_field_from_immutable.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/read_field_from_immutable.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // similar to dynamic_field_tests but over multiple transactions, as this uses a different code path @@ -9,7 +10,7 @@ //# publish module a::m { -use sui::dynamic_field::{add, borrow}; +use iota::dynamic_field::{add, borrow}; public struct Obj has key { id: object::UID, @@ -18,7 +19,7 @@ public struct Obj has key { entry fun add_then_freeze(ctx: &mut TxContext) { let mut id = object::new(ctx); add(&mut id, 0, 0); - sui::transfer::freeze_object(Obj { id }) + iota::transfer::freeze_object(Obj { id }) } entry fun read_from_frozen(obj: &Obj) { diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/receive_remove_add_back_and_remove_type.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/receive_remove_add_back_and_remove_type.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/receive_remove_add_back_and_remove_type.exp rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/receive_remove_add_back_and_remove_type.exp diff --git a/crates/iota-adapter-transactional-tests/tests/dynamic_fields/receive_remove_add_back_and_remove_type.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/receive_remove_add_back_and_remove_type.move new file mode 100644 index 00000000000..16e2a71794c --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/receive_remove_add_back_and_remove_type.move @@ -0,0 +1,104 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// This test attempts to receive two objects, remove a child, add it back, remove it again, and then transfer/delete it. +// This is an interesting test case because when child objects are removed, added back and removed again, +// they won't show up in the child_object_effects in the object runtiem. We must look at either transfers +// or deleted_object_ids to figure them out. + +//# init --addresses test=0x0 --accounts A + +//# publish +module test::m1 { + use iota::transfer::Receiving; + + public struct Object has key, store { + id: UID, + } + + public struct C1 has key, store { + id: UID, + } + + public struct C2 has key, store { + id: UID, + } + + public struct Wrapper has key, store { + id: UID, + value: T, + } + + public entry fun create(ctx: &mut TxContext) { + let o = Object { id: object::new(ctx) }; + let c1 = C1 { id: object::new(ctx) }; + let c2 = C2 { id: object::new(ctx) }; + let o_address = object::id_address(&o); + transfer::public_transfer(o, tx_context::sender(ctx)); + transfer::public_transfer(c1, o_address); + transfer::public_transfer(c2, o_address); + } + + public entry fun test_dof(parent: &mut Object, c1: Receiving, c2: Receiving) { + let c1 = transfer::receive(&mut parent.id, c1); + iota::dynamic_object_field::add(&mut parent.id, 0, c1); + let c1: C1 = iota::dynamic_object_field::remove(&mut parent.id, 0); + transfer::public_transfer(c1, @test); + + let c2 = transfer::receive(&mut parent.id, c2); + iota::dynamic_object_field::add(&mut parent.id, 0, c2); + let C2 { id } = iota::dynamic_object_field::remove(&mut parent.id, 0); + object::delete(id); + } + + public entry fun test_df(parent: &mut Object, c1: Receiving, c2: Receiving) { + let c1 = transfer::receive(&mut parent.id, c1); + iota::dynamic_field::add(&mut parent.id, 0, c1); + let c1: C1 = iota::dynamic_field::remove(&mut parent.id, 0); + transfer::public_transfer(c1, @test); + + let c2 = transfer::receive(&mut parent.id, c2); + iota::dynamic_field::add(&mut parent.id, 0, c2); + let C2 { id } = iota::dynamic_field::remove(&mut parent.id, 0); + object::delete(id); + } + + // Try to "wash" the receiving object through a dynamic object field and then wrap it in a wrapper object. + public entry fun test_dof_wrapper(parent: &mut Object, c1: Receiving, _c2: Receiving, ctx: &mut TxContext) { + let c1 = transfer::receive(&mut parent.id, c1); + iota::dynamic_object_field::add(&mut parent.id, 0, c1); + let c1: C1 = iota::dynamic_object_field::remove(&mut parent.id, 0); + let w = Wrapper { id: object::new(ctx), value: c1 }; + iota::dynamic_object_field::add(&mut parent.id, 0, w); + let w: Wrapper = iota::dynamic_object_field::remove(&mut parent.id, 0); + transfer::public_transfer(w, @test); + } + + // Try to "wash" the receiving object through a dynamic field and then wrap it in a wrapper object. + public entry fun test_df_wrapper(parent: &mut Object, c1: Receiving, _c2: Receiving, ctx: &mut TxContext) { + let c1 = transfer::receive(&mut parent.id, c1); + iota::dynamic_field::add(&mut parent.id, 0, c1); + let c1: C1 = iota::dynamic_field::remove(&mut parent.id, 0); + let w = Wrapper { id: object::new(ctx), value: c1 }; + iota::dynamic_field::add(&mut parent.id, 0, w); + let w: Wrapper = iota::dynamic_field::remove(&mut parent.id, 0); + transfer::public_transfer(w, @test); + } +} + +//# run test::m1::create --sender A + +//# run test::m1::test_dof --args object(2,2) receiving(2,0) receiving(2,1) --sender A + +//# run test::m1::create --sender A + +//# run test::m1::test_df --args object(4,2) receiving(4,0) receiving(4,1) --sender A + +//# run test::m1::create --sender A + +//# run test::m1::test_dof_wrapper --args object(6,2) receiving(6,0) receiving(6,1) --sender A + +//# run test::m1::create --sender A + +//# run test::m1::test_df_wrapper --args object(8,2) receiving(8,0) receiving(8,1) --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove.exp rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove.exp diff --git a/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove.move new file mode 100644 index 00000000000..4a3a349f483 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove.move @@ -0,0 +1,70 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// This test attempts to remove a child, add it back, remove it again, and then transfer/delete it. +// This is an interesting test case because when child objects are removed, added back and removed again, +// they won't show up in the child_object_effects in the object runtiem. We must look at either transfers +// or deleted_object_ids to figure them out. + +//# init --addresses test=0x0 --accounts A + +//# publish +module test::m1 { + public struct Object has key, store { + id: UID, + wrapped: Option, + } + + public struct Child has key, store { + id: UID, + } + + public entry fun create(ctx: &mut TxContext) { + let o = Object { id: object::new(ctx), wrapped: option::none() }; + transfer::public_transfer(o, tx_context::sender(ctx)) + } + + public entry fun add_child(parent: &mut Object, ctx: &mut TxContext) { + let child = Child { id: object::new(ctx) }; + iota::dynamic_object_field::add(&mut parent.id, 0, child); + } + + public fun transfer_child(parent: &mut Object, ctx: &TxContext) { + let child: Child = iota::dynamic_object_field::remove(&mut parent.id, 0); + iota::dynamic_object_field::add(&mut parent.id, 1, child); + let child: Child = iota::dynamic_object_field::remove(&mut parent.id, 1); + transfer::public_transfer(child, tx_context::sender(ctx)) + } + + public fun delete_child(parent: &mut Object) { + let child: Child = iota::dynamic_object_field::remove(&mut parent.id, 0); + iota::dynamic_object_field::add(&mut parent.id, 1, child); + let Child { id } = iota::dynamic_object_field::remove(&mut parent.id, 1); + object::delete(id); + } + + public fun wrap_child(parent: &mut Object) { + let child: Child = iota::dynamic_object_field::remove(&mut parent.id, 0); + iota::dynamic_object_field::add(&mut parent.id, 1, child); + let child = iota::dynamic_object_field::remove(&mut parent.id, 1); + option::fill(&mut parent.wrapped, child); + } +} + +//# run test::m1::create --sender A + +// transfer +//# run test::m1::add_child --args object(2,0) --sender A + +//# run test::m1::transfer_child --args object(2,0) --sender A + +// delete +//# run test::m1::add_child --args object(2,0) --sender A + +//# run test::m1::delete_child --args object(2,0) --sender A + +// wrap +//# run test::m1::add_child --args object(2,0) --sender A + +//# run test::m1::wrap_child --args object(2,0) --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove_type.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove_type.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove_type.exp rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove_type.exp diff --git a/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove_type.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove_type.move new file mode 100644 index 00000000000..4f002976c4d --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove_type.move @@ -0,0 +1,55 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// This test attempts to remove a child, add it back, remove it again, and then transfer/delete it. +// This is an interesting test case because when child objects are removed, added back and removed again, +// they won't show up in the child_object_effects in the object runtiem. We must look at either transfers +// or deleted_object_ids to figure them out. + +//# init --addresses test=0x0 --accounts A + +//# publish +module test::m1 { + public struct Object has key, store { + id: UID, + } + + public struct C1 has key, store { + id: UID, + } + + public struct C2 has key, store { + id: UID, + } + + public entry fun create(ctx: &mut TxContext) { + let o = Object { id: object::new(ctx) }; + transfer::public_transfer(o, tx_context::sender(ctx)) + } + + public entry fun test_dof(parent: &mut Object, ctx: &mut TxContext) { + let c1 = C1 { id: object::new(ctx) }; + iota::dynamic_object_field::add(&mut parent.id, 0, c1); + let C1 { id } = iota::dynamic_object_field::remove(&mut parent.id, 0); + object::delete(id); + + let c2 = C2 { id: object::new(ctx) }; + iota::dynamic_object_field::add(&mut parent.id, 0, c2); + let C2 { id } = iota::dynamic_object_field::remove(&mut parent.id, 0); + object::delete(id); + } + + public entry fun test_df(parent: &mut Object) { + iota::dynamic_field::add(&mut parent.id, 0, b"true"); + let _: vector = iota::dynamic_field::remove(&mut parent.id, 0); + iota::dynamic_field::add(&mut parent.id, 0, true); + let _: bool = iota::dynamic_field::remove(&mut parent.id, 0); + } +} + +//# run test::m1::create --sender A + +//# run test::m1::test_dof --args object(2,0) --sender A + +//# run test::m1::test_df --args object(2,0) --sender A diff --git a/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type.exp new file mode 100644 index 00000000000..bf34733a018 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type.exp @@ -0,0 +1,18 @@ +processed 4 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 9-29: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 6019200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 31-31: +created: object(2,0), object(2,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 3678400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'run'. lines 33-33: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::dynamic_field::remove_child_object (function index 13) at offset 0, Abort Code: 2 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 13, instruction: 0, function_name: Some("remove_child_object") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(13), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type.move similarity index 80% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type.move index d84ddf0c9f1..2fa2da47a43 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // similar to dynamic_field_tests but over multiple transactions, as this uses a different code path @@ -9,7 +10,7 @@ //# publish module a::m { -use sui::dynamic_field::{add, remove}; +use iota::dynamic_field::{add, remove}; public struct Obj has key { id: object::UID, @@ -18,7 +19,7 @@ public struct Obj has key { entry fun t1(ctx: &mut TxContext) { let mut id = object::new(ctx); add(&mut id, 0, 0); - sui::transfer::transfer(Obj { id }, ctx.sender()) + iota::transfer::transfer(Obj { id }, ctx.sender()) } entry fun t2(obj: &mut Obj) { diff --git a/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type_object.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type_object.exp new file mode 100644 index 00000000000..b9d9b113120 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type_object.exp @@ -0,0 +1,18 @@ +processed 4 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 10-34: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 6695600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 36-36: +created: object(2,0), object(2,1), object(2,2) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'run'. lines 38-38: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::dynamic_field::remove_child_object (function index 13) at offset 0, Abort Code: 2 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 13, instruction: 0, function_name: Some("remove_child_object") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(13), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type_object.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type_object.move similarity index 82% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type_object.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type_object.move index a169457dc88..7e1840b9f47 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type_object.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type_object.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // similar to dynamic_object_field_tests but over multiple transactions, @@ -10,7 +11,7 @@ //# publish module a::m { -use sui::dynamic_object_field::{add, remove}; +use iota::dynamic_object_field::{add, remove}; public struct Obj has key, store { id: object::UID, @@ -23,7 +24,7 @@ public struct Fake has key, store { entry fun t1(ctx: &mut TxContext) { let mut id = object::new(ctx); add(&mut id, 0, Obj { id: object::new(ctx) }); - sui::transfer::public_transfer(Obj { id }, ctx.sender()) + iota::transfer::public_transfer(Obj { id }, ctx.sender()) } entry fun t2(obj: &mut Obj) { diff --git a/crates/iota-adapter-transactional-tests/tests/dynamic_fields/shared_object.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/shared_object.exp new file mode 100644 index 00000000000..4b6dce1885a --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/shared_object.exp @@ -0,0 +1,41 @@ +processed 9 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-72: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 9690000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 74-74: +created: object(2,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2470000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'run'. lines 76-78: +created: object(3,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2287600, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 4 'run'. lines 79-79: +Error: Transaction Effects Status: The shared object operation is not allowed. +Debug of error: SharedObjectOperationNotAllowed at command None + +task 5 'view-object'. lines 81-81: +Owner: Shared +Version: 4 +Contents: test::m::Child {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, value: 0u64} + +task 6 'run'. lines 83-83: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::dynamic_field::borrow_child_object (function index 11) at offset 0, Abort Code: 1 +Debug of error: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) at command Some(0) + +task 7 'view-object'. lines 85-85: +Owner: Shared +Version: 4 +Contents: test::m::Child {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, value: 0u64} + +task 8 'run'. lines 87-87: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::dynamic_field::borrow_child_object (function index 11) at offset 0, Abort Code: 1 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1), source: Some(VMError { major_status: ABORTED, sub_status: Some(1), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(11), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/shared_object.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/shared_object.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/shared_object.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/shared_object.move index 6f21b197ddf..7645b096be9 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/shared_object.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/shared_object.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests adding a shared object as a dynamic field @@ -8,7 +9,7 @@ //# publish module test::m { - use sui::dynamic_object_field as ofield; + use iota::dynamic_object_field as ofield; public struct Outer has key { id: UID, diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/transfer_object.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/transfer_object.exp similarity index 80% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/transfer_object.exp rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/transfer_object.exp index 2b0aa95ade0..ade3ebca5ff 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/transfer_object.exp +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/transfer_object.exp @@ -46,5 +46,5 @@ mutated: object(0,0), object(3,0) gas summary: computation_cost: 1000000, storage_cost: 2211600, storage_rebate: 2189484, non_refundable_storage_fee: 22116 task 10 'run'. lines 83-83: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::dynamic_field::borrow_child_object_mut (function index 12) at offset 0, Abort Code: 1 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 12, instruction: 0, function_name: Some("borrow_child_object_mut") }, 1), source: Some(VMError { major_status: ABORTED, sub_status: Some(1), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::dynamic_field::borrow_child_object_mut (function index 12) at offset 0, Abort Code: 1 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 12, instruction: 0, function_name: Some("borrow_child_object_mut") }, 1), source: Some(VMError { major_status: ABORTED, sub_status: Some(1), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/transfer_object.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/transfer_object.move similarity index 90% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/transfer_object.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/transfer_object.move index 57a85c3d3b4..849a8585774 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/transfer_object.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/transfer_object.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // similar to dynamic_object_field_tests but over multiple transactions, @@ -10,7 +11,7 @@ //# publish module a::m { -use sui::dynamic_object_field::{add, borrow, borrow_mut, remove}; +use iota::dynamic_object_field::{add, borrow, borrow_mut, remove}; public struct Obj has key, store { id: UID, @@ -42,7 +43,7 @@ fun destroy(counter: Counter): u64 { entry fun create(ctx: &mut TxContext) { let id = object::new(ctx); - sui::transfer::public_transfer(Obj { id }, ctx.sender()) + iota::transfer::public_transfer(Obj { id }, ctx.sender()) } entry fun add_counter(obj: &mut Obj, ctx: &mut TxContext) { diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/unwrap_object.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/unwrap_object.exp similarity index 90% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/unwrap_object.exp rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/unwrap_object.exp index 9f2919fbd21..93119bde20f 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/unwrap_object.exp +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/unwrap_object.exp @@ -23,7 +23,7 @@ gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: task 4 'view-object'. lines 45-45: Owner: Object ID: ( fake(3,1) ) Version: 3 -Contents: a::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}} +Contents: a::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}} task 5 'run'. lines 48-48: created: object(5,0), object(5,1) @@ -50,4 +50,4 @@ gas summary: computation_cost: 1000000, storage_cost: 3435200, storage_rebate: task 9 'view-object'. lines 58-58: Owner: Account Address ( A ) Version: 7 -Contents: a::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(7,0)}}} +Contents: a::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(7,0)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/unwrap_object.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/unwrap_object.move similarity index 83% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/unwrap_object.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/unwrap_object.move index b86c16737f8..73cc21565b1 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/unwrap_object.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/unwrap_object.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // test unwrapping an object in a dynamic field @@ -8,8 +9,8 @@ //# publish module a::m { -use sui::dynamic_field; -use sui::dynamic_object_field; +use iota::dynamic_field; +use iota::dynamic_object_field; public struct Obj has key, store { id: object::UID, @@ -18,7 +19,7 @@ public struct Obj has key, store { entry fun mint(ctx: &mut TxContext) { let mut parent = object::new(ctx); dynamic_field::add(&mut parent, 0, Obj { id: object::new(ctx) }); - sui::transfer::public_transfer(Obj { id: parent }, ctx.sender()) + iota::transfer::public_transfer(Obj { id: parent }, ctx.sender()) } entry fun take_and_wrap(obj: &mut Obj) { @@ -33,7 +34,7 @@ entry fun take_and_destroy(obj: &mut Obj) { entry fun take_and_take(obj: &mut Obj, ctx: &mut TxContext) { let v = dynamic_field::remove(&mut obj.id, 0); - sui::transfer::public_transfer(v, ctx.sender()) + iota::transfer::public_transfer(v, ctx.sender()) } } diff --git a/crates/iota-adapter-transactional-tests/tests/dynamic_fields/wrap_object.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/wrap_object.exp new file mode 100644 index 00000000000..7bf1afd6d9e --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/wrap_object.exp @@ -0,0 +1,59 @@ +processed 12 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-39: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 7478400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 41-41: +created: object(2,0), object(2,1), object(2,2) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 43-43: +Owner: Object ID: ( fake(2,2) ) +Version: 2 +Contents: a::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 4 'run'. lines 45-45: +created: object(4,0) +mutated: object(0,0), object(2,0) +deleted: object(2,2) +wrapped: object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 4157200, storage_rebate: 5831100, non_refundable_storage_fee: 58900 + +task 5 'run'. lines 48-48: +created: object(5,0), object(5,1), object(5,2) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 6 'view-object'. lines 50-50: +Owner: Object ID: ( fake(5,1) ) +Version: 4 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(5,2)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(5,0)}} + +task 7 'run'. lines 52-52: +mutated: object(0,0), object(5,1) +deleted: object(5,0), object(5,2) +gas summary: computation_cost: 1000000, storage_cost: 2211600, storage_rebate: 5831100, non_refundable_storage_fee: 58900 + +task 8 'run'. lines 55-55: +created: object(8,0), object(8,1), object(8,2) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 9 'view-object'. lines 57-57: +Owner: Object ID: ( fake(8,0) ) +Version: 6 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(8,2)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(8,1)}} + +task 10 'run'. lines 59-59: +mutated: object(0,0), object(8,0), object(8,1) +deleted: object(8,2) +gas summary: computation_cost: 1000000, storage_cost: 3435200, storage_rebate: 5831100, non_refundable_storage_fee: 58900 + +task 11 'view-object'. lines 61-61: +No object at id 8,2 diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/wrap_object.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/wrap_object.move similarity index 83% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/wrap_object.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/wrap_object.move index 382839f7bac..eb33ddbfd18 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/wrap_object.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/wrap_object.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // test wrapping an object in a dynamic field @@ -8,8 +9,8 @@ //# publish module a::m { -use sui::dynamic_field; -use sui::dynamic_object_field; +use iota::dynamic_field; +use iota::dynamic_object_field; public struct Obj has key, store { id: object::UID, @@ -18,7 +19,7 @@ public struct Obj has key, store { entry fun mint(ctx: &mut TxContext) { let mut parent = object::new(ctx); dynamic_object_field::add(&mut parent, 0, Obj { id: object::new(ctx) }); - sui::transfer::public_transfer(Obj { id: parent }, ctx.sender()) + iota::transfer::public_transfer(Obj { id: parent }, ctx.sender()) } entry fun take_and_wrap(obj: &mut Obj) { @@ -33,7 +34,7 @@ entry fun take_and_destroy(obj: &mut Obj) { entry fun take_and_take(obj: &mut Obj, ctx: &mut TxContext) { let v = dynamic_object_field::remove(&mut obj.id, 0); - sui::transfer::public_transfer(v, ctx.sender()) + iota::transfer::public_transfer(v, ctx.sender()) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/wrapped_uid_after_delete.exp b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/wrapped_uid_after_delete.exp similarity index 77% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/wrapped_uid_after_delete.exp rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/wrapped_uid_after_delete.exp index 30886a31e26..1c644499e24 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/wrapped_uid_after_delete.exp +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/wrapped_uid_after_delete.exp @@ -31,7 +31,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2485200, storage_rebate: task 6 'view-object'. lines 92-92: Owner: Object ID: ( fake(2,0) ) Version: 4 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, name: 0u64, value: a::m::Counter {id: sui::object::UID {id: sui::object::ID {bytes: _}}, count: 1u64}} +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, name: 0u64, value: a::m::Counter {id: iota::object::UID {id: iota::object::ID {bytes: _}}, count: 1u64}} task 7 'run'. lines 94-94: mutated: object(0,0), object(5,0) @@ -46,4 +46,4 @@ gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 2 task 9 'view-object'. lines 98-98: Owner: Object ID: ( fake(2,0) ) Version: 4 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, name: 0u64, value: a::m::Counter {id: sui::object::UID {id: sui::object::ID {bytes: _}}, count: 1u64}} +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, name: 0u64, value: a::m::Counter {id: iota::object::UID {id: iota::object::ID {bytes: _}}, count: 1u64}} diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/wrapped_uid_after_delete.move b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/wrapped_uid_after_delete.move similarity index 89% rename from crates/sui-adapter-transactional-tests/tests/dynamic_fields/wrapped_uid_after_delete.move rename to crates/iota-adapter-transactional-tests/tests/dynamic_fields/wrapped_uid_after_delete.move index ad3d0f4bbcf..9ddfb596af9 100644 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/wrapped_uid_after_delete.move +++ b/crates/iota-adapter-transactional-tests/tests/dynamic_fields/wrapped_uid_after_delete.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // similar to dynamic_object_field_tests but over multiple transactions, @@ -10,7 +11,7 @@ //# publish module a::m { -use sui::dynamic_field::{add, exists_, borrow, borrow_mut}; +use iota::dynamic_field::{add, exists_, borrow, borrow_mut}; public struct Wrapper has key { id: UID, @@ -47,7 +48,7 @@ fun destroy(counter: Counter): u64 { entry fun t0(ctx: &mut TxContext) { let id = object::new(ctx); - sui::transfer::transfer(Obj { id }, ctx.sender()) + iota::transfer::transfer(Obj { id }, ctx.sender()) } entry fun t1(obj: &mut Obj, ctx: &mut TxContext) { @@ -64,7 +65,7 @@ entry fun t3(obj: Obj, ctx: &mut TxContext) { let Obj { id } = obj; assert!(count(borrow(&id, 0)) == 1, 0); let wrapper = Wrapper { id: object::new(ctx), old: id }; - sui::transfer::transfer(wrapper, ctx.sender()) + iota::transfer::transfer(wrapper, ctx.sender()) } entry fun t4(wrapper: &mut Wrapper) { diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/ascii.exp b/crates/iota-adapter-transactional-tests/tests/entry_points/ascii.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/entry_points/ascii.exp rename to crates/iota-adapter-transactional-tests/tests/entry_points/ascii.exp diff --git a/crates/iota-adapter-transactional-tests/tests/entry_points/ascii.move b/crates/iota-adapter-transactional-tests/tests/entry_points/ascii.move new file mode 100644 index 00000000000..2e82a3d5183 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/entry_points/ascii.move @@ -0,0 +1,48 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --addresses Test=0x0 --accounts A + +//# publish +module Test::M { + use std::ascii; + + public entry fun ascii_arg(s: ascii::String, _: &mut TxContext) { + assert!(ascii::length(&s) == 10, 0); + } + + public entry fun ascii_vec_arg(mut v: vector, _: &mut TxContext) { + let mut l = 0; + while (!vector::is_empty(&v)) { + let s = vector::pop_back(&mut v); + l = l + ascii::length(&s) + }; + assert!(l == 10, 0); + } + +} + +// string of ASCII characters as byte string + +//# run Test::M::ascii_arg --sender A --args b"SomeString" + + +// string of ASCII characters as UTF8 string + +//# run Test::M::ascii_arg --sender A --args "SomeString" + + +// vector of ASCII character strings as byte strings + +//# run Test::M::ascii_vec_arg --sender A --args vector[b"Some",b"String"] + + +// vector of ASCII character strings as UTF8 strings + +// run Test::M::ascii_vec_arg --sender A --args vector["Some","String"] + + +// error - a character out of ASCII range + +//# run Test::M::ascii_arg --sender A --args "Some∫tring" diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/generic_by_ref.exp b/crates/iota-adapter-transactional-tests/tests/entry_points/generic_by_ref.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/entry_points/generic_by_ref.exp rename to crates/iota-adapter-transactional-tests/tests/entry_points/generic_by_ref.exp diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/generic_by_ref.move b/crates/iota-adapter-transactional-tests/tests/entry_points/generic_by_ref.move similarity index 89% rename from crates/sui-adapter-transactional-tests/tests/entry_points/generic_by_ref.move rename to crates/iota-adapter-transactional-tests/tests/entry_points/generic_by_ref.move index db468132811..a2cc499dbc3 100644 --- a/crates/sui-adapter-transactional-tests/tests/entry_points/generic_by_ref.move +++ b/crates/iota-adapter-transactional-tests/tests/entry_points/generic_by_ref.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses test=0x0 --accounts A diff --git a/crates/iota-adapter-transactional-tests/tests/entry_points/generic_by_ref_invalid.exp b/crates/iota-adapter-transactional-tests/tests/entry_points/generic_by_ref_invalid.exp new file mode 100644 index 00000000000..1366cd0229c --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/entry_points/generic_by_ref_invalid.exp @@ -0,0 +1,20 @@ +processed 5 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-11: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &T0"), command: Some(0) } } + +task 2 'publish'. lines 13-16: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &mut T0"), command: Some(0) } } + +task 3 'publish'. lines 18-21: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &T0"), command: Some(0) } } + +task 4 'publish'. lines 23-26: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &mut T0"), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/generic_by_ref_invalid.move b/crates/iota-adapter-transactional-tests/tests/entry_points/generic_by_ref_invalid.move similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/entry_points/generic_by_ref_invalid.move rename to crates/iota-adapter-transactional-tests/tests/entry_points/generic_by_ref_invalid.move index 4a3b8d88ca9..2d0b731c5ce 100644 --- a/crates/sui-adapter-transactional-tests/tests/entry_points/generic_by_ref_invalid.move +++ b/crates/iota-adapter-transactional-tests/tests/entry_points/generic_by_ref_invalid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // entry functions cannot take primitives by ref, so the generic must be an object diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/imm_txn_context.exp b/crates/iota-adapter-transactional-tests/tests/entry_points/imm_txn_context.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/entry_points/imm_txn_context.exp rename to crates/iota-adapter-transactional-tests/tests/entry_points/imm_txn_context.exp diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/imm_txn_context.move b/crates/iota-adapter-transactional-tests/tests/entry_points/imm_txn_context.move similarity index 80% rename from crates/sui-adapter-transactional-tests/tests/entry_points/imm_txn_context.move rename to crates/iota-adapter-transactional-tests/tests/entry_points/imm_txn_context.move index b66398ef331..394f37eba42 100644 --- a/crates/sui-adapter-transactional-tests/tests/entry_points/imm_txn_context.move +++ b/crates/iota-adapter-transactional-tests/tests/entry_points/imm_txn_context.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test=0x0 --accounts A @@ -6,13 +7,13 @@ //# publish module Test::M { public struct Obj has key { - id: sui::object::UID, + id: iota::object::UID, value: u64 } public entry fun mint(ctx: &mut TxContext) { - sui::transfer::transfer( - Obj { id: sui::object::new(ctx), value: 0 }, + iota::transfer::transfer( + Obj { id: iota::object::new(ctx), value: 0 }, tx_context::sender(ctx), ) } diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/missing_type.exp b/crates/iota-adapter-transactional-tests/tests/entry_points/missing_type.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/entry_points/missing_type.exp rename to crates/iota-adapter-transactional-tests/tests/entry_points/missing_type.exp diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/missing_type.move b/crates/iota-adapter-transactional-tests/tests/entry_points/missing_type.move similarity index 81% rename from crates/sui-adapter-transactional-tests/tests/entry_points/missing_type.move rename to crates/iota-adapter-transactional-tests/tests/entry_points/missing_type.move index 8653b2559fb..90069c06db5 100644 --- a/crates/sui-adapter-transactional-tests/tests/entry_points/missing_type.move +++ b/crates/iota-adapter-transactional-tests/tests/entry_points/missing_type.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests invalid type args @@ -16,7 +17,7 @@ entry fun foo() {} //# run test::m::foo --type-args test::x::x -//# run test::m::foo --type-args test::m::SUI +//# run test::m::foo --type-args test::m::IOTA //# run test::m::foo --type-args test::m::S diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/no_txn_context.exp b/crates/iota-adapter-transactional-tests/tests/entry_points/no_txn_context.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/entry_points/no_txn_context.exp rename to crates/iota-adapter-transactional-tests/tests/entry_points/no_txn_context.exp diff --git a/crates/iota-adapter-transactional-tests/tests/entry_points/no_txn_context.move b/crates/iota-adapter-transactional-tests/tests/entry_points/no_txn_context.move new file mode 100644 index 00000000000..78d00325f76 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/entry_points/no_txn_context.move @@ -0,0 +1,28 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --addresses Test=0x0 --accounts A + +//# publish +module Test::M { + public struct Obj has key { + id: iota::object::UID, + value: u64 + } + + public entry fun mint(ctx: &mut TxContext) { + iota::transfer::transfer( + Obj { id: iota::object::new(ctx), value: 0 }, + tx_context::sender(ctx), + ) + } + + public entry fun incr(obj: &mut Obj) { + obj.value = obj.value + 1 + } +} + +//# run Test::M::mint --sender A + +//# run Test::M::incr --sender A --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector.exp b/crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector.exp rename to crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector.exp diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector.move b/crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector.move similarity index 98% rename from crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector.move rename to crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector.move index 48127f524bf..3c34fe31089 100644 --- a/crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector.move +++ b/crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests vector of objects @@ -38,7 +39,7 @@ module Test::M { } public entry fun mint_child(v: u64, parent: &mut Obj, ctx: &mut TxContext) { - sui::dynamic_object_field::add( + iota::dynamic_object_field::add( &mut parent.id, 0, Obj { id: object::new(ctx), diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_generic.exp b/crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_generic.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_generic.exp rename to crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_generic.exp diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_generic.move b/crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_generic.move similarity index 98% rename from crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_generic.move rename to crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_generic.move index cfb027a2e3e..9f2e2c3e17e 100644 --- a/crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_generic.move +++ b/crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_generic.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests vector of objects where operations involve generics (type parameters) @@ -40,7 +41,7 @@ module Test::M { } public entry fun mint_child_any(v: u64, parent: &mut ObjAny, ctx: &mut TxContext) { - sui::dynamic_object_field::add( + iota::dynamic_object_field::add( &mut parent.id, 0, ObjAny { diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_generic_v20.exp b/crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_generic_v20.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_generic_v20.exp rename to crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_generic_v20.exp diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_generic_v20.move b/crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_generic_v20.move similarity index 98% rename from crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_generic_v20.move rename to crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_generic_v20.move index ebb1faa718a..1ade95c91fb 100644 --- a/crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_generic_v20.move +++ b/crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_generic_v20.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests vector of objects where operations involve generics (type parameters) @@ -40,7 +41,7 @@ module Test::M { } public entry fun mint_child_any(v: u64, parent: &mut ObjAny, ctx: &mut TxContext) { - sui::dynamic_object_field::add( + iota::dynamic_object_field::add( &mut parent.id, 0, ObjAny { diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_v20.exp b/crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_v20.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_v20.exp rename to crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_v20.exp diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_v20.move b/crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_v20.move similarity index 98% rename from crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_v20.move rename to crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_v20.move index d38e195e6c9..d4496722844 100644 --- a/crates/sui-adapter-transactional-tests/tests/entry_points/obj_vector_v20.move +++ b/crates/iota-adapter-transactional-tests/tests/entry_points/obj_vector_v20.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests vector of objects @@ -38,7 +39,7 @@ module Test::M { } public entry fun mint_child(v: u64, parent: &mut Obj, ctx: &mut TxContext) { - sui::dynamic_object_field::add( + iota::dynamic_object_field::add( &mut parent.id, 0, Obj { id: object::new(ctx), diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/utf8.exp b/crates/iota-adapter-transactional-tests/tests/entry_points/utf8.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/entry_points/utf8.exp rename to crates/iota-adapter-transactional-tests/tests/entry_points/utf8.exp diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/utf8.move b/crates/iota-adapter-transactional-tests/tests/entry_points/utf8.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/entry_points/utf8.move rename to crates/iota-adapter-transactional-tests/tests/entry_points/utf8.move index 00691dcd3d9..e20bc73d3f0 100644 --- a/crates/sui-adapter-transactional-tests/tests/entry_points/utf8.move +++ b/crates/iota-adapter-transactional-tests/tests/entry_points/utf8.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/wrong_visibility.exp b/crates/iota-adapter-transactional-tests/tests/entry_points/wrong_visibility.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/entry_points/wrong_visibility.exp rename to crates/iota-adapter-transactional-tests/tests/entry_points/wrong_visibility.exp diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/wrong_visibility.move b/crates/iota-adapter-transactional-tests/tests/entry_points/wrong_visibility.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/entry_points/wrong_visibility.move rename to crates/iota-adapter-transactional-tests/tests/entry_points/wrong_visibility.move index c5decfb75f7..45dd36e8257 100644 --- a/crates/sui-adapter-transactional-tests/tests/entry_points/wrong_visibility.move +++ b/crates/iota-adapter-transactional-tests/tests/entry_points/wrong_visibility.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, the adapter should yell that the invoked functions have the wrong visibility diff --git a/crates/sui-adapter-transactional-tests/tests/init/entry.exp b/crates/iota-adapter-transactional-tests/tests/init/entry.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/init/entry.exp rename to crates/iota-adapter-transactional-tests/tests/init/entry.exp diff --git a/crates/iota-adapter-transactional-tests/tests/init/entry_new.exp b/crates/iota-adapter-transactional-tests/tests/init/entry_new.exp new file mode 100644 index 00000000000..6c43ee1f400 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/init/entry_new.exp @@ -0,0 +1,8 @@ +processed 3 tasks + +task 1 'publish'. lines 8-17: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m. 'init' cannot be 'entry'"), command: Some(0) } } + +task 2 'run'. lines 18-18: +Error: Error checking transaction input objects: DependentPackageNotFound { package_id: 0x0000000000000000000000000000000000000000000000000000000000000000 } diff --git a/crates/sui-adapter-transactional-tests/tests/init/entry_new.mvir b/crates/iota-adapter-transactional-tests/tests/init/entry_new.mvir similarity index 87% rename from crates/sui-adapter-transactional-tests/tests/init/entry_new.mvir rename to crates/iota-adapter-transactional-tests/tests/init/entry_new.mvir index d90ec98786e..329ece23994 100644 --- a/crates/sui-adapter-transactional-tests/tests/init/entry_new.mvir +++ b/crates/iota-adapter-transactional-tests/tests/init/entry_new.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // init with entry is no longer allowed diff --git a/crates/sui-adapter-transactional-tests/tests/init/entry_old.exp b/crates/iota-adapter-transactional-tests/tests/init/entry_old.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/init/entry_old.exp rename to crates/iota-adapter-transactional-tests/tests/init/entry_old.exp diff --git a/crates/sui-adapter-transactional-tests/tests/init/entry_old.mvir b/crates/iota-adapter-transactional-tests/tests/init/entry_old.mvir similarity index 89% rename from crates/sui-adapter-transactional-tests/tests/init/entry_old.mvir rename to crates/iota-adapter-transactional-tests/tests/init/entry_old.mvir index 1ed47f09a1e..83a1f2fa8e9 100644 --- a/crates/sui-adapter-transactional-tests/tests/init/entry_old.mvir +++ b/crates/iota-adapter-transactional-tests/tests/init/entry_old.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // init with entry used to be allowed @@ -31,7 +32,7 @@ module 0x0.m { // //# upgrade --package test --sender A --upgrade-capability 1,1 // module v2::m { -// use sui::tx_context::TxContext; +// use iota::tx_context::TxContext; // fun init(_: &mut TxContext) { // } diff --git a/crates/sui-adapter-transactional-tests/tests/sui/coin_in_vec.exp b/crates/iota-adapter-transactional-tests/tests/iota/coin_in_vec.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/sui/coin_in_vec.exp rename to crates/iota-adapter-transactional-tests/tests/iota/coin_in_vec.exp diff --git a/crates/sui-adapter-transactional-tests/tests/sui/coin_in_vec.move b/crates/iota-adapter-transactional-tests/tests/iota/coin_in_vec.move similarity index 81% rename from crates/sui-adapter-transactional-tests/tests/sui/coin_in_vec.move rename to crates/iota-adapter-transactional-tests/tests/iota/coin_in_vec.move index 4a57b8b73fb..24a5db7f214 100644 --- a/crates/sui-adapter-transactional-tests/tests/sui/coin_in_vec.move +++ b/crates/iota-adapter-transactional-tests/tests/iota/coin_in_vec.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses test=0x0 --accounts A @@ -6,19 +7,19 @@ //# publish --sender A module test::coin_in_vec { - use sui::coin::Coin; - use sui::sui::SUI; + use iota::coin::Coin; + use iota::iota::IOTA; public struct Wrapper has key { id: UID, - coins: vector>, + coins: vector>, } fun init(ctx: &mut TxContext) { transfer::transfer(Wrapper { id: object::new(ctx), coins: vector[] }, tx_context::sender(ctx)); } - public fun deposit(wrapper: &mut Wrapper, c: Coin) { + public fun deposit(wrapper: &mut Wrapper, c: Coin) { vector::push_back(&mut wrapper.coins, c) } diff --git a/crates/iota-adapter-transactional-tests/tests/iota/coin_transfer.exp b/crates/iota-adapter-transactional-tests/tests/iota/coin_transfer.exp new file mode 100644 index 00000000000..3f7f8a55ae9 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/iota/coin_transfer.exp @@ -0,0 +1,37 @@ +processed 8 tasks + +init: +A: object(0,0), B: object(0,1), C: object(0,2) + +task 1 'programmable'. lines 8-10: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'view-object'. lines 12-12: +Owner: Account Address ( B ) +Version: 2 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,0)}}, balance: iota::balance::Balance {value: 10u64}} + +task 3 'run'. lines 14-14: +created: object(3,0) +mutated: object(0,1), object(1,0) +gas summary: computation_cost: 1000000, storage_cost: 2964000, storage_rebate: 1956240, non_refundable_storage_fee: 19760 + +task 4 'view-object'. lines 16-16: +Owner: Account Address ( B ) +Version: 3 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,0)}}, balance: iota::balance::Balance {value: 0u64}} + +task 5 'view-object'. lines 18-18: +Owner: Account Address ( A ) +Version: 3 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, balance: iota::balance::Balance {value: 10u64}} + +task 6 'run'. lines 20-20: +Error: Error checking transaction input objects: IncorrectUserSignature { error: "Object object(1,0) is owned by account address @B, but given owner/signer address is @A" } + +task 7 'view-object'. lines 22-22: +Owner: Account Address ( B ) +Version: 3 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,0)}}, balance: iota::balance::Balance {value: 0u64}} diff --git a/crates/iota-adapter-transactional-tests/tests/iota/coin_transfer.move b/crates/iota-adapter-transactional-tests/tests/iota/coin_transfer.move new file mode 100644 index 00000000000..e7c1f325145 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/iota/coin_transfer.move @@ -0,0 +1,23 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// Test basic coin transfer + +//# init --accounts A B C + +//# programmable --sender B --inputs 10 @B +//> SplitCoins(Gas, [Input(0)]); +//> TransferObjects([Result(0)], Input(1)) + +//# view-object 1,0 + +//# run iota::pay::split_and_transfer --type-args iota::iota::IOTA --args object(1,0) 10 @A --sender B + +//# view-object 1,0 + +//# view-object 3,0 + +//# run iota::pay::split_and_transfer --type-args iota::iota::IOTA --args object(1,0) 0 @C --sender A + +//# view-object 1,0 diff --git a/crates/sui-adapter-transactional-tests/tests/sui/freeze.exp b/crates/iota-adapter-transactional-tests/tests/iota/freeze.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/sui/freeze.exp rename to crates/iota-adapter-transactional-tests/tests/iota/freeze.exp diff --git a/crates/iota-adapter-transactional-tests/tests/iota/freeze.move b/crates/iota-adapter-transactional-tests/tests/iota/freeze.move new file mode 100644 index 00000000000..078f6266cec --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/iota/freeze.move @@ -0,0 +1,76 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// test that freezing prevents transfers/mutations + +//# init --addresses test=0x0 --accounts A --shared-object-deletion true + +//# publish + +module test::object_basics { + use iota::event; + + public struct Object has key, store { + id: UID, + value: u64, + } + + public struct Wrapper has key { + id: UID, + o: Object + } + + public struct NewValueEvent has copy, drop { + new_value: u64 + } + + public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { + transfer::public_transfer( + Object { id: object::new(ctx), value }, + recipient + ) + } + + public entry fun transfer_(o: Object, recipient: address) { + transfer::public_transfer(o, recipient) + } + + public entry fun freeze_object(o: Object) { + transfer::public_freeze_object(o) + } + + public entry fun set_value(o: &mut Object, value: u64) { + o.value = value; + } + + // test that reading o2 and updating o1 works + public entry fun update(o1: &mut Object, o2: &Object) { + o1.value = o2.value; + // emit an event so the world can see the new value + event::emit(NewValueEvent { new_value: o2.value }) + } + + public entry fun delete(o: Object) { + let Object { id, value: _ } = o; + object::delete(id); + } + + public entry fun wrap(o: Object, ctx: &mut TxContext) { + transfer::transfer(Wrapper { id: object::new(ctx), o }, tx_context::sender(ctx)) + } + + public entry fun unwrap(w: Wrapper, ctx: &mut TxContext) { + let Wrapper { id, o } = w; + object::delete(id); + transfer::public_transfer(o, tx_context::sender(ctx)) + } +} + +//# run test::object_basics::create --args 10 @A --sender A + +//# run test::object_basics::freeze_object --args object(2,0) --sender A + +//# run test::object_basics::transfer_ --args object(2,0) @A --sender A + +//# run test::object_basics::set_value --args object(2,0) 1 --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/sui/freeze_v20.exp b/crates/iota-adapter-transactional-tests/tests/iota/freeze_v20.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/sui/freeze_v20.exp rename to crates/iota-adapter-transactional-tests/tests/iota/freeze_v20.exp diff --git a/crates/sui-adapter-transactional-tests/tests/sui/freeze_v20.move b/crates/iota-adapter-transactional-tests/tests/iota/freeze_v20.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/sui/freeze_v20.move rename to crates/iota-adapter-transactional-tests/tests/iota/freeze_v20.move index deaa0586b17..18f988d7b96 100644 --- a/crates/sui-adapter-transactional-tests/tests/sui/freeze_v20.move +++ b/crates/iota-adapter-transactional-tests/tests/iota/freeze_v20.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // test that freezing prevents transfers/mutations @@ -8,7 +9,7 @@ //# publish module test::object_basics { - use sui::event; + use iota::event; public struct Object has key, store { id: UID, diff --git a/crates/sui-adapter-transactional-tests/tests/sui/move_call_args_type_mismatch.exp b/crates/iota-adapter-transactional-tests/tests/iota/move_call_args_type_mismatch.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/sui/move_call_args_type_mismatch.exp rename to crates/iota-adapter-transactional-tests/tests/iota/move_call_args_type_mismatch.exp diff --git a/crates/sui-adapter-transactional-tests/tests/sui/move_call_args_type_mismatch.move b/crates/iota-adapter-transactional-tests/tests/iota/move_call_args_type_mismatch.move similarity index 86% rename from crates/sui-adapter-transactional-tests/tests/sui/move_call_args_type_mismatch.move rename to crates/iota-adapter-transactional-tests/tests/iota/move_call_args_type_mismatch.move index 2a420fa28f1..59dec627b5f 100644 --- a/crates/sui-adapter-transactional-tests/tests/sui/move_call_args_type_mismatch.move +++ b/crates/iota-adapter-transactional-tests/tests/iota/move_call_args_type_mismatch.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test=0x0 diff --git a/crates/sui-adapter-transactional-tests/tests/sui/move_call_incorrect_function.exp b/crates/iota-adapter-transactional-tests/tests/iota/move_call_incorrect_function.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/sui/move_call_incorrect_function.exp rename to crates/iota-adapter-transactional-tests/tests/iota/move_call_incorrect_function.exp diff --git a/crates/sui-adapter-transactional-tests/tests/sui/move_call_incorrect_function.move b/crates/iota-adapter-transactional-tests/tests/iota/move_call_incorrect_function.move similarity index 88% rename from crates/sui-adapter-transactional-tests/tests/sui/move_call_incorrect_function.move rename to crates/iota-adapter-transactional-tests/tests/iota/move_call_incorrect_function.move index 9bd1e226d21..ac6a1bd5263 100644 --- a/crates/sui-adapter-transactional-tests/tests/sui/move_call_incorrect_function.move +++ b/crates/iota-adapter-transactional-tests/tests/iota/move_call_incorrect_function.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // These functions do not exist diff --git a/crates/sui-adapter-transactional-tests/tests/sui/object_basics.exp b/crates/iota-adapter-transactional-tests/tests/iota/object_basics.exp similarity index 87% rename from crates/sui-adapter-transactional-tests/tests/sui/object_basics.exp rename to crates/iota-adapter-transactional-tests/tests/iota/object_basics.exp index c0065a883d9..5389a0cd72b 100644 --- a/crates/sui-adapter-transactional-tests/tests/sui/object_basics.exp +++ b/crates/iota-adapter-transactional-tests/tests/iota/object_basics.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2386400, storage_rebate: task 3 'view-object'. lines 71-71: Owner: Account Address ( A ) Version: 2 -Contents: test::object_basics::Object {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, value: 10u64} +Contents: test::object_basics::Object {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, value: 10u64} task 4 'run'. lines 73-73: mutated: object(0,0), object(2,0) @@ -25,7 +25,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2386400, storage_rebate: task 5 'view-object'. lines 75-75: Owner: Account Address ( B ) Version: 3 -Contents: test::object_basics::Object {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, value: 10u64} +Contents: test::object_basics::Object {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, value: 10u64} task 6 'run'. lines 77-77: created: object(6,0) diff --git a/crates/iota-adapter-transactional-tests/tests/iota/object_basics.move b/crates/iota-adapter-transactional-tests/tests/iota/object_basics.move new file mode 100644 index 00000000000..f70914624c4 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/iota/object_basics.move @@ -0,0 +1,82 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// Exercise test functions that create, transfer, read, update, and delete objects + +//# init --addresses test=0x0 --accounts A B + +//# publish + +module test::object_basics { + use iota::event; + + public struct Object has key, store { + id: UID, + value: u64, + } + + public struct Wrapper has key { + id: UID, + o: Object + } + + public struct NewValueEvent has copy, drop { + new_value: u64 + } + + public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { + transfer::public_transfer( + Object { id: object::new(ctx), value }, + recipient + ) + } + + public entry fun transfer_(o: Object, recipient: address) { + transfer::public_transfer(o, recipient) + } + + public entry fun freeze_object(o: Object) { + transfer::public_freeze_object(o) + } + + public entry fun set_value(o: &mut Object, value: u64) { + o.value = value; + } + + // test that reading o2 and updating o1 works + public entry fun update(o1: &mut Object, o2: &Object) { + o1.value = o2.value; + // emit an event so the world can see the new value + event::emit(NewValueEvent { new_value: o2.value }) + } + + public entry fun delete(o: Object) { + let Object { id, value: _ } = o; + object::delete(id); + } + + public entry fun wrap(o: Object, ctx: &mut TxContext) { + transfer::transfer(Wrapper { id: object::new(ctx), o }, tx_context::sender(ctx)) + } + + public entry fun unwrap(w: Wrapper, ctx: &mut TxContext) { + let Wrapper { id, o } = w; + object::delete(id); + transfer::public_transfer(o, tx_context::sender(ctx)) + } +} + +//# run test::object_basics::create --sender A --args 10 @A + +//# view-object 2,0 + +//# run test::object_basics::transfer_ --sender A --args object(2,0) @B + +//# view-object 2,0 + +//# run test::object_basics::create --sender B --args 20 @B + +//# run test::object_basics::update --sender B --args object(2,0) object(6,0) + +//# run test::object_basics::delete --sender B --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/sui/publish_module_non_zero_address.exp b/crates/iota-adapter-transactional-tests/tests/iota/publish_module_non_zero_address.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/sui/publish_module_non_zero_address.exp rename to crates/iota-adapter-transactional-tests/tests/iota/publish_module_non_zero_address.exp diff --git a/crates/sui-adapter-transactional-tests/tests/sui/publish_module_non_zero_address.move b/crates/iota-adapter-transactional-tests/tests/iota/publish_module_non_zero_address.move similarity index 80% rename from crates/sui-adapter-transactional-tests/tests/sui/publish_module_non_zero_address.move rename to crates/iota-adapter-transactional-tests/tests/iota/publish_module_non_zero_address.move index f964983ca88..a9a5d773ccb 100644 --- a/crates/sui-adapter-transactional-tests/tests/sui/publish_module_non_zero_address.move +++ b/crates/iota-adapter-transactional-tests/tests/iota/publish_module_non_zero_address.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Publishing must be done at with the initial address of the module set to 0x0 diff --git a/crates/sui-adapter-transactional-tests/tests/sui/unwrap.exp b/crates/iota-adapter-transactional-tests/tests/iota/unwrap.exp similarity index 80% rename from crates/sui-adapter-transactional-tests/tests/sui/unwrap.exp rename to crates/iota-adapter-transactional-tests/tests/iota/unwrap.exp index dfe3aa91993..9b24841444b 100644 --- a/crates/sui-adapter-transactional-tests/tests/sui/unwrap.exp +++ b/crates/iota-adapter-transactional-tests/tests/iota/unwrap.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2386400, storage_rebate: task 3 'view-object'. lines 72-72: Owner: Account Address ( A ) Version: 3 -Contents: test::object_basics::Object {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, value: 10u64} +Contents: test::object_basics::Object {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, value: 10u64} task 4 'run'. lines 74-74: created: object(4,0) @@ -33,4 +33,4 @@ gas summary: computation_cost: 1000000, storage_cost: 2386400, storage_rebate: task 6 'view-object'. lines 78-78: Owner: Account Address ( A ) Version: 5 -Contents: test::object_basics::Object {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, value: 10u64} +Contents: test::object_basics::Object {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, value: 10u64} diff --git a/crates/sui-adapter-transactional-tests/tests/sui/unwrap.move b/crates/iota-adapter-transactional-tests/tests/iota/unwrap.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/sui/unwrap.move rename to crates/iota-adapter-transactional-tests/tests/iota/unwrap.move index 95818febf17..b35a1d5dfe5 100644 --- a/crates/sui-adapter-transactional-tests/tests/sui/unwrap.move +++ b/crates/iota-adapter-transactional-tests/tests/iota/unwrap.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Exercise test functions that wrap and object and subsequently unwrap it @@ -9,7 +10,7 @@ //# publish module test::object_basics { - use sui::event; + use iota::event; public struct Object has key, store { id: UID, diff --git a/crates/sui-adapter-transactional-tests/tests/sui/unwrap_then_delete.exp b/crates/iota-adapter-transactional-tests/tests/iota/unwrap_then_delete.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/sui/unwrap_then_delete.exp rename to crates/iota-adapter-transactional-tests/tests/iota/unwrap_then_delete.exp diff --git a/crates/sui-adapter-transactional-tests/tests/sui/unwrap_then_delete.move b/crates/iota-adapter-transactional-tests/tests/iota/unwrap_then_delete.move similarity index 97% rename from crates/sui-adapter-transactional-tests/tests/sui/unwrap_then_delete.move rename to crates/iota-adapter-transactional-tests/tests/iota/unwrap_then_delete.move index 4907bfe18b1..6ed22da0a61 100644 --- a/crates/sui-adapter-transactional-tests/tests/sui/unwrap_then_delete.move +++ b/crates/iota-adapter-transactional-tests/tests/iota/unwrap_then_delete.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Exercise test functions that wrap an object and subsequently unwrap and delete it. diff --git a/crates/sui-adapter-transactional-tests/tests/sui/unwrap_then_freeze.exp b/crates/iota-adapter-transactional-tests/tests/iota/unwrap_then_freeze.exp similarity index 80% rename from crates/sui-adapter-transactional-tests/tests/sui/unwrap_then_freeze.exp rename to crates/iota-adapter-transactional-tests/tests/iota/unwrap_then_freeze.exp index 9a08f71d721..26d47ed267f 100644 --- a/crates/sui-adapter-transactional-tests/tests/sui/unwrap_then_freeze.exp +++ b/crates/iota-adapter-transactional-tests/tests/iota/unwrap_then_freeze.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2386400, storage_rebate: task 3 'view-object'. lines 42-42: Owner: Account Address ( A ) Version: 3 -Contents: test::object_basics::Object {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, value: 10u64} +Contents: test::object_basics::Object {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, value: 10u64} task 4 'run'. lines 44-44: created: object(4,0) @@ -33,4 +33,4 @@ gas summary: computation_cost: 1000000, storage_cost: 2386400, storage_rebate: task 6 'view-object'. lines 48-48: Owner: Immutable Version: 5 -Contents: test::object_basics::Object {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, value: 10u64} +Contents: test::object_basics::Object {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, value: 10u64} diff --git a/crates/sui-adapter-transactional-tests/tests/sui/unwrap_then_freeze.move b/crates/iota-adapter-transactional-tests/tests/iota/unwrap_then_freeze.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/sui/unwrap_then_freeze.move rename to crates/iota-adapter-transactional-tests/tests/iota/unwrap_then_freeze.move index 6e94810cfc3..7ed72f14b96 100644 --- a/crates/sui-adapter-transactional-tests/tests/sui/unwrap_then_freeze.move +++ b/crates/iota-adapter-transactional-tests/tests/iota/unwrap_then_freeze.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Exercise test functions that wrap and object and subsequently unwrap it diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/child_of_child.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/child_of_child.exp new file mode 100644 index 00000000000..aff3874c6ed --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/child_of_child.exp @@ -0,0 +1,62 @@ +processed 14 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-66: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 9218800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 68-70: +created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 9750800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 72-72: +Owner: Account Address ( A ) +Version: 2 +Contents: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,4)}}, value: 0u64} + +task 4 'programmable'. lines 74-75: +mutated: object(0,0), object(2,2), object(2,3), object(2,4) +gas summary: computation_cost: 1000000, storage_cost: 4841200, storage_rebate: 4792788, non_refundable_storage_fee: 48412 + +task 5 'view-object'. lines 77-77: +Owner: Account Address ( A ) +Version: 3 +Contents: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,4)}}, value: 1u64} + +task 6 'programmable'. lines 79-80: +mutated: object(0,0), object(2,4) +deleted: object(2,0), object(2,2) +gas summary: computation_cost: 1000000, storage_cost: 2272400, storage_rebate: 5951484, non_refundable_storage_fee: 60116 + +task 7 'view-object'. lines 82-85: +Owner: Account Address ( A ) +Version: 4 +Contents: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,4)}}, value: 1u64} + +task 8 'programmable'. lines 87-88: +mutated: object(_), object(2,4) +gas summary: computation_cost: 500000, storage_cost: 2272400, storage_rebate: 1271556, non_refundable_storage_fee: 12844 + +task 9 'programmable'. lines 90-91: +mutated: object(_), object(2,4) +gas summary: computation_cost: 500000, storage_cost: 2272400, storage_rebate: 1271556, non_refundable_storage_fee: 12844 + +task 10 'programmable'. lines 93-97: +mutated: object(_), object(2,4) +gas summary: computation_cost: 500000, storage_cost: 2272400, storage_rebate: 1271556, non_refundable_storage_fee: 12844 + +task 11 'programmable'. lines 99-100: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 + +task 12 'programmable'. lines 102-103: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 + +task 13 'programmable'. lines 105-106: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/child_of_child.move b/crates/iota-adapter-transactional-tests/tests/mvcc/child_of_child.move new file mode 100644 index 00000000000..a4c9b1f3696 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/child_of_child.move @@ -0,0 +1,107 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests accessing the versions of a child of a child + +//# init --addresses test=0x0 --accounts A + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct Obj has key, store { + id: UID, + value: u64, + } + + const KEY: u64 = 0; + + ////////////////////////////////////////////////////////////// + // new + + public fun new(ctx: &mut TxContext): Obj { + let mut grand = Obj { id: object::new(ctx), value: 0 }; + let mut parent = Obj { id: object::new(ctx), value: 0 }; + let child = Obj { id: object::new(ctx), value: 0 }; + ofield::add(&mut parent.id, KEY, child); + ofield::add(&mut grand.id, KEY, parent); + grand + } + + ////////////////////////////////////////////////////////////// + // set + + public fun set(grand: &mut Obj, v1: u64, v2: u64, v3: u64) { + grand.value = v1; + let parent: &mut Obj = ofield::borrow_mut(&mut grand.id, KEY); + parent.value = v2; + let child: &mut Obj = ofield::borrow_mut(&mut parent.id, KEY); + child.value = v3; + } + + ////////////////////////////////////////////////////////////// + // remove + + public fun remove(grand: &mut Obj) { + let parent: &mut Obj = ofield::borrow_mut(&mut grand.id, KEY); + let Obj { id, value: _ } = ofield::remove(&mut parent.id, KEY); + object::delete(id); + } + + ////////////////////////////////////////////////////////////// + // check + + public fun check(grand: &Obj, v1: u64, v2: u64, v3: Option) { + assert!(grand.value == v1, 0); + let parent: &Obj = ofield::borrow(&grand.id, KEY); + assert!(parent.value == v2, 0); + if (option::is_some(&v3)) { + let child: &Obj = ofield::borrow(&parent.id, KEY); + assert!(&child.value == option::borrow(&v3), 0); + } else { + assert!(!ofield::exists_(&parent.id, KEY), 0); + } + } +} + +//# programmable --sender A --inputs @A +//> 0: test::m::new(); +//> TransferObjects([Result(0)], Input(0)) + +//# view-object 2,4 + +//# programmable --sender A --inputs object(2,4) 1 2 3 +//> test::m::set(Input(0), Input(1), Input(2), Input(3)) + +//# view-object 2,4 + +//# programmable --sender A --inputs object(2,4) +//> test::m::remove(Input(0)) + +//# view-object 2,4 + + +// dev-inspect with 'check' and correct values + +//# programmable --sender A --inputs object(2,4)@2 0 0 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1), Input(2), Input(3)) + +//# programmable --sender A --inputs object(2,4)@3 1 2 vector[3] --dev-inspect +//> test::m::check(Input(0), Input(1), Input(2), Input(3)) + +//# programmable --sender A --inputs object(2,4)@4 1 2 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1), Input(2), Input(3)) + + +// dev-inspect with 'check' and _incorrect_ values + +//# programmable --sender A --inputs object(2,4)@3 0 0 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1), Input(2), Input(3)) + +//# programmable --sender A --inputs object(2,4)@4 1 2 vector[3] --dev-inspect +//> test::m::check(Input(0), Input(1), Input(2), Input(3)) + +//# programmable --sender A --inputs object(2,4)@2 1 2 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1), Input(2), Input(3)) diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids.exp new file mode 100644 index 00000000000..47954051a49 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids.exp @@ -0,0 +1,62 @@ +processed 14 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-117: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 12205600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 119-121: +created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 15640800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 123-123: +Owner: Account Address ( A ) +Version: 2 +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,8)}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}]} + +task 4 'programmable'. lines 125-126: +mutated: object(0,0), object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8) +gas summary: computation_cost: 1000000, storage_cost: 15640800, storage_rebate: 15484392, non_refundable_storage_fee: 156408 + +task 5 'view-object'. lines 128-128: +Owner: Account Address ( A ) +Version: 3 +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,8)}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}]} + +task 6 'programmable'. lines 130-131: +mutated: object(0,0), object(2,8) +deleted: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7) +gas summary: computation_cost: 1000000, storage_cost: 3906400, storage_rebate: 15484392, non_refundable_storage_fee: 156408 + +task 7 'view-object'. lines 133-136: +Owner: Account Address ( A ) +Version: 4 +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,8)}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}]} + +task 8 'programmable'. lines 138-139: +mutated: object(_), object(2,8) +gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 + +task 9 'programmable'. lines 141-142: +mutated: object(_), object(2,8) +gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 + +task 10 'programmable'. lines 144-148: +mutated: object(_), object(2,8) +gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 + +task 11 'programmable'. lines 150-151: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 12, function_name: Some("check_") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 12, function_name: Some("check_") }, 0) in command 0 + +task 12 'programmable'. lines 153-154: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 + +task 13 'programmable'. lines 156-157: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 20, function_name: Some("check_") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 20, function_name: Some("check_") }, 0) in command 0 diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids.move b/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids.move new file mode 100644 index 00000000000..03c824d5eab --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids.move @@ -0,0 +1,158 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests finding UIDs for dynamic field access + +//# init --addresses test=0x0 --accounts A + +//# publish + +module test::m { + use iota::dynamic_field as field; + + public struct S has key, store { + id: UID, + other: UID, + wrapped: Wrapped, + many: vector, + } + + public struct Wrapped has key, store { + id: UID, + other: UID, + } + + const KEY: u64 = 0; + + ////////////////////////////////////////////////////////////// + // new + + public fun new(ctx: &mut TxContext): S { + let mut s = S { + id: object::new(ctx), + other: object::new(ctx), + wrapped: wrapped(ctx), + many: vector[wrapped(ctx), wrapped(ctx)], + }; + field::add(&mut s.id, KEY, 0); + field::add(&mut s.other, KEY, 0); + s + } + + fun wrapped(ctx: &mut TxContext): Wrapped { + let mut w = Wrapped { + id: object::new(ctx), + other: object::new(ctx), + }; + field::add(&mut w.id, KEY, 0); + field::add(&mut w.other, KEY, 0); + w + } + + ////////////////////////////////////////////////////////////// + // set + + public fun set(s: &mut S, value: u64) { + set_(&mut s.id, value); + set_(&mut s.other, value); + set_wrapped(&mut s.wrapped, value); + set_wrapped(vector::borrow_mut(&mut s.many, 0), value); + set_wrapped(vector::borrow_mut(&mut s.many, 1), value); + } + + fun set_wrapped(w: &mut Wrapped, value: u64) { + set_(&mut w.id, value); + set_(&mut w.other, value); + + } + + fun set_(id: &mut UID, value: u64) { + *field::borrow_mut(id, KEY) = value; + } + + ////////////////////////////////////////////////////////////// + // remove + + public fun remove(s: &mut S) { + remove_(&mut s.id); + remove_(&mut s.other); + remove_wrapped(&mut s.wrapped); + remove_wrapped(vector::borrow_mut(&mut s.many, 0)); + remove_wrapped(vector::borrow_mut(&mut s.many, 1)); + } + + fun remove_wrapped(w: &mut Wrapped) { + remove_(&mut w.id); + remove_(&mut w.other); + } + + fun remove_(id: &mut UID) { + field::remove(id, KEY); + } + + ////////////////////////////////////////////////////////////// + // check + + public fun check(s: &S, expected: Option) { + check_(&s.id, expected); + check_(&s.other, expected); + check_wrapped(&s.wrapped, expected); + check_wrapped(vector::borrow(&s.many, 0), expected); + check_wrapped(vector::borrow(&s.many, 1), expected); + } + + fun check_wrapped(w: &Wrapped, expected: Option) { + check_(&w.id, expected); + check_(&w.other, expected); + } + + fun check_(id: &UID, expected: Option) { + if (option::is_some(&expected)) { + let f = field::borrow(id, KEY); + assert!(f == option::borrow(&expected), 0); + } else { + assert!(!field::exists_with_type(id, KEY), 0); + } + } +} + +//# programmable --sender A --inputs @A +//> 0: test::m::new(); +//> TransferObjects([Result(0)], Input(0)) + +//# view-object 2,8 + +//# programmable --sender A --inputs object(2,8) 112 +//> test::m::set(Input(0), Input(1)) + +//# view-object 2,8 + +//# programmable --sender A --inputs object(2,8) 112 +//> test::m::remove(Input(0)) + +//# view-object 2,8 + + +// dev-inspect with 'check' and correct values + +//# programmable --sender A --inputs object(2,8)@2 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@3 vector[112] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@4 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1)) + + +// dev-inspect with 'check' and _incorrect_ values + +//# programmable --sender A --inputs object(2,8)@3 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@4 vector[112] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@2 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1)) diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids_dof.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids_dof.exp new file mode 100644 index 00000000000..9c04b6a0389 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids_dof.exp @@ -0,0 +1,62 @@ +processed 14 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-130: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 13353200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 132-134: +created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8), object(2,9), object(2,10), object(2,11), object(2,12), object(2,13), object(2,14), object(2,15), object(2,16) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 33941600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 136-136: +Owner: Account Address ( A ) +Version: 2 +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,8)}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}]} + +task 4 'programmable'. lines 138-139: +mutated: object(0,0), object(2,8), object(2,9), object(2,10), object(2,11), object(2,12), object(2,13), object(2,14), object(2,15), object(2,16) +gas summary: computation_cost: 1000000, storage_cost: 14303200, storage_rebate: 14160168, non_refundable_storage_fee: 143032 + +task 5 'view-object'. lines 141-141: +Owner: Account Address ( A ) +Version: 3 +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,8)}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}]} + +task 6 'programmable'. lines 143-144: +mutated: object(0,0), object(2,8) +deleted: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,9), object(2,10), object(2,11), object(2,12), object(2,13), object(2,14), object(2,15), object(2,16) +gas summary: computation_cost: 1000000, storage_cost: 3906400, storage_rebate: 33602184, non_refundable_storage_fee: 339416 + +task 7 'view-object'. lines 146-149: +Owner: Account Address ( A ) +Version: 4 +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,8)}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}]} + +task 8 'programmable'. lines 151-152: +mutated: object(_), object(2,8) +gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 + +task 9 'programmable'. lines 154-155: +mutated: object(_), object(2,8) +gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 + +task 10 'programmable'. lines 157-161: +mutated: object(_), object(2,8) +gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 + +task 11 'programmable'. lines 163-164: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 18, function_name: Some("check_") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 18, function_name: Some("check_") }, 0) in command 0 + +task 12 'programmable'. lines 166-167: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 + +task 13 'programmable'. lines 169-170: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 26, function_name: Some("check_") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 26, function_name: Some("check_") }, 0) in command 0 diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids_dof.move b/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids_dof.move new file mode 100644 index 00000000000..60fce153842 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids_dof.move @@ -0,0 +1,171 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests finding UIDs for dynamic object field access + +//# init --addresses test=0x0 --accounts A + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct S has key, store { + id: UID, + other: UID, + wrapped: Wrapped, + many: vector, + } + + public struct Wrapped has key, store { + id: UID, + other: UID, + } + + public struct Value has key, store { + id: UID, + value: u64, + } + + const KEY: u64 = 0; + + ////////////////////////////////////////////////////////////// + // new + + public fun new(ctx: &mut TxContext): S { + let mut s = S { + id: object::new(ctx), + other: object::new(ctx), + wrapped: wrapped(ctx), + many: vector[wrapped(ctx), wrapped(ctx)], + }; + ofield::add(&mut s.id, KEY, value(0, ctx)); + ofield::add(&mut s.other, KEY, value(0, ctx)); + s + } + + fun wrapped(ctx: &mut TxContext): Wrapped { + let mut w = Wrapped { + id: object::new(ctx), + other: object::new(ctx), + }; + ofield::add(&mut w.id, KEY, value(0, ctx)); + ofield::add(&mut w.other, KEY, value(0, ctx)); + w + } + + fun value(value: u64, ctx: &mut TxContext): Value { + Value { + id: object::new(ctx), + value + } + } + + ////////////////////////////////////////////////////////////// + // set + + public fun set(s: &mut S, value: u64) { + set_(&mut s.id, value); + set_(&mut s.other, value); + set_wrapped(&mut s.wrapped, value); + set_wrapped(vector::borrow_mut(&mut s.many, 0), value); + set_wrapped(vector::borrow_mut(&mut s.many, 1), value); + } + + fun set_wrapped(w: &mut Wrapped, value: u64) { + set_(&mut w.id, value); + set_(&mut w.other, value); + + } + + fun set_(id: &mut UID, value: u64) { + ofield::borrow_mut(id, KEY).value = value; + } + + ////////////////////////////////////////////////////////////// + // remove + + public fun remove(s: &mut S) { + remove_(&mut s.id); + remove_(&mut s.other); + remove_wrapped(&mut s.wrapped); + remove_wrapped(vector::borrow_mut(&mut s.many, 0)); + remove_wrapped(vector::borrow_mut(&mut s.many, 1)); + } + + fun remove_wrapped(w: &mut Wrapped) { + remove_(&mut w.id); + remove_(&mut w.other); + } + + fun remove_(id: &mut UID) { + let Value { id, value: _ } = ofield::remove(id, KEY); + object::delete(id); + } + + ////////////////////////////////////////////////////////////// + // check + + public fun check(s: &S, expected: Option) { + check_(&s.id, expected); + check_(&s.other, expected); + check_wrapped(&s.wrapped, expected); + check_wrapped(vector::borrow(&s.many, 0), expected); + check_wrapped(vector::borrow(&s.many, 1), expected); + } + + fun check_wrapped(w: &Wrapped, expected: Option) { + check_(&w.id, expected); + check_(&w.other, expected); + } + + fun check_(id: &UID, expected: Option) { + if (option::is_some(&expected)) { + let Value { id: _, value } = ofield::borrow(id, KEY); + assert!(value == option::borrow(&expected), 0); + } else { + assert!(!ofield::exists_with_type(id, KEY), 0); + } + } +} + +//# programmable --sender A --inputs @A +//> 0: test::m::new(); +//> TransferObjects([Result(0)], Input(0)) + +//# view-object 2,8 + +//# programmable --sender A --inputs object(2,8) 112 +//> test::m::set(Input(0), Input(1)) + +//# view-object 2,8 + +//# programmable --sender A --inputs object(2,8) 112 +//> test::m::remove(Input(0)) + +//# view-object 2,8 + + +// dev-inspect with 'check' and correct values + +//# programmable --sender A --inputs object(2,8)@2 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@3 vector[112] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@4 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1)) + + +// dev-inspect with 'check' and _incorrect_ values + +//# programmable --sender A --inputs object(2,8)@3 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@4 vector[112] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@2 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1)) diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids_on_child.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids_on_child.exp new file mode 100644 index 00000000000..d6a2494586f --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids_on_child.exp @@ -0,0 +1,62 @@ +processed 14 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-140: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 13862400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 142-144: +created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8), object(2,9) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 17609200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 146-146: +Owner: Account Address ( A ) +Version: 2 +Contents: test::m::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,9)}}} + +task 4 'programmable'. lines 148-149: +mutated: object(0,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8), object(2,9) +gas summary: computation_cost: 1000000, storage_cost: 13968800, storage_rebate: 13829112, non_refundable_storage_fee: 139688 + +task 5 'view-object'. lines 151-151: +Owner: Account Address ( A ) +Version: 3 +Contents: test::m::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,9)}}} + +task 6 'programmable'. lines 153-154: +mutated: object(0,0), object(2,9) +deleted: object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8) +gas summary: computation_cost: 1000000, storage_cost: 2234400, storage_rebate: 13829112, non_refundable_storage_fee: 139688 + +task 7 'view-object'. lines 156-159: +Owner: Account Address ( A ) +Version: 4 +Contents: test::m::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,9)}}} + +task 8 'programmable'. lines 161-162: +mutated: object(_), object(2,9) +gas summary: computation_cost: 500000, storage_cost: 2234400, storage_rebate: 1233936, non_refundable_storage_fee: 12464 + +task 9 'programmable'. lines 164-165: +mutated: object(_), object(2,9) +gas summary: computation_cost: 500000, storage_cost: 2234400, storage_rebate: 1233936, non_refundable_storage_fee: 12464 + +task 10 'programmable'. lines 167-171: +mutated: object(_), object(2,9) +gas summary: computation_cost: 500000, storage_cost: 2234400, storage_rebate: 1233936, non_refundable_storage_fee: 12464 + +task 11 'programmable'. lines 173-174: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 12, function_name: Some("check_") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 12, function_name: Some("check_") }, 0) in command 0 + +task 12 'programmable'. lines 176-177: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 + +task 13 'programmable'. lines 179-180: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 20, function_name: Some("check_") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 20, function_name: Some("check_") }, 0) in command 0 diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids_on_child.move b/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids_on_child.move new file mode 100644 index 00000000000..6c86497c89b --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/find_all_uids_on_child.move @@ -0,0 +1,181 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests finding UIDs for dynamic field access on a child object (non-input) + +//# init --addresses test=0x0 --accounts A + +//# publish + +module test::m { + use iota::dynamic_field as field; + + public struct Parent has key, store { + id: UID, + } + + public struct S has key, store { + id: UID, + other: UID, + wrapped: Wrapped, + many: vector, + } + + public struct Wrapped has key, store { + id: UID, + other: UID, + } + + const KEY: u64 = 0; + + ////////////////////////////////////////////////////////////// + // new + + public fun new(ctx: &mut TxContext): Parent { + let mut parent = Parent { id: object::new(ctx) }; + field::add(&mut parent.id, KEY, s(ctx)); + parent + } + + fun s(ctx: &mut TxContext): S { + let mut s = S { + id: object::new(ctx), + other: object::new(ctx), + wrapped: wrapped(ctx), + many: vector[wrapped(ctx), wrapped(ctx)], + }; + field::add(&mut s.id, KEY, 0); + field::add(&mut s.other, KEY, 0); + s + } + + fun wrapped(ctx: &mut TxContext): Wrapped { + let mut w = Wrapped { + id: object::new(ctx), + other: object::new(ctx), + }; + field::add(&mut w.id, KEY, 0); + field::add(&mut w.other, KEY, 0); + w + } + + ////////////////////////////////////////////////////////////// + // set + + public fun set(parent: &mut Parent, value: u64) { + set_s(field::borrow_mut(&mut parent.id, KEY), value); + } + + + fun set_s(s: &mut S, value: u64) { + set_(&mut s.id, value); + set_(&mut s.other, value); + set_wrapped(&mut s.wrapped, value); + set_wrapped(vector::borrow_mut(&mut s.many, 0), value); + set_wrapped(vector::borrow_mut(&mut s.many, 1), value); + } + + fun set_wrapped(w: &mut Wrapped, value: u64) { + set_(&mut w.id, value); + set_(&mut w.other, value); + + } + + fun set_(id: &mut UID, value: u64) { + *field::borrow_mut(id, KEY) = value; + } + + ////////////////////////////////////////////////////////////// + // remove + + public fun remove(parent: &mut Parent) { + remove_s(field::borrow_mut(&mut parent.id, KEY)); + } + + fun remove_s(s: &mut S) { + remove_(&mut s.id); + remove_(&mut s.other); + remove_wrapped(&mut s.wrapped); + remove_wrapped(vector::borrow_mut(&mut s.many, 0)); + remove_wrapped(vector::borrow_mut(&mut s.many, 1)); + } + + fun remove_wrapped(w: &mut Wrapped) { + remove_(&mut w.id); + remove_(&mut w.other); + } + + fun remove_(id: &mut UID) { + field::remove(id, KEY); + } + + ////////////////////////////////////////////////////////////// + // check + + public fun check(parent: &Parent, expected: Option) { + check_s(field::borrow(&parent.id, KEY), expected); + } + + fun check_s(s: &S, expected: Option) { + check_(&s.id, expected); + check_(&s.other, expected); + check_wrapped(&s.wrapped, expected); + check_wrapped(vector::borrow(&s.many, 0), expected); + check_wrapped(vector::borrow(&s.many, 1), expected); + } + + fun check_wrapped(w: &Wrapped, expected: Option) { + check_(&w.id, expected); + check_(&w.other, expected); + } + + fun check_(id: &UID, expected: Option) { + if (option::is_some(&expected)) { + let f = field::borrow(id, KEY); + assert!(f == option::borrow(&expected), 0); + } else { + assert!(!field::exists_with_type(id, KEY), 0); + } + } +} + +//# programmable --sender A --inputs @A +//> 0: test::m::new(); +//> TransferObjects([Result(0)], Input(0)) + +//# view-object 2,9 + +//# programmable --sender A --inputs object(2,9) 112 +//> test::m::set(Input(0), Input(1)) + +//# view-object 2,9 + +//# programmable --sender A --inputs object(2,9) 112 +//> test::m::remove(Input(0)) + +//# view-object 2,9 + + +// dev-inspect with 'check' and correct values + +//# programmable --sender A --inputs object(2,9)@2 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,9)@3 vector[112] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,9)@4 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1)) + + +// dev-inspect with 'check' and _incorrect_ values + +//# programmable --sender A --inputs object(2,9)@3 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,9)@4 vector[112] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,9)@2 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1)) diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/middle_version_less_than_child.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/middle_version_less_than_child.exp new file mode 100644 index 00000000000..ca19df92b5d --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/middle_version_less_than_child.exp @@ -0,0 +1,52 @@ +processed 11 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-51: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 7493600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 53-57: +created: object(2,0), object(2,1), object(2,2) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 6285200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 59-59: +Owner: Object ID: ( _ ) +Version: 2 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, name: 0u64, value: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: _}}, value: 0u64}} + +task 4 'view-object'. lines 61-61: +Owner: Object ID: ( fake(2,2) ) +Version: 2 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, name: 0u64, value: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: _}}, value: 0u64}} + +task 5 'view-object'. lines 63-63: +Owner: Account Address ( A ) +Version: 2 +Contents: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}, value: 0u64} + +task 6 'programmable'. lines 65-68: +mutated: object(0,0), object(2,0), object(2,2) +gas summary: computation_cost: 1000000, storage_cost: 4278800, storage_rebate: 4236012, non_refundable_storage_fee: 42788 + +task 7 'view-object'. lines 70-70: +Owner: Object ID: ( _ ) +Version: 3 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, name: 0u64, value: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: _}}, value: 112u64}} + +task 8 'view-object'. lines 72-72: +Owner: Object ID: ( fake(2,2) ) +Version: 2 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, name: 0u64, value: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: _}}, value: 0u64}} + +task 9 'view-object'. lines 74-77: +Owner: Account Address ( A ) +Version: 3 +Contents: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}, value: 0u64} + +task 10 'programmable'. lines 79-80: +mutated: object(0,0), object(2,2) +gas summary: computation_cost: 1000000, storage_cost: 2272400, storage_rebate: 2249676, non_refundable_storage_fee: 22724 diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/middle_version_less_than_child.move b/crates/iota-adapter-transactional-tests/tests/mvcc/middle_version_less_than_child.move new file mode 100644 index 00000000000..354556c2db2 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/middle_version_less_than_child.move @@ -0,0 +1,81 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests accessing the versions of a child of a child + +//# init --addresses test=0x0 --accounts A + +//# publish + +module test::m { + use iota::dynamic_field as field; + + public struct Obj has key, store { + id: UID, + value: u64, + } + + const KEY: u64 = 0; + + ////////////////////////////////////////////////////////////// + // new + + public fun new(ctx: &mut TxContext): Obj { + let mut grand = Obj { id: object::new(ctx), value: 0 }; + let mut parent = Obj { id: object::new(ctx), value: 0 }; + let child = Obj { id: object::new(ctx), value: 0 }; + field::add(&mut parent.id, KEY, child); + field::add(&mut grand.id, KEY, parent); + grand + } + + ////////////////////////////////////////////////////////////// + // set + + public fun set(grand: &mut Obj, v: u64) { + let parent: &mut Obj = field::borrow_mut(&mut grand.id, KEY); + let child: &mut Obj = field::borrow_mut(&mut parent.id, KEY); + child.value = v; + } + + ////////////////////////////////////////////////////////////// + // check + + public fun check(grand: &Obj, expected: u64) { + assert!(grand.value == 0, 0); + let parent: &Obj = field::borrow(&grand.id, KEY); + assert!(parent.value == 0, 0); + let child: &Obj = field::borrow(&parent.id, KEY); + assert!(child.value == expected, 0); + } +} + +//# programmable --sender A --inputs @A +//> 0: test::m::new(); +//> TransferObjects([Result(0)], Input(0)) + +// All 3 objects have version 2 + +//# view-object 2,0 + +//# view-object 2,1 + +//# view-object 2,2 + +//# programmable --sender A --inputs object(2,2) 112 +//> test::m::set(Input(0), Input(1)) + +// The middle object has version 2, while the root and modified leaf have version 3 + +//# view-object 2,0 + +//# view-object 2,1 + +//# view-object 2,2 + +// correctly load the leaf even though it has a version greater than its immediate +// parent + +//# programmable --sender A --inputs object(2,2) 112 +//> test::m::check(Input(0), Input(1)) diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/not_root_version.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/not_root_version.exp new file mode 100644 index 00000000000..e46d70ca2c8 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/not_root_version.exp @@ -0,0 +1,66 @@ +processed 14 tasks + +init: +P1: object(0,0), P2: object(0,1) + +task 1 'publish'. lines 8-53: +created: object(1,0) +mutated: object(0,2) +gas summary: computation_cost: 1000000, storage_cost: 7432800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 55-57: +created: object(2,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'programmable'. lines 59-60: +mutated: object(0,0), object(2,0) +gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 2174436, non_refundable_storage_fee: 21964 + +task 4 'programmable'. lines 62-63: +mutated: object(0,0), object(2,0) +gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 2174436, non_refundable_storage_fee: 21964 + +task 5 'view-object'. lines 65-68: +Owner: Account Address ( P1 ) +Version: 4 +Contents: test::m::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 6 'programmable'. lines 70-72: +created: object(6,0), object(6,1) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 7 'view-object'. lines 74-74: +Owner: Object ID: ( fake(6,1) ) +Version: 2 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}, name: 0u64, value: 0u64} + +task 8 'programmable'. lines 76-77: +mutated: object(0,1), object(6,0), object(6,1) +gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 3626568, non_refundable_storage_fee: 36632 + +task 9 'view-object'. lines 79-83: +Owner: Object ID: ( fake(6,1) ) +Version: 3 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}, name: 0u64, value: 1u64} + +task 10 'programmable'. lines 85-90: +created: object(10,0) +mutated: object(_), object(2,0) +wrapped: object(6,1) +gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 + +task 11 'programmable'. lines 92-96: +created: object(10,0) +mutated: object(_), object(2,0) +wrapped: object(6,1) +gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 + +task 12 'programmable'. lines 98-102: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 + +task 13 'programmable'. lines 104-106: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/not_root_version.move b/crates/iota-adapter-transactional-tests/tests/mvcc/not_root_version.move new file mode 100644 index 00000000000..412b939a995 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/not_root_version.move @@ -0,0 +1,107 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests accessing version of the input parent, not the runtime parent + +//# init --addresses test=0x0 --accounts P1 P2 + +//# publish + +module test::m { + use iota::dynamic_field as field; + + public struct A has key, store { + id: UID, + } + + public struct B has key, store { + id: UID, + } + + const KEY: u64 = 0; + + public fun a(ctx: &mut TxContext): A { + A { id: object::new(ctx) } + } + + public fun b(ctx: &mut TxContext): B { + let mut b = B { id: object::new(ctx) }; + field::add(&mut b.id, KEY, 0); + b + + } + + public fun bump(b: &mut B) { + let f = field::borrow_mut(&mut b.id, KEY); + *f = *f + 1; + } + + public fun append(a: &mut A, b: B) { + field::add(&mut a.id, KEY, b); + } + + public fun check(a: &A, expected: u64) { + let b: &B = field::borrow(&a.id, KEY); + let v = *field::borrow(&b.id, KEY); + assert!(v == expected, 0); + } + + public fun nop() { + } +} + +// Create object A and bump the version to 4 + +//# programmable --sender P1 --inputs @P1 +//> 0: test::m::a(); +//> TransferObjects([Result(0)], Input(0)) + +//# programmable --sender P1 --inputs object(2,0) +//> test::m::nop(); + +//# programmable --sender P1 --inputs object(2,0) +//> test::m::nop(); + +//# view-object 2,0 + + +// Create object B witha version 2 and 3 for it's dynamic field + +//# programmable --sender P2 --inputs @P2 +//> 0: test::m::b(); +//> TransferObjects([Result(0)], Input(0)) + +//# view-object 6,0 + +//# programmable --sender P2 --inputs object(6,1) +//> 0: test::m::bump(Input(0)); + +//# view-object 6,0 + + +// Append object B to object A, but using version 2 of object B. And ensure that +// when we later read the dynamic field of object B, we get the version 2 value. + +//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@2 0 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); + +// checking that with version 3 we get the other value, then flip them to ensure +// they abort + +//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@3 1 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); + +// @2 with value 1 aborts + +//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@2 1 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); + +// @3 with value 0 aborts + +//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@3 0 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/not_root_version_flipped_case.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/not_root_version_flipped_case.exp new file mode 100644 index 00000000000..75e01454d1b --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/not_root_version_flipped_case.exp @@ -0,0 +1,58 @@ +processed 12 tasks + +init: +P1: object(0,0), P2: object(0,1) + +task 1 'publish'. lines 8-53: +created: object(1,0) +mutated: object(0,2) +gas summary: computation_cost: 1000000, storage_cost: 7432800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 55-57: +created: object(2,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 60-63: +Owner: Account Address ( P1 ) +Version: 2 +Contents: test::m::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 4 'programmable'. lines 65-67: +created: object(4,0), object(4,1) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 5 'view-object'. lines 69-69: +Owner: Object ID: ( fake(4,1) ) +Version: 2 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(4,0)}}, name: 0u64, value: 0u64} + +task 6 'programmable'. lines 71-72: +mutated: object(0,1), object(4,0), object(4,1) +gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 3626568, non_refundable_storage_fee: 36632 + +task 7 'view-object'. lines 74-77: +Owner: Object ID: ( fake(4,1) ) +Version: 3 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(4,0)}}, name: 0u64, value: 1u64} + +task 8 'programmable'. lines 79-84: +created: object(8,0) +mutated: object(_), object(2,0) +wrapped: object(4,1) +gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 + +task 9 'programmable'. lines 86-90: +created: object(8,0) +mutated: object(_), object(2,0) +wrapped: object(4,1) +gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 + +task 10 'programmable'. lines 92-96: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 + +task 11 'programmable'. lines 98-100: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/not_root_version_flipped_case.move b/crates/iota-adapter-transactional-tests/tests/mvcc/not_root_version_flipped_case.move new file mode 100644 index 00000000000..853e3421a5e --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/not_root_version_flipped_case.move @@ -0,0 +1,101 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests accessing version of the input parent, not the runtime parent + +//# init --addresses test=0x0 --accounts P1 P2 + +//# publish + +module test::m { + use iota::dynamic_field as field; + + public struct A has key, store { + id: UID, + } + + public struct B has key, store { + id: UID, + } + + const KEY: u64 = 0; + + public fun a(ctx: &mut TxContext): A { + A { id: object::new(ctx) } + } + + public fun b(ctx: &mut TxContext): B { + let mut b = B { id: object::new(ctx) }; + field::add(&mut b.id, KEY, 0); + b + + } + + public fun bump(b: &mut B) { + let f = field::borrow_mut(&mut b.id, KEY); + *f = *f + 1; + } + + public fun append(a: &mut A, b: B) { + field::add(&mut a.id, KEY, b); + } + + public fun check(a: &A, expected: u64) { + let b: &B = field::borrow(&a.id, KEY); + let v = *field::borrow(&b.id, KEY); + assert!(v == expected, 0); + } + + public fun nop() { + } +} + +// Create object A at version 2 + +//# programmable --sender P1 --inputs @P1 +//> 0: test::m::a(); +//> TransferObjects([Result(0)], Input(0)) + + +//# view-object 2,0 + + +// Create object B with a version 2 and 3 for it's dynamic field + +//# programmable --sender P2 --inputs @P2 +//> 0: test::m::b(); +//> TransferObjects([Result(0)], Input(0)) + +//# view-object 4,0 + +//# programmable --sender P2 --inputs object(4,1) +//> 0: test::m::bump(Input(0)); + +//# view-object 4,0 + +// Append object B to object A. And ensure that when we later read the dynamic +// field of object B, we get the most recent version. + +//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@3 1 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); + +// checking that with version 3 we get the other value, then flip them to ensure +// they abort + +//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@2 0 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); + +// @2 with value 1 aborts + +//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@2 1 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); + +// @3 with value 0 aborts + +//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@3 0 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_df.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_df.exp new file mode 100644 index 00000000000..e7eccfe20c0 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_df.exp @@ -0,0 +1,70 @@ +processed 14 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 6-76: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 12524800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 78-78: +created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 15298800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 80-80: +Owner: Object ID: ( _ ) +Version: 2 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, name: iota::dynamic_object_field::Wrapper {name: 1u64}, value: iota::object::ID {bytes: fake(2,5)}} + +task 4 'view-object'. lines 82-82: +Owner: Object ID: ( fake(2,6) ) +Version: 2 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, name: 0u64, value: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: _}}, value: vector[98u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8]}} + +task 5 'view-object'. lines 84-84: +Owner: Object ID: ( _ ) +Version: 2 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}, name: 0u64, value: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: _}}, value: vector[98u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8]}} + +task 6 'view-object'. lines 86-86: +Owner: Object ID: ( _ ) +Version: 2 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,3)}}, name: 0u64, value: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: _}}, value: vector[119u8, 114u8, 97u8, 112u8, 112u8, 101u8, 100u8, 95u8, 100u8, 111u8, 102u8]}} + +task 7 'view-object'. lines 88-88: +Owner: Account Address ( A ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,4)}}, value: vector[97u8, 95u8, 112u8, 97u8, 114u8, 101u8, 110u8, 116u8]} + +task 8 'view-object'. lines 90-90: +Owner: Object ID: ( fake(2,0) ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,5)}}, value: vector[98u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8, 95u8, 100u8, 111u8, 102u8]} + +task 9 'view-object'. lines 92-92: +Owner: Account Address ( fake(2,4) ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,6)}}, value: vector[98u8, 95u8, 112u8, 97u8, 114u8, 101u8, 110u8, 116u8]} + +task 10 'view-object'. lines 94-97: +Owner: Account Address ( fake(2,4) ) +Version: 2 +Contents: tto::M1::Wrapper {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,7)}}, value: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: _}}, value: vector[119u8, 114u8, 97u8, 112u8, 112u8, 101u8, 100u8]}} + +task 11 'run'. lines 98-98: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::receive_impl (function index 12) at offset 0, Abort Code: 2 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } + +task 12 'run'. lines 100-100: +created: object(12,0) +mutated: object(0,0), object(2,4) +wrapped: object(2,6) +gas summary: computation_cost: 1000000, storage_cost: 4278800, storage_rebate: 3521232, non_refundable_storage_fee: 35568 + +task 13 'run'. lines 102-102: +created: object(13,0) +mutated: object(0,0), object(2,4) +wrapped: object(2,7) +gas summary: computation_cost: 1000000, storage_cost: 4856400, storage_rebate: 4093056, non_refundable_storage_fee: 41344 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_df.move b/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_df.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_df.move rename to crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_df.move index bef7befc1c4..b92fa68699e 100644 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_df.move +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_df.move @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 --accounts A //# publish module tto::M1 { - use sui::transfer::Receiving; - use sui::dynamic_object_field as dof; - use sui::dynamic_field as df; + use iota::transfer::Receiving; + use iota::dynamic_object_field as dof; + use iota::dynamic_field as df; const KEY: u64 = 0; const BKEY: u64 = 1; diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_dof.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_dof.exp new file mode 100644 index 00000000000..e1fbc0c5706 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_dof.exp @@ -0,0 +1,78 @@ +processed 16 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 6-76: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 12509600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 78-78: +created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8), object(2,9) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 18749200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 80-80: +Owner: Object ID: ( fake(2,7) ) +Version: 2 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(2,4)}} + +task 4 'view-object'. lines 82-82: +Owner: Object ID: ( _ ) +Version: 2 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(2,5)}} + +task 5 'view-object'. lines 84-84: +Owner: Object ID: ( fake(2,6) ) +Version: 2 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(2,7)}} + +task 6 'view-object'. lines 86-86: +Owner: Object ID: ( fake(2,7) ) +Version: 2 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,3)}}, name: 1u64, value: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: _}}, value: vector[98u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8, 95u8, 100u8, 102u8]}} + +task 7 'view-object'. lines 88-88: +Owner: Object ID: ( fake(2,0) ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,4)}}, value: vector[98u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8]} + +task 8 'view-object'. lines 90-90: +Owner: Object ID: ( fake(2,1) ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,5)}}, value: vector[119u8, 114u8, 97u8, 112u8, 112u8, 101u8, 100u8, 95u8, 100u8, 102u8]} + +task 9 'view-object'. lines 92-92: +Owner: Account Address ( fake(2,8) ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,6)}}, value: vector[98u8, 95u8, 112u8, 97u8, 114u8, 101u8, 110u8, 116u8]} + +task 10 'view-object'. lines 94-94: +Owner: Object ID: ( fake(2,2) ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,7)}}, value: vector[98u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8]} + +task 11 'view-object'. lines 96-96: +Owner: Account Address ( A ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,8)}}, value: vector[97u8, 95u8, 112u8, 97u8, 114u8, 101u8, 110u8, 116u8]} + +task 12 'view-object'. lines 98-101: +Owner: Account Address ( fake(2,8) ) +Version: 2 +Contents: tto::M1::Wrapper {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,9)}}, value: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: _}}, value: vector[119u8, 114u8, 97u8, 112u8, 112u8, 101u8, 100u8]}} + +task 13 'run'. lines 102-102: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::receive_impl (function index 12) at offset 0, Abort Code: 2 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } + +task 14 'run'. lines 104-104: +created: object(14,0) +mutated: object(0,0), object(2,6), object(2,8) +gas summary: computation_cost: 1000000, storage_cost: 6011600, storage_rebate: 3521232, non_refundable_storage_fee: 35568 + +task 15 'run'. lines 106-106: +created: object(15,0) +mutated: object(0,0), object(2,8), object(2,9) +gas summary: computation_cost: 1000000, storage_cost: 6589200, storage_rebate: 4093056, non_refundable_storage_fee: 41344 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_dof.move b/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_dof.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_dof.move rename to crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_dof.move index 40a3ccee3bd..00687295e8e 100644 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_dof.move +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_dof.move @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 --accounts A //# publish module tto::M1 { - use sui::transfer::Receiving; - use sui::dynamic_object_field as dof; - use sui::dynamic_field as df; + use iota::transfer::Receiving; + use iota::dynamic_object_field as dof; + use iota::dynamic_field as df; const KEY: u64 = 0; const BKEY: u64 = 1; diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_dof.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_dof.exp new file mode 100644 index 00000000000..88e3acf71a6 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_dof.exp @@ -0,0 +1,112 @@ +processed 24 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 6-58: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 10533600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 60-60: +created: object(2,0), object(2,1), object(2,2), object(2,3) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 7273200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 62-62: +Owner: Object ID: ( fake(2,1) ) +Version: 2 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(2,3)}} + +task 4 'view-object'. lines 64-64: +Owner: Object ID: ( fake(2,0) ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,3)}}, value: 0u64} + +task 5 'view-object'. lines 66-66: +Owner: Account Address ( fake(2,2) ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, value: 0u64} + +task 6 'view-object'. lines 68-68: +Owner: Account Address ( A ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}, value: 0u64} + +task 7 'run'. lines 70-70: +created: object(7,0) +mutated: object(0,0), object(2,1), object(2,2) +gas summary: computation_cost: 1000000, storage_cost: 5996400, storage_rebate: 3506184, non_refundable_storage_fee: 35416 + +task 8 'view-object'. lines 72-74: +Owner: Object ID: ( fake(2,1) ) +Version: 2 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(2,3)}} + +task 9 'view-object'. lines 75-75: +Owner: Object ID: ( fake(2,0) ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,3)}}, value: 0u64} + +task 10 'view-object'. lines 77-77: +Owner: Object ID: ( fake(7,0) ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, value: 0u64} + +task 11 'view-object'. lines 79-79: +Owner: Account Address ( A ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}, value: 0u64} + +task 12 'programmable'. lines 81-82: +mutated: object(0,0), object(2,1), object(2,2), object(2,3) +gas summary: computation_cost: 1000000, storage_cost: 4818400, storage_rebate: 4770216, non_refundable_storage_fee: 48184 + +task 13 'view-object'. lines 84-86: +Owner: Object ID: ( fake(2,1) ) +Version: 2 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(2,3)}} + +task 14 'view-object'. lines 87-87: +Owner: Object ID: ( fake(2,0) ) +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,3)}}, value: 3u64} + +task 15 'view-object'. lines 89-89: +Owner: Object ID: ( fake(7,0) ) +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, value: 2u64} + +task 16 'view-object'. lines 91-91: +Owner: Account Address ( A ) +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}, value: 1u64} + +task 17 'programmable'. lines 93-96: +mutated: object(0,0), object(2,2) +deleted: object(2,0), object(2,3) +gas summary: computation_cost: 1000000, storage_cost: 2264800, storage_rebate: 5936436, non_refundable_storage_fee: 59964 + +task 18 'programmable'. lines 98-99: +mutated: object(_), object(2,2) +gas summary: computation_cost: 500000, storage_cost: 2264800, storage_rebate: 1264032, non_refundable_storage_fee: 12768 + +task 19 'programmable'. lines 101-102: +mutated: object(_), object(2,2) +gas summary: computation_cost: 500000, storage_cost: 2264800, storage_rebate: 1264032, non_refundable_storage_fee: 12768 + +task 20 'programmable'. lines 104-107: +mutated: object(_), object(2,2) +gas summary: computation_cost: 500000, storage_cost: 2264800, storage_rebate: 1264032, non_refundable_storage_fee: 12768 + +task 21 'programmable'. lines 109-110: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: tto, name: Identifier("M1") }, function: 4, instruction: 10, function_name: Some("check") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: tto, name: Identifier("M1") }, function: 4, instruction: 10, function_name: Some("check") }, 0) in command 0 + +task 22 'programmable'. lines 112-113: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 + +task 23 'programmable'. lines 115-116: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: tto, name: Identifier("M1") }, function: 4, instruction: 10, function_name: Some("check") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: tto, name: Identifier("M1") }, function: 4, instruction: 10, function_name: Some("check") }, 0) in command 0 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_dof.move b/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_dof.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_dof.move rename to crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_dof.move index b260d9fd37b..0b51e0c68b8 100644 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_dof.move +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/receive_object_dof.move @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 --accounts A //# publish module tto::M1 { - use sui::transfer::Receiving; - use sui::dynamic_object_field as dof; + use iota::transfer::Receiving; + use iota::dynamic_object_field as dof; const KEY: u64 = 0; diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/v0/child_of_child.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/child_of_child.exp new file mode 100644 index 00000000000..aff3874c6ed --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/child_of_child.exp @@ -0,0 +1,62 @@ +processed 14 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-66: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 9218800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 68-70: +created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 9750800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 72-72: +Owner: Account Address ( A ) +Version: 2 +Contents: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,4)}}, value: 0u64} + +task 4 'programmable'. lines 74-75: +mutated: object(0,0), object(2,2), object(2,3), object(2,4) +gas summary: computation_cost: 1000000, storage_cost: 4841200, storage_rebate: 4792788, non_refundable_storage_fee: 48412 + +task 5 'view-object'. lines 77-77: +Owner: Account Address ( A ) +Version: 3 +Contents: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,4)}}, value: 1u64} + +task 6 'programmable'. lines 79-80: +mutated: object(0,0), object(2,4) +deleted: object(2,0), object(2,2) +gas summary: computation_cost: 1000000, storage_cost: 2272400, storage_rebate: 5951484, non_refundable_storage_fee: 60116 + +task 7 'view-object'. lines 82-85: +Owner: Account Address ( A ) +Version: 4 +Contents: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,4)}}, value: 1u64} + +task 8 'programmable'. lines 87-88: +mutated: object(_), object(2,4) +gas summary: computation_cost: 500000, storage_cost: 2272400, storage_rebate: 1271556, non_refundable_storage_fee: 12844 + +task 9 'programmable'. lines 90-91: +mutated: object(_), object(2,4) +gas summary: computation_cost: 500000, storage_cost: 2272400, storage_rebate: 1271556, non_refundable_storage_fee: 12844 + +task 10 'programmable'. lines 93-97: +mutated: object(_), object(2,4) +gas summary: computation_cost: 500000, storage_cost: 2272400, storage_rebate: 1271556, non_refundable_storage_fee: 12844 + +task 11 'programmable'. lines 99-100: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 + +task 12 'programmable'. lines 102-103: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 + +task 13 'programmable'. lines 105-106: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/v0/child_of_child.move b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/child_of_child.move new file mode 100644 index 00000000000..36bd2dab86b --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/child_of_child.move @@ -0,0 +1,107 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests accessing the versions of a child of a child + +//# init --addresses test=0x0 --accounts A --protocol-version 16 + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct Obj has key, store { + id: UID, + value: u64, + } + + const KEY: u64 = 0; + + ////////////////////////////////////////////////////////////// + // new + + public fun new(ctx: &mut TxContext): Obj { + let mut grand = Obj { id: object::new(ctx), value: 0 }; + let mut parent = Obj { id: object::new(ctx), value: 0 }; + let child = Obj { id: object::new(ctx), value: 0 }; + ofield::add(&mut parent.id, KEY, child); + ofield::add(&mut grand.id, KEY, parent); + grand + } + + ////////////////////////////////////////////////////////////// + // set + + public fun set(grand: &mut Obj, v1: u64, v2: u64, v3: u64) { + grand.value = v1; + let parent: &mut Obj = ofield::borrow_mut(&mut grand.id, KEY); + parent.value = v2; + let child: &mut Obj = ofield::borrow_mut(&mut parent.id, KEY); + child.value = v3; + } + + ////////////////////////////////////////////////////////////// + // remove + + public fun remove(grand: &mut Obj) { + let parent: &mut Obj = ofield::borrow_mut(&mut grand.id, KEY); + let Obj { id, value: _ } = ofield::remove(&mut parent.id, KEY); + object::delete(id); + } + + ////////////////////////////////////////////////////////////// + // check + + public fun check(grand: &Obj, v1: u64, v2: u64, v3: Option) { + assert!(grand.value == v1, 0); + let parent: &Obj = ofield::borrow(&grand.id, KEY); + assert!(parent.value == v2, 0); + if (option::is_some(&v3)) { + let child: &Obj = ofield::borrow(&parent.id, KEY); + assert!(&child.value == option::borrow(&v3), 0); + } else { + assert!(!ofield::exists_(&parent.id, KEY), 0); + } + } +} + +//# programmable --sender A --inputs @A +//> 0: test::m::new(); +//> TransferObjects([Result(0)], Input(0)) + +//# view-object 2,4 + +//# programmable --sender A --inputs object(2,4) 1 2 3 +//> test::m::set(Input(0), Input(1), Input(2), Input(3)) + +//# view-object 2,4 + +//# programmable --sender A --inputs object(2,4) +//> test::m::remove(Input(0)) + +//# view-object 2,4 + + +// dev-inspect with 'check' and correct values + +//# programmable --sender A --inputs object(2,4)@2 0 0 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1), Input(2), Input(3)) + +//# programmable --sender A --inputs object(2,4)@3 1 2 vector[3] --dev-inspect +//> test::m::check(Input(0), Input(1), Input(2), Input(3)) + +//# programmable --sender A --inputs object(2,4)@4 1 2 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1), Input(2), Input(3)) + + +// dev-inspect with 'check' and _incorrect_ values + +//# programmable --sender A --inputs object(2,4)@3 0 0 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1), Input(2), Input(3)) + +//# programmable --sender A --inputs object(2,4)@4 1 2 vector[3] --dev-inspect +//> test::m::check(Input(0), Input(1), Input(2), Input(3)) + +//# programmable --sender A --inputs object(2,4)@2 1 2 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1), Input(2), Input(3)) diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids.exp new file mode 100644 index 00000000000..47954051a49 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids.exp @@ -0,0 +1,62 @@ +processed 14 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-117: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 12205600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 119-121: +created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 15640800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 123-123: +Owner: Account Address ( A ) +Version: 2 +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,8)}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}]} + +task 4 'programmable'. lines 125-126: +mutated: object(0,0), object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8) +gas summary: computation_cost: 1000000, storage_cost: 15640800, storage_rebate: 15484392, non_refundable_storage_fee: 156408 + +task 5 'view-object'. lines 128-128: +Owner: Account Address ( A ) +Version: 3 +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,8)}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}]} + +task 6 'programmable'. lines 130-131: +mutated: object(0,0), object(2,8) +deleted: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7) +gas summary: computation_cost: 1000000, storage_cost: 3906400, storage_rebate: 15484392, non_refundable_storage_fee: 156408 + +task 7 'view-object'. lines 133-136: +Owner: Account Address ( A ) +Version: 4 +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,8)}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}]} + +task 8 'programmable'. lines 138-139: +mutated: object(_), object(2,8) +gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 + +task 9 'programmable'. lines 141-142: +mutated: object(_), object(2,8) +gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 + +task 10 'programmable'. lines 144-148: +mutated: object(_), object(2,8) +gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 + +task 11 'programmable'. lines 150-151: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 12, function_name: Some("check_") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 12, function_name: Some("check_") }, 0) in command 0 + +task 12 'programmable'. lines 153-154: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 + +task 13 'programmable'. lines 156-157: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 20, function_name: Some("check_") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 20, function_name: Some("check_") }, 0) in command 0 diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids.move b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids.move new file mode 100644 index 00000000000..865ff0f5759 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids.move @@ -0,0 +1,158 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests finding UIDs for dynamic field access + +//# init --addresses test=0x0 --accounts A --protocol-version 16 + +//# publish + +module test::m { + use iota::dynamic_field as field; + + public struct S has key, store { + id: UID, + other: UID, + wrapped: Wrapped, + many: vector, + } + + public struct Wrapped has key, store { + id: UID, + other: UID, + } + + const KEY: u64 = 0; + + ////////////////////////////////////////////////////////////// + // new + + public fun new(ctx: &mut TxContext): S { + let mut s = S { + id: object::new(ctx), + other: object::new(ctx), + wrapped: wrapped(ctx), + many: vector[wrapped(ctx), wrapped(ctx)], + }; + field::add(&mut s.id, KEY, 0); + field::add(&mut s.other, KEY, 0); + s + } + + fun wrapped(ctx: &mut TxContext): Wrapped { + let mut w = Wrapped { + id: object::new(ctx), + other: object::new(ctx), + }; + field::add(&mut w.id, KEY, 0); + field::add(&mut w.other, KEY, 0); + w + } + + ////////////////////////////////////////////////////////////// + // set + + public fun set(s: &mut S, value: u64) { + set_(&mut s.id, value); + set_(&mut s.other, value); + set_wrapped(&mut s.wrapped, value); + set_wrapped(vector::borrow_mut(&mut s.many, 0), value); + set_wrapped(vector::borrow_mut(&mut s.many, 1), value); + } + + fun set_wrapped(w: &mut Wrapped, value: u64) { + set_(&mut w.id, value); + set_(&mut w.other, value); + + } + + fun set_(id: &mut UID, value: u64) { + *field::borrow_mut(id, KEY) = value; + } + + ////////////////////////////////////////////////////////////// + // remove + + public fun remove(s: &mut S) { + remove_(&mut s.id); + remove_(&mut s.other); + remove_wrapped(&mut s.wrapped); + remove_wrapped(vector::borrow_mut(&mut s.many, 0)); + remove_wrapped(vector::borrow_mut(&mut s.many, 1)); + } + + fun remove_wrapped(w: &mut Wrapped) { + remove_(&mut w.id); + remove_(&mut w.other); + } + + fun remove_(id: &mut UID) { + field::remove(id, KEY); + } + + ////////////////////////////////////////////////////////////// + // check + + public fun check(s: &S, expected: Option) { + check_(&s.id, expected); + check_(&s.other, expected); + check_wrapped(&s.wrapped, expected); + check_wrapped(vector::borrow(&s.many, 0), expected); + check_wrapped(vector::borrow(&s.many, 1), expected); + } + + fun check_wrapped(w: &Wrapped, expected: Option) { + check_(&w.id, expected); + check_(&w.other, expected); + } + + fun check_(id: &UID, expected: Option) { + if (option::is_some(&expected)) { + let f = field::borrow(id, KEY); + assert!(f == option::borrow(&expected), 0); + } else { + assert!(!field::exists_with_type(id, KEY), 0); + } + } +} + +//# programmable --sender A --inputs @A +//> 0: test::m::new(); +//> TransferObjects([Result(0)], Input(0)) + +//# view-object 2,8 + +//# programmable --sender A --inputs object(2,8) 112 +//> test::m::set(Input(0), Input(1)) + +//# view-object 2,8 + +//# programmable --sender A --inputs object(2,8) 112 +//> test::m::remove(Input(0)) + +//# view-object 2,8 + + +// dev-inspect with 'check' and correct values + +//# programmable --sender A --inputs object(2,8)@2 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@3 vector[112] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@4 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1)) + + +// dev-inspect with 'check' and _incorrect_ values + +//# programmable --sender A --inputs object(2,8)@3 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@4 vector[112] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@2 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1)) diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_dof.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_dof.exp new file mode 100644 index 00000000000..9c04b6a0389 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_dof.exp @@ -0,0 +1,62 @@ +processed 14 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-130: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 13353200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 132-134: +created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8), object(2,9), object(2,10), object(2,11), object(2,12), object(2,13), object(2,14), object(2,15), object(2,16) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 33941600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 136-136: +Owner: Account Address ( A ) +Version: 2 +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,8)}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}]} + +task 4 'programmable'. lines 138-139: +mutated: object(0,0), object(2,8), object(2,9), object(2,10), object(2,11), object(2,12), object(2,13), object(2,14), object(2,15), object(2,16) +gas summary: computation_cost: 1000000, storage_cost: 14303200, storage_rebate: 14160168, non_refundable_storage_fee: 143032 + +task 5 'view-object'. lines 141-141: +Owner: Account Address ( A ) +Version: 3 +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,8)}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}]} + +task 6 'programmable'. lines 143-144: +mutated: object(0,0), object(2,8) +deleted: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,9), object(2,10), object(2,11), object(2,12), object(2,13), object(2,14), object(2,15), object(2,16) +gas summary: computation_cost: 1000000, storage_cost: 3906400, storage_rebate: 33602184, non_refundable_storage_fee: 339416 + +task 7 'view-object'. lines 146-149: +Owner: Account Address ( A ) +Version: 4 +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,8)}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}, test::m::Wrapped {id: iota::object::UID {id: iota::object::ID {bytes: _}}, other: iota::object::UID {id: iota::object::ID {bytes: _}}}]} + +task 8 'programmable'. lines 151-152: +mutated: object(_), object(2,8) +gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 + +task 9 'programmable'. lines 154-155: +mutated: object(_), object(2,8) +gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 + +task 10 'programmable'. lines 157-161: +mutated: object(_), object(2,8) +gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 + +task 11 'programmable'. lines 163-164: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 18, function_name: Some("check_") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 18, function_name: Some("check_") }, 0) in command 0 + +task 12 'programmable'. lines 166-167: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 + +task 13 'programmable'. lines 169-170: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 26, function_name: Some("check_") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 26, function_name: Some("check_") }, 0) in command 0 diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_dof.move b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_dof.move new file mode 100644 index 00000000000..a2a77b57cfa --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_dof.move @@ -0,0 +1,171 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests finding UIDs for dynamic object field access + +//# init --addresses test=0x0 --accounts A --protocol-version 16 + +//# publish + +module test::m { + use iota::dynamic_object_field as ofield; + + public struct S has key, store { + id: UID, + other: UID, + wrapped: Wrapped, + many: vector, + } + + public struct Wrapped has key, store { + id: UID, + other: UID, + } + + public struct Value has key, store { + id: UID, + value: u64, + } + + const KEY: u64 = 0; + + ////////////////////////////////////////////////////////////// + // new + + public fun new(ctx: &mut TxContext): S { + let mut s = S { + id: object::new(ctx), + other: object::new(ctx), + wrapped: wrapped(ctx), + many: vector[wrapped(ctx), wrapped(ctx)], + }; + ofield::add(&mut s.id, KEY, value(0, ctx)); + ofield::add(&mut s.other, KEY, value(0, ctx)); + s + } + + fun wrapped(ctx: &mut TxContext): Wrapped { + let mut w = Wrapped { + id: object::new(ctx), + other: object::new(ctx), + }; + ofield::add(&mut w.id, KEY, value(0, ctx)); + ofield::add(&mut w.other, KEY, value(0, ctx)); + w + } + + fun value(value: u64, ctx: &mut TxContext): Value { + Value { + id: object::new(ctx), + value + } + } + + ////////////////////////////////////////////////////////////// + // set + + public fun set(s: &mut S, value: u64) { + set_(&mut s.id, value); + set_(&mut s.other, value); + set_wrapped(&mut s.wrapped, value); + set_wrapped(vector::borrow_mut(&mut s.many, 0), value); + set_wrapped(vector::borrow_mut(&mut s.many, 1), value); + } + + fun set_wrapped(w: &mut Wrapped, value: u64) { + set_(&mut w.id, value); + set_(&mut w.other, value); + + } + + fun set_(id: &mut UID, value: u64) { + ofield::borrow_mut(id, KEY).value = value; + } + + ////////////////////////////////////////////////////////////// + // remove + + public fun remove(s: &mut S) { + remove_(&mut s.id); + remove_(&mut s.other); + remove_wrapped(&mut s.wrapped); + remove_wrapped(vector::borrow_mut(&mut s.many, 0)); + remove_wrapped(vector::borrow_mut(&mut s.many, 1)); + } + + fun remove_wrapped(w: &mut Wrapped) { + remove_(&mut w.id); + remove_(&mut w.other); + } + + fun remove_(id: &mut UID) { + let Value { id, value: _ } = ofield::remove(id, KEY); + object::delete(id); + } + + ////////////////////////////////////////////////////////////// + // check + + public fun check(s: &S, expected: Option) { + check_(&s.id, expected); + check_(&s.other, expected); + check_wrapped(&s.wrapped, expected); + check_wrapped(vector::borrow(&s.many, 0), expected); + check_wrapped(vector::borrow(&s.many, 1), expected); + } + + fun check_wrapped(w: &Wrapped, expected: Option) { + check_(&w.id, expected); + check_(&w.other, expected); + } + + fun check_(id: &UID, expected: Option) { + if (option::is_some(&expected)) { + let Value { id: _, value } = ofield::borrow(id, KEY); + assert!(value == option::borrow(&expected), 0); + } else { + assert!(!ofield::exists_with_type(id, KEY), 0); + } + } +} + +//# programmable --sender A --inputs @A +//> 0: test::m::new(); +//> TransferObjects([Result(0)], Input(0)) + +//# view-object 2,8 + +//# programmable --sender A --inputs object(2,8) 112 +//> test::m::set(Input(0), Input(1)) + +//# view-object 2,8 + +//# programmable --sender A --inputs object(2,8) 112 +//> test::m::remove(Input(0)) + +//# view-object 2,8 + + +// dev-inspect with 'check' and correct values + +//# programmable --sender A --inputs object(2,8)@2 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@3 vector[112] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@4 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1)) + + +// dev-inspect with 'check' and _incorrect_ values + +//# programmable --sender A --inputs object(2,8)@3 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@4 vector[112] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,8)@2 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1)) diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_on_child.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_on_child.exp new file mode 100644 index 00000000000..d6a2494586f --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_on_child.exp @@ -0,0 +1,62 @@ +processed 14 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-140: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 13862400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 142-144: +created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8), object(2,9) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 17609200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 146-146: +Owner: Account Address ( A ) +Version: 2 +Contents: test::m::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,9)}}} + +task 4 'programmable'. lines 148-149: +mutated: object(0,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8), object(2,9) +gas summary: computation_cost: 1000000, storage_cost: 13968800, storage_rebate: 13829112, non_refundable_storage_fee: 139688 + +task 5 'view-object'. lines 151-151: +Owner: Account Address ( A ) +Version: 3 +Contents: test::m::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,9)}}} + +task 6 'programmable'. lines 153-154: +mutated: object(0,0), object(2,9) +deleted: object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8) +gas summary: computation_cost: 1000000, storage_cost: 2234400, storage_rebate: 13829112, non_refundable_storage_fee: 139688 + +task 7 'view-object'. lines 156-159: +Owner: Account Address ( A ) +Version: 4 +Contents: test::m::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,9)}}} + +task 8 'programmable'. lines 161-162: +mutated: object(_), object(2,9) +gas summary: computation_cost: 500000, storage_cost: 2234400, storage_rebate: 1233936, non_refundable_storage_fee: 12464 + +task 9 'programmable'. lines 164-165: +mutated: object(_), object(2,9) +gas summary: computation_cost: 500000, storage_cost: 2234400, storage_rebate: 1233936, non_refundable_storage_fee: 12464 + +task 10 'programmable'. lines 167-171: +mutated: object(_), object(2,9) +gas summary: computation_cost: 500000, storage_cost: 2234400, storage_rebate: 1233936, non_refundable_storage_fee: 12464 + +task 11 'programmable'. lines 173-174: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 12, function_name: Some("check_") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 12, function_name: Some("check_") }, 0) in command 0 + +task 12 'programmable'. lines 176-177: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 + +task 13 'programmable'. lines 179-180: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 20, function_name: Some("check_") }, 0) in command 0 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 20, function_name: Some("check_") }, 0) in command 0 diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_on_child.move b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_on_child.move new file mode 100644 index 00000000000..bb4b50bd745 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_on_child.move @@ -0,0 +1,181 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests finding UIDs for dynamic field access on a child object (non-input) + +//# init --addresses test=0x0 --accounts A --protocol-version 16 + +//# publish + +module test::m { + use iota::dynamic_field as field; + + public struct Parent has key, store { + id: UID, + } + + public struct S has key, store { + id: UID, + other: UID, + wrapped: Wrapped, + many: vector, + } + + public struct Wrapped has key, store { + id: UID, + other: UID, + } + + const KEY: u64 = 0; + + ////////////////////////////////////////////////////////////// + // new + + public fun new(ctx: &mut TxContext): Parent { + let mut parent = Parent { id: object::new(ctx) }; + field::add(&mut parent.id, KEY, s(ctx)); + parent + } + + fun s(ctx: &mut TxContext): S { + let mut s = S { + id: object::new(ctx), + other: object::new(ctx), + wrapped: wrapped(ctx), + many: vector[wrapped(ctx), wrapped(ctx)], + }; + field::add(&mut s.id, KEY, 0); + field::add(&mut s.other, KEY, 0); + s + } + + fun wrapped(ctx: &mut TxContext): Wrapped { + let mut w = Wrapped { + id: object::new(ctx), + other: object::new(ctx), + }; + field::add(&mut w.id, KEY, 0); + field::add(&mut w.other, KEY, 0); + w + } + + ////////////////////////////////////////////////////////////// + // set + + public fun set(parent: &mut Parent, value: u64) { + set_s(field::borrow_mut(&mut parent.id, KEY), value); + } + + + fun set_s(s: &mut S, value: u64) { + set_(&mut s.id, value); + set_(&mut s.other, value); + set_wrapped(&mut s.wrapped, value); + set_wrapped(vector::borrow_mut(&mut s.many, 0), value); + set_wrapped(vector::borrow_mut(&mut s.many, 1), value); + } + + fun set_wrapped(w: &mut Wrapped, value: u64) { + set_(&mut w.id, value); + set_(&mut w.other, value); + + } + + fun set_(id: &mut UID, value: u64) { + *field::borrow_mut(id, KEY) = value; + } + + ////////////////////////////////////////////////////////////// + // remove + + public fun remove(parent: &mut Parent) { + remove_s(field::borrow_mut(&mut parent.id, KEY)); + } + + fun remove_s(s: &mut S) { + remove_(&mut s.id); + remove_(&mut s.other); + remove_wrapped(&mut s.wrapped); + remove_wrapped(vector::borrow_mut(&mut s.many, 0)); + remove_wrapped(vector::borrow_mut(&mut s.many, 1)); + } + + fun remove_wrapped(w: &mut Wrapped) { + remove_(&mut w.id); + remove_(&mut w.other); + } + + fun remove_(id: &mut UID) { + field::remove(id, KEY); + } + + ////////////////////////////////////////////////////////////// + // check + + public fun check(parent: &Parent, expected: Option) { + check_s(field::borrow(&parent.id, KEY), expected); + } + + fun check_s(s: &S, expected: Option) { + check_(&s.id, expected); + check_(&s.other, expected); + check_wrapped(&s.wrapped, expected); + check_wrapped(vector::borrow(&s.many, 0), expected); + check_wrapped(vector::borrow(&s.many, 1), expected); + } + + fun check_wrapped(w: &Wrapped, expected: Option) { + check_(&w.id, expected); + check_(&w.other, expected); + } + + fun check_(id: &UID, expected: Option) { + if (option::is_some(&expected)) { + let f = field::borrow(id, KEY); + assert!(f == option::borrow(&expected), 0); + } else { + assert!(!field::exists_with_type(id, KEY), 0); + } + } +} + +//# programmable --sender A --inputs @A +//> 0: test::m::new(); +//> TransferObjects([Result(0)], Input(0)) + +//# view-object 2,9 + +//# programmable --sender A --inputs object(2,9) 112 +//> test::m::set(Input(0), Input(1)) + +//# view-object 2,9 + +//# programmable --sender A --inputs object(2,9) 112 +//> test::m::remove(Input(0)) + +//# view-object 2,9 + + +// dev-inspect with 'check' and correct values + +//# programmable --sender A --inputs object(2,9)@2 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,9)@3 vector[112] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,9)@4 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1)) + + +// dev-inspect with 'check' and _incorrect_ values + +//# programmable --sender A --inputs object(2,9)@3 vector[0] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,9)@4 vector[112] --dev-inspect +//> test::m::check(Input(0), Input(1)) + +//# programmable --sender A --inputs object(2,9)@2 vector[] --dev-inspect +//> test::m::check(Input(0), Input(1)) diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/v0/middle_version_less_than_child.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/middle_version_less_than_child.exp new file mode 100644 index 00000000000..ca19df92b5d --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/middle_version_less_than_child.exp @@ -0,0 +1,52 @@ +processed 11 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-51: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 7493600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 53-57: +created: object(2,0), object(2,1), object(2,2) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 6285200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 59-59: +Owner: Object ID: ( _ ) +Version: 2 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, name: 0u64, value: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: _}}, value: 0u64}} + +task 4 'view-object'. lines 61-61: +Owner: Object ID: ( fake(2,2) ) +Version: 2 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, name: 0u64, value: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: _}}, value: 0u64}} + +task 5 'view-object'. lines 63-63: +Owner: Account Address ( A ) +Version: 2 +Contents: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}, value: 0u64} + +task 6 'programmable'. lines 65-68: +mutated: object(0,0), object(2,0), object(2,2) +gas summary: computation_cost: 1000000, storage_cost: 4278800, storage_rebate: 4236012, non_refundable_storage_fee: 42788 + +task 7 'view-object'. lines 70-70: +Owner: Object ID: ( _ ) +Version: 3 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, name: 0u64, value: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: _}}, value: 112u64}} + +task 8 'view-object'. lines 72-72: +Owner: Object ID: ( fake(2,2) ) +Version: 2 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, name: 0u64, value: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: _}}, value: 0u64}} + +task 9 'view-object'. lines 74-77: +Owner: Account Address ( A ) +Version: 3 +Contents: test::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}, value: 0u64} + +task 10 'programmable'. lines 79-80: +mutated: object(0,0), object(2,2) +gas summary: computation_cost: 1000000, storage_cost: 2272400, storage_rebate: 2249676, non_refundable_storage_fee: 22724 diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/v0/middle_version_less_than_child.move b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/middle_version_less_than_child.move new file mode 100644 index 00000000000..7506abc83c3 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/middle_version_less_than_child.move @@ -0,0 +1,81 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests accessing the versions of a child of a child + +//# init --addresses test=0x0 --accounts A --protocol-version 16 + +//# publish + +module test::m { + use iota::dynamic_field as field; + + public struct Obj has key, store { + id: UID, + value: u64, + } + + const KEY: u64 = 0; + + ////////////////////////////////////////////////////////////// + // new + + public fun new(ctx: &mut TxContext): Obj { + let mut grand = Obj { id: object::new(ctx), value: 0 }; + let mut parent = Obj { id: object::new(ctx), value: 0 }; + let child = Obj { id: object::new(ctx), value: 0 }; + field::add(&mut parent.id, KEY, child); + field::add(&mut grand.id, KEY, parent); + grand + } + + ////////////////////////////////////////////////////////////// + // set + + public fun set(grand: &mut Obj, v: u64) { + let parent: &mut Obj = field::borrow_mut(&mut grand.id, KEY); + let child: &mut Obj = field::borrow_mut(&mut parent.id, KEY); + child.value = v; + } + + ////////////////////////////////////////////////////////////// + // check + + public fun check(grand: &Obj, expected: u64) { + assert!(grand.value == 0, 0); + let parent: &Obj = field::borrow(&grand.id, KEY); + assert!(parent.value == 0, 0); + let child: &Obj = field::borrow(&parent.id, KEY); + assert!(child.value == expected, 0); + } +} + +//# programmable --sender A --inputs @A +//> 0: test::m::new(); +//> TransferObjects([Result(0)], Input(0)) + +// All 3 objects have version 2 + +//# view-object 2,0 + +//# view-object 2,1 + +//# view-object 2,2 + +//# programmable --sender A --inputs object(2,2) 112 +//> test::m::set(Input(0), Input(1)) + +// The middle object has version 2, while the root and modified leaf have version 3 + +//# view-object 2,0 + +//# view-object 2,1 + +//# view-object 2,2 + +// correctly load the leaf even though it has a version greater than its immediate +// parent + +//# programmable --sender A --inputs object(2,2) 112 +//> test::m::check(Input(0), Input(1)) diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/v0/not_root_version.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/not_root_version.exp new file mode 100644 index 00000000000..e46d70ca2c8 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/not_root_version.exp @@ -0,0 +1,66 @@ +processed 14 tasks + +init: +P1: object(0,0), P2: object(0,1) + +task 1 'publish'. lines 8-53: +created: object(1,0) +mutated: object(0,2) +gas summary: computation_cost: 1000000, storage_cost: 7432800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 55-57: +created: object(2,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'programmable'. lines 59-60: +mutated: object(0,0), object(2,0) +gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 2174436, non_refundable_storage_fee: 21964 + +task 4 'programmable'. lines 62-63: +mutated: object(0,0), object(2,0) +gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 2174436, non_refundable_storage_fee: 21964 + +task 5 'view-object'. lines 65-68: +Owner: Account Address ( P1 ) +Version: 4 +Contents: test::m::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 6 'programmable'. lines 70-72: +created: object(6,0), object(6,1) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 7 'view-object'. lines 74-74: +Owner: Object ID: ( fake(6,1) ) +Version: 2 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}, name: 0u64, value: 0u64} + +task 8 'programmable'. lines 76-77: +mutated: object(0,1), object(6,0), object(6,1) +gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 3626568, non_refundable_storage_fee: 36632 + +task 9 'view-object'. lines 79-83: +Owner: Object ID: ( fake(6,1) ) +Version: 3 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}, name: 0u64, value: 1u64} + +task 10 'programmable'. lines 85-90: +created: object(10,0) +mutated: object(_), object(2,0) +wrapped: object(6,1) +gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 + +task 11 'programmable'. lines 92-96: +created: object(10,0) +mutated: object(_), object(2,0) +wrapped: object(6,1) +gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 + +task 12 'programmable'. lines 98-102: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 + +task 13 'programmable'. lines 104-106: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/v0/not_root_version.move b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/not_root_version.move new file mode 100644 index 00000000000..49211202abf --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/not_root_version.move @@ -0,0 +1,107 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests accessing version of the input parent, not the runtime parent + +//# init --addresses test=0x0 --accounts P1 P2 --protocol-version 16 + +//# publish + +module test::m { + use iota::dynamic_field as field; + + public struct A has key, store { + id: UID, + } + + public struct B has key, store { + id: UID, + } + + const KEY: u64 = 0; + + public fun a(ctx: &mut TxContext): A { + A { id: object::new(ctx) } + } + + public fun b(ctx: &mut TxContext): B { + let mut b = B { id: object::new(ctx) }; + field::add(&mut b.id, KEY, 0); + b + + } + + public fun bump(b: &mut B) { + let f = field::borrow_mut(&mut b.id, KEY); + *f = *f + 1; + } + + public fun append(a: &mut A, b: B) { + field::add(&mut a.id, KEY, b); + } + + public fun check(a: &A, expected: u64) { + let b: &B = field::borrow(&a.id, KEY); + let v = *field::borrow(&b.id, KEY); + assert!(v == expected, 0); + } + + public fun nop() { + } +} + +// Create object A and bump the version to 4 + +//# programmable --sender P1 --inputs @P1 +//> 0: test::m::a(); +//> TransferObjects([Result(0)], Input(0)) + +//# programmable --sender P1 --inputs object(2,0) +//> test::m::nop(); + +//# programmable --sender P1 --inputs object(2,0) +//> test::m::nop(); + +//# view-object 2,0 + + +// Create object B witha version 2 and 3 for it's dynamic field + +//# programmable --sender P2 --inputs @P2 +//> 0: test::m::b(); +//> TransferObjects([Result(0)], Input(0)) + +//# view-object 6,0 + +//# programmable --sender P2 --inputs object(6,1) +//> 0: test::m::bump(Input(0)); + +//# view-object 6,0 + + +// Append object B to object A, but using version 2 of object B. And ensure that +// when we later read the dynamic field of object B, we get the version 2 value. + +//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@2 0 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); + +// checking that with version 3 we get the other value, then flip them to ensure +// they abort + +//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@3 1 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); + +// @2 with value 1 aborts + +//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@2 1 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); + +// @3 with value 0 aborts + +//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@3 0 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/v0/not_root_version_flipped_case.exp b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/not_root_version_flipped_case.exp new file mode 100644 index 00000000000..75e01454d1b --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/not_root_version_flipped_case.exp @@ -0,0 +1,58 @@ +processed 12 tasks + +init: +P1: object(0,0), P2: object(0,1) + +task 1 'publish'. lines 8-53: +created: object(1,0) +mutated: object(0,2) +gas summary: computation_cost: 1000000, storage_cost: 7432800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 55-57: +created: object(2,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 60-63: +Owner: Account Address ( P1 ) +Version: 2 +Contents: test::m::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 4 'programmable'. lines 65-67: +created: object(4,0), object(4,1) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 5 'view-object'. lines 69-69: +Owner: Object ID: ( fake(4,1) ) +Version: 2 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(4,0)}}, name: 0u64, value: 0u64} + +task 6 'programmable'. lines 71-72: +mutated: object(0,1), object(4,0), object(4,1) +gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 3626568, non_refundable_storage_fee: 36632 + +task 7 'view-object'. lines 74-77: +Owner: Object ID: ( fake(4,1) ) +Version: 3 +Contents: iota::dynamic_field::Field {id: iota::object::UID {id: iota::object::ID {bytes: fake(4,0)}}, name: 0u64, value: 1u64} + +task 8 'programmable'. lines 79-84: +created: object(8,0) +mutated: object(_), object(2,0) +wrapped: object(4,1) +gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 + +task 9 'programmable'. lines 86-90: +created: object(8,0) +mutated: object(_), object(2,0) +wrapped: object(4,1) +gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 + +task 10 'programmable'. lines 92-96: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 + +task 11 'programmable'. lines 98-100: +Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 +Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 diff --git a/crates/iota-adapter-transactional-tests/tests/mvcc/v0/not_root_version_flipped_case.move b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/not_root_version_flipped_case.move new file mode 100644 index 00000000000..667c3ca2b47 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/mvcc/v0/not_root_version_flipped_case.move @@ -0,0 +1,101 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests accessing version of the input parent, not the runtime parent + +//# init --addresses test=0x0 --accounts P1 P2 --protocol-version 16 + +//# publish + +module test::m { + use iota::dynamic_field as field; + + public struct A has key, store { + id: UID, + } + + public struct B has key, store { + id: UID, + } + + const KEY: u64 = 0; + + public fun a(ctx: &mut TxContext): A { + A { id: object::new(ctx) } + } + + public fun b(ctx: &mut TxContext): B { + let mut b = B { id: object::new(ctx) }; + field::add(&mut b.id, KEY, 0); + b + + } + + public fun bump(b: &mut B) { + let f = field::borrow_mut(&mut b.id, KEY); + *f = *f + 1; + } + + public fun append(a: &mut A, b: B) { + field::add(&mut a.id, KEY, b); + } + + public fun check(a: &A, expected: u64) { + let b: &B = field::borrow(&a.id, KEY); + let v = *field::borrow(&b.id, KEY); + assert!(v == expected, 0); + } + + public fun nop() { + } +} + +// Create object A at version 2 + +//# programmable --sender P1 --inputs @P1 +//> 0: test::m::a(); +//> TransferObjects([Result(0)], Input(0)) + + +//# view-object 2,0 + + +// Create object B with a version 2 and 3 for it's dynamic field + +//# programmable --sender P2 --inputs @P2 +//> 0: test::m::b(); +//> TransferObjects([Result(0)], Input(0)) + +//# view-object 4,0 + +//# programmable --sender P2 --inputs object(4,1) +//> 0: test::m::bump(Input(0)); + +//# view-object 4,0 + +// Append object B to object A. And ensure that when we later read the dynamic +// field of object B, we get the most recent version. + +//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@3 1 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); + +// checking that with version 3 we get the other value, then flip them to ensure +// they abort + +//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@2 0 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); + +// @2 with value 1 aborts + +//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@2 1 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); + +// @3 with value 0 aborts + +//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@3 0 --dev-inspect +//> 0: test::m::append(Input(0), Input(1)); +//> 1: test::m::check(Input(0), Input(2)); diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_copyable_invalid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_copyable_invalid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_copyable_invalid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_copyable_invalid.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_copyable_invalid.move b/crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_copyable_invalid.move similarity index 94% rename from crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_copyable_invalid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_copyable_invalid.move index 3e86cd6f459..ea01bd2e9f9 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_copyable_invalid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_copyable_invalid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests various invalid usages of a borrowed arg diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_non_copyable_invalid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_non_copyable_invalid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_non_copyable_invalid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_non_copyable_invalid.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_non_copyable_invalid.move b/crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_non_copyable_invalid.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_non_copyable_invalid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_non_copyable_invalid.move index 64d7cbaaedc..efa4d4d5d96 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_non_copyable_invalid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_non_copyable_invalid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests various invalid usages of a borrowed arg diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_primitives_invalid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_primitives_invalid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_primitives_invalid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_primitives_invalid.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_primitives_invalid.move b/crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_primitives_invalid.move similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_primitives_invalid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_primitives_invalid.move index 3955587f78e..a0cef78b774 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_primitives_invalid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_primitives_invalid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests various invalid usages of a borrowed arg in non-Move calls diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_valid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_valid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_valid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_valid.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_valid.move b/crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_valid.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_valid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_valid.move index ccc156454d9..a9377592cb4 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/borrowed_arg_valid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/borrowed_arg_valid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests various usages of a borrowed arg diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_emit.exp b/crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_emit.exp similarity index 82% rename from crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_emit.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_emit.exp index c58143a2d6b..9181dc8d904 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_emit.exp +++ b/crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_emit.exp @@ -10,12 +10,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3906400, storage_rebate: task 2 'programmable'. lines 14-16: Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call functions in sui::event"), command: Some(1) } } +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call functions in iota::event"), command: Some(1) } } task 3 'programmable'. lines 18-21: Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call functions in sui::event"), command: Some(1) } } +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call functions in iota::event"), command: Some(1) } } task 4 'programmable'. lines 23-26: Error: Transaction Effects Status: Function Not Found. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: FunctionNotFound, source: Some("Could not resolve function 'does_not_exist' in module sui::event"), command: Some(1) } } +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: FunctionNotFound, source: Some("Could not resolve function 'does_not_exist' in module iota::event"), command: Some(1) } } diff --git a/crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_emit.move b/crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_emit.move new file mode 100644 index 00000000000..1aeace98c56 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_emit.move @@ -0,0 +1,27 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests cannot call init with programmable transactions + +//# init --addresses test=0x0 --accounts A + +//# publish +module test::m1 { + public struct A has copy, drop, store {} + public fun a(): A { A {} } +} + +//# programmable +//> 0: test::m1::a(); +//> iota::event::emit(Result(0)); + +//# programmable +//> 0: test::m1::a(); +// wrong type annotation doesn't matter +//> iota::event::emit(Result(0)); + +//# programmable +//> 0: test::m1::a(); +// function doesn't exist +//> iota::event::does_not_exist(Result(0)); diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_init.exp b/crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_init.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_init.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_init.exp diff --git a/crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_init.move b/crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_init.move new file mode 100644 index 00000000000..e0cd8f3aabf --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_init.move @@ -0,0 +1,15 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests cannot call init with programmable transactions + +//# init --addresses test=0x0 --accounts A + +//# publish +module test::m1 { + fun init(_: &mut iota::tx_context::TxContext) {} +} + +//# programmable +//> 0: test::m1::init(); diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_private.exp b/crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_private.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_private.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_private.exp diff --git a/crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_private.move b/crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_private.move new file mode 100644 index 00000000000..4162e46e6e2 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable/cannot_call_private.move @@ -0,0 +1,15 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests cannot call private with programmable transactions + +//# init --addresses test=0x0 --accounts A + +//# publish +module test::m1 { + fun priv(_: &mut iota::tx_context::TxContext) {} +} + +//# programmable +//> 0: test::m1::priv(); diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/coin_negative.exp b/crates/iota-adapter-transactional-tests/tests/programmable/coin_negative.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/coin_negative.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/coin_negative.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/coin_negative.move b/crates/iota-adapter-transactional-tests/tests/programmable/coin_negative.move similarity index 86% rename from crates/sui-adapter-transactional-tests/tests/programmable/coin_negative.move rename to crates/iota-adapter-transactional-tests/tests/programmable/coin_negative.move index 8b538e66b2b..58105d03c88 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/coin_negative.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/coin_negative.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests coin balance going negative on split @@ -7,7 +8,7 @@ //# publish --sender A module test::fake { - use sui::coin; + use iota::coin; public struct FAKE has drop {} @@ -20,7 +21,7 @@ module test::fake { } //# programmable --sender A --inputs object(1,2) 1 @A -//> 0: sui::coin::mint(Input(0), Input(1)); +//> 0: iota::coin::mint(Input(0), Input(1)); //> TransferObjects([Result(0)], Input(2)) //# programmable --sender A --inputs object(2,0) 2 diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/coin_operations_custom_coin.exp b/crates/iota-adapter-transactional-tests/tests/programmable/coin_operations_custom_coin.exp similarity index 81% rename from crates/sui-adapter-transactional-tests/tests/programmable/coin_operations_custom_coin.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/coin_operations_custom_coin.exp index efec9da047c..5064d1e70ea 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/coin_operations_custom_coin.exp +++ b/crates/iota-adapter-transactional-tests/tests/programmable/coin_operations_custom_coin.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 4012800, storage_rebate: task 3 'view-object'. lines 26-26: Owner: Account Address ( A ) Version: 3 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, balance: sui::balance::Balance {value: 100u64}} +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, balance: iota::balance::Balance {value: 100u64}} task 4 'programmable'. lines 28-34: created: object(4,0) diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/coin_operations_custom_coin.move b/crates/iota-adapter-transactional-tests/tests/programmable/coin_operations_custom_coin.move similarity index 78% rename from crates/sui-adapter-transactional-tests/tests/programmable/coin_operations_custom_coin.move rename to crates/iota-adapter-transactional-tests/tests/programmable/coin_operations_custom_coin.move index 44cab7b800d..529fde82551 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/coin_operations_custom_coin.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/coin_operations_custom_coin.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests coin operations with custom coins @@ -7,7 +8,7 @@ //# publish --sender A module test::fake { - use sui::coin; + use iota::coin; public struct FAKE has drop {} @@ -20,14 +21,14 @@ module test::fake { } //# programmable --sender A --inputs object(1,2) 100 @A -//> 0: sui::coin::mint(Input(0), Input(1)); +//> 0: iota::coin::mint(Input(0), Input(1)); //> TransferObjects([Result(0)], Input(2)) //# view-object 2,0 //# programmable --sender A --inputs object(1,2) 100 object(2,0) 1 @A -//> 0: sui::coin::mint(Input(0), Input(1)); -//> 1: sui::coin::mint(Input(0), Input(1)); +//> 0: iota::coin::mint(Input(0), Input(1)); +//> 1: iota::coin::mint(Input(0), Input(1)); //> 2: SplitCoins(Result(0), [Input(3)]); //> 3: SplitCoins(Input(2), [Input(3)]); //> MergeCoins(Result(1), [Result(0), Input(2), Result(2), Result(3)]); diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/coin_operations_non_coins.exp b/crates/iota-adapter-transactional-tests/tests/programmable/coin_operations_non_coins.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/coin_operations_non_coins.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/coin_operations_non_coins.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/coin_operations_non_coins.move b/crates/iota-adapter-transactional-tests/tests/programmable/coin_operations_non_coins.move similarity index 84% rename from crates/sui-adapter-transactional-tests/tests/programmable/coin_operations_non_coins.move rename to crates/iota-adapter-transactional-tests/tests/programmable/coin_operations_non_coins.move index 48fec0bb190..313d0bce519 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/coin_operations_non_coins.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/coin_operations_non_coins.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // test invalid usages of coin commands @@ -24,17 +25,17 @@ module test::m1 { // split non-coin //# programmable --sender A --inputs 0 -//> 0: test::m1::mint(); +//> 0: test::m1::mint(); //> SplitCoins(Result(0), [Input(0)]) // merge into non-coin //# programmable --sender A --inputs 0 -//> 0: test::m1::mint(); +//> 0: test::m1::mint(); //> MergeCoins(Result(0), [Gas]) // merge non-coin into gas //# programmable --sender A --inputs 0 -//> 0: test::m1::mint(); +//> 0: test::m1::mint(); //> MergeCoins(Gas, [Result(0)]) //# programmable --sender A --inputs 10000u64 diff --git a/crates/iota-adapter-transactional-tests/tests/programmable/coin_overflow.exp b/crates/iota-adapter-transactional-tests/tests/programmable/coin_overflow.exp new file mode 100644 index 00000000000..174fdf88b6a --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable/coin_overflow.exp @@ -0,0 +1,22 @@ +processed 5 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-20: +created: object(1,0), object(1,1), object(1,2) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 10617200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 22-24: +created: object(2,0) +mutated: object(0,0), object(1,2) +gas summary: computation_cost: 1000000, storage_cost: 4012800, storage_rebate: 2663496, non_refundable_storage_fee: 26904 + +task 3 'programmable'. lines 26-28: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::balance::increase_supply (function index 3) at offset 12, Abort Code: 1 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("balance") }, function: 3, instruction: 12, function_name: Some("increase_supply") }, 1), source: Some(VMError { major_status: ABORTED, sub_status: Some(1), message: Some("iota::balance::increase_supply at offset 12"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("balance") }), indices: [], offsets: [(FunctionDefinitionIndex(3), 12)] }), command: Some(0) } } + +task 4 'programmable'. lines 30-31: +Error: Transaction Effects Status: Invalid command argument at 1. Invalid usage of value. Mutably borrowed values require unique usage. Immutably borrowed values cannot be taken or borrowed mutably. Taken values cannot be used again. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: CommandArgumentError { arg_idx: 1, kind: InvalidValueUsage }, source: None, command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/coin_overflow.move b/crates/iota-adapter-transactional-tests/tests/programmable/coin_overflow.move similarity index 82% rename from crates/sui-adapter-transactional-tests/tests/programmable/coin_overflow.move rename to crates/iota-adapter-transactional-tests/tests/programmable/coin_overflow.move index 6e5a16a0f70..c0b2a9cc523 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/coin_overflow.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/coin_overflow.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests coin overflow... which isn't actually possible without directly editing the coin bytes @@ -7,7 +8,7 @@ //# publish --sender A module test::fake { - use sui::coin; + use iota::coin; public struct FAKE has drop {} @@ -20,11 +21,11 @@ module test::fake { } //# programmable --sender A --inputs object(1,2) 18446744073709551614 @A -//> 0: sui::coin::mint(Input(0), Input(1)); +//> 0: iota::coin::mint(Input(0), Input(1)); //> TransferObjects([Result(0)], Input(2)) //# programmable --sender A --inputs object(1,2) 1 @A -//> 0: sui::coin::mint(Input(0), Input(1)); +//> 0: iota::coin::mint(Input(0), Input(1)); //> TransferObjects([Result(0)], Input(2)) //# programmable --sender A --inputs object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/delayed_invalid_gas_by_value.exp b/crates/iota-adapter-transactional-tests/tests/programmable/delayed_invalid_gas_by_value.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/delayed_invalid_gas_by_value.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/delayed_invalid_gas_by_value.exp diff --git a/crates/iota-adapter-transactional-tests/tests/programmable/delayed_invalid_gas_by_value.move b/crates/iota-adapter-transactional-tests/tests/programmable/delayed_invalid_gas_by_value.move new file mode 100644 index 00000000000..7991ad2d939 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable/delayed_invalid_gas_by_value.move @@ -0,0 +1,24 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests that gas-by-value rules come after taken/borrow rules + +//# init --addresses test=0x0 --accounts A + +//# publish +module test::m1 { + public fun take(_: T) { abort 0 } + public fun imm(_: &T, _: T) { abort 0 } + public fun mut_(_: &mut T, _: T) { abort 0 } +} + +//# programmable --sender A --inputs @A +//> TransferObjects([Gas], Input(0)); +//> test::m1::take>(Gas) + +//# programmable +//> test::m1::imm>(Gas, Gas) + +//# programmable +//> test::m1::mut_>(Gas, Gas) diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/delayed_invalid_object_by_value.exp b/crates/iota-adapter-transactional-tests/tests/programmable/delayed_invalid_object_by_value.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/delayed_invalid_object_by_value.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/delayed_invalid_object_by_value.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/delayed_invalid_object_by_value.move b/crates/iota-adapter-transactional-tests/tests/programmable/delayed_invalid_object_by_value.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/programmable/delayed_invalid_object_by_value.move rename to crates/iota-adapter-transactional-tests/tests/programmable/delayed_invalid_object_by_value.move index 0acf9e7244f..8ee2c5bd730 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/delayed_invalid_object_by_value.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/delayed_invalid_object_by_value.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests that object-by-value rules come after taken/borrow rules diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_reference.exp b/crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_reference.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_reference.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_reference.exp diff --git a/crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_reference.move b/crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_reference.move new file mode 100644 index 00000000000..1eb97f04e37 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_reference.move @@ -0,0 +1,47 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests valid gas coin usage by reference + +//# init --addresses test=0x0 --accounts A + +//# publish +module test::m1 { + public entry fun t1(_: &T) { + } + public fun t2(_: &T) { + } + entry fun t3(_: &T) { + } + public entry fun t4(_: &mut T) { + } + public fun t5(_: &mut T) { + } + entry fun t6(_: &mut T) { + } +} + +// can pass to Move function by ref +//# programmable --sender A +//> test::m1::t1>(Gas) + +//# programmable --sender A +//> test::m1::t2>(Gas) + +//# programmable --sender A +//> test::m1::t2>(Gas) + +//# programmable --sender A +//> test::m1::t4>(Gas) + +//# programmable --sender A +//> test::m1::t5>(Gas) + +//# programmable --sender A +//> test::m1::t6>(Gas) + +// can pass to merge and split +//# programmable --sender A --inputs 10 --gas-budget 10000000000 +//> 0: SplitCoins(Gas, [Input(0)]); +//> MergeCoins(Gas, [Result(0)]) diff --git a/crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_value.exp b/crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_value.exp new file mode 100644 index 00000000000..ad596784800 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_value.exp @@ -0,0 +1,13 @@ +processed 3 tasks + +init: +A: object(0,0), B: object(0,1) + +task 1 'programmable'. lines 8-9: +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'view-object'. lines 11-11: +Owner: Account Address ( B ) +Version: 2 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(0,0)}}, balance: iota::balance::Balance {value: 299999998012000u64}} diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_value.move b/crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_value.move similarity index 83% rename from crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_value.move rename to crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_value.move index 9692cbecda7..e7b3c4ad5c1 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_value.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_value.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests valid gas coin usage by value diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_value_invalid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_value_invalid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_value_invalid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_value_invalid.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_value_invalid.move b/crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_value_invalid.move similarity index 75% rename from crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_value_invalid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_value_invalid.move index 7bdf2ac23bf..550c053c808 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_value_invalid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/gas_coin_by_value_invalid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests invalid gas coin usage by value @@ -22,13 +23,13 @@ module test::m1 { // cannot pass to Move function //# programmable --sender A -//> test::m1::t1>(Gas) +//> test::m1::t1>(Gas) //# programmable --sender A -//> test::m1::t2>(Gas) +//> test::m1::t2>(Gas) //# programmable --sender A -//> test::m1::t2>(Gas) +//> test::m1::t2>(Gas) // cannot merge gas coin //# programmable --sender A --inputs 10 --gas-budget 10000000000 @@ -42,4 +43,4 @@ module test::m1 { // we give the error that the gas coin was taken, even though this call is invalid //# programmable --sender A --inputs @A //> TransferObjects([Gas], Input(0)); -//> test::m1::t1>(Gas) +//> test::m1::t1>(Gas) diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/generics_substitution.exp b/crates/iota-adapter-transactional-tests/tests/programmable/generics_substitution.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/generics_substitution.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/generics_substitution.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/generics_substitution.move b/crates/iota-adapter-transactional-tests/tests/programmable/generics_substitution.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/programmable/generics_substitution.move rename to crates/iota-adapter-transactional-tests/tests/programmable/generics_substitution.move index 6e488c14e8f..c756b1e8206 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/generics_substitution.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/generics_substitution.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests correct generic substitution in Move call diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/invalid_option.exp b/crates/iota-adapter-transactional-tests/tests/programmable/invalid_option.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/invalid_option.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/invalid_option.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/invalid_option.move b/crates/iota-adapter-transactional-tests/tests/programmable/invalid_option.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/programmable/invalid_option.move rename to crates/iota-adapter-transactional-tests/tests/programmable/invalid_option.move index c2db39e21ea..7c39309a530 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/invalid_option.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/invalid_option.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests various invalid vector instantions for types @@ -39,7 +40,7 @@ module test::m1 { //> test::m1::option_prim
    (Input(0)); //# programmable --inputs vector[@0,@0] -//> test::m1::option_prim(Input(0)); +//> test::m1::option_prim(Input(0)); // vectors @@ -69,4 +70,4 @@ module test::m1 { //> test::m1::option_prim>(Input(0)); //# programmable --inputs vector[vector[],vector[]] -//> test::m1::option_prim>(Input(0)); +//> test::m1::option_prim>(Input(0)); diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/invalid_public_function_return.exp b/crates/iota-adapter-transactional-tests/tests/programmable/invalid_public_function_return.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/invalid_public_function_return.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/invalid_public_function_return.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/invalid_public_function_return.move b/crates/iota-adapter-transactional-tests/tests/programmable/invalid_public_function_return.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/programmable/invalid_public_function_return.move rename to crates/iota-adapter-transactional-tests/tests/programmable/invalid_public_function_return.move index 641d098b2c7..888faf9d66c 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/invalid_public_function_return.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/invalid_public_function_return.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests invalid return values from public functions diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/invalid_result_arity.exp b/crates/iota-adapter-transactional-tests/tests/programmable/invalid_result_arity.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/invalid_result_arity.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/invalid_result_arity.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/invalid_result_arity.move b/crates/iota-adapter-transactional-tests/tests/programmable/invalid_result_arity.move similarity index 94% rename from crates/sui-adapter-transactional-tests/tests/programmable/invalid_result_arity.move rename to crates/iota-adapter-transactional-tests/tests/programmable/invalid_result_arity.move index db0221b991b..46a21729376 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/invalid_result_arity.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/invalid_result_arity.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests when NestedResult is needed, but Result is used diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/make_vec_objects.exp b/crates/iota-adapter-transactional-tests/tests/programmable/make_vec_objects.exp similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/programmable/make_vec_objects.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/make_vec_objects.exp index cdb279a19b8..159781d06ea 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/make_vec_objects.exp +++ b/crates/iota-adapter-transactional-tests/tests/programmable/make_vec_objects.exp @@ -28,7 +28,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2280000, storage_rebate: task 6 'view-object'. lines 70-70: Owner: Account Address ( A ) Version: 5 -Contents: test::m1::Pub {id: sui::object::UID {id: sui::object::ID {bytes: fake(5,0)}}, value: 112u64} +Contents: test::m1::Pub {id: iota::object::UID {id: iota::object::ID {bytes: fake(5,0)}}, value: 112u64} task 7 'programmable'. lines 72-78: mutated: object(0,0) diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/make_vec_objects.move b/crates/iota-adapter-transactional-tests/tests/programmable/make_vec_objects.move similarity index 97% rename from crates/sui-adapter-transactional-tests/tests/programmable/make_vec_objects.move rename to crates/iota-adapter-transactional-tests/tests/programmable/make_vec_objects.move index a8a89087478..a764be9091a 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/make_vec_objects.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/make_vec_objects.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests various vector instantions with objects diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/make_vec_special_validation_invalid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/make_vec_special_validation_invalid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/make_vec_special_validation_invalid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/make_vec_special_validation_invalid.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/make_vec_special_validation_invalid.move b/crates/iota-adapter-transactional-tests/tests/programmable/make_vec_special_validation_invalid.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/programmable/make_vec_special_validation_invalid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/make_vec_special_validation_invalid.move index 9d4083e218b..aaefdf96496 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/make_vec_special_validation_invalid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/make_vec_special_validation_invalid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests that MakeMoveVec performs necessary validation for special types like Option or String diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/merge_coin_mismatched_coin.exp b/crates/iota-adapter-transactional-tests/tests/programmable/merge_coin_mismatched_coin.exp similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/programmable/merge_coin_mismatched_coin.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/merge_coin_mismatched_coin.exp index 6af7013b8bd..d7bceb0c4ad 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/merge_coin_mismatched_coin.exp +++ b/crates/iota-adapter-transactional-tests/tests/programmable/merge_coin_mismatched_coin.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 4012800, storage_rebate: task 3 'view-object'. lines 26-26: Owner: Account Address ( A ) Version: 3 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, balance: sui::balance::Balance {value: 100u64}} +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, balance: iota::balance::Balance {value: 100u64}} task 4 'programmable'. lines 28-30: Error: Transaction Effects Status: Invalid command argument at 1. The type of the value does not match the expected type diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/merge_coin_mismatched_coin.move b/crates/iota-adapter-transactional-tests/tests/programmable/merge_coin_mismatched_coin.move similarity index 77% rename from crates/sui-adapter-transactional-tests/tests/programmable/merge_coin_mismatched_coin.move rename to crates/iota-adapter-transactional-tests/tests/programmable/merge_coin_mismatched_coin.move index 3238c1c8dc7..349ee2a7a96 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/merge_coin_mismatched_coin.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/merge_coin_mismatched_coin.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests various mismatched coin types for merge coins @@ -7,7 +8,7 @@ //# publish --sender A module test::fake { - use sui::coin; + use iota::coin; public struct FAKE has drop {} @@ -20,13 +21,13 @@ module test::fake { } //# programmable --sender A --inputs object(1,2) 100 @A -//> 0: sui::coin::mint(Input(0), Input(1)); +//> 0: iota::coin::mint(Input(0), Input(1)); //> TransferObjects([Result(0)], Input(2)) //# view-object 2,0 //# programmable --sender A --inputs object(1,2) 100 -//> 0: sui::coin::mint(Input(0), Input(1)); +//> 0: iota::coin::mint(Input(0), Input(1)); //> MergeCoins(Gas, [Result(0)]) //# programmable --sender A --inputs object(2,0) @@ -34,11 +35,11 @@ module test::fake { //# programmable --sender A --inputs object(1,2) 100 object(2,0) -//> 0: sui::coin::mint(Input(0), Input(1)); +//> 0: iota::coin::mint(Input(0), Input(1)); //> 1: SplitCoins(Gas, [Input(1)]); //> MergeCoins(Result(0), [Input(2), Result(1)]) //# programmable --sender A --inputs object(1,2) 100 -//> 0: sui::coin::mint(Input(0), Input(1)); +//> 0: iota::coin::mint(Input(0), Input(1)); //> 1: SplitCoins(Result(0), [Input(1)]); //> MergeCoins(Gas, [Result(1)]) diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/nested_result_zero_zero.exp b/crates/iota-adapter-transactional-tests/tests/programmable/nested_result_zero_zero.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/nested_result_zero_zero.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/nested_result_zero_zero.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/nested_result_zero_zero.move b/crates/iota-adapter-transactional-tests/tests/programmable/nested_result_zero_zero.move similarity index 89% rename from crates/sui-adapter-transactional-tests/tests/programmable/nested_result_zero_zero.move rename to crates/iota-adapter-transactional-tests/tests/programmable/nested_result_zero_zero.move index 6e4e4076d7b..9ef76ac8801 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/nested_result_zero_zero.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/nested_result_zero_zero.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests NestedResult(0,0) is always equivalent to Result(0) diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/non_primitive_non_object_arguments.exp b/crates/iota-adapter-transactional-tests/tests/programmable/non_primitive_non_object_arguments.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/non_primitive_non_object_arguments.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/non_primitive_non_object_arguments.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/non_primitive_non_object_arguments.move b/crates/iota-adapter-transactional-tests/tests/programmable/non_primitive_non_object_arguments.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/programmable/non_primitive_non_object_arguments.move rename to crates/iota-adapter-transactional-tests/tests/programmable/non_primitive_non_object_arguments.move index fa46a2e3a2c..172bfeb0e89 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/non_primitive_non_object_arguments.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/non_primitive_non_object_arguments.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests various calls of non-primitive argument usage diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_input.exp b/crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_input.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_input.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_input.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_input.move b/crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_input.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_input.move rename to crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_input.move index 5c0b789d864..052f808cf4a 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_input.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_input.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests out of bounds arguments for Input diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_nested.exp b/crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_nested.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_nested.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_nested.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_nested.move b/crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_nested.move similarity index 97% rename from crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_nested.move rename to crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_nested.move index 5218110aaf3..e9778aedf8d 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_nested.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_nested.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests out of bounds arguments for NestedResult diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_result.exp b/crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_result.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_result.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_result.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_result.move b/crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_result.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_result.move rename to crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_result.move index 48ceef03a67..24083f97311 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/out_of_bounds_result.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/out_of_bounds_result.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests out of bounds arguments for Result diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_invalid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_invalid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_invalid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_invalid.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_invalid.move b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_invalid.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_invalid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_invalid.move index 835d5992e2b..f3e98a7611d 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_invalid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_invalid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests that object values cannot be used private entry functions if they have been diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_valid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_valid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_valid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_valid.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_valid.move b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_valid.move similarity index 88% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_valid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_valid.move index 35f608898cb..9c64f625888 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_valid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_by_ref_input_valid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests that object values can be used private entry functions if they have been used @@ -8,8 +9,8 @@ //# publish module test::m1 { - use sui::coin::Coin; - use sui::sui::SUI; + use iota::coin::Coin; + use iota::iota::IOTA; public struct R has key, store { id: UID } public fun r(ctx: &mut TxContext): R { R { id: object::new(ctx) } } @@ -19,7 +20,7 @@ module test::m1 { public entry fun clean(_: &mut R, _extra_arg: u64) {} entry fun priv(_: &mut R) { } - entry fun coin(_: &mut Coin) {} + entry fun coin(_: &mut Coin) {} } //# programmable --sender A --inputs @A diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_copied_input_valid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_copied_input_valid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_copied_input_valid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_copied_input_valid.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_copied_input_valid.move b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_copied_input_valid.move similarity index 89% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_copied_input_valid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_copied_input_valid.move index a38cc5a59c2..c3238039cb7 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_copied_input_valid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_copied_input_valid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests that non-input primitive values can be used private entry functions, even if they have diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_invalid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_invalid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_invalid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_invalid.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_invalid.move b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_invalid.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_invalid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_invalid.move index 010acf6416d..ab2435fb219 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_invalid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_invalid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests MakeMoveVec makes a "dirty" value if at least one value has been used in a non-entry diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_valid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_valid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_valid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_valid.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_valid.move b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_valid.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_valid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_valid.move index e19625cb492..6bfe5ec3d19 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_valid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_make_move_vec_valid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests MakeMoveVec does not "dirty" value if no value has been used in a non-entry diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_non_pure_input_invalid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_non_pure_input_invalid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_non_pure_input_invalid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_non_pure_input_invalid.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_non_pure_input_invalid.move b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_non_pure_input_invalid.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_non_pure_input_invalid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_non_pure_input_invalid.move index 6940b7153c3..903a130a6ce 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_non_pure_input_invalid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_non_pure_input_invalid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests that non-input primitive values cannot be used private entry functions diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_per_argument.exp b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_per_argument.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_per_argument.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_per_argument.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_per_argument.move b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_per_argument.move similarity index 94% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_per_argument.move rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_per_argument.move index 843baa0ebc7..2dffb8d90d9 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_per_argument.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_per_argument.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests dirty check happens in order of arguments, nto all at once diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_type_check.exp b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_type_check.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_type_check.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_type_check.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_type_check.move b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_type_check.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_type_check.move rename to crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_type_check.move index a77d58e2a21..bb87d1e5945 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_type_check.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/private_entry_value_restriction_type_check.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests dirty check happens before type checking diff --git a/crates/iota-adapter-transactional-tests/tests/programmable/private_transfer_invalid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/private_transfer_invalid.exp new file mode 100644 index 00000000000..d485b81e25a --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable/private_transfer_invalid.exp @@ -0,0 +1,45 @@ +processed 11 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-17: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 5228800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 19-21: +Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call iota::transfer::transfer. Use the public variant instead, iota::transfer::public_transfer"), command: Some(1) } } + +task 3 'programmable'. lines 23-25: +Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call iota::transfer::share_object. Use the public variant instead, iota::transfer::public_share_object"), command: Some(1) } } + +task 4 'programmable'. lines 27-32: +Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call iota::transfer::freeze_object. Use the public variant instead, iota::transfer::public_freeze_object"), command: Some(1) } } + +task 5 'programmable'. lines 34-36: +Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call iota::transfer::transfer. Use the public variant instead, iota::transfer::public_transfer"), command: Some(1) } } + +task 6 'programmable'. lines 38-40: +Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call iota::transfer::share_object. Use the public variant instead, iota::transfer::public_share_object"), command: Some(1) } } + +task 7 'programmable'. lines 42-47: +Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call iota::transfer::freeze_object. Use the public variant instead, iota::transfer::public_freeze_object"), command: Some(1) } } + +task 8 'programmable'. lines 49-51: +Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: CONSTRAINT_NOT_SATISFIED, sub_status: None, message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [] }), command: Some(1) } } + +task 9 'programmable'. lines 53-55: +Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: CONSTRAINT_NOT_SATISFIED, sub_status: None, message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [] }), command: Some(1) } } + +task 10 'programmable'. lines 57-59: +Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: CONSTRAINT_NOT_SATISFIED, sub_status: None, message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [] }), command: Some(1) } } diff --git a/crates/iota-adapter-transactional-tests/tests/programmable/private_transfer_invalid.move b/crates/iota-adapter-transactional-tests/tests/programmable/private_transfer_invalid.move new file mode 100644 index 00000000000..306359dc702 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable/private_transfer_invalid.move @@ -0,0 +1,60 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests calling public transfer functions + +//# init --addresses test=0x0 --accounts A + +//# publish +module test::m1 { + public struct Pub has key, store { id: UID } + public fun pub(ctx: &mut TxContext): Pub { Pub { id: object::new(ctx) } } + + public struct Priv has key { id: UID } + public fun priv(ctx: &mut TxContext): Priv { Priv { id: object::new(ctx) } } +} + +// Has store, but cannot be used with internal variants + +//# programmable --sender A --inputs @A +//> 0: test::m1::pub(); +//> iota::transfer::transfer(Result(0), Input(0)); + +//# programmable +//> 0: test::m1::pub(); +//> iota::transfer::share_object(Result(0)); + +//# programmable +//> 0: test::m1::pub(); +//> iota::transfer::freeze_object(Result(0)); + + +// Does not have store, cannot be used with internal variants + +//# programmable --sender A --inputs @A +//> 0: test::m1::priv(); +//> iota::transfer::transfer(Result(0), Input(0)); + +//# programmable +//> 0: test::m1::priv(); +//> iota::transfer::share_object(Result(0)); + +//# programmable +//> 0: test::m1::priv(); +//> iota::transfer::freeze_object(Result(0)); + + +// Does not have store, cannot be used with public variants + +//# programmable --sender A --inputs @A +//> 0: test::m1::priv(); +//> iota::transfer::public_transfer(Result(0), Input(0)); + +//# programmable +//> 0: test::m1::priv(); +//> iota::transfer::public_share_object(Result(0)); + +//# programmable +//> 0: test::m1::priv(); +//> iota::transfer::public_freeze_object(Result(0)); diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_transfer_valid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/private_transfer_valid.exp similarity index 79% rename from crates/sui-adapter-transactional-tests/tests/programmable/private_transfer_valid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/private_transfer_valid.exp index 5a4407c152a..b6665aeec6e 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/private_transfer_valid.exp +++ b/crates/iota-adapter-transactional-tests/tests/programmable/private_transfer_valid.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2219200, storage_rebate: task 3 'view-object'. lines 18-18: Owner: Account Address ( A ) Version: 2 -Contents: test::m1::Pub {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m1::Pub {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'programmable'. lines 20-22: created: object(4,0) @@ -26,7 +26,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2219200, storage_rebate: task 5 'view-object'. lines 24-24: Owner: Shared Version: 3 -Contents: test::m1::Pub {id: sui::object::UID {id: sui::object::ID {bytes: fake(4,0)}}} +Contents: test::m1::Pub {id: iota::object::UID {id: iota::object::ID {bytes: fake(4,0)}}} task 6 'programmable'. lines 26-28: created: object(6,0) @@ -36,4 +36,4 @@ gas summary: computation_cost: 1000000, storage_cost: 2219200, storage_rebate: task 7 'view-object'. lines 30-30: Owner: Immutable Version: 4 -Contents: test::m1::Pub {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}} +Contents: test::m1::Pub {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}} diff --git a/crates/iota-adapter-transactional-tests/tests/programmable/private_transfer_valid.move b/crates/iota-adapter-transactional-tests/tests/programmable/private_transfer_valid.move new file mode 100644 index 00000000000..9be4e6fb180 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable/private_transfer_valid.move @@ -0,0 +1,31 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests calling public transfer functions + +//# init --addresses test=0x0 --accounts A + +//# publish +module test::m1 { + public struct Pub has key, store { id: UID } + public fun pub(ctx: &mut TxContext): Pub { Pub { id: object::new(ctx) } } +} + +//# programmable --sender A --inputs @A +//> 0: test::m1::pub(); +//> iota::transfer::public_transfer(Result(0), Input(0)); + +//# view-object 2,0 + +//# programmable +//> 0: test::m1::pub(); +//> iota::transfer::public_share_object(Result(0)); + +//# view-object 4,0 + +//# programmable +//> 0: test::m1::pub(); +//> iota::transfer::public_freeze_object(Result(0)); + +//# view-object 6,0 diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/pure_arg_type_change.exp b/crates/iota-adapter-transactional-tests/tests/programmable/pure_arg_type_change.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/pure_arg_type_change.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/pure_arg_type_change.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/pure_arg_type_change.move b/crates/iota-adapter-transactional-tests/tests/programmable/pure_arg_type_change.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/programmable/pure_arg_type_change.move rename to crates/iota-adapter-transactional-tests/tests/programmable/pure_arg_type_change.move index 3f32fe981e3..d19459ccdb0 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/pure_arg_type_change.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/pure_arg_type_change.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests that pure arguments have their types fixed/changed after being used by a mutable reference @@ -36,7 +37,7 @@ module test::m1 { //> 0: test::m1::addr(Input(0)); //> 1: test::m1::id(Input(0)); -//> 2: test::m1::fix(Input(0)); +//> 2: test::m1::fix(Input(0)); // now will fail as Input(0) if always an ID //> 3: test::m1::addr(Input(0)); diff --git a/crates/iota-adapter-transactional-tests/tests/programmable/split_coins.exp b/crates/iota-adapter-transactional-tests/tests/programmable/split_coins.exp new file mode 100644 index 00000000000..b5b4292351c --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable/split_coins.exp @@ -0,0 +1,99 @@ +processed 20 tasks + +init: +A: object(0,0), B: object(0,1) + +task 1 'publish'. lines 9-24: +created: object(1,0) +mutated: object(0,2) +gas summary: computation_cost: 1000000, storage_cost: 5403600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 26-30: +created: object(2,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'run'. lines 31-31: +created: object(3,0) +mutated: object(0,0), object(2,0) +gas summary: computation_cost: 1000000, storage_cost: 2964000, storage_rebate: 1956240, non_refundable_storage_fee: 19760 + +task 4 'view-object'. lines 33-35: +Owner: Account Address ( A ) +Version: 3 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, balance: iota::balance::Balance {value: 1000u64}} + +task 5 'programmable'. lines 36-38: +created: object(5,0) +mutated: object(0,0), object(3,0) +gas summary: computation_cost: 1000000, storage_cost: 2964000, storage_rebate: 1956240, non_refundable_storage_fee: 19760 + +task 6 'view-object'. lines 40-40: +Owner: Account Address ( A ) +Version: 4 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, balance: iota::balance::Balance {value: 900u64}} + +task 7 'view-object'. lines 42-45: +Owner: Account Address ( B ) +Version: 4 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(5,0)}}, balance: iota::balance::Balance {value: 100u64}} + +task 8 'programmable'. lines 46-48: +created: object(8,0), object(8,1) +mutated: object(0,0), object(3,0) +gas summary: computation_cost: 1000000, storage_cost: 3952000, storage_rebate: 1956240, non_refundable_storage_fee: 19760 + +task 9 'view-object'. lines 50-50: +Owner: Account Address ( A ) +Version: 5 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, balance: iota::balance::Balance {value: 700u64}} + +task 10 'view-object'. lines 52-52: +Owner: Account Address ( B ) +Version: 5 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(8,0)}}, balance: iota::balance::Balance {value: 100u64}} + +task 11 'view-object'. lines 54-56: +Owner: Account Address ( B ) +Version: 5 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(8,1)}}, balance: iota::balance::Balance {value: 100u64}} + +task 12 'programmable'. lines 57-60: +created: object(12,0), object(12,1) +mutated: object(0,0), object(3,0) +gas summary: computation_cost: 1000000, storage_cost: 3952000, storage_rebate: 1956240, non_refundable_storage_fee: 19760 + +task 13 'view-object'. lines 62-62: +Owner: Account Address ( A ) +Version: 6 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, balance: iota::balance::Balance {value: 500u64}} + +task 14 'view-object'. lines 64-64: +Owner: Account Address ( B ) +Version: 6 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(12,0)}}, balance: iota::balance::Balance {value: 100u64}} + +task 15 'view-object'. lines 66-69: +Owner: Account Address ( B ) +Version: 6 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(12,1)}}, balance: iota::balance::Balance {value: 100u64}} + +task 16 'programmable'. lines 70-74: +created: object(16,0), object(16,1) +mutated: object(0,0), object(3,0) +gas summary: computation_cost: 1000000, storage_cost: 3952000, storage_rebate: 1956240, non_refundable_storage_fee: 19760 + +task 17 'view-object'. lines 76-76: +Owner: Account Address ( A ) +Version: 7 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, balance: iota::balance::Balance {value: 300u64}} + +task 18 'view-object'. lines 78-78: +Owner: Account Address ( B ) +Version: 7 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(16,0)}}, balance: iota::balance::Balance {value: 100u64}} + +task 19 'view-object'. lines 80-80: +Owner: Account Address ( B ) +Version: 7 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(16,1)}}, balance: iota::balance::Balance {value: 100u64}} diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/split_coins.move b/crates/iota-adapter-transactional-tests/tests/programmable/split_coins.move similarity index 84% rename from crates/sui-adapter-transactional-tests/tests/programmable/split_coins.move rename to crates/iota-adapter-transactional-tests/tests/programmable/split_coins.move index 2cb3f1a452d..48eab84445d 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/split_coins.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/split_coins.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests various valid operations involving SplitCoins @@ -8,13 +9,13 @@ //# publish module test::m1 { - use sui::coin; + use iota::coin; public fun ret_one_amount(): u64 { 100 } - public fun transfer_(mut v: vector>, r: address) { + public fun transfer_(mut v: vector>, r: address) { while (!vector::is_empty(&v)) { let c = vector::pop_back(&mut v); transfer::public_transfer(c, r); @@ -28,7 +29,7 @@ module test::m1 { //> TransferObjects([Result(0)], Input(1)) // let's get ourselves a coin worth 1000 -//# run sui::pay::split_and_transfer --type-args sui::sui::SUI --args object(2,0) 1000 @A --sender A +//# run iota::pay::split_and_transfer --type-args iota::iota::IOTA --args object(2,0) 1000 @A --sender A //# view-object 3,0 @@ -70,7 +71,7 @@ module test::m1 { //# programmable --sender A --inputs object(3,0) 100 @B //> 0: test::m1::ret_one_amount(); //> 1: SplitCoins(Input(0), [Result(0), Input(1)]); -//> 2: MakeMoveVec>([NestedResult(1,0), NestedResult(1,1)]); +//> 2: MakeMoveVec>([NestedResult(1,0), NestedResult(1,1)]); //> test::m1::transfer_(Result(2), Input(2)); //# view-object 3,0 diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/split_coins_invalid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/split_coins_invalid.exp similarity index 94% rename from crates/sui-adapter-transactional-tests/tests/programmable/split_coins_invalid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/split_coins_invalid.exp index 6bfba974982..acc556224b7 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/split_coins_invalid.exp +++ b/crates/iota-adapter-transactional-tests/tests/programmable/split_coins_invalid.exp @@ -21,7 +21,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2964000, storage_rebate: task 4 'view-object'. lines 33-35: Owner: Account Address ( A ) Version: 3 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, balance: sui::balance::Balance {value: 1000u64}} +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, balance: iota::balance::Balance {value: 1000u64}} task 5 'programmable'. lines 36-39: Error: Transaction Effects Status: Insufficient coin balance for operation. diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/split_coins_invalid.move b/crates/iota-adapter-transactional-tests/tests/programmable/split_coins_invalid.move similarity index 88% rename from crates/sui-adapter-transactional-tests/tests/programmable/split_coins_invalid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/split_coins_invalid.move index 22723324ab1..4fe23a9d625 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/split_coins_invalid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/split_coins_invalid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests various invalid operations involving SplitCoins @@ -8,13 +9,13 @@ //# publish module test::m1 { - use sui::coin; + use iota::coin; public fun ret_one_amount(): address { @42 } - public fun transfer_(mut v: vector>, r: address) { + public fun transfer_(mut v: vector>, r: address) { while (!vector::is_empty(&v)) { let c = vector::pop_back(&mut v); transfer::public_transfer(c, r); @@ -28,7 +29,7 @@ module test::m1 { //> TransferObjects([Result(0)], Input(1)) // let's get ourselves a coin worth 1000 -//# run sui::pay::split_and_transfer --type-args sui::sui::SUI --args object(2,0) 1000 @A --sender A +//# run iota::pay::split_and_transfer --type-args iota::iota::IOTA --args object(2,0) 1000 @A --sender A //# view-object 3,0 diff --git a/crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects.exp b/crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects.exp new file mode 100644 index 00000000000..fd637c65207 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects.exp @@ -0,0 +1,59 @@ +processed 12 tasks + +init: +A: object(0,0), B: object(0,1) + +task 1 'publish'. lines 8-32: +created: object(1,0) +mutated: object(0,2) +gas summary: computation_cost: 1000000, storage_cost: 6004000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 33-35: +created: object(2,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2280000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 37-39: +Owner: Account Address ( A ) +Version: 2 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(0,0)}}, balance: iota::balance::Balance {value: 299999996720000u64}} + +task 4 'programmable'. lines 40-43: +created: object(4,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2280000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 5 'view-object'. lines 45-47: +Owner: Account Address ( _ ) +Version: 3 +Contents: test::m1::Pub {id: iota::object::UID {id: iota::object::ID {bytes: fake(4,0)}}, value: 112u64} + +task 6 'programmable'. lines 48-53: +created: object(6,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2280000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 7 'view-object'. lines 55-57: +Owner: Account Address ( B ) +Version: 4 +Contents: test::m1::Pub {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}, value: 112u64} + +task 8 'programmable'. lines 58-65: +created: object(8,0), object(8,1), object(8,2) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5388400, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 9 'view-object'. lines 67-67: +Owner: Account Address ( B ) +Version: 5 +Contents: test::m1::Cup {id: iota::object::UID {id: iota::object::ID {bytes: fake(8,0)}}} + +task 10 'view-object'. lines 69-69: +Owner: Account Address ( B ) +Version: 5 +Contents: test::m1::Cup {id: iota::object::UID {id: iota::object::ID {bytes: fake(8,1)}}} + +task 11 'view-object'. lines 71-71: +Owner: Account Address ( B ) +Version: 5 +Contents: test::m1::Pub {id: iota::object::UID {id: iota::object::ID {bytes: fake(8,2)}}, value: 112u64} diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects.move b/crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects.move similarity index 82% rename from crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects.move rename to crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects.move index c58e519328b..2feb5403267 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests various valid operations involving TransferObjects @@ -38,7 +39,7 @@ module test::m1 { // cast using a Move function //# programmable --sender A --inputs 0u256 -//> 0: sui::address::from_u256(Input(0)); +//> 0: iota::address::from_u256(Input(0)); //> 1: test::m1::new(); //> TransferObjects([Result(1)], Result(0)); @@ -46,8 +47,8 @@ module test::m1 { // compilicated Move logic //# programmable --sender A --inputs @B true -//> 0: sui::address::to_u256(Input(0)); -//> 1: sui::address::from_u256(Result(0)); +//> 0: iota::address::to_u256(Input(0)); +//> 1: iota::address::from_u256(Result(0)); //> 2: test::m1::new(); //> 3: test::m1::addr(Result(1), Input(1)); //> TransferObjects([Result(2)], Result(3)); @@ -56,11 +57,11 @@ module test::m1 { // many object types //# programmable --sender A --inputs @B true -//> 0: sui::address::to_u256(Input(0)); -//> 1: sui::address::from_u256(Result(0)); +//> 0: iota::address::to_u256(Input(0)); +//> 1: iota::address::from_u256(Result(0)); //> 2: test::m1::new(); //> 3: test::m1::addr(Result(1), Input(1)); -//> 4: test::m1::cup(); +//> 4: test::m1::cup(); //> 5: test::m1::cup(); //> TransferObjects([Result(4), Result(2), Result(5)], Result(3)); diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_address.exp b/crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_address.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_address.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_address.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_address.move b/crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_address.move similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_address.move rename to crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_address.move index d942be84e3a..4e70e2636c6 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_address.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_address.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests various invalid operations involving TransferObjects to invalid address @@ -21,7 +22,7 @@ module test::m1 { } public fun vec(): vector { - sui::address::to_bytes(@0) + iota::address::to_bytes(@0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_object.exp b/crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_object.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_object.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_object.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_object.move b/crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_object.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_object.move rename to crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_object.move index e446ba686c3..55d0f341237 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_object.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/transfer_objects_invalid_object.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests various invalid operations involving TransferObjects of invalid objects diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/unused_values_invalid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/unused_values_invalid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/unused_values_invalid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/unused_values_invalid.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/unused_values_invalid.move b/crates/iota-adapter-transactional-tests/tests/programmable/unused_values_invalid.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/programmable/unused_values_invalid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/unused_values_invalid.move index e97d9fcf693..2d710a664df 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/unused_values_invalid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/unused_values_invalid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests invalid unused values diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/unused_values_valid.exp b/crates/iota-adapter-transactional-tests/tests/programmable/unused_values_valid.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable/unused_values_valid.exp rename to crates/iota-adapter-transactional-tests/tests/programmable/unused_values_valid.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/unused_values_valid.move b/crates/iota-adapter-transactional-tests/tests/programmable/unused_values_valid.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/programmable/unused_values_valid.move rename to crates/iota-adapter-transactional-tests/tests/programmable/unused_values_valid.move index 4f4002e427f..94981eb3796 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable/unused_values_valid.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable/unused_values_valid.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests unused values diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/bad_syntax.exp b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/bad_syntax.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/bad_syntax.exp rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/bad_syntax.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/bad_syntax.move b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/bad_syntax.move similarity index 78% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/bad_syntax.move rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/bad_syntax.move index a619987dc19..0bf3fc67c4c 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/bad_syntax.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/bad_syntax.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# programmable diff --git a/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/coin_limit.exp b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/coin_limit.exp new file mode 100644 index 00000000000..beede5c5e79 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/coin_limit.exp @@ -0,0 +1,53 @@ +processed 11 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 6-25: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 6650000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'programmable'. lines 26-29: +created: object(2,0), object(2,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 3260400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 31-31: +Owner: Account Address ( _ ) +Version: 2 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, balance: iota::balance::Balance {value: 100u64}} + +task 4 'view-object'. lines 33-35: +Owner: Account Address ( A ) +Version: 2 +Contents: test::m1::CoolMarker {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 5 'programmable'. lines 36-41: +Error: Transaction Effects Status: Unused result without the drop ability. Command result 1, return value 0 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: UnusedValueWithoutDrop { result_idx: 1, secondary_idx: 0 }, source: None, command: None } } + +task 6 'programmable'. lines 42-47: +created: object(6,0), object(6,1), object(6,2), object(6,3) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5532800, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 7 'view-object'. lines 49-49: +Owner: Account Address ( _ ) +Version: 4 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}, balance: iota::balance::Balance {value: 100u64}} + +task 8 'view-object'. lines 51-51: +Owner: Account Address ( _ ) +Version: 4 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,1)}}, balance: iota::balance::Balance {value: 100u64}} + +task 9 'view-object'. lines 53-53: +Owner: Account Address ( A ) +Version: 4 +Contents: test::m1::CoolMarker {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,2)}}} + +task 10 'view-object'. lines 55-55: +Owner: Account Address ( A ) +Version: 4 +Contents: test::m1::CoolMarker {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,3)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/coin_limit.move b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/coin_limit.move similarity index 83% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/coin_limit.move rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/coin_limit.move index eb0ec682d81..cae7d6f5008 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/coin_limit.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/coin_limit.move @@ -1,20 +1,21 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses test=0x0 --accounts A //# publish module test::m1 { - use sui::coin::{Self, Coin}; - use sui::sui::SUI; + use iota::coin::{Self, Coin}; + use iota::iota::IOTA; public struct CoolMarker has key, store { id: UID } - public entry fun purchase(coin: Coin, ctx: &mut TxContext) { + public entry fun purchase(coin: Coin, ctx: &mut TxContext) { transfer::public_transfer(purchase_(coin, ctx), tx_context::sender(ctx)) } - public fun purchase_(coin: Coin, ctx: &mut TxContext): CoolMarker { + public fun purchase_(coin: Coin, ctx: &mut TxContext): CoolMarker { assert!(coin::value(&coin) >= 100, 0); transfer::public_transfer(coin, @0x70DD); CoolMarker { id: object::new(ctx) } diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec.exp b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec.exp rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec.exp diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec.move b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec.move similarity index 98% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec.move rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec.move index cf854e37ed9..ceaf755f28c 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses test=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec_shared.exp b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec_shared.exp similarity index 88% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec_shared.exp rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec_shared.exp index 561f81d19a8..2acf82e1cd2 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec_shared.exp +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec_shared.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 3 'view-object'. lines 33-33: Owner: Shared Version: 3 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'programmable'. lines 35-37: mutated: object(0,0) diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec_shared.move b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec_shared.move similarity index 94% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec_shared.move rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec_shared.move index 51f9428fcb1..85fe5c6598c 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec_shared.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/make_vec_shared.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests shared object scenarios as part of programmable transactions diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared.exp b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared.exp similarity index 86% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared.exp rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared.exp index e2bec48894f..ec8d9a98785 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared.exp +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2287600, storage_rebate: task 3 'view-object'. lines 30-30: Owner: Shared Version: 3 -Contents: test::m1::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, value: 1000000u64} +Contents: test::m1::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, value: 1000000u64} task 4 'programmable'. lines 32-33: Error: Transaction Effects Status: Invalid command argument at 1. The type of the value does not match the expected type diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared.move b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared.move rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared.move index d64ad2c479d..d78e90eb32c 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // test invalid usages of shared coin diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared_real_coin.exp b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared_real_coin.exp similarity index 79% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared_real_coin.exp rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared_real_coin.exp index b09bef47ff4..5a442066b61 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared_real_coin.exp +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared_real_coin.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: task 3 'view-object'. lines 21-21: Owner: Shared Version: 3 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, balance: sui::balance::Balance {value: 0u64}} +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, balance: iota::balance::Balance {value: 0u64}} task 4 'programmable'. lines 23-24: mutated: object(0,0) diff --git a/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared_real_coin.move b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared_real_coin.move new file mode 100644 index 00000000000..42747f66cf3 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared_real_coin.move @@ -0,0 +1,25 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// test valid usages of shared coin + +//# init --addresses test=0x0 --accounts A --shared-object-deletion true + +//# publish + +module test::m1 { + use iota::iota::IOTA; + use iota::coin; + + public fun mint_shared(ctx: &mut TxContext) { + transfer::public_share_object(coin::zero(ctx)) + } +} + +//# run test::m1::mint_shared + +//# view-object 2,0 + +//# programmable --sender A --inputs object(2,0) +//> MergeCoins(Gas, [Input(0)]) diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/publish.exp b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/publish.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/publish.exp rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/publish.exp diff --git a/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/publish.move b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/publish.move new file mode 100644 index 00000000000..2fee263cdf1 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/publish.move @@ -0,0 +1,50 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// simple test of publish + +//# init --addresses p=0x0 q=0x0 r=0x0 --accounts A + +//# stage-package +module p::m { + public fun foo(x: u64) { + p::n::bar(x) + } +} +module p::n { + public fun bar(x: u64) { + assert!(x == 0, 0); + } +} + + +//# stage-package +module q::m { + public fun x(): u64 { 0 } +} + + +//# programmable --sender A --inputs 10 @A +//> 0: SplitCoins(Gas, [Input(0)]); +//> 1: Publish(q, []); +//> 2: TransferObjects([Result(0)], Input(1)); +//> 3: Publish(p, []); +//> TransferObjects([Result(1), Result(3)], Input(1)) + +//# set-address p object(3,1) + +//# set-address q object(3,0) + +//# programmable --sender A +//> 0: q::m::x(); +//> p::m::foo(Result(0)) + +//# publish --dependencies p q +module r::all { + public fun foo_x() { + p::m::foo(q::m::x()) + } +} + +//# run r::all::foo_x diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/receipt.exp b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/receipt.exp similarity index 83% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/receipt.exp rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/receipt.exp index 1234f4cfe0a..20bd1de2f0b 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/receipt.exp +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/receipt.exp @@ -13,4 +13,4 @@ gas summary: computation_cost: 1000000, storage_cost: 2249600, storage_rebate: task 3 'view-object'. lines 31-31: Owner: Account Address ( _ ) Version: 3 -Contents: test::m1::Witness {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m1::Witness {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/receipt.move b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/receipt.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/receipt.move rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/receipt.move index f9366a50cab..e342740736e 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/receipt.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/receipt.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses test=0x0 A=0x42 diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/split_coin_share.exp b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/split_coin_share.exp similarity index 87% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/split_coin_share.exp rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/split_coin_share.exp index c4971aa9ed7..600a1fe809e 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/split_coin_share.exp +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/split_coin_share.exp @@ -26,7 +26,7 @@ gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: task 5 'view-object'. lines 30-32: Owner: Shared Version: 3 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(4,0)}}, balance: sui::balance::Balance {value: 0u64}} +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(4,0)}}, balance: iota::balance::Balance {value: 0u64}} task 6 'programmable'. lines 33-37: created: object(6,0) diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/split_coin_share.move b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/split_coin_share.move similarity index 76% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/split_coin_share.move rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/split_coin_share.move index fc58798a587..e720056d204 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/split_coin_share.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/split_coin_share.move @@ -1,29 +1,30 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses p=0x0 q=0x0 q_2=0x0 r=0x0 s=0x0 --accounts A //# publish module p::m { - use sui::sui::SUI; - use sui::coin; + use iota::iota::IOTA; + use iota::coin; public fun sharer(x: T) { transfer::public_share_object(x); } public fun mint_shared(ctx: &mut TxContext) { - transfer::public_share_object(coin::zero(ctx)) + transfer::public_share_object(coin::zero(ctx)) } } //# programmable --sender A --inputs 10 //> 0: SplitCoins(Gas, [Input(0)]); -//> 1: sui::transfer::public_share_object>(Result(0)); +//> 1: iota::transfer::public_share_object>(Result(0)); //# programmable --sender A --inputs 10 //> 0: SplitCoins(Gas, [Input(0)]); -//> 1: p::m::sharer>(Result(0)); +//> 1: p::m::sharer>(Result(0)); //# run p::m::mint_shared diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/transfer_shared.exp b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/transfer_shared.exp similarity index 88% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/transfer_shared.exp rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/transfer_shared.exp index b8f8e1eea30..5342c406037 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/transfer_shared.exp +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/transfer_shared.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 3 'view-object'. lines 26-26: Owner: Shared Version: 3 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'programmable'. lines 28-29: Error: Transaction Effects Status: The shared object operation is not allowed. diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/transfer_shared.move b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/transfer_shared.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/transfer_shared.move rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/transfer_shared.move index 766ec757777..7ac8f8736e1 100644 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/transfer_shared.move +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/transfer_shared.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests shared object transfer as part of programmable transactions diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/upgrade.exp b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/upgrade.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/upgrade.exp rename to crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/upgrade.exp diff --git a/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/upgrade.move b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/upgrade.move new file mode 100644 index 00000000000..ef53172e24b --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/programmable_transaction_examples/upgrade.move @@ -0,0 +1,61 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// simple test of upgrade + +//# init --addresses p=0x0 q=0x0 q_2=0x0 r=0x0 s=0x0 --accounts A + +//# publish +module p::m { + public fun foo(x: u64) { + p::n::bar(x) + } +} +module p::n { + public fun bar(x: u64) { + assert!(x == 1, 0); + } +} + +//# publish --upgradeable --sender A +module q::m { + public fun x(): u64 { 0 } +} + +//# publish +module r::m { + public fun y(): u64 { 0 } +} + +//# stage-package --dependencies r +module q_2::m { + public fun x(): u64 { y() + 1 } + public fun y(): u64 { r::m::y() } +} + +//# programmable --sender A --inputs 10 @A object(2,1) 0u8 digest(q_2) +//> 0: iota::package::authorize_upgrade(Input(2), Input(3), Input(4)); +//> 1: SplitCoins(Gas, [Input(0)]); +//> 2: Upgrade(q_2, [iota,std,r], q, Result(0)); +//> TransferObjects([Result(1)], Input(1)); +//> iota::package::commit_upgrade(Input(2), Result(2)) + +//# programmable --sender A +//> 0: q::m::x(); +//> p::m::foo(Result(0)) + +//# set-address q_2 object(5,0) + +//# programmable --sender A +//> 0: q_2::m::x(); +//> p::m::foo(Result(0)) + +//# publish --dependencies p q_2 r +module s::all { + public fun foo_x() { + p::m::foo(q::m::x()) + } +} + +//# run s::all::foo_x diff --git a/crates/sui-adapter-transactional-tests/tests/publish/init.exp b/crates/iota-adapter-transactional-tests/tests/publish/init.exp similarity index 75% rename from crates/sui-adapter-transactional-tests/tests/publish/init.exp rename to crates/iota-adapter-transactional-tests/tests/publish/init.exp index a3f9137c665..c992784cc9e 100644 --- a/crates/sui-adapter-transactional-tests/tests/publish/init.exp +++ b/crates/iota-adapter-transactional-tests/tests/publish/init.exp @@ -8,7 +8,7 @@ gas summary: computation_cost: 1000000, storage_cost: 6642400, storage_rebate: task 2 'view-object'. lines 21-21: Owner: Account Address ( _ ) Version: 2 -Contents: Test::M1::Object {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,1)}}, value: 42u64} +Contents: Test::M1::Object {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,1)}}, value: 42u64} task 3 'view-object'. lines 23-23: 1,0::M1 diff --git a/crates/sui-adapter-transactional-tests/tests/publish/init.move b/crates/iota-adapter-transactional-tests/tests/publish/init.move similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/publish/init.move rename to crates/iota-adapter-transactional-tests/tests/publish/init.move index 7ccc08a2ee3..d6e466e6937 100644 --- a/crates/sui-adapter-transactional-tests/tests/publish/init.move +++ b/crates/iota-adapter-transactional-tests/tests/publish/init.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test=0x0 diff --git a/crates/iota-adapter-transactional-tests/tests/publish/init_param.exp b/crates/iota-adapter-transactional-tests/tests/publish/init_param.exp new file mode 100644 index 00000000000..a41315be23c --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/publish/init_param.exp @@ -0,0 +1,5 @@ +processed 2 tasks + +task 1 'publish'. lines 5-27: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Expected last parameter for _::M1::init to be &mut iota::tx_context::TxContext or &iota::tx_context::TxContext, but found &mut iota::tx_context::TxContext"), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/publish/init_param.mvir b/crates/iota-adapter-transactional-tests/tests/publish/init_param.mvir similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/publish/init_param.mvir rename to crates/iota-adapter-transactional-tests/tests/publish/init_param.mvir index b4ed9a11954..c3f5bf363ed 100644 --- a/crates/sui-adapter-transactional-tests/tests/publish/init_param.mvir +++ b/crates/iota-adapter-transactional-tests/tests/publish/init_param.mvir @@ -1,5 +1,6 @@ //# init --addresses Test=0x0 // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-adapter-transactional-tests/tests/publish/init_public.exp b/crates/iota-adapter-transactional-tests/tests/publish/init_public.exp new file mode 100644 index 00000000000..ce0f0e64a9b --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/publish/init_public.exp @@ -0,0 +1,5 @@ +processed 2 tasks + +task 1 'publish'. lines 5-27: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::M1. 'init' function must be private"), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/publish/init_public.mvir b/crates/iota-adapter-transactional-tests/tests/publish/init_public.mvir similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/publish/init_public.mvir rename to crates/iota-adapter-transactional-tests/tests/publish/init_public.mvir index 41cbc05d29f..63579e799c6 100644 --- a/crates/sui-adapter-transactional-tests/tests/publish/init_public.mvir +++ b/crates/iota-adapter-transactional-tests/tests/publish/init_public.mvir @@ -1,5 +1,6 @@ //# init --addresses Test=0x0 // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-adapter-transactional-tests/tests/publish/init_ret.exp b/crates/iota-adapter-transactional-tests/tests/publish/init_ret.exp new file mode 100644 index 00000000000..e479726bf25 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/publish/init_ret.exp @@ -0,0 +1,5 @@ +processed 2 tasks + +task 1 'publish'. lines 5-27: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::M1, 'init' function cannot have return values"), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/publish/init_ret.mvir b/crates/iota-adapter-transactional-tests/tests/publish/init_ret.mvir similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/publish/init_ret.mvir rename to crates/iota-adapter-transactional-tests/tests/publish/init_ret.mvir index aa55d510245..eff3aa9dc1a 100644 --- a/crates/sui-adapter-transactional-tests/tests/publish/init_ret.mvir +++ b/crates/iota-adapter-transactional-tests/tests/publish/init_ret.mvir @@ -1,5 +1,6 @@ //# init --addresses Test=0x0 // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-adapter-transactional-tests/tests/publish/multi_module_publish.exp b/crates/iota-adapter-transactional-tests/tests/publish/multi_module_publish.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/publish/multi_module_publish.exp rename to crates/iota-adapter-transactional-tests/tests/publish/multi_module_publish.exp diff --git a/crates/sui-adapter-transactional-tests/tests/publish/multi_module_publish.move b/crates/iota-adapter-transactional-tests/tests/publish/multi_module_publish.move similarity index 83% rename from crates/sui-adapter-transactional-tests/tests/publish/multi_module_publish.move rename to crates/iota-adapter-transactional-tests/tests/publish/multi_module_publish.move index 7a2594fc3d3..394ca9f8387 100644 --- a/crates/sui-adapter-transactional-tests/tests/publish/multi_module_publish.move +++ b/crates/iota-adapter-transactional-tests/tests/publish/multi_module_publish.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test=0x0 diff --git a/crates/iota-adapter-transactional-tests/tests/publish/publish_with_upgrade.exp b/crates/iota-adapter-transactional-tests/tests/publish/publish_with_upgrade.exp new file mode 100644 index 00000000000..b5b029c0620 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/publish/publish_with_upgrade.exp @@ -0,0 +1,11 @@ +processed 3 tasks + +task 1 'publish'. lines 6-9: +created: object(1,0), object(1,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5532800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'view-object'. lines 11-11: +Owner: Account Address ( _ ) +Version: 2 +Contents: iota::package::UpgradeCap {id: iota::object::UID {id: iota::object::ID {bytes: fake(1,1)}}, package: iota::object::ID {bytes: Test}, version: 1u64, policy: 0u8} diff --git a/crates/sui-adapter-transactional-tests/tests/publish/publish_with_upgrade.move b/crates/iota-adapter-transactional-tests/tests/publish/publish_with_upgrade.move similarity index 80% rename from crates/sui-adapter-transactional-tests/tests/publish/publish_with_upgrade.move rename to crates/iota-adapter-transactional-tests/tests/publish/publish_with_upgrade.move index f2028cbfc0b..cc32511de23 100644 --- a/crates/sui-adapter-transactional-tests/tests/publish/publish_with_upgrade.move +++ b/crates/iota-adapter-transactional-tests/tests/publish/publish_with_upgrade.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test=0x0 diff --git a/crates/sui-adapter-transactional-tests/tests/random/happy_flows.exp b/crates/iota-adapter-transactional-tests/tests/random/happy_flows.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/random/happy_flows.exp rename to crates/iota-adapter-transactional-tests/tests/random/happy_flows.exp diff --git a/crates/sui-adapter-transactional-tests/tests/random/happy_flows.move b/crates/iota-adapter-transactional-tests/tests/random/happy_flows.move similarity index 94% rename from crates/sui-adapter-transactional-tests/tests/random/happy_flows.move rename to crates/iota-adapter-transactional-tests/tests/random/happy_flows.move index 43bd5fd19a8..2f8bfb72f23 100644 --- a/crates/sui-adapter-transactional-tests/tests/random/happy_flows.move +++ b/crates/iota-adapter-transactional-tests/tests/random/happy_flows.move @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --accounts A B --addresses test=0x0 //# publish --sender A module test::random { - use sui::clock::Clock; - use sui::random::Random; + use iota::clock::Clock; + use iota::random::Random; public struct Obj has key, store { id: object::UID, diff --git a/crates/sui-adapter-transactional-tests/tests/random/move_call_clock_after_random.exp b/crates/iota-adapter-transactional-tests/tests/random/move_call_clock_after_random.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/random/move_call_clock_after_random.exp rename to crates/iota-adapter-transactional-tests/tests/random/move_call_clock_after_random.exp diff --git a/crates/sui-adapter-transactional-tests/tests/random/move_call_clock_after_random.move b/crates/iota-adapter-transactional-tests/tests/random/move_call_clock_after_random.move similarity index 80% rename from crates/sui-adapter-transactional-tests/tests/random/move_call_clock_after_random.move rename to crates/iota-adapter-transactional-tests/tests/random/move_call_clock_after_random.move index 9e4776446bf..d8ef6dc9270 100644 --- a/crates/sui-adapter-transactional-tests/tests/random/move_call_clock_after_random.move +++ b/crates/iota-adapter-transactional-tests/tests/random/move_call_clock_after_random.move @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --accounts A B --addresses test=0x0 //# publish --sender A module test::random { - use sui::clock::Clock; - use sui::random::Random; + use iota::clock::Clock; + use iota::random::Random; public fun use_clock(_clock: &Clock) {} public fun use_random(_random: &Random) {} diff --git a/crates/sui-adapter-transactional-tests/tests/random/move_call_clock_after_random_and_transfer.exp b/crates/iota-adapter-transactional-tests/tests/random/move_call_clock_after_random_and_transfer.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/random/move_call_clock_after_random_and_transfer.exp rename to crates/iota-adapter-transactional-tests/tests/random/move_call_clock_after_random_and_transfer.exp diff --git a/crates/sui-adapter-transactional-tests/tests/random/move_call_clock_after_random_and_transfer.move b/crates/iota-adapter-transactional-tests/tests/random/move_call_clock_after_random_and_transfer.move similarity index 83% rename from crates/sui-adapter-transactional-tests/tests/random/move_call_clock_after_random_and_transfer.move rename to crates/iota-adapter-transactional-tests/tests/random/move_call_clock_after_random_and_transfer.move index 31fe3f1aa3f..15f2bf32746 100644 --- a/crates/sui-adapter-transactional-tests/tests/random/move_call_clock_after_random_and_transfer.move +++ b/crates/iota-adapter-transactional-tests/tests/random/move_call_clock_after_random_and_transfer.move @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --accounts A B --addresses test=0x0 //# publish --sender A module test::random { - use sui::clock::Clock; - use sui::random::Random; + use iota::clock::Clock; + use iota::random::Random; public fun use_clock(_clock: &Clock) {} public fun use_random(_random: &Random) {} diff --git a/crates/sui-adapter-transactional-tests/tests/random/move_call_u64_after_random.exp b/crates/iota-adapter-transactional-tests/tests/random/move_call_u64_after_random.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/random/move_call_u64_after_random.exp rename to crates/iota-adapter-transactional-tests/tests/random/move_call_u64_after_random.exp diff --git a/crates/sui-adapter-transactional-tests/tests/random/move_call_u64_after_random.move b/crates/iota-adapter-transactional-tests/tests/random/move_call_u64_after_random.move similarity index 84% rename from crates/sui-adapter-transactional-tests/tests/random/move_call_u64_after_random.move rename to crates/iota-adapter-transactional-tests/tests/random/move_call_u64_after_random.move index 7f52374a0ba..ed56e9923ef 100644 --- a/crates/sui-adapter-transactional-tests/tests/random/move_call_u64_after_random.move +++ b/crates/iota-adapter-transactional-tests/tests/random/move_call_u64_after_random.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --accounts A B --addresses test=0x0 //# publish --sender A module test::random { - use sui::random::Random; + use iota::random::Random; public fun use_random(_random: &Random) {} public fun use_value(_value: u64) {} diff --git a/crates/sui-adapter-transactional-tests/tests/random/two_move_calls_with_random.exp b/crates/iota-adapter-transactional-tests/tests/random/two_move_calls_with_random.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/random/two_move_calls_with_random.exp rename to crates/iota-adapter-transactional-tests/tests/random/two_move_calls_with_random.exp diff --git a/crates/sui-adapter-transactional-tests/tests/random/two_move_calls_with_random.move b/crates/iota-adapter-transactional-tests/tests/random/two_move_calls_with_random.move similarity index 82% rename from crates/sui-adapter-transactional-tests/tests/random/two_move_calls_with_random.move rename to crates/iota-adapter-transactional-tests/tests/random/two_move_calls_with_random.move index 7d0b5837517..35388ae750f 100644 --- a/crates/sui-adapter-transactional-tests/tests/random/two_move_calls_with_random.move +++ b/crates/iota-adapter-transactional-tests/tests/random/two_move_calls_with_random.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --accounts A B --addresses test=0x0 //# publish --sender A module test::random { - use sui::random::Random; + use iota::random::Random; public fun use_random(_random: &Random) {} } diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/basic_receive.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/basic_receive.exp new file mode 100644 index 00000000000..15307cabdba --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/basic_receive.exp @@ -0,0 +1,39 @@ +processed 9 tasks + +task 1 'publish'. lines 6-30: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 6923600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 32-32: +created: object(2,0), object(2,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'view-object'. lines 34-34: +Owner: Account Address ( _ ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 4 'view-object'. lines 36-38: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 5 'run'. lines 39-39: +mutated: object(0,0), object(2,0), object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 + +task 6 'view-object'. lines 41-41: +Owner: Account Address ( _ ) +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 7 'view-object'. lines 43-45: +Owner: Account Address ( _ ) +Version: 4 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 8 'run'. lines 46-46: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3), source: Some(VMError { major_status: ABORTED, sub_status: Some(3), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/basic_receive.move b/crates/iota-adapter-transactional-tests/tests/receive_object/basic_receive.move new file mode 100644 index 00000000000..61d9339a6f3 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/basic_receive.move @@ -0,0 +1,47 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --addresses tto=0x0 + +//# publish +module tto::M1 { + use iota::transfer::Receiving; + + public struct A has key, store { + id: UID, + } + + public struct B has key, store { + id: UID, + } + + public fun start(ctx: &mut TxContext) { + let a = A { id: object::new(ctx) }; + let a_address = object::id_address(&a); + let b = B { id: object::new(ctx) }; + transfer::public_transfer(a, tx_context::sender(ctx)); + transfer::public_transfer(b, a_address); + } + + public entry fun receiver(parent: &mut A, x: Receiving) { + let b = transfer::receive(&mut parent.id, x); + transfer::public_transfer(b, @tto); + } +} + +//# run tto::M1::start + +//# view-object 2,0 + +//# view-object 2,1 + +// Can receive the object +//# run tto::M1::receiver --args object(2,0) receiving(2,1) + +//# view-object 2,0 + +//# view-object 2,1 + +// Cannot receive the object again at the old version +//# run tto::M1::receiver --args object(2,0) receiving(2,1)@3 diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/drop_receiving.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/drop_receiving.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/receive_object/drop_receiving.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/drop_receiving.exp diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/drop_receiving.move b/crates/iota-adapter-transactional-tests/tests/receive_object/drop_receiving.move new file mode 100644 index 00000000000..a1c33f9c739 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/drop_receiving.move @@ -0,0 +1,49 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --addresses tto=0x0 + +//# publish +module tto::M1 { + use iota::transfer::Receiving; + + public struct A has key, store { + id: UID, + } + + public struct B has key, store { + id: UID, + } + + public fun start(ctx: &mut TxContext) { + let a = A { id: object::new(ctx) }; + let a_address = object::id_address(&a); + let b = B { id: object::new(ctx) }; + transfer::public_transfer(a, tx_context::sender(ctx)); + transfer::public_transfer(b, a_address); + } + + public entry fun send_back(parent: &mut A, x: Receiving) { + let b = transfer::receive(&mut parent.id, x); + let parent_address = object::id_address(parent); + transfer::public_transfer(b, parent_address); + } + + public entry fun nop(_parent: &mut A) { } + public entry fun nop_with_receiver(_parent: &mut A, _x: Receiving) { } +} + +//# run tto::M1::start + +//# programmable --inputs object(2,0) receiving(2,1) +//> tto::M1::send_back(Input(0), Input(1)) + +// Include the receiving argument, but don't use it at the PTB level +//# programmable --inputs object(2,0) receiving(2,1) +//> tto::M1::nop(Input(0)) + +// Include the receiving argument, but don't use it at the Move level. The +// receiving object should not be mutated by this. +//# programmable --inputs object(2,0) receiving(2,1) +//> tto::M1::nop_with_receiver(Input(0), Input(1)) diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/duplicate_receive_argument.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/duplicate_receive_argument.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/receive_object/duplicate_receive_argument.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/duplicate_receive_argument.exp diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/duplicate_receive_argument.move b/crates/iota-adapter-transactional-tests/tests/receive_object/duplicate_receive_argument.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/receive_object/duplicate_receive_argument.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/duplicate_receive_argument.move index 61e53597803..7a06aaf641c 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/duplicate_receive_argument.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/duplicate_receive_argument.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/move_vec_receiving_types.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/move_vec_receiving_types.exp new file mode 100644 index 00000000000..28f0a0146e9 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/move_vec_receiving_types.exp @@ -0,0 +1,60 @@ +processed 14 tasks + +task 1 'publish'. lines 6-63: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 10579200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 65-65: +created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 7068000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'view-object'. lines 67-67: +Owner: Account Address ( _ ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 4 'view-object'. lines 69-69: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 5 'view-object'. lines 71-71: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}} + +task 6 'view-object'. lines 73-73: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::C {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,3)}}} + +task 7 'view-object'. lines 75-77: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::C {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,4)}}} + +task 8 'programmable'. lines 78-81: +mutated: object(0,0), object(2,0) +gas summary: computation_cost: 1000000, storage_cost: 2204000, storage_rebate: 2181960, non_refundable_storage_fee: 22040 + +task 9 'programmable'. lines 82-86: +mutated: object(0,0), object(2,0) +gas summary: computation_cost: 1000000, storage_cost: 2204000, storage_rebate: 2181960, non_refundable_storage_fee: 22040 + +task 10 'programmable'. lines 87-92: +Error: Transaction Effects Status: Invalid command argument at 0. The type of the value does not match the expected type +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: CommandArgumentError { arg_idx: 0, kind: TypeMismatch }, source: None, command: Some(1) } } + +task 11 'programmable'. lines 93-97: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::receive_impl (function index 12) at offset 0, Abort Code: 2 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(1) } } + +task 12 'programmable'. lines 98-100: +Error: Transaction Effects Status: Invalid command argument at 4. The type of the value does not match the expected type +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: CommandArgumentError { arg_idx: 4, kind: TypeMismatch }, source: None, command: Some(1) } } + +task 13 'programmable'. lines 102-105: +Error: Transaction Effects Status: Invalid command argument at 4. The type of the value does not match the expected type +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: CommandArgumentError { arg_idx: 4, kind: TypeMismatch }, source: None, command: Some(2) } } diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/move_vec_receiving_types.move b/crates/iota-adapter-transactional-tests/tests/receive_object/move_vec_receiving_types.move similarity index 80% rename from crates/sui-adapter-transactional-tests/tests/receive_object/move_vec_receiving_types.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/move_vec_receiving_types.move index ddd70732f28..1d515d352d2 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/move_vec_receiving_types.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/move_vec_receiving_types.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, @@ -76,30 +77,30 @@ module tto::M1 { // Receiving arguments are untyped at the PTB level //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) -//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); +//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); // As long as you don't load the object the type will not be checked. //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) -//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); +//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); //> 1: tto::M1::receive_none(Result(0)); // Try to pass the wrong-type move vec to the function //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) -//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); +//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); //> 1: tto::M1::receive_none_a(Result(0)); // If you try to receive an object at the wrong type, it will fail // E_RECEIVING_TYPE_MISMATCH //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) -//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); +//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); //> 1: tto::M1::receive_all(Input(0), Result(0)); // Try to spoof a receiving object //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) //> 0: tto::M1::make_recv_spoof_b(); -//> 1: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4), Result(0)]); +//> 1: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4), Result(0)]); //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) //> 0: tto::M1::make_recv_spoof_b(); //> 1: tto::M1::spoof_bytes(Result(0)); -//> 2: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4), Result(1)]); +//> 2: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4), Result(1)]); diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/pass_receiver_immut_then_reuse.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/pass_receiver_immut_then_reuse.exp similarity index 81% rename from crates/sui-adapter-transactional-tests/tests/receive_object/pass_receiver_immut_then_reuse.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/pass_receiver_immut_then_reuse.exp index 934676dd6f9..dc639f340c4 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/pass_receiver_immut_then_reuse.exp +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/pass_receiver_immut_then_reuse.exp @@ -13,12 +13,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: task 3 'view-object'. lines 36-36: Owner: Account Address ( _ ) Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 38-40: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'programmable'. lines 41-43: mutated: object(0,0), object(2,0), object(2,1) diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/pass_receiver_immut_then_reuse.move b/crates/iota-adapter-transactional-tests/tests/receive_object/pass_receiver_immut_then_reuse.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/receive_object/pass_receiver_immut_then_reuse.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/pass_receiver_immut_then_reuse.move index a25b76d65e3..935c9af3d73 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/pass_receiver_immut_then_reuse.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/pass_receiver_immut_then_reuse.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/pass_receiver_mut_then_reuse.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/pass_receiver_mut_then_reuse.exp similarity index 81% rename from crates/sui-adapter-transactional-tests/tests/receive_object/pass_receiver_mut_then_reuse.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/pass_receiver_mut_then_reuse.exp index 934676dd6f9..dc639f340c4 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/pass_receiver_mut_then_reuse.exp +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/pass_receiver_mut_then_reuse.exp @@ -13,12 +13,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: task 3 'view-object'. lines 36-36: Owner: Account Address ( _ ) Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 38-40: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'programmable'. lines 41-43: mutated: object(0,0), object(2,0), object(2,1) diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/pass_receiver_mut_then_reuse.move b/crates/iota-adapter-transactional-tests/tests/receive_object/pass_receiver_mut_then_reuse.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/receive_object/pass_receiver_mut_then_reuse.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/pass_receiver_mut_then_reuse.move index 57142fee4c7..a372bfd2fad 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/pass_receiver_mut_then_reuse.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/pass_receiver_mut_then_reuse.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/pt_receive_type_fixing.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/pt_receive_type_fixing.exp similarity index 94% rename from crates/sui-adapter-transactional-tests/tests/receive_object/pt_receive_type_fixing.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/pt_receive_type_fixing.exp index d1d10a63b85..e26495513cc 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/pt_receive_type_fixing.exp +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/pt_receive_type_fixing.exp @@ -13,12 +13,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: task 3 'view-object'. lines 54-54: Owner: Account Address ( _ ) Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 56-59: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'programmable'. lines 60-62: mutated: object(0,0), object(2,0), object(2,1) diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/pt_receive_type_fixing.move b/crates/iota-adapter-transactional-tests/tests/receive_object/pt_receive_type_fixing.move similarity index 88% rename from crates/sui-adapter-transactional-tests/tests/receive_object/pt_receive_type_fixing.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/pt_receive_type_fixing.move index 4db13609345..0385224a4c5 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/pt_receive_type_fixing.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/pt_receive_type_fixing.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, @@ -75,21 +76,21 @@ module tto::M1 { // make vec, then unpack it and make sure the type is fixed //# programmable --inputs object(2,0) receiving(2,1) -//> 0: MakeMoveVec>([Input(1)]); +//> 0: MakeMoveVec>([Input(1)]); //> 1: tto::M1::unpacker_b(Result(0)); //# programmable --inputs object(2,0) receiving(2,1) -//> 0: MakeMoveVec>([Input(1)]); +//> 0: MakeMoveVec>([Input(1)]); //> 1: tto::M1::unpacker_a(Result(0)); //> 2: tto::M1::receiver(Input(0), Result(1)); // This is fine since we are going A -> A in the unpack. But we should fail the call. //# programmable --inputs object(2,0) receiving(2,1) -//> 0: MakeMoveVec>([Input(1)]); +//> 0: MakeMoveVec>([Input(1)]); //> 1: tto::M1::unpacker_generic(Result(0)); //> 2: tto::M1::receiver(Input(0), Result(1)); // This should fail since we're going A -> B in the unpack. //# programmable --inputs object(2,0) receiving(2,1) -//> 0: MakeMoveVec>([Input(1)]); +//> 0: MakeMoveVec>([Input(1)]); //> 1: tto::M1::unpacker_generic(Result(0)); diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/receive_add_dof_and_mutate.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_add_dof_and_mutate.exp new file mode 100644 index 00000000000..52f805e177a --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_add_dof_and_mutate.exp @@ -0,0 +1,54 @@ +processed 11 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 6-36: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 7835600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 38-38: +created: object(2,0), object(2,1) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 3541600, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'view-object'. lines 40-40: +Owner: Account Address ( _ ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, value: 0u64} + +task 4 'view-object'. lines 42-42: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, value: 0u64} + +task 5 'run'. lines 44-44: +created: object(5,0), object(5,1), object(5,2) +mutated: object(0,1), object(2,0), object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 9728000, storage_rebate: 3506184, non_refundable_storage_fee: 35416 + +task 6 'view-object'. lines 46-46: +Owner: Account Address ( _ ) +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, value: 0u64} + +task 7 'view-object'. lines 48-48: +Owner: Object ID: ( fake(5,0) ) +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, value: 100u64} + +task 8 'view-object'. lines 50-50: +Owner: Object ID: ( fake(2,0) ) +Version: 4 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(5,0)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(2,1)}} + +task 9 'view-object'. lines 52-52: +Owner: Object ID: ( fake(2,1) ) +Version: 4 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(5,1)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(5,2)}} + +task 10 'view-object'. lines 54-54: +Owner: Object ID: ( fake(5,1) ) +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(5,2)}}, value: 100u64} diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_add_dof_and_mutate.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_add_dof_and_mutate.move similarity index 90% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_add_dof_and_mutate.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_add_dof_and_mutate.move index c9f4c352638..ae12728cc69 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_add_dof_and_mutate.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_add_dof_and_mutate.move @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 --accounts A //# publish module tto::M1 { - use sui::transfer::Receiving; - use sui::dynamic_object_field as dof; + use iota::transfer::Receiving; + use iota::dynamic_object_field as dof; const KEY: u64 = 0; diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_abort.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_abort.exp similarity index 80% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_abort.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_abort.exp index de7f4f0c7c0..606a5b26a0a 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_abort.exp +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_abort.exp @@ -13,12 +13,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: task 3 'view-object'. lines 34-34: Owner: Account Address ( _ ) Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 36-38: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'run'. lines 39-39: Error: Transaction Effects Status: Move Runtime Abort. Location: tto::M1::receiver (function index 1) at offset 6, Abort Code: 0 @@ -27,9 +27,9 @@ Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { k task 6 'view-object'. lines 41-41: Owner: Account Address ( _ ) Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 7 'view-object'. lines 43-43: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_abort.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_abort.move similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_abort.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_abort.move index 5b1a310b819..0f32b59545e 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_abort.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_abort.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_deleted.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_deleted.exp new file mode 100644 index 00000000000..275d887458e --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_deleted.exp @@ -0,0 +1,38 @@ +processed 9 tasks + +task 1 'publish'. lines 6-30: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 6726000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 32-32: +created: object(2,0), object(2,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'view-object'. lines 34-34: +Owner: Account Address ( _ ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 4 'view-object'. lines 36-38: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 5 'run'. lines 39-39: +mutated: object(0,0), object(2,0) +deleted: object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 2204000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 + +task 6 'view-object'. lines 41-41: +Owner: Account Address ( _ ) +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 7 'view-object'. lines 43-45: +No object at id 2,1 + +task 8 'run'. lines 46-46: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3), source: Some(VMError { major_status: ABORTED, sub_status: Some(3), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_deleted.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_deleted.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_deleted.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_deleted.move index 9f91212ccf6..0a600fbd430 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_deleted.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_deleted.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_send_back.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_send_back.exp new file mode 100644 index 00000000000..d9a2ec39da9 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_send_back.exp @@ -0,0 +1,39 @@ +processed 9 tasks + +task 1 'publish'. lines 6-31: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 6756400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 33-33: +created: object(2,0), object(2,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'view-object'. lines 35-35: +Owner: Account Address ( _ ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 4 'view-object'. lines 37-39: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 5 'run'. lines 40-40: +mutated: object(0,0), object(2,0), object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 + +task 6 'view-object'. lines 42-42: +Owner: Account Address ( _ ) +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 7 'view-object'. lines 44-46: +Owner: Account Address ( fake(2,0) ) +Version: 4 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 8 'run'. lines 47-47: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3), source: Some(VMError { major_status: ABORTED, sub_status: Some(3), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_send_back.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_send_back.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_send_back.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_send_back.move index 8dd7e9f5677..a48c9371ad6 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_send_back.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_send_back.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_wrap.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_wrap.exp new file mode 100644 index 00000000000..f16913d6d00 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_wrap.exp @@ -0,0 +1,39 @@ +processed 9 tasks + +task 1 'publish'. lines 6-39: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 7569600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 41-41: +created: object(2,0), object(2,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'view-object'. lines 43-43: +Owner: Account Address ( _ ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 4 'view-object'. lines 45-47: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 5 'run'. lines 48-48: +created: object(5,0) +mutated: object(0,0), object(2,0) +wrapped: object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 3708800, storage_rebate: 3385800, non_refundable_storage_fee: 34200 + +task 6 'view-object'. lines 50-50: +Owner: Account Address ( _ ) +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 7 'view-object'. lines 52-54: +No object at id 2,1 + +task 8 'run'. lines 55-55: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3), source: Some(VMError { major_status: ABORTED, sub_status: Some(3), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_wrap.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_wrap.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_wrap.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_wrap.move index 197abb39c57..e78be03a7c9 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_wrap.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_and_wrap.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct Wrapper has key, store { id: UID, diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_by_ref.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_by_ref.exp similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_by_ref.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_by_ref.exp index 8c81a2be199..8072b66dcb2 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_by_ref.exp +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_by_ref.exp @@ -13,12 +13,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: task 3 'view-object'. lines 43-43: Owner: Account Address ( _ ) Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 45-45: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'run'. lines 47-47: mutated: object(0,0), object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_by_ref.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_by_ref.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_by_ref.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_by_ref.move index 27a62a84fc6..23643b5b625 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_by_ref.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_by_ref.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_by_value_flow_through.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_by_value_flow_through.exp similarity index 84% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_by_value_flow_through.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_by_value_flow_through.exp index 23209ac526c..bb89041c9dc 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_by_value_flow_through.exp +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_by_value_flow_through.exp @@ -13,12 +13,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: task 3 'view-object'. lines 32-32: Owner: Account Address ( _ ) Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 34-36: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'run'. lines 37-39: mutated: object(0,0), object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_by_value_flow_through.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_by_value_flow_through.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_by_value_flow_through.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_by_value_flow_through.move index b026e135e93..51f3c5ecddd 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_by_value_flow_through.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_by_value_flow_through.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/receive_dof_and_mutate.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_dof_and_mutate.exp new file mode 100644 index 00000000000..7266413b23d --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_dof_and_mutate.exp @@ -0,0 +1,59 @@ +processed 12 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 6-34: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 7828000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 36-36: +created: object(2,0), object(2,1), object(2,2), object(2,3) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 7273200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 38-38: +Owner: Object ID: ( fake(2,2) ) +Version: 2 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(2,3)}} + +task 4 'view-object'. lines 40-40: +Owner: Account Address ( A ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, value: 0u64} + +task 5 'view-object'. lines 42-42: +Owner: Account Address ( fake(2,1) ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}, value: 0u64} + +task 6 'view-object'. lines 44-44: +Owner: Object ID: ( fake(2,0) ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,3)}}, value: 0u64} + +task 7 'run'. lines 46-46: +created: object(7,0) +mutated: object(0,0), object(2,1), object(2,2) +gas summary: computation_cost: 1000000, storage_cost: 5996400, storage_rebate: 3506184, non_refundable_storage_fee: 35416 + +task 8 'view-object'. lines 48-48: +Owner: Object ID: ( fake(2,2) ) +Version: 2 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(2,3)}} + +task 9 'view-object'. lines 50-50: +Owner: Account Address ( A ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, value: 0u64} + +task 10 'view-object'. lines 52-52: +Owner: Object ID: ( fake(7,0) ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}, value: 100u64} + +task 11 'view-object'. lines 54-54: +Owner: Object ID: ( fake(2,0) ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,3)}}, value: 0u64} diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/receive_dof_and_mutate.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_dof_and_mutate.move new file mode 100644 index 00000000000..2cb344d05d3 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_dof_and_mutate.move @@ -0,0 +1,55 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --addresses tto=0x0 --accounts A + +//# publish +module tto::M1 { + use iota::transfer::Receiving; + use iota::dynamic_object_field as dof; + + const KEY: u64 = 0; + + public struct A has key, store { + id: UID, + value: u64, + } + + public fun start(ctx: &mut TxContext) { + let a = A { id: object::new(ctx), value: 0 }; + let a_address = object::id_address(&a); + let mut b = A { id: object::new(ctx), value: 0 }; + dof::add(&mut b.id, KEY, A { id: object::new(ctx), value: 0 }); + transfer::public_transfer(a, tx_context::sender(ctx)); + transfer::public_transfer(b, a_address); + } + + public entry fun receive(parent: &mut A, x: Receiving) { + let b = transfer::receive(&mut parent.id, x); + dof::add(&mut parent.id, KEY, b); + let _: &A = dof::borrow(&parent.id, KEY); + let x: &mut A = dof::borrow_mut(&mut parent.id, KEY); + x.value = 100; + } +} + +//# run tto::M1::start --sender A + +//# view-object 2,0 + +//# view-object 2,1 + +//# view-object 2,2 + +//# view-object 2,3 + +//# run tto::M1::receive --args object(2,1) receiving(2,2) --sender A + +//# view-object 2,0 + +//# view-object 2,1 + +//# view-object 2,2 + +//# view-object 2,3 diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_duo_struct.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_duo_struct.exp similarity index 82% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_duo_struct.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_duo_struct.exp index bcd336358f2..50428042cc2 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_duo_struct.exp +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_duo_struct.exp @@ -13,17 +13,17 @@ gas summary: computation_cost: 1000000, storage_cost: 4636000, storage_rebate: task 3 'view-object'. lines 48-48: Owner: Account Address ( _ ) Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 50-50: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'view-object'. lines 52-54: Owner: Account Address ( fake(2,1) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}} task 6 'programmable'. lines 55-58: mutated: object(0,0), object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_duo_struct.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_duo_struct.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_duo_struct.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_duo_struct.move index 66e1aa8f880..eeb08e5d95f 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_duo_struct.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_duo_struct.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_invalid_param_ty.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_invalid_param_ty.exp similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_invalid_param_ty.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_invalid_param_ty.exp index eafd9afde2f..e6108ad41d2 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_invalid_param_ty.exp +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_invalid_param_ty.exp @@ -13,12 +13,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: task 3 'view-object'. lines 45-45: Owner: Account Address ( _ ) Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 47-47: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'run'. lines 49-49: Error: Transaction Effects Status: Invalid command argument at 0. The type of the value does not match the expected type diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_invalid_param_ty.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_invalid_param_ty.move similarity index 94% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_invalid_param_ty.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_invalid_param_ty.move index cbc3aba8ee9..2fe8eb5c84d 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_invalid_param_ty.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_invalid_param_ty.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/receive_invalid_type.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_invalid_type.exp new file mode 100644 index 00000000000..3d912dd74c0 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_invalid_type.exp @@ -0,0 +1,25 @@ +processed 6 tasks + +task 1 'publish'. lines 6-30: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 6923600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 32-32: +created: object(2,0), object(2,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'view-object'. lines 34-34: +Owner: Account Address ( _ ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 4 'view-object'. lines 36-38: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 5 'run'. lines 39-39: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::receive_impl (function index 12) at offset 0, Abort Code: 2 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_invalid_type.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_invalid_type.move similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_invalid_type.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_invalid_type.move index 23c6c6e91a6..54bb5918a49 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_invalid_type.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_invalid_type.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_many_move_vec.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_many_move_vec.exp similarity index 79% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_many_move_vec.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_many_move_vec.exp index 4b7ba51b392..cc2f1f5b258 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_many_move_vec.exp +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_many_move_vec.exp @@ -13,27 +13,27 @@ gas summary: computation_cost: 1000000, storage_cost: 7068000, storage_rebate: task 3 'view-object'. lines 81-81: Owner: Account Address ( _ ) Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 83-83: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'view-object'. lines 85-85: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}} task 6 'view-object'. lines 87-87: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,3)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,3)}}} task 7 'view-object'. lines 89-91: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,4)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,4)}}} task 8 'programmable'. lines 92-95: mutated: object(0,0), object(2,0) @@ -74,24 +74,24 @@ gas summary: computation_cost: 1000000, storage_cost: 7068000, storage_rebate: task 17 'view-object'. lines 140-140: Owner: Account Address ( _ ) Version: 12 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 18 'view-object'. lines 142-142: Owner: Account Address ( _ ) Version: 12 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 19 'view-object'. lines 144-144: Owner: Account Address ( _ ) Version: 12 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}} task 20 'view-object'. lines 146-146: Owner: Account Address ( _ ) Version: 12 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,3)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,3)}}} task 21 'view-object'. lines 148-148: Owner: Account Address ( _ ) Version: 12 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,4)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,4)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_many_move_vec.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_many_move_vec.move similarity index 84% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_many_move_vec.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_many_move_vec.move index baeaafb9377..a1fd9107572 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_many_move_vec.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_many_move_vec.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, @@ -90,51 +91,51 @@ module tto::M1 { // Make the Move vec but then never use it -- this should be fine since they're all drop //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) -//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); +//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); // Make the Move vec and pass, but never receive //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) -//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); +//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); //> 1: tto::M1::receive_none(Input(0), Result(0)); // Make the Move vec of receiving arguments and then receive all but the last. Only the ince we receive should be mutated //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) -//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); +//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); //> 1: tto::M1::receive_all_but_last(Input(0), Result(0)); // Make the Move vec of receiving arguments, pass to a function by immref, then later use the vec to receive all of them //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) -//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); +//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); //> 1: tto::M1::receive_none_by_immref(Input(0), Result(0)); //> 2: tto::M1::receive_all_send_back(Input(0), Result(0)); // Make the Move vec of receiving arguments, pass to a function by mutref, then later use the vec to receive all of them //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) -//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); +//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); //> 1: tto::M1::receive_none_by_mutref(Input(0), Result(0)); //> 2: tto::M1::receive_all_send_back(Input(0), Result(0)); // Make the Move vec of receiving arguments, pass to a function by mutref and receive some //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) -//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); +//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); //> 1: tto::M1::receive_all_but_last_by_mut_ref(Input(0), Result(0)); //> 2: tto::M1::receive_all_by_mut_ref(Input(0), Result(0)); // Make the Move vec of receiving arguments, pass to a function by mutref, receive some, then pass by mutref again to receive the rest //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) -//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); +//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); //> 1: tto::M1::receive_all_but_last_by_mut_ref(Input(0), Result(0)); //> 2: tto::M1::receive_all_by_mut_ref(Input(0), Result(0)); // Make the Move vec of receiving arguments, pass to a function by mutref, receive some, then pass by value to receive the rest //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) -//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); +//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); //> 1: tto::M1::receive_all_but_last_by_mut_ref(Input(0), Result(0)); //> 2: tto::M1::receive_all_send_back(Input(0), Result(0)); // Make the Move vec of receiving arguments and then receive all of them //# programmable --inputs object(2,0) receiving(2,1) receiving(2,2) receiving(2,3) receiving(2,4) -//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); +//> 0: MakeMoveVec>([Input(1), Input(2), Input(3), Input(4)]); //> 1: tto::M1::receive_all(Input(0), Result(0)); //# view-object 2,0 diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/receive_multiple_times_in_row.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_multiple_times_in_row.exp new file mode 100644 index 00000000000..387ebfb1551 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_multiple_times_in_row.exp @@ -0,0 +1,59 @@ +processed 13 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 6-36: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 7007200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 38-38: +created: object(2,0), object(2,1) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'run'. lines 40-40: +created: object(3,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2204000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 4 'view-object'. lines 42-42: +Owner: Account Address ( _ ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 5 'view-object'. lines 44-46: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 6 'run'. lines 47-47: +mutated: object(0,1), object(2,0), object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 + +task 7 'view-object'. lines 49-49: +Owner: Account Address ( _ ) +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 8 'view-object'. lines 51-53: +Owner: Account Address ( fake(2,0) ) +Version: 4 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 9 'run'. lines 54-56: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3), source: Some(VMError { major_status: ABORTED, sub_status: Some(3), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } + +task 10 'run'. lines 57-59: +mutated: object(0,1), object(2,0), object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 + +task 11 'run'. lines 60-62: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3), source: Some(VMError { major_status: ABORTED, sub_status: Some(3), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } + +task 12 'run'. lines 63-63: +mutated: object(0,1), object(2,0), object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/receive_multiple_times_in_row.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_multiple_times_in_row.move new file mode 100644 index 00000000000..678ea44ffb3 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_multiple_times_in_row.move @@ -0,0 +1,64 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --addresses tto=0x0 --accounts A + +//# publish +module tto::M1 { + use iota::transfer::Receiving; + + public struct A has key, store { + id: UID, + } + + public struct B has key, store { + id: UID, + } + + public fun start(ctx: &mut TxContext) { + let a = A { id: object::new(ctx) }; + let a_address = object::id_address(&a); + let b = B { id: object::new(ctx) }; + transfer::public_transfer(a, tx_context::sender(ctx)); + transfer::public_transfer(b, a_address); + } + + public fun middle(ctx: &mut TxContext) { + let a = A { id: object::new(ctx) }; + transfer::public_transfer(a, tx_context::sender(ctx)); + } + + public entry fun send_back(parent: &mut A, x: Receiving) { + let b = transfer::receive(&mut parent.id, x); + let parent_address = object::id_address(parent); + transfer::public_transfer(b, parent_address); + } +} + +//# run tto::M1::start + +//# run tto::M1::middle --sender A + +//# view-object 2,0 + +//# view-object 2,1 + +// Receive the object and then send it +//# run tto::M1::send_back --args object(2,0) receiving(2,1) + +//# view-object 2,0 + +//# view-object 2,1 + +// Can no longer receive that object at the previous version number +//# run tto::M1::send_back --args object(2,0) receiving(2,1)@3 + +// Can receive the object at the new version number +//# run tto::M1::send_back --args object(2,0) receiving(2,1)@4 + +// Cannot try and receive the object with an invalid owner even if it has the right type +//# run tto::M1::send_back --summarize --args object(3,0) receiving(2,1)@6 --sender A + +// Can still receive and send back so state is all good still, and version number hasn't been incremented for the receiving object due to the failed tx above. +//# run tto::M1::send_back --args object(2,0) receiving(2,1)@6 diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_object_id.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_object_id.exp similarity index 78% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_object_id.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_object_id.exp index 1d3e484ec82..2794d658635 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_object_id.exp +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_object_id.exp @@ -13,12 +13,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: task 3 'view-object'. lines 33-33: Owner: Account Address ( _ ) Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 35-35: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'run'. lines 37-37: mutated: object(0,0) @@ -35,9 +35,9 @@ gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 9 task 8 'view-object'. lines 45-45: Owner: Account Address ( _ ) Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 9 'view-object'. lines 47-47: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_object_id.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_object_id.move similarity index 86% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_object_id.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_object_id.move index ab18351a785..232f9bd14e4 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_object_id.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_object_id.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, @@ -37,7 +38,7 @@ module tto::M1 { //# run tto::M1::receiver --args receiving(2,1) //# programmable --inputs receiving(2,1) -//> sui::transfer::receiving_object_id(Input(0)) +//> iota::transfer::receiving_object_id(Input(0)) //# programmable --inputs receiving(2,1) //> tto::M1::receiver(Input(0)) diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/receive_object_owner.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_object_owner.exp new file mode 100644 index 00000000000..a8c35303c47 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_object_owner.exp @@ -0,0 +1,35 @@ +processed 8 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 6-28: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 6634800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 30-30: +created: object(2,0), object(2,1), object(2,2) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5996400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 32-32: +Owner: Object ID: ( fake(2,2) ) +Version: 2 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(2,1)}} + +task 4 'view-object'. lines 34-34: +Owner: Object ID: ( fake(2,0) ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, value: 0u64} + +task 5 'view-object'. lines 36-38: +Owner: Account Address ( A ) +Version: 2 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}, value: 0u64} + +task 6 'run'. lines 39-41: +Error: Error checking transaction input objects: InvalidChildObjectArgument { child_id: object(2,1), parent_id: object(2,0) } + +task 7 'run'. lines 42-42: +Error: Error checking transaction input objects: InvalidChildObjectArgument { child_id: object(2,0), parent_id: object(2,2) } diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_object_owner.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_object_owner.move similarity index 88% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_object_owner.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_object_owner.move index aaee77f1af4..034510cd7f2 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_object_owner.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_object_owner.move @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 --accounts A //# publish module tto::M1 { - use sui::transfer::Receiving; - use sui::dynamic_object_field as dof; + use iota::transfer::Receiving; + use iota::dynamic_object_field as dof; const KEY: u64 = 0; diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_return_object_dont_touch.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_return_object_dont_touch.exp similarity index 75% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_return_object_dont_touch.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_return_object_dont_touch.exp index df94a93a8db..784a3f83f32 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_return_object_dont_touch.exp +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_return_object_dont_touch.exp @@ -13,12 +13,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: task 3 'view-object'. lines 33-33: Owner: Account Address ( _ ) Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 35-37: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'programmable'. lines 38-39: Error: Transaction Effects Status: Unused result without the drop ability. Command result 0, return value 0 @@ -27,9 +27,9 @@ Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { k task 6 'view-object'. lines 41-41: Owner: Account Address ( _ ) Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 7 'view-object'. lines 43-43: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_return_object_dont_touch.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_return_object_dont_touch.move similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_return_object_dont_touch.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_return_object_dont_touch.move index 8bb2f20a1a2..03230bc90ac 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_return_object_dont_touch.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_return_object_dont_touch.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/receive_return_object_then_transfer.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_return_object_then_transfer.exp new file mode 100644 index 00000000000..25977cbafc5 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_return_object_then_transfer.exp @@ -0,0 +1,35 @@ +processed 8 tasks + +task 1 'publish'. lines 6-29: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 6604400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 31-31: +created: object(2,0), object(2,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'view-object'. lines 33-33: +Owner: Account Address ( _ ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 4 'view-object'. lines 35-37: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 5 'programmable'. lines 38-40: +mutated: object(0,0), object(2,0), object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 + +task 6 'view-object'. lines 42-42: +Owner: Account Address ( _ ) +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 7 'view-object'. lines 44-44: +Owner: Account Address ( tto ) +Version: 4 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_return_object_then_transfer.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_return_object_then_transfer.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_return_object_then_transfer.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_return_object_then_transfer.move index 79da6a20e50..3448969bfe6 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_return_object_then_transfer.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_return_object_then_transfer.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_ticket_coin_operations.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_ticket_coin_operations.exp similarity index 85% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_ticket_coin_operations.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_ticket_coin_operations.exp index 8db9e32d055..867addbf27d 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_ticket_coin_operations.exp +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_ticket_coin_operations.exp @@ -13,12 +13,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: task 3 'view-object'. lines 27-27: Owner: Account Address ( _ ) Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 29-31: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'programmable'. lines 32-33: Error: Transaction Effects Status: Invalid command argument at 0. The type of the value does not match the expected type @@ -39,9 +39,9 @@ Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { k task 9 'view-object'. lines 44-44: Owner: Account Address ( _ ) Version: 7 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 10 'view-object'. lines 46-46: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_ticket_coin_operations.move b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_ticket_coin_operations.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/receive_object/receive_ticket_coin_operations.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/receive_ticket_coin_operations.move index 1f9cd85f10a..2ab6b3ef432 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_ticket_coin_operations.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/receive_ticket_coin_operations.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/basic_receive.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/basic_receive.exp new file mode 100644 index 00000000000..a2a87f53810 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/basic_receive.exp @@ -0,0 +1,39 @@ +processed 9 tasks + +task 1 'publish'. lines 6-30: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 6969200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 32-32: +created: object(2,0), object(2,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'view-object'. lines 34-34: +Owner: Shared +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 4 'view-object'. lines 36-36: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 5 'run'. lines 38-38: +mutated: object(0,0), object(2,0), object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 + +task 6 'view-object'. lines 40-40: +Owner: Shared +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 7 'view-object'. lines 42-42: +Owner: Account Address ( _ ) +Version: 4 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 8 'run'. lines 44-44: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 +Debug of error: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3) at command Some(0) diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/basic_receive.move b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/basic_receive.move new file mode 100644 index 00000000000..7ba34354308 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/basic_receive.move @@ -0,0 +1,45 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --addresses tto=0x0 + +//# publish +module tto::M1 { + use iota::transfer::Receiving; + + public struct A has key, store { + id: UID, + } + + public struct B has key, store { + id: UID, + } + + public fun start(ctx: &mut TxContext) { + let a = A { id: object::new(ctx) }; + let a_address = object::id_address(&a); + let b = B { id: object::new(ctx) }; + transfer::public_share_object(a); + transfer::public_transfer(b, a_address); + } + + public entry fun receiver(parent: &mut A, x: Receiving) { + let b = transfer::receive(&mut parent.id, x); + transfer::public_transfer(b, @tto); + } +} + +//# run tto::M1::start + +//# view-object 2,0 + +//# view-object 2,1 + +//# run tto::M1::receiver --args object(2,0) receiving(2,1) + +//# view-object 2,0 + +//# view-object 2,1 + +//# run tto::M1::receiver --args object(2,0) receiving(2,1)@3 diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/drop_receiving.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/drop_receiving.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/drop_receiving.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/drop_receiving.exp diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/drop_receiving.move b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/drop_receiving.move new file mode 100644 index 00000000000..c25e45b67aa --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/drop_receiving.move @@ -0,0 +1,48 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --addresses tto=0x0 + +//# publish +module tto::M1 { + use iota::transfer::Receiving; + + public struct A has key, store { + id: UID, + } + + public struct B has key, store { + id: UID, + } + public fun start(ctx: &mut TxContext) { + let a = A { id: object::new(ctx) }; + let a_address = object::id_address(&a); + let b = B { id: object::new(ctx) }; + transfer::public_share_object(a); + transfer::public_transfer(b, a_address); + } + + public entry fun send_back(parent: &mut A, x: Receiving) { + let b = transfer::receive(&mut parent.id, x); + let parent_address = object::id_address(parent); + transfer::public_transfer(b, parent_address); + } + + public entry fun nop(_parent: &mut A) { } + public entry fun nop_with_receiver(_parent: &mut A, _x: Receiving) { } +} + +//# run tto::M1::start + +//# programmable --inputs object(2,0) receiving(2,1) +//> tto::M1::send_back(Input(0), Input(1)) + +// Include the receiving argument, but don't use it at the PTB level +//# programmable --inputs object(2,0) receiving(2,1) +//> tto::M1::nop(Input(0)) + +// Include the receiving argument, but don't use it at the Move level. The +// receiving object should not be mutated by this. +//# programmable --inputs object(2,0) receiving(2,1) +//> tto::M1::nop_with_receiver(Input(0), Input(1)) diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/receive_dof_and_mutate.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/receive_dof_and_mutate.exp new file mode 100644 index 00000000000..ff88f21d933 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/receive_dof_and_mutate.exp @@ -0,0 +1,59 @@ +processed 12 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 6-34: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 7881200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 36-36: +created: object(2,0), object(2,1), object(2,2), object(2,3) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 7273200, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'view-object'. lines 38-38: +Owner: Object ID: ( fake(2,3) ) +Version: 3 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(2,2)}} + +task 4 'view-object'. lines 40-40: +Owner: Shared +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, value: 0u64} + +task 5 'view-object'. lines 42-42: +Owner: Object ID: ( fake(2,0) ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}, value: 0u64} + +task 6 'view-object'. lines 44-44: +Owner: Account Address ( fake(2,1) ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,3)}}, value: 0u64} + +task 7 'run'. lines 46-46: +created: object(7,0) +mutated: object(0,1), object(2,1), object(2,3) +gas summary: computation_cost: 1000000, storage_cost: 5996400, storage_rebate: 3506184, non_refundable_storage_fee: 35416 + +task 8 'view-object'. lines 48-48: +Owner: Object ID: ( fake(2,3) ) +Version: 3 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(2,2)}} + +task 9 'view-object'. lines 50-50: +Owner: Shared +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}, value: 0u64} + +task 10 'view-object'. lines 52-52: +Owner: Object ID: ( fake(2,0) ) +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}, value: 0u64} + +task 11 'view-object'. lines 54-54: +Owner: Object ID: ( fake(7,0) ) +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,3)}}, value: 100u64} diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/receive_dof_and_mutate.move b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/receive_dof_and_mutate.move new file mode 100644 index 00000000000..44959d67a55 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/receive_dof_and_mutate.move @@ -0,0 +1,55 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --addresses tto=0x0 --accounts A + +//# publish +module tto::M1 { + use iota::transfer::Receiving; + use iota::dynamic_object_field as dof; + + const KEY: u64 = 0; + + public struct A has key, store { + id: UID, + value: u64, + } + + public fun start(ctx: &mut TxContext) { + let a = A { id: object::new(ctx), value: 0 }; + let a_address = object::id_address(&a); + let mut b = A { id: object::new(ctx), value: 0 }; + dof::add(&mut b.id, KEY, A { id: object::new(ctx), value: 0 }); + transfer::public_share_object(a); + transfer::public_transfer(b, a_address); + } + + public entry fun receive(parent: &mut A, x: Receiving) { + let b = transfer::receive(&mut parent.id, x); + dof::add(&mut parent.id, KEY, b); + let _: &A = dof::borrow(&parent.id, KEY); + let x: &mut A = dof::borrow_mut(&mut parent.id, KEY); + x.value = 100; + } +} + +//# run tto::M1::start + +//# view-object 2,0 + +//# view-object 2,1 + +//# view-object 2,2 + +//# view-object 2,3 + +//# run tto::M1::receive --args object(2,1) receiving(2,3) + +//# view-object 2,0 + +//# view-object 2,1 + +//# view-object 2,2 + +//# view-object 2,3 diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/receive_multiple_times_in_row.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/receive_multiple_times_in_row.exp new file mode 100644 index 00000000000..e35c22ea23e --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/receive_multiple_times_in_row.exp @@ -0,0 +1,59 @@ +processed 13 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 6-37: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 7182000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 39-39: +created: object(2,0), object(2,1) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'run'. lines 41-41: +created: object(3,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2204000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 4 'view-object'. lines 43-43: +Owner: Shared +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 5 'view-object'. lines 45-47: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 6 'run'. lines 48-48: +mutated: object(0,1), object(2,0), object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 + +task 7 'view-object'. lines 50-50: +Owner: Shared +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 8 'view-object'. lines 52-54: +Owner: Account Address ( fake(2,0) ) +Version: 4 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 9 'run'. lines 55-57: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 +Debug of error: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3) at command Some(0) + +task 10 'run'. lines 58-60: +mutated: object(0,1), object(2,0), object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 + +task 11 'run'. lines 61-63: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3), source: Some(VMError { major_status: ABORTED, sub_status: Some(3), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } + +task 12 'run'. lines 64-64: +mutated: object(0,1), object(2,0), object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/receive_multiple_times_in_row.move b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/receive_multiple_times_in_row.move new file mode 100644 index 00000000000..5edd7c6fae4 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/receive_multiple_times_in_row.move @@ -0,0 +1,65 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --addresses tto=0x0 --accounts A + +//# publish +module tto::M1 { + use iota::transfer::Receiving; + + public struct A has key, store { + id: UID, + } + + public struct B has key, store { + id: UID, + } + + public fun start(ctx: &mut TxContext) { + let a = A { id: object::new(ctx) }; + let a_address = object::id_address(&a); + let b = B { id: object::new(ctx) }; + transfer::public_share_object(a); + transfer::public_transfer(b, a_address); + } + + + public fun middle(ctx: &mut TxContext) { + let a = A { id: object::new(ctx) }; + transfer::public_transfer(a, tx_context::sender(ctx)); + } + + public entry fun send_back(parent: &mut A, x: Receiving) { + let b = transfer::receive(&mut parent.id, x); + let parent_address = object::id_address(parent); + transfer::public_transfer(b, parent_address); + } +} + +//# run tto::M1::start + +//# run tto::M1::middle --sender A + +//# view-object 2,0 + +//# view-object 2,1 + +// Can receive the object and then send it +//# run tto::M1::send_back --args object(2,0) receiving(2,1) + +//# view-object 2,0 + +//# view-object 2,1 + +// Can no longer receive that object at the previous version number +//# run tto::M1::send_back --args object(2,0) receiving(2,1)@3 + +// Can receive the object at the new version number +//# run tto::M1::send_back --args object(2,0) receiving(2,1)@4 + +// Cannot try and receive the object with an invalid owner even if it has the right type +//# run tto::M1::send_back --summarize --args object(3,0) receiving(2,1)@6 --sender A + +// Can run still receive and send back so state is all good still, and version number hasn't been incremented for the object +//# run tto::M1::send_back --args object(2,0) receiving(2,1)@6 diff --git a/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/transfer_then_share.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/transfer_then_share.exp new file mode 100644 index 00000000000..d54fed5bc71 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/transfer_then_share.exp @@ -0,0 +1,39 @@ +processed 9 tasks + +task 1 'publish'. lines 6-31: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 6916000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 33-33: +created: object(2,0), object(2,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'view-object'. lines 35-35: +Owner: Shared +Version: 3 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 4 'view-object'. lines 37-37: +Owner: Account Address ( fake(2,0) ) +Version: 3 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 5 'run'. lines 39-39: +mutated: object(0,0), object(2,0), object(2,1) +gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 + +task 6 'view-object'. lines 41-41: +Owner: Shared +Version: 4 +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} + +task 7 'view-object'. lines 43-43: +Owner: Account Address ( _ ) +Version: 4 +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} + +task 8 'run'. lines 45-45: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 +Debug of error: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3) at command Some(0) diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/transfer_then_share.move b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/transfer_then_share.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/transfer_then_share.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/transfer_then_share.move index c105c6121c6..aea6c768db5 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/transfer_then_share.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/shared_parent/transfer_then_share.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/take_receiver_then_try_to_reuse.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/take_receiver_then_try_to_reuse.exp similarity index 85% rename from crates/sui-adapter-transactional-tests/tests/receive_object/take_receiver_then_try_to_reuse.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/take_receiver_then_try_to_reuse.exp index f93b5d149f9..2a8fd983a9a 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/take_receiver_then_try_to_reuse.exp +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/take_receiver_then_try_to_reuse.exp @@ -13,12 +13,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: task 3 'view-object'. lines 36-36: Owner: Account Address ( _ ) Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: tto::M1::A {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 38-40: Owner: Account Address ( fake(2,0) ) Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: tto::M1::B {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'programmable'. lines 41-43: Error: Transaction Effects Status: Invalid command argument at 1. Invalid usage of value. Mutably borrowed values require unique usage. Immutably borrowed values cannot be taken or borrowed mutably. Taken values cannot be used again. diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/take_receiver_then_try_to_reuse.move b/crates/iota-adapter-transactional-tests/tests/receive_object/take_receiver_then_try_to_reuse.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/receive_object/take_receiver_then_try_to_reuse.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/take_receiver_then_try_to_reuse.move index 1fbaa82b101..a31e8215f7a 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/take_receiver_then_try_to_reuse.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/take_receiver_then_try_to_reuse.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 //# publish module tto::M1 { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct A has key, store { id: UID, diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/transfer_object_cyclic.exp b/crates/iota-adapter-transactional-tests/tests/receive_object/transfer_object_cyclic.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/receive_object/transfer_object_cyclic.exp rename to crates/iota-adapter-transactional-tests/tests/receive_object/transfer_object_cyclic.exp diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/transfer_object_cyclic.move b/crates/iota-adapter-transactional-tests/tests/receive_object/transfer_object_cyclic.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/receive_object/transfer_object_cyclic.move rename to crates/iota-adapter-transactional-tests/tests/receive_object/transfer_object_cyclic.move index 40b624738d8..95a43bd1b58 100644 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/transfer_object_cyclic.move +++ b/crates/iota-adapter-transactional-tests/tests/receive_object/transfer_object_cyclic.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses tto=0x0 diff --git a/crates/sui-adapter-transactional-tests/tests/runtime_behavior/error_locations.exp b/crates/iota-adapter-transactional-tests/tests/runtime_behavior/error_locations.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/runtime_behavior/error_locations.exp rename to crates/iota-adapter-transactional-tests/tests/runtime_behavior/error_locations.exp diff --git a/crates/sui-adapter-transactional-tests/tests/runtime_behavior/error_locations.move b/crates/iota-adapter-transactional-tests/tests/runtime_behavior/error_locations.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/runtime_behavior/error_locations.move rename to crates/iota-adapter-transactional-tests/tests/runtime_behavior/error_locations.move index 320bf4875dd..f010a2bef65 100644 --- a/crates/sui-adapter-transactional-tests/tests/runtime_behavior/error_locations.move +++ b/crates/iota-adapter-transactional-tests/tests/runtime_behavior/error_locations.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // test location for execution errors diff --git a/crates/sui-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_new.exp b/crates/iota-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_new.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_new.exp rename to crates/iota-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_new.exp diff --git a/crates/sui-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_new.move b/crates/iota-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_new.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_new.move rename to crates/iota-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_new.move index 480421f7c3f..19e6cde8e76 100644 --- a/crates/sui-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_new.move +++ b/crates/iota-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_new.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // test old behavior of invariant violation diff --git a/crates/sui-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_old.exp b/crates/iota-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_old.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_old.exp rename to crates/iota-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_old.exp diff --git a/crates/sui-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_old.move b/crates/iota-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_old.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_old.move rename to crates/iota-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_old.move index deb40eec2f2..36c78455324 100644 --- a/crates/sui-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_old.move +++ b/crates/iota-adapter-transactional-tests/tests/runtime_behavior/versioned_check_swap_loc_old.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // test old behavior of invariant violation diff --git a/crates/sui-adapter-transactional-tests/tests/shared/add_dynamic_field.exp b/crates/iota-adapter-transactional-tests/tests/shared/add_dynamic_field.exp similarity index 86% rename from crates/sui-adapter-transactional-tests/tests/shared/add_dynamic_field.exp rename to crates/iota-adapter-transactional-tests/tests/shared/add_dynamic_field.exp index 098a9ec34b7..1d2c935bb7e 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/add_dynamic_field.exp +++ b/crates/iota-adapter-transactional-tests/tests/shared/add_dynamic_field.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2211600, storage_rebate: task 3 'view-object'. lines 36-36: Owner: Shared Version: 2 -Contents: a::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: a::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'run'. lines 38-38: created: object(4,0) @@ -31,7 +31,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2211600, storage_rebate: task 6 'view-object'. lines 42-42: Owner: Shared Version: 4 -Contents: a::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(5,0)}}} +Contents: a::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(5,0)}}} task 7 'run'. lines 44-44: mutated: object(0,0), object(5,0) diff --git a/crates/sui-adapter-transactional-tests/tests/shared/add_dynamic_field.move b/crates/iota-adapter-transactional-tests/tests/shared/add_dynamic_field.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/shared/add_dynamic_field.move rename to crates/iota-adapter-transactional-tests/tests/shared/add_dynamic_field.move index f5f5f7593f3..f36c44a3500 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/add_dynamic_field.move +++ b/crates/iota-adapter-transactional-tests/tests/shared/add_dynamic_field.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests that shared objects can have dynamic fields added @@ -8,7 +9,7 @@ //# publish module a::m { - use sui::dynamic_field::{add, remove}; + use iota::dynamic_field::{add, remove}; public struct Obj has key, store { id: object::UID, diff --git a/crates/sui-adapter-transactional-tests/tests/shared/become_dynamic_field.exp b/crates/iota-adapter-transactional-tests/tests/shared/become_dynamic_field.exp similarity index 86% rename from crates/sui-adapter-transactional-tests/tests/shared/become_dynamic_field.exp rename to crates/iota-adapter-transactional-tests/tests/shared/become_dynamic_field.exp index 1af89e5fc9b..b830a28ac09 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/become_dynamic_field.exp +++ b/crates/iota-adapter-transactional-tests/tests/shared/become_dynamic_field.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 3 'view-object'. lines 43-43: Owner: Shared Version: 2 -Contents: a::m::Inner {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: a::m::Inner {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'run'. lines 45-45: Error: Transaction Effects Status: The shared object operation is not allowed. @@ -30,7 +30,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 6 'view-object'. lines 49-49: Owner: Shared Version: 4 -Contents: a::m::Inner {id: sui::object::UID {id: sui::object::ID {bytes: fake(5,0)}}} +Contents: a::m::Inner {id: iota::object::UID {id: iota::object::ID {bytes: fake(5,0)}}} task 7 'run'. lines 51-51: created: object(7,0) diff --git a/crates/sui-adapter-transactional-tests/tests/shared/become_dynamic_field.move b/crates/iota-adapter-transactional-tests/tests/shared/become_dynamic_field.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/shared/become_dynamic_field.move rename to crates/iota-adapter-transactional-tests/tests/shared/become_dynamic_field.move index 88166e584f9..02e009a9d51 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/become_dynamic_field.move +++ b/crates/iota-adapter-transactional-tests/tests/shared/become_dynamic_field.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests that shared objects cannot become dynamic fields and that a shared object @@ -8,7 +9,7 @@ //# publish module a::m { - use sui::dynamic_field::{add, remove}; + use iota::dynamic_field::{add, remove}; public struct Outer has key, store { id: object::UID, diff --git a/crates/sui-adapter-transactional-tests/tests/shared/become_dynamic_object_field.exp b/crates/iota-adapter-transactional-tests/tests/shared/become_dynamic_object_field.exp similarity index 86% rename from crates/sui-adapter-transactional-tests/tests/shared/become_dynamic_object_field.exp rename to crates/iota-adapter-transactional-tests/tests/shared/become_dynamic_object_field.exp index ab9557522b0..4dbe00d6f5f 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/become_dynamic_object_field.exp +++ b/crates/iota-adapter-transactional-tests/tests/shared/become_dynamic_object_field.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 3 'view-object'. lines 43-43: Owner: Shared Version: 2 -Contents: a::m::Inner {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: a::m::Inner {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'run'. lines 45-45: Error: Transaction Effects Status: The shared object operation is not allowed. @@ -30,7 +30,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 6 'view-object'. lines 49-49: Owner: Shared Version: 4 -Contents: a::m::Inner {id: sui::object::UID {id: sui::object::ID {bytes: fake(5,0)}}} +Contents: a::m::Inner {id: iota::object::UID {id: iota::object::ID {bytes: fake(5,0)}}} task 7 'run'. lines 51-51: created: object(7,0) diff --git a/crates/sui-adapter-transactional-tests/tests/shared/become_dynamic_object_field.move b/crates/iota-adapter-transactional-tests/tests/shared/become_dynamic_object_field.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/shared/become_dynamic_object_field.move rename to crates/iota-adapter-transactional-tests/tests/shared/become_dynamic_object_field.move index 8b666945486..1b64cf0c826 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/become_dynamic_object_field.move +++ b/crates/iota-adapter-transactional-tests/tests/shared/become_dynamic_object_field.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests that shared objects cannot become dynamic fields and that a shared object @@ -8,7 +9,7 @@ //# publish module a::m { - use sui::dynamic_object_field::{add, remove}; + use iota::dynamic_object_field::{add, remove}; public struct Outer has key, store { id: object::UID, diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion.exp b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion.exp similarity index 87% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion.exp rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion.exp index 51ebd871f1c..222ccff93cd 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion.exp +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion.exp @@ -18,7 +18,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 4 'view-object'. lines 40-42: Owner: Shared Version: 4 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}} task 5 'run'. lines 43-43: mutated: object(0,0) @@ -33,7 +33,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 7 'view-object'. lines 47-49: Owner: Shared Version: 6 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}} task 8 'run'. lines 50-50: mutated: object(0,0) diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion.move b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion.move rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion.move index 5a943db8420..e4a154c5830 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion.move +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests that shared objects can be deleted by passing by value diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec.exp b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec.exp similarity index 79% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec.exp rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec.exp index 8796fd44132..a4523d855a6 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec.exp +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec.exp @@ -18,12 +18,12 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 4 'view-object'. lines 51-51: Owner: Shared Version: 3 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 5 'view-object'. lines 53-55: Owner: Shared Version: 4 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}} task 6 'programmable'. lines 56-58: mutated: object(0,0), object(2,0) @@ -38,7 +38,7 @@ gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: task 8 'view-object'. lines 62-64: Owner: Shared Version: 6 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(7,0)}}, balance: sui::balance::Balance {value: 0u64}} +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(7,0)}}, balance: iota::balance::Balance {value: 0u64}} task 9 'programmable'. lines 65-70: created: object(9,0) diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec.move b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec.move similarity index 83% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec.move rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec.move index 1df7715563b..342c3fe5a22 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec.move +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses t1=0x0 t2=0x0 --shared-object-deletion true @@ -6,15 +7,15 @@ //# publish module t2::o2 { - use sui::sui::SUI; - use sui::coin::{Self, Coin}; + use iota::iota::IOTA; + use iota::coin::{Self, Coin}; public struct Obj2 has key, store { id: UID, } public fun mint_shared_coin(ctx: &mut TxContext) { - transfer::public_share_object(coin::zero(ctx)) + transfer::public_share_object(coin::zero(ctx)) } public fun create(ctx: &mut TxContext) { @@ -33,13 +34,13 @@ module t2::o2 { object::delete(id); } - public fun pop_coin(mut o2: vector>): Coin { + public fun pop_coin(mut o2: vector>): Coin { let o = vector::pop_back(&mut o2); vector::destroy_empty(o2); o } - public fun share_coin(o2: Coin) { + public fun share_coin(o2: Coin) { transfer::public_share_object(o2); } } diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec_fails.exp b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec_fails.exp similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec_fails.exp rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec_fails.exp index 0483b045a2c..9b863bf381a 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec_fails.exp +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec_fails.exp @@ -18,12 +18,12 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 4 'view-object'. lines 103-103: Owner: Shared Version: 3 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 5 'view-object'. lines 105-107: Owner: Shared Version: 4 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}} task 6 'programmable'. lines 108-112: Error: Transaction Effects Status: The shared object operation is not allowed. @@ -69,7 +69,7 @@ gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: task 16 'view-object'. lines 159-162: Owner: Shared Version: 14 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(15,0)}}, balance: sui::balance::Balance {value: 0u64}} +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(15,0)}}, balance: iota::balance::Balance {value: 0u64}} task 17 'programmable'. lines 163-169: Error: Transaction Effects Status: Unused result without the drop ability. Command result 1, return value 0 diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec_fails.move b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec_fails.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec_fails.move rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec_fails.move index 3f1d5fab549..05b706f46f1 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec_fails.move +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_make_move_vec_fails.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses t1=0x0 t2=0x0 --shared-object-deletion true @@ -6,20 +7,20 @@ //# publish module t2::o2 { - use sui::dynamic_field as df; - use sui::dynamic_object_field as dof; - use sui::sui::SUI; - use sui::coin::{Self, Coin}; + use iota::dynamic_field as df; + use iota::dynamic_object_field as dof; + use iota::iota::IOTA; + use iota::coin::{Self, Coin}; public struct Obj2 has key, store { id: UID, } public fun mint_shared_coin(ctx: &mut TxContext) { - transfer::public_share_object(coin::zero(ctx)) + transfer::public_share_object(coin::zero(ctx)) } - public fun pop_coin(mut o2: vector>): Coin { + public fun pop_coin(mut o2: vector>): Coin { let o = vector::pop_back(&mut o2); vector::destroy_empty(o2); o @@ -91,7 +92,7 @@ module t2::o2 { transfer::share_object(o2); } - public fun share_coin(o2: Coin) { + public fun share_coin(o2: Coin) { transfer::public_share_object(o2); } } @@ -172,7 +173,7 @@ module t2::o2 { //> 1: t2::o2::pop_coin(Result(0)); //> 2: SplitCoins(Result(1), [Input(0)]); //> 3: TransferObjects([Result(2)], Input(2)); -//> 4: sui::transfer::public_share_object(Input(1)); +//> 4: iota::transfer::public_share_object(Input(1)); // Try to reshare the shared object -- this should fail since the input was // used for the `MakeMoveVec` call diff --git a/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge.exp b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge.exp new file mode 100644 index 00000000000..422004e2db2 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge.exp @@ -0,0 +1,104 @@ +processed 21 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 13-60: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 9264400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 62-62: +created: object(2,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'run'. lines 64-64: +created: object(3,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 4 'view-object'. lines 66-66: +Owner: Shared +Version: 3 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, balance: iota::balance::Balance {value: 0u64}} + +task 5 'view-object'. lines 68-71: +Owner: Account Address ( A ) +Version: 4 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, balance: iota::balance::Balance {value: 0u64}} + +task 6 'programmable'. lines 72-76: +mutated: object(0,0), object(3,0) +deleted: object(2,0) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 1956240, non_refundable_storage_fee: 19760 + +task 7 'run'. lines 78-78: +created: object(7,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 8 'run'. lines 80-80: +created: object(8,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 9 'run'. lines 82-82: +created: object(9,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 10 'view-object'. lines 84-84: +Owner: Account Address ( A ) +Version: 5 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(7,0)}}, balance: iota::balance::Balance {value: 0u64}} + +task 11 'view-object'. lines 86-86: +Owner: Shared +Version: 6 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(8,0)}}, balance: iota::balance::Balance {value: 0u64}} + +task 12 'view-object'. lines 88-90: +Owner: Shared +Version: 7 +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(9,0)}}} + +task 13 'programmable'. lines 91-95: +mutated: object(0,0), object(9,0) +deleted: object(7,0), object(8,0) +gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: 4160772, non_refundable_storage_fee: 42028 + +task 14 'run'. lines 97-97: +created: object(14,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 15 'run'. lines 99-99: +created: object(15,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 16 'run'. lines 101-101: +created: object(16,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 17 'view-object'. lines 103-103: +Owner: Shared +Version: 8 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(14,0)}}, balance: iota::balance::Balance {value: 0u64}} + +task 18 'view-object'. lines 105-105: +Owner: Shared +Version: 9 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(15,0)}}, balance: iota::balance::Balance {value: 0u64}} + +task 19 'view-object'. lines 107-109: +Owner: Shared +Version: 10 +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(16,0)}}} + +task 20 'programmable'. lines 110-112: +mutated: object(0,0), object(16,0) +deleted: object(14,0), object(15,0) +gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: 4160772, non_refundable_storage_fee: 42028 diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge.move b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge.move similarity index 78% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge.move rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge.move index 2bb778a43e3..6f487cf18da 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge.move +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses t1=0x0 t2=0x0 --accounts A --shared-object-deletion true @@ -13,17 +14,17 @@ //# publish module t2::o2 { - use sui::dynamic_field as df; - use sui::dynamic_object_field as dof; - use sui::sui::SUI; - use sui::coin::{Self, Coin}; + use iota::dynamic_field as df; + use iota::dynamic_object_field as dof; + use iota::iota::IOTA; + use iota::coin::{Self, Coin}; public struct Obj2 has key, store { id: UID, } public fun mint_shared_coin(ctx: &mut TxContext) { - transfer::public_share_object(coin::zero(ctx)) + transfer::public_share_object(coin::zero(ctx)) } public fun mint_shared_obj(ctx: &mut TxContext) { @@ -31,30 +32,30 @@ module t2::o2 { } public fun mint_owned_coin(ctx: &mut TxContext) { - transfer::public_transfer(coin::zero(ctx), @A) + transfer::public_transfer(coin::zero(ctx), @A) } - public fun deleter(o2: Coin) { + public fun deleter(o2: Coin) { coin::destroy_zero(o2); } - public fun freezer(o2: Coin) { + public fun freezer(o2: Coin) { transfer::public_freeze_object(o2); } - public fun dofer(parent: &mut Obj2, o2: Coin) { + public fun dofer(parent: &mut Obj2, o2: Coin) { dof::add(&mut parent.id, 0, o2); } - public fun dfer(parent: &mut Obj2, o2: Coin) { + public fun dfer(parent: &mut Obj2, o2: Coin) { df::add(&mut parent.id, 0, o2); } - public fun transferer(o2: Coin) { + public fun transferer(o2: Coin) { transfer::public_transfer(o2, @0x0); } - public fun sharer(o2: Coin) { + public fun sharer(o2: Coin) { transfer::public_share_object(o2); } } diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge_fails.exp b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge_fails.exp similarity index 80% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge_fails.exp rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge_fails.exp index 0dd98dbcfa7..2369d1ebef9 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge_fails.exp +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge_fails.exp @@ -26,17 +26,17 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 5 'view-object'. lines 70-70: Owner: Account Address ( A ) Version: 3 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, balance: sui::balance::Balance {value: 0u64}} +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, balance: iota::balance::Balance {value: 0u64}} task 6 'view-object'. lines 72-72: Owner: Shared Version: 4 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, balance: sui::balance::Balance {value: 0u64}} +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, balance: iota::balance::Balance {value: 0u64}} task 7 'view-object'. lines 74-76: Owner: Shared Version: 5 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(4,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(4,0)}}} task 8 'programmable'. lines 77-81: Error: Transaction Effects Status: The shared object operation is not allowed. @@ -76,17 +76,17 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 16 'view-object'. lines 109-109: Owner: Shared Version: 6 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(13,0)}}, balance: sui::balance::Balance {value: 0u64}} +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(13,0)}}, balance: iota::balance::Balance {value: 0u64}} task 17 'view-object'. lines 111-111: Owner: Shared Version: 7 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(14,0)}}, balance: sui::balance::Balance {value: 0u64}} +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(14,0)}}, balance: iota::balance::Balance {value: 0u64}} task 18 'view-object'. lines 113-115: Owner: Shared Version: 8 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(15,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(15,0)}}} task 19 'programmable'. lines 116-120: Error: Transaction Effects Status: The shared object operation is not allowed. diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge_fails.move b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge_fails.move similarity index 85% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge_fails.move rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge_fails.move index d1ae9c0dc0b..65069b5b99b 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge_fails.move +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge_fails.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses t1=0x0 t2=0x0 --accounts A --shared-object-deletion true @@ -13,17 +14,17 @@ //# publish module t2::o2 { - use sui::dynamic_field as df; - use sui::dynamic_object_field as dof; - use sui::sui::SUI; - use sui::coin::{Self, Coin}; + use iota::dynamic_field as df; + use iota::dynamic_object_field as dof; + use iota::iota::IOTA; + use iota::coin::{Self, Coin}; public struct Obj2 has key, store { id: UID, } public fun mint_shared_coin(ctx: &mut TxContext) { - transfer::public_share_object(coin::zero(ctx)) + transfer::public_share_object(coin::zero(ctx)) } public fun mint_shared_obj(ctx: &mut TxContext) { @@ -31,30 +32,30 @@ module t2::o2 { } public fun mint_owned_coin(ctx: &mut TxContext) { - transfer::public_transfer(coin::zero(ctx), @A) + transfer::public_transfer(coin::zero(ctx), @A) } - public fun deleter(o2: Coin) { + public fun deleter(o2: Coin) { coin::destroy_zero(o2); } - public fun freezer(o2: Coin) { + public fun freezer(o2: Coin) { transfer::public_freeze_object(o2); } - public fun dofer(parent: &mut Obj2, o2: Coin) { + public fun dofer(parent: &mut Obj2, o2: Coin) { dof::add(&mut parent.id, 0, o2); } - public fun dfer(parent: &mut Obj2, o2: Coin) { + public fun dfer(parent: &mut Obj2, o2: Coin) { df::add(&mut parent.id, 0, o2); } - public fun transferer(o2: Coin) { + public fun transferer(o2: Coin) { transfer::public_transfer(o2, @0x0); } - public fun sharer(o2: Coin) { + public fun sharer(o2: Coin) { transfer::public_share_object(o2); } } diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call.exp b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call.exp similarity index 81% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call.exp rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call.exp index 0b3522ad28d..1a4b5bb32ea 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call.exp +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call.exp @@ -18,12 +18,12 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 4 'view-object'. lines 41-41: Owner: Shared Version: 3 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 5 'view-object'. lines 43-45: Owner: Shared Version: 4 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}} task 6 'programmable'. lines 46-48: mutated: object(0,0), object(2,0) @@ -38,7 +38,7 @@ gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: task 8 'view-object'. lines 52-54: Owner: Shared Version: 6 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(7,0)}}, balance: sui::balance::Balance {value: 0u64}} +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(7,0)}}, balance: iota::balance::Balance {value: 0u64}} task 9 'programmable'. lines 55-61: created: object(9,0) diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call.move b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call.move similarity index 76% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call.move rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call.move index 85489c959bf..0f2b8afebbd 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call.move +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses t1=0x0 t2=0x0 --shared-object-deletion true @@ -6,15 +7,15 @@ //# publish module t2::o2 { - use sui::sui::SUI; - use sui::coin::{Self, Coin}; + use iota::iota::IOTA; + use iota::coin::{Self, Coin}; public struct Obj2 has key, store { id: UID, } public fun mint_shared_coin(ctx: &mut TxContext) { - transfer::public_share_object(coin::zero(ctx)) + transfer::public_share_object(coin::zero(ctx)) } public fun create(ctx: &mut TxContext) { @@ -29,7 +30,7 @@ module t2::o2 { public fun id(i: T): T { i } - public fun share_coin(o2: Coin) { + public fun share_coin(o2: Coin) { transfer::public_share_object(o2); } } @@ -53,14 +54,14 @@ module t2::o2 { // Reshare the shared object after making the move v //# programmable --inputs 0 object(7,0) @0x0 -//> 0: t2::o2::id>(Input(1)); +//> 0: t2::o2::id>(Input(1)); //> 1: SplitCoins(Result(0), [Input(0)]); //> 2: TransferObjects([Result(1)], Input(2)); //> 3: t2::o2::share_coin(Result(0)); // Try to call public_share_object directly -- this should work because the coin has `store`. //# programmable --inputs 0 object(7,0) @0x0 -//> 0: t2::o2::id>(Input(1)); +//> 0: t2::o2::id>(Input(1)); //> 1: SplitCoins(Result(0), [Input(0)]); //> 2: TransferObjects([Result(1)], Input(2)); -//> 3: sui::transfer::public_share_object>(Result(0)); +//> 3: iota::transfer::public_share_object>(Result(0)); diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call_fails.exp b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call_fails.exp similarity index 89% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call_fails.exp rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call_fails.exp index 8e86ab161b4..bc10b041cf5 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call_fails.exp +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call_fails.exp @@ -18,12 +18,12 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 4 'view-object'. lines 63-63: Owner: Shared Version: 3 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 5 'view-object'. lines 65-67: Owner: Shared Version: 4 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}} task 6 'programmable'. lines 68-72: Error: Transaction Effects Status: The shared object operation is not allowed. @@ -49,7 +49,7 @@ gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: task 11 'view-object'. lines 89-91: Owner: Shared Version: 9 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(10,0)}}, balance: sui::balance::Balance {value: 0u64}} +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(10,0)}}, balance: iota::balance::Balance {value: 0u64}} task 12 'programmable'. lines 92-98: Error: Transaction Effects Status: Invalid command argument at 0. Invalid usage of value. Mutably borrowed values require unique usage. Immutably borrowed values cannot be taken or borrowed mutably. Taken values cannot be used again. diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call_fails.move b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call_fails.move similarity index 81% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call_fails.move rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call_fails.move index 86eca7dce11..743e8ad16fe 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call_fails.move +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_move_call_fails.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses t1=0x0 t2=0x0 --shared-object-deletion true @@ -6,17 +7,17 @@ //# publish module t2::o2 { - use sui::dynamic_field as df; - use sui::dynamic_object_field as dof; - use sui::sui::SUI; - use sui::coin::{Self, Coin}; + use iota::dynamic_field as df; + use iota::dynamic_object_field as dof; + use iota::iota::IOTA; + use iota::coin::{Self, Coin}; public struct Obj2 has key, store { id: UID, } public fun mint_shared_coin(ctx: &mut TxContext) { - transfer::public_share_object(coin::zero(ctx)) + transfer::public_share_object(coin::zero(ctx)) } public fun create(ctx: &mut TxContext) { @@ -49,7 +50,7 @@ module t2::o2 { transfer::share_object(o2); } - public fun share_coin(o2: Coin) { + public fun share_coin(o2: Coin) { transfer::public_share_object(o2); } @@ -90,28 +91,28 @@ module t2::o2 { // Try to double-use the input //# programmable --inputs 0 object(10,0) @0x0 -//> 0: t2::o2::id>(Input(1)); +//> 0: t2::o2::id>(Input(1)); //> 1: SplitCoins(Result(0), [Input(0)]); //> 2: TransferObjects([Result(1)], Input(2)); -//> 3: sui::transfer::public_share_object>(Input(1)); +//> 3: iota::transfer::public_share_object>(Input(1)); // Try to double-use the input using a user-defined function //# programmable --inputs 0 object(10,0) @0x0 -//> 0: t2::o2::id>(Input(1)); +//> 0: t2::o2::id>(Input(1)); //> 1: SplitCoins(Result(0), [Input(0)]); //> 2: TransferObjects([Result(1)], Input(2)); //> 3: t2::o2::share_coin(Input(1)); // Try to transfer the shared object and double-use the input //# programmable --inputs 0 object(10,0) @0x0 -//> 0: t2::o2::id>(Input(1)); +//> 0: t2::o2::id>(Input(1)); //> 1: SplitCoins(Result(0), [Input(0)]); //> 2: TransferObjects([Result(1)], Input(2)); //> 3: TransferObjects([Input(1)], Input(2)); // Try to transfer the shared object //# programmable --inputs 0 object(10,0) @0x0 -//> 0: t2::o2::id>(Input(1)); +//> 0: t2::o2::id>(Input(1)); //> 1: SplitCoins(Result(0), [Input(0)]); //> 2: TransferObjects([Result(1)], Input(2)); //> 3: TransferObjects([Result(0)], Input(2)); diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_v20.exp b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_v20.exp similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_v20.exp rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_v20.exp index f9bee46463a..add60dee0c5 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_v20.exp +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_v20.exp @@ -18,7 +18,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 4 'view-object'. lines 39-39: Owner: Shared Version: 4 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}} task 5 'run'. lines 41-41: Error: Transaction Effects Status: Invalid command argument at 0. Immutable objects cannot be passed by-value. diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_v20.move b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_v20.move similarity index 94% rename from crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_v20.move rename to crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_v20.move index ca07c72cf9b..e886208aab7 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_v20.move +++ b/crates/iota-adapter-transactional-tests/tests/shared/by_value_shared_object_v20.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests that shared objects can diff --git a/crates/sui-adapter-transactional-tests/tests/shared/freeze.exp b/crates/iota-adapter-transactional-tests/tests/shared/freeze.exp similarity index 87% rename from crates/sui-adapter-transactional-tests/tests/shared/freeze.exp rename to crates/iota-adapter-transactional-tests/tests/shared/freeze.exp index 42d7a5d389e..a82dadf2666 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/freeze.exp +++ b/crates/iota-adapter-transactional-tests/tests/shared/freeze.exp @@ -13,7 +13,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 3 'view-object'. lines 29-29: Owner: Shared Version: 3 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'run'. lines 31-31: Error: Transaction Effects Status: The shared object operation is not allowed. diff --git a/crates/iota-adapter-transactional-tests/tests/shared/freeze.move b/crates/iota-adapter-transactional-tests/tests/shared/freeze.move new file mode 100644 index 00000000000..8e000003922 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/shared/freeze.move @@ -0,0 +1,32 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests that shared objects cannot be freezed + +//# init --addresses t1=0x0 t2=0x0 --shared-object-deletion true + +//# publish + + +module t2::o2 { + public struct Obj2 has key, store { + id: UID, + } + + public entry fun create(ctx: &mut TxContext) { + let o = Obj2 { id: object::new(ctx) }; + transfer::public_share_object(o) + } + + public entry fun freeze_o2(o2: Obj2) { + transfer::freeze_object(o2); + } + +} + +//# run t2::o2::create + +//# view-object 2,0 + +//# run t2::o2::freeze_o2 --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/shared/re_share.exp b/crates/iota-adapter-transactional-tests/tests/shared/re_share.exp similarity index 90% rename from crates/sui-adapter-transactional-tests/tests/shared/re_share.exp rename to crates/iota-adapter-transactional-tests/tests/shared/re_share.exp index 7e80b2718c6..5fef1a5a7f9 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/re_share.exp +++ b/crates/iota-adapter-transactional-tests/tests/shared/re_share.exp @@ -13,7 +13,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 3 'view-object'. lines 31-31: Owner: Shared Version: 3 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'run'. lines 33-33: mutated: object(0,0), object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/shared/re_share.move b/crates/iota-adapter-transactional-tests/tests/shared/re_share.move similarity index 94% rename from crates/sui-adapter-transactional-tests/tests/shared/re_share.move rename to crates/iota-adapter-transactional-tests/tests/shared/re_share.move index d3f92cb2806..6b231cd7797 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/re_share.move +++ b/crates/iota-adapter-transactional-tests/tests/shared/re_share.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests that shared objects can be re-shared as shared objects diff --git a/crates/sui-adapter-transactional-tests/tests/shared/transfer.exp b/crates/iota-adapter-transactional-tests/tests/shared/transfer.exp similarity index 87% rename from crates/sui-adapter-transactional-tests/tests/shared/transfer.exp rename to crates/iota-adapter-transactional-tests/tests/shared/transfer.exp index b88741ca685..a0652951057 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/transfer.exp +++ b/crates/iota-adapter-transactional-tests/tests/shared/transfer.exp @@ -13,7 +13,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 3 'view-object'. lines 28-28: Owner: Shared Version: 3 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'run'. lines 30-30: Error: Transaction Effects Status: The shared object operation is not allowed. diff --git a/crates/iota-adapter-transactional-tests/tests/shared/transfer.move b/crates/iota-adapter-transactional-tests/tests/shared/transfer.move new file mode 100644 index 00000000000..8dc0b21698c --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/shared/transfer.move @@ -0,0 +1,31 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests that shared objects cannot be transfered in a way that will result +// in their ownership no longer being shared + +//# init --addresses t1=0x0 t2=0x0 --shared-object-deletion true + +//# publish + +module t2::o2 { + public struct Obj2 has key, store { + id: UID, + } + + public entry fun create(ctx: &mut TxContext) { + let o = Obj2 { id: object::new(ctx) }; + transfer::public_share_object(o) + } + + public entry fun transfer_to_single_owner(o2: Obj2, ctx: &mut TxContext) { + transfer::transfer(o2, tx_context::sender(ctx)) + } +} + +//# run t2::o2::create + +//# view-object 2,0 + +//# run t2::o2::transfer_to_single_owner --args object(2,0) diff --git a/crates/iota-adapter-transactional-tests/tests/shared/upgrade.exp b/crates/iota-adapter-transactional-tests/tests/shared/upgrade.exp new file mode 100644 index 00000000000..b473fc54ffa --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/shared/upgrade.exp @@ -0,0 +1,31 @@ +processed 7 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 8-36: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 7440400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 38-38: +created: object(2,0), object(2,1), object(2,2), object(2,3) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 7835600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'view-object'. lines 40-40: +Owner: Account Address ( A ) +Version: 2 +Contents: t::m::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,2)}}} + +task 4 'run'. lines 42-42: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::share_object_impl (function index 10) at offset 0, Abort Code: 0 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 10, instruction: 0, function_name: Some("share_object_impl") }, 0), source: Some(VMError { major_status: ABORTED, sub_status: Some(0), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(10), 0)] }), command: Some(0) } } + +task 5 'run'. lines 44-44: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::share_object_impl (function index 10) at offset 0, Abort Code: 0 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 10, instruction: 0, function_name: Some("share_object_impl") }, 0), source: Some(VMError { major_status: ABORTED, sub_status: Some(0), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(10), 0)] }), command: Some(0) } } + +task 6 'run'. lines 46-46: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::transfer::share_object_impl (function index 10) at offset 0, Abort Code: 0 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("transfer") }, function: 10, instruction: 0, function_name: Some("share_object_impl") }, 0), source: Some(VMError { major_status: ABORTED, sub_status: Some(0), message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(10), 0)] }), command: Some(0) } } diff --git a/crates/iota-adapter-transactional-tests/tests/shared/upgrade.move b/crates/iota-adapter-transactional-tests/tests/shared/upgrade.move new file mode 100644 index 00000000000..6765d25f206 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/shared/upgrade.move @@ -0,0 +1,47 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests that shared objects must be newly created + +//# init --addresses t=0x0 --accounts A + +//# publish + +module t::m { + public struct Obj has key, store { + id: UID, + } + + public entry fun create(ctx: &mut TxContext) { + let mut o = Obj { id: object::new(ctx) }; + iota::dynamic_field::add(&mut o.id, 0, Obj { id: object::new(ctx) }); + iota::dynamic_object_field::add(&mut o.id, 0, Obj { id: object::new(ctx) }); + transfer::public_transfer(o, ctx.sender()) + } + + public entry fun share(o: Obj) { + transfer::public_share_object(o) + } + + public entry fun share_wrapped(o: &mut Obj) { + let inner: Obj = iota::dynamic_field::remove(&mut o.id, 0); + transfer::public_share_object(inner) + } + + public entry fun share_child(o: &mut Obj) { + let inner: Obj = iota::dynamic_object_field::remove(&mut o.id, 0); + transfer::public_share_object(inner) + } + +} + +//# run t::m::create --sender A + +//# view-object 2,2 + +//# run t::m::share --args object(2,2) --sender A + +//# run t::m::share_wrapped --args object(2,2) --sender A + +//# run t::m::share_child --args object(2,2) --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/shared/wrap.exp b/crates/iota-adapter-transactional-tests/tests/shared/wrap.exp similarity index 87% rename from crates/sui-adapter-transactional-tests/tests/shared/wrap.exp rename to crates/iota-adapter-transactional-tests/tests/shared/wrap.exp index 2c78bfc9827..f1a63b9cbd7 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/wrap.exp +++ b/crates/iota-adapter-transactional-tests/tests/shared/wrap.exp @@ -13,7 +13,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: task 3 'view-object'. lines 32-32: Owner: Shared Version: 3 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: t2::o2::Obj2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'run'. lines 34-34: Error: Transaction Effects Status: The shared object operation is not allowed. diff --git a/crates/sui-adapter-transactional-tests/tests/shared/wrap.move b/crates/iota-adapter-transactional-tests/tests/shared/wrap.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/shared/wrap.move rename to crates/iota-adapter-transactional-tests/tests/shared/wrap.move index 8c180a81014..6c751488560 100644 --- a/crates/sui-adapter-transactional-tests/tests/shared/wrap.move +++ b/crates/iota-adapter-transactional-tests/tests/shared/wrap.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests that shared objects cannot be wrapped diff --git a/crates/iota-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.exp b/crates/iota-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.exp new file mode 100644 index 00000000000..fc0956a4b6a --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.exp @@ -0,0 +1,26 @@ +processed 7 tasks + +task 1 'publish'. lines 8-32: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5259200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 33-35: +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'run'. lines 36-38: +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 4 'run'. lines 39-41: +mutated: object(0,0) +gas summary: computation_cost: 5000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 5 'run'. lines 42-44: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } + +task 6 'run'. lines 45-45: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.move b/crates/iota-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.move rename to crates/iota-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.move index 826b7927933..f2584d67001 100644 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.move +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Test limits on number of deleted IDs diff --git a/crates/iota-adapter-transactional-tests/tests/size_limits/event_limits_tests.exp b/crates/iota-adapter-transactional-tests/tests/size_limits/event_limits_tests.exp new file mode 100644 index 00000000000..f3ccb0ab882 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/event_limits_tests.exp @@ -0,0 +1,42 @@ +processed 10 tasks + +task 1 'publish'. lines 8-55: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 7311200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 56-58: +events: 1 +mutated: 1 +gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'run'. lines 59-61: +events: 50 +mutated: 1 +gas summary: computation_cost: 3000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 4 'run'. lines 62-64: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::event::emit (function index 0) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("event") }, function: 0, instruction: 0, function_name: Some("emit") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(0), message: Some("Emitting more than 1024 events is not allowed"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("event") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 0)] }), command: Some(0) } } + +task 5 'run'. lines 65-67: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::event::emit (function index 0) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("event") }, function: 0, instruction: 0, function_name: Some("emit") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(0), message: Some("Emitting more than 1024 events is not allowed"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("event") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 0)] }), command: Some(0) } } + +task 6 'run'. lines 68-70: +events: 1 +mutated: 1 +gas summary: computation_cost: 1393000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 7 'run'. lines 71-73: +events: 1 +mutated: 1 +gas summary: computation_cost: 1814000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 8 'run'. lines 74-76: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::event::emit (function index 0) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("event") }, function: 0, instruction: 0, function_name: Some("emit") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(1), message: Some("Emitting event of size 256001 bytes. Limit is 256000 bytes."), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("event") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 0)] }), command: Some(0) } } + +task 9 'run'. lines 77-77: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::event::emit (function index 0) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("event") }, function: 0, instruction: 0, function_name: Some("emit") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(1), message: Some("Emitting event of size 259000 bytes. Limit is 256000 bytes."), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("event") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/event_limits_tests.move b/crates/iota-adapter-transactional-tests/tests/size_limits/event_limits_tests.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/size_limits/event_limits_tests.move rename to crates/iota-adapter-transactional-tests/tests/size_limits/event_limits_tests.move index 920b656fb79..c8c8097b582 100644 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/event_limits_tests.move +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/event_limits_tests.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Test limits on number and sizes of emitted events @@ -9,8 +10,8 @@ /// Test event limits enforced module Test::M1 { - use sui::event; - use sui::bcs; + use iota::event; + use iota::bcs; public struct NewValueEvent has copy, drop { contents: vector diff --git a/crates/iota-adapter-transactional-tests/tests/size_limits/event_limits_tests_out_of_gas.exp b/crates/iota-adapter-transactional-tests/tests/size_limits/event_limits_tests_out_of_gas.exp new file mode 100644 index 00000000000..395d4de49ea --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/event_limits_tests_out_of_gas.exp @@ -0,0 +1,22 @@ +processed 6 tasks + +task 1 'publish'. lines 8-66: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 7919200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 67-69: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::event::emit (function index 0) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("event") }, function: 0, instruction: 0, function_name: Some("emit") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(0), message: Some("Emitting more than 1024 events is not allowed"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("event") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 0)] }), command: Some(0) } } + +task 3 'run'. lines 70-72: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::event::emit (function index 0) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("event") }, function: 0, instruction: 0, function_name: Some("emit") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(0), message: Some("Emitting more than 1024 events is not allowed"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("event") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 0)] }), command: Some(0) } } + +task 4 'run'. lines 73-75: +Error: Transaction Effects Status: Insufficient Gas. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: InsufficientGas, source: Some(VMError { major_status: OUT_OF_GAS, sub_status: None, message: None, exec_state: None, location: Module(ModuleId { address: Test, name: Identifier("M1") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 27)] }), command: Some(0) } } + +task 5 'run'. lines 76-76: +Error: Transaction Effects Status: Insufficient Gas. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: InsufficientGas, source: Some(VMError { major_status: OUT_OF_GAS, sub_status: None, message: None, exec_state: None, location: Module(ModuleId { address: Test, name: Identifier("M1") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 33)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/event_limits_tests_out_of_gas.move b/crates/iota-adapter-transactional-tests/tests/size_limits/event_limits_tests_out_of_gas.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/size_limits/event_limits_tests_out_of_gas.move rename to crates/iota-adapter-transactional-tests/tests/size_limits/event_limits_tests_out_of_gas.move index e4ecfee4696..c0067b8874a 100644 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/event_limits_tests_out_of_gas.move +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/event_limits_tests_out_of_gas.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Test limits on number and sizes of emitted events @@ -9,8 +10,8 @@ /// Test event limits enforced module Test::M1 { - use sui::event; - use sui::bcs; + use iota::event; + use iota::bcs; public struct NewValueEvent has copy, drop { contents: vector diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/identitifer_len_limits.exp b/crates/iota-adapter-transactional-tests/tests/size_limits/identitifer_len_limits.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/size_limits/identitifer_len_limits.exp rename to crates/iota-adapter-transactional-tests/tests/size_limits/identitifer_len_limits.exp diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/identitifer_len_limits.move b/crates/iota-adapter-transactional-tests/tests/size_limits/identitifer_len_limits.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/size_limits/identitifer_len_limits.move rename to crates/iota-adapter-transactional-tests/tests/size_limits/identitifer_len_limits.move index 07c21aee5a3..490f914f0b6 100644 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/identitifer_len_limits.move +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/identitifer_len_limits.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Test Identifer length limits diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/move_object_size_limit.exp b/crates/iota-adapter-transactional-tests/tests/size_limits/move_object_size_limit.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/size_limits/move_object_size_limit.exp rename to crates/iota-adapter-transactional-tests/tests/size_limits/move_object_size_limit.exp diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/move_object_size_limit.move b/crates/iota-adapter-transactional-tests/tests/size_limits/move_object_size_limit.move similarity index 97% rename from crates/sui-adapter-transactional-tests/tests/size_limits/move_object_size_limit.move rename to crates/iota-adapter-transactional-tests/tests/size_limits/move_object_size_limit.move index fac5b12a589..7eee330ad69 100644 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/move_object_size_limit.move +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/move_object_size_limit.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Test creating objects just below the size limit, and above it @@ -8,7 +9,7 @@ //# publish module Test::M1 { - use sui::bcs; + use iota::bcs; public struct S has key, store { id: UID, diff --git a/crates/iota-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.exp b/crates/iota-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.exp new file mode 100644 index 00000000000..2fec959222b --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.exp @@ -0,0 +1,26 @@ +processed 7 tasks + +task 1 'publish'. lines 8-33: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5259200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 34-36: +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'run'. lines 37-39: +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 4 'run'. lines 40-42: +mutated: object(0,0) +gas summary: computation_cost: 5000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 5 'run'. lines 43-45: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } + +task 6 'run'. lines 46-46: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.move b/crates/iota-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.move rename to crates/iota-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.move index 0d4150d4939..6c0c64792dd 100644 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.move +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Test limits on number of created IDs diff --git a/crates/iota-adapter-transactional-tests/tests/size_limits/object_runtime_limits.exp b/crates/iota-adapter-transactional-tests/tests/size_limits/object_runtime_limits.exp new file mode 100644 index 00000000000..4f82093ca93 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/object_runtime_limits.exp @@ -0,0 +1,27 @@ +processed 6 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 7-26: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 5821600, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 28-28: +created: 200 +mutated: 1 +gas summary: computation_cost: 1000000, storage_cost: 270028000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'run'. lines 30-30: +created: 2000 +mutated: 1 +gas summary: computation_cost: 7000000, storage_cost: 2691388000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 4 'run'. lines 32-32: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::dynamic_field::has_child_object (function index 14) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 14, instruction: 0, function_name: Some("has_child_object") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(5), message: Some("Object runtime cached objects limit (1000 entries) reached"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(14), 0)] }), command: Some(0) } } + +task 5 'run'. lines 34-34: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::dynamic_field::has_child_object (function index 14) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("dynamic_field") }, function: 14, instruction: 0, function_name: Some("has_child_object") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(5), message: Some("Object runtime cached objects limit (1000 entries) reached"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(14), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/object_runtime_limits.move b/crates/iota-adapter-transactional-tests/tests/size_limits/object_runtime_limits.move similarity index 84% rename from crates/sui-adapter-transactional-tests/tests/size_limits/object_runtime_limits.move rename to crates/iota-adapter-transactional-tests/tests/size_limits/object_runtime_limits.move index 5fddb9557eb..4904259495a 100644 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/object_runtime_limits.move +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/object_runtime_limits.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 @@ -7,7 +8,7 @@ //# publish module a::m { - use sui::dynamic_field::add; + use iota::dynamic_field::add; public struct Obj has key { id: object::UID, @@ -18,7 +19,7 @@ module a::m { while (i < n) { let mut id = object::new(ctx); add(&mut id, i, i); - sui::transfer::transfer(Obj { id }, ctx.sender()); + iota::transfer::transfer(Obj { id }, ctx.sender()); i = i + 1; }; diff --git a/crates/iota-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.exp b/crates/iota-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.exp new file mode 100644 index 00000000000..798a4de1300 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.exp @@ -0,0 +1,37 @@ +processed 9 tasks + +task 1 'publish'. lines 8-32: +created: object(1,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5578400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 33-35: +created: 1 +mutated: 1 +gas summary: computation_cost: 1000000, storage_cost: 2219200, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'run'. lines 36-38: +created: 256 +mutated: 1 +gas summary: computation_cost: 1000000, storage_cost: 316175200, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 4 'run'. lines 39-41: +created: 2048 +mutated: 1 +gas summary: computation_cost: 4000000, storage_cost: 2522485600, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 5 'run'. lines 42-44: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } + +task 6 'run'. lines 45-47: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } + +task 7 'run'. lines 48-50: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } + +task 8 'run'. lines 51-51: +Error: Transaction Effects Status: Move Primitive Runtime Error. Location: iota::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: iota, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.move b/crates/iota-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.move similarity index 97% rename from crates/sui-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.move rename to crates/iota-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.move index 89d8f6db392..51bacdabaa6 100644 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.move +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Test limits on number of transferd IDs diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/vector_len_limits.exp b/crates/iota-adapter-transactional-tests/tests/size_limits/vector_len_limits.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/size_limits/vector_len_limits.exp rename to crates/iota-adapter-transactional-tests/tests/size_limits/vector_len_limits.exp diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/vector_len_limits.move b/crates/iota-adapter-transactional-tests/tests/size_limits/vector_len_limits.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/size_limits/vector_len_limits.move rename to crates/iota-adapter-transactional-tests/tests/size_limits/vector_len_limits.move index cbc817ee848..1842cff17b4 100644 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/vector_len_limits.move +++ b/crates/iota-adapter-transactional-tests/tests/size_limits/vector_len_limits.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Test limits on length of vectors diff --git a/crates/iota-adapter-transactional-tests/tests/tests.rs b/crates/iota-adapter-transactional-tests/tests/tests.rs new file mode 100644 index 00000000000..23f2350a3fd --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/tests.rs @@ -0,0 +1,8 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub const TEST_DIR: &str = "tests"; +use iota_transactional_test_runner::run_test; + +datatest_stable::harness!(run_test, TEST_DIR, r".*\.(mvir|move)$"); diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store.exp b/crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store.exp similarity index 79% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store.exp rename to crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store.exp index 838ba794e60..0a904885a94 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store.exp +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: task 3 'view-object'. lines 29-29: Owner: Account Address ( A ) Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'transfer-object'. lines 31-31: Error: Transaction Effects Status: Invalid Transfer Object, object does not have public transfer. @@ -25,7 +25,7 @@ Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { k task 5 'view-object'. lines 33-36: Owner: Account Address ( A ) Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 6 'run'. lines 38-38: created: object(6,0) @@ -35,7 +35,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2500400, storage_rebate: task 7 'view-object'. lines 40-40: Owner: Account Address ( A ) Version: 4 -Contents: test::m::Cup {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}} +Contents: test::m::Cup {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}} task 8 'transfer-object'. lines 42-42: Error: Transaction Effects Status: Invalid Transfer Object, object does not have public transfer. @@ -44,4 +44,4 @@ Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { k task 9 'view-object'. lines 44-44: Owner: Account Address ( A ) Version: 5 -Contents: test::m::Cup {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}} +Contents: test::m::Cup {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store.move b/crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store.move rename to crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store.move index fb412afe867..39cb0e67b7f 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store.move +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests TransferObject should fail for an object _without_ public transfer diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive.exp b/crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive.exp similarity index 75% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive.exp rename to crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive.exp index 2d6ec38ead2..8af8d5db6d7 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive.exp +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive.exp @@ -16,12 +16,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3442800, storage_rebate: task 3 'view-object'. lines 81-81: Owner: Account Address ( A ) Version: 2 -Contents: test::m::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 83-83: Owner: Account Address ( fake(2,0) ) Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'programmable'. lines 85-87: mutated: object(0,0), object(2,0) @@ -36,12 +36,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3465600, storage_rebate: task 7 'view-object'. lines 91-91: Owner: Account Address ( fake(6,1) ) Version: 4 -Contents: test::m::Cup {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}} +Contents: test::m::Cup {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}} task 8 'view-object'. lines 93-93: Owner: Account Address ( A ) Version: 4 -Contents: test::m::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,1)}}} +Contents: test::m::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,1)}}} task 9 'programmable'. lines 95-99: mutated: object(0,0), object(6,1) @@ -56,20 +56,20 @@ gas summary: computation_cost: 1000000, storage_cost: 3442800, storage_rebate: task 11 'view-object'. lines 103-103: Owner: Account Address ( A ) Version: 6 -Contents: test::m::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(10,0)}}} +Contents: test::m::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(10,0)}}} task 12 'view-object'. lines 105-105: Owner: Account Address ( fake(10,0) ) Version: 6 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(10,1)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(10,1)}}} task 13 'programmable'. lines 107-109: Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: CONSTRAINT_NOT_SATISFIED, sub_status: None, message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [] }), command: Some(1) } } +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: CONSTRAINT_NOT_SATISFIED, sub_status: None, message: None, exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("transfer") }), indices: [], offsets: [] }), command: Some(1) } } task 14 'programmable'. lines 111-117: Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call sui::transfer::receive. Use the public variant instead, sui::transfer::public_receive"), command: Some(1) } } +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call iota::transfer::receive. Use the public variant instead, iota::transfer::public_receive"), command: Some(1) } } task 15 'run'. lines 119-119: created: object(15,0), object(15,1) @@ -79,16 +79,16 @@ gas summary: computation_cost: 1000000, storage_cost: 3473200, storage_rebate: task 16 'view-object'. lines 121-121: Owner: Account Address ( A ) Version: 9 -Contents: test::m::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(15,0)}}} +Contents: test::m::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(15,0)}}} task 17 'view-object'. lines 123-123: Owner: Account Address ( fake(15,0) ) Version: 9 -Contents: test::m::Store {id: sui::object::UID {id: sui::object::ID {bytes: fake(15,1)}}} +Contents: test::m::Store {id: iota::object::UID {id: iota::object::ID {bytes: fake(15,1)}}} task 18 'programmable'. lines 125-129: Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call sui::transfer::receive. Use the public variant instead, sui::transfer::public_receive"), command: Some(1) } } +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call iota::transfer::receive. Use the public variant instead, iota::transfer::public_receive"), command: Some(1) } } task 19 'programmable'. lines 130-134: mutated: object(0,0) diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive.move b/crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive.move similarity index 89% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive.move rename to crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive.move index 36da0567a10..9e9326a3e60 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive.move +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Tests `public_receive` should fail for an object _without_ public transfer, @@ -8,7 +9,7 @@ //# publish module test::m { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct Parent has key { id: UID } public struct S has key { id: UID } @@ -106,11 +107,11 @@ module test::m { //# programmable --sender A --inputs object(10,0) receiving(10,1) //> 0: test::m::parent_uid(Input(0)); -//> 1: sui::transfer::public_receive(Result(0), Input(1)); +//> 1: iota::transfer::public_receive(Result(0), Input(1)); //# programmable --sender A --inputs object(10,0) receiving(10,1) //> 0: test::m::parent_uid(Input(0)); -//> 1: sui::transfer::receive(Result(0), Input(1)); +//> 1: iota::transfer::receive(Result(0), Input(1)); // Now publish one with store. We should: // 1. Not be able to call `receive` to receive it. @@ -124,11 +125,11 @@ module test::m { //# programmable --sender A --inputs object(15,0) receiving(15,1) //> 0: test::m::parent_uid(Input(0)); -//> 1: sui::transfer::receive(Result(0), Input(1)); +//> 1: iota::transfer::receive(Result(0), Input(1)); // Can receive it via a direct `public_receive` call since `Store` has the `store` ability. //# programmable --sender A --inputs object(15,0) receiving(15,1) //> 0: test::m::parent_uid(Input(0)); -//> 1: sui::transfer::public_receive(Result(0), Input(1)); +//> 1: iota::transfer::public_receive(Result(0), Input(1)); //> 2: test::m::destroy_store(Result(1)); -//> 3: sui::object::delete(Result(0)); +//> 3: iota::object::delete(Result(0)); diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive_version30.exp b/crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive_version30.exp similarity index 77% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive_version30.exp rename to crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive_version30.exp index fd7aea8186f..5f0f7831895 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive_version30.exp +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive_version30.exp @@ -16,12 +16,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3442800, storage_rebate: task 3 'view-object'. lines 81-81: Owner: Account Address ( A ) Version: 2 -Contents: test::m::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'view-object'. lines 83-83: Owner: Account Address ( fake(2,0) ) Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 5 'programmable'. lines 85-87: mutated: object(0,0), object(2,0) @@ -36,12 +36,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3465600, storage_rebate: task 7 'view-object'. lines 91-91: Owner: Account Address ( fake(6,1) ) Version: 4 -Contents: test::m::Cup {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}} +Contents: test::m::Cup {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}} task 8 'view-object'. lines 93-93: Owner: Account Address ( A ) Version: 4 -Contents: test::m::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,1)}}} +Contents: test::m::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,1)}}} task 9 'programmable'. lines 95-99: mutated: object(0,0), object(6,1) @@ -56,12 +56,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3442800, storage_rebate: task 11 'view-object'. lines 103-103: Owner: Account Address ( A ) Version: 6 -Contents: test::m::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(10,0)}}} +Contents: test::m::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(10,0)}}} task 12 'view-object'. lines 105-105: Owner: Account Address ( fake(10,0) ) Version: 6 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(10,1)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(10,1)}}} task 13 'programmable'. lines 107-113: mutated: object(0,0) @@ -76,12 +76,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3473200, storage_rebate: task 15 'view-object'. lines 117-117: Owner: Account Address ( A ) Version: 8 -Contents: test::m::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(14,0)}}} +Contents: test::m::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(14,0)}}} task 16 'view-object'. lines 119-119: Owner: Account Address ( fake(14,0) ) Version: 8 -Contents: test::m::Store {id: sui::object::UID {id: sui::object::ID {bytes: fake(14,1)}}} +Contents: test::m::Store {id: iota::object::UID {id: iota::object::ID {bytes: fake(14,1)}}} task 17 'programmable'. lines 121-125: mutated: object(0,0) diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive_version30.move b/crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive_version30.move similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive_version30.move rename to crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive_version30.move index 09d56f6bdca..8b98d77a354 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive_version30.move +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/does_not_have_store_receive_version30.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Tests `public_receive` should fail for an object _without_ public transfer, @@ -8,7 +9,7 @@ //# publish module test::m { - use sui::transfer::Receiving; + use iota::transfer::Receiving; public struct Parent has key { id: UID } public struct S has key { id: UID } @@ -106,9 +107,9 @@ module test::m { //# programmable --sender A --inputs object(10,0) receiving(10,1) //> 0: test::m::parent_uid(Input(0)); -//> 1: sui::transfer::receive(Result(0), Input(1)); +//> 1: iota::transfer::receive(Result(0), Input(1)); //> 2: test::m::destroy_s(Result(1)); -//> 3: sui::object::delete(Result(0)); +//> 3: iota::object::delete(Result(0)); // Now publish one with store. We should still be able to call `receive` to receive it. @@ -120,6 +121,6 @@ module test::m { //# programmable --sender A --inputs object(14,0) receiving(14,1) //> 0: test::m::parent_uid(Input(0)); -//> 1: sui::transfer::receive(Result(0), Input(1)); +//> 1: iota::transfer::receive(Result(0), Input(1)); //> 2: test::m::destroy_store(Result(1)); -//> 3: sui::object::delete(Result(0)); +//> 3: iota::object::delete(Result(0)); diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/has_store.exp b/crates/iota-adapter-transactional-tests/tests/transfer_object/has_store.exp similarity index 77% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/has_store.exp rename to crates/iota-adapter-transactional-tests/tests/transfer_object/has_store.exp index 3196780c821..2cf377cfdbb 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/has_store.exp +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/has_store.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: task 3 'view-object'. lines 29-29: Owner: Account Address ( A ) Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'transfer-object'. lines 31-31: mutated: object(0,0), object(2,0) @@ -25,7 +25,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: task 5 'view-object'. lines 33-36: Owner: Account Address ( B ) Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 6 'run'. lines 38-38: created: object(6,0) @@ -35,7 +35,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2500400, storage_rebate: task 7 'view-object'. lines 40-40: Owner: Account Address ( A ) Version: 4 -Contents: test::m::Cup {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}} +Contents: test::m::Cup {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}} task 8 'transfer-object'. lines 42-42: mutated: object(0,0), object(6,0) @@ -44,4 +44,4 @@ gas summary: computation_cost: 1000000, storage_cost: 2500400, storage_rebate: task 9 'view-object'. lines 44-44: Owner: Account Address ( B ) Version: 5 -Contents: test::m::Cup {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}} +Contents: test::m::Cup {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/has_store.move b/crates/iota-adapter-transactional-tests/tests/transfer_object/has_store.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/has_store.move rename to crates/iota-adapter-transactional-tests/tests/transfer_object/has_store.move index fe9fa042094..6d7cd90a352 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/has_store.move +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/has_store.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests TransferObject with an object with public transfer diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/immutable.exp b/crates/iota-adapter-transactional-tests/tests/transfer_object/immutable.exp similarity index 83% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/immutable.exp rename to crates/iota-adapter-transactional-tests/tests/transfer_object/immutable.exp index 303b3fd9ce8..a6462905343 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/immutable.exp +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/immutable.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: task 3 'view-object'. lines 23-23: Owner: Immutable Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'transfer-object'. lines 25-25: Error: Transaction Effects Status: Invalid command argument at 0. Immutable objects cannot be passed by-value. @@ -25,4 +25,4 @@ Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { k task 5 'view-object'. lines 27-27: Owner: Immutable Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/immutable.move b/crates/iota-adapter-transactional-tests/tests/transfer_object/immutable.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/immutable.move rename to crates/iota-adapter-transactional-tests/tests/transfer_object/immutable.move index aa7fbe18049..4f6a125c1fa 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/immutable.move +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/immutable.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests TransferObject should fail for an immutable object diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/immutable_v20.exp b/crates/iota-adapter-transactional-tests/tests/transfer_object/immutable_v20.exp similarity index 83% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/immutable_v20.exp rename to crates/iota-adapter-transactional-tests/tests/transfer_object/immutable_v20.exp index 39b6227aede..c21863ea01b 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/immutable_v20.exp +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/immutable_v20.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: task 3 'view-object'. lines 22-22: Owner: Immutable Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'transfer-object'. lines 24-24: Error: Transaction Effects Status: Invalid command argument at 0. Immutable objects cannot be passed by-value. @@ -25,4 +25,4 @@ Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { k task 5 'view-object'. lines 26-26: Owner: Immutable Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/immutable_v20.move b/crates/iota-adapter-transactional-tests/tests/transfer_object/immutable_v20.move similarity index 92% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/immutable_v20.move rename to crates/iota-adapter-transactional-tests/tests/transfer_object/immutable_v20.move index 4415a8a75b0..0d4d6fa52a6 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/immutable_v20.move +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/immutable_v20.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests TransferObject should fail for an immutable object diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/package.exp b/crates/iota-adapter-transactional-tests/tests/transfer_object/package.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/package.exp rename to crates/iota-adapter-transactional-tests/tests/transfer_object/package.exp diff --git a/crates/iota-adapter-transactional-tests/tests/transfer_object/package.move b/crates/iota-adapter-transactional-tests/tests/transfer_object/package.move new file mode 100644 index 00000000000..b4156c69f0d --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/package.move @@ -0,0 +1,18 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests TransferObject should fail for a package + +//# init --accounts A B --addresses test=0x0 + +//# publish --sender A + +module test::m {} + + +//# view-object 1,0 + +//# transfer-object 1,0 --sender A --recipient B + +//# view-object 1,0 diff --git a/crates/iota-adapter-transactional-tests/tests/transfer_object/quasi_shared.exp b/crates/iota-adapter-transactional-tests/tests/transfer_object/quasi_shared.exp new file mode 100644 index 00000000000..acabddc765e --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/quasi_shared.exp @@ -0,0 +1,32 @@ +processed 7 tasks + +init: +A: object(0,0), B: object(0,1) + +task 1 'publish'. lines 8-23: +created: object(1,0) +mutated: object(0,2) +gas summary: computation_cost: 1000000, storage_cost: 6148400, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 25-25: +created: object(2,0) +mutated: object(0,2) +gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'run'. lines 27-27: +created: object(3,0), object(3,1) +mutated: object(0,2), object(2,0) +gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: 2174436, non_refundable_storage_fee: 21964 + +task 4 'view-object'. lines 29-29: +Owner: Object ID: ( fake(2,0) ) +Version: 4 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(3,1)}} + +task 5 'transfer-object'. lines 31-31: +Error: Error checking transaction input objects: InvalidChildObjectArgument { child_id: object(3,0), parent_id: object(2,0) } + +task 6 'view-object'. lines 33-33: +Owner: Object ID: ( fake(2,0) ) +Version: 4 +Contents: iota::dynamic_field::Field, iota::object::ID> {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, name: iota::dynamic_object_field::Wrapper {name: 0u64}, value: iota::object::ID {bytes: fake(3,1)}} diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/quasi_shared.move b/crates/iota-adapter-transactional-tests/tests/transfer_object/quasi_shared.move similarity index 85% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/quasi_shared.move rename to crates/iota-adapter-transactional-tests/tests/transfer_object/quasi_shared.move index 298a464d5f4..aab05d2b9b0 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/quasi_shared.move +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/quasi_shared.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests TransferObject should fail for a quasi-shared object @@ -18,7 +19,7 @@ module test::m { public entry fun mint_child(s: &mut S, ctx: &mut TxContext) { let id = object::new(ctx); - sui::dynamic_object_field::add(&mut s.id, 0, Child { id }); + iota::dynamic_object_field::add(&mut s.id, 0, Child { id }); } } diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/shared.exp b/crates/iota-adapter-transactional-tests/tests/transfer_object/shared.exp similarity index 78% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/shared.exp rename to crates/iota-adapter-transactional-tests/tests/transfer_object/shared.exp index d804e78fc33..e61d7641302 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/shared.exp +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/shared.exp @@ -21,12 +21,12 @@ gas summary: computation_cost: 1000000, storage_cost: 2204000, storage_rebate: task 4 'view-object'. lines 31-31: Owner: Shared Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 5 'view-object'. lines 33-33: Owner: Shared Version: 4 -Contents: test::m::S2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}} +Contents: test::m::S2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}} task 6 'transfer-object'. lines 35-35: Error: Transaction Effects Status: Invalid Transfer Object, object does not have public transfer. @@ -39,9 +39,9 @@ Debug of error: SharedObjectOperationNotAllowed at command None task 8 'view-object'. lines 39-39: Owner: Shared Version: 4 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 9 'view-object'. lines 41-41: Owner: Shared Version: 5 -Contents: test::m::S2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}} +Contents: test::m::S2 {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}} diff --git a/crates/iota-adapter-transactional-tests/tests/transfer_object/shared.move b/crates/iota-adapter-transactional-tests/tests/transfer_object/shared.move new file mode 100644 index 00000000000..0ad7d19844d --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/shared.move @@ -0,0 +1,42 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests TransferObject should fail for a shared object with and without store + +//# init --accounts A B --addresses test=0x0 --shared-object-deletion true + +//# publish + +module test::m { + + public struct S has key { id: UID } + + public struct S2 has key, store { id: UID } + + public fun mint_s(ctx: &mut TxContext) { + let id = object::new(ctx); + transfer::share_object(S { id }) + } + + public fun mint_s2(ctx: &mut TxContext) { + let id = object::new(ctx); + transfer::share_object(S2 { id }) + } +} + +//# run test::m::mint_s + +//# run test::m::mint_s2 + +//# view-object 2,0 + +//# view-object 3,0 + +//# transfer-object 2,0 --sender A --recipient B + +//# transfer-object 3,0 --sender A --recipient B + +//# view-object 2,0 + +//# view-object 3,0 diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/shared_v20.exp b/crates/iota-adapter-transactional-tests/tests/transfer_object/shared_v20.exp similarity index 82% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/shared_v20.exp rename to crates/iota-adapter-transactional-tests/tests/transfer_object/shared_v20.exp index f944d86dbe2..ec400da2df2 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/shared_v20.exp +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/shared_v20.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: task 3 'view-object'. lines 22-22: Owner: Shared Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'transfer-object'. lines 24-24: Error: Transaction Effects Status: Invalid command argument at 0. Immutable objects cannot be passed by-value. @@ -25,4 +25,4 @@ Debug of error: CommandArgumentError { arg_idx: 0, kind: InvalidObjectByValue } task 5 'view-object'. lines 26-26: Owner: Shared Version: 4 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: test::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/shared_v20.move b/crates/iota-adapter-transactional-tests/tests/transfer_object/shared_v20.move similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/shared_v20.move rename to crates/iota-adapter-transactional-tests/tests/transfer_object/shared_v20.move index 3c84242a9a3..e327581cee6 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/shared_v20.move +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/shared_v20.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests TransferObject should fail for a shared object diff --git a/crates/iota-adapter-transactional-tests/tests/transfer_object/transfer_coin.exp b/crates/iota-adapter-transactional-tests/tests/transfer_object/transfer_coin.exp new file mode 100644 index 00000000000..cff5c670359 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/transfer_coin.exp @@ -0,0 +1,22 @@ +processed 5 tasks + +init: +A: object(0,0), B: object(0,1), C: object(0,2) + +task 1 'programmable'. lines 8-9: +mutated: object(0,2) +gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'view-object'. lines 11-11: +Owner: Account Address ( A ) +Version: 2 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(0,2)}}, balance: iota::balance::Balance {value: 299999998012000u64}} + +task 3 'transfer-object'. lines 13-13: +mutated: object(0,0), object(0,2) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 4 'view-object'. lines 15-15: +Owner: Account Address ( B ) +Version: 3 +Contents: iota::coin::Coin {id: iota::object::UID {id: iota::object::ID {bytes: fake(0,2)}}, balance: iota::balance::Balance {value: 299999998012000u64}} diff --git a/crates/iota-adapter-transactional-tests/tests/transfer_object/transfer_coin.move b/crates/iota-adapter-transactional-tests/tests/transfer_object/transfer_coin.move new file mode 100644 index 00000000000..75b2057f9a8 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/transfer_coin.move @@ -0,0 +1,16 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tests TransferObject with a IOTA coin + +//# init --accounts A B C + +//# programmable --sender C --inputs @A +//> TransferObjects([Gas], Input(0)) + +//# view-object 0,2 + +//# transfer-object 0,2 --sender A --recipient B + +//# view-object 0,2 diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/wrap_unwrap.exp b/crates/iota-adapter-transactional-tests/tests/transfer_object/wrap_unwrap.exp similarity index 76% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/wrap_unwrap.exp rename to crates/iota-adapter-transactional-tests/tests/transfer_object/wrap_unwrap.exp index 4ef4b9f04cd..7763da73cc2 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/wrap_unwrap.exp +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/wrap_unwrap.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: task 3 'view-object'. lines 43-43: Owner: Account Address ( A ) Version: 2 -Contents: a::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: a::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} task 4 'run'. lines 45-45: created: object(4,0) @@ -27,7 +27,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2439600, storage_rebate: task 5 'view-object'. lines 47-47: Owner: Account Address ( A ) Version: 3 -Contents: a::m::T {id: sui::object::UID {id: sui::object::ID {bytes: fake(4,0)}}, s: a::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}}} +Contents: a::m::T {id: iota::object::UID {id: iota::object::ID {bytes: fake(4,0)}}, s: a::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}}} task 6 'run'. lines 49-49: mutated: object(0,0) @@ -38,4 +38,4 @@ gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: task 7 'view-object'. lines 51-51: Owner: Account Address ( A ) Version: 4 -Contents: a::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} +Contents: a::m::S {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/wrap_unwrap.move b/crates/iota-adapter-transactional-tests/tests/transfer_object/wrap_unwrap.move similarity index 82% rename from crates/sui-adapter-transactional-tests/tests/transfer_object/wrap_unwrap.move rename to crates/iota-adapter-transactional-tests/tests/transfer_object/wrap_unwrap.move index 4e22e1bc541..8ca33ac2110 100644 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/wrap_unwrap.move +++ b/crates/iota-adapter-transactional-tests/tests/transfer_object/wrap_unwrap.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // test impact to versions for wrapping and unwrapping an object @@ -18,14 +19,14 @@ module a::m { } entry fun mint(ctx: &mut TxContext) { - sui::transfer::public_transfer( + iota::transfer::public_transfer( S { id: object::new(ctx) }, tx_context::sender(ctx), ); } entry fun wrap(s: S, ctx: &mut TxContext) { - sui::transfer::public_transfer( + iota::transfer::public_transfer( T { id: object::new(ctx), s }, tx_context::sender(ctx), ); @@ -34,7 +35,7 @@ module a::m { entry fun unwrap(t: T, ctx: &mut TxContext) { let T { id, s } = t; object::delete(id); - sui::transfer::public_transfer(s, tx_context::sender(ctx)); + iota::transfer::public_transfer(s, tx_context::sender(ctx)); } } diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade.exp similarity index 94% rename from crates/sui-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade.exp index d4a270c16c6..d6f75a575a5 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade.exp +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade.exp @@ -33,8 +33,8 @@ Error: Transaction Effects Status: Invalid package upgrade. New package is incom Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: PackageUpgradeError { upgrade_error: IncompatibleUpgrade }, source: Some(PartialVMError { major_status: BACKWARD_INCOMPATIBLE_MODULE_UPDATE, sub_status: None, message: None, exec_state: None, indices: [], offsets: [] }), command: Some(1) } } task 8 'upgrade'. lines 45-48: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("First field of struct Foo must be 'id', dummy_field found"), command: Some(1) } } +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("First field of struct Foo must be 'id', dummy_field found"), command: Some(1) } } task 9 'upgrade'. lines 50-56: Error: Transaction Effects Status: Invalid package upgrade. New package is incompatible with previous version diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade.move b/crates/iota-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade.move index 39c14bad205..b60ad3effff 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test_V0=0x0 Test_V1=0x0 --accounts A --flavor core @@ -11,7 +12,7 @@ module Test_V0::base { //# upgrade --package Test_V0 --upgrade-capability 1,1 --sender A module Test_V1::base { - use sui::object::UID; + use iota::object::UID; public struct Foo has key { id: UID } @@ -49,7 +50,7 @@ module Test_V1::base { //# upgrade --package Test_V0 --upgrade-capability 1,1 --sender A module Test_V1::base { - use sui::object::UID; + use iota::object::UID; public struct Foo has store, key { id: UID } diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade_generics.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade_generics.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade_generics.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade_generics.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade_generics.move b/crates/iota-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade_generics.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade_generics.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade_generics.move index f00c70fef1e..e44255d7201 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade_generics.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/add_ability_during_upgrade_generics.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses A0=0x0 A1=0x0 B0=0x0 B1=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/add_key_during_upgrade.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/add_key_during_upgrade.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/add_key_during_upgrade.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/add_key_during_upgrade.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/add_key_during_upgrade.move b/crates/iota-adapter-transactional-tests/tests/upgrade/add_key_during_upgrade.move similarity index 90% rename from crates/sui-adapter-transactional-tests/tests/upgrade/add_key_during_upgrade.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/add_key_during_upgrade.move index b2c84b94781..6928b4d8e9a 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/add_key_during_upgrade.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/add_key_during_upgrade.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test_V0=0x0 Test_V1=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/add_new_type_with_key.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/add_new_type_with_key.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/add_new_type_with_key.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/add_new_type_with_key.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/add_new_type_with_key.move b/crates/iota-adapter-transactional-tests/tests/upgrade/add_new_type_with_key.move similarity index 89% rename from crates/sui-adapter-transactional-tests/tests/upgrade/add_new_type_with_key.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/add_new_type_with_key.move index 0ef223f03b4..5dc7090b8f2 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/add_new_type_with_key.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/add_new_type_with_key.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test_V0=0x0 Test_V1=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/basic.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/basic.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/basic.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/basic.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/basic.move b/crates/iota-adapter-transactional-tests/tests/upgrade/basic.move similarity index 87% rename from crates/sui-adapter-transactional-tests/tests/upgrade/basic.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/basic.move index 68d71bfdbaf..d25ba118715 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/basic.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/basic.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/constants.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/constants.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/constants.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/constants.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/constants.move b/crates/iota-adapter-transactional-tests/tests/upgrade/constants.move similarity index 98% rename from crates/sui-adapter-transactional-tests/tests/upgrade/constants.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/constants.move index 9253f22c1c2..3442d32fe6f 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/constants.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/constants.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses V0=0x0 V1=0x0 V2=0x0 V3=0x0 V4=0x0 V5=0x0 V6=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/dep_override.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/dep_override.exp similarity index 87% rename from crates/sui-adapter-transactional-tests/tests/upgrade/dep_override.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/dep_override.exp index 1c7917f56db..cb4dcadcf38 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/dep_override.exp +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/dep_override.exp @@ -51,7 +51,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2325600, storage_rebate: task 10 'view-object'. lines 89-89: Owner: Shared Version: 2 -Contents: Test_DepDepV1::DepDepM1::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(9,0)}}, v: 42u64} +Contents: Test_DepDepV1::DepDepM1::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(9,0)}}, v: 42u64} task 11 'run'. lines 91-91: created: object(11,0) @@ -61,7 +61,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2325600, storage_rebate: task 12 'view-object'. lines 93-93: Owner: Shared Version: 3 -Contents: Test_DepDepV1::DepDepM1::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(11,0)}}, v: 7u64} +Contents: Test_DepDepV1::DepDepM1::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(11,0)}}, v: 7u64} task 13 'run'. lines 95-95: created: object(13,0) @@ -71,7 +71,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2325600, storage_rebate: task 14 'view-object'. lines 97-100: Owner: Shared Version: 4 -Contents: Test_DepDepV1::DepDepM1::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(13,0)}}, v: 0u64} +Contents: Test_DepDepV1::DepDepM1::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(13,0)}}, v: 0u64} task 15 'programmable'. lines 101-103: created: object(15,0), object(15,1) @@ -81,12 +81,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: task 16 'view-object'. lines 105-105: Owner: Shared Version: 10 -Contents: Test_DepDepV1::DepDepM1::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(15,0)}}, v: 7u64} +Contents: Test_DepDepV1::DepDepM1::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(15,0)}}, v: 7u64} task 17 'view-object'. lines 107-112: Owner: Shared Version: 10 -Contents: Test_DepDepV1::DepDepM1::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(15,1)}}, v: 0u64} +Contents: Test_DepDepV1::DepDepM1::Obj {id: iota::object::UID {id: iota::object::ID {bytes: fake(15,1)}}, v: 0u64} task 18 'upgrade'. lines 114-120: Error: Transaction Effects Status: Publish/Upgrade Error, Missing dependency. A dependency of a published or upgraded package has not been assigned an on-chain address. diff --git a/crates/iota-adapter-transactional-tests/tests/upgrade/dep_override.move b/crates/iota-adapter-transactional-tests/tests/upgrade/dep_override.move new file mode 100644 index 00000000000..45bbf708543 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/dep_override.move @@ -0,0 +1,135 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --addresses Test_DepDepV1=0x0 Test_DepDepV2=0x0 Test_DepDepV3=0x0 Test_DepV1=0x0 Test_DepV2=0x0 Test_V1=0x0 Test_V2=0x0 Test_V3=0x0 Test_V4=0x0 --accounts A + + +// 3 versions of the transitive dependency + + +//# publish --upgradeable --sender A +module Test_DepDepV1::DepDepM1 { + + public struct Obj has key, store { id: iota::object::UID, v: u64 } + + public fun foo(ctx: &mut iota::tx_context::TxContext) { + iota::transfer::share_object(Obj { id: iota::object::new(ctx), v: 42 }) + } +} + +//# upgrade --package Test_DepDepV1 --upgrade-capability 1,1 --sender A +module Test_DepDepV2::DepDepM1 { + + public struct Obj has key, store { id: iota::object::UID, v: u64 } + + public fun foo(ctx: &mut iota::tx_context::TxContext) { + iota::transfer::share_object(Obj { id: iota::object::new(ctx), v: 7 }) + } +} + +//# upgrade --package Test_DepDepV2 --upgrade-capability 1,1 --sender A +module Test_DepDepV3::DepDepM1 { + + public struct Obj has key, store { id: iota::object::UID, v: u64 } + + public fun foo(ctx: &mut iota::tx_context::TxContext) { + iota::transfer::share_object(Obj { id: iota::object::new(ctx), v: 0 }) + } +} + + +// 2 versions of the direct dependency + + +//# publish --upgradeable --dependencies Test_DepDepV1 --sender A +module Test_DepV1::DepM1 { + use Test_DepDepV1::DepDepM1; + + public fun bar(ctx: &mut iota::tx_context::TxContext) { DepDepM1::foo(ctx) } +} + +//# upgrade --package Test_DepV1 --upgrade-capability 4,1 --dependencies Test_DepDepV2 --sender A +module Test_DepV2::DepM1 { + use Test_DepDepV2::DepDepM1; + + public fun bar(ctx: &mut iota::tx_context::TxContext) { DepDepM1::foo(ctx) } +} + + +// 3 versions of the root package + + +//# publish --upgradeable --dependencies Test_DepV1 Test_DepDepV1 --sender A +module Test_V1::M1 { + use Test_DepV1::DepM1; + + public entry fun baz(ctx: &mut iota::tx_context::TxContext) { DepM1::bar(ctx) } +} + +// override direct dependency + +//# upgrade --package Test_V1 --upgrade-capability 6,1 --dependencies Test_DepV2 Test_DepDepV2 --sender A +module Test_V2::M1 { + use Test_DepV2::DepM1; + + public entry fun baz(ctx: &mut iota::tx_context::TxContext) { DepM1::bar(ctx) } +} + +// override indirect dependency + +//# upgrade --package Test_V2 --upgrade-capability 6,1 --dependencies Test_DepV1 Test_DepDepV3 --sender A +module Test_V3::M1 { + use Test_DepV1::DepM1; + + public entry fun baz(ctx: &mut iota::tx_context::TxContext) { DepM1::bar(ctx) } +} + +//# run Test_V1::M1::baz + +//# view-object 9,0 + +//# run Test_V2::M1::baz + +//# view-object 11,0 + +//# run Test_V3::M1::baz + +//# view-object 13,0 + +// call same function from two different module versions but defined in both modules (should produce +// different result due to overrides) +//# programmable --sender A +//> 0: Test_V2::M1::baz(); +//> 1: Test_V3::M1::baz(); + +//# view-object 15,0 + +//# view-object 15,1 + + +// expected upgrade errors + +// missing direct dependency (should fail) + +//# upgrade --package Test_V3 --upgrade-capability 6,1 --dependencies Test_DepDepV1 --sender A +module Test_V4::M1 { + use Test_DepV1::DepM1; + public entry fun baz(ctx: &mut iota::tx_context::TxContext) { DepM1::bar(ctx) } +} + +// missing indirect dependency (should fail) + +//# upgrade --package Test_V3 --upgrade-capability 6,1 --dependencies Test_DepV2 --sender A +module Test_V4::M1 { + use Test_DepV2::DepM1; + public entry fun baz(ctx: &mut iota::tx_context::TxContext) { DepM1::bar(ctx) } +} + +// downgrade indirect dependency (should fail) + +//# upgrade --package Test_V3 --upgrade-capability 6,1 --dependencies Test_DepV2 Test_DepDepV1 --sender A +module Test_V4::M1 { + use Test_DepV2::DepM1; + public entry fun baz(ctx: &mut iota::tx_context::TxContext) { DepM1::bar(ctx) } +} diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/friend_fun_changes.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/friend_fun_changes.exp similarity index 90% rename from crates/sui-adapter-transactional-tests/tests/upgrade/friend_fun_changes.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/friend_fun_changes.exp index cce275121ec..48df21a512e 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/friend_fun_changes.exp +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/friend_fun_changes.exp @@ -35,4 +35,4 @@ gas summary: computation_cost: 1000000, storage_cost: 2432000, storage_rebate: task 7 'view-object'. lines 89-89: Owner: Account Address ( A ) Version: 3 -Contents: V0::base_module::Object {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}, field0: 10u64, field1: 10u64} +Contents: V0::base_module::Object {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}, field0: 10u64, field1: 10u64} diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/friend_fun_changes.move b/crates/iota-adapter-transactional-tests/tests/upgrade/friend_fun_changes.move similarity index 98% rename from crates/sui-adapter-transactional-tests/tests/upgrade/friend_fun_changes.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/friend_fun_changes.move index b9e13fbb460..2fbe16d146e 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/friend_fun_changes.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/friend_fun_changes.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses V0=0x0 V1=0x0 V2=0x0 V3=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/large_module_inclusion_checks.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/large_module_inclusion_checks.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/large_module_inclusion_checks.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/large_module_inclusion_checks.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/large_module_inclusion_checks.move b/crates/iota-adapter-transactional-tests/tests/upgrade/large_module_inclusion_checks.move similarity index 99% rename from crates/sui-adapter-transactional-tests/tests/upgrade/large_module_inclusion_checks.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/large_module_inclusion_checks.move index 6d5bc652b03..f1fb815f439 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/large_module_inclusion_checks.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/large_module_inclusion_checks.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses V0=0x0 V1=0x0 V2=0x0 V3=0x0 V4=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/linkage.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/linkage.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/linkage.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/linkage.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/linkage.move b/crates/iota-adapter-transactional-tests/tests/upgrade/linkage.move similarity index 82% rename from crates/sui-adapter-transactional-tests/tests/upgrade/linkage.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/linkage.move index 1ca4b50a5e3..e6788137be8 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/linkage.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/linkage.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test_V2=0x0 Test_V1=0x0 Test_DepV1=0x0 Test_DepV2=0x0 --accounts A //# publish --upgradeable --sender A module Test_DepV1::DepM1 { - public struct DepObj has key, store { id: sui::object::UID, v: u64 } + public struct DepObj has key, store { id: iota::object::UID, v: u64 } public fun mod_obj(o: &mut DepObj) { o.v = 0; } @@ -13,7 +14,7 @@ module Test_DepV1::DepM1 { //# upgrade --package Test_DepV1 --upgrade-capability 1,1 --sender A module Test_DepV2::DepM1 { - public struct DepObj has key, store { id: sui::object::UID, v: u64 } + public struct DepObj has key, store { id: iota::object::UID, v: u64 } public fun mod_obj(o: &mut DepObj) { o.v = 0; } diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/modules.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/modules.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/modules.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/modules.exp diff --git a/crates/iota-adapter-transactional-tests/tests/upgrade/modules.move b/crates/iota-adapter-transactional-tests/tests/upgrade/modules.move new file mode 100644 index 00000000000..e9a76e08940 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/modules.move @@ -0,0 +1,103 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --addresses V0=0x0 V1=0x0 V2=0x0 V3=0x0 --accounts A + +//# publish --upgradeable --sender A +module V0::base_module { + public struct Object has key, store { + id: UID, + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { 0 } +} +module V0::a { + fun call_friend(): u64 { V0::base_module::public_fun() } +} +module V0::b { + public fun public_fun(): u64 { 0 } +} +module V0::other_module { + public struct Y { } + fun public_fun(): u64 { 0 } +} + +// other_module::Y is missing in V1 +//# upgrade --package V0 --upgrade-capability 1,1 --sender A +module V1::base_module { + public struct Object has key, store { + id: UID, + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { 0 } +} +module V1::a { + fun call_friend(): u64 { V0::base_module::public_fun() } +} +module V1::b { + public fun public_fun(): u64 { 0 } +} +module V1::other_module { + fun public_fun(): u64 { 0 } +} + +// other_module missing in V1 +//# upgrade --package V0 --upgrade-capability 1,1 --sender A +module V1::base_module { + public struct Object has key, store { + id: UID, + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { 0 } +} +module V1::a { + fun call_friend(): u64 { V0::base_module::public_fun() } +} +module V1::b { + public fun public_fun(): u64 { 0 } +} + +// `b` missing in V1 +//# upgrade --package V0 --upgrade-capability 1,1 --sender A +module V1::base_module { + public struct Object has key, store { + id: UID, + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { 0 } +} +module V1::a { + fun call_friend(): u64 { V0::base_module::public_fun() } +} +module V1::other_module { + public struct Y { } + fun public_fun(): u64 { 0 } +} + +// `a` missing in V1 +//# upgrade --package V0 --upgrade-capability 1,1 --sender A +module V0::base_module { + public struct Object has key, store { + id: UID, + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { 0 } +} +module V0::b { + public fun public_fun(): u64 { 0 } +} +module V0::other_module { + public struct Y { } + fun public_fun(): u64 { 0 } +} diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/multi_version.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/multi_version.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/multi_version.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/multi_version.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/multi_version.move b/crates/iota-adapter-transactional-tests/tests/upgrade/multi_version.move similarity index 91% rename from crates/sui-adapter-transactional-tests/tests/upgrade/multi_version.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/multi_version.move index 0a2066100a1..9247d55e9f4 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/multi_version.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/multi_version.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test_V1=0x0 Test_V2=0x0 Test_V3=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/new_types.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/new_types.exp similarity index 82% rename from crates/sui-adapter-transactional-tests/tests/upgrade/new_types.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/new_types.exp index 941758653b5..977c0f37e5e 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/new_types.exp +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/new_types.exp @@ -36,7 +36,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2325600, storage_rebate: task 7 'view-object'. lines 78-80: Owner: Shared Version: 2 -Contents: Test_DepV1::DepM1::DepObj {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}, v: 42u64} +Contents: Test_DepV1::DepM1::DepObj {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}, v: 42u64} task 8 'programmable'. lines 81-83: mutated: object(0,0), object(6,0) @@ -45,7 +45,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2325600, storage_rebate: task 9 'view-object'. lines 85-88: Owner: Shared Version: 7 -Contents: Test_DepV1::DepM1::DepObj {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}, v: 39u64} +Contents: Test_DepV1::DepM1::DepObj {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}, v: 39u64} task 10 'programmable'. lines 89-91: mutated: object(0,0), object(6,0) @@ -54,7 +54,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2325600, storage_rebate: task 11 'view-object'. lines 93-96: Owner: Shared Version: 8 -Contents: Test_DepV1::DepM1::DepObj {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}, v: 37u64} +Contents: Test_DepV1::DepM1::DepObj {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}, v: 37u64} task 12 'programmable'. lines 97-99: mutated: object(0,0), object(6,0) @@ -63,4 +63,4 @@ gas summary: computation_cost: 1000000, storage_cost: 2325600, storage_rebate: task 13 'view-object'. lines 101-101: Owner: Shared Version: 9 -Contents: Test_DepV1::DepM1::DepObj {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}, v: 34u64} +Contents: Test_DepV1::DepM1::DepObj {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}, v: 34u64} diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/new_types.move b/crates/iota-adapter-transactional-tests/tests/upgrade/new_types.move similarity index 76% rename from crates/sui-adapter-transactional-tests/tests/upgrade/new_types.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/new_types.move index 0e6a209601c..ecf405da9eb 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/new_types.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/new_types.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test_DepV1=0x0 Test_DepV2=0x0 Test_V1=0x0 Test_V2=0x0 Test_V3=0x0 --accounts A @@ -6,10 +7,10 @@ //# publish --upgradeable --sender A module Test_DepV1::DepM1 { - public struct DepObj has key, store { id: sui::object::UID, v: u64 } + public struct DepObj has key, store { id: iota::object::UID, v: u64 } - public fun foo(ctx: &mut sui::tx_context::TxContext) { - sui::transfer::share_object(DepObj { id: sui::object::new(ctx), v: 42 }); + public fun foo(ctx: &mut iota::tx_context::TxContext) { + iota::transfer::share_object(DepObj { id: iota::object::new(ctx), v: 42 }); } public fun mod_obj(o: &mut DepObj) { @@ -21,10 +22,10 @@ module Test_DepV1::DepM1 { //# upgrade --package Test_DepV1 --upgrade-capability 1,1 --sender A module Test_DepV2::DepM1 { - public struct DepObj has key, store { id: sui::object::UID, v: u64 } + public struct DepObj has key, store { id: iota::object::UID, v: u64 } - public fun foo(ctx: &mut sui::tx_context::TxContext) { - sui::transfer::share_object(DepObj { id: sui::object::new(ctx), v: 7 }); + public fun foo(ctx: &mut iota::tx_context::TxContext) { + iota::transfer::share_object(DepObj { id: iota::object::new(ctx), v: 7 }); } public fun mod_obj(o: &mut DepObj) { @@ -37,7 +38,7 @@ module Test_DepV2::DepM1 { module Test_V1::M1 { use Test_DepV1::DepM1; - public entry fun bar(ctx: &mut sui::tx_context::TxContext) { + public entry fun bar(ctx: &mut iota::tx_context::TxContext) { DepM1::foo(ctx); } @@ -50,7 +51,7 @@ module Test_V1::M1 { module Test_V2::M1 { use Test_DepV1::DepM1; - public entry fun bar(ctx: &mut sui::tx_context::TxContext) { + public entry fun bar(ctx: &mut iota::tx_context::TxContext) { DepM1::foo(ctx); } @@ -63,7 +64,7 @@ module Test_V2::M1 { module Test_V3::M1 { use Test_DepV2::DepM1; - public entry fun bar(ctx: &mut sui::tx_context::TxContext) { + public entry fun bar(ctx: &mut iota::tx_context::TxContext) { DepM1::foo(ctx); } diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/private_fun_changes.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/private_fun_changes.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/private_fun_changes.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/private_fun_changes.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/private_fun_changes.move b/crates/iota-adapter-transactional-tests/tests/upgrade/private_fun_changes.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/upgrade/private_fun_changes.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/private_fun_changes.move index 87c4ea876e7..d97cc755807 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/private_fun_changes.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/private_fun_changes.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses V0=0x0 V1=0x0 V2=0x0 V3=0x0 V4=0x0 V5=0x0 V6=0x0 V7=0x0 V8=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/public_fun_changes.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/public_fun_changes.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/public_fun_changes.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/public_fun_changes.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/public_fun_changes.move b/crates/iota-adapter-transactional-tests/tests/upgrade/public_fun_changes.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/upgrade/public_fun_changes.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/public_fun_changes.move index 846f1ccfcb5..e611f1e5ab1 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/public_fun_changes.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/public_fun_changes.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test_V0=0x0 Test_V1=0x0 Test_V2=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/publisher.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/publisher.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/publisher.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/publisher.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/publisher.move b/crates/iota-adapter-transactional-tests/tests/upgrade/publisher.move similarity index 87% rename from crates/sui-adapter-transactional-tests/tests/upgrade/publisher.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/publisher.move index 8b5c4233b5c..d2580c1a67e 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/publisher.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/publisher.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses A0=0x0 A1=0x0 --accounts A //# publish --upgradeable --sender A module A0::m { - use sui::package; + use iota::package; public struct A {} public struct M has drop {} @@ -17,7 +18,7 @@ module A0::m { //# upgrade --package A0 --upgrade-capability 1,2 --sender A module A1::m { - use sui::package::{Self, Publisher}; + use iota::package::{Self, Publisher}; public struct A {} public struct B {} diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_fun_generics.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_fun_generics.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_fun_generics.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_fun_generics.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_fun_generics.move b/crates/iota-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_fun_generics.move similarity index 93% rename from crates/sui-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_fun_generics.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_fun_generics.move index a4e26aa3a2a..07d446810ca 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_fun_generics.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_fun_generics.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses A0=0x0 A1=0x0 A2=0x0 A3=0x0 A4=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_generics.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_generics.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_generics.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_generics.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_generics.move b/crates/iota-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_generics.move similarity index 95% rename from crates/sui-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_generics.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_generics.move index d60f22c38e2..6118bbe9a4b 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_generics.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/remove_ability_during_upgrade_generics.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses A0=0x0 A1=0x0 B0=0x0 B1=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/remove_phantom.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/remove_phantom.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/remove_phantom.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/remove_phantom.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/remove_phantom.move b/crates/iota-adapter-transactional-tests/tests/upgrade/remove_phantom.move similarity index 90% rename from crates/sui-adapter-transactional-tests/tests/upgrade/remove_phantom.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/remove_phantom.move index 2a6aa1f9d66..46a9da2057c 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/remove_phantom.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/remove_phantom.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses A0=0x0 A1=0x0 B0=0x0 B1=0x0 --accounts A diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/structs.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/structs.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/structs.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/structs.exp diff --git a/crates/iota-adapter-transactional-tests/tests/upgrade/structs.move b/crates/iota-adapter-transactional-tests/tests/upgrade/structs.move new file mode 100644 index 00000000000..1526d97d704 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/structs.move @@ -0,0 +1,61 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --addresses Test_V0=0x0 Test_V1=0x0 --accounts A + +//# publish --upgradeable --sender A +module Test_V0::base_module { + public struct X { + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { 0 } +} + +//# upgrade --package Test_V0 --upgrade-capability 1,1 --sender A +module Test_V1::base_module { + public struct Y { + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { 0 } +} + +//# upgrade --package Test_V0 --upgrade-capability 1,1 --sender A +module Test_V1::base_module { + public fun public_fun(): u64 { 0 } +} + +//# upgrade --package Test_V0 --upgrade-capability 1,1 --sender A +module Test_V1::base_module { + public struct X { + field2: u64, + field1: u64, + } + + public fun public_fun(): u64 { 0 } +} + +//# upgrade --package Test_V0 --upgrade-capability 1,1 --sender A +module Test_V1::base_module { + public struct X { + field1: u64, + field0: u64, + } + + public fun public_fun(): u64 { 0 } +} + +//# upgrade --package Test_V0 --upgrade-capability 1,1 --sender A +module Test_V1::base_module { + public struct X { + field0: u64, + field1: u64, + field2: u64, + } + + public fun public_fun(): u64 { 0 } +} diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/transitive_linkage.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/transitive_linkage.exp similarity index 100% rename from crates/sui-adapter-transactional-tests/tests/upgrade/transitive_linkage.exp rename to crates/iota-adapter-transactional-tests/tests/upgrade/transitive_linkage.exp diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/transitive_linkage.move b/crates/iota-adapter-transactional-tests/tests/upgrade/transitive_linkage.move similarity index 83% rename from crates/sui-adapter-transactional-tests/tests/upgrade/transitive_linkage.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/transitive_linkage.move index 7d5cf175c27..c74982c625a 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/transitive_linkage.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/transitive_linkage.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses Test_V3=0x0 Test_V2=0x0 Test_V1=0x0 Test_DepV1=0x0 Test_DepV2=0x0 Test_DepV3=0x0 --accounts A //# publish --upgradeable --sender A module Test_DepV1::DepM1 { - public struct DepObj has key, store { id: sui::object::UID, v: u64 } + public struct DepObj has key, store { id: iota::object::UID, v: u64 } public fun mod_obj(o: &mut DepObj) { o.v = 0; } @@ -14,7 +15,7 @@ module Test_DepV1::DepM1 { //# upgrade --package Test_DepV1 --upgrade-capability 1,1 --sender A module Test_DepV2::DepM1 { - public struct DepObj has key, store { id: sui::object::UID, v: u64 } + public struct DepObj has key, store { id: iota::object::UID, v: u64 } public fun mod_obj(o: &mut DepObj) { o.v = 0; } @@ -22,7 +23,7 @@ module Test_DepV2::DepM1 { //# upgrade --package Test_DepV2 --upgrade-capability 1,1 --sender A module Test_DepV3::DepM1 { - public struct DepObj has key, store { id: sui::object::UID, v: u64 } + public struct DepObj has key, store { id: iota::object::UID, v: u64 } public fun mod_obj(o: &mut DepObj) { o.v = 0; } diff --git a/crates/iota-adapter-transactional-tests/tests/upgrade/type_names.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/type_names.exp new file mode 100644 index 00000000000..b999d8188d7 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/type_names.exp @@ -0,0 +1,59 @@ +processed 12 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 6-15: +created: object(1,0), object(1,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 6171200, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'upgrade'. lines 17-26: +created: object(2,0) +mutated: object(0,0), object(1,1) +gas summary: computation_cost: 1000000, storage_cost: 6520800, storage_rebate: 2595780, non_refundable_storage_fee: 26220 + +task 3 'upgrade'. lines 28-55: +created: object(3,0) +mutated: object(0,0), object(1,1) +gas summary: computation_cost: 1000000, storage_cost: 9135200, storage_rebate: 2595780, non_refundable_storage_fee: 26220 + +task 4 'run'. lines 57-57: +created: object(4,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2728400, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 5 'run'. lines 59-59: +created: object(5,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2728400, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 6 'run'. lines 61-61: +created: object(6,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2728400, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 7 'run'. lines 63-63: +created: object(7,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 2728400, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 8 'view-object'. lines 65-65: +Owner: Account Address ( A ) +Version: 5 +Contents: A0::m::Canary {id: iota::object::UID {id: iota::object::ID {bytes: fake(4,0)}}, addr: vector[55u8, 99u8, 53u8, 56u8, 50u8, 49u8, 97u8, 97u8, 54u8, 56u8, 54u8, 55u8, 100u8, 97u8, 48u8, 101u8, 102u8, 97u8, 55u8, 101u8, 50u8, 54u8, 48u8, 54u8, 101u8, 56u8, 97u8, 102u8, 49u8, 54u8, 52u8, 52u8, 100u8, 97u8, 48u8, 54u8, 55u8, 49u8, 99u8, 52u8, 49u8, 102u8, 100u8, 57u8, 51u8, 52u8, 56u8, 97u8, 98u8, 97u8, 97u8, 51u8, 54u8, 49u8, 57u8, 101u8, 97u8, 53u8, 49u8, 100u8, 57u8, 99u8, 100u8, 97u8]} + +task 9 'view-object'. lines 67-67: +Owner: Account Address ( A ) +Version: 6 +Contents: A0::m::Canary {id: iota::object::UID {id: iota::object::ID {bytes: fake(5,0)}}, addr: vector[55u8, 99u8, 53u8, 56u8, 50u8, 49u8, 97u8, 97u8, 54u8, 56u8, 54u8, 55u8, 100u8, 97u8, 48u8, 101u8, 102u8, 97u8, 55u8, 101u8, 50u8, 54u8, 48u8, 54u8, 101u8, 56u8, 97u8, 102u8, 49u8, 54u8, 52u8, 52u8, 100u8, 97u8, 48u8, 54u8, 55u8, 49u8, 99u8, 52u8, 49u8, 102u8, 100u8, 57u8, 51u8, 52u8, 56u8, 97u8, 98u8, 97u8, 97u8, 51u8, 54u8, 49u8, 57u8, 101u8, 97u8, 53u8, 49u8, 100u8, 57u8, 99u8, 100u8, 97u8]} + +task 10 'view-object'. lines 69-69: +Owner: Account Address ( A ) +Version: 7 +Contents: A0::m::Canary {id: iota::object::UID {id: iota::object::ID {bytes: fake(6,0)}}, addr: vector[55u8, 99u8, 53u8, 56u8, 50u8, 49u8, 97u8, 97u8, 54u8, 56u8, 54u8, 55u8, 100u8, 97u8, 48u8, 101u8, 102u8, 97u8, 55u8, 101u8, 50u8, 54u8, 48u8, 54u8, 101u8, 56u8, 97u8, 102u8, 49u8, 54u8, 52u8, 52u8, 100u8, 97u8, 48u8, 54u8, 55u8, 49u8, 99u8, 52u8, 49u8, 102u8, 100u8, 57u8, 51u8, 52u8, 56u8, 97u8, 98u8, 97u8, 97u8, 51u8, 54u8, 49u8, 57u8, 101u8, 97u8, 53u8, 49u8, 100u8, 57u8, 99u8, 100u8, 97u8]} + +task 11 'view-object'. lines 71-71: +Owner: Account Address ( A ) +Version: 8 +Contents: A0::m::Canary {id: iota::object::UID {id: iota::object::ID {bytes: fake(7,0)}}, addr: vector[100u8, 51u8, 100u8, 99u8, 49u8, 54u8, 99u8, 53u8, 53u8, 50u8, 100u8, 57u8, 50u8, 53u8, 50u8, 100u8, 97u8, 56u8, 97u8, 100u8, 57u8, 97u8, 98u8, 52u8, 101u8, 50u8, 50u8, 57u8, 49u8, 57u8, 100u8, 51u8, 54u8, 48u8, 98u8, 55u8, 100u8, 101u8, 97u8, 97u8, 52u8, 53u8, 100u8, 97u8, 57u8, 102u8, 51u8, 97u8, 54u8, 57u8, 52u8, 57u8, 50u8, 102u8, 98u8, 99u8, 99u8, 99u8, 57u8, 98u8, 102u8, 98u8, 48u8, 56u8]} diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/type_names.move b/crates/iota-adapter-transactional-tests/tests/upgrade/type_names.move similarity index 96% rename from crates/sui-adapter-transactional-tests/tests/upgrade/type_names.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/type_names.move index 1b3961e3eac..683414374f1 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/type_names.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/type_names.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses A0=0x0 A1=0x0 A2=0x0 --accounts A diff --git a/crates/iota-adapter-transactional-tests/tests/upgrade/upgrade_ratchet.exp b/crates/iota-adapter-transactional-tests/tests/upgrade/upgrade_ratchet.exp new file mode 100644 index 00000000000..662c1483028 --- /dev/null +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/upgrade_ratchet.exp @@ -0,0 +1,64 @@ +processed 15 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 6-12: +created: object(1,0), object(1,1) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 5646800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'upgrade'. lines 13-16: +created: object(2,0) +mutated: object(0,0), object(1,1) +gas summary: computation_cost: 1000000, storage_cost: 5016000, storage_rebate: 2595780, non_refundable_storage_fee: 26220 + +task 3 'run'. lines 18-20: +mutated: object(0,0), object(1,1) +gas summary: computation_cost: 1000000, storage_cost: 2622000, storage_rebate: 2595780, non_refundable_storage_fee: 26220 + +task 4 'upgrade'. lines 21-26: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::package::authorize_upgrade (function index 21) at offset 24, Abort Code: 1 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("package") }, function: 21, instruction: 24, function_name: Some("authorize_upgrade") }, 1), source: Some(VMError { major_status: ABORTED, sub_status: Some(1), message: Some("iota::package::authorize_upgrade at offset 24"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("package") }), indices: [], offsets: [(FunctionDefinitionIndex(21), 24)] }), command: Some(0) } } + +task 5 'upgrade'. lines 27-32: +created: object(5,0) +mutated: object(0,0), object(1,1) +gas summary: computation_cost: 1000000, storage_cost: 5016000, storage_rebate: 2595780, non_refundable_storage_fee: 26220 + +task 6 'upgrade'. lines 33-36: +created: object(6,0) +mutated: object(0,0), object(1,1) +gas summary: computation_cost: 1000000, storage_cost: 5016000, storage_rebate: 2595780, non_refundable_storage_fee: 26220 + +task 7 'run'. lines 38-40: +mutated: object(0,0), object(1,1) +gas summary: computation_cost: 1000000, storage_cost: 2622000, storage_rebate: 2595780, non_refundable_storage_fee: 26220 + +task 8 'upgrade'. lines 41-46: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::package::authorize_upgrade (function index 21) at offset 24, Abort Code: 1 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("package") }, function: 21, instruction: 24, function_name: Some("authorize_upgrade") }, 1), source: Some(VMError { major_status: ABORTED, sub_status: Some(1), message: Some("iota::package::authorize_upgrade at offset 24"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("package") }), indices: [], offsets: [(FunctionDefinitionIndex(21), 24)] }), command: Some(0) } } + +task 9 'upgrade'. lines 47-52: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::package::authorize_upgrade (function index 21) at offset 24, Abort Code: 1 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("package") }, function: 21, instruction: 24, function_name: Some("authorize_upgrade") }, 1), source: Some(VMError { major_status: ABORTED, sub_status: Some(1), message: Some("iota::package::authorize_upgrade at offset 24"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("package") }), indices: [], offsets: [(FunctionDefinitionIndex(21), 24)] }), command: Some(0) } } + +task 10 'upgrade'. lines 53-58: +created: object(10,0) +mutated: object(0,0), object(1,1) +gas summary: computation_cost: 1000000, storage_cost: 5016000, storage_rebate: 2595780, non_refundable_storage_fee: 26220 + +task 11 'run'. lines 59-61: +Error: Transaction Effects Status: Move Runtime Abort. Location: iota::package::restrict (function index 23) at offset 10, Abort Code: 1 +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: iota, name: Identifier("package") }, function: 23, instruction: 10, function_name: Some("restrict") }, 1), source: Some(VMError { major_status: ABORTED, sub_status: Some(1), message: Some("iota::package::restrict at offset 10"), exec_state: None, location: Module(ModuleId { address: iota, name: Identifier("package") }), indices: [], offsets: [(FunctionDefinitionIndex(23), 10)] }), command: Some(0) } } + +task 12 'run'. lines 62-62: +mutated: object(0,0) +deleted: object(1,1) +gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 2595780, non_refundable_storage_fee: 26220 + +task 13 'view-object'. lines 64-66: +No object at id 1,1 + +task 14 'upgrade'. lines 67-70: +Error: INVALID TEST. Could not load object argument object(1,1) diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/upgrade_ratchet.move b/crates/iota-adapter-transactional-tests/tests/upgrade/upgrade_ratchet.move similarity index 83% rename from crates/sui-adapter-transactional-tests/tests/upgrade/upgrade_ratchet.move rename to crates/iota-adapter-transactional-tests/tests/upgrade/upgrade_ratchet.move index 96044bcb852..8edbba1c65c 100644 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/upgrade_ratchet.move +++ b/crates/iota-adapter-transactional-tests/tests/upgrade/upgrade_ratchet.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --addresses V0=0x0 V1=0x0 V2=0x0 V3=0x0 V4=0x0 V5=0x0 --accounts A @@ -15,7 +16,7 @@ module V1::M1 { public fun f1() { } } -//# run sui::package::only_additive_upgrades --args object(1,1) --sender A +//# run iota::package::only_additive_upgrades --args object(1,1) --sender A // Fails now since we've updated the package to only allow additive (or more restrictive) upgrades //# upgrade --package V1 --upgrade-capability 1,1 --sender A --policy compatible @@ -35,7 +36,7 @@ module V3::M1 { public fun f1() { } } -//# run sui::package::only_dep_upgrades --args object(1,1) --sender A +//# run iota::package::only_dep_upgrades --args object(1,1) --sender A // Fails now since we've updated the package to only allow dep_only upgrades //# upgrade --package V3 --upgrade-capability 1,1 --sender A --policy compatible @@ -56,10 +57,10 @@ module V4::M1 { } // Can't go back to a less restrictive policy -//# run sui::package::only_additive_upgrades --args object(1,1) --sender A +//# run iota::package::only_additive_upgrades --args object(1,1) --sender A // Can make it immutable though -//# run sui::package::make_immutable --args object(1,1) --sender A +//# run iota::package::make_immutable --args object(1,1) --sender A //# view-object 1,1 diff --git a/crates/iota-analytics-indexer-derive/Cargo.toml b/crates/iota-analytics-indexer-derive/Cargo.toml new file mode 100644 index 00000000000..0ec6288bdd4 --- /dev/null +++ b/crates/iota-analytics-indexer-derive/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "iota-analytics-indexer-derive" +version.workspace = true +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2.workspace = true +quote.workspace = true +syn.workspace = true diff --git a/crates/iota-analytics-indexer-derive/src/lib.rs b/crates/iota-analytics-indexer-derive/src/lib.rs new file mode 100644 index 00000000000..f2a62b2ca6b --- /dev/null +++ b/crates/iota-analytics-indexer-derive/src/lib.rs @@ -0,0 +1,53 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, Data, DeriveInput, Fields}; + +#[proc_macro_derive(SerializeParquet)] +pub fn schema_derive(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let struct_name = &input.ident; + let (schema, getter_implementation) = match &input.data { + Data::Struct(data_struct) => match &data_struct.fields { + Fields::Named(fields) => { + let (schema_iter, getter_iter): (Vec<_>, Vec<_>) = fields + .named + .iter() + .enumerate() + .map(|(idx, field)| { + let field_name = field.ident.as_ref().unwrap().to_string(); + ( + format!("\"{}\".to_string()", field_name), + format!( + "if idx == {} {{ return self.{}.clone().into(); }}", + idx, field_name + ), + ) + }) + .unzip(); + (schema_iter.join(", "), getter_iter.join("\n")) + } + _ => panic!("not supported struct for parquet serialization"), + }, + _ => panic!("not supported struct for parquet serialization"), + }; + let schema_tokens: proc_macro2::TokenStream = schema.parse().unwrap(); + let getter_implementation_tokens: proc_macro2::TokenStream = + getter_implementation.parse().unwrap(); + quote! { + impl ParquetSchema for #struct_name { + fn schema() -> Vec { + vec![#schema_tokens] + } + + fn get_column(&self, idx: usize) -> ParquetValue { + #getter_implementation_tokens + panic!("not supported column {:?}", idx); + } + } + } + .into() +} diff --git a/crates/iota-analytics-indexer/Cargo.toml b/crates/iota-analytics-indexer/Cargo.toml new file mode 100644 index 00000000000..22542295d02 --- /dev/null +++ b/crates/iota-analytics-indexer/Cargo.toml @@ -0,0 +1,63 @@ +[package] +name = "iota-analytics-indexer" +version.workspace = true +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + + +[dependencies] +anyhow.workspace = true +async-trait.workspace = true +axum.workspace = true +bcs.workspace = true +byteorder.workspace = true +bytes.workspace = true +chrono.workspace = true +clap.workspace = true +csv.workspace = true +move-core-types.workspace = true +object_store.workspace = true +num_enum.workspace = true +prometheus.workspace = true +serde.workspace = true +thiserror.workspace = true +tracing.workspace = true +tokio = { workspace = true, features = ["full"] } +tokio-stream.workspace = true +url.workspace = true +serde_json.workspace = true +strum.workspace = true +strum_macros.workspace = true +parquet.workspace = true +arrow-array.workspace = true +fastcrypto = { workspace = true, features = ["copy_key"] } +mysten-metrics.workspace = true +iota-analytics-indexer-derive.workspace = true +iota-indexer.workspace = true +eyre.workspace = true +rocksdb.workspace = true +tempfile.workspace = true +iota-types.workspace = true +telemetry-subscribers.workspace = true +iota-rest-api.workspace = true +iota-storage.workspace = true +iota-config.workspace = true +typed-store-derive.workspace = true +typed-store.workspace = true +move-binary-format.workspace = true +move-bytecode-utils.workspace = true +iota-json-rpc-types.workspace = true +iota-package-resolver.workspace = true +simulacrum.workspace = true +arrow = { version = "50.0.0"} +gcp-bigquery-client = "0.18.0" +snowflake-api = { version = "0.6.0" } +tap = { version = "1.0.1", features = [] } + +[dev-dependencies] + +[[bin]] +name = "iota-analytics-indexer" +path = "src/main.rs" diff --git a/crates/sui-analytics-indexer/src/analytics_metrics.rs b/crates/iota-analytics-indexer/src/analytics_metrics.rs similarity index 96% rename from crates/sui-analytics-indexer/src/analytics_metrics.rs rename to crates/iota-analytics-indexer/src/analytics_metrics.rs index bfc28d4cf5d..233c3b6ef3b 100644 --- a/crates/sui-analytics-indexer/src/analytics_metrics.rs +++ b/crates/iota-analytics-indexer/src/analytics_metrics.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #![allow(dead_code)] use prometheus::{ diff --git a/crates/sui-analytics-indexer/src/analytics_processor.rs b/crates/iota-analytics-indexer/src/analytics_processor.rs similarity index 96% rename from crates/sui-analytics-indexer/src/analytics_processor.rs rename to crates/iota-analytics-indexer/src/analytics_processor.rs index 1d53e6a7709..9ddf572cced 100644 --- a/crates/sui-analytics-indexer/src/analytics_processor.rs +++ b/crates/iota-analytics-indexer/src/analytics_processor.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -10,13 +11,13 @@ use std::{ }; use anyhow::{Context, Result}; +use iota_config::object_storage_config::{ObjectStoreConfig, ObjectStoreType}; +use iota_indexer::framework::Handler; +use iota_rest_api::CheckpointData; +use iota_storage::object_store::util::{copy_file, path_to_filesystem}; +use iota_types::messages_checkpoint::CheckpointSequenceNumber; use object_store::{path::Path, DynObjectStore}; use serde::Serialize; -use sui_config::object_storage_config::{ObjectStoreConfig, ObjectStoreType}; -use sui_indexer::framework::Handler; -use sui_rest_api::CheckpointData; -use sui_storage::object_store::util::{copy_file, path_to_filesystem}; -use sui_types::messages_checkpoint::CheckpointSequenceNumber; use tokio::sync::{mpsc, oneshot}; use tracing::{error, info}; diff --git a/crates/iota-analytics-indexer/src/errors.rs b/crates/iota-analytics-indexer/src/errors.rs new file mode 100644 index 00000000000..97c5268e902 --- /dev/null +++ b/crates/iota-analytics-indexer/src/errors.rs @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum AnalyticsIndexerError { + #[error("Generic error: `{0}`")] + GenericError(String), + #[error("Failed to retrieve the current directory.")] + CurrentDirError, +} diff --git a/crates/iota-analytics-indexer/src/handlers/checkpoint_handler.rs b/crates/iota-analytics-indexer/src/handlers/checkpoint_handler.rs new file mode 100644 index 00000000000..de97e43c685 --- /dev/null +++ b/crates/iota-analytics-indexer/src/handlers/checkpoint_handler.rs @@ -0,0 +1,110 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::Result; +use fastcrypto::traits::EncodeDecodeBase64; +use iota_indexer::framework::Handler; +use iota_rest_api::{CheckpointData, CheckpointTransaction}; +use iota_types::{ + effects::TransactionEffectsAPI, + messages_checkpoint::{CertifiedCheckpointSummary, CheckpointSummary}, + transaction::TransactionDataAPI, +}; + +use crate::{handlers::AnalyticsHandler, tables::CheckpointEntry, FileType}; + +pub struct CheckpointHandler { + checkpoints: Vec, +} + +#[async_trait::async_trait] +impl Handler for CheckpointHandler { + fn name(&self) -> &str { + "checkpoint" + } + async fn process_checkpoint(&mut self, checkpoint_data: &CheckpointData) -> Result<()> { + let CheckpointData { + checkpoint_summary, + transactions: checkpoint_transactions, + .. + } = checkpoint_data; + self.process_checkpoint_transactions(checkpoint_summary, checkpoint_transactions); + Ok(()) + } +} + +#[async_trait::async_trait] +impl AnalyticsHandler for CheckpointHandler { + fn read(&mut self) -> Result> { + let cloned = self.checkpoints.clone(); + self.checkpoints.clear(); + Ok(cloned) + } + + fn file_type(&self) -> Result { + Ok(FileType::Checkpoint) + } +} + +impl CheckpointHandler { + pub fn new() -> Self { + CheckpointHandler { + checkpoints: vec![], + } + } + fn process_checkpoint_transactions( + &mut self, + summary: &CertifiedCheckpointSummary, + checkpoint_transactions: &[CheckpointTransaction], + ) { + let CheckpointSummary { + epoch, + sequence_number, + network_total_transactions, + previous_digest, + epoch_rolling_gas_cost_summary, + timestamp_ms, + end_of_epoch_data, + .. + } = summary.data(); + + let total_gas_cost = epoch_rolling_gas_cost_summary.computation_cost as i64 + + epoch_rolling_gas_cost_summary.storage_cost as i64 + - epoch_rolling_gas_cost_summary.storage_rebate as i64; + let total_transaction_blocks = checkpoint_transactions.len() as u64; + let mut total_transactions: u64 = 0; + let mut total_successful_transaction_blocks: u64 = 0; + let mut total_successful_transactions: u64 = 0; + for checkpoint_transaction in checkpoint_transactions { + let txn_data = checkpoint_transaction.transaction.transaction_data(); + let cmds = txn_data.kind().num_commands() as u64; + total_transactions += cmds; + if checkpoint_transaction.effects.status().is_ok() { + total_successful_transaction_blocks += 1; + total_successful_transactions += cmds; + } + } + + let checkpoint_entry = CheckpointEntry { + sequence_number: *sequence_number, + checkpoint_digest: summary.digest().base58_encode(), + previous_checkpoint_digest: previous_digest.map(|d| d.base58_encode()), + epoch: *epoch, + end_of_epoch: end_of_epoch_data.is_some(), + total_gas_cost, + computation_cost: epoch_rolling_gas_cost_summary.computation_cost, + storage_cost: epoch_rolling_gas_cost_summary.storage_cost, + storage_rebate: epoch_rolling_gas_cost_summary.storage_rebate, + non_refundable_storage_fee: epoch_rolling_gas_cost_summary.non_refundable_storage_fee, + total_transaction_blocks, + total_transactions, + total_successful_transaction_blocks, + total_successful_transactions, + network_total_transaction: *network_total_transactions, + timestamp_ms: *timestamp_ms, + validator_signature: summary.auth_sig().signature.encode_base64(), + }; + self.checkpoints.push(checkpoint_entry); + } +} diff --git a/crates/sui-analytics-indexer/src/handlers/df_handler.rs b/crates/iota-analytics-indexer/src/handlers/df_handler.rs similarity index 94% rename from crates/sui-analytics-indexer/src/handlers/df_handler.rs rename to crates/iota-analytics-indexer/src/handlers/df_handler.rs index 6050ea22907..836812de4ae 100644 --- a/crates/sui-analytics-indexer/src/handlers/df_handler.rs +++ b/crates/iota-analytics-indexer/src/handlers/df_handler.rs @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, path::Path}; use anyhow::Result; use fastcrypto::encoding::{Base64, Encoding}; -use sui_indexer::{errors::IndexerError, framework::Handler, types::owner_to_owner_info}; -use sui_json_rpc_types::SuiMoveValue; -use sui_package_resolver::Resolver; -use sui_rest_api::{CheckpointData, CheckpointTransaction}; -use sui_types::{ +use iota_indexer::{errors::IndexerError, framework::Handler, types::owner_to_owner_info}; +use iota_json_rpc_types::IotaMoveValue; +use iota_package_resolver::Resolver; +use iota_rest_api::{CheckpointData, CheckpointTransaction}; +use iota_types::{ base_types::ObjectID, dynamic_field::{DynamicFieldInfo, DynamicFieldName, DynamicFieldType}, object::Object, @@ -119,7 +120,7 @@ impl DynamicFieldHandler { })?; let name = DynamicFieldName { type_: name_type, - value: SuiMoveValue::from(name_value).to_json_value(), + value: IotaMoveValue::from(name_value).to_json_value(), }; let name_json = serde_json::to_string(&name)?; let (_owner_type, owner_id) = owner_to_owner_info(&object.owner); diff --git a/crates/sui-analytics-indexer/src/handlers/event_handler.rs b/crates/iota-analytics-indexer/src/handlers/event_handler.rs similarity index 85% rename from crates/sui-analytics-indexer/src/handlers/event_handler.rs rename to crates/iota-analytics-indexer/src/handlers/event_handler.rs index d31a710a931..fc404725edb 100644 --- a/crates/sui-analytics-indexer/src/handlers/event_handler.rs +++ b/crates/iota-analytics-indexer/src/handlers/event_handler.rs @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::Path; use anyhow::Result; use fastcrypto::encoding::{Base64, Encoding}; -use sui_indexer::framework::Handler; -use sui_json_rpc_types::SuiMoveStruct; -use sui_package_resolver::Resolver; -use sui_rest_api::CheckpointData; -use sui_types::{digests::TransactionDigest, effects::TransactionEvents, event::Event}; +use iota_indexer::framework::Handler; +use iota_json_rpc_types::IotaMoveStruct; +use iota_package_resolver::Resolver; +use iota_rest_api::CheckpointData; +use iota_types::{digests::TransactionDigest, effects::TransactionEvents, event::Event}; use crate::{ handlers::{get_move_struct, AnalyticsHandler}, @@ -93,13 +94,13 @@ impl EventHandler { contents, } = event; let move_struct = get_move_struct(type_, contents, &self.resolver).await?; - let (_struct_tag, sui_move_struct) = match move_struct.into() { - SuiMoveStruct::WithTypes { type_, fields } => { - (type_, SuiMoveStruct::WithFields(fields)) + let (_struct_tag, iota_move_struct) = match move_struct.into() { + IotaMoveStruct::WithTypes { type_, fields } => { + (type_, IotaMoveStruct::WithFields(fields)) } fields => (type_.clone(), fields), }; - let event_json = sui_move_struct.to_json_value(); + let event_json = iota_move_struct.to_json_value(); let entry = EventEntry { transaction_digest: digest.base58_encode(), event_index: idx as u64, diff --git a/crates/iota-analytics-indexer/src/handlers/mod.rs b/crates/iota-analytics-indexer/src/handlers/mod.rs new file mode 100644 index 00000000000..9a2d0bd75d9 --- /dev/null +++ b/crates/iota-analytics-indexer/src/handlers/mod.rs @@ -0,0 +1,330 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::{BTreeMap, BTreeSet}; + +use anyhow::{anyhow, Result}; +use iota_indexer::framework::Handler; +use iota_package_resolver::{PackageStore, Resolver}; +use iota_types::{ + base_types::ObjectID, + effects::{TransactionEffects, TransactionEffectsAPI}, + object::{bounded_visitor::BoundedVisitor, Object, Owner}, + transaction::{TransactionData, TransactionDataAPI}, +}; +use move_core_types::{ + annotated_value::{MoveStruct, MoveTypeLayout, MoveValue}, + language_storage::{StructTag, TypeTag}, +}; + +use crate::{ + tables::{InputObjectKind, ObjectStatus, OwnerType}, + FileType, +}; + +pub mod checkpoint_handler; +pub mod df_handler; +pub mod event_handler; +pub mod move_call_handler; +pub mod object_handler; +pub mod package_handler; +pub mod transaction_handler; +pub mod transaction_objects_handler; +pub mod wrapped_object_handler; + +const WRAPPED_INDEXING_DISALLOW_LIST: [&str; 4] = [ + "0x1::string::String", + "0x1::ascii::String", + "0x2::url::Url", + "0x2::object::ID", +]; + +#[async_trait::async_trait] +pub trait AnalyticsHandler: Handler { + /// Read back rows which are ready to be persisted. This function + /// will be invoked by the analytics processor after every call to + /// process_checkpoint + fn read(&mut self) -> Result>; + /// Type of data being written by this processor i.e. checkpoint, object, + /// etc + fn file_type(&self) -> Result; +} + +fn initial_shared_version(object: &Object) -> Option { + match object.owner { + Owner::Shared { + initial_shared_version, + } => Some(initial_shared_version.value()), + _ => None, + } +} + +fn get_owner_type(object: &Object) -> OwnerType { + match object.owner { + Owner::AddressOwner(_) => OwnerType::AddressOwner, + Owner::ObjectOwner(_) => OwnerType::ObjectOwner, + Owner::Shared { .. } => OwnerType::Shared, + Owner::Immutable => OwnerType::Immutable, + } +} + +fn get_owner_address(object: &Object) -> Option { + match object.owner { + Owner::AddressOwner(address) => Some(address.to_string()), + Owner::ObjectOwner(address) => Some(address.to_string()), + Owner::Shared { .. } => None, + Owner::Immutable => None, + } +} + +// Helper class to track input object kind. +// Build sets of object ids for input, shared input and gas coin objects as +// defined in the transaction data. +// Input objects include coins and shared. +struct InputObjectTracker { + shared: BTreeSet, + coins: BTreeSet, + input: BTreeSet, +} + +impl InputObjectTracker { + fn new(txn_data: &TransactionData) -> Self { + let shared: BTreeSet = txn_data + .shared_input_objects() + .iter() + .map(|shared_io| shared_io.id()) + .collect(); + let coins: BTreeSet = txn_data.gas().iter().map(|obj_ref| obj_ref.0).collect(); + let input: BTreeSet = txn_data + .input_objects() + .expect("Input objects must be valid") + .iter() + .map(|io_kind| io_kind.object_id()) + .collect(); + Self { + shared, + coins, + input, + } + } + + fn get_input_object_kind(&self, object_id: &ObjectID) -> Option { + if self.coins.contains(object_id) { + Some(InputObjectKind::GasCoin) + } else if self.shared.contains(object_id) { + Some(InputObjectKind::SharedInput) + } else if self.input.contains(object_id) { + Some(InputObjectKind::Input) + } else { + None + } + } +} + +// Helper class to track object status. +// Build sets of object ids for created, mutated and deleted objects as reported +// in the transaction effects. +struct ObjectStatusTracker { + created: BTreeSet, + mutated: BTreeSet, + deleted: BTreeSet, +} + +impl ObjectStatusTracker { + fn new(effects: &TransactionEffects) -> Self { + let created: BTreeSet = effects + .created() + .iter() + .map(|(obj_ref, _)| obj_ref.0) + .collect(); + let mutated: BTreeSet = effects + .mutated() + .iter() + .chain(effects.unwrapped().iter()) + .map(|(obj_ref, _)| obj_ref.0) + .collect(); + let deleted: BTreeSet = effects + .all_tombstones() + .into_iter() + .map(|(id, _)| id) + .collect(); + Self { + created, + mutated, + deleted, + } + } + + fn get_object_status(&self, object_id: &ObjectID) -> Option { + if self.mutated.contains(object_id) { + Some(ObjectStatus::Mutated) + } else if self.deleted.contains(object_id) { + Some(ObjectStatus::Deleted) + } else if self.created.contains(object_id) { + Some(ObjectStatus::Created) + } else { + None + } + } +} + +async fn get_move_struct( + struct_tag: &StructTag, + contents: &[u8], + resolver: &Resolver, +) -> Result { + let move_struct = match resolver + .type_layout(TypeTag::Struct(Box::new(struct_tag.clone()))) + .await? + { + MoveTypeLayout::Struct(move_struct_layout) => { + BoundedVisitor::deserialize_struct(contents, &move_struct_layout) + } + _ => Err(anyhow!("Object is not a move struct")), + }?; + Ok(move_struct) +} + +#[derive(Debug, Default)] +pub struct WrappedStruct { + object_id: Option, + struct_tag: Option, +} + +fn parse_struct( + path: &str, + move_struct: MoveStruct, + all_structs: &mut BTreeMap, +) { + let mut wrapped_struct = WrappedStruct { + struct_tag: Some(move_struct.type_), + ..Default::default() + }; + for (k, v) in move_struct.fields { + parse_struct_field( + &format!("{}.{}", path, &k), + v, + &mut wrapped_struct, + all_structs, + ); + } + all_structs.insert(path.to_string(), wrapped_struct); +} + +fn parse_struct_field( + path: &str, + move_value: MoveValue, + curr_struct: &mut WrappedStruct, + all_structs: &mut BTreeMap, +) { + match move_value { + MoveValue::Struct(move_struct) => { + let values = move_struct + .fields + .iter() + .map(|(id, value)| (id.to_string(), value)) + .collect::>(); + let struct_name = format!( + "0x{}::{}::{}", + move_struct.type_.address.short_str_lossless(), + move_struct.type_.module, + move_struct.type_.name + ); + if "0x2::object::UID" == struct_name { + if let Some(MoveValue::Struct(id_struct)) = values.get("id").cloned() { + let id_values = id_struct + .fields + .iter() + .map(|(id, value)| (id.to_string(), value)) + .collect::>(); + if let Some(MoveValue::Address(address) | MoveValue::Signer(address)) = + id_values.get("bytes").cloned() + { + curr_struct.object_id = Some(ObjectID::from_address(*address)) + } + } + } else if "0x1::option::Option" == struct_name { + // Option in iota move is implemented as vector of size 1 + if let Some(MoveValue::Vector(vec_values)) = values.get("vec").cloned() { + if let Some(first_value) = vec_values.first() { + parse_struct_field( + &format!("{}[0]", path), + first_value.clone(), + curr_struct, + all_structs, + ); + } + } + } else if !WRAPPED_INDEXING_DISALLOW_LIST.contains(&&*struct_name) { + // Do not index most common struct types i.e. string, url, etc + parse_struct(path, move_struct, all_structs) + } + } + MoveValue::Vector(fields) => { + for (index, field) in fields.iter().enumerate() { + parse_struct_field( + &format!("{}[{}]", path, &index), + field.clone(), + curr_struct, + all_structs, + ); + } + } + _ => {} + } +} + +#[cfg(test)] +mod tests { + use std::{collections::BTreeMap, str::FromStr}; + + use iota_types::base_types::ObjectID; + use move_core_types::{ + account_address::AccountAddress, + annotated_value::{MoveStruct, MoveValue}, + identifier::Identifier, + language_storage::StructTag, + }; + + use crate::handlers::parse_struct; + + #[tokio::test] + async fn test_wrapped_object_parsing() -> anyhow::Result<()> { + let uid_field = MoveValue::Struct(MoveStruct { + type_: StructTag::from_str("0x2::object::UID")?, + fields: vec![( + Identifier::from_str("id")?, + MoveValue::Struct(MoveStruct { + type_: StructTag::from_str("0x2::object::ID")?, + fields: vec![( + Identifier::from_str("bytes")?, + MoveValue::Signer(AccountAddress::from_hex_literal("0x300")?), + )], + }), + )], + }); + let balance_field = MoveValue::Struct(MoveStruct { + type_: StructTag::from_str("0x2::balance::Balance")?, + fields: vec![(Identifier::from_str("value")?, MoveValue::U32(10))], + }); + let move_struct = MoveStruct { + type_: StructTag::from_str("0x2::test::Test")?, + fields: vec![ + (Identifier::from_str("id")?, uid_field), + (Identifier::from_str("principal")?, balance_field), + ], + }; + let mut all_structs = BTreeMap::new(); + parse_struct("$", move_struct, &mut all_structs); + assert_eq!( + all_structs.get("$").unwrap().object_id, + Some(ObjectID::from_hex_literal("0x300")?) + ); + assert_eq!( + all_structs.get("$.principal").unwrap().struct_tag, + Some(StructTag::from_str("0x2::balance::Balance")?) + ); + Ok(()) + } +} diff --git a/crates/sui-analytics-indexer/src/handlers/move_call_handler.rs b/crates/iota-analytics-indexer/src/handlers/move_call_handler.rs similarity index 92% rename from crates/sui-analytics-indexer/src/handlers/move_call_handler.rs rename to crates/iota-analytics-indexer/src/handlers/move_call_handler.rs index b11aec2609c..35aa9050ebc 100644 --- a/crates/sui-analytics-indexer/src/handlers/move_call_handler.rs +++ b/crates/iota-analytics-indexer/src/handlers/move_call_handler.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; +use iota_indexer::framework::Handler; +use iota_rest_api::CheckpointData; +use iota_types::{base_types::ObjectID, transaction::TransactionDataAPI}; use move_core_types::identifier::IdentStr; -use sui_indexer::framework::Handler; -use sui_rest_api::CheckpointData; -use sui_types::{base_types::ObjectID, transaction::TransactionDataAPI}; use crate::{handlers::AnalyticsHandler, tables::MoveCallEntry, FileType}; diff --git a/crates/sui-analytics-indexer/src/handlers/object_handler.rs b/crates/iota-analytics-indexer/src/handlers/object_handler.rs similarity index 91% rename from crates/sui-analytics-indexer/src/handlers/object_handler.rs rename to crates/iota-analytics-indexer/src/handlers/object_handler.rs index 5a8afaea187..4446fff2fad 100644 --- a/crates/sui-analytics-indexer/src/handlers/object_handler.rs +++ b/crates/iota-analytics-indexer/src/handlers/object_handler.rs @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::Path; use anyhow::Result; use fastcrypto::encoding::{Base64, Encoding}; -use sui_indexer::framework::Handler; -use sui_json_rpc_types::SuiMoveStruct; -use sui_package_resolver::Resolver; -use sui_rest_api::{CheckpointData, CheckpointTransaction}; -use sui_types::{effects::TransactionEffects, object::Object}; +use iota_indexer::framework::Handler; +use iota_json_rpc_types::IotaMoveStruct; +use iota_package_resolver::Resolver; +use iota_rest_api::{CheckpointData, CheckpointTransaction}; +use iota_types::{effects::TransactionEffects, object::Object}; use crate::{ handlers::{ @@ -145,10 +146,10 @@ impl ObjectHandler { } else { None }; - let (struct_tag, sui_move_struct) = if let Some(move_struct) = move_struct { + let (struct_tag, iota_move_struct) = if let Some(move_struct) = move_struct { match move_struct.into() { - SuiMoveStruct::WithTypes { type_, fields } => { - (Some(type_), Some(SuiMoveStruct::WithFields(fields))) + IotaMoveStruct::WithTypes { type_, fields } => { + (Some(type_), Some(IotaMoveStruct::WithFields(fields))) } fields => (object.struct_tag(), Some(fields)), } @@ -182,7 +183,7 @@ impl ObjectHandler { None }, struct_tag: struct_tag.map(|x| x.to_string()), - object_json: sui_move_struct.map(|x| x.to_json_value().to_string()), + object_json: iota_move_struct.map(|x| x.to_json_value().to_string()), }; self.objects.push(entry); Ok(()) diff --git a/crates/sui-analytics-indexer/src/handlers/package_handler.rs b/crates/iota-analytics-indexer/src/handlers/package_handler.rs similarity index 90% rename from crates/sui-analytics-indexer/src/handlers/package_handler.rs rename to crates/iota-analytics-indexer/src/handlers/package_handler.rs index fefe066578f..8c7f60fecad 100644 --- a/crates/sui-analytics-indexer/src/handlers/package_handler.rs +++ b/crates/iota-analytics-indexer/src/handlers/package_handler.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; use fastcrypto::encoding::{Base64, Encoding}; -use sui_indexer::framework::Handler; -use sui_rest_api::CheckpointData; -use sui_types::{full_checkpoint_content::CheckpointTransaction, object::Object}; +use iota_indexer::framework::Handler; +use iota_rest_api::CheckpointData; +use iota_types::{full_checkpoint_content::CheckpointTransaction, object::Object}; use crate::{handlers::AnalyticsHandler, tables::MovePackageEntry, FileType}; @@ -72,7 +73,7 @@ impl PackageHandler { timestamp_ms: u64, object: &Object, ) -> Result<()> { - if let sui_types::object::Data::Package(p) = &object.data { + if let iota_types::object::Data::Package(p) = &object.data { let package_id = p.id(); let package_version = p.version().value(); let original_package_id = p.original_package_id(); diff --git a/crates/sui-analytics-indexer/src/handlers/transaction_handler.rs b/crates/iota-analytics-indexer/src/handlers/transaction_handler.rs similarity index 95% rename from crates/sui-analytics-indexer/src/handlers/transaction_handler.rs rename to crates/iota-analytics-indexer/src/handlers/transaction_handler.rs index 51da4289161..73052906de7 100644 --- a/crates/sui-analytics-indexer/src/handlers/transaction_handler.rs +++ b/crates/iota-analytics-indexer/src/handlers/transaction_handler.rs @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeSet; use anyhow::Result; use fastcrypto::encoding::{Base64, Encoding}; -use sui_indexer::framework::Handler; -use sui_rest_api::{CheckpointData, CheckpointTransaction}; -use sui_types::{ +use iota_indexer::framework::Handler; +use iota_rest_api::{CheckpointData, CheckpointTransaction}; +use iota_types::{ effects::{TransactionEffects, TransactionEffectsAPI}, transaction::{Command, TransactionDataAPI, TransactionKind}, }; @@ -183,9 +184,9 @@ impl TransactionHandler { #[cfg(test)] mod tests { use fastcrypto::encoding::{Base64, Encoding}; + use iota_indexer::framework::Handler; + use iota_types::{base_types::IotaAddress, storage::ReadStore}; use simulacrum::Simulacrum; - use sui_indexer::framework::Handler; - use sui_types::{base_types::SuiAddress, storage::ReadStore}; use crate::handlers::transaction_handler::TransactionHandler; @@ -194,7 +195,7 @@ mod tests { let mut sim = Simulacrum::new(); // Execute a simple transaction. - let transfer_recipient = SuiAddress::random_for_testing_only(); + let transfer_recipient = IotaAddress::random_for_testing_only(); let (transaction, _) = sim.transfer_txn(transfer_recipient); let (_effects, err) = sim.execute_transaction(transaction.clone()).unwrap(); assert!(err.is_none()); diff --git a/crates/sui-analytics-indexer/src/handlers/transaction_objects_handler.rs b/crates/iota-analytics-indexer/src/handlers/transaction_objects_handler.rs similarity index 96% rename from crates/sui-analytics-indexer/src/handlers/transaction_objects_handler.rs rename to crates/iota-analytics-indexer/src/handlers/transaction_objects_handler.rs index 10807d856eb..721fea00ece 100644 --- a/crates/sui-analytics-indexer/src/handlers/transaction_objects_handler.rs +++ b/crates/iota-analytics-indexer/src/handlers/transaction_objects_handler.rs @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; -use sui_indexer::framework::Handler; -use sui_rest_api::{CheckpointData, CheckpointTransaction}; -use sui_types::{ +use iota_indexer::framework::Handler; +use iota_rest_api::{CheckpointData, CheckpointTransaction}; +use iota_types::{ base_types::ObjectID, effects::TransactionEffects, transaction::TransactionDataAPI, }; diff --git a/crates/sui-analytics-indexer/src/handlers/wrapped_object_handler.rs b/crates/iota-analytics-indexer/src/handlers/wrapped_object_handler.rs similarity index 94% rename from crates/sui-analytics-indexer/src/handlers/wrapped_object_handler.rs rename to crates/iota-analytics-indexer/src/handlers/wrapped_object_handler.rs index 1a3e708a8f9..7c9e6df6129 100644 --- a/crates/sui-analytics-indexer/src/handlers/wrapped_object_handler.rs +++ b/crates/iota-analytics-indexer/src/handlers/wrapped_object_handler.rs @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, path::Path}; use anyhow::Result; -use sui_indexer::framework::Handler; -use sui_package_resolver::Resolver; -use sui_rest_api::{CheckpointData, CheckpointTransaction}; -use sui_types::object::Object; +use iota_indexer::framework::Handler; +use iota_package_resolver::Resolver; +use iota_rest_api::{CheckpointData, CheckpointTransaction}; +use iota_types::object::Object; use crate::{ handlers::{get_move_struct, parse_struct, AnalyticsHandler}, diff --git a/crates/iota-analytics-indexer/src/lib.rs b/crates/iota-analytics-indexer/src/lib.rs new file mode 100644 index 00000000000..2dba37092f9 --- /dev/null +++ b/crates/iota-analytics-indexer/src/lib.rs @@ -0,0 +1,917 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ops::Range, path::PathBuf}; + +use anyhow::{anyhow, Result}; +use arrow_array::{Array, Int32Array}; +use clap::*; +use gcp_bigquery_client::{model::query_request::QueryRequest, Client}; +use iota_config::object_storage_config::ObjectStoreConfig; +use iota_indexer::framework::Handler; +use iota_rest_api::CheckpointData; +use iota_storage::object_store::util::{ + find_all_dirs_with_epoch_prefix, find_all_files_with_epoch_prefix, +}; +use iota_types::{ + base_types::EpochId, dynamic_field::DynamicFieldType, + messages_checkpoint::CheckpointSequenceNumber, +}; +use num_enum::{IntoPrimitive, TryFromPrimitive}; +use object_store::path::Path; +use serde::{Deserialize, Serialize}; +use snowflake_api::{QueryResult, SnowflakeApi}; +use strum_macros::EnumIter; +use tracing::info; + +use crate::{ + analytics_metrics::AnalyticsMetrics, + analytics_processor::AnalyticsProcessor, + handlers::{ + checkpoint_handler::CheckpointHandler, df_handler::DynamicFieldHandler, + event_handler::EventHandler, move_call_handler::MoveCallHandler, + object_handler::ObjectHandler, package_handler::PackageHandler, + transaction_handler::TransactionHandler, + transaction_objects_handler::TransactionObjectsHandler, + wrapped_object_handler::WrappedObjectHandler, AnalyticsHandler, + }, + tables::{ + CheckpointEntry, DynamicFieldEntry, EventEntry, InputObjectKind, MoveCallEntry, + MovePackageEntry, ObjectEntry, ObjectStatus, OwnerType, TransactionEntry, + TransactionObjectEntry, WrappedObjectEntry, + }, + writers::{csv_writer::CSVWriter, parquet_writer::ParquetWriter, AnalyticsWriter}, +}; + +pub mod analytics_metrics; +pub mod analytics_processor; +pub mod errors; +mod handlers; +mod package_store; +pub mod tables; +mod writers; + +const EPOCH_DIR_PREFIX: &str = "epoch_"; +const CHECKPOINT_DIR_PREFIX: &str = "checkpoints"; +const OBJECT_DIR_PREFIX: &str = "objects"; +const TRANSACTION_DIR_PREFIX: &str = "transactions"; +const EVENT_DIR_PREFIX: &str = "events"; +const TRANSACTION_OBJECT_DIR_PREFIX: &str = "transaction_objects"; +const MOVE_CALL_PREFIX: &str = "move_call"; +const MOVE_PACKAGE_PREFIX: &str = "move_package"; +const DYNAMIC_FIELD_PREFIX: &str = "dynamic_field"; + +const WRAPPED_OBJECT_PREFIX: &str = "wrapped_object"; + +#[derive(Parser, Clone, Debug)] +#[clap( + name = "Iota Analytics Indexer", + about = "Indexer service to upload data for the analytics pipeline.", + rename_all = "kebab-case" +)] +pub struct AnalyticsIndexerConfig { + /// The url of the checkpoint client to connect to. + #[clap(long)] + pub rest_url: String, + /// The url of the metrics client to connect to. + #[clap(long, default_value = "127.0.0.1", global = true)] + pub client_metric_host: String, + /// The port of the metrics client to connect to. + #[clap(long, default_value = "8081", global = true)] + pub client_metric_port: u16, + /// Directory to contain the temporary files for checkpoint entries. + #[clap(long, global = true, default_value = "/tmp")] + pub checkpoint_dir: PathBuf, + /// Number of checkpoints to process before uploading to the datastore. + #[clap(long, default_value = "10000", global = true)] + pub checkpoint_interval: u64, + /// Maximum file size in mb before uploading to the datastore. + #[clap(long, default_value = "100", global = true)] + pub max_file_size_mb: u64, + /// Checkpoint sequence number to start the download from + #[clap(long, default_value = None, global = true)] + pub starting_checkpoint_seq_num: Option, + /// Time to process in seconds before uploading to the datastore. + #[clap(long, default_value = "600", global = true)] + pub time_interval_s: u64, + // Remote object store where data gets written to + #[command(flatten)] + pub remote_store_config: ObjectStoreConfig, + // Remote object store path prefix to use while writing + #[clap(long, default_value = None, global = true)] + pub remote_store_path_prefix: Option, + // File format to store data in i.e. csv, parquet, etc + #[clap(long, value_enum, default_value = "csv", global = true)] + pub file_format: FileFormat, + // Type of data to write i.e. checkpoint, object, transaction, etc + #[clap(long, value_enum, long, global = true)] + pub file_type: FileType, + // Directory to contain the package cache for pipelines + #[clap( + long, + value_enum, + long, + global = true, + default_value = "/opt/iota/db/package_cache" + )] + pub package_cache_path: PathBuf, + #[clap(long, default_value = None, global = true)] + pub bq_service_account_key_file: Option, + #[clap(long, default_value = None, global = true)] + pub bq_project_id: Option, + #[clap(long, default_value = None, global = true)] + pub bq_dataset_id: Option, + #[clap(long, default_value = None, global = true)] + pub bq_table_id: Option, + #[clap(long, default_value = None, global = true)] + pub bq_checkpoint_col_id: Option, + #[clap(long, global = true)] + pub report_bq_max_table_checkpoint: bool, + #[clap(long, default_value = None, global = true)] + pub sf_account_identifier: Option, + #[clap(long, default_value = None, global = true)] + pub sf_warehouse: Option, + #[clap(long, default_value = None, global = true)] + pub sf_database: Option, + #[clap(long, default_value = None, global = true)] + pub sf_schema: Option, + #[clap(long, default_value = None, global = true)] + pub sf_username: Option, + #[clap(long, default_value = None, global = true)] + pub sf_role: Option, + #[clap(long, default_value = None, global = true)] + pub sf_password: Option, + #[clap(long, default_value = None, global = true)] + pub sf_table_id: Option, + #[clap(long, default_value = None, global = true)] + pub sf_checkpoint_col_id: Option, + #[clap(long, global = true)] + pub report_sf_max_table_checkpoint: bool, +} + +#[async_trait::async_trait] +pub trait MaxCheckpointReader: Send + Sync + 'static { + async fn max_checkpoint(&self) -> Result; +} + +struct SnowflakeMaxCheckpointReader { + query: String, + api: SnowflakeApi, +} + +impl SnowflakeMaxCheckpointReader { + pub async fn new( + account_identifier: &str, + warehouse: &str, + database: &str, + schema: &str, + user: &str, + role: &str, + passwd: &str, + table_id: &str, + col_id: &str, + ) -> anyhow::Result { + let api = SnowflakeApi::with_password_auth( + account_identifier, + Some(warehouse), + Some(database), + Some(schema), + user, + Some(role), + passwd, + ) + .expect("Failed to build sf api client"); + Ok(SnowflakeMaxCheckpointReader { + query: format!("SELECT max({}) from {}", col_id, table_id), + api, + }) + } +} + +#[async_trait::async_trait] +impl MaxCheckpointReader for SnowflakeMaxCheckpointReader { + async fn max_checkpoint(&self) -> Result { + let res = self.api.exec(&self.query).await?; + match res { + QueryResult::Arrow(a) => { + if let Some(record_batch) = a.first() { + let col = record_batch.column(0); + let col_array = col + .as_any() + .downcast_ref::() + .expect("Failed to downcast arrow column"); + Ok(col_array.value(0) as i64) + } else { + Ok(-1) + } + } + QueryResult::Json(_j) => Err(anyhow!("Unexpected query result")), + QueryResult::Empty => Err(anyhow!("Unexpected query result")), + } + } +} + +struct BQMaxCheckpointReader { + query: String, + project_id: String, + client: Client, +} + +impl BQMaxCheckpointReader { + pub async fn new( + key_path: &str, + project_id: &str, + dataset_id: &str, + table_id: &str, + col_id: &str, + ) -> anyhow::Result { + Ok(BQMaxCheckpointReader { + query: format!( + "SELECT max({}) from `{}.{}.{}`", + col_id, project_id, dataset_id, table_id + ), + client: Client::from_service_account_key_file(key_path).await?, + project_id: project_id.to_string(), + }) + } +} + +#[async_trait::async_trait] +impl MaxCheckpointReader for BQMaxCheckpointReader { + async fn max_checkpoint(&self) -> Result { + let mut result = self + .client + .job() + .query(&self.project_id, QueryRequest::new(&self.query)) + .await?; + if result.next_row() { + let max_checkpoint = result.get_i64(0)?.ok_or(anyhow!("No rows returned"))?; + Ok(max_checkpoint) + } else { + Ok(-1) + } + } +} + +struct NoOpCheckpointReader; + +#[async_trait::async_trait] +impl MaxCheckpointReader for NoOpCheckpointReader { + async fn max_checkpoint(&self) -> Result { + Ok(-1) + } +} + +#[derive( + Copy, + Clone, + Debug, + Eq, + PartialEq, + Parser, + strum_macros::Display, + ValueEnum, + Serialize, + Deserialize, + TryFromPrimitive, + IntoPrimitive, + EnumIter, +)] +#[repr(u8)] +pub enum FileFormat { + CSV = 0, + PARQUET = 1, +} + +impl FileFormat { + pub fn file_suffix(&self) -> &str { + match self { + FileFormat::CSV => "csv", + FileFormat::PARQUET => "parquet", + } + } +} + +#[derive( + Copy, + Clone, + Debug, + Eq, + PartialEq, + Serialize, + Deserialize, + TryFromPrimitive, + IntoPrimitive, + EnumIter, + ValueEnum, +)] +#[repr(u8)] +pub enum FileType { + Checkpoint = 0, + Object, + Transaction, + TransactionObjects, + Event, + MoveCall, + MovePackage, + DynamicField, + WrappedObject, +} + +impl FileType { + pub fn dir_prefix(&self) -> Path { + match self { + FileType::Checkpoint => Path::from(CHECKPOINT_DIR_PREFIX), + FileType::Transaction => Path::from(TRANSACTION_DIR_PREFIX), + FileType::TransactionObjects => Path::from(TRANSACTION_OBJECT_DIR_PREFIX), + FileType::Object => Path::from(OBJECT_DIR_PREFIX), + FileType::Event => Path::from(EVENT_DIR_PREFIX), + FileType::MoveCall => Path::from(MOVE_CALL_PREFIX), + FileType::MovePackage => Path::from(MOVE_PACKAGE_PREFIX), + FileType::DynamicField => Path::from(DYNAMIC_FIELD_PREFIX), + FileType::WrappedObject => Path::from(WRAPPED_OBJECT_PREFIX), + } + } + + pub fn file_path( + &self, + file_format: FileFormat, + epoch_num: EpochId, + checkpoint_range: Range, + ) -> Path { + self.dir_prefix() + .child(format!("{}{}", EPOCH_DIR_PREFIX, epoch_num)) + .child(format!( + "{}_{}.{}", + checkpoint_range.start, + checkpoint_range.end, + file_format.file_suffix() + )) + } +} + +pub enum ParquetValue { + U64(u64), + Str(String), + Bool(bool), + I64(i64), + OptionU64(Option), + OptionStr(Option), +} + +impl From for ParquetValue { + fn from(value: u64) -> Self { + Self::U64(value) + } +} + +impl From for ParquetValue { + fn from(value: i64) -> Self { + Self::I64(value) + } +} + +impl From for ParquetValue { + fn from(value: String) -> Self { + Self::Str(value) + } +} + +impl From> for ParquetValue { + fn from(value: Option) -> Self { + Self::OptionU64(value) + } +} + +impl From> for ParquetValue { + fn from(value: Option) -> Self { + Self::OptionStr(value) + } +} + +impl From for ParquetValue { + fn from(value: bool) -> Self { + Self::Bool(value) + } +} + +impl From for ParquetValue { + fn from(value: OwnerType) -> Self { + Self::Str(value.to_string()) + } +} + +impl From> for ParquetValue { + fn from(value: Option) -> Self { + value.map(|v| v.to_string()).into() + } +} + +impl From for ParquetValue { + fn from(value: ObjectStatus) -> Self { + Self::Str(value.to_string()) + } +} + +impl From> for ParquetValue { + fn from(value: Option) -> Self { + Self::OptionStr(value.map(|v| v.to_string())) + } +} + +impl From> for ParquetValue { + fn from(value: Option) -> Self { + Self::OptionStr(value.map(|v| v.to_string())) + } +} + +impl From for ParquetValue { + fn from(value: DynamicFieldType) -> Self { + Self::Str(value.to_string()) + } +} + +impl From> for ParquetValue { + fn from(value: Option) -> Self { + Self::OptionStr(value.map(|v| v.to_string())) + } +} + +pub trait ParquetSchema { + fn schema() -> Vec; + + fn get_column(&self, idx: usize) -> ParquetValue; +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +pub struct FileMetadata { + pub file_type: FileType, + pub file_format: FileFormat, + pub epoch_num: u64, + pub checkpoint_seq_range: Range, +} + +impl FileMetadata { + fn new( + file_type: FileType, + file_format: FileFormat, + epoch_num: u64, + checkpoint_seq_range: Range, + ) -> FileMetadata { + FileMetadata { + file_type, + file_format, + epoch_num, + checkpoint_seq_range, + } + } + + pub fn file_path(&self) -> Path { + self.file_type.file_path( + self.file_format, + self.epoch_num, + self.checkpoint_seq_range.clone(), + ) + } +} + +pub struct Processor { + pub processor: Box, + pub starting_checkpoint_seq_num: CheckpointSequenceNumber, +} + +#[async_trait::async_trait] +impl Handler for Processor { + #[inline] + fn name(&self) -> &str { + self.processor.name() + } + + #[inline] + async fn process_checkpoint(&mut self, checkpoint_data: &CheckpointData) -> Result<()> { + self.processor.process_checkpoint(checkpoint_data).await + } +} + +impl Processor { + pub async fn new( + handler: Box>, + writer: Box>, + max_checkpoint_reader: Box, + starting_checkpoint_seq_num: CheckpointSequenceNumber, + metrics: AnalyticsMetrics, + config: AnalyticsIndexerConfig, + ) -> Result { + let processor = Box::new( + AnalyticsProcessor::new( + handler, + writer, + max_checkpoint_reader, + starting_checkpoint_seq_num, + metrics, + config, + ) + .await?, + ); + + Ok(Processor { + processor, + starting_checkpoint_seq_num, + }) + } + + pub fn last_committed_checkpoint(&self) -> Option { + Some(self.starting_checkpoint_seq_num.saturating_sub(1)).filter(|x| *x > 0) + } +} + +pub async fn read_store_for_checkpoint( + remote_store_config: ObjectStoreConfig, + file_type: FileType, + dir_prefix: Option, +) -> Result { + let remote_object_store = remote_store_config.make()?; + let remote_store_is_empty = remote_object_store + .list_with_delimiter(None) + .await + .expect("Failed to read remote analytics store") + .common_prefixes + .is_empty(); + info!("Remote store is empty: {remote_store_is_empty}"); + let file_type_prefix = file_type.dir_prefix(); + let prefix = join_paths(dir_prefix, &file_type_prefix); + let epoch_dirs = find_all_dirs_with_epoch_prefix(&remote_object_store, Some(&prefix)).await?; + let epoch = epoch_dirs.last_key_value().map(|(k, _v)| *k).unwrap_or(0); + let epoch_prefix = prefix.child(format!("epoch_{}", epoch)); + let checkpoints = + find_all_files_with_epoch_prefix(&remote_object_store, Some(&epoch_prefix)).await?; + let next_checkpoint_seq_num = checkpoints + .iter() + .max_by(|x, y| x.end.cmp(&y.end)) + .map(|r| r.end) + .unwrap_or(0); + Ok(next_checkpoint_seq_num) +} + +pub async fn make_max_checkpoint_reader( + config: &AnalyticsIndexerConfig, +) -> Result> { + let res: Box = if config.report_bq_max_table_checkpoint { + Box::new( + BQMaxCheckpointReader::new( + config + .bq_service_account_key_file + .as_ref() + .ok_or(anyhow!("Missing gcp key file"))?, + config + .bq_project_id + .as_ref() + .ok_or(anyhow!("Missing big query project id"))?, + config + .bq_dataset_id + .as_ref() + .ok_or(anyhow!("Missing big query dataset id"))?, + config + .bq_table_id + .as_ref() + .ok_or(anyhow!("Missing big query table id"))?, + config + .bq_checkpoint_col_id + .as_ref() + .ok_or(anyhow!("Missing big query checkpoint col id"))?, + ) + .await?, + ) + } else if config.report_sf_max_table_checkpoint { + Box::new( + SnowflakeMaxCheckpointReader::new( + config + .sf_account_identifier + .as_ref() + .ok_or(anyhow!("Missing sf account identifier"))?, + config + .sf_warehouse + .as_ref() + .ok_or(anyhow!("Missing sf warehouse"))?, + config + .sf_database + .as_ref() + .ok_or(anyhow!("Missing sf database"))?, + config + .sf_schema + .as_ref() + .ok_or(anyhow!("Missing sf schema"))?, + config + .sf_username + .as_ref() + .ok_or(anyhow!("Missing sf username"))?, + config.sf_role.as_ref().ok_or(anyhow!("Missing sf role"))?, + config + .sf_password + .as_ref() + .ok_or(anyhow!("Missing sf password"))?, + config + .sf_table_id + .as_ref() + .ok_or(anyhow!("Missing sf table id"))?, + config + .sf_checkpoint_col_id + .as_ref() + .ok_or(anyhow!("Missing sf checkpoint col id"))?, + ) + .await?, + ) + } else { + Box::new(NoOpCheckpointReader {}) + }; + Ok(res) +} + +pub async fn make_checkpoint_processor( + config: AnalyticsIndexerConfig, + metrics: AnalyticsMetrics, +) -> Result { + let handler: Box> = Box::new(CheckpointHandler::new()); + let starting_checkpoint_seq_num = + get_starting_checkpoint_seq_num(config.clone(), FileType::Checkpoint).await?; + let writer = make_writer::( + config.clone(), + FileType::Checkpoint, + starting_checkpoint_seq_num, + )?; + let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; + Processor::new::( + handler, + writer, + max_checkpoint_reader, + starting_checkpoint_seq_num, + metrics, + config, + ) + .await +} + +pub async fn make_transaction_processor( + config: AnalyticsIndexerConfig, + metrics: AnalyticsMetrics, +) -> Result { + let handler: Box> = Box::new(TransactionHandler::new()); + let starting_checkpoint_seq_num = + get_starting_checkpoint_seq_num(config.clone(), FileType::Transaction).await?; + let writer = make_writer::( + config.clone(), + FileType::Transaction, + starting_checkpoint_seq_num, + )?; + let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; + Processor::new::( + handler, + writer, + max_checkpoint_reader, + starting_checkpoint_seq_num, + metrics, + config, + ) + .await +} + +pub async fn make_object_processor( + config: AnalyticsIndexerConfig, + metrics: AnalyticsMetrics, +) -> Result { + let handler: Box> = Box::new(ObjectHandler::new( + &config.package_cache_path, + &config.rest_url, + )); + let starting_checkpoint_seq_num = + get_starting_checkpoint_seq_num(config.clone(), FileType::Object).await?; + let writer = make_writer::( + config.clone(), + FileType::Object, + starting_checkpoint_seq_num, + )?; + let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; + Processor::new::( + handler, + writer, + max_checkpoint_reader, + starting_checkpoint_seq_num, + metrics, + config, + ) + .await +} + +pub async fn make_event_processor( + config: AnalyticsIndexerConfig, + metrics: AnalyticsMetrics, +) -> Result { + let handler: Box> = Box::new(EventHandler::new( + &config.package_cache_path, + &config.rest_url, + )); + let starting_checkpoint_seq_num = + get_starting_checkpoint_seq_num(config.clone(), FileType::Event).await?; + let writer = + make_writer::(config.clone(), FileType::Event, starting_checkpoint_seq_num)?; + let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; + Processor::new::( + handler, + writer, + max_checkpoint_reader, + starting_checkpoint_seq_num, + metrics, + config, + ) + .await +} + +pub async fn make_transaction_objects_processor( + config: AnalyticsIndexerConfig, + metrics: AnalyticsMetrics, +) -> Result { + let starting_checkpoint_seq_num = + get_starting_checkpoint_seq_num(config.clone(), FileType::TransactionObjects).await?; + let handler = Box::new(TransactionObjectsHandler::new()); + let writer = make_writer( + config.clone(), + FileType::TransactionObjects, + starting_checkpoint_seq_num, + )?; + let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; + Processor::new::( + handler, + writer, + max_checkpoint_reader, + starting_checkpoint_seq_num, + metrics, + config, + ) + .await +} + +pub async fn make_move_package_processor( + config: AnalyticsIndexerConfig, + metrics: AnalyticsMetrics, +) -> Result { + let handler: Box> = Box::new(PackageHandler::new()); + let starting_checkpoint_seq_num = + get_starting_checkpoint_seq_num(config.clone(), FileType::MovePackage).await?; + let writer = make_writer::( + config.clone(), + FileType::MovePackage, + starting_checkpoint_seq_num, + )?; + let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; + Processor::new::( + handler, + writer, + max_checkpoint_reader, + starting_checkpoint_seq_num, + metrics, + config, + ) + .await +} + +pub async fn make_move_call_processor( + config: AnalyticsIndexerConfig, + metrics: AnalyticsMetrics, +) -> Result { + let starting_checkpoint_seq_num = + get_starting_checkpoint_seq_num(config.clone(), FileType::MoveCall).await?; + let handler: Box> = Box::new(MoveCallHandler::new()); + let writer = make_writer::( + config.clone(), + FileType::MoveCall, + starting_checkpoint_seq_num, + )?; + let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; + Processor::new::( + handler, + writer, + max_checkpoint_reader, + starting_checkpoint_seq_num, + metrics, + config, + ) + .await +} + +pub async fn make_dynamic_field_processor( + config: AnalyticsIndexerConfig, + metrics: AnalyticsMetrics, +) -> Result { + let starting_checkpoint_seq_num = + get_starting_checkpoint_seq_num(config.clone(), FileType::DynamicField).await?; + let handler: Box> = Box::new(DynamicFieldHandler::new( + &config.package_cache_path, + &config.rest_url, + )); + let writer = make_writer::( + config.clone(), + FileType::DynamicField, + starting_checkpoint_seq_num, + )?; + let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; + Processor::new::( + handler, + writer, + max_checkpoint_reader, + starting_checkpoint_seq_num, + metrics, + config, + ) + .await +} + +pub async fn make_wrapped_object_processor( + config: AnalyticsIndexerConfig, + metrics: AnalyticsMetrics, +) -> Result { + let starting_checkpoint_seq_num = + get_starting_checkpoint_seq_num(config.clone(), FileType::WrappedObject).await?; + let handler: Box> = Box::new( + WrappedObjectHandler::new(&config.package_cache_path, &config.rest_url), + ); + let writer = make_writer::( + config.clone(), + FileType::WrappedObject, + starting_checkpoint_seq_num, + )?; + let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; + Processor::new::( + handler, + writer, + max_checkpoint_reader, + starting_checkpoint_seq_num, + metrics, + config, + ) + .await +} + +pub fn make_writer( + config: AnalyticsIndexerConfig, + file_type: FileType, + starting_checkpoint_seq_num: u64, +) -> Result>> { + Ok(match config.file_format { + FileFormat::CSV => Box::new(CSVWriter::new( + &config.checkpoint_dir, + file_type, + starting_checkpoint_seq_num, + )?), + FileFormat::PARQUET => Box::new(ParquetWriter::new( + &config.checkpoint_dir, + file_type, + starting_checkpoint_seq_num, + )?), + }) +} + +pub async fn get_starting_checkpoint_seq_num( + config: AnalyticsIndexerConfig, + file_type: FileType, +) -> Result { + let checkpoint = if let Some(starting_checkpoint_seq_num) = config.starting_checkpoint_seq_num { + starting_checkpoint_seq_num + } else { + read_store_for_checkpoint( + config.remote_store_config.clone(), + file_type, + config.remote_store_path_prefix, + ) + .await? + }; + Ok(checkpoint) +} + +pub async fn make_analytics_processor( + config: AnalyticsIndexerConfig, + metrics: AnalyticsMetrics, +) -> Result { + match config.file_type { + FileType::Checkpoint => make_checkpoint_processor(config, metrics).await, + FileType::Object => make_object_processor(config, metrics).await, + FileType::Transaction => make_transaction_processor(config, metrics).await, + FileType::Event => make_event_processor(config, metrics).await, + FileType::TransactionObjects => make_transaction_objects_processor(config, metrics).await, + FileType::MoveCall => make_move_call_processor(config, metrics).await, + FileType::MovePackage => make_move_package_processor(config, metrics).await, + FileType::DynamicField => make_dynamic_field_processor(config, metrics).await, + FileType::WrappedObject => make_wrapped_object_processor(config, metrics).await, + } +} + +pub fn join_paths(base: Option, child: &Path) -> Path { + base.map(|p| { + let mut out_path = p.clone(); + for part in child.parts() { + out_path = out_path.child(part) + } + out_path + }) + .unwrap_or(child.clone()) +} diff --git a/crates/iota-analytics-indexer/src/main.rs b/crates/iota-analytics-indexer/src/main.rs new file mode 100644 index 00000000000..30d0a000ff2 --- /dev/null +++ b/crates/iota-analytics-indexer/src/main.rs @@ -0,0 +1,46 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use clap::*; +use iota_analytics_indexer::{ + analytics_metrics::AnalyticsMetrics, errors::AnalyticsIndexerError, make_analytics_processor, + AnalyticsIndexerConfig, +}; +use iota_indexer::{framework::IndexerBuilder, metrics::IndexerMetrics}; +use prometheus::Registry; +use tracing::info; + +#[tokio::main] +async fn main() -> Result<(), AnalyticsIndexerError> { + let _guard = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .init(); + + let config = AnalyticsIndexerConfig::parse(); + info!("Parsed config: {:#?}", config); + let registry_service = mysten_metrics::start_prometheus_server( + format!( + "{}:{}", + config.client_metric_host, config.client_metric_port + ) + .parse() + .unwrap(), + ); + let registry: Registry = registry_service.default_registry(); + mysten_metrics::init_metrics(®istry); + let metrics = AnalyticsMetrics::new(®istry); + let indexer_metrics = IndexerMetrics::new(®istry); + + let rest_url = config.rest_url.clone(); + let processor = make_analytics_processor(config, metrics) + .await + .map_err(|e| AnalyticsIndexerError::GenericError(e.to_string()))?; + IndexerBuilder::new(indexer_metrics) + .last_downloaded_checkpoint(processor.last_committed_checkpoint()) + .rest_url(&rest_url) + .handler(processor) + .run() + .await; + Ok(()) +} diff --git a/crates/sui-analytics-indexer/src/package_store.rs b/crates/iota-analytics-indexer/src/package_store.rs similarity index 96% rename from crates/sui-analytics-indexer/src/package_store.rs rename to crates/iota-analytics-indexer/src/package_store.rs index 44404228da3..aa345957150 100644 --- a/crates/sui-analytics-indexer/src/package_store.rs +++ b/crates/iota-analytics-indexer/src/package_store.rs @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{path::Path, sync::Arc}; use async_trait::async_trait; -use move_core_types::account_address::AccountAddress; -use sui_package_resolver::{ +use iota_package_resolver::{ error::Error as PackageResolverError, Package, PackageStore, PackageStoreWithLruCache, Result, }; -use sui_rest_api::Client; -use sui_types::{ +use iota_rest_api::Client; +use iota_types::{ base_types::{ObjectID, SequenceNumber}, object::Object, }; +use move_core_types::account_address::AccountAddress; use thiserror::Error; use typed_store::{ rocks::{DBMap, MetricConf}, diff --git a/crates/sui-analytics-indexer/src/store/bq/schemas/checkpoint.sql b/crates/iota-analytics-indexer/src/store/bq/schemas/checkpoint.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/bq/schemas/checkpoint.sql rename to crates/iota-analytics-indexer/src/store/bq/schemas/checkpoint.sql diff --git a/crates/sui-analytics-indexer/src/store/bq/schemas/event.sql b/crates/iota-analytics-indexer/src/store/bq/schemas/event.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/bq/schemas/event.sql rename to crates/iota-analytics-indexer/src/store/bq/schemas/event.sql diff --git a/crates/sui-analytics-indexer/src/store/bq/schemas/move_call.sql b/crates/iota-analytics-indexer/src/store/bq/schemas/move_call.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/bq/schemas/move_call.sql rename to crates/iota-analytics-indexer/src/store/bq/schemas/move_call.sql diff --git a/crates/sui-analytics-indexer/src/store/bq/schemas/object.sql b/crates/iota-analytics-indexer/src/store/bq/schemas/object.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/bq/schemas/object.sql rename to crates/iota-analytics-indexer/src/store/bq/schemas/object.sql diff --git a/crates/sui-analytics-indexer/src/store/bq/schemas/package.sql b/crates/iota-analytics-indexer/src/store/bq/schemas/package.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/bq/schemas/package.sql rename to crates/iota-analytics-indexer/src/store/bq/schemas/package.sql diff --git a/crates/sui-analytics-indexer/src/store/bq/schemas/transaction.sql b/crates/iota-analytics-indexer/src/store/bq/schemas/transaction.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/bq/schemas/transaction.sql rename to crates/iota-analytics-indexer/src/store/bq/schemas/transaction.sql diff --git a/crates/sui-analytics-indexer/src/store/bq/schemas/transaction_objects.sql b/crates/iota-analytics-indexer/src/store/bq/schemas/transaction_objects.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/bq/schemas/transaction_objects.sql rename to crates/iota-analytics-indexer/src/store/bq/schemas/transaction_objects.sql diff --git a/crates/sui-analytics-indexer/src/store/snowflake/schemas/checkpoint.sql b/crates/iota-analytics-indexer/src/store/snowflake/schemas/checkpoint.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/snowflake/schemas/checkpoint.sql rename to crates/iota-analytics-indexer/src/store/snowflake/schemas/checkpoint.sql diff --git a/crates/sui-analytics-indexer/src/store/snowflake/schemas/event.sql b/crates/iota-analytics-indexer/src/store/snowflake/schemas/event.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/snowflake/schemas/event.sql rename to crates/iota-analytics-indexer/src/store/snowflake/schemas/event.sql diff --git a/crates/sui-analytics-indexer/src/store/snowflake/schemas/move_call.sql b/crates/iota-analytics-indexer/src/store/snowflake/schemas/move_call.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/snowflake/schemas/move_call.sql rename to crates/iota-analytics-indexer/src/store/snowflake/schemas/move_call.sql diff --git a/crates/sui-analytics-indexer/src/store/snowflake/schemas/object.sql b/crates/iota-analytics-indexer/src/store/snowflake/schemas/object.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/snowflake/schemas/object.sql rename to crates/iota-analytics-indexer/src/store/snowflake/schemas/object.sql diff --git a/crates/sui-analytics-indexer/src/store/snowflake/schemas/package.sql b/crates/iota-analytics-indexer/src/store/snowflake/schemas/package.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/snowflake/schemas/package.sql rename to crates/iota-analytics-indexer/src/store/snowflake/schemas/package.sql diff --git a/crates/sui-analytics-indexer/src/store/snowflake/schemas/setup.sql b/crates/iota-analytics-indexer/src/store/snowflake/schemas/setup.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/snowflake/schemas/setup.sql rename to crates/iota-analytics-indexer/src/store/snowflake/schemas/setup.sql diff --git a/crates/sui-analytics-indexer/src/store/snowflake/schemas/transaction.sql b/crates/iota-analytics-indexer/src/store/snowflake/schemas/transaction.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/snowflake/schemas/transaction.sql rename to crates/iota-analytics-indexer/src/store/snowflake/schemas/transaction.sql diff --git a/crates/sui-analytics-indexer/src/store/snowflake/schemas/transaction_objects.sql b/crates/iota-analytics-indexer/src/store/snowflake/schemas/transaction_objects.sql similarity index 100% rename from crates/sui-analytics-indexer/src/store/snowflake/schemas/transaction_objects.sql rename to crates/iota-analytics-indexer/src/store/snowflake/schemas/transaction_objects.sql diff --git a/crates/iota-analytics-indexer/src/tables.rs b/crates/iota-analytics-indexer/src/tables.rs new file mode 100644 index 00000000000..6f1edf43b3e --- /dev/null +++ b/crates/iota-analytics-indexer/src/tables.rs @@ -0,0 +1,272 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +#![allow(dead_code)] + +use iota_analytics_indexer_derive::SerializeParquet; +use iota_types::dynamic_field::DynamicFieldType; +use serde::Serialize; +use strum_macros::Display; + +use crate::{ParquetSchema, ParquetValue}; + +// Table entries for the analytics database. +// Each entry is a row in the database. +// + +// Checkpoint information. +#[derive(Serialize, Clone, SerializeParquet)] +pub(crate) struct CheckpointEntry { + // indexes + pub(crate) checkpoint_digest: String, + pub(crate) sequence_number: u64, + pub(crate) epoch: u64, + pub(crate) timestamp_ms: u64, + + pub(crate) previous_checkpoint_digest: Option, + pub(crate) end_of_epoch: bool, + // gas stats + pub(crate) total_gas_cost: i64, + pub(crate) computation_cost: u64, + pub(crate) storage_cost: u64, + pub(crate) storage_rebate: u64, + pub(crate) non_refundable_storage_fee: u64, + // transaction stats + pub(crate) total_transaction_blocks: u64, + pub(crate) total_transactions: u64, + pub(crate) total_successful_transaction_blocks: u64, + pub(crate) total_successful_transactions: u64, + + pub(crate) network_total_transaction: u64, + pub(crate) validator_signature: String, +} + +// Transaction information. +#[derive(Serialize, Clone, SerializeParquet)] +pub(crate) struct TransactionEntry { + // main indexes + pub(crate) transaction_digest: String, + pub(crate) checkpoint: u64, + pub(crate) epoch: u64, + pub(crate) timestamp_ms: u64, + // transaction info + pub(crate) sender: String, + pub(crate) transaction_kind: String, + pub(crate) is_system_txn: bool, + pub(crate) is_sponsored_tx: bool, + pub(crate) transaction_count: u64, + pub(crate) execution_success: bool, + // object info + pub(crate) input: u64, + pub(crate) shared_input: u64, + pub(crate) gas_coins: u64, + // objects are broken up in created, mutated and deleted. + // No wrap or unwrap information is provided + pub(crate) created: u64, + pub(crate) mutated: u64, + pub(crate) deleted: u64, + // PTB info + pub(crate) transfers: u64, + pub(crate) split_coins: u64, + pub(crate) merge_coins: u64, + pub(crate) publish: u64, + pub(crate) upgrade: u64, + // move_vec or default for future commands + pub(crate) others: u64, + pub(crate) move_calls: u64, + // pub(crate) packages: BTreeSet, + // commas separated list of packages used by the transaction. + // Use as a simple way to query for transactions that use a specific package. + pub(crate) packages: String, + // gas info + pub(crate) gas_owner: String, + pub(crate) gas_object_id: String, + pub(crate) gas_object_sequence: u64, + pub(crate) gas_object_digest: String, + pub(crate) gas_budget: u64, + pub(crate) total_gas_cost: i64, + pub(crate) computation_cost: u64, + pub(crate) storage_cost: u64, + pub(crate) storage_rebate: u64, + pub(crate) non_refundable_storage_fee: u64, + pub(crate) gas_price: u64, + // raw transaction bytes + // pub(crate) raw_transaction: Vec, + // We represent them in base64 encoding so they work with the csv. + // TODO: review and possibly move back to Vec + pub(crate) raw_transaction: String, + pub(crate) has_zklogin_sig: bool, + pub(crate) has_upgraded_multisig: bool, + pub(crate) transaction_json: Option, + pub(crate) effects_json: Option, +} + +// Event information. +// Events identity is via `transaction_digest` and `event_index`. +#[derive(Serialize, Clone, SerializeParquet)] +pub(crate) struct EventEntry { + // indexes + pub(crate) transaction_digest: String, + pub(crate) event_index: u64, + pub(crate) checkpoint: u64, + pub(crate) epoch: u64, + pub(crate) timestamp_ms: u64, + // sender + pub(crate) sender: String, + // event type + pub(crate) package: String, + pub(crate) module: String, + pub(crate) event_type: String, + // raw event bytes + // pub(crate) bcs: Vec, + // We represent them in base64 encoding so they work with the csv. + // TODO: review and possibly move back to Vec + pub(crate) bcs: String, + pub(crate) event_json: String, +} + +// Used in the transaction object table to identify the type of input object. +#[derive(Serialize, Clone, Display)] +pub enum InputObjectKind { + Input, + SharedInput, + GasCoin, +} + +// Used in the object table to identify the status of object, its result in the +// last transaction effect. +#[derive(Serialize, Clone, Display)] +pub enum ObjectStatus { + Created, + Mutated, + Deleted, +} + +// Object owner information. +#[derive(Serialize, Clone, Display)] +pub enum OwnerType { + AddressOwner, + ObjectOwner, + Shared, + Immutable, +} + +// Object information. +// A row in the live object table. +#[derive(Serialize, Clone, SerializeParquet)] +pub(crate) struct ObjectEntry { + // indexes + pub(crate) object_id: String, + pub(crate) version: u64, + pub(crate) digest: String, + pub(crate) type_: Option, // None is for packages + pub(crate) checkpoint: u64, + pub(crate) epoch: u64, + pub(crate) timestamp_ms: u64, + // owner info + pub(crate) owner_type: Option, + pub(crate) owner_address: Option, + // object info + pub(crate) object_status: ObjectStatus, + pub(crate) initial_shared_version: Option, + pub(crate) previous_transaction: String, + pub(crate) has_public_transfer: bool, + pub(crate) storage_rebate: Option, + // raw object bytes + // pub(crate) bcs: Vec, + // We represent them in base64 encoding so they work with the csv. + // TODO: review and possibly move back to Vec + pub(crate) bcs: Option, + + pub(crate) coin_type: Option, + pub(crate) coin_balance: Option, + + pub(crate) struct_tag: Option, + pub(crate) object_json: Option, +} + +// Objects used and manipulated in a transaction. +// Both input object and objects in effects are reported here with the proper +// input kind (for input objects) and status (for objets in effects). +// An object may appear twice as an input and output object. In that case, the +// version will be different. +#[derive(Serialize, Clone, SerializeParquet)] +pub(crate) struct TransactionObjectEntry { + // indexes + pub(crate) object_id: String, + pub(crate) version: Option, + pub(crate) transaction_digest: String, + pub(crate) checkpoint: u64, + pub(crate) epoch: u64, + pub(crate) timestamp_ms: u64, + // input/output information + pub(crate) input_kind: Option, + pub(crate) object_status: Option, +} + +// A Move call expressed as a package, module and function. +#[derive(Serialize, Clone, SerializeParquet)] +pub(crate) struct MoveCallEntry { + // indexes + pub(crate) transaction_digest: String, + pub(crate) checkpoint: u64, + pub(crate) epoch: u64, + pub(crate) timestamp_ms: u64, + // move call info + pub(crate) package: String, + pub(crate) module: String, + pub(crate) function: String, +} + +// A Move package. Package id and MovePackage object bytes +#[derive(Serialize, Clone, SerializeParquet)] +pub(crate) struct MovePackageEntry { + // indexes + pub(crate) package_id: String, + pub(crate) checkpoint: u64, + pub(crate) epoch: u64, + pub(crate) timestamp_ms: u64, + // raw package bytes + // pub(crate) bcs: Vec, + // We represent them in base64 encoding so they work with the csv. + // TODO: review and possibly move back to Vec + pub(crate) bcs: String, + // txn publishing the package + pub(crate) transaction_digest: String, + pub(crate) package_version: Option, + pub(crate) original_package_id: Option, +} + +#[derive(Serialize, Clone, SerializeParquet)] +pub(crate) struct DynamicFieldEntry { + // indexes + pub(crate) parent_object_id: String, + pub(crate) transaction_digest: String, + pub(crate) checkpoint: u64, + pub(crate) epoch: u64, + pub(crate) timestamp_ms: u64, + // df information + pub(crate) name: String, + pub(crate) bcs_name: String, + pub(crate) type_: DynamicFieldType, + pub(crate) object_id: String, + pub(crate) version: u64, + pub(crate) digest: String, + pub(crate) object_type: String, +} + +// Object information. +// A row in the live object table. +#[derive(Serialize, Clone, SerializeParquet)] +pub(crate) struct WrappedObjectEntry { + // indexes + pub(crate) object_id: Option, + pub(crate) root_object_id: String, + pub(crate) root_object_version: u64, + pub(crate) checkpoint: u64, + pub(crate) epoch: u64, + pub(crate) timestamp_ms: u64, + // wrapped info + pub(crate) json_path: String, + pub(crate) struct_tag: Option, +} diff --git a/crates/sui-analytics-indexer/src/writers/csv_writer.rs b/crates/iota-analytics-indexer/src/writers/csv_writer.rs similarity index 95% rename from crates/sui-analytics-indexer/src/writers/csv_writer.rs rename to crates/iota-analytics-indexer/src/writers/csv_writer.rs index 0f6c45a9b61..befcc7e5c2e 100644 --- a/crates/sui-analytics-indexer/src/writers/csv_writer.rs +++ b/crates/iota-analytics-indexer/src/writers/csv_writer.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #![allow(dead_code)] @@ -11,9 +12,9 @@ use std::{ use anyhow::{anyhow, Result}; use csv::{Writer, WriterBuilder}; +use iota_storage::object_store::util::path_to_filesystem; +use iota_types::base_types::EpochId; use serde::Serialize; -use sui_storage::object_store::util::path_to_filesystem; -use sui_types::base_types::EpochId; use crate::{writers::AnalyticsWriter, FileFormat, FileType, ParquetSchema}; diff --git a/crates/iota-analytics-indexer/src/writers/mod.rs b/crates/iota-analytics-indexer/src/writers/mod.rs new file mode 100644 index 00000000000..9c7ccbde368 --- /dev/null +++ b/crates/iota-analytics-indexer/src/writers/mod.rs @@ -0,0 +1,25 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::Result; +use iota_types::base_types::EpochId; +use serde::Serialize; + +use crate::{FileFormat, ParquetSchema}; + +pub mod csv_writer; +pub mod parquet_writer; + +pub trait AnalyticsWriter: Send + Sync + 'static { + /// File format i.e. csv, parquet, etc + fn file_format(&self) -> Result; + /// Persist given rows into a file + fn write(&mut self, rows: &[S]) -> Result<()>; + /// Flush the current file + fn flush(&mut self, end_checkpoint_seq_num: u64) -> Result; + /// Reset internal state with given epoch and checkpoint sequence number + fn reset(&mut self, epoch_num: EpochId, start_checkpoint_seq_num: u64) -> Result<()>; + /// Approx size in bytes of the current staging file if available + fn file_size(&self) -> Result>; +} diff --git a/crates/sui-analytics-indexer/src/writers/parquet_writer.rs b/crates/iota-analytics-indexer/src/writers/parquet_writer.rs similarity index 96% rename from crates/sui-analytics-indexer/src/writers/parquet_writer.rs rename to crates/iota-analytics-indexer/src/writers/parquet_writer.rs index bd719ecbf78..fbac7ae874e 100644 --- a/crates/sui-analytics-indexer/src/writers/parquet_writer.rs +++ b/crates/iota-analytics-indexer/src/writers/parquet_writer.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -10,10 +11,10 @@ use std::{ use anyhow::{anyhow, Result}; use arrow_array::{ArrayRef, BooleanArray, Int64Array, RecordBatch, StringArray, UInt64Array}; +use iota_storage::object_store::util::path_to_filesystem; +use iota_types::base_types::EpochId; use parquet::{arrow::ArrowWriter, basic::Compression, file::properties::WriterProperties}; use serde::Serialize; -use sui_storage::object_store::util::path_to_filesystem; -use sui_types::base_types::EpochId; use crate::{AnalyticsWriter, FileFormat, FileType, ParquetSchema, ParquetValue}; diff --git a/crates/iota-archival/Cargo.toml b/crates/iota-archival/Cargo.toml new file mode 100644 index 00000000000..a83db4cdcc1 --- /dev/null +++ b/crates/iota-archival/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "iota-archival" +version = "0.1.0" +edition = "2021" +publish = false +license = "Apache-2.0" +authors = ["Mysten Labs "] + +[dependencies] +indicatif.workspace = true +anyhow.workspace = true +serde.workspace = true +byteorder.workspace = true +tracing.workspace = true +bytes.workspace = true +num_enum.workspace = true +futures.workspace = true +rand.workspace = true +object_store.workspace = true +prometheus.workspace = true +iota-config.workspace = true +iota-types = { workspace = true, features = ["test-utils"]} +iota-storage.workspace = true +fastcrypto = { workspace = true, features = ["copy_key"] } +tokio = { workspace = true, features = ["full"] } +serde_json = "1.0.95" + +[dev-dependencies] +tempfile.workspace = true +more-asserts.workspace = true +telemetry-subscribers.workspace = true +move-binary-format.workspace = true +move-core-types.workspace = true +move-package.workspace = true +tokio = { workspace = true, features = ["test-util"] } +ed25519-consensus.workspace = true +fastcrypto = { workspace = true } +iota-swarm-config.workspace = true +iota-macros.workspace = true + +[target.'cfg(msim)'.dependencies] +iota-simulator.workspace = true diff --git a/crates/iota-archival/src/lib.rs b/crates/iota-archival/src/lib.rs new file mode 100644 index 00000000000..c0fd6e31f8a --- /dev/null +++ b/crates/iota-archival/src/lib.rs @@ -0,0 +1,547 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +#![allow(dead_code)] + +pub mod reader; +pub mod writer; + +#[cfg(test)] +mod tests; + +use std::{ + fs, + io::{BufWriter, Cursor, Read, Seek, SeekFrom, Write}, + num::NonZeroUsize, + ops::Range, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, + }, + time::{Duration, Instant}, +}; + +use anyhow::{anyhow, Result}; +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use bytes::Bytes; +use fastcrypto::hash::{HashFunction, Sha3_256}; +use indicatif::{ProgressBar, ProgressStyle}; +use iota_config::{ + genesis::Genesis, node::ArchiveReaderConfig, object_storage_config::ObjectStoreConfig, +}; +use iota_storage::{ + blob::{Blob, BlobEncoding}, + compute_sha3_checksum, compute_sha3_checksum_for_bytes, + object_store::{ + util::{get, put}, + ObjectStoreGetExt, ObjectStorePutExt, + }, + SHA3_BYTES, +}; +use iota_types::{ + base_types::ExecutionData, + messages_checkpoint::{FullCheckpointContents, VerifiedCheckpointContents}, + storage::{SingleCheckpointSharedInMemoryStore, WriteStore}, +}; +use num_enum::{IntoPrimitive, TryFromPrimitive}; +use object_store::path::Path; +use prometheus::Registry; +use serde::{Deserialize, Serialize}; +use tracing::{error, info}; + +use crate::reader::{ArchiveReader, ArchiveReaderMetrics}; + +#[allow(rustdoc::invalid_html_tags)] +/// Checkpoints and summaries are persisted as blob files. Files are committed +/// to local store by duration or file size. Committed files are synced with the +/// remote store continuously. Files are optionally compressed with the zstd +/// compression format. Filenames follow the format . +/// where `checkpoint_seq_num` is the first checkpoint present in that +/// file. MANIFEST is the index and source of truth for all files present in the +/// archive. +/// +/// State Archival Directory Layout +/// - archive/ +/// - MANIFEST +/// - epoch_0/ +/// - 0.chk +/// - 0.sum +/// - 1000.chk +/// - 1000.sum +/// - 3000.chk +/// - 3000.sum +/// - ... +/// - 100000.chk +/// - 100000.sum +/// - epoch_1/ +/// - 101000.chk +/// - ... +/// Blob File Disk Format +/// ┌──────────────────────────────┐ +/// │ magic <4 byte> │ +/// ├──────────────────────────────┤ +/// │ storage format <1 byte> │ +// ├──────────────────────────────┤ +/// │ file compression <1 byte> │ +// ├──────────────────────────────┤ +/// │ ┌──────────────────────────┐ │ +/// │ │ Blob 1 │ │ +/// │ ├──────────────────────────┤ │ +/// │ │ ... │ │ +/// │ ├──────────────────────────┤ │ +/// │ │ Blob N │ │ +/// │ └──────────────────────────┘ │ +/// └──────────────────────────────┘ +/// Blob +/// ┌───────────────┬───────────────────┬──────────────┐ +/// │ len │ encoding <1 byte> │ data │ +/// └───────────────┴───────────────────┴──────────────┘ +/// +/// MANIFEST File Disk Format +/// ┌──────────────────────────────┐ +/// │ magic<4 byte> │ +/// ├──────────────────────────────┤ +/// │ serialized manifest │ +/// ├──────────────────────────────┤ +/// │ sha3 <32 bytes> │ +/// └──────────────────────────────┘ +pub const CHECKPOINT_FILE_MAGIC: u32 = 0x0000DEAD; +pub const SUMMARY_FILE_MAGIC: u32 = 0x0000CAFE; +const MANIFEST_FILE_MAGIC: u32 = 0x00C0FFEE; +const MAGIC_BYTES: usize = 4; +const CHECKPOINT_FILE_SUFFIX: &str = "chk"; +const SUMMARY_FILE_SUFFIX: &str = "sum"; +const EPOCH_DIR_PREFIX: &str = "epoch_"; +const MANIFEST_FILENAME: &str = "MANIFEST"; + +#[derive( + Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, TryFromPrimitive, IntoPrimitive, +)] +#[repr(u8)] +pub enum FileType { + CheckpointContent = 0, + CheckpointSummary, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +pub struct FileMetadata { + pub file_type: FileType, + pub epoch_num: u64, + pub checkpoint_seq_range: Range, + pub sha3_digest: [u8; 32], +} + +impl FileMetadata { + pub fn file_path(&self) -> Path { + let dir_path = Path::from(format!("{}{}", EPOCH_DIR_PREFIX, self.epoch_num)); + match self.file_type { + FileType::CheckpointContent => dir_path.child(&*format!( + "{}.{CHECKPOINT_FILE_SUFFIX}", + self.checkpoint_seq_range.start + )), + FileType::CheckpointSummary => dir_path.child(&*format!( + "{}.{SUMMARY_FILE_SUFFIX}", + self.checkpoint_seq_range.start + )), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +pub struct ManifestV1 { + pub archive_version: u8, + pub next_checkpoint_seq_num: u64, + pub file_metadata: Vec, + pub epoch: u64, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub enum Manifest { + V1(ManifestV1), +} + +impl Manifest { + pub fn new(epoch: u64, next_checkpoint_seq_num: u64) -> Self { + Manifest::V1(ManifestV1 { + archive_version: 1, + next_checkpoint_seq_num, + file_metadata: vec![], + epoch, + }) + } + pub fn files(&self) -> Vec { + match self { + Manifest::V1(manifest) => manifest.file_metadata.clone(), + } + } + pub fn epoch_num(&self) -> u64 { + match self { + Manifest::V1(manifest) => manifest.epoch, + } + } + pub fn next_checkpoint_seq_num(&self) -> u64 { + match self { + Manifest::V1(manifest) => manifest.next_checkpoint_seq_num, + } + } + pub fn next_checkpoint_after_epoch(&self, epoch_num: u64) -> u64 { + match self { + Manifest::V1(manifest) => { + let mut summary_files: Vec<_> = manifest + .file_metadata + .clone() + .into_iter() + .filter(|f| f.file_type == FileType::CheckpointSummary) + .collect(); + summary_files.sort_by_key(|f| f.checkpoint_seq_range.start); + assert!( + summary_files + .windows(2) + .all(|w| w[1].checkpoint_seq_range.start == w[0].checkpoint_seq_range.end) + ); + assert_eq!(summary_files.first().unwrap().checkpoint_seq_range.start, 0); + summary_files + .iter() + .find(|f| f.epoch_num > epoch_num) + .map(|f| f.checkpoint_seq_range.start) + .unwrap_or(u64::MAX) + } + } + } + pub fn update( + &mut self, + epoch_num: u64, + checkpoint_sequence_number: u64, + checkpoint_file_metadata: FileMetadata, + summary_file_metadata: FileMetadata, + ) { + match self { + Manifest::V1(manifest) => { + manifest + .file_metadata + .extend(vec![checkpoint_file_metadata, summary_file_metadata]); + manifest.epoch = epoch_num; + manifest.next_checkpoint_seq_num = checkpoint_sequence_number; + } + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +pub struct CheckpointUpdates { + checkpoint_file_metadata: FileMetadata, + summary_file_metadata: FileMetadata, + manifest: Manifest, +} + +impl CheckpointUpdates { + pub fn new( + epoch_num: u64, + checkpoint_sequence_number: u64, + checkpoint_file_metadata: FileMetadata, + summary_file_metadata: FileMetadata, + manifest: &mut Manifest, + ) -> Self { + manifest.update( + epoch_num, + checkpoint_sequence_number, + checkpoint_file_metadata.clone(), + summary_file_metadata.clone(), + ); + CheckpointUpdates { + checkpoint_file_metadata, + summary_file_metadata, + manifest: manifest.clone(), + } + } + pub fn content_file_path(&self) -> Path { + self.checkpoint_file_metadata.file_path() + } + pub fn summary_file_path(&self) -> Path { + self.summary_file_metadata.file_path() + } + pub fn manifest_file_path(&self) -> Path { + Path::from(MANIFEST_FILENAME) + } +} + +pub fn create_file_metadata( + file_path: &std::path::Path, + file_type: FileType, + epoch_num: u64, + checkpoint_seq_range: Range, +) -> Result { + let sha3_digest = compute_sha3_checksum(file_path)?; + let file_metadata = FileMetadata { + file_type, + epoch_num, + checkpoint_seq_range, + sha3_digest, + }; + Ok(file_metadata) +} + +pub fn create_file_metadata_from_bytes( + bytes: Bytes, + file_type: FileType, + epoch_num: u64, + checkpoint_seq_range: Range, +) -> Result { + let sha3_digest = compute_sha3_checksum_for_bytes(bytes)?; + let file_metadata = FileMetadata { + file_type, + epoch_num, + checkpoint_seq_range, + sha3_digest, + }; + Ok(file_metadata) +} + +pub async fn read_manifest(remote_store: S) -> Result { + let manifest_file_path = Path::from(MANIFEST_FILENAME); + let vec = get(&remote_store, &manifest_file_path).await?.to_vec(); + read_manifest_from_bytes(vec) +} + +pub fn read_manifest_from_bytes(vec: Vec) -> Result { + let manifest_file_size = vec.len(); + let mut manifest_reader = Cursor::new(vec); + manifest_reader.rewind()?; + let magic = manifest_reader.read_u32::()?; + if magic != MANIFEST_FILE_MAGIC { + return Err(anyhow!("Unexpected magic byte in manifest: {}", magic)); + } + manifest_reader.seek(SeekFrom::End(-(SHA3_BYTES as i64)))?; + let mut sha3_digest = [0u8; SHA3_BYTES]; + manifest_reader.read_exact(&mut sha3_digest)?; + manifest_reader.rewind()?; + let mut content_buf = vec![0u8; manifest_file_size - SHA3_BYTES]; + manifest_reader.read_exact(&mut content_buf)?; + let mut hasher = Sha3_256::default(); + hasher.update(&content_buf); + let computed_digest = hasher.finalize().digest; + if computed_digest != sha3_digest { + return Err(anyhow!( + "Manifest corrupted, computed checksum: {:?}, stored checksum: {:?}", + computed_digest, + sha3_digest + )); + } + manifest_reader.rewind()?; + manifest_reader.seek(SeekFrom::Start(MAGIC_BYTES as u64))?; + Blob::read(&mut manifest_reader)?.decode() +} + +pub fn finalize_manifest(manifest: Manifest) -> Result { + let mut buf = BufWriter::new(vec![]); + buf.write_u32::(MANIFEST_FILE_MAGIC)?; + let blob = Blob::encode(&manifest, BlobEncoding::Bcs)?; + blob.write(&mut buf)?; + buf.flush()?; + let mut hasher = Sha3_256::default(); + hasher.update(buf.get_ref()); + let computed_digest = hasher.finalize().digest; + buf.write_all(&computed_digest)?; + Ok(Bytes::from(buf.into_inner()?)) +} + +pub async fn write_manifest( + manifest: Manifest, + remote_store: S, +) -> Result<()> { + let path = Path::from(MANIFEST_FILENAME); + let bytes = finalize_manifest(manifest)?; + put(&remote_store, &path, bytes).await?; + Ok(()) +} + +pub async fn read_manifest_as_json(remote_store_config: ObjectStoreConfig) -> Result { + let metrics = ArchiveReaderMetrics::new(&Registry::default()); + let config = ArchiveReaderConfig { + remote_store_config, + download_concurrency: NonZeroUsize::new(1).unwrap(), + use_for_pruning_watermark: false, + }; + let archive_reader = ArchiveReader::new(config, &metrics)?; + archive_reader.sync_manifest_once().await?; + let manifest = archive_reader.get_manifest().await?; + let json = serde_json::to_string(&manifest).expect("Failed to serialize object"); + Ok(json) +} + +pub async fn write_manifest_from_json( + remote_store_config: ObjectStoreConfig, + json_manifest_path: std::path::PathBuf, +) -> Result<()> { + let manifest: Manifest = serde_json::from_str(&fs::read_to_string(json_manifest_path)?)?; + let store = remote_store_config.make()?; + write_manifest(manifest, store).await?; + Ok(()) +} + +pub async fn verify_archive_with_genesis_config( + genesis: &std::path::Path, + remote_store_config: ObjectStoreConfig, + concurrency: usize, + interactive: bool, + num_retries: u32, +) -> Result<()> { + let genesis = Genesis::load(genesis).unwrap(); + let genesis_committee = genesis.committee()?; + let mut store = SingleCheckpointSharedInMemoryStore::default(); + let contents = genesis.checkpoint_contents(); + let fullcheckpoint_contents = FullCheckpointContents::from_contents_and_execution_data( + contents.clone(), + std::iter::once(ExecutionData::new( + genesis.transaction().clone(), + genesis.effects().clone(), + )), + ); + store.insert_genesis_state( + genesis.checkpoint(), + VerifiedCheckpointContents::new_unchecked(fullcheckpoint_contents), + genesis_committee, + ); + + let num_retries = std::cmp::max(num_retries, 1); + for _ in 0..num_retries { + match verify_archive_with_local_store( + store.clone(), + remote_store_config.clone(), + concurrency, + interactive, + ) + .await + { + Ok(_) => return Ok(()), + Err(e) => { + error!("Error while verifying archive: {}", e); + tokio::time::sleep(Duration::from_secs(10)).await; + } + } + } + + Err::<(), anyhow::Error>(anyhow!( + "Failed to verify archive after {} retries", + num_retries + )) +} + +pub async fn verify_archive_with_checksums( + remote_store_config: ObjectStoreConfig, + concurrency: usize, +) -> Result<()> { + let metrics = ArchiveReaderMetrics::new(&Registry::default()); + let config = ArchiveReaderConfig { + remote_store_config, + download_concurrency: NonZeroUsize::new(concurrency).unwrap(), + use_for_pruning_watermark: false, + }; + let archive_reader = ArchiveReader::new(config, &metrics)?; + archive_reader.sync_manifest_once().await?; + let manifest = archive_reader.get_manifest().await?; + info!( + "Next checkpoint in archive store: {}", + manifest.next_checkpoint_seq_num() + ); + + let file_metadata = archive_reader.verify_manifest(manifest).await?; + // Account for both summary and content files + let num_files = file_metadata.len() * 2; + archive_reader + .verify_file_consistency(file_metadata) + .await?; + info!("All {} files are valid", num_files); + Ok(()) +} + +pub async fn verify_archive_with_local_store( + store: S, + remote_store_config: ObjectStoreConfig, + concurrency: usize, + interactive: bool, +) -> Result<()> +where + S: WriteStore + Clone + Send + 'static, +{ + let metrics = ArchiveReaderMetrics::new(&Registry::default()); + let config = ArchiveReaderConfig { + remote_store_config, + download_concurrency: NonZeroUsize::new(concurrency).unwrap(), + use_for_pruning_watermark: false, + }; + let archive_reader = ArchiveReader::new(config, &metrics)?; + archive_reader.sync_manifest_once().await?; + let latest_checkpoint_in_archive = archive_reader.latest_available_checkpoint().await?; + info!( + "Latest available checkpoint in archive store: {}", + latest_checkpoint_in_archive + ); + let latest_checkpoint = store + .get_highest_synced_checkpoint() + .map_err(|_| anyhow!("Failed to read highest synced checkpoint"))? + .sequence_number; + info!("Highest synced checkpoint in db: {latest_checkpoint}"); + let txn_counter = Arc::new(AtomicU64::new(0)); + let checkpoint_counter = Arc::new(AtomicU64::new(0)); + let progress_bar = if interactive { + let progress_bar = ProgressBar::new(latest_checkpoint_in_archive).with_style( + ProgressStyle::with_template("[{elapsed_precise}] {wide_bar} {pos}/{len}({msg})") + .unwrap(), + ); + let cloned_progress_bar = progress_bar.clone(); + let cloned_counter = txn_counter.clone(); + let cloned_checkpoint_counter = checkpoint_counter.clone(); + let instant = Instant::now(); + tokio::spawn(async move { + loop { + let total_checkpoints_loaded = cloned_checkpoint_counter.load(Ordering::Relaxed); + let total_checkpoints_per_sec = + total_checkpoints_loaded as f64 / instant.elapsed().as_secs_f64(); + let total_txns_per_sec = + cloned_counter.load(Ordering::Relaxed) as f64 / instant.elapsed().as_secs_f64(); + cloned_progress_bar.set_position(latest_checkpoint + total_checkpoints_loaded); + cloned_progress_bar.set_message(format!( + "checkpoints/s: {}, txns/s: {}", + total_checkpoints_per_sec, total_txns_per_sec + )); + tokio::time::sleep(Duration::from_secs(1)).await; + } + }); + Some(progress_bar) + } else { + let cloned_store = store.clone(); + tokio::spawn(async move { + loop { + let latest_checkpoint = cloned_store + .get_highest_synced_checkpoint() + .map_err(|_| anyhow!("Failed to read highest synced checkpoint"))? + .sequence_number; + let percent = (latest_checkpoint * 100) / latest_checkpoint_in_archive; + info!("done = {percent}%"); + tokio::time::sleep(Duration::from_secs(60)).await; + if percent >= 100 { + break; + } + } + Ok::<(), anyhow::Error>(()) + }); + None + }; + archive_reader + .read( + store.clone(), + (latest_checkpoint + 1)..u64::MAX, + txn_counter, + checkpoint_counter, + true, + ) + .await?; + progress_bar.iter().for_each(|p| p.finish_and_clear()); + let end = store + .get_highest_synced_checkpoint() + .map_err(|_| anyhow!("Failed to read watermark"))? + .sequence_number; + info!("Highest verified checkpoint: {}", end); + Ok(()) +} diff --git a/crates/iota-archival/src/reader.rs b/crates/iota-archival/src/reader.rs new file mode 100644 index 00000000000..4b43905f133 --- /dev/null +++ b/crates/iota-archival/src/reader.rs @@ -0,0 +1,649 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + borrow::Borrow, + future, + ops::Range, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, + }, + time::Duration, +}; + +use anyhow::{anyhow, Context, Result}; +use bytes::{buf::Reader, Buf, Bytes}; +use futures::{StreamExt, TryStreamExt}; +use iota_config::node::ArchiveReaderConfig; +use iota_storage::{ + compute_sha3_checksum_for_bytes, make_iterator, + object_store::{http::HttpDownloaderBuilder, util::get, ObjectStoreGetExt}, + verify_checkpoint, +}; +use iota_types::{ + messages_checkpoint::{ + CertifiedCheckpointSummary, CheckpointSequenceNumber, + FullCheckpointContents as CheckpointContents, VerifiedCheckpoint, + VerifiedCheckpointContents, + }, + storage::WriteStore, +}; +use prometheus::{register_int_counter_vec_with_registry, IntCounterVec, Registry}; +use rand::seq::SliceRandom; +use tokio::sync::{oneshot, oneshot::Sender, Mutex}; +use tracing::info; + +use crate::{ + read_manifest, FileMetadata, FileType, Manifest, CHECKPOINT_FILE_MAGIC, SUMMARY_FILE_MAGIC, +}; + +#[derive(Debug)] +pub struct ArchiveReaderMetrics { + pub archive_txns_read: IntCounterVec, + pub archive_checkpoints_read: IntCounterVec, +} + +impl ArchiveReaderMetrics { + pub fn new(registry: &Registry) -> Arc { + let this = Self { + archive_txns_read: register_int_counter_vec_with_registry!( + "archive_txns_read", + "Number of transactions read from archive", + &["bucket"], + registry + ) + .unwrap(), + archive_checkpoints_read: register_int_counter_vec_with_registry!( + "archive_checkpoints_read", + "Number of checkpoints read from archive", + &["bucket"], + registry + ) + .unwrap(), + }; + Arc::new(this) + } +} + +// ArchiveReaderBalancer selects archives for reading based on whether they can +// fulfill a checkpoint request +#[derive(Default, Clone)] +pub struct ArchiveReaderBalancer { + readers: Vec>, +} + +impl ArchiveReaderBalancer { + pub fn new(configs: Vec, registry: &Registry) -> Result { + let mut readers = vec![]; + let metrics = ArchiveReaderMetrics::new(registry); + for config in configs.into_iter() { + readers.push(Arc::new(ArchiveReader::new(config.clone(), &metrics)?)); + } + Ok(ArchiveReaderBalancer { readers }) + } + pub async fn get_archive_watermark(&self) -> Result> { + let mut checkpoints: Vec> = vec![]; + for reader in self + .readers + .iter() + .filter(|r| r.use_for_pruning_watermark()) + { + let latest_checkpoint = reader.latest_available_checkpoint().await; + info!( + "Latest archived checkpoint in remote store: {:?} is: {:?}", + reader.remote_store_identifier(), + latest_checkpoint + ); + checkpoints.push(latest_checkpoint) + } + let checkpoints: Result> = checkpoints.into_iter().collect(); + checkpoints.map(|vec| vec.into_iter().min()) + } + pub async fn pick_one_random( + &self, + checkpoint_range: Range, + ) -> Option> { + let mut archives_with_complete_range = vec![]; + for reader in self.readers.iter() { + let latest_checkpoint = reader.latest_available_checkpoint().await.unwrap_or(0); + if latest_checkpoint >= checkpoint_range.end { + archives_with_complete_range.push(reader.clone()); + } + } + if !archives_with_complete_range.is_empty() { + return Some( + archives_with_complete_range + .choose(&mut rand::thread_rng()) + .unwrap() + .clone(), + ); + } + let mut archives_with_partial_range = vec![]; + for reader in self.readers.iter() { + let latest_checkpoint = reader.latest_available_checkpoint().await.unwrap_or(0); + if latest_checkpoint >= checkpoint_range.start { + archives_with_partial_range.push(reader.clone()); + } + } + if !archives_with_partial_range.is_empty() { + return Some( + archives_with_partial_range + .choose(&mut rand::thread_rng()) + .unwrap() + .clone(), + ); + } + None + } +} + +#[derive(Clone)] +pub struct ArchiveReader { + bucket: String, + concurrency: usize, + sender: Arc>, + manifest: Arc>, + use_for_pruning_watermark: bool, + remote_object_store: Arc, + archive_reader_metrics: Arc, +} + +impl ArchiveReader { + pub fn new(config: ArchiveReaderConfig, metrics: &Arc) -> Result { + let bucket = config + .remote_store_config + .bucket + .clone() + .unwrap_or("unknown".to_string()); + let remote_object_store = if config.remote_store_config.no_sign_request { + config.remote_store_config.make_http()? + } else { + config.remote_store_config.make().map(Arc::new)? + }; + let (sender, recv) = oneshot::channel(); + let manifest = Arc::new(Mutex::new(Manifest::new(0, 0))); + // Start a background tokio task to keep local manifest in sync with remote + Self::spawn_manifest_sync_task(remote_object_store.clone(), manifest.clone(), recv); + Ok(ArchiveReader { + bucket, + manifest, + sender: Arc::new(sender), + remote_object_store, + use_for_pruning_watermark: config.use_for_pruning_watermark, + concurrency: config.download_concurrency.get(), + archive_reader_metrics: metrics.clone(), + }) + } + + /// This function verifies that the files in archive cover the entire range + /// of checkpoints from sequence number 0 until the latest available + /// checkpoint with no missing checkpoint + pub async fn verify_manifest( + &self, + manifest: Manifest, + ) -> Result> { + let files = manifest.files(); + if files.is_empty() { + return Err(anyhow!("Unexpected empty archive store")); + } + + let mut summary_files: Vec<_> = files + .clone() + .into_iter() + .filter(|f| f.file_type == FileType::CheckpointSummary) + .collect(); + let mut contents_files: Vec<_> = files + .into_iter() + .filter(|f| f.file_type == FileType::CheckpointContent) + .collect(); + assert_eq!(summary_files.len(), contents_files.len()); + + summary_files.sort_by_key(|f| f.checkpoint_seq_range.start); + contents_files.sort_by_key(|f| f.checkpoint_seq_range.start); + + assert!( + summary_files + .windows(2) + .all(|w| w[1].checkpoint_seq_range.start == w[0].checkpoint_seq_range.end) + ); + assert!( + contents_files + .windows(2) + .all(|w| w[1].checkpoint_seq_range.start == w[0].checkpoint_seq_range.end) + ); + + let files: Vec<(FileMetadata, FileMetadata)> = summary_files + .into_iter() + .zip(contents_files.into_iter()) + .map(|(s, c)| { + assert_eq!(s.checkpoint_seq_range, c.checkpoint_seq_range); + (s, c) + }) + .collect(); + + assert_eq!(files.first().unwrap().0.checkpoint_seq_range.start, 0); + + Ok(files) + } + + /// This function downloads summary and content files and ensures their + /// computed checksum matches the one in manifest + pub async fn verify_file_consistency( + &self, + files: Vec<(FileMetadata, FileMetadata)>, + ) -> Result<()> { + let remote_object_store = self.remote_object_store.clone(); + futures::stream::iter(files.iter()) + .enumerate() + .map(|(_, (summary_metadata, content_metadata))| { + let remote_object_store = remote_object_store.clone(); + async move { + let summary_data = + get(&remote_object_store, &summary_metadata.file_path()).await?; + let content_data = + get(&remote_object_store, &content_metadata.file_path()).await?; + Ok::<((Bytes, &FileMetadata), (Bytes, &FileMetadata)), anyhow::Error>(( + (summary_data, summary_metadata), + (content_data, content_metadata), + )) + } + }) + .boxed() + .buffer_unordered(self.concurrency) + .try_for_each( + |((summary_data, summary_metadata), (content_data, content_metadata))| { + let checksums = compute_sha3_checksum_for_bytes(summary_data).and_then(|s| { + compute_sha3_checksum_for_bytes(content_data).map(|c| (s, c)) + }); + let result = checksums.and_then(|(summary_checksum, content_checksum)| { + (summary_checksum == summary_metadata.sha3_digest) + .then_some(()) + .ok_or(anyhow!( + "Summary checksum doesn't match for file: {:?}", + summary_metadata.file_path() + ))?; + (content_checksum == content_metadata.sha3_digest) + .then_some(()) + .ok_or(anyhow!( + "Content checksum doesn't match for file: {:?}", + content_metadata.file_path() + ))?; + Ok::<(), anyhow::Error>(()) + }); + futures::future::ready(result) + }, + ) + .await + } + + /// Load checkpoints+txns+effects from archive into the input store `S` for + /// the given checkpoint range. Summaries are downloaded out of order + /// and inserted without verification + pub async fn read_summaries( + &self, + store: S, + checkpoint_range: Range, + checkpoint_counter: Arc, + verify: bool, + ) -> Result<()> + where + S: WriteStore + Clone, + { + let (summary_files, start_index, end_index) = + self.get_summary_files(checkpoint_range.clone()).await?; + let remote_object_store = self.remote_object_store.clone(); + let stream = futures::stream::iter(summary_files.iter()) + .enumerate() + .filter(|(index, _s)| future::ready(*index >= start_index && *index < end_index)) + .map(|(_, summary_metadata)| { + let remote_object_store = remote_object_store.clone(); + async move { + let summary_data = + get(&remote_object_store, &summary_metadata.file_path()).await?; + Ok::(summary_data) + } + }) + .boxed(); + if verify { + stream + .buffered(self.concurrency) + .try_for_each(|summary_data| { + let result: Result<(), anyhow::Error> = + make_iterator::>( + SUMMARY_FILE_MAGIC, + summary_data.reader(), + ) + .and_then(|summary_iter| { + summary_iter + .filter(|s| { + s.sequence_number >= checkpoint_range.start + && s.sequence_number < checkpoint_range.end + }) + .try_for_each(|summary| { + let verified_checkpoint = Self::get_or_insert_verified_checkpoint( + &store, + summary.clone(), + true, + ) + .unwrap_or_else(|_| { + panic!( + "Checkpoint verification failed for checkpoint {}", + summary.sequence_number + ) + }); + // Update highest synced watermark + store + .update_highest_verified_checkpoint(&verified_checkpoint) + .expect("Failed to update watermark"); + checkpoint_counter.fetch_add(1, Ordering::Relaxed); + Ok::<(), anyhow::Error>(()) + }) + }); + futures::future::ready(result) + }) + .await + } else { + stream + .buffer_unordered(self.concurrency) + .try_for_each(|summary_data| { + let result: Result<(), anyhow::Error> = + make_iterator::>( + SUMMARY_FILE_MAGIC, + summary_data.reader(), + ) + .and_then(|summary_iter| { + summary_iter + .filter(|s| { + s.sequence_number >= checkpoint_range.start + && s.sequence_number < checkpoint_range.end + }) + .try_for_each(|summary| { + Self::insert_certified_checkpoint(&store, summary)?; + checkpoint_counter.fetch_add(1, Ordering::Relaxed); + Ok::<(), anyhow::Error>(()) + }) + }); + futures::future::ready(result) + }) + .await + } + } + + /// Load checkpoints+txns+effects from archive into the input store `S` for + /// the given checkpoint range. If latest available checkpoint in + /// archive is older than the start of the input range then this call + /// fails with an error otherwise we load as many checkpoints as + /// possible until the end of the provided checkpoint range. + pub async fn read( + &self, + store: S, + checkpoint_range: Range, + txn_counter: Arc, + checkpoint_counter: Arc, + verify: bool, + ) -> Result<()> + where + S: WriteStore + Clone, + { + let manifest = self.manifest.lock().await.clone(); + + let latest_available_checkpoint = manifest + .next_checkpoint_seq_num() + .checked_sub(1) + .context("Checkpoint seq num underflow")?; + + if checkpoint_range.start > latest_available_checkpoint { + return Err(anyhow!( + "Latest available checkpoint is: {}", + latest_available_checkpoint + )); + } + + let files: Vec<(FileMetadata, FileMetadata)> = self.verify_manifest(manifest).await?; + + let start_index = match files.binary_search_by_key(&checkpoint_range.start, |(s, _c)| { + s.checkpoint_seq_range.start + }) { + Ok(index) => index, + Err(index) => index - 1, + }; + + let end_index = match files.binary_search_by_key(&checkpoint_range.end, |(s, _c)| { + s.checkpoint_seq_range.start + }) { + Ok(index) => index, + Err(index) => index, + }; + + let remote_object_store = self.remote_object_store.clone(); + futures::stream::iter(files.iter()) + .enumerate() + .filter(|(index, (_s, _c))| future::ready(*index >= start_index && *index < end_index)) + .map(|(_, (summary_metadata, content_metadata))| { + let remote_object_store = remote_object_store.clone(); + async move { + let summary_data = + get(&remote_object_store, &summary_metadata.file_path()).await?; + let content_data = + get(&remote_object_store, &content_metadata.file_path()).await?; + Ok::<(Bytes, Bytes), anyhow::Error>((summary_data, content_data)) + } + }) + .boxed() + .buffered(self.concurrency) + .try_for_each(|(summary_data, content_data)| { + let result: Result<(), anyhow::Error> = make_iterator::< + CertifiedCheckpointSummary, + Reader, + >( + SUMMARY_FILE_MAGIC, summary_data.reader() + ) + .and_then(|s| { + make_iterator::>( + CHECKPOINT_FILE_MAGIC, + content_data.reader(), + ) + .map(|c| (s, c)) + }) + .and_then(|(summary_iter, content_iter)| { + summary_iter + .zip(content_iter) + .filter(|(s, _c)| { + s.sequence_number >= checkpoint_range.start + && s.sequence_number < checkpoint_range.end + }) + .try_for_each(|(summary, contents)| { + let verified_checkpoint = + Self::get_or_insert_verified_checkpoint(&store, summary, verify)?; + // Verify content + let digest = verified_checkpoint.content_digest; + contents.verify_digests(digest)?; + let verified_contents = + VerifiedCheckpointContents::new_unchecked(contents.clone()); + // Insert content + store + .insert_checkpoint_contents(&verified_checkpoint, verified_contents) + .map_err(|e| anyhow!("Failed to insert content: {e}"))?; + // Update highest synced watermark + store + .update_highest_synced_checkpoint(&verified_checkpoint) + .map_err(|e| anyhow!("Failed to update watermark: {e}"))?; + txn_counter.fetch_add(contents.size() as u64, Ordering::Relaxed); + self.archive_reader_metrics + .archive_txns_read + .with_label_values(&[&self.bucket]) + .inc_by(contents.size() as u64); + checkpoint_counter.fetch_add(1, Ordering::Relaxed); + self.archive_reader_metrics + .archive_checkpoints_read + .with_label_values(&[&self.bucket]) + .inc_by(1); + Ok::<(), anyhow::Error>(()) + }) + }); + futures::future::ready(result) + }) + .await + } + + /// Return latest available checkpoint in archive + pub async fn latest_available_checkpoint(&self) -> Result { + let manifest = self.manifest.lock().await.clone(); + manifest + .next_checkpoint_seq_num() + .checked_sub(1) + .context("No checkpoint data in archive") + } + + pub fn use_for_pruning_watermark(&self) -> bool { + self.use_for_pruning_watermark + } + + pub fn remote_store_identifier(&self) -> String { + self.remote_object_store.to_string() + } + + pub async fn sync_manifest_once(&self) -> Result<()> { + Self::sync_manifest(self.remote_object_store.clone(), self.manifest.clone()).await?; + Ok(()) + } + + pub async fn get_manifest(&self) -> Result { + Ok(self.manifest.lock().await.clone()) + } + + async fn sync_manifest( + remote_store: Arc, + manifest: Arc>, + ) -> Result<()> { + let new_manifest = read_manifest(remote_store.clone()).await?; + let mut locked = manifest.lock().await; + *locked = new_manifest; + Ok(()) + } + + /// Insert checkpoint summary without verifying it + fn insert_certified_checkpoint( + store: &S, + certified_checkpoint: CertifiedCheckpointSummary, + ) -> Result<()> + where + S: WriteStore + Clone, + { + store + .insert_checkpoint(VerifiedCheckpoint::new_unchecked(certified_checkpoint).borrow()) + .map_err(|e| anyhow!("Failed to insert checkpoint: {e}")) + } + + /// Insert checkpoint summary if it doesn't already exist after verifying it + fn get_or_insert_verified_checkpoint( + store: &S, + certified_checkpoint: CertifiedCheckpointSummary, + verify: bool, + ) -> Result + where + S: WriteStore + Clone, + { + store + .get_checkpoint_by_sequence_number(certified_checkpoint.sequence_number) + .map_err(|e| anyhow!("Store op failed: {e}"))? + .map(Ok::) + .unwrap_or_else(|| { + let verified_checkpoint = if verify { + // Verify checkpoint summary + let prev_checkpoint_seq_num = certified_checkpoint + .sequence_number + .checked_sub(1) + .context("Checkpoint seq num underflow")?; + let prev_checkpoint = store + .get_checkpoint_by_sequence_number(prev_checkpoint_seq_num) + .map_err(|e| anyhow!("Store op failed: {e}"))? + .context(format!( + "Missing previous checkpoint {} in store", + prev_checkpoint_seq_num + ))?; + + verify_checkpoint(&prev_checkpoint, store, certified_checkpoint) + .map_err(|_| anyhow!("Checkpoint verification failed"))? + } else { + VerifiedCheckpoint::new_unchecked(certified_checkpoint) + }; + // Insert checkpoint summary + store + .insert_checkpoint(&verified_checkpoint) + .map_err(|e| anyhow!("Failed to insert checkpoint: {e}"))?; + // Update highest verified checkpoint watermark + store + .update_highest_verified_checkpoint(&verified_checkpoint) + .expect("store operation should not fail"); + Ok::(verified_checkpoint) + }) + .map_err(|e| anyhow!("Failed to get verified checkpoint: {:?}", e)) + } + + async fn get_summary_files( + &self, + checkpoint_range: Range, + ) -> Result<(Vec, usize, usize)> { + let manifest = self.manifest.lock().await.clone(); + + let latest_available_checkpoint = manifest + .next_checkpoint_seq_num() + .checked_sub(1) + .context("Checkpoint seq num underflow")?; + + if checkpoint_range.start > latest_available_checkpoint { + return Err(anyhow!( + "Latest available checkpoint is: {}", + latest_available_checkpoint + )); + } + + let summary_files: Vec = self + .verify_manifest(manifest) + .await? + .iter() + .map(|(s, _)| s.clone()) + .collect(); + + let start_index = match summary_files + .binary_search_by_key(&checkpoint_range.start, |s| s.checkpoint_seq_range.start) + { + Ok(index) => index, + Err(index) => index - 1, + }; + + let end_index = match summary_files + .binary_search_by_key(&checkpoint_range.end, |s| s.checkpoint_seq_range.start) + { + Ok(index) => index, + Err(index) => index, + }; + + Ok((summary_files, start_index, end_index)) + } + + fn spawn_manifest_sync_task( + remote_store: S, + manifest: Arc>, + mut recv: oneshot::Receiver<()>, + ) { + tokio::task::spawn(async move { + let mut interval = tokio::time::interval(Duration::from_secs(60)); + loop { + tokio::select! { + _ = interval.tick() => { + let new_manifest = read_manifest(remote_store.clone()).await?; + let mut locked = manifest.lock().await; + *locked = new_manifest; + } + _ = &mut recv => break, + } + } + info!("Terminating the manifest sync loop"); + Ok::<(), anyhow::Error>(()) + }); + } +} diff --git a/crates/iota-archival/src/tests.rs b/crates/iota-archival/src/tests.rs new file mode 100644 index 00000000000..aa2daa95f8a --- /dev/null +++ b/crates/iota-archival/src/tests.rs @@ -0,0 +1,389 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + fs, + fs::File, + io::Write, + num::NonZeroUsize, + path::PathBuf, + sync::{atomic::AtomicU64, Arc}, + time::Duration, +}; + +use anyhow::{anyhow, Context, Result}; +use iota_config::{ + node::ArchiveReaderConfig, + object_storage_config::{ObjectStoreConfig, ObjectStoreType}, +}; +use iota_storage::{object_store::util::path_to_filesystem, FileCompression, StorageFormat}; +use iota_swarm_config::test_utils::{empty_contents, CommitteeFixture}; +use iota_types::{ + messages_checkpoint::{VerifiedCheckpoint, VerifiedCheckpointContents}, + storage::{ReadStore, SharedInMemoryStore, SingleCheckpointSharedInMemoryStore}, +}; +use more_asserts as ma; +use object_store::DynObjectStore; +use prometheus::Registry; +use tempfile::tempdir; + +use crate::{ + read_manifest, + reader::{ArchiveReader, ArchiveReaderMetrics}, + verify_archive_with_local_store, write_manifest, + writer::ArchiveWriter, + Manifest, +}; + +struct TestState { + archive_writer: ArchiveWriter, + archive_reader: ArchiveReader, + local_path: PathBuf, + remote_path: PathBuf, + local_store: Arc, + remote_store: Arc, + local_store_config: ObjectStoreConfig, + remote_store_config: ObjectStoreConfig, + committee: CommitteeFixture, +} + +fn temp_dir() -> std::path::PathBuf { + tempdir() + .expect("Failed to open temporary directory") + .into_path() +} + +async fn write_new_checkpoints_to_store( + test_state: &TestState, + store: SharedInMemoryStore, + num_checkpoints: usize, + prev_checkpoint: Option, +) -> Result> { + let (ordered_checkpoints, _contents, _sequence_number_to_digest, _checkpoints) = test_state + .committee + .make_empty_checkpoints(num_checkpoints, prev_checkpoint.clone()); + if prev_checkpoint.is_none() { + store.inner_mut().insert_genesis_state( + ordered_checkpoints.first().cloned().unwrap(), + empty_contents(), + test_state.committee.committee().to_owned(), + ); + } + for checkpoint in ordered_checkpoints.iter() { + store.inner_mut().insert_checkpoint(checkpoint); + } + Ok(ordered_checkpoints.last().cloned()) +} + +async fn setup_test_state(temp_dir: PathBuf) -> anyhow::Result { + let local_path = temp_dir.join("local_dir"); + let remote_path = temp_dir.join("remote_dir"); + let local_store_config = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(local_path.clone()), + ..Default::default() + }; + let remote_store_config = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(remote_path.clone()), + ..Default::default() + }; + let committee = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); + let archive_writer = ArchiveWriter::new( + local_store_config.clone(), + remote_store_config.clone(), + FileCompression::Zstd, + StorageFormat::Blob, + Duration::from_secs(10), + 20, + &Registry::default(), + ) + .await?; + let archive_reader_config = ArchiveReaderConfig { + remote_store_config: remote_store_config.clone(), + download_concurrency: NonZeroUsize::new(2).unwrap(), + use_for_pruning_watermark: false, + }; + let metrics = ArchiveReaderMetrics::new(&Registry::default()); + let archive_reader = ArchiveReader::new(archive_reader_config, &metrics)?; + let local_store = local_store_config.make()?; + let remote_store = remote_store_config.make()?; + Ok(TestState { + archive_writer, + archive_reader, + local_path, + remote_path, + local_store, + remote_store, + local_store_config, + remote_store_config, + committee, + }) +} + +async fn insert_checkpoints_and_verify_manifest( + test_state: &TestState, + test_store: SharedInMemoryStore, + prev_checkpoint: Option, +) -> Result> { + let mut prev_tail = None; + let mut prev_checkpoint = prev_checkpoint; + let mut num_verified_iterations = 0; + loop { + if test_state.remote_path.join("MANIFEST").exists() { + if let Ok(manifest) = read_manifest(test_state.remote_store.clone()).await { + for file in manifest.files().into_iter() { + let file_path = + path_to_filesystem(test_state.remote_path.clone(), &file.file_path())?; + assert!(file_path.exists()); + } + + if let Some(prev_tail) = prev_tail { + // Ensure checkpoint sequence number in manifest never moves back + assert!(manifest.next_checkpoint_seq_num() >= prev_tail); + if manifest.next_checkpoint_seq_num() > prev_tail { + num_verified_iterations += 1; + } + } + prev_tail = Some(manifest.next_checkpoint_seq_num()); + // Break out of the loop once we have ensured that we noticed MANIFEST + // got updated at least 5 times + if num_verified_iterations > 5 { + break; + } + } + } + tokio::time::sleep(Duration::from_secs(1)).await; + prev_checkpoint = + write_new_checkpoints_to_store(test_state, test_store.clone(), 1, prev_checkpoint) + .await?; + } + Ok(prev_checkpoint) +} + +#[tokio::test] +async fn test_archive_basic() -> Result<(), anyhow::Error> { + let test_store = SharedInMemoryStore::default(); + let test_state = setup_test_state(temp_dir()).await?; + let kill = test_state.archive_writer.start(test_store.clone()).await?; + insert_checkpoints_and_verify_manifest(&test_state, test_store, None).await?; + kill.send(())?; + Ok(()) +} + +#[tokio::test] +async fn test_archive_resumes() -> Result<(), anyhow::Error> { + let test_store = SharedInMemoryStore::default(); + let test_state = setup_test_state(temp_dir()).await?; + let kill = test_state.archive_writer.start(test_store.clone()).await?; + let prev_checkpoint = + insert_checkpoints_and_verify_manifest(&test_state, test_store.clone(), None).await?; + + // Kill the archive writer so we can restart it again + drop(kill); + let test_state = setup_test_state(temp_dir()).await?; + let kill = test_state.archive_writer.start(test_store.clone()).await?; + insert_checkpoints_and_verify_manifest(&test_state, test_store, prev_checkpoint).await?; + kill.send(())?; + Ok(()) +} + +#[tokio::test] +async fn test_manifest_serde() -> Result<()> { + let original_manifest = Manifest::new(0, 100); + let remote_store = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(temp_dir()), + ..Default::default() + } + .make()?; + write_manifest(original_manifest.clone(), remote_store.clone()).await?; + let downloaded_manifest = read_manifest(remote_store).await?; + assert_eq!(downloaded_manifest, original_manifest); + Ok(()) +} + +#[tokio::test] +async fn test_archive_reader_e2e() -> Result<(), anyhow::Error> { + let test_store = SharedInMemoryStore::default(); + let test_state = setup_test_state(temp_dir()).await?; + let kill = test_state.archive_writer.start(test_store.clone()).await?; + let mut latest_archived_checkpoint_seq_num = 0; + while latest_archived_checkpoint_seq_num < 10 { + insert_checkpoints_and_verify_manifest(&test_state, test_store.clone(), None).await?; + let new_latest_archived_checkpoint_seq_num = test_state + .archive_reader + .latest_available_checkpoint() + .await?; + ma::assert_ge!( + new_latest_archived_checkpoint_seq_num, + latest_archived_checkpoint_seq_num + ); + latest_archived_checkpoint_seq_num = new_latest_archived_checkpoint_seq_num; + tokio::time::sleep(Duration::from_secs(1)).await; + } + ma::assert_ge!(latest_archived_checkpoint_seq_num, 10); + let genesis_checkpoint = test_store + .get_checkpoint_by_sequence_number(0)? + .context("Missing genesis checkpoint")?; + let genesis_checkpoint_content = test_store + .get_full_checkpoint_contents_by_sequence_number(0)? + .context("Missing genesis checkpoint")?; + let read_store = SharedInMemoryStore::default(); + read_store.inner_mut().insert_genesis_state( + genesis_checkpoint, + VerifiedCheckpointContents::new_unchecked(genesis_checkpoint_content), + test_state.committee.committee().to_owned(), + ); + let tx_counter = Arc::new(AtomicU64::new(0)); + let checkpoint_counter = Arc::new(AtomicU64::new(0)); + test_state.archive_reader.sync_manifest_once().await?; + test_state + .archive_reader + .read( + read_store.clone(), + 0..(latest_archived_checkpoint_seq_num + 1), + tx_counter, + checkpoint_counter, + true, + ) + .await?; + ma::assert_ge!( + read_store + .get_highest_verified_checkpoint()? + .sequence_number, + latest_archived_checkpoint_seq_num + ); + ma::assert_ge!( + read_store.get_highest_synced_checkpoint()?.sequence_number, + latest_archived_checkpoint_seq_num + ); + kill.send(())?; + Ok(()) +} + +#[tokio::test] +async fn test_verify_archive_with_oneshot_store() -> Result<(), anyhow::Error> { + let test_store = SharedInMemoryStore::default(); + let test_state = setup_test_state(temp_dir()).await?; + let kill = test_state.archive_writer.start(test_store.clone()).await?; + let mut latest_archived_checkpoint_seq_num = 0; + while latest_archived_checkpoint_seq_num < 10 { + insert_checkpoints_and_verify_manifest(&test_state, test_store.clone(), None).await?; + let new_latest_archived_checkpoint_seq_num = test_state + .archive_reader + .latest_available_checkpoint() + .await?; + ma::assert_ge!( + new_latest_archived_checkpoint_seq_num, + latest_archived_checkpoint_seq_num + ); + latest_archived_checkpoint_seq_num = new_latest_archived_checkpoint_seq_num; + tokio::time::sleep(Duration::from_secs(1)).await; + } + ma::assert_ge!(latest_archived_checkpoint_seq_num, 10); + let genesis_checkpoint = test_store + .get_checkpoint_by_sequence_number(0)? + .context("Missing genesis checkpoint")?; + let genesis_checkpoint_content = test_store + .get_full_checkpoint_contents_by_sequence_number(0)? + .context("Missing genesis checkpoint")?; + let mut read_store = SingleCheckpointSharedInMemoryStore::default(); + read_store.insert_genesis_state( + genesis_checkpoint, + VerifiedCheckpointContents::new_unchecked(genesis_checkpoint_content), + test_state.committee.committee().to_owned(), + ); + + // Verification should pass + assert!( + verify_archive_with_local_store( + read_store, + test_state.remote_store_config.clone(), + 1, + false + ) + .await + .is_ok() + ); + kill.send(())?; + Ok(()) +} + +#[tokio::test] +async fn test_verify_archive_with_oneshot_store_bad_data() -> Result<(), anyhow::Error> { + let test_store = SharedInMemoryStore::default(); + let test_state = setup_test_state(temp_dir()).await?; + let kill = test_state.archive_writer.start(test_store.clone()).await?; + let mut latest_archived_checkpoint_seq_num = 0; + while latest_archived_checkpoint_seq_num < 10 { + insert_checkpoints_and_verify_manifest(&test_state, test_store.clone(), None).await?; + let new_latest_archived_checkpoint_seq_num = test_state + .archive_reader + .latest_available_checkpoint() + .await?; + ma::assert_ge!( + new_latest_archived_checkpoint_seq_num, + latest_archived_checkpoint_seq_num + ); + latest_archived_checkpoint_seq_num = new_latest_archived_checkpoint_seq_num; + tokio::time::sleep(Duration::from_secs(1)).await; + } + ma::assert_ge!(latest_archived_checkpoint_seq_num, 10); + + // Corrupt the .chk and .sum files in the archive + let dir = fs::read_dir(test_state.remote_path)?; + let mut num_files_corrupted = 0; + for file in dir { + let file = file?; + let file_metadata = file.metadata()?; + if file_metadata.is_dir() { + // epoch dir + let epoch_dir = fs::read_dir(file.path())?; + for epoch_file in epoch_dir { + let epoch_file = epoch_file?; + // epoch dir should only have checkpoint files and no dir + assert!(epoch_file.metadata()?.is_file()); + if epoch_file + .file_name() + .into_string() + .map_err(|_| anyhow!("Failed to read file name"))? + .ends_with(".chk") + { + let mut f = File::options().write(true).open(epoch_file.path())?; + f.write_all("hello_world".as_bytes())?; + num_files_corrupted += 1; + } + } + } + } + ma::assert_gt!(num_files_corrupted, 0); + let genesis_checkpoint = test_store + .get_checkpoint_by_sequence_number(0)? + .context("Missing genesis checkpoint")?; + let genesis_checkpoint_content = test_store + .get_full_checkpoint_contents_by_sequence_number(0)? + .context("Missing genesis checkpoint")?; + let mut read_store = SingleCheckpointSharedInMemoryStore::default(); + read_store.insert_genesis_state( + genesis_checkpoint, + VerifiedCheckpointContents::new_unchecked(genesis_checkpoint_content), + test_state.committee.committee().to_owned(), + ); + + // Verification should fail + assert!( + verify_archive_with_local_store( + read_store, + test_state.remote_store_config.clone(), + 1, + false + ) + .await + .is_err() + ); + kill.send(())?; + + Ok(()) +} diff --git a/crates/iota-archival/src/writer.rs b/crates/iota-archival/src/writer.rs new file mode 100644 index 00000000000..ced54accae0 --- /dev/null +++ b/crates/iota-archival/src/writer.rs @@ -0,0 +1,512 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +#![allow(dead_code)] + +use std::{ + fs, + fs::{File, OpenOptions}, + io::{BufWriter, Seek, SeekFrom, Write}, + ops::Range, + path::{Path, PathBuf}, + sync::Arc, + thread::sleep, + time::Duration, +}; + +use anyhow::{anyhow, Context, Result}; +use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; +use iota_config::object_storage_config::ObjectStoreConfig; +use iota_storage::{ + blob::{Blob, BlobEncoding}, + compress, + object_store::util::{copy_file, path_to_filesystem}, + FileCompression, StorageFormat, +}; +use iota_types::{ + messages_checkpoint::{ + CertifiedCheckpointSummary as Checkpoint, CheckpointSequenceNumber, + FullCheckpointContents as CheckpointContents, + }, + storage::WriteStore, +}; +use object_store::DynObjectStore; +use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; +use tokio::{ + sync::{ + mpsc, + mpsc::{Receiver, Sender}, + }, + time::Instant, +}; +use tracing::{debug, info}; + +use crate::{ + create_file_metadata, read_manifest, write_manifest, CheckpointUpdates, FileMetadata, FileType, + Manifest, CHECKPOINT_FILE_MAGIC, CHECKPOINT_FILE_SUFFIX, EPOCH_DIR_PREFIX, MAGIC_BYTES, + SUMMARY_FILE_MAGIC, SUMMARY_FILE_SUFFIX, +}; + +pub struct ArchiveMetrics { + pub latest_checkpoint_archived: IntGauge, +} + +impl ArchiveMetrics { + pub fn new(registry: &Registry) -> Arc { + let this = Self { + latest_checkpoint_archived: register_int_gauge_with_registry!( + "latest_checkpoint_archived", + "Latest checkpoint to have archived to the remote store", + registry + ) + .unwrap(), + }; + Arc::new(this) + } +} + +/// CheckpointWriter writes checkpoints and summaries. It creates multiple *.chk +/// and *.sum files +struct CheckpointWriter { + root_dir_path: PathBuf, + epoch_num: u64, + checkpoint_range: Range, + wbuf: BufWriter, + summary_wbuf: BufWriter, + sender: Sender, + checkpoint_buf_offset: usize, + file_compression: FileCompression, + storage_format: StorageFormat, + manifest: Manifest, + last_commit_instant: Instant, + commit_duration: Duration, + commit_file_size: usize, +} + +impl CheckpointWriter { + fn new( + root_dir_path: PathBuf, + file_compression: FileCompression, + storage_format: StorageFormat, + sender: Sender, + manifest: Manifest, + commit_duration: Duration, + commit_file_size: usize, + ) -> Result { + let epoch_num = manifest.epoch_num(); + let checkpoint_sequence_num = manifest.next_checkpoint_seq_num(); + let epoch_dir = root_dir_path.join(format!("{}{epoch_num}", EPOCH_DIR_PREFIX)); + if epoch_dir.exists() { + fs::remove_dir_all(&epoch_dir)?; + } + fs::create_dir_all(&epoch_dir)?; + let checkpoint_file = Self::next_file( + &epoch_dir, + checkpoint_sequence_num, + CHECKPOINT_FILE_SUFFIX, + CHECKPOINT_FILE_MAGIC, + storage_format, + file_compression, + )?; + let summary_file = Self::next_file( + &epoch_dir, + checkpoint_sequence_num, + SUMMARY_FILE_SUFFIX, + SUMMARY_FILE_MAGIC, + storage_format, + file_compression, + )?; + Ok(CheckpointWriter { + root_dir_path, + epoch_num, + checkpoint_range: checkpoint_sequence_num..checkpoint_sequence_num, + wbuf: BufWriter::new(checkpoint_file), + summary_wbuf: BufWriter::new(summary_file), + checkpoint_buf_offset: 0, + sender, + file_compression, + storage_format, + manifest, + last_commit_instant: Instant::now(), + commit_duration, + commit_file_size, + }) + } + + pub fn write( + &mut self, + checkpoint_contents: CheckpointContents, + checkpoint_summary: Checkpoint, + ) -> Result<()> { + match self.storage_format { + StorageFormat::Blob => self.write_as_blob(checkpoint_contents, checkpoint_summary), + } + } + + pub fn write_as_blob( + &mut self, + checkpoint_contents: CheckpointContents, + checkpoint_summary: Checkpoint, + ) -> Result<()> { + assert_eq!( + checkpoint_summary.sequence_number, + self.checkpoint_range.end + ); + + if checkpoint_summary.epoch() + == self + .epoch_num + .checked_add(1) + .context("Epoch num overflow")? + { + self.cut()?; + self.update_to_next_epoch(); + if self.epoch_dir().exists() { + fs::remove_dir_all(self.epoch_dir())?; + } + fs::create_dir_all(self.epoch_dir())?; + self.reset()?; + } + + assert_eq!(checkpoint_summary.epoch, self.epoch_num); + + assert_eq!( + checkpoint_summary.content_digest, + *checkpoint_contents.checkpoint_contents().digest() + ); + + let contents_blob = Blob::encode(&checkpoint_contents, BlobEncoding::Bcs)?; + let blob_size = contents_blob.size(); + let cut_new_checkpoint_file = (self.checkpoint_buf_offset + blob_size) + > self.commit_file_size + || (self.last_commit_instant.elapsed() > self.commit_duration); + if cut_new_checkpoint_file { + self.cut()?; + self.reset()?; + } + + self.checkpoint_buf_offset += contents_blob.write(&mut self.wbuf)?; + + let summary_blob = Blob::encode(&checkpoint_summary, BlobEncoding::Bcs)?; + summary_blob.write(&mut self.summary_wbuf)?; + + self.checkpoint_range.end = self + .checkpoint_range + .end + .checked_add(1) + .context("Checkpoint sequence num overflow")?; + Ok(()) + } + fn finalize(&mut self) -> Result { + self.wbuf.flush()?; + self.wbuf.get_ref().sync_data()?; + let off = self.wbuf.get_ref().stream_position()?; + self.wbuf.get_ref().set_len(off)?; + let file_path = self.epoch_dir().join(format!( + "{}.{CHECKPOINT_FILE_SUFFIX}", + self.checkpoint_range.start + )); + self.compress(&file_path)?; + let file_metadata = create_file_metadata( + &file_path, + FileType::CheckpointContent, + self.epoch_num, + self.checkpoint_range.clone(), + )?; + Ok(file_metadata) + } + fn finalize_summary(&mut self) -> Result { + self.summary_wbuf.flush()?; + self.summary_wbuf.get_ref().sync_data()?; + let off = self.summary_wbuf.get_ref().stream_position()?; + self.summary_wbuf.get_ref().set_len(off)?; + let file_path = self.epoch_dir().join(format!( + "{}.{SUMMARY_FILE_SUFFIX}", + self.checkpoint_range.start + )); + self.compress(&file_path)?; + let file_metadata = create_file_metadata( + &file_path, + FileType::CheckpointSummary, + self.epoch_num, + self.checkpoint_range.clone(), + )?; + Ok(file_metadata) + } + fn cut(&mut self) -> Result<()> { + if !self.checkpoint_range.is_empty() { + let checkpoint_file_metadata = self.finalize()?; + let summary_file_metadata = self.finalize_summary()?; + let checkpoint_updates = CheckpointUpdates::new( + self.epoch_num, + self.checkpoint_range.end, + checkpoint_file_metadata, + summary_file_metadata, + &mut self.manifest, + ); + info!("Checkpoint file cut for: {:?}", checkpoint_updates); + self.sender.blocking_send(checkpoint_updates)?; + } + Ok(()) + } + fn compress(&self, source: &Path) -> Result<()> { + if self.file_compression == FileCompression::None { + return Ok(()); + } + let mut input = File::open(source)?; + let tmp_file_name = source.with_extension("tmp"); + let mut output = File::create(&tmp_file_name)?; + compress(&mut input, &mut output)?; + fs::rename(tmp_file_name, source)?; + Ok(()) + } + fn next_file( + dir_path: &Path, + checkpoint_sequence_num: u64, + suffix: &str, + magic_bytes: u32, + storage_format: StorageFormat, + file_compression: FileCompression, + ) -> Result { + let next_file_path = dir_path.join(format!("{checkpoint_sequence_num}.{suffix}")); + let mut f = File::create(next_file_path.clone())?; + let mut metab = [0u8; MAGIC_BYTES]; + BigEndian::write_u32(&mut metab, magic_bytes); + let n = f.write(&metab)?; + drop(f); + f = OpenOptions::new().append(true).open(next_file_path)?; + f.seek(SeekFrom::Start(n as u64))?; + f.write_u8(storage_format.into())?; + f.write_u8(file_compression.into())?; + Ok(f) + } + fn create_new_files(&mut self) -> Result<()> { + let f = Self::next_file( + &self.epoch_dir(), + self.checkpoint_range.start, + CHECKPOINT_FILE_SUFFIX, + CHECKPOINT_FILE_MAGIC, + self.storage_format, + self.file_compression, + )?; + self.checkpoint_buf_offset = MAGIC_BYTES; + self.wbuf = BufWriter::new(f); + let f = Self::next_file( + &self.epoch_dir(), + self.checkpoint_range.start, + SUMMARY_FILE_SUFFIX, + SUMMARY_FILE_MAGIC, + self.storage_format, + self.file_compression, + )?; + self.summary_wbuf = BufWriter::new(f); + Ok(()) + } + fn reset(&mut self) -> Result<()> { + self.reset_checkpoint_range(); + self.create_new_files()?; + self.reset_last_commit_ts(); + Ok(()) + } + fn reset_last_commit_ts(&mut self) { + self.last_commit_instant = Instant::now(); + } + fn reset_checkpoint_range(&mut self) { + self.checkpoint_range = self.checkpoint_range.end..self.checkpoint_range.end + } + fn epoch_dir(&self) -> PathBuf { + self.root_dir_path + .join(format!("{}{}", EPOCH_DIR_PREFIX, self.epoch_num)) + } + fn update_to_next_epoch(&mut self) { + self.epoch_num = self.epoch_num.checked_add(1).unwrap(); + } +} + +/// ArchiveWriter archives history by tailing checkpoints writing them to a +/// local staging dir and simultaneously uploading them to a remote object store +pub struct ArchiveWriter { + file_compression: FileCompression, + storage_format: StorageFormat, + local_staging_dir_root: PathBuf, + local_object_store: Arc, + remote_object_store: Arc, + commit_duration: Duration, + commit_file_size: usize, + archive_metrics: Arc, +} + +impl ArchiveWriter { + pub async fn new( + local_store_config: ObjectStoreConfig, + remote_store_config: ObjectStoreConfig, + file_compression: FileCompression, + storage_format: StorageFormat, + commit_duration: Duration, + commit_file_size: usize, + registry: &Registry, + ) -> Result { + Ok(ArchiveWriter { + file_compression, + storage_format, + remote_object_store: remote_store_config.make()?, + local_object_store: local_store_config.make()?, + local_staging_dir_root: local_store_config.directory.context("Missing local dir")?, + commit_duration, + commit_file_size, + archive_metrics: ArchiveMetrics::new(registry), + }) + } + + pub async fn start(&self, store: S) -> Result> + where + S: WriteStore + Send + Sync + 'static, + { + let remote_archive_is_empty = self + .remote_object_store + .list_with_delimiter(None) + .await + .expect("Failed to read remote archive dir") + .common_prefixes + .is_empty(); + let manifest = if remote_archive_is_empty { + // Start from genesis + Manifest::new(0, 0) + } else { + read_manifest(self.remote_object_store.clone()) + .await + .expect("Failed to read manifest") + }; + let start_checkpoint_sequence_number = manifest.next_checkpoint_seq_num(); + let (sender, receiver) = mpsc::channel::(100); + let checkpoint_writer = CheckpointWriter::new( + self.local_staging_dir_root.clone(), + self.file_compression, + self.storage_format, + sender, + manifest, + self.commit_duration, + self.commit_file_size, + ) + .expect("Failed to create checkpoint writer"); + let (kill_sender, kill_receiver) = tokio::sync::broadcast::channel::<()>(1); + tokio::spawn(Self::start_syncing_with_remote( + self.remote_object_store.clone(), + self.local_object_store.clone(), + self.local_staging_dir_root.clone(), + receiver, + kill_sender.subscribe(), + self.archive_metrics.clone(), + )); + tokio::task::spawn_blocking(move || { + Self::start_tailing_checkpoints( + start_checkpoint_sequence_number, + checkpoint_writer, + store, + kill_receiver, + ) + }); + Ok(kill_sender) + } + + fn start_tailing_checkpoints( + start_checkpoint_sequence_number: CheckpointSequenceNumber, + mut checkpoint_writer: CheckpointWriter, + store: S, + mut kill: tokio::sync::broadcast::Receiver<()>, + ) -> Result<()> + where + S: WriteStore + Send + Sync + 'static, + { + let mut checkpoint_sequence_number = start_checkpoint_sequence_number; + info!("Starting checkpoint tailing from sequence number: {checkpoint_sequence_number}"); + + while kill.try_recv().is_err() { + if let Some(checkpoint_summary) = store + .get_checkpoint_by_sequence_number(checkpoint_sequence_number) + .map_err(|_| anyhow!("Failed to read checkpoint summary from store"))? + { + if let Some(checkpoint_contents) = store + .get_full_checkpoint_contents(&checkpoint_summary.content_digest) + .map_err(|_| anyhow!("Failed to read checkpoint content from store"))? + { + checkpoint_writer + .write(checkpoint_contents, checkpoint_summary.into_inner())?; + checkpoint_sequence_number = checkpoint_sequence_number + .checked_add(1) + .context("checkpoint seq number overflow")?; + // There is more checkpoints to tail, so continue without sleeping + continue; + } + } + // Checkpoint with `checkpoint_sequence_number` is not available to read from + // store yet, sleep for sometime and then retry + sleep(Duration::from_secs(3)); + } + Ok(()) + } + + async fn start_syncing_with_remote( + remote_object_store: Arc, + local_object_store: Arc, + local_staging_root_dir: PathBuf, + mut update_receiver: Receiver, + mut kill: tokio::sync::broadcast::Receiver<()>, + metrics: Arc, + ) -> Result<()> { + loop { + tokio::select! { + _ = kill.recv() => break, + updates = update_receiver.recv() => { + if let Some(checkpoint_updates) = updates { + info!("Received checkpoint update: {:?}", checkpoint_updates); + let latest_checkpoint_seq_num = checkpoint_updates.manifest.next_checkpoint_seq_num(); + let summary_file_path = checkpoint_updates.summary_file_path(); + Self::sync_file_to_remote( + local_staging_root_dir.clone(), + summary_file_path, + local_object_store.clone(), + remote_object_store.clone() + ) + .await + .expect("Syncing checkpoint summary should not fail"); + + let content_file_path = checkpoint_updates.content_file_path(); + Self::sync_file_to_remote( + local_staging_root_dir.clone(), + content_file_path, + local_object_store.clone(), + remote_object_store.clone() + ) + .await + .expect("Syncing checkpoint content should not fail"); + + write_manifest( + checkpoint_updates.manifest, + remote_object_store.clone() + ) + .await + .expect("Updating manifest should not fail"); + metrics.latest_checkpoint_archived.set(latest_checkpoint_seq_num as i64) + } else { + info!("Terminating archive sync loop"); + break; + } + }, + } + } + Ok(()) + } + + async fn sync_file_to_remote( + dir: PathBuf, + path: object_store::path::Path, + from: Arc, + to: Arc, + ) -> Result<()> { + debug!("Syncing archive file to remote: {:?}", path); + copy_file(&path, &path, &from, &to).await?; + fs::remove_file(path_to_filesystem(dir, &path)?)?; + Ok(()) + } +} diff --git a/crates/iota-authority-aggregation/Cargo.toml b/crates/iota-authority-aggregation/Cargo.toml new file mode 100644 index 00000000000..47e95c0092e --- /dev/null +++ b/crates/iota-authority-aggregation/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "iota-authority-aggregation" +authors = ["Mysten Labs "] +license = "Apache-2.0" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +iota-types.workspace = true +mysten-metrics.workspace = true +tokio.workspace = true +tracing.workspace = true +futures.workspace = true diff --git a/crates/iota-authority-aggregation/src/lib.rs b/crates/iota-authority-aggregation/src/lib.rs new file mode 100644 index 00000000000..d1478c2490c --- /dev/null +++ b/crates/iota-authority-aggregation/src/lib.rs @@ -0,0 +1,179 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{BTreeMap, BTreeSet}, + sync::Arc, + time::Duration, +}; + +use futures::{future::BoxFuture, stream::FuturesUnordered, Future, StreamExt}; +use iota_types::{ + base_types::ConciseableName, + committee::{CommitteeTrait, StakeUnit}, +}; +use mysten_metrics::monitored_future; +use tokio::time::timeout; +use tracing::instrument::Instrument; + +pub type AsyncResult<'a, T, E> = BoxFuture<'a, Result>; + +pub enum ReduceOutput { + Continue(S), + ContinueWithTimeout(S, Duration), + Failed(S), + Success(R), +} + +pub async fn quorum_map_then_reduce_with_timeout_and_prefs< + 'a, + C, + K, + Client: 'a, + S, + V, + R, + E, + FMap, + FReduce, +>( + committee: Arc, + authority_clients: Arc>>, + authority_preferences: Option<&BTreeSet>, + initial_state: S, + map_each_authority: FMap, + reduce_result: FReduce, + initial_timeout: Duration, +) -> Result< + ( + R, + FuturesUnordered)> + 'a>, + ), + S, +> +where + K: Ord + ConciseableName<'a> + Copy + 'a, + C: CommitteeTrait, + FMap: FnOnce(K, Arc) -> AsyncResult<'a, V, E> + Clone + 'a, + FReduce: Fn(S, K, StakeUnit, Result) -> BoxFuture<'a, ReduceOutput>, +{ + let authorities_shuffled = committee.shuffle_by_stake(authority_preferences, None); + + // First, execute in parallel for each authority FMap. + let mut responses: futures::stream::FuturesUnordered<_> = authorities_shuffled + .into_iter() + .map(|name| { + let client = authority_clients[&name].clone(); + let execute = map_each_authority.clone(); + let concise_name = name.concise_owned(); + monitored_future!(async move { + ( + name, + execute(name, client) + .instrument( + tracing::trace_span!("quorum_map_auth", authority =? concise_name), + ) + .await, + ) + }) + }) + .collect(); + + let mut current_timeout = initial_timeout; + let mut accumulated_state = initial_state; + // Then, as results become available fold them into the state using FReduce. + while let Ok(Some((authority_name, result))) = timeout(current_timeout, responses.next()).await + { + let authority_weight = committee.weight(&authority_name); + accumulated_state = + match reduce_result(accumulated_state, authority_name, authority_weight, result).await { + // In the first two cases we are told to continue the iteration. + ReduceOutput::Continue(state) => state, + ReduceOutput::ContinueWithTimeout(state, duration) => { + // Adjust the waiting timeout. + current_timeout = duration; + state + } + ReduceOutput::Failed(state) => { + return Err(state); + } + ReduceOutput::Success(result) => { + // The reducer tells us that we have the result needed. Just return it. + return Ok((result, responses)); + } + } + } + // If we have exhausted all authorities and still have not returned a result, + // return error with the accumulated state. + Err(accumulated_state) +} + +/// This function takes an initial state, than executes an asynchronous function +/// (FMap) for each authority, and folds the results as they become available +/// into the state using an async function (FReduce). +/// +/// FMap can do io, and returns a result V. An error there may not be fatal, and +/// could be consumed by the MReduce function to overall recover from it. This +/// is necessary to ensure byzantine authorities cannot interrupt the logic of +/// this function. +/// +/// FReduce returns a result to a ReduceOutput. If the result is Err the +/// function shortcuts and the Err is returned. An Ok ReduceOutput result can be +/// used to shortcut and return the resulting state (ReduceOutput::End), +/// continue the folding as new states arrive (ReduceOutput::Continue), +/// or continue with a timeout maximum waiting time +/// (ReduceOutput::ContinueWithTimeout). +/// +/// This function provides a flexible way to communicate with a quorum of +/// authorities, processing and processing their results into a safe overall +/// result, and also safely allowing operations to continue past the quorum to +/// ensure all authorities are up to date (up to a timeout). +pub async fn quorum_map_then_reduce_with_timeout< + 'a, + C, + K, + Client: 'a, + S: 'a, + V: 'a, + R: 'a, + E, + FMap, + FReduce, +>( + committee: Arc, + authority_clients: Arc>>, + // The initial state that will be used to fold in values from authorities. + initial_state: S, + // The async function used to apply to each authority. It takes an authority name, + // and authority client parameter and returns a Result. + map_each_authority: FMap, + // The async function that takes an accumulated state, and a new result for V from an + // authority and returns a result to a ReduceOutput state. + reduce_result: FReduce, + // The initial timeout applied to all + initial_timeout: Duration, +) -> Result< + ( + R, + FuturesUnordered)> + 'a>, + ), + S, +> +where + K: Ord + ConciseableName<'a> + Copy + 'a, + C: CommitteeTrait, + FMap: FnOnce(K, Arc) -> AsyncResult<'a, V, E> + Clone + 'a, + FReduce: Fn(S, K, StakeUnit, Result) -> BoxFuture<'a, ReduceOutput> + 'a, +{ + quorum_map_then_reduce_with_timeout_and_prefs( + committee, + authority_clients, + None, + initial_state, + map_each_authority, + reduce_result, + initial_timeout, + ) + .await +} diff --git a/crates/sui-aws-orchestrator/.gitignore b/crates/iota-aws-orchestrator/.gitignore similarity index 100% rename from crates/sui-aws-orchestrator/.gitignore rename to crates/iota-aws-orchestrator/.gitignore diff --git a/crates/iota-aws-orchestrator/Cargo.toml b/crates/iota-aws-orchestrator/Cargo.toml new file mode 100644 index 00000000000..1d985e17492 --- /dev/null +++ b/crates/iota-aws-orchestrator/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "iota-aws-orchestrator" +version = "0.0.1" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +aws-sdk-ec2.workspace = true +aws-smithy-http.workspace = true +aws-smithy-runtime-api.workspace = true +russh.workspace = true +russh-keys.workspace = true +aws-config.workspace = true +color-eyre.workspace = true +clap.workspace = true +eyre.workspace = true +prettytable-rs.workspace = true +serde_json.workspace = true +futures.workspace = true +thiserror.workspace = true +reqwest.workspace = true +async-trait.workspace = true +crossterm.workspace = true +serde.workspace = true +tokio = { workspace = true, features = ["full"] } +prometheus-parse.workspace = true + +mysten-metrics.workspace = true +iota-config = { path = "../iota-config" } +narwhal-config.workspace = true +iota-types = { path = "../iota-types" } +iota-swarm-config = { path = "../iota-swarm-config" } + +[dev-dependencies] +tempfile = "3.6.0" + +[[bin]] +name = "iota-aws-orchestrator" +path = "src/main.rs" diff --git a/crates/iota-aws-orchestrator/README.md b/crates/iota-aws-orchestrator/README.md new file mode 100644 index 00000000000..520e75189b7 --- /dev/null +++ b/crates/iota-aws-orchestrator/README.md @@ -0,0 +1,157 @@ +# Orchestrator + +The Orchestrator crate provides facilities for quickly deploying and benchmarking this codebase in a geo-distributed environment. Please note that it is not intended for production deployments or as an indicator of production engineering best practices. Its purpose is to facilitate research projects by allowing benchmarking of (variants of) the codebase and analyzing performance. + +This guide provides a step-by-step explanation of how to run geo-distributed benchmarks on [Amazon Web Services (AWS)](http://aws.amazon.com). + +## Step 1. Set up credentials + +To enable programmatic access to your cloud provider account from your local machine, you need to set up your cloud provider credentials. These credentials authorize your machine to create, delete, and edit instances programmatically on your account. + +### Setting up AWS credentials + +1. Find your ['access key id' and 'secret access key'](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds). +2. Create a file `~/.aws/credentials` with the following content: + +```text +[default] +aws_access_key_id = YOUR_ACCESS_KEY_ID +aws_secret_access_key = YOUR_SECRET_ACCESS_KEY +``` + +Do not specify any AWS region in that file, as the scripts need to handle multiple regions programmatically. + +### Setting up SSH credentials + +Running `ssh-keygen -t ed25519 -C "..."` would generate a new ssh key pair under the specified path, +e.g. private key at `~/.ssh/aws` and public key at `~/.ssh/aws.pub`. If the public key is not +at the corresponding private key path with `.pub` extension, then the public key path must be specified +for `ssh_public_key_file` in `settings.json`. + +## Step 2. Specify the testbed configuration + +Create a file called `settings.json` that contains all the configuration parameters for the testbed deployment. You can find a template at `./assets/settings-template.json`. Example content: + +```json +{ + "testbed_id": "alberto-0", + "cloud_provider": "aws", + "token_file": "/Users/alberto/.aws/credentials", + "ssh_private_key_file": "/Users/alberto/.ssh/aws", + "regions": [ + "us-east-1", + "us-west-2", + "ca-central-1", + "eu-central-1", + "ap-northeast-1", + "eu-west-1", + "eu-west-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2" + ], + "specs": "m5d.8xlarge", + "repository": { + "url": "https://github.com/iotaledger/iota.git", + "commit": "main" + }, + "results_directory": "./results", + "logs_directory": "./logs" +} +``` + +The documentation of the `Settings` struct in `./src/settings.rs` provides detailed information about each `Settings` field. + +If you're working with a private GitHub repository, you can include a [private access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) in the repository URL. For example, if your access token is `[your_token]`, the repository URL should be formatted as follows: + +```json +"repository": { + "url": "http://[your_token]@github.com/iotaledger/iota.git", + "commit": "main" +} +``` + +## Step 3. Create a testbed + +The `iota-aws-orchestrator` binary provides various functionalities for creating, starting, stopping, and destroying instances. You can use the following command to boot 2 instances per region (if the settings file specifies 10 regions, as shown in the example above, a total of 20 instances will be created): + +```bash +cargo run --bin iota-aws-orchestrator -- testbed deploy --instances 2 +``` + +To check the current status of the testbed instances, use the following command: + +```bash +cargo run --bin iota-aws-orchestrator testbed status +``` + +Instances listed with a green number are available and ready for use, while instances listed with a red number are stopped. + +Also keep in mind that there is nothing stopping you from running the `deploy` command multiple times if you find your self +needing more instances down the line. + +## Step 4. Choose protocol + +There is support to benchmark either Iota or Narwhal only. To choose which protocol to benchmark, you can set the `Protocol` & `BenchmarkType` field [here](https://github.com/iotaledger/iota/blob/main/crates/iota-aws-orchestrator/src/main.rs#L33-L34) + +``` +// Iota +use protocol::iota::{IotaBenchmarkType, IotaProtocol}; +type Protocol = IotaProtocol; +type BenchmarkType = IotaBenchmarkType; +// Narwhal +use protocol::narwhal::{NarwhalBenchmarkType, NarwhalProtocol}; +type Protocol = NarwhalProtocol; +type BenchmarkType = NarwhalBenchmarkType; +``` + +## Step 5. Running benchmarks + +Running benchmarks involves installing the specified version of the codebase on the remote machines and running one validator and one load generator per instance. For example, the following command benchmarks a committee of 10 validators under a constant load of 200 tx/s for 3 minutes: + +```bash +cargo run --bin iota-aws-orchestrator -- benchmark --committee 10 fixed-load --loads 200 --duration 180 +``` + +In a network of 10 validators, each with a corresponding load generator, each load generator submits a fixed load of 20 tx/s. Performance measurements are collected by regularly scraping the Prometheus metrics exposed by the load generators. The `iota-aws-orchestrator` binary provides additional commands to run a specific number of load generators on separate machines. + +## Step 6. Monitoring + +The orchestrator provides facilities to monitor metrics on clients and nodes. The orchestrator deploys a [Prometheus](https://prometheus.io) instance and a [Grafana](https://grafana.com) instance on a dedicated remote machine. Grafana is then available on the address printed on stdout (e.g., `http://3.83.97.12:3000`) with the default username and password both set to `admin`. You can either create a [new dashboard](https://grafana.com/docs/grafana/latest/getting-started/build-first-dashboard/) or [import](https://grafana.com/docs/grafana/latest/dashboards/manage-dashboards/#import-a-dashboard) the example dashboards located in the `./assets` folder. + +## Destroy a testbed +After you have found yourself that you don't need the deployed testbed anymore you can simply run + +``` +cargo run --bin iota-aws-orchestrator -- testbed destroy +``` + +that will terminate all the deployed EC2 instances. Keep in mind that AWS is not immediately deleting the terminated instances - this could take a few hours - so in case you want to immediately deploy a new testbed it would be advised +to use a different `testbed_id` in the `settings.json` to avoid any later conflicts (see the FAQ section for more information). + +## FAQ + +### I am getting an error "Failed to read settings file '"crates/iota-aws-orchestrator/assets/settings.json"': No such file or directory" +To run the tool a `settings.json` file with the deployment configuration should be under the directory `crates/iota-aws-orchestrator/assets`. Also, please make sure +that you run the orchestrator from the top level repo folder, ex `/iota $ cargo run --bin iota-aws-orchestrator` + +### I am getting an error "IncorrectInstanceState" with message "The instance 'i-xxxxxxx' is not in a state from which it can be started."" when I try to run a benchmark +When a testbed is deployed the EC2 instances are tagged with the `testbed_id` as dictated in the `settings.json` file. When trying to run a benchmark the tool will try to list +all the EC2 instances on the dictated by the configuration regions. To successfully run the benchmark all the listed instances should be in status +`Running`. If there is any instance in different state , ex `Terminated` , then the above error will arise. Please pay attention that if you `destroy` a deployment +and then immediately `deploy` a new one under the same `testbed_id`, then it is possible to have a mix of instances with status `Running` and `Terminated`, as AWS does not immediately +delete the `Terminated` instances. That can eventually cause the above false positive error as well. It is advised in this case to use a different `testbed_id` to ensure that +there is no overlap between instances. + +### I am getting an error "Not enough instances: missing X instances" when running a benchmark +In the common case to successfully run a benchmark we need to have enough instances available to run +* the required validators +* the grafana dashboard +* the benchmarking clients + +for example when running the command `cargo run --bin iota-aws-orchestrator -- benchmark --committee 4 fixed-load --loads 500 --duration 500`, we'll need the following amount of instances available: +* `4 instances` to run the validators (since we set `--committee 4`) +* `1 instance` to run the grafana dashboard (by default only 1 is needed) +* no additional instances to run the benchmarking clients, as those will be co-deployed on the validator nodes + +so in total we must have deployed a testbed of at least `5 instances`. If we attempt to run with fewer, then the above error will be thrown. diff --git a/crates/sui-aws-orchestrator/assets/grafana-dashboard-narwhal-only.json b/crates/iota-aws-orchestrator/assets/grafana-dashboard-narwhal-only.json similarity index 99% rename from crates/sui-aws-orchestrator/assets/grafana-dashboard-narwhal-only.json rename to crates/iota-aws-orchestrator/assets/grafana-dashboard-narwhal-only.json index 10ca7630cc3..8e841c72a12 100644 --- a/crates/sui-aws-orchestrator/assets/grafana-dashboard-narwhal-only.json +++ b/crates/iota-aws-orchestrator/assets/grafana-dashboard-narwhal-only.json @@ -2638,7 +2638,7 @@ "type": "timeseries" } ], - "title": "NW behavior from Sui POV", + "title": "NW behavior from Iota POV", "type": "row" }, { @@ -6597,7 +6597,7 @@ }, "timepicker": {}, "timezone": "", - "title": "Sui Validators - Narwhal Only", + "title": "Iota Validators - Narwhal Only", "uid": "SpRJIxL4z", "version": 3, "weekStart": "" diff --git a/crates/sui-aws-orchestrator/assets/grafana-dashboard-narwhal.json b/crates/iota-aws-orchestrator/assets/grafana-dashboard-narwhal.json similarity index 99% rename from crates/sui-aws-orchestrator/assets/grafana-dashboard-narwhal.json rename to crates/iota-aws-orchestrator/assets/grafana-dashboard-narwhal.json index 0ec17493aea..0856898ca1c 100644 --- a/crates/sui-aws-orchestrator/assets/grafana-dashboard-narwhal.json +++ b/crates/iota-aws-orchestrator/assets/grafana-dashboard-narwhal.json @@ -977,7 +977,7 @@ }, "id": 43, "panels": [], - "title": "NW behavior from Sui POV", + "title": "NW behavior from Iota POV", "type": "row" }, { @@ -6028,7 +6028,7 @@ }, "timepicker": {}, "timezone": "", - "title": "Sui Validators - Narwhal", + "title": "Iota Validators - Narwhal", "uid": "SpRJIxL4z", "version": 7, "weekStart": "" diff --git a/crates/sui-aws-orchestrator/assets/grafana-dashboard.json b/crates/iota-aws-orchestrator/assets/grafana-dashboard.json similarity index 100% rename from crates/sui-aws-orchestrator/assets/grafana-dashboard.json rename to crates/iota-aws-orchestrator/assets/grafana-dashboard.json diff --git a/crates/sui-aws-orchestrator/assets/plot.py b/crates/iota-aws-orchestrator/assets/plot.py similarity index 99% rename from crates/sui-aws-orchestrator/assets/plot.py rename to crates/iota-aws-orchestrator/assets/plot.py index ed3e32e7e95..d3cc090b244 100644 --- a/crates/sui-aws-orchestrator/assets/plot.py +++ b/crates/iota-aws-orchestrator/assets/plot.py @@ -1,6 +1,9 @@ # Copyright (c) Mysten Labs, Inc. # SPDX-License-Identifier: Apache-2.0 +# Modifications Copyright (c) 2024 IOTA Stiftung +# SPDX-License-Identifier: Apache-2.0 + import argparse from enum import Enum import glob @@ -418,7 +421,7 @@ def plot_duration(self, file, precision): if __name__ == "__main__": parser = argparse.ArgumentParser( - prog='Sui Plotter', + prog='Iota Plotter', description='Simple script to plot measurement data' ) parser.add_argument( diff --git a/crates/sui-aws-orchestrator/assets/requirements.txt b/crates/iota-aws-orchestrator/assets/requirements.txt similarity index 100% rename from crates/sui-aws-orchestrator/assets/requirements.txt rename to crates/iota-aws-orchestrator/assets/requirements.txt diff --git a/crates/sui-aws-orchestrator/assets/settings-template.json b/crates/iota-aws-orchestrator/assets/settings-template.json similarity index 88% rename from crates/sui-aws-orchestrator/assets/settings-template.json rename to crates/iota-aws-orchestrator/assets/settings-template.json index b99fb1dee71..3599a73f916 100644 --- a/crates/sui-aws-orchestrator/assets/settings-template.json +++ b/crates/iota-aws-orchestrator/assets/settings-template.json @@ -6,7 +6,7 @@ "regions": ["us-east-1", "us-west-2", "ca-central-1", "eu-central-1", "ap-northeast-1", "eu-west-1", "eu-west-2", "eu-north-1", "ap-south-1", "ap-southeast-1", "ap-southeast-2"], "specs": "m5d.8xlarge", "repository": { - "url": "https://github.com/mystenlabs/sui.git", + "url": "https://github.com/iotaledger/iota.git", "commit": "main" } } \ No newline at end of file diff --git a/crates/sui-aws-orchestrator/src/benchmark.rs b/crates/iota-aws-orchestrator/src/benchmark.rs similarity index 99% rename from crates/sui-aws-orchestrator/src/benchmark.rs rename to crates/iota-aws-orchestrator/src/benchmark.rs index 07ecd959457..50599bc557e 100644 --- a/crates/sui-aws-orchestrator/src/benchmark.rs +++ b/crates/iota-aws-orchestrator/src/benchmark.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/sui-aws-orchestrator/src/client/aws.rs b/crates/iota-aws-orchestrator/src/client/aws.rs similarity index 99% rename from crates/sui-aws-orchestrator/src/client/aws.rs rename to crates/iota-aws-orchestrator/src/client/aws.rs index fecf5beb02f..c88521291c5 100644 --- a/crates/sui-aws-orchestrator/src/client/aws.rs +++ b/crates/iota-aws-orchestrator/src/client/aws.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/iota-aws-orchestrator/src/client/mod.rs b/crates/iota-aws-orchestrator/src/client/mod.rs new file mode 100644 index 00000000000..a49d2a8ed20 --- /dev/null +++ b/crates/iota-aws-orchestrator/src/client/mod.rs @@ -0,0 +1,197 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + fmt::Display, + net::{Ipv4Addr, SocketAddr}, +}; + +use serde::{Deserialize, Serialize}; + +use super::error::CloudProviderResult; + +pub mod aws; + +/// Represents a cloud provider instance. +#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash)] +pub struct Instance { + /// The unique identifier of the instance. + pub id: String, + /// The region where the instance runs. + pub region: String, + /// The public ip address of the instance (accessible from anywhere). + pub main_ip: Ipv4Addr, + /// The list of tags associated with the instance. + pub tags: Vec, + /// The specs of the instance. + pub specs: String, + /// The current status of the instance. + pub status: String, +} + +impl Instance { + /// Return whether the instance is active and running. + pub fn is_active(&self) -> bool { + self.status.to_lowercase() == "running" + } + + /// Return whether the instance is inactive and not ready for use. + pub fn is_inactive(&self) -> bool { + !self.is_active() + } + + /// Return whether the instance is terminated and in the process of being + /// deleted. + pub fn is_terminated(&self) -> bool { + self.status.to_lowercase() == "terminated" + } + + /// Return the ssh address to connect to the instance. + pub fn ssh_address(&self) -> SocketAddr { + format!("{}:22", self.main_ip).parse().unwrap() + } + + #[cfg(test)] + pub fn new_for_test(id: String) -> Self { + Self { + id, + region: Default::default(), + main_ip: Ipv4Addr::new(127, 0, 0, 1), + tags: Default::default(), + specs: Default::default(), + status: Default::default(), + } + } +} + +#[async_trait::async_trait] +pub trait ServerProviderClient: Display { + /// The username used to connect to the instances. + const USERNAME: &'static str; + + /// List all existing instances (regardless of their status). + async fn list_instances(&self) -> CloudProviderResult>; + + /// Start the specified instances. + async fn start_instances<'a, I>(&self, instances: I) -> CloudProviderResult<()> + where + I: Iterator + Send; + + /// Halt/Stop the specified instances. We may still be billed for stopped + /// instances. + async fn stop_instances<'a, I>(&self, instance_ids: I) -> CloudProviderResult<()> + where + I: Iterator + Send; + + /// Create an instance in a specific region. + async fn create_instance(&self, region: S) -> CloudProviderResult + where + S: Into + Serialize + Send; + + /// Delete a specific instance. Calling this function ensures we are no + /// longer billed for the specified instance. + async fn delete_instance(&self, instance: Instance) -> CloudProviderResult<()>; + + /// Authorize the provided ssh public key to access machines. + async fn register_ssh_public_key(&self, public_key: String) -> CloudProviderResult<()>; + + /// Return provider-specific commands to setup the instance. + async fn instance_setup_commands(&self) -> CloudProviderResult>; +} + +#[cfg(test)] +pub mod test_client { + use std::{fmt::Display, sync::Mutex}; + + use serde::Serialize; + + use super::{Instance, ServerProviderClient}; + use crate::{error::CloudProviderResult, settings::Settings}; + + pub struct TestClient { + settings: Settings, + instances: Mutex>, + } + + impl TestClient { + pub fn new(settings: Settings) -> Self { + Self { + settings, + instances: Mutex::new(Vec::new()), + } + } + } + + impl Display for TestClient { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "TestClient") + } + } + + #[async_trait::async_trait] + impl ServerProviderClient for TestClient { + const USERNAME: &'static str = "root"; + + async fn list_instances(&self) -> CloudProviderResult> { + let guard = self.instances.lock().unwrap(); + Ok(guard.clone()) + } + + async fn start_instances<'a, I>(&self, instances: I) -> CloudProviderResult<()> + where + I: Iterator + Send, + { + let instance_ids: Vec<_> = instances.map(|x| x.id.clone()).collect(); + let mut guard = self.instances.lock().unwrap(); + for instance in guard.iter_mut().filter(|x| instance_ids.contains(&x.id)) { + instance.status = "running".into(); + } + Ok(()) + } + + async fn stop_instances<'a, I>(&self, instances: I) -> CloudProviderResult<()> + where + I: Iterator + Send, + { + let instance_ids: Vec<_> = instances.map(|x| x.id.clone()).collect(); + let mut guard = self.instances.lock().unwrap(); + for instance in guard.iter_mut().filter(|x| instance_ids.contains(&x.id)) { + instance.status = "stopped".into(); + } + Ok(()) + } + + async fn create_instance(&self, region: S) -> CloudProviderResult + where + S: Into + Serialize + Send, + { + let mut guard = self.instances.lock().unwrap(); + let id = guard.len(); + let instance = Instance { + id: id.to_string(), + region: region.into(), + main_ip: format!("0.0.0.{id}").parse().unwrap(), + tags: Vec::new(), + specs: self.settings.specs.clone(), + status: "running".into(), + }; + guard.push(instance.clone()); + Ok(instance) + } + + async fn delete_instance(&self, instance: Instance) -> CloudProviderResult<()> { + let mut guard = self.instances.lock().unwrap(); + guard.retain(|x| x.id != instance.id); + Ok(()) + } + + async fn register_ssh_public_key(&self, _public_key: String) -> CloudProviderResult<()> { + Ok(()) + } + + async fn instance_setup_commands(&self) -> CloudProviderResult> { + Ok(Vec::new()) + } + } +} diff --git a/crates/iota-aws-orchestrator/src/display.rs b/crates/iota-aws-orchestrator/src/display.rs new file mode 100644 index 00000000000..adf701a392f --- /dev/null +++ b/crates/iota-aws-orchestrator/src/display.rs @@ -0,0 +1,118 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{fmt::Display, io::stdout}; + +use crossterm::{ + cursor::{RestorePosition, SavePosition}, + style::{Print, PrintStyledContent, Stylize}, + terminal::{Clear, ClearType}, +}; +use prettytable::format::{self}; + +pub fn header(message: S) { + crossterm::execute!( + stdout(), + PrintStyledContent(format!("\n{message}\n").green().bold()), + ) + .unwrap(); +} + +pub fn error(message: S) { + crossterm::execute!( + stdout(), + PrintStyledContent(format!("\n{message}\n").red().bold()), + ) + .unwrap(); +} + +pub fn warn(message: S) { + crossterm::execute!( + stdout(), + PrintStyledContent(format!("\n{message}\n").bold()), + ) + .unwrap(); +} + +pub fn config(name: N, value: V) { + crossterm::execute!( + stdout(), + PrintStyledContent(format!("{name}: ").bold()), + Print(format!("{value}\n")) + ) + .unwrap(); +} + +pub fn action(message: S) { + crossterm::execute!(stdout(), Print(format!("{message} ... ")), SavePosition).unwrap(); +} + +pub fn status(status: S) { + crossterm::execute!( + stdout(), + RestorePosition, + SavePosition, + Clear(ClearType::UntilNewLine), + Print(format!("[{status}]")) + ) + .unwrap(); +} + +pub fn done() { + crossterm::execute!( + stdout(), + RestorePosition, + Clear(ClearType::UntilNewLine), + Print(format!("[{}]\n", "Ok".green())) + ) + .unwrap(); +} + +pub fn newline() { + crossterm::execute!(stdout(), Print("\n")).unwrap(); +} + +/// Default style for tables printed to stdout. +pub fn default_table_format() -> format::TableFormat { + format::FormatBuilder::new() + .separators( + &[ + format::LinePosition::Top, + format::LinePosition::Bottom, + format::LinePosition::Title, + ], + format::LineSeparator::new('-', '-', '-', '-'), + ) + .padding(1, 1) + .build() +} + +#[cfg(test)] +mod test { + use std::time::Duration; + + use tokio::time::sleep; + + use super::{action, config, done, error, header, newline, warn}; + use crate::display::status; + + #[tokio::test] + #[ignore = "only used to manually check if prints work correctly"] + async fn display() { + header("This is a header"); + config("This is a config", 2); + action("Running a long function"); + for i in 0..5 { + sleep(Duration::from_secs(1)).await; + if i == 2 { + warn("This is a warning!"); + } + status(format!("{}/5", i + 1)); + } + done(); + error("This is an error!"); + warn("This is a warning!"); + newline(); + } +} diff --git a/crates/iota-aws-orchestrator/src/error.rs b/crates/iota-aws-orchestrator/src/error.rs new file mode 100644 index 00000000000..856ddc27d39 --- /dev/null +++ b/crates/iota-aws-orchestrator/src/error.rs @@ -0,0 +1,111 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::net::SocketAddr; + +use reqwest::Url; + +#[macro_export(local_inner_macros)] +macro_rules! ensure { + ($cond:expr, $e:expr) => { + if !($cond) { + return Err($e); + } + }; +} + +pub type SettingsResult = Result; + +#[derive(thiserror::Error, Debug)] +pub enum SettingsError { + #[error("Failed to read settings file '{file:?}': {message}")] + InvalidSettings { file: String, message: String }, + + #[error("Failed to read token file '{file:?}': {message}")] + InvalidTokenFile { file: String, message: String }, + + #[error("Failed to read ssh public key file '{file:?}': {message}")] + InvalidSshPublicKeyFile { file: String, message: String }, + + #[error("Malformed repository url: {0:?}")] + MalformedRepositoryUrl(Url), +} + +pub type CloudProviderResult = Result; + +#[derive(thiserror::Error, Debug)] +pub enum CloudProviderError { + #[error("Failed to send server request: {0}")] + RequestError(String), + + #[error("Unexpected response: {0}")] + UnexpectedResponse(String), + + #[error("Received error status code ({0}): {1}")] + FailureResponseCode(String, String), + + #[error("SSH key \"{0}\" not found")] + SshKeyNotFound(String), +} + +pub type SshResult = Result; + +#[derive(thiserror::Error, Debug)] +pub enum SshError { + #[error("Failed to load private key for {address}: {error}")] + PrivateKeyError { + address: SocketAddr, + error: russh_keys::Error, + }, + + #[error("Failed to create ssh session with {address}: {error}")] + SessionError { + address: SocketAddr, + error: russh::Error, + }, + + #[error("Failed to connect to instance {address}: {error}")] + ConnectionError { + address: SocketAddr, + error: russh::Error, + }, + + #[error("Remote execution on {address} returned exit code ({code}): {message}")] + NonZeroExitCode { + address: SocketAddr, + code: u32, + message: String, + }, +} + +pub type MonitorResult = Result; + +#[derive(thiserror::Error, Debug)] +pub enum MonitorError { + #[error(transparent)] + SshError(#[from] SshError), + + #[error("Failed to start Grafana: {0}")] + GrafanaError(String), +} + +pub type TestbedResult = Result; + +#[derive(thiserror::Error, Debug)] +pub enum TestbedError { + #[error(transparent)] + SettingsError(#[from] SettingsError), + + #[error(transparent)] + CloudProviderError(#[from] CloudProviderError), + + #[error(transparent)] + SshError(#[from] SshError), + + #[error("Not enough instances: missing {0} instances")] + InsufficientCapacity(usize), + + #[error(transparent)] + MonitorError(#[from] MonitorError), +} diff --git a/crates/sui-aws-orchestrator/src/faults.rs b/crates/iota-aws-orchestrator/src/faults.rs similarity index 99% rename from crates/sui-aws-orchestrator/src/faults.rs rename to crates/iota-aws-orchestrator/src/faults.rs index e1de1b285a4..25db502be39 100644 --- a/crates/sui-aws-orchestrator/src/faults.rs +++ b/crates/iota-aws-orchestrator/src/faults.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/sui-aws-orchestrator/src/logs.rs b/crates/iota-aws-orchestrator/src/logs.rs similarity index 97% rename from crates/sui-aws-orchestrator/src/logs.rs rename to crates/iota-aws-orchestrator/src/logs.rs index d0921ee0f3a..29b2b0f55af 100644 --- a/crates/sui-aws-orchestrator/src/logs.rs +++ b/crates/iota-aws-orchestrator/src/logs.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::cmp::max; diff --git a/crates/iota-aws-orchestrator/src/main.rs b/crates/iota-aws-orchestrator/src/main.rs new file mode 100644 index 00000000000..302daeb7810 --- /dev/null +++ b/crates/iota-aws-orchestrator/src/main.rs @@ -0,0 +1,348 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{str::FromStr, time::Duration}; + +use benchmark::{BenchmarkParametersGenerator, LoadType}; +use clap::Parser; +use client::{aws::AwsClient, ServerProviderClient}; +use eyre::{Context, Result}; +use faults::FaultsType; +use measurement::MeasurementsCollection; +use orchestrator::Orchestrator; +use protocol::narwhal::{NarwhalBenchmarkType, NarwhalProtocol}; +use settings::{CloudProvider, Settings}; +use ssh::SshConnectionManager; +use testbed::Testbed; + +pub mod benchmark; +pub mod client; +pub mod display; +pub mod error; +pub mod faults; +pub mod logs; +pub mod measurement; +mod monitor; +pub mod orchestrator; +pub mod protocol; +pub mod settings; +pub mod ssh; +pub mod testbed; + +/// NOTE: Link these types to the correct protocol. Either Iota or Narwhal. +// use protocol::iota::{IotaBenchmarkType, IotaProtocol}; +// type Protocol = IotaProtocol; +// type BenchmarkType = IotaBenchmarkType; +type Protocol = NarwhalProtocol; +type BenchmarkType = NarwhalBenchmarkType; + +#[derive(Parser)] +#[command(author, version, about = "Testbed orchestrator", long_about = None)] +pub struct Opts { + /// The path to the settings file. This file contains basic information to + /// deploy testbeds and run benchmarks such as the url of the git repo, + /// the commit to deploy, etc. + #[clap( + long, + value_name = "FILE", + default_value = "crates/iota-aws-orchestrator/assets/settings.json", + global = true + )] + settings_path: String, + + /// The type of operation to run. + #[clap(subcommand)] + operation: Operation, +} + +#[derive(Parser)] +pub enum Operation { + /// Get or modify the status of the testbed. + Testbed { + #[clap(subcommand)] + action: TestbedAction, + }, + + /// Run a benchmark on the specified testbed. + Benchmark { + /// Percentage of shared vs owned objects; 0 means only owned objects + /// and 100 means only shared objects. + #[clap(long, default_value = "0", global = true)] + benchmark_type: String, + + /// The committee size to deploy. + #[clap(long, value_name = "INT")] + committee: usize, + + /// Number of faulty nodes. + #[clap(long, value_name = "INT", default_value = "0", global = true)] + faults: usize, + + /// Whether the faulty nodes recover. + #[clap(long, action, default_value = "false", global = true)] + crash_recovery: bool, + + /// The interval to crash nodes in seconds. + #[clap(long, value_parser = parse_duration, default_value = "60", global = true)] + crash_interval: Duration, + + /// The minimum duration of the benchmark in seconds. + #[clap(long, value_parser = parse_duration, default_value = "600", global = true)] + duration: Duration, + + /// The interval between measurements collection in seconds. + #[clap(long, value_parser = parse_duration, default_value = "15", global = true)] + scrape_interval: Duration, + + /// Whether to skip testbed updates before running benchmarks. + #[clap(long, action, default_value = "false", global = true)] + skip_testbed_update: bool, + + /// Whether to skip testbed configuration before running benchmarks. + #[clap(long, action, default_value = "false", global = true)] + skip_testbed_configuration: bool, + + /// Whether to download and analyze the client and node log files. + #[clap(long, action, default_value = "false", global = true)] + log_processing: bool, + + /// The number of instances running exclusively load generators. If set + /// to zero the orchestrator collocates one load generator with + /// each node. + #[clap(long, value_name = "INT", default_value = "0", global = true)] + dedicated_clients: usize, + + /// Whether to forgo a grafana and prometheus instance and leave the + /// testbed unmonitored. + #[clap(long, action, default_value = "false", global = true)] + skip_monitoring: bool, + + /// The timeout duration for ssh commands (in seconds). + #[clap(long, action, value_parser = parse_duration, default_value = "30", global = true)] + timeout: Duration, + + /// The number of times the orchestrator should retry an ssh command. + #[clap(long, value_name = "INT", default_value = "5", global = true)] + retries: usize, + + /// The load to submit to the system. + #[clap(subcommand)] + load_type: Load, + }, + + /// Print a summary of the specified measurements collection. + Summarize { + /// The path to the settings file. + #[clap(long, value_name = "FILE")] + path: String, + }, +} + +#[derive(Parser)] +#[clap(rename_all = "kebab-case")] +pub enum TestbedAction { + /// Display the testbed status. + Status, + + /// Deploy the specified number of instances in all regions specified by in + /// the setting file. + Deploy { + /// Number of instances to deploy. + #[clap(long)] + instances: usize, + + /// The region where to deploy the instances. If this parameter is not + /// specified, the command deploys the specified number of + /// instances in all regions listed in the setting file. + #[clap(long)] + region: Option, + }, + + /// Start at most the specified number of instances per region on an + /// existing testbed. + Start { + /// Number of instances to deploy. + #[clap(long, default_value = "200")] + instances: usize, + }, + + /// Stop an existing testbed (without destroying the instances). + Stop, + + /// Destroy the testbed and terminate all instances. + Destroy, +} + +#[derive(Parser)] +pub enum Load { + /// The fixed loads (in tx/s) to submit to the nodes. + FixedLoad { + /// A list of fixed load (tx/s). + #[clap( + long, + value_name = "INT", + num_args(1..), + value_delimiter = ',' + )] + loads: Vec, + }, + + /// Search for the maximum load that the system can sustainably handle. + Search { + /// The initial load (in tx/s) to test and use a baseline. + #[clap(long, value_name = "INT", default_value = "250")] + starting_load: usize, + /// The maximum number of iterations before converging on a breaking + /// point. + #[clap(long, value_name = "INT", default_value = "5")] + max_iterations: usize, + }, +} + +fn parse_duration(arg: &str) -> Result { + let seconds = arg.parse()?; + Ok(Duration::from_secs(seconds)) +} + +#[tokio::main] +async fn main() -> Result<()> { + color_eyre::install()?; + let opts: Opts = Opts::parse(); + + // Load the settings files. + let settings = Settings::load(&opts.settings_path).wrap_err("Failed to load settings")?; + + match &settings.cloud_provider { + CloudProvider::Aws => { + // Create the client for the cloud provider. + let client = AwsClient::new(settings.clone()).await; + + // Execute the command. + run(settings, client, opts).await + } + } +} + +async fn run(settings: Settings, client: C, opts: Opts) -> Result<()> { + // Create a new testbed. + let mut testbed = Testbed::new(settings.clone(), client) + .await + .wrap_err("Failed to create testbed")?; + + match opts.operation { + Operation::Testbed { action } => match action { + // Display the current status of the testbed. + TestbedAction::Status => testbed.status(), + + // Deploy the specified number of instances on the testbed. + TestbedAction::Deploy { instances, region } => testbed + .deploy(instances, region) + .await + .wrap_err("Failed to deploy testbed")?, + + // Start the specified number of instances on an existing testbed. + TestbedAction::Start { instances } => testbed + .start(instances) + .await + .wrap_err("Failed to start testbed")?, + + // Stop an existing testbed. + TestbedAction::Stop => testbed.stop().await.wrap_err("Failed to stop testbed")?, + + // Destroy the testbed and terminal all instances. + TestbedAction::Destroy => testbed + .destroy() + .await + .wrap_err("Failed to destroy testbed")?, + }, + + // Run benchmarks. + Operation::Benchmark { + benchmark_type, + committee, + faults, + crash_recovery, + crash_interval, + duration, + scrape_interval, + skip_testbed_update, + skip_testbed_configuration, + log_processing, + dedicated_clients, + skip_monitoring, + timeout, + retries, + load_type, + } => { + // Create a new orchestrator to instruct the testbed. + let username = testbed.username(); + let private_key_file = settings.ssh_private_key_file.clone(); + let ssh_manager = SshConnectionManager::new(username.into(), private_key_file) + .with_timeout(timeout) + .with_retries(retries); + + let instances = testbed.instances(); + + let setup_commands = testbed + .setup_commands() + .await + .wrap_err("Failed to load testbed setup commands")?; + + let protocol_commands = Protocol::new(&settings); + let benchmark_type = BenchmarkType::from_str(&benchmark_type)?; + + let load = match load_type { + Load::FixedLoad { loads } => { + let loads = if loads.is_empty() { vec![200] } else { loads }; + LoadType::Fixed(loads) + } + Load::Search { + starting_load, + max_iterations, + } => LoadType::Search { + starting_load, + max_iterations, + }, + }; + + let fault_type = if !crash_recovery || faults == 0 { + FaultsType::Permanent { faults } + } else { + FaultsType::CrashRecovery { + max_faults: faults, + interval: crash_interval, + } + }; + + let generator = BenchmarkParametersGenerator::new(committee, load) + .with_benchmark_type(benchmark_type) + .with_custom_duration(duration) + .with_faults(fault_type); + + Orchestrator::new( + settings, + instances, + setup_commands, + protocol_commands, + ssh_manager, + ) + .with_scrape_interval(scrape_interval) + .with_crash_interval(crash_interval) + .skip_testbed_updates(skip_testbed_update) + .skip_testbed_configuration(skip_testbed_configuration) + .with_log_processing(log_processing) + .with_dedicated_clients(dedicated_clients) + .skip_monitoring(skip_monitoring) + .run_benchmarks(generator) + .await + .wrap_err("Failed to run benchmarks")?; + } + + // Print a summary of the specified measurements collection. + Operation::Summarize { path } => { + MeasurementsCollection::::load(path)?.display_summary() + } + } + Ok(()) +} diff --git a/crates/sui-aws-orchestrator/src/measurement.rs b/crates/iota-aws-orchestrator/src/measurement.rs similarity index 99% rename from crates/sui-aws-orchestrator/src/measurement.rs rename to crates/iota-aws-orchestrator/src/measurement.rs index ebba07bf017..4c340017808 100644 --- a/crates/sui-aws-orchestrator/src/measurement.rs +++ b/crates/iota-aws-orchestrator/src/measurement.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/sui-aws-orchestrator/src/monitor.rs b/crates/iota-aws-orchestrator/src/monitor.rs similarity index 99% rename from crates/sui-aws-orchestrator/src/monitor.rs rename to crates/iota-aws-orchestrator/src/monitor.rs index cfa02acf6ee..2ce01cf57b3 100644 --- a/crates/sui-aws-orchestrator/src/monitor.rs +++ b/crates/iota-aws-orchestrator/src/monitor.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fs, net::SocketAddr, path::PathBuf}; diff --git a/crates/iota-aws-orchestrator/src/orchestrator.rs b/crates/iota-aws-orchestrator/src/orchestrator.rs new file mode 100644 index 00000000000..30673912b65 --- /dev/null +++ b/crates/iota-aws-orchestrator/src/orchestrator.rs @@ -0,0 +1,649 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{HashMap, VecDeque}, + fs::{self}, + marker::PhantomData, + path::PathBuf, + time::Duration, +}; + +use tokio::time::{self, Instant}; + +use crate::{ + benchmark::{BenchmarkParameters, BenchmarkParametersGenerator, BenchmarkType}, + client::Instance, + display, ensure, + error::{TestbedError, TestbedResult}, + faults::CrashRecoverySchedule, + logs::LogsAnalyzer, + measurement::{Measurement, MeasurementsCollection}, + monitor::Monitor, + protocol::{ProtocolCommands, ProtocolMetrics}, + settings::Settings, + ssh::{CommandContext, CommandStatus, SshConnectionManager}, +}; + +/// An orchestrator to run benchmarks on a testbed. +pub struct Orchestrator { + /// The testbed's settings. + settings: Settings, + /// The state of the testbed (reflecting accurately the state of the + /// machines). + instances: Vec, + /// The type of the benchmark parameters. + benchmark_type: PhantomData, + /// Provider-specific commands to install on the instance. + instance_setup_commands: Vec, + /// Protocol-specific commands generator to generate the protocol + /// configuration files, boot clients and nodes, etc. + protocol_commands: P, + /// The interval between measurements collection. + scrape_interval: Duration, + /// The interval to crash nodes. + crash_interval: Duration, + /// Handle ssh connections to instances. + ssh_manager: SshConnectionManager, + /// Whether to skip testbed updates before running benchmarks. + skip_testbed_update: bool, + /// Whether to skip testbed configuration before running benchmarks. + skip_testbed_configuration: bool, + /// Whether to downloading and analyze the client and node log files. + log_processing: bool, + /// Number of instances running only load generators (not nodes). If this + /// value is set to zero, the orchestrator runs a load generate + /// collocated with each node. + dedicated_clients: usize, + /// Whether to forgo a grafana and prometheus instance and leave the testbed + /// unmonitored. + skip_monitoring: bool, +} + +impl Orchestrator { + /// The default interval between measurements collection. + const DEFAULT_SCRAPE_INTERVAL: Duration = Duration::from_secs(15); + /// The default interval to crash nodes. + const DEFAULT_CRASH_INTERVAL: Duration = Duration::from_secs(60); + + /// Make a new orchestrator. + pub fn new( + settings: Settings, + instances: Vec, + instance_setup_commands: Vec, + protocol_commands: P, + ssh_manager: SshConnectionManager, + ) -> Self { + Self { + settings, + instances, + benchmark_type: PhantomData, + instance_setup_commands, + protocol_commands, + ssh_manager, + scrape_interval: Self::DEFAULT_SCRAPE_INTERVAL, + crash_interval: Self::DEFAULT_CRASH_INTERVAL, + skip_testbed_update: false, + skip_testbed_configuration: false, + log_processing: false, + dedicated_clients: 0, + skip_monitoring: false, + } + } + + /// Set interval between measurements collection. + pub fn with_scrape_interval(mut self, scrape_interval: Duration) -> Self { + self.scrape_interval = scrape_interval; + self + } + + /// Set interval with which to crash nodes. + pub fn with_crash_interval(mut self, crash_interval: Duration) -> Self { + self.crash_interval = crash_interval; + self + } + + /// Set whether to skip testbed updates before running benchmarks. + pub fn skip_testbed_updates(mut self, skip_testbed_update: bool) -> Self { + self.skip_testbed_update = skip_testbed_update; + self + } + + /// Whether to skip testbed configuration before running benchmarks. + pub fn skip_testbed_configuration(mut self, skip_testbed_configuration: bool) -> Self { + self.skip_testbed_configuration = skip_testbed_configuration; + self + } + + /// Set whether to download and analyze the client and node log files. + pub fn with_log_processing(mut self, log_processing: bool) -> Self { + self.log_processing = log_processing; + self + } + + /// Set the number of instances running exclusively load generators. + pub fn with_dedicated_clients(mut self, dedicated_clients: usize) -> Self { + self.dedicated_clients = dedicated_clients; + self + } + + /// Set whether to boot grafana on the local machine to monitor the nodes. + pub fn skip_monitoring(mut self, skip_monitoring: bool) -> Self { + self.skip_monitoring = skip_monitoring; + self + } + + /// Select on which instances of the testbed to run the benchmarks. This + /// function returns two vector of instances; the first contains the + /// instances on which to run the load generators and the second + /// contains the instances on which to run the nodes. + pub fn select_instances( + &self, + parameters: &BenchmarkParameters, + ) -> TestbedResult<(Vec, Vec, Option)> { + // Ensure there are enough active instances. + let available_instances: Vec<_> = self.instances.iter().filter(|x| x.is_active()).collect(); + let minimum_instances = if self.skip_monitoring { + parameters.nodes + self.dedicated_clients + } else { + parameters.nodes + self.dedicated_clients + 1 + }; + ensure!( + available_instances.len() >= minimum_instances, + TestbedError::InsufficientCapacity(minimum_instances - available_instances.len()) + ); + + // Sort the instances by region. + let mut instances_by_regions = HashMap::new(); + for instance in available_instances { + instances_by_regions + .entry(&instance.region) + .or_insert_with(VecDeque::new) + .push_back(instance); + } + + // Select the instance to host the monitoring stack. + let mut monitoring_instance = None; + if !self.skip_monitoring { + for region in &self.settings.regions { + if let Some(regional_instances) = instances_by_regions.get_mut(region) { + if let Some(instance) = regional_instances.pop_front() { + monitoring_instance = Some(instance.clone()); + } + break; + } + } + } + + // Select the instances to host exclusively load generators. + let mut client_instances = Vec::new(); + for region in self.settings.regions.iter().cycle() { + if client_instances.len() == self.dedicated_clients { + break; + } + if let Some(regional_instances) = instances_by_regions.get_mut(region) { + if let Some(instance) = regional_instances.pop_front() { + client_instances.push(instance.clone()); + } + } + } + + // Select the instances to host the nodes. + let mut nodes_instances = Vec::new(); + for region in self.settings.regions.iter().cycle() { + if nodes_instances.len() == parameters.nodes { + break; + } + if let Some(regional_instances) = instances_by_regions.get_mut(region) { + if let Some(instance) = regional_instances.pop_front() { + nodes_instances.push(instance.clone()); + } + } + } + + // Spawn a load generate collocated with each node if there are no instances + // dedicated to excursively run load generators. + if client_instances.is_empty() { + client_instances = nodes_instances.clone(); + } + + Ok((client_instances, nodes_instances, monitoring_instance)) + } +} + +impl + ProtocolMetrics, T: BenchmarkType> Orchestrator { + /// Boot one node per instance. + async fn boot_nodes( + &self, + instances: Vec, + parameters: &BenchmarkParameters, + ) -> TestbedResult<()> { + // Run one node per instance. + let targets = self + .protocol_commands + .node_command(instances.clone(), parameters); + + let repo = self.settings.repository_name(); + let context = CommandContext::new() + .run_background("node".into()) + .with_log_file("~/node.log".into()) + .with_execute_from_path(repo.into()); + self.ssh_manager + .execute_per_instance(targets, context) + .await?; + + // Wait until all nodes are reachable. + let commands = self + .protocol_commands + .nodes_metrics_command(instances.clone()); + self.ssh_manager.wait_for_success(commands).await; + + Ok(()) + } + + /// Install the codebase and its dependencies on the testbed. + pub async fn install(&self) -> TestbedResult<()> { + display::action("Installing dependencies on all machines"); + + let working_dir = self.settings.working_dir.display(); + let url = &self.settings.repository.url; + let basic_commands = [ + "sudo apt-get update", + "sudo apt-get -y upgrade", + "sudo apt-get -y autoremove", + // Disable "pending kernel upgrade" message. + "sudo apt-get -y remove needrestart", + // The following dependencies: + // * build-essential: prevent the error: [error: linker `cc` not found]. + // * libssl-dev - Required to compile the orchestrator, todo remove this dependency + "sudo apt-get -y install build-essential libssl-dev", + // Install rust (non-interactive). + "curl --proto \"=https\" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y", + "echo \"source $HOME/.cargo/env\" | tee -a ~/.bashrc", + "source $HOME/.cargo/env", + "rustup default stable", + // Create the working directory. + &format!("mkdir -p {working_dir}"), + // Clone the repo. + &format!("(git clone {url} || true)"), + ]; + + let cloud_provider_specific_dependencies: Vec<_> = self + .instance_setup_commands + .iter() + .map(|x| x.as_str()) + .collect(); + + let protocol_dependencies = self.protocol_commands.protocol_dependencies(); + + let command = [ + &basic_commands[..], + &Monitor::dependencies()[..], + &cloud_provider_specific_dependencies[..], + &protocol_dependencies[..], + ] + .concat() + .join(" && "); + + let active = self.instances.iter().filter(|x| x.is_active()).cloned(); + let context = CommandContext::default(); + self.ssh_manager.execute(active, command, context).await?; + + display::done(); + Ok(()) + } + + /// Reload prometheus on all instances. + pub async fn start_monitoring(&self, parameters: &BenchmarkParameters) -> TestbedResult<()> { + let (clients, nodes, instance) = self.select_instances(parameters)?; + if let Some(instance) = instance { + display::action("Configuring monitoring instance"); + + let monitor = Monitor::new(instance, clients, nodes, self.ssh_manager.clone()); + monitor.start_prometheus(&self.protocol_commands).await?; + monitor.start_grafana().await?; + + display::done(); + display::config("Grafana address", monitor.grafana_address()); + display::newline(); + } + + Ok(()) + } + + /// Update all instances to use the version of the codebase specified in the + /// setting file. + pub async fn update(&self) -> TestbedResult<()> { + display::action("Updating all instances"); + + // Update all active instances. This requires compiling the codebase in release + // (which may take a long time) so we run the command in the background + // to avoid keeping alive many ssh connections for too long. + let commit = &self.settings.repository.commit; + let command = [ + "git fetch -f", + &format!("(git checkout -b {commit} {commit} || git checkout -f {commit})"), + "(git pull -f || true)", + "source $HOME/.cargo/env", + "cargo build --release", + ] + .join(" && "); + + let active = self.instances.iter().filter(|x| x.is_active()).cloned(); + + let id = "update"; + let repo_name = self.settings.repository_name(); + let context = CommandContext::new() + .run_background(id.into()) + .with_execute_from_path(repo_name.into()); + self.ssh_manager + .execute(active.clone(), command, context) + .await?; + + // Wait until the command finished running. + self.ssh_manager + .wait_for_command(active, id, CommandStatus::Terminated) + .await?; + + display::done(); + Ok(()) + } + + /// Configure the instances with the appropriate configuration files. + pub async fn configure(&self, parameters: &BenchmarkParameters) -> TestbedResult<()> { + display::action("Configuring instances"); + + // Select instances to configure. + let (clients, nodes, _) = self.select_instances(parameters)?; + + // Generate the genesis configuration file and the keystore allowing access to + // gas objects. + let command = self.protocol_commands.genesis_command(nodes.iter()); + let repo_name = self.settings.repository_name(); + let context = CommandContext::new().with_execute_from_path(repo_name.into()); + let all = clients.into_iter().chain(nodes); + self.ssh_manager.execute(all, command, context).await?; + + display::done(); + Ok(()) + } + + /// Cleanup all instances and optionally delete their log files. + pub async fn cleanup(&self, cleanup: bool) -> TestbedResult<()> { + display::action("Cleaning up testbed"); + + // Kill all tmux servers and delete the nodes dbs. Optionally clear logs. + let mut command = vec!["(tmux kill-server || true)".into()]; + for path in self.protocol_commands.db_directories() { + command.push(format!("(rm -rf {} || true)", path.display())); + } + if cleanup { + command.push("(rm -rf ~/*log* || true)".into()); + } + let command = command.join(" ; "); + + // Execute the deletion on all machines. + let active = self.instances.iter().filter(|x| x.is_active()).cloned(); + let context = CommandContext::default(); + self.ssh_manager.execute(active, command, context).await?; + + display::done(); + Ok(()) + } + + /// Deploy the nodes. + pub async fn run_nodes(&self, parameters: &BenchmarkParameters) -> TestbedResult<()> { + display::action("Deploying validators"); + + // Select the instances to run. + let (_, nodes, _) = self.select_instances(parameters)?; + + // Boot one node per instance. + self.boot_nodes(nodes, parameters).await?; + + display::done(); + Ok(()) + } + + /// Deploy the load generators. + pub async fn run_clients(&self, parameters: &BenchmarkParameters) -> TestbedResult<()> { + display::action("Setting up load generators"); + + // Select the instances to run. + let (clients, _, _) = self.select_instances(parameters)?; + + // Deploy the load generators. + let targets = self + .protocol_commands + .client_command(clients.clone(), parameters); + + let repo = self.settings.repository_name(); + let context = CommandContext::new() + .run_background("client".into()) + .with_log_file("~/client.log".into()) + .with_execute_from_path(repo.into()); + self.ssh_manager + .execute_per_instance(targets, context) + .await?; + + // Wait until all load generators are reachable. + let commands = self.protocol_commands.clients_metrics_command(clients); + self.ssh_manager.wait_for_success(commands).await; + + display::done(); + Ok(()) + } + + /// Collect metrics from the load generators. + pub async fn run( + &self, + parameters: &BenchmarkParameters, + ) -> TestbedResult> { + display::action(format!( + "Scraping metrics (at least {}s)", + parameters.duration.as_secs() + )); + + // Select the instances to run. + let (clients, nodes, _) = self.select_instances(parameters)?; + + // Regularly scrape the client + let mut metrics_commands = self.protocol_commands.clients_metrics_command(clients); + + // TODO: Remove this when narwhal client latency metrics are available. + // We will be getting latency metrics directly from narwhal nodes instead from + // the nw client + metrics_commands.append(&mut self.protocol_commands.nodes_metrics_command(nodes.clone())); + + let mut aggregator = MeasurementsCollection::new(&self.settings, parameters.clone()); + let mut metrics_interval = time::interval(self.scrape_interval); + metrics_interval.tick().await; // The first tick returns immediately. + + let faults_type = parameters.faults.clone(); + let mut faults_schedule = CrashRecoverySchedule::new(faults_type, nodes.clone()); + let mut faults_interval = time::interval(self.crash_interval); + faults_interval.tick().await; // The first tick returns immediately. + + let start = Instant::now(); + loop { + tokio::select! { + // Scrape metrics. + now = metrics_interval.tick() => { + let elapsed = now.duration_since(start).as_secs_f64().ceil() as u64; + display::status(format!("{elapsed}s")); + + let stdio = self + .ssh_manager + .execute_per_instance(metrics_commands.clone(), CommandContext::default()) + .await?; + for (i, (stdout, _stderr)) in stdio.iter().enumerate() { + let measurement = Measurement::from_prometheus::

    (stdout); + aggregator.add(i, measurement); + } + + if elapsed > parameters.duration .as_secs() { + break; + } + }, + + // Kill and recover nodes according to the input schedule. + _ = faults_interval.tick() => { + let action = faults_schedule.update(); + if !action.kill.is_empty() { + self.ssh_manager.kill(action.kill.clone(), "node").await?; + } + if !action.boot.is_empty() { + self.boot_nodes(action.boot.clone(), parameters).await?; + } + if !action.kill.is_empty() || !action.boot.is_empty() { + display::newline(); + display::config("Testbed update", action); + } + } + } + } + + let results_directory = &self.settings.results_dir; + let commit = &self.settings.repository.commit; + let path: PathBuf = [results_directory, &format!("results-{commit}").into()] + .iter() + .collect(); + fs::create_dir_all(&path).expect("Failed to create log directory"); + aggregator.save(path); + + display::done(); + Ok(aggregator) + } + + /// Download the log files from the nodes and clients. + pub async fn download_logs( + &self, + parameters: &BenchmarkParameters, + ) -> TestbedResult { + // Select the instances to run. + let (clients, nodes, _) = self.select_instances(parameters)?; + + // Create a log sub-directory for this run. + let commit = &self.settings.repository.commit; + let path: PathBuf = [ + &self.settings.logs_dir, + &format!("logs-{commit}").into(), + &format!("logs-{parameters:?}").into(), + ] + .iter() + .collect(); + fs::create_dir_all(&path).expect("Failed to create log directory"); + + // NOTE: Our ssh library does not seem to be able to transfers files in parallel + // reliably. + let mut log_parsers = Vec::new(); + + // Download the clients log files. + display::action("Downloading clients logs"); + for (i, instance) in clients.iter().enumerate() { + display::status(format!("{}/{}", i + 1, clients.len())); + + let connection = self.ssh_manager.connect(instance.ssh_address()).await?; + let client_log_content = connection.download("client.log").await?; + + let client_log_file = [path.clone(), format!("client-{i}.log").into()] + .iter() + .collect::(); + fs::write(&client_log_file, client_log_content.as_bytes()) + .expect("Cannot write log file"); + + let mut log_parser = LogsAnalyzer::default(); + log_parser.set_client_errors(&client_log_content); + log_parsers.push(log_parser) + } + display::done(); + + display::action("Downloading nodes logs"); + for (i, instance) in nodes.iter().enumerate() { + display::status(format!("{}/{}", i + 1, nodes.len())); + + let connection = self.ssh_manager.connect(instance.ssh_address()).await?; + let node_log_content = connection.download("node.log").await?; + + let node_log_file = [path.clone(), format!("node-{i}.log").into()] + .iter() + .collect::(); + fs::write(&node_log_file, node_log_content.as_bytes()).expect("Cannot write log file"); + + let mut log_parser = LogsAnalyzer::default(); + log_parser.set_node_errors(&node_log_content); + log_parsers.push(log_parser) + } + display::done(); + + Ok(LogsAnalyzer::aggregate(log_parsers)) + } + + /// Run all the benchmarks specified by the benchmark generator. + pub async fn run_benchmarks( + &mut self, + mut generator: BenchmarkParametersGenerator, + ) -> TestbedResult<()> { + display::header("Preparing testbed"); + display::config("Commit", format!("'{}'", &self.settings.repository.commit)); + display::newline(); + + // Cleanup the testbed (in case the previous run was not completed). + self.cleanup(true).await?; + + // Update the software on all instances. + if !self.skip_testbed_update { + self.install().await?; + self.update().await?; + } + + // Run all benchmarks. + let mut i = 1; + let mut latest_committee_size = 0; + while let Some(parameters) = generator.next() { + display::header(format!("Starting benchmark {i}")); + display::config("Benchmark type", ¶meters.benchmark_type); + display::config("Parameters", ¶meters); + display::newline(); + + // Cleanup the testbed (in case the previous run was not completed). + self.cleanup(true).await?; + // Start the instance monitoring tools. + self.start_monitoring(¶meters).await?; + + // Configure all instances (if needed). + if !self.skip_testbed_configuration && latest_committee_size != parameters.nodes { + self.configure(¶meters).await?; + latest_committee_size = parameters.nodes; + } + + // Deploy the validators. + self.run_nodes(¶meters).await?; + + // Deploy the load generators. + self.run_clients(¶meters).await?; + + // Wait for the benchmark to terminate. Then save the results and print a + // summary. + let aggregator = self.run(¶meters).await?; + aggregator.display_summary(); + generator.register_result(aggregator); + // drop(monitor); + + // Kill the nodes and clients (without deleting the log files). + self.cleanup(false).await?; + + // Download the log files. + if self.log_processing { + let error_counter = self.download_logs(¶meters).await?; + error_counter.print_summary(); + } + + i += 1; + } + + display::header("Benchmark completed"); + Ok(()) + } +} diff --git a/crates/iota-aws-orchestrator/src/protocol/iota.rs b/crates/iota-aws-orchestrator/src/protocol/iota.rs new file mode 100644 index 00000000000..914a3adfdf7 --- /dev/null +++ b/crates/iota-aws-orchestrator/src/protocol/iota.rs @@ -0,0 +1,295 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + fmt::{Debug, Display}, + path::PathBuf, + str::FromStr, +}; + +use iota_swarm_config::genesis_config::GenesisConfig; +use iota_types::{base_types::IotaAddress, multiaddr::Multiaddr}; +use serde::{Deserialize, Serialize}; + +use super::{ProtocolCommands, ProtocolMetrics}; +use crate::{ + benchmark::{BenchmarkParameters, BenchmarkType}, + client::Instance, + settings::Settings, +}; + +#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct IotaBenchmarkType { + /// Percentage of shared vs owned objects; 0 means only owned objects and + /// 100 means only shared objects. + shared_objects_ratio: u16, +} + +impl Debug for IotaBenchmarkType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.shared_objects_ratio) + } +} + +impl Display for IotaBenchmarkType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}% shared objects", self.shared_objects_ratio) + } +} + +impl FromStr for IotaBenchmarkType { + type Err = std::num::ParseIntError; + + fn from_str(s: &str) -> Result { + Ok(Self { + shared_objects_ratio: s.parse::()?.min(100), + }) + } +} + +impl BenchmarkType for IotaBenchmarkType {} + +/// All configurations information to run a Iota client or validator. +pub struct IotaProtocol { + working_dir: PathBuf, +} + +impl ProtocolCommands for IotaProtocol { + fn protocol_dependencies(&self) -> Vec<&'static str> { + vec![ + // Install typical iota dependencies. + "sudo apt-get -y install curl git-all clang cmake gcc libssl-dev pkg-config libclang-dev", + // This dependency is missing from the Iota docs. + "sudo apt-get -y install libpq-dev", + ] + } + + fn db_directories(&self) -> Vec { + let authorities_db = [&self.working_dir, &iota_config::AUTHORITIES_DB_NAME.into()] + .iter() + .collect(); + let consensus_db = [&self.working_dir, &iota_config::CONSENSUS_DB_NAME.into()] + .iter() + .collect(); + vec![authorities_db, consensus_db] + } + + fn genesis_command<'a, I>(&self, instances: I) -> String + where + I: Iterator, + { + let working_dir = self.working_dir.display(); + let ips = instances + .map(|x| x.main_ip.to_string()) + .collect::>() + .join(" "); + let genesis = [ + "cargo run --release --bin iota --", + "genesis", + &format!("-f --working-dir {working_dir} --benchmark-ips {ips}"), + ] + .join(" "); + + [ + &format!("mkdir -p {working_dir}"), + "source $HOME/.cargo/env", + &genesis, + ] + .join(" && ") + } + + fn monitor_command(&self, _instances: I) -> Vec<(Instance, String)> + where + I: IntoIterator, + { + // instances + // .into_iter() + // .map(|i| { + // ( + // i, + // "tail -f --pid=$(pidof iota) -f /dev/null; tail -100 + // node.log".to_string(), ) + // }) + // .collect() + vec![] + } + + fn node_command( + &self, + instances: I, + _parameters: &BenchmarkParameters, + ) -> Vec<(Instance, String)> + where + I: IntoIterator, + { + let working_dir = self.working_dir.clone(); + let network_addresses = Self::resolve_network_addresses(instances); + + network_addresses + .into_iter() + .enumerate() + .map(|(i, (instance, network_address))| { + let validator_config = + iota_config::validator_config_file(network_address.clone(), i); + let config_path: PathBuf = working_dir.join(validator_config); + + let run = [ + "cargo run --release --bin iota-node --", + &format!( + "--config-path {} --listen-address {}", + config_path.display(), + network_address.with_zero_ip() + ), + ] + .join(" "); + let command = ["source $HOME/.cargo/env", &run].join(" && "); + + (instance, command) + }) + .collect() + } + + fn client_command( + &self, + instances: I, + parameters: &BenchmarkParameters, + ) -> Vec<(Instance, String)> + where + I: IntoIterator, + { + let genesis_path: PathBuf = [ + &self.working_dir, + &iota_config::IOTA_GENESIS_FILENAME.into(), + ] + .iter() + .collect(); + let keystore_path: PathBuf = [ + &self.working_dir, + &iota_config::IOTA_BENCHMARK_GENESIS_GAS_KEYSTORE_FILENAME.into(), + ] + .iter() + .collect(); + + let committee_size = parameters.nodes; + let clients: Vec<_> = instances.into_iter().collect(); + let load_share = parameters.load / clients.len(); + let shared_counter = parameters.benchmark_type.shared_objects_ratio; + let transfer_objects = 100 - shared_counter; + let metrics_port = Self::CLIENT_METRICS_PORT; + let gas_keys = GenesisConfig::benchmark_gas_keys(committee_size); + + clients + .into_iter() + .enumerate() + .map(|(i, instance)| { + let genesis = genesis_path.display(); + let keystore = keystore_path.display(); + let gas_key = &gas_keys[i % committee_size]; + let gas_address = IotaAddress::from(&gas_key.public()); + + let run = [ + "cargo run --release --bin stress --", + "--num-client-threads 24 --num-server-threads 1", + "--local false --num-transfer-accounts 2", + &format!("--genesis-blob-path {genesis} --keystore-path {keystore}",), + &format!("--primary-gas-owner-id {gas_address}"), + "bench", + &format!("--in-flight-ratio 30 --num-workers 24 --target-qps {load_share}"), + &format!( + "--shared-counter {shared_counter} --transfer-object {transfer_objects}" + ), + "--shared-counter-hotness-factor 50", + &format!("--client-metric-host 0.0.0.0 --client-metric-port {metrics_port}"), + ] + .join(" "); + let command = ["source $HOME/.cargo/env", &run].join(" && "); + + (instance, command) + }) + .collect() + } +} + +impl IotaProtocol { + const CLIENT_METRICS_PORT: u16 = GenesisConfig::BENCHMARKS_PORT_OFFSET + 2000; + + /// Make a new instance of the Iota protocol commands generator. + pub fn new(settings: &Settings) -> Self { + Self { + working_dir: [&settings.working_dir, &iota_config::IOTA_CONFIG_DIR.into()] + .iter() + .collect(), + } + } + + /// Creates the network addresses in multi address format for the instances. + /// It returns the Instance and the corresponding address. + pub fn resolve_network_addresses( + instances: impl IntoIterator, + ) -> Vec<(Instance, Multiaddr)> { + let instances: Vec = instances.into_iter().collect(); + let ips: Vec<_> = instances.iter().map(|x| x.main_ip.to_string()).collect(); + let genesis_config = GenesisConfig::new_for_benchmarks(&ips); + let mut addresses = Vec::new(); + if let Some(validator_configs) = genesis_config.validator_config_info.as_ref() { + for (i, validator_info) in validator_configs.iter().enumerate() { + let address = &validator_info.network_address; + addresses.push((instances[i].clone(), address.clone())); + } + } + addresses + } +} + +impl ProtocolMetrics for IotaProtocol { + const BENCHMARK_DURATION: &'static str = "benchmark_duration"; + const TOTAL_TRANSACTIONS: &'static str = "latency_s_count"; + const LATENCY_BUCKETS: &'static str = "latency_s"; + const LATENCY_SUM: &'static str = "latency_s_sum"; + const LATENCY_SQUARED_SUM: &'static str = "latency_squared_s"; + + fn nodes_metrics_path(&self, instances: I) -> Vec<(Instance, String)> + where + I: IntoIterator, + { + let (ips, instances): (Vec<_>, Vec<_>) = instances + .into_iter() + .map(|x| (x.main_ip.to_string(), x)) + .unzip(); + + GenesisConfig::new_for_benchmarks(&ips) + .validator_config_info + .expect("No validator in genesis") + .iter() + .zip(instances) + .map(|(config, instance)| { + let path = format!( + "{}:{}{}", + instance.main_ip, + config.metrics_address.port(), + mysten_metrics::METRICS_ROUTE + ); + (instance, path) + }) + .collect() + } + + fn clients_metrics_path(&self, instances: I) -> Vec<(Instance, String)> + where + I: IntoIterator, + { + instances + .into_iter() + .map(|instance| { + let path = format!( + "{}:{}{}", + instance.main_ip, + Self::CLIENT_METRICS_PORT, + mysten_metrics::METRICS_ROUTE + ); + (instance, path) + }) + .collect() + } +} diff --git a/crates/iota-aws-orchestrator/src/protocol/mod.rs b/crates/iota-aws-orchestrator/src/protocol/mod.rs new file mode 100644 index 00000000000..9a00957d96f --- /dev/null +++ b/crates/iota-aws-orchestrator/src/protocol/mod.rs @@ -0,0 +1,141 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::path::PathBuf; + +use crate::{ + benchmark::{BenchmarkParameters, BenchmarkType}, + client::Instance, +}; + +pub mod iota; +pub mod narwhal; + +/// The minimum interface that the protocol should implement to allow benchmarks +/// from the orchestrator. +pub trait ProtocolCommands { + /// The list of dependencies to install (e.g., through apt-get). + fn protocol_dependencies(&self) -> Vec<&'static str>; + + /// The directories of all databases (that should be erased before each + /// run). + fn db_directories(&self) -> Vec; + + /// The command to generate the genesis and all configuration files. This + /// command is run on each remote machine. + fn genesis_command<'a, I>(&self, instances: I) -> String + where + I: Iterator; + + /// The command to run a node. The function returns a vector of commands + /// along with the associated instance on which to run the command. + fn node_command( + &self, + instances: I, + parameters: &BenchmarkParameters, + ) -> Vec<(Instance, String)> + where + I: IntoIterator; + + fn monitor_command(&self, instances: I) -> Vec<(Instance, String)> + where + I: IntoIterator; + + /// The command to run a client. The function returns a vector of commands + /// along with the associated instance on which to run the command. + fn client_command( + &self, + instances: I, + parameters: &BenchmarkParameters, + ) -> Vec<(Instance, String)> + where + I: IntoIterator; +} + +/// The names of the minimum metrics exposed by the load generators that are +/// required to compute performance. +pub trait ProtocolMetrics { + /// The name of the metric reporting the total duration of the benchmark (in + /// seconds). + const BENCHMARK_DURATION: &'static str; + /// The name of the metric reporting the total number of finalized + /// transactions + const TOTAL_TRANSACTIONS: &'static str; + /// The name of the metric reporting the latency buckets. + const LATENCY_BUCKETS: &'static str; + /// The name of the metric reporting the sum of the end-to-end latency of + /// all finalized transactions. + const LATENCY_SUM: &'static str; + /// The name of the metric reporting the square of the sum of the end-to-end + /// latency of all finalized transactions. + const LATENCY_SQUARED_SUM: &'static str; + + /// The network path where the nodes expose prometheus metrics. + fn nodes_metrics_path(&self, instances: I) -> Vec<(Instance, String)> + where + I: IntoIterator; + /// The command to retrieve the metrics from the nodes. + fn nodes_metrics_command(&self, instances: I) -> Vec<(Instance, String)> + where + I: IntoIterator, + { + self.nodes_metrics_path(instances) + .into_iter() + .map(|(instance, path)| (instance, format!("curl {path}"))) + .collect() + } + + /// The network path where the clients expose prometheus metrics. + fn clients_metrics_path(&self, instances: I) -> Vec<(Instance, String)> + where + I: IntoIterator; + /// The command to retrieve the metrics from the clients. + fn clients_metrics_command(&self, instances: I) -> Vec<(Instance, String)> + where + I: IntoIterator, + { + self.clients_metrics_path(instances) + .into_iter() + .map(|(instance, path)| (instance, format!("curl {path}"))) + .collect() + } +} + +#[cfg(test)] +pub mod test_protocol_metrics { + use super::ProtocolMetrics; + use crate::client::Instance; + + pub struct TestProtocolMetrics; + + impl ProtocolMetrics for TestProtocolMetrics { + const BENCHMARK_DURATION: &'static str = "benchmark_duration"; + const TOTAL_TRANSACTIONS: &'static str = "latency_s_count"; + const LATENCY_BUCKETS: &'static str = "latency_s"; + const LATENCY_SUM: &'static str = "latency_s_sum"; + const LATENCY_SQUARED_SUM: &'static str = "latency_squared_s"; + + fn nodes_metrics_path(&self, instances: I) -> Vec<(Instance, String)> + where + I: IntoIterator, + { + instances + .into_iter() + .enumerate() + .map(|(i, instance)| (instance, format!("localhost:{}/metrics", 8000 + i as u16))) + .collect() + } + + fn clients_metrics_path(&self, instances: I) -> Vec<(Instance, String)> + where + I: IntoIterator, + { + instances + .into_iter() + .enumerate() + .map(|(i, instance)| (instance, format!("localhost:{}/metrics", 9000 + i as u16))) + .collect() + } + } +} diff --git a/crates/sui-aws-orchestrator/src/protocol/narwhal.rs b/crates/iota-aws-orchestrator/src/protocol/narwhal.rs similarity index 99% rename from crates/sui-aws-orchestrator/src/protocol/narwhal.rs rename to crates/iota-aws-orchestrator/src/protocol/narwhal.rs index 7439d0e966e..b6bb543fbaa 100644 --- a/crates/sui-aws-orchestrator/src/protocol/narwhal.rs +++ b/crates/iota-aws-orchestrator/src/protocol/narwhal.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/sui-aws-orchestrator/src/settings.rs b/crates/iota-aws-orchestrator/src/settings.rs similarity index 99% rename from crates/sui-aws-orchestrator/src/settings.rs rename to crates/iota-aws-orchestrator/src/settings.rs index 50b8a70355c..1eb116ae64c 100644 --- a/crates/sui-aws-orchestrator/src/settings.rs +++ b/crates/iota-aws-orchestrator/src/settings.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/sui-aws-orchestrator/src/ssh.rs b/crates/iota-aws-orchestrator/src/ssh.rs similarity index 99% rename from crates/sui-aws-orchestrator/src/ssh.rs rename to crates/iota-aws-orchestrator/src/ssh.rs index f8d07ec1fcb..aa15d269bc1 100644 --- a/crates/sui-aws-orchestrator/src/ssh.rs +++ b/crates/iota-aws-orchestrator/src/ssh.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/sui-aws-orchestrator/src/testbed.rs b/crates/iota-aws-orchestrator/src/testbed.rs similarity index 99% rename from crates/sui-aws-orchestrator/src/testbed.rs rename to crates/iota-aws-orchestrator/src/testbed.rs index 15cefb5ead0..9f181b47313 100644 --- a/crates/sui-aws-orchestrator/src/testbed.rs +++ b/crates/iota-aws-orchestrator/src/testbed.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::time::Duration; diff --git a/crates/iota-axelar-cgp/README.md b/crates/iota-axelar-cgp/README.md new file mode 100644 index 00000000000..0843fea8c06 --- /dev/null +++ b/crates/iota-axelar-cgp/README.md @@ -0,0 +1,5 @@ +# Axelar cross-chain gateway protocol Iota implementation + + +## Design +TODO \ No newline at end of file diff --git a/crates/iota-axelar-cgp/move/Move.toml b/crates/iota-axelar-cgp/move/Move.toml new file mode 100644 index 00000000000..4eb3618c46a --- /dev/null +++ b/crates/iota-axelar-cgp/move/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "iota-axelar-cgp" +version = "0.0.1" + +[dependencies] +Iota = { local= "../../iota-framework/packages/iota-framework" } + +[addresses] +axelar = "0x0" +iota = "0x2" diff --git a/crates/sui-axelar-cgp/move/presets/.gitignore b/crates/iota-axelar-cgp/move/presets/.gitignore similarity index 100% rename from crates/sui-axelar-cgp/move/presets/.gitignore rename to crates/iota-axelar-cgp/move/presets/.gitignore diff --git a/crates/sui-axelar-cgp/move/presets/index.js b/crates/iota-axelar-cgp/move/presets/index.js similarity index 96% rename from crates/sui-axelar-cgp/move/presets/index.js rename to crates/iota-axelar-cgp/move/presets/index.js index 3d813c5e3e8..d40a1ca671b 100644 --- a/crates/sui-axelar-cgp/move/presets/index.js +++ b/crates/iota-axelar-cgp/move/presets/index.js @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /** @@ -10,8 +11,8 @@ const secp256k1 = require("secp256k1"); const { utils: {keccak256}, } = require("ethers"); -const {BCS, fromHEX, toHEX, getSuiMoveConfig} = require("@mysten/bcs"); -const bcs = new BCS(getSuiMoveConfig()); +const {BCS, fromHEX, toHEX, getIotaMoveConfig} = require("@iota/bcs"); +const bcs = new BCS(getIotaMoveConfig()); // generate privKey const privKey = Buffer.from( @@ -182,7 +183,7 @@ console.log(secp256k1.ecdsaVerify(signature, hashed, pubKey)); function hashMessage(data) { // sorry for putting it here... const messagePrefix = new Uint8Array( - Buffer.from("\x19Sui Signed Message:\n", "ascii") + Buffer.from("\x19Iota Signed Message:\n", "ascii") ); let hashed = new Uint8Array(messagePrefix.length + data.length); hashed.set(messagePrefix); diff --git a/crates/iota-axelar-cgp/move/presets/package.json b/crates/iota-axelar-cgp/move/presets/package.json new file mode 100644 index 00000000000..64cc3f4a717 --- /dev/null +++ b/crates/iota-axelar-cgp/move/presets/package.json @@ -0,0 +1,12 @@ +{ + "name": "axelar-presets", + "version": "1.0.0", + "main": "index.js", + "author": "Damir Shamanaev ", + "license": "MIT", + "dependencies": { + "@iota/bcs": "^0.5.0", + "ethers": "^5.7.1", + "secp256k1": "^4.0.3" + } +} diff --git a/crates/sui-axelar-cgp/move/presets/yarn.lock b/crates/iota-axelar-cgp/move/presets/yarn.lock similarity index 99% rename from crates/sui-axelar-cgp/move/presets/yarn.lock rename to crates/iota-axelar-cgp/move/presets/yarn.lock index 4e3fefc84e5..42c5e388d73 100644 --- a/crates/sui-axelar-cgp/move/presets/yarn.lock +++ b/crates/iota-axelar-cgp/move/presets/yarn.lock @@ -344,9 +344,9 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" -"@mysten/bcs@^0.5.0": +"@iota/bcs@^0.5.0": version "0.5.0" - resolved "https://registry.yarnpkg.com/@mysten/bcs/-/bcs-0.5.0.tgz#d2570971e3d9121b83091ced38db13e907ab4198" + resolved "https://registry.yarnpkg.com/@iota/bcs/-/bcs-0.5.0.tgz#d2570971e3d9121b83091ced38db13e907ab4198" integrity sha512-FjGnXZfR4dY01Q1l3xjgaU+ruIlVomXZk8vzgsQXPFOv7O4pNiOOpJyMEMUnWcyUiktk4R9MxoJJrygOtdxaUw== aes-js@3.0.0: diff --git a/crates/sui-axelar-cgp/move/sources/channel.move b/crates/iota-axelar-cgp/move/sources/channel.move similarity index 93% rename from crates/sui-axelar-cgp/move/sources/channel.move rename to crates/iota-axelar-cgp/move/sources/channel.move index fbd383744db..0e6b00657af 100644 --- a/crates/sui-axelar-cgp/move/sources/channel.move +++ b/crates/iota-axelar-cgp/move/sources/channel.move @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module axelar::channel { use std::string::String; - use sui::linked_table::{Self, LinkedTable}; - use sui::object::{Self, UID}; - use sui::tx_context::TxContext; + use iota::linked_table::{Self, LinkedTable}; + use iota::object::{Self, UID}; + use iota::tx_context::TxContext; friend axelar::validators; /// Generic target for the messaging system. /// - /// This struct is required on the Sui side to be the destination for the + /// This struct is required on the Iota side to be the destination for the /// messages sent from other chains. Even though it has a UID field, it does /// not have a `key` ability to force wrapping. /// @@ -30,13 +31,13 @@ module axelar::channel { /// the system. Destroying a channel would mean the end of the Channel cycle /// and all further messages will have to target a new Channel if there is one. /// - /// - Does not contain direct link to the state in Sui, as some functions + /// - Does not contain direct link to the state in Iota, as some functions /// might not take any specific data (eg allow users to create new objects). - /// If specific object on Sui is targeted by this `Channel`, its reference + /// If specific object on Iota is targeted by this `Channel`, its reference /// should be implemented using the `data` field. /// /// - The funniest and extremely simple implementation would be a `Channel` - /// since it actually contains the data required to point at the object in Sui. + /// since it actually contains the data required to point at the object in Iota. /// For when trying to consume the wrong object. const EWrongDestination: u64 = 0; @@ -162,7 +163,7 @@ module axelar::channel { /// Get the bytes of the Channel address public fun source_id(self: &Channel): vector { - sui::bcs::to_bytes(&self.id) + iota::bcs::to_bytes(&self.id) } // === Testing === diff --git a/crates/sui-axelar-cgp/move/sources/gateway.move b/crates/iota-axelar-cgp/move/sources/gateway.move similarity index 94% rename from crates/sui-axelar-cgp/move/sources/gateway.move rename to crates/iota-axelar-cgp/move/sources/gateway.move index f9dbd86999b..260a90279d8 100644 --- a/crates/sui-axelar-cgp/move/sources/gateway.move +++ b/crates/iota-axelar-cgp/move/sources/gateway.move @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Implementation a cross-chain messaging system for Axelar. /// /// This code is based on the following: /// -/// - When call approvals is sent to Sui, it targets an object and not a module; +/// - When call approvals is sent to Iota, it targets an object and not a module; /// - To support cross-chain messaging, a Channel object has to be created; /// - Channel can be either owned or shared but not frozen; -/// - Module developer on the Sui side will have to implement a system to support messaging; +/// - Module developer on the Iota side will have to implement a system to support messaging; /// - Checks for uniqueness of approvals should be done through `Channel`s to avoid big data storage; /// /// I. Sending call approvals @@ -32,9 +33,9 @@ module axelar::gateway { use std::string::{Self, String}; use std::vector; - use sui::bcs; + use iota::bcs; - use axelar::utils::to_sui_signed; + use axelar::utils::to_iota_signed; use axelar::channel::{Self, Channel, ApprovedCall}; use axelar::validators::{Self, AxelarValidators, validate_proof}; @@ -44,14 +45,14 @@ module axelar::gateway { /// For when number of commands does not match number of command ids. const EInvalidCommands: u64 = 4; - /// For when approval chainId is not SUI. + /// For when approval chainId is not IOTA. const EInvalidChain: u64 = 3; // These are currently supported const SELECTOR_APPROVE_CONTRACT_CALL: vector = b"approveContractCall"; const SELECTOR_TRANSFER_OPERATORSHIP: vector = b"transferOperatorship"; - /// Emitted when a new message is sent from the SUI network. + /// Emitted when a new message is sent from the IOTA network. struct ContractCall has copy, drop { source: vector, destination: vector, @@ -80,7 +81,7 @@ module axelar::gateway { bcs::peel_vec_u8(&mut bytes) ); - let allow_operatorship_transfer = validate_proof(validators, to_sui_signed(*&data), proof); + let allow_operatorship_transfer = validate_proof(validators, to_iota_signed(*&data), proof); // Treat `data` as BCS bytes. let data_bcs = bcs::new(data); @@ -162,7 +163,7 @@ module axelar::gateway { destination_address: vector, payload: vector ) { - sui::event::emit(ContractCall { + iota::event::emit(ContractCall { source: channel::source_id(channel), destination, destination_address, @@ -173,7 +174,7 @@ module axelar::gateway { #[test_only] use axelar::utils::operators_hash; #[test_only] - use sui::vec_map; + use iota::vec_map; #[test_only] /// Test call approval for the `test_execute` test. @@ -187,7 +188,7 @@ module axelar::gateway { /// Tests execution with a set of validators. /// Samples for this test are generated with the `presets/` application. fun test_execute() { - use sui::test_scenario::{Self as ts, ctx}; + use iota::test_scenario::{Self as ts, ctx}; // public keys of `operators` let epoch = 1; @@ -217,7 +218,7 @@ module axelar::gateway { #[test] fun test_transfer_operatorship() { - use sui::test_scenario::{Self as ts, ctx}; + use iota::test_scenario::{Self as ts, ctx}; // public keys of `operators` let epoch = 1; let operators = vector[ diff --git a/crates/sui-axelar-cgp/move/sources/utils.move b/crates/iota-axelar-cgp/move/sources/utils.move similarity index 78% rename from crates/sui-axelar-cgp/move/sources/utils.move rename to crates/iota-axelar-cgp/move/sources/utils.move index a9b1f3ce592..b3e69ebdbd2 100644 --- a/crates/sui-axelar-cgp/move/sources/utils.move +++ b/crates/iota-axelar-cgp/move/sources/utils.move @@ -1,19 +1,20 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module axelar::utils { use std::vector; - use sui::bcs; - use sui::hash; + use iota::bcs; + use iota::hash; const EInvalidSignatureLength: u64 = 0; - /// Prefix for Sui Messages. - const PREFIX: vector = b"\x19Sui Signed Message:\n"; + /// Prefix for Iota Messages. + const PREFIX: vector = b"\x19Iota Signed Message:\n"; /// Normalize last byte of the signature. Have it 1 or 0. - /// See https://tech.mystenlabs.com/cryptography-in-sui-cross-chain-signature-verification/ + /// See https://tech.mystenlabs.com/cryptography-in-iota-cross-chain-signature-verification/ public fun normalize_signature(signature: &mut vector) { // Compute v = 0 or 1. assert!(vector::length(signature) == 65, EInvalidSignatureLength); @@ -28,7 +29,7 @@ module axelar::utils { } /// Add a prefix to the bytes. - public fun to_sui_signed(bytes: vector): vector { + public fun to_iota_signed(bytes: vector): vector { let res = vector[]; vector::append(&mut res, PREFIX); vector::append(&mut res, bytes); diff --git a/crates/sui-axelar-cgp/move/sources/validators.move b/crates/iota-axelar-cgp/move/sources/validators.move similarity index 95% rename from crates/sui-axelar-cgp/move/sources/validators.move rename to crates/iota-axelar-cgp/move/sources/validators.move index bd39aa6abec..b1e2dc85595 100644 --- a/crates/sui-axelar-cgp/move/sources/validators.move +++ b/crates/iota-axelar-cgp/move/sources/validators.move @@ -1,21 +1,22 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module axelar::validators { use std::string::{Self, String}; use std::vector; - use sui::table::{Self, Table}; - use sui::address; - use sui::bcs; - use sui::dynamic_field as df; - use sui::ecdsa_k1 as ecdsa; - use sui::event; - use sui::hash; - use sui::object::{Self, UID}; - use sui::transfer; - use sui::tx_context::TxContext; - use sui::vec_map:: {Self, VecMap}; + use iota::table::{Self, Table}; + use iota::address; + use iota::bcs; + use iota::dynamic_field as df; + use iota::ecdsa_k1 as ecdsa; + use iota::event; + use iota::hash; + use iota::object::{Self, UID}; + use iota::transfer; + use iota::tx_context::TxContext; + use iota::vec_map:: {Self, VecMap}; use axelar::channel::{Self, ApprovedCall}; use axelar::utils::{normalize_signature, operators_hash}; @@ -262,7 +263,7 @@ module axelar::validators { } #[test_only] - use axelar::utils::to_sui_signed; + use axelar::utils::to_iota_signed; #[test_only] public fun drop_for_test(self: AxelarValidators) { @@ -283,20 +284,20 @@ module axelar::validators { const SIGNER: vector = x"037286a4f1177bea06c8e15cf6ec3df0b7747a01ac2329ca2999dfd74eff599028"; #[test] - /// Tests `ecrecover`, makes sure external signing process works with Sui ecrecover. + /// Tests `ecrecover`, makes sure external signing process works with Iota ecrecover. /// Samples for this test are generated with the `presets/` application. fun test_ecrecover() { let message = x"68656c6c6f20776f726c64"; // hello world let signature = x"0e88ac153a06d86f28dc0f946654d02302099c0c6558806b569d43f8bd062d5c295beb095e9cc396cd68a6b18daa0f1c0489b778831c4b3bb46f7aa1171c23b101"; normalize_signature(&mut signature); - let pubkey = ecdsa::secp256k1_ecrecover(&signature, &to_sui_signed(message), 0); + let pubkey = ecdsa::secp256k1_ecrecover(&signature, &to_iota_signed(message), 0); assert!(pubkey == SIGNER, 0); } #[test] - /// Tests "Sui Signed Message" prefix addition ecrecover. + /// Tests "Iota Signed Message" prefix addition ecrecover. /// Checks if the signature generated outside matches the message generated in this module. /// Samples for this test are generated with the `presets/` application. fun test_to_signed() { @@ -304,7 +305,7 @@ module axelar::validators { let signature = x"0e88ac153a06d86f28dc0f946654d02302099c0c6558806b569d43f8bd062d5c295beb095e9cc396cd68a6b18daa0f1c0489b778831c4b3bb46f7aa1171c23b101"; normalize_signature(&mut signature); - let pub_key = ecdsa::secp256k1_ecrecover(&signature, &to_sui_signed(message), 0); + let pub_key = ecdsa::secp256k1_ecrecover(&signature, &to_iota_signed(message), 0); assert!(pub_key == SIGNER, 0); } } diff --git a/crates/iota-benchmark/Cargo.toml b/crates/iota-benchmark/Cargo.toml new file mode 100644 index 00000000000..01fb248665e --- /dev/null +++ b/crates/iota-benchmark/Cargo.toml @@ -0,0 +1,59 @@ +[package] +name = "iota-benchmark" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +async-trait.workspace = true +anyhow = { workspace = true, features = ["backtrace"] } +futures.workspace = true +serde.workspace = true +serde_json.workspace = true +itertools.workspace = true +tokio = { workspace = true, features = ["full"] } +strum.workspace = true +strum_macros.workspace = true +tracing.workspace = true +clap.workspace = true +prometheus.workspace = true +rand.workspace = true +indicatif.workspace = true +duration-str.workspace = true +hdrhistogram.workspace = true +comfy-table.workspace = true +bcs.workspace = true +tokio-util.workspace = true +iota-core.workspace = true +iota-config.workspace = true +iota-network.workspace = true +iota-storage.workspace = true +iota-types.workspace = true +iota-sdk.workspace = true +iota-keys.workspace = true +iota-json-rpc-types.workspace = true +iota-protocol-config.workspace = true +iota-test-transaction-builder.workspace = true +iota-swarm-config.workspace = true +telemetry-subscribers.workspace = true +roaring.workspace = true +regex.workspace = true +fastcrypto-zkp.workspace = true + +move-core-types.workspace = true +mysten-metrics.workspace = true +narwhal-node.workspace = true +test-cluster.workspace = true +sysinfo.workspace = true + +[target.'cfg(msim)'.dependencies] +iota-framework.workspace = true +iota-framework-snapshot.workspace = true +iota-macros.workspace = true +iota-simulator.workspace = true +typed-store.workspace = true + +[features] +benchmark = ["narwhal-node/benchmark"] diff --git a/crates/sui-benchmark/src/bank.rs b/crates/iota-benchmark/src/bank.rs similarity index 91% rename from crates/sui-benchmark/src/bank.rs rename to crates/iota-benchmark/src/bank.rs index 74d851f9e57..02d99b324bc 100644 --- a/crates/sui-benchmark/src/bank.rs +++ b/crates/iota-benchmark/src/bank.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -7,9 +8,9 @@ use std::{ }; use anyhow::{Error, Result}; +use iota_core::test_utils::{make_pay_iota_transaction, make_transfer_iota_transaction}; +use iota_types::{base_types::IotaAddress, crypto::AccountKeyPair}; use itertools::Itertools; -use sui_core::test_utils::{make_pay_sui_transaction, make_transfer_sui_transaction}; -use sui_types::{base_types::SuiAddress, crypto::AccountKeyPair}; use tracing::info; use crate::{ @@ -70,7 +71,7 @@ impl BenchmarkBank { info!("Number of gas requests = {}", chunked_coin_configs.len()); for chunk in chunked_coin_configs { - let gas_coins = self.pay_sui(chunk, &mut init_coin, gas_price).await?; + let gas_coins = self.pay_iota(chunk, &mut init_coin, gas_price).await?; new_gas_coins.extend(gas_coins); } let mut workloads = vec![]; @@ -102,13 +103,14 @@ impl BenchmarkBank { Ok(workloads) } - async fn pay_sui( + async fn pay_iota( &mut self, coin_configs: &[GasCoinConfig], init_coin: &mut Gas, gas_price: u64, ) -> Result { - let recipient_addresses: Vec = coin_configs.iter().map(|g| g.address).collect(); + let recipient_addresses: Vec = + coin_configs.iter().map(|g| g.address).collect(); let amounts: Vec = coin_configs.iter().map(|c| c.amount).collect(); info!( @@ -117,7 +119,7 @@ impl BenchmarkBank { amounts[0], ); - let tx = make_pay_sui_transaction( + let tx = make_pay_iota_transaction( init_coin.0, vec![], recipient_addresses, @@ -146,7 +148,7 @@ impl BenchmarkBank { init_coin.1 = updated_gas.1.get_owner_address()?; init_coin.2 = self.primary_coin.2.clone(); - let address_map: HashMap> = coin_configs + let address_map: HashMap> = coin_configs .iter() .map(|c| (c.address, c.keypair.clone())) .collect(); @@ -170,7 +172,7 @@ impl BenchmarkBank { async fn create_init_coin(&mut self, amount: u64, gas_price: u64) -> Result { info!("Creating initilization coin of value {amount}..."); - let tx = make_transfer_sui_transaction( + let tx = make_transfer_iota_transaction( self.primary_coin.0, self.primary_coin.1, Some(amount), diff --git a/crates/sui-benchmark/src/benchmark_setup.rs b/crates/iota-benchmark/src/benchmark_setup.rs similarity index 94% rename from crates/sui-benchmark/src/benchmark_setup.rs rename to crates/iota-benchmark/src/benchmark_setup.rs index 2fc44d70da7..5b0fcc78695 100644 --- a/crates/sui-benchmark/src/benchmark_setup.rs +++ b/crates/iota-benchmark/src/benchmark_setup.rs @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{path::PathBuf, sync::Arc, thread::JoinHandle, time::Duration}; use anyhow::{anyhow, bail, Context, Result}; -use prometheus::Registry; -use rand::seq::SliceRandom; -use sui_swarm_config::genesis_config::AccountConfig; -use sui_types::{ - base_types::{ConciseableName, ObjectID, SuiAddress}, +use iota_swarm_config::genesis_config::AccountConfig; +use iota_types::{ + base_types::{ConciseableName, IotaAddress, ObjectID}, crypto::{deterministic_random_account_key, AccountKeyPair}, - gas_coin::TOTAL_SUPPLY_MIST, + gas_coin::TOTAL_SUPPLY_MICROS, object::Owner, }; +use prometheus::Registry; +use rand::seq::SliceRandom; use test_cluster::TestClusterBuilder; use tokio::{ runtime::Builder, @@ -81,11 +82,11 @@ impl Env { num_server_threads: u64, ) -> Result { info!("Running benchmark setup in local mode.."); - let (primary_gas_owner, keypair): (SuiAddress, AccountKeyPair) = + let (primary_gas_owner, keypair): (IotaAddress, AccountKeyPair) = deterministic_random_account_key(); let keypair = Arc::new(keypair); - // spawn a thread to spin up sui nodes on the multi-threaded server runtime. + // spawn a thread to spin up iota nodes on the multi-threaded server runtime. // running forever let (shutdown_sender, shutdown_recv) = tokio::sync::oneshot::channel::<()>(); let (genesis_sender, genesis_recv) = tokio::sync::oneshot::channel(); @@ -101,9 +102,9 @@ impl Env { let cluster = TestClusterBuilder::new() .with_accounts(vec![AccountConfig { address: Some(primary_gas_owner), - // We can't use TOTAL_SUPPLY_MIST because we need to account for validator + // We can't use TOTAL_SUPPLY_MICROS because we need to account for validator // stakes in genesis allocation. - gas_amounts: vec![TOTAL_SUPPLY_MIST / 2], + gas_amounts: vec![TOTAL_SUPPLY_MICROS / 2], }]) .with_num_validators(committee_size) .build() @@ -166,7 +167,7 @@ impl Env { }); }); - let genesis = sui_config::node::Genesis::new_from_file(genesis_blob_path); + let genesis = iota_config::node::Genesis::new_from_file(genesis_blob_path); let genesis = genesis.genesis()?; let fullnode_rpc_urls = fullnode_rpc_address.clone(); diff --git a/crates/sui-benchmark/src/bin/stress.rs b/crates/iota-benchmark/src/bin/stress.rs similarity index 95% rename from crates/sui-benchmark/src/bin/stress.rs rename to crates/iota-benchmark/src/bin/stress.rs index b9ac64a5f65..351f8326bc1 100644 --- a/crates/sui-benchmark/src/bin/stress.rs +++ b/crates/iota-benchmark/src/bin/stress.rs @@ -1,26 +1,27 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{sync::Arc, time::Duration}; use anyhow::{anyhow, Context, Result}; use clap::*; -use prometheus::Registry; -use rand::{seq::SliceRandom, Rng}; -use sui_benchmark::{ +use iota_benchmark::{ benchmark_setup::Env, drivers::{bench_driver::BenchDriver, driver::Driver, BenchmarkCmp, BenchmarkStats}, options::Opts, system_state_observer::SystemStateObserver, workloads::workload_configuration::WorkloadConfiguration, }; -use sui_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; +use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; +use prometheus::Registry; +use rand::{seq::SliceRandom, Rng}; use tokio::{runtime::Builder, sync::Barrier, time::sleep}; /// To spin up a local cluster and direct some load /// at it with 50/50 shared and owned traffic, use /// it something like: -/// ```cargo run --release --package sui-benchmark +/// ```cargo run --release --package iota-benchmark /// --bin stress -- --num-client-threads 12 \ /// --num-server-threads 10 \ /// --num-transfer-accounts 2 \ @@ -31,12 +32,12 @@ use tokio::{runtime::Builder, sync::Barrier, time::sleep}; /// --transfer-object 50``` /// To point the traffic to an already running cluster, /// use it something like: -/// ```cargo run --release --package sui-benchmark --bin stress -- --num-client-threads 12 \ +/// ```cargo run --release --package iota-benchmark --bin stress -- --num-client-threads 12 \ /// --num-server-threads 10 \ /// --num-transfer-accounts 2 \ /// --primary-gas-id 0x59931dcac57ba20d75321acaf55e8eb5a2c47e9f \ /// --genesis-blob-path /tmp/genesis.blob \ -/// --keystore-path /tmp/sui.keystore bench \ +/// --keystore-path /tmp/iota.keystore bench \ /// --target-qps 100 \ /// --in-flight-ratio 2 \ /// --shared-counter 50 \ diff --git a/crates/sui-benchmark/src/drivers/bench_driver.rs b/crates/iota-benchmark/src/drivers/bench_driver.rs similarity index 99% rename from crates/sui-benchmark/src/drivers/bench_driver.rs rename to crates/iota-benchmark/src/drivers/bench_driver.rs index c07c3cb2c42..b474cbcd3dd 100644 --- a/crates/sui-benchmark/src/drivers/bench_driver.rs +++ b/crates/iota-benchmark/src/drivers/bench_driver.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -20,6 +21,11 @@ use futures::{ FutureExt, StreamExt, }; use indicatif::{ProgressBar, ProgressStyle}; +use iota_types::{ + committee::Committee, + quorum_driver_types::QuorumDriverError, + transaction::{Transaction, TransactionDataAPI}, +}; use prometheus::{ register_counter_vec_with_registry, register_gauge_vec_with_registry, register_histogram_vec_with_registry, register_int_counter_vec_with_registry, @@ -27,11 +33,6 @@ use prometheus::{ Registry, }; use rand::seq::SliceRandom; -use sui_types::{ - committee::Committee, - quorum_driver_types::QuorumDriverError, - transaction::{Transaction, TransactionDataAPI}, -}; use sysinfo::{CpuExt, System, SystemExt}; use tokio::{ sync::{ @@ -102,7 +103,7 @@ impl BenchMetrics { .unwrap(), num_submitted: register_int_counter_vec_with_registry!( "num_submitted", - "Total number of transaction submitted to sui", + "Total number of transaction submitted to iota", &["workload"], registry, ) diff --git a/crates/sui-benchmark/src/drivers/driver.rs b/crates/iota-benchmark/src/drivers/driver.rs similarity index 93% rename from crates/sui-benchmark/src/drivers/driver.rs rename to crates/iota-benchmark/src/drivers/driver.rs index e138ab6b44d..edb0543e180 100644 --- a/crates/sui-benchmark/src/drivers/driver.rs +++ b/crates/iota-benchmark/src/drivers/driver.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, sync::Arc}; diff --git a/crates/iota-benchmark/src/drivers/mod.rs b/crates/iota-benchmark/src/drivers/mod.rs new file mode 100644 index 00000000000..4e07ce7f109 --- /dev/null +++ b/crates/iota-benchmark/src/drivers/mod.rs @@ -0,0 +1,420 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{fmt::Formatter, str::FromStr, time::Duration}; + +use duration_str::parse; + +pub mod bench_driver; +pub mod driver; +use comfy_table::{Cell, Color, ContentArrangement, Row, Table}; +use hdrhistogram::{serialization::Serializer, Histogram}; + +#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, Eq, PartialEq)] +pub enum Interval { + Count(u64), + Time(tokio::time::Duration), +} + +impl Interval { + pub fn is_unbounded(&self) -> bool { + matches!(self, Interval::Time(tokio::time::Duration::MAX)) + } +} + +impl FromStr for Interval { + type Err = String; + + fn from_str(s: &str) -> Result { + if let Ok(i) = s.parse() { + Ok(Interval::Count(i)) + } else if let Ok(d) = parse(s) { + Ok(Interval::Time(d)) + } else if "unbounded" == s { + Ok(Interval::Time(Duration::MAX)) + } else { + Err("Required integer number of cycles or time duration".to_string()) + } + } +} + +impl std::fmt::Display for Interval { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Interval::Count(count) => f.write_str(format!("{}", count).as_str()), + Interval::Time(d) => { + if *d == Duration::MAX { + f.write_str("unbounded") + } else { + f.write_str(format!("{}sec", d.as_secs()).as_str()) + } + } + } + } +} + +// wrapper which implements serde +#[allow(dead_code)] +#[derive(Debug)] +pub struct HistogramWrapper { + histogram: Histogram, +} + +impl Default for HistogramWrapper { + fn default() -> Self { + Self { + histogram: Histogram::new(0).unwrap(), + } + } +} + +impl serde::Serialize for HistogramWrapper { + fn serialize(&self, serializer: S) -> Result { + let mut vec = Vec::new(); + hdrhistogram::serialization::V2Serializer::new() + .serialize(&self.histogram, &mut vec) + .map_err(|e| serde::ser::Error::custom(e.to_string()))?; + serializer.serialize_bytes(&vec) + } +} + +impl<'de> serde::Deserialize<'de> for HistogramWrapper { + fn deserialize>(deserializer: D) -> Result { + let vec: Vec = serde::Deserialize::deserialize(deserializer)?; + let histogram: Histogram = hdrhistogram::serialization::Deserializer::new() + .deserialize(&mut &vec[..]) + .map_err(|e| serde::de::Error::custom(e.to_string()))?; + Ok(HistogramWrapper { histogram }) + } +} + +// Stores the final stress statisicts of the test run. +#[derive(serde::Serialize, serde::Deserialize)] +pub struct StressStats { + pub cpu_usage: HistogramWrapper, +} + +impl StressStats { + pub fn update(&mut self, sample_stat: &StressStats) { + self.cpu_usage + .histogram + .add(&sample_stat.cpu_usage.histogram) + .unwrap(); + } + + pub fn to_table(&self) -> Table { + let mut table = Table::new(); + table + .set_content_arrangement(ContentArrangement::Dynamic) + .set_width(200) + .set_header(vec!["metric", "p50", "p99"]); + + let mut row = Row::new(); + row.add_cell(Cell::new("cpu usage")); + row.add_cell(Cell::new(self.cpu_usage.histogram.value_at_quantile(0.5))); + row.add_cell(Cell::new(self.cpu_usage.histogram.value_at_quantile(0.99))); + table.add_row(row); + table + } +} + +/// Stores the final statistics of the test run. +#[derive(serde::Serialize, serde::Deserialize, Debug, Default)] +pub struct BenchmarkStats { + pub duration: Duration, + /// Number of transactions that ended in an error + pub num_error_txes: u64, + /// Number of transactions that were executed successfully + pub num_success_txes: u64, + /// Total number of commands in transactions that executed successfully + pub num_success_cmds: u64, + /// Total gas used + pub total_gas_used: u64, + pub latency_ms: HistogramWrapper, +} + +impl BenchmarkStats { + pub fn update(&mut self, duration: Duration, sample_stat: &BenchmarkStats) { + self.duration = duration; + self.num_error_txes += sample_stat.num_error_txes; + self.num_success_txes += sample_stat.num_success_txes; + self.num_success_cmds += sample_stat.num_success_cmds; + self.total_gas_used += sample_stat.total_gas_used; + self.latency_ms + .histogram + .add(&sample_stat.latency_ms.histogram) + .unwrap(); + } + pub fn to_table(&self) -> Table { + let mut table = Table::new(); + table + .set_content_arrangement(ContentArrangement::Dynamic) + .set_width(200) + .set_header(vec![ + "duration(s)", + "tps", + "cps", + "error%", + "latency (min)", + "latency (p50)", + "latency (p99)", + "gas used (MICROS total)", + "gas used/hr (MICROS approx.)", + ]); + let mut row = Row::new(); + row.add_cell(Cell::new(self.duration.as_secs())); + row.add_cell(Cell::new(self.num_success_txes / self.duration.as_secs())); + row.add_cell(Cell::new(self.num_success_cmds / self.duration.as_secs())); + row.add_cell(Cell::new( + (100 * self.num_error_txes) as f32 + / (self.num_error_txes + self.num_success_txes) as f32, + )); + row.add_cell(Cell::new(self.latency_ms.histogram.min())); + row.add_cell(Cell::new(self.latency_ms.histogram.value_at_quantile(0.5))); + row.add_cell(Cell::new(self.latency_ms.histogram.value_at_quantile(0.99))); + row.add_cell(Cell::new(format_num_with_separators( + self.total_gas_used, + 3, + ",", + ))); + row.add_cell(Cell::new(format_num_with_separators( + self.total_gas_used * 60 * 60 / self.duration.as_secs(), + 3, + ",", + ))); + table.add_row(row); + table + } +} + +/// A comparison between an old and a new benchmark. +/// All differences are reported in terms of measuring improvements +/// (negative) or regressions (positive). That is, if an old benchmark +/// is slower than a new benchmark, then the difference is negative. +/// Conversely, if an old benchmark is faster than a new benchmark, +/// then the difference is positive. +#[derive(Clone, Debug)] +pub struct Comparison { + pub name: String, + pub old_value: String, + pub new_value: String, + pub diff: i64, + pub diff_ratio: f64, + pub speedup: f64, +} + +pub struct BenchmarkCmp<'a> { + pub new: &'a BenchmarkStats, + pub old: &'a BenchmarkStats, +} + +impl BenchmarkCmp<'_> { + pub fn to_table(&self) -> Table { + let mut table = Table::new(); + table.set_header(vec!["name", "old", "new", "diff", "diff_ratio", "speedup"]); + for cmp in self.all_cmps() { + let diff_ratio = format!("{:.2}%", cmp.diff_ratio * 100f64); + let speedup = format!("{:.2}x", cmp.speedup); + let diff = format!("{:.2}", cmp.diff); + let mut row = Row::new(); + row.add_cell(Cell::new(cmp.name)); + row.add_cell(Cell::new(cmp.old_value)); + row.add_cell(Cell::new(cmp.new_value)); + if cmp.speedup >= 1.0 { + row.add_cell(Cell::new(diff).fg(Color::Green)); + row.add_cell(Cell::new(diff_ratio).fg(Color::Green)); + row.add_cell(Cell::new(speedup).fg(Color::Green)); + } else { + row.add_cell(Cell::new(diff).fg(Color::Red)); + row.add_cell(Cell::new(diff_ratio).fg(Color::Red)); + row.add_cell(Cell::new(speedup).fg(Color::Red)); + } + table.add_row(row); + } + table + } + pub fn all_cmps(&self) -> Vec { + vec![ + self.cmp_tps(), + self.cmp_error_rate(), + self.cmp_min_latency(), + self.cmp_p25_latency(), + self.cmp_p50_latency(), + self.cmp_p75_latency(), + self.cmp_p90_latency(), + self.cmp_p99_latency(), + self.cmp_p999_latency(), + self.cmp_max_latency(), + ] + } + pub fn cmp_tps(&self) -> Comparison { + let old_tps = self.old.num_success_txes / self.old.duration.as_secs(); + let new_tps = self.new.num_success_txes / self.new.duration.as_secs(); + let diff = new_tps as i64 - old_tps as i64; + let diff_ratio = diff as f64 / old_tps as f64; + let speedup = 1.0 + diff_ratio; + Comparison { + name: "tps".to_string(), + old_value: format!("{:.2}", old_tps), + new_value: format!("{:.2}", new_tps), + diff, + diff_ratio, + speedup, + } + } + pub fn cmp_error_rate(&self) -> Comparison { + let old_error_rate = + self.old.num_error_txes / (self.old.num_error_txes + self.old.num_success_txes); + let new_error_rate = + self.new.num_error_txes / (self.new.num_error_txes + self.new.num_success_txes); + let diff = new_error_rate as i64 - old_error_rate as i64; + let diff_ratio = diff as f64 / old_error_rate as f64; + let speedup = 1.0 / (1.0 + diff_ratio); + Comparison { + name: "error_rate".to_string(), + old_value: format!("{:.2}", old_error_rate), + new_value: format!("{:.2}", new_error_rate), + diff, + diff_ratio, + speedup, + } + } + pub fn cmp_min_latency(&self) -> Comparison { + let old = self.old.latency_ms.histogram.min() as i64; + let new = self.new.latency_ms.histogram.min() as i64; + let diff = new - old; + let diff_ratio = diff as f64 / old as f64; + let speedup = 1.0 / (1.0 + diff_ratio); + Comparison { + name: "min_latency".to_string(), + old_value: format!("{:.2}", old), + new_value: format!("{:.2}", new), + diff, + diff_ratio, + speedup, + } + } + pub fn cmp_p25_latency(&self) -> Comparison { + let old = self.old.latency_ms.histogram.value_at_quantile(0.25) as i64; + let new = self.new.latency_ms.histogram.value_at_quantile(0.25) as i64; + let diff = new - old; + let diff_ratio = diff as f64 / old as f64; + let speedup = 1.0 / (1.0 + diff_ratio); + Comparison { + name: "p25_latency".to_string(), + old_value: format!("{:.2}", old), + new_value: format!("{:.2}", new), + diff, + diff_ratio, + speedup, + } + } + pub fn cmp_p50_latency(&self) -> Comparison { + let old = self.old.latency_ms.histogram.value_at_quantile(0.5) as i64; + let new = self.new.latency_ms.histogram.value_at_quantile(0.5) as i64; + let diff = new - old; + let diff_ratio = diff as f64 / old as f64; + let speedup = 1.0 / (1.0 + diff_ratio); + Comparison { + name: "p50_latency".to_string(), + old_value: format!("{:.2}", old), + new_value: format!("{:.2}", new), + diff, + diff_ratio, + speedup, + } + } + pub fn cmp_p75_latency(&self) -> Comparison { + let old = self.old.latency_ms.histogram.value_at_quantile(0.75) as i64; + let new = self.new.latency_ms.histogram.value_at_quantile(0.75) as i64; + let diff = new - old; + let diff_ratio = diff as f64 / old as f64; + let speedup = 1.0 / (1.0 + diff_ratio); + Comparison { + name: "p75_latency".to_string(), + old_value: format!("{:.2}", old), + new_value: format!("{:.2}", new), + diff, + diff_ratio, + speedup, + } + } + pub fn cmp_p90_latency(&self) -> Comparison { + let old = self.old.latency_ms.histogram.value_at_quantile(0.9) as i64; + let new = self.new.latency_ms.histogram.value_at_quantile(0.9) as i64; + let diff = new - old; + let diff_ratio = diff as f64 / old as f64; + let speedup = 1.0 / (1.0 + diff_ratio); + Comparison { + name: "p90_latency".to_string(), + old_value: format!("{:.2}", old), + new_value: format!("{:.2}", new), + diff, + diff_ratio, + speedup, + } + } + pub fn cmp_p99_latency(&self) -> Comparison { + let old = self.old.latency_ms.histogram.value_at_quantile(0.99) as i64; + let new = self.new.latency_ms.histogram.value_at_quantile(0.99) as i64; + let diff = new - old; + let diff_ratio = diff as f64 / old as f64; + let speedup = 1.0 / (1.0 + diff_ratio); + Comparison { + name: "p99_latency".to_string(), + old_value: format!("{:.2}", old), + new_value: format!("{:.2}", new), + diff, + diff_ratio, + speedup, + } + } + pub fn cmp_p999_latency(&self) -> Comparison { + let old = self.old.latency_ms.histogram.value_at_quantile(0.999) as i64; + let new = self.new.latency_ms.histogram.value_at_quantile(0.999) as i64; + let diff = new - old; + let diff_ratio = diff as f64 / old as f64; + let speedup = 1.0 / (1.0 + diff_ratio); + Comparison { + name: "p999_latency".to_string(), + old_value: format!("{:.2}", old), + new_value: format!("{:.2}", new), + diff, + diff_ratio, + speedup, + } + } + pub fn cmp_max_latency(&self) -> Comparison { + let old = self.old.latency_ms.histogram.max() as i64; + let new = self.new.latency_ms.histogram.max() as i64; + let diff = new - old; + let diff_ratio = diff as f64 / old as f64; + let speedup = 1.0 / (1.0 + diff_ratio); + Comparison { + name: "max_latency".to_string(), + old_value: format!("{:.2}", old), + new_value: format!("{:.2}", new), + diff, + diff_ratio, + speedup, + } + } +} + +/// Convert an unsigned number into a string separated by `delim` every +/// `step_size` digits For example used to make 100000 more readable as 100,000 +fn format_num_with_separators + std::fmt::Display>( + x: T, + step_size: u8, + delim: &'static str, +) -> String { + x.to_string() + .as_bytes() + .rchunks(step_size as usize) + .rev() + .map(std::str::from_utf8) + .collect::, _>>() + .unwrap() + .join(delim) +} diff --git a/crates/sui-benchmark/src/embedded_reconfig_observer.rs b/crates/iota-benchmark/src/embedded_reconfig_observer.rs similarity index 95% rename from crates/sui-benchmark/src/embedded_reconfig_observer.rs rename to crates/iota-benchmark/src/embedded_reconfig_observer.rs index 8667c83f905..a84e45f56b4 100644 --- a/crates/sui-benchmark/src/embedded_reconfig_observer.rs +++ b/crates/iota-benchmark/src/embedded_reconfig_observer.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; use anyhow::anyhow; use async_trait::async_trait; -use sui_core::{ +use iota_core::{ authority_aggregator::AuthorityAggregator, authority_client::NetworkAuthorityClient, quorum_driver::{reconfig_observer::ReconfigObserver, QuorumDriver}, }; -use sui_network::default_mysten_network_config; -use sui_types::sui_system_state::SuiSystemStateTrait; +use iota_network::default_mysten_network_config; +use iota_types::iota_system_state::IotaSystemStateTrait; use tracing::{error, info, trace}; /// A ReconfigObserver that polls validators periodically diff --git a/crates/sui-benchmark/src/fullnode_reconfig_observer.rs b/crates/iota-benchmark/src/fullnode_reconfig_observer.rs similarity index 78% rename from crates/sui-benchmark/src/fullnode_reconfig_observer.rs rename to crates/iota-benchmark/src/fullnode_reconfig_observer.rs index 5f19f3ab667..61fbdf24886 100644 --- a/crates/sui-benchmark/src/fullnode_reconfig_observer.rs +++ b/crates/iota-benchmark/src/fullnode_reconfig_observer.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, sync::Arc}; use async_trait::async_trait; -use sui_core::{ +use iota_core::{ authority_aggregator::{AuthAggMetrics, AuthorityAggregator}, authority_client::NetworkAuthorityClient, epoch::committee_store::CommitteeStore, quorum_driver::{reconfig_observer::ReconfigObserver, QuorumDriver}, safe_client::SafeClientMetricsBase, }; -use sui_sdk::{SuiClient, SuiClientBuilder}; +use iota_sdk::{IotaClient, IotaClientBuilder}; use tracing::{debug, error, trace}; /// A ReconfigObserver that polls FullNode periodically @@ -21,7 +22,7 @@ use tracing::{debug, error, trace}; /// as stress, but may not be suitable in some other cases. #[derive(Clone)] pub struct FullNodeReconfigObserver { - pub fullnode_client: SuiClient, + pub fullnode_client: IotaClient, committee_store: Arc, safe_client_metrics_base: SafeClientMetricsBase, auth_agg_metrics: Arc, @@ -35,12 +36,12 @@ impl FullNodeReconfigObserver { auth_agg_metrics: Arc, ) -> Self { Self { - fullnode_client: SuiClientBuilder::default() + fullnode_client: IotaClientBuilder::default() .build(fullnode_rpc_url) .await .unwrap_or_else(|e| { panic!( - "Can't create SuiClient with rpc url {fullnode_rpc_url}: {:?}", + "Can't create IotaClient with rpc url {fullnode_rpc_url}: {:?}", e ) }), @@ -63,19 +64,19 @@ impl ReconfigObserver for FullNodeReconfigObserver { match self .fullnode_client .governance_api() - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await { - Ok(sui_system_state) => { - let epoch_id = sui_system_state.epoch; + Ok(iota_system_state) => { + let epoch_id = iota_system_state.epoch; if epoch_id > quorum_driver.current_epoch() { - debug!(epoch_id, "Got SuiSystemState in newer epoch"); - let new_committee = sui_system_state - .get_sui_committee_for_benchmarking() + debug!(epoch_id, "Got IotaSystemState in newer epoch"); + let new_committee = iota_system_state + .get_iota_committee_for_benchmarking() .committee; let _ = self.committee_store.insert_new_committee(&new_committee); match AuthorityAggregator::new_from_committee( - sui_system_state.get_sui_committee_for_benchmarking(), + iota_system_state.get_iota_committee_for_benchmarking(), &self.committee_store, self.safe_client_metrics_base.clone(), self.auth_agg_metrics.clone(), @@ -85,7 +86,7 @@ impl ReconfigObserver for FullNodeReconfigObserver { quorum_driver.update_validators(Arc::new(auth_agg)).await } Err(err) => error!( - "Can't create AuthorityAggregator from SuiSystemState: {:?}", + "Can't create AuthorityAggregator from IotaSystemState: {:?}", err ), } @@ -96,7 +97,7 @@ impl ReconfigObserver for FullNodeReconfigObserver { ); } } - Err(err) => error!("Can't get SuiSystemState from Full Node: {:?}", err,), + Err(err) => error!("Can't get IotaSystemState from Full Node: {:?}", err,), } } } diff --git a/crates/sui-benchmark/src/in_memory_wallet.rs b/crates/iota-benchmark/src/in_memory_wallet.rs similarity index 84% rename from crates/sui-benchmark/src/in_memory_wallet.rs rename to crates/iota-benchmark/src/in_memory_wallet.rs index cc2f6a286f3..95d4a4ef30c 100644 --- a/crates/sui-benchmark/src/in_memory_wallet.rs +++ b/crates/iota-benchmark/src/in_memory_wallet.rs @@ -1,25 +1,26 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, sync::Arc}; -use move_core_types::{identifier::Identifier, language_storage::TypeTag}; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef}, crypto::AccountKeyPair, object::Owner, transaction::{CallArg, Command, Transaction, TransactionData, TransactionDataAPI}, utils::to_sender_signed_transaction, }; +use move_core_types::{identifier::Identifier, language_storage::TypeTag}; use crate::{ convert_move_call_args, workloads::Gas, BenchMoveCallArg, ExecutionEffects, ProgrammableTransactionBuilder, }; -/// A Sui account and all of the objects it owns +/// A Iota account and all of the objects it owns #[derive(Debug)] -pub struct SuiAccount { +pub struct IotaAccount { key: Arc, /// object this account uses to pay for gas pub gas: ObjectRef, @@ -28,10 +29,10 @@ pub struct SuiAccount { // TODO: optional type info } -impl SuiAccount { +impl IotaAccount { pub fn new(key: Arc, gas: ObjectRef, objs: Vec) -> Self { let owned = objs.into_iter().map(|obj| (obj.0, obj)).collect(); - SuiAccount { key, gas, owned } + IotaAccount { key, gas, owned } } /// Update the state associated with `obj`, adding it if it doesn't exist @@ -62,7 +63,8 @@ impl SuiAccount { /// objects, and immutable objects #[derive(Debug, Default)] pub struct InMemoryWallet { - accounts: BTreeMap, // TODO: track shared and immutable objects as well + accounts: BTreeMap, /* TODO: track shared and immutable objects as + * well */ } impl InMemoryWallet { @@ -76,12 +78,12 @@ impl InMemoryWallet { pub fn add_account( &mut self, - addr: SuiAddress, + addr: IotaAddress, key: Arc, gas: ObjectRef, objs: Vec, ) { - self.accounts.insert(addr, SuiAccount::new(key, gas, objs)); + self.accounts.insert(addr, IotaAccount::new(key, gas, objs)); } /// Apply updates from `effects` to `self` @@ -107,23 +109,23 @@ impl InMemoryWallet { } // else, tx sender is not an account we can spend from, we don't care } - pub fn account_mut(&mut self, addr: &SuiAddress) -> Option<&mut SuiAccount> { + pub fn account_mut(&mut self, addr: &IotaAddress) -> Option<&mut IotaAccount> { self.accounts.get_mut(addr) } - pub fn account(&self, addr: &SuiAddress) -> Option<&SuiAccount> { + pub fn account(&self, addr: &IotaAddress) -> Option<&IotaAccount> { self.accounts.get(addr) } - pub fn gas(&self, addr: &SuiAddress) -> Option<&ObjectRef> { + pub fn gas(&self, addr: &IotaAddress) -> Option<&ObjectRef> { self.accounts.get(addr).map(|a| &a.gas) } - pub fn owned_object(&self, addr: &SuiAddress, id: &ObjectID) -> Option<&ObjectRef> { + pub fn owned_object(&self, addr: &IotaAddress, id: &ObjectID) -> Option<&ObjectRef> { self.accounts.get(addr).and_then(|a| a.owned.get(id)) } - pub fn owned_objects(&self, addr: &SuiAddress) -> Option> { + pub fn owned_objects(&self, addr: &IotaAddress) -> Option> { self.accounts.get(addr).map(|a| a.owned.values()) } @@ -134,7 +136,7 @@ impl InMemoryWallet { pub fn move_call( &self, - sender: SuiAddress, + sender: IotaAddress, package: ObjectID, module: &str, function: &str, @@ -161,7 +163,7 @@ impl InMemoryWallet { pub fn move_call_pt( &self, - sender: SuiAddress, + sender: IotaAddress, package: ObjectID, module: &str, function: &str, @@ -185,7 +187,7 @@ impl InMemoryWallet { ) } - pub fn keypair(&self, addr: &SuiAddress) -> Option> { + pub fn keypair(&self, addr: &IotaAddress) -> Option> { self.accounts.get(addr).map(|a| a.key.clone()) } @@ -193,7 +195,7 @@ impl InMemoryWallet { self.accounts.len() } - pub fn addresses(&self) -> impl Iterator { + pub fn addresses(&self) -> impl Iterator { self.accounts.keys() } @@ -207,7 +209,7 @@ impl InMemoryWallet { } pub fn move_call_pt_impl( - sender: SuiAddress, + sender: IotaAddress, keypair: &AccountKeyPair, package: ObjectID, module: &str, diff --git a/crates/iota-benchmark/src/lib.rs b/crates/iota-benchmark/src/lib.rs new file mode 100644 index 00000000000..d1bdec8d0e3 --- /dev/null +++ b/crates/iota-benchmark/src/lib.rs @@ -0,0 +1,917 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use std::{ + collections::BTreeMap, + sync::{Arc, Mutex}, + time::Duration, +}; + +use anyhow::bail; +use async_trait::async_trait; +use embedded_reconfig_observer::EmbeddedReconfigObserver; +use fullnode_reconfig_observer::FullNodeReconfigObserver; +use futures::{stream::FuturesUnordered, StreamExt}; +use iota_config::genesis::Genesis; +use iota_core::{ + authority_aggregator::{AuthorityAggregator, AuthorityAggregatorBuilder}, + authority_client::{ + make_authority_clients_with_timeout_config, AuthorityAPI, NetworkAuthorityClient, + }, + quorum_driver::{ + QuorumDriver, QuorumDriverHandler, QuorumDriverHandlerBuilder, QuorumDriverMetrics, + }, +}; +use iota_json_rpc_types::{ + IotaObjectDataOptions, IotaObjectResponse, IotaObjectResponseQuery, + IotaTransactionBlockEffects, IotaTransactionBlockEffectsAPI, + IotaTransactionBlockResponseOptions, +}; +use iota_network::{DEFAULT_CONNECT_TIMEOUT_SEC, DEFAULT_REQUEST_TIMEOUT_SEC}; +use iota_sdk::{IotaClient, IotaClientBuilder}; +use iota_types::{ + base_types::{ + AuthorityName, ConciseableName, IotaAddress, ObjectID, ObjectRef, SequenceNumber, + }, + committee::{Committee, CommitteeTrait, EpochId}, + crypto::{ + AggregateAuthenticator, AggregateAuthoritySignature, AuthorityQuorumSignInfo, + AuthoritySignature, AuthorityStrongQuorumSignInfo, + }, + effects::{CertifiedTransactionEffects, TransactionEffectsAPI, TransactionEvents}, + error::IotaError, + gas::GasCostSummary, + gas_coin::GasCoin, + iota_system_state::{iota_system_state_summary::IotaSystemStateSummary, IotaSystemStateTrait}, + message_envelope::Envelope, + object::{Object, Owner}, + programmable_transaction_builder::ProgrammableTransactionBuilder, + transaction::{Argument, CallArg, CertifiedTransaction, ObjectArg, Transaction}, +}; +use mysten_metrics::GaugeGuard; +use prometheus::Registry; +use rand::Rng; +use roaring::RoaringBitmap; +use tokio::{ + task::JoinSet, + time::{sleep, timeout}, +}; +use tracing::{error, info}; + +pub mod bank; +pub mod benchmark_setup; +pub mod drivers; +pub mod embedded_reconfig_observer; +pub mod fullnode_reconfig_observer; +pub mod in_memory_wallet; +pub mod options; +pub mod system_state_observer; +pub mod util; +pub mod workloads; +use futures::FutureExt; +use iota_types::{ + messages_grpc::{HandleCertificateResponseV2, TransactionStatus}, + quorum_driver_types::{QuorumDriverError, QuorumDriverResponse}, +}; + +#[derive(Debug)] +/// A wrapper on execution results to accommodate different types of +/// responses from LocalValidatorAggregatorProxy and FullNodeProxy +#[allow(clippy::large_enum_variant)] +pub enum ExecutionEffects { + CertifiedTransactionEffects(CertifiedTransactionEffects, TransactionEvents), + IotaTransactionBlockEffects(IotaTransactionBlockEffects), +} + +impl ExecutionEffects { + pub fn mutated(&self) -> Vec<(ObjectRef, Owner)> { + match self { + ExecutionEffects::CertifiedTransactionEffects(certified_effects, ..) => { + certified_effects.data().mutated().to_vec() + } + ExecutionEffects::IotaTransactionBlockEffects(iota_tx_effects) => iota_tx_effects + .mutated() + .iter() + .map(|refe| (refe.reference.to_object_ref(), refe.owner)) + .collect(), + } + } + + pub fn created(&self) -> Vec<(ObjectRef, Owner)> { + match self { + ExecutionEffects::CertifiedTransactionEffects(certified_effects, ..) => { + certified_effects.data().created() + } + ExecutionEffects::IotaTransactionBlockEffects(iota_tx_effects) => iota_tx_effects + .created() + .iter() + .map(|refe| (refe.reference.to_object_ref(), refe.owner)) + .collect(), + } + } + + pub fn deleted(&self) -> Vec { + match self { + ExecutionEffects::CertifiedTransactionEffects(certified_effects, ..) => { + certified_effects.data().deleted().to_vec() + } + ExecutionEffects::IotaTransactionBlockEffects(iota_tx_effects) => iota_tx_effects + .deleted() + .iter() + .map(|refe| refe.to_object_ref()) + .collect(), + } + } + + pub fn quorum_sig(&self) -> Option<&AuthorityStrongQuorumSignInfo> { + match self { + ExecutionEffects::CertifiedTransactionEffects(certified_effects, ..) => { + Some(certified_effects.auth_sig()) + } + ExecutionEffects::IotaTransactionBlockEffects(_) => None, + } + } + + pub fn gas_object(&self) -> (ObjectRef, Owner) { + match self { + ExecutionEffects::CertifiedTransactionEffects(certified_effects, ..) => { + certified_effects.data().gas_object() + } + ExecutionEffects::IotaTransactionBlockEffects(iota_tx_effects) => { + let refe = &iota_tx_effects.gas_object(); + (refe.reference.to_object_ref(), refe.owner) + } + } + } + + pub fn sender(&self) -> IotaAddress { + match self.gas_object().1 { + Owner::AddressOwner(a) => a, + Owner::ObjectOwner(_) | Owner::Shared { .. } | Owner::Immutable => unreachable!(), /* owner of gas object is always an address */ + } + } + + pub fn is_ok(&self) -> bool { + match self { + ExecutionEffects::CertifiedTransactionEffects(certified_effects, ..) => { + certified_effects.data().status().is_ok() + } + ExecutionEffects::IotaTransactionBlockEffects(iota_tx_effects) => { + iota_tx_effects.status().is_ok() + } + } + } + + pub fn status(&self) -> String { + match self { + ExecutionEffects::CertifiedTransactionEffects(certified_effects, ..) => { + format!("{:#?}", certified_effects.data().status()) + } + ExecutionEffects::IotaTransactionBlockEffects(iota_tx_effects) => { + format!("{:#?}", iota_tx_effects.status()) + } + } + } + + pub fn gas_cost_summary(&self) -> GasCostSummary { + match self { + crate::ExecutionEffects::CertifiedTransactionEffects(a, _) => { + a.data().gas_cost_summary().clone() + } + crate::ExecutionEffects::IotaTransactionBlockEffects(b) => { + std::convert::Into::::into(b.gas_cost_summary().clone()) + } + } + } + + pub fn gas_used(&self) -> u64 { + self.gas_cost_summary().gas_used() + } + + pub fn net_gas_used(&self) -> i64 { + self.gas_cost_summary().net_gas_usage() + } + + pub fn print_gas_summary(&self) { + let gas_object = self.gas_object(); + let sender = self.sender(); + let status = self.status(); + let gas_cost_summary = self.gas_cost_summary(); + let gas_used = self.gas_used(); + let net_gas_used = self.net_gas_used(); + + info!( + "Summary:\n\ + Gas Object: {gas_object:?}\n\ + Sender: {sender:?}\n\ + status: {status}\n\ + Gas Cost Summary: {gas_cost_summary:#?}\n\ + Gas Used: {gas_used}\n\ + Net Gas Used: {net_gas_used}" + ); + } +} + +#[async_trait] +pub trait ValidatorProxy { + async fn get_object(&self, object_id: ObjectID) -> Result; + + async fn get_owned_objects( + &self, + account_address: IotaAddress, + ) -> Result, anyhow::Error>; + + async fn get_latest_system_state_object(&self) + -> Result; + + async fn execute_transaction_block(&self, tx: Transaction) -> anyhow::Result; + + /// This function is similar to `execute_transaction` but does not check any + /// validator's signature. It should only be used for benchmarks. + async fn execute_bench_transaction(&self, tx: Transaction) -> anyhow::Result; + + fn clone_committee(&self) -> Arc; + + fn get_current_epoch(&self) -> EpochId; + + fn clone_new(&self) -> Box; + + async fn get_validators(&self) -> Result, anyhow::Error>; +} + +// TODO: Eventually remove this proxy because we shouldn't rely on validators to +// read objects. +pub struct LocalValidatorAggregatorProxy { + _qd_handler: QuorumDriverHandler, + // Stress client does not verify individual validator signatures since this is very expensive + qd: Arc>, + committee: Committee, + clients: BTreeMap, + requests: Mutex>, +} + +impl LocalValidatorAggregatorProxy { + pub async fn from_genesis( + genesis: &Genesis, + registry: &Registry, + reconfig_fullnode_rpc_url: Option<&str>, + ) -> Self { + let (aggregator, _) = AuthorityAggregatorBuilder::from_genesis(genesis) + .with_registry(registry) + .build() + .unwrap(); + + let committee = genesis.committee_with_network(); + let clients = make_authority_clients_with_timeout_config( + &committee, + DEFAULT_CONNECT_TIMEOUT_SEC, + DEFAULT_REQUEST_TIMEOUT_SEC, + ) + .unwrap(); + + Self::new_impl( + aggregator, + registry, + reconfig_fullnode_rpc_url, + clients, + committee.committee, + ) + .await + } + + async fn new_impl( + aggregator: AuthorityAggregator, + registry: &Registry, + reconfig_fullnode_rpc_url: Option<&str>, + clients: BTreeMap, + committee: Committee, + ) -> Self { + let quorum_driver_metrics = Arc::new(QuorumDriverMetrics::new(registry)); + let qd_handler = (if let Some(reconfig_fullnode_rpc_url) = reconfig_fullnode_rpc_url { + let qd_handler_builder = QuorumDriverHandlerBuilder::new( + Arc::new(aggregator.clone()), + quorum_driver_metrics, + ); + info!( + "Using FullNodeReconfigObserver: {:?}", + reconfig_fullnode_rpc_url + ); + let committee_store = aggregator.clone_committee_store(); + let reconfig_observer = Arc::new( + FullNodeReconfigObserver::new( + reconfig_fullnode_rpc_url, + committee_store, + aggregator.safe_client_metrics_base.clone(), + aggregator.metrics.clone(), + ) + .await, + ); + qd_handler_builder.with_reconfig_observer(reconfig_observer) + } else { + info!("Using EmbeddedReconfigObserver"); + let observer = EmbeddedReconfigObserver::new(); + // Get the latest committee from config observer + let new_agg = observer + .get_committee(Arc::new(aggregator)) + .await + .expect("Failed to get latest committee"); + let qd_handler_builder = + QuorumDriverHandlerBuilder::new(new_agg, quorum_driver_metrics); + qd_handler_builder.with_reconfig_observer(Arc::new(EmbeddedReconfigObserver::new())) + }) + .start(); + + let qd = qd_handler.clone_quorum_driver(); + Self { + _qd_handler: qd_handler, + qd, + clients, + committee, + requests: Mutex::new(JoinSet::new()), + } + } +} + +#[async_trait] +impl ValidatorProxy for LocalValidatorAggregatorProxy { + async fn get_object(&self, object_id: ObjectID) -> Result { + let auth_agg = self.qd.authority_aggregator().load(); + Ok(auth_agg + .get_latest_object_version_for_testing(object_id) + .await?) + } + + async fn get_owned_objects( + &self, + _account_address: IotaAddress, + ) -> Result, anyhow::Error> { + unimplemented!("Not available for local proxy"); + } + + async fn get_latest_system_state_object( + &self, + ) -> Result { + let auth_agg = self.qd.authority_aggregator().load(); + Ok(auth_agg + .get_latest_system_state_object_for_testing() + .await? + .into_iota_system_state_summary()) + } + + async fn execute_transaction_block(&self, tx: Transaction) -> anyhow::Result { + if std::env::var("BENCH_MODE").is_ok() { + return self.execute_bench_transaction(tx).await; + } + let tx_digest = *tx.digest(); + let mut retry_cnt = 0; + while retry_cnt < 3 { + let ticket = self.qd.submit_transaction(tx.clone()).await?; + // The ticket only times out when QuorumDriver exceeds the retry times + match ticket.await { + Ok(resp) => { + let QuorumDriverResponse { + effects_cert, + events, + } = resp; + return Ok(ExecutionEffects::CertifiedTransactionEffects( + effects_cert.into(), + events, + )); + } + Err(QuorumDriverError::NonRecoverableTransactionError { errors }) => { + bail!(QuorumDriverError::NonRecoverableTransactionError { errors }); + } + Err(err) => { + let delay = Duration::from_millis(rand::thread_rng().gen_range(100..1000)); + error!( + ?tx_digest, + retry_cnt, + "Transaction failed with err: {:?}. Sleeping for {:?} ...", + err, + delay, + ); + retry_cnt += 1; + sleep(delay).await; + } + } + } + bail!("Transaction {:?} failed for {retry_cnt} times", tx_digest); + } + + async fn execute_bench_transaction(&self, tx: Transaction) -> anyhow::Result { + // Store the epoch number; we read it from the votes and use it later to create + // the certificate. + let mut epoch = 0; + let auth_agg = self.qd.authority_aggregator().load(); + + // Send the transaction to all validators. + let tx_guard = GaugeGuard::acquire(&auth_agg.metrics.inflight_transactions); + let mut futures = FuturesUnordered::new(); + for (name, client) in self.clients.iter() { + let fut = client.handle_transaction(tx.clone()).map(|r| (r, *name)); + futures.push(fut); + } + auth_agg + .metrics + .inflight_transaction_requests + .add(futures.len() as i64); + + // TODO: This following aggregation will not work well at epoch boundary. + + // Listen to the replies from the first 2f+1 votes. + let mut total_stake = 0; + let mut votes = Vec::new(); + let mut certificate = None; + while let Some((response, name)) = futures.next().await { + auth_agg.metrics.inflight_transaction_requests.dec(); + match response { + Ok(response) => match response.status { + // If all goes well, the authority returns a vote. + TransactionStatus::Signed(signature) => { + epoch = signature.epoch; + total_stake += self.committee.weight(&signature.authority); + votes.push(signature); + } + // The transaction may be submitted again in case the certificate's submission + // failed. + TransactionStatus::Executed(cert, _effects, _) => { + tracing::warn!("Transaction already submitted: {tx:?}"); + if let Some(cert) = cert { + certificate = Some(CertifiedTransaction::new_from_data_and_sig( + tx.data().clone(), + cert, + )); + } + } + }, + // This typically happens when the validators are overloaded and the transaction is + // immediately rejected. + Err(e) => { + self.qd + .authority_aggregator() + .load() + .metrics + .process_tx_errors + .with_label_values(&[&name.concise().to_string(), e.as_ref()]) + .inc(); + tracing::warn!("Failed to submit transaction: {e}") + } + } + + if total_stake >= self.committee.quorum_threshold() { + break; + } + + if certificate.is_some() { + break; + } + } + + // Assemble a certificate from the validator's replies. + let certified_transaction: CertifiedTransaction = match certificate { + Some(x) => x, + None => { + let signatures: BTreeMap<_, _> = votes + .into_iter() + .map(|a| (a.authority, a.signature)) + .collect(); + let mut signers_map = RoaringBitmap::new(); + for pk in signatures.keys() { + signers_map.insert( + self.committee + .authority_index(pk) + .ok_or(IotaError::UnknownSigner { + signer: Some(pk.concise().to_string()), + index: None, + committee: Box::new(self.committee.clone()), + }) + .expect("Received signature from unknown validator"), + ); + } + let sigs: Vec = signatures.into_values().collect(); + + let quorum_signature = AuthorityQuorumSignInfo { + epoch, + // Note: This function simply aggregates signatures (it does not check that they + // are individually valid). + signature: AggregateAuthoritySignature::aggregate(&sigs) + .map_err(|e| IotaError::InvalidSignature { + error: e.to_string(), + }) + .expect("Validator returned invalid signature"), + signers_map, + }; + + Envelope::new_from_data_and_sig(tx.into_data(), quorum_signature) + } + }; + auth_agg + .metrics + .inflight_transaction_requests + .sub(futures.len() as i64); + drop(tx_guard); + + // Send the certificate to all validators. + let _cert_guard = GaugeGuard::acquire(&auth_agg.metrics.inflight_certificates); + let mut futures = FuturesUnordered::new(); + total_stake = 0; + let mut transaction_effects = None; + let mut transaction_events = None; + for (name, client) in self.clients.iter() { + let client = client.clone(); + let certificate = certified_transaction.clone(); + let name = *name; + futures.push(async move { + client + .handle_certificate_v2(certificate) + .map(move |r| (r, name)) + .await + }); + } + auth_agg + .metrics + .inflight_certificate_requests + .add(futures.len() as i64); + + // Wait for the replies from a quorum of validators. + while let Some((response, name)) = futures.next().await { + auth_agg.metrics.inflight_certificate_requests.dec(); + match response { + // If all goes well, the validators reply with signed effects. + Ok(HandleCertificateResponseV2 { + signed_effects, + events, + fastpath_input_objects: _, // unused field + }) => { + let author = signed_effects.auth_sig().authority; + transaction_effects = Some(signed_effects.data().clone()); + transaction_events = Some(events); + total_stake += self.committee.weight(&author); + } + + // This typically happens when the validators are overloaded and the certificate is + // immediately rejected. + Err(e) => { + auth_agg + .metrics + .process_cert_errors + .with_label_values(&[&name.concise().to_string(), e.as_ref()]) + .inc(); + tracing::warn!("Failed to submit certificate: {e}") + } + } + + if total_stake >= self.committee.quorum_threshold() { + break; + } + } + + // Abort if we failed to submit the certificate to enough validators. This + // typically happens when the validators are overloaded and the requests + // timed out. + if transaction_effects.is_none() || total_stake < self.committee.quorum_threshold() { + bail!("Failed to submit certificate to quorum of validators"); + } + + // Wait for 10 more seconds on remaining requests asynchronously. + const WAIT_TIMEOUT: Duration = Duration::from_secs(10); + { + let auth_agg = auth_agg.clone(); + let mut requests = self.requests.lock().unwrap(); + requests.spawn(async move { + let _ = timeout(WAIT_TIMEOUT, async { + while futures.next().await.is_some() { + auth_agg.metrics.inflight_certificate_requests.dec(); + } + }) + .await; + auth_agg + .metrics + .inflight_certificate_requests + .sub(futures.len() as i64); + }); + } + + // Package the certificate and effects to return. + let signed_material = certified_transaction.auth_sig().clone(); + let effects = ExecutionEffects::CertifiedTransactionEffects( + Envelope::new_from_data_and_sig(transaction_effects.unwrap(), signed_material), + transaction_events.unwrap(), + ); + Ok(effects) + } + + fn clone_committee(&self) -> Arc { + self.qd.clone_committee() + } + + fn get_current_epoch(&self) -> EpochId { + self.qd.current_epoch() + } + + fn clone_new(&self) -> Box { + let qdh = self._qd_handler.clone_new(); + let qd = qdh.clone_quorum_driver(); + Box::new(Self { + _qd_handler: qdh, + qd, + clients: self.clients.clone(), + committee: self.committee.clone(), + requests: Mutex::new(JoinSet::new()), + }) + } + + async fn get_validators(&self) -> Result, anyhow::Error> { + let system_state = self.get_latest_system_state_object().await?; + Ok(system_state + .active_validators + .iter() + .map(|v| v.iota_address) + .collect()) + } +} + +pub struct FullNodeProxy { + iota_client: IotaClient, + committee: Arc, +} + +impl FullNodeProxy { + pub async fn from_url(http_url: &str) -> Result { + // Each request times out after 60s (default value) + let iota_client = IotaClientBuilder::default() + .max_concurrent_requests(500_000) + .build(http_url) + .await?; + + let resp = iota_client.read_api().get_committee_info(None).await?; + let epoch = resp.epoch; + let committee_vec = resp.validators; + let committee_map = BTreeMap::from_iter(committee_vec.into_iter()); + let committee = + Committee::new_for_testing_with_normalized_voting_power(epoch, committee_map); + + Ok(Self { + iota_client, + committee: Arc::new(committee), + }) + } +} + +#[async_trait] +impl ValidatorProxy for FullNodeProxy { + async fn get_object(&self, object_id: ObjectID) -> Result { + let response = self + .iota_client + .read_api() + .get_object_with_options(object_id, IotaObjectDataOptions::bcs_lossless()) + .await?; + + if let Some(iota_object) = response.data { + iota_object.try_into() + } else if let Some(error) = response.error { + bail!("Error getting object {:?}: {}", object_id, error) + } else { + bail!("Object {:?} not found and no error provided", object_id) + } + } + + async fn get_owned_objects( + &self, + account_address: IotaAddress, + ) -> Result, anyhow::Error> { + let mut objects: Vec = Vec::new(); + let mut cursor = None; + loop { + let response = self + .iota_client + .read_api() + .get_owned_objects( + account_address, + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::bcs_lossless(), + )), + cursor, + None, + ) + .await?; + + objects.extend(response.data); + + if response.has_next_page { + cursor = response.next_cursor; + } else { + break; + } + } + + let mut values_objects = Vec::new(); + + for object in objects { + let o = object.data; + if let Some(o) = o { + let temp: Object = o.clone().try_into()?; + let gas_coin = GasCoin::try_from(&temp)?; + values_objects.push((gas_coin.value(), o.clone().try_into()?)); + } + } + + Ok(values_objects) + } + + async fn get_latest_system_state_object( + &self, + ) -> Result { + Ok(self + .iota_client + .governance_api() + .get_latest_iota_system_state() + .await?) + } + + async fn execute_transaction_block(&self, tx: Transaction) -> anyhow::Result { + let tx_digest = *tx.digest(); + let mut retry_cnt = 0; + while retry_cnt < 10 { + // Fullnode could time out after WAIT_FOR_FINALITY_TIMEOUT (30s) in + // TransactionOrchestrator IotaClient times out after 60s + match self + .iota_client + .quorum_driver_api() + .execute_transaction_block( + tx.clone(), + IotaTransactionBlockResponseOptions::new().with_effects(), + None, + ) + .await + { + Ok(resp) => { + let effects = ExecutionEffects::IotaTransactionBlockEffects( + resp.effects.expect("effects field should not be None"), + ); + return Ok(effects); + } + Err(err) => { + error!( + ?tx_digest, + retry_cnt, "Transaction failed with err: {:?}", err + ); + retry_cnt += 1; + } + } + } + bail!("Transaction {:?} failed for {retry_cnt} times", tx_digest); + } + + async fn execute_bench_transaction(&self, tx: Transaction) -> anyhow::Result { + self.execute_transaction_block(tx).await + } + + fn clone_committee(&self) -> Arc { + self.committee.clone() + } + + fn get_current_epoch(&self) -> EpochId { + self.committee.epoch + } + + fn clone_new(&self) -> Box { + Box::new(Self { + iota_client: self.iota_client.clone(), + committee: self.clone_committee(), + }) + } + + async fn get_validators(&self) -> Result, anyhow::Error> { + let validators = self + .iota_client + .governance_api() + .get_latest_iota_system_state() + .await? + .active_validators; + Ok(validators.into_iter().map(|v| v.iota_address).collect()) + } +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub enum BenchMoveCallArg { + Pure(Vec), + Shared((ObjectID, SequenceNumber, bool)), + ImmOrOwnedObject(ObjectRef), + ImmOrOwnedObjectVec(Vec), + SharedObjectVec(Vec<(ObjectID, SequenceNumber, bool)>), +} + +impl From for BenchMoveCallArg { + fn from(b: bool) -> Self { + // unwrap safe because every u8 value is BCS-serializable + BenchMoveCallArg::Pure(bcs::to_bytes(&b).unwrap()) + } +} + +impl From for BenchMoveCallArg { + fn from(n: u8) -> Self { + // unwrap safe because every u8 value is BCS-serializable + BenchMoveCallArg::Pure(bcs::to_bytes(&n).unwrap()) + } +} + +impl From for BenchMoveCallArg { + fn from(n: u16) -> Self { + // unwrap safe because every u16 value is BCS-serializable + BenchMoveCallArg::Pure(bcs::to_bytes(&n).unwrap()) + } +} + +impl From for BenchMoveCallArg { + fn from(n: u32) -> Self { + // unwrap safe because every u32 value is BCS-serializable + BenchMoveCallArg::Pure(bcs::to_bytes(&n).unwrap()) + } +} + +impl From for BenchMoveCallArg { + fn from(n: u64) -> Self { + // unwrap safe because every u64 value is BCS-serializable + BenchMoveCallArg::Pure(bcs::to_bytes(&n).unwrap()) + } +} + +impl From for BenchMoveCallArg { + fn from(n: u128) -> Self { + // unwrap safe because every u128 value is BCS-serializable + BenchMoveCallArg::Pure(bcs::to_bytes(&n).unwrap()) + } +} + +impl From<&Vec> for BenchMoveCallArg { + fn from(v: &Vec) -> Self { + // unwrap safe because every vec value is BCS-serializable + BenchMoveCallArg::Pure(bcs::to_bytes(v).unwrap()) + } +} + +impl From for BenchMoveCallArg { + fn from(obj: ObjectRef) -> Self { + BenchMoveCallArg::ImmOrOwnedObject(obj) + } +} + +impl From for BenchMoveCallArg { + fn from(ca: CallArg) -> Self { + match ca { + CallArg::Pure(p) => BenchMoveCallArg::Pure(p), + CallArg::Object(obj) => match obj { + ObjectArg::ImmOrOwnedObject(imo) => BenchMoveCallArg::ImmOrOwnedObject(imo), + ObjectArg::SharedObject { + id, + initial_shared_version, + mutable, + } => BenchMoveCallArg::Shared((id, initial_shared_version, mutable)), + ObjectArg::Receiving(_) => { + unimplemented!("Receiving is not supported for benchmarks") + } + }, + } + } +} + +/// Convert MoveCallArg to Vector of Argument for PT +pub fn convert_move_call_args( + args: &[BenchMoveCallArg], + pt_builder: &mut ProgrammableTransactionBuilder, +) -> Vec { + args.iter() + .map(|arg| match arg { + BenchMoveCallArg::Pure(bytes) => { + pt_builder.input(CallArg::Pure(bytes.clone())).unwrap() + } + BenchMoveCallArg::Shared((id, initial_shared_version, mutable)) => pt_builder + .input(CallArg::Object(ObjectArg::SharedObject { + id: *id, + initial_shared_version: *initial_shared_version, + mutable: *mutable, + })) + .unwrap(), + BenchMoveCallArg::ImmOrOwnedObject(obj_ref) => { + pt_builder.input((*obj_ref).into()).unwrap() + } + BenchMoveCallArg::ImmOrOwnedObjectVec(obj_refs) => pt_builder + .make_obj_vec(obj_refs.iter().map(|q| ObjectArg::ImmOrOwnedObject(*q))) + .unwrap(), + BenchMoveCallArg::SharedObjectVec(obj_refs) => pt_builder + .make_obj_vec( + obj_refs + .iter() + .map( + |(id, initial_shared_version, mutable)| ObjectArg::SharedObject { + id: *id, + initial_shared_version: *initial_shared_version, + mutable: *mutable, + }, + ), + ) + .unwrap(), + }) + .collect() +} diff --git a/crates/sui-benchmark/src/options.rs b/crates/iota-benchmark/src/options.rs similarity index 98% rename from crates/sui-benchmark/src/options.rs rename to crates/iota-benchmark/src/options.rs index bb6f895f070..757de7feed0 100644 --- a/crates/sui-benchmark/src/options.rs +++ b/crates/iota-benchmark/src/options.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::str::FromStr; @@ -11,7 +12,7 @@ use crate::drivers::Interval; #[derive(Parser)] #[clap(name = "Stress Testing Framework")] pub struct Opts { - /// Size of the Sui committee. + /// Size of the Iota committee. #[clap(long, default_value = "4", global = true)] pub committee_size: u64, /// Num of accounts to use for transfer objects @@ -32,7 +33,7 @@ pub struct Opts { pub genesis_blob_path: String, /// [Required for remote benchmark] /// Path where keypair for primary gas account is stored. The format of - /// this file is same as what `sui keytool generate` outputs + /// this file is same as what `iota keytool generate` outputs #[clap(long, default_value = "", global = true)] pub keystore_path: String, /// [Required for remote benchmark] diff --git a/crates/sui-benchmark/src/system_state_observer.rs b/crates/iota-benchmark/src/system_state_observer.rs similarity index 94% rename from crates/sui-benchmark/src/system_state_observer.rs rename to crates/iota-benchmark/src/system_state_observer.rs index fae2bf0bfac..1de3b4fed5a 100644 --- a/crates/sui-benchmark/src/system_state_observer.rs +++ b/crates/iota-benchmark/src/system_state_observer.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{sync::Arc, time::Duration}; -use sui_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; +use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; use tokio::{ sync::{oneshot::Sender, watch, watch::Receiver}, time, diff --git a/crates/iota-benchmark/src/util.rs b/crates/iota-benchmark/src/util.rs new file mode 100644 index 00000000000..47d89f60392 --- /dev/null +++ b/crates/iota-benchmark/src/util.rs @@ -0,0 +1,74 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{path::PathBuf, sync::Arc}; + +use anyhow::Result; +use iota_keys::keystore::{AccountKeystore, FileBasedKeystore}; +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ + base_types::{IotaAddress, ObjectRef}, + crypto::{AccountKeyPair, IotaKeyPair, KeypairTraits}, + object::Owner, + transaction::{Transaction, TransactionData, TEST_ONLY_GAS_UNIT_FOR_TRANSFER}, + utils::to_sender_signed_transaction, +}; + +use crate::{workloads::Gas, ValidatorProxy}; + +// This is the maximum gas we will transfer from primary coin into any gas coin +// for running the benchmark + +pub type UpdatedAndNewlyMintedGasCoins = Vec; + +pub fn get_ed25519_keypair_from_keystore( + keystore_path: PathBuf, + requested_address: &IotaAddress, +) -> Result { + let keystore = FileBasedKeystore::new(&keystore_path)?; + match keystore.get_key(requested_address) { + Ok(IotaKeyPair::Ed25519(kp)) => Ok(kp.copy()), + other => Err(anyhow::anyhow!("Invalid key type: {:?}", other)), + } +} + +pub fn make_pay_tx( + input_coins: Vec, + sender: IotaAddress, + addresses: Vec, + split_amounts: Vec, + gas: ObjectRef, + keypair: &AccountKeyPair, + gas_price: u64, +) -> Result { + let pay = TransactionData::new_pay( + sender, + input_coins, + addresses, + split_amounts, + gas, + TEST_ONLY_GAS_UNIT_FOR_TRANSFER * gas_price, + gas_price, + )?; + Ok(to_sender_signed_transaction(pay, keypair)) +} + +pub async fn publish_basics_package( + gas: ObjectRef, + proxy: Arc, + sender: IotaAddress, + keypair: &AccountKeyPair, + gas_price: u64, +) -> ObjectRef { + let transaction = TestTransactionBuilder::new(sender, gas, gas_price) + .publish_examples("basics") + .build_and_sign(keypair); + let effects = proxy.execute_transaction_block(transaction).await.unwrap(); + effects + .created() + .iter() + .find(|(_, owner)| matches!(owner, Owner::Immutable)) + .map(|(reference, _)| *reference) + .unwrap() +} diff --git a/crates/sui-benchmark/src/workloads/adversarial.rs b/crates/iota-benchmark/src/workloads/adversarial.rs similarity index 98% rename from crates/sui-benchmark/src/workloads/adversarial.rs rename to crates/iota-benchmark/src/workloads/adversarial.rs index d9a7060b151..bbcf6bfec82 100644 --- a/crates/sui-benchmark/src/workloads/adversarial.rs +++ b/crates/iota-benchmark/src/workloads/adversarial.rs @@ -1,10 +1,21 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{path::PathBuf, str::FromStr, sync::Arc}; use anyhow::anyhow; use async_trait::async_trait; +use iota_protocol_config::ProtocolConfig; +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ + base_types::{random_object_ref, IotaAddress, ObjectID, ObjectRef}, + crypto::get_key_pair, + effects::TransactionEffectsAPI, + object::Owner, + transaction::{CallArg, Command, ObjectArg, Transaction, TransactionData}, + utils::to_sender_signed_transaction, +}; use itertools::Itertools; use move_core_types::identifier::Identifier; use rand::{ @@ -14,16 +25,6 @@ use rand::{ use regex::Regex; use strum::{EnumCount, IntoEnumIterator}; use strum_macros::{EnumCount as EnumCountMacro, EnumIter}; -use sui_protocol_config::ProtocolConfig; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ - base_types::{random_object_ref, ObjectID, ObjectRef, SuiAddress}, - crypto::get_key_pair, - effects::TransactionEffectsAPI, - object::Owner, - transaction::{CallArg, Command, ObjectArg, Transaction, TransactionData}, - utils::to_sender_signed_transaction, -}; use tracing::debug; use super::{ @@ -117,7 +118,7 @@ pub struct AdversarialTestPayload { package_id: ObjectID, df_parent_obj_ref: ObjectRef, /// address to send adversarial transactions from - sender: SuiAddress, + sender: IotaAddress, /// Shared object refs for checking max reads with contention shared_objs: Vec, state: InMemoryWallet, @@ -172,7 +173,7 @@ impl Payload for AdversarialTestPayload { // Sometimes useful when figuring out why things failed let stat = match effects { ExecutionEffects::CertifiedTransactionEffects(e, _) => e.data().status(), - ExecutionEffects::SuiTransactionBlockEffects(_) => unimplemented!("Not impl"), + ExecutionEffects::IotaTransactionBlockEffects(_) => unimplemented!("Not impl"), }; debug_assert!( diff --git a/crates/sui-benchmark/src/workloads/batch_payment.rs b/crates/iota-benchmark/src/workloads/batch_payment.rs similarity index 91% rename from crates/sui-benchmark/src/workloads/batch_payment.rs rename to crates/iota-benchmark/src/workloads/batch_payment.rs index 2b3cf0f19c9..eee99eea106 100644 --- a/crates/sui-benchmark/src/workloads/batch_payment.rs +++ b/crates/iota-benchmark/src/workloads/batch_payment.rs @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, sync::Arc}; use async_trait::async_trait; -use sui_core::test_utils::make_pay_sui_transaction; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress}, +use iota_core::test_utils::make_pay_iota_transaction; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber}, crypto::get_key_pair, digests::ObjectDigest, - gas_coin::MIST_PER_SUI, + gas_coin::MICROS_PER_IOTA, object::Owner, transaction::Transaction, }; @@ -27,12 +28,12 @@ use crate::{ ExecutionEffects, ValidatorProxy, }; -/// Value of each address's "primary coin" in mist. The first transaction gives -/// each address a coin worth PRIMARY_COIN_VALUE, and all subsequent transfers -/// send TRANSFER_AMOUNT coins each time -const PRIMARY_COIN_VALUE: u64 = 100 * MIST_PER_SUI; +/// Value of each address's "primary coin" in micros. The first transaction +/// gives each address a coin worth PRIMARY_COIN_VALUE, and all subsequent +/// transfers send TRANSFER_AMOUNT coins each time +const PRIMARY_COIN_VALUE: u64 = 100 * MICROS_PER_IOTA; -/// Number of mist sent to each address on each batch transfer +/// Number of micros sent to each address on each batch transfer const BATCH_TRANSFER_AMOUNT: u64 = 1; const DUMMY_GAS: ObjectRef = (ObjectID::ZERO, SequenceNumber::MIN, ObjectDigest::MIN); @@ -44,7 +45,7 @@ pub struct BatchPaymentTestPayload { num_payments: usize, /// address of the first sender. important because in the beginning, only /// one address has any coins. after the first tx, any address can send - first_sender: SuiAddress, + first_sender: IotaAddress, system_state_observer: Arc, } @@ -75,7 +76,11 @@ impl Payload for BatchPaymentTestPayload { } fn make_transaction(&mut self) -> Transaction { - let addrs = self.state.addresses().cloned().collect::>(); + let addrs = self + .state + .addresses() + .cloned() + .collect::>(); let num_recipients = addrs.len(); let sender = if self.num_payments == 0 { // first tx--use the address that has gas @@ -106,7 +111,7 @@ impl Payload for BatchPaymentTestPayload { let coins = Vec::new(); // create a sender -> all transfer, using all of the sender's coins // TODO: use a larger amount, fewer input coins? - make_pay_sui_transaction( + make_pay_iota_transaction( *gas_obj, coins, addrs, @@ -224,7 +229,7 @@ impl Workload for BatchPaymentWorkload { _proxy: Arc, system_state_observer: Arc, ) -> Vec> { - let mut gas_by_address: HashMap> = HashMap::new(); + let mut gas_by_address: HashMap> = HashMap::new(); debug!( "Making test payloads with {} payload gas...", self.payload_gas.len() diff --git a/crates/iota-benchmark/src/workloads/data/adversarial/Move.toml b/crates/iota-benchmark/src/workloads/data/adversarial/Move.toml new file mode 100644 index 00000000000..90e0da91efe --- /dev/null +++ b/crates/iota-benchmark/src/workloads/data/adversarial/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "adversarial" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +adversarial = "0x0" +iota = "0000000000000000000000000000000000000000000000000000000000000002" diff --git a/crates/sui-benchmark/src/workloads/data/adversarial/sources/adversarial.move b/crates/iota-benchmark/src/workloads/data/adversarial/sources/adversarial.move similarity index 99% rename from crates/sui-benchmark/src/workloads/data/adversarial/sources/adversarial.move rename to crates/iota-benchmark/src/workloads/data/adversarial/sources/adversarial.move index 92c25143ac3..b4d0d810abb 100644 --- a/crates/sui-benchmark/src/workloads/data/adversarial/sources/adversarial.move +++ b/crates/iota-benchmark/src/workloads/data/adversarial/sources/adversarial.move @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module adversarial::adversarial { use std::vector; - use sui::bcs; - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer; - use sui::event; - use sui::dynamic_field::{add, borrow}; + use iota::bcs; + use iota::object::{Self, UID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer; + use iota::event; + use iota::dynamic_field::{add, borrow}; use std::string::Self; use std::ascii; diff --git a/crates/iota-benchmark/src/workloads/data/max_package/Move.toml b/crates/iota-benchmark/src/workloads/data/max_package/Move.toml new file mode 100644 index 00000000000..68659c52998 --- /dev/null +++ b/crates/iota-benchmark/src/workloads/data/max_package/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "max_package" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +max_package = "0x0" +iota = "0000000000000000000000000000000000000000000000000000000000000002" diff --git a/crates/sui-benchmark/src/workloads/data/max_package/sources/max_package.move b/crates/iota-benchmark/src/workloads/data/max_package/sources/max_package.move similarity index 99% rename from crates/sui-benchmark/src/workloads/data/max_package/sources/max_package.move rename to crates/iota-benchmark/src/workloads/data/max_package/sources/max_package.move index 6acb7e88d4f..671f465312c 100644 --- a/crates/sui-benchmark/src/workloads/data/max_package/sources/max_package.move +++ b/crates/iota-benchmark/src/workloads/data/max_package/sources/max_package.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // This creates the largest package possible in Move. It is used to test the limits of the TX size limits logic diff --git a/crates/sui-benchmark/src/workloads/delegation.rs b/crates/iota-benchmark/src/workloads/delegation.rs similarity index 93% rename from crates/sui-benchmark/src/workloads/delegation.rs rename to crates/iota-benchmark/src/workloads/delegation.rs index 4f16782c327..a47ffa23117 100644 --- a/crates/sui-benchmark/src/workloads/delegation.rs +++ b/crates/iota-benchmark/src/workloads/delegation.rs @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; use async_trait::async_trait; -use rand::seq::IteratorRandom; -use sui_core::test_utils::make_transfer_sui_transaction; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ - base_types::{ObjectRef, SuiAddress}, +use iota_core::test_utils::make_transfer_iota_transaction; +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ + base_types::{IotaAddress, ObjectRef}, crypto::{get_key_pair, AccountKeyPair}, - gas_coin::MIST_PER_SUI, + gas_coin::MICROS_PER_IOTA, transaction::Transaction, }; +use rand::seq::IteratorRandom; use tracing::error; use crate::{ @@ -33,8 +34,8 @@ use crate::{ pub struct DelegationTestPayload { coin: Option, gas: ObjectRef, - validator: SuiAddress, - sender: SuiAddress, + validator: IotaAddress, + sender: IotaAddress, keypair: Arc, system_state_observer: Arc, } @@ -75,10 +76,10 @@ impl Payload for DelegationTestPayload { ) .call_staking(coin, self.validator) .build_and_sign(self.keypair.as_ref()), - None => make_transfer_sui_transaction( + None => make_transfer_iota_transaction( self.gas, self.sender, - Some(MIST_PER_SUI), + Some(MICROS_PER_IOTA), self.sender, &self.keypair, self.system_state_observer diff --git a/crates/iota-benchmark/src/workloads/mod.rs b/crates/iota-benchmark/src/workloads/mod.rs new file mode 100644 index 00000000000..b21e3dfa805 --- /dev/null +++ b/crates/iota-benchmark/src/workloads/mod.rs @@ -0,0 +1,58 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod adversarial; +pub mod batch_payment; +pub mod delegation; +pub mod payload; +pub mod shared_counter; +pub mod shared_object_deletion; +pub mod transfer_object; +pub mod workload; +pub mod workload_configuration; + +use std::sync::Arc; + +use iota_types::{ + base_types::{IotaAddress, ObjectRef}, + crypto::AccountKeyPair, +}; +use workload::*; + +use crate::{drivers::Interval, workloads::payload::Payload}; + +pub type GroupID = u32; + +#[derive(Debug, Clone)] +pub struct WorkloadParams { + pub group: GroupID, + pub target_qps: u64, + pub num_workers: u64, + pub max_ops: u64, + pub duration: Interval, +} + +#[derive(Debug)] +pub struct WorkloadBuilderInfo { + pub workload_params: WorkloadParams, + pub workload_builder: Box>, +} + +#[derive(Debug)] +pub struct WorkloadInfo { + pub workload_params: WorkloadParams, + pub workload: Box>, +} + +pub type Gas = (ObjectRef, IotaAddress, Arc); + +#[derive(Clone)] +pub struct GasCoinConfig { + // amount of IOTA to transfer to this gas coin + pub amount: u64, + // recipient of this gas coin + pub address: IotaAddress, + // recipient account key pair (useful for signing txns) + pub keypair: Arc, +} diff --git a/crates/sui-benchmark/src/workloads/payload.rs b/crates/iota-benchmark/src/workloads/payload.rs similarity index 87% rename from crates/sui-benchmark/src/workloads/payload.rs rename to crates/iota-benchmark/src/workloads/payload.rs index 5ff54638ab8..f60b350b7d4 100644 --- a/crates/sui-benchmark/src/workloads/payload.rs +++ b/crates/iota-benchmark/src/workloads/payload.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::fmt::Display; -use sui_types::transaction::Transaction; +use iota_types::transaction::Transaction; use crate::ExecutionEffects; diff --git a/crates/sui-benchmark/src/workloads/shared_counter.rs b/crates/iota-benchmark/src/workloads/shared_counter.rs similarity index 98% rename from crates/sui-benchmark/src/workloads/shared_counter.rs rename to crates/iota-benchmark/src/workloads/shared_counter.rs index ceea911f817..d03fcfe738c 100644 --- a/crates/sui-benchmark/src/workloads/shared_counter.rs +++ b/crates/iota-benchmark/src/workloads/shared_counter.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; use async_trait::async_trait; use futures::future::join_all; -use rand::{seq::SliceRandom, Rng}; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ base_types::{ObjectDigest, ObjectID, SequenceNumber}, crypto::get_key_pair, transaction::Transaction, }; +use rand::{seq::SliceRandom, Rng}; use tracing::{debug, error, info}; use crate::{ diff --git a/crates/sui-benchmark/src/workloads/shared_object_deletion.rs b/crates/iota-benchmark/src/workloads/shared_object_deletion.rs similarity index 98% rename from crates/sui-benchmark/src/workloads/shared_object_deletion.rs rename to crates/iota-benchmark/src/workloads/shared_object_deletion.rs index 1913a958c80..a44291686a5 100644 --- a/crates/sui-benchmark/src/workloads/shared_object_deletion.rs +++ b/crates/iota-benchmark/src/workloads/shared_object_deletion.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; use async_trait::async_trait; use futures::future::join_all; -use rand::{seq::SliceRandom, Rng}; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ base_types::{ObjectDigest, ObjectID, SequenceNumber}, crypto::get_key_pair, transaction::Transaction, }; +use rand::{seq::SliceRandom, Rng}; use tracing::{debug, error, info}; use crate::{ diff --git a/crates/sui-benchmark/src/workloads/transfer_object.rs b/crates/iota-benchmark/src/workloads/transfer_object.rs similarity index 94% rename from crates/sui-benchmark/src/workloads/transfer_object.rs rename to crates/iota-benchmark/src/workloads/transfer_object.rs index 47d32c97fc1..a70aa879371 100644 --- a/crates/sui-benchmark/src/workloads/transfer_object.rs +++ b/crates/iota-benchmark/src/workloads/transfer_object.rs @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, sync::Arc}; use async_trait::async_trait; -use rand::seq::IteratorRandom; -use sui_core::test_utils::make_transfer_object_transaction; -use sui_types::{ - base_types::{ObjectRef, SuiAddress}, +use iota_core::test_utils::make_transfer_object_transaction; +use iota_types::{ + base_types::{IotaAddress, ObjectRef}, crypto::{get_key_pair, AccountKeyPair}, transaction::Transaction, }; +use rand::seq::IteratorRandom; use tracing::error; use crate::{ @@ -28,14 +29,14 @@ use crate::{ }; /// TODO: This should be the amount that is being transferred instead of -/// MAX_GAS. Number of mist sent to each address on each batch transfer +/// MAX_GAS. Number of micros sent to each address on each batch transfer const _TRANSFER_AMOUNT: u64 = 1; #[derive(Debug)] pub struct TransferObjectTestPayload { transfer_object: ObjectRef, - transfer_from: SuiAddress, - transfer_to: SuiAddress, + transfer_from: IotaAddress, + transfer_to: IotaAddress, gas: Vec, system_state_observer: Arc, } @@ -211,7 +212,7 @@ impl Workload for TransferObjectWorkload { system_state_observer: Arc, ) -> Vec> { let (transfer_tokens, payload_gas) = self.payload_gas.split_at(self.num_tokens as usize); - let mut gas_by_address: HashMap> = HashMap::new(); + let mut gas_by_address: HashMap> = HashMap::new(); for gas in payload_gas.iter() { gas_by_address .entry(gas.1) @@ -219,7 +220,7 @@ impl Workload for TransferObjectWorkload { .push(gas.clone()); } - let addresses: Vec = gas_by_address.keys().cloned().collect(); + let addresses: Vec = gas_by_address.keys().cloned().collect(); let mut transfer_gas: Vec> = vec![]; for i in 0..self.num_tokens { let mut account_transfer_gas = vec![]; diff --git a/crates/iota-benchmark/src/workloads/workload.rs b/crates/iota-benchmark/src/workloads/workload.rs new file mode 100644 index 00000000000..c87b5137004 --- /dev/null +++ b/crates/iota-benchmark/src/workloads/workload.rs @@ -0,0 +1,59 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::Arc; + +use async_trait::async_trait; +use iota_types::gas_coin::MICROS_PER_IOTA; + +use crate::{ + system_state_observer::SystemStateObserver, + workloads::{payload::Payload, Gas, GasCoinConfig}, + ValidatorProxy, +}; + +// This is the maximum gas we will transfer from primary coin into any gas coin +// for running the benchmark +pub const MAX_GAS_FOR_TESTING: u64 = 1_000 * MICROS_PER_IOTA; + +// TODO: get this information from protocol config +// This is the maximum budget that can be set for a transaction. 50 IOTA. +pub const MAX_BUDGET: u64 = 50 * MICROS_PER_IOTA; +// (COIN_BYTES_SIZE * STORAGE_PRICE * STORAGE_UNITS_PER_BYTE) +pub const STORAGE_COST_PER_COIN: u64 = 130 * 76 * 100; +// (COUNTER_BYTES_SIZE * STORAGE_PRICE * STORAGE_UNITS_PER_BYTE) +pub const STORAGE_COST_PER_COUNTER: u64 = 341 * 76 * 100; +/// Used to estimate the budget required for each transaction. +pub const ESTIMATED_COMPUTATION_COST: u64 = 1_000_000; + +#[async_trait] +pub trait WorkloadBuilder: Send + Sync + std::fmt::Debug { + async fn generate_coin_config_for_init(&self) -> Vec; + async fn generate_coin_config_for_payloads(&self) -> Vec; + async fn build(&self, init_gas: Vec, payload_gas: Vec) -> Box>; +} + +/// A Workload is used to generate multiple payloads during setup phase with +/// `make_test_payloads()` which are added to a local queue. We execute +/// transactions (the queue is drained based on the target qps i.e. for 100 tps, +/// the queue will be popped 100 times every second) with those payloads +/// and generate new payloads (which are enqueued back to the queue) with the +/// returned effects. The total number of payloads to generate depends on how +/// much transaction throughput we want and the maximum number of transactions +/// we want to have in flight. For instance, for a 100 target_qps and +/// in_flight_ratio of 5, a maximum of 500 transactions is expected to be in +/// flight and that many payloads are created. +#[async_trait] +pub trait Workload: Send + Sync + std::fmt::Debug { + async fn init( + &mut self, + proxy: Arc, + system_state_observer: Arc, + ); + async fn make_test_payloads( + &self, + proxy: Arc, + system_state_observer: Arc, + ) -> Vec>; +} diff --git a/crates/sui-benchmark/src/workloads/workload_configuration.rs b/crates/iota-benchmark/src/workloads/workload_configuration.rs similarity index 99% rename from crates/sui-benchmark/src/workloads/workload_configuration.rs rename to crates/iota-benchmark/src/workloads/workload_configuration.rs index 73e77bad22b..f620c907868 100644 --- a/crates/sui-benchmark/src/workloads/workload_configuration.rs +++ b/crates/iota-benchmark/src/workloads/workload_configuration.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, str::FromStr, sync::Arc}; diff --git a/crates/iota-benchmark/tests/data/deepbook_client/Move.toml b/crates/iota-benchmark/tests/data/deepbook_client/Move.toml new file mode 100644 index 00000000000..5629e231569 --- /dev/null +++ b/crates/iota-benchmark/tests/data/deepbook_client/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "deepbook_client" +version = "0.0.1" + +[dependencies] +DeepBook = { local = "../../../../iota-framework/packages/deepbook" } + +[addresses] +deepbook_client = "0x0" diff --git a/crates/sui-benchmark/tests/data/deepbook_client/sources/deepbook_client.move b/crates/iota-benchmark/tests/data/deepbook_client/sources/deepbook_client.move similarity index 80% rename from crates/sui-benchmark/tests/data/deepbook_client/sources/deepbook_client.move rename to crates/iota-benchmark/tests/data/deepbook_client/sources/deepbook_client.move index 5b122fec50a..02e33f28ce9 100644 --- a/crates/sui-benchmark/tests/data/deepbook_client/sources/deepbook_client.move +++ b/crates/iota-benchmark/tests/data/deepbook_client/sources/deepbook_client.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module deepbook_client::deepbook_client { diff --git a/crates/sui-benchmark/tests/simtest.rs b/crates/iota-benchmark/tests/simtest.rs similarity index 92% rename from crates/sui-benchmark/tests/simtest.rs rename to crates/iota-benchmark/tests/simtest.rs index 4ed3cceabf4..6ea42019989 100644 --- a/crates/sui-benchmark/tests/simtest.rs +++ b/crates/iota-benchmark/tests/simtest.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[cfg(msim)] @@ -14,8 +15,7 @@ mod test { time::{Duration, Instant}, }; - use rand::{distributions::uniform::SampleRange, thread_rng, Rng}; - use sui_benchmark::{ + use iota_benchmark::{ bank::BenchmarkBank, drivers::{bench_driver::BenchDriver, driver::Driver, Interval}, system_state_observer::SystemStateObserver, @@ -25,32 +25,33 @@ mod test { }, LocalValidatorAggregatorProxy, ValidatorProxy, }; - use sui_config::{genesis::Genesis, AUTHORITIES_DB_NAME, SUI_KEYSTORE_FILENAME}; - use sui_core::{ + use iota_config::{genesis::Genesis, AUTHORITIES_DB_NAME, IOTA_KEYSTORE_FILENAME}; + use iota_core::{ authority::{ authority_store_tables::AuthorityPerpetualTables, framework_injection, AuthorityState, }, checkpoints::{CheckpointStore, CheckpointWatermark}, }; - use sui_framework::BuiltInFramework; - use sui_macros::{ + use iota_framework::BuiltInFramework; + use iota_macros::{ clear_fail_point, nondeterministic, register_fail_point_async, register_fail_point_if, register_fail_points, sim_test, }; - use sui_protocol_config::{ProtocolVersion, SupportedProtocolVersions}; - use sui_simulator::{configs::*, tempfile::TempDir, SimConfig}; - use sui_storage::blob::Blob; - use sui_types::{ - base_types::{ObjectRef, SuiAddress}, + use iota_protocol_config::{ProtocolVersion, SupportedProtocolVersions}; + use iota_simulator::{configs::*, tempfile::TempDir, SimConfig}; + use iota_storage::blob::Blob; + use iota_types::{ + base_types::{IotaAddress, ObjectRef}, full_checkpoint_content::CheckpointData, messages_checkpoint::VerifiedCheckpoint, }; + use rand::{distributions::uniform::SampleRange, thread_rng, Rng}; use test_cluster::{TestCluster, TestClusterBuilder}; use tracing::{error, info}; use typed_store::traits::Map; struct DeadValidator { - node_id: sui_simulator::task::NodeId, + node_id: iota_simulator::task::NodeId, dead_until: std::time::Instant, } @@ -82,14 +83,14 @@ mod test { #[sim_test(config = "test_config()")] async fn test_simulated_load_with_reconfig() { - sui_protocol_config::ProtocolConfig::poison_get_for_min_version(); + iota_protocol_config::ProtocolConfig::poison_get_for_min_version(); let test_cluster = build_test_cluster(4, 1000).await; test_simulated_load(TestInitData::new(&test_cluster).await, 60).await; } #[sim_test(config = "test_config()")] async fn test_simulated_load_with_reconfig_and_correlated_crashes() { - sui_protocol_config::ProtocolConfig::poison_get_for_min_version(); + iota_protocol_config::ProtocolConfig::poison_get_for_min_version(); register_fail_point_if("correlated-crash-after-consensus-commit-boundary", || true); // TODO: enable this - right now it causes rocksdb errors when re-opening DBs @@ -101,14 +102,14 @@ mod test { #[sim_test(config = "test_config()")] async fn test_simulated_load_basic() { - sui_protocol_config::ProtocolConfig::poison_get_for_min_version(); + iota_protocol_config::ProtocolConfig::poison_get_for_min_version(); let test_cluster = build_test_cluster(7, 0).await; test_simulated_load(TestInitData::new(&test_cluster).await, 15).await; } #[sim_test(config = "test_config()")] async fn test_simulated_load_restarts() { - sui_protocol_config::ProtocolConfig::poison_get_for_min_version(); + iota_protocol_config::ProtocolConfig::poison_get_for_min_version(); let test_cluster = Arc::new(build_test_cluster(4, 0).await); let node_restarter = test_cluster .random_node_restarter() @@ -123,7 +124,7 @@ mod test { async fn test_simulated_load_reconfig_restarts() { // TODO added to invalidate a failing test seed in CI. Remove me tokio::time::sleep(Duration::from_secs(1)).await; - sui_protocol_config::ProtocolConfig::poison_get_for_min_version(); + iota_protocol_config::ProtocolConfig::poison_get_for_min_version(); let test_cluster = Arc::new(build_test_cluster(4, 1000).await); let node_restarter = test_cluster .random_node_restarter() @@ -137,7 +138,7 @@ mod test { /// tests. This includes the client node which is the node that is /// running the test, as well as rpc fullnode which are needed to run /// the benchmark. - fn get_keep_alive_nodes(cluster: &TestCluster) -> HashSet { + fn get_keep_alive_nodes(cluster: &TestCluster) -> HashSet { let mut keep_alive_nodes = HashSet::new(); // The first fullnode in the swarm ins the rpc fullnode. keep_alive_nodes.insert( @@ -150,17 +151,17 @@ mod test { .unwrap() .with(|n| n.get_sim_node_id()), ); - keep_alive_nodes.insert(sui_simulator::current_simnode_id()); + keep_alive_nodes.insert(iota_simulator::current_simnode_id()); keep_alive_nodes } fn handle_failpoint( dead_validator: Arc>>, - keep_alive_nodes: HashSet, + keep_alive_nodes: HashSet, probability: f64, ) { let mut dead_validator = dead_validator.lock().unwrap(); - let cur_node = sui_simulator::current_simnode_id(); + let cur_node = iota_simulator::current_simnode_id(); if keep_alive_nodes.contains(&cur_node) { return; @@ -188,7 +189,7 @@ mod test { // and would poison the lock. drop(dead_validator); - sui_simulator::task::kill_current_node(Some(restart_after)); + iota_simulator::task::kill_current_node(Some(restart_after)); } } @@ -225,10 +226,10 @@ mod test { // Tests load with aggressive pruning and compaction. #[sim_test(config = "test_config()")] async fn test_simulated_load_reconfig_with_prune_and_compact() { - sui_protocol_config::ProtocolConfig::poison_get_for_min_version(); + iota_protocol_config::ProtocolConfig::poison_get_for_min_version(); let test_cluster = build_test_cluster(4, 1000).await; - let node_state = test_cluster.fullnode_handle.sui_node.clone().state(); + let node_state = test_cluster.fullnode_handle.iota_node.clone().state(); register_fail_point_async("prune-and-compact", move || { handle_failpoint_prune_and_compact(node_state.clone(), 0.5) }); @@ -241,7 +242,7 @@ mod test { #[sim_test(config = "test_config()")] async fn test_simulated_load_reconfig_with_crashes_and_delays() { - sui_protocol_config::ProtocolConfig::poison_get_for_min_version(); + iota_protocol_config::ProtocolConfig::poison_get_for_min_version(); let test_cluster = build_test_cluster(4, 1000).await; let dead_validator_orig: Arc>> = Default::default(); @@ -299,7 +300,7 @@ mod test { #[sim_test(config = "test_config()")] async fn test_simulated_load_reconfig_crashes_during_epoch_change() { - sui_protocol_config::ProtocolConfig::poison_get_for_min_version(); + iota_protocol_config::ProtocolConfig::poison_get_for_min_version(); let test_cluster = build_test_cluster(4, 10000).await; let dead_validator: Arc>> = Default::default(); @@ -406,14 +407,14 @@ mod test { async fn test_protocol_upgrade_compatibility_impl() { let max_ver = ProtocolVersion::MAX.as_u64(); - let manifest = sui_framework_snapshot::load_bytecode_snapshot_manifest(); + let manifest = iota_framework_snapshot::load_bytecode_snapshot_manifest(); let Some((&starting_version, _)) = manifest.range(..max_ver).last() else { panic!("Couldn't find previously supported version"); }; let init_framework = - sui_framework_snapshot::load_bytecode_snapshot(starting_version).unwrap(); + iota_framework_snapshot::load_bytecode_snapshot(starting_version).unwrap(); let mut test_cluster = init_test_cluster_builder(7, 5000) .with_protocol_version(ProtocolVersion::new(starting_version)) .with_supported_protocol_versions(SupportedProtocolVersions::new_for_testing( @@ -445,7 +446,7 @@ mod test { break; } let next_version = version + 1; - let new_framework = sui_framework_snapshot::load_bytecode_snapshot(next_version); + let new_framework = iota_framework_snapshot::load_bytecode_snapshot(next_version); let new_framework_ref = match &new_framework { Ok(f) => Some(f.iter().collect::>()), Err(_) => { @@ -521,14 +522,14 @@ mod test { keystore_path: PathBuf, genesis: Genesis, pub primary_gas: ObjectRef, - pub sender: SuiAddress, + pub sender: IotaAddress, } impl TestInitData { pub async fn new(test_cluster: &TestCluster) -> Self { let sender = test_cluster.get_address_0(); Self { - keystore_path: test_cluster.swarm.dir().join(SUI_KEYSTORE_FILENAME), + keystore_path: test_cluster.swarm.dir().join(IOTA_KEYSTORE_FILENAME), genesis: test_cluster.swarm.config().genesis.clone(), primary_gas: test_cluster .wallet diff --git a/crates/iota-bridge/Cargo.toml b/crates/iota-bridge/Cargo.toml new file mode 100644 index 00000000000..bb6ded02beb --- /dev/null +++ b/crates/iota-bridge/Cargo.toml @@ -0,0 +1,62 @@ +[package] +name = "iota-bridge" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +ethers = "2.0" +tokio = { workspace = true, features = ["full"] } +iota-types.workspace = true +iota-common.workspace = true +arc-swap.workspace = true +num_enum.workspace = true +move-core-types.workspace = true +url.workspace = true +futures.workspace = true +once_cell.workspace = true +telemetry-subscribers.workspace = true +prometheus.workspace = true +async-trait.workspace = true +typed-store-derive.workspace = true +rocksdb.workspace = true +typed-store.workspace = true +mysten-metrics.workspace = true +iota-sdk.workspace = true +iota-config.workspace = true +clap.workspace = true +tracing.workspace = true +git-version.workspace = true +const-str.workspace = true +bcs.workspace = true +iota-json-rpc-types.workspace = true +serde.workspace = true +serde_with.workspace = true +serde_json.workspace = true +eyre.workspace = true +tempfile.workspace = true +axum.workspace = true +anyhow.workspace = true +reqwest.workspace = true +fastcrypto.workspace = true +tap.workspace = true +rand.workspace = true +lru.workspace = true +shared-crypto.workspace = true +backoff = { version = "0.4.0", features = [ + "futures", +] } + +[dev-dependencies] +iota-types = { workspace = true, features = ["test-utils"] } +iota-json-rpc-types = { workspace = true, features = ["test-utils"] } +iota-config.workspace = true +iota-test-transaction-builder.workspace = true +test-cluster.workspace = true +hex-literal = "0.3.4" + +[[bin]] +name = "iota-bridge-cli" +path = "src/tools/cli.rs" diff --git a/crates/sui-bridge/abi/bridge_committee.json b/crates/iota-bridge/abi/bridge_committee.json similarity index 100% rename from crates/sui-bridge/abi/bridge_committee.json rename to crates/iota-bridge/abi/bridge_committee.json diff --git a/crates/sui-bridge/abi/bridge_vault.json b/crates/iota-bridge/abi/bridge_vault.json similarity index 100% rename from crates/sui-bridge/abi/bridge_vault.json rename to crates/iota-bridge/abi/bridge_vault.json diff --git a/crates/iota-bridge/abi/iota_bridge.json b/crates/iota-bridge/abi/iota_bridge.json new file mode 100644 index 00000000000..253e8c90d67 --- /dev/null +++ b/crates/iota-bridge/abi/iota_bridge.json @@ -0,0 +1,644 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint8", + "name": "sourceChainId", + "type": "uint8" + }, + { + "indexed": true, + "internalType": "uint64", + "name": "nonce", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "uint8", + "name": "destinationChainId", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "tokenCode", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "iotaAdjustedAmount", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "address", + "name": "sourceAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "targetAddress", + "type": "bytes" + } + ], + "name": "TokensBridgedToIota", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "inputs": [], + "name": "BRIDGE_UPGRADE_STAKE_REQUIRED", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "FREEZING_STAKE_REQUIRED", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TRANSFER_STAKE_REQUIRED", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UNFREEZING_STAKE_REQUIRED", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "tokenId", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "originalAmount", + "type": "uint64" + }, + { + "internalType": "uint8", + "name": "ethDecimal", + "type": "uint8" + } + ], + "name": "adjustDecimalsForErc20", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "tokenId", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "originalAmount", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "ethDecimal", + "type": "uint8" + } + ], + "name": "adjustDecimalsForIotaToken", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "targetAddress", + "type": "bytes" + }, + { + "internalType": "uint8", + "name": "destinationChainId", + "type": "uint8" + } + ], + "name": "bridgeETHToIota", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "tokenId", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "targetAddress", + "type": "bytes" + }, + { + "internalType": "uint8", + "name": "destinationChainId", + "type": "uint8" + } + ], + "name": "bridgeToIota", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "chainId", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "committee", + "outputs": [ + { + "internalType": "contract IBridgeCommittee", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "signatures", + "type": "bytes[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "messageType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "nonce", + "type": "uint64" + }, + { + "internalType": "uint8", + "name": "chainID", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "payload", + "type": "bytes" + } + ], + "internalType": "struct Messages.Message", + "name": "message", + "type": "tuple" + } + ], + "name": "executeEmergencyOpWithSignatures", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_supportedTokens", + "type": "address[]" + }, + { + "internalType": "address", + "name": "_committee", + "type": "address" + }, + { + "internalType": "address", + "name": "_vault", + "type": "address" + }, + { + "internalType": "address", + "name": "_weth9", + "type": "address" + }, + { + "internalType": "uint8", + "name": "_chainId", + "type": "uint8" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "name": "messageProcessed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "name": "requiredApprovalStake", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "name": "supportedTokens", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "signatures", + "type": "bytes[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "messageType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "nonce", + "type": "uint64" + }, + { + "internalType": "uint8", + "name": "chainID", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "payload", + "type": "bytes" + } + ], + "internalType": "struct Messages.Message", + "name": "message", + "type": "tuple" + } + ], + "name": "transferTokensWithSignatures", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "signatures", + "type": "bytes[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "messageType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "nonce", + "type": "uint64" + }, + { + "internalType": "uint8", + "name": "chainID", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "payload", + "type": "bytes" + } + ], + "internalType": "struct Messages.Message", + "name": "message", + "type": "tuple" + } + ], + "name": "upgradeBridgeWithSignatures", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "vault", + "outputs": [ + { + "internalType": "contract IBridgeVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "weth9", + "outputs": [ + { + "internalType": "contract IWETH9", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/crates/iota-bridge/build.rs b/crates/iota-bridge/build.rs new file mode 100644 index 00000000000..1aea7f748e5 --- /dev/null +++ b/crates/iota-bridge/build.rs @@ -0,0 +1,119 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + fs, + path::{Path, PathBuf}, + process::{exit, Command, ExitStatus}, +}; + +fn main() -> Result<(), ExitStatus> { + #[cfg(windows)] + { + eprintln!("bridge tests are not supported on Windows."); + return Ok(()); + } + + println!("cargo:rerun-if-changed=build.rs"); + let base = env!("CARGO_MANIFEST_DIR"); + let bridge_path = format!("{base}/../../bridge/evm"); + let bridge_lib_path = format!("{base}/../../bridge/evm/lib"); + let mut forge_path = "forge".to_owned(); + // Check if Forge is installed + let forge_installed = Command::new("which") + .arg("forge") + .output() + .map(|output| output.status.success()) + .unwrap_or(false); + if !forge_installed { + eprintln!("Installing forge"); + // Also print the path where foundryup is installed + let install_cmd = "curl -L https://foundry.paradigm.xyz | { cat; echo 'echo foundryup-path=\"$FOUNDRY_BIN_DIR/foundryup\"'; } | bash"; + + let output = Command::new("sh") + .arg("-c") + .arg(install_cmd) + .output() + .expect("Failed to install Forge"); + + // extract foundryup path + let output_str = String::from_utf8_lossy(&output.stdout); + let mut foundryup_path = None; + for line in output_str.lines() { + if line.starts_with("foundryup-path=") { + foundryup_path = Some(line.trim_start_matches("foundryup-path=")); + break; + } + } + if foundryup_path.is_none() { + eprintln!("Error installing forge: expect a foundry path in output"); + exit(1); + } + let foundryup_path = foundryup_path.unwrap(); + eprintln!("foundryup path: {foundryup_path}"); + // Run foundryup + let output = Command::new(foundryup_path) + .output() + .expect("Failed to run foundryup"); + + if !output.status.success() { + eprintln!("Error running foundryup: {:?}", output); + exit(1); + } + // Update forge path + let mut forge = PathBuf::from(foundryup_path); + forge.pop(); + forge.push("forge"); + forge_path = forge.to_str().unwrap().to_owned(); + } + + // check if should install dependencies + if should_install_dependencies(&bridge_lib_path) { + // Run Foundry CLI command to install dependencies + Command::new(forge_path) + .current_dir(bridge_path) + .arg("install") + .arg("https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable@v5.0.1") + .arg("https://github.com/foundry-rs/forge-std@v1.3.0") + .arg("https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades") + .arg("--no-git") + .arg("--no-commit") + .status() + .expect("Failed to execute Foundry CLI command"); + } + + Ok(()) +} + +fn should_install_dependencies(dir_path: &str) -> bool { + let dependencies = vec![ + "forge-std", + "openzeppelin-contracts-upgradeable", + "openzeppelin-foundry-upgrades", + ]; + let mut missing_dependencies = false; + for d in &dependencies { + let path = format!("{}/{}", dir_path, d); + let path = Path::new(&path); + if !path.exists() { + missing_dependencies = true; + break; + } + } + // found all dependencies, no need to install + if !missing_dependencies { + return false; + } + // if any dependencies are missing, recreate an empty directory and then + // reinstall + eprintln!( + "cargo:warning={:?} does not have all the dependnecies, re-creating", + dir_path + ); + if Path::new(&dir_path).exists() { + fs::remove_dir_all(dir_path).unwrap(); + } + fs::create_dir_all(dir_path).expect("Failed to create directory"); + true +} diff --git a/crates/iota-bridge/src/abi.rs b/crates/iota-bridge/src/abi.rs new file mode 100644 index 00000000000..56e37d232a6 --- /dev/null +++ b/crates/iota-bridge/src/abi.rs @@ -0,0 +1,114 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use ethers::{ + abi::RawLog, + contract::{abigen, EthLogDecode}, + types::Address as EthAddress, +}; +use iota_types::base_types::IotaAddress; +use serde::{Deserialize, Serialize}; + +use crate::{ + error::{BridgeError, BridgeResult}, + types::{BridgeAction, BridgeChainId, EthLog, EthToIotaBridgeAction, TokenId}, +}; + +// TODO: write a macro to handle variants + +// TODO: Add other events +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum EthBridgeEvent { + EthIotaBridgeEvents(EthIotaBridgeEvents), +} + +abigen!( + EthIotaBridge, + "abi/iota_bridge.json", + event_derives(serde::Deserialize, serde::Serialize) +); + +impl EthBridgeEvent { + pub fn try_from_eth_log(log: &EthLog) -> Option { + let raw_log = RawLog { + topics: log.log.topics.clone(), + data: log.log.data.to_vec(), + }; + + if let Ok(decoded) = EthIotaBridgeEvents::decode_log(&raw_log) { + return Some(EthBridgeEvent::EthIotaBridgeEvents(decoded)); + } + + // TODO: try other variants + None + } +} + +impl EthBridgeEvent { + pub fn try_into_bridge_action( + self, + eth_tx_hash: ethers::types::H256, + eth_event_index: u16, + ) -> Option { + match self { + EthBridgeEvent::EthIotaBridgeEvents(event) => { + match event { + EthIotaBridgeEvents::TokensBridgedToIotaFilter(event) => { + let bridge_event = match EthToIotaTokenBridgeV1::try_from(&event) { + Ok(bridge_event) => bridge_event, + // This only happens when solidity code does not align with rust code. + // When this happens in production, there is a risk of stuck bridge + // transfers. We log error here. + // TODO: add metrics and alert + Err(e) => { + tracing::error!( + ?eth_tx_hash, + eth_event_index, + "Failed to convert TokensBridgedToIota log to EthToIotaTokenBridgeV1. This indicates incorrect parameters or a bug in the code: {:?}. Err: {:?}", + event, + e + ); + return None; + } + }; + + Some(BridgeAction::EthToIotaBridgeAction(EthToIotaBridgeAction { + eth_tx_hash, + eth_event_index, + eth_bridge_event: bridge_event, + })) + } + _ => None, + } + } + } + } +} + +// Sanity checked version of TokensBridgedToIotaFilter +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Hash)] +pub struct EthToIotaTokenBridgeV1 { + pub nonce: u64, + pub iota_chain_id: BridgeChainId, + pub eth_chain_id: BridgeChainId, + pub iota_address: IotaAddress, + pub eth_address: EthAddress, + pub token_id: TokenId, + pub amount: u64, +} + +impl TryFrom<&TokensBridgedToIotaFilter> for EthToIotaTokenBridgeV1 { + type Error = BridgeError; + fn try_from(event: &TokensBridgedToIotaFilter) -> BridgeResult { + Ok(Self { + nonce: event.nonce, + iota_chain_id: BridgeChainId::try_from(event.destination_chain_id)?, + eth_chain_id: BridgeChainId::try_from(event.source_chain_id)?, + iota_address: IotaAddress::from_bytes(event.target_address.as_ref())?, + eth_address: event.source_address, + token_id: TokenId::try_from(event.token_code)?, + amount: event.iota_adjusted_amount, + }) + } +} diff --git a/crates/sui-bridge/src/action_executor.rs b/crates/iota-bridge/src/action_executor.rs similarity index 81% rename from crates/sui-bridge/src/action_executor.rs rename to crates/iota-bridge/src/action_executor.rs index ac42224ad64..b6576e9bda3 100644 --- a/crates/sui-bridge/src/action_executor.rs +++ b/crates/iota-bridge/src/action_executor.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! BridgeActionExecutor receives BridgeActions (from BridgeOrchestrator), @@ -6,28 +7,28 @@ use std::sync::Arc; -use mysten_metrics::spawn_logged_monitored_task; -use shared_crypto::intent::{Intent, IntentMessage}; -use sui_json_rpc_types::{ - SuiExecutionStatus, SuiTransactionBlockEffects, SuiTransactionBlockEffectsAPI, +use iota_json_rpc_types::{ + IotaExecutionStatus, IotaTransactionBlockEffects, IotaTransactionBlockEffectsAPI, }; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef}, committee::VALIDITY_THRESHOLD, - crypto::{Signature, SuiKeyPair}, + crypto::{IotaKeyPair, Signature}, digests::TransactionDigest, gas_coin::GasCoin, object::Owner, transaction::Transaction, }; +use mysten_metrics::spawn_logged_monitored_task; +use shared_crypto::intent::{Intent, IntentMessage}; use tracing::{error, info, warn}; use crate::{ client::bridge_authority_aggregator::BridgeAuthorityAggregator, error::BridgeError, + iota_client::{IotaClient, IotaClientInner}, + iota_transaction_builder::build_transaction, storage::BridgeOrchestratorTables, - sui_client::{SuiClient, SuiClientInner}, - sui_transaction_builder::build_transaction, types::{BridgeAction, BridgeActionStatus, VerifiedCertifiedBridgeAction}, }; @@ -60,17 +61,17 @@ pub trait BridgeActionExecutorTrait { } pub struct BridgeActionExecutor { - sui_client: Arc>, + iota_client: Arc>, bridge_auth_agg: Arc, - key: SuiKeyPair, - sui_address: SuiAddress, + key: IotaKeyPair, + iota_address: IotaAddress, gas_object_id: ObjectID, store: Arc, } impl BridgeActionExecutorTrait for BridgeActionExecutor where - C: SuiClientInner + 'static, + C: IotaClientInner + 'static, { fn run( self, @@ -85,23 +86,23 @@ where impl BridgeActionExecutor where - C: SuiClientInner + 'static, + C: IotaClientInner + 'static, { pub fn new( - sui_client: Arc>, + iota_client: Arc>, bridge_auth_agg: Arc, store: Arc, - key: SuiKeyPair, - sui_address: SuiAddress, + key: IotaKeyPair, + iota_address: IotaAddress, gas_object_id: ObjectID, ) -> Self { Self { - sui_client, + iota_client, bridge_auth_agg, store, key, gas_object_id, - sui_address, + iota_address, } } @@ -132,7 +133,7 @@ where let execution_tx_clone = execution_tx.clone(); let sender_clone = sender.clone(); let store_clone = self.store.clone(); - let client_clone = self.sui_client.clone(); + let client_clone = self.iota_client.clone(); let mut tasks = vec![]; tasks.push(spawn_logged_monitored_task!( Self::run_signature_aggregation_loop( @@ -148,9 +149,9 @@ where let execution_tx_clone = execution_tx.clone(); tasks.push(spawn_logged_monitored_task!( Self::run_onchain_execution_loop( - self.sui_client.clone(), + self.iota_client.clone(), key, - self.sui_address, + self.iota_address, self.gas_object_id, self.store.clone(), execution_tx_clone, @@ -161,7 +162,7 @@ where } async fn run_signature_aggregation_loop( - sui_client: Arc>, + iota_client: Arc>, auth_agg: Arc, store: Arc, signing_queue_sender: mysten_metrics::metered_channel::Sender, @@ -178,10 +179,10 @@ where let auth_agg_clone = auth_agg.clone(); let signing_queue_sender_clone = signing_queue_sender.clone(); let execution_queue_sender_clone = execution_queue_sender.clone(); - let sui_client_clone = sui_client.clone(); + let iota_client_clone = iota_client.clone(); let store_clone = store.clone(); spawn_logged_monitored_task!(Self::request_signature( - sui_client_clone, + iota_client_clone, auth_agg_clone, action, store_clone, @@ -195,11 +196,11 @@ where // If yes, skip this action and remove it from the pending log. // Returns true if the action is already processed. async fn handle_already_processed_token_transfer_action_maybe( - sui_client: &Arc>, + iota_client: &Arc>, action: &BridgeAction, store: &Arc, ) -> bool { - let status = sui_client + let status = iota_client .get_token_transfer_action_onchain_status_until_success(action) .await; match status { @@ -215,14 +216,14 @@ where }); true } - // Although theoretically a legit SuiToEthBridgeAction should not have + // Although theoretically a legit IotaToEthBridgeAction should not have // status `RecordNotFound` BridgeActionStatus::Pending | BridgeActionStatus::RecordNotFound => false, } } async fn request_signature( - sui_client: Arc>, + iota_client: Arc>, auth_agg: Arc, action: BridgeActionExecutionWrapper, store: Arc, @@ -235,12 +236,12 @@ where // Only token transfer action should reach here match &action { - BridgeAction::SuiToEthBridgeAction(_) | BridgeAction::EthToSuiBridgeAction(_) => (), + BridgeAction::IotaToEthBridgeAction(_) | BridgeAction::EthToIotaBridgeAction(_) => (), _ => unreachable!("Non token transfer action should not reach here"), }; // If the action is already processed, skip it. - if Self::handle_already_processed_token_transfer_action_maybe(&sui_client, &action, &store) + if Self::handle_already_processed_token_transfer_action_maybe(&iota_client, &action, &store) .await { return; @@ -276,12 +277,12 @@ where } } - // Before calling this function, `key` and `sui_address` need to be + // Before calling this function, `key` and `iota_address` need to be // verified to match. async fn run_onchain_execution_loop( - sui_client: Arc>, - sui_key: SuiKeyPair, - sui_address: SuiAddress, + iota_client: Arc>, + iota_key: IotaKeyPair, + iota_address: IotaAddress, gas_object_id: ObjectID, store: Arc, execution_queue_sender: mysten_metrics::metered_channel::Sender< @@ -303,7 +304,7 @@ where let action = certificate.data(); // If the action is already processed, skip it. if Self::handle_already_processed_token_transfer_action_maybe( - &sui_client, + &iota_client, action, &store, ) @@ -314,9 +315,10 @@ where // TODO check gas coin balance here. If gas balance too low, do not proceed. let (_gas_coin, gas_object_ref) = - Self::get_gas_data_assert_ownership(sui_address, gas_object_id, &sui_client).await; + Self::get_gas_data_assert_ownership(iota_address, gas_object_id, &iota_client) + .await; let ceriticate_clone = certificate.clone(); - let tx_data = match build_transaction(sui_address, &gas_object_ref, ceriticate_clone) { + let tx_data = match build_transaction(iota_address, &gas_object_ref, ceriticate_clone) { Ok(tx_data) => tx_data, Err(err) => { // TODO: add mertrics @@ -330,15 +332,15 @@ where } }; let sig = Signature::new_secure( - &IntentMessage::new(Intent::sui_transaction(), &tx_data), - &sui_key, + &IntentMessage::new(Intent::iota_transaction(), &tx_data), + &iota_key, ); let signed_tx = Transaction::from_data(tx_data, vec![sig]); let tx_digest = *signed_tx.digest(); - info!(?tx_digest, ?gas_object_ref, "Sending transaction to Sui"); + info!(?tx_digest, ?gas_object_ref, "Sending transaction to Iota"); // TODO: add metrics to detect low balances and so on - match sui_client + match iota_client .execute_transaction_block_with_effects(signed_tx) .await { @@ -349,7 +351,7 @@ where // If the transaction did not go through, retry up to a certain times. Err(err) => { - error!("Sui transaction failed at signing: {err:?}"); + error!("Iota transaction failed at signing: {err:?}"); // Do this in a separate task so we won't deadlock here let sender_clone = execution_queue_sender.clone(); @@ -381,21 +383,21 @@ where // TODO: do we need a mechanism to periodically read pending actions from DB? async fn handle_execution_effects( tx_digest: TransactionDigest, - effects: SuiTransactionBlockEffects, + effects: IotaTransactionBlockEffects, store: &Arc, action: &BridgeAction, ) { let status = effects.status(); match status { - SuiExecutionStatus::Success => { - info!(?tx_digest, "Sui transaction executed successfully"); + IotaExecutionStatus::Success => { + info!(?tx_digest, "Iota transaction executed successfully"); store .remove_pending_actions(&[action.digest()]) .unwrap_or_else(|e| { panic!("Write to DB should not fail: {:?}", e); }) } - SuiExecutionStatus::Failure { error } => { + IotaExecutionStatus::Failure { error } => { // In practice the transaction could fail because of running out of gas, but // really should not be due to other reasons. // This means manual intervention is needed. So we do not push them back to @@ -406,7 +408,7 @@ where // TODO metrics + alerts error!( ?tx_digest, - "Manual intervention is needed. Sui transaction executed and failed with error: {error:?}" + "Manual intervention is needed. Iota transaction executed and failed with error: {error:?}" ); } } @@ -414,11 +416,11 @@ where /// Panics if the gas object is not owned by the address. async fn get_gas_data_assert_ownership( - sui_address: SuiAddress, + iota_address: IotaAddress, gas_object_id: ObjectID, - sui_client: &SuiClient, + iota_client: &IotaClient, ) -> (GasCoin, ObjectRef) { - let (gas_coin, gas_obj_ref, owner) = sui_client + let (gas_coin, gas_obj_ref, owner) = iota_client .get_gas_data_panic_if_not_gas(gas_object_id) .await; @@ -426,10 +428,10 @@ where // transferred gas object instead. assert_eq!( owner, - Owner::AddressOwner(sui_address), + Owner::AddressOwner(iota_address), "Gas object {:?} is no longer owned by address {}", gas_object_id, - sui_address + iota_address ); (gas_coin, gas_obj_ref) } @@ -449,12 +451,12 @@ mod tests { use std::collections::BTreeMap; use fastcrypto::traits::KeyPair; - use prometheus::Registry; - use sui_json_rpc_types::SuiTransactionBlockResponse; - use sui_types::{ + use iota_json_rpc_types::IotaTransactionBlockResponse; + use iota_types::{ base_types::random_object_ref, crypto::get_key_pair, gas_coin::GasCoin, transaction::TransactionData, }; + use prometheus::Registry; use super::*; use crate::{ @@ -462,10 +464,10 @@ mod tests { BridgeAuthorityKeyPair, BridgeAuthorityPublicKeyBytes, BridgeAuthorityRecoverableSignature, }, + iota_mock_client::IotaMockClient, server::mock_handler::BridgeRequestMockHandler, - sui_mock_client::SuiMockClient, test_utils::{ - get_test_authorities_and_run_mock_bridge_server, get_test_sui_to_eth_bridge_action, + get_test_authorities_and_run_mock_bridge_server, get_test_iota_to_eth_bridge_action, sign_action_with_key, }, types::{BridgeCommittee, BridgeCommitteeValiditySignInfo, CertifiedBridgeAction}, @@ -476,18 +478,18 @@ mod tests { let ( signing_tx, _execution_tx, - sui_client_mock, + iota_client_mock, mut tx_subscription, store, secrets, - dummy_sui_key, + dummy_iota_key, mock0, mock1, mock2, mock3, _handles, gas_object_ref, - sui_address, + iota_address, ) = setup(); // TODO: remove once we don't rely on env var to get object id @@ -500,22 +502,22 @@ mod tests { ); let action = action_certificate.data().clone(); - let tx_data = build_transaction(sui_address, &gas_object_ref, action_certificate).unwrap(); + let tx_data = build_transaction(iota_address, &gas_object_ref, action_certificate).unwrap(); - let tx_digest = get_tx_digest(tx_data, &dummy_sui_key); + let tx_digest = get_tx_digest(tx_data, &dummy_iota_key); let gas_coin = GasCoin::new_for_testing(1_000_000_000_000); // dummy gas coin - sui_client_mock.add_gas_object_info( + iota_client_mock.add_gas_object_info( gas_coin.clone(), gas_object_ref, - Owner::AddressOwner(sui_address), + Owner::AddressOwner(iota_address), ); // Mock the transaction to be successfully executed mock_transaction_response( - &sui_client_mock, + &iota_client_mock, tx_digest, - SuiExecutionStatus::Success, + IotaExecutionStatus::Success, true, ); @@ -548,14 +550,14 @@ mod tests { let action = action_certificate.data().clone(); - let tx_data = build_transaction(sui_address, &gas_object_ref, action_certificate).unwrap(); - let tx_digest = get_tx_digest(tx_data, &dummy_sui_key); + let tx_data = build_transaction(iota_address, &gas_object_ref, action_certificate).unwrap(); + let tx_digest = get_tx_digest(tx_data, &dummy_iota_key); // Mock the transaction to fail mock_transaction_response( - &sui_client_mock, + &iota_client_mock, tx_digest, - SuiExecutionStatus::Failure { + IotaExecutionStatus::Failure { error: "failure is mother of success".to_string(), }, true, @@ -593,10 +595,10 @@ mod tests { let action = action_certificate.data().clone(); - let tx_data = build_transaction(sui_address, &gas_object_ref, action_certificate).unwrap(); - let tx_digest = get_tx_digest(tx_data, &dummy_sui_key); + let tx_data = build_transaction(iota_address, &gas_object_ref, action_certificate).unwrap(); + let tx_digest = get_tx_digest(tx_data, &dummy_iota_key); mock_transaction_error( - &sui_client_mock, + &iota_client_mock, tx_digest, BridgeError::Generic("some random error".to_string()), true, @@ -627,9 +629,9 @@ mod tests { // Now let it succeed mock_transaction_response( - &sui_client_mock, + &iota_client_mock, tx_digest, - SuiExecutionStatus::Success, + IotaExecutionStatus::Success, true, ); @@ -649,25 +651,25 @@ mod tests { let ( signing_tx, _execution_tx, - sui_client_mock, + iota_client_mock, mut tx_subscription, store, secrets, - dummy_sui_key, + dummy_iota_key, mock0, mock1, mock2, mock3, _handles, gas_object_ref, - sui_address, + iota_address, ) = setup(); // TODO: remove once we don't rely on env var to get object id std::env::set_var("ROOT_BRIDGE_OBJECT_ID", "0x09"); std::env::set_var("ROOT_BRIDGE_OBJECT_INITIAL_SHARED_VERSION", "1"); - let (action_certificate, sui_tx_digest, sui_tx_event_index) = + let (action_certificate, iota_tx_digest, iota_tx_event_index) = get_bridge_authority_approved_action( vec![&mock0, &mock1, &mock2, &mock3], vec![&secrets[0], &secrets[1], &secrets[2], &secrets[3]], @@ -675,22 +677,22 @@ mod tests { let action = action_certificate.data().clone(); mock_bridge_authority_signing_errors( vec![&mock0, &mock1, &mock2], - sui_tx_digest, - sui_tx_event_index, + iota_tx_digest, + iota_tx_event_index, ); let mut sigs = mock_bridge_authority_sigs( vec![&mock3], &action, vec![&secrets[3]], - sui_tx_digest, - sui_tx_event_index, + iota_tx_digest, + iota_tx_event_index, ); let gas_coin = GasCoin::new_for_testing(1_000_000_000_000); // dummy gas coin - sui_client_mock.add_gas_object_info( + iota_client_mock.add_gas_object_info( gas_coin, gas_object_ref, - Owner::AddressOwner(sui_address), + Owner::AddressOwner(iota_address), ); store.insert_pending_actions(&[action.clone()]).unwrap(); @@ -708,7 +710,7 @@ mod tests { // dropped) loop { let requested_times = - mock0.get_sui_token_events_requested(sui_tx_digest, sui_tx_event_index); + mock0.get_iota_token_events_requested(iota_tx_digest, iota_tx_event_index); if requested_times >= 2 { break; } @@ -730,8 +732,8 @@ mod tests { vec![&mock2], &action, vec![&secrets[2]], - sui_tx_digest, - sui_tx_event_index, + iota_tx_digest, + iota_tx_event_index, ); sigs.extend(sig_from_2); let certified_action = CertifiedBridgeAction::new_from_data_and_sig( @@ -740,13 +742,13 @@ mod tests { ); let action_certificate = VerifiedCertifiedBridgeAction::new_from_verified(certified_action); - let tx_data = build_transaction(sui_address, &gas_object_ref, action_certificate).unwrap(); - let tx_digest = get_tx_digest(tx_data, &dummy_sui_key); + let tx_data = build_transaction(iota_address, &gas_object_ref, action_certificate).unwrap(); + let tx_digest = get_tx_digest(tx_data, &dummy_iota_key); mock_transaction_response( - &sui_client_mock, + &iota_client_mock, tx_digest, - SuiExecutionStatus::Success, + IotaExecutionStatus::Success, true, ); @@ -766,36 +768,36 @@ mod tests { let ( signing_tx, _execution_tx, - sui_client_mock, + iota_client_mock, mut tx_subscription, store, _secrets, - _dummy_sui_key, + _dummy_iota_key, mock0, mock1, mock2, mock3, _handles, _gas_object_ref, - _sui_address, + _iota_address, ) = setup(); // TODO: remove once we don't rely on env var to get object id std::env::set_var("ROOT_BRIDGE_OBJECT_ID", "0x09"); std::env::set_var("ROOT_BRIDGE_OBJECT_INITIAL_SHARED_VERSION", "1"); - let sui_tx_digest = TransactionDigest::random(); - let sui_tx_event_index = 0; - let action = get_test_sui_to_eth_bridge_action( - Some(sui_tx_digest), - Some(sui_tx_event_index), + let iota_tx_digest = TransactionDigest::random(); + let iota_tx_event_index = 0; + let action = get_test_iota_to_eth_bridge_action( + Some(iota_tx_digest), + Some(iota_tx_event_index), None, None, ); mock_bridge_authority_signing_errors( vec![&mock0, &mock1, &mock2, &mock3], - sui_tx_digest, - sui_tx_event_index, + iota_tx_digest, + iota_tx_event_index, ); store.insert_pending_actions(&[action.clone()]).unwrap(); assert_eq!( @@ -821,7 +823,7 @@ mod tests { .contains_key(&action_digest) ); - sui_client_mock.set_action_onchain_status(&action, BridgeActionStatus::Approved); + iota_client_mock.set_action_onchain_status(&action, BridgeActionStatus::Approved); // The next retry will see the action is already processed on chain and remove // it from WAL @@ -844,18 +846,18 @@ mod tests { let ( _signing_tx, execution_tx, - sui_client_mock, + iota_client_mock, mut tx_subscription, store, secrets, - dummy_sui_key, + dummy_iota_key, mock0, mock1, mock2, mock3, _handles, gas_object_ref, - sui_address, + iota_address, ) = setup(); // TODO: remove once we don't rely on env var to get object id @@ -870,23 +872,23 @@ mod tests { let action = action_certificate.data().clone(); let tx_data = - build_transaction(sui_address, &gas_object_ref, action_certificate.clone()).unwrap(); - let tx_digest = get_tx_digest(tx_data, &dummy_sui_key); + build_transaction(iota_address, &gas_object_ref, action_certificate.clone()).unwrap(); + let tx_digest = get_tx_digest(tx_data, &dummy_iota_key); mock_transaction_error( - &sui_client_mock, + &iota_client_mock, tx_digest, BridgeError::Generic("some random error".to_string()), true, ); let gas_coin = GasCoin::new_for_testing(1_000_000_000_000); // dummy gas coin - sui_client_mock.add_gas_object_info( + iota_client_mock.add_gas_object_info( gas_coin.clone(), gas_object_ref, - Owner::AddressOwner(sui_address), + Owner::AddressOwner(iota_address), ); - sui_client_mock.set_action_onchain_status(&action, BridgeActionStatus::Pending); + iota_client_mock.set_action_onchain_status(&action, BridgeActionStatus::Pending); store.insert_pending_actions(&[action.clone()]).unwrap(); assert_eq!( @@ -904,7 +906,7 @@ mod tests { tx_subscription.recv().await.unwrap(); // Set the action to be already approved on chain - sui_client_mock.set_action_onchain_status(&action, BridgeActionStatus::Approved); + iota_client_mock.set_action_onchain_status(&action, BridgeActionStatus::Approved); // The next retry will see the action is already processed on chain and remove // it from WAL @@ -926,16 +928,16 @@ mod tests { mocks: Vec<&BridgeRequestMockHandler>, action: &BridgeAction, secrets: Vec<&BridgeAuthorityKeyPair>, - sui_tx_digest: TransactionDigest, - sui_tx_event_index: u16, + iota_tx_digest: TransactionDigest, + iota_tx_event_index: u16, ) -> BTreeMap { assert_eq!(mocks.len(), secrets.len()); let mut signed_actions = BTreeMap::new(); for (mock, secret) in mocks.iter().zip(secrets.iter()) { let signed_action = sign_action_with_key(action, secret); - mock.add_sui_event_response( - sui_tx_digest, - sui_tx_event_index, + mock.add_iota_event_response( + iota_tx_digest, + iota_tx_event_index, Ok(signed_action.clone()), ); signed_actions.insert(secret.public().into(), signed_action.into_sig().signature); @@ -945,13 +947,13 @@ mod tests { fn mock_bridge_authority_signing_errors( mocks: Vec<&BridgeRequestMockHandler>, - sui_tx_digest: TransactionDigest, - sui_tx_event_index: u16, + iota_tx_digest: TransactionDigest, + iota_tx_event_index: u16, ) { for mock in mocks { - mock.add_sui_event_response( - sui_tx_digest, - sui_tx_event_index, + mock.add_iota_event_response( + iota_tx_digest, + iota_tx_event_index, Err(BridgeError::RestAPIError("small issue".into())), ); } @@ -962,32 +964,37 @@ mod tests { mocks: Vec<&BridgeRequestMockHandler>, secrets: Vec<&BridgeAuthorityKeyPair>, ) -> (VerifiedCertifiedBridgeAction, TransactionDigest, u16) { - let sui_tx_digest = TransactionDigest::random(); - let sui_tx_event_index = 1; - let action = get_test_sui_to_eth_bridge_action( - Some(sui_tx_digest), - Some(sui_tx_event_index), + let iota_tx_digest = TransactionDigest::random(); + let iota_tx_event_index = 1; + let action = get_test_iota_to_eth_bridge_action( + Some(iota_tx_digest), + Some(iota_tx_event_index), None, None, ); - let sigs = - mock_bridge_authority_sigs(mocks, &action, secrets, sui_tx_digest, sui_tx_event_index); + let sigs = mock_bridge_authority_sigs( + mocks, + &action, + secrets, + iota_tx_digest, + iota_tx_event_index, + ); let certified_action = CertifiedBridgeAction::new_from_data_and_sig( action, BridgeCommitteeValiditySignInfo { signatures: sigs }, ); ( VerifiedCertifiedBridgeAction::new_from_verified(certified_action), - sui_tx_digest, - sui_tx_event_index, + iota_tx_digest, + iota_tx_event_index, ) } - fn get_tx_digest(tx_data: TransactionData, dummy_sui_key: &SuiKeyPair) -> TransactionDigest { + fn get_tx_digest(tx_data: TransactionData, dummy_iota_key: &IotaKeyPair) -> TransactionDigest { let sig = Signature::new_secure( - &IntentMessage::new(Intent::sui_transaction(), &tx_data), - dummy_sui_key, + &IntentMessage::new(Intent::iota_transaction(), &tx_data), + dummy_iota_key, ); let signed_tx = Transaction::from_data(tx_data, vec![sig]); *signed_tx.digest() @@ -997,31 +1004,31 @@ mod tests { /// are part of transaction data. Depending on whose signatures /// are included in what order, this may change the tx digest. fn mock_transaction_response( - sui_client_mock: &SuiMockClient, + iota_client_mock: &IotaMockClient, tx_digest: TransactionDigest, - status: SuiExecutionStatus, + status: IotaExecutionStatus, wildcard: bool, ) { - let mut response = SuiTransactionBlockResponse::new(tx_digest); - let effects = SuiTransactionBlockEffects::new_for_testing(tx_digest, status); + let mut response = IotaTransactionBlockResponse::new(tx_digest); + let effects = IotaTransactionBlockEffects::new_for_testing(tx_digest, status); response.effects = Some(effects); if wildcard { - sui_client_mock.set_wildcard_transaction_response(Ok(response)); + iota_client_mock.set_wildcard_transaction_response(Ok(response)); } else { - sui_client_mock.add_transaction_response(tx_digest, Ok(response)); + iota_client_mock.add_transaction_response(tx_digest, Ok(response)); } } fn mock_transaction_error( - sui_client_mock: &SuiMockClient, + iota_client_mock: &IotaMockClient, tx_digest: TransactionDigest, error: BridgeError, wildcard: bool, ) { if wildcard { - sui_client_mock.set_wildcard_transaction_response(Err(error)); + iota_client_mock.set_wildcard_transaction_response(Err(error)); } else { - sui_client_mock.add_transaction_response(tx_digest, Err(error)); + iota_client_mock.add_transaction_response(tx_digest, Err(error)); } } @@ -1029,37 +1036,37 @@ mod tests { fn setup() -> ( mysten_metrics::metered_channel::Sender, mysten_metrics::metered_channel::Sender, - SuiMockClient, + IotaMockClient, tokio::sync::broadcast::Receiver, Arc, Vec, - SuiKeyPair, + IotaKeyPair, BridgeRequestMockHandler, BridgeRequestMockHandler, BridgeRequestMockHandler, BridgeRequestMockHandler, Vec>, ObjectRef, - SuiAddress, + IotaAddress, ) { telemetry_subscribers::init_for_testing(); let registry = Registry::new(); mysten_metrics::init_metrics(®istry); - let (sui_address, kp): (_, fastcrypto::secp256k1::Secp256k1KeyPair) = get_key_pair(); - let sui_key = SuiKeyPair::from(kp); + let (iota_address, kp): (_, fastcrypto::secp256k1::Secp256k1KeyPair) = get_key_pair(); + let iota_key = IotaKeyPair::from(kp); let gas_object_ref = random_object_ref(); let temp_dir = tempfile::tempdir().unwrap(); let store = BridgeOrchestratorTables::new(temp_dir.path()); - let sui_client_mock = SuiMockClient::default(); - let tx_subscription = sui_client_mock.subscribe_to_requested_transactions(); - let sui_client = Arc::new(SuiClient::new_for_testing(sui_client_mock.clone())); + let iota_client_mock = IotaMockClient::default(); + let tx_subscription = iota_client_mock.subscribe_to_requested_transactions(); + let iota_client = Arc::new(IotaClient::new_for_testing(iota_client_mock.clone())); // The dummy key is used to sign transaction so we can get TransactionDigest // easily. User signature is not part of the transaction so it does not // matter which key it is. let (_, dummy_kp): (_, fastcrypto::secp256k1::Secp256k1KeyPair) = get_key_pair(); - let dummy_sui_key = SuiKeyPair::from(dummy_kp); + let dummy_iota_key = IotaKeyPair::from(dummy_kp); let mock0 = BridgeRequestMockHandler::new(); let mock1 = BridgeRequestMockHandler::new(); @@ -1076,11 +1083,11 @@ mod tests { let agg = Arc::new(BridgeAuthorityAggregator::new(Arc::new(committee))); let executor = BridgeActionExecutor::new( - sui_client.clone(), + iota_client.clone(), agg.clone(), store.clone(), - sui_key, - sui_address, + iota_key, + iota_address, gas_object_ref.0, ); @@ -1089,18 +1096,18 @@ mod tests { ( signing_tx, execution_tx, - sui_client_mock, + iota_client_mock, tx_subscription, store, secrets, - dummy_sui_key, + dummy_iota_key, mock0, mock1, mock2, mock3, handles, gas_object_ref, - sui_address, + iota_address, ) } } diff --git a/crates/sui-bridge/src/client/bridge_authority_aggregator.rs b/crates/iota-bridge/src/client/bridge_authority_aggregator.rs similarity index 91% rename from crates/sui-bridge/src/client/bridge_authority_aggregator.rs rename to crates/iota-bridge/src/client/bridge_authority_aggregator.rs index 4567fc6a42b..5a3f799b1f0 100644 --- a/crates/sui-bridge/src/client/bridge_authority_aggregator.rs +++ b/crates/iota-bridge/src/client/bridge_authority_aggregator.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! BridgeAuthorityAggregator aggregates signatures from BridgeCommittee. @@ -9,8 +10,8 @@ use std::{ time::Duration, }; -use sui_common::authority_aggregation::{quorum_map_then_reduce_with_timeout, ReduceOutput}; -use sui_types::{ +use iota_common::authority_aggregation::{quorum_map_then_reduce_with_timeout, ReduceOutput}; +use iota_types::{ base_types::ConciseableName, committee::{StakeUnit, TOTAL_VOTING_POWER}, }; @@ -134,7 +135,7 @@ impl GetSigsState { .map(|(k, v)| (k.clone(), v.signature.clone())) .collect::>(); let sig_info = BridgeCommitteeValiditySignInfo { signatures }; - let certified_action: sui_types::message_envelope::Envelope< + let certified_action: iota_types::message_envelope::Envelope< BridgeAction, BridgeCommitteeValiditySignInfo, > = CertifiedBridgeAction::new_from_data_and_sig( @@ -242,7 +243,7 @@ mod tests { use std::collections::BTreeSet; use fastcrypto::traits::ToFromBytes; - use sui_types::{committee::VALIDITY_THRESHOLD, digests::TransactionDigest}; + use iota_types::{committee::VALIDITY_THRESHOLD, digests::TransactionDigest}; use super::*; use crate::{ @@ -250,7 +251,7 @@ mod tests { server::mock_handler::BridgeRequestMockHandler, test_utils::{ get_test_authorities_and_run_mock_bridge_server, get_test_authority_and_key, - get_test_sui_to_eth_bridge_action, sign_action_with_key, + get_test_iota_to_eth_bridge_action, sign_action_with_key, }, types::BridgeCommittee, }; @@ -323,36 +324,36 @@ mod tests { let agg = BridgeAuthorityAggregator::new(Arc::new(committee)); - let sui_tx_digest = TransactionDigest::random(); - let sui_tx_event_index = 0; + let iota_tx_digest = TransactionDigest::random(); + let iota_tx_event_index = 0; let nonce = 0; let amount = 1000; - let action = get_test_sui_to_eth_bridge_action( - Some(sui_tx_digest), - Some(sui_tx_event_index), + let action = get_test_iota_to_eth_bridge_action( + Some(iota_tx_digest), + Some(iota_tx_event_index), Some(nonce), Some(amount), ); // All authorities return signatures - mock0.add_sui_event_response( - sui_tx_digest, - sui_tx_event_index, + mock0.add_iota_event_response( + iota_tx_digest, + iota_tx_event_index, Ok(sign_action_with_key(&action, &secrets[0])), ); - mock1.add_sui_event_response( - sui_tx_digest, - sui_tx_event_index, + mock1.add_iota_event_response( + iota_tx_digest, + iota_tx_event_index, Ok(sign_action_with_key(&action, &secrets[1])), ); - mock2.add_sui_event_response( - sui_tx_digest, - sui_tx_event_index, + mock2.add_iota_event_response( + iota_tx_digest, + iota_tx_event_index, Ok(sign_action_with_key(&action, &secrets[2])), ); - mock3.add_sui_event_response( - sui_tx_digest, - sui_tx_event_index, + mock3.add_iota_event_response( + iota_tx_digest, + iota_tx_event_index, Ok(sign_action_with_key(&action, &secrets[3])), ); agg.request_committee_signatures(action.clone(), VALIDITY_THRESHOLD) @@ -360,9 +361,9 @@ mod tests { .unwrap(); // 1 out of 4 authorities returns error - mock3.add_sui_event_response( - sui_tx_digest, - sui_tx_event_index, + mock3.add_iota_event_response( + iota_tx_digest, + iota_tx_event_index, Err(BridgeError::RestAPIError("".into())), ); agg.request_committee_signatures(action.clone(), VALIDITY_THRESHOLD) @@ -370,9 +371,9 @@ mod tests { .unwrap(); // 2 out of 4 authorities returns error - mock2.add_sui_event_response( - sui_tx_digest, - sui_tx_event_index, + mock2.add_iota_event_response( + iota_tx_digest, + iota_tx_event_index, Err(BridgeError::RestAPIError("".into())), ); agg.request_committee_signatures(action.clone(), VALIDITY_THRESHOLD) @@ -380,9 +381,9 @@ mod tests { .unwrap(); // 3 out of 4 authorities returns error - good stake below valdiity threshold - mock1.add_sui_event_response( - sui_tx_digest, - sui_tx_event_index, + mock1.add_iota_event_response( + iota_tx_digest, + iota_tx_event_index, Err(BridgeError::RestAPIError("".into())), ); let err = agg @@ -417,13 +418,13 @@ mod tests { let agg = BridgeAuthorityAggregator::new(Arc::new(committee)); - let sui_tx_digest = TransactionDigest::random(); - let sui_tx_event_index = 0; + let iota_tx_digest = TransactionDigest::random(); + let iota_tx_event_index = 0; let nonce = 0; let amount = 1000; - let action = get_test_sui_to_eth_bridge_action( - Some(sui_tx_digest), - Some(sui_tx_event_index), + let action = get_test_iota_to_eth_bridge_action( + Some(iota_tx_digest), + Some(iota_tx_event_index), Some(nonce), Some(amount), ); @@ -431,14 +432,14 @@ mod tests { // Only mock authority 2 and 3 to return signatures, such that if // BridgeAuthorityAggregator requests to authority 0 and 1 (which should // not happen) it will panic. - mock2.add_sui_event_response( - sui_tx_digest, - sui_tx_event_index, + mock2.add_iota_event_response( + iota_tx_digest, + iota_tx_event_index, Ok(sign_action_with_key(&action, &secrets[2])), ); - mock3.add_sui_event_response( - sui_tx_digest, - sui_tx_event_index, + mock3.add_iota_event_response( + iota_tx_digest, + iota_tx_event_index, Ok(sign_action_with_key(&action, &secrets[3])), ); let certified = agg @@ -460,9 +461,9 @@ mod tests { ); // if mock 3 returns error, then it won't reach validity threshold - mock3.add_sui_event_response( - sui_tx_digest, - sui_tx_event_index, + mock3.add_iota_event_response( + iota_tx_digest, + iota_tx_event_index, Err(BridgeError::RestAPIError("".into())), ); let err = agg @@ -476,9 +477,9 @@ mod tests { // if mock 3 returns duplicated signature (by authority 2), `BridgeClient` will // catch this - mock3.add_sui_event_response( - sui_tx_digest, - sui_tx_event_index, + mock3.add_iota_event_response( + iota_tx_digest, + iota_tx_event_index, Ok(sign_action_with_key(&action, &secrets[2])), ); let err = agg @@ -551,13 +552,13 @@ mod tests { let threshold = VALIDITY_THRESHOLD; let mut state = GetSigsState::new(threshold, Arc::new(committee.clone())); - let sui_tx_digest = TransactionDigest::random(); - let sui_tx_event_index = 0; + let iota_tx_digest = TransactionDigest::random(); + let iota_tx_event_index = 0; let nonce = 0; let amount = 1000; - let action = get_test_sui_to_eth_bridge_action( - Some(sui_tx_digest), - Some(sui_tx_event_index), + let action = get_test_iota_to_eth_bridge_action( + Some(iota_tx_digest), + Some(iota_tx_event_index), Some(nonce), Some(amount), ); diff --git a/crates/sui-bridge/src/client/bridge_client.rs b/crates/iota-bridge/src/client/bridge_client.rs similarity index 87% rename from crates/sui-bridge/src/client/bridge_client.rs rename to crates/iota-bridge/src/client/bridge_client.rs index db32ce96d5c..f0ff4f9eed8 100644 --- a/crates/sui-bridge/src/client/bridge_client.rs +++ b/crates/iota-bridge/src/client/bridge_client.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! `BridgeClient` talks to BridgeNode. @@ -58,12 +59,12 @@ impl BridgeClient { // Important: the paths need to match the ones in mod.rs fn bridge_action_to_path(event: &BridgeAction) -> String { match event { - BridgeAction::SuiToEthBridgeAction(e) => format!( - "sign/bridge_tx/sui/eth/{}/{}", - e.sui_tx_digest, e.sui_tx_event_index + BridgeAction::IotaToEthBridgeAction(e) => format!( + "sign/bridge_tx/iota/eth/{}/{}", + e.iota_tx_digest, e.iota_tx_event_index ), - BridgeAction::EthToSuiBridgeAction(e) => format!( - "sign/bridge_tx/eth/sui/{}/{}", + BridgeAction::EthToIotaBridgeAction(e) => format!( + "sign/bridge_tx/eth/iota/{}/{}", Hex::encode(e.eth_tx_hash.0), e.eth_event_index ), @@ -178,17 +179,17 @@ mod tests { hash::{HashFunction, Keccak256}, traits::KeyPair, }; + use iota_types::{base_types::IotaAddress, crypto::get_key_pair, digests::TransactionDigest}; use prometheus::Registry; - use sui_types::{base_types::SuiAddress, crypto::get_key_pair, digests::TransactionDigest}; use super::*; use crate::{ - abi::EthToSuiTokenBridgeV1, + abi::EthToIotaTokenBridgeV1, crypto::BridgeAuthoritySignInfo, - events::EmittedSuiToEthTokenBridgeV1, + events::EmittedIotaToEthTokenBridgeV1, server::mock_handler::BridgeRequestMockHandler, test_utils::{ - get_test_authority_and_key, get_test_sui_to_eth_bridge_action, run_mock_bridge_server, + get_test_authority_and_key, get_test_iota_to_eth_bridge_action, run_mock_bridge_server, }, types::{BridgeChainId, SignedBridgeAction, TokenId}, }; @@ -201,14 +202,14 @@ mod tests { let pubkey_bytes = BridgeAuthorityPublicKeyBytes::from(&pubkey); let committee = Arc::new(BridgeCommittee::new(vec![authority.clone()]).unwrap()); - let action = get_test_sui_to_eth_bridge_action(None, Some(1), Some(1), Some(100)); + let action = get_test_iota_to_eth_bridge_action(None, Some(1), Some(1), Some(100)); // Ok let client = BridgeClient::new(pubkey_bytes.clone(), committee).unwrap(); assert!(client.base_url.is_some()); // Ok - authority.base_url = "https://foo.suibridge.io".to_string(); + authority.base_url = "https://foo.iotabridge.io".to_string(); let committee = Arc::new(BridgeCommittee::new(vec![authority.clone()]).unwrap()); let client = BridgeClient::new(pubkey_bytes.clone(), committee.clone()).unwrap(); assert!(client.base_url.is_some()); @@ -278,11 +279,15 @@ mod tests { let tx_digest = TransactionDigest::random(); let event_idx = 4; - let action = - get_test_sui_to_eth_bridge_action(Some(tx_digest), Some(event_idx), Some(1), Some(100)); + let action = get_test_iota_to_eth_bridge_action( + Some(tx_digest), + Some(event_idx), + Some(1), + Some(100), + ); let sig = BridgeAuthoritySignInfo::new(&action, &secret); let signed_event = SignedBridgeAction::new_from_data_and_sig(action.clone(), sig.clone()); - mock_handler.add_sui_event_response(tx_digest, event_idx, Ok(signed_event.clone())); + mock_handler.add_iota_event_response(tx_digest, event_idx, Ok(signed_event.clone())); // success client @@ -292,12 +297,16 @@ mod tests { // mismatched action would fail, this could happen when the authority fetched // the wrong event - let action2 = - get_test_sui_to_eth_bridge_action(Some(tx_digest), Some(event_idx), Some(2), Some(200)); + let action2 = get_test_iota_to_eth_bridge_action( + Some(tx_digest), + Some(event_idx), + Some(2), + Some(200), + ); let wrong_sig = BridgeAuthoritySignInfo::new(&action2, &secret); let wrong_signed_action = SignedBridgeAction::new_from_data_and_sig(action2.clone(), wrong_sig.clone()); - mock_handler.add_sui_event_response(tx_digest, event_idx, Ok(wrong_signed_action)); + mock_handler.add_iota_event_response(tx_digest, event_idx, Ok(wrong_signed_action)); let err = client .request_sign_bridge_action(action.clone()) .await @@ -307,7 +316,7 @@ mod tests { // The action matches but the signature is wrong, fail let wrong_signed_action = SignedBridgeAction::new_from_data_and_sig(action.clone(), wrong_sig); - mock_handler.add_sui_event_response(tx_digest, event_idx, Ok(wrong_signed_action)); + mock_handler.add_iota_event_response(tx_digest, event_idx, Ok(wrong_signed_action)); let err = client .request_sign_bridge_action(action.clone()) .await @@ -324,7 +333,7 @@ mod tests { BridgeCommittee::new(vec![authority_blocklisted.clone(), authority2.clone()]).unwrap(), ); client.update_committee(committee2); - mock_handler.add_sui_event_response(tx_digest, event_idx, Ok(signed_event)); + mock_handler.add_iota_event_response(tx_digest, event_idx, Ok(signed_event)); let err = client .request_sign_bridge_action(action.clone()) @@ -339,7 +348,7 @@ mod tests { // signed by a different authority in committee would fail let sig2 = BridgeAuthoritySignInfo::new(&action, &secret2); let signed_event2 = SignedBridgeAction::new_from_data_and_sig(action.clone(), sig2.clone()); - mock_handler.add_sui_event_response(tx_digest, event_idx, Ok(signed_event2)); + mock_handler.add_iota_event_response(tx_digest, event_idx, Ok(signed_event2)); let err = client .request_sign_bridge_action(action.clone()) .await @@ -351,7 +360,7 @@ mod tests { let secret3 = Arc::pin(kp3); let sig3 = BridgeAuthoritySignInfo::new(&action, &secret3); let signed_event3 = SignedBridgeAction::new_from_data_and_sig(action.clone(), sig3); - mock_handler.add_sui_event_response(tx_digest, event_idx, Ok(signed_event3)); + mock_handler.add_iota_event_response(tx_digest, event_idx, Ok(signed_event3)); let err = client .request_sign_bridge_action(action.clone()) .await @@ -361,15 +370,15 @@ mod tests { #[test] fn test_bridge_action_path_regression_tests() { - let sui_tx_digest = TransactionDigest::random(); - let sui_tx_event_index = 5; - let action = BridgeAction::SuiToEthBridgeAction(crate::types::SuiToEthBridgeAction { - sui_tx_digest, - sui_tx_event_index, - sui_bridge_event: EmittedSuiToEthTokenBridgeV1 { - sui_chain_id: BridgeChainId::SuiDevnet, + let iota_tx_digest = TransactionDigest::random(); + let iota_tx_event_index = 5; + let action = BridgeAction::IotaToEthBridgeAction(crate::types::IotaToEthBridgeAction { + iota_tx_digest, + iota_tx_event_index, + iota_bridge_event: EmittedIotaToEthTokenBridgeV1 { + iota_chain_id: BridgeChainId::IotaDevnet, nonce: 1, - sui_address: SuiAddress::random_for_testing_only(), + iota_address: IotaAddress::random_for_testing_only(), eth_chain_id: BridgeChainId::EthSepolia, eth_address: EthAddress::random(), token_id: TokenId::USDT, @@ -379,22 +388,22 @@ mod tests { assert_eq!( BridgeClient::bridge_action_to_path(&action), format!( - "sign/bridge_tx/sui/eth/{}/{}", - sui_tx_digest, sui_tx_event_index + "sign/bridge_tx/iota/eth/{}/{}", + iota_tx_digest, iota_tx_event_index ) ); let eth_tx_hash = TxHash::random(); let eth_event_index = 6; - let action = BridgeAction::EthToSuiBridgeAction(crate::types::EthToSuiBridgeAction { + let action = BridgeAction::EthToIotaBridgeAction(crate::types::EthToIotaBridgeAction { eth_tx_hash, eth_event_index, - eth_bridge_event: EthToSuiTokenBridgeV1 { + eth_bridge_event: EthToIotaTokenBridgeV1 { eth_chain_id: BridgeChainId::EthSepolia, nonce: 1, eth_address: EthAddress::random(), - sui_chain_id: BridgeChainId::SuiDevnet, - sui_address: SuiAddress::random_for_testing_only(), + iota_chain_id: BridgeChainId::IotaDevnet, + iota_address: IotaAddress::random_for_testing_only(), token_id: TokenId::USDT, amount: 1, }, @@ -403,7 +412,7 @@ mod tests { assert_eq!( BridgeClient::bridge_action_to_path(&action), format!( - "sign/bridge_tx/eth/sui/{}/{}", + "sign/bridge_tx/eth/iota/{}/{}", Hex::encode(eth_tx_hash.0), eth_event_index ) @@ -444,7 +453,7 @@ mod tests { ); let action = BridgeAction::EmergencyAction(crate::types::EmergencyAction { - chain_id: BridgeChainId::SuiLocalTest, + chain_id: BridgeChainId::IotaLocalTest, nonce: 5, action_type: crate::types::EmergencyActionType::Pause, }); @@ -454,7 +463,7 @@ mod tests { ); let action = BridgeAction::LimitUpdateAction(crate::types::LimitUpdateAction { - chain_id: BridgeChainId::SuiLocalTest, + chain_id: BridgeChainId::IotaLocalTest, nonce: 10, sending_chain_id: BridgeChainId::EthLocalTest, new_usd_limit: 100, @@ -465,7 +474,7 @@ mod tests { ); let action = BridgeAction::AssetPriceUpdateAction(crate::types::AssetPriceUpdateAction { - chain_id: BridgeChainId::SuiDevnet, + chain_id: BridgeChainId::IotaDevnet, nonce: 8, token_id: TokenId::BTC, new_usd_price: 100_000_000, diff --git a/crates/iota-bridge/src/client/mod.rs b/crates/iota-bridge/src/client/mod.rs new file mode 100644 index 00000000000..4f516992c65 --- /dev/null +++ b/crates/iota-bridge/src/client/mod.rs @@ -0,0 +1,6 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod bridge_authority_aggregator; +pub mod bridge_client; diff --git a/crates/iota-bridge/src/config.rs b/crates/iota-bridge/src/config.rs new file mode 100644 index 00000000000..63071fdac95 --- /dev/null +++ b/crates/iota-bridge/src/config.rs @@ -0,0 +1,320 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{BTreeMap, HashSet}, + path::PathBuf, + str::FromStr, + sync::Arc, +}; + +use anyhow::anyhow; +use ethers::types::Address as EthAddress; +use fastcrypto::traits::EncodeDecodeBase64; +use iota_config::Config; +use iota_sdk::IotaClient as IotaSdkClient; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef}, + crypto::IotaKeyPair, + event::EventID, + object::Owner, + Identifier, +}; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; +use tracing::info; + +use crate::{ + crypto::BridgeAuthorityKeyPair, error::BridgeError, eth_client::EthClient, + iota_client::IotaClient, types::BridgeAction, +}; + +#[serde_as] +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct BridgeNodeConfig { + /// The port that the server listens on. + pub server_listen_port: u16, + /// The port that for metrics server. + pub metrics_port: u16, + /// Path of the file where bridge authority key (Secp256k1) is stored as + /// Base64 encoded `privkey`. + pub bridge_authority_key_path_base64_raw: PathBuf, + /// Rpc url for Iota fullnode, used for query stuff and submit transactions. + pub iota_rpc_url: String, + /// Rpc url for Eth fullnode, used for query stuff. + pub eth_rpc_url: String, + /// The eth contract addresses (hex). It must not be empty. It serves two + /// purpose: + /// 1. validator only signs bridge actions that are generated from these + /// contracts. + /// 2. for EthSyncer to watch for when `run_client` is true. + pub eth_addresses: Vec, + /// Path of the file where bridge client key (any IotaKeyPair) is stored as + /// Base64 encoded `flag || privkey`. If `run_client` is true, and this + /// is None, then use `bridge_authority_key_path_base64_raw` as client key. + #[serde(skip_serializing_if = "Option::is_none")] + pub bridge_client_key_path_base64_iota_key: Option, + /// Whether to run client. If true, + /// `bridge_client_key_path_base64_iota_key`, `bridge_client_gas_object` + /// and `db_path` needs to be provided. + pub run_client: bool, + /// The gas object to use for paying for gas fees for the client. It needs + /// to be owned by the address associated with bridge client key. + #[serde(skip_serializing_if = "Option::is_none")] + pub bridge_client_gas_object: Option, + /// Path of the client storage. Required when `run_client` is true. + #[serde(skip_serializing_if = "Option::is_none")] + pub db_path: Option, + // TODO: this should be hardcoded and removed from config + /// The iota modules of bridge packages for client to watch for. Need to + /// contain at least one item when `run_client` is true. + pub iota_bridge_modules: Option>, + // TODO: we need to hardcode the starting blocks for eth networks for cold start. + /// Override the start block number for each eth address. Key must be in + /// `eth_addresses`. When set, EthSyncer will start from this block + /// number (inclusively) instead of the one in storage. + /// Key: eth address, Value: block number to start from + /// Note: This field should be rarely used. Only use it when you understand + /// how to follow up. + #[serde(skip_serializing_if = "Option::is_none")] + pub eth_bridge_contracts_start_block_override: Option>, + /// Override the last processed EventID for each bridge module. Key must be + /// in `iota_bridge_modules`. When set, IotaSyncer will start from this + /// cursor (exclusively) instead of the one in storage. Key: iota module, + /// Value: last processed EventID (tx_digest, event_seq). Note 1: This + /// field should be rarely used. Only use it when you understand how to + /// follow up. Note 2: the EventID needs to be valid, namely it must + /// exist and matches the filter. Otherwise, it will miss one event + /// because of fullnode Event query semantics. + #[serde(skip_serializing_if = "Option::is_none")] + pub iota_bridge_modules_last_processed_event_id_override: Option>, + /// A list of approved governance actions. Action in this list will be + /// signed when requested by client. + pub approved_governance_actions: Vec, +} + +impl Config for BridgeNodeConfig {} + +impl BridgeNodeConfig { + pub async fn validate( + &self, + ) -> anyhow::Result<(BridgeServerConfig, Option)> { + let bridge_authority_key = + read_bridge_authority_key(&self.bridge_authority_key_path_base64_raw)?; + + // TODO: verify it's part of bridge committee + let iota_client = Arc::new(IotaClient::::new(&self.iota_rpc_url).await?); + + // TODO(audit-blocking): verify Iota Chain ID matches bridge Chain ID + + if self.eth_addresses.is_empty() { + return Err(anyhow!("`eth_addresses` must contain at least one address")); + } + let eth_bridge_contracts = self + .eth_addresses + .iter() + .map(|addr| EthAddress::from_str(addr)) + .collect::, _>>()?; + let eth_client = Arc::new( + EthClient::::new( + &self.eth_rpc_url, + HashSet::from_iter(eth_bridge_contracts.iter().cloned()), + ) + .await?, + ); + // TODO(audit-blocking): verify Ethereum Chain ID matches bridge Chain ID + + // Validate approved actions that must be governace actions + for action in &self.approved_governance_actions { + if !action.is_governace_action() { + return Err(anyhow::anyhow!(format!( + "{:?}", + BridgeError::ActionIsNotGovernanceAction(action.clone()) + ))); + } + } + let approved_governance_actions = self.approved_governance_actions.clone(); + + let bridge_server_config = BridgeServerConfig { + key: bridge_authority_key, + metrics_port: self.metrics_port, + server_listen_port: self.server_listen_port, + iota_client: iota_client.clone(), + eth_client: eth_client.clone(), + approved_governance_actions, + }; + + if !self.run_client { + return Ok((bridge_server_config, None)); + } + // If client is enabled, prepare client config + let bridge_client_key = if self.bridge_client_key_path_base64_iota_key.is_none() { + let bridge_client_key = + read_bridge_authority_key(&self.bridge_authority_key_path_base64_raw)?; + Ok(IotaKeyPair::from(bridge_client_key)) + } else { + read_bridge_client_key( + self.bridge_client_key_path_base64_iota_key + .as_ref() + .unwrap(), + ) + }?; + + let client_iota_address = IotaAddress::from(&bridge_client_key.public()); + info!("Bridge client iota address: {:?}", client_iota_address); + let gas_object_id = self.bridge_client_gas_object.ok_or(anyhow!( + "`bridge_client_gas_object` is required when `run_client` is true" + ))?; + let db_path = self + .db_path + .clone() + .ok_or(anyhow!("`db_path` is required when `run_client` is true"))?; + + let mut eth_bridge_contracts_start_block_override = BTreeMap::new(); + match &self.eth_bridge_contracts_start_block_override { + Some(overrides) => { + for (addr, block_number) in overrides { + let address = EthAddress::from_str(addr)?; + if eth_bridge_contracts.contains(&address) { + eth_bridge_contracts_start_block_override.insert(address, *block_number); + } else { + return Err(anyhow!( + "Override start block number for address {:?} is not in `eth_addresses`", + addr + )); + } + } + } + None => {} + } + + let iota_bridge_modules = match &self.iota_bridge_modules { + Some(modules) => { + if modules.is_empty() { + return Err(anyhow!( + "`iota_bridge_modules` is required when `run_client` is true" + )); + } + modules + .iter() + .map(|module| Identifier::from_str(module)) + .collect::, _>>() + .map_err(|e| anyhow!("Error parsing iota module: {:?}", e))? + } + None => { + return Err(anyhow!( + "`iota_bridge_modules` is required when `run_client` is true" + )); + } + }; + + let mut iota_bridge_modules_last_processed_event_id_override = BTreeMap::new(); + match &self.iota_bridge_modules_last_processed_event_id_override { + Some(overrides) => { + for (module, cursor) in overrides { + let module = Identifier::from_str(module)?; + if iota_bridge_modules.contains(&module) { + iota_bridge_modules_last_processed_event_id_override + .insert(module, *cursor); + } else { + return Err(anyhow!( + "Override start tx digest for module {:?} is not in `iota_bridge_modules`", + module + )); + } + } + } + None => {} + } + + let (gas_coin, gas_object_ref, owner) = iota_client + .get_gas_data_panic_if_not_gas(gas_object_id) + .await; + if owner != Owner::AddressOwner(client_iota_address) { + return Err(anyhow!( + "Gas object {:?} is not owned by bridge client key's associated iota address {:?}, but {:?}", + gas_object_id, + client_iota_address, + owner + )); + } + info!( + "Starting bridge client with gas object {:?}, balance: {}", + gas_object_ref.0, + gas_coin.value() + ); + let bridge_client_config = BridgeClientConfig { + iota_address: client_iota_address, + key: bridge_client_key, + gas_object_ref, + metrics_port: self.metrics_port, + iota_client: iota_client.clone(), + eth_client: eth_client.clone(), + db_path, + eth_bridge_contracts, + iota_bridge_modules, + eth_bridge_contracts_start_block_override, + iota_bridge_modules_last_processed_event_id_override, + }; + + Ok((bridge_server_config, Some(bridge_client_config))) + } +} + +pub struct BridgeServerConfig { + pub key: BridgeAuthorityKeyPair, + pub server_listen_port: u16, + pub metrics_port: u16, + pub iota_client: Arc>, + pub eth_client: Arc>, + /// A list of approved governance actions. Action in this list will be + /// signed when requested by client. + pub approved_governance_actions: Vec, +} + +// TODO: add gas balance alert threshold +pub struct BridgeClientConfig { + pub iota_address: IotaAddress, + pub key: IotaKeyPair, + pub gas_object_ref: ObjectRef, + pub metrics_port: u16, + pub iota_client: Arc>, + pub eth_client: Arc>, + pub db_path: PathBuf, + pub eth_bridge_contracts: Vec, + pub iota_bridge_modules: Vec, + pub eth_bridge_contracts_start_block_override: BTreeMap, + pub iota_bridge_modules_last_processed_event_id_override: BTreeMap, +} + +/// Read Bridge Authority key (Secp256k1KeyPair) from a file. +/// BridgeAuthority key is stored as base64 encoded `privkey`. +pub fn read_bridge_authority_key(path: &PathBuf) -> Result { + if !path.exists() { + return Err(anyhow::anyhow!( + "Bridge authority key file not found at path: {:?}", + path + )); + } + let contents = std::fs::read_to_string(path)?; + + BridgeAuthorityKeyPair::decode_base64(contents.as_str().trim()) + .map_err(|e| anyhow!("Error decoding authority key: {:?}", e)) +} + +/// Read Bridge client key (any IotaKeyPair) from a file. +/// Read from file as Base64 encoded `flag || privkey`. +pub fn read_bridge_client_key(path: &PathBuf) -> Result { + if !path.exists() { + return Err(anyhow::anyhow!( + "Bridge client key file not found at path: {:?}", + path + )); + } + let contents = std::fs::read_to_string(path)?; + + IotaKeyPair::decode_base64(contents.as_str().trim()) + .map_err(|e| anyhow!("Error decoding authority key: {:?}", e)) +} diff --git a/crates/iota-bridge/src/crypto.rs b/crates/iota-bridge/src/crypto.rs new file mode 100644 index 00000000000..1c23d9c1e37 --- /dev/null +++ b/crates/iota-bridge/src/crypto.rs @@ -0,0 +1,391 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt::{Debug, Display, Formatter}; + +use ethers::{ + core::k256::{ecdsa::VerifyingKey, elliptic_curve::sec1::ToEncodedPoint}, + types::Address as EthAddress, +}; +use fastcrypto::{ + encoding::{Encoding, Hex}, + error::FastCryptoError, + hash::{HashFunction, Keccak256}, + secp256k1::{ + recoverable::Secp256k1RecoverableSignature, Secp256k1KeyPair, Secp256k1PublicKey, + Secp256k1PublicKeyAsBytes, + }, + traits::{KeyPair, RecoverableSigner, ToFromBytes, VerifyRecoverable}, +}; +use iota_types::{base_types::ConciseableName, message_envelope::VerifiedEnvelope}; +use serde::{Deserialize, Serialize}; +use tap::TapFallible; + +use crate::{ + error::{BridgeError, BridgeResult}, + types::{BridgeAction, BridgeCommittee, SignedBridgeAction, VerifiedSignedBridgeAction}, +}; +pub type BridgeAuthorityKeyPair = Secp256k1KeyPair; +pub type BridgeAuthorityPublicKey = Secp256k1PublicKey; +pub type BridgeAuthorityRecoverableSignature = Secp256k1RecoverableSignature; + +#[derive(Ord, PartialOrd, PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)] +pub struct BridgeAuthorityPublicKeyBytes(Secp256k1PublicKeyAsBytes); + +impl BridgeAuthorityPublicKeyBytes { + pub fn to_eth_address(&self) -> EthAddress { + // unwrap: the conversion should not fail + let pubkey = VerifyingKey::from_sec1_bytes(self.as_bytes()).unwrap(); + let affine: ðers::core::k256::AffinePoint = pubkey.as_ref(); + let encoded = affine.to_encoded_point(false); + let pubkey = &encoded.as_bytes()[1..]; + assert_eq!(pubkey.len(), 64, "raw public key must be 64 bytes"); + let hash = Keccak256::digest(pubkey).digest; + EthAddress::from_slice(&hash[12..]) + } +} + +impl From<&BridgeAuthorityPublicKey> for BridgeAuthorityPublicKeyBytes { + fn from(pk: &BridgeAuthorityPublicKey) -> Self { + Self(Secp256k1PublicKeyAsBytes::from(pk)) + } +} + +impl ToFromBytes for BridgeAuthorityPublicKeyBytes { + /// Parse an object from its byte representation + fn from_bytes(bytes: &[u8]) -> Result { + let pk = BridgeAuthorityPublicKey::from_bytes(bytes)?; + Ok(Self::from(&pk)) + } + + /// Borrow a byte slice representing the serialized form of this object + fn as_bytes(&self) -> &[u8] { + self.as_ref() + } +} + +pub struct ConciseBridgeAuthorityPublicKeyBytesRef<'a>(&'a BridgeAuthorityPublicKeyBytes); + +impl Debug for ConciseBridgeAuthorityPublicKeyBytesRef<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + let s = Hex::encode(self.0.0.0.get(0..4).ok_or(std::fmt::Error)?); + write!(f, "k#{}..", s) + } +} + +impl Display for ConciseBridgeAuthorityPublicKeyBytesRef<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + Debug::fmt(self, f) + } +} + +impl AsRef<[u8]> for BridgeAuthorityPublicKeyBytes { + fn as_ref(&self) -> &[u8] { + self.0.0.as_ref() + } +} + +impl<'a> ConciseableName<'a> for BridgeAuthorityPublicKeyBytes { + type ConciseTypeRef = ConciseBridgeAuthorityPublicKeyBytesRef<'a>; + type ConciseType = String; + + fn concise(&'a self) -> ConciseBridgeAuthorityPublicKeyBytesRef<'a> { + ConciseBridgeAuthorityPublicKeyBytesRef(self) + } + + fn concise_owned(&self) -> String { + format!("{:?}", ConciseBridgeAuthorityPublicKeyBytesRef(self)) + } +} + +// TODO: include epoch ID here to reduce race conditions? +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +pub struct BridgeAuthoritySignInfo { + pub authority_pub_key: BridgeAuthorityPublicKey, + pub signature: BridgeAuthorityRecoverableSignature, +} + +impl BridgeAuthoritySignInfo { + pub fn new(msg: &BridgeAction, secret: &BridgeAuthorityKeyPair) -> Self { + let msg_bytes = msg.to_bytes(); + + Self { + authority_pub_key: secret.public().clone(), + signature: secret.sign_recoverable_with_hash::(&msg_bytes), + } + } + + pub fn verify(&self, msg: &BridgeAction, committee: &BridgeCommittee) -> BridgeResult<()> { + // 1. verify committee member is in the committee and not blocklisted + if !committee.is_active_member(&self.authority_pub_key_bytes()) { + return Err(BridgeError::InvalidBridgeAuthority( + self.authority_pub_key_bytes(), + )); + } + + // 2. verify signature + let msg_bytes = msg.to_bytes(); + + self.authority_pub_key + .verify_recoverable_with_hash::(&msg_bytes, &self.signature) + .map_err(|e| { + BridgeError::InvalidBridgeAuthoritySignature(( + self.authority_pub_key_bytes(), + e.to_string(), + )) + }) + } + + pub fn authority_pub_key_bytes(&self) -> BridgeAuthorityPublicKeyBytes { + BridgeAuthorityPublicKeyBytes::from(&self.authority_pub_key) + } +} + +/// Verifies a SignedBridgeAction (response from bridge authority to bridge +/// client) represents the right BridgeAction, and is signed by the right +/// authority. +pub fn verify_signed_bridge_action( + expected_action: &BridgeAction, + signed_action: SignedBridgeAction, + expected_signer: &BridgeAuthorityPublicKeyBytes, + committee: &BridgeCommittee, +) -> BridgeResult { + if signed_action.data() != expected_action { + return Err(BridgeError::MismatchedAction); + } + + let sig = signed_action.auth_sig(); + if &sig.authority_pub_key_bytes() != expected_signer { + return Err(BridgeError::MismatchedAuthoritySigner); + } + sig.verify(signed_action.data(), committee).tap_err(|e| { + tracing::error!( + "Failed to verify SignedBridgeEvent {:?}. Error {:?}", + signed_action, + e + ) + })?; + Ok(VerifiedEnvelope::new_from_verified(signed_action)) +} + +#[cfg(test)] +mod tests { + use std::{str::FromStr, sync::Arc}; + + use ethers::types::Address as EthAddress; + use fastcrypto::traits::{KeyPair, ToFromBytes}; + use iota_types::{base_types::IotaAddress, crypto::get_key_pair, digests::TransactionDigest}; + use prometheus::Registry; + + use super::*; + use crate::{ + events::EmittedIotaToEthTokenBridgeV1, + test_utils::{get_test_authority_and_key, get_test_iota_to_eth_bridge_action}, + types::{ + BridgeAction, BridgeAuthority, BridgeChainId, IotaToEthBridgeAction, + SignedBridgeAction, TokenId, + }, + }; + + #[test] + fn test_sign_and_verify_bridge_event_basic() -> anyhow::Result<()> { + telemetry_subscribers::init_for_testing(); + let registry = Registry::new(); + mysten_metrics::init_metrics(®istry); + + let (mut authority1, pubkey, secret) = get_test_authority_and_key(5000, 9999); + let pubkey_bytes = BridgeAuthorityPublicKeyBytes::from(&pubkey); + + let (authority2, pubkey2, _secret) = get_test_authority_and_key(5000, 9999); + let pubkey_bytes2 = BridgeAuthorityPublicKeyBytes::from(&pubkey2); + + let committee = BridgeCommittee::new(vec![authority1.clone(), authority2.clone()]).unwrap(); + + let action: BridgeAction = + get_test_iota_to_eth_bridge_action(None, Some(1), Some(1), Some(100)); + + let sig = BridgeAuthoritySignInfo::new(&action, &secret); + + let signed_action = SignedBridgeAction::new_from_data_and_sig(action.clone(), sig.clone()); + + // Verification should succeed + let _ = + verify_signed_bridge_action(&action, signed_action.clone(), &pubkey_bytes, &committee) + .unwrap(); + + // Verification should fail - mismatched signer + assert!(matches!( + verify_signed_bridge_action(&action, signed_action.clone(), &pubkey_bytes2, &committee) + .unwrap_err(), + BridgeError::MismatchedAuthoritySigner + )); + + let mismatched_action: BridgeAction = + get_test_iota_to_eth_bridge_action(None, Some(2), Some(3), Some(4)); + // Verification should fail - mismatched action + assert!(matches!( + verify_signed_bridge_action( + &mismatched_action, + signed_action.clone(), + &pubkey_bytes2, + &committee + ) + .unwrap_err(), + BridgeError::MismatchedAction, + )); + + // Signature is invalid (signed over different message), verification should + // fail + let action2: BridgeAction = + get_test_iota_to_eth_bridge_action(None, Some(3), Some(5), Some(77)); + + let invalid_sig = BridgeAuthoritySignInfo::new(&action2, &secret); + let signed_action = SignedBridgeAction::new_from_data_and_sig(action.clone(), invalid_sig); + let _ = verify_signed_bridge_action(&action, signed_action, &pubkey_bytes, &committee) + .unwrap_err(); + + // Signer is not in committee, verification should fail + let (_, kp2): (_, fastcrypto::secp256k1::Secp256k1KeyPair) = get_key_pair(); + let pubkey_bytes_2 = BridgeAuthorityPublicKeyBytes::from(kp2.public()); + let secret2 = Arc::pin(kp2); + let sig2 = BridgeAuthoritySignInfo::new(&action, &secret2); + let signed_action2 = SignedBridgeAction::new_from_data_and_sig(action.clone(), sig2); + let _ = verify_signed_bridge_action(&action, signed_action2, &pubkey_bytes_2, &committee) + .unwrap_err(); + + // Authority is blocklisted, verification should fail + authority1.is_blocklisted = true; + let committee = BridgeCommittee::new(vec![authority1, authority2]).unwrap(); + let signed_action = SignedBridgeAction::new_from_data_and_sig(action.clone(), sig); + let _ = verify_signed_bridge_action(&action, signed_action, &pubkey_bytes, &committee) + .unwrap_err(); + + Ok(()) + } + + #[test] + fn test_bridge_sig_verification_regression_test() { + telemetry_subscribers::init_for_testing(); + let registry = Registry::new(); + mysten_metrics::init_metrics(®istry); + + let public_key_bytes = + Hex::decode("02321ede33d2c2d7a8a152f275a1484edef2098f034121a602cb7d767d38680aa4") + .unwrap(); + let pubkey1 = BridgeAuthorityPublicKey::from_bytes(&public_key_bytes).unwrap(); + let authority1 = BridgeAuthority { + pubkey: pubkey1.clone(), + voting_power: 2500, + is_blocklisted: false, + base_url: "".into(), + }; + + let public_key_bytes = + Hex::decode("027f1178ff417fc9f5b8290bd8876f0a157a505a6c52db100a8492203ddd1d4279") + .unwrap(); + let pubkey2 = BridgeAuthorityPublicKey::from_bytes(&public_key_bytes).unwrap(); + let authority2 = BridgeAuthority { + pubkey: pubkey2.clone(), + voting_power: 2500, + is_blocklisted: false, + base_url: "".into(), + }; + + let public_key_bytes = + Hex::decode("026f311bcd1c2664c14277c7a80e4857c690626597064f89edc33b8f67b99c6bc0") + .unwrap(); + let pubkey3 = BridgeAuthorityPublicKey::from_bytes(&public_key_bytes).unwrap(); + let authority3 = BridgeAuthority { + pubkey: pubkey3.clone(), + voting_power: 2500, + is_blocklisted: false, + base_url: "".into(), + }; + + let public_key_bytes = + Hex::decode("03a57b85771aedeb6d31c808be9a6e73194e4b70e679608f2bca68bcc684773736") + .unwrap(); + let pubkey4 = BridgeAuthorityPublicKey::from_bytes(&public_key_bytes).unwrap(); + let authority4 = BridgeAuthority { + pubkey: pubkey4.clone(), + voting_power: 2500, + is_blocklisted: false, + base_url: "".into(), + }; + + let committee = BridgeCommittee::new(vec![ + authority1.clone(), + authority2.clone(), + authority3.clone(), + authority4.clone(), + ]) + .unwrap(); + + let action = BridgeAction::IotaToEthBridgeAction(IotaToEthBridgeAction { + iota_tx_digest: TransactionDigest::random(), + iota_tx_event_index: 0, + iota_bridge_event: EmittedIotaToEthTokenBridgeV1 { + nonce: 1, + iota_chain_id: BridgeChainId::IotaTestnet, + iota_address: IotaAddress::from_str( + "0x80ab1ee086210a3a37355300ca24672e81062fcdb5ced6618dab203f6a3b291c", + ) + .unwrap(), + eth_chain_id: BridgeChainId::EthSepolia, + eth_address: EthAddress::from_str("0xb18f79Fe671db47393315fFDB377Da4Ea1B7AF96") + .unwrap(), + token_id: TokenId::ETH, + amount: 100000u64, + }, + }); + let sig = BridgeAuthoritySignInfo { + authority_pub_key: pubkey1, + signature: BridgeAuthorityRecoverableSignature::from_bytes( + &Hex::decode("e1cf11b380855ff1d4a451ebc2fd68477cf701b7d4ec88da3082709fe95201a5061b4b60cf13815a80ba9dfead23e220506aa74c4a863ba045d95715b4cc6b6e00").unwrap(), + ).unwrap(), + }; + sig.verify(&action, &committee).unwrap(); + + let sig = BridgeAuthoritySignInfo { + authority_pub_key: pubkey4.clone(), + signature: BridgeAuthorityRecoverableSignature::from_bytes( + &Hex::decode("8ba9ec92c2d5a44ecc123182f689b901a93921fd35f581354fea20b25a0ded6d055b96a64bdda77dd5a62b93d29abe93640aa3c1a136348093cd7a2418c6bfa301").unwrap(), + ).unwrap(), + }; + sig.verify(&action, &committee).unwrap(); + + let sig = BridgeAuthoritySignInfo { + authority_pub_key: pubkey4, + signature: BridgeAuthorityRecoverableSignature::from_bytes( + // invalid sdig + &Hex::decode("8ba9ec92c2d5a44ecc123182f689b901a93921fd35f581354fea20b25a0ded6d055b96a64bdda77dd5a62b93d29abe93640aa3c1a136348093cd7a2418c6bfa302").unwrap(), + ).unwrap(), + }; + sig.verify(&action, &committee).unwrap_err(); + } + + #[test] + fn test_bridge_authority_public_key_bytes_to_eth_address() { + let pub_key_bytes = BridgeAuthorityPublicKeyBytes::from_bytes( + &Hex::decode("02321ede33d2c2d7a8a152f275a1484edef2098f034121a602cb7d767d38680aa4") + .unwrap(), + ) + .unwrap(); + let addr = "0x68b43fd906c0b8f024a18c56e06744f7c6157c65" + .parse::() + .unwrap(); + assert_eq!(pub_key_bytes.to_eth_address(), addr); + + // Example from: https://github.com/gakonst/ethers-rs/blob/master/ethers-core/src/utils/mod.rs#L1235 + let pub_key_bytes = BridgeAuthorityPublicKeyBytes::from_bytes( + &Hex::decode("0376698beebe8ee5c74d8cc50ab84ac301ee8f10af6f28d0ffd6adf4d6d3b9b762") + .unwrap(), + ) + .unwrap(); + let addr = "0Ac1dF02185025F65202660F8167210A80dD5086" + .parse::() + .unwrap(); + assert_eq!(pub_key_bytes.to_eth_address(), addr); + } +} diff --git a/crates/iota-bridge/src/error.rs b/crates/iota-bridge/src/error.rs new file mode 100644 index 00000000000..078f5e0b7c5 --- /dev/null +++ b/crates/iota-bridge/src/error.rs @@ -0,0 +1,69 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use crate::{crypto::BridgeAuthorityPublicKeyBytes, types::BridgeAction}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum BridgeError { + // The input is not an invalid transaction digest/hash + InvalidTxHash, + // The referenced transaction failed + OriginTxFailed, + // The referenced transction does not exist + TxNotFound, + // Tx is not yet finalized + TxNotFinalized, + // No recognized bridge event in specified transaction and event position + NoBridgeEventsInTxPosition, + // Found a bridge event but not in a recognized Eth bridge contract + BridgeEventInUnrecognizedEthContract, + // Found a bridge event but not in a recognized Iota bridge package + BridgeEventInUnrecognizedIotaPackage, + // Found BridgeEvent but not BridgeAction + BridgeEventNotActionable, + // Failure to serialize + BridgeSerializationError(String), + // Internal Bridge error + InternalError(String), + // Authority signature duplication + AuthoritySignatureDuplication(String), + // Too many errors when aggregating authority signatures + AuthoritySignatureAggregationTooManyError(String), + // Transient Ethereum provider error + TransientProviderError(String), + // Ethereum provider error + ProviderError(String), + // Invalid BridgeCommittee + InvalidBridgeCommittee(String), + // Invalid Bridge authority signature + InvalidBridgeAuthoritySignature((BridgeAuthorityPublicKeyBytes, String)), + // Entity is not in the Bridge committee or is blocklisted + InvalidBridgeAuthority(BridgeAuthorityPublicKeyBytes), + // Authority's base_url is invalid + InvalidAuthorityUrl(BridgeAuthorityPublicKeyBytes), + // Invalid Bridge Client request + InvalidBridgeClientRequest(String), + // Message is signed by mismatched authority + MismatchedAuthoritySigner, + // Signature is over a mismatched action + MismatchedAction, + // Action is not a governance action + ActionIsNotGovernanceAction(BridgeAction), + // Client requested an non-approved governace action + GovernanceActionIsNotApproved, + // Authority has invalid url + AuthoirtyUrlInvalid, + // Action is not token transfer + ActionIsNotTokenTransferAction, + // Iota transaction failure due to generic error + IotaTxFailureGeneric(String), + // Storage Error + StorageError(String), + // Rest API Error + RestAPIError(String), + // Uncategorized error + Generic(String), +} + +pub type BridgeResult = Result; diff --git a/crates/sui-bridge/src/eth_client.rs b/crates/iota-bridge/src/eth_client.rs similarity index 99% rename from crates/sui-bridge/src/eth_client.rs rename to crates/iota-bridge/src/eth_client.rs index 7a0adc1a4a1..15df2522a97 100644 --- a/crates/sui-bridge/src/eth_client.rs +++ b/crates/iota-bridge/src/eth_client.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::HashSet; diff --git a/crates/sui-bridge/src/eth_mock_provider.rs b/crates/iota-bridge/src/eth_mock_provider.rs similarity index 98% rename from crates/sui-bridge/src/eth_mock_provider.rs rename to crates/iota-bridge/src/eth_mock_provider.rs index f835b73839a..2d0939d7cd2 100644 --- a/crates/sui-bridge/src/eth_mock_provider.rs +++ b/crates/iota-bridge/src/eth_mock_provider.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! A mock implementation of Ethereum JSON-RPC client, based on `MockProvider` diff --git a/crates/sui-bridge/src/eth_syncer.rs b/crates/iota-bridge/src/eth_syncer.rs similarity index 99% rename from crates/sui-bridge/src/eth_syncer.rs rename to crates/iota-bridge/src/eth_syncer.rs index 7f189c17396..acab1b96755 100644 --- a/crates/sui-bridge/src/eth_syncer.rs +++ b/crates/iota-bridge/src/eth_syncer.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! The EthSyncer module is responsible for synchronizing Events emitted on diff --git a/crates/iota-bridge/src/events.rs b/crates/iota-bridge/src/events.rs new file mode 100644 index 00000000000..41fa275346c --- /dev/null +++ b/crates/iota-bridge/src/events.rs @@ -0,0 +1,256 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! This file contains the definition of the IotaBridgeEvent enum, of +//! which each variant is an emitted Event struct defind in the Move +//! Bridge module. We rely on structures in this file to decode +//! the bcs content of the emitted events. + +use std::str::FromStr; + +use ethers::types::Address as EthAddress; +use fastcrypto::encoding::{Encoding, Hex}; +use iota_json_rpc_types::IotaEvent; +use iota_types::{base_types::IotaAddress, digests::TransactionDigest}; +use move_core_types::language_storage::StructTag; +use once_cell::sync::OnceCell; +use serde::{Deserialize, Serialize}; + +use crate::{ + error::{BridgeError, BridgeResult}, + iota_transaction_builder::get_bridge_package_id, + types::{BridgeAction, BridgeActionType, BridgeChainId, IotaToEthBridgeAction, TokenId}, +}; + +// This is the event structure defined and emitted in Move +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] +pub struct MoveTokenBridgeEvent { + pub message_type: u8, + pub seq_num: u64, + pub source_chain: u8, + pub sender_address: Vec, + pub target_chain: u8, + pub target_address: Vec, + pub token_type: u8, + pub amount: u64, +} + +// Sanitized version of MoveTokenBridgeEvent +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Hash)] +pub struct EmittedIotaToEthTokenBridgeV1 { + pub nonce: u64, + pub iota_chain_id: BridgeChainId, + pub eth_chain_id: BridgeChainId, + pub iota_address: IotaAddress, + pub eth_address: EthAddress, + pub token_id: TokenId, + pub amount: u64, +} + +impl TryFrom for EmittedIotaToEthTokenBridgeV1 { + type Error = BridgeError; + + fn try_from(event: MoveTokenBridgeEvent) -> BridgeResult { + if event.message_type != BridgeActionType::TokenTransfer as u8 { + return Err(BridgeError::Generic(format!( + "Failed to convert MoveTokenBridgeEvent to EmittedIotaToEthTokenBridgeV1. Expected message type {}, got {}", + BridgeActionType::TokenTransfer as u8, + event.message_type + ))); + } + let token_id = TokenId::try_from(event.token_type).map_err(|_e| { + BridgeError::Generic(format!( + "Failed to convert MoveTokenBridgeEvent to EmittedIotaToEthTokenBridgeV1. Failed to convert token type {} to TokenId", + event.token_type, + )) + })?; + + let iota_chain_id = BridgeChainId::try_from(event.source_chain).map_err(|_e| { + BridgeError::Generic(format!( + "Failed to convert MoveTokenBridgeEvent to EmittedIotaToEthTokenBridgeV1. Failed to convert source chain {} to BridgeChainId", + event.token_type, + )) + })?; + let eth_chain_id = BridgeChainId::try_from(event.target_chain).map_err(|_e| { + BridgeError::Generic(format!( + "Failed to convert MoveTokenBridgeEvent to EmittedIotaToEthTokenBridgeV1. Failed to convert target chain {} to BridgeChainId", + event.token_type, + )) + })?; + + match iota_chain_id { + BridgeChainId::IotaMainnet + | BridgeChainId::IotaTestnet + | BridgeChainId::IotaDevnet + | BridgeChainId::IotaLocalTest => {} + _ => { + return Err(BridgeError::Generic(format!( + "Failed to convert MoveTokenBridgeEvent to EmittedIotaToEthTokenBridgeV1. Invalid source chain {}", + event.source_chain + ))); + } + } + match eth_chain_id { + BridgeChainId::EthMainnet | BridgeChainId::EthSepolia | BridgeChainId::EthLocalTest => { + } + _ => { + return Err(BridgeError::Generic(format!( + "Failed to convert MoveTokenBridgeEvent to EmittedIotaToEthTokenBridgeV1. Invalid target chain {}", + event.target_chain + ))); + } + } + + let iota_address = IotaAddress::from_bytes(event.sender_address) + .map_err(|e| BridgeError::Generic(format!("Failed to convert MoveTokenBridgeEvent to EmittedIotaToEthTokenBridgeV1. Failed to convert sender_address to IotaAddress: {:?}", e)))?; + let eth_address = EthAddress::from_str(&Hex::encode(&event.target_address))?; + + Ok(Self { + nonce: event.seq_num, + iota_chain_id, + eth_chain_id, + iota_address, + eth_address, + token_id, + amount: event.amount, + }) + } +} + +// TODO: update this once we have bridge package on iota framework +pub fn get_bridge_event_struct_tag() -> &'static str { + static BRIDGE_EVENT_STRUCT_TAG: OnceCell = OnceCell::new(); + BRIDGE_EVENT_STRUCT_TAG.get_or_init(|| { + let bridge_package_id = *get_bridge_package_id(); + format!("0x{}::bridge::TokenBridgeEvent", bridge_package_id.to_hex()) + }) +} + +crate::declare_events!( + IotaToEthTokenBridgeV1(EmittedIotaToEthTokenBridgeV1) => (get_bridge_event_struct_tag(), MoveTokenBridgeEvent) + // Add new event types here. Format: EnumVariantName(Struct) => ("StructTagString", CorrespondingMoveStruct) +); + +#[macro_export] +macro_rules! declare_events { + ($($variant:ident($type:path) => ($event_tag:expr, $event_struct:path)),* $(,)?) => { + + #[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)] + pub enum IotaBridgeEvent { + $($variant($type),)* + } + + #[allow(non_upper_case_globals)] + $(pub(crate) static $variant: OnceCell = OnceCell::new();)* + + pub(crate) fn init_all_struct_tags() { + $($variant.get_or_init(|| { + StructTag::from_str($event_tag).unwrap() + });)* + } + + // Try to convert a IotaEvent into IotaBridgeEvent + impl IotaBridgeEvent { + pub fn try_from_iota_event(event: &IotaEvent) -> BridgeResult> { + init_all_struct_tags(); // Ensure all tags are initialized + + // Unwrap safe: we inited above + $( + if &event.type_ == $variant.get().unwrap() { + let event_struct: $event_struct = bcs::from_bytes(&event.bcs).map_err(|e| BridgeError::InternalError(format!("Failed to deserialize event to {}: {:?}", stringify!($event_struct), e)))?; + return Ok(Some(IotaBridgeEvent::$variant(event_struct.try_into()?))); + } + )* + Ok(None) + } + } + }; +} + +impl IotaBridgeEvent { + pub fn try_into_bridge_action( + self, + iota_tx_digest: TransactionDigest, + iota_tx_event_index: u16, + ) -> Option { + match self { + IotaBridgeEvent::IotaToEthTokenBridgeV1(event) => { + Some(BridgeAction::IotaToEthBridgeAction(IotaToEthBridgeAction { + iota_tx_digest, + iota_tx_event_index, + iota_bridge_event: event.clone(), + })) + } + } + } +} + +#[cfg(test)] +pub mod tests { + use std::str::FromStr; + + use ethers::types::Address as EthAddress; + use iota_json_rpc_types::IotaEvent; + use iota_types::{ + base_types::{IotaAddress, ObjectID}, + digests::TransactionDigest, + event::EventID, + Identifier, + }; + use move_core_types::language_storage::StructTag; + + use super::{get_bridge_event_struct_tag, EmittedIotaToEthTokenBridgeV1, MoveTokenBridgeEvent}; + use crate::types::{ + BridgeAction, BridgeActionType, BridgeChainId, IotaToEthBridgeAction, TokenId, + }; + + /// Returns a test IotaEvent and corresponding BridgeAction + pub fn get_test_iota_event_and_action(identifier: Identifier) -> (IotaEvent, BridgeAction) { + let sanitized_event = EmittedIotaToEthTokenBridgeV1 { + nonce: 1, + iota_chain_id: BridgeChainId::IotaTestnet, + iota_address: IotaAddress::random_for_testing_only(), + eth_chain_id: BridgeChainId::EthSepolia, + eth_address: EthAddress::random(), + token_id: TokenId::Iota, + amount: 100, + }; + let emitted_event = MoveTokenBridgeEvent { + message_type: BridgeActionType::TokenTransfer as u8, + seq_num: sanitized_event.nonce, + source_chain: sanitized_event.iota_chain_id as u8, + sender_address: sanitized_event.iota_address.to_vec(), + target_chain: sanitized_event.eth_chain_id as u8, + target_address: sanitized_event.eth_address.as_bytes().to_vec(), + token_type: sanitized_event.token_id as u8, + amount: sanitized_event.amount, + }; + + let tx_digest = TransactionDigest::random(); + let event_idx = 10u16; + let bridge_action = BridgeAction::IotaToEthBridgeAction(IotaToEthBridgeAction { + iota_tx_digest: tx_digest, + iota_tx_event_index: event_idx, + iota_bridge_event: sanitized_event.clone(), + }); + let event = IotaEvent { + // For this test to pass, match what is in events.rs + type_: StructTag::from_str(get_bridge_event_struct_tag()).unwrap(), + bcs: bcs::to_bytes(&emitted_event).unwrap(), + id: EventID { + tx_digest, + event_seq: event_idx as u64, + }, + + // The following fields do not matter as of writing, + // but if tests start to fail, it's worth checking these fields. + package_id: ObjectID::ZERO, + transaction_module: identifier.clone(), + sender: IotaAddress::random_for_testing_only(), + parsed_json: serde_json::json!({"test": "test"}), + timestamp_ms: None, + }; + (event, bridge_action) + } +} diff --git a/crates/iota-bridge/src/iota_client.rs b/crates/iota-bridge/src/iota_client.rs new file mode 100644 index 00000000000..dd06ba4dc79 --- /dev/null +++ b/crates/iota-bridge/src/iota_client.rs @@ -0,0 +1,621 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// TODO remove when integrated +#![allow(unused)] + +use std::{ + str::{from_utf8, FromStr}, + time::Duration, +}; + +use anyhow::anyhow; +use async_trait::async_trait; +use axum::response::sse::Event; +use ethers::types::{Address, U256}; +use fastcrypto::traits::{KeyPair, ToFromBytes}; +use iota_json_rpc_types::{ + EventFilter, EventPage, IotaData, IotaEvent, IotaObjectDataOptions, + IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, Page, +}; +use iota_sdk::{IotaClient as IotaSdkClient, IotaClientBuilder}; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef}, + collection_types::LinkedTableNode, + crypto::get_key_pair, + digests::TransactionDigest, + dynamic_field::{DynamicFieldName, Field}, + error::{IotaObjectResponseError, UserInputError}, + event, + event::EventID, + gas_coin::GasCoin, + object::{Object, Owner}, + transaction::Transaction, + Identifier, TypeTag, +}; +use once_cell::sync::OnceCell; +use serde::{Deserialize, Serialize}; +use tap::TapFallible; +use tracing::{error, warn}; + +use crate::{ + crypto::BridgeAuthorityPublicKey, + error::{BridgeError, BridgeResult}, + events::IotaBridgeEvent, + iota_transaction_builder::get_bridge_package_id, + retry_with_max_elapsed_time, + types::{ + BridgeAction, BridgeActionStatus, BridgeAuthority, BridgeCommittee, + BridgeInnerDynamicField, BridgeRecordDyanmicField, MoveTypeBridgeCommittee, + MoveTypeBridgeInner, MoveTypeBridgeMessageKey, MoveTypeBridgeRecord, + MoveTypeCommitteeMember, + }, +}; + +// TODO: once we have bridge package on iota framework, we can hardcode the +// actual bridge dynamic field object id (not 0x9 or dynamic field wrapper) and +// update along with software upgrades. +// Or do we always retrieve from 0x9? We can figure this out before the first +// uggrade. +fn get_bridge_object_id() -> &'static ObjectID { + static BRIDGE_OBJ_ID: OnceCell = OnceCell::new(); + BRIDGE_OBJ_ID.get_or_init(|| { + let bridge_object_id = + std::env::var("BRIDGE_OBJECT_ID").expect("Expect BRIDGE_OBJECT_ID env var set"); + ObjectID::from_hex_literal(&bridge_object_id) + .expect("BRIDGE_OBJECT_ID must be a valid hex string") + }) +} + +// object id of BridgeRecord, this is wrapped in the bridge inner object. +// TODO: once we have bridge package on iota framework, we can hardcode the +// actual id. +fn get_bridge_record_id() -> &'static ObjectID { + static BRIDGE_RECORD_ID: OnceCell = OnceCell::new(); + BRIDGE_RECORD_ID.get_or_init(|| { + let bridge_record_id = + std::env::var("BRIDGE_RECORD_ID").expect("Expect BRIDGE_RECORD_ID env var set"); + ObjectID::from_hex_literal(&bridge_record_id) + .expect("BRIDGE_RECORD_ID must be a valid hex string") + }) +} + +pub struct IotaClient

    { + inner: P, +} + +impl IotaClient { + pub async fn new(rpc_url: &str) -> anyhow::Result { + let inner = IotaClientBuilder::default().build(rpc_url).await?; + let self_ = Self { inner }; + self_.describe().await?; + Ok(self_) + } +} + +impl

    IotaClient

    +where + P: IotaClientInner, +{ + pub fn new_for_testing(inner: P) -> Self { + Self { inner } + } + + // TODO assert chain identifier + async fn describe(&self) -> anyhow::Result<()> { + let chain_id = self.inner.get_chain_identifier().await?; + let block_number = self.inner.get_latest_checkpoint_sequence_number().await?; + tracing::info!( + "IotaClient is connected to chain {chain_id}, current block number: {block_number}" + ); + Ok(()) + } + + /// Query emitted Events that are defined in the given Move Module. + pub async fn query_events_by_module( + &self, + package: ObjectID, + module: Identifier, + // cursor is exclusive + cursor: EventID, + ) -> BridgeResult> { + let filter = EventFilter::MoveEventModule { + package, + module: module.clone(), + }; + let events = self.inner.query_events(filter.clone(), cursor).await?; + + // Safeguard check that all events are emitted from requested package and module + assert!( + events + .data + .iter() + .all(|event| event.type_.address.as_ref() == package.as_ref() + && event.type_.module == module) + ); + Ok(events) + } + + /// Returns BridgeAction from a Iota Transaction with transaction hash + /// and the event index. If event is declared in an unrecognized + /// package, return error. + pub async fn get_bridge_action_by_tx_digest_and_event_idx_maybe( + &self, + tx_digest: &TransactionDigest, + event_idx: u16, + ) -> BridgeResult { + let events = self.inner.get_events_by_tx_digest(*tx_digest).await?; + let event = events + .get(event_idx as usize) + .ok_or(BridgeError::NoBridgeEventsInTxPosition)?; + if event.type_.address.as_ref() != get_bridge_package_id().as_ref() { + return Err(BridgeError::BridgeEventInUnrecognizedIotaPackage); + } + let bridge_event = IotaBridgeEvent::try_from_iota_event(event)? + .ok_or(BridgeError::NoBridgeEventsInTxPosition)?; + + bridge_event + .try_into_bridge_action(*tx_digest, event_idx) + .ok_or(BridgeError::BridgeEventNotActionable) + } + + // TODO: expose this API to jsonrpc like system state query + pub async fn get_bridge_committee(&self) -> BridgeResult { + let move_type_bridge_committee = + self.inner.get_bridge_committee().await.map_err(|e| { + BridgeError::InternalError(format!("Can't get bridge committee: {e}")) + })?; + let mut authorities = vec![]; + // TODO: move this to MoveTypeBridgeCommittee + for member in move_type_bridge_committee.members.contents { + let MoveTypeCommitteeMember { + iota_address, + bridge_pubkey_bytes, + voting_power, + http_rest_url, + blocklisted, + } = member.value; + let pubkey = BridgeAuthorityPublicKey::from_bytes(&bridge_pubkey_bytes)?; + let base_url = from_utf8(&http_rest_url).unwrap_or_else(|e| { + warn!( + "Bridge authority address: {}, pubkey: {:?} has invalid http url: {:?}", + iota_address, bridge_pubkey_bytes, http_rest_url + ); + "" + }); + authorities.push(BridgeAuthority { + pubkey, + voting_power, + base_url: base_url.into(), + is_blocklisted: blocklisted, + }); + } + BridgeCommittee::new(authorities) + } + + pub async fn execute_transaction_block_with_effects( + &self, + tx: iota_types::transaction::Transaction, + ) -> BridgeResult { + self.inner.execute_transaction_block_with_effects(tx).await + } + + pub async fn get_token_transfer_action_onchain_status_until_success( + &self, + action: &BridgeAction, + ) -> BridgeActionStatus { + loop { + let Ok(Ok(status)) = retry_with_max_elapsed_time!( + self.inner.get_token_transfer_action_onchain_status(action), + Duration::from_secs(30) + ) else { + // TODO: add metrics and fire alert + error!("Failed to get action onchain status for: {:?}", action); + continue; + }; + return status; + } + } + + pub async fn get_gas_data_panic_if_not_gas( + &self, + gas_object_id: ObjectID, + ) -> (GasCoin, ObjectRef, Owner) { + self.inner + .get_gas_data_panic_if_not_gas(gas_object_id) + .await + } +} + +/// Use a trait to abstract over the IotaSDKClient and IotaMockClient for +/// testing. +#[async_trait] +pub trait IotaClientInner: Send + Sync { + type Error: Into + Send + Sync + std::error::Error + 'static; + async fn query_events( + &self, + query: EventFilter, + cursor: EventID, + ) -> Result; + + async fn get_events_by_tx_digest( + &self, + tx_digest: TransactionDigest, + ) -> Result, Self::Error>; + + async fn get_chain_identifier(&self) -> Result; + + async fn get_latest_checkpoint_sequence_number(&self) -> Result; + + async fn get_bridge_committee(&self) -> Result; + + async fn execute_transaction_block_with_effects( + &self, + tx: Transaction, + ) -> Result; + + async fn get_token_transfer_action_onchain_status( + &self, + action: &BridgeAction, + ) -> Result; + + async fn get_gas_data_panic_if_not_gas( + &self, + gas_object_id: ObjectID, + ) -> (GasCoin, ObjectRef, Owner); +} + +#[async_trait] +impl IotaClientInner for IotaSdkClient { + type Error = iota_sdk::error::Error; + + async fn query_events( + &self, + query: EventFilter, + cursor: EventID, + ) -> Result { + self.event_api() + .query_events(query, Some(cursor), None, false) + .await + } + + async fn get_events_by_tx_digest( + &self, + tx_digest: TransactionDigest, + ) -> Result, Self::Error> { + self.event_api().get_events(tx_digest).await + } + + async fn get_chain_identifier(&self) -> Result { + self.read_api().get_chain_identifier().await + } + + async fn get_latest_checkpoint_sequence_number(&self) -> Result { + self.read_api() + .get_latest_checkpoint_sequence_number() + .await + } + + // TODO: Add a test for this + async fn get_bridge_committee(&self) -> Result { + let object_id = *get_bridge_object_id(); + let bcs_bytes = self.read_api().get_move_object_bcs(object_id).await?; + let bridge_dynamic_field: BridgeInnerDynamicField = bcs::from_bytes(&bcs_bytes)?; + Ok(bridge_dynamic_field.value.committee) + } + + async fn get_token_transfer_action_onchain_status( + &self, + action: &BridgeAction, + ) -> Result { + match &action { + BridgeAction::IotaToEthBridgeAction(_) | BridgeAction::EthToIotaBridgeAction(_) => (), + _ => return Err(BridgeError::ActionIsNotTokenTransferAction), + }; + let package_id = *get_bridge_package_id(); + let key = serde_json::json!( + { + // u64 is represented as string + "bridge_seq_num": action.seq_number().to_string(), + "message_type": action.action_type() as u8, + "source_chain": action.chain_id() as u8, + } + ); + let status_object_id = match self + .read_api() + .get_dynamic_field_object( + *get_bridge_record_id(), + DynamicFieldName { + type_: TypeTag::from_str(&format!( + "{:?}::message::BridgeMessageKey", + package_id + )) + .unwrap(), + value: key.clone(), + }, + ) + .await? + .into_object() + { + Ok(object) => object.object_id, + Err(IotaObjectResponseError::DynamicFieldNotFound { .. }) => { + return Ok(BridgeActionStatus::RecordNotFound); + } + other => { + return Err(BridgeError::Generic(format!( + "Can't get bridge action record dynamic field {:?}: {:?}", + key, other + ))); + } + }; + + // get_dynamic_field_object does not return bcs, so we have to issue anothe + // query + let bcs_bytes = self + .read_api() + .get_move_object_bcs(status_object_id) + .await?; + let status_object: BridgeRecordDyanmicField = bcs::from_bytes(&bcs_bytes)?; + + if status_object.value.value.claimed { + return Ok(BridgeActionStatus::Claimed); + } + + if status_object.value.value.verified_signatures.is_some() { + return Ok(BridgeActionStatus::Approved); + } + + return Ok(BridgeActionStatus::Pending); + } + + async fn execute_transaction_block_with_effects( + &self, + tx: Transaction, + ) -> Result { + match self.quorum_driver_api().execute_transaction_block( + tx, + IotaTransactionBlockResponseOptions::new().with_effects(), + Some(iota_types::quorum_driver_types::ExecuteTransactionRequestType::WaitForEffectsCert), + ).await { + Ok(response) => Ok(response), + Err(e) => return Err(BridgeError::IotaTxFailureGeneric(e.to_string())), + } + } + + async fn get_gas_data_panic_if_not_gas( + &self, + gas_object_id: ObjectID, + ) -> (GasCoin, ObjectRef, Owner) { + loop { + match self + .read_api() + .get_object_with_options( + gas_object_id, + IotaObjectDataOptions::default().with_owner().with_content(), + ) + .await + .map(|resp| resp.data) + { + Ok(Some(gas_obj)) => { + let owner = gas_obj.owner.expect("Owner is requested"); + let gas_coin = GasCoin::try_from(&gas_obj) + .unwrap_or_else(|err| panic!("{} is not a gas coin: {err}", gas_object_id)); + return (gas_coin, gas_obj.object_ref(), owner); + } + other => { + warn!("Can't get gas object: {:?}: {:?}", gas_object_id, other); + tokio::time::sleep(Duration::from_secs(5)).await; + } + } + } + } +} + +#[cfg(test)] +mod tests { + use std::{collections::HashSet, str::FromStr}; + + use ethers::{ + abi::Token, + types::{ + Address as EthAddress, Block, BlockNumber, Filter, FilterBlockOption, Log, + ValueOrArray, U64, + }, + }; + use move_core_types::account_address::AccountAddress; + use prometheus::Registry; + use test_cluster::TestClusterBuilder; + + use super::*; + use crate::{ + events::{ + init_all_struct_tags, EmittedIotaToEthTokenBridgeV1, IotaToEthTokenBridgeV1, + MoveTokenBridgeEvent, + }, + iota_mock_client::IotaMockClient, + test_utils::{ + bridge_token, get_test_iota_to_eth_bridge_action, mint_tokens, publish_bridge_package, + transfer_treasury_cap, + }, + types::{BridgeActionType, BridgeChainId, IotaToEthBridgeAction, TokenId}, + }; + + #[tokio::test] + async fn get_bridge_action_by_tx_digest_and_event_idx_maybe() { + // Note: for random events generated in this test, we only care about + // tx_digest and event_seq, so it's ok that package and module does + // not match the query parameters. + telemetry_subscribers::init_for_testing(); + let mock_client = IotaMockClient::default(); + let iota_client = IotaClient::new_for_testing(mock_client.clone()); + let tx_digest = TransactionDigest::random(); + + // Ensure all struct tags are inited + init_all_struct_tags(); + + let sanitized_event_1 = EmittedIotaToEthTokenBridgeV1 { + nonce: 1, + iota_chain_id: BridgeChainId::IotaTestnet, + iota_address: IotaAddress::random_for_testing_only(), + eth_chain_id: BridgeChainId::EthSepolia, + eth_address: Address::random(), + token_id: TokenId::Iota, + amount: 100, + }; + let emitted_event_1 = MoveTokenBridgeEvent { + message_type: BridgeActionType::TokenTransfer as u8, + seq_num: sanitized_event_1.nonce, + source_chain: sanitized_event_1.iota_chain_id as u8, + sender_address: sanitized_event_1.iota_address.to_vec(), + target_chain: sanitized_event_1.eth_chain_id as u8, + target_address: sanitized_event_1.eth_address.as_bytes().to_vec(), + token_type: sanitized_event_1.token_id as u8, + amount: sanitized_event_1.amount, + }; + + // TODO: remove once we don't rely on env var to get package id + std::env::set_var("BRIDGE_PACKAGE_ID", "0x0b"); + + let mut iota_event_1 = IotaEvent::random_for_testing(); + iota_event_1.type_ = IotaToEthTokenBridgeV1.get().unwrap().clone(); + iota_event_1.bcs = bcs::to_bytes(&emitted_event_1).unwrap(); + + #[derive(Serialize, Deserialize)] + struct RandomStruct {}; + + let event_2: RandomStruct = RandomStruct {}; + // undeclared struct tag + let mut iota_event_2 = IotaEvent::random_for_testing(); + iota_event_2.type_ = IotaToEthTokenBridgeV1.get().unwrap().clone(); + iota_event_2.type_.module = Identifier::from_str("unrecognized_module").unwrap(); + iota_event_2.bcs = bcs::to_bytes(&event_2).unwrap(); + + // Event 3 is defined in non-bridge package + let mut iota_event_3 = iota_event_1.clone(); + iota_event_3.type_.address = AccountAddress::random(); + + mock_client.add_events_by_tx_digest( + tx_digest, + vec![ + iota_event_1.clone(), + iota_event_2.clone(), + iota_event_1.clone(), + iota_event_3.clone(), + ], + ); + let mut expected_action_1 = BridgeAction::IotaToEthBridgeAction(IotaToEthBridgeAction { + iota_tx_digest: tx_digest, + iota_tx_event_index: 0, + iota_bridge_event: sanitized_event_1.clone(), + }); + assert_eq!( + iota_client + .get_bridge_action_by_tx_digest_and_event_idx_maybe(&tx_digest, 0) + .await + .unwrap(), + expected_action_1, + ); + let mut expected_action_2 = BridgeAction::IotaToEthBridgeAction(IotaToEthBridgeAction { + iota_tx_digest: tx_digest, + iota_tx_event_index: 2, + iota_bridge_event: sanitized_event_1.clone(), + }); + assert_eq!( + iota_client + .get_bridge_action_by_tx_digest_and_event_idx_maybe(&tx_digest, 2) + .await + .unwrap(), + expected_action_2, + ); + assert!(matches!( + iota_client + .get_bridge_action_by_tx_digest_and_event_idx_maybe(&tx_digest, 1) + .await + .unwrap_err(), + BridgeError::NoBridgeEventsInTxPosition + ),); + assert!(matches!( + iota_client + .get_bridge_action_by_tx_digest_and_event_idx_maybe(&tx_digest, 3) + .await + .unwrap_err(), + BridgeError::BridgeEventInUnrecognizedIotaPackage + ),); + assert!(matches!( + iota_client + .get_bridge_action_by_tx_digest_and_event_idx_maybe(&tx_digest, 4) + .await + .unwrap_err(), + BridgeError::NoBridgeEventsInTxPosition + ),); + + // if the StructTag matches with unparsable bcs, it returns an error + iota_event_2.type_ = IotaToEthTokenBridgeV1.get().unwrap().clone(); + mock_client.add_events_by_tx_digest(tx_digest, vec![iota_event_2]); + iota_client + .get_bridge_action_by_tx_digest_and_event_idx_maybe(&tx_digest, 2) + .await + .unwrap_err(); + } + + #[tokio::test] + async fn test_get_action_onchain_status_for_iota_to_eth_transfer() { + let mut test_cluster = TestClusterBuilder::new().build().await; + let context = &mut test_cluster.wallet; + let sender = context.active_address().unwrap(); + + let treasury_caps = publish_bridge_package(context).await; + let iota_client = IotaClient::new(&test_cluster.fullnode_handle.rpc_url) + .await + .unwrap(); + + let action = get_test_iota_to_eth_bridge_action(None, None, None, None); + + let status = iota_client + .inner + .get_token_transfer_action_onchain_status(&action) + .await + .unwrap(); + assert_eq!(status, BridgeActionStatus::RecordNotFound); + + // mint 1000 USDC + let amount = 1_000_000_000u64; + let (treasury_cap_obj_ref, usdc_coin_obj_ref) = mint_tokens( + context, + treasury_caps[&TokenId::USDC], + amount, + TokenId::USDC, + ) + .await; + + transfer_treasury_cap(context, treasury_cap_obj_ref, TokenId::USDC).await; + + let recv_address = EthAddress::random(); + let bridge_event = + bridge_token(context, recv_address, usdc_coin_obj_ref, TokenId::USDC).await; + assert_eq!(bridge_event.nonce, 0); + assert_eq!(bridge_event.iota_chain_id, BridgeChainId::IotaLocalTest); + assert_eq!(bridge_event.eth_chain_id, BridgeChainId::EthLocalTest); + assert_eq!(bridge_event.eth_address, recv_address); + assert_eq!(bridge_event.iota_address, sender); + assert_eq!(bridge_event.token_id, TokenId::USDC); + assert_eq!(bridge_event.amount, amount); + + let status = iota_client + .inner + .get_token_transfer_action_onchain_status(&action) + .await + .unwrap(); + assert_eq!(status, BridgeActionStatus::Pending); + + // TODO: run bridge committee and approve the action, then assert status + // is Approved + } + + #[tokio::test] + async fn test_get_action_onchain_status_for_eth_to_iota_transfer() { + // TODO: init an eth -> iota transfer, run bridge committee, approve the + // action, then assert status is Approved/Claimed + } +} diff --git a/crates/iota-bridge/src/iota_mock_client.rs b/crates/iota-bridge/src/iota_mock_client.rs new file mode 100644 index 00000000000..41bd9b9a198 --- /dev/null +++ b/crates/iota-bridge/src/iota_mock_client.rs @@ -0,0 +1,238 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! A mock implementation of Iota JSON-RPC client. + +use std::{ + collections::{HashMap, VecDeque}, + sync::{Arc, Mutex}, +}; + +use async_trait::async_trait; +use iota_json_rpc_types::{EventFilter, EventPage, IotaEvent, IotaTransactionBlockResponse}; +use iota_types::{ + base_types::{ObjectID, ObjectRef}, + digests::TransactionDigest, + event::EventID, + gas_coin::GasCoin, + object::Owner, + transaction::Transaction, + Identifier, +}; + +use crate::{ + error::{BridgeError, BridgeResult}, + iota_client::IotaClientInner, + types::{BridgeAction, BridgeActionDigest, BridgeActionStatus, MoveTypeBridgeCommittee}, +}; + +/// Mock client used in test environments. +#[allow(clippy::type_complexity)] +#[derive(Clone, Debug)] +pub struct IotaMockClient { + // the top two fields do not change during tests so we don't need them to be Arc> + chain_identifier: String, + latest_checkpoint_sequence_number: u64, + events: Arc>>, + past_event_query_params: Arc>>, + events_by_tx_digest: + Arc, iota_sdk::error::Error>>>>, + transaction_responses: + Arc>>>, + wildcard_transaction_response: Arc>>>, + get_object_info: Arc>>, + onchain_status: Arc>>, + + requested_transactions_tx: tokio::sync::broadcast::Sender, +} + +impl IotaMockClient { + pub fn default() -> Self { + Self { + chain_identifier: "".to_string(), + latest_checkpoint_sequence_number: 0, + events: Default::default(), + past_event_query_params: Default::default(), + events_by_tx_digest: Default::default(), + transaction_responses: Default::default(), + wildcard_transaction_response: Default::default(), + get_object_info: Default::default(), + onchain_status: Default::default(), + requested_transactions_tx: tokio::sync::broadcast::channel(10000).0, + } + } + + pub fn add_event_response( + &self, + package: ObjectID, + module: Identifier, + cursor: EventID, + events: EventPage, + ) { + self.events + .lock() + .unwrap() + .insert((package, module, cursor), events); + } + + pub fn add_events_by_tx_digest(&self, tx_digest: TransactionDigest, events: Vec) { + self.events_by_tx_digest + .lock() + .unwrap() + .insert(tx_digest, Ok(events)); + } + + pub fn add_events_by_tx_digest_error(&self, tx_digest: TransactionDigest) { + self.events_by_tx_digest.lock().unwrap().insert( + tx_digest, + Err(iota_sdk::error::Error::DataError("".to_string())), + ); + } + + pub fn add_transaction_response( + &self, + tx_digest: TransactionDigest, + response: BridgeResult, + ) { + self.transaction_responses + .lock() + .unwrap() + .insert(tx_digest, response); + } + + pub fn set_action_onchain_status(&self, action: &BridgeAction, status: BridgeActionStatus) { + self.onchain_status + .lock() + .unwrap() + .insert(action.digest(), status); + } + + pub fn set_wildcard_transaction_response( + &self, + response: BridgeResult, + ) { + *self.wildcard_transaction_response.lock().unwrap() = Some(response); + } + + pub fn add_gas_object_info(&self, gas_coin: GasCoin, object_ref: ObjectRef, owner: Owner) { + self.get_object_info + .lock() + .unwrap() + .insert(object_ref.0, (gas_coin, object_ref, owner)); + } + + pub fn subscribe_to_requested_transactions( + &self, + ) -> tokio::sync::broadcast::Receiver { + self.requested_transactions_tx.subscribe() + } +} + +#[async_trait] +impl IotaClientInner for IotaMockClient { + type Error = iota_sdk::error::Error; + + // Unwraps in this function: We assume the responses are pre-populated + // by the test before calling into this function. + async fn query_events( + &self, + query: EventFilter, + cursor: EventID, + ) -> Result { + let events = self.events.lock().unwrap(); + match query { + EventFilter::MoveEventModule { package, module } => { + self.past_event_query_params.lock().unwrap().push_back(( + package, + module.clone(), + cursor, + )); + Ok(events + .get(&(package, module.clone(), cursor)) + .cloned() + .unwrap_or_else(|| { + panic!( + "No preset events found for package: {:?}, module: {:?}, cursor: {:?}", + package, module, cursor + ) + })) + } + _ => unimplemented!(), + } + } + + async fn get_events_by_tx_digest( + &self, + tx_digest: TransactionDigest, + ) -> Result, Self::Error> { + let events = self.events_by_tx_digest.lock().unwrap(); + + match events + .get(&tx_digest) + .unwrap_or_else(|| panic!("No preset events found for tx_digest: {:?}", tx_digest)) + { + Ok(events) => Ok(events.clone()), + // iota_sdk::error::Error is not Clone + Err(_) => Err(iota_sdk::error::Error::DataError("".to_string())), + } + } + + async fn get_chain_identifier(&self) -> Result { + Ok(self.chain_identifier.clone()) + } + + async fn get_latest_checkpoint_sequence_number(&self) -> Result { + Ok(self.latest_checkpoint_sequence_number) + } + + async fn get_bridge_committee(&self) -> Result { + unimplemented!() + } + + async fn get_token_transfer_action_onchain_status( + &self, + action: &BridgeAction, + ) -> Result { + Ok(self + .onchain_status + .lock() + .unwrap() + .get(&action.digest()) + .cloned() + .unwrap_or(BridgeActionStatus::Pending)) + } + + async fn execute_transaction_block_with_effects( + &self, + tx: Transaction, + ) -> Result { + self.requested_transactions_tx.send(*tx.digest()).unwrap(); + match self.transaction_responses.lock().unwrap().get(tx.digest()) { + Some(response) => response.clone(), + None => self + .wildcard_transaction_response + .lock() + .unwrap() + .clone() + .unwrap_or_else(|| panic!("No preset transaction response found for tx: {:?}", tx)), + } + } + + async fn get_gas_data_panic_if_not_gas( + &self, + gas_object_id: ObjectID, + ) -> (GasCoin, ObjectRef, Owner) { + self.get_object_info + .lock() + .unwrap() + .get(&gas_object_id) + .cloned() + .unwrap_or_else(|| { + panic!( + "No preset gas object info found for gas_object_id: {:?}", + gas_object_id + ) + }) + } +} diff --git a/crates/iota-bridge/src/iota_syncer.rs b/crates/iota-bridge/src/iota_syncer.rs new file mode 100644 index 00000000000..73dd6ccdb89 --- /dev/null +++ b/crates/iota-bridge/src/iota_syncer.rs @@ -0,0 +1,241 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! The IotaSyncer module is responsible for synchronizing Events emitted on +//! Iota blockchain from concerned bridge packages. + +use std::{collections::HashMap, sync::Arc}; + +use iota_json_rpc_types::IotaEvent; +use iota_types::{event::EventID, Identifier}; +use mysten_metrics::spawn_logged_monitored_task; +use tokio::{ + task::JoinHandle, + time::{self, Duration}, +}; + +use crate::{ + error::BridgeResult, + iota_client::{IotaClient, IotaClientInner}, + iota_transaction_builder::get_bridge_package_id, + retry_with_max_elapsed_time, +}; + +// TODO: use the right package id +// const PACKAGE_ID: ObjectID = IOTA_SYSTEM_PACKAGE_ID; +const IOTA_EVENTS_CHANNEL_SIZE: usize = 1000; + +/// Map from contract address to their start cursor (exclusive) +pub type IotaTargetModules = HashMap; + +pub struct IotaSyncer { + iota_client: Arc>, + // The last transaction that the syncer has fully processed. + // Syncer will resume post this transaction (i.e. exclusive), when it starts. + cursors: IotaTargetModules, +} + +impl IotaSyncer +where + C: IotaClientInner + 'static, +{ + pub fn new(iota_client: Arc>, cursors: IotaTargetModules) -> Self { + Self { + iota_client, + cursors, + } + } + + pub async fn run( + self, + query_interval: Duration, + ) -> BridgeResult<( + Vec>, + mysten_metrics::metered_channel::Receiver<(Identifier, Vec)>, + )> { + let (events_tx, events_rx) = mysten_metrics::metered_channel::channel( + IOTA_EVENTS_CHANNEL_SIZE, + &mysten_metrics::get_metrics() + .unwrap() + .channels + .with_label_values(&["iota_events_queue"]), + ); + + let mut task_handles = vec![]; + for (module, cursor) in self.cursors { + let events_rx_clone = events_tx.clone(); + let iota_client_clone = self.iota_client.clone(); + task_handles.push(spawn_logged_monitored_task!( + Self::run_event_listening_task( + module, + cursor, + events_rx_clone, + iota_client_clone, + query_interval + ) + )); + } + Ok((task_handles, events_rx)) + } + + async fn run_event_listening_task( + // The module where interested events are defined. + // Moudle is always of bridge package 0x9. + module: Identifier, + mut cursor: EventID, + events_sender: mysten_metrics::metered_channel::Sender<(Identifier, Vec)>, + iota_client: Arc>, + query_interval: Duration, + ) { + tracing::info!(?module, ?cursor, "Starting iota events listening task"); + let mut interval = time::interval(query_interval); + interval.set_missed_tick_behavior(time::MissedTickBehavior::Skip); + loop { + interval.tick().await; + let Ok(Ok(events)) = retry_with_max_elapsed_time!( + iota_client.query_events_by_module( + *get_bridge_package_id(), + module.clone(), + cursor + ), + Duration::from_secs(10) + ) else { + tracing::error!("Failed to query events from iota client after retry"); + continue; + }; + + let len = events.data.len(); + if len != 0 { + // Note: it's extremely critical to make sure the IotaEvents we send via this + // channel are complete per transaction level. Namely, we should + // never send a partial list of events for a transaction. + // Otherwise, we may end up missing events. See `iota_client. + // query_events_by_module` for how this is implemented. + events_sender + .send((module.clone(), events.data)) + .await + .expect("All Iota event channel receivers are closed"); + if let Some(next) = events.next_cursor { + cursor = next; + } + tracing::info!(?module, ?cursor, "Observed {len} new Iota events"); + } + } + } +} + +#[cfg(test)] +mod tests { + use iota_json_rpc_types::EventPage; + use iota_types::{digests::TransactionDigest, event::EventID, Identifier}; + use prometheus::Registry; + use tokio::time::timeout; + + use super::*; + use crate::{iota_client::IotaClient, iota_mock_client::IotaMockClient}; + + #[tokio::test] + async fn test_iota_syncer_basic() -> anyhow::Result<()> { + telemetry_subscribers::init_for_testing(); + let registry = Registry::new(); + mysten_metrics::init_metrics(®istry); + + let mock = IotaMockClient::default(); + let client = Arc::new(IotaClient::new_for_testing(mock.clone())); + let module_foo = Identifier::new("Foo").unwrap(); + let module_bar = Identifier::new("Bar").unwrap(); + let empty_events = EventPage::empty(); + let cursor = EventID { + tx_digest: TransactionDigest::random(), + event_seq: 0, + }; + add_event_response(&mock, module_foo.clone(), cursor, empty_events.clone()); + add_event_response(&mock, module_bar.clone(), cursor, empty_events.clone()); + + let target_modules = HashMap::from_iter(vec![ + (module_foo.clone(), cursor), + (module_bar.clone(), cursor), + ]); + let interval = Duration::from_millis(200); + let (_handles, mut events_rx) = IotaSyncer::new(client, target_modules) + .run(interval) + .await + .unwrap(); + + // Initially there are no events + assert_no_more_events(interval, &mut events_rx).await; + + // Module Foo has new events + let mut event_1: IotaEvent = IotaEvent::random_for_testing(); + let package_id = *get_bridge_package_id(); + event_1.type_.address = package_id.into(); + event_1.type_.module = module_foo.clone(); + let module_foo_events_1: iota_json_rpc_types::Page = EventPage { + data: vec![event_1.clone(), event_1.clone()], + next_cursor: Some(event_1.id), + has_next_page: false, + }; + add_event_response(&mock, module_foo.clone(), event_1.id, empty_events.clone()); + add_event_response( + &mock, + module_foo.clone(), + cursor, + module_foo_events_1.clone(), + ); + + let (identifier, received_events) = events_rx.recv().await.unwrap(); + assert_eq!(identifier, module_foo); + assert_eq!(received_events.len(), 2); + assert_eq!(received_events[0].id, event_1.id); + assert_eq!(received_events[1].id, event_1.id); + // No more + assert_no_more_events(interval, &mut events_rx).await; + + // Module Bar has new events + let mut event_2: IotaEvent = IotaEvent::random_for_testing(); + event_2.type_.address = package_id.into(); + event_2.type_.module = module_bar.clone(); + let module_bar_events_1 = EventPage { + data: vec![event_2.clone()], + next_cursor: Some(event_2.id), + has_next_page: false, + }; + add_event_response(&mock, module_bar.clone(), event_2.id, empty_events.clone()); + + add_event_response(&mock, module_bar.clone(), cursor, module_bar_events_1); + + let (identifier, received_events) = events_rx.recv().await.unwrap(); + assert_eq!(identifier, module_bar); + assert_eq!(received_events.len(), 1); + assert_eq!(received_events[0].id, event_2.id); + // No more + assert_no_more_events(interval, &mut events_rx).await; + + Ok(()) + } + + async fn assert_no_more_events( + interval: Duration, + events_rx: &mut mysten_metrics::metered_channel::Receiver<(Identifier, Vec)>, + ) { + match timeout(interval * 2, events_rx.recv()).await { + Err(_e) => (), + other => panic!("Should have timed out, but got: {:?}", other), + }; + } + + fn add_event_response( + mock: &IotaMockClient, + module: Identifier, + cursor: EventID, + events: EventPage, + ) { + mock.add_event_response( + *get_bridge_package_id(), + module.clone(), + cursor, + events.clone(), + ); + } +} diff --git a/crates/iota-bridge/src/iota_transaction_builder.rs b/crates/iota-bridge/src/iota_transaction_builder.rs new file mode 100644 index 00000000000..40cd2984628 --- /dev/null +++ b/crates/iota-bridge/src/iota_transaction_builder.rs @@ -0,0 +1,234 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::HashMap, str::FromStr}; + +use fastcrypto::traits::ToFromBytes; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber}, + gas_coin::GAS, + programmable_transaction_builder::ProgrammableTransactionBuilder, + transaction::{ObjectArg, TransactionData}, + TypeTag, +}; +use move_core_types::ident_str; +use once_cell::sync::OnceCell; + +use crate::{ + error::{BridgeError, BridgeResult}, + types::{BridgeAction, TokenId, VerifiedCertifiedBridgeAction}, +}; + +// TODO: once we have bridge package on iota framework, we can hardcode the +// actual package id. +pub fn get_bridge_package_id() -> &'static ObjectID { + static BRIDGE_PACKAGE_ID: OnceCell = OnceCell::new(); + BRIDGE_PACKAGE_ID.get_or_init(|| match std::env::var("BRIDGE_PACKAGE_ID") { + Ok(id) => { + ObjectID::from_hex_literal(&id).expect("BRIDGE_PACKAGE_ID must be a valid hex string") + } + Err(_) => ObjectID::from_hex_literal("0x9").unwrap(), + }) +} + +// TODO: this should be hardcoded once we have bridge package on iota framework. +pub fn get_root_bridge_object_arg() -> &'static ObjectArg { + static ROOT_BRIDGE_OBJ_ID: OnceCell = OnceCell::new(); + ROOT_BRIDGE_OBJ_ID.get_or_init(|| { + let bridge_object_id = std::env::var("ROOT_BRIDGE_OBJECT_ID") + .expect("Expect ROOT_BRIDGE_OBJECT_ID env var set"); + let object_id = ObjectID::from_hex_literal(&bridge_object_id) + .expect("ROOT_BRIDGE_OBJECT_ID must be a valid hex string"); + let initial_shared_version = std::env::var("ROOT_BRIDGE_OBJECT_INITIAL_SHARED_VERSION") + .expect("Expect ROOT_BRIDGE_OBJECT_INITIAL_SHARED_VERSION env var set") + .parse::() + .expect("ROOT_BRIDGE_OBJECT_INITIAL_SHARED_VERSION must be a valid u64"); + ObjectArg::SharedObject { + id: object_id, + initial_shared_version: SequenceNumber::from_u64(initial_shared_version), + mutable: true, + } + }) +} + +// TODO: how do we generalize this thing more? +pub fn get_iota_token_type_tag(token_id: TokenId) -> TypeTag { + static TYPE_TAGS: OnceCell> = OnceCell::new(); + let type_tags = TYPE_TAGS.get_or_init(|| { + let package_id = get_bridge_package_id(); + let mut type_tags = HashMap::new(); + type_tags.insert(TokenId::Iota, GAS::type_tag()); + type_tags.insert( + TokenId::BTC, + TypeTag::from_str(&format!("{:?}::btc::BTC", package_id)).unwrap(), + ); + type_tags.insert( + TokenId::ETH, + TypeTag::from_str(&format!("{:?}::eth::ETH", package_id)).unwrap(), + ); + type_tags.insert( + TokenId::USDC, + TypeTag::from_str(&format!("{:?}::usdc::USDC", package_id)).unwrap(), + ); + type_tags.insert( + TokenId::USDT, + TypeTag::from_str(&format!("{:?}::usdt::USDT", package_id)).unwrap(), + ); + type_tags + }); + type_tags.get(&token_id).unwrap().clone() +} + +// TODO: pass in gas price +pub fn build_transaction( + client_address: IotaAddress, + gas_object_ref: &ObjectRef, + action: VerifiedCertifiedBridgeAction, +) -> BridgeResult { + match action.data() { + BridgeAction::EthToIotaBridgeAction(_) => { + build_token_bridge_approve_transaction(client_address, gas_object_ref, action, true) + } + BridgeAction::IotaToEthBridgeAction(_) => { + build_token_bridge_approve_transaction(client_address, gas_object_ref, action, false) + } + BridgeAction::BlocklistCommitteeAction(_) => { + // TODO: handle this case + unimplemented!() + } + BridgeAction::EmergencyAction(_) => { + // TODO: handle this case + unimplemented!() + } + BridgeAction::LimitUpdateAction(_) => { + // TODO: handle this case + unimplemented!() + } + BridgeAction::AssetPriceUpdateAction(_) => { + // TODO: handle this case + unimplemented!() + } + BridgeAction::EvmContractUpgradeAction(_) => { + // TODO: handle this case + unimplemented!() + } + } +} + +// TODO: pass in gas price +fn build_token_bridge_approve_transaction( + client_address: IotaAddress, + gas_object_ref: &ObjectRef, + action: VerifiedCertifiedBridgeAction, + claim: bool, +) -> BridgeResult { + let (bridge_action, sigs) = action.into_inner().into_data_and_sig(); + let mut builder = ProgrammableTransactionBuilder::new(); + + let (source_chain, seq_num, sender, target_chain, target, token_type, amount) = + match bridge_action { + BridgeAction::IotaToEthBridgeAction(a) => { + let bridge_event = a.iota_bridge_event; + ( + bridge_event.iota_chain_id, + bridge_event.nonce, + bridge_event.iota_address.to_vec(), + bridge_event.eth_chain_id, + bridge_event.eth_address.to_fixed_bytes().to_vec(), + bridge_event.token_id, + bridge_event.amount, + ) + } + BridgeAction::EthToIotaBridgeAction(a) => { + let bridge_event = a.eth_bridge_event; + ( + bridge_event.eth_chain_id, + bridge_event.nonce, + bridge_event.eth_address.to_fixed_bytes().to_vec(), + bridge_event.iota_chain_id, + bridge_event.iota_address.to_vec(), + bridge_event.token_id, + bridge_event.amount, + ) + } + _ => unreachable!(), + }; + + let source_chain = builder.pure(source_chain as u8).unwrap(); + let seq_num = builder.pure(seq_num).unwrap(); + let sender = builder.pure(sender.clone()).map_err(|e| { + BridgeError::BridgeSerializationError(format!( + "Failed to serialize sender: {:?}. Err: {:?}", + sender, e + )) + })?; + let target_chain = builder.pure(target_chain as u8).unwrap(); + let target = builder.pure(target.clone()).map_err(|e| { + BridgeError::BridgeSerializationError(format!( + "Failed to serialize target: {:?}. Err: {:?}", + target, e + )) + })?; + let arg_token_type = builder.pure(token_type as u8).unwrap(); + let amount = builder.pure(amount).unwrap(); + + let arg_msg = builder.programmable_move_call( + *get_bridge_package_id(), + ident_str!("message").to_owned(), + ident_str!("create_token_bridge_message").to_owned(), + vec![], + vec![ + source_chain, + seq_num, + sender, + target_chain, + target, + arg_token_type, + amount, + ], + ); + + // Unwrap: this should not fail + let arg_bridge = builder.obj(*get_root_bridge_object_arg()).unwrap(); + + let mut sig_bytes = vec![]; + for (_, sig) in sigs.signatures { + sig_bytes.push(sig.as_bytes().to_vec()); + } + let arg_signatures = builder.pure(sig_bytes.clone()).map_err(|e| { + BridgeError::BridgeSerializationError(format!( + "Failed to serialize signatures: {:?}. Err: {:?}", + sig_bytes, e + )) + })?; + + builder.programmable_move_call( + *get_bridge_package_id(), + ident_str!("bridge").to_owned(), + ident_str!("approve_bridge_message").to_owned(), + vec![], + vec![arg_bridge, arg_msg, arg_signatures], + ); + + if claim { + builder.programmable_move_call( + *get_bridge_package_id(), + ident_str!("bridge").to_owned(), + ident_str!("claim_and_transfer_token").to_owned(), + vec![get_iota_token_type_tag(token_type)], + vec![arg_bridge, source_chain, seq_num], + ); + } + + let pt = builder.finish(); + + Ok(TransactionData::new_programmable( + client_address, + vec![*gas_object_ref], + pt, + 15_000_000, + // TODO: use reference gas price + 1500, + )) +} diff --git a/crates/iota-bridge/src/lib.rs b/crates/iota-bridge/src/lib.rs new file mode 100644 index 00000000000..ada332da23d --- /dev/null +++ b/crates/iota-bridge/src/lib.rs @@ -0,0 +1,96 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod abi; +pub mod action_executor; +pub mod client; +pub mod config; +pub mod crypto; +pub mod error; +pub mod eth_client; +pub mod eth_syncer; +pub mod events; +pub mod iota_client; +pub mod iota_syncer; +pub mod iota_transaction_builder; +pub mod node; +pub mod orchestrator; +pub mod server; +pub mod storage; +pub mod types; + +#[cfg(test)] +pub(crate) mod eth_mock_provider; + +#[cfg(test)] +pub(crate) mod iota_mock_client; + +#[cfg(test)] +pub(crate) mod test_utils; + +#[macro_export] +macro_rules! retry_with_max_elapsed_time { + ($func:expr, $max_elapsed_time:expr) => {{ + // The following delay sequence (in secs) will be used, applied with jitter + // 0.1, 0.2, 0.4, 0.8, 1.6, 3.2, 6.4, 12.8, 25.6, 30, 30, 30 ... + let backoff = backoff::ExponentialBackoff { + initial_interval: Duration::from_millis(100), + randomization_factor: 0.1, + multiplier: 2.0, + max_interval: Duration::from_secs(30), + max_elapsed_time: Some($max_elapsed_time), + ..Default::default() + }; + backoff::future::retry(backoff, || { + let fut = async { + let result = $func.await; + match result { + Ok(_) => { + return Ok(result); + } + Err(e) => { + // For simplicity we treat every error as transient so we can retry until + // max_elapsed_time + tracing::debug!("Retrying due to error: {:?}", e); + return Err(backoff::Error::transient(e)); + } + } + }; + std::boxed::Box::pin(fut) + }) + .await + }}; +} + +#[cfg(test)] +mod tests { + use std::time::Duration; + + use super::*; + + async fn example_func_ok() -> anyhow::Result<()> { + Ok(()) + } + + async fn example_func_err() -> anyhow::Result<()> { + Err(anyhow::anyhow!("")) + } + + #[tokio::test] + async fn test_retry_with_max_elapsed_time() { + // no retry is needed, should return immediately. We give it a very small + // max_elapsed_time and it should still finish in time. + let max_elapsed_time = Duration::from_millis(20); + retry_with_max_elapsed_time!(example_func_ok(), max_elapsed_time) + .unwrap() + .unwrap(); + + // now call a function that always errors and expect it to return before + // max_elapsed_time runs out + let max_elapsed_time = Duration::from_secs(4); + let instant = std::time::Instant::now(); + retry_with_max_elapsed_time!(example_func_err(), max_elapsed_time).unwrap_err(); + assert!(instant.elapsed() < max_elapsed_time); + } +} diff --git a/crates/iota-bridge/src/main.rs b/crates/iota-bridge/src/main.rs new file mode 100644 index 00000000000..bf95f660a86 --- /dev/null +++ b/crates/iota-bridge/src/main.rs @@ -0,0 +1,63 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + net::{IpAddr, Ipv4Addr, SocketAddr}, + path::PathBuf, +}; + +use clap::Parser; +use iota_bridge::{config::BridgeNodeConfig, node::run_bridge_node}; +use iota_config::Config; +use mysten_metrics::start_prometheus_server; +use tracing::info; + +// TODO consolidate this with iota-node/src/main.rs, but where to put it? +const GIT_REVISION: &str = { + if let Some(revision) = option_env!("GIT_REVISION") { + revision + } else { + let version = git_version::git_version!( + args = ["--always", "--abbrev=12", "--dirty", "--exclude", "*"], + fallback = "" + ); + + if version.is_empty() { + panic!("unable to query git revision"); + } + version + } +}; +const VERSION: &str = const_str::concat!(env!("CARGO_PKG_VERSION"), "-", GIT_REVISION); + +#[derive(Parser)] +#[clap(rename_all = "kebab-case")] +#[clap(name = env!("CARGO_BIN_NAME"))] +#[clap(version = VERSION)] +struct Args { + #[clap(long)] + pub config_path: PathBuf, +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let args = Args::parse(); + let config = BridgeNodeConfig::load(&args.config_path).unwrap(); + + // Init metrics server + let metrics_address = + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), config.metrics_port); + let registry_service = start_prometheus_server(metrics_address); + let prometheus_registry = registry_service.default_registry(); + mysten_metrics::init_metrics(&prometheus_registry); + info!("Metrics server started at port {}", config.metrics_port); + + // Init logging + let (_guard, _filter_handle) = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .with_prom_registry(&prometheus_registry) + .init(); + + run_bridge_node(config).await +} diff --git a/crates/iota-bridge/src/node.rs b/crates/iota-bridge/src/node.rs new file mode 100644 index 00000000000..d25347d4f47 --- /dev/null +++ b/crates/iota-bridge/src/node.rs @@ -0,0 +1,166 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::HashMap, + net::{IpAddr, Ipv4Addr, SocketAddr}, + sync::Arc, + time::Duration, +}; + +use tokio::task::JoinHandle; +use tracing::info; + +use crate::{ + action_executor::BridgeActionExecutor, + client::bridge_authority_aggregator::BridgeAuthorityAggregator, + config::{BridgeClientConfig, BridgeNodeConfig}, + eth_syncer::EthSyncer, + iota_syncer::IotaSyncer, + orchestrator::BridgeOrchestrator, + server::{handler::BridgeRequestHandler, run_server}, + storage::BridgeOrchestratorTables, +}; + +pub async fn run_bridge_node(config: BridgeNodeConfig) -> anyhow::Result<()> { + let (server_config, client_config) = config.validate().await?; + + // Start Client + let _handles = if let Some(client_config) = client_config { + start_client_components(client_config).await + } else { + Ok(vec![]) + }?; + + // Start Server + let socket_address = SocketAddr::new( + IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), + server_config.server_listen_port, + ); + run_server( + &socket_address, + BridgeRequestHandler::new( + server_config.key, + server_config.iota_client, + server_config.eth_client, + server_config.approved_governance_actions, + ), + ) + .await; + + Ok(()) +} + +// TODO: is there a way to clean up the overrides after it's stored in DB? +async fn start_client_components( + client_config: BridgeClientConfig, +) -> anyhow::Result>> { + let store: std::sync::Arc = + BridgeOrchestratorTables::new(&client_config.db_path.join("client")); + let stored_module_cursors = store + .get_iota_event_cursors(&client_config.iota_bridge_modules) + .map_err(|e| anyhow::anyhow!("Unable to get iota event cursors from storage: {e:?}"))?; + let mut iota_modules_to_watch = HashMap::new(); + for (module, cursor) in client_config + .iota_bridge_modules + .iter() + .zip(stored_module_cursors) + { + if client_config + .iota_bridge_modules_last_processed_event_id_override + .contains_key(module) + { + iota_modules_to_watch.insert( + module.clone(), + client_config.iota_bridge_modules_last_processed_event_id_override[module], + ); + info!( + "Overriding cursor for iota bridge module {} to {:?}. Stored cursor: {:?}", + module, + client_config.iota_bridge_modules_last_processed_event_id_override[module], + cursor + ); + } else if let Some(cursor) = cursor { + iota_modules_to_watch.insert(module.clone(), cursor); + } else { + return Err(anyhow::anyhow!( + "No cursor found for iota bridge module {} in storage or config override", + module + )); + } + } + + let stored_eth_cursors = store + .get_eth_event_cursors(&client_config.eth_bridge_contracts) + .map_err(|e| anyhow::anyhow!("Unable to get eth event cursors from storage: {e:?}"))?; + let mut eth_contracts_to_watch = HashMap::new(); + for (contract, cursor) in client_config + .eth_bridge_contracts + .iter() + .zip(stored_eth_cursors) + { + if client_config + .eth_bridge_contracts_start_block_override + .contains_key(contract) + { + eth_contracts_to_watch.insert( + *contract, + client_config.eth_bridge_contracts_start_block_override[contract], + ); + info!( + "Overriding cursor for eth bridge contract {} to {}. Stored cursor: {:?}", + contract, client_config.eth_bridge_contracts_start_block_override[contract], cursor + ); + } else if let Some(cursor) = cursor { + // +1: The stored value is the last block that was processed, so we start from + // the next block. + eth_contracts_to_watch.insert(*contract, cursor + 1); + } else { + return Err(anyhow::anyhow!( + "No cursor found for eth contract {} in storage or config override", + contract + )); + } + } + + let iota_client = client_config.iota_client.clone(); + + let mut all_handles = vec![]; + let (task_handles, eth_events_rx, _) = + EthSyncer::new(client_config.eth_client.clone(), eth_contracts_to_watch) + .run() + .await + .expect("Failed to start eth syncer"); + all_handles.extend(task_handles); + + let (task_handles, iota_events_rx) = + IotaSyncer::new(client_config.iota_client, iota_modules_to_watch) + .run(Duration::from_secs(2)) + .await + .expect("Failed to start iota syncer"); + all_handles.extend(task_handles); + + let committee = Arc::new( + iota_client + .get_bridge_committee() + .await + .expect("Failed to get committee"), + ); + let bridge_auth_agg = BridgeAuthorityAggregator::new(committee); + + let bridge_action_executor = BridgeActionExecutor::new( + iota_client.clone(), + Arc::new(bridge_auth_agg), + store.clone(), + client_config.key, + client_config.iota_address, + client_config.gas_object_ref.0, + ); + + let orchestrator = + BridgeOrchestrator::new(iota_client, iota_events_rx, eth_events_rx, store.clone()); + + all_handles.extend(orchestrator.run(bridge_action_executor)); + Ok(all_handles) +} diff --git a/crates/iota-bridge/src/orchestrator.rs b/crates/iota-bridge/src/orchestrator.rs new file mode 100644 index 00000000000..03755adb099 --- /dev/null +++ b/crates/iota-bridge/src/orchestrator.rs @@ -0,0 +1,423 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! `BridgeOrchestrator` is the component that: +//! 1. monitors Iota and Ethereum events with the help of `IotaSyncer` and +//! `EthSyncer` +//! 2. updates WAL table and cursor tables +//! 2. hands actions to `BridgeExecutor` for execution + +use std::sync::Arc; + +use ethers::types::Address as EthAddress; +use iota_json_rpc_types::IotaEvent; +use iota_types::Identifier; +use mysten_metrics::spawn_logged_monitored_task; +use tokio::task::JoinHandle; +use tracing::{info, warn}; + +use crate::{ + abi::EthBridgeEvent, + action_executor::{ + submit_to_executor, BridgeActionExecutionWrapper, BridgeActionExecutorTrait, + }, + error::BridgeResult, + events::IotaBridgeEvent, + iota_client::{IotaClient, IotaClientInner}, + storage::BridgeOrchestratorTables, + types::EthLog, +}; + +pub struct BridgeOrchestrator { + _iota_client: Arc>, + iota_events_rx: mysten_metrics::metered_channel::Receiver<(Identifier, Vec)>, + eth_events_rx: mysten_metrics::metered_channel::Receiver<(EthAddress, u64, Vec)>, + store: Arc, +} + +impl BridgeOrchestrator +where + C: IotaClientInner + 'static, +{ + pub fn new( + iota_client: Arc>, + iota_events_rx: mysten_metrics::metered_channel::Receiver<(Identifier, Vec)>, + eth_events_rx: mysten_metrics::metered_channel::Receiver<(EthAddress, u64, Vec)>, + store: Arc, + ) -> Self { + Self { + _iota_client: iota_client, + iota_events_rx, + eth_events_rx, + store, + } + } + + pub fn run( + self, + bridge_action_executor: impl BridgeActionExecutorTrait, + ) -> Vec> { + tracing::info!("Starting BridgeOrchestrator"); + let mut task_handles = vec![]; + let store_clone = self.store.clone(); + + // Spawn BridgeActionExecutor + let (handles, executor_sender) = bridge_action_executor.run(); + task_handles.extend(handles); + let executor_sender_clone = executor_sender.clone(); + task_handles.push(spawn_logged_monitored_task!(Self::run_iota_watcher( + store_clone, + executor_sender_clone, + self.iota_events_rx, + ))); + let store_clone = self.store.clone(); + task_handles.push(spawn_logged_monitored_task!(Self::run_eth_watcher( + store_clone, + executor_sender, + self.eth_events_rx, + ))); + // TODO: spawn bridge committee change watcher task + task_handles + } + + async fn run_iota_watcher( + store: Arc, + executor_tx: mysten_metrics::metered_channel::Sender, + mut iota_events_rx: mysten_metrics::metered_channel::Receiver<(Identifier, Vec)>, + ) { + info!("Starting iota watcher task"); + while let Some((identifier, events)) = iota_events_rx.recv().await { + if events.is_empty() { + continue; + } + + // TODO: skip events that are already processed (in DB and on chain) + + let bridge_events = events + .iter() + .map(IotaBridgeEvent::try_from_iota_event) + .collect::>>() + .expect("Iota Event could not be deserialzed to IotaBridgeEvent"); + + let mut actions = vec![]; + for (iota_event, opt_bridge_event) in events.iter().zip(bridge_events) { + if opt_bridge_event.is_none() { + // TODO: we probably should not miss any events, warn for now. + warn!("Iota event not recognized: {:?}", iota_event); + continue; + } + // Unwrap safe: checked above + let bridge_event: IotaBridgeEvent = opt_bridge_event.unwrap(); + + if let Some(action) = bridge_event + .try_into_bridge_action(iota_event.id.tx_digest, iota_event.id.event_seq as u16) + { + actions.push(action); + } + // TODO: handle non Action events + } + + if !actions.is_empty() { + // Write action to pending WAL + store + .insert_pending_actions(&actions) + .expect("Store operation should not fail"); + for action in actions { + submit_to_executor(&executor_tx, action) + .await + .expect("Submit to executor should not fail"); + } + } + + // Unwrap safe: in the beginning of the loop we checked that events is not empty + let cursor = events.last().unwrap().id; + store + .update_iota_event_cursor(identifier, cursor) + .expect("Store operation should not fail"); + } + panic!("Iota event channel was closed"); + } + + async fn run_eth_watcher( + store: Arc, + executor_tx: mysten_metrics::metered_channel::Sender, + mut eth_events_rx: mysten_metrics::metered_channel::Receiver<( + ethers::types::Address, + u64, + Vec, + )>, + ) { + info!("Starting eth watcher task"); + while let Some((contract, end_block, logs)) = eth_events_rx.recv().await { + if logs.is_empty() { + store + .update_eth_event_cursor(contract, end_block) + .expect("Store operation should not fail"); + continue; + } + + // TODO: skip events that are not already processed (in DB and on chain) + let bridge_events = logs + .iter() + .map(EthBridgeEvent::try_from_eth_log) + .collect::>(); + + let mut actions = vec![]; + for (log, opt_bridge_event) in logs.iter().zip(bridge_events) { + if opt_bridge_event.is_none() { + // TODO: we probably should not miss any events, warn for now. + warn!("Eth event not recognized: {:?}", log); + continue; + } + // Unwrap safe: checked above + let bridge_event = opt_bridge_event.unwrap(); + + if let Some(action) = + bridge_event.try_into_bridge_action(log.tx_hash, log.log_index_in_tx) + { + actions.push(action); + } + // TODO: handle non Action events + } + if !actions.is_empty() { + // Write action to pending WAL + store + .insert_pending_actions(&actions) + .expect("Store operation should not fail"); + // Execution will remove the pending actions from DB when the action is + // completed. + for action in actions { + submit_to_executor(&executor_tx, action) + .await + .expect("Submit to executor should not fail"); + } + } + + store + .update_eth_event_cursor(contract, end_block) + .expect("Store operation should not fail"); + } + panic!("Eth event channel was closed"); + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use ethers::types::{Address as EthAddress, TxHash}; + use prometheus::Registry; + + use super::*; + use crate::{ + events::tests::get_test_iota_event_and_action, iota_mock_client::IotaMockClient, + test_utils::get_test_log_and_action, types::BridgeActionDigest, + }; + + #[tokio::test] + async fn test_iota_watcher_task() { + // Note: this test may fail beacuse of the following reasons: + // the IotaEvent's struct tag does not match the ones in events.rs + + let (iota_events_tx, iota_events_rx, _eth_events_tx, eth_events_rx, iota_client, store) = + setup(); + + let (executor, mut executor_requested_action_rx) = MockExecutor::new(); + // start orchestrator + let _handles = BridgeOrchestrator::new( + Arc::new(iota_client), + iota_events_rx, + eth_events_rx, + store.clone(), + ) + .run(executor); + + let identifier = Identifier::from_str("test_iota_watcher_task").unwrap(); + let (iota_event, bridge_action) = get_test_iota_event_and_action(identifier.clone()); + iota_events_tx + .send((identifier.clone(), vec![iota_event.clone()])) + .await + .unwrap(); + + let start = std::time::Instant::now(); + // Executor should have received the action + assert_eq!( + executor_requested_action_rx.recv().await.unwrap(), + bridge_action.digest() + ); + loop { + let actions = store.get_all_pending_actions().unwrap(); + if actions.is_empty() { + if start.elapsed().as_secs() > 5 { + panic!("Timed out waiting for action to be written to WAL"); + } + tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; + continue; + } + assert_eq!(actions.len(), 1); + let action = actions.get(&bridge_action.digest()).unwrap(); + assert_eq!(action, &bridge_action); + assert_eq!( + store.get_iota_event_cursors(&[identifier]).unwrap()[0].unwrap(), + iota_event.id, + ); + break; + } + } + + #[tokio::test] + async fn test_eth_watcher_task() { + // Note: this test may fail beacuse of the following reasons: + // 1. Log and BridgeAction returned from `get_test_log_and_action` are not in + // sync + // 2. Log returned from `get_test_log_and_action` is not parseable log (not + // abigen!, check abi.rs) + + let (_iota_events_tx, iota_events_rx, eth_events_tx, eth_events_rx, iota_client, store) = + setup(); + let (executor, mut executor_requested_action_rx) = MockExecutor::new(); + // start orchestrator + let _handles = BridgeOrchestrator::new( + Arc::new(iota_client), + iota_events_rx, + eth_events_rx, + store.clone(), + ) + .run(executor); + let address = EthAddress::random(); + let (log, bridge_action) = get_test_log_and_action(address, TxHash::random(), 10); + let log_index_in_tx = 10; + let log_block_num = log.block_number.unwrap().as_u64(); + let eth_log = EthLog { + log: log.clone(), + tx_hash: log.transaction_hash.unwrap(), + block_number: log_block_num, + log_index_in_tx, + }; + let end_block_num = log_block_num + 15; + + eth_events_tx + .send((address, end_block_num, vec![eth_log.clone()])) + .await + .unwrap(); + + // Executor should have received the action + assert_eq!( + executor_requested_action_rx.recv().await.unwrap(), + bridge_action.digest() + ); + let start = std::time::Instant::now(); + loop { + let actions = store.get_all_pending_actions().unwrap(); + if actions.is_empty() { + if start.elapsed().as_secs() > 5 { + panic!("Timed out waiting for action to be written to WAL"); + } + tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; + continue; + } + assert_eq!(actions.len(), 1); + let action = actions.get(&bridge_action.digest()).unwrap(); + assert_eq!(action, &bridge_action); + assert_eq!( + store.get_eth_event_cursors(&[address]).unwrap()[0].unwrap(), + end_block_num, + ); + break; + } + } + + #[allow(clippy::type_complexity)] + fn setup() -> ( + mysten_metrics::metered_channel::Sender<(Identifier, Vec)>, + mysten_metrics::metered_channel::Receiver<(Identifier, Vec)>, + mysten_metrics::metered_channel::Sender<(EthAddress, u64, Vec)>, + mysten_metrics::metered_channel::Receiver<(EthAddress, u64, Vec)>, + IotaClient, + Arc, + ) { + telemetry_subscribers::init_for_testing(); + let registry = Registry::new(); + mysten_metrics::init_metrics(®istry); + + // TODO: remove once we don't rely on env var to get package id + std::env::set_var("BRIDGE_PACKAGE_ID", "0x0b"); + + let temp_dir = tempfile::tempdir().unwrap(); + let store = BridgeOrchestratorTables::new(temp_dir.path()); + + let mock_client = IotaMockClient::default(); + let iota_client = IotaClient::new_for_testing(mock_client.clone()); + + let (eth_events_tx, eth_events_rx) = mysten_metrics::metered_channel::channel( + 100, + &mysten_metrics::get_metrics() + .unwrap() + .channels + .with_label_values(&["unit_test_eth_events_queue"]), + ); + + let (iota_events_tx, iota_events_rx) = mysten_metrics::metered_channel::channel( + 100, + &mysten_metrics::get_metrics() + .unwrap() + .channels + .with_label_values(&["unit_test_iota_events_queue"]), + ); + + ( + iota_events_tx, + iota_events_rx, + eth_events_tx, + eth_events_rx, + iota_client, + store, + ) + } + + /// A `BridgeActionExecutorTrait` implementation that only tracks the + /// submitted actions. + struct MockExecutor { + requested_transactions_tx: tokio::sync::broadcast::Sender, + } + + impl MockExecutor { + fn new() -> (Self, tokio::sync::broadcast::Receiver) { + let (tx, rx) = tokio::sync::broadcast::channel(100); + ( + Self { + requested_transactions_tx: tx, + }, + rx, + ) + } + } + + impl BridgeActionExecutorTrait for MockExecutor { + fn run( + self, + ) -> ( + Vec>, + mysten_metrics::metered_channel::Sender, + ) { + let (tx, mut rx) = + mysten_metrics::metered_channel::channel::( + 100, + &mysten_metrics::get_metrics() + .unwrap() + .channels + .with_label_values(&["unit_test_mock_executor"]), + ); + + let handles = tokio::spawn(async move { + while let Some(action) = rx.recv().await { + self.requested_transactions_tx + .send(action.0.digest()) + .unwrap(); + } + }); + (vec![handles], tx) + } + } +} diff --git a/crates/sui-bridge/src/server/governance_verifier.rs b/crates/iota-bridge/src/server/governance_verifier.rs similarity index 91% rename from crates/sui-bridge/src/server/governance_verifier.rs rename to crates/iota-bridge/src/server/governance_verifier.rs index 180eb6b5c60..bb2443aeb64 100644 --- a/crates/sui-bridge/src/server/governance_verifier.rs +++ b/crates/iota-bridge/src/server/governance_verifier.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::HashMap; @@ -53,7 +54,7 @@ impl ActionVerifier for GovernanceVerifier { mod tests { use super::*; use crate::{ - test_utils::get_test_sui_to_eth_bridge_action, + test_utils::get_test_iota_to_eth_bridge_action, types::{ BridgeAction, BridgeChainId, EmergencyAction, EmergencyActionType, LimitUpdateAction, }, @@ -68,7 +69,7 @@ mod tests { }); let action_2 = BridgeAction::LimitUpdateAction(LimitUpdateAction { chain_id: BridgeChainId::EthLocalTest, - sending_chain_id: BridgeChainId::SuiLocalTest, + sending_chain_id: BridgeChainId::IotaLocalTest, nonce: 1, new_usd_limit: 10000, }); @@ -85,7 +86,7 @@ mod tests { let action_3 = BridgeAction::LimitUpdateAction(LimitUpdateAction { chain_id: BridgeChainId::EthLocalTest, - sending_chain_id: BridgeChainId::SuiLocalTest, + sending_chain_id: BridgeChainId::IotaLocalTest, nonce: 2, new_usd_limit: 10000, }); @@ -95,7 +96,7 @@ mod tests { ); // Token transfer action is not allowed - let action_4 = get_test_sui_to_eth_bridge_action(None, None, None, None); + let action_4 = get_test_iota_to_eth_bridge_action(None, None, None, None); assert!(matches!( GovernanceVerifier::new(vec![action_1, action_2, action_4.clone()]).unwrap_err(), BridgeError::ActionIsNotGovernanceAction(..) diff --git a/crates/sui-bridge/src/server/handler.rs b/crates/iota-bridge/src/server/handler.rs similarity index 78% rename from crates/sui-bridge/src/server/handler.rs rename to crates/iota-bridge/src/server/handler.rs index ad298887e45..05419db4b49 100644 --- a/crates/sui-bridge/src/server/handler.rs +++ b/crates/iota-bridge/src/server/handler.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #![allow(clippy::type_complexity)] @@ -8,8 +9,8 @@ use std::{num::NonZeroUsize, str::FromStr, sync::Arc}; use async_trait::async_trait; use axum::Json; use ethers::{providers::JsonRpcClient, types::TxHash}; +use iota_types::digests::TransactionDigest; use lru::LruCache; -use sui_types::digests::TransactionDigest; use tap::TapFallible; use tokio::sync::{oneshot, Mutex}; use tracing::{info, instrument}; @@ -19,14 +20,14 @@ use crate::{ crypto::{BridgeAuthorityKeyPair, BridgeAuthoritySignInfo}, error::{BridgeError, BridgeResult}, eth_client::EthClient, - sui_client::{SuiClient, SuiClientInner}, + iota_client::{IotaClient, IotaClientInner}, types::{BridgeAction, SignedBridgeAction}, }; #[async_trait] pub trait BridgeRequestHandlerTrait { /// Handles a request to sign a BridgeAction that bridges assets - /// from Ethereum to Sui. The inputs are a transaction hash on Ethereum + /// from Ethereum to Iota. The inputs are a transaction hash on Ethereum /// that emitted the bridge event and the Event index in that transaction async fn handle_eth_tx_hash( &self, @@ -34,9 +35,9 @@ pub trait BridgeRequestHandlerTrait { event_idx: u16, ) -> Result, BridgeError>; /// Handles a request to sign a BridgeAction that bridges assets - /// from Sui to Ethereum. The inputs are a transaction digest on Sui + /// from Iota to Ethereum. The inputs are a transaction digest on Iota /// that emitted the bridge event and the Event index in that transaction - async fn handle_sui_tx_digest( + async fn handle_iota_tx_digest( &self, tx_digest_base58: String, event_idx: u16, @@ -54,8 +55,8 @@ pub trait ActionVerifier: Send + Sync { async fn verify(&self, key: K) -> BridgeResult; } -struct SuiActionVerifier { - sui_client: Arc>, +struct IotaActionVerifier { + iota_client: Arc>, } struct EthActionVerifier

    { @@ -63,16 +64,16 @@ struct EthActionVerifier

    { } #[async_trait::async_trait] -impl ActionVerifier<(TransactionDigest, u16)> for SuiActionVerifier +impl ActionVerifier<(TransactionDigest, u16)> for IotaActionVerifier where - C: SuiClientInner + Send + Sync + 'static, + C: IotaClientInner + Send + Sync + 'static, { async fn verify(&self, key: (TransactionDigest, u16)) -> BridgeResult { let (tx_digest, event_idx) = key; - self.sui_client + self.iota_client .get_bridge_action_by_tx_digest_and_event_idx_maybe(&tx_digest, event_idx) .await - .tap_ok(|action| info!("Sui action found: {:?}", action)) + .tap_ok(|action| info!("Iota action found: {:?}", action)) } } @@ -167,7 +168,7 @@ where // Only cache non-transient errors BridgeError::GovernanceActionIsNotApproved { .. } | BridgeError::ActionIsNotGovernanceAction(..) - | BridgeError::BridgeEventInUnrecognizedSuiPackage + | BridgeError::BridgeEventInUnrecognizedIotaPackage | BridgeError::BridgeEventInUnrecognizedEthContract | BridgeError::BridgeEventNotActionable | BridgeError::NoBridgeEventsInTxPosition => { @@ -191,7 +192,7 @@ where } pub struct BridgeRequestHandler { - sui_signer_tx: mysten_metrics::metered_channel::Sender<( + iota_signer_tx: mysten_metrics::metered_channel::Sender<( (TransactionDigest, u16), oneshot::Sender>, )>, @@ -207,20 +208,20 @@ pub struct BridgeRequestHandler { impl BridgeRequestHandler { pub fn new< - SC: SuiClientInner + Send + Sync + 'static, + SC: IotaClientInner + Send + Sync + 'static, EP: JsonRpcClient + Send + Sync + 'static, >( signer: BridgeAuthorityKeyPair, - sui_client: Arc>, + iota_client: Arc>, eth_client: Arc>, approved_governance_actions: Vec, ) -> Self { - let (sui_signer_tx, sui_rx) = mysten_metrics::metered_channel::channel( + let (iota_signer_tx, iota_rx) = mysten_metrics::metered_channel::channel( 1000, &mysten_metrics::get_metrics() .unwrap() .channels - .with_label_values(&["server_sui_action_signing_queue"]), + .with_label_values(&["server_iota_action_signing_queue"]), ); let (eth_signer_tx, eth_rx) = mysten_metrics::metered_channel::channel( 1000, @@ -238,7 +239,7 @@ impl BridgeRequestHandler { ); let signer = Arc::new(signer); - SignerWithCache::new(signer.clone(), SuiActionVerifier { sui_client }).spawn(sui_rx); + SignerWithCache::new(signer.clone(), IotaActionVerifier { iota_client }).spawn(iota_rx); SignerWithCache::new(signer.clone(), EthActionVerifier { eth_client }).spawn(eth_rx); SignerWithCache::new( signer.clone(), @@ -247,7 +248,7 @@ impl BridgeRequestHandler { .spawn(governance_rx); Self { - sui_signer_tx, + iota_signer_tx, eth_signer_tx, governance_signer_tx, } @@ -277,19 +278,19 @@ impl BridgeRequestHandlerTrait for BridgeRequestHandler { } #[instrument(level = "info", skip(self))] - async fn handle_sui_tx_digest( + async fn handle_iota_tx_digest( &self, tx_digest_base58: String, event_idx: u16, ) -> Result, BridgeError> { - info!("Received handle sui tx request"); + info!("Received handle iota tx request"); let tx_digest = TransactionDigest::from_str(&tx_digest_base58) .map_err(|_e| BridgeError::InvalidTxHash)?; let (tx, rx) = oneshot::channel(); - self.sui_signer_tx + self.iota_signer_tx .send(((tx_digest, event_idx), tx)) .await - .unwrap_or_else(|_| panic!("Server sui signing channel is closed")); + .unwrap_or_else(|_| panic!("Server iota signing channel is closed")); let signed_action = rx .blocking_recv() .unwrap_or_else(|_| panic!("Server signing task's oneshot channel is dropped"))?; @@ -321,16 +322,16 @@ mod tests { use std::collections::HashSet; use ethers::types::{Address as EthAddress, TransactionReceipt}; - use sui_json_rpc_types::SuiEvent; - use sui_types::{base_types::SuiAddress, crypto::get_key_pair}; + use iota_json_rpc_types::IotaEvent; + use iota_types::{base_types::IotaAddress, crypto::get_key_pair}; use super::*; use crate::{ eth_mock_provider::EthMockProvider, - events::{init_all_struct_tags, MoveTokenBridgeEvent, SuiToEthTokenBridgeV1}, - sui_mock_client::SuiMockClient, + events::{init_all_struct_tags, IotaToEthTokenBridgeV1, MoveTokenBridgeEvent}, + iota_mock_client::IotaMockClient, test_utils::{ - get_test_log_and_action, get_test_sui_to_eth_bridge_action, mock_last_finalized_block, + get_test_iota_to_eth_bridge_action, get_test_log_and_action, mock_last_finalized_block, }, types::{ BridgeActionType, BridgeChainId, EmergencyAction, EmergencyActionType, @@ -339,84 +340,88 @@ mod tests { }; #[tokio::test] - async fn test_sui_signer_with_cache() { + async fn test_iota_signer_with_cache() { let (_, kp): (_, BridgeAuthorityKeyPair) = get_key_pair(); let signer = Arc::new(kp); - let sui_client_mock = SuiMockClient::default(); - let sui_verifier = SuiActionVerifier { - sui_client: Arc::new(SuiClient::new_for_testing(sui_client_mock.clone())), + let iota_client_mock = IotaMockClient::default(); + let iota_verifier = IotaActionVerifier { + iota_client: Arc::new(IotaClient::new_for_testing(iota_client_mock.clone())), }; - let mut sui_signer_with_cache = SignerWithCache::new(signer.clone(), sui_verifier); + let mut iota_signer_with_cache = SignerWithCache::new(signer.clone(), iota_verifier); // Test `get_cache_entry` creates a new entry if not exist - let sui_tx_digest = TransactionDigest::random(); - let sui_event_idx = 42; + let iota_tx_digest = TransactionDigest::random(); + let iota_event_idx = 42; assert!( - sui_signer_with_cache - .get_testing_only((sui_tx_digest, sui_event_idx)) + iota_signer_with_cache + .get_testing_only((iota_tx_digest, iota_event_idx)) .await .is_none() ); - let entry = sui_signer_with_cache - .get_cache_entry((sui_tx_digest, sui_event_idx)) + let entry = iota_signer_with_cache + .get_cache_entry((iota_tx_digest, iota_event_idx)) .await; - let entry_ = sui_signer_with_cache - .get_testing_only((sui_tx_digest, sui_event_idx)) + let entry_ = iota_signer_with_cache + .get_testing_only((iota_tx_digest, iota_event_idx)) .await; assert!(entry_.unwrap().lock().await.is_none()); - let action = - get_test_sui_to_eth_bridge_action(Some(sui_tx_digest), Some(sui_event_idx), None, None); + let action = get_test_iota_to_eth_bridge_action( + Some(iota_tx_digest), + Some(iota_event_idx), + None, + None, + ); let sig = BridgeAuthoritySignInfo::new(&action, &signer); let signed_action = SignedBridgeAction::new_from_data_and_sig(action.clone(), sig); entry.lock().await.replace(Ok(signed_action)); - let entry_ = sui_signer_with_cache - .get_testing_only((sui_tx_digest, sui_event_idx)) + let entry_ = iota_signer_with_cache + .get_testing_only((iota_tx_digest, iota_event_idx)) .await; assert!(entry_.unwrap().lock().await.is_some()); // Test `sign` caches Err result - let sui_tx_digest = TransactionDigest::random(); - let sui_event_idx = 0; + let iota_tx_digest = TransactionDigest::random(); + let iota_event_idx = 0; // Mock an non-cacheable error such as rpc error - sui_client_mock.add_events_by_tx_digest_error(sui_tx_digest); - sui_signer_with_cache - .sign((sui_tx_digest, sui_event_idx)) + iota_client_mock.add_events_by_tx_digest_error(iota_tx_digest); + iota_signer_with_cache + .sign((iota_tx_digest, iota_event_idx)) .await .unwrap_err(); - let entry_ = sui_signer_with_cache - .get_testing_only((sui_tx_digest, sui_event_idx)) + let entry_ = iota_signer_with_cache + .get_testing_only((iota_tx_digest, iota_event_idx)) .await; assert!(entry_.unwrap().lock().await.is_none()); // Mock a cacheable error such as no bridge events in tx position (empty event // list) - sui_client_mock.add_events_by_tx_digest(sui_tx_digest, vec![]); + iota_client_mock.add_events_by_tx_digest(iota_tx_digest, vec![]); assert!(matches!( - sui_signer_with_cache - .sign((sui_tx_digest, sui_event_idx)) + iota_signer_with_cache + .sign((iota_tx_digest, iota_event_idx)) .await, Err(BridgeError::NoBridgeEventsInTxPosition) )); - let entry_ = sui_signer_with_cache - .get_testing_only((sui_tx_digest, sui_event_idx)) + let entry_ = iota_signer_with_cache + .get_testing_only((iota_tx_digest, iota_event_idx)) .await; assert_eq!( entry_.unwrap().lock().await.clone().unwrap().unwrap_err(), BridgeError::NoBridgeEventsInTxPosition, ); - // TODO: test BridgeEventInUnrecognizedSuiPackage, - // SuiBridgeEvent::try_from_sui_event and BridgeEventNotActionable to be + // TODO: test BridgeEventInUnrecognizedIotaPackage, + // IotaBridgeEvent::try_from_iota_event and BridgeEventNotActionable to be // cached // Test `sign` caches Ok result let emitted_event_1 = MoveTokenBridgeEvent { message_type: BridgeActionType::TokenTransfer as u8, seq_num: 1, - source_chain: BridgeChainId::SuiLocalTest as u8, - sender_address: SuiAddress::random_for_testing_only().to_vec(), + source_chain: BridgeChainId::IotaLocalTest as u8, + sender_address: IotaAddress::random_for_testing_only().to_vec(), target_chain: BridgeChainId::EthLocalTest as u8, target_address: EthAddress::random().as_bytes().to_vec(), token_type: TokenId::USDC as u8, @@ -427,44 +432,44 @@ mod tests { std::env::set_var("BRIDGE_PACKAGE_ID", "0x0b"); init_all_struct_tags(); - let mut sui_event_1 = SuiEvent::random_for_testing(); - sui_event_1.type_ = SuiToEthTokenBridgeV1.get().unwrap().clone(); - sui_event_1.bcs = bcs::to_bytes(&emitted_event_1).unwrap(); - let sui_tx_digest = sui_event_1.id.tx_digest; + let mut iota_event_1 = IotaEvent::random_for_testing(); + iota_event_1.type_ = IotaToEthTokenBridgeV1.get().unwrap().clone(); + iota_event_1.bcs = bcs::to_bytes(&emitted_event_1).unwrap(); + let iota_tx_digest = iota_event_1.id.tx_digest; - let mut sui_event_2 = SuiEvent::random_for_testing(); - sui_event_2.type_ = SuiToEthTokenBridgeV1.get().unwrap().clone(); - sui_event_2.bcs = bcs::to_bytes(&emitted_event_1).unwrap(); - let sui_event_idx_2 = 1; - sui_client_mock.add_events_by_tx_digest(sui_tx_digest, vec![sui_event_2.clone()]); + let mut iota_event_2 = IotaEvent::random_for_testing(); + iota_event_2.type_ = IotaToEthTokenBridgeV1.get().unwrap().clone(); + iota_event_2.bcs = bcs::to_bytes(&emitted_event_1).unwrap(); + let iota_event_idx_2 = 1; + iota_client_mock.add_events_by_tx_digest(iota_tx_digest, vec![iota_event_2.clone()]); - sui_client_mock.add_events_by_tx_digest( - sui_tx_digest, - vec![sui_event_1.clone(), sui_event_2.clone()], + iota_client_mock.add_events_by_tx_digest( + iota_tx_digest, + vec![iota_event_1.clone(), iota_event_2.clone()], ); - let signed_1 = sui_signer_with_cache - .sign((sui_tx_digest, sui_event_idx)) + let signed_1 = iota_signer_with_cache + .sign((iota_tx_digest, iota_event_idx)) .await .unwrap(); - let signed_2 = sui_signer_with_cache - .sign((sui_tx_digest, sui_event_idx_2)) + let signed_2 = iota_signer_with_cache + .sign((iota_tx_digest, iota_event_idx_2)) .await .unwrap(); // Because the result is cached now, the verifier should not be called again. // Even though we remove the `add_events_by_tx_digest` mock, we will still get // the same result. - sui_client_mock.add_events_by_tx_digest(sui_tx_digest, vec![]); + iota_client_mock.add_events_by_tx_digest(iota_tx_digest, vec![]); assert_eq!( - sui_signer_with_cache - .sign((sui_tx_digest, sui_event_idx)) + iota_signer_with_cache + .sign((iota_tx_digest, iota_event_idx)) .await .unwrap(), signed_1 ); assert_eq!( - sui_signer_with_cache - .sign((sui_tx_digest, sui_event_idx_2)) + iota_signer_with_cache + .sign((iota_tx_digest, iota_event_idx_2)) .await .unwrap(), signed_2 @@ -553,7 +558,7 @@ mod tests { }); let action_2 = BridgeAction::LimitUpdateAction(LimitUpdateAction { chain_id: BridgeChainId::EthLocalTest, - sending_chain_id: BridgeChainId::SuiLocalTest, + sending_chain_id: BridgeChainId::IotaLocalTest, nonce: 1, new_usd_limit: 10000, }); @@ -607,7 +612,7 @@ mod tests { )); // Non governace action is not signable - let action_4 = get_test_sui_to_eth_bridge_action(None, None, None, None); + let action_4 = get_test_iota_to_eth_bridge_action(None, None, None, None); assert!(matches!( signer_with_cache.sign(action_4.clone()).await.unwrap_err(), BridgeError::ActionIsNotGovernanceAction(..) diff --git a/crates/sui-bridge/src/server/mock_handler.rs b/crates/iota-bridge/src/server/mock_handler.rs similarity index 80% rename from crates/sui-bridge/src/server/mock_handler.rs rename to crates/iota-bridge/src/server/mock_handler.rs index 1179ce9e24d..be17f48bb99 100644 --- a/crates/sui-bridge/src/server/mock_handler.rs +++ b/crates/iota-bridge/src/server/mock_handler.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! A mock implementation for `BridgeRequestHandlerTrait` @@ -14,7 +15,7 @@ use std::{ use arc_swap::ArcSwap; use async_trait::async_trait; use axum::Json; -use sui_types::digests::TransactionDigest; +use iota_types::digests::TransactionDigest; use super::{handler::BridgeRequestHandlerTrait, make_router}; use crate::{ @@ -27,39 +28,39 @@ use crate::{ #[derive(Clone)] pub struct BridgeRequestMockHandler { signer: Arc>>, - sui_token_events: + iota_token_events: Arc>>>, - sui_token_events_requested: Arc>>, + iota_token_events_requested: Arc>>, } impl BridgeRequestMockHandler { pub fn new() -> Self { Self { signer: Arc::new(ArcSwap::new(Arc::new(None))), - sui_token_events: Arc::new(Mutex::new(HashMap::new())), - sui_token_events_requested: Arc::new(Mutex::new(HashMap::new())), + iota_token_events: Arc::new(Mutex::new(HashMap::new())), + iota_token_events_requested: Arc::new(Mutex::new(HashMap::new())), } } - pub fn add_sui_event_response( + pub fn add_iota_event_response( &self, tx_digest: TransactionDigest, idx: u16, response: BridgeResult, ) { - self.sui_token_events + self.iota_token_events .lock() .unwrap() .insert((tx_digest, idx), response); } - pub fn get_sui_token_events_requested( + pub fn get_iota_token_events_requested( &self, tx_digest: TransactionDigest, event_index: u16, ) -> u64 { *self - .sui_token_events_requested + .iota_token_events_requested .lock() .unwrap() .get(&(tx_digest, event_index)) @@ -81,29 +82,29 @@ impl BridgeRequestHandlerTrait for BridgeRequestMockHandler { unimplemented!() } - async fn handle_sui_tx_digest( + async fn handle_iota_tx_digest( &self, tx_digest_base58: String, event_idx: u16, ) -> Result, BridgeError> { let tx_digest = TransactionDigest::from_str(&tx_digest_base58) .map_err(|_e| BridgeError::InvalidTxHash)?; - let preset = self.sui_token_events.lock().unwrap(); + let preset = self.iota_token_events.lock().unwrap(); if !preset.contains_key(&(tx_digest, event_idx)) { // Ok to panic in test panic!( - "No preset handle_sui_tx_digest result for tx_digest: {}, event_idx: {}", + "No preset handle_iota_tx_digest result for tx_digest: {}, event_idx: {}", tx_digest, event_idx ); } - let mut requested = self.sui_token_events_requested.lock().unwrap(); + let mut requested = self.iota_token_events_requested.lock().unwrap(); let entry = requested.entry((tx_digest, event_idx)).or_default(); *entry += 1; let result = preset.get(&(tx_digest, event_idx)).unwrap(); if let Err(e) = result { return Err(e.clone()); } - let signed_action: &sui_types::message_envelope::Envelope< + let signed_action: &iota_types::message_envelope::Envelope< crate::types::BridgeAction, crate::crypto::BridgeAuthoritySignInfo, > = result.as_ref().unwrap(); diff --git a/crates/iota-bridge/src/server/mod.rs b/crates/iota-bridge/src/server/mod.rs new file mode 100644 index 00000000000..a5bfaf2b10f --- /dev/null +++ b/crates/iota-bridge/src/server/mod.rs @@ -0,0 +1,364 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#![allow(clippy::inconsistent_digit_grouping)] + +use std::{net::SocketAddr, sync::Arc}; + +use axum::{ + extract::{Path, State}, + http::StatusCode, + routing::get, + Json, Router, +}; +use ethers::types::Address as EthAddress; +use fastcrypto::{ + encoding::{Encoding, Hex}, + traits::ToFromBytes, +}; + +use crate::{ + crypto::BridgeAuthorityPublicKeyBytes, + error::BridgeError, + server::handler::{BridgeRequestHandler, BridgeRequestHandlerTrait}, + types::{ + AssetPriceUpdateAction, BlocklistCommitteeAction, BlocklistType, BridgeAction, + BridgeChainId, EmergencyAction, EmergencyActionType, EvmContractUpgradeAction, + LimitUpdateAction, SignedBridgeAction, TokenId, + }, +}; + +pub mod governance_verifier; +pub mod handler; + +#[cfg(test)] +pub(crate) mod mock_handler; + +pub const APPLICATION_JSON: &str = "application/json"; + +// Important: the paths need to match the ones in bridge_client.rs +pub const ETH_TO_IOTA_TX_PATH: &str = "/sign/bridge_tx/eth/iota/:tx_hash/:event_index"; +pub const IOTA_TO_ETH_TX_PATH: &str = "/sign/bridge_tx/iota/eth/:tx_digest/:event_index"; +pub const COMMITTEE_BLOCKLIST_UPDATE_PATH: &str = + "/sign/update_committee_blocklist/:chain_id/:nonce/:type/:keys"; +pub const EMERGENCY_BUTTON_PATH: &str = "/sign/emergency_button/:chain_id/:nonce/:type"; +pub const LIMIT_UPDATE_PATH: &str = + "/sign/update_limit/:chain_id/:nonce/:sending_chain_id/:new_usd_limit"; +pub const ASSET_PRICE_UPDATE_PATH: &str = + "/sign/update_asset_price/:chain_id/:nonce/:token_id/:new_usd_price"; +pub const EVM_CONTRACT_UPGRADE_PATH_WITH_CALLDATA: &str = + "/sign/upgrade_evm_contract/:chain_id/:nonce/:proxy_address/:new_impl_address/:calldata"; +pub const EVM_CONTRACT_UPGRADE_PATH: &str = + "/sign/upgrade_evm_contract/:chain_id/:nonce/:proxy_address/:new_impl_address"; + +pub async fn run_server(socket_address: &SocketAddr, handler: BridgeRequestHandler) { + axum::Server::bind(socket_address) + .serve(make_router(Arc::new(handler)).into_make_service()) + .await + .unwrap(); +} + +pub(crate) fn make_router( + handler: Arc, +) -> Router { + Router::new() + .route("/", get(health_check)) + .route(ETH_TO_IOTA_TX_PATH, get(handle_eth_tx_hash)) + .route(IOTA_TO_ETH_TX_PATH, get(handle_iota_tx_digest)) + .route( + COMMITTEE_BLOCKLIST_UPDATE_PATH, + get(handle_update_committee_blocklist_action), + ) + .route(EMERGENCY_BUTTON_PATH, get(handle_emergecny_action)) + .route(LIMIT_UPDATE_PATH, get(handle_limit_update_action)) + .route( + ASSET_PRICE_UPDATE_PATH, + get(handle_asset_price_update_action), + ) + .route(EVM_CONTRACT_UPGRADE_PATH, get(handle_evm_contract_upgrade)) + .route( + EVM_CONTRACT_UPGRADE_PATH_WITH_CALLDATA, + get(handle_evm_contract_upgrade_with_calldata), + ) + .with_state(handler) +} + +impl axum::response::IntoResponse for BridgeError { + // TODO: distinguish client error. + fn into_response(self) -> axum::response::Response { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Something went wrong: {:?}", self), + ) + .into_response() + } +} + +impl From for BridgeError +where + E: Into, +{ + fn from(err: E) -> Self { + Self::Generic(err.into().to_string()) + } +} + +async fn health_check() -> StatusCode { + StatusCode::OK +} + +async fn handle_eth_tx_hash( + Path((tx_hash_hex, event_idx)): Path<(String, u16)>, + State(handler): State>, +) -> Result, BridgeError> { + let sig = handler.handle_eth_tx_hash(tx_hash_hex, event_idx).await?; + Ok(sig) +} + +async fn handle_iota_tx_digest( + Path((tx_digest_base58, event_idx)): Path<(String, u16)>, + State(handler): State>, +) -> Result, BridgeError> { + let sig: Json = handler + .handle_iota_tx_digest(tx_digest_base58, event_idx) + .await?; + Ok(sig) +} + +async fn handle_update_committee_blocklist_action( + Path((chain_id, nonce, blocklist_type, keys)): Path<(u8, u64, u8, String)>, + State(handler): State>, +) -> Result, BridgeError> { + let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| { + BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err)) + })?; + let blocklist_type = BlocklistType::try_from(blocklist_type).map_err(|err| { + BridgeError::InvalidBridgeClientRequest(format!("Invalid blocklist action type: {:?}", err)) + })?; + let blocklisted_members = keys + .split(',') + .map(|s| { + let bytes = Hex::decode(s).map_err(|e| anyhow::anyhow!("{:?}", e))?; + BridgeAuthorityPublicKeyBytes::from_bytes(&bytes) + .map_err(|e| anyhow::anyhow!("{:?}", e)) + }) + .collect::, _>>() + .map_err(|e| BridgeError::InvalidBridgeClientRequest(format!("{:?}", e)))?; + let action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction { + chain_id, + nonce, + blocklist_type, + blocklisted_members, + }); + + let sig: Json = handler.handle_governance_action(action).await?; + Ok(sig) +} + +async fn handle_emergecny_action( + Path((chain_id, nonce, action_type)): Path<(u8, u64, u8)>, + State(handler): State>, +) -> Result, BridgeError> { + let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| { + BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err)) + })?; + let action_type = EmergencyActionType::try_from(action_type).map_err(|err| { + BridgeError::InvalidBridgeClientRequest(format!("Invalid emergency action type: {:?}", err)) + })?; + let action = BridgeAction::EmergencyAction(EmergencyAction { + chain_id, + nonce, + action_type, + }); + let sig: Json = handler.handle_governance_action(action).await?; + Ok(sig) +} + +async fn handle_limit_update_action( + Path((chain_id, nonce, sending_chain_id, new_usd_limit)): Path<(u8, u64, u8, u64)>, + State(handler): State>, +) -> Result, BridgeError> { + let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| { + BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err)) + })?; + let sending_chain_id = BridgeChainId::try_from(sending_chain_id).map_err(|err| { + BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err)) + })?; + let action = BridgeAction::LimitUpdateAction(LimitUpdateAction { + chain_id, + nonce, + sending_chain_id, + new_usd_limit, + }); + let sig: Json = handler.handle_governance_action(action).await?; + Ok(sig) +} + +async fn handle_asset_price_update_action( + Path((chain_id, nonce, token_id, new_usd_price)): Path<(u8, u64, u8, u64)>, + State(handler): State>, +) -> Result, BridgeError> { + let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| { + BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err)) + })?; + let token_id = TokenId::try_from(token_id).map_err(|err| { + BridgeError::InvalidBridgeClientRequest(format!("Invalid token id: {:?}", err)) + })?; + let action = BridgeAction::AssetPriceUpdateAction(AssetPriceUpdateAction { + chain_id, + nonce, + token_id, + new_usd_price, + }); + let sig: Json = handler.handle_governance_action(action).await?; + Ok(sig) +} + +async fn handle_evm_contract_upgrade_with_calldata( + Path((chain_id, nonce, proxy_address, new_impl_address, calldata)): Path<( + u8, + u64, + EthAddress, + EthAddress, + String, + )>, + State(handler): State>, +) -> Result, BridgeError> { + let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| { + BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err)) + })?; + let call_data = Hex::decode(&calldata).map_err(|e| { + BridgeError::InvalidBridgeClientRequest(format!("Invalid call data: {:?}", e)) + })?; + let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { + chain_id, + nonce, + proxy_address, + new_impl_address, + call_data, + }); + let sig: Json = handler.handle_governance_action(action).await?; + Ok(sig) +} + +async fn handle_evm_contract_upgrade( + Path((chain_id, nonce, proxy_address, new_impl_address)): Path<( + u8, + u64, + EthAddress, + EthAddress, + )>, + State(handler): State>, +) -> Result, BridgeError> { + let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| { + BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err)) + })?; + let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { + chain_id, + nonce, + proxy_address, + new_impl_address, + call_data: vec![], + }); + let sig: Json = handler.handle_governance_action(action).await?; + Ok(sig) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + client::bridge_client::BridgeClient, server::mock_handler::BridgeRequestMockHandler, + test_utils::get_test_authorities_and_run_mock_bridge_server, types::BridgeCommittee, + }; + + #[tokio::test] + async fn test_bridge_server_handle_blocklist_update_action_path() { + let client = setup(); + + let pub_key_bytes = BridgeAuthorityPublicKeyBytes::from_bytes( + &Hex::decode("02321ede33d2c2d7a8a152f275a1484edef2098f034121a602cb7d767d38680aa4") + .unwrap(), + ) + .unwrap(); + let action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction { + nonce: 129, + chain_id: BridgeChainId::IotaLocalTest, + blocklist_type: BlocklistType::Blocklist, + blocklisted_members: vec![pub_key_bytes.clone()], + }); + client.request_sign_bridge_action(action).await.unwrap(); + } + + #[tokio::test] + async fn test_bridge_server_handle_emergency_action_path() { + let client = setup(); + + let action = BridgeAction::EmergencyAction(EmergencyAction { + nonce: 55, + chain_id: BridgeChainId::IotaLocalTest, + action_type: EmergencyActionType::Pause, + }); + client.request_sign_bridge_action(action).await.unwrap(); + } + + #[tokio::test] + async fn test_bridge_server_handle_limit_update_action_path() { + let client = setup(); + + let action = BridgeAction::LimitUpdateAction(LimitUpdateAction { + nonce: 15, + chain_id: BridgeChainId::IotaLocalTest, + sending_chain_id: BridgeChainId::EthLocalTest, + new_usd_limit: 1_000_000_0000, // $1M USD + }); + client.request_sign_bridge_action(action).await.unwrap(); + } + + #[tokio::test] + async fn test_bridge_server_handle_asset_price_update_action_path() { + let client = setup(); + + let action = BridgeAction::AssetPriceUpdateAction(AssetPriceUpdateAction { + nonce: 266, + chain_id: BridgeChainId::IotaLocalTest, + token_id: TokenId::BTC, + new_usd_price: 100_000_0000, // $100k USD + }); + client.request_sign_bridge_action(action).await.unwrap(); + } + + #[tokio::test] + async fn test_bridge_server_handle_evm_contract_upgrade_action_path() { + let client = setup(); + + let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { + nonce: 123, + chain_id: BridgeChainId::EthLocalTest, + proxy_address: EthAddress::repeat_byte(6), + new_impl_address: EthAddress::repeat_byte(9), + call_data: vec![], + }); + client.request_sign_bridge_action(action).await.unwrap(); + + let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { + nonce: 123, + chain_id: BridgeChainId::EthLocalTest, + proxy_address: EthAddress::repeat_byte(6), + new_impl_address: EthAddress::repeat_byte(9), + call_data: vec![12, 34, 56], + }); + client.request_sign_bridge_action(action).await.unwrap(); + } + + fn setup() -> BridgeClient { + let mock = BridgeRequestMockHandler::new(); + let (_handles, authorities, mut secrets) = + get_test_authorities_and_run_mock_bridge_server(vec![10000], vec![mock.clone()]); + mock.set_signer(secrets.swap_remove(0)); + let committee = BridgeCommittee::new(authorities).unwrap(); + let pub_key = committee.members().keys().next().unwrap(); + BridgeClient::new(pub_key.clone(), Arc::new(committee)).unwrap() + } +} diff --git a/crates/iota-bridge/src/storage.rs b/crates/iota-bridge/src/storage.rs new file mode 100644 index 00000000000..8d1f75d6434 --- /dev/null +++ b/crates/iota-bridge/src/storage.rs @@ -0,0 +1,247 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::HashMap, path::Path, sync::Arc}; + +use iota_types::{event::EventID, Identifier}; +use typed_store::{ + rocks::{DBMap, MetricConf}, + traits::{TableSummary, TypedStoreDebug}, + Map, +}; +use typed_store_derive::DBMapUtils; + +use crate::{ + error::{BridgeError, BridgeResult}, + types::{BridgeAction, BridgeActionDigest}, +}; + +#[derive(DBMapUtils)] +pub struct BridgeOrchestratorTables { + /// pending BridgeActions that orchestrator received but not yet executed + pub(crate) pending_actions: DBMap, + /// module identifier to the last processed EventID + pub(crate) iota_syncer_cursors: DBMap, + /// contract address to the last processed block + pub(crate) eth_syncer_cursors: DBMap, +} + +// TODO remove after wireup +#[allow(dead_code)] +impl BridgeOrchestratorTables { + pub fn new(path: &Path) -> Arc { + Arc::new(Self::open_tables_read_write( + path.to_path_buf(), + MetricConf::new("bridge"), + None, + None, + )) + } + + pub(crate) fn insert_pending_actions(&self, actions: &[BridgeAction]) -> BridgeResult<()> { + let mut batch = self.pending_actions.batch(); + batch + .insert_batch( + &self.pending_actions, + actions.iter().map(|a| (a.digest(), a)), + ) + .map_err(|e| { + BridgeError::StorageError(format!("Couldn't insert into pending_actions: {:?}", e)) + })?; + batch + .write() + .map_err(|e| BridgeError::StorageError(format!("Couldn't write batch: {:?}", e))) + } + + pub(crate) fn remove_pending_actions( + &self, + actions: &[BridgeActionDigest], + ) -> BridgeResult<()> { + let mut batch = self.pending_actions.batch(); + batch + .delete_batch(&self.pending_actions, actions) + .map_err(|e| { + BridgeError::StorageError(format!("Couldn't delete from pending_actions: {:?}", e)) + })?; + batch + .write() + .map_err(|e| BridgeError::StorageError(format!("Couldn't write batch: {:?}", e))) + } + + pub(crate) fn update_iota_event_cursor( + &self, + module: Identifier, + cursor: EventID, + ) -> BridgeResult<()> { + let mut batch = self.iota_syncer_cursors.batch(); + + batch + .insert_batch(&self.iota_syncer_cursors, [(module, cursor)]) + .map_err(|e| { + BridgeError::StorageError(format!( + "Coudln't insert into iota_syncer_cursors: {:?}", + e + )) + })?; + batch + .write() + .map_err(|e| BridgeError::StorageError(format!("Couldn't write batch: {:?}", e))) + } + + pub(crate) fn update_eth_event_cursor( + &self, + contract_address: ethers::types::Address, + cursor: u64, + ) -> BridgeResult<()> { + let mut batch = self.eth_syncer_cursors.batch(); + + batch + .insert_batch(&self.eth_syncer_cursors, [(contract_address, cursor)]) + .map_err(|e| { + BridgeError::StorageError(format!( + "Coudln't insert into eth_syncer_cursors: {:?}", + e + )) + })?; + batch + .write() + .map_err(|e| BridgeError::StorageError(format!("Couldn't write batch: {:?}", e))) + } + + pub fn get_all_pending_actions( + &self, + ) -> BridgeResult> { + Ok(self.pending_actions.unbounded_iter().collect()) + } + + pub fn get_iota_event_cursors( + &self, + identifiers: &[Identifier], + ) -> BridgeResult>> { + self.iota_syncer_cursors + .multi_get(identifiers) + .map_err(|e| { + BridgeError::StorageError(format!("Couldn't get iota_syncer_cursors: {:?}", e)) + }) + } + + pub fn get_eth_event_cursors( + &self, + contract_addresses: &[ethers::types::Address], + ) -> BridgeResult>> { + self.eth_syncer_cursors + .multi_get(contract_addresses) + .map_err(|e| { + BridgeError::StorageError(format!("Couldn't get iota_syncer_cursors: {:?}", e)) + }) + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use iota_types::digests::TransactionDigest; + + use super::*; + use crate::test_utils::get_test_iota_to_eth_bridge_action; + + // async: existing runtime is required with typed-store + #[tokio::test] + async fn test_bridge_storage_basic() { + let temp_dir = tempfile::tempdir().unwrap(); + let store = BridgeOrchestratorTables::new(temp_dir.path()); + + let action1 = get_test_iota_to_eth_bridge_action(None, Some(0), Some(99), Some(10000)); + + let action2 = get_test_iota_to_eth_bridge_action(None, Some(2), Some(100), Some(10000)); + + // in the beginning it's empty + let actions = store.get_all_pending_actions().unwrap(); + assert!(actions.is_empty()); + + // remove non existing entry is ok + store.remove_pending_actions(&[action1.digest()]).unwrap(); + + store + .insert_pending_actions(&vec![action1.clone(), action2.clone()]) + .unwrap(); + + let actions = store.get_all_pending_actions().unwrap(); + assert_eq!( + actions, + HashMap::from_iter(vec![ + (action1.digest(), action1.clone()), + (action2.digest(), action2.clone()) + ]) + ); + + // insert an existing action is ok + store.insert_pending_actions(&[action1.clone()]).unwrap(); + let actions = store.get_all_pending_actions().unwrap(); + assert_eq!( + actions, + HashMap::from_iter(vec![ + (action1.digest(), action1.clone()), + (action2.digest(), action2.clone()) + ]) + ); + + // remove action 2 + store.remove_pending_actions(&[action2.digest()]).unwrap(); + let actions = store.get_all_pending_actions().unwrap(); + assert_eq!( + actions, + HashMap::from_iter(vec![(action1.digest(), action1.clone())]) + ); + + // remove action 1 + store.remove_pending_actions(&[action1.digest()]).unwrap(); + let actions = store.get_all_pending_actions().unwrap(); + assert!(actions.is_empty()); + + // update eth event cursor + let eth_contract_address = ethers::types::Address::random(); + let eth_block_num = 199999u64; + assert!( + store + .get_eth_event_cursors(&[eth_contract_address]) + .unwrap()[0] + .is_none() + ); + store + .update_eth_event_cursor(eth_contract_address, eth_block_num) + .unwrap(); + assert_eq!( + store + .get_eth_event_cursors(&[eth_contract_address]) + .unwrap()[0] + .unwrap(), + eth_block_num + ); + + // update iota event cursor + let iota_module = Identifier::from_str("test").unwrap(); + let iota_cursor = EventID { + tx_digest: TransactionDigest::random(), + event_seq: 1, + }; + assert!( + store + .get_iota_event_cursors(&[iota_module.clone()]) + .unwrap()[0] + .is_none() + ); + store + .update_iota_event_cursor(iota_module.clone(), iota_cursor) + .unwrap(); + assert_eq!( + store + .get_iota_event_cursors(&[iota_module.clone()]) + .unwrap()[0] + .unwrap(), + iota_cursor + ); + } +} diff --git a/crates/iota-bridge/src/test_utils.rs b/crates/iota-bridge/src/test_utils.rs new file mode 100644 index 00000000000..11d96f83b1f --- /dev/null +++ b/crates/iota-bridge/src/test_utils.rs @@ -0,0 +1,442 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::BTreeMap, + net::{IpAddr, Ipv4Addr, SocketAddr}, + path::PathBuf, +}; + +use ethers::{ + abi::{long_signature, ParamType}, + types::{ + Address as EthAddress, Block, BlockNumber, Filter, FilterBlockOption, Log, + TransactionReceipt, TxHash, ValueOrArray, U64, + }, +}; +use fastcrypto::{ + encoding::{Encoding, Hex}, + traits::KeyPair, +}; +use hex_literal::hex; +use iota_config::local_ip_utils; +use iota_json_rpc_types::ObjectChange; +use iota_sdk::wallet_context::WalletContext; +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ + base_types::{IotaAddress, ObjectRef}, + crypto::get_key_pair, + digests::TransactionDigest, + object::Owner, + transaction::{CallArg, ObjectArg}, + IOTA_FRAMEWORK_PACKAGE_ID, +}; +use tokio::task::JoinHandle; + +use crate::{ + abi::EthToIotaTokenBridgeV1, + crypto::{BridgeAuthorityKeyPair, BridgeAuthorityPublicKey, BridgeAuthoritySignInfo}, + eth_mock_provider::EthMockProvider, + events::{EmittedIotaToEthTokenBridgeV1, IotaBridgeEvent}, + iota_transaction_builder::{ + get_bridge_package_id, get_iota_token_type_tag, get_root_bridge_object_arg, + }, + server::mock_handler::{run_mock_server, BridgeRequestMockHandler}, + types::{ + BridgeAction, BridgeAuthority, BridgeChainId, BridgeInnerDynamicField, + EthToIotaBridgeAction, IotaToEthBridgeAction, SignedBridgeAction, TokenId, + }, +}; + +pub fn get_test_authority_and_key( + voting_power: u64, + port: u16, +) -> ( + BridgeAuthority, + BridgeAuthorityPublicKey, + BridgeAuthorityKeyPair, +) { + let (_, kp): (_, fastcrypto::secp256k1::Secp256k1KeyPair) = get_key_pair(); + let pubkey = kp.public().clone(); + let authority = BridgeAuthority { + pubkey: pubkey.clone(), + voting_power, + base_url: format!("http://127.0.0.1:{}", port), + is_blocklisted: false, + }; + + (authority, pubkey, kp) +} + +pub fn get_test_iota_to_eth_bridge_action( + iota_tx_digest: Option, + iota_tx_event_index: Option, + nonce: Option, + amount: Option, +) -> BridgeAction { + BridgeAction::IotaToEthBridgeAction(IotaToEthBridgeAction { + iota_tx_digest: iota_tx_digest.unwrap_or_else(TransactionDigest::random), + iota_tx_event_index: iota_tx_event_index.unwrap_or(0), + iota_bridge_event: EmittedIotaToEthTokenBridgeV1 { + nonce: nonce.unwrap_or_default(), + iota_chain_id: BridgeChainId::IotaLocalTest, + iota_address: IotaAddress::random_for_testing_only(), + eth_chain_id: BridgeChainId::EthLocalTest, + eth_address: EthAddress::random(), + token_id: TokenId::Iota, + amount: amount.unwrap_or(100_000), + }, + }) +} + +pub fn run_mock_bridge_server( + mock_handlers: Vec, +) -> (Vec>, Vec) { + let mut handles = vec![]; + let mut ports = vec![]; + for mock_handler in mock_handlers { + let localhost = local_ip_utils::localhost_for_testing(); + let port = local_ip_utils::get_available_port(&localhost); + // start server + let server_handle = run_mock_server( + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port), + mock_handler.clone(), + ); + ports.push(port); + handles.push(server_handle); + } + (handles, ports) +} + +pub fn get_test_authorities_and_run_mock_bridge_server( + voting_power: Vec, + mock_handlers: Vec, +) -> ( + Vec>, + Vec, + Vec, +) { + assert_eq!(voting_power.len(), mock_handlers.len()); + let (handles, ports) = run_mock_bridge_server(mock_handlers); + let mut authorites = vec![]; + let mut secrets = vec![]; + for (port, vp) in ports.iter().zip(voting_power) { + let (authority, _, secret) = get_test_authority_and_key(vp, *port); + authorites.push(authority); + secrets.push(secret); + } + + (handles, authorites, secrets) +} + +pub fn sign_action_with_key( + action: &BridgeAction, + secret: &BridgeAuthorityKeyPair, +) -> SignedBridgeAction { + let sig = BridgeAuthoritySignInfo::new(action, secret); + SignedBridgeAction::new_from_data_and_sig(action.clone(), sig) +} + +pub fn mock_last_finalized_block(mock_provider: &EthMockProvider, block_number: u64) { + let block = Block:: { + number: Some(U64::from(block_number)), + ..Default::default() + }; + mock_provider + .add_response("eth_getBlockByNumber", ("finalized", false), block) + .unwrap(); +} + +// Mocks eth_getLogs and eth_getTransactionReceipt for the given address and +// block range. The input log needs to have transaction_hash set. +pub fn mock_get_logs( + mock_provider: &EthMockProvider, + address: EthAddress, + from_block: u64, + to_block: u64, + logs: Vec, +) { + mock_provider.add_response::<[ethers::types::Filter; 1], Vec, Vec>( + "eth_getLogs", + [ + Filter { + block_option: FilterBlockOption::Range { + from_block: Some(BlockNumber::Number(U64::from(from_block))), + to_block: Some(BlockNumber::Number(U64::from(to_block))), + }, + address: Some(ValueOrArray::Value(address)), + topics: [None, None, None, None], + } + ], + logs.clone(), + ).unwrap(); + + for log in logs { + mock_provider + .add_response::<[TxHash; 1], TransactionReceipt, TransactionReceipt>( + "eth_getTransactionReceipt", + [log.transaction_hash.unwrap()], + TransactionReceipt { + block_number: log.block_number, + logs: vec![log], + ..Default::default() + }, + ) + .unwrap(); + } +} + +/// Returns a test Log and corresponding BridgeAction +// Refernece: https://github.com/rust-ethereum/ethabi/blob/master/ethabi/src/event.rs#L192 +pub fn get_test_log_and_action( + contract_address: EthAddress, + tx_hash: TxHash, + event_index: u16, +) -> (Log, BridgeAction) { + let token_code = 3u8; + let amount = 10000000u64; + let source_address = EthAddress::random(); + let iota_address: IotaAddress = IotaAddress::random_for_testing_only(); + let target_address = Hex::decode(&iota_address.to_string()).unwrap(); + // Note: must use `encode` rather than `encode_packged` + let encoded = ethers::abi::encode(&[ + // u8 is encoded as u256 in abi standard + ethers::abi::Token::Uint(ethers::types::U256::from(token_code)), + ethers::abi::Token::Uint(ethers::types::U256::from(amount)), + ethers::abi::Token::Address(source_address), + ethers::abi::Token::Bytes(target_address.clone()), + ]); + let log = Log { + address: contract_address, + topics: vec![ + long_signature( + "TokensBridgedToIota", + &[ + ParamType::Uint(8), + ParamType::Uint(64), + ParamType::Uint(8), + ParamType::Uint(8), + ParamType::Uint(64), + ParamType::Address, + ParamType::Bytes, + ], + ), + hex!("0000000000000000000000000000000000000000000000000000000000000001").into(), /* chain id: iota testnet */ + hex!("0000000000000000000000000000000000000000000000000000000000000010").into(), /* nonce: 16 */ + hex!("000000000000000000000000000000000000000000000000000000000000000b").into(), /* chain id: sepolia */ + ], + data: encoded.into(), + block_hash: Some(TxHash::random()), + block_number: Some(1.into()), + transaction_hash: Some(tx_hash), + log_index: Some(0.into()), + ..Default::default() + }; + let topic_1: [u8; 32] = log.topics[1].into(); + let topic_3: [u8; 32] = log.topics[3].into(); + + let bridge_action = BridgeAction::EthToIotaBridgeAction(EthToIotaBridgeAction { + eth_tx_hash: tx_hash, + eth_event_index: event_index, + eth_bridge_event: EthToIotaTokenBridgeV1 { + eth_chain_id: BridgeChainId::try_from(topic_1[topic_1.len() - 1]).unwrap(), + nonce: u64::from_be_bytes(log.topics[2].as_ref()[24..32].try_into().unwrap()), + iota_chain_id: BridgeChainId::try_from(topic_3[topic_3.len() - 1]).unwrap(), + token_id: TokenId::try_from(token_code).unwrap(), + amount, + iota_address, + eth_address: source_address, + }, + }); + (log, bridge_action) +} + +pub async fn publish_bridge_package(context: &WalletContext) -> BTreeMap { + let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); + let gas_price = context.get_reference_gas_price().await.unwrap(); + + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.extend(["..", "..", "examples", "move", "bridge"]); + + let txn = context.sign_transaction( + &TestTransactionBuilder::new(sender, gas_object, gas_price) + .publish(path) + .build(), + ); + let resp = context.execute_transaction_must_succeed(txn).await; + let object_changes = resp.object_changes.unwrap(); + let package_id = object_changes + .iter() + .find(|change| matches!(change, ObjectChange::Published { .. })) + .map(|change| change.object_id()) + .unwrap(); + + let mut treasury_caps = BTreeMap::new(); + object_changes.iter().for_each(|change| { + if let ObjectChange::Created { object_type, .. } = change { + let object_type_str = object_type.to_string(); + if object_type_str.contains("TreasuryCap") { + if object_type_str.contains("BTC") { + treasury_caps.insert(TokenId::BTC, change.object_ref()); + } else if object_type_str.contains("ETH") { + treasury_caps.insert(TokenId::ETH, change.object_ref()); + } else if object_type_str.contains("USDC") { + treasury_caps.insert(TokenId::USDC, change.object_ref()); + } else if object_type_str.contains("USDT") { + treasury_caps.insert(TokenId::USDT, change.object_ref()); + } + } + } + }); + + let root_bridge_object_ref = object_changes + .iter() + .find(|change| match change { + ObjectChange::Created { + object_type, owner, .. + } => { + object_type.to_string().contains("Bridge") && matches!(owner, Owner::Shared { .. }) + } + _ => false, + }) + .map(|change| change.object_ref()) + .unwrap(); + + let bridge_inner_object_ref = object_changes + .iter() + .find(|change| match change { + ObjectChange::Created { object_type, .. } => { + object_type.to_string().contains("BridgeInner") + } + _ => false, + }) + .map(|change| change.object_ref()) + .unwrap(); + + let client = context.get_client().await.unwrap(); + let bcs_bytes = client + .read_api() + .get_move_object_bcs(bridge_inner_object_ref.0) + .await + .unwrap(); + let bridge_inner_object: BridgeInnerDynamicField = bcs::from_bytes(&bcs_bytes).unwrap(); + let bridge_record_id = bridge_inner_object.value.bridge_records.id; + + // TODO: remove once we don't rely on env var to get package id + std::env::set_var("BRIDGE_PACKAGE_ID", package_id.to_string()); + std::env::set_var("BRIDGE_RECORD_ID", bridge_record_id.to_string()); + std::env::set_var( + "ROOT_BRIDGE_OBJECT_ID", + root_bridge_object_ref.0.to_string(), + ); + std::env::set_var( + "ROOT_BRIDGE_OBJECT_INITIAL_SHARED_VERSION", + u64::from(root_bridge_object_ref.1).to_string(), + ); + std::env::set_var("BRIDGE_OBJECT_ID", bridge_inner_object_ref.0.to_string()); + + treasury_caps +} + +pub async fn mint_tokens( + context: &mut WalletContext, + treasury_cap_ref: ObjectRef, + amount: u64, + token_id: TokenId, +) -> (ObjectRef, ObjectRef) { + let rgp = context.get_reference_gas_price().await.unwrap(); + let sender = context.active_address().unwrap(); + let gas_obj_ref = context.get_one_gas_object().await.unwrap().unwrap().1; + let tx = TestTransactionBuilder::new(sender, gas_obj_ref, rgp) + .move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + "coin", + "mint_and_transfer", + vec![ + CallArg::Object(ObjectArg::ImmOrOwnedObject(treasury_cap_ref)), + CallArg::Pure(bcs::to_bytes(&amount).unwrap()), + CallArg::Pure(sender.to_vec()), + ], + ) + .with_type_args(vec![get_iota_token_type_tag(token_id)]) + .build(); + let signed_tn = context.sign_transaction(&tx); + let resp = context.execute_transaction_must_succeed(signed_tn).await; + let object_changes = resp.object_changes.unwrap(); + + let treasury_cap_obj_ref = object_changes + .iter() + .find(|change| matches!(change, ObjectChange::Mutated { object_type, .. } if object_type.to_string().contains("TreasuryCap"))) + .map(|change| change.object_ref()) + .unwrap(); + + let minted_coin_obj_ref = object_changes + .iter() + .find(|change| matches!(change, ObjectChange::Created { .. })) + .map(|change| change.object_ref()) + .unwrap(); + + (treasury_cap_obj_ref, minted_coin_obj_ref) +} + +pub async fn transfer_treasury_cap( + context: &mut WalletContext, + treasury_cap_ref: ObjectRef, + token_id: TokenId, +) { + let rgp = context.get_reference_gas_price().await.unwrap(); + let sender = context.active_address().unwrap(); + let gas_object = context.get_one_gas_object().await.unwrap().unwrap().1; + let tx = TestTransactionBuilder::new(sender, gas_object, rgp) + .move_call( + *get_bridge_package_id(), + "bridge", + "add_treasury_cap", + vec![ + CallArg::Object(*get_root_bridge_object_arg()), + CallArg::Object(ObjectArg::ImmOrOwnedObject(treasury_cap_ref)), + ], + ) + .with_type_args(vec![get_iota_token_type_tag(token_id)]) + .build(); + let signed_tn = context.sign_transaction(&tx); + context.execute_transaction_must_succeed(signed_tn).await; +} + +pub async fn bridge_token( + context: &mut WalletContext, + recv_address: EthAddress, + token_ref: ObjectRef, + token_id: TokenId, +) -> EmittedIotaToEthTokenBridgeV1 { + let rgp = context.get_reference_gas_price().await.unwrap(); + let sender = context.active_address().unwrap(); + let gas_object = context.get_one_gas_object().await.unwrap().unwrap().1; + let tx = TestTransactionBuilder::new(sender, gas_object, rgp) + .move_call( + *get_bridge_package_id(), + "bridge", + "send_token", + vec![ + CallArg::Object(*get_root_bridge_object_arg()), + CallArg::Pure(bcs::to_bytes(&(BridgeChainId::EthLocalTest as u8)).unwrap()), + CallArg::Pure(bcs::to_bytes(&recv_address.as_bytes()).unwrap()), + CallArg::Object(ObjectArg::ImmOrOwnedObject(token_ref)), + ], + ) + .with_type_args(vec![get_iota_token_type_tag(token_id)]) + .build(); + let signed_tn = context.sign_transaction(&tx); + let resp = context.execute_transaction_must_succeed(signed_tn).await; + let events = resp.events.unwrap(); + let mut bridge_events = events + .data + .iter() + .filter_map(|event| IotaBridgeEvent::try_from_iota_event(event).unwrap()) + .collect::>(); + assert_eq!(bridge_events.len(), 1); + match bridge_events.remove(0) { + IotaBridgeEvent::IotaToEthTokenBridgeV1(event) => event, + } +} diff --git a/crates/sui-bridge/src/tools/cli.rs b/crates/iota-bridge/src/tools/cli.rs similarity index 84% rename from crates/sui-bridge/src/tools/cli.rs rename to crates/iota-bridge/src/tools/cli.rs index bb7fd006ee6..52239d0fdc6 100644 --- a/crates/sui-bridge/src/tools/cli.rs +++ b/crates/iota-bridge/src/tools/cli.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::PathBuf; @@ -8,14 +9,14 @@ use clap::*; use fastcrypto::{ ed25519::Ed25519KeyPair, secp256k1::Secp256k1KeyPair, traits::EncodeDecodeBase64, }; -use sui_bridge::{ +use iota_bridge::{ config::BridgeNodeConfig, crypto::{BridgeAuthorityKeyPair, BridgeAuthorityPublicKeyBytes}, }; -use sui_config::Config; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, - crypto::{get_key_pair, SuiKeyPair}, +use iota_config::Config; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + crypto::{get_key_pair, IotaKeyPair}, }; #[derive(Parser)] @@ -77,10 +78,10 @@ fn generate_bridge_authority_key_and_write_to_file(path: &PathBuf) -> Result<(), "Corresponding Ethereum address by this ecdsa key: {:?}", eth_address ); - let sui_address = SuiAddress::from(&kp.public); + let iota_address = IotaAddress::from(&kp.public); println!( - "Corresponding Sui address by this ecdsa key: {:?}", - sui_address + "Corresponding Iota address by this ecdsa key: {:?}", + iota_address ); let base64_encoded = kp.encode_base64(); std::fs::write(path, base64_encoded) @@ -100,13 +101,13 @@ fn generate_bridge_client_key_and_write_to_file( "Corresponding Ethereum address by this ecdsa key: {:?}", eth_address ); - SuiKeyPair::from(kp) + IotaKeyPair::from(kp) } else { let (_, kp): (_, Ed25519KeyPair) = get_key_pair(); - SuiKeyPair::from(kp) + IotaKeyPair::from(kp) }; - let sui_address = SuiAddress::from(&kp.public()); - println!("Corresponding Sui address by this key: {:?}", sui_address); + let iota_address = IotaAddress::from(&kp.public()); + println!("Corresponding Iota address by this key: {:?}", iota_address); let contents = kp.encode_base64(); std::fs::write(path, contents) @@ -122,20 +123,20 @@ fn generate_bridge_node_config_and_write_to_file( server_listen_port: 9191, metrics_port: 9184, bridge_authority_key_path_base64_raw: PathBuf::from("/path/to/your/bridge_authority_key"), - sui_rpc_url: "your_sui_rpc_url".to_string(), + iota_rpc_url: "your_iota_rpc_url".to_string(), eth_rpc_url: "your_eth_rpc_url".to_string(), eth_addresses: vec!["bridge_eth_proxy_address".into()], approved_governance_actions: vec![], run_client, - bridge_client_key_path_base64_sui_key: None, + bridge_client_key_path_base64_iota_key: None, bridge_client_gas_object: None, - sui_bridge_modules: Some(vec!["modules_to_watch".into()]), + iota_bridge_modules: Some(vec!["modules_to_watch".into()]), db_path: None, eth_bridge_contracts_start_block_override: None, - sui_bridge_modules_last_processed_event_id_override: None, + iota_bridge_modules_last_processed_event_id_override: None, }; if run_client { - config.bridge_client_key_path_base64_sui_key = + config.bridge_client_key_path_base64_iota_key = Some(PathBuf::from("/path/to/your/bridge_client_key")); config.bridge_client_gas_object = Some(ObjectID::ZERO); config.db_path = Some(PathBuf::from("/path/to/your/client_db")); diff --git a/crates/iota-bridge/src/types.rs b/crates/iota-bridge/src/types.rs new file mode 100644 index 00000000000..156f952e471 --- /dev/null +++ b/crates/iota-bridge/src/types.rs @@ -0,0 +1,1326 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::{BTreeMap, BTreeSet}; + +pub use ethers::types::H256 as EthTransactionHash; +use ethers::types::{Address as EthAddress, Log, H256}; +use fastcrypto::hash::{HashFunction, Keccak256}; +use iota_types::{ + base_types::{IotaAddress, IOTA_ADDRESS_LENGTH}, + collection_types::{Bag, LinkedTable, LinkedTableNode, VecMap}, + committee::{CommitteeTrait, EpochId, StakeUnit}, + digests::{Digest, TransactionDigest}, + dynamic_field::Field, + error::IotaResult, + message_envelope::{Envelope, Message, VerifiedEnvelope}, +}; +use num_enum::TryFromPrimitive; +use rand::{seq::SliceRandom, Rng}; +use serde::{Deserialize, Serialize}; +use shared_crypto::intent::IntentScope; + +use crate::{ + abi::EthToIotaTokenBridgeV1, + crypto::{ + BridgeAuthorityPublicKey, BridgeAuthorityPublicKeyBytes, + BridgeAuthorityRecoverableSignature, BridgeAuthoritySignInfo, + }, + error::{BridgeError, BridgeResult}, + events::EmittedIotaToEthTokenBridgeV1, +}; + +pub const BRIDGE_AUTHORITY_TOTAL_VOTING_POWER: u64 = 10000; + +pub const USD_MULTIPLIER: u64 = 10000; // decimal places = 4 + +pub type BridgeInnerDynamicField = Field; +pub type BridgeRecordDyanmicField = Field< + MoveTypeBridgeMessageKey, + LinkedTableNode, +>; + +#[derive(Debug, Eq, PartialEq, Clone)] +pub struct BridgeAuthority { + pub pubkey: BridgeAuthorityPublicKey, + pub voting_power: u64, + pub base_url: String, + pub is_blocklisted: bool, +} + +impl BridgeAuthority { + pub fn pubkey_bytes(&self) -> BridgeAuthorityPublicKeyBytes { + BridgeAuthorityPublicKeyBytes::from(&self.pubkey) + } +} + +// A static Bridge committee implementation +#[derive(Debug, Clone)] +pub struct BridgeCommittee { + members: BTreeMap, + total_blocklisted_stake: StakeUnit, +} + +impl BridgeCommittee { + pub fn new(members: Vec) -> BridgeResult { + let mut members_map = BTreeMap::new(); + let mut total_stake = 0; + let mut total_blocklisted_stake = 0; + for member in members { + let public_key = BridgeAuthorityPublicKeyBytes::from(&member.pubkey); + if members_map.contains_key(&public_key) { + return Err(BridgeError::InvalidBridgeCommittee( + "Duplicate BridgeAuthority Public key".into(), + )); + } + // TODO: should we disallow identical network addresses? + total_stake += member.voting_power; + if member.is_blocklisted { + total_blocklisted_stake += member.voting_power; + } + members_map.insert(public_key, member); + } + if total_stake != BRIDGE_AUTHORITY_TOTAL_VOTING_POWER { + return Err(BridgeError::InvalidBridgeCommittee( + "Total voting power does not equal to 10000".into(), + )); + } + Ok(Self { + members: members_map, + total_blocklisted_stake, + }) + } + + pub fn is_active_member(&self, member: &BridgeAuthorityPublicKeyBytes) -> bool { + self.members.contains_key(member) && !self.members.get(member).unwrap().is_blocklisted + } + + pub fn members(&self) -> &BTreeMap { + &self.members + } + + pub fn member(&self, member: &BridgeAuthorityPublicKeyBytes) -> Option<&BridgeAuthority> { + self.members.get(member) + } + + pub fn total_blocklisted_stake(&self) -> StakeUnit { + self.total_blocklisted_stake + } +} + +impl CommitteeTrait for BridgeCommittee { + // Note: + // 1. preference is not supported today. + // 2. blocklisted members are always excluded. + fn shuffle_by_stake_with_rng( + &self, + // preference is not supported today + _preferences: Option<&BTreeSet>, + // only attempt from these authorities. + restrict_to: Option<&BTreeSet>, + rng: &mut impl Rng, + ) -> Vec { + let candidates = self + .members + .iter() + .filter_map(|(name, a)| { + // Remove blocklisted members + if a.is_blocklisted { + return None; + } + // exclude non-allowlisted members + if let Some(restrict_to) = restrict_to { + match restrict_to.contains(name) { + true => Some((name.clone(), a.voting_power)), + false => None, + } + } else { + Some((name.clone(), a.voting_power)) + } + }) + .collect::>(); + + candidates + .choose_multiple_weighted(rng, candidates.len(), |(_, weight)| *weight as f64) + // Unwrap safe: it panics when the third parameter is larger than the size of the slice + .unwrap() + .map(|(name, _)| name) + .cloned() + .collect() + } + + fn weight(&self, author: &BridgeAuthorityPublicKeyBytes) -> StakeUnit { + self.members + .get(author) + .map(|a| a.voting_power) + .unwrap_or(0) + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +#[repr(u8)] +pub enum BridgeActionType { + TokenTransfer = 0, + UpdateCommitteeBlocklist = 1, + EmergencyButton = 2, + LimitUpdate = 3, + AssetPriceUpdate = 4, + EvmContractUpgrade = 5, +} + +pub const IOTA_TX_DIGEST_LENGTH: usize = 32; +pub const ETH_TX_HASH_LENGTH: usize = 32; + +pub const BRIDGE_MESSAGE_PREFIX: &[u8] = b"IOTA_BRIDGE_MESSAGE"; + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, TryFromPrimitive, Hash)] +#[repr(u8)] +pub enum BridgeChainId { + IotaMainnet = 0, + IotaTestnet = 1, + IotaDevnet = 2, + IotaLocalTest = 3, + + EthMainnet = 10, + EthSepolia = 11, + EthLocalTest = 12, +} + +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + Serialize, + Deserialize, + TryFromPrimitive, + Hash, + Ord, + PartialOrd, +)] +#[repr(u8)] +pub enum TokenId { + Iota = 0, + BTC = 1, + ETH = 2, + USDC = 3, + USDT = 4, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum BridgeActionStatus { + RecordNotFound, + Pending, + Approved, + Claimed, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub struct IotaToEthBridgeAction { + // Digest of the transaction where the event was emitted + pub iota_tx_digest: TransactionDigest, + // The index of the event in the transaction + pub iota_tx_event_index: u16, + pub iota_bridge_event: EmittedIotaToEthTokenBridgeV1, +} + +impl IotaToEthBridgeAction { + pub fn to_bytes(&self) -> Vec { + let mut bytes = Vec::new(); + let e = &self.iota_bridge_event; + // Add message type + bytes.push(BridgeActionType::TokenTransfer as u8); + // Add message version + bytes.push(TOKEN_TRANSFER_MESSAGE_VERSION); + // Add nonce + bytes.extend_from_slice(&e.nonce.to_be_bytes()); + // Add source chain id + bytes.push(e.iota_chain_id as u8); + + // Add source address length + bytes.push(IOTA_ADDRESS_LENGTH as u8); + // Add source address + bytes.extend_from_slice(&e.iota_address.to_vec()); + // Add dest chain id + bytes.push(e.eth_chain_id as u8); + // Add dest address length + bytes.push(EthAddress::len_bytes() as u8); + // Add dest address + bytes.extend_from_slice(e.eth_address.as_bytes()); + + // Add token id + bytes.push(e.token_id as u8); + + // Add token amount + bytes.extend_from_slice(&e.amount.to_be_bytes()); + + bytes + } +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub struct EthToIotaBridgeAction { + // Digest of the transaction where the event was emitted + pub eth_tx_hash: EthTransactionHash, + // The index of the event in the transaction + pub eth_event_index: u16, + pub eth_bridge_event: EthToIotaTokenBridgeV1, +} + +impl EthToIotaBridgeAction { + pub fn to_bytes(&self) -> Vec { + let mut bytes = Vec::new(); + let e = &self.eth_bridge_event; + // Add message type + bytes.push(BridgeActionType::TokenTransfer as u8); + // Add message version + bytes.push(TOKEN_TRANSFER_MESSAGE_VERSION); + // Add nonce + bytes.extend_from_slice(&e.nonce.to_be_bytes()); + // Add source chain id + bytes.push(e.eth_chain_id as u8); + + // Add source address length + bytes.push(EthAddress::len_bytes() as u8); + // Add source address + bytes.extend_from_slice(e.eth_address.as_bytes()); + // Add dest chain id + bytes.push(e.iota_chain_id as u8); + // Add dest address length + bytes.push(IOTA_ADDRESS_LENGTH as u8); + // Add dest address + bytes.extend_from_slice(&e.iota_address.to_vec()); + + // Add token id + bytes.push(e.token_id as u8); + + // Add token amount + bytes.extend_from_slice(&e.amount.to_be_bytes()); + + bytes + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, TryFromPrimitive, Hash)] +#[repr(u8)] +pub enum BlocklistType { + Blocklist = 0, + Unblocklist = 1, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub struct BlocklistCommitteeAction { + pub nonce: u64, + pub chain_id: BridgeChainId, + pub blocklist_type: BlocklistType, + pub blocklisted_members: Vec, +} + +impl BlocklistCommitteeAction { + pub fn to_bytes(&self) -> Vec { + let mut bytes = Vec::new(); + // Add message type + bytes.push(BridgeActionType::UpdateCommitteeBlocklist as u8); + // Add message version + bytes.push(COMMITTEE_BLOCKLIST_MESSAGE_VERSION); + // Add nonce + bytes.extend_from_slice(&self.nonce.to_be_bytes()); + // Add chain id + bytes.push(self.chain_id as u8); + // Add blocklist type + bytes.push(self.blocklist_type as u8); + // Add length of updated members. + // Unwrap: It should not overflow given what we have today. + bytes.push(u8::try_from(self.blocklisted_members.len()).unwrap()); + + // Add list of updated members + // Members are represented as pubkey dervied evm addresses (20 bytes) + let members_bytes = self + .blocklisted_members + .iter() + .map(|m| m.to_eth_address().to_fixed_bytes().to_vec()) + .collect::>(); + for members_bytes in members_bytes { + bytes.extend_from_slice(&members_bytes); + } + bytes + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, TryFromPrimitive, Hash)] +#[repr(u8)] +pub enum EmergencyActionType { + Pause = 0, + Unpause = 1, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub struct EmergencyAction { + pub nonce: u64, + pub chain_id: BridgeChainId, + pub action_type: EmergencyActionType, +} + +impl EmergencyAction { + pub fn to_bytes(&self) -> Vec { + let mut bytes = Vec::new(); + // Add message type + bytes.push(BridgeActionType::EmergencyButton as u8); + // Add message version + bytes.push(EMERGENCY_BUTTON_MESSAGE_VERSION); + // Add nonce + bytes.extend_from_slice(&self.nonce.to_be_bytes()); + // Add chain id + bytes.push(self.chain_id as u8); + // Add action type + bytes.push(self.action_type as u8); + bytes + } +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub struct LimitUpdateAction { + pub nonce: u64, + // The chain id that will receive this signed action. It's also the destination chain id + // for the limit update. For example, if chain_id is EthMainnet and sending_chain_id is + // IotaMainnet, it means we want to update the limit for the IotaMainnet to EthMainnet route. + pub chain_id: BridgeChainId, + // The sending chain id for the limit update. + pub sending_chain_id: BridgeChainId, + pub new_usd_limit: u64, +} + +impl LimitUpdateAction { + pub fn to_bytes(&self) -> Vec { + let mut bytes = Vec::new(); + // Add message type + bytes.push(BridgeActionType::LimitUpdate as u8); + // Add message version + bytes.push(LIMIT_UPDATE_MESSAGE_VERSION); + // Add nonce + bytes.extend_from_slice(&self.nonce.to_be_bytes()); + // Add chain id + bytes.push(self.chain_id as u8); + // Add sending chain id + bytes.push(self.sending_chain_id as u8); + // Add new usd limit + bytes.extend_from_slice(&self.new_usd_limit.to_be_bytes()); + bytes + } +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub struct AssetPriceUpdateAction { + pub nonce: u64, + pub chain_id: BridgeChainId, + pub token_id: TokenId, + pub new_usd_price: u64, +} + +impl AssetPriceUpdateAction { + pub fn to_bytes(&self) -> Vec { + let mut bytes = Vec::new(); + // Add message type + bytes.push(BridgeActionType::AssetPriceUpdate as u8); + // Add message version + bytes.push(EMERGENCY_BUTTON_MESSAGE_VERSION); + // Add nonce + bytes.extend_from_slice(&self.nonce.to_be_bytes()); + // Add chain id + bytes.push(self.chain_id as u8); + // Add token id + bytes.push(self.token_id as u8); + // Add new usd limit + bytes.extend_from_slice(&self.new_usd_price.to_be_bytes()); + bytes + } +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub struct EvmContractUpgradeAction { + pub nonce: u64, + pub chain_id: BridgeChainId, + pub proxy_address: EthAddress, + pub new_impl_address: EthAddress, + pub call_data: Vec, +} + +impl EvmContractUpgradeAction { + pub fn to_bytes(&self) -> Vec { + let mut bytes = Vec::new(); + // Add message type + bytes.push(BridgeActionType::EvmContractUpgrade as u8); + // Add message version + bytes.push(EVM_CONTRACT_UPGRADE_MESSAGE_VERSION); + // Add nonce + bytes.extend_from_slice(&self.nonce.to_be_bytes()); + // Add chain id + bytes.push(self.chain_id as u8); + // Add payload + let encoded = ethers::abi::encode(&[ + ethers::abi::Token::Address(self.proxy_address), + ethers::abi::Token::Address(self.new_impl_address), + ethers::abi::Token::Bytes(self.call_data.clone()), + ]); + bytes.extend_from_slice(&encoded); + bytes + } +} + +/// The type of actions Bridge Committee verify and sign off to execution. +/// Its relationship with BridgeEvent is similar to the relationship between +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub enum BridgeAction { + /// Iota to Eth bridge action + IotaToEthBridgeAction(IotaToEthBridgeAction), + /// Eth to iota bridge action + EthToIotaBridgeAction(EthToIotaBridgeAction), + BlocklistCommitteeAction(BlocklistCommitteeAction), + EmergencyAction(EmergencyAction), + LimitUpdateAction(LimitUpdateAction), + AssetPriceUpdateAction(AssetPriceUpdateAction), + EvmContractUpgradeAction(EvmContractUpgradeAction), + // TODO: add other bridge actions such as blocklist & emergency button +} + +pub const TOKEN_TRANSFER_MESSAGE_VERSION: u8 = 1; +pub const COMMITTEE_BLOCKLIST_MESSAGE_VERSION: u8 = 1; +pub const EMERGENCY_BUTTON_MESSAGE_VERSION: u8 = 1; +pub const LIMIT_UPDATE_MESSAGE_VERSION: u8 = 1; +pub const ASSET_PRICE_UPDATE_MESSAGE_VERSION: u8 = 1; +pub const EVM_CONTRACT_UPGRADE_MESSAGE_VERSION: u8 = 1; + +impl BridgeAction { + /// Convert to message bytes that are verified in Move and Solidity + pub fn to_bytes(&self) -> Vec { + let mut bytes = Vec::new(); + // Add prefix + bytes.extend_from_slice(BRIDGE_MESSAGE_PREFIX); + match self { + BridgeAction::IotaToEthBridgeAction(a) => { + bytes.extend_from_slice(&a.to_bytes()); + } + BridgeAction::EthToIotaBridgeAction(a) => { + bytes.extend_from_slice(&a.to_bytes()); + } + BridgeAction::BlocklistCommitteeAction(a) => { + bytes.extend_from_slice(&a.to_bytes()); + } + BridgeAction::EmergencyAction(a) => { + bytes.extend_from_slice(&a.to_bytes()); + } + BridgeAction::LimitUpdateAction(a) => { + bytes.extend_from_slice(&a.to_bytes()); + } + BridgeAction::AssetPriceUpdateAction(a) => { + bytes.extend_from_slice(&a.to_bytes()); + } + BridgeAction::EvmContractUpgradeAction(a) => { + bytes.extend_from_slice(&a.to_bytes()); + } // TODO add formats for other events + } + bytes + } + + // Digest of BridgeAction (with Keccak256 hasher) + pub fn digest(&self) -> BridgeActionDigest { + let mut hasher = Keccak256::default(); + hasher.update(&self.to_bytes()); + BridgeActionDigest::new(hasher.finalize().into()) + } + + pub fn chain_id(&self) -> BridgeChainId { + match self { + BridgeAction::IotaToEthBridgeAction(a) => a.iota_bridge_event.iota_chain_id, + BridgeAction::EthToIotaBridgeAction(a) => a.eth_bridge_event.eth_chain_id, + BridgeAction::BlocklistCommitteeAction(a) => a.chain_id, + BridgeAction::EmergencyAction(a) => a.chain_id, + BridgeAction::LimitUpdateAction(a) => a.chain_id, + BridgeAction::AssetPriceUpdateAction(a) => a.chain_id, + BridgeAction::EvmContractUpgradeAction(a) => a.chain_id, + } + } + + pub fn is_governace_action(&self) -> bool { + match self.action_type() { + BridgeActionType::TokenTransfer => false, + BridgeActionType::UpdateCommitteeBlocklist => true, + BridgeActionType::EmergencyButton => true, + BridgeActionType::LimitUpdate => true, + BridgeActionType::AssetPriceUpdate => true, + BridgeActionType::EvmContractUpgrade => true, + } + } + + // Also called `message_type` + pub fn action_type(&self) -> BridgeActionType { + match self { + BridgeAction::IotaToEthBridgeAction(_) => BridgeActionType::TokenTransfer, + BridgeAction::EthToIotaBridgeAction(_) => BridgeActionType::TokenTransfer, + BridgeAction::BlocklistCommitteeAction(_) => BridgeActionType::UpdateCommitteeBlocklist, + BridgeAction::EmergencyAction(_) => BridgeActionType::EmergencyButton, + BridgeAction::LimitUpdateAction(_) => BridgeActionType::LimitUpdate, + BridgeAction::AssetPriceUpdateAction(_) => BridgeActionType::AssetPriceUpdate, + BridgeAction::EvmContractUpgradeAction(_) => BridgeActionType::EvmContractUpgrade, + } + } + + // Also called `nonce` + pub fn seq_number(&self) -> u64 { + match self { + BridgeAction::IotaToEthBridgeAction(a) => a.iota_bridge_event.nonce, + BridgeAction::EthToIotaBridgeAction(a) => a.eth_bridge_event.nonce, + BridgeAction::BlocklistCommitteeAction(a) => a.nonce, + BridgeAction::EmergencyAction(a) => a.nonce, + BridgeAction::LimitUpdateAction(a) => a.nonce, + BridgeAction::AssetPriceUpdateAction(a) => a.nonce, + BridgeAction::EvmContractUpgradeAction(a) => a.nonce, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +pub struct BridgeActionDigest(Digest); + +impl BridgeActionDigest { + pub const fn new(digest: [u8; 32]) -> Self { + Self(Digest::new(digest)) + } +} + +#[derive(Debug, Clone)] +pub struct BridgeCommitteeValiditySignInfo { + pub signatures: BTreeMap, +} + +pub type SignedBridgeAction = Envelope; +pub type VerifiedSignedBridgeAction = VerifiedEnvelope; +pub type CertifiedBridgeAction = Envelope; +pub type VerifiedCertifiedBridgeAction = + VerifiedEnvelope; + +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub struct BridgeEventDigest(Digest); + +impl BridgeEventDigest { + pub const fn new(digest: [u8; 32]) -> Self { + Self(Digest::new(digest)) + } +} + +impl Message for BridgeAction { + type DigestType = BridgeEventDigest; + + // this is not encoded in message today + const SCOPE: IntentScope = IntentScope::BridgeEventUnused; + + // this is not used today + fn digest(&self) -> Self::DigestType { + unreachable!("BridgeEventDigest is not used today") + } + + fn verify_user_input(&self) -> IotaResult { + Ok(()) + } + + fn verify_epoch(&self, _epoch: EpochId) -> IotaResult { + Ok(()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EthLog { + pub block_number: u64, + pub tx_hash: H256, + pub log_index_in_tx: u16, + // TODO: pull necessary fields from `Log`. + pub log: Log, +} + +/////////////////////////// Move Types Start ////////////////////////// + +/// Rust version of the Move bridge::BridgeInner type. +#[derive(Debug, Serialize, Deserialize)] +pub struct MoveTypeBridgeInner { + pub bridge_version: u64, + pub chain_id: u8, + pub sequence_nums: VecMap, + pub committee: MoveTypeBridgeCommittee, + pub treasury: MoveTypeBridgeTreasury, + pub bridge_records: LinkedTable, + pub frozen: bool, +} + +/// Rust version of the Move treasury::BridgeTreasury type. +#[derive(Debug, Serialize, Deserialize)] +pub struct MoveTypeBridgeTreasury { + pub treasuries: Bag, +} + +/// Rust version of the Move committee::BridgeCommittee type. +#[derive(Debug, Serialize, Deserialize)] +pub struct MoveTypeBridgeCommittee { + pub members: VecMap, MoveTypeCommitteeMember>, + pub thresholds: VecMap, +} + +/// Rust version of the Move committee::CommitteeMember type. +#[derive(Debug, Serialize, Deserialize)] +pub struct MoveTypeCommitteeMember { + pub iota_address: IotaAddress, + pub bridge_pubkey_bytes: Vec, + pub voting_power: u64, + pub http_rest_url: Vec, + pub blocklisted: bool, +} + +/// Rust version of the Move message::BridgeMessageKey type. +#[derive(Debug, Serialize, Deserialize)] +pub struct MoveTypeBridgeMessageKey { + pub source_chain: u8, + pub message_type: u8, + pub bridge_seq_num: u64, +} + +/// Rust version of the Move message::BridgeMessage type. +#[derive(Debug, Serialize, Deserialize)] +pub struct MoveTypeBridgeMessage { + pub message_type: u8, + pub message_version: u8, + pub seq_num: u64, + pub source_chain: u8, + pub payload: Vec, +} + +/// Rust version of the Move message::BridgeMessage type. +#[derive(Debug, Serialize, Deserialize)] +pub struct MoveTypeBridgeRecord { + pub message: MoveTypeBridgeMessage, + pub verified_signatures: Option>>, + pub claimed: bool, +} + +/////////////////////////// Move Types End ////////////////////////// + +#[cfg(test)] +mod tests { + use std::{collections::HashSet, str::FromStr}; + + use ethers::{ + abi::ParamType, + types::{Address as EthAddress, TxHash}, + }; + use fastcrypto::{ + encoding::{Encoding, Hex}, + hash::HashFunction, + traits::{KeyPair, ToFromBytes}, + }; + use iota_types::{ + base_types::{IotaAddress, TransactionDigest}, + crypto::get_key_pair, + }; + use prometheus::Registry; + + use super::*; + use crate::{test_utils::get_test_authority_and_key, types::TokenId}; + + #[test] + fn test_bridge_message_encoding() -> anyhow::Result<()> { + telemetry_subscribers::init_for_testing(); + let registry = Registry::new(); + mysten_metrics::init_metrics(®istry); + let nonce = 54321u64; + let iota_tx_digest = TransactionDigest::random(); + let iota_chain_id = BridgeChainId::IotaTestnet; + let iota_tx_event_index = 1u16; + let eth_chain_id = BridgeChainId::EthSepolia; + let iota_address = IotaAddress::random_for_testing_only(); + let eth_address = EthAddress::random(); + let token_id = TokenId::USDC; + let amount = 1_000_000; + + let iota_bridge_event = EmittedIotaToEthTokenBridgeV1 { + nonce, + iota_chain_id, + eth_chain_id, + iota_address, + eth_address, + token_id, + amount, + }; + + let encoded_bytes = BridgeAction::IotaToEthBridgeAction(IotaToEthBridgeAction { + iota_tx_digest, + iota_tx_event_index, + iota_bridge_event, + }) + .to_bytes(); + + // Construct the expected bytes + let prefix_bytes = BRIDGE_MESSAGE_PREFIX.to_vec(); // len: 18 + let message_type = vec![BridgeActionType::TokenTransfer as u8]; // len: 1 + let message_version = vec![TOKEN_TRANSFER_MESSAGE_VERSION]; // len: 1 + let nonce_bytes = nonce.to_be_bytes().to_vec(); // len: 8 + let source_chain_id_bytes = vec![iota_chain_id as u8]; // len: 1 + + let iota_address_length_bytes = vec![IOTA_ADDRESS_LENGTH as u8]; // len: 1 + let iota_address_bytes = iota_address.to_vec(); // len: 32 + let dest_chain_id_bytes = vec![eth_chain_id as u8]; // len: 1 + let eth_address_length_bytes = vec![EthAddress::len_bytes() as u8]; // len: 1 + let eth_address_bytes = eth_address.as_bytes().to_vec(); // len: 20 + + let token_id_bytes = vec![token_id as u8]; // len: 1 + let token_amount_bytes = amount.to_be_bytes().to_vec(); // len: 8 + + let mut combined_bytes = Vec::new(); + combined_bytes.extend_from_slice(&prefix_bytes); + combined_bytes.extend_from_slice(&message_type); + combined_bytes.extend_from_slice(&message_version); + combined_bytes.extend_from_slice(&nonce_bytes); + combined_bytes.extend_from_slice(&source_chain_id_bytes); + combined_bytes.extend_from_slice(&iota_address_length_bytes); + combined_bytes.extend_from_slice(&iota_address_bytes); + combined_bytes.extend_from_slice(&dest_chain_id_bytes); + combined_bytes.extend_from_slice(ð_address_length_bytes); + combined_bytes.extend_from_slice(ð_address_bytes); + combined_bytes.extend_from_slice(&token_id_bytes); + combined_bytes.extend_from_slice(&token_amount_bytes); + + assert_eq!(combined_bytes, encoded_bytes); + + // Assert fixed length + // TODO: for each action type add a test to assert the length + assert_eq!( + combined_bytes.len(), + 18 + 1 + 1 + 8 + 1 + 1 + 32 + 1 + 20 + 1 + 1 + 8 + ); + Ok(()) + } + + #[test] + fn test_bridge_message_encoding_regression_emitted_iota_to_eth_token_bridge_v1() + -> anyhow::Result<()> { + telemetry_subscribers::init_for_testing(); + let registry = Registry::new(); + mysten_metrics::init_metrics(®istry); + let iota_tx_digest = TransactionDigest::random(); + let iota_tx_event_index = 1u16; + + let nonce = 10u64; + let iota_chain_id = BridgeChainId::IotaTestnet; + let eth_chain_id = BridgeChainId::EthSepolia; + let iota_address = IotaAddress::from_str( + "0x0000000000000000000000000000000000000000000000000000000000000064", + ) + .unwrap(); + let eth_address = + EthAddress::from_str("0x00000000000000000000000000000000000000c8").unwrap(); + let token_id = TokenId::USDC; + let amount = 12345; + + let iota_bridge_event = EmittedIotaToEthTokenBridgeV1 { + nonce, + iota_chain_id, + eth_chain_id, + iota_address, + eth_address, + token_id, + amount, + }; + let encoded_bytes = BridgeAction::IotaToEthBridgeAction(IotaToEthBridgeAction { + iota_tx_digest, + iota_tx_event_index, + iota_bridge_event, + }) + .to_bytes(); + assert_eq!( + encoded_bytes, + Hex::decode("5355495f4252494447455f4d4553534147450001000000000000000a012000000000000000000000000000000000000000000000000000000000000000640b1400000000000000000000000000000000000000c8030000000000003039").unwrap(), + ); + + let hash = Keccak256::digest(encoded_bytes).digest; + assert_eq!( + hash.to_vec(), + Hex::decode("6ab34c52b6264cbc12fe8c3874f9b08f8481d2e81530d136386646dbe2f8baf4") + .unwrap(), + ); + Ok(()) + } + + #[test] + fn test_bridge_message_encoding_blocklist_update_v1() { + telemetry_subscribers::init_for_testing(); + let registry = Registry::new(); + mysten_metrics::init_metrics(®istry); + + let pub_key_bytes = BridgeAuthorityPublicKeyBytes::from_bytes( + &Hex::decode("02321ede33d2c2d7a8a152f275a1484edef2098f034121a602cb7d767d38680aa4") + .unwrap(), + ) + .unwrap(); + let blocklist_action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction { + nonce: 129, + chain_id: BridgeChainId::IotaLocalTest, + blocklist_type: BlocklistType::Blocklist, + blocklisted_members: vec![pub_key_bytes.clone()], + }); + let bytes = blocklist_action.to_bytes(); + // 5355495f4252494447455f4d455353414745: prefix + // 01: msg type + // 01: msg version + // 0000000000000081: nonce + // 03: chain id + // 00: blocklist type + // 01: length of updated members + // [ + // 68b43fd906c0b8f024a18c56e06744f7c6157c65 + // ]: blocklisted members abi-encoded + assert_eq!(bytes, Hex::decode("5355495f4252494447455f4d4553534147450101000000000000008103000168b43fd906c0b8f024a18c56e06744f7c6157c65").unwrap()); + + let pub_key_bytes_2 = BridgeAuthorityPublicKeyBytes::from_bytes( + &Hex::decode("027f1178ff417fc9f5b8290bd8876f0a157a505a6c52db100a8492203ddd1d4279") + .unwrap(), + ) + .unwrap(); + // its evem address: 0xacaef39832cb995c4e049437a3e2ec6a7bad1ab5 + let blocklist_action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction { + nonce: 68, + chain_id: BridgeChainId::IotaDevnet, + blocklist_type: BlocklistType::Unblocklist, + blocklisted_members: vec![pub_key_bytes.clone(), pub_key_bytes_2.clone()], + }); + let bytes = blocklist_action.to_bytes(); + // 5355495f4252494447455f4d455353414745: prefix + // 01: msg type + // 01: msg version + // 0000000000000044: nonce + // 02: chain id + // 01: blocklist type + // 02: length of updated members + // [ + // 68b43fd906c0b8f024a18c56e06744f7c6157c65 + // acaef39832cb995c4e049437a3e2ec6a7bad1ab5 + // ]: blocklisted members abi-encoded + assert_eq!(bytes, Hex::decode("5355495f4252494447455f4d4553534147450101000000000000004402010268b43fd906c0b8f024a18c56e06744f7c6157c65acaef39832cb995c4e049437a3e2ec6a7bad1ab5").unwrap()); + + let blocklist_action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction { + nonce: 49, + chain_id: BridgeChainId::EthLocalTest, + blocklist_type: BlocklistType::Blocklist, + blocklisted_members: vec![pub_key_bytes.clone()], + }); + let bytes = blocklist_action.to_bytes(); + // 5355495f4252494447455f4d455353414745: prefix + // 01: msg type + // 01: msg version + // 0000000000000031: nonce + // 0c: chain id + // 00: blocklist type + // 01: length of updated members + // [ + // 68b43fd906c0b8f024a18c56e06744f7c6157c65 + // ]: blocklisted members abi-encoded + assert_eq!(bytes, Hex::decode("5355495f4252494447455f4d455353414745010100000000000000310c000168b43fd906c0b8f024a18c56e06744f7c6157c65").unwrap()); + + let blocklist_action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction { + nonce: 94, + chain_id: BridgeChainId::EthSepolia, + blocklist_type: BlocklistType::Unblocklist, + blocklisted_members: vec![pub_key_bytes.clone(), pub_key_bytes_2.clone()], + }); + let bytes = blocklist_action.to_bytes(); + // 5355495f4252494447455f4d455353414745: prefix + // 01: msg type + // 01: msg version + // 000000000000005e: nonce + // 0b: chain id + // 01: blocklist type + // 02: length of updated members + // [ + // 00000000000000000000000068b43fd906c0b8f024a18c56e06744f7c6157c65 + // 000000000000000000000000acaef39832cb995c4e049437a3e2ec6a7bad1ab5 + // ]: blocklisted members abi-encoded + assert_eq!(bytes, Hex::decode("5355495f4252494447455f4d4553534147450101000000000000005e0b010268b43fd906c0b8f024a18c56e06744f7c6157c65acaef39832cb995c4e049437a3e2ec6a7bad1ab5").unwrap()); + } + + #[test] + fn test_emergency_action_encoding() { + let action = BridgeAction::EmergencyAction(EmergencyAction { + nonce: 55, + chain_id: BridgeChainId::IotaLocalTest, + action_type: EmergencyActionType::Pause, + }); + let bytes = action.to_bytes(); + // 5355495f4252494447455f4d455353414745: prefix + // 02: msg type + // 01: msg version + // 0000000000000037: nonce + // 03: chain id + // 00: action type + assert_eq!( + bytes, + Hex::decode("5355495f4252494447455f4d455353414745020100000000000000370300").unwrap() + ); + + let action = BridgeAction::EmergencyAction(EmergencyAction { + nonce: 56, + chain_id: BridgeChainId::EthSepolia, + action_type: EmergencyActionType::Unpause, + }); + let bytes = action.to_bytes(); + // 5355495f4252494447455f4d455353414745: prefix + // 02: msg type + // 01: msg version + // 0000000000000038: nonce + // 0b: chain id + // 01: action type + assert_eq!( + bytes, + Hex::decode("5355495f4252494447455f4d455353414745020100000000000000380b01").unwrap() + ); + } + + #[test] + fn test_limit_update_action_encoding() { + let action = BridgeAction::LimitUpdateAction(LimitUpdateAction { + nonce: 15, + chain_id: BridgeChainId::IotaLocalTest, + sending_chain_id: BridgeChainId::EthLocalTest, + new_usd_limit: 1_000_000 * USD_MULTIPLIER, // $1M USD + }); + let bytes = action.to_bytes(); + // 5355495f4252494447455f4d455353414745: prefix + // 03: msg type + // 01: msg version + // 000000000000000f: nonce + // 03: chain id + // 0c: sending chain id + // 00000002540be400: new usd limit + assert_eq!( + bytes, + Hex::decode( + "5355495f4252494447455f4d4553534147450301000000000000000f030c00000002540be400" + ) + .unwrap() + ); + } + + #[test] + fn test_asset_price_update_action_encoding() { + let action = BridgeAction::AssetPriceUpdateAction(AssetPriceUpdateAction { + nonce: 266, + chain_id: BridgeChainId::IotaLocalTest, + token_id: TokenId::BTC, + new_usd_price: 100_000 * USD_MULTIPLIER, // $100k USD + }); + let bytes = action.to_bytes(); + // 5355495f4252494447455f4d455353414745: prefix + // 04: msg type + // 01: msg version + // 000000000000010a: nonce + // 03: chain id + // 01: token id + // 000000003b9aca00: new usd price + assert_eq!( + bytes, + Hex::decode( + "5355495f4252494447455f4d4553534147450401000000000000010a0301000000003b9aca00" + ) + .unwrap() + ); + } + + #[test] + fn test_evm_contract_upgrade_action() { + // Calldata with only the function selector and no parameters: `function + // initializeV2()` + let function_signature = "initializeV2()"; + let selector = &Keccak256::digest(function_signature).digest[0..4]; + let call_data = selector.to_vec(); + assert_eq!(Hex::encode(call_data.clone()), "5cd8a76b"); + + let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { + nonce: 123, + chain_id: BridgeChainId::EthLocalTest, + proxy_address: EthAddress::repeat_byte(6), + new_impl_address: EthAddress::repeat_byte(9), + call_data, + }); + // 5355495f4252494447455f4d455353414745: prefix + // 05: msg type + // 01: msg version + // 000000000000007b: nonce + // 0c: chain id + // 0000000000000000000000000606060606060606060606060606060606060606: proxy + // address + // 0000000000000000000000000909090909090909090909090909090909090909: new impl + // address + // + // 0000000000000000000000000000000000000000000000000000000000000060 + // 0000000000000000000000000000000000000000000000000000000000000004 + // 5cd8a76b00000000000000000000000000000000000000000000000000000000: call data + assert_eq!( + Hex::encode(action.to_bytes().clone()), + "5355495f4252494447455f4d4553534147450501000000000000007b0c00000000000000000000000006060606060606060606060606060606060606060000000000000000000000000909090909090909090909090909090909090909000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000045cd8a76b00000000000000000000000000000000000000000000000000000000" + ); + + // Calldata with one parameter: `function newMockFunction(bool)` + let function_signature = "newMockFunction(bool)"; + let selector = &Keccak256::digest(function_signature).digest[0..4]; + let mut call_data = selector.to_vec(); + call_data.extend(ethers::abi::encode(&[ethers::abi::Token::Bool(true)])); + assert_eq!( + Hex::encode(call_data.clone()), + "417795ef0000000000000000000000000000000000000000000000000000000000000001" + ); + let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { + nonce: 123, + chain_id: BridgeChainId::EthLocalTest, + proxy_address: EthAddress::repeat_byte(6), + new_impl_address: EthAddress::repeat_byte(9), + call_data, + }); + // 5355495f4252494447455f4d455353414745: prefix + // 05: msg type + // 01: msg version + // 000000000000007b: nonce + // 0c: chain id + // 0000000000000000000000000606060606060606060606060606060606060606: proxy + // address + // 0000000000000000000000000909090909090909090909090909090909090909: new impl + // address + // + // 0000000000000000000000000000000000000000000000000000000000000060 + // 0000000000000000000000000000000000000000000000000000000000000024 + // 417795ef00000000000000000000000000000000000000000000000000000000 + // 0000000100000000000000000000000000000000000000000000000000000000: call data + assert_eq!( + Hex::encode(action.to_bytes().clone()), + "5355495f4252494447455f4d4553534147450501000000000000007b0c0000000000000000000000000606060606060606060606060606060606060606000000000000000000000000090909090909090909090909090909090909090900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000024417795ef000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000" + ); + + // Calldata with two parameters: `function newerMockFunction(bool, uint8)` + let function_signature = "newMockFunction(bool,uint8)"; + let selector = &Keccak256::digest(function_signature).digest[0..4]; + let mut call_data = selector.to_vec(); + call_data.extend(ethers::abi::encode(&[ + ethers::abi::Token::Bool(true), + ethers::abi::Token::Uint(42u8.into()), + ])); + assert_eq!( + Hex::encode(call_data.clone()), + "be8fc25d0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002a" + ); + let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { + nonce: 123, + chain_id: BridgeChainId::EthLocalTest, + proxy_address: EthAddress::repeat_byte(6), + new_impl_address: EthAddress::repeat_byte(9), + call_data, + }); + // 5355495f4252494447455f4d455353414745: prefix + // 05: msg type + // 01: msg version + // 000000000000007b: nonce + // 0c: chain id + // 0000000000000000000000000606060606060606060606060606060606060606: proxy + // address + // 0000000000000000000000000909090909090909090909090909090909090909: new impl + // address + // + // 0000000000000000000000000000000000000000000000000000000000000060 + // 0000000000000000000000000000000000000000000000000000000000000044 + // be8fc25d00000000000000000000000000000000000000000000000000000000 + // 0000000100000000000000000000000000000000000000000000000000000000 + // 0000002a00000000000000000000000000000000000000000000000000000000: call data + assert_eq!( + Hex::encode(action.to_bytes().clone()), + "5355495f4252494447455f4d4553534147450501000000000000007b0c0000000000000000000000000606060606060606060606060606060606060606000000000000000000000000090909090909090909090909090909090909090900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044be8fc25d0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000" + ); + + // Empty calldate + let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { + nonce: 123, + chain_id: BridgeChainId::EthLocalTest, + proxy_address: EthAddress::repeat_byte(6), + new_impl_address: EthAddress::repeat_byte(9), + call_data: vec![], + }); + // 5355495f4252494447455f4d455353414745: prefix + // 05: msg type + // 01: msg version + // 000000000000007b: nonce + // 0c: chain id + // 0000000000000000000000000606060606060606060606060606060606060606: proxy + // address + // 0000000000000000000000000909090909090909090909090909090909090909: new impl + // address + // + // 0000000000000000000000000000000000000000000000000000000000000060 + // 0000000000000000000000000000000000000000000000000000000000000000: call data + let data = action.to_bytes(); + assert_eq!( + Hex::encode(data.clone()), + "5355495f4252494447455f4d4553534147450501000000000000007b0c0000000000000000000000000606060606060606060606060606060606060606000000000000000000000000090909090909090909090909090909090909090900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000" + ); + let types = vec![ParamType::Address, ParamType::Address, ParamType::Bytes]; + // Ensure that the call data (start from bytes 29) can be decoded + ethers::abi::decode(&types, &data[29..]).unwrap(); + } + + #[test] + fn test_bridge_message_encoding_regression_eth_to_iota_token_bridge_v1() -> anyhow::Result<()> { + telemetry_subscribers::init_for_testing(); + let registry = Registry::new(); + mysten_metrics::init_metrics(®istry); + let eth_tx_hash = TxHash::random(); + let eth_event_index = 1u16; + + let nonce = 10u64; + let iota_chain_id = BridgeChainId::IotaTestnet; + let eth_chain_id = BridgeChainId::EthSepolia; + let iota_address = IotaAddress::from_str( + "0x0000000000000000000000000000000000000000000000000000000000000064", + ) + .unwrap(); + let eth_address = + EthAddress::from_str("0x00000000000000000000000000000000000000c8").unwrap(); + let token_id = TokenId::USDC; + let amount = 12345; + + let eth_bridge_event = EthToIotaTokenBridgeV1 { + nonce, + iota_chain_id, + eth_chain_id, + iota_address, + eth_address, + token_id, + amount, + }; + let encoded_bytes = BridgeAction::EthToIotaBridgeAction(EthToIotaBridgeAction { + eth_tx_hash, + eth_event_index, + eth_bridge_event, + }) + .to_bytes(); + + assert_eq!( + encoded_bytes, + Hex::decode("5355495f4252494447455f4d4553534147450001000000000000000a0b1400000000000000000000000000000000000000c801200000000000000000000000000000000000000000000000000000000000000064030000000000003039").unwrap(), + ); + + let hash = Keccak256::digest(encoded_bytes).digest; + assert_eq!( + hash.to_vec(), + Hex::decode("b352508c301a37bb1b68a75dd0fc42b6f692b2650818631c8f8a4d4d3e5bef46") + .unwrap(), + ); + Ok(()) + } + + #[test] + fn test_bridge_committee_construction() -> anyhow::Result<()> { + let (mut authority, _, _) = get_test_authority_and_key(10000, 9999); + // This is ok + let _ = BridgeCommittee::new(vec![authority.clone()]).unwrap(); + + // This is not ok - total voting power != 10000 + authority.voting_power = 9999; + let _ = BridgeCommittee::new(vec![authority.clone()]).unwrap_err(); + + // This is not ok - total voting power != 10000 + authority.voting_power = 10001; + let _ = BridgeCommittee::new(vec![authority.clone()]).unwrap_err(); + + // This is ok + authority.voting_power = 5000; + let mut authority_2 = authority.clone(); + let (_, kp): (_, fastcrypto::secp256k1::Secp256k1KeyPair) = get_key_pair(); + let pubkey = kp.public().clone(); + authority_2.pubkey = pubkey.clone(); + let _ = BridgeCommittee::new(vec![authority.clone(), authority_2.clone()]).unwrap(); + + // This is not ok - duplicate pub key + authority_2.pubkey = authority.pubkey.clone(); + let _ = BridgeCommittee::new(vec![authority.clone(), authority.clone()]).unwrap_err(); + Ok(()) + } + + #[test] + fn test_bridge_committee_total_blocklisted_stake() -> anyhow::Result<()> { + let (mut authority1, _, _) = get_test_authority_and_key(10000, 9999); + assert_eq!( + BridgeCommittee::new(vec![authority1.clone()]) + .unwrap() + .total_blocklisted_stake(), + 0 + ); + authority1.voting_power = 6000; + + let (mut authority2, _, _) = get_test_authority_and_key(4000, 9999); + authority2.is_blocklisted = true; + assert_eq!( + BridgeCommittee::new(vec![authority1.clone(), authority2.clone()]) + .unwrap() + .total_blocklisted_stake(), + 4000 + ); + + authority1.voting_power = 7000; + authority2.voting_power = 2000; + let (mut authority3, _, _) = get_test_authority_and_key(1000, 9999); + authority3.is_blocklisted = true; + assert_eq!( + BridgeCommittee::new(vec![authority1, authority2, authority3]) + .unwrap() + .total_blocklisted_stake(), + 3000 + ); + + Ok(()) + } + + #[test] + fn test_bridge_committee_filter_blocklisted_authorities() -> anyhow::Result<()> { + // Note: today BridgeCommitte does not shuffle authorities + let (authority1, _, _) = get_test_authority_and_key(5000, 9999); + let (mut authority2, _, _) = get_test_authority_and_key(3000, 9999); + authority2.is_blocklisted = true; + let (authority3, _, _) = get_test_authority_and_key(2000, 9999); + let committee = BridgeCommittee::new(vec![ + authority1.clone(), + authority2.clone(), + authority3.clone(), + ]) + .unwrap(); + + // exclude authority2 + let result = committee + .shuffle_by_stake(None, None) + .into_iter() + .collect::>(); + assert_eq!( + HashSet::from_iter(vec![authority1.pubkey_bytes(), authority3.pubkey_bytes()]), + result + ); + + // exclude authority2 and authority3 + let result = committee + .shuffle_by_stake( + None, + Some( + &[authority1.pubkey_bytes(), authority2.pubkey_bytes()] + .iter() + .cloned() + .collect(), + ), + ) + .into_iter() + .collect::>(); + assert_eq!(HashSet::from_iter(vec![authority1.pubkey_bytes()]), result); + + Ok(()) + } +} diff --git a/crates/iota-cluster-test/Cargo.toml b/crates/iota-cluster-test/Cargo.toml new file mode 100644 index 00000000000..b4496d67f82 --- /dev/null +++ b/crates/iota-cluster-test/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "iota-cluster-test" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +futures.workspace = true +serde_json.workspace = true +tempfile.workspace = true +tokio = { workspace = true, features = ["full"] } +jsonrpsee.workspace = true +tracing.workspace = true +clap.workspace = true +reqwest.workspace = true +async-trait.workspace = true +anyhow = { workspace = true, features = ["backtrace"] } +uuid.workspace = true +prometheus.workspace = true +fastcrypto.workspace = true +shared-crypto.workspace = true +derivative.workspace = true +regex.workspace = true + +iota-indexer.workspace = true +iota-faucet.workspace = true +iota-graphql-rpc.workspace = true +iota-swarm.workspace = true +iota.workspace = true +iota-swarm-config.workspace = true +iota-json-rpc-types.workspace = true +iota-sdk.workspace = true +iota-keys.workspace = true +iota-types.workspace = true +iota-core.workspace = true +iota-json.workspace = true +iota-config.workspace = true +iota-test-transaction-builder.workspace = true +telemetry-subscribers.workspace = true + +test-cluster.workspace = true +move-core-types.workspace = true + +[features] +pg_integration = [] diff --git a/crates/iota-cluster-test/src/cluster.rs b/crates/iota-cluster-test/src/cluster.rs new file mode 100644 index 00000000000..de1ae8e7c8e --- /dev/null +++ b/crates/iota-cluster-test/src/cluster.rs @@ -0,0 +1,374 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{net::SocketAddr, path::Path}; + +use async_trait::async_trait; +use iota_config::{Config, PersistedConfig, IOTA_KEYSTORE_FILENAME, IOTA_NETWORK_CONFIG}; +use iota_graphql_rpc::{ + config::ConnectionConfig, test_infra::cluster::start_graphql_server_with_fn_rpc, +}; +use iota_indexer::test_utils::{start_test_indexer, ReaderWriterConfig}; +use iota_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; +use iota_sdk::{ + iota_client_config::{IotaClientConfig, IotaEnv}, + wallet_context::WalletContext, +}; +use iota_swarm::memory::Swarm; +use iota_swarm_config::{genesis_config::GenesisConfig, network_config::NetworkConfig}; +use iota_types::{ + base_types::IotaAddress, + crypto::{get_key_pair, AccountKeyPair, IotaKeyPair, KeypairTraits}, +}; +use test_cluster::{TestCluster, TestClusterBuilder}; +use tracing::info; + +use super::config::{ClusterTestOpt, Env}; + +const DEVNET_FAUCET_ADDR: &str = "https://faucet.devnet.iota.io:443"; +const STAGING_FAUCET_ADDR: &str = "https://faucet.staging.iota.io:443"; +const CONTINUOUS_FAUCET_ADDR: &str = "https://faucet.ci.iota.io:443"; +const CONTINUOUS_NOMAD_FAUCET_ADDR: &str = "https://faucet.nomad.ci.iota.io:443"; +const TESTNET_FAUCET_ADDR: &str = "https://faucet.testnet.iota.io:443"; +const DEVNET_FULLNODE_ADDR: &str = "https://rpc.devnet.iota.io:443"; +const STAGING_FULLNODE_ADDR: &str = "https://fullnode.staging.iota.io:443"; +const CONTINUOUS_FULLNODE_ADDR: &str = "https://fullnode.ci.iota.io:443"; +const CONTINUOUS_NOMAD_FULLNODE_ADDR: &str = "https://fullnode.nomad.ci.iota.io:443"; +const TESTNET_FULLNODE_ADDR: &str = "https://fullnode.testnet.iota.io:443"; + +pub struct ClusterFactory; + +impl ClusterFactory { + pub async fn start( + options: &ClusterTestOpt, + ) -> Result, anyhow::Error> { + Ok(match &options.env { + Env::NewLocal => Box::new(LocalNewCluster::start(options).await?), + _ => Box::new(RemoteRunningCluster::start(options).await?), + }) + } +} + +/// Cluster Abstraction +#[async_trait] +pub trait Cluster { + async fn start(options: &ClusterTestOpt) -> Result + where + Self: Sized; + + fn fullnode_url(&self) -> &str; + fn user_key(&self) -> AccountKeyPair; + fn indexer_url(&self) -> &Option; + + /// Returns faucet url in a remote cluster. + fn remote_faucet_url(&self) -> Option<&str>; + + /// Returns faucet key in a local cluster. + fn local_faucet_key(&self) -> Option<&AccountKeyPair>; + + /// Place to put config for the wallet, and any locally running services. + fn config_directory(&self) -> &Path; +} + +/// Represents an up and running cluster deployed remotely. +pub struct RemoteRunningCluster { + fullnode_url: String, + faucet_url: String, + config_directory: tempfile::TempDir, +} + +#[async_trait] +impl Cluster for RemoteRunningCluster { + async fn start(options: &ClusterTestOpt) -> Result { + let (fullnode_url, faucet_url) = match options.env { + Env::Devnet => ( + String::from(DEVNET_FULLNODE_ADDR), + String::from(DEVNET_FAUCET_ADDR), + ), + Env::Staging => ( + String::from(STAGING_FULLNODE_ADDR), + String::from(STAGING_FAUCET_ADDR), + ), + Env::Ci => ( + String::from(CONTINUOUS_FULLNODE_ADDR), + String::from(CONTINUOUS_FAUCET_ADDR), + ), + Env::CiNomad => ( + String::from(CONTINUOUS_NOMAD_FULLNODE_ADDR), + String::from(CONTINUOUS_NOMAD_FAUCET_ADDR), + ), + Env::Testnet => ( + String::from(TESTNET_FULLNODE_ADDR), + String::from(TESTNET_FAUCET_ADDR), + ), + Env::CustomRemote => ( + options + .fullnode_address + .clone() + .expect("Expect 'fullnode_address' for Env::Custom"), + options + .faucet_address + .clone() + .expect("Expect 'faucet_address' for Env::Custom"), + ), + Env::NewLocal => unreachable!("NewLocal shouldn't use RemoteRunningCluster"), + }; + + // TODO: test connectivity before proceeding? + + Ok(Self { + fullnode_url, + faucet_url, + config_directory: tempfile::tempdir()?, + }) + } + + fn fullnode_url(&self) -> &str { + &self.fullnode_url + } + + fn indexer_url(&self) -> &Option { + &None + } + + fn user_key(&self) -> AccountKeyPair { + get_key_pair().1 + } + + fn remote_faucet_url(&self) -> Option<&str> { + Some(&self.faucet_url) + } + + fn local_faucet_key(&self) -> Option<&AccountKeyPair> { + None + } + + fn config_directory(&self) -> &Path { + self.config_directory.path() + } +} + +/// Represents a local Cluster which starts per cluster test run. +pub struct LocalNewCluster { + test_cluster: TestCluster, + fullnode_url: String, + indexer_url: Option, + faucet_key: AccountKeyPair, + config_directory: tempfile::TempDir, +} + +impl LocalNewCluster { + #[allow(unused)] + pub fn swarm(&self) -> &Swarm { + &self.test_cluster.swarm + } +} + +#[async_trait] +impl Cluster for LocalNewCluster { + async fn start(options: &ClusterTestOpt) -> Result { + // TODO: options should contain port instead of address + let fullnode_port = options.fullnode_address.as_ref().map(|addr| { + addr.parse::() + .expect("Unable to parse fullnode address") + .port() + }); + + let indexer_address = options.indexer_address.as_ref().map(|addr| { + addr.parse::() + .expect("Unable to parse indexer address") + }); + + let mut cluster_builder = TestClusterBuilder::new().enable_fullnode_events(); + + // Check if we already have a config directory that is passed + if let Some(config_dir) = options.config_dir.clone() { + assert!(options.epoch_duration_ms.is_none()); + // Load the config of the Iota authority. + let network_config_path = config_dir.join(IOTA_NETWORK_CONFIG); + let network_config: NetworkConfig = PersistedConfig::read(&network_config_path) + .map_err(|err| { + err.context(format!( + "Cannot open Iota network config file at {:?}", + network_config_path + )) + })?; + + cluster_builder = cluster_builder.set_network_config(network_config); + cluster_builder = cluster_builder.with_config_dir(config_dir); + } else { + // Let the faucet account hold 1000 gas objects on genesis + let genesis_config = GenesisConfig::custom_genesis(1, 100); + // Custom genesis should be build here where we add the extra accounts + cluster_builder = cluster_builder.set_genesis_config(genesis_config); + + if let Some(epoch_duration_ms) = options.epoch_duration_ms { + cluster_builder = cluster_builder.with_epoch_duration_ms(epoch_duration_ms); + } + } + + if let Some(rpc_port) = fullnode_port { + cluster_builder = cluster_builder.with_fullnode_rpc_port(rpc_port); + } + + let mut test_cluster = cluster_builder.build().await; + + // Use the wealthy account for faucet + let faucet_key = test_cluster.swarm.config_mut().account_keys.swap_remove(0); + let faucet_address = IotaAddress::from(faucet_key.public()); + info!(?faucet_address, "faucet_address"); + + // This cluster has fullnode handle, safe to unwrap + let fullnode_url = test_cluster.fullnode_handle.rpc_url.clone(); + + if let (Some(pg_address), Some(indexer_address)) = + (options.pg_address.clone(), indexer_address) + { + // Start in writer mode + start_test_indexer( + Some(pg_address.clone()), + fullnode_url.clone(), + ReaderWriterConfig::writer_mode(None), + ) + .await; + + // Start in reader mode + start_test_indexer( + Some(pg_address), + fullnode_url.clone(), + ReaderWriterConfig::reader_mode(indexer_address.to_string()), + ) + .await; + } + + if let Some(graphql_address) = &options.graphql_address { + let graphql_address = graphql_address.parse::()?; + let graphql_connection_config = ConnectionConfig::new( + Some(graphql_address.port()), + Some(graphql_address.ip().to_string()), + options.pg_address.clone(), + None, + None, + None, + ); + + start_graphql_server_with_fn_rpc( + graphql_connection_config.clone(), + Some(fullnode_url.clone()), + // cancellation_token + None, + ) + .await; + } + + // Let nodes connect to one another + tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; + + // TODO: test connectivity before proceeding? + Ok(Self { + test_cluster, + fullnode_url, + faucet_key, + config_directory: tempfile::tempdir()?, + indexer_url: options.indexer_address.clone(), + }) + } + + fn fullnode_url(&self) -> &str { + &self.fullnode_url + } + + fn indexer_url(&self) -> &Option { + &self.indexer_url + } + + fn user_key(&self) -> AccountKeyPair { + get_key_pair().1 + } + + fn remote_faucet_url(&self) -> Option<&str> { + None + } + + fn local_faucet_key(&self) -> Option<&AccountKeyPair> { + Some(&self.faucet_key) + } + + fn config_directory(&self) -> &Path { + self.config_directory.path() + } +} + +// Make linter happy +#[async_trait] +impl Cluster for Box { + async fn start(_options: &ClusterTestOpt) -> Result { + unreachable!( + "If we already have a boxed Cluster trait object we wouldn't have to call this function" + ); + } + fn fullnode_url(&self) -> &str { + (**self).fullnode_url() + } + fn indexer_url(&self) -> &Option { + (**self).indexer_url() + } + + fn user_key(&self) -> AccountKeyPair { + (**self).user_key() + } + + fn remote_faucet_url(&self) -> Option<&str> { + (**self).remote_faucet_url() + } + + fn local_faucet_key(&self) -> Option<&AccountKeyPair> { + (**self).local_faucet_key() + } + + fn config_directory(&self) -> &Path { + (**self).config_directory() + } +} + +pub fn new_wallet_context_from_cluster( + cluster: &(dyn Cluster + Sync + Send), + key_pair: AccountKeyPair, +) -> WalletContext { + let config_dir = cluster.config_directory(); + let wallet_config_path = config_dir.join("client.yaml"); + let fullnode_url = cluster.fullnode_url(); + info!("Use RPC: {}", &fullnode_url); + let keystore_path = config_dir.join(IOTA_KEYSTORE_FILENAME); + let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + let address: IotaAddress = key_pair.public().into(); + keystore + .add_key(None, IotaKeyPair::Ed25519(key_pair)) + .unwrap(); + IotaClientConfig { + keystore, + envs: vec![IotaEnv { + alias: "localnet".to_string(), + rpc: fullnode_url.into(), + ws: None, + }], + active_address: Some(address), + active_env: Some("localnet".to_string()), + } + .persisted(&wallet_config_path) + .save() + .unwrap(); + + info!( + "Initialize wallet from config path: {:?}", + wallet_config_path + ); + + WalletContext::new(&wallet_config_path, None, None).unwrap_or_else(|e| { + panic!( + "Failed to init wallet context from path {:?}, error: {e}", + wallet_config_path + ) + }) +} diff --git a/crates/iota-cluster-test/src/config.rs b/crates/iota-cluster-test/src/config.rs new file mode 100644 index 00000000000..7498303b6bc --- /dev/null +++ b/crates/iota-cluster-test/src/config.rs @@ -0,0 +1,75 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{fmt, path::PathBuf}; + +use clap::*; +use regex::Regex; + +#[derive(Parser, Clone, ValueEnum, Debug)] +pub enum Env { + Devnet, + Staging, + Ci, + CiNomad, + Testnet, + CustomRemote, + NewLocal, +} + +#[derive(derivative::Derivative, Parser)] +#[derivative(Debug)] +#[clap(name = "", rename_all = "kebab-case")] +pub struct ClusterTestOpt { + #[clap(value_enum)] + pub env: Env, + #[clap(long)] + pub faucet_address: Option, + #[clap(long)] + pub fullnode_address: Option, + #[clap(long)] + pub epoch_duration_ms: Option, + /// URL for the indexer RPC server + #[clap(long)] + pub indexer_address: Option, + /// URL for the Indexer Postgres DB + #[clap(long)] + #[derivative(Debug(format_with = "obfuscated_pg_address"))] + pub pg_address: Option, + #[clap(long)] + pub config_dir: Option, + /// URL for the indexer RPC server + #[clap(long)] + pub graphql_address: Option, +} + +fn obfuscated_pg_address(val: &Option, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match val { + None => write!(f, "None"), + Some(val) => { + write!( + f, + "{}", + Regex::new(r":.*@") + .unwrap() + .replace_all(val.as_str(), ":*****@") + ) + } + } +} + +impl ClusterTestOpt { + pub fn new_local() -> Self { + Self { + env: Env::NewLocal, + faucet_address: None, + fullnode_address: None, + epoch_duration_ms: None, + indexer_address: None, + pg_address: None, + config_dir: None, + graphql_address: None, + } + } +} diff --git a/crates/sui-cluster-test/src/faucet.rs b/crates/iota-cluster-test/src/faucet.rs similarity index 90% rename from crates/sui-cluster-test/src/faucet.rs rename to crates/iota-cluster-test/src/faucet.rs index c9a06b32234..a60a32251c4 100644 --- a/crates/sui-cluster-test/src/faucet.rs +++ b/crates/iota-cluster-test/src/faucet.rs @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, env, sync::Arc}; use async_trait::async_trait; use fastcrypto::encoding::{Encoding, Hex}; -use sui_faucet::{ +use iota_faucet::{ BatchFaucetResponse, BatchStatusFaucetResponse, Faucet, FaucetConfig, FaucetResponse, SimpleFaucet, }; -use sui_types::{base_types::SuiAddress, crypto::KeypairTraits}; +use iota_types::{base_types::IotaAddress, crypto::KeypairTraits}; use tracing::{debug, info, info_span, Instrument}; use uuid::Uuid; @@ -51,8 +52,8 @@ impl FaucetClientFactory { /// Faucet Client abstraction #[async_trait] pub trait FaucetClient { - async fn request_sui_coins(&self, request_address: SuiAddress) -> FaucetResponse; - async fn batch_request_sui_coins(&self, request_address: SuiAddress) -> BatchFaucetResponse; + async fn request_iota_coins(&self, request_address: IotaAddress) -> FaucetResponse; + async fn batch_request_iota_coins(&self, request_address: IotaAddress) -> BatchFaucetResponse; async fn get_batch_send_status(&self, task_id: Uuid) -> BatchStatusFaucetResponse; } @@ -70,9 +71,9 @@ impl RemoteFaucetClient { #[async_trait] impl FaucetClient for RemoteFaucetClient { - /// Request test SUI coins from faucet. + /// Request test IOTA coins from faucet. /// It also verifies the effects are observed by fullnode. - async fn request_sui_coins(&self, request_address: SuiAddress) -> FaucetResponse { + async fn request_iota_coins(&self, request_address: IotaAddress) -> FaucetResponse { let gas_url = format!("{}/gas", self.remote_url); debug!("Getting coin from remote faucet {}", gas_url); let data = HashMap::from([("recipient", Hex::encode(request_address))]); @@ -101,7 +102,7 @@ impl FaucetClient for RemoteFaucetClient { faucet_response } - async fn batch_request_sui_coins(&self, request_address: SuiAddress) -> BatchFaucetResponse { + async fn batch_request_iota_coins(&self, request_address: IotaAddress) -> BatchFaucetResponse { let gas_url = format!("{}/v1/gas", self.remote_url); debug!("Getting coin from remote faucet {}", gas_url); let data = HashMap::from([("recipient", Hex::encode(request_address))]); @@ -173,7 +174,7 @@ impl LocalFaucetClient { } #[async_trait] impl FaucetClient for LocalFaucetClient { - async fn request_sui_coins(&self, request_address: SuiAddress) -> FaucetResponse { + async fn request_iota_coins(&self, request_address: IotaAddress) -> FaucetResponse { let receipt = self .simple_faucet .send(Uuid::new_v4(), request_address, &[200_000_000_000; 5]) @@ -182,7 +183,7 @@ impl FaucetClient for LocalFaucetClient { receipt.into() } - async fn batch_request_sui_coins(&self, request_address: SuiAddress) -> BatchFaucetResponse { + async fn batch_request_iota_coins(&self, request_address: IotaAddress) -> BatchFaucetResponse { let receipt = self .simple_faucet .batch_send(Uuid::new_v4(), request_address, &[200_000_000_000; 5]) diff --git a/crates/sui-cluster-test/src/helper.rs b/crates/iota-cluster-test/src/helper.rs similarity index 77% rename from crates/sui-cluster-test/src/helper.rs rename to crates/iota-cluster-test/src/helper.rs index 087e7992759..e5190830e00 100644 --- a/crates/sui-cluster-test/src/helper.rs +++ b/crates/iota-cluster-test/src/helper.rs @@ -1,29 +1,30 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::bail; -use move_core_types::language_storage::TypeTag; -use sui_json_rpc_types::{BalanceChange, SuiData, SuiObjectData, SuiObjectDataOptions}; -use sui_sdk::SuiClient; -use sui_types::{ - base_types::ObjectID, error::SuiObjectResponseError, gas_coin::GasCoin, object::Owner, - parse_sui_type_tag, +use iota_json_rpc_types::{BalanceChange, IotaData, IotaObjectData, IotaObjectDataOptions}; +use iota_sdk::IotaClient; +use iota_types::{ + base_types::ObjectID, error::IotaObjectResponseError, gas_coin::GasCoin, object::Owner, + parse_iota_type_tag, }; +use move_core_types::language_storage::TypeTag; use tracing::{debug, trace}; -/// A util struct that helps verify Sui Object. +/// A util struct that helps verify Iota Object. /// Use builder style to construct the conditions. /// When optionals fields are not set, related checks are omitted. /// Consuming functions such as `check` perform the check and panics if /// verification results are unexpected. `check_into_object` and -/// `check_into_gas_coin` expect to get a `SuiObjectData` and `GasCoin` +/// `check_into_gas_coin` expect to get a `IotaObjectData` and `GasCoin` /// respectfully. #[derive(Debug)] pub struct ObjectChecker { object_id: ObjectID, owner: Option, is_deleted: bool, - is_sui_coin: Option, + is_iota_coin: Option, } impl ObjectChecker { @@ -32,7 +33,7 @@ impl ObjectChecker { object_id, owner: None, is_deleted: false, // default to exist - is_sui_coin: None, + is_iota_coin: None, } } @@ -46,27 +47,27 @@ impl ObjectChecker { self } - pub fn is_sui_coin(mut self, is_sui_coin: bool) -> Self { - self.is_sui_coin = Some(is_sui_coin); + pub fn is_iota_coin(mut self, is_iota_coin: bool) -> Self { + self.is_iota_coin = Some(is_iota_coin); self } - pub async fn check_into_gas_coin(self, client: &SuiClient) -> GasCoin { - if self.is_sui_coin == Some(false) { - panic!("'check_into_gas_coin' shouldn't be called with 'is_sui_coin' set as false"); + pub async fn check_into_gas_coin(self, client: &IotaClient) -> GasCoin { + if self.is_iota_coin == Some(false) { + panic!("'check_into_gas_coin' shouldn't be called with 'is_iota_coin' set as false"); } - self.is_sui_coin(true) + self.is_iota_coin(true) .check(client) .await .unwrap() .into_gas_coin() } - pub async fn check_into_object(self, client: &SuiClient) -> SuiObjectData { + pub async fn check_into_object(self, client: &IotaClient) -> IotaObjectData { self.check(client).await.unwrap().into_object() } - pub async fn check(self, client: &SuiClient) -> Result { + pub async fn check(self, client: &IotaClient) -> Result { debug!(?self); let object_id = self.object_id; @@ -74,7 +75,7 @@ impl ObjectChecker { .read_api() .get_object_with_options( object_id, - SuiObjectDataOptions::new() + IotaObjectDataOptions::new() .with_type() .with_owner() .with_bcs(), @@ -85,7 +86,7 @@ impl ObjectChecker { trace!("getting object {object_id}, info :: {object_info:?}"); match (object_info.data, object_info.error) { - (None, Some(SuiObjectResponseError::NotExists { object_id })) => { + (None, Some(IotaObjectResponseError::NotExists { object_id })) => { panic!( "Node can't find gas object {} with client {:?}", object_id, @@ -94,7 +95,7 @@ impl ObjectChecker { } ( None, - Some(SuiObjectResponseError::DynamicFieldNotFound { + Some(IotaObjectResponseError::DynamicFieldNotFound { parent_object_id: object_id, }), ) => { @@ -106,7 +107,7 @@ impl ObjectChecker { } ( None, - Some(SuiObjectResponseError::Deleted { + Some(IotaObjectResponseError::Deleted { object_id, version: _, digest: _, @@ -131,7 +132,7 @@ impl ObjectChecker { object_id, owner, object_owner ); } - if self.is_sui_coin == Some(true) { + if self.is_iota_coin == Some(true) { let move_obj = object .bcs .as_ref() @@ -144,10 +145,10 @@ impl ObjectChecker { } Ok(CheckerResultObject::new(None, Some(object))) } - (None, Some(SuiObjectResponseError::DisplayError { error })) => { + (None, Some(IotaObjectResponseError::DisplayError { error })) => { panic!("Display Error: {error:?}"); } - (None, None) | (None, Some(SuiObjectResponseError::Unknown)) => { + (None, None) | (None, Some(IotaObjectResponseError::Unknown)) => { panic!("Unexpected response: object not found and no specific error provided"); } } @@ -156,17 +157,17 @@ impl ObjectChecker { pub struct CheckerResultObject { gas_coin: Option, - object: Option, + object: Option, } impl CheckerResultObject { - pub fn new(gas_coin: Option, object: Option) -> Self { + pub fn new(gas_coin: Option, object: Option) -> Self { Self { gas_coin, object } } pub fn into_gas_coin(self) -> GasCoin { self.gas_coin.unwrap() } - pub fn into_object(self) -> SuiObjectData { + pub fn into_object(self) -> IotaObjectData { self.object.unwrap() } } @@ -202,7 +203,7 @@ impl BalanceChangeChecker { self } pub fn coin_type(mut self, coin_type: &str) -> Self { - self.coin_type = Some(parse_sui_type_tag(coin_type).unwrap()); + self.coin_type = Some(parse_iota_type_tag(coin_type).unwrap()); self } diff --git a/crates/iota-cluster-test/src/lib.rs b/crates/iota-cluster-test/src/lib.rs new file mode 100644 index 00000000000..55d7ade16db --- /dev/null +++ b/crates/iota-cluster-test/src/lib.rs @@ -0,0 +1,329 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use std::sync::Arc; + +use async_trait::async_trait; +use cluster::{Cluster, ClusterFactory}; +use config::ClusterTestOpt; +use futures::{stream::FuturesUnordered, StreamExt}; +use helper::ObjectChecker; +use iota_faucet::CoinInfo; +use iota_json_rpc_types::{ + IotaExecutionStatus, IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponse, + IotaTransactionBlockResponseOptions, TransactionBlockBytes, +}; +use iota_sdk::{wallet_context::WalletContext, IotaClient}; +use iota_test_transaction_builder::batch_make_transfer_transactions; +use iota_types::{ + base_types::{IotaAddress, TransactionDigest}, + gas_coin::GasCoin, + iota_system_state::iota_system_state_summary::IotaSystemStateSummary, + object::Owner, + quorum_driver_types::ExecuteTransactionRequestType, + transaction::{Transaction, TransactionData}, +}; +use jsonrpsee::{ + core::{client::ClientT, params::ArrayParams}, + http_client::HttpClientBuilder, +}; +use test_case::{ + coin_index_test::CoinIndexTest, coin_merge_split_test::CoinMergeSplitTest, + fullnode_build_publish_transaction_test::FullNodeBuildPublishTransactionTest, + fullnode_execute_transaction_test::FullNodeExecuteTransactionTest, + native_transfer_test::NativeTransferTest, shared_object_test::SharedCounterTest, +}; +use tokio::time::{self, Duration}; +use tracing::{error, info}; +use wallet_client::WalletClient; + +use crate::faucet::{FaucetClient, FaucetClientFactory}; + +pub mod cluster; +pub mod config; +pub mod faucet; +pub mod helper; +pub mod test_case; +pub mod wallet_client; + +#[allow(unused)] +pub struct TestContext { + /// Cluster handle that allows access to various components in a cluster + cluster: Box, + /// Client that provides wallet context and fullnode access + client: WalletClient, + /// Facuet client that provides faucet access to a test + faucet: Arc, +} + +impl TestContext { + async fn get_iota_from_faucet(&self, minimum_coins: Option) -> Vec { + let addr = self.get_wallet_address(); + let faucet_response = self.faucet.request_iota_coins(addr).await; + + let coin_info = faucet_response + .transferred_gas_objects + .iter() + .map(|coin_info| coin_info.transfer_tx_digest) + .collect::>(); + self.let_fullnode_sync(coin_info, 5).await; + + let gas_coins = self + .check_owner_and_into_gas_coin(faucet_response.transferred_gas_objects, addr) + .await; + + let minimum_coins = minimum_coins.unwrap_or(1); + + if gas_coins.len() < minimum_coins { + panic!( + "Expect to get at least {minimum_coins} Iota Coins for address {addr}, but only got {}", + gas_coins.len() + ) + } + + gas_coins + } + + fn get_context(&self) -> &WalletClient { + &self.client + } + + fn get_fullnode_client(&self) -> &IotaClient { + self.client.get_fullnode_client() + } + + fn clone_fullnode_client(&self) -> IotaClient { + self.client.get_fullnode_client().clone() + } + + fn get_fullnode_rpc_url(&self) -> &str { + self.cluster.fullnode_url() + } + + fn get_wallet(&self) -> &WalletContext { + self.client.get_wallet() + } + + async fn get_latest_iota_system_state(&self) -> IotaSystemStateSummary { + self.client + .get_fullnode_client() + .governance_api() + .get_latest_iota_system_state() + .await + .unwrap() + } + + async fn get_reference_gas_price(&self) -> u64 { + self.client + .get_fullnode_client() + .governance_api() + .get_reference_gas_price() + .await + .unwrap() + } + + fn get_wallet_address(&self) -> IotaAddress { + self.client.get_wallet_address() + } + + /// See `make_transactions_with_wallet_context` for potential caveats + /// of this helper function. + pub async fn make_transactions(&self, max_txn_num: usize) -> Vec { + batch_make_transfer_transactions(self.get_wallet(), max_txn_num).await + } + + pub async fn build_transaction_remotely( + &self, + method: &str, + params: ArrayParams, + ) -> anyhow::Result { + let fn_rpc_url = self.get_fullnode_rpc_url(); + // TODO cache this? + let rpc_client = HttpClientBuilder::default().build(fn_rpc_url)?; + + TransactionBlockBytes::to_data(rpc_client.request(method, params).await?) + } + + async fn sign_and_execute( + &self, + txn_data: TransactionData, + desc: &str, + ) -> IotaTransactionBlockResponse { + let signature = self.get_context().sign(&txn_data, desc); + let resp = self + .get_fullnode_client() + .quorum_driver_api() + .execute_transaction_block( + Transaction::from_data(txn_data, vec![signature]), + IotaTransactionBlockResponseOptions::new() + .with_object_changes() + .with_balance_changes() + .with_effects() + .with_events(), + Some(ExecuteTransactionRequestType::WaitForLocalExecution), + ) + .await + .unwrap_or_else(|e| panic!("Failed to execute transaction for {}. {}", desc, e)); + assert!( + matches!( + resp.effects.as_ref().unwrap().status(), + IotaExecutionStatus::Success + ), + "Failed to execute transaction for {desc}: {:?}", + resp + ); + resp + } + + pub async fn setup(options: ClusterTestOpt) -> Result { + let cluster = ClusterFactory::start(&options).await?; + let wallet_client = WalletClient::new_from_cluster(&cluster).await; + let faucet = FaucetClientFactory::new_from_cluster(&cluster).await; + Ok(Self { + cluster, + client: wallet_client, + faucet, + }) + } + + // TODO: figure out a more efficient way to test a local cluster + // A potential way to do this is to subscribe to txns from fullnode + // when the feature is ready + pub async fn let_fullnode_sync(&self, digests: Vec, timeout_sec: u64) { + let mut futures = FuturesUnordered::new(); + for digest in digests.clone() { + let task = self.get_tx_with_retry_times(digest, 1); + futures.push(Box::pin(task)); + } + let mut sleep = Box::pin(time::sleep(Duration::from_secs(timeout_sec))); + + loop { + tokio::select! { + _ = &mut sleep => { + panic!("Fullnode does not know all of {:?} after {} secs.", digests, timeout_sec); + } + res = futures.next() => { + match res { + Some((true, _, _)) => {}, + Some((false, digest, retry_times)) => { + let task = self.get_tx_with_retry_times(digest, retry_times); + futures.push(Box::pin(task)); + }, + None => break, // all txns appear on fullnode, mission completed + } + } + } + } + } + + async fn get_tx_with_retry_times( + &self, + digest: TransactionDigest, + retry_times: u64, + ) -> (bool, TransactionDigest, u64) { + match self + .client + .get_fullnode_client() + .read_api() + .get_transaction_with_options(digest, IotaTransactionBlockResponseOptions::new()) + .await + { + Ok(_) => (true, digest, retry_times), + Err(_) => { + time::sleep(Duration::from_millis(300 * retry_times)).await; + (false, digest, retry_times + 1) + } + } + } + + async fn check_owner_and_into_gas_coin( + &self, + coin_info: Vec, + owner: IotaAddress, + ) -> Vec { + futures::future::join_all( + coin_info + .iter() + .map(|coin_info| { + ObjectChecker::new(coin_info.id) + .owner(Owner::AddressOwner(owner)) + .check_into_gas_coin(self.get_fullnode_client()) + }) + .collect::>(), + ) + .await + .into_iter() + .collect::>() + } +} + +pub struct TestCase<'a> { + test_case: Box, +} + +impl<'a> TestCase<'a> { + pub fn new(test_case: impl TestCaseImpl + 'a) -> Self { + TestCase { + test_case: (Box::new(test_case)), + } + } + + pub async fn run(self, ctx: &mut TestContext) -> bool { + let test_name = self.test_case.name(); + info!("Running test {}.", test_name); + + // TODO: unwind panic and fail gracefully? + + match self.test_case.run(ctx).await { + Ok(()) => { + info!("Test {test_name} succeeded."); + true + } + Err(e) => { + error!("Test {test_name} failed with error: {e}."); + false + } + } + } +} + +#[async_trait] +pub trait TestCaseImpl { + fn name(&self) -> &'static str; + fn description(&self) -> &'static str; + async fn run(&self, ctx: &mut TestContext) -> Result<(), anyhow::Error>; +} + +pub struct ClusterTest; + +impl ClusterTest { + pub async fn run(options: ClusterTestOpt) { + let mut ctx = TestContext::setup(options) + .await + .unwrap_or_else(|e| panic!("Failed to set up TestContext, e: {e}")); + + // TODO: collect tests from each test_case file instead. + let tests = vec![ + TestCase::new(NativeTransferTest {}), + TestCase::new(CoinMergeSplitTest {}), + TestCase::new(SharedCounterTest {}), + TestCase::new(FullNodeExecuteTransactionTest {}), + TestCase::new(FullNodeBuildPublishTransactionTest {}), + TestCase::new(CoinIndexTest {}), + ]; + + // TODO: improve the runner parallelism for efficiency + // For now we run tests serially + let mut success_cnt = 0; + let total_cnt = tests.len() as i32; + for t in tests { + let is_success = t.run(&mut ctx).await as i32; + success_cnt += is_success; + } + if success_cnt < total_cnt { + // If any test failed, panic to bubble up the signal + panic!("{success_cnt} of {total_cnt} tests passed."); + } + info!("{success_cnt} of {total_cnt} tests passed."); + } +} diff --git a/crates/iota-cluster-test/src/main.rs b/crates/iota-cluster-test/src/main.rs new file mode 100644 index 00000000000..c6a0ff0da21 --- /dev/null +++ b/crates/iota-cluster-test/src/main.rs @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use clap::*; +use iota_cluster_test::{config::ClusterTestOpt, ClusterTest}; + +#[tokio::main] +async fn main() { + let _guard = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .init(); + + let options = ClusterTestOpt::parse(); + + ClusterTest::run(options).await; +} diff --git a/crates/sui-cluster-test/src/test_case.rs b/crates/iota-cluster-test/src/test_case.rs similarity index 84% rename from crates/sui-cluster-test/src/test_case.rs rename to crates/iota-cluster-test/src/test_case.rs index cfacfde3b3a..12d054d8132 100644 --- a/crates/sui-cluster-test/src/test_case.rs +++ b/crates/iota-cluster-test/src/test_case.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 pub mod coin_index_test; diff --git a/crates/sui-cluster-test/src/test_case/coin_index_test.rs b/crates/iota-cluster-test/src/test_case/coin_index_test.rs similarity index 86% rename from crates/sui-cluster-test/src/test_case/coin_index_test.rs rename to crates/iota-cluster-test/src/test_case/coin_index_test.rs index a95f60ea375..b5d61760ca7 100644 --- a/crates/sui-cluster-test/src/test_case/coin_index_test.rs +++ b/crates/iota-cluster-test/src/test_case/coin_index_test.rs @@ -1,24 +1,25 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::HashMap; use async_trait::async_trait; -use jsonrpsee::rpc_params; -use move_core_types::language_storage::StructTag; -use serde_json::json; -use sui_core::test_utils::compile_managed_coin_package; -use sui_json::SuiJsonValue; -use sui_json_rpc_types::{ - Balance, ObjectChange, SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, +use iota_core::test_utils::compile_managed_coin_package; +use iota_json::IotaJsonValue; +use iota_json_rpc_types::{ + Balance, IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, ObjectChange, }; -use sui_test_transaction_builder::make_staking_transaction; -use sui_types::{ +use iota_test_transaction_builder::make_staking_transaction; +use iota_types::{ base_types::{ObjectID, ObjectRef}, gas_coin::GAS, object::Owner, quorum_driver_types::ExecuteTransactionRequestType, }; +use jsonrpsee::rpc_params; +use move_core_types::language_storage::StructTag; +use serde_json::json; use tracing::info; use crate::{TestCaseImpl, TestContext}; @@ -41,7 +42,7 @@ impl TestCaseImpl for CoinIndexTest { let rgp = ctx.get_reference_gas_price().await; // 0. Get some coins first - ctx.get_sui_from_faucet(None).await; + ctx.get_iota_from_faucet(None).await; // Record initial balances let Balance { @@ -56,7 +57,7 @@ impl TestCaseImpl for CoinIndexTest { .quorum_driver_api() .execute_transaction_block( txn, - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_effects() .with_balance_changes(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), @@ -102,19 +103,19 @@ impl TestCaseImpl for CoinIndexTest { // 2. Test Staking let validator_addr = ctx - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await .active_validators .first() .unwrap() - .sui_address; + .iota_address; let txn = make_staking_transaction(ctx.get_wallet(), validator_addr).await; let response = client .quorum_driver_api() .execute_transaction_block( txn, - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_effects() .with_balance_changes(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), @@ -133,7 +134,7 @@ impl TestCaseImpl for CoinIndexTest { assert_eq!( total_balance, (old_total_balance as i128 + balance_change.amount) as u128, - "total_balance: {}, old_total_balance: {}, sui_balance_change.amount: {}", + "total_balance: {}, old_total_balance: {}, iota_balance_change.amount: {}", total_balance, old_total_balance, balance_change.amount @@ -150,15 +151,15 @@ impl TestCaseImpl for CoinIndexTest { "token package published, package: {:?}, cap: {:?}", package, cap ); - let sui_type_str = "0x2::sui::SUI"; + let iota_type_str = "0x2::iota::IOTA"; let coin_type_str = format!("{}::managed::MANAGED", package.0); info!("coin type: {}", coin_type_str); // 4. Mint 1 MANAGED coin to account, balance 10000 let args = vec![ - SuiJsonValue::from_object_id(cap.0), - SuiJsonValue::new(json!("10000"))?, - SuiJsonValue::new(json!(account))?, + IotaJsonValue::from_object_id(cap.0), + IotaJsonValue::new(json!("10000"))?, + IotaJsonValue::new(json!(account))?, ]; let txn = client .transaction_builder() @@ -178,16 +179,16 @@ impl TestCaseImpl for CoinIndexTest { let response = ctx.sign_and_execute(txn, "mint managed coin to self").await; let balance_changes = &response.balance_changes.unwrap(); - let sui_balance_change = balance_changes + let iota_balance_change = balance_changes .iter() - .find(|b| b.coin_type.to_string().contains("SUI")) + .find(|b| b.coin_type.to_string().contains("IOTA")) .unwrap(); let managed_balance_change = balance_changes .iter() .find(|b| b.coin_type.to_string().contains("MANAGED")) .unwrap(); - assert_eq!(sui_balance_change.owner, Owner::AddressOwner(account)); + assert_eq!(iota_balance_change.owner, Owner::AddressOwner(account)); assert_eq!(managed_balance_change.owner, Owner::AddressOwner(account)); let Balance { total_balance, .. } = @@ -195,11 +196,11 @@ impl TestCaseImpl for CoinIndexTest { assert_eq!(coin_object_count, old_coin_object_count); assert_eq!( total_balance, - (old_total_balance as i128 + sui_balance_change.amount) as u128, - "total_balance: {}, old_total_balance: {}, sui_balance_change.amount: {}", + (old_total_balance as i128 + iota_balance_change.amount) as u128, + "total_balance: {}, old_total_balance: {}, iota_balance_change.amount: {}", total_balance, old_total_balance, - sui_balance_change.amount + iota_balance_change.amount ); old_coin_object_count = coin_object_count; @@ -222,7 +223,7 @@ impl TestCaseImpl for CoinIndexTest { let mut balances = client.coin_read_api().get_all_balances(account).await?; let mut expected_balances = vec![ Balance { - coin_type: sui_type_str.into(), + coin_type: iota_type_str.into(), coin_object_count: old_coin_object_count, total_balance, locked_balance: HashMap::new(), @@ -250,9 +251,9 @@ impl TestCaseImpl for CoinIndexTest { "mint", vec![], vec![ - SuiJsonValue::from_object_id(cap.0), - SuiJsonValue::new(json!("10"))?, - SuiJsonValue::new(json!(account))?, + IotaJsonValue::from_object_id(cap.0), + IotaJsonValue::new(json!("10"))?, + IotaJsonValue::new(json!(account))?, ], None, rgp * 2_000_000, @@ -310,7 +311,7 @@ impl TestCaseImpl for CoinIndexTest { let managed_old_total_count = managed_balance.coin_object_count; // 7. take back the balance 10 MANAGED coin - let args = vec![SuiJsonValue::from_object_id(envelope.0)]; + let args = vec![IotaJsonValue::from_object_id(envelope.0)]; let txn = client .transaction_builder() .move_call( @@ -357,8 +358,8 @@ impl TestCaseImpl for CoinIndexTest { "take_from_envelope_and_burn", vec![], vec![ - SuiJsonValue::from_object_id(cap.0), - SuiJsonValue::from_object_id(envelope.0), + IotaJsonValue::from_object_id(cap.0), + IotaJsonValue::from_object_id(envelope.0), ], None, rgp * 2_000_000, @@ -389,8 +390,8 @@ impl TestCaseImpl for CoinIndexTest { "burn", vec![], vec![ - SuiJsonValue::from_object_id(cap.0), - SuiJsonValue::from_object_id(managed_coin_id_10k), + IotaJsonValue::from_object_id(cap.0), + IotaJsonValue::from_object_id(managed_coin_id_10k), ], None, rgp * 2_000_000, @@ -410,15 +411,15 @@ impl TestCaseImpl for CoinIndexTest { // =========================== Test Get Coins Starts =========================== - let sui_coins = client + let iota_coins = client .coin_read_api() - .get_coins(account, Some(sui_type_str.into()), None, None) + .get_coins(account, Some(iota_type_str.into()), None, None) .await .unwrap() .data; assert_eq!( - sui_coins, + iota_coins, client .coin_read_api() .get_coins(account, None, None, None) @@ -427,8 +428,8 @@ impl TestCaseImpl for CoinIndexTest { .data, ); assert_eq!( - // this is only SUI coins at the moment - sui_coins, + // this is only IOTA coins at the moment + iota_coins, client .coin_read_api() .get_all_coins(account, None, None) @@ -437,14 +438,14 @@ impl TestCaseImpl for CoinIndexTest { .data, ); - let sui_balance = client + let iota_balance = client .coin_read_api() .get_balance(account, None) .await .unwrap(); assert_eq!( - sui_balance.total_balance, - sui_coins.iter().map(|c| c.balance as u128).sum::() + iota_balance.total_balance, + iota_coins.iter().map(|c| c.balance as u128).sum::() ); // 11. Mint 40 MANAGED coins with balance 5 @@ -457,10 +458,10 @@ impl TestCaseImpl for CoinIndexTest { "mint_multi", vec![], vec![ - SuiJsonValue::from_object_id(cap.0), - SuiJsonValue::new(json!("5"))?, // balance = 5 - SuiJsonValue::new(json!("40"))?, // num = 40 - SuiJsonValue::new(json!(account))?, + IotaJsonValue::from_object_id(cap.0), + IotaJsonValue::new(json!("5"))?, // balance = 5 + IotaJsonValue::new(json!("40"))?, // num = 40 + IotaJsonValue::new(json!(account))?, ], None, rgp * 2_000_000, @@ -471,19 +472,19 @@ impl TestCaseImpl for CoinIndexTest { let response = ctx.sign_and_execute(txn, "multi mint").await; assert!(response.status_ok().unwrap()); - let sui_coins = client + let iota_coins = client .coin_read_api() - .get_coins(account, Some(sui_type_str.into()), None, None) + .get_coins(account, Some(iota_type_str.into()), None, None) .await .unwrap() .data; // No more even if ask for more assert_eq!( - sui_coins, + iota_coins, client .coin_read_api() - .get_coins(account, None, None, Some(sui_coins.len() + 1)) + .get_coins(account, None, None, Some(iota_coins.len() + 1)) .await .unwrap() .data, @@ -516,23 +517,23 @@ impl TestCaseImpl for CoinIndexTest { } } - assert_eq!(sui_coins.len() + managed_coins.len(), total_coins,); + assert_eq!(iota_coins.len() + managed_coins.len(), total_coins,); - let sui_coins_with_managed_coin_1 = client + let iota_coins_with_managed_coin_1 = client .coin_read_api() - .get_all_coins(account, None, Some(sui_coins.len() + 1)) + .get_all_coins(account, None, Some(iota_coins.len() + 1)) .await .unwrap(); assert_eq!( - sui_coins_with_managed_coin_1.data.len(), - sui_coins.len() + 1 + iota_coins_with_managed_coin_1.data.len(), + iota_coins.len() + 1 ); assert_eq!( - sui_coins_with_managed_coin_1.next_cursor, + iota_coins_with_managed_coin_1.next_cursor, Some(first_managed_coin) ); - assert!(sui_coins_with_managed_coin_1.has_next_page); - let cursor = sui_coins_with_managed_coin_1.next_cursor; + assert!(iota_coins_with_managed_coin_1.has_next_page); + let cursor = iota_coins_with_managed_coin_1.next_cursor; let managed_coins_2_11 = client .coin_read_api() @@ -695,7 +696,7 @@ async fn add_to_envelope( pkg_id: ObjectID, envelope: ObjectID, coin: ObjectID, -) -> SuiTransactionBlockResponse { +) -> IotaTransactionBlockResponse { let account = ctx.get_wallet_address(); let client = ctx.clone_fullnode_client(); let rgp = ctx.get_reference_gas_price().await; @@ -708,8 +709,8 @@ async fn add_to_envelope( "add_to_envelope", vec![], vec![ - SuiJsonValue::from_object_id(envelope), - SuiJsonValue::from_object_id(coin), + IotaJsonValue::from_object_id(envelope), + IotaJsonValue::from_object_id(coin), ], None, rgp * 2_000_000, diff --git a/crates/sui-cluster-test/src/test_case/coin_merge_split_test.rs b/crates/iota-cluster-test/src/test_case/coin_merge_split_test.rs similarity index 87% rename from crates/sui-cluster-test/src/test_case/coin_merge_split_test.rs rename to crates/iota-cluster-test/src/test_case/coin_merge_split_test.rs index 1dee0e9a787..62b8a653c20 100644 --- a/crates/sui-cluster-test/src/test_case/coin_merge_split_test.rs +++ b/crates/iota-cluster-test/src/test_case/coin_merge_split_test.rs @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_trait::async_trait; -use jsonrpsee::rpc_params; -use sui_json_rpc_types::{SuiTransactionBlockEffectsAPI, SuiTransactionBlockResponse}; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, +use iota_json_rpc_types::{IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponse}; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + iota_serde::BigInt, object::Owner, - sui_serde::BigInt, }; +use jsonrpsee::rpc_params; use tracing::{debug, info}; use crate::{helper::ObjectChecker, TestCaseImpl, TestContext}; @@ -22,17 +23,17 @@ impl TestCaseImpl for CoinMergeSplitTest { } fn description(&self) -> &'static str { - "Test merge and split SUI coins" + "Test merge and split IOTA coins" } async fn run(&self, ctx: &mut TestContext) -> Result<(), anyhow::Error> { - let mut sui_objs = ctx.get_sui_from_faucet(Some(1)).await; - let gas_obj = sui_objs.swap_remove(0); + let mut iota_objs = ctx.get_iota_from_faucet(Some(1)).await; + let gas_obj = iota_objs.swap_remove(0); let signer = ctx.get_wallet_address(); - let mut sui_objs_2 = ctx.get_sui_from_faucet(Some(1)).await; + let mut iota_objs_2 = ctx.get_iota_from_faucet(Some(1)).await; - let primary_coin = sui_objs_2.swap_remove(0); + let primary_coin = iota_objs_2.swap_remove(0); let primary_coin_id = *primary_coin.id(); let original_value = primary_coin.value(); @@ -120,11 +121,11 @@ impl TestCaseImpl for CoinMergeSplitTest { impl CoinMergeSplitTest { async fn merge_coin( ctx: &TestContext, - signer: SuiAddress, + signer: IotaAddress, primary_coin: ObjectID, coin_to_merge: ObjectID, gas_obj_id: ObjectID, - ) -> SuiTransactionBlockResponse { + ) -> IotaTransactionBlockResponse { let params = rpc_params![ signer, primary_coin, @@ -143,11 +144,11 @@ impl CoinMergeSplitTest { async fn split_coin( ctx: &TestContext, - signer: SuiAddress, + signer: IotaAddress, primary_coin: ObjectID, amounts: Vec>, gas_obj_id: ObjectID, - ) -> SuiTransactionBlockResponse { + ) -> IotaTransactionBlockResponse { let params = rpc_params![ signer, primary_coin, diff --git a/crates/sui-cluster-test/src/test_case/fullnode_build_publish_transaction_test.rs b/crates/iota-cluster-test/src/test_case/fullnode_build_publish_transaction_test.rs similarity index 87% rename from crates/sui-cluster-test/src/test_case/fullnode_build_publish_transaction_test.rs rename to crates/iota-cluster-test/src/test_case/fullnode_build_publish_transaction_test.rs index bf37dacac4b..471848f59c9 100644 --- a/crates/sui-cluster-test/src/test_case/fullnode_build_publish_transaction_test.rs +++ b/crates/iota-cluster-test/src/test_case/fullnode_build_publish_transaction_test.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_trait::async_trait; +use iota_core::test_utils::compile_basics_package; +use iota_json_rpc_types::IotaTransactionBlockEffectsAPI; +use iota_types::{base_types::ObjectID, object::Owner}; use jsonrpsee::rpc_params; -use sui_core::test_utils::compile_basics_package; -use sui_json_rpc_types::SuiTransactionBlockEffectsAPI; -use sui_types::{base_types::ObjectID, object::Owner}; use crate::{TestCaseImpl, TestContext}; diff --git a/crates/sui-cluster-test/src/test_case/fullnode_execute_transaction_test.rs b/crates/iota-cluster-test/src/test_case/fullnode_execute_transaction_test.rs similarity index 80% rename from crates/sui-cluster-test/src/test_case/fullnode_execute_transaction_test.rs rename to crates/iota-cluster-test/src/test_case/fullnode_execute_transaction_test.rs index 71ae0698d1e..f95a2cab6a5 100644 --- a/crates/sui-cluster-test/src/test_case/fullnode_execute_transaction_test.rs +++ b/crates/iota-cluster-test/src/test_case/fullnode_execute_transaction_test.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_trait::async_trait; -use sui_json_rpc_types::{ - SuiExecutionStatus, SuiTransactionBlockEffectsAPI, SuiTransactionBlockResponseOptions, +use iota_json_rpc_types::{ + IotaExecutionStatus, IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponseOptions, }; -use sui_sdk::SuiClient; -use sui_types::{ +use iota_sdk::IotaClient; +use iota_types::{ base_types::TransactionDigest, quorum_driver_types::ExecuteTransactionRequestType, }; use tracing::info; @@ -16,10 +17,10 @@ use crate::{TestCaseImpl, TestContext}; pub struct FullNodeExecuteTransactionTest; impl FullNodeExecuteTransactionTest { - async fn verify_transaction(fullnode: &SuiClient, tx_digest: TransactionDigest) { + async fn verify_transaction(fullnode: &IotaClient, tx_digest: TransactionDigest) { fullnode .read_api() - .get_transaction_with_options(tx_digest, SuiTransactionBlockResponseOptions::new()) + .get_transaction_with_options(tx_digest, IotaTransactionBlockResponseOptions::new()) .await .unwrap_or_else(|e| { panic!( @@ -42,7 +43,7 @@ impl TestCaseImpl for FullNodeExecuteTransactionTest { async fn run(&self, ctx: &mut TestContext) -> Result<(), anyhow::Error> { let txn_count = 4; - ctx.get_sui_from_faucet(Some(1)).await; + ctx.get_iota_from_faucet(Some(1)).await; let mut txns = ctx.make_transactions(txn_count).await; assert!( @@ -62,7 +63,7 @@ impl TestCaseImpl for FullNodeExecuteTransactionTest { .quorum_driver_api() .execute_transaction_block( txn, - SuiTransactionBlockResponseOptions::new().with_effects(), + IotaTransactionBlockResponseOptions::new().with_effects(), Some(ExecuteTransactionRequestType::WaitForEffectsCert), ) .await?; @@ -70,7 +71,7 @@ impl TestCaseImpl for FullNodeExecuteTransactionTest { assert!(!response.confirmed_local_execution.unwrap()); assert_eq!(txn_digest, response.digest); let effects = response.effects.unwrap(); - if !matches!(effects.status(), SuiExecutionStatus::Success { .. }) { + if !matches!(effects.status(), IotaExecutionStatus::Success { .. }) { panic!( "Failed to execute transfer transaction {:?}: {:?}", txn_digest, @@ -89,14 +90,14 @@ impl TestCaseImpl for FullNodeExecuteTransactionTest { .quorum_driver_api() .execute_transaction_block( txn, - SuiTransactionBlockResponseOptions::new().with_effects(), + IotaTransactionBlockResponseOptions::new().with_effects(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; assert!(response.confirmed_local_execution.unwrap()); assert_eq!(txn_digest, response.digest); let effects = response.effects.unwrap(); - if !matches!(effects.status(), SuiExecutionStatus::Success { .. }) { + if !matches!(effects.status(), IotaExecutionStatus::Success { .. }) { panic!( "Failed to execute transfer transaction {:?}: {:?}", txn_digest, diff --git a/crates/sui-cluster-test/src/test_case/native_transfer_test.rs b/crates/iota-cluster-test/src/test_case/native_transfer_test.rs similarity index 77% rename from crates/sui-cluster-test/src/test_case/native_transfer_test.rs rename to crates/iota-cluster-test/src/test_case/native_transfer_test.rs index 6ce1f865f74..134bf001324 100644 --- a/crates/sui-cluster-test/src/test_case/native_transfer_test.rs +++ b/crates/iota-cluster-test/src/test_case/native_transfer_test.rs @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_trait::async_trait; -use jsonrpsee::rpc_params; -use sui_json_rpc_types::SuiTransactionBlockResponse; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, +use iota_json_rpc_types::IotaTransactionBlockResponse; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, crypto::{get_key_pair, AccountKeyPair}, object::Owner, }; +use jsonrpsee::rpc_params; use tracing::info; use crate::{ @@ -25,18 +26,18 @@ impl TestCaseImpl for NativeTransferTest { } fn description(&self) -> &'static str { - "Test tranferring SUI coins natively" + "Test tranferring IOTA coins natively" } async fn run(&self, ctx: &mut TestContext) -> Result<(), anyhow::Error> { info!("Testing gas coin transfer"); - let mut sui_objs = ctx.get_sui_from_faucet(Some(1)).await; - let gas_obj = ctx.get_sui_from_faucet(Some(1)).await.swap_remove(0); + let mut iota_objs = ctx.get_iota_from_faucet(Some(1)).await; + let gas_obj = ctx.get_iota_from_faucet(Some(1)).await.swap_remove(0); let signer = ctx.get_wallet_address(); let (recipient_addr, _): (_, AccountKeyPair) = get_key_pair(); // Test transfer object - let obj_to_transfer: ObjectID = *sui_objs.swap_remove(0).id(); + let obj_to_transfer: ObjectID = *iota_objs.swap_remove(0).id(); let params = rpc_params![ signer, obj_to_transfer, @@ -51,9 +52,9 @@ impl TestCaseImpl for NativeTransferTest { Self::examine_response(ctx, &mut response, signer, recipient_addr, obj_to_transfer).await; - let mut sui_objs_2 = ctx.get_sui_from_faucet(Some(1)).await; - // Test transfer sui - let obj_to_transfer_2 = *sui_objs_2.swap_remove(0).id(); + let mut iota_objs_2 = ctx.get_iota_from_faucet(Some(1)).await; + // Test transfer iota + let obj_to_transfer_2 = *iota_objs_2.swap_remove(0).id(); let params = rpc_params![ signer, obj_to_transfer_2, @@ -62,7 +63,7 @@ impl TestCaseImpl for NativeTransferTest { None:: ]; let data = ctx - .build_transaction_remotely("unsafe_transferSui", params) + .build_transaction_remotely("unsafe_transferIota", params) .await?; let mut response = ctx.sign_and_execute(data, "coin transfer").await; @@ -74,9 +75,9 @@ impl TestCaseImpl for NativeTransferTest { impl NativeTransferTest { async fn examine_response( ctx: &TestContext, - response: &mut SuiTransactionBlockResponse, - signer: SuiAddress, - recipient: SuiAddress, + response: &mut IotaTransactionBlockResponse, + signer: IotaAddress, + recipient: IotaAddress, obj_to_transfer_id: ObjectID, ) { let balance_changes = &mut response.balance_changes.as_mut().unwrap(); @@ -95,11 +96,11 @@ impl NativeTransferTest { } BalanceChangeChecker::new() .owner(Owner::AddressOwner(recipient)) - .coin_type("0x2::sui::SUI") + .coin_type("0x2::iota::IOTA") .check(&balance_changes.remove(0)); BalanceChangeChecker::new() .owner(Owner::AddressOwner(signer)) - .coin_type("0x2::sui::SUI") + .coin_type("0x2::iota::IOTA") .check(&balance_changes.remove(0)); // Verify fullnode observes the txn ctx.let_fullnode_sync(vec![response.digest], 5).await; diff --git a/crates/sui-cluster-test/src/test_case/shared_object_test.rs b/crates/iota-cluster-test/src/test_case/shared_object_test.rs similarity index 85% rename from crates/sui-cluster-test/src/test_case/shared_object_test.rs rename to crates/iota-cluster-test/src/test_case/shared_object_test.rs index d7beabdbb71..6a1722842b0 100644 --- a/crates/sui-cluster-test/src/test_case/shared_object_test.rs +++ b/crates/iota-cluster-test/src/test_case/shared_object_test.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_trait::async_trait; -use sui_json_rpc_types::{SuiExecutionStatus, SuiTransactionBlockEffectsAPI}; -use sui_sdk::wallet_context::WalletContext; -use sui_test_transaction_builder::{increment_counter, publish_basics_package_and_make_counter}; -use sui_types::object::Owner; +use iota_json_rpc_types::{IotaExecutionStatus, IotaTransactionBlockEffectsAPI}; +use iota_sdk::wallet_context::WalletContext; +use iota_test_transaction_builder::{increment_counter, publish_basics_package_and_make_counter}; +use iota_types::object::Owner; use tracing::info; use crate::{helper::ObjectChecker, TestCaseImpl, TestContext}; @@ -25,8 +26,8 @@ impl TestCaseImpl for SharedCounterTest { async fn run(&self, ctx: &mut TestContext) -> Result<(), anyhow::Error> { info!("Testing shared object transactions."); - let sui_objs = ctx.get_sui_from_faucet(Some(1)).await; - assert!(!sui_objs.is_empty()); + let iota_objs = ctx.get_iota_from_faucet(Some(1)).await; + assert!(!iota_objs.is_empty()); let wallet_context: &WalletContext = ctx.get_wallet(); let address = ctx.get_wallet_address(); @@ -43,7 +44,7 @@ impl TestCaseImpl for SharedCounterTest { .await; assert_eq!( *response.effects.as_ref().unwrap().status(), - SuiExecutionStatus::Success, + IotaExecutionStatus::Success, "Increment counter txn failed: {:?}", *response.effects.as_ref().unwrap().status() ); diff --git a/crates/iota-cluster-test/src/wallet_client.rs b/crates/iota-cluster-test/src/wallet_client.rs new file mode 100644 index 00000000000..e4d9150443f --- /dev/null +++ b/crates/iota-cluster-test/src/wallet_client.rs @@ -0,0 +1,66 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_keys::keystore::AccountKeystore; +use iota_sdk::{wallet_context::WalletContext, IotaClient, IotaClientBuilder}; +use iota_types::{ + base_types::IotaAddress, + crypto::{KeypairTraits, Signature}, + transaction::TransactionData, +}; +use shared_crypto::intent::Intent; +use tracing::{info, info_span, Instrument}; + +use super::Cluster; +use crate::cluster::new_wallet_context_from_cluster; + +pub struct WalletClient { + wallet_context: WalletContext, + address: IotaAddress, + fullnode_client: IotaClient, +} + +#[allow(clippy::borrowed_box)] +impl WalletClient { + pub async fn new_from_cluster(cluster: &(dyn Cluster + Sync + Send)) -> Self { + let key = cluster.user_key(); + let address: IotaAddress = key.public().into(); + let wallet_context = new_wallet_context_from_cluster(cluster, key) + .instrument(info_span!("init_wallet_context_for_test_user")); + + let rpc_url = String::from(cluster.fullnode_url()); + info!("Use fullnode rpc: {}", &rpc_url); + let fullnode_client = IotaClientBuilder::default().build(rpc_url).await.unwrap(); + + Self { + wallet_context: wallet_context.into_inner(), + address, + fullnode_client, + } + } + + pub fn get_wallet(&self) -> &WalletContext { + &self.wallet_context + } + + pub fn get_wallet_mut(&mut self) -> &mut WalletContext { + &mut self.wallet_context + } + + pub fn get_wallet_address(&self) -> IotaAddress { + self.address + } + + pub fn get_fullnode_client(&self) -> &IotaClient { + &self.fullnode_client + } + + pub fn sign(&self, txn_data: &TransactionData, desc: &str) -> Signature { + self.get_wallet() + .config + .keystore + .sign_secure(&self.address, txn_data, Intent::iota_transaction()) + .unwrap_or_else(|e| panic!("Failed to sign transaction for {}. {}", desc, e)) + } +} diff --git a/crates/sui-cluster-test/tests/local_cluster_test.rs b/crates/iota-cluster-test/tests/local_cluster_test.rs similarity index 86% rename from crates/sui-cluster-test/tests/local_cluster_test.rs rename to crates/iota-cluster-test/tests/local_cluster_test.rs index 1cb15f2e499..4f4d22ae6f6 100644 --- a/crates/sui-cluster-test/tests/local_cluster_test.rs +++ b/crates/iota-cluster-test/tests/local_cluster_test.rs @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use sui_cluster_test::{config::ClusterTestOpt, ClusterTest}; +use iota_cluster_test::{config::ClusterTestOpt, ClusterTest}; #[tokio::test] async fn cluster_test() { @@ -12,17 +13,17 @@ async fn cluster_test() { #[cfg(feature = "pg_integration")] #[tokio::test] -async fn test_sui_cluster() { - use reqwest::StatusCode; - use sui_cluster_test::{ +async fn test_iota_cluster() { + use iota_cluster_test::{ cluster::{Cluster, LocalNewCluster}, config::Env, }; - use sui_graphql_rpc::client::simple_client::SimpleClient; + use iota_graphql_rpc::client::simple_client::SimpleClient; + use reqwest::StatusCode; use tokio::time::sleep; let fullnode_rpc_port: u16 = 9020; let indexer_rpc_port: u16 = 9124; - let pg_address = "postgres://postgres:postgrespw@localhost:5432/sui_indexer".to_string(); + let pg_address = "postgres://postgres:postgrespw@localhost:5432/iota_indexer".to_string(); let graphql_address = format!("127.0.0.1:{}", 8000); let opts = ClusterTestOpt { diff --git a/crates/iota-common/Cargo.toml b/crates/iota-common/Cargo.toml new file mode 100644 index 00000000000..296e75cf304 --- /dev/null +++ b/crates/iota-common/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "iota-common" +authors = ["Mysten Labs "] +license = "Apache-2.0" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +iota-types.workspace = true +mysten-metrics.workspace = true +tokio.workspace = true +tracing.workspace = true +futures.workspace = true diff --git a/crates/sui-common/src/authority_aggregation.rs b/crates/iota-common/src/authority_aggregation.rs similarity index 98% rename from crates/sui-common/src/authority_aggregation.rs rename to crates/iota-common/src/authority_aggregation.rs index ebcb8124c9e..70e91a9ec8e 100644 --- a/crates/sui-common/src/authority_aggregation.rs +++ b/crates/iota-common/src/authority_aggregation.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -8,11 +9,11 @@ use std::{ }; use futures::{future::BoxFuture, stream::FuturesUnordered, Future, StreamExt}; -use mysten_metrics::monitored_future; -use sui_types::{ +use iota_types::{ base_types::ConciseableName, committee::{CommitteeTrait, StakeUnit}, }; +use mysten_metrics::monitored_future; use tokio::time::timeout; use tracing::instrument::Instrument; diff --git a/crates/iota-common/src/lib.rs b/crates/iota-common/src/lib.rs new file mode 100644 index 00000000000..10e44bc89b5 --- /dev/null +++ b/crates/iota-common/src/lib.rs @@ -0,0 +1,5 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod authority_aggregation; diff --git a/crates/iota-config/Cargo.toml b/crates/iota-config/Cargo.toml new file mode 100644 index 00000000000..0a5e41624cb --- /dev/null +++ b/crates/iota-config/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "iota-config" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anemo.workspace = true +anyhow = { workspace = true, features = ["backtrace"] } +bcs.workspace = true +csv.workspace = true +dirs.workspace = true +fastcrypto.workspace = true +once_cell.workspace = true +rand.workspace = true +serde = { workspace = true, features = ["derive", "rc"] } +serde_with.workspace = true +serde_yaml.workspace = true +tracing.workspace = true +prometheus.workspace = true +clap.workspace = true +object_store.workspace = true +reqwest.workspace = true + +narwhal-config.workspace = true +iota-keys.workspace = true +iota-protocol-config.workspace = true +iota-types.workspace = true + +[dev-dependencies] +insta.workspace = true +tempfile.workspace = true +iota-types = { workspace = true, features = ["test-utils"] } diff --git a/crates/sui-config/data/fullnode-template-with-path.yaml b/crates/iota-config/data/fullnode-template-with-path.yaml similarity index 89% rename from crates/sui-config/data/fullnode-template-with-path.yaml rename to crates/iota-config/data/fullnode-template-with-path.yaml index 07ac7e7f5dd..b0fc801dc76 100644 --- a/crates/sui-config/data/fullnode-template-with-path.yaml +++ b/crates/iota-config/data/fullnode-template-with-path.yaml @@ -1,5 +1,5 @@ -# Update this value to the location you want Sui to store its database -db-path: "suidb" +# Update this value to the location you want Iota to store its database +db-path: "iotadb" # For ipv4, update this to "/ipv4/X.X.X.X/tcp/8080/http" network-address: "/dns/localhost/tcp/8080/http" diff --git a/crates/sui-config/data/fullnode-template.yaml b/crates/iota-config/data/fullnode-template.yaml similarity index 78% rename from crates/sui-config/data/fullnode-template.yaml rename to crates/iota-config/data/fullnode-template.yaml index f0816a26990..cb5d6438eb8 100644 --- a/crates/sui-config/data/fullnode-template.yaml +++ b/crates/iota-config/data/fullnode-template.yaml @@ -1,5 +1,5 @@ -# Update this value to the location you want Sui to store its database -db-path: "/opt/sui/db" +# Update this value to the location you want Iota to store its database +db-path: "/opt/iota/db" # For ipv4, update this to "/ipv4/X.X.X.X/tcp/8080/http" network-address: "/dns/localhost/tcp/8080/http" @@ -10,7 +10,7 @@ enable-event-processing: true genesis: # Update this to the location of where the genesis file is stored - genesis-file-location: "/opt/sui/config/genesis.blob" + genesis-file-location: "/opt/iota/config/genesis.blob" authority-store-pruning-config: num-latest-epoch-dbs-to-retain: 3 diff --git a/crates/sui-config/src/certificate_deny_config.rs b/crates/iota-config/src/certificate_deny_config.rs similarity index 95% rename from crates/sui-config/src/certificate_deny_config.rs rename to crates/iota-config/src/certificate_deny_config.rs index a9293ac08df..d28fc204b1b 100644 --- a/crates/sui-config/src/certificate_deny_config.rs +++ b/crates/iota-config/src/certificate_deny_config.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::HashSet; +use iota_types::base_types::TransactionDigest; use once_cell::sync::OnceCell; use serde::{Deserialize, Serialize}; -use sui_types::base_types::TransactionDigest; #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] diff --git a/crates/iota-config/src/genesis.rs b/crates/iota-config/src/genesis.rs new file mode 100644 index 00000000000..25fcd846d99 --- /dev/null +++ b/crates/iota-config/src/genesis.rs @@ -0,0 +1,674 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{fs, path::Path}; + +use anyhow::{Context, Result}; +use fastcrypto::{ + encoding::{Base64, Encoding}, + hash::HashFunction, +}; +use iota_types::{ + authenticator_state::{get_authenticator_state, AuthenticatorStateInner}, + base_types::{IotaAddress, ObjectID}, + clock::Clock, + committee::{Committee, CommitteeWithNetworkMetadata, EpochId, ProtocolVersion}, + crypto::DefaultHash, + deny_list::{get_coin_deny_list, PerTypeDenyList}, + effects::{TransactionEffects, TransactionEvents}, + error::IotaResult, + gas_coin::TOTAL_SUPPLY_MICROS, + iota_system_state::{ + get_iota_system_state, get_iota_system_state_wrapper, IotaSystemState, + IotaSystemStateTrait, IotaSystemStateWrapper, IotaValidatorGenesis, + }, + messages_checkpoint::{ + CertifiedCheckpointSummary, CheckpointContents, CheckpointSummary, VerifiedCheckpoint, + }, + object::Object, + storage::ObjectStore, + transaction::Transaction, + IOTA_RANDOMNESS_STATE_OBJECT_ID, +}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use tracing::trace; + +#[derive(Clone, Debug)] +pub struct Genesis { + checkpoint: CertifiedCheckpointSummary, + checkpoint_contents: CheckpointContents, + transaction: Transaction, + effects: TransactionEffects, + events: TransactionEvents, + objects: Vec, +} + +#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug)] +pub struct UnsignedGenesis { + pub checkpoint: CheckpointSummary, + pub checkpoint_contents: CheckpointContents, + pub transaction: Transaction, + pub effects: TransactionEffects, + pub events: TransactionEvents, + pub objects: Vec, +} + +// Hand implement PartialEq in order to get around the fact that AuthSigs don't +// impl Eq +impl PartialEq for Genesis { + fn eq(&self, other: &Self) -> bool { + self.checkpoint.data() == other.checkpoint.data() + && { + let this = self.checkpoint.auth_sig(); + let other = other.checkpoint.auth_sig(); + + this.epoch == other.epoch + && this.signature.as_ref() == other.signature.as_ref() + && this.signers_map == other.signers_map + } + && self.checkpoint_contents == other.checkpoint_contents + && self.transaction == other.transaction + && self.effects == other.effects + && self.objects == other.objects + } +} + +impl Eq for Genesis {} + +impl Genesis { + pub fn new( + checkpoint: CertifiedCheckpointSummary, + checkpoint_contents: CheckpointContents, + transaction: Transaction, + effects: TransactionEffects, + events: TransactionEvents, + objects: Vec, + ) -> Self { + Self { + checkpoint, + checkpoint_contents, + transaction, + effects, + events, + objects, + } + } + + pub fn objects(&self) -> &[Object] { + &self.objects + } + + pub fn object(&self, id: ObjectID) -> Option { + self.objects.iter().find(|o| o.id() == id).cloned() + } + + pub fn transaction(&self) -> &Transaction { + &self.transaction + } + + pub fn effects(&self) -> &TransactionEffects { + &self.effects + } + pub fn events(&self) -> &TransactionEvents { + &self.events + } + + pub fn checkpoint(&self) -> VerifiedCheckpoint { + self.checkpoint + .clone() + .verify(&self.committee().unwrap()) + .unwrap() + } + + pub fn checkpoint_contents(&self) -> &CheckpointContents { + &self.checkpoint_contents + } + + pub fn epoch(&self) -> EpochId { + 0 + } + + pub fn validator_set_for_tooling(&self) -> Vec { + self.iota_system_object() + .into_genesis_version_for_tooling() + .validators + .active_validators + } + + pub fn committee_with_network(&self) -> CommitteeWithNetworkMetadata { + self.iota_system_object().get_current_epoch_committee() + } + + pub fn reference_gas_price(&self) -> u64 { + self.iota_system_object().reference_gas_price() + } + + // TODO: No need to return IotaResult. + pub fn committee(&self) -> IotaResult { + Ok(self.committee_with_network().committee) + } + + pub fn iota_system_wrapper_object(&self) -> IotaSystemStateWrapper { + get_iota_system_state_wrapper(&self.objects()) + .expect("Iota System State Wrapper object must always exist") + } + + pub fn iota_system_object(&self) -> IotaSystemState { + get_iota_system_state(&self.objects()).expect("Iota System State object must always exist") + } + + pub fn clock(&self) -> Clock { + let clock = self + .objects() + .iter() + .find(|o| o.id() == iota_types::IOTA_CLOCK_OBJECT_ID) + .expect("Clock must always exist") + .data + .try_as_move() + .expect("Clock must be a Move object"); + bcs::from_bytes::(clock.contents()) + .expect("Clock object deserialization cannot fail") + } + + pub fn load>(path: P) -> Result { + let path = path.as_ref(); + trace!("Reading Genesis from {}", path.display()); + let bytes = fs::read(path) + .with_context(|| format!("Unable to load Genesis from {}", path.display()))?; + bcs::from_bytes(&bytes) + .with_context(|| format!("Unable to parse Genesis from {}", path.display())) + } + + pub fn save>(&self, path: P) -> Result<(), anyhow::Error> { + let path = path.as_ref(); + trace!("Writing Genesis to {}", path.display()); + let bytes = bcs::to_bytes(&self)?; + fs::write(path, bytes) + .with_context(|| format!("Unable to save Genesis to {}", path.display()))?; + Ok(()) + } + + pub fn to_bytes(&self) -> Vec { + bcs::to_bytes(self).expect("failed to serialize genesis") + } + + pub fn hash(&self) -> [u8; 32] { + use std::io::Write; + + let mut digest = DefaultHash::default(); + digest.write_all(&self.to_bytes()).unwrap(); + let hash = digest.finalize(); + hash.into() + } +} + +impl Serialize for Genesis { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::Error; + + #[derive(Serialize)] + struct RawGenesis<'a> { + checkpoint: &'a CertifiedCheckpointSummary, + checkpoint_contents: &'a CheckpointContents, + transaction: &'a Transaction, + effects: &'a TransactionEffects, + events: &'a TransactionEvents, + objects: &'a [Object], + } + + let raw_genesis = RawGenesis { + checkpoint: &self.checkpoint, + checkpoint_contents: &self.checkpoint_contents, + transaction: &self.transaction, + effects: &self.effects, + events: &self.events, + objects: &self.objects, + }; + + let bytes = bcs::to_bytes(&raw_genesis).map_err(|e| Error::custom(e.to_string()))?; + + if serializer.is_human_readable() { + let s = Base64::encode(&bytes); + serializer.serialize_str(&s) + } else { + serializer.serialize_bytes(&bytes) + } + } +} + +impl<'de> Deserialize<'de> for Genesis { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de::Error; + + #[derive(Deserialize)] + struct RawGenesis { + checkpoint: CertifiedCheckpointSummary, + checkpoint_contents: CheckpointContents, + transaction: Transaction, + effects: TransactionEffects, + events: TransactionEvents, + objects: Vec, + } + + let bytes = if deserializer.is_human_readable() { + let s = String::deserialize(deserializer)?; + Base64::decode(&s).map_err(|e| Error::custom(e.to_string()))? + } else { + let data: Vec = Vec::deserialize(deserializer)?; + data + }; + + let RawGenesis { + checkpoint, + checkpoint_contents, + transaction, + effects, + events, + objects, + } = bcs::from_bytes(&bytes).map_err(|e| Error::custom(e.to_string()))?; + + Ok(Genesis { + checkpoint, + checkpoint_contents, + transaction, + effects, + events, + objects, + }) + } +} + +impl UnsignedGenesis { + pub fn objects(&self) -> &[Object] { + &self.objects + } + + pub fn object(&self, id: ObjectID) -> Option { + self.objects.iter().find(|o| o.id() == id).cloned() + } + + pub fn transaction(&self) -> &Transaction { + &self.transaction + } + + pub fn effects(&self) -> &TransactionEffects { + &self.effects + } + pub fn events(&self) -> &TransactionEvents { + &self.events + } + + pub fn checkpoint(&self) -> &CheckpointSummary { + &self.checkpoint + } + + pub fn checkpoint_contents(&self) -> &CheckpointContents { + &self.checkpoint_contents + } + + pub fn epoch(&self) -> EpochId { + 0 + } + + pub fn iota_system_wrapper_object(&self) -> IotaSystemStateWrapper { + get_iota_system_state_wrapper(&self.objects()) + .expect("Iota System State Wrapper object must always exist") + } + + pub fn iota_system_object(&self) -> IotaSystemState { + get_iota_system_state(&self.objects()).expect("Iota System State object must always exist") + } + + pub fn authenticator_state_object(&self) -> Option { + get_authenticator_state(&self.objects()).expect("read from genesis cannot fail") + } + + pub fn has_randomness_state_object(&self) -> bool { + self.objects() + .get_object(&IOTA_RANDOMNESS_STATE_OBJECT_ID) + .expect("read from genesis cannot fail") + .is_some() + } + + pub fn coin_deny_list_state(&self) -> Option { + get_coin_deny_list(&self.objects()) + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub struct GenesisChainParameters { + pub protocol_version: u64, + pub chain_start_timestamp_ms: u64, + pub epoch_duration_ms: u64, + + // Stake Subsidy parameters + pub stake_subsidy_start_epoch: u64, + pub stake_subsidy_initial_distribution_amount: u64, + pub stake_subsidy_period_length: u64, + pub stake_subsidy_decrease_rate: u16, + + // Validator committee parameters + pub max_validator_count: u64, + pub min_validator_joining_stake: u64, + pub validator_low_stake_threshold: u64, + pub validator_very_low_stake_threshold: u64, + pub validator_low_stake_grace_period: u64, +} + +/// Initial set of parameters for a chain. +#[derive(Serialize, Deserialize)] +pub struct GenesisCeremonyParameters { + #[serde(default = "GenesisCeremonyParameters::default_timestamp_ms")] + pub chain_start_timestamp_ms: u64, + + /// protocol version that the chain starts at. + #[serde(default = "ProtocolVersion::max")] + pub protocol_version: ProtocolVersion, + + #[serde(default = "GenesisCeremonyParameters::default_allow_insertion_of_extra_objects")] + pub allow_insertion_of_extra_objects: bool, + + /// The duration of an epoch, in milliseconds. + #[serde(default = "GenesisCeremonyParameters::default_epoch_duration_ms")] + pub epoch_duration_ms: u64, + + /// The starting epoch in which stake subsidies start being paid out. + #[serde(default)] + pub stake_subsidy_start_epoch: u64, + + /// The amount of stake subsidy to be drawn down per distribution. + /// This amount decays and decreases over time. + #[serde( + default = "GenesisCeremonyParameters::default_initial_stake_subsidy_distribution_amount" + )] + pub stake_subsidy_initial_distribution_amount: u64, + + /// Number of distributions to occur before the distribution amount decays. + #[serde(default = "GenesisCeremonyParameters::default_stake_subsidy_period_length")] + pub stake_subsidy_period_length: u64, + + /// The rate at which the distribution amount decays at the end of each + /// period. Expressed in basis points. + #[serde(default = "GenesisCeremonyParameters::default_stake_subsidy_decrease_rate")] + pub stake_subsidy_decrease_rate: u16, + // Most other parameters (e.g. initial gas schedule) should be derived from protocol_version. +} + +impl GenesisCeremonyParameters { + pub fn new() -> Self { + Self { + chain_start_timestamp_ms: Self::default_timestamp_ms(), + protocol_version: ProtocolVersion::MAX, + allow_insertion_of_extra_objects: true, + stake_subsidy_start_epoch: 0, + epoch_duration_ms: Self::default_epoch_duration_ms(), + stake_subsidy_initial_distribution_amount: + Self::default_initial_stake_subsidy_distribution_amount(), + stake_subsidy_period_length: Self::default_stake_subsidy_period_length(), + stake_subsidy_decrease_rate: Self::default_stake_subsidy_decrease_rate(), + } + } + + fn default_timestamp_ms() -> u64 { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_millis() as u64 + } + + fn default_allow_insertion_of_extra_objects() -> bool { + true + } + + fn default_epoch_duration_ms() -> u64 { + // 24 hrs + 24 * 60 * 60 * 1000 + } + + fn default_initial_stake_subsidy_distribution_amount() -> u64 { + // 1M Iota + 1_000_000 * iota_types::gas_coin::MICROS_PER_IOTA + } + + fn default_stake_subsidy_period_length() -> u64 { + // 10 distributions or epochs + 10 + } + + fn default_stake_subsidy_decrease_rate() -> u16 { + // 10% in basis points + 1000 + } + + pub fn to_genesis_chain_parameters(&self) -> GenesisChainParameters { + GenesisChainParameters { + protocol_version: self.protocol_version.as_u64(), + stake_subsidy_start_epoch: self.stake_subsidy_start_epoch, + chain_start_timestamp_ms: self.chain_start_timestamp_ms, + epoch_duration_ms: self.epoch_duration_ms, + stake_subsidy_initial_distribution_amount: self + .stake_subsidy_initial_distribution_amount, + stake_subsidy_period_length: self.stake_subsidy_period_length, + stake_subsidy_decrease_rate: self.stake_subsidy_decrease_rate, + max_validator_count: iota_types::governance::MAX_VALIDATOR_COUNT, + min_validator_joining_stake: iota_types::governance::MIN_VALIDATOR_JOINING_STAKE_MICROS, + validator_low_stake_threshold: + iota_types::governance::VALIDATOR_LOW_STAKE_THRESHOLD_MICROS, + validator_very_low_stake_threshold: + iota_types::governance::VALIDATOR_VERY_LOW_STAKE_THRESHOLD_MICROS, + validator_low_stake_grace_period: + iota_types::governance::VALIDATOR_LOW_STAKE_GRACE_PERIOD, + } + } +} + +impl Default for GenesisCeremonyParameters { + fn default() -> Self { + Self::new() + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub struct TokenDistributionSchedule { + pub stake_subsidy_fund_micros: u64, + pub allocations: Vec, +} + +impl TokenDistributionSchedule { + pub fn validate(&self) { + let mut total_micros = self.stake_subsidy_fund_micros; + + for allocation in &self.allocations { + total_micros += allocation.amount_micros; + } + + if total_micros != TOTAL_SUPPLY_MICROS { + panic!( + "TokenDistributionSchedule adds up to {total_micros} and not expected {TOTAL_SUPPLY_MICROS}" + ); + } + } + + pub fn check_all_stake_operations_are_for_valid_validators< + I: IntoIterator, + >( + &self, + validators: I, + ) { + use std::collections::HashMap; + + let mut validators: HashMap = + validators.into_iter().map(|a| (a, 0)).collect(); + + // Check that all allocations are for valid validators, while summing up all + // allocations for each validator + for allocation in &self.allocations { + if let Some(staked_with_validator) = &allocation.staked_with_validator { + *validators + .get_mut(staked_with_validator) + .expect("allocation must be staked with valid validator") += + allocation.amount_micros; + } + } + + // Check that all validators have sufficient stake allocated to ensure they meet + // the minimum stake threshold + let minimum_required_stake = iota_types::governance::VALIDATOR_LOW_STAKE_THRESHOLD_MICROS; + for (validator, stake) in validators { + if stake < minimum_required_stake { + panic!( + "validator {validator} has '{stake}' stake and does not meet the minimum required stake threshold of '{minimum_required_stake}'" + ); + } + } + } + + pub fn new_for_validators_with_default_allocation>( + validators: I, + ) -> Self { + let mut supply = TOTAL_SUPPLY_MICROS; + let default_allocation = iota_types::governance::VALIDATOR_LOW_STAKE_THRESHOLD_MICROS; + + let allocations = validators + .into_iter() + .map(|a| { + supply -= default_allocation; + TokenAllocation { + recipient_address: a, + amount_micros: default_allocation, + staked_with_validator: Some(a), + } + }) + .collect(); + + let schedule = Self { + stake_subsidy_fund_micros: supply, + allocations, + }; + + schedule.validate(); + schedule + } + + /// Helper to read a TokenDistributionSchedule from a csv file. + /// + /// The file is encoded such that the final entry in the CSV file is used to + /// denote the allocation to the stake subsidy fund. It must be in the + /// following format: + /// `0x0000000000000000000000000000000000000000000000000000000000000000, + /// ,` + /// + /// All entries in a token distribution schedule must add up to 10B Iota. + pub fn from_csv(reader: R) -> Result { + let mut reader = csv::Reader::from_reader(reader); + let mut allocations: Vec = + reader.deserialize().collect::>()?; + assert_eq!( + TOTAL_SUPPLY_MICROS, + allocations.iter().map(|a| a.amount_micros).sum::(), + "Token Distribution Schedule must add up to 10B Iota", + ); + let stake_subsidy_fund_allocation = allocations.pop().unwrap(); + assert_eq!( + IotaAddress::default(), + stake_subsidy_fund_allocation.recipient_address, + "Final allocation must be for stake subsidy fund", + ); + assert!( + stake_subsidy_fund_allocation + .staked_with_validator + .is_none(), + "Can't stake the stake subsidy fund", + ); + + let schedule = Self { + stake_subsidy_fund_micros: stake_subsidy_fund_allocation.amount_micros, + allocations, + }; + + schedule.validate(); + Ok(schedule) + } + + pub fn to_csv(&self, writer: W) -> Result<()> { + let mut writer = csv::Writer::from_writer(writer); + + for allocation in &self.allocations { + writer.serialize(allocation)?; + } + + writer.serialize(TokenAllocation { + recipient_address: IotaAddress::default(), + amount_micros: self.stake_subsidy_fund_micros, + staked_with_validator: None, + })?; + + Ok(()) + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub struct TokenAllocation { + pub recipient_address: IotaAddress, + pub amount_micros: u64, + + /// Indicates if this allocation should be staked at genesis and with which + /// validator + pub staked_with_validator: Option, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct TokenDistributionScheduleBuilder { + pool: u64, + allocations: Vec, +} + +impl TokenDistributionScheduleBuilder { + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + Self { + pool: TOTAL_SUPPLY_MICROS, + allocations: vec![], + } + } + + pub fn default_allocation_for_validators>( + &mut self, + validators: I, + ) { + let default_allocation = iota_types::governance::VALIDATOR_LOW_STAKE_THRESHOLD_MICROS; + + for validator in validators { + self.add_allocation(TokenAllocation { + recipient_address: validator, + amount_micros: default_allocation, + staked_with_validator: Some(validator), + }); + } + } + + pub fn add_allocation(&mut self, allocation: TokenAllocation) { + self.pool = self.pool.checked_sub(allocation.amount_micros).unwrap(); + self.allocations.push(allocation); + } + + pub fn build(&self) -> TokenDistributionSchedule { + let schedule = TokenDistributionSchedule { + stake_subsidy_fund_micros: self.pool, + allocations: self.allocations.clone(), + }; + + schedule.validate(); + schedule + } +} diff --git a/crates/iota-config/src/lib.rs b/crates/iota-config/src/lib.rs new file mode 100644 index 00000000000..554c0e5f4f5 --- /dev/null +++ b/crates/iota-config/src/lib.rs @@ -0,0 +1,141 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + fs, + path::{Path, PathBuf}, +}; + +use anyhow::{Context, Result}; +use serde::{de::DeserializeOwned, Serialize}; +use tracing::trace; + +pub mod certificate_deny_config; +pub mod genesis; +pub mod local_ip_utils; +pub mod node; +pub mod node_config_metrics; +pub mod object_storage_config; +pub mod p2p; +pub mod transaction_deny_config; + +use iota_types::multiaddr::Multiaddr; +pub use node::{ConsensusConfig, NodeConfig}; + +const IOTA_DIR: &str = ".iota"; +pub const IOTA_CONFIG_DIR: &str = "iota_config"; +pub const IOTA_NETWORK_CONFIG: &str = "network.yaml"; +pub const IOTA_FULLNODE_CONFIG: &str = "fullnode.yaml"; +pub const IOTA_CLIENT_CONFIG: &str = "client.yaml"; +pub const IOTA_KEYSTORE_FILENAME: &str = "iota.keystore"; +pub const IOTA_KEYSTORE_ALIASES_FILENAME: &str = "iota.aliases"; +pub const IOTA_BENCHMARK_GENESIS_GAS_KEYSTORE_FILENAME: &str = "benchmark.keystore"; +pub const IOTA_GENESIS_FILENAME: &str = "genesis.blob"; +pub const IOTA_DEV_NET_URL: &str = "https://fullnode.devnet.iota.io:443"; + +pub const AUTHORITIES_DB_NAME: &str = "authorities_db"; +pub const CONSENSUS_DB_NAME: &str = "consensus_db"; +pub const FULL_NODE_DB_PATH: &str = "full_node_db"; + +pub fn iota_config_dir() -> Result { + match std::env::var_os("IOTA_CONFIG_DIR") { + Some(config_env) => Ok(config_env.into()), + None => match dirs::home_dir() { + Some(v) => Ok(v.join(IOTA_DIR).join(IOTA_CONFIG_DIR)), + None => anyhow::bail!("Cannot obtain home directory path"), + }, + } + .and_then(|dir| { + if !dir.exists() { + fs::create_dir_all(dir.clone())?; + } + Ok(dir) + }) +} + +pub fn validator_config_file(address: Multiaddr, i: usize) -> String { + multiaddr_to_filename(address).unwrap_or(format!("validator-config-{}.yaml", i)) +} + +pub fn ssfn_config_file(address: Multiaddr, i: usize) -> String { + multiaddr_to_filename(address).unwrap_or(format!("ssfn-config-{}.yaml", i)) +} + +fn multiaddr_to_filename(address: Multiaddr) -> Option { + if let Some(hostname) = address.hostname() { + if let Some(port) = address.port() { + return Some(format!("{}-{}.yaml", hostname, port)); + } + } + None +} + +pub trait Config +where + Self: DeserializeOwned + Serialize, +{ + fn persisted(self, path: &Path) -> PersistedConfig { + PersistedConfig { + inner: self, + path: path.to_path_buf(), + } + } + + fn load>(path: P) -> Result { + let path = path.as_ref(); + trace!("Reading config from {}", path.display()); + let reader = fs::File::open(path) + .with_context(|| format!("Unable to load config from {}", path.display()))?; + Ok(serde_yaml::from_reader(reader)?) + } + + fn save>(&self, path: P) -> Result<(), anyhow::Error> { + let path = path.as_ref(); + trace!("Writing config to {}", path.display()); + let config = serde_yaml::to_string(&self)?; + fs::write(path, config) + .with_context(|| format!("Unable to save config to {}", path.display()))?; + Ok(()) + } +} + +pub struct PersistedConfig { + inner: C, + path: PathBuf, +} + +impl PersistedConfig +where + C: Config, +{ + pub fn read(path: &Path) -> Result { + Config::load(path) + } + + pub fn save(&self) -> Result<(), anyhow::Error> { + self.inner.save(&self.path) + } + + pub fn into_inner(self) -> C { + self.inner + } + + pub fn path(&self) -> &Path { + &self.path + } +} + +impl std::ops::Deref for PersistedConfig { + type Target = C; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl std::ops::DerefMut for PersistedConfig { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} diff --git a/crates/sui-config/src/local_ip_utils.rs b/crates/iota-config/src/local_ip_utils.rs similarity index 98% rename from crates/sui-config/src/local_ip_utils.rs rename to crates/iota-config/src/local_ip_utils.rs index eb8ae104a6d..14057564bd1 100644 --- a/crates/sui-config/src/local_ip_utils.rs +++ b/crates/iota-config/src/local_ip_utils.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::net::SocketAddr; #[cfg(msim)] use std::sync::{atomic::AtomicI16, Arc}; -use sui_types::multiaddr::Multiaddr; +use iota_types::multiaddr::Multiaddr; /// A singleton struct to manage IP addresses and ports for simtest. /// This allows us to generate unique IP addresses and ports for each node in diff --git a/crates/iota-config/src/node.rs b/crates/iota-config/src/node.rs new file mode 100644 index 00000000000..8cdadcc76af --- /dev/null +++ b/crates/iota-config/src/node.rs @@ -0,0 +1,1092 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use std::{ + collections::{BTreeMap, BTreeSet}, + net::SocketAddr, + num::NonZeroUsize, + path::{Path, PathBuf}, + sync::Arc, + time::Duration, + usize, +}; + +use anyhow::Result; +use iota_keys::keypair_file::{read_authority_keypair_from_file, read_keypair_from_file}; +use iota_protocol_config::{Chain, SupportedProtocolVersions}; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + committee::EpochId, + crypto::{ + get_key_pair_from_rng, AccountKeyPair, AuthorityKeyPair, AuthorityPublicKeyBytes, + IotaKeyPair, KeypairTraits, NetworkKeyPair, + }, + messages_checkpoint::CheckpointSequenceNumber, + multiaddr::Multiaddr, +}; +use narwhal_config::Parameters as ConsensusParameters; +use once_cell::sync::OnceCell; +use rand::rngs::OsRng; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; +use tracing::info; + +use crate::{ + certificate_deny_config::CertificateDenyConfig, genesis, + object_storage_config::ObjectStoreConfig, p2p::P2pConfig, + transaction_deny_config::TransactionDenyConfig, Config, +}; + +// Default max number of concurrent requests served +pub const DEFAULT_GRPC_CONCURRENCY_LIMIT: usize = 20000000000; + +/// Default gas price of 100 Micros +pub const DEFAULT_VALIDATOR_GAS_PRICE: u64 = iota_types::transaction::DEFAULT_VALIDATOR_GAS_PRICE; + +/// Default commission rate of 2% +pub const DEFAULT_COMMISSION_RATE: u64 = 200; + +#[serde_as] +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct NodeConfig { + #[serde(default = "default_authority_key_pair")] + pub protocol_key_pair: AuthorityKeyPairWithPath, + #[serde(default = "default_key_pair")] + pub worker_key_pair: KeyPairWithPath, + #[serde(default = "default_key_pair")] + pub account_key_pair: KeyPairWithPath, + #[serde(default = "default_key_pair")] + pub network_key_pair: KeyPairWithPath, + + pub db_path: PathBuf, + #[serde(default = "default_grpc_address")] + pub network_address: Multiaddr, + #[serde(default = "default_json_rpc_address")] + pub json_rpc_address: SocketAddr, + + #[serde(default)] + pub enable_experimental_rest_api: bool, + + #[serde(default = "default_metrics_address")] + pub metrics_address: SocketAddr, + #[serde(default = "default_admin_interface_port")] + pub admin_interface_port: u16, + + #[serde(skip_serializing_if = "Option::is_none")] + pub consensus_config: Option, + + // TODO: Remove this as it's no longer used. + #[serde(default)] + pub enable_event_processing: bool, + + #[serde(default = "default_enable_index_processing")] + pub enable_index_processing: bool, + + // only alow websocket connections for jsonrpc traffic + #[serde(default)] + pub websocket_only: bool, + + #[serde(default)] + pub grpc_load_shed: Option, + + #[serde(default = "default_concurrency_limit")] + pub grpc_concurrency_limit: Option, + + #[serde(default)] + pub p2p_config: P2pConfig, + + pub genesis: Genesis, + + #[serde(default = "default_authority_store_pruning_config")] + pub authority_store_pruning_config: AuthorityStorePruningConfig, + + /// Size of the broadcast channel used for notifying other systems of end of + /// epoch. + /// + /// If unspecified, this will default to `128`. + #[serde(default = "default_end_of_epoch_broadcast_channel_capacity")] + pub end_of_epoch_broadcast_channel_capacity: usize, + + #[serde(default)] + pub checkpoint_executor_config: CheckpointExecutorConfig, + + #[serde(skip_serializing_if = "Option::is_none")] + pub metrics: Option, + + /// In a `iota-node` binary, this is set to + /// SupportedProtocolVersions::SYSTEM_DEFAULT in iota-node/src/main.rs. + /// It is present in the config so that it can be changed by tests in + /// order to test protocol upgrades. + #[serde(skip)] + pub supported_protocol_versions: Option, + + #[serde(default)] + pub db_checkpoint_config: DBCheckpointConfig, + + #[serde(default)] + pub indirect_objects_threshold: usize, + + #[serde(default)] + pub expensive_safety_check_config: ExpensiveSafetyCheckConfig, + + #[serde(skip_serializing_if = "Option::is_none")] + pub name_service_package_address: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub name_service_registry_id: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub name_service_reverse_registry_id: Option, + + #[serde(default)] + pub transaction_deny_config: TransactionDenyConfig, + + #[serde(default)] + pub certificate_deny_config: CertificateDenyConfig, + + #[serde(default)] + pub state_debug_dump_config: StateDebugDumpConfig, + + #[serde(default)] + pub state_archive_write_config: StateArchiveConfig, + + #[serde(default)] + pub state_archive_read_config: Vec, + + #[serde(default)] + pub state_snapshot_write_config: StateSnapshotConfig, + + #[serde(default)] + pub indexer_max_subscriptions: Option, + + #[serde(default = "default_transaction_kv_store_config")] + pub transaction_kv_store_read_config: TransactionKeyValueStoreReadConfig, + + #[serde(skip_serializing_if = "Option::is_none")] + pub transaction_kv_store_write_config: Option, + + #[serde(default = "default_jwk_fetch_interval_seconds")] + pub jwk_fetch_interval_seconds: u64, + + #[serde(default = "default_zklogin_oauth_providers")] + pub zklogin_oauth_providers: BTreeMap>, + + #[serde(default = "default_authority_overload_config")] + pub authority_overload_config: AuthorityOverloadConfig, + + #[serde(skip_serializing_if = "Option::is_none")] + pub run_with_range: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize, Default)] +#[serde(rename_all = "kebab-case")] +pub struct TransactionKeyValueStoreReadConfig { + pub base_url: String, +} + +fn default_jwk_fetch_interval_seconds() -> u64 { + 3600 +} + +pub fn default_zklogin_oauth_providers() -> BTreeMap> { + let mut map = BTreeMap::new(); + let experimental_providers = BTreeSet::from([ + "Google".to_string(), + "Facebook".to_string(), + "Twitch".to_string(), + "Kakao".to_string(), + "Apple".to_string(), + "Slack".to_string(), + ]); + let providers = BTreeSet::from([ + "Google".to_string(), + "Facebook".to_string(), + "Twitch".to_string(), + "Apple".to_string(), + ]); + map.insert(Chain::Mainnet, providers.clone()); + map.insert(Chain::Testnet, providers); + map.insert(Chain::Unknown, experimental_providers); + map +} + +fn default_transaction_kv_store_config() -> TransactionKeyValueStoreReadConfig { + TransactionKeyValueStoreReadConfig { + base_url: "https://transactions.iota.io/".to_string(), + } +} + +fn default_authority_store_pruning_config() -> AuthorityStorePruningConfig { + AuthorityStorePruningConfig::default() +} + +pub fn default_enable_index_processing() -> bool { + true +} + +fn default_grpc_address() -> Multiaddr { + "/ip4/0.0.0.0/tcp/8080".parse().unwrap() +} +fn default_authority_key_pair() -> AuthorityKeyPairWithPath { + AuthorityKeyPairWithPath::new(get_key_pair_from_rng::(&mut OsRng).1) +} + +fn default_key_pair() -> KeyPairWithPath { + KeyPairWithPath::new( + get_key_pair_from_rng::(&mut OsRng) + .1 + .into(), + ) +} + +fn default_metrics_address() -> SocketAddr { + use std::net::{IpAddr, Ipv4Addr}; + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9184) +} + +pub fn default_admin_interface_port() -> u16 { + 1337 +} + +pub fn default_json_rpc_address() -> SocketAddr { + use std::net::{IpAddr, Ipv4Addr}; + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9000) +} + +pub fn default_concurrency_limit() -> Option { + Some(DEFAULT_GRPC_CONCURRENCY_LIMIT) +} + +pub fn default_end_of_epoch_broadcast_channel_capacity() -> usize { + 128 +} + +pub fn bool_true() -> bool { + true +} + +impl Config for NodeConfig {} + +impl NodeConfig { + pub fn protocol_key_pair(&self) -> &AuthorityKeyPair { + self.protocol_key_pair.authority_keypair() + } + + pub fn worker_key_pair(&self) -> &NetworkKeyPair { + match self.worker_key_pair.keypair() { + IotaKeyPair::Ed25519(kp) => kp, + other => panic!( + "Invalid keypair type: {:?}, only Ed25519 is allowed for worker key", + other + ), + } + } + + pub fn network_key_pair(&self) -> &NetworkKeyPair { + match self.network_key_pair.keypair() { + IotaKeyPair::Ed25519(kp) => kp, + other => panic!( + "Invalid keypair type: {:?}, only Ed25519 is allowed for network key", + other + ), + } + } + + pub fn protocol_public_key(&self) -> AuthorityPublicKeyBytes { + self.protocol_key_pair().public().into() + } + + pub fn db_path(&self) -> PathBuf { + self.db_path.join("live") + } + + pub fn db_checkpoint_path(&self) -> PathBuf { + self.db_path.join("db_checkpoints") + } + + pub fn archive_path(&self) -> PathBuf { + self.db_path.join("archive") + } + + pub fn snapshot_path(&self) -> PathBuf { + self.db_path.join("snapshot") + } + + pub fn network_address(&self) -> &Multiaddr { + &self.network_address + } + + pub fn consensus_config(&self) -> Option<&ConsensusConfig> { + self.consensus_config.as_ref() + } + + pub fn genesis(&self) -> Result<&genesis::Genesis> { + self.genesis.genesis() + } + + pub fn iota_address(&self) -> IotaAddress { + (&self.account_key_pair.keypair().public()).into() + } + + pub fn archive_reader_config(&self) -> Vec { + self.state_archive_read_config + .iter() + .flat_map(|config| { + config + .object_store_config + .as_ref() + .map(|remote_store_config| ArchiveReaderConfig { + remote_store_config: remote_store_config.clone(), + download_concurrency: NonZeroUsize::new(config.concurrency) + .unwrap_or(NonZeroUsize::new(5).unwrap()), + use_for_pruning_watermark: config.use_for_pruning_watermark, + }) + }) + .collect() + } +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub enum ConsensusProtocol { + #[serde(rename = "narwhal")] + Narwhal, + #[serde(rename = "mysticeti")] + Mysticeti, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct ConsensusConfig { + pub address: Multiaddr, + pub db_path: PathBuf, + + /// Optional alternative address preferentially used by a primary to talk to + /// its own worker. For example, this could be used to connect to + /// co-located workers over a private LAN address. + pub internal_worker_address: Option, + + /// Maximum number of pending transactions to submit to consensus, including + /// those in submission wait. + /// Assuming 10_000 txn tps * 10 sec consensus latency = 100_000 inflight + /// consensus txns, Default to 100_000. + pub max_pending_transactions: Option, + + /// When defined caps the calculated submission position to the + /// max_submit_position. Even if the is elected to submit from a higher + /// position than this, it will "reset" to the max_submit_position. + pub max_submit_position: Option, + + /// The submit delay step to consensus defined in milliseconds. When + /// provided it will override the current back off logic otherwise the + /// default backoff logic will be applied based on consensus latency + /// estimates. + pub submit_delay_step_override_millis: Option, + + pub narwhal_config: ConsensusParameters, + + /// The choice of consensus protocol to run. We default to Narwhal. + #[serde(skip)] + #[serde(default = "default_consensus_protocol")] + pub protocol: ConsensusProtocol, +} + +impl ConsensusConfig { + pub fn address(&self) -> &Multiaddr { + &self.address + } + + pub fn db_path(&self) -> &Path { + &self.db_path + } + + pub fn max_pending_transactions(&self) -> usize { + self.max_pending_transactions.unwrap_or(100_000) + } + + pub fn submit_delay_step_override(&self) -> Option { + self.submit_delay_step_override_millis + .map(Duration::from_millis) + } + + pub fn narwhal_config(&self) -> &ConsensusParameters { + &self.narwhal_config + } +} + +pub fn default_consensus_protocol() -> ConsensusProtocol { + ConsensusProtocol::Narwhal +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct CheckpointExecutorConfig { + /// Upper bound on the number of checkpoints that can be concurrently + /// executed + /// + /// If unspecified, this will default to `200` + #[serde(default = "default_checkpoint_execution_max_concurrency")] + pub checkpoint_execution_max_concurrency: usize, + + /// Number of seconds to wait for effects of a batch of transactions + /// before logging a warning. Note that we will continue to retry + /// indefinitely + /// + /// If unspecified, this will default to `10`. + #[serde(default = "default_local_execution_timeout_sec")] + pub local_execution_timeout_sec: u64, + + /// Optional directory used for data ingestion pipeline + /// When specified, each executed checkpoint will be saved in a local + /// directory for post processing + #[serde(default, skip_serializing_if = "Option::is_none")] + pub data_ingestion_dir: Option, +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct ExpensiveSafetyCheckConfig { + /// If enabled, at epoch boundary, we will check that the storage + /// fund balance is always identical to the sum of the storage + /// rebate of all live objects, and that the total IOTA in the network + /// remains the same. + #[serde(default)] + enable_epoch_iota_conservation_check: bool, + + /// If enabled, we will check that the total IOTA in all input objects of a + /// tx (both the Move part and the storage rebate) matches the total IOTA + /// in all output objects of the tx + gas fees + #[serde(default)] + enable_deep_per_tx_iota_conservation_check: bool, + + /// Disable epoch IOTA conservation check even when we are running in debug + /// mode. + #[serde(default)] + force_disable_epoch_iota_conservation_check: bool, + + /// If enabled, at epoch boundary, we will check that the accumulated + /// live object state matches the end of epoch root state digest. + #[serde(default)] + enable_state_consistency_check: bool, + + /// Disable state consistency check even when we are running in debug mode. + #[serde(default)] + force_disable_state_consistency_check: bool, + + #[serde(default)] + enable_secondary_index_checks: bool, + // TODO: Add more expensive checks here +} + +impl ExpensiveSafetyCheckConfig { + pub fn new_enable_all() -> Self { + Self { + enable_epoch_iota_conservation_check: true, + enable_deep_per_tx_iota_conservation_check: true, + force_disable_epoch_iota_conservation_check: false, + enable_state_consistency_check: true, + force_disable_state_consistency_check: false, + enable_secondary_index_checks: false, // Disable by default for now + } + } + + pub fn new_disable_all() -> Self { + Self { + enable_epoch_iota_conservation_check: false, + enable_deep_per_tx_iota_conservation_check: false, + force_disable_epoch_iota_conservation_check: true, + enable_state_consistency_check: false, + force_disable_state_consistency_check: true, + enable_secondary_index_checks: false, + } + } + + pub fn force_disable_epoch_iota_conservation_check(&mut self) { + self.force_disable_epoch_iota_conservation_check = true; + } + + pub fn enable_epoch_iota_conservation_check(&self) -> bool { + (self.enable_epoch_iota_conservation_check || cfg!(debug_assertions)) + && !self.force_disable_epoch_iota_conservation_check + } + + pub fn force_disable_state_consistency_check(&mut self) { + self.force_disable_state_consistency_check = true; + } + + pub fn enable_state_consistency_check(&self) -> bool { + (self.enable_state_consistency_check || cfg!(debug_assertions)) + && !self.force_disable_state_consistency_check + } + + pub fn enable_deep_per_tx_iota_conservation_check(&self) -> bool { + self.enable_deep_per_tx_iota_conservation_check || cfg!(debug_assertions) + } + + pub fn enable_secondary_index_checks(&self) -> bool { + self.enable_secondary_index_checks + } +} + +fn default_checkpoint_execution_max_concurrency() -> usize { + 200 +} + +fn default_local_execution_timeout_sec() -> u64 { + 30 +} + +impl Default for CheckpointExecutorConfig { + fn default() -> Self { + Self { + checkpoint_execution_max_concurrency: default_checkpoint_execution_max_concurrency(), + local_execution_timeout_sec: default_local_execution_timeout_sec(), + data_ingestion_dir: None, + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct AuthorityStorePruningConfig { + /// number of the latest epoch dbs to retain + #[serde(default = "default_num_latest_epoch_dbs_to_retain")] + pub num_latest_epoch_dbs_to_retain: usize, + /// time interval used by the pruner to determine whether there are any + /// epoch DBs to remove + #[serde(default = "default_epoch_db_pruning_period_secs")] + pub epoch_db_pruning_period_secs: u64, + /// number of epochs to keep the latest version of objects for. + /// Note that a zero value corresponds to an aggressive pruner. + /// This mode is experimental and needs to be used with caution. + /// Use `u64::MAX` to disable the pruner for the objects. + #[serde(default)] + pub num_epochs_to_retain: u64, + /// pruner's runtime interval used for aggressive mode + #[serde(skip_serializing_if = "Option::is_none")] + pub pruning_run_delay_seconds: Option, + /// maximum number of checkpoints in the pruning batch. Can be adjusted to + /// increase performance + #[serde(default = "default_max_checkpoints_in_batch")] + pub max_checkpoints_in_batch: usize, + /// maximum number of transaction in the pruning batch + #[serde(default = "default_max_transactions_in_batch")] + pub max_transactions_in_batch: usize, + /// enables periodic background compaction for old SST files whose last + /// modified time is older than `periodic_compaction_threshold_days` + /// days. That ensures that all sst files eventually go through the + /// compaction process + #[serde(skip_serializing_if = "Option::is_none")] + pub periodic_compaction_threshold_days: Option, + /// number of epochs to keep the latest version of transactions and effects + /// for + #[serde(skip_serializing_if = "Option::is_none")] + pub num_epochs_to_retain_for_checkpoints: Option, + /// disables object tombstone pruning. We don't serialize it if it is the + /// default value, false. + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub killswitch_tombstone_pruning: bool, + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub smooth: bool, +} + +fn default_num_latest_epoch_dbs_to_retain() -> usize { + 3 +} + +fn default_epoch_db_pruning_period_secs() -> u64 { + 3600 +} + +fn default_max_transactions_in_batch() -> usize { + 1000 +} + +fn default_max_checkpoints_in_batch() -> usize { + 10 +} + +impl Default for AuthorityStorePruningConfig { + fn default() -> Self { + Self { + num_latest_epoch_dbs_to_retain: default_num_latest_epoch_dbs_to_retain(), + epoch_db_pruning_period_secs: default_epoch_db_pruning_period_secs(), + num_epochs_to_retain: 0, + pruning_run_delay_seconds: if cfg!(msim) { Some(2) } else { None }, + max_checkpoints_in_batch: default_max_checkpoints_in_batch(), + max_transactions_in_batch: default_max_transactions_in_batch(), + periodic_compaction_threshold_days: None, + num_epochs_to_retain_for_checkpoints: if cfg!(msim) { Some(2) } else { None }, + killswitch_tombstone_pruning: false, + smooth: false, + } + } +} + +impl AuthorityStorePruningConfig { + pub fn set_num_epochs_to_retain_for_checkpoints(&mut self, num_epochs_to_retain: Option) { + self.num_epochs_to_retain_for_checkpoints = num_epochs_to_retain; + } + + pub fn num_epochs_to_retain_for_checkpoints(&self) -> Option { + self.num_epochs_to_retain_for_checkpoints + // if n less than 2, coerce to 2 and log + .map(|n| { + if n < 2 { + info!("num_epochs_to_retain_for_checkpoints must be at least 2, rounding up from {}", n); + 2 + } else { + n + } + }) + } + + pub fn set_killswitch_tombstone_pruning(&mut self, killswitch_tombstone_pruning: bool) { + self.killswitch_tombstone_pruning = killswitch_tombstone_pruning; + } +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct MetricsConfig { + #[serde(skip_serializing_if = "Option::is_none")] + pub push_interval_seconds: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub push_url: Option, +} + +#[derive(Default, Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct DBCheckpointConfig { + #[serde(default)] + pub perform_db_checkpoints_at_epoch_end: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub checkpoint_path: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub object_store_config: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub perform_index_db_checkpoints_at_epoch_end: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub prune_and_compact_before_upload: Option, +} + +#[derive(Debug, Clone)] +pub struct ArchiveReaderConfig { + pub remote_store_config: ObjectStoreConfig, + pub download_concurrency: NonZeroUsize, + pub use_for_pruning_watermark: bool, +} + +#[derive(Default, Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct StateArchiveConfig { + #[serde(skip_serializing_if = "Option::is_none")] + pub object_store_config: Option, + pub concurrency: usize, + pub use_for_pruning_watermark: bool, +} + +#[derive(Default, Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct StateSnapshotConfig { + #[serde(skip_serializing_if = "Option::is_none")] + pub object_store_config: Option, + pub concurrency: usize, +} + +#[derive(Default, Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct TransactionKeyValueStoreWriteConfig { + pub aws_access_key_id: String, + pub aws_secret_access_key: String, + pub aws_region: String, + pub table_name: String, + pub bucket_name: String, + pub concurrency: usize, +} + +/// Configuration for the threshold(s) at which we consider the system +/// to be overloaded. When one of the threshold is passed, the node may +/// stop processing new transactions and/or certificates until the congestion +/// resolves. +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct AuthorityOverloadConfig { + #[serde(default = "default_max_txn_age_in_queue")] + pub max_txn_age_in_queue: Duration, + + // The interval of checking overload signal. + #[serde(default = "default_overload_monitor_interval")] + pub overload_monitor_interval: Duration, + + // The execution queueing latency when entering load shedding mode. + #[serde(default = "default_execution_queue_latency_soft_limit")] + pub execution_queue_latency_soft_limit: Duration, + + // The execution queueing latency when entering aggressive load shedding mode. + #[serde(default = "default_execution_queue_latency_hard_limit")] + pub execution_queue_latency_hard_limit: Duration, + + // The maximum percentage of transactions to shed in load shedding mode. + #[serde(default = "default_max_load_shedding_percentage")] + pub max_load_shedding_percentage: u32, + + // When in aggressive load shedding mode, the minimum percentage of + // transactions to shed. + #[serde(default = "default_min_load_shedding_percentage_above_hard_limit")] + pub min_load_shedding_percentage_above_hard_limit: u32, + + // If transaction ready rate is below this rate, we consider the validator + // is well under used, and will not enter load shedding mode. + #[serde(default = "default_safe_transaction_ready_rate")] + pub safe_transaction_ready_rate: u32, + + // When set to true, transaction signing may be rejected when the validator + // is overloaded. + #[serde(default = "default_check_system_overload_at_signing")] + pub check_system_overload_at_signing: bool, + + // When set to true, transaction execution may be rejected when the validator + // is overloaded. + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub check_system_overload_at_execution: bool, + // TODO: Move other thresholds here as well, including `MAX_TM_QUEUE_LENGTH` + // and `MAX_PER_OBJECT_QUEUE_LENGTH`. +} + +fn default_max_txn_age_in_queue() -> Duration { + Duration::from_secs(1) +} + +fn default_overload_monitor_interval() -> Duration { + Duration::from_secs(10) +} + +fn default_execution_queue_latency_soft_limit() -> Duration { + Duration::from_secs(1) +} + +fn default_execution_queue_latency_hard_limit() -> Duration { + Duration::from_secs(10) +} + +fn default_max_load_shedding_percentage() -> u32 { + 95 +} + +fn default_min_load_shedding_percentage_above_hard_limit() -> u32 { + 50 +} + +fn default_safe_transaction_ready_rate() -> u32 { + 100 +} + +fn default_check_system_overload_at_signing() -> bool { + true +} + +impl Default for AuthorityOverloadConfig { + fn default() -> Self { + Self { + max_txn_age_in_queue: default_max_txn_age_in_queue(), + overload_monitor_interval: default_overload_monitor_interval(), + execution_queue_latency_soft_limit: default_execution_queue_latency_soft_limit(), + execution_queue_latency_hard_limit: default_execution_queue_latency_hard_limit(), + max_load_shedding_percentage: default_max_load_shedding_percentage(), + min_load_shedding_percentage_above_hard_limit: + default_min_load_shedding_percentage_above_hard_limit(), + safe_transaction_ready_rate: default_safe_transaction_ready_rate(), + check_system_overload_at_signing: true, + check_system_overload_at_execution: false, + } + } +} + +fn default_authority_overload_config() -> AuthorityOverloadConfig { + AuthorityOverloadConfig::default() +} + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)] +pub struct Genesis { + #[serde(flatten)] + location: GenesisLocation, + + #[serde(skip)] + genesis: once_cell::sync::OnceCell, +} + +impl Genesis { + pub fn new(genesis: genesis::Genesis) -> Self { + Self { + location: GenesisLocation::InPlace { genesis }, + genesis: Default::default(), + } + } + + pub fn new_from_file>(path: P) -> Self { + Self { + location: GenesisLocation::File { + genesis_file_location: path.into(), + }, + genesis: Default::default(), + } + } + + pub fn genesis(&self) -> Result<&genesis::Genesis> { + match &self.location { + GenesisLocation::InPlace { genesis } => Ok(genesis), + GenesisLocation::File { + genesis_file_location, + } => self + .genesis + .get_or_try_init(|| genesis::Genesis::load(genesis_file_location)), + } + } +} + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)] +#[serde(untagged)] +enum GenesisLocation { + InPlace { + genesis: genesis::Genesis, + }, + File { + #[serde(rename = "genesis-file-location")] + genesis_file_location: PathBuf, + }, +} + +/// Wrapper struct for IotaKeyPair that can be deserialized from a file path. +/// Used by network, worker, and account keypair. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub struct KeyPairWithPath { + #[serde(flatten)] + location: KeyPairLocation, + + #[serde(skip)] + keypair: OnceCell>, +} + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)] +#[serde_as] +#[serde(untagged)] +enum KeyPairLocation { + InPlace { + #[serde_as(as = "Arc")] + value: Arc, + }, + File { + #[serde(rename = "path")] + path: PathBuf, + }, +} + +impl KeyPairWithPath { + pub fn new(kp: IotaKeyPair) -> Self { + let cell: OnceCell> = OnceCell::new(); + let arc_kp = Arc::new(kp); + // OK to unwrap panic because authority should not start without all keypairs + // loaded. + cell.set(arc_kp.clone()).expect("Failed to set keypair"); + Self { + location: KeyPairLocation::InPlace { value: arc_kp }, + keypair: cell, + } + } + + pub fn new_from_path(path: PathBuf) -> Self { + let cell: OnceCell> = OnceCell::new(); + // OK to unwrap panic because authority should not start without all keypairs + // loaded. + cell.set(Arc::new(read_keypair_from_file(&path).unwrap_or_else( + |e| panic!("Invalid keypair file at path {:?}: {e}", &path), + ))) + .expect("Failed to set keypair"); + Self { + location: KeyPairLocation::File { path }, + keypair: cell, + } + } + + pub fn keypair(&self) -> &IotaKeyPair { + self.keypair + .get_or_init(|| match &self.location { + KeyPairLocation::InPlace { value } => value.clone(), + KeyPairLocation::File { path } => { + // OK to unwrap panic because authority should not start without all keypairs + // loaded. + Arc::new( + read_keypair_from_file(path).unwrap_or_else(|e| { + panic!("Invalid keypair file at path {:?}: {e}", path) + }), + ) + } + }) + .as_ref() + } +} + +/// Wrapper struct for AuthorityKeyPair that can be deserialized from a file +/// path. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub struct AuthorityKeyPairWithPath { + #[serde(flatten)] + location: AuthorityKeyPairLocation, + + #[serde(skip)] + keypair: OnceCell>, +} + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)] +#[serde_as] +#[serde(untagged)] +enum AuthorityKeyPairLocation { + InPlace { value: Arc }, + File { path: PathBuf }, +} + +impl AuthorityKeyPairWithPath { + pub fn new(kp: AuthorityKeyPair) -> Self { + let cell: OnceCell> = OnceCell::new(); + let arc_kp = Arc::new(kp); + // OK to unwrap panic because authority should not start without all keypairs + // loaded. + cell.set(arc_kp.clone()) + .expect("Failed to set authority keypair"); + Self { + location: AuthorityKeyPairLocation::InPlace { value: arc_kp }, + keypair: cell, + } + } + + pub fn new_from_path(path: PathBuf) -> Self { + let cell: OnceCell> = OnceCell::new(); + // OK to unwrap panic because authority should not start without all keypairs + // loaded. + cell.set(Arc::new( + read_authority_keypair_from_file(&path) + .unwrap_or_else(|_| panic!("Invalid authority keypair file at path {:?}", &path)), + )) + .expect("Failed to set authority keypair"); + Self { + location: AuthorityKeyPairLocation::File { path }, + keypair: cell, + } + } + + pub fn authority_keypair(&self) -> &AuthorityKeyPair { + self.keypair + .get_or_init(|| match &self.location { + AuthorityKeyPairLocation::InPlace { value } => value.clone(), + AuthorityKeyPairLocation::File { path } => { + // OK to unwrap panic because authority should not start without all keypairs + // loaded. + Arc::new( + read_authority_keypair_from_file(path).unwrap_or_else(|_| { + panic!("Invalid authority keypair file {:?}", &path) + }), + ) + } + }) + .as_ref() + } +} + +/// Configurations which determine how we dump state debug info. +/// Debug info is dumped when a node forks. +#[derive(Clone, Debug, Deserialize, Serialize, Default)] +#[serde(rename_all = "kebab-case")] +pub struct StateDebugDumpConfig { + #[serde(skip_serializing_if = "Option::is_none")] + pub dump_file_directory: Option, +} + +#[cfg(test)] +mod tests { + use std::path::PathBuf; + + use fastcrypto::traits::KeyPair; + use iota_keys::keypair_file::{write_authority_keypair_to_file, write_keypair_to_file}; + use iota_types::crypto::{ + get_key_pair_from_rng, AuthorityKeyPair, IotaKeyPair, NetworkKeyPair, + }; + use rand::{rngs::StdRng, SeedableRng}; + + use super::Genesis; + use crate::NodeConfig; + + #[test] + fn serialize_genesis_from_file() { + let g = Genesis::new_from_file("path/to/file"); + + let s = serde_yaml::to_string(&g).unwrap(); + assert_eq!("---\ngenesis-file-location: path/to/file\n", s); + let loaded_genesis: Genesis = serde_yaml::from_str(&s).unwrap(); + assert_eq!(g, loaded_genesis); + } + + #[test] + fn fullnode_template() { + const TEMPLATE: &str = include_str!("../data/fullnode-template.yaml"); + + let _template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap(); + } + + #[test] + fn load_key_pairs_to_node_config() { + let protocol_key_pair: AuthorityKeyPair = + get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1; + let worker_key_pair: NetworkKeyPair = + get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1; + let network_key_pair: NetworkKeyPair = + get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1; + + write_authority_keypair_to_file(&protocol_key_pair, PathBuf::from("protocol.key")).unwrap(); + write_keypair_to_file( + &IotaKeyPair::Ed25519(worker_key_pair.copy()), + PathBuf::from("worker.key"), + ) + .unwrap(); + write_keypair_to_file( + &IotaKeyPair::Ed25519(network_key_pair.copy()), + PathBuf::from("network.key"), + ) + .unwrap(); + + const TEMPLATE: &str = include_str!("../data/fullnode-template-with-path.yaml"); + let template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap(); + assert_eq!( + template.protocol_key_pair().public(), + protocol_key_pair.public() + ); + assert_eq!( + template.network_key_pair().public(), + network_key_pair.public() + ); + assert_eq!( + template.worker_key_pair().public(), + worker_key_pair.public() + ); + } +} + +// RunWithRange is used to specify the ending epoch/checkpoint to process. +// this is intended for use with disaster recovery debugging and verification +// workflows, never in normal operations +#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)] +pub enum RunWithRange { + Epoch(EpochId), + Checkpoint(CheckpointSequenceNumber), +} + +impl RunWithRange { + // is epoch_id > RunWithRange::Epoch + pub fn is_epoch_gt(&self, epoch_id: EpochId) -> bool { + matches!(self, RunWithRange::Epoch(e) if epoch_id > *e) + } + + pub fn matches_checkpoint(&self, seq_num: CheckpointSequenceNumber) -> bool { + matches!(self, RunWithRange::Checkpoint(seq) if *seq == seq_num) + } +} diff --git a/crates/sui-config/src/node_config_metrics.rs b/crates/iota-config/src/node_config_metrics.rs similarity index 98% rename from crates/sui-config/src/node_config_metrics.rs rename to crates/iota-config/src/node_config_metrics.rs index 9b74b6b8923..775f28eb8a7 100644 --- a/crates/sui-config/src/node_config_metrics.rs +++ b/crates/iota-config/src/node_config_metrics.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; diff --git a/crates/sui-config/src/object_storage_config.rs b/crates/iota-config/src/object_storage_config.rs similarity index 99% rename from crates/sui-config/src/object_storage_config.rs rename to crates/iota-config/src/object_storage_config.rs index 5aea7e27bed..4d883268307 100644 --- a/crates/sui-config/src/object_storage_config.rs +++ b/crates/iota-config/src/object_storage_config.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fs, path::PathBuf, sync::Arc}; diff --git a/crates/sui-config/src/p2p.rs b/crates/iota-config/src/p2p.rs similarity index 99% rename from crates/sui-config/src/p2p.rs rename to crates/iota-config/src/p2p.rs index b6c8206bda0..c485ffd20e7 100644 --- a/crates/sui-config/src/p2p.rs +++ b/crates/iota-config/src/p2p.rs @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{net::SocketAddr, num::NonZeroU32, time::Duration}; -use serde::{Deserialize, Serialize}; -use sui_types::{ +use iota_types::{ messages_checkpoint::{CheckpointDigest, CheckpointSequenceNumber}, multiaddr::Multiaddr, }; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] diff --git a/crates/iota-config/src/test_gateway.yml b/crates/iota-config/src/test_gateway.yml new file mode 100644 index 00000000000..e70b0d449a4 --- /dev/null +++ b/crates/iota-config/src/test_gateway.yml @@ -0,0 +1,251 @@ + --- + epoch: 0 + validator_set: + - name: validator-9 + account-key: AD0iV/PbGVBoPExdB+4wfprZLoS9N4ltb00p1MNnlm71 + protocol-key: getJQ17IvK3nYcHAOLZ1PDeQt5dNcxGGkCooW9AYo0fUNEu1C3Uo264SZBiEqhqUD3QcR018SpZkYYEntPS/B/I8QGRJFBa55O1GSGGNscJ3rOOArqGKM4cOBaJUF2nH + worker-key: RXzQ+WNIIcodae0f1AaRVg3qvzbySW4EYBUVf68VdzA= + network-key: OD73hNLl2wBqBrmcxG00r77V7Kgdi2fu4YpnoEJDyPs= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/ny2-iotaval-1.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/ny2-iotaval-1.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/ny2-iotaval-1.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-14 + account-key: APxJHKslYpWYWmMIlpKfzBTj9K5I84diueoJ4sWHwjmS + protocol-key: hUY69ZxcvuOaoY9AoazvEAsum2bS/61LZU7d88h/baYO5rBXFod3UeYC+wr0J51qF6JUpOaNk/E2OIFSbI1GoLUxu0AxIfe23ph+BLD3CbttFMbpqZa7Zza6DOHpjyok + worker-key: IrjezuU/lXLkyXkAUvWbKBGPLH5GCrJqCRYKTVc9nao= + network-key: pu7Q7oXG6GiRfoEcR7azVoWUVQC10gY7MLi3xVoYa0g= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/mh1-iotaval-2.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/mh1-iotaval-2.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/mh1-iotaval-2.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-13 + account-key: AF7odQ5Mwj8PBN/7LYTqyB/gS1OywSBOcKuCS/+VNyLd + protocol-key: iBNb7x9vyRov6hR/y0671JJ3gYTGWjDtSO8BLZ0FjZQkkQ3peXhjQZnVUe7VO8CnGN630twyg6zfBwS8CL51rV0UbsEJ0ZOn/4uwR/rq8PwMdod+Wf84AkGhbrZ0AUh4 + worker-key: H2uJQcpeBVF/cn5VBR3re7HZugsooxv2TeGfoctO6GE= + network-key: tgVQjD8k8ymbIdWYhi8VxjMw9FInsfh8xLd+4xhOIOE= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/mh1-iotaval-1.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/mh1-iotaval-1.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/mh1-iotaval-1.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-17 + account-key: AO6lcah9+F9DfVBwE5+30kmi8pkw7nHPeolO0LNIJUQi + protocol-key: iJOovXaLrS4FvmlpMnkCk0oEY79HrBPLxY+21WhK2sKsaTsAgjL4KnyXVbrb7nTOAm0z6CkdzT+hMmMw1E7csmK8dV8VjKpgaR66oMxcGDM2Rbu0XhqIx7uH3DpwYezp + worker-key: jdsdCfcvGNs5XxGk+jwNbOF6caMnaWvCGKOp0b4QslI= + network-key: qqL4hLWUa7bitFYj0k1uosnmKEEslk/o8shtOOJriWY= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/ty6-iotaval-1.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/ty6-iotaval-1.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/ty6-iotaval-1.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-10 + account-key: AEM7kl/d6VlBG1IgY+lHdxzudYT6ZhtXiYBh3kCxLZCq + protocol-key: iic7mlIKCwVxaqej7btkXo045aJYw6hgqpHZT+n25aqICuYCkc0PUXzZ2qSGTrUgDkhcyLKUpMPXjNCPw7AV3M+B+dPuKf6BVVo4Enj4KJe5SnoNOYRE7Ll01K9KfbWU + worker-key: +Ukw2HM7IYXyIxp9F2ZbBZMAQpIMN24fhzArm41CJy0= + network-key: IXFQDgUFO6XD+eqnCHf4aAR2HVdqKKM/7l13nlFIk+w= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/ny2-iotaval-2.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/ny2-iotaval-2.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/ny2-iotaval-2.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-7 + account-key: ALO4VmUJME24oEDq0tzE7MRi+83HZE3UCuLTVPIE4ZQK + protocol-key: krpOBB6E7P0N4jsUHBGFPSHX0UPoS6uFR1I/kKND+em8+cgrujsm31oygHdrKhUeDjq4UWUtCyxLoCczGLO/F1VUooI/J3iqzjN1RvkG7CiFriuU0L9GF7/l64U01DwN + worker-key: knT4d0Du6/s0qQWtIeAHI25gRjTXHQe4g0SK56LGtLw= + network-key: ZtPhPziNESJSElsa2y7GZWkc97kKPMrJTq1UldpxUoU= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/dal2-iotaval-3.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/dal2-iotaval-3.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/dal2-iotaval-3.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-8 + account-key: AJN7LZADOBBRulSlRjE0HJs3YR8I3WPwg2ejh4HbDmIS + protocol-key: ky1saTSmEpWC/F4MKypOBzJaNaqxHk7gTWkhDnJP0NMZG0vniS+3YIGtg/MsHPQXAVJkmj/rq9AgGNN/xxmUXd7iB/6xnldUSRfHDberjd9lr6zlG+oEtj9nmpLNA/Wd + worker-key: feBqPOJotxyv+jWKWvYGWw6/ISzP2dms9jhiy4Nbj4Q= + network-key: yfVmqGTyP3tutFvvrvklhafUJUCTmik+6u6zBRV3Vb4= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/ny2-iotaval-0.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/ny2-iotaval-0.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/ny2-iotaval-0.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-4 + account-key: ACfae1xB9WlL4aSAEbIeTzHSK70s6pUFK4MWerGsas0i + protocol-key: lwDow31chV6Qb3bqcHN5EjFVRf6MVttV94z4d4y5srrEz/Ljax/6RV3rHR65OfU1ExK8K5bX1gZ6q8pZgVUTPjWrRt3G8P1aD8hw0gXFFYeE3Wx2+Y4P4r8H4LMcqriZ + worker-key: XpdNknObin/NdNWpBISwDdJxhSlyBVZ85Vn9AnVzxtY= + network-key: 7b8+yXq6rdRw7eToBWfCnYoDBPxDvTVeW6xyiK5u4HM= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/dal2-iotaval-0.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/dal2-iotaval-0.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/dal2-iotaval-0.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-18 + account-key: AE6+TGtd9SgOFPJh7sswMd8YDf7G080NeGYwzuIS3/zM + protocol-key: l/fjESkdgYtdwiEnTNEEltgjImpW5k5CIwnq3YHSAlXW2wATYAf+U0CwYHIbFelxC4XpuDZJTMUDp/B1q7lbMms/EuUmHvP59uz3ysNMERt0w+kDDIcdN45yPhJJOTwq + worker-key: Qn3hFtZnGKB5NKeLsjAzb0+N6Nar2UpLeiUYcOBAaAs= + network-key: y3wT8cSNLo+flMsvseffK5fJC72J12ZrT6Tjy6wzQkM= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/ty6-iotaval-2.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/ty6-iotaval-2.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/ty6-iotaval-2.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-2 + account-key: AGhrMVMiJ67VCxth8gWXNFOLnFuNkIMjV0GK3EFBfaio + protocol-key: pGmknQNryWXOmxfNJ1L2IpVplX0kcjMpeHAcuRbxv6rlJt1N+96RWegxtf38mLWQFt2b+S8diM25yMFn4ox2YzAHShhhISz8ZzB38WPScV3xXGG0F5KyPXk0sLM1/vjx + worker-key: qolNIcgY6rYX64P5O4oF9ugXl3hPi6yUyZlV1SPjt+M= + network-key: Qn8Zhwld5x22fE1GwIg6Hain9iVRi+iam1RDgp8mvhk= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/la2-iotaval-2.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/la2-iotaval-2.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/la2-iotaval-2.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-11 + account-key: AK6LecW3y0UyqzCHu3lUgffRyhGrxEQPjaHRxCilP6Rp + protocol-key: pVydcYoBSOHxVnw2mOg8YXJyqpDYP+ksefqghJwr3OChJNTa3A2NkDaCRKGcvRm6DPiaqBu8qBUSAfjWE4KHfQIllc7qkWYsRfKi0RYQ3zTFYSjal93Am/cAI1q6QX59 + worker-key: PqUDf04k2xNSqR0u2pmaU7L23hIt8gO6B3NoYPsR+RA= + network-key: x/0p4eV6ZQOyRGv9K9hiiaN7TvSfk2AvCttMAVpOoMk= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/ny2-iotaval-3.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/ny2-iotaval-3.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/ny2-iotaval-3.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-16 + account-key: AImuNvQVTUSNUQrsBSi7dzT+a+wVsSQM5fQMfdQ1CTZ0 + protocol-key: qBvUTaWiYjKIledSoTM8rwt4C7dqCVFuUPyQBNDOOSa109JlgUafHGEIeOHrrUlCEnAwTiXs+s2JlwmyegQzJp2ECnbz4JRPzFqbBhS7VDJ7UfydXbq4KDt12q8yb5v4 + worker-key: XFw5/sTtKHd47+vpj7uvt+FkAyOq1FnvGS/7be6suoA= + network-key: EEqhzNCQ6/nPfCW7jLMKQS2TGb2dY2CHAme8mlEZGKY= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/ty6-iotaval-0.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/ty6-iotaval-0.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/ty6-iotaval-0.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-15 + account-key: AFDDthZ/GakRrsI2QZJ8gQFEt+fJvKwpJJoYm+p/NW07 + protocol-key: q5U/HPqV6OsFbc5gzr+FPRfBGqyHqO683epGiQ535TOEYRkSi3wZFFUdDfWId7ORD5EIYWj7ZtA4C8uPrP3XsbIQogNizEyDu3CwytSwtcTa4/bIvc8HK/0KoDnPNOG2 + worker-key: ydUPJzWYwe3RdAUo5zMZvyAattOKn+wfxwdrQTRpxqA= + network-key: rU4e5yh97eNS5nCaa7EbbqnJVMcHehybdtBlIZjSHdU= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/mh1-iotaval-3.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/mh1-iotaval-3.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/mh1-iotaval-3.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-5 + account-key: ALaZN89Ud2dli3QScggR+9+2CqSkct2f7qMXQ1osFaBd + protocol-key: rA3xsZLdYP8f1Jhdy/qaAZJTZ1XGza6P167xhffC9qd/ThVdV0K/Pg0t9g5TpYHoEygnvMO8oPyJA2+zwbutgCTRaM1z573NN3mtbjK57R+S7aqwZiN2kI7aoymX9oHs + worker-key: EgpJ/Hdk6X+H8jXxurlwR1EiIlDkryVCQ4HMrk72INQ= + network-key: twXGi96O3XWKERXGzu1Y03Rl6uUr+1Tqx9kGuGV+Gew= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/dal2-iotaval-1.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/dal2-iotaval-1.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/dal2-iotaval-1.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-19 + account-key: AFhY6i8XnpRoImndz7kj+M6mjIpZz1248oyO5Ou/ajG8 + protocol-key: rewCDjFrQpvCurd4M6cl1/icgJsGKombV1OAd0iyskXN4WqXZiP/V7xy7fNZfciwD2k0nl8uQCaLEPXsO/zBL0ZGr2n274JYVm8j4gOekJcUpdAQ3LWPqDh3pRsxBVE+ + worker-key: 7J91jtn+//gCHUPIi8Std5hhSFLs9snJhPbnHPueudc= + network-key: 3PKKDx6y6CzV0+eK9G3WvH/queuZe3byCYIOTYIkyiQ= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/ty6-iotaval-3.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/ty6-iotaval-3.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/ty6-iotaval-3.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-12 + account-key: AAYmiOgJnOyXfMPEwP49TUUUTw4dlIA/8IXeKEv8M4RK + protocol-key: sfQG62p+A88facvLw+lXcDh6TtSaeaRa3D8dhMJpLWgJZ4NRl2JFSaUlYHWwP+zVGSdbyLGm72426wv5cKnVkHM8cxhNvpZRq370bYHTfTAb34WJ2mxHiqx5pChHJp4E + worker-key: UEtOxAHp/invOWPV8Uuls3/46iLdKFJIGEb2zhJIsNs= + network-key: ibWn5j/N9BqepJXTWioH47A2u//ASB3Xug50e7jmJ80= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/mh1-iotaval-0.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/mh1-iotaval-0.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/mh1-iotaval-0.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-3 + account-key: AIyUji/hvun9TdRLQXpN8UNgn3sIjSosETJWkPSwDzHr + protocol-key: tH2JgU9S5IFnC17arEV0dn2sRlZmgaHpOAVQvIJfvXAnZTOLDwHzepPbFpp3i9g+DzUyeKWSh06N7jILNze8jdhLeZ1fumbu07GgmpL2vdYR3Qbxg64DpsKLPMeNi3V1 + worker-key: NM/63ks+HTfHnPSRKU7Yh9I0c5qTm1ajr4akXpBR5V0= + network-key: 5VuCiFi9kAK7QlsZBuymT9xsIG/sPoFcmjHoGn/CPgs= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/la2-iotaval-3.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/la2-iotaval-3.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/la2-iotaval-3.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-1 + account-key: AG+M0+OIB31YRR/FQKdzt7aP4qUPBQSMyCWK+Da9Zmax + protocol-key: tlb8KVZRWWJZQ6TmpE+5ZL05Vb0TTnCMbJ+kWX5GtcnpaeRiFqlUKiYM5npZCCWyFx8f1VwW5gfg8OejVRlo+weJr50yphZdA53GkbJiOWxSY58DSNTQINB/lEdOAeJQ + worker-key: xplIPV8w5ahH8UaWChJcPrkSVZAGtKwMXCWdT8lSaPU= + network-key: pZdlHJfW9hxT415bG8kusy7m4TDfW0gkNMsx3MVs73o= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/la2-iotaval-1.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/la2-iotaval-1.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/la2-iotaval-1.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-6 + account-key: AGq4caYZr20U1EM7WkRo6CYVuKfjWmda1b5AGdgaSN2s + protocol-key: t/ueFnCtZPsfXozjLmRwefOht+pyelCaTgctHqOomF5gd0MuXdDSvOCAH3yWiaIVBskY54766sEG0antAeAtJHRwKXHGo99RR5nRRxUbekTvq7T05TTpQxW1pi4Cr/5O + worker-key: MM7hhssxwhocxsg8ZrEYXjMggQsrWaiQzCZpkwv7ya8= + network-key: q1+yp6neJ0VYGcRFDDfarMM6XN+CwiNVmqfc7IElUNY= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/dal2-iotaval-2.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/dal2-iotaval-2.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/dal2-iotaval-2.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + - name: validator-0 + account-key: APlYeKnmB0RcPB5cYaII7aAvjjAt19cVt3d9eJBCQwjX + protocol-key: uQWpdXdUDiw5/MSyB56qIUZoCOApbKzuXE9MkgjekQsn6PPSLEIydbr16TVKm8ifADeZUnFeIQ39VwT3LBveXXS8ncRoBddREyR/S19AXGWigynhjLi5hNGCfFO+FWHS + worker-key: 6zvKuVVIhIgczd4Gf3AhWzdJyINtK8yxoVLxlUw3kSU= + network-key: 2tgtZR/dK2E9rEfdenqmLKxjqjH0jJV7CcT4ywRA6uw= + stake: 1 + delegation: 0 + gas-price: 1 + network-address: /dns/la2-iotaval-0.testnet.iota.io/tcp/8080/http + narwhal-primary-address: /dns/la2-iotaval-0.testnet.iota.io/udp/8081 + narwhal-worker-address: /dns/la2-iotaval-0.testnet.iota.io/udp/8082 + narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http + send_timeout: + secs: 30 + nanos: 0 + recv_timeout: + secs: 30 + nanos: 0 + buffer_size: 650000 + db_folder_path: /data/gateway_client_db diff --git a/crates/sui-config/src/transaction_deny_config.rs b/crates/iota-config/src/transaction_deny_config.rs similarity index 92% rename from crates/sui-config/src/transaction_deny_config.rs rename to crates/iota-config/src/transaction_deny_config.rs index a94e43d367e..8d0416d6dad 100644 --- a/crates/sui-config/src/transaction_deny_config.rs +++ b/crates/iota-config/src/transaction_deny_config.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::HashSet; +use iota_types::base_types::{IotaAddress, ObjectID}; use once_cell::sync::OnceCell; use serde::{Deserialize, Serialize}; -use sui_types::base_types::{ObjectID, SuiAddress}; #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] @@ -32,10 +33,10 @@ pub struct TransactionDenyConfig { #[serde(default, skip_serializing_if = "Vec::is_empty")] package_deny_list: Vec, - /// A list of sui addresses that are not allowed to be used as the sender or - /// sponsor. + /// A list of iota addresses that are not allowed to be used as the sender + /// or sponsor. #[serde(default, skip_serializing_if = "Vec::is_empty")] - address_deny_list: Vec, + address_deny_list: Vec, /// Whether publishing new packages is disabled. #[serde(default)] @@ -63,7 +64,7 @@ pub struct TransactionDenyConfig { package_deny_set: OnceCell>, #[serde(skip)] - address_deny_set: OnceCell>, + address_deny_set: OnceCell>, /// Whether receiving objects transferred to other objects is allowed #[serde(default)] @@ -92,7 +93,7 @@ impl TransactionDenyConfig { .get_or_init(|| self.package_deny_list.iter().cloned().collect()) } - pub fn get_address_deny_set(&self) -> &HashSet { + pub fn get_address_deny_set(&self) -> &HashSet { self.address_deny_set .get_or_init(|| self.address_deny_list.iter().cloned().collect()) } @@ -170,7 +171,7 @@ impl TransactionDenyConfigBuilder { self } - pub fn add_denied_address(mut self, address: SuiAddress) -> Self { + pub fn add_denied_address(mut self, address: IotaAddress) -> Self { self.config.address_deny_list.push(address); self } diff --git a/crates/iota-core/Cargo.toml b/crates/iota-core/Cargo.toml new file mode 100644 index 00000000000..1bd8f3632d8 --- /dev/null +++ b/crates/iota-core/Cargo.toml @@ -0,0 +1,142 @@ +[package] +name = "iota-core" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow = { workspace = true, features = ["backtrace"] } +arc-swap.workspace = true +async-trait.workspace = true +bcs.workspace = true +bytes.workspace = true +chrono.workspace = true +consensus-core.workspace = true +consensus-config.workspace = true +dashmap.workspace = true +diffy = { version = "0.3", default-features = false } +either.workspace = true +enum_dispatch.workspace = true +eyre.workspace = true +futures.workspace = true +im.workspace = true +indexmap.workspace = true +itertools.workspace = true +lru.workspace = true +mockall.workspace = true +num_cpus.workspace = true +object_store.workspace = true +once_cell.workspace = true +parking_lot.workspace = true +prometheus.workspace = true +rand.workspace = true +roaring.workspace = true +rocksdb.workspace = true +scopeguard.workspace = true +serde.workspace = true +serde_json.workspace = true +serde_with.workspace = true +signature.workspace = true +static_assertions.workspace = true +tap.workspace = true +tempfile.workspace = true +thiserror.workspace = true +tokio = { workspace = true, features = ["full", "tracing", "test-util"] } +tokio-retry.workspace = true +tokio-stream.workspace = true +tracing.workspace = true +twox-hash.workspace = true + +anemo.workspace = true +fastcrypto.workspace = true +fastcrypto-tbls.workspace = true +fastcrypto-zkp.workspace = true +move-binary-format.workspace = true +move-bytecode-utils.workspace = true +move-core-types.workspace = true +move-package.workspace = true +move-symbol-pool.workspace = true +mysten-common.workspace = true +mysten-network.workspace = true +telemetry-subscribers.workspace = true +typed-store-derive.workspace = true +typed-store.workspace = true + +mysten-metrics.workspace = true +narwhal-config.workspace = true +narwhal-crypto.workspace = true +narwhal-executor.workspace = true +narwhal-network.workspace = true +narwhal-node.workspace = true +narwhal-test-utils.workspace = true +narwhal-types.workspace = true +narwhal-worker.workspace = true +shared-crypto.workspace = true +iota-archival.workspace = true +iota-config.workspace = true +iota-authority-aggregation.workspace = true +iota-execution = { path = "../../iota-execution" } +iota-framework.workspace = true +iota-swarm-config.workspace = true +iota-genesis-builder.workspace = true +iota-json-rpc-types.workspace = true +iota-macros.workspace = true +iota-move-build.workspace = true +iota-network.workspace = true +iota-protocol-config.workspace = true +iota-transaction-checks.workspace = true +iota-simulator.workspace = true +iota-storage.workspace = true +iota-types.workspace = true +zeroize.workspace = true + +[dev-dependencies] +clap.workspace = true +criterion.workspace = true +expect-test.workspace = true +fs_extra.workspace = true +more-asserts.workspace = true +pretty_assertions.workspace = true +serde-reflection.workspace = true +serde_yaml.workspace = true +num-bigint = "0.4.4" + +test-cluster.workspace = true +move-symbol-pool.workspace = true + +iota-test-transaction-builder.workspace = true +iota-types = { workspace = true, features = ["test-utils"] } + +[target.'cfg(not(target_env = "msvc"))'.dev-dependencies] +pprof.workspace = true +test-fuzz.workspace = true + +iota-macros.workspace = true +iota-protocol-config.workspace = true + +# moka uses `quanta` by default for timing, which is not compatible with the simulator +[target.'cfg(msim)'.dependencies] +moka = { workspace = true, default-features = false, features = [ + "sync", + "atomic64", +] } +[target.'cfg(not(msim))'.dependencies] +moka = { workspace = true, features = ["sync"] } + +[[example]] +name = "generate-format" +path = "src/generate_format.rs" +test = false + +[[bench]] +name = "verified_cert_cache_bench" +harness = false + +[[bench]] +name = "batch_verification_bench" +harness = false + +[features] +test-utils = [] diff --git a/crates/sui-core/benches/batch_verification_bench.rs b/crates/iota-core/benches/batch_verification_bench.rs similarity index 98% rename from crates/sui-core/benches/batch_verification_bench.rs rename to crates/iota-core/benches/batch_verification_bench.rs index 2cb8be5cb1f..2cf39a25545 100644 --- a/crates/sui-core/benches/batch_verification_bench.rs +++ b/crates/iota-core/benches/batch_verification_bench.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; @@ -6,17 +7,17 @@ use std::sync::Arc; use criterion::*; use fastcrypto_zkp::bn254::zk_login_api::ZkLoginEnv; use futures::future::join_all; -use prometheus::Registry; -use rand::{prelude::*, seq::SliceRandom}; -use sui_core::{ +use iota_core::{ signature_verifier::*, test_utils::{make_cert_with_large_committee, make_dummy_tx}, }; -use sui_types::{ +use iota_types::{ committee::Committee, crypto::{get_key_pair, AccountKeyPair, AuthorityKeyPair}, transaction::CertifiedTransaction, }; +use prometheus::Registry; +use rand::{prelude::*, seq::SliceRandom}; fn gen_certs( committee: &Committee, diff --git a/crates/sui-core/benches/verified_cert_cache_bench.rs b/crates/iota-core/benches/verified_cert_cache_bench.rs similarity index 91% rename from crates/sui-core/benches/verified_cert_cache_bench.rs rename to crates/iota-core/benches/verified_cert_cache_bench.rs index b0ceb41da51..c1f9604b771 100644 --- a/crates/sui-core/benches/verified_cert_cache_bench.rs +++ b/crates/iota-core/benches/verified_cert_cache_bench.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use criterion::{Criterion, *}; -use sui_core::signature_verifier::{SignatureVerifierMetrics, VerifiedDigestCache}; -use sui_types::digests::CertificateDigest; +use iota_core::signature_verifier::{SignatureVerifierMetrics, VerifiedDigestCache}; +use iota_types::digests::CertificateDigest; fn verified_cert_cache_bench(c: &mut Criterion) { let mut digests: Vec<_> = (0..(1 << 18)) diff --git a/crates/sui-core/src/authority.rs b/crates/iota-core/src/authority.rs similarity index 94% rename from crates/sui-core/src/authority.rs rename to crates/iota-core/src/authority.rs index 91883b73ef7..44d75f7769f 100644 --- a/crates/sui-core/src/authority.rs +++ b/crates/iota-core/src/authority.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -24,24 +25,8 @@ use fastcrypto::{ encoding::{Base58, Encoding}, hash::MultisetHash, }; -use itertools::Itertools; -use move_binary_format::{binary_config::BinaryConfig, CompiledModule}; -use move_core_types::{annotated_value::MoveStructLayout, language_storage::ModuleId}; -use mysten_metrics::{ - monitored_scope, spawn_monitored_task, TX_TYPE_SHARED_OBJ_TX, TX_TYPE_SINGLE_WRITER_TX, -}; -use once_cell::sync::OnceCell; -use parking_lot::Mutex; -use prometheus::{ - register_histogram_vec_with_registry, register_histogram_with_registry, - register_int_counter_vec_with_registry, register_int_counter_with_registry, - register_int_gauge_vec_with_registry, register_int_gauge_with_registry, Histogram, IntCounter, - IntCounterVec, IntGauge, IntGaugeVec, Registry, -}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use shared_crypto::intent::{AppId, Intent, IntentMessage, IntentScope, IntentVersion}; -use sui_archival::reader::ArchiveReaderBalancer; -use sui_config::{ +use iota_archival::reader::ArchiveReaderBalancer; +use iota_config::{ certificate_deny_config::CertificateDenyConfig, genesis::Genesis, node::{ @@ -51,23 +36,23 @@ use sui_config::{ transaction_deny_config::TransactionDenyConfig, NodeConfig, }; -use sui_framework::{BuiltInFramework, SystemPackage}; -use sui_json_rpc_types::{ - DevInspectResults, DryRunTransactionBlockResponse, EventFilter, SuiEvent, SuiMoveValue, - SuiObjectDataFilter, SuiTransactionBlockData, SuiTransactionBlockEffects, - SuiTransactionBlockEvents, TransactionFilter, +use iota_framework::{BuiltInFramework, SystemPackage}; +use iota_json_rpc_types::{ + DevInspectResults, DryRunTransactionBlockResponse, EventFilter, IotaEvent, IotaMoveValue, + IotaObjectDataFilter, IotaTransactionBlockData, IotaTransactionBlockEffects, + IotaTransactionBlockEvents, TransactionFilter, }; -use sui_macros::{fail_point, fail_point_async, fail_point_if}; -use sui_protocol_config::{ProtocolConfig, SupportedProtocolVersions}; -use sui_storage::{ +use iota_macros::{fail_point, fail_point_async, fail_point_if}; +use iota_protocol_config::{ProtocolConfig, SupportedProtocolVersions}; +use iota_storage::{ indexes::{CoinInfo, ObjectIndexChanges}, key_value_store::{TransactionKeyValueStore, TransactionKeyValueStoreTrait}, key_value_store_metrics::KeyValueStoreMetrics, IndexStore, }; #[cfg(msim)] -use sui_types::committee::CommitteeTrait; -use sui_types::{ +use iota_types::committee::CommitteeTrait; +use iota_types::{ authenticator_state::get_authenticator_state, base_types::*, committee::{Committee, EpochId, ProtocolVersion}, @@ -79,17 +64,21 @@ use sui_types::{ InputSharedObject, SignedTransactionEffects, TransactionEffects, TransactionEffectsAPI, TransactionEvents, VerifiedCertifiedTransactionEffects, VerifiedSignedTransactionEffects, }, - error::{ExecutionError, SuiError, SuiResult, UserInputError}, + error::{ExecutionError, IotaError, IotaResult, UserInputError}, event::{Event, EventID}, executable_transaction::VerifiedExecutableTransaction, execution_config_utils::to_binary_config, execution_status::ExecutionStatus, fp_ensure, - gas::{GasCostSummary, SuiGasStatus}, + gas::{GasCostSummary, IotaGasStatus}, inner_temporary_store::{ InnerTemporaryStore, ObjectMap, TemporaryModuleResolver, TemporaryPackageStore, TxCoins, WrittenObjects, }, + iota_system_state::{ + epoch_start_iota_system_state::EpochStartSystemStateTrait, get_iota_system_state, + IotaSystemState, IotaSystemStateTrait, + }, is_system_package, message_envelope::Message, messages_checkpoint::{ @@ -110,14 +99,26 @@ use sui_types::{ storage::{ BackingPackageStore, BackingStore, ObjectKey, ObjectOrTombstone, ObjectStore, WriteKind, }, - sui_system_state::{ - epoch_start_sui_system_state::EpochStartSystemStateTrait, get_sui_system_state, - SuiSystemState, SuiSystemStateTrait, - }, transaction::*, type_resolver::LayoutResolver, - TypeTag, SUI_SYSTEM_ADDRESS, + TypeTag, IOTA_SYSTEM_ADDRESS, }; +use itertools::Itertools; +use move_binary_format::{binary_config::BinaryConfig, CompiledModule}; +use move_core_types::{annotated_value::MoveStructLayout, language_storage::ModuleId}; +use mysten_metrics::{ + monitored_scope, spawn_monitored_task, TX_TYPE_SHARED_OBJ_TX, TX_TYPE_SINGLE_WRITER_TX, +}; +use once_cell::sync::OnceCell; +use parking_lot::Mutex; +use prometheus::{ + register_histogram_vec_with_registry, register_histogram_with_registry, + register_int_counter_vec_with_registry, register_int_counter_with_registry, + register_int_gauge_vec_with_registry, register_int_gauge_with_registry, Histogram, IntCounter, + IntCounterVec, IntGauge, IntGaugeVec, Registry, +}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use shared_crypto::intent::{AppId, Intent, IntentMessage, IntentScope, IntentVersion}; use tap::{TapFallible, TapOptional}; use tokio::{ sync::{mpsc, mpsc::unbounded_channel, oneshot, RwLock}, @@ -826,7 +827,7 @@ impl AuthorityState { pub fn get_epoch_state_commitments( &self, epoch: EpochId, - ) -> SuiResult>> { + ) -> IotaResult>> { let commitments = self.checkpoint_store .get_epoch_last_checkpoint(epoch)? @@ -849,7 +850,7 @@ impl AuthorityState { &self, transaction: VerifiedTransaction, epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { let tx_digest = transaction.digest(); let tx_data = transaction.data().transaction_data(); @@ -863,7 +864,7 @@ impl AuthorityState { // Note: the deny checks may do redundant package loads but: // - they only load packages when there is an active package deny map // - the loads are cached anyway - sui_transaction_checks::deny::check_transaction_for_signing( + iota_transaction_checks::deny::check_transaction_for_signing( tx_data, transaction.tx_signatures(), &input_object_kinds, @@ -882,14 +883,15 @@ impl AuthorityState { ) .await?; - let (_gas_status, checked_input_objects) = sui_transaction_checks::check_transaction_input( - epoch_store.protocol_config(), - epoch_store.reference_gas_price(), - tx_data, - input_objects, - &receiving_objects, - &self.metrics.bytecode_verifier_metrics, - )?; + let (_gas_status, checked_input_objects) = + iota_transaction_checks::check_transaction_input( + epoch_store.protocol_config(), + epoch_store.reference_gas_price(), + tx_data, + input_objects, + &receiving_objects, + &self.metrics.bytecode_verifier_metrics, + )?; if epoch_store.coin_deny_list_state_enabled() { self.check_coin_deny(tx_data.sender(), &checked_input_objects, &receiving_objects)?; @@ -921,11 +923,11 @@ impl AuthorityState { &self, epoch_store: &Arc, transaction: VerifiedTransaction, - ) -> SuiResult { + ) -> IotaResult { // CRITICAL! Validators should never sign an external system transaction. fp_ensure!( !transaction.is_system_tx(), - SuiError::InvalidSystemTransaction + IotaError::InvalidSystemTransaction ); let tx_digest = *transaction.digest(); @@ -951,7 +953,7 @@ impl AuthorityState { .get_reconfig_state_read_lock_guard() .should_accept_user_certs() { - return Err(SuiError::ValidatorHaltedAtEpochEnd); + return Err(IotaError::ValidatorHaltedAtEpochEnd); } // Checks to see if the transaction has expired @@ -959,7 +961,7 @@ impl AuthorityState { TransactionExpiration::None => false, TransactionExpiration::Epoch(epoch) => *epoch < epoch_store.epoch(), } { - return Err(SuiError::TransactionExpired); + return Err(IotaError::TransactionExpired); } let signed = self.handle_transaction_impl(transaction, epoch_store).await; @@ -994,7 +996,7 @@ impl AuthorityState { consensus_adapter: &Arc, tx_data: &SenderSignedData, do_authority_overload_check: bool, - ) -> SuiResult { + ) -> IotaResult { if do_authority_overload_check { self.check_authority_overload(tx_data)?; } @@ -1004,7 +1006,7 @@ impl AuthorityState { Ok(()) } - fn check_authority_overload(&self, tx_data: &SenderSignedData) -> SuiResult { + fn check_authority_overload(&self, tx_data: &SenderSignedData) -> IotaResult { if !self.overload_info.is_overload.load(Ordering::Relaxed) { return Ok(()); } @@ -1033,7 +1035,7 @@ impl AuthorityState { // giving us incorrect effects. effects: &VerifiedCertifiedTransactionEffects, epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { assert!(self.is_fullnode(epoch_store)); let _metrics_guard = self .metrics @@ -1043,7 +1045,7 @@ impl AuthorityState { debug!("execute_certificate_with_effects"); fp_ensure!( *effects.data().transaction_digest() == digest, - SuiError::ErrorWhileProcessingCertificate { + IotaError::ErrorWhileProcessingCertificate { err: "effects/tx digest mismatch".to_string() } ); @@ -1093,7 +1095,7 @@ impl AuthorityState { &self, certificate: &VerifiedCertificate, epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { let _metrics_guard = if certificate.contains_shared_object() { self.metrics .execute_certificate_latency_shared_object @@ -1132,14 +1134,14 @@ impl AuthorityState { /// locks are set. If this cannot be satisfied by the caller, /// execute_certificate() should be called instead. /// - /// Should only be called within sui-core. + /// Should only be called within iota-core. #[instrument(level = "trace", skip_all)] pub async fn try_execute_immediately( &self, certificate: &VerifiedExecutableTransaction, expected_effects_digest: Option, epoch_store: &Arc, - ) -> SuiResult<(TransactionEffects, Option)> { + ) -> IotaResult<(TransactionEffects, Option)> { let _scope = monitored_scope("Execution::try_execute_immediately"); let _metrics_guard = self.metrics.internal_execution_latency.start_timer(); debug!("execute_certificate_internal"); @@ -1169,7 +1171,7 @@ impl AuthorityState { &self, certificate: &VerifiedExecutableTransaction, epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { let _scope = monitored_scope("Execution::load_input_objects"); let _metrics_guard = self .metrics @@ -1200,7 +1202,7 @@ impl AuthorityState { &self, certificate: &VerifiedExecutableTransaction, epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { self.read_objects(certificate, epoch_store).await } @@ -1210,7 +1212,7 @@ impl AuthorityState { pub async fn try_execute_for_test( &self, certificate: &VerifiedCertificate, - ) -> SuiResult<(VerifiedSignedTransactionEffects, Option)> { + ) -> IotaResult<(VerifiedSignedTransactionEffects, Option)> { let epoch_store = self.epoch_store_for_testing(); let (effects, execution_error_opt) = self .try_execute_immediately( @@ -1226,14 +1228,14 @@ impl AuthorityState { pub async fn notify_read_effects( &self, certificate: &VerifiedCertificate, - ) -> SuiResult { + ) -> IotaResult { self.execution_cache .notify_read_executed_effects(&[*certificate.digest()]) .await .map(|mut r| r.pop().expect("must return correct number of effects")) } - fn check_owned_locks(&self, owned_object_refs: &[ObjectRef]) -> SuiResult { + fn check_owned_locks(&self, owned_object_refs: &[ObjectRef]) -> IotaResult { self.execution_cache .check_owned_object_locks_exist(owned_object_refs) } @@ -1250,7 +1252,7 @@ impl AuthorityState { inner_temporary_store: &InnerTemporaryStore, certificate: &VerifiedExecutableTransaction, debug_dump_config: &StateDebugDumpConfig, - ) -> SuiResult { + ) -> IotaResult { let dump_dir = debug_dump_config .dump_file_directory .as_ref() @@ -1268,7 +1270,7 @@ impl AuthorityState { certificate, )? .write_to_file(&dump_dir) - .map_err(|e| SuiError::FileIOError(e.to_string())) + .map_err(|e| IotaError::FileIOError(e.to_string())) } #[instrument(level = "trace", skip_all)] @@ -1279,13 +1281,13 @@ impl AuthorityState { input_objects: InputObjects, expected_effects_digest: Option, epoch_store: &Arc, - ) -> SuiResult<(TransactionEffects, Option)> { + ) -> IotaResult<(TransactionEffects, Option)> { let process_certificate_start_time = tokio::time::Instant::now(); let digest = *certificate.digest(); fail_point_if!("correlated-crash-process-certificate", || { - if sui_simulator::random::deterministic_probability_once(&digest, 0.01) { - sui_simulator::task::kill_current_node(None); + if iota_simulator::random::deterministic_probability_once(&digest, 0.01) { + iota_simulator::task::kill_current_node(None); } }); @@ -1316,7 +1318,7 @@ impl AuthorityState { if *execution_guard != epoch_store.epoch() { tx_guard.release(); info!("The epoch of the execution_guard doesn't match the epoch store"); - return Err(SuiError::WrongEpoch { + return Err(IotaError::WrongEpoch { expected_epoch: epoch_store.epoch(), actual_epoch: *execution_guard, }); @@ -1442,7 +1444,7 @@ impl AuthorityState { tx_guard: CertTxGuard, _execution_guard: ExecutionLockReadGuard<'_>, epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { let _scope: Option = monitored_scope("Execution::commit_certificate"); let _metrics_guard = self.metrics.commit_certificate_latency.start_timer(); @@ -1459,7 +1461,7 @@ impl AuthorityState { Some(AuthoritySignInfo::new( epoch_store.epoch(), effects, - Intent::sui_app(IntentScope::TransactionEffects), + Intent::iota_app(IntentScope::TransactionEffects), self.name, &*self.secret, )) @@ -1577,7 +1579,7 @@ impl AuthorityState { certificate: &VerifiedExecutableTransaction, input_objects: InputObjects, epoch_store: &Arc, - ) -> SuiResult<( + ) -> IotaResult<( InnerTemporaryStore, TransactionEffects, Option, @@ -1593,7 +1595,7 @@ impl AuthorityState { // The cost of partially re-auditing a transaction before execution is // tolerated. - let (gas_status, input_objects) = sui_transaction_checks::check_certificate_input( + let (gas_status, input_objects) = iota_transaction_checks::check_certificate_input( certificate, input_objects, epoch_store.protocol_config(), @@ -1614,9 +1616,9 @@ impl AuthorityState { protocol_config, self.metrics.limits_metrics.clone(), // TODO: would be nice to pass the whole NodeConfig here, but it creates a - // cyclic dependency w/ sui-adapter + // cyclic dependency w/ iota-adapter self.expensive_safety_check_config - .enable_deep_per_tx_sui_conservation_check(), + .enable_deep_per_tx_iota_conservation_check(), self.certificate_deny_config.certificate_deny_set(), &epoch_store.epoch_start_config().epoch_data().epoch_id(), epoch_store @@ -1651,7 +1653,7 @@ impl AuthorityState { certificate: &VerifiedExecutableTransaction, input_objects: InputObjects, epoch_store: &Arc, - ) -> SuiResult<( + ) -> IotaResult<( InnerTemporaryStore, TransactionEffects, Option, @@ -1666,7 +1668,7 @@ impl AuthorityState { &self, transaction: TransactionData, transaction_digest: TransactionDigest, - ) -> SuiResult<( + ) -> IotaResult<( DryRunTransactionBlockResponse, BTreeMap, TransactionEffects, @@ -1674,13 +1676,13 @@ impl AuthorityState { )> { let epoch_store = self.load_epoch_store_one_call_per_task(); if !self.is_fullnode(&epoch_store) { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: "dry-exec is only supported on fullnodes".to_string(), }); } if transaction.kind().is_system_tx() { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: "dry-exec does not support system transactions".to_string(), }); } @@ -1692,7 +1694,7 @@ impl AuthorityState { let input_object_kinds = transaction.input_objects()?; let receiving_object_refs = transaction.receiving_objects(); - sui_transaction_checks::deny::check_transaction_for_signing( + iota_transaction_checks::deny::check_transaction_for_signing( &transaction, &[], &input_object_kinds, @@ -1715,10 +1717,10 @@ impl AuthorityState { let mut gas_object_refs = transaction.gas().to_vec(); let ((gas_status, checked_input_objects), mock_gas) = if transaction.gas().is_empty() { let sender = transaction.sender(); - // use a 1B sui coin - const MIST_TO_SUI: u64 = 1_000_000_000; - const DRY_RUN_SUI: u64 = 1_000_000_000; - let max_coin_value = MIST_TO_SUI * DRY_RUN_SUI; + // use a 1B iota coin + const MICROS_TO_IOTA: u64 = 1_000_000_000; + const DRY_RUN_IOTA: u64 = 1_000_000_000; + let max_coin_value = MICROS_TO_IOTA * DRY_RUN_IOTA; let gas_object_id = ObjectID::random(); let gas_object = Object::new_move( MoveObject::new_gas_coin(OBJECT_START_VERSION, gas_object_id, max_coin_value), @@ -1728,7 +1730,7 @@ impl AuthorityState { let gas_object_ref = gas_object.compute_object_reference(); gas_object_refs = vec![gas_object_ref]; ( - sui_transaction_checks::check_transaction_input_with_given_gas( + iota_transaction_checks::check_transaction_input_with_given_gas( epoch_store.protocol_config(), epoch_store.reference_gas_price(), &transaction, @@ -1741,7 +1743,7 @@ impl AuthorityState { ) } else { ( - sui_transaction_checks::check_transaction_input( + iota_transaction_checks::check_transaction_input( epoch_store.protocol_config(), epoch_store.reference_gas_price(), &transaction, @@ -1757,7 +1759,7 @@ impl AuthorityState { let (kind, signer, _) = transaction.execution_parts(); let silent = true; - let executor = sui_execution::executor(protocol_config, silent, None) + let executor = iota_execution::executor(protocol_config, silent, None) .expect("Creating an executor should not fail here"); let expensive_checks = false; @@ -1823,16 +1825,16 @@ impl AuthorityState { Ok(( DryRunTransactionBlockResponse { - input: SuiTransactionBlockData::try_from(transaction, &module_cache).map_err( - |e| SuiError::TransactionSerializationError { + input: IotaTransactionBlockData::try_from(transaction, &module_cache).map_err( + |e| IotaError::TransactionSerializationError { error: format!( - "Failed to convert transaction to SuiTransactionBlockData: {}", + "Failed to convert transaction to IotaTransactionBlockData: {}", e ), }, - )?, // TODO: replace the underlying try_from to SuiError. This one goes deep + )?, // TODO: replace the underlying try_from to IotaError. This one goes deep effects: effects.clone().try_into()?, - events: SuiTransactionBlockEvents::try_from( + events: IotaTransactionBlockEvents::try_from( inner_temp_store.events.clone(), tx_digest, None, @@ -1851,25 +1853,25 @@ impl AuthorityState { #[allow(clippy::collapsible_else_if)] pub async fn dev_inspect_transaction_block( &self, - sender: SuiAddress, + sender: IotaAddress, transaction_kind: TransactionKind, gas_price: Option, gas_budget: Option, - gas_sponsor: Option, + gas_sponsor: Option, gas_objects: Option>, show_raw_txn_data_and_effects: Option, skip_checks: Option, - ) -> SuiResult { + ) -> IotaResult { let epoch_store = self.load_epoch_store_one_call_per_task(); if !self.is_fullnode(&epoch_store) { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: "dev-inspect is only supported on fullnodes".to_string(), }); } if transaction_kind.is_system_tx() { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: "system transactions are not supported".to_string(), }); } @@ -1899,7 +1901,7 @@ impl AuthorityState { }); let raw_txn_data = if show_raw_txn_data_and_effects { - bcs::to_bytes(&transaction).map_err(|_| SuiError::TransactionSerializationError { + bcs::to_bytes(&transaction).map_err(|_| IotaError::TransactionSerializationError { error: "Failed to serialize transaction during dev inspect".to_string(), })? } else { @@ -1912,7 +1914,7 @@ impl AuthorityState { let input_object_kinds = transaction.input_objects()?; let receiving_object_refs = transaction.receiving_objects(); - sui_transaction_checks::deny::check_transaction_for_signing( + iota_transaction_checks::deny::check_transaction_for_signing( &transaction, &[], &input_object_kinds, @@ -1954,13 +1956,13 @@ impl AuthorityState { dummy_gas_object.into(), )); } - let checked_input_objects = sui_transaction_checks::check_dev_inspect_input( + let checked_input_objects = iota_transaction_checks::check_dev_inspect_input( protocol_config, &transaction_kind, input_objects, receiving_objects, )?; - let gas_status = SuiGasStatus::new( + let gas_status = IotaGasStatus::new( max_tx_gas, transaction.gas_price(), reference_gas_price, @@ -1973,7 +1975,7 @@ impl AuthorityState { // function and its dummy gas variant which will perform full // fledged checks just like a real transaction execution. if transaction.gas().is_empty() { - sui_transaction_checks::check_transaction_input_with_given_gas( + iota_transaction_checks::check_transaction_input_with_given_gas( epoch_store.protocol_config(), epoch_store.reference_gas_price(), &transaction, @@ -1983,7 +1985,7 @@ impl AuthorityState { &self.metrics.bytecode_verifier_metrics, )? } else { - sui_transaction_checks::check_transaction_input( + iota_transaction_checks::check_transaction_input( epoch_store.protocol_config(), epoch_store.reference_gas_price(), &transaction, @@ -1994,13 +1996,13 @@ impl AuthorityState { } }; - let executor = sui_execution::executor(protocol_config, /* silent */ true, None) + let executor = iota_execution::executor(protocol_config, /* silent */ true, None) .expect("Creating an executor should not fail here"); let intent_msg = IntentMessage::new( Intent { version: IntentVersion::V0, scope: IntentScope::TransactionData, - app_id: AppId::Sui, + app_id: AppId::Iota, }, transaction, ); @@ -2027,7 +2029,7 @@ impl AuthorityState { ); let raw_effects = if show_raw_txn_data_and_effects { - bcs::to_bytes(&effects).map_err(|_| SuiError::TransactionSerializationError { + bcs::to_bytes(&effects).map_err(|_| IotaError::TransactionSerializationError { error: "Failed to serialize transaction effects during dev inspect".to_string(), })? } else { @@ -2057,7 +2059,7 @@ impl AuthorityState { Ok(epoch_store.reference_gas_price()) } - pub fn is_tx_already_executed(&self, digest: &TransactionDigest) -> SuiResult { + pub fn is_tx_already_executed(&self, digest: &TransactionDigest) -> IotaResult { self.execution_cache.is_tx_already_executed(digest) } @@ -2074,7 +2076,7 @@ impl AuthorityState { tx_coins: Option, written: &WrittenObjects, inner_temporary_store: &InnerTemporaryStore, - ) -> SuiResult { + ) -> IotaResult { let changes = self .process_object_index(effects, written, inner_temporary_store) .tap_err(|e| warn!(tx_digest=?digest, "Failed to process object index, index_tx is skipped: {e}"))?; @@ -2146,7 +2148,7 @@ impl AuthorityState { effects: &TransactionEffects, written: &WrittenObjects, inner_temporary_store: &InnerTemporaryStore, - ) -> SuiResult { + ) -> IotaResult { let epoch_store = self.load_epoch_store_one_call_per_task(); let mut layout_resolver = epoch_store @@ -2292,7 +2294,7 @@ impl AuthorityState { o: &Object, written: &WrittenObjects, resolver: &mut dyn LayoutResolver, - ) -> SuiResult> { + ) -> IotaResult> { // Skip if not a move object let Some(move_object) = o.data.try_as_move().cloned() else { return Ok(None); @@ -2311,14 +2313,14 @@ impl AuthorityState { let name_type = move_object.type_().try_extract_field_name(&type_)?; let bcs_name = bcs::to_bytes(&name_value.clone().undecorate()).map_err(|e| { - SuiError::ObjectSerializationError { + IotaError::ObjectSerializationError { error: format!("{e}"), } })?; let name = DynamicFieldName { type_: name_type, - value: SuiMoveValue::from(name_value).to_json_value(), + value: IotaMoveValue::from(name_value).to_json_value(), }; Ok(Some(match type_ { @@ -2375,7 +2377,7 @@ impl AuthorityState { effects: &TransactionEffects, inner_temporary_store: &InnerTemporaryStore, epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { if self.indexes.is_none() { return Ok(()); } @@ -2406,7 +2408,7 @@ impl AuthorityState { .tap_err(|e| error!(?tx_digest, "Post processing - Couldn't index tx: {e}")) .expect("Indexing tx should not fail"); - let effects: SuiTransactionBlockEffects = effects.clone().try_into()?; + let effects: IotaTransactionBlockEffects = effects.clone().try_into()?; let events = self.make_transaction_block_events( events.clone(), *tx_digest, @@ -2444,7 +2446,7 @@ impl AuthorityState { timestamp_ms: u64, epoch_store: &Arc, inner_temporary_store: &InnerTemporaryStore, - ) -> SuiResult { + ) -> IotaResult { let mut layout_resolver = epoch_store .executor() @@ -2452,7 +2454,7 @@ impl AuthorityState { inner_temporary_store, self.execution_cache.clone(), ))); - SuiTransactionBlockEvents::try_from( + IotaTransactionBlockEvents::try_from( transaction_events, digest, Some(timestamp_ms), @@ -2469,11 +2471,11 @@ impl AuthorityState { pub async fn handle_transaction_info_request( &self, request: TransactionInfoRequest, - ) -> SuiResult { + ) -> IotaResult { let epoch_store = self.load_epoch_store_one_call_per_task(); let (transaction, status) = self .get_transaction_status(&request.transaction_digest, &epoch_store)? - .ok_or(SuiError::TransactionNotFound { + .ok_or(IotaError::TransactionNotFound { digest: request.transaction_digest, })?; Ok(TransactionInfoResponse { @@ -2486,7 +2488,7 @@ impl AuthorityState { pub async fn handle_object_info_request( &self, request: ObjectInfoRequest, - ) -> SuiResult { + ) -> IotaResult { let epoch_store = self.load_epoch_store_one_call_per_task(); let requested_object_seq = match request.request_kind { @@ -2495,7 +2497,7 @@ impl AuthorityState { .get_object_or_tombstone(request.object_id) .await? .ok_or_else(|| { - SuiError::from(UserInputError::ObjectNotFound { + IotaError::from(UserInputError::ObjectNotFound { object_id: request.object_id, version: None, }) @@ -2509,7 +2511,7 @@ impl AuthorityState { .execution_cache .get_object_by_key(&request.object_id, requested_object_seq)? .ok_or_else(|| { - SuiError::from(UserInputError::ObjectNotFound { + IotaError::from(UserInputError::ObjectNotFound { object_id: request.object_id, version: Some(requested_object_seq), }) @@ -2548,7 +2550,7 @@ impl AuthorityState { pub fn handle_checkpoint_request( &self, request: &CheckpointRequest, - ) -> SuiResult { + ) -> IotaResult { let summary = match request.sequence_number { Some(seq) => self .checkpoint_store @@ -2572,7 +2574,7 @@ impl AuthorityState { pub fn handle_checkpoint_request_v2( &self, request: &CheckpointRequestV2, - ) -> SuiResult { + ) -> IotaResult { let summary = if request.certified { let summary = match request.sequence_number { Some(seq) => self @@ -2611,7 +2613,7 @@ impl AuthorityState { info!("supported versions are: {:?}", supported_protocol_versions); if !supported_protocol_versions.is_version_supported(current_version) { let msg = format!( - "Unsupported protocol version. The network is at {:?}, but this SuiNode only supports: {:?}. Shutting down.", + "Unsupported protocol version. The network is at {:?}, but this IotaNode only supports: {:?}. Shutting down.", current_version, supported_protocol_versions, ); @@ -2622,7 +2624,7 @@ impl AuthorityState { std::process::exit(1); #[cfg(msim)] - sui_simulator::task::shutdown_current_node(); + iota_simulator::task::shutdown_current_node(); } } @@ -2811,7 +2813,7 @@ impl AuthorityState { &self, genesis_objects: &[Object], epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { let Some(index_store) = &self.indexes else { return Ok(()); }; @@ -2860,12 +2862,12 @@ impl AuthorityState { pub async fn execution_lock_for_executable_transaction( &self, transaction: &VerifiedExecutableTransaction, - ) -> SuiResult { + ) -> IotaResult { let lock = self.execution_lock.read().await; if *lock == transaction.auth_sig().epoch() { Ok(lock) } else { - Err(SuiError::WrongEpoch { + Err(IotaError::WrongEpoch { expected_epoch: *lock, actual_epoch: transaction.auth_sig().epoch(), }) @@ -2886,7 +2888,7 @@ impl AuthorityState { checkpoint_executor: &CheckpointExecutor, accumulator: Arc, expensive_safety_check_config: &ExpensiveSafetyCheckConfig, - ) -> SuiResult> { + ) -> IotaResult> { Self::check_protocol_version( supported_protocol_versions, epoch_start_configuration @@ -2975,13 +2977,13 @@ impl AuthorityState { expensive_safety_check_config: &ExpensiveSafetyCheckConfig, ) { info!( - "Performing sui conservation consistency check for epoch {}", + "Performing iota conservation consistency check for epoch {}", cur_epoch_store.epoch() ); if let Err(err) = self .execution_cache - .expensive_check_sui_conservation(cur_epoch_store) + .expensive_check_iota_conservation(cur_epoch_store) { if cfg!(debug_assertions) { panic!("{}", err); @@ -2989,10 +2991,10 @@ impl AuthorityState { // We cannot panic in production yet because it is known that there are some // inconsistencies in testnet. We will enable this once we make it balanced // again in testnet. - warn!("Sui conservation consistency check failed: {}", err); + warn!("Iota conservation consistency check failed: {}", err); } } else { - info!("Sui conservation consistency check passed"); + info!("Iota conservation consistency check passed"); } // check for root state hash consistency with live object set @@ -3071,7 +3073,7 @@ impl AuthorityState { checkpoint_path: &Path, cur_epoch_store: &AuthorityPerEpochStore, checkpoint_indexes: bool, - ) -> SuiResult { + ) -> IotaResult { let _metrics_guard = self.metrics.db_checkpoint_latency.start_timer(); let current_epoch = cur_epoch_store.epoch(); @@ -3085,13 +3087,13 @@ impl AuthorityState { if checkpoint_path_tmp.exists() { fs::remove_dir_all(&checkpoint_path_tmp) - .map_err(|e| SuiError::FileIOError(e.to_string()))?; + .map_err(|e| IotaError::FileIOError(e.to_string()))?; } fs::create_dir_all(&checkpoint_path_tmp) - .map_err(|e| SuiError::FileIOError(e.to_string()))?; + .map_err(|e| IotaError::FileIOError(e.to_string()))?; fs::create_dir(&store_checkpoint_path_tmp) - .map_err(|e| SuiError::FileIOError(e.to_string()))?; + .map_err(|e| IotaError::FileIOError(e.to_string()))?; // NOTE: Do not change the order of invoking these checkpoint calls // We want to snapshot checkpoint db first to not race with state sync @@ -3111,7 +3113,7 @@ impl AuthorityState { } fs::rename(checkpoint_path_tmp, checkpoint_path) - .map_err(|e| SuiError::FileIOError(e.to_string()))?; + .map_err(|e| IotaError::FileIOError(e.to_string()))?; Ok(()) } @@ -3135,23 +3137,23 @@ impl AuthorityState { } #[instrument(level = "trace", skip_all)] - pub async fn get_object(&self, object_id: &ObjectID) -> SuiResult> { + pub async fn get_object(&self, object_id: &ObjectID) -> IotaResult> { self.execution_cache .get_object(object_id) .map_err(Into::into) } - pub async fn get_sui_system_package_object_ref(&self) -> SuiResult { + pub async fn get_iota_system_package_object_ref(&self) -> IotaResult { Ok(self - .get_object(&SUI_SYSTEM_ADDRESS.into()) + .get_object(&IOTA_SYSTEM_ADDRESS.into()) .await? .expect("framework object should always exist") .compute_object_reference()) } // This function is only used for testing. - pub fn get_sui_system_state_object_for_testing(&self) -> SuiResult { - self.execution_cache.get_sui_system_state_object_unsafe() + pub fn get_iota_system_state_object_for_testing(&self) -> IotaResult { + self.execution_cache.get_iota_system_state_object_unsafe() } #[instrument(level = "trace", skip_all)] @@ -3159,7 +3161,7 @@ impl AuthorityState { &self, digest: &TransactionDigest, epoch_store: &AuthorityPerEpochStore, - ) -> SuiResult> { + ) -> IotaResult> { epoch_store.get_transaction_checkpoint(digest) } @@ -3167,7 +3169,7 @@ impl AuthorityState { pub fn get_checkpoint_by_sequence_number( &self, sequence_number: CheckpointSequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self .checkpoint_store .get_checkpoint_by_sequence_number(sequence_number)?) @@ -3178,7 +3180,7 @@ impl AuthorityState { &self, digest: &TransactionDigest, epoch_store: &AuthorityPerEpochStore, - ) -> SuiResult> { + ) -> IotaResult> { let checkpoint = self.get_transaction_checkpoint_sequence(digest, epoch_store)?; let Some(checkpoint) = checkpoint else { return Ok(None); @@ -3190,7 +3192,7 @@ impl AuthorityState { } #[instrument(level = "trace", skip_all)] - pub fn get_object_read(&self, object_id: &ObjectID) -> SuiResult { + pub fn get_object_read(&self, object_id: &ObjectID) -> IotaResult { Ok( match self .execution_cache @@ -3223,19 +3225,19 @@ impl AuthorityState { } #[instrument(level = "trace", skip_all)] - pub fn get_move_object(&self, object_id: &ObjectID) -> SuiResult + pub fn get_move_object(&self, object_id: &ObjectID) -> IotaResult where T: DeserializeOwned, { let o = self.get_object_read(object_id)?.into_object()?; if let Some(move_object) = o.data.try_as_move() { Ok(bcs::from_bytes(move_object.contents()).map_err(|e| { - SuiError::ObjectDeserializationError { + IotaError::ObjectDeserializationError { error: format!("{e}"), } })?) } else { - Err(SuiError::ObjectDeserializationError { + Err(IotaError::ObjectDeserializationError { error: format!("Provided object : [{object_id}] is not a Move object."), }) } @@ -3251,7 +3253,7 @@ impl AuthorityState { &self, object_id: &ObjectID, version: SequenceNumber, - ) -> SuiResult { + ) -> IotaResult { // Firstly we see if the object ever existed by getting its latest data let Some(obj_ref) = self .execution_cache @@ -3305,7 +3307,7 @@ impl AuthorityState { &self, object_id: &ObjectID, version: SequenceNumber, - ) -> SuiResult)>> { + ) -> IotaResult)>> { let Some(object) = self.execution_cache.get_object_by_key(object_id, version)? else { return Ok(None); }; @@ -3314,7 +3316,7 @@ impl AuthorityState { Ok(Some((object, layout))) } - fn get_object_layout(&self, object: &Object) -> SuiResult> { + fn get_object_layout(&self, object: &Object) -> IotaResult> { let layout = object .data .try_as_move() @@ -3333,11 +3335,11 @@ impl AuthorityState { &self, object_id: &ObjectID, version: SequenceNumber, - ) -> SuiResult { + ) -> IotaResult { self.execution_cache .get_object_by_key(object_id, version)? .ok_or_else(|| { - SuiError::from(UserInputError::ObjectNotFound { + IotaError::from(UserInputError::ObjectNotFound { object_id: *object_id, version: Some(version), }) @@ -3348,57 +3350,57 @@ impl AuthorityState { #[instrument(level = "trace", skip_all)] pub fn get_owner_objects( &self, - owner: SuiAddress, + owner: IotaAddress, // If `Some`, the query will start from the next item after the specified cursor cursor: Option, limit: usize, - filter: Option, - ) -> SuiResult> { + filter: Option, + ) -> IotaResult> { if let Some(indexes) = &self.indexes { indexes.get_owner_objects(owner, cursor, limit, filter) } else { - Err(SuiError::IndexStoreNotAvailable) + Err(IotaError::IndexStoreNotAvailable) } } #[instrument(level = "trace", skip_all)] pub fn get_owned_coins_iterator_with_cursor( &self, - owner: SuiAddress, + owner: IotaAddress, // If `Some`, the query will start from the next item after the specified cursor cursor: (String, ObjectID), limit: usize, one_coin_type_only: bool, - ) -> SuiResult + '_> { + ) -> IotaResult + '_> { if let Some(indexes) = &self.indexes { indexes.get_owned_coins_iterator_with_cursor(owner, cursor, limit, one_coin_type_only) } else { - Err(SuiError::IndexStoreNotAvailable) + Err(IotaError::IndexStoreNotAvailable) } } #[instrument(level = "trace", skip_all)] pub fn get_owner_objects_iterator( &self, - owner: SuiAddress, + owner: IotaAddress, // If `Some`, the query will start from the next item after the specified cursor cursor: Option, - filter: Option, - ) -> SuiResult + '_> { + filter: Option, + ) -> IotaResult + '_> { let cursor_u = cursor.unwrap_or(ObjectID::ZERO); if let Some(indexes) = &self.indexes { indexes.get_owner_objects_iterator(owner, cursor_u, filter) } else { - Err(SuiError::IndexStoreNotAvailable) + Err(IotaError::IndexStoreNotAvailable) } } #[instrument(level = "trace", skip_all)] pub async fn get_move_objects( &self, - owner: SuiAddress, + owner: IotaAddress, type_: MoveObjectType, - ) -> SuiResult> + ) -> IotaResult> where T: DeserializeOwned, { @@ -3416,16 +3418,16 @@ impl AuthorityState { for (o, id) in objects.into_iter().zip(object_ids) { let object = o.ok_or_else(|| { - SuiError::from(UserInputError::ObjectNotFound { + IotaError::from(UserInputError::ObjectNotFound { object_id: id.0, version: Some(id.1), }) })?; let move_object = object.data.try_as_move().ok_or_else(|| { - SuiError::from(UserInputError::MovePackageAsObject { object_id: id.0 }) + IotaError::from(UserInputError::MovePackageAsObject { object_id: id.0 }) })?; move_objects.push(bcs::from_bytes(move_object.contents()).map_err(|e| { - SuiError::ObjectDeserializationError { + IotaError::ObjectDeserializationError { error: format!("{e}"), } })?); @@ -3440,7 +3442,7 @@ impl AuthorityState { // If `Some`, the query will start from the next item after the specified cursor cursor: Option, limit: usize, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self .get_dynamic_fields_iterator(owner, cursor)? .take(limit) @@ -3452,12 +3454,12 @@ impl AuthorityState { owner: ObjectID, // If `Some`, the query will start from the next item after the specified cursor cursor: Option, - ) -> SuiResult> + '_> + ) -> IotaResult> + '_> { if let Some(indexes) = &self.indexes { indexes.get_dynamic_fields_iterator(owner, cursor) } else { - Err(SuiError::IndexStoreNotAvailable) + Err(IotaError::IndexStoreNotAvailable) } } @@ -3467,16 +3469,16 @@ impl AuthorityState { owner: ObjectID, name_type: TypeTag, name_bcs_bytes: &[u8], - ) -> SuiResult> { + ) -> IotaResult> { if let Some(indexes) = &self.indexes { indexes.get_dynamic_field_object_id(owner, name_type, name_bcs_bytes) } else { - Err(SuiError::IndexStoreNotAvailable) + Err(IotaError::IndexStoreNotAvailable) } } #[instrument(level = "trace", skip_all)] - pub fn get_total_transaction_blocks(&self) -> SuiResult { + pub fn get_total_transaction_blocks(&self) -> IotaResult { Ok(self.get_indexes()?.next_sequence_number()) } @@ -3485,7 +3487,7 @@ impl AuthorityState { &self, digest: TransactionDigest, kv_store: Arc, - ) -> SuiResult<(Transaction, TransactionEffects)> { + ) -> IotaResult<(Transaction, TransactionEffects)> { let transaction = kv_store.get_tx(digest).await?; let effects = kv_store.get_fx_by_tx_digest(digest).await?; Ok((transaction, effects)) @@ -3495,7 +3497,7 @@ impl AuthorityState { pub fn multi_get_checkpoint_by_sequence_number( &self, sequence_numbers: &[CheckpointSequenceNumber], - ) -> SuiResult>> { + ) -> IotaResult>> { Ok(self .checkpoint_store .multi_get_checkpoint_by_sequence_number(sequence_numbers)?) @@ -3505,16 +3507,16 @@ impl AuthorityState { pub fn get_transaction_events( &self, digest: &TransactionEventsDigest, - ) -> SuiResult { + ) -> IotaResult { self.execution_cache .get_events(digest)? - .ok_or(SuiError::TransactionEventsNotFound { digest: *digest }) + .ok_or(IotaError::TransactionEventsNotFound { digest: *digest }) } - fn get_indexes(&self) -> SuiResult> { + fn get_indexes(&self) -> IotaResult> { match &self.indexes { Some(i) => Ok(i.clone()), - None => Err(SuiError::UnsupportedFeatureError { + None => Err(IotaError::UnsupportedFeatureError { error: "extended object indexing is not enabled on this server".into(), }), } @@ -3524,7 +3526,7 @@ impl AuthorityState { pub fn loaded_child_object_versions( &self, transaction_digest: &TransactionDigest, - ) -> SuiResult>> { + ) -> IotaResult>> { self.get_indexes()? .loaded_child_object_versions(transaction_digest) } @@ -3535,7 +3537,7 @@ impl AuthorityState { cursor: Option, limit: Option, reverse: bool, - ) -> SuiResult> { + ) -> IotaResult> { let metrics = KeyValueStoreMetrics::new_for_tests(); let kv_store = Arc::new(TransactionKeyValueStore::new( "rocksdb", @@ -3555,7 +3557,7 @@ impl AuthorityState { cursor: Option, limit: Option, reverse: bool, - ) -> SuiResult> { + ) -> IotaResult> { if let Some(TransactionFilter::Checkpoint(sequence_number)) = filter { let checkpoint_contents = kv_store.get_checkpoint_contents(sequence_number).await?; let iter = checkpoint_contents.iter().map(|c| c.transaction); @@ -3580,16 +3582,18 @@ impl AuthorityState { &self.checkpoint_store } - pub fn get_latest_checkpoint_sequence_number(&self) -> SuiResult { + pub fn get_latest_checkpoint_sequence_number(&self) -> IotaResult { self.get_checkpoint_store() .get_highest_executed_checkpoint_seq_number()? - .ok_or(SuiError::UserInputError { + .ok_or(IotaError::UserInputError { error: UserInputError::LatestCheckpointSequenceNumberNotFound, }) } #[cfg(msim)] - pub fn get_highest_pruned_checkpoint_for_testing(&self) -> SuiResult { + pub fn get_highest_pruned_checkpoint_for_testing( + &self, + ) -> IotaResult { self.database_for_testing() .perpetual_tables .get_highest_pruned_checkpoint() @@ -3599,13 +3603,13 @@ impl AuthorityState { pub fn get_checkpoint_summary_by_sequence_number( &self, sequence_number: CheckpointSequenceNumber, - ) -> SuiResult { + ) -> IotaResult { let verified_checkpoint = self .get_checkpoint_store() .get_checkpoint_by_sequence_number(sequence_number)?; match verified_checkpoint { Some(verified_checkpoint) => Ok(verified_checkpoint.into_inner().into_data()), - None => Err(SuiError::UserInputError { + None => Err(IotaError::UserInputError { error: UserInputError::VerifiedCheckpointNotFound(sequence_number), }), } @@ -3615,20 +3619,20 @@ impl AuthorityState { pub fn get_checkpoint_summary_by_digest( &self, digest: CheckpointDigest, - ) -> SuiResult { + ) -> IotaResult { let verified_checkpoint = self .get_checkpoint_store() .get_checkpoint_by_digest(&digest)?; match verified_checkpoint { Some(verified_checkpoint) => Ok(verified_checkpoint.into_inner().into_data()), - None => Err(SuiError::UserInputError { + None => Err(IotaError::UserInputError { error: UserInputError::VerifiedCheckpointDigestNotFound(Base58::encode(digest)), }), } } #[instrument(level = "trace", skip_all)] - pub fn find_publish_txn_digest(&self, package_id: ObjectID) -> SuiResult { + pub fn find_publish_txn_digest(&self, package_id: ObjectID) -> IotaResult { if is_system_package(package_id) { return self.find_genesis_txn_digest(); } @@ -3639,14 +3643,14 @@ impl AuthorityState { } #[instrument(level = "trace", skip_all)] - pub fn find_genesis_txn_digest(&self) -> SuiResult { + pub fn find_genesis_txn_digest(&self) -> IotaResult { let summary = self .get_verified_checkpoint_by_sequence_number(0)? .into_message(); let content = self.get_checkpoint_contents(summary.content_digest)?; let genesis_transaction = content.enumerate_transactions(&summary).next(); Ok(genesis_transaction - .ok_or(SuiError::UserInputError { + .ok_or(IotaError::UserInputError { error: UserInputError::GenesisTransactionNotFound, })? .1 @@ -3657,13 +3661,13 @@ impl AuthorityState { pub fn get_verified_checkpoint_by_sequence_number( &self, sequence_number: CheckpointSequenceNumber, - ) -> SuiResult { + ) -> IotaResult { let verified_checkpoint = self .get_checkpoint_store() .get_checkpoint_by_sequence_number(sequence_number)?; match verified_checkpoint { Some(verified_checkpoint) => Ok(verified_checkpoint), - None => Err(SuiError::UserInputError { + None => Err(IotaError::UserInputError { error: UserInputError::VerifiedCheckpointNotFound(sequence_number), }), } @@ -3673,13 +3677,13 @@ impl AuthorityState { pub fn get_verified_checkpoint_summary_by_digest( &self, digest: CheckpointDigest, - ) -> SuiResult { + ) -> IotaResult { let verified_checkpoint = self .get_checkpoint_store() .get_checkpoint_by_digest(&digest)?; match verified_checkpoint { Some(verified_checkpoint) => Ok(verified_checkpoint), - None => Err(SuiError::UserInputError { + None => Err(IotaError::UserInputError { error: UserInputError::VerifiedCheckpointDigestNotFound(Base58::encode(digest)), }), } @@ -3689,10 +3693,10 @@ impl AuthorityState { pub fn get_checkpoint_contents( &self, digest: CheckpointContentsDigest, - ) -> SuiResult { + ) -> IotaResult { self.get_checkpoint_store() .get_checkpoint_contents(&digest)? - .ok_or(SuiError::UserInputError { + .ok_or(IotaError::UserInputError { error: UserInputError::CheckpointContentsNotFound(digest), }) } @@ -3701,7 +3705,7 @@ impl AuthorityState { pub fn get_checkpoint_contents_by_sequence_number( &self, sequence_number: CheckpointSequenceNumber, - ) -> SuiResult { + ) -> IotaResult { let verified_checkpoint = self .get_checkpoint_store() .get_checkpoint_by_sequence_number(sequence_number)?; @@ -3710,7 +3714,7 @@ impl AuthorityState { let content_digest = verified_checkpoint.into_inner().content_digest; self.get_checkpoint_contents(content_digest) } - None => Err(SuiError::UserInputError { + None => Err(IotaError::UserInputError { error: UserInputError::VerifiedCheckpointNotFound(sequence_number), }), } @@ -3725,13 +3729,13 @@ impl AuthorityState { cursor: Option, limit: usize, descending: bool, - ) -> SuiResult> { + ) -> IotaResult> { let index_store = self.get_indexes()?; // Get the tx_num from tx_digest let (tx_num, event_num) = if let Some(cursor) = cursor.as_ref() { let tx_seq = index_store.get_transaction_seq(&cursor.tx_digest)?.ok_or( - SuiError::TransactionNotFound { + IotaError::TransactionNotFound { digest: cursor.tx_digest, }, )?; @@ -3748,7 +3752,7 @@ impl AuthorityState { if filters.is_empty() { index_store.all_events(tx_num, event_num, limit, descending)? } else { - return Err(SuiError::UserInputError { + return Err(IotaError::UserInputError { error: UserInputError::Unsupported( "This query type does not currently support filter combinations" .to_string(), @@ -3793,7 +3797,7 @@ impl AuthorityState { | EventFilter::Any(_) | EventFilter::And(_, _) | EventFilter::Or(_, _) => { - return Err(SuiError::UserInputError { + return Err(IotaError::UserInputError { error: UserInputError::Unsupported( "This query type is not supported by the full node.".to_string(), ), @@ -3838,7 +3842,7 @@ impl AuthorityState { .map(|((digest, tx_digest, event_seq, timestamp), event)| { event .map(|e| (e, tx_digest, event_seq, timestamp)) - .ok_or(SuiError::TransactionEventsNotFound { digest }) + .ok_or(IotaError::TransactionEventsNotFound { digest }) }) .collect::, _>>()?; @@ -3849,7 +3853,7 @@ impl AuthorityState { .type_layout_resolver(Box::new(backing_store)); let mut events = vec![]; for (e, tx_digest, event_seq, timestamp) in stored_events.into_iter() { - events.push(SuiEvent::try_from( + events.push(IotaEvent::try_from( e.clone(), tx_digest, event_seq as u64, @@ -3881,7 +3885,7 @@ impl AuthorityState { &self, transaction_digest: &TransactionDigest, epoch_store: &Arc, - ) -> SuiResult> { + ) -> IotaResult> { // TODO: In the case of read path, we should not have to re-sign the effects. if let Some(effects) = self.get_signed_effects_and_maybe_resign(transaction_digest, epoch_store)? @@ -3925,7 +3929,7 @@ impl AuthorityState { &self, transaction_digest: &TransactionDigest, epoch_store: &Arc, - ) -> SuiResult> { + ) -> IotaResult> { let effects = self .execution_cache .get_executed_effects(transaction_digest)?; @@ -3940,7 +3944,7 @@ impl AuthorityState { &self, effects: TransactionEffects, epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { let tx_digest = *effects.transaction_digest(); let signed_effects = match epoch_store.get_effects_signature(&tx_digest)? { Some(sig) if sig.epoch == epoch_store.epoch() => { @@ -4049,11 +4053,11 @@ impl AuthorityState { &self, object_ref: &ObjectRef, epoch_store: &AuthorityPerEpochStore, - ) -> SuiResult> { + ) -> IotaResult> { let lock_info = self .execution_cache .get_lock(*object_ref, epoch_store) - .map_err(SuiError::from)?; + .map_err(IotaError::from)?; let lock_info = match lock_info { ObjectLockStatus::LockedAtDifferentVersion { locked_ref } => { return Err(UserInputError::ObjectVersionUnavailableForConsumption { @@ -4071,14 +4075,14 @@ impl AuthorityState { epoch_store.get_signed_transaction(&lock_info.tx_digest) } - pub async fn get_objects(&self, objects: &[ObjectID]) -> SuiResult>> { + pub async fn get_objects(&self, objects: &[ObjectID]) -> IotaResult>> { self.execution_cache.get_objects(objects) } pub async fn get_object_or_tombstone( &self, object_id: ObjectID, - ) -> SuiResult> { + ) -> IotaResult> { self.execution_cache .get_latest_object_ref_or_tombstone(object_id) } @@ -4096,11 +4100,11 @@ impl AuthorityState { &self, expected_epoch: EpochId, buffer_stake_bps: u64, - ) -> SuiResult { + ) -> IotaResult { let epoch_store = self.load_epoch_store_one_call_per_task(); let actual_epoch = epoch_store.epoch(); if actual_epoch != expected_epoch { - return Err(SuiError::WrongEpoch { + return Err(IotaError::WrongEpoch { expected_epoch, actual_epoch, }); @@ -4112,11 +4116,11 @@ impl AuthorityState { pub fn clear_override_protocol_upgrade_buffer_stake( &self, expected_epoch: EpochId, - ) -> SuiResult { + ) -> IotaResult { let epoch_store = self.load_epoch_store_one_call_per_task(); let actual_epoch = epoch_store.epoch(); if actual_epoch != expected_epoch { - return Err(SuiError::WrongEpoch { + return Err(IotaError::WrongEpoch { expected_epoch, actual_epoch, }); @@ -4149,7 +4153,7 @@ impl AuthorityState { let modules = framework_injection::get_override_modules(system_package.id(), self.name) .unwrap_or(modules); - let Some(obj_ref) = sui_framework::compare_system_package( + let Some(obj_ref) = iota_framework::compare_system_package( &self.execution_cache, system_package.id(), &modules, @@ -4451,7 +4455,7 @@ impl AuthorityState { gas_cost_summary: &GasCostSummary, checkpoint: CheckpointSequenceNumber, epoch_start_timestamp_ms: CheckpointTimestamp, - ) -> anyhow::Result<(SuiSystemState, TransactionEffects)> { + ) -> anyhow::Result<(IotaSystemState, TransactionEffects)> { let mut txns = Vec::new(); if let Some(tx) = self.create_authenticator_state_tx(epoch_store) { @@ -4592,7 +4596,7 @@ impl AuthorityState { let (temporary_store, effects, _execution_error_opt) = self.prepare_certificate(&execution_guard, &executable_tx, input_objects, epoch_store)?; - let system_obj = get_sui_system_state(&temporary_store.written) + let system_obj = get_iota_system_state(&temporary_store.written) .expect("change epoch tx must write to system object"); // We must write tx and effects to the state sync tables so that state sync is @@ -4622,7 +4626,7 @@ impl AuthorityState { async fn revert_uncommitted_epoch_transactions( &self, epoch_store: &AuthorityPerEpochStore, - ) -> SuiResult { + ) -> IotaResult { { let state = epoch_store.get_reconfig_state_write_lock_guard(); if state.should_accept_user_certs() { @@ -4661,10 +4665,10 @@ impl AuthorityState { fn check_coin_deny( &self, - sender: SuiAddress, + sender: IotaAddress, input_objects: &CheckedInputObjects, receiving_objects: &ReceivingObjects, - ) -> SuiResult { + ) -> IotaResult { let all_objects = input_objects .inner() .iter_objects() @@ -4690,7 +4694,7 @@ impl AuthorityState { new_committee: Committee, epoch_start_configuration: EpochStartConfiguration, expensive_safety_check_config: &ExpensiveSafetyCheckConfig, - ) -> SuiResult> { + ) -> IotaResult> { let new_epoch = new_committee.epoch; info!(new_epoch = ?new_epoch, "re-opening AuthorityEpochTables for new epoch"); assert_eq!( @@ -4741,7 +4745,7 @@ impl AuthorityState { /// NOTE: this function is only to be used for fuzzing and testing. Never /// use in prod - pub async fn insert_objects_unsafe_for_testing_only(&self, objects: &[Object]) -> SuiResult { + pub async fn insert_objects_unsafe_for_testing_only(&self, objects: &[Object]) -> IotaResult { self.execution_cache.bulk_insert_genesis_objects(objects)?; self.execution_cache .force_reload_system_packages(&BuiltInFramework::all_package_ids()); @@ -4850,7 +4854,7 @@ impl TransactionKeyValueStoreTrait for AuthorityState { transactions: &[TransactionDigest], effects: &[TransactionDigest], events: &[TransactionEventsDigest], - ) -> SuiResult<( + ) -> IotaResult<( Vec>, Vec>, Vec>, @@ -4886,7 +4890,7 @@ impl TransactionKeyValueStoreTrait for AuthorityState { checkpoint_contents: &[CheckpointSequenceNumber], checkpoint_summaries_by_digest: &[CheckpointDigest], checkpoint_contents_by_digest: &[CheckpointContentsDigest], - ) -> SuiResult<( + ) -> IotaResult<( Vec>, Vec>, Vec>, @@ -4935,7 +4939,7 @@ impl TransactionKeyValueStoreTrait for AuthorityState { async fn deprecated_get_transaction_checkpoint( &self, digest: TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { self.execution_cache .deprecated_get_transaction_checkpoint(&digest) .map(|res| res.map(|(_epoch, checkpoint)| checkpoint)) @@ -4945,7 +4949,7 @@ impl TransactionKeyValueStoreTrait for AuthorityState { &self, object_id: ObjectID, version: VersionNumber, - ) -> SuiResult> { + ) -> IotaResult> { self.execution_cache .get_object_by_key(&object_id, version) .map_err(Into::into) @@ -4954,7 +4958,7 @@ impl TransactionKeyValueStoreTrait for AuthorityState { async fn multi_get_transaction_checkpoint( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { let res = self .execution_cache .deprecated_multi_get_transaction_checkpoint(digests)?; @@ -4973,12 +4977,12 @@ pub mod framework_injection { collections::{BTreeMap, BTreeSet}, }; - use move_binary_format::CompiledModule; - use sui_framework::{BuiltInFramework, SystemPackage}; - use sui_types::{ + use iota_framework::{BuiltInFramework, SystemPackage}; + use iota_types::{ base_types::{AuthorityName, ObjectID}, is_system_package, }; + use move_binary_format::CompiledModule; type FrameworkOverrideConfig = BTreeMap; @@ -5135,7 +5139,7 @@ impl NodeStateDump { epoch_store: &Arc, inner_temporary_store: &InnerTemporaryStore, certificate: &VerifiedExecutableTransaction, - ) -> SuiResult { + ) -> IotaResult { // Epoch info let executed_epoch = epoch_store.epoch(); let reference_gas_price = epoch_store.reference_gas_price(); diff --git a/crates/sui-core/src/authority/authority_notify_read.rs b/crates/iota-core/src/authority/authority_notify_read.rs similarity index 80% rename from crates/sui-core/src/authority/authority_notify_read.rs rename to crates/iota-core/src/authority/authority_notify_read.rs index 4804593b6be..11a1ac8f08a 100644 --- a/crates/sui-core/src/authority/authority_notify_read.rs +++ b/crates/iota-core/src/authority/authority_notify_read.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_trait::async_trait; -use sui_types::{ +use iota_types::{ base_types::{TransactionDigest, TransactionEffectsDigest}, effects::TransactionEffects, - error::SuiResult, + error::IotaResult, }; #[async_trait] @@ -20,15 +21,15 @@ pub trait EffectsNotifyRead: Send + Sync + 'static { async fn notify_read_executed_effects( &self, digests: Vec, - ) -> SuiResult>; + ) -> IotaResult>; async fn notify_read_executed_effects_digests( &self, digests: Vec, - ) -> SuiResult>; + ) -> IotaResult>; fn multi_get_executed_effects( &self, digests: &[TransactionDigest], - ) -> SuiResult>>; + ) -> IotaResult>>; } diff --git a/crates/sui-core/src/authority/authority_per_epoch_store.rs b/crates/iota-core/src/authority/authority_per_epoch_store.rs similarity index 96% rename from crates/sui-core/src/authority/authority_per_epoch_store.rs rename to crates/iota-core/src/authority/authority_per_epoch_store.rs index 1e3ef6a9f21..4924e09923d 100644 --- a/crates/sui-core/src/authority/authority_per_epoch_store.rs +++ b/crates/iota-core/src/authority/authority_per_epoch_store.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -21,22 +22,12 @@ use futures::{ future::{join_all, select, Either}, FutureExt, }; -use itertools::{izip, Itertools}; -use move_bytecode_utils::module_cache::SyncModuleCache; -use mysten_common::sync::{notify_once::NotifyOnce, notify_read::NotifyRead}; -use mysten_metrics::monitored_scope; -use narwhal_executor::ExecutionIndices; -use narwhal_types::{Round, TimestampMs}; -use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use prometheus::IntCounter; -use rocksdb::Options; -use serde::{Deserialize, Serialize}; -use sui_config::node::ExpensiveSafetyCheckConfig; -use sui_execution::{self, Executor}; -use sui_macros::fail_point; -use sui_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; -use sui_storage::mutex_table::{MutexGuard, MutexTable}; -use sui_types::{ +use iota_config::node::ExpensiveSafetyCheckConfig; +use iota_execution::{self, Executor}; +use iota_macros::fail_point; +use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; +use iota_storage::mutex_table::{MutexGuard, MutexTable}; +use iota_types::{ accumulator::Accumulator, authenticator_state::{get_authenticator_state, ActiveJwk}, base_types::{ @@ -47,8 +38,11 @@ use sui_types::{ crypto::{AuthoritySignInfo, AuthorityStrongQuorumSignInfo, RandomnessRound}, digests::ChainIdentifier, effects::TransactionEffects, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, executable_transaction::{TrustedExecutableTransaction, VerifiedExecutableTransaction}, + iota_system_state::epoch_start_iota_system_state::{ + EpochStartSystemState, EpochStartSystemStateTrait, + }, message_envelope::TrustedEnvelope, messages_checkpoint::{ CheckpointContents, CheckpointSequenceNumber, CheckpointSignatureMessage, CheckpointSummary, @@ -59,15 +53,22 @@ use sui_types::{ }, signature::GenericSignature, storage::{GetSharedLocks, InputKey}, - sui_system_state::epoch_start_sui_system_state::{ - EpochStartSystemState, EpochStartSystemStateTrait, - }, transaction::{ AuthenticatorStateUpdate, CertifiedTransaction, InputObjectKind, SenderSignedData, Transaction, TransactionDataAPI, TransactionKey, TransactionKind, VerifiedCertificate, VerifiedSignedTransaction, VerifiedTransaction, }, }; +use itertools::{izip, Itertools}; +use move_bytecode_utils::module_cache::SyncModuleCache; +use mysten_common::sync::{notify_once::NotifyOnce, notify_read::NotifyRead}; +use mysten_metrics::monitored_scope; +use narwhal_executor::ExecutionIndices; +use narwhal_types::{Round, TimestampMs}; +use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use prometheus::IntCounter; +use rocksdb::Options; +use serde::{Deserialize, Serialize}; use tap::TapOptional; use tokio::{sync::OnceCell, time::Instant}; use tracing::{debug, error, info, instrument, trace, warn}; @@ -145,7 +146,7 @@ pub enum ConsensusCertificateResult { /// processed). Ignored, /// An executable transaction (can be a user tx or a system tx) - SuiTransaction(VerifiedExecutableTransaction), + IotaTransaction(VerifiedExecutableTransaction), /// The transaction should be re-processed at a future commit, specified by /// the DeferralKey Deferred(DeferralKey), @@ -691,7 +692,7 @@ impl AuthorityEpochTables { parent_path.join(format!("{}{}", EPOCH_DB_PREFIX, epoch)) } - fn load_reconfig_state(&self) -> SuiResult { + fn load_reconfig_state(&self) -> IotaResult { let state = self .reconfig_state .get(&RECONFIG_STATE_INDEX)? @@ -706,7 +707,7 @@ impl AuthorityEpochTables { .collect() } - pub fn reset_db_for_execution_since_genesis(&self) -> SuiResult { + pub fn reset_db_for_execution_since_genesis(&self) -> IotaResult { // TODO: Add new tables that get added to the db automatically self.executed_transactions_to_checkpoint.unsafe_clear()?; Ok(()) @@ -715,16 +716,16 @@ impl AuthorityEpochTables { /// WARNING: This method is very subtle and can corrupt the database if used /// incorrectly. It should only be used in one-off cases or tests after /// fully understanding the risk. - pub fn remove_executed_tx_subtle(&self, digest: &TransactionDigest) -> SuiResult { + pub fn remove_executed_tx_subtle(&self, digest: &TransactionDigest) -> IotaResult { self.executed_transactions_to_checkpoint.remove(digest)?; Ok(()) } - pub fn get_last_consensus_index(&self) -> SuiResult> { + pub fn get_last_consensus_index(&self) -> IotaResult> { Ok(self.last_consensus_index.get(&LAST_CONSENSUS_STATS_ADDR)?) } - pub fn get_last_consensus_stats(&self) -> SuiResult> { + pub fn get_last_consensus_stats(&self) -> IotaResult> { Ok(self.last_consensus_stats.get(&LAST_CONSENSUS_STATS_ADDR)?) } @@ -732,7 +733,7 @@ impl AuthorityEpochTables { &self, checkpoint_seq: CheckpointSequenceNumber, starting_index: u64, - ) -> SuiResult< + ) -> IotaResult< impl Iterator + '_, > { let key = (checkpoint_seq, starting_index); @@ -741,10 +742,10 @@ impl AuthorityEpochTables { .pending_checkpoint_signatures .unbounded_iter() .skip_to(&key)?; - Ok::<_, SuiError>(iter) + Ok::<_, IotaError>(iter) } - pub fn get_locked_transaction(&self, obj_ref: &ObjectRef) -> SuiResult> { + pub fn get_locked_transaction(&self, obj_ref: &ObjectRef) -> IotaResult> { Ok(self .owned_object_locked_transactions .get(obj_ref)? @@ -754,7 +755,7 @@ impl AuthorityEpochTables { pub fn multi_get_locked_transactions( &self, owned_input_objects: &[ObjectRef], - ) -> SuiResult>> { + ) -> IotaResult>> { Ok(self .owned_object_locked_transactions .multi_get(owned_input_objects)? @@ -767,7 +768,7 @@ impl AuthorityEpochTables { &self, transaction: VerifiedSignedTransaction, locks_to_write: impl IntoIterator, - ) -> SuiResult { + ) -> IotaResult { let mut batch = self.owned_object_locked_transactions.batch(); batch.insert_batch( &self.owned_object_locked_transactions, @@ -936,10 +937,10 @@ impl AuthorityPerEpochStore { s } - pub fn tables(&self) -> SuiResult> { + pub fn tables(&self) -> IotaResult> { match self.tables.load_full() { Some(tables) => Ok(tables), - None => Err(SuiError::EpochEnded), + None => Err(IotaError::EpochEnded), } } @@ -980,7 +981,7 @@ impl AuthorityPerEpochStore { pub fn set_randomness_manager( &self, mut randomness_manager: RandomnessManager, - ) -> SuiResult<()> { + ) -> IotaResult<()> { let reporter = randomness_manager.reporter(); let result = randomness_manager.start_dkg(); if self @@ -1067,7 +1068,7 @@ impl AuthorityPerEpochStore { pub fn get_state_hash_for_checkpoint( &self, checkpoint: &CheckpointSequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self.tables()?.state_hash_by_checkpoint.get(checkpoint)?) } @@ -1075,7 +1076,7 @@ impl AuthorityPerEpochStore { &self, checkpoint: &CheckpointSequenceNumber, accumulator: &Accumulator, - ) -> SuiResult { + ) -> IotaResult { Ok(self .tables()? .state_hash_by_checkpoint @@ -1101,7 +1102,7 @@ impl AuthorityPerEpochStore { pub async fn acquire_tx_guard( &self, cert: &VerifiedExecutableTransaction, - ) -> SuiResult { + ) -> IotaResult { let digest = cert.digest(); Ok(CertTxGuard(self.acquire_tx_lock(digest).await)) } @@ -1111,7 +1112,7 @@ impl AuthorityPerEpochStore { CertLockGuard(self.mutex_table.acquire_lock(*digest).await) } - pub fn store_reconfig_state(&self, new_state: &ReconfigState) -> SuiResult { + pub fn store_reconfig_state(&self, new_state: &ReconfigState) -> IotaResult { self.tables()? .reconfig_state .insert(&RECONFIG_STATE_INDEX, new_state)?; @@ -1122,7 +1123,7 @@ impl AuthorityPerEpochStore { &self, new_state: &ReconfigState, batch: &mut DBBatch, - ) -> SuiResult { + ) -> IotaResult { batch.insert_batch( &self.tables()?.reconfig_state, [(&RECONFIG_STATE_INDEX, new_state)], @@ -1130,7 +1131,7 @@ impl AuthorityPerEpochStore { Ok(()) } - pub fn insert_signed_transaction(&self, transaction: VerifiedSignedTransaction) -> SuiResult { + pub fn insert_signed_transaction(&self, transaction: VerifiedSignedTransaction) -> IotaResult { Ok(self .tables()? .signed_transactions @@ -1160,7 +1161,7 @@ impl AuthorityPerEpochStore { pub fn get_signed_transaction( &self, tx_digest: &TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self .tables()? .signed_transactions @@ -1175,7 +1176,7 @@ impl AuthorityPerEpochStore { tx_digest: &TransactionDigest, cert_sig: Option<&AuthorityStrongQuorumSignInfo>, effects_signature: Option<&AuthoritySignInfo>, - ) -> SuiResult { + ) -> IotaResult { let mut batch = self.tables()?.effects_signatures.batch(); if let Some(cert_sig) = cert_sig { batch.insert_batch( @@ -1206,7 +1207,7 @@ impl AuthorityPerEpochStore { pub fn effects_signatures_exists<'a>( &self, digests: impl IntoIterator, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self .tables()? .effects_signatures @@ -1216,14 +1217,14 @@ impl AuthorityPerEpochStore { pub fn get_effects_signature( &self, tx_digest: &TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self.tables()?.effects_signatures.get(tx_digest)?) } pub fn get_transaction_cert_sig( &self, tx_digest: &TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self.tables()?.transaction_cert_signatures.get(tx_digest)?) } @@ -1271,18 +1272,18 @@ impl AuthorityPerEpochStore { .collect() } - pub fn get_last_consensus_index(&self) -> SuiResult { + pub fn get_last_consensus_index(&self) -> IotaResult { self.tables()? .get_last_consensus_index() .map(|x| x.unwrap_or_default()) - .map_err(SuiError::from) + .map_err(IotaError::from) } - pub fn get_last_consensus_stats(&self) -> SuiResult { + pub fn get_last_consensus_stats(&self) -> IotaResult { match self .tables()? .get_last_consensus_stats() - .map_err(SuiError::from)? + .map_err(IotaError::from)? { Some(stats) => Ok(stats), // TODO: stop reading from last_consensus_index after rollout. @@ -1291,7 +1292,7 @@ impl AuthorityPerEpochStore { .tables()? .get_last_consensus_index() .map(|x| x.unwrap_or_default()) - .map_err(SuiError::from)?; + .map_err(IotaError::from)?; Ok(ExecutionIndicesWithStats { index: indices.index, hash: indices.hash, @@ -1305,7 +1306,7 @@ impl AuthorityPerEpochStore { &self, from_checkpoint: CheckpointSequenceNumber, to_checkpoint: CheckpointSequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { self.tables()? .state_hash_by_checkpoint .safe_range_iter(from_checkpoint..=to_checkpoint) @@ -1318,7 +1319,7 @@ impl AuthorityPerEpochStore { pub async fn notify_read_checkpoint_state_digests( &self, checkpoints: Vec, - ) -> SuiResult> { + ) -> IotaResult> { // We need to register waiters _before_ reading from the database to avoid // race conditions let registrations = self.checkpoint_state_notify_read.register_all(&checkpoints); @@ -1346,7 +1347,7 @@ impl AuthorityPerEpochStore { /// TransactionManager. /// Gets all pending certificates. Used during recovery. - pub fn all_pending_execution(&self) -> SuiResult> { + pub fn all_pending_execution(&self) -> IotaResult> { Ok(self .tables()? .pending_execution @@ -1357,7 +1358,7 @@ impl AuthorityPerEpochStore { /// Deletes one pending certificate. #[instrument(level = "trace", skip_all)] - pub fn remove_pending_execution(&self, digest: &TransactionDigest) -> SuiResult<()> { + pub fn remove_pending_execution(&self, digest: &TransactionDigest) -> IotaResult<()> { self.tables()?.pending_execution.remove(digest)?; Ok(()) } @@ -1381,7 +1382,7 @@ impl AuthorityPerEpochStore { &self, tx_digest: &TransactionDigest, assigned_versions: &Vec<(ObjectID, SequenceNumber)>, - ) -> SuiResult { + ) -> IotaResult { if self.randomness_state_enabled() { self.tables()? .assigned_shared_object_versions_v2 @@ -1398,7 +1399,7 @@ impl AuthorityPerEpochStore { &self, digests: &[TransactionDigest], sequence: CheckpointSequenceNumber, - ) -> SuiResult { + ) -> IotaResult { let mut batch = self.tables()?.executed_transactions_to_checkpoint.batch(); batch.insert_batch( &self.tables()?.executed_transactions_to_checkpoint, @@ -1412,7 +1413,7 @@ impl AuthorityPerEpochStore { pub fn is_transaction_executed_in_checkpoint( &self, digest: &TransactionDigest, - ) -> SuiResult { + ) -> IotaResult { Ok(self .tables()? .executed_transactions_to_checkpoint @@ -1422,7 +1423,7 @@ impl AuthorityPerEpochStore { pub fn get_transaction_checkpoint( &self, digest: &TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self .tables()? .executed_transactions_to_checkpoint @@ -1432,7 +1433,7 @@ impl AuthorityPerEpochStore { pub fn multi_get_transaction_checkpoint( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { Ok(self .tables()? .executed_transactions_to_checkpoint @@ -1472,7 +1473,7 @@ impl AuthorityPerEpochStore { &self, objects_to_init: &[(ObjectID, SequenceNumber)], cache_reader: &dyn ExecutionCacheRead, - ) -> SuiResult> { + ) -> IotaResult> { let mut ret: HashMap<_, _>; // Since this can be called from consensus task, we must retry forever - the // only other option is to panic. It is extremely unlikely that more @@ -1544,7 +1545,7 @@ impl AuthorityPerEpochStore { &self, versions: AssignedTxAndVersions, db_batch: &mut DBBatch, - ) -> SuiResult { + ) -> IotaResult { debug!("set_assigned_shared_object_versions: {:?}", versions); if self.randomness_state_enabled() { @@ -1565,7 +1566,7 @@ impl AuthorityPerEpochStore { batch: &mut DBBatch, key: DeferralKey, transactions: Vec, - ) -> SuiResult { + ) -> IotaResult { batch.insert_batch( &self.tables()?.deferred_transactions, std::iter::once((key, transactions)), @@ -1576,7 +1577,7 @@ impl AuthorityPerEpochStore { fn load_deferred_transactions_for_randomness( &self, batch: &mut DBBatch, - ) -> SuiResult> { + ) -> IotaResult> { let (min, max) = DeferralKey::full_range_for_randomness(); self.load_deferred_transactions(batch, min, max) } @@ -1585,7 +1586,7 @@ impl AuthorityPerEpochStore { &self, batch: &mut DBBatch, consensus_round: u64, - ) -> SuiResult> { + ) -> IotaResult> { let (min, max) = DeferralKey::range_for_consensus_round(consensus_round); self.load_deferred_transactions(batch, min, max) } @@ -1596,7 +1597,7 @@ impl AuthorityPerEpochStore { batch: &mut DBBatch, min: DeferralKey, max: DeferralKey, - ) -> SuiResult> { + ) -> IotaResult> { let mut keys = Vec::new(); let mut txns = Vec::new(); self.tables()? @@ -1657,7 +1658,7 @@ impl AuthorityPerEpochStore { certificate: &VerifiedExecutableTransaction, effects: &TransactionEffects, cache_reader: &dyn ExecutionCacheRead, - ) -> SuiResult { + ) -> IotaResult { let versions = SharedObjVerManager::assign_versions_from_effects( &[(certificate, effects)], self, @@ -1677,7 +1678,7 @@ impl AuthorityPerEpochStore { &self, transaction: &ConsensusTransaction, lock: Option<&RwLockReadGuard>, - ) -> SuiResult { + ) -> IotaResult { self.tables()? .pending_consensus_transactions .insert(&transaction.key(), transaction)?; @@ -1695,7 +1696,10 @@ impl AuthorityPerEpochStore { Ok(()) } - pub fn remove_pending_consensus_transaction(&self, key: &ConsensusTransactionKey) -> SuiResult { + pub fn remove_pending_consensus_transaction( + &self, + key: &ConsensusTransactionKey, + ) -> IotaResult { self.tables()?.pending_consensus_transactions.remove(key)?; if let ConsensusTransactionKey::Certificate(cert) = key { self.pending_consensus_certificates.lock().remove(cert); @@ -1726,7 +1730,7 @@ impl AuthorityPerEpochStore { pub fn insert_pending_execution( &self, certs: &[TrustedExecutableTransaction], - ) -> SuiResult<()> { + ) -> IotaResult<()> { let mut batch = self.tables()?.pending_execution.batch(); batch.insert_batch( &self.tables()?.pending_execution, @@ -1744,7 +1748,7 @@ impl AuthorityPerEpochStore { pub fn is_tx_cert_consensus_message_processed( &self, certificate: &CertifiedTransaction, - ) -> SuiResult { + ) -> IotaResult { self.is_consensus_message_processed(&SequencedConsensusTransactionKey::External( ConsensusTransactionKey::Certificate(*certificate.digest()), )) @@ -1753,7 +1757,7 @@ impl AuthorityPerEpochStore { pub fn is_consensus_message_processed( &self, key: &SequencedConsensusTransactionKey, - ) -> SuiResult { + ) -> IotaResult { Ok(self .tables()? .consensus_message_processed @@ -1763,7 +1767,7 @@ impl AuthorityPerEpochStore { pub async fn consensus_message_processed_notify( &self, key: SequencedConsensusTransactionKey, - ) -> Result<(), SuiError> { + ) -> Result<(), IotaError> { let registration = self.consensus_notify_read.register_one(&key); if self.is_consensus_message_processed(&key)? { return Ok(()); @@ -1775,7 +1779,7 @@ impl AuthorityPerEpochStore { pub fn check_consensus_messages_processed<'a>( &self, keys: impl Iterator, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self .tables()? .consensus_message_processed @@ -1785,7 +1789,7 @@ impl AuthorityPerEpochStore { pub async fn consensus_messages_processed_notify( &self, keys: Vec, - ) -> Result<(), SuiError> { + ) -> Result<(), IotaError> { let registrations = self.consensus_notify_read.register_all(&keys); let unprocessed_keys_registrations = registrations @@ -1798,7 +1802,7 @@ impl AuthorityPerEpochStore { Ok(()) } - pub fn has_sent_end_of_publish(&self, authority: &AuthorityName) -> SuiResult { + pub fn has_sent_end_of_publish(&self, authority: &AuthorityName) -> IotaResult { Ok(self .end_of_publish .try_lock() @@ -1811,7 +1815,7 @@ impl AuthorityPerEpochStore { pub async fn notify_read_executed_digests( &self, keys: &[TransactionKey], - ) -> SuiResult> { + ) -> IotaResult> { let non_digest_keys: Vec<_> = keys .iter() .filter_map(|key| { @@ -1860,7 +1864,7 @@ impl AuthorityPerEpochStore { &self, transactions: &[VerifiedTransaction], digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { assert_eq!(transactions.len(), digests.len()); let signatures = self .tables()? @@ -1879,7 +1883,7 @@ impl AuthorityPerEpochStore { // so we can just pull it from the transaction. transaction.tx_signatures().to_vec() } else { - return Err(SuiError::from( + return Err(IotaError::from( format!( "Can not find user signature for checkpoint for transaction {:?}", transaction.key() @@ -1892,7 +1896,7 @@ impl AuthorityPerEpochStore { Ok(result) } - pub fn clear_override_protocol_upgrade_buffer_stake(&self) -> SuiResult { + pub fn clear_override_protocol_upgrade_buffer_stake(&self) -> IotaResult { warn!( epoch = ?self.epoch(), "clearing buffer_stake_for_protocol_upgrade_bps override" @@ -1904,7 +1908,7 @@ impl AuthorityPerEpochStore { Ok(()) } - pub fn set_override_protocol_upgrade_buffer_stake(&self, new_stake_bps: u64) -> SuiResult { + pub fn set_override_protocol_upgrade_buffer_stake(&self, new_stake_bps: u64) -> IotaResult { warn!( ?new_stake_bps, epoch = ?self.epoch(), @@ -1940,7 +1944,7 @@ impl AuthorityPerEpochStore { } /// Record most recently advertised capabilities of all authorities - pub fn record_capabilities(&self, capabilities: &AuthorityCapabilities) -> SuiResult { + pub fn record_capabilities(&self, capabilities: &AuthorityCapabilities) -> IotaResult { info!("received capabilities {:?}", capabilities); let authority = &capabilities.authority; @@ -1961,7 +1965,7 @@ impl AuthorityPerEpochStore { Ok(()) } - pub fn get_capabilities(&self) -> SuiResult> { + pub fn get_capabilities(&self) -> IotaResult> { let result: Result, TypedStoreError> = self .tables()? .authority_capabilities @@ -1978,7 +1982,7 @@ impl AuthorityPerEpochStore { authority: AuthorityName, id: &JwkId, jwk: &JWK, - ) -> SuiResult { + ) -> IotaResult { info!( "received jwk vote from {:?} for jwk ({:?}, {:?})", authority.concise(), @@ -2029,7 +2033,7 @@ impl AuthorityPerEpochStore { Ok(()) } - pub(crate) fn get_new_jwks(&self, round: u64) -> SuiResult> { + pub(crate) fn get_new_jwks(&self, round: u64) -> IotaResult> { let epoch = self.epoch(); let empty_jwk_id = JwkId::new(String::new(), String::new()); @@ -2065,7 +2069,7 @@ impl AuthorityPerEpochStore { &self, batch: &mut DBBatch, key: SequencedConsensusTransactionKey, - ) -> SuiResult { + ) -> IotaResult { batch.insert_batch(&self.tables()?.consensus_message_processed, [(key, true)])?; Ok(()) } @@ -2075,7 +2079,7 @@ impl AuthorityPerEpochStore { &self, batch: &mut DBBatch, consensus_stats: &ExecutionIndicesWithStats, - ) -> SuiResult { + ) -> IotaResult { // TODO: remove writing to last_consensus_index. batch.insert_batch( &self.tables()?.last_consensus_index, @@ -2118,7 +2122,7 @@ impl AuthorityPerEpochStore { &self, batch: &mut DBBatch, certificates: &[VerifiedExecutableTransaction], - ) -> SuiResult { + ) -> IotaResult { for certificate in certificates { batch.insert_batch( &self.tables()?.pending_execution, @@ -2212,7 +2216,7 @@ impl AuthorityPerEpochStore { } #[instrument(level = "trace", skip_all)] - pub fn verify_transaction(&self, tx: Transaction) -> SuiResult { + pub fn verify_transaction(&self, tx: Transaction) -> IotaResult { self.signature_verifier .verify_tx(tx.data()) .map(|_| VerifiedTransaction::new_from_verified(tx)) @@ -2243,7 +2247,7 @@ impl AuthorityPerEpochStore { return None; } // Signatures are verified as part of narwhal payload verification in - // SuiTxValidator + // IotaTxValidator match &transaction.transaction { SequencedConsensusTransactionKind::External(ConsensusTransaction { kind: ConsensusTransactionKind::UserTransaction(_certificate), @@ -2338,7 +2342,7 @@ impl AuthorityPerEpochStore { Some(VerifiedSequencedConsensusTransaction(transaction)) } - fn db_batch(&self) -> SuiResult { + fn db_batch(&self) -> IotaResult { Ok(self.tables()?.last_consensus_index.batch()) } @@ -2361,7 +2365,7 @@ impl AuthorityPerEpochStore { commit_round: Round, commit_timestamp: TimestampMs, skipped_consensus_txns: &IntCounter, - ) -> SuiResult> { + ) -> IotaResult> { // Split transactions into different types for processing. let verified_transactions: Vec<_> = transactions .into_iter() @@ -2626,7 +2630,7 @@ impl AuthorityPerEpochStore { transactions: &[VerifiedExecutableTransaction], randomness_round: Option, db_batch: &mut DBBatch, - ) -> SuiResult { + ) -> IotaResult { let ConsensusSharedObjVerAssignment { shared_input_next_versions, assigned_versions, @@ -2680,7 +2684,7 @@ impl AuthorityPerEpochStore { checkpoint_service: &Arc, cache_reader: &dyn ExecutionCacheRead, skipped_consensus_txns: &IntCounter, - ) -> SuiResult> { + ) -> IotaResult> { self.process_consensus_transactions_and_commit_boundary( transactions, &ExecutionIndicesWithStats::default(), @@ -2726,7 +2730,7 @@ impl AuthorityPerEpochStore { mut randomness_manager: Option<&mut RandomnessManager>, dkg_closed: bool, generate_randomness: bool, - ) -> SuiResult<( + ) -> IotaResult<( Vec, // transactions to schedule Vec, // keys to notify as complete Vec, // roots of any deferred transactions @@ -2770,7 +2774,7 @@ impl AuthorityPerEpochStore { ) .await? { - ConsensusCertificateResult::SuiTransaction(cert) => { + ConsensusCertificateResult::IotaTransaction(cert) => { notifications.push(key.clone()); verified_certificates.push(cert); } @@ -2844,7 +2848,7 @@ impl AuthorityPerEpochStore { write_batch: &mut DBBatch, transactions: &[VerifiedSequencedConsensusTransaction], commit_has_deferred_txns: bool, - ) -> SuiResult<( + ) -> IotaResult<( Option>, bool, // true if final round )> { @@ -2958,7 +2962,7 @@ impl AuthorityPerEpochStore { mut randomness_manager: Option<&mut RandomnessManager>, dkg_closed: bool, generating_randomness: bool, - ) -> SuiResult { + ) -> IotaResult { let _scope = monitored_scope("HandleConsensusTransaction"); let VerifiedSequencedConsensusTransaction(SequencedConsensusTransaction { certificate_author_index: _, @@ -3000,7 +3004,7 @@ impl AuthorityPerEpochStore { return Ok(ConsensusCertificateResult::Ignored); } // Safe because signatures are verified when consensus called into - // SuiTxValidator::validate_batch. + // IotaTxValidator::validate_batch. let certificate = VerifiedCertificate::new_unchecked(*certificate.clone()); let certificate = VerifiedExecutableTransaction::new_from_certificate(certificate); @@ -3045,13 +3049,13 @@ impl AuthorityPerEpochStore { return Ok(ConsensusCertificateResult::Ignored); } - Ok(ConsensusCertificateResult::SuiTransaction(certificate)) + Ok(ConsensusCertificateResult::IotaTransaction(certificate)) } SequencedConsensusTransactionKind::External(ConsensusTransaction { kind: ConsensusTransactionKind::CheckpointSignature(info), .. }) => { - // We usually call notify_checkpoint_signature in SuiTxValidator, but that step + // We usually call notify_checkpoint_signature in IotaTxValidator, but that step // can be skipped when a batch is already part of a certificate, // so we must also notify here. checkpoint_service.notify_checkpoint_signature(self, info)?; @@ -3198,7 +3202,7 @@ impl AuthorityPerEpochStore { // If needed we can support owned object system transactions as well... assert!(system_transaction.contains_shared_object()); - Ok(ConsensusCertificateResult::SuiTransaction( + Ok(ConsensusCertificateResult::IotaTransaction( system_transaction.clone(), )) } @@ -3209,7 +3213,7 @@ impl AuthorityPerEpochStore { &self, batch: &mut DBBatch, checkpoint: &PendingCheckpointV2, - ) -> SuiResult { + ) -> IotaResult { if let Some(pending) = self.get_pending_checkpoint(&checkpoint.height())? { if pending.roots() != checkpoint.roots() { panic!( @@ -3254,7 +3258,7 @@ impl AuthorityPerEpochStore { pub fn get_pending_checkpoints( &self, last: Option, - ) -> SuiResult> { + ) -> IotaResult> { let tables = self.tables()?; if self.randomness_state_enabled() { let mut iter = tables.pending_checkpoints_v2.unbounded_iter(); @@ -3274,7 +3278,7 @@ impl AuthorityPerEpochStore { pub fn get_pending_checkpoint( &self, index: &CheckpointHeight, - ) -> SuiResult> { + ) -> IotaResult> { if self.randomness_state_enabled() { Ok(self.tables()?.pending_checkpoints_v2.get(index)?) } else { @@ -3290,7 +3294,7 @@ impl AuthorityPerEpochStore { &self, commit_height: CheckpointHeight, content_info: Vec<(CheckpointSummary, CheckpointContents)>, - ) -> SuiResult<()> { + ) -> IotaResult<()> { // All created checkpoints are inserted in builder_checkpoint_summary in a // single batch. This means that upon restart we can use // BuilderCheckpointSummary::commit_height from the last built summary @@ -3323,7 +3327,7 @@ impl AuthorityPerEpochStore { &self, summary: &CheckpointSummary, contents: &CheckpointContents, - ) -> SuiResult<()> { + ) -> IotaResult<()> { let sequence = summary.sequence_number; for transaction in contents.iter() { let digest = transaction.transaction; @@ -3346,7 +3350,7 @@ impl AuthorityPerEpochStore { Ok(()) } - pub fn last_built_checkpoint_commit_height(&self) -> SuiResult> { + pub fn last_built_checkpoint_commit_height(&self) -> IotaResult> { Ok(self .tables()? .builder_checkpoint_summary_v2 @@ -3358,7 +3362,7 @@ impl AuthorityPerEpochStore { pub fn last_built_checkpoint_summary( &self, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self .tables()? .builder_checkpoint_summary_v2 @@ -3371,7 +3375,7 @@ impl AuthorityPerEpochStore { pub fn get_built_checkpoint_summary( &self, sequence: CheckpointSequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self .tables()? .builder_checkpoint_summary_v2 @@ -3382,14 +3386,14 @@ impl AuthorityPerEpochStore { pub fn builder_included_transactions_in_checkpoint<'a>( &self, digests: impl Iterator, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self .tables()? .builder_digest_to_checkpoint .multi_contains_keys(digests)?) } - pub fn get_last_checkpoint_signature_index(&self) -> SuiResult { + pub fn get_last_checkpoint_signature_index(&self) -> IotaResult { Ok(self .tables()? .pending_checkpoint_signatures @@ -3405,7 +3409,7 @@ impl AuthorityPerEpochStore { checkpoint_seq: CheckpointSequenceNumber, index: u64, info: &CheckpointSignatureMessage, - ) -> SuiResult<()> { + ) -> IotaResult<()> { Ok(self .tables()? .pending_checkpoint_signatures @@ -3506,7 +3510,7 @@ impl GetSharedLocks for AuthorityPerEpochStore { fn get_shared_locks( &self, key: &TransactionKey, - ) -> Result, SuiError> { + ) -> Result, IotaError> { if self.randomness_state_enabled() { Ok(self .tables()? @@ -3532,7 +3536,7 @@ impl ExecutionComponents { _expensive_safety_check_config: &ExpensiveSafetyCheckConfig, ) -> Self { let silent = true; - let executor = sui_execution::executor(protocol_config, silent, None) + let executor = iota_execution::executor(protocol_config, silent, None) .expect("Creating an executor should not fail here"); let module_cache = Arc::new(SyncModuleCache::new(ResolverWrapper::new( diff --git a/crates/sui-core/src/authority/authority_per_epoch_store_pruner.rs b/crates/iota-core/src/authority/authority_per_epoch_store_pruner.rs similarity index 97% rename from crates/sui-core/src/authority/authority_per_epoch_store_pruner.rs rename to crates/iota-core/src/authority/authority_per_epoch_store_pruner.rs index f7e2e81da6b..61baa07425b 100644 --- a/crates/sui-core/src/authority/authority_per_epoch_store_pruner.rs +++ b/crates/iota-core/src/authority/authority_per_epoch_store_pruner.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fs, path::PathBuf, time::Duration}; +use iota_config::node::AuthorityStorePruningConfig; use itertools::Itertools; -use sui_config::node::AuthorityStorePruningConfig; use tokio::sync::oneshot; use tracing::log::{error, info}; use typed_store::rocks::safe_drop_db; diff --git a/crates/sui-core/src/authority/authority_store.rs b/crates/iota-core/src/authority/authority_store.rs similarity index 91% rename from crates/sui-core/src/authority/authority_store.rs rename to crates/iota-core/src/authority/authority_store.rs index 91cff85f1b5..7ef7ac28586 100644 --- a/crates/sui-core/src/authority/authority_store.rs +++ b/crates/iota-core/src/authority/authority_store.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{cmp::Ordering, iter, mem, ops::Not, sync::Arc, thread}; @@ -6,13 +7,9 @@ use std::{cmp::Ordering, iter, mem, ops::Not, sync::Arc, thread}; use either::Either; use fastcrypto::hash::{HashFunction, MultisetHash, Sha3_256}; use futures::stream::FuturesUnordered; -use itertools::izip; -use move_core_types::resolver::ModuleResolver; -use mysten_common::sync::notify_read::NotifyRead; -use serde::{Deserialize, Serialize}; -use sui_macros::fail_point_arg; -use sui_storage::mutex_table::{MutexGuard, MutexTable, RwLockGuard, RwLockTable}; -use sui_types::{ +use iota_macros::fail_point_arg; +use iota_storage::mutex_table::{MutexGuard, MutexTable, RwLockGuard, RwLockTable}; +use iota_types::{ accumulator::Accumulator, base_types::SequenceNumber, digests::TransactionEventsDigest, @@ -20,13 +17,17 @@ use sui_types::{ error::UserInputError, execution::TypeLayoutStore, fp_bail, fp_ensure, - gas_coin::TOTAL_SUPPLY_MIST, + gas_coin::TOTAL_SUPPLY_MICROS, + iota_system_state::get_iota_system_state, message_envelope::Message, storage::{ get_module, BackingPackageStore, MarkerValue, ObjectKey, ObjectOrTombstone, ObjectStore, }, - sui_system_state::get_sui_system_state, }; +use itertools::izip; +use move_core_types::resolver::ModuleResolver; +use mysten_common::sync::notify_read::NotifyRead; +use serde::{Deserialize, Serialize}; use tokio::{ sync::{RwLockReadGuard, RwLockWriteGuard}, time::Instant, @@ -58,45 +59,45 @@ use crate::{ const NUM_SHARDS: usize = 4096; struct AuthorityStoreMetrics { - sui_conservation_check_latency: IntGauge, - sui_conservation_live_object_count: IntGauge, - sui_conservation_live_object_size: IntGauge, - sui_conservation_imbalance: IntGauge, - sui_conservation_storage_fund: IntGauge, - sui_conservation_storage_fund_imbalance: IntGauge, + iota_conservation_check_latency: IntGauge, + iota_conservation_live_object_count: IntGauge, + iota_conservation_live_object_size: IntGauge, + iota_conservation_imbalance: IntGauge, + iota_conservation_storage_fund: IntGauge, + iota_conservation_storage_fund_imbalance: IntGauge, epoch_flags: IntGaugeVec, } impl AuthorityStoreMetrics { pub fn new(registry: &Registry) -> Self { Self { - sui_conservation_check_latency: register_int_gauge_with_registry!( - "sui_conservation_check_latency", - "Number of seconds took to scan all live objects in the store for SUI conservation check", + iota_conservation_check_latency: register_int_gauge_with_registry!( + "iota_conservation_check_latency", + "Number of seconds took to scan all live objects in the store for IOTA conservation check", registry, ).unwrap(), - sui_conservation_live_object_count: register_int_gauge_with_registry!( - "sui_conservation_live_object_count", + iota_conservation_live_object_count: register_int_gauge_with_registry!( + "iota_conservation_live_object_count", "Number of live objects in the store", registry, ).unwrap(), - sui_conservation_live_object_size: register_int_gauge_with_registry!( - "sui_conservation_live_object_size", + iota_conservation_live_object_size: register_int_gauge_with_registry!( + "iota_conservation_live_object_size", "Size in bytes of live objects in the store", registry, ).unwrap(), - sui_conservation_imbalance: register_int_gauge_with_registry!( - "sui_conservation_imbalance", - "Total amount of SUI in the network - 10B * 10^9. This delta shows the amount of imbalance", + iota_conservation_imbalance: register_int_gauge_with_registry!( + "iota_conservation_imbalance", + "Total amount of IOTA in the network - 10B * 10^9. This delta shows the amount of imbalance", registry, ).unwrap(), - sui_conservation_storage_fund: register_int_gauge_with_registry!( - "sui_conservation_storage_fund", + iota_conservation_storage_fund: register_int_gauge_with_registry!( + "iota_conservation_storage_fund", "Storage Fund pool balance (only includes the storage fund proper that represents object storage)", registry, ).unwrap(), - sui_conservation_storage_fund_imbalance: register_int_gauge_with_registry!( - "sui_conservation_storage_fund_imbalance", + iota_conservation_storage_fund_imbalance: register_int_gauge_with_registry!( + "iota_conservation_storage_fund_imbalance", "Imbalance of storage fund, computed with storage_fund_balance - total_object_storage_rebates", registry, ).unwrap(), @@ -113,9 +114,9 @@ impl AuthorityStoreMetrics { /// ALL_OBJ_VER determines whether we want to store all past /// versions of every object in the store. Authority doesn't store /// them, but other entities such as replicas will. -/// S is a template on Authority signature state. This allows SuiDataStore to be -/// used on either authorities or non-authorities. Specifically, when storing -/// transactions and effects, S allows SuiDataStore to either store the +/// S is a template on Authority signature state. This allows IotaDataStore to +/// be used on either authorities or non-authorities. Specifically, when storing +/// transactions and effects, S allows IotaDataStore to either store the /// authority signed version or unsigned version. pub struct AuthorityStore { /// Internal vector of locks to manage concurrent writes to the database @@ -130,8 +131,8 @@ pub struct AuthorityStore { indirect_objects_threshold: usize, - /// Whether to enable expensive SUI conservation check at epoch boundaries. - enable_epoch_sui_conservation_check: bool, + /// Whether to enable expensive IOTA conservation check at epoch boundaries. + enable_epoch_iota_conservation_check: bool, metrics: AuthorityStoreMetrics, } @@ -146,9 +147,9 @@ impl AuthorityStore { perpetual_tables: Arc, genesis: &Genesis, indirect_objects_threshold: usize, - enable_epoch_sui_conservation_check: bool, + enable_epoch_iota_conservation_check: bool, registry: &Registry, - ) -> SuiResult> { + ) -> IotaResult> { let epoch_start_configuration = if perpetual_tables.database_is_empty()? { info!("Creating new epoch start config from genesis"); @@ -160,7 +161,7 @@ impl AuthorityStore { }); let epoch_start_configuration = EpochStartConfiguration::new( - genesis.sui_system_object().into_epoch_start_state(), + genesis.iota_system_object().into_epoch_start_state(), *genesis.checkpoint().digest(), &genesis.objects(), initial_epoch_flags, @@ -181,7 +182,7 @@ impl AuthorityStore { genesis, perpetual_tables, indirect_objects_threshold, - enable_epoch_sui_conservation_check, + enable_epoch_iota_conservation_check, registry, ) .await?; @@ -210,7 +211,7 @@ impl AuthorityStore { pub fn clear_object_per_epoch_marker_table( &self, _execution_guard: &ExecutionLockWriteGuard<'_>, - ) -> SuiResult<()> { + ) -> IotaResult<()> { // We can safely delete all entries in the per epoch marker table since this is // only called at epoch boundaries (during reconfiguration). Therefore // any entries that currently exist can be removed. Because of this we @@ -226,7 +227,7 @@ impl AuthorityStore { committee: &Committee, genesis: &Genesis, indirect_objects_threshold: usize, - ) -> SuiResult> { + ) -> IotaResult> { // TODO: Since we always start at genesis, the committee should be technically // the same as the genesis committee. assert_eq!(committee.epoch, 0); @@ -244,9 +245,9 @@ impl AuthorityStore { genesis: &Genesis, perpetual_tables: Arc, indirect_objects_threshold: usize, - enable_epoch_sui_conservation_check: bool, + enable_epoch_iota_conservation_check: bool, registry: &Registry, - ) -> SuiResult> { + ) -> IotaResult> { let store = Arc::new(Self { mutex_table: MutexTable::new(NUM_SHARDS), perpetual_tables, @@ -254,7 +255,7 @@ impl AuthorityStore { NotifyRead::::new(), objects_lock_table: Arc::new(RwLockTable::new(NUM_SHARDS)), indirect_objects_threshold, - enable_epoch_sui_conservation_check, + enable_epoch_iota_conservation_check, metrics: AuthorityStoreMetrics::new(registry), }); // Only initialize an empty database. @@ -303,9 +304,9 @@ impl AuthorityStore { pub fn open_no_genesis( perpetual_tables: Arc, indirect_objects_threshold: usize, - enable_epoch_sui_conservation_check: bool, + enable_epoch_iota_conservation_check: bool, registry: &Registry, - ) -> SuiResult> { + ) -> IotaResult> { let store = Arc::new(Self { mutex_table: MutexTable::new(NUM_SHARDS), perpetual_tables, @@ -313,25 +314,25 @@ impl AuthorityStore { NotifyRead::::new(), objects_lock_table: Arc::new(RwLockTable::new(NUM_SHARDS)), indirect_objects_threshold, - enable_epoch_sui_conservation_check, + enable_epoch_iota_conservation_check, metrics: AuthorityStoreMetrics::new(registry), }); Ok(store) } - pub fn get_recovery_epoch_at_restart(&self) -> SuiResult { + pub fn get_recovery_epoch_at_restart(&self) -> IotaResult { self.perpetual_tables.get_recovery_epoch_at_restart() } pub fn get_effects( &self, effects_digest: &TransactionEffectsDigest, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self.perpetual_tables.effects.get(effects_digest)?) } /// Returns true if we have an effects structure for this transaction digest - pub fn effects_exists(&self, effects_digest: &TransactionEffectsDigest) -> SuiResult { + pub fn effects_exists(&self, effects_digest: &TransactionEffectsDigest) -> IotaResult { self.perpetual_tables .effects .contains_key(effects_digest) @@ -354,7 +355,7 @@ impl AuthorityStore { pub fn multi_get_events( &self, event_digests: &[TransactionEventsDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { Ok(event_digests .iter() .map(|digest| self.get_events(digest)) @@ -364,14 +365,14 @@ impl AuthorityStore { pub fn multi_get_effects<'a>( &self, effects_digests: impl Iterator, - ) -> SuiResult>> { + ) -> IotaResult>> { Ok(self.perpetual_tables.effects.multi_get(effects_digests)?) } pub fn get_executed_effects( &self, tx_digest: &TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { let effects_digest = self.perpetual_tables.executed_effects.get(tx_digest)?; match effects_digest { Some(digest) => Ok(self.perpetual_tables.effects.get(&digest)?), @@ -385,7 +386,7 @@ impl AuthorityStore { pub fn multi_get_executed_effects_digests( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { Ok(self.perpetual_tables.executed_effects.multi_get(digests)?) } @@ -395,7 +396,7 @@ impl AuthorityStore { pub fn multi_get_executed_effects( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { let executed_effects_digests = self.perpetual_tables.executed_effects.multi_get(digests)?; let effects = self.multi_get_effects(executed_effects_digests.iter().flatten())?; let mut tx_to_effects_map = effects @@ -409,7 +410,7 @@ impl AuthorityStore { .collect()) } - pub fn is_tx_already_executed(&self, digest: &TransactionDigest) -> SuiResult { + pub fn is_tx_already_executed(&self, digest: &TransactionDigest) -> IotaResult { Ok(self .perpetual_tables .executed_effects @@ -421,7 +422,7 @@ impl AuthorityStore { object_id: &ObjectID, version: &SequenceNumber, epoch_id: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { let object_key = (epoch_id, ObjectKey(*object_id, *version)); Ok(self .perpetual_tables @@ -433,7 +434,7 @@ impl AuthorityStore { &self, object_id: &ObjectID, epoch_id: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { let min_key = (epoch_id, ObjectKey::min_for_id(object_id)); let max_key = (epoch_id, ObjectKey::max_for_id(object_id)); @@ -460,7 +461,7 @@ impl AuthorityStore { pub async fn notify_read_root_state_hash( &self, epoch: EpochId, - ) -> SuiResult<(CheckpointSequenceNumber, Accumulator)> { + ) -> IotaResult<(CheckpointSequenceNumber, Accumulator)> { // We need to register waiters _before_ reading from the database to avoid race // conditions let registration = self.root_state_notify_read.register_one(&epoch); @@ -482,7 +483,7 @@ impl AuthorityStore { digests: &[TransactionDigest], epoch: EpochId, sequence: CheckpointSequenceNumber, - ) -> SuiResult { + ) -> IotaResult { let mut batch = self .perpetual_tables .executed_transactions_to_checkpoint @@ -500,7 +501,7 @@ impl AuthorityStore { pub fn deprecated_get_transaction_checkpoint( &self, digest: &TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self .perpetual_tables .executed_transactions_to_checkpoint @@ -511,7 +512,7 @@ impl AuthorityStore { pub fn deprecated_multi_get_transaction_checkpoint( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { Ok(self .perpetual_tables .executed_transactions_to_checkpoint @@ -521,7 +522,7 @@ impl AuthorityStore { } /// Returns true if there are no objects in the database - pub fn database_is_empty(&self) -> SuiResult { + pub fn database_is_empty(&self) -> IotaResult { self.perpetual_tables.database_is_empty() } @@ -537,14 +538,14 @@ impl AuthorityStore { &self, object_id: &ObjectID, version: VersionNumber, - ) -> SuiResult { + ) -> IotaResult { Ok(self .perpetual_tables .objects .contains_key(&ObjectKey(*object_id, version))?) } - pub fn multi_object_exists_by_key(&self, object_keys: &[ObjectKey]) -> SuiResult> { + pub fn multi_object_exists_by_key(&self, object_keys: &[ObjectKey]) -> IotaResult> { Ok(self .perpetual_tables .objects @@ -557,7 +558,7 @@ impl AuthorityStore { &self, object_id: &ObjectID, version: VersionNumber, - ) -> Result, SuiError> { + ) -> Result, IotaError> { let Some(prior_version) = version.one_before() else { return Ok(None); }; @@ -580,7 +581,7 @@ impl AuthorityStore { pub fn multi_get_objects_by_key( &self, object_keys: &[ObjectKey], - ) -> Result>, SuiError> { + ) -> Result>, IotaError> { let wrappers = self .perpetual_tables .objects @@ -598,7 +599,7 @@ impl AuthorityStore { } /// Get many objects - pub fn get_objects(&self, objects: &[ObjectID]) -> Result>, SuiError> { + pub fn get_objects(&self, objects: &[ObjectID]) -> Result>, IotaError> { let mut result = Vec::new(); for id in objects { result.push(self.get_object(id)?); @@ -611,7 +612,7 @@ impl AuthorityStore { object_id: &ObjectID, version: VersionNumber, epoch_id: EpochId, - ) -> Result { + ) -> Result { let object_key = ObjectKey::max_for_id(object_id); let marker_key = (epoch_id, object_key); @@ -641,7 +642,7 @@ impl AuthorityStore { /// Insert a genesis object. /// TODO: delete this method entirely (still used by authority_tests.rs) - pub(crate) fn insert_genesis_object(&self, object: Object) -> SuiResult { + pub(crate) fn insert_genesis_object(&self, object: Object) -> IotaResult { // We only side load objects with a genesis parent transaction. debug_assert!(object.previous_transaction == TransactionDigest::genesis_marker()); let object_ref = object.compute_object_reference(); @@ -651,7 +652,7 @@ impl AuthorityStore { /// Insert an object directly into the store, and also update relevant /// tables NOTE: does not handle transaction lock. /// This is used to insert genesis objects - fn insert_object_direct(&self, object_ref: ObjectRef, object: &Object) -> SuiResult { + fn insert_object_direct(&self, object_ref: ObjectRef, object: &Object) -> IotaResult { let mut write_batch = self.perpetual_tables.objects.batch(); // Insert object @@ -683,7 +684,7 @@ impl AuthorityStore { /// This function should only be used for initializing genesis and should /// remain private. - pub(crate) fn bulk_insert_genesis_objects(&self, objects: &[Object]) -> SuiResult<()> { + pub(crate) fn bulk_insert_genesis_objects(&self, objects: &[Object]) -> IotaResult<()> { let mut batch = self.perpetual_tables.objects.batch(); let ref_and_objects: Vec<_> = objects .iter() @@ -731,7 +732,7 @@ impl AuthorityStore { live_objects: impl Iterator, indirect_objects_threshold: usize, expected_sha3_digest: &[u8; 32], - ) -> SuiResult<()> { + ) -> IotaResult<()> { let mut hasher = Sha3_256::default(); let mut batch = perpetual_db.objects.batch(); for object in live_objects { @@ -779,7 +780,7 @@ impl AuthorityStore { "Sha does not match! expected: {:?}, actual: {:?}", expected_sha3_digest, sha3_digest ); - return Err(SuiError::from("Sha does not match")); + return Err(IotaError::from("Sha does not match")); } batch.write()?; Ok(()) @@ -788,13 +789,13 @@ impl AuthorityStore { pub fn set_epoch_start_configuration( &self, epoch_start_configuration: &EpochStartConfiguration, - ) -> SuiResult { + ) -> IotaResult { self.perpetual_tables .set_epoch_start_configuration(epoch_start_configuration)?; Ok(()) } - pub fn get_epoch_start_configuration(&self) -> SuiResult> { + pub fn get_epoch_start_configuration(&self) -> IotaResult> { Ok(self.perpetual_tables.epoch_start_configuration.get(&())?) } @@ -835,7 +836,7 @@ impl AuthorityStore { &self, epoch_id: EpochId, tx_outputs: Arc, - ) -> SuiResult { + ) -> IotaResult { let TransactionOutputs { transaction, effects, @@ -982,7 +983,7 @@ impl AuthorityStore { epoch_store: &AuthorityPerEpochStore, owned_input_objects: &[ObjectRef], transaction: VerifiedSignedTransaction, - ) -> SuiResult { + ) -> IotaResult { let tx_digest = *transaction.digest(); if epoch_store.object_lock_split_tables_enabled() { self.acquire_transaction_locks_v2(epoch_store, owned_input_objects, transaction) @@ -1000,7 +1001,7 @@ impl AuthorityStore { epoch_store: &AuthorityPerEpochStore, owned_input_objects: &[ObjectRef], tx_digest: TransactionDigest, - ) -> SuiResult { + ) -> IotaResult { let epoch = epoch_store.epoch(); // Other writers may be attempting to acquire locks on the same objects, so a // mutex is required. @@ -1037,7 +1038,7 @@ impl AuthorityStore { { fp_ensure!( &epoch >= previous_epoch, - SuiError::ObjectLockedAtFutureEpoch { + IotaError::ObjectLockedAtFutureEpoch { obj_refs: owned_input_objects.to_vec(), locked_epoch: *previous_epoch, new_epoch: epoch, @@ -1051,7 +1052,7 @@ impl AuthorityStore { info!(prev_tx_digest = ?previous_tx_digest, cur_tx_digest = ?tx_digest, "Cannot acquire lock: conflicting transaction!"); - return Err(SuiError::ObjectLockConflict { + return Err(IotaError::ObjectLockConflict { obj_ref: *obj_ref, pending_transaction: *previous_tx_digest, }); @@ -1087,7 +1088,7 @@ impl AuthorityStore { epoch_store: &AuthorityPerEpochStore, owned_input_objects: &[ObjectRef], transaction: VerifiedSignedTransaction, - ) -> SuiResult { + ) -> IotaResult { let tx_digest = *transaction.digest(); let epoch = epoch_store.epoch(); // Other writers may be attempting to acquire locks on the same objects, so a @@ -1150,7 +1151,7 @@ impl AuthorityStore { info!(prev_tx_digest = ?previous_tx_digest, cur_tx_digest = ?tx_digest, "Cannot acquire lock: conflicting transaction!"); - return Err(SuiError::ObjectLockConflict { + return Err(IotaError::ObjectLockConflict { obj_ref: *obj_ref, pending_transaction: *previous_tx_digest, }); @@ -1175,7 +1176,7 @@ impl AuthorityStore { &self, obj_ref: ObjectRef, epoch_store: &AuthorityPerEpochStore, - ) -> SuiLockResult { + ) -> IotaLockResult { if epoch_store.object_lock_split_tables_enabled() { self.get_lock_v2(obj_ref, epoch_store) } else { @@ -1187,7 +1188,7 @@ impl AuthorityStore { &self, obj_ref: ObjectRef, epoch_store: &AuthorityPerEpochStore, - ) -> SuiLockResult { + ) -> IotaLockResult { if self .perpetual_tables .live_owned_object_markers @@ -1214,7 +1215,7 @@ impl AuthorityStore { } } - fn get_lock_v1(&self, obj_ref: ObjectRef, epoch_id: EpochId) -> SuiLockResult { + fn get_lock_v1(&self, obj_ref: ObjectRef, epoch_id: EpochId) -> IotaLockResult { Ok( if let Some(lock_info) = self .perpetual_tables @@ -1232,7 +1233,7 @@ impl AuthorityStore { locked_by_tx: lock_info, }, Ordering::Greater => { - return Err(SuiError::ObjectLockedAtFutureEpoch { + return Err(IotaError::ObjectLockedAtFutureEpoch { obj_refs: vec![obj_ref], locked_epoch: lock_info.epoch, new_epoch: epoch_id, @@ -1256,7 +1257,7 @@ impl AuthorityStore { pub(crate) fn get_latest_live_version_for_object_id( &self, object_id: ObjectID, - ) -> SuiResult { + ) -> IotaResult { let mut iterator = self .perpetual_tables .live_owned_object_markers @@ -1273,7 +1274,7 @@ impl AuthorityStore { } }) .ok_or_else(|| { - SuiError::from(UserInputError::ObjectNotFound { + IotaError::from(UserInputError::ObjectNotFound { object_id, version: None, }) @@ -1286,7 +1287,7 @@ impl AuthorityStore { /// least one of the objects. /// Returns UserInputError::ObjectVersionUnavailableForConsumption if at /// least one object lock is not initialized at the given version. - pub fn check_owned_object_locks_exist(&self, objects: &[ObjectRef]) -> SuiResult { + pub fn check_owned_object_locks_exist(&self, objects: &[ObjectRef]) -> IotaResult { let locks = self .perpetual_tables .live_owned_object_markers @@ -1307,14 +1308,14 @@ impl AuthorityStore { } /// Initialize a lock to None (but exists) for a given list of ObjectRefs. - /// Returns SuiError::ObjectLockAlreadyInitialized if the lock already + /// Returns IotaError::ObjectLockAlreadyInitialized if the lock already /// exists and is locked to a transaction fn initialize_live_object_markers_impl( &self, write_batch: &mut DBBatch, objects: &[ObjectRef], is_force_reset: bool, - ) -> SuiResult { + ) -> IotaResult { trace!(?objects, "initialize_locks"); AuthorityStore::initialize_live_object_markers( &self.perpetual_tables.live_owned_object_markers, @@ -1329,7 +1330,7 @@ impl AuthorityStore { write_batch: &mut DBBatch, objects: &[ObjectRef], is_force_reset: bool, - ) -> SuiResult { + ) -> IotaResult { trace!(?objects, "initialize_locks"); let locks = live_object_marker_table.multi_get(objects)?; @@ -1352,7 +1353,7 @@ impl AuthorityStore { ?existing_locks, "Cannot initialize locks because some exist already" ); - return Err(SuiError::ObjectLockAlreadyInitialized { + return Err(IotaError::ObjectLockAlreadyInitialized { refs: existing_locks, }); } @@ -1370,7 +1371,7 @@ impl AuthorityStore { &self, write_batch: &mut DBBatch, objects: &[ObjectRef], - ) -> SuiResult { + ) -> IotaResult { trace!(?objects, "delete_locks"); write_batch.delete_batch( &self.perpetual_tables.live_owned_object_markers, @@ -1419,7 +1420,7 @@ impl AuthorityStore { /// so that when we receive the checkpoint that includes it from state /// sync, we are able to execute the checkpoint. /// TODO: implement GC for transactions that are no longer needed. - pub fn revert_state_update(&self, tx_digest: &TransactionDigest) -> SuiResult { + pub fn revert_state_update(&self, tx_digest: &TransactionDigest) -> IotaResult { let Some(effects) = self.get_executed_effects(tx_digest)? else { debug!("Not reverting {:?} as it was not executed", tx_digest); return Ok(()); @@ -1516,7 +1517,7 @@ impl AuthorityStore { &self, object_id: ObjectID, version: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { self.perpetual_tables .find_object_lt_or_eq_version(object_id, version) } @@ -1534,7 +1535,7 @@ impl AuthorityStore { pub fn get_latest_object_ref_or_tombstone( &self, object_id: ObjectID, - ) -> Result, SuiError> { + ) -> Result, IotaError> { self.perpetual_tables .get_latest_object_ref_or_tombstone(object_id) } @@ -1544,7 +1545,7 @@ impl AuthorityStore { pub fn get_latest_object_ref_if_alive( &self, object_id: ObjectID, - ) -> Result, SuiError> { + ) -> Result, IotaError> { match self.get_latest_object_ref_or_tombstone(object_id)? { Some(objref) if objref.2.is_alive() => Ok(Some(objref)), _ => Ok(None), @@ -1558,7 +1559,7 @@ impl AuthorityStore { pub fn get_latest_object_or_tombstone( &self, object_id: ObjectID, - ) -> Result, SuiError> { + ) -> Result, IotaError> { let Some((object_key, store_object)) = self .perpetual_tables .get_latest_object_or_tombstone(object_id)? @@ -1625,7 +1626,7 @@ impl AuthorityStore { pub fn multi_get_transaction_blocks( &self, tx_digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { Ok(self .perpetual_tables .transactions @@ -1649,30 +1650,30 @@ impl AuthorityStore { /// Hence this function should only be called during RPC reads where data /// race is not a major concern. In general we should avoid this as much /// as possible. If the intent is for testing, you can use - /// AuthorityState:: get_sui_system_state_object_for_testing. - pub fn get_sui_system_state_object_unsafe(&self) -> SuiResult { - get_sui_system_state(self.perpetual_tables.as_ref()) + /// AuthorityState:: get_iota_system_state_object_for_testing. + pub fn get_iota_system_state_object_unsafe(&self) -> IotaResult { + get_iota_system_state(self.perpetual_tables.as_ref()) } - pub fn expensive_check_sui_conservation( + pub fn expensive_check_iota_conservation( self: &Arc, type_layout_store: T, old_epoch_store: &AuthorityPerEpochStore, - ) -> SuiResult + ) -> IotaResult where T: TypeLayoutStore + Send + Copy, { - if !self.enable_epoch_sui_conservation_check { + if !self.enable_epoch_iota_conservation_check { return Ok(()); } let executor = old_epoch_store.executor(); - info!("Starting SUI conservation check. This may take a while.."); + info!("Starting IOTA conservation check. This may take a while.."); let cur_time = Instant::now(); let mut pending_objects = vec![]; let mut count = 0; let mut size = 0; - let (mut total_sui, mut total_storage_rebate) = thread::scope(|s| { + let (mut total_iota, mut total_storage_rebate) = thread::scope(|s| { let pending_tasks = FuturesUnordered::new(); for o in self.iter_live_object_set(false) { match o { @@ -1687,20 +1688,20 @@ impl AuthorityStore { let mut layout_resolver = executor.type_layout_resolver(Box::new(type_layout_store)); let mut total_storage_rebate = 0; - let mut total_sui = 0; + let mut total_iota = 0; for object in task_objects { total_storage_rebate += object.storage_rebate; - // get_total_sui includes storage rebate, however all storage + // get_total_iota includes storage rebate, however all storage // rebate is also stored in // the storage fund, so we need to subtract it here. - total_sui += - object.get_total_sui(layout_resolver.as_mut()).unwrap() + total_iota += + object.get_total_iota(layout_resolver.as_mut()).unwrap() - object.storage_rebate; } if count % 50_000_000 == 0 { info!("Processed {} objects", count); } - (total_sui, total_storage_rebate) + (total_iota, total_storage_rebate) })); } } @@ -1717,8 +1718,8 @@ impl AuthorityStore { let mut layout_resolver = executor.type_layout_resolver(Box::new(type_layout_store)); for object in pending_objects { total_storage_rebate += object.storage_rebate; - total_sui += - object.get_total_sui(layout_resolver.as_mut()).unwrap() - object.storage_rebate; + total_iota += + object.get_total_iota(layout_resolver.as_mut()).unwrap() - object.storage_rebate; } info!( "Scanned {} live objects, took {:?}", @@ -1726,37 +1727,37 @@ impl AuthorityStore { cur_time.elapsed() ); self.metrics - .sui_conservation_live_object_count + .iota_conservation_live_object_count .set(count as i64); self.metrics - .sui_conservation_live_object_size + .iota_conservation_live_object_size .set(size as i64); self.metrics - .sui_conservation_check_latency + .iota_conservation_check_latency .set(cur_time.elapsed().as_secs() as i64); // It is safe to call this function because we are in the middle of // reconfiguration. let system_state = self - .get_sui_system_state_object_unsafe() - .expect("Reading sui system state object cannot fail") - .into_sui_system_state_summary(); + .get_iota_system_state_object_unsafe() + .expect("Reading iota system state object cannot fail") + .into_iota_system_state_summary(); let storage_fund_balance = system_state.storage_fund_total_object_storage_rebates; info!( - "Total SUI amount in the network: {}, storage fund balance: {}, total storage rebate: {} at beginning of epoch {}", - total_sui, storage_fund_balance, total_storage_rebate, system_state.epoch + "Total IOTA amount in the network: {}, storage fund balance: {}, total storage rebate: {} at beginning of epoch {}", + total_iota, storage_fund_balance, total_storage_rebate, system_state.epoch ); let imbalance = (storage_fund_balance as i64) - (total_storage_rebate as i64); self.metrics - .sui_conservation_storage_fund + .iota_conservation_storage_fund .set(storage_fund_balance as i64); self.metrics - .sui_conservation_storage_fund_imbalance + .iota_conservation_storage_fund_imbalance .set(imbalance); self.metrics - .sui_conservation_imbalance - .set((total_sui as i128 - TOTAL_SUPPLY_MIST as i128) as i64); + .iota_conservation_imbalance + .set((total_iota as i128 - TOTAL_SUPPLY_MICROS as i128) as i64); if let Some(expected_imbalance) = self .perpetual_tables @@ -1766,7 +1767,7 @@ impl AuthorityStore { { fp_ensure!( imbalance == expected_imbalance, - SuiError::from( + IotaError::from( format!( "Inconsistent state detected at epoch {}: total storage rebate: {}, storage fund balance: {}, expected imbalance: {}", system_state.epoch, total_storage_rebate, storage_fund_balance, expected_imbalance @@ -1780,26 +1781,26 @@ impl AuthorityStore { .expect("DB write cannot fail"); } - if let Some(expected_sui) = self + if let Some(expected_iota) = self .perpetual_tables - .expected_network_sui_amount + .expected_network_iota_amount .get(&()) .expect("DB read cannot fail") { fp_ensure!( - total_sui == expected_sui, - SuiError::from( + total_iota == expected_iota, + IotaError::from( format!( - "Inconsistent state detected at epoch {}: total sui: {}, expecting {}", - system_state.epoch, total_sui, expected_sui + "Inconsistent state detected at epoch {}: total iota: {}, expecting {}", + system_state.epoch, total_iota, expected_iota ) .as_str() ) ); } else { self.perpetual_tables - .expected_network_sui_amount - .insert(&(), &total_sui) + .expected_network_iota_amount + .insert(&(), &total_iota) .expect("DB write cannot fail"); } @@ -2006,14 +2007,14 @@ impl AccumulatorStore for AuthorityStore { &self, object_id: &ObjectID, version: VersionNumber, - ) -> SuiResult> { + ) -> IotaResult> { self.get_object_ref_prior_to_key(object_id, version) } fn get_root_state_accumulator_for_epoch( &self, epoch: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { self.perpetual_tables .root_state_hash_by_epoch .get(&epoch) @@ -2022,7 +2023,7 @@ impl AccumulatorStore for AuthorityStore { fn get_root_state_accumulator_for_highest_epoch( &self, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self .perpetual_tables .root_state_hash_by_epoch @@ -2037,7 +2038,7 @@ impl AccumulatorStore for AuthorityStore { epoch: EpochId, last_checkpoint_of_epoch: &CheckpointSequenceNumber, acc: &Accumulator, - ) -> SuiResult { + ) -> IotaResult { self.perpetual_tables .root_state_hash_by_epoch .insert(&epoch, &(*last_checkpoint_of_epoch, acc.clone()))?; @@ -2063,7 +2064,7 @@ impl ObjectStore for AuthorityStore { fn get_object( &self, object_id: &ObjectID, - ) -> Result, sui_types::storage::error::Error> { + ) -> Result, iota_types::storage::error::Error> { self.perpetual_tables.as_ref().get_object(object_id) } @@ -2071,7 +2072,7 @@ impl ObjectStore for AuthorityStore { &self, object_id: &ObjectID, version: VersionNumber, - ) -> Result, sui_types::storage::error::Error> { + ) -> Result, iota_types::storage::error::Error> { self.perpetual_tables.get_object_by_key(object_id, version) } } @@ -2096,7 +2097,7 @@ impl ResolverWrapper { } impl ModuleResolver for ResolverWrapper { - type Error = SuiError; + type Error = IotaError; fn get_module(&self, module_id: &ModuleId) -> Result>, Self::Error> { self.inc_cache_size_gauge(); get_module(&self.resolver, module_id) @@ -2108,7 +2109,7 @@ pub enum UpdateType { Genesis, } -pub type SuiLockResult = SuiResult; +pub type IotaLockResult = IotaResult; #[derive(Debug, PartialEq, Eq)] pub enum ObjectLockStatus { diff --git a/crates/sui-core/src/authority/authority_store_pruner.rs b/crates/iota-core/src/authority/authority_store_pruner.rs similarity index 99% rename from crates/sui-core/src/authority/authority_store_pruner.rs rename to crates/iota-core/src/authority/authority_store_pruner.rs index a27f6a159ea..5cf7440a089 100644 --- a/crates/sui-core/src/authority/authority_store_pruner.rs +++ b/crates/iota-core/src/authority/authority_store_pruner.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -9,6 +10,16 @@ use std::{ }; use anyhow::anyhow; +use iota_archival::reader::ArchiveReaderBalancer; +use iota_config::node::AuthorityStorePruningConfig; +use iota_storage::mutex_table::RwLockTable; +use iota_types::{ + base_types::{ObjectID, SequenceNumber, VersionNumber}, + effects::{TransactionEffects, TransactionEffectsAPI}, + message_envelope::Message, + messages_checkpoint::{CheckpointContents, CheckpointDigest, CheckpointSequenceNumber}, + storage::ObjectKey, +}; use mysten_metrics::{monitored_scope, spawn_monitored_task}; use once_cell::sync::Lazy; use prometheus::{ @@ -16,16 +27,6 @@ use prometheus::{ Registry, }; use rocksdb::LiveFile; -use sui_archival::reader::ArchiveReaderBalancer; -use sui_config::node::AuthorityStorePruningConfig; -use sui_storage::mutex_table::RwLockTable; -use sui_types::{ - base_types::{ObjectID, SequenceNumber, VersionNumber}, - effects::{TransactionEffects, TransactionEffectsAPI}, - message_envelope::Message, - messages_checkpoint::{CheckpointContents, CheckpointDigest, CheckpointSequenceNumber}, - storage::ObjectKey, -}; use tokio::{ sync::oneshot::{self, Sender}, time::Instant, @@ -715,15 +716,15 @@ impl AuthorityStorePruner { mod tests { use std::{collections::HashSet, path::Path, sync::Arc, time::Duration}; - use more_asserts as ma; - use prometheus::Registry; - use sui_storage::mutex_table::RwLockTable; - use sui_types::{ + use iota_storage::mutex_table::RwLockTable; + use iota_types::{ base_types::{ObjectDigest, ObjectID, SequenceNumber}, effects::{TransactionEffects, TransactionEffectsAPI}, object::Object, storage::ObjectKey, }; + use more_asserts as ma; + use prometheus::Registry; use tracing::log::info; use typed_store::{ rocks::{util::reference_count_merge_operator, DBMap, MetricConf, ReadWriteOptions}, @@ -1037,14 +1038,14 @@ mod tests { mod pprof_tests { use std::sync::Arc; - use pprof::Symbol; - use prometheus::Registry; - use sui_types::{ + use iota_types::{ base_types::{ObjectDigest, ObjectID, SequenceNumber, VersionNumber}, effects::{TransactionEffects, TransactionEffectsAPI}, object::Object, storage::ObjectKey, }; + use pprof::Symbol; + use prometheus::Registry; use tracing::log::{error, info}; use typed_store::{rocks::DBMap, Map}; diff --git a/crates/sui-core/src/authority/authority_store_tables.rs b/crates/iota-core/src/authority/authority_store_tables.rs similarity index 92% rename from crates/sui-core/src/authority/authority_store_tables.rs rename to crates/iota-core/src/authority/authority_store_tables.rs index cfe1a54d350..e5f5019bfdc 100644 --- a/crates/sui-core/src/authority/authority_store_tables.rs +++ b/crates/iota-core/src/authority/authority_store_tables.rs @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::Path; -use rocksdb::Options; -use serde::{Deserialize, Serialize}; -use sui_types::{ +use iota_types::{ accumulator::Accumulator, base_types::SequenceNumber, digests::TransactionEventsDigest, effects::TransactionEffects, storage::MarkerValue, }; +use rocksdb::Options; +use serde::{Deserialize, Serialize}; use typed_store::{ metrics::SamplingInterval, rocks::{ @@ -127,12 +128,12 @@ pub struct AuthorityPerpetualTables { /// objects pruner progress pub(crate) pruned_checkpoint: DBMap<(), CheckpointSequenceNumber>, - /// Expected total amount of SUI in the network. This is expected to remain + /// Expected total amount of IOTA in the network. This is expected to remain /// constant throughout the lifetime of the network. We check it at the /// end of each epoch if expensive checks are enabled. We cannot use 10B /// today because in tests we often inject extra gas objects into /// genesis. - pub(crate) expected_network_sui_amount: DBMap<(), u64>, + pub(crate) expected_network_iota_amount: DBMap<(), u64>, /// Expected imbalance between storage fund balance and the sum of storage /// rebate of all live objects. This could be non-zero due to bugs in @@ -182,7 +183,7 @@ impl AuthorityPerpetualTables { &self, object_id: ObjectID, version: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { let iter = self .objects .safe_range_iter(ObjectKey::min_for_id(&object_id)..=ObjectKey::max_for_id(&object_id)) @@ -198,7 +199,7 @@ impl AuthorityPerpetualTables { &self, object_key: &ObjectKey, store_object: StoreObjectValue, - ) -> Result { + ) -> Result { let indirect_object = match store_object.data { StoreData::IndirectObject(ref metadata) => self .indirect_move_objects @@ -209,13 +210,13 @@ impl AuthorityPerpetualTables { try_construct_object(object_key, store_object, indirect_object) } - // Constructs `sui_types::object::Object` from `StoreObjectWrapper`. + // Constructs `iota_types::object::Object` from `StoreObjectWrapper`. // Returns `None` if object was deleted/wrapped pub fn object( &self, object_key: &ObjectKey, store_object: StoreObjectWrapper, - ) -> Result, SuiError> { + ) -> Result, IotaError> { let StoreObject::Value(store_object) = store_object.migrate().into_inner() else { return Ok(None); }; @@ -226,7 +227,7 @@ impl AuthorityPerpetualTables { &self, object_key: &ObjectKey, store_object: StoreObjectWrapper, - ) -> Result { + ) -> Result { let obj_ref = match store_object.migrate().into_inner() { StoreObject::Value(object) => self .construct_object(object_key, object)? @@ -249,7 +250,7 @@ impl AuthorityPerpetualTables { &self, object_key: &ObjectKey, store_object: &StoreObjectWrapper, - ) -> Result, SuiError> { + ) -> Result, IotaError> { let obj_ref = match store_object.inner() { StoreObject::Deleted => Some(( object_key.0, @@ -269,7 +270,7 @@ impl AuthorityPerpetualTables { pub fn get_latest_object_ref_or_tombstone( &self, object_id: ObjectID, - ) -> Result, SuiError> { + ) -> Result, IotaError> { let mut iterator = self .objects .unbounded_iter() @@ -286,7 +287,7 @@ impl AuthorityPerpetualTables { pub fn get_latest_object_or_tombstone( &self, object_id: ObjectID, - ) -> Result, SuiError> { + ) -> Result, IotaError> { let mut iterator = self .objects .unbounded_iter() @@ -300,7 +301,7 @@ impl AuthorityPerpetualTables { Ok(None) } - pub fn get_recovery_epoch_at_restart(&self) -> SuiResult { + pub fn get_recovery_epoch_at_restart(&self) -> IotaResult { Ok(self .epoch_start_configuration .get(&())? @@ -312,7 +313,7 @@ impl AuthorityPerpetualTables { pub fn set_epoch_start_configuration( &self, epoch_start_configuration: &EpochStartConfiguration, - ) -> SuiResult { + ) -> IotaResult { let mut wb = self.epoch_start_configuration.batch(); wb.insert_batch( &self.epoch_start_configuration, @@ -322,7 +323,7 @@ impl AuthorityPerpetualTables { Ok(()) } - pub fn get_highest_pruned_checkpoint(&self) -> SuiResult { + pub fn get_highest_pruned_checkpoint(&self) -> IotaResult { Ok(self.pruned_checkpoint.get(&())?.unwrap_or_default()) } @@ -330,7 +331,7 @@ impl AuthorityPerpetualTables { &self, wb: &mut DBBatch, checkpoint_number: CheckpointSequenceNumber, - ) -> SuiResult { + ) -> IotaResult { wb.insert_batch(&self.pruned_checkpoint, [((), checkpoint_number)])?; Ok(()) } @@ -338,14 +339,17 @@ impl AuthorityPerpetualTables { pub fn get_transaction( &self, digest: &TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { let Some(transaction) = self.transactions.get(digest)? else { return Ok(None); }; Ok(Some(transaction)) } - pub fn get_effects(&self, digest: &TransactionDigest) -> SuiResult> { + pub fn get_effects( + &self, + digest: &TransactionDigest, + ) -> IotaResult> { let Some(effect_digest) = self.executed_effects.get(digest)? else { return Ok(None); }; @@ -357,14 +361,14 @@ impl AuthorityPerpetualTables { pub fn get_checkpoint_sequence_number( &self, digest: &TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self.executed_transactions_to_checkpoint.get(digest)?) } pub fn get_newer_object_keys( &self, object: &(ObjectID, SequenceNumber), - ) -> SuiResult> { + ) -> IotaResult> { let mut objects = vec![]; for result in self.objects.safe_iter_with_bounds( Some(ObjectKey(object.0, object.1.next())), @@ -379,14 +383,14 @@ impl AuthorityPerpetualTables { pub fn set_highest_pruned_checkpoint_without_wb( &self, checkpoint_number: CheckpointSequenceNumber, - ) -> SuiResult { + ) -> IotaResult { let mut wb = self.pruned_checkpoint.batch(); self.set_highest_pruned_checkpoint(&mut wb, checkpoint_number)?; wb.write()?; Ok(()) } - pub fn database_is_empty(&self) -> SuiResult { + pub fn database_is_empty(&self) -> IotaResult { Ok(self .objects .unbounded_iter() @@ -404,12 +408,12 @@ impl AuthorityPerpetualTables { } } - pub fn checkpoint_db(&self, path: &Path) -> SuiResult { + pub fn checkpoint_db(&self, path: &Path) -> IotaResult { // This checkpoints the entire db and not just objects table self.objects.checkpoint_db(path).map_err(Into::into) } - pub fn reset_db_for_execution_since_genesis(&self) -> SuiResult { + pub fn reset_db_for_execution_since_genesis(&self) -> IotaResult { // TODO: Add new tables that get added to the db automatically self.objects.unsafe_clear()?; self.indirect_move_objects.unsafe_clear()?; @@ -420,7 +424,7 @@ impl AuthorityPerpetualTables { self.root_state_hash_by_epoch.unsafe_clear()?; self.epoch_start_configuration.unsafe_clear()?; self.pruned_checkpoint.unsafe_clear()?; - self.expected_network_sui_amount.unsafe_clear()?; + self.expected_network_iota_amount.unsafe_clear()?; self.expected_storage_fund_imbalance.unsafe_clear()?; self.object_per_epoch_marker_table.unsafe_clear()?; self.objects.rocksdb.flush()?; @@ -430,7 +434,7 @@ impl AuthorityPerpetualTables { pub fn get_root_state_hash( &self, epoch: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self.root_state_hash_by_epoch.get(&epoch)?) } @@ -439,13 +443,13 @@ impl AuthorityPerpetualTables { epoch: EpochId, last_checkpoint_of_epoch: CheckpointSequenceNumber, accumulator: Accumulator, - ) -> SuiResult { + ) -> IotaResult { self.root_state_hash_by_epoch .insert(&epoch, &(last_checkpoint_of_epoch, accumulator))?; Ok(()) } - pub fn insert_object_test_only(&self, object: Object) -> SuiResult { + pub fn insert_object_test_only(&self, object: Object) -> IotaResult { let object_reference = object.compute_object_reference(); let StoreObjectPair(wrapper, _indirect_object) = get_store_object_pair(object, usize::MAX); let mut wb = self.objects.batch(); @@ -463,18 +467,18 @@ impl ObjectStore for AuthorityPerpetualTables { fn get_object( &self, object_id: &ObjectID, - ) -> Result, sui_types::storage::error::Error> { + ) -> Result, iota_types::storage::error::Error> { let obj_entry = self .objects .unbounded_iter() .skip_prior_to(&ObjectKey::max_for_id(object_id)) - .map_err(sui_types::storage::error::Error::custom)? + .map_err(iota_types::storage::error::Error::custom)? .next(); match obj_entry { Some((ObjectKey(obj_id, version), obj)) if obj_id == *object_id => Ok(self .object(&ObjectKey(obj_id, version), obj) - .map_err(sui_types::storage::error::Error::custom)?), + .map_err(iota_types::storage::error::Error::custom)?), _ => Ok(None), } } @@ -483,14 +487,14 @@ impl ObjectStore for AuthorityPerpetualTables { &self, object_id: &ObjectID, version: VersionNumber, - ) -> Result, sui_types::storage::error::Error> { + ) -> Result, iota_types::storage::error::Error> { Ok(self .objects .get(&ObjectKey(*object_id, version)) - .map_err(sui_types::storage::error::Error::custom)? + .map_err(iota_types::storage::error::Error::custom)? .map(|object| self.object(&ObjectKey(*object_id, version), object)) .transpose() - .map_err(sui_types::storage::error::Error::custom)? + .map_err(iota_types::storage::error::Error::custom)? .flatten()) } } diff --git a/crates/sui-core/src/authority/authority_store_types.rs b/crates/iota-core/src/authority/authority_store_types.rs similarity index 97% rename from crates/sui-core/src/authority/authority_store_types.rs rename to crates/iota-core/src/authority/authority_store_types.rs index 66c03fc08c1..2ddc23e33d0 100644 --- a/crates/sui-core/src/authority/authority_store_types.rs +++ b/crates/iota-core/src/authority/authority_store_types.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use serde::{Deserialize, Serialize}; -use serde_with::{serde_as, Bytes}; -use sui_types::{ +use iota_types::{ base_types::{MoveObjectType, ObjectDigest, SequenceNumber, TransactionDigest}, coin::Coin, crypto::{default_hash, Signable}, - error::SuiError, + error::IotaError, move_package::MovePackage, object::{Data, MoveObject, Object, ObjectInner, Owner}, storage::ObjectKey, }; +use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, Bytes}; pub type ObjectContentDigest = ObjectDigest; @@ -93,7 +94,7 @@ pub enum StoreObjectV1 { Wrapped, } -/// Forked version of [`sui_types::object::Object`] +/// Forked version of [`iota_types::object::Object`] /// Used for efficient storing of move objects in the database #[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)] pub struct StoreObjectValue { @@ -103,7 +104,7 @@ pub struct StoreObjectValue { pub storage_rebate: u64, } -/// Forked version of [`sui_types::object::Data`] +/// Forked version of [`iota_types::object::Data`] /// Adds extra enum value `IndirectObject`, which represents a reference to an /// object stored separately #[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)] @@ -250,7 +251,7 @@ pub(crate) fn try_construct_object( object_key: &ObjectKey, store_object: StoreObjectValue, indirect_object: Option, -) -> Result { +) -> Result { let data = match (store_object.data, indirect_object) { (StoreData::Move(object), None) => Data::Move(object), (StoreData::Package(package), None) => Data::Package(package), @@ -274,7 +275,7 @@ pub(crate) fn try_construct_object( )?) }, _ => { - return Err(SuiError::Storage( + return Err(IotaError::Storage( "corrupted field: inconsistent object representation".to_string(), )); } diff --git a/crates/sui-core/src/authority/authority_test_utils.rs b/crates/iota-core/src/authority/authority_test_utils.rs similarity index 93% rename from crates/sui-core/src/authority/authority_test_utils.rs rename to crates/iota-core/src/authority/authority_test_utils.rs index e07b7aa6a1b..4a68daf060b 100644 --- a/crates/sui-core/src/authority/authority_test_utils.rs +++ b/crates/iota-core/src/authority/authority_test_utils.rs @@ -1,20 +1,21 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::default::Default; use fastcrypto::{hash::MultisetHash, traits::KeyPair}; -use move_core_types::account_address::AccountAddress; -use move_symbol_pool::Symbol; -use sui_move_build::{BuildConfig, CompiledPackage}; -use sui_types::{ +use iota_move_build::{BuildConfig, CompiledPackage}; +use iota_types::{ crypto::{AccountKeyPair, AuthorityKeyPair, Signature}, messages_consensus::ConsensusTransaction, move_package::UpgradePolicy, programmable_transaction_builder::ProgrammableTransactionBuilder, utils::to_sender_signed_transaction, }; +use move_core_types::account_address::AccountAddress; +use move_symbol_pool::Symbol; use super::{test_authority_builder::TestAuthorityBuilder, *}; use crate::{checkpoints::CheckpointServiceNoop, consensus_handler::SequencedConsensusTransaction}; @@ -22,7 +23,7 @@ use crate::{checkpoints::CheckpointServiceNoop, consensus_handler::SequencedCons pub async fn send_and_confirm_transaction( authority: &AuthorityState, transaction: Transaction, -) -> Result<(CertifiedTransaction, SignedTransactionEffects), SuiError> { +) -> Result<(CertifiedTransaction, SignedTransactionEffects), IotaError> { send_and_confirm_transaction_( authority, None, // no fullnode_key_pair @@ -36,7 +37,7 @@ pub async fn send_and_confirm_transaction_( fullnode: Option<&AuthorityState>, transaction: Transaction, with_shared: bool, // transaction includes shared objects -) -> Result<(CertifiedTransaction, SignedTransactionEffects), SuiError> { +) -> Result<(CertifiedTransaction, SignedTransactionEffects), IotaError> { let (txn, effects, _execution_error_opt) = send_and_confirm_transaction_with_execution_error( authority, fullnode, @@ -50,7 +51,7 @@ pub async fn send_and_confirm_transaction_( pub async fn certify_transaction( authority: &AuthorityState, transaction: Transaction, -) -> Result { +) -> Result { // Make the initial request let epoch_store = authority.load_epoch_store_one_call_per_task(); let transaction = epoch_store.verify_transaction(transaction).unwrap(); @@ -80,7 +81,7 @@ pub async fn execute_certificate_with_execution_error( SignedTransactionEffects, Option, ), - SuiError, + IotaError, > { let epoch_store = authority.load_epoch_store_one_call_per_task(); // We also check the incremental effects of the transaction on the live object @@ -136,14 +137,14 @@ pub async fn send_and_confirm_transaction_with_execution_error( SignedTransactionEffects, Option, ), - SuiError, + IotaError, > { let certificate = certify_transaction(authority, transaction).await?; execute_certificate_with_execution_error(authority, fullnode, certificate, with_shared).await } pub async fn init_state_validator_with_fullnode() -> (Arc, Arc) { - use sui_types::crypto::get_authority_key_pair; + use iota_types::crypto::get_authority_key_pair; let validator = TestAuthorityBuilder::new().build().await; let fullnode_key_pair = get_authority_key_pair().1; @@ -164,7 +165,7 @@ pub async fn init_state_with_committee( .await } -pub async fn init_state_with_ids>( +pub async fn init_state_with_ids>( objects: I, ) -> Arc { let state = TestAuthorityBuilder::new().build().await; @@ -177,7 +178,7 @@ pub async fn init_state_with_ids> } pub async fn init_state_with_ids_and_versions< - I: IntoIterator, + I: IntoIterator, >( objects: I, ) -> Arc { @@ -193,7 +194,8 @@ pub async fn init_state_with_objects>( objects: I, ) -> Arc { let dir = tempfile::TempDir::new().unwrap(); - let network_config = sui_swarm_config::network_config_builder::ConfigBuilder::new(&dir).build(); + let network_config = + iota_swarm_config::network_config_builder::ConfigBuilder::new(&dir).build(); let genesis = network_config.genesis; let keypair = network_config.validator_configs[0] .protocol_key_pair() @@ -214,14 +216,14 @@ pub async fn init_state_with_objects_and_committee Arc { init_state_with_ids(std::iter::once((address, object))).await } pub async fn init_state_with_ids_and_expensive_checks< - I: IntoIterator, + I: IntoIterator, >( objects: I, config: ExpensiveSafetyCheckConfig, @@ -240,9 +242,9 @@ pub async fn init_state_with_ids_and_expensive_checks< pub fn init_transfer_transaction( authority_state: &AuthorityState, - sender: SuiAddress, + sender: IotaAddress, secret: &AccountKeyPair, - recipient: SuiAddress, + recipient: IotaAddress, object_ref: ObjectRef, gas_object_ref: ObjectRef, gas_budget: u64, @@ -264,9 +266,9 @@ pub fn init_transfer_transaction( } pub fn init_certified_transfer_transaction( - sender: SuiAddress, + sender: IotaAddress, secret: &AccountKeyPair, - recipient: SuiAddress, + recipient: IotaAddress, object_ref: ObjectRef, gas_object_ref: ObjectRef, authority_state: &AuthorityState, @@ -311,7 +313,7 @@ pub fn init_certified_transaction( pub async fn certify_shared_obj_transaction_no_execution( authority: &AuthorityState, transaction: Transaction, -) -> Result { +) -> Result { let epoch_store = authority.load_epoch_store_one_call_per_task(); let transaction = epoch_store.verify_transaction(transaction).unwrap(); let response = authority @@ -335,7 +337,7 @@ pub async fn certify_shared_obj_transaction_no_execution( pub async fn enqueue_all_and_execute_all( authority: &AuthorityState, certificates: Vec, -) -> Result, SuiError> { +) -> Result, IotaError> { authority.enqueue_certificates_for_execution( certificates.clone(), &authority.epoch_store_for_testing(), @@ -351,7 +353,7 @@ pub async fn enqueue_all_and_execute_all( pub async fn execute_sequenced_certificate_to_effects( authority: &AuthorityState, certificate: VerifiedCertificate, -) -> Result<(TransactionEffects, Option), SuiError> { +) -> Result<(TransactionEffects, Option), IotaError> { authority.enqueue_certificates_for_execution( vec![certificate.clone()], &authority.epoch_store_for_testing(), @@ -450,13 +452,13 @@ pub fn build_test_modules_with_dep_addr( /// version (if there were upgrades). pub async fn publish_package_on_single_authority( path: PathBuf, - sender: SuiAddress, + sender: IotaAddress, sender_key: &dyn Signer, gas_payment: ObjectRef, dep_original_addresses: impl IntoIterator, dep_ids: Vec, state: &Arc, -) -> SuiResult<(ObjectID, ObjectRef)> { +) -> IotaResult<(ObjectID, ObjectRef)> { let mut build_config = BuildConfig::new_for_testing(); for (addr_name, obj_id) in dep_original_addresses { build_config @@ -503,7 +505,7 @@ pub async fn publish_package_on_single_authority( pub async fn upgrade_package_on_single_authority( path: PathBuf, - sender: SuiAddress, + sender: IotaAddress, sender_key: &dyn Signer, gas_payment: ObjectRef, package_id: ObjectID, @@ -511,7 +513,7 @@ pub async fn upgrade_package_on_single_authority( dep_original_addresses: impl IntoIterator, dep_id_mapping: impl IntoIterator, state: &Arc, -) -> SuiResult { +) -> IotaResult { let package = build_test_modules_with_dep_addr(path, dep_original_addresses, dep_id_mapping); let with_unpublished_deps = false; diff --git a/crates/sui-core/src/authority/epoch_start_configuration.rs b/crates/iota-core/src/authority/epoch_start_configuration.rs similarity index 98% rename from crates/sui-core/src/authority/epoch_start_configuration.rs rename to crates/iota-core/src/authority/epoch_start_configuration.rs index f46b7ab0b78..025f44ff2f9 100644 --- a/crates/sui-core/src/authority/epoch_start_configuration.rs +++ b/crates/iota-core/src/authority/epoch_start_configuration.rs @@ -1,23 +1,24 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::fmt; use enum_dispatch::enum_dispatch; -use serde::{Deserialize, Serialize}; -use sui_types::{ +use iota_types::{ authenticator_state::get_authenticator_state_obj_initial_shared_version, base_types::SequenceNumber, deny_list::get_deny_list_obj_initial_shared_version, epoch_data::EpochData, - error::SuiResult, + error::IotaResult, + iota_system_state::epoch_start_iota_system_state::{ + EpochStartSystemState, EpochStartSystemStateTrait, + }, messages_checkpoint::{CheckpointDigest, CheckpointTimestamp}, randomness_state::get_randomness_state_obj_initial_shared_version, storage::ObjectStore, - sui_system_state::epoch_start_sui_system_state::{ - EpochStartSystemState, EpochStartSystemStateTrait, - }, }; +use serde::{Deserialize, Serialize}; #[enum_dispatch] pub trait EpochStartConfigTrait { @@ -53,7 +54,7 @@ impl EpochStartConfiguration { epoch_digest: CheckpointDigest, object_store: &dyn ObjectStore, initial_epoch_flags: Option>, - ) -> SuiResult { + ) -> IotaResult { let authenticator_obj_initial_shared_version = get_authenticator_state_obj_initial_shared_version(object_store)?; let randomness_obj_initial_shared_version = diff --git a/crates/sui-core/src/authority/shared_object_version_manager.rs b/crates/iota-core/src/authority/shared_object_version_manager.rs similarity index 93% rename from crates/sui-core/src/authority/shared_object_version_manager.rs rename to crates/iota-core/src/authority/shared_object_version_manager.rs index c3f01f0ad8d..837bcc780b1 100644 --- a/crates/sui-core/src/authority/shared_object_version_manager.rs +++ b/crates/iota-core/src/authority/shared_object_version_manager.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::HashMap; -use sui_types::{ +use iota_types::{ base_types::{ObjectID, SequenceNumber}, crypto::RandomnessRound, effects::{TransactionEffects, TransactionEffectsAPI}, - error::SuiResult, + error::IotaResult, executable_transaction::VerifiedExecutableTransaction, storage::{transaction_input_object_keys, transaction_receiving_object_keys, ObjectKey}, transaction::{SenderSignedData, SharedInputObject, TransactionDataAPI, TransactionKey}, - SUI_RANDOMNESS_STATE_OBJECT_ID, + IOTA_RANDOMNESS_STATE_OBJECT_ID, }; use tracing::{debug, trace}; @@ -37,7 +38,7 @@ impl SharedObjVerManager { cache_reader: &dyn ExecutionCacheRead, certificates: &[VerifiedExecutableTransaction], randomness_round: Option, - ) -> SuiResult { + ) -> IotaResult { let mut shared_input_next_versions = get_or_init_versions( certificates.iter().map(|cert| cert.data()), epoch_store, @@ -53,7 +54,7 @@ impl SharedObjVerManager { if let Some(round) = randomness_round { // If we're generating randomness, update the randomness state object version. let version = shared_input_next_versions - .get_mut(&SUI_RANDOMNESS_STATE_OBJECT_ID) + .get_mut(&IOTA_RANDOMNESS_STATE_OBJECT_ID) .expect("randomness state object must have been added in get_or_init_versions()"); debug!( "assigning shared object versions for randomness: epoch {}, round {round:?} -> version {version:?}", @@ -61,7 +62,7 @@ impl SharedObjVerManager { ); assigned_versions.push(( TransactionKey::RandomnessRound(epoch_store.epoch(), round), - vec![(SUI_RANDOMNESS_STATE_OBJECT_ID, *version)], + vec![(IOTA_RANDOMNESS_STATE_OBJECT_ID, *version)], )); version.increment(); } @@ -84,7 +85,7 @@ impl SharedObjVerManager { certs_and_effects: &[(&VerifiedExecutableTransaction, &TransactionEffects)], epoch_store: &AuthorityPerEpochStore, cache_reader: &dyn ExecutionCacheRead, - ) -> SuiResult { + ) -> IotaResult { // We don't care about the results since we can use effects to assign versions. // But we must call it to make sure whenever a shared object is touched the // first time during an epoch, either through consensus or through @@ -124,7 +125,7 @@ async fn get_or_init_versions( epoch_store: &AuthorityPerEpochStore, cache_reader: &dyn ExecutionCacheRead, generate_randomness: bool, -) -> SuiResult> { +) -> IotaResult> { let mut shared_input_objects: Vec<_> = transactions .flat_map(|tx| { tx.transaction_data() @@ -136,7 +137,7 @@ async fn get_or_init_versions( if generate_randomness { shared_input_objects.push(( - SUI_RANDOMNESS_STATE_OBJECT_ID, + IOTA_RANDOMNESS_STATE_OBJECT_ID, epoch_store .epoch_start_config() .randomness_obj_initial_shared_version() @@ -211,10 +212,9 @@ fn assign_versions_for_certificate( mod tests { use std::collections::{BTreeMap, HashMap}; - use shared_crypto::intent::Intent; - use sui_test_transaction_builder::TestTransactionBuilder; - use sui_types::{ - base_types::{ObjectID, SequenceNumber, SuiAddress}, + use iota_test_transaction_builder::TestTransactionBuilder; + use iota_types::{ + base_types::{IotaAddress, ObjectID, SequenceNumber}, crypto::RandomnessRound, digests::ObjectDigest, effects::TestEffectsBuilder, @@ -224,8 +224,9 @@ mod tests { object::{Object, Owner}, programmable_transaction_builder::ProgrammableTransactionBuilder, transaction::{ObjectArg, SenderSignedData, TransactionKey}, - SUI_RANDOMNESS_STATE_OBJECT_ID, + IOTA_RANDOMNESS_STATE_OBJECT_ID, }; + use shared_crypto::intent::Intent; use crate::authority::{ epoch_start_configuration::EpochStartConfigTrait, @@ -304,7 +305,7 @@ mod tests { .unwrap(); let certs = vec![ generate_shared_obj_tx_with_gas_version( - SUI_RANDOMNESS_STATE_OBJECT_ID, + IOTA_RANDOMNESS_STATE_OBJECT_ID, randomness_obj_version, // This can only be false since it's not allowed to use randomness object with // mutable=true. @@ -312,7 +313,7 @@ mod tests { 3, ), generate_shared_obj_tx_with_gas_version( - SUI_RANDOMNESS_STATE_OBJECT_ID, + IOTA_RANDOMNESS_STATE_OBJECT_ID, randomness_obj_version, false, 5, @@ -332,7 +333,7 @@ mod tests { // Check that the randomness object's next version is initialized. assert_eq!( epoch_store - .get_next_object_version(&SUI_RANDOMNESS_STATE_OBJECT_ID) + .get_next_object_version(&IOTA_RANDOMNESS_STATE_OBJECT_ID) .unwrap(), randomness_obj_version ); @@ -340,26 +341,26 @@ mod tests { assert_eq!( shared_input_next_versions, // Randomness object's version is only incremented by 1 regardless of lamport version. - HashMap::from([(SUI_RANDOMNESS_STATE_OBJECT_ID, next_randomness_obj_version)]) + HashMap::from([(IOTA_RANDOMNESS_STATE_OBJECT_ID, next_randomness_obj_version)]) ); assert_eq!( assigned_versions, vec![ ( TransactionKey::RandomnessRound(0, RandomnessRound::new(1)), - vec![(SUI_RANDOMNESS_STATE_OBJECT_ID, randomness_obj_version),] + vec![(IOTA_RANDOMNESS_STATE_OBJECT_ID, randomness_obj_version),] ), ( certs[0].key(), // It is critical that the randomness object version is updated before the // assignment. - vec![(SUI_RANDOMNESS_STATE_OBJECT_ID, next_randomness_obj_version)] + vec![(IOTA_RANDOMNESS_STATE_OBJECT_ID, next_randomness_obj_version)] ), ( certs[1].key(), // It is critical that the randomness object version is updated before the // assignment. - vec![(SUI_RANDOMNESS_STATE_OBJECT_ID, next_randomness_obj_version)] + vec![(IOTA_RANDOMNESS_STATE_OBJECT_ID, next_randomness_obj_version)] ), ] ); @@ -446,7 +447,7 @@ mod tests { }) .unwrap(); let tx_data = TestTransactionBuilder::new( - SuiAddress::ZERO, + IotaAddress::ZERO, ( ObjectID::random(), SequenceNumber::from_u64(gas_object_version), @@ -456,7 +457,7 @@ mod tests { ) .programmable(builder.finish()) .build(); - let tx = SenderSignedData::new(tx_data, Intent::sui_transaction(), vec![]); + let tx = SenderSignedData::new(tx_data, Intent::iota_transaction(), vec![]); VerifiedExecutableTransaction::new_unchecked(ExecutableTransaction::new_from_data_and_sig( tx, CertificateProof::new_system(0), diff --git a/crates/sui-core/src/authority/test_authority_builder.rs b/crates/iota-core/src/authority/test_authority_builder.rs similarity index 95% rename from crates/sui-core/src/authority/test_authority_builder.rs rename to crates/iota-core/src/authority/test_authority_builder.rs index 570b5892f45..da3f2b18d8e 100644 --- a/crates/sui-core/src/authority/test_authority_builder.rs +++ b/crates/iota-core/src/authority/test_authority_builder.rs @@ -1,12 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{path::PathBuf, sync::Arc}; use fastcrypto::traits::KeyPair; -use prometheus::Registry; -use sui_archival::reader::ArchiveReaderBalancer; -use sui_config::{ +use iota_archival::reader::ArchiveReaderBalancer; +use iota_config::{ certificate_deny_config::CertificateDenyConfig, genesis::Genesis, node::{ @@ -15,19 +15,20 @@ use sui_config::{ }, transaction_deny_config::TransactionDenyConfig, }; -use sui_macros::nondeterministic; -use sui_protocol_config::{ProtocolConfig, SupportedProtocolVersions}; -use sui_storage::IndexStore; -use sui_swarm_config::{genesis_config::AccountConfig, network_config::NetworkConfig}; -use sui_types::{ +use iota_macros::nondeterministic; +use iota_protocol_config::{ProtocolConfig, SupportedProtocolVersions}; +use iota_storage::IndexStore; +use iota_swarm_config::{genesis_config::AccountConfig, network_config::NetworkConfig}; +use iota_types::{ base_types::{AuthorityName, ObjectID}, crypto::AuthorityKeyPair, digests::ChainIdentifier, executable_transaction::VerifiedExecutableTransaction, + iota_system_state::IotaSystemStateTrait, object::Object, - sui_system_state::SuiSystemStateTrait, transaction::VerifiedTransaction, }; +use prometheus::Registry; use tempfile::tempdir; use crate::{ @@ -161,7 +162,7 @@ impl<'a> TestAuthorityBuilder<'a> { pub async fn build(self) -> Arc { let mut local_network_config_builder = - sui_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir() + iota_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir() .with_accounts(self.accounts) .with_reference_gas_price(self.reference_gas_price.unwrap_or(500)); if let Some(protocol_config) = &self.protocol_config { @@ -216,7 +217,7 @@ impl<'a> TestAuthorityBuilder<'a> { }) }; let epoch_start_configuration = EpochStartConfiguration::new( - genesis.sui_system_object().into_epoch_start_state(), + genesis.iota_system_object().into_epoch_start_state(), *genesis.checkpoint().digest(), &genesis.objects(), None, diff --git a/crates/sui-core/src/authority_aggregator.rs b/crates/iota-core/src/authority_aggregator.rs similarity index 96% rename from crates/sui-core/src/authority_aggregator.rs rename to crates/iota-core/src/authority_aggregator.rs index a7e86b8c1bd..7346d29835c 100644 --- a/crates/sui-core/src/authority_aggregator.rs +++ b/crates/iota-core/src/authority_aggregator.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -12,19 +13,13 @@ use std::{ use fastcrypto::traits::ToFromBytes; use futures::{future::BoxFuture, stream::FuturesUnordered, StreamExt}; -use mysten_metrics::{histogram::Histogram, monitored_future, spawn_monitored_task, GaugeGuard}; -use mysten_network::config::Config; -use prometheus::{ - register_int_counter_vec_with_registry, register_int_counter_with_registry, - register_int_gauge_with_registry, IntCounter, IntCounterVec, IntGauge, Registry, -}; -use sui_authority_aggregation::{quorum_map_then_reduce_with_timeout, AsyncResult, ReduceOutput}; -use sui_config::genesis::Genesis; -use sui_network::{ +use iota_authority_aggregation::{quorum_map_then_reduce_with_timeout, AsyncResult, ReduceOutput}; +use iota_config::genesis::Genesis; +use iota_network::{ default_mysten_network_config, DEFAULT_CONNECT_TIMEOUT_SEC, DEFAULT_REQUEST_TIMEOUT_SEC, }; -use sui_swarm_config::network_config::NetworkConfig; -use sui_types::{ +use iota_swarm_config::network_config::NetworkConfig; +use iota_types::{ base_types::*, committee::{ Committee, CommitteeTrait, CommitteeWithNetworkMetadata, ProtocolVersion, StakeUnit, @@ -34,8 +29,9 @@ use sui_types::{ CertifiedTransactionEffects, SignedTransactionEffects, TransactionEffects, TransactionEvents, VerifiedCertifiedTransactionEffects, }, - error::{SuiError, SuiResult, UserInputError}, + error::{IotaError, IotaResult, UserInputError}, fp_ensure, + iota_system_state::{IotaSystemState, IotaSystemStateTrait}, message_envelope::Message, messages_grpc::{ HandleCertificateResponseV2, LayoutGenerationOption, ObjectInfoRequest, @@ -44,9 +40,14 @@ use sui_types::{ messages_safe_client::PlainTransactionInfoResponse, object::Object, quorum_driver_types::GroupedErrors, - sui_system_state::{SuiSystemState, SuiSystemStateTrait}, transaction::*, }; +use mysten_metrics::{histogram::Histogram, monitored_future, spawn_monitored_task, GaugeGuard}; +use mysten_network::config::Config; +use prometheus::{ + register_int_counter_vec_with_registry, register_int_counter_with_registry, + register_int_gauge_with_registry, IntCounter, IntCounterVec, IntGauge, Registry, +}; use thiserror::Error; use tokio::time::{sleep, timeout}; use tracing::{debug, error, info, trace, warn, Instrument}; @@ -278,7 +279,7 @@ pub enum AggregatorProcessCertificateError { RetryableExecuteCertificate { retryable_errors: GroupedErrors }, } -pub fn group_errors(errors: Vec<(SuiError, Vec, StakeUnit)>) -> GroupedErrors { +pub fn group_errors(errors: Vec<(IotaError, Vec, StakeUnit)>) -> GroupedErrors { let mut grouped_errors = HashMap::new(); for (error, names, stake) in errors { let entry = grouped_errors.entry(error).or_insert((0, vec![])); @@ -302,10 +303,10 @@ struct ProcessTransactionState { tx_signatures: StakeAggregator, effects_map: MultiStakeAggregator, // The list of errors gathered at any point - errors: Vec<(SuiError, Vec, StakeUnit)>, + errors: Vec<(IotaError, Vec, StakeUnit)>, // This is exclusively non-retryable stake. non_retryable_stake: StakeUnit, - // This includes both object and package not found sui errors. + // This includes both object and package not found iota errors. object_or_package_not_found_stake: StakeUnit, // Validators that are overloaded with txns pending execution. overloaded_stake: StakeUnit, @@ -347,9 +348,9 @@ impl ProcessTransactionState { &mut self, validator_name: AuthorityName, weight: StakeUnit, - err: &SuiError, + err: &IotaError, ) -> bool { - if let SuiError::ObjectLockConflict { + if let IotaError::ObjectLockConflict { obj_ref, pending_transaction: transaction, } = err @@ -376,7 +377,7 @@ impl ProcessTransactionState { // In some edge cases, the client may send the same transaction multiple times // but with different user signatures. When this happens, the "minority" // tx will fail in safe_client because the certificate verification would fail - // and return Sui::FailedToVerifyTxCertWithExecutedEffects. + // and return Iota::FailedToVerifyTxCertWithExecutedEffects. // Here, we check if there are f+1 validators return this error. If so, the // transaction is already finalized with a different set of user // signatures. It's not trivial to return the results of that successful @@ -387,7 +388,7 @@ impl ProcessTransactionState { .errors .iter() .filter_map(|(e, _, stake)| { - if matches!(e, SuiError::FailedToVerifyTxCertWithExecutedEffects { .. }) { + if matches!(e, IotaError::FailedToVerifyTxCertWithExecutedEffects { .. }) { Some(stake) } else { None @@ -405,8 +406,8 @@ struct ProcessCertificateState { effects_map: MultiStakeAggregator<(EpochId, TransactionEffectsDigest), TransactionEffects, true>, non_retryable_stake: StakeUnit, - non_retryable_errors: Vec<(SuiError, Vec, StakeUnit)>, - retryable_errors: Vec<(SuiError, Vec, StakeUnit)>, + non_retryable_errors: Vec<(IotaError, Vec, StakeUnit)>, + retryable_errors: Vec<(IotaError, Vec, StakeUnit)>, // As long as none of the exit criteria are met we consider the state retryable // 1) >= 2f+1 signatures // 2) >= f+1 non-retryable errors @@ -437,7 +438,7 @@ impl ProcessTransactionResult { #[derive(Clone)] pub struct AuthorityAggregator { - /// Our Sui committee. + /// Our Iota committee. pub committee: Arc, /// For more human readable metrics reporting. /// It's OK for this map to be empty or missing validators, it then defaults @@ -531,10 +532,10 @@ impl AuthorityAggregator { committee: CommitteeWithNetworkMetadata, network_config: &Config, disallow_missing_intermediate_committees: bool, - ) -> SuiResult> { + ) -> IotaResult> { let network_clients = make_network_authority_clients_with_network_config(&committee, network_config) - .map_err(|err| SuiError::GenericAuthorityError { + .map_err(|err| IotaError::GenericAuthorityError { error: format!( "Failed to make authority clients from committee {committee}, err: {:?}", err @@ -563,7 +564,7 @@ impl AuthorityAggregator { if disallow_missing_intermediate_committees { fp_ensure!( self.committee.epoch + 1 == new_committee.epoch, - SuiError::AdvanceEpochError { + IotaError::AdvanceEpochError { error: format!( "Trying to advance from epoch {} to epoch {}", self.committee.epoch, new_committee.epoch @@ -654,10 +655,10 @@ impl AuthorityAggregator { // consistency. Instead of this function use // AuthorityEpochStore::epoch_start_configuration() to access this object // everywhere besides when we are reading fields for the current epoch - let sui_system_state = store.get_sui_system_state_object_unsafe()?; - let committee = sui_system_state.get_current_epoch_committee(); - let validator_display_names = sui_system_state - .into_sui_system_state_summary() + let iota_system_state = store.get_iota_system_state_object_unsafe()?; + let committee = iota_system_state.get_current_epoch_committee(); + let validator_display_names = iota_system_state + .into_iota_system_state_summary() .active_validators .into_iter() .filter_map(|s| { @@ -718,10 +719,10 @@ where // and authority client parameter and returns a Result. map_each_authority: FMap, timeout_each_authority: Duration, - authority_errors: &mut HashMap, - ) -> Result + authority_errors: &mut HashMap, + ) -> Result where - FMap: Fn(AuthorityName, Arc>) -> AsyncResult<'a, S, SuiError> + FMap: Fn(AuthorityName, Arc>) -> AsyncResult<'a, S, IotaError> + Send + Clone + 'a, @@ -733,7 +734,7 @@ where let authorities_shuffled = self.committee.shuffle_by_stake(preferences, restrict_to); let mut authorities_shuffled = authorities_shuffled.iter(); - type RequestResult = Result, tokio::time::error::Elapsed>; + type RequestResult = Result, tokio::time::error::Elapsed>; enum Event { StartNext, @@ -787,7 +788,7 @@ where ?restrict_to, "Available authorities list is empty." ); - SuiError::from("Available authorities list is empty") + IotaError::from("Available authorities list is empty") })?; futures.push(start_req(*name, self.authority_clients[name].clone())); futures.push(schedule_next()); @@ -803,7 +804,7 @@ where // timeout Err(_) => { debug!(name=?name.concise(), "authority request timed out"); - authority_errors.insert(name, SuiError::TimeoutError); + authority_errors.insert(name, IotaError::TimeoutError); } // request completed Ok(inner_res) => { @@ -857,9 +858,9 @@ where timeout_total: Option, // The behavior that authorities expect to perform, used for logging and error description: String, - ) -> Result + ) -> Result where - FMap: Fn(AuthorityName, Arc>) -> AsyncResult<'a, S, SuiError> + FMap: Fn(AuthorityName, Arc>) -> AsyncResult<'a, S, IotaError> + Send + Clone + 'a, @@ -878,9 +879,9 @@ where if let Some(t) = timeout_total { timeout(t, fut).await.map_err(|_timeout_error| { if authority_errors.is_empty() { - SuiError::TimeoutError + IotaError::TimeoutError } else { - SuiError::TooManyIncorrectAuthorities { + IotaError::TooManyIncorrectAuthorities { errors: authority_errors .iter() .map(|(a, b)| (*a, b.clone())) @@ -903,7 +904,7 @@ where pub async fn get_latest_object_version_for_testing( &self, object_id: ObjectID, - ) -> SuiResult { + ) -> IotaResult { #[derive(Debug, Default)] struct State { latest_object_version: Option, @@ -950,7 +951,7 @@ where // A long timeout before we hear back from a quorum self.timeouts.pre_quorum_timeout, ) - .await.map_err(|_state| SuiError::from(UserInputError::ObjectNotFound { + .await.map_err(|_state| IotaError::from(UserInputError::ObjectNotFound { object_id, version: None, }))?; @@ -962,10 +963,10 @@ where /// It should only be used for testing or benchmarking. pub async fn get_latest_system_state_object_for_testing( &self, - ) -> anyhow::Result { + ) -> anyhow::Result { #[derive(Debug, Default)] struct State { - latest_system_state: Option, + latest_system_state: Option, total_weight: StakeUnit, } let initial_state = State::default(); @@ -1174,9 +1175,9 @@ where fn record_rpc_error_maybe( metrics: Arc, display_name: &String, - error: &SuiError, + error: &IotaError, ) { - if let SuiError::RpcError(_message, code) = error { + if let IotaError::RpcError(_message, code) = error { metrics .total_rpc_err .with_label_values(&[display_name, code.as_str()]) @@ -1303,10 +1304,10 @@ where &self, tx_digest: &TransactionDigest, state: &mut ProcessTransactionState, - response: SuiResult, + response: IotaResult, name: AuthorityName, weight: StakeUnit, - ) -> SuiResult> { + ) -> IotaResult> { match response { Ok(PlainTransactionInfoResponse::Signed(signed)) => { debug!(?tx_digest, name=?name.concise(), weight, "Received signed transaction from validator handle_transaction"); @@ -1328,7 +1329,7 @@ where &self, state: &mut ProcessTransactionState, plain_tx: SignedTransaction, - ) -> SuiResult> { + ) -> IotaResult> { match state.tx_signatures.insert(plain_tx.clone()) { InsertResult::NotEnoughVotes { bad_votes, @@ -1337,7 +1338,7 @@ where state.non_retryable_stake += bad_votes; if bad_votes > 0 { state.errors.push(( - SuiError::InvalidSignature { + IotaError::InvalidSignature { error: "Individual signature verification failed".to_string(), }, bad_authorities, @@ -1362,7 +1363,7 @@ where certificate: Option, plain_tx_effects: SignedTransactionEffects, events: TransactionEvents, - ) -> SuiResult> { + ) -> IotaResult> { match certificate { Some(certificate) if certificate.epoch() == self.committee.epoch => { // If we get a certificate in the same epoch, then we use it. @@ -1384,7 +1385,7 @@ where state.non_retryable_stake += bad_votes; if bad_votes > 0 { state.errors.push(( - SuiError::InvalidSignature { + IotaError::InvalidSignature { error: "Individual signature verification failed".to_string(), }, bad_authorities, @@ -1458,7 +1459,7 @@ where // the non-quorum effects in the final error if state is no longer // retryable state.errors.push(( - SuiError::QuorumFailedToGetEffectsQuorumWhenProcessingTransaction { + IotaError::QuorumFailedToGetEffectsQuorumWhenProcessingTransaction { effects_map: non_quorum_effects, }, involved_validators, @@ -1591,12 +1592,12 @@ where ); // record errors and tx retryable state - for (sui_err, _, _) in state.retryable_errors.iter().chain(state.non_retryable_errors.iter()) { + for (iota_err, _, _) in state.retryable_errors.iter().chain(state.non_retryable_errors.iter()) { self .metrics .total_aggregated_err .with_label_values(&[ - sui_err.as_ref(), + iota_err.as_ref(), if state.retryable { "recoverable" } else { @@ -1648,9 +1649,9 @@ where committee: Arc, tx_digest: &TransactionDigest, state: &mut ProcessCertificateState, - response: SuiResult, + response: IotaResult, name: AuthorityName, - ) -> SuiResult> { + ) -> IotaResult> { match response { Ok(HandleCertificateResponseV2 { signed_effects, @@ -1675,7 +1676,7 @@ where state.non_retryable_stake += bad_votes; if bad_votes > 0 { state.non_retryable_errors.push(( - SuiError::InvalidSignature { + IotaError::InvalidSignature { error: "Individual signature verification failed".to_string(), }, bad_authorities, @@ -1736,7 +1737,7 @@ where // authorities known to have the transaction info we are requesting. validators: &BTreeSet, timeout_total: Option, - ) -> SuiResult { + ) -> IotaResult { self.quorum_once_with_timeout( None, Some(validators), diff --git a/crates/sui-core/src/authority_client.rs b/crates/iota-core/src/authority_client.rs similarity index 83% rename from crates/sui-core/src/authority_client.rs rename to crates/iota-core/src/authority_client.rs index d9cb48a8fd2..ebd17050640 100644 --- a/crates/sui-core/src/authority_client.rs +++ b/crates/iota-core/src/authority_client.rs @@ -1,17 +1,18 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, time::Duration}; use anyhow::anyhow; use async_trait::async_trait; -use mysten_network::config::Config; -use sui_network::{api::ValidatorClient, tonic, tonic::transport::Channel}; -use sui_types::{ +use iota_network::{api::ValidatorClient, tonic, tonic::transport::Channel}; +use iota_types::{ base_types::AuthorityName, committee::CommitteeWithNetworkMetadata, - error::SuiError, + error::IotaError, + iota_system_state::IotaSystemState, messages_checkpoint::{ CheckpointRequest, CheckpointRequestV2, CheckpointResponse, CheckpointResponseV2, }, @@ -20,52 +21,52 @@ use sui_types::{ ObjectInfoResponse, SystemStateRequest, TransactionInfoRequest, TransactionInfoResponse, }, multiaddr::Multiaddr, - sui_system_state::SuiSystemState, transaction::*, }; +use mysten_network::config::Config; #[async_trait] pub trait AuthorityAPI { - /// Initiate a new transaction to a Sui or Primary account. + /// Initiate a new transaction to a Iota or Primary account. async fn handle_transaction( &self, transaction: Transaction, - ) -> Result; + ) -> Result; /// Execute a certificate. async fn handle_certificate_v2( &self, certificate: CertifiedTransaction, - ) -> Result; + ) -> Result; /// Handle Object information requests for this account. async fn handle_object_info_request( &self, request: ObjectInfoRequest, - ) -> Result; + ) -> Result; /// Handle Object information requests for this account. async fn handle_transaction_info_request( &self, request: TransactionInfoRequest, - ) -> Result; + ) -> Result; async fn handle_checkpoint( &self, request: CheckpointRequest, - ) -> Result; + ) -> Result; async fn handle_checkpoint_v2( &self, request: CheckpointRequestV2, - ) -> Result; + ) -> Result; // This API is exclusively used by the benchmark code. // Hence it's OK to return a fixed system state type. async fn handle_system_state_object( &self, request: SystemStateRequest, - ) -> Result; + ) -> Result; } #[derive(Clone)] @@ -100,11 +101,11 @@ impl NetworkAuthorityClient { #[async_trait] impl AuthorityAPI for NetworkAuthorityClient { - /// Initiate a new transfer to a Sui or Primary account. + /// Initiate a new transfer to a Iota or Primary account. async fn handle_transaction( &self, transaction: Transaction, - ) -> Result { + ) -> Result { self.client() .transaction(transaction) .await @@ -116,7 +117,7 @@ impl AuthorityAPI for NetworkAuthorityClient { async fn handle_certificate_v2( &self, certificate: CertifiedTransaction, - ) -> Result { + ) -> Result { let response = self .client() .handle_certificate_v2(certificate.clone()) @@ -129,7 +130,7 @@ impl AuthorityAPI for NetworkAuthorityClient { async fn handle_object_info_request( &self, request: ObjectInfoRequest, - ) -> Result { + ) -> Result { self.client() .object_info(request) .await @@ -141,7 +142,7 @@ impl AuthorityAPI for NetworkAuthorityClient { async fn handle_transaction_info_request( &self, request: TransactionInfoRequest, - ) -> Result { + ) -> Result { self.client() .transaction_info(request) .await @@ -153,7 +154,7 @@ impl AuthorityAPI for NetworkAuthorityClient { async fn handle_checkpoint( &self, request: CheckpointRequest, - ) -> Result { + ) -> Result { self.client() .checkpoint(request) .await @@ -165,7 +166,7 @@ impl AuthorityAPI for NetworkAuthorityClient { async fn handle_checkpoint_v2( &self, request: CheckpointRequestV2, - ) -> Result { + ) -> Result { self.client() .checkpoint_v2(request) .await @@ -176,7 +177,7 @@ impl AuthorityAPI for NetworkAuthorityClient { async fn handle_system_state_object( &self, request: SystemStateRequest, - ) -> Result { + ) -> Result { self.client() .get_system_state_object(request) .await @@ -195,7 +196,7 @@ pub fn make_network_authority_clients_with_network_config( .network_metadata .get(name) .ok_or_else(|| { - SuiError::from("Missing network metadata in CommitteeWithNetworkMetadata") + IotaError::from("Missing network metadata in CommitteeWithNetworkMetadata") })? .network_address; let channel = network_config diff --git a/crates/sui-core/src/authority_server.rs b/crates/iota-core/src/authority_server.rs similarity index 96% rename from crates/sui-core/src/authority_server.rs rename to crates/iota-core/src/authority_server.rs index fec4e6620b3..2111fc0df7f 100644 --- a/crates/sui-core/src/authority_server.rs +++ b/crates/iota-core/src/authority_server.rs @@ -1,25 +1,21 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{io, sync::Arc}; use anyhow::Result; use async_trait::async_trait; -use mysten_metrics::{histogram::Histogram as MystenHistogram, spawn_monitored_task}; -use narwhal_worker::LazyNarwhalClient; -use prometheus::{ - register_int_counter_vec_with_registry, register_int_counter_with_registry, IntCounter, - IntCounterVec, Registry, -}; -use sui_network::{ +use iota_network::{ api::{Validator, ValidatorServer}, tonic, }; -use sui_types::{ +use iota_types::{ effects::{TransactionEffectsAPI, TransactionEvents}, error::*, fp_ensure, + iota_system_state::IotaSystemState, message_envelope::Message, messages_checkpoint::{ CheckpointRequest, CheckpointRequestV2, CheckpointResponse, CheckpointResponseV2, @@ -31,9 +27,14 @@ use sui_types::{ TransactionInfoResponse, }, multiaddr::Multiaddr, - sui_system_state::SuiSystemState, transaction::*, }; +use mysten_metrics::{histogram::Histogram as MystenHistogram, spawn_monitored_task}; +use narwhal_worker::LazyNarwhalClient; +use prometheus::{ + register_int_counter_vec_with_registry, register_int_counter_with_registry, IntCounter, + IntCounterVec, Registry, +}; use tap::TapFallible; use tokio::task::JoinHandle; use tracing::{error_span, info, Instrument}; @@ -294,7 +295,7 @@ impl ValidatorService { transaction.validity_check(epoch_store.protocol_config())?; if !epoch_store.protocol_config().zklogin_auth() && transaction.has_zklogin_sig() { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: "zklogin is not enabled on this network".to_string(), } .into()); @@ -303,14 +304,14 @@ impl ValidatorService { if !epoch_store.protocol_config().supports_upgraded_multisig() && transaction.has_upgraded_multisig() { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: "upgraded multisig format not enabled on this network".to_string(), } .into()); } if !epoch_store.randomness_state_enabled() && transaction.is_randomness_reader() { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: "randomness is not enabled on this network".to_string(), } .into()); @@ -337,7 +338,7 @@ impl ValidatorService { .inc(); // TODO: consider change the behavior for other types of overload errors. match error { - SuiError::ValidatorOverloadedRetryAfter { .. } => { + IotaError::ValidatorOverloadedRetryAfter { .. } => { validator_pushback_error = Some(error) } _ => return Err(error.into()), @@ -362,7 +363,7 @@ impl ValidatorService { .instrument(span) .await .tap_err(|e| { - if let SuiError::ValidatorHaltedAtEpochEnd = e { + if let IotaError::ValidatorHaltedAtEpochEnd = e { metrics.num_rejected_tx_in_epoch_boundary.inc(); } })?; @@ -388,13 +389,13 @@ impl ValidatorService { // Fullnode does not serve handle_certificate call. fp_ensure!( !self.state.is_fullnode(&epoch_store), - SuiError::FullNodeCantHandleCertificate.into() + IotaError::FullNodeCantHandleCertificate.into() ); // CRITICAL! Validators should never sign an external system transaction. fp_ensure!( !certificate.is_system_tx(), - SuiError::InvalidSystemTransaction.into() + IotaError::InvalidSystemTransaction.into() ); certificate @@ -466,7 +467,7 @@ impl ValidatorService { let reconfiguration_lock = epoch_store.get_reconfig_state_read_lock_guard(); if !reconfiguration_lock.should_accept_user_certs() { self.metrics.num_rejected_cert_in_epoch_boundary.inc(); - return Err(SuiError::ValidatorHaltedAtEpochEnd.into()); + return Err(IotaError::ValidatorHaltedAtEpochEnd.into()); } // 3) All certificates are sent to consensus (at least by some authorities) @@ -626,11 +627,11 @@ impl Validator for ValidatorService { async fn get_system_state_object( &self, _request: tonic::Request, - ) -> Result, tonic::Status> { + ) -> Result, tonic::Status> { let response = self .state .get_cache_reader() - .get_sui_system_state_object_unsafe()?; + .get_iota_system_state_object_unsafe()?; return Ok(tonic::Response::new(response)); } diff --git a/crates/sui-core/src/checkpoints/causal_order.rs b/crates/iota-core/src/checkpoints/causal_order.rs similarity index 99% rename from crates/sui-core/src/checkpoints/causal_order.rs rename to crates/iota-core/src/checkpoints/causal_order.rs index c6cbc36589c..0d7c6cf5270 100644 --- a/crates/sui-core/src/checkpoints/causal_order.rs +++ b/crates/iota-core/src/checkpoints/causal_order.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::{BTreeMap, BTreeSet, HashMap}; -use sui_types::{ +use iota_types::{ base_types::TransactionDigest, effects::{InputSharedObject, TransactionEffects, TransactionEffectsAPI}, storage::ObjectKey, @@ -219,7 +220,7 @@ impl InsertState { #[cfg(test)] mod tests { - use sui_types::{ + use iota_types::{ base_types::{ObjectDigest, ObjectID, SequenceNumber}, effects::TransactionEffects, }; diff --git a/crates/sui-core/src/checkpoints/checkpoint_executor/data_ingestion_handler.rs b/crates/iota-core/src/checkpoints/checkpoint_executor/data_ingestion_handler.rs similarity index 82% rename from crates/sui-core/src/checkpoints/checkpoint_executor/data_ingestion_handler.rs rename to crates/iota-core/src/checkpoints/checkpoint_executor/data_ingestion_handler.rs index c244c96072f..ffd6be5dbc8 100644 --- a/crates/sui-core/src/checkpoints/checkpoint_executor/data_ingestion_handler.rs +++ b/crates/iota-core/src/checkpoints/checkpoint_executor/data_ingestion_handler.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -7,11 +8,11 @@ use std::{ sync::Arc, }; -use sui_storage::blob::{Blob, BlobEncoding}; -use sui_types::{ +use iota_storage::blob::{Blob, BlobEncoding}; +use iota_types::{ digests::TransactionDigest, effects::TransactionEffectsAPI, - error::{SuiError, SuiResult, UserInputError}, + error::{IotaError, IotaResult, UserInputError}, full_checkpoint_content::{CheckpointData, CheckpointTransaction}, messages_checkpoint::VerifiedCheckpoint, storage::ObjectKey, @@ -25,7 +26,7 @@ pub(crate) fn store_checkpoint_locally( cache_reader: &dyn ExecutionCacheRead, checkpoint_store: Arc, transaction_digests: Vec, -) -> SuiResult { +) -> IotaResult { let checkpoint_contents = checkpoint_store .get_checkpoint_contents(&checkpoint.content_digest)? .expect("checkpoint content has to be stored"); @@ -34,15 +35,15 @@ pub(crate) fn store_checkpoint_locally( .multi_get_transaction_blocks(&transaction_digests)? .into_iter() .zip(&transaction_digests) - .map(|(tx, digest)| tx.ok_or(SuiError::TransactionNotFound { digest: *digest })) - .collect::>>()?; + .map(|(tx, digest)| tx.ok_or(IotaError::TransactionNotFound { digest: *digest })) + .collect::>>()?; let effects = cache_reader .multi_get_executed_effects(&transaction_digests)? .into_iter() .zip(transaction_digests) - .map(|(effects, digest)| effects.ok_or(SuiError::TransactionNotFound { digest })) - .collect::>>()?; + .map(|(effects, digest)| effects.ok_or(IotaError::TransactionNotFound { digest })) + .collect::>>()?; let event_digests = effects .iter() @@ -53,8 +54,10 @@ pub(crate) fn store_checkpoint_locally( .multi_get_events(&event_digests)? .into_iter() .zip(&event_digests) - .map(|(event, digest)| event.ok_or(SuiError::TransactionEventsNotFound { digest: *digest })) - .collect::>>()?; + .map(|(event, digest)| { + event.ok_or(IotaError::TransactionEventsNotFound { digest: *digest }) + }) + .collect::>>()?; let events: HashMap<_, _> = event_digests.into_iter().zip(events).collect(); let mut full_transactions = Vec::with_capacity(transactions.len()); @@ -96,14 +99,14 @@ pub(crate) fn store_checkpoint_locally( .into_iter() .zip(&input_object_keys) .map(|(object, object_key)| { - object.ok_or(SuiError::UserInputError { + object.ok_or(IotaError::UserInputError { error: UserInputError::ObjectNotFound { object_id: object_key.0, version: Some(object_key.1), }, }) }) - .collect::>>()?; + .collect::>>()?; let output_object_keys = fx .all_changed_objects() @@ -116,14 +119,14 @@ pub(crate) fn store_checkpoint_locally( .into_iter() .zip(&output_object_keys) .map(|(object, object_key)| { - object.ok_or(SuiError::UserInputError { + object.ok_or(IotaError::UserInputError { error: UserInputError::ObjectNotFound { object_id: object_key.0, version: Some(object_key.1), }, }) }) - .collect::>>()?; + .collect::>>()?; let full_transaction = CheckpointTransaction { transaction: (*tx).clone().into(), @@ -142,19 +145,19 @@ pub(crate) fn store_checkpoint_locally( }; std::fs::create_dir_all(&path).map_err(|err| { - SuiError::FileIOError(format!( + IotaError::FileIOError(format!( "failed to save full checkpoint content locally {:?}", err )) })?; Blob::encode(&checkpoint_data, BlobEncoding::Bcs) - .map_err(|_| SuiError::TransactionSerializationError { + .map_err(|_| IotaError::TransactionSerializationError { error: "failed to serialize full checkpoint content".to_string(), }) // Map the first error .and_then(|blob| { std::fs::write(path.join(file_name), blob.to_bytes()).map_err(|_| { - SuiError::FileIOError("failed to save full checkpoint content locally".to_string()) + IotaError::FileIOError("failed to save full checkpoint content locally".to_string()) }) })?; diff --git a/crates/iota-core/src/checkpoints/checkpoint_executor/metrics.rs b/crates/iota-core/src/checkpoints/checkpoint_executor/metrics.rs new file mode 100644 index 00000000000..2dacfa5914c --- /dev/null +++ b/crates/iota-core/src/checkpoints/checkpoint_executor/metrics.rs @@ -0,0 +1,105 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::Arc; + +use mysten_metrics::histogram::Histogram; +use prometheus::{ + register_int_counter_with_registry, register_int_gauge_with_registry, IntCounter, IntGauge, + Registry, +}; + +pub struct CheckpointExecutorMetrics { + pub checkpoint_exec_sync_tps: IntGauge, + pub last_executed_checkpoint: IntGauge, + pub last_executed_checkpoint_timestamp_ms: IntGauge, + pub checkpoint_exec_errors: IntCounter, + pub checkpoint_exec_epoch: IntGauge, + pub checkpoint_exec_inflight: IntGauge, + pub checkpoint_exec_latency_us: Histogram, + pub checkpoint_prepare_latency_us: Histogram, + pub checkpoint_transaction_count: Histogram, + pub checkpoint_contents_age_ms: Histogram, + pub last_executed_checkpoint_age_ms: Histogram, + pub accumulator_inconsistent_state: IntGauge, +} + +impl CheckpointExecutorMetrics { + pub fn new(registry: &Registry) -> Arc { + let this = Self { + checkpoint_exec_sync_tps: register_int_gauge_with_registry!( + "checkpoint_exec_sync_tps", + "Checkpoint sync estimated transactions per second", + registry + ) + .unwrap(), + last_executed_checkpoint: register_int_gauge_with_registry!( + "last_executed_checkpoint", + "Last executed checkpoint", + registry + ) + .unwrap(), + last_executed_checkpoint_timestamp_ms: register_int_gauge_with_registry!( + "last_executed_checkpoint_timestamp_ms", + "Last executed checkpoint timestamp ms", + registry + ) + .unwrap(), + checkpoint_exec_errors: register_int_counter_with_registry!( + "checkpoint_exec_errors", + "Checkpoint execution errors count", + registry + ) + .unwrap(), + checkpoint_exec_epoch: register_int_gauge_with_registry!( + "checkpoint_exec_epoch", + "Current epoch number in the checkpoint executor", + registry + ) + .unwrap(), + checkpoint_exec_inflight: register_int_gauge_with_registry!( + "checkpoint_exec_inflight", + "Current number of inflight checkpoints being executed", + registry + ) + .unwrap(), + checkpoint_exec_latency_us: Histogram::new_in_registry( + "checkpoint_exec_latency_us", + "Latency of executing a checkpoint from enqueue to all effects available, in microseconds", + registry, + ), + checkpoint_prepare_latency_us: Histogram::new_in_registry( + "checkpoint_prepare_latency_us", + "Latency of preparing a checkpoint to enqueue for execution, in microseconds", + registry, + ), + checkpoint_transaction_count: Histogram::new_in_registry( + "checkpoint_transaction_count", + "Number of transactions in the checkpoint", + registry, + ), + checkpoint_contents_age_ms: Histogram::new_in_registry( + "checkpoint_contents_age_ms", + "Age of checkpoints when they arrive for execution", + registry, + ), + last_executed_checkpoint_age_ms: Histogram::new_in_registry( + "last_executed_checkpoint_age_ms", + "Age of the last executed checkpoint", + registry + ), + accumulator_inconsistent_state: register_int_gauge_with_registry!( + "accumulator_inconsistent_state", + "1 if accumulated live object set differs from StateAccumulator root state hash for the previous epoch", + registry, + ) + .unwrap(), + }; + Arc::new(this) + } + + pub fn new_for_tests() -> Arc { + Self::new(&Registry::new()) + } +} diff --git a/crates/iota-core/src/checkpoints/checkpoint_executor/mod.rs b/crates/iota-core/src/checkpoints/checkpoint_executor/mod.rs new file mode 100644 index 00000000000..966d2ff3bb4 --- /dev/null +++ b/crates/iota-core/src/checkpoints/checkpoint_executor/mod.rs @@ -0,0 +1,1222 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! CheckpointExecutor is a Node component that executes all checkpoints for the +//! given epoch. It acts as a Consumer to StateSync +//! for newly synced checkpoints, taking these checkpoints and +//! scheduling and monitoring their execution. Its primary goal is to allow +//! for catching up to the current checkpoint sequence number of the network +//! as quickly as possible so that a newly joined, or recovering Node can +//! participate in a timely manner. To that end, CheckpointExecutor attempts +//! to saturate the CPU with executor tasks (one per checkpoint), each of which +//! handle scheduling and awaiting checkpoint transaction execution. +//! +//! CheckpointExecutor is made recoverable in the event of Node shutdown by way +//! of a watermark, highest_executed_checkpoint, which is guaranteed to be +//! updated sequentially in order, despite checkpoints themselves potentially +//! being executed nonsequentially and in parallel. CheckpointExecutor +//! parallelizes checkpoints of the same epoch as much as possible. +//! CheckpointExecutor enforces the invariant that if `run` returns +//! successfully, we have reached the end of epoch. This allows us to use it as +//! a signal for reconfig. + +use std::{ + collections::HashMap, + path::PathBuf, + sync::Arc, + time::{Duration, Instant}, +}; + +use futures::stream::FuturesOrdered; +use iota_config::node::{CheckpointExecutorConfig, RunWithRange}; +use iota_macros::{fail_point, fail_point_async}; +use iota_types::{ + base_types::{ExecutionDigests, TransactionDigest, TransactionEffectsDigest}, + crypto::RandomnessRound, + effects::{TransactionEffects, TransactionEffectsAPI}, + error::IotaResult, + executable_transaction::VerifiedExecutableTransaction, + message_envelope::Message, + messages_checkpoint::{CheckpointSequenceNumber, VerifiedCheckpoint}, + transaction::{TransactionDataAPI, TransactionKind, VerifiedTransaction}, +}; +use itertools::izip; +use mysten_metrics::{spawn_monitored_task, MonitoredFutureExt}; +use prometheus::Registry; +use tap::{TapFallible, TapOptional}; +use tokio::{ + sync::broadcast::{self, error::RecvError}, + task::JoinHandle, + time::timeout, +}; +use tokio_stream::StreamExt; +use tracing::{debug, error, info, instrument, trace, warn}; + +use self::metrics::CheckpointExecutorMetrics; +use crate::{ + authority::{authority_per_epoch_store::AuthorityPerEpochStore, AuthorityState}, + checkpoints::{ + checkpoint_executor::data_ingestion_handler::store_checkpoint_locally, CheckpointStore, + }, + execution_cache::ExecutionCacheRead, + state_accumulator::StateAccumulator, + transaction_manager::TransactionManager, +}; + +mod data_ingestion_handler; +mod metrics; +#[cfg(test)] +pub(crate) mod tests; + +type CheckpointExecutionBuffer = + FuturesOrdered)>>; + +/// The interval to log checkpoint progress, in # of checkpoints processed. +const CHECKPOINT_PROGRESS_LOG_COUNT_INTERVAL: u64 = 5000; + +const SCHEDULING_EVENT_FUTURE_TIMEOUT_MS: u64 = 2000; + +#[derive(PartialEq, Eq, Debug)] +pub enum StopReason { + EpochComplete, + RunWithRangeCondition, +} + +pub struct CheckpointExecutor { + mailbox: broadcast::Receiver, + // TODO: AuthorityState is only needed because we have to call + // deprecated_insert_finalized_transactions once that code is fully deprecated we can + // remove this + state: Arc, + checkpoint_store: Arc, + cache_reader: Arc, + tx_manager: Arc, + accumulator: Arc, + config: CheckpointExecutorConfig, + metrics: Arc, +} + +impl CheckpointExecutor { + pub fn new( + mailbox: broadcast::Receiver, + checkpoint_store: Arc, + state: Arc, + accumulator: Arc, + config: CheckpointExecutorConfig, + prometheus_registry: &Registry, + ) -> Self { + Self { + mailbox, + state: state.clone(), + checkpoint_store, + cache_reader: state.get_cache_reader().clone(), + tx_manager: state.transaction_manager().clone(), + accumulator, + config, + metrics: CheckpointExecutorMetrics::new(prometheus_registry), + } + } + + pub fn new_for_tests( + mailbox: broadcast::Receiver, + checkpoint_store: Arc, + state: Arc, + accumulator: Arc, + ) -> Self { + Self { + mailbox, + state: state.clone(), + checkpoint_store, + cache_reader: state.get_cache_reader().clone(), + tx_manager: state.transaction_manager().clone(), + accumulator, + config: Default::default(), + metrics: CheckpointExecutorMetrics::new_for_tests(), + } + } + + /// Ensure that all checkpoints in the current epoch will be executed. + /// We don't technically need &mut on self, but passing it to make sure only + /// one instance is running at one time. + pub async fn run_epoch( + &mut self, + epoch_store: Arc, + run_with_range: Option, + ) -> StopReason { + // check if we want to run this epoch based on RunWithRange condition value + // we want to be inclusive of the defined RunWithRangeEpoch::Epoch + // i.e Epoch(N) means we will execute epoch N and stop when reaching N+1 + if run_with_range.map_or(false, |rwr| rwr.is_epoch_gt(epoch_store.epoch())) { + info!( + "RunWithRange condition satisfied at {:?}, run_epoch={:?}", + run_with_range, + epoch_store.epoch() + ); + return StopReason::RunWithRangeCondition; + }; + + debug!( + "Checkpoint executor running for epoch {}", + epoch_store.epoch(), + ); + self.metrics + .checkpoint_exec_epoch + .set(epoch_store.epoch() as i64); + + // Decide the first checkpoint to schedule for execution. + // If we haven't executed anything in the past, we schedule checkpoint 0. + // Otherwise we schedule the one after highest executed. + let mut highest_executed = self + .checkpoint_store + .get_highest_executed_checkpoint() + .unwrap(); + + if let Some(highest_executed) = &highest_executed { + if epoch_store.epoch() == highest_executed.epoch() + && highest_executed.is_last_checkpoint_of_epoch() + { + // We can arrive at this point if we bump the highest_executed_checkpoint + // watermark, and then crash before completing reconfiguration. + info!(seq = ?highest_executed.sequence_number, "final checkpoint of epoch has already been executed"); + return StopReason::EpochComplete; + } + } + + let mut next_to_schedule = highest_executed + .as_ref() + .map(|c| c.sequence_number() + 1) + .unwrap_or_else(|| { + // TODO this invariant may no longer hold once we introduce snapshots + assert_eq!(epoch_store.epoch(), 0); + 0 + }); + let mut pending: CheckpointExecutionBuffer = FuturesOrdered::new(); + + let mut now_time = Instant::now(); + let mut now_transaction_num = highest_executed + .as_ref() + .map(|c| c.network_total_transactions) + .unwrap_or(0); + let scheduling_timeout = Duration::from_millis(SCHEDULING_EVENT_FUTURE_TIMEOUT_MS); + + loop { + // If we have executed the last checkpoint of the current epoch, stop. + // Note: when we arrive here with highest_executed == the final checkpoint of + // the epoch, we are in an edge case where highest_executed does not + // actually correspond to the watermark. The watermark is only + // bumped past the epoch final checkpoint after execution of the change + // epoch tx, and state accumulation. + if self + .check_epoch_last_checkpoint(epoch_store.clone(), &highest_executed) + .await + { + self.checkpoint_store + .prune_local_summaries() + .tap_err(|e| error!("Failed to prune local summaries: {}", e)) + .ok(); + + // be extra careful to ensure we don't have orphans + assert!( + pending.is_empty(), + "Pending checkpoint execution buffer should be empty after processing last checkpoint of epoch", + ); + fail_point_async!("crash"); + return StopReason::EpochComplete; + } + + self.schedule_synced_checkpoints( + &mut pending, + // next_to_schedule will be updated to the next checkpoint to schedule. + // This makes sure we don't re-schedule the same checkpoint multiple times. + &mut next_to_schedule, + epoch_store.clone(), + run_with_range, + ); + + self.metrics + .checkpoint_exec_inflight + .set(pending.len() as i64); + + tokio::select! { + // Check for completed workers and ratchet the highest_checkpoint_executed + // watermark accordingly. Note that given that checkpoints are guaranteed to + // be processed (added to FuturesOrdered) in seq_number order, using FuturesOrdered + // guarantees that we will also ratchet the watermarks in order. + Some(Ok((checkpoint, tx_digests))) = pending.next() => { + self.process_executed_checkpoint(&epoch_store, &checkpoint, &tx_digests).await; + highest_executed = Some(checkpoint.clone()); + + // Estimate TPS every 10k transactions or 30 sec + let elapsed = now_time.elapsed().as_millis(); + let current_transaction_num = highest_executed.as_ref().map(|c| c.network_total_transactions).unwrap_or(0); + if current_transaction_num - now_transaction_num > 10_000 || elapsed > 30_000{ + let tps = (1000.0 * (current_transaction_num - now_transaction_num) as f64 / elapsed as f64) as i32; + self.metrics.checkpoint_exec_sync_tps.set(tps as i64); + now_time = Instant::now(); + now_transaction_num = current_transaction_num; + } + // we want to be inclusive of checkpoints in RunWithRange::Checkpoint type + if run_with_range.map_or(false, |rwr| rwr.matches_checkpoint(checkpoint.sequence_number)) { + info!( + "RunWithRange condition satisfied after checkpoint sequence number {:?}", + checkpoint.sequence_number + ); + return StopReason::RunWithRangeCondition; + } + } + // Check for newly synced checkpoints from StateSync. + received = timeout(scheduling_timeout, self.mailbox.recv()) => match received { + Err(_elapsed) => { + warn!( + "Received no new synced checkpoints for {scheduling_timeout:?}. Next checkpoint to be scheduled: {next_to_schedule}", + ); + fail_point!("cp_exec_scheduling_timeout_reached"); + }, + Ok(Ok(checkpoint)) => { + debug!( + sequence_number = ?checkpoint.sequence_number, + "received checkpoint summary from state sync" + ); + checkpoint.report_checkpoint_age_ms(&self.metrics.checkpoint_contents_age_ms); + }, + // In this case, messages in the mailbox have been overwritten + // as a result of lagging too far behind. + Ok(Err(RecvError::Lagged(num_skipped))) => { + debug!( + "Checkpoint Execution Recv channel overflowed {:?} messages", + num_skipped, + ); + } + Ok(Err(RecvError::Closed)) => { + panic!("Checkpoint Execution Sender (StateSync) closed channel unexpectedly"); + } + } + } + } + } + + pub fn set_inconsistent_state(&self, is_inconsistent_state: bool) { + self.metrics + .accumulator_inconsistent_state + .set(is_inconsistent_state as i64); + } + + fn bump_highest_executed_checkpoint(&self, checkpoint: &VerifiedCheckpoint) { + // Ensure that we are not skipping checkpoints at any point + let seq = *checkpoint.sequence_number(); + debug!("Bumping highest_executed_checkpoint watermark to {seq:?}"); + if let Some(prev_highest) = self + .checkpoint_store + .get_highest_executed_checkpoint_seq_number() + .unwrap() + { + assert_eq!(prev_highest + 1, seq); + } else { + assert_eq!(seq, 0); + } + if seq % CHECKPOINT_PROGRESS_LOG_COUNT_INTERVAL == 0 { + info!("Finished syncing and executing checkpoint {}", seq); + } + + fail_point!("highest-executed-checkpoint"); + + // We store a fixed number of additional FullCheckpointContents after execution + // is complete for use in state sync. + const NUM_SAVED_FULL_CHECKPOINT_CONTENTS: u64 = 5_000; + if seq >= NUM_SAVED_FULL_CHECKPOINT_CONTENTS { + let prune_seq = seq - NUM_SAVED_FULL_CHECKPOINT_CONTENTS; + let prune_checkpoint = self + .checkpoint_store + .get_checkpoint_by_sequence_number(prune_seq) + .expect("Failed to fetch checkpoint") + .expect("Failed to retrieve earlier checkpoint by sequence number"); + self.checkpoint_store + .delete_full_checkpoint_contents(prune_seq) + .expect("Failed to delete full checkpoint contents"); + self.checkpoint_store + .delete_contents_digest_sequence_number_mapping(&prune_checkpoint.content_digest) + .expect("Failed to delete contents digest -> sequence number mapping"); + } + + self.checkpoint_store + .update_highest_executed_checkpoint(checkpoint) + .unwrap(); + self.metrics.last_executed_checkpoint.set(seq as i64); + + self.metrics + .last_executed_checkpoint_timestamp_ms + .set(checkpoint.timestamp_ms as i64); + checkpoint.report_checkpoint_age_ms(&self.metrics.last_executed_checkpoint_age_ms); + } + + /// Post processing and plumbing after we executed a checkpoint. This + /// function is guaranteed to be called in the order of checkpoint + /// sequence number. + #[instrument(level = "debug", skip_all)] + async fn process_executed_checkpoint( + &self, + epoch_store: &AuthorityPerEpochStore, + checkpoint: &VerifiedCheckpoint, + all_tx_digests: &[TransactionDigest], + ) { + // Commit all transaction effects to disk + let cache_commit = self.state.get_cache_commit(); + debug!(seq = ?checkpoint.sequence_number, "committing checkpoint transactions to disk"); + for digest in all_tx_digests { + cache_commit + .commit_transaction_outputs(epoch_store.epoch(), digest) + .await + .expect("commit_transaction_outputs cannot fail"); + } + + if !checkpoint.is_last_checkpoint_of_epoch() { + self.bump_highest_executed_checkpoint(checkpoint); + } + } + + #[instrument(level = "debug", skip_all)] + fn schedule_synced_checkpoints( + &self, + pending: &mut CheckpointExecutionBuffer, + next_to_schedule: &mut CheckpointSequenceNumber, + epoch_store: Arc, + run_with_range: Option, + ) { + let Some(latest_synced_checkpoint) = self + .checkpoint_store + .get_highest_synced_checkpoint() + .expect("Failed to read highest synced checkpoint") + else { + debug!("No checkpoints to schedule, highest synced checkpoint is None",); + return; + }; + + while *next_to_schedule <= *latest_synced_checkpoint.sequence_number() + && pending.len() < self.config.checkpoint_execution_max_concurrency + { + let checkpoint = self + .checkpoint_store + .get_checkpoint_by_sequence_number(*next_to_schedule) + .unwrap() + .unwrap_or_else(|| { + panic!( + "Checkpoint sequence number {:?} does not exist in checkpoint store", + *next_to_schedule + ) + }); + if checkpoint.epoch() > epoch_store.epoch() { + return; + } + match run_with_range { + Some(RunWithRange::Checkpoint(seq)) if *next_to_schedule > seq => { + debug!( + "RunWithRange Checkpoint {} is set, not scheduling checkpoint {}", + seq, *next_to_schedule + ); + return; + } + _ => { + self.schedule_checkpoint(checkpoint, pending, epoch_store.clone()); + *next_to_schedule += 1; + } + } + } + } + + #[instrument(level = "error", skip_all, fields(seq = ?checkpoint.sequence_number(), epoch = ?epoch_store.epoch()))] + fn schedule_checkpoint( + &self, + checkpoint: VerifiedCheckpoint, + pending: &mut CheckpointExecutionBuffer, + epoch_store: Arc, + ) { + debug!("Scheduling checkpoint for execution"); + + // Mismatch between node epoch and checkpoint epoch after startup + // crash recovery is invalid + let checkpoint_epoch = checkpoint.epoch(); + assert_eq!( + checkpoint_epoch, + epoch_store.epoch(), + "Epoch mismatch after startup recovery. checkpoint epoch: {:?}, node epoch: {:?}", + checkpoint_epoch, + epoch_store.epoch(), + ); + + let metrics = self.metrics.clone(); + let local_execution_timeout_sec = self.config.local_execution_timeout_sec; + let data_ingestion_dir = self.config.data_ingestion_dir.clone(); + let checkpoint_store = self.checkpoint_store.clone(); + let cache_reader = self.cache_reader.clone(); + let tx_manager = self.tx_manager.clone(); + let accumulator = self.accumulator.clone(); + let state = self.state.clone(); + + pending.push_back(spawn_monitored_task!(async move { + let epoch_store = epoch_store.clone(); + let tx_digests = loop { + match execute_checkpoint( + checkpoint.clone(), + &state, + cache_reader.as_ref(), + checkpoint_store.clone(), + epoch_store.clone(), + tx_manager.clone(), + accumulator.clone(), + local_execution_timeout_sec, + &metrics, + data_ingestion_dir.clone(), + ) + .await + { + Err(err) => { + error!( + "Error while executing checkpoint, will retry in 1s: {:?}", + err + ); + tokio::time::sleep(Duration::from_secs(1)).await; + metrics.checkpoint_exec_errors.inc(); + } + Ok(tx_digests) => break tx_digests, + } + }; + (checkpoint, tx_digests) + })); + } + + #[instrument(level = "info", skip_all)] + async fn execute_change_epoch_tx( + &self, + execution_digests: ExecutionDigests, + change_epoch_tx_digest: TransactionDigest, + change_epoch_tx: VerifiedExecutableTransaction, + epoch_store: Arc, + checkpoint: VerifiedCheckpoint, + ) { + let change_epoch_fx = self + .cache_reader + .get_effects(&execution_digests.effects) + .expect("Fetching effects for change_epoch tx cannot fail") + .expect("Change_epoch tx effects must exist"); + + if change_epoch_tx.contains_shared_object() { + epoch_store + .acquire_shared_locks_from_effects( + &change_epoch_tx, + &change_epoch_fx, + self.cache_reader.as_ref(), + ) + .await + .expect("Acquiring shared locks for change_epoch tx cannot fail"); + } + + self.tx_manager.enqueue_with_expected_effects_digest( + vec![(change_epoch_tx.clone(), execution_digests.effects)], + &epoch_store, + ); + handle_execution_effects( + &self.state, + vec![execution_digests], + vec![change_epoch_tx_digest], + checkpoint.clone(), + self.checkpoint_store.clone(), + self.cache_reader.as_ref(), + epoch_store.clone(), + self.tx_manager.clone(), + self.accumulator.clone(), + self.config.local_execution_timeout_sec, + self.config.data_ingestion_dir.clone(), + ) + .await; + } + + /// Check whether `checkpoint` is the last checkpoint of the current epoch. + /// If so, perform special case logic (execute change_epoch tx, + /// accumulate epoch, finalize transactions), then return true. + pub async fn check_epoch_last_checkpoint( + &self, + epoch_store: Arc, + checkpoint: &Option, + ) -> bool { + let cur_epoch = epoch_store.epoch(); + + if let Some(checkpoint) = checkpoint { + if checkpoint.epoch() == cur_epoch { + if let Some((change_epoch_execution_digests, change_epoch_tx)) = + extract_end_of_epoch_tx( + checkpoint, + self.cache_reader.as_ref(), + self.checkpoint_store.clone(), + epoch_store.clone(), + ) + { + let change_epoch_tx_digest = change_epoch_execution_digests.transaction; + + info!( + ended_epoch = cur_epoch, + last_checkpoint = checkpoint.sequence_number(), + "Reached end of epoch, executing change_epoch transaction", + ); + + self.execute_change_epoch_tx( + change_epoch_execution_digests, + change_epoch_tx_digest, + change_epoch_tx, + epoch_store.clone(), + checkpoint.clone(), + ) + .await; + + let cache_commit = self.state.get_cache_commit(); + cache_commit + .commit_transaction_outputs(cur_epoch, &change_epoch_tx_digest) + .await + .expect("commit_transaction_outputs cannot fail"); + + fail_point_async!("prune-and-compact"); + + // For finalizing the checkpoint, we need to pass in all checkpoint + // transaction effects, not just the change_epoch tx effects. However, + // we have already notify awaited all tx effects separately (once + // for change_epoch tx, and once for all other txes). Therefore this + // should be a fast operation + let all_tx_digests: Vec<_> = self + .checkpoint_store + .get_checkpoint_contents(&checkpoint.content_digest) + .expect("read cannot fail") + .expect("Checkpoint contents should exist") + .iter() + .map(|digests| digests.transaction) + .collect(); + + let effects = self + .cache_reader + .notify_read_executed_effects(&all_tx_digests) + .await + .expect("Failed to get executed effects for finalizing checkpoint"); + + finalize_checkpoint( + &self.state, + self.cache_reader.as_ref(), + self.checkpoint_store.clone(), + &all_tx_digests, + epoch_store.clone(), + checkpoint.clone(), + self.accumulator.clone(), + effects, + self.config.data_ingestion_dir.clone(), + ) + .await + .expect("Finalizing checkpoint cannot fail"); + + self.accumulator + .accumulate_epoch( + &cur_epoch, + *checkpoint.sequence_number(), + epoch_store.clone(), + ) + .in_monitored_scope("CheckpointExecutor::accumulate_epoch") + .await + .expect("Accumulating epoch cannot fail"); + + self.bump_highest_executed_checkpoint(checkpoint); + + return true; + } + } + } + false + } +} + +// Logs within the function are annotated with the checkpoint sequence number +// and epoch, from schedule_checkpoint(). +#[instrument(level = "debug", skip_all, fields(seq = ?checkpoint.sequence_number(), epoch = ?epoch_store.epoch()))] +async fn execute_checkpoint( + checkpoint: VerifiedCheckpoint, + state: &AuthorityState, + cache_reader: &dyn ExecutionCacheRead, + checkpoint_store: Arc, + epoch_store: Arc, + transaction_manager: Arc, + accumulator: Arc, + local_execution_timeout_sec: u64, + metrics: &Arc, + data_ingestion_dir: Option, +) -> IotaResult> { + debug!("Preparing checkpoint for execution",); + let prepare_start = Instant::now(); + + // this function must guarantee that all transactions in the checkpoint are + // executed before it returns. This invariant is enforced in two phases: + // - First, we filter out any already executed transactions from the checkpoint + // in get_unexecuted_transactions() + // - Second, we execute all remaining transactions. + + let (execution_digests, all_tx_digests, executable_txns, randomness_round) = + get_unexecuted_transactions( + checkpoint.clone(), + cache_reader, + checkpoint_store.clone(), + epoch_store.clone(), + ); + + let tx_count = execution_digests.len(); + debug!("Number of transactions in the checkpoint: {:?}", tx_count); + metrics.checkpoint_transaction_count.report(tx_count as u64); + + execute_transactions( + execution_digests, + all_tx_digests.clone(), + executable_txns, + state, + cache_reader, + checkpoint_store.clone(), + epoch_store.clone(), + transaction_manager, + accumulator, + local_execution_timeout_sec, + checkpoint, + metrics, + prepare_start, + data_ingestion_dir, + ) + .await?; + + // Once execution is complete, we know that any randomness contained in this + // checkpoint has been successfully included in a checkpoint certified by + // quorum of validators. + if let Some(round) = randomness_round { + // RandomnessManager is only present on validators. + if let Some(randomness_reporter) = epoch_store.randomness_reporter() { + debug!( + ?round, + "notifying RandomnessReporter that randomness update was executed in checkpoint" + ); + randomness_reporter.notify_randomness_in_checkpoint(round)?; + } + } + + Ok(all_tx_digests) +} + +#[instrument(level = "error", skip_all, fields(seq = ?checkpoint.sequence_number(), epoch = ?epoch_store.epoch()))] +async fn handle_execution_effects( + state: &AuthorityState, + execution_digests: Vec, + all_tx_digests: Vec, + checkpoint: VerifiedCheckpoint, + checkpoint_store: Arc, + cache_reader: &dyn ExecutionCacheRead, + epoch_store: Arc, + transaction_manager: Arc, + accumulator: Arc, + local_execution_timeout_sec: u64, + data_ingestion_dir: Option, +) { + // Once synced_txns have been awaited, all txns should have effects committed. + let mut periods = 1; + let log_timeout_sec = Duration::from_secs(local_execution_timeout_sec); + // Whether the checkpoint is next to execute and blocking additional executions. + let mut blocking_execution = false; + loop { + let effects_future = cache_reader.notify_read_executed_effects(&all_tx_digests); + + match timeout(log_timeout_sec, effects_future).await { + Err(_elapsed) => { + // Reading this value every timeout should be ok. + let highest_seq = checkpoint_store + .get_highest_executed_checkpoint_seq_number() + .unwrap() + .unwrap_or_default(); + if checkpoint.sequence_number <= highest_seq { + error!( + "Re-executing checkpoint {} after higher checkpoint {} has executed!", + checkpoint.sequence_number, highest_seq + ); + continue; + } + if checkpoint.sequence_number > highest_seq + 1 { + trace!( + "Checkpoint {} is still executing. Highest executed = {}", + checkpoint.sequence_number, + highest_seq + ); + continue; + } + if !blocking_execution { + trace!( + "Checkpoint {} is next to execute.", + checkpoint.sequence_number + ); + blocking_execution = true; + continue; + } + + // Only log details when the checkpoint is next to execute, but has not finished + // execution within log_timeout_sec. + let missing_digests: Vec = cache_reader + .multi_get_executed_effects_digests(&all_tx_digests) + .expect("multi_get_executed_effects cannot fail") + .iter() + .zip(all_tx_digests.clone()) + .filter_map( + |(fx, digest)| { + if fx.is_none() { Some(digest) } else { None } + }, + ) + .collect(); + + if missing_digests.is_empty() { + // All effects just become available. + continue; + } + + warn!( + "Transaction effects for checkpoint tx digests {:?} not present within {:?}. ", + missing_digests, + log_timeout_sec * periods, + ); + + // Print out more information for the 1st pending transaction, which should have + // all of its input available. + let pending_digest = missing_digests.first().unwrap(); + if let Some(missing_input) = transaction_manager.get_missing_input(pending_digest) { + warn!( + "Transaction {pending_digest:?} has missing input objects {missing_input:?}", + ); + } + periods += 1; + } + Ok(Err(err)) => panic!("Failed to notify_read_executed_effects: {:?}", err), + Ok(Ok(effects)) => { + for (tx_digest, expected_digest, actual_effects) in + izip!(&all_tx_digests, &execution_digests, &effects) + { + let expected_effects_digest = &expected_digest.effects; + assert_not_forked( + &checkpoint, + tx_digest, + expected_effects_digest, + &actual_effects.digest(), + cache_reader, + ); + } + + // return Ok(effects); + + // if end of epoch checkpoint, we must finalize the checkpoint after executing + // the change epoch tx, which is done after all other checkpoint execution + if checkpoint.end_of_epoch_data.is_none() { + finalize_checkpoint( + state, + cache_reader, + checkpoint_store.clone(), + &all_tx_digests, + epoch_store.clone(), + checkpoint.clone(), + accumulator.clone(), + effects, + data_ingestion_dir, + ) + .await + .expect("Finalizing checkpoint cannot fail"); + } + return; + } + } + } +} + +fn assert_not_forked( + checkpoint: &VerifiedCheckpoint, + tx_digest: &TransactionDigest, + expected_digest: &TransactionEffectsDigest, + actual_effects_digest: &TransactionEffectsDigest, + cache_reader: &dyn ExecutionCacheRead, +) { + if *expected_digest != *actual_effects_digest { + let actual_effects = cache_reader + .get_executed_effects(tx_digest) + .expect("get_executed_effects cannot fail") + .expect("actual effects should exist"); + + // log observed effects (too big for panic message) and then panic. + error!( + ?checkpoint, + ?tx_digest, + ?expected_digest, + ?actual_effects, + "fork detected!" + ); + panic!( + "When executing checkpoint {}, transaction {} \ + is expected to have effects digest {}, but got {}!", + checkpoint.sequence_number(), + tx_digest, + expected_digest, + actual_effects_digest, + ); + } +} + +// Given a checkpoint, find the end of epoch transaction, if it exists +fn extract_end_of_epoch_tx( + checkpoint: &VerifiedCheckpoint, + cache_reader: &dyn ExecutionCacheRead, + checkpoint_store: Arc, + epoch_store: Arc, +) -> Option<(ExecutionDigests, VerifiedExecutableTransaction)> { + checkpoint.end_of_epoch_data.as_ref()?; + + // Last checkpoint must have the end of epoch transaction as the last + // transaction. + + let checkpoint_sequence = checkpoint.sequence_number(); + let execution_digests = checkpoint_store + .get_checkpoint_contents(&checkpoint.content_digest) + .expect("Failed to get checkpoint contents from store") + .unwrap_or_else(|| { + panic!( + "Checkpoint contents for digest {:?} does not exist", + checkpoint.content_digest + ) + }) + .into_inner(); + + let digests = execution_digests + .last() + .expect("Final checkpoint must have at least one transaction"); + + let change_epoch_tx = cache_reader + .get_transaction_block(&digests.transaction) + .expect("read cannot fail"); + + let change_epoch_tx = VerifiedExecutableTransaction::new_from_checkpoint( + (*change_epoch_tx.unwrap_or_else(|| + panic!( + "state-sync should have ensured that transaction with digest {:?} exists for checkpoint: {checkpoint:?}", + digests.transaction, + ) + )).clone(), + epoch_store.epoch(), + *checkpoint_sequence, + ); + + assert!( + change_epoch_tx + .data() + .intent_message() + .value + .is_end_of_epoch_tx() + ); + + Some((*digests, change_epoch_tx)) +} + +// Given a checkpoint, filter out any already executed transactions, then return +// the remaining execution digests, transaction digests, transactions to be +// executed, and randomness round (if any) included in the checkpoint. +#[allow(clippy::type_complexity)] +fn get_unexecuted_transactions( + checkpoint: VerifiedCheckpoint, + cache_reader: &dyn ExecutionCacheRead, + checkpoint_store: Arc, + epoch_store: Arc, +) -> ( + Vec, + Vec, + Vec<(VerifiedExecutableTransaction, TransactionEffectsDigest)>, + Option, +) { + let checkpoint_sequence = checkpoint.sequence_number(); + let full_contents = checkpoint_store + .get_full_checkpoint_contents_by_sequence_number(*checkpoint_sequence) + .expect("Failed to get checkpoint contents from store") + .tap_some(|_| { + debug!("loaded full checkpoint contents in bulk for sequence {checkpoint_sequence}") + }); + + let mut execution_digests = checkpoint_store + .get_checkpoint_contents(&checkpoint.content_digest) + .expect("Failed to get checkpoint contents from store") + .unwrap_or_else(|| { + panic!( + "Checkpoint contents for digest {:?} does not exist", + checkpoint.content_digest + ) + }) + .into_inner(); + + let full_contents_txns = full_contents.map(|c| { + c.into_iter() + .zip(execution_digests.iter()) + .map(|(txn, digests)| (digests.transaction, txn)) + .collect::>() + }); + + // Remove the change epoch transaction so that we can special case its + // execution. + checkpoint.end_of_epoch_data.as_ref().tap_some(|_| { + let change_epoch_tx_digest = execution_digests + .pop() + .expect("Final checkpoint must have at least one transaction") + .transaction; + + let change_epoch_tx = cache_reader + .get_transaction_block(&change_epoch_tx_digest) + .expect("read cannot fail") + .unwrap_or_else(|| + panic!( + "state-sync should have ensured that transaction with digest {change_epoch_tx_digest:?} exists for checkpoint: {}", + checkpoint.sequence_number() + ) + ); + assert!(change_epoch_tx.data().intent_message().value.is_end_of_epoch_tx()); + }); + + // Look for a randomness state update tx. It must be first if it exists, because + // all other transactions in a checkpoint that includes a randomness state + // update are causally dependent on it. + let randomness_round = if let Some(first_digest) = execution_digests.first() { + let maybe_randomness_tx = cache_reader.get_transaction_block(&first_digest.transaction) + .expect("read cannot fail") + .unwrap_or_else(|| + panic!( + "state-sync should have ensured that transaction with digest {first_digest:?} exists for checkpoint: {}", + checkpoint.sequence_number() + ) + ); + if let TransactionKind::RandomnessStateUpdate(rsu) = + maybe_randomness_tx.data().transaction_data().kind() + { + Some(rsu.randomness_round) + } else { + None + } + } else { + None + }; + + let all_tx_digests: Vec = + execution_digests.iter().map(|tx| tx.transaction).collect(); + + let executed_effects_digests = cache_reader + .multi_get_executed_effects_digests(&all_tx_digests) + .expect("failed to read executed_effects from store"); + + let (unexecuted_txns, expected_effects_digests): (Vec<_>, Vec<_>) = + izip!(execution_digests.iter(), executed_effects_digests.iter()) + .filter_map(|(digests, effects_digest)| match effects_digest { + None => Some((digests.transaction, digests.effects)), + Some(actual_effects_digest) => { + let tx_digest = &digests.transaction; + let effects_digest = &digests.effects; + trace!( + "Transaction with digest {:?} has already been executed", + tx_digest + ); + assert_not_forked( + &checkpoint, + tx_digest, + effects_digest, + actual_effects_digest, + cache_reader, + ); + None + } + }) + .unzip(); + + // read remaining unexecuted transactions from store + let executable_txns: Vec<_> = if let Some(full_contents_txns) = full_contents_txns { + unexecuted_txns + .into_iter() + .zip(expected_effects_digests) + .map(|(tx_digest, expected_effects_digest)| { + let tx = &full_contents_txns.get(&tx_digest).unwrap().transaction; + ( + VerifiedExecutableTransaction::new_from_checkpoint( + VerifiedTransaction::new_unchecked(tx.clone()), + epoch_store.epoch(), + *checkpoint_sequence, + ), + expected_effects_digest, + ) + }) + .collect() + } else { + cache_reader + .multi_get_transaction_blocks(&unexecuted_txns) + .expect("Failed to get checkpoint txes from store") + .into_iter() + .zip(expected_effects_digests) + .enumerate() + .map(|(i, (tx, expected_effects_digest))| { + let tx = tx.unwrap_or_else(|| + panic!( + "state-sync should have ensured that transaction with digest {:?} exists for checkpoint: {checkpoint:?}", + unexecuted_txns[i] + ) + ); + // change epoch tx is handled specially in check_epoch_last_checkpoint + assert!(!tx.data().intent_message().value.is_end_of_epoch_tx()); + ( + VerifiedExecutableTransaction::new_from_checkpoint( + Arc::try_unwrap(tx).unwrap_or_else(|tx| (*tx).clone()), + epoch_store.epoch(), + *checkpoint_sequence, + ), + expected_effects_digest + ) + }) + .collect() + }; + + ( + execution_digests, + all_tx_digests, + executable_txns, + randomness_round, + ) +} + +// Logs within the function are annotated with the checkpoint sequence number +// and epoch, from schedule_checkpoint(). +#[instrument(level = "debug", skip_all)] +async fn execute_transactions( + execution_digests: Vec, + all_tx_digests: Vec, + executable_txns: Vec<(VerifiedExecutableTransaction, TransactionEffectsDigest)>, + state: &AuthorityState, + cache_reader: &dyn ExecutionCacheRead, + checkpoint_store: Arc, + epoch_store: Arc, + transaction_manager: Arc, + accumulator: Arc, + local_execution_timeout_sec: u64, + checkpoint: VerifiedCheckpoint, + metrics: &Arc, + prepare_start: Instant, + data_ingestion_dir: Option, +) -> IotaResult { + let effects_digests: HashMap<_, _> = execution_digests + .iter() + .map(|digest| (digest.transaction, digest.effects)) + .collect(); + + let shared_effects_digests = executable_txns + .iter() + .filter(|(tx, _)| tx.contains_shared_object()) + .map(|(tx, _)| { + *effects_digests + .get(tx.digest()) + .expect("Transaction digest not found in effects_digests") + }) + .collect::>(); + + let digest_to_effects: HashMap = cache_reader + .multi_get_effects(&shared_effects_digests)? + .into_iter() + .zip(shared_effects_digests) + .map(|(fx, fx_digest)| { + if fx.is_none() { + panic!( + "Transaction effects for effects digest {:?} do not exist in effects table", + fx_digest + ); + } + let fx = fx.unwrap(); + (*fx.transaction_digest(), fx) + }) + .collect(); + + for (tx, _) in &executable_txns { + if tx.contains_shared_object() { + epoch_store + .acquire_shared_locks_from_effects( + tx, + digest_to_effects.get(tx.digest()).unwrap(), + cache_reader, + ) + .await?; + } + } + + let prepare_elapsed = prepare_start.elapsed(); + metrics + .checkpoint_prepare_latency_us + .report(prepare_elapsed.as_micros() as u64); + if checkpoint.sequence_number % CHECKPOINT_PROGRESS_LOG_COUNT_INTERVAL == 0 { + info!( + "Checkpoint preparation for execution took {:?}", + prepare_elapsed + ); + } + + let exec_start = Instant::now(); + transaction_manager.enqueue_with_expected_effects_digest(executable_txns.clone(), &epoch_store); + + handle_execution_effects( + state, + execution_digests, + all_tx_digests, + checkpoint.clone(), + checkpoint_store, + cache_reader, + epoch_store, + transaction_manager, + accumulator, + local_execution_timeout_sec, + data_ingestion_dir, + ) + .await; + + let exec_elapsed = exec_start.elapsed(); + metrics + .checkpoint_exec_latency_us + .report(exec_elapsed.as_micros() as u64); + if checkpoint.sequence_number % CHECKPOINT_PROGRESS_LOG_COUNT_INTERVAL == 0 { + info!("Checkpoint execution took {:?}", exec_elapsed); + } + + Ok(()) +} + +#[instrument(level = "debug", skip_all)] +async fn finalize_checkpoint( + state: &AuthorityState, + cache_reader: &dyn ExecutionCacheRead, + checkpoint_store: Arc, + tx_digests: &[TransactionDigest], + epoch_store: Arc, + checkpoint: VerifiedCheckpoint, + accumulator: Arc, + effects: Vec, + data_ingestion_dir: Option, +) -> IotaResult { + if epoch_store.per_epoch_finalized_txns_enabled() { + epoch_store.insert_finalized_transactions(tx_digests, checkpoint.sequence_number)?; + } + // TODO remove once we no longer need to support this table for read RPC + state + .get_checkpoint_cache() + .deprecated_insert_finalized_transactions( + tx_digests, + epoch_store.epoch(), + checkpoint.sequence_number, + )?; + + accumulator.accumulate_checkpoint(effects, checkpoint.sequence_number, epoch_store)?; + if let Some(path) = data_ingestion_dir { + store_checkpoint_locally( + path, + checkpoint, + cache_reader, + checkpoint_store, + tx_digests.to_vec(), + )?; + } + Ok(()) +} diff --git a/crates/iota-core/src/checkpoints/checkpoint_executor/tests.rs b/crates/iota-core/src/checkpoints/checkpoint_executor/tests.rs new file mode 100644 index 00000000000..b7b8c1123bd --- /dev/null +++ b/crates/iota-core/src/checkpoints/checkpoint_executor/tests.rs @@ -0,0 +1,492 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{sync::Arc, time::Duration}; + +use broadcast::{Receiver, Sender}; +use iota_config::node::ExpensiveSafetyCheckConfig; +use iota_protocol_config::SupportedProtocolVersions; +use iota_swarm_config::test_utils::{empty_contents, CommitteeFixture}; +use iota_types::{ + committee::ProtocolVersion, + gas::GasCostSummary, + iota_system_state::epoch_start_iota_system_state::EpochStartSystemState, + messages_checkpoint::{ECMHLiveObjectSetDigest, EndOfEpochData, VerifiedCheckpoint}, +}; +use tempfile::tempdir; +use tokio::{sync::broadcast, time::timeout}; +use typed_store::Map; + +use super::*; +use crate::{ + authority::{ + epoch_start_configuration::EpochStartConfiguration, + test_authority_builder::TestAuthorityBuilder, AuthorityState, + }, + checkpoints::CheckpointStore, + state_accumulator::{AccumulatorStore, StateAccumulator}, +}; + +/// Test checkpoint executor happy path, test that checkpoint executor correctly +/// picks up where it left off in the event of a mid-epoch node crash. +#[tokio::test] +pub async fn test_checkpoint_executor_crash_recovery() { + let buffer_size = num_cpus::get() * 2; + let tempdir = tempdir().unwrap(); + let checkpoint_store = CheckpointStore::new(tempdir.path()); + + let (state, mut executor, accumulator, checkpoint_sender, committee): ( + Arc, + CheckpointExecutor, + Arc, + Sender, + CommitteeFixture, + ) = init_executor_test(buffer_size, checkpoint_store.clone()).await; + + assert!( + checkpoint_store + .get_highest_executed_checkpoint_seq_number() + .unwrap() + .is_none() + ); + let checkpoints = sync_new_checkpoints( + &checkpoint_store, + &checkpoint_sender, + 2 * buffer_size, + None, + &committee, + ); + + let epoch_store = state.epoch_store_for_testing().clone(); + let executor_handle = + spawn_monitored_task!(async move { executor.run_epoch(epoch_store, None).await }); + tokio::time::sleep(Duration::from_secs(5)).await; + + // ensure we executed all synced checkpoints + let highest_executed = checkpoint_store + .get_highest_executed_checkpoint_seq_number() + .unwrap() + .expect("Expected highest executed to not be None"); + assert_eq!(highest_executed, 2 * (buffer_size as u64) - 1,); + + // Simulate node restart + executor_handle.abort(); + + // sync more checkpoints in the meantime + let _ = sync_new_checkpoints( + &checkpoint_store, + &checkpoint_sender, + 2 * buffer_size, + Some(checkpoints.last().cloned().unwrap()), + &committee, + ); + + // restart checkpoint executor and ensure that it picks + // up where it left off + let mut executor = CheckpointExecutor::new_for_tests( + checkpoint_sender.subscribe(), + checkpoint_store.clone(), + state.clone(), + accumulator.clone(), + ); + + let epoch_store = state.epoch_store_for_testing().clone(); + let executor_handle = + spawn_monitored_task!(async move { executor.run_epoch(epoch_store, None).await }); + tokio::time::sleep(Duration::from_secs(15)).await; + + let highest_executed = checkpoint_store + .get_highest_executed_checkpoint_seq_number() + .unwrap() + .expect("Expected highest executed to not be None"); + assert_eq!(highest_executed, 4 * (buffer_size as u64) - 1); + + executor_handle.abort(); +} + +/// Test that checkpoint execution correctly signals end of epoch after +/// receiving last checkpoint of epoch, then resumes executing cehckpoints +/// from the next epoch if called after reconfig +/// +/// TODO(william) disabling reconfig unit tests here for now until we can work +/// on correctly inserting transactions, especially the change_epoch tx. As it +/// stands, this is better tested in existing reconfig simtests +#[tokio::test] +#[ignore] +pub async fn test_checkpoint_executor_cross_epoch() { + let buffer_size = 10; + let num_to_sync_per_epoch = buffer_size * 2; + let tempdir = tempdir().unwrap(); + let checkpoint_store = CheckpointStore::new(tempdir.path()); + + let (authority_state, mut executor, accumulator, checkpoint_sender, first_committee): ( + Arc, + CheckpointExecutor, + Arc, + Sender, + CommitteeFixture, + ) = init_executor_test(buffer_size, checkpoint_store.clone()).await; + + let epoch_store = authority_state.epoch_store_for_testing(); + let epoch = epoch_store.epoch(); + assert_eq!(epoch, 0); + + assert!( + checkpoint_store + .get_highest_executed_checkpoint_seq_number() + .unwrap() + .is_none() + ); + + // sync 20 checkpoints + let cold_start_checkpoints = sync_new_checkpoints( + &checkpoint_store, + &checkpoint_sender, + num_to_sync_per_epoch, + None, + &first_committee, + ); + + // sync end of epoch checkpoint + let last_executed_checkpoint = cold_start_checkpoints.last().cloned().unwrap(); + let (end_of_epoch_0_checkpoint, second_committee) = sync_end_of_epoch_checkpoint( + authority_state.clone(), + &checkpoint_store, + &checkpoint_sender, + last_executed_checkpoint.clone(), + &first_committee, + ) + .await; + + // sync 20 more checkpoints + let next_epoch_checkpoints = sync_new_checkpoints( + &checkpoint_store, + &checkpoint_sender, + num_to_sync_per_epoch, + Some(end_of_epoch_0_checkpoint.clone()), + &second_committee, + ); + + authority_state + .get_checkpoint_store() + .epoch_last_checkpoint_map + .insert( + &end_of_epoch_0_checkpoint.epoch, + end_of_epoch_0_checkpoint.sequence_number(), + ) + .unwrap(); + authority_state + .get_checkpoint_store() + .certified_checkpoints + .insert( + end_of_epoch_0_checkpoint.sequence_number(), + end_of_epoch_0_checkpoint.serializable_ref(), + ) + .unwrap(); + // sync end of epoch checkpoint + let last_executed_checkpoint = next_epoch_checkpoints.last().cloned().unwrap(); + let (_end_of_epoch_1_checkpoint, _third_committee) = sync_end_of_epoch_checkpoint( + authority_state.clone(), + &checkpoint_store, + &checkpoint_sender, + last_executed_checkpoint.clone(), + &second_committee, + ) + .await; + + // Ensure root state hash for epoch does not exist before we close epoch + assert!( + authority_state + .get_execution_cache() + .get_root_state_accumulator_for_epoch(0) + .unwrap() + .is_none() + ); + + // Ensure executor reaches end of epoch in a timely manner + timeout(Duration::from_secs(5), async { + executor.run_epoch(epoch_store.clone(), None).await; + }) + .await + .unwrap(); + + // We should have synced up to epoch boundary + assert_eq!( + checkpoint_store + .get_highest_executed_checkpoint_seq_number() + .unwrap() + .unwrap(), + num_to_sync_per_epoch as u64, + ); + + let first_epoch = 0; + + // Ensure root state hash for epoch exists at end of epoch + authority_state + .get_execution_cache() + .get_root_state_accumulator_for_epoch(first_epoch) + .unwrap() + .expect("root state hash for epoch should exist"); + + let system_state = EpochStartSystemState::new_for_testing_with_epoch(1); + + let new_epoch_store = authority_state + .reconfigure( + &authority_state.epoch_store_for_testing(), + SupportedProtocolVersions::SYSTEM_DEFAULT, + second_committee.committee().clone(), + EpochStartConfiguration::new( + system_state, + Default::default(), + authority_state.get_object_store(), + None, + ) + .unwrap(), + &executor, + accumulator, + &ExpensiveSafetyCheckConfig::default(), + ) + .await + .unwrap(); + + // checkpoint execution should resume starting at checkpoints + // of next epoch + timeout(Duration::from_secs(5), async { + executor.run_epoch(new_epoch_store.clone(), None).await; + }) + .await + .unwrap(); + + assert_eq!( + checkpoint_store + .get_highest_executed_checkpoint_seq_number() + .unwrap() + .unwrap(), + 2 * num_to_sync_per_epoch as u64 + 1, + ); + + let second_epoch = 1; + assert!(second_epoch == new_epoch_store.epoch()); + + authority_state + .get_execution_cache() + .get_root_state_accumulator_for_epoch(second_epoch) + .unwrap() + .expect("root state hash for epoch should exist"); +} + +/// Test that if we crash at end of epoch / during reconfig, we recover on +/// startup by starting at the old epoch and immediately retrying reconfig +/// +/// TODO(william) disabling reconfig unit tests here for now until we can work +/// on correctly inserting transactions, especially the change_epoch tx. As it +/// stands, this is better tested in existing reconfig simtests +#[tokio::test] +#[ignore] +pub async fn test_reconfig_crash_recovery() { + let tempdir = tempdir().unwrap(); + let checkpoint_store = CheckpointStore::new(tempdir.path()); + + // new Node (syncing from checkpoint 0) + let (authority_state, mut executor, accumulator, checkpoint_sender, first_committee): ( + Arc, + CheckpointExecutor, + Arc, + Sender, + CommitteeFixture, + ) = init_executor_test( + 10, // StateSync -> Executor channel buffer size + checkpoint_store.clone(), + ) + .await; + + assert!( + checkpoint_store + .get_highest_executed_checkpoint_seq_number() + .unwrap() + .is_none() + ); + + // sync 1 checkpoint + let checkpoint = sync_new_checkpoints( + &checkpoint_store, + &checkpoint_sender, + 1, + None, + &first_committee, + ) + .pop() + .unwrap(); + + // sync end of epoch checkpoint + let (end_of_epoch_checkpoint, second_committee) = sync_end_of_epoch_checkpoint( + authority_state.clone(), + &checkpoint_store, + &checkpoint_sender, + checkpoint, + &first_committee, + ) + .await; + // sync 1 more checkpoint + let _next_epoch_checkpoints = sync_new_checkpoints( + &checkpoint_store, + &checkpoint_sender, + 1, + Some(end_of_epoch_checkpoint.clone()), + &second_committee, + ); + + timeout(Duration::from_secs(1), async { + executor + .run_epoch(authority_state.epoch_store_for_testing().clone(), None) + .await; + }) + .await + .unwrap(); + + // Check that we stopped execution at epoch boundary + assert_eq!( + checkpoint_store + .get_highest_executed_checkpoint_seq_number() + .unwrap() + .unwrap(), + *end_of_epoch_checkpoint.sequence_number(), + ); + + // Drop and re-istantiate checkpoint executor without performing reconfig. This + // is logically equivalent to reconfig crashing and the node restarting, in + // which case executor should be able to infer that, rather than beginning + // execution of the next epoch, we should immediately exit so that reconfig + // can be reattempted. + drop(executor); + let mut executor = CheckpointExecutor::new_for_tests( + checkpoint_sender.subscribe(), + checkpoint_store.clone(), + authority_state.clone(), + accumulator.clone(), + ); + + timeout(Duration::from_millis(200), async { + executor + .run_epoch(authority_state.epoch_store_for_testing().clone(), None) + .await; + }) + .await + .unwrap(); + + // Check that we have still not gone beyond epoch boundary + assert_eq!( + checkpoint_store + .get_highest_executed_checkpoint_seq_number() + .unwrap() + .unwrap(), + *end_of_epoch_checkpoint.sequence_number(), + ); +} + +async fn init_executor_test( + buffer_size: usize, + store: Arc, +) -> ( + Arc, + CheckpointExecutor, + Arc, + Sender, + CommitteeFixture, +) { + let network_config = + iota_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir().build(); + let state = TestAuthorityBuilder::new() + .with_network_config(&network_config) + .build() + .await; + + let (checkpoint_sender, _): (Sender, Receiver) = + broadcast::channel(buffer_size); + + let accumulator = StateAccumulator::new(state.get_execution_cache()); + let accumulator = Arc::new(accumulator); + + let executor = CheckpointExecutor::new_for_tests( + checkpoint_sender.subscribe(), + store.clone(), + state.clone(), + accumulator.clone(), + ); + ( + state, + executor, + accumulator, + checkpoint_sender, + CommitteeFixture::from_network_config(&network_config), + ) +} + +/// Creates and simulates syncing of a new checkpoint by StateSync, i.e. new +/// checkpoint is persisted, along with its contents, highest synced checkpoint +/// watermark is updated, and message is broadcasted notifying of the newly +/// synced checkpoint. Returns created checkpoints +fn sync_new_checkpoints( + checkpoint_store: &CheckpointStore, + sender: &Sender, + number_of_checkpoints: usize, + previous_checkpoint: Option, + committee: &CommitteeFixture, +) -> Vec { + let (ordered_checkpoints, _, _sequence_number_to_digest, _checkpoints) = + committee.make_empty_checkpoints(number_of_checkpoints, previous_checkpoint); + + for checkpoint in ordered_checkpoints.iter() { + sync_checkpoint(checkpoint, checkpoint_store, sender); + } + + ordered_checkpoints +} + +async fn sync_end_of_epoch_checkpoint( + authority_state: Arc, + checkpoint_store: &CheckpointStore, + sender: &Sender, + previous_checkpoint: VerifiedCheckpoint, + committee: &CommitteeFixture, +) -> (VerifiedCheckpoint, CommitteeFixture) { + let new_committee = + CommitteeFixture::generate(rand::rngs::OsRng, committee.committee().epoch + 1, 4); + let (_sequence_number, _digest, checkpoint) = committee.make_end_of_epoch_checkpoint( + previous_checkpoint, + Some(EndOfEpochData { + next_epoch_committee: new_committee.committee().voting_rights.clone(), + next_epoch_protocol_version: ProtocolVersion::MIN, + epoch_commitments: vec![ECMHLiveObjectSetDigest::default().into()], + }), + ); + authority_state + .create_and_execute_advance_epoch_tx( + &authority_state.epoch_store_for_testing().clone(), + &GasCostSummary::new(0, 0, 0, 0), + *checkpoint.sequence_number(), + 0, // epoch_start_timestamp_ms + ) + .await + .expect("Failed to create and execute advance epoch tx"); + sync_checkpoint(&checkpoint, checkpoint_store, sender); + (checkpoint, new_committee) +} + +fn sync_checkpoint( + checkpoint: &VerifiedCheckpoint, + checkpoint_store: &CheckpointStore, + sender: &Sender, +) { + checkpoint_store + .insert_verified_checkpoint(checkpoint) + .unwrap(); + checkpoint_store + .insert_checkpoint_contents(empty_contents().into_inner().into_checkpoint_contents()) + .unwrap(); + checkpoint_store + .update_highest_synced_checkpoint(checkpoint) + .unwrap(); + sender.send(checkpoint.clone()).unwrap(); +} diff --git a/crates/sui-core/src/checkpoints/checkpoint_output.rs b/crates/iota-core/src/checkpoints/checkpoint_output.rs similarity index 92% rename from crates/sui-core/src/checkpoints/checkpoint_output.rs rename to crates/iota-core/src/checkpoints/checkpoint_output.rs index ab5a632af62..e6712c54af0 100644 --- a/crates/sui-core/src/checkpoints/checkpoint_output.rs +++ b/crates/iota-core/src/checkpoints/checkpoint_output.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; use async_trait::async_trait; -use sui_types::{ +use iota_types::{ base_types::AuthorityName, - error::SuiResult, + error::IotaResult, message_envelope::Message, messages_checkpoint::{ CertifiedCheckpointSummary, CheckpointContents, CheckpointSignatureMessage, @@ -30,13 +31,15 @@ pub trait CheckpointOutput: Sync + Send + 'static { summary: &CheckpointSummary, contents: &CheckpointContents, epoch_store: &Arc, - ) -> SuiResult; + ) -> IotaResult; } #[async_trait] pub trait CertifiedCheckpointOutput: Sync + Send + 'static { - async fn certified_checkpoint_created(&self, summary: &CertifiedCheckpointSummary) - -> SuiResult; + async fn certified_checkpoint_created( + &self, + summary: &CertifiedCheckpointSummary, + ) -> IotaResult; } pub struct SubmitCheckpointToConsensus { @@ -69,7 +72,7 @@ impl CheckpointOutput summary: &CheckpointSummary, contents: &CheckpointContents, epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { let checkpoint_seq = summary.sequence_number; let checkpoint_timestamp = summary.timestamp_ms; self.metrics.checkpoint_creation_latency_ms.observe( @@ -118,7 +121,7 @@ impl CheckpointOutput for LogCheckpointOutput { summary: &CheckpointSummary, contents: &CheckpointContents, _epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { trace!( "Including following transactions in checkpoint {}: {:?}", summary.sequence_number, @@ -144,7 +147,7 @@ impl CertifiedCheckpointOutput for LogCheckpointOutput { async fn certified_checkpoint_created( &self, summary: &CertifiedCheckpointSummary, - ) -> SuiResult { + ) -> IotaResult { info!( "Certified checkpoint with sequence {} and digest {}", summary.sequence_number, @@ -155,11 +158,11 @@ impl CertifiedCheckpointOutput for LogCheckpointOutput { } pub struct SendCheckpointToStateSync { - handle: sui_network::state_sync::Handle, + handle: iota_network::state_sync::Handle, } impl SendCheckpointToStateSync { - pub fn new(handle: sui_network::state_sync::Handle) -> Self { + pub fn new(handle: iota_network::state_sync::Handle) -> Self { Self { handle } } } @@ -170,7 +173,7 @@ impl CertifiedCheckpointOutput for SendCheckpointToStateSync { async fn certified_checkpoint_created( &self, summary: &CertifiedCheckpointSummary, - ) -> SuiResult { + ) -> IotaResult { info!( "Certified checkpoint with sequence {} and digest {}", summary.sequence_number, diff --git a/crates/iota-core/src/checkpoints/metrics.rs b/crates/iota-core/src/checkpoints/metrics.rs new file mode 100644 index 00000000000..2a29ed5642e --- /dev/null +++ b/crates/iota-core/src/checkpoints/metrics.rs @@ -0,0 +1,124 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::Arc; + +use mysten_metrics::histogram::Histogram; +use prometheus::{ + register_int_counter_vec_with_registry, register_int_counter_with_registry, + register_int_gauge_vec_with_registry, register_int_gauge_with_registry, IntCounter, + IntCounterVec, IntGauge, IntGaugeVec, Registry, +}; + +pub struct CheckpointMetrics { + pub last_certified_checkpoint: IntGauge, + pub last_constructed_checkpoint: IntGauge, + pub checkpoint_errors: IntCounter, + pub transactions_included_in_checkpoint: IntCounter, + pub checkpoint_roots_count: IntCounter, + pub checkpoint_participation: IntCounterVec, + pub last_received_checkpoint_signatures: IntGaugeVec, + pub last_sent_checkpoint_signature: IntGauge, + pub highest_accumulated_epoch: IntGauge, + pub checkpoint_creation_latency_ms: Histogram, + pub remote_checkpoint_forks: IntCounter, + pub split_brain_checkpoint_forks: IntCounter, + pub last_created_checkpoint_age_ms: Histogram, + pub last_certified_checkpoint_age_ms: Histogram, +} + +impl CheckpointMetrics { + pub fn new(registry: &Registry) -> Arc { + let this = Self { + last_certified_checkpoint: register_int_gauge_with_registry!( + "last_certified_checkpoint", + "Last certified checkpoint", + registry + ) + .unwrap(), + last_constructed_checkpoint: register_int_gauge_with_registry!( + "last_constructed_checkpoint", + "Last constructed checkpoint", + registry + ) + .unwrap(), + last_created_checkpoint_age_ms: Histogram::new_in_registry( + "last_created_checkpoint_age_ms", + "Age of the last created checkpoint", + registry, + ), + last_certified_checkpoint_age_ms: Histogram::new_in_registry( + "last_certified_checkpoint_age_ms", + "Age of the last certified checkpoint", + registry, + ), + checkpoint_errors: register_int_counter_with_registry!( + "checkpoint_errors", + "Checkpoints errors count", + registry + ) + .unwrap(), + transactions_included_in_checkpoint: register_int_counter_with_registry!( + "transactions_included_in_checkpoint", + "Transactions included in a checkpoint", + registry + ) + .unwrap(), + checkpoint_roots_count: register_int_counter_with_registry!( + "checkpoint_roots_count", + "Number of checkpoint roots received from consensus", + registry + ) + .unwrap(), + checkpoint_participation: register_int_counter_vec_with_registry!( + "checkpoint_participation", + "Participation in checkpoint certification by validator", + &["signer"], + registry + ) + .unwrap(), + last_received_checkpoint_signatures: register_int_gauge_vec_with_registry!( + "last_received_checkpoint_signatures", + "Last received checkpoint signatures by validator", + &["signer"], + registry + ) + .unwrap(), + last_sent_checkpoint_signature: register_int_gauge_with_registry!( + "last_sent_checkpoint_signature", + "Last checkpoint signature sent by myself", + registry + ) + .unwrap(), + highest_accumulated_epoch: register_int_gauge_with_registry!( + "highest_accumulated_epoch", + "Highest accumulated epoch", + registry + ) + .unwrap(), + checkpoint_creation_latency_ms: Histogram::new_in_registry( + "checkpoint_creation_latency_ms", + "Latency from consensus commit timstamp to local checkpoint creation in milliseconds", + registry, + ), + remote_checkpoint_forks: register_int_counter_with_registry!( + "remote_checkpoint_forks", + "Number of remote checkpoints that forked from local checkpoints", + registry + ) + .unwrap(), + split_brain_checkpoint_forks: register_int_counter_with_registry!( + "split_brain_checkpoint_forks", + "Number of checkpoints that have resulted in a split brain", + registry + ) + .unwrap(), + }; + Arc::new(this) + } + + pub fn new_for_tests() -> Arc { + Self::new(&Registry::new()) + } +} diff --git a/crates/iota-core/src/checkpoints/mod.rs b/crates/iota-core/src/checkpoints/mod.rs new file mode 100644 index 00000000000..8e5d253b926 --- /dev/null +++ b/crates/iota-core/src/checkpoints/mod.rs @@ -0,0 +1,2325 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod causal_order; +pub mod checkpoint_executor; +mod checkpoint_output; +mod metrics; + +use std::{ + collections::{BTreeMap, HashMap, HashSet}, + fs::File, + io::Write, + path::Path, + sync::Arc, + time::Duration, +}; + +use chrono::Utc; +use diffy::create_patch; +use futures::{ + future::{select, Either}, + FutureExt, +}; +use iota_macros::fail_point; +use iota_network::default_mysten_network_config; +use iota_protocol_config::ProtocolVersion; +use iota_types::{ + base_types::{AuthorityName, ConciseableName, EpochId, TransactionDigest}, + committee::StakeUnit, + crypto::AuthorityStrongQuorumSignInfo, + digests::{CheckpointContentsDigest, CheckpointDigest}, + effects::{TransactionEffects, TransactionEffectsAPI}, + error::IotaResult, + gas::GasCostSummary, + iota_system_state::{ + epoch_start_iota_system_state::EpochStartSystemStateTrait, IotaSystemState, + IotaSystemStateTrait, + }, + message_envelope::Message, + messages_checkpoint::{ + CertifiedCheckpointSummary, CheckpointContents, CheckpointRequestV2, CheckpointResponseV2, + CheckpointSequenceNumber, CheckpointSignatureMessage, CheckpointSummary, + CheckpointSummaryResponse, CheckpointTimestamp, EndOfEpochData, FullCheckpointContents, + SignedCheckpointSummary, TrustedCheckpoint, VerifiedCheckpoint, VerifiedCheckpointContents, + }, + messages_consensus::ConsensusTransactionKey, + signature::GenericSignature, + transaction::{TransactionDataAPI, TransactionKey, TransactionKind}, +}; +use itertools::Itertools; +use mysten_metrics::{monitored_scope, spawn_monitored_task, MonitoredFutureExt}; +use parking_lot::Mutex; +use rand::{rngs::OsRng, seq::SliceRandom}; +use serde::{Deserialize, Serialize}; +use tokio::{ + sync::{watch, Notify}, + time::timeout, +}; +use tracing::{debug, error, info, instrument, warn}; +use typed_store::{ + rocks::{DBMap, MetricConf}, + traits::{TableSummary, TypedStoreDebug}, + Map, TypedStoreError, +}; +use typed_store_derive::DBMapUtils; + +pub use crate::checkpoints::{ + checkpoint_output::{ + LogCheckpointOutput, SendCheckpointToStateSync, SubmitCheckpointToConsensus, + }, + metrics::CheckpointMetrics, +}; +use crate::{ + authority::{ + authority_per_epoch_store::AuthorityPerEpochStore, AuthorityState, EffectsNotifyRead, + }, + authority_client::{make_network_authority_clients_with_network_config, AuthorityAPI}, + checkpoints::{ + causal_order::CausalOrder, + checkpoint_output::{CertifiedCheckpointOutput, CheckpointOutput}, + }, + consensus_handler::SequencedConsensusTransactionKey, + stake_aggregator::{InsertResult, MultiStakeAggregator}, + state_accumulator::StateAccumulator, +}; + +pub type CheckpointHeight = u64; + +pub struct EpochStats { + pub checkpoint_count: u64, + pub transaction_count: u64, + pub total_gas_reward: u64, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PendingCheckpointInfo { + pub timestamp_ms: CheckpointTimestamp, + pub last_of_epoch: bool, + pub checkpoint_height: CheckpointHeight, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PendingCheckpoint { + pub roots: Vec, + pub details: PendingCheckpointInfo, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum PendingCheckpointV2 { + // This is an enum for future upgradability, though at the moment there is only one variant. + V2(PendingCheckpointV2Contents), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PendingCheckpointV2Contents { + pub roots: Vec, + pub details: PendingCheckpointInfo, +} + +impl PendingCheckpointV2 { + pub fn as_v2(&self) -> &PendingCheckpointV2Contents { + match self { + PendingCheckpointV2::V2(contents) => contents, + } + } + + pub fn into_v2(self) -> PendingCheckpointV2Contents { + match self { + PendingCheckpointV2::V2(contents) => contents, + } + } + + pub fn expect_v1(self) -> PendingCheckpoint { + let v2 = self.into_v2(); + PendingCheckpoint { + roots: v2 + .roots + .into_iter() + .map(|root| *root.unwrap_digest()) + .collect(), + details: v2.details, + } + } + + pub fn roots(&self) -> &Vec { + &self.as_v2().roots + } + + pub fn details(&self) -> &PendingCheckpointInfo { + &self.as_v2().details + } + + pub fn height(&self) -> CheckpointHeight { + self.details().checkpoint_height + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct BuilderCheckpointSummary { + pub summary: CheckpointSummary, + // Height at which this checkpoint summary was built. None for genesis checkpoint + pub checkpoint_height: Option, + pub position_in_commit: usize, +} + +#[derive(DBMapUtils)] +pub struct CheckpointStore { + /// Maps checkpoint contents digest to checkpoint contents + pub(crate) checkpoint_content: DBMap, + + /// Maps checkpoint contents digest to checkpoint sequence number + pub(crate) checkpoint_sequence_by_contents_digest: + DBMap, + + /// Stores entire checkpoint contents from state sync, indexed by sequence + /// number, for efficient reads of full checkpoints. Entries from this + /// table are deleted after state accumulation has completed. + full_checkpoint_content: DBMap, + + /// Stores certified checkpoints + pub(crate) certified_checkpoints: DBMap, + /// Map from checkpoint digest to certified checkpoint + pub(crate) checkpoint_by_digest: DBMap, + + /// Store locally computed checkpoint summaries so that we can detect forks + /// and log useful information. Can be pruned as soon as we verify that + /// we are in agreement with the latest certified checkpoint. + pub(crate) locally_computed_checkpoints: DBMap, + + /// A map from epoch ID to the sequence number of the last checkpoint in + /// that epoch. + epoch_last_checkpoint_map: DBMap, + + /// Watermarks used to determine the highest verified, fully synced, and + /// fully executed checkpoints + pub(crate) watermarks: DBMap, +} + +impl CheckpointStore { + pub fn new(path: &Path) -> Arc { + Arc::new(Self::open_tables_read_write( + path.to_path_buf(), + MetricConf::new("checkpoint"), + None, + None, + )) + } + + pub fn open_readonly(path: &Path) -> CheckpointStoreReadOnly { + Self::get_read_only_handle( + path.to_path_buf(), + None, + None, + MetricConf::new("checkpoint_readonly"), + ) + } + + #[instrument(level = "info", skip_all)] + pub fn insert_genesis_checkpoint( + &self, + checkpoint: VerifiedCheckpoint, + contents: CheckpointContents, + epoch_store: &AuthorityPerEpochStore, + ) { + assert_eq!( + checkpoint.epoch(), + 0, + "can't call insert_genesis_checkpoint with a checkpoint not in epoch 0" + ); + assert_eq!( + *checkpoint.sequence_number(), + 0, + "can't call insert_genesis_checkpoint with a checkpoint that doesn't have a sequence number of 0" + ); + + // Only insert the genesis checkpoint if the DB is empty and doesn't have it + // already + if self + .get_checkpoint_by_digest(checkpoint.digest()) + .unwrap() + .is_none() + { + if epoch_store.epoch() == checkpoint.epoch { + epoch_store + .put_genesis_checkpoint_in_builder(checkpoint.data(), &contents) + .unwrap(); + } else { + debug!( + validator_epoch =% epoch_store.epoch(), + genesis_epoch =% checkpoint.epoch(), + "Not inserting checkpoint builder data for genesis checkpoint", + ); + } + self.insert_checkpoint_contents(contents).unwrap(); + self.insert_verified_checkpoint(&checkpoint).unwrap(); + self.update_highest_synced_checkpoint(&checkpoint).unwrap(); + } + } + + pub fn get_checkpoint_by_digest( + &self, + digest: &CheckpointDigest, + ) -> Result, TypedStoreError> { + self.checkpoint_by_digest + .get(digest) + .map(|maybe_checkpoint| maybe_checkpoint.map(|c| c.into())) + } + + pub fn get_checkpoint_by_sequence_number( + &self, + sequence_number: CheckpointSequenceNumber, + ) -> Result, TypedStoreError> { + self.certified_checkpoints + .get(&sequence_number) + .map(|maybe_checkpoint| maybe_checkpoint.map(|c| c.into())) + } + + pub fn get_locally_computed_checkpoint( + &self, + sequence_number: CheckpointSequenceNumber, + ) -> Result, TypedStoreError> { + self.locally_computed_checkpoints.get(&sequence_number) + } + + pub fn get_sequence_number_by_contents_digest( + &self, + digest: &CheckpointContentsDigest, + ) -> Result, TypedStoreError> { + self.checkpoint_sequence_by_contents_digest.get(digest) + } + + pub fn delete_contents_digest_sequence_number_mapping( + &self, + digest: &CheckpointContentsDigest, + ) -> Result<(), TypedStoreError> { + self.checkpoint_sequence_by_contents_digest.remove(digest) + } + + pub fn get_latest_certified_checkpoint(&self) -> Option { + self.certified_checkpoints + .unbounded_iter() + .skip_to_last() + .next() + .map(|(_, v)| v.into()) + } + + pub fn get_latest_locally_computed_checkpoint(&self) -> Option { + self.locally_computed_checkpoints + .unbounded_iter() + .skip_to_last() + .next() + .map(|(_, v)| v) + } + + pub fn multi_get_checkpoint_by_sequence_number( + &self, + sequence_numbers: &[CheckpointSequenceNumber], + ) -> Result>, TypedStoreError> { + let checkpoints = self + .certified_checkpoints + .multi_get(sequence_numbers)? + .into_iter() + .map(|maybe_checkpoint| maybe_checkpoint.map(|c| c.into())) + .collect(); + + Ok(checkpoints) + } + + pub fn multi_get_checkpoint_content( + &self, + contents_digest: &[CheckpointContentsDigest], + ) -> Result>, TypedStoreError> { + self.checkpoint_content.multi_get(contents_digest) + } + + pub fn get_highest_verified_checkpoint( + &self, + ) -> Result, TypedStoreError> { + let highest_verified = if let Some(highest_verified) = + self.watermarks.get(&CheckpointWatermark::HighestVerified)? + { + highest_verified + } else { + return Ok(None); + }; + self.get_checkpoint_by_digest(&highest_verified.1) + } + + pub fn get_highest_synced_checkpoint( + &self, + ) -> Result, TypedStoreError> { + let highest_synced = if let Some(highest_synced) = + self.watermarks.get(&CheckpointWatermark::HighestSynced)? + { + highest_synced + } else { + return Ok(None); + }; + self.get_checkpoint_by_digest(&highest_synced.1) + } + + pub fn get_highest_executed_checkpoint_seq_number( + &self, + ) -> Result, TypedStoreError> { + if let Some(highest_executed) = + self.watermarks.get(&CheckpointWatermark::HighestExecuted)? + { + Ok(Some(highest_executed.0)) + } else { + Ok(None) + } + } + + pub fn get_highest_executed_checkpoint( + &self, + ) -> Result, TypedStoreError> { + let highest_executed = if let Some(highest_executed) = + self.watermarks.get(&CheckpointWatermark::HighestExecuted)? + { + highest_executed + } else { + return Ok(None); + }; + self.get_checkpoint_by_digest(&highest_executed.1) + } + + pub fn get_highest_pruned_checkpoint_seq_number( + &self, + ) -> Result { + Ok(self + .watermarks + .get(&CheckpointWatermark::HighestPruned)? + .unwrap_or_default() + .0) + } + + pub fn get_checkpoint_contents( + &self, + digest: &CheckpointContentsDigest, + ) -> Result, TypedStoreError> { + self.checkpoint_content.get(digest) + } + + pub fn get_full_checkpoint_contents_by_sequence_number( + &self, + seq: CheckpointSequenceNumber, + ) -> Result, TypedStoreError> { + self.full_checkpoint_content.get(&seq) + } + + fn prune_local_summaries(&self) -> IotaResult { + if let Some((last_local_summary, _)) = self + .locally_computed_checkpoints + .unbounded_iter() + .skip_to_last() + .next() + { + let mut batch = self.locally_computed_checkpoints.batch(); + batch.schedule_delete_range( + &self.locally_computed_checkpoints, + &0, + &last_local_summary, + )?; + batch.write()?; + info!("Pruned local summaries up to {:?}", last_local_summary); + } + Ok(()) + } + + fn check_for_checkpoint_fork( + &self, + local_checkpoint: &CheckpointSummary, + verified_checkpoint: &VerifiedCheckpoint, + ) { + if local_checkpoint != verified_checkpoint.data() { + let verified_contents = self + .get_checkpoint_contents(&verified_checkpoint.content_digest) + .map(|opt_contents| { + opt_contents + .map(|contents| format!("{:?}", contents)) + .unwrap_or_else(|| { + format!( + "Verified checkpoint contents not found, digest: {:?}", + verified_checkpoint.content_digest, + ) + }) + }) + .map_err(|e| { + format!( + "Failed to get verified checkpoint contents, digest: {:?} error: {:?}", + verified_checkpoint.content_digest, e + ) + }) + .unwrap_or_else(|err_msg| err_msg); + + let local_contents = self + .get_checkpoint_contents(&local_checkpoint.content_digest) + .map(|opt_contents| { + opt_contents + .map(|contents| format!("{:?}", contents)) + .unwrap_or_else(|| { + format!( + "Local checkpoint contents not found, digest: {:?}", + local_checkpoint.content_digest + ) + }) + }) + .map_err(|e| { + format!( + "Failed to get local checkpoint contents, digest: {:?} error: {:?}", + local_checkpoint.content_digest, e + ) + }) + .unwrap_or_else(|err_msg| err_msg); + + // checkpoint contents may be too large for panic message. + error!( + verified_checkpoint = ?verified_checkpoint.data(), + ?verified_contents, + ?local_checkpoint, + ?local_contents, + "Local checkpoint fork detected!", + ); + panic!( + "Local checkpoint fork detected for sequence number: {}", + local_checkpoint.sequence_number() + ); + } + } + + // Called by consensus (ConsensusAggregator). + // Different from `insert_verified_checkpoint`, it does not touch + // the highest_verified_checkpoint watermark such that state sync + // will have a chance to process this checkpoint and perform some + // state-sync only things. + pub fn insert_certified_checkpoint( + &self, + checkpoint: &VerifiedCheckpoint, + ) -> Result<(), TypedStoreError> { + debug!( + checkpoint_seq = checkpoint.sequence_number(), + "Inserting certified checkpoint", + ); + let mut batch = self.certified_checkpoints.batch(); + batch + .insert_batch( + &self.certified_checkpoints, + [(checkpoint.sequence_number(), checkpoint.serializable_ref())], + )? + .insert_batch( + &self.checkpoint_by_digest, + [(checkpoint.digest(), checkpoint.serializable_ref())], + )?; + if checkpoint.next_epoch_committee().is_some() { + batch.insert_batch( + &self.epoch_last_checkpoint_map, + [(&checkpoint.epoch(), checkpoint.sequence_number())], + )?; + } + batch.write()?; + + if let Some(local_checkpoint) = self + .locally_computed_checkpoints + .get(checkpoint.sequence_number())? + { + self.check_for_checkpoint_fork(&local_checkpoint, checkpoint); + } + + Ok(()) + } + + // Called by state sync, apart from inserting the checkpoint and updating + // related tables, it also bumps the highest_verified_checkpoint watermark. + #[instrument(level = "debug", skip_all)] + pub fn insert_verified_checkpoint( + &self, + checkpoint: &VerifiedCheckpoint, + ) -> Result<(), TypedStoreError> { + self.insert_certified_checkpoint(checkpoint)?; + self.update_highest_verified_checkpoint(checkpoint) + } + + pub fn update_highest_verified_checkpoint( + &self, + checkpoint: &VerifiedCheckpoint, + ) -> Result<(), TypedStoreError> { + if Some(*checkpoint.sequence_number()) + > self + .get_highest_verified_checkpoint()? + .map(|x| *x.sequence_number()) + { + debug!( + checkpoint_seq = checkpoint.sequence_number(), + "Updating highest verified checkpoint", + ); + self.watermarks.insert( + &CheckpointWatermark::HighestVerified, + &(*checkpoint.sequence_number(), *checkpoint.digest()), + )?; + } + + Ok(()) + } + + pub fn update_highest_synced_checkpoint( + &self, + checkpoint: &VerifiedCheckpoint, + ) -> Result<(), TypedStoreError> { + debug!( + checkpoint_seq = checkpoint.sequence_number(), + "Updating highest synced checkpoint", + ); + self.watermarks.insert( + &CheckpointWatermark::HighestSynced, + &(*checkpoint.sequence_number(), *checkpoint.digest()), + ) + } + + pub fn update_highest_executed_checkpoint( + &self, + checkpoint: &VerifiedCheckpoint, + ) -> Result<(), TypedStoreError> { + if let Some(seq_number) = self.get_highest_executed_checkpoint_seq_number()? { + if seq_number >= *checkpoint.sequence_number() { + return Ok(()); + } + assert_eq!( + seq_number + 1, + *checkpoint.sequence_number(), + "Cannot update highest executed checkpoint to {} when current highest executed checkpoint is {}", + checkpoint.sequence_number(), + seq_number + ); + } + debug!( + checkpoint_seq = checkpoint.sequence_number(), + "Updating highest executed checkpoint", + ); + self.watermarks.insert( + &CheckpointWatermark::HighestExecuted, + &(*checkpoint.sequence_number(), *checkpoint.digest()), + ) + } + + pub fn update_highest_pruned_checkpoint( + &self, + checkpoint: &VerifiedCheckpoint, + ) -> Result<(), TypedStoreError> { + self.watermarks.insert( + &CheckpointWatermark::HighestPruned, + &(*checkpoint.sequence_number(), *checkpoint.digest()), + ) + } + + /// Sets highest executed checkpoint to any value. + /// + /// WARNING: This method is very subtle and can corrupt the database if used + /// incorrectly. It should only be used in one-off cases or tests after + /// fully understanding the risk. + pub fn set_highest_executed_checkpoint_subtle( + &self, + checkpoint: &VerifiedCheckpoint, + ) -> Result<(), TypedStoreError> { + self.watermarks.insert( + &CheckpointWatermark::HighestExecuted, + &(*checkpoint.sequence_number(), *checkpoint.digest()), + ) + } + + pub fn insert_checkpoint_contents( + &self, + contents: CheckpointContents, + ) -> Result<(), TypedStoreError> { + debug!( + checkpoint_seq = ?contents.digest(), + "Inserting checkpoint contents", + ); + self.checkpoint_content.insert(contents.digest(), &contents) + } + + pub fn insert_verified_checkpoint_contents( + &self, + checkpoint: &VerifiedCheckpoint, + full_contents: VerifiedCheckpointContents, + ) -> Result<(), TypedStoreError> { + let mut batch = self.full_checkpoint_content.batch(); + batch.insert_batch( + &self.checkpoint_sequence_by_contents_digest, + [(&checkpoint.content_digest, checkpoint.sequence_number())], + )?; + let full_contents = full_contents.into_inner(); + batch.insert_batch( + &self.full_checkpoint_content, + [(checkpoint.sequence_number(), &full_contents)], + )?; + + let contents = full_contents.into_checkpoint_contents(); + assert_eq!(&checkpoint.content_digest, contents.digest()); + + batch.insert_batch(&self.checkpoint_content, [(contents.digest(), &contents)])?; + + batch.write() + } + + pub fn delete_full_checkpoint_contents( + &self, + seq: CheckpointSequenceNumber, + ) -> Result<(), TypedStoreError> { + self.full_checkpoint_content.remove(&seq) + } + + pub fn get_epoch_last_checkpoint( + &self, + epoch_id: EpochId, + ) -> IotaResult> { + let seq = self.epoch_last_checkpoint_map.get(&epoch_id)?; + let checkpoint = match seq { + Some(seq) => self.get_checkpoint_by_sequence_number(seq)?, + None => None, + }; + Ok(checkpoint) + } + + pub fn insert_epoch_last_checkpoint( + &self, + epoch_id: EpochId, + checkpoint: &VerifiedCheckpoint, + ) -> IotaResult { + self.epoch_last_checkpoint_map + .insert(&epoch_id, checkpoint.sequence_number())?; + Ok(()) + } + + /// Given the epoch ID, and the last checkpoint of the epoch, derive a few + /// statistics of the epoch. + pub fn get_epoch_stats( + &self, + epoch: EpochId, + last_checkpoint: &CheckpointSummary, + ) -> Option { + let (first_checkpoint, prev_epoch_network_transactions) = if epoch == 0 { + (0, 0) + } else if let Ok(Some(checkpoint)) = self.get_epoch_last_checkpoint(epoch - 1) { + ( + checkpoint.sequence_number + 1, + checkpoint.network_total_transactions, + ) + } else { + return None; + }; + Some(EpochStats { + checkpoint_count: last_checkpoint.sequence_number - first_checkpoint + 1, + transaction_count: last_checkpoint.network_total_transactions + - prev_epoch_network_transactions, + total_gas_reward: last_checkpoint + .epoch_rolling_gas_cost_summary + .computation_cost, + }) + } + + pub fn checkpoint_db(&self, path: &Path) -> IotaResult { + // This checkpoints the entire db and not one column family + self.checkpoint_content + .checkpoint_db(path) + .map_err(Into::into) + } + + pub fn delete_highest_executed_checkpoint_test_only(&self) -> Result<(), TypedStoreError> { + let mut wb = self.watermarks.batch(); + wb.delete_batch( + &self.watermarks, + std::iter::once(CheckpointWatermark::HighestExecuted), + )?; + wb.write()?; + Ok(()) + } + + pub fn reset_db_for_execution_since_genesis(&self) -> IotaResult { + self.delete_highest_executed_checkpoint_test_only()?; + self.watermarks.rocksdb.flush()?; + Ok(()) + } +} + +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] +pub enum CheckpointWatermark { + HighestVerified, + HighestSynced, + HighestExecuted, + HighestPruned, +} + +pub struct CheckpointBuilder { + state: Arc, + tables: Arc, + epoch_store: Arc, + notify: Arc, + notify_aggregator: Arc, + effects_store: Arc, + accumulator: Arc, + output: Box, + exit: watch::Receiver<()>, + metrics: Arc, + max_transactions_per_checkpoint: usize, + max_checkpoint_size_bytes: usize, +} + +pub struct CheckpointAggregator { + tables: Arc, + epoch_store: Arc, + notify: Arc, + exit: watch::Receiver<()>, + current: Option, + output: Box, + state: Arc, + metrics: Arc, +} + +// This holds information to aggregate signatures for one checkpoint +pub struct CheckpointSignatureAggregator { + next_index: u64, + summary: CheckpointSummary, + digest: CheckpointDigest, + /// Aggregates voting stake for each signed checkpoint proposal by authority + signatures_by_digest: MultiStakeAggregator, + tables: Arc, + state: Arc, + metrics: Arc, +} + +impl CheckpointBuilder { + fn new( + state: Arc, + tables: Arc, + epoch_store: Arc, + notify: Arc, + effects_store: Arc, + accumulator: Arc, + output: Box, + exit: watch::Receiver<()>, + notify_aggregator: Arc, + metrics: Arc, + max_transactions_per_checkpoint: usize, + max_checkpoint_size_bytes: usize, + ) -> Self { + Self { + state, + tables, + epoch_store, + notify, + effects_store, + accumulator, + output, + exit, + notify_aggregator, + metrics, + max_transactions_per_checkpoint, + max_checkpoint_size_bytes, + } + } + + async fn run(mut self) { + info!("Starting CheckpointBuilder"); + 'main: loop { + // Check whether an exit signal has been received, if so we break the loop. + // This gives us a chance to exit, in case checkpoint making keeps failing. + match self.exit.has_changed() { + Ok(true) | Err(_) => { + break; + } + Ok(false) => (), + }; + let mut last = self + .epoch_store + .last_built_checkpoint_commit_height() + .expect("epoch should not have ended"); + for (height, pending) in self + .epoch_store + .get_pending_checkpoints(last) + .expect("unexpected epoch store error") + { + last = Some(height); + debug!( + checkpoint_commit_height = height, + "Making checkpoint at commit height" + ); + if let Err(e) = self.make_checkpoint(height, pending).await { + error!("Error while making checkpoint, will retry in 1s: {:?}", e); + tokio::time::sleep(Duration::from_secs(1)).await; + self.metrics.checkpoint_errors.inc(); + continue 'main; + } + } + debug!("Waiting for more checkpoints from consensus after processing {last:?}"); + match select(self.exit.changed().boxed(), self.notify.notified().boxed()).await { + Either::Left(_) => { + // break loop on exit signal + break; + } + Either::Right(_) => {} + } + } + info!("Shutting down CheckpointBuilder"); + } + + #[instrument(level = "debug", skip_all, fields(?height))] + async fn make_checkpoint( + &self, + height: CheckpointHeight, + pending: PendingCheckpointV2, + ) -> anyhow::Result<()> { + let pending = pending.into_v2(); + self.metrics + .checkpoint_roots_count + .inc_by(pending.roots.len() as u64); + + let root_digests = self + .epoch_store + .notify_read_executed_digests(&pending.roots) + .in_monitored_scope("CheckpointNotifyDigests") + .await?; + let root_effects = self + .effects_store + .notify_read_executed_effects(root_digests) + .in_monitored_scope("CheckpointNotifyRead") + .await?; + + let _scope = monitored_scope("CheckpointBuilder"); + let unsorted = self.complete_checkpoint_effects(root_effects)?; + let sorted = { + let _scope = monitored_scope("CheckpointBuilder::causal_sort"); + CausalOrder::causal_sort(unsorted) + }; + let new_checkpoint = self.create_checkpoints(sorted, pending.details).await?; + self.write_checkpoints(height, new_checkpoint).await?; + Ok(()) + } + + #[instrument(level = "debug", skip_all)] + async fn write_checkpoints( + &self, + height: CheckpointHeight, + new_checkpoint: Vec<(CheckpointSummary, CheckpointContents)>, + ) -> IotaResult { + let _scope = monitored_scope("CheckpointBuilder::write_checkpoints"); + let mut batch = self.tables.checkpoint_content.batch(); + for (summary, contents) in &new_checkpoint { + debug!( + checkpoint_commit_height = height, + checkpoint_seq = summary.sequence_number, + contents_digest = ?contents.digest(), + "writing checkpoint", + ); + self.output + .checkpoint_created(summary, contents, &self.epoch_store) + .await?; + + self.metrics + .transactions_included_in_checkpoint + .inc_by(contents.size() as u64); + let sequence_number = summary.sequence_number; + self.metrics + .last_constructed_checkpoint + .set(sequence_number as i64); + + batch.insert_batch( + &self.tables.checkpoint_content, + [(contents.digest(), contents)], + )?; + + batch.insert_batch( + &self.tables.locally_computed_checkpoints, + [(sequence_number, summary)], + )?; + } + batch.write()?; + + for (local_checkpoint, _) in &new_checkpoint { + if let Some(certified_checkpoint) = self + .tables + .certified_checkpoints + .get(local_checkpoint.sequence_number())? + { + self.tables + .check_for_checkpoint_fork(local_checkpoint, &certified_checkpoint.into()); + } + } + + self.notify_aggregator.notify_one(); + self.epoch_store + .process_pending_checkpoint(height, new_checkpoint)?; + Ok(()) + } + + #[allow(clippy::type_complexity)] + fn split_checkpoint_chunks( + &self, + effects_and_transaction_sizes: Vec<(TransactionEffects, usize)>, + signatures: Vec>, + ) -> anyhow::Result)>>> { + let _guard = monitored_scope("CheckpointBuilder::split_checkpoint_chunks"); + let mut chunks = Vec::new(); + let mut chunk = Vec::new(); + let mut chunk_size: usize = 0; + for ((effects, transaction_size), signatures) in effects_and_transaction_sizes + .into_iter() + .zip(signatures.into_iter()) + { + // Roll over to a new chunk after either max count or max size is reached. + // The size calculation here is intended to estimate the size of the + // FullCheckpointContents struct. If this code is modified, that struct + // should also be updated accordingly. + let size = transaction_size + + bcs::serialized_size(&effects)? + + bcs::serialized_size(&signatures)?; + if chunk.len() == self.max_transactions_per_checkpoint + || (chunk_size + size) > self.max_checkpoint_size_bytes + { + if chunk.is_empty() { + // Always allow at least one tx in a checkpoint. + warn!( + "Size of single transaction ({size}) exceeds max checkpoint size ({}); allowing excessively large checkpoint to go through.", + self.max_checkpoint_size_bytes + ); + } else { + chunks.push(chunk); + chunk = Vec::new(); + chunk_size = 0; + } + } + + chunk.push((effects, signatures)); + chunk_size += size; + } + + if !chunk.is_empty() || chunks.is_empty() { + // We intentionally create an empty checkpoint if there is no content provided + // to make a 'heartbeat' checkpoint. + // Important: if some conditions are added here later, we need to make sure we + // always have at least one chunk if last_pending_of_epoch is set + chunks.push(chunk); + // Note: empty checkpoints are ok - they shouldn't happen at all on + // a network with even modest load. Even if they do + // happen, it is still useful as it allows fullnodes to + // distinguish between "no transactions have happened" and "i am not + // receiving new checkpoints". + } + Ok(chunks) + } + + #[instrument(level = "debug", skip_all)] + async fn create_checkpoints( + &self, + all_effects: Vec, + details: PendingCheckpointInfo, + ) -> anyhow::Result> { + let _scope = monitored_scope("CheckpointBuilder::create_checkpoints"); + let total = all_effects.len(); + let mut last_checkpoint = self.epoch_store.last_built_checkpoint_summary()?; + if last_checkpoint.is_none() { + let epoch = self.epoch_store.epoch(); + if epoch > 0 { + let previous_epoch = epoch - 1; + let last_verified = self.tables.get_epoch_last_checkpoint(previous_epoch)?; + last_checkpoint = last_verified.map(VerifiedCheckpoint::into_summary_and_sequence); + if let Some((ref seq, _)) = last_checkpoint { + debug!( + "No checkpoints in builder DB, taking checkpoint from previous epoch with sequence {seq}" + ); + } else { + // This is some serious bug with when CheckpointBuilder started so surfacing it + // via panic + panic!("Can not find last checkpoint for previous epoch {previous_epoch}"); + } + } + } + let last_checkpoint_seq = last_checkpoint.as_ref().map(|(seq, _)| *seq); + info!( + next_checkpoint_seq = last_checkpoint_seq.unwrap_or_default() + 1, + checkpoint_timestamp = details.timestamp_ms, + "Creating checkpoint(s) for {} transactions", + all_effects.len(), + ); + + let all_digests: Vec<_> = all_effects + .iter() + .map(|effect| *effect.transaction_digest()) + .collect(); + let transactions_and_sizes = self + .state + .get_cache_reader() + .get_transactions_and_serialized_sizes(&all_digests)?; + let mut all_effects_and_transaction_sizes = Vec::with_capacity(all_effects.len()); + let mut transactions = Vec::with_capacity(all_effects.len()); + let mut transaction_keys = Vec::with_capacity(all_effects.len()); + { + let _guard = monitored_scope("CheckpointBuilder::wait_for_transactions_sequenced"); + debug!( + ?last_checkpoint_seq, + "Waiting for {:?} certificates to appear in consensus", + all_effects_and_transaction_sizes.len() + ); + + for (effects, transaction_and_size) in all_effects + .into_iter() + .zip(transactions_and_sizes.into_iter()) + { + let (transaction, size) = transaction_and_size + .unwrap_or_else(|| panic!("Could not find executed transaction {:?}", effects)); + // ConsensusCommitPrologue and AuthenticatorStateUpdate are guaranteed to be + // processed before we reach here + if !matches!( + transaction.inner().transaction_data().kind(), + TransactionKind::ConsensusCommitPrologue(_) + | TransactionKind::ConsensusCommitPrologueV2(_) + | TransactionKind::AuthenticatorStateUpdate(_) + | TransactionKind::RandomnessStateUpdate(_) + ) { + transaction_keys.push(SequencedConsensusTransactionKey::External( + ConsensusTransactionKey::Certificate(*effects.transaction_digest()), + )); + } + transactions.push(transaction); + all_effects_and_transaction_sizes.push((effects, size)); + } + + self.epoch_store + .consensus_messages_processed_notify(transaction_keys) + .await?; + } + + let signatures = self + .epoch_store + .user_signatures_for_checkpoint(&transactions, &all_digests)?; + debug!( + ?last_checkpoint_seq, + "Received {} checkpoint user signatures from consensus", + signatures.len() + ); + + let chunks = self.split_checkpoint_chunks(all_effects_and_transaction_sizes, signatures)?; + let chunks_count = chunks.len(); + + let mut checkpoints = Vec::with_capacity(chunks_count); + debug!( + ?last_checkpoint_seq, + "Creating {} checkpoints with {} transactions", chunks_count, total, + ); + + let epoch = self.epoch_store.epoch(); + for (index, transactions) in chunks.into_iter().enumerate() { + let first_checkpoint_of_epoch = index == 0 + && last_checkpoint + .as_ref() + .map(|(_, c)| c.epoch != epoch) + .unwrap_or(true); + if first_checkpoint_of_epoch { + self.epoch_store + .record_epoch_first_checkpoint_creation_time_metric(); + } + let last_checkpoint_of_epoch = details.last_of_epoch && index == chunks_count - 1; + + let sequence_number = last_checkpoint + .as_ref() + .map(|(_, c)| c.sequence_number + 1) + .unwrap_or_default(); + let timestamp_ms = details.timestamp_ms; + if let Some((_, last_checkpoint)) = &last_checkpoint { + if last_checkpoint.timestamp_ms > timestamp_ms { + error!( + "Unexpected decrease of checkpoint timestamp, sequence: {}, previous: {}, current: {}", + sequence_number, last_checkpoint.timestamp_ms, timestamp_ms + ); + } + } + + let (mut effects, mut signatures): (Vec<_>, Vec<_>) = transactions.into_iter().unzip(); + let epoch_rolling_gas_cost_summary = + self.get_epoch_total_gas_cost(last_checkpoint.as_ref().map(|(_, c)| c), &effects); + + let end_of_epoch_data = if last_checkpoint_of_epoch { + let system_state_obj = self + .augment_epoch_last_checkpoint( + &epoch_rolling_gas_cost_summary, + timestamp_ms, + &mut effects, + &mut signatures, + sequence_number, + ) + .await?; + + let committee = system_state_obj.get_current_epoch_committee().committee; + + // This must happen after the call to augment_epoch_last_checkpoint, + // otherwise we will not capture the change_epoch tx + self.accumulator.accumulate_checkpoint( + effects.clone(), + sequence_number, + self.epoch_store.clone(), + )?; + + let root_state_digest = self + .accumulator + .digest_epoch(&epoch, sequence_number, self.epoch_store.clone()) + .in_monitored_scope("CheckpointBuilder::digest_epoch") + .await?; + self.metrics.highest_accumulated_epoch.set(epoch as i64); + info!("Epoch {epoch} root state hash digest: {root_state_digest:?}"); + + let epoch_commitments = if self + .epoch_store + .protocol_config() + .check_commit_root_state_digest_supported() + { + vec![root_state_digest.into()] + } else { + vec![] + }; + + Some(EndOfEpochData { + next_epoch_committee: committee.voting_rights, + next_epoch_protocol_version: ProtocolVersion::new( + system_state_obj.protocol_version(), + ), + epoch_commitments, + }) + } else { + None + }; + + let contents = CheckpointContents::new_with_digests_and_signatures( + effects.iter().map(TransactionEffects::execution_digests), + signatures, + ); + + let num_txns = contents.size() as u64; + + let network_total_transactions = last_checkpoint + .as_ref() + .map(|(_, c)| c.network_total_transactions + num_txns) + .unwrap_or(num_txns); + + let previous_digest = last_checkpoint.as_ref().map(|(_, c)| c.digest()); + let summary = CheckpointSummary::new( + epoch, + sequence_number, + network_total_transactions, + &contents, + previous_digest, + epoch_rolling_gas_cost_summary, + end_of_epoch_data, + timestamp_ms, + ); + summary.report_checkpoint_age_ms(&self.metrics.last_created_checkpoint_age_ms); + if last_checkpoint_of_epoch { + info!( + checkpoint_seq = sequence_number, + "creating last checkpoint of epoch {}", epoch + ); + if let Some(stats) = self.tables.get_epoch_stats(epoch, &summary) { + self.epoch_store + .report_epoch_metrics_at_last_checkpoint(stats); + } + } + last_checkpoint = Some((sequence_number, summary.clone())); + checkpoints.push((summary, contents)); + } + + Ok(checkpoints) + } + + fn get_epoch_total_gas_cost( + &self, + last_checkpoint: Option<&CheckpointSummary>, + cur_checkpoint_effects: &[TransactionEffects], + ) -> GasCostSummary { + let (previous_epoch, previous_gas_costs) = last_checkpoint + .map(|c| (c.epoch, c.epoch_rolling_gas_cost_summary.clone())) + .unwrap_or_default(); + let current_gas_costs = GasCostSummary::new_from_txn_effects(cur_checkpoint_effects.iter()); + if previous_epoch == self.epoch_store.epoch() { + // sum only when we are within the same epoch + GasCostSummary::new( + previous_gas_costs.computation_cost + current_gas_costs.computation_cost, + previous_gas_costs.storage_cost + current_gas_costs.storage_cost, + previous_gas_costs.storage_rebate + current_gas_costs.storage_rebate, + previous_gas_costs.non_refundable_storage_fee + + current_gas_costs.non_refundable_storage_fee, + ) + } else { + current_gas_costs + } + } + + #[instrument(level = "error", skip_all)] + async fn augment_epoch_last_checkpoint( + &self, + epoch_total_gas_cost: &GasCostSummary, + epoch_start_timestamp_ms: CheckpointTimestamp, + checkpoint_effects: &mut Vec, + signatures: &mut Vec>, + checkpoint: CheckpointSequenceNumber, + // TODO: Check whether we must use anyhow::Result or can we use IotaResult. + ) -> anyhow::Result { + let (system_state, effects) = self + .state + .create_and_execute_advance_epoch_tx( + &self.epoch_store, + epoch_total_gas_cost, + checkpoint, + epoch_start_timestamp_ms, + ) + .await?; + checkpoint_effects.push(effects); + signatures.push(vec![]); + Ok(system_state) + } + + /// For the given roots return complete list of effects to include in + /// checkpoint This list includes the roots and all their dependencies, + /// which are not part of checkpoint already + #[instrument(level = "debug", skip_all)] + fn complete_checkpoint_effects( + &self, + mut roots: Vec, + ) -> IotaResult> { + let _scope = monitored_scope("CheckpointBuilder::complete_checkpoint_effects"); + let mut results = vec![]; + let mut seen = HashSet::new(); + loop { + let mut pending = HashSet::new(); + + let transactions_included = self + .epoch_store + .builder_included_transactions_in_checkpoint( + roots.iter().map(|e| e.transaction_digest()), + )?; + + for (effect, tx_included) in roots.into_iter().zip(transactions_included.into_iter()) { + let digest = effect.transaction_digest(); + // Unnecessary to read effects of a dependency if the effect is already + // processed. + seen.insert(*digest); + + // Skip roots already included in checkpoints or roots from previous epochs + if tx_included || effect.executed_epoch() < self.epoch_store.epoch() { + continue; + } + + let existing_effects = self + .epoch_store + .effects_signatures_exists(effect.dependencies().iter())?; + + for (dependency, effects_signature_exists) in + effect.dependencies().iter().zip(existing_effects.iter()) + { + // Skip here if dependency not executed in the current epoch. + // Note that the existence of an effects signature in the + // epoch store for the given digest indicates that the transaction + // was locally executed in the current epoch + if !effects_signature_exists { + continue; + } + if seen.insert(*dependency) { + pending.insert(*dependency); + } + } + results.push(effect); + } + if pending.is_empty() { + break; + } + let pending = pending.into_iter().collect::>(); + let effects = self.effects_store.multi_get_executed_effects(&pending)?; + let effects = effects + .into_iter() + .zip(pending) + .map(|(opt, digest)| match opt { + Some(x) => x, + None => panic!( + "Can not find effect for transaction {:?}, however transaction that depend on it was already executed", + digest + ), + }) + .collect::>(); + roots = effects; + } + Ok(results) + } +} + +impl CheckpointAggregator { + fn new( + tables: Arc, + epoch_store: Arc, + notify: Arc, + exit: watch::Receiver<()>, + output: Box, + state: Arc, + metrics: Arc, + ) -> Self { + let current = None; + Self { + tables, + epoch_store, + notify, + exit, + current, + output, + state, + metrics, + } + } + + async fn run(mut self) { + info!("Starting CheckpointAggregator"); + loop { + if let Err(e) = self.run_and_notify().await { + error!( + "Error while aggregating checkpoint, will retry in 1s: {:?}", + e + ); + self.metrics.checkpoint_errors.inc(); + tokio::time::sleep(Duration::from_secs(1)).await; + continue; + } + + match select( + self.exit.changed().boxed(), + timeout(Duration::from_secs(1), self.notify.notified()).boxed(), + ) + .await + { + Either::Left(_) => { + // return on exit signal + info!("Shutting down CheckpointAggregator"); + return; + } + Either::Right(_) => {} + } + } + } + + async fn run_and_notify(&mut self) -> IotaResult { + let summaries = self.run_inner()?; + for summary in summaries { + self.output.certified_checkpoint_created(&summary).await?; + } + Ok(()) + } + + fn run_inner(&mut self) -> IotaResult> { + let _scope = monitored_scope("CheckpointAggregator"); + let mut result = vec![]; + 'outer: loop { + let next_to_certify = self.next_checkpoint_to_certify(); + let current = if let Some(current) = &mut self.current { + // It's possible that the checkpoint was already certified by + // the rest of the network and we've already received the + // certified checkpoint via StateSync. In this case, we reset + // the current signature aggregator to the next checkpoint to + // be certified + if current.summary.sequence_number < next_to_certify { + self.current = None; + continue; + } + current + } else { + let Some(summary) = self + .epoch_store + .get_built_checkpoint_summary(next_to_certify)? + else { + return Ok(result); + }; + self.current = Some(CheckpointSignatureAggregator { + next_index: 0, + digest: summary.digest(), + summary, + signatures_by_digest: MultiStakeAggregator::new( + self.epoch_store.committee().clone(), + ), + tables: self.tables.clone(), + state: self.state.clone(), + metrics: self.metrics.clone(), + }); + self.current.as_mut().unwrap() + }; + + let epoch_tables = self + .epoch_store + .tables() + .expect("should not run past end of epoch"); + let iter = epoch_tables.get_pending_checkpoint_signatures_iter( + current.summary.sequence_number, + current.next_index, + )?; + for ((seq, index), data) in iter { + if seq != current.summary.sequence_number { + debug!( + checkpoint_seq =? current.summary.sequence_number, + "Not enough checkpoint signatures", + ); + // No more signatures (yet) for this checkpoint + return Ok(result); + } + debug!( + checkpoint_seq = current.summary.sequence_number, + "Processing signature for checkpoint (digest: {:?}) from {:?}", + current.summary.digest(), + data.summary.auth_sig().authority.concise() + ); + self.metrics + .checkpoint_participation + .with_label_values(&[&format!( + "{:?}", + data.summary.auth_sig().authority.concise() + )]) + .inc(); + if let Ok(auth_signature) = current.try_aggregate(data) { + let summary = VerifiedCheckpoint::new_unchecked( + CertifiedCheckpointSummary::new_from_data_and_sig( + current.summary.clone(), + auth_signature, + ), + ); + + self.tables.insert_certified_checkpoint(&summary)?; + self.metrics + .last_certified_checkpoint + .set(current.summary.sequence_number as i64); + current + .summary + .report_checkpoint_age_ms(&self.metrics.last_certified_checkpoint_age_ms); + result.push(summary.into_inner()); + self.current = None; + continue 'outer; + } else { + current.next_index = index + 1; + } + } + break; + } + Ok(result) + } + + fn next_checkpoint_to_certify(&self) -> CheckpointSequenceNumber { + self.tables + .certified_checkpoints + .unbounded_iter() + .skip_to_last() + .next() + .map(|(seq, _)| seq + 1) + .unwrap_or_default() + } +} + +impl CheckpointSignatureAggregator { + #[allow(clippy::result_unit_err)] + pub fn try_aggregate( + &mut self, + data: CheckpointSignatureMessage, + ) -> Result { + let their_digest = *data.summary.digest(); + let (_, signature) = data.summary.into_data_and_sig(); + let author = signature.authority; + let envelope = + SignedCheckpointSummary::new_from_data_and_sig(self.summary.clone(), signature); + match self.signatures_by_digest.insert(their_digest, envelope) { + InsertResult::Failed { error } => { + warn!( + checkpoint_seq = self.summary.sequence_number, + "Failed to aggregate new signature from validator {:?}: {:?}", + author.concise(), + error + ); + self.check_for_split_brain(); + Err(()) + } + InsertResult::QuorumReached(cert) => { + // It is not guaranteed that signature.authority == narwhal_cert.author, but we + // do verify the signature so we know that the author signed the + // message at some point. + if their_digest != self.digest { + self.metrics.remote_checkpoint_forks.inc(); + warn!( + checkpoint_seq = self.summary.sequence_number, + "Validator {:?} has mismatching checkpoint digest {}, we have digest {}", + author.concise(), + their_digest, + self.digest + ); + return Err(()); + } + Ok(cert) + } + InsertResult::NotEnoughVotes { + bad_votes: _, + bad_authorities: _, + } => { + self.check_for_split_brain(); + Err(()) + } + } + } + + /// Check if there is a split brain condition in checkpoint signature + /// aggregation, defined as any state wherein it is no longer possible + /// to achieve quorum on a checkpoint proposal, irrespective of the + /// outcome of any outstanding votes. + fn check_for_split_brain(&self) { + debug!( + checkpoint_seq = self.summary.sequence_number, + "Checking for split brain condition" + ); + if self.signatures_by_digest.quorum_unreachable() { + // TODO: at this point we should immediately halt processing + // of new transaction certificates to avoid building on top of + // forked output + // self.halt_all_execution(); + + let digests_by_stake_messages = self + .signatures_by_digest + .get_all_unique_values() + .into_iter() + .sorted_by_key(|(_, (_, stake))| -(*stake as i64)) + .map(|(digest, (_authorities, total_stake))| { + format!("{:?} (total stake: {})", digest, total_stake) + }) + .collect::>(); + error!( + checkpoint_seq = self.summary.sequence_number, + "Split brain detected in checkpoint signature aggregation! Remaining stake: {:?}, Digests by stake: {:?}", + self.signatures_by_digest.uncommitted_stake(), + digests_by_stake_messages, + ); + self.metrics.split_brain_checkpoint_forks.inc(); + + let all_unique_values = self.signatures_by_digest.get_all_unique_values(); + let local_summary = self.summary.clone(); + let state = self.state.clone(); + let tables = self.tables.clone(); + + tokio::spawn(async move { + diagnose_split_brain(all_unique_values, local_summary, state, tables).await; + }); + } + } +} + +/// Create data dump containing relevant data for diagnosing cause of the +/// split brain by querying one disagreeing validator for full checkpoint +/// contents. To minimize peer chatter, we only query one validator at random +/// from each disagreeing faction, as all honest validators that participated in +/// this round may inevitably run the same process. +async fn diagnose_split_brain( + all_unique_values: BTreeMap, StakeUnit)>, + local_summary: CheckpointSummary, + state: Arc, + tables: Arc, +) { + debug!( + checkpoint_seq = local_summary.sequence_number, + "Running split brain diagnostics..." + ); + let time = Utc::now(); + // collect one random disagreeing validator per differing digest + let digest_to_validator = all_unique_values + .iter() + .filter_map(|(digest, (validators, _))| { + if *digest != local_summary.digest() { + let random_validator = validators.choose(&mut OsRng).unwrap(); + Some((*digest, *random_validator)) + } else { + None + } + }) + .collect::>(); + if digest_to_validator.is_empty() { + panic!( + "Given split brain condition, there should be at \ + least one validator that disagrees with local signature" + ); + } + + let epoch_store = state.load_epoch_store_one_call_per_task(); + let committee = epoch_store + .epoch_start_state() + .get_iota_committee_with_network_metadata(); + let network_config = default_mysten_network_config(); + let network_clients = + make_network_authority_clients_with_network_config(&committee, &network_config) + .expect("Failed to make authority clients from committee {committee}"); + + // Query all disagreeing validators + let response_futures = digest_to_validator + .values() + .cloned() + .map(|validator| { + let client = network_clients + .get(&validator) + .expect("Failed to get network client"); + let request = CheckpointRequestV2 { + sequence_number: Some(local_summary.sequence_number), + request_content: true, + certified: false, + }; + client.handle_checkpoint_v2(request) + }) + .collect::>(); + + let digest_name_pair = digest_to_validator.iter(); + let response_data = futures::future::join_all(response_futures) + .await + .into_iter() + .zip(digest_name_pair) + .filter_map(|(response, (digest, name))| match response { + Ok(response) => match response { + CheckpointResponseV2 { + checkpoint: Some(CheckpointSummaryResponse::Pending(summary)), + contents: Some(contents), + } => Some((*name, *digest, summary, contents)), + CheckpointResponseV2 { + checkpoint: Some(CheckpointSummaryResponse::Certified(_)), + contents: _, + } => { + panic!("Expected pending checkpoint, but got certified checkpoint"); + } + CheckpointResponseV2 { + checkpoint: None, + contents: _, + } => { + error!( + "Summary for checkpoint {:?} not found on validator {:?}", + local_summary.sequence_number, name + ); + None + } + CheckpointResponseV2 { + checkpoint: _, + contents: None, + } => { + error!( + "Contents for checkpoint {:?} not found on validator {:?}", + local_summary.sequence_number, name + ); + None + } + }, + Err(e) => { + error!( + "Failed to get checkpoint contents from validator for fork diagnostics: {:?}", + e + ); + None + } + }) + .collect::>(); + + let local_checkpoint_contents = tables + .get_checkpoint_contents(&local_summary.content_digest) + .unwrap_or_else(|_| { + panic!( + "Could not find checkpoint contents for digest {:?}", + local_summary.digest() + ) + }) + .unwrap_or_else(|| { + panic!( + "Could not find local full checkpoint contents for checkpoint {:?}, digest {:?}", + local_summary.sequence_number, + local_summary.digest() + ) + }); + let local_contents_text = format!("{local_checkpoint_contents:?}"); + + let local_summary_text = format!("{local_summary:?}"); + let local_validator = state.name.concise(); + let diff_patches = response_data + .iter() + .map(|(name, other_digest, other_summary, contents)| { + let other_contents_text = format!("{contents:?}"); + let other_summary_text = format!("{other_summary:?}"); + let (local_transactions, local_effects): (Vec<_>, Vec<_>) = local_checkpoint_contents + .enumerate_transactions(&local_summary) + .map(|(_, exec_digest)| (exec_digest.transaction, exec_digest.effects)) + .unzip(); + let (other_transactions, other_effects): (Vec<_>, Vec<_>) = contents + .enumerate_transactions(other_summary) + .map(|(_, exec_digest)| (exec_digest.transaction, exec_digest.effects)) + .unzip(); + let summary_patch = create_patch(&local_summary_text, &other_summary_text); + let contents_patch = create_patch(&local_contents_text, &other_contents_text); + let local_transactions_text = format!("{local_transactions:#?}"); + let other_transactions_text = format!("{other_transactions:#?}"); + let transactions_patch = + create_patch(&local_transactions_text, &other_transactions_text); + let local_effects_text = format!("{local_effects:#?}"); + let other_effects_text = format!("{other_effects:#?}"); + let effects_patch = create_patch(&local_effects_text, &other_effects_text); + let seq_number = local_summary.sequence_number; + let local_digest = local_summary.digest(); + let other_validator = name.concise(); + format!( + "Checkpoint: {seq_number:?}\n\ + Local validator (original): {local_validator:?}, digest: {local_digest:?}\n\ + Other validator (modified): {other_validator:?}, digest: {other_digest:?}\n\n\ + Summary Diff: \n{summary_patch}\n\n\ + Contents Diff: \n{contents_patch}\n\n\ + Transactions Diff: \n{transactions_patch}\n\n\ + Effects Diff: \n{effects_patch}", + ) + }) + .collect::>() + .join("\n\n\n"); + + let header = format!( + "Checkpoint Fork Dump - Authority {local_validator:?}: \n\ + Datetime: {time}", + ); + let fork_logs_text = format!("{header}\n\n{diff_patches}\n\n"); + let path = tempfile::tempdir() + .expect("Failed to create tempdir") + .into_path() + .join(Path::new("checkpoint_fork_dump.txt")); + let mut file = File::create(path).unwrap(); + write!(file, "{}", fork_logs_text).unwrap(); + debug!("{}", fork_logs_text); + + fail_point!("split_brain_reached"); +} + +pub trait CheckpointServiceNotify { + fn notify_checkpoint_signature( + &self, + epoch_store: &AuthorityPerEpochStore, + info: &CheckpointSignatureMessage, + ) -> IotaResult; + + fn notify_checkpoint(&self) -> IotaResult; +} + +/// This is a service used to communicate with other pieces of iota(for ex. +/// authority) +pub struct CheckpointService { + tables: Arc, + notify_builder: Arc, + notify_aggregator: Arc, + last_signature_index: Mutex, + metrics: Arc, +} + +impl CheckpointService { + pub fn spawn( + state: Arc, + checkpoint_store: Arc, + epoch_store: Arc, + effects_store: Arc, + accumulator: Arc, + checkpoint_output: Box, + certified_checkpoint_output: Box, + metrics: Arc, + max_transactions_per_checkpoint: usize, + max_checkpoint_size_bytes: usize, + ) -> (Arc, watch::Sender<()> /* The exit sender */) { + info!( + "Starting checkpoint service with {max_transactions_per_checkpoint} max_transactions_per_checkpoint and {max_checkpoint_size_bytes} max_checkpoint_size_bytes" + ); + let notify_builder = Arc::new(Notify::new()); + let notify_aggregator = Arc::new(Notify::new()); + + let (exit_snd, exit_rcv) = watch::channel(()); + + let builder = CheckpointBuilder::new( + state.clone(), + checkpoint_store.clone(), + epoch_store.clone(), + notify_builder.clone(), + effects_store, + accumulator, + checkpoint_output, + exit_rcv.clone(), + notify_aggregator.clone(), + metrics.clone(), + max_transactions_per_checkpoint, + max_checkpoint_size_bytes, + ); + + spawn_monitored_task!(builder.run()); + + let aggregator = CheckpointAggregator::new( + checkpoint_store.clone(), + epoch_store.clone(), + notify_aggregator.clone(), + exit_rcv, + certified_checkpoint_output, + state.clone(), + metrics.clone(), + ); + + spawn_monitored_task!(aggregator.run()); + + let last_signature_index = epoch_store + .get_last_checkpoint_signature_index() + .expect("should not cross end of epoch"); + let last_signature_index = Mutex::new(last_signature_index); + + let service = Arc::new(Self { + tables: checkpoint_store, + notify_builder, + notify_aggregator, + last_signature_index, + metrics, + }); + (service, exit_snd) + } + + #[cfg(test)] + fn write_and_notify_checkpoint_for_testing( + &self, + epoch_store: &AuthorityPerEpochStore, + checkpoint: PendingCheckpointV2, + ) -> IotaResult { + let mut batch = epoch_store.db_batch_for_test(); + epoch_store.write_pending_checkpoint(&mut batch, &checkpoint)?; + batch.write()?; + self.notify_checkpoint()?; + Ok(()) + } +} + +impl CheckpointServiceNotify for CheckpointService { + fn notify_checkpoint_signature( + &self, + epoch_store: &AuthorityPerEpochStore, + info: &CheckpointSignatureMessage, + ) -> IotaResult { + let sequence = info.summary.sequence_number; + let signer = info.summary.auth_sig().authority.concise(); + if let Some(last_certified) = self + .tables + .certified_checkpoints + .keys() + .skip_to_last() + .next() + .transpose()? + { + if sequence <= last_certified { + debug!( + checkpoint_seq = sequence, + "Ignore checkpoint signature from {} - already certified", signer, + ); + return Ok(()); + } + } + debug!( + checkpoint_seq = sequence, + "Received checkpoint signature, digest {} from {}", + info.summary.digest(), + signer, + ); + self.metrics + .last_received_checkpoint_signatures + .with_label_values(&[&signer.to_string()]) + .set(sequence as i64); + // While it can be tempting to make last_signature_index into AtomicU64, this + // won't work We need to make sure we write to `pending_signatures` and + // trigger `notify_aggregator` without race conditions + let mut index = self.last_signature_index.lock(); + *index += 1; + epoch_store.insert_checkpoint_signature(sequence, *index, info)?; + self.notify_aggregator.notify_one(); + Ok(()) + } + + fn notify_checkpoint(&self) -> IotaResult { + self.notify_builder.notify_one(); + Ok(()) + } +} + +// test helper +pub struct CheckpointServiceNoop {} +impl CheckpointServiceNotify for CheckpointServiceNoop { + fn notify_checkpoint_signature( + &self, + _: &AuthorityPerEpochStore, + _: &CheckpointSignatureMessage, + ) -> IotaResult { + Ok(()) + } + + fn notify_checkpoint(&self) -> IotaResult { + Ok(()) + } +} + +impl PendingCheckpoint { + pub fn height(&self) -> CheckpointHeight { + self.details.checkpoint_height + } +} + +impl PendingCheckpointV2 {} + +impl From for PendingCheckpointV2 { + fn from(value: PendingCheckpoint) -> Self { + PendingCheckpointV2::V2(PendingCheckpointV2Contents { + roots: value + .roots + .into_iter() + .map(TransactionKey::Digest) + .collect(), + details: value.details, + }) + } +} + +#[cfg(test)] +mod tests { + use std::{ + collections::{BTreeMap, HashMap}, + ops::Deref, + }; + + use async_trait::async_trait; + use iota_macros::sim_test; + use iota_types::{ + base_types::{ObjectID, SequenceNumber, TransactionEffectsDigest}, + crypto::{AuthoritySignInfo, Signature}, + effects::TransactionEffects, + messages_checkpoint::SignedCheckpointSummary, + move_package::MovePackage, + object, + transaction::{GenesisObject, VerifiedTransaction}, + }; + use shared_crypto::intent::{Intent, IntentScope}; + use tokio::sync::mpsc; + + use super::*; + use crate::authority::test_authority_builder::TestAuthorityBuilder; + + #[sim_test] + pub async fn checkpoint_builder_test() { + telemetry_subscribers::init_for_testing(); + let state = TestAuthorityBuilder::new().build().await; + + let dummy_tx = VerifiedTransaction::new_genesis_transaction(vec![]); + let dummy_tx_with_data = + VerifiedTransaction::new_genesis_transaction(vec![GenesisObject::RawObject { + data: object::Data::Package( + MovePackage::new( + ObjectID::random(), + SequenceNumber::new(), + BTreeMap::from([(format!("{:0>40000}", "1"), Vec::new())]), + 100_000, + // no modules so empty type_origin_table as no types are defined in this + // package + Vec::new(), + // no modules so empty linkage_table as no dependencies of this package + // exist + BTreeMap::new(), + ) + .unwrap(), + ), + owner: object::Owner::Immutable, + }]); + for i in 0..15 { + state + .database_for_testing() + .perpetual_tables + .transactions + .insert(&d(i), dummy_tx.serializable_ref()) + .unwrap(); + } + for i in 15..20 { + state + .database_for_testing() + .perpetual_tables + .transactions + .insert(&d(i), dummy_tx_with_data.serializable_ref()) + .unwrap(); + } + + let mut store = HashMap::::new(); + commit_cert_for_test( + &mut store, + state.clone(), + d(1), + vec![d(2), d(3)], + GasCostSummary::new(11, 12, 11, 1), + ); + commit_cert_for_test( + &mut store, + state.clone(), + d(2), + vec![d(3), d(4)], + GasCostSummary::new(21, 22, 21, 1), + ); + commit_cert_for_test( + &mut store, + state.clone(), + d(3), + vec![], + GasCostSummary::new(31, 32, 31, 1), + ); + commit_cert_for_test( + &mut store, + state.clone(), + d(4), + vec![], + GasCostSummary::new(41, 42, 41, 1), + ); + for i in [10, 11, 12, 13] { + commit_cert_for_test( + &mut store, + state.clone(), + d(i), + vec![], + GasCostSummary::new(41, 42, 41, 1), + ); + } + for i in [15, 16, 17] { + commit_cert_for_test( + &mut store, + state.clone(), + d(i), + vec![], + GasCostSummary::new(51, 52, 51, 1), + ); + } + let all_digests: Vec<_> = store.keys().copied().collect(); + for digest in all_digests { + let signature = Signature::Ed25519IotaSignature(Default::default()).into(); + state + .epoch_store_for_testing() + .test_insert_user_signature(digest, vec![signature]); + } + + let (output, mut result) = mpsc::channel::<(CheckpointContents, CheckpointSummary)>(10); + let (certified_output, mut certified_result) = + mpsc::channel::(10); + let store = Arc::new(store); + + let ckpt_dir = tempfile::tempdir().unwrap(); + let checkpoint_store = CheckpointStore::new(ckpt_dir.path()); + + let accumulator = StateAccumulator::new(state.get_accumulator_store().clone()); + + let epoch_store = state.epoch_store_for_testing(); + let (checkpoint_service, _exit) = CheckpointService::spawn( + state.clone(), + checkpoint_store, + epoch_store.clone(), + store, + Arc::new(accumulator), + Box::new(output), + Box::new(certified_output), + CheckpointMetrics::new_for_tests(), + 3, + 100_000, + ); + + checkpoint_service + .write_and_notify_checkpoint_for_testing(&epoch_store, p(0, vec![4])) + .unwrap(); + // Verify that sending same digests at same height is noop + checkpoint_service + .write_and_notify_checkpoint_for_testing(&epoch_store, p(0, vec![4])) + .unwrap(); + checkpoint_service + .write_and_notify_checkpoint_for_testing(&epoch_store, p(1, vec![1, 3])) + .unwrap(); + checkpoint_service + .write_and_notify_checkpoint_for_testing(&epoch_store, p(2, vec![10, 11, 12, 13])) + .unwrap(); + checkpoint_service + .write_and_notify_checkpoint_for_testing(&epoch_store, p(3, vec![15, 16, 17])) + .unwrap(); + + let (c1c, c1s) = result.recv().await.unwrap(); + let (c2c, c2s) = result.recv().await.unwrap(); + + let c1t = c1c.iter().map(|d| d.transaction).collect::>(); + let c2t = c2c.iter().map(|d| d.transaction).collect::>(); + assert_eq!(c1t, vec![d(4)]); + assert_eq!(c1s.previous_digest, None); + assert_eq!(c1s.sequence_number, 0); + assert_eq!( + c1s.epoch_rolling_gas_cost_summary, + GasCostSummary::new(41, 42, 41, 1) + ); + + assert_eq!(c2t, vec![d(3), d(2), d(1)]); + assert_eq!(c2s.previous_digest, Some(c1s.digest())); + assert_eq!(c2s.sequence_number, 1); + assert_eq!( + c2s.epoch_rolling_gas_cost_summary, + GasCostSummary::new(104, 108, 104, 4) + ); + + // Pending at index 2 had 4 transactions, and we configured 3 transactions max. + // Verify that we split into 2 checkpoints. + let (c3c, c3s) = result.recv().await.unwrap(); + let c3t = c3c.iter().map(|d| d.transaction).collect::>(); + let (c4c, c4s) = result.recv().await.unwrap(); + let c4t = c4c.iter().map(|d| d.transaction).collect::>(); + assert_eq!(c3s.sequence_number, 2); + assert_eq!(c3s.previous_digest, Some(c2s.digest())); + assert_eq!(c4s.sequence_number, 3); + assert_eq!(c4s.previous_digest, Some(c3s.digest())); + assert_eq!(c3t, vec![d(10), d(11), d(12)]); + assert_eq!(c4t, vec![d(13)]); + + // Pending at index 3 had 3 transactions of 40K size, and we configured 100K + // max. Verify that we split into 2 checkpoints. + let (c5c, c5s) = result.recv().await.unwrap(); + let c5t = c5c.iter().map(|d| d.transaction).collect::>(); + let (c6c, c6s) = result.recv().await.unwrap(); + let c6t = c6c.iter().map(|d| d.transaction).collect::>(); + assert_eq!(c5s.sequence_number, 4); + assert_eq!(c5s.previous_digest, Some(c4s.digest())); + assert_eq!(c6s.sequence_number, 5); + assert_eq!(c6s.previous_digest, Some(c5s.digest())); + assert_eq!(c5t, vec![d(15), d(16)]); + assert_eq!(c6t, vec![d(17)]); + + let c1ss = SignedCheckpointSummary::new(c1s.epoch, c1s, state.secret.deref(), state.name); + let c2ss = SignedCheckpointSummary::new(c2s.epoch, c2s, state.secret.deref(), state.name); + + checkpoint_service + .notify_checkpoint_signature( + &epoch_store, + &CheckpointSignatureMessage { summary: c2ss }, + ) + .unwrap(); + checkpoint_service + .notify_checkpoint_signature( + &epoch_store, + &CheckpointSignatureMessage { summary: c1ss }, + ) + .unwrap(); + + let c1sc = certified_result.recv().await.unwrap(); + let c2sc = certified_result.recv().await.unwrap(); + assert_eq!(c1sc.sequence_number, 0); + assert_eq!(c2sc.sequence_number, 1); + } + + #[async_trait] + impl EffectsNotifyRead for HashMap { + async fn notify_read_executed_effects( + &self, + digests: Vec, + ) -> IotaResult> { + Ok(digests + .into_iter() + .map(|d| self.get(&d).expect("effects not found").clone()) + .collect()) + } + + async fn notify_read_executed_effects_digests( + &self, + digests: Vec, + ) -> IotaResult> { + Ok(digests + .into_iter() + .map(|d| { + self.get(&d) + .map(|fx| fx.digest()) + .expect("effects not found") + }) + .collect()) + } + + fn multi_get_executed_effects( + &self, + digests: &[TransactionDigest], + ) -> IotaResult>> { + Ok(digests.iter().map(|d| self.get(d).cloned()).collect()) + } + } + + #[async_trait::async_trait] + impl CheckpointOutput for mpsc::Sender<(CheckpointContents, CheckpointSummary)> { + async fn checkpoint_created( + &self, + summary: &CheckpointSummary, + contents: &CheckpointContents, + _epoch_store: &Arc, + ) -> IotaResult { + self.try_send((contents.clone(), summary.clone())).unwrap(); + Ok(()) + } + } + + #[async_trait::async_trait] + impl CertifiedCheckpointOutput for mpsc::Sender { + async fn certified_checkpoint_created( + &self, + summary: &CertifiedCheckpointSummary, + ) -> IotaResult { + self.try_send(summary.clone()).unwrap(); + Ok(()) + } + } + + fn p(i: u64, t: Vec) -> PendingCheckpointV2 { + PendingCheckpointV2::V2(PendingCheckpointV2Contents { + roots: t + .into_iter() + .map(|t| TransactionKey::Digest(d(t))) + .collect(), + details: PendingCheckpointInfo { + timestamp_ms: 0, + last_of_epoch: false, + checkpoint_height: i, + }, + }) + } + + fn d(i: u8) -> TransactionDigest { + let mut bytes: [u8; 32] = Default::default(); + bytes[0] = i; + TransactionDigest::new(bytes) + } + + fn e( + transaction_digest: TransactionDigest, + dependencies: Vec, + gas_used: GasCostSummary, + ) -> TransactionEffects { + let mut effects = TransactionEffects::default(); + *effects.transaction_digest_mut_for_testing() = transaction_digest; + *effects.dependencies_mut_for_testing() = dependencies; + *effects.gas_cost_summary_mut_for_testing() = gas_used; + effects + } + + fn commit_cert_for_test( + store: &mut HashMap, + state: Arc, + digest: TransactionDigest, + dependencies: Vec, + gas_used: GasCostSummary, + ) { + let epoch_store = state.epoch_store_for_testing(); + let effects = e(digest, dependencies, gas_used); + store.insert(digest, effects.clone()); + epoch_store + .insert_tx_cert_and_effects_signature( + &TransactionKey::Digest(digest), + &digest, + None, + Some(&AuthoritySignInfo::new( + epoch_store.epoch(), + &effects, + Intent::iota_app(IntentScope::TransactionEffects), + state.name, + &*state.secret, + )), + ) + .expect("Inserting cert fx and sigs should not fail"); + } +} diff --git a/crates/sui-core/src/consensus_adapter.rs b/crates/iota-core/src/consensus_adapter.rs similarity index 98% rename from crates/sui-core/src/consensus_adapter.rs rename to crates/iota-core/src/consensus_adapter.rs index acde7800be0..b417ccb8dd9 100644 --- a/crates/sui-core/src/consensus_adapter.rs +++ b/crates/iota-core/src/consensus_adapter.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -19,6 +20,15 @@ use futures::{ future::{select, Either}, pin_mut, FutureExt, }; +use iota_protocol_config::ProtocolConfig; +use iota_simulator::{anemo::PeerId, narwhal_network::connectivity::ConnectionStatus}; +use iota_types::{ + base_types::{AuthorityName, TransactionDigest}, + committee::{Committee, CommitteeTrait}, + error::{IotaError, IotaResult}, + fp_ensure, + messages_consensus::{ConsensusTransaction, ConsensusTransactionKind}, +}; use itertools::Itertools; use mysten_metrics::{spawn_monitored_task, GaugeGuard, GaugeGuardFutureExt}; use narwhal_types::{TransactionProto, TransactionsClient}; @@ -31,15 +41,6 @@ use prometheus::{ IntGaugeVec, Registry, }; use rand::{rngs::StdRng, SeedableRng}; -use sui_protocol_config::ProtocolConfig; -use sui_simulator::{anemo::PeerId, narwhal_network::connectivity::ConnectionStatus}; -use sui_types::{ - base_types::{AuthorityName, TransactionDigest}, - committee::{Committee, CommitteeTrait}, - error::{SuiError, SuiResult}, - fp_ensure, - messages_consensus::{ConsensusTransaction, ConsensusTransactionKind}, -}; use tap::prelude::*; use tokio::{ sync::{Semaphore, SemaphorePermit}, @@ -185,16 +186,16 @@ pub trait SubmitToConsensus: Sync + Send + 'static { &self, transaction: &ConsensusTransaction, epoch_store: &Arc, - ) -> SuiResult; + ) -> IotaResult; } #[async_trait::async_trait] -impl SubmitToConsensus for TransactionsClient { +impl SubmitToConsensus for TransactionsClient { async fn submit_to_consensus( &self, transaction: &ConsensusTransaction, _epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { let serialized = bcs::to_bytes(transaction).expect("Serializing consensus transaction cannot fail"); let bytes = Bytes::from(serialized.clone()); @@ -202,7 +203,7 @@ impl SubmitToConsensus for TransactionsClient, - ) -> SuiResult { + ) -> IotaResult { let transaction = bcs::to_bytes(transaction).expect("Serializing consensus transaction cannot fail"); // The retrieved LocalNarwhalClient can be from the past epoch. Submit would @@ -236,7 +237,7 @@ impl SubmitToConsensus for LazyNarwhalClient { client .submit_transaction(transaction) .await - .map_err(|e| SuiError::FailedToSubmitToConsensus(format!("{:?}", e))) + .map_err(|e| IotaError::FailedToSubmitToConsensus(format!("{:?}", e))) .tap_err(|r| { // Will be logged by caller as well. warn!("Submit transaction failed with: {:?}", r); @@ -245,7 +246,7 @@ impl SubmitToConsensus for LazyNarwhalClient { } } -/// Submit Sui certificates to the consensus. +/// Submit Iota certificates to the consensus. pub struct ConsensusAdapter { /// The network client connecting to the consensus node of this authority. consensus_client: Arc, @@ -594,7 +595,7 @@ impl ConsensusAdapter { transaction: ConsensusTransaction, lock: Option<&RwLockReadGuard>, epoch_store: &Arc, - ) -> SuiResult> { + ) -> IotaResult> { epoch_store.insert_pending_consensus_transactions(&transaction, lock)?; Ok(self.submit_unchecked(transaction, epoch_store)) } @@ -612,10 +613,10 @@ impl ConsensusAdapter { self.submit_semaphore.available_permits() > 0 } - pub(crate) fn check_consensus_overload(&self) -> SuiResult { + pub(crate) fn check_consensus_overload(&self) -> IotaResult { fp_ensure!( self.check_limits(), - SuiError::TooManyTransactionsPendingConsensus + IotaError::TooManyTransactionsPendingConsensus ); Ok(()) } @@ -1067,7 +1068,7 @@ impl SubmitToConsensus for Arc { &self, transaction: &ConsensusTransaction, epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { self.submit(transaction.clone(), None, epoch_store) .map(|_| ()) } @@ -1087,12 +1088,12 @@ mod adapter_tests { use std::{sync::Arc, time::Duration}; use fastcrypto::traits::KeyPair; - use rand::{rngs::StdRng, Rng, SeedableRng}; - use sui_types::{ + use iota_types::{ base_types::TransactionDigest, committee::Committee, crypto::{get_key_pair_from_rng, AuthorityKeyPair, AuthorityPublicKeyBytes}, }; + use rand::{rngs::StdRng, Rng, SeedableRng}; use super::position_submit_certificate; use crate::consensus_adapter::{ @@ -1135,7 +1136,7 @@ mod adapter_tests { Some(1), Some(Duration::from_secs(2)), ConsensusAdapterMetrics::new_test(), - sui_protocol_config::ProtocolConfig::get_for_max_version_UNSAFE(), + iota_protocol_config::ProtocolConfig::get_for_max_version_UNSAFE(), ); // transaction to submit @@ -1167,7 +1168,7 @@ mod adapter_tests { None, None, ConsensusAdapterMetrics::new_test(), - sui_protocol_config::ProtocolConfig::get_for_max_version_UNSAFE(), + iota_protocol_config::ProtocolConfig::get_for_max_version_UNSAFE(), ); let (delay_step, position, positions_moved, _) = diff --git a/crates/sui-core/src/consensus_handler.rs b/crates/iota-core/src/consensus_handler.rs similarity index 98% rename from crates/sui-core/src/consensus_handler.rs rename to crates/iota-core/src/consensus_handler.rs index 3bf2db10d9e..f7bc6079bf3 100644 --- a/crates/sui-core/src/consensus_handler.rs +++ b/crates/iota-core/src/consensus_handler.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -10,22 +11,22 @@ use std::{ use arc_swap::ArcSwap; use async_trait::async_trait; -use lru::LruCache; -use mysten_metrics::{monitored_scope, spawn_monitored_task}; -use narwhal_config::Committee; -use narwhal_executor::{ExecutionIndices, ExecutionState}; -use narwhal_types::ConsensusOutput; -use serde::{Deserialize, Serialize}; -use sui_macros::{fail_point_async, fail_point_if}; -use sui_types::{ +use iota_macros::{fail_point_async, fail_point_if}; +use iota_types::{ authenticator_state::ActiveJwk, base_types::{AuthorityName, EpochId, TransactionDigest}, digests::ConsensusCommitDigest, executable_transaction::{TrustedExecutableTransaction, VerifiedExecutableTransaction}, + iota_system_state::epoch_start_iota_system_state::EpochStartSystemStateTrait, messages_consensus::{ConsensusTransaction, ConsensusTransactionKey, ConsensusTransactionKind}, - sui_system_state::epoch_start_sui_system_state::EpochStartSystemStateTrait, transaction::{SenderSignedData, VerifiedTransaction}, }; +use lru::LruCache; +use mysten_metrics::{monitored_scope, spawn_monitored_task}; +use narwhal_config::Committee; +use narwhal_executor::{ExecutionIndices, ExecutionState}; +use narwhal_types::ConsensusOutput; +use serde::{Deserialize, Serialize}; use tracing::{debug, error, info, instrument, trace_span}; use crate::{ @@ -479,8 +480,8 @@ impl ConsensusHandler { fail_point_if!("correlated-crash-after-consensus-commit-boundary", || { let key = [commit_sub_dag_index, self.epoch_store.epoch()]; - if sui_simulator::random::deterministic_probability(&key, 0.01) { - sui_simulator::task::kill_current_node(None); + if iota_simulator::random::deterministic_probability(&key, 0.01) { + iota_simulator::task::kill_current_node(None); } }); @@ -825,24 +826,24 @@ impl SequencedConsensusTransaction { mod tests { use std::collections::BTreeSet; - use narwhal_config::AuthorityIdentifier; - use narwhal_test_utils::latest_protocol_version; - use narwhal_types::{Batch, Certificate, CommittedSubDag, HeaderV1Builder, ReputationScores}; - use prometheus::Registry; - use shared_crypto::intent::Intent; - use sui_protocol_config::{ConsensusTransactionOrdering, SupportedProtocolVersions}; - use sui_types::{ - base_types::{random_object_ref, AuthorityName, SuiAddress}, + use iota_protocol_config::{ConsensusTransactionOrdering, SupportedProtocolVersions}; + use iota_types::{ + base_types::{random_object_ref, AuthorityName, IotaAddress}, committee::Committee, + iota_system_state::epoch_start_iota_system_state::EpochStartSystemStateTrait, messages_consensus::{ AuthorityCapabilities, ConsensusTransaction, ConsensusTransactionKind, }, object::Object, - sui_system_state::epoch_start_sui_system_state::EpochStartSystemStateTrait, transaction::{ CertifiedTransaction, SenderSignedData, TransactionData, TransactionDataAPI, }, }; + use narwhal_config::AuthorityIdentifier; + use narwhal_test_utils::latest_protocol_version; + use narwhal_types::{Batch, Certificate, CommittedSubDag, HeaderV1Builder, ReputationScores}; + use prometheus::Registry; + use shared_crypto::intent::Intent; use super::*; use crate::{ @@ -864,7 +865,7 @@ mod tests { let latest_protocol_config = &latest_protocol_version(); let network_config = - sui_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir() + iota_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir() .with_objects(objects.clone()) .build(); @@ -1110,14 +1111,14 @@ mod tests { let (committee, keypairs) = Committee::new_simple_test_committee(); let data = SenderSignedData::new( TransactionData::new_transfer( - SuiAddress::default(), + IotaAddress::default(), random_object_ref(), - SuiAddress::default(), + IotaAddress::default(), random_object_ref(), 1000 * gas_price, gas_price, ), - Intent::sui_transaction(), + Intent::iota_transaction(), vec![], ); txn(ConsensusTransactionKind::UserTransaction(Box::new( diff --git a/crates/iota-core/src/consensus_manager/mod.rs b/crates/iota-core/src/consensus_manager/mod.rs new file mode 100644 index 00000000000..bb670098ee9 --- /dev/null +++ b/crates/iota-core/src/consensus_manager/mod.rs @@ -0,0 +1,231 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use std::{path::PathBuf, sync::Arc, time::Instant}; + +use async_trait::async_trait; +use enum_dispatch::enum_dispatch; +use fastcrypto::traits::KeyPair as _; +use iota_config::{ConsensusConfig, NodeConfig}; +use iota_protocol_config::ProtocolVersion; +use iota_types::committee::EpochId; +use mysten_metrics::RegistryService; +use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; +use tokio::sync::{Mutex, MutexGuard}; + +use crate::{ + authority::authority_per_epoch_store::AuthorityPerEpochStore, + consensus_handler::ConsensusHandlerInitializer, + consensus_manager::{ + mysticeti_manager::MysticetiManager, + narwhal_manager::{NarwhalConfiguration, NarwhalManager}, + }, + consensus_validator::IotaTxValidator, + mysticeti_adapter::LazyMysticetiClient, +}; + +pub mod mysticeti_manager; +pub mod narwhal_manager; + +#[derive(PartialEq)] +pub(crate) enum Running { + True(EpochId, ProtocolVersion), + False, +} + +/// An enum to easily differentiate between the chosen consensus engine +#[enum_dispatch] +pub enum ConsensusManager { + Narwhal(NarwhalManager), + Mysticeti(MysticetiManager), +} + +#[async_trait] +#[enum_dispatch(ConsensusManager)] +pub trait ConsensusManagerTrait { + async fn start( + &self, + config: &NodeConfig, + epoch_store: Arc, + consensus_handler_initializer: ConsensusHandlerInitializer, + tx_validator: IotaTxValidator, + ); + + async fn shutdown(&self); + + async fn is_running(&self) -> bool; + + fn get_storage_base_path(&self) -> PathBuf; +} + +impl ConsensusManager { + /// Create a new narwhal manager and wrap it around the Manager enum + pub fn new_narwhal( + config: &NodeConfig, + consensus_config: &ConsensusConfig, + registry_service: &RegistryService, + ) -> Self { + let narwhal_config = NarwhalConfiguration { + primary_keypair: config.protocol_key_pair().copy(), + network_keypair: config.network_key_pair().copy(), + worker_ids_and_keypairs: vec![(0, config.worker_key_pair().copy())], + storage_base_path: consensus_config.db_path().to_path_buf(), + parameters: consensus_config.narwhal_config().to_owned(), + registry_service: registry_service.clone(), + }; + + let metrics = ConsensusManagerMetrics::new(®istry_service.default_registry()); + + Self::Narwhal(NarwhalManager::new(narwhal_config, metrics)) + } + + pub fn new_mysticeti( + config: &NodeConfig, + consensus_config: &ConsensusConfig, + registry_service: &RegistryService, + client: Arc, + ) -> Self { + let metrics = ConsensusManagerMetrics::new(®istry_service.default_registry()); + + Self::Mysticeti(MysticetiManager::new( + config.worker_key_pair().copy(), + config.network_key_pair().copy(), + consensus_config.db_path().to_path_buf(), + metrics, + registry_service.clone(), + client, + )) + } +} + +pub struct ConsensusManagerMetrics { + start_latency: IntGauge, + shutdown_latency: IntGauge, + start_primary_retries: IntGauge, + start_worker_retries: IntGauge, +} + +impl ConsensusManagerMetrics { + pub fn new(registry: &Registry) -> Self { + Self { + start_latency: register_int_gauge_with_registry!( + "consensus_manager_start_latency", + "The latency of starting up consensus nodes", + registry, + ) + .unwrap(), + shutdown_latency: register_int_gauge_with_registry!( + "consensus_manager_shutdown_latency", + "The latency of shutting down consensus nodes", + registry, + ) + .unwrap(), + start_primary_retries: register_int_gauge_with_registry!( + "narwhal_manager_start_primary_retries", + "The number of retries took to start narwhal primary node", + registry + ) + .unwrap(), + start_worker_retries: register_int_gauge_with_registry!( + "narwhal_manager_start_worker_retries", + "The number of retries took to start narwhal worker node", + registry + ) + .unwrap(), + } + } +} + +pub(crate) struct RunningLockGuard<'a> { + state_guard: MutexGuard<'a, Running>, + metrics: &'a ConsensusManagerMetrics, + epoch: Option, + protocol_version: Option, + start: Instant, +} + +impl<'a> RunningLockGuard<'a> { + pub(crate) async fn acquire_start( + metrics: &'a ConsensusManagerMetrics, + running_mutex: &'a Mutex, + epoch: EpochId, + version: ProtocolVersion, + ) -> Option> { + let running = running_mutex.lock().await; + if let Running::True(epoch, version) = *running { + tracing::warn!( + "Consensus is already Running for epoch {epoch:?} & protocol version {version:?} - shutdown first before starting", + ); + return None; + } + + tracing::info!("Starting up consensus for epoch {epoch:?} & protocol version {version:?}"); + + Some(RunningLockGuard { + state_guard: running, + metrics, + start: Instant::now(), + epoch: Some(epoch), + protocol_version: Some(version), + }) + } + + pub(crate) async fn acquire_shutdown( + metrics: &'a ConsensusManagerMetrics, + running_mutex: &'a Mutex, + ) -> Option> { + let running = running_mutex.lock().await; + if let Running::True(epoch, version) = *running { + tracing::info!( + "Shutting down consensus for epoch {epoch:?} & protocol version {version:?}" + ); + } else { + tracing::warn!("Consensus shutdown was called but Narwhal node is not running"); + return None; + } + + Some(RunningLockGuard { + state_guard: running, + metrics, + start: Instant::now(), + epoch: None, + protocol_version: None, + }) + } +} + +impl Drop for RunningLockGuard<'_> { + fn drop(&mut self) { + match *self.state_guard { + // consensus was running and now will have to be marked as shutdown + Running::True(epoch, version) => { + tracing::info!( + "Consensus shutdown for epoch {epoch:?} & protocol version {version:?} is complete - took {} seconds", + self.start.elapsed().as_secs_f64() + ); + + self.metrics + .shutdown_latency + .set(self.start.elapsed().as_secs_f64() as i64); + + *self.state_guard = Running::False; + } + // consensus was not running and now will be marked as started + Running::False => { + tracing::info!( + "Starting up consensus for epoch {} & protocol version {:?} is complete - took {} seconds", + self.epoch.unwrap(), + self.protocol_version.unwrap(), + self.start.elapsed().as_secs_f64() + ); + + self.metrics + .start_latency + .set(self.start.elapsed().as_secs_f64() as i64); + + *self.state_guard = + Running::True(self.epoch.unwrap(), self.protocol_version.unwrap()); + } + } + } +} diff --git a/crates/sui-core/src/consensus_manager/mysticeti_manager.rs b/crates/iota-core/src/consensus_manager/mysticeti_manager.rs similarity index 96% rename from crates/sui-core/src/consensus_manager/mysticeti_manager.rs rename to crates/iota-core/src/consensus_manager/mysticeti_manager.rs index e6a2cb816f3..d1168670356 100644 --- a/crates/sui-core/src/consensus_manager/mysticeti_manager.rs +++ b/crates/iota-core/src/consensus_manager/mysticeti_manager.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{path::PathBuf, sync::Arc}; @@ -7,13 +8,14 @@ use async_trait::async_trait; use consensus_config::{Committee, NetworkKeyPair, Parameters, ProtocolKeyPair}; use consensus_core::{CommitConsumer, CommitIndex, ConsensusAuthority, NetworkType, Round}; use fastcrypto::ed25519; +use iota_config::NodeConfig; +use iota_types::{ + committee::EpochId, + iota_system_state::epoch_start_iota_system_state::EpochStartSystemStateTrait, +}; use mysten_metrics::{RegistryID, RegistryService}; use narwhal_executor::ExecutionState; use prometheus::Registry; -use sui_config::NodeConfig; -use sui_types::{ - committee::EpochId, sui_system_state::epoch_start_sui_system_state::EpochStartSystemStateTrait, -}; use tokio::sync::{mpsc::unbounded_channel, Mutex}; use crate::{ @@ -22,7 +24,7 @@ use crate::{ consensus_manager::{ ConsensusManagerMetrics, ConsensusManagerTrait, Running, RunningLockGuard, }, - consensus_validator::SuiTxValidator, + consensus_validator::IotaTxValidator, mysticeti_adapter::LazyMysticetiClient, }; @@ -84,7 +86,7 @@ impl ConsensusManagerTrait for MysticetiManager { _config: &NodeConfig, epoch_store: Arc, consensus_handler_initializer: ConsensusHandlerInitializer, - tx_validator: SuiTxValidator, + tx_validator: IotaTxValidator, ) { let system_state = epoch_store.epoch_start_state(); let committee: Committee = system_state.get_mysticeti_committee(); diff --git a/crates/sui-core/src/consensus_manager/narwhal_manager.rs b/crates/iota-core/src/consensus_manager/narwhal_manager.rs similarity index 96% rename from crates/sui-core/src/consensus_manager/narwhal_manager.rs rename to crates/iota-core/src/consensus_manager/narwhal_manager.rs index f521cabe194..db71d37a41b 100644 --- a/crates/sui-core/src/consensus_manager/narwhal_manager.rs +++ b/crates/iota-core/src/consensus_manager/narwhal_manager.rs @@ -1,21 +1,22 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{path::PathBuf, sync::Arc}; use async_trait::async_trait; use fastcrypto::traits::KeyPair; +use iota_config::NodeConfig; +use iota_types::{ + committee::EpochId, + crypto::{AuthorityKeyPair, NetworkKeyPair}, + iota_system_state::epoch_start_iota_system_state::EpochStartSystemStateTrait, +}; use mysten_metrics::RegistryService; use narwhal_config::{Parameters, WorkerId}; use narwhal_network::client::NetworkClient; use narwhal_node::{ primary_node::PrimaryNode, worker_node::WorkerNodes, CertificateStoreCacheMetrics, NodeStorage, }; -use sui_config::NodeConfig; -use sui_types::{ - committee::EpochId, - crypto::{AuthorityKeyPair, NetworkKeyPair}, - sui_system_state::epoch_start_sui_system_state::EpochStartSystemStateTrait, -}; use tokio::sync::Mutex; use crate::{ @@ -24,7 +25,7 @@ use crate::{ consensus_manager::{ ConsensusManagerMetrics, ConsensusManagerTrait, Running, RunningLockGuard, }, - consensus_validator::SuiTxValidator, + consensus_validator::IotaTxValidator, }; #[cfg(test)] @@ -101,7 +102,7 @@ impl ConsensusManagerTrait for NarwhalManager { config: &NodeConfig, epoch_store: Arc, consensus_handler_initializer: ConsensusHandlerInitializer, - tx_validator: SuiTxValidator, + tx_validator: IotaTxValidator, ) { let system_state = epoch_store.epoch_start_state(); let epoch = epoch_store.epoch(); diff --git a/crates/sui-core/src/consensus_throughput_calculator.rs b/crates/iota-core/src/consensus_throughput_calculator.rs similarity index 99% rename from crates/sui-core/src/consensus_throughput_calculator.rs rename to crates/iota-core/src/consensus_throughput_calculator.rs index 9f7b33e00ec..465cc306167 100644 --- a/crates/sui-core/src/consensus_throughput_calculator.rs +++ b/crates/iota-core/src/consensus_throughput_calculator.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ collections::{BTreeMap, VecDeque}, @@ -7,10 +8,10 @@ use std::{ }; use arc_swap::ArcSwap; +use iota_protocol_config::Chain; +use iota_types::digests::ChainIdentifier; use narwhal_types::TimestampMs; use parking_lot::Mutex; -use sui_protocol_config::Chain; -use sui_types::digests::ChainIdentifier; use tracing::{debug, warn}; use crate::authority::AuthorityMetrics; diff --git a/crates/sui-core/src/consensus_types/committee_api.rs b/crates/iota-core/src/consensus_types/committee_api.rs similarity index 92% rename from crates/sui-core/src/consensus_types/committee_api.rs rename to crates/iota-core/src/consensus_types/committee_api.rs index 6ec4caaef11..6ce19f051ac 100644 --- a/crates/sui-core/src/consensus_types/committee_api.rs +++ b/crates/iota-core/src/consensus_types/committee_api.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_types::{base_types::AuthorityName, committee::StakeUnit}; use narwhal_config::committee::AuthorityIdentifier; -use sui_types::{base_types::AuthorityName, committee::StakeUnit}; use crate::consensus_types::AuthorityIndex; diff --git a/crates/sui-core/src/consensus_types/consensus_output_api.rs b/crates/iota-core/src/consensus_types/consensus_output_api.rs similarity index 96% rename from crates/sui-core/src/consensus_types/consensus_output_api.rs rename to crates/iota-core/src/consensus_types/consensus_output_api.rs index 067c71730f2..73f0ea8abb0 100644 --- a/crates/sui-core/src/consensus_types/consensus_output_api.rs +++ b/crates/iota-core/src/consensus_types/consensus_output_api.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::fmt::Display; use consensus_core::BlockAPI; use fastcrypto::hash::Hash; +use iota_types::{digests::ConsensusCommitDigest, messages_consensus::ConsensusTransaction}; use narwhal_types::{BatchAPI, CertificateAPI, ConsensusOutputDigest, HeaderAPI}; -use sui_types::{digests::ConsensusCommitDigest, messages_consensus::ConsensusTransaction}; use crate::consensus_types::AuthorityIndex; @@ -98,7 +99,7 @@ impl ConsensusOutputAPI for narwhal_types::ConsensusOutput { fn consensus_digest(&self) -> ConsensusCommitDigest { // We port ConsensusOutputDigest, a narwhal space object, into - // ConsensusCommitDigest, a sui-core space object. We assume they always + // ConsensusCommitDigest, a iota-core space object. We assume they always // have the same format. static_assertions::assert_eq_size!(ConsensusCommitDigest, ConsensusOutputDigest); ConsensusCommitDigest::new(self.digest().into_inner()) diff --git a/crates/iota-core/src/consensus_types/mod.rs b/crates/iota-core/src/consensus_types/mod.rs new file mode 100644 index 00000000000..56a7a6b69fd --- /dev/null +++ b/crates/iota-core/src/consensus_types/mod.rs @@ -0,0 +1,11 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub(crate) mod committee_api; +pub(crate) mod consensus_output_api; + +/// An unique integer ID for a validator used by consensus. +/// In Narwhal, this is the inner value of the `AuthorityIdentifier` type. +/// In Mysticeti, this is used the same way as the AuthorityIndex type there. +pub type AuthorityIndex = u32; diff --git a/crates/sui-core/src/consensus_validator.rs b/crates/iota-core/src/consensus_validator.rs similarity index 88% rename from crates/sui-core/src/consensus_validator.rs rename to crates/iota-core/src/consensus_validator.rs index 20acb4556c0..f86d8dc089f 100644 --- a/crates/sui-core/src/consensus_validator.rs +++ b/crates/iota-core/src/consensus_validator.rs @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; use consensus_core::{TransactionVerifier, ValidationError}; use eyre::WrapErr; +use iota_protocol_config::ProtocolConfig; +use iota_types::messages_consensus::{ConsensusTransaction, ConsensusTransactionKind}; use mysten_metrics::monitored_scope; use narwhal_types::{validate_batch_version, BatchAPI}; use narwhal_worker::TransactionValidator; use prometheus::{register_int_counter_with_registry, IntCounter, Registry}; -use sui_protocol_config::ProtocolConfig; -use sui_types::messages_consensus::{ConsensusTransaction, ConsensusTransactionKind}; use tap::TapFallible; use tracing::{info, warn}; @@ -21,22 +22,22 @@ use crate::{ /// Allows verifying the validity of transactions #[derive(Clone)] -pub struct SuiTxValidator { +pub struct IotaTxValidator { epoch_store: Arc, checkpoint_service: Arc, _transaction_manager: Arc, - metrics: Arc, + metrics: Arc, } -impl SuiTxValidator { +impl IotaTxValidator { pub fn new( epoch_store: Arc, checkpoint_service: Arc, transaction_manager: Arc, - metrics: Arc, + metrics: Arc, ) -> Self { info!( - "SuiTxValidator constructed for epoch {}", + "IotaTxValidator constructed for epoch {}", epoch_store.epoch() ); Self { @@ -122,11 +123,11 @@ fn tx_from_bytes(tx: &[u8]) -> Result { .wrap_err("Malformed transaction (failed to deserialize)") } -impl TransactionValidator for SuiTxValidator { +impl TransactionValidator for IotaTxValidator { type Error = eyre::Report; fn validate(&self, _tx: &[u8]) -> Result<(), Self::Error> { - // We only accept transactions from local sui instance so no need to re-verify + // We only accept transactions from local iota instance so no need to re-verify // it Ok(()) } @@ -152,7 +153,7 @@ impl TransactionValidator for SuiTxValidator { } } -impl TransactionVerifier for SuiTxValidator { +impl TransactionVerifier for IotaTxValidator { fn verify_batch( &self, _protocol_config: &ProtocolConfig, @@ -172,12 +173,12 @@ impl TransactionVerifier for SuiTxValidator { } } -pub struct SuiTxValidatorMetrics { +pub struct IotaTxValidatorMetrics { certificate_signatures_verified: IntCounter, checkpoint_signatures_verified: IntCounter, } -impl SuiTxValidatorMetrics { +impl IotaTxValidatorMetrics { pub fn new(registry: &Registry) -> Arc { Arc::new(Self { certificate_signatures_verified: register_int_counter_with_registry!( @@ -200,20 +201,20 @@ impl SuiTxValidatorMetrics { mod tests { use std::sync::Arc; + use iota_macros::sim_test; + use iota_types::{ + crypto::Ed25519IotaSignature, messages_consensus::ConsensusTransaction, object::Object, + signature::GenericSignature, + }; use narwhal_test_utils::latest_protocol_version; use narwhal_types::{Batch, BatchV1}; use narwhal_worker::TransactionValidator; - use sui_macros::sim_test; - use sui_types::{ - crypto::Ed25519SuiSignature, messages_consensus::ConsensusTransaction, object::Object, - signature::GenericSignature, - }; use crate::{ authority::test_authority_builder::TestAuthorityBuilder, checkpoints::CheckpointServiceNoop, consensus_adapter::consensus_tests::{test_certificates, test_gas_objects}, - consensus_validator::{SuiTxValidator, SuiTxValidatorMetrics}, + consensus_validator::{IotaTxValidator, IotaTxValidatorMetrics}, }; #[sim_test] @@ -226,7 +227,7 @@ mod tests { let latest_protocol_config = &latest_protocol_version(); let network_config = - sui_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir() + iota_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir() .with_objects(objects.clone()) .build(); @@ -243,8 +244,8 @@ mod tests { ) .unwrap(); - let metrics = SuiTxValidatorMetrics::new(&Default::default()); - let validator = SuiTxValidator::new( + let metrics = IotaTxValidatorMetrics::new(&Default::default()); + let validator = IotaTxValidator::new( state.epoch_store_for_testing().clone(), Arc::new(CheckpointServiceNoop {}), state.transaction_manager().clone(), @@ -269,10 +270,11 @@ mod tests { .into_iter() .map(|mut cert| { // set it to an all-zero user signature - cert.tx_signatures_mut_for_testing()[0] = - GenericSignature::Signature(sui_types::crypto::Signature::Ed25519SuiSignature( - Ed25519SuiSignature::default(), - )); + cert.tx_signatures_mut_for_testing()[0] = GenericSignature::Signature( + iota_types::crypto::Signature::Ed25519IotaSignature( + Ed25519IotaSignature::default(), + ), + ); bcs::to_bytes(&ConsensusTransaction::new_certificate_message(&name1, cert)).unwrap() }) .collect(); diff --git a/crates/sui-core/src/db_checkpoint_handler.rs b/crates/iota-core/src/db_checkpoint_handler.rs similarity index 99% rename from crates/sui-core/src/db_checkpoint_handler.rs rename to crates/iota-core/src/db_checkpoint_handler.rs index 674ea80d384..f1078841c41 100644 --- a/crates/sui-core/src/db_checkpoint_handler.rs +++ b/crates/iota-core/src/db_checkpoint_handler.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fs, num::NonZeroUsize, path::PathBuf, sync::Arc, time::Duration}; @@ -6,19 +7,19 @@ use std::{fs, num::NonZeroUsize, path::PathBuf, sync::Arc, time::Duration}; use anyhow::Result; use bytes::Bytes; use futures::future::try_join_all; -use object_store::{path::Path, DynObjectStore}; -use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; -use sui_config::{ +use iota_config::{ node::AuthorityStorePruningConfig, object_storage_config::{ObjectStoreConfig, ObjectStoreType}, }; -use sui_storage::{ +use iota_storage::{ mutex_table::RwLockTable, object_store::util::{ copy_recursively, find_all_dirs_with_epoch_prefix, find_missing_epochs_dirs, path_to_filesystem, put, run_manifest_update_loop, write_snapshot_manifest, }, }; +use object_store::{path::Path, DynObjectStore}; +use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; use tracing::{debug, error, info}; use typed_store::rocks::MetricConf; @@ -386,11 +387,11 @@ impl DBCheckpointHandler { mod tests { use std::fs; - use itertools::Itertools; - use sui_config::object_storage_config::{ObjectStoreConfig, ObjectStoreType}; - use sui_storage::object_store::util::{ + use iota_config::object_storage_config::{ObjectStoreConfig, ObjectStoreType}; + use iota_storage::object_store::util::{ find_all_dirs_with_epoch_prefix, find_missing_epochs_dirs, path_to_filesystem, }; + use itertools::Itertools; use tempfile::TempDir; use crate::db_checkpoint_handler::{ diff --git a/crates/sui-core/src/epoch/committee_store.rs b/crates/iota-core/src/epoch/committee_store.rs similarity index 90% rename from crates/sui-core/src/epoch/committee_store.rs rename to crates/iota-core/src/epoch/committee_store.rs index d6a42b18c36..c8a01ae2b68 100644 --- a/crates/sui-core/src/epoch/committee_store.rs +++ b/crates/iota-core/src/epoch/committee_store.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -7,14 +8,14 @@ use std::{ sync::Arc, }; -use parking_lot::RwLock; -use rocksdb::Options; -use sui_macros::nondeterministic; -use sui_types::{ +use iota_macros::nondeterministic; +use iota_types::{ base_types::ObjectID, committee::{Committee, EpochId}, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, }; +use parking_lot::RwLock; +use rocksdb::Options; use typed_store::{ rocks::{default_db_options, DBMap, DBOptions, MetricConf}, traits::{TableSummary, TypedStoreDebug}, @@ -65,14 +66,14 @@ impl CommitteeStore { Self::new(path, genesis_committee, None) } - pub fn init_genesis_committee(&self, genesis_committee: Committee) -> SuiResult { + pub fn init_genesis_committee(&self, genesis_committee: Committee) -> IotaResult { assert_eq!(genesis_committee.epoch, 0); self.tables.committee_map.insert(&0, &genesis_committee)?; self.cache.write().insert(0, Arc::new(genesis_committee)); Ok(()) } - pub fn insert_new_committee(&self, new_committee: &Committee) -> SuiResult { + pub fn insert_new_committee(&self, new_committee: &Committee) -> IotaResult { if let Some(old_committee) = self.get_committee(&new_committee.epoch)? { // If somehow we already have this committee in the store, they must be the // same. @@ -88,7 +89,7 @@ impl CommitteeStore { Ok(()) } - pub fn get_committee(&self, epoch_id: &EpochId) -> SuiResult>> { + pub fn get_committee(&self, epoch_id: &EpochId) -> IotaResult>> { if let Some(committee) = self.cache.read().get(epoch_id) { return Ok(Some(committee.clone())); } @@ -115,17 +116,17 @@ impl CommitteeStore { /// Return the committee specified by `epoch`. If `epoch` is `None`, return /// the latest committee. // todo - make use of cache or remove this method - pub fn get_or_latest_committee(&self, epoch: Option) -> SuiResult { + pub fn get_or_latest_committee(&self, epoch: Option) -> IotaResult { Ok(match epoch { Some(epoch) => self .get_committee(&epoch)? - .ok_or(SuiError::MissingCommitteeAtEpoch(epoch)) + .ok_or(IotaError::MissingCommitteeAtEpoch(epoch)) .map(|c| Committee::clone(&*c))?, None => self.get_latest_committee(), }) } - pub fn checkpoint_db(&self, path: &Path) -> SuiResult { + pub fn checkpoint_db(&self, path: &Path) -> IotaResult { self.tables .committee_map .checkpoint_db(path) diff --git a/crates/sui-core/src/epoch/data_removal.rs b/crates/iota-core/src/epoch/data_removal.rs similarity index 98% rename from crates/sui-core/src/epoch/data_removal.rs rename to crates/iota-core/src/epoch/data_removal.rs index 88c18752450..c2ea58ca1eb 100644 --- a/crates/sui-core/src/epoch/data_removal.rs +++ b/crates/iota-core/src/epoch/data_removal.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[cfg(test)] diff --git a/crates/sui-core/src/epoch/epoch_metrics.rs b/crates/iota-core/src/epoch/epoch_metrics.rs similarity index 99% rename from crates/sui-core/src/epoch/epoch_metrics.rs rename to crates/iota-core/src/epoch/epoch_metrics.rs index 7ba5bee8176..4710f4cd7c0 100644 --- a/crates/sui-core/src/epoch/epoch_metrics.rs +++ b/crates/iota-core/src/epoch/epoch_metrics.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; diff --git a/crates/iota-core/src/epoch/mod.rs b/crates/iota-core/src/epoch/mod.rs new file mode 100644 index 00000000000..04cc0355c1f --- /dev/null +++ b/crates/iota-core/src/epoch/mod.rs @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod committee_store; +pub mod data_removal; +pub mod epoch_metrics; +pub mod randomness; +pub mod reconfiguration; diff --git a/crates/sui-core/src/epoch/randomness.rs b/crates/iota-core/src/epoch/randomness.rs similarity index 97% rename from crates/sui-core/src/epoch/randomness.rs rename to crates/iota-core/src/epoch/randomness.rs index 47bf1cc2061..fcc95f51267 100644 --- a/crates/sui-core/src/epoch/randomness.rs +++ b/crates/iota-core/src/epoch/randomness.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -17,19 +18,19 @@ use fastcrypto::{ }; use fastcrypto_tbls::{dkg, nodes, nodes::PartyId}; use futures::{stream::FuturesUnordered, StreamExt}; -use narwhal_types::Round; -use rand::{ - rngs::{OsRng, StdRng}, - SeedableRng, -}; -use sui_network::randomness; -use sui_types::{ +use iota_network::randomness; +use iota_types::{ base_types::AuthorityName, committee::{Committee, EpochId, StakeUnit}, crypto::{AuthorityKeyPair, RandomnessRound}, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, + iota_system_state::epoch_start_iota_system_state::EpochStartSystemStateTrait, messages_consensus::ConsensusTransaction, - sui_system_state::epoch_start_sui_system_state::EpochStartSystemStateTrait, +}; +use narwhal_types::Round; +use rand::{ + rngs::{OsRng, StdRng}, + SeedableRng, }; use tokio::{sync::OnceCell, task::JoinHandle}; use tracing::{debug, error, info, warn}; @@ -296,7 +297,7 @@ impl RandomnessManager { } /// Sends the initial dkg::Message to begin the randomness DKG protocol. - pub fn start_dkg(&mut self) -> SuiResult { + pub fn start_dkg(&mut self) -> IotaResult { if self.used_messages.initialized() || self.dkg_output.initialized() { // DKG already started (or completed or failed). return Ok(()); @@ -346,7 +347,7 @@ impl RandomnessManager { /// Processes all received messages and advances the randomness DKG state /// machine when possible, sending out a dkg::Confirmation and /// generating final output. - pub async fn advance_dkg(&mut self, batch: &mut DBBatch, round: Round) -> SuiResult { + pub async fn advance_dkg(&mut self, batch: &mut DBBatch, round: Round) -> IotaResult { let epoch_store = self.epoch_store()?; // Once we have enough Messages, send a Confirmation. @@ -484,7 +485,7 @@ impl RandomnessManager { &mut self, authority: &AuthorityName, msg: dkg::Message, - ) -> SuiResult { + ) -> IotaResult { if self.used_messages.initialized() || self.dkg_output.initialized() { // We've already sent a `Confirmation`, so we can't add any more messages. return Ok(()); @@ -530,7 +531,7 @@ impl RandomnessManager { batch: &mut DBBatch, authority: &AuthorityName, conf: dkg::Confirmation, - ) -> SuiResult { + ) -> IotaResult { if self.dkg_output.initialized() { // Once we have completed DKG, no more `Confirmation`s are needed. return Ok(()); @@ -559,7 +560,7 @@ impl RandomnessManager { /// the given batch is written, `generate_randomness` must be called to /// start the process. On restart, any reserved rounds for which the /// batch was written will automatically be resumed. - pub fn reserve_next_randomness(&mut self, batch: &mut DBBatch) -> SuiResult { + pub fn reserve_next_randomness(&mut self, batch: &mut DBBatch) -> IotaResult { let tables = self.tables()?; let randomness_round = self.next_randomness_round; @@ -606,11 +607,11 @@ impl RandomnessManager { } } - fn epoch_store(&self) -> SuiResult> { - self.epoch_store.upgrade().ok_or(SuiError::EpochEnded) + fn epoch_store(&self) -> IotaResult> { + self.epoch_store.upgrade().ok_or(IotaError::EpochEnded) } - fn tables(&self) -> SuiResult> { + fn tables(&self) -> IotaResult> { self.epoch_store()?.tables() } @@ -662,8 +663,8 @@ impl RandomnessReporter { /// Notifies the associated randomness manager that randomness for the given /// round has been durably committed in a checkpoint. This completes the /// process of generating randomness for the round. - pub fn notify_randomness_in_checkpoint(&self, round: RandomnessRound) -> SuiResult { - let epoch_store = self.epoch_store.upgrade().ok_or(SuiError::EpochEnded)?; + pub fn notify_randomness_in_checkpoint(&self, round: RandomnessRound) -> IotaResult { + let epoch_store = self.epoch_store.upgrade().ok_or(IotaError::EpochEnded)?; epoch_store .tables()? .randomness_rounds_pending @@ -678,7 +679,7 @@ impl RandomnessReporter { mod tests { use std::num::NonZeroUsize; - use sui_types::messages_consensus::ConsensusTransactionKind; + use iota_types::messages_consensus::ConsensusTransactionKind; use tokio::sync::mpsc; use crate::{ @@ -695,7 +696,7 @@ mod tests { telemetry_subscribers::init_for_testing(); let network_config = - sui_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir() + iota_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir() .committee_size(NonZeroUsize::new(4).unwrap()) .with_reference_gas_price(500) .build(); @@ -735,7 +736,7 @@ mod tests { let randomness_manager = RandomnessManager::try_new( Arc::downgrade(&epoch_store), consensus_adapter.clone(), - sui_network::randomness::Handle::new_stub(), + iota_network::randomness::Handle::new_stub(), validator.protocol_key_pair(), ) .await @@ -816,7 +817,7 @@ mod tests { telemetry_subscribers::init_for_testing(); let network_config = - sui_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir() + iota_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir() .committee_size(NonZeroUsize::new(4).unwrap()) .with_reference_gas_price(500) .build(); @@ -856,7 +857,7 @@ mod tests { let randomness_manager = RandomnessManager::try_new( Arc::downgrade(&epoch_store), consensus_adapter.clone(), - sui_network::randomness::Handle::new_stub(), + iota_network::randomness::Handle::new_stub(), validator.protocol_key_pair(), ) .await diff --git a/crates/sui-core/src/epoch/reconfiguration.rs b/crates/iota-core/src/epoch/reconfiguration.rs similarity index 97% rename from crates/sui-core/src/epoch/reconfiguration.rs rename to crates/iota-core/src/epoch/reconfiguration.rs index 956938d7a1e..7563feb2c08 100644 --- a/crates/sui-core/src/epoch/reconfiguration.rs +++ b/crates/iota-core/src/epoch/reconfiguration.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; diff --git a/crates/sui-core/src/execution_cache.rs b/crates/iota-core/src/execution_cache.rs similarity index 87% rename from crates/sui-core/src/execution_cache.rs rename to crates/iota-core/src/execution_cache.rs index 61dd4919648..b1df6ed1836 100644 --- a/crates/sui-core/src/execution_cache.rs +++ b/crates/iota-core/src/execution_cache.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashSet, path::Path, sync::Arc}; use async_trait::async_trait; use futures::{future::BoxFuture, FutureExt}; -use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; -use sui_protocol_config::ProtocolVersion; -use sui_types::{ +use iota_protocol_config::ProtocolVersion; +use iota_types::{ base_types::{EpochId, ObjectID, ObjectRef, SequenceNumber, VerifiedExecutionData}, digests::{TransactionDigest, TransactionEffectsDigest, TransactionEventsDigest}, effects::{TransactionEffects, TransactionEvents}, - error::{SuiError, SuiResult, UserInputError}, + error::{IotaError, IotaResult, UserInputError}, + iota_system_state::IotaSystemState, messages_checkpoint::CheckpointSequenceNumber, object::{Object, Owner}, storage::{ @@ -19,16 +20,16 @@ use sui_types::{ BackingPackageStore, ChildObjectResolver, InputKey, MarkerValue, ObjectKey, ObjectOrTombstone, ObjectStore, PackageObject, ParentSync, }, - sui_system_state::SuiSystemState, transaction::{VerifiedSignedTransaction, VerifiedTransaction}, }; +use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; use tracing::instrument; use crate::{ authority::{ authority_notify_read::EffectsNotifyRead, authority_per_epoch_store::AuthorityPerEpochStore, - authority_store::{ExecutionLockWriteGuard, SuiLockResult}, + authority_store::{ExecutionLockWriteGuard, IotaLockResult}, epoch_start_configuration::{EpochFlag, EpochStartConfiguration}, }, transaction_outputs::TransactionOutputs, @@ -69,16 +70,16 @@ pub trait ExecutionCacheCommit: Send + Sync { &self, epoch: EpochId, digest: &TransactionDigest, - ) -> BoxFuture<'_, SuiResult>; + ) -> BoxFuture<'_, IotaResult>; } pub trait ExecutionCacheRead: Send + Sync { - fn get_package_object(&self, id: &ObjectID) -> SuiResult>; + fn get_package_object(&self, id: &ObjectID) -> IotaResult>; fn force_reload_system_packages(&self, system_package_ids: &[ObjectID]); - fn get_object(&self, id: &ObjectID) -> SuiResult>; + fn get_object(&self, id: &ObjectID) -> IotaResult>; - fn get_objects(&self, objects: &[ObjectID]) -> SuiResult>> { + fn get_objects(&self, objects: &[ObjectID]) -> IotaResult>> { let mut ret = Vec::with_capacity(objects.len()); for object_id in objects { ret.push(self.get_object(object_id)?); @@ -89,29 +90,31 @@ pub trait ExecutionCacheRead: Send + Sync { fn get_latest_object_ref_or_tombstone( &self, object_id: ObjectID, - ) -> SuiResult>; + ) -> IotaResult>; fn get_latest_object_or_tombstone( &self, object_id: ObjectID, - ) -> SuiResult>; + ) -> IotaResult>; fn get_object_by_key( &self, object_id: &ObjectID, version: SequenceNumber, - ) -> SuiResult>; + ) -> IotaResult>; - fn multi_get_objects_by_key(&self, object_keys: &[ObjectKey]) - -> SuiResult>>; + fn multi_get_objects_by_key( + &self, + object_keys: &[ObjectKey], + ) -> IotaResult>>; fn object_exists_by_key( &self, object_id: &ObjectID, version: SequenceNumber, - ) -> SuiResult; + ) -> IotaResult; - fn multi_object_exists_by_key(&self, object_keys: &[ObjectKey]) -> SuiResult>; + fn multi_object_exists_by_key(&self, object_keys: &[ObjectKey]) -> IotaResult>; /// Load a list of objects from the store by object reference. /// If they exist in the store, they are returned directly. @@ -124,7 +127,7 @@ pub trait ExecutionCacheRead: Send + Sync { fn multi_get_objects_with_more_accurate_error_return( &self, object_refs: &[ObjectRef], - ) -> Result, SuiError> { + ) -> Result, IotaError> { let objects = self.multi_get_objects_by_key( &object_refs.iter().map(ObjectKey::from).collect::>(), )?; @@ -144,7 +147,7 @@ pub trait ExecutionCacheRead: Send + Sync { version: Some(object_ref.1), } }; - return Err(SuiError::UserInputError { error }); + return Err(IotaError::UserInputError { error }); } Some(object) => { result.push(object); @@ -165,7 +168,7 @@ pub trait ExecutionCacheRead: Send + Sync { keys: &[InputKey], receiving_objects: HashSet, epoch: EpochId, - ) -> Result, SuiError> { + ) -> Result, IotaError> { let (keys_with_version, keys_without_version): (Vec<_>, Vec<_>) = keys .iter() .enumerate() @@ -249,25 +252,25 @@ pub trait ExecutionCacheRead: Send + Sync { &self, object_id: ObjectID, version: SequenceNumber, - ) -> SuiResult>; + ) -> IotaResult>; - fn get_lock(&self, obj_ref: ObjectRef, epoch_store: &AuthorityPerEpochStore) -> SuiLockResult; + fn get_lock(&self, obj_ref: ObjectRef, epoch_store: &AuthorityPerEpochStore) -> IotaLockResult; // This method is considered "private" - only used by // multi_get_objects_with_more_accurate_error_return - fn _get_latest_lock_for_object_id(&self, object_id: ObjectID) -> SuiResult; + fn _get_latest_lock_for_object_id(&self, object_id: ObjectID) -> IotaResult; - fn check_owned_object_locks_exist(&self, owned_object_refs: &[ObjectRef]) -> SuiResult; + fn check_owned_object_locks_exist(&self, owned_object_refs: &[ObjectRef]) -> IotaResult; fn multi_get_transaction_blocks( &self, digests: &[TransactionDigest], - ) -> SuiResult>>>; + ) -> IotaResult>>>; fn get_transaction_block( &self, digest: &TransactionDigest, - ) -> SuiResult>> { + ) -> IotaResult>> { self.multi_get_transaction_blocks(&[*digest]) .map(|mut blocks| { blocks @@ -280,7 +283,7 @@ pub trait ExecutionCacheRead: Send + Sync { fn get_transactions_and_serialized_sizes( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { let txns = self.multi_get_transaction_blocks(digests)?; txns.into_iter() .map(|txn| { @@ -302,9 +305,9 @@ pub trait ExecutionCacheRead: Send + Sync { fn multi_get_executed_effects_digests( &self, digests: &[TransactionDigest], - ) -> SuiResult>>; + ) -> IotaResult>>; - fn is_tx_already_executed(&self, digest: &TransactionDigest) -> SuiResult { + fn is_tx_already_executed(&self, digest: &TransactionDigest) -> IotaResult { self.multi_get_executed_effects_digests(&[*digest]) .map(|mut digests| { digests @@ -317,7 +320,7 @@ pub trait ExecutionCacheRead: Send + Sync { fn multi_get_executed_effects( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { let effects_digests = self.multi_get_executed_effects_digests(digests)?; assert_eq!(effects_digests.len(), digests.len()); @@ -343,7 +346,7 @@ pub trait ExecutionCacheRead: Send + Sync { fn get_executed_effects( &self, digest: &TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { self.multi_get_executed_effects(&[*digest]) .map(|mut effects| { effects @@ -355,12 +358,12 @@ pub trait ExecutionCacheRead: Send + Sync { fn multi_get_effects( &self, digests: &[TransactionEffectsDigest], - ) -> SuiResult>>; + ) -> IotaResult>>; fn get_effects( &self, digest: &TransactionEffectsDigest, - ) -> SuiResult> { + ) -> IotaResult> { self.multi_get_effects(&[*digest]).map(|mut effects| { effects .pop() @@ -371,9 +374,12 @@ pub trait ExecutionCacheRead: Send + Sync { fn multi_get_events( &self, event_digests: &[TransactionEventsDigest], - ) -> SuiResult>>; + ) -> IotaResult>>; - fn get_events(&self, digest: &TransactionEventsDigest) -> SuiResult> { + fn get_events( + &self, + digest: &TransactionEventsDigest, + ) -> IotaResult> { self.multi_get_events(&[*digest]).map(|mut events| { events .pop() @@ -384,12 +390,12 @@ pub trait ExecutionCacheRead: Send + Sync { fn notify_read_executed_effects_digests<'a>( &'a self, digests: &'a [TransactionDigest], - ) -> BoxFuture<'a, SuiResult>>; + ) -> BoxFuture<'a, IotaResult>>; fn notify_read_executed_effects<'a>( &'a self, digests: &'a [TransactionDigest], - ) -> BoxFuture<'a, SuiResult>> { + ) -> BoxFuture<'a, IotaResult>> { async move { let digests = self.notify_read_executed_effects_digests(digests).await?; // once digests are available, effects must be present as well @@ -403,7 +409,7 @@ pub trait ExecutionCacheRead: Send + Sync { .boxed() } - fn get_sui_system_state_object_unsafe(&self) -> SuiResult; + fn get_iota_system_state_object_unsafe(&self) -> IotaResult; // Marker methods @@ -413,14 +419,14 @@ pub trait ExecutionCacheRead: Send + Sync { object_id: &ObjectID, version: SequenceNumber, epoch_id: EpochId, - ) -> SuiResult>; + ) -> IotaResult>; /// Get the latest marker for a given object. fn get_latest_marker( &self, object_id: &ObjectID, epoch_id: EpochId, - ) -> SuiResult>; + ) -> IotaResult>; /// If the shared object was deleted, return deletion info for the current /// live version @@ -428,7 +434,7 @@ pub trait ExecutionCacheRead: Send + Sync { &self, object_id: &ObjectID, epoch_id: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { match self.get_latest_marker(object_id, epoch_id)? { Some((version, MarkerValue::SharedDeleted(digest))) => Ok(Some((version, digest))), _ => Ok(None), @@ -442,7 +448,7 @@ pub trait ExecutionCacheRead: Send + Sync { object_id: &ObjectID, version: SequenceNumber, epoch_id: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { match self.get_marker_value(object_id, version, epoch_id)? { Some(MarkerValue::SharedDeleted(digest)) => Ok(Some(digest)), _ => Ok(None), @@ -454,7 +460,7 @@ pub trait ExecutionCacheRead: Send + Sync { object_id: &ObjectID, version: SequenceNumber, epoch_id: EpochId, - ) -> SuiResult { + ) -> IotaResult { match self.get_marker_value(object_id, version, epoch_id)? { Some(MarkerValue::Received) => Ok(true), _ => Ok(false), @@ -466,7 +472,7 @@ pub trait ExecutionCacheRead: Send + Sync { object_id: &ObjectID, version: SequenceNumber, epoch_id: EpochId, - ) -> SuiResult { + ) -> IotaResult { match self.get_latest_marker(object_id, epoch_id)? { Some((marker_version, MarkerValue::OwnedDeleted)) if marker_version >= version => { Ok(true) @@ -501,7 +507,7 @@ pub trait ExecutionCacheWrite: Send + Sync { &self, epoch_id: EpochId, tx_outputs: Arc, - ) -> BoxFuture<'_, SuiResult>; + ) -> BoxFuture<'_, IotaResult>; /// Attempt to acquire object locks for all of the owned input locks. fn acquire_transaction_locks<'a>( @@ -509,7 +515,7 @@ pub trait ExecutionCacheWrite: Send + Sync { epoch_store: &'a AuthorityPerEpochStore, owned_input_objects: &'a [ObjectRef], transaction: VerifiedSignedTransaction, - ) -> BoxFuture<'a, SuiResult>; + ) -> BoxFuture<'a, IotaResult>; } pub trait CheckpointCache: Send + Sync { @@ -520,41 +526,41 @@ pub trait CheckpointCache: Send + Sync { fn deprecated_get_transaction_checkpoint( &self, digest: &TransactionDigest, - ) -> SuiResult>; + ) -> IotaResult>; fn deprecated_multi_get_transaction_checkpoint( &self, digests: &[TransactionDigest], - ) -> SuiResult>>; + ) -> IotaResult>>; fn deprecated_insert_finalized_transactions( &self, digests: &[TransactionDigest], epoch: EpochId, sequence: CheckpointSequenceNumber, - ) -> SuiResult; + ) -> IotaResult; } pub trait ExecutionCacheReconfigAPI: Send + Sync { - fn insert_genesis_object(&self, object: Object) -> SuiResult; - fn bulk_insert_genesis_objects(&self, objects: &[Object]) -> SuiResult; + fn insert_genesis_object(&self, object: Object) -> IotaResult; + fn bulk_insert_genesis_objects(&self, objects: &[Object]) -> IotaResult; - fn revert_state_update(&self, digest: &TransactionDigest) -> SuiResult; + fn revert_state_update(&self, digest: &TransactionDigest) -> IotaResult; fn set_epoch_start_configuration( &self, epoch_start_config: &EpochStartConfiguration, - ) -> SuiResult; + ) -> IotaResult; fn update_epoch_flags_metrics(&self, old: &[EpochFlag], new: &[EpochFlag]); fn clear_state_end_of_epoch(&self, execution_guard: &ExecutionLockWriteGuard<'_>); - fn expensive_check_sui_conservation( + fn expensive_check_iota_conservation( &self, old_epoch_store: &AuthorityPerEpochStore, - ) -> SuiResult; + ) -> IotaResult; - fn checkpoint_db(&self, path: &Path) -> SuiResult; + fn checkpoint_db(&self, path: &Path) -> IotaResult; /// This is a temporary method to be used when we enable /// simplified_unwrap_then_delete. It re-accumulates state hash for the @@ -575,12 +581,12 @@ pub trait StateSyncAPI: Send + Sync { &self, transaction: &VerifiedTransaction, transaction_effects: &TransactionEffects, - ) -> SuiResult; + ) -> IotaResult; fn multi_insert_transaction_and_effects( &self, transactions_and_effects: &[VerifiedExecutionData], - ) -> SuiResult; + ) -> IotaResult; } // TODO: Remove EffectsNotifyRead trait and just use ExecutionCacheRead directly @@ -600,21 +606,21 @@ impl EffectsNotifyRead for NotifyReadWrapper async fn notify_read_executed_effects( &self, digests: Vec, - ) -> SuiResult> { + ) -> IotaResult> { self.0.notify_read_executed_effects(&digests).await } async fn notify_read_executed_effects_digests( &self, digests: Vec, - ) -> SuiResult> { + ) -> IotaResult> { self.0.notify_read_executed_effects_digests(&digests).await } fn multi_get_executed_effects( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { self.0.multi_get_executed_effects(digests) } } @@ -629,7 +635,7 @@ macro_rules! implement_storage_traits { fn get_object_by_key( &self, object_id: &ObjectID, - version: sui_types::base_types::VersionNumber, + version: iota_types::base_types::VersionNumber, ) -> StorageResult> { ExecutionCacheRead::get_object_by_key(self, object_id, version) .map_err(StorageError::custom) @@ -642,7 +648,7 @@ macro_rules! implement_storage_traits { parent: &ObjectID, child: &ObjectID, child_version_upper_bound: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { let Some(child_object) = self.find_object_lt_or_eq_version(*child, child_version_upper_bound)? else { @@ -651,7 +657,7 @@ macro_rules! implement_storage_traits { let parent = *parent; if child_object.owner != Owner::ObjectOwner(parent.into()) { - return Err(SuiError::InvalidChildObjectAccess { + return Err(IotaError::InvalidChildObjectAccess { object: *child, given_parent: parent, actual_owner: child_object.owner, @@ -666,7 +672,7 @@ macro_rules! implement_storage_traits { receiving_object_id: &ObjectID, receive_object_at_version: SequenceNumber, epoch_id: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { let Some(recv_object) = ExecutionCacheRead::get_object_by_key( self, receiving_object_id, @@ -701,7 +707,7 @@ macro_rules! implement_storage_traits { fn get_package_object( &self, package_id: &ObjectID, - ) -> SuiResult> { + ) -> IotaResult> { ExecutionCacheRead::get_package_object(self, package_id) } } @@ -710,7 +716,7 @@ macro_rules! implement_storage_traits { fn get_latest_parent_entry_ref_deprecated( &self, object_id: ObjectID, - ) -> SuiResult> { + ) -> IotaResult> { ExecutionCacheRead::get_latest_object_ref_or_tombstone(self, object_id) } } @@ -725,14 +731,14 @@ macro_rules! implement_passthrough_traits { fn deprecated_get_transaction_checkpoint( &self, digest: &TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { self.store.deprecated_get_transaction_checkpoint(digest) } fn deprecated_multi_get_transaction_checkpoint( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { self.store .deprecated_multi_get_transaction_checkpoint(digests) } @@ -742,29 +748,29 @@ macro_rules! implement_passthrough_traits { digests: &[TransactionDigest], epoch: EpochId, sequence: CheckpointSequenceNumber, - ) -> SuiResult { + ) -> IotaResult { self.store .deprecated_insert_finalized_transactions(digests, epoch, sequence) } } impl ExecutionCacheReconfigAPI for $implementor { - fn insert_genesis_object(&self, object: Object) -> SuiResult { + fn insert_genesis_object(&self, object: Object) -> IotaResult { self.store.insert_genesis_object(object) } - fn bulk_insert_genesis_objects(&self, objects: &[Object]) -> SuiResult { + fn bulk_insert_genesis_objects(&self, objects: &[Object]) -> IotaResult { self.store.bulk_insert_genesis_objects(objects) } - fn revert_state_update(&self, digest: &TransactionDigest) -> SuiResult { + fn revert_state_update(&self, digest: &TransactionDigest) -> IotaResult { self.revert_state_update_impl(digest) } fn set_epoch_start_configuration( &self, epoch_start_config: &EpochStartConfiguration, - ) -> SuiResult { + ) -> IotaResult { self.store.set_epoch_start_configuration(epoch_start_config) } @@ -776,15 +782,15 @@ macro_rules! implement_passthrough_traits { self.clear_state_end_of_epoch_impl(execution_guard) } - fn expensive_check_sui_conservation( + fn expensive_check_iota_conservation( &self, old_epoch_store: &AuthorityPerEpochStore, - ) -> SuiResult { + ) -> IotaResult { self.store - .expensive_check_sui_conservation(self, old_epoch_store) + .expensive_check_iota_conservation(self, old_epoch_store) } - fn checkpoint_db(&self, path: &std::path::Path) -> SuiResult { + fn checkpoint_db(&self, path: &std::path::Path) -> IotaResult { self.store.perpetual_tables.checkpoint_db(path) } @@ -803,7 +809,7 @@ macro_rules! implement_passthrough_traits { &self, transaction: &VerifiedTransaction, transaction_effects: &TransactionEffects, - ) -> SuiResult { + ) -> IotaResult { Ok(self .store .insert_transaction_and_effects(transaction, transaction_effects)?) @@ -812,7 +818,7 @@ macro_rules! implement_passthrough_traits { fn multi_insert_transaction_and_effects( &self, transactions_and_effects: &[VerifiedExecutionData], - ) -> SuiResult { + ) -> IotaResult { Ok(self .store .multi_insert_transaction_and_effects(transactions_and_effects.iter())?) diff --git a/crates/sui-core/src/execution_cache/cached_version_map.rs b/crates/iota-core/src/execution_cache/cached_version_map.rs similarity index 98% rename from crates/sui-core/src/execution_cache/cached_version_map.rs rename to crates/iota-core/src/execution_cache/cached_version_map.rs index 9a816aaa8e4..c5c524b9586 100644 --- a/crates/sui-core/src/execution_cache/cached_version_map.rs +++ b/crates/iota-core/src/execution_cache/cached_version_map.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{cmp::Ordering, collections::VecDeque}; -use sui_types::base_types::SequenceNumber; +use iota_types::base_types::SequenceNumber; /// CachedVersionMap is a map from version to value, with the additional /// contraints: @@ -103,7 +104,7 @@ impl CachedVersionMap { #[cfg(test)] mod tests { - use sui_types::base_types::SequenceNumber; + use iota_types::base_types::SequenceNumber; use super::*; diff --git a/crates/sui-core/src/execution_cache/passthrough_cache.rs b/crates/iota-core/src/execution_cache/passthrough_cache.rs similarity index 84% rename from crates/sui-core/src/execution_cache/passthrough_cache.rs rename to crates/iota-core/src/execution_cache/passthrough_cache.rs index 8fa4bcabde7..a3a362f3fac 100644 --- a/crates/sui-core/src/execution_cache/passthrough_cache.rs +++ b/crates/iota-core/src/execution_cache/passthrough_cache.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; @@ -8,24 +9,24 @@ use futures::{ future::{join_all, BoxFuture}, FutureExt, }; -use mysten_common::sync::notify_read::NotifyRead; -use prometheus::Registry; -use sui_config::node::AuthorityStorePruningConfig; -use sui_protocol_config::ProtocolVersion; -use sui_storage::package_object_cache::PackageObjectCache; -use sui_types::{ +use iota_config::node::AuthorityStorePruningConfig; +use iota_protocol_config::ProtocolVersion; +use iota_storage::package_object_cache::PackageObjectCache; +use iota_types::{ accumulator::Accumulator, base_types::{EpochId, ObjectID, ObjectRef, SequenceNumber, VerifiedExecutionData}, digests::{TransactionDigest, TransactionEffectsDigest, TransactionEventsDigest}, effects::{TransactionEffects, TransactionEvents}, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, + iota_system_state::{get_iota_system_state, IotaSystemState}, message_envelope::Message, messages_checkpoint::CheckpointSequenceNumber, object::Object, storage::{MarkerValue, ObjectKey, ObjectOrTombstone, ObjectStore, PackageObject}, - sui_system_state::{get_sui_system_state, SuiSystemState}, transaction::{VerifiedSignedTransaction, VerifiedTransaction}, }; +use mysten_common::sync::notify_read::NotifyRead; +use prometheus::Registry; use tap::TapFallible; use tracing::instrument; use typed_store::Map; @@ -38,7 +39,7 @@ use super::{ use crate::{ authority::{ authority_per_epoch_store::AuthorityPerEpochStore, - authority_store::{ExecutionLockWriteGuard, SuiLockResult}, + authority_store::{ExecutionLockWriteGuard, IotaLockResult}, authority_store_pruner::{ AuthorityStorePruner, AuthorityStorePruningMetrics, EPOCH_DURATION_MS_FOR_TESTING, }, @@ -101,7 +102,7 @@ impl PassthroughCache { let _ = AuthorityStorePruner::compact(&self.store.perpetual_tables); } - fn revert_state_update_impl(&self, digest: &TransactionDigest) -> SuiResult { + fn revert_state_update_impl(&self, digest: &TransactionDigest) -> IotaResult { self.store.revert_state_update(digest) } @@ -116,7 +117,7 @@ impl PassthroughCache { } impl ExecutionCacheRead for PassthroughCache { - fn get_package_object(&self, package_id: &ObjectID) -> SuiResult> { + fn get_package_object(&self, package_id: &ObjectID) -> IotaResult> { self.package_cache .get_package_object(package_id, &*self.store) } @@ -126,7 +127,7 @@ impl ExecutionCacheRead for PassthroughCache { .force_reload_system_packages(system_package_ids.iter().cloned(), self); } - fn get_object(&self, id: &ObjectID) -> SuiResult> { + fn get_object(&self, id: &ObjectID) -> IotaResult> { self.store.get_object(id).map_err(Into::into) } @@ -134,14 +135,14 @@ impl ExecutionCacheRead for PassthroughCache { &self, object_id: &ObjectID, version: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self.store.get_object_by_key(object_id, version)?) } fn multi_get_objects_by_key( &self, object_keys: &[ObjectKey], - ) -> Result>, SuiError> { + ) -> Result>, IotaError> { Ok(self.store.multi_get_objects_by_key(object_keys)?) } @@ -149,25 +150,25 @@ impl ExecutionCacheRead for PassthroughCache { &self, object_id: &ObjectID, version: SequenceNumber, - ) -> SuiResult { + ) -> IotaResult { self.store.object_exists_by_key(object_id, version) } - fn multi_object_exists_by_key(&self, object_keys: &[ObjectKey]) -> SuiResult> { + fn multi_object_exists_by_key(&self, object_keys: &[ObjectKey]) -> IotaResult> { self.store.multi_object_exists_by_key(object_keys) } fn get_latest_object_ref_or_tombstone( &self, object_id: ObjectID, - ) -> SuiResult> { + ) -> IotaResult> { self.store.get_latest_object_ref_or_tombstone(object_id) } fn get_latest_object_or_tombstone( &self, object_id: ObjectID, - ) -> Result, SuiError> { + ) -> Result, IotaError> { self.store.get_latest_object_or_tombstone(object_id) } @@ -175,26 +176,26 @@ impl ExecutionCacheRead for PassthroughCache { &self, object_id: ObjectID, version: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { self.store.find_object_lt_or_eq_version(object_id, version) } - fn get_lock(&self, obj_ref: ObjectRef, epoch_store: &AuthorityPerEpochStore) -> SuiLockResult { + fn get_lock(&self, obj_ref: ObjectRef, epoch_store: &AuthorityPerEpochStore) -> IotaLockResult { self.store.get_lock(obj_ref, epoch_store) } - fn _get_latest_lock_for_object_id(&self, object_id: ObjectID) -> SuiResult { + fn _get_latest_lock_for_object_id(&self, object_id: ObjectID) -> IotaResult { self.store.get_latest_live_version_for_object_id(object_id) } - fn check_owned_object_locks_exist(&self, owned_object_refs: &[ObjectRef]) -> SuiResult { + fn check_owned_object_locks_exist(&self, owned_object_refs: &[ObjectRef]) -> IotaResult { self.store.check_owned_object_locks_exist(owned_object_refs) } fn multi_get_transaction_blocks( &self, digests: &[TransactionDigest], - ) -> SuiResult>>> { + ) -> IotaResult>>> { Ok(self .store .multi_get_transaction_blocks(digests)? @@ -206,21 +207,21 @@ impl ExecutionCacheRead for PassthroughCache { fn multi_get_executed_effects_digests( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { self.store.multi_get_executed_effects_digests(digests) } fn multi_get_effects( &self, digests: &[TransactionEffectsDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { Ok(self.store.perpetual_tables.effects.multi_get(digests)?) } fn notify_read_executed_effects_digests<'a>( &'a self, digests: &'a [TransactionDigest], - ) -> BoxFuture<'a, SuiResult>> { + ) -> BoxFuture<'a, IotaResult>> { async move { let registrations = self .executed_effects_digests_notify_read @@ -245,12 +246,12 @@ impl ExecutionCacheRead for PassthroughCache { fn multi_get_events( &self, event_digests: &[TransactionEventsDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { self.store.multi_get_events(event_digests) } - fn get_sui_system_state_object_unsafe(&self) -> SuiResult { - get_sui_system_state(self) + fn get_iota_system_state_object_unsafe(&self) -> IotaResult { + get_iota_system_state(self) } fn get_marker_value( @@ -258,7 +259,7 @@ impl ExecutionCacheRead for PassthroughCache { object_id: &ObjectID, version: SequenceNumber, epoch_id: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { self.store.get_marker_value(object_id, &version, epoch_id) } @@ -266,7 +267,7 @@ impl ExecutionCacheRead for PassthroughCache { &self, object_id: &ObjectID, epoch_id: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { self.store.get_latest_marker(object_id, epoch_id) } } @@ -277,7 +278,7 @@ impl ExecutionCacheWrite for PassthroughCache { &'a self, epoch_id: EpochId, tx_outputs: Arc, - ) -> BoxFuture<'a, SuiResult> { + ) -> BoxFuture<'a, IotaResult> { async move { let tx_digest = *tx_outputs.transaction.digest(); let effects_digest = tx_outputs.effects.digest(); @@ -302,7 +303,7 @@ impl ExecutionCacheWrite for PassthroughCache { epoch_store: &'a AuthorityPerEpochStore, owned_input_objects: &'a [ObjectRef], transaction: VerifiedSignedTransaction, - ) -> BoxFuture<'a, SuiResult> { + ) -> BoxFuture<'a, IotaResult> { self.store .acquire_transaction_locks(epoch_store, owned_input_objects, transaction) .boxed() @@ -313,8 +314,8 @@ impl AccumulatorStore for PassthroughCache { fn get_object_ref_prior_to_key_deprecated( &self, object_id: &ObjectID, - version: sui_types::base_types::VersionNumber, - ) -> SuiResult> { + version: iota_types::base_types::VersionNumber, + ) -> IotaResult> { self.store .get_object_ref_prior_to_key_deprecated(object_id, version) } @@ -322,13 +323,13 @@ impl AccumulatorStore for PassthroughCache { fn get_root_state_accumulator_for_epoch( &self, epoch: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { self.store.get_root_state_accumulator_for_epoch(epoch) } fn get_root_state_accumulator_for_highest_epoch( &self, - ) -> SuiResult> { + ) -> IotaResult> { self.store.get_root_state_accumulator_for_highest_epoch() } @@ -337,7 +338,7 @@ impl AccumulatorStore for PassthroughCache { epoch: EpochId, checkpoint_seq_num: &CheckpointSequenceNumber, acc: &Accumulator, - ) -> SuiResult { + ) -> IotaResult { self.store .insert_state_accumulator_for_epoch(epoch, checkpoint_seq_num, acc) } @@ -355,7 +356,7 @@ impl ExecutionCacheCommit for PassthroughCache { &self, _epoch: EpochId, _digest: &TransactionDigest, - ) -> BoxFuture<'_, SuiResult> { + ) -> BoxFuture<'_, IotaResult> { // Nothing needs to be done since they were already committed in // write_transaction_outputs async { Ok(()) }.boxed() diff --git a/crates/sui-core/src/execution_cache/unit_tests/writeback_cache_tests.rs b/crates/iota-core/src/execution_cache/unit_tests/writeback_cache_tests.rs similarity index 97% rename from crates/sui-core/src/execution_cache/unit_tests/writeback_cache_tests.rs rename to crates/iota-core/src/execution_cache/unit_tests/writeback_cache_tests.rs index 39885191b80..fca5f6fa36b 100644 --- a/crates/sui-core/src/execution_cache/unit_tests/writeback_cache_tests.rs +++ b/crates/iota-core/src/execution_cache/unit_tests/writeback_cache_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -11,18 +12,18 @@ use std::{ }, }; -use prometheus::default_registry; -use rand::{rngs::StdRng, SeedableRng}; -use sui_framework::BuiltInFramework; -use sui_macros::{register_fail_point_async, sim_test}; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ - base_types::{random_object_ref, SuiAddress}, +use iota_framework::BuiltInFramework; +use iota_macros::{register_fail_point_async, sim_test}; +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ + base_types::{random_object_ref, IotaAddress}, crypto::{deterministic_random_account_key, get_key_pair_from_rng, AccountKeyPair}, effects::TestEffectsBuilder, object::{MoveObject, Owner, OBJECT_START_VERSION}, storage::ChildObjectResolver, }; +use prometheus::default_registry; +use rand::{rngs::StdRng, SeedableRng}; use tempfile::tempdir; use super::*; @@ -155,8 +156,8 @@ impl Scenario { fn new_outputs() -> TransactionOutputs { let mut rng = StdRng::from_seed([0; 32]); - let (sender, keypair): (SuiAddress, AccountKeyPair) = get_key_pair_from_rng(&mut rng); - let (receiver, _): (SuiAddress, AccountKeyPair) = get_key_pair_from_rng(&mut rng); + let (sender, keypair): (IotaAddress, AccountKeyPair) = get_key_pair_from_rng(&mut rng); + let (receiver, _): (IotaAddress, AccountKeyPair) = get_key_pair_from_rng(&mut rng); // Tx is opaque to the cache, so we just build a dummy tx. The only requirement // is that it has a unique digest every time. @@ -191,7 +192,7 @@ impl Scenario { } fn new_package() -> Object { - use sui_move_build::BuildConfig; + use iota_move_build::BuildConfig; // add object_basics package object to genesis, since lots of test use it let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); @@ -354,7 +355,7 @@ impl Scenario { } // commit a transaction to the database - async fn commit(&mut self, tx: TransactionDigest) -> SuiResult { + async fn commit(&mut self, tx: TransactionDigest) -> IotaResult { let res = self.cache().commit_transaction_outputs(1, &tx).await; self.count_action(); res diff --git a/crates/sui-core/src/execution_cache/writeback_cache.rs b/crates/iota-core/src/execution_cache/writeback_cache.rs similarity index 95% rename from crates/sui-core/src/execution_cache/writeback_cache.rs rename to crates/iota-core/src/execution_cache/writeback_cache.rs index 99c9357483b..97b0ff2af7b 100644 --- a/crates/sui-core/src/execution_cache/writeback_cache.rs +++ b/crates/iota-core/src/execution_cache/writeback_cache.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! MemoryCache is a cache for the transaction execution which delays writes to @@ -54,26 +55,26 @@ use futures::{ future::{join_all, BoxFuture}, FutureExt, }; -use moka::sync::Cache as MokaCache; -use mysten_common::sync::notify_read::NotifyRead; -use parking_lot::Mutex; -use prometheus::Registry; -use sui_config::node::AuthorityStorePruningConfig; -use sui_macros::fail_point_async; -use sui_protocol_config::ProtocolVersion; -use sui_types::{ +use iota_config::node::AuthorityStorePruningConfig; +use iota_macros::fail_point_async; +use iota_protocol_config::ProtocolVersion; +use iota_types::{ accumulator::Accumulator, base_types::{EpochId, ObjectID, ObjectRef, SequenceNumber, VerifiedExecutionData}, digests::{ObjectDigest, TransactionDigest, TransactionEffectsDigest, TransactionEventsDigest}, effects::{TransactionEffects, TransactionEvents}, - error::{SuiError, SuiResult, UserInputError}, + error::{IotaError, IotaResult, UserInputError}, + iota_system_state::{get_iota_system_state, IotaSystemState}, message_envelope::Message, messages_checkpoint::CheckpointSequenceNumber, object::Object, storage::{MarkerValue, ObjectKey, ObjectOrTombstone, ObjectStore, PackageObject}, - sui_system_state::{get_sui_system_state, SuiSystemState}, transaction::{VerifiedSignedTransaction, VerifiedTransaction}, }; +use moka::sync::Cache as MokaCache; +use mysten_common::sync::notify_read::NotifyRead; +use parking_lot::Mutex; +use prometheus::Registry; use tracing::{info, instrument}; use super::{ @@ -84,7 +85,7 @@ use super::{ use crate::{ authority::{ authority_per_epoch_store::AuthorityPerEpochStore, - authority_store::{ExecutionLockWriteGuard, SuiLockResult}, + authority_store::{ExecutionLockWriteGuard, IotaLockResult}, authority_store_pruner::{ AuthorityStorePruner, AuthorityStorePruningMetrics, EPOCH_DURATION_MS_FOR_TESTING, }, @@ -494,7 +495,7 @@ impl WritebackCache { &self, epoch: EpochId, digest: TransactionDigest, - ) -> SuiResult { + ) -> IotaResult { let Some((_, outputs)) = self.dirty.pending_transaction_writes.remove(&digest) else { panic!("Attempt to commit unknown transaction {:?}", digest); }; @@ -666,7 +667,7 @@ impl WritebackCache { self.dirty.clear(); } - fn revert_state_update_impl(&self, tx: &TransactionDigest) -> SuiResult { + fn revert_state_update_impl(&self, tx: &TransactionDigest) -> IotaResult { // TODO: remove revert_state_update_impl entirely, and simply drop all dirty // state when clear_state_end_of_epoch_impl is called. let (_, outputs) = self @@ -701,13 +702,13 @@ impl ExecutionCacheCommit for WritebackCache { &self, epoch: EpochId, digest: &TransactionDigest, - ) -> BoxFuture<'_, SuiResult> { + ) -> BoxFuture<'_, IotaResult> { WritebackCache::commit_transaction_outputs(self, epoch, *digest).boxed() } } impl ExecutionCacheRead for WritebackCache { - fn get_package_object(&self, package_id: &ObjectID) -> SuiResult> { + fn get_package_object(&self, package_id: &ObjectID) -> IotaResult> { if let Some(p) = self.packages.get(package_id) { if cfg!(debug_assertions) { if let Some(store_package) = self.store.get_object(package_id).unwrap() { @@ -731,7 +732,7 @@ impl ExecutionCacheRead for WritebackCache { self.packages.insert(*package_id, p.clone()); Ok(Some(p)) } else { - Err(SuiError::UserInputError { + Err(IotaError::UserInputError { error: UserInputError::MoveObjectAsPackage { object_id: *package_id, }, @@ -766,7 +767,7 @@ impl ExecutionCacheRead for WritebackCache { // objects and immutable objects) If we do this, we must be VERY CAREFUL not // to break the contiguous version property of the cache. - fn get_object(&self, id: &ObjectID) -> SuiResult> { + fn get_object(&self, id: &ObjectID) -> IotaResult> { match self.get_object_by_id_cache_only(id) { CacheResult::Hit((_, object)) => Ok(Some(object)), CacheResult::NegativeHit => Ok(None), @@ -778,7 +779,7 @@ impl ExecutionCacheRead for WritebackCache { &self, object_id: &ObjectID, version: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { match self.get_object_by_key_cache_only(object_id, version) { CacheResult::Hit(object) => Ok(Some(object)), CacheResult::NegativeHit => Ok(None), @@ -789,7 +790,7 @@ impl ExecutionCacheRead for WritebackCache { fn multi_get_objects_by_key( &self, object_keys: &[ObjectKey], - ) -> Result>, SuiError> { + ) -> Result>, IotaError> { do_fallback_lookup( object_keys, |key| { @@ -811,7 +812,7 @@ impl ExecutionCacheRead for WritebackCache { &self, object_id: &ObjectID, version: SequenceNumber, - ) -> SuiResult { + ) -> IotaResult { match self.get_object_by_key_cache_only(object_id, version) { CacheResult::Hit(_) => Ok(true), CacheResult::NegativeHit => Ok(false), @@ -819,7 +820,7 @@ impl ExecutionCacheRead for WritebackCache { } } - fn multi_object_exists_by_key(&self, object_keys: &[ObjectKey]) -> SuiResult> { + fn multi_object_exists_by_key(&self, object_keys: &[ObjectKey]) -> IotaResult> { do_fallback_lookup( object_keys, |key| { @@ -836,7 +837,7 @@ impl ExecutionCacheRead for WritebackCache { fn get_latest_object_ref_or_tombstone( &self, object_id: ObjectID, - ) -> SuiResult> { + ) -> IotaResult> { match self.get_object_entry_by_id_cache_only(&object_id) { CacheResult::Hit((version, entry)) => Ok(Some(match entry { ObjectEntry::Object(object) => object.compute_object_reference(), @@ -853,7 +854,7 @@ impl ExecutionCacheRead for WritebackCache { fn get_latest_object_or_tombstone( &self, object_id: ObjectID, - ) -> Result, SuiError> { + ) -> Result, IotaError> { match self.get_object_entry_by_id_cache_only(&object_id) { CacheResult::Hit((version, entry)) => { let key = ObjectKey(object_id, version); @@ -888,7 +889,7 @@ impl ExecutionCacheRead for WritebackCache { &self, object_id: ObjectID, version: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { macro_rules! check_cache_entry { ($objects: expr) => { if let Some(objects) = $objects { @@ -921,7 +922,7 @@ impl ExecutionCacheRead for WritebackCache { fn multi_get_transaction_blocks( &self, digests: &[TransactionDigest], - ) -> SuiResult>>> { + ) -> IotaResult>>> { do_fallback_lookup( digests, |digest| { @@ -944,7 +945,7 @@ impl ExecutionCacheRead for WritebackCache { fn multi_get_executed_effects_digests( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { do_fallback_lookup( digests, |digest| { @@ -963,7 +964,7 @@ impl ExecutionCacheRead for WritebackCache { fn multi_get_effects( &self, digests: &[TransactionEffectsDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { do_fallback_lookup( digests, |digest| { @@ -982,7 +983,7 @@ impl ExecutionCacheRead for WritebackCache { fn notify_read_executed_effects_digests<'a>( &'a self, digests: &'a [TransactionDigest], - ) -> BoxFuture<'a, SuiResult>> { + ) -> BoxFuture<'a, IotaResult>> { async move { let registrations = self .executed_effects_digests_notify_read @@ -1007,7 +1008,7 @@ impl ExecutionCacheRead for WritebackCache { fn multi_get_events( &self, event_digests: &[TransactionEventsDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { do_fallback_lookup( event_digests, |digest| { @@ -1023,8 +1024,8 @@ impl ExecutionCacheRead for WritebackCache { ) } - fn get_sui_system_state_object_unsafe(&self) -> SuiResult { - get_sui_system_state(self) + fn get_iota_system_state_object_unsafe(&self) -> IotaResult { + get_iota_system_state(self) } fn get_marker_value( @@ -1032,7 +1033,7 @@ impl ExecutionCacheRead for WritebackCache { object_id: &ObjectID, version: SequenceNumber, epoch_id: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { match self.get_marker_value_cache_only(object_id, version, epoch_id) { CacheResult::Hit(marker) => Ok(Some(marker)), CacheResult::NegativeHit => Ok(None), @@ -1044,7 +1045,7 @@ impl ExecutionCacheRead for WritebackCache { &self, object_id: &ObjectID, epoch_id: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { match self.get_latest_marker_value_cache_only(object_id, epoch_id) { CacheResult::Hit((v, marker)) => Ok(Some((v, marker))), CacheResult::NegativeHit => { @@ -1058,15 +1059,15 @@ impl ExecutionCacheRead for WritebackCache { &self, _obj_ref: ObjectRef, _epoch_store: &AuthorityPerEpochStore, - ) -> SuiLockResult { + ) -> IotaLockResult { todo!() } - fn _get_latest_lock_for_object_id(&self, _object_id: ObjectID) -> SuiResult { + fn _get_latest_lock_for_object_id(&self, _object_id: ObjectID) -> IotaResult { todo!() } - fn check_owned_object_locks_exist(&self, _owned_object_refs: &[ObjectRef]) -> SuiResult { + fn check_owned_object_locks_exist(&self, _owned_object_refs: &[ObjectRef]) -> IotaResult { todo!() } } @@ -1078,7 +1079,7 @@ impl ExecutionCacheWrite for WritebackCache { _epoch_store: &AuthorityPerEpochStore, _owned_input_objects: &'a [ObjectRef], _tx_digest: VerifiedSignedTransaction, - ) -> BoxFuture<'a, SuiResult> { + ) -> BoxFuture<'a, IotaResult> { todo!() } @@ -1087,7 +1088,7 @@ impl ExecutionCacheWrite for WritebackCache { &self, epoch_id: EpochId, tx_outputs: Arc, - ) -> BoxFuture<'_, SuiResult> { + ) -> BoxFuture<'_, IotaResult> { async move { let TransactionOutputs { transaction, @@ -1189,9 +1190,9 @@ impl ExecutionCacheWrite for WritebackCache { /// caller and provided via the get_cached_key and multiget_fallback functions. fn do_fallback_lookup( keys: &[K], - get_cached_key: impl Fn(&K) -> SuiResult>, - multiget_fallback: impl Fn(&[K]) -> SuiResult>, -) -> SuiResult> { + get_cached_key: impl Fn(&K) -> IotaResult>, + multiget_fallback: impl Fn(&[K]) -> IotaResult>, +) -> IotaResult> { let mut results = vec![V::default(); keys.len()]; let mut fallback_keys = Vec::with_capacity(keys.len()); let mut fallback_indices = Vec::with_capacity(keys.len()); @@ -1229,7 +1230,7 @@ impl AccumulatorStore for WritebackCache { &self, object_id: &ObjectID, version: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { // There is probably a more efficient way to implement this, but since this is // only used by old protocol versions, it is better to do the simple // thing that is obviously correct. In this case we previous version @@ -1281,13 +1282,13 @@ impl AccumulatorStore for WritebackCache { fn get_root_state_accumulator_for_epoch( &self, epoch: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { self.store.get_root_state_accumulator_for_epoch(epoch) } fn get_root_state_accumulator_for_highest_epoch( &self, - ) -> SuiResult> { + ) -> IotaResult> { self.store.get_root_state_accumulator_for_highest_epoch() } @@ -1296,7 +1297,7 @@ impl AccumulatorStore for WritebackCache { epoch: EpochId, checkpoint_seq_num: &CheckpointSequenceNumber, acc: &Accumulator, - ) -> SuiResult { + ) -> IotaResult { self.store .insert_state_accumulator_for_epoch(epoch, checkpoint_seq_num, acc) } diff --git a/crates/sui-core/src/execution_driver.rs b/crates/iota-core/src/execution_driver.rs similarity index 98% rename from crates/sui-core/src/execution_driver.rs rename to crates/iota-core/src/execution_driver.rs index 4498e4aecaf..afc2bc90ccb 100644 --- a/crates/sui-core/src/execution_driver.rs +++ b/crates/iota-core/src/execution_driver.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -6,12 +7,12 @@ use std::{ time::Duration, }; +use iota_macros::fail_point_async; use mysten_metrics::{monitored_scope, spawn_monitored_task}; use rand::{ rngs::{OsRng, StdRng}, Rng, SeedableRng, }; -use sui_macros::fail_point_async; use tokio::{ sync::{mpsc::UnboundedReceiver, oneshot, Semaphore}, time::sleep, diff --git a/crates/sui-core/src/generate_format.rs b/crates/iota-core/src/generate_format.rs similarity index 90% rename from crates/sui-core/src/generate_format.rs rename to crates/iota-core/src/generate_format.rs index 86c982423e5..8b3e9dceb0e 100644 --- a/crates/sui-core/src/generate_format.rs +++ b/crates/iota-core/src/generate_format.rs @@ -1,24 +1,20 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fs::File, io::Write, str::FromStr}; use clap::*; use fastcrypto_zkp::{bn254::zk_login::OIDCProvider, zk_login_utils::Bn254FrElement}; -use move_core_types::language_storage::{StructTag, TypeTag}; -use pretty_assertions::assert_str_eq; -use rand::{rngs::StdRng, SeedableRng}; -use serde_reflection::{Registry, Result, Samples, Tracer, TracerConfig}; -use shared_crypto::intent::{Intent, IntentMessage, PersonalMessage}; -use sui_types::{ +use iota_types::{ base_types::{ self, MoveObjectType, MoveObjectType_, ObjectDigest, ObjectID, TransactionDigest, TransactionEffectsDigest, }, crypto::{ get_key_pair, get_key_pair_from_rng, AccountKeyPair, AuthorityKeyPair, - AuthorityPublicKeyBytes, AuthoritySignature, KeypairTraits, PublicKey, Signature, Signer, - SuiKeyPair, ZkLoginPublicIdentifier, + AuthorityPublicKeyBytes, AuthoritySignature, IotaKeyPair, KeypairTraits, PublicKey, + Signature, Signer, ZkLoginPublicIdentifier, }, effects::{IDOperation, ObjectIn, ObjectOut, TransactionEffects, UnchangedSharedKind}, execution_status::{ @@ -40,6 +36,11 @@ use sui_types::{ }, utils::DEFAULT_ADDRESS_SEED, }; +use move_core_types::language_storage::{StructTag, TypeTag}; +use pretty_assertions::assert_str_eq; +use rand::{rngs::StdRng, SeedableRng}; +use serde_reflection::{Registry, Result, Samples, Tracer, TracerConfig}; +use shared_crypto::intent::{Intent, IntentMessage, PersonalMessage}; use typed_store::TypedStoreError; fn get_registry() -> Result { let config = TracerConfig::default() @@ -71,12 +72,12 @@ fn get_registry() -> Result { let sig: Signature = Signer::sign(&s_kp, b"hello world"); tracer.trace_value(&mut samples, &sig)?; - let kp1: SuiKeyPair = - SuiKeyPair::Ed25519(get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1); - let kp2: SuiKeyPair = - SuiKeyPair::Secp256k1(get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1); - let kp3: SuiKeyPair = - SuiKeyPair::Secp256r1(get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1); + let kp1: IotaKeyPair = + IotaKeyPair::Ed25519(get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1); + let kp2: IotaKeyPair = + IotaKeyPair::Secp256k1(get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1); + let kp3: IotaKeyPair = + IotaKeyPair::Secp256r1(get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1); let pk_zklogin = PublicKey::ZkLogin( ZkLoginPublicIdentifier::new( &OIDCProvider::Twitch.get_config().iss, @@ -93,7 +94,7 @@ fn get_registry() -> Result { .unwrap(); let msg = IntentMessage::new( - Intent::sui_transaction(), + Intent::iota_transaction(), PersonalMessage { message: "Message".as_bytes().to_vec(), }, @@ -118,7 +119,7 @@ fn get_registry() -> Result { tracer.trace_value(&mut samples, &sig2)?; tracer.trace_value(&mut samples, &sig3)?; tracer.trace_value(&mut samples, &sig4)?; - // ObjectID and SuiAddress are the same length + // ObjectID and IotaAddress are the same length let oid: ObjectID = addr.into(); tracer.trace_value(&mut samples, &oid)?; @@ -135,7 +136,7 @@ fn get_registry() -> Result { let ccd = CheckpointContentsDigest::random(); tracer.trace_value(&mut samples, &ccd)?; - let struct_tag = StructTag::from_str("0x2::coin::Coin<0x2::sui::SUI>").unwrap(); + let struct_tag = StructTag::from_str("0x2::coin::Coin<0x2::iota::IOTA>").unwrap(); tracer.trace_value(&mut samples, &struct_tag)?; let ccd = CheckpointDigest::random(); @@ -154,7 +155,7 @@ fn get_registry() -> Result { tracer.trace_type::(&samples)?; tracer.trace_type::(&samples)?; tracer.trace_type::(&samples)?; - tracer.trace_type::(&samples)?; + tracer.trace_type::(&samples)?; tracer.trace_type::(&samples)?; tracer.trace_type::(&samples)?; tracer.trace_type::(&samples)?; @@ -187,15 +188,15 @@ enum Action { #[derive(Debug, Parser)] #[clap( - name = "Sui format generator", - about = "Trace serde (de)serialization to generate format descriptions for Sui types" + name = "Iota format generator", + about = "Trace serde (de)serialization to generate format descriptions for Iota types" )] struct Options { #[clap(value_enum, default_value = "Print", ignore_case = true)] action: Action, } -const FILE_PATH: &str = "sui-core/tests/staged/sui.yaml"; +const FILE_PATH: &str = "iota-core/tests/staged/iota.yaml"; fn main() { let options = Options::parse(); diff --git a/crates/iota-core/src/lib.rs b/crates/iota-core/src/lib.rs new file mode 100644 index 00000000000..b976e7ab270 --- /dev/null +++ b/crates/iota-core/src/lib.rs @@ -0,0 +1,70 @@ +// Copyright (c) 2021, Facebook, Inc. and its affiliates +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +extern crate core; + +pub mod authority; +pub mod authority_aggregator; +pub mod authority_client; +pub mod authority_server; +pub mod checkpoints; +pub mod consensus_adapter; +pub mod consensus_handler; +pub mod consensus_manager; +pub mod consensus_throughput_calculator; +pub(crate) mod consensus_types; +pub mod consensus_validator; +pub mod db_checkpoint_handler; +pub mod epoch; +pub mod execution_cache; +mod execution_driver; +pub mod metrics; +pub mod module_cache_metrics; +pub mod mysticeti_adapter; +pub mod overload_monitor; +pub(crate) mod post_consensus_tx_reorder; +pub mod quorum_driver; +pub mod safe_client; +mod scoring_decision; +mod stake_aggregator; +pub mod state_accumulator; +pub mod storage; +pub mod streamer; +pub mod subscription_handler; +#[cfg(any(test, feature = "test-utils"))] +pub mod test_utils; +mod transaction_input_loader; +mod transaction_manager; +pub mod transaction_orchestrator; +mod transaction_outputs; +pub mod verify_indexes; + +#[cfg(test)] +#[path = "unit_tests/move_package_publish_tests.rs"] +mod move_package_publish_tests; +#[cfg(test)] +#[path = "unit_tests/move_package_tests.rs"] +mod move_package_tests; +#[cfg(test)] +#[path = "unit_tests/move_package_upgrade_tests.rs"] +mod move_package_upgrade_tests; +#[cfg(test)] +#[path = "unit_tests/pay_iota_tests.rs"] +mod pay_iota_tests; +#[cfg(test)] +#[path = "unit_tests/shared_object_deletion_tests.rs"] +mod shared_object_deletion_tests; +pub mod test_authority_clients; +#[cfg(test)] +#[path = "unit_tests/transfer_to_object_tests.rs"] +mod transfer_to_object_tests; +#[cfg(test)] +#[path = "unit_tests/type_param_tests.rs"] +mod type_param_tests; + +pub mod signature_verifier; + +pub mod runtime; +mod transaction_signing_filter; diff --git a/crates/iota-core/src/metrics.rs b/crates/iota-core/src/metrics.rs new file mode 100644 index 00000000000..a30dc2c70b6 --- /dev/null +++ b/crates/iota-core/src/metrics.rs @@ -0,0 +1,240 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::VecDeque, + default::Default, + sync::atomic::{AtomicU64, Ordering}, +}; + +use parking_lot::Mutex; +use tokio::time::{Duration, Instant}; + +pub struct LatencyObserver { + data: Mutex, + latency_ms: AtomicU64, +} + +#[derive(Default)] +struct LatencyObserverInner { + points: VecDeque, + sum: Duration, +} + +impl LatencyObserver { + pub fn new() -> Self { + Self { + data: Mutex::new(LatencyObserverInner::default()), + latency_ms: AtomicU64::new(u64::MAX), + } + } + + pub fn report(&self, latency: Duration) { + const MAX_SAMPLES: usize = 64; + let mut data = self.data.lock(); + data.points.push_back(latency); + data.sum += latency; + if data.points.len() >= MAX_SAMPLES { + let pop = data.points.pop_front().expect("data vector is not empty"); + data.sum -= pop; // This does not overflow because of how running sum is calculated + } + let latency = data.sum.as_millis() as u64 / data.points.len() as u64; + self.latency_ms.store(latency, Ordering::Relaxed); + } + + pub fn latency(&self) -> Option { + let latency = self.latency_ms.load(Ordering::Relaxed); + if latency == u64::MAX { + // Not initialized yet (0 data points) + None + } else { + Some(Duration::from_millis(latency)) + } + } +} + +impl Default for LatencyObserver { + fn default() -> Self { + Self::new() + } +} + +/// RateTracker tracks events in a rolling window, and calculates the rate of +/// events. Internally, the tracker divides the tracking window into multiple +/// BIN_DURATION, and counts events in each BIN_DURATION in a fixed sized +/// buffer. +pub struct RateTracker { + // Counts the number of events by bins. Each bin is BIN_DURATION long within window_duration. + // The size of the buffer = window_duration / BIN_DURATION. + event_buffer: Vec, + window_duration: Duration, + total_bins: usize, + + // We use the event time and the tracker start time to calculate the bin that a event + // belongs to. + // event_global_bin_index = (event_time - start_time) / BIN_DURATION. + // event_index_in_buffer = event_global_bin_index % buffer_size. + start_time: Instant, + + // Last updated global bin index. This tracks the end of the rolling window. + global_bin_index: u64, +} + +const BIN_DURATION: Duration = Duration::from_millis(100); + +impl RateTracker { + /// Create a new RateTracker to track event rate (events/seconds) in + /// `window_duration`. + pub fn new(window_duration: Duration) -> Self { + assert!(window_duration > BIN_DURATION); + let total_bins = (window_duration.as_millis() / BIN_DURATION.as_millis()) as usize; + RateTracker { + event_buffer: vec![0; total_bins], + window_duration, + total_bins, + start_time: Instant::now(), + global_bin_index: 0, + } + } + + /// Records an event at time `now`. + pub fn record_at_time(&mut self, now: Instant) { + self.update_window(now); + let current_bin_index = self.get_bin_index(now) as usize; + if current_bin_index + self.total_bins <= self.global_bin_index as usize { + // The bin associated with `now` has passed the rolling window. + return; + } + + self.event_buffer[current_bin_index % self.total_bins] += 1; + } + + /// Records an event at current time. + pub fn record(&mut self) { + self.record_at_time(Instant::now()); + } + + /// Returns the rate of events. + pub fn rate(&mut self) -> f64 { + let now = Instant::now(); + self.update_window(now); + self.event_buffer.iter().sum::() as f64 / self.window_duration.as_secs_f64() + } + + // Given a time `now`, returns the bin index since `start_time`. + fn get_bin_index(&self, now: Instant) -> u64 { + (now.duration_since(self.start_time).as_millis() / BIN_DURATION.as_millis()) as u64 + } + + // Updates the rolling window to accommodate the time of interests, `now`. That + // is, remove any event counts happened prior to (`now` - + // `window_duration`). + fn update_window(&mut self, now: Instant) { + let current_bin_index = self.get_bin_index(now); + if self.global_bin_index >= current_bin_index { + // The rolling doesn't move. + return; + } + + for bin_index in (self.global_bin_index + 1)..=current_bin_index { + // Time has elapsed from global_bin_index to current_bin_index. Clear all the + // buffer counter associated with them. + let index_in_buffer = bin_index as usize % self.total_bins; + self.event_buffer[index_in_buffer] = 0; + } + self.global_bin_index = current_bin_index; + } +} + +#[cfg(test)] +mod tests { + use rand::{rngs::StdRng, Rng, SeedableRng}; + use tokio::time::advance; + + use super::*; + + #[tokio::test(flavor = "current_thread", start_paused = true)] + pub async fn test_rate_tracker_basic() { + // 1 sec rolling window. + let mut tracker = RateTracker::new(Duration::from_secs(1)); + assert_eq!(tracker.rate(), 0.0); + tracker.record(); + tracker.record(); + tracker.record(); + assert_eq!(tracker.rate(), 3.0); + + advance(Duration::from_millis(200)).await; + tracker.record(); + tracker.record(); + tracker.record(); + assert_eq!(tracker.rate(), 6.0); + + advance(Duration::from_millis(800)).await; + assert_eq!(tracker.rate(), 3.0); + + advance(Duration::from_millis(200)).await; + assert_eq!(tracker.rate(), 0.0); + } + + // Tests rate calculation using different window duration. + #[tokio::test(flavor = "current_thread", start_paused = true)] + pub async fn test_rate_tracker_window() { + let seed = [0; 32]; + let mut rng = StdRng::from_seed(seed); + let random_windows: Vec = (0..10).map(|_| rng.gen_range(1..=60)).collect(); + for window in random_windows { + let mut tracker = RateTracker::new(Duration::from_secs(window)); + for _ in 0..23 { + tracker.record(); + } + assert_eq!(tracker.rate(), 23.0 / window as f64); + advance(Duration::from_secs(window)).await; + assert_eq!(tracker.rate(), 0.0); + } + } + + // Tests rate calculation when window moves continuously. + #[tokio::test(flavor = "current_thread", start_paused = true)] + pub async fn test_rate_tracker_rolling_window() { + let mut tracker = RateTracker::new(Duration::from_secs(1)); + // Generate event every 100ms. + for i in 0..10 { + tracker.record(); + assert_eq!(tracker.rate(), (i + 1) as f64); + advance(Duration::from_millis(100)).await; + } + + // Generate event every 50ms. + for i in 0..10 { + tracker.record(); + advance(Duration::from_millis(50)).await; + tracker.record(); + assert_eq!(tracker.rate(), 11.0 + i as f64); + advance(Duration::from_millis(50)).await; + } + + // Rate gradually returns to 0. + for i in 0..10 { + assert_eq!(tracker.rate(), 20.0 - (i as f64 + 1.0) * 2.0); + advance(Duration::from_millis(100)).await; + } + assert_eq!(tracker.rate(), 0.0); + } + + // Tests that events happened prior to tracking window shouldn't affect the + // rate. + #[tokio::test(flavor = "current_thread", start_paused = true)] + pub async fn test_rate_tracker_outside_of_window() { + let mut tracker = RateTracker::new(Duration::from_secs(1)); + advance(Duration::from_secs(60)).await; + tracker.record(); + tracker.record(); + tracker.record(); + assert_eq!(tracker.rate(), 3.0); + tracker.record_at_time(Instant::now() - Duration::from_millis(1100)); + tracker.record_at_time(Instant::now() - Duration::from_millis(1100)); + tracker.record_at_time(Instant::now() - Duration::from_millis(1100)); + assert_eq!(tracker.rate(), 3.0); + } +} diff --git a/crates/sui-core/src/module_cache_metrics.rs b/crates/iota-core/src/module_cache_metrics.rs similarity index 92% rename from crates/sui-core/src/module_cache_metrics.rs rename to crates/iota-core/src/module_cache_metrics.rs index aed059e48fd..f4c27abf005 100644 --- a/crates/sui-core/src/module_cache_metrics.rs +++ b/crates/iota-core/src/module_cache_metrics.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; diff --git a/crates/sui-core/src/mysticeti_adapter.rs b/crates/iota-core/src/mysticeti_adapter.rs similarity index 91% rename from crates/sui-core/src/mysticeti_adapter.rs rename to crates/iota-core/src/mysticeti_adapter.rs index bb704c09249..f7860eb9afd 100644 --- a/crates/sui-core/src/mysticeti_adapter.rs +++ b/crates/iota-core/src/mysticeti_adapter.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{sync::Arc, time::Duration}; use arc_swap::{ArcSwapOption, Guard}; use consensus_core::TransactionClient; -use sui_types::{ - error::{SuiError, SuiResult}, +use iota_types::{ + error::{IotaError, IotaResult}, messages_consensus::ConsensusTransaction, }; use tap::prelude::*; @@ -41,7 +42,7 @@ impl LazyMysticetiClient { return client; } - // We expect this to get called during the SUI process start. After that at + // We expect this to get called during the IOTA process start. After that at // least one object will have initialised and won't need to call again. const MYSTICETI_START_TIMEOUT: Duration = Duration::from_secs(30); const LOAD_RETRY_TIMEOUT: Duration = Duration::from_millis(100); @@ -77,7 +78,7 @@ impl SubmitToConsensus for LazyMysticetiClient { &self, transaction: &ConsensusTransaction, _epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { // TODO(mysticeti): confirm comment is still true // The retrieved TransactionClient can be from the past epoch. Submit would fail // after Mysticeti shuts down, so there should be no correctness issue. @@ -92,7 +93,7 @@ impl SubmitToConsensus for LazyMysticetiClient { // Will be logged by caller as well. warn!("Submit transaction failed with: {:?}", r); }) - .map_err(|err| SuiError::FailedToSubmitToConsensus(err.to_string()))?; + .map_err(|err| IotaError::FailedToSubmitToConsensus(err.to_string()))?; Ok(()) } } diff --git a/crates/sui-core/src/overload_monitor.rs b/crates/iota-core/src/overload_monitor.rs similarity index 98% rename from crates/sui-core/src/overload_monitor.rs rename to crates/iota-core/src/overload_monitor.rs index 241d02f8fa9..9ad56fa201e 100644 --- a/crates/sui-core/src/overload_monitor.rs +++ b/crates/iota-core/src/overload_monitor.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -11,10 +12,10 @@ use std::{ time::{Duration, SystemTime, UNIX_EPOCH}, }; -use sui_config::node::AuthorityOverloadConfig; -use sui_types::{ +use iota_config::node::AuthorityOverloadConfig; +use iota_types::{ digests::TransactionDigest, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, fp_bail, }; use tokio::time::sleep; @@ -248,7 +249,7 @@ fn should_reject_tx( pub fn overload_monitor_accept_tx( load_shedding_percentage: u32, tx_digest: TransactionDigest, -) -> SuiResult { +) -> IotaResult { // Derive a random seed from the epoch time for transaction selection. Changing // the seed every `SEED_UPDATE_DURATION_SECS` interval allows rejected // transaction's retry to have a chance to go through in the future. @@ -256,7 +257,7 @@ pub fn overload_monitor_accept_tx( // all validators makes the same decision. let temporal_seed = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Sui did not exist prior to 1970") + .expect("Iota did not exist prior to 1970") .as_secs() / SEED_UPDATE_DURATION_SECS; @@ -264,7 +265,7 @@ pub fn overload_monitor_accept_tx( // TODO: using `SEED_UPDATE_DURATION_SECS` is a safe suggestion that the time // based seed is definitely different by then. However, a shorter // suggestion may be available. - fp_bail!(SuiError::ValidatorOverloadedRetryAfter { + fp_bail!(IotaError::ValidatorOverloadedRetryAfter { retry_after_secs: SEED_UPDATE_DURATION_SECS }); } @@ -276,11 +277,11 @@ pub fn overload_monitor_accept_tx( mod tests { use std::sync::Arc; + use iota_macros::sim_test; use rand::{ rngs::{OsRng, StdRng}, Rng, SeedableRng, }; - use sui_macros::sim_test; use tokio::{ sync::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, diff --git a/crates/sui-core/src/post_consensus_tx_reorder.rs b/crates/iota-core/src/post_consensus_tx_reorder.rs similarity index 90% rename from crates/sui-core/src/post_consensus_tx_reorder.rs rename to crates/iota-core/src/post_consensus_tx_reorder.rs index 7bbfe047173..6710775a882 100644 --- a/crates/sui-core/src/post_consensus_tx_reorder.rs +++ b/crates/iota-core/src/post_consensus_tx_reorder.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_protocol_config::ConsensusTransactionOrdering; +use iota_types::messages_consensus::{ConsensusTransaction, ConsensusTransactionKind}; use mysten_metrics::monitored_scope; -use sui_protocol_config::ConsensusTransactionOrdering; -use sui_types::messages_consensus::{ConsensusTransaction, ConsensusTransactionKind}; use crate::consensus_handler::{ SequencedConsensusTransactionKind, VerifiedSequencedConsensusTransaction, diff --git a/crates/iota-core/src/quorum_driver/metrics.rs b/crates/iota-core/src/quorum_driver/metrics.rs new file mode 100644 index 00000000000..c0ce4e98fa4 --- /dev/null +++ b/crates/iota-core/src/quorum_driver/metrics.rs @@ -0,0 +1,138 @@ +// Copyright (c) 2021, Facebook, Inc. and its affiliates +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use mysten_metrics::histogram::Histogram; +use prometheus::{ + register_histogram_vec_with_registry, register_int_counter_vec_with_registry, + register_int_counter_with_registry, register_int_gauge_with_registry, HistogramVec, IntCounter, + IntCounterVec, IntGauge, Registry, +}; + +const FINALITY_LATENCY_SEC_BUCKETS: &[f64] = &[ + 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, + 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, + 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, + 7.0, 7.5, 8.0, 8.5, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, + 25.0, +]; + +#[derive(Clone)] +pub struct QuorumDriverMetrics { + pub(crate) total_requests: IntCounter, + pub(crate) total_enqueued: IntCounter, + pub(crate) total_ok_responses: IntCounter, + pub(crate) total_err_responses: IntCounterVec, + pub(crate) attempt_times_ok_response: Histogram, + + // TODO: add histogram of attempt that tx succeeds + pub(crate) current_requests_in_flight: IntGauge, + + pub(crate) total_err_process_tx_responses_with_nonzero_conflicting_transactions: IntCounter, + pub(crate) total_attempts_retrying_conflicting_transaction: IntCounter, + pub(crate) total_successful_attempts_retrying_conflicting_transaction: IntCounter, + pub(crate) total_times_conflicting_transaction_already_finalized_when_retrying: IntCounter, + pub(crate) total_retryable_overload_errors: IntCounter, + pub(crate) transaction_retry_count: Histogram, + pub(crate) current_transactions_in_retry: IntGauge, + + pub(crate) settlement_finality_latency: HistogramVec, +} + +impl QuorumDriverMetrics { + pub fn new(registry: &Registry) -> Self { + Self { + total_requests: register_int_counter_with_registry!( + "quorum_driver_total_requests", + "Total number of requests received", + registry, + ) + .unwrap(), + total_enqueued: register_int_counter_with_registry!( + "quorum_driver_total_enqueued", + "Total number of requests enqueued", + registry, + ) + .unwrap(), + total_ok_responses: register_int_counter_with_registry!( + "quorum_driver_total_ok_responses", + "Total number of requests processed with Ok responses", + registry, + ) + .unwrap(), + total_err_responses: register_int_counter_vec_with_registry!( + "quorum_driver_total_err_responses", + "Total number of requests returned with Err responses, grouped by error type", + &["error"], + registry, + ) + .unwrap(), + attempt_times_ok_response: Histogram::new_in_registry( + "quorum_driver_attempt_times_ok_response", + "Total attempt times of ok response", + registry, + ), + current_requests_in_flight: register_int_gauge_with_registry!( + "current_requests_in_flight", + "Current number of requests being processed in QuorumDriver", + registry, + ) + .unwrap(), + total_err_process_tx_responses_with_nonzero_conflicting_transactions: register_int_counter_with_registry!( + "quorum_driver_total_err_process_tx_responses_with_nonzero_conflicting_transactions", + "Total number of err process_tx responses with non empty conflicting transactions", + registry, + ) + .unwrap(), + total_attempts_retrying_conflicting_transaction: register_int_counter_with_registry!( + "quorum_driver_total_attempts_trying_conflicting_transaction", + "Total number of attempts to retry a conflicting transaction", + registry, + ) + .unwrap(), + total_successful_attempts_retrying_conflicting_transaction: register_int_counter_with_registry!( + "quorum_driver_total_successful_attempts_trying_conflicting_transaction", + "Total number of successful attempts to retry a conflicting transaction", + registry, + ) + .unwrap(), + total_times_conflicting_transaction_already_finalized_when_retrying: register_int_counter_with_registry!( + "quorum_driver_total_times_conflicting_transaction_already_finalized_when_retrying", + "Total number of times the conflicting transaction is already finalized when retrying", + registry, + ) + .unwrap(), + total_retryable_overload_errors: register_int_counter_with_registry!( + "quorum_driver_total_retryable_overload_errors", + "Total number of transactions experiencing retryable overload error", + registry, + ) + .unwrap(), + transaction_retry_count: Histogram::new_in_registry( + "quorum_driver_transaction_retry_count", + "Histogram of transaction retry count", + registry, + ), + current_transactions_in_retry: register_int_gauge_with_registry!( + "current_transactions_in_retry", + "Current number of transactions in retry loop in QuorumDriver", + registry, + ) + .unwrap(), + settlement_finality_latency: register_histogram_vec_with_registry!( + "quorum_driver_settlement_finality_latency", + "Settlement finality latency observed from quorum driver", + &["tx_type"], + FINALITY_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + } + } + + pub fn new_for_tests() -> Self { + let registry = Registry::new(); + Self::new(®istry) + } +} diff --git a/crates/iota-core/src/quorum_driver/mod.rs b/crates/iota-core/src/quorum_driver/mod.rs new file mode 100644 index 00000000000..7e238d390dc --- /dev/null +++ b/crates/iota-core/src/quorum_driver/mod.rs @@ -0,0 +1,946 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod metrics; +pub use metrics::*; + +pub mod reconfig_observer; + +use std::{ + collections::{BTreeMap, BTreeSet}, + fmt::{Debug, Formatter, Write}, + sync::Arc, + time::Duration, +}; + +use arc_swap::ArcSwap; +use iota_types::{ + base_types::{AuthorityName, ObjectRef, TransactionDigest}, + committee::{Committee, EpochId, StakeUnit}, + error::{IotaError, IotaResult}, + messages_safe_client::PlainTransactionInfoResponse, + quorum_driver_types::{ + QuorumDriverEffectsQueueResult, QuorumDriverError, QuorumDriverResponse, QuorumDriverResult, + }, + transaction::{CertifiedTransaction, Transaction}, +}; +use mysten_common::sync::notify_read::{NotifyRead, Registration}; +use mysten_metrics::{ + spawn_monitored_task, GaugeGuard, TX_TYPE_SHARED_OBJ_TX, TX_TYPE_SINGLE_WRITER_TX, +}; +use tap::TapFallible; +use tokio::{ + sync::{ + mpsc::{self, Receiver, Sender}, + Semaphore, + }, + task::JoinHandle, + time::{sleep_until, Instant}, +}; +use tracing::{debug, error, info, warn, Instrument}; + +use self::reconfig_observer::ReconfigObserver; +use crate::{ + authority_aggregator::{ + AggregatorProcessCertificateError, AggregatorProcessTransactionError, AuthorityAggregator, + ProcessTransactionResult, + }, + authority_client::AuthorityAPI, +}; + +#[cfg(test)] +mod tests; + +const TASK_QUEUE_SIZE: usize = 2000; +const EFFECTS_QUEUE_SIZE: usize = 10000; +const TX_MAX_RETRY_TIMES: u32 = 10; + +#[derive(Clone)] +pub struct QuorumDriverTask { + pub transaction: Transaction, + pub tx_cert: Option, + pub retry_times: u32, + pub next_retry_after: Instant, +} + +impl Debug for QuorumDriverTask { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let mut writer = String::new(); + write!(writer, "tx_digest={:?} ", self.transaction.digest())?; + write!(writer, "has_tx_cert={} ", self.tx_cert.is_some())?; + write!(writer, "retry_times={} ", self.retry_times)?; + write!(writer, "next_retry_after={:?} ", self.next_retry_after)?; + write!(f, "{}", writer) + } +} + +pub struct QuorumDriver { + validators: ArcSwap>, + task_sender: Sender, + effects_subscribe_sender: tokio::sync::broadcast::Sender, + notifier: Arc>, + metrics: Arc, + max_retry_times: u32, +} + +impl QuorumDriver { + pub(crate) fn new( + validators: ArcSwap>, + task_sender: Sender, + effects_subscribe_sender: tokio::sync::broadcast::Sender, + notifier: Arc>, + metrics: Arc, + max_retry_times: u32, + ) -> Self { + Self { + validators, + task_sender, + effects_subscribe_sender, + notifier, + metrics, + max_retry_times, + } + } + + pub fn authority_aggregator(&self) -> &ArcSwap> { + &self.validators + } + + pub fn clone_committee(&self) -> Arc { + self.validators.load().committee.clone() + } + + pub fn current_epoch(&self) -> EpochId { + self.validators.load().committee.epoch + } + + async fn enqueue_task(&self, task: QuorumDriverTask) -> IotaResult<()> { + self.task_sender + .send(task.clone()) + .await + .tap_err(|e| debug!(?task, "Failed to enqueue task: {:?}", e)) + .tap_ok(|_| { + debug!(?task, "Enqueued task."); + self.metrics.current_requests_in_flight.inc(); + self.metrics.total_enqueued.inc(); + if task.retry_times == 1 { + self.metrics.current_transactions_in_retry.inc(); + } + }) + .map_err(|e| IotaError::QuorumDriverCommunicationError { + error: e.to_string(), + }) + } + + /// Enqueue the task again if it hasn't maxed out the total retry attempts. + /// If it has, notify failure. + async fn enqueue_again_maybe( + &self, + transaction: Transaction, + tx_cert: Option, + old_retry_times: u32, + ) -> IotaResult<()> { + if old_retry_times >= self.max_retry_times { + // max out the retry times, notify failure + info!(tx_digest=?transaction.digest(), "Failed to reach finality after attempting for {} times", old_retry_times+1); + self.notify( + &transaction, + &Err( + QuorumDriverError::FailedWithTransientErrorAfterMaximumAttempts { + total_attempts: old_retry_times + 1, + }, + ), + old_retry_times + 1, + ); + return Ok(()); + } + self.backoff_and_enqueue(transaction, tx_cert, old_retry_times) + .await + } + + /// Performs exponential backoff and enqueue the `transaction` to the + /// execution queue. + async fn backoff_and_enqueue( + &self, + transaction: Transaction, + tx_cert: Option, + old_retry_times: u32, + ) -> IotaResult<()> { + let next_retry_after = + Instant::now() + Duration::from_millis(200 * u64::pow(2, old_retry_times)); + sleep_until(next_retry_after).await; + + let tx_cert = match tx_cert { + // TxCert is only valid when its epoch matches current epoch. + // Note, it's impossible that TxCert's epoch is larger than current epoch + // because the TxCert will be considered invalid and cannot reach here. + Some(tx_cert) if tx_cert.epoch() == self.current_epoch() => Some(tx_cert), + _other => None, + }; + + self.enqueue_task(QuorumDriverTask { + transaction, + tx_cert, + retry_times: old_retry_times + 1, + next_retry_after, + }) + .await + } + + pub fn notify( + &self, + transaction: &Transaction, + response: &QuorumDriverResult, + total_attempts: u32, + ) { + let tx_digest = transaction.digest(); + let effects_queue_result = match &response { + Ok(resp) => { + self.metrics.total_ok_responses.inc(); + self.metrics + .attempt_times_ok_response + .report(total_attempts as u64); + Ok((transaction.clone(), resp.clone())) + } + Err(err) => { + self.metrics + .total_err_responses + .with_label_values(&[err.as_ref()]) + .inc(); + Err((*tx_digest, err.clone())) + } + }; + if total_attempts > 1 { + self.metrics.current_transactions_in_retry.dec(); + } + // On fullnode we expect the send to always succeed because + // TransactionOrchestrator should be subscribing to this queue all the + // time. However the if QuorumDriver is used elsewhere log may be noisy. + if let Err(err) = self.effects_subscribe_sender.send(effects_queue_result) { + warn!(?tx_digest, "No subscriber found for effects: {}", err); + } + debug!(?tx_digest, "notify QuorumDriver task result"); + self.notifier.notify(tx_digest, response); + } +} + +impl QuorumDriver +where + A: AuthorityAPI + Send + Sync + 'static + Clone, +{ + pub async fn submit_transaction( + &self, + transaction: Transaction, + ) -> IotaResult> { + let tx_digest = transaction.digest(); + debug!(?tx_digest, "Received transaction execution request."); + self.metrics.total_requests.inc(); + + let ticket = self.notifier.register_one(tx_digest); + self.enqueue_task(QuorumDriverTask { + transaction, + tx_cert: None, + retry_times: 0, + next_retry_after: Instant::now(), + }) + .await?; + Ok(ticket) + } + + // Used when the it is called in a component holding the notifier, and a ticket + // is already obtained prior to calling this function, for instance, + // TransactionOrchestrator + pub async fn submit_transaction_no_ticket(&self, transaction: Transaction) -> IotaResult<()> { + let tx_digest = transaction.digest(); + debug!( + ?tx_digest, + "Received transaction execution request, no ticket." + ); + self.metrics.total_requests.inc(); + + self.enqueue_task(QuorumDriverTask { + transaction, + tx_cert: None, + retry_times: 0, + next_retry_after: Instant::now(), + }) + .await + } + + pub(crate) async fn process_transaction( + &self, + transaction: Transaction, + ) -> Result> { + let auth_agg = self.validators.load(); + let _tx_guard = GaugeGuard::acquire(&auth_agg.metrics.inflight_transactions); + let tx_digest = *transaction.digest(); + let result = auth_agg + .process_transaction(transaction) + .instrument(tracing::debug_span!("aggregator_process_tx", ?tx_digest)) + .await; + + self.process_transaction_result(result, tx_digest).await + } + + async fn process_transaction_result( + &self, + result: Result, + tx_digest: TransactionDigest, + ) -> Result> { + match result { + Ok(resp) => Ok(resp), + Err(AggregatorProcessTransactionError::RetryableConflictingTransaction { + conflicting_tx_digest_to_retry, + errors, + conflicting_tx_digests, + }) => { + self.metrics + .total_err_process_tx_responses_with_nonzero_conflicting_transactions + .inc(); + debug!( + ?tx_digest, + "Observed {} conflicting transactions: {:?}", + conflicting_tx_digests.len(), + conflicting_tx_digests + ); + + if let Some(conflicting_tx_digest) = conflicting_tx_digest_to_retry { + self.process_conflicting_tx( + tx_digest, + conflicting_tx_digest, + conflicting_tx_digests, + ) + .await + } else { + // If no retryable conflicting transaction was returned that means we have >= + // 2f+1 good stake for the original transaction + retryable + // stake. Will continue to retry the original transaction. + debug!( + ?errors, + "Observed Tx {tx_digest:} is still in retryable state. Conflicting Txes: {conflicting_tx_digests:?}", + ); + Err(None) + } + } + + Err(AggregatorProcessTransactionError::FatalConflictingTransaction { + errors, + conflicting_tx_digests, + }) => { + debug!( + ?errors, + "Observed Tx {tx_digest:} double spend attempted. Conflicting Txes: {conflicting_tx_digests:?}", + ); + Err(Some(QuorumDriverError::ObjectsDoubleUsed { + conflicting_txes: conflicting_tx_digests, + retried_tx: None, + retried_tx_success: None, + })) + } + + Err(AggregatorProcessTransactionError::FatalTransaction { errors }) => { + debug!(?tx_digest, ?errors, "Nonretryable transaction error"); + Err(Some(QuorumDriverError::NonRecoverableTransactionError { + errors, + })) + } + + Err(AggregatorProcessTransactionError::SystemOverload { + overloaded_stake, + errors, + }) => { + debug!(?tx_digest, ?errors, "System overload"); + Err(Some(QuorumDriverError::SystemOverload { + overloaded_stake, + errors, + })) + } + + Err(AggregatorProcessTransactionError::SystemOverloadRetryAfter { + overload_stake, + errors, + retry_after_secs, + }) => { + self.metrics.total_retryable_overload_errors.inc(); + debug!(?tx_digest, ?errors, "System overload and retry"); + Err(Some(QuorumDriverError::SystemOverloadRetryAfter { + overload_stake, + errors, + retry_after_secs, + })) + } + + Err(AggregatorProcessTransactionError::RetryableTransaction { errors }) => { + debug!(?tx_digest, ?errors, "Retryable transaction error"); + Err(None) + } + + Err( + AggregatorProcessTransactionError::TxAlreadyFinalizedWithDifferentUserSignatures, + ) => { + debug!( + ?tx_digest, + "Transaction is already finalized with different user signatures" + ); + Err(Some( + QuorumDriverError::TxAlreadyFinalizedWithDifferentUserSignatures, + )) + } + } + } + + async fn process_conflicting_tx( + &self, + tx_digest: TransactionDigest, + conflicting_tx_digest: TransactionDigest, + conflicting_tx_digests: BTreeMap< + TransactionDigest, + (Vec<(AuthorityName, ObjectRef)>, StakeUnit), + >, + ) -> Result> { + // Safe to unwrap because tx_digest_to_retry is generated from + // conflicting_tx_digests + // in ProcessTransactionState::conflicting_tx_digest_with_most_stake() + let (validators, _) = conflicting_tx_digests.get(&conflicting_tx_digest).unwrap(); + let attempt_result = self + .attempt_conflicting_transaction( + &conflicting_tx_digest, + &tx_digest, + validators.iter().map(|(pub_key, _)| *pub_key).collect(), + ) + .await; + self.metrics + .total_attempts_retrying_conflicting_transaction + .inc(); + + match attempt_result { + Err(err) => { + debug!( + ?tx_digest, + ?conflicting_tx_digest, + "Encountered error while attempting conflicting transaction: {:?}", + err + ); + Err(Some(QuorumDriverError::ObjectsDoubleUsed { + conflicting_txes: conflicting_tx_digests, + retried_tx: None, + retried_tx_success: None, + })) + } + Ok(success) => { + debug!( + ?tx_digest, + ?conflicting_tx_digest, + "Retried conflicting transaction. Success: {}", + success + ); + if success { + self.metrics + .total_successful_attempts_retrying_conflicting_transaction + .inc(); + } + Err(Some(QuorumDriverError::ObjectsDoubleUsed { + conflicting_txes: conflicting_tx_digests, + retried_tx: Some(conflicting_tx_digest), + retried_tx_success: Some(success), + })) + } + } + } + + pub(crate) async fn process_certificate( + &self, + certificate: CertifiedTransaction, + ) -> Result> { + let auth_agg = self.validators.load(); + let _cert_guard = GaugeGuard::acquire(&auth_agg.metrics.inflight_certificates); + let tx_digest = *certificate.digest(); + let (effects, events) = auth_agg + .process_certificate(certificate.clone()) + .instrument(tracing::debug_span!("aggregator_process_cert", ?tx_digest)) + .await + .map_err(|agg_err| match agg_err { + AggregatorProcessCertificateError::FatalExecuteCertificate { + non_retryable_errors, + } => { + // Normally a certificate shouldn't have fatal errors. + error!( + ?tx_digest, + ?non_retryable_errors, + "[WATCHOUT] Unexpected Fatal error for certificate" + ); + Some(QuorumDriverError::NonRecoverableTransactionError { + errors: non_retryable_errors, + }) + } + AggregatorProcessCertificateError::RetryableExecuteCertificate { + retryable_errors, + } => { + debug!(?retryable_errors, "Retryable certificate"); + None + } + })?; + let response = QuorumDriverResponse { + effects_cert: effects, + events, + }; + + Ok(response) + } + + pub async fn update_validators(&self, new_validators: Arc>) { + info!( + "Quorum Driver updating AuthorityAggregator with committee {}", + new_validators.committee + ); + self.validators.store(new_validators); + } + + /// Returns Some(true) if the conflicting transaction is executed + /// successfully (or already executed), or Some(false) if it did not. + async fn attempt_conflicting_transaction( + &self, + tx_digest: &TransactionDigest, + original_tx_digest: &TransactionDigest, + validators: BTreeSet, + ) -> IotaResult { + let response = self + .validators + .load() + .handle_transaction_info_request_from_some_validators( + tx_digest, + &validators, + Some(Duration::from_secs(10)), + ) + .await?; + + // If we are able to get a certificate right away, we use it and execute the + // cert; otherwise, we have to re-form a cert and execute it. + let transaction = match response { + PlainTransactionInfoResponse::ExecutedWithCert(cert, _, _) => { + self.metrics + .total_times_conflicting_transaction_already_finalized_when_retrying + .inc(); + // We still want to ask validators to execute this certificate in case this + // certificate is not known to the rest of them (e.g. when + // *this* validator is bad). + let result = self + .validators + .load() + .process_certificate(cert) + .await + .tap_ok(|_resp| { + debug!( + ?tx_digest, + ?original_tx_digest, + "Retry conflicting transaction certificate succeeded." + ); + }) + .tap_err(|err| { + debug!( + ?tx_digest, + ?original_tx_digest, + "Retry conflicting transaction certificate got an error: {:?}", + err + ); + }); + // We only try it once. + return Ok(result.is_ok()); + } + PlainTransactionInfoResponse::Signed(signed) => { + signed.verify_committee_sigs_only(&self.clone_committee())?; + signed.into_unsigned() + } + PlainTransactionInfoResponse::ExecutedWithoutCert(transaction, _, _) => transaction, + }; + // Now ask validators to execute this transaction. + let result = self + .validators + .load() + .execute_transaction_block(&transaction) + .await + .tap_ok(|_resp| { + debug!( + ?tx_digest, + ?original_tx_digest, + "Retry conflicting transaction succeeded." + ); + }) + .tap_err(|err| { + debug!( + ?tx_digest, + ?original_tx_digest, + "Retry conflicting transaction got an error: {:?}", + err + ); + }); + // We only try it once + Ok(result.is_ok()) + } +} + +pub struct QuorumDriverHandler { + quorum_driver: Arc>, + effects_subscriber: tokio::sync::broadcast::Receiver, + quorum_driver_metrics: Arc, + reconfig_observer: Arc + Sync + Send>, + _processor_handle: JoinHandle<()>, +} + +impl QuorumDriverHandler +where + A: AuthorityAPI + Send + Sync + 'static + Clone, +{ + pub(crate) fn new( + validators: Arc>, + notifier: Arc>, + reconfig_observer: Arc + Sync + Send>, + metrics: Arc, + max_retry_times: u32, + ) -> Self { + let (task_tx, task_rx) = mpsc::channel::(TASK_QUEUE_SIZE); + let (subscriber_tx, subscriber_rx) = + tokio::sync::broadcast::channel::<_>(EFFECTS_QUEUE_SIZE); + let quorum_driver = Arc::new(QuorumDriver::new( + ArcSwap::from(validators), + task_tx, + subscriber_tx, + notifier, + metrics.clone(), + max_retry_times, + )); + let metrics_clone = metrics.clone(); + let processor_handle = { + let quorum_driver_clone = quorum_driver.clone(); + spawn_monitored_task!(Self::task_queue_processor( + quorum_driver_clone, + task_rx, + metrics_clone + )) + }; + let reconfig_observer_clone = reconfig_observer.clone(); + { + let quorum_driver_clone = quorum_driver.clone(); + spawn_monitored_task!({ + async move { + let mut reconfig_observer_clone = reconfig_observer_clone.clone_boxed(); + reconfig_observer_clone.run(quorum_driver_clone).await; + } + }); + }; + Self { + quorum_driver, + effects_subscriber: subscriber_rx, + quorum_driver_metrics: metrics, + reconfig_observer, + _processor_handle: processor_handle, + } + } + + // Used when the it is called in a component holding the notifier, and a ticket + // is already obtained prior to calling this function, for instance, + // TransactionOrchestrator + pub async fn submit_transaction_no_ticket(&self, transaction: Transaction) -> IotaResult<()> { + self.quorum_driver + .submit_transaction_no_ticket(transaction) + .await + } + + pub async fn submit_transaction( + &self, + transaction: Transaction, + ) -> IotaResult> { + self.quorum_driver.submit_transaction(transaction).await + } + + /// Create a new `QuorumDriverHandler` based on the same + /// AuthorityAggregator. Note: the new `QuorumDriverHandler` will have a + /// new `ArcSwap` that is NOT tied to the original + /// one. So if there are multiple QuorumDriver(Handler) then all of them + /// need to do reconfigs on their own. + pub fn clone_new(&self) -> Self { + let (task_sender, task_rx) = mpsc::channel::(TASK_QUEUE_SIZE); + let (effects_subscribe_sender, subscriber_rx) = + tokio::sync::broadcast::channel::<_>(EFFECTS_QUEUE_SIZE); + let validators = ArcSwap::new(self.quorum_driver.authority_aggregator().load_full()); + let quorum_driver = Arc::new(QuorumDriver { + validators, + task_sender, + effects_subscribe_sender, + notifier: Arc::new(NotifyRead::new()), + metrics: self.quorum_driver_metrics.clone(), + max_retry_times: self.quorum_driver.max_retry_times, + }); + let metrics = self.quorum_driver_metrics.clone(); + let processor_handle = { + let quorum_driver_copy = quorum_driver.clone(); + spawn_monitored_task!(Self::task_queue_processor( + quorum_driver_copy, + task_rx, + metrics, + )) + }; + { + let quorum_driver_copy = quorum_driver.clone(); + let reconfig_observer = self.reconfig_observer.clone(); + spawn_monitored_task!({ + async move { + let mut reconfig_observer_clone = reconfig_observer.clone_boxed(); + reconfig_observer_clone.run(quorum_driver_copy).await; + } + }) + }; + + Self { + quorum_driver, + effects_subscriber: subscriber_rx, + quorum_driver_metrics: self.quorum_driver_metrics.clone(), + reconfig_observer: self.reconfig_observer.clone(), + _processor_handle: processor_handle, + } + } + + pub fn clone_quorum_driver(&self) -> Arc> { + self.quorum_driver.clone() + } + + pub fn subscribe_to_effects( + &self, + ) -> tokio::sync::broadcast::Receiver { + self.effects_subscriber.resubscribe() + } + + pub fn authority_aggregator(&self) -> &ArcSwap> { + self.quorum_driver.authority_aggregator() + } + + pub fn current_epoch(&self) -> EpochId { + self.quorum_driver.current_epoch() + } + + /// Process a QuorumDriverTask. + /// The function has no return value - the corresponding actions of task + /// result are performed in this call. + async fn process_task(quorum_driver: Arc>, task: QuorumDriverTask) { + debug!(?task, "Quorum Driver processing task"); + let QuorumDriverTask { + transaction, + tx_cert, + retry_times: old_retry_times, + .. + } = task; + let tx_digest = *transaction.digest(); + let is_single_writer_tx = !transaction.contains_shared_object(); + + quorum_driver + .metrics + .transaction_retry_count + .report(old_retry_times as u64 + 1); + + let timer = Instant::now(); + let tx_cert = match tx_cert { + None => match quorum_driver.process_transaction(transaction.clone()).await { + Ok(ProcessTransactionResult::Certified(tx_cert)) => { + debug!(?tx_digest, "Transaction processing succeeded"); + tx_cert + } + Ok(ProcessTransactionResult::Executed(effects_cert, events)) => { + debug!( + ?tx_digest, + "Transaction processing succeeded with effects directly" + ); + let response = QuorumDriverResponse { + effects_cert, + events, + }; + quorum_driver.notify(&transaction, &Ok(response), old_retry_times + 1); + return; + } + Err(err) => { + Self::handle_error( + quorum_driver, + transaction, + err, + None, + old_retry_times, + "get tx cert", + ); + return; + } + }, + Some(tx_cert) => tx_cert, + }; + + let response = match quorum_driver.process_certificate(tx_cert.clone()).await { + Ok(response) => { + debug!(?tx_digest, "Certificate processing succeeded"); + response + } + // Note: non retryable failure when processing a cert + // should be very rare. + Err(err) => { + Self::handle_error( + quorum_driver, + transaction, + err, + Some(tx_cert), + old_retry_times, + "get effects cert", + ); + return; + } + }; + let settlement_finality_latency = timer.elapsed().as_secs_f64(); + quorum_driver + .metrics + .settlement_finality_latency + .with_label_values(&[if is_single_writer_tx { + TX_TYPE_SINGLE_WRITER_TX + } else { + TX_TYPE_SHARED_OBJ_TX + }]) + .observe(settlement_finality_latency); + if settlement_finality_latency >= 8.0 || settlement_finality_latency <= 0.1 { + debug!( + ?tx_digest, + "Settlement finality latency is out of expected range: {}", + settlement_finality_latency + ); + } + + quorum_driver.notify(&transaction, &Ok(response), old_retry_times + 1); + } + + fn handle_error( + quorum_driver: Arc>, + transaction: Transaction, + err: Option, + tx_cert: Option, + old_retry_times: u32, + action: &'static str, + ) { + let tx_digest = *transaction.digest(); + match err { + None => { + debug!(?tx_digest, "Failed to {action} - Retrying"); + spawn_monitored_task!(quorum_driver.enqueue_again_maybe( + transaction.clone(), + tx_cert, + old_retry_times + )); + } + Some(QuorumDriverError::SystemOverloadRetryAfter { .. }) => { + // Special case for SystemOverloadRetryAfter error. In this case, due to that + // objects are already locked inside validators, we need to + // perform continuous retry and ignore `max_retry_times`. + // TODO: the txn can potentially be retried unlimited times, therefore, we need + // to bound the number of on going transactions in a quorum + // driver. When the limit is reached, the quorum driver should + // reject any new transaction requests. + debug!(?tx_digest, "Failed to {action} - Retrying"); + spawn_monitored_task!(quorum_driver.backoff_and_enqueue( + transaction.clone(), + tx_cert, + old_retry_times + )); + } + Some(qd_error) => { + debug!(?tx_digest, "Failed to {action}: {}", qd_error); + // non-retryable failure, this task reaches terminal state for now, notify + // waiter. + quorum_driver.notify(&transaction, &Err(qd_error), old_retry_times + 1); + } + } + } + + async fn task_queue_processor( + quorum_driver: Arc>, + mut task_receiver: Receiver, + metrics: Arc, + ) { + let limit = Arc::new(Semaphore::new(TASK_QUEUE_SIZE)); + while let Some(task) = task_receiver.recv().await { + // hold semaphore permit until task completes. unwrap ok because we never close + // the semaphore in this context. + let limit = limit.clone(); + let permit = limit.acquire_owned().await.unwrap(); + + // TODO check reconfig process here + + debug!(?task, "Dequeued task"); + if Instant::now() + .checked_duration_since(task.next_retry_after) + .is_none() + { + // Not ready for next attempt yet, re-enqueue + let _ = quorum_driver.enqueue_task(task).await; + continue; + } + metrics.current_requests_in_flight.dec(); + let qd = quorum_driver.clone(); + spawn_monitored_task!(async move { + let _guard = permit; + QuorumDriverHandler::process_task(qd, task).await + }); + } + } +} + +pub struct QuorumDriverHandlerBuilder { + validators: Arc>, + metrics: Arc, + notifier: Option>>, + reconfig_observer: Option + Sync + Send>>, + max_retry_times: u32, +} + +impl QuorumDriverHandlerBuilder +where + A: AuthorityAPI + Send + Sync + 'static + Clone, +{ + pub fn new(validators: Arc>, metrics: Arc) -> Self { + Self { + validators, + metrics, + notifier: None, + reconfig_observer: None, + max_retry_times: TX_MAX_RETRY_TIMES, + } + } + + pub(crate) fn with_notifier( + mut self, + notifier: Arc>, + ) -> Self { + self.notifier = Some(notifier); + self + } + + pub fn with_reconfig_observer( + mut self, + reconfig_observer: Arc + Sync + Send>, + ) -> Self { + self.reconfig_observer = Some(reconfig_observer); + self + } + + /// Used in tests when smaller number of retries is desired + pub fn with_max_retry_times(mut self, max_retry_times: u32) -> Self { + self.max_retry_times = max_retry_times; + self + } + + pub fn start(self) -> QuorumDriverHandler { + QuorumDriverHandler::new( + self.validators, + self.notifier.unwrap_or_else(|| { + Arc::new(NotifyRead::::new()) + }), + self.reconfig_observer + .expect("Reconfig observer is missing"), + self.metrics, + self.max_retry_times, + ) + } +} diff --git a/crates/sui-core/src/quorum_driver/reconfig_observer.rs b/crates/iota-core/src/quorum_driver/reconfig_observer.rs similarity index 93% rename from crates/sui-core/src/quorum_driver/reconfig_observer.rs rename to crates/iota-core/src/quorum_driver/reconfig_observer.rs index a68fd029a1c..02a7181eaa8 100644 --- a/crates/sui-core/src/quorum_driver/reconfig_observer.rs +++ b/crates/iota-core/src/quorum_driver/reconfig_observer.rs @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; use async_trait::async_trait; -use sui_types::sui_system_state::{SuiSystemState, SuiSystemStateTrait}; +use iota_types::iota_system_state::{IotaSystemState, IotaSystemStateTrait}; use tokio::sync::broadcast::error::RecvError; use tracing::{info, warn}; @@ -26,7 +27,7 @@ pub trait ReconfigObserver { /// A ReconfigObserver that subscribes to a reconfig channel of new committee. /// This is used in TransactionOrchestrator. pub struct OnsiteReconfigObserver { - reconfig_rx: tokio::sync::broadcast::Receiver, + reconfig_rx: tokio::sync::broadcast::Receiver, execution_cache: Arc, committee_store: Arc, safe_client_metrics_base: SafeClientMetricsBase, @@ -35,7 +36,7 @@ pub struct OnsiteReconfigObserver { impl OnsiteReconfigObserver { pub fn new( - reconfig_rx: tokio::sync::broadcast::Receiver, + reconfig_rx: tokio::sync::broadcast::Receiver, execution_cache: Arc, committee_store: Arc, safe_client_metrics_base: SafeClientMetricsBase, @@ -83,7 +84,7 @@ impl ReconfigObserver for OnsiteReconfigObserver { async fn run(&mut self, quorum_driver: Arc>) { // A tiny optimization: when a very stale node just starts, the // channel may fill up committees quickly. Here we skip directly to - // the last known committee by looking at SuiSystemState. + // the last known committee by looking at IotaSystemState. let authority_agg = self.create_authority_aggregator_from_system_state().await; if authority_agg.committee.epoch > quorum_driver.current_epoch() { quorum_driver diff --git a/crates/iota-core/src/quorum_driver/tests.rs b/crates/iota-core/src/quorum_driver/tests.rs new file mode 100644 index 00000000000..5c1e337f3b1 --- /dev/null +++ b/crates/iota-core/src/quorum_driver/tests.rs @@ -0,0 +1,526 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{sync::Arc, time::Duration}; + +use iota_types::{ + base_types::{IotaAddress, TransactionDigest}, + crypto::{deterministic_random_account_key, get_key_pair, AccountKeyPair}, + effects::TransactionEffectsAPI, + object::{generate_test_gas_objects, Object}, + quorum_driver_types::{QuorumDriverError, QuorumDriverResponse, QuorumDriverResult}, + transaction::Transaction, +}; +use mysten_common::sync::notify_read::{NotifyRead, Registration}; +use tokio::time::timeout; + +use crate::{ + quorum_driver::{ + reconfig_observer::DummyReconfigObserver, AuthorityAggregator, QuorumDriverHandlerBuilder, + QuorumDriverMetrics, + }, + test_authority_clients::{LocalAuthorityClient, LocalAuthorityClientFaultConfig}, + test_utils::{init_local_authorities, make_transfer_iota_transaction}, +}; + +async fn setup() -> (AuthorityAggregator, Transaction) { + let (sender, keypair): (_, AccountKeyPair) = get_key_pair(); + let gas_object = Object::with_owner_for_testing(sender); + let (aggregator, authorities, genesis, _) = + init_local_authorities(4, vec![gas_object.clone()]).await; + let rgp = authorities + .first() + .unwrap() + .reference_gas_price_for_testing() + .unwrap(); + let gas_object = genesis + .objects() + .iter() + .find(|o| o.id() == gas_object.id()) + .unwrap(); + + let tx = make_tx(gas_object, sender, &keypair, rgp); + (aggregator, tx) +} + +fn make_tx( + gas: &Object, + sender: IotaAddress, + keypair: &AccountKeyPair, + gas_price: u64, +) -> Transaction { + make_transfer_iota_transaction( + gas.compute_object_reference(), + IotaAddress::random_for_testing_only(), + None, + sender, + keypair, + gas_price, + ) +} + +#[tokio::test] +async fn test_quorum_driver_submit_transaction() { + let (aggregator, tx) = setup().await; + let digest = *tx.digest(); + + let quorum_driver_handler = Arc::new( + QuorumDriverHandlerBuilder::new( + Arc::new(aggregator), + Arc::new(QuorumDriverMetrics::new_for_tests()), + ) + .with_reconfig_observer(Arc::new(DummyReconfigObserver {})) + .start(), + ); + // Test submit_transaction + let qd_clone = quorum_driver_handler.clone(); + let handle = tokio::task::spawn(async move { + let (tx, QuorumDriverResponse { effects_cert, .. }) = qd_clone + .subscribe_to_effects() + .recv() + .await + .unwrap() + .unwrap(); + assert_eq!(tx.digest(), &digest); + assert_eq!(*effects_cert.data().transaction_digest(), digest); + }); + let ticket = quorum_driver_handler.submit_transaction(tx).await.unwrap(); + verify_ticket_response(ticket, &digest).await; + + handle.await.unwrap(); +} + +#[tokio::test] +async fn test_quorum_driver_submit_transaction_no_ticket() { + let (aggregator, tx) = setup().await; + let digest = *tx.digest(); + + let quorum_driver_handler = Arc::new( + QuorumDriverHandlerBuilder::new( + Arc::new(aggregator), + Arc::new(QuorumDriverMetrics::new_for_tests()), + ) + .with_reconfig_observer(Arc::new(DummyReconfigObserver {})) + .start(), + ); + let qd_clone = quorum_driver_handler.clone(); + let handle = tokio::task::spawn(async move { + let (tx, QuorumDriverResponse { effects_cert, .. }) = qd_clone + .subscribe_to_effects() + .recv() + .await + .unwrap() + .unwrap(); + assert_eq!(tx.digest(), &digest); + assert_eq!(*effects_cert.data().transaction_digest(), digest); + }); + quorum_driver_handler + .submit_transaction_no_ticket(tx) + .await + .unwrap(); + handle.await.unwrap(); +} + +async fn verify_ticket_response<'a>( + ticket: Registration<'a, TransactionDigest, QuorumDriverResult>, + tx_digest: &TransactionDigest, +) { + let QuorumDriverResponse { effects_cert, .. } = ticket.await.unwrap(); + assert_eq!(effects_cert.data().transaction_digest(), tx_digest); +} + +#[tokio::test] +async fn test_quorum_driver_with_given_notify_read() { + let (aggregator, tx) = setup().await; + let digest = *tx.digest(); + let notifier = Arc::new(NotifyRead::new()); + + let quorum_driver_handler = Arc::new( + QuorumDriverHandlerBuilder::new( + Arc::new(aggregator), + Arc::new(QuorumDriverMetrics::new_for_tests()), + ) + .with_notifier(notifier.clone()) + .with_reconfig_observer(Arc::new(DummyReconfigObserver {})) + .start(), + ); + + let qd_clone = quorum_driver_handler.clone(); + let handle = tokio::task::spawn(async move { + let (tx, QuorumDriverResponse { effects_cert, .. }) = qd_clone + .subscribe_to_effects() + .recv() + .await + .unwrap() + .unwrap(); + assert_eq!(tx.digest(), &digest); + assert_eq!(*effects_cert.data().transaction_digest(), digest); + }); + let ticket1 = notifier.register_one(&digest); + let ticket2 = quorum_driver_handler.submit_transaction(tx).await.unwrap(); + verify_ticket_response(ticket1, &digest).await; + verify_ticket_response(ticket2, &digest).await; + + handle.await.unwrap(); +} + +// TODO: add other cases for mismatched validator/client epoch +#[tokio::test] +async fn test_quorum_driver_update_validators_and_max_retry_times() { + telemetry_subscribers::init_for_testing(); + let (mut aggregator, tx) = setup().await; + let arc_aggregator = Arc::new(aggregator.clone()); + + let quorum_driver_handler = Arc::new( + QuorumDriverHandlerBuilder::new( + arc_aggregator.clone(), + Arc::new(QuorumDriverMetrics::new_for_tests()), + ) + .with_reconfig_observer(Arc::new(DummyReconfigObserver {})) + .with_max_retry_times(3) + .start(), + ); + + let quorum_driver = quorum_driver_handler.clone_quorum_driver(); + let quorum_driver_clone = quorum_driver.clone(); + let handle = tokio::task::spawn(async move { + // Wait till the epoch/committee is updated. + tokio::time::sleep(Duration::from_secs(3)).await; + + // This now will fail due to server/client epoch mismatch: + // server's epoch is 0 but client's is 10 + // This error should not happen in practice for benign validators and a working + // client + let ticket = quorum_driver.submit_transaction(tx).await.unwrap(); + // We have a timeout here to make the test fail fast if fails + match tokio::time::timeout(Duration::from_secs(20), ticket).await { + Ok(Err(QuorumDriverError::FailedWithTransientErrorAfterMaximumAttempts { + total_attempts, + })) => assert_eq!(total_attempts, 4), + _ => panic!( + "The transaction should err on SafeClient epoch check mismatch, be retried 3 times and raise QuorumDriverError::FailedWithTransientErrorAfterMaximumAttempts error" + ), + }; + }); + + // Update authority aggregator with a new epoch number, and let quorum driver + // know. + let mut committee = aggregator.clone_inner_committee_test_only(); + committee.epoch = 10; + aggregator.committee = Arc::new(committee); + quorum_driver_clone + .update_validators(Arc::new(aggregator)) + .await; + assert_eq!( + quorum_driver_handler.clone_quorum_driver().current_epoch(), + 10 + ); + + handle.await.unwrap(); +} + +#[tokio::test] +async fn test_quorum_driver_object_locked() -> Result<(), anyhow::Error> { + let gas_objects = generate_test_gas_objects(); + let (sender, keypair): (IotaAddress, AccountKeyPair) = deterministic_random_account_key(); + + let (aggregator, authorities, genesis, _) = + init_local_authorities(4, gas_objects.clone()).await; + let rgp = authorities + .first() + .unwrap() + .reference_gas_price_for_testing() + .unwrap(); + + let mut gas_objects = gas_objects + .into_iter() + .map(|o| { + genesis + .objects() + .iter() + .find(|go| go.id() == o.id()) + .unwrap() + .to_owned() + }) + .collect::>(); + + let aggregator = Arc::new(aggregator); + + let quorum_driver_handler = Arc::new( + QuorumDriverHandlerBuilder::new( + aggregator.clone(), + Arc::new(QuorumDriverMetrics::new_for_tests()), + ) + .with_reconfig_observer(Arc::new(DummyReconfigObserver {})) + .start(), + ); + + let quorum_driver = quorum_driver_handler.clone_quorum_driver(); + + let gas = gas_objects.pop().unwrap(); + let tx = make_tx(&gas, sender, &keypair, rgp); + let names: Vec<_> = aggregator.authority_clients.keys().clone().collect(); + assert_eq!(names.len(), 4); + let client0 = aggregator.clone_client_test_only(names[0]); + let client1 = aggregator.clone_client_test_only(names[1]); + let client2 = aggregator.clone_client_test_only(names[2]); + + println!("Case 0 - two validators lock the object with the same tx"); + assert!(client0.handle_transaction(tx.clone()).await.is_ok()); + assert!(client1.handle_transaction(tx.clone()).await.is_ok()); + + let tx2 = make_tx(&gas, sender, &keypair, rgp); + let res = quorum_driver.submit_transaction(tx2).await.unwrap().await; + + // Aggregator waits for all responses when it sees a conflicting tx and because + // there are not enough retryable errors to push the original tx or the most + // staked conflicting tx >= 2f+1 stake. Neither transaction can be retried + // due to client double spend and this is a fatal error. + if let Err(QuorumDriverError::ObjectsDoubleUsed { + conflicting_txes, + retried_tx, + retried_tx_success, + }) = res + { + assert_eq!(retried_tx, None); + assert_eq!(retried_tx_success, None); + assert_eq!(conflicting_txes.len(), 1); + assert_eq!(conflicting_txes.iter().next().unwrap().0, tx.digest()); + } else { + panic!( + "expect Err(QuorumDriverError::ObjectsDoubleUsed) but got {:?}", + res + ); + } + + println!("Case 1 - three validators lock the object with the same tx"); + let gas = gas_objects.pop().unwrap(); + let tx = make_tx(&gas, sender, &keypair, rgp); + + assert!(client0.handle_transaction(tx.clone()).await.is_ok()); + assert!(client1.handle_transaction(tx.clone()).await.is_ok()); + assert!(client2.handle_transaction(tx.clone()).await.is_ok()); + + let tx2 = make_tx(&gas, sender, &keypair, rgp); + + let res = quorum_driver.submit_transaction(tx2).await.unwrap().await; + // Aggregator gets three bad responses, and tries tx, which should succeed. + if let Err(QuorumDriverError::ObjectsDoubleUsed { + conflicting_txes, + retried_tx, + retried_tx_success, + }) = res + { + assert_eq!(retried_tx, Some(*tx.digest())); + assert_eq!(retried_tx_success, Some(true)); + assert_eq!(conflicting_txes.len(), 1); + assert_eq!(conflicting_txes.iter().next().unwrap().0, tx.digest()); + } else { + panic!( + "expect Err(QuorumDriverError::ObjectsDoubleUsed) but got {:?}", + res + ) + } + + println!("Case 2 - one validator locks the object"); + let gas = gas_objects.pop().unwrap(); + let tx = make_tx(&gas, sender, &keypair, rgp); + assert!(client0.handle_transaction(tx.clone()).await.is_ok()); + + let tx2 = make_tx(&gas, sender, &keypair, rgp); + let tx2_digest = *tx2.digest(); + + let res = quorum_driver + .submit_transaction(tx2) + .await + .unwrap() + .await + .unwrap(); + + // Aggregator gets three good responses and execution succeeds. + let QuorumDriverResponse { effects_cert, .. } = res; + assert_eq!(*effects_cert.transaction_digest(), tx2_digest); + + println!( + "Case 3 - object is locked by 2 txes with weight 2 and 1 respectivefully. Then try to execute the third txn" + ); + let gas = gas_objects.pop().unwrap(); + let tx = make_tx(&gas, sender, &keypair, rgp); + let tx2 = make_tx(&gas, sender, &keypair, rgp); + + assert!(client0.handle_transaction(tx.clone()).await.is_ok()); + assert!(client1.handle_transaction(tx.clone()).await.is_ok()); + assert!(client2.handle_transaction(tx2.clone()).await.is_ok()); + + let tx3 = make_tx(&gas, sender, &keypair, rgp); + + let res = quorum_driver.submit_transaction(tx3).await.unwrap().await; + + if let Err(QuorumDriverError::ObjectsDoubleUsed { + conflicting_txes, + retried_tx, + retried_tx_success, + }) = res + { + assert_eq!(retried_tx, None); + assert_eq!(retried_tx_success, None); + assert_eq!(conflicting_txes.len(), 2); + let tx_stake = conflicting_txes.get(tx.digest()).unwrap().1; + assert!(tx_stake == 2500 || tx_stake == 5000); + assert_eq!(conflicting_txes.get(tx2.digest()).unwrap().1, 2500); + } else { + panic!( + "expect Err(QuorumDriverError::ObjectsDoubleUsed) but got {:?}", + res + ) + } + + println!( + "Case 4 - object is locked by 2 txes with weight 2 and 1, try to execute the lighter stake tx" + ); + let gas = gas_objects.pop().unwrap(); + let tx = make_tx(&gas, sender, &keypair, rgp); + let tx2 = make_tx(&gas, sender, &keypair, rgp); + assert!(client0.handle_transaction(tx.clone()).await.is_ok()); + assert!(client1.handle_transaction(tx.clone()).await.is_ok()); + assert!(client2.handle_transaction(tx2.clone()).await.is_ok()); + let res = quorum_driver.submit_transaction(tx2).await.unwrap().await; + + if let Err(QuorumDriverError::ObjectsDoubleUsed { + conflicting_txes, + retried_tx, + retried_tx_success, + }) = res + { + assert_eq!(retried_tx, None); + assert_eq!(retried_tx_success, None); + assert_eq!(conflicting_txes.len(), 1); + assert_eq!(conflicting_txes.get(tx.digest()).unwrap().1, 5000); + } else { + panic!( + "expect Err(QuorumDriverError::ObjectsDoubleUsed) but got {:?}", + res + ) + } + + println!( + "Case 5 - object is locked by 2 txes with weight 2 and 1, try to execute the heavier stake tx" + ); + let gas = gas_objects.pop().unwrap(); + let tx = make_tx(&gas, sender, &keypair, rgp); + let tx_digest = *tx.digest(); + let tx2 = make_tx(&gas, sender, &keypair, rgp); + + assert!(client0.handle_transaction(tx.clone()).await.is_ok()); + assert!(client1.handle_transaction(tx.clone()).await.is_ok()); + assert!(client2.handle_transaction(tx2).await.is_ok()); + + let res = quorum_driver + .submit_transaction(tx) + .await + .unwrap() + .await + .unwrap(); + + let QuorumDriverResponse { effects_cert, .. } = res; + assert_eq!(*effects_cert.transaction_digest(), tx_digest); + + println!("Case 6 - three validators lock the object, by different txes"); + let gas = gas_objects.pop().unwrap(); + let tx = make_tx(&gas, sender, &keypair, rgp); + let tx2 = make_tx(&gas, sender, &keypair, rgp); + let tx3 = make_tx(&gas, sender, &keypair, rgp); + assert!(client0.handle_transaction(tx.clone()).await.is_ok()); + assert!(client1.handle_transaction(tx2.clone()).await.is_ok()); + assert!(client2.handle_transaction(tx3.clone()).await.is_ok()); + + let tx4 = make_tx(&gas, sender, &keypair, rgp); + let res = quorum_driver + .submit_transaction(tx4.clone()) + .await + .unwrap() + .await; + + if let Err(QuorumDriverError::ObjectsDoubleUsed { + conflicting_txes, + retried_tx, + retried_tx_success, + }) = res + { + assert_eq!(retried_tx, None); + assert_eq!(retried_tx_success, None); + assert!(conflicting_txes.len() == 3 || conflicting_txes.len() == 2); + assert!( + conflicting_txes + .iter() + .all(|(digest, (_objs, stake))| (*stake == 2500) + && (digest == tx.digest() || digest == tx2.digest() || digest == tx3.digest())) + ); + } else { + panic!( + "expect Err(QuorumDriverError::ObjectsDoubleUsed) but got {:?}", + res + ) + } + + Ok(()) +} + +// Tests that quorum driver can continuously retry txn with +// SystemOverloadedRetryAfter error. +#[tokio::test(flavor = "current_thread", start_paused = true)] +async fn test_quorum_driver_handling_overload_and_retry() { + telemetry_subscribers::init_for_testing(); + + // Setup + let (sender, keypair): (_, AccountKeyPair) = get_key_pair(); + let gas_object = Object::with_owner_for_testing(sender); + let (mut aggregator, authorities, genesis, _) = + init_local_authorities(4, vec![gas_object.clone()]).await; + + // Make local authority client to always return SystemOverloadedRetryAfter + // error. + let fault_config = LocalAuthorityClientFaultConfig { + overload_retry_after_handle_transaction: true, + ..Default::default() + }; + let mut clients = aggregator.clone_inner_clients_test_only(); + for client in &mut clients.values_mut() { + client.authority_client_mut().fault_config = fault_config; + } + let clients = clients.into_iter().map(|(k, v)| (k, Arc::new(v))).collect(); + aggregator.authority_clients = Arc::new(clients); + + // Create a transaction for the test. + let rgp = authorities + .first() + .unwrap() + .reference_gas_price_for_testing() + .unwrap(); + let gas_object = genesis + .objects() + .iter() + .find(|o| o.id() == gas_object.id()) + .unwrap(); + let tx = make_tx(gas_object, sender, &keypair, rgp); + + // Create a quorum driver with max_retry_times = 0. + let arc_aggregator = Arc::new(aggregator.clone()); + let quorum_driver_handler = Arc::new( + QuorumDriverHandlerBuilder::new( + arc_aggregator.clone(), + Arc::new(QuorumDriverMetrics::new_for_tests()), + ) + .with_reconfig_observer(Arc::new(DummyReconfigObserver {})) + .with_max_retry_times(0) + .start(), + ); + + // Submit the transaction, and check that it shouldn't return. + let ticket = quorum_driver_handler.submit_transaction(tx).await.unwrap(); + match timeout(Duration::from_secs(300), ticket).await { + Ok(result) => panic!("Process transaction should timeout! {:?}", result), + Err(_) => eprintln!("Waiting for txn timed out! This is desired behavior."), + } +} diff --git a/crates/sui-core/src/runtime.rs b/crates/iota-core/src/runtime.rs similarity index 81% rename from crates/sui-core/src/runtime.rs rename to crates/iota-core/src/runtime.rs index 56876044b25..2fd1ae723c3 100644 --- a/crates/sui-core/src/runtime.rs +++ b/crates/iota-core/src/runtime.rs @@ -1,24 +1,25 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{env, str::FromStr}; -use sui_config::NodeConfig; +use iota_config::NodeConfig; use tap::TapFallible; use tokio::runtime::Runtime; use tracing::warn; -pub struct SuiRuntimes { +pub struct IotaRuntimes { // Order in this struct is the order in which runtimes are stopped pub json_rpc: Runtime, - pub sui_node: Runtime, + pub iota_node: Runtime, pub metrics: Runtime, } -impl SuiRuntimes { +impl IotaRuntimes { pub fn new(_confg: &NodeConfig) -> Self { - let sui_node = tokio::runtime::Builder::new_multi_thread() - .thread_name("sui-node-runtime") + let iota_node = tokio::runtime::Builder::new_multi_thread() + .thread_name("iota-node-runtime") .enable_all() .build() .unwrap(); @@ -45,7 +46,7 @@ impl SuiRuntimes { .build() .unwrap(); Self { - sui_node, + iota_node, metrics, json_rpc, } diff --git a/crates/sui-core/src/safe_client.rs b/crates/iota-core/src/safe_client.rs similarity index 91% rename from crates/sui-core/src/safe_client.rs rename to crates/iota-core/src/safe_client.rs index 2992307e8d5..b940f70206c 100644 --- a/crates/sui-core/src/safe_client.rs +++ b/crates/iota-core/src/safe_client.rs @@ -1,20 +1,18 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; -use mysten_metrics::histogram::{Histogram, HistogramVec}; -use prometheus::{ - core::GenericCounter, register_int_counter_vec_with_registry, IntCounterVec, Registry, -}; -use sui_types::{ +use iota_types::{ base_types::*, committee::*, crypto::AuthorityPublicKeyBytes, effects::{SignedTransactionEffects, TransactionEffectsAPI}, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, fp_ensure, + iota_system_state::IotaSystemState, messages_checkpoint::{ CertifiedCheckpointSummary, CheckpointRequest, CheckpointResponse, CheckpointSequenceNumber, }, @@ -23,9 +21,12 @@ use sui_types::{ TransactionInfoRequest, TransactionStatus, VerifiedObjectInfoResponse, }, messages_safe_client::PlainTransactionInfoResponse, - sui_system_state::SuiSystemState, transaction::*, }; +use mysten_metrics::histogram::{Histogram, HistogramVec}; +use prometheus::{ + core::GenericCounter, register_int_counter_vec_with_registry, IntCounterVec, Registry, +}; use tap::TapFallible; use tracing::{debug, error}; @@ -179,10 +180,10 @@ impl SafeClient { &mut self.authority_client } - fn get_committee(&self, epoch_id: &EpochId) -> SuiResult> { + fn get_committee(&self, epoch_id: &EpochId) -> IotaResult> { self.committee_store .get_committee(epoch_id)? - .ok_or(SuiError::MissingCommitteeAtEpoch(*epoch_id)) + .ok_or(IotaError::MissingCommitteeAtEpoch(*epoch_id)) } fn check_signed_effects_plain( @@ -190,11 +191,11 @@ impl SafeClient { digest: &TransactionDigest, signed_effects: SignedTransactionEffects, expected_effects_digest: Option<&TransactionEffectsDigest>, - ) -> SuiResult { + ) -> IotaResult { // Check it has the right signer fp_ensure!( signed_effects.auth_sig().authority == self.address, - SuiError::ByzantineAuthoritySuspicion { + IotaError::ByzantineAuthoritySuspicion { authority: self.address, reason: format!( "Unexpected validator address in the signed effects signature: {:?}", @@ -205,7 +206,7 @@ impl SafeClient { // Checks it concerns the right tx fp_ensure!( signed_effects.data().transaction_digest() == digest, - SuiError::ByzantineAuthoritySuspicion { + IotaError::ByzantineAuthoritySuspicion { authority: self.address, reason: "Unexpected tx digest in the signed effects".to_string() } @@ -214,7 +215,7 @@ impl SafeClient { if let Some(effects_digest) = expected_effects_digest { fp_ensure!( signed_effects.digest() == effects_digest, - SuiError::ByzantineAuthoritySuspicion { + IotaError::ByzantineAuthoritySuspicion { authority: self.address, reason: "Effects digest does not match with expected digest".to_string() } @@ -229,10 +230,10 @@ impl SafeClient { digest: &TransactionDigest, transaction: Transaction, status: TransactionStatus, - ) -> SuiResult { + ) -> IotaResult { fp_ensure!( digest == transaction.digest(), - SuiError::ByzantineAuthoritySuspicion { + IotaError::ByzantineAuthoritySuspicion { authority: self.address, reason: "Signed transaction digest does not match with expected digest".to_string() } @@ -254,7 +255,7 @@ impl SafeClient { cert, ); ct.verify_committee_sigs_only(&committee).map_err(|e| { - SuiError::FailedToVerifyTxCertWithExecutedEffects { + IotaError::FailedToVerifyTxCertWithExecutedEffects { validator_name: self.address, error: e.to_string(), } @@ -279,7 +280,7 @@ impl SafeClient { &self, request: &ObjectInfoRequest, response: ObjectInfoResponse, - ) -> SuiResult { + ) -> IotaResult { let ObjectInfoResponse { object, layout: _, @@ -288,7 +289,7 @@ impl SafeClient { fp_ensure!( request.object_id == object.id(), - SuiError::ByzantineAuthoritySuspicion { + IotaError::ByzantineAuthoritySuspicion { authority: self.address, reason: "Object id mismatch in the response".to_string() } @@ -306,11 +307,11 @@ impl SafeClient where C: AuthorityAPI + Send + Sync + Clone + 'static, { - /// Initiate a new transfer to a Sui or Primary account. + /// Initiate a new transfer to a Iota or Primary account. pub async fn handle_transaction( &self, transaction: Transaction, - ) -> Result { + ) -> Result { let _timer = self.metrics.handle_transaction_latency.start_timer(); let digest = *transaction.digest(); let response = self @@ -329,7 +330,7 @@ where &self, digest: &TransactionDigest, response: HandleCertificateResponseV2, - ) -> SuiResult { + ) -> IotaResult { let signed_effects = self.check_signed_effects_plain(digest, response.signed_effects, None)?; @@ -344,7 +345,7 @@ where pub async fn handle_certificate_v2( &self, certificate: CertifiedTransaction, - ) -> Result { + ) -> Result { let digest = *certificate.digest(); let _timer = self.metrics.handle_certificate_latency.start_timer(); let response = self @@ -363,7 +364,7 @@ where pub async fn handle_object_info_request( &self, request: ObjectInfoRequest, - ) -> Result { + ) -> Result { self.metrics.total_requests_handle_object_info_request.inc(); let _timer = self.metrics.handle_obj_info_latency.start_timer(); @@ -385,7 +386,7 @@ where pub async fn handle_transaction_info_request( &self, request: TransactionInfoRequest, - ) -> Result { + ) -> Result { self.metrics .total_requests_handle_transaction_info_request .inc(); @@ -415,13 +416,13 @@ where &self, expected_seq: Option, checkpoint: &Option, - ) -> SuiResult { + ) -> IotaResult { let observed_seq = checkpoint.as_ref().map(|c| c.sequence_number); if let (Some(e), Some(o)) = (expected_seq, observed_seq) { fp_ensure!( e == o, - SuiError::from("Expected checkpoint number doesn't match with returned") + IotaError::from("Expected checkpoint number doesn't match with returned") ); } Ok(()) @@ -432,14 +433,14 @@ where request_content: bool, checkpoint: &Option, contents: &Option, - ) -> SuiResult { + ) -> IotaResult { match (request_content, checkpoint, contents) { // If content is requested, checkpoint is not None, but we are not getting any content, // it's an error. // If content is not requested, or checkpoint is None, yet we are still getting content, // it's an error. (true, Some(_), None) | (false, _, Some(_)) | (_, None, Some(_)) => Err( - SuiError::from("Checkpoint contents inconsistent with request"), + IotaError::from("Checkpoint contents inconsistent with request"), ), _ => Ok(()), } @@ -449,7 +450,7 @@ where &self, request: &CheckpointRequest, response: &CheckpointResponse, - ) -> SuiResult { + ) -> IotaResult { // Verify response data was correct for request let CheckpointResponse { checkpoint, @@ -471,7 +472,7 @@ where pub async fn handle_checkpoint( &self, request: CheckpointRequest, - ) -> Result { + ) -> Result { let resp = self .authority_client .handle_checkpoint(request.clone()) @@ -483,7 +484,7 @@ where Ok(resp) } - pub async fn handle_system_state_object(&self) -> Result { + pub async fn handle_system_state_object(&self) -> Result { self.authority_client .handle_system_state_object(SystemStateRequest { _unused: false }) .await diff --git a/crates/sui-core/src/scoring_decision.rs b/crates/iota-core/src/scoring_decision.rs similarity index 98% rename from crates/sui-core/src/scoring_decision.rs rename to crates/iota-core/src/scoring_decision.rs index 0ad798880ff..07e9d3a458f 100644 --- a/crates/sui-core/src/scoring_decision.rs +++ b/crates/iota-core/src/scoring_decision.rs @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, sync::Arc}; use arc_swap::ArcSwap; +use iota_types::base_types::AuthorityName; use narwhal_config::Stake; -use sui_types::base_types::AuthorityName; use tracing::debug; use crate::{ diff --git a/crates/sui-core/src/signature_verifier.rs b/crates/iota-core/src/signature_verifier.rs similarity index 97% rename from crates/sui-core/src/signature_verifier.rs rename to crates/iota-core/src/signature_verifier.rs index 48cd6cb6c48..e4098d8cc68 100644 --- a/crates/sui-core/src/signature_verifier.rs +++ b/crates/iota-core/src/signature_verifier.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{hash::Hash, sync::Arc}; @@ -10,22 +11,22 @@ use fastcrypto_zkp::bn254::{ }; use futures::pin_mut; use im::hashmap::HashMap as ImHashMap; -use itertools::izip; -use lru::LruCache; -use mysten_metrics::monitored_scope; -use parking_lot::{Mutex, MutexGuard, RwLock}; -use prometheus::{register_int_counter_with_registry, IntCounter, Registry}; -use shared_crypto::intent::Intent; -use sui_types::{ +use iota_types::{ committee::Committee, crypto::{AuthoritySignInfoTrait, VerificationObligation}, digests::{CertificateDigest, SenderSignedDataDigest, ZKLoginInputsDigest}, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, message_envelope::{AuthenticatedMessage, Message}, messages_checkpoint::SignedCheckpointSummary, signature::VerifyParams, transaction::{CertifiedTransaction, SenderSignedData, VerifiedCertificate}, }; +use itertools::izip; +use lru::LruCache; +use mysten_metrics::monitored_scope; +use parking_lot::{Mutex, MutexGuard, RwLock}; +use prometheus::{register_int_counter_with_registry, IntCounter, Registry}; +use shared_crypto::intent::Intent; use tap::TapFallible; use tokio::{ runtime::Handle, @@ -44,7 +45,7 @@ const BATCH_TIMEOUT_MS: Duration = Duration::from_millis(10); // loaded). const MAX_BATCH_SIZE: usize = 8; -type Sender = oneshot::Sender>; +type Sender = oneshot::Sender>; struct CertBuffer { certs: Vec, @@ -188,7 +189,7 @@ impl SignatureVerifier { &self, certs: Vec, checkpoints: Vec, - ) -> SuiResult { + ) -> IotaResult { let certs: Vec<_> = certs .into_iter() .filter(|cert| !self.certificate_cache.is_cached(&cert.certificate_digest())) @@ -207,7 +208,7 @@ impl SignatureVerifier { } /// Verifies one cert asynchronously, in a batch. - pub async fn verify_cert(&self, cert: CertifiedTransaction) -> SuiResult { + pub async fn verify_cert(&self, cert: CertifiedTransaction) -> IotaResult { let cert_digest = cert.certificate_digest(); if self.certificate_cache.is_cached(&cert_digest) { return Ok(VerifiedCertificate::new_unchecked(cert)); @@ -222,11 +223,11 @@ impl SignatureVerifier { pub async fn verify_cert_skip_cache( &self, cert: CertifiedTransaction, - ) -> SuiResult { + ) -> IotaResult { // this is the only innocent error we are likely to encounter - filter it before // we poison a whole batch. if cert.auth_sig().epoch != self.committee.epoch() { - return Err(SuiError::WrongEpoch { + return Err(IotaError::WrongEpoch { expected_epoch: self.committee.epoch(), actual_epoch: cert.auth_sig().epoch, }); @@ -238,7 +239,7 @@ impl SignatureVerifier { async fn verify_cert_inner( &self, cert: CertifiedTransaction, - ) -> SuiResult { + ) -> IotaResult { // Cancellation safety: we use parking_lot locks, which cannot be held across // awaits. Therefore once the queue has been taken by a thread, it is // guaranteed to process the queue and send all results before the @@ -355,7 +356,7 @@ impl SignatureVerifier { self.jwks.read().clone() } - pub fn verify_tx(&self, signed_tx: &SenderSignedData) -> SuiResult { + pub fn verify_tx(&self, signed_tx: &SenderSignedData) -> IotaResult { self.signed_data_cache.is_verified( signed_tx.full_message_digest(), || { @@ -494,7 +495,7 @@ pub fn batch_verify_all_certificates_and_checkpoints( committee: &Committee, certs: &[CertifiedTransaction], checkpoints: &[SignedCheckpointSummary], -) -> SuiResult { +) -> IotaResult { // certs.data() is assumed to be verified already by the caller. for ckpt in checkpoints { @@ -509,7 +510,7 @@ pub fn batch_verify_all_certificates_and_checkpoints( pub fn batch_verify_certificates( committee: &Committee, certs: &[CertifiedTransaction], -) -> Vec { +) -> Vec { // certs.data() is assumed to be verified already by the caller. let verify_params = VerifyParams::new( Default::default(), @@ -537,17 +538,17 @@ fn batch_verify( committee: &Committee, certs: &[CertifiedTransaction], checkpoints: &[SignedCheckpointSummary], -) -> SuiResult { +) -> IotaResult { let mut obligation = VerificationObligation::default(); for cert in certs { - let idx = obligation.add_message(cert.data(), cert.epoch(), Intent::sui_app(cert.scope())); + let idx = obligation.add_message(cert.data(), cert.epoch(), Intent::iota_app(cert.scope())); cert.auth_sig() .add_to_verification_obligation(committee, &mut obligation, idx)?; } for ckpt in checkpoints { - let idx = obligation.add_message(ckpt.data(), ckpt.epoch(), Intent::sui_app(ckpt.scope())); + let idx = obligation.add_message(ckpt.data(), ckpt.epoch(), Intent::iota_app(ckpt.scope())); ckpt.auth_sig() .add_to_verification_obligation(committee, &mut obligation, idx)?; } @@ -616,10 +617,10 @@ impl VerifiedDigestCache { }); } - pub fn is_verified(&self, digest: D, verify_callback: F, uncached_checks: G) -> SuiResult + pub fn is_verified(&self, digest: D, verify_callback: F, uncached_checks: G) -> IotaResult where - F: FnOnce() -> SuiResult, - G: FnOnce() -> SuiResult, + F: FnOnce() -> IotaResult, + G: FnOnce() -> IotaResult, { if !self.is_cached(&digest) { verify_callback()?; diff --git a/crates/sui-core/src/stake_aggregator.rs b/crates/iota-core/src/stake_aggregator.rs similarity index 97% rename from crates/sui-core/src/stake_aggregator.rs rename to crates/iota-core/src/stake_aggregator.rs index c3025ca756c..972ea576606 100644 --- a/crates/sui-core/src/stake_aggregator.rs +++ b/crates/iota-core/src/stake_aggregator.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -7,15 +8,15 @@ use std::{ sync::Arc, }; -use serde::Serialize; -use shared_crypto::intent::Intent; -use sui_types::{ +use iota_types::{ base_types::{AuthorityName, ConciseableName}, committee::{Committee, CommitteeTrait, StakeUnit}, crypto::{AuthorityQuorumSignInfo, AuthoritySignInfo, AuthoritySignInfoTrait}, - error::SuiError, + error::IotaError, message_envelope::{Envelope, Message}, }; +use serde::Serialize; +use shared_crypto::intent::Intent; use tracing::warn; /// StakeAggregator allows us to keep track of the total stake of a set of @@ -68,7 +69,7 @@ impl StakeAggregator { match self.data.entry(authority) { Entry::Occupied(oc) => { return InsertResult::Failed { - error: SuiError::StakeAggregatorRepeatedSigner { + error: IotaError::StakeAggregatorRepeatedSigner { signer: authority, conflicting_sig: oc.get() != &s, }, @@ -91,7 +92,7 @@ impl StakeAggregator { } } else { InsertResult::Failed { - error: SuiError::InvalidAuthenticator, + error: IotaError::InvalidAuthenticator, } } } @@ -133,7 +134,7 @@ impl StakeAggregator { let (data, sig) = envelope.into_data_and_sig(); if self.committee.epoch != sig.epoch { return InsertResult::Failed { - error: SuiError::WrongEpoch { + error: IotaError::WrongEpoch { expected_epoch: self.committee.epoch, actual_epoch: sig.epoch, }, @@ -148,7 +149,7 @@ impl StakeAggregator { Ok(aggregated) => { match aggregated.verify_secure( &data, - Intent::sui_app(T::SCOPE), + Intent::iota_app(T::SCOPE), self.committee(), ) { // In the happy path, the aggregated signature verifies ok and no need @@ -171,7 +172,7 @@ impl StakeAggregator { for (name, sig) in &self.data.clone() { if let Err(err) = sig.verify_secure( &data, - Intent::sui_app(T::SCOPE), + Intent::iota_app(T::SCOPE), self.committee(), ) { // TODO(joyqvq): Currently, the aggregator cannot do much @@ -214,7 +215,7 @@ impl StakeAggregator { pub enum InsertResult { QuorumReached(CertT), Failed { - error: SuiError, + error: IotaError, }, NotEnoughVotes { bad_votes: u64, diff --git a/crates/sui-core/src/state_accumulator.rs b/crates/iota-core/src/state_accumulator.rs similarity index 95% rename from crates/sui-core/src/state_accumulator.rs rename to crates/iota-core/src/state_accumulator.rs index 858a6210b5b..adfb7dbbd1e 100644 --- a/crates/sui-core/src/state_accumulator.rs +++ b/crates/iota-core/src/state_accumulator.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -7,21 +8,21 @@ use std::{ }; use fastcrypto::hash::MultisetHash; -use itertools::Itertools; -use mysten_metrics::monitored_scope; -use serde::Serialize; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ +use iota_protocol_config::ProtocolConfig; +use iota_types::{ accumulator::Accumulator, base_types::{ObjectID, ObjectRef, SequenceNumber, VersionNumber}, committee::EpochId, digests::{ObjectDigest, TransactionDigest}, effects::{TransactionEffects, TransactionEffectsAPI}, - error::SuiResult, + error::IotaResult, in_memory_storage::InMemoryStorage, messages_checkpoint::{CheckpointSequenceNumber, ECMHLiveObjectSetDigest}, storage::{ObjectKey, ObjectStore}, }; +use itertools::Itertools; +use mysten_metrics::monitored_scope; +use serde::Serialize; use tracing::debug; use crate::authority::{ @@ -40,23 +41,23 @@ pub trait AccumulatorStore: ObjectStore + Send + Sync { &self, object_id: &ObjectID, version: VersionNumber, - ) -> SuiResult>; + ) -> IotaResult>; fn get_root_state_accumulator_for_epoch( &self, epoch: EpochId, - ) -> SuiResult>; + ) -> IotaResult>; fn get_root_state_accumulator_for_highest_epoch( &self, - ) -> SuiResult>; + ) -> IotaResult>; fn insert_state_accumulator_for_epoch( &self, epoch: EpochId, checkpoint_seq_num: &CheckpointSequenceNumber, acc: &Accumulator, - ) -> SuiResult; + ) -> IotaResult; fn iter_live_object_set( &self, @@ -69,7 +70,7 @@ impl AccumulatorStore for InMemoryStorage { &self, _object_id: &ObjectID, _version: VersionNumber, - ) -> SuiResult> { + ) -> IotaResult> { unreachable!( "get_object_ref_prior_to_key is only called by accumulate_effects_v1, while InMemoryStorage is used by testing and genesis only, which always uses latest protocol " ) @@ -78,13 +79,13 @@ impl AccumulatorStore for InMemoryStorage { fn get_root_state_accumulator_for_epoch( &self, _epoch: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { unreachable!("not used for testing") } fn get_root_state_accumulator_for_highest_epoch( &self, - ) -> SuiResult> { + ) -> IotaResult> { unreachable!("not used for testing") } @@ -93,7 +94,7 @@ impl AccumulatorStore for InMemoryStorage { _epoch: EpochId, _checkpoint_seq_num: &CheckpointSequenceNumber, _acc: &Accumulator, - ) -> SuiResult { + ) -> IotaResult { unreachable!("not used for testing") } @@ -365,7 +366,7 @@ impl StateAccumulator { effects: Vec, checkpoint_seq_num: CheckpointSequenceNumber, epoch_store: Arc, - ) -> SuiResult { + ) -> IotaResult { let _scope = monitored_scope("AccumulateCheckpoint"); if let Some(acc) = epoch_store.get_state_hash_for_checkpoint(&checkpoint_seq_num)? { return Ok(acc); @@ -402,7 +403,7 @@ impl StateAccumulator { epoch: &EpochId, last_checkpoint_of_epoch: CheckpointSequenceNumber, epoch_store: Arc, - ) -> SuiResult { + ) -> IotaResult { if let Some((_checkpoint, acc)) = self.store.get_root_state_accumulator_for_epoch(*epoch)? { return Ok(acc); } @@ -501,7 +502,7 @@ impl StateAccumulator { epoch: &EpochId, last_checkpoint_of_epoch: CheckpointSequenceNumber, epoch_store: Arc, - ) -> SuiResult { + ) -> IotaResult { Ok(self .accumulate_epoch(epoch, last_checkpoint_of_epoch, epoch_store) .await? diff --git a/crates/iota-core/src/storage.rs b/crates/iota-core/src/storage.rs new file mode 100644 index 00000000000..a7c9340e51a --- /dev/null +++ b/crates/iota-core/src/storage.rs @@ -0,0 +1,338 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::Arc; + +use iota_types::{ + base_types::TransactionDigest, + committee::{Committee, EpochId}, + digests::TransactionEventsDigest, + effects::{TransactionEffects, TransactionEvents}, + error::IotaError, + messages_checkpoint::{ + CheckpointContentsDigest, CheckpointDigest, CheckpointSequenceNumber, EndOfEpochData, + FullCheckpointContents, VerifiedCheckpoint, VerifiedCheckpointContents, + }, + object::Object, + storage::{error::Error as StorageError, ObjectKey, ObjectStore, ReadStore, WriteStore}, + transaction::VerifiedTransaction, +}; +use parking_lot::Mutex; + +use crate::{ + checkpoints::CheckpointStore, + epoch::committee_store::CommitteeStore, + execution_cache::{ExecutionCacheRead, StateSyncAPI}, +}; + +#[derive(Clone)] +pub struct RocksDbStore { + // Note: All three of these Arcs point to the same object, + // but we need to store them separately to satisfy the trait bounds. + execution_cache: Arc, + object_store: Arc, + state_sync_store: Arc, + + committee_store: Arc, + checkpoint_store: Arc, + // in memory checkpoint watermark sequence numbers + highest_verified_checkpoint: Arc>>, + highest_synced_checkpoint: Arc>>, +} + +impl RocksDbStore { + pub fn new( + execution_cache: Arc, + committee_store: Arc, + checkpoint_store: Arc, + ) -> Self { + Self { + execution_cache: execution_cache.clone(), + object_store: execution_cache.clone(), + state_sync_store: execution_cache.clone(), + committee_store, + checkpoint_store, + highest_verified_checkpoint: Arc::new(Mutex::new(None)), + highest_synced_checkpoint: Arc::new(Mutex::new(None)), + } + } + + pub fn get_objects(&self, object_keys: &[ObjectKey]) -> Result>, IotaError> { + self.execution_cache.multi_get_objects_by_key(object_keys) + } + + pub fn get_last_executed_checkpoint(&self) -> Result, IotaError> { + Ok(self.checkpoint_store.get_highest_executed_checkpoint()?) + } +} + +impl ReadStore for RocksDbStore { + fn get_checkpoint_by_digest( + &self, + digest: &CheckpointDigest, + ) -> Result, StorageError> { + self.checkpoint_store + .get_checkpoint_by_digest(digest) + .map_err(Into::into) + } + + fn get_checkpoint_by_sequence_number( + &self, + sequence_number: CheckpointSequenceNumber, + ) -> Result, StorageError> { + self.checkpoint_store + .get_checkpoint_by_sequence_number(sequence_number) + .map_err(Into::into) + } + + fn get_highest_verified_checkpoint(&self) -> Result { + self.checkpoint_store + .get_highest_verified_checkpoint() + .map(|maybe_checkpoint| { + maybe_checkpoint + .expect("storage should have been initialized with genesis checkpoint") + }) + .map_err(Into::into) + } + + fn get_highest_synced_checkpoint(&self) -> Result { + self.checkpoint_store + .get_highest_synced_checkpoint() + .map(|maybe_checkpoint| { + maybe_checkpoint + .expect("storage should have been initialized with genesis checkpoint") + }) + .map_err(Into::into) + } + + fn get_lowest_available_checkpoint(&self) -> Result { + self.checkpoint_store + .get_highest_pruned_checkpoint_seq_number() + .map(|seq| seq + 1) + .map_err(Into::into) + } + + fn get_full_checkpoint_contents_by_sequence_number( + &self, + sequence_number: CheckpointSequenceNumber, + ) -> Result, StorageError> { + self.checkpoint_store + .get_full_checkpoint_contents_by_sequence_number(sequence_number) + .map_err(Into::into) + } + + fn get_full_checkpoint_contents( + &self, + digest: &CheckpointContentsDigest, + ) -> Result, StorageError> { + // First look to see if we saved the complete contents already. + if let Some(seq_num) = self + .checkpoint_store + .get_sequence_number_by_contents_digest(digest) + .map_err(iota_types::storage::error::Error::custom)? + { + let contents = self + .checkpoint_store + .get_full_checkpoint_contents_by_sequence_number(seq_num) + .map_err(iota_types::storage::error::Error::custom)?; + if contents.is_some() { + return Ok(contents); + } + } + + // Otherwise gather it from the individual components. + // Note we can't insert the constructed contents into `full_checkpoint_content`, + // because it needs to be inserted along with + // `checkpoint_sequence_by_contents_digest` and `checkpoint_content`. + // However at this point it's likely we don't know the corresponding + // sequence number yet. + self.checkpoint_store + .get_checkpoint_contents(digest) + .map_err(iota_types::storage::error::Error::custom)? + .map(|contents| { + let mut transactions = Vec::with_capacity(contents.size()); + for tx in contents.iter() { + if let (Some(t), Some(e)) = ( + self.get_transaction(&tx.transaction)?, + self.execution_cache + .get_effects(&tx.effects) + .map_err(iota_types::storage::error::Error::custom)?, + ) { + transactions.push(iota_types::base_types::ExecutionData::new( + (*t).clone().into_inner(), + e, + )) + } else { + return Result::< + Option, + iota_types::storage::error::Error, + >::Ok(None); + } + } + Ok(Some( + FullCheckpointContents::from_contents_and_execution_data( + contents, + transactions.into_iter(), + ), + )) + }) + .transpose() + .map(|contents| contents.flatten()) + .map_err(iota_types::storage::error::Error::custom) + } + + fn get_committee( + &self, + epoch: EpochId, + ) -> Result>, iota_types::storage::error::Error> { + Ok(self.committee_store.get_committee(&epoch).unwrap()) + } + + fn get_transaction( + &self, + digest: &TransactionDigest, + ) -> Result>, StorageError> { + self.execution_cache + .get_transaction_block(digest) + .map_err(StorageError::custom) + } + + fn get_transaction_effects( + &self, + digest: &TransactionDigest, + ) -> Result, StorageError> { + self.execution_cache + .get_executed_effects(digest) + .map_err(StorageError::custom) + } + + fn get_events( + &self, + digest: &TransactionEventsDigest, + ) -> Result, StorageError> { + self.execution_cache + .get_events(digest) + .map_err(StorageError::custom) + } + + fn get_latest_checkpoint(&self) -> iota_types::storage::error::Result { + self.checkpoint_store + .get_latest_certified_checkpoint() + .ok_or_else(|| { + iota_types::storage::error::Error::missing("unable to get latest checkpoint") + }) + } + + fn get_checkpoint_contents_by_digest( + &self, + digest: &CheckpointContentsDigest, + ) -> iota_types::storage::error::Result< + Option, + > { + self.checkpoint_store + .get_checkpoint_contents(digest) + .map_err(iota_types::storage::error::Error::custom) + } + + fn get_checkpoint_contents_by_sequence_number( + &self, + _sequence_number: CheckpointSequenceNumber, + ) -> iota_types::storage::error::Result< + Option, + > { + todo!() + } +} + +impl ObjectStore for RocksDbStore { + fn get_object( + &self, + object_id: &iota_types::base_types::ObjectID, + ) -> iota_types::storage::error::Result> { + self.object_store.get_object(object_id) + } + + fn get_object_by_key( + &self, + object_id: &iota_types::base_types::ObjectID, + version: iota_types::base_types::VersionNumber, + ) -> iota_types::storage::error::Result> { + self.object_store.get_object_by_key(object_id, version) + } +} + +impl WriteStore for RocksDbStore { + fn insert_checkpoint( + &self, + checkpoint: &VerifiedCheckpoint, + ) -> Result<(), iota_types::storage::error::Error> { + if let Some(EndOfEpochData { + next_epoch_committee, + .. + }) = checkpoint.end_of_epoch_data.as_ref() + { + let next_committee = next_epoch_committee.iter().cloned().collect(); + let committee = + Committee::new(checkpoint.epoch().checked_add(1).unwrap(), next_committee); + self.insert_committee(committee)?; + } + + self.checkpoint_store + .insert_verified_checkpoint(checkpoint) + .map_err(Into::into) + } + + fn update_highest_synced_checkpoint( + &self, + checkpoint: &VerifiedCheckpoint, + ) -> Result<(), iota_types::storage::error::Error> { + let mut locked = self.highest_synced_checkpoint.lock(); + if locked.is_some() && locked.unwrap() >= checkpoint.sequence_number { + return Ok(()); + } + self.checkpoint_store + .update_highest_synced_checkpoint(checkpoint) + .map_err(iota_types::storage::error::Error::custom)?; + *locked = Some(checkpoint.sequence_number); + Ok(()) + } + + fn update_highest_verified_checkpoint( + &self, + checkpoint: &VerifiedCheckpoint, + ) -> Result<(), iota_types::storage::error::Error> { + let mut locked = self.highest_verified_checkpoint.lock(); + if locked.is_some() && locked.unwrap() >= checkpoint.sequence_number { + return Ok(()); + } + self.checkpoint_store + .update_highest_verified_checkpoint(checkpoint) + .map_err(iota_types::storage::error::Error::custom)?; + *locked = Some(checkpoint.sequence_number); + Ok(()) + } + + fn insert_checkpoint_contents( + &self, + checkpoint: &VerifiedCheckpoint, + contents: VerifiedCheckpointContents, + ) -> Result<(), iota_types::storage::error::Error> { + self.state_sync_store + .multi_insert_transaction_and_effects(contents.transactions()) + .map_err(iota_types::storage::error::Error::custom)?; + self.checkpoint_store + .insert_verified_checkpoint_contents(checkpoint, contents) + .map_err(Into::into) + } + + fn insert_committee( + &self, + new_committee: Committee, + ) -> Result<(), iota_types::storage::error::Error> { + self.committee_store + .insert_new_committee(&new_committee) + .unwrap(); + Ok(()) + } +} diff --git a/crates/sui-core/src/streamer.rs b/crates/iota-core/src/streamer.rs similarity index 94% rename from crates/sui-core/src/streamer.rs rename to crates/iota-core/src/streamer.rs index 844619187d7..eb635f90900 100644 --- a/crates/sui-core/src/streamer.rs +++ b/crates/iota-core/src/streamer.rs @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, fmt::Debug, sync::Arc}; use futures::Stream; +use iota_json_rpc_types::Filter; +use iota_types::{base_types::ObjectID, error::IotaError}; use mysten_metrics::{metered_channel::Sender, spawn_monitored_task}; use parking_lot::RwLock; use prometheus::Registry; -use sui_json_rpc_types::Filter; -use sui_types::{base_types::ObjectID, error::SuiError}; use tokio::sync::mpsc; use tokio_stream::wrappers::ReceiverStream; use tracing::{debug, warn}; @@ -134,11 +135,11 @@ where ReceiverStream::new(rx) } - pub async fn send(&self, data: T) -> Result<(), SuiError> { + pub async fn send(&self, data: T) -> Result<(), IotaError> { self.streamer_queue .send(data) .await - .map_err(|e| SuiError::FailedToDispatchSubscription { + .map_err(|e| IotaError::FailedToDispatchSubscription { error: e.to_string(), }) } diff --git a/crates/sui-core/src/subscription_handler.rs b/crates/iota-core/src/subscription_handler.rs similarity index 82% rename from crates/sui-core/src/subscription_handler.rs rename to crates/iota-core/src/subscription_handler.rs index d29e3cdab2a..a03d09ce681 100644 --- a/crates/sui-core/src/subscription_handler.rs +++ b/crates/iota-core/src/subscription_handler.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; +use iota_json_rpc_types::{ + EffectsWithInput, EventFilter, IotaEvent, IotaTransactionBlockEffects, + IotaTransactionBlockEffectsAPI, IotaTransactionBlockEvents, TransactionFilter, +}; +use iota_types::{error::IotaResult, transaction::TransactionData}; use prometheus::{ register_int_counter_vec_with_registry, register_int_gauge_vec_with_registry, IntCounterVec, IntGaugeVec, Registry, }; -use sui_json_rpc_types::{ - EffectsWithInput, EventFilter, SuiEvent, SuiTransactionBlockEffects, - SuiTransactionBlockEffectsAPI, SuiTransactionBlockEvents, TransactionFilter, -}; -use sui_types::{error::SuiResult, transaction::TransactionData}; use tokio_stream::Stream; use tracing::{error, instrument, trace}; @@ -58,8 +59,9 @@ impl SubscriptionMetrics { } pub struct SubscriptionHandler { - event_streamer: Streamer, - transaction_streamer: Streamer, + event_streamer: Streamer, + transaction_streamer: + Streamer, } impl SubscriptionHandler { @@ -77,9 +79,9 @@ impl SubscriptionHandler { pub async fn process_tx( &self, input: &TransactionData, - effects: &SuiTransactionBlockEffects, - events: &SuiTransactionBlockEvents, - ) -> SuiResult { + effects: &IotaTransactionBlockEffects, + events: &IotaTransactionBlockEvents, + ) -> IotaResult { trace!( num_events = events.data.len(), tx_digest =? effects.transaction_digest(), @@ -106,14 +108,14 @@ impl SubscriptionHandler { Ok(()) } - pub fn subscribe_events(&self, filter: EventFilter) -> impl Stream { + pub fn subscribe_events(&self, filter: EventFilter) -> impl Stream { self.event_streamer.subscribe(filter) } pub fn subscribe_transactions( &self, filter: TransactionFilter, - ) -> impl Stream { + ) -> impl Stream { self.transaction_streamer.subscribe(filter) } } diff --git a/crates/sui-core/src/test_authority_clients.rs b/crates/iota-core/src/test_authority_clients.rs similarity index 80% rename from crates/sui-core/src/test_authority_clients.rs rename to crates/iota-core/src/test_authority_clients.rs index bff472f82ef..6854deb34af 100644 --- a/crates/sui-core/src/test_authority_clients.rs +++ b/crates/iota-core/src/test_authority_clients.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -8,12 +9,12 @@ use std::{ }; use async_trait::async_trait; -use mysten_metrics::spawn_monitored_task; -use sui_config::genesis::Genesis; -use sui_types::{ +use iota_config::genesis::Genesis; +use iota_types::{ crypto::AuthorityKeyPair, effects::{TransactionEffectsAPI, TransactionEvents}, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, + iota_system_state::IotaSystemState, messages_checkpoint::{ CheckpointRequest, CheckpointRequestV2, CheckpointResponse, CheckpointResponseV2, }, @@ -21,9 +22,9 @@ use sui_types::{ HandleCertificateResponseV2, HandleTransactionResponse, ObjectInfoRequest, ObjectInfoResponse, SystemStateRequest, TransactionInfoRequest, TransactionInfoResponse, }, - sui_system_state::SuiSystemState, transaction::{CertifiedTransaction, Transaction, VerifiedTransaction}, }; +use mysten_metrics::spawn_monitored_task; use crate::{ authority::{test_authority_builder::TestAuthorityBuilder, AuthorityState}, @@ -56,9 +57,9 @@ impl AuthorityAPI for LocalAuthorityClient { async fn handle_transaction( &self, transaction: Transaction, - ) -> Result { + ) -> Result { if self.fault_config.fail_before_handle_transaction { - return Err(SuiError::from("Mock error before handle_transaction")); + return Err(IotaError::from("Mock error before handle_transaction")); } let state = self.state.clone(); let epoch_store = self.state.load_epoch_store_one_call_per_task(); @@ -68,12 +69,12 @@ impl AuthorityAPI for LocalAuthorityClient { .map(|_| VerifiedTransaction::new_from_verified(transaction))?; let result = state.handle_transaction(&epoch_store, transaction).await; if self.fault_config.fail_after_handle_transaction { - return Err(SuiError::GenericAuthorityError { + return Err(IotaError::GenericAuthorityError { error: "Mock error after handle_transaction".to_owned(), }); } if self.fault_config.overload_retry_after_handle_transaction { - return Err(SuiError::ValidatorOverloadedRetryAfter { + return Err(IotaError::ValidatorOverloadedRetryAfter { retry_after_secs: 0, }); } @@ -83,7 +84,7 @@ impl AuthorityAPI for LocalAuthorityClient { async fn handle_certificate_v2( &self, certificate: CertifiedTransaction, - ) -> Result { + ) -> Result { let state = self.state.clone(); let fault_config = self.fault_config; spawn_monitored_task!(Self::handle_certificate(state, certificate, fault_config)) @@ -94,7 +95,7 @@ impl AuthorityAPI for LocalAuthorityClient { async fn handle_object_info_request( &self, request: ObjectInfoRequest, - ) -> Result { + ) -> Result { let state = self.state.clone(); state.handle_object_info_request(request).await } @@ -103,7 +104,7 @@ impl AuthorityAPI for LocalAuthorityClient { async fn handle_transaction_info_request( &self, request: TransactionInfoRequest, - ) -> Result { + ) -> Result { let state = self.state.clone(); state.handle_transaction_info_request(request).await } @@ -111,7 +112,7 @@ impl AuthorityAPI for LocalAuthorityClient { async fn handle_checkpoint( &self, request: CheckpointRequest, - ) -> Result { + ) -> Result { let state = self.state.clone(); state.handle_checkpoint_request(&request) @@ -120,7 +121,7 @@ impl AuthorityAPI for LocalAuthorityClient { async fn handle_checkpoint_v2( &self, request: CheckpointRequestV2, - ) -> Result { + ) -> Result { let state = self.state.clone(); state.handle_checkpoint_request_v2(&request) @@ -129,8 +130,8 @@ impl AuthorityAPI for LocalAuthorityClient { async fn handle_system_state_object( &self, _request: SystemStateRequest, - ) -> Result { - self.state.get_sui_system_state_object_for_testing() + ) -> Result { + self.state.get_iota_system_state_object_for_testing() } } @@ -161,9 +162,9 @@ impl LocalAuthorityClient { state: Arc, certificate: CertifiedTransaction, fault_config: LocalAuthorityClientFaultConfig, - ) -> Result { + ) -> Result { if fault_config.fail_before_handle_confirmation { - return Err(SuiError::GenericAuthorityError { + return Err(IotaError::GenericAuthorityError { error: "Mock error before handle_confirmation_transaction".to_owned(), }); } @@ -195,7 +196,7 @@ impl LocalAuthorityClient { }; if fault_config.fail_after_handle_confirmation { - return Err(SuiError::GenericAuthorityError { + return Err(IotaError::GenericAuthorityError { error: "Mock error after handle_confirmation_transaction".to_owned(), }); } @@ -212,7 +213,7 @@ impl LocalAuthorityClient { pub struct MockAuthorityApi { delay: Duration, count: Arc>, - handle_object_info_request_result: Option>, + handle_object_info_request_result: Option>, } impl MockAuthorityApi { @@ -224,18 +225,18 @@ impl MockAuthorityApi { } } - pub fn set_handle_object_info_request(&mut self, result: SuiResult) { + pub fn set_handle_object_info_request(&mut self, result: IotaResult) { self.handle_object_info_request_result = Some(result); } } #[async_trait] impl AuthorityAPI for MockAuthorityApi { - /// Initiate a new transaction to a Sui or Primary account. + /// Initiate a new transaction to a Iota or Primary account. async fn handle_transaction( &self, _transaction: Transaction, - ) -> Result { + ) -> Result { unimplemented!(); } @@ -243,7 +244,7 @@ impl AuthorityAPI for MockAuthorityApi { async fn handle_certificate_v2( &self, _certificate: CertifiedTransaction, - ) -> Result { + ) -> Result { unimplemented!() } @@ -251,7 +252,7 @@ impl AuthorityAPI for MockAuthorityApi { async fn handle_object_info_request( &self, _request: ObjectInfoRequest, - ) -> Result { + ) -> Result { self.handle_object_info_request_result.clone().unwrap() } @@ -259,7 +260,7 @@ impl AuthorityAPI for MockAuthorityApi { async fn handle_transaction_info_request( &self, request: TransactionInfoRequest, - ) -> Result { + ) -> Result { let count = { let mut count = self.count.lock().unwrap(); *count += 1; @@ -271,7 +272,7 @@ impl AuthorityAPI for MockAuthorityApi { tokio::time::sleep(self.delay).await; } - Err(SuiError::TransactionNotFound { + Err(IotaError::TransactionNotFound { digest: request.transaction_digest, }) } @@ -279,29 +280,29 @@ impl AuthorityAPI for MockAuthorityApi { async fn handle_checkpoint( &self, _request: CheckpointRequest, - ) -> Result { + ) -> Result { unimplemented!(); } async fn handle_checkpoint_v2( &self, _request: CheckpointRequestV2, - ) -> Result { + ) -> Result { unimplemented!(); } async fn handle_system_state_object( &self, _request: SystemStateRequest, - ) -> Result { + ) -> Result { unimplemented!(); } } #[derive(Clone)] pub struct HandleTransactionTestAuthorityClient { - pub tx_info_resp_to_return: SuiResult, - pub cert_resp_to_return: SuiResult, + pub tx_info_resp_to_return: IotaResult, + pub cert_resp_to_return: IotaResult, // If set, sleep for this duration before responding to a request. // This is useful in testing a timeout scenario. pub sleep_duration_before_responding: Option, @@ -312,7 +313,7 @@ impl AuthorityAPI for HandleTransactionTestAuthorityClient { async fn handle_transaction( &self, _transaction: Transaction, - ) -> Result { + ) -> Result { if let Some(duration) = self.sleep_duration_before_responding { tokio::time::sleep(duration).await; } @@ -322,7 +323,7 @@ impl AuthorityAPI for HandleTransactionTestAuthorityClient { async fn handle_certificate_v2( &self, _certificate: CertifiedTransaction, - ) -> Result { + ) -> Result { if let Some(duration) = self.sleep_duration_before_responding { tokio::time::sleep(duration).await; } @@ -332,35 +333,35 @@ impl AuthorityAPI for HandleTransactionTestAuthorityClient { async fn handle_object_info_request( &self, _request: ObjectInfoRequest, - ) -> Result { + ) -> Result { unimplemented!() } async fn handle_transaction_info_request( &self, _request: TransactionInfoRequest, - ) -> Result { + ) -> Result { unimplemented!() } async fn handle_checkpoint( &self, _request: CheckpointRequest, - ) -> Result { + ) -> Result { unimplemented!() } async fn handle_checkpoint_v2( &self, _request: CheckpointRequestV2, - ) -> Result { + ) -> Result { unimplemented!() } async fn handle_system_state_object( &self, _request: SystemStateRequest, - ) -> Result { + ) -> Result { unimplemented!() } } @@ -368,8 +369,8 @@ impl AuthorityAPI for HandleTransactionTestAuthorityClient { impl HandleTransactionTestAuthorityClient { pub fn new() -> Self { Self { - tx_info_resp_to_return: Err(SuiError::Unknown("".to_string())), - cert_resp_to_return: Err(SuiError::Unknown("".to_string())), + tx_info_resp_to_return: Err(IotaError::Unknown("".to_string())), + cert_resp_to_return: Err(IotaError::Unknown("".to_string())), sleep_duration_before_responding: None, } } @@ -378,24 +379,24 @@ impl HandleTransactionTestAuthorityClient { self.tx_info_resp_to_return = Ok(resp); } - pub fn set_tx_info_response_error(&mut self, error: SuiError) { + pub fn set_tx_info_response_error(&mut self, error: IotaError) { self.tx_info_resp_to_return = Err(error); } pub fn reset_tx_info_response(&mut self) { - self.tx_info_resp_to_return = Err(SuiError::Unknown("".to_string())); + self.tx_info_resp_to_return = Err(IotaError::Unknown("".to_string())); } pub fn set_cert_resp_to_return(&mut self, resp: HandleCertificateResponseV2) { self.cert_resp_to_return = Ok(resp); } - pub fn set_cert_resp_to_return_error(&mut self, error: SuiError) { + pub fn set_cert_resp_to_return_error(&mut self, error: IotaError) { self.cert_resp_to_return = Err(error); } pub fn reset_cert_response(&mut self) { - self.cert_resp_to_return = Err(SuiError::Unknown("".to_string())); + self.cert_resp_to_return = Err(IotaError::Unknown("".to_string())); } pub fn set_sleep_duration_before_responding(&mut self, duration: Duration) { diff --git a/crates/iota-core/src/test_utils.rs b/crates/iota-core/src/test_utils.rs new file mode 100644 index 00000000000..dd50ff3eaf8 --- /dev/null +++ b/crates/iota-core/src/test_utils.rs @@ -0,0 +1,473 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{BTreeMap, HashMap}, + path::PathBuf, + sync::Arc, + time::Duration, +}; + +use fastcrypto::{hash::MultisetHash, traits::KeyPair}; +use futures::future::join_all; +use iota_config::{genesis::Genesis, local_ip_utils, node::AuthorityOverloadConfig}; +use iota_framework::BuiltInFramework; +use iota_genesis_builder::validator_info::ValidatorInfo; +use iota_macros::nondeterministic; +use iota_move_build::{BuildConfig, CompiledPackage, IotaPackageHooks}; +use iota_protocol_config::ProtocolConfig; +use iota_types::{ + base_types::{ + random_object_ref, AuthorityName, ExecutionDigests, IotaAddress, ObjectID, ObjectRef, + TransactionDigest, + }, + committee::Committee, + crypto::{ + generate_proof_of_possession, get_key_pair, AccountKeyPair, AuthorityKeyPair, + AuthorityPublicKeyBytes, AuthoritySignInfo, AuthoritySignature, IotaKeyPair, + NetworkKeyPair, Signer, + }, + effects::{SignedTransactionEffects, TestEffectsBuilder}, + error::IotaError, + message_envelope::Message, + object::Object, + transaction::{ + CallArg, CertifiedTransaction, ObjectArg, SignedTransaction, Transaction, TransactionData, + TEST_ONLY_GAS_UNIT_FOR_TRANSFER, + }, + utils::{create_fake_transaction, to_sender_signed_transaction}, +}; +use move_core_types::{account_address::AccountAddress, ident_str}; +use prometheus::Registry; +use shared_crypto::intent::{Intent, IntentScope}; +use tokio::time::timeout; +use tracing::{info, warn}; + +use crate::{ + authority::{test_authority_builder::TestAuthorityBuilder, AuthorityState}, + authority_aggregator::{AuthorityAggregator, TimeoutConfig}, + epoch::committee_store::CommitteeStore, + state_accumulator::StateAccumulator, + test_authority_clients::LocalAuthorityClient, +}; + +const WAIT_FOR_TX_TIMEOUT: Duration = Duration::from_secs(15); + +pub async fn send_and_confirm_transaction( + authority: &AuthorityState, + fullnode: Option<&AuthorityState>, + transaction: Transaction, +) -> Result<(CertifiedTransaction, SignedTransactionEffects), IotaError> { + // Make the initial request + let epoch_store = authority.load_epoch_store_one_call_per_task(); + let transaction = epoch_store.verify_transaction(transaction)?; + let response = authority + .handle_transaction(&epoch_store, transaction.clone()) + .await?; + let vote = response.status.into_signed_for_testing(); + + // Collect signatures from a quorum of authorities + let committee = authority.clone_committee_for_testing(); + let certificate = + CertifiedTransaction::new(transaction.into_message(), vec![vote.clone()], &committee) + .unwrap() + .verify_authenticated(&committee, &Default::default()) + .unwrap(); + + // Submit the confirmation. *Now* execution actually happens, and it should fail + // when we try to look up our dummy module. we unfortunately don't get a + // very descriptive error message, but we can at least see that something went + // wrong inside the VM + // + // We also check the incremental effects of the transaction on the live object + // set against StateAccumulator for testing and regression detection + let state_acc = StateAccumulator::new(authority.get_execution_cache().clone()); + let include_wrapped_tombstone = !authority + .epoch_store_for_testing() + .protocol_config() + .simplified_unwrap_then_delete(); + let mut state = state_acc.accumulate_live_object_set(include_wrapped_tombstone); + let (result, _execution_error_opt) = authority.try_execute_for_test(&certificate).await?; + let state_after = state_acc.accumulate_live_object_set(include_wrapped_tombstone); + let effects_acc = state_acc.accumulate_effects( + vec![result.inner().data().clone()], + epoch_store.protocol_config(), + ); + state.union(&effects_acc); + + assert_eq!(state_after.digest(), state.digest()); + + if let Some(fullnode) = fullnode { + fullnode.try_execute_for_test(&certificate).await?; + } + Ok((certificate.into_inner(), result.into_inner())) +} + +// note: clippy is confused about this being dead - it appears to only be used +// in cfg(test), but adding #[cfg(test)] causes other targets to fail +#[allow(dead_code)] +pub(crate) fn init_state_parameters_from_rng(rng: &mut R) -> (Genesis, AuthorityKeyPair) +where + R: rand::CryptoRng + rand::RngCore, +{ + let dir = nondeterministic!(tempfile::TempDir::new().unwrap()); + let network_config = iota_swarm_config::network_config_builder::ConfigBuilder::new(&dir) + .rng(rng) + .build(); + let genesis = network_config.genesis; + let authority_key = network_config.validator_configs[0] + .protocol_key_pair() + .copy(); + + (genesis, authority_key) +} + +pub async fn wait_for_tx(digest: TransactionDigest, state: Arc) { + match timeout( + WAIT_FOR_TX_TIMEOUT, + state + .get_cache_reader() + .notify_read_executed_effects(&[digest]), + ) + .await + { + Ok(_) => info!(?digest, "digest found"), + Err(e) => { + warn!(?digest, "digest not found!"); + panic!("timed out waiting for effects of digest! {e}"); + } + } +} + +pub async fn wait_for_all_txes(digests: Vec, state: Arc) { + match timeout( + WAIT_FOR_TX_TIMEOUT, + state + .get_cache_reader() + .notify_read_executed_effects(&digests), + ) + .await + { + Ok(_) => info!(?digests, "all digests found"), + Err(e) => { + warn!(?digests, "some digests not found!"); + panic!("timed out waiting for effects of digests! {e}"); + } + } +} + +pub fn create_fake_cert_and_effect_digest<'a>( + signers: impl Iterator< + Item = ( + &'a AuthorityName, + &'a (dyn Signer + Send + Sync), + ), + >, + committee: &Committee, +) -> (ExecutionDigests, CertifiedTransaction) { + let transaction = create_fake_transaction(); + let cert = CertifiedTransaction::new( + transaction.data().clone(), + signers + .map(|(name, signer)| { + AuthoritySignInfo::new( + committee.epoch, + transaction.data(), + Intent::iota_app(IntentScope::SenderSignedTransaction), + *name, + signer, + ) + }) + .collect(), + committee, + ) + .unwrap(); + let effects = TestEffectsBuilder::new(transaction.data()).build(); + ( + ExecutionDigests::new(*transaction.digest(), effects.digest()), + cert, + ) +} + +pub fn compile_basics_package() -> CompiledPackage { + compile_example_package("../../iota_programmability/examples/basics") +} + +pub fn compile_managed_coin_package() -> CompiledPackage { + compile_example_package("../../crates/iota-core/src/unit_tests/data/managed_coin") +} + +pub fn compile_example_package(relative_path: &str) -> CompiledPackage { + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push(relative_path); + + BuildConfig::new_for_testing().build(path).unwrap() +} + +async fn init_genesis( + committee_size: usize, + mut genesis_objects: Vec, +) -> ( + Genesis, + Vec<(AuthorityPublicKeyBytes, AuthorityKeyPair)>, + ObjectID, +) { + // add object_basics package object to genesis + let modules: Vec<_> = compile_basics_package().get_modules().cloned().collect(); + let genesis_move_packages: Vec<_> = BuiltInFramework::genesis_move_packages().collect(); + let pkg = Object::new_package( + &modules, + TransactionDigest::genesis_marker(), + ProtocolConfig::get_for_max_version_UNSAFE().max_move_package_size(), + &genesis_move_packages, + ) + .unwrap(); + let pkg_id = pkg.id(); + genesis_objects.push(pkg); + + let mut builder = iota_genesis_builder::Builder::new().add_objects(genesis_objects); + let mut key_pairs = Vec::new(); + for i in 0..committee_size { + let key_pair: AuthorityKeyPair = get_key_pair().1; + let authority_name = key_pair.public().into(); + let worker_key_pair: NetworkKeyPair = get_key_pair().1; + let worker_name = worker_key_pair.public().clone(); + let account_key_pair: IotaKeyPair = get_key_pair::().1.into(); + let network_key_pair: NetworkKeyPair = get_key_pair().1; + let validator_info = ValidatorInfo { + name: format!("validator-{i}"), + protocol_key: authority_name, + worker_key: worker_name, + account_address: IotaAddress::from(&account_key_pair.public()), + network_key: network_key_pair.public().clone(), + gas_price: 1, + commission_rate: 0, + network_address: local_ip_utils::new_local_tcp_address_for_testing(), + p2p_address: local_ip_utils::new_local_udp_address_for_testing(), + narwhal_primary_address: local_ip_utils::new_local_udp_address_for_testing(), + narwhal_worker_address: local_ip_utils::new_local_udp_address_for_testing(), + description: String::new(), + image_url: String::new(), + project_url: String::new(), + }; + let pop = generate_proof_of_possession(&key_pair, (&account_key_pair.public()).into()); + builder = builder.add_validator(validator_info, pop); + key_pairs.push((authority_name, key_pair)); + } + for (_, key) in &key_pairs { + builder = builder.add_validator_signature(key); + } + let genesis = builder.build(); + (genesis, key_pairs, pkg_id) +} + +pub async fn init_local_authorities( + committee_size: usize, + genesis_objects: Vec, +) -> ( + AuthorityAggregator, + Vec>, + Genesis, + ObjectID, +) { + let (genesis, key_pairs, framework) = init_genesis(committee_size, genesis_objects).await; + let authorities = join_all(key_pairs.iter().map(|(_, key_pair)| { + TestAuthorityBuilder::new() + .with_genesis_and_keypair(&genesis, key_pair) + .build() + })) + .await; + let aggregator = init_local_authorities_with_genesis(&genesis, authorities.clone()).await; + (aggregator, authorities, genesis, framework) +} + +pub async fn init_local_authorities_with_overload_thresholds( + committee_size: usize, + genesis_objects: Vec, + overload_thresholds: AuthorityOverloadConfig, +) -> ( + AuthorityAggregator, + Vec>, + Genesis, + ObjectID, +) { + let (genesis, key_pairs, framework) = init_genesis(committee_size, genesis_objects).await; + let authorities = join_all(key_pairs.iter().map(|(_, key_pair)| { + TestAuthorityBuilder::new() + .with_genesis_and_keypair(&genesis, key_pair) + .with_authority_overload_config(overload_thresholds.clone()) + .build() + })) + .await; + let aggregator = init_local_authorities_with_genesis(&genesis, authorities.clone()).await; + (aggregator, authorities, genesis, framework) +} + +pub async fn init_local_authorities_with_genesis( + genesis: &Genesis, + authorities: Vec>, +) -> AuthorityAggregator { + telemetry_subscribers::init_for_testing(); + let committee = genesis.committee().unwrap(); + + let mut clients = BTreeMap::new(); + for state in authorities { + let name = state.name; + let client = LocalAuthorityClient::new_from_authority(state); + clients.insert(name, client); + } + let timeouts = TimeoutConfig { + pre_quorum_timeout: Duration::from_secs(5), + post_quorum_timeout: Duration::from_secs(5), + serial_authority_request_interval: Duration::from_secs(1), + }; + let committee_store = Arc::new(CommitteeStore::new_for_testing(&committee)); + AuthorityAggregator::new_with_timeouts( + committee, + committee_store, + clients, + &Registry::new(), + Arc::new(HashMap::new()), + timeouts, + ) +} + +pub fn make_transfer_iota_transaction( + gas_object: ObjectRef, + recipient: IotaAddress, + amount: Option, + sender: IotaAddress, + keypair: &AccountKeyPair, + gas_price: u64, +) -> Transaction { + let data = TransactionData::new_transfer_iota( + recipient, + sender, + amount, + gas_object, + gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, + gas_price, + ); + to_sender_signed_transaction(data, keypair) +} + +pub fn make_pay_iota_transaction( + gas_object: ObjectRef, + coins: Vec, + recipients: Vec, + amounts: Vec, + sender: IotaAddress, + keypair: &AccountKeyPair, + gas_price: u64, + gas_budget: u64, +) -> Transaction { + let data = TransactionData::new_pay_iota( + sender, coins, recipients, amounts, gas_object, gas_budget, gas_price, + ) + .unwrap(); + to_sender_signed_transaction(data, keypair) +} + +pub fn make_transfer_object_transaction( + object_ref: ObjectRef, + gas_object: ObjectRef, + sender: IotaAddress, + keypair: &AccountKeyPair, + recipient: IotaAddress, + gas_price: u64, +) -> Transaction { + let data = TransactionData::new_transfer( + recipient, + object_ref, + sender, + gas_object, + gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER * 10, + gas_price, + ); + to_sender_signed_transaction(data, keypair) +} + +pub fn make_transfer_object_move_transaction( + src: IotaAddress, + keypair: &AccountKeyPair, + dest: IotaAddress, + object_ref: ObjectRef, + framework_obj_id: ObjectID, + gas_object_ref: ObjectRef, + gas_budget_in_units: u64, + gas_price: u64, +) -> Transaction { + let args = vec![ + CallArg::Object(ObjectArg::ImmOrOwnedObject(object_ref)), + CallArg::Pure(bcs::to_bytes(&AccountAddress::from(dest)).unwrap()), + ]; + + to_sender_signed_transaction( + TransactionData::new_move_call( + src, + framework_obj_id, + ident_str!("object_basics").to_owned(), + ident_str!("transfer").to_owned(), + Vec::new(), + gas_object_ref, + args, + gas_budget_in_units * gas_price, + gas_price, + ) + .unwrap(), + keypair, + ) +} + +/// Make a dummy tx that uses random object refs. +pub fn make_dummy_tx( + receiver: IotaAddress, + sender: IotaAddress, + sender_sec: &AccountKeyPair, +) -> Transaction { + Transaction::from_data_and_signer( + TransactionData::new_transfer( + receiver, + random_object_ref(), + sender, + random_object_ref(), + TEST_ONLY_GAS_UNIT_FOR_TRANSFER * 10, + 10, + ), + vec![sender_sec], + ) +} + +/// Make a cert using an arbitrarily large committee. +pub fn make_cert_with_large_committee( + committee: &Committee, + key_pairs: &[AuthorityKeyPair], + transaction: &Transaction, +) -> CertifiedTransaction { + // assumes equal weighting. + let len = committee.voting_rights.len(); + assert_eq!(len, key_pairs.len()); + let count = (len * 2 + 2) / 3; + + let sigs: Vec<_> = key_pairs + .iter() + .take(count) + .map(|key_pair| { + SignedTransaction::new( + committee.epoch(), + transaction.clone().into_data(), + key_pair, + AuthorityPublicKeyBytes::from(key_pair.public()), + ) + .auth_sig() + .clone() + }) + .collect(); + + let cert = CertifiedTransaction::new(transaction.clone().into_data(), sigs, committee).unwrap(); + cert.verify_signatures_authenticated(committee, &Default::default()) + .unwrap(); + cert +} diff --git a/crates/sui-core/src/transaction_input_loader.rs b/crates/iota-core/src/transaction_input_loader.rs similarity index 94% rename from crates/sui-core/src/transaction_input_loader.rs rename to crates/iota-core/src/transaction_input_loader.rs index 4e183b17029..6eb60e3d3e8 100644 --- a/crates/sui-core/src/transaction_input_loader.rs +++ b/crates/iota-core/src/transaction_input_loader.rs @@ -1,20 +1,21 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, sync::Arc}; -use itertools::izip; -use once_cell::unsync::OnceCell; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ +use iota_protocol_config::ProtocolConfig; +use iota_types::{ base_types::{EpochId, ObjectID, ObjectRef, SequenceNumber, TransactionDigest}, - error::{SuiError, SuiResult, UserInputError}, + error::{IotaError, IotaResult, UserInputError}, storage::{GetSharedLocks, ObjectKey}, transaction::{ InputObjectKind, InputObjects, ObjectReadResult, ObjectReadResultKind, ReceivingObjectReadResult, ReceivingObjectReadResultKind, ReceivingObjects, TransactionKey, }, }; +use itertools::izip; +use once_cell::unsync::OnceCell; use tracing::instrument; use crate::execution_cache::ExecutionCacheRead; @@ -43,7 +44,7 @@ impl TransactionInputLoader { input_object_kinds: &[InputObjectKind], receiving_objects: &[ObjectRef], epoch_id: EpochId, - ) -> SuiResult<(InputObjects, ReceivingObjects)> { + ) -> IotaResult<(InputObjects, ReceivingObjects)> { // Length of input_object_kinds have beeen checked via validity_check() for // ProgrammableTransaction. let mut input_results = vec![None; input_object_kinds.len()]; @@ -55,7 +56,7 @@ impl TransactionInputLoader { // Packages are loaded one at a time via the cache InputObjectKind::MovePackage(id) => { let Some(package) = self.cache.get_package_object(id)?.map(|o| o.into()) else { - return Err(SuiError::from(kind.object_not_found_error())); + return Err(IotaError::from(kind.object_not_found_error())); }; input_results[i] = Some(ObjectReadResult { input_object_kind: *kind, @@ -76,7 +77,7 @@ impl TransactionInputLoader { object: ObjectReadResultKind::DeletedSharedObject(version, digest), }); } else { - return Err(SuiError::from(kind.object_not_found_error())); + return Err(IotaError::from(kind.object_not_found_error())); } } }, @@ -120,7 +121,7 @@ impl TransactionInputLoader { tx_digest: &TransactionDigest, input_object_kinds: &[InputObjectKind], protocol_config: &ProtocolConfig, - ) -> SuiResult { + ) -> IotaResult { self.read_objects_for_synchronous_execution_impl( Some(tx_digest), input_object_kinds, @@ -139,7 +140,7 @@ impl TransactionInputLoader { input_object_kinds: &[InputObjectKind], receiving_objects: &[ObjectRef], protocol_config: &ProtocolConfig, - ) -> SuiResult<(InputObjects, ReceivingObjects)> { + ) -> IotaResult<(InputObjects, ReceivingObjects)> { self.read_objects_for_synchronous_execution_impl( Some(tx_digest), input_object_kinds, @@ -156,7 +157,7 @@ impl TransactionInputLoader { input_object_kinds: &[InputObjectKind], receiving_objects: &[ObjectRef], protocol_config: &ProtocolConfig, - ) -> SuiResult<(InputObjects, ReceivingObjects)> { + ) -> IotaResult<(InputObjects, ReceivingObjects)> { self.read_objects_for_synchronous_execution_impl( None, input_object_kinds, @@ -191,7 +192,7 @@ impl TransactionInputLoader { tx_key: &TransactionKey, input_object_kinds: &[InputObjectKind], epoch_id: EpochId, - ) -> SuiResult { + ) -> IotaResult { let shared_locks_cell: OnceCell> = OnceCell::new(); let mut results = vec![None; input_object_kinds.len()]; @@ -217,7 +218,7 @@ impl TransactionInputLoader { } InputObjectKind::SharedMoveObject { id, .. } => { let shared_locks = shared_locks_cell.get_or_try_init(|| { - Ok::, SuiError>( + Ok::, IotaError>( shared_lock_store .get_shared_locks(tx_key)? .into_iter() @@ -290,7 +291,7 @@ impl TransactionInputLoader { input_object_kinds: &[InputObjectKind], receiving_objects: &[ObjectRef], _protocol_config: &ProtocolConfig, - ) -> SuiResult<(InputObjects, ReceivingObjects)> { + ) -> IotaResult<(InputObjects, ReceivingObjects)> { let mut results = Vec::with_capacity(input_object_kinds.len()); // Length of input_object_kinds have beeen checked via validity_check() for // ProgrammableTransaction. @@ -306,7 +307,7 @@ impl TransactionInputLoader { self.cache.get_object_by_key(&objref.0, objref.1)? } } - .ok_or_else(|| SuiError::from(kind.object_not_found_error()))?; + .ok_or_else(|| IotaError::from(kind.object_not_found_error()))?; results.push(ObjectReadResult::new(*kind, obj.into())); } @@ -319,7 +320,7 @@ impl TransactionInputLoader { &self, receiving_objects: &[ObjectRef], epoch_id: EpochId, - ) -> SuiResult { + ) -> IotaResult { let mut receiving_results = Vec::with_capacity(receiving_objects.len()); for objref in receiving_objects { // Note: the digest is checked later in check_transaction_input diff --git a/crates/sui-core/src/transaction_manager.rs b/crates/iota-core/src/transaction_manager.rs similarity index 99% rename from crates/sui-core/src/transaction_manager.rs rename to crates/iota-core/src/transaction_manager.rs index 795317f66ce..debf136ef28 100644 --- a/crates/sui-core/src/transaction_manager.rs +++ b/crates/iota-core/src/transaction_manager.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -9,20 +10,20 @@ use std::{ }; use indexmap::IndexMap; -use lru::LruCache; -use mysten_metrics::monitored_scope; -use parking_lot::RwLock; -use sui_types::{ +use iota_types::{ base_types::{ObjectID, SequenceNumber, TransactionDigest}, committee::EpochId, digests::TransactionEffectsDigest, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, executable_transaction::VerifiedExecutableTransaction, fp_bail, fp_ensure, message_envelope::Message, storage::InputKey, transaction::{SenderSignedData, TransactionDataAPI, VerifiedCertificate}, }; +use lru::LruCache; +use mysten_metrics::monitored_scope; +use parking_lot::RwLock; use tap::TapOptional; use tokio::{sync::mpsc::UnboundedSender, time::Instant}; use tracing::{error, info, instrument, trace, warn}; @@ -838,12 +839,12 @@ impl TransactionManager { &self, txn_age_threshold: Duration, tx_data: &SenderSignedData, - ) -> SuiResult { + ) -> IotaResult { // Too many transactions are pending execution. let inflight_queue_len = self.inflight_queue_len(); fp_ensure!( inflight_queue_len < MAX_TM_QUEUE_LENGTH, - SuiError::TooManyTransactionsPendingExecution { + IotaError::TooManyTransactionsPendingExecution { queue_len: inflight_queue_len, threshold: MAX_TM_QUEUE_LENGTH, } @@ -864,7 +865,7 @@ impl TransactionManager { "Overload detected on object {:?} with {} pending transactions", object_id, queue_len ); - fp_bail!(SuiError::TooManyTransactionsPendingOnObject { + fp_bail!(IotaError::TooManyTransactionsPendingOnObject { object_id, queue_len, threshold: MAX_PER_OBJECT_QUEUE_LENGTH, @@ -879,7 +880,7 @@ impl TransactionManager { object_id, age.as_secs() ); - fp_bail!(SuiError::TooOldTransactionPendingOnObject { + fp_bail!(IotaError::TooOldTransactionPendingOnObject { object_id, txn_age_sec: age.as_secs(), threshold: txn_age_threshold.as_secs(), diff --git a/crates/sui-core/src/transaction_orchestrator.rs b/crates/iota-core/src/transaction_orchestrator.rs similarity index 98% rename from crates/sui-core/src/transaction_orchestrator.rs rename to crates/iota-core/src/transaction_orchestrator.rs index f8b125b98b0..ee75a4f9702 100644 --- a/crates/sui-core/src/transaction_orchestrator.rs +++ b/crates/iota-core/src/transaction_orchestrator.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{path::Path, sync::Arc, time::Duration}; @@ -7,6 +8,20 @@ use futures::{ future::{select, Either, Future}, FutureExt, }; +use iota_storage::write_path_pending_tx_log::WritePathPendingTransactionLog; +use iota_types::{ + base_types::TransactionDigest, + effects::{TransactionEffectsAPI, VerifiedCertifiedTransactionEffects}, + error::{IotaError, IotaResult}, + executable_transaction::VerifiedExecutableTransaction, + iota_system_state::IotaSystemState, + quorum_driver_types::{ + ExecuteTransactionRequest, ExecuteTransactionRequestType, ExecuteTransactionResponse, + FinalizedEffects, QuorumDriverEffectsQueueResult, QuorumDriverError, QuorumDriverResponse, + QuorumDriverResult, + }, + transaction::VerifiedTransaction, +}; use mysten_common::sync::notify_read::NotifyRead; use mysten_metrics::{ histogram::{Histogram, HistogramVec}, @@ -18,20 +33,6 @@ use prometheus::{ register_int_counter_vec_with_registry, register_int_counter_with_registry, register_int_gauge_vec_with_registry, register_int_gauge_with_registry, Registry, }; -use sui_storage::write_path_pending_tx_log::WritePathPendingTransactionLog; -use sui_types::{ - base_types::TransactionDigest, - effects::{TransactionEffectsAPI, VerifiedCertifiedTransactionEffects}, - error::{SuiError, SuiResult}, - executable_transaction::VerifiedExecutableTransaction, - quorum_driver_types::{ - ExecuteTransactionRequest, ExecuteTransactionRequestType, ExecuteTransactionResponse, - FinalizedEffects, QuorumDriverEffectsQueueResult, QuorumDriverError, QuorumDriverResponse, - QuorumDriverResult, - }, - sui_system_state::SuiSystemState, - transaction::VerifiedTransaction, -}; use tokio::{ sync::broadcast::{error::RecvError, Receiver}, task::JoinHandle, @@ -72,7 +73,7 @@ pub struct TransactiondOrchestrator { impl TransactiondOrchestrator { pub fn new_with_network_clients( validator_state: Arc, - reconfig_channel: Receiver, + reconfig_channel: Receiver, parent_path: &Path, prometheus_registry: &Registry, ) -> anyhow::Result { @@ -271,7 +272,7 @@ where async fn submit( &self, transaction: VerifiedTransaction, - ) -> SuiResult> + '_> { + ) -> IotaResult> + '_> { let tx_digest = *transaction.digest(); let ticket = self.notifier.register_one(&tx_digest); if self @@ -318,7 +319,7 @@ where transaction: &VerifiedExecutableTransaction, effects_cert: &VerifiedCertifiedTransactionEffects, metrics: &TransactionOrchestratorMetrics, - ) -> SuiResult { + ) -> IotaResult { // TODO: attempt a finalized tx at most once per request. // Every WaitForLocalExecution request will be attempted to execute twice, // one from the subscriber queue, one from the proactive execution before @@ -365,7 +366,7 @@ where LOCAL_EXECUTION_TIMEOUT ); metrics.local_execution_timeout.inc(); - Err(SuiError::TimeoutError) + Err(IotaError::TimeoutError) } Ok(Err(err)) => { debug!( @@ -373,7 +374,7 @@ where "Executing tx locally by orchestrator failed with error: {:?}", err ); metrics.local_execution_failure.inc(); - Err(SuiError::TransactionOrchestratorLocalExecutionError { + Err(IotaError::TransactionOrchestratorLocalExecutionError { error: err.to_string(), }) } diff --git a/crates/sui-core/src/transaction_outputs.rs b/crates/iota-core/src/transaction_outputs.rs similarity index 98% rename from crates/sui-core/src/transaction_outputs.rs rename to crates/iota-core/src/transaction_outputs.rs index b5c7d6d79f8..1b14b9a9e6d 100644 --- a/crates/sui-core/src/transaction_outputs.rs +++ b/crates/iota-core/src/transaction_outputs.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -6,7 +7,7 @@ use std::{ sync::Arc, }; -use sui_types::{ +use iota_types::{ base_types::ObjectRef, effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, inner_temporary_store::{InnerTemporaryStore, WrittenObjects}, diff --git a/crates/sui-core/src/transaction_signing_filter.rs b/crates/iota-core/src/transaction_signing_filter.rs similarity index 76% rename from crates/sui-core/src/transaction_signing_filter.rs rename to crates/iota-core/src/transaction_signing_filter.rs index 79433414e4b..b3558f73f49 100644 --- a/crates/sui-core/src/transaction_signing_filter.rs +++ b/crates/iota-core/src/transaction_signing_filter.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[cfg(test)] diff --git a/crates/sui-core/src/unit_tests/authority_aggregator_tests.rs b/crates/iota-core/src/unit_tests/authority_aggregator_tests.rs similarity index 91% rename from crates/sui-core/src/unit_tests/authority_aggregator_tests.rs rename to crates/iota-core/src/unit_tests/authority_aggregator_tests.rs index dd0c6053b85..719940f86b0 100644 --- a/crates/sui-core/src/unit_tests/authority_aggregator_tests.rs +++ b/crates/iota-core/src/unit_tests/authority_aggregator_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -7,16 +8,13 @@ use std::{ sync::{Arc, Mutex}, }; -use move_core_types::{account_address::AccountAddress, ident_str}; -use rand::{rngs::StdRng, SeedableRng}; -use shared_crypto::intent::{Intent, IntentScope}; -use sui_authority_aggregation::quorum_map_then_reduce_with_timeout; -use sui_framework::BuiltInFramework; -use sui_macros::sim_test; -use sui_move_build::BuildConfig; +use iota_authority_aggregation::quorum_map_then_reduce_with_timeout; +use iota_framework::BuiltInFramework; +use iota_macros::sim_test; +use iota_move_build::BuildConfig; #[cfg(msim)] -use sui_simulator::configs::constant_latency_ms; -use sui_types::{ +use iota_simulator::configs::constant_latency_ms; +use iota_types::{ crypto::{ get_key_pair, get_key_pair_from_rng, AccountKeyPair, AuthorityKeyPair, AuthoritySignature, KeypairTraits, Signature, Signer, @@ -28,6 +26,9 @@ use sui_types::{ transaction::*, utils::{create_fake_transaction, to_sender_signed_transaction}, }; +use move_core_types::{account_address::AccountAddress, ident_str}; +use rand::{rngs::StdRng, SeedableRng}; +use shared_crypto::intent::{Intent, IntentScope}; use tokio::time::Instant; use super::*; @@ -38,7 +39,7 @@ use crate::{ LocalAuthorityClientFaultConfig, MockAuthorityApi, }, test_utils::{ - init_local_authorities, make_transfer_object_transaction, make_transfer_sui_transaction, + init_local_authorities, make_transfer_iota_transaction, make_transfer_object_transaction, }, }; @@ -78,9 +79,9 @@ pub fn set_local_client_config( } pub fn create_object_move_transaction( - src: SuiAddress, + src: IotaAddress, secret: &dyn Signer, - dest: SuiAddress, + dest: IotaAddress, value: u64, package_id: ObjectID, gas_object_ref: ObjectRef, @@ -111,7 +112,7 @@ pub fn create_object_move_transaction( } pub fn delete_object_move_transaction( - src: SuiAddress, + src: IotaAddress, secret: &dyn Signer, object_ref: ObjectRef, framework_obj_id: ObjectID, @@ -136,7 +137,7 @@ pub fn delete_object_move_transaction( } pub fn set_object_move_transaction( - src: SuiAddress, + src: IotaAddress, secret: &dyn Signer, object_ref: ObjectRef, value: u64, @@ -393,7 +394,7 @@ async fn test_map_reducer() { 0usize, |_name, _client| { Box::pin(async move { - let res: Result = Err(SuiError::TooManyIncorrectAuthorities { + let res: Result = Err(IotaError::TooManyIncorrectAuthorities { errors: vec![], action: "".to_string(), }); @@ -404,7 +405,7 @@ async fn test_map_reducer() { Box::pin(async move { assert!(matches!( result, - Err(SuiError::TooManyIncorrectAuthorities { .. }) + Err(IotaError::TooManyIncorrectAuthorities { .. }) )); accumulated_state += 1; ReduceOutput::Continue(accumulated_state) @@ -592,7 +593,7 @@ async fn test_quorum_once_with_timeout() { match res { Ok(_) => Ok(()), // Treat transaction not found OK just to test timeout functionality. - Err(SuiError::TransactionNotFound { .. }) => Ok(()), + Err(IotaError::TransactionNotFound { .. }) => Ok(()), Err(err) => Err(err), } }) @@ -728,9 +729,9 @@ async fn test_handle_transaction_fork() { let (sender, sender_kp): (_, AccountKeyPair) = get_key_pair(); let gas_object = random_object_ref(); - let tx = make_transfer_sui_transaction( + let tx = make_transfer_iota_transaction( gas_object, - SuiAddress::default(), + IotaAddress::default(), None, sender, &sender_kp, @@ -805,9 +806,9 @@ async fn test_handle_certificate_response() { let (sender, sender_kp): (_, AccountKeyPair) = get_key_pair(); let gas_object = random_object_ref(); - let tx = VerifiedTransaction::new_unchecked(make_transfer_sui_transaction( + let tx = VerifiedTransaction::new_unchecked(make_transfer_iota_transaction( gas_object, - SuiAddress::default(), + IotaAddress::default(), None, sender, &sender_kp, @@ -835,7 +836,7 @@ async fn test_handle_certificate_response() { agg.committee = Arc::new(committee_1.clone()); assert_resp_err(&agg, tx.clone().into(), |e| matches!(e, AggregatorProcessTransactionError::RetryableTransaction { .. }), - |e| matches!(e, SuiError::WrongEpoch { expected_epoch, actual_epoch } if *expected_epoch == 1 && *actual_epoch == 0) + |e| matches!(e, IotaError::WrongEpoch { expected_epoch, actual_epoch } if *expected_epoch == 1 && *actual_epoch == 0) ).await; set_cert_response_with_certified_tx(&mut clients, &authority_keys, &cert_epoch_0, 0); @@ -853,7 +854,7 @@ async fn test_handle_certificate_response() { err, AggregatorProcessCertificateError::RetryableExecuteCertificate { retryable_errors, .. - } if retryable_errors.iter().any(|(error, _, _)| matches!(error, SuiError::WrongEpoch { + } if retryable_errors.iter().any(|(error, _, _)| matches!(error, IotaError::WrongEpoch { expected_epoch: 1, actual_epoch: 0 })) ); @@ -875,28 +876,28 @@ async fn test_handle_transaction_response() { let (sender, sender_kp): (_, AccountKeyPair) = get_key_pair(); let gas_object = random_object_ref(); - let tx = VerifiedTransaction::new_unchecked(make_transfer_sui_transaction( + let tx = VerifiedTransaction::new_unchecked(make_transfer_iota_transaction( gas_object, - SuiAddress::default(), + IotaAddress::default(), None, sender, &sender_kp, 666, // this is a dummy value which does not matter )); - let tx2 = VerifiedTransaction::new_unchecked(make_transfer_sui_transaction( + let tx2 = VerifiedTransaction::new_unchecked(make_transfer_iota_transaction( gas_object, - SuiAddress::default(), + IotaAddress::default(), Some(1), sender, &sender_kp, 666, // this is a dummy value which does not matter )); - let package_not_found_error = SuiError::UserInputError { + let package_not_found_error = IotaError::UserInputError { error: UserInputError::DependentPackageNotFound { package_id: gas_object.0, }, }; - let object_not_found_error = SuiError::UserInputError { + let object_not_found_error = IotaError::UserInputError { error: UserInputError::ObjectNotFound { object_id: gas_object.0, version: Some(gas_object.1), @@ -917,7 +918,7 @@ async fn test_handle_transaction_response() { AggregatorProcessTransactionError::FatalTransaction { .. } ) }, - |e| matches!(e, SuiError::Unknown(..)), + |e| matches!(e, IotaError::Unknown(..)), ) .await; @@ -944,7 +945,7 @@ async fn test_handle_transaction_response() { agg.committee = Arc::new(committee_1); assert_resp_err(&agg, tx.clone().into(), |e| matches!(e, AggregatorProcessTransactionError::RetryableTransaction { .. }), - |e| matches!(e, SuiError::WrongEpoch { expected_epoch, actual_epoch } if *expected_epoch == 1 && *actual_epoch == 0) + |e| matches!(e, IotaError::WrongEpoch { expected_epoch, actual_epoch } if *expected_epoch == 1 && *actual_epoch == 0) ).await; println!("Case 3 - Successful Cert Transaction"); @@ -988,7 +989,7 @@ async fn test_handle_transaction_response() { AggregatorProcessTransactionError::RetryableTransaction { .. } ) }, - |e| matches!(e, SuiError::MissingCommitteeAtEpoch(e) if *e == 1), + |e| matches!(e, IotaError::MissingCommitteeAtEpoch(e) if *e == 1), ) .await; @@ -1021,7 +1022,7 @@ async fn test_handle_transaction_response() { // Err because either cert or signed effects is in epoch 0 assert_resp_err(&agg, tx.clone().into(), |e| matches!(e, AggregatorProcessTransactionError::RetryableTransaction { .. }), - |e| matches!(e, SuiError::WrongEpoch { expected_epoch, actual_epoch } if *expected_epoch == 1 && *actual_epoch == 0) + |e| matches!(e, IotaError::WrongEpoch { expected_epoch, actual_epoch } if *expected_epoch == 1 && *actual_epoch == 0) ).await; set_tx_info_response_with_cert_and_effects( @@ -1069,8 +1070,8 @@ async fn test_handle_transaction_response() { |e| { matches!( e, - SuiError::QuorumFailedToGetEffectsQuorumWhenProcessingTransaction { .. } - | SuiError::RpcError(..) + IotaError::QuorumFailedToGetEffectsQuorumWhenProcessingTransaction { .. } + | IotaError::RpcError(..) ) }, ) @@ -1145,8 +1146,8 @@ async fn test_handle_transaction_response() { |e| { matches!( e, - SuiError::QuorumFailedToGetEffectsQuorumWhenProcessingTransaction { .. } - | SuiError::RpcError(..) + IotaError::QuorumFailedToGetEffectsQuorumWhenProcessingTransaction { .. } + | IotaError::RpcError(..) ) }, ) @@ -1232,9 +1233,9 @@ async fn test_handle_transaction_response() { |e| { matches!( e, - SuiError::QuorumFailedToGetEffectsQuorumWhenProcessingTransaction { .. } - | SuiError::RpcError(..) - | SuiError::ByzantineAuthoritySuspicion { .. } + IotaError::QuorumFailedToGetEffectsQuorumWhenProcessingTransaction { .. } + | IotaError::RpcError(..) + | IotaError::ByzantineAuthoritySuspicion { .. } ) }, ) @@ -1261,7 +1262,7 @@ async fn test_handle_transaction_response() { AggregatorProcessTransactionError::RetryableTransaction { .. } ) }, - |e| matches!(e, SuiError::MissingCommitteeAtEpoch(e) if *e == 1), + |e| matches!(e, IotaError::MissingCommitteeAtEpoch(e) if *e == 1), ) .await; @@ -1275,7 +1276,7 @@ async fn test_handle_transaction_response() { assert_resp_err( &agg, tx.clone().into(), |e| matches!(e, AggregatorProcessTransactionError::RetryableTransaction { .. }), - |e| matches!(e, SuiError::WrongEpoch { expected_epoch, actual_epoch } if *expected_epoch == 0 && *actual_epoch == 1) + |e| matches!(e, IotaError::WrongEpoch { expected_epoch, actual_epoch } if *expected_epoch == 0 && *actual_epoch == 1) ) .await; @@ -1303,7 +1304,12 @@ async fn test_handle_transaction_response() { AggregatorProcessTransactionError::RetryableTransaction { .. } ) }, - |e| matches!(e, SuiError::UserInputError { .. } | SuiError::RpcError(..)), + |e| { + matches!( + e, + IotaError::UserInputError { .. } | IotaError::RpcError(..) + ) + }, ) .await; @@ -1327,7 +1333,12 @@ async fn test_handle_transaction_response() { AggregatorProcessTransactionError::RetryableTransaction { .. } ) }, - |e| matches!(e, SuiError::UserInputError { .. } | SuiError::RpcError(..)), + |e| { + matches!( + e, + IotaError::UserInputError { .. } | IotaError::RpcError(..) + ) + }, ) .await; @@ -1351,7 +1362,12 @@ async fn test_handle_transaction_response() { AggregatorProcessTransactionError::RetryableTransaction { .. } ) }, - |e| matches!(e, SuiError::UserInputError { .. } | SuiError::RpcError(..)), + |e| { + matches!( + e, + IotaError::UserInputError { .. } | IotaError::RpcError(..) + ) + }, ) .await; @@ -1374,7 +1390,12 @@ async fn test_handle_transaction_response() { AggregatorProcessTransactionError::FatalTransaction { .. } ) }, - |e| matches!(e, SuiError::UserInputError { .. } | SuiError::RpcError(..)), + |e| { + matches!( + e, + IotaError::UserInputError { .. } | IotaError::RpcError(..) + ) + }, ) .await; @@ -1397,7 +1418,12 @@ async fn test_handle_transaction_response() { AggregatorProcessTransactionError::FatalTransaction { .. } ) }, - |e| matches!(e, SuiError::UserInputError { .. } | SuiError::RpcError(..)), + |e| { + matches!( + e, + IotaError::UserInputError { .. } | IotaError::RpcError(..) + ) + }, ) .await; @@ -1425,7 +1451,12 @@ async fn test_handle_transaction_response() { AggregatorProcessTransactionError::FatalTransaction { .. } ) }, - |e| matches!(e, SuiError::UserInputError { .. } | SuiError::RpcError(..)), + |e| { + matches!( + e, + IotaError::UserInputError { .. } | IotaError::RpcError(..) + ) + }, ) .await; } @@ -1445,32 +1476,32 @@ async fn test_handle_conflicting_transaction_response() { let (sender, sender_kp): (_, AccountKeyPair) = get_key_pair(); let conflicting_object = random_object_ref(); - let tx1 = VerifiedTransaction::new_unchecked(make_transfer_sui_transaction( + let tx1 = VerifiedTransaction::new_unchecked(make_transfer_iota_transaction( conflicting_object, - SuiAddress::default(), + IotaAddress::default(), Some(1), sender, &sender_kp, 666, // this is a dummy value which does not matter )); - let conflicting_tx2 = VerifiedTransaction::new_unchecked(make_transfer_sui_transaction( + let conflicting_tx2 = VerifiedTransaction::new_unchecked(make_transfer_iota_transaction( conflicting_object, - SuiAddress::default(), + IotaAddress::default(), Some(2), sender, &sender_kp, 666, // this is a dummy value which does not matter )); - let conflicting_error = SuiError::ObjectLockConflict { + let conflicting_error = IotaError::ObjectLockConflict { obj_ref: conflicting_object, pending_transaction: *conflicting_tx2.digest(), }; - let retryable_error = SuiError::RpcError("RPC".into(), "Error".into()); - let non_retryable_error = SuiError::ByzantineAuthoritySuspicion { + let retryable_error = IotaError::RpcError("RPC".into(), "Error".into()); + let non_retryable_error = IotaError::ByzantineAuthoritySuspicion { authority: authority_keys[0].0, reason: "Faulty".into(), }; - let object_not_found_error = SuiError::UserInputError { + let object_not_found_error = IotaError::UserInputError { error: UserInputError::ObjectNotFound { object_id: conflicting_object.0, version: Some(conflicting_object.1), @@ -1506,7 +1537,7 @@ async fn test_handle_conflicting_transaction_response() { |e| { matches!( e, - SuiError::ObjectLockConflict { .. } | SuiError::RpcError(..) + IotaError::ObjectLockConflict { .. } | IotaError::RpcError(..) ) }, ) @@ -1539,7 +1570,7 @@ async fn test_handle_conflicting_transaction_response() { |e| { matches!( e, - SuiError::ObjectLockConflict { .. } | SuiError::RpcError(..) + IotaError::ObjectLockConflict { .. } | IotaError::RpcError(..) ) }, ) @@ -1571,7 +1602,7 @@ async fn test_handle_conflicting_transaction_response() { |e| { matches!( e, - SuiError::ObjectLockConflict { .. } | SuiError::RpcError(..) + IotaError::ObjectLockConflict { .. } | IotaError::RpcError(..) ) }, ) @@ -1597,7 +1628,7 @@ async fn test_handle_conflicting_transaction_response() { AggregatorProcessTransactionError::FatalConflictingTransaction { .. } ) }, - |e| matches!(e, SuiError::ObjectLockConflict { .. }), + |e| matches!(e, IotaError::ObjectLockConflict { .. }), ) .await; @@ -1610,15 +1641,15 @@ async fn test_handle_conflicting_transaction_response() { .unwrap() .set_tx_info_response_error(conflicting_error.clone()); // Validator 3 returns a conflicting tx3 - let conflicting_tx3 = make_transfer_sui_transaction( + let conflicting_tx3 = make_transfer_iota_transaction( conflicting_object, - SuiAddress::default(), + IotaAddress::default(), Some(3), sender, &sender_kp, 666, // this is a dummy value which does not matter ); - let conflicting_error_2 = SuiError::ObjectLockConflict { + let conflicting_error_2 = IotaError::ObjectLockConflict { obj_ref: conflicting_object, pending_transaction: *conflicting_tx3.digest(), }; @@ -1645,7 +1676,8 @@ async fn test_handle_conflicting_transaction_response() { |e| { matches!( e, - SuiError::ObjectLockConflict { .. } | SuiError::ByzantineAuthoritySuspicion { .. } + IotaError::ObjectLockConflict { .. } + | IotaError::ByzantineAuthoritySuspicion { .. } ) }, ) @@ -1662,15 +1694,15 @@ async fn test_handle_conflicting_transaction_response() { .unwrap() .set_tx_info_response_error(conflicting_error.clone()); // Validator 3 returns a conflicting tx3 - let conflicting_tx3 = make_transfer_sui_transaction( + let conflicting_tx3 = make_transfer_iota_transaction( conflicting_object, - SuiAddress::default(), + IotaAddress::default(), Some(3), sender, &sender_kp, 666, // this is a dummy value which does not matter ); - let conflicting_error_2 = SuiError::ObjectLockConflict { + let conflicting_error_2 = IotaError::ObjectLockConflict { obj_ref: conflicting_object, pending_transaction: *conflicting_tx3.digest(), }; @@ -1697,7 +1729,7 @@ async fn test_handle_conflicting_transaction_response() { |e| { matches!( e, - SuiError::ObjectLockConflict { .. } | SuiError::UserInputError { .. } + IotaError::ObjectLockConflict { .. } | IotaError::UserInputError { .. } ) }, ) @@ -1737,9 +1769,9 @@ async fn test_handle_conflicting_transaction_response() { |e| { matches!( e, - SuiError::ObjectLockConflict { .. } - | SuiError::UserInputError { .. } - | SuiError::ByzantineAuthoritySuspicion { .. } + IotaError::ObjectLockConflict { .. } + | IotaError::UserInputError { .. } + | IotaError::ByzantineAuthoritySuspicion { .. } ) }, ) @@ -1830,7 +1862,7 @@ async fn test_handle_conflicting_transaction_response() { |e| { matches!( e, - SuiError::MissingCommitteeAtEpoch(..) | SuiError::ObjectLockConflict { .. } + IotaError::MissingCommitteeAtEpoch(..) | IotaError::ObjectLockConflict { .. } ) }, ) @@ -1855,7 +1887,7 @@ async fn test_handle_conflicting_transaction_response() { |e| { matches!( e, - SuiError::WrongEpoch { .. } | SuiError::ObjectLockConflict { .. } + IotaError::WrongEpoch { .. } | IotaError::ObjectLockConflict { .. } ) }, ) @@ -1882,20 +1914,20 @@ async fn test_handle_overload_response() { let (sender, sender_kp): (_, AccountKeyPair) = get_key_pair(); let gas_object = random_object_ref(); - let txn = make_transfer_sui_transaction( + let txn = make_transfer_iota_transaction( gas_object, - SuiAddress::default(), + IotaAddress::default(), None, sender, &sender_kp, 666, // this is a dummy value which does not matter ); - let overload_error = SuiError::TooManyTransactionsPendingExecution { + let overload_error = IotaError::TooManyTransactionsPendingExecution { queue_len: 100, threshold: 100, }; - let rpc_error = SuiError::RpcError("RPC".into(), "Error".into()); + let rpc_error = IotaError::RpcError("RPC".into(), "Error".into()); // Have 2f + 1 validators return the overload error and we should get the // `SystemOverload` error. @@ -1918,7 +1950,7 @@ async fn test_handle_overload_response() { |e| { matches!( e, - SuiError::TooManyTransactionsPendingExecution { .. } | SuiError::RpcError(..) + IotaError::TooManyTransactionsPendingExecution { .. } | IotaError::RpcError(..) ) }, ) @@ -1945,7 +1977,7 @@ async fn test_handle_overload_response() { |e| { matches!( e, - SuiError::TooManyTransactionsPendingExecution { .. } | SuiError::RpcError(..) + IotaError::TooManyTransactionsPendingExecution { .. } | IotaError::RpcError(..) ) }, ) @@ -1953,7 +1985,7 @@ async fn test_handle_overload_response() { } // Tests that authority aggregator can aggregate -// SuiError::ValidatorOverloadedRetryAfter into +// IotaError::ValidatorOverloadedRetryAfter into // AggregatorProcessTransactionError::SystemOverloadRetryAfter. #[tokio::test] async fn test_handle_overload_retry_response() { @@ -1970,19 +2002,19 @@ async fn test_handle_overload_retry_response() { let (sender, sender_kp): (_, AccountKeyPair) = get_key_pair(); let gas_object = random_object_ref(); - let txn = make_transfer_sui_transaction( + let txn = make_transfer_iota_transaction( gas_object, - SuiAddress::default(), + IotaAddress::default(), None, sender, &sender_kp, 666, // this is a dummy value which does not matter ); - let overload_error = SuiError::ValidatorOverloadedRetryAfter { + let overload_error = IotaError::ValidatorOverloadedRetryAfter { retry_after_secs: 0, }; - let rpc_error = SuiError::RpcError("RPC".into(), "Error".into()); + let rpc_error = IotaError::RpcError("RPC".into(), "Error".into()); // Have 2f + 1 validators return the overload error and we should get the // `SystemOverload` error. @@ -2002,7 +2034,7 @@ async fn test_handle_overload_retry_response() { |e| { matches!( e, - SuiError::ValidatorOverloadedRetryAfter { .. } | SuiError::RpcError(..) + IotaError::ValidatorOverloadedRetryAfter { .. } | IotaError::RpcError(..) ) }, ) @@ -2029,7 +2061,7 @@ async fn test_handle_overload_retry_response() { |e| { matches!( e, - SuiError::ValidatorOverloadedRetryAfter { .. } | SuiError::RpcError(..) + IotaError::ValidatorOverloadedRetryAfter { .. } | IotaError::RpcError(..) ) }, ) @@ -2050,9 +2082,9 @@ async fn test_early_exit_with_too_many_conflicts() { } let (sender, sender_kp): (_, AccountKeyPair) = get_key_pair(); - let txn = make_transfer_sui_transaction( + let txn = make_transfer_iota_transaction( random_object_ref(), - SuiAddress::default(), + IotaAddress::default(), None, sender, &sender_kp, @@ -2065,7 +2097,7 @@ async fn test_early_exit_with_too_many_conflicts() { set_tx_info_response_with_error( &mut clients, authority_keys.iter().take(1), - SuiError::ObjectLockConflict { + IotaError::ObjectLockConflict { obj_ref: random_object_ref(), pending_transaction: TransactionDigest::random(), }, @@ -2073,7 +2105,7 @@ async fn test_early_exit_with_too_many_conflicts() { set_tx_info_response_with_error( &mut clients, authority_keys.iter().skip(1).take(1), - SuiError::ObjectLockConflict { + IotaError::ObjectLockConflict { obj_ref: random_object_ref(), pending_transaction: TransactionDigest::random(), }, @@ -2081,7 +2113,7 @@ async fn test_early_exit_with_too_many_conflicts() { set_tx_info_response_with_error( &mut clients, authority_keys.iter().skip(2).take(1), - SuiError::ObjectLockConflict { + IotaError::ObjectLockConflict { obj_ref: random_object_ref(), pending_transaction: TransactionDigest::random(), }, @@ -2089,7 +2121,7 @@ async fn test_early_exit_with_too_many_conflicts() { set_tx_info_response_with_error( &mut clients, authority_keys.iter().skip(3).take(1), - SuiError::TooManyTransactionsPendingExecution { + IotaError::TooManyTransactionsPendingExecution { queue_len: 100, threshold: 100, }, @@ -2206,7 +2238,7 @@ async fn run_aggregator( AuthoritySignInfo::new( 0, tx.clone().data(), - Intent::sui_app(IntentScope::ProofOfPossession), // bad intent + Intent::iota_app(IntentScope::ProofOfPossession), // bad intent *name, secret, ) @@ -2215,7 +2247,7 @@ async fn run_aggregator( AuthoritySignInfo::new( 0, tx.clone().data(), - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), *name, secret, ) @@ -2285,7 +2317,7 @@ async fn process_with_cert( AuthoritySignInfo::new( 0, &effects.clone(), - Intent::sui_app(IntentScope::ProofOfPossession), // bad intent + Intent::iota_app(IntentScope::ProofOfPossession), // bad intent *name, secret, ) @@ -2294,7 +2326,7 @@ async fn process_with_cert( AuthoritySignInfo::new( 0, &effects.clone(), - Intent::sui_app(IntentScope::TransactionEffects), + Intent::iota_app(IntentScope::TransactionEffects), *name, secret, ) @@ -2319,10 +2351,10 @@ async fn assert_resp_err( agg: &AuthorityAggregator, tx: Transaction, agg_err_checker: E, - sui_err_checker: F, + iota_err_checker: F, ) where E: Fn(&AggregatorProcessTransactionError) -> bool, - F: Fn(&SuiError) -> bool, + F: Fn(&IotaError) -> bool, { match agg.process_transaction(tx).await { Err(received_agg_err) if agg_err_checker(&received_agg_err) => match received_agg_err { @@ -2332,7 +2364,7 @@ async fn assert_resp_err( conflicting_tx_digests, } => { assert!(!conflicting_tx_digests.is_empty()); - assert!(errors.iter().map(|e| &e.0).all(sui_err_checker)); + assert!(errors.iter().map(|e| &e.0).all(iota_err_checker)); } AggregatorProcessTransactionError::TxAlreadyFinalizedWithDifferentUserSignatures => (), AggregatorProcessTransactionError::FatalConflictingTransaction { @@ -2340,23 +2372,23 @@ async fn assert_resp_err( conflicting_tx_digests, } => { assert!(!conflicting_tx_digests.is_empty()); - assert!(errors.iter().map(|e| &e.0).all(sui_err_checker)); + assert!(errors.iter().map(|e| &e.0).all(iota_err_checker)); } AggregatorProcessTransactionError::RetryableTransaction { errors } => { - assert!(errors.iter().map(|e| &e.0).all(sui_err_checker)); + assert!(errors.iter().map(|e| &e.0).all(iota_err_checker)); } AggregatorProcessTransactionError::FatalTransaction { errors } => { - assert!(errors.iter().map(|e| &e.0).all(sui_err_checker)); + assert!(errors.iter().map(|e| &e.0).all(iota_err_checker)); } AggregatorProcessTransactionError::SystemOverload { errors, .. } => { - assert!(errors.iter().map(|e| &e.0).all(sui_err_checker)); + assert!(errors.iter().map(|e| &e.0).all(iota_err_checker)); } AggregatorProcessTransactionError::SystemOverloadRetryAfter { errors, .. } => { - assert!(errors.iter().map(|e| &e.0).all(sui_err_checker)); + assert!(errors.iter().map(|e| &e.0).all(iota_err_checker)); } }, Err(received_agg_err) => { @@ -2427,14 +2459,14 @@ fn set_retryable_tx_info_response_error( clients: &mut BTreeMap, authority_keys: &[(AuthorityName, AuthorityKeyPair)], ) { - let error = SuiError::RpcError("RPC".into(), "Error".into()); + let error = IotaError::RpcError("RPC".into(), "Error".into()); set_tx_info_response_with_error(clients, authority_keys.iter(), error); } fn set_tx_info_response_with_error<'a>( clients: &mut BTreeMap, authority_keys: impl Iterator, - error: SuiError, + error: IotaError, ) { for (name, _) in authority_keys { clients diff --git a/crates/sui-core/src/unit_tests/authority_tests.rs b/crates/iota-core/src/unit_tests/authority_tests.rs similarity index 97% rename from crates/sui-core/src/unit_tests/authority_tests.rs rename to crates/iota-core/src/unit_tests/authority_tests.rs index ff735d522f5..323f24ed36d 100644 --- a/crates/sui-core/src/unit_tests/authority_tests.rs +++ b/crates/iota-core/src/unit_tests/authority_tests.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashSet, convert::TryInto, env, fs}; @@ -7,6 +8,32 @@ use std::{collections::HashSet, convert::TryInto, env, fs}; use bcs; use fastcrypto::traits::KeyPair; use futures::{stream::FuturesUnordered, StreamExt}; +use iota_json_rpc_types::{ + IotaArgument, IotaExecutionResult, IotaExecutionStatus, IotaTransactionBlockEffectsAPI, + IotaTypeTag, +}; +use iota_macros::sim_test; +use iota_protocol_config::{ProtocolConfig, SupportedProtocolVersions}; +use iota_types::{ + base_types::dbg_addr, + crypto::{get_key_pair, AccountKeyPair, AuthorityKeyPair, Signature}, + digests::ConsensusCommitDigest, + dynamic_field::DynamicFieldType, + effects::TransactionEffects, + epoch_data::EpochData, + error::UserInputError, + execution_status::{ExecutionFailureStatus, ExecutionStatus}, + gas_coin::GasCoin, + iota_system_state::IotaSystemStateWrapper, + messages_consensus::{ConsensusCommitPrologue, ConsensusCommitPrologueV2}, + object::{Data, Owner, GAS_VALUE_FOR_TESTING, OBJECT_START_VERSION}, + programmable_transaction_builder::ProgrammableTransactionBuilder, + randomness_state::get_randomness_state_obj_initial_shared_version, + storage::GetSharedLocks, + utils::{to_sender_signed_transaction, to_sender_signed_transaction_with_multi_signers}, + IOTA_AUTHENTICATOR_STATE_OBJECT_ID, IOTA_CLOCK_OBJECT_ID, IOTA_FRAMEWORK_PACKAGE_ID, + IOTA_RANDOMNESS_STATE_OBJECT_ID, IOTA_SYSTEM_STATE_OBJECT_ID, MOVE_STDLIB_PACKAGE_ID, +}; use move_binary_format::{ access::ModuleAccess, file_format::{self, AddressIdentifierIndex, IdentifierIndex, ModuleHandle}, @@ -25,31 +52,6 @@ use rand::{ Rng, SeedableRng, }; use serde_json::json; -use sui_json_rpc_types::{ - SuiArgument, SuiExecutionResult, SuiExecutionStatus, SuiTransactionBlockEffectsAPI, SuiTypeTag, -}; -use sui_macros::sim_test; -use sui_protocol_config::{ProtocolConfig, SupportedProtocolVersions}; -use sui_types::{ - base_types::dbg_addr, - crypto::{get_key_pair, AccountKeyPair, AuthorityKeyPair, Signature}, - digests::ConsensusCommitDigest, - dynamic_field::DynamicFieldType, - effects::TransactionEffects, - epoch_data::EpochData, - error::UserInputError, - execution_status::{ExecutionFailureStatus, ExecutionStatus}, - gas_coin::GasCoin, - messages_consensus::{ConsensusCommitPrologue, ConsensusCommitPrologueV2}, - object::{Data, Owner, GAS_VALUE_FOR_TESTING, OBJECT_START_VERSION}, - programmable_transaction_builder::ProgrammableTransactionBuilder, - randomness_state::get_randomness_state_obj_initial_shared_version, - storage::GetSharedLocks, - sui_system_state::SuiSystemStateWrapper, - utils::{to_sender_signed_transaction, to_sender_signed_transaction_with_multi_signers}, - MOVE_STDLIB_PACKAGE_ID, SUI_AUTHENTICATOR_STATE_OBJECT_ID, SUI_CLOCK_OBJECT_ID, - SUI_FRAMEWORK_PACKAGE_ID, SUI_RANDOMNESS_STATE_OBJECT_ID, SUI_SYSTEM_STATE_OBJECT_ID, -}; use super::*; pub use crate::authority::authority_test_utils::*; @@ -223,7 +225,7 @@ async fn test_dry_run_transaction_block() { ) .await .unwrap(); - assert_eq!(*response.effects.status(), SuiExecutionStatus::Success); + assert_eq!(*response.effects.status(), IotaExecutionStatus::Success); let gas_usage = response.effects.gas_cost_summary(); // Make sure that objects are not mutated after dry run. @@ -255,7 +257,7 @@ async fn test_dry_run_transaction_block() { .await .unwrap(); let gas_usage_no_gas = response.effects.gas_cost_summary(); - assert_eq!(*response.effects.status(), SuiExecutionStatus::Success); + assert_eq!(*response.effects.status(), IotaExecutionStatus::Success); assert_eq!(gas_usage, gas_usage_no_gas); } @@ -269,7 +271,7 @@ async fn test_dry_run_no_gas_big_transfer() { let amount = 1_000_000_000u64; let mut builder = ProgrammableTransactionBuilder::new(); - builder.transfer_sui(recipient, Some(amount)); + builder.transfer_iota(recipient, Some(amount)); let pt = builder.finish(); let data = TransactionData::new_programmable( sender, @@ -288,7 +290,7 @@ async fn test_dry_run_no_gas_big_transfer() { ) .await .unwrap(); - assert_eq!(*dry_run_res.effects.status(), SuiExecutionStatus::Success); + assert_eq!(*dry_run_res.effects.status(), IotaExecutionStatus::Success); } #[tokio::test] @@ -323,7 +325,7 @@ async fn test_dev_inspect_object_by_bytes() { let mut results = results.unwrap(); assert_eq!(results.len(), 1); let exec_results = results.pop().unwrap(); - let SuiExecutionResult { + let IotaExecutionResult { mutable_reference_outputs, return_values, } = exec_results; @@ -392,7 +394,7 @@ async fn test_dev_inspect_object_by_bytes() { let mut results = results.unwrap(); assert_eq!(results.len(), 1); let exec_results = results.pop().unwrap(); - let SuiExecutionResult { + let IotaExecutionResult { mutable_reference_outputs, return_values, } = exec_results; @@ -496,7 +498,7 @@ async fn test_dev_inspect_unowned_object() { let mut results = results.unwrap(); assert_eq!(results.len(), 1); let exec_results = results.pop().unwrap(); - let SuiExecutionResult { + let IotaExecutionResult { mutable_reference_outputs, return_values, } = exec_results; @@ -608,7 +610,7 @@ async fn test_dev_inspect_dynamic_field() { assert!(effects.gas_cost_summary().computation_cost > 0); assert_eq!(results.len(), 1); let exec_results = results.pop().unwrap(); - let SuiExecutionResult { + let IotaExecutionResult { mutable_reference_outputs, return_values, } = exec_results; @@ -671,7 +673,7 @@ async fn test_dev_inspect_return_values() { let mut results = results.unwrap(); assert_eq!(results.len(), 1); let exec_results = results.pop().unwrap(); - let SuiExecutionResult { + let IotaExecutionResult { mutable_reference_outputs, mut return_values, } = exec_results; @@ -698,7 +700,7 @@ async fn test_dev_inspect_return_values() { let mut results = results.unwrap(); assert_eq!(results.len(), 1); let exec_results = results.pop().unwrap(); - let SuiExecutionResult { + let IotaExecutionResult { mutable_reference_outputs, mut return_values, } = exec_results; @@ -725,7 +727,7 @@ async fn test_dev_inspect_return_values() { let mut results = results.unwrap(); assert_eq!(results.len(), 1); let exec_results = results.pop().unwrap(); - let SuiExecutionResult { + let IotaExecutionResult { mutable_reference_outputs, mut return_values, } = exec_results; @@ -779,7 +781,7 @@ async fn test_dev_inspect_return_values() { let mut results = results.unwrap(); assert_eq!(results.len(), 1); let exec_results = results.pop().unwrap(); - let SuiExecutionResult { + let IotaExecutionResult { mutable_reference_outputs, mut return_values, } = exec_results; @@ -803,12 +805,12 @@ async fn test_dev_inspect_gas_coin_argument() { let epoch_store = validator.epoch_store_for_testing(); let protocol_config = epoch_store.protocol_config(); - let sender = SuiAddress::random_for_testing_only(); - let recipient = SuiAddress::random_for_testing_only(); + let sender = IotaAddress::random_for_testing_only(); + let recipient = IotaAddress::random_for_testing_only(); let amount = 500; let pt = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.pay_sui(vec![recipient], vec![amount]).unwrap(); + builder.pay_iota(vec![recipient], vec![amount]).unwrap(); builder.finish() }; let kind = TransactionKind::programmable(pt); @@ -820,14 +822,14 @@ async fn test_dev_inspect_gas_coin_argument() { .unwrap(); assert_eq!(results.len(), 2); // Split results - let SuiExecutionResult { + let IotaExecutionResult { mutable_reference_outputs, return_values, } = &results[0]; // check argument is the gas coin updated assert_eq!(mutable_reference_outputs.len(), 1); let (arg, arg_value, arg_type) = &mutable_reference_outputs[0]; - assert_eq!(arg, &SuiArgument::GasCoin); + assert_eq!(arg, &IotaArgument::GasCoin); check_coin_value( arg_value, arg_type, @@ -839,7 +841,7 @@ async fn test_dev_inspect_gas_coin_argument() { check_coin_value(ret_value, ret_type, amount); // Transfer results - let SuiExecutionResult { + let IotaExecutionResult { mutable_reference_outputs, return_values, } = &results[1]; @@ -852,12 +854,12 @@ async fn test_dev_inspect_gas_price() { let (_, fullnode, _object_basics) = init_state_with_ids_and_object_basics_with_fullnode(vec![]).await; - let sender = SuiAddress::random_for_testing_only(); - let recipient = SuiAddress::random_for_testing_only(); + let sender = IotaAddress::random_for_testing_only(); + let recipient = IotaAddress::random_for_testing_only(); let amount = 500; let pt = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.pay_sui(vec![recipient], vec![amount]).unwrap(); + builder.pay_iota(vec![recipient], vec![amount]).unwrap(); builder.finish() }; let kind = TransactionKind::programmable(pt); @@ -898,7 +900,7 @@ async fn test_dev_inspect_gas_price() { ); } -fn check_coin_value(actual_value: &[u8], actual_type: &SuiTypeTag, expected_value: u64) { +fn check_coin_value(actual_value: &[u8], actual_type: &IotaTypeTag, expected_value: u64) { let actual_type: TypeTag = actual_type.clone().try_into().unwrap(); assert_eq!(actual_type, TypeTag::Struct(Box::new(GasCoin::type_()))); let actual_coin: GasCoin = bcs::from_bytes(actual_value).unwrap(); @@ -1136,7 +1138,7 @@ async fn test_dry_run_dev_inspect_max_gas_version() { .dev_inspect_transaction_block(sender, kind, Some(rgp + 100), None, None, None, None, None) .await .unwrap(); - assert_eq!(effects.status(), &SuiExecutionStatus::Success); + assert_eq!(effects.status(), &IotaExecutionStatus::Success); // dry run let data = TransactionData::new_programmable( @@ -1150,7 +1152,7 @@ async fn test_dry_run_dev_inspect_max_gas_version() { let digest = *transaction.digest(); let DryRunTransactionBlockResponse { effects, .. } = fullnode.dry_exec_transaction(data, digest).await.unwrap().0; - assert_eq!(effects.status(), &SuiExecutionStatus::Success); + assert_eq!(effects.status(), &IotaExecutionStatus::Success); } #[tokio::test] @@ -1622,7 +1624,7 @@ async fn test_transfer_package() { .unwrap() .unwrap(); let package_object_ref = authority_state - .get_sui_system_package_object_ref() + .get_iota_system_package_object_ref() .await .unwrap(); // We are trying to transfer the genesis package object, which is immutable. @@ -1697,7 +1699,7 @@ async fn test_objected_owned_gas() { .insert_genesis_object(child_object.clone()) .await; let rgp = authority_state.reference_gas_price_for_testing().unwrap(); - let data = TransactionData::new_transfer_sui( + let data = TransactionData::new_transfer_iota( recipient, sender, None, @@ -2058,7 +2060,7 @@ async fn test_conflicting_transactions() { (second.unwrap(), first.unwrap_err()) }; - assert!(matches!(err, SuiError::ObjectLockConflict { .. })); + assert!(matches!(err, IotaError::ObjectLockConflict { .. })); let object_info = authority_state .handle_object_info_request(ObjectInfoRequest::latest_object_info_request( @@ -2149,7 +2151,7 @@ async fn test_handle_transfer_transaction_double_spend() { } #[tokio::test] -async fn test_handle_transfer_sui_with_amount_insufficient_gas() { +async fn test_handle_transfer_iota_with_amount_insufficient_gas() { let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); let recipient = dbg_addr(2); let object_id = ObjectID::random(); @@ -2160,7 +2162,7 @@ async fn test_handle_transfer_sui_with_amount_insufficient_gas() { .await .unwrap() .unwrap(); - let data = TransactionData::new_transfer_sui( + let data = TransactionData::new_transfer_iota( recipient, sender, Some(GAS_VALUE_FOR_TESTING), @@ -3038,7 +3040,7 @@ async fn test_refusal_to_sign_consensus_commit_prologue() { authority_state .handle_transaction(&epoch_store, transaction) .await, - Err(SuiError::InvalidSystemTransaction), + Err(IotaError::InvalidSystemTransaction), )); } @@ -3075,7 +3077,7 @@ async fn test_refusal_to_sign_consensus_commit_prologue_v2() { authority_state .handle_transaction(&epoch_store, transaction) .await, - Err(SuiError::InvalidSystemTransaction), + Err(IotaError::InvalidSystemTransaction), )); } @@ -3119,7 +3121,7 @@ async fn test_invalid_mutable_clock_parameter() { assert_eq!( UserInputError::try_from(e).unwrap(), UserInputError::ImmutableParameterExpectedError { - object_id: SUI_CLOCK_OBJECT_ID + object_id: IOTA_CLOCK_OBJECT_ID } ); } @@ -3165,7 +3167,7 @@ async fn test_invalid_authenticator_state_parameter() { assert_eq!( UserInputError::try_from(e).unwrap(), UserInputError::InaccessibleSystemObject { - object_id: SUI_AUTHENTICATOR_STATE_OBJECT_ID + object_id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID } ); } @@ -3186,7 +3188,7 @@ async fn test_invalid_randomness_parameter() { .unwrap() .unwrap(); let random_mut = CallArg::Object(ObjectArg::SharedObject { - id: SUI_RANDOMNESS_STATE_OBJECT_ID, + id: IOTA_RANDOMNESS_STATE_OBJECT_ID, initial_shared_version: init_random_version, mutable: true, }); @@ -3220,7 +3222,7 @@ async fn test_invalid_randomness_parameter() { assert_eq!( UserInputError::try_from(e).unwrap(), UserInputError::ImmutableParameterExpectedError { - object_id: SUI_RANDOMNESS_STATE_OBJECT_ID + object_id: IOTA_RANDOMNESS_STATE_OBJECT_ID } ); } @@ -3311,26 +3313,26 @@ async fn test_valid_immutable_clock_parameter() { } #[tokio::test] -async fn test_genesis_sui_system_state_object() { - // This test verifies that we can read the genesis SuiSystemState object. +async fn test_genesis_iota_system_state_object() { + // This test verifies that we can read the genesis IotaSystemState object. // And its Move layout matches the definition in Rust (so that we can // deserialize it). let authority_state = TestAuthorityBuilder::new().build().await; let wrapper = authority_state - .get_object(&SUI_SYSTEM_STATE_OBJECT_ID) + .get_object(&IOTA_SYSTEM_STATE_OBJECT_ID) .await .unwrap() .unwrap(); assert_eq!(wrapper.version(), SequenceNumber::from(1)); let move_object = wrapper.data.try_as_move().unwrap(); - let _sui_system_state = - bcs::from_bytes::(move_object.contents()).unwrap(); - assert!(move_object.type_().is(&SuiSystemStateWrapper::type_())); - let sui_system_state = authority_state - .get_sui_system_state_object_for_testing() + let _iota_system_state = + bcs::from_bytes::(move_object.contents()).unwrap(); + assert!(move_object.type_().is(&IotaSystemStateWrapper::type_())); + let iota_system_state = authority_state + .get_iota_system_state_object_for_testing() .unwrap(); assert_eq!( - &sui_system_state.get_current_epoch_committee().committee, + &iota_system_state.get_current_epoch_committee().committee, authority_state .epoch_store_for_testing() .committee() @@ -3339,19 +3341,19 @@ async fn test_genesis_sui_system_state_object() { } #[tokio::test] -async fn test_transfer_sui_no_amount() { +async fn test_transfer_iota_no_amount() { let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); let recipient = dbg_addr(2); let gas_object_id = ObjectID::random(); let gas_object = Object::with_id_owner_for_testing(gas_object_id, sender); - let init_balance = sui_types::gas::get_gas_balance(&gas_object).unwrap(); + let init_balance = iota_types::gas::get_gas_balance(&gas_object).unwrap(); let authority_state = init_state_with_objects(vec![gas_object.clone()]).await; let epoch_store = authority_state.load_epoch_store_one_call_per_task(); let rgp = epoch_store.reference_gas_price(); let gas_ref = gas_object.compute_object_reference(); - let tx_data = TransactionData::new_transfer_sui( + let tx_data = TransactionData::new_transfer_iota( recipient, sender, None, @@ -3381,7 +3383,7 @@ async fn test_transfer_sui_no_amount() { assert!(effects.mutated_excluding_gas().is_empty()); assert!(gas_ref.1 < effects.gas_object().0.1); assert_eq!(effects.gas_object().1, Owner::AddressOwner(recipient)); - let new_balance = sui_types::gas::get_gas_balance( + let new_balance = iota_types::gas::get_gas_balance( &authority_state .get_object(&gas_object_id) .await @@ -3396,17 +3398,17 @@ async fn test_transfer_sui_no_amount() { } #[tokio::test] -async fn test_transfer_sui_with_amount() { +async fn test_transfer_iota_with_amount() { let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); let recipient = dbg_addr(2); let gas_object_id = ObjectID::random(); let gas_object = Object::with_id_owner_for_testing(gas_object_id, sender); - let init_balance = sui_types::gas::get_gas_balance(&gas_object).unwrap(); + let init_balance = iota_types::gas::get_gas_balance(&gas_object).unwrap(); let authority_state = init_state_with_objects(vec![gas_object.clone()]).await; let rgp = authority_state.reference_gas_price_for_testing().unwrap(); let gas_ref = gas_object.compute_object_reference(); - let tx_data = TransactionData::new_transfer_sui( + let tx_data = TransactionData::new_transfer_iota( recipient, sender, Some(500), @@ -3432,10 +3434,10 @@ async fn test_transfer_sui_with_amount() { .await .unwrap() .unwrap(); - assert_eq!(sui_types::gas::get_gas_balance(&new_gas).unwrap(), 500); + assert_eq!(iota_types::gas::get_gas_balance(&new_gas).unwrap(), 500); assert!(gas_ref.1 < effects.gas_object().0.1); assert_eq!(effects.gas_object().1, Owner::AddressOwner(sender)); - let new_balance = sui_types::gas::get_gas_balance( + let new_balance = iota_types::gas::get_gas_balance( &authority_state .get_object(&gas_object_id) .await @@ -3450,8 +3452,8 @@ async fn test_transfer_sui_with_amount() { } #[tokio::test] -async fn test_store_revert_transfer_sui() { - // This test checks the correctness of revert_state_update in SuiDataStore. +async fn test_store_revert_transfer_iota() { + // This test checks the correctness of revert_state_update in IotaDataStore. let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); let (recipient, _sender_key): (_, AccountKeyPair) = get_key_pair(); let gas_object_id = ObjectID::random(); @@ -3460,7 +3462,7 @@ async fn test_store_revert_transfer_sui() { let authority_state = init_state_with_objects(vec![gas_object.clone()]).await; let rgp = authority_state.reference_gas_price_for_testing().unwrap(); - let tx_data = TransactionData::new_transfer_sui( + let tx_data = TransactionData::new_transfer_iota( recipient, sender, None, @@ -3670,7 +3672,7 @@ async fn test_store_get_dynamic_field() { assert_eq!(TypeTag::Bool, fields[0].name.type_) } -async fn create_and_retrieve_df_info(function: &IdentStr) -> (SuiAddress, Vec) { +async fn create_and_retrieve_df_info(function: &IdentStr) -> (IotaAddress, Vec) { let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); let gas_object_id = ObjectID::random(); let (authority_state, object_basics) = @@ -4253,7 +4255,7 @@ pub async fn init_state_with_objects_and_object_basics, + I: IntoIterator, >( objects: I, ) -> (Arc, ObjectRef) { @@ -4266,7 +4268,7 @@ pub async fn init_state_with_ids_and_object_basics< } async fn publish_object_basics(state: Arc) -> (Arc, ObjectRef) { - use sui_move_build::BuildConfig; + use iota_move_build::BuildConfig; // add object_basics package object to genesis, since lots of test use it let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); @@ -4291,11 +4293,11 @@ async fn publish_object_basics(state: Arc) -> (Arc, + I: IntoIterator, >( objects: I, ) -> (Arc, Arc, ObjectRef) { - use sui_move_build::BuildConfig; + use iota_move_build::BuildConfig; let (validator, fullnode) = init_state_validator_with_fullnode().await; for (address, object_id) in objects { @@ -4329,14 +4331,14 @@ pub async fn init_state_with_ids_and_object_basics_with_fullnode< pub async fn call_move( authority: &AuthorityState, gas_object_id: &ObjectID, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, package: &ObjectID, module: &'_ str, function: &'_ str, type_args: Vec, test_args: Vec, -) -> SuiResult { +) -> IotaResult { call_move_( authority, None, @@ -4357,7 +4359,7 @@ pub async fn call_move_( authority: &AuthorityState, fullnode: Option<&AuthorityState>, gas_object_id: &ObjectID, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, package: &ObjectID, module: &'_ str, @@ -4365,7 +4367,7 @@ pub async fn call_move_( type_args: Vec, test_args: Vec, with_shared: bool, // Move call includes shared objects -) -> SuiResult { +) -> IotaResult { let gas_object = authority.get_object(gas_object_id).await.unwrap(); let gas_object_ref = gas_object.unwrap().compute_object_reference(); let mut builder = ProgrammableTransactionBuilder::new(); @@ -4400,11 +4402,11 @@ pub async fn call_move_( pub async fn execute_programmable_transaction( authority: &AuthorityState, gas_object_id: &ObjectID, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, pt: ProgrammableTransaction, gas_unit: u64, -) -> SuiResult { +) -> IotaResult { execute_programmable_transaction_( authority, None, @@ -4422,11 +4424,11 @@ pub async fn execute_programmable_transaction( pub async fn execute_programmable_transaction_with_shared( authority: &AuthorityState, gas_object_id: &ObjectID, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, pt: ProgrammableTransaction, gas_unit: u64, -) -> SuiResult { +) -> IotaResult { execute_programmable_transaction_( authority, None, @@ -4444,11 +4446,11 @@ pub async fn execute_programmable_transaction_with_shared( pub async fn build_programmable_transaction( authority: &AuthorityState, gas_object_id: &ObjectID, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, pt: ProgrammableTransaction, gas_unit: u64, -) -> SuiResult { +) -> IotaResult { let rgp = authority.reference_gas_price_for_testing().unwrap(); let gas_object = authority.get_object(gas_object_id).await.unwrap(); let gas_object_ref = gas_object.unwrap().compute_object_reference(); @@ -4462,12 +4464,12 @@ async fn execute_programmable_transaction_( authority: &AuthorityState, fullnode: Option<&AuthorityState>, gas_object_id: &ObjectID, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, pt: ProgrammableTransaction, with_shared: bool, // Move call includes shared objects gas_unit: u64, -) -> SuiResult { +) -> IotaResult { let rgp = authority.reference_gas_price_for_testing().unwrap(); let gas_object = authority.get_object(gas_object_id).await.unwrap(); let gas_object_ref = gas_object.unwrap().compute_object_reference(); @@ -4487,7 +4489,7 @@ async fn call_move_with_gas_coins( fullnode: Option<&AuthorityState>, gas_object_ids: &[ObjectID], gas_budget: u64, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, package: &ObjectID, module: &'_ str, @@ -4495,7 +4497,7 @@ async fn call_move_with_gas_coins( type_args: Vec, test_args: Vec, with_shared: bool, // Move call includes shared objects -) -> SuiResult { +) -> IotaResult { let mut gas_object_refs = vec![]; for obj_id in gas_object_ids { let gas_object = authority.get_object(obj_id).await.unwrap(); @@ -4535,9 +4537,9 @@ pub async fn create_move_object( package_id: &ObjectID, authority: &AuthorityState, gas_object_id: &ObjectID, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, -) -> SuiResult { +) -> IotaResult { call_move( authority, gas_object_id, @@ -4560,9 +4562,9 @@ async fn create_move_object_with_gas_coins( authority: &AuthorityState, gas_object_ids: &[ObjectID], gas_budget: u64, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, -) -> SuiResult { +) -> IotaResult { call_move_with_gas_coins( authority, None, @@ -4588,9 +4590,9 @@ pub async fn wrap_object( authority: &AuthorityState, object_id: &ObjectID, gas_object_id: &ObjectID, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, -) -> SuiResult { +) -> IotaResult { call_move( authority, gas_object_id, @@ -4611,9 +4613,9 @@ pub async fn add_ofield( outer_object_id: &ObjectID, inner_object_id: &ObjectID, gas_object_id: &ObjectID, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, -) -> SuiResult { +) -> IotaResult { call_move( authority, gas_object_id, @@ -4633,13 +4635,13 @@ pub async fn add_ofield( pub async fn call_dev_inspect( authority: &AuthorityState, - sender: &SuiAddress, + sender: &IotaAddress, package: &ObjectID, module: &str, function: &str, type_arguments: Vec, test_args: Vec, -) -> SuiResult { +) -> IotaResult { let mut builder = ProgrammableTransactionBuilder::new(); let mut arguments = Vec::with_capacity(test_args.len()); for a in test_args { @@ -4668,7 +4670,7 @@ pub async fn call_dev_inspect( /// this may be fine. #[cfg(test)] async fn make_test_transaction( - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, shared_object_id: ObjectID, shared_object_initial_shared_version: SequenceNumber, @@ -4687,7 +4689,7 @@ async fn make_test_transaction( .unwrap(); let data = TransactionData::new_move_call( *sender, - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, ident_str!(module).to_owned(), ident_str!(function).to_owned(), // type_args @@ -4830,7 +4832,7 @@ async fn test_consensus_message_processed() { let shared_object_id = ObjectID::random(); let shared_object = { - use sui_types::object::MoveObject; + use iota_types::object::MoveObject; let obj = MoveObject::new_gas_coin(OBJECT_START_VERSION, shared_object_id, 10); let owner = Owner::Shared { initial_shared_version: obj.version(), @@ -4840,7 +4842,7 @@ async fn test_consensus_message_processed() { let initial_shared_version = shared_object.version(); let dir = tempfile::TempDir::new().unwrap(); - let network_config = sui_swarm_config::network_config_builder::ConfigBuilder::new(&dir) + let network_config = iota_swarm_config::network_config_builder::ConfigBuilder::new(&dir) .committee_size(2.try_into().unwrap()) .with_objects(vec![gas_object.clone(), shared_object.clone()]) .build(); @@ -5203,7 +5205,7 @@ async fn test_gas_smashing() { // run a create move object transaction with a given set o gas coins and a // budget async fn create_obj( - sender: SuiAddress, + sender: IotaAddress, sender_key: AccountKeyPair, gas_coins: Vec, gas_budget: u64, @@ -5224,7 +5226,7 @@ async fn test_gas_smashing() { } // make a `coin_num` coins distributing `gas_amount` across them - fn make_gas_coins(owner: SuiAddress, gas_amount: u64, coin_num: u64) -> Vec { + fn make_gas_coins(owner: IotaAddress, gas_amount: u64, coin_num: u64) -> Vec { let mut objects = vec![]; let coin_balance = gas_amount / coin_num; for _ in 1..coin_num { @@ -5282,7 +5284,7 @@ async fn test_gas_smashing() { ); } // balance on first coin is correct - let balance = sui_types::gas::get_gas_balance( + let balance = iota_types::gas::get_gas_balance( &state.get_object(&gas_coin_ids[0]).await.unwrap().unwrap(), ) .unwrap(); @@ -5312,7 +5314,7 @@ async fn test_gas_smashing() { #[tokio::test] async fn test_for_inc_201_dev_inspect() { - use sui_move_build::BuildConfig; + use iota_move_build::BuildConfig; let (sender, _sender_key): (_, AccountKeyPair) = get_key_pair(); let gas_object_id = ObjectID::random(); @@ -5357,7 +5359,7 @@ async fn test_for_inc_201_dev_inspect() { #[tokio::test] async fn test_for_inc_201_dry_run() { - use sui_move_build::BuildConfig; + use iota_move_build::BuildConfig; let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); let gas_object_id = ObjectID::random(); @@ -5400,7 +5402,7 @@ async fn test_for_inc_201_dry_run() { ) .await .unwrap(); - assert_eq!(effects.status(), &SuiExecutionStatus::Success); + assert_eq!(effects.status(), &IotaExecutionStatus::Success); assert_eq!(1, events.data.len()); assert_eq!( @@ -5412,7 +5414,7 @@ async fn test_for_inc_201_dry_run() { #[tokio::test] async fn test_publish_transitive_dependencies_ok() { - use sui_move_build::BuildConfig; + use iota_move_build::BuildConfig; let (sender, key): (_, AccountKeyPair) = get_key_pair(); let gas_id = ObjectID::random(); @@ -5585,7 +5587,7 @@ async fn test_publish_transitive_dependencies_ok() { #[tokio::test] async fn test_publish_missing_dependency() { - use sui_move_build::BuildConfig; + use iota_move_build::BuildConfig; let (sender, key): (_, AccountKeyPair) = get_key_pair(); let gas_id = ObjectID::random(); @@ -5605,7 +5607,7 @@ async fn test_publish_missing_dependency() { .get_package_bytes(/* with_unpublished_deps */ false); let mut builder = ProgrammableTransactionBuilder::new(); - builder.publish_immutable(modules, vec![SUI_FRAMEWORK_PACKAGE_ID]); + builder.publish_immutable(modules, vec![IOTA_FRAMEWORK_PACKAGE_ID]); let kind = TransactionKind::programmable(builder.finish()); let rgp = state.reference_gas_price_for_testing().unwrap(); @@ -5634,7 +5636,7 @@ async fn test_publish_missing_dependency() { #[tokio::test] async fn test_publish_missing_transitive_dependency() { - use sui_move_build::BuildConfig; + use iota_move_build::BuildConfig; let (sender, key): (_, AccountKeyPair) = get_key_pair(); let gas_id = ObjectID::random(); @@ -5683,7 +5685,7 @@ async fn test_publish_missing_transitive_dependency() { #[tokio::test] async fn test_publish_not_a_package_dependency() { - use sui_move_build::BuildConfig; + use iota_move_build::BuildConfig; let (sender, key): (_, AccountKeyPair) = get_key_pair(); let gas_id = ObjectID::random(); @@ -5705,7 +5707,7 @@ async fn test_publish_not_a_package_dependency() { let mut builder = ProgrammableTransactionBuilder::new(); let mut deps = BuiltInFramework::all_package_ids(); // One of these things is not like the others - deps.push(SUI_SYSTEM_STATE_OBJECT_ID); + deps.push(IOTA_SYSTEM_STATE_OBJECT_ID); builder.publish_immutable(modules, deps); let kind = TransactionKind::programmable(builder.finish()); @@ -5724,9 +5726,9 @@ async fn test_publish_not_a_package_dependency() { .unwrap_err(); assert_eq!( - SuiError::UserInputError { + IotaError::UserInputError { error: UserInputError::MoveObjectAsPackage { - object_id: SUI_SYSTEM_STATE_OBJECT_ID + object_id: IOTA_SYSTEM_STATE_OBJECT_ID } }, failure, diff --git a/crates/sui-core/src/unit_tests/batch_transaction_tests.rs b/crates/iota-core/src/unit_tests/batch_transaction_tests.rs similarity index 99% rename from crates/sui-core/src/unit_tests/batch_transaction_tests.rs rename to crates/iota-core/src/unit_tests/batch_transaction_tests.rs index 2539f56e07a..05777e47308 100644 --- a/crates/sui-core/src/unit_tests/batch_transaction_tests.rs +++ b/crates/iota-core/src/unit_tests/batch_transaction_tests.rs @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use authority_tests::send_and_confirm_transaction; use bcs; -use move_core_types::{account_address::AccountAddress, ident_str}; -use sui_types::{ +use iota_types::{ crypto::{get_key_pair, AccountKeyPair}, execution_status::ExecutionStatus, object::Owner, programmable_transaction_builder::ProgrammableTransactionBuilder, utils::to_sender_signed_transaction, }; +use move_core_types::{account_address::AccountAddress, ident_str}; use super::*; use crate::authority::authority_tests::init_state_with_ids_and_object_basics; diff --git a/crates/sui-core/src/unit_tests/batch_verification_tests.rs b/crates/iota-core/src/unit_tests/batch_verification_tests.rs similarity index 98% rename from crates/sui-core/src/unit_tests/batch_verification_tests.rs rename to crates/iota-core/src/unit_tests/batch_verification_tests.rs index 50f5a01adcf..871705ce3d9 100644 --- a/crates/sui-core/src/unit_tests/batch_verification_tests.rs +++ b/crates/iota-core/src/unit_tests/batch_verification_tests.rs @@ -1,20 +1,21 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; use fastcrypto::traits::KeyPair; use futures::future::join_all; -use prometheus::Registry; -use rand::{thread_rng, Rng}; -use sui_macros::sim_test; -use sui_types::{ +use iota_macros::sim_test; +use iota_types::{ committee::Committee, crypto::{get_key_pair, AccountKeyPair, AuthorityKeyPair}, gas::GasCostSummary, messages_checkpoint::{CheckpointContents, CheckpointSummary, SignedCheckpointSummary}, transaction::CertifiedTransaction, }; +use prometheus::Registry; +use rand::{thread_rng, Rng}; use crate::{ signature_verifier::*, diff --git a/crates/sui-core/src/unit_tests/consensus_tests.rs b/crates/iota-core/src/unit_tests/consensus_tests.rs similarity index 97% rename from crates/sui-core/src/unit_tests/consensus_tests.rs rename to crates/iota-core/src/unit_tests/consensus_tests.rs index 086ee98554a..a0ba95edc28 100644 --- a/crates/sui-core/src/unit_tests/consensus_tests.rs +++ b/crates/iota-core/src/unit_tests/consensus_tests.rs @@ -1,10 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use move_core_types::{account_address::AccountAddress, ident_str}; -use narwhal_types::{Empty, TransactionProto, Transactions, TransactionsServer}; -use sui_network::tonic; -use sui_types::{ +use iota_network::tonic; +use iota_types::{ base_types::ObjectID, crypto::deterministic_random_account_key, multiaddr::Multiaddr, @@ -14,8 +13,10 @@ use sui_types::{ TEST_ONLY_GAS_UNIT_FOR_OBJECT_BASICS, }, utils::to_sender_signed_transaction, - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, }; +use move_core_types::{account_address::AccountAddress, ident_str}; +use narwhal_types::{Empty, TransactionProto, Transactions, TransactionsServer}; use tokio::sync::mpsc::{channel, Receiver, Sender}; use super::*; @@ -66,7 +67,7 @@ pub async fn test_certificates(authority: &AuthorityState) -> Vec, - ) -> SuiResult { + ) -> IotaResult { epoch_store .process_consensus_transactions_for_tests( vec![SequencedConsensusTransaction::new_test(transaction.clone())], diff --git a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest/Move.toml b/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/custom_properties_in_manifest/Move.toml rename to crates/iota-core/src/unit_tests/data/custom_properties_in_manifest/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest/sources/main.move b/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest/sources/main.move new file mode 100644 index 00000000000..3c72cbaad73 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest/sources/main.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module main::main { + public entry fun main() {} +} diff --git a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/Move.toml b/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/Move.toml rename to crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/sources/main.move b/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/sources/main.move new file mode 100644 index 00000000000..3c72cbaad73 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/sources/main.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module main::main { + public entry fun main() {} +} diff --git a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/Move.toml b/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/Move.toml rename to crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/sources/main.move b/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/sources/main.move new file mode 100644 index 00000000000..3c72cbaad73 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/sources/main.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module main::main { + public entry fun main() {} +} diff --git a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/Move.toml b/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/Move.toml rename to crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/sources/main.move b/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/sources/main.move new file mode 100644 index 00000000000..3c72cbaad73 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/sources/main.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module main::main { + public entry fun main() {} +} diff --git a/crates/iota-core/src/unit_tests/data/depends_on_basics/Move.toml b/crates/iota-core/src/unit_tests/data/depends_on_basics/Move.toml new file mode 100644 index 00000000000..859988c12e6 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/depends_on_basics/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "DependsOnBasics" +version = "0.0.0" + +[dependencies] +Examples = { local = "../object_basics" } +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +depends = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/depends_on_basics/sources/depends_on_basics.move b/crates/iota-core/src/unit_tests/data/depends_on_basics/sources/depends_on_basics.move new file mode 100644 index 00000000000..18d7edcec7b --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/depends_on_basics/sources/depends_on_basics.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Test depending on another unpublished package, which is published +/// along with your own. +module depends::depends_on_basics { + use examples::object_basics; + use iota::tx_context::TxContext; + + public entry fun delegate(ctx: &mut TxContext) { + object_basics::share(ctx); + } +} diff --git a/crates/iota-core/src/unit_tests/data/entry_point_types/Move.lock b/crates/iota-core/src/unit_tests/data/entry_point_types/Move.lock new file mode 100644 index 00000000000..a67bae5ad12 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/entry_point_types/Move.lock @@ -0,0 +1,22 @@ +# @generated by Move, please check-in and do not edit manually. + +[move] +version = 0 +manifest_digest = "767739C9147CAC379CE17A273955EE03EF28351CE7D26C3C286A02AAA14FB302" +deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082" + +dependencies = [ + { name = "Iota" }, +] + +[[move.package]] +name = "MoveStdlib" +source = { local = "../../../../../iota-framework/packages/move-stdlib" } + +[[move.package]] +name = "Iota" +source = { local = "../../../../../iota-framework/packages/iota-framework" } + +dependencies = [ + { name = "MoveStdlib" }, +] diff --git a/crates/iota-core/src/unit_tests/data/entry_point_types/Move.toml b/crates/iota-core/src/unit_tests/data/entry_point_types/Move.toml new file mode 100644 index 00000000000..eb3d07bec19 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/entry_point_types/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "entry_point_types" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +entry_point_types = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/entry_point_types/sources/entry_point_types.move b/crates/iota-core/src/unit_tests/data/entry_point_types/sources/entry_point_types.move similarity index 94% rename from crates/sui-core/src/unit_tests/data/entry_point_types/sources/entry_point_types.move rename to crates/iota-core/src/unit_tests/data/entry_point_types/sources/entry_point_types.move index a3b4069aa7d..37f379f610e 100644 --- a/crates/sui-core/src/unit_tests/data/entry_point_types/sources/entry_point_types.move +++ b/crates/iota-core/src/unit_tests/data/entry_point_types/sources/entry_point_types.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module entry_point_types::entry_point_types { use std::ascii; use std::string; - use sui::tx_context::TxContext; + use iota::tx_context::TxContext; use std::vector; use std::option::Option; diff --git a/crates/iota-core/src/unit_tests/data/entry_point_vector/Move.lock b/crates/iota-core/src/unit_tests/data/entry_point_vector/Move.lock new file mode 100644 index 00000000000..18a8cfbd4af --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/entry_point_vector/Move.lock @@ -0,0 +1,22 @@ +# @generated by Move, please check-in and do not edit manually. + +[move] +version = 0 +manifest_digest = "5EDC4495EB1E648D2099207F79D616639179085FA517FC2CE705753805534B04" +deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082" + +dependencies = [ + { name = "Iota" }, +] + +[[move.package]] +name = "MoveStdlib" +source = { local = "../../../../../iota-framework/packages/move-stdlib" } + +[[move.package]] +name = "Iota" +source = { local = "../../../../../iota-framework/packages/iota-framework" } + +dependencies = [ + { name = "MoveStdlib" }, +] diff --git a/crates/iota-core/src/unit_tests/data/entry_point_vector/Move.toml b/crates/iota-core/src/unit_tests/data/entry_point_vector/Move.toml new file mode 100644 index 00000000000..1fbe310f8d7 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/entry_point_vector/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "entry_point_vector" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +entry_point_vector = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/entry_point_vector/sources/objects_vector.move b/crates/iota-core/src/unit_tests/data/entry_point_vector/sources/objects_vector.move similarity index 96% rename from crates/sui-core/src/unit_tests/data/entry_point_vector/sources/objects_vector.move rename to crates/iota-core/src/unit_tests/data/entry_point_vector/sources/objects_vector.move index e54fef4113b..c1c8bda5089 100644 --- a/crates/sui-core/src/unit_tests/data/entry_point_vector/sources/objects_vector.move +++ b/crates/iota-core/src/unit_tests/data/entry_point_vector/sources/objects_vector.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module entry_point_vector::entry_point_vector { - use sui::object::{Self, UID}; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; + use iota::object::{Self, UID}; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; use std::vector; struct Obj has key, store { @@ -50,7 +51,7 @@ module entry_point_vector::entry_point_vector { } public entry fun mint_child(v: u64, parent: &mut Obj, ctx: &mut TxContext) { - sui::dynamic_object_field::add( + iota::dynamic_object_field::add( &mut parent.id, 0, Obj { id: object::new(ctx), @@ -144,7 +145,7 @@ module entry_point_vector::entry_point_vector { } public entry fun mint_child_any(v: u64, parent: &mut ObjAny, ctx: &mut TxContext) { - sui::dynamic_object_field::add( + iota::dynamic_object_field::add( &mut parent.id, 0, ObjAny { diff --git a/crates/iota-core/src/unit_tests/data/generate_move_lock_file/Move.toml b/crates/iota-core/src/unit_tests/data/generate_move_lock_file/Move.toml new file mode 100644 index 00000000000..96ffb797147 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/generate_move_lock_file/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "GenerateMoveLockFile" +version = "0.0.0" + +[dependencies] +Examples = { local = "../object_basics" } +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +depends = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/generate_move_lock_file/sources/depends_on_basics.move b/crates/iota-core/src/unit_tests/data/generate_move_lock_file/sources/depends_on_basics.move new file mode 100644 index 00000000000..9ab4e9a6a37 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/generate_move_lock_file/sources/depends_on_basics.move @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Create a dependency on a package to test Move.lock generation. +module depends::depends_on_basics { + use examples::object_basics; + use iota::tx_context::TxContext; + + public entry fun delegate(ctx: &mut TxContext) { + object_basics::share(ctx); + } +} diff --git a/crates/iota-core/src/unit_tests/data/managed_coin/Move.toml b/crates/iota-core/src/unit_tests/data/managed_coin/Move.toml new file mode 100644 index 00000000000..f6439c8093e --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/managed_coin/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "FungibleTokens" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +fungible_tokens = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/managed_coin/sources/managed.move b/crates/iota-core/src/unit_tests/data/managed_coin/sources/managed.move new file mode 100644 index 00000000000..7c45a3e79c1 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/managed_coin/sources/managed.move @@ -0,0 +1,76 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// A module to test coin index. +module fungible_tokens::managed { + use std::option; + use iota::coin::{Self, Coin, TreasuryCap}; + use iota::transfer; + use iota::object::{Self, UID}; + use iota::table_vec::{Self, TableVec}; + use iota::tx_context::{Self, TxContext}; + + struct PublicRedEnvelope has key, store { + id: UID, + coins: TableVec>, + } + + /// Name of the coin. By convention, this type has the same name as its parent module + /// and has no fields. The full type of the coin defined by this module will be `COIN`. + struct MANAGED has drop {} + + /// Register the managed currency to acquire its `TreasuryCap`. Because + /// this is a module initializer, it ensures the currency only gets + /// registered once. + fun init(witness: MANAGED, ctx: &mut TxContext) { + // Get a treasury cap for the coin and give it to the transaction sender + let (treasury_cap, metadata) = coin::create_currency(witness, 2, b"MANAGED", b"", b"", option::none(), ctx); + transfer::public_freeze_object(metadata); + transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); + + let red_envelopes = PublicRedEnvelope { id: object::new(ctx), coins: table_vec::empty(ctx) }; + transfer::share_object(red_envelopes) + } + + public entry fun mint( + treasury_cap: &mut TreasuryCap, amount: u64, recipient: address, ctx: &mut TxContext + ) { + coin::mint_and_transfer(treasury_cap, amount, recipient, ctx) + } + + public entry fun mint_multi( + treasury_cap: &mut TreasuryCap, amount: u64, num: u64, recipient: address, ctx: &mut TxContext + ) { + let i = 0; + while (i < num) { + coin::mint_and_transfer(treasury_cap, amount, recipient, ctx); + i = i + 1; + } + } + + public entry fun add_to_envelope( + red_envelopes: &mut PublicRedEnvelope, coin: Coin, + ) { + table_vec::push_back(&mut red_envelopes.coins, coin) + } + + public entry fun take_from_envelope( + red_envelopes: &mut PublicRedEnvelope, ctx: &mut TxContext + ) { + let coin = table_vec::pop_back(&mut red_envelopes.coins); + transfer::public_transfer(coin, tx_context::sender(ctx)) + } + + public entry fun take_from_envelope_and_burn( + treasury_cap: &mut TreasuryCap, + red_envelopes: &mut PublicRedEnvelope, + ) { + let coin = table_vec::pop_back(&mut red_envelopes.coins); + coin::burn(treasury_cap, coin); + } + + public entry fun burn(treasury_cap: &mut TreasuryCap, coin: Coin) { + coin::burn(treasury_cap, coin); + } +} diff --git a/crates/sui-core/src/unit_tests/data/move_package/A/Move.toml b/crates/iota-core/src/unit_tests/data/move_package/A/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_package/A/Move.toml rename to crates/iota-core/src/unit_tests/data/move_package/A/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_package/A/sources/a.move b/crates/iota-core/src/unit_tests/data/move_package/A/sources/a.move new file mode 100644 index 00000000000..9f2553016b6 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_package/A/sources/a.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module a::a { + public fun a(): u64 { + b::b::b() + } +} diff --git a/crates/sui-core/src/unit_tests/data/move_package/B/Move.toml b/crates/iota-core/src/unit_tests/data/move_package/B/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_package/B/Move.toml rename to crates/iota-core/src/unit_tests/data/move_package/B/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_package/B/sources/b.move b/crates/iota-core/src/unit_tests/data/move_package/B/sources/b.move new file mode 100644 index 00000000000..8551397ed90 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_package/B/sources/b.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::b { + public fun b(): u64 { + c::c::c() + } +} diff --git a/crates/sui-core/src/unit_tests/data/move_package/Bv2/Move.toml b/crates/iota-core/src/unit_tests/data/move_package/Bv2/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_package/Bv2/Move.toml rename to crates/iota-core/src/unit_tests/data/move_package/Bv2/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_package/Bv2/sources/b.move b/crates/iota-core/src/unit_tests/data/move_package/Bv2/sources/b.move new file mode 100644 index 00000000000..8551397ed90 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_package/Bv2/sources/b.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::b { + public fun b(): u64 { + c::c::c() + } +} diff --git a/crates/sui-core/src/unit_tests/data/move_package/Cv1/Move.toml b/crates/iota-core/src/unit_tests/data/move_package/Cv1/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_package/Cv1/Move.toml rename to crates/iota-core/src/unit_tests/data/move_package/Cv1/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_package/Cv1/sources/c.move b/crates/iota-core/src/unit_tests/data/move_package/Cv1/sources/c.move new file mode 100644 index 00000000000..3cbfce09279 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_package/Cv1/sources/c.move @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module c::c { + struct C { + x: u64 + } + + public fun c(): u64 { + 42 + } +} diff --git a/crates/sui-core/src/unit_tests/data/move_package/Cv2/Move.toml b/crates/iota-core/src/unit_tests/data/move_package/Cv2/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_package/Cv2/Move.toml rename to crates/iota-core/src/unit_tests/data/move_package/Cv2/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_package/Cv2/sources/c.move b/crates/iota-core/src/unit_tests/data/move_package/Cv2/sources/c.move new file mode 100644 index 00000000000..85d95aa9a8a --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_package/Cv2/sources/c.move @@ -0,0 +1,18 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module c::c { + struct C { + x: u64 + } + + struct D { + x: u64, + y: u64, + } + + public fun c(): u64 { + 43 + } +} diff --git a/crates/iota-core/src/unit_tests/data/move_random/Move.toml b/crates/iota-core/src/unit_tests/data/move_random/Move.toml new file mode 100644 index 00000000000..73e85620763 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_random/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "Examples" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +examples = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/move_random/sources/move_random.move b/crates/iota-core/src/unit_tests/data/move_random/sources/move_random.move similarity index 84% rename from crates/sui-core/src/unit_tests/data/move_random/sources/move_random.move rename to crates/iota-core/src/unit_tests/data/move_random/sources/move_random.move index c70df9a3590..66291b69804 100644 --- a/crates/sui-core/src/unit_tests/data/move_random/sources/move_random.move +++ b/crates/iota-core/src/unit_tests/data/move_random/sources/move_random.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module examples::move_random { use std::vector; - use sui::object::{Self, UID}; - use sui::transfer; - use sui::tx_context::TxContext; + use iota::object::{Self, UID}; + use iota::transfer; + use iota::tx_context::TxContext; struct Object has key, store { id: UID, diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade/Move.toml rename to crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade/sources/base.move new file mode 100644 index 00000000000..418ad037ff8 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade/sources/base.move @@ -0,0 +1,32 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + + struct A { + f1: bool, + f2: T + } + + // new struct is fine + struct B { + f2: bool, + f1: T, + } + + friend base_addr::friend_module; + + // new function is fine + public fun return_1(): u64 { 1 } + + public fun return_0(): u64 { abort 42 } + + public fun plus_1(x: u64): u64 { x + 1 } + + public(friend) fun friend_fun(x: u64): u64 { x } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } + + entry fun entry_fun() { } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade/sources/friend_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade/sources/friend_module.move new file mode 100644 index 00000000000..ed97c439499 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade/sources/friend_module.move @@ -0,0 +1,19 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::friend_module { + + struct A { + field1: u64, + field2: T + } + + public fun friend_call(): u64 { base_addr::base::friend_fun(1) } + + public fun return_0(): u64 { 0 } + + public fun plus_1(x: u64): u64 { x + 1 } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } +} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/Move.toml rename to crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/sources/base.move new file mode 100644 index 00000000000..1e96f42e606 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/sources/base.move @@ -0,0 +1,33 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + + struct A { + f1: bool, + f2: T + } + + // new struct is fine + struct B { + f2: bool, + f1: T, + } + + friend base_addr::friend_module; + + // new function is fine + public fun return_1(): u64 { 1 } + + public fun return_0(): u64 { 0 } + + public fun plus_1(x: u64): u64 { x + 1 } + + public(friend) fun friend_fun(x: u64): u64 { x } + + // This is invalid since I just changed the code + fun non_public_fun(y: bool): u64 { if (y) 0 else 2 } + + entry fun entry_fun() { } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/sources/friend_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/sources/friend_module.move new file mode 100644 index 00000000000..ed97c439499 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/sources/friend_module.move @@ -0,0 +1,19 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::friend_module { + + struct A { + field1: u64, + field2: T + } + + public fun friend_call(): u64 { base_addr::base::friend_fun(1) } + + public fun return_0(): u64 { 0 } + + public fun plus_1(x: u64): u64 { x + 1 } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } +} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/base/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/base/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_upgrade/base/Move.toml rename to crates/iota-core/src/unit_tests/data/move_upgrade/base/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/base/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/base/sources/base.move new file mode 100644 index 00000000000..60065d2acf8 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/base/sources/base.move @@ -0,0 +1,23 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + + struct A { + f1: bool, + f2: T + } + + friend base_addr::friend_module; + + public fun return_0(): u64 { abort 42 } + + public fun plus_1(x: u64): u64 { x + 1 } + + public(friend) fun friend_fun(x: u64): u64 { x } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } + + entry fun entry_fun() { } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/base/sources/friend_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/base/sources/friend_module.move new file mode 100644 index 00000000000..ed97c439499 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/base/sources/friend_module.move @@ -0,0 +1,19 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::friend_module { + + struct A { + field1: u64, + field2: T + } + + public fun friend_call(): u64 { base_addr::base::friend_fun(1) } + + public fun return_0(): u64 { 0 } + + public fun plus_1(x: u64): u64 { x + 1 } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } +} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/base_as_dep/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/base_as_dep/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_upgrade/base_as_dep/Move.toml rename to crates/iota-core/src/unit_tests/data/move_upgrade/base_as_dep/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/base_as_dep/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/base_as_dep/sources/base.move new file mode 100644 index 00000000000..21dea76bb67 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/base_as_dep/sources/base.move @@ -0,0 +1,23 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + + struct A { + f1: bool, + f2: T + } + + friend base_addr::friend_module; + + public fun return_0(): u64 { 0 } + + public fun plus_1(x: u64): u64 { x + 1 } + + public(friend) fun friend_fun(x: u64): u64 { x } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } + + entry fun entry_fun() { } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/base_as_dep/sources/friend_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/base_as_dep/sources/friend_module.move new file mode 100644 index 00000000000..ed97c439499 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/base_as_dep/sources/friend_module.move @@ -0,0 +1,19 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::friend_module { + + struct A { + field1: u64, + field2: T + } + + public fun friend_call(): u64 { base_addr::base::friend_fun(1) } + + public fun return_0(): u64 { 0 } + + public fun plus_1(x: u64): u64 { x + 1 } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } +} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/compatibility_invalid/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/compatibility_invalid/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_upgrade/compatibility_invalid/Move.toml rename to crates/iota-core/src/unit_tests/data/move_upgrade/compatibility_invalid/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/compatibility_invalid/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/compatibility_invalid/sources/base.move new file mode 100644 index 00000000000..2e132ad2c3f --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/compatibility_invalid/sources/base.move @@ -0,0 +1,23 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + + struct A { + f1: bool, + f2: T + } + + friend base_addr::friend_module; + + public fun return_0(): u64 { 0 } + + public fun plus_1(x: u64, y: u64): u64 { x + y } + + public(friend) fun friend_fun(x: u64): u64 { x } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } + + entry fun entry_fun() { } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/compatibility_invalid/sources/friend_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/compatibility_invalid/sources/friend_module.move new file mode 100644 index 00000000000..ed97c439499 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/compatibility_invalid/sources/friend_module.move @@ -0,0 +1,19 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::friend_module { + + struct A { + field1: u64, + field2: T + } + + public fun friend_call(): u64 { base_addr::base::friend_fun(1) } + + public fun return_0(): u64 { 0 } + + public fun plus_1(x: u64): u64 { x + 1 } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } +} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_dep/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_dep/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_dep/Move.toml rename to crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_dep/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_dep/sources/my_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_dep/sources/my_module.move new file mode 100644 index 00000000000..22f2e1f5e0b --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_dep/sources/my_module.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module a::my_module { + use dep_on_upgrading_package::my_module; + + public fun call_return_0(): u64 { my_module::call_return_0() } +} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package/Move.toml rename to crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package/sources/my_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package/sources/my_module.move new file mode 100644 index 00000000000..6f7ae12b811 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package/sources/my_module.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module dep_on_upgrading_package::my_module { + use base_addr::base; + + public fun call_return_0(): u64 { base::return_0() } +} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_transitive/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_transitive/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_transitive/Move.toml rename to crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_transitive/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_transitive/sources/my_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_transitive/sources/my_module.move new file mode 100644 index 00000000000..882438a3ba0 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_transitive/sources/my_module.move @@ -0,0 +1,10 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module dep_on_upgrading_package_transitive::my_module { + use base_addr::base; + use dep_on_upgrading_package::my_module; + + public fun call_return_0(): u64 { my_module::call_return_0() + base::return_0() } +} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_upgradeable/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_upgradeable/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_upgradeable/Move.toml rename to crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_upgradeable/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_upgradeable/sources/my_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_upgradeable/sources/my_module.move new file mode 100644 index 00000000000..6f7ae12b811 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_upgradeable/sources/my_module.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module dep_on_upgrading_package::my_module { + use base_addr::base; + + public fun call_return_0(): u64 { base::return_0() } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/Move.toml new file mode 100644 index 00000000000..2ebdbfa3af5 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "package_upgrade_base" +version = "0.0.1" + +[addresses] +base_addr = "0x0" + +[dependencies] +Iota = { local = "../../../../../../iota-framework/packages/iota-framework" } diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/sources/base.move new file mode 100644 index 00000000000..60065d2acf8 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/sources/base.move @@ -0,0 +1,23 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + + struct A { + f1: bool, + f2: T + } + + friend base_addr::friend_module; + + public fun return_0(): u64 { abort 42 } + + public fun plus_1(x: u64): u64 { x + 1 } + + public(friend) fun friend_fun(x: u64): u64 { x } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } + + entry fun entry_fun() { } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/sources/friend_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/sources/friend_module.move new file mode 100644 index 00000000000..ed97c439499 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/sources/friend_module.move @@ -0,0 +1,19 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::friend_module { + + struct A { + field1: u64, + field2: T + } + + public fun friend_call(): u64 { base_addr::base::friend_fun(1) } + + public fun return_0(): u64 { 0 } + + public fun plus_1(x: u64): u64 { x + 1 } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/makes_another_object/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/makes_another_object/Move.toml new file mode 100644 index 00000000000..2f94c149a3d --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/makes_another_object/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "makes_another_object" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../../iota-framework/packages/iota-framework" } + +[addresses] +base_addr = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/makes_another_object/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/makes_another_object/sources/base.move new file mode 100644 index 00000000000..f4f06ee5ebc --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/makes_another_object/sources/base.move @@ -0,0 +1,78 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + use iota::object::{Self, UID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer; + use iota::event; + + struct A { + f1: bool, + f2: T + } + + struct B has key { + id: UID, + x: u64, + } + + struct BModEvent has copy, drop { + old: u64, + new: u64, + } + + struct C has key { + id: UID, + x: u64, + } + + struct CModEvent has copy, drop { + old: u64, + new: u64, + } + + friend base_addr::friend_module; + + public fun return_0(): u64 { abort 42 } + + public fun plus_1(x: u64): u64 { x + 1 } + + public(friend) fun friend_fun(x: u64): u64 { x } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } + + entry fun makes_b(ctx: &mut TxContext) { + transfer::transfer( + B { id: object::new(ctx), x: 42 }, + tx_context::sender(ctx), + ) + } + + entry fun destroys_b(b: B) { + let B { id, x: _ } = b; + object::delete(id); + } + + entry fun modifies_b(b: B, ctx: &mut TxContext) { + event::emit(BModEvent{ old: b.x, new: 7 }); + b.x = 7; + transfer::transfer(b, tx_context::sender(ctx)) + } + + entry fun makes_c(ctx: &mut TxContext) { + transfer::transfer( + C { id: object::new(ctx), x: 42 }, + tx_context::sender(ctx), + ) + } + + entry fun modifies_c(c: C, ctx: &mut TxContext) { + event::emit(CModEvent{ old: c.x, new: 7 }); + c.x = 7; + transfer::transfer(c, tx_context::sender(ctx)) + } + + +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/makes_another_object/sources/friend_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/makes_another_object/sources/friend_module.move new file mode 100644 index 00000000000..ed97c439499 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/makes_another_object/sources/friend_module.move @@ -0,0 +1,19 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::friend_module { + + struct A { + field1: u64, + field2: T + } + + public fun friend_call(): u64 { base_addr::base::friend_fun(1) } + + public fun return_0(): u64 { 0 } + + public fun plus_1(x: u64): u64 { x + 1 } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/makes_new_object/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/makes_new_object/Move.toml new file mode 100644 index 00000000000..df58f49a9bf --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/makes_new_object/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "makes_new_object" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../../iota-framework/packages/iota-framework" } + +[addresses] +base_addr = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/makes_new_object/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/makes_new_object/sources/base.move new file mode 100644 index 00000000000..f8a0ca22147 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/makes_new_object/sources/base.move @@ -0,0 +1,54 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + use iota::object::{Self, UID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer; + use iota::event; + + struct A { + f1: bool, + f2: T + } + + struct B has key { + id: UID, + x: u64, + } + + struct BModEvent has copy, drop { + old: u64, + new: u64, + } + + friend base_addr::friend_module; + + public fun return_0(): u64 { abort 42 } + + public fun plus_1(x: u64): u64 { x + 1 } + + public(friend) fun friend_fun(x: u64): u64 { x } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } + + entry fun makes_b(ctx: &mut TxContext) { + transfer::transfer( + B { id: object::new(ctx), x: 42 }, + tx_context::sender(ctx), + ) + } + + entry fun destroys_b(b: B) { + let B { id, x: _ } = b; + object::delete(id); + } + + entry fun modifies_b(b: B, ctx: &mut TxContext) { + event::emit(BModEvent{ old: b.x, new: 7 }); + b.x = 7; + transfer::transfer(b, tx_context::sender(ctx)) + } + +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/makes_new_object/sources/friend_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/makes_new_object/sources/friend_module.move new file mode 100644 index 00000000000..ed97c439499 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/makes_new_object/sources/friend_module.move @@ -0,0 +1,19 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::friend_module { + + struct A { + field1: u64, + field2: T + } + + public fun friend_call(): u64 { base_addr::base::friend_fun(1) } + + public fun return_0(): u64 { 0 } + + public fun plus_1(x: u64): u64 { x + 1 } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } +} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v1/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v1/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v1/Move.toml rename to crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v1/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v1/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v1/sources/base.move new file mode 100644 index 00000000000..a8e9f12b05e --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v1/sources/base.move @@ -0,0 +1,19 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + + struct A { + f1: bool, + f2: T + } + + public fun return_0(): u64 { abort 42 } + + public fun plus_1(x: u64): u64 { x + 1 } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } + + entry fun entry_fun() { } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v1/sources/other_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v1/sources/other_module.move new file mode 100644 index 00000000000..fdc05a2fd4d --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v1/sources/other_module.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::other_module { + struct X {} +} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v2/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v2/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v2/Move.toml rename to crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v2/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v2/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v2/sources/base.move new file mode 100644 index 00000000000..a8e9f12b05e --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v2/sources/base.move @@ -0,0 +1,19 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + + struct A { + f1: bool, + f2: T + } + + public fun return_0(): u64 { abort 42 } + + public fun plus_1(x: u64): u64 { x + 1 } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } + + entry fun entry_fun() { } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v2/sources/other_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v2/sources/other_module.move new file mode 100644 index 00000000000..c01d5dc24d9 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v2/sources/other_module.move @@ -0,0 +1,6 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::other_module { +} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v2_module_removed/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v2_module_removed/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v2_module_removed/Move.toml rename to crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v2_module_removed/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v2_module_removed/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v2_module_removed/sources/base.move new file mode 100644 index 00000000000..a8e9f12b05e --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/missing_type_v2_module_removed/sources/base.move @@ -0,0 +1,19 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + + struct A { + f1: bool, + f2: T + } + + public fun return_0(): u64 { abort 42 } + + public fun plus_1(x: u64): u64 { x + 1 } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } + + entry fun entry_fun() { } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/new_object/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/new_object/Move.toml new file mode 100644 index 00000000000..098d8cfe402 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/new_object/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "new_object" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../../iota-framework/packages/iota-framework" } + +[addresses] +base_addr = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/new_object/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/new_object/sources/base.move new file mode 100644 index 00000000000..19de2eabb96 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/new_object/sources/base.move @@ -0,0 +1,28 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + use iota::object::UID; + + struct A { + f1: bool, + f2: T + } + + struct B has key { + id: UID, + x: u64, + } + + friend base_addr::friend_module; + + + public fun return_0(): u64 { abort 42 } + + public fun plus_1(x: u64): u64 { x + 1 } + + public(friend) fun friend_fun(x: u64): u64 { x } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/new_object/sources/friend_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/new_object/sources/friend_module.move new file mode 100644 index 00000000000..ed97c439499 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/new_object/sources/friend_module.move @@ -0,0 +1,19 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::friend_module { + + struct A { + field1: u64, + field2: T + } + + public fun friend_call(): u64 { base_addr::base::friend_fun(1) } + + public fun return_0(): u64 { 0 } + + public fun plus_1(x: u64): u64 { x + 1 } + + fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/Move.toml new file mode 100644 index 00000000000..6a198af4d41 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "object_cross_module_ref" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../../iota-framework/packages/iota-framework" } + +[addresses] +base_addr = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/sources/base.move new file mode 100644 index 00000000000..6927973b70f --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/sources/base.move @@ -0,0 +1,46 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + use iota::object::{Self, UID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer; + use base_addr::friend_module::{Self, X}; + + struct A has store, drop { + v: u16, + } + + struct B has key { + id: UID, + field1: u32, + field2: A, + } + + struct C has key { + id: UID, + field1: u64, + field2: X, + } + + entry fun make_objs(ctx: &mut TxContext) { + let field2 = A { v: 128 }; + transfer::transfer( + B { id: object::new(ctx), field1: 256, field2 }, + tx_context::sender(ctx), + ); + let field2 = friend_module::make_x(true); + transfer::transfer( + C { id: object::new(ctx), field1: 0, field2 }, + tx_context::sender(ctx), + ); + } + + entry fun destroy_objs(b: B, c: C) { + let B { id, field1: _, field2: _ } = b; + object::delete(id); + let C { id, field1: _, field2: _ } = c; + object::delete(id); + } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/sources/friend_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/sources/friend_module.move new file mode 100644 index 00000000000..9d48317e98c --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/sources/friend_module.move @@ -0,0 +1,22 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::friend_module { + + struct X has store, drop { + v: bool, + } + + struct Y has store, drop { + v: u64, + } + + public fun make_x(v: bool): X { + X { v } + } + + public fun make_y(v: u64): Y { + Y { v } + } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/Move.toml new file mode 100644 index 00000000000..f4786203662 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "object_cross_module_ref1" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../../iota-framework/packages/iota-framework" } + +[addresses] +base_addr = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/sources/base.move new file mode 100644 index 00000000000..b8416be94c9 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/sources/base.move @@ -0,0 +1,75 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + use iota::object::{Self, UID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer; + use base_addr::friend_module::{Self, X, Z}; + + struct A has store, drop { + v: u16, + } + + struct B has key { + id: UID, + field1: u32, + field2: A, + } + + struct C has key { + id: UID, + field1: u64, + field2: X, + } + + struct D has key { + id: UID, + field1: u64, + field2: A, + } + + struct E has key { + id: UID, + field1: u64, + field2: X, + } + + struct F has key { + id: UID, + field1: u64, + field2: Z, + } + + entry fun make_objs(ctx: &mut TxContext) { + let field2 = A { v: 128 }; + transfer::transfer( + B { id: object::new(ctx), field1: 256, field2 }, + tx_context::sender(ctx), + ); + let field2 = friend_module::make_x(true); + transfer::transfer( + C { id: object::new(ctx), field1: 0, field2 }, + tx_context::sender(ctx), + ); + } + + entry fun make_objs_v2(ctx: &mut TxContext) { + let field2 = A { v: 128 }; + transfer::transfer( + D { id: object::new(ctx), field1: 256, field2 }, + tx_context::sender(ctx), + ); + let field2 = friend_module::make_x(true); + transfer::transfer( + E { id: object::new(ctx), field1: 0, field2 }, + tx_context::sender(ctx), + ); + let field2 = friend_module::make_z(true); + transfer::transfer( + F { id: object::new(ctx), field1: 0, field2 }, + tx_context::sender(ctx), + ); + } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/sources/friend_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/sources/friend_module.move new file mode 100644 index 00000000000..9da1e5d5ded --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/sources/friend_module.move @@ -0,0 +1,31 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::friend_module { + + struct X has store, drop { + v: bool, + } + + struct Y has store, drop { + v: u64, + } + + struct Z has store, drop { + x: X, + } + + public fun make_x(v: bool): X { + X { v } + } + + public fun make_y(v: u64): Y { + Y { v } + } + + public fun make_z(v: bool): Z { + let x = X { v }; + Z { x } + } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/Move.toml new file mode 100644 index 00000000000..e16360fddb1 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "object_cross_module_ref2" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../../iota-framework/packages/iota-framework" } + +[addresses] +base_addr = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/sources/base.move new file mode 100644 index 00000000000..1463edc43e1 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/sources/base.move @@ -0,0 +1,89 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + use iota::object::{Self, UID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer; + use base_addr::friend_module::{Self, X, Y, Z}; + + struct A has store, drop { + v: u16, + } + + struct B has key { + id: UID, + field1: u32, + field2: A, + } + + struct C has key { + id: UID, + field1: u64, + field2: X, + } + + struct D has key { + id: UID, + field1: u64, + field2: A, + } + + struct E has key { + id: UID, + field1: u64, + field2: X, + } + + struct F has key { + id: UID, + field1: u64, + field2: Z, + } + + struct G has key { + id: UID, + field1: bool, + field2: Y, + } + + entry fun make_objs(ctx: &mut TxContext) { + let field2 = A { v: 128 }; + transfer::transfer( + B { id: object::new(ctx), field1: 256, field2 }, + tx_context::sender(ctx), + ); + let field2 = friend_module::make_x(true); + transfer::transfer( + C { id: object::new(ctx), field1: 0, field2 }, + tx_context::sender(ctx), + ); + } + + entry fun make_objs_v2(ctx: &mut TxContext) { + let field2 = A { v: 128 }; + transfer::transfer( + D { id: object::new(ctx), field1: 256, field2 }, + tx_context::sender(ctx), + ); + let field2 = friend_module::make_x(true); + transfer::transfer( + E { id: object::new(ctx), field1: 0, field2 }, + tx_context::sender(ctx), + ); + let field2 = friend_module::make_z(true); + transfer::transfer( + F { id: object::new(ctx), field1: 0, field2 }, + tx_context::sender(ctx), + ); + } + + entry fun make_objs_v3(ctx: &mut TxContext) { + let field2 = friend_module::make_y(100000000); + transfer::transfer( + G { id: object::new(ctx), field1: false, field2 }, + tx_context::sender(ctx), + ); + } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/sources/friend_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/sources/friend_module.move new file mode 100644 index 00000000000..9da1e5d5ded --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/sources/friend_module.move @@ -0,0 +1,31 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::friend_module { + + struct X has store, drop { + v: bool, + } + + struct Y has store, drop { + v: u64, + } + + struct Z has store, drop { + x: X, + } + + public fun make_x(v: bool): X { + X { v } + } + + public fun make_y(v: u64): Y { + Y { v } + } + + public fun make_z(v: bool): Z { + let x = X { v }; + Z { x } + } +} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/Move.toml rename to crates/iota-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/base.move new file mode 100644 index 00000000000..b4af0626e94 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/base.move @@ -0,0 +1,32 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + + struct A { + f1: bool, + f2: T + } + + // Add a struct + struct B { + f1: bool, + f2: T + } + + friend base_addr::friend_module; + + public fun return_0(): u64 { 0 } + + public fun plus_1(x: u64): u64 { x + 1 } + + // We currently cannot change a friend function as the loader will yell at us. + public(friend) fun friend_fun(x: u64): u64 { x } + + // Change this private function + fun non_public_fun(y: bool, g: u64): u64 { if (y) 0 else g } + + // Note that this is fine since the entry function is private + entry fun entry_fun(x: u64): u64 { x } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/friend_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/friend_module.move new file mode 100644 index 00000000000..645c6c57ea0 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/friend_module.move @@ -0,0 +1,20 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::friend_module { + + struct A { + field1: u64, + field2: T + } + + public fun friend_call(): u64 { base_addr::base::friend_fun(1) } + + public fun return_0(): u64 { 0 } + + fun non_public_fun(y: u64): u64 { y } + + // Reorder the functions + public fun plus_1(x: u64): u64 { x + 1 } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/new_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/new_module.move new file mode 100644 index 00000000000..6679f9dedf2 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/new_module.move @@ -0,0 +1,11 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::new_module { + public fun this_is_a_new_module() { } + + public fun i_can_call_funs_in_other_modules_that_already_existed(): u64 { + base_addr::friend_module::friend_call() + } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/Move.toml b/crates/iota-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/Move.toml new file mode 100644 index 00000000000..c81f1dcc277 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "stage2_basic_compatibility_valid" +version = "0.0.3" + +[dependencies] +Iota = { local = "../../../../../../iota-framework/packages/iota-framework" } + +[addresses] +base_addr = "0x0" +iota = "0x2" diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/base.move b/crates/iota-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/base.move new file mode 100644 index 00000000000..2d0ed991057 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/base.move @@ -0,0 +1,31 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::base { + + struct A { + f1: bool, + f2: T + } + + // Add a struct + struct B { + f1: bool, + f2: T + } + + friend base_addr::friend_module; + + public fun return_0(): u64 { 0 } + + public fun plus_1(x: u64): u64 { x + 1 } + + // We currently cannot change a friend function as the loader will yell at us. + public(friend) fun friend_fun(x: u64): u64 { x } + + // Change this private function + fun non_public_fun(y: bool, g: u64): u64 { if (y) 0 else g } + + entry fun entry_fun() { } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/friend_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/friend_module.move new file mode 100644 index 00000000000..645c6c57ea0 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/friend_module.move @@ -0,0 +1,20 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::friend_module { + + struct A { + field1: u64, + field2: T + } + + public fun friend_call(): u64 { base_addr::base::friend_fun(1) } + + public fun return_0(): u64 { 0 } + + fun non_public_fun(y: u64): u64 { y } + + // Reorder the functions + public fun plus_1(x: u64): u64 { x + 1 } +} diff --git a/crates/iota-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/new_module.move b/crates/iota-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/new_module.move new file mode 100644 index 00000000000..e43b6f3514b --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/new_module.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base_addr::new_module { + + struct MyObject has key, store { + id: iota::object::UID, + data: u64 + } + + public fun this_is_a_new_module() { } + + public fun i_can_call_funs_in_other_modules_that_already_existed(): u64 { + base_addr::friend_module::friend_call() + } +} diff --git a/crates/iota-core/src/unit_tests/data/object_basics/Move.toml b/crates/iota-core/src/unit_tests/data/object_basics/Move.toml new file mode 100644 index 00000000000..73e85620763 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/object_basics/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "Examples" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +examples = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/object_basics/sources/object_basics.move b/crates/iota-core/src/unit_tests/data/object_basics/sources/object_basics.move new file mode 100644 index 00000000000..72dae72d032 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/object_basics/sources/object_basics.move @@ -0,0 +1,152 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Test CTURD object basics (create, transfer, update, read, delete) +module examples::object_basics { + use iota::clock::Clock; + use iota::authenticator_state::AuthenticatorState; + use iota::random::Random; + use iota::dynamic_object_field as ofield; + use iota::event; + use iota::object::{Self, UID, ID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer; + + struct Object has key, store { + id: UID, + value: u64, + } + + struct Wrapper has key { + id: UID, + o: Object + } + + struct NewValueEvent has copy, drop { + new_value: u64 + } + + public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { + transfer::public_transfer( + Object { id: object::new(ctx), value }, + recipient + ) + } + + public entry fun share(ctx: &mut TxContext) { + transfer::public_share_object(Object { id: object::new(ctx), value: 0 }) + } + + public entry fun transfer(o: Object, recipient: address) { + transfer::public_transfer(o, recipient) + } + + public entry fun freeze_object(o: Object) { + transfer::public_freeze_object(o) + } + + public entry fun set_value(o: &mut Object, value: u64) { + o.value = value; + } + + // test that reading o2 and updating o1 works + public entry fun update(o1: &mut Object, o2: &Object) { + o1.value = o2.value; + // emit an event so the world can see the new value + event::emit(NewValueEvent { new_value: o2.value }) + } + + public entry fun delete(o: Object) { + let Object { id, value: _ } = o; + object::delete(id); + } + + public entry fun wrap(o: Object, ctx: &mut TxContext) { + transfer::transfer(wrap_object(o, ctx), tx_context::sender(ctx)) + } + + public entry fun unwrap(w: Wrapper, ctx: &mut TxContext) { + let Wrapper { id, o } = w; + object::delete(id); + transfer::public_transfer(o, tx_context::sender(ctx)) + } + + public fun wrap_object(o: Object, ctx: &mut TxContext): Wrapper { + Wrapper { id: object::new(ctx), o } + } + + public entry fun add_ofield(o: &mut Object, v: Object) { + ofield::add(&mut o.id, true, v); + } + + public entry fun remove_ofield(o: &mut Object, ctx: &mut TxContext) { + transfer::public_transfer( + ofield::remove(&mut o.id, true), + tx_context::sender(ctx), + ); + } + + fun borrow_value_mut(o: &mut Object): &mut u64 { + &mut o.value + } + + fun borrow_value(o: &Object): &u64 { + &o.value + } + + fun get_value(o: &Object): u64 { + o.value + } + + fun get_contents(o: &Object): (ID, u64) { + (object::id(o), o.value) + } + + public entry fun add_field(o: &mut Object, v: Object) { + iota::dynamic_field::add(&mut o.id, true, v); + } + + public entry fun remove_field(o: &mut Object, ctx: &mut TxContext) { + transfer::public_transfer( + iota::dynamic_field::remove(&mut o.id, true), + tx_context::sender(ctx), + ); + } + + struct Name has copy, drop, store { + name_str: std::string::String + } + + public entry fun add_field_with_struct_name(o: &mut Object, v: Object) { + iota::dynamic_field::add(&mut o.id, Name {name_str: std::string::utf8(b"Test Name")}, v); + } + + public entry fun add_ofield_with_struct_name(o: &mut Object, v: Object) { + ofield::add(&mut o.id, Name {name_str: std::string::utf8(b"Test Name")}, v); + } + + public entry fun add_field_with_bytearray_name(o: &mut Object, v: Object) { + iota::dynamic_field::add(&mut o.id,b"Test Name", v); + } + + public entry fun add_ofield_with_bytearray_name(o: &mut Object, v: Object) { + ofield::add(&mut o.id,b"Test Name", v); + } + + public entry fun add_field_with_address_name(o: &mut Object, v: Object, ctx: &mut TxContext) { + iota::dynamic_field::add(&mut o.id,tx_context::sender(ctx), v); + } + + public entry fun add_ofield_with_address_name(o: &mut Object, v: Object, ctx: &mut TxContext) { + ofield::add(&mut o.id,tx_context::sender(ctx), v); + } + + public entry fun generic_test() {} + + public entry fun use_clock(_clock: &Clock) {} + + public entry fun use_auth_state(_auth_state: &AuthenticatorState) {} + + public entry fun use_random(_random: &Random) {} +} diff --git a/crates/iota-core/src/unit_tests/data/object_no_id/Move.toml b/crates/iota-core/src/unit_tests/data/object_no_id/Move.toml new file mode 100644 index 00000000000..a1933ca6030 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/object_no_id/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "object_no_id" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +object_no_id = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/object_no_id/sources/test_only_object_no_id.move b/crates/iota-core/src/unit_tests/data/object_no_id/sources/test_only_object_no_id.move new file mode 100644 index 00000000000..c39ed830bc3 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/object_no_id/sources/test_only_object_no_id.move @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module object_no_id::test_only_object_no_id { + #[test_only] + struct NotObject has key {f: u64} + + #[test] + fun bad_share() { + iota::transfer::share_object(NotObject{f: 42}); + } +} diff --git a/crates/iota-core/src/unit_tests/data/object_owner/Move.toml b/crates/iota-core/src/unit_tests/data/object_owner/Move.toml new file mode 100644 index 00000000000..9b5789d92d5 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/object_owner/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "object_owner" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +object_owner = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/object_owner/sources/object_owner.move b/crates/iota-core/src/unit_tests/data/object_owner/sources/object_owner.move similarity index 95% rename from crates/sui-core/src/unit_tests/data/object_owner/sources/object_owner.move rename to crates/iota-core/src/unit_tests/data/object_owner/sources/object_owner.move index 3f8427f8d5c..e57956a2c11 100644 --- a/crates/sui-core/src/unit_tests/data/object_owner/sources/object_owner.move +++ b/crates/iota-core/src/unit_tests/data/object_owner/sources/object_owner.move @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module object_owner::object_owner { use std::option::{Self, Option}; - use sui::dynamic_object_field; - use sui::dynamic_field; - use sui::object::{Self, ID, UID}; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; + use iota::dynamic_object_field; + use iota::dynamic_field; + use iota::object::{Self, ID, UID}; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; struct Parent has key { id: UID, diff --git a/crates/iota-core/src/unit_tests/data/object_wrapping/Move.toml b/crates/iota-core/src/unit_tests/data/object_wrapping/Move.toml new file mode 100644 index 00000000000..ff820723411 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/object_wrapping/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "object_wrapping" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +object_wrapping = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/object_wrapping/sources/object_wrapping.move b/crates/iota-core/src/unit_tests/data/object_wrapping/sources/object_wrapping.move similarity index 90% rename from crates/sui-core/src/unit_tests/data/object_wrapping/sources/object_wrapping.move rename to crates/iota-core/src/unit_tests/data/object_wrapping/sources/object_wrapping.move index 5a6e9208127..a2b2f778e56 100644 --- a/crates/sui-core/src/unit_tests/data/object_wrapping/sources/object_wrapping.move +++ b/crates/iota-core/src/unit_tests/data/object_wrapping/sources/object_wrapping.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module object_wrapping::object_wrapping { use std::option::{Self, Option}; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; - use sui::object::{Self, UID}; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; + use iota::object::{Self, UID}; struct Child has key, store { id: UID, diff --git a/crates/sui-core/src/unit_tests/data/package_deny/a/Move.toml b/crates/iota-core/src/unit_tests/data/package_deny/a/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/package_deny/a/Move.toml rename to crates/iota-core/src/unit_tests/data/package_deny/a/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/package_deny/a/sources/a.move b/crates/iota-core/src/unit_tests/data/package_deny/a/sources/a.move new file mode 100644 index 00000000000..71c909f1ae8 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/package_deny/a/sources/a.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module a::a { + public entry fun a() { + b::b::b() + } +} diff --git a/crates/sui-core/src/unit_tests/data/package_deny/b/Move.toml b/crates/iota-core/src/unit_tests/data/package_deny/b/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/package_deny/b/Move.toml rename to crates/iota-core/src/unit_tests/data/package_deny/b/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/package_deny/b/sources/b.move b/crates/iota-core/src/unit_tests/data/package_deny/b/sources/b.move new file mode 100644 index 00000000000..da565bd642a --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/package_deny/b/sources/b.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::b { + public entry fun b() { + c::c::c() + } +} diff --git a/crates/sui-core/src/unit_tests/data/package_deny/c/Move.toml b/crates/iota-core/src/unit_tests/data/package_deny/c/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/package_deny/c/Move.toml rename to crates/iota-core/src/unit_tests/data/package_deny/c/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/package_deny/c/sources/c.move b/crates/iota-core/src/unit_tests/data/package_deny/c/sources/c.move new file mode 100644 index 00000000000..d49c0fadf82 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/package_deny/c/sources/c.move @@ -0,0 +1,11 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module c::c { + struct C { + x: u64 + } + + public entry fun c() {} +} diff --git a/crates/iota-core/src/unit_tests/data/publish_with_event/Move.toml b/crates/iota-core/src/unit_tests/data/publish_with_event/Move.toml new file mode 100644 index 00000000000..73e85620763 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/publish_with_event/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "Examples" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +examples = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/publish_with_event/sources/publish.move b/crates/iota-core/src/unit_tests/data/publish_with_event/sources/publish.move new file mode 100644 index 00000000000..dc41d9b738e --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/publish_with_event/sources/publish.move @@ -0,0 +1,18 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module examples::publish_with_event { + use std::ascii::{Self, String}; + + use iota::event; + use iota::tx_context::TxContext; + + struct PublishEvent has copy, drop { + foo: String + } + + fun init(_ctx: &mut TxContext) { + event::emit(PublishEvent { foo: ascii::string(b"bar") }) + } +} diff --git a/crates/iota-core/src/unit_tests/data/shared_object_deletion/Move.toml b/crates/iota-core/src/unit_tests/data/shared_object_deletion/Move.toml new file mode 100644 index 00000000000..0d27a74852a --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/shared_object_deletion/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "shared_object_deletion" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +shared_object_deletion = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/shared_object_deletion/sources/shared_object_deletion.move b/crates/iota-core/src/unit_tests/data/shared_object_deletion/sources/shared_object_deletion.move similarity index 95% rename from crates/sui-core/src/unit_tests/data/shared_object_deletion/sources/shared_object_deletion.move rename to crates/iota-core/src/unit_tests/data/shared_object_deletion/sources/shared_object_deletion.move index d64df2075bd..8ee8f9f35e9 100644 --- a/crates/sui-core/src/unit_tests/data/shared_object_deletion/sources/shared_object_deletion.move +++ b/crates/iota-core/src/unit_tests/data/shared_object_deletion/sources/shared_object_deletion.move @@ -1,12 +1,13 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module shared_object_deletion::o2 { use std::vector; - use sui::object::{Self, UID}; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; + use iota::object::{Self, UID}; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; struct Obj has key, store { id: UID, diff --git a/crates/sui-core/src/unit_tests/data/transitive_dependencies/a/Move.toml b/crates/iota-core/src/unit_tests/data/transitive_dependencies/a/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/transitive_dependencies/a/Move.toml rename to crates/iota-core/src/unit_tests/data/transitive_dependencies/a/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/transitive_dependencies/a/sources/a.move b/crates/iota-core/src/unit_tests/data/transitive_dependencies/a/sources/a.move new file mode 100644 index 00000000000..9f2553016b6 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/transitive_dependencies/a/sources/a.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module a::a { + public fun a(): u64 { + b::b::b() + } +} diff --git a/crates/sui-core/src/unit_tests/data/transitive_dependencies/b/Move.toml b/crates/iota-core/src/unit_tests/data/transitive_dependencies/b/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/transitive_dependencies/b/Move.toml rename to crates/iota-core/src/unit_tests/data/transitive_dependencies/b/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/transitive_dependencies/b/sources/b.move b/crates/iota-core/src/unit_tests/data/transitive_dependencies/b/sources/b.move new file mode 100644 index 00000000000..8551397ed90 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/transitive_dependencies/b/sources/b.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::b { + public fun b(): u64 { + c::c::c() + } +} diff --git a/crates/sui-core/src/unit_tests/data/transitive_dependencies/c/Move.toml b/crates/iota-core/src/unit_tests/data/transitive_dependencies/c/Move.toml similarity index 100% rename from crates/sui-core/src/unit_tests/data/transitive_dependencies/c/Move.toml rename to crates/iota-core/src/unit_tests/data/transitive_dependencies/c/Move.toml diff --git a/crates/iota-core/src/unit_tests/data/transitive_dependencies/c/sources/c.move b/crates/iota-core/src/unit_tests/data/transitive_dependencies/c/sources/c.move new file mode 100644 index 00000000000..3cbfce09279 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/transitive_dependencies/c/sources/c.move @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module c::c { + struct C { + x: u64 + } + + public fun c(): u64 { + 42 + } +} diff --git a/crates/iota-core/src/unit_tests/data/transitive_dependencies/root/Move.toml b/crates/iota-core/src/unit_tests/data/transitive_dependencies/root/Move.toml new file mode 100644 index 00000000000..c61feabc6ef --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/transitive_dependencies/root/Move.toml @@ -0,0 +1,7 @@ +[package] +name = "Examples" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../../iota-framework/packages/iota-framework" } +A = { local = "../a" } diff --git a/crates/iota-core/src/unit_tests/data/transitive_dependencies/root/sources/trusted_coin.move b/crates/iota-core/src/unit_tests/data/transitive_dependencies/root/sources/trusted_coin.move new file mode 100644 index 00000000000..fe543cae046 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/transitive_dependencies/root/sources/trusted_coin.move @@ -0,0 +1,40 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Example coin with a trusted owner responsible for minting/burning (e.g., a stablecoin) +module examples::trusted_coin { + use std::option; + use iota::coin::{Self, TreasuryCap}; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; + + /// Name of the coin + struct TRUSTED_COIN has drop {} + + /// Register the trusted currency to acquire its `TreasuryCap`. Because + /// this is a module initializer, it ensures the currency only gets + /// registered once. + fun init(witness: TRUSTED_COIN, ctx: &mut TxContext) { + // Get a treasury cap for the coin and give it to the transaction + // sender + let (treasury_cap, metadata) = coin::create_currency(witness, 2, b"TRUSTED", b"", b"", option::none(), ctx); + transfer::public_freeze_object(metadata); + transfer::public_transfer(treasury_cap, tx_context::sender(ctx)) + } + + public entry fun mint(treasury_cap: &mut TreasuryCap, ctx: &mut TxContext) { + let coin = coin::mint(treasury_cap, a::a::a(), ctx); + transfer::public_transfer(coin, tx_context::sender(ctx)); + } + + public entry fun transfer(treasury_cap: TreasuryCap, recipient: address) { + transfer::public_transfer(treasury_cap, recipient); + } + + #[test_only] + /// Wrapper of module initializer for testing + public fun test_init(ctx: &mut TxContext) { + init(TRUSTED_COIN {}, ctx) + } +} diff --git a/crates/iota-core/src/unit_tests/data/tto/Move.toml b/crates/iota-core/src/unit_tests/data/tto/Move.toml new file mode 100644 index 00000000000..8062b7f07b2 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/tto/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "tto" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +tto = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/tto/sources/tto1.move b/crates/iota-core/src/unit_tests/data/tto/sources/tto1.move new file mode 100644 index 00000000000..665216a9c18 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/tto/sources/tto1.move @@ -0,0 +1,63 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module tto::M1 { + use iota::object::{Self, UID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer::{Self, Receiving}; + use iota::dynamic_object_field; + + struct A has key, store { + id: UID, + } + + struct B has key, store { + id: UID, + } + + struct C has key { + id: UID, + wrapped: B, + } + + public fun start(ctx: &mut TxContext) { + let a = A { id: object::new(ctx) }; + let a_address = object::id_address(&a); + let b = B { id: object::new(ctx) }; + let c = A { id: object::new(ctx) }; + let d = A { id: object::new(ctx) }; + let e = A { id: object::new(ctx) }; + dynamic_object_field::add(&mut d.id, 0, e); + + transfer::public_transfer(a, tx_context::sender(ctx)); + transfer::public_transfer(b, a_address); + transfer::freeze_object(c); + transfer::share_object(d); + } + + public entry fun receiver(parent: &mut A, x: Receiving) { + let b = transfer::receive(&mut parent.id, x); + transfer::public_transfer(b, @tto); + } + + public entry fun send_back(parent: &mut A, x: Receiving) { + let b = transfer::receive(&mut parent.id, x); + let parent_address = object::id_address(parent); + transfer::public_transfer(b, parent_address); + } + + public entry fun deleter(parent: &mut A, x: Receiving) { + let B { id } = transfer::receive(&mut parent.id, x); + object::delete(id); + } + + public entry fun wrapper(parent: &mut A, x: Receiving, ctx: &mut TxContext) { + let b = transfer::receive(&mut parent.id, x); + let c = C { id: object::new(ctx), wrapped: b }; + transfer::transfer(c, @tto); + } + + public fun call_immut_ref(_parent: &mut A, _x: &Receiving) { } + public fun call_mut_ref(_parent: &mut A, _x: &mut Receiving) { } +} diff --git a/crates/sui-core/src/unit_tests/data/tto/sources/tto2.move b/crates/iota-core/src/unit_tests/data/tto/sources/tto2.move similarity index 86% rename from crates/sui-core/src/unit_tests/data/tto/sources/tto2.move rename to crates/iota-core/src/unit_tests/data/tto/sources/tto2.move index b29eac1de57..41dfd0631ad 100644 --- a/crates/sui-core/src/unit_tests/data/tto/sources/tto2.move +++ b/crates/iota-core/src/unit_tests/data/tto/sources/tto2.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module tto::M2 { - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer::{Self, Receiving}; - use sui::dynamic_field as df; + use iota::object::{Self, UID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer::{Self, Receiving}; + use iota::dynamic_field as df; struct A has key, store { id: UID, diff --git a/crates/sui-core/src/unit_tests/data/tto/sources/tto3.move b/crates/iota-core/src/unit_tests/data/tto/sources/tto3.move similarity index 87% rename from crates/sui-core/src/unit_tests/data/tto/sources/tto3.move rename to crates/iota-core/src/unit_tests/data/tto/sources/tto3.move index 60b564cf96b..b80f03a5aed 100644 --- a/crates/sui-core/src/unit_tests/data/tto/sources/tto3.move +++ b/crates/iota-core/src/unit_tests/data/tto/sources/tto3.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module tto::M3 { - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer::{Self, Receiving}; + use iota::object::{Self, UID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer::{Self, Receiving}; struct A has key, store { id: UID, diff --git a/crates/sui-core/src/unit_tests/data/tto/sources/tto4.move b/crates/iota-core/src/unit_tests/data/tto/sources/tto4.move similarity index 88% rename from crates/sui-core/src/unit_tests/data/tto/sources/tto4.move rename to crates/iota-core/src/unit_tests/data/tto/sources/tto4.move index f38137c762d..877a70b87c7 100644 --- a/crates/sui-core/src/unit_tests/data/tto/sources/tto4.move +++ b/crates/iota-core/src/unit_tests/data/tto/sources/tto4.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module tto::M4 { - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer::{Self, Receiving}; + use iota::object::{Self, UID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer::{Self, Receiving}; struct A has key, store { id: UID, diff --git a/crates/sui-core/src/unit_tests/data/tto/sources/tto5.move b/crates/iota-core/src/unit_tests/data/tto/sources/tto5.move similarity index 81% rename from crates/sui-core/src/unit_tests/data/tto/sources/tto5.move rename to crates/iota-core/src/unit_tests/data/tto/sources/tto5.move index 731f1b1a5ed..0d45805dc30 100644 --- a/crates/sui-core/src/unit_tests/data/tto/sources/tto5.move +++ b/crates/iota-core/src/unit_tests/data/tto/sources/tto5.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module tto::M5 { - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer::{Self, Receiving}; - use sui::dynamic_object_field as dof; + use iota::object::{Self, UID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer::{Self, Receiving}; + use iota::dynamic_object_field as dof; struct A has key, store { id: UID, diff --git a/crates/iota-core/src/unit_tests/data/type_params/Move.toml b/crates/iota-core/src/unit_tests/data/type_params/Move.toml new file mode 100644 index 00000000000..7e537917f29 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/type_params/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "type_params" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +type_params = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/type_params/sources/m1.move b/crates/iota-core/src/unit_tests/data/type_params/sources/m1.move new file mode 100644 index 00000000000..e82f4496130 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/type_params/sources/m1.move @@ -0,0 +1,41 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module type_params::m1 { + use iota::object::{Self, UID}; + use iota::tx_context::TxContext; + use iota::transfer; + use type_params::m2; + + struct Object has key, store { + id: UID, + value: u64, + } + + struct GenObject has key, store { + id: UID, + o: T, + } + + public entry fun create_and_transfer(value: u64, recipient: address, ctx: &mut TxContext) { + transfer::public_transfer( + Object { id: object::new(ctx), value }, + recipient + ) + } + + public entry fun create_and_transfer_gen(value: u64, recipient: address, ctx: &mut TxContext) { + let another = m2::create(value, ctx); + transfer::public_transfer( + GenObject { id: object::new(ctx), o: another }, + recipient + ) + } + + public entry fun transfer_object(o: T, recipient: address) { + transfer::public_transfer(o, recipient); + } + + +} diff --git a/crates/sui-core/src/unit_tests/data/type_params/sources/m2.move b/crates/iota-core/src/unit_tests/data/type_params/sources/m2.move similarity index 79% rename from crates/sui-core/src/unit_tests/data/type_params/sources/m2.move rename to crates/iota-core/src/unit_tests/data/type_params/sources/m2.move index 79ebe8bbeb7..a7cbc6ee2ba 100644 --- a/crates/sui-core/src/unit_tests/data/type_params/sources/m2.move +++ b/crates/iota-core/src/unit_tests/data/type_params/sources/m2.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module type_params::m2 { - use sui::object::{Self, UID}; - use sui::tx_context::TxContext; - use sui::transfer; + use iota::object::{Self, UID}; + use iota::tx_context::TxContext; + use iota::transfer; struct AnotherObject has key, store { id: UID, diff --git a/crates/sui-core/src/unit_tests/data/type_params/sources/m3.move b/crates/iota-core/src/unit_tests/data/type_params/sources/m3.move similarity index 76% rename from crates/sui-core/src/unit_tests/data/type_params/sources/m3.move rename to crates/iota-core/src/unit_tests/data/type_params/sources/m3.move index d6f6a96ac4e..9674af68ff6 100644 --- a/crates/sui-core/src/unit_tests/data/type_params/sources/m3.move +++ b/crates/iota-core/src/unit_tests/data/type_params/sources/m3.move @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module type_params::m3 { - use sui::transfer; + use iota::transfer; public entry fun transfer_object(o: T, recipient: address) { transfer::public_transfer(o, recipient); diff --git a/crates/iota-core/src/unit_tests/data/type_params_extra/Move.toml b/crates/iota-core/src/unit_tests/data/type_params_extra/Move.toml new file mode 100644 index 00000000000..3d88526312b --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/type_params_extra/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "type_params_extra" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } + +[addresses] +type_params = "0x0" diff --git a/crates/iota-core/src/unit_tests/data/type_params_extra/sources/m1.move b/crates/iota-core/src/unit_tests/data/type_params_extra/sources/m1.move new file mode 100644 index 00000000000..0c7de6a8ec4 --- /dev/null +++ b/crates/iota-core/src/unit_tests/data/type_params_extra/sources/m1.move @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module type_params::m1 { + use iota::transfer; + + public entry fun transfer_object(o: T, recipient: address) { + transfer::public_transfer(o, recipient); + } + + +} diff --git a/crates/sui-core/src/unit_tests/epoch_data_tests.rs b/crates/iota-core/src/unit_tests/epoch_data_tests.rs similarity index 97% rename from crates/sui-core/src/unit_tests/epoch_data_tests.rs rename to crates/iota-core/src/unit_tests/epoch_data_tests.rs index 99202131f5c..dcb4c580c14 100644 --- a/crates/sui-core/src/unit_tests/epoch_data_tests.rs +++ b/crates/iota-core/src/unit_tests/epoch_data_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fs, path::PathBuf}; diff --git a/crates/sui-core/src/unit_tests/execution_driver_tests.rs b/crates/iota-core/src/unit_tests/execution_driver_tests.rs similarity index 98% rename from crates/sui-core/src/unit_tests/execution_driver_tests.rs rename to crates/iota-core/src/unit_tests/execution_driver_tests.rs index 85fd9b2eb65..570afc3238f 100644 --- a/crates/sui-core/src/unit_tests/execution_driver_tests.rs +++ b/crates/iota-core/src/unit_tests/execution_driver_tests.rs @@ -1,23 +1,24 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeSet, sync::Arc, time::Duration}; -use itertools::Itertools; -use sui_config::node::AuthorityOverloadConfig; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ +use iota_config::node::AuthorityOverloadConfig; +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ base_types::TransactionDigest, committee::Committee, crypto::{get_key_pair, AccountKeyPair}, effects::{TransactionEffects, TransactionEffectsAPI}, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, object::{Object, Owner}, transaction::{ CertifiedTransaction, Transaction, VerifiedCertificate, TEST_ONLY_GAS_UNIT_FOR_HEAVY_COMPUTATION_STORAGE, }, }; +use itertools::Itertools; use tokio::{ sync::mpsc::UnboundedReceiver, time::{sleep, timeout}, @@ -457,7 +458,7 @@ async fn try_sign_on_first_three_authorities( authority_clients: &[Arc>], committee: &Committee, txn: &Transaction, -) -> SuiResult { +) -> IotaResult { for client in authority_clients.iter().take(3) { client.handle_transaction(txn.clone()).await?; } @@ -783,8 +784,8 @@ async fn test_authority_txn_signing_pushback() { .handle_transaction_for_testing(tx.clone()) .await; assert!(matches!( - SuiError::from(response.err().unwrap()), - SuiError::ValidatorOverloadedRetryAfter { .. } + IotaError::from(response.err().unwrap()), + IotaError::ValidatorOverloadedRetryAfter { .. } )); // Check that the input object should be locked by the above transaction. @@ -804,7 +805,7 @@ async fn test_authority_txn_signing_pushback() { .err() .unwrap() .into(), - SuiError::ValidatorOverloadedRetryAfter { .. } + IotaError::ValidatorOverloadedRetryAfter { .. } )); // Send another transaction, that send the same object to a different recipient. @@ -825,7 +826,7 @@ async fn test_authority_txn_signing_pushback() { .err() .unwrap() .into(), - SuiError::ObjectLockConflict { .. } + IotaError::ObjectLockConflict { .. } )); // Clear the authority overload status. @@ -933,7 +934,7 @@ async fn test_authority_txn_execution_pushback() { .err() .unwrap() .into(), - SuiError::ValidatorOverloadedRetryAfter { .. } + IotaError::ValidatorOverloadedRetryAfter { .. } )); // Clear the validator overload status and retry the certificate. It should diff --git a/crates/sui-core/src/unit_tests/gas_tests.rs b/crates/iota-core/src/unit_tests/gas_tests.rs similarity index 96% rename from crates/sui-core/src/unit_tests/gas_tests.rs rename to crates/iota-core/src/unit_tests/gas_tests.rs index 54ffe1dd2d4..9eb44450b6e 100644 --- a/crates/sui-core/src/unit_tests/gas_tests.rs +++ b/crates/iota-core/src/unit_tests/gas_tests.rs @@ -1,10 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use move_core_types::{account_address::AccountAddress, ident_str}; -use once_cell::sync::Lazy; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ +use iota_protocol_config::ProtocolConfig; +use iota_types::{ base_types::dbg_addr, crypto::{get_key_pair, AccountKeyPair}, effects::TransactionEvents, @@ -14,6 +13,8 @@ use sui_types::{ programmable_transaction_builder::ProgrammableTransactionBuilder, utils::to_sender_signed_transaction, }; +use move_core_types::{account_address::AccountAddress, ident_str}; +use once_cell::sync::Lazy; use super::{ authority_tests::{init_state_with_ids, send_and_confirm_transaction}, @@ -80,7 +81,7 @@ async fn test_tx_more_than_maximum_gas_budget() { // is entire budget) // // With multiple gas coins is practically impossible to fail storage cost -// because we get a significant among of MIST back from smashing. So we try: +// because we get a significant among of MICROS back from smashing. So we try: // - OOG computation, storage ok // // impossible scenarios: @@ -94,7 +95,7 @@ async fn test_tx_more_than_maximum_gas_budget() { async fn publish_move_random_package( authority_state: &Arc, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, gas_object_id: &ObjectID, ) -> ObjectID { @@ -125,7 +126,7 @@ async fn publish_move_random_package( } async fn check_oog_transaction( - sender: SuiAddress, + sender: IotaAddress, sender_key: AccountKeyPair, function: &'static str, args: Vec, @@ -133,9 +134,9 @@ async fn check_oog_transaction( gas_price: u64, coin_num: u64, checker: F, -) -> SuiResult +) -> IotaResult where - F: FnOnce(&GasCostSummary, u64, u64) -> SuiResult, + F: FnOnce(&GasCostSummary, u64, u64) -> IotaResult, { // initial system with given gas coins let gas_amount: u64 = if budget < 10_000_000_000 { @@ -234,7 +235,7 @@ where } // make a `coin_num` coins distributing `gas_amount` across them -fn make_gas_coins(owner: SuiAddress, gas_amount: u64, coin_num: u64) -> Vec { +fn make_gas_coins(owner: IotaAddress, gas_amount: u64, coin_num: u64) -> Vec { let mut objects = vec![]; let coin_balance = gas_amount / coin_num; for _ in 1..coin_num { @@ -259,9 +260,9 @@ fn make_gas_coins(owner: SuiAddress, gas_amount: u64, coin_num: u64) -> Vec SuiResult { +async fn test_oog_computation_storage_ok_one_coin() -> IotaResult { const GAS_PRICE: u64 = 1_000; let budget: u64 = ProtocolConfig::get_for_max_version_UNSAFE().max_tx_gas(); let (sender, sender_key) = get_key_pair(); @@ -322,7 +323,7 @@ async fn test_oog_computation_storage_ok_one_coin() -> SuiResult { } #[tokio::test] -async fn test_oog_computation_storage_ok_multi_coins() -> SuiResult { +async fn test_oog_computation_storage_ok_multi_coins() -> IotaResult { const GAS_PRICE: u64 = 1_000; let budget: u64 = ProtocolConfig::get_for_max_version_UNSAFE().max_tx_gas(); let (sender, sender_key) = get_key_pair(); @@ -352,7 +353,7 @@ async fn test_oog_computation_storage_ok_multi_coins() -> SuiResult { // OOG for computation, OOG for minimal storage (e.g. computation is entire // budget) #[tokio::test] -async fn test_oog_computation_oog_storage_final_one_coin() -> SuiResult { +async fn test_oog_computation_oog_storage_final_one_coin() -> IotaResult { const GAS_PRICE: u64 = 1000; const MAX_UNIT_BUDGET: u64 = 5_000_000; const BUDGET: u64 = MAX_UNIT_BUDGET * GAS_PRICE; @@ -382,7 +383,7 @@ async fn test_oog_computation_oog_storage_final_one_coin() -> SuiResult { // - computation ok, OOG for storage, minimal storage ok #[tokio::test] -async fn test_computation_ok_oog_storage_minimal_ok_one_coin() -> SuiResult { +async fn test_computation_ok_oog_storage_minimal_ok_one_coin() -> IotaResult { const GAS_PRICE: u64 = 1001; const BUDGET: u64 = 1_100_000; let (sender, sender_key) = get_key_pair(); @@ -414,7 +415,7 @@ async fn test_computation_ok_oog_storage_minimal_ok_one_coin() -> SuiResult { // - computation ok, OOG for storage, minimal storage ok #[tokio::test] -async fn test_computation_ok_oog_storage_minimal_ok_multi_coins() -> SuiResult { +async fn test_computation_ok_oog_storage_minimal_ok_multi_coins() -> IotaResult { const GAS_PRICE: u64 = 1001; const BUDGET: u64 = 1_100_000; let (sender, sender_key) = get_key_pair(); @@ -447,7 +448,7 @@ async fn test_computation_ok_oog_storage_minimal_ok_multi_coins() -> SuiResult { // - computation ok, OOG for storage, OOG for minimal storage (e.g. computation // is entire budget) #[tokio::test] -async fn test_computation_ok_oog_storage_final_one_coin() -> SuiResult { +async fn test_computation_ok_oog_storage_final_one_coin() -> IotaResult { const GAS_PRICE: u64 = 1001; const BUDGET: u64 = 1_002_000; let (sender, sender_key) = get_key_pair(); @@ -492,7 +493,7 @@ async fn test_tx_gas_balance_less_than_budget() { } #[tokio::test] -async fn test_native_transfer_sufficient_gas() -> SuiResult { +async fn test_native_transfer_sufficient_gas() -> IotaResult { // This test does a native transfer with sufficient gas budget and balance. // It's expected to succeed. We check that gas was charged properly. let result = execute_transfer(*MAX_GAS_BUDGET, *MAX_GAS_BUDGET, true, false).await; @@ -556,7 +557,7 @@ async fn test_native_transfer_gas_price_is_used() { } #[tokio::test] -async fn test_transfer_sui_insufficient_gas() { +async fn test_transfer_iota_insufficient_gas() { let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); let recipient = dbg_addr(2); let authority_state = TestAuthorityBuilder::new().build().await; @@ -568,7 +569,7 @@ async fn test_transfer_sui_insufficient_gas() { let pt = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.transfer_sui(recipient, None); + builder.transfer_iota(recipient, None); builder.finish() }; let kind = TransactionKind::ProgrammableTransaction(pt); @@ -621,19 +622,19 @@ async fn test_invalid_gas_owners() { )) .await; let non_sender_owned_object = - init_object(Object::with_owner_for_testing(SuiAddress::ZERO)).await; + init_object(Object::with_owner_for_testing(IotaAddress::ZERO)).await; async fn test( good_gas_object: ObjectRef, bad_gas_object: ObjectRef, - sender: SuiAddress, + sender: IotaAddress, sender_key: &AccountKeyPair, authority_state: &AuthorityState, ) -> UserInputError { let pt = { let mut builder = ProgrammableTransactionBuilder::new(); let recipient = dbg_addr(2); - builder.transfer_sui(recipient, None); + builder.transfer_iota(recipient, None); builder.finish() }; let kind = TransactionKind::ProgrammableTransaction(pt); @@ -842,7 +843,7 @@ async fn test_publish_gas() -> anyhow::Result<()> { } #[tokio::test] -async fn test_move_call_gas() -> SuiResult { +async fn test_move_call_gas() -> IotaResult { let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); let gas_object_id = ObjectID::random(); let (authority_state, package_object_ref) = @@ -961,7 +962,7 @@ async fn test_tx_gas_coins_input_coins() { async fn run_merge( authority_state: &AuthorityState, - sender: SuiAddress, + sender: IotaAddress, sender_key: &AccountKeyPair, gas_coin_refs: Vec, coin_ref: ObjectRef, @@ -1012,7 +1013,7 @@ async fn test_tx_gas_coins_input_coins() { struct TransferResult { pub authority_state: Arc, pub gas_object_id: ObjectID, - pub response: SuiResult, + pub response: IotaResult, pub rgp: u64, } diff --git a/crates/sui-core/src/unit_tests/move_integration_tests.rs b/crates/iota-core/src/unit_tests/move_integration_tests.rs similarity index 98% rename from crates/sui-core/src/unit_tests/move_integration_tests.rs rename to crates/iota-core/src/unit_tests/move_integration_tests.rs index 6aed096d34f..ba8d44d9c3d 100644 --- a/crates/sui-core/src/unit_tests/move_integration_tests.rs +++ b/crates/iota-core/src/unit_tests/move_integration_tests.rs @@ -1,25 +1,26 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashSet, env, path::PathBuf, str::FromStr}; -use move_core_types::{ - account_address::AccountAddress, - identifier::{IdentStr, Identifier}, - language_storage::{StructTag, TypeTag}, - u256::U256, -}; -use sui_move_build::{BuildConfig, SuiPackageHooks}; -use sui_types::{ +use iota_move_build::{BuildConfig, IotaPackageHooks}; +use iota_types::{ base_types::{RESOLVED_ASCII_STR, RESOLVED_STD_OPTION, RESOLVED_UTF8_STR}, crypto::{get_key_pair, AccountKeyPair}, - error::{ExecutionErrorKind, SuiError}, + error::{ExecutionErrorKind, IotaError}, execution_status::{CommandArgumentError, ExecutionFailureStatus, ExecutionStatus}, move_package::UpgradeCap, programmable_transaction_builder::ProgrammableTransactionBuilder, utils::to_sender_signed_transaction, - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, +}; +use move_core_types::{ + account_address::AccountAddress, + identifier::{IdentStr, Identifier}, + language_storage::{StructTag, TypeTag}, + u256::U256, }; use super::*; @@ -876,7 +877,7 @@ async fn test_entry_point_vector_empty() { .unwrap_err(); assert_eq!( err, - SuiError::UserInputError { + IotaError::UserInputError { error: UserInputError::EmptyCommandInput } ); @@ -906,7 +907,7 @@ async fn test_entry_point_vector_empty() { .unwrap_err(); assert_eq!( err, - SuiError::UserInputError { + IotaError::UserInputError { error: UserInputError::EmptyCommandInput } ); @@ -2285,7 +2286,7 @@ async fn test_entry_point_string_option_error() { async fn test_make_move_vec_for_type( authority: &AuthorityState, gas: &ObjectID, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, package_id: ObjectID, t: TypeTag, @@ -2536,14 +2537,14 @@ make_vec_tests_for_type!(test_make_move_vec_u128, u128, TypeTag::U128, 0u128); make_vec_tests_for_type!(test_make_move_vec_u256, U256, TypeTag::U256, U256::zero()); make_vec_tests_for_type!( test_make_move_vec_address, - SuiAddress, + IotaAddress, TypeTag::Address, - SuiAddress::ZERO + IotaAddress::ZERO ); make_vec_tests_for_type!( test_make_move_vec_address_id, ObjectID, - TypeTag::Struct(Box::new(sui_types::id::ID::type_())), + TypeTag::Struct(Box::new(iota_types::id::ID::type_())), ObjectID::ZERO ); make_vec_tests_for_type!(test_make_move_vec_utf8, &str, utf8_tag(), "❤️🧀"); @@ -2557,7 +2558,7 @@ make_vec_tests_for_type!( async fn error_test_make_move_vec_for_type( authority: &AuthorityState, gas: &ObjectID, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, t: TypeTag, value: T, @@ -2724,14 +2725,14 @@ make_vec_error_tests_for_type!( ); make_vec_error_tests_for_type!( test_error_make_move_vec_address, - SuiAddress, + IotaAddress, TypeTag::Address, - SuiAddress::ZERO + IotaAddress::ZERO ); make_vec_error_tests_for_type!( test_error_make_move_vec_address_id, ObjectID, - TypeTag::Struct(Box::new(sui_types::id::ID::type_())), + TypeTag::Struct(Box::new(iota_types::id::ID::type_())), ObjectID::ZERO ); make_vec_error_tests_for_type!(test_error_make_move_vec_utf8, &str, utf8_tag(), "❤️🧀"); @@ -2764,7 +2765,7 @@ async fn test_make_move_vec_empty() { .unwrap_err(); assert_eq!( result, - SuiError::UserInputError { + IotaError::UserInputError { error: UserInputError::EmptyCommandInput } ); @@ -2807,8 +2808,8 @@ async fn test_object_no_id_error() { path.extend(["src", "unit_tests", "data", "object_no_id"]); let res = build_config.build(path); - matches!(res.err(), Some(SuiError::ExecutionError(err_str)) if - err_str.contains("SuiMoveVerificationError") + matches!(res.err(), Some(IotaError::ExecutionError(err_str)) if + err_str.contains("IotaMoveVerificationError") && err_str.contains("First field of struct NotObject must be 'id'")); } @@ -2825,7 +2826,7 @@ pub fn build_package( code_dir: &str, with_unpublished_deps: bool, ) -> (Vec, Vec>, Vec) { - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); path.extend(["src", "unit_tests", "data", code_dir]); let compiled_package = BuildConfig::new_for_testing().build(path).unwrap(); @@ -2837,7 +2838,7 @@ pub fn build_package( pub async fn build_and_try_publish_test_package( authority: &AuthorityState, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, gas_object_id: &ObjectID, test_dir: &str, @@ -2845,7 +2846,7 @@ pub async fn build_and_try_publish_test_package( gas_price: u64, with_unpublished_deps: bool, ) -> (Transaction, SignedTransactionEffects) { - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); path.extend(["src", "unit_tests", "data", test_dir]); @@ -2877,7 +2878,7 @@ pub async fn build_and_try_publish_test_package( pub async fn build_and_publish_test_package( authority: &AuthorityState, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, gas_object_id: &ObjectID, test_dir: &str, @@ -2897,7 +2898,7 @@ pub async fn build_and_publish_test_package( pub async fn build_and_publish_test_package_with_upgrade_cap( authority: &AuthorityState, - sender: &SuiAddress, + sender: &IotaAddress, sender_key: &AccountKeyPair, gas_object_id: &ObjectID, test_dir: &str, @@ -2964,11 +2965,11 @@ pub async fn collect_packages_and_upgrade_caps( pub async fn run_multi_txns( authority: &AuthorityState, - sender: SuiAddress, + sender: IotaAddress, sender_key: &AccountKeyPair, gas_object_id: &ObjectID, builder: ProgrammableTransactionBuilder, -) -> Result<(CertifiedTransaction, SignedTransactionEffects), SuiError> { +) -> Result<(CertifiedTransaction, SignedTransactionEffects), IotaError> { // build the transaction data let pt = builder.finish(); let gas_object = authority.get_object(gas_object_id).await.unwrap(); @@ -2986,7 +2987,7 @@ pub async fn run_multi_txns( pub fn build_multi_publish_txns( builder: &mut ProgrammableTransactionBuilder, - sender: SuiAddress, + sender: IotaAddress, packages: Vec<(Vec>, Vec)>, ) { for (modules, dep_ids) in packages { @@ -3017,7 +3018,7 @@ pub fn build_multi_upgrade_txns( let policy = builder.pure(package_upgrade.policy).unwrap(); let digest = builder.pure(package_upgrade.digest).unwrap(); let ticket = builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, Identifier::new("package").unwrap(), Identifier::new("authorize_upgrade").unwrap(), vec![], @@ -3030,7 +3031,7 @@ pub fn build_multi_upgrade_txns( package_upgrade.modules, ); builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, Identifier::new("package").unwrap(), Identifier::new("commit_upgrade").unwrap(), vec![], diff --git a/crates/sui-core/src/unit_tests/move_package_publish_tests.rs b/crates/iota-core/src/unit_tests/move_package_publish_tests.rs similarity index 96% rename from crates/sui-core/src/unit_tests/move_package_publish_tests.rs rename to crates/iota-core/src/unit_tests/move_package_publish_tests.rs index b48d7ff2ea5..09ea2f06f45 100644 --- a/crates/sui-core/src/unit_tests/move_package_publish_tests.rs +++ b/crates/iota-core/src/unit_tests/move_package_publish_tests.rs @@ -1,24 +1,25 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashSet, env, fs::File, io::Read, path::PathBuf}; use expect_test::expect; -use move_binary_format::CompiledModule; -use move_package::source_package::manifest_parser; -use sui_framework::BuiltInFramework; -use sui_move_build::{check_unpublished_dependencies, gather_published_ids, BuildConfig}; -use sui_types::{ +use iota_framework::BuiltInFramework; +use iota_move_build::{check_unpublished_dependencies, gather_published_ids, BuildConfig}; +use iota_types::{ base_types::ObjectID, crypto::{get_key_pair, AccountKeyPair}, effects::TransactionEffectsAPI, - error::{SuiError, UserInputError}, + error::{IotaError, UserInputError}, execution_status::{ExecutionFailureStatus, ExecutionStatus}, object::{Data, ObjectRead, Owner}, programmable_transaction_builder::ProgrammableTransactionBuilder, transaction::{TransactionData, TEST_ONLY_GAS_UNIT_FOR_PUBLISH}, utils::to_sender_signed_transaction, }; +use move_binary_format::CompiledModule; +use move_package::source_package::manifest_parser; use crate::authority::{ authority_tests::{call_move, init_state_with_ids, send_and_confirm_transaction}, @@ -117,7 +118,7 @@ async fn test_publish_empty_package() { .unwrap_err(); assert_eq!( err, - SuiError::UserInputError { + IotaError::UserInputError { error: UserInputError::EmptyCommandInput } ); @@ -218,7 +219,7 @@ async fn test_generate_lock_file() { deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600" dependencies = [ { name = "Examples" }, - { name = "Sui" }, + { name = "Iota" }, ] [[move.package]] @@ -226,16 +227,16 @@ async fn test_generate_lock_file() { source = { local = "../object_basics" } dependencies = [ - { name = "Sui" }, + { name = "Iota" }, ] [[move.package]] name = "MoveStdlib" - source = { local = "../../../../../sui-framework/packages/move-stdlib" } + source = { local = "../../../../../iota-framework/packages/move-stdlib" } [[move.package]] - name = "Sui" - source = { local = "../../../../../sui-framework/packages/sui-framework" } + name = "Iota" + source = { local = "../../../../../iota-framework/packages/iota-framework" } dependencies = [ { name = "MoveStdlib" }, @@ -244,7 +245,7 @@ async fn test_generate_lock_file() { [move.toolchain-version] compiler-version = "0.0.1" edition = "legacy" - flavor = "sui" + flavor = "iota" "#]]; expected.assert_eq(lock_file_contents.as_str()); } @@ -296,7 +297,7 @@ async fn test_custom_property_check_unpublished_dependencies() { .resolution_graph_for_package(&path, &mut std::io::sink()) .expect("Could not build resolution graph."); - let SuiError::ModulePublishFailure { error } = + let IotaError::ModulePublishFailure { error } = check_unpublished_dependencies(&gather_published_ids(&resolution_graph).1.unpublished) .err() .unwrap() @@ -485,7 +486,7 @@ async fn test_publish_more_than_max_packages_error() { .unwrap_err(); assert_eq!( err, - SuiError::UserInputError { + IotaError::UserInputError { error: UserInputError::MaxPublishCountExceeded { max_publish_commands: max_pub_cmd, publish_count: max_pub_cmd + 1, diff --git a/crates/sui-core/src/unit_tests/move_package_tests.rs b/crates/iota-core/src/unit_tests/move_package_tests.rs similarity index 98% rename from crates/sui-core/src/unit_tests/move_package_tests.rs rename to crates/iota-core/src/unit_tests/move_package_tests.rs index bb9ef60a2e2..ae7e318f098 100644 --- a/crates/sui-core/src/unit_tests/move_package_tests.rs +++ b/crates/iota-core/src/unit_tests/move_package_tests.rs @@ -1,12 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, path::PathBuf}; -use move_binary_format::file_format::CompiledModule; -use sui_move_build::{BuildConfig, CompiledPackage}; -use sui_protocol_config::{Chain, ProtocolConfig}; -use sui_types::{ +use iota_move_build::{BuildConfig, CompiledPackage}; +use iota_protocol_config::{Chain, ProtocolConfig}; +use iota_types::{ base_types::ObjectID, digests::TransactionDigest, error::ExecutionErrorKind, @@ -14,6 +14,7 @@ use sui_types::{ move_package::{MovePackage, TypeOrigin, UpgradeInfo}, object::{Data, Object, OBJECT_START_VERSION}, }; +use move_binary_format::file_format::CompiledModule; macro_rules! type_origin_table { {} => { Vec::new() }; diff --git a/crates/sui-core/src/unit_tests/move_package_upgrade_tests.rs b/crates/iota-core/src/unit_tests/move_package_upgrade_tests.rs similarity index 95% rename from crates/sui-core/src/unit_tests/move_package_upgrade_tests.rs rename to crates/iota-core/src/unit_tests/move_package_upgrade_tests.rs index a5601daae3f..bc6d35d9cb2 100644 --- a/crates/sui-core/src/unit_tests/move_package_upgrade_tests.rs +++ b/crates/iota-core/src/unit_tests/move_package_upgrade_tests.rs @@ -1,16 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeSet, path::PathBuf, str::FromStr, sync::Arc}; -use move_core_types::{ident_str, language_storage::StructTag}; -use sui_move_build::BuildConfig; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, +use iota_move_build::BuildConfig; +use iota_protocol_config::ProtocolConfig; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef}, crypto::{get_key_pair, AccountKeyPair}, effects::{TransactionEffects, TransactionEffectsAPI}, - error::{SuiError, UserInputError}, + error::{IotaError, UserInputError}, execution_config_utils::to_binary_config, execution_status::{ CommandArgumentError, ExecutionFailureStatus, ExecutionStatus, PackageUpgradeError, @@ -20,8 +20,9 @@ use sui_types::{ programmable_transaction_builder::ProgrammableTransactionBuilder, storage::ObjectStore, transaction::{Argument, ObjectArg, ProgrammableTransaction, TEST_ONLY_GAS_UNIT_FOR_PUBLISH}, - MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID, }; +use move_core_types::{ident_str, language_storage::StructTag}; use crate::authority::{ authority_test_utils::build_test_modules_with_dep_addr, @@ -93,19 +94,19 @@ pub fn build_upgrade_txn( let digest_arg = builder.pure(digest).unwrap(); let upgrade_ticket = move_call! { builder, - (SUI_FRAMEWORK_PACKAGE_ID)::package::authorize_upgrade(Argument::Input(0), upgrade_arg, digest_arg) + (IOTA_FRAMEWORK_PACKAGE_ID)::package::authorize_upgrade(Argument::Input(0), upgrade_arg, digest_arg) }; let upgrade_receipt = builder.upgrade(current_pkg_id, upgrade_ticket, vec![], modules); move_call! { builder, - (SUI_FRAMEWORK_PACKAGE_ID)::package::commit_upgrade(Argument::Input(0), upgrade_receipt) + (IOTA_FRAMEWORK_PACKAGE_ID)::package::commit_upgrade(Argument::Input(0), upgrade_receipt) }; builder.finish() } struct UpgradeStateRunner { - pub sender: SuiAddress, + pub sender: IotaAddress, pub sender_key: AccountKeyPair, pub gas_object_id: ObjectID, pub authority_state: Arc, @@ -193,11 +194,11 @@ impl UpgradeStateRunner { let digest = builder.pure(digest).unwrap(); let ticket = move_call! { builder, - (SUI_FRAMEWORK_PACKAGE_ID)::package::authorize_upgrade(cap, policy, digest) + (IOTA_FRAMEWORK_PACKAGE_ID)::package::authorize_upgrade(cap, policy, digest) }; let receipt = builder.upgrade(package_id, ticket, dep_ids, modules); - move_call! { builder, (SUI_FRAMEWORK_PACKAGE_ID)::package::commit_upgrade(cap, receipt) }; + move_call! { builder, (IOTA_FRAMEWORK_PACKAGE_ID)::package::commit_upgrade(cap, receipt) }; builder.finish() }; @@ -313,7 +314,7 @@ async fn test_upgrade_introduces_type_then_uses_it() { UpgradePolicy::COMPATIBLE, digest, modules, - vec![SUI_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID], + vec![IOTA_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID], ) .await; @@ -327,7 +328,7 @@ async fn test_upgrade_introduces_type_then_uses_it() { UpgradePolicy::COMPATIBLE, digest, modules, - vec![SUI_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID], + vec![IOTA_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID], ) .await; @@ -426,7 +427,7 @@ async fn test_upgrade_package_compatibility_too_permissive() { let cap = builder .obj(ObjectArg::ImmOrOwnedObject(runner.upgrade_cap)) .unwrap(); - move_call! { builder, (SUI_FRAMEWORK_PACKAGE_ID)::package::only_dep_upgrades(cap) }; + move_call! { builder, (IOTA_FRAMEWORK_PACKAGE_ID)::package::only_dep_upgrades(cap) }; builder.finish() }) .await; @@ -584,7 +585,7 @@ async fn test_upgrade_package_dep_only_mode() { UpgradePolicy::DEP_ONLY, digest, modules, - vec![SUI_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID], + vec![IOTA_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID], ) .await; @@ -632,7 +633,7 @@ async fn test_upgrade_ticket_doesnt_match() { let digest_arg = builder.pure(digest).unwrap(); let upgrade_ticket = move_call! { builder, - (SUI_FRAMEWORK_PACKAGE_ID)::package::authorize_upgrade(Argument::Input(0), upgrade_arg, digest_arg) + (IOTA_FRAMEWORK_PACKAGE_ID)::package::authorize_upgrade(Argument::Input(0), upgrade_arg, digest_arg) }; builder.upgrade(MOVE_STDLIB_PACKAGE_ID, upgrade_ticket, vec![], modules); builder.finish() @@ -688,7 +689,7 @@ async fn test_multiple_upgrades( .0 .0; - // Second upgrade: May also adds a dep on the sui framework and stdlib. + // Second upgrade: May also adds a dep on the iota framework and stdlib. let (digest, modules) = build_upgrade_test_modules("stage2_basic_compatibility_valid"); let effects = runner .upgrade( @@ -698,7 +699,7 @@ async fn test_multiple_upgrades( if use_empty_deps { vec![] } else { - vec![SUI_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID] + vec![IOTA_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID] }, ) .await; @@ -734,12 +735,12 @@ async fn test_interleaved_upgrades() { let digest_arg = builder.pure(digest).unwrap(); let upgrade_ticket = move_call! { builder, - (SUI_FRAMEWORK_PACKAGE_ID)::package::authorize_upgrade(Argument::Input(0), upgrade_arg, digest_arg) + (IOTA_FRAMEWORK_PACKAGE_ID)::package::authorize_upgrade(Argument::Input(0), upgrade_arg, digest_arg) }; let upgrade_receipt = builder.upgrade(current_package_id, upgrade_ticket, vec![], modules); move_call! { builder, - (SUI_FRAMEWORK_PACKAGE_ID)::package::commit_upgrade(Argument::Input(0), upgrade_receipt) + (IOTA_FRAMEWORK_PACKAGE_ID)::package::commit_upgrade(Argument::Input(0), upgrade_receipt) }; builder.finish() @@ -774,12 +775,12 @@ async fn test_interleaved_upgrades() { let digest_arg = builder.pure(digest).unwrap(); let upgrade_ticket = move_call! { builder, - (SUI_FRAMEWORK_PACKAGE_ID)::package::authorize_upgrade(Argument::Input(0), upgrade_arg, digest_arg) + (IOTA_FRAMEWORK_PACKAGE_ID)::package::authorize_upgrade(Argument::Input(0), upgrade_arg, digest_arg) }; let upgrade_receipt = builder.upgrade(current_package_id, upgrade_ticket, dep_ids, modules); move_call! { builder, - (SUI_FRAMEWORK_PACKAGE_ID)::package::commit_upgrade(Argument::Input(0), upgrade_receipt) + (IOTA_FRAMEWORK_PACKAGE_ID)::package::commit_upgrade(Argument::Input(0), upgrade_receipt) }; builder.finish() @@ -1034,7 +1035,7 @@ async fn test_upgraded_types_in_one_txn() { UpgradePolicy::COMPATIBLE, digest, modules, - vec![SUI_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID], + vec![IOTA_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID], ) .await; @@ -1048,7 +1049,7 @@ async fn test_upgraded_types_in_one_txn() { UpgradePolicy::COMPATIBLE, digest, modules, - vec![SUI_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID], + vec![IOTA_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID], ) .await; @@ -1209,12 +1210,12 @@ async fn test_conflicting_versions_across_calls() { let digest_arg = builder.pure(digest).unwrap(); let upgrade_ticket = move_call! { builder, - (SUI_FRAMEWORK_PACKAGE_ID)::package::authorize_upgrade(Argument::Input(0), upgrade_arg, digest_arg) + (IOTA_FRAMEWORK_PACKAGE_ID)::package::authorize_upgrade(Argument::Input(0), upgrade_arg, digest_arg) }; let upgrade_receipt = builder.upgrade(current_package_id, upgrade_ticket, dep_ids, modules); move_call! { builder, - (SUI_FRAMEWORK_PACKAGE_ID)::package::commit_upgrade(Argument::Input(0), upgrade_receipt) + (IOTA_FRAMEWORK_PACKAGE_ID)::package::commit_upgrade(Argument::Input(0), upgrade_receipt) }; builder.finish() @@ -1280,7 +1281,7 @@ async fn test_upgrade_cross_module_refs() { UpgradePolicy::COMPATIBLE, digest, modules, - vec![SUI_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID], + vec![IOTA_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID], ) .await; @@ -1307,7 +1308,7 @@ async fn test_upgrade_cross_module_refs() { UpgradePolicy::COMPATIBLE, digest, modules, - vec![SUI_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID], + vec![IOTA_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID], ) .await; @@ -1437,7 +1438,7 @@ async fn test_upgrade_more_than_max_packages_error() { .unwrap_err(); assert_eq!( err, - SuiError::UserInputError { + IotaError::UserInputError { error: UserInputError::MaxPublishCountExceeded { max_publish_commands: max_pub_cmd, publish_count: max_pub_cmd + 2, diff --git a/crates/sui-core/src/unit_tests/mysticeti_manager_tests.rs b/crates/iota-core/src/unit_tests/mysticeti_manager_tests.rs similarity index 90% rename from crates/sui-core/src/unit_tests/mysticeti_manager_tests.rs rename to crates/iota-core/src/unit_tests/mysticeti_manager_tests.rs index 1bffdeb4dfb..f1b69ed31c0 100644 --- a/crates/sui-core/src/unit_tests/mysticeti_manager_tests.rs +++ b/crates/iota-core/src/unit_tests/mysticeti_manager_tests.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{sync::Arc, time::Duration}; use fastcrypto::traits::KeyPair; +use iota_swarm_config::network_config_builder::ConfigBuilder; use mysten_metrics::RegistryService; use prometheus::Registry; -use sui_swarm_config::network_config_builder::ConfigBuilder; use tokio::time::sleep; use crate::{ @@ -18,7 +19,7 @@ use crate::{ narwhal_manager::narwhal_manager_tests::checkpoint_service_for_testing, ConsensusManagerMetrics, ConsensusManagerTrait, }, - consensus_validator::{SuiTxValidator, SuiTxValidatorMetrics}, + consensus_validator::{IotaTxValidator, IotaTxValidatorMetrics}, mysticeti_adapter::LazyMysticetiClient, }; @@ -66,11 +67,11 @@ async fn test_mysticeti_manager() { config, epoch_store.clone(), consensus_handler_initializer, - SuiTxValidator::new( + IotaTxValidator::new( epoch_store.clone(), Arc::new(CheckpointServiceNoop {}), state.transaction_manager().clone(), - SuiTxValidatorMetrics::new(&Registry::new()), + IotaTxValidatorMetrics::new(&Registry::new()), ), ) .await; diff --git a/crates/sui-core/src/unit_tests/narwhal_manager_tests.rs b/crates/iota-core/src/unit_tests/narwhal_manager_tests.rs similarity index 91% rename from crates/sui-core/src/unit_tests/narwhal_manager_tests.rs rename to crates/iota-core/src/unit_tests/narwhal_manager_tests.rs index 2ba443f84ce..adcd55c38f3 100644 --- a/crates/sui-core/src/unit_tests/narwhal_manager_tests.rs +++ b/crates/iota-core/src/unit_tests/narwhal_manager_tests.rs @@ -1,21 +1,22 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{sync::Arc, time::Duration}; use bytes::Bytes; use fastcrypto::{bls12381, traits::KeyPair}; +use iota_swarm_config::network_config_builder::ConfigBuilder; +use iota_types::{ + iota_system_state::{ + epoch_start_iota_system_state::EpochStartSystemStateTrait, IotaSystemStateTrait, + }, + messages_checkpoint::{CertifiedCheckpointSummary, CheckpointContents, CheckpointSummary}, +}; use mysten_metrics::RegistryService; use narwhal_config::{Epoch, WorkerCache}; use narwhal_types::{TransactionProto, TransactionsClient}; use prometheus::Registry; -use sui_swarm_config::network_config_builder::ConfigBuilder; -use sui_types::{ - messages_checkpoint::{CertifiedCheckpointSummary, CheckpointContents, CheckpointSummary}, - sui_system_state::{ - epoch_start_sui_system_state::EpochStartSystemStateTrait, SuiSystemStateTrait, - }, -}; use tokio::{ sync::{broadcast, mpsc}, time::{interval, sleep}, @@ -29,7 +30,7 @@ use crate::{ narwhal_manager::{NarwhalConfiguration, NarwhalManager}, ConsensusManagerMetrics, ConsensusManagerTrait, }, - consensus_validator::{SuiTxValidator, SuiTxValidatorMetrics}, + consensus_validator::{IotaTxValidator, IotaTxValidatorMetrics}, state_accumulator::StateAccumulator, }; @@ -115,8 +116,8 @@ async fn test_narwhal_manager() { .await; let system_state = state - .get_sui_system_state_object_for_testing() - .expect("Reading Sui system state object cannot fail") + .get_iota_system_state_object_for_testing() + .expect("Reading Iota system state object cannot fail") .into_epoch_start_state(); let transactions_addr = &config.consensus_config.as_ref().unwrap().address; @@ -148,11 +149,11 @@ async fn test_narwhal_manager() { config, epoch_store.clone(), consensus_handler_initializer, - SuiTxValidator::new( + IotaTxValidator::new( epoch_store.clone(), Arc::new(CheckpointServiceNoop {}), state.transaction_manager().clone(), - SuiTxValidatorMetrics::new(&Registry::new()), + IotaTxValidatorMetrics::new(&Registry::new()), ), ) .await; @@ -206,8 +207,8 @@ async fn test_narwhal_manager() { ); let system_state = state - .get_sui_system_state_object_for_testing() - .expect("Reading Sui system state object cannot fail") + .get_iota_system_state_object_for_testing() + .expect("Reading Iota system state object cannot fail") .into_epoch_start_state(); let narwhal_committee = system_state.get_narwhal_committee(); let worker_cache = system_state.get_narwhal_worker_cache(&transactions_addr); @@ -225,11 +226,11 @@ async fn test_narwhal_manager() { config, epoch_store.clone(), consensus_handler_initializer, - SuiTxValidator::new( + IotaTxValidator::new( epoch_store.clone(), Arc::new(CheckpointServiceNoop {}), state.transaction_manager().clone(), - SuiTxValidatorMetrics::new(&Registry::new()), + IotaTxValidatorMetrics::new(&Registry::new()), ), ) .await; diff --git a/crates/sui-core/src/unit_tests/overload_monitor_tests.rs b/crates/iota-core/src/unit_tests/overload_monitor_tests.rs similarity index 93% rename from crates/sui-core/src/unit_tests/overload_monitor_tests.rs rename to crates/iota-core/src/unit_tests/overload_monitor_tests.rs index 79a8261c873..c287ecae7f2 100644 --- a/crates/sui-core/src/unit_tests/overload_monitor_tests.rs +++ b/crates/iota-core/src/unit_tests/overload_monitor_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Tests that overload monitor only starts on validators. @@ -9,7 +10,7 @@ mod simtests { Arc, }; - use sui_macros::{register_fail_point, sim_test}; + use iota_macros::{register_fail_point, sim_test}; use test_cluster::TestClusterBuilder; #[sim_test] diff --git a/crates/iota-core/src/unit_tests/pay_iota_tests.rs b/crates/iota-core/src/unit_tests/pay_iota_tests.rs new file mode 100644 index 00000000000..79641e1580f --- /dev/null +++ b/crates/iota-core/src/unit_tests/pay_iota_tests.rs @@ -0,0 +1,476 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::HashMap, sync::Arc}; + +use futures::future::join_all; +use iota_types::{ + base_types::{dbg_addr, IotaAddress, ObjectID, ObjectRef}, + crypto::{get_key_pair, AccountKeyPair}, + effects::{SignedTransactionEffects, TransactionEffectsAPI}, + error::{IotaError, UserInputError}, + execution_status::{ExecutionFailureStatus, ExecutionStatus}, + gas_coin::GasCoin, + object::Object, + programmable_transaction_builder::ProgrammableTransactionBuilder, + transaction::TransactionData, + utils::to_sender_signed_transaction, +}; + +use crate::authority::{ + authority_tests::{init_state_with_committee, send_and_confirm_transaction}, + test_authority_builder::TestAuthorityBuilder, + AuthorityState, +}; + +#[tokio::test] +async fn test_pay_iota_failure_empty_recipients() { + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let coin_id = ObjectID::random(); + let coin1 = Object::with_id_owner_gas_for_testing(coin_id, sender, 2000000); + + // an empty set of programmable transaction commands will still charge gas + let res = execute_pay_iota(vec![coin1], vec![], vec![], sender, sender_key, 2000000).await; + + let effects = res.txn_result.unwrap().into_data(); + assert_eq!(effects.status(), &ExecutionStatus::Success); + assert_eq!(effects.mutated().len(), 1); + assert_eq!(effects.mutated()[0].0.0, coin_id); + assert!(effects.deleted().is_empty()); + assert!(effects.created().is_empty()); +} + +#[tokio::test] +async fn test_pay_iota_failure_insufficient_gas_balance_one_input_coin() { + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let coin1 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 2000); + let recipient1 = dbg_addr(1); + let recipient2 = dbg_addr(2); + + let res = execute_pay_iota( + vec![coin1], + vec![recipient1, recipient2], + vec![100, 100], + sender, + sender_key, + 2200000, + ) + .await; + + assert_eq!( + UserInputError::try_from(res.txn_result.unwrap_err()).unwrap(), + UserInputError::GasBalanceTooLow { + gas_balance: 2000, + needed_gas_amount: 2200000, + } + ); +} + +#[tokio::test] +async fn test_pay_iota_failure_insufficient_total_balance_one_input_coin() { + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let coin1 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 500100); + let recipient1 = dbg_addr(1); + let recipient2 = dbg_addr(2); + + let res = execute_pay_iota( + vec![coin1], + vec![recipient1, recipient2], + vec![100, 100], + sender, + sender_key, + 500000, + ) + .await; + + assert_eq!( + res.txn_result.as_ref().unwrap().status(), + &ExecutionStatus::Failure { + error: ExecutionFailureStatus::InsufficientCoinBalance, + command: Some(0) // SplitCoins is the first command in the implementation of pay + }, + ); +} + +#[tokio::test] +async fn test_pay_iota_failure_insufficient_gas_balance_multiple_input_coins() { + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let coin1 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 800); + let coin2 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 700); + let recipient1 = dbg_addr(1); + let recipient2 = dbg_addr(2); + + let res = execute_pay_iota( + vec![coin1, coin2], + vec![recipient1, recipient2], + vec![100, 100], + sender, + sender_key, + 2000000, + ) + .await; + + assert_eq!( + UserInputError::try_from(res.txn_result.unwrap_err()).unwrap(), + UserInputError::GasBalanceTooLow { + gas_balance: 1500, + needed_gas_amount: 2000000, + } + ); +} + +#[tokio::test] +async fn test_pay_iota_failure_insufficient_total_balance_multiple_input_coins() { + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let coin1 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 204000); + let coin2 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 303000); + let recipient1 = dbg_addr(1); + let recipient2 = dbg_addr(2); + + let res = execute_pay_iota( + vec![coin1, coin2], + vec![recipient1, recipient2], + vec![4000, 4000], + sender, + sender_key, + 500000, + ) + .await; + assert_eq!( + res.txn_result.as_ref().unwrap().status(), + &ExecutionStatus::Failure { + error: ExecutionFailureStatus::InsufficientCoinBalance, + command: Some(0) // SplitCoins is the first command in the implementation of pay + }, + ); +} + +#[tokio::test] +async fn test_pay_iota_success_one_input_coin() -> anyhow::Result<()> { + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let object_id = ObjectID::random(); + let coin_amount = 50000000; + let coin_obj = Object::with_id_owner_gas_for_testing(object_id, sender, 50000000); + let recipient1 = dbg_addr(1); + let recipient2 = dbg_addr(2); + let recipient3 = dbg_addr(3); + let recipient_amount_map: HashMap<_, u64> = + HashMap::from([(recipient1, 100), (recipient2, 200), (recipient3, 300)]); + let res = execute_pay_iota( + vec![coin_obj], + vec![recipient1, recipient2, recipient3], + vec![100, 200, 300], + sender, + sender_key, + coin_amount - 300 - 200 - 100, + ) + .await; + + let effects = res.txn_result.unwrap().into_data(); + assert_eq!(*effects.status(), ExecutionStatus::Success); + // make sure each recipient receives the specified amount + assert_eq!(effects.created().len(), 3); + let created_obj_id1 = effects.created()[0].0.0; + let created_obj_id2 = effects.created()[1].0.0; + let created_obj_id3 = effects.created()[2].0.0; + let created_obj1 = res + .authority_state + .get_object(&created_obj_id1) + .await + .unwrap() + .unwrap(); + let created_obj2 = res + .authority_state + .get_object(&created_obj_id2) + .await + .unwrap() + .unwrap(); + let created_obj3 = res + .authority_state + .get_object(&created_obj_id3) + .await + .unwrap() + .unwrap(); + + let addr1 = effects.created()[0].1.get_owner_address()?; + let addr2 = effects.created()[1].1.get_owner_address()?; + let addr3 = effects.created()[2].1.get_owner_address()?; + let coin_val1 = *recipient_amount_map + .get(&addr1) + .ok_or(IotaError::InvalidAddress)?; + let coin_val2 = *recipient_amount_map + .get(&addr2) + .ok_or(IotaError::InvalidAddress)?; + let coin_val3 = *recipient_amount_map + .get(&addr3) + .ok_or(IotaError::InvalidAddress)?; + assert_eq!(GasCoin::try_from(&created_obj1)?.value(), coin_val1); + assert_eq!(GasCoin::try_from(&created_obj2)?.value(), coin_val2); + assert_eq!(GasCoin::try_from(&created_obj3)?.value(), coin_val3); + + // make sure the first object still belongs to the sender, + // the value is equal to all residual values after amounts transferred and gas + // payment. + assert_eq!(effects.mutated()[0].0.0, object_id); + assert_eq!(effects.mutated()[0].1, sender); + let gas_used = effects.gas_cost_summary().net_gas_usage() as u64; + let gas_object = res.authority_state.get_object(&object_id).await?.unwrap(); + assert_eq!( + GasCoin::try_from(&gas_object)?.value(), + coin_amount - 100 - 200 - 300 - gas_used, + ); + + Ok(()) +} + +#[tokio::test] +async fn test_pay_iota_success_multiple_input_coins() -> anyhow::Result<()> { + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let object_id1 = ObjectID::random(); + let object_id2 = ObjectID::random(); + let object_id3 = ObjectID::random(); + let coin_obj1 = Object::with_id_owner_gas_for_testing(object_id1, sender, 5000000); + let coin_obj2 = Object::with_id_owner_gas_for_testing(object_id2, sender, 1000); + let coin_obj3 = Object::with_id_owner_gas_for_testing(object_id3, sender, 1000); + let recipient1 = dbg_addr(1); + let recipient2 = dbg_addr(2); + + let res = execute_pay_iota( + vec![coin_obj1, coin_obj2, coin_obj3], + vec![recipient1, recipient2], + vec![500, 1500], + sender, + sender_key, + 5000000, + ) + .await; + let recipient_amount_map: HashMap<_, u64> = + HashMap::from([(recipient1, 500), (recipient2, 1500)]); + let effects = res.txn_result.unwrap().into_data(); + assert_eq!(*effects.status(), ExecutionStatus::Success); + + // make sure each recipient receives the specified amount + assert_eq!(effects.created().len(), 2); + let created_obj_id1 = effects.created()[0].0.0; + let created_obj_id2 = effects.created()[1].0.0; + let created_obj1 = res + .authority_state + .get_object(&created_obj_id1) + .await + .unwrap() + .unwrap(); + let created_obj2 = res + .authority_state + .get_object(&created_obj_id2) + .await + .unwrap() + .unwrap(); + let addr1 = effects.created()[0].1.get_owner_address()?; + let addr2 = effects.created()[1].1.get_owner_address()?; + let coin_val1 = *recipient_amount_map + .get(&addr1) + .ok_or(IotaError::InvalidAddress)?; + let coin_val2 = *recipient_amount_map + .get(&addr2) + .ok_or(IotaError::InvalidAddress)?; + assert_eq!(GasCoin::try_from(&created_obj1)?.value(), coin_val1); + assert_eq!(GasCoin::try_from(&created_obj2)?.value(), coin_val2); + // make sure the first input coin still belongs to the sender, + // the value is equal to all residual values after amounts transferred and gas + // payment. + assert_eq!(effects.mutated()[0].0.0, object_id1); + assert_eq!(effects.mutated()[0].1, sender); + let gas_used = effects.gas_cost_summary().net_gas_usage() as u64; + let gas_object = res.authority_state.get_object(&object_id1).await?.unwrap(); + assert_eq!( + GasCoin::try_from(&gas_object)?.value(), + 5002000 - 500 - 1500 - gas_used, + ); + + // make sure the second and third input coins are deleted + let deleted_ids: Vec = effects.deleted().iter().map(|d| d.0).collect(); + assert!(deleted_ids.contains(&object_id2)); + assert!(deleted_ids.contains(&object_id3)); + Ok(()) +} + +#[tokio::test] +async fn test_pay_all_iota_failure_insufficient_gas_one_input_coin() { + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let coin1 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 1800); + let recipient = dbg_addr(2); + + let res = execute_pay_all_iota(vec![&coin1], recipient, sender, sender_key, 2000000).await; + + assert_eq!( + UserInputError::try_from(res.txn_result.unwrap_err()).unwrap(), + UserInputError::GasBalanceTooLow { + gas_balance: 1800, + needed_gas_amount: 2000000, + } + ); +} + +#[tokio::test] +async fn test_pay_all_iota_failure_insufficient_gas_budget_multiple_input_coins() { + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let coin1 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 1000); + let coin2 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 1000); + let recipient = dbg_addr(2); + let res = + execute_pay_all_iota(vec![&coin1, &coin2], recipient, sender, sender_key, 2500000).await; + + assert_eq!( + UserInputError::try_from(res.txn_result.unwrap_err()).unwrap(), + UserInputError::GasBalanceTooLow { + gas_balance: 2000, + needed_gas_amount: 2500000, + } + ); +} + +#[tokio::test] +async fn test_pay_all_iota_success_one_input_coin() -> anyhow::Result<()> { + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let object_id = ObjectID::random(); + let coin_obj = Object::with_id_owner_gas_for_testing(object_id, sender, 3000000); + let recipient = dbg_addr(2); + let res = execute_pay_all_iota(vec![&coin_obj], recipient, sender, sender_key, 2000000).await; + + let effects = res.txn_result.unwrap().into_data(); + assert_eq!(*effects.status(), ExecutionStatus::Success); + + // make sure the first object now belongs to the recipient, + // the value is equal to all residual values after gas payment. + let obj_ref = &effects.mutated()[0].0; + assert_eq!(obj_ref.0, object_id); + assert_eq!(effects.mutated()[0].1, recipient); + + let gas_used = effects.gas_cost_summary().gas_used(); + let gas_object = res.authority_state.get_object(&object_id).await?.unwrap(); + assert_eq!(GasCoin::try_from(&gas_object)?.value(), 3000000 - gas_used,); + Ok(()) +} + +#[tokio::test] +async fn test_pay_all_iota_success_multiple_input_coins() -> anyhow::Result<()> { + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let object_id1 = ObjectID::random(); + let coin_obj1 = Object::with_id_owner_gas_for_testing(object_id1, sender, 3000000); + let coin_obj2 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 1000); + let coin_obj3 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 1000); + let recipient = dbg_addr(2); + let res = execute_pay_all_iota( + vec![&coin_obj1, &coin_obj2, &coin_obj3], + recipient, + sender, + sender_key, + 3000000, + ) + .await; + + let effects = res.txn_result.unwrap().into_data(); + assert_eq!(*effects.status(), ExecutionStatus::Success); + + // make sure the first object now belongs to the recipient, + // the value is equal to all residual values after gas payment. + let obj_ref = &effects.mutated()[0].0; + assert_eq!(obj_ref.0, object_id1); + assert_eq!(effects.mutated()[0].1, recipient); + + let gas_used = effects.gas_cost_summary().gas_used(); + let gas_object = res.authority_state.get_object(&object_id1).await?.unwrap(); + assert_eq!(GasCoin::try_from(&gas_object)?.value(), 3002000 - gas_used,); + Ok(()) +} + +struct PayIotaTransactionBlockExecutionResult { + pub authority_state: Arc, + pub txn_result: Result, +} + +async fn execute_pay_iota( + input_coin_objects: Vec, + recipients: Vec, + amounts: Vec, + sender: IotaAddress, + sender_key: AccountKeyPair, + gas_budget: u64, +) -> PayIotaTransactionBlockExecutionResult { + let authority_state = TestAuthorityBuilder::new().build().await; + + let input_coin_refs: Vec = input_coin_objects + .iter() + .map(|coin_obj| coin_obj.compute_object_reference()) + .collect(); + let handles: Vec<_> = input_coin_objects + .into_iter() + .map(|obj| authority_state.insert_genesis_object(obj)) + .collect(); + join_all(handles).await; + let rgp = authority_state.reference_gas_price_for_testing().unwrap(); + + let mut builder = ProgrammableTransactionBuilder::new(); + builder.pay_iota(recipients, amounts).unwrap(); + let pt = builder.finish(); + let data = TransactionData::new_programmable(sender, input_coin_refs, pt, gas_budget, rgp); + let tx = to_sender_signed_transaction(data, &sender_key); + let txn_result = send_and_confirm_transaction(&authority_state, tx) + .await + .map(|(_, effects)| effects); + + PayIotaTransactionBlockExecutionResult { + authority_state, + txn_result, + } +} + +async fn execute_pay_all_iota( + input_coin_objects: Vec<&Object>, + recipient: IotaAddress, + sender: IotaAddress, + sender_key: AccountKeyPair, + gas_budget: u64, +) -> PayIotaTransactionBlockExecutionResult { + let dir = tempfile::TempDir::new().unwrap(); + let network_config = iota_swarm_config::network_config_builder::ConfigBuilder::new(&dir) + .with_reference_gas_price(700) + .with_objects( + input_coin_objects + .clone() + .into_iter() + .map(ToOwned::to_owned), + ) + .build(); + let genesis = network_config.genesis; + let keypair = network_config.validator_configs[0].protocol_key_pair(); + + let authority_state = init_state_with_committee(&genesis, keypair).await; + let rgp = authority_state.reference_gas_price_for_testing().unwrap(); + + let mut input_coins = Vec::new(); + for coin in input_coin_objects { + let id = coin.id(); + let object_ref = genesis + .objects() + .iter() + .find(|o| o.id() == id) + .unwrap() + .compute_object_reference(); + input_coins.push(object_ref); + } + + let mut builder = ProgrammableTransactionBuilder::new(); + builder.pay_all_iota(recipient); + let pt = builder.finish(); + let data = TransactionData::new_programmable(sender, input_coins, pt, gas_budget, rgp); + let tx = to_sender_signed_transaction(data, &sender_key); + let txn_result = send_and_confirm_transaction(&authority_state, tx) + .await + .map(|(_, effects)| effects); + PayIotaTransactionBlockExecutionResult { + authority_state, + txn_result, + } +} diff --git a/crates/sui-core/src/unit_tests/server_tests.rs b/crates/iota-core/src/unit_tests/server_tests.rs similarity index 94% rename from crates/sui-core/src/unit_tests/server_tests.rs rename to crates/iota-core/src/unit_tests/server_tests.rs index 2b7aea28e22..a1f1e61af3e 100644 --- a/crates/sui-core/src/unit_tests/server_tests.rs +++ b/crates/iota-core/src/unit_tests/server_tests.rs @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use sui_types::{ +use iota_types::{ base_types::{dbg_addr, dbg_object_id}, messages_grpc::LayoutGenerationOption, }; diff --git a/crates/sui-core/src/unit_tests/shared_object_deletion_tests.rs b/crates/iota-core/src/unit_tests/shared_object_deletion_tests.rs similarity index 99% rename from crates/sui-core/src/unit_tests/shared_object_deletion_tests.rs rename to crates/iota-core/src/unit_tests/shared_object_deletion_tests.rs index 3b1770eb3c3..094f77f755f 100644 --- a/crates/sui-core/src/unit_tests/shared_object_deletion_tests.rs +++ b/crates/iota-core/src/unit_tests/shared_object_deletion_tests.rs @@ -1,17 +1,17 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; -use move_core_types::ident_str; -use sui_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress, TransactionDigest}, +use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber, TransactionDigest}, committee::EpochId, crypto::{get_key_pair, AccountKeyPair}, effects::{TransactionEffects, TransactionEffectsAPI}, - error::{ExecutionError, SuiError}, + error::{ExecutionError, IotaError}, execution_status::{ CommandArgumentError, ExecutionFailureStatus, ExecutionFailureStatus::{InputObjectDeleted, SharedObjectOperationNotAllowed}, @@ -23,6 +23,7 @@ use sui_types::{ TEST_ONLY_GAS_UNIT_FOR_PUBLISH, }, }; +use move_core_types::ident_str; use crate::{ authority::{ @@ -39,7 +40,7 @@ use crate::{ }; pub struct TestRunner { - pub sender: SuiAddress, + pub sender: IotaAddress, pub sender_key: AccountKeyPair, pub gas_object_ids: Vec, pub authority_state: Arc, @@ -534,21 +535,21 @@ impl TestRunner { pub async fn certify_shared_obj_transaction( &mut self, tx: Transaction, - ) -> Result { + ) -> Result { certify_shared_obj_transaction_no_execution(&self.authority_state, tx).await } pub async fn enqueue_all_and_execute_all( &mut self, certificates: Vec, - ) -> Result, SuiError> { + ) -> Result, IotaError> { enqueue_all_and_execute_all(&self.authority_state, certificates).await } pub async fn execute_sequenced_certificate_to_effects( &mut self, certificate: VerifiedCertificate, - ) -> Result<(TransactionEffects, Option), SuiError> { + ) -> Result<(TransactionEffects, Option), IotaError> { execute_sequenced_certificate_to_effects(&self.authority_state, certificate).await } @@ -1824,7 +1825,7 @@ async fn test_object_lock_conflict() { assert!(matches!( mutate_cert_res.err(), - Some(SuiError::ObjectLockConflict { .. }) + Some(IotaError::ObjectLockConflict { .. }) )); } diff --git a/crates/sui-core/src/unit_tests/subscription_handler_tests.rs b/crates/iota-core/src/unit_tests/subscription_handler_tests.rs similarity index 90% rename from crates/sui-core/src/unit_tests/subscription_handler_tests.rs rename to crates/iota-core/src/unit_tests/subscription_handler_tests.rs index 149aa4ab4d1..b2f8dfa90b5 100644 --- a/crates/sui-core/src/unit_tests/subscription_handler_tests.rs +++ b/crates/iota-core/src/unit_tests/subscription_handler_tests.rs @@ -1,6 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_json_rpc_types::IotaMoveStruct; +use iota_types::{ + base_types::ObjectID, gas_coin::GasCoin, object::bounded_visitor::BoundedVisitor, + IOTA_FRAMEWORK_ADDRESS, MOVE_STDLIB_ADDRESS, +}; use move_core_types::{ account_address::AccountAddress, annotated_value::{MoveFieldLayout, MoveStructLayout, MoveTypeLayout}, @@ -10,11 +16,6 @@ use move_core_types::{ }; use serde::{Deserialize, Serialize}; use serde_json::json; -use sui_json_rpc_types::SuiMoveStruct; -use sui_types::{ - base_types::ObjectID, gas_coin::GasCoin, object::bounded_visitor::BoundedVisitor, - MOVE_STDLIB_ADDRESS, SUI_FRAMEWORK_ADDRESS, -}; #[test] fn test_to_json_value() { @@ -29,11 +30,11 @@ fn test_to_json_value() { ], }; let event_bytes = bcs::to_bytes(&move_event).unwrap(); - let sui_move_struct: SuiMoveStruct = + let iota_move_struct: IotaMoveStruct = BoundedVisitor::deserialize_struct(&event_bytes, &TestEvent::layout()) .unwrap() .into(); - let json_value = sui_move_struct.to_json_value(); + let json_value = iota_move_struct.to_json_value(); assert_eq!( Some(&json!("1000000")), json_value.pointer("/coins/0/balance") @@ -71,8 +72,8 @@ pub struct TestEvent { impl TestEvent { fn type_() -> StructTag { StructTag { - address: SUI_FRAMEWORK_ADDRESS, - module: ident_str!("SUI").to_owned(), + address: IOTA_FRAMEWORK_ADDRESS, + module: ident_str!("IOTA").to_owned(), name: ident_str!("new_foobar").to_owned(), type_params: vec![], } @@ -101,7 +102,7 @@ impl TestEvent { } // Rust version of the Move std::string::String type -// TODO: Do we need this in the sui-types lib? +// TODO: Do we need this in the iota-types lib? #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] struct UTF8String { bytes: String, diff --git a/crates/sui-core/src/unit_tests/transaction_deny_tests.rs b/crates/iota-core/src/unit_tests/transaction_deny_tests.rs similarity index 94% rename from crates/sui-core/src/unit_tests/transaction_deny_tests.rs rename to crates/iota-core/src/unit_tests/transaction_deny_tests.rs index 788aec3dccb..9cb086df1f8 100644 --- a/crates/sui-core/src/unit_tests/transaction_deny_tests.rs +++ b/crates/iota-core/src/unit_tests/transaction_deny_tests.rs @@ -1,23 +1,23 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{path::PathBuf, sync::Arc}; use fastcrypto::{ed25519::Ed25519KeyPair, traits::KeyPair}; -use move_core_types::ident_str; -use sui_config::{ +use iota_config::{ certificate_deny_config::CertificateDenyConfigBuilder, transaction_deny_config::{TransactionDenyConfig, TransactionDenyConfigBuilder}, }; -use sui_swarm_config::{ +use iota_swarm_config::{ genesis_config::{AccountConfig, DEFAULT_GAS_AMOUNT}, network_config::NetworkConfig, }; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef}, effects::TransactionEffectsAPI, - error::{SuiError, SuiResult, UserInputError}, + error::{IotaError, IotaResult, UserInputError}, execution_status::{ExecutionFailureStatus, ExecutionStatus}, messages_grpc::HandleTransactionResponse, transaction::{ @@ -29,6 +29,7 @@ use sui_types::{ to_sender_signed_transaction_with_multi_signers, }, }; +use move_core_types::ident_str; use crate::{ authority::{ @@ -38,7 +39,7 @@ use crate::{ test_authority_builder::TestAuthorityBuilder, AuthorityState, }, - test_utils::make_transfer_sui_transaction, + test_utils::make_transfer_iota_transaction, }; const ACCOUNT_NUM: usize = 5; @@ -46,7 +47,7 @@ const GAS_OBJECT_COUNT: usize = 15; async fn setup_test(deny_config: TransactionDenyConfig) -> (NetworkConfig, Arc) { let network_config = - sui_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir() + iota_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir() .with_accounts(vec![ AccountConfig { address: None, @@ -76,7 +77,7 @@ async fn reload_state_with_new_deny_config( .await } -type Account = (SuiAddress, Ed25519KeyPair, Vec); +type Account = (IotaAddress, Ed25519KeyPair, Vec); fn get_accounts_and_coins( network_config: &NetworkConfig, @@ -86,7 +87,7 @@ fn get_accounts_and_coins( .account_keys .iter() .map(|account| { - let address: SuiAddress = account.public().into(); + let address: IotaAddress = account.public().into(); let objects: Vec<_> = state .get_owner_objects(address, None, GAS_OBJECT_COUNT, None) .unwrap() @@ -104,7 +105,7 @@ fn get_accounts_and_coins( async fn process_zklogin_tx( tx: Transaction, state: &Arc, -) -> SuiResult { +) -> IotaResult { let verified_tx = VerifiedTransaction::new_from_verified(tx); state @@ -116,9 +117,9 @@ async fn transfer_with_account( sender_account: &Account, sponsor_account: &Account, state: &Arc, -) -> SuiResult { +) -> IotaResult { let rgp = state.reference_gas_price_for_testing().unwrap(); - let data = TransactionData::new_transfer_sui_allow_sponsor( + let data = TransactionData::new_transfer_iota_allow_sponsor( sender_account.0, sender_account.0, None, @@ -148,7 +149,7 @@ async fn handle_move_call_transaction( args: Vec, account: &Account, gas_payment_index: usize, -) -> SuiResult { +) -> IotaResult { let rgp = state.reference_gas_price_for_testing().unwrap(); let data = TransactionData::new_move_call( account.0, @@ -168,10 +169,10 @@ async fn handle_move_call_transaction( state.handle_transaction(&epoch_store, tx).await } -fn assert_denied(result: &SuiResult) { +fn assert_denied(result: &IotaResult) { assert!(matches!( result.as_ref().unwrap_err(), - SuiError::UserInputError { + IotaError::UserInputError { error: UserInputError::TransactionDenied { .. } } )); @@ -265,7 +266,7 @@ async fn test_shared_object_transaction_disabled() { let gas_price = state.reference_gas_price_for_testing().unwrap(); let account = &accounts[0]; let tx = TestTransactionBuilder::new(account.0, account.2[0], gas_price) - .call_staking(account.2[1], SuiAddress::default()) + .call_staking(account.2[1], IotaAddress::default()) .build_and_sign(&account.1); let epoch_store = state.epoch_store_for_testing(); let tx = epoch_store.verify_transaction(tx).unwrap(); @@ -451,7 +452,7 @@ async fn test_certificate_deny() { let (sender, key, gas_objects) = get_accounts_and_coins(&network_config, &state) .pop() .unwrap(); - let tx = make_transfer_sui_transaction( + let tx = make_transfer_iota_transaction( gas_objects[0], sender, None, diff --git a/crates/sui-core/src/unit_tests/transaction_manager_tests.rs b/crates/iota-core/src/unit_tests/transaction_manager_tests.rs similarity index 99% rename from crates/sui-core/src/unit_tests/transaction_manager_tests.rs rename to crates/iota-core/src/unit_tests/transaction_manager_tests.rs index 0347c3fb900..89318e78fd1 100644 --- a/crates/sui-core/src/unit_tests/transaction_manager_tests.rs +++ b/crates/iota-core/src/unit_tests/transaction_manager_tests.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{time::Duration, vec}; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ base_types::ObjectID, crypto::deterministic_random_account_key, executable_transaction::VerifiedExecutableTransaction, object::Object, storage::InputKey, transaction::{CallArg, ObjectArg, VerifiedTransaction}, - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, }; use tokio::{ sync::mpsc::{error::TryRecvError, unbounded_channel, UnboundedReceiver}, @@ -47,7 +48,7 @@ fn make_transaction(gas_object: Object, input: Vec) -> VerifiedExecutab let (sender, keypair) = deterministic_random_account_key(); let transaction = TestTransactionBuilder::new(sender, gas_object.compute_object_reference(), rgp) - .move_call(SUI_FRAMEWORK_PACKAGE_ID, "counter", "assert_value", input) + .move_call(IOTA_FRAMEWORK_PACKAGE_ID, "counter", "assert_value", input) .build_and_sign(&keypair); VerifiedExecutableTransaction::new_system(VerifiedTransaction::new_unchecked(transaction), 0) } diff --git a/crates/iota-core/src/unit_tests/transaction_tests.rs b/crates/iota-core/src/unit_tests/transaction_tests.rs new file mode 100644 index 00000000000..145c710892e --- /dev/null +++ b/crates/iota-core/src/unit_tests/transaction_tests.rs @@ -0,0 +1,1255 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::ops::Deref; + +use fastcrypto::{ed25519::Ed25519KeyPair, traits::KeyPair}; +use fastcrypto_zkp::bn254::zk_login::{parse_jwks, OIDCProvider, ZkLoginInputs}; +use iota_macros::sim_test; +use iota_types::{ + authenticator_state::ActiveJwk, + base_types::dbg_addr, + crypto::{get_key_pair, AccountKeyPair, IotaKeyPair, Signature}, + error::{IotaError, UserInputError}, + multisig::{MultiSig, MultiSigPublicKey}, + signature::GenericSignature, + transaction::{ + AuthenticatorStateUpdate, GenesisTransaction, TransactionDataAPI, TransactionExpiration, + TransactionKind, + }, + utils::{load_test_vectors, to_sender_signed_transaction}, + zk_login_authenticator::ZkLoginAuthenticator, + zk_login_util::DEFAULT_JWK_BYTES, +}; +use mysten_network::Multiaddr; +use rand::{rngs::StdRng, SeedableRng}; +use shared_crypto::intent::{Intent, IntentMessage}; + +macro_rules! assert_matches { + ($expression:expr, $pattern:pat $(if $guard: expr)?) => { + match $expression { + $pattern $(if $guard)? => {} + ref e => panic!( + "assertion failed: `(left == right)` \ + (left: `{:?}`, right: `{:?}`)", + e, + stringify!($pattern $(if $guard)?) + ), + } + }; +} + +use fastcrypto::traits::AggregateAuthenticator; +use iota_types::programmable_transaction_builder::ProgrammableTransactionBuilder; + +use super::*; +pub use crate::authority::authority_test_utils::init_state_with_ids; +use crate::{ + authority_client::{AuthorityAPI, NetworkAuthorityClient}, + authority_server::{AuthorityServer, AuthorityServerHandle}, + stake_aggregator::{InsertResult, StakeAggregator}, +}; + +#[sim_test] +async fn test_handle_transfer_transaction_bad_signature() { + do_transaction_test( + 1, + |_| {}, + |mut_tx| { + let (_unknown_address, unknown_key): (_, AccountKeyPair) = get_key_pair(); + let data = mut_tx.data_mut_for_testing(); + *data.tx_signatures_mut_for_testing() = + vec![Signature::new_secure(data.intent_message(), &unknown_key).into()]; + }, + |err| { + assert_matches!(err, IotaError::SignerSignatureAbsent { .. }); + }, + ) + .await; +} + +#[sim_test] +async fn test_handle_transfer_transaction_no_signature() { + do_transaction_test( + 1, + |_| {}, + |tx| { + *tx.data_mut_for_testing().tx_signatures_mut_for_testing() = vec![]; + }, + |err| { + assert_matches!( + err, + IotaError::SignerSignatureNumberMismatch { + expected: 1, + actual: 0 + } + ); + }, + ) + .await; +} + +#[sim_test] +async fn test_handle_transfer_transaction_extra_signature() { + do_transaction_test( + 1, + |_| {}, + |tx| { + let sigs = tx.data_mut_for_testing().tx_signatures_mut_for_testing(); + sigs.push(sigs[0].clone()); + }, + |err| { + assert_matches!( + err, + IotaError::SignerSignatureNumberMismatch { + expected: 1, + actual: 2 + } + ); + }, + ) + .await; +} + +// TODO: verify that these cases are not exploitable via consensus input +#[sim_test] +async fn test_empty_sender_signed_data() { + do_transaction_test( + 0, + |_| {}, + |tx| { + let data = tx.data_mut_for_testing(); + data.inner_vec_mut_for_testing().clear(); + }, + |err| { + assert_matches!( + err, + IotaError::UserInputError { + error: UserInputError::Unsupported { .. } + } + ); + }, + ) + .await; +} + +#[sim_test] +async fn test_multiple_sender_signed_data() { + do_transaction_test( + 0, + |_| {}, + |tx| { + let data = tx.data_mut_for_testing(); + let tx_vec = data.inner_vec_mut_for_testing(); + assert_eq!(tx_vec.len(), 1); + let mut new = tx_vec[0].clone(); + // make sure second message has unique digest + *new.intent_message.value.expiration_mut_for_testing() = + TransactionExpiration::Epoch(123); + tx_vec.push(new); + }, + |err| { + assert_matches!( + err, + IotaError::UserInputError { + error: UserInputError::Unsupported { .. } + } + ); + }, + ) + .await; +} + +#[sim_test] +async fn test_duplicate_sender_signed_data() { + do_transaction_test( + 0, + |_| {}, + |tx| { + let data = tx.data_mut_for_testing(); + let tx_vec = data.inner_vec_mut_for_testing(); + assert_eq!(tx_vec.len(), 1); + let new = tx_vec[0].clone(); + tx_vec.push(new); + }, + |err| { + assert_matches!( + err, + IotaError::UserInputError { + error: UserInputError::Unsupported { .. } + } + ); + }, + ) + .await; +} + +#[sim_test] +async fn test_empty_gas_data() { + do_transaction_test_skip_cert_checks( + 0, + |tx| { + tx.gas_data_mut().payment = vec![]; + }, + |_| {}, + |err| { + assert_matches!( + err, + IotaError::UserInputError { + error: UserInputError::MissingGasPayment + } + ); + }, + ) + .await; +} + +#[sim_test] +async fn test_duplicate_gas_data() { + do_transaction_test_skip_cert_checks( + 0, + |tx| { + let gas_data = tx.gas_data_mut(); + let new_gas = gas_data.payment[0]; + gas_data.payment.push(new_gas); + }, + |_| {}, + |err| { + assert_matches!( + err, + IotaError::UserInputError { + error: UserInputError::MutableObjectUsedMoreThanOnce { .. } + } + ); + }, + ) + .await; +} + +#[sim_test] +async fn test_gas_wrong_owner_matches_sender() { + do_transaction_test( + 1, + |tx| { + let gas_data = tx.gas_data_mut(); + let (new_addr, _): (_, AccountKeyPair) = get_key_pair(); + gas_data.owner = new_addr; + *tx.sender_mut_for_testing() = new_addr; + }, + |_| {}, + |err| { + assert_matches!(err, IotaError::SignerSignatureAbsent { .. }); + }, + ) + .await; +} + +#[sim_test] +async fn test_gas_wrong_owner() { + do_transaction_test( + 1, + |tx| { + let gas_data = tx.gas_data_mut(); + let (new_addr, _): (_, AccountKeyPair) = get_key_pair(); + gas_data.owner = new_addr; + }, + |_| {}, + |err| { + assert_matches!( + err, + IotaError::SignerSignatureNumberMismatch { + expected: 2, + actual: 1 + } + ); + }, + ) + .await; +} + +#[sim_test] +async fn test_user_sends_system_transaction() { + do_transaction_test_skip_cert_checks( + 0, + |tx| { + *tx.kind_mut() = TransactionKind::Genesis(GenesisTransaction { objects: vec![] }); + }, + |_| {}, + |err| { + assert_matches!( + err, + IotaError::UserInputError { + error: UserInputError::Unsupported { .. } + } + ); + }, + ) + .await; +} + +pub fn init_transfer_transaction( + pre_sign_mutations: impl FnOnce(&mut TransactionData), + sender: IotaAddress, + secret: &AccountKeyPair, + recipient: IotaAddress, + object_ref: ObjectRef, + gas_object_ref: ObjectRef, + gas_budget: u64, + gas_price: u64, +) -> Transaction { + let mut data = TransactionData::new_transfer( + recipient, + object_ref, + sender, + gas_object_ref, + gas_budget, + gas_price, + ); + pre_sign_mutations(&mut data); + to_sender_signed_transaction(data, secret) +} + +async fn do_transaction_test_skip_cert_checks( + expected_sig_errors: u64, + pre_sign_mutations: impl FnOnce(&mut TransactionData), + post_sign_mutations: impl FnOnce(&mut Transaction), + err_check: impl Fn(&IotaError), +) { + do_transaction_test_impl( + expected_sig_errors, + false, + pre_sign_mutations, + post_sign_mutations, + err_check, + ) + .await +} + +async fn do_transaction_test( + expected_sig_errors: u64, + pre_sign_mutations: impl FnOnce(&mut TransactionData), + post_sign_mutations: impl FnOnce(&mut Transaction), + err_check: impl Fn(&IotaError), +) { + do_transaction_test_impl( + expected_sig_errors, + true, + pre_sign_mutations, + post_sign_mutations, + err_check, + ) + .await +} + +async fn do_transaction_test_impl( + _expected_sig_errors: u64, + check_forged_cert: bool, + pre_sign_mutations: impl FnOnce(&mut TransactionData), + post_sign_mutations: impl FnOnce(&mut Transaction), + err_check: impl Fn(&IotaError), +) { + telemetry_subscribers::init_for_testing(); + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let recipient = dbg_addr(2); + let object_id = ObjectID::random(); + let gas_object_id = ObjectID::random(); + let authority_state = + init_state_with_ids(vec![(sender, object_id), (sender, gas_object_id)]).await; + let rgp = authority_state.reference_gas_price_for_testing().unwrap(); + let object = authority_state + .get_object(&object_id) + .await + .unwrap() + .unwrap(); + let gas_object = authority_state + .get_object(&gas_object_id) + .await + .unwrap() + .unwrap(); + + let mut transfer_transaction = init_transfer_transaction( + pre_sign_mutations, + sender, + &sender_key, + recipient, + object.compute_object_reference(), + gas_object.compute_object_reference(), + rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, + rgp, + ); + + let consensus_address = "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(); + + let server = AuthorityServer::new_for_test( + "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(), + authority_state.clone(), + consensus_address, + ); + + let server_handle = server.spawn_for_test().await.unwrap(); + + let client = NetworkAuthorityClient::connect(server_handle.address()) + .await + .unwrap(); + + post_sign_mutations(&mut transfer_transaction); + + let err = client + .handle_transaction(transfer_transaction.clone()) + .await + .unwrap_err(); + err_check(&err); + + check_locks(authority_state.clone(), vec![object_id]).await; + + // now verify that the same transaction is rejected if a false certificate is + // somehow formed and sent + if check_forged_cert { + let epoch_store = authority_state.epoch_store_for_testing(); + let signed_transaction = VerifiedSignedTransaction::new( + epoch_store.epoch(), + VerifiedTransaction::new_unchecked(transfer_transaction), + authority_state.name, + &*authority_state.secret, + ); + let mut agg = StakeAggregator::new(epoch_store.committee().clone()); + + let InsertResult::QuorumReached(cert_sig) = agg.insert(signed_transaction.clone().into()) + else { + panic!("quorum expected"); + }; + + let plain_tx = signed_transaction.into_inner(); + + let ct = CertifiedTransaction::new_from_data_and_sig(plain_tx.into_data(), cert_sig); + + let err = client.handle_certificate_v2(ct.clone()).await.unwrap_err(); + err_check(&err); + epoch_store.clear_signature_cache(); + let err = client.handle_certificate_v2(ct.clone()).await.unwrap_err(); + err_check(&err); + } +} + +#[sim_test] +async fn test_zklogin_transfer_with_bad_ephemeral_sig() { + do_zklogin_transaction_test( + 1, + |_| {}, + |tx| { + let data = tx.data_mut_for_testing(); + let intent_message = data.intent_message().clone(); + let sigs = data.tx_signatures_mut_for_testing(); + let GenericSignature::ZkLoginAuthenticator(zklogin) = sigs.get_mut(0).unwrap() else { + panic!(); + }; + + let (_unknown_address, unknown_key): (_, AccountKeyPair) = get_key_pair(); + let sig = Signature::new_secure(&intent_message, &unknown_key); + *zklogin.user_signature_mut_for_testing() = sig; + }, + ) + .await; +} +#[sim_test] +async fn test_zklogin_transfer_with_large_address_seed() { + telemetry_subscribers::init_for_testing(); + let (object_ids, gas_object_ids, authority_state, _epoch_store, _, _, _server, client) = + setup_zklogin_network(|_| {}).await; + + let ephemeral_key = Ed25519KeyPair::generate(&mut StdRng::from_seed([3; 32])); + + let large_address_seed = + num_bigint::BigInt::from_bytes_be(num_bigint::Sign::Plus, &[1; 33]).to_string(); + let zklogin = ZkLoginInputs::from_json("{\"proofPoints\":{\"a\":[\"7351610957585487046328875967050889651854514987235893782501043846344306437586\",\"15901581830174345085102528605366245320934422564305327249129736514949843983391\",\"1\"],\"b\":[[\"8511334686125322419369086121569737536249817670014553268281989325333085952301\",\"4879445774811020644521006463993914729416121646921376735430388611804034116132\"],[\"17435652898871739253945717312312680537810513841582909477368887889905134847157\",\"14885460127400879557124294989610467103783286587437961743305395373299049315863\"],[\"1\",\"0\"]],\"c\":[\"18935582624804960299209074901817240117999581542763303721451852621662183299378\",\"5367019427921492326304024952457820199970536888356564030410757345854117465786\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", &large_address_seed).unwrap(); + let sender = IotaAddress::generate(StdRng::from_seed([3; 32])); + let recipient = dbg_addr(2); + + let tx = init_zklogin_transfer( + &authority_state, + object_ids[2], + gas_object_ids[2], + recipient, + sender, + |_| {}, + &ephemeral_key, + &zklogin, + ) + .await; + + assert!(client.handle_transaction(tx).await.is_err()); +} + +#[sim_test] +async fn zklogin_test_cached_proof_wrong_key() { + telemetry_subscribers::init_for_testing(); + let ( + mut object_ids, + gas_object_ids, + authority_state, + _epoch_store, + transfer_transaction, + metrics, + _server, + client, + ) = setup_zklogin_network(|_| {}).await; + + let res = client.handle_transaction(transfer_transaction).await; + assert!(res.is_ok()); + + // assert_eq!( + // epoch_store + // .signature_verifier + // .metrics + // .zklogin_inputs_cache_misses + // .get(), + // 1 + // ); + + let (skp, _eph_pk, zklogin) = + &load_test_vectors("../iota-types/src/unit_tests/zklogin_test_vectors.json")[1]; + let ephemeral_key = match skp { + IotaKeyPair::Ed25519(kp) => kp, + _ => panic!(), + }; + let sender = IotaAddress::try_from_unpadded(zklogin).unwrap(); + let recipient = dbg_addr(2); + + let mut transfer_transaction2 = init_zklogin_transfer( + &authority_state, + object_ids[2], + gas_object_ids[2], + recipient, + sender, + |_| {}, + ephemeral_key, + zklogin, + ) + .await; + + let intent_message = transfer_transaction2.data().intent_message().clone(); + match &mut transfer_transaction2 + .data_mut_for_testing() + .tx_signatures_mut_for_testing()[0] + { + GenericSignature::ZkLoginAuthenticator(zklogin) => { + let (_unknown_address, unknown_key): (_, AccountKeyPair) = get_key_pair(); + // replace the signature with a bogus one + *zklogin.user_signature_mut_for_testing() = + Signature::new_secure(&intent_message, &unknown_key); + } + _ => panic!(), + } + + // This tx should fail, but passes because we skip the ephemeral sig check when + // hitting the zklogin check! + assert!( + client + .handle_transaction(transfer_transaction2) + .await + .is_err() + ); + + // TODO: re-enable when cache is re-enabled. + // assert_eq!( + // epoch_store + // .signature_verifier + // .metrics + // .zklogin_inputs_cache_hits + // .get(), + // 1 + // ); + + assert_eq!(metrics.signature_errors.get(), 1); + + object_ids.remove(0); // first object was successfully locked. + check_locks(authority_state, object_ids).await; +} + +async fn do_zklogin_transaction_test( + expected_sig_errors: u64, + pre_sign_mutations: impl FnOnce(&mut TransactionData), + post_sign_mutations: impl FnOnce(&mut Transaction), +) { + let ( + object_ids, + _gas_object_id, + authority_state, + _epoch_store, + mut transfer_transaction, + metrics, + _server, + client, + ) = setup_zklogin_network(pre_sign_mutations).await; + + post_sign_mutations(&mut transfer_transaction); + + assert!( + client + .handle_transaction(transfer_transaction) + .await + .is_err() + ); + + // TODO: re-enable when cache is re-enabled. + // assert_eq!( + // epoch_store + // .signature_verifier + // .metrics + // .zklogin_inputs_cache_misses + // .get(), + // 1 + // ); + + assert_eq!(metrics.signature_errors.get(), expected_sig_errors); + + check_locks(authority_state, object_ids).await; +} + +async fn check_locks(authority_state: Arc, object_ids: Vec) { + for object_id in object_ids { + let object = authority_state + .get_object(&object_id) + .await + .unwrap() + .unwrap(); + assert!( + authority_state + .get_transaction_lock( + &object.compute_object_reference(), + &authority_state.epoch_store_for_testing() + ) + .await + .unwrap() + .is_none() + ); + } +} + +async fn setup_zklogin_network( + pre_sign_mutations: impl FnOnce(&mut TransactionData), +) -> ( + Vec, // objects + Vec, // gas objects + Arc, + Guard>, + iota_types::message_envelope::Envelope, + Arc, + AuthorityServerHandle, + NetworkAuthorityClient, +) { + let (skp, _eph_pk, zklogin) = + &load_test_vectors("../iota-types/src/unit_tests/zklogin_test_vectors.json")[1]; + let ephemeral_key = match skp { + IotaKeyPair::Ed25519(kp) => kp, + _ => panic!(), + }; + let sender = IotaAddress::try_from_unpadded(zklogin).unwrap(); + + let recipient = dbg_addr(2); + let objects: Vec<_> = (0..10).map(|_| (sender, ObjectID::random())).collect(); + let gas_objects: Vec<_> = (0..10).map(|_| (sender, ObjectID::random())).collect(); + let object_ids: Vec<_> = objects.iter().map(|(_, id)| *id).collect(); + let gas_object_ids: Vec<_> = gas_objects.iter().map(|(_, id)| *id).collect(); + + let authority_state = + init_state_with_ids(objects.into_iter().chain(gas_objects).collect::>()).await; + + let object_id = object_ids[0]; + let gas_object_id = gas_object_ids[0]; + let jwks = parse_jwks(DEFAULT_JWK_BYTES, &OIDCProvider::Twitch).unwrap(); + let epoch_store = authority_state.epoch_store_for_testing(); + epoch_store.update_authenticator_state(&AuthenticatorStateUpdate { + epoch: 0, + round: 0, + new_active_jwks: jwks + .into_iter() + .map(|(jwk_id, jwk)| ActiveJwk { + jwk_id, + jwk, + epoch: 0, + }) + .collect(), + authenticator_obj_initial_shared_version: 1.into(), + }); + + let transfer_transaction = init_zklogin_transfer( + &authority_state, + object_id, + gas_object_id, + recipient, + sender, + pre_sign_mutations, + ephemeral_key, + zklogin, + ) + .await; + + let consensus_address = "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(); + + let server = AuthorityServer::new_for_test( + "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(), + authority_state.clone(), + consensus_address, + ); + let metrics = server.metrics.clone(); + + let server_handle = server.spawn_for_test().await.unwrap(); + + let client = NetworkAuthorityClient::connect(server_handle.address()) + .await + .unwrap(); + ( + object_ids, + gas_object_ids, + authority_state, + epoch_store, + transfer_transaction, + metrics, + server_handle, + client, + ) +} + +async fn init_zklogin_transfer( + authority_state: &Arc, + object_id: ObjectID, + gas_object_id: ObjectID, + recipient: IotaAddress, + sender: IotaAddress, + pre_sign_mutations: impl FnOnce(&mut TransactionData), + ephemeral_key: &Ed25519KeyPair, + zklogin: &ZkLoginInputs, +) -> iota_types::message_envelope::Envelope { + let rgp = authority_state.reference_gas_price_for_testing().unwrap(); + let object = authority_state + .get_object(&object_id) + .await + .unwrap() + .unwrap(); + let gas_object = authority_state + .get_object(&gas_object_id) + .await + .unwrap() + .unwrap(); + let object_ref = object.compute_object_reference(); + let gas_object_ref = gas_object.compute_object_reference(); + let gas_budget = rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER; + let mut data = TransactionData::new_transfer( + recipient, + object_ref, + sender, + gas_object_ref, + gas_budget, + rgp, + ); + pre_sign_mutations(&mut data); + let mut tx = to_sender_signed_transaction(data, ephemeral_key); + let GenericSignature::Signature(signature) = + tx.data_mut_for_testing().tx_signatures_mut_for_testing()[0].clone() + else { + panic!(); + }; + let authenticator = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( + zklogin.clone(), + 2, + signature, + )); + tx.data_mut_for_testing().tx_signatures_mut_for_testing()[0] = authenticator; + tx +} + +#[tokio::test] +async fn zklogin_txn_fail_if_missing_jwk() { + telemetry_subscribers::init_for_testing(); + + // Initialize an authorty state with some objects under a zklogin address. + let (skp, _eph_pk, zklogin) = + &load_test_vectors("../iota-types/src/unit_tests/zklogin_test_vectors.json")[1]; + let ephemeral_key = match skp { + IotaKeyPair::Ed25519(kp) => kp, + _ => panic!(), + }; + let sender = IotaAddress::try_from_unpadded(zklogin).unwrap(); + let recipient = dbg_addr(2); + let objects: Vec<_> = (0..10).map(|_| (sender, ObjectID::random())).collect(); + let gas_objects: Vec<_> = (0..10).map(|_| (sender, ObjectID::random())).collect(); + let object_ids: Vec<_> = objects.iter().map(|(_, id)| *id).collect(); + let gas_object_ids: Vec<_> = gas_objects.iter().map(|(_, id)| *id).collect(); + let authority_state = + init_state_with_ids(objects.into_iter().chain(gas_objects).collect::>()).await; + + // Initialize an authenticator state with a Google JWK. + let jwks = parse_jwks(DEFAULT_JWK_BYTES, &OIDCProvider::Google).unwrap(); + let epoch_store = authority_state.epoch_store_for_testing(); + epoch_store.update_authenticator_state(&AuthenticatorStateUpdate { + epoch: 0, + round: 0, + new_active_jwks: jwks + .into_iter() + .map(|(jwk_id, jwk)| ActiveJwk { + jwk_id, + jwk, + epoch: 0, + }) + .collect(), + authenticator_obj_initial_shared_version: 1.into(), + }); + + // Case 1: Submit a transaction with zklogin signature derived from a Twitch JWT + // should fail. + let txn1 = init_zklogin_transfer( + &authority_state, + object_ids[2], + gas_object_ids[2], + recipient, + sender, + |_| {}, + ephemeral_key, + zklogin, + ) + .await; + execute_transaction_assert_err(authority_state.clone(), txn1.clone(), object_ids.clone()).await; + + // Initialize an authenticator state with Twitch's kid as "nosuckkey". + pub const BAD_JWK_BYTES: &[u8] = r#"{"keys":[{"alg":"RS256","e":"AQAB","kid":"nosuchkey","kty":"RSA","n":"6lq9MQ-q6hcxr7kOUp-tHlHtdcDsVLwVIw13iXUCvuDOeCi0VSuxCCUY6UmMjy53dX00ih2E4Y4UvlrmmurK0eG26b-HMNNAvCGsVXHU3RcRhVoHDaOwHwU72j7bpHn9XbP3Q3jebX6KIfNbei2MiR0Wyb8RZHE-aZhRYO8_-k9G2GycTpvc-2GBsP8VHLUKKfAs2B6sW3q3ymU6M0L-cFXkZ9fHkn9ejs-sqZPhMJxtBPBxoUIUQFTgv4VXTSv914f_YkNw-EjuwbgwXMvpyr06EyfImxHoxsZkFYB-qBYHtaMxTnFsZBr6fn8Ha2JqT1hoP7Z5r5wxDu3GQhKkHw","use":"sig"}]}"#.as_bytes(); + let jwks = parse_jwks(BAD_JWK_BYTES, &OIDCProvider::Twitch).unwrap(); + epoch_store.update_authenticator_state(&AuthenticatorStateUpdate { + epoch: 0, + round: 0, + new_active_jwks: jwks + .into_iter() + .map(|(jwk_id, jwk)| ActiveJwk { + jwk_id, + jwk, + epoch: 0, + }) + .collect(), + authenticator_obj_initial_shared_version: 1.into(), + }); + + // Case 2: Submit a transaction with zklogin signature derived from a Twitch JWT + // with kid "1" should fail. + execute_transaction_assert_err(authority_state, txn1, object_ids).await; +} + +#[tokio::test] +async fn zk_multisig_test() { + telemetry_subscribers::init_for_testing(); + + // User generate a multisig account with no zklogin signer. + let keys = iota_types::utils::keys(); + let pk1 = keys[0].public(); + let pk2 = keys[1].public(); + let pk3 = keys[2].public(); + let multisig_pk = MultiSigPublicKey::new( + vec![pk1.clone(), pk2.clone(), pk3.clone()], + vec![1, 1, 1], + 2, + ) + .unwrap(); + let victim_addr = IotaAddress::from(&multisig_pk); + + let recipient = dbg_addr(2); + let object_id = ObjectID::random(); + let gas_object_id = ObjectID::random(); + let authority_state = + init_state_with_ids(vec![(victim_addr, object_id), (victim_addr, gas_object_id)]).await; + + let jwks = parse_jwks(DEFAULT_JWK_BYTES, &OIDCProvider::Twitch).unwrap(); + let epoch_store = authority_state.epoch_store_for_testing(); + epoch_store.update_authenticator_state(&AuthenticatorStateUpdate { + epoch: 0, + round: 0, + new_active_jwks: jwks + .into_iter() + .map(|(jwk_id, jwk)| ActiveJwk { + jwk_id, + jwk, + epoch: 0, + }) + .collect(), + authenticator_obj_initial_shared_version: 1.into(), + }); + + let rgp = authority_state.reference_gas_price_for_testing().unwrap(); + let object = authority_state + .get_object(&object_id) + .await + .unwrap() + .unwrap(); + let gas_object = authority_state + .get_object(&gas_object_id) + .await + .unwrap() + .unwrap(); + + let data = TransactionData::new_transfer( + recipient, + object.compute_object_reference(), + victim_addr, + gas_object.compute_object_reference(), + rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, + rgp, + ); + + // Step 1. construct 2 zklogin signatures + let test_vectors = + &load_test_vectors("../iota-types/src/unit_tests/zklogin_test_vectors.json")[1..]; + let mut zklogin_sigs = vec![]; + for (kp, _pk_zklogin, inputs) in test_vectors { + let intent_message = IntentMessage::new(Intent::iota_transaction(), data.clone()); + let eph_sig = Signature::new_secure(&intent_message, kp); + let zklogin_sig = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( + inputs.clone(), + 2, + eph_sig, + )); + zklogin_sigs.push(zklogin_sig); + } + + // Step 2. Construct the fake multisig with the zklogin signatures. + let multisig = MultiSig::insecure_new( + vec![ + zklogin_sigs[0].clone().to_compressed().unwrap(), + zklogin_sigs[1].clone().to_compressed().unwrap(), + ], // zklogin sigs + 3, + multisig_pk, + ); + let generic_sig = GenericSignature::MultiSig(multisig); + let transfer_transaction = Transaction::from_generic_sig_data(data, vec![generic_sig]); + + execute_transaction_assert_err(authority_state, transfer_transaction, vec![object_id]).await; +} + +async fn execute_transaction_assert_err( + authority_state: Arc, + txn: Transaction, + object_ids: Vec, +) { + let consensus_address = "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(); + + let server = AuthorityServer::new_for_test( + "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(), + authority_state.clone(), + consensus_address, + ); + + let server_handle = server.spawn_for_test().await.unwrap(); + + let client = NetworkAuthorityClient::connect(server_handle.address()) + .await + .unwrap(); + + let err = client.handle_transaction(txn.clone()).await; + + assert!(dbg!(err).is_err()); + + check_locks(authority_state.clone(), object_ids).await; +} + +#[tokio::test] +async fn test_oversized_txn() { + telemetry_subscribers::init_for_testing(); + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let recipient = dbg_addr(2); + let object_id = ObjectID::random(); + let authority_state = init_state_with_ids(vec![(sender, object_id)]).await; + let max_txn_size = authority_state + .epoch_store_for_testing() + .protocol_config() + .max_tx_size_bytes() as usize; + let object = authority_state + .get_object(&object_id) + .await + .unwrap() + .unwrap(); + let obj_ref = object.compute_object_reference(); + + // Construct an oversized txn. + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + // Put a lot of commands in the txn so it's large. + for _ in 0..(1024 * 16) { + builder.transfer_object(recipient, obj_ref).unwrap(); + } + builder.finish() + }; + + let txn_data = TransactionData::new_programmable(sender, vec![obj_ref], pt, 0, 0); + + let txn = to_sender_signed_transaction(txn_data, &sender_key); + let tx_size = bcs::serialized_size(&txn).unwrap(); + + // Making sure the txn is larger than the max txn size. + assert!(tx_size > max_txn_size); + + let consensus_address = "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(); + + let server = AuthorityServer::new_for_test( + "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(), + authority_state.clone(), + consensus_address, + ); + + let server_handle = server.spawn_for_test().await.unwrap(); + + let client = NetworkAuthorityClient::connect(server_handle.address()) + .await + .unwrap(); + + let res = client.handle_transaction(txn).await; + // The txn should be rejected due to its size. + assert!( + res.err() + .unwrap() + .to_string() + .contains("serialized transaction size exceeded maximum") + ); +} + +#[tokio::test] +async fn test_very_large_certificate() { + telemetry_subscribers::init_for_testing(); + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let recipient = dbg_addr(2); + let object_id = ObjectID::random(); + let gas_object_id = ObjectID::random(); + let authority_state = + init_state_with_ids(vec![(sender, object_id), (sender, gas_object_id)]).await; + let rgp = authority_state.reference_gas_price_for_testing().unwrap(); + let object = authority_state + .get_object(&object_id) + .await + .unwrap() + .unwrap(); + let gas_object = authority_state + .get_object(&gas_object_id) + .await + .unwrap() + .unwrap(); + + let transfer_transaction = init_transfer_transaction( + |_| {}, + sender, + &sender_key, + recipient, + object.compute_object_reference(), + gas_object.compute_object_reference(), + rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, + rgp, + ); + + let consensus_address = "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(); + + let server = AuthorityServer::new_for_test( + "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(), + authority_state.clone(), + consensus_address, + ); + + let server_handle = server.spawn_for_test().await.unwrap(); + + let client = NetworkAuthorityClient::connect(server_handle.address()) + .await + .unwrap(); + + let auth_sig = client + .handle_transaction(transfer_transaction.clone()) + .await + .unwrap() + .status + .into_signed_for_testing(); + + let signatures: BTreeMap<_, _> = vec![auth_sig] + .into_iter() + .map(|a| (a.authority, a.signature)) + .collect(); + + // Insert a lot into the bitmap so the cert is very large, while the txn inside + // is reasonably sized. + let mut signers_map = roaring::bitmap::RoaringBitmap::new(); + signers_map.insert_range(0..52108864); + let sigs: Vec = signatures.into_values().collect(); + + let quorum_signature = iota_types::crypto::AuthorityQuorumSignInfo { + epoch: 0, + signature: iota_types::crypto::AggregateAuthoritySignature::aggregate(&sigs) + .map_err(|e| IotaError::InvalidSignature { + error: e.to_string(), + }) + .expect("Validator returned invalid signature"), + signers_map, + }; + let cert = iota_types::message_envelope::Envelope::new_from_data_and_sig( + transfer_transaction.into_data(), + quorum_signature, + ); + + let res = client.handle_certificate_v2(cert).await; + assert!(res.is_err()); + let err = res.err().unwrap(); + // The resulting error should be a RpcError with a message length too large. + assert!( + matches!(err, IotaError::RpcError(..)) + && err.to_string().contains("message length too large") + ); +} + +#[tokio::test] +async fn test_handle_certificate_errors() { + telemetry_subscribers::init_for_testing(); + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let recipient = dbg_addr(2); + let object_id = ObjectID::random(); + let gas_object_id = ObjectID::random(); + let authority_state = + init_state_with_ids(vec![(sender, object_id), (sender, gas_object_id)]).await; + let rgp = authority_state.reference_gas_price_for_testing().unwrap(); + let object = authority_state + .get_object(&object_id) + .await + .unwrap() + .unwrap(); + let gas_object = authority_state + .get_object(&gas_object_id) + .await + .unwrap() + .unwrap(); + + let transfer_transaction = init_transfer_transaction( + |_| {}, + sender, + &sender_key, + recipient, + object.compute_object_reference(), + gas_object.compute_object_reference(), + rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, + rgp, + ); + + let consensus_address: Multiaddr = "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(); + + let server = AuthorityServer::new_for_test( + "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(), + authority_state.clone(), + consensus_address.clone(), + ); + + let server_handle = server.spawn_for_test().await.unwrap(); + + let client = NetworkAuthorityClient::connect(server_handle.address()) + .await + .unwrap(); + + // Test handle certificate from the wrong epoch + let epoch_store = authority_state.epoch_store_for_testing(); + let next_epoch = epoch_store.epoch() + 1; + let signed_transaction = VerifiedSignedTransaction::new( + next_epoch, + VerifiedTransaction::new_unchecked(transfer_transaction.clone()), + authority_state.name, + &*authority_state.secret, + ); + + let mut committee_1 = epoch_store.committee().deref().clone(); + committee_1.epoch = next_epoch; + let ct = CertifiedTransaction::new( + transfer_transaction.data().clone(), + vec![signed_transaction.auth_sig().clone()], + &committee_1, + ) + .unwrap(); + + let err = client.handle_certificate_v2(ct.clone()).await.unwrap_err(); + assert_matches!( + err, + IotaError::WrongEpoch { + expected_epoch: 0, + actual_epoch: 1 + } + ); + + // Test handle certificate with invalid user input + let signed_transaction = VerifiedSignedTransaction::new( + epoch_store.epoch(), + VerifiedTransaction::new_unchecked(transfer_transaction.clone()), + authority_state.name, + &*authority_state.secret, + ); + + let mut empty_tx = transfer_transaction.clone(); + let data = empty_tx.data_mut_for_testing(); + data.inner_vec_mut_for_testing().clear(); + + let committee = epoch_store.committee().deref().clone(); + let ct = CertifiedTransaction::new( + data.clone(), + vec![signed_transaction.auth_sig().clone()], + &committee, + ) + .unwrap(); + + let err = client.handle_certificate_v2(ct.clone()).await.unwrap_err(); + + assert_matches!( + err, + IotaError::UserInputError { + error: UserInputError::Unsupported(message) + } if message == "SenderSignedData must contain exactly one transaction" + ); + + let tx = VerifiedTransaction::new_consensus_commit_prologue(0, 0, 42); + let ct = CertifiedTransaction::new( + tx.data().clone(), + vec![signed_transaction.auth_sig().clone()], + &committee, + ) + .unwrap(); + + let err = client.handle_certificate_v2(ct.clone()).await.unwrap_err(); + + assert_matches!( + err, + IotaError::UserInputError { + error: UserInputError::Unsupported(message) + } if message == "SenderSignedData must not contain system transaction" + ); + + let mut invalid_sig_count_tx = transfer_transaction.clone(); + let data = invalid_sig_count_tx.data_mut_for_testing(); + data.tx_signatures_mut_for_testing().clear(); + let ct = CertifiedTransaction::new( + data.clone(), + vec![signed_transaction.auth_sig().clone()], + &committee, + ) + .unwrap(); + let err = client.handle_certificate_v2(ct.clone()).await.unwrap_err(); + + assert_matches!( + err, + IotaError::SignerSignatureNumberMismatch { + expected: 1, + actual: 0 + } + ); + + let mut absent_sig_tx = transfer_transaction.clone(); + let (_unknown_address, unknown_key): (_, AccountKeyPair) = get_key_pair(); + let data = absent_sig_tx.data_mut_for_testing(); + *data.tx_signatures_mut_for_testing() = + vec![Signature::new_secure(data.intent_message(), &unknown_key).into()]; + let ct = CertifiedTransaction::new( + data.clone(), + vec![signed_transaction.auth_sig().clone()], + &committee, + ) + .unwrap(); + + let err = client.handle_certificate_v2(ct.clone()).await.unwrap_err(); + + assert_matches!(err, IotaError::SignerSignatureAbsent { .. }); +} diff --git a/crates/iota-core/src/unit_tests/transfer_to_object_tests.rs b/crates/iota-core/src/unit_tests/transfer_to_object_tests.rs new file mode 100644 index 00000000000..886ccc6aaf9 --- /dev/null +++ b/crates/iota-core/src/unit_tests/transfer_to_object_tests.rs @@ -0,0 +1,1785 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::HashSet, sync::Arc}; + +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber}, + crypto::{get_key_pair, AccountKeyPair}, + digests::ObjectDigest, + effects::{TransactionEffects, TransactionEffectsAPI}, + error::{IotaError, UserInputError}, + execution_status::{ExecutionFailureStatus, ExecutionStatus}, + object::{Object, Owner}, + programmable_transaction_builder::ProgrammableTransactionBuilder, + transaction::{ + CallArg, ObjectArg, ProgrammableTransaction, VerifiedCertificate, + TEST_ONLY_GAS_UNIT_FOR_PUBLISH, + }, +}; +use move_core_types::ident_str; + +use crate::{ + authority::{ + authority_test_utils::{certify_transaction, send_consensus}, + authority_tests::{ + build_programmable_transaction, execute_programmable_transaction, + execute_programmable_transaction_with_shared, + }, + move_integration_tests::build_and_publish_test_package_with_upgrade_cap, + test_authority_builder::TestAuthorityBuilder, + AuthorityState, + }, + move_call, +}; + +// The primary use for these tests is to make sure the generated effect sets +// match what we expect when receiving an object, and if we then perform +// different types of operations on the received object (e.g., deleting, +// wrapping, unwrapping, adding as a dynamic field, etc.) and various +// combinations of that. Some of these tests also check and validate locking +// behavior around receiving object arguments as well. + +// Run the test twice -- once with aggressive pruning enabled, and the other +// with it not enabled. +macro_rules! transfer_test_runner { + (gas_objects: $num:expr, $expr:expr) => { + let runner = TestRunner::new_with_objects("tto", $num, false).await; + #[allow(clippy::redundant_closure_call)] + $expr(runner).await; + let runner = TestRunner::new_with_objects("tto", $num, true).await; + #[allow(clippy::redundant_closure_call)] + $expr(runner).await; + }; + ($expr:expr) => { + let runner = TestRunner::new("tto", false).await; + #[allow(clippy::redundant_closure_call)] + $expr(runner).await; + let runner = TestRunner::new("tto", true).await; + #[allow(clippy::redundant_closure_call)] + $expr(runner).await; + }; +} + +struct TestRunner { + pub sender: IotaAddress, + pub sender_key: AccountKeyPair, + pub gas_object_ids: Vec, + pub authority_state: Arc, + pub package: ObjectRef, + pub upgrade_cap: ObjectRef, + pub rgp: u64, + pub aggressive_pruning_enabled: bool, +} + +impl TestRunner { + pub async fn new_with_objects( + base_package_name: &str, + num: usize, + aggressive_pruning_enabled: bool, + ) -> Self { + telemetry_subscribers::init_for_testing(); + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + + let authority_state = TestAuthorityBuilder::new().build().await; + let rgp = authority_state.reference_gas_price_for_testing().unwrap(); + let mut gas_object_ids = vec![]; + for _ in 0..num { + let gas_object_id = ObjectID::random(); + let gas_object = Object::with_id_owner_for_testing(gas_object_id, sender); + authority_state.insert_genesis_object(gas_object).await; + gas_object_ids.push(gas_object_id); + } + + let (package, upgrade_cap) = build_and_publish_test_package_with_upgrade_cap( + &authority_state, + &sender, + &sender_key, + &gas_object_ids[0], + base_package_name, + // with_unpublished_deps + false, + ) + .await; + + Self { + sender, + sender_key, + gas_object_ids, + authority_state, + package, + upgrade_cap, + rgp, + aggressive_pruning_enabled, + } + } + + pub async fn new(base_package_name: &str, aggressive_pruning_enabled: bool) -> Self { + Self::new_with_objects(base_package_name, 1, aggressive_pruning_enabled).await + } + + pub async fn signing_error(&mut self, pt: ProgrammableTransaction) -> IotaError { + execute_programmable_transaction( + &self.authority_state, + &self.gas_object_ids[0], + &self.sender, + &self.sender_key, + pt, + self.rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, + ) + .await + .map(|_| ()) + .unwrap_err() + } + + pub async fn run_with_gas_object( + &mut self, + pt: ProgrammableTransaction, + idx: usize, + ) -> TransactionEffects { + let effects = execute_programmable_transaction( + &self.authority_state, + &self.gas_object_ids[idx], + &self.sender, + &self.sender_key, + pt, + self.rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, + ) + .await + .unwrap(); + + if self.aggressive_pruning_enabled { + self.authority_state + .database_for_testing() + .prune_objects_immediately_for_testing(vec![effects.clone()]) + .await + .unwrap(); + } + + if let Some(updated_cap) = effects + .mutated() + .into_iter() + .find_map(|(cap, _)| (cap.0 == self.upgrade_cap.0).then_some(cap)) + { + self.upgrade_cap = updated_cap; + } + + effects + } + + pub async fn run_with_gas_object_shared( + &mut self, + pt: ProgrammableTransaction, + idx: usize, + ) -> TransactionEffects { + let effects = execute_programmable_transaction_with_shared( + &self.authority_state, + &self.gas_object_ids[idx], + &self.sender, + &self.sender_key, + pt, + self.rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, + ) + .await + .unwrap(); + + if self.aggressive_pruning_enabled { + self.authority_state + .database_for_testing() + .prune_objects_immediately_for_testing(vec![effects.clone()]) + .await + .unwrap(); + } + + if let Some(updated_cap) = effects + .mutated() + .into_iter() + .find_map(|(cap, _)| (cap.0 == self.upgrade_cap.0).then_some(cap)) + { + self.upgrade_cap = updated_cap; + } + + effects + } + + pub async fn run(&mut self, pt: ProgrammableTransaction) -> TransactionEffects { + self.run_with_gas_object(pt, 0).await + } + + pub async fn lock_and_verify_transaction( + &mut self, + pt: ProgrammableTransaction, + account_id: usize, + ) -> VerifiedCertificate { + let transaction = build_programmable_transaction( + &self.authority_state, + &self.gas_object_ids[account_id], + &self.sender, + &self.sender_key, + pt, + TEST_ONLY_GAS_UNIT_FOR_PUBLISH, + ) + .await + .unwrap(); + certify_transaction(&self.authority_state, transaction) + .await + .unwrap() + } + + pub async fn execute_certificate( + &mut self, + ct: VerifiedCertificate, + shared: bool, + ) -> TransactionEffects { + let epoch_store = self.authority_state.load_epoch_store_one_call_per_task(); + if shared { + send_consensus(&self.authority_state, &ct).await; + } + // Call `execute_certificate` instead of + // `execute_certificate_with_execution_error` to make sure we go through TM + let effects = self + .authority_state + .execute_certificate(&ct, &epoch_store) + .await + .unwrap() + .inner() + .clone() + .into_data(); + + if self.aggressive_pruning_enabled { + self.authority_state + .database_for_testing() + .prune_objects_immediately_for_testing(vec![effects.clone()]) + .await + .unwrap(); + } + effects + } +} + +fn get_parent_and_child( + created: Vec<(ObjectRef, Owner)>, +) -> ((ObjectRef, Owner), (ObjectRef, Owner)) { + // make sure there is an object with an `AddressOwner` who matches the object ID + // of another object. + let created_addrs: HashSet<_> = created.iter().map(|((i, _, _), _)| i).collect(); + let (child, parent_id) = created + .iter() + .find_map(|child @ (_, owner)| match owner { + Owner::AddressOwner(j) if created_addrs.contains(&ObjectID::from(*j)) => { + Some((child, (*j).into())) + } + _ => None, + }) + .unwrap(); + let parent = *created + .iter() + .find(|((id, _, _), _)| *id == parent_id) + .unwrap(); + (parent, *child) +} + +#[tokio::test] +async fn test_tto_transfer() { + transfer_test_runner! { |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M1::start() + }; + builder.finish() + }) + .await; + + let (parent, child) = get_parent_and_child(effects.created()); + let transfer_digest = effects.transaction_digest(); + + // No receive the sent object + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M1::receiver(parent, child) + }; + builder.finish() + }) + .await; + + assert!(effects.status().is_ok()); + assert!(effects.created().is_empty()); + assert!(effects.unwrapped().is_empty()); + assert!(effects.deleted().is_empty()); + assert!(effects.unwrapped_then_deleted().is_empty()); + assert!(effects.wrapped().is_empty()); + assert!(effects.dependencies().contains(transfer_digest)); + + for (obj_ref, owner) in effects.mutated().iter() { + if obj_ref.0 == child.0 .0 { + // Child should be sent to 0x0 + assert_eq!(owner, &Owner::AddressOwner(IotaAddress::ZERO)); + // It's version should be bumped as well + assert!(obj_ref.1 > child.0 .1); + } + if obj_ref.0 == parent.0 .0 { + // owner of the parent stays the same + assert_eq!(owner, &parent.1); + // parent version is also bumped + assert!(obj_ref.1 > parent.0 .1); + } + } + } + } +} + +#[tokio::test] +async fn test_tto_intersection_input_and_receiving_objects() { + transfer_test_runner! { |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M1::start() + }; + builder.finish() + }) + .await; + + let (parent, child) = get_parent_and_child(effects.created()); + let parent_receiving_arg = CallArg::Object(ObjectArg::Receiving(parent.0)); + let child_receiving_arg = CallArg::Object(ObjectArg::Receiving(child.0)); + + // Duplicate object reference between receiving and input object arguments. + let IotaError::UserInputError { error } = runner + .signing_error({ + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M1::receiver(parent, child) + }; + let mut built = builder.finish(); + built.inputs.push(parent_receiving_arg); + built + }) + .await else { + panic!("expected signing error"); + }; + assert!(matches!(error, UserInputError::DuplicateObjectRefInput)); + + // Duplicate object reference in receiving object arguments. + let IotaError::UserInputError { error } = runner + .signing_error({ + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M1::receiver(parent, child) + }; + let mut built = builder.finish(); + built.inputs.push(child_receiving_arg); + built + }) + .await else { + panic!("expected signing error"); + }; + assert!(matches!(error, UserInputError::DuplicateObjectRefInput)); + } + } +} + +#[tokio::test] +async fn test_tto_invalid_receiving_arguments() { + transfer_test_runner! { |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M1::start() + }; + builder.finish() + }) + .await; + + let (parent, child) = get_parent_and_child(effects.created()); + let package_object_ref = runner.package; + let shared = *effects + .created() + .iter() + .find(|(_, owner)| matches!(owner, Owner::Shared { .. })) + .unwrap(); + let immutable = *effects + .created() + .iter() + .find(|(_, owner)| matches!(owner, Owner::Immutable)) + .unwrap(); + let object_owned = *effects + .created() + .iter() + .find(|(_, owner)| matches!(owner, Owner::ObjectOwner(_))) + .unwrap(); + + #[allow(clippy::type_complexity)] + let mutations: Vec<( + Box ObjectRef>, + Box bool>, + )> = vec![ + ( + Box::new(|x: ObjectRef| (x.0, SequenceNumber::MAX, x.2)), + Box::new(|err| matches!(err, UserInputError::InvalidSequenceNumber)), + ), + ( + Box::new(|x: ObjectRef| (ObjectID::ZERO, x.1, x.2)), + Box::new(|err| matches!(err, UserInputError::ObjectNotFound { .. })), + ), + ( + Box::new(|x: ObjectRef| (x.0, x.1.next(), x.2)), + Box::new(|err| { + matches!( + err, + UserInputError::ObjectVersionUnavailableForConsumption { .. } + ) + }), + ), + ( + Box::new(|x: ObjectRef| (x.0, x.1.one_before().unwrap(), x.2)), + Box::new(|err| { + matches!( + err, + UserInputError::ObjectVersionUnavailableForConsumption { .. } + ) + }), + ), + ( + Box::new(|_: ObjectRef| package_object_ref), + Box::new(|err| matches!(err, UserInputError::MovePackageAsObject { .. })), + ), + ( + Box::new(|x: ObjectRef| (x.0, x.1, ObjectDigest::random())), + Box::new(|err| matches!(err, UserInputError::InvalidObjectDigest { .. })), + ), + ( + Box::new(|_: ObjectRef| shared.0), + Box::new(|err| matches!(err, UserInputError::NotSharedObjectError)), + ), + ( + Box::new(|_: ObjectRef| object_owned.0), + Box::new(|err| matches!(err, UserInputError::InvalidChildObjectArgument { .. })), + ), + ( + Box::new(|_: ObjectRef| immutable.0), + Box::new(|err| matches!(err, UserInputError::MutableParameterExpected { .. })), + ), + ]; + + for (i, (mutate, expect)) in mutations.into_iter().enumerate() { + let IotaError::UserInputError { error } = runner.signing_error({ + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(mutate(child.0))).unwrap(); + move_call! { + builder, + (runner.package.0)::M1::receiver(parent, child) + }; + builder.finish() + }) + .await else { + panic!("failed on iteration {}", i); + }; + assert!( + expect(error), + "failed to match expected error on iteration {}", + i + ); + } + } + } +} + +#[tokio::test] +async fn test_tto_unused_receiver() { + transfer_test_runner! { |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M1::start() + }; + builder.finish() + }) + .await; + + let (parent, child) = get_parent_and_child(effects.created()); + + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + builder.finish() + }) + .await; + + assert!(effects.status().is_ok()); + assert!(effects.created().is_empty()); + assert!(effects.unwrapped().is_empty()); + assert!(effects.deleted().is_empty()); + assert!(effects.unwrapped_then_deleted().is_empty()); + assert!(effects.wrapped().is_empty()); + + // If the receiving argument is not used it should not be modified! + assert!(!effects + .modified_at_versions() + .iter() + .any(|(i, _)| i == &child.0 .0)); + // Since the parent was not used but it was an input object, it should be modified + assert!(effects + .modified_at_versions() + .iter() + .any(|(i, _)| i == &parent.0 .0)); + + // Make sure parent exists in mutated, and the version is bumped. + for (obj_ref, owner) in effects.mutated().iter() { + if obj_ref.0 == parent.0 .0 { + // owner of the parent stays the same + assert_eq!(owner, &parent.1); + // parent version is also bumped + assert!(obj_ref.1 > parent.0 .1); + } + } + } + } +} + +#[tokio::test] +async fn test_tto_pass_receiving_by_refs() { + transfer_test_runner! { |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M1::start() + }; + builder.finish() + }) + .await; + + let (parent, child) = get_parent_and_child(effects.created()); + + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M1::call_immut_ref(parent, child) + }; + move_call! { + builder, + (runner.package.0)::M1::call_mut_ref(parent, child) + }; + builder.finish() + }) + .await; + + assert!(effects.status().is_ok()); + assert!(effects.created().is_empty()); + assert!(effects.unwrapped().is_empty()); + assert!(effects.deleted().is_empty()); + assert!(effects.unwrapped_then_deleted().is_empty()); + assert!(effects.wrapped().is_empty()); + + // If the receiving argument is not used it should not be modified! + assert!(!effects + .modified_at_versions() + .iter() + .any(|(i, _)| i == &child.0 .0)); + // Since the parent was not used but it was an input object, it should be modified + assert!(effects + .modified_at_versions() + .iter() + .any(|(i, _)| i == &parent.0 .0)); + + // Make sure parent exists in mutated, and the version is bumped. + for (obj_ref, owner) in effects.mutated().iter() { + if obj_ref.0 == parent.0 .0 { + // owner of the parent stays the same + assert_eq!(owner, &parent.1); + // parent version is also bumped + assert!(obj_ref.1 > parent.0 .1); + } + } + } + } +} + +#[tokio::test] +async fn test_tto_delete() { + transfer_test_runner! { |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M1::start() + }; + builder.finish() + }) + .await; + + let (parent, child) = get_parent_and_child(effects.created()); + + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M1::deleter(parent, child) + }; + builder.finish() + }) + .await; + + assert!(effects.status().is_ok()); + assert!(effects.created().is_empty()); + assert!(effects.unwrapped().is_empty()); + assert!(effects.unwrapped_then_deleted().is_empty()); + assert!(effects.wrapped().is_empty()); + // Deleted should be non-empty + assert_eq!(effects.deleted().len(), 1); + // Deleted should contain the child object + assert_eq!(effects.deleted()[0].0, child.0 .0); + + // Make sure parent exists in mutated, and the version is bumped. + for (obj_ref, owner) in effects.mutated().iter() { + if obj_ref.0 == parent.0 .0 { + // owner of the parent stays the same + assert_eq!(owner, &parent.1); + // parent version is also bumped + assert!(obj_ref.1 > parent.0 .1); + } + } + } + } +} + +#[tokio::test] +async fn test_tto_wrap() { + transfer_test_runner! { |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M1::start() + }; + builder.finish() + }) + .await; + + let (parent, child) = get_parent_and_child(effects.created()); + + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M1::wrapper(parent, child) + }; + builder.finish() + }) + .await; + + assert!(effects.status().is_ok()); + assert!(effects.unwrapped().is_empty()); + assert!(effects.unwrapped_then_deleted().is_empty()); + assert!(effects.deleted().is_empty()); + // We created an object since we wrapped this when we received the transaction + assert_eq!(effects.created().len(), 1); + // Wrapped should be non-empty + assert_eq!(effects.wrapped().len(), 1); + // Wrapped should contain the child object + assert_eq!(effects.wrapped()[0].0, child.0 .0); + + // Make sure parent exists in mutated, and the version is bumped. + for (obj_ref, owner) in effects.mutated().iter() { + if obj_ref.0 == parent.0 .0 { + // owner of the parent stays the same + assert_eq!(owner, &parent.1); + // parent version is also bumped + assert!(obj_ref.1 > parent.0 .1); + } + } + } + } +} + +#[tokio::test] +async fn test_tto_unwrap_transfer() { + transfer_test_runner! { |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M2::start() + }; + builder.finish() + }) + .await; + + let (parent, child) = get_parent_and_child(effects.created()); + + // No receive the sent object + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M2::unwrap_receiver(parent, child) + }; + builder.finish() + }) + .await; + + assert!(effects.status().is_ok()); + assert!(effects.created().is_empty()); + assert!(effects.unwrapped_then_deleted().is_empty()); + assert!(effects.wrapped().is_empty()); + + // Unwrapped should be size 1 + assert_eq!(effects.unwrapped().len(), 1); + // The now-unwrapped object should be sent to 0x0 + assert_eq!( + effects.unwrapped()[0].1, + Owner::AddressOwner(IotaAddress::ZERO) + ); + + // Receiving object ID is deleted + assert_eq!(effects.deleted().len(), 1); + // Deleted should contain the child object id + assert_eq!(effects.deleted()[0].0, child.0 .0); + + for (obj_ref, owner) in effects.mutated().iter() { + // child ref should not be mutated since it was deleted + assert_ne!(obj_ref.0, child.0 .0); + if obj_ref.0 == parent.0 .0 { + // owner of the parent stays the same + assert_eq!(owner, &parent.1); + // parent version is also bumped + assert!(obj_ref.1 > parent.0 .1); + } + } + } + } +} + +#[tokio::test] +async fn test_tto_unwrap_delete() { + transfer_test_runner! { |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M2::start() + }; + builder.finish() + }) + .await; + + let (parent, child) = get_parent_and_child(effects.created()); + + // No receive the sent object + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M2::unwrap_deleter(parent, child) + }; + builder.finish() + }) + .await; + + assert!(effects.status().is_ok()); + assert!(effects.created().is_empty()); + assert!(effects.unwrapped().is_empty()); + assert!(effects.wrapped().is_empty()); + + // The deleted should be of size 1, and should contain the child address + assert_eq!(effects.deleted().len(), 1); + assert_eq!(effects.deleted()[0].0, child.0 .0); + + // Unwrapped then deleted should be of size 1 since we deleted the inner object as well. + assert_eq!(effects.unwrapped_then_deleted().len(), 1); + + for (obj_ref, owner) in effects.mutated().iter() { + // child ref should not be mutated since it was deleted + assert_ne!(obj_ref.0, child.0 .0); + if obj_ref.0 == parent.0 .0 { + // owner of the parent stays the same + assert_eq!(owner, &parent.1); + // parent version is also bumped + assert!(obj_ref.1 > parent.0 .1); + } + } + } + } +} + +#[tokio::test] +async fn test_tto_unwrap_add_as_dynamic_field() { + transfer_test_runner! { |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M2::start() + }; + builder.finish() + }) + .await; + + let (parent, child) = get_parent_and_child(effects.created()); + + // No receive the sent object + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M2::unwrap_add_dyn(parent, child) + }; + builder.finish() + }) + .await; + + assert!(effects.status().is_ok()); + // Since it's placed as a dynamic field it will be rewrapped(). So `unwrapped` should be empty + assert!(effects.unwrapped().is_empty()); + // Similarly it was already wrapped, so even though we're wrapping with the dynamic field `wrapped` should be empty + assert!(effects.wrapped().is_empty()); + assert!(effects.unwrapped_then_deleted().is_empty()); + + assert_eq!(effects.created().len(), 1); + + // The deleted should be of size 1, and should contain the child address + assert_eq!(effects.deleted().len(), 1); + assert_eq!(effects.deleted()[0].0, child.0 .0); + + for (obj_ref, owner) in effects.mutated().iter() { + assert_ne!(obj_ref.0, child.0 .0); + if obj_ref.0 == parent.0 .0 { + // owner of the parent stays the same + assert_eq!(owner, &parent.1); + // parent version is also bumped + assert!(obj_ref.1 > parent.0 .1); + } + } + } + } +} + +// This tests that locks are not grabbed for receiving objects. +// This test does this by +// 1. Creating a parent object and child object +// 2. Creating a fake parent object +// 3. Create and sign a transaction `tx1` that tries to receive the child object +// using the fake parent. +// 4. Create and sign a transaction `tx2` that receives the child object using +// the valid parent object. +// 5. Execute `tx2` and verify that it can be executed successfully. +// 6. Execute `tx1` and verify that it can be executed, but will result in a +// Move abort. +// The order of steps 5 and 6 are swapped if `flipper` is `true`. +// The object is deleted instead of received if `should_delete` is `true`. +async fn verify_tto_not_locked( + flipper: bool, + should_delete: bool, + aggressive_pruning: bool, +) -> (TransactionEffects, TransactionEffects) { + let mut runner = TestRunner::new_with_objects("tto", 2, aggressive_pruning).await; + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M3::start() + }; + builder.finish() + }) + .await; + + let (parent, child) = get_parent_and_child(effects.created()); + let fake_parent = *effects + .created() + .iter() + .find(|(obj_ref, _)| obj_ref.0 != parent.0.0 && obj_ref.0 != child.0.0) + .unwrap(); + + // Now get a certificate for fake_parent/child1. This will lock input objects. + // NB: the receiving object is _not_ locked. + let cert_for_fake_parent = runner + .lock_and_verify_transaction( + { + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder + .obj(ObjectArg::ImmOrOwnedObject(fake_parent.0)) + .unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + if should_delete { + move_call!(builder, (runner.package.0)::M3::deleter(parent, child)); + } else { + move_call!(builder, (runner.package.0)::M3::receiver(parent, child)); + }; + builder.finish() + }, + 0, + ) + .await; + + // After the other (fake) transaction has been created and signed, sign and + // execute this transaction. This should have no issues because the + // receiving object is not locked by the signing of the transaction above. + let valid_cert = runner + .lock_and_verify_transaction( + { + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + if should_delete { + move_call!(builder, (runner.package.0)::M3::deleter(parent, child)); + } else { + move_call!(builder, (runner.package.0)::M3::receiver(parent, child)); + }; + builder.finish() + }, + 1, + ) + .await; + + // The order of the execution of these transactions is flipped depending on the + // value of flipper. However, the result should be the same in either case. + let (valid_effects, invalid_effects) = if flipper { + let invalid_effects = runner + .execute_certificate(cert_for_fake_parent, false) + .await; + let valid_effects = runner.execute_certificate(valid_cert, false).await; + (valid_effects, invalid_effects) + } else { + let valid_effects = runner.execute_certificate(valid_cert, false).await; + let invalid_effects = runner + .execute_certificate(cert_for_fake_parent, false) + .await; + (valid_effects, invalid_effects) + }; + + assert!(valid_effects.status().is_ok()); + assert!(invalid_effects.status().is_err()); + assert!(matches!( + invalid_effects.status(), + ExecutionStatus::Failure { + error: ExecutionFailureStatus::MoveAbort(_, _), + .. + } + )); + (valid_effects, invalid_effects) +} + +fn assert_effects_equivalent(ef1: &TransactionEffects, ef2: &TransactionEffects) { + assert_eq!(ef1.status(), ef2.status()); + assert_eq!(ef1.executed_epoch(), ef2.executed_epoch()); + assert_eq!(ef1.gas_cost_summary(), ef2.gas_cost_summary()); + assert_eq!( + ef1.modified_at_versions().len(), + ef2.modified_at_versions().len() + ); + assert_eq!(ef1.created().len(), ef2.created().len()); + assert_eq!(ef1.mutated().len(), ef2.mutated().len()); + assert_eq!(ef1.unwrapped().len(), ef2.unwrapped().len()); + assert_eq!(ef1.deleted().len(), ef2.deleted().len()); + assert_eq!( + ef1.unwrapped_then_deleted().len(), + ef2.unwrapped_then_deleted().len() + ); + assert_eq!(ef1.wrapped().len(), ef2.wrapped().len()); + assert_eq!(ef1.dependencies().len(), ef2.dependencies().len()); +} + +#[tokio::test] +async fn test_tto_not_locked() { + for aggressive_pruning_enabled in [true, false] { + // The transaction effects for the valid and invalid transactions should be the + // same regardless of the order in which they are run. + let (valid1, invalid1) = + verify_tto_not_locked(false, false, aggressive_pruning_enabled).await; + let (valid2, invalid2) = + verify_tto_not_locked(true, false, aggressive_pruning_enabled).await; + assert_effects_equivalent(&valid1, &valid2); + assert_effects_equivalent(&invalid1, &invalid2); + + // The same should hold if the object is deleted by an intervening transaction. + let (valid1, invalid1) = + verify_tto_not_locked(false, true, aggressive_pruning_enabled).await; + let (valid2, invalid2) = + verify_tto_not_locked(true, true, aggressive_pruning_enabled).await; + assert_effects_equivalent(&valid1, &valid2); + assert_effects_equivalent(&invalid1, &invalid2); + } +} + +#[tokio::test] +async fn test_tto_valid_dependencies() { + transfer_test_runner! {gas_objects: 3, |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M4::start1() + }; + builder.finish() + }) + .await; + let parent = effects.created()[0]; + + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M4::start2() + }; + builder.finish() + }) + .await; + let child = effects.created()[0]; + + // Use a different gas coin than for all the other transactions. This serves two purposes: + // 1. Makes sure that we are registering the dependency on the transaction that transferred the + // object solely because of the fact that we received it in this transaction. + // 2. Since the gas coin is fresh it will have a smaller version, so this will test that we + // properly compute and update the lamport version that we should use for the transaction. + let effects = runner + .run_with_gas_object( + { + let mut builder = ProgrammableTransactionBuilder::new(); + builder + .transfer_object(IotaAddress::from(parent.0 .0), child.0) + .unwrap(); + builder.finish() + }, + 1, + ) + .await; + + let child = *effects + .mutated() + .iter() + .find(|(o, _)| o.0 == child.0 .0) + .unwrap(); + let transfer_digest = effects.transaction_digest(); + + // No receive the sent object + let effects = runner + .run_with_gas_object( + { + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M4::receiver(parent, child) + }; + builder.finish() + }, + 2, + ) + .await; + + assert!(effects.status().is_ok()); + assert!(effects.created().is_empty()); + assert!(effects.unwrapped().is_empty()); + assert!(effects.deleted().is_empty()); + assert!(effects.unwrapped_then_deleted().is_empty()); + assert!(effects.wrapped().is_empty()); + assert!(effects.dependencies().contains(transfer_digest)); + + for (obj_ref, owner) in effects.mutated().iter() { + if obj_ref.0 == child.0 .0 { + // Child should be sent to 0x0 + assert_eq!(owner, &Owner::AddressOwner(IotaAddress::ZERO)); + // It's version should be bumped as well + assert!(obj_ref.1 > child.0 .1); + // The child should be the max version + assert_eq!(obj_ref.1.value(), child.0 .1.value() + 1); + } + if obj_ref.0 == parent.0 .0 { + // owner of the parent stays the same + assert_eq!(owner, &parent.1); + // parent version is also bumped + assert!(obj_ref.1 > parent.0 .1); + // The child should be the max version + assert_eq!(obj_ref.1.value(), child.0 .1.value() + 1); + } + } + } + } +} + +#[tokio::test] +async fn test_tto_valid_dependencies_delete_on_receive() { + transfer_test_runner! {gas_objects: 3, |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M4::start1() + }; + builder.finish() + }) + .await; + let parent = effects.created()[0]; + + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M4::start2() + }; + builder.finish() + }) + .await; + let child = effects.created()[0]; + + // Use a different gas coin than for all the other transactions. This serves two purposes: + // 1. Makes sure that we are registering the dependency on the transaction that transferred the + // object solely because of the fact that we received it in this transaction. + // 2. Since the gas coin is fresh it will have a smaller version, so this will test that we + // properly compute and update the lamport version that we should use for the transaction. + let effects = runner + .run_with_gas_object( + { + let mut builder = ProgrammableTransactionBuilder::new(); + builder + .transfer_object(IotaAddress::from(parent.0 .0), child.0) + .unwrap(); + builder.finish() + }, + 1, + ) + .await; + + let child = *effects + .mutated() + .iter() + .find(|(o, _)| o.0 == child.0 .0) + .unwrap(); + let transfer_digest = effects.transaction_digest(); + + // No receive and delete the sent object + let effects = runner + .run_with_gas_object( + { + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M4::deleter(parent, child) + }; + builder.finish() + }, + 2, + ) + .await; + + assert!(effects.status().is_ok()); + assert!(effects.created().is_empty()); + assert!(effects.unwrapped().is_empty()); + assert!(effects.unwrapped_then_deleted().is_empty()); + assert!(effects.wrapped().is_empty()); + // Deleted should be non-empty + assert_eq!(effects.deleted().len(), 1); + // Deleted should contain the child object + assert_eq!(effects.deleted()[0].0, child.0 .0); + assert!(effects.dependencies().contains(transfer_digest)); + + // Make sure parent exists in mutated, and the version is bumped and is equal to the child's + // version + 1 since the child has the highest version number in the transaction. + for (obj_ref, owner) in effects.mutated().iter() { + if obj_ref.0 == parent.0 .0 { + // owner of the parent stays the same + assert_eq!(owner, &parent.1); + // parent version is also bumped + assert!(obj_ref.1 > parent.0 .1); + assert_eq!(obj_ref.1.value(), child.0 .1.value() + 1); + } + } + } + } +} + +#[tokio::test] +async fn test_tto_dependencies_dont_receive() { + transfer_test_runner! {gas_objects: 3, |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M4::start1() + }; + builder.finish() + }) + .await; + let parent = effects.created()[0]; + + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M4::start2() + }; + builder.finish() + }) + .await; + let old_child = effects.created()[0]; + + // Use a different gas coin than for all the other transactions. This: + // 1. Makes sure that we are registering the dependency on the transaction that transferred the + // object solely because of the fact that we received it in this transaction. + // 2. Since the gas coin is fresh it will have a smaller version, so this will test that we + // properly compute and update the lamport version that we should use for the transaction. + let effects = runner + .run_with_gas_object( + { + let mut builder = ProgrammableTransactionBuilder::new(); + builder + .transfer_object(IotaAddress::from(parent.0 .0), old_child.0) + .unwrap(); + builder.finish() + }, + 1, + ) + .await; + + let child = *effects + .mutated() + .iter() + .find(|(o, _)| o.0 == old_child.0 .0) + .unwrap(); + let transfer_digest = effects.transaction_digest(); + + // ensure child version is greater than parent version, otherwise the check afterwards won't be + // checking the correct thing. + assert!(parent.0 .1.value() < child.0 .1.value()); + + // Now dont receive the sent object but include it in the arguments for the PTB. + let effects = runner + .run_with_gas_object( + { + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M4::nop(parent, child) + }; + builder.finish() + }, + 2, + ) + .await; + + assert!(effects.status().is_ok()); + assert!(effects.created().is_empty()); + assert!(effects.unwrapped().is_empty()); + assert!(effects.deleted().is_empty()); + assert!(effects.unwrapped_then_deleted().is_empty()); + assert!(effects.wrapped().is_empty()); + // Not received so dependency is not added. + assert!(!effects.dependencies().contains(transfer_digest)); + + for (obj_ref, owner) in effects.mutated().iter() { + assert_ne!(obj_ref.0, child.0 .0); + if obj_ref.0 == parent.0 .0 { + // owner of the parent stays the same + assert_eq!(owner, &parent.1); + // parent version is also bumped + assert!(obj_ref.1 > parent.0 .1); + // Parent version is the largest in this transaction + assert_eq!(obj_ref.1.value(), child.0 .1.value() + 1); + } + } + } + } +} + +#[tokio::test] +async fn test_tto_dependencies_dont_receive_but_abort() { + transfer_test_runner! {gas_objects: 3, |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M4::start1() + }; + builder.finish() + }) + .await; + let parent = effects.created()[0]; + + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M4::start2() + }; + builder.finish() + }) + .await; + let old_child = effects.created()[0]; + + // Use a different gas coin than for all the other transactions. This: + // 1. Makes sure that we are registering the dependency on the transaction that transferred the + // object solely because of the fact that we received it in this transaction. + // 2. Since the gas coin is fresh it will have a smaller version, so this will test that we + // properly compute and update the lamport version that we should use for the transaction. + let effects = runner + .run_with_gas_object( + { + let mut builder = ProgrammableTransactionBuilder::new(); + builder + .transfer_object(IotaAddress::from(parent.0 .0), old_child.0) + .unwrap(); + builder.finish() + }, + 1, + ) + .await; + + let child = *effects + .mutated() + .iter() + .find(|(o, _)| o.0 == old_child.0 .0) + .unwrap(); + let transfer_digest = effects.transaction_digest(); + + assert!(parent.0 .1.value() < child.0 .1.value()); + + let effects = runner + .run_with_gas_object( + { + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M4::aborter(parent, child) + }; + builder.finish() + }, + 2, + ) + .await; + + assert!(effects.status().is_err()); + assert!(effects.created().is_empty()); + assert!(effects.unwrapped().is_empty()); + assert!(effects.deleted().is_empty()); + assert!(effects.unwrapped_then_deleted().is_empty()); + assert!(effects.wrapped().is_empty()); + // Not received so dependency is not added. + assert!(!effects.dependencies().contains(transfer_digest)); + + for (obj_ref, owner) in effects.mutated().iter() { + assert_ne!(obj_ref.0, child.0 .0); + if obj_ref.0 == parent.0 .0 { + // owner of the parent stays the same + assert_eq!(owner, &parent.1); + // parent version is also bumped + assert!(obj_ref.1 > parent.0 .1); + // child version is the largest in this transaction, and even though it's not received + // it still contributes to the lamport version of the transaction. + assert_eq!(obj_ref.1.value(), child.0 .1.value() + 1); + } + } + } + } +} + +#[tokio::test] +async fn test_tto_dependencies_receive_and_abort() { + transfer_test_runner! {gas_objects: 3, |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M4::start1() + }; + builder.finish() + }) + .await; + let parent = effects.created()[0]; + + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M4::start2() + }; + builder.finish() + }) + .await; + let old_child = effects.created()[0]; + + // Use a different gas coin than for all the other transactions. This: + // 1. Makes sure that we are registering the dependency on the transaction that transferred the + // object solely because of the fact that we received it in this transaction. + // 2. Since the gas coin is fresh it will have a smaller version, so this will test that we + // properly compute and update the lamport version that we should use for the transaction. + let effects = runner + .run_with_gas_object( + { + let mut builder = ProgrammableTransactionBuilder::new(); + builder + .transfer_object(IotaAddress::from(parent.0 .0), old_child.0) + .unwrap(); + builder.finish() + }, + 1, + ) + .await; + + let child = *effects + .mutated() + .iter() + .find(|(o, _)| o.0 == old_child.0 .0) + .unwrap(); + let transfer_digest = effects.transaction_digest(); + + assert!(parent.0 .1.value() < child.0 .1.value()); + + let effects = runner + .run_with_gas_object( + { + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M4::receive_abort(parent, child) + }; + builder.finish() + }, + 2, + ) + .await; + + assert!(effects.status().is_err()); + assert!(effects.created().is_empty()); + assert!(effects.unwrapped().is_empty()); + assert!(effects.deleted().is_empty()); + assert!(effects.unwrapped_then_deleted().is_empty()); + assert!(effects.wrapped().is_empty()); + // Received but aborted -- dependency is still added. + assert!(effects.dependencies().contains(transfer_digest)); + + for (obj_ref, owner) in effects.mutated().iter() { + assert_ne!(obj_ref.0, child.0 .0); + if obj_ref.0 == parent.0 .0 { + // owner of the parent stays the same + assert_eq!(owner, &parent.1); + // parent version is also bumped + assert!(obj_ref.1 > parent.0 .1); + // Child version is the largest in this transaction even though it's not received + assert_eq!(obj_ref.1.value(), child.0 .1.value() + 1); + } + } + } + } +} + +#[tokio::test] +async fn test_tto_dependencies_receive_and_type_mismatch() { + transfer_test_runner! {gas_objects: 3, |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M4::start1() + }; + builder.finish() + }) + .await; + let parent = effects.created()[0]; + + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M4::start2() + }; + builder.finish() + }) + .await; + let old_child = effects.created()[0]; + + // Use a different gas coin than for all the other transactions. This: + // 1. Makes sure that we are registering the dependency on the transaction that transferred the + // object solely because of the fact that we received it in this transaction. + // 2. Since the gas coin is fresh it will have a smaller version, so this will test that we + // properly compute and update the lamport version that we should use for the transaction. + let effects = runner + .run_with_gas_object( + { + let mut builder = ProgrammableTransactionBuilder::new(); + builder + .transfer_object(IotaAddress::from(parent.0 .0), old_child.0) + .unwrap(); + builder.finish() + }, + 1, + ) + .await; + + let child = *effects + .mutated() + .iter() + .find(|(o, _)| o.0 == old_child.0 .0) + .unwrap(); + let transfer_digest = effects.transaction_digest(); + + assert!(parent.0 .1.value() < child.0 .1.value()); + + let effects = runner + .run_with_gas_object( + { + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M4::receive_type_mismatch(parent, child) + }; + builder.finish() + }, + 2, + ) + .await; + + assert!(effects.status().is_err()); + + // Type mismatch is an abort code of 2 from `receive_impl` + let is_type_mismatch_error = matches!( + effects.status().clone().unwrap_err().0, + ExecutionFailureStatus::MoveAbort(x, 2) if x.function_name == Some("receive_impl".to_string()) + ); + assert!(is_type_mismatch_error); + assert!(effects.created().is_empty()); + assert!(effects.unwrapped().is_empty()); + assert!(effects.deleted().is_empty()); + assert!(effects.unwrapped_then_deleted().is_empty()); + assert!(effects.wrapped().is_empty()); + // Received but there was a type mismatch -- dependency is still added. + assert!(effects.dependencies().contains(transfer_digest)); + + for (obj_ref, owner) in effects.mutated().iter() { + assert_ne!(obj_ref.0, child.0 .0); + if obj_ref.0 == parent.0 .0 { + // owner of the parent stays the same + assert_eq!(owner, &parent.1); + // parent version is also bumped + assert!(obj_ref.1 > parent.0 .1); + // Child version is the largest in this transaction even though it's not received + assert_eq!(obj_ref.1.value(), child.0 .1.value() + 1); + } + } + } + } +} + +#[tokio::test] +async fn receive_and_dof_interleave() { + transfer_test_runner! {gas_objects: 3, |mut runner: TestRunner| async move { + // step 1 & 2 + let effects = runner + .run_with_gas_object( + { + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M5::start() + }; + builder.finish() + }, + 0, + ) + .await; + + let shared = *effects + .created() + .iter() + .find(|(_, owner)| matches!(owner, Owner::Shared { .. })) + .unwrap(); + let owned = *effects + .created() + .iter() + .find(|(_, owner)| matches!(owner, Owner::AddressOwner(_))) + .unwrap(); + let Owner::Shared { initial_shared_version }= shared.1 else { unreachable!() }; + + let init_digest = effects.transaction_digest(); + + let cert = runner + .lock_and_verify_transaction( + { + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder + .obj(ObjectArg::SharedObject { + id: shared.0 .0, + initial_shared_version, + mutable: true, + }) + .unwrap(); + let child = builder.obj(ObjectArg::Receiving(owned.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M5::deleter(parent, child) + }; + builder.finish() + }, + 1, + ) + .await; + + let dof_effects = runner + .run_with_gas_object_shared( + { + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder + .obj(ObjectArg::SharedObject { + id: shared.0 .0, + initial_shared_version, + mutable: true, + }) + .unwrap(); + let child = builder.obj(ObjectArg::ImmOrOwnedObject(owned.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M5::add_dof(parent, child) + }; + builder.finish() + }, + 2, + ) + .await; + + assert!(dof_effects.status().is_ok()); + + let recv_effects = runner.execute_certificate(cert, true).await; + assert!(recv_effects.status().is_ok()); + // The recv_effects should not contain the dependency on the initial transaction since we + // didn't actually receive the object -- it was loaded via the dynamic field instead. + assert!(!recv_effects.dependencies().contains(init_digest)); + } + } +} + +#[tokio::test] +async fn test_have_deleted_owned_object() { + transfer_test_runner! { |mut runner: TestRunner| async move { + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + move_call! { + builder, + (runner.package.0)::M1::start() + }; + builder.finish() + }) + .await; + + let (parent, child) = get_parent_and_child(effects.created()); + + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M1::send_back(parent, child) + }; + builder.finish() + }) + .await; + + let (new_parent, new_child) = get_parent_and_child(effects.mutated()); + + let cache = runner.authority_state.get_cache_reader().clone(); + + assert!(cache.get_object(&new_child.0.0).unwrap().is_some()); + // Should not show as deleted for either versions + assert!(!cache.have_deleted_owned_object_at_version_or_after(&new_child.0.0, new_child.0.1, 0).unwrap()); + assert!(!cache.have_deleted_owned_object_at_version_or_after(&new_child.0.0, child.0.1, 0).unwrap()); + + let effects = runner + .run({ + let mut builder = ProgrammableTransactionBuilder::new(); + let parent = builder.obj(ObjectArg::ImmOrOwnedObject(new_parent.0)).unwrap(); + let child = builder.obj(ObjectArg::Receiving(new_child.0)).unwrap(); + move_call! { + builder, + (runner.package.0)::M1::deleter(parent, child) + }; + builder.finish() + }) + .await; + + let deleted_child = effects.deleted().into_iter().find(|(id, _, _)| *id == new_child.0 .0).unwrap(); + assert!(cache.get_object(&deleted_child.0).unwrap().is_none()); + assert!(cache.have_deleted_owned_object_at_version_or_after(&deleted_child.0, deleted_child.1, 0).unwrap()); + assert!(cache.have_deleted_owned_object_at_version_or_after(&deleted_child.0, new_child.0.1, 0).unwrap()); + assert!(cache.have_deleted_owned_object_at_version_or_after(&deleted_child.0, child.0.1, 0).unwrap()); + // Should not show as deleted for versions after this though + assert!(!cache.have_deleted_owned_object_at_version_or_after(&deleted_child.0, deleted_child.1.next(), 0).unwrap()); + // Should not show as deleted for other epochs outside of our current epoch too + assert!(!cache.have_deleted_owned_object_at_version_or_after(&deleted_child.0, deleted_child.1, 1).unwrap()); + } + } +} diff --git a/crates/sui-core/src/unit_tests/type_param_tests.rs b/crates/iota-core/src/unit_tests/type_param_tests.rs similarity index 99% rename from crates/sui-core/src/unit_tests/type_param_tests.rs rename to crates/iota-core/src/unit_tests/type_param_tests.rs index 9942c4590e4..2754a290845 100644 --- a/crates/sui-core/src/unit_tests/type_param_tests.rs +++ b/crates/iota-core/src/unit_tests/type_param_tests.rs @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::str::FromStr; -use move_core_types::language_storage::TypeTag; -use sui_types::{ +use iota_types::{ base_types::ObjectID, crypto::{get_key_pair, AccountKeyPair}, effects::TransactionEffectsAPI, }; +use move_core_types::language_storage::TypeTag; use crate::authority::{ authority_tests::{call_move, init_state_with_ids, TestCallArg}, diff --git a/crates/sui-core/src/verify_indexes.rs b/crates/iota-core/src/verify_indexes.rs similarity index 95% rename from crates/sui-core/src/verify_indexes.rs rename to crates/iota-core/src/verify_indexes.rs index 804cc318529..67a0c1fc6ed 100644 --- a/crates/sui-core/src/verify_indexes.rs +++ b/crates/iota-core/src/verify_indexes.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, sync::Arc}; use anyhow::{anyhow, bail, Result}; -use sui_storage::{indexes::CoinInfo, IndexStore}; -use sui_types::{base_types::ObjectInfo, object::Owner}; +use iota_storage::{indexes::CoinInfo, IndexStore}; +use iota_types::{base_types::ObjectInfo, object::Owner}; use tracing::info; use typed_store::traits::Map; diff --git a/crates/iota-core/tests/README.md b/crates/iota-core/tests/README.md new file mode 100644 index 00000000000..bfa6f1696e2 --- /dev/null +++ b/crates/iota-core/tests/README.md @@ -0,0 +1,66 @@ +## What this test is about + +This repository checks the conformance of our code to a BCS-compatible manifest of our serialized data formats. + +It does this by running a manifest generator from the code (using serde-reflection) and checking the output has not changed. + +If it has in a legitimate fashion (e.g. we update one of our main types), all that's left to do is to re-run the generator and check in the change. + +Here are the references to the software above: +https://github.com/diem/bcs +https://github.com/novifinancial/serde-reflection + +## Examples + +In this example, we will update one of our core types (IotaError), and then update the manifest: + +``` +huitseeker@Garillots-MBP.localdomain➜~/tmp/iota(main)» git checkout main [7:40:40] +Already on 'main' +Your branch is up to date with 'origin/main'. +huitseeker@Garillots-MBP.localdomain➜~/tmp/iota(main)» ruplacer --subvert 'CertificateAuthorityReuse' 'CertificateAuthorityDuplicate' --go [8:42:33] +./iota_types/src/error.rs:103 - CertificateAuthorityReuse, +./iota_types/src/error.rs:103 + CertificateAuthorityDuplicate, + +./iota_types/src/messages.rs:610 - IotaError::CertificateAuthorityReuse +./iota_types/src/messages.rs:610 + IotaError::CertificateAuthorityDuplicate +./iota_types/src/messages.rs:638 - IotaError::CertificateAuthorityReuse +./iota_types/src/messages.rs:638 + IotaError::CertificateAuthorityDuplicate + +./iota_core/tests/staged/iota.yaml:390 - CertificateAuthorityReuse: UNIT +./iota_core/tests/staged/iota.yaml:390 + CertificateAuthorityDuplicate: UNIT + +Performed 4 replacements on 196 matching files +``` + +Now our code is modified in a way that will make the format test fail: let's update the manifest. + +``` +huitseeker@Garillots-MBP.localdomain➜~/tmp/iota(main✗)» cd iota_core [8:43:38] +huitseeker@Garillots-MBP.localdomain➜tmp/iota/iota_core(main✗)» cargo -q run --example generate-format -- print > tests/staged/iota.yaml +``` + + +Let's check that we pass the test again: +``` +huitseeker@Garillots-MBP.localdomain➜tmp/iota/iota_core(main✗)» cargo test format 2>&1 |tail -n 40 [8:47:22] + Finished test [unoptimized + debuginfo] target(s) in 0.35s + Running unittests (/Users/huitseeker/tmp/iota/target/debug/deps/iota_core-5796871991341984) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 52 filtered out; finished in 0.00s + + Running tests/format.rs (/Users/huitseeker/tmp/iota/target/debug/deps/format-ecdfa91a67810be3) + +running 1 test + Finished dev [unoptimized + debuginfo] target(s) in 0.20s + Running `target/debug/examples/generate-format test` +test test_format ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.48s +huitseeker@Garillots-MBP.localdomain➜tmp/iota/iota_core(main✗)» git status -s [8:47:38] + M tests/staged/iota.yaml + M ../iota_types/src/error.rs + M ../iota_types/src/messages.rs + ``` \ No newline at end of file diff --git a/crates/sui-core/tests/format.rs b/crates/iota-core/tests/format.rs similarity index 79% rename from crates/sui-core/tests/format.rs rename to crates/iota-core/tests/format.rs index 637ed35b43f..752e4af311f 100644 --- a/crates/sui-core/tests/format.rs +++ b/crates/iota-core/tests/format.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test] @@ -7,7 +8,7 @@ fn test_format() { // If this test breaks and you intended a format change, you need to run to get // the fresh format: # cargo -q run --example generate-format -- print > - // crates/sui-core/tests/staged/sui.yaml + // crates/iota-core/tests/staged/iota.yaml let status = std::process::Command::new("cargo") .current_dir("..") @@ -19,7 +20,7 @@ fn test_format() { status.success(), "\n\ If this test breaks and you intended a format change, you need to run to get the fresh format:\n\ -cargo -q run --example generate-format -- print > crates/sui-core/tests/staged/sui.yaml\n\ +cargo -q run --example generate-format -- print > crates/iota-core/tests/staged/iota.yaml\n\ " ); } diff --git a/crates/iota-core/tests/staged/iota.yaml b/crates/iota-core/tests/staged/iota.yaml new file mode 100644 index 00000000000..c40a1cad15e --- /dev/null +++ b/crates/iota-core/tests/staged/iota.yaml @@ -0,0 +1,1061 @@ +--- +AccountAddress: + NEWTYPESTRUCT: + TUPLEARRAY: + CONTENT: U8 + SIZE: 32 +ActiveJwk: + STRUCT: + - jwk_id: + TYPENAME: JwkId + - jwk: + TYPENAME: JWK + - epoch: U64 +Argument: + ENUM: + 0: + GasCoin: UNIT + 1: + Input: + NEWTYPE: U16 + 2: + Result: + NEWTYPE: U16 + 3: + NestedResult: + TUPLE: + - U16 + - U16 +AuthenticatorStateExpire: + STRUCT: + - min_epoch: U64 + - authenticator_obj_initial_shared_version: + TYPENAME: SequenceNumber +AuthenticatorStateUpdate: + STRUCT: + - epoch: U64 + - round: U64 + - new_active_jwks: + SEQ: + TYPENAME: ActiveJwk + - authenticator_obj_initial_shared_version: + TYPENAME: SequenceNumber +AuthorityPublicKeyBytes: + NEWTYPESTRUCT: BYTES +CallArg: + ENUM: + 0: + Pure: + NEWTYPE: + SEQ: U8 + 1: + Object: + NEWTYPE: + TYPENAME: ObjectArg +ChangeEpoch: + STRUCT: + - epoch: U64 + - protocol_version: + TYPENAME: ProtocolVersion + - storage_charge: U64 + - computation_charge: U64 + - storage_rebate: U64 + - non_refundable_storage_fee: U64 + - epoch_start_timestamp_ms: U64 + - system_packages: + SEQ: + TUPLE: + - TYPENAME: SequenceNumber + - SEQ: + SEQ: U8 + - SEQ: + TYPENAME: ObjectID +CheckpointCommitment: + ENUM: + 0: + ECMHLiveObjectSetDigest: + NEWTYPE: + TYPENAME: ECMHLiveObjectSetDigest +CheckpointContents: + ENUM: + 0: + V1: + NEWTYPE: + TYPENAME: CheckpointContentsV1 +CheckpointContentsDigest: + NEWTYPESTRUCT: + TYPENAME: Digest +CheckpointContentsV1: + STRUCT: + - transactions: + SEQ: + TYPENAME: ExecutionDigests + - user_signatures: + SEQ: + SEQ: + TYPENAME: GenericSignature +CheckpointDigest: + NEWTYPESTRUCT: + TYPENAME: Digest +CheckpointSummary: + STRUCT: + - epoch: U64 + - sequence_number: U64 + - network_total_transactions: U64 + - content_digest: + TYPENAME: CheckpointContentsDigest + - previous_digest: + OPTION: + TYPENAME: CheckpointDigest + - epoch_rolling_gas_cost_summary: + TYPENAME: GasCostSummary + - timestamp_ms: U64 + - checkpoint_commitments: + SEQ: + TYPENAME: CheckpointCommitment + - end_of_epoch_data: + OPTION: + TYPENAME: EndOfEpochData + - version_specific_data: + SEQ: U8 +Command: + ENUM: + 0: + MoveCall: + NEWTYPE: + TYPENAME: ProgrammableMoveCall + 1: + TransferObjects: + TUPLE: + - SEQ: + TYPENAME: Argument + - TYPENAME: Argument + 2: + SplitCoins: + TUPLE: + - TYPENAME: Argument + - SEQ: + TYPENAME: Argument + 3: + MergeCoins: + TUPLE: + - TYPENAME: Argument + - SEQ: + TYPENAME: Argument + 4: + Publish: + TUPLE: + - SEQ: + SEQ: U8 + - SEQ: + TYPENAME: ObjectID + 5: + MakeMoveVec: + TUPLE: + - OPTION: + TYPENAME: TypeTag + - SEQ: + TYPENAME: Argument + 6: + Upgrade: + TUPLE: + - SEQ: + SEQ: U8 + - SEQ: + TYPENAME: ObjectID + - TYPENAME: ObjectID + - TYPENAME: Argument +CommandArgumentError: + ENUM: + 0: + TypeMismatch: UNIT + 1: + InvalidBCSBytes: UNIT + 2: + InvalidUsageOfPureArg: UNIT + 3: + InvalidArgumentToPrivateEntryFunction: UNIT + 4: + IndexOutOfBounds: + STRUCT: + - idx: U16 + 5: + SecondaryIndexOutOfBounds: + STRUCT: + - result_idx: U16 + - secondary_idx: U16 + 6: + InvalidResultArity: + STRUCT: + - result_idx: U16 + 7: + InvalidGasCoinUsage: UNIT + 8: + InvalidValueUsage: UNIT + 9: + InvalidObjectByValue: UNIT + 10: + InvalidObjectByMutRef: UNIT + 11: + SharedObjectOperationNotAllowed: UNIT +CompressedSignature: + ENUM: + 0: + Ed25519: + NEWTYPE: + TUPLEARRAY: + CONTENT: U8 + SIZE: 64 + 1: + Secp256k1: + NEWTYPE: + TUPLEARRAY: + CONTENT: U8 + SIZE: 64 + 2: + Secp256r1: + NEWTYPE: + TUPLEARRAY: + CONTENT: U8 + SIZE: 64 + 3: + ZkLogin: + NEWTYPE: + TYPENAME: ZkLoginAuthenticatorAsBytes +ConsensusCommitDigest: + NEWTYPESTRUCT: + TYPENAME: Digest +ConsensusCommitPrologue: + STRUCT: + - epoch: U64 + - round: U64 + - commit_timestamp_ms: U64 +ConsensusCommitPrologueV2: + STRUCT: + - epoch: U64 + - round: U64 + - commit_timestamp_ms: U64 + - consensus_commit_digest: + TYPENAME: ConsensusCommitDigest +Data: + ENUM: + 0: + Move: + NEWTYPE: + TYPENAME: MoveObject + 1: + Package: + NEWTYPE: + TYPENAME: MovePackage +DeleteKind: + ENUM: + 0: + Normal: UNIT + 1: + UnwrapThenDelete: UNIT + 2: + Wrap: UNIT +Digest: + NEWTYPESTRUCT: BYTES +ECMHLiveObjectSetDigest: + STRUCT: + - digest: + TYPENAME: Digest +EffectsAuxDataDigest: + NEWTYPESTRUCT: + TYPENAME: Digest +EffectsObjectChange: + STRUCT: + - input_state: + TYPENAME: ObjectIn + - output_state: + TYPENAME: ObjectOut + - id_operation: + TYPENAME: IDOperation +EmptySignInfo: + STRUCT: [] +EndOfEpochData: + STRUCT: + - nextEpochCommittee: + SEQ: + TUPLE: + - TYPENAME: AuthorityPublicKeyBytes + - U64 + - nextEpochProtocolVersion: + TYPENAME: ProtocolVersion + - epochCommitments: + SEQ: + TYPENAME: CheckpointCommitment +EndOfEpochTransactionKind: + ENUM: + 0: + ChangeEpoch: + NEWTYPE: + TYPENAME: ChangeEpoch + 1: + AuthenticatorStateCreate: UNIT + 2: + AuthenticatorStateExpire: + NEWTYPE: + TYPENAME: AuthenticatorStateExpire + 3: + RandomnessStateCreate: UNIT + 4: + DenyListStateCreate: UNIT +Envelope: + STRUCT: + - data: + TYPENAME: SenderSignedData + - auth_signature: + TYPENAME: EmptySignInfo +ExecutionData: + STRUCT: + - transaction: + TYPENAME: Envelope + - effects: + TYPENAME: TransactionEffects +ExecutionDigests: + STRUCT: + - transaction: + TYPENAME: TransactionDigest + - effects: + TYPENAME: TransactionEffectsDigest +ExecutionFailureStatus: + ENUM: + 0: + InsufficientGas: UNIT + 1: + InvalidGasObject: UNIT + 2: + InvariantViolation: UNIT + 3: + FeatureNotYetSupported: UNIT + 4: + MoveObjectTooBig: + STRUCT: + - object_size: U64 + - max_object_size: U64 + 5: + MovePackageTooBig: + STRUCT: + - object_size: U64 + - max_object_size: U64 + 6: + CircularObjectOwnership: + STRUCT: + - object: + TYPENAME: ObjectID + 7: + InsufficientCoinBalance: UNIT + 8: + CoinBalanceOverflow: UNIT + 9: + PublishErrorNonZeroAddress: UNIT + 10: + IotaMoveVerificationError: UNIT + 11: + MovePrimitiveRuntimeError: + NEWTYPE: + TYPENAME: MoveLocationOpt + 12: + MoveAbort: + TUPLE: + - TYPENAME: MoveLocation + - U64 + 13: + VMVerificationOrDeserializationError: UNIT + 14: + VMInvariantViolation: UNIT + 15: + FunctionNotFound: UNIT + 16: + ArityMismatch: UNIT + 17: + TypeArityMismatch: UNIT + 18: + NonEntryFunctionInvoked: UNIT + 19: + CommandArgumentError: + STRUCT: + - arg_idx: U16 + - kind: + TYPENAME: CommandArgumentError + 20: + TypeArgumentError: + STRUCT: + - argument_idx: U16 + - kind: + TYPENAME: TypeArgumentError + 21: + UnusedValueWithoutDrop: + STRUCT: + - result_idx: U16 + - secondary_idx: U16 + 22: + InvalidPublicFunctionReturnType: + STRUCT: + - idx: U16 + 23: + InvalidTransferObject: UNIT + 24: + EffectsTooLarge: + STRUCT: + - current_size: U64 + - max_size: U64 + 25: + PublishUpgradeMissingDependency: UNIT + 26: + PublishUpgradeDependencyDowngrade: UNIT + 27: + PackageUpgradeError: + STRUCT: + - upgrade_error: + TYPENAME: PackageUpgradeError + 28: + WrittenObjectsTooLarge: + STRUCT: + - current_size: U64 + - max_size: U64 + 29: + CertificateDenied: UNIT + 30: + IotaMoveVerificationTimedout: UNIT + 31: + SharedObjectOperationNotAllowed: UNIT + 32: + InputObjectDeleted: UNIT +ExecutionStatus: + ENUM: + 0: + Success: UNIT + 1: + Failure: + STRUCT: + - error: + TYPENAME: ExecutionFailureStatus + - command: + OPTION: U64 +FullCheckpointContents: + STRUCT: + - transactions: + SEQ: + TYPENAME: ExecutionData + - user_signatures: + SEQ: + SEQ: + TYPENAME: GenericSignature +GasCostSummary: + STRUCT: + - computationCost: U64 + - storageCost: U64 + - storageRebate: U64 + - nonRefundableStorageFee: U64 +GasData: + STRUCT: + - payment: + SEQ: + TUPLE: + - TYPENAME: ObjectID + - TYPENAME: SequenceNumber + - TYPENAME: ObjectDigest + - owner: + TYPENAME: IotaAddress + - price: U64 + - budget: U64 +GenericSignature: + NEWTYPESTRUCT: + SEQ: U8 +GenesisObject: + ENUM: + 0: + RawObject: + STRUCT: + - data: + TYPENAME: Data + - owner: + TYPENAME: Owner +GenesisTransaction: + STRUCT: + - objects: + SEQ: + TYPENAME: GenesisObject +IDOperation: + ENUM: + 0: + None: UNIT + 1: + Created: UNIT + 2: + Deleted: UNIT +Identifier: + NEWTYPESTRUCT: STR +Intent: + STRUCT: + - scope: U8 + - version: U8 + - app_id: U8 +IntentMessage: + STRUCT: + - intent: + TYPENAME: Intent + - value: + TYPENAME: TransactionData +JWK: + STRUCT: + - kty: STR + - e: STR + - n: STR + - alg: STR +JwkId: + STRUCT: + - iss: STR + - kid: STR +ModuleId: + STRUCT: + - address: + TYPENAME: AccountAddress + - name: + TYPENAME: Identifier +MoveLocation: + STRUCT: + - module: + TYPENAME: ModuleId + - function: U16 + - instruction: U16 + - function_name: + OPTION: STR +MoveLocationOpt: + NEWTYPESTRUCT: + OPTION: + TYPENAME: MoveLocation +MoveObject: + STRUCT: + - type_: + TYPENAME: MoveObjectType + - has_public_transfer: BOOL + - version: + TYPENAME: SequenceNumber + - contents: BYTES +MoveObjectType: + NEWTYPESTRUCT: + TYPENAME: MoveObjectType_ +MoveObjectType_: + ENUM: + 0: + Other: + NEWTYPE: + TYPENAME: StructTag + 1: + GasCoin: UNIT + 2: + StakedIota: UNIT + 3: + Coin: + NEWTYPE: + TYPENAME: TypeTag +MovePackage: + STRUCT: + - id: + TYPENAME: ObjectID + - version: + TYPENAME: SequenceNumber + - module_map: + MAP: + KEY: STR + VALUE: BYTES + - type_origin_table: + SEQ: + TYPENAME: TypeOrigin + - linkage_table: + MAP: + KEY: + TYPENAME: ObjectID + VALUE: + TYPENAME: UpgradeInfo +MultiSig: + STRUCT: + - sigs: + SEQ: + TYPENAME: CompressedSignature + - bitmap: U16 + - multisig_pk: + TYPENAME: MultiSigPublicKey +MultiSigPublicKey: + STRUCT: + - pk_map: + SEQ: + TUPLE: + - TYPENAME: PublicKey + - U8 + - threshold: U16 +ObjectArg: + ENUM: + 0: + ImmOrOwnedObject: + NEWTYPE: + TUPLE: + - TYPENAME: ObjectID + - TYPENAME: SequenceNumber + - TYPENAME: ObjectDigest + 1: + SharedObject: + STRUCT: + - id: + TYPENAME: ObjectID + - initial_shared_version: + TYPENAME: SequenceNumber + - mutable: BOOL + 2: + Receiving: + NEWTYPE: + TUPLE: + - TYPENAME: ObjectID + - TYPENAME: SequenceNumber + - TYPENAME: ObjectDigest +ObjectDigest: + NEWTYPESTRUCT: + TYPENAME: Digest +ObjectID: + NEWTYPESTRUCT: + TYPENAME: AccountAddress +ObjectIn: + ENUM: + 0: + NotExist: UNIT + 1: + Exist: + NEWTYPE: + TUPLE: + - TUPLE: + - TYPENAME: SequenceNumber + - TYPENAME: ObjectDigest + - TYPENAME: Owner +ObjectInfoRequestKind: + ENUM: + 0: + LatestObjectInfo: UNIT + 1: + PastObjectInfoDebug: + NEWTYPE: + TYPENAME: SequenceNumber +ObjectOut: + ENUM: + 0: + NotExist: UNIT + 1: + ObjectWrite: + NEWTYPE: + TUPLE: + - TYPENAME: ObjectDigest + - TYPENAME: Owner + 2: + PackageWrite: + NEWTYPE: + TUPLE: + - TYPENAME: SequenceNumber + - TYPENAME: ObjectDigest +Owner: + ENUM: + 0: + AddressOwner: + NEWTYPE: + TYPENAME: IotaAddress + 1: + ObjectOwner: + NEWTYPE: + TYPENAME: IotaAddress + 2: + Shared: + STRUCT: + - initial_shared_version: + TYPENAME: SequenceNumber + 3: + Immutable: UNIT +PackageUpgradeError: + ENUM: + 0: + UnableToFetchPackage: + STRUCT: + - package_id: + TYPENAME: ObjectID + 1: + NotAPackage: + STRUCT: + - object_id: + TYPENAME: ObjectID + 2: + IncompatibleUpgrade: UNIT + 3: + DigestDoesNotMatch: + STRUCT: + - digest: + SEQ: U8 + 4: + UnknownUpgradePolicy: + STRUCT: + - policy: U8 + 5: + PackageIDDoesNotMatch: + STRUCT: + - package_id: + TYPENAME: ObjectID + - ticket_id: + TYPENAME: ObjectID +ProgrammableMoveCall: + STRUCT: + - package: + TYPENAME: ObjectID + - module: + TYPENAME: Identifier + - function: + TYPENAME: Identifier + - type_arguments: + SEQ: + TYPENAME: TypeTag + - arguments: + SEQ: + TYPENAME: Argument +ProgrammableTransaction: + STRUCT: + - inputs: + SEQ: + TYPENAME: CallArg + - commands: + SEQ: + TYPENAME: Command +ProtocolVersion: + NEWTYPESTRUCT: U64 +PublicKey: + ENUM: + 0: + Ed25519: + NEWTYPE: + TUPLEARRAY: + CONTENT: U8 + SIZE: 32 + 1: + Secp256k1: + NEWTYPE: + TUPLEARRAY: + CONTENT: U8 + SIZE: 33 + 2: + Secp256r1: + NEWTYPE: + TUPLEARRAY: + CONTENT: U8 + SIZE: 33 + 3: + ZkLogin: + NEWTYPE: + TYPENAME: ZkLoginPublicIdentifier +RandomnessRound: + NEWTYPESTRUCT: U64 +RandomnessStateUpdate: + STRUCT: + - epoch: U64 + - randomness_round: + TYPENAME: RandomnessRound + - random_bytes: + SEQ: U8 + - randomness_obj_initial_shared_version: + TYPENAME: SequenceNumber +SenderSignedData: + NEWTYPESTRUCT: + SEQ: + TYPENAME: SenderSignedTransaction +SenderSignedTransaction: + STRUCT: + - intent_message: + TYPENAME: IntentMessage + - tx_signatures: + SEQ: + TYPENAME: GenericSignature +SequenceNumber: + NEWTYPESTRUCT: U64 +StructTag: + STRUCT: + - address: + TYPENAME: AccountAddress + - module: + TYPENAME: Identifier + - name: + TYPENAME: Identifier + - type_args: + SEQ: + TYPENAME: TypeTag +IotaAddress: + NEWTYPESTRUCT: + TUPLEARRAY: + CONTENT: U8 + SIZE: 32 +TransactionData: + ENUM: + 0: + V1: + NEWTYPE: + TYPENAME: TransactionDataV1 +TransactionDataV1: + STRUCT: + - kind: + TYPENAME: TransactionKind + - sender: + TYPENAME: IotaAddress + - gas_data: + TYPENAME: GasData + - expiration: + TYPENAME: TransactionExpiration +TransactionDigest: + NEWTYPESTRUCT: + TYPENAME: Digest +TransactionEffects: + ENUM: + 0: + V1: + NEWTYPE: + TYPENAME: TransactionEffectsV1 + 1: + V2: + NEWTYPE: + TYPENAME: TransactionEffectsV2 +TransactionEffectsDigest: + NEWTYPESTRUCT: + TYPENAME: Digest +TransactionEffectsV1: + STRUCT: + - status: + TYPENAME: ExecutionStatus + - executed_epoch: U64 + - gas_used: + TYPENAME: GasCostSummary + - modified_at_versions: + SEQ: + TUPLE: + - TYPENAME: ObjectID + - TYPENAME: SequenceNumber + - shared_objects: + SEQ: + TUPLE: + - TYPENAME: ObjectID + - TYPENAME: SequenceNumber + - TYPENAME: ObjectDigest + - transaction_digest: + TYPENAME: TransactionDigest + - created: + SEQ: + TUPLE: + - TUPLE: + - TYPENAME: ObjectID + - TYPENAME: SequenceNumber + - TYPENAME: ObjectDigest + - TYPENAME: Owner + - mutated: + SEQ: + TUPLE: + - TUPLE: + - TYPENAME: ObjectID + - TYPENAME: SequenceNumber + - TYPENAME: ObjectDigest + - TYPENAME: Owner + - unwrapped: + SEQ: + TUPLE: + - TUPLE: + - TYPENAME: ObjectID + - TYPENAME: SequenceNumber + - TYPENAME: ObjectDigest + - TYPENAME: Owner + - deleted: + SEQ: + TUPLE: + - TYPENAME: ObjectID + - TYPENAME: SequenceNumber + - TYPENAME: ObjectDigest + - unwrapped_then_deleted: + SEQ: + TUPLE: + - TYPENAME: ObjectID + - TYPENAME: SequenceNumber + - TYPENAME: ObjectDigest + - wrapped: + SEQ: + TUPLE: + - TYPENAME: ObjectID + - TYPENAME: SequenceNumber + - TYPENAME: ObjectDigest + - gas_object: + TUPLE: + - TUPLE: + - TYPENAME: ObjectID + - TYPENAME: SequenceNumber + - TYPENAME: ObjectDigest + - TYPENAME: Owner + - events_digest: + OPTION: + TYPENAME: TransactionEventsDigest + - dependencies: + SEQ: + TYPENAME: TransactionDigest +TransactionEffectsV2: + STRUCT: + - status: + TYPENAME: ExecutionStatus + - executed_epoch: U64 + - gas_used: + TYPENAME: GasCostSummary + - transaction_digest: + TYPENAME: TransactionDigest + - gas_object_index: + OPTION: U32 + - events_digest: + OPTION: + TYPENAME: TransactionEventsDigest + - dependencies: + SEQ: + TYPENAME: TransactionDigest + - lamport_version: + TYPENAME: SequenceNumber + - changed_objects: + SEQ: + TUPLE: + - TYPENAME: ObjectID + - TYPENAME: EffectsObjectChange + - unchanged_shared_objects: + SEQ: + TUPLE: + - TYPENAME: ObjectID + - TYPENAME: UnchangedSharedKind + - aux_data_digest: + OPTION: + TYPENAME: EffectsAuxDataDigest +TransactionEventsDigest: + NEWTYPESTRUCT: + TYPENAME: Digest +TransactionExpiration: + ENUM: + 0: + None: UNIT + 1: + Epoch: + NEWTYPE: U64 +TransactionKind: + ENUM: + 0: + ProgrammableTransaction: + NEWTYPE: + TYPENAME: ProgrammableTransaction + 1: + ChangeEpoch: + NEWTYPE: + TYPENAME: ChangeEpoch + 2: + Genesis: + NEWTYPE: + TYPENAME: GenesisTransaction + 3: + ConsensusCommitPrologue: + NEWTYPE: + TYPENAME: ConsensusCommitPrologue + 4: + AuthenticatorStateUpdate: + NEWTYPE: + TYPENAME: AuthenticatorStateUpdate + 5: + EndOfEpochTransaction: + NEWTYPE: + SEQ: + TYPENAME: EndOfEpochTransactionKind + 6: + RandomnessStateUpdate: + NEWTYPE: + TYPENAME: RandomnessStateUpdate + 7: + ConsensusCommitPrologueV2: + NEWTYPE: + TYPENAME: ConsensusCommitPrologueV2 +TypeArgumentError: + ENUM: + 0: + TypeNotFound: UNIT + 1: + ConstraintNotSatisfied: UNIT +TypeOrigin: + STRUCT: + - module_name: STR + - struct_name: STR + - package: + TYPENAME: ObjectID +TypeTag: + ENUM: + 0: + bool: UNIT + 1: + u8: UNIT + 2: + u64: UNIT + 3: + u128: UNIT + 4: + address: UNIT + 5: + signer: UNIT + 6: + vector: + NEWTYPE: + TYPENAME: TypeTag + 7: + struct: + NEWTYPE: + TYPENAME: StructTag + 8: + u16: UNIT + 9: + u32: UNIT + 10: + u256: UNIT +TypedStoreError: + ENUM: + 0: + RocksDBError: + NEWTYPE: STR + 1: + SerializationError: + NEWTYPE: STR + 2: + UnregisteredColumn: + NEWTYPE: STR + 3: + CrossDBBatch: UNIT + 4: + MetricsReporting: UNIT + 5: + RetryableTransactionError: UNIT +UnchangedSharedKind: + ENUM: + 0: + ReadOnlyRoot: + NEWTYPE: + TUPLE: + - TYPENAME: SequenceNumber + - TYPENAME: ObjectDigest + 1: + MutateDeleted: + NEWTYPE: + TYPENAME: SequenceNumber + 2: + ReadDeleted: + NEWTYPE: + TYPENAME: SequenceNumber +UpgradeInfo: + STRUCT: + - upgraded_id: + TYPENAME: ObjectID + - upgraded_version: + TYPENAME: SequenceNumber +ZkLoginAuthenticatorAsBytes: + NEWTYPESTRUCT: + SEQ: U8 +ZkLoginPublicIdentifier: + NEWTYPESTRUCT: + SEQ: U8 + diff --git a/crates/iota-cost/Cargo.toml b/crates/iota-cost/Cargo.toml new file mode 100644 index 00000000000..7249b26c83a --- /dev/null +++ b/crates/iota-cost/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "iota-cost" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +iota-types.workspace = true +anyhow.workspace = true +tokio = { workspace = true, features = ["full"] } +serde.workspace = true +strum.workspace = true +strum_macros.workspace = true +bcs.workspace = true + +[dev-dependencies] +insta.workspace = true +test-cluster.workspace = true +iota-config.workspace = true +iota-swarm-config.workspace = true +iota-test-transaction-builder.workspace = true +iota-move-build.workspace = true +move-cli.workspace = true +move-disassembler.workspace = true +iota-json-rpc-types.workspace = true diff --git a/crates/iota-cost/tests/data/dummy_modules_publish/Move.toml b/crates/iota-cost/tests/data/dummy_modules_publish/Move.toml new file mode 100644 index 00000000000..e518fc169a9 --- /dev/null +++ b/crates/iota-cost/tests/data/dummy_modules_publish/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "Examples" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../iota-framework/packages/iota-framework" } + +[addresses] +examples = "0x0" diff --git a/crates/iota-cost/tests/data/dummy_modules_publish/sources/trusted_coin.move b/crates/iota-cost/tests/data/dummy_modules_publish/sources/trusted_coin.move new file mode 100644 index 00000000000..0707868408a --- /dev/null +++ b/crates/iota-cost/tests/data/dummy_modules_publish/sources/trusted_coin.move @@ -0,0 +1,30 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Example coin with a trusted owner responsible for minting/burning (e.g., a stablecoin) +module examples::trusted_coin { + use std::option; + use iota::coin::{Self, TreasuryCap}; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; + + /// Name of the coin + struct TRUSTED_COIN has drop {} + + /// Register the trusted currency to acquire its `TreasuryCap`. Because + /// this is a module initializer, it ensures the currency only gets + /// registered once. + fun init(witness: TRUSTED_COIN, ctx: &mut TxContext) { + // Get a treasury cap for the coin and give it to the transaction + // sender + let (treasury_cap, metadata) = coin::create_currency(witness, 2, b"TRUSTED", b"", b"", option::none(), ctx); + transfer::public_freeze_object(metadata); + transfer::public_transfer(treasury_cap, tx_context::sender(ctx)) + } + + public entry fun mint(treasury_cap: &mut TreasuryCap, amount: u64, ctx: &mut TxContext) { + let coin = coin::mint(treasury_cap, amount, ctx); + transfer::public_transfer(coin, tx_context::sender(ctx)); + } +} diff --git a/crates/sui-cost/tests/empirical_transaction_cost.rs b/crates/iota-cost/tests/empirical_transaction_cost.rs similarity index 87% rename from crates/sui-cost/tests/empirical_transaction_cost.rs rename to crates/iota-cost/tests/empirical_transaction_cost.rs index 9466164549c..03494cb30e4 100644 --- a/crates/sui-cost/tests/empirical_transaction_cost.rs +++ b/crates/iota-cost/tests/empirical_transaction_cost.rs @@ -1,24 +1,25 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, path::PathBuf}; use insta::assert_json_snapshot; -use serde::{Deserialize, Serialize}; -use strum_macros::{Display, EnumString}; -use sui_json_rpc_types::SuiTransactionBlockEffectsAPI; -use sui_swarm_config::genesis_config::{AccountConfig, DEFAULT_GAS_AMOUNT}; -use sui_test_transaction_builder::{ +use iota_json_rpc_types::IotaTransactionBlockEffectsAPI; +use iota_swarm_config::genesis_config::{AccountConfig, DEFAULT_GAS_AMOUNT}; +use iota_test_transaction_builder::{ publish_basics_package_and_make_counter, TestTransactionBuilder, }; -use sui_types::{ - base_types::{ObjectRef, SuiAddress}, +use iota_types::{ + base_types::{IotaAddress, ObjectRef}, coin::{PAY_JOIN_FUNC_NAME, PAY_MODULE_NAME, PAY_SPLIT_VEC_FUNC_NAME}, gas::GasCostSummary, gas_coin::GAS, transaction::{CallArg, ObjectArg, TransactionData}, - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, }; +use serde::{Deserialize, Serialize}; +use strum_macros::{Display, EnumString}; use test_cluster::{TestCluster, TestClusterBuilder}; #[derive( @@ -29,8 +30,8 @@ pub enum CommonTransactionCosts { MergeCoin, SplitCoin(usize), TransferWholeCoin, - TransferWholeSuiCoin, - TransferPortionSuiCoin, + TransferWholeIotaCoin, + TransferPortionIotaCoin, SharedCounterCreate, SharedCounterAssertValue, SharedCounterIncrement, @@ -51,7 +52,7 @@ const TEST_DATA_DIR: &str = "tests/data/"; // Execute every entry function in Move framework and examples and ensure costs // don't change To review snapshot changes, and fix snapshot differences, // 0. Install cargo-insta -// 1. Run `cargo insta test --review` under `./sui-cost`. +// 1. Run `cargo insta test --review` under `./iota-cost`. // 2. Review, accept or reject changes. #[tokio::test] @@ -71,14 +72,14 @@ async fn split_n_tx( coin: ObjectRef, gas: ObjectRef, gas_price: u64, - sender: SuiAddress, + sender: IotaAddress, ) -> TransactionData { let split_amounts = vec![10u64; n as usize]; let type_args = vec![GAS::type_tag()]; TestTransactionBuilder::new(sender, gas, gas_price) .move_call( - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, PAY_MODULE_NAME.as_str(), PAY_SPLIT_VEC_FUNC_NAME.as_str(), vec![ @@ -114,29 +115,29 @@ async fn create_txes( .build(); ret.insert(CommonTransactionCosts::Publish, publish_tx); - // Transfer Whole Sui Coin and Transfer Portion of Sui Coin + // Transfer Whole Iota Coin and Transfer Portion of Iota Coin // - let whole_sui_coin_tx = + let whole_iota_coin_tx = TestTransactionBuilder::new(sender, gas_objects.pop().unwrap(), gas_price) - .transfer_sui(None, SuiAddress::default()) + .transfer_iota(None, IotaAddress::default()) .build(); - let partial_sui_coin_tx = + let partial_iota_coin_tx = TestTransactionBuilder::new(sender, gas_objects.pop().unwrap(), gas_price) - .transfer_sui(Some(10), SuiAddress::default()) + .transfer_iota(Some(10), IotaAddress::default()) .build(); ret.insert( - CommonTransactionCosts::TransferWholeSuiCoin, - whole_sui_coin_tx, + CommonTransactionCosts::TransferWholeIotaCoin, + whole_iota_coin_tx, ); ret.insert( - CommonTransactionCosts::TransferPortionSuiCoin, - partial_sui_coin_tx, + CommonTransactionCosts::TransferPortionIotaCoin, + partial_iota_coin_tx, ); // Transfer Whole Coin Object // let whole_coin_tx = TestTransactionBuilder::new(sender, gas_objects.pop().unwrap(), gas_price) - .transfer(gas_objects.pop().unwrap(), SuiAddress::default()) + .transfer(gas_objects.pop().unwrap(), IotaAddress::default()) .build(); ret.insert(CommonTransactionCosts::TransferWholeCoin, whole_coin_tx); @@ -148,7 +149,7 @@ async fn create_txes( let merge_tx = TestTransactionBuilder::new(sender, gas_objects.pop().unwrap(), gas_price) .move_call( - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, PAY_MODULE_NAME.as_str(), PAY_JOIN_FUNC_NAME.as_str(), vec![ diff --git a/crates/sui-cost/tests/snapshots/empirical_transaction_cost__good_snapshot.snap b/crates/iota-cost/tests/snapshots/empirical_transaction_cost__good_snapshot.snap similarity index 92% rename from crates/sui-cost/tests/snapshots/empirical_transaction_cost__good_snapshot.snap rename to crates/iota-cost/tests/snapshots/empirical_transaction_cost__good_snapshot.snap index f16001b9b02..abbaec16c68 100644 --- a/crates/sui-cost/tests/snapshots/empirical_transaction_cost__good_snapshot.snap +++ b/crates/iota-cost/tests/snapshots/empirical_transaction_cost__good_snapshot.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-cost/tests/empirical_transaction_cost.rs +source: crates/iota-cost/tests/empirical_transaction_cost.rs expression: common_costs_actual --- { @@ -39,7 +39,7 @@ expression: common_costs_actual "storageRebate": "0", "nonRefundableStorageFee": "0" }, - "TransferPortionSuiCoin": { + "TransferPortionIotaCoin": { "computationCost": "1000000", "storageCost": "1976000", "storageRebate": "0", @@ -51,7 +51,7 @@ expression: common_costs_actual "storageRebate": "0", "nonRefundableStorageFee": "0" }, - "TransferWholeSuiCoin": { + "TransferWholeIotaCoin": { "computationCost": "1000000", "storageCost": "988000", "storageRebate": "0", diff --git a/crates/iota-cost/troubleshooting.md b/crates/iota-cost/troubleshooting.md new file mode 100644 index 00000000000..9d37cba8362 --- /dev/null +++ b/crates/iota-cost/troubleshooting.md @@ -0,0 +1,13 @@ +# Troubleshooting + +## Iota Framework change + +If Iota framework code got updated, the expectations need to be changed. Follow these steps: + +```bash +# required; can be omitted if cargo-insta is installed +$ cargo install cargo-insta + +# run in ./iota-cost +$ cargo insta test --review +``` diff --git a/crates/iota-data-ingestion-core/Cargo.toml b/crates/iota-data-ingestion-core/Cargo.toml new file mode 100644 index 00000000000..b6670d0d766 --- /dev/null +++ b/crates/iota-data-ingestion-core/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "iota-data-ingestion-core" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" +version = "0.1.0" + +[dependencies] +anyhow.workspace = true +async-trait.workspace = true +backoff.workspace = true +futures.workspace = true +mysten-metrics.workspace = true +notify.workspace = true +serde.workspace = true +serde_json.workspace = true +object_store.workspace = true +prometheus.workspace = true +telemetry-subscribers.workspace = true +tokio = { workspace = true, features = ["full"] } +tracing.workspace = true +iota-storage.workspace = true +iota-types.workspace = true +url.workspace = true +tempfile.workspace = true +tap.workspace = true + +[dev-dependencies] +rand.workspace = true +iota-types = { workspace = true, features = ["test-utils"] } diff --git a/crates/iota-data-ingestion-core/src/executor.rs b/crates/iota-data-ingestion-core/src/executor.rs new file mode 100644 index 00000000000..98f8850e0c3 --- /dev/null +++ b/crates/iota-data-ingestion-core/src/executor.rs @@ -0,0 +1,133 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{path::PathBuf, pin::Pin}; + +use anyhow::Result; +use futures::Future; +use iota_types::{ + full_checkpoint_content::CheckpointData, messages_checkpoint::CheckpointSequenceNumber, +}; +use mysten_metrics::spawn_monitored_task; +use prometheus::Registry; +use tokio::sync::{mpsc, oneshot}; + +use crate::{ + progress_store::{ExecutorProgress, ProgressStore, ProgressStoreWrapper, ShimProgressStore}, + reader::CheckpointReader, + worker_pool::WorkerPool, + DataIngestionMetrics, ReaderOptions, Worker, +}; + +pub const MAX_CHECKPOINTS_IN_PROGRESS: usize = 10000; + +pub struct IndexerExecutor

    { + pools: Vec + Send>>>, + pool_senders: Vec>, + progress_store: ProgressStoreWrapper

    , + pool_progress_sender: mpsc::Sender<(String, CheckpointSequenceNumber)>, + pool_progress_receiver: mpsc::Receiver<(String, CheckpointSequenceNumber)>, + metrics: DataIngestionMetrics, +} + +impl IndexerExecutor

    { + pub fn new(progress_store: P, number_of_jobs: usize, metrics: DataIngestionMetrics) -> Self { + let (pool_progress_sender, pool_progress_receiver) = + mpsc::channel(number_of_jobs * MAX_CHECKPOINTS_IN_PROGRESS); + Self { + pools: vec![], + pool_senders: vec![], + progress_store: ProgressStoreWrapper::new(progress_store), + pool_progress_sender, + pool_progress_receiver, + metrics, + } + } + + /// Registers new worker pool in executor + pub async fn register(&mut self, pool: WorkerPool) -> Result<()> { + let checkpoint_number = self.progress_store.load(pool.task_name.clone()).await?; + let (sender, receiver) = mpsc::channel(MAX_CHECKPOINTS_IN_PROGRESS); + self.pools.push(Box::pin(pool.run( + checkpoint_number, + receiver, + self.pool_progress_sender.clone(), + ))); + self.pool_senders.push(sender); + Ok(()) + } + + /// Main executor loop + pub async fn run( + mut self, + path: PathBuf, + remote_store_url: Option, + remote_store_options: Vec<(String, String)>, + reader_options: ReaderOptions, + mut exit_receiver: oneshot::Receiver<()>, + ) -> Result { + let mut reader_checkpoint_number = self.progress_store.min_watermark()?; + let (checkpoint_reader, mut checkpoint_recv, gc_sender, _exit_sender) = + CheckpointReader::initialize( + path, + reader_checkpoint_number, + remote_store_url, + remote_store_options, + reader_options, + ); + spawn_monitored_task!(checkpoint_reader.run()); + + for pool in std::mem::take(&mut self.pools) { + spawn_monitored_task!(pool); + } + loop { + tokio::select! { + _ = &mut exit_receiver => break, + Some((task_name, sequence_number)) = self.pool_progress_receiver.recv() => { + self.progress_store.save(task_name.clone(), sequence_number).await?; + let seq_number = self.progress_store.min_watermark()?; + if seq_number > reader_checkpoint_number { + gc_sender.send(seq_number).await?; + reader_checkpoint_number = seq_number; + } + self.metrics.data_ingestion_checkpoint.with_label_values(&[&task_name]).set(sequence_number as i64); + } + Some(checkpoint) = checkpoint_recv.recv() => { + for sender in &self.pool_senders { + sender.send(checkpoint.clone()).await?; + } + } + } + } + Ok(self.progress_store.stats()) + } +} + +pub async fn setup_single_workflow( + worker: W, + remote_store_url: String, + initial_checkpoint_number: CheckpointSequenceNumber, + concurrency: usize, + reader_options: Option, +) -> Result<( + impl Future>, + oneshot::Sender<()>, +)> { + let (exit_sender, exit_receiver) = oneshot::channel(); + let metrics = DataIngestionMetrics::new(&Registry::new()); + let progress_store = ShimProgressStore(initial_checkpoint_number); + let mut executor = IndexerExecutor::new(progress_store, 1, metrics); + let worker_pool = WorkerPool::new(worker, "workflow".to_string(), concurrency); + executor.register(worker_pool).await?; + Ok(( + executor.run( + tempfile::tempdir()?.into_path(), + Some(remote_store_url), + vec![], + reader_options.unwrap_or_default(), + exit_receiver, + ), + exit_sender, + )) +} diff --git a/crates/iota-data-ingestion-core/src/lib.rs b/crates/iota-data-ingestion-core/src/lib.rs new file mode 100644 index 00000000000..4deb834941a --- /dev/null +++ b/crates/iota-data-ingestion-core/src/lib.rs @@ -0,0 +1,40 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod executor; +mod metrics; +mod progress_store; +mod reader; +#[cfg(test)] +mod tests; +mod util; +mod worker_pool; + +use anyhow::Result; +use async_trait::async_trait; +pub use executor::{setup_single_workflow, IndexerExecutor, MAX_CHECKPOINTS_IN_PROGRESS}; +use iota_types::{ + full_checkpoint_content::CheckpointData, messages_checkpoint::CheckpointSequenceNumber, +}; +pub use metrics::DataIngestionMetrics; +pub use progress_store::{FileProgressStore, ProgressStore}; +pub use reader::ReaderOptions; +pub use util::create_remote_store_client; +pub use worker_pool::WorkerPool; + +#[async_trait] +pub trait Worker: Send + Sync { + async fn process_checkpoint(&self, checkpoint: CheckpointData) -> Result<()>; + /// Optional method. Allows controlling when workflow progress is updated in + /// the progress store. For instance, some pipelines may benefit from + /// aggregating checkpoints, thus skipping the saving of updates for + /// intermediate checkpoints. The default implementation is to update + /// the progress store for every processed checkpoint. + async fn save_progress( + &self, + sequence_number: CheckpointSequenceNumber, + ) -> Option { + Some(sequence_number) + } +} diff --git a/crates/iota-data-ingestion-core/src/metrics.rs b/crates/iota-data-ingestion-core/src/metrics.rs new file mode 100644 index 00000000000..8880766dc12 --- /dev/null +++ b/crates/iota-data-ingestion-core/src/metrics.rs @@ -0,0 +1,24 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use prometheus::{register_int_gauge_vec_with_registry, IntGaugeVec, Registry}; + +#[derive(Clone)] +pub struct DataIngestionMetrics { + pub data_ingestion_checkpoint: IntGaugeVec, +} + +impl DataIngestionMetrics { + pub fn new(registry: &Registry) -> Self { + Self { + data_ingestion_checkpoint: register_int_gauge_vec_with_registry!( + "data_ingestion_checkpoint", + "Number of uploaded checkpoints.", + &["task"], + registry, + ) + .unwrap(), + } + } +} diff --git a/crates/sui-data-ingestion-core/src/progress_store/file.rs b/crates/iota-data-ingestion-core/src/progress_store/file.rs similarity index 91% rename from crates/sui-data-ingestion-core/src/progress_store/file.rs rename to crates/iota-data-ingestion-core/src/progress_store/file.rs index d37bf018107..b392a1674a9 100644 --- a/crates/sui-data-ingestion-core/src/progress_store/file.rs +++ b/crates/iota-data-ingestion-core/src/progress_store/file.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::PathBuf; use anyhow::Result; use async_trait::async_trait; +use iota_types::messages_checkpoint::CheckpointSequenceNumber; use serde_json::{Number, Value}; -use sui_types::messages_checkpoint::CheckpointSequenceNumber; use crate::progress_store::ProgressStore; diff --git a/crates/iota-data-ingestion-core/src/progress_store/mod.rs b/crates/iota-data-ingestion-core/src/progress_store/mod.rs new file mode 100644 index 00000000000..f299cfbc7d9 --- /dev/null +++ b/crates/iota-data-ingestion-core/src/progress_store/mod.rs @@ -0,0 +1,82 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashMap; + +use anyhow::Result; +use async_trait::async_trait; +use iota_types::messages_checkpoint::CheckpointSequenceNumber; +mod file; +pub use file::FileProgressStore; + +pub type ExecutorProgress = HashMap; + +#[async_trait] +pub trait ProgressStore: Send { + async fn load(&mut self, task_name: String) -> Result; + async fn save( + &mut self, + task_name: String, + checkpoint_number: CheckpointSequenceNumber, + ) -> Result<()>; +} + +pub struct ProgressStoreWrapper

    { + progress_store: P, + pending_state: ExecutorProgress, +} + +#[async_trait] +impl ProgressStore for ProgressStoreWrapper

    { + async fn load(&mut self, task_name: String) -> Result { + let watermark = self.progress_store.load(task_name.clone()).await?; + self.pending_state.insert(task_name, watermark); + Ok(watermark) + } + + async fn save( + &mut self, + task_name: String, + checkpoint_number: CheckpointSequenceNumber, + ) -> Result<()> { + self.progress_store + .save(task_name.clone(), checkpoint_number) + .await?; + self.pending_state.insert(task_name, checkpoint_number); + Ok(()) + } +} + +impl ProgressStoreWrapper

    { + pub fn new(progress_store: P) -> Self { + Self { + progress_store, + pending_state: HashMap::new(), + } + } + + pub fn min_watermark(&self) -> Result { + self.pending_state + .values() + .min() + .cloned() + .ok_or_else(|| anyhow::anyhow!("pools can't be empty")) + } + + pub fn stats(&self) -> ExecutorProgress { + self.pending_state.clone() + } +} + +pub struct ShimProgressStore(pub u64); + +#[async_trait] +impl ProgressStore for ShimProgressStore { + async fn load(&mut self, _: String) -> Result { + Ok(self.0) + } + async fn save(&mut self, _: String, _: CheckpointSequenceNumber) -> Result<()> { + Ok(()) + } +} diff --git a/crates/iota-data-ingestion-core/src/reader.rs b/crates/iota-data-ingestion-core/src/reader.rs new file mode 100644 index 00000000000..9dc5d7e816e --- /dev/null +++ b/crates/iota-data-ingestion-core/src/reader.rs @@ -0,0 +1,297 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ffi::OsString, fs, path::PathBuf, time::Duration}; + +use anyhow::Result; +use backoff::backoff::Backoff; +use futures::StreamExt; +use iota_storage::blob::Blob; +use iota_types::{ + full_checkpoint_content::CheckpointData, messages_checkpoint::CheckpointSequenceNumber, +}; +use mysten_metrics::spawn_monitored_task; +use notify::{RecursiveMode, Watcher}; +use object_store::{path::Path, ObjectStore}; +use tap::pipe::Pipe; +use tokio::{ + sync::{mpsc, mpsc::error::TryRecvError, oneshot}, + time::timeout, +}; +use tracing::{debug, error, info}; + +use crate::{create_remote_store_client, executor::MAX_CHECKPOINTS_IN_PROGRESS}; + +/// Implements a checkpoint reader that monitors a local directory. +/// Designed for setups where the indexer daemon is colocated with FN. +/// This implementation is push-based and utilizes the inotify API. +pub struct CheckpointReader { + path: PathBuf, + remote_store_url: Option, + remote_store_options: Vec<(String, String)>, + current_checkpoint_number: CheckpointSequenceNumber, + last_pruned_watermark: CheckpointSequenceNumber, + checkpoint_sender: mpsc::Sender, + processed_receiver: mpsc::Receiver, + remote_fetcher_receiver: Option>>, + exit_receiver: oneshot::Receiver<()>, + options: ReaderOptions, +} + +#[derive(Clone)] +pub struct ReaderOptions { + pub tick_interal_ms: u64, + pub timeout_secs: u64, + pub batch_size: usize, +} + +impl Default for ReaderOptions { + fn default() -> Self { + Self { + tick_interal_ms: 100, + timeout_secs: 5, + batch_size: 100, + } + } +} + +impl CheckpointReader { + /// Represents a single iteration of the reader. + /// Reads files in a local directory, validates them, and forwards + /// `CheckpointData` to the executor. + async fn read_local_files(&self) -> Result> { + let mut files = vec![]; + for entry in fs::read_dir(self.path.clone())? { + let entry = entry?; + let filename = entry.file_name(); + if let Some(sequence_number) = Self::checkpoint_number_from_file_path(&filename) { + if sequence_number >= self.current_checkpoint_number { + files.push((sequence_number, entry.path())); + } + } + } + files.sort(); + debug!("unprocessed local files {:?}", files); + let mut checkpoints = vec![]; + for (_, filename) in files.iter().take(MAX_CHECKPOINTS_IN_PROGRESS) { + let checkpoint = Blob::from_bytes::(&fs::read(filename)?)?; + checkpoints.push(checkpoint); + } + Ok(checkpoints) + } + + fn exceeds_capacity(&self, checkpoint_number: CheckpointSequenceNumber) -> bool { + (MAX_CHECKPOINTS_IN_PROGRESS as u64 + self.last_pruned_watermark) <= checkpoint_number + } + + async fn remote_fetch_checkpoint_internal( + store: &dyn ObjectStore, + checkpoint_number: CheckpointSequenceNumber, + ) -> Result { + let path = Path::from(format!("{}.chk", checkpoint_number)); + let response = store.get(&path).await?; + let bytes = response.bytes().await?; + Blob::from_bytes::(&bytes) + } + + async fn remote_fetch_checkpoint( + store: &dyn ObjectStore, + checkpoint_number: CheckpointSequenceNumber, + ) -> Result { + let mut backoff = backoff::ExponentialBackoff::default(); + backoff.max_elapsed_time = Some(Duration::from_secs(60)); + backoff.initial_interval = Duration::from_millis(100); + backoff.current_interval = backoff.initial_interval; + backoff.multiplier = 1.0; + loop { + match Self::remote_fetch_checkpoint_internal(store, checkpoint_number).await { + Ok(data) => return Ok(data), + Err(err) if err.to_string().contains("404") => match backoff.next_backoff() { + Some(duration) => tokio::time::sleep(duration).await, + None => return Err(err), + }, + Err(err) => return Err(err), + } + } + } + + fn start_remote_fetcher(&mut self) -> mpsc::Receiver> { + let batch_size = self.options.batch_size; + let start_checkpoint = self.current_checkpoint_number; + let (sender, receiver) = mpsc::channel(batch_size); + let url = self + .remote_store_url + .clone() + .expect("remote store url must be set"); + let store = create_remote_store_client( + url, + self.remote_store_options.clone(), + self.options.timeout_secs, + ) + .expect("failed to create remote store client"); + + spawn_monitored_task!(async move { + let mut checkpoint_stream = (start_checkpoint..u64::MAX) + .map(|checkpoint_number| Self::remote_fetch_checkpoint(&store, checkpoint_number)) + .pipe(futures::stream::iter) + .buffered(batch_size); + + while let Some(checkpoint) = checkpoint_stream.next().await { + if sender.send(checkpoint).await.is_err() { + info!("remote reader dropped"); + break; + } + } + }); + receiver + } + + fn remote_fetch(&mut self) -> Vec { + let mut checkpoints = vec![]; + if self.remote_fetcher_receiver.is_none() { + self.remote_fetcher_receiver = Some(self.start_remote_fetcher()); + } + while !self.exceeds_capacity(self.current_checkpoint_number + checkpoints.len() as u64) { + match self.remote_fetcher_receiver.as_mut().unwrap().try_recv() { + Ok(Ok(checkpoint)) => checkpoints.push(checkpoint), + Ok(Err(err)) => { + error!("remote reader transient error {:?}", err); + self.remote_fetcher_receiver = None; + break; + } + Err(TryRecvError::Disconnected) => { + error!("remote reader channel disconnect error"); + self.remote_fetcher_receiver = None; + break; + } + Err(TryRecvError::Empty) => break, + } + } + checkpoints + } + + async fn sync(&mut self) -> Result<()> { + let backoff = backoff::ExponentialBackoff::default(); + let mut checkpoints = backoff::future::retry(backoff, || async { + self.read_local_files() + .await + .map_err(backoff::Error::transient) + }) + .await?; + + if self.remote_store_url.is_some() + && (checkpoints.is_empty() + || checkpoints[0].checkpoint_summary.sequence_number + > self.current_checkpoint_number) + { + checkpoints = self.remote_fetch(); + } else { + // cancel remote fetcher execution because local reader has made progress + self.remote_fetcher_receiver = None; + } + + info!( + "Local reader. Current checkpoint number: {}, pruning watermark: {}, unprocessed checkpoints: {:?}", + self.current_checkpoint_number, + self.last_pruned_watermark, + checkpoints.len(), + ); + for checkpoint in checkpoints { + assert_eq!( + checkpoint.checkpoint_summary.sequence_number, + self.current_checkpoint_number + ); + if self.exceeds_capacity(checkpoint.checkpoint_summary.sequence_number) { + break; + } + self.checkpoint_sender.send(checkpoint).await?; + self.current_checkpoint_number += 1; + } + Ok(()) + } + + /// Cleans the local directory by removing all processed checkpoint files. + fn gc_processed_files(&mut self, watermark: CheckpointSequenceNumber) -> Result<()> { + info!("cleaning processed files, watermark is {}", watermark); + self.last_pruned_watermark = watermark; + for entry in fs::read_dir(self.path.clone())? { + let entry = entry?; + let filename = entry.file_name(); + if let Some(sequence_number) = Self::checkpoint_number_from_file_path(&filename) { + if sequence_number < watermark { + fs::remove_file(entry.path())?; + } + } + } + Ok(()) + } + + fn checkpoint_number_from_file_path(file_name: &OsString) -> Option { + file_name + .to_str() + .and_then(|s| s.rfind('.').map(|pos| &s[..pos])) + .and_then(|s| s.parse().ok()) + } + + pub fn initialize( + path: PathBuf, + starting_checkpoint_number: CheckpointSequenceNumber, + remote_store_url: Option, + remote_store_options: Vec<(String, String)>, + options: ReaderOptions, + ) -> ( + Self, + mpsc::Receiver, + mpsc::Sender, + oneshot::Sender<()>, + ) { + let (checkpoint_sender, checkpoint_recv) = mpsc::channel(MAX_CHECKPOINTS_IN_PROGRESS); + let (processed_sender, processed_receiver) = mpsc::channel(MAX_CHECKPOINTS_IN_PROGRESS); + let (exit_sender, exit_receiver) = oneshot::channel(); + let reader = Self { + path, + remote_store_url, + remote_store_options, + current_checkpoint_number: starting_checkpoint_number, + last_pruned_watermark: starting_checkpoint_number, + checkpoint_sender, + processed_receiver, + remote_fetcher_receiver: None, + options, + exit_receiver, + }; + (reader, checkpoint_recv, processed_sender, exit_sender) + } + + pub async fn run(mut self) -> Result<()> { + let (inotify_sender, mut inotify_recv) = mpsc::channel(1); + std::fs::create_dir_all(self.path.clone()).expect("failed to create a directory"); + let mut watcher = notify::recommended_watcher(move |res| { + if let Err(err) = res { + eprintln!("watch error: {:?}", err); + } + inotify_sender + .blocking_send(()) + .expect("Failed to send inotify update"); + }) + .expect("Failed to init inotify"); + + watcher + .watch(&self.path, RecursiveMode::NonRecursive) + .expect("Inotify watcher failed"); + + loop { + tokio::select! { + _ = &mut self.exit_receiver => break, + Some(gc_checkpoint_number) = self.processed_receiver.recv() => { + self.gc_processed_files(gc_checkpoint_number).expect("Failed to clean the directory"); + } + Ok(Some(_)) | Err(_) = timeout(Duration::from_millis(self.options.tick_interal_ms), inotify_recv.recv()) => { + self.sync().await.expect("Failed to read checkpoint files"); + } + } + } + Ok(()) + } +} diff --git a/crates/iota-data-ingestion-core/src/tests.rs b/crates/iota-data-ingestion-core/src/tests.rs new file mode 100644 index 00000000000..c8947da8d2c --- /dev/null +++ b/crates/iota-data-ingestion-core/src/tests.rs @@ -0,0 +1,170 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{path::PathBuf, time::Duration}; + +use anyhow::Result; +use async_trait::async_trait; +use iota_storage::blob::{Blob, BlobEncoding}; +use iota_types::{ + crypto::KeypairTraits, + full_checkpoint_content::CheckpointData, + gas::GasCostSummary, + messages_checkpoint::{ + CertifiedCheckpointSummary, CheckpointContents, CheckpointSequenceNumber, + CheckpointSummary, SignedCheckpointSummary, + }, + utils::make_committee_key, +}; +use prometheus::Registry; +use rand::{prelude::StdRng, SeedableRng}; +use tempfile::NamedTempFile; +use tokio::sync::oneshot; + +use crate::{ + progress_store::ExecutorProgress, DataIngestionMetrics, FileProgressStore, IndexerExecutor, + ReaderOptions, Worker, WorkerPool, +}; + +async fn add_worker_pool( + indexer: &mut IndexerExecutor, + worker: W, + concurrency: usize, +) -> Result<()> { + let worker_pool = WorkerPool::new(worker, "test".to_string(), concurrency); + indexer.register(worker_pool).await?; + Ok(()) +} + +async fn run( + indexer: IndexerExecutor, + path: Option, + duration: Option, +) -> Result { + let options = ReaderOptions { + tick_interal_ms: 10, + batch_size: 1, + ..Default::default() + }; + let (sender, recv) = oneshot::channel(); + match duration { + None => { + indexer + .run(path.unwrap_or_else(temp_dir), None, vec![], options, recv) + .await + } + Some(duration) => { + let handle = tokio::task::spawn(async move { + indexer + .run(path.unwrap_or_else(temp_dir), None, vec![], options, recv) + .await + }); + tokio::time::sleep(duration).await; + drop(sender); + handle.await? + } + } +} + +struct ExecutorBundle { + executor: IndexerExecutor, + _progress_file: NamedTempFile, +} + +#[derive(Clone)] +struct TestWorker; + +#[async_trait] +impl Worker for TestWorker { + async fn process_checkpoint(&self, _checkpoint: CheckpointData) -> Result<()> { + Ok(()) + } +} + +#[tokio::test] +async fn empty_pools() { + let bundle = create_executor_bundle(); + let result = run(bundle.executor, None, None).await; + assert!(result.is_err()); + if let Err(err) = result { + assert!(err.to_string().contains("pools can't be empty")); + } +} + +#[tokio::test] +async fn basic_flow() { + let mut bundle = create_executor_bundle(); + add_worker_pool(&mut bundle.executor, TestWorker, 5) + .await + .unwrap(); + let path = temp_dir(); + for checkpoint_number in 0..20 { + let bytes = mock_checkpoint_data_bytes(checkpoint_number); + std::fs::write(path.join(format!("{}.chk", checkpoint_number)), bytes).unwrap(); + } + let result = run(bundle.executor, Some(path), Some(Duration::from_secs(1))).await; + assert!(result.is_ok()); + assert_eq!(result.unwrap().get("test"), Some(&20)); +} + +fn temp_dir() -> std::path::PathBuf { + tempfile::tempdir() + .expect("Failed to open temporary directory") + .into_path() +} + +fn create_executor_bundle() -> ExecutorBundle { + let progress_file = NamedTempFile::new().unwrap(); + let path = progress_file.path().to_path_buf(); + std::fs::write(path.clone(), "{}").unwrap(); + let progress_store = FileProgressStore::new(path); + let executor = IndexerExecutor::new( + progress_store, + 1, + DataIngestionMetrics::new(&Registry::new()), + ); + ExecutorBundle { + executor, + _progress_file: progress_file, + } +} + +const RNG_SEED: [u8; 32] = [ + 21, 23, 199, 200, 234, 250, 252, 178, 94, 15, 202, 178, 62, 186, 88, 137, 233, 192, 130, 157, + 179, 179, 65, 9, 31, 249, 221, 123, 225, 112, 199, 247, +]; + +fn mock_checkpoint_data_bytes(seq_number: CheckpointSequenceNumber) -> Vec { + let mut rng = StdRng::from_seed(RNG_SEED); + let (keys, committee) = make_committee_key(&mut rng); + let contents = CheckpointContents::new_with_digests_only_for_tests(vec![]); + let summary = CheckpointSummary::new( + 0, + seq_number, + 0, + &contents, + None, + GasCostSummary::default(), + None, + 0, + ); + + let sign_infos: Vec<_> = keys + .iter() + .map(|k| { + let name = k.public().into(); + SignedCheckpointSummary::sign(committee.epoch, &summary, k, name) + }) + .collect(); + + let checkpoint_data = CheckpointData { + checkpoint_summary: CertifiedCheckpointSummary::new(summary, sign_infos, &committee) + .unwrap(), + checkpoint_contents: contents, + transactions: vec![], + }; + Blob::encode(&checkpoint_data, BlobEncoding::Bcs) + .unwrap() + .to_bytes() +} diff --git a/crates/iota-data-ingestion-core/src/util.rs b/crates/iota-data-ingestion-core/src/util.rs new file mode 100644 index 00000000000..ca04c78823d --- /dev/null +++ b/crates/iota-data-ingestion-core/src/util.rs @@ -0,0 +1,52 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{str::FromStr, time::Duration}; + +use anyhow::Result; +use object_store::{ + aws::AmazonS3ConfigKey, gcp::GoogleConfigKey, ClientOptions, ObjectStore, RetryConfig, +}; +use url::Url; + +pub fn create_remote_store_client( + url: String, + remote_store_options: Vec<(String, String)>, + timeout_secs: u64, +) -> Result> { + let retry_config = RetryConfig { + max_retries: 0, + retry_timeout: Duration::from_secs(timeout_secs + 1), + ..Default::default() + }; + let client_options = ClientOptions::new().with_timeout(Duration::from_secs(timeout_secs)); + if remote_store_options.is_empty() { + let http_store = object_store::http::HttpBuilder::new() + .with_url(url) + .with_client_options(client_options) + .with_retry(retry_config) + .build()?; + Ok(Box::new(http_store)) + } else if Url::parse(&url)?.scheme() == "gs" { + let url = Url::parse(&url)?; + let mut builder = object_store::gcp::GoogleCloudStorageBuilder::new() + .with_url(url.as_str()) + .with_retry(retry_config) + .with_client_options(client_options); + for (key, value) in remote_store_options { + builder = builder.with_config(GoogleConfigKey::from_str(&key)?, value); + } + Ok(Box::new(builder.build()?)) + } else { + let url = Url::parse(&url)?; + let mut builder = object_store::aws::AmazonS3Builder::new() + .with_url(url.as_str()) + .with_retry(retry_config) + .with_client_options(client_options); + for (key, value) in remote_store_options { + builder = builder.with_config(AmazonS3ConfigKey::from_str(&key)?, value); + } + Ok(Box::new(builder.build()?)) + } +} diff --git a/crates/sui-data-ingestion-core/src/worker_pool.rs b/crates/iota-data-ingestion-core/src/worker_pool.rs similarity index 99% rename from crates/sui-data-ingestion-core/src/worker_pool.rs rename to crates/iota-data-ingestion-core/src/worker_pool.rs index c261fe25631..2d2229b9721 100644 --- a/crates/sui-data-ingestion-core/src/worker_pool.rs +++ b/crates/iota-data-ingestion-core/src/worker_pool.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -7,10 +8,10 @@ use std::{ time::Instant, }; -use mysten_metrics::spawn_monitored_task; -use sui_types::{ +use iota_types::{ full_checkpoint_content::CheckpointData, messages_checkpoint::CheckpointSequenceNumber, }; +use mysten_metrics::spawn_monitored_task; use tokio::sync::{mpsc, oneshot}; use tracing::info; diff --git a/crates/iota-data-ingestion/Cargo.toml b/crates/iota-data-ingestion/Cargo.toml new file mode 100644 index 00000000000..3bbb40b0e5c --- /dev/null +++ b/crates/iota-data-ingestion/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "iota-data-ingestion" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" +version = "0.1.0" + +[dependencies] +anyhow.workspace = true +async-trait.workspace = true +aws-config.workspace = true +aws-sdk-dynamodb.workspace = true +aws-sdk-s3.workspace = true +backoff.workspace = true +base64-url.workspace = true +bcs.workspace = true +byteorder.workspace = true +bytes.workspace = true +futures.workspace = true +mysten-metrics.workspace = true +notify.workspace = true +object_store.workspace = true +serde.workspace = true +serde_json.workspace = true +serde_yaml.workspace = true +prometheus.workspace = true +telemetry-subscribers.workspace = true +tokio = { workspace = true, features = ["full"] } +tracing.workspace = true +iota-archival.workspace = true +iota-storage.workspace = true +iota-data-ingestion-core.workspace = true +iota-types.workspace = true +url.workspace = true + +[dev-dependencies] +rand.workspace = true +tempfile.workspace = true +iota-types = { workspace = true, features = ["test-utils"] } diff --git a/crates/iota-data-ingestion/src/lib.rs b/crates/iota-data-ingestion/src/lib.rs new file mode 100644 index 00000000000..9db53401fcb --- /dev/null +++ b/crates/iota-data-ingestion/src/lib.rs @@ -0,0 +1,11 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod progress_store; +mod workers; + +pub use progress_store::DynamoDBProgressStore; +pub use workers::{ + ArchivalConfig, ArchivalWorker, BlobTaskConfig, BlobWorker, KVStoreTaskConfig, KVStoreWorker, +}; diff --git a/crates/iota-data-ingestion/src/main.rs b/crates/iota-data-ingestion/src/main.rs new file mode 100644 index 00000000000..88f087fcacf --- /dev/null +++ b/crates/iota-data-ingestion/src/main.rs @@ -0,0 +1,159 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{env, path::PathBuf}; + +use anyhow::Result; +use iota_data_ingestion::{ + ArchivalConfig, ArchivalWorker, BlobTaskConfig, BlobWorker, DynamoDBProgressStore, + KVStoreTaskConfig, KVStoreWorker, +}; +use iota_data_ingestion_core::{DataIngestionMetrics, IndexerExecutor, ReaderOptions, WorkerPool}; +use prometheus::Registry; +use serde::{Deserialize, Serialize}; +use tokio::{signal, sync::oneshot}; + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "lowercase")] +enum Task { + Archival(ArchivalConfig), + Blob(BlobTaskConfig), + KV(KVStoreTaskConfig), +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +struct TaskConfig { + #[serde(flatten)] + task: Task, + name: String, + concurrency: usize, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "lowercase")] +struct ProgressStoreConfig { + pub aws_access_key_id: String, + pub aws_secret_access_key: String, + pub aws_region: String, + pub table_name: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +struct IndexerConfig { + path: PathBuf, + tasks: Vec, + progress_store: ProgressStoreConfig, + #[serde(skip_serializing_if = "Option::is_none")] + remote_store_url: Option, + #[serde(skip_serializing_if = "Vec::is_empty", default)] + remote_store_options: Vec<(String, String)>, + #[serde(default = "default_remote_read_batch_size")] + remote_read_batch_size: usize, + #[serde(default = "default_metrics_host")] + metrics_host: String, + #[serde(default = "default_metrics_port")] + metrics_port: u16, +} + +fn default_metrics_host() -> String { + "127.0.0.1".to_string() +} + +fn default_metrics_port() -> u16 { + 8081 +} + +fn default_remote_read_batch_size() -> usize { + 100 +} + +fn setup_env(exit_sender: oneshot::Sender<()>) { + let default_hook = std::panic::take_hook(); + + std::panic::set_hook(Box::new(move |panic| { + default_hook(panic); + std::process::exit(12); + })); + + tokio::spawn(async { + signal::ctrl_c() + .await + .expect("Failed to install Ctrl+C handler"); + exit_sender + .send(()) + .expect("Failed to gracefully process shutdown"); + }); +} + +#[tokio::main] +async fn main() -> Result<()> { + let (exit_sender, exit_receiver) = oneshot::channel(); + setup_env(exit_sender); + + let args: Vec = env::args().collect(); + assert_eq!(args.len(), 2, "configuration yaml file is required"); + let config: IndexerConfig = serde_yaml::from_str(&std::fs::read_to_string(&args[1])?)?; + + // setup metrics + let _guard = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .init(); + let registry_service = mysten_metrics::start_prometheus_server( + format!("{}:{}", config.metrics_host, config.metrics_port).parse()?, + ); + let registry: Registry = registry_service.default_registry(); + mysten_metrics::init_metrics(®istry); + let metrics = DataIngestionMetrics::new(®istry); + + let progress_store = DynamoDBProgressStore::new( + &config.progress_store.aws_access_key_id, + &config.progress_store.aws_secret_access_key, + config.progress_store.aws_region, + config.progress_store.table_name, + ) + .await; + let mut executor = IndexerExecutor::new(progress_store, config.tasks.len(), metrics); + for task_config in config.tasks { + match task_config.task { + Task::Archival(archival_config) => { + let worker_pool = WorkerPool::new( + ArchivalWorker::new(archival_config).await?, + task_config.name, + task_config.concurrency, + ); + executor.register(worker_pool).await?; + } + Task::Blob(blob_config) => { + let worker_pool = WorkerPool::new( + BlobWorker::new(blob_config), + task_config.name, + task_config.concurrency, + ); + executor.register(worker_pool).await?; + } + Task::KV(kv_config) => { + let worker_pool = WorkerPool::new( + KVStoreWorker::new(kv_config).await, + task_config.name, + task_config.concurrency, + ); + executor.register(worker_pool).await?; + } + }; + } + let reader_options = ReaderOptions { + batch_size: config.remote_read_batch_size, + ..Default::default() + }; + executor + .run( + config.path, + config.remote_store_url, + config.remote_store_options, + reader_options, + exit_receiver, + ) + .await?; + Ok(()) +} diff --git a/crates/sui-data-ingestion/src/progress_store.rs b/crates/iota-data-ingestion/src/progress_store.rs similarity index 94% rename from crates/sui-data-ingestion/src/progress_store.rs rename to crates/iota-data-ingestion/src/progress_store.rs index 081af3558c3..d53ecea4af8 100644 --- a/crates/sui-data-ingestion/src/progress_store.rs +++ b/crates/iota-data-ingestion/src/progress_store.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{str::FromStr, time::Duration}; @@ -8,8 +9,8 @@ use async_trait::async_trait; use aws_config::timeout::TimeoutConfig; use aws_sdk_dynamodb::{types::AttributeValue, Client}; use aws_sdk_s3::config::{Credentials, Region}; -use sui_data_ingestion_core::ProgressStore; -use sui_types::messages_checkpoint::CheckpointSequenceNumber; +use iota_data_ingestion_core::ProgressStore; +use iota_types::messages_checkpoint::CheckpointSequenceNumber; pub struct DynamoDBProgressStore { client: Client, diff --git a/crates/sui-data-ingestion/src/workers/archival.rs b/crates/iota-data-ingestion/src/workers/archival.rs similarity index 97% rename from crates/sui-data-ingestion/src/workers/archival.rs rename to crates/iota-data-ingestion/src/workers/archival.rs index 9363635b276..ae1db5def99 100644 --- a/crates/sui-data-ingestion/src/workers/archival.rs +++ b/crates/iota-data-ingestion/src/workers/archival.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -11,22 +12,22 @@ use anyhow::Result; use async_trait::async_trait; use byteorder::{BigEndian, ByteOrder}; use bytes::Bytes; -use object_store::{path::Path, ObjectStore}; -use serde::{Deserialize, Serialize}; -use sui_archival::{ +use iota_archival::{ create_file_metadata_from_bytes, finalize_manifest, read_manifest_from_bytes, FileType, Manifest, CHECKPOINT_FILE_MAGIC, SUMMARY_FILE_MAGIC, }; -use sui_data_ingestion_core::{create_remote_store_client, Worker, MAX_CHECKPOINTS_IN_PROGRESS}; -use sui_storage::{ +use iota_data_ingestion_core::{create_remote_store_client, Worker, MAX_CHECKPOINTS_IN_PROGRESS}; +use iota_storage::{ blob::{Blob, BlobEncoding}, compress, FileCompression, StorageFormat, }; -use sui_types::{ +use iota_types::{ base_types::{EpochId, ExecutionData}, full_checkpoint_content::CheckpointData, messages_checkpoint::{CheckpointSequenceNumber, FullCheckpointContents}, }; +use object_store::{path::Path, ObjectStore}; +use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; #[derive(Serialize, Deserialize, Clone, Debug)] diff --git a/crates/iota-data-ingestion/src/workers/blob.rs b/crates/iota-data-ingestion/src/workers/blob.rs new file mode 100644 index 00000000000..b7ddee2a9ce --- /dev/null +++ b/crates/iota-data-ingestion/src/workers/blob.rs @@ -0,0 +1,44 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::Result; +use async_trait::async_trait; +use bytes::Bytes; +use iota_data_ingestion_core::{create_remote_store_client, Worker}; +use iota_storage::blob::{Blob, BlobEncoding}; +use iota_types::full_checkpoint_content::CheckpointData; +use object_store::{path::Path, ObjectStore}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct BlobTaskConfig { + pub url: String, + pub remote_store_options: Vec<(String, String)>, +} + +pub struct BlobWorker { + remote_store: Box, +} + +impl BlobWorker { + pub fn new(config: BlobTaskConfig) -> Self { + Self { + remote_store: create_remote_store_client(config.url, config.remote_store_options, 10) + .expect("failed to create remote store client"), + } + } +} + +#[async_trait] +impl Worker for BlobWorker { + async fn process_checkpoint(&self, checkpoint: CheckpointData) -> Result<()> { + let bytes = Blob::encode(&checkpoint, BlobEncoding::Bcs)?.to_bytes(); + let location = Path::from(format!( + "{}.chk", + checkpoint.checkpoint_summary.sequence_number + )); + self.remote_store.put(&location, Bytes::from(bytes)).await?; + Ok(()) + } +} diff --git a/crates/sui-data-ingestion/src/workers/kv_store.rs b/crates/iota-data-ingestion/src/workers/kv_store.rs similarity index 97% rename from crates/sui-data-ingestion/src/workers/kv_store.rs rename to crates/iota-data-ingestion/src/workers/kv_store.rs index 2e9d67e4330..4c923e5056e 100644 --- a/crates/sui-data-ingestion/src/workers/kv_store.rs +++ b/crates/iota-data-ingestion/src/workers/kv_store.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -19,10 +20,10 @@ use aws_sdk_dynamodb::{ use aws_sdk_s3 as s3; use aws_sdk_s3::config::{Credentials, Region}; use backoff::{backoff::Backoff, ExponentialBackoff}; +use iota_data_ingestion_core::Worker; +use iota_storage::http_key_value_store::TaggedKey; +use iota_types::{full_checkpoint_content::CheckpointData, storage::ObjectKey}; use serde::{Deserialize, Serialize}; -use sui_data_ingestion_core::Worker; -use sui_storage::http_key_value_store::TaggedKey; -use sui_types::{full_checkpoint_content::CheckpointData, storage::ObjectKey}; const TIMEOUT: Duration = Duration::from_secs(60); diff --git a/crates/iota-data-ingestion/src/workers/mod.rs b/crates/iota-data-ingestion/src/workers/mod.rs new file mode 100644 index 00000000000..70b1851eb80 --- /dev/null +++ b/crates/iota-data-ingestion/src/workers/mod.rs @@ -0,0 +1,10 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod archival; +mod blob; +mod kv_store; +pub use archival::{ArchivalConfig, ArchivalWorker}; +pub use blob::{BlobTaskConfig, BlobWorker}; +pub use kv_store::{KVStoreTaskConfig, KVStoreWorker}; diff --git a/crates/iota-e2e-tests/Cargo.toml b/crates/iota-e2e-tests/Cargo.toml new file mode 100644 index 00000000000..64258425fe3 --- /dev/null +++ b/crates/iota-e2e-tests/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "iota-e2e-tests" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" +version = "0.1.0" + +[dependencies] + +[dev-dependencies] +tempfile.workspace = true +futures.workspace = true +prometheus.workspace = true +fs_extra.workspace = true +indexmap.workspace = true +insta.workspace = true +jsonrpsee.workspace = true +test-cluster.workspace = true +rand.workspace = true +expect-test.workspace = true +tokio.workspace = true +tracing.workspace = true +assert_cmd.workspace = true +serde.workspace = true +bcs.workspace = true +anyhow.workspace = true +async-trait.workspace = true +clap.workspace = true +serde_json.workspace = true + +move-binary-format.workspace = true +move-package.workspace = true +telemetry-subscribers.workspace = true +fastcrypto.workspace = true +fastcrypto-zkp.workspace = true +move-core-types.workspace = true + +iota-core.workspace = true +iota-framework.workspace = true +iota-json-rpc.workspace = true +iota-json-rpc-api.workspace = true +iota-node.workspace = true +iota-macros.workspace = true +iota-simulator.workspace = true +iota-storage.workspace = true +mysten-metrics.workspace = true +iota-tool.workspace = true +iota-protocol-config.workspace = true +iota-types.workspace = true +iota-move-build.workspace = true +iota-swarm-config.workspace = true +iota-swarm.workspace = true +iota-test-transaction-builder.workspace = true +iota-config.workspace = true +iota-json-rpc-types.workspace = true +iota.workspace = true +iota-sdk.workspace = true +iota-keys.workspace = true +shared-crypto.workspace = true diff --git a/crates/sui-e2e-tests/tests/checkpoint_tests.rs b/crates/iota-e2e-tests/tests/checkpoint_tests.rs similarity index 85% rename from crates/sui-e2e-tests/tests/checkpoint_tests.rs rename to crates/iota-e2e-tests/tests/checkpoint_tests.rs index 3a2019ab022..f8ba9f11b33 100644 --- a/crates/sui-e2e-tests/tests/checkpoint_tests.rs +++ b/crates/iota-e2e-tests/tests/checkpoint_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -9,14 +10,14 @@ use std::{ time::Duration, }; -use sui_macros::{register_fail_point, register_fail_point_if, sim_test}; -use sui_test_transaction_builder::make_transfer_sui_transaction; +use iota_macros::{register_fail_point, register_fail_point_if, sim_test}; +use iota_test_transaction_builder::make_transfer_iota_transaction; use test_cluster::TestClusterBuilder; #[sim_test] async fn basic_checkpoints_integration_test() { let test_cluster = TestClusterBuilder::new().build().await; - let tx = make_transfer_sui_transaction(&test_cluster.wallet, None, None).await; + let tx = make_transfer_iota_transaction(&test_cluster.wallet, None, None).await; let digest = *tx.digest(); test_cluster.execute_transaction(tx).await; @@ -61,7 +62,7 @@ async fn checkpoint_split_brain_test() { .build() .await; - let tx = make_transfer_sui_transaction(&test_cluster.wallet, None, None).await; + let tx = make_transfer_iota_transaction(&test_cluster.wallet, None, None).await; test_cluster .wallet .execute_transaction_may_fail(tx) diff --git a/crates/sui-e2e-tests/tests/coin_deny_list_tests.rs b/crates/iota-e2e-tests/tests/coin_deny_list_tests.rs similarity index 88% rename from crates/sui-e2e-tests/tests/coin_deny_list_tests.rs rename to crates/iota-e2e-tests/tests/coin_deny_list_tests.rs index 4adc60c5e7b..e6f8c0caa8b 100644 --- a/crates/sui-e2e-tests/tests/coin_deny_list_tests.rs +++ b/crates/iota-e2e-tests/tests/coin_deny_list_tests.rs @@ -1,22 +1,23 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::PathBuf; -use sui_core::authority::epoch_start_configuration::EpochStartConfigTrait; -use sui_json_rpc_types::{ - SuiTransactionBlockDataAPI, SuiTransactionBlockEffectsAPI, SuiTransactionBlockKind, - SuiTransactionBlockResponseOptions, +use iota_core::authority::epoch_start_configuration::EpochStartConfigTrait; +use iota_json_rpc_types::{ + IotaTransactionBlockDataAPI, IotaTransactionBlockEffectsAPI, IotaTransactionBlockKind, + IotaTransactionBlockResponseOptions, }; -use sui_macros::sim_test; -use sui_types::{ +use iota_macros::sim_test; +use iota_types::{ deny_list::{ get_coin_deny_list, get_deny_list_obj_initial_shared_version, get_deny_list_root_object, CoinDenyCap, DenyList, RegulatedCoinMetadata, }, id::UID, storage::ObjectStore, - SUI_DENY_LIST_OBJECT_ID, + IOTA_DENY_LIST_OBJECT_ID, }; use test_cluster::TestClusterBuilder; @@ -64,7 +65,7 @@ async fn test_coin_deny_list_creation() { assert_eq!(deny_list_object.version(), version); assert!(deny_list_object.owner.is_shared()); let deny_list: DenyList = deny_list_object.to_rust().unwrap(); - assert_eq!(deny_list.id, UID::new(SUI_DENY_LIST_OBJECT_ID)); + assert_eq!(deny_list.id, UID::new(IOTA_DENY_LIST_OBJECT_ID)); assert_eq!(deny_list.lists.size, 1); if let Some(prev_tx) = prev_tx { @@ -82,16 +83,16 @@ async fn test_coin_deny_list_creation() { let prev_tx = prev_tx.unwrap(); let tx = test_cluster .fullnode_handle - .sui_client + .iota_client .read_api() - .get_transaction_with_options(prev_tx, SuiTransactionBlockResponseOptions::full_content()) + .get_transaction_with_options(prev_tx, IotaTransactionBlockResponseOptions::full_content()) .await .unwrap() .transaction .unwrap(); assert!(matches!( tx.data.transaction(), - SuiTransactionBlockKind::EndOfEpochTransaction(_) + IotaTransactionBlockKind::EndOfEpochTransaction(_) )); test_cluster.wait_for_epoch_all_nodes(3).await; // Check that we are not re-creating the same object again. @@ -100,7 +101,7 @@ async fn test_coin_deny_list_creation() { assert_eq!( node.state() .get_object_store() - .get_object(&SUI_DENY_LIST_OBJECT_ID) + .get_object(&IOTA_DENY_LIST_OBJECT_ID) .unwrap() .unwrap() .previous_transaction, diff --git a/crates/sui-e2e-tests/tests/dynamic_committee_tests.rs b/crates/iota-e2e-tests/tests/dynamic_committee_tests.rs similarity index 80% rename from crates/sui-e2e-tests/tests/dynamic_committee_tests.rs rename to crates/iota-e2e-tests/tests/dynamic_committee_tests.rs index 28c77231347..559a3e41ad1 100644 --- a/crates/sui-e2e-tests/tests/dynamic_committee_tests.rs +++ b/crates/iota-e2e-tests/tests/dynamic_committee_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -8,25 +9,25 @@ use std::{ use anyhow::Result; use async_trait::async_trait; -use move_core_types::ident_str; -use rand::{rngs::StdRng, Rng, SeedableRng}; -use sui_core::authority::AuthorityState; -use sui_macros::*; -use sui_swarm_config::genesis_config::{AccountConfig, DEFAULT_GAS_AMOUNT}; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, +use iota_core::authority::AuthorityState; +use iota_macros::*; +use iota_swarm_config::genesis_config::{AccountConfig, DEFAULT_GAS_AMOUNT}; +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef}, effects::{TransactionEffects, TransactionEffectsAPI}, + iota_system_state::{ + iota_system_state_summary::{IotaSystemStateSummary, IotaValidatorSummary}, + IotaSystemStateTrait, + }, object::{Object, Owner}, programmable_transaction_builder::ProgrammableTransactionBuilder, storage::ObjectStore, - sui_system_state::{ - sui_system_state_summary::{SuiSystemStateSummary, SuiValidatorSummary}, - SuiSystemStateTrait, - }, transaction::{Argument, Command, ObjectArg, ProgrammableTransaction}, - SUI_SYSTEM_PACKAGE_ID, + IOTA_SYSTEM_PACKAGE_ID, }; +use move_core_types::ident_str; +use rand::{rngs::StdRng, Rng, SeedableRng}; use test_cluster::{TestCluster, TestClusterBuilder}; use tracing::info; @@ -69,14 +70,14 @@ trait StatePredicate { struct StressTestRunner { pub post_epoch_predicates: Vec>, pub test_cluster: TestCluster, - pub accounts: Vec, - pub active_validators: BTreeSet, - pub preactive_validators: BTreeMap, - pub removed_validators: BTreeSet, - pub delegation_requests_this_epoch: BTreeMap, + pub accounts: Vec, + pub active_validators: BTreeSet, + pub preactive_validators: BTreeMap, + pub removed_validators: BTreeSet, + pub delegation_requests_this_epoch: BTreeMap, pub delegation_withdraws_this_epoch: u64, - pub delegations: BTreeMap, - pub reports: BTreeMap>, + pub delegations: BTreeMap, + pub reports: BTreeMap>, pub rng: StdRng, } @@ -108,18 +109,18 @@ impl StressTestRunner { } } - pub fn pick_random_sender(&mut self) -> SuiAddress { + pub fn pick_random_sender(&mut self) -> IotaAddress { self.accounts[self.rng.gen_range(0..self.accounts.len())] } - pub fn system_state(&self) -> SuiSystemStateSummary { + pub fn system_state(&self) -> IotaSystemStateSummary { self.state() - .get_sui_system_state_object_for_testing() + .get_iota_system_state_object_for_testing() .unwrap() - .into_sui_system_state_summary() + .into_iota_system_state_summary() } - pub fn pick_random_active_validator(&mut self) -> SuiValidatorSummary { + pub fn pick_random_active_validator(&mut self) -> IotaValidatorSummary { let system_state = self.system_state(); system_state .active_validators @@ -128,7 +129,11 @@ impl StressTestRunner { .clone() } - pub async fn run(&self, sender: SuiAddress, pt: ProgrammableTransaction) -> TransactionEffects { + pub async fn run( + &self, + sender: IotaAddress, + pt: ProgrammableTransaction, + ) -> TransactionEffects { let rgp = self.test_cluster.get_reference_gas_price().await; let gas_object = self .test_cluster @@ -169,9 +174,9 @@ impl StressTestRunner { .unwrap(); let Some(object) = object_opt else { continue }; let struct_tag = object.struct_tag().unwrap(); - let total_sui = - object.get_total_sui(layout_resolver.as_mut()).unwrap() - object.storage_rebate; - println!(">> {struct_tag} TOTAL_SUI: {total_sui}"); + let total_iota = + object.get_total_iota(layout_resolver.as_mut()).unwrap() - object.storage_rebate; + println!(">> {struct_tag} TOTAL_IOTA: {total_iota}"); } println!("MUTATED:"); @@ -182,9 +187,9 @@ impl StressTestRunner { .unwrap() .unwrap(); let struct_tag = object.struct_tag().unwrap(); - let total_sui = - object.get_total_sui(layout_resolver.as_mut()).unwrap() - object.storage_rebate; - println!(">> {struct_tag} TOTAL_SUI: {total_sui}"); + let total_iota = + object.get_total_iota(layout_resolver.as_mut()).unwrap() - object.storage_rebate; + println!(">> {struct_tag} TOTAL_IOTA: {total_iota}"); } println!("SHARED:"); @@ -196,9 +201,9 @@ impl StressTestRunner { .unwrap() .unwrap(); let struct_tag = object.struct_tag().unwrap(); - let total_sui = - object.get_total_sui(layout_resolver.as_mut()).unwrap() - object.storage_rebate; - println!(">> {struct_tag} TOTAL_SUI: {total_sui}"); + let total_iota = + object.get_total_iota(layout_resolver.as_mut()).unwrap() - object.storage_rebate; + println!(">> {struct_tag} TOTAL_IOTA: {total_iota}"); } } @@ -207,7 +212,7 @@ impl StressTestRunner { // } pub fn state(&self) -> Arc { - self.test_cluster.fullnode_handle.sui_node.state() + self.test_cluster.fullnode_handle.iota_node.state() } pub async fn change_epoch(&self) { @@ -265,16 +270,16 @@ impl StressTestRunner { } mod add_stake { - use sui_types::effects::TransactionEffects; + use iota_types::effects::TransactionEffects; use super::*; pub struct RequestAddStakeGen; pub struct RequestAddStake { - sender: SuiAddress, + sender: IotaAddress, stake_amount: u64, - staked_with: SuiAddress, + staked_with: IotaAddress, } impl GenStateChange for RequestAddStakeGen { @@ -284,7 +289,7 @@ mod add_stake { let stake_amount = runner .rng .gen_range(MIN_DELEGATION_AMOUNT..=MAX_DELEGATION_AMOUNT); - let staked_with = runner.pick_random_active_validator().sui_address; + let staked_with = runner.pick_random_active_validator().iota_address; let sender = runner.pick_random_sender(); RequestAddStake { sender, @@ -299,12 +304,12 @@ mod add_stake { async fn run(&mut self, runner: &mut StressTestRunner) -> Result { let pt = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap(); + builder.obj(ObjectArg::IOTA_SYSTEM_MUT).unwrap(); builder.pure(self.staked_with).unwrap(); let coin = StressTestRunner::split_off(&mut builder, self.stake_amount); move_call! { builder, - (SUI_SYSTEM_PACKAGE_ID)::sui_system::request_add_stake(Argument::Input(0), coin, Argument::Input(1)) + (IOTA_SYSTEM_PACKAGE_ID)::iota_system::request_add_stake(Argument::Input(0), coin, Argument::Input(1)) }; builder.finish() }; @@ -318,10 +323,10 @@ mod add_stake { runner: &StressTestRunner, effects: &TransactionEffects, ) { - // Assert that a `StakedSui` object matching the amount delegated is created. - // Assert that this staked sui + // Assert that a `StakedIota` object matching the amount delegated is created. + // Assert that this staked iota let object = runner - .get_created_object_of_type_name(effects, "StakedSui") + .get_created_object_of_type_name(effects, "StakedIota") .await .unwrap(); let state = runner.state(); @@ -331,7 +336,7 @@ mod add_stake { .executor() .type_layout_resolver(Box::new(cache.as_ref())); let staked_amount = - object.get_total_sui(layout_resolver.as_mut()).unwrap() - object.storage_rebate; + object.get_total_iota(layout_resolver.as_mut()).unwrap() - object.storage_rebate; assert_eq!(staked_amount, self.stake_amount); assert_eq!(object.owner.get_owner_address().unwrap(), self.sender); runner.display_effects(effects); diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/add_key_ability/Move.toml b/crates/iota-e2e-tests/tests/framework_upgrades/add_key_ability/Move.toml new file mode 100644 index 00000000000..7df86b5d157 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/add_key_ability/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "IotaExtraAddKeyAbility" +version = "0.0.1" + +[dependencies] +IotaSystem = { local = "../../../../iota-framework/packages/iota-system" } +Iota = { local = "../../../../iota-framework/packages/iota-framework" } +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +iota_system = "0x3" diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/add_key_ability/sources/modules.move b/crates/iota-e2e-tests/tests/framework_upgrades/add_key_ability/sources/modules.move new file mode 100644 index 00000000000..a35aa69a821 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/add_key_ability/sources/modules.move @@ -0,0 +1,37 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::msim_extra_1 { + use iota::object::UID; + use iota::tx_context::TxContext; + + struct Type has drop { + x: u64, + } + + struct Obj has key { + id: UID, + } + + struct AlmostObj has key { + id: UID, + } + + public fun canary(): u64 { + private_function(42) + } + + entry fun mint(_ctx: &mut TxContext) {} + + entry fun entry_fun() {} + + fun private_function(x: u64): u64 { + private_function_2(x) + 1 + } + + fun private_function_2(x: u64): u64 { x } + fun private_function_3(_x: u64) {} + + public fun generic(_t: T) {} +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/add_struct_ability/Move.toml b/crates/iota-e2e-tests/tests/framework_upgrades/add_struct_ability/Move.toml new file mode 100644 index 00000000000..6ad93d793a7 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/add_struct_ability/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "IotaExtraAddStructAbility" +version = "0.0.1" + +[dependencies] +IotaSystem = { local = "../../../../iota-framework/packages/iota-system" } +Iota = { local = "../../../../iota-framework/packages/iota-framework" } +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +iota_system = "0x3" diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/add_struct_ability/sources/modules.move b/crates/iota-e2e-tests/tests/framework_upgrades/add_struct_ability/sources/modules.move new file mode 100644 index 00000000000..8f431389316 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/add_struct_ability/sources/modules.move @@ -0,0 +1,55 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::msim_extra_1 { + use iota::object::{Self, UID}; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; + + struct Type has drop, copy { + x: u64, + } + + struct Obj has key, store { + id: UID, + } + + struct AlmostObj { + id: UID, + } + + struct Wrapper has key { + id: UID, + obj: Obj, + } + + public fun canary(): u64 { + private_function(42) + } + + entry fun mint(ctx: &mut TxContext) { + transfer::transfer( + Obj { id: object::new(ctx) }, + tx_context::sender(ctx), + ) + } + + entry fun wrap(obj: Obj, ctx: &mut TxContext) { + transfer::transfer( + Wrapper { id: object::new(ctx), obj }, + tx_context::sender(ctx), + ) + } + + entry fun entry_fun() {} + + fun private_function(x: u64): u64 { + private_function_2(x) + 1 + } + + fun private_function_2(x: u64): u64 { x } + fun private_function_3(_x: u64) {} + + public fun generic(_t: T) {} +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/base/Move.toml b/crates/iota-e2e-tests/tests/framework_upgrades/base/Move.toml new file mode 100644 index 00000000000..103af02a1c3 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/base/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "IotaExtraBase" +version = "0.0.1" + +[dependencies] +IotaSystem = { local = "../../../../iota-framework/packages/iota-system" } +Iota = { local = "../../../../iota-framework/packages/iota-framework" } +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +iota_system = "0x3" diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/base/sources/modules.move b/crates/iota-e2e-tests/tests/framework_upgrades/base/sources/modules.move new file mode 100644 index 00000000000..1460030187b --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/base/sources/modules.move @@ -0,0 +1,43 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::msim_extra_1 { + use iota::object::{Self, UID}; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; + + struct Type has drop { + x: u64, + } + + struct Obj has key { + id: UID, + } + + struct AlmostObj { + id: UID, + } + + public fun canary(): u64 { + private_function(41) + } + + entry fun mint(ctx: &mut TxContext) { + transfer::transfer( + Obj { id: object::new(ctx) }, + tx_context::sender(ctx), + ) + } + + entry fun entry_fun() {} + + fun private_function(x: u64): u64 { + private_function_2(x) + 1 + } + + fun private_function_2(x: u64): u64 { x } + fun private_function_3(_x: u64) {} + + public fun generic(_t: T) {} +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/change_entry_function_signature/Move.toml b/crates/iota-e2e-tests/tests/framework_upgrades/change_entry_function_signature/Move.toml new file mode 100644 index 00000000000..c0d7211dfe9 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/change_entry_function_signature/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "IotaExtraChangeEntryFunctionSignature" +version = "0.0.1" + +[dependencies] +IotaSystem = { local = "../../../../iota-framework/packages/iota-system" } +Iota = { local = "../../../../iota-framework/packages/iota-framework" } +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +iota_system = "0x3" diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/change_entry_function_signature/sources/modules.move b/crates/iota-e2e-tests/tests/framework_upgrades/change_entry_function_signature/sources/modules.move new file mode 100644 index 00000000000..054ade2e5b3 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/change_entry_function_signature/sources/modules.move @@ -0,0 +1,37 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::msim_extra_1 { + use iota::object::UID; + use iota::tx_context::TxContext; + + struct Type has drop { + x: u64, + } + + struct Obj has key { + id: UID, + } + + struct AlmostObj { + id: UID, + } + + public fun canary(): u64 { + private_function(47) + } + + entry fun mint(_ctx: &mut TxContext) {} + + entry fun entry_fun(_x: u64) {} + + fun private_function(x: u64): u64 { + private_function_2(x) + 1 + } + + fun private_function_2(x: u64): u64 { x } + fun private_function_3(_x: u64) {} + + public fun generic(_t: T) {} +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/change_public_function_signature/Move.toml b/crates/iota-e2e-tests/tests/framework_upgrades/change_public_function_signature/Move.toml new file mode 100644 index 00000000000..7a472a3034b --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/change_public_function_signature/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "IotaExtraChangePublicFunctionSignature" +version = "0.0.1" + +[dependencies] +IotaSystem = { local = "../../../../iota-framework/packages/iota-system" } +Iota = { local = "../../../../iota-framework/packages/iota-framework" } +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +iota_system = "0x3" diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/change_public_function_signature/sources/modules.move b/crates/iota-e2e-tests/tests/framework_upgrades/change_public_function_signature/sources/modules.move new file mode 100644 index 00000000000..8367844a96a --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/change_public_function_signature/sources/modules.move @@ -0,0 +1,37 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::msim_extra_1 { + use iota::object::UID; + use iota::tx_context::TxContext; + + struct Type has drop { + x: u64, + } + + struct Obj has key { + id: UID, + } + + struct AlmostObj { + id: UID, + } + + public fun canary(): u64 { + private_function(46) + } + + entry fun mint(_ctx: &mut TxContext) {} + + entry fun entry_fun() {} + + fun private_function(x: u64): u64 { + x + 1 + } + + fun private_function_2(x: u64): u64 { x } + fun private_function_3(_x: u64) {} + + public fun generic(_t: T, _x: u64) {} +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/change_struct_ability/Move.toml b/crates/iota-e2e-tests/tests/framework_upgrades/change_struct_ability/Move.toml new file mode 100644 index 00000000000..d1e42cf41fa --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/change_struct_ability/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "IotaExtraChangeStructAbility" +version = "0.0.1" + +[dependencies] +IotaSystem = { local = "../../../../iota-framework/packages/iota-system" } +Iota = { local = "../../../../iota-framework/packages/iota-framework" } +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +iota_system = "0x3" diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/change_struct_ability/sources/modules.move b/crates/iota-e2e-tests/tests/framework_upgrades/change_struct_ability/sources/modules.move new file mode 100644 index 00000000000..2a6acd4b8d7 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/change_struct_ability/sources/modules.move @@ -0,0 +1,37 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::msim_extra_1 { + use iota::object::UID; + use iota::tx_context::TxContext; + + struct Type { + x: u64, + } + + struct Obj has key { + id: UID, + } + + struct AlmostObj { + id: UID, + } + + public fun canary(): u64 { + private_function(44) + } + + entry fun mint(_ctx: &mut TxContext) {} + + entry fun entry_fun() {} + + fun private_function(x: u64): u64 { + x + 1 + } + + fun private_function_2(x: u64): u64 { x } + fun private_function_3(_x: u64) {} + + public fun generic(_t: T) {} +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/change_struct_layout/Move.toml b/crates/iota-e2e-tests/tests/framework_upgrades/change_struct_layout/Move.toml new file mode 100644 index 00000000000..6610889c37d --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/change_struct_layout/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "IotaExtraChangeStructLayout" +version = "0.0.1" + +[dependencies] +IotaSystem = { local = "../../../../iota-framework/packages/iota-system" } +Iota = { local = "../../../../iota-framework/packages/iota-framework" } +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +iota_system = "0x3" diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/change_struct_layout/sources/modules.move b/crates/iota-e2e-tests/tests/framework_upgrades/change_struct_layout/sources/modules.move new file mode 100644 index 00000000000..8dcd1a350d9 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/change_struct_layout/sources/modules.move @@ -0,0 +1,38 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::msim_extra_1 { + use iota::object::UID; + use iota::tx_context::TxContext; + + struct Type has drop { + x: u64, + y: u64, + } + + struct Obj has key { + id: UID, + } + + struct AlmostObj { + id: UID, + } + + public fun canary(): u64 { + private_function(43) + } + + entry fun mint(_ctx: &mut TxContext) {} + + entry fun entry_fun() {} + + fun private_function(x: u64): u64 { + x + 1 + } + + fun private_function_2(x: u64): u64 { x } + fun private_function_3(_x: u64) {} + + public fun generic(_t: T) {} +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/change_type_constraint/Move.toml b/crates/iota-e2e-tests/tests/framework_upgrades/change_type_constraint/Move.toml new file mode 100644 index 00000000000..1d88893f9df --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/change_type_constraint/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "IotaExtraChangeTypeConstraint" +version = "0.0.1" + +[dependencies] +IotaSystem = { local = "../../../../iota-framework/packages/iota-system" } +Iota = { local = "../../../../iota-framework/packages/iota-framework" } +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +iota_system = "0x3" diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/change_type_constraint/sources/modules.move b/crates/iota-e2e-tests/tests/framework_upgrades/change_type_constraint/sources/modules.move new file mode 100644 index 00000000000..c627fb09754 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/change_type_constraint/sources/modules.move @@ -0,0 +1,37 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::msim_extra_1 { + use iota::object::UID; + use iota::tx_context::TxContext; + + struct Type has drop { + x: u64, + } + + struct Obj has key { + id: UID, + } + + struct AlmostObj { + id: UID, + } + + public fun canary(): u64 { + private_function(45) + } + + entry fun mint(_ctx: &mut TxContext) {} + + entry fun entry_fun() {} + + fun private_function(x: u64): u64 { + x + 1 + } + + fun private_function_2(x: u64): u64 { x } + fun private_function_3(_x: u64) {} + + public fun generic(_t: T) {} +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/compatible/Move.toml b/crates/iota-e2e-tests/tests/framework_upgrades/compatible/Move.toml new file mode 100644 index 00000000000..612ec72891f --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/compatible/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "IotaExtraCompatible" +version = "0.0.1" + +[dependencies] +IotaSystem = { local = "../../../../iota-framework/packages/iota-system" } +Iota = { local = "../../../../iota-framework/packages/iota-framework" } +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +iota_system = "0x3" diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/compatible/sources/modules.move b/crates/iota-e2e-tests/tests/framework_upgrades/compatible/sources/modules.move new file mode 100644 index 00000000000..d446afdd02d --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/compatible/sources/modules.move @@ -0,0 +1,51 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::msim_extra_1 { + use iota::object::UID; + use iota::tx_context::TxContext; + + struct Type has drop { + x: u64 + } + + struct Obj has key { + id: UID, + } + + struct AlmostObj { + id: UID, + } + + struct NewType { + t: Type, + } + + public fun canary(): u64 { + private_function(20, 21) + } + + entry fun mint(_ctx: &mut TxContext) {} + + public entry fun entry_fun() {} + + /// Bit of a confusing function name, but we're testing that a + /// once private function can be made public. + public fun private_function(x: u64, y: u64): u64 { + x + y + 2 + } + + // Removing this function + // fun private_function_2(x: u64): u64 { x } + + entry fun private_function_3(_x: u64) {} + + public fun generic(_t: T) {} +} + +module iota_system::msim_extra_2 { + public fun bar(): u64 { + 43 + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/extra_package/Move.toml b/crates/iota-e2e-tests/tests/framework_upgrades/extra_package/Move.toml new file mode 100644 index 00000000000..f1ec6f076c8 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/extra_package/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "IotaExtra" +version = "0.0.1" + +[dependencies] +IotaSystem = { local = "../../../../iota-framework/packages/iota-system" } +Iota = { local = "../../../../iota-framework/packages/iota-framework" } +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +iota_extra = "0x42" diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/extra_package/sources/modules.move b/crates/iota-e2e-tests/tests/framework_upgrades/extra_package/sources/modules.move new file mode 100644 index 00000000000..448b5faad2f --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/extra_package/sources/modules.move @@ -0,0 +1,21 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_extra::msim_extra_1 { + use iota::object::{Self, UID}; + use iota::transfer; + use iota::tx_context::TxContext; + + struct S has key { id: UID } + + fun init(ctx: &mut TxContext) { + transfer::share_object(S { + id: object::new(ctx) + }) + } + + public fun canary(): u64 { + 43 + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/Move.toml b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/Move.toml new file mode 100644 index 00000000000..59fa29734b6 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "MockIotaSystemBase" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } +MoveStdlib = { local = "../../../../../iota-framework/packages/move-stdlib" } + +[addresses] +iota_system = "0x3" diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/README.txt b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/README.txt new file mode 100644 index 00000000000..c40cfc5d190 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/README.txt @@ -0,0 +1,9 @@ +This directory contains a mock version of the 0x3 package (iota-system). +The idea is to introduce a minimum version of the iota-system that we can use to start Iota. +We can then use this mock version as the base package to test various things such as iota system state upgrades. +This allows us to decouple from the complicated code in the original iota-system under iota-framework. +We only need to update code here and in other mock versions when the core protocol changes. This includes: +1. The genesis creation function interface +2. advance_epoch and advance_epoch_safe_mode interface +3. Any new system function call to the iota-system package required by protocol. +4. Any new information needed at epoch start. diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/genesis.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/genesis.move new file mode 100644 index 00000000000..4ab5441074a --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/genesis.move @@ -0,0 +1,127 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::genesis { + use std::vector; + use iota::balance::{Self, Balance}; + use iota::object::UID; + use iota::iota::IOTA; + use iota::tx_context::{Self, TxContext}; + use std::option::Option; + + use iota_system::iota_system; + use iota_system::validator; + + struct GenesisValidatorMetadata has drop, copy { + name: vector, + description: vector, + image_url: vector, + project_url: vector, + + iota_address: address, + + gas_price: u64, + commission_rate: u64, + + protocol_public_key: vector, + proof_of_possession: vector, + + network_public_key: vector, + worker_public_key: vector, + + network_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + } + + struct GenesisChainParameters has drop, copy { + protocol_version: u64, + chain_start_timestamp_ms: u64, + epoch_duration_ms: u64, + + stake_subsidy_start_epoch: u64, + stake_subsidy_initial_distribution_amount: u64, + stake_subsidy_period_length: u64, + stake_subsidy_decrease_rate: u16, + + max_validator_count: u64, + min_validator_joining_stake: u64, + validator_low_stake_threshold: u64, + validator_very_low_stake_threshold: u64, + validator_low_stake_grace_period: u64, + } + + struct TokenDistributionSchedule has drop { + stake_subsidy_fund_micros: u64, + allocations: vector, + } + + struct TokenAllocation has drop { + recipient_address: address, + amount_micros: u64, + staked_with_validator: Option

    , + } + + fun create( + iota_system_state_id: UID, + iota_supply: Balance, + genesis_chain_parameters: GenesisChainParameters, + genesis_validators: vector, + _token_distribution_schedule: TokenDistributionSchedule, + ctx: &mut TxContext, + ) { + assert!(tx_context::epoch(ctx) == 0, 0); + + let validators = vector::empty(); + let count = vector::length(&genesis_validators); + let i = 0; + while (i < count) { + let GenesisValidatorMetadata { + name: _, + description: _, + image_url: _, + project_url: _, + iota_address, + gas_price: _, + commission_rate: _, + protocol_public_key, + proof_of_possession: _, + network_public_key, + worker_public_key, + network_address, + p2p_address, + primary_address, + worker_address, + } = *vector::borrow(&genesis_validators, i); + + let validator = validator::new( + iota_address, + protocol_public_key, + network_public_key, + worker_public_key, + network_address, + p2p_address, + primary_address, + worker_address, + balance::split(&mut iota_supply, 2500), + ctx + ); + + vector::push_back(&mut validators, validator); + + i = i + 1; + }; + + iota_system::create( + iota_system_state_id, + validators, + iota_supply, // storage_fund + genesis_chain_parameters.protocol_version, + genesis_chain_parameters.chain_start_timestamp_ms, + genesis_chain_parameters.epoch_duration_ms, + ctx, + ); + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/iota_system.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/iota_system.move new file mode 100644 index 00000000000..4cdb2350ca0 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/iota_system.move @@ -0,0 +1,91 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::iota_system { + use iota::balance::Balance; + use iota::object::UID; + use iota::iota::IOTA; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; + use iota::dynamic_field; + + use iota_system::validator::Validator; + use iota_system::iota_system_state_inner::IotaSystemStateInner; + use iota_system::iota_system_state_inner; + + friend iota_system::genesis; + + struct IotaSystemState has key { + id: UID, + version: u64, + } + + public(friend) fun create( + id: UID, + validators: vector, + storage_fund: Balance, + protocol_version: u64, + epoch_start_timestamp_ms: u64, + epoch_duration_ms: u64, + ctx: &mut TxContext, + ) { + let system_state = iota_system_state_inner::create( + validators, + storage_fund, + protocol_version, + epoch_start_timestamp_ms, + epoch_duration_ms, + ctx, + ); + let version = iota_system_state_inner::genesis_system_state_version(); + let self = IotaSystemState { + id, + version, + }; + dynamic_field::add(&mut self.id, version, system_state); + transfer::share_object(self); + } + + fun advance_epoch( + storage_reward: Balance, + computation_reward: Balance, + wrapper: &mut IotaSystemState, + new_epoch: u64, + next_protocol_version: u64, + storage_rebate: u64, + _non_refundable_storage_fee: u64, + _storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested + // into storage fund, in basis point. + _reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. + epoch_start_timestamp_ms: u64, // Timestamp of the epoch start + ctx: &mut TxContext, + ) : Balance { + let self = load_system_state_mut(wrapper); + assert!(tx_context::sender(ctx) == @0x0, 0); + let storage_rebate = iota_system_state_inner::advance_epoch( + self, + new_epoch, + next_protocol_version, + storage_reward, + computation_reward, + storage_rebate, + epoch_start_timestamp_ms, + ); + + storage_rebate + } + + fun load_system_state_mut(self: &mut IotaSystemState): &mut IotaSystemStateInner { + load_inner_maybe_upgrade(self) + } + + fun load_inner_maybe_upgrade(self: &mut IotaSystemState): &mut IotaSystemStateInner { + let version = self.version; + // TODO: This is where we check the version and perform upgrade if necessary. + + let inner: &mut IotaSystemStateInner = dynamic_field::borrow_mut(&mut self.id, version); + assert!(iota_system_state_inner::system_state_version(inner) == version, 0); + inner + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/iota_system_state_inner.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/iota_system_state_inner.move new file mode 100644 index 00000000000..2076a239ff3 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/iota_system_state_inner.move @@ -0,0 +1,119 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::iota_system_state_inner { + use iota::balance::{Self, Balance}; + use iota::iota::IOTA; + use iota::tx_context::TxContext; + use iota::bag::{Self, Bag}; + use iota::table::{Self, Table}; + use iota::object::ID; + + use iota_system::validator::Validator; + use iota_system::validator_wrapper::ValidatorWrapper; + use iota_system::validator_wrapper; + use iota_system::validator; + use iota::object; + + friend iota_system::iota_system; + + const SYSTEM_STATE_VERSION_V1: u64 = 18446744073709551605; // u64::MAX - 10 + + struct SystemParameters has store { + epoch_duration_ms: u64, + extra_fields: Bag, + } + + struct ValidatorSet has store { + active_validators: vector, + inactive_validators: Table, + extra_fields: Bag, + } + + struct IotaSystemStateInner has store { + epoch: u64, + protocol_version: u64, + system_state_version: u64, + validators: ValidatorSet, + storage_fund: Balance, + parameters: SystemParameters, + reference_gas_price: u64, + safe_mode: bool, + epoch_start_timestamp_ms: u64, + extra_fields: Bag, + } + + public(friend) fun create( + validators: vector, + storage_fund: Balance, + protocol_version: u64, + epoch_start_timestamp_ms: u64, + epoch_duration_ms: u64, + ctx: &mut TxContext, + ): IotaSystemStateInner { + let validators = new_validator_set(validators, ctx); + let system_state = IotaSystemStateInner { + epoch: 0, + protocol_version, + system_state_version: genesis_system_state_version(), + validators, + storage_fund, + parameters: SystemParameters { + epoch_duration_ms, + extra_fields: bag::new(ctx), + }, + reference_gas_price: 1, + safe_mode: false, + epoch_start_timestamp_ms, + extra_fields: bag::new(ctx), + }; + // Add a dummy inactive validator so that we could test validator upgrade through wrapper latter. + add_dummy_inactive_validator_for_testing(&mut system_state, ctx); + system_state + } + + public(friend) fun advance_epoch( + self: &mut IotaSystemStateInner, + new_epoch: u64, + next_protocol_version: u64, + storage_reward: Balance, + computation_reward: Balance, + storage_rebate_amount: u64, + epoch_start_timestamp_ms: u64, + ) : Balance { + self.epoch_start_timestamp_ms = epoch_start_timestamp_ms; + self.epoch = self.epoch + 1; + assert!(new_epoch == self.epoch, 0); + self.safe_mode = false; + self.protocol_version = next_protocol_version; + + balance::join(&mut self.storage_fund, computation_reward); + balance::join(&mut self.storage_fund, storage_reward); + let storage_rebate = balance::split(&mut self.storage_fund, storage_rebate_amount); + storage_rebate + } + + public(friend) fun protocol_version(self: &IotaSystemStateInner): u64 { self.protocol_version } + public(friend) fun system_state_version(self: &IotaSystemStateInner): u64 { self.system_state_version } + public(friend) fun genesis_system_state_version(): u64 { + SYSTEM_STATE_VERSION_V1 + } + + public(friend) fun add_dummy_inactive_validator_for_testing(self: &mut IotaSystemStateInner, ctx: &mut TxContext) { + // Add a new entry to the inactive validator table for upgrade testing. + let dummy_inactive_validator = validator_wrapper::create_v1( + validator::new_dummy_inactive_validator(ctx), + ctx, + ); + table::add(&mut self.validators.inactive_validators, object::id_from_address(@0x0), dummy_inactive_validator); + } + + fun new_validator_set(init_active_validators: vector, ctx: &mut TxContext): ValidatorSet { + ValidatorSet { + active_validators: init_active_validators, + inactive_validators: table::new(ctx), + extra_fields: bag::new(ctx), + } + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/validator.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/validator.move new file mode 100644 index 00000000000..c4c2c6fe884 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/validator.move @@ -0,0 +1,91 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::validator { + use std::ascii; + + use iota::tx_context::TxContext; + use std::string::{Self, String}; + use iota::bag::{Self, Bag}; + use iota::balance::{Self, Balance}; + use iota::iota::IOTA; + + friend iota_system::genesis; + friend iota_system::iota_system_state_inner; + friend iota_system::validator_wrapper; + + struct ValidatorMetadata has store { + iota_address: address, + protocol_pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + net_address: String, + p2p_address: String, + primary_address: String, + worker_address: String, + extra_fields: Bag, + } + + struct Validator has store { + metadata: ValidatorMetadata, + voting_power: u64, + stake: Balance, + extra_fields: Bag, + } + + public(friend) fun new( + iota_address: address, + protocol_pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + net_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + init_stake: Balance, + ctx: &mut TxContext + ): Validator { + let metadata = ValidatorMetadata { + iota_address, + protocol_pubkey_bytes, + network_pubkey_bytes, + worker_pubkey_bytes, + net_address: string::from_ascii(ascii::string(net_address)), + p2p_address: string::from_ascii(ascii::string(p2p_address)), + primary_address: string::from_ascii(ascii::string(primary_address)), + worker_address: string::from_ascii(ascii::string(worker_address)), + extra_fields: bag::new(ctx), + }; + + Validator { + metadata, + voting_power: balance::value(&init_stake), + stake: init_stake, + extra_fields: bag::new(ctx), + } + } + + public(friend) fun new_dummy_inactive_validator( + ctx: &mut TxContext + ): Validator { + let metadata = ValidatorMetadata { + iota_address: @0x0, + protocol_pubkey_bytes: vector[], + network_pubkey_bytes: vector[], + worker_pubkey_bytes: vector[], + net_address: string::utf8(vector[]), + p2p_address: string::utf8(vector[]), + primary_address: string::utf8(vector[]), + worker_address: string::utf8(vector[]), + extra_fields: bag::new(ctx), + }; + + Validator { + metadata, + voting_power: 0, + stake: balance::zero(), + extra_fields: bag::new(ctx), + } + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/validator_wrapper.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/validator_wrapper.move new file mode 100644 index 00000000000..71ec008eccd --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/base/sources/validator_wrapper.move @@ -0,0 +1,51 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::validator_wrapper { + use iota::versioned::Versioned; + use iota::versioned; + use iota::tx_context::TxContext; + use iota_system::validator::Validator; + + friend iota_system::iota_system_state_inner; + + const VALIDATOR_VERSION_V1: u64 = 18446744073709551605; // u64::MAX - 10 + + const EInvalidVersion: u64 = 0; + + struct ValidatorWrapper has store { + inner: Versioned + } + + // Validator corresponds to version 1. + public(friend) fun create_v1(validator: Validator, ctx: &mut TxContext): ValidatorWrapper { + ValidatorWrapper { + inner: versioned::create(VALIDATOR_VERSION_V1, validator, ctx) + } + } + + /// This function should always return the latest supported version. + /// If the inner version is old, we upgrade it lazily in-place. + public(friend) fun load_validator_maybe_upgrade(self: &mut ValidatorWrapper): &mut Validator { + upgrade_to_latest(self); + versioned::load_value_mut(&mut self.inner) + } + + /// Destroy the wrapper and retrieve the inner validator object. + public(friend) fun destroy(self: ValidatorWrapper): Validator { + upgrade_to_latest(&mut self); + let ValidatorWrapper { inner } = self; + versioned::destroy(inner) + } + + fun upgrade_to_latest(self: &mut ValidatorWrapper) { + let version = version(self); + // TODO: When new versions are added, we need to explicitly upgrade here. + assert!(version == VALIDATOR_VERSION_V1, EInvalidVersion); + } + + fun version(self: &ValidatorWrapper): u64 { + versioned::version(&self.inner) + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/Move.toml b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/Move.toml new file mode 100644 index 00000000000..fa41f9c7cb5 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "IotaSystemDeepUpgrade" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } +MoveStdlib = { local = "../../../../../iota-framework/packages/move-stdlib" } + +[addresses] +iota_system = "0x3" diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/genesis.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/genesis.move new file mode 100644 index 00000000000..4ab5441074a --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/genesis.move @@ -0,0 +1,127 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::genesis { + use std::vector; + use iota::balance::{Self, Balance}; + use iota::object::UID; + use iota::iota::IOTA; + use iota::tx_context::{Self, TxContext}; + use std::option::Option; + + use iota_system::iota_system; + use iota_system::validator; + + struct GenesisValidatorMetadata has drop, copy { + name: vector, + description: vector, + image_url: vector, + project_url: vector, + + iota_address: address, + + gas_price: u64, + commission_rate: u64, + + protocol_public_key: vector, + proof_of_possession: vector, + + network_public_key: vector, + worker_public_key: vector, + + network_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + } + + struct GenesisChainParameters has drop, copy { + protocol_version: u64, + chain_start_timestamp_ms: u64, + epoch_duration_ms: u64, + + stake_subsidy_start_epoch: u64, + stake_subsidy_initial_distribution_amount: u64, + stake_subsidy_period_length: u64, + stake_subsidy_decrease_rate: u16, + + max_validator_count: u64, + min_validator_joining_stake: u64, + validator_low_stake_threshold: u64, + validator_very_low_stake_threshold: u64, + validator_low_stake_grace_period: u64, + } + + struct TokenDistributionSchedule has drop { + stake_subsidy_fund_micros: u64, + allocations: vector, + } + + struct TokenAllocation has drop { + recipient_address: address, + amount_micros: u64, + staked_with_validator: Option
    , + } + + fun create( + iota_system_state_id: UID, + iota_supply: Balance, + genesis_chain_parameters: GenesisChainParameters, + genesis_validators: vector, + _token_distribution_schedule: TokenDistributionSchedule, + ctx: &mut TxContext, + ) { + assert!(tx_context::epoch(ctx) == 0, 0); + + let validators = vector::empty(); + let count = vector::length(&genesis_validators); + let i = 0; + while (i < count) { + let GenesisValidatorMetadata { + name: _, + description: _, + image_url: _, + project_url: _, + iota_address, + gas_price: _, + commission_rate: _, + protocol_public_key, + proof_of_possession: _, + network_public_key, + worker_public_key, + network_address, + p2p_address, + primary_address, + worker_address, + } = *vector::borrow(&genesis_validators, i); + + let validator = validator::new( + iota_address, + protocol_public_key, + network_public_key, + worker_public_key, + network_address, + p2p_address, + primary_address, + worker_address, + balance::split(&mut iota_supply, 2500), + ctx + ); + + vector::push_back(&mut validators, validator); + + i = i + 1; + }; + + iota_system::create( + iota_system_state_id, + validators, + iota_supply, // storage_fund + genesis_chain_parameters.protocol_version, + genesis_chain_parameters.chain_start_timestamp_ms, + genesis_chain_parameters.epoch_duration_ms, + ctx, + ); + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/iota_system.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/iota_system.move new file mode 100644 index 00000000000..753320dacb6 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/iota_system.move @@ -0,0 +1,96 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::iota_system { + use iota::balance::Balance; + use iota::object::UID; + use iota::iota::IOTA; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; + use iota::dynamic_field; + + use iota_system::validator::Validator; + use iota_system::iota_system_state_inner::{Self, IotaSystemStateInnerV2, IotaSystemStateInner}; + + friend iota_system::genesis; + + struct IotaSystemState has key { + id: UID, + version: u64, + } + + public(friend) fun create( + id: UID, + validators: vector, + storage_fund: Balance, + protocol_version: u64, + epoch_start_timestamp_ms: u64, + epoch_duration_ms: u64, + ctx: &mut TxContext, + ) { + let system_state = iota_system_state_inner::create( + validators, + storage_fund, + protocol_version, + epoch_start_timestamp_ms, + epoch_duration_ms, + ctx, + ); + let version = iota_system_state_inner::genesis_system_state_version(); + let self = IotaSystemState { + id, + version, + }; + dynamic_field::add(&mut self.id, version, system_state); + transfer::share_object(self); + } + + fun advance_epoch( + storage_reward: Balance, + computation_reward: Balance, + wrapper: &mut IotaSystemState, + new_epoch: u64, + next_protocol_version: u64, + storage_rebate: u64, + _non_refundable_storage_fee: u64, + _storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested + // into storage fund, in basis point. + _reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. + epoch_start_timestamp_ms: u64, // Timestamp of the epoch start + ctx: &mut TxContext, + ) : Balance { + let self = load_system_state_mut(wrapper); + assert!(tx_context::sender(ctx) == @0x0, 0); + let storage_rebate = iota_system_state_inner::advance_epoch( + self, + new_epoch, + next_protocol_version, + storage_reward, + computation_reward, + storage_rebate, + epoch_start_timestamp_ms, + ); + + storage_rebate + } + + fun load_system_state_mut(self: &mut IotaSystemState): &mut IotaSystemStateInnerV2 { + load_inner_maybe_upgrade(self) + } + + fun load_inner_maybe_upgrade(self: &mut IotaSystemState): &mut IotaSystemStateInnerV2 { + let version = self.version; + if (version == iota_system_state_inner::genesis_system_state_version()) { + let inner: IotaSystemStateInner = dynamic_field::remove(&mut self.id, version); + let new_inner = iota_system_state_inner::v1_to_v2(inner); + version = iota_system_state_inner::system_state_version(&new_inner); + dynamic_field::add(&mut self.id, version, new_inner); + self.version = version; + }; + + let inner: &mut IotaSystemStateInnerV2 = dynamic_field::borrow_mut(&mut self.id, version); + assert!(iota_system_state_inner::system_state_version(inner) == version, 0); + inner + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/iota_system_state_inner.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/iota_system_state_inner.move new file mode 100644 index 00000000000..8182c1d58aa --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/iota_system_state_inner.move @@ -0,0 +1,191 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::iota_system_state_inner { + use std::vector; + + use iota::balance::{Self, Balance}; + use iota::iota::IOTA; + use iota::tx_context::TxContext; + use iota::bag::{Self, Bag}; + use iota::table::{Self, Table}; + use iota::object::ID; + + use iota_system::validator::{Validator, ValidatorV2}; + use iota_system::validator_wrapper::ValidatorWrapper; + use iota_system::validator_wrapper; + use iota::object; + use iota_system::validator; + + friend iota_system::iota_system; + + const SYSTEM_STATE_VERSION_V1: u64 = 18446744073709551605; // u64::MAX - 10 + // Not using MAX - 9 since it's already used in the shallow upgrade test. + const SYSTEM_STATE_VERSION_V2: u64 = 18446744073709551607; // u64::MAX - 8 + + struct SystemParameters has store { + epoch_duration_ms: u64, + extra_fields: Bag, + } + + struct ValidatorSet has store { + active_validators: vector, + inactive_validators: Table, + extra_fields: Bag, + } + + struct ValidatorSetV2 has store { + active_validators: vector, + inactive_validators: Table, + extra_fields: Bag, + } + + struct IotaSystemStateInner has store { + epoch: u64, + protocol_version: u64, + system_state_version: u64, + validators: ValidatorSet, + storage_fund: Balance, + parameters: SystemParameters, + reference_gas_price: u64, + safe_mode: bool, + epoch_start_timestamp_ms: u64, + extra_fields: Bag, + } + + struct IotaSystemStateInnerV2 has store { + new_dummy_field: u64, + epoch: u64, + protocol_version: u64, + system_state_version: u64, + validators: ValidatorSetV2, + storage_fund: Balance, + parameters: SystemParameters, + reference_gas_price: u64, + safe_mode: bool, + epoch_start_timestamp_ms: u64, + extra_fields: Bag, + } + + public(friend) fun create( + validators: vector, + storage_fund: Balance, + protocol_version: u64, + epoch_start_timestamp_ms: u64, + epoch_duration_ms: u64, + ctx: &mut TxContext, + ): IotaSystemStateInner { + let validators = new_validator_set(validators, ctx); + let system_state = IotaSystemStateInner { + epoch: 0, + protocol_version, + system_state_version: genesis_system_state_version(), + validators, + storage_fund, + parameters: SystemParameters { + epoch_duration_ms, + extra_fields: bag::new(ctx), + }, + reference_gas_price: 1, + safe_mode: false, + epoch_start_timestamp_ms, + extra_fields: bag::new(ctx), + }; + system_state + } + + public(friend) fun advance_epoch( + self: &mut IotaSystemStateInnerV2, + new_epoch: u64, + next_protocol_version: u64, + storage_reward: Balance, + computation_reward: Balance, + storage_rebate_amount: u64, + epoch_start_timestamp_ms: u64, + ) : Balance { + touch_dummy_inactive_validator(self); + + self.epoch_start_timestamp_ms = epoch_start_timestamp_ms; + self.epoch = self.epoch + 1; + assert!(new_epoch == self.epoch, 0); + self.safe_mode = false; + self.protocol_version = next_protocol_version; + + balance::join(&mut self.storage_fund, computation_reward); + balance::join(&mut self.storage_fund, storage_reward); + let storage_rebate = balance::split(&mut self.storage_fund, storage_rebate_amount); + storage_rebate + } + + public(friend) fun protocol_version(self: &IotaSystemStateInnerV2): u64 { self.protocol_version } + public(friend) fun system_state_version(self: &IotaSystemStateInnerV2): u64 { self.system_state_version } + public(friend) fun genesis_system_state_version(): u64 { + SYSTEM_STATE_VERSION_V1 + } + + fun new_validator_set(init_active_validators: vector, ctx: &mut TxContext): ValidatorSet { + ValidatorSet { + active_validators: init_active_validators, + inactive_validators: table::new(ctx), + extra_fields: bag::new(ctx), + } + } + + public(friend) fun v1_to_v2(v1: IotaSystemStateInner): IotaSystemStateInnerV2 { + let IotaSystemStateInner { + epoch, + protocol_version, + system_state_version: old_system_state_version, + validators, + storage_fund, + parameters, + reference_gas_price, + safe_mode, + epoch_start_timestamp_ms, + extra_fields, + } = v1; + let new_validator_set = validator_set_v1_to_v2(validators); + assert!(old_system_state_version == SYSTEM_STATE_VERSION_V1, 0); + IotaSystemStateInnerV2 { + new_dummy_field: 100, + epoch, + protocol_version, + system_state_version: SYSTEM_STATE_VERSION_V2, + validators: new_validator_set, + storage_fund, + parameters, + reference_gas_price, + safe_mode, + epoch_start_timestamp_ms, + extra_fields, + } + } + + /// Load the dummy inactive validator added in the base version, trigger it to be upgraded. + fun touch_dummy_inactive_validator(self: &mut IotaSystemStateInnerV2) { + let validator_wrapper = table::borrow_mut(&mut self.validators.inactive_validators, object::id_from_address(@0x0)); + let _ = validator_wrapper::load_validator_maybe_upgrade(validator_wrapper); + } + + fun validator_set_v1_to_v2(v1: ValidatorSet): ValidatorSetV2 { + let ValidatorSet { + active_validators, + inactive_validators, + extra_fields, + } = v1; + let new_active_validators = vector[]; + while (!vector::is_empty(&active_validators)) { + let validator = vector::pop_back(&mut active_validators); + let validator = validator::v1_to_v2(validator); + vector::push_back(&mut new_active_validators, validator); + }; + vector::destroy_empty(active_validators); + vector::reverse(&mut new_active_validators); + ValidatorSetV2 { + active_validators: new_active_validators, + inactive_validators, + extra_fields, + } + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/validator.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/validator.move new file mode 100644 index 00000000000..b654d7a5e48 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/validator.move @@ -0,0 +1,92 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::validator { + use std::ascii; + + use iota::tx_context::TxContext; + use std::string::{Self, String}; + use iota::bag::{Self, Bag}; + use iota::balance::{Self, Balance}; + use iota::iota::IOTA; + + friend iota_system::genesis; + friend iota_system::iota_system_state_inner; + friend iota_system::validator_wrapper; + + struct ValidatorMetadata has store { + iota_address: address, + protocol_pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + net_address: String, + p2p_address: String, + primary_address: String, + worker_address: String, + extra_fields: Bag, + } + + struct Validator has store { + metadata: ValidatorMetadata, + voting_power: u64, + stake: Balance, + extra_fields: Bag, + } + + struct ValidatorV2 has store { + new_dummy_field: u64, + metadata: ValidatorMetadata, + voting_power: u64, + stake: Balance, + extra_fields: Bag, + } + + public(friend) fun new( + iota_address: address, + protocol_pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + net_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + init_stake: Balance, + ctx: &mut TxContext + ): Validator { + let metadata = ValidatorMetadata { + iota_address, + protocol_pubkey_bytes, + network_pubkey_bytes, + worker_pubkey_bytes, + net_address: string::from_ascii(ascii::string(net_address)), + p2p_address: string::from_ascii(ascii::string(p2p_address)), + primary_address: string::from_ascii(ascii::string(primary_address)), + worker_address: string::from_ascii(ascii::string(worker_address)), + extra_fields: bag::new(ctx), + }; + + Validator { + metadata, + voting_power: balance::value(&init_stake), + stake: init_stake, + extra_fields: bag::new(ctx), + } + } + + public(friend) fun v1_to_v2(v1: Validator): ValidatorV2 { + let Validator { + metadata, + voting_power, + stake, + extra_fields, + } = v1; + ValidatorV2 { + new_dummy_field: 100, + metadata, + voting_power, + stake, + extra_fields, + } + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/validator_wrapper.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/validator_wrapper.move new file mode 100644 index 00000000000..df727819949 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/deep_upgrade/sources/validator_wrapper.move @@ -0,0 +1,58 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::validator_wrapper { + use iota::versioned::Versioned; + use iota::versioned; + use iota::tx_context::TxContext; + use iota_system::validator::{Validator, ValidatorV2}; + use iota_system::validator; + + friend iota_system::iota_system; + friend iota_system::iota_system_state_inner; + + const VALIDATOR_VERSION_V1: u64 = 18446744073709551605; // u64::MAX - 10 + const VALIDATOR_VERSION_V3: u64 = 18446744073709551607; // u64::MAX - 8 + + const EInvalidVersion: u64 = 0; + + struct ValidatorWrapper has store { + inner: Versioned + } + + // Validator corresponds to version 1. + public(friend) fun create_v1(validator: Validator, ctx: &mut TxContext): ValidatorWrapper { + ValidatorWrapper { + inner: versioned::create(VALIDATOR_VERSION_V1, validator, ctx) + } + } + + /// This function should always return the latest supported version. + /// If the inner version is old, we upgrade it lazily in-place. + public(friend) fun load_validator_maybe_upgrade(self: &mut ValidatorWrapper): &mut ValidatorV2 { + upgrade_to_latest(self); + versioned::load_value_mut(&mut self.inner) + } + + /// Destroy the wrapper and retrieve the inner validator object. + public(friend) fun destroy(self: ValidatorWrapper): ValidatorV2 { + upgrade_to_latest(&mut self); + let ValidatorWrapper { inner } = self; + versioned::destroy(inner) + } + + fun upgrade_to_latest(self: &mut ValidatorWrapper) { + let version = version(self); + if (version == VALIDATOR_VERSION_V1) { + let (v1, cap) = versioned::remove_value_for_upgrade(&mut self.inner); + let v3 = validator::v1_to_v2(v1); + versioned::upgrade(&mut self.inner, VALIDATOR_VERSION_V3, v3, cap); + }; + assert!(version(self) == VALIDATOR_VERSION_V3, EInvalidVersion); + } + + fun version(self: &ValidatorWrapper): u64 { + versioned::version(&self.inner) + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/Move.toml b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/Move.toml new file mode 100644 index 00000000000..174d73a5fee --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "MockIotaSystemSafeMode" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } +MoveStdlib = { local = "../../../../../iota-framework/packages/move-stdlib" } + +[addresses] +iota_system = "0x3" diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/genesis.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/genesis.move new file mode 100644 index 00000000000..4ab5441074a --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/genesis.move @@ -0,0 +1,127 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::genesis { + use std::vector; + use iota::balance::{Self, Balance}; + use iota::object::UID; + use iota::iota::IOTA; + use iota::tx_context::{Self, TxContext}; + use std::option::Option; + + use iota_system::iota_system; + use iota_system::validator; + + struct GenesisValidatorMetadata has drop, copy { + name: vector, + description: vector, + image_url: vector, + project_url: vector, + + iota_address: address, + + gas_price: u64, + commission_rate: u64, + + protocol_public_key: vector, + proof_of_possession: vector, + + network_public_key: vector, + worker_public_key: vector, + + network_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + } + + struct GenesisChainParameters has drop, copy { + protocol_version: u64, + chain_start_timestamp_ms: u64, + epoch_duration_ms: u64, + + stake_subsidy_start_epoch: u64, + stake_subsidy_initial_distribution_amount: u64, + stake_subsidy_period_length: u64, + stake_subsidy_decrease_rate: u16, + + max_validator_count: u64, + min_validator_joining_stake: u64, + validator_low_stake_threshold: u64, + validator_very_low_stake_threshold: u64, + validator_low_stake_grace_period: u64, + } + + struct TokenDistributionSchedule has drop { + stake_subsidy_fund_micros: u64, + allocations: vector, + } + + struct TokenAllocation has drop { + recipient_address: address, + amount_micros: u64, + staked_with_validator: Option
    , + } + + fun create( + iota_system_state_id: UID, + iota_supply: Balance, + genesis_chain_parameters: GenesisChainParameters, + genesis_validators: vector, + _token_distribution_schedule: TokenDistributionSchedule, + ctx: &mut TxContext, + ) { + assert!(tx_context::epoch(ctx) == 0, 0); + + let validators = vector::empty(); + let count = vector::length(&genesis_validators); + let i = 0; + while (i < count) { + let GenesisValidatorMetadata { + name: _, + description: _, + image_url: _, + project_url: _, + iota_address, + gas_price: _, + commission_rate: _, + protocol_public_key, + proof_of_possession: _, + network_public_key, + worker_public_key, + network_address, + p2p_address, + primary_address, + worker_address, + } = *vector::borrow(&genesis_validators, i); + + let validator = validator::new( + iota_address, + protocol_public_key, + network_public_key, + worker_public_key, + network_address, + p2p_address, + primary_address, + worker_address, + balance::split(&mut iota_supply, 2500), + ctx + ); + + vector::push_back(&mut validators, validator); + + i = i + 1; + }; + + iota_system::create( + iota_system_state_id, + validators, + iota_supply, // storage_fund + genesis_chain_parameters.protocol_version, + genesis_chain_parameters.chain_start_timestamp_ms, + genesis_chain_parameters.epoch_duration_ms, + ctx, + ); + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/iota_system.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/iota_system.move new file mode 100644 index 00000000000..b4f7e4e45aa --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/iota_system.move @@ -0,0 +1,77 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::iota_system { + use iota::balance::Balance; + use iota::object::UID; + use iota::iota::IOTA; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; + use iota::dynamic_field; + + use iota_system::validator::Validator; + use iota_system::iota_system_state_inner::IotaSystemStateInner; + use iota_system::iota_system_state_inner; + + friend iota_system::genesis; + + struct IotaSystemState has key { + id: UID, + version: u64, + } + + public(friend) fun create( + id: UID, + validators: vector, + storage_fund: Balance, + protocol_version: u64, + epoch_start_timestamp_ms: u64, + epoch_duration_ms: u64, + ctx: &mut TxContext, + ) { + let system_state = iota_system_state_inner::create( + validators, + storage_fund, + protocol_version, + epoch_start_timestamp_ms, + epoch_duration_ms, + ctx, + ); + let version = iota_system_state_inner::genesis_system_state_version(); + let self = IotaSystemState { + id, + version, + }; + dynamic_field::add(&mut self.id, version, system_state); + transfer::share_object(self); + } + + fun advance_epoch( + storage_reward: Balance, + computation_reward: Balance, + wrapper: &mut IotaSystemState, + _new_epoch: u64, + _next_protocol_version: u64, + storage_rebate: u64, + _non_refundable_storage_fee: u64, + _storage_fund_reinvest_rate: u64, + _reward_slashing_rate: u64, + _epoch_start_timestamp_ms: u64, + ctx: &mut TxContext, + ) : Balance { + let self = load_system_state_mut(wrapper); + assert!(tx_context::sender(ctx) == @0x1, 0); // aborts here + iota_system_state_inner::advance_epoch( + self, + storage_reward, + computation_reward, + storage_rebate, + ) + } + + fun load_system_state_mut(self: &mut IotaSystemState): &mut IotaSystemStateInner { + let version = self.version; + dynamic_field::borrow_mut(&mut self.id, version) + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/iota_system_state_inner.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/iota_system_state_inner.move new file mode 100644 index 00000000000..24136f839ce --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/iota_system_state_inner.move @@ -0,0 +1,89 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::iota_system_state_inner { + use iota::balance::{Self, Balance}; + use iota::iota::IOTA; + use iota::tx_context::TxContext; + use iota::bag::{Self, Bag}; + use iota::table::{Self, Table}; + use iota::object::ID; + + use iota_system::validator::Validator; + use iota_system::validator_wrapper::ValidatorWrapper; + + friend iota_system::iota_system; + + const SYSTEM_STATE_VERSION_V1: u64 = 18446744073709551605; // u64::MAX - 10 + + struct SystemParameters has store { + epoch_duration_ms: u64, + extra_fields: Bag, + } + + struct ValidatorSet has store { + active_validators: vector, + inactive_validators: Table, + extra_fields: Bag, + } + + struct IotaSystemStateInner has store { + epoch: u64, + protocol_version: u64, + system_state_version: u64, + validators: ValidatorSet, + storage_fund: Balance, + parameters: SystemParameters, + reference_gas_price: u64, + safe_mode: bool, + epoch_start_timestamp_ms: u64, + extra_fields: Bag, + } + + public(friend) fun create( + validators: vector, + storage_fund: Balance, + protocol_version: u64, + epoch_start_timestamp_ms: u64, + epoch_duration_ms: u64, + ctx: &mut TxContext, + ): IotaSystemStateInner { + let system_state = IotaSystemStateInner { + epoch: 0, + protocol_version, + system_state_version: genesis_system_state_version(), + validators: ValidatorSet { + active_validators: validators, + inactive_validators: table::new(ctx), + extra_fields: bag::new(ctx), + }, + storage_fund, + parameters: SystemParameters { + epoch_duration_ms, + extra_fields: bag::new(ctx), + }, + reference_gas_price: 1, + safe_mode: false, + epoch_start_timestamp_ms, + extra_fields: bag::new(ctx), + }; + system_state + } + + public(friend) fun advance_epoch( + self: &mut IotaSystemStateInner, + storage_reward: Balance, + computation_reward: Balance, + storage_rebate_amount: u64, + ) : Balance { + balance::join(&mut self.storage_fund, computation_reward); + balance::join(&mut self.storage_fund, storage_reward); + let storage_rebate = balance::split(&mut self.storage_fund, storage_rebate_amount); + storage_rebate + } + + public(friend) fun genesis_system_state_version(): u64 { + SYSTEM_STATE_VERSION_V1 + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/validator.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/validator.move new file mode 100644 index 00000000000..894b994941d --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/validator.move @@ -0,0 +1,68 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::validator { + use std::ascii; + + use iota::tx_context::TxContext; + use std::string::{Self, String}; + use iota::bag::{Self, Bag}; + use iota::balance::{Self, Balance}; + use iota::iota::IOTA; + + friend iota_system::genesis; + friend iota_system::iota_system_state_inner; + friend iota_system::validator_wrapper; + + struct ValidatorMetadata has store { + iota_address: address, + protocol_pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + net_address: String, + p2p_address: String, + primary_address: String, + worker_address: String, + extra_fields: Bag, + } + + struct Validator has store { + metadata: ValidatorMetadata, + voting_power: u64, + stake: Balance, + extra_fields: Bag, + } + + public(friend) fun new( + iota_address: address, + protocol_pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + net_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + init_stake: Balance, + ctx: &mut TxContext + ): Validator { + let metadata = ValidatorMetadata { + iota_address, + protocol_pubkey_bytes, + network_pubkey_bytes, + worker_pubkey_bytes, + net_address: string::from_ascii(ascii::string(net_address)), + p2p_address: string::from_ascii(ascii::string(p2p_address)), + primary_address: string::from_ascii(ascii::string(primary_address)), + worker_address: string::from_ascii(ascii::string(worker_address)), + extra_fields: bag::new(ctx), + }; + + Validator { + metadata, + voting_power: balance::value(&init_stake), + stake: init_stake, + extra_fields: bag::new(ctx), + } + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/validator_wrapper.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/validator_wrapper.move new file mode 100644 index 00000000000..4607d6f115a --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/safe_mode/sources/validator_wrapper.move @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::validator_wrapper { + use iota::versioned::Versioned; + + friend iota_system::iota_system_state_inner; + + struct ValidatorWrapper has store { + inner: Versioned + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/Move.toml b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/Move.toml new file mode 100644 index 00000000000..61f99581da8 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "IotaSystemShallowUpgrade" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../../iota-framework/packages/iota-framework" } +MoveStdlib = { local = "../../../../../iota-framework/packages/move-stdlib" } + +[addresses] +iota_system = "0x3" diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/genesis.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/genesis.move new file mode 100644 index 00000000000..4ab5441074a --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/genesis.move @@ -0,0 +1,127 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::genesis { + use std::vector; + use iota::balance::{Self, Balance}; + use iota::object::UID; + use iota::iota::IOTA; + use iota::tx_context::{Self, TxContext}; + use std::option::Option; + + use iota_system::iota_system; + use iota_system::validator; + + struct GenesisValidatorMetadata has drop, copy { + name: vector, + description: vector, + image_url: vector, + project_url: vector, + + iota_address: address, + + gas_price: u64, + commission_rate: u64, + + protocol_public_key: vector, + proof_of_possession: vector, + + network_public_key: vector, + worker_public_key: vector, + + network_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + } + + struct GenesisChainParameters has drop, copy { + protocol_version: u64, + chain_start_timestamp_ms: u64, + epoch_duration_ms: u64, + + stake_subsidy_start_epoch: u64, + stake_subsidy_initial_distribution_amount: u64, + stake_subsidy_period_length: u64, + stake_subsidy_decrease_rate: u16, + + max_validator_count: u64, + min_validator_joining_stake: u64, + validator_low_stake_threshold: u64, + validator_very_low_stake_threshold: u64, + validator_low_stake_grace_period: u64, + } + + struct TokenDistributionSchedule has drop { + stake_subsidy_fund_micros: u64, + allocations: vector, + } + + struct TokenAllocation has drop { + recipient_address: address, + amount_micros: u64, + staked_with_validator: Option
    , + } + + fun create( + iota_system_state_id: UID, + iota_supply: Balance, + genesis_chain_parameters: GenesisChainParameters, + genesis_validators: vector, + _token_distribution_schedule: TokenDistributionSchedule, + ctx: &mut TxContext, + ) { + assert!(tx_context::epoch(ctx) == 0, 0); + + let validators = vector::empty(); + let count = vector::length(&genesis_validators); + let i = 0; + while (i < count) { + let GenesisValidatorMetadata { + name: _, + description: _, + image_url: _, + project_url: _, + iota_address, + gas_price: _, + commission_rate: _, + protocol_public_key, + proof_of_possession: _, + network_public_key, + worker_public_key, + network_address, + p2p_address, + primary_address, + worker_address, + } = *vector::borrow(&genesis_validators, i); + + let validator = validator::new( + iota_address, + protocol_public_key, + network_public_key, + worker_public_key, + network_address, + p2p_address, + primary_address, + worker_address, + balance::split(&mut iota_supply, 2500), + ctx + ); + + vector::push_back(&mut validators, validator); + + i = i + 1; + }; + + iota_system::create( + iota_system_state_id, + validators, + iota_supply, // storage_fund + genesis_chain_parameters.protocol_version, + genesis_chain_parameters.chain_start_timestamp_ms, + genesis_chain_parameters.epoch_duration_ms, + ctx, + ); + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/iota_system.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/iota_system.move new file mode 100644 index 00000000000..19a966800e8 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/iota_system.move @@ -0,0 +1,96 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::iota_system { + use iota::balance::Balance; + use iota::object::UID; + use iota::iota::IOTA; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; + use iota::dynamic_field; + + use iota_system::validator::Validator; + use iota_system::iota_system_state_inner::{Self, IotaSystemStateInner, IotaSystemStateInnerV2}; + + friend iota_system::genesis; + + struct IotaSystemState has key { + id: UID, + version: u64, + } + + public(friend) fun create( + id: UID, + validators: vector, + storage_fund: Balance, + protocol_version: u64, + epoch_start_timestamp_ms: u64, + epoch_duration_ms: u64, + ctx: &mut TxContext, + ) { + let system_state = iota_system_state_inner::create( + validators, + storage_fund, + protocol_version, + epoch_start_timestamp_ms, + epoch_duration_ms, + ctx, + ); + let version = iota_system_state_inner::genesis_system_state_version(); + let self = IotaSystemState { + id, + version, + }; + dynamic_field::add(&mut self.id, version, system_state); + transfer::share_object(self); + } + + fun advance_epoch( + storage_reward: Balance, + computation_reward: Balance, + wrapper: &mut IotaSystemState, + new_epoch: u64, + next_protocol_version: u64, + storage_rebate: u64, + _non_refundable_storage_fee: u64, + _storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested + // into storage fund, in basis point. + _reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. + epoch_start_timestamp_ms: u64, // Timestamp of the epoch start + ctx: &mut TxContext, + ) : Balance { + let self = load_system_state_mut(wrapper); + assert!(tx_context::sender(ctx) == @0x0, 0); + let storage_rebate = iota_system_state_inner::advance_epoch( + self, + new_epoch, + next_protocol_version, + storage_reward, + computation_reward, + storage_rebate, + epoch_start_timestamp_ms, + ); + + storage_rebate + } + + fun load_system_state_mut(self: &mut IotaSystemState): &mut IotaSystemStateInnerV2 { + load_inner_maybe_upgrade(self) + } + + fun load_inner_maybe_upgrade(self: &mut IotaSystemState): &mut IotaSystemStateInnerV2 { + let version = self.version; + if (version == iota_system_state_inner::genesis_system_state_version()) { + let inner: IotaSystemStateInner = dynamic_field::remove(&mut self.id, version); + let new_inner = iota_system_state_inner::v1_to_v2(inner); + version = iota_system_state_inner::system_state_version(&new_inner); + dynamic_field::add(&mut self.id, version, new_inner); + self.version = version; + }; + + let inner: &mut IotaSystemStateInnerV2 = dynamic_field::borrow_mut(&mut self.id, version); + assert!(iota_system_state_inner::system_state_version(inner) == version, 0); + inner + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/iota_system_state_inner.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/iota_system_state_inner.move new file mode 100644 index 00000000000..57c066f3566 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/iota_system_state_inner.move @@ -0,0 +1,149 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::iota_system_state_inner { + use iota::balance::{Self, Balance}; + use iota::iota::IOTA; + use iota::tx_context::TxContext; + use iota::bag::{Self, Bag}; + use iota::table::{Self, Table}; + use iota::object::ID; + + use iota_system::validator::Validator; + use iota_system::validator_wrapper::ValidatorWrapper; + + friend iota_system::iota_system; + + const SYSTEM_STATE_VERSION_V1: u64 = 18446744073709551605; // u64::MAX - 10 + const SYSTEM_STATE_VERSION_V2: u64 = 18446744073709551606; // u64::MAX - 9 + + struct SystemParameters has store { + epoch_duration_ms: u64, + extra_fields: Bag, + } + + struct ValidatorSet has store { + active_validators: vector, + inactive_validators: Table, + extra_fields: Bag, + } + + struct IotaSystemStateInner has store { + epoch: u64, + protocol_version: u64, + system_state_version: u64, + validators: ValidatorSet, + storage_fund: Balance, + parameters: SystemParameters, + reference_gas_price: u64, + safe_mode: bool, + epoch_start_timestamp_ms: u64, + extra_fields: Bag, + } + + struct IotaSystemStateInnerV2 has store { + new_dummy_field: u64, + epoch: u64, + protocol_version: u64, + system_state_version: u64, + validators: ValidatorSet, + storage_fund: Balance, + parameters: SystemParameters, + reference_gas_price: u64, + safe_mode: bool, + epoch_start_timestamp_ms: u64, + extra_fields: Bag, + } + + public(friend) fun create( + validators: vector, + storage_fund: Balance, + protocol_version: u64, + epoch_start_timestamp_ms: u64, + epoch_duration_ms: u64, + ctx: &mut TxContext, + ): IotaSystemStateInner { + let validators = new_validator_set(validators, ctx); + let system_state = IotaSystemStateInner { + epoch: 0, + protocol_version, + system_state_version: genesis_system_state_version(), + validators, + storage_fund, + parameters: SystemParameters { + epoch_duration_ms, + extra_fields: bag::new(ctx), + }, + reference_gas_price: 1, + safe_mode: false, + epoch_start_timestamp_ms, + extra_fields: bag::new(ctx), + }; + system_state + } + + public(friend) fun advance_epoch( + self: &mut IotaSystemStateInnerV2, + new_epoch: u64, + next_protocol_version: u64, + storage_reward: Balance, + computation_reward: Balance, + storage_rebate_amount: u64, + epoch_start_timestamp_ms: u64, + ) : Balance { + self.epoch_start_timestamp_ms = epoch_start_timestamp_ms; + self.epoch = self.epoch + 1; + assert!(new_epoch == self.epoch, 0); + self.safe_mode = false; + self.protocol_version = next_protocol_version; + + balance::join(&mut self.storage_fund, computation_reward); + balance::join(&mut self.storage_fund, storage_reward); + let storage_rebate = balance::split(&mut self.storage_fund, storage_rebate_amount); + storage_rebate + } + + public(friend) fun protocol_version(self: &IotaSystemStateInnerV2): u64 { self.protocol_version } + public(friend) fun system_state_version(self: &IotaSystemStateInnerV2): u64 { self.system_state_version } + public(friend) fun genesis_system_state_version(): u64 { + SYSTEM_STATE_VERSION_V1 + } + + fun new_validator_set(init_active_validators: vector, ctx: &mut TxContext): ValidatorSet { + ValidatorSet { + active_validators: init_active_validators, + inactive_validators: table::new(ctx), + extra_fields: bag::new(ctx), + } + } + + public(friend) fun v1_to_v2(v1: IotaSystemStateInner): IotaSystemStateInnerV2 { + let IotaSystemStateInner { + epoch, + protocol_version, + system_state_version: old_system_state_version, + validators, + storage_fund, + parameters, + reference_gas_price, + safe_mode, + epoch_start_timestamp_ms, + extra_fields, + } = v1; + assert!(old_system_state_version == SYSTEM_STATE_VERSION_V1, 0); + IotaSystemStateInnerV2 { + new_dummy_field: 100, + epoch, + protocol_version, + system_state_version: SYSTEM_STATE_VERSION_V2, + validators, + storage_fund, + parameters, + reference_gas_price, + safe_mode, + epoch_start_timestamp_ms, + extra_fields, + } + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/validator.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/validator.move new file mode 100644 index 00000000000..894b994941d --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/validator.move @@ -0,0 +1,68 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::validator { + use std::ascii; + + use iota::tx_context::TxContext; + use std::string::{Self, String}; + use iota::bag::{Self, Bag}; + use iota::balance::{Self, Balance}; + use iota::iota::IOTA; + + friend iota_system::genesis; + friend iota_system::iota_system_state_inner; + friend iota_system::validator_wrapper; + + struct ValidatorMetadata has store { + iota_address: address, + protocol_pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + net_address: String, + p2p_address: String, + primary_address: String, + worker_address: String, + extra_fields: Bag, + } + + struct Validator has store { + metadata: ValidatorMetadata, + voting_power: u64, + stake: Balance, + extra_fields: Bag, + } + + public(friend) fun new( + iota_address: address, + protocol_pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + net_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + init_stake: Balance, + ctx: &mut TxContext + ): Validator { + let metadata = ValidatorMetadata { + iota_address, + protocol_pubkey_bytes, + network_pubkey_bytes, + worker_pubkey_bytes, + net_address: string::from_ascii(ascii::string(net_address)), + p2p_address: string::from_ascii(ascii::string(p2p_address)), + primary_address: string::from_ascii(ascii::string(primary_address)), + worker_address: string::from_ascii(ascii::string(worker_address)), + extra_fields: bag::new(ctx), + }; + + Validator { + metadata, + voting_power: balance::value(&init_stake), + stake: init_stake, + extra_fields: bag::new(ctx), + } + } +} diff --git a/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/validator_wrapper.move b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/validator_wrapper.move new file mode 100644 index 00000000000..15bff841188 --- /dev/null +++ b/crates/iota-e2e-tests/tests/framework_upgrades/mock_iota_systems/shallow_upgrade/sources/validator_wrapper.move @@ -0,0 +1,50 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::validator_wrapper { + use iota::versioned::Versioned; + use iota::versioned; + use iota::tx_context::TxContext; + use iota_system::validator::Validator; + + friend iota_system::iota_system; + friend iota_system::iota_system_state_inner; + + const EInvalidVersion: u64 = 0; + + struct ValidatorWrapper has store { + inner: Versioned + } + + // Validator corresponds to version 1. + public(friend) fun create_v1(validator: Validator, ctx: &mut TxContext): ValidatorWrapper { + ValidatorWrapper { + inner: versioned::create(1, validator, ctx) + } + } + + /// This function should always return the latest supported version. + /// If the inner version is old, we upgrade it lazily in-place. + public(friend) fun load_validator_maybe_upgrade(self: &mut ValidatorWrapper): &mut Validator { + upgrade_to_latest(self); + versioned::load_value_mut(&mut self.inner) + } + + /// Destroy the wrapper and retrieve the inner validator object. + public(friend) fun destroy(self: ValidatorWrapper): Validator { + upgrade_to_latest(&mut self); + let ValidatorWrapper { inner } = self; + versioned::destroy(inner) + } + + fun upgrade_to_latest(self: &mut ValidatorWrapper) { + let version = version(self); + // TODO: When new versions are added, we need to explicitly upgrade here. + assert!(version == 1, EInvalidVersion); + } + + fun version(self: &ValidatorWrapper): u64 { + versioned::version(&self.inner) + } +} diff --git a/crates/sui-e2e-tests/tests/full_node_tests.rs b/crates/iota-e2e-tests/tests/full_node_tests.rs similarity index 92% rename from crates/sui-e2e-tests/tests/full_node_tests.rs rename to crates/iota-e2e-tests/tests/full_node_tests.rs index c5c34b5b7f4..ebe7c0a3f29 100644 --- a/crates/sui-e2e-tests/tests/full_node_tests.rs +++ b/crates/iota-e2e-tests/tests/full_node_tests.rs @@ -1,41 +1,35 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; use futures::future; -use jsonrpsee::{ - core::client::{ClientT, Subscription, SubscriptionClientT}, - rpc_params, -}; -use move_core_types::{annotated_value::MoveStructLayout, ident_str, parser::parse_struct_tag}; -use rand::rngs::OsRng; -use serde_json::json; -use sui::client_commands::{SuiClientCommandResult, SuiClientCommands}; -use sui_config::node::RunWithRange; -use sui_core::authority::EffectsNotifyRead; -use sui_json_rpc_types::{ - type_and_fields_from_move_struct, EventFilter, EventPage, SuiEvent, SuiExecutionStatus, - SuiTransactionBlockEffectsAPI, SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, - TransactionFilter, +use iota::client_commands::{IotaClientCommandResult, IotaClientCommands}; +use iota_config::node::RunWithRange; +use iota_core::authority::EffectsNotifyRead; +use iota_json_rpc_types::{ + type_and_fields_from_move_struct, EventFilter, EventPage, IotaEvent, IotaExecutionStatus, + IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponse, + IotaTransactionBlockResponseOptions, TransactionFilter, }; -use sui_keys::keystore::AccountKeystore; -use sui_macros::*; -use sui_node::SuiNodeHandle; -use sui_sdk::wallet_context::WalletContext; -use sui_storage::{ +use iota_keys::keystore::AccountKeystore; +use iota_macros::*; +use iota_node::IotaNodeHandle; +use iota_sdk::wallet_context::WalletContext; +use iota_storage::{ key_value_store::TransactionKeyValueStore, key_value_store_metrics::KeyValueStoreMetrics, }; -use sui_test_transaction_builder::{ +use iota_test_transaction_builder::{ batch_make_transfer_transactions, create_devnet_nft, delete_devnet_nft, increment_counter, publish_basics_package, publish_basics_package_and_make_counter, publish_nfts_package, TestTransactionBuilder, }; -use sui_tool::restore_from_db_checkpoint; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress, TransactionDigest}, - crypto::{get_key_pair, SuiKeyPair}, - error::{SuiError, UserInputError}, +use iota_tool::restore_from_db_checkpoint; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber, TransactionDigest}, + crypto::{get_key_pair, IotaKeyPair}, + error::{IotaError, UserInputError}, event::{Event, EventID}, message_envelope::Message, messages_grpc::TransactionInfoRequest, @@ -52,6 +46,13 @@ use sui_types::{ }, utils::{to_sender_signed_transaction, to_sender_signed_transaction_with_multi_signers}, }; +use jsonrpsee::{ + core::client::{ClientT, Subscription, SubscriptionClientT}, + rpc_params, +}; +use move_core_types::{annotated_value::MoveStructLayout, ident_str, parser::parse_struct_tag}; +use rand::rngs::OsRng; +use serde_json::json; use test_cluster::TestClusterBuilder; use tokio::{ sync::Mutex, @@ -62,11 +63,11 @@ use tracing::info; #[sim_test] async fn test_full_node_follows_txes() -> Result<(), anyhow::Error> { let mut test_cluster = TestClusterBuilder::new().build().await; - let fullnode = test_cluster.spawn_new_fullnode().await.sui_node; + let fullnode = test_cluster.spawn_new_fullnode().await.iota_node; let context = &mut test_cluster.wallet; - // TODO: test fails on CI due to flakiness without this. Once https://github.com/MystenLabs/sui/pull/7056 is + // TODO: test fails on CI due to flakiness without this. Once https://github.com/iotaledger/iota/pull/7056 is // merged we should be able to root out the flakiness. sleep(Duration::from_millis(10)).await; @@ -119,7 +120,7 @@ async fn test_full_node_shared_objects() -> Result<(), anyhow::Error> { .await; let digest = response.digest; handle - .sui_node + .iota_node .state() .get_effects_notify_read() .notify_read_executed_effects(vec![digest]) @@ -202,7 +203,7 @@ async fn test_sponsored_transaction() -> Result<(), anyhow::Error> { async fn test_full_node_move_function_index() -> Result<(), anyhow::Error> { telemetry_subscribers::init_for_testing(); let mut test_cluster = TestClusterBuilder::new().build().await; - let node = &test_cluster.fullnode_handle.sui_node; + let node = &test_cluster.fullnode_handle.iota_node; let sender = test_cluster.get_address_0(); let context = &mut test_cluster.wallet; @@ -282,7 +283,7 @@ async fn test_full_node_indexes() -> Result<(), anyhow::Error> { .enable_fullnode_events() .build() .await; - let node = &test_cluster.fullnode_handle.sui_node; + let node = &test_cluster.fullnode_handle.iota_node; let context = &mut test_cluster.wallet; let (transferred_object, sender, receiver, digest, _) = transfer_coin(context).await?; @@ -372,19 +373,19 @@ async fn test_full_node_indexes() -> Result<(), anyhow::Error> { // let sender_balance_change = BalanceChange { // change_type: BalanceChangeType::Pay, // owner: sender, - // coin_type: parse_struct_tag("0x2::sui::SUI").unwrap(), + // coin_type: parse_struct_tag("0x2::iota::IOTA").unwrap(), // amount: -100000000000000, // }; // let recipient_balance_change = BalanceChange { // change_type: BalanceChangeType::Receive, // owner: receiver, - // coin_type: parse_struct_tag("0x2::sui::SUI").unwrap(), + // coin_type: parse_struct_tag("0x2::iota::IOTA").unwrap(), // amount: 100000000000000, // }; // let gas_balance_change = BalanceChange { // change_type: BalanceChangeType::Gas, // owner: sender, - // coin_type: parse_struct_tag("0x2::sui::SUI").unwrap(), + // coin_type: parse_struct_tag("0x2::iota::IOTA").unwrap(), // amount: (gas_used as i128).neg(), // }; // @@ -476,7 +477,7 @@ async fn test_full_node_indexes() -> Result<(), anyhow::Error> { // .state() // .query_events( // EventQuery::MoveModule { - // package: SuiFramework::ID, + // package: IotaFramework::ID, // module: "unused_input_object".to_string(), // }, // None, @@ -511,7 +512,7 @@ async fn test_full_node_cold_sync() -> Result<(), anyhow::Error> { sleep(Duration::from_millis(1000)).await; // Start a new fullnode that is not on the write path - let fullnode = test_cluster.spawn_new_fullnode().await.sui_node; + let fullnode = test_cluster.spawn_new_fullnode().await.iota_node; fullnode .state() @@ -546,7 +547,7 @@ async fn do_test_full_node_sync_flood() { let mut test_cluster = TestClusterBuilder::new().build().await; // Start a new fullnode that is not on the write path - let fullnode = test_cluster.spawn_new_fullnode().await.sui_node; + let fullnode = test_cluster.spawn_new_fullnode().await.iota_node; let context = test_cluster.wallet; @@ -584,7 +585,7 @@ async fn do_test_full_node_sync_flood() { for _ in 0..10 { let res = { let context = &mut context.lock().await; - SuiClientCommands::SplitCoin { + IotaClientCommands::SplitCoin { amounts: Some(vec![1]), count: None, coin_id: object_to_split.0, @@ -599,7 +600,7 @@ async fn do_test_full_node_sync_flood() { .unwrap() }; - owned_tx_digest = if let SuiClientCommandResult::SplitCoin(resp) = res { + owned_tx_digest = if let IotaClientCommandResult::SplitCoin(resp) = res { Some(resp.digest) } else { panic!("transfer command did not return WalletCommandResult::Transfer"); @@ -651,7 +652,7 @@ async fn test_full_node_sub_and_query_move_event_ok() -> Result<(), anyhow::Erro let fullnode = test_cluster.spawn_new_fullnode().await; let ws_client = fullnode.ws_client().await; - let node = fullnode.sui_node; + let node = fullnode.iota_node; let context = &mut test_cluster.wallet; let package_id = publish_nfts_package(context).await.0; @@ -659,11 +660,11 @@ async fn test_full_node_sub_and_query_move_event_ok() -> Result<(), anyhow::Erro let struct_tag_str = format!("{package_id}::devnet_nft::MintNFTEvent"); let struct_tag = parse_struct_tag(&struct_tag_str).unwrap(); - let mut sub: Subscription = ws_client + let mut sub: Subscription = ws_client .subscribe( - "suix_subscribeEvent", + "iotax_subscribeEvent", rpc_params![EventFilter::MoveEventType(struct_tag.clone())], - "suix_unsubscribeEvent", + "iotax_unsubscribeEvent", ) .await .unwrap(); @@ -677,7 +678,7 @@ async fn test_full_node_sub_and_query_move_event_ok() -> Result<(), anyhow::Erro // Wait for streaming let bcs = match timeout(Duration::from_secs(5), sub.next()).await { - Ok(Some(Ok(SuiEvent { + Ok(Some(Ok(IotaEvent { type_, parsed_json, bcs, @@ -694,7 +695,7 @@ async fn test_full_node_sub_and_query_move_event_ok() -> Result<(), anyhow::Erro ); bcs } - other => panic!("Failed to get SuiEvent, but {:?}", other), + other => panic!("Failed to get IotaEvent, but {:?}", other), }; let struct_tag = parse_struct_tag(&struct_tag_str).unwrap(); let layout = MoveObject::get_layout_from_struct_tag( @@ -705,7 +706,7 @@ async fn test_full_node_sub_and_query_move_event_ok() -> Result<(), anyhow::Erro let expected_parsed_event = Event::move_event_to_move_struct(&bcs, layout).unwrap(); let (_, expected_parsed_event) = type_and_fields_from_move_struct(&struct_tag, expected_parsed_event); - let expected_event = SuiEvent { + let expected_event = IotaEvent { id: EventID { tx_digest: digest, event_seq: 0, @@ -721,7 +722,7 @@ async fn test_full_node_sub_and_query_move_event_ok() -> Result<(), anyhow::Erro // get tx events let events = test_cluster - .sui_client() + .iota_client() .event_api() .get_events(digest) .await?; @@ -751,7 +752,7 @@ async fn test_full_node_event_read_api_ok() { .await; let context = &mut test_cluster.wallet; - let node = &test_cluster.fullnode_handle.sui_node; + let node = &test_cluster.fullnode_handle.iota_node; let jsonrpc_client = &test_cluster.fullnode_handle.rpc_client; let (package_id, gas_id_1, _) = publish_nfts_package(context).await; @@ -787,8 +788,8 @@ async fn test_full_node_event_read_api_ok() { // query by move event struct name let params = rpc_params![digest2]; - let events: Vec = jsonrpc_client - .request("sui_getEvents", params) + let events: Vec = jsonrpc_client + .request("iota_getEvents", params) .await .unwrap(); assert_eq!(events.len(), 1); @@ -821,7 +822,7 @@ async fn test_full_node_event_query_by_module_ok() { module: ident_str!("devnet_nft").into() }]; let page: EventPage = jsonrpc_client - .request("suix_queryEvents", params) + .request("iotax_queryEvents", params) .await .unwrap(); assert_eq!(page.data.len(), 1); @@ -831,7 +832,7 @@ async fn test_full_node_event_query_by_module_ok() { #[sim_test] async fn test_full_node_transaction_orchestrator_basic() -> Result<(), anyhow::Error> { let mut test_cluster = TestClusterBuilder::new().build().await; - let fullnode = test_cluster.spawn_new_fullnode().await.sui_node; + let fullnode = test_cluster.spawn_new_fullnode().await.iota_node; let metrics = KeyValueStoreMetrics::new_for_tests(); let kv_store = Arc::new(TransactionKeyValueStore::new( "rocksdb", @@ -946,11 +947,11 @@ async fn test_execute_tx_with_serialized_signature() -> Result<(), anyhow::Error context .config .keystore - .add_key(None, SuiKeyPair::Secp256k1(get_key_pair().1))?; + .add_key(None, IotaKeyPair::Secp256k1(get_key_pair().1))?; context .config .keystore - .add_key(None, SuiKeyPair::Ed25519(get_key_pair().1))?; + .add_key(None, IotaKeyPair::Ed25519(get_key_pair().1))?; let jsonrpc_client = &test_cluster.fullnode_handle.rpc_client; @@ -962,15 +963,15 @@ async fn test_execute_tx_with_serialized_signature() -> Result<(), anyhow::Error let params = rpc_params![ tx_bytes, signatures, - SuiTransactionBlockResponseOptions::new(), + IotaTransactionBlockResponseOptions::new(), ExecuteTransactionRequestType::WaitForLocalExecution ]; - let response: SuiTransactionBlockResponse = jsonrpc_client - .request("sui_executeTransactionBlock", params) + let response: IotaTransactionBlockResponse = jsonrpc_client + .request("iota_executeTransactionBlock", params) .await .unwrap(); - let SuiTransactionBlockResponse { + let IotaTransactionBlockResponse { digest, confirmed_local_execution, .. @@ -1003,15 +1004,15 @@ async fn test_full_node_transaction_orchestrator_rpc_ok() -> Result<(), anyhow:: let params = rpc_params![ tx_bytes, signatures, - SuiTransactionBlockResponseOptions::new(), + IotaTransactionBlockResponseOptions::new(), ExecuteTransactionRequestType::WaitForLocalExecution ]; - let response: SuiTransactionBlockResponse = jsonrpc_client - .request("sui_executeTransactionBlock", params) + let response: IotaTransactionBlockResponse = jsonrpc_client + .request("iota_executeTransactionBlock", params) .await .unwrap(); - let SuiTransactionBlockResponse { + let IotaTransactionBlockResponse { digest, confirmed_local_execution, .. @@ -1019,8 +1020,8 @@ async fn test_full_node_transaction_orchestrator_rpc_ok() -> Result<(), anyhow:: assert_eq!(&digest, tx_digest); assert!(confirmed_local_execution.unwrap()); - let _response: SuiTransactionBlockResponse = jsonrpc_client - .request("sui_getTransactionBlock", rpc_params![*tx_digest]) + let _response: IotaTransactionBlockResponse = jsonrpc_client + .request("iota_getTransactionBlock", rpc_params![*tx_digest]) .await .unwrap(); @@ -1029,15 +1030,15 @@ async fn test_full_node_transaction_orchestrator_rpc_ok() -> Result<(), anyhow:: let params = rpc_params![ tx_bytes, signatures, - SuiTransactionBlockResponseOptions::new().with_effects(), + IotaTransactionBlockResponseOptions::new().with_effects(), ExecuteTransactionRequestType::WaitForEffectsCert ]; - let response: SuiTransactionBlockResponse = jsonrpc_client - .request("sui_executeTransactionBlock", params) + let response: IotaTransactionBlockResponse = jsonrpc_client + .request("iota_executeTransactionBlock", params) .await .unwrap(); - let SuiTransactionBlockResponse { + let IotaTransactionBlockResponse { effects, confirmed_local_execution, .. @@ -1049,7 +1050,7 @@ async fn test_full_node_transaction_orchestrator_rpc_ok() -> Result<(), anyhow:: } async fn get_obj_read_from_node( - node: &SuiNodeHandle, + node: &IotaNodeHandle, object_id: ObjectID, ) -> Result<(ObjectRef, Object, Option), anyhow::Error> { if let ObjectRead::Exists(obj_ref, object, layout) = node.state().get_object_read(&object_id)? { @@ -1060,7 +1061,7 @@ async fn get_obj_read_from_node( } async fn get_past_obj_read_from_node( - node: &SuiNodeHandle, + node: &IotaNodeHandle, object_id: ObjectID, seq_num: SequenceNumber, ) -> Result<(ObjectRef, Object, Option), anyhow::Error> { @@ -1078,7 +1079,7 @@ async fn test_get_objects_read() -> Result<(), anyhow::Error> { telemetry_subscribers::init_for_testing(); let test_cluster = TestClusterBuilder::new().build().await; let rgp = test_cluster.get_reference_gas_price().await; - let node = &test_cluster.fullnode_handle.sui_node; + let node = &test_cluster.fullnode_handle.iota_node; let package_id = publish_nfts_package(&test_cluster.wallet).await.0; // Create the object @@ -1107,7 +1108,7 @@ async fn test_get_objects_read() -> Result<(), anyhow::Error> { let (object_ref_v2, object_v2, _) = get_obj_read_from_node(node, object_id).await?; assert_ne!(object_ref_v2, object_ref_v1); - // Transfer some SUI to recipient + // Transfer some IOTA to recipient transfer_coin(&test_cluster.wallet) .await .expect("Failed to transfer coins to recipient"); @@ -1117,7 +1118,7 @@ async fn test_get_objects_read() -> Result<(), anyhow::Error> { delete_devnet_nft(&test_cluster.wallet, recipient, package_id, object_ref_v2).await; assert_eq!( *response.effects.unwrap().status(), - SuiExecutionStatus::Success + IotaExecutionStatus::Success ); sleep(Duration::from_secs(1)).await; @@ -1184,7 +1185,7 @@ async fn test_full_node_bootstrap_from_snapshot() -> Result<(), anyhow::Error> { let checkpoint_path = test_cluster .fullnode_handle - .sui_node + .iota_node .with(|node| node.db_checkpoint_path()); let config = test_cluster .fullnode_config_builder() @@ -1210,7 +1211,7 @@ async fn test_full_node_bootstrap_from_snapshot() -> Result<(), anyhow::Error> { let node = test_cluster .start_fullnode_from_config(config) .await - .sui_node; + .iota_node; node.state() .get_effects_notify_read() @@ -1245,7 +1246,7 @@ async fn test_full_node_bootstrap_from_snapshot() -> Result<(), anyhow::Error> { async fn test_pass_back_no_object() -> Result<(), anyhow::Error> { let mut test_cluster = TestClusterBuilder::new().build().await; let rgp = test_cluster.get_reference_gas_price().await; - let fullnode = test_cluster.spawn_new_fullnode().await.sui_node; + let fullnode = test_cluster.spawn_new_fullnode().await.iota_node; let context = &mut test_cluster.wallet; @@ -1258,7 +1259,7 @@ async fn test_pass_back_no_object() -> Result<(), anyhow::Error> { .unwrap(); // TODO: this is publishing the wrong package - we should be publishing the one - // in `sui-core/src/unit_tests/data` instead. + // in `iota-core/src/unit_tests/data` instead. let package_ref = publish_basics_package(context).await; let gas_obj = context @@ -1323,7 +1324,7 @@ async fn test_access_old_object_pruned() { let sender = tx_builder.sender(); let gas_object = tx_builder.gas_object(); let effects = test_cluster - .sign_and_execute_transaction(&tx_builder.transfer_sui(None, sender).build()) + .sign_and_execute_transaction(&tx_builder.transfer_iota(None, sender).build()) .await .effects .unwrap(); @@ -1336,7 +1337,7 @@ async fn test_access_old_object_pruned() { .await // Make sure we are doing something different from the first transaction. // Otherwise we would just end up with the same digest. - .transfer_sui(Some(1), sender) + .transfer_iota(Some(1), sender) .build(), ); for validator in test_cluster.swarm.active_validators() { @@ -1359,7 +1360,7 @@ async fn test_access_old_object_pruned() { ) .await .unwrap_err(), - SuiError::UserInputError { + IotaError::UserInputError { error: UserInputError::ObjectVersionUnavailableForConsumption { provided_obj_ref: gas_object, current_version: new_gas_version, @@ -1386,8 +1387,8 @@ async fn transfer_coin( ) -> Result< ( ObjectID, - SuiAddress, - SuiAddress, + IotaAddress, + IotaAddress, TransactionDigest, ObjectRef, ), @@ -1426,7 +1427,7 @@ async fn test_full_node_run_with_range_checkpoint() -> Result<(), anyhow::Error> assert_eq!(got_run_with_range, want_run_with_range); // ensure the highest synced checkpoint matches - assert!(test_cluster.fullnode_handle.sui_node.with(|node| { + assert!(test_cluster.fullnode_handle.iota_node.with(|node| { node.state() .get_checkpoint_store() .get_highest_executed_checkpoint_seq_number() @@ -1438,7 +1439,7 @@ async fn test_full_node_run_with_range_checkpoint() -> Result<(), anyhow::Error> tokio::time::sleep(tokio::time::Duration::from_secs(15)).await; // verify again execution has not progressed beyond expectations - assert!(test_cluster.fullnode_handle.sui_node.with(|node| { + assert!(test_cluster.fullnode_handle.iota_node.with(|node| { node.state() .get_checkpoint_store() .get_highest_executed_checkpoint_seq_number() @@ -1450,7 +1451,7 @@ async fn test_full_node_run_with_range_checkpoint() -> Result<(), anyhow::Error> assert!( test_cluster .fullnode_handle - .sui_node + .iota_node .with(|node| node.transaction_orchestrator()) .is_none() ); @@ -1480,7 +1481,7 @@ async fn test_full_node_run_with_range_epoch() -> Result<(), anyhow::Error> { assert!( test_cluster .fullnode_handle - .sui_node + .iota_node .with(|node| node.current_epoch_for_testing() == stop_after_epoch + 1) ); @@ -1492,7 +1493,7 @@ async fn test_full_node_run_with_range_epoch() -> Result<(), anyhow::Error> { assert!( test_cluster .fullnode_handle - .sui_node + .iota_node .with(|node| node.current_epoch_for_testing() == stop_after_epoch + 1) ); @@ -1500,7 +1501,7 @@ async fn test_full_node_run_with_range_epoch() -> Result<(), anyhow::Error> { assert!( test_cluster .fullnode_handle - .sui_node + .iota_node .with(|node| node.transaction_orchestrator()) .is_none() ); diff --git a/crates/iota-e2e-tests/tests/move_test_code/Move.toml b/crates/iota-e2e-tests/tests/move_test_code/Move.toml new file mode 100644 index 00000000000..61b80407047 --- /dev/null +++ b/crates/iota-e2e-tests/tests/move_test_code/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "move_test_code" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../iota-framework/packages/iota-framework" } + +[addresses] +move_test_code = "0x0" diff --git a/crates/iota-e2e-tests/tests/move_test_code/sources/regulated_coin.move b/crates/iota-e2e-tests/tests/move_test_code/sources/regulated_coin.move new file mode 100644 index 00000000000..e35f14426e7 --- /dev/null +++ b/crates/iota-e2e-tests/tests/move_test_code/sources/regulated_coin.move @@ -0,0 +1,33 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module move_test_code::regulated_coin { + use std::option; + use iota::coin; + use iota::object::UID; + use iota::transfer; + use iota::tx_context; + use iota::tx_context::TxContext; + + struct REGULATED_COIN has drop {} + + struct Wallet has key { + id: UID, + } + + fun init(otw: REGULATED_COIN, ctx: &mut TxContext) { + let (treasury_cap, deny_cap, metadata) = coin::create_regulated_currency( + otw, + 9, + b"RC", + b"REGULATED_COIN", + b"A new regulated coin", + option::none(), + ctx + ); + transfer::public_transfer(deny_cap, tx_context::sender(ctx)); + transfer::public_freeze_object(treasury_cap); + transfer::public_freeze_object(metadata); + } +} diff --git a/crates/sui-e2e-tests/tests/move_test_code/sources/shared_objects_version.move b/crates/iota-e2e-tests/tests/move_test_code/sources/shared_objects_version.move similarity index 84% rename from crates/sui-e2e-tests/tests/move_test_code/sources/shared_objects_version.move rename to crates/iota-e2e-tests/tests/move_test_code/sources/shared_objects_version.move index 1f4ebf4ecd8..07c90b1f523 100644 --- a/crates/sui-e2e-tests/tests/move_test_code/sources/shared_objects_version.move +++ b/crates/iota-e2e-tests/tests/move_test_code/sources/shared_objects_version.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module move_test_code::shared_objects_version { - use sui::object::{Self, UID}; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; + use iota::object::{Self, UID}; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; struct Counter has key { id: UID, diff --git a/crates/iota-e2e-tests/tests/move_test_code/sources/tto1.move b/crates/iota-e2e-tests/tests/move_test_code/sources/tto1.move new file mode 100644 index 00000000000..435c841f33b --- /dev/null +++ b/crates/iota-e2e-tests/tests/move_test_code/sources/tto1.move @@ -0,0 +1,38 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module move_test_code::tto { + use iota::object::{Self, UID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer::{Self, Receiving}; + + struct A has key, store { + id: UID, + } + + struct B has key, store { + id: UID, + } + + public fun start(ctx: &mut TxContext) { + let a = A { id: object::new(ctx) }; + let a_address = object::id_address(&a); + let b = B { id: object::new(ctx) }; + let c = B { id: object::new(ctx) }; + transfer::share_object(c); + transfer::public_transfer(a, tx_context::sender(ctx)); + transfer::public_transfer(b, a_address); + } + + public entry fun receiver(parent: &mut A, x: Receiving) { + let b = transfer::receive(&mut parent.id, x); + // transfer back to the parent so we can reuse + transfer::public_transfer(b, object::id_address(parent)); + } + + public entry fun deleter(parent: &mut A, x: Receiving) { + let B { id } = transfer::receive(&mut parent.id, x); + object::delete(id); + } +} diff --git a/crates/iota-e2e-tests/tests/multisig_tests.rs b/crates/iota-e2e-tests/tests/multisig_tests.rs new file mode 100644 index 00000000000..1142bf04af6 --- /dev/null +++ b/crates/iota-e2e-tests/tests/multisig_tests.rs @@ -0,0 +1,819 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use fastcrypto::traits::EncodeDecodeBase64; +use iota_core::authority_client::AuthorityAPI; +use iota_macros::sim_test; +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ + base_types::IotaAddress, + crypto::{ + get_key_pair, CompressedSignature, IotaKeyPair, PublicKey, Signature, + ZkLoginAuthenticatorAsBytes, ZkLoginPublicIdentifier, + }, + error::{IotaError, IotaResult}, + multisig::{MultiSig, MultiSigPublicKey}, + multisig_legacy::MultiSigPublicKeyLegacy, + signature::GenericSignature, + transaction::Transaction, + utils::{keys, load_test_vectors, make_upgraded_multisig_tx}, + zk_login_authenticator::ZkLoginAuthenticator, +}; +use shared_crypto::intent::{Intent, IntentMessage}; +use test_cluster::{TestCluster, TestClusterBuilder}; +async fn do_upgraded_multisig_test() -> IotaResult { + let test_cluster = TestClusterBuilder::new().build().await; + let tx = make_upgraded_multisig_tx(); + + test_cluster + .authority_aggregator() + .authority_clients + .values() + .next() + .unwrap() + .authority_client() + .handle_transaction(tx) + .await + .map(|_| ()) +} + +#[sim_test] +async fn test_upgraded_multisig_feature_deny() { + use iota_protocol_config::ProtocolConfig; + + let _guard = ProtocolConfig::apply_overrides_for_testing(|_, mut config| { + config.set_upgraded_multisig_for_testing(false); + config + }); + + let err = do_upgraded_multisig_test().await.unwrap_err(); + + assert!(matches!(err, IotaError::UnsupportedFeatureError { .. })); +} + +#[sim_test] +async fn test_upgraded_multisig_feature_allow() { + use iota_protocol_config::ProtocolConfig; + + let _guard = ProtocolConfig::apply_overrides_for_testing(|_, mut config| { + config.set_upgraded_multisig_for_testing(true); + config + }); + + let res = do_upgraded_multisig_test().await; + + // we didn't make a real transaction with a valid object, but we verify that we + // pass the feature gate. + assert!(matches!(res.unwrap_err(), IotaError::UserInputError { .. })); +} + +#[sim_test] +async fn test_multisig_e2e() { + let test_cluster = TestClusterBuilder::new().build().await; + let context = &test_cluster.wallet; + let rgp = test_cluster.get_reference_gas_price().await; + + let keys = keys(); + let pk0 = keys[0].public(); // ed25519 + let pk1 = keys[1].public(); // secp256k1 + let pk2 = keys[2].public(); // secp256r1 + + let multisig_pk = MultiSigPublicKey::insecure_new( + vec![(pk0.clone(), 1), (pk1.clone(), 1), (pk2.clone(), 1)], + 2, + ); + let multisig_addr = IotaAddress::from(&multisig_pk); + + // fund wallet and get a gas object to use later. + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) + .await; + + // 1. sign with key 0 and 1 executes successfully. + let tx1 = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build_and_sign_multisig(multisig_pk.clone(), &[&keys[0], &keys[1]], 0b011); + let res = context.execute_transaction_must_succeed(tx1).await; + assert!(res.status_ok().unwrap()); + + // 2. sign with key 1 and 2 executes successfully. + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) + .await; + let tx2 = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build_and_sign_multisig(multisig_pk.clone(), &[&keys[1], &keys[2]], 0b110); + let res = context.execute_transaction_must_succeed(tx2).await; + assert!(res.status_ok().unwrap()); + + // 3. signature 2 and 1 swapped fails to execute. + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) + .await; + let tx3 = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build_and_sign_multisig(multisig_pk.clone(), &[&keys[2], &keys[1]], 0b110); + let res = context.execute_transaction_may_fail(tx3).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Invalid sig for pk=AQIOF81ZOeRrGWZBlozXWZELold+J/pz/eOHbbm+xbzrKw==") + ); + + // 4. sign with key 0 only is below threshold, fails to execute. + let tx4 = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build_and_sign_multisig(multisig_pk.clone(), &[&keys[0]], 0b001); + let res = context.execute_transaction_may_fail(tx4).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Insufficient weight=1 threshold=2") + ); + + // 5. multisig with no single sig fails to execute. + let tx5 = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build_and_sign_multisig(multisig_pk.clone(), &[], 0b001); + let res = context.execute_transaction_may_fail(tx5).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Invalid value was given to the function") + ); + + // 6. multisig two dup sigs fails to execute. + let tx6 = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build_and_sign_multisig(multisig_pk.clone(), &[&keys[0], &keys[0]], 0b011); + let res = context.execute_transaction_may_fail(tx6).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Invalid ed25519 pk bytes") + ); + + // 7. mismatch pks in sig with multisig address fails to execute. + let kp3: IotaKeyPair = IotaKeyPair::Secp256r1(get_key_pair().1); + let pk3 = kp3.public(); + let wrong_multisig_pk = MultiSigPublicKey::new( + vec![pk0.clone(), pk1.clone(), pk3.clone()], + vec![1, 1, 1], + 2, + ) + .unwrap(); + let wrong_sender = IotaAddress::from(&wrong_multisig_pk); + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), wrong_sender) + .await; + let tx7 = TestTransactionBuilder::new(wrong_sender, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build_and_sign_multisig(wrong_multisig_pk.clone(), &[&keys[0], &keys[2]], 0b101); + let res = context.execute_transaction_may_fail(tx7).await; + assert!( + res.unwrap_err() + .to_string() + .contains(format!("Invalid sig for pk={}", pk3.encode_base64()).as_str()) + ); +} + +#[sim_test] +async fn test_multisig_with_zklogin_scenerios() { + let test_cluster = TestClusterBuilder::new() + .with_epoch_duration_ms(15000) + .with_default_jwks() + .build() + .await; + + test_cluster.wait_for_epoch(Some(1)).await; + + let rgp = test_cluster.get_reference_gas_price().await; + let context = &test_cluster.wallet; + + let keys = keys(); + let pk0 = keys[0].public(); // ed25519 + let pk1 = keys[1].public(); // secp256k1 + let pk2 = keys[2].public(); // secp256r1 + + // construct a multisig address with 4 pks (ed25519, secp256k1, secp256r1, + // zklogin) with threshold = 1. + let (eph_kp, _eph_pk, zklogin_inputs) = + &load_test_vectors("../iota-types/src/unit_tests/zklogin_test_vectors.json")[1]; + let (eph_kp_1, _, _) = + &load_test_vectors("../iota-types/src/unit_tests/zklogin_test_vectors.json")[2]; + let zklogin_pk = PublicKey::ZkLogin( + ZkLoginPublicIdentifier::new(zklogin_inputs.get_iss(), zklogin_inputs.get_address_seed()) + .unwrap(), + ); + let multisig_pk = MultiSigPublicKey::new( + vec![pk0.clone(), pk1.clone(), pk2.clone(), zklogin_pk.clone()], + vec![1, 1, 1, 1], + 1, + ) + .unwrap(); + + // fund the multisig address. + let multisig_addr = IotaAddress::from(&multisig_pk); + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) + .await; + let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let wrong_intent_msg = IntentMessage::new(Intent::personal_message(), tx_data.clone()); + + // 1. a multisig with a bad ed25519 sig fails to execute. + let wrong_sig: GenericSignature = Signature::new_secure(&wrong_intent_msg, &keys[0]).into(); + let multisig = GenericSignature::MultiSig( + MultiSig::combine(vec![wrong_sig], multisig_pk.clone()).unwrap(), + ); + let tx_1 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_1).await; + assert!( + res.unwrap_err() + .to_string() + .contains(format!("Invalid sig for pk={}", pk0.encode_base64()).as_str()) + ); + + // 2. a multisig with a bad secp256k1 sig fails to execute. + let wrong_sig_2: GenericSignature = Signature::new_secure(&wrong_intent_msg, &keys[1]).into(); + let multisig = GenericSignature::MultiSig( + MultiSig::combine(vec![wrong_sig_2], multisig_pk.clone()).unwrap(), + ); + let tx_2 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_2).await; + assert!( + res.unwrap_err() + .to_string() + .contains(format!("Invalid sig for pk={}", pk1.encode_base64()).as_str()) + ); + + // 3. a multisig with a bad secp256r1 sig fails to execute. + let wrong_sig_3: GenericSignature = Signature::new_secure(&wrong_intent_msg, &keys[2]).into(); + let multisig = GenericSignature::MultiSig( + MultiSig::combine(vec![wrong_sig_3], multisig_pk.clone()).unwrap(), + ); + let tx_3 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_3).await; + assert!( + res.unwrap_err() + .to_string() + .contains(format!("Invalid sig for pk={}", pk2.encode_base64()).as_str()) + ); + + // 4. a multisig with a bad ephemeral sig inside zklogin sig fails to execute. + let wrong_eph_sig = Signature::new_secure(&wrong_intent_msg, eph_kp); + let wrong_zklogin_sig = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( + zklogin_inputs.clone(), + 2, + wrong_eph_sig, + )); + let multisig = GenericSignature::MultiSig( + MultiSig::combine(vec![wrong_zklogin_sig], multisig_pk.clone()).unwrap(), + ); + let tx_4 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_4).await; + let pk3 = PublicKey::ZkLogin( + ZkLoginPublicIdentifier::new(zklogin_inputs.get_iss(), zklogin_inputs.get_address_seed()) + .unwrap(), + ); + assert!( + res.unwrap_err() + .to_string() + .contains(format!("Invalid sig for pk={}", pk3.encode_base64()).as_str()) + ); + + // 5. a multisig with a mismatch ephermeal sig and zklogin inputs fails to + // execute. + let eph_sig = Signature::new_secure(&intent_msg, eph_kp_1); + let zklogin_sig_mismatch = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( + zklogin_inputs.clone(), + 2, + eph_sig, + )); + let multisig = GenericSignature::MultiSig( + MultiSig::combine(vec![zklogin_sig_mismatch], multisig_pk.clone()).unwrap(), + ); + let tx_5 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_5).await; + assert!( + res.unwrap_err() + .to_string() + .contains(format!("Invalid sig for pk={}", pk3.encode_base64()).as_str()) + ); + + // 6. a multisig with an inconsistent max_epoch with zk proof itself fails to + // execute. + let eph_sig = Signature::new_secure(&intent_msg, eph_kp); + let zklogin_sig_wrong_zklogin_inputs = GenericSignature::ZkLoginAuthenticator( + ZkLoginAuthenticator::new(zklogin_inputs.clone(), 1, eph_sig), /* max_epoch set to 1 + * instead of 2 */ + ); + let multisig = GenericSignature::MultiSig( + MultiSig::combine(vec![zklogin_sig_wrong_zklogin_inputs], multisig_pk.clone()).unwrap(), + ); + let tx_7 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_7).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Groth16 proof verify failed") + ); + + // 7. a multisig with the wrong sender fails to execute. + let wrong_multisig_addr = IotaAddress::from( + &MultiSigPublicKey::new( + vec![pk0.clone(), pk1.clone(), pk2.clone()], + vec![1, 1, 1], + 1, + ) + .unwrap(), + ); + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), wrong_multisig_addr) + .await; + let tx_data = TestTransactionBuilder::new(wrong_multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let sig_4: GenericSignature = ZkLoginAuthenticator::new( + zklogin_inputs.clone(), + 2, + Signature::new_secure(&intent_msg, eph_kp), + ) + .into(); + let multisig = + GenericSignature::MultiSig(MultiSig::combine(vec![sig_4], multisig_pk.clone()).unwrap()); + let tx_8 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_8).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Required Signature from") + ); + + // 8. a multisig with zklogin sig of invalid compact signature bytes fails to + // execute. + let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( + vec![CompressedSignature::ZkLogin(ZkLoginAuthenticatorAsBytes( + vec![0], + ))], + 0b1000, + multisig_pk.clone(), + )); + let tx_7 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_7).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Invalid zklogin authenticator bytes") + ); + + // assert positive case for all 4 participanting parties. + // 1a. good ed25519 sig used in multisig executes successfully. + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) + .await; + let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let sig_0: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); + let multisig = + GenericSignature::MultiSig(MultiSig::combine(vec![sig_0], multisig_pk.clone()).unwrap()); + let tx_8 = Transaction::from_generic_sig_data(tx_data, vec![multisig]); + let _ = context.execute_transaction_must_succeed(tx_8).await; + + // 2a. good secp256k1 sig used in multisig executes successfully. + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) + .await; + let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let sig_1: GenericSignature = Signature::new_secure(&intent_msg, &keys[1]).into(); + let multisig = + GenericSignature::MultiSig(MultiSig::combine(vec![sig_1], multisig_pk.clone()).unwrap()); + let tx_9 = Transaction::from_generic_sig_data(tx_data, vec![multisig]); + let _ = context.execute_transaction_must_succeed(tx_9).await; + + // 3a. good secp256r1 sig used in multisig executes successfully. + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) + .await; + let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let sig_2: GenericSignature = Signature::new_secure(&intent_msg, &keys[2]).into(); + let multisig = + GenericSignature::MultiSig(MultiSig::combine(vec![sig_2], multisig_pk.clone()).unwrap()); + let tx_9 = Transaction::from_generic_sig_data(tx_data, vec![multisig]); + let _ = context.execute_transaction_must_succeed(tx_9).await; + + // 4b. good zklogin sig used in multisig executes successfully. + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) + .await; + let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let sig_4: GenericSignature = ZkLoginAuthenticator::new( + zklogin_inputs.clone(), + 2, + Signature::new_secure(&intent_msg, eph_kp), + ) + .into(); + let multisig = + GenericSignature::MultiSig(MultiSig::combine(vec![sig_4], multisig_pk.clone()).unwrap()); + let tx_10 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let _ = context.execute_transaction_must_succeed(tx_10).await; + + // 4c. good zklogin sig AND good ed25519 combined used in multisig executes + // successfully. + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) + .await; + let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); + let sig_1: GenericSignature = ZkLoginAuthenticator::new( + zklogin_inputs.clone(), + 2, + Signature::new_secure(&intent_msg, eph_kp), + ) + .into(); + let multisig = GenericSignature::MultiSig( + MultiSig::combine(vec![sig, sig_1], multisig_pk.clone()).unwrap(), + ); + let tx_11 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let _ = context.execute_transaction_must_succeed(tx_11).await; + + // 9. wrong bitmap fails to execute. + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) + .await; + let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); + let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( + vec![sig.to_compressed().unwrap()], + 0b0010, + multisig_pk.clone(), + )); + let tx_11 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_11).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Invalid ed25519 pk bytes") + ); + + // 10. invalid bitmap b10000 when the max bitmap for 4 pks is b1111, fails to + // execute. + let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( + vec![sig.clone().to_compressed().unwrap()], + 1 << 4, + multisig_pk.clone(), + )); + let tx_10 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_10).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Invalid public keys index") + ); + + // 11. malformed multisig pk where threshold = 0, fails to execute. + let bad_multisig_pk = MultiSigPublicKey::insecure_new( + vec![(pk0.clone(), 1), (pk1.clone(), 1), (pk2.clone(), 1)], + 0, + ); + let bad_multisig_addr = IotaAddress::from(&bad_multisig_pk); + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), bad_multisig_addr) + .await; + let tx_data = TestTransactionBuilder::new(bad_multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); + let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( + vec![sig.to_compressed().unwrap()], + 0b001, + bad_multisig_pk.clone(), + )); + let tx_11 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_11).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Invalid value was given to the function") + ); + + // 12. malformed multisig a pk has weight = 0, fails to execute. + let bad_multisig_pk_2 = MultiSigPublicKey::insecure_new( + vec![(pk0.clone(), 1), (pk1.clone(), 1), (pk2.clone(), 0)], + 1, + ); + let bad_multisig_addr_2 = IotaAddress::from(&bad_multisig_pk_2); + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), bad_multisig_addr_2) + .await; + let tx_data = TestTransactionBuilder::new(bad_multisig_addr_2, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); + let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( + vec![sig.to_compressed().unwrap()], + 2, + bad_multisig_pk, + )); + let tx_14 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_14).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Invalid value was given to the function") + ); + + // 13. pass in 2 sigs when only 1 pk in multisig_pk, fails to execute. + let small_multisig_pk = MultiSigPublicKey::insecure_new(vec![(pk0.clone(), 1)], 1); + let bad_multisig_addr_3 = IotaAddress::from(&small_multisig_pk); + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), bad_multisig_addr_3) + .await; + let tx_data = TestTransactionBuilder::new(bad_multisig_addr_3, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); + let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( + vec![sig.to_compressed().unwrap(), sig.to_compressed().unwrap()], + 0b1, + small_multisig_pk, + )); + let tx_13 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_13).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Invalid value was given to the function") + ); + + // 14. pass a multisig where there is dup pk in multisig_pk, fails to execute. + let multisig_pk_with_dup = + MultiSigPublicKey::insecure_new(vec![(pk0.clone(), 1), (pk0.clone(), 1)], 1); + let bad_multisig_addr_4 = IotaAddress::from(&multisig_pk_with_dup); + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), bad_multisig_addr_4) + .await; + let tx_data = TestTransactionBuilder::new(bad_multisig_addr_4, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); + let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( + vec![sig.to_compressed().unwrap()], + 0b01, + multisig_pk_with_dup, + )); + let tx_14 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_14).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Invalid value was given to the function") + ); + + // 15. a sig with 11 pks fails to execute. + let multisig_pk_11 = MultiSigPublicKey::insecure_new(vec![(pk0.clone(), 1); 11], 1); + let bad_multisig_addr_11 = IotaAddress::from(&multisig_pk_11); + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), bad_multisig_addr_11) + .await; + let tx_data = TestTransactionBuilder::new(bad_multisig_addr_11, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); + let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( + vec![sig.to_compressed().unwrap()], + 0b00000000001, + multisig_pk_11, + )); + let tx_15 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_15).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Invalid value was given to the function") + ); + + // 16. total weight of all pks < threshold fails to execute. + let multisig_pk_12 = + MultiSigPublicKey::insecure_new(vec![(pk0.clone(), 1), (pk0.clone(), 1)], 3); + let bad_multisig_addr = IotaAddress::from(&multisig_pk_12); + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), bad_multisig_addr) + .await; + let tx_data = TestTransactionBuilder::new(bad_multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); + let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( + vec![sig.to_compressed().unwrap()], + 0b00000000001, + multisig_pk_12, + )); + let tx_16 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_16).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Invalid value was given to the function") + ); + + // 17. multisig with empty pk map fails to execute. + let bad_multisig_empty_pk = MultiSigPublicKey::insecure_new(vec![], 1); + let bad_multisig_addr = IotaAddress::from(&bad_multisig_empty_pk); + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), bad_multisig_addr) + .await; + let tx_data = TestTransactionBuilder::new(bad_multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); + let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( + vec![sig.to_compressed().unwrap()], + 0b01, + bad_multisig_empty_pk, + )); + let tx_17 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let res = context.execute_transaction_may_fail(tx_17).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Invalid value was given to the function") + ); +} + +#[sim_test] +async fn test_expired_epoch_zklogin_in_multisig() { + let test_cluster = TestClusterBuilder::new() + .with_epoch_duration_ms(10000) + .with_default_jwks() + .build() + .await; + test_cluster.wait_for_epoch(Some(3)).await; + let tx = construct_simple_zklogin_multisig_tx(&test_cluster).await; + let res = test_cluster.wallet.execute_transaction_may_fail(tx).await; + assert!( + res.unwrap_err() + .to_string() + .contains("ZKLogin expired at epoch 2") + ); +} + +#[sim_test] +async fn test_random_zklogin_in_multisig() { + let test_vectors = + &load_test_vectors("../iota-types/src/unit_tests/zklogin_test_vectors.json")[1..11]; + let test_cluster = TestClusterBuilder::new().with_default_jwks().build().await; + test_cluster.wait_for_authenticator_state_update().await; + let rgp = test_cluster.get_reference_gas_price().await; + let context = &test_cluster.wallet; + + // create a multisig with 10 zklogin pks. + let pks = test_vectors.iter().map(|(_, pk, _)| pk.clone()).collect(); + let multisig_pk = MultiSigPublicKey::new(pks, vec![1; 10], 10).unwrap(); + let multisig_addr = IotaAddress::from(&multisig_pk); + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) + .await; + let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let mut zklogin_sigs = vec![]; + for (kp, _pk, inputs) in test_vectors { + let eph_sig = Signature::new_secure(&intent_msg, kp); + let zklogin_sig = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( + inputs.clone(), + 2, + eph_sig, + )); + zklogin_sigs.push(zklogin_sig); + } + let short_multisig = GenericSignature::MultiSig( + MultiSig::combine(zklogin_sigs[..9].to_vec(), multisig_pk.clone()).unwrap(), + ); + let bad_tx = Transaction::from_generic_sig_data(tx_data.clone(), vec![short_multisig]); + let res = context.execute_transaction_may_fail(bad_tx).await; + assert!( + res.unwrap_err() + .to_string() + .contains("Insufficient weight=9 threshold=10") + ); + + let multisig = GenericSignature::MultiSig( + MultiSig::combine(zklogin_sigs.clone(), multisig_pk.clone()).unwrap(), + ); + let tx = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); + let _ = context.execute_transaction_must_succeed(tx).await; +} +#[sim_test] +async fn test_multisig_legacy_works() { + let test_cluster = TestClusterBuilder::new().build().await; + let rgp = test_cluster.get_reference_gas_price().await; + + let keys = keys(); + let pk1 = keys[0].public(); + let pk2 = keys[1].public(); + let pk3 = keys[2].public(); + + let multisig_pk_legacy = MultiSigPublicKeyLegacy::new( + vec![pk1.clone(), pk2.clone(), pk3.clone()], + vec![1, 1, 1], + 2, + ) + .unwrap(); + let multisig_pk = MultiSigPublicKey::new( + vec![pk1.clone(), pk2.clone(), pk3.clone()], + vec![1, 1, 1], + 2, + ) + .unwrap(); + let multisig_addr = IotaAddress::from(&multisig_pk); + let context = &test_cluster.wallet; + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) + .await; + let transfer_from_multisig = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(Some(1000000), IotaAddress::ZERO) + .build_and_sign_multisig_legacy(multisig_pk_legacy, &[&keys[0], &keys[1]]); + + context + .execute_transaction_must_succeed(transfer_from_multisig) + .await; +} + +#[sim_test] +async fn test_zklogin_inside_multisig_feature_deny() { + use iota_protocol_config::ProtocolConfig; + + // if feature disabled, fails to execute. + let _guard = ProtocolConfig::apply_overrides_for_testing(|_, mut config| { + config.set_accept_zklogin_in_multisig_for_testing(false); + config + }); + let test_cluster = TestClusterBuilder::new().with_default_jwks().build().await; + test_cluster.wait_for_authenticator_state_update().await; + let tx = construct_simple_zklogin_multisig_tx(&test_cluster).await; + let res = test_cluster.wallet.execute_transaction_may_fail(tx).await; + assert!( + res.unwrap_err() + .to_string() + .contains("zkLogin sig not supported inside multisig") + ); +} + +async fn construct_simple_zklogin_multisig_tx(test_cluster: &TestCluster) -> Transaction { + // construct a multisig address with 1 zklogin pk with threshold = 1. + let (eph_kp, _eph_pk, zklogin_inputs) = + &load_test_vectors("../iota-types/src/unit_tests/zklogin_test_vectors.json")[1]; + let zklogin_pk = PublicKey::ZkLogin( + ZkLoginPublicIdentifier::new(zklogin_inputs.get_iss(), zklogin_inputs.get_address_seed()) + .unwrap(), + ); + let multisig_pk = MultiSigPublicKey::insecure_new(vec![(zklogin_pk.clone(), 1)], 1); + let rgp = test_cluster.get_reference_gas_price().await; + + let multisig_addr = IotaAddress::from(&multisig_pk); + let gas = test_cluster + .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) + .await; + let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) + .transfer_iota(None, IotaAddress::ZERO) + .build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); + let sig_4: GenericSignature = ZkLoginAuthenticator::new( + zklogin_inputs.clone(), + 2, + Signature::new_secure(&intent_msg, eph_kp), + ) + .into(); + let multisig = + GenericSignature::MultiSig(MultiSig::combine(vec![sig_4], multisig_pk.clone()).unwrap()); + Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]) +} diff --git a/crates/sui-e2e-tests/tests/object_deletion_tests.rs b/crates/iota-e2e-tests/tests/object_deletion_tests.rs similarity index 93% rename from crates/sui-e2e-tests/tests/object_deletion_tests.rs rename to crates/iota-e2e-tests/tests/object_deletion_tests.rs index 4c46e037369..4465e576e1f 100644 --- a/crates/sui-e2e-tests/tests/object_deletion_tests.rs +++ b/crates/iota-e2e-tests/tests/object_deletion_tests.rs @@ -1,19 +1,20 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[cfg(msim)] mod sim_only_tests { use std::{path::PathBuf, time::Duration}; - use sui_core::{ + use iota_core::{ authority::authority_store_tables::LiveObject, state_accumulator::AccumulatorStore, }; - use sui_json_rpc_types::{SuiTransactionBlockEffects, SuiTransactionBlockEffectsAPI}; - use sui_macros::sim_test; - use sui_node::SuiNode; - use sui_protocol_config::{ProtocolConfig, ProtocolVersion, SupportedProtocolVersions}; - use sui_test_transaction_builder::publish_package; - use sui_types::{ + use iota_json_rpc_types::{IotaTransactionBlockEffects, IotaTransactionBlockEffectsAPI}; + use iota_macros::sim_test; + use iota_node::IotaNode; + use iota_protocol_config::{ProtocolConfig, ProtocolVersion, SupportedProtocolVersions}; + use iota_test_transaction_builder::publish_package; + use iota_types::{ base_types::ObjectID, digests::TransactionDigest, messages_checkpoint::CheckpointSequenceNumber, }; @@ -81,7 +82,7 @@ mod sim_only_tests { #[sim_test] async fn object_pruning_test() { let test_cluster = TestClusterBuilder::new().build().await; - let fullnode = &test_cluster.fullnode_handle.sui_node; + let fullnode = &test_cluster.fullnode_handle.iota_node; // Create a root object and a child object. Wrap the child object inside the // root object. @@ -192,7 +193,7 @@ mod sim_only_tests { let package_id = publish_package( &test_cluster.wallet, PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("../sui-surfer/tests/move_building_blocks"), + .join("../iota-surfer/tests/move_building_blocks"), ) .await .0; @@ -238,7 +239,7 @@ mod sim_only_tests { package_id: ObjectID, object_id: ObjectID, child_id: ObjectID, - ) -> SuiTransactionBlockEffects { + ) -> IotaTransactionBlockEffects { let object = test_cluster.wallet.get_object_ref(object_id).await.unwrap(); let child = test_cluster.wallet.get_object_ref(child_id).await.unwrap(); let effects = test_cluster @@ -272,7 +273,7 @@ mod sim_only_tests { test_cluster: &TestCluster, package_id: ObjectID, object_id: ObjectID, - ) -> SuiTransactionBlockEffects { + ) -> IotaTransactionBlockEffects { let object = test_cluster.wallet.get_object_ref(object_id).await.unwrap(); let effects = test_cluster .sign_and_execute_transaction( @@ -298,7 +299,7 @@ mod sim_only_tests { test_cluster: &TestCluster, package_id: ObjectID, object_id: ObjectID, - ) -> SuiTransactionBlockEffects { + ) -> IotaTransactionBlockEffects { let object = test_cluster.wallet.get_object_ref(object_id).await.unwrap(); let effects = test_cluster .sign_and_execute_transaction( @@ -318,11 +319,11 @@ mod sim_only_tests { fn count_fullnode_wrapped_tombstones(test_cluster: &TestCluster) -> usize { test_cluster .fullnode_handle - .sui_node + .iota_node .with(|node| count_wrapped_tombstone(node)) } - fn count_wrapped_tombstone(node: &SuiNode) -> usize { + fn count_wrapped_tombstone(node: &IotaNode) -> usize { let store = node.state().get_execution_cache(); store .iter_live_object_set(true) @@ -331,7 +332,7 @@ mod sim_only_tests { } async fn wait_until_txn_in_checkpoint( - node: &SuiNode, + node: &IotaNode, digest: &TransactionDigest, ) -> CheckpointSequenceNumber { loop { @@ -347,7 +348,7 @@ mod sim_only_tests { } } - async fn wait_until_checkpoint_pruned(node: &SuiNode, checkpoint: CheckpointSequenceNumber) { + async fn wait_until_checkpoint_pruned(node: &IotaNode, checkpoint: CheckpointSequenceNumber) { loop { if node .state() diff --git a/crates/sui-e2e-tests/tests/onsite_reconfig_observer_tests.rs b/crates/iota-e2e-tests/tests/onsite_reconfig_observer_tests.rs similarity index 93% rename from crates/sui-e2e-tests/tests/onsite_reconfig_observer_tests.rs rename to crates/iota-e2e-tests/tests/onsite_reconfig_observer_tests.rs index 458a8d1c4d5..c86a9a098d8 100644 --- a/crates/sui-e2e-tests/tests/onsite_reconfig_observer_tests.rs +++ b/crates/iota-e2e-tests/tests/onsite_reconfig_observer_tests.rs @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use prometheus::Registry; -use sui_core::{ +use iota_core::{ authority_aggregator::AuthAggMetrics, quorum_driver::reconfig_observer::{OnsiteReconfigObserver, ReconfigObserver}, safe_client::SafeClientMetricsBase, }; -use sui_macros::sim_test; +use iota_macros::sim_test; +use prometheus::Registry; use test_cluster::TestClusterBuilder; use tracing::info; @@ -19,7 +20,7 @@ async fn test_onsite_reconfig_observer_basic() { .build() .await; - let fullnode = &test_cluster.fullnode_handle.sui_node; + let fullnode = &test_cluster.fullnode_handle.iota_node; let qd = fullnode.with(|node| { node.transaction_orchestrator() diff --git a/crates/sui-e2e-tests/tests/protocol_version_tests.rs b/crates/iota-e2e-tests/tests/protocol_version_tests.rs similarity index 86% rename from crates/sui-e2e-tests/tests/protocol_version_tests.rs rename to crates/iota-e2e-tests/tests/protocol_version_tests.rs index ee63bc3c32f..46dcfed07e7 100644 --- a/crates/sui-e2e-tests/tests/protocol_version_tests.rs +++ b/crates/iota-e2e-tests/tests/protocol_version_tests.rs @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use sui_protocol_config::{ProtocolConfig, ProtocolVersion, SupportedProtocolVersions}; +use iota_protocol_config::{ProtocolConfig, ProtocolVersion, SupportedProtocolVersions}; use test_cluster::TestClusterBuilder; #[tokio::test] @@ -57,35 +58,35 @@ mod sim_only_tests { use std::{path::PathBuf, sync::Arc}; use fastcrypto::encoding::Base64; - use move_binary_format::CompiledModule; - use move_core_types::ident_str; - use sui_core::authority::framework_injection; - use sui_framework::BuiltInFramework; - use sui_json_rpc_api::WriteApiClient; - use sui_json_rpc_types::{SuiTransactionBlockEffects, SuiTransactionBlockEffectsAPI}; - use sui_macros::*; - use sui_move_build::{BuildConfig, CompiledPackage}; - use sui_protocol_config::SupportedProtocolVersions; - use sui_types::{ - base_types::{ConciseableName, ObjectID, ObjectRef, SequenceNumber, SuiAddress}, + use iota_core::authority::framework_injection; + use iota_framework::BuiltInFramework; + use iota_json_rpc_api::WriteApiClient; + use iota_json_rpc_types::{IotaTransactionBlockEffects, IotaTransactionBlockEffectsAPI}; + use iota_macros::*; + use iota_move_build::{BuildConfig, CompiledPackage}; + use iota_protocol_config::SupportedProtocolVersions; + use iota_types::{ + base_types::{ConciseableName, IotaAddress, ObjectID, ObjectRef, SequenceNumber}, digests::TransactionDigest, effects::{TransactionEffects, TransactionEffectsAPI}, id::ID, + iota_system_state::{ + epoch_start_iota_system_state::EpochStartSystemStateTrait, get_validator_from_table, + IotaSystemState, IotaSystemStateTrait, IOTA_SYSTEM_STATE_SIM_TEST_DEEP_V2, + IOTA_SYSTEM_STATE_SIM_TEST_SHALLOW_V2, IOTA_SYSTEM_STATE_SIM_TEST_V1, + }, object::{Object, Owner}, programmable_transaction_builder::ProgrammableTransactionBuilder, - sui_system_state::{ - epoch_start_sui_system_state::EpochStartSystemStateTrait, get_validator_from_table, - SuiSystemState, SuiSystemStateTrait, SUI_SYSTEM_STATE_SIM_TEST_DEEP_V2, - SUI_SYSTEM_STATE_SIM_TEST_SHALLOW_V2, SUI_SYSTEM_STATE_SIM_TEST_V1, - }, transaction::{ CallArg, Command, ObjectArg, ProgrammableMoveCall, ProgrammableTransaction, TransactionData, TransactionKind, TEST_ONLY_GAS_UNIT_FOR_GENERIC, }, - MOVE_STDLIB_PACKAGE_ID, SUI_AUTHENTICATOR_STATE_OBJECT_ID, SUI_CLOCK_OBJECT_ID, - SUI_FRAMEWORK_PACKAGE_ID, SUI_RANDOMNESS_STATE_OBJECT_ID, SUI_SYSTEM_PACKAGE_ID, - SUI_SYSTEM_STATE_OBJECT_ID, + IOTA_AUTHENTICATOR_STATE_OBJECT_ID, IOTA_CLOCK_OBJECT_ID, IOTA_FRAMEWORK_PACKAGE_ID, + IOTA_RANDOMNESS_STATE_OBJECT_ID, IOTA_SYSTEM_PACKAGE_ID, IOTA_SYSTEM_STATE_OBJECT_ID, + MOVE_STDLIB_PACKAGE_ID, }; + use move_binary_format::CompiledModule; + use move_core_types::ident_str; use test_cluster::TestCluster; use tokio::time::{sleep, Duration}; use tracing::info; @@ -350,9 +351,9 @@ mod sim_only_tests { // Instances of the type that existed before and new instances are able to take // advantage of the newly introduced ability wrap_obj(&cluster, to_wrap0).await; - transfer_obj(&cluster, SuiAddress::ZERO, to_transfer0).await; + transfer_obj(&cluster, IotaAddress::ZERO, to_transfer0).await; wrap_obj(&cluster, to_wrap1).await; - transfer_obj(&cluster, SuiAddress::ZERO, to_transfer1).await; + transfer_obj(&cluster, IotaAddress::ZERO, to_transfer1).await; } #[sim_test] @@ -404,8 +405,8 @@ mod sim_only_tests { async fn test_new_framework_package() { ProtocolConfig::poison_get_for_min_version(); - let sui_extra = ObjectID::from_single_byte(0x42); - framework_injection::set_override(sui_extra, fixture_modules("extra_package")); + let iota_extra = ObjectID::from_single_byte(0x42); + framework_injection::set_override(iota_extra, fixture_modules("extra_package")); let cluster = TestClusterBuilder::new() .with_epoch_duration_ms(20000) @@ -419,7 +420,7 @@ mod sim_only_tests { // Make sure the epoch change event includes the event from the new package's // module initializer - let effects = get_framework_upgrade_effects(&cluster, &sui_extra).await; + let effects = get_framework_upgrade_effects(&cluster, &iota_extra).await; let shared_id = effects .created() @@ -427,10 +428,10 @@ mod sim_only_tests { .find_map(|(obj, owner)| { if let Owner::Shared { .. } = owner { let is_framework_obj = [ - SUI_SYSTEM_STATE_OBJECT_ID, - SUI_CLOCK_OBJECT_ID, - SUI_AUTHENTICATOR_STATE_OBJECT_ID, - SUI_RANDOMNESS_STATE_OBJECT_ID, + IOTA_SYSTEM_STATE_OBJECT_ID, + IOTA_CLOCK_OBJECT_ID, + IOTA_AUTHENTICATOR_STATE_OBJECT_ID, + IOTA_RANDOMNESS_STATE_OBJECT_ID, ] .contains(&obj.0); (!is_framework_obj).then_some(obj.0) @@ -450,7 +451,7 @@ mod sim_only_tests { dev_inspect_call( &cluster, ProgrammableMoveCall { - package: sui_extra, + package: iota_extra, module: ident_str!("msim_extra_1").to_owned(), function: ident_str!("canary").to_owned(), type_arguments: vec![], @@ -465,10 +466,10 @@ mod sim_only_tests { async fn run_framework_upgrade(from: &str, to: &str) -> TestCluster { ProtocolConfig::poison_get_for_min_version(); - override_sui_system_modules(to); + override_iota_system_modules(to); TestClusterBuilder::new() .with_epoch_duration_ms(20000) - .with_objects([sui_system_package_object(from)]) + .with_objects([iota_system_package_object(from)]) .with_supported_protocol_versions(SupportedProtocolVersions::new_for_testing( START, FINISH, )) @@ -480,7 +481,7 @@ mod sim_only_tests { dev_inspect_call( cluster, ProgrammableMoveCall { - package: SUI_SYSTEM_PACKAGE_ID, + package: IOTA_SYSTEM_PACKAGE_ID, module: ident_str!("msim_extra_1").to_owned(), function: ident_str!("canary").to_owned(), type_arguments: vec![], @@ -495,7 +496,7 @@ mod sim_only_tests { let mut builder = ProgrammableTransactionBuilder::new(); builder .move_call( - SUI_SYSTEM_PACKAGE_ID, + IOTA_SYSTEM_PACKAGE_ID, ident_str!("msim_extra_1").to_owned(), ident_str!("mint").to_owned(), // type_arguments @@ -517,7 +518,7 @@ mod sim_only_tests { let mut builder = ProgrammableTransactionBuilder::new(); builder .move_call( - SUI_SYSTEM_PACKAGE_ID, + IOTA_SYSTEM_PACKAGE_ID, ident_str!("msim_extra_1").to_owned(), ident_str!("wrap").to_owned(), // type_arguments @@ -535,7 +536,7 @@ mod sim_only_tests { async fn transfer_obj( cluster: &TestCluster, - recipient: SuiAddress, + recipient: IotaAddress, obj: ObjectRef, ) -> ObjectRef { execute(cluster, { @@ -598,7 +599,7 @@ mod sim_only_tests { async fn execute( cluster: &TestCluster, ptb: ProgrammableTransaction, - ) -> SuiTransactionBlockEffects { + ) -> IotaTransactionBlockEffects { let context = &cluster.wallet; let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); @@ -629,17 +630,17 @@ mod sim_only_tests { async fn get_framework_upgrade_versions( cluster: &TestCluster, ) -> (Option, Option) { - let effects = get_framework_upgrade_effects(cluster, &SUI_SYSTEM_PACKAGE_ID).await; + let effects = get_framework_upgrade_effects(cluster, &IOTA_SYSTEM_PACKAGE_ID).await; let modified_at = effects .modified_at_versions() .iter() - .find_map(|(id, v)| (id == &SUI_SYSTEM_PACKAGE_ID).then_some(*v)); + .find_map(|(id, v)| (id == &IOTA_SYSTEM_PACKAGE_ID).then_some(*v)); let mutated_to = effects .mutated() .iter() - .find_map(|((id, v, _), _)| (id == &SUI_SYSTEM_PACKAGE_ID).then_some(*v)); + .find_map(|((id, v, _), _)| (id == &IOTA_SYSTEM_PACKAGE_ID).then_some(*v)); (modified_at, mutated_to) } @@ -648,7 +649,7 @@ mod sim_only_tests { cluster: &TestCluster, package: &ObjectID, ) -> TransactionEffects { - let node_handle = &cluster.fullnode_handle.sui_node; + let node_handle = &cluster.fullnode_handle.iota_node; node_handle .with_async(|node| async { @@ -662,7 +663,7 @@ mod sim_only_tests { } async fn get_object(cluster: &TestCluster, object_id: &ObjectID) -> Object { - let node_handle = &cluster.fullnode_handle.sui_node; + let node_handle = &cluster.fullnode_handle.iota_node; node_handle .with_async(|node| async { @@ -690,10 +691,10 @@ mod sim_only_tests { // Even though a new framework is available, the required new protocol version // is not. - override_sui_system_modules("compatible"); + override_iota_system_modules("compatible"); let test_cluster = TestClusterBuilder::new() .with_epoch_duration_ms(20000) - .with_objects([sui_system_package_object("base")]) + .with_objects([iota_system_package_object("base")]) .with_supported_protocol_versions(SupportedProtocolVersions::new_for_testing( START, START, )) @@ -726,12 +727,12 @@ mod sim_only_tests { test_cluster.stop_all_validators().await; let first = test_cluster.swarm.validator_nodes().next().unwrap(); let first_name = first.name(); - override_sui_system_modules_cb(Box::new(move |name| { + override_iota_system_modules_cb(Box::new(move |name| { if name == first_name { info!("node {:?} using compatible packages", name.concise()); - Some(sui_system_modules("base")) + Some(iota_system_modules("base")) } else { - Some(sui_system_modules("compatible")) + Some(iota_system_modules("compatible")) } })); test_cluster.start_all_validators().await; @@ -778,9 +779,9 @@ mod sim_only_tests { let mut validators = test_cluster.swarm.validator_nodes(); let first = validators.next().unwrap().name(); let second = validators.next().unwrap().name(); - override_sui_system_modules_cb(Box::new(move |name| { + override_iota_system_modules_cb(Box::new(move |name| { if name == first || name == second { - Some(sui_system_modules("compatible")) + Some(iota_system_modules("compatible")) } else { None } @@ -792,11 +793,11 @@ mod sim_only_tests { #[sim_test] async fn test_safe_mode_recovery() { - override_sui_system_modules("mock_sui_systems/base"); + override_iota_system_modules("mock_iota_systems/base"); let test_cluster = TestClusterBuilder::new() .with_epoch_duration_ms(20000) - // Overrides with a sui system package that would abort during epoch change txn - .with_objects([sui_system_package_object("mock_sui_systems/safe_mode")]) + // Overrides with a iota system package that would abort during epoch change txn + .with_objects([iota_system_package_object("mock_iota_systems/safe_mode")]) .with_supported_protocol_versions(SupportedProtocolVersions::new_for_testing( START, FINISH, )) @@ -840,13 +841,13 @@ mod sim_only_tests { } #[sim_test] - async fn sui_system_mock_smoke_test() { + async fn iota_system_mock_smoke_test() { let test_cluster = TestClusterBuilder::new() .with_epoch_duration_ms(20000) .with_supported_protocol_versions(SupportedProtocolVersions::new_for_testing( START, START, )) - .with_objects([sui_system_package_object("mock_sui_systems/base")]) + .with_objects([iota_system_package_object("mock_iota_systems/base")]) .build() .await; // Make sure we can survive at least one epoch. @@ -854,15 +855,15 @@ mod sim_only_tests { } #[sim_test] - async fn sui_system_state_shallow_upgrade_test() { - override_sui_system_modules("mock_sui_systems/shallow_upgrade"); + async fn iota_system_state_shallow_upgrade_test() { + override_iota_system_modules("mock_iota_systems/shallow_upgrade"); let test_cluster = TestClusterBuilder::new() .with_epoch_duration_ms(20000) .with_supported_protocol_versions(SupportedProtocolVersions::new_for_testing( START, FINISH, )) - .with_objects([sui_system_package_object("mock_sui_systems/base")]) + .with_objects([iota_system_package_object("mock_iota_systems/base")]) .build() .await; // Wait for the upgrade to finish. After the upgrade, the new framework will be @@ -871,30 +872,30 @@ mod sim_only_tests { assert_eq!(system_state.protocol_version(), FINISH); assert_eq!( system_state.system_state_version(), - SUI_SYSTEM_STATE_SIM_TEST_V1 + IOTA_SYSTEM_STATE_SIM_TEST_V1 ); - assert!(matches!(system_state, SuiSystemState::SimTestV1(_))); + assert!(matches!(system_state, IotaSystemState::SimTestV1(_))); // The system state object will be upgraded next time we execute advance_epoch // transaction at epoch boundary. let system_state = test_cluster.wait_for_epoch(Some(2)).await; assert_eq!( system_state.system_state_version(), - SUI_SYSTEM_STATE_SIM_TEST_SHALLOW_V2 + IOTA_SYSTEM_STATE_SIM_TEST_SHALLOW_V2 ); - assert!(matches!(system_state, SuiSystemState::SimTestShallowV2(_))); + assert!(matches!(system_state, IotaSystemState::SimTestShallowV2(_))); } #[sim_test] - async fn sui_system_state_deep_upgrade_test() { - override_sui_system_modules("mock_sui_systems/deep_upgrade"); + async fn iota_system_state_deep_upgrade_test() { + override_iota_system_modules("mock_iota_systems/deep_upgrade"); let test_cluster = TestClusterBuilder::new() .with_epoch_duration_ms(20000) .with_supported_protocol_versions(SupportedProtocolVersions::new_for_testing( START, FINISH, )) - .with_objects([sui_system_package_object("mock_sui_systems/base")]) + .with_objects([iota_system_package_object("mock_iota_systems/base")]) .build() .await; // Wait for the upgrade to finish. After the upgrade, the new framework will be @@ -903,15 +904,15 @@ mod sim_only_tests { assert_eq!(system_state.protocol_version(), FINISH); assert_eq!( system_state.system_state_version(), - SUI_SYSTEM_STATE_SIM_TEST_V1 + IOTA_SYSTEM_STATE_SIM_TEST_V1 ); - if let SuiSystemState::SimTestV1(inner) = system_state { + if let IotaSystemState::SimTestV1(inner) = system_state { // Make sure we have 1 inactive validator for latter testing. assert_eq!(inner.validators.inactive_validators.size, 1); get_validator_from_table( test_cluster .fullnode_handle - .sui_node + .iota_node .state() .get_object_store() .as_ref(), @@ -928,15 +929,15 @@ mod sim_only_tests { let system_state = test_cluster.wait_for_epoch(Some(2)).await; assert_eq!( system_state.system_state_version(), - SUI_SYSTEM_STATE_SIM_TEST_DEEP_V2 + IOTA_SYSTEM_STATE_SIM_TEST_DEEP_V2 ); - if let SuiSystemState::SimTestDeepV2(inner) = system_state { + if let IotaSystemState::SimTestDeepV2(inner) = system_state { // Make sure we have 1 inactive validator for latter testing. assert_eq!(inner.validators.inactive_validators.size, 1); get_validator_from_table( test_cluster .fullnode_handle - .sui_node + .iota_node .state() .get_object_store() .as_ref(), @@ -950,9 +951,9 @@ mod sim_only_tests { } #[sim_test] - async fn sui_system_state_production_upgrade_test() { - // Use this test to test a real sui system state upgrade. To make this test - // work, put the new sui system in a new path and point to it in the + async fn iota_system_state_production_upgrade_test() { + // Use this test to test a real iota system state upgrade. To make this test + // work, put the new iota system in a new path and point to it in the // override. It's important to also handle the new protocol version in // protocol-config/lib.rs. The MAX_PROTOCOL_VERSION must not be changed // yet when testing this. @@ -964,7 +965,7 @@ mod sim_only_tests { .build() .await; // TODO: Replace the path with the new framework path when we test it for real. - override_sui_system_modules("../../../sui-framework/packages/sui-system"); + override_iota_system_modules("../../../iota-framework/packages/iota-system"); // Wait for the upgrade to finish. After the upgrade, the new framework will be // installed, but the system state object hasn't been upgraded yet. let system_state = test_cluster.wait_for_epoch(Some(1)).await; @@ -973,10 +974,10 @@ mod sim_only_tests { // The system state object will be upgraded next time we execute advance_epoch // transaction at epoch boundary. let system_state = test_cluster.wait_for_epoch(Some(2)).await; - if let SuiSystemState::V2(inner) = system_state { + if let IotaSystemState::V2(inner) = system_state { assert_eq!(inner.parameters.min_validator_count, 4); } else { - unreachable!("Unexpected sui system state version"); + unreachable!("Unexpected iota system state version"); } } @@ -987,32 +988,32 @@ mod sim_only_tests { test_cluster.wait_for_epoch(Some(2)).await; } - fn override_sui_system_modules(path: &str) { - framework_injection::set_override(SUI_SYSTEM_PACKAGE_ID, sui_system_modules(path)); + fn override_iota_system_modules(path: &str) { + framework_injection::set_override(IOTA_SYSTEM_PACKAGE_ID, iota_system_modules(path)); } - fn override_sui_system_modules_cb(f: framework_injection::PackageUpgradeCallback) { - framework_injection::set_override_cb(SUI_SYSTEM_PACKAGE_ID, f) + fn override_iota_system_modules_cb(f: framework_injection::PackageUpgradeCallback) { + framework_injection::set_override_cb(IOTA_SYSTEM_PACKAGE_ID, f) } - /// Get compiled modules for Sui System, built from fixture `fixture` in the - /// `framework_upgrades` directory. - fn sui_system_modules(fixture: &str) -> Vec { + /// Get compiled modules for Iota System, built from fixture `fixture` in + /// the `framework_upgrades` directory. + fn iota_system_modules(fixture: &str) -> Vec { fixture_package(fixture) - .get_sui_system_modules() + .get_iota_system_modules() .cloned() .collect() } - /// Like `sui_system_modules`, but package the modules in an `Object`. - fn sui_system_package_object(fixture: &str) -> Object { + /// Like `iota_system_modules`, but package the modules in an `Object`. + fn iota_system_package_object(fixture: &str) -> Object { Object::new_package( - &sui_system_modules(fixture), + &iota_system_modules(fixture), TransactionDigest::genesis_marker(), u64::MAX, &[ BuiltInFramework::get_package_by_id(&MOVE_STDLIB_PACKAGE_ID).genesis_move_package(), - BuiltInFramework::get_package_by_id(&SUI_FRAMEWORK_PACKAGE_ID) + BuiltInFramework::get_package_by_id(&IOTA_FRAMEWORK_PACKAGE_ID) .genesis_move_package(), ], ) diff --git a/crates/sui-e2e-tests/tests/randomness_tests.rs b/crates/iota-e2e-tests/tests/randomness_tests.rs similarity index 80% rename from crates/sui-e2e-tests/tests/randomness_tests.rs rename to crates/iota-e2e-tests/tests/randomness_tests.rs index 8cd21745876..d426210da83 100644 --- a/crates/sui-e2e-tests/tests/randomness_tests.rs +++ b/crates/iota-e2e-tests/tests/randomness_tests.rs @@ -1,9 +1,10 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use sui_macros::sim_test; -use sui_types::SUI_RANDOMNESS_STATE_OBJECT_ID; +use iota_macros::sim_test; +use iota_types::IOTA_RANDOMNESS_STATE_OBJECT_ID; use test_cluster::TestClusterBuilder; #[sim_test] @@ -22,7 +23,7 @@ async fn test_create_randomness_state_object() { assert!( node.state() .get_cache_reader() - .get_latest_object_ref_or_tombstone(SUI_RANDOMNESS_STATE_OBJECT_ID) + .get_latest_object_ref_or_tombstone(IOTA_RANDOMNESS_STATE_OBJECT_ID) .unwrap() .is_none() ); @@ -39,7 +40,7 @@ async fn test_create_randomness_state_object() { h.with(|node| { node.state() .get_cache_reader() - .get_latest_object_ref_or_tombstone(SUI_RANDOMNESS_STATE_OBJECT_ID) + .get_latest_object_ref_or_tombstone(IOTA_RANDOMNESS_STATE_OBJECT_ID) .unwrap() .expect("randomness state object should exist"); }); diff --git a/crates/sui-e2e-tests/tests/readme.rs b/crates/iota-e2e-tests/tests/readme.rs similarity index 96% rename from crates/sui-e2e-tests/tests/readme.rs rename to crates/iota-e2e-tests/tests/readme.rs index a21036b8bd9..8edd05d2919 100644 --- a/crates/sui-e2e-tests/tests/readme.rs +++ b/crates/iota-e2e-tests/tests/readme.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{io::Write, process::Command}; diff --git a/crates/sui-e2e-tests/tests/reconfiguration_tests.rs b/crates/iota-e2e-tests/tests/reconfiguration_tests.rs similarity index 88% rename from crates/sui-e2e-tests/tests/reconfiguration_tests.rs rename to crates/iota-e2e-tests/tests/reconfiguration_tests.rs index e5bd24c18db..e7190ba8737 100644 --- a/crates/sui-e2e-tests/tests/reconfiguration_tests.rs +++ b/crates/iota-e2e-tests/tests/reconfiguration_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -8,29 +9,29 @@ use std::{ }; use futures::future::join_all; -use rand::rngs::OsRng; -use sui_core::{ +use iota_core::{ authority::epoch_start_configuration::EpochFlag, consensus_adapter::position_submit_certificate, }; -use sui_json_rpc_types::SuiTransactionBlockEffectsAPI; -use sui_macros::{register_fail_point_arg, sim_test}; -use sui_node::SuiNodeHandle; -use sui_protocol_config::ProtocolConfig; -use sui_swarm_config::genesis_config::{ValidatorGenesisConfig, ValidatorGenesisConfigBuilder}; -use sui_test_transaction_builder::{make_transfer_sui_transaction, TestTransactionBuilder}; -use sui_types::{ - base_types::SuiAddress, +use iota_json_rpc_types::IotaTransactionBlockEffectsAPI; +use iota_macros::{register_fail_point_arg, sim_test}; +use iota_node::IotaNodeHandle; +use iota_protocol_config::ProtocolConfig; +use iota_swarm_config::genesis_config::{ValidatorGenesisConfig, ValidatorGenesisConfigBuilder}; +use iota_test_transaction_builder::{make_transfer_iota_transaction, TestTransactionBuilder}; +use iota_types::{ + base_types::IotaAddress, effects::TransactionEffectsAPI, - error::SuiError, + error::IotaError, gas::GasCostSummary, - governance::MIN_VALIDATOR_JOINING_STAKE_MIST, - message_envelope::Message, - sui_system_state::{ - get_validator_from_table, sui_system_state_summary::get_validator_by_pool_id, - SuiSystemStateTrait, + governance::MIN_VALIDATOR_JOINING_STAKE_MICROS, + iota_system_state::{ + get_validator_from_table, iota_system_state_summary::get_validator_by_pool_id, + IotaSystemStateTrait, }, + message_envelope::Message, transaction::{TransactionDataAPI, TransactionExpiration}, }; +use rand::rngs::OsRng; use test_cluster::{TestCluster, TestClusterBuilder}; use tokio::time::sleep; @@ -98,7 +99,7 @@ async fn test_transaction_expiration() { .unwrap(); let rgp = test_cluster.get_reference_gas_price().await; let mut data = TestTransactionBuilder::new(sender, gas, rgp) - .transfer_sui(Some(1), sender) + .transfer_iota(Some(1), sender) .build(); // Expired transaction returns an error let mut expired_data = data.clone(); @@ -115,7 +116,7 @@ async fn test_transaction_expiration() { .await }) .await; - assert!(matches!(result.unwrap_err(), SuiError::TransactionExpired)); + assert!(matches!(result.unwrap_err(), IotaError::TransactionExpired)); // Non expired transaction signed without issue *data.expiration_mut_for_testing() = TransactionExpiration::Epoch(10); @@ -144,7 +145,7 @@ async fn reconfig_with_revert_end_to_end_test() { let gas1 = gas_objects.pop().unwrap(); let tx = test_cluster.wallet.sign_transaction( &TestTransactionBuilder::new(sender, gas1, rgp) - .transfer_sui(None, sender) + .transfer_iota(None, sender) .build(), ); let effects1 = test_cluster.execute_transaction(tx).await; @@ -154,12 +155,12 @@ async fn reconfig_with_revert_end_to_end_test() { let gas2 = gas_objects.pop().unwrap(); let tx = test_cluster.wallet.sign_transaction( &TestTransactionBuilder::new(sender, gas2, rgp) - .transfer_sui(None, sender) + .transfer_iota(None, sender) .build(), ); let net = test_cluster .fullnode_handle - .sui_node + .iota_node .with(|node| node.clone_authority_aggregator().unwrap()); let cert = net .process_transaction(tx.clone()) @@ -344,19 +345,19 @@ async fn do_test_lock_table_upgrade() { let receiver = accounts_and_objs[1].0; let gas_object = accounts_and_objs[0].1[0]; - let transfer_sui = |amount| { + let transfer_iota = |amount| { test_cluster.wallet.sign_transaction( &TestTransactionBuilder::new(sender, gas_object, gas_price) - .transfer_sui(Some(amount), receiver) + .transfer_iota(Some(amount), receiver) .build(), ) }; - let t1 = transfer_sui(1); + let t1 = transfer_iota(1); test_cluster.create_certificate(t1.clone()).await.unwrap(); // attempt to equivocate - let t2 = transfer_sui(2); + let t2 = transfer_iota(2); test_cluster .create_certificate(t2.clone()) .await @@ -380,12 +381,12 @@ async fn do_test_lock_table_upgrade() { async fn test_create_advance_epoch_tx_race() { use std::sync::Arc; - use sui_macros::{register_fail_point, register_fail_point_async}; + use iota_macros::{register_fail_point, register_fail_point_async}; use tokio::sync::broadcast; use tracing::info; telemetry_subscribers::init_for_testing(); - sui_protocol_config::ProtocolConfig::poison_get_for_min_version(); + iota_protocol_config::ProtocolConfig::poison_get_for_min_version(); // panic if we enter safe mode. If you remove the check for // `is_tx_already_executed` in @@ -397,9 +398,9 @@ async fn test_create_advance_epoch_tx_race() { // Intercept the specified async wait point on a given node, and wait there // until a message is sent from the given tx. let register_wait = |failpoint, node_id, tx: Arc>| { - let node = sui_simulator::task::NodeId(node_id); + let node = iota_simulator::task::NodeId(node_id); register_fail_point_async(failpoint, move || { - let cur_node = sui_simulator::current_simnode_id(); + let cur_node = iota_simulator::current_simnode_id(); let tx = tx.clone(); async move { if cur_node == node { @@ -453,7 +454,7 @@ async fn test_create_advance_epoch_tx_race() { #[sim_test] async fn test_reconfig_with_failing_validator() { - sui_protocol_config::ProtocolConfig::poison_get_for_min_version(); + iota_protocol_config::ProtocolConfig::poison_get_for_min_version(); let test_cluster = Arc::new( TestClusterBuilder::new() @@ -486,7 +487,7 @@ async fn test_validator_resign_effects() { // were finalized in previous epochs. This allows authority aggregator to // form a new effects certificate in the new epoch. let test_cluster = TestClusterBuilder::new().build().await; - let tx = make_transfer_sui_transaction(&test_cluster.wallet, None, None).await; + let tx = make_transfer_iota_transaction(&test_cluster.wallet, None, None).await; let effects0 = test_cluster .execute_transaction(tx.clone()) .await @@ -497,7 +498,7 @@ async fn test_validator_resign_effects() { let net = test_cluster .fullnode_handle - .sui_node + .iota_node .with(|node| node.clone_authority_aggregator().unwrap()); let effects1 = net .process_transaction(tx) @@ -512,18 +513,18 @@ async fn test_validator_resign_effects() { #[sim_test] async fn test_validator_candidate_pool_read() { let new_validator = ValidatorGenesisConfigBuilder::new().build(&mut OsRng); - let address: SuiAddress = (&new_validator.account_key_pair.public()).into(); + let address: IotaAddress = (&new_validator.account_key_pair.public()).into(); let test_cluster = TestClusterBuilder::new() .with_validator_candidates([address]) .build() .await; add_validator_candidate(&test_cluster, &new_validator).await; - test_cluster.fullnode_handle.sui_node.with(|node| { + test_cluster.fullnode_handle.iota_node.with(|node| { let system_state = node .state() - .get_sui_system_state_object_for_testing() + .get_iota_system_state_object_for_testing() .unwrap(); - let system_state_summary = system_state.clone().into_sui_system_state_summary(); + let system_state_summary = system_state.clone().into_iota_system_state_summary(); let staking_pool_id = get_validator_from_table( node.state().get_object_store().as_ref(), system_state_summary.validator_candidates_id, @@ -538,7 +539,7 @@ async fn test_validator_candidate_pool_read() { staking_pool_id, ) .unwrap(); - assert_eq!(validator.sui_address, address); + assert_eq!(validator.iota_address, address); }); } @@ -550,24 +551,24 @@ async fn test_inactive_validator_pool_read() { .await; // Pick the first validator. let validator = test_cluster.swarm.validator_node_handles().pop().unwrap(); - let address = validator.with(|node| node.get_config().sui_address()); - let staking_pool_id = test_cluster.fullnode_handle.sui_node.with(|node| { + let address = validator.with(|node| node.get_config().iota_address()); + let staking_pool_id = test_cluster.fullnode_handle.iota_node.with(|node| { node.state() - .get_sui_system_state_object_for_testing() + .get_iota_system_state_object_for_testing() .unwrap() - .into_sui_system_state_summary() + .into_iota_system_state_summary() .active_validators .iter() - .find(|v| v.sui_address == address) + .find(|v| v.iota_address == address) .unwrap() .staking_pool_id }); - test_cluster.fullnode_handle.sui_node.with(|node| { + test_cluster.fullnode_handle.iota_node.with(|node| { let system_state = node .state() - .get_sui_system_state_object_for_testing() + .get_iota_system_state_object_for_testing() .unwrap(); - let system_state_summary = system_state.clone().into_sui_system_state_summary(); + let system_state_summary = system_state.clone().into_iota_system_state_summary(); // Validator is active. Check that we can find its summary by staking pool id. let validator = get_validator_by_pool_id( node.state().get_object_store().as_ref(), @@ -576,7 +577,7 @@ async fn test_inactive_validator_pool_read() { staking_pool_id, ) .unwrap(); - assert_eq!(validator.sui_address, address); + assert_eq!(validator.iota_address, address); }); execute_remove_validator_tx(&test_cluster, &validator).await; @@ -593,10 +594,10 @@ async fn test_inactive_validator_pool_read() { // Check that the validator that just left now shows up in the // inactive_validators, and we can still deserialize it and get the inactive // staking pool. - test_cluster.fullnode_handle.sui_node.with(|node| { + test_cluster.fullnode_handle.iota_node.with(|node| { let system_state = node .state() - .get_sui_system_state_object_for_testing() + .get_iota_system_state_object_for_testing() .unwrap(); assert_eq!( system_state @@ -605,7 +606,7 @@ async fn test_inactive_validator_pool_read() { .num_members(), 4 ); - let system_state_summary = system_state.clone().into_sui_system_state_summary(); + let system_state_summary = system_state.clone().into_iota_system_state_summary(); let validator = get_validator_by_pool_id( node.state().get_object_store().as_ref(), &system_state, @@ -613,7 +614,7 @@ async fn test_inactive_validator_pool_read() { staking_pool_id, ) .unwrap(); - assert_eq!(validator.sui_address, address); + assert_eq!(validator.iota_address, address); assert!(validator.staking_pool_deactivation_epoch.is_some()); }) } @@ -635,7 +636,7 @@ async fn test_reconfig_with_committee_change_basic() { test_cluster.trigger_reconfiguration().await; // Check that a new validator has joined the committee. - test_cluster.fullnode_handle.sui_node.with(|node| { + test_cluster.fullnode_handle.iota_node.with(|node| { assert_eq!( node.state() .epoch_store_for_testing() @@ -656,7 +657,7 @@ async fn test_reconfig_with_committee_change_basic() { execute_remove_validator_tx(&test_cluster, &new_validator_handle).await; test_cluster.trigger_reconfiguration().await; - test_cluster.fullnode_handle.sui_node.with(|node| { + test_cluster.fullnode_handle.iota_node.with(|node| { assert_eq!( node.state() .epoch_store_for_testing() @@ -684,7 +685,7 @@ async fn do_test_reconfig_with_committee_change_stress() { let addresses = candidates .iter() .map(|c| (&c.account_key_pair.public()).into()) - .collect::>(); + .collect::>(); let mut test_cluster = TestClusterBuilder::new() .with_num_validators(7) .with_validator_candidates(addresses) @@ -721,7 +722,7 @@ async fn do_test_reconfig_with_committee_change_stress() { test_cluster.trigger_reconfiguration().await; let committee = test_cluster .fullnode_handle - .sui_node + .iota_node .with(|node| node.state().epoch_store_for_testing().committee().clone()); assert_eq!(committee.num_members(), 7); assert!(committee.authority_exists(&handle1.state().name)); @@ -735,8 +736,8 @@ async fn do_test_reconfig_with_committee_change_stress() { #[cfg(msim)] #[sim_test] async fn safe_mode_reconfig_test() { - use sui_test_transaction_builder::make_staking_transaction; - use sui_types::sui_system_state::advance_epoch_result_injection; + use iota_test_transaction_builder::make_staking_transaction; + use iota_types::iota_system_state::advance_epoch_result_injection; const EPOCH_DURATION: u64 = 10000; @@ -749,9 +750,9 @@ async fn safe_mode_reconfig_test() { .await; let system_state = test_cluster - .sui_client() + .iota_client() .governance_api() - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await .unwrap(); @@ -780,9 +781,9 @@ async fn safe_mode_reconfig_test() { // Try a staking transaction. let validator_address = system_state - .into_sui_system_state_summary() + .into_iota_system_state_summary() .active_validators[0] - .sui_address; + .iota_address; let txn = make_staking_transaction(&test_cluster.wallet, validator_address).await; test_cluster.execute_transaction(txn).await; @@ -800,11 +801,11 @@ async fn add_validator_candidate( test_cluster: &TestCluster, new_validator: &ValidatorGenesisConfig, ) { - let cur_validator_candidate_count = test_cluster.fullnode_handle.sui_node.with(|node| { + let cur_validator_candidate_count = test_cluster.fullnode_handle.iota_node.with(|node| { node.state() - .get_sui_system_state_object_for_testing() + .get_iota_system_state_object_for_testing() .unwrap() - .into_sui_system_state_summary() + .into_iota_system_state_summary() .validator_candidates_size }); let address = (&new_validator.account_key_pair.public()).into(); @@ -824,12 +825,12 @@ async fn add_validator_candidate( test_cluster.execute_transaction(tx).await; // Check that the candidate can be found in the candidate table now. - test_cluster.fullnode_handle.sui_node.with(|node| { + test_cluster.fullnode_handle.iota_node.with(|node| { let system_state = node .state() - .get_sui_system_state_object_for_testing() + .get_iota_system_state_object_for_testing() .unwrap(); - let system_state_summary = system_state.into_sui_system_state_summary(); + let system_state_summary = system_state.into_iota_system_state_summary(); assert_eq!( system_state_summary.validator_candidates_size, cur_validator_candidate_count + 1 @@ -837,8 +838,8 @@ async fn add_validator_candidate( }); } -async fn execute_remove_validator_tx(test_cluster: &TestCluster, handle: &SuiNodeHandle) { - let address = handle.with(|node| node.get_config().sui_address()); +async fn execute_remove_validator_tx(test_cluster: &TestCluster, handle: &IotaNodeHandle) { + let address = handle.with(|node| node.get_config().iota_address()); let gas = test_cluster .wallet .get_one_gas_object_owned_by_address(address) @@ -862,10 +863,10 @@ async fn execute_add_validator_transactions( test_cluster: &TestCluster, new_validator: &ValidatorGenesisConfig, ) { - let pending_active_count = test_cluster.fullnode_handle.sui_node.with(|node| { + let pending_active_count = test_cluster.fullnode_handle.iota_node.with(|node| { let system_state = node .state() - .get_sui_system_state_object_for_testing() + .get_iota_system_state_object_for_testing() .unwrap(); system_state .get_pending_active_validators(node.state().get_object_store().as_ref()) @@ -879,7 +880,7 @@ async fn execute_add_validator_transactions( .wallet .gas_for_owner_budget( address, - MIN_VALIDATOR_JOINING_STAKE_MIST, + MIN_VALIDATOR_JOINING_STAKE_MICROS, Default::default(), ) .await @@ -907,17 +908,17 @@ async fn execute_add_validator_transactions( test_cluster.execute_transaction(tx).await; // Check that we can get the pending validator from 0x5. - test_cluster.fullnode_handle.sui_node.with(|node| { + test_cluster.fullnode_handle.iota_node.with(|node| { let system_state = node .state() - .get_sui_system_state_object_for_testing() + .get_iota_system_state_object_for_testing() .unwrap(); let pending_active_validators = system_state .get_pending_active_validators(node.state().get_object_store().as_ref()) .unwrap(); assert_eq!(pending_active_validators.len(), pending_active_count + 1); assert_eq!( - pending_active_validators[pending_active_validators.len() - 1].sui_address, + pending_active_validators[pending_active_validators.len() - 1].iota_address, address ); }); diff --git a/crates/sui-e2e-tests/tests/sdk_stream_tests.rs b/crates/iota-e2e-tests/tests/sdk_stream_tests.rs similarity index 76% rename from crates/sui-e2e-tests/tests/sdk_stream_tests.rs rename to crates/iota-e2e-tests/tests/sdk_stream_tests.rs index 9b11d5d8923..40db232332b 100644 --- a/crates/sui-e2e-tests/tests/sdk_stream_tests.rs +++ b/crates/iota-e2e-tests/tests/sdk_stream_tests.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::future; use futures::StreamExt; -use sui_sdk::{SuiClientBuilder, SUI_COIN_TYPE}; -use sui_swarm_config::genesis_config::{DEFAULT_GAS_AMOUNT, DEFAULT_NUMBER_OF_OBJECT_PER_ACCOUNT}; +use iota_sdk::{IotaClientBuilder, IOTA_COIN_TYPE}; +use iota_swarm_config::genesis_config::{DEFAULT_GAS_AMOUNT, DEFAULT_NUMBER_OF_OBJECT_PER_ACCOUNT}; use test_cluster::TestClusterBuilder; // TODO: rewrite the tests after the removal of DevNet NFT @@ -14,17 +15,17 @@ use test_cluster::TestClusterBuilder; // let mut test_cluster = TestClusterBuilder::new().build().await?; // let rpc_url = test_cluster.rpc_url(); -// let client = SuiClientBuilder::default().build(rpc_url).await?; +// let client = IotaClientBuilder::default().build(rpc_url).await?; // let txs = client // .read_api() -// .get_transactions_stream(SuiTransactionBlockResponseQuery::default(), +// .get_transactions_stream(IotaTransactionBlockResponseQuery::default(), // None, true) .collect::>() // .await; // assert_eq!(1, txs.len()); // // execute some transactions -// SuiClientCommands::CreateExampleNFT { +// IotaClientCommands::CreateExampleNFT { // name: None, // description: None, // url: None, @@ -36,7 +37,7 @@ use test_cluster::TestClusterBuilder; // let txs = client // .read_api() -// .get_transactions_stream(SuiTransactionBlockResponseQuery::default(), +// .get_transactions_stream(IotaTransactionBlockResponseQuery::default(), // None, true) .collect::>() // .await; @@ -52,7 +53,7 @@ use test_cluster::TestClusterBuilder; // .await?; // let rpc_url = test_cluster.rpc_url(); -// let client = SuiClientBuilder::default().build(rpc_url).await?; +// let client = IotaClientBuilder::default().build(rpc_url).await?; // let events = client // .event_api() // .get_events_stream(EventFilter::All(vec![]), None, true) @@ -62,7 +63,7 @@ use test_cluster::TestClusterBuilder; // let starting_event_count = events.len(); // // execute some transactions -// SuiClientCommands::CreateExampleNFT { +// IotaClientCommands::CreateExampleNFT { // name: None, // description: None, // url: None, @@ -88,10 +89,10 @@ async fn test_coins_stream() -> Result<(), anyhow::Error> { let address = test_cluster.get_address_0(); let rpc_url = test_cluster.rpc_url(); - let client = SuiClientBuilder::default().build(rpc_url).await?; + let client = IotaClientBuilder::default().build(rpc_url).await?; let coins = client .coin_read_api() - .get_coins_stream(address, Some(SUI_COIN_TYPE.to_string())) + .get_coins_stream(address, Some(IOTA_COIN_TYPE.to_string())) .collect::>() .await; @@ -99,7 +100,7 @@ async fn test_coins_stream() -> Result<(), anyhow::Error> { let page = client .coin_read_api() - .get_coins(address, Some(SUI_COIN_TYPE.to_string()), None, None) + .get_coins(address, Some(IOTA_COIN_TYPE.to_string()), None, None) .await?; for (coin1, coin2) in coins.into_iter().zip(page.data) { @@ -108,7 +109,7 @@ async fn test_coins_stream() -> Result<(), anyhow::Error> { let amount = client .coin_read_api() - .get_coins_stream(address, Some(SUI_COIN_TYPE.to_string())) + .get_coins_stream(address, Some(IOTA_COIN_TYPE.to_string())) .fold(0u128, |acc, coin| async move { acc + coin.balance as u128 }) .await; @@ -121,7 +122,7 @@ async fn test_coins_stream() -> Result<(), anyhow::Error> { let coins = client .coin_read_api() - .get_coins_stream(address, Some(SUI_COIN_TYPE.to_string())) + .get_coins_stream(address, Some(IOTA_COIN_TYPE.to_string())) .take_while(|coin| { let ready = future::ready(total < DEFAULT_GAS_AMOUNT as u128 * 3); total += coin.balance as u128; diff --git a/crates/sui-e2e-tests/tests/shared_objects_tests.rs b/crates/iota-e2e-tests/tests/shared_objects_tests.rs similarity index 95% rename from crates/sui-e2e-tests/tests/shared_objects_tests.rs rename to crates/iota-e2e-tests/tests/shared_objects_tests.rs index 5392d4df8a5..f216fe8ad7a 100644 --- a/crates/sui-e2e-tests/tests/shared_objects_tests.rs +++ b/crates/iota-e2e-tests/tests/shared_objects_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -7,26 +8,26 @@ use std::{ }; use futures::{future::join_all, join}; -use rand::distributions::Distribution; -use sui_config::node::AuthorityOverloadConfig; -use sui_core::{authority::EffectsNotifyRead, consensus_adapter::position_submit_certificate}; -use sui_json_rpc_types::SuiTransactionBlockEffectsAPI; -use sui_macros::{register_fail_point_async, sim_test}; -use sui_swarm_config::genesis_config::{AccountConfig, DEFAULT_GAS_AMOUNT}; -use sui_test_transaction_builder::{ +use iota_config::node::AuthorityOverloadConfig; +use iota_core::{authority::EffectsNotifyRead, consensus_adapter::position_submit_certificate}; +use iota_json_rpc_types::IotaTransactionBlockEffectsAPI; +use iota_macros::{register_fail_point_async, sim_test}; +use iota_swarm_config::genesis_config::{AccountConfig, DEFAULT_GAS_AMOUNT}; +use iota_test_transaction_builder::{ publish_basics_package, publish_basics_package_and_make_counter, TestTransactionBuilder, }; -use sui_types::{ +use iota_types::{ effects::TransactionEffectsAPI, event::Event, execution_status::{CommandArgumentError, ExecutionFailureStatus, ExecutionStatus}, messages_grpc::{LayoutGenerationOption, ObjectInfoRequest}, transaction::{CallArg, ObjectArg}, }; +use rand::distributions::Distribution; use test_cluster::TestClusterBuilder; use tokio::time::sleep; -/// Send a simple shared object transaction to Sui and ensures the client gets +/// Send a simple shared object transaction to Iota and ensures the client gets /// back a response. #[sim_test] async fn shared_object_transaction() { @@ -42,7 +43,7 @@ async fn shared_object_transaction() { .next() .unwrap() .config - .sui_address(), + .iota_address(), ) .build(); @@ -134,7 +135,7 @@ async fn shared_object_deletion_multiple_times() { // Start a new fullnode and let it sync from genesis and wait for us to see all // the deletion transactions. - let fullnode = test_cluster.spawn_new_fullnode().await.sui_node; + let fullnode = test_cluster.spawn_new_fullnode().await.iota_node; fullnode .state() .get_effects_notify_read() @@ -190,7 +191,7 @@ async fn shared_object_deletion_multiple_times_cert_racing() { // Start a new fullnode and let it sync from genesis and wait for us to see all // the deletion transactions. - let fullnode = test_cluster.spawn_new_fullnode().await.sui_node; + let fullnode = test_cluster.spawn_new_fullnode().await.iota_node; fullnode .state() .get_effects_notify_read() @@ -305,7 +306,7 @@ async fn shared_object_deletion_multi_certs() { ); // Start a new fullnode that is not on the write path - let fullnode = test_cluster.spawn_new_fullnode().await.sui_node; + let fullnode = test_cluster.spawn_new_fullnode().await.iota_node; fullnode .state() .get_effects_notify_read() @@ -314,8 +315,8 @@ async fn shared_object_deletion_multi_certs() { .unwrap(); } -/// End-to-end shared transaction test for a Sui validator. It does not test the -/// client or wallet, but tests the end-to-end flow from Sui to consensus. +/// End-to-end shared transaction test for a Iota validator. It does not test +/// the client or wallet, but tests the end-to-end flow from Iota to consensus. #[sim_test] async fn call_shared_object_contract() { let test_cluster = TestClusterBuilder::new().build().await; @@ -524,7 +525,7 @@ async fn access_clock_object_test() { loop { let checkpoint = test_cluster .fullnode_handle - .sui_node + .iota_node .with_async(|node| async { node.state() .get_transaction_checkpoint_for_tests( @@ -644,7 +645,7 @@ async fn shared_object_sync() { assert!(effects.status().is_ok()); } -/// Send a simple shared object transaction to Sui and ensures the client gets +/// Send a simple shared object transaction to Iota and ensures the client gets /// back a response. #[sim_test] async fn replay_shared_object_transaction() { diff --git a/crates/sui-e2e-tests/tests/shared_objects_version_tests.rs b/crates/iota-e2e-tests/tests/shared_objects_version_tests.rs similarity index 94% rename from crates/sui-e2e-tests/tests/shared_objects_version_tests.rs rename to crates/iota-e2e-tests/tests/shared_objects_version_tests.rs index 29e15071d07..69976ff36e8 100644 --- a/crates/sui-e2e-tests/tests/shared_objects_version_tests.rs +++ b/crates/iota-e2e-tests/tests/shared_objects_version_tests.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::PathBuf; -use sui_macros::*; -use sui_test_transaction_builder::publish_package; -use sui_types::{ +use iota_macros::*; +use iota_test_transaction_builder::publish_package; +use iota_types::{ base_types::{ObjectID, ObjectRef, SequenceNumber}, effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, execution_status::{ExecutionFailureStatus, ExecutionStatus}, object::{Owner, OBJECT_START_VERSION}, transaction::{CallArg, ObjectArg}, - SUI_FRAMEWORK_ADDRESS, + IOTA_FRAMEWORK_ADDRESS, }; use test_cluster::{TestCluster, TestClusterBuilder}; @@ -35,7 +36,7 @@ async fn objects_transitioning_to_shared_remember_their_previous_version() { else { panic!() }; - assert_eq!(location.module.address(), &SUI_FRAMEWORK_ADDRESS); + assert_eq!(location.module.address(), &IOTA_FRAMEWORK_ADDRESS); assert_eq!(location.module.name().as_str(), "transfer"); assert_eq!(code, 0 /* ESharedNonNewObject */); } @@ -51,7 +52,7 @@ async fn shared_object_owner_doesnt_change_on_write() { else { panic!() }; - assert_eq!(location.module.address(), &SUI_FRAMEWORK_ADDRESS); + assert_eq!(location.module.address(), &IOTA_FRAMEWORK_ADDRESS); assert_eq!(location.module.name().as_str(), "transfer"); assert_eq!(code, 0 /* ESharedNonNewObject */); } @@ -67,7 +68,7 @@ async fn initial_shared_version_mismatch_start_version() { else { panic!() }; - assert_eq!(location.module.address(), &SUI_FRAMEWORK_ADDRESS); + assert_eq!(location.module.address(), &IOTA_FRAMEWORK_ADDRESS); assert_eq!(location.module.name().as_str(), "transfer"); assert_eq!(code, 0 /* ESharedNonNewObject */); } @@ -82,7 +83,7 @@ async fn initial_shared_version_mismatch_current_version() { else { panic!() }; - assert_eq!(location.module.address(), &SUI_FRAMEWORK_ADDRESS); + assert_eq!(location.module.address(), &IOTA_FRAMEWORK_ADDRESS); assert_eq!(location.module.name().as_str(), "transfer"); assert_eq!(code, 0 /* ESharedNonNewObject */); } diff --git a/crates/sui-e2e-tests/tests/simulator_tests.rs b/crates/iota-e2e-tests/tests/simulator_tests.rs similarity index 92% rename from crates/sui-e2e-tests/tests/simulator_tests.rs rename to crates/iota-e2e-tests/tests/simulator_tests.rs index 68b4ef4240c..f00319a971d 100644 --- a/crates/sui-e2e-tests/tests/simulator_tests.rs +++ b/crates/iota-e2e-tests/tests/simulator_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::{HashMap, HashSet}; @@ -7,15 +8,15 @@ use futures::{ stream::{FuturesOrdered, FuturesUnordered}, StreamExt, }; +use iota_core::authority::EffectsNotifyRead; +use iota_macros::*; +use iota_protocol_config::ProtocolConfig; +use iota_test_transaction_builder::make_transfer_iota_transaction; use rand::{ distributions::{Distribution, Uniform}, rngs::OsRng, Rng, }; -use sui_core::authority::EffectsNotifyRead; -use sui_macros::*; -use sui_protocol_config::ProtocolConfig; -use sui_test_transaction_builder::make_transfer_sui_transaction; use test_cluster::TestClusterBuilder; use tokio::time::{sleep, Duration, Instant}; use tracing::{debug, trace}; @@ -139,7 +140,7 @@ async fn test_net_determinism() { let mut test_cluster = TestClusterBuilder::new().build().await; - let txn = make_transfer_sui_transaction(&test_cluster.wallet, None, None).await; + let txn = make_transfer_iota_transaction(&test_cluster.wallet, None, None).await; let digest = test_cluster.execute_transaction(txn).await.digest; sleep(Duration::from_millis(1000)).await; @@ -147,7 +148,7 @@ async fn test_net_determinism() { let handle = test_cluster.spawn_new_fullnode().await; handle - .sui_node + .iota_node .state() .get_effects_notify_read() .notify_read_executed_effects(vec![digest]) diff --git a/crates/iota-e2e-tests/tests/snapshot_tests.rs b/crates/iota-e2e-tests/tests/snapshot_tests.rs new file mode 100644 index 00000000000..3b8894d51af --- /dev/null +++ b/crates/iota-e2e-tests/tests/snapshot_tests.rs @@ -0,0 +1,80 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use clap::Parser; +use insta::assert_json_snapshot; +use iota::iota_commands::IotaCommand; +use iota_macros::sim_test; +use iota_sdk::wallet_context::WalletContext; +use test_cluster::TestClusterBuilder; + +// special constants for substitution in commands +const ME: &str = "{ME}"; + +async fn run_one( + test: Vec<&str>, + context: &mut WalletContext, +) -> Result, anyhow::Error> { + let mut test_output = Vec::new(); + let active_addr = context.active_address()?.to_string(); + for cli_cmd in test { + let mut cli_cmd_vec = cli_cmd.split(' ').collect::>(); + for word in cli_cmd_vec.iter_mut() { + if *word == ME { + *word = &active_addr + } + } + test_output.push(serde_json::Value::String(cli_cmd.to_string())); + let c = IotaCommand::try_parse_from(cli_cmd_vec)?; + match c { + IotaCommand::Client { cmd, .. } => { + if let Some(client_cmd) = cmd { + match client_cmd.execute(context).await { + Ok(output) => { + if let Some(block_response) = output.tx_block_response() { + test_output.push(serde_json::to_value(block_response)?); + } else if let Some(objects_response) = output.objects_response() { + test_output.push(serde_json::to_value(objects_response)?) + } + } + Err(e) => test_output.push(serde_json::Value::String(e.to_string())), + } + } + } + IotaCommand::Move { + package_path: _, + build_config: _, + cmd: _, + } => unimplemented!("Supporting Move publish and upgrade commands"), + _ => panic!("Command {:?} not supported by RPC snapshot tests", cli_cmd), + } + } + Ok(test_output) +} + +#[ignore] +#[sim_test] +async fn basic_read_cmd_snapshot_tests() -> Result<(), anyhow::Error> { + let mut test_cluster = TestClusterBuilder::new().build().await; + let context = &mut test_cluster.wallet; + + let cmds = vec![ + "iota client objects {ME}", // valid addr + "iota client objects 0x0000000000000000000000000000000000000000000000000000000000000000", /* empty addr */ + "iota client object 0x5", // valid object + "iota client object 0x5 --bcs", // valid object BCS + // Simtest object IDs are not stable so these object IDs may or may not exist currently -- + // commenting them out for now. + // "iota client object 0x3b5121a0603ef7ab4cb57827fceca17db3338ef2cd76126cc1523b681df27cee", + // // valid object "iota client object + // 0x3b5121a0603ef7ab4cb57827fceca17db3338ef2cd76126cc1523b681df27cee --bcs", // valid + // object BCS + "iota client object 0x0000000000000000000000000000000000000000000000000000000000000000", /* non-existent object */ + "iota client tx-block Duwr9uSk9ZvAndEa8oDHunx345i6oyrp3e78MYHVAbYdv", // valid tx digest + "iota client tx-block EgMTHQygMi6SRsBqrPHAEKZCNrpShXurCp9rcb9qbSg8", /* non-existent tx + * digest */ + ]; + assert_json_snapshot!(run_one(cmds, context).await?); + Ok(()) +} diff --git a/crates/sui-e2e-tests/tests/snapshots/snapshot_tests__basic_read_cmd_snapshot_tests.snap b/crates/iota-e2e-tests/tests/snapshots/snapshot_tests__basic_read_cmd_snapshot_tests.snap similarity index 83% rename from crates/sui-e2e-tests/tests/snapshots/snapshot_tests__basic_read_cmd_snapshot_tests.snap rename to crates/iota-e2e-tests/tests/snapshots/snapshot_tests__basic_read_cmd_snapshot_tests.snap index f172483edf4..102d5c89493 100644 --- a/crates/sui-e2e-tests/tests/snapshots/snapshot_tests__basic_read_cmd_snapshot_tests.snap +++ b/crates/iota-e2e-tests/tests/snapshots/snapshot_tests__basic_read_cmd_snapshot_tests.snap @@ -1,16 +1,16 @@ --- -source: crates/sui-e2e-tests/tests/snapshot_tests.rs +source: crates/iota-e2e-tests/tests/snapshot_tests.rs expression: "run_one(cmds, context).await?" --- [ - "sui client objects {ME}", + "iota client objects {ME}", [ { "data": { "objectId": "0x1f06d54bea8de188480b8b7fa04738b74f8de4a304c009ed7546ee1668caa42a", "version": "1", "digest": "3s2ZQ3BLCqb5Q52s7bvSJ1FUK8whocJCPW6bjUfTx4pQ", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0x27b7eae6e24b7175c296a26292d6fbc0ec96f036d42270617a6ca8e0c4310b59" }, @@ -18,7 +18,7 @@ expression: "run_one(cmds, context).await?" "storageRebate": "0", "content": { "dataType": "moveObject", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "hasPublicTransfer": true, "fields": { "balance": "30000000000000000", @@ -34,7 +34,7 @@ expression: "run_one(cmds, context).await?" "objectId": "0x4c5b07bf473981857914de322ba555242af597d856ecaef054b2a4537155a7b7", "version": "1", "digest": "5cpa4GwCUfeW6JsbNWQdd77bH5wYHsK8GKrqgiwC1rdF", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0x27b7eae6e24b7175c296a26292d6fbc0ec96f036d42270617a6ca8e0c4310b59" }, @@ -42,7 +42,7 @@ expression: "run_one(cmds, context).await?" "storageRebate": "0", "content": { "dataType": "moveObject", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "hasPublicTransfer": true, "fields": { "balance": "30000000000000000", @@ -58,7 +58,7 @@ expression: "run_one(cmds, context).await?" "objectId": "0x8e6170e371897b90def1a115e87f7f2f8edb6532812572e9096ed234ddfb09c2", "version": "1", "digest": "AUFXcsqx8sdHo9TTHgP6Rqaz6Nqnmn3Mcq1DAsqFnaFr", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0x27b7eae6e24b7175c296a26292d6fbc0ec96f036d42270617a6ca8e0c4310b59" }, @@ -66,7 +66,7 @@ expression: "run_one(cmds, context).await?" "storageRebate": "0", "content": { "dataType": "moveObject", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "hasPublicTransfer": true, "fields": { "balance": "30000000000000000", @@ -82,7 +82,7 @@ expression: "run_one(cmds, context).await?" "objectId": "0xc90f8c38315f01cc0b3b360d6dc6ca396ebcc30b1824e8b8b7e007d810f547f9", "version": "1", "digest": "DatScUS9tv29UuXTqBM3Z9z2qNySzPv6LQzEVjk1MhKU", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0x27b7eae6e24b7175c296a26292d6fbc0ec96f036d42270617a6ca8e0c4310b59" }, @@ -90,7 +90,7 @@ expression: "run_one(cmds, context).await?" "storageRebate": "0", "content": { "dataType": "moveObject", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "hasPublicTransfer": true, "fields": { "balance": "30000000000000000", @@ -106,7 +106,7 @@ expression: "run_one(cmds, context).await?" "objectId": "0xebef54337dbec7ff13ff1e2c9080a2e6cc5d57d002254bed93198c0dda7bb5c1", "version": "1", "digest": "Gt6Da5BqyvCCjF2t5qzkE1RvwXk8UJzrWG334akGSdex", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0x27b7eae6e24b7175c296a26292d6fbc0ec96f036d42270617a6ca8e0c4310b59" }, @@ -114,7 +114,7 @@ expression: "run_one(cmds, context).await?" "storageRebate": "0", "content": { "dataType": "moveObject", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "hasPublicTransfer": true, "fields": { "balance": "30000000000000000", @@ -126,16 +126,16 @@ expression: "run_one(cmds, context).await?" } } ], - "sui client objects 0x0000000000000000000000000000000000000000000000000000000000000000", + "iota client objects 0x0000000000000000000000000000000000000000000000000000000000000000", [], - "sui client object 0x5", + "iota client object 0x5", [ { "data": { "objectId": "0x0000000000000000000000000000000000000000000000000000000000000005", "version": "1", "digest": "MmKCAHwfU7DrwgAf7LE6C7DEF7xHq8tPxfntbHu9AeS", - "type": "0x3::sui_system::SuiSystemState", + "type": "0x3::iota_system::IotaSystemState", "owner": { "Shared": { "initial_shared_version": { @@ -147,7 +147,7 @@ expression: "run_one(cmds, context).await?" "storageRebate": "0", "content": { "dataType": "moveObject", - "type": "0x3::sui_system::SuiSystemState", + "type": "0x3::iota_system::IotaSystemState", "hasPublicTransfer": false, "fields": { "id": { @@ -159,14 +159,14 @@ expression: "run_one(cmds, context).await?" } } ], - "sui client object 0x5 --bcs", + "iota client object 0x5 --bcs", [ { "data": { "objectId": "0x0000000000000000000000000000000000000000000000000000000000000005", "version": "1", "digest": "MmKCAHwfU7DrwgAf7LE6C7DEF7xHq8tPxfntbHu9AeS", - "type": "0x3::sui_system::SuiSystemState", + "type": "0x3::iota_system::IotaSystemState", "owner": { "Shared": { "initial_shared_version": { @@ -178,7 +178,7 @@ expression: "run_one(cmds, context).await?" "storageRebate": "0", "bcs": { "dataType": "moveObject", - "type": "0x3::sui_system::SuiSystemState", + "type": "0x3::iota_system::IotaSystemState", "hasPublicTransfer": false, "version": { "$serde_json::private::Number": "1" @@ -188,7 +188,7 @@ expression: "run_one(cmds, context).await?" } } ], - "sui client object 0x0000000000000000000000000000000000000000000000000000000000000000", + "iota client object 0x0000000000000000000000000000000000000000000000000000000000000000", [ { "error": { @@ -197,8 +197,8 @@ expression: "run_one(cmds, context).await?" } } ], - "sui client tx-block Duwr9uSk9ZvNdEa8oDHunx345i6oyrp3e78MYHVAbYdv", + "iota client tx-block Duwr9uSk9ZvNdEa8oDHunx345i6oyrp3e78MYHVAbYdv", "RPC call failed: ErrorObject { code: InvalidParams, message: \"Could not find the referenced transaction [TransactionDigest(Duwr9uSk9ZvNdEa8oDHunx345i6oyrp3e78MYHVAbYdv)].\", data: None }", - "sui client tx-block EgMTHQygMi6SRsBqrPHAEKZCNrpShXurCp9rcb9qbSg8", + "iota client tx-block EgMTHQygMi6SRsBqrPHAEKZCNrpShXurCp9rcb9qbSg8", "RPC call failed: ErrorObject { code: InvalidParams, message: \"Could not find the referenced transaction [TransactionDigest(EgMTHQygMi6SRsBqrPHAEKZCNrpShXurCp9rcb9qbSg8)].\", data: None }" ] diff --git a/crates/sui-e2e-tests/tests/transaction_orchestrator_tests.rs b/crates/iota-e2e-tests/tests/transaction_orchestrator_tests.rs similarity index 93% rename from crates/sui-e2e-tests/tests/transaction_orchestrator_tests.rs rename to crates/iota-e2e-tests/tests/transaction_orchestrator_tests.rs index 9e2c90cecfc..d67233d34f9 100644 --- a/crates/sui-e2e-tests/tests/transaction_orchestrator_tests.rs +++ b/crates/iota-e2e-tests/tests/transaction_orchestrator_tests.rs @@ -1,27 +1,28 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{sync::Arc, time::Duration}; -use prometheus::Registry; -use sui_core::{ +use iota_core::{ authority::EffectsNotifyRead, authority_client::NetworkAuthorityClient, transaction_orchestrator::TransactiondOrchestrator, }; -use sui_macros::sim_test; -use sui_storage::{ +use iota_macros::sim_test; +use iota_storage::{ key_value_store::TransactionKeyValueStore, key_value_store_metrics::KeyValueStoreMetrics, }; -use sui_test_transaction_builder::{ - batch_make_transfer_transactions, make_transfer_sui_transaction, +use iota_test_transaction_builder::{ + batch_make_transfer_transactions, make_transfer_iota_transaction, }; -use sui_types::{ +use iota_types::{ quorum_driver_types::{ ExecuteTransactionRequest, ExecuteTransactionRequestType, ExecuteTransactionResponse, FinalizedEffects, QuorumDriverError, }, transaction::Transaction, }; +use prometheus::Registry; use test_cluster::TestClusterBuilder; use tokio::time::timeout; use tracing::info; @@ -30,7 +31,7 @@ use tracing::info; async fn test_blocking_execution() -> Result<(), anyhow::Error> { let mut test_cluster = TestClusterBuilder::new().build().await; let context = &mut test_cluster.wallet; - let handle = &test_cluster.fullnode_handle.sui_node; + let handle = &test_cluster.fullnode_handle.iota_node; let temp_dir = tempfile::tempdir().unwrap(); let registry = Registry::new(); @@ -112,7 +113,7 @@ async fn test_fullnode_wal_log() -> Result<(), anyhow::Error> { .build() .await; - let handle = &test_cluster.fullnode_handle.sui_node; + let handle = &test_cluster.fullnode_handle.iota_node; let temp_dir = tempfile::tempdir().unwrap(); tokio::task::yield_now().await; @@ -199,7 +200,7 @@ async fn test_fullnode_wal_log() -> Result<(), anyhow::Error> { async fn test_transaction_orchestrator_reconfig() { telemetry_subscribers::init_for_testing(); let test_cluster = TestClusterBuilder::new().build().await; - let epoch = test_cluster.fullnode_handle.sui_node.with(|node| { + let epoch = test_cluster.fullnode_handle.iota_node.with(|node| { node.transaction_orchestrator() .unwrap() .quorum_driver() @@ -215,7 +216,7 @@ async fn test_transaction_orchestrator_reconfig() { // reliable. timeout(Duration::from_secs(5), async { loop { - let epoch = test_cluster.fullnode_handle.sui_node.with(|node| { + let epoch = test_cluster.fullnode_handle.iota_node.with(|node| { node.transaction_orchestrator() .unwrap() .quorum_driver() @@ -231,7 +232,7 @@ async fn test_transaction_orchestrator_reconfig() { .unwrap(); assert_eq!( - test_cluster.fullnode_handle.sui_node.with(|node| node + test_cluster.fullnode_handle.iota_node.with(|node| node .clone_authority_aggregator() .unwrap() .committee @@ -247,7 +248,7 @@ async fn test_tx_across_epoch_boundaries() { let (result_tx, mut result_rx) = tokio::sync::mpsc::channel::(total_tx_cnt); let test_cluster = TestClusterBuilder::new().build().await; - let tx = make_transfer_sui_transaction(&test_cluster.wallet, None, None).await; + let tx = make_transfer_iota_transaction(&test_cluster.wallet, None, None).await; let authorities = test_cluster.swarm.validator_node_handles(); // We first let 2 validators stop accepting user cert @@ -262,7 +263,7 @@ async fn test_tx_across_epoch_boundaries() { // across the epoch boundary. let to = test_cluster .fullnode_handle - .sui_node + .iota_node .with(|node| node.transaction_orchestrator().unwrap()); let tx_digest = *tx.digest(); diff --git a/crates/iota-e2e-tests/tests/transfer_to_object_tests.rs b/crates/iota-e2e-tests/tests/transfer_to_object_tests.rs new file mode 100644 index 00000000000..ba8eefac724 --- /dev/null +++ b/crates/iota-e2e-tests/tests/transfer_to_object_tests.rs @@ -0,0 +1,257 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::HashSet, path::PathBuf}; + +use iota_core::authority_client::AuthorityAPI; +use iota_macros::*; +use iota_test_transaction_builder::publish_package; +use iota_types::{ + base_types::{ObjectID, ObjectRef}, + effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, + error::IotaError, + object::Owner, + transaction::{CallArg, ObjectArg, Transaction}, +}; +use test_cluster::{TestCluster, TestClusterBuilder}; + +#[sim_test] +async fn receive_object_feature_deny() { + use iota_protocol_config::ProtocolConfig; + + let _guard = ProtocolConfig::apply_overrides_for_testing(|_, mut config| { + config.set_receive_object_for_testing(false); + config + }); + + let env = TestEnvironment::new().await; + let (parent, child) = env.start().await; + let arguments = vec![ + CallArg::Object(ObjectArg::ImmOrOwnedObject(parent)), + CallArg::Object(ObjectArg::Receiving(child)), + ]; + let txn = env.create_move_call("receiver", arguments).await; + let err = env + .test_cluster + .authority_aggregator() + .authority_clients + .values() + .next() + .unwrap() + .authority_client() + .handle_transaction(txn) + .await + .map(|_| ()) + .unwrap_err(); + + assert!(matches!(err, IotaError::UnsupportedFeatureError { .. })); +} + +#[sim_test] +async fn receive_of_object() { + let env = TestEnvironment::new().await; + let (parent, child) = env.start().await; + env.receive(parent, child).await.unwrap(); +} + +#[sim_test] +async fn receive_of_object_with_reconfiguration() { + let env = TestEnvironment::new().await; + let (parent, child) = env.start().await; + env.receive(parent, child).await.unwrap(); + env.test_cluster.trigger_reconfiguration().await; +} + +#[sim_test] +async fn receive_of_object_with_reconfiguration_receive_after_reconfig() { + let env = TestEnvironment::new().await; + let (parent, child) = env.start().await; + let (new_parent, new_child) = env.receive(parent, child).await.unwrap(); + env.test_cluster.trigger_reconfiguration().await; + assert!(env.receive(new_parent, new_child).await.is_ok()); +} + +#[sim_test] +async fn receive_of_object_with_reconfiguration_receive_of_old_child_after_reconfig() { + let env = TestEnvironment::new().await; + let (parent, child) = env.start().await; + let (new_parent, _) = env.receive(parent, child).await.unwrap(); + env.test_cluster.trigger_reconfiguration().await; + assert!(env.receive(new_parent, child).await.is_err()); +} + +#[sim_test] +async fn receive_of_object_with_reconfiguration_receive_of_old_parent_after_reconfig() { + let env = TestEnvironment::new().await; + let (parent, child) = env.start().await; + let (_, new_child) = env.receive(parent, child).await.unwrap(); + env.test_cluster.trigger_reconfiguration().await; + assert!(env.receive(parent, new_child).await.is_err()); +} + +#[sim_test] +async fn receive_of_object_with_reconfiguration_receive_of_old_parent_and_child_after_reconfig() { + let env = TestEnvironment::new().await; + let (parent, child) = env.start().await; + env.receive(parent, child).await.unwrap(); + env.test_cluster.trigger_reconfiguration().await; + assert!(env.receive(parent, child).await.is_err()); +} + +#[sim_test] +async fn receive_of_object_with_reconfiguration_receive_after_reconfig_with_invalid_child() { + let env = TestEnvironment::new().await; + let (parent, child) = env.start().await; + let (new_parent, new_child) = env.receive(parent, child).await.unwrap(); + env.test_cluster.trigger_reconfiguration().await; + assert!(env.receive(new_child, new_parent).await.is_err()); +} + +#[sim_test] +async fn delete_of_object_with_reconfiguration_receive_of_old_parent_and_child_after_reconfig() { + let env = TestEnvironment::new().await; + let (parent, child) = env.start().await; + env.delete(parent, child).await; + env.test_cluster.trigger_reconfiguration().await; + assert!(env.receive(parent, child).await.is_err()); +} + +#[sim_test] +async fn delete_of_object_with_reconfiguration_receive_of_new_parent_and_old_child_after_reconfig() +{ + let env = TestEnvironment::new().await; + let (parent, child) = env.start().await; + let new_parent = env.delete(parent, child).await; + env.test_cluster.trigger_reconfiguration().await; + assert!(env.receive(new_parent, child).await.is_err()); +} + +fn get_parent_and_child(created: Vec<(ObjectRef, Owner)>) -> (ObjectRef, ObjectRef) { + // make sure there is an object with an `AddressOwner` who matches the object ID + // of another object. + let created_addrs: HashSet<_> = created.iter().map(|((i, _, _), _)| i).collect(); + let (child, parent_id) = created + .iter() + .find_map(|child @ (_, owner)| match owner { + Owner::AddressOwner(j) if created_addrs.contains(&ObjectID::from(*j)) => { + Some((child, (*j).into())) + } + _ => None, + }) + .unwrap(); + let parent = created + .iter() + .find(|((id, _, _), _)| *id == parent_id) + .unwrap(); + (parent.0, child.0) +} + +struct TestEnvironment { + pub test_cluster: TestCluster, + move_package: ObjectID, +} + +impl TestEnvironment { + async fn new() -> Self { + let test_cluster = TestClusterBuilder::new().build().await; + + let move_package = publish_move_package(&test_cluster).await.0; + + Self { + test_cluster, + move_package, + } + } + + async fn create_move_call( + &self, + function: &'static str, + arguments: Vec, + ) -> Transaction { + let transaction = self + .test_cluster + .test_transaction_builder() + .await + .move_call(self.move_package, "tto", function, arguments) + .build(); + self.test_cluster.wallet.sign_transaction(&transaction) + } + + async fn move_call( + &self, + function: &'static str, + arguments: Vec, + ) -> anyhow::Result<(TransactionEffects, TransactionEvents)> { + let transaction = self.create_move_call(function, arguments).await; + self.test_cluster + .execute_transaction_return_raw_effects(transaction) + .await + } + + async fn start(&self) -> (ObjectRef, ObjectRef) { + let (fx, _) = self.move_call("start", vec![]).await.unwrap(); + assert!(fx.status().is_ok()); + + get_parent_and_child(fx.created()) + } + + async fn receive( + &self, + parent: ObjectRef, + child: ObjectRef, + ) -> anyhow::Result<(ObjectRef, ObjectRef)> { + let arguments = vec![ + CallArg::Object(ObjectArg::ImmOrOwnedObject(parent)), + CallArg::Object(ObjectArg::Receiving(child)), + ]; + let fx = self.move_call("receiver", arguments).await?; + assert!(fx.0.status().is_ok()); + let new_child_ref = + fx.0.mutated_excluding_gas() + .iter() + .find_map( + |(oref, _)| { + if oref.0 == child.0 { Some(*oref) } else { None } + }, + ) + .unwrap(); + let new_parent_ref = + fx.0.mutated_excluding_gas() + .iter() + .find_map(|(oref, _)| { + if oref.0 == parent.0 { + Some(*oref) + } else { + None + } + }) + .unwrap(); + Ok((new_parent_ref, new_child_ref)) + } + + async fn delete(&self, parent: ObjectRef, child: ObjectRef) -> ObjectRef { + let arguments = vec![ + CallArg::Object(ObjectArg::ImmOrOwnedObject(parent)), + CallArg::Object(ObjectArg::Receiving(child)), + ]; + let fx = self.move_call("deleter", arguments).await.unwrap(); + assert!(fx.0.status().is_ok()); + fx.0.mutated_excluding_gas() + .iter() + .find_map(|(oref, _)| { + if oref.0 == parent.0 { + Some(*oref) + } else { + None + } + }) + .unwrap() + } +} + +async fn publish_move_package(test_cluster: &TestCluster) -> ObjectRef { + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push("tests/move_test_code"); + publish_package(&test_cluster.wallet, path).await +} diff --git a/crates/sui-e2e-tests/tests/zklogin_tests.rs b/crates/iota-e2e-tests/tests/zklogin_tests.rs similarity index 85% rename from crates/sui-e2e-tests/tests/zklogin_tests.rs rename to crates/iota-e2e-tests/tests/zklogin_tests.rs index ff4602d87ae..b4029b95c65 100644 --- a/crates/sui-e2e-tests/tests/zklogin_tests.rs +++ b/crates/iota-e2e-tests/tests/zklogin_tests.rs @@ -1,15 +1,15 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use shared_crypto::intent::{Intent, IntentMessage}; -use sui_core::authority_client::AuthorityAPI; -use sui_macros::sim_test; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ - base_types::SuiAddress, +use iota_core::authority_client::AuthorityAPI; +use iota_macros::sim_test; +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ + base_types::IotaAddress, crypto::Signature, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, signature::GenericSignature, transaction::Transaction, utils::{ @@ -17,11 +17,12 @@ use sui_types::{ make_zklogin_tx, }, zk_login_authenticator::ZkLoginAuthenticator, - SUI_AUTHENTICATOR_STATE_OBJECT_ID, + IOTA_AUTHENTICATOR_STATE_OBJECT_ID, }; +use shared_crypto::intent::{Intent, IntentMessage}; use test_cluster::TestClusterBuilder; -async fn do_zklogin_test(address: SuiAddress, legacy: bool) -> SuiResult { +async fn do_zklogin_test(address: IotaAddress, legacy: bool) -> IotaResult { let test_cluster = TestClusterBuilder::new().build().await; let (_, tx, _) = make_zklogin_tx(address, legacy); @@ -39,7 +40,7 @@ async fn do_zklogin_test(address: SuiAddress, legacy: bool) -> SuiResult { #[sim_test] async fn test_zklogin_feature_deny() { - use sui_protocol_config::ProtocolConfig; + use iota_protocol_config::ProtocolConfig; let _guard = ProtocolConfig::apply_overrides_for_testing(|_, mut config| { config.set_zklogin_auth_for_testing(false); @@ -50,12 +51,12 @@ async fn test_zklogin_feature_deny() { .await .unwrap_err(); - assert!(matches!(err, SuiError::UnsupportedFeatureError { .. })); + assert!(matches!(err, IotaError::UnsupportedFeatureError { .. })); } #[sim_test] async fn test_zklogin_feature_legacy_address_deny() { - use sui_protocol_config::ProtocolConfig; + use iota_protocol_config::ProtocolConfig; let _guard = ProtocolConfig::apply_overrides_for_testing(|_, mut config| { config.set_verify_legacy_zklogin_address(false); @@ -65,12 +66,12 @@ async fn test_zklogin_feature_legacy_address_deny() { let err = do_zklogin_test(get_legacy_zklogin_user_address(), true) .await .unwrap_err(); - assert!(matches!(err, SuiError::SignerSignatureAbsent { .. })); + assert!(matches!(err, IotaError::SignerSignatureAbsent { .. })); } #[sim_test] async fn test_legacy_zklogin_address_accept() { - use sui_protocol_config::ProtocolConfig; + use iota_protocol_config::ProtocolConfig; let _guard = ProtocolConfig::apply_overrides_for_testing(|_, mut config| { config.set_verify_legacy_zklogin_address(true); config @@ -80,7 +81,7 @@ async fn test_legacy_zklogin_address_accept() { .unwrap_err(); // it does not hit the signer absent error. - assert!(matches!(err, SuiError::InvalidSignature { .. })); + assert!(matches!(err, IotaError::InvalidSignature { .. })); } #[sim_test] @@ -96,7 +97,7 @@ async fn zklogin_end_to_end_test() { // load test vectors let (kp, pk_zklogin, inputs) = - &load_test_vectors("../sui-types/src/unit_tests/zklogin_test_vectors.json")[1]; + &load_test_vectors("../iota-types/src/unit_tests/zklogin_test_vectors.json")[1]; let zklogin_addr = (pk_zklogin).into(); let rgp = test_cluster.get_reference_gas_price().await; @@ -104,10 +105,10 @@ async fn zklogin_end_to_end_test() { .fund_address_and_return_gas(rgp, Some(20000000000), zklogin_addr) .await; let tx_data = TestTransactionBuilder::new(zklogin_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) + .transfer_iota(None, IotaAddress::ZERO) .build(); - let msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); + let msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); let eph_sig = Signature::new_secure(&msg, kp); // combine ephemeral sig with zklogin inputs. @@ -154,7 +155,7 @@ async fn test_expired_zklogin_sig() { test_cluster.trigger_reconfiguration().await; // load one test vector, the zklogin inputs corresponds to max_epoch = 1 let (kp, pk_zklogin, inputs) = - &load_test_vectors("../sui-types/src/unit_tests/zklogin_test_vectors.json")[1]; + &load_test_vectors("../iota-types/src/unit_tests/zklogin_test_vectors.json")[1]; let zklogin_addr = (pk_zklogin).into(); let rgp = test_cluster.get_reference_gas_price().await; @@ -162,10 +163,10 @@ async fn test_expired_zklogin_sig() { .fund_address_and_return_gas(rgp, Some(20000000000), zklogin_addr) .await; let tx_data = TestTransactionBuilder::new(zklogin_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) + .transfer_iota(None, IotaAddress::ZERO) .build(); - let msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); + let msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); let eph_sig = Signature::new_secure(&msg, kp); // combine ephemeral sig with zklogin inputs. @@ -220,7 +221,7 @@ async fn test_create_authenticator_state_object() { assert!( node.state() .get_cache_reader() - .get_latest_object_ref_or_tombstone(SUI_AUTHENTICATOR_STATE_OBJECT_ID) + .get_latest_object_ref_or_tombstone(IOTA_AUTHENTICATOR_STATE_OBJECT_ID) .unwrap() .is_none() ); @@ -237,7 +238,7 @@ async fn test_create_authenticator_state_object() { h.with(|node| { node.state() .get_cache_reader() - .get_latest_object_ref_or_tombstone(SUI_AUTHENTICATOR_STATE_OBJECT_ID) + .get_latest_object_ref_or_tombstone(IOTA_AUTHENTICATOR_STATE_OBJECT_ID) .unwrap() .expect("auth state object should exist"); }); @@ -255,8 +256,8 @@ async fn test_conflicting_jwks() { }; use futures::StreamExt; - use sui_json_rpc_types::{SuiTransactionBlockEffectsAPI, TransactionFilter}; - use sui_types::{ + use iota_json_rpc_types::{IotaTransactionBlockEffectsAPI, TransactionFilter}; + use iota_types::{ base_types::ObjectID, transaction::{TransactionDataAPI, TransactionKind}, }; @@ -271,7 +272,7 @@ async fn test_conflicting_jwks() { let jwks = Arc::new(Mutex::new(Vec::new())); let jwks_clone = jwks.clone(); - test_cluster.fullnode_handle.sui_node.with(|node| { + test_cluster.fullnode_handle.iota_node.with(|node| { let mut txns = node.state().subscription_handler.subscribe_transactions( TransactionFilter::ChangedObject(ObjectID::from_hex_literal("0x7").unwrap()), ); diff --git a/crates/iota-enum-compat-util/Cargo.toml b/crates/iota-enum-compat-util/Cargo.toml new file mode 100644 index 00000000000..e088979a9ee --- /dev/null +++ b/crates/iota-enum-compat-util/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "iota-enum-compat-util" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +serde_yaml.workspace = true diff --git a/crates/iota-enum-compat-util/src/lib.rs b/crates/iota-enum-compat-util/src/lib.rs new file mode 100644 index 00000000000..342c83824b4 --- /dev/null +++ b/crates/iota-enum-compat-util/src/lib.rs @@ -0,0 +1,52 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{io::Write, path::PathBuf}; + +pub trait EnumOrderMap { + fn order_to_variant_map() -> std::collections::BTreeMap; +} + +pub fn check_enum_compat_order(snapshot_file: PathBuf) { + let new_map = T::order_to_variant_map(); + + if let Err(err) = std::fs::read_to_string(snapshot_file.clone()) { + if err.kind() == std::io::ErrorKind::NotFound { + // Create the file if not exists + let mut file = std::fs::File::create(snapshot_file).unwrap(); + let content: String = serde_yaml::to_string(&new_map).unwrap(); + + write!(file, "{}", content).unwrap(); + return; + } + panic!("Error reading file: {:?}: err {:?}", snapshot_file, err); + } + + let existing_map: std::collections::BTreeMap = + serde_yaml::from_str(&std::fs::read_to_string(snapshot_file.clone()).unwrap()).unwrap(); + + // Check that the new map includes the existing map in order + for (pos, val) in existing_map { + match new_map.get(&pos) { + None => { + panic!( + "Enum variant {} has been removed. Not allowed: enum must be backward compatible.", + val + ); + } + Some(new_val) if new_val == &val => continue, + Some(new_val) => { + panic!( + "Enum variant {val} has been swapped with {new_val} at position {pos}. Not allowed: enum must be backward compatible." + ); + } + } + } + + // Update the file + let mut file = std::fs::File::create(snapshot_file).unwrap(); + let content: String = serde_yaml::to_string(&new_map).unwrap(); + + write!(file, "{}", content).unwrap(); +} diff --git a/crates/iota-faucet/Cargo.toml b/crates/iota-faucet/Cargo.toml new file mode 100644 index 00000000000..214fbcf1d0e --- /dev/null +++ b/crates/iota-faucet/Cargo.toml @@ -0,0 +1,50 @@ +[package] +name = "iota-faucet" +version.workspace = true +edition = "2021" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false + +[dependencies] +anyhow.workspace = true +async-trait.workspace = true +axum.workspace = true +clap.workspace = true +thiserror.workspace = true +tokio = { workspace = true, features = ["full"] } +tracing.workspace = true +serde.workspace = true +tower.workspace = true +tower-http.workspace = true +http.workspace = true +futures.workspace = true +uuid.workspace = true +prometheus.workspace = true +scopeguard.workspace = true +tap.workspace = true +ttl_cache.workspace = true +eyre.workspace = true +rocksdb.workspace = true +tempfile.workspace = true +parking_lot.workspace = true + +iota.workspace = true +iota-json-rpc-types.workspace = true +iota-types.workspace = true +iota-config.workspace = true +iota-keys.workspace = true +iota-sdk.workspace = true +mysten-metrics.workspace = true +telemetry-subscribers.workspace = true +typed-store.workspace = true +typed-store-derive.workspace = true +shared-crypto.workspace = true +async-recursion.workspace = true + +[dev-dependencies] +test-cluster.workspace = true + +[[bin]] +name = "iota-faucet" +path = "src/main.rs" diff --git a/crates/sui-faucet/src/bin/merge_coins.rs b/crates/iota-faucet/src/bin/merge_coins.rs similarity index 83% rename from crates/sui-faucet/src/bin/merge_coins.rs rename to crates/iota-faucet/src/bin/merge_coins.rs index 3cb3946880e..f7adf0961c1 100644 --- a/crates/sui-faucet/src/bin/merge_coins.rs +++ b/crates/iota-faucet/src/bin/merge_coins.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{str::FromStr, time::Duration}; -use shared_crypto::intent::Intent; -use sui_config::{sui_config_dir, SUI_CLIENT_CONFIG}; -use sui_faucet::FaucetError; -use sui_json_rpc_types::SuiTransactionBlockResponseOptions; -use sui_keys::keystore::AccountKeystore; -use sui_sdk::wallet_context::WalletContext; -use sui_types::{ +use iota_config::{iota_config_dir, IOTA_CLIENT_CONFIG}; +use iota_faucet::FaucetError; +use iota_json_rpc_types::IotaTransactionBlockResponseOptions; +use iota_keys::keystore::AccountKeystore; +use iota_sdk::wallet_context::WalletContext; +use iota_types::{ base_types::ObjectID, gas_coin::GasCoin, quorum_driver_types::ExecuteTransactionRequestType, transaction::Transaction, }; +use shared_crypto::intent::Intent; use tracing::info; #[tokio::main] @@ -57,14 +58,14 @@ async fn _split_coins_equally( let signature = wallet .config .keystore - .sign_secure(&active_address, &tx_data, Intent::sui_transaction()) + .sign_secure(&active_address, &tx_data, Intent::iota_transaction()) .unwrap(); let tx = Transaction::from_data(tx_data, vec![signature]); let resp = client .quorum_driver_api() .execute_transaction_block( tx.clone(), - SuiTransactionBlockResponseOptions::new().with_effects(), + IotaTransactionBlockResponseOptions::new().with_effects(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; @@ -87,7 +88,7 @@ async fn _merge_coins(gas_coin: &str, mut wallet: WalletContext) -> Result<(), a .iter() // Ok to unwrap() since `get_gas_objects` guarantees gas .map(|q| GasCoin::try_from(&q.1).unwrap()) - // Everything less than 1 sui + // Everything less than 1 iota .filter(|coin| coin.0.balance.value() <= 10000000000) .collect::>(); @@ -107,19 +108,19 @@ async fn _merge_coins(gas_coin: &str, mut wallet: WalletContext) -> Result<(), a let tx_data = client .transaction_builder() - .pay_sui(active_address, coin_vector, target, target_amount, 1000000) + .pay_iota(active_address, coin_vector, target, target_amount, 1000000) .await?; let signature = wallet .config .keystore - .sign_secure(&active_address, &tx_data, Intent::sui_transaction()) + .sign_secure(&active_address, &tx_data, Intent::iota_transaction()) .unwrap(); let tx = Transaction::from_data(tx_data, vec![signature]); client .quorum_driver_api() .execute_transaction_block( tx.clone(), - SuiTransactionBlockResponseOptions::new().with_effects(), + IotaTransactionBlockResponseOptions::new().with_effects(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; @@ -128,7 +129,7 @@ async fn _merge_coins(gas_coin: &str, mut wallet: WalletContext) -> Result<(), a } pub fn create_wallet_context(timeout_secs: u64) -> Result { - let wallet_conf = sui_config_dir()?.join(SUI_CLIENT_CONFIG); + let wallet_conf = iota_config_dir()?.join(IOTA_CLIENT_CONFIG); info!("Initialize wallet from config path: {:?}", wallet_conf); WalletContext::new(&wallet_conf, Some(Duration::from_secs(timeout_secs)), None) } diff --git a/crates/iota-faucet/src/errors.rs b/crates/iota-faucet/src/errors.rs new file mode 100644 index 00000000000..95cbdf82b9a --- /dev/null +++ b/crates/iota-faucet/src/errors.rs @@ -0,0 +1,52 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use thiserror::Error; + +#[derive(Error, Debug, PartialEq, Eq)] +pub enum FaucetError { + #[error("Faucet cannot read objects from fullnode: {0}")] + FullnodeReadingError(String), + + #[error("Failed to parse transaction response {0}")] + ParseTransactionResponseError(String), + + #[error( + "Gas coin `{0}` does not have sufficient balance and has been removed from gas coin pool" + )] + GasCoinWithInsufficientBalance(String), + + #[error("Faucet does not have enough balance")] + InsuffientBalance, + + #[error("Gas coin `{0}` is not valid and has been removed from gas coin pool")] + InvalidGasCoin(String), + + #[error("Timed out waiting for a coin from the gas coin pool")] + NoGasCoinAvailable, + + #[error("Wallet Error: `{0}`")] + Wallet(String), + + #[error("Coin Transfer Failed `{0}`")] + Transfer(String), + + #[error("Too many coins in the batch queue. Please try again later.")] + BatchSendQueueFull, + + #[error("Request consumer queue closed.")] + ChannelClosed, + + #[error("Coin amounts sent are incorrect:`{0}`")] + CoinAmountTransferredIncorrect(String), + + #[error("Internal error: {0}")] + Internal(String), +} + +impl FaucetError { + pub(crate) fn internal(e: impl ToString) -> Self { + FaucetError::Internal(e.to_string()) + } +} diff --git a/crates/iota-faucet/src/faucet/mod.rs b/crates/iota-faucet/src/faucet/mod.rs new file mode 100644 index 00000000000..b8288871f15 --- /dev/null +++ b/crates/iota-faucet/src/faucet/mod.rs @@ -0,0 +1,142 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use async_trait::async_trait; +use iota_types::base_types::{IotaAddress, ObjectID, TransactionDigest}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use crate::FaucetError; + +mod simple_faucet; +mod write_ahead_log; +use std::{net::Ipv4Addr, path::PathBuf}; + +use clap::Parser; + +pub use self::simple_faucet::SimpleFaucet; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct FaucetReceipt { + pub sent: Vec, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct BatchFaucetReceipt { + pub task: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct CoinInfo { + pub amount: u64, + pub id: ObjectID, + pub transfer_tx_digest: TransactionDigest, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct BatchSendStatus { + pub status: BatchSendStatusType, + pub transferred_gas_objects: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[serde(rename_all = "UPPERCASE")] +pub enum BatchSendStatusType { + INPROGRESS, + SUCCEEDED, + DISCARDED, +} + +#[async_trait] +pub trait Faucet { + /// Send `Coin` of the specified amount to the recipient + async fn send( + &self, + id: Uuid, + recipient: IotaAddress, + amounts: &[u64], + ) -> Result; + + /// Send `Coin` of the specified amount to the recipient in a batch + /// request + async fn batch_send( + &self, + id: Uuid, + recipient: IotaAddress, + amounts: &[u64], + ) -> Result; + + /// Get the status of a batch_send request + async fn get_batch_send_status(&self, task_id: Uuid) -> Result; +} + +pub const DEFAULT_AMOUNT: u64 = 1_000_000_000; +pub const DEFAULT_NUM_OF_COINS: usize = 1; + +#[derive(Parser, Clone)] +#[clap( + name = "Iota Faucet", + about = "Faucet for requesting test tokens on Iota", + rename_all = "kebab-case" +)] +pub struct FaucetConfig { + #[clap(long, default_value_t = 5003)] + pub port: u16, + + #[clap(long, default_value = "127.0.0.1")] + pub host_ip: Ipv4Addr, + + #[clap(long, default_value_t = DEFAULT_AMOUNT)] + pub amount: u64, + + #[clap(long, default_value_t = DEFAULT_NUM_OF_COINS)] + pub num_coins: usize, + + #[clap(long, default_value_t = 10)] + pub request_buffer_size: usize, + + #[clap(long, default_value_t = 10)] + pub max_request_per_second: u64, + + #[clap(long, default_value_t = 60)] + pub wallet_client_timeout_secs: u64, + + #[clap(long)] + pub write_ahead_log: PathBuf, + + #[clap(long, default_value_t = 300)] + pub wal_retry_interval: u64, + + #[clap(long, default_value_t = 10000)] + pub max_request_queue_length: u64, + + #[clap(long, default_value_t = 500)] + pub batch_request_size: u64, + + #[clap(long, default_value_t = 300)] + pub ttl_expiration: u64, + + #[clap(long, action = clap::ArgAction::Set, default_value_t = false)] + pub batch_enabled: bool, +} + +impl Default for FaucetConfig { + fn default() -> Self { + Self { + port: 5003, + host_ip: Ipv4Addr::new(127, 0, 0, 1), + amount: 1_000_000_000, + num_coins: 1, + request_buffer_size: 10, + max_request_per_second: 10, + wallet_client_timeout_secs: 60, + write_ahead_log: Default::default(), + wal_retry_interval: 300, + max_request_queue_length: 10000, + batch_request_size: 500, + ttl_expiration: 300, + batch_enabled: false, + } + } +} diff --git a/crates/sui-faucet/src/faucet/simple_faucet.rs b/crates/iota-faucet/src/faucet/simple_faucet.rs similarity index 91% rename from crates/sui-faucet/src/faucet/simple_faucet.rs rename to crates/iota-faucet/src/faucet/simple_faucet.rs index 7b188afeebd..aeda6a0859c 100644 --- a/crates/sui-faucet/src/faucet/simple_faucet.rs +++ b/crates/iota-faucet/src/faucet/simple_faucet.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[cfg(test)] @@ -12,23 +13,23 @@ use std::{ use async_recursion::async_recursion; use async_trait::async_trait; -use mysten_metrics::spawn_monitored_task; -use prometheus::Registry; -use shared_crypto::intent::Intent; -use sui_json_rpc_types::{ - OwnedObjectRef, SuiObjectDataOptions, SuiTransactionBlockEffectsAPI, - SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, +use iota_json_rpc_types::{ + IotaObjectDataOptions, IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponse, + IotaTransactionBlockResponseOptions, OwnedObjectRef, }; -use sui_keys::keystore::AccountKeystore; -use sui_sdk::wallet_context::WalletContext; -use sui_types::{ - base_types::{ObjectID, SuiAddress, TransactionDigest}, +use iota_keys::keystore::AccountKeystore; +use iota_sdk::wallet_context::WalletContext; +use iota_types::{ + base_types::{IotaAddress, ObjectID, TransactionDigest}, gas_coin::GasCoin, object::Owner, programmable_transaction_builder::ProgrammableTransactionBuilder, quorum_driver_types::ExecuteTransactionRequestType, transaction::{Transaction, TransactionData}, }; +use mysten_metrics::spawn_monitored_task; +use prometheus::Registry; +use shared_crypto::intent::Intent; use tap::tap::TapFallible; use tokio::{ sync::{ @@ -50,14 +51,14 @@ use crate::{ pub struct SimpleFaucet { wallet: WalletContext, - active_address: SuiAddress, + active_address: IotaAddress, producer: Mutex>, consumer: Mutex>, batch_producer: Mutex>, batch_consumer: Mutex>, pub metrics: FaucetMetrics, pub wal: Mutex, - request_producer: Sender<(Uuid, SuiAddress, Vec)>, + request_producer: Sender<(Uuid, IotaAddress, Vec)>, batch_request_size: u64, task_id_cache: Mutex>, ttl_expiration: u64, @@ -125,8 +126,9 @@ impl SimpleFaucet { let (producer, consumer) = mpsc::channel(coins.len()); let (batch_producer, batch_consumer) = mpsc::channel(coins.len()); - let (sender, mut receiver) = - mpsc::channel::<(Uuid, SuiAddress, Vec)>(config.max_request_queue_length as usize); + let (sender, mut receiver) = mpsc::channel::<(Uuid, IotaAddress, Vec)>( + config.max_request_queue_length as usize, + ); // This is to handle the case where there is only 1 coin, we want it to go to // the normal queue @@ -346,7 +348,7 @@ impl SimpleFaucet { .read_api() .get_object_with_options( coin_id, - SuiObjectDataOptions::new() + IotaObjectDataOptions::new() .with_type() .with_owner() .with_content(), @@ -416,16 +418,16 @@ impl SimpleFaucet { async fn sign_and_execute_txn( &self, uuid: Uuid, - recipient: SuiAddress, + recipient: IotaAddress, coin_id: ObjectID, tx_data: TransactionData, for_batch: bool, - ) -> Result { + ) -> Result { let signature = self .wallet .config .keystore - .sign_secure(&self.active_address, &tx_data, Intent::sui_transaction()) + .sign_secure(&self.active_address, &tx_data, Intent::iota_transaction()) .map_err(FaucetError::internal)?; let tx = Transaction::from_data(tx_data, vec![signature]); let tx_digest = *tx.digest(); @@ -434,12 +436,12 @@ impl SimpleFaucet { ?recipient, ?coin_id, ?uuid, - "PaySui transaction in faucet." + "PayIota transaction in faucet." ); match timeout( Duration::from_secs(300), - self.execute_pay_sui_txn_with_retries(&tx, coin_id, recipient, uuid), + self.execute_pay_iota_txn_with_retries(&tx, coin_id, recipient, uuid), ) .await { @@ -448,7 +450,7 @@ impl SimpleFaucet { ?recipient, ?coin_id, ?uuid, - "Failed to execute PaySui transactions in faucet after {elapsed}. Coin will \ + "Failed to execute PayIota transactions in faucet after {elapsed}. Coin will \ not be reused." ); @@ -498,7 +500,7 @@ impl SimpleFaucet { async fn transfer_gases( &self, amounts: &[u64], - recipient: SuiAddress, + recipient: IotaAddress, uuid: Uuid, ) -> Result<(TransactionDigest, Vec), FaucetError> { let number_of_coins = amounts.len(); @@ -511,7 +513,7 @@ impl SimpleFaucet { match gas_coin_response { GasCoinResponse::ValidGasCoin(coin_id) => { let tx_data = self - .build_pay_sui_txn(coin_id, self.active_address, recipient, amounts, gas_cost) + .build_pay_iota_txn(coin_id, self.active_address, recipient, amounts, gas_cost) .await .map_err(FaucetError::internal)?; @@ -581,17 +583,19 @@ impl SimpleFaucet { info!(?uuid, ?coin_id, "Recycled coin"); } - async fn execute_pay_sui_txn_with_retries( + async fn execute_pay_iota_txn_with_retries( &self, tx: &Transaction, coin_id: ObjectID, - recipient: SuiAddress, + recipient: IotaAddress, uuid: Uuid, - ) -> SuiTransactionBlockResponse { + ) -> IotaTransactionBlockResponse { let mut retry_delay = Duration::from_millis(500); loop { - let res = self.execute_pay_sui_txn(tx, coin_id, recipient, uuid).await; + let res = self + .execute_pay_iota_txn(tx, coin_id, recipient, uuid) + .await; if let Ok(res) = res { return res; @@ -602,7 +606,7 @@ impl SimpleFaucet { ?coin_id, ?uuid, ?retry_delay, - "PaySui transaction in faucet failed, previous error: {:?}", + "PayIota transaction in faucet failed, previous error: {:?}", &res, ); @@ -611,13 +615,13 @@ impl SimpleFaucet { } } - async fn execute_pay_sui_txn( + async fn execute_pay_iota_txn( &self, tx: &Transaction, coin_id: ObjectID, - recipient: SuiAddress, + recipient: IotaAddress, uuid: Uuid, - ) -> Result { + ) -> Result { self.metrics.current_executions_in_flight.inc(); let _metrics_guard = scopeguard::guard(self.metrics.clone(), |metrics| { metrics.current_executions_in_flight.dec(); @@ -629,7 +633,7 @@ impl SimpleFaucet { .quorum_driver_api() .execute_transaction_block( tx.clone(), - SuiTransactionBlockResponseOptions::new().with_effects(), + IotaTransactionBlockResponseOptions::new().with_effects(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await @@ -663,11 +667,11 @@ impl SimpleFaucet { .map_err(|e| FaucetError::FullnodeReadingError(format!("Error fetch gas price {e:?}"))) } - async fn build_pay_sui_txn( + async fn build_pay_iota_txn( &self, coin_id: ObjectID, - signer: SuiAddress, - recipient: SuiAddress, + signer: IotaAddress, + recipient: IotaAddress, amounts: &[u64], budget: u64, ) -> Result { @@ -675,11 +679,11 @@ impl SimpleFaucet { let client = self.wallet.get_client().await?; client .transaction_builder() - .pay_sui(signer, vec![coin_id], recipients, amounts.to_vec(), budget) + .pay_iota(signer, vec![coin_id], recipients, amounts.to_vec(), budget) .await .map_err(|e| { anyhow::anyhow!( - "Failed to build PaySui transaction for coin {:?}, with err {:?}", + "Failed to build PayIota transaction for coin {:?}, with err {:?}", coin_id, e ) @@ -688,9 +692,9 @@ impl SimpleFaucet { async fn check_and_map_transfer_gas_result( &self, - res: SuiTransactionBlockResponse, + res: IotaTransactionBlockResponse, number_of_coins: usize, - recipient: SuiAddress, + recipient: IotaAddress, ) -> Result<(TransactionDigest, Vec), FaucetError> { let created = res .effects @@ -704,7 +708,7 @@ impl SimpleFaucet { .to_vec(); if created.len() != number_of_coins { return Err(FaucetError::CoinAmountTransferredIncorrect(format!( - "PaySui Transaction should create exact {:?} new coins, but got {:?}", + "PayIota Transaction should create exact {:?} new coins, but got {:?}", number_of_coins, created ))); } @@ -720,11 +724,11 @@ impl SimpleFaucet { Ok((res.digest, coin_ids)) } - async fn build_batch_pay_sui_txn( + async fn build_batch_pay_iota_txn( &self, coin_id: ObjectID, - batch_requests: Vec<(Uuid, SuiAddress, Vec)>, - signer: SuiAddress, + batch_requests: Vec<(Uuid, IotaAddress, Vec)>, + signer: IotaAddress, budget: u64, ) -> Result { let gas_payment = self.wallet.get_object_ref(coin_id).await?; @@ -735,7 +739,7 @@ impl SimpleFaucet { let mut builder = ProgrammableTransactionBuilder::new(); for (_uuid, recipient, amounts) in batch_requests { let recipients = vec![recipient; amounts.len()]; - builder.pay_sui(recipients, amounts)?; + builder.pay_iota(recipients, amounts)?; } builder.finish() }; @@ -751,11 +755,11 @@ impl SimpleFaucet { async fn check_and_map_batch_transfer_gas_result( &self, - res: SuiTransactionBlockResponse, - requests: Vec<(Uuid, SuiAddress, Vec)>, + res: IotaTransactionBlockResponse, + requests: Vec<(Uuid, IotaAddress, Vec)>, ) -> Result<(), FaucetError> { // Grab the list of created coins and turn it into a map of destination - // SuiAddress to Vec + // IotaAddress to Vec let created = res .effects .ok_or_else(|| { @@ -767,7 +771,7 @@ impl SimpleFaucet { .created() .to_vec(); - let mut address_coins_map: HashMap> = HashMap::new(); + let mut address_coins_map: HashMap> = HashMap::new(); created.iter().for_each(|created_coin_owner_ref| { let owner = created_coin_owner_ref.owner; let coin_obj_ref = created_coin_owner_ref.clone(); @@ -779,14 +783,14 @@ impl SimpleFaucet { .push(coin_obj_ref); }); - // Assert that the number of times a sui_address occurs is the number of times + // Assert that the number of times a iota_address occurs is the number of times // the coins come up in the vector. - let mut request_count: HashMap = HashMap::new(); + let mut request_count: HashMap = HashMap::new(); // Acquire lock and update all of the request Uuids let mut task_map = self.task_id_cache.lock().await; for (uuid, addy, amounts) in requests { let number_of_coins = amounts.len(); - // Get or insert sui_address into request count + // Get or insert iota_address into request count let index = *request_count.entry(addy).or_insert(0); // The address coin map should contain the coins transferred in the given @@ -795,7 +799,7 @@ impl SimpleFaucet { if number_of_coins as u64 + index > coins_created_for_address.len() as u64 { return Err(FaucetError::CoinAmountTransferredIncorrect(format!( - "PaySui Transaction should create exact {:?} new coins, but got {:?}", + "PayIota Transaction should create exact {:?} new coins, but got {:?}", number_of_coins as u64 + index, coins_created_for_address.len() ))); @@ -876,14 +880,14 @@ impl Faucet for SimpleFaucet { async fn send( &self, id: Uuid, - recipient: SuiAddress, + recipient: IotaAddress, amounts: &[u64], ) -> Result { info!(?recipient, uuid = ?id, ?amounts, "Getting faucet requests"); let (digest, coin_ids) = self.transfer_gases(amounts, recipient, id).await?; - info!(uuid = ?id, ?recipient, ?digest, "PaySui txn succeeded"); + info!(uuid = ?id, ?recipient, ?digest, "PayIota txn succeeded"); let mut sent = Vec::with_capacity(coin_ids.len()); let coin_results = futures::future::join_all(coin_ids.iter().map(|coin_id| self.get_coin(*coin_id))).await; @@ -925,7 +929,7 @@ impl Faucet for SimpleFaucet { async fn batch_send( &self, id: Uuid, - recipient: SuiAddress, + recipient: IotaAddress, amounts: &[u64], ) -> Result { info!(?recipient, uuid = ?id, "Getting faucet request"); @@ -960,8 +964,8 @@ impl Faucet for SimpleFaucet { } pub async fn batch_gather( - request_consumer: &mut Receiver<(Uuid, SuiAddress, Vec)>, - requests: &mut Vec<(Uuid, SuiAddress, Vec)>, + request_consumer: &mut Receiver<(Uuid, IotaAddress, Vec)>, + requests: &mut Vec<(Uuid, IotaAddress, Vec)>, batch_request_size: u64, ) -> Result<(), FaucetError> { // Gather the rest of the batch after the first item has been taken. @@ -980,7 +984,7 @@ pub async fn batch_gather( // Function to process the batch send of the mcsp queue pub async fn batch_transfer_gases( weak_faucet: &Weak, - request_consumer: &mut Receiver<(Uuid, SuiAddress, Vec)>, + request_consumer: &mut Receiver<(Uuid, IotaAddress, Vec)>, rx_batch_transfer_shutdown: &mut oneshot::Receiver<()>, ) -> Result { let mut requests = Vec::new(); @@ -1024,17 +1028,17 @@ pub async fn batch_transfer_gases( ?uuid, "Batch transfer attempted of size: {:?}", total_requests ); - let total_sui_needed: u64 = requests.iter().flat_map(|(_, _, amounts)| amounts).sum(); + let total_iota_needed: u64 = requests.iter().flat_map(|(_, _, amounts)| amounts).sum(); // This loop is utilized to grab a coin that is large enough for the request loop { let gas_coin_response = faucet - .prepare_gas_coin(total_sui_needed + gas_cost, uuid, true) + .prepare_gas_coin(total_iota_needed + gas_cost, uuid, true) .await; match gas_coin_response { GasCoinResponse::ValidGasCoin(coin_id) => { let tx_data = faucet - .build_batch_pay_sui_txn( + .build_batch_pay_iota_txn( coin_id, requests.clone(), faucet.active_address, @@ -1044,9 +1048,9 @@ pub async fn batch_transfer_gases( .map_err(FaucetError::internal)?; // Because we are batching transactions to faucet, we will just not use a real - // recipient for sui address, and instead just fill it with the + // recipient for iota address, and instead just fill it with the // ZERO address. - let recipient = SuiAddress::ZERO; + let recipient = IotaAddress::ZERO; { // Register the intention to send this transaction before we send it, so that if // faucet fails or we give up before we get a definite response, we have a @@ -1100,12 +1104,12 @@ pub async fn batch_transfer_gases( #[cfg(test)] mod tests { - use sui::{ - client_commands::{SuiClientCommandResult, SuiClientCommands}, + use iota::{ + client_commands::{IotaClientCommandResult, IotaClientCommands}, key_identity::KeyIdentity, }; - use sui_json_rpc_types::SuiExecutionStatus; - use sui_sdk::wallet_context::WalletContext; + use iota_json_rpc_types::IotaExecutionStatus; + use iota_sdk::wallet_context::WalletContext; use test_cluster::TestClusterBuilder; use super::*; @@ -1122,7 +1126,7 @@ mod tests { let mut context = test_cluster.wallet; let gases = get_current_gases(address, &mut context).await; // Split some extra gas coins so that we can test batch queue - SuiClientCommands::SplitCoin { + IotaClientCommands::SplitCoin { coin_id: *gases[0].id(), amounts: None, gas_budget: 50000000, @@ -1216,7 +1220,7 @@ mod tests { let _ = futures::future::join_all((0..30).map(|_| { faucet.send( Uuid::new_v4(), - SuiAddress::random_for_testing_only(), + IotaAddress::random_for_testing_only(), amounts, ) })) @@ -1251,7 +1255,7 @@ mod tests { let mut context = test_cluster.wallet; let gases = get_current_gases(address, &mut context).await; // Split some extra gas coins so that we can test batch queue - SuiClientCommands::SplitCoin { + IotaClientCommands::SplitCoin { coin_id: *gases[0].id(), amounts: None, gas_budget: 50000000, @@ -1276,8 +1280,8 @@ mod tests { let amounts = &vec![coin_amount]; // Create a vector containing five randomly generated addresses - let target_addresses: Vec = (0..5) - .map(|_| SuiAddress::random_for_testing_only()) + let target_addresses: Vec = (0..5) + .map(|_| IotaAddress::random_for_testing_only()) .collect(); let response = futures::future::join_all( @@ -1356,8 +1360,8 @@ mod tests { let amounts = &vec![1; 1]; // Create a vector containing five randomly generated addresses - let target_addresses: Vec = (0..5) - .map(|_| SuiAddress::random_for_testing_only()) + let target_addresses: Vec = (0..5) + .map(|_| IotaAddress::random_for_testing_only()) .collect(); let response = futures::future::join_all( @@ -1410,9 +1414,9 @@ mod tests { let faucet: &mut SimpleFaucet = &mut Arc::try_unwrap(faucet).unwrap(); // Now we transfer one gas out - let res = SuiClientCommands::PayAllSui { + let res = IotaClientCommands::PayAllIota { input_coins: vec![*bad_gas.id()], - recipient: KeyIdentity::Address(SuiAddress::random_for_testing_only()), + recipient: KeyIdentity::Address(IotaAddress::random_for_testing_only()), gas_budget: 2_000_000, serialize_unsigned_transaction: false, serialize_signed_transaction: false, @@ -1421,13 +1425,13 @@ mod tests { .await .unwrap(); - if let SuiClientCommandResult::PayAllSui(response) = res { + if let IotaClientCommandResult::PayAllIota(response) = res { assert!(matches!( response.effects.unwrap().status(), - SuiExecutionStatus::Success + IotaExecutionStatus::Success )); } else { - panic!("PayAllSui command did not return SuiClientCommandResult::PayAllSui"); + panic!("PayAllIota command did not return IotaClientCommandResult::PayAllIota"); }; let number_of_coins = gases.len(); @@ -1437,7 +1441,7 @@ mod tests { futures::future::join_all((0..2).map(|_| { faucet.send( Uuid::new_v4(), - SuiAddress::random_for_testing_only(), + IotaAddress::random_for_testing_only(), amounts, ) })) @@ -1477,7 +1481,7 @@ mod tests { let original_available = faucet.metrics.total_available_coins.get(); let original_discarded = faucet.metrics.total_discarded_coins.get(); - let recipient = SuiAddress::random_for_testing_only(); + let recipient = IotaAddress::random_for_testing_only(); let faucet_address = faucet.active_address; let uuid = Uuid::new_v4(); @@ -1488,7 +1492,7 @@ mod tests { }; let tx_data = faucet - .build_pay_sui_txn(coin_id, faucet_address, recipient, &[100], 200_000_000) + .build_pay_iota_txn(coin_id, faucet_address, recipient, &[100], 200_000_000) .await .map_err(FaucetError::internal) .unwrap(); @@ -1535,7 +1539,7 @@ mod tests { // faucet due to gas changes let config = FaucetConfig::default(); let tiny_value = (config.num_coins as u64 * config.amount) + 1; - let res = SuiClientCommands::SplitCoin { + let res = IotaClientCommands::SplitCoin { coin_id: *gases[0].id(), amounts: Some(vec![tiny_value]), gas_budget: 50000000, @@ -1547,12 +1551,12 @@ mod tests { .execute(&mut context) .await; - let tiny_coin_id = if let SuiClientCommandResult::SplitCoin(resp) = res.unwrap() { + let tiny_coin_id = if let IotaClientCommandResult::SplitCoin(resp) = res.unwrap() { resp.effects.as_ref().unwrap().created()[0] .reference .object_id } else { - panic!("split command did not return SuiClientCommandResult::SplitCoin"); + panic!("split command did not return IotaClientCommandResult::SplitCoin"); }; // Get the latest list of gas @@ -1588,7 +1592,7 @@ mod tests { futures::future::join_all((0..10).map(|_| { faucet.send( Uuid::new_v4(), - SuiAddress::random_for_testing_only(), + IotaAddress::random_for_testing_only(), amounts, ) })) @@ -1622,7 +1626,7 @@ mod tests { // The coin that is split off stays because we don't try to refresh the coin // vector let reasonable_value = (config.num_coins as u64 * config.amount) * 10; - SuiClientCommands::SplitCoin { + IotaClientCommands::SplitCoin { coin_id: *gases[0].id(), amounts: Some(vec![reasonable_value]), gas_budget: 50000000, @@ -1635,12 +1639,12 @@ mod tests { .await .expect("split failed"); - let destination_address = SuiAddress::random_for_testing_only(); + let destination_address = IotaAddress::random_for_testing_only(); // Transfer all valid gases away except for 1 for gas in gases.iter().take(gases.len() - 1) { - SuiClientCommands::TransferSui { + IotaClientCommands::TransferIota { to: KeyIdentity::Address(destination_address), - sui_coin_object_id: *gas.id(), + iota_coin_object_id: *gas.id(), gas_budget: 50000000, amount: None, serialize_unsigned_transaction: false, @@ -1672,7 +1676,7 @@ mod tests { futures::future::join_all((0..2).map(|_| { faucet.send( Uuid::new_v4(), - SuiAddress::random_for_testing_only(), + IotaAddress::random_for_testing_only(), &[30000000000], ) })) @@ -1696,7 +1700,7 @@ mod tests { let config = FaucetConfig::default(); let tiny_value = (config.num_coins as u64 * config.amount) + 1; - let _res = SuiClientCommands::SplitCoin { + let _res = IotaClientCommands::SplitCoin { coin_id: *gases[0].id(), amounts: Some(vec![tiny_value]), gas_budget: 50000000, @@ -1708,13 +1712,13 @@ mod tests { .execute(&mut context) .await; - let destination_address = SuiAddress::random_for_testing_only(); + let destination_address = IotaAddress::random_for_testing_only(); // Transfer all valid gases away for gas in gases { - SuiClientCommands::TransferSui { + IotaClientCommands::TransferIota { to: KeyIdentity::Address(destination_address), - sui_coin_object_id: *gas.id(), + iota_coin_object_id: *gas.id(), gas_budget: 50000000, amount: None, serialize_unsigned_transaction: false, @@ -1741,7 +1745,7 @@ mod tests { .await .unwrap(); - let destination_address = SuiAddress::random_for_testing_only(); + let destination_address = IotaAddress::random_for_testing_only(); // Assert that faucet will discard and also terminate let res = faucet .send(Uuid::new_v4(), destination_address, &[30000000000]) @@ -1768,7 +1772,7 @@ mod tests { .await .unwrap(); - let recipient = SuiAddress::random_for_testing_only(); + let recipient = IotaAddress::random_for_testing_only(); let faucet_address = faucet.active_address; let uuid = Uuid::new_v4(); @@ -1779,7 +1783,7 @@ mod tests { }; let tx_data = faucet - .build_pay_sui_txn(coin_id, faucet_address, recipient, &[100], 200_000_000) + .build_pay_iota_txn(coin_id, faucet_address, recipient, &[100], 200_000_000) .await .map_err(FaucetError::internal) .unwrap(); @@ -1831,7 +1835,7 @@ mod tests { let mut context = test_cluster.wallet; let gases = get_current_gases(address, &mut context).await; // Split some extra gas coins so that we can test batch queue - SuiClientCommands::SplitCoin { + IotaClientCommands::SplitCoin { coin_id: *gases[0].id(), amounts: None, gas_budget: 50000000, @@ -1858,11 +1862,11 @@ mod tests { .unwrap(); // Create a vector containing two randomly generated addresses - let target_addresses: Vec = (0..2) - .map(|_| SuiAddress::random_for_testing_only()) + let target_addresses: Vec = (0..2) + .map(|_| IotaAddress::random_for_testing_only()) .collect(); - // Send 2 coins of 1 sui each. We + // Send 2 coins of 1 iota each. We let coins_sent = 2; let amounts = &vec![amount_to_send; coins_sent]; @@ -1911,7 +1915,7 @@ mod tests { } async fn test_send_interface_has_success_status(faucet: &impl Faucet) { - let recipient = SuiAddress::random_for_testing_only(); + let recipient = IotaAddress::random_for_testing_only(); let amounts = vec![1, 2, 3]; let uuid_test = Uuid::new_v4(); @@ -1932,7 +1936,7 @@ mod tests { } async fn test_basic_interface(faucet: &impl Faucet) { - let recipient = SuiAddress::random_for_testing_only(); + let recipient = IotaAddress::random_for_testing_only(); let amounts = vec![1, 2, 3]; let FaucetReceipt { sent } = faucet @@ -1944,17 +1948,17 @@ mod tests { assert_eq!(actual_amounts, amounts); } - async fn get_current_gases(address: SuiAddress, context: &mut WalletContext) -> Vec { + async fn get_current_gases(address: IotaAddress, context: &mut WalletContext) -> Vec { // Get the latest list of gas - let results = SuiClientCommands::Gas { + let results = IotaClientCommands::Gas { address: Some(KeyIdentity::Address(address)), } .execute(context) .await .unwrap(); match results { - SuiClientCommandResult::Gas(gases) => gases, - other => panic!("Expect SuiClientCommandResult::Gas, but got {:?}", other), + IotaClientCommandResult::Gas(gases) => gases, + other => panic!("Expect IotaClientCommandResult::Gas, but got {:?}", other), } } } diff --git a/crates/sui-faucet/src/faucet/write_ahead_log.rs b/crates/iota-faucet/src/faucet/write_ahead_log.rs similarity index 94% rename from crates/sui-faucet/src/faucet/write_ahead_log.rs rename to crates/iota-faucet/src/faucet/write_ahead_log.rs index 87784f394bd..6ae0bd99a09 100644 --- a/crates/sui-faucet/src/faucet/write_ahead_log.rs +++ b/crates/iota-faucet/src/faucet/write_ahead_log.rs @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::Path; -use serde::{Deserialize, Serialize}; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, +use iota_types::{ + base_types::{IotaAddress, ObjectID}, transaction::TransactionData, }; +use serde::{Deserialize, Serialize}; use tracing::info; use typed_store::{ rocks::DBMap, @@ -17,7 +18,7 @@ use typed_store::{ use typed_store_derive::DBMapUtils; use uuid::Uuid; -/// Persistent log of transactions paying out sui from the faucet, keyed by the +/// Persistent log of transactions paying out iota from the faucet, keyed by the /// coin serving the request. Transactions are expected to be written to the /// log before they are sent to full-node, and removed after receiving a /// response back, before the coin becomes available for subsequent writes. @@ -33,7 +34,7 @@ pub struct WriteAheadLog { pub struct Entry { pub uuid: uuid::Bytes, // TODO (jian): remove recipient - pub recipient: SuiAddress, + pub recipient: IotaAddress, pub tx: TransactionData, pub retry_count: u64, pub in_flight: bool, @@ -56,7 +57,7 @@ impl WriteAheadLog { &mut self, uuid: Uuid, coin: ObjectID, - recipient: SuiAddress, + recipient: IotaAddress, tx: TransactionData, ) -> Result<(), TypedStoreError> { if self.log.contains_key(&coin)? { @@ -137,7 +138,7 @@ impl WriteAheadLog { #[cfg(test)] mod tests { - use sui_types::{ + use iota_types::{ base_types::{random_object_ref, ObjectRef}, transaction::TEST_ONLY_GAS_UNIT_FOR_TRANSFER, }; @@ -257,13 +258,13 @@ mod tests { wal.reserve(uuid, coin.0, recv1, tx1).unwrap(); } - fn random_request(coin: ObjectRef) -> (SuiAddress, TransactionData) { + fn random_request(coin: ObjectRef) -> (IotaAddress, TransactionData) { let gas_price = 1; - let send = SuiAddress::random_for_testing_only(); - let recv = SuiAddress::random_for_testing_only(); + let send = IotaAddress::random_for_testing_only(); + let recv = IotaAddress::random_for_testing_only(); ( recv, - TransactionData::new_pay_sui( + TransactionData::new_pay_iota( send, vec![coin], vec![recv], diff --git a/crates/iota-faucet/src/lib.rs b/crates/iota-faucet/src/lib.rs new file mode 100644 index 00000000000..b65b13cd101 --- /dev/null +++ b/crates/iota-faucet/src/lib.rs @@ -0,0 +1,16 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod errors; +mod faucet; +mod metrics; +mod requests; +mod responses; + +pub mod metrics_layer; +pub use errors::FaucetError; +pub use faucet::*; +pub use metrics_layer::*; +pub use requests::*; +pub use responses::*; diff --git a/crates/iota-faucet/src/main.rs b/crates/iota-faucet/src/main.rs new file mode 100644 index 00000000000..275085c7c75 --- /dev/null +++ b/crates/iota-faucet/src/main.rs @@ -0,0 +1,314 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + borrow::Cow, + env, + net::{IpAddr, SocketAddr}, + sync::Arc, + time::Duration, +}; + +use axum::{ + error_handling::HandleErrorLayer, + extract::Path, + http::StatusCode, + response::IntoResponse, + routing::{get, post}, + BoxError, Extension, Json, Router, +}; +use clap::Parser; +use http::Method; +use iota_config::{iota_config_dir, IOTA_CLIENT_CONFIG}; +use iota_faucet::{ + BatchFaucetResponse, BatchStatusFaucetResponse, Faucet, FaucetConfig, FaucetError, + FaucetRequest, FaucetResponse, RequestMetricsLayer, SimpleFaucet, +}; +use iota_sdk::wallet_context::WalletContext; +use mysten_metrics::spawn_monitored_task; +use tower::{limit::RateLimitLayer, ServiceBuilder}; +use tower_http::cors::{Any, CorsLayer}; +use tracing::{info, warn}; +use uuid::Uuid; + +const CONCURRENCY_LIMIT: usize = 30; + +struct AppState> { + faucet: F, + config: FaucetConfig, +} + +const PROM_PORT_ADDR: &str = "0.0.0.0:9184"; + +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + // initialize tracing + let _guard = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .init(); + + let max_concurrency = match env::var("MAX_CONCURRENCY") { + Ok(val) => val.parse::().unwrap(), + _ => CONCURRENCY_LIMIT, + }; + info!("Max concurrency: {max_concurrency}."); + + let config: FaucetConfig = FaucetConfig::parse(); + let FaucetConfig { + port, + host_ip, + request_buffer_size, + max_request_per_second, + wallet_client_timeout_secs, + ref write_ahead_log, + wal_retry_interval, + .. + } = config; + + let context = create_wallet_context(wallet_client_timeout_secs)?; + + let prom_binding = PROM_PORT_ADDR.parse().unwrap(); + info!("Starting Prometheus HTTP endpoint at {}", prom_binding); + let registry_service = mysten_metrics::start_prometheus_server(prom_binding); + let prometheus_registry = registry_service.default_registry(); + let app_state = Arc::new(AppState { + faucet: SimpleFaucet::new( + context, + &prometheus_registry, + write_ahead_log, + config.clone(), + ) + .await + .unwrap(), + config, + }); + + // TODO: restrict access if needed + let cors = CorsLayer::new() + .allow_methods(vec![Method::GET, Method::POST]) + .allow_headers(Any) + .allow_origin(Any); + + let app = Router::new() + .route("/", get(health)) + .route("/gas", post(request_gas)) + .route("/v1/gas", post(batch_request_gas)) + .route("/v1/status/:task_id", get(request_status)) + .layer( + ServiceBuilder::new() + .layer(HandleErrorLayer::new(handle_error)) + .layer(RequestMetricsLayer::new(&prometheus_registry)) + .layer(cors) + .load_shed() + .buffer(request_buffer_size) + .layer(RateLimitLayer::new( + max_request_per_second, + Duration::from_secs(1), + )) + .concurrency_limit(max_concurrency) + .layer(Extension(app_state.clone())) + .into_inner(), + ); + + spawn_monitored_task!(async move { + info!("Starting task to clear WAL."); + loop { + // Every config.wal_retry_interval (Default: 300 seconds) we try to clear the + // wal coins + tokio::time::sleep(Duration::from_secs(wal_retry_interval)).await; + app_state.faucet.retry_wal_coins().await.unwrap(); + } + }); + + let addr = SocketAddr::new(IpAddr::V4(host_ip), port); + info!("listening on {}", addr); + axum::Server::bind(&addr) + .serve(app.into_make_service()) + .await?; + Ok(()) +} + +/// basic handler that responds with a static string +async fn health() -> &'static str { + "OK" +} + +/// handler for batch_request_gas requests +async fn batch_request_gas( + Extension(state): Extension>, + Json(payload): Json, +) -> impl IntoResponse { + let id = Uuid::new_v4(); + // ID for traceability + info!(uuid = ?id, "Got new gas request."); + + let FaucetRequest::FixedAmountRequest(request) = payload else { + return ( + StatusCode::BAD_REQUEST, + Json(BatchFaucetResponse::from(FaucetError::Internal( + "Input Error.".to_string(), + ))), + ); + }; + + if state.config.batch_enabled { + let result = spawn_monitored_task!(async move { + state + .faucet + .batch_send( + id, + request.recipient, + &vec![state.config.amount; state.config.num_coins], + ) + .await + }) + .await + .unwrap(); + + match result { + Ok(v) => { + info!(uuid =?id, "Request is successfully served"); + (StatusCode::ACCEPTED, Json(BatchFaucetResponse::from(v))) + } + Err(v) => { + warn!(uuid =?id, "Failed to request gas: {:?}", v); + ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(BatchFaucetResponse::from(v)), + ) + } + } + } else { + // TODO (jian): remove this feature gate when batch has proven to be baked long + // enough + info!(uuid = ?id, "Falling back to v1 implementation"); + let result = spawn_monitored_task!(async move { + state + .faucet + .send( + id, + request.recipient, + &vec![state.config.amount; state.config.num_coins], + ) + .await + }) + .await + .unwrap(); + + match result { + Ok(_) => { + info!(uuid =?id, "Request is successfully served"); + (StatusCode::ACCEPTED, Json(BatchFaucetResponse::from(id))) + } + Err(v) => { + warn!(uuid =?id, "Failed to request gas: {:?}", v); + ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(BatchFaucetResponse::from(v)), + ) + } + } + } +} + +/// handler for batch_get_status requests +async fn request_status( + Extension(state): Extension>, + Path(id): Path, +) -> impl IntoResponse { + match Uuid::parse_str(&id) { + Ok(task_id) => { + let result = state.faucet.get_batch_send_status(task_id).await; + match result { + Ok(v) => ( + StatusCode::CREATED, + Json(BatchStatusFaucetResponse::from(v)), + ), + Err(v) => ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(BatchStatusFaucetResponse::from(v)), + ), + } + } + Err(e) => ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(BatchStatusFaucetResponse::from(FaucetError::Internal( + e.to_string(), + ))), + ), + } +} + +/// handler for all the request_gas requests +async fn request_gas( + Extension(state): Extension>, + Json(payload): Json, +) -> impl IntoResponse { + // ID for traceability + let id = Uuid::new_v4(); + info!(uuid = ?id, "Got new gas request."); + let result = match payload { + FaucetRequest::FixedAmountRequest(requests) => { + // We spawn a tokio task for this such that connection drop will not interrupt + // it and impact the recycling of coins + spawn_monitored_task!(async move { + state + .faucet + .send( + id, + requests.recipient, + &vec![state.config.amount; state.config.num_coins], + ) + .await + }) + .await + .unwrap() + } + _ => { + return ( + StatusCode::BAD_REQUEST, + Json(FaucetResponse::from(FaucetError::Internal( + "Input Error.".to_string(), + ))), + ); + } + }; + match result { + Ok(v) => { + info!(uuid =?id, "Request is successfully served"); + (StatusCode::CREATED, Json(FaucetResponse::from(v))) + } + Err(v) => { + warn!(uuid =?id, "Failed to request gas: {:?}", v); + ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(FaucetResponse::from(v)), + ) + } + } +} + +fn create_wallet_context(timeout_secs: u64) -> Result { + let wallet_conf = iota_config_dir()?.join(IOTA_CLIENT_CONFIG); + info!("Initialize wallet from config path: {:?}", wallet_conf); + WalletContext::new( + &wallet_conf, + Some(Duration::from_secs(timeout_secs)), + Some(1000), + ) +} + +async fn handle_error(error: BoxError) -> impl IntoResponse { + if error.is::() { + return ( + StatusCode::SERVICE_UNAVAILABLE, + Cow::from("service is overloaded, please try again later"), + ); + } + + ( + StatusCode::INTERNAL_SERVER_ERROR, + Cow::from(format!("Unhandled internal error: {}", error)), + ) +} diff --git a/crates/iota-faucet/src/metrics.rs b/crates/iota-faucet/src/metrics.rs new file mode 100644 index 00000000000..c74cb0c60d3 --- /dev/null +++ b/crates/iota-faucet/src/metrics.rs @@ -0,0 +1,118 @@ +// Copyright (c) 2021, Facebook, Inc. and its affiliates +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use prometheus::{ + register_histogram_with_registry, register_int_counter_with_registry, + register_int_gauge_with_registry, Histogram, IntCounter, IntGauge, Registry, +}; + +/// Prometheus metrics which can be displayed in Grafana, queried and alerted on + +/// Metrics relevant to the requests coming into the service +#[derive(Clone, Debug)] +pub struct RequestMetrics { + pub(crate) total_requests_received: IntCounter, + pub(crate) total_requests_succeeded: IntCounter, + pub(crate) total_requests_shed: IntCounter, + pub(crate) total_requests_failed: IntCounter, + pub(crate) total_requests_disconnected: IntCounter, + pub(crate) current_requests_in_flight: IntGauge, + pub(crate) process_latency: Histogram, +} + +/// Metrics relevant to the running of the service +#[derive(Clone, Debug)] +pub struct FaucetMetrics { + pub(crate) current_executions_in_flight: IntGauge, + pub(crate) total_available_coins: IntGauge, + pub(crate) total_discarded_coins: IntGauge, + pub(crate) total_coin_requests_succeeded: IntGauge, +} + +const LATENCY_SEC_BUCKETS: &[f64] = &[ + 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1., 2.5, 5., 10., 20., 30., 60., 90., +]; + +impl RequestMetrics { + pub fn new(registry: &Registry) -> Self { + Self { + total_requests_received: register_int_counter_with_registry!( + "total_requests_received", + "Total number of requests received in Faucet", + registry, + ) + .unwrap(), + total_requests_succeeded: register_int_counter_with_registry!( + "total_requests_succeeded", + "Total number of requests processed successfully in Faucet", + registry, + ) + .unwrap(), + total_requests_shed: register_int_counter_with_registry!( + "total_requests_shed", + "Total number of requests that were dropped because the service was saturated", + registry, + ) + .unwrap(), + total_requests_failed: register_int_counter_with_registry!( + "total_requests_failed", + "Total number of requests that started but failed with an uncaught error", + registry, + ) + .unwrap(), + total_requests_disconnected: register_int_counter_with_registry!( + "total_requests_disconnected", + "Total number of requests where the client disconnected before the service \ + returned a response", + registry, + ) + .unwrap(), + current_requests_in_flight: register_int_gauge_with_registry!( + "current_requests_in_flight", + "Current number of requests being processed in Faucet", + registry, + ) + .unwrap(), + process_latency: register_histogram_with_registry!( + "process_latency", + "Latency of processing a Faucet request", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + } + } +} + +impl FaucetMetrics { + pub fn new(registry: &Registry) -> Self { + Self { + current_executions_in_flight: register_int_gauge_with_registry!( + "current_executions_in_flight", + "Current number of transactions being executed in Faucet", + registry, + ) + .unwrap(), + total_available_coins: register_int_gauge_with_registry!( + "total_available_coins", + "Total number of available coins in queue", + registry, + ) + .unwrap(), + total_discarded_coins: register_int_gauge_with_registry!( + "total_discarded_coins", + "Total number of discarded coins", + registry, + ) + .unwrap(), + total_coin_requests_succeeded: register_int_gauge_with_registry!( + "total_coin_requests_succeeded", + "Total number of requests processed successfully in Faucet (both batch and non_batched)", + registry, + ) + .unwrap(), + } + } +} diff --git a/crates/sui-faucet/src/metrics_layer.rs b/crates/iota-faucet/src/metrics_layer.rs similarity index 98% rename from crates/sui-faucet/src/metrics_layer.rs rename to crates/iota-faucet/src/metrics_layer.rs index bd2d29f8f99..cf98cebd00b 100644 --- a/crates/sui-faucet/src/metrics_layer.rs +++ b/crates/iota-faucet/src/metrics_layer.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/sui-faucet/src/requests.rs b/crates/iota-faucet/src/requests.rs similarity index 80% rename from crates/sui-faucet/src/requests.rs rename to crates/iota-faucet/src/requests.rs index 959088749a6..a0df3bb423b 100644 --- a/crates/sui-faucet/src/requests.rs +++ b/crates/iota-faucet/src/requests.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_types::base_types::IotaAddress; use serde::{Deserialize, Serialize}; -use sui_types::base_types::SuiAddress; #[derive(Serialize, Deserialize, Debug, Clone)] pub enum FaucetRequest { @@ -12,7 +13,7 @@ pub enum FaucetRequest { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct FixedAmountRequest { - pub recipient: SuiAddress, + pub recipient: IotaAddress, } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -21,7 +22,7 @@ pub struct GetBatchSendStatusRequest { } impl FaucetRequest { - pub fn new_fixed_amount_request(recipient: impl Into) -> Self { + pub fn new_fixed_amount_request(recipient: impl Into) -> Self { Self::FixedAmountRequest(FixedAmountRequest { recipient: recipient.into(), }) diff --git a/crates/sui-faucet/src/responses.rs b/crates/iota-faucet/src/responses.rs similarity index 97% rename from crates/sui-faucet/src/responses.rs rename to crates/iota-faucet/src/responses.rs index 74cf366c2a3..076c79b5e86 100644 --- a/crates/sui-faucet/src/responses.rs +++ b/crates/iota-faucet/src/responses.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use serde::{Deserialize, Serialize}; diff --git a/crates/iota-framework-snapshot/Cargo.toml b/crates/iota-framework-snapshot/Cargo.toml new file mode 100644 index 00000000000..8bea797d023 --- /dev/null +++ b/crates/iota-framework-snapshot/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "iota-framework-snapshot" +version = "0.1.0" +edition = "2021" +authors = ["Mysten Labs "] +description = "Tool to create a bytecode snapshot of the current iota-framework" +license = "Apache-2.0" +publish = false + +[dependencies] +anyhow.workspace = true +bcs.workspace = true +serde.workspace = true +serde_json.workspace = true +git-version.workspace = true + +iota-framework.workspace = true +iota-protocol-config.workspace = true +iota-types.workspace = true + +[dev-dependencies] +tokio = { workspace = true, features = ["full"] } diff --git a/crates/iota-framework-snapshot/README.txt b/crates/iota-framework-snapshot/README.txt new file mode 100644 index 00000000000..77daa2cd681 --- /dev/null +++ b/crates/iota-framework-snapshot/README.txt @@ -0,0 +1,7 @@ +Whenever we release a new binary that has a new protocol version to a network, we should go to the tip of that network's branch, and run this command: +``` +cargo run --bin iota-framework-snapshot +``` +And the commit the changes to `main` branch to record it. +It's important to ensure that each protocol version should correspond to a unique snapshot among all networks, +i.e. for the same protocol version, testnet and mainnet should contain identical framework bytecode. diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/10/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/10/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/10/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/10/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/10/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/10/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/10/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/10/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/10/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/10/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/10/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/10/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/10/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/10/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/10/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/10/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/11/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/11/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/11/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/11/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/11/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/11/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/11/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/11/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/11/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/11/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/11/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/11/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/11/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/11/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/11/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/11/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/12/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/12/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/12/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/12/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/12/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/12/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/12/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/12/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/12/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/12/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/12/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/12/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/12/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/12/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/12/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/12/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/13/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/13/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/13/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/13/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/13/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/13/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/13/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/13/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/13/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/13/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/13/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/13/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/13/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/13/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/13/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/13/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/14/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/14/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/14/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/14/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/14/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/14/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/14/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/14/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/14/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/14/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/14/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/14/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/14/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/14/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/14/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/14/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/15/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/15/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/15/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/15/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/15/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/15/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/15/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/15/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/15/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/15/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/15/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/15/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/15/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/15/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/15/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/15/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/16/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/16/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/16/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/16/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/16/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/16/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/16/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/16/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/16/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/16/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/16/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/16/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/16/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/16/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/16/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/16/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/17/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/17/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/17/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/17/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/17/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/17/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/17/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/17/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/17/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/17/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/17/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/17/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/17/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/17/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/17/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/17/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/18/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/18/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/18/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/18/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/18/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/18/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/18/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/18/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/18/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/18/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/18/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/18/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/18/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/18/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/18/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/18/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/19/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/19/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/19/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/19/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/19/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/19/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/19/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/19/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/19/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/19/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/19/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/19/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/19/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/19/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/19/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/19/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/20/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/20/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/20/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/20/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/20/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/20/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/20/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/20/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/20/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/20/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/20/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/20/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/20/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/20/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/20/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/20/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/21/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/21/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/21/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/21/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/21/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/21/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/21/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/21/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/21/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/21/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/21/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/21/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/21/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/21/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/21/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/21/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/22/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/22/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/22/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/22/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/22/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/22/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/22/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/22/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/22/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/22/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/22/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/22/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/22/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/22/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/22/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/22/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/23/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/23/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/23/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/23/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/23/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/23/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/23/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/23/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/23/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/23/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/23/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/23/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/23/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/23/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/23/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/23/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/24/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/24/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/24/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/24/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/24/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/24/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/24/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/24/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/24/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/24/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/24/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/24/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/24/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/24/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/24/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/24/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/25/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/25/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/25/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/25/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/25/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/25/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/25/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/25/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/25/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/25/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/25/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/25/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/25/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/25/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/25/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/25/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/26/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/26/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/26/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/26/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/26/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/26/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/26/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/26/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/26/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/26/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/26/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/26/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/26/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/26/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/26/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/26/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/27/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/27/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/27/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/27/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/27/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/27/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/27/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/27/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/27/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/27/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/27/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/27/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/27/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/27/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/27/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/27/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/28/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/28/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/28/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/28/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/28/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/28/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/28/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/28/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/28/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/28/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/28/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/28/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/28/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/28/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/28/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/28/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/29/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/29/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/29/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/29/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/29/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/29/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/29/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/29/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/29/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/29/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/29/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/29/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/29/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/29/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/29/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/29/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/3/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/3/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/3/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/3/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/3/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/3/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/3/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/3/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/3/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/3/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/3/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/3/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/30/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/30/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/30/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/30/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/30/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/30/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/30/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/30/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/30/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/30/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/30/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/30/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/30/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/30/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/30/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/30/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/31/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/31/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/31/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/31/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/31/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/31/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/31/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/31/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/31/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/31/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/31/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/31/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/31/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/31/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/31/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/31/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/32/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/32/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/32/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/32/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/32/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/32/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/32/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/32/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/32/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/32/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/32/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/32/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/32/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/32/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/32/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/32/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/33/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/33/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/33/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/33/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/33/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/33/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/33/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/33/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/33/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/33/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/33/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/33/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/33/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/33/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/33/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/33/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/34/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/34/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/34/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/34/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/34/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/34/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/34/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/34/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/34/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/34/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/34/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/34/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/34/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/34/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/34/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/34/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/35/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/35/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/35/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/35/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/35/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/35/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/35/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/35/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/35/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/35/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/35/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/35/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/35/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/35/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/35/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/35/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/36/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/36/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/36/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/36/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/36/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/36/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/36/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/36/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/36/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/36/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/36/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/36/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/36/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/36/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/36/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/36/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/37/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/37/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/37/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/37/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/37/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/37/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/37/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/37/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/37/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/37/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/37/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/37/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/37/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/37/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/37/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/37/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/38/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/38/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/38/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/38/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/38/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/38/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/38/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/38/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/38/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/38/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/38/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/38/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/38/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/38/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/38/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/38/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/39/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/39/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/39/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/39/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/39/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/39/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/39/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/39/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/39/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/39/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/39/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/39/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/39/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/39/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/39/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/39/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/4/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/4/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/4/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/4/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/4/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/4/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/4/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/4/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/4/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/4/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/4/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/4/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/40/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/40/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/40/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/40/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/40/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/40/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/40/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/40/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/40/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/40/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/40/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/40/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/40/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/40/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/40/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/40/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/iota-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000002 new file mode 100644 index 00000000000..3e57266f655 Binary files /dev/null and b/crates/iota-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000002 differ diff --git a/crates/iota-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000003 new file mode 100644 index 00000000000..e7ee641e5b2 Binary files /dev/null and b/crates/iota-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000003 differ diff --git a/crates/iota-framework-snapshot/bytecode_snapshot/42/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/42/0x000000000000000000000000000000000000000000000000000000000000dee9 new file mode 100644 index 00000000000..f305fd88b88 Binary files /dev/null and b/crates/iota-framework-snapshot/bytecode_snapshot/42/0x000000000000000000000000000000000000000000000000000000000000dee9 differ diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/5/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/5/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/5/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/5/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/5/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/5/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/5/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/5/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/5/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/5/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/5/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/5/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/5/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/5/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/5/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/5/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/6/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/6/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/6/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/6/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/6/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/6/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/6/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/6/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/6/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/6/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/6/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/6/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/6/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/6/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/6/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/6/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/7/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/7/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/7/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/7/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/7/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/7/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/7/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/7/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/7/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/7/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/7/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/7/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/7/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/7/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/7/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/7/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/8/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/8/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/8/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/8/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/8/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/8/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/8/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/8/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/8/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/8/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/8/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/8/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/8/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/8/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/8/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/8/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/9/0x0000000000000000000000000000000000000000000000000000000000000001 b/crates/iota-framework-snapshot/bytecode_snapshot/9/0x0000000000000000000000000000000000000000000000000000000000000001 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/9/0x0000000000000000000000000000000000000000000000000000000000000001 rename to crates/iota-framework-snapshot/bytecode_snapshot/9/0x0000000000000000000000000000000000000000000000000000000000000001 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/9/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/iota-framework-snapshot/bytecode_snapshot/9/0x0000000000000000000000000000000000000000000000000000000000000002 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/9/0x0000000000000000000000000000000000000000000000000000000000000002 rename to crates/iota-framework-snapshot/bytecode_snapshot/9/0x0000000000000000000000000000000000000000000000000000000000000002 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/9/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/iota-framework-snapshot/bytecode_snapshot/9/0x0000000000000000000000000000000000000000000000000000000000000003 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/9/0x0000000000000000000000000000000000000000000000000000000000000003 rename to crates/iota-framework-snapshot/bytecode_snapshot/9/0x0000000000000000000000000000000000000000000000000000000000000003 diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/9/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/iota-framework-snapshot/bytecode_snapshot/9/0x000000000000000000000000000000000000000000000000000000000000dee9 similarity index 100% rename from crates/sui-framework-snapshot/bytecode_snapshot/9/0x000000000000000000000000000000000000000000000000000000000000dee9 rename to crates/iota-framework-snapshot/bytecode_snapshot/9/0x000000000000000000000000000000000000000000000000000000000000dee9 diff --git a/crates/sui-framework-snapshot/manifest.json b/crates/iota-framework-snapshot/manifest.json similarity index 99% rename from crates/sui-framework-snapshot/manifest.json rename to crates/iota-framework-snapshot/manifest.json index 5420bad6623..c9219cdb6b4 100644 --- a/crates/sui-framework-snapshot/manifest.json +++ b/crates/iota-framework-snapshot/manifest.json @@ -331,7 +331,7 @@ ] }, "42": { - "git_revision": "404b5aa266", + "git_revision": "26d6a0fd34", "package_ids": [ "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000002", diff --git a/crates/iota-framework-snapshot/src/lib.rs b/crates/iota-framework-snapshot/src/lib.rs new file mode 100644 index 00000000000..969276d03c7 --- /dev/null +++ b/crates/iota-framework-snapshot/src/lib.rs @@ -0,0 +1,93 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::BTreeMap, fs, io::Read, path::PathBuf}; + +use iota_framework::SystemPackage; +use iota_types::{ + base_types::ObjectID, DEEPBOOK_PACKAGE_ID, IOTA_FRAMEWORK_PACKAGE_ID, IOTA_SYSTEM_PACKAGE_ID, + MOVE_STDLIB_PACKAGE_ID, +}; +use serde::{Deserialize, Serialize}; + +pub type SnapshotManifest = BTreeMap; + +#[derive(Serialize, Deserialize)] +pub struct SingleSnapshot { + /// Git revision that this snapshot is taken on. + git_revision: String, + /// List of file names (also identical to object ID) of the bytecode package + /// files. + package_ids: Vec, +} + +impl SingleSnapshot { + pub fn git_revision(&self) -> &str { + &self.git_revision + } + pub fn package_ids(&self) -> &[ObjectID] { + &self.package_ids + } +} + +const SYSTEM_PACKAGE_PUBLISH_ORDER: &[ObjectID] = &[ + MOVE_STDLIB_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, + IOTA_SYSTEM_PACKAGE_ID, + DEEPBOOK_PACKAGE_ID, +]; + +pub fn load_bytecode_snapshot_manifest() -> SnapshotManifest { + let Ok(bytes) = fs::read(manifest_path()) else { + return SnapshotManifest::default(); + }; + serde_json::from_slice::(&bytes) + .expect("Could not deserialize SnapshotManifest") +} + +pub fn update_bytecode_snapshot_manifest(git_revision: &str, version: u64, files: Vec) { + let mut snapshot = load_bytecode_snapshot_manifest(); + + snapshot.insert( + version, + SingleSnapshot { + git_revision: git_revision.to_string(), + package_ids: files, + }, + ); + + let json = + serde_json::to_string_pretty(&snapshot).expect("Could not serialize SnapshotManifest"); + fs::write(manifest_path(), json).expect("Could not update manifest file"); +} + +pub fn load_bytecode_snapshot(protocol_version: u64) -> anyhow::Result> { + let mut snapshot_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + snapshot_path.extend(["bytecode_snapshot", protocol_version.to_string().as_str()]); + let mut snapshots: BTreeMap = fs::read_dir(&snapshot_path)? + .flatten() + .map(|entry| { + let file_name = entry.file_name().to_str().unwrap().to_string(); + let mut file = fs::File::open(snapshot_path.clone().join(file_name))?; + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer)?; + let package: SystemPackage = bcs::from_bytes(&buffer)?; + Ok((*package.id(), package)) + }) + .collect::>()?; + + // system packages need to be restored in a specific order + assert!(snapshots.len() <= SYSTEM_PACKAGE_PUBLISH_ORDER.len()); + let mut snapshot_objects = Vec::new(); + for package_id in SYSTEM_PACKAGE_PUBLISH_ORDER { + if let Some(object) = snapshots.remove(package_id) { + snapshot_objects.push(object); + } + } + Ok(snapshot_objects) +} + +fn manifest_path() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("manifest.json") +} diff --git a/crates/iota-framework-snapshot/src/main.rs b/crates/iota-framework-snapshot/src/main.rs new file mode 100644 index 00000000000..175ba4b27cb --- /dev/null +++ b/crates/iota-framework-snapshot/src/main.rs @@ -0,0 +1,49 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{env, fs, path::PathBuf}; + +use iota_framework::{BuiltInFramework, SystemPackage}; +use iota_framework_snapshot::update_bytecode_snapshot_manifest; +use iota_protocol_config::ProtocolVersion; + +const GIT_REVISION: &str = { + if let Some(revision) = option_env!("GIT_REVISION") { + revision + } else { + let version = git_version::git_version!( + args = ["--always", "--dirty", "--exclude", "*"], + fallback = "" + ); + + if version.is_empty() { + panic!("unable to query git revision"); + } + version + } +}; + +fn main() { + // Always generate snapshot for the latest version. + let version = ProtocolVersion::MAX.as_u64(); + let mut files = vec![]; + for package in BuiltInFramework::iter_system_packages() { + write_package_to_file(version, package); + files.push(*package.id()); + } + update_bytecode_snapshot_manifest(GIT_REVISION, version, files); +} + +fn write_package_to_file(version: u64, package: &SystemPackage) { + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.extend(["bytecode_snapshot", version.to_string().as_str()]); + fs::create_dir_all(&path) + .or_else(|e| match e.kind() { + std::io::ErrorKind::AlreadyExists => Ok(()), + _ => Err(e), + }) + .expect("Unable to create snapshot directory"); + let bytes = bcs::to_bytes(package).expect("Deserialization cannot fail"); + fs::write(path.join(package.id().to_string()), bytes).expect("Unable to write data to file"); +} diff --git a/crates/sui-framework-snapshot/tests/compatibility_tests.rs b/crates/iota-framework-snapshot/tests/compatibility_tests.rs similarity index 87% rename from crates/sui-framework-snapshot/tests/compatibility_tests.rs rename to crates/iota-framework-snapshot/tests/compatibility_tests.rs index 33f30482f9d..a769b8b87b1 100644 --- a/crates/sui-framework-snapshot/tests/compatibility_tests.rs +++ b/crates/iota-framework-snapshot/tests/compatibility_tests.rs @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 mod compatibility_tests { use std::collections::BTreeMap; - use sui_framework::{compare_system_package, BuiltInFramework}; - use sui_framework_snapshot::{load_bytecode_snapshot, load_bytecode_snapshot_manifest}; - use sui_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; - use sui_types::execution_config_utils::to_binary_config; + use iota_framework::{compare_system_package, BuiltInFramework}; + use iota_framework_snapshot::{load_bytecode_snapshot, load_bytecode_snapshot_manifest}; + use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; + use iota_types::execution_config_utils::to_binary_config; #[tokio::test] async fn test_framework_compatibility() { @@ -34,7 +35,7 @@ mod compatibility_tests { .is_none() { panic!( - "The current Sui framework {:?} is not compatible with version {:?}", + "The current Iota framework {:?} is not compatible with version {:?}", cur_package.id(), version ); diff --git a/crates/iota-framework-tests/Cargo.toml b/crates/iota-framework-tests/Cargo.toml new file mode 100644 index 00000000000..681b379116e --- /dev/null +++ b/crates/iota-framework-tests/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "iota-framework-tests" +version = "0.1.0" +edition = "2021" +authors = ["Mysten Labs "] +description = "Runs Move tests for iota-framework" +license = "Apache-2.0" +publish = false + +[dev-dependencies] +prometheus.workspace = true + +iota-framework.workspace = true +iota-move = { workspace = true, features = ["unit_test"] } +iota-move-build.workspace = true +iota-protocol-config.workspace = true +iota-types.workspace = true + +move-bytecode-verifier = { path = "../../external-crates/move/crates/move-bytecode-verifier" } +iota-adapter = { path = "../../iota-execution/latest/iota-adapter", package = "iota-adapter-latest" } +iota-verifier = { path = "../../iota-execution/latest/iota-verifier", package = "iota-verifier-latest" } + +move-cli.workspace = true +move-package.workspace = true +move-unit-test.workspace = true + +[dependencies] diff --git a/crates/iota-framework-tests/src/lib.rs b/crates/iota-framework-tests/src/lib.rs new file mode 100644 index 00000000000..979e39c87b1 --- /dev/null +++ b/crates/iota-framework-tests/src/lib.rs @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(test)] +mod unit_tests; + +#[cfg(test)] +mod metered_verifier; diff --git a/crates/sui-framework-tests/src/metered_verifier.rs b/crates/iota-framework-tests/src/metered_verifier.rs similarity index 86% rename from crates/sui-framework-tests/src/metered_verifier.rs rename to crates/iota-framework-tests/src/metered_verifier.rs index fde5b7a060f..aae1e45896c 100644 --- a/crates/sui-framework-tests/src/metered_verifier.rs +++ b/crates/iota-framework-tests/src/metered_verifier.rs @@ -1,22 +1,23 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{path::PathBuf, sync::Arc, time::Instant}; -use move_bytecode_verifier::meter::Scope; -use prometheus::Registry; -use sui_adapter::adapter::run_metered_move_bytecode_verifier; -use sui_framework::BuiltInFramework; -use sui_move_build::{CompiledPackage, SuiPackageHooks}; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ - error::{SuiError, SuiResult}, +use iota_adapter::adapter::run_metered_move_bytecode_verifier; +use iota_framework::BuiltInFramework; +use iota_move_build::{CompiledPackage, IotaPackageHooks}; +use iota_protocol_config::ProtocolConfig; +use iota_types::{ + error::{IotaError, IotaResult}, metrics::BytecodeVerifierMetrics, }; -use sui_verifier::{default_verifier_config, meter::SuiVerifierMeter}; +use iota_verifier::{default_verifier_config, meter::IotaVerifierMeter}; +use move_bytecode_verifier::meter::Scope; +use prometheus::Registry; -fn build(path: PathBuf) -> SuiResult { - let mut config = sui_move_build::BuildConfig::new_for_testing(); +fn build(path: PathBuf) -> IotaResult { + let mut config = iota_move_build::BuildConfig::new_for_testing(); config.config.warnings_are_errors = true; config.build(path) } @@ -24,9 +25,9 @@ fn build(path: PathBuf) -> SuiResult { #[test] #[cfg_attr(msim, ignore)] fn test_metered_move_bytecode_verifier() { - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); let path = - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../sui-framework/packages/sui-framework"); + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../iota-framework/packages/iota-framework"); let compiled_package = build(path).unwrap(); let compiled_modules: Vec<_> = compiled_package.get_modules().cloned().collect(); @@ -36,7 +37,7 @@ fn test_metered_move_bytecode_verifier() { ); let registry = &Registry::new(); let bytecode_verifier_metrics = Arc::new(BytecodeVerifierMetrics::new(registry)); - let mut meter = SuiVerifierMeter::new(&metered_verifier_config); + let mut meter = IotaVerifierMeter::new(&metered_verifier_config); let timer_start = Instant::now(); // Default case should pass let r = run_metered_move_bytecode_verifier( @@ -103,7 +104,7 @@ fn test_metered_move_bytecode_verifier() { bytecode_verifier_metrics .verifier_timeout_metrics .with_label_values(&[ - BytecodeVerifierMetrics::SUI_VERIFIER_TAG, + BytecodeVerifierMetrics::IOTA_VERIFIER_TAG, BytecodeVerifierMetrics::TIMEOUT_TAG, ]) .get(), @@ -127,7 +128,7 @@ fn test_metered_move_bytecode_verifier() { metered_verifier_config.max_per_mod_meter_units = Some(10_000); metered_verifier_config.max_per_fun_meter_units = Some(10_000); - let mut meter = SuiVerifierMeter::new(&metered_verifier_config); + let mut meter = IotaVerifierMeter::new(&metered_verifier_config); let timer_start = Instant::now(); let r = run_metered_move_bytecode_verifier( &compiled_modules, @@ -139,7 +140,7 @@ fn test_metered_move_bytecode_verifier() { assert!(matches!( r.unwrap_err(), - SuiError::ModuleVerificationFailure { .. } + IotaError::ModuleVerificationFailure { .. } )); // Some new modules might have passed @@ -184,13 +185,13 @@ fn test_metered_move_bytecode_verifier() { ]) .get(), ); - // Sui verifier did not fail + // Iota verifier did not fail assert_eq!( 0, bytecode_verifier_metrics .verifier_timeout_metrics .with_label_values(&[ - BytecodeVerifierMetrics::SUI_VERIFIER_TAG, + BytecodeVerifierMetrics::IOTA_VERIFIER_TAG, BytecodeVerifierMetrics::TIMEOUT_TAG, ]) .get(), @@ -211,14 +212,14 @@ fn test_metered_move_bytecode_verifier() { // Check shared meter logic works across all publish in PT let mut packages = vec![]; let with_unpublished_deps = false; - let path = - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../sui_programmability/examples/basics"); + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../../iota_programmability/examples/basics"); let package = build(path).unwrap(); packages.push(package.get_dependency_sorted_modules(with_unpublished_deps)); packages.push(package.get_dependency_sorted_modules(with_unpublished_deps)); let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("../../sui_programmability/examples/fungible_tokens"); + .join("../../iota_programmability/examples/fungible_tokens"); let package = build(path).unwrap(); packages.push(package.get_dependency_sorted_modules(with_unpublished_deps)); @@ -227,7 +228,7 @@ fn test_metered_move_bytecode_verifier() { let metered_verifier_config = default_verifier_config(&protocol_config, is_metered); // Check if the same meter is indeed used multiple invocations of the verifier - let mut meter = SuiVerifierMeter::new(&metered_verifier_config); + let mut meter = IotaVerifierMeter::new(&metered_verifier_config); for modules in &packages { let prev_meter = meter.get_usage(Scope::Module) + meter.get_usage(Scope::Function); @@ -247,14 +248,14 @@ fn test_metered_move_bytecode_verifier() { #[test] #[cfg_attr(msim, ignore)] fn test_meter_system_packages() { - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); let is_metered = true; let metered_verifier_config = default_verifier_config(&ProtocolConfig::get_for_max_version_UNSAFE(), is_metered); let registry = &Registry::new(); let bytecode_verifier_metrics = Arc::new(BytecodeVerifierMetrics::new(registry)); - let mut meter = SuiVerifierMeter::new(&metered_verifier_config); + let mut meter = IotaVerifierMeter::new(&metered_verifier_config); for system_package in BuiltInFramework::iter_system_packages() { run_metered_move_bytecode_verifier( &system_package.modules(), @@ -287,7 +288,7 @@ fn test_meter_system_packages() { bytecode_verifier_metrics .verifier_timeout_metrics .with_label_values(&[ - BytecodeVerifierMetrics::SUI_VERIFIER_TAG, + BytecodeVerifierMetrics::IOTA_VERIFIER_TAG, BytecodeVerifierMetrics::TIMEOUT_TAG, ]) .get(), @@ -311,7 +312,7 @@ fn test_meter_system_packages() { #[test] #[cfg_attr(msim, ignore)] fn test_build_and_verify_programmability_examples() { - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); let is_metered = true; let metered_verifier_config = @@ -319,7 +320,7 @@ fn test_build_and_verify_programmability_examples() { let registry = &Registry::new(); let bytecode_verifier_metrics = Arc::new(BytecodeVerifierMetrics::new(registry)); let examples = - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../sui_programmability/examples"); + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../iota_programmability/examples"); for example in std::fs::read_dir(examples).unwrap() { let Ok(example) = example else { continue }; @@ -336,7 +337,7 @@ fn test_build_and_verify_programmability_examples() { let modules = build(path).unwrap().into_modules(); - let mut meter = SuiVerifierMeter::new(&metered_verifier_config); + let mut meter = IotaVerifierMeter::new(&metered_verifier_config); run_metered_move_bytecode_verifier( &modules, &metered_verifier_config, diff --git a/crates/sui-framework-tests/src/unit_tests.rs b/crates/iota-framework-tests/src/unit_tests.rs similarity index 84% rename from crates/sui-framework-tests/src/unit_tests.rs rename to crates/iota-framework-tests/src/unit_tests.rs index 5618cfa098c..59a86cbe039 100644 --- a/crates/sui-framework-tests/src/unit_tests.rs +++ b/crates/iota-framework-tests/src/unit_tests.rs @@ -1,32 +1,33 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fs, io, path::PathBuf}; +use iota_move::unit_test::run_move_unit_tests; +use iota_move_build::BuildConfig; use move_cli::base::test::UnitTestResult; use move_package::LintFlag; use move_unit_test::UnitTestingConfig; -use sui_move::unit_test::run_move_unit_tests; -use sui_move_build::BuildConfig; const FILTER_ENV: &str = "FILTER"; #[test] #[cfg_attr(msim, ignore)] -fn run_sui_framework_tests() { +fn run_iota_framework_tests() { check_move_unit_tests({ let mut buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - buf.extend(["..", "sui-framework", "packages", "sui-framework"]); + buf.extend(["..", "iota-framework", "packages", "iota-framework"]); buf }); } #[test] #[cfg_attr(msim, ignore)] -fn run_sui_system_tests() { +fn run_iota_system_tests() { check_move_unit_tests({ let mut buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - buf.extend(["..", "sui-framework", "packages", "sui-system"]); + buf.extend(["..", "iota-framework", "packages", "iota-system"]); buf }); } @@ -36,7 +37,7 @@ fn run_sui_system_tests() { fn run_deepbook_tests() { check_move_unit_tests({ let mut buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - buf.extend(["..", "sui-framework", "packages", "deepbook"]); + buf.extend(["..", "iota-framework", "packages", "deepbook"]); buf }); } @@ -46,7 +47,7 @@ fn run_deepbook_tests() { fn run_stardust_tests() { check_move_unit_tests({ let mut buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - buf.extend(["..", "sui-framework", "packages", "stardust"]); + buf.extend(["..", "iota-framework", "packages", "stardust"]); buf }); } @@ -56,7 +57,7 @@ fn run_stardust_tests() { fn run_timelock_tests() { check_move_unit_tests({ let mut buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - buf.extend(["..", "sui-framework", "packages", "timelock"]); + buf.extend(["..", "iota-framework", "packages", "timelock"]); buf }); } @@ -77,7 +78,7 @@ fn run_examples_move_unit_tests() { ] { let path = { let mut buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - buf.extend(["..", "..", "sui_programmability", "examples", example]); + buf.extend(["..", "..", "iota_programmability", "examples", example]); buf }; diff --git a/crates/iota-framework/CONTRIBUTING.md b/crates/iota-framework/CONTRIBUTING.md new file mode 100644 index 00000000000..a48ab00d6a2 --- /dev/null +++ b/crates/iota-framework/CONTRIBUTING.md @@ -0,0 +1,16 @@ +This file contains useful information and troubleshooting advice for those wishing to contribute to `iota-framework` crate. + +## Framework Move source code changes + +If changes need to be made to the framework's Move code, additional actions need to be taken to ensure that the system builds and runs correctly. In particular, one needs to make sure that the framework snapshot tests are up-to-date and that any new native functions are correctly handled by the [Move Prover](https://github.com/move-language/move/tree/main/language/move-prover). + +### Snapshot tests update + +Run the following commands in Iota's [root directory](../../) and accept the changes, if any (if you do not have `cargo-insta` command installed, please run the `cargo install cargo-insta` command first): + +``` bash +cargo insta test -p iota-cost --review +cargo insta test -p iota-config --review +``` + +Please use your best judgment to decide if the changes between old and new versions of the snapshots look "reasonable" (e.g., a minor change in gas costs). When in doubt, please reach out to a member of Iota core team. diff --git a/crates/iota-framework/Cargo.toml b/crates/iota-framework/Cargo.toml new file mode 100644 index 00000000000..fe7b133e147 --- /dev/null +++ b/crates/iota-framework/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "iota-framework" +version = "0.1.0" +edition = "2021" +authors = ["Mysten Labs "] +description = "Move framework for iota platform" +license = "Apache-2.0" +publish = false + +[dependencies] +bcs.workspace = true +serde.workspace = true +once_cell.workspace = true +tracing.workspace = true + +iota-types.workspace = true + +move-binary-format.workspace = true +move-core-types.workspace = true + +[build-dependencies] +anyhow.workspace = true +bcs.workspace = true +regex.workspace = true + +iota-move-build.workspace = true + +move-binary-format.workspace = true +move-compiler.workspace = true +move-package.workspace = true diff --git a/crates/iota-framework/README.md b/crates/iota-framework/README.md new file mode 100644 index 00000000000..d9b2664fd47 --- /dev/null +++ b/crates/iota-framework/README.md @@ -0,0 +1,11 @@ +# To add a new native Move function + +1. Add a new `./iota-framework/{name}.move` file or find an appropriate `.move`. +2. Add the signature of the function you are adding in `{name}.move`. +3. Add the rust implementation of the function under `./iota-framework/src/natives` with name `{name}.rs`. +4. Link the move interface with the native function in [all_natives](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/src/natives/mod.rs#L23) +5. Write some tests in `{name}_tests.move` and pass `run_framework_move_unit_tests`. +6. Optionally, update the mock move VM value in [gas_tests.rs](https://github.com/iotaledger/iota/blob/276356e168047cdfce71814cb14403f4653a3656/crates/iota-core/src/unit_tests/gas_tests.rs) since the iota-framework package will increase the gas metering. +7. Optionally, run `cargo insta test` and `cargo insta review` since the iota-framework build will change the empty genesis config. + +Note: The gas metering for native functions is currently a WIP; use a dummy value for now and please open an issue with `move` label. diff --git a/crates/iota-framework/build.rs b/crates/iota-framework/build.rs new file mode 100644 index 00000000000..0f4c5fe292e --- /dev/null +++ b/crates/iota-framework/build.rs @@ -0,0 +1,328 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::BTreeMap, + env, fs, + path::{Path, PathBuf}, +}; + +use anyhow::Result; +use iota_move_build::{BuildConfig, IotaPackageHooks}; +use move_binary_format::CompiledModule; +use move_compiler::editions::Edition; +use move_package::{BuildConfig as MoveBuildConfig, LintFlag}; + +const DOCS_DIR: &str = "docs"; + +/// Save revision info to environment variable +fn main() { + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let packages_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("packages"); + + let deepbook_path = packages_path.join("deepbook"); + let iota_system_path = packages_path.join("iota-system"); + let iota_framework_path = packages_path.join("iota-framework"); + let stardust_path = packages_path.join("stardust"); + let timelock_path = packages_path.join("timelock"); + let deepbook_path_clone = deepbook_path.clone(); + let iota_system_path_clone = iota_system_path.clone(); + let iota_framework_path_clone = iota_framework_path.clone(); + let stardust_path_clone = stardust_path.clone(); + let timelock_path_clone = timelock_path.clone(); + let move_stdlib_path = packages_path.join("move-stdlib"); + + build_packages( + deepbook_path_clone, + iota_system_path_clone, + iota_framework_path_clone, + stardust_path_clone, + timelock_path_clone, + out_dir, + ); + + println!("cargo:rerun-if-changed=build.rs"); + println!( + "cargo:rerun-if-changed={}", + deepbook_path.join("Move.toml").display() + ); + println!( + "cargo:rerun-if-changed={}", + deepbook_path.join("sources").display() + ); + println!( + "cargo:rerun-if-changed={}", + iota_system_path.join("Move.toml").display() + ); + println!( + "cargo:rerun-if-changed={}", + iota_system_path.join("sources").display() + ); + println!( + "cargo:rerun-if-changed={}", + iota_framework_path.join("Move.toml").display() + ); + println!( + "cargo:rerun-if-changed={}", + iota_framework_path.join("sources").display() + ); + println!( + "cargo:rerun-if-changed={}", + move_stdlib_path.join("Move.toml").display() + ); + println!( + "cargo:rerun-if-changed={}", + move_stdlib_path.join("sources").display() + ); + println!( + "cargo:rerun-if-changed={}", + stardust_path.join("Move.toml").display() + ); + println!( + "cargo:rerun-if-changed={}", + stardust_path.join("sources").display() + ); + println!( + "cargo:rerun-if-changed={}", + timelock_path.join("Move.toml").display() + ); + println!( + "cargo:rerun-if-changed={}", + timelock_path.join("sources").display() + ); +} + +fn build_packages( + deepbook_path: PathBuf, + iota_system_path: PathBuf, + iota_framework_path: PathBuf, + stardust_path: PathBuf, + timelock_path: PathBuf, + out_dir: PathBuf, +) { + let config = MoveBuildConfig { + generate_docs: true, + warnings_are_errors: true, + install_dir: Some(PathBuf::from(".")), + lint_flag: LintFlag::LEVEL_NONE, + default_edition: Some(Edition::E2024_BETA), + ..Default::default() + }; + debug_assert!(!config.test_mode); + build_packages_with_move_config( + deepbook_path.clone(), + iota_system_path.clone(), + iota_framework_path.clone(), + stardust_path.clone(), + timelock_path.clone(), + out_dir.clone(), + "deepbook", + "iota-system", + "iota-framework", + "move-stdlib", + "stardust", + "timelock", + config, + true, + ); + let config = MoveBuildConfig { + generate_docs: true, + test_mode: true, + warnings_are_errors: true, + install_dir: Some(PathBuf::from(".")), + lint_flag: LintFlag::LEVEL_NONE, + default_edition: Some(Edition::E2024_BETA), + ..Default::default() + }; + build_packages_with_move_config( + deepbook_path, + iota_system_path, + iota_framework_path, + stardust_path, + timelock_path, + out_dir, + "deepbook-test", + "iota-system-test", + "iota-framework-test", + "move-stdlib-test", + "stardust-test", + "timelock-test", + config, + false, + ); +} + +fn build_packages_with_move_config( + deepbook_path: PathBuf, + iota_system_path: PathBuf, + iota_framework_path: PathBuf, + stardust_path: PathBuf, + timelock_path: PathBuf, + out_dir: PathBuf, + deepbook_dir: &str, + system_dir: &str, + framework_dir: &str, + stdlib_dir: &str, + stardust_dir: &str, + timelock_dir: &str, + config: MoveBuildConfig, + write_docs: bool, +) { + let framework_pkg = BuildConfig { + config: config.clone(), + run_bytecode_verifier: true, + print_diags_to_stderr: false, + } + .build(iota_framework_path) + .unwrap(); + let system_pkg = BuildConfig { + config: config.clone(), + run_bytecode_verifier: true, + print_diags_to_stderr: false, + } + .build(iota_system_path) + .unwrap(); + let deepbook_pkg = BuildConfig { + config: config.clone(), + run_bytecode_verifier: true, + print_diags_to_stderr: false, + } + .build(deepbook_path) + .unwrap(); + let stardust_pkg = BuildConfig { + config: config.clone(), + run_bytecode_verifier: true, + print_diags_to_stderr: false, + } + .build(stardust_path) + .unwrap(); + let timelock_pkg = BuildConfig { + config, + run_bytecode_verifier: true, + print_diags_to_stderr: false, + } + .build(timelock_path) + .unwrap(); + + let iota_system = system_pkg.get_iota_system_modules(); + let iota_framework = framework_pkg.get_iota_framework_modules(); + let deepbook = deepbook_pkg.get_deepbook_modules(); + let move_stdlib = framework_pkg.get_stdlib_modules(); + let stardust = stardust_pkg.get_stardust_modules(); + let timelock = timelock_pkg.get_timelock_modules(); + + serialize_modules_to_file(iota_system, &out_dir.join(system_dir)).unwrap(); + serialize_modules_to_file(iota_framework, &out_dir.join(framework_dir)).unwrap(); + serialize_modules_to_file(deepbook, &out_dir.join(deepbook_dir)).unwrap(); + serialize_modules_to_file(move_stdlib, &out_dir.join(stdlib_dir)).unwrap(); + serialize_modules_to_file(stardust, &out_dir.join(stardust_dir)).unwrap(); + serialize_modules_to_file(timelock, &out_dir.join(timelock_dir)).unwrap(); + // write out generated docs + if write_docs { + // Remove the old docs directory -- in case there was a module that was deleted + // (could happen during development). + if Path::new(DOCS_DIR).exists() { + std::fs::remove_dir_all(DOCS_DIR).unwrap(); + } + let mut files_to_write = BTreeMap::new(); + relocate_docs( + deepbook_dir, + &deepbook_pkg.package.compiled_docs.unwrap(), + &mut files_to_write, + ); + relocate_docs( + system_dir, + &system_pkg.package.compiled_docs.unwrap(), + &mut files_to_write, + ); + relocate_docs( + framework_dir, + &framework_pkg.package.compiled_docs.unwrap(), + &mut files_to_write, + ); + relocate_docs( + stardust_dir, + &stardust_pkg.package.compiled_docs.unwrap(), + &mut files_to_write, + ); + relocate_docs( + timelock_dir, + &timelock_pkg.package.compiled_docs.unwrap(), + &mut files_to_write, + ); + for (fname, doc) in files_to_write { + let mut dst_path = PathBuf::from(DOCS_DIR); + dst_path.push(fname); + fs::create_dir_all(dst_path.parent().unwrap()).unwrap(); + fs::write(dst_path, doc).unwrap(); + } + } +} + +/// Post process the generated docs so that they are in a format that can be +/// consumed by docusaurus. +/// * Flatten out the tree-like structure of the docs directory that we generate +/// for a package into a flat list of packages; +/// * Deduplicate packages (since multiple packages could share dependencies); +/// and +/// * Write out the package docs in a flat directory structure. +fn relocate_docs(prefix: &str, files: &[(String, String)], output: &mut BTreeMap) { + // Turn on multi-line mode so that `.` matches newlines, consume from the start + // of the file to beginning of the heading, then capture the heading and + // replace with the yaml tag for docusaurus. E.g., ``` + // - + // - + // -# Module `0x2::display` + // - + // +--- + // +title: Module `0x2::display` + // +--- + //``` + let re = regex::Regex::new(r"(?s).*\n#\s+(.*?)\n").unwrap(); + for (file_name, file_content) in files { + let path = PathBuf::from(file_name); + let top_level = path.components().count() == 1; + let file_name = if top_level { + let mut new_path = PathBuf::from(prefix); + new_path.push(file_name); + new_path.to_string_lossy().to_string() + } else { + let mut new_path = PathBuf::new(); + new_path.push(path.components().skip(1).collect::()); + new_path.to_string_lossy().to_string() + }; + output.entry(file_name).or_insert_with(|| { + re.replace_all( + &file_content + .replace("../../dependencies/", "../") + .replace("dependencies/", "../"), + "---\ntitle: $1\n---\n", + ) + .to_string() + }); + } +} + +fn serialize_modules_to_file<'a>( + modules: impl Iterator, + file: &Path, +) -> Result<()> { + let mut serialized_modules = Vec::new(); + for module in modules { + let mut buf = Vec::new(); + module.serialize(&mut buf)?; + serialized_modules.push(buf); + } + assert!( + !serialized_modules.is_empty(), + "Failed to find system or framework or stdlib modules" + ); + + let binary = bcs::to_bytes(&serialized_modules)?; + + fs::write(file, binary)?; + + Ok(()) +} diff --git a/crates/iota-framework/docs/deepbook/clob.md b/crates/iota-framework/docs/deepbook/clob.md new file mode 100644 index 00000000000..f0dc3afb83b --- /dev/null +++ b/crates/iota-framework/docs/deepbook/clob.md @@ -0,0 +1,2535 @@ +--- +title: Module `0xdee9::clob` +--- + + + +- [Struct `PoolCreated`](#0xdee9_clob_PoolCreated) +- [Struct `OrderPlacedV2`](#0xdee9_clob_OrderPlacedV2) +- [Struct `OrderCanceled`](#0xdee9_clob_OrderCanceled) +- [Struct `OrderFilledV2`](#0xdee9_clob_OrderFilledV2) +- [Struct `Order`](#0xdee9_clob_Order) +- [Struct `TickLevel`](#0xdee9_clob_TickLevel) +- [Resource `Pool`](#0xdee9_clob_Pool) +- [Struct `OrderPlaced`](#0xdee9_clob_OrderPlaced) +- [Struct `OrderFilled`](#0xdee9_clob_OrderFilled) +- [Constants](#@Constants_0) +- [Function `destroy_empty_level`](#0xdee9_clob_destroy_empty_level) +- [Function `create_account`](#0xdee9_clob_create_account) +- [Function `create_pool`](#0xdee9_clob_create_pool) +- [Function `deposit_base`](#0xdee9_clob_deposit_base) +- [Function `deposit_quote`](#0xdee9_clob_deposit_quote) +- [Function `withdraw_base`](#0xdee9_clob_withdraw_base) +- [Function `withdraw_quote`](#0xdee9_clob_withdraw_quote) +- [Function `swap_exact_base_for_quote`](#0xdee9_clob_swap_exact_base_for_quote) +- [Function `swap_exact_quote_for_base`](#0xdee9_clob_swap_exact_quote_for_base) +- [Function `match_bid_with_quote_quantity`](#0xdee9_clob_match_bid_with_quote_quantity) +- [Function `match_bid`](#0xdee9_clob_match_bid) +- [Function `match_ask`](#0xdee9_clob_match_ask) +- [Function `place_market_order`](#0xdee9_clob_place_market_order) +- [Function `inject_limit_order`](#0xdee9_clob_inject_limit_order) +- [Function `place_limit_order`](#0xdee9_clob_place_limit_order) +- [Function `order_is_bid`](#0xdee9_clob_order_is_bid) +- [Function `emit_order_canceled`](#0xdee9_clob_emit_order_canceled) +- [Function `emit_order_filled`](#0xdee9_clob_emit_order_filled) +- [Function `cancel_order`](#0xdee9_clob_cancel_order) +- [Function `remove_order`](#0xdee9_clob_remove_order) +- [Function `cancel_all_orders`](#0xdee9_clob_cancel_all_orders) +- [Function `batch_cancel_order`](#0xdee9_clob_batch_cancel_order) +- [Function `list_open_orders`](#0xdee9_clob_list_open_orders) +- [Function `account_balance`](#0xdee9_clob_account_balance) +- [Function `get_market_price`](#0xdee9_clob_get_market_price) +- [Function `get_level2_book_status_bid_side`](#0xdee9_clob_get_level2_book_status_bid_side) +- [Function `get_level2_book_status_ask_side`](#0xdee9_clob_get_level2_book_status_ask_side) +- [Function `get_level2_book_status`](#0xdee9_clob_get_level2_book_status) +- [Function `get_order_status`](#0xdee9_clob_get_order_status) + + +
    use 0x1::option;
    +use 0x1::type_name;
    +use 0x2::balance;
    +use 0x2::clock;
    +use 0x2::coin;
    +use 0x2::event;
    +use 0x2::iota;
    +use 0x2::linked_table;
    +use 0x2::object;
    +use 0x2::table;
    +use 0x2::tx_context;
    +use 0xdee9::critbit;
    +use 0xdee9::custodian;
    +use 0xdee9::math;
    +
    + + + + + +## Struct `PoolCreated` + +Emitted when a new pool is created + + +
    struct PoolCreated has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +pool_id: object::ID +
    +
    + object ID of the newly created pool +
    +
    +base_asset: type_name::TypeName +
    +
    + +
    +
    +quote_asset: type_name::TypeName +
    +
    + +
    +
    +taker_fee_rate: u64 +
    +
    + +
    +
    +maker_rebate_rate: u64 +
    +
    + +
    +
    +tick_size: u64 +
    +
    + +
    +
    +lot_size: u64 +
    +
    + +
    +
    + + +
    + + + +## Struct `OrderPlacedV2` + +Emitted when a maker order is injected into the order book. + + +
    struct OrderPlacedV2<BaseAsset, QuoteAsset> has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +pool_id: object::ID +
    +
    + object ID of the pool the order was placed on +
    +
    +order_id: u64 +
    +
    + ID of the order within the pool +
    +
    +is_bid: bool +
    +
    + +
    +
    +owner: object::ID +
    +
    + object ID of the AccountCap that placed the order +
    +
    +base_asset_quantity_placed: u64 +
    +
    + +
    +
    +price: u64 +
    +
    + +
    +
    +expire_timestamp: u64 +
    +
    + +
    +
    + + +
    + + + +## Struct `OrderCanceled` + +Emitted when a maker order is canceled. + + +
    struct OrderCanceled<BaseAsset, QuoteAsset> has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +pool_id: object::ID +
    +
    + object ID of the pool the order was placed on +
    +
    +order_id: u64 +
    +
    + ID of the order within the pool +
    +
    +is_bid: bool +
    +
    + +
    +
    +owner: object::ID +
    +
    + object ID of the AccountCap that placed the order +
    +
    +base_asset_quantity_canceled: u64 +
    +
    + +
    +
    +price: u64 +
    +
    + +
    +
    + + +
    + + + +## Struct `OrderFilledV2` + +Emitted only when a maker order is filled. + + +
    struct OrderFilledV2<BaseAsset, QuoteAsset> has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +pool_id: object::ID +
    +
    + object ID of the pool the order was placed on +
    +
    +order_id: u64 +
    +
    + ID of the order within the pool +
    +
    +is_bid: bool +
    +
    + +
    +
    +owner: object::ID +
    +
    + object ID of the AccountCap that placed the order +
    +
    +total_quantity: u64 +
    +
    + +
    +
    +base_asset_quantity_filled: u64 +
    +
    + +
    +
    +base_asset_quantity_remaining: u64 +
    +
    + +
    +
    +price: u64 +
    +
    + +
    +
    +taker_commission: u64 +
    +
    + +
    +
    +maker_rebates: u64 +
    +
    + +
    +
    + + +
    + + + +## Struct `Order` + + + +
    struct Order has drop, store
    +
    + + + +
    +Fields + + +
    +
    +order_id: u64 +
    +
    + +
    +
    +price: u64 +
    +
    + +
    +
    +quantity: u64 +
    +
    + +
    +
    +is_bid: bool +
    +
    + +
    +
    +owner: object::ID +
    +
    + +
    +
    +expire_timestamp: u64 +
    +
    + +
    +
    + + +
    + + + +## Struct `TickLevel` + + + +
    struct TickLevel has store
    +
    + + + +
    +Fields + + +
    +
    +price: u64 +
    +
    + +
    +
    +open_orders: linked_table::LinkedTable<u64, clob::Order> +
    +
    + +
    +
    + + +
    + + + +## Resource `Pool` + + + +
    struct Pool<BaseAsset, QuoteAsset> has key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +bids: critbit::CritbitTree<clob::TickLevel> +
    +
    + +
    +
    +asks: critbit::CritbitTree<clob::TickLevel> +
    +
    + +
    +
    +next_bid_order_id: u64 +
    +
    + +
    +
    +next_ask_order_id: u64 +
    +
    + +
    +
    +usr_open_orders: table::Table<object::ID, linked_table::LinkedTable<u64, u64>> +
    +
    + +
    +
    +taker_fee_rate: u64 +
    +
    + +
    +
    +maker_rebate_rate: u64 +
    +
    + +
    +
    +tick_size: u64 +
    +
    + +
    +
    +lot_size: u64 +
    +
    + +
    +
    +base_custodian: custodian::Custodian<BaseAsset> +
    +
    + +
    +
    +quote_custodian: custodian::Custodian<QuoteAsset> +
    +
    + +
    +
    +creation_fee: balance::Balance<iota::IOTA> +
    +
    + +
    +
    +base_asset_trading_fees: balance::Balance<BaseAsset> +
    +
    + +
    +
    +quote_asset_trading_fees: balance::Balance<QuoteAsset> +
    +
    + +
    +
    + + +
    + + + +## Struct `OrderPlaced` + +Deprecated since v1.0.0, use OrderPlacedV2 instead. + + +
    struct OrderPlaced<BaseAsset, QuoteAsset> has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +pool_id: object::ID +
    +
    + object ID of the pool the order was placed on +
    +
    +order_id: u64 +
    +
    + ID of the order within the pool +
    +
    +is_bid: bool +
    +
    + +
    +
    +owner: object::ID +
    +
    + object ID of the AccountCap that placed the order +
    +
    +base_asset_quantity_placed: u64 +
    +
    + +
    +
    +price: u64 +
    +
    + +
    +
    + + +
    + + + +## Struct `OrderFilled` + +Deprecated since v1.0.0, use OrderFilledV2 instead. + + +
    struct OrderFilled<BaseAsset, QuoteAsset> has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +pool_id: object::ID +
    +
    + object ID of the pool the order was placed on +
    +
    +order_id: u64 +
    +
    + ID of the order within the pool +
    +
    +is_bid: bool +
    +
    + +
    +
    +owner: object::ID +
    +
    + object ID of the AccountCap that placed the order +
    +
    +total_quantity: u64 +
    +
    + +
    +
    +base_asset_quantity_filled: u64 +
    +
    + +
    +
    +base_asset_quantity_remaining: u64 +
    +
    + +
    +
    +price: u64 +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + + + +
    const FLOAT_SCALING: u64 = 1000000000;
    +
    + + + + + + + +
    const DEPRECATED: u64 = 0;
    +
    + + + + + + + +
    const EInsufficientBaseCoin: u64 = 7;
    +
    + + + + + + + +
    const EInsufficientQuoteCoin: u64 = 8;
    +
    + + + + + + + +
    const EInvalidExpireTimestamp: u64 = 19;
    +
    + + + + + + + +
    const EInvalidOrderId: u64 = 3;
    +
    + + + + + + + +
    const EInvalidPrice: u64 = 5;
    +
    + + + + + + + +
    const EInvalidQuantity: u64 = 6;
    +
    + + + + + + + +
    const EInvalidRestriction: u64 = 14;
    +
    + + + + + + + +
    const EInvalidTickPrice: u64 = 11;
    +
    + + + + + + + +
    const EInvalidUser: u64 = 12;
    +
    + + + + + + + +
    const EOrderCannotBeFullyFilled: u64 = 9;
    +
    + + + + + + + +
    const EOrderCannotBeFullyPassive: u64 = 10;
    +
    + + + + + + + +
    const EUnauthorizedCancel: u64 = 4;
    +
    + + + + + + + +
    const FILL_OR_KILL: u8 = 2;
    +
    + + + + + + + +
    const IMMEDIATE_OR_CANCEL: u8 = 1;
    +
    + + + + + + + +
    const MAX_PRICE: u64 = 9223372036854775808;
    +
    + + + + + + + +
    const MIN_ASK_ORDER_ID: u64 = 9223372036854775808;
    +
    + + + + + + + +
    const MIN_PRICE: u64 = 0;
    +
    + + + + + + + +
    const NO_RESTRICTION: u8 = 0;
    +
    + + + + + + + +
    const POST_OR_ABORT: u8 = 3;
    +
    + + + + + +## Function `destroy_empty_level` + + + +
    fun destroy_empty_level(level: clob::TickLevel)
    +
    + + + +
    +Implementation + + +
    fun destroy_empty_level(level: TickLevel) {
    +    let TickLevel {
    +        price: _,
    +        open_orders: orders,
    +    } = level;
    +
    +    linked_table::destroy_empty(orders);
    +}
    +
    + + + +
    + + + +## Function `create_account` + + + +
    public fun create_account(_ctx: &mut tx_context::TxContext): custodian::AccountCap
    +
    + + + +
    +Implementation + + +
    public fun create_account(_ctx: &mut TxContext): AccountCap {
    +    abort DEPRECATED
    +}
    +
    + + + +
    + + + +## Function `create_pool` + + + +
    public fun create_pool<BaseAsset, QuoteAsset>(_tick_size: u64, _lot_size: u64, _creation_fee: coin::Coin<iota::IOTA>, _ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public fun create_pool<BaseAsset, QuoteAsset>(
    +    _tick_size: u64,
    +    _lot_size: u64,
    +    _creation_fee: Coin<IOTA>,
    +    _ctx: &mut TxContext,
    +) {
    +    abort DEPRECATED
    +}
    +
    + + + +
    + + + +## Function `deposit_base` + + + +
    public fun deposit_base<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, coin: coin::Coin<BaseAsset>, account_cap: &custodian::AccountCap)
    +
    + + + +
    +Implementation + + +
    public fun deposit_base<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    coin: Coin<BaseAsset>,
    +    account_cap: &AccountCap
    +) {
    +    assert!(coin::value(&coin) != 0, EInsufficientBaseCoin);
    +    custodian::increase_user_available_balance(
    +        &mut pool.base_custodian,
    +        object::id(account_cap),
    +        coin::into_balance(coin)
    +    )
    +}
    +
    + + + +
    + + + +## Function `deposit_quote` + + + +
    public fun deposit_quote<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, coin: coin::Coin<QuoteAsset>, account_cap: &custodian::AccountCap)
    +
    + + + +
    +Implementation + + +
    public fun deposit_quote<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    coin: Coin<QuoteAsset>,
    +    account_cap: &AccountCap
    +) {
    +    assert!(coin::value(&coin) != 0, EInsufficientQuoteCoin);
    +    custodian::increase_user_available_balance(
    +        &mut pool.quote_custodian,
    +        object::id(account_cap),
    +        coin::into_balance(coin)
    +    )
    +}
    +
    + + + +
    + + + +## Function `withdraw_base` + + + +
    public fun withdraw_base<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, quantity: u64, account_cap: &custodian::AccountCap, ctx: &mut tx_context::TxContext): coin::Coin<BaseAsset>
    +
    + + + +
    +Implementation + + +
    public fun withdraw_base<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    quantity: u64,
    +    account_cap: &AccountCap,
    +    ctx: &mut TxContext
    +): Coin<BaseAsset> {
    +    assert!(quantity > 0, EInvalidQuantity);
    +    custodian::withdraw_asset(&mut pool.base_custodian, quantity, account_cap, ctx)
    +}
    +
    + + + +
    + + + +## Function `withdraw_quote` + + + +
    public fun withdraw_quote<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, quantity: u64, account_cap: &custodian::AccountCap, ctx: &mut tx_context::TxContext): coin::Coin<QuoteAsset>
    +
    + + + +
    +Implementation + + +
    public fun withdraw_quote<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    quantity: u64,
    +    account_cap: &AccountCap,
    +    ctx: &mut TxContext
    +): Coin<QuoteAsset> {
    +    assert!(quantity > 0, EInvalidQuantity);
    +    custodian::withdraw_asset(&mut pool.quote_custodian, quantity, account_cap, ctx)
    +}
    +
    + + + +
    + + + +## Function `swap_exact_base_for_quote` + + + +
    public fun swap_exact_base_for_quote<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, quantity: u64, base_coin: coin::Coin<BaseAsset>, quote_coin: coin::Coin<QuoteAsset>, clock: &clock::Clock, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, u64)
    +
    + + + +
    +Implementation + + +
    public fun swap_exact_base_for_quote<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    quantity: u64,
    +    base_coin: Coin<BaseAsset>,
    +    quote_coin: Coin<QuoteAsset>,
    +    clock: &Clock,
    +    ctx: &mut TxContext,
    +): (Coin<BaseAsset>, Coin<QuoteAsset>, u64) {
    +    assert!(quantity > 0, EInvalidQuantity);
    +    assert!(coin::value(&base_coin) >= quantity, EInsufficientBaseCoin);
    +    let original_val = coin::value("e_coin);
    +    let (ret_base_coin, ret_quote_coin) = place_market_order(
    +        pool,
    +        quantity,
    +        false,
    +        base_coin,
    +        quote_coin,
    +        clock,
    +        ctx
    +    );
    +    let ret_val = coin::value(&ret_quote_coin);
    +    (ret_base_coin, ret_quote_coin, ret_val - original_val)
    +}
    +
    + + + +
    + + + +## Function `swap_exact_quote_for_base` + + + +
    public fun swap_exact_quote_for_base<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, quantity: u64, clock: &clock::Clock, quote_coin: coin::Coin<QuoteAsset>, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, u64)
    +
    + + + +
    +Implementation + + +
    public fun swap_exact_quote_for_base<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    quantity: u64,
    +    clock: &Clock,
    +    quote_coin: Coin<QuoteAsset>,
    +    ctx: &mut TxContext,
    +): (Coin<BaseAsset>, Coin<QuoteAsset>, u64) {
    +    assert!(quantity > 0, EInvalidQuantity);
    +    assert!(coin::value("e_coin) >= quantity, EInsufficientQuoteCoin);
    +    let (base_asset_balance, quote_asset_balance) = match_bid_with_quote_quantity(
    +        pool,
    +        quantity,
    +        MAX_PRICE,
    +        clock::timestamp_ms(clock),
    +        coin::into_balance(quote_coin)
    +    );
    +    let val = balance::value(&base_asset_balance);
    +    (coin::from_balance(base_asset_balance, ctx), coin::from_balance(quote_asset_balance, ctx), val)
    +}
    +
    + + + +
    + + + +## Function `match_bid_with_quote_quantity` + + + +
    fun match_bid_with_quote_quantity<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, quantity: u64, price_limit: u64, current_timestamp: u64, quote_balance: balance::Balance<QuoteAsset>): (balance::Balance<BaseAsset>, balance::Balance<QuoteAsset>)
    +
    + + + +
    +Implementation + + +
    fun match_bid_with_quote_quantity<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    quantity: u64,
    +    price_limit: u64,
    +    current_timestamp: u64,
    +    quote_balance: Balance<QuoteAsset>,
    +): (Balance<BaseAsset>, Balance<QuoteAsset>) {
    +    // Base balance received by taker, taking into account of taker commission.
    +    // Need to individually keep track of the remaining base quantity to be filled to avoid infinite loop.
    +    let pool_id = *object::uid_as_inner(&pool.id);
    +    let mut taker_quote_quantity_remaining = quantity;
    +    let mut base_balance_filled = balance::zero<BaseAsset>();
    +    let mut quote_balance_left = quote_balance;
    +    let all_open_orders = &mut pool.asks;
    +    if (critbit::is_empty(all_open_orders)) {
    +        return (base_balance_filled, quote_balance_left)
    +    };
    +    let (mut tick_price, mut tick_index) = min_leaf(all_open_orders);
    +    let mut terminate_loop = false;
    +
    +    while (!is_empty<TickLevel>(all_open_orders) && tick_price <= price_limit) {
    +        let tick_level = borrow_mut_leaf_by_index(all_open_orders, tick_index);
    +        let mut order_id = *option::borrow(linked_table::front(&tick_level.open_orders));
    +
    +        while (!linked_table::is_empty(&tick_level.open_orders)) {
    +            let maker_order = linked_table::borrow(&tick_level.open_orders, order_id);
    +            let mut maker_base_quantity = maker_order.quantity;
    +            let mut skip_order = false;
    +
    +            if (maker_order.expire_timestamp <= current_timestamp) {
    +                skip_order = true;
    +                custodian::unlock_balance(&mut pool.base_custodian, maker_order.owner, maker_order.quantity);
    +                emit_order_canceled<BaseAsset, QuoteAsset>(pool_id, maker_order);
    +            } else {
    +                // Calculate how much quote asset (maker_quote_quantity) is required, including the commission, to fill the maker order.
    +                let maker_quote_quantity_without_commission = clob_math::mul(
    +                    maker_base_quantity,
    +                    maker_order.price
    +                );
    +                let (is_round_down, mut taker_commission)  = clob_math::unsafe_mul_round(
    +                    maker_quote_quantity_without_commission,
    +                    pool.taker_fee_rate
    +                );
    +                if (is_round_down)  taker_commission = taker_commission + 1;
    +
    +                let maker_quote_quantity = maker_quote_quantity_without_commission + taker_commission;
    +
    +                // Total base quantity filled.
    +                let mut filled_base_quantity: u64;
    +                // Total quote quantity filled, excluding commission and rebate.
    +                let mut filled_quote_quantity: u64;
    +                // Total quote quantity paid by taker.
    +                // filled_quote_quantity_without_commission * (FLOAT_SCALING + taker_fee_rate) = filled_quote_quantity
    +                let mut filled_quote_quantity_without_commission: u64;
    +                if (taker_quote_quantity_remaining > maker_quote_quantity) {
    +                    filled_quote_quantity = maker_quote_quantity;
    +                    filled_quote_quantity_without_commission = maker_quote_quantity_without_commission;
    +                    filled_base_quantity = maker_base_quantity;
    +                } else {
    +                    terminate_loop = true;
    +                    // if not enough quote quantity to pay for taker commission, then no quantity will be filled
    +                    filled_quote_quantity_without_commission = clob_math::unsafe_div(
    +                        taker_quote_quantity_remaining,
    +                        FLOAT_SCALING + pool.taker_fee_rate
    +                    );
    +                    // filled_base_quantity = 0 is permitted since filled_quote_quantity_without_commission can be 0
    +                    filled_base_quantity = clob_math::unsafe_div(
    +                        filled_quote_quantity_without_commission,
    +                        maker_order.price
    +                    );
    +                    let filled_base_lot = filled_base_quantity / pool.lot_size;
    +                    filled_base_quantity = filled_base_lot * pool.lot_size;
    +                    // filled_quote_quantity_without_commission = 0 is permitted here since filled_base_quantity could be 0
    +                    filled_quote_quantity_without_commission = clob_math::unsafe_mul(
    +                        filled_base_quantity,
    +                        maker_order.price
    +                    );
    +                    // if taker_commission = 0 due to underflow, round it up to 1
    +                    let (round_down, mut taker_commission) = clob_math::unsafe_mul_round(
    +                        filled_quote_quantity_without_commission,
    +                        pool.taker_fee_rate
    +                    );
    +                    if (round_down) {
    +                        taker_commission = taker_commission + 1;
    +                    };
    +                    filled_quote_quantity = filled_quote_quantity_without_commission + taker_commission;
    +                };
    +                // if maker_rebate = 0 due to underflow, maker will not receive a rebate
    +                let maker_rebate = clob_math::unsafe_mul(
    +                    filled_quote_quantity_without_commission,
    +                    pool.maker_rebate_rate
    +                );
    +                maker_base_quantity = maker_base_quantity - filled_base_quantity;
    +
    +                // maker in ask side, decrease maker's locked base asset, increase maker's available quote asset
    +                taker_quote_quantity_remaining = taker_quote_quantity_remaining - filled_quote_quantity;
    +                let locked_base_balance = custodian::decrease_user_locked_balance<BaseAsset>(
    +                    &mut pool.base_custodian,
    +                    maker_order.owner,
    +                    filled_base_quantity
    +                );
    +
    +                let mut quote_balance_filled = balance::split(
    +                    &mut quote_balance_left,
    +                    filled_quote_quantity,
    +                );
    +                // Send quote asset including rebate to maker.
    +                custodian::increase_user_available_balance<QuoteAsset>(
    +                    &mut pool.quote_custodian,
    +                    maker_order.owner,
    +                    balance::split(
    +                        &mut quote_balance_filled,
    +                        maker_rebate + filled_quote_quantity_without_commission,
    +                    ),
    +                );
    +                // Send remaining of commission - rebate to the protocol.
    +                // commission - rebate = filled_quote_quantity_without_commission - filled_quote_quantity - maker_rebate
    +                balance::join(&mut pool.quote_asset_trading_fees, quote_balance_filled);
    +                balance::join(&mut base_balance_filled, locked_base_balance);
    +
    +                emit_order_filled<BaseAsset, QuoteAsset>(
    +                    *object::uid_as_inner(&pool.id),
    +                    maker_order,
    +                    filled_base_quantity,
    +                    // taker_commission = filled_quote_quantity - filled_quote_quantity_without_commission
    +                    // This guarantees that the subtraction will not underflow
    +                    filled_quote_quantity - filled_quote_quantity_without_commission,
    +                    maker_rebate
    +                )
    +            };
    +
    +            if (skip_order || maker_base_quantity == 0) {
    +                // Remove the maker order.
    +                let old_order_id = order_id;
    +                let maybe_order_id = linked_table::next(&tick_level.open_orders, order_id);
    +                if (!option::is_none(maybe_order_id)) {
    +                    order_id = *option::borrow(maybe_order_id);
    +                };
    +                let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, maker_order.owner);
    +                linked_table::remove(usr_open_order_ids, old_order_id);
    +                linked_table::remove(&mut tick_level.open_orders, old_order_id);
    +            } else {
    +                // Update the maker order.
    +                let maker_order_mut = linked_table::borrow_mut(
    +                    &mut tick_level.open_orders,
    +                    order_id);
    +                maker_order_mut.quantity = maker_base_quantity;
    +            };
    +            if (terminate_loop) {
    +                break
    +            };
    +        };
    +        if (linked_table::is_empty(&tick_level.open_orders)) {
    +            (tick_price, _) = next_leaf(all_open_orders, tick_price);
    +            destroy_empty_level(remove_leaf_by_index(all_open_orders, tick_index));
    +            (_, tick_index) = find_leaf(all_open_orders, tick_price);
    +        };
    +        if (terminate_loop) {
    +            break
    +        };
    +    };
    +    return (base_balance_filled, quote_balance_left)
    +}
    +
    + + + +
    + + + +## Function `match_bid` + + + +
    fun match_bid<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, quantity: u64, price_limit: u64, current_timestamp: u64, quote_balance: balance::Balance<QuoteAsset>): (balance::Balance<BaseAsset>, balance::Balance<QuoteAsset>)
    +
    + + + +
    +Implementation + + +
    fun match_bid<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    quantity: u64,
    +    price_limit: u64,
    +    current_timestamp: u64,
    +    quote_balance: Balance<QuoteAsset>,
    +): (Balance<BaseAsset>, Balance<QuoteAsset>) {
    +    let pool_id = *object::uid_as_inner(&pool.id);
    +    // Base balance received by taker.
    +    // Need to individually keep track of the remaining base quantity to be filled to avoid infinite loop.
    +    let mut taker_base_quantity_remaining = quantity;
    +    let mut base_balance_filled = balance::zero<BaseAsset>();
    +    let mut quote_balance_left = quote_balance;
    +    let all_open_orders = &mut pool.asks;
    +    if (critbit::is_empty(all_open_orders)) {
    +        return (base_balance_filled, quote_balance_left)
    +    };
    +    let (mut tick_price, mut tick_index) = min_leaf(all_open_orders);
    +
    +    while (!is_empty<TickLevel>(all_open_orders) && tick_price <= price_limit) {
    +        let tick_level = borrow_mut_leaf_by_index(all_open_orders, tick_index);
    +        let mut order_id = *option::borrow(linked_table::front(&tick_level.open_orders));
    +
    +        while (!linked_table::is_empty(&tick_level.open_orders)) {
    +            let maker_order = linked_table::borrow(&tick_level.open_orders, order_id);
    +            let mut maker_base_quantity = maker_order.quantity;
    +            let mut skip_order = false;
    +
    +            if (maker_order.expire_timestamp <= current_timestamp) {
    +                skip_order = true;
    +                custodian::unlock_balance(&mut pool.base_custodian, maker_order.owner, maker_order.quantity);
    +                emit_order_canceled<BaseAsset, QuoteAsset>(pool_id, maker_order);
    +            } else {
    +                let filled_base_quantity =
    +                    if (taker_base_quantity_remaining > maker_base_quantity) { maker_base_quantity }
    +                    else { taker_base_quantity_remaining };
    +
    +                let filled_quote_quantity = clob_math::mul(filled_base_quantity, maker_order.price);
    +
    +                // if maker_rebate = 0 due to underflow, maker will not receive a rebate
    +                let maker_rebate = clob_math::unsafe_mul(filled_quote_quantity, pool.maker_rebate_rate);
    +                // if taker_commission = 0 due to underflow, round it up to 1
    +                let (is_round_down, mut taker_commission) = clob_math::unsafe_mul_round(
    +                    filled_quote_quantity,
    +                    pool.taker_fee_rate
    +                );
    +                if (is_round_down) taker_commission = taker_commission + 1;
    +
    +                maker_base_quantity = maker_base_quantity - filled_base_quantity;
    +
    +                // maker in ask side, decrease maker's locked base asset, increase maker's available quote asset
    +                taker_base_quantity_remaining = taker_base_quantity_remaining - filled_base_quantity;
    +                let locked_base_balance = custodian::decrease_user_locked_balance<BaseAsset>(
    +                    &mut pool.base_custodian,
    +                    maker_order.owner,
    +                    filled_base_quantity
    +                );
    +                let mut taker_commission_balance = balance::split(
    +                    &mut quote_balance_left,
    +                    taker_commission,
    +                );
    +                custodian::increase_user_available_balance<QuoteAsset>(
    +                    &mut pool.quote_custodian,
    +                    maker_order.owner,
    +                    balance::split(
    +                        &mut taker_commission_balance,
    +                        maker_rebate,
    +                    ),
    +                );
    +                balance::join(&mut pool.quote_asset_trading_fees, taker_commission_balance);
    +                balance::join(&mut base_balance_filled, locked_base_balance);
    +
    +                custodian::increase_user_available_balance<QuoteAsset>(
    +                    &mut pool.quote_custodian,
    +                    maker_order.owner,
    +                    balance::split(
    +                        &mut quote_balance_left,
    +                        filled_quote_quantity,
    +                    ),
    +                );
    +
    +                emit_order_filled<BaseAsset, QuoteAsset>(
    +                    *object::uid_as_inner(&pool.id),
    +                    maker_order,
    +                    filled_base_quantity,
    +                    taker_commission,
    +                    maker_rebate
    +                );
    +            };
    +
    +            if (skip_order || maker_base_quantity == 0) {
    +                // Remove the maker order.
    +                let old_order_id = order_id;
    +                let maybe_order_id = linked_table::next(&tick_level.open_orders, order_id);
    +                if (!option::is_none(maybe_order_id)) {
    +                    order_id = *option::borrow(maybe_order_id);
    +                };
    +                let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, maker_order.owner);
    +                linked_table::remove(usr_open_order_ids, old_order_id);
    +                linked_table::remove(&mut tick_level.open_orders, old_order_id);
    +            } else {
    +                // Update the maker order.
    +                let maker_order_mut = linked_table::borrow_mut(
    +                    &mut tick_level.open_orders,
    +                    order_id);
    +                maker_order_mut.quantity = maker_base_quantity;
    +            };
    +            if (taker_base_quantity_remaining == 0) {
    +                break
    +            };
    +        };
    +        if (linked_table::is_empty(&tick_level.open_orders)) {
    +            (tick_price, _) = next_leaf(all_open_orders, tick_price);
    +            destroy_empty_level(remove_leaf_by_index(all_open_orders, tick_index));
    +            (_, tick_index) = find_leaf(all_open_orders, tick_price);
    +        };
    +        if (taker_base_quantity_remaining == 0) {
    +            break
    +        };
    +    };
    +    return (base_balance_filled, quote_balance_left)
    +}
    +
    + + + +
    + + + +## Function `match_ask` + + + +
    fun match_ask<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, price_limit: u64, current_timestamp: u64, base_balance: balance::Balance<BaseAsset>): (balance::Balance<BaseAsset>, balance::Balance<QuoteAsset>)
    +
    + + + +
    +Implementation + + +
    fun match_ask<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    price_limit: u64,
    +    current_timestamp: u64,
    +    base_balance: Balance<BaseAsset>,
    +): (Balance<BaseAsset>, Balance<QuoteAsset>) {
    +    let pool_id = *object::uid_as_inner(&pool.id);
    +    let mut base_balance_left = base_balance;
    +    // Base balance received by taker, taking into account of taker commission.
    +    let mut quote_balance_filled = balance::zero<QuoteAsset>();
    +    let all_open_orders = &mut pool.bids;
    +    if (critbit::is_empty(all_open_orders)) {
    +        return (base_balance_left, quote_balance_filled)
    +    };
    +    let (mut tick_price, mut tick_index) = max_leaf(all_open_orders);
    +    while (!is_empty<TickLevel>(all_open_orders) && tick_price >= price_limit) {
    +        let tick_level = borrow_mut_leaf_by_index(all_open_orders, tick_index);
    +        let mut order_id = *option::borrow(linked_table::front(&tick_level.open_orders));
    +        while (!linked_table::is_empty(&tick_level.open_orders)) {
    +            let maker_order = linked_table::borrow(&tick_level.open_orders, order_id);
    +            let mut maker_base_quantity = maker_order.quantity;
    +            let mut skip_order = false;
    +
    +            if (maker_order.expire_timestamp <= current_timestamp) {
    +                skip_order = true;
    +                let maker_quote_quantity = clob_math::mul(maker_order.quantity, maker_order.price);
    +                custodian::unlock_balance(&mut pool.quote_custodian, maker_order.owner, maker_quote_quantity);
    +                emit_order_canceled<BaseAsset, QuoteAsset>(pool_id, maker_order);
    +            } else {
    +                let taker_base_quantity_remaining = balance::value(&base_balance_left);
    +                let filled_base_quantity =
    +                    if (taker_base_quantity_remaining >= maker_base_quantity) { maker_base_quantity }
    +                    else { taker_base_quantity_remaining };
    +
    +                let filled_quote_quantity = clob_math::mul(filled_base_quantity, maker_order.price);
    +
    +                // if maker_rebate = 0 due to underflow, maker will not receive a rebate
    +                let maker_rebate = clob_math::unsafe_mul(filled_quote_quantity, pool.maker_rebate_rate);
    +                // if taker_commission = 0 due to underflow, round it up to 1
    +                let (is_round_down, mut taker_commission) = clob_math::unsafe_mul_round(
    +                    filled_quote_quantity,
    +                    pool.taker_fee_rate
    +                );
    +                if (is_round_down) taker_commission = taker_commission + 1;
    +
    +                maker_base_quantity = maker_base_quantity - filled_base_quantity;
    +                // maker in bid side, decrease maker's locked quote asset, increase maker's available base asset
    +                let mut locked_quote_balance = custodian::decrease_user_locked_balance<QuoteAsset>(
    +                    &mut pool.quote_custodian,
    +                    maker_order.owner,
    +                    filled_quote_quantity
    +                );
    +                let mut taker_commission_balance = balance::split(
    +                    &mut locked_quote_balance,
    +                    taker_commission,
    +                );
    +                custodian::increase_user_available_balance<QuoteAsset>(
    +                    &mut pool.quote_custodian,
    +                    maker_order.owner,
    +                    balance::split(
    +                        &mut taker_commission_balance,
    +                        maker_rebate,
    +                    ),
    +                );
    +                balance::join(&mut pool.quote_asset_trading_fees, taker_commission_balance);
    +                balance::join(&mut quote_balance_filled, locked_quote_balance);
    +
    +                custodian::increase_user_available_balance<BaseAsset>(
    +                    &mut pool.base_custodian,
    +                    maker_order.owner,
    +                    balance::split(
    +                        &mut base_balance_left,
    +                        filled_base_quantity,
    +                    ),
    +                );
    +
    +                emit_order_filled<BaseAsset, QuoteAsset>(
    +                    *object::uid_as_inner(&pool.id),
    +                    maker_order,
    +                    filled_base_quantity,
    +                    taker_commission,
    +                    maker_rebate
    +                );
    +            };
    +
    +            if (skip_order || maker_base_quantity == 0) {
    +                // Remove the maker order.
    +                let old_order_id = order_id;
    +                let maybe_order_id = linked_table::next(&tick_level.open_orders, order_id);
    +                if (!option::is_none(maybe_order_id)) {
    +                    order_id = *option::borrow(maybe_order_id);
    +                };
    +                let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, maker_order.owner);
    +                linked_table::remove(usr_open_order_ids, old_order_id);
    +                linked_table::remove(&mut tick_level.open_orders, old_order_id);
    +            } else {
    +                // Update the maker order.
    +                let maker_order_mut = linked_table::borrow_mut(
    +                    &mut tick_level.open_orders,
    +                    order_id);
    +                maker_order_mut.quantity = maker_base_quantity;
    +            };
    +            if (balance::value(&base_balance_left) == 0) {
    +                break
    +            };
    +        };
    +        if (linked_table::is_empty(&tick_level.open_orders)) {
    +            (tick_price, _) = previous_leaf(all_open_orders, tick_price);
    +            destroy_empty_level(remove_leaf_by_index(all_open_orders, tick_index));
    +            (_, tick_index) = find_leaf(all_open_orders, tick_price);
    +        };
    +        if (balance::value(&base_balance_left) == 0) {
    +            break
    +        };
    +    };
    +    return (base_balance_left, quote_balance_filled)
    +}
    +
    + + + +
    + + + +## Function `place_market_order` + +Place a market order to the order book. + + +
    public fun place_market_order<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, quantity: u64, is_bid: bool, base_coin: coin::Coin<BaseAsset>, quote_coin: coin::Coin<QuoteAsset>, clock: &clock::Clock, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>)
    +
    + + + +
    +Implementation + + +
    public fun place_market_order<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    quantity: u64,
    +    is_bid: bool,
    +    mut base_coin: Coin<BaseAsset>,
    +    mut quote_coin: Coin<QuoteAsset>,
    +    clock: &Clock,
    +    ctx: &mut TxContext,
    +): (Coin<BaseAsset>, Coin<QuoteAsset>) {
    +    // If market bid order, match against the open ask orders. Otherwise, match against the open bid orders.
    +    // Take market bid order for example.
    +    // We first retrieve the PriceLevel with the lowest price by calling min_leaf on the asks Critbit Tree.
    +    // We then match the market order by iterating through open orders on that price level in ascending order of the order id.
    +    // Open orders that are being filled are removed from the order book.
    +    // We stop the iteration untill all quantities are filled.
    +    // If the total quantity of open orders at the lowest price level is not large enough to fully fill the market order,
    +    // we move on to the next price level by calling next_leaf on the asks Critbit Tree and repeat the same procedure.
    +    // Continue iterating over the price levels in ascending order until the market order is completely filled.
    +    // If ther market order cannot be completely filled even after consuming all the open ask orders,
    +    // the unfilled quantity will be cancelled.
    +    // Market ask order follows similar procedure.
    +    // The difference is that market ask order is matched against the open bid orders.
    +    // We start with the bid PriceLeve with the highest price by calling max_leaf on the bids Critbit Tree.
    +    // The inner loop for iterating over the open orders in ascending orders of order id is the same as above.
    +    // Then iterate over the price levels in descending order until the market order is completely filled.
    +    assert!(quantity % pool.lot_size == 0, EInvalidQuantity);
    +    assert!(quantity != 0, EInvalidQuantity);
    +    if (is_bid) {
    +        let (base_balance_filled, quote_balance_left) = match_bid(
    +            pool,
    +            quantity,
    +            MAX_PRICE,
    +            clock::timestamp_ms(clock),
    +            coin::into_balance(quote_coin),
    +        );
    +        join(
    +            &mut base_coin,
    +            coin::from_balance(base_balance_filled, ctx),
    +        );
    +        quote_coin = coin::from_balance(quote_balance_left, ctx);
    +    } else {
    +        assert!(quantity <= coin::value(&base_coin), EInsufficientBaseCoin);
    +        let (base_balance_left, quote_balance_filled) = match_ask(
    +            pool,
    +            MIN_PRICE,
    +            clock::timestamp_ms(clock),
    +            coin::into_balance(base_coin),
    +        );
    +        base_coin = coin::from_balance(base_balance_left, ctx);
    +        join(
    +            &mut quote_coin,
    +            coin::from_balance(quote_balance_filled, ctx),
    +        );
    +    };
    +    (base_coin, quote_coin)
    +}
    +
    + + + +
    + + + +## Function `inject_limit_order` + +Injects a maker order to the order book. +Returns the order id. + + +
    fun inject_limit_order<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, price: u64, quantity: u64, is_bid: bool, expire_timestamp: u64, account_cap: &custodian::AccountCap, ctx: &mut tx_context::TxContext): u64
    +
    + + + +
    +Implementation + + +
    fun inject_limit_order<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    price: u64,
    +    quantity: u64,
    +    is_bid: bool,
    +    expire_timestamp: u64,
    +    account_cap: &AccountCap,
    +    ctx: &mut TxContext
    +): u64 {
    +    let user = object::id(account_cap);
    +    let order_id: u64;
    +    let open_orders: &mut CritbitTree<TickLevel>;
    +    if (is_bid) {
    +        let quote_quantity = clob_math::mul(quantity, price);
    +        custodian::lock_balance<QuoteAsset>(&mut pool.quote_custodian, account_cap, quote_quantity);
    +        order_id = pool.next_bid_order_id;
    +        pool.next_bid_order_id = pool.next_bid_order_id + 1;
    +        open_orders = &mut pool.bids;
    +    } else {
    +        custodian::lock_balance<BaseAsset>(&mut pool.base_custodian, account_cap, quantity);
    +        order_id = pool.next_ask_order_id;
    +        pool.next_ask_order_id = pool.next_ask_order_id + 1;
    +        open_orders = &mut pool.asks;
    +    };
    +    let order = Order {
    +        order_id,
    +        price,
    +        quantity,
    +        is_bid,
    +        owner: user,
    +        expire_timestamp,
    +    };
    +    let (tick_exists, mut tick_index) = find_leaf(open_orders, price);
    +    if (!tick_exists) {
    +        tick_index = insert_leaf(
    +            open_orders,
    +            price,
    +            TickLevel {
    +                price,
    +                open_orders: linked_table::new(ctx),
    +            });
    +    };
    +
    +    let tick_level = borrow_mut_leaf_by_index(open_orders, tick_index);
    +    linked_table::push_back(&mut tick_level.open_orders, order_id, order);
    +    event::emit(OrderPlacedV2<BaseAsset, QuoteAsset> {
    +        pool_id: *object::uid_as_inner(&pool.id),
    +        order_id,
    +        is_bid,
    +        owner: user,
    +        base_asset_quantity_placed: quantity,
    +        price,
    +        expire_timestamp
    +    });
    +    if (!contains(&pool.usr_open_orders, user)) {
    +        add(&mut pool.usr_open_orders, user, linked_table::new(ctx));
    +    };
    +    linked_table::push_back(borrow_mut(&mut pool.usr_open_orders, user), order_id, price);
    +
    +    return order_id
    +}
    +
    + + + +
    + + + +## Function `place_limit_order` + +Place a limit order to the order book. +Returns (base quantity filled, quote quantity filled, whether a maker order is being placed, order id of the maker order). +When the limit order is not successfully placed, we return false to indicate that and also returns a meaningless order_id 0. +When the limit order is successfully placed, we return true to indicate that and also the corresponding order_id. +So please check that boolean value first before using the order id. + + +
    public fun place_limit_order<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, price: u64, quantity: u64, is_bid: bool, expire_timestamp: u64, restriction: u8, clock: &clock::Clock, account_cap: &custodian::AccountCap, ctx: &mut tx_context::TxContext): (u64, u64, bool, u64)
    +
    + + + +
    +Implementation + + +
    public fun place_limit_order<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    price: u64,
    +    quantity: u64,
    +    is_bid: bool,
    +    expire_timestamp: u64, // Expiration timestamp in ms in absolute value inclusive.
    +    restriction: u8,
    +    clock: &Clock,
    +    account_cap: &AccountCap,
    +    ctx: &mut TxContext
    +): (u64, u64, bool, u64) {
    +    // If limit bid order, check whether the price is lower than the lowest ask order by checking the min_leaf of asks Critbit Tree.
    +    // If so, assign the sequence id of the order to be next_bid_order_id and increment next_bid_order_id by 1.
    +    // Inject the new order to the bids Critbit Tree according to the price and order id.
    +    // Otherwise, find the price level from the asks Critbit Tree that is no greater than the input price.
    +    // Match the bid order against the asks Critbit Tree in the same way as a market order but up until the price level found in the previous step.
    +    // If the bid order is not completely filled, inject the remaining quantity to the bids Critbit Tree according to the input price and order id.
    +    // If limit ask order, vice versa.
    +    assert!(quantity > 0, EInvalidQuantity);
    +    assert!(price > 0, EInvalidPrice);
    +    assert!(price % pool.tick_size == 0, EInvalidPrice);
    +    assert!(quantity % pool.lot_size == 0, EInvalidQuantity);
    +    assert!(expire_timestamp > clock::timestamp_ms(clock), EInvalidExpireTimestamp);
    +    let user = object::id(account_cap);
    +    let base_quantity_filled;
    +    let quote_quantity_filled;
    +
    +    if (is_bid) {
    +        let quote_quantity_original = custodian::account_available_balance<QuoteAsset>(
    +            &pool.quote_custodian,
    +            user,
    +        );
    +        let quote_balance = custodian::decrease_user_available_balance<QuoteAsset>(
    +            &mut pool.quote_custodian,
    +            account_cap,
    +            quote_quantity_original,
    +        );
    +        let (base_balance_filled, quote_balance_left) = match_bid(
    +            pool,
    +            quantity,
    +            price,
    +            clock::timestamp_ms(clock),
    +            quote_balance,
    +        );
    +        base_quantity_filled = balance::value(&base_balance_filled);
    +        quote_quantity_filled = quote_quantity_original - balance::value("e_balance_left);
    +
    +        custodian::increase_user_available_balance<BaseAsset>(
    +            &mut pool.base_custodian,
    +            user,
    +            base_balance_filled,
    +        );
    +        custodian::increase_user_available_balance<QuoteAsset>(
    +            &mut pool.quote_custodian,
    +            user,
    +            quote_balance_left,
    +        );
    +    } else {
    +        let base_balance = custodian::decrease_user_available_balance<BaseAsset>(
    +            &mut pool.base_custodian,
    +            account_cap,
    +            quantity,
    +        );
    +        let (base_balance_left, quote_balance_filled) = match_ask(
    +            pool,
    +            price,
    +            clock::timestamp_ms(clock),
    +            base_balance,
    +        );
    +
    +        base_quantity_filled = quantity - balance::value(&base_balance_left);
    +        quote_quantity_filled = balance::value("e_balance_filled);
    +
    +        custodian::increase_user_available_balance<BaseAsset>(
    +            &mut pool.base_custodian,
    +            user,
    +            base_balance_left,
    +        );
    +        custodian::increase_user_available_balance<QuoteAsset>(
    +            &mut pool.quote_custodian,
    +            user,
    +            quote_balance_filled,
    +        );
    +    };
    +
    +    let order_id;
    +    if (restriction == IMMEDIATE_OR_CANCEL) {
    +        return (base_quantity_filled, quote_quantity_filled, false, 0)
    +    };
    +    if (restriction == FILL_OR_KILL) {
    +        assert!(base_quantity_filled == quantity, EOrderCannotBeFullyFilled);
    +        return (base_quantity_filled, quote_quantity_filled, false, 0)
    +    };
    +    if (restriction == POST_OR_ABORT) {
    +        assert!(base_quantity_filled == 0, EOrderCannotBeFullyPassive);
    +        order_id = inject_limit_order(pool, price, quantity, is_bid, expire_timestamp, account_cap, ctx);
    +        return (base_quantity_filled, quote_quantity_filled, true, order_id)
    +    } else {
    +        assert!(restriction == NO_RESTRICTION, EInvalidRestriction);
    +        if (quantity > base_quantity_filled) {
    +            order_id = inject_limit_order(
    +                pool,
    +                price,
    +                quantity - base_quantity_filled,
    +                is_bid,
    +                expire_timestamp,
    +                account_cap,
    +                ctx
    +            );
    +            return (base_quantity_filled, quote_quantity_filled, true, order_id)
    +        };
    +        return (base_quantity_filled, quote_quantity_filled, false, 0)
    +    }
    +}
    +
    + + + +
    + + + +## Function `order_is_bid` + + + +
    fun order_is_bid(order_id: u64): bool
    +
    + + + +
    +Implementation + + +
    fun order_is_bid(order_id: u64): bool {
    +    return order_id < MIN_ASK_ORDER_ID
    +}
    +
    + + + +
    + + + +## Function `emit_order_canceled` + + + +
    fun emit_order_canceled<BaseAsset, QuoteAsset>(pool_id: object::ID, order: &clob::Order)
    +
    + + + +
    +Implementation + + +
    fun emit_order_canceled<BaseAsset, QuoteAsset>(
    +    pool_id: ID,
    +    order: &Order
    +) {
    +    event::emit(OrderCanceled<BaseAsset, QuoteAsset> {
    +        pool_id,
    +        order_id: order.order_id,
    +        is_bid: order.is_bid,
    +        owner: order.owner,
    +        base_asset_quantity_canceled: order.quantity,
    +        price: order.price
    +    })
    +}
    +
    + + + +
    + + + +## Function `emit_order_filled` + + + +
    fun emit_order_filled<BaseAsset, QuoteAsset>(pool_id: object::ID, order: &clob::Order, base_asset_quantity_filled: u64, taker_commission: u64, maker_rebates: u64)
    +
    + + + +
    +Implementation + + +
    fun emit_order_filled<BaseAsset, QuoteAsset>(
    +    pool_id: ID,
    +    order: &Order,
    +    base_asset_quantity_filled: u64,
    +    taker_commission: u64,
    +    maker_rebates: u64
    +) {
    +    event::emit(OrderFilledV2<BaseAsset, QuoteAsset> {
    +        pool_id,
    +        order_id: order.order_id,
    +        is_bid: order.is_bid,
    +        owner: order.owner,
    +        total_quantity: order.quantity,
    +        base_asset_quantity_filled,
    +        // order.quantity = base_asset_quantity_filled + base_asset_quantity_remaining
    +        // This guarantees that the subtraction will not underflow
    +        base_asset_quantity_remaining: order.quantity - base_asset_quantity_filled,
    +        price: order.price,
    +        taker_commission,
    +        maker_rebates
    +    })
    +}
    +
    + + + +
    + + + +## Function `cancel_order` + +Cancel and opening order. +Abort if order_id is invalid or if the order is not submitted by the transaction sender. + + +
    public fun cancel_order<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, order_id: u64, account_cap: &custodian::AccountCap)
    +
    + + + +
    +Implementation + + +
    public fun cancel_order<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    order_id: u64,
    +    account_cap: &AccountCap
    +) {
    +    // First check the highest bit of the order id to see whether it's bid or ask.
    +    // Then retrieve the price using the order id.
    +    // Using the price to retrieve the corresponding PriceLevel from the bids / asks Critbit Tree.
    +    // Retrieve and remove the order from open orders of the PriceLevel.
    +    let user = object::id(account_cap);
    +    assert!(contains(&pool.usr_open_orders, user), EInvalidUser);
    +    let usr_open_orders = borrow_mut(&mut pool.usr_open_orders, user);
    +    assert!(linked_table::contains(usr_open_orders, order_id), EInvalidOrderId);
    +    let tick_price = *linked_table::borrow(usr_open_orders, order_id);
    +    let is_bid = order_is_bid(order_id);
    +    let (tick_exists, tick_index) = find_leaf(
    +        if (is_bid) { &pool.bids } else { &pool.asks },
    +        tick_price);
    +    assert!(tick_exists, EInvalidOrderId);
    +    let order = remove_order(
    +        if (is_bid) { &mut pool.bids } else { &mut pool.asks },
    +        usr_open_orders,
    +        tick_index,
    +        order_id,
    +        user
    +    );
    +    if (is_bid) {
    +        let balance_locked = clob_math::mul(order.quantity, order.price);
    +        custodian::unlock_balance(&mut pool.quote_custodian, user, balance_locked);
    +    } else {
    +        custodian::unlock_balance(&mut pool.base_custodian, user, order.quantity);
    +    };
    +    emit_order_canceled<BaseAsset, QuoteAsset>(*object::uid_as_inner(&pool.id), &order);
    +}
    +
    + + + +
    + + + +## Function `remove_order` + + + +
    fun remove_order(open_orders: &mut critbit::CritbitTree<clob::TickLevel>, usr_open_orders: &mut linked_table::LinkedTable<u64, u64>, tick_index: u64, order_id: u64, user: object::ID): clob::Order
    +
    + + + +
    +Implementation + + +
    fun remove_order(
    +    open_orders: &mut CritbitTree<TickLevel>,
    +    usr_open_orders: &mut LinkedTable<u64, u64>,
    +    tick_index: u64,
    +    order_id: u64,
    +    user: ID,
    +): Order {
    +    linked_table::remove(usr_open_orders, order_id);
    +    let tick_level = borrow_leaf_by_index(open_orders, tick_index);
    +    assert!(linked_table::contains(&tick_level.open_orders, order_id), EInvalidOrderId);
    +    let mut_tick_level = borrow_mut_leaf_by_index(open_orders, tick_index);
    +    let order = linked_table::remove(&mut mut_tick_level.open_orders, order_id);
    +    assert!(order.owner == user, EUnauthorizedCancel);
    +    if (linked_table::is_empty(&mut_tick_level.open_orders)) {
    +        destroy_empty_level(remove_leaf_by_index(open_orders, tick_index));
    +    };
    +    order
    +}
    +
    + + + +
    + + + +## Function `cancel_all_orders` + + + +
    public fun cancel_all_orders<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian::AccountCap)
    +
    + + + +
    +Implementation + + +
    public fun cancel_all_orders<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    account_cap: &AccountCap
    +) {
    +    let pool_id = *object::uid_as_inner(&pool.id);
    +    let user = object::id(account_cap);
    +    assert!(contains(&pool.usr_open_orders, user), EInvalidUser);
    +    let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, user);
    +    while (!linked_table::is_empty(usr_open_order_ids)) {
    +        let order_id = *option::borrow(linked_table::back(usr_open_order_ids));
    +        let order_price = *linked_table::borrow(usr_open_order_ids, order_id);
    +        let is_bid = order_is_bid(order_id);
    +        let open_orders =
    +            if (is_bid) { &mut pool.bids }
    +            else { &mut pool.asks };
    +        let (_, tick_index) = critbit::find_leaf(open_orders, order_price);
    +        let order = remove_order(
    +            open_orders,
    +            usr_open_order_ids,
    +            tick_index,
    +            order_id,
    +            user
    +        );
    +        if (is_bid) {
    +            let balance_locked = clob_math::mul(order.quantity, order.price);
    +            custodian::unlock_balance(&mut pool.quote_custodian, user, balance_locked);
    +        } else {
    +            custodian::unlock_balance(&mut pool.base_custodian, user, order.quantity);
    +        };
    +        emit_order_canceled<BaseAsset, QuoteAsset>(pool_id, &order);
    +    };
    +}
    +
    + + + +
    + + + +## Function `batch_cancel_order` + +Batch cancel limit orders to save gas cost. +Abort if any of the order_ids are not submitted by the sender. +Skip any order_id that is invalid. +Note that this function can reduce gas cost even further if caller has multiple orders at the same price level, +and if orders with the same price are grouped together in the vector. +For example, if we have the following order_id to price mapping, {0: 100., 1: 200., 2: 100., 3: 200.}. +Grouping order_ids like [0, 2, 1, 3] would make it the most gas efficient. + + +
    public fun batch_cancel_order<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, order_ids: vector<u64>, account_cap: &custodian::AccountCap)
    +
    + + + +
    +Implementation + + +
    public fun batch_cancel_order<BaseAsset, QuoteAsset>(
    +    pool: &mut Pool<BaseAsset, QuoteAsset>,
    +    order_ids: vector<u64>,
    +    account_cap: &AccountCap
    +) {
    +    let pool_id = *object::uid_as_inner(&pool.id);
    +    // First group the order ids according to price level,
    +    // so that we don't have to retrieve the PriceLevel multiple times if there are orders at the same price level.
    +    // Iterate over each price level, retrieve the corresponding PriceLevel.
    +    // Iterate over the order ids that need to be canceled at that price level,
    +    // retrieve and remove the order from open orders of the PriceLevel.
    +    let user = object::id(account_cap);
    +    assert!(contains(&pool.usr_open_orders, user), 0);
    +    let mut tick_index: u64 = 0;
    +    let mut tick_price: u64 = 0;
    +    let n_order = vector::length(&order_ids);
    +    let mut i_order = 0;
    +    let usr_open_orders = borrow_mut(&mut pool.usr_open_orders, user);
    +    while (i_order < n_order) {
    +        let order_id = *vector::borrow(&order_ids, i_order);
    +        assert!(linked_table::contains(usr_open_orders, order_id), EInvalidOrderId);
    +        let new_tick_price = *linked_table::borrow(usr_open_orders, order_id);
    +        let is_bid = order_is_bid(order_id);
    +        if (new_tick_price != tick_price) {
    +            tick_price = new_tick_price;
    +            let (tick_exists, new_tick_index) = find_leaf(
    +                if (is_bid) { &pool.bids } else { &pool.asks },
    +                tick_price
    +            );
    +            assert!(tick_exists, EInvalidTickPrice);
    +            tick_index = new_tick_index;
    +        };
    +        let order = remove_order(
    +            if (is_bid) { &mut pool.bids } else { &mut pool.asks },
    +            usr_open_orders,
    +            tick_index,
    +            order_id,
    +            user
    +        );
    +        if (is_bid) {
    +            let balance_locked = clob_math::mul(order.quantity, order.price);
    +            custodian::unlock_balance(&mut pool.quote_custodian, user, balance_locked);
    +        } else {
    +            custodian::unlock_balance(&mut pool.base_custodian, user, order.quantity);
    +        };
    +        emit_order_canceled<BaseAsset, QuoteAsset>(pool_id, &order);
    +        i_order = i_order + 1;
    +    }
    +}
    +
    + + + +
    + + + +## Function `list_open_orders` + + + +
    public fun list_open_orders<BaseAsset, QuoteAsset>(pool: &clob::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian::AccountCap): vector<clob::Order>
    +
    + + + +
    +Implementation + + +
    public fun list_open_orders<BaseAsset, QuoteAsset>(
    +    pool: &Pool<BaseAsset, QuoteAsset>,
    +    account_cap: &AccountCap
    +): vector<Order> {
    +    let user = object::id(account_cap);
    +    let usr_open_order_ids = table::borrow(&pool.usr_open_orders, user);
    +    let mut open_orders = vector::empty<Order>();
    +    let mut order_id = linked_table::front(usr_open_order_ids);
    +    while (!option::is_none(order_id)) {
    +        let order_price = *linked_table::borrow(usr_open_order_ids, *option::borrow(order_id));
    +        let tick_level =
    +            if (order_is_bid(*option::borrow(order_id))) borrow_leaf_by_key(&pool.bids, order_price)
    +            else borrow_leaf_by_key(&pool.asks, order_price);
    +        let order = linked_table::borrow(&tick_level.open_orders, *option::borrow(order_id));
    +        vector::push_back(&mut open_orders, Order {
    +            order_id: order.order_id,
    +            price: order.price,
    +            quantity: order.quantity,
    +            is_bid: order.is_bid,
    +            owner: order.owner,
    +            expire_timestamp: order.expire_timestamp
    +        });
    +        order_id = linked_table::next(usr_open_order_ids, *option::borrow(order_id));
    +    };
    +    open_orders
    +}
    +
    + + + +
    + + + +## Function `account_balance` + +query user balance inside custodian + + +
    public fun account_balance<BaseAsset, QuoteAsset>(pool: &clob::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian::AccountCap): (u64, u64, u64, u64)
    +
    + + + +
    +Implementation + + +
    public fun account_balance<BaseAsset, QuoteAsset>(
    +    pool: &Pool<BaseAsset, QuoteAsset>,
    +    account_cap: &AccountCap
    +): (u64, u64, u64, u64) {
    +    let user = object::id(account_cap);
    +    let (base_avail, base_locked) = custodian::account_balance(&pool.base_custodian, user);
    +    let (quote_avail, quote_locked) = custodian::account_balance(&pool.quote_custodian, user);
    +    (base_avail, base_locked, quote_avail, quote_locked)
    +}
    +
    + + + +
    + + + +## Function `get_market_price` + +Query the market price of order book +returns (best_bid_price, best_ask_price) + + +
    public fun get_market_price<BaseAsset, QuoteAsset>(pool: &clob::Pool<BaseAsset, QuoteAsset>): (u64, u64)
    +
    + + + +
    +Implementation + + +
    public fun get_market_price<BaseAsset, QuoteAsset>(
    +    pool: &Pool<BaseAsset, QuoteAsset>
    +): (u64, u64){
    +    let (bid_price, _) = critbit::max_leaf(&pool.bids);
    +    let (ask_price, _) = critbit::min_leaf(&pool.asks);
    +    return (bid_price, ask_price)
    +}
    +
    + + + +
    + + + +## Function `get_level2_book_status_bid_side` + +Enter a price range and return the level2 order depth of all valid prices within this price range in bid side +returns two vectors of u64 +The previous is a list of all valid prices +The latter is the corresponding depth list + + +
    public fun get_level2_book_status_bid_side<BaseAsset, QuoteAsset>(pool: &clob::Pool<BaseAsset, QuoteAsset>, price_low: u64, price_high: u64, clock: &clock::Clock): (vector<u64>, vector<u64>)
    +
    + + + +
    +Implementation + + +
    public fun get_level2_book_status_bid_side<BaseAsset, QuoteAsset>(
    +    pool: &Pool<BaseAsset, QuoteAsset>,
    +    mut price_low: u64,
    +    mut price_high: u64,
    +    clock: &Clock
    +): (vector<u64>, vector<u64>) {
    +    let (price_low_, _) = critbit::min_leaf(&pool.bids);
    +    if (price_low < price_low_) price_low = price_low_;
    +    let (price_high_, _) = critbit::max_leaf(&pool.bids);
    +    if (price_high > price_high_) price_high = price_high_;
    +    price_low = critbit::find_closest_key(&pool.bids, price_low);
    +    price_high = critbit::find_closest_key(&pool.bids, price_high);
    +    let mut price_vec = vector::empty<u64>();
    +    let mut depth_vec = vector::empty<u64>();
    +    if (price_low == 0) { return (price_vec, depth_vec) };
    +    while (price_low <= price_high) {
    +        let depth = get_level2_book_status(
    +            &pool.bids,
    +            price_low,
    +            clock::timestamp_ms(clock)
    +        );
    +        vector::push_back(&mut price_vec, price_low);
    +        vector::push_back(&mut depth_vec, depth);
    +        let (next_price, _) = critbit::next_leaf(&pool.bids, price_low);
    +        if (next_price == 0) { break }
    +        else { price_low = next_price };
    +    };
    +    (price_vec, depth_vec)
    +}
    +
    + + + +
    + + + +## Function `get_level2_book_status_ask_side` + +Enter a price range and return the level2 order depth of all valid prices within this price range in ask side +returns two vectors of u64 +The previous is a list of all valid prices +The latter is the corresponding depth list + + +
    public fun get_level2_book_status_ask_side<BaseAsset, QuoteAsset>(pool: &clob::Pool<BaseAsset, QuoteAsset>, price_low: u64, price_high: u64, clock: &clock::Clock): (vector<u64>, vector<u64>)
    +
    + + + +
    +Implementation + + +
    public fun get_level2_book_status_ask_side<BaseAsset, QuoteAsset>(
    +    pool: &Pool<BaseAsset, QuoteAsset>,
    +    mut price_low: u64,
    +    mut price_high: u64,
    +    clock: &Clock
    +): (vector<u64>, vector<u64>) {
    +    let (price_low_, _) = critbit::min_leaf(&pool.asks);
    +    if (price_low < price_low_) price_low = price_low_;
    +    let (price_high_, _) = critbit::max_leaf(&pool.asks);
    +    if (price_high > price_high_) price_high = price_high_;
    +    price_low = critbit::find_closest_key(&pool.asks, price_low);
    +    price_high = critbit::find_closest_key(&pool.asks, price_high);
    +    let mut price_vec = vector::empty<u64>();
    +    let mut depth_vec = vector::empty<u64>();
    +    if (price_low == 0) { return (price_vec, depth_vec) };
    +    while (price_low <= price_high) {
    +        let depth = get_level2_book_status(
    +            &pool.asks,
    +            price_low,
    +            clock::timestamp_ms(clock)
    +        );
    +        vector::push_back(&mut price_vec, price_low);
    +        vector::push_back(&mut depth_vec, depth);
    +        let (next_price, _) = critbit::next_leaf(&pool.asks, price_low);
    +        if (next_price == 0) { break }
    +        else { price_low = next_price };
    +    };
    +    (price_vec, depth_vec)
    +}
    +
    + + + +
    + + + +## Function `get_level2_book_status` + +internal func to retrive single depth of a tick price + + +
    fun get_level2_book_status(open_orders: &critbit::CritbitTree<clob::TickLevel>, price: u64, time_stamp: u64): u64
    +
    + + + +
    +Implementation + + +
    fun get_level2_book_status(
    +    open_orders: &CritbitTree<TickLevel>,
    +    price: u64,
    +    time_stamp: u64
    +): u64 {
    +    let tick_level = critbit::borrow_leaf_by_key(open_orders, price);
    +    let tick_open_orders = &tick_level.open_orders;
    +    let mut depth = 0;
    +    let mut order_id = linked_table::front(tick_open_orders);
    +    let mut order: &Order;
    +    while (!option::is_none(order_id)) {
    +        order = linked_table::borrow(tick_open_orders, *option::borrow(order_id));
    +        if (order.expire_timestamp > time_stamp) depth = depth + order.quantity;
    +        order_id = linked_table::next(tick_open_orders, *option::borrow(order_id));
    +    };
    +    depth
    +}
    +
    + + + +
    + + + +## Function `get_order_status` + + + +
    public fun get_order_status<BaseAsset, QuoteAsset>(pool: &clob::Pool<BaseAsset, QuoteAsset>, order_id: u64, account_cap: &custodian::AccountCap): &clob::Order
    +
    + + + +
    +Implementation + + +
    public fun get_order_status<BaseAsset, QuoteAsset>(
    +    pool: &Pool<BaseAsset, QuoteAsset>,
    +    order_id: u64,
    +    account_cap: &AccountCap
    +): &Order {
    +    let user = object::id(account_cap);
    +    assert!(table::contains(&pool.usr_open_orders, user), EInvalidUser);
    +    let usr_open_order_ids = table::borrow(&pool.usr_open_orders, user);
    +    assert!(linked_table::contains(usr_open_order_ids, order_id), EInvalidOrderId);
    +    let order_price = *linked_table::borrow(usr_open_order_ids, order_id);
    +    let open_orders =
    +        if (order_id < MIN_ASK_ORDER_ID) { &pool.bids }
    +        else { &pool.asks };
    +    let tick_level = critbit::borrow_leaf_by_key(open_orders, order_price);
    +    let tick_open_orders = &tick_level.open_orders;
    +    let order = linked_table::borrow(tick_open_orders, order_id);
    +    order
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/deepbook/clob_v2.md b/crates/iota-framework/docs/deepbook/clob_v2.md similarity index 77% rename from crates/sui-framework/docs/deepbook/clob_v2.md rename to crates/iota-framework/docs/deepbook/clob_v2.md index 3092a29e94a..c690d12ea97 100644 --- a/crates/sui-framework/docs/deepbook/clob_v2.md +++ b/crates/iota-framework/docs/deepbook/clob_v2.md @@ -88,16 +88,16 @@ title: Module `0xdee9::clob_v2`
    use 0x1::option;
     use 0x1::type_name;
     use 0x1::vector;
    -use 0x2::balance;
    -use 0x2::clock;
    -use 0x2::coin;
    -use 0x2::event;
    -use 0x2::linked_table;
    -use 0x2::object;
    -use 0x2::sui;
    -use 0x2::table;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    +use 0x2::balance;
    +use 0x2::clock;
    +use 0x2::coin;
    +use 0x2::event;
    +use 0x2::iota;
    +use 0x2::linked_table;
    +use 0x2::object;
    +use 0x2::table;
    +use 0x2::transfer;
    +use 0x2::tx_context;
     use 0xdee9::critbit;
     use 0xdee9::custodian_v2;
     use 0xdee9::math;
    @@ -123,7 +123,7 @@ Emitted when a new pool is created
     
     
    -pool_id: object::ID +pool_id: object::ID
    object ID of the newly created pool @@ -187,7 +187,7 @@ Emitted when a maker order is injected into the order book.
    -pool_id: object::ID +pool_id: object::ID
    object ID of the pool the order was placed on @@ -263,7 +263,7 @@ Emitted when a maker order is canceled.
    -pool_id: object::ID +pool_id: object::ID
    object ID of the pool the order was placed on @@ -397,7 +397,7 @@ Emitted when batch of orders are canceled.
    -pool_id: object::ID +pool_id: object::ID
    object ID of the pool the order was placed on @@ -431,7 +431,7 @@ Emitted only when a maker order is filled.
    -pool_id: object::ID +pool_id: object::ID
    object ID of the pool the order was placed on @@ -531,7 +531,7 @@ Emitted when user deposit asset to custodian
    -pool_id: object::ID +pool_id: object::ID
    object id of the pool that asset deposit to @@ -571,7 +571,7 @@ Emitted when user withdraw asset from custodian
    -pool_id: object::ID +pool_id: object::ID
    object id of the pool that asset withdraw from @@ -611,7 +611,7 @@ Returned as metadata only when a maker order is filled from place order function
    -pool_id: object::ID +pool_id: object::ID
    object ID of the pool the order was placed on @@ -767,7 +767,7 @@ Returned as metadata only when a maker order is filled from place order function
    -open_orders: linked_table::LinkedTable<u64, clob_v2::Order> +open_orders: linked_table::LinkedTable<u64, clob_v2::Order>
    @@ -794,7 +794,7 @@ Returned as metadata only when a maker order is filled from place order function
    -id: object::UID +id: object::UID
    @@ -824,7 +824,7 @@ Returned as metadata only when a maker order is filled from place order function
    -usr_open_orders: table::Table<address, linked_table::LinkedTable<u64, u64>> +usr_open_orders: table::Table<address, linked_table::LinkedTable<u64, u64>>
    @@ -866,19 +866,19 @@ Returned as metadata only when a maker order is filled from place order function
    -creation_fee: balance::Balance<sui::SUI> +creation_fee: balance::Balance<iota::IOTA>
    -base_asset_trading_fees: balance::Balance<BaseAsset> +base_asset_trading_fees: balance::Balance<BaseAsset>
    -quote_asset_trading_fees: balance::Balance<QuoteAsset> +quote_asset_trading_fees: balance::Balance<QuoteAsset>
    @@ -920,7 +920,7 @@ do not have this capability:
    -id: object::UID +id: object::UID
    @@ -1250,7 +1250,7 @@ Accessor functions pool: &Pool<BaseAsset, QuoteAsset>, owner: address ): bool { - table::contains(&pool.usr_open_orders, owner) + table::contains(&pool.usr_open_orders, owner) }
    @@ -1264,7 +1264,7 @@ Accessor functions -
    public fun usr_open_orders_for_address<BaseAsset, QuoteAsset>(pool: &clob_v2::Pool<BaseAsset, QuoteAsset>, owner: address): &linked_table::LinkedTable<u64, u64>
    +
    public fun usr_open_orders_for_address<BaseAsset, QuoteAsset>(pool: &clob_v2::Pool<BaseAsset, QuoteAsset>, owner: address): &linked_table::LinkedTable<u64, u64>
     
    @@ -1277,7 +1277,7 @@ Accessor functions pool: &Pool<BaseAsset, QuoteAsset>, owner: address ): &LinkedTable<u64, u64> { - table::borrow(&pool.usr_open_orders, owner) + table::borrow(&pool.usr_open_orders, owner) }
    @@ -1291,7 +1291,7 @@ Accessor functions -
    public fun usr_open_orders<BaseAsset, QuoteAsset>(pool: &clob_v2::Pool<BaseAsset, QuoteAsset>): &table::Table<address, linked_table::LinkedTable<u64, u64>>
    +
    public fun usr_open_orders<BaseAsset, QuoteAsset>(pool: &clob_v2::Pool<BaseAsset, QuoteAsset>): &table::Table<address, linked_table::LinkedTable<u64, u64>>
     
    @@ -1318,7 +1318,7 @@ Accessor functions Function to withdraw fees created from a pool -
    public fun withdraw_fees<BaseAsset, QuoteAsset>(pool_owner_cap: &clob_v2::PoolOwnerCap, pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, ctx: &mut tx_context::TxContext): coin::Coin<QuoteAsset>
    +
    public fun withdraw_fees<BaseAsset, QuoteAsset>(pool_owner_cap: &clob_v2::PoolOwnerCap, pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, ctx: &mut tx_context::TxContext): coin::Coin<QuoteAsset>
     
    @@ -1332,10 +1332,10 @@ Function to withdraw fees created from a pool pool: &mut Pool<BaseAsset, QuoteAsset>, ctx: &mut TxContext, ): Coin<QuoteAsset> { - assert!(pool_owner_cap.owner == object::uid_to_address(&pool.id), EIncorrectPoolOwner); + assert!(pool_owner_cap.owner == object::uid_to_address(&pool.id), EIncorrectPoolOwner); let quantity = quote_asset_trading_fees_value(pool); - let to_withdraw = balance::split(&mut pool.quote_asset_trading_fees, quantity); - coin::from_balance(to_withdraw, ctx) + let to_withdraw = balance::split(&mut pool.quote_asset_trading_fees, quantity); + coin::from_balance(to_withdraw, ctx) }
    @@ -1361,7 +1361,7 @@ Destroy the given pool_owner_cap object
    public fun delete_pool_owner_cap(pool_owner_cap: PoolOwnerCap) {
         let PoolOwnerCap { id, owner: _ } = pool_owner_cap;
    -    object::delete(id)
    +    object::delete(id)
     }
     
    @@ -1390,7 +1390,7 @@ Destroy the given pool_owner_cap object open_orders: orders, } = level; - linked_table::destroy_empty(orders); + linked_table::destroy_empty(orders); }
    @@ -1404,7 +1404,7 @@ Destroy the given pool_owner_cap object -
    public fun create_account(ctx: &mut tx_context::TxContext): custodian_v2::AccountCap
    +
    public fun create_account(ctx: &mut tx_context::TxContext): custodian_v2::AccountCap
     
    @@ -1428,7 +1428,7 @@ Destroy the given pool_owner_cap object -
    fun create_pool_<BaseAsset, QuoteAsset>(taker_fee_rate: u64, maker_rebate_rate: u64, tick_size: u64, lot_size: u64, creation_fee: balance::Balance<sui::SUI>, ctx: &mut tx_context::TxContext)
    +
    fun create_pool_<BaseAsset, QuoteAsset>(taker_fee_rate: u64, maker_rebate_rate: u64, tick_size: u64, lot_size: u64, creation_fee: balance::Balance<iota::IOTA>, ctx: &mut tx_context::TxContext)
     
    @@ -1442,7 +1442,7 @@ Destroy the given pool_owner_cap object maker_rebate_rate: u64, tick_size: u64, lot_size: u64, - creation_fee: Balance<SUI>, + creation_fee: Balance<IOTA>, ctx: &mut TxContext, ) { let (pool, pool_owner_cap) = create_pool_with_return_<BaseAsset, QuoteAsset>( @@ -1454,8 +1454,8 @@ Destroy the given pool_owner_cap object ctx ); - transfer::public_transfer(pool_owner_cap, tx_context::sender(ctx)); - transfer::share_object(pool); + transfer::public_transfer(pool_owner_cap, tx_context::sender(ctx)); + transfer::share_object(pool); }
    @@ -1469,7 +1469,7 @@ Destroy the given pool_owner_cap object -
    public fun create_pool<BaseAsset, QuoteAsset>(tick_size: u64, lot_size: u64, creation_fee: coin::Coin<sui::SUI>, ctx: &mut tx_context::TxContext)
    +
    public fun create_pool<BaseAsset, QuoteAsset>(tick_size: u64, lot_size: u64, creation_fee: coin::Coin<iota::IOTA>, ctx: &mut tx_context::TxContext)
     
    @@ -1481,7 +1481,7 @@ Destroy the given pool_owner_cap object
    public fun create_pool<BaseAsset, QuoteAsset>(
         tick_size: u64,
         lot_size: u64,
    -    creation_fee: Coin<SUI>,
    +    creation_fee: Coin<IOTA>,
         ctx: &mut TxContext,
     ) {
         create_customized_pool<BaseAsset, QuoteAsset>(
    @@ -1508,7 +1508,7 @@ The taker_fee_rate should be greater than or equal to the maker_rebate_rate, and
     Taker_fee_rate of 0.25% should be 2_500_000 for example
     
     
    -
    public fun create_customized_pool<BaseAsset, QuoteAsset>(tick_size: u64, lot_size: u64, taker_fee_rate: u64, maker_rebate_rate: u64, creation_fee: coin::Coin<sui::SUI>, ctx: &mut tx_context::TxContext)
    +
    public fun create_customized_pool<BaseAsset, QuoteAsset>(tick_size: u64, lot_size: u64, taker_fee_rate: u64, maker_rebate_rate: u64, creation_fee: coin::Coin<iota::IOTA>, ctx: &mut tx_context::TxContext)
     
    @@ -1522,7 +1522,7 @@ Taker_fee_rate of 0.25% should be 2_500_000 for example lot_size: u64, taker_fee_rate: u64, maker_rebate_rate: u64, - creation_fee: Coin<SUI>, + creation_fee: Coin<IOTA>, ctx: &mut TxContext, ) { create_pool_<BaseAsset, QuoteAsset>( @@ -1530,7 +1530,7 @@ Taker_fee_rate of 0.25% should be 2_500_000 for example maker_rebate_rate, tick_size, lot_size, - coin::into_balance(creation_fee), + coin::into_balance(creation_fee), ctx ) } @@ -1547,7 +1547,7 @@ Taker_fee_rate of 0.25% should be 2_500_000 for example Helper function that all the create pools now call to create pools. -
    fun create_pool_with_return_<BaseAsset, QuoteAsset>(taker_fee_rate: u64, maker_rebate_rate: u64, tick_size: u64, lot_size: u64, creation_fee: balance::Balance<sui::SUI>, ctx: &mut tx_context::TxContext): (clob_v2::Pool<BaseAsset, QuoteAsset>, clob_v2::PoolOwnerCap)
    +
    fun create_pool_with_return_<BaseAsset, QuoteAsset>(taker_fee_rate: u64, maker_rebate_rate: u64, tick_size: u64, lot_size: u64, creation_fee: balance::Balance<iota::IOTA>, ctx: &mut tx_context::TxContext): (clob_v2::Pool<BaseAsset, QuoteAsset>, clob_v2::PoolOwnerCap)
     
    @@ -1561,10 +1561,10 @@ Helper function that all the create pools now call to create pools. maker_rebate_rate: u64, tick_size: u64, lot_size: u64, - creation_fee: Balance<SUI>, + creation_fee: Balance<IOTA>, ctx: &mut TxContext, ): (Pool<BaseAsset, QuoteAsset>, PoolOwnerCap) { - assert!(balance::value(&creation_fee) == FEE_AMOUNT_FOR_CREATE_POOL, EInvalidFee); + assert!(balance::value(&creation_fee) == FEE_AMOUNT_FOR_CREATE_POOL, EInvalidFee); let base_type_name = type_name::get<BaseAsset>(); let quote_type_name = type_name::get<QuoteAsset>(); @@ -1573,15 +1573,15 @@ Helper function that all the create pools now call to create pools. assert!(base_type_name != quote_type_name, EInvalidPair); assert!(taker_fee_rate >= maker_rebate_rate, EInvalidFeeRateRebateRate); - let pool_uid = object::new(ctx); - let pool_id = *object::uid_as_inner(&pool_uid); + let pool_uid = object::new(ctx); + let pool_id = *object::uid_as_inner(&pool_uid); // Creates the capability to mark a pool owner. - let id = object::new(ctx); - let owner = object::uid_to_address(&pool_uid); + let id = object::new(ctx); + let owner = object::uid_to_address(&pool_uid); let pool_owner_cap = PoolOwnerCap { id, owner }; - event::emit(PoolCreated { + event::emit(PoolCreated { pool_id, base_asset: base_type_name, quote_asset: quote_type_name, @@ -1596,7 +1596,7 @@ Helper function that all the create pools now call to create pools. asks: critbit::new(ctx), next_bid_order_id: MIN_BID_ORDER_ID, next_ask_order_id: MIN_ASK_ORDER_ID, - usr_open_orders: table::new(ctx), + usr_open_orders: table::new(ctx), taker_fee_rate, maker_rebate_rate, tick_size, @@ -1604,8 +1604,8 @@ Helper function that all the create pools now call to create pools. base_custodian: custodian::new<BaseAsset>(ctx), quote_custodian: custodian::new<QuoteAsset>(ctx), creation_fee, - base_asset_trading_fees: balance::zero(), - quote_asset_trading_fees: balance::zero(), + base_asset_trading_fees: balance::zero(), + quote_asset_trading_fees: balance::zero(), }, pool_owner_cap) }
    @@ -1621,7 +1621,7 @@ Helper function that all the create pools now call to create pools. Function for creating an external pool. This API can be used to wrap deepbook pools into other objects. -
    public fun create_pool_with_return<BaseAsset, QuoteAsset>(tick_size: u64, lot_size: u64, creation_fee: coin::Coin<sui::SUI>, ctx: &mut tx_context::TxContext): clob_v2::Pool<BaseAsset, QuoteAsset>
    +
    public fun create_pool_with_return<BaseAsset, QuoteAsset>(tick_size: u64, lot_size: u64, creation_fee: coin::Coin<iota::IOTA>, ctx: &mut tx_context::TxContext): clob_v2::Pool<BaseAsset, QuoteAsset>
     
    @@ -1633,7 +1633,7 @@ Function for creating an external pool. This API can be used to wrap deepbook po
    public fun create_pool_with_return<BaseAsset, QuoteAsset>(
         tick_size: u64,
         lot_size: u64,
    -    creation_fee: Coin<SUI>,
    +    creation_fee: Coin<IOTA>,
         ctx: &mut TxContext,
     ): Pool<BaseAsset, QuoteAsset> {
         create_customized_pool_with_return<BaseAsset, QuoteAsset>(
    @@ -1660,7 +1660,7 @@ The taker_fee_rate should be greater than or equal to the maker_rebate_rate, and
     Taker_fee_rate of 0.25% should be 2_500_000 for example
     
     
    -
    public fun create_customized_pool_with_return<BaseAsset, QuoteAsset>(tick_size: u64, lot_size: u64, taker_fee_rate: u64, maker_rebate_rate: u64, creation_fee: coin::Coin<sui::SUI>, ctx: &mut tx_context::TxContext): clob_v2::Pool<BaseAsset, QuoteAsset>
    +
    public fun create_customized_pool_with_return<BaseAsset, QuoteAsset>(tick_size: u64, lot_size: u64, taker_fee_rate: u64, maker_rebate_rate: u64, creation_fee: coin::Coin<iota::IOTA>, ctx: &mut tx_context::TxContext): clob_v2::Pool<BaseAsset, QuoteAsset>
     
    @@ -1674,7 +1674,7 @@ Taker_fee_rate of 0.25% should be 2_500_000 for example lot_size: u64, taker_fee_rate: u64, maker_rebate_rate: u64, - creation_fee: Coin<SUI>, + creation_fee: Coin<IOTA>, ctx: &mut TxContext, ) : Pool<BaseAsset, QuoteAsset> { let (pool, pool_owner_cap) = create_pool_with_return_<BaseAsset, QuoteAsset>( @@ -1682,10 +1682,10 @@ Taker_fee_rate of 0.25% should be 2_500_000 for example maker_rebate_rate, tick_size, lot_size, - coin::into_balance(creation_fee), + coin::into_balance(creation_fee), ctx ); - transfer::public_transfer(pool_owner_cap, tx_context::sender(ctx)); + transfer::public_transfer(pool_owner_cap, tx_context::sender(ctx)); pool }
    @@ -1703,7 +1703,7 @@ If a user wants to create a pool and then destroy/lock the pool_owner_cap one ca so with this function. -
    public fun create_customized_pool_v2<BaseAsset, QuoteAsset>(tick_size: u64, lot_size: u64, taker_fee_rate: u64, maker_rebate_rate: u64, creation_fee: coin::Coin<sui::SUI>, ctx: &mut tx_context::TxContext): (clob_v2::Pool<BaseAsset, QuoteAsset>, clob_v2::PoolOwnerCap)
    +
    public fun create_customized_pool_v2<BaseAsset, QuoteAsset>(tick_size: u64, lot_size: u64, taker_fee_rate: u64, maker_rebate_rate: u64, creation_fee: coin::Coin<iota::IOTA>, ctx: &mut tx_context::TxContext): (clob_v2::Pool<BaseAsset, QuoteAsset>, clob_v2::PoolOwnerCap)
     
    @@ -1717,7 +1717,7 @@ so with this function. lot_size: u64, taker_fee_rate: u64, maker_rebate_rate: u64, - creation_fee: Coin<SUI>, + creation_fee: Coin<IOTA>, ctx: &mut TxContext, ) : (Pool<BaseAsset, QuoteAsset>, PoolOwnerCap) { create_pool_with_return_<BaseAsset, QuoteAsset>( @@ -1725,7 +1725,7 @@ so with this function. maker_rebate_rate, tick_size, lot_size, - coin::into_balance(creation_fee), + coin::into_balance(creation_fee), ctx ) } @@ -1741,7 +1741,7 @@ so with this function. -
    public fun deposit_base<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, coin: coin::Coin<BaseAsset>, account_cap: &custodian_v2::AccountCap)
    +
    public fun deposit_base<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, coin: coin::Coin<BaseAsset>, account_cap: &custodian_v2::AccountCap)
     
    @@ -1752,18 +1752,18 @@ so with this function.
    public fun deposit_base<BaseAsset, QuoteAsset>(
         pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    coin: Coin<BaseAsset>,
    +    coin: Coin<BaseAsset>,
         account_cap: &AccountCap
     ) {
    -    let quantity = coin::value(&coin);
    +    let quantity = coin::value(&coin);
         assert!(quantity != 0, EInsufficientBaseCoin);
         custodian::increase_user_available_balance(
             &mut pool.base_custodian,
             account_owner(account_cap),
    -        coin::into_balance(coin)
    +        coin::into_balance(coin)
         );
    -    event::emit(DepositAsset<BaseAsset>{
    -        pool_id: *object::uid_as_inner(&pool.id),
    +    event::emit(DepositAsset<BaseAsset>{
    +        pool_id: *object::uid_as_inner(&pool.id),
             quantity,
             owner: account_owner(account_cap)
         })
    @@ -1780,7 +1780,7 @@ so with this function.
     
     
     
    -
    public fun deposit_quote<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, coin: coin::Coin<QuoteAsset>, account_cap: &custodian_v2::AccountCap)
    +
    public fun deposit_quote<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, coin: coin::Coin<QuoteAsset>, account_cap: &custodian_v2::AccountCap)
     
    @@ -1791,18 +1791,18 @@ so with this function.
    public fun deposit_quote<BaseAsset, QuoteAsset>(
         pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    coin: Coin<QuoteAsset>,
    +    coin: Coin<QuoteAsset>,
         account_cap: &AccountCap
     ) {
    -    let quantity = coin::value(&coin);
    +    let quantity = coin::value(&coin);
         assert!(quantity != 0, EInsufficientQuoteCoin);
         custodian::increase_user_available_balance(
             &mut pool.quote_custodian,
             account_owner(account_cap),
    -        coin::into_balance(coin)
    +        coin::into_balance(coin)
         );
    -    event::emit(DepositAsset<QuoteAsset>{
    -        pool_id: *object::uid_as_inner(&pool.id),
    +    event::emit(DepositAsset<QuoteAsset>{
    +        pool_id: *object::uid_as_inner(&pool.id),
             quantity,
             owner: account_owner(account_cap)
         })
    @@ -1819,7 +1819,7 @@ so with this function.
     
     
     
    -
    public fun withdraw_base<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, quantity: u64, account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): coin::Coin<BaseAsset>
    +
    public fun withdraw_base<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, quantity: u64, account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): coin::Coin<BaseAsset>
     
    @@ -1835,8 +1835,8 @@ so with this function. ctx: &mut TxContext ): Coin<BaseAsset> { assert!(quantity > 0, EInvalidQuantity); - event::emit(WithdrawAsset<BaseAsset>{ - pool_id: *object::uid_as_inner(&pool.id), + event::emit(WithdrawAsset<BaseAsset>{ + pool_id: *object::uid_as_inner(&pool.id), quantity, owner: account_owner(account_cap) }); @@ -1854,7 +1854,7 @@ so with this function. -
    public fun withdraw_quote<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, quantity: u64, account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): coin::Coin<QuoteAsset>
    +
    public fun withdraw_quote<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, quantity: u64, account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): coin::Coin<QuoteAsset>
     
    @@ -1870,8 +1870,8 @@ so with this function. ctx: &mut TxContext ): Coin<QuoteAsset> { assert!(quantity > 0, EInvalidQuantity); - event::emit(WithdrawAsset<QuoteAsset>{ - pool_id: *object::uid_as_inner(&pool.id), + event::emit(WithdrawAsset<QuoteAsset>{ + pool_id: *object::uid_as_inner(&pool.id), quantity, owner: account_owner(account_cap) }); @@ -1889,7 +1889,7 @@ so with this function. -
    public fun swap_exact_base_for_quote<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, account_cap: &custodian_v2::AccountCap, quantity: u64, base_coin: coin::Coin<BaseAsset>, quote_coin: coin::Coin<QuoteAsset>, clock: &clock::Clock, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, u64)
    +
    public fun swap_exact_base_for_quote<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, account_cap: &custodian_v2::AccountCap, quantity: u64, base_coin: coin::Coin<BaseAsset>, quote_coin: coin::Coin<QuoteAsset>, clock: &clock::Clock, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, u64)
     
    @@ -1905,12 +1905,12 @@ so with this function. quantity: u64, base_coin: Coin<BaseAsset>, quote_coin: Coin<QuoteAsset>, - clock: &Clock, + clock: &Clock, ctx: &mut TxContext, ): (Coin<BaseAsset>, Coin<QuoteAsset>, u64) { assert!(quantity > 0, EInvalidQuantity); - assert!(coin::value(&base_coin) >= quantity, EInsufficientBaseCoin); - let original_val = coin::value("e_coin); + assert!(coin::value(&base_coin) >= quantity, EInsufficientBaseCoin); + let original_val = coin::value("e_coin); let (ret_base_coin, ret_quote_coin) = place_market_order( pool, account_cap, @@ -1919,10 +1919,10 @@ so with this function. false, base_coin, quote_coin, - clock, + clock, ctx ); - let ret_val = coin::value(&ret_quote_coin); + let ret_val = coin::value(&ret_quote_coin); (ret_base_coin, ret_quote_coin, ret_val - original_val) }
    @@ -1937,7 +1937,7 @@ so with this function. -
    public fun swap_exact_base_for_quote_with_metadata<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, account_cap: &custodian_v2::AccountCap, quantity: u64, base_coin: coin::Coin<BaseAsset>, quote_coin: coin::Coin<QuoteAsset>, clock: &clock::Clock, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, u64, vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>)
    +
    public fun swap_exact_base_for_quote_with_metadata<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, account_cap: &custodian_v2::AccountCap, quantity: u64, base_coin: coin::Coin<BaseAsset>, quote_coin: coin::Coin<QuoteAsset>, clock: &clock::Clock, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, u64, vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>)
     
    @@ -1953,10 +1953,10 @@ so with this function. quantity: u64, base_coin: Coin<BaseAsset>, quote_coin: Coin<QuoteAsset>, - clock: &Clock, + clock: &Clock, ctx: &mut TxContext, ): (Coin<BaseAsset>, Coin<QuoteAsset>, u64, vector<MatchedOrderMetadata<BaseAsset, QuoteAsset>>) { - let original_val = coin::value("e_coin); + let original_val = coin::value("e_coin); let (ret_base_coin, ret_quote_coin, mut matched_order_metadata) = place_market_order_int( pool, account_cap, @@ -1965,11 +1965,11 @@ so with this function. false, base_coin, quote_coin, - clock, + clock, true, // return metadata ctx ); - let ret_val = coin::value(&ret_quote_coin); + let ret_val = coin::value(&ret_quote_coin); (ret_base_coin, ret_quote_coin, ret_val - original_val, option::extract(&mut matched_order_metadata)) }
    @@ -1984,7 +1984,7 @@ so with this function. -
    public fun swap_exact_quote_for_base<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, account_cap: &custodian_v2::AccountCap, quantity: u64, clock: &clock::Clock, quote_coin: coin::Coin<QuoteAsset>, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, u64)
    +
    public fun swap_exact_quote_for_base<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, account_cap: &custodian_v2::AccountCap, quantity: u64, clock: &clock::Clock, quote_coin: coin::Coin<QuoteAsset>, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, u64)
     
    @@ -1998,24 +1998,24 @@ so with this function. client_order_id: u64, account_cap: &AccountCap, quantity: u64, - clock: &Clock, + clock: &Clock, quote_coin: Coin<QuoteAsset>, ctx: &mut TxContext, ): (Coin<BaseAsset>, Coin<QuoteAsset>, u64) { assert!(quantity > 0, EInvalidQuantity); - assert!(coin::value("e_coin) >= quantity, EInsufficientQuoteCoin); + assert!(coin::value("e_coin) >= quantity, EInsufficientQuoteCoin); let (base_asset_balance, quote_asset_balance, _matched_order_metadata) = match_bid_with_quote_quantity( pool, account_cap, client_order_id, quantity, MAX_PRICE, - clock::timestamp_ms(clock), - coin::into_balance(quote_coin), + clock::timestamp_ms(clock), + coin::into_balance(quote_coin), false // don't return metadata ); - let val = balance::value(&base_asset_balance); - (coin::from_balance(base_asset_balance, ctx), coin::from_balance(quote_asset_balance, ctx), val) + let val = balance::value(&base_asset_balance); + (coin::from_balance(base_asset_balance, ctx), coin::from_balance(quote_asset_balance, ctx), val) }
    @@ -2029,7 +2029,7 @@ so with this function. -
    public fun swap_exact_quote_for_base_with_metadata<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, account_cap: &custodian_v2::AccountCap, quantity: u64, clock: &clock::Clock, quote_coin: coin::Coin<QuoteAsset>, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, u64, vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>)
    +
    public fun swap_exact_quote_for_base_with_metadata<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, account_cap: &custodian_v2::AccountCap, quantity: u64, clock: &clock::Clock, quote_coin: coin::Coin<QuoteAsset>, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, u64, vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>)
     
    @@ -2043,24 +2043,24 @@ so with this function. client_order_id: u64, account_cap: &AccountCap, quantity: u64, - clock: &Clock, + clock: &Clock, quote_coin: Coin<QuoteAsset>, ctx: &mut TxContext, ): (Coin<BaseAsset>, Coin<QuoteAsset>, u64, vector<MatchedOrderMetadata<BaseAsset, QuoteAsset>>) { assert!(quantity > 0, EInvalidQuantity); - assert!(coin::value("e_coin) >= quantity, EInsufficientQuoteCoin); + assert!(coin::value("e_coin) >= quantity, EInsufficientQuoteCoin); let (base_asset_balance, quote_asset_balance, mut matched_order_metadata) = match_bid_with_quote_quantity( pool, account_cap, client_order_id, quantity, MAX_PRICE, - clock::timestamp_ms(clock), - coin::into_balance(quote_coin), + clock::timestamp_ms(clock), + coin::into_balance(quote_coin), true // return metadata ); - let val = balance::value(&base_asset_balance); - (coin::from_balance(base_asset_balance, ctx), coin::from_balance(quote_asset_balance, ctx), val, option::extract(&mut matched_order_metadata)) + let val = balance::value(&base_asset_balance); + (coin::from_balance(base_asset_balance, ctx), coin::from_balance(quote_asset_balance, ctx), val, option::extract(&mut matched_order_metadata)) }
    @@ -2074,7 +2074,7 @@ so with this function. -
    fun match_bid_with_quote_quantity<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian_v2::AccountCap, client_order_id: u64, quantity: u64, price_limit: u64, current_timestamp: u64, quote_balance: balance::Balance<QuoteAsset>, compute_metadata: bool): (balance::Balance<BaseAsset>, balance::Balance<QuoteAsset>, option::Option<vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>>)
    +
    fun match_bid_with_quote_quantity<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian_v2::AccountCap, client_order_id: u64, quantity: u64, price_limit: u64, current_timestamp: u64, quote_balance: balance::Balance<QuoteAsset>, compute_metadata: bool): (balance::Balance<BaseAsset>, balance::Balance<QuoteAsset>, option::Option<vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>>)
     
    @@ -2093,11 +2093,11 @@ so with this function. quote_balance: Balance<QuoteAsset>, compute_metadata: bool, ): (Balance<BaseAsset>, Balance<QuoteAsset>, Option<vector<MatchedOrderMetadata<BaseAsset, QuoteAsset>>>) { - // Base balance received by taker, taking into account of taker commission. + // Base balance received by taker, taking into account of taker commission. // Need to individually keep track of the remaining base quantity to be filled to avoid infinite loop. - let pool_id = *object::uid_as_inner(&pool.id); + let pool_id = *object::uid_as_inner(&pool.id); let mut taker_quote_quantity_remaining = quantity; - let mut base_balance_filled = balance::zero<BaseAsset>(); + let mut base_balance_filled = balance::zero<BaseAsset>(); let mut quote_balance_left = quote_balance; let all_open_orders = &mut pool.asks; let mut matched_order_metadata = vector::empty<MatchedOrderMetadata<BaseAsset, QuoteAsset>>(); @@ -2110,10 +2110,10 @@ so with this function. while (!is_empty<TickLevel>(all_open_orders) && tick_price <= price_limit) { let tick_level = borrow_mut_leaf_by_index(all_open_orders, tick_index); - let mut order_id = *option::borrow(linked_table::front(&tick_level.open_orders)); + let mut order_id = *option::borrow(linked_table::front(&tick_level.open_orders)); - while (!linked_table::is_empty(&tick_level.open_orders)) { - let maker_order = linked_table::borrow(&tick_level.open_orders, order_id); + while (!linked_table::is_empty(&tick_level.open_orders)) { + let maker_order = linked_table::borrow(&tick_level.open_orders, order_id); let mut maker_base_quantity = maker_order.quantity; let mut skip_order = false; @@ -2201,7 +2201,7 @@ so with this function. filled_base_quantity ); - let mut quote_balance_filled = balance::split( + let mut quote_balance_filled = balance::split( &mut quote_balance_left, filled_quote_quantity, ); @@ -2209,18 +2209,18 @@ so with this function. custodian::increase_user_available_balance<QuoteAsset>( &mut pool.quote_custodian, maker_order.owner, - balance::split( + balance::split( &mut quote_balance_filled, maker_rebate + filled_quote_quantity_without_commission, ), ); // Send remaining of commission - rebate to the protocol. // commission - rebate = filled_quote_quantity_without_commission - filled_quote_quantity - maker_rebate - balance::join(&mut pool.quote_asset_trading_fees, quote_balance_filled); - balance::join(&mut base_balance_filled, locked_base_balance); + balance::join(&mut pool.quote_asset_trading_fees, quote_balance_filled); + balance::join(&mut base_balance_filled, locked_base_balance); emit_order_filled<BaseAsset, QuoteAsset>( - *object::uid_as_inner(&pool.id), + *object::uid_as_inner(&pool.id), client_order_id, account_owner(account_cap), maker_order, @@ -2234,7 +2234,7 @@ so with this function. vector::push_back( &mut matched_order_metadata, matched_order_metadata( - *object::uid_as_inner(&pool.id), + *object::uid_as_inner(&pool.id), account_owner(account_cap), maker_order, filled_base_quantity, @@ -2250,16 +2250,16 @@ so with this function. if (skip_order || maker_base_quantity == 0) { // Remove the maker order. let old_order_id = order_id; - let maybe_order_id = linked_table::next(&tick_level.open_orders, order_id); + let maybe_order_id = linked_table::next(&tick_level.open_orders, order_id); if (!option::is_none(maybe_order_id)) { order_id = *option::borrow(maybe_order_id); }; - let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, maker_order.owner); - linked_table::remove(usr_open_order_ids, old_order_id); - linked_table::remove(&mut tick_level.open_orders, old_order_id); + let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, maker_order.owner); + linked_table::remove(usr_open_order_ids, old_order_id); + linked_table::remove(&mut tick_level.open_orders, old_order_id); } else { // Update the maker order. - let maker_order_mut = linked_table::borrow_mut( + let maker_order_mut = linked_table::borrow_mut( &mut tick_level.open_orders, order_id); maker_order_mut.quantity = maker_base_quantity; @@ -2268,7 +2268,7 @@ so with this function. break }; }; - if (linked_table::is_empty(&tick_level.open_orders)) { + if (linked_table::is_empty(&tick_level.open_orders)) { (tick_price, _) = next_leaf(all_open_orders, tick_price); destroy_empty_level(remove_leaf_by_index(all_open_orders, tick_index)); (_, tick_index) = find_leaf(all_open_orders, tick_price); @@ -2279,7 +2279,7 @@ so with this function. }; if (!vector::is_empty(&canceled_order_events)) { - event::emit(AllOrdersCanceled<BaseAsset, QuoteAsset> { + event::emit(AllOrdersCanceled<BaseAsset, QuoteAsset> { pool_id, orders_canceled: canceled_order_events, }); @@ -2299,7 +2299,7 @@ so with this function. -
    fun match_bid<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian_v2::AccountCap, client_order_id: u64, quantity: u64, price_limit: u64, current_timestamp: u64, quote_balance: balance::Balance<QuoteAsset>, compute_metadata: bool): (balance::Balance<BaseAsset>, balance::Balance<QuoteAsset>, option::Option<vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>>)
    +
    fun match_bid<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian_v2::AccountCap, client_order_id: u64, quantity: u64, price_limit: u64, current_timestamp: u64, quote_balance: balance::Balance<QuoteAsset>, compute_metadata: bool): (balance::Balance<BaseAsset>, balance::Balance<QuoteAsset>, option::Option<vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>>)
     
    @@ -2318,11 +2318,11 @@ so with this function. quote_balance: Balance<QuoteAsset>, compute_metadata: bool, ): (Balance<BaseAsset>, Balance<QuoteAsset>, Option<vector<MatchedOrderMetadata<BaseAsset, QuoteAsset>>>) { - let pool_id = *object::uid_as_inner(&pool.id); - // Base balance received by taker. + let pool_id = *object::uid_as_inner(&pool.id); + // Base balance received by taker. // Need to individually keep track of the remaining base quantity to be filled to avoid infinite loop. let mut taker_base_quantity_remaining = quantity; - let mut base_balance_filled = balance::zero<BaseAsset>(); + let mut base_balance_filled = balance::zero<BaseAsset>(); let mut quote_balance_left = quote_balance; let all_open_orders = &mut pool.asks; let mut matched_order_metadata = vector::empty<MatchedOrderMetadata<BaseAsset, QuoteAsset>>(); @@ -2334,10 +2334,10 @@ so with this function. while (!is_empty<TickLevel>(all_open_orders) && tick_price <= price_limit) { let tick_level = borrow_mut_leaf_by_index(all_open_orders, tick_index); - let mut order_id = *option::borrow(linked_table::front(&tick_level.open_orders)); + let mut order_id = *option::borrow(linked_table::front(&tick_level.open_orders)); - while (!linked_table::is_empty(&tick_level.open_orders)) { - let maker_order = linked_table::borrow(&tick_level.open_orders, order_id); + while (!linked_table::is_empty(&tick_level.open_orders)) { + let maker_order = linked_table::borrow(&tick_level.open_orders, order_id); let mut maker_base_quantity = maker_order.quantity; let mut skip_order = false; @@ -2381,32 +2381,32 @@ so with this function. maker_order.owner, filled_base_quantity ); - let mut taker_commission_balance = balance::split( + let mut taker_commission_balance = balance::split( &mut quote_balance_left, taker_commission, ); custodian::increase_user_available_balance<QuoteAsset>( &mut pool.quote_custodian, maker_order.owner, - balance::split( + balance::split( &mut taker_commission_balance, maker_rebate, ), ); - balance::join(&mut pool.quote_asset_trading_fees, taker_commission_balance); - balance::join(&mut base_balance_filled, locked_base_balance); + balance::join(&mut pool.quote_asset_trading_fees, taker_commission_balance); + balance::join(&mut base_balance_filled, locked_base_balance); custodian::increase_user_available_balance<QuoteAsset>( &mut pool.quote_custodian, maker_order.owner, - balance::split( + balance::split( &mut quote_balance_left, filled_quote_quantity, ), ); emit_order_filled<BaseAsset, QuoteAsset>( - *object::uid_as_inner(&pool.id), + *object::uid_as_inner(&pool.id), client_order_id, account_owner(account_cap), maker_order, @@ -2418,7 +2418,7 @@ so with this function. vector::push_back( &mut matched_order_metadata, matched_order_metadata( - *object::uid_as_inner(&pool.id), + *object::uid_as_inner(&pool.id), account_owner(account_cap), maker_order, filled_base_quantity, @@ -2432,16 +2432,16 @@ so with this function. if (skip_order || maker_base_quantity == 0) { // Remove the maker order. let old_order_id = order_id; - let maybe_order_id = linked_table::next(&tick_level.open_orders, order_id); + let maybe_order_id = linked_table::next(&tick_level.open_orders, order_id); if (!option::is_none(maybe_order_id)) { order_id = *option::borrow(maybe_order_id); }; - let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, maker_order.owner); - linked_table::remove(usr_open_order_ids, old_order_id); - linked_table::remove(&mut tick_level.open_orders, old_order_id); + let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, maker_order.owner); + linked_table::remove(usr_open_order_ids, old_order_id); + linked_table::remove(&mut tick_level.open_orders, old_order_id); } else { // Update the maker order. - let maker_order_mut = linked_table::borrow_mut( + let maker_order_mut = linked_table::borrow_mut( &mut tick_level.open_orders, order_id); maker_order_mut.quantity = maker_base_quantity; @@ -2450,7 +2450,7 @@ so with this function. break }; }; - if (linked_table::is_empty(&tick_level.open_orders)) { + if (linked_table::is_empty(&tick_level.open_orders)) { (tick_price, _) = next_leaf(all_open_orders, tick_price); destroy_empty_level(remove_leaf_by_index(all_open_orders, tick_index)); (_, tick_index) = find_leaf(all_open_orders, tick_price); @@ -2461,7 +2461,7 @@ so with this function. }; if (!vector::is_empty(&canceled_order_events)) { - event::emit(AllOrdersCanceled<BaseAsset, QuoteAsset> { + event::emit(AllOrdersCanceled<BaseAsset, QuoteAsset> { pool_id, orders_canceled: canceled_order_events, }); @@ -2480,7 +2480,7 @@ so with this function. -
    fun match_ask<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian_v2::AccountCap, client_order_id: u64, price_limit: u64, current_timestamp: u64, base_balance: balance::Balance<BaseAsset>, compute_metadata: bool): (balance::Balance<BaseAsset>, balance::Balance<QuoteAsset>, option::Option<vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>>)
    +
    fun match_ask<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian_v2::AccountCap, client_order_id: u64, price_limit: u64, current_timestamp: u64, base_balance: balance::Balance<BaseAsset>, compute_metadata: bool): (balance::Balance<BaseAsset>, balance::Balance<QuoteAsset>, option::Option<vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>>)
     
    @@ -2498,10 +2498,10 @@ so with this function. base_balance: Balance<BaseAsset>, compute_metadata: bool, ): (Balance<BaseAsset>, Balance<QuoteAsset>, Option<vector<MatchedOrderMetadata<BaseAsset, QuoteAsset>>>) { - let pool_id = *object::uid_as_inner(&pool.id); + let pool_id = *object::uid_as_inner(&pool.id); let mut base_balance_left = base_balance; - // Base balance received by taker, taking into account of taker commission. - let mut quote_balance_filled = balance::zero<QuoteAsset>(); + // Base balance received by taker, taking into account of taker commission. + let mut quote_balance_filled = balance::zero<QuoteAsset>(); let all_open_orders = &mut pool.bids; let mut matched_order_metadata = vector::empty<MatchedOrderMetadata<BaseAsset, QuoteAsset>>(); if (critbit::is_empty(all_open_orders)) { @@ -2511,9 +2511,9 @@ so with this function. let mut canceled_order_events = vector[]; while (!is_empty<TickLevel>(all_open_orders) && tick_price >= price_limit) { let tick_level = borrow_mut_leaf_by_index(all_open_orders, tick_index); - let mut order_id = *option::borrow(linked_table::front(&tick_level.open_orders)); - while (!linked_table::is_empty(&tick_level.open_orders)) { - let maker_order = linked_table::borrow(&tick_level.open_orders, order_id); + let mut order_id = *option::borrow(linked_table::front(&tick_level.open_orders)); + while (!linked_table::is_empty(&tick_level.open_orders)) { + let maker_order = linked_table::borrow(&tick_level.open_orders, order_id); let mut maker_base_quantity = maker_order.quantity; let mut skip_order = false; @@ -2532,7 +2532,7 @@ so with this function. }; vector::push_back(&mut canceled_order_events, canceled_order_event); } else { - let taker_base_quantity_remaining = balance::value(&base_balance_left); + let taker_base_quantity_remaining = balance::value(&base_balance_left); let filled_base_quantity = if (taker_base_quantity_remaining >= maker_base_quantity) { maker_base_quantity } else { taker_base_quantity_remaining }; @@ -2544,7 +2544,7 @@ so with this function. maker_order.owner, 1 ); - balance::join(&mut pool.quote_asset_trading_fees, rounded_down_quantity); + balance::join(&mut pool.quote_asset_trading_fees, rounded_down_quantity); }; // if maker_rebate = 0 due to underflow, maker will not receive a rebate @@ -2563,31 +2563,31 @@ so with this function. maker_order.owner, filled_quote_quantity ); - let mut taker_commission_balance = balance::split( + let mut taker_commission_balance = balance::split( &mut locked_quote_balance, taker_commission, ); custodian::increase_user_available_balance<QuoteAsset>( &mut pool.quote_custodian, maker_order.owner, - balance::split( + balance::split( &mut taker_commission_balance, maker_rebate, ), ); - balance::join(&mut pool.quote_asset_trading_fees, taker_commission_balance); - balance::join(&mut quote_balance_filled, locked_quote_balance); + balance::join(&mut pool.quote_asset_trading_fees, taker_commission_balance); + balance::join(&mut quote_balance_filled, locked_quote_balance); custodian::increase_user_available_balance<BaseAsset>( &mut pool.base_custodian, maker_order.owner, - balance::split( + balance::split( &mut base_balance_left, filled_base_quantity, ), ); emit_order_filled<BaseAsset, QuoteAsset>( - *object::uid_as_inner(&pool.id), + *object::uid_as_inner(&pool.id), client_order_id, account_owner(account_cap), maker_order, @@ -2599,7 +2599,7 @@ so with this function. vector::push_back( &mut matched_order_metadata, matched_order_metadata( - *object::uid_as_inner(&pool.id), + *object::uid_as_inner(&pool.id), account_owner(account_cap), maker_order, filled_base_quantity, @@ -2613,36 +2613,36 @@ so with this function. if (skip_order || maker_base_quantity == 0) { // Remove the maker order. let old_order_id = order_id; - let maybe_order_id = linked_table::next(&tick_level.open_orders, order_id); + let maybe_order_id = linked_table::next(&tick_level.open_orders, order_id); if (!option::is_none(maybe_order_id)) { order_id = *option::borrow(maybe_order_id); }; - let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, maker_order.owner); - linked_table::remove(usr_open_order_ids, old_order_id); - linked_table::remove(&mut tick_level.open_orders, old_order_id); + let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, maker_order.owner); + linked_table::remove(usr_open_order_ids, old_order_id); + linked_table::remove(&mut tick_level.open_orders, old_order_id); } else { // Update the maker order. - let maker_order_mut = linked_table::borrow_mut( + let maker_order_mut = linked_table::borrow_mut( &mut tick_level.open_orders, order_id); maker_order_mut.quantity = maker_base_quantity; }; - if (balance::value(&base_balance_left) == 0) { + if (balance::value(&base_balance_left) == 0) { break }; }; - if (linked_table::is_empty(&tick_level.open_orders)) { + if (linked_table::is_empty(&tick_level.open_orders)) { (tick_price, _) = previous_leaf(all_open_orders, tick_price); destroy_empty_level(remove_leaf_by_index(all_open_orders, tick_index)); (_, tick_index) = find_leaf(all_open_orders, tick_price); }; - if (balance::value(&base_balance_left) == 0) { + if (balance::value(&base_balance_left) == 0) { break }; }; if (!vector::is_empty(&canceled_order_events)) { - event::emit(AllOrdersCanceled<BaseAsset, QuoteAsset> { + event::emit(AllOrdersCanceled<BaseAsset, QuoteAsset> { pool_id, orders_canceled: canceled_order_events, }); @@ -2663,7 +2663,7 @@ so with this function. Place a market order to the order book. -
    public fun place_market_order<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian_v2::AccountCap, client_order_id: u64, quantity: u64, is_bid: bool, base_coin: coin::Coin<BaseAsset>, quote_coin: coin::Coin<QuoteAsset>, clock: &clock::Clock, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>)
    +
    public fun place_market_order<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian_v2::AccountCap, client_order_id: u64, quantity: u64, is_bid: bool, base_coin: coin::Coin<BaseAsset>, quote_coin: coin::Coin<QuoteAsset>, clock: &clock::Clock, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>)
     
    @@ -2680,7 +2680,7 @@ Place a market order to the order book. is_bid: bool, base_coin: Coin<BaseAsset>, quote_coin: Coin<QuoteAsset>, - clock: &Clock, + clock: &Clock, ctx: &mut TxContext, ): (Coin<BaseAsset>, Coin<QuoteAsset>) { let (base_coin, quote_coin, _metadata) = place_market_order_int( @@ -2691,7 +2691,7 @@ Place a market order to the order book. is_bid, base_coin, quote_coin, - clock, + clock, false, // don't return metadata ctx ); @@ -2709,7 +2709,7 @@ Place a market order to the order book. -
    public fun place_market_order_with_metadata<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian_v2::AccountCap, client_order_id: u64, quantity: u64, is_bid: bool, base_coin: coin::Coin<BaseAsset>, quote_coin: coin::Coin<QuoteAsset>, clock: &clock::Clock, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>)
    +
    public fun place_market_order_with_metadata<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian_v2::AccountCap, client_order_id: u64, quantity: u64, is_bid: bool, base_coin: coin::Coin<BaseAsset>, quote_coin: coin::Coin<QuoteAsset>, clock: &clock::Clock, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>)
     
    @@ -2726,7 +2726,7 @@ Place a market order to the order book. is_bid: bool, base_coin: Coin<BaseAsset>, quote_coin: Coin<QuoteAsset>, - clock: &Clock, + clock: &Clock, ctx: &mut TxContext, ): (Coin<BaseAsset>, Coin<QuoteAsset>, vector<MatchedOrderMetadata<BaseAsset, QuoteAsset>>) { let (base_coin, quote_coin, mut metadata) = place_market_order_int( @@ -2737,7 +2737,7 @@ Place a market order to the order book. is_bid, base_coin, quote_coin, - clock, + clock, true, // return metadata ctx ); @@ -2756,7 +2756,7 @@ Place a market order to the order book. Place a market order to the order book. -
    fun place_market_order_int<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian_v2::AccountCap, client_order_id: u64, quantity: u64, is_bid: bool, base_coin: coin::Coin<BaseAsset>, quote_coin: coin::Coin<QuoteAsset>, clock: &clock::Clock, compute_metadata: bool, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, option::Option<vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>>)
    +
    fun place_market_order_int<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian_v2::AccountCap, client_order_id: u64, quantity: u64, is_bid: bool, base_coin: coin::Coin<BaseAsset>, quote_coin: coin::Coin<QuoteAsset>, clock: &clock::Clock, compute_metadata: bool, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, option::Option<vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>>)
     
    @@ -2773,7 +2773,7 @@ Place a market order to the order book. is_bid: bool, mut base_coin: Coin<BaseAsset>, mut quote_coin: Coin<QuoteAsset>, - clock: &Clock, + clock: &Clock, compute_metadata: bool, ctx: &mut TxContext, ): (Coin<BaseAsset>, Coin<QuoteAsset>, Option<vector<MatchedOrderMetadata<BaseAsset, QuoteAsset>>>) { @@ -2803,34 +2803,34 @@ Place a market order to the order book. client_order_id, quantity, MAX_PRICE, - clock::timestamp_ms(clock), - coin::into_balance(quote_coin), + clock::timestamp_ms(clock), + coin::into_balance(quote_coin), compute_metadata ); join( &mut base_coin, - coin::from_balance(base_balance_filled, ctx), + coin::from_balance(base_balance_filled, ctx), ); - quote_coin = coin::from_balance(quote_balance_left, ctx); + quote_coin = coin::from_balance(quote_balance_left, ctx); metadata = matched_order_metadata; } else { - assert!(quantity <= coin::value(&base_coin), EInsufficientBaseCoin); - let base_coin_to_sell = coin::split(&mut base_coin, quantity, ctx); + assert!(quantity <= coin::value(&base_coin), EInsufficientBaseCoin); + let base_coin_to_sell = coin::split(&mut base_coin, quantity, ctx); let (base_balance_left, quote_balance_filled, matched_order_metadata) = match_ask( pool, account_cap, client_order_id, MIN_PRICE, - clock::timestamp_ms(clock), - coin::into_balance(base_coin_to_sell), + clock::timestamp_ms(clock), + coin::into_balance(base_coin_to_sell), compute_metadata ); join( &mut base_coin, - coin::from_balance(base_balance_left, ctx)); + coin::from_balance(base_balance_left, ctx)); join( &mut quote_coin, - coin::from_balance(quote_balance_filled, ctx), + coin::from_balance(quote_balance_filled, ctx), ); metadata = matched_order_metadata; }; @@ -2850,7 +2850,7 @@ Injects a maker order to the order book. Returns the order id. -
    fun inject_limit_order<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, price: u64, original_quantity: u64, quantity: u64, is_bid: bool, self_matching_prevention: u8, expire_timestamp: u64, account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): u64
    +
    fun inject_limit_order<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, price: u64, original_quantity: u64, quantity: u64, is_bid: bool, self_matching_prevention: u8, expire_timestamp: u64, account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): u64
     
    @@ -2904,14 +2904,14 @@ Returns the order id. price, TickLevel { price, - open_orders: linked_table::new(ctx), + open_orders: linked_table::new(ctx), }); }; let tick_level = borrow_mut_leaf_by_index(open_orders, tick_index); - linked_table::push_back(&mut tick_level.open_orders, order_id, order); - event::emit(OrderPlaced<BaseAsset, QuoteAsset> { - pool_id: *object::uid_as_inner(&pool.id), + linked_table::push_back(&mut tick_level.open_orders, order_id, order); + event::emit(OrderPlaced<BaseAsset, QuoteAsset> { + pool_id: *object::uid_as_inner(&pool.id), order_id, client_order_id, is_bid, @@ -2922,9 +2922,9 @@ Returns the order id. expire_timestamp }); if (!contains(&pool.usr_open_orders, owner)) { - add(&mut pool.usr_open_orders, owner, linked_table::new(ctx)); + add(&mut pool.usr_open_orders, owner, linked_table::new(ctx)); }; - linked_table::push_back(borrow_mut(&mut pool.usr_open_orders, owner), order_id, price); + linked_table::push_back(borrow_mut(&mut pool.usr_open_orders, owner), order_id, price); return order_id } @@ -2945,7 +2945,7 @@ When the limit order is successfully placed, we return true to indicate that and So please check that boolean value first before using the order id. -
    public fun place_limit_order<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, price: u64, quantity: u64, self_matching_prevention: u8, is_bid: bool, expire_timestamp: u64, restriction: u8, clock: &clock::Clock, account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): (u64, u64, bool, u64)
    +
    public fun place_limit_order<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, price: u64, quantity: u64, self_matching_prevention: u8, is_bid: bool, expire_timestamp: u64, restriction: u8, clock: &clock::Clock, account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): (u64, u64, bool, u64)
     
    @@ -2963,7 +2963,7 @@ So please check that boolean value first before using the order id. is_bid: bool, expire_timestamp: u64, // Expiration timestamp in ms in absolute value inclusive. restriction: u8, - clock: &Clock, + clock: &Clock, account_cap: &AccountCap, ctx: &mut TxContext ): (u64, u64, bool, u64) { @@ -2976,7 +2976,7 @@ So please check that boolean value first before using the order id. is_bid, expire_timestamp, // Expiration timestamp in ms in absolute value inclusive. restriction, - clock, + clock, account_cap, false, // don't compute metadata ctx @@ -3000,7 +3000,7 @@ When the limit order is successfully placed, we return true to indicate that and So please check that boolean value first before using the order id. -
    public fun place_limit_order_with_metadata<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, price: u64, quantity: u64, self_matching_prevention: u8, is_bid: bool, expire_timestamp: u64, restriction: u8, clock: &clock::Clock, account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): (u64, u64, bool, u64, vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>)
    +
    public fun place_limit_order_with_metadata<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, price: u64, quantity: u64, self_matching_prevention: u8, is_bid: bool, expire_timestamp: u64, restriction: u8, clock: &clock::Clock, account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): (u64, u64, bool, u64, vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>)
     
    @@ -3018,7 +3018,7 @@ So please check that boolean value first before using the order id. is_bid: bool, expire_timestamp: u64, // Expiration timestamp in ms in absolute value inclusive. restriction: u8, - clock: &Clock, + clock: &Clock, account_cap: &AccountCap, ctx: &mut TxContext ): (u64, u64, bool, u64, vector<MatchedOrderMetadata<BaseAsset, QuoteAsset>>) { @@ -3031,7 +3031,7 @@ So please check that boolean value first before using the order id. is_bid, expire_timestamp, // Expiration timestamp in ms in absolute value inclusive. restriction, - clock, + clock, account_cap, true, // return metadata ctx @@ -3050,7 +3050,7 @@ So please check that boolean value first before using the order id. -
    fun place_limit_order_int<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, price: u64, quantity: u64, self_matching_prevention: u8, is_bid: bool, expire_timestamp: u64, restriction: u8, clock: &clock::Clock, account_cap: &custodian_v2::AccountCap, compute_metadata: bool, ctx: &mut tx_context::TxContext): (u64, u64, bool, u64, option::Option<vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>>)
    +
    fun place_limit_order_int<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, client_order_id: u64, price: u64, quantity: u64, self_matching_prevention: u8, is_bid: bool, expire_timestamp: u64, restriction: u8, clock: &clock::Clock, account_cap: &custodian_v2::AccountCap, compute_metadata: bool, ctx: &mut tx_context::TxContext): (u64, u64, bool, u64, option::Option<vector<clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>>>)
     
    @@ -3068,7 +3068,7 @@ So please check that boolean value first before using the order id. is_bid: bool, expire_timestamp: u64, // Expiration timestamp in ms in absolute value inclusive. restriction: u8, - clock: &Clock, + clock: &Clock, account_cap: &AccountCap, compute_metadata: bool, ctx: &mut TxContext @@ -3085,7 +3085,7 @@ So please check that boolean value first before using the order id. assert!(price > 0, EInvalidPrice); assert!(price % pool.tick_size == 0, EInvalidPrice); assert!(quantity % pool.lot_size == 0, EInvalidQuantity); - assert!(expire_timestamp > clock::timestamp_ms(clock), EInvalidExpireTimestamp); + assert!(expire_timestamp > clock::timestamp_ms(clock), EInvalidExpireTimestamp); let owner = account_owner(account_cap); let original_quantity = quantity; let base_quantity_filled; @@ -3106,12 +3106,12 @@ So please check that boolean value first before using the order id. client_order_id, quantity, price, - clock::timestamp_ms(clock), + clock::timestamp_ms(clock), quote_balance, compute_metadata ); - base_quantity_filled = balance::value(&base_balance_filled); - quote_quantity_filled = quote_quantity_original - balance::value("e_balance_left); + base_quantity_filled = balance::value(&base_balance_filled); + quote_quantity_filled = quote_quantity_original - balance::value("e_balance_left); custodian::increase_user_available_balance<BaseAsset>( &mut pool.base_custodian, @@ -3136,13 +3136,13 @@ So please check that boolean value first before using the order id. account_cap, client_order_id, price, - clock::timestamp_ms(clock), + clock::timestamp_ms(clock), base_balance, compute_metadata ); - base_quantity_filled = quantity - balance::value(&base_balance_left); - quote_quantity_filled = balance::value("e_balance_filled); + base_quantity_filled = quantity - balance::value(&base_balance_left); + quote_quantity_filled = balance::value("e_balance_filled); custodian::increase_user_available_balance<BaseAsset>( &mut pool.base_custodian, @@ -3236,7 +3236,7 @@ So please check that boolean value first before using the order id. -
    fun emit_order_canceled<BaseAsset, QuoteAsset>(pool_id: object::ID, order: &clob_v2::Order)
    +
    fun emit_order_canceled<BaseAsset, QuoteAsset>(pool_id: object::ID, order: &clob_v2::Order)
     
    @@ -3249,7 +3249,7 @@ So please check that boolean value first before using the order id. pool_id: ID, order: &Order ) { - event::emit(OrderCanceled<BaseAsset, QuoteAsset> { + event::emit(OrderCanceled<BaseAsset, QuoteAsset> { pool_id, client_order_id: order.client_order_id, order_id: order.order_id, @@ -3272,7 +3272,7 @@ So please check that boolean value first before using the order id. -
    fun emit_order_filled<BaseAsset, QuoteAsset>(pool_id: object::ID, taker_client_id: u64, taker_address: address, order: &clob_v2::Order, base_asset_quantity_filled: u64, taker_commission: u64, maker_rebates: u64)
    +
    fun emit_order_filled<BaseAsset, QuoteAsset>(pool_id: object::ID, taker_client_id: u64, taker_address: address, order: &clob_v2::Order, base_asset_quantity_filled: u64, taker_commission: u64, maker_rebates: u64)
     
    @@ -3290,7 +3290,7 @@ So please check that boolean value first before using the order id. taker_commission: u64, maker_rebates: u64 ) { - event::emit(OrderFilled<BaseAsset, QuoteAsset> { + event::emit(OrderFilled<BaseAsset, QuoteAsset> { pool_id, order_id: order.order_id, taker_client_order_id: taker_client_id, @@ -3343,8 +3343,8 @@ Abort if order_id is invalid or if the order is not submitted by the transaction let owner = account_owner(account_cap); assert!(contains(&pool.usr_open_orders, owner), EInvalidUser); let usr_open_orders = borrow_mut(&mut pool.usr_open_orders, owner); - assert!(linked_table::contains(usr_open_orders, order_id), EInvalidOrderId); - let tick_price = *linked_table::borrow(usr_open_orders, order_id); + assert!(linked_table::contains(usr_open_orders, order_id), EInvalidOrderId); + let tick_price = *linked_table::borrow(usr_open_orders, order_id); let is_bid = order_is_bid(order_id); let (tick_exists, tick_index) = find_leaf( if (is_bid) { &pool.bids } else { &pool.asks }, @@ -3363,7 +3363,7 @@ Abort if order_id is invalid or if the order is not submitted by the transaction } else { custodian::unlock_balance(&mut pool.base_custodian, owner, order.quantity); }; - emit_order_canceled<BaseAsset, QuoteAsset>(*object::uid_as_inner(&pool.id), &order); + emit_order_canceled<BaseAsset, QuoteAsset>(*object::uid_as_inner(&pool.id), &order); }
    @@ -3377,7 +3377,7 @@ Abort if order_id is invalid or if the order is not submitted by the transaction -
    fun remove_order(open_orders: &mut critbit::CritbitTree<clob_v2::TickLevel>, usr_open_orders: &mut linked_table::LinkedTable<u64, u64>, tick_index: u64, order_id: u64, owner: address): clob_v2::Order
    +
    fun remove_order(open_orders: &mut critbit::CritbitTree<clob_v2::TickLevel>, usr_open_orders: &mut linked_table::LinkedTable<u64, u64>, tick_index: u64, order_id: u64, owner: address): clob_v2::Order
     
    @@ -3393,13 +3393,13 @@ Abort if order_id is invalid or if the order is not submitted by the transaction order_id: u64, owner: address, ): Order { - linked_table::remove(usr_open_orders, order_id); + linked_table::remove(usr_open_orders, order_id); let tick_level = borrow_leaf_by_index(open_orders, tick_index); - assert!(linked_table::contains(&tick_level.open_orders, order_id), EInvalidOrderId); + assert!(linked_table::contains(&tick_level.open_orders, order_id), EInvalidOrderId); let mut_tick_level = borrow_mut_leaf_by_index(open_orders, tick_index); - let order = linked_table::remove(&mut mut_tick_level.open_orders, order_id); + let order = linked_table::remove(&mut mut_tick_level.open_orders, order_id); assert!(order.owner == owner, EUnauthorizedCancel); - if (linked_table::is_empty(&mut_tick_level.open_orders)) { + if (linked_table::is_empty(&mut_tick_level.open_orders)) { destroy_empty_level(remove_leaf_by_index(open_orders, tick_index)); }; order @@ -3429,14 +3429,14 @@ Abort if order_id is invalid or if the order is not submitted by the transaction pool: &mut Pool<BaseAsset, QuoteAsset>, account_cap: &AccountCap ) { - let pool_id = *object::uid_as_inner(&pool.id); + let pool_id = *object::uid_as_inner(&pool.id); let owner = account_owner(account_cap); assert!(contains(&pool.usr_open_orders, owner), EInvalidUser); - let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, owner); + let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, owner); let mut canceled_order_events = vector[]; - while (!linked_table::is_empty(usr_open_order_ids)) { - let order_id = *option::borrow(linked_table::back(usr_open_order_ids)); - let order_price = *linked_table::borrow(usr_open_order_ids, order_id); + while (!linked_table::is_empty(usr_open_order_ids)) { + let order_id = *option::borrow(linked_table::back(usr_open_order_ids)); + let order_price = *linked_table::borrow(usr_open_order_ids, order_id); let is_bid = order_is_bid(order_id); let open_orders = if (is_bid) { &mut pool.bids } @@ -3469,7 +3469,7 @@ Abort if order_id is invalid or if the order is not submitted by the transaction }; if (!vector::is_empty(&canceled_order_events)) { - event::emit(AllOrdersCanceled<BaseAsset, QuoteAsset> { + event::emit(AllOrdersCanceled<BaseAsset, QuoteAsset> { pool_id, orders_canceled: canceled_order_events, }); @@ -3508,7 +3508,7 @@ Grouping order_ids like [0, 2, 1, 3] would make it the most gas efficient. order_ids: vector<u64>, account_cap: &AccountCap ) { - let pool_id = *object::uid_as_inner(&pool.id); + let pool_id = *object::uid_as_inner(&pool.id); // First group the order ids according to price level, // so that we don't have to retrieve the PriceLevel multiple times if there are orders at the same price level. // Iterate over each price level, retrieve the corresponding PriceLevel. @@ -3525,8 +3525,8 @@ Grouping order_ids like [0, 2, 1, 3] would make it the most gas efficient. while (i_order < n_order) { let order_id = *vector::borrow(&order_ids, i_order); - assert!(linked_table::contains(usr_open_orders, order_id), EInvalidOrderId); - let new_tick_price = *linked_table::borrow(usr_open_orders, order_id); + assert!(linked_table::contains(usr_open_orders, order_id), EInvalidOrderId); + let new_tick_price = *linked_table::borrow(usr_open_orders, order_id); let is_bid = order_is_bid(order_id); if (new_tick_price != tick_price) { tick_price = new_tick_price; @@ -3565,7 +3565,7 @@ Grouping order_ids like [0, 2, 1, 3] would make it the most gas efficient. }; if (!vector::is_empty(&canceled_order_events)) { - event::emit(AllOrdersCanceled<BaseAsset, QuoteAsset> { + event::emit(AllOrdersCanceled<BaseAsset, QuoteAsset> { pool_id, orders_canceled: canceled_order_events, }); @@ -3590,7 +3590,7 @@ Order owners should be the owner addresses from the account capacities which pla and they should correspond to the order IDs one by one. -
    public fun clean_up_expired_orders<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, clock: &clock::Clock, order_ids: vector<u64>, order_owners: vector<address>)
    +
    public fun clean_up_expired_orders<BaseAsset, QuoteAsset>(pool: &mut clob_v2::Pool<BaseAsset, QuoteAsset>, clock: &clock::Clock, order_ids: vector<u64>, order_owners: vector<address>)
     
    @@ -3601,12 +3601,12 @@ and they should correspond to the order IDs one by one.
    public fun clean_up_expired_orders<BaseAsset, QuoteAsset>(
         pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    clock: &Clock,
    +    clock: &Clock,
         order_ids: vector<u64>,
         order_owners: vector<address>
     ) {
    -    let pool_id = *object::uid_as_inner(&pool.id);
    -    let now = clock::timestamp_ms(clock);
    +    let pool_id = *object::uid_as_inner(&pool.id);
    +    let now = clock::timestamp_ms(clock);
         let n_order = vector::length(&order_ids);
         assert!(n_order == vector::length(&order_owners), ENotEqual);
         let mut i_order = 0;
    @@ -3616,10 +3616,10 @@ and they should correspond to the order IDs one by one.
         while (i_order < n_order) {
             let order_id = *vector::borrow(&order_ids, i_order);
             let owner = *vector::borrow(&order_owners, i_order);
    -        if (!table::contains(&pool.usr_open_orders, owner)) { continue };
    +        if (!table::contains(&pool.usr_open_orders, owner)) { continue };
             let usr_open_orders = borrow_mut(&mut pool.usr_open_orders, owner);
    -        if (!linked_table::contains(usr_open_orders, order_id)) { continue };
    -        let new_tick_price = *linked_table::borrow(usr_open_orders, order_id);
    +        if (!linked_table::contains(usr_open_orders, order_id)) { continue };
    +        let new_tick_price = *linked_table::borrow(usr_open_orders, order_id);
             let is_bid = order_is_bid(order_id);
             let open_orders = if (is_bid) { &mut pool.bids } else { &mut pool.asks };
             if (new_tick_price != tick_price) {
    @@ -3654,7 +3654,7 @@ and they should correspond to the order IDs one by one.
         };
     
         if (!vector::is_empty(&canceled_order_events)) {
    -        event::emit(AllOrdersCanceled<BaseAsset, QuoteAsset> {
    +        event::emit(AllOrdersCanceled<BaseAsset, QuoteAsset> {
                 pool_id,
                 orders_canceled: canceled_order_events,
             });
    @@ -3690,14 +3690,14 @@ and they should correspond to the order IDs one by one.
         if (!usr_open_orders_exist(pool, owner)) {
             return open_orders
         };
    -    let usr_open_order_ids = table::borrow(&pool.usr_open_orders, owner);
    -    let mut order_id = linked_table::front(usr_open_order_ids);
    +    let usr_open_order_ids = table::borrow(&pool.usr_open_orders, owner);
    +    let mut order_id = linked_table::front(usr_open_order_ids);
         while (!option::is_none(order_id)) {
    -        let order_price = *linked_table::borrow(usr_open_order_ids, *option::borrow(order_id));
    +        let order_price = *linked_table::borrow(usr_open_order_ids, *option::borrow(order_id));
             let tick_level =
                 if (order_is_bid(*option::borrow(order_id))) borrow_leaf_by_key(&pool.bids, order_price)
                 else borrow_leaf_by_key(&pool.asks, order_price);
    -        let order = linked_table::borrow(&tick_level.open_orders, *option::borrow(order_id));
    +        let order = linked_table::borrow(&tick_level.open_orders, *option::borrow(order_id));
             vector::push_back(&mut open_orders, Order {
                 order_id: order.order_id,
                 client_order_id: order.client_order_id,
    @@ -3709,7 +3709,7 @@ and they should correspond to the order IDs one by one.
                 expire_timestamp: order.expire_timestamp,
                 self_matching_prevention: order.self_matching_prevention
             });
    -        order_id = linked_table::next(usr_open_order_ids, *option::borrow(order_id));
    +        order_id = linked_table::next(usr_open_order_ids, *option::borrow(order_id));
         };
         open_orders
     }
    @@ -3801,7 +3801,7 @@ The previous is a list of all valid prices
     The latter is the corresponding depth list
     
     
    -
    public fun get_level2_book_status_bid_side<BaseAsset, QuoteAsset>(pool: &clob_v2::Pool<BaseAsset, QuoteAsset>, price_low: u64, price_high: u64, clock: &clock::Clock): (vector<u64>, vector<u64>)
    +
    public fun get_level2_book_status_bid_side<BaseAsset, QuoteAsset>(pool: &clob_v2::Pool<BaseAsset, QuoteAsset>, price_low: u64, price_high: u64, clock: &clock::Clock): (vector<u64>, vector<u64>)
     
    @@ -3814,7 +3814,7 @@ The latter is the corresponding depth list pool: &Pool<BaseAsset, QuoteAsset>, mut price_low: u64, mut price_high: u64, - clock: &Clock + clock: &Clock ): (vector<u64>, vector<u64>) { let mut price_vec = vector::empty<u64>(); let mut depth_vec = vector::empty<u64>(); @@ -3846,7 +3846,7 @@ The latter is the corresponding depth list let depth = get_level2_book_status( &pool.bids, price_low, - clock::timestamp_ms(clock) + clock::timestamp_ms(clock) ); if (depth != 0) { vector::push_back(&mut price_vec, price_low); @@ -3874,7 +3874,7 @@ The previous is a list of all valid prices The latter is the corresponding depth list -
    public fun get_level2_book_status_ask_side<BaseAsset, QuoteAsset>(pool: &clob_v2::Pool<BaseAsset, QuoteAsset>, price_low: u64, price_high: u64, clock: &clock::Clock): (vector<u64>, vector<u64>)
    +
    public fun get_level2_book_status_ask_side<BaseAsset, QuoteAsset>(pool: &clob_v2::Pool<BaseAsset, QuoteAsset>, price_low: u64, price_high: u64, clock: &clock::Clock): (vector<u64>, vector<u64>)
     
    @@ -3887,7 +3887,7 @@ The latter is the corresponding depth list pool: &Pool<BaseAsset, QuoteAsset>, mut price_low: u64, mut price_high: u64, - clock: &Clock + clock: &Clock ): (vector<u64>, vector<u64>) { let mut price_vec = vector::empty<u64>(); let mut depth_vec = vector::empty<u64>(); @@ -3919,7 +3919,7 @@ The latter is the corresponding depth list let depth = get_level2_book_status( &pool.asks, price_low, - clock::timestamp_ms(clock) + clock::timestamp_ms(clock) ); if (depth != 0) { vector::push_back(&mut price_vec, price_low); @@ -3961,12 +3961,12 @@ internal func to retrive single depth of a tick price let tick_level = critbit::borrow_leaf_by_key(open_orders, price); let tick_open_orders = &tick_level.open_orders; let mut depth = 0; - let mut order_id = linked_table::front(tick_open_orders); + let mut order_id = linked_table::front(tick_open_orders); let mut order: &Order; while (!option::is_none(order_id)) { - order = linked_table::borrow(tick_open_orders, *option::borrow(order_id)); + order = linked_table::borrow(tick_open_orders, *option::borrow(order_id)); if (order.expire_timestamp > time_stamp) depth = depth + order.quantity; - order_id = linked_table::next(tick_open_orders, *option::borrow(order_id)); + order_id = linked_table::next(tick_open_orders, *option::borrow(order_id)); }; depth } @@ -3997,16 +3997,16 @@ internal func to retrive single depth of a tick price account_cap: &AccountCap ): &Order { let owner = account_owner(account_cap); - assert!(table::contains(&pool.usr_open_orders, owner), EInvalidUser); - let usr_open_order_ids = table::borrow(&pool.usr_open_orders, owner); - assert!(linked_table::contains(usr_open_order_ids, order_id), EInvalidOrderId); - let order_price = *linked_table::borrow(usr_open_order_ids, order_id); + assert!(table::contains(&pool.usr_open_orders, owner), EInvalidUser); + let usr_open_order_ids = table::borrow(&pool.usr_open_orders, owner); + assert!(linked_table::contains(usr_open_order_ids, order_id), EInvalidOrderId); + let order_price = *linked_table::borrow(usr_open_order_ids, order_id); let open_orders = if (order_id < MIN_ASK_ORDER_ID) { &pool.bids } else { &pool.asks }; let tick_level = critbit::borrow_leaf_by_key(open_orders, order_price); let tick_open_orders = &tick_level.open_orders; - let order = linked_table::borrow(tick_open_orders, order_id); + let order = linked_table::borrow(tick_open_orders, order_id); order }
    @@ -4021,7 +4021,7 @@ internal func to retrive single depth of a tick price -
    fun matched_order_metadata<BaseAsset, QuoteAsset>(pool_id: object::ID, taker_address: address, order: &clob_v2::Order, base_asset_quantity_filled: u64, taker_commission: u64, maker_rebates: u64): clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>
    +
    fun matched_order_metadata<BaseAsset, QuoteAsset>(pool_id: object::ID, taker_address: address, order: &clob_v2::Order, base_asset_quantity_filled: u64, taker_commission: u64, maker_rebates: u64): clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>
     
    @@ -4062,7 +4062,7 @@ internal func to retrive single depth of a tick price -
    public fun matched_order_metadata_info<BaseAsset, QuoteAsset>(matched_order_metadata: &clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>): (object::ID, u64, bool, address, address, u64, u64, u64, u64)
    +
    public fun matched_order_metadata_info<BaseAsset, QuoteAsset>(matched_order_metadata: &clob_v2::MatchedOrderMetadata<BaseAsset, QuoteAsset>): (object::ID, u64, bool, address, address, u64, u64, u64, u64)
     
    @@ -4242,7 +4242,7 @@ internal func to retrive single depth of a tick price -
    public fun open_orders(tick_level: &clob_v2::TickLevel): &linked_table::LinkedTable<u64, clob_v2::Order>
    +
    public fun open_orders(tick_level: &clob_v2::TickLevel): &linked_table::LinkedTable<u64, clob_v2::Order>
     
    @@ -4444,7 +4444,7 @@ internal func to retrive single depth of a tick price
    public fun quote_asset_trading_fees_value<BaseAsset, QuoteAsset>(pool: &Pool<BaseAsset, QuoteAsset>): u64 {
    -    balance::value(&pool.quote_asset_trading_fees)
    +    balance::value(&pool.quote_asset_trading_fees)
     }
     
    diff --git a/crates/sui-framework/docs/deepbook/critbit.md b/crates/iota-framework/docs/deepbook/critbit.md similarity index 82% rename from crates/sui-framework/docs/deepbook/critbit.md rename to crates/iota-framework/docs/deepbook/critbit.md index 7b86d7731e6..abfc8c22396 100644 --- a/crates/sui-framework/docs/deepbook/critbit.md +++ b/crates/iota-framework/docs/deepbook/critbit.md @@ -31,8 +31,8 @@ title: Module `0xdee9::critbit` - [Function `is_left_child`](#0xdee9_critbit_is_left_child) -
    use 0x2::table;
    -use 0x2::tx_context;
    +
    use 0x2::table;
    +use 0x2::tx_context;
     use 0xdee9::math;
     
    @@ -145,13 +145,13 @@ title: Module `0xdee9::critbit`
    -internal_nodes: table::Table<u64, critbit::InternalNode> +internal_nodes: table::Table<u64, critbit::InternalNode>
    -leaves: table::Table<u64, critbit::Leaf<V>> +leaves: table::Table<u64, critbit::Leaf<V>>
    @@ -277,7 +277,7 @@ title: Module `0xdee9::critbit` -
    public(friend) fun new<V: store>(ctx: &mut tx_context::TxContext): critbit::CritbitTree<V>
    +
    public(friend) fun new<V: store>(ctx: &mut tx_context::TxContext): critbit::CritbitTree<V>
     
    @@ -289,8 +289,8 @@ title: Module `0xdee9::critbit`
    public(package) fun new<V: store>(ctx: &mut TxContext): CritbitTree<V> {
         CritbitTree<V> {
             root: PARTITION_INDEX,
    -        internal_nodes: table::new(ctx),
    -        leaves: table::new(ctx),
    +        internal_nodes: table::new(ctx),
    +        leaves: table::new(ctx),
             min_leaf: PARTITION_INDEX,
             max_leaf: PARTITION_INDEX,
             next_internal_node_index: 0,
    @@ -319,7 +319,7 @@ title: Module `0xdee9::critbit`
     
     
     
    public(package) fun size<V: store>(tree: &CritbitTree<V>): u64 {
    -    table::length(&tree.leaves)
    +    table::length(&tree.leaves)
     }
     
    @@ -343,7 +343,7 @@ title: Module `0xdee9::critbit`
    public(package) fun is_empty<V: store>(tree: &CritbitTree<V>): bool {
    -    table::is_empty(&tree.leaves)
    +    table::is_empty(&tree.leaves)
     }
     
    @@ -368,7 +368,7 @@ title: Module `0xdee9::critbit`
    public fun min_leaf<V: store>(tree: &CritbitTree<V>): (u64, u64) {
         assert!(!is_empty(tree), ELeafNotExist);
    -    let min_leaf = table::borrow(&tree.leaves, tree.min_leaf);
    +    let min_leaf = table::borrow(&tree.leaves, tree.min_leaf);
         return (min_leaf.key, tree.min_leaf)
     }
     
    @@ -394,7 +394,7 @@ title: Module `0xdee9::critbit`
    public fun max_leaf<V: store>(tree: &CritbitTree<V>): (u64, u64) {
         assert!(!is_empty(tree), ELeafNotExist);
    -    let max_leaf = table::borrow(&tree.leaves, tree.max_leaf);
    +    let max_leaf = table::borrow(&tree.leaves, tree.max_leaf);
         return (max_leaf.key, tree.max_leaf)
     }
     
    @@ -422,16 +422,16 @@ title: Module `0xdee9::critbit` let (_, mut index) = find_leaf(tree, key); assert!(index != PARTITION_INDEX, ELeafNotExist); let mut ptr = MAX_U64 - index; - let mut parent = table::borrow(&tree.leaves, index).parent; + let mut parent = table::borrow(&tree.leaves, index).parent; while (parent != PARTITION_INDEX && is_left_child(tree, parent, ptr)){ ptr = parent; - parent = table::borrow(&tree.internal_nodes, ptr).parent; + parent = table::borrow(&tree.internal_nodes, ptr).parent; }; if(parent == PARTITION_INDEX) { return (0, PARTITION_INDEX) }; - index = MAX_U64 - right_most_leaf(tree, table::borrow(&tree.internal_nodes, parent).left_child); - let key = table::borrow(&tree.leaves, index).key; + index = MAX_U64 - right_most_leaf(tree, table::borrow(&tree.internal_nodes, parent).left_child); + let key = table::borrow(&tree.leaves, index).key; return (key, index) }
    @@ -459,16 +459,16 @@ title: Module `0xdee9::critbit` let (_, mut index) = find_leaf(tree, key); assert!(index != PARTITION_INDEX, ELeafNotExist); let mut ptr = MAX_U64 - index; - let mut parent = table::borrow(&tree.leaves, index).parent; + let mut parent = table::borrow(&tree.leaves, index).parent; while (parent != PARTITION_INDEX && !is_left_child(tree, parent, ptr)){ ptr = parent; - parent = table::borrow(&tree.internal_nodes, ptr).parent; + parent = table::borrow(&tree.internal_nodes, ptr).parent; }; if(parent == PARTITION_INDEX) { return (0, PARTITION_INDEX) }; - index = MAX_U64 - left_most_leaf(tree, table::borrow(&tree.internal_nodes, parent).right_child); - let key = table::borrow(&tree.leaves, index).key; + index = MAX_U64 - left_most_leaf(tree, table::borrow(&tree.internal_nodes, parent).right_child); + let key = table::borrow(&tree.leaves, index).key; return (key, index) }
    @@ -495,7 +495,7 @@ title: Module `0xdee9::critbit`
    fun left_most_leaf<V: store>(tree: &CritbitTree<V>, root: u64): u64 {
         let mut ptr = root;
         while (ptr < PARTITION_INDEX){
    -        ptr = table::borrow(& tree.internal_nodes, ptr).left_child;
    +        ptr = table::borrow(& tree.internal_nodes, ptr).left_child;
         };
         ptr
     }
    @@ -523,7 +523,7 @@ title: Module `0xdee9::critbit`
     
    fun right_most_leaf<V: store>(tree: &CritbitTree<V>, root: u64): u64 {
         let mut ptr = root;
         while (ptr < PARTITION_INDEX){
    -        ptr = table::borrow(& tree.internal_nodes, ptr).right_child;
    +        ptr = table::borrow(& tree.internal_nodes, ptr).right_child;
         };
         ptr
     }
    @@ -557,7 +557,7 @@ title: Module `0xdee9::critbit`
         let new_leaf_index = tree.next_leaf_index;
         tree.next_leaf_index = tree.next_leaf_index + 1;
         assert!(new_leaf_index < MAX_CAPACITY - 1, EExceedCapacity);
    -    table::add(&mut tree.leaves, new_leaf_index, new_leaf);
    +    table::add(&mut tree.leaves, new_leaf_index, new_leaf);
     
         let closest_leaf_index = get_closest_leaf_index_by_key(tree, key);
     
    @@ -570,7 +570,7 @@ title: Module `0xdee9::critbit`
             return 0
         };
     
    -    let closest_key = table::borrow(&tree.leaves, closest_leaf_index).key;
    +    let closest_key = table::borrow(&tree.leaves, closest_leaf_index).key;
         assert!(closest_key != key, EKeyAlreadyExist);
     
         // Note that we reserve count_leading_zeros of form u128 for future use
    @@ -585,13 +585,13 @@ title: Module `0xdee9::critbit`
         };
         let new_internal_node_index = tree.next_internal_node_index;
         tree.next_internal_node_index = tree.next_internal_node_index + 1;
    -    table::add(&mut tree.internal_nodes, new_internal_node_index, new_internal_node);
    +    table::add(&mut tree.internal_nodes, new_internal_node_index, new_internal_node);
     
         let mut ptr = tree.root;
         let mut new_internal_node_parent_index = PARTITION_INDEX;
         // Search position of the new internal node
         while (ptr < PARTITION_INDEX) {
    -        let internal_node = table::borrow(&tree.internal_nodes, ptr);
    +        let internal_node = table::borrow(&tree.internal_nodes, ptr);
             if (new_mask > internal_node.mask) {
                 break
             };
    @@ -619,10 +619,10 @@ title: Module `0xdee9::critbit`
         update_child(tree, new_internal_node_index, MAX_U64 - new_leaf_index, is_left_child);
         update_child(tree, new_internal_node_index, ptr, !is_left_child);
     
    -    if (table::borrow(&tree.leaves, tree.min_leaf).key > key) {
    +    if (table::borrow(&tree.leaves, tree.min_leaf).key > key) {
             tree.min_leaf = new_leaf_index;
         };
    -    if (table::borrow(&tree.leaves, tree.max_leaf).key < key) {
    +    if (table::borrow(&tree.leaves, tree.max_leaf).key < key) {
             tree.max_leaf = new_leaf_index;
         };
         new_leaf_index
    @@ -653,7 +653,7 @@ title: Module `0xdee9::critbit`
             return (false, PARTITION_INDEX)
         };
         let closest_leaf_index = get_closest_leaf_index_by_key(tree, key);
    -    let closeset_leaf = table::borrow(&tree.leaves, closest_leaf_index);
    +    let closeset_leaf = table::borrow(&tree.leaves, closest_leaf_index);
         if (closeset_leaf.key != key){
             return (false, PARTITION_INDEX)
         } else{
    @@ -686,7 +686,7 @@ title: Module `0xdee9::critbit`
             return 0
         };
         let closest_leaf_index = get_closest_leaf_index_by_key(tree, key);
    -    let closeset_leaf = table::borrow(&tree.leaves, closest_leaf_index);
    +    let closeset_leaf = table::borrow(&tree.leaves, closest_leaf_index);
         closeset_leaf.key
     }
     
    @@ -711,7 +711,7 @@ title: Module `0xdee9::critbit`
    public(package) fun remove_leaf_by_index<V: store>(tree: &mut CritbitTree<V>, index: u64): V {
    -    let key = table::borrow(& tree.leaves, index).key;
    +    let key = table::borrow(& tree.leaves, index).key;
         if (tree.min_leaf == index) {
             let (_, index) = next_leaf(tree, key);
             tree.min_leaf = index;
    @@ -722,7 +722,7 @@ title: Module `0xdee9::critbit`
         };
     
         let mut is_left_child_;
    -    let Leaf<V> {key: _, value, parent: removed_leaf_parent_index} = table::remove(&mut tree.leaves, index);
    +    let Leaf<V> {key: _, value, parent: removed_leaf_parent_index} = table::remove(&mut tree.leaves, index);
     
         if (size(tree) == 0) {
             tree.root = PARTITION_INDEX;
    @@ -732,7 +732,7 @@ title: Module `0xdee9::critbit`
             tree.next_leaf_index = 0;
         } else {
             assert!(removed_leaf_parent_index != PARTITION_INDEX, EIndexOutOfRange);
    -        let removed_leaf_parent = table::borrow(&tree.internal_nodes, removed_leaf_parent_index);
    +        let removed_leaf_parent = table::borrow(&tree.internal_nodes, removed_leaf_parent_index);
             let removed_leaf_grand_parent_index = removed_leaf_parent.parent;
     
             // Note that sibling of the removed leaf can be a leaf or an internal node
    @@ -745,10 +745,10 @@ title: Module `0xdee9::critbit`
                 // Update the parent of the sibling node and and set sibling as the tree root
                 if (sibling_index < PARTITION_INDEX) {
                     // sibling is an internal node
    -                table::borrow_mut(&mut tree.internal_nodes, sibling_index).parent = PARTITION_INDEX;
    +                table::borrow_mut(&mut tree.internal_nodes, sibling_index).parent = PARTITION_INDEX;
                 } else{
                     // sibling is a leaf
    -                table::borrow_mut(&mut tree.leaves, MAX_U64 - sibling_index).parent = PARTITION_INDEX;
    +                table::borrow_mut(&mut tree.leaves, MAX_U64 - sibling_index).parent = PARTITION_INDEX;
                 };
                 tree.root = sibling_index;
             } else {
    @@ -757,7 +757,7 @@ title: Module `0xdee9::critbit`
                 is_left_child_ = is_left_child(tree, removed_leaf_grand_parent_index, removed_leaf_parent_index);
                 update_child(tree, removed_leaf_grand_parent_index, sibling_index, is_left_child_);
             };
    -        table::remove(&mut tree.internal_nodes, removed_leaf_parent_index);
    +        table::remove(&mut tree.internal_nodes, removed_leaf_parent_index);
         };
         value
     }
    @@ -783,7 +783,7 @@ title: Module `0xdee9::critbit`
     
     
     
    public(package) fun borrow_mut_leaf_by_index<V: store>(tree: &mut CritbitTree<V>, index: u64): &mut V {
    -    let entry = table::borrow_mut(&mut tree.leaves, index);
    +    let entry = table::borrow_mut(&mut tree.leaves, index);
         &mut entry.value
     }
     
    @@ -808,7 +808,7 @@ title: Module `0xdee9::critbit`
    public fun borrow_leaf_by_index<V: store>(tree: & CritbitTree<V>, index: u64): &V {
    -    let entry = table::borrow(&tree.leaves, index);
    +    let entry = table::borrow(&tree.leaves, index);
         &entry.value
     }
     
    @@ -869,8 +869,8 @@ title: Module `0xdee9::critbit` next_leaf_index: _, } = tree; - table::drop(internal_nodes); - table::drop(leaves); + table::drop(internal_nodes); + table::drop(leaves); }
    @@ -894,7 +894,7 @@ title: Module `0xdee9::critbit`
    public(package) fun destroy_empty<V: store>(tree: CritbitTree<V>) {
    -    assert!(table::length(&tree.leaves) == 0, 0);
    +    assert!(table::length(&tree.leaves) == 0, 0);
     
         let CritbitTree<V> {
             root: _,
    @@ -906,8 +906,8 @@ title: Module `0xdee9::critbit`
             next_leaf_index: _
         } = tree;
     
    -    table::destroy_empty(leaves);
    -    table::destroy_empty(internal_nodes);
    +    table::destroy_empty(leaves);
    +    table::destroy_empty(internal_nodes);
     }
     
    @@ -935,7 +935,7 @@ title: Module `0xdee9::critbit` // if tree is empty, return the patrition index if(ptr == PARTITION_INDEX) return PARTITION_INDEX; while (ptr < PARTITION_INDEX){ - let node = table::borrow(&tree.internal_nodes, ptr); + let node = table::borrow(&tree.internal_nodes, ptr); if (key & node.mask == 0){ ptr = node.left_child; } else { @@ -968,14 +968,14 @@ title: Module `0xdee9::critbit`
    fun update_child<V: store>(tree: &mut CritbitTree<V>, parent_index: u64, new_child: u64, is_left_child: bool) {
         assert!(parent_index != PARTITION_INDEX, ENullParent);
         if (is_left_child) {
    -        table::borrow_mut(&mut tree.internal_nodes, parent_index).left_child = new_child;
    +        table::borrow_mut(&mut tree.internal_nodes, parent_index).left_child = new_child;
         } else{
    -        table::borrow_mut(&mut tree.internal_nodes, parent_index).right_child = new_child;
    +        table::borrow_mut(&mut tree.internal_nodes, parent_index).right_child = new_child;
         };
         if (new_child > PARTITION_INDEX) {
    -        table::borrow_mut(&mut tree.leaves, MAX_U64 - new_child).parent = parent_index;
    +        table::borrow_mut(&mut tree.leaves, MAX_U64 - new_child).parent = parent_index;
         } else {
    -        table::borrow_mut(&mut tree.internal_nodes, new_child).parent = parent_index;
    +        table::borrow_mut(&mut tree.internal_nodes, new_child).parent = parent_index;
         }
     }
     
    @@ -1000,7 +1000,7 @@ title: Module `0xdee9::critbit`
    fun is_left_child<V: store>(tree: &CritbitTree<V>, parent_index: u64, index: u64): bool {
    -    table::borrow(&tree.internal_nodes, parent_index).left_child == index
    +    table::borrow(&tree.internal_nodes, parent_index).left_child == index
     }
     
    diff --git a/crates/iota-framework/docs/deepbook/custodian.md b/crates/iota-framework/docs/deepbook/custodian.md new file mode 100644 index 00000000000..a09cca529ad --- /dev/null +++ b/crates/iota-framework/docs/deepbook/custodian.md @@ -0,0 +1,504 @@ +--- +title: Module `0xdee9::custodian` +--- + + + +- [Struct `Account`](#0xdee9_custodian_Account) +- [Resource `AccountCap`](#0xdee9_custodian_AccountCap) +- [Resource `Custodian`](#0xdee9_custodian_Custodian) +- [Function `mint_account_cap`](#0xdee9_custodian_mint_account_cap) +- [Function `account_balance`](#0xdee9_custodian_account_balance) +- [Function `new`](#0xdee9_custodian_new) +- [Function `withdraw_asset`](#0xdee9_custodian_withdraw_asset) +- [Function `increase_user_available_balance`](#0xdee9_custodian_increase_user_available_balance) +- [Function `decrease_user_available_balance`](#0xdee9_custodian_decrease_user_available_balance) +- [Function `increase_user_locked_balance`](#0xdee9_custodian_increase_user_locked_balance) +- [Function `decrease_user_locked_balance`](#0xdee9_custodian_decrease_user_locked_balance) +- [Function `lock_balance`](#0xdee9_custodian_lock_balance) +- [Function `unlock_balance`](#0xdee9_custodian_unlock_balance) +- [Function `account_available_balance`](#0xdee9_custodian_account_available_balance) +- [Function `account_locked_balance`](#0xdee9_custodian_account_locked_balance) +- [Function `borrow_mut_account_balance`](#0xdee9_custodian_borrow_mut_account_balance) + + +
    use 0x2::balance;
    +use 0x2::coin;
    +use 0x2::object;
    +use 0x2::table;
    +use 0x2::tx_context;
    +
    + + + + + +## Struct `Account` + + + +
    struct Account<T> has store
    +
    + + + +
    +Fields + + +
    +
    +available_balance: balance::Balance<T> +
    +
    + +
    +
    +locked_balance: balance::Balance<T> +
    +
    + +
    +
    + + +
    + + + +## Resource `AccountCap` + + + +
    struct AccountCap has store, key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    + + +
    + + + +## Resource `Custodian` + + + +
    struct Custodian<T> has store, key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +account_balances: table::Table<object::ID, custodian::Account<T>> +
    +
    + Map from an AccountCap object ID to an Account object +
    +
    + + +
    + + + +## Function `mint_account_cap` + +Create an AccountCap that can be used across all DeepBook pool + + +
    public fun mint_account_cap(ctx: &mut tx_context::TxContext): custodian::AccountCap
    +
    + + + +
    +Implementation + + +
    public fun mint_account_cap(ctx: &mut TxContext): AccountCap {
    +    AccountCap { id: object::new(ctx) }
    +}
    +
    + + + +
    + + + +## Function `account_balance` + + + +
    public(friend) fun account_balance<Asset>(custodian: &custodian::Custodian<Asset>, user: object::ID): (u64, u64)
    +
    + + + +
    +Implementation + + +
    public(package) fun account_balance<Asset>(
    +    custodian: &Custodian<Asset>,
    +    user: ID
    +): (u64, u64) {
    +    // if custodian account is not created yet, directly return (0, 0) rather than abort
    +    if (!table::contains(&custodian.account_balances, user)) {
    +        return (0, 0)
    +    };
    +    let account_balances = table::borrow(&custodian.account_balances, user);
    +    let avail_balance = balance::value(&account_balances.available_balance);
    +    let locked_balance = balance::value(&account_balances.locked_balance);
    +    (avail_balance, locked_balance)
    +}
    +
    + + + +
    + + + +## Function `new` + + + +
    public(friend) fun new<T>(ctx: &mut tx_context::TxContext): custodian::Custodian<T>
    +
    + + + +
    +Implementation + + +
    public(package) fun new<T>(ctx: &mut TxContext): Custodian<T> {
    +    Custodian<T> {
    +        id: object::new(ctx),
    +        account_balances: table::new(ctx),
    +    }
    +}
    +
    + + + +
    + + + +## Function `withdraw_asset` + + + +
    public(friend) fun withdraw_asset<Asset>(custodian: &mut custodian::Custodian<Asset>, quantity: u64, account_cap: &custodian::AccountCap, ctx: &mut tx_context::TxContext): coin::Coin<Asset>
    +
    + + + +
    +Implementation + + +
    public(package) fun withdraw_asset<Asset>(
    +    custodian: &mut Custodian<Asset>,
    +    quantity: u64,
    +    account_cap: &AccountCap,
    +    ctx: &mut TxContext
    +): Coin<Asset> {
    +    coin::from_balance(decrease_user_available_balance<Asset>(custodian, account_cap, quantity), ctx)
    +}
    +
    + + + +
    + + + +## Function `increase_user_available_balance` + + + +
    public(friend) fun increase_user_available_balance<T>(custodian: &mut custodian::Custodian<T>, user: object::ID, quantity: balance::Balance<T>)
    +
    + + + +
    +Implementation + + +
    public(package) fun increase_user_available_balance<T>(
    +    custodian: &mut Custodian<T>,
    +    user: ID,
    +    quantity: Balance<T>,
    +) {
    +    let account = borrow_mut_account_balance<T>(custodian, user);
    +    balance::join(&mut account.available_balance, quantity);
    +}
    +
    + + + +
    + + + +## Function `decrease_user_available_balance` + + + +
    public(friend) fun decrease_user_available_balance<T>(custodian: &mut custodian::Custodian<T>, account_cap: &custodian::AccountCap, quantity: u64): balance::Balance<T>
    +
    + + + +
    +Implementation + + +
    public(package) fun decrease_user_available_balance<T>(
    +    custodian: &mut Custodian<T>,
    +    account_cap: &AccountCap,
    +    quantity: u64,
    +): Balance<T> {
    +    let account = borrow_mut_account_balance<T>(custodian, object::uid_to_inner(&account_cap.id));
    +    balance::split(&mut account.available_balance, quantity)
    +}
    +
    + + + +
    + + + +## Function `increase_user_locked_balance` + + + +
    public(friend) fun increase_user_locked_balance<T>(custodian: &mut custodian::Custodian<T>, account_cap: &custodian::AccountCap, quantity: balance::Balance<T>)
    +
    + + + +
    +Implementation + + +
    public(package) fun increase_user_locked_balance<T>(
    +    custodian: &mut Custodian<T>,
    +    account_cap: &AccountCap,
    +    quantity: Balance<T>,
    +) {
    +    let account = borrow_mut_account_balance<T>(custodian, object::uid_to_inner(&account_cap.id));
    +    balance::join(&mut account.locked_balance, quantity);
    +}
    +
    + + + +
    + + + +## Function `decrease_user_locked_balance` + + + +
    public(friend) fun decrease_user_locked_balance<T>(custodian: &mut custodian::Custodian<T>, user: object::ID, quantity: u64): balance::Balance<T>
    +
    + + + +
    +Implementation + + +
    public(package) fun decrease_user_locked_balance<T>(
    +    custodian: &mut Custodian<T>,
    +    user: ID,
    +    quantity: u64,
    +): Balance<T> {
    +    let account = borrow_mut_account_balance<T>(custodian, user);
    +    split(&mut account.locked_balance, quantity)
    +}
    +
    + + + +
    + + + +## Function `lock_balance` + +Move quantity from the unlocked balance of user to the locked balance of user + + +
    public(friend) fun lock_balance<T>(custodian: &mut custodian::Custodian<T>, account_cap: &custodian::AccountCap, quantity: u64)
    +
    + + + +
    +Implementation + + +
    public(package) fun lock_balance<T>(
    +    custodian: &mut Custodian<T>,
    +    account_cap: &AccountCap,
    +    quantity: u64,
    +) {
    +    let to_lock = decrease_user_available_balance(custodian, account_cap, quantity);
    +    increase_user_locked_balance(custodian, account_cap, to_lock);
    +}
    +
    + + + +
    + + + +## Function `unlock_balance` + +Move quantity from the locked balance of user to the unlocked balacne of user + + +
    public(friend) fun unlock_balance<T>(custodian: &mut custodian::Custodian<T>, user: object::ID, quantity: u64)
    +
    + + + +
    +Implementation + + +
    public(package) fun unlock_balance<T>(
    +    custodian: &mut Custodian<T>,
    +    user: ID,
    +    quantity: u64,
    +) {
    +    let locked_balance = decrease_user_locked_balance<T>(custodian, user, quantity);
    +    increase_user_available_balance<T>(custodian, user, locked_balance)
    +}
    +
    + + + +
    + + + +## Function `account_available_balance` + + + +
    public(friend) fun account_available_balance<T>(custodian: &custodian::Custodian<T>, user: object::ID): u64
    +
    + + + +
    +Implementation + + +
    public(package) fun account_available_balance<T>(
    +    custodian: &Custodian<T>,
    +    user: ID,
    +): u64 {
    +    balance::value(&table::borrow(&custodian.account_balances, user).available_balance)
    +}
    +
    + + + +
    + + + +## Function `account_locked_balance` + + + +
    public(friend) fun account_locked_balance<T>(custodian: &custodian::Custodian<T>, user: object::ID): u64
    +
    + + + +
    +Implementation + + +
    public(package) fun account_locked_balance<T>(
    +    custodian: &Custodian<T>,
    +    user: ID,
    +): u64 {
    +    balance::value(&table::borrow(&custodian.account_balances, user).locked_balance)
    +}
    +
    + + + +
    + + + +## Function `borrow_mut_account_balance` + + + +
    fun borrow_mut_account_balance<T>(custodian: &mut custodian::Custodian<T>, user: object::ID): &mut custodian::Account<T>
    +
    + + + +
    +Implementation + + +
    fun borrow_mut_account_balance<T>(
    +    custodian: &mut Custodian<T>,
    +    user: ID,
    +): &mut Account<T> {
    +    if (!table::contains(&custodian.account_balances, user)) {
    +        table::add(
    +            &mut custodian.account_balances,
    +            user,
    +            Account { available_balance: balance::zero(), locked_balance: balance::zero() }
    +        );
    +    };
    +    table::borrow_mut(&mut custodian.account_balances, user)
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/deepbook/custodian_v2.md b/crates/iota-framework/docs/deepbook/custodian_v2.md similarity index 78% rename from crates/sui-framework/docs/deepbook/custodian_v2.md rename to crates/iota-framework/docs/deepbook/custodian_v2.md index 371ccf8324d..dc5aa8e9177 100644 --- a/crates/sui-framework/docs/deepbook/custodian_v2.md +++ b/crates/iota-framework/docs/deepbook/custodian_v2.md @@ -26,11 +26,11 @@ title: Module `0xdee9::custodian_v2` - [Function `borrow_mut_account_balance`](#0xdee9_custodian_v2_borrow_mut_account_balance) -
    use 0x2::balance;
    -use 0x2::coin;
    -use 0x2::object;
    -use 0x2::table;
    -use 0x2::tx_context;
    +
    use 0x2::balance;
    +use 0x2::coin;
    +use 0x2::object;
    +use 0x2::table;
    +use 0x2::tx_context;
     
    @@ -52,13 +52,13 @@ title: Module `0xdee9::custodian_v2`
    -available_balance: balance::Balance<T> +available_balance: balance::Balance<T>
    -locked_balance: balance::Balance<T> +locked_balance: balance::Balance<T>
    @@ -90,7 +90,7 @@ that can access funds, but cannot create new object::UID +id: object::UID
    @@ -124,13 +124,13 @@ that can access funds, but cannot create new object::UID +id: object::UID
    -account_balances: table::Table<address, custodian_v2::Account<T>> +account_balances: table::Table<address, custodian_v2::Account<T>>
    Map from the owner address of AccountCap object to an Account object @@ -162,7 +162,7 @@ Create an admin A the permission to create new AccountCaps that can access the same source of funds -
    public(friend) fun mint_account_cap(ctx: &mut tx_context::TxContext): custodian_v2::AccountCap
    +
    public(friend) fun mint_account_cap(ctx: &mut tx_context::TxContext): custodian_v2::AccountCap
     
    @@ -172,8 +172,8 @@ the permission to create new mint_account_cap(ctx: &mut TxContext): AccountCap { - let id = object::new(ctx); - let owner = object::uid_to_address(&id); + let id = object::new(ctx); + let owner = object::uid_to_address(&id); AccountCap { id, owner } }
    @@ -190,7 +190,7 @@ Create a "child account cap" such that id != owner that can access funds, but cannot create new AccountCaps. -
    public fun create_child_account_cap(admin_account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): custodian_v2::AccountCap
    +
    public fun create_child_account_cap(admin_account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): custodian_v2::AccountCap
     
    @@ -201,10 +201,10 @@ that can access funds, but cannot create new create_child_account_cap(admin_account_cap: &AccountCap, ctx: &mut TxContext): AccountCap { // Only the admin account cap can create new account caps - assert!(object::uid_to_address(&admin_account_cap.id) == admin_account_cap.owner, EAdminAccountCapRequired); + assert!(object::uid_to_address(&admin_account_cap.id) == admin_account_cap.owner, EAdminAccountCapRequired); AccountCap { - id: object::new(ctx), + id: object::new(ctx), owner: admin_account_cap.owner } } @@ -232,7 +232,7 @@ Destroy the given account_cap object
    public fun delete_account_cap(account_cap: AccountCap) {
         let AccountCap { id, owner: _ } = account_cap;
    -    object::delete(id)
    +    object::delete(id)
     }
     
    @@ -285,12 +285,12 @@ Return the owner of an AccountCap owner: address ): (u64, u64) { // if custodian account is not created yet, directly return (0, 0) rather than abort - if (!table::contains(&custodian.account_balances, owner)) { + if (!table::contains(&custodian.account_balances, owner)) { return (0, 0) }; - let account_balances = table::borrow(&custodian.account_balances, owner); - let avail_balance = balance::value(&account_balances.available_balance); - let locked_balance = balance::value(&account_balances.locked_balance); + let account_balances = table::borrow(&custodian.account_balances, owner); + let avail_balance = balance::value(&account_balances.available_balance); + let locked_balance = balance::value(&account_balances.locked_balance); (avail_balance, locked_balance) }
    @@ -305,7 +305,7 @@ Return the owner of an AccountCap -
    public(friend) fun new<T>(ctx: &mut tx_context::TxContext): custodian_v2::Custodian<T>
    +
    public(friend) fun new<T>(ctx: &mut tx_context::TxContext): custodian_v2::Custodian<T>
     
    @@ -316,8 +316,8 @@ Return the owner of an AccountCap
    public(package) fun new<T>(ctx: &mut TxContext): Custodian<T> {
         Custodian<T> {
    -        id: object::new(ctx),
    -        account_balances: table::new(ctx),
    +        id: object::new(ctx),
    +        account_balances: table::new(ctx),
         }
     }
     
    @@ -332,7 +332,7 @@ Return the owner of an AccountCap -
    public(friend) fun withdraw_asset<Asset>(custodian: &mut custodian_v2::Custodian<Asset>, quantity: u64, account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): coin::Coin<Asset>
    +
    public(friend) fun withdraw_asset<Asset>(custodian: &mut custodian_v2::Custodian<Asset>, quantity: u64, account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): coin::Coin<Asset>
     
    @@ -347,7 +347,7 @@ Return the owner of an AccountCap account_cap: &AccountCap, ctx: &mut TxContext ): Coin<Asset> { - coin::from_balance(decrease_user_available_balance<Asset>(custodian, account_cap, quantity), ctx) + coin::from_balance(decrease_user_available_balance<Asset>(custodian, account_cap, quantity), ctx) }
    @@ -361,7 +361,7 @@ Return the owner of an AccountCap -
    public(friend) fun increase_user_available_balance<T>(custodian: &mut custodian_v2::Custodian<T>, owner: address, quantity: balance::Balance<T>)
    +
    public(friend) fun increase_user_available_balance<T>(custodian: &mut custodian_v2::Custodian<T>, owner: address, quantity: balance::Balance<T>)
     
    @@ -376,7 +376,7 @@ Return the owner of an AccountCap quantity: Balance<T>, ) { let account = borrow_mut_account_balance<T>(custodian, owner); - balance::join(&mut account.available_balance, quantity); + balance::join(&mut account.available_balance, quantity); }
    @@ -390,7 +390,7 @@ Return the owner of an AccountCap -
    public(friend) fun decrease_user_available_balance<T>(custodian: &mut custodian_v2::Custodian<T>, account_cap: &custodian_v2::AccountCap, quantity: u64): balance::Balance<T>
    +
    public(friend) fun decrease_user_available_balance<T>(custodian: &mut custodian_v2::Custodian<T>, account_cap: &custodian_v2::AccountCap, quantity: u64): balance::Balance<T>
     
    @@ -405,7 +405,7 @@ Return the owner of an AccountCap quantity: u64, ): Balance<T> { let account = borrow_mut_account_balance<T>(custodian, account_cap.owner); - balance::split(&mut account.available_balance, quantity) + balance::split(&mut account.available_balance, quantity) }
    @@ -419,7 +419,7 @@ Return the owner of an AccountCap -
    public(friend) fun increase_user_locked_balance<T>(custodian: &mut custodian_v2::Custodian<T>, account_cap: &custodian_v2::AccountCap, quantity: balance::Balance<T>)
    +
    public(friend) fun increase_user_locked_balance<T>(custodian: &mut custodian_v2::Custodian<T>, account_cap: &custodian_v2::AccountCap, quantity: balance::Balance<T>)
     
    @@ -434,7 +434,7 @@ Return the owner of an AccountCap quantity: Balance<T>, ) { let account = borrow_mut_account_balance<T>(custodian, account_cap.owner); - balance::join(&mut account.locked_balance, quantity); + balance::join(&mut account.locked_balance, quantity); }
    @@ -448,7 +448,7 @@ Return the owner of an AccountCap -
    public(friend) fun decrease_user_locked_balance<T>(custodian: &mut custodian_v2::Custodian<T>, owner: address, quantity: u64): balance::Balance<T>
    +
    public(friend) fun decrease_user_locked_balance<T>(custodian: &mut custodian_v2::Custodian<T>, owner: address, quantity: u64): balance::Balance<T>
     
    @@ -550,7 +550,7 @@ Move quantity from the locked balance of user to the u custodian: &Custodian<T>, owner: address, ): u64 { - balance::value(&table::borrow(&custodian.account_balances, owner).available_balance) + balance::value(&table::borrow(&custodian.account_balances, owner).available_balance) }
    @@ -577,7 +577,7 @@ Move quantity from the locked balance of user to the u custodian: &Custodian<T>, owner: address, ): u64 { - balance::value(&table::borrow(&custodian.account_balances, owner).locked_balance) + balance::value(&table::borrow(&custodian.account_balances, owner).locked_balance) }
    @@ -604,14 +604,14 @@ Move quantity from the locked balance of user to the u custodian: &mut Custodian<T>, owner: address, ): &mut Account<T> { - if (!table::contains(&custodian.account_balances, owner)) { - table::add( + if (!table::contains(&custodian.account_balances, owner)) { + table::add( &mut custodian.account_balances, owner, - Account { available_balance: balance::zero(), locked_balance: balance::zero() } + Account { available_balance: balance::zero(), locked_balance: balance::zero() } ); }; - table::borrow_mut(&mut custodian.account_balances, owner) + table::borrow_mut(&mut custodian.account_balances, owner) }
    diff --git a/crates/sui-framework/docs/deepbook/math.md b/crates/iota-framework/docs/deepbook/math.md similarity index 100% rename from crates/sui-framework/docs/deepbook/math.md rename to crates/iota-framework/docs/deepbook/math.md diff --git a/crates/sui-framework/docs/deepbook/order_query.md b/crates/iota-framework/docs/deepbook/order_query.md similarity index 96% rename from crates/sui-framework/docs/deepbook/order_query.md rename to crates/iota-framework/docs/deepbook/order_query.md index d6787a205c8..6f7fdb7fc15 100644 --- a/crates/sui-framework/docs/deepbook/order_query.md +++ b/crates/iota-framework/docs/deepbook/order_query.md @@ -18,7 +18,7 @@ title: Module `0xdee9::order_query`
    use 0x1::option;
    -use 0x2::linked_table;
    +use 0x2::linked_table;
     use 0xdee9::clob_v2;
     use 0xdee9::critbit;
     
    @@ -251,7 +251,7 @@ title: Module `0xdee9::order_query` let mut next_order_key = if (option::is_some(&start_order_id)) { let key = option::destroy_some(start_order_id); - if (!linked_table::contains(open_orders, key)) { + if (!linked_table::contains(open_orders, key)) { let (next_leaf, _) = if (ascending) { critbit::next_leaf(ticks, tick_level_key) }else { @@ -263,19 +263,19 @@ title: Module `0xdee9::order_query` start_order_id = option::none(); some(key) }else { - *linked_table::front(open_orders) + *linked_table::front(open_orders) }; while (option::is_some(&next_order_key) && vector::length(&orders) < PAGE_LIMIT + 1) { let key = option::destroy_some(next_order_key); - let order = linked_table::borrow(open_orders, key); + let order = linked_table::borrow(open_orders, key); // if the order id is greater than max_id, we end the iteration for this tick level. if (option::is_some(&max_id) && key > option::destroy_some(max_id)) { break }; - next_order_key = *linked_table::next(open_orders, key); + next_order_key = *linked_table::next(open_orders, key); // if expire timestamp is set, and if the order is expired, we skip it. if (option::is_none(&min_expire_timestamp) || diff --git a/crates/iota-framework/docs/iota-framework/address.md b/crates/iota-framework/docs/iota-framework/address.md new file mode 100644 index 00000000000..f10fb359c14 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/address.md @@ -0,0 +1,323 @@ +--- +title: Module `0x2::address` +--- + + + +- [Constants](#@Constants_0) +- [Function `to_u256`](#0x2_address_to_u256) +- [Function `from_u256`](#0x2_address_from_u256) +- [Function `from_bytes`](#0x2_address_from_bytes) +- [Function `to_bytes`](#0x2_address_to_bytes) +- [Function `to_ascii_string`](#0x2_address_to_ascii_string) +- [Function `to_string`](#0x2_address_to_string) +- [Function `from_ascii_bytes`](#0x2_address_from_ascii_bytes) +- [Function `hex_char_value`](#0x2_address_hex_char_value) +- [Function `length`](#0x2_address_length) +- [Function `max`](#0x2_address_max) + + +
    use 0x1::ascii;
    +use 0x1::bcs;
    +use 0x1::string;
    +use 0x2::hex;
    +
    + + + + + +## Constants + + + + +Error from from_bytes when it is supplied too many or too few bytes. + + +
    const EAddressParseError: u64 = 0;
    +
    + + + + + +The length of an address, in bytes + + +
    const LENGTH: u64 = 32;
    +
    + + + + + + + +
    const MAX: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
    +
    + + + + + +## Function `to_u256` + +Convert a into a u256 by interpreting a as the bytes of a big-endian integer +(e.g., to_u256(0x1) == 1) + + +
    public fun to_u256(a: address): u256
    +
    + + + +
    +Implementation + + +
    public native fun to_u256(a: address): u256;
    +
    + + + +
    + + + +## Function `from_u256` + +Convert n into an address by encoding it as a big-endian integer (e.g., from_u256(1) = @0x1) +Aborts if n > MAX_ADDRESS + + +
    public fun from_u256(n: u256): address
    +
    + + + +
    +Implementation + + +
    public native fun from_u256(n: u256): address;
    +
    + + + +
    + + + +## Function `from_bytes` + +Convert bytes into an address. +Aborts with EAddressParseError if the length of bytes is not 32 + + +
    public fun from_bytes(bytes: vector<u8>): address
    +
    + + + +
    +Implementation + + +
    public native fun from_bytes(bytes: vector<u8>): address;
    +
    + + + +
    + + + +## Function `to_bytes` + +Convert a into BCS-encoded bytes. + + +
    public fun to_bytes(a: address): vector<u8>
    +
    + + + +
    +Implementation + + +
    public fun to_bytes(a: address): vector<u8> {
    +    bcs::to_bytes(&a)
    +}
    +
    + + + +
    + + + +## Function `to_ascii_string` + +Convert a to a hex-encoded ASCII string + + +
    public fun to_ascii_string(a: address): ascii::String
    +
    + + + +
    +Implementation + + +
    public fun to_ascii_string(a: address): ascii::String {
    +    hex::encode(to_bytes(a)).to_ascii_string()
    +}
    +
    + + + +
    + + + +## Function `to_string` + +Convert a to a hex-encoded string + + +
    public fun to_string(a: address): string::String
    +
    + + + +
    +Implementation + + +
    public fun to_string(a: address): string::String {
    +    to_ascii_string(a).to_string()
    +}
    +
    + + + +
    + + + +## Function `from_ascii_bytes` + +Converts an ASCII string to an address, taking the numerical value for each character. The +string must be Base16 encoded, and thus exactly 64 characters long. +For example, the string "00000000000000000000000000000000000000000000000000000000DEADB33F" +will be converted to the address @0xDEADB33F. +Aborts with EAddressParseError if the length of s is not 64, +or if an invalid character is encountered. + + +
    public fun from_ascii_bytes(bytes: &vector<u8>): address
    +
    + + + +
    +Implementation + + +
    public fun from_ascii_bytes(bytes: &vector<u8>): address {
    +    assert!(bytes.length() == 64, EAddressParseError);
    +    let mut hex_bytes = vector[];
    +    let mut i = 0;
    +    while (i < 64) {
    +        let hi = hex_char_value(bytes[i]);
    +        let lo = hex_char_value(bytes[i+1]);
    +        hex_bytes.push_back((hi << 4) | lo);
    +        i = i + 2;
    +    };
    +    from_bytes(hex_bytes)
    +}
    +
    + + + +
    + + + +## Function `hex_char_value` + + + +
    fun hex_char_value(c: u8): u8
    +
    + + + +
    +Implementation + + +
    fun hex_char_value(c: u8): u8 {
    +    if (c >= 48 && c <= 57) c - 48 // 0-9
    +    else if (c >= 65 && c <= 70) c - 55 // A-F
    +    else if (c >= 97 && c <= 102) c - 87 // a-f
    +    else abort EAddressParseError
    +}
    +
    + + + +
    + + + +## Function `length` + +Length of a Iota address in bytes + + +
    public fun length(): u64
    +
    + + + +
    +Implementation + + +
    public fun length(): u64 {
    +    LENGTH
    +}
    +
    + + + +
    + + + +## Function `max` + +Largest possible address + + +
    public fun max(): u256
    +
    + + + +
    +Implementation + + +
    public fun max(): u256 {
    +    MAX
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-framework/authenticator_state.md b/crates/iota-framework/docs/iota-framework/authenticator_state.md new file mode 100644 index 00000000000..d13c429e955 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/authenticator_state.md @@ -0,0 +1,807 @@ +--- +title: Module `0x2::authenticator_state` +--- + + + +- [Resource `AuthenticatorState`](#0x2_authenticator_state_AuthenticatorState) +- [Struct `AuthenticatorStateInner`](#0x2_authenticator_state_AuthenticatorStateInner) +- [Struct `JWK`](#0x2_authenticator_state_JWK) +- [Struct `JwkId`](#0x2_authenticator_state_JwkId) +- [Struct `ActiveJwk`](#0x2_authenticator_state_ActiveJwk) +- [Constants](#@Constants_0) +- [Function `active_jwk_equal`](#0x2_authenticator_state_active_jwk_equal) +- [Function `jwk_equal`](#0x2_authenticator_state_jwk_equal) +- [Function `jwk_id_equal`](#0x2_authenticator_state_jwk_id_equal) +- [Function `string_bytes_lt`](#0x2_authenticator_state_string_bytes_lt) +- [Function `jwk_lt`](#0x2_authenticator_state_jwk_lt) +- [Function `create`](#0x2_authenticator_state_create) +- [Function `load_inner_mut`](#0x2_authenticator_state_load_inner_mut) +- [Function `load_inner`](#0x2_authenticator_state_load_inner) +- [Function `check_sorted`](#0x2_authenticator_state_check_sorted) +- [Function `update_authenticator_state`](#0x2_authenticator_state_update_authenticator_state) +- [Function `deduplicate`](#0x2_authenticator_state_deduplicate) +- [Function `expire_jwks`](#0x2_authenticator_state_expire_jwks) +- [Function `get_active_jwks`](#0x2_authenticator_state_get_active_jwks) + + +
    use 0x1::option;
    +use 0x1::string;
    +use 0x2::dynamic_field;
    +use 0x2::math;
    +use 0x2::object;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +
    + + + + + +## Resource `AuthenticatorState` + +Singleton shared object which stores the global authenticator state. +The actual state is stored in a dynamic field of type AuthenticatorStateInner to support +future versions of the authenticator state. + + +
    struct AuthenticatorState has key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +version: u64 +
    +
    + +
    +
    + + +
    + + + +## Struct `AuthenticatorStateInner` + + + +
    struct AuthenticatorStateInner has store
    +
    + + + +
    +Fields + + +
    +
    +version: u64 +
    +
    + +
    +
    +active_jwks: vector<authenticator_state::ActiveJwk> +
    +
    + List of currently active JWKs. +
    +
    + + +
    + + + +## Struct `JWK` + +Must match the JWK struct in fastcrypto-zkp + + +
    struct JWK has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +kty: string::String +
    +
    + +
    +
    +e: string::String +
    +
    + +
    +
    +n: string::String +
    +
    + +
    +
    +alg: string::String +
    +
    + +
    +
    + + +
    + + + +## Struct `JwkId` + +Must match the JwkId struct in fastcrypto-zkp + + +
    struct JwkId has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +iss: string::String +
    +
    + +
    +
    +kid: string::String +
    +
    + +
    +
    + + +
    + + + +## Struct `ActiveJwk` + + + +
    struct ActiveJwk has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +jwk_id: authenticator_state::JwkId +
    +
    + +
    +
    +jwk: authenticator_state::JWK +
    +
    + +
    +
    +epoch: u64 +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + +Sender is not @0x0 the system address. + + +
    const ENotSystemAddress: u64 = 0;
    +
    + + + + + + + +
    const CurrentVersion: u64 = 1;
    +
    + + + + + + + +
    const EJwksNotSorted: u64 = 2;
    +
    + + + + + + + +
    const EWrongInnerVersion: u64 = 1;
    +
    + + + + + +## Function `active_jwk_equal` + + + +
    fun active_jwk_equal(a: &authenticator_state::ActiveJwk, b: &authenticator_state::ActiveJwk): bool
    +
    + + + +
    +Implementation + + +
    fun active_jwk_equal(a: &ActiveJwk, b: &ActiveJwk): bool {
    +    // note: epoch is ignored
    +    jwk_equal(&a.jwk, &b.jwk) && jwk_id_equal(&a.jwk_id, &b.jwk_id)
    +}
    +
    + + + +
    + + + +## Function `jwk_equal` + + + +
    fun jwk_equal(a: &authenticator_state::JWK, b: &authenticator_state::JWK): bool
    +
    + + + +
    +Implementation + + +
    fun jwk_equal(a: &JWK, b: &JWK): bool {
    +    (&a.kty == &b.kty) &&
    +       (&a.e == &b.e) &&
    +       (&a.n == &b.n) &&
    +       (&a.alg == &b.alg)
    +}
    +
    + + + +
    + + + +## Function `jwk_id_equal` + + + +
    fun jwk_id_equal(a: &authenticator_state::JwkId, b: &authenticator_state::JwkId): bool
    +
    + + + +
    +Implementation + + +
    fun jwk_id_equal(a: &JwkId, b: &JwkId): bool {
    +    (&a.iss == &b.iss) && (&a.kid == &b.kid)
    +}
    +
    + + + +
    + + + +## Function `string_bytes_lt` + + + +
    fun string_bytes_lt(a: &string::String, b: &string::String): bool
    +
    + + + +
    +Implementation + + +
    fun string_bytes_lt(a: &String, b: &String): bool {
    +    let a_bytes = a.bytes();
    +    let b_bytes = b.bytes();
    +
    +    if (a_bytes.length() < b_bytes.length()) {
    +        true
    +    } else if (a_bytes.length() > b_bytes.length()) {
    +        false
    +    } else {
    +        let mut i = 0;
    +        while (i < a_bytes.length()) {
    +            let a_byte = a_bytes[i];
    +            let b_byte = b_bytes[i];
    +            if (a_byte < b_byte) {
    +                return true
    +            } else if (a_byte > b_byte) {
    +                return false
    +            };
    +            i = i + 1;
    +        };
    +        // all bytes are equal
    +        false
    +    }
    +}
    +
    + + + +
    + + + +## Function `jwk_lt` + + + +
    fun jwk_lt(a: &authenticator_state::ActiveJwk, b: &authenticator_state::ActiveJwk): bool
    +
    + + + +
    +Implementation + + +
    fun jwk_lt(a: &ActiveJwk, b: &ActiveJwk): bool {
    +    // note: epoch is ignored
    +    if (&a.jwk_id.iss != &b.jwk_id.iss) {
    +        return string_bytes_lt(&a.jwk_id.iss, &b.jwk_id.iss)
    +    };
    +    if (&a.jwk_id.kid != &b.jwk_id.kid) {
    +        return string_bytes_lt(&a.jwk_id.kid, &b.jwk_id.kid)
    +    };
    +    if (&a.jwk.kty != &b.jwk.kty) {
    +        return string_bytes_lt(&a.jwk.kty, &b.jwk.kty)
    +    };
    +    if (&a.jwk.e != &b.jwk.e) {
    +        return string_bytes_lt(&a.jwk.e, &b.jwk.e)
    +    };
    +    if (&a.jwk.n != &b.jwk.n) {
    +        return string_bytes_lt(&a.jwk.n, &b.jwk.n)
    +    };
    +    string_bytes_lt(&a.jwk.alg, &b.jwk.alg)
    +}
    +
    + + + +
    + + + +## Function `create` + +Create and share the AuthenticatorState object. This function is call exactly once, when +the authenticator state object is first created. +Can only be called by genesis or change_epoch transactions. + + +
    fun create(ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    fun create(ctx: &TxContext) {
    +    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    +
    +    let version = CurrentVersion;
    +
    +    let inner = AuthenticatorStateInner {
    +        version,
    +        active_jwks: vector[],
    +    };
    +
    +    let mut self = AuthenticatorState {
    +        id: object::authenticator_state(),
    +        version,
    +    };
    +
    +    dynamic_field::add(&mut self.id, version, inner);
    +    transfer::share_object(self);
    +}
    +
    + + + +
    + + + +## Function `load_inner_mut` + + + +
    fun load_inner_mut(self: &mut authenticator_state::AuthenticatorState): &mut authenticator_state::AuthenticatorStateInner
    +
    + + + +
    +Implementation + + +
    fun load_inner_mut(
    +    self: &mut AuthenticatorState,
    +): &mut AuthenticatorStateInner {
    +    let version = self.version;
    +
    +    // replace this with a lazy update function when we add a new version of the inner object.
    +    assert!(version == CurrentVersion, EWrongInnerVersion);
    +
    +    let inner: &mut AuthenticatorStateInner = dynamic_field::borrow_mut(&mut self.id, self.version);
    +
    +    assert!(inner.version == version, EWrongInnerVersion);
    +    inner
    +}
    +
    + + + +
    + + + +## Function `load_inner` + + + +
    fun load_inner(self: &authenticator_state::AuthenticatorState): &authenticator_state::AuthenticatorStateInner
    +
    + + + +
    +Implementation + + +
    fun load_inner(
    +    self: &AuthenticatorState,
    +): &AuthenticatorStateInner {
    +    let version = self.version;
    +
    +    // replace this with a lazy update function when we add a new version of the inner object.
    +    assert!(version == CurrentVersion, EWrongInnerVersion);
    +
    +    let inner: &AuthenticatorStateInner = dynamic_field::borrow(&self.id, self.version);
    +
    +    assert!(inner.version == version, EWrongInnerVersion);
    +    inner
    +}
    +
    + + + +
    + + + +## Function `check_sorted` + + + +
    fun check_sorted(new_active_jwks: &vector<authenticator_state::ActiveJwk>)
    +
    + + + +
    +Implementation + + +
    fun check_sorted(new_active_jwks: &vector<ActiveJwk>) {
    +    let mut i = 0;
    +    while (i < new_active_jwks.length() - 1) {
    +        let a = &new_active_jwks[i];
    +        let b = &new_active_jwks[i + 1];
    +        assert!(jwk_lt(a, b), EJwksNotSorted);
    +        i = i + 1;
    +    };
    +}
    +
    + + + +
    + + + +## Function `update_authenticator_state` + +Record a new set of active_jwks. Called when executing the AuthenticatorStateUpdate system +transaction. The new input vector must be sorted and must not contain duplicates. +If a new JWK is already present, but with a previous epoch, then the epoch is updated to +indicate that the JWK has been validated in the current epoch and should not be expired. + + +
    fun update_authenticator_state(self: &mut authenticator_state::AuthenticatorState, new_active_jwks: vector<authenticator_state::ActiveJwk>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    fun update_authenticator_state(
    +    self: &mut AuthenticatorState,
    +    new_active_jwks: vector<ActiveJwk>,
    +    ctx: &TxContext,
    +) {
    +    // Validator will make a special system call with sender set as 0x0.
    +    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    +
    +    check_sorted(&new_active_jwks);
    +    let new_active_jwks = deduplicate(new_active_jwks);
    +
    +    let inner = self.load_inner_mut();
    +
    +    let mut res = vector[];
    +    let mut i = 0;
    +    let mut j = 0;
    +    let active_jwks_len = inner.active_jwks.length();
    +    let new_active_jwks_len = new_active_jwks.length();
    +
    +    while (i < active_jwks_len && j < new_active_jwks_len) {
    +        let old_jwk = &inner.active_jwks[i];
    +        let new_jwk = &new_active_jwks[j];
    +
    +        // when they are equal, push only one, but use the max epoch of the two
    +        if (active_jwk_equal(old_jwk, new_jwk)) {
    +            let mut jwk = *old_jwk;
    +            jwk.epoch = math::max(old_jwk.epoch, new_jwk.epoch);
    +            res.push_back(jwk);
    +            i = i + 1;
    +            j = j + 1;
    +        } else if (jwk_id_equal(&old_jwk.jwk_id, &new_jwk.jwk_id)) {
    +            // if only jwk_id is equal, then the key has changed. Providers should not send
    +            // JWKs like this, but if they do, we must ignore the new JWK to avoid having a
    +            // liveness / forking issues
    +            res.push_back(*old_jwk);
    +            i = i + 1;
    +            j = j + 1;
    +        } else if (jwk_lt(old_jwk, new_jwk)) {
    +            res.push_back(*old_jwk);
    +            i = i + 1;
    +        } else {
    +            res.push_back(*new_jwk);
    +            j = j + 1;
    +        }
    +    };
    +
    +    while (i < active_jwks_len) {
    +        res.push_back(inner.active_jwks[i]);
    +        i = i + 1;
    +    };
    +    while (j < new_active_jwks_len) {
    +        res.push_back(new_active_jwks[j]);
    +        j = j + 1;
    +    };
    +
    +    inner.active_jwks = res;
    +}
    +
    + + + +
    + + + +## Function `deduplicate` + + + +
    fun deduplicate(jwks: vector<authenticator_state::ActiveJwk>): vector<authenticator_state::ActiveJwk>
    +
    + + + +
    +Implementation + + +
    fun deduplicate(jwks: vector<ActiveJwk>): vector<ActiveJwk> {
    +    let mut res = vector[];
    +    let mut i = 0;
    +    let mut prev: Option<JwkId> = option::none();
    +    while (i < jwks.length()) {
    +        let jwk = &jwks[i];
    +        if (prev.is_none()) {
    +            prev.fill(jwk.jwk_id);
    +        } else if (jwk_id_equal(prev.borrow(), &jwk.jwk_id)) {
    +            // skip duplicate jwks in input
    +            i = i + 1;
    +            continue
    +        } else {
    +            *prev.borrow_mut() = jwk.jwk_id;
    +        };
    +        res.push_back(*jwk);
    +        i = i + 1;
    +    };
    +    res
    +}
    +
    + + + +
    + + + +## Function `expire_jwks` + + + +
    fun expire_jwks(self: &mut authenticator_state::AuthenticatorState, min_epoch: u64, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    fun expire_jwks(
    +    self: &mut AuthenticatorState,
    +    // any jwk below this epoch is not retained
    +    min_epoch: u64,
    +    ctx: &TxContext) {
    +    // This will only be called by iota_system::advance_epoch
    +    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    +
    +    let inner = load_inner_mut(self);
    +
    +    let len = inner.active_jwks.length();
    +
    +    // first we count how many jwks from each issuer are above the min_epoch
    +    // and store the counts in a vector that parallels the (sorted) active_jwks vector
    +    let mut issuer_max_epochs = vector[];
    +    let mut i = 0;
    +    let mut prev_issuer: Option<String> = option::none();
    +
    +    while (i < len) {
    +        let cur = &inner.active_jwks[i];
    +        let cur_iss = &cur.jwk_id.iss;
    +        if (prev_issuer.is_none()) {
    +            prev_issuer.fill(*cur_iss);
    +            issuer_max_epochs.push_back(cur.epoch);
    +        } else {
    +            if (cur_iss == prev_issuer.borrow()) {
    +                let back = issuer_max_epochs.length() - 1;
    +                let prev_max_epoch = &mut issuer_max_epochs[back];
    +                *prev_max_epoch = math::max(*prev_max_epoch, cur.epoch);
    +            } else {
    +                *prev_issuer.borrow_mut() = *cur_iss;
    +                issuer_max_epochs.push_back(cur.epoch);
    +            }
    +        };
    +        i = i + 1;
    +    };
    +
    +    // Now, filter out any JWKs that are below the min_epoch, unless that issuer has no
    +    // JWKs >= the min_epoch, in which case we keep all of them.
    +    let mut new_active_jwks: vector<ActiveJwk> = vector[];
    +    let mut prev_issuer: Option<String> = option::none();
    +    let mut i = 0;
    +    let mut j = 0;
    +    while (i < len) {
    +        let jwk = &inner.active_jwks[i];
    +        let cur_iss = &jwk.jwk_id.iss;
    +
    +        if (prev_issuer.is_none()) {
    +            prev_issuer.fill(*cur_iss);
    +        } else if (cur_iss != prev_issuer.borrow()) {
    +            *prev_issuer.borrow_mut() = *cur_iss;
    +            j = j + 1;
    +        };
    +
    +        let max_epoch_for_iss = &issuer_max_epochs[j];
    +
    +        // TODO: if the iss for this jwk has *no* jwks that meet the minimum epoch,
    +        // then expire nothing.
    +        if (*max_epoch_for_iss < min_epoch || jwk.epoch >= min_epoch) {
    +            new_active_jwks.push_back(*jwk);
    +        };
    +        i = i + 1;
    +    };
    +    inner.active_jwks = new_active_jwks;
    +}
    +
    + + + +
    + + + +## Function `get_active_jwks` + +Get the current active_jwks. Called when the node starts up in order to load the current +JWK state from the chain. + + +
    fun get_active_jwks(self: &authenticator_state::AuthenticatorState, ctx: &tx_context::TxContext): vector<authenticator_state::ActiveJwk>
    +
    + + + +
    +Implementation + + +
    fun get_active_jwks(
    +    self: &AuthenticatorState,
    +    ctx: &TxContext,
    +): vector<ActiveJwk> {
    +    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    +    self.load_inner().active_jwks
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-framework/bag.md b/crates/iota-framework/docs/iota-framework/bag.md new file mode 100644 index 00000000000..7fc6a9f7a02 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/bag.md @@ -0,0 +1,367 @@ +--- +title: Module `0x2::bag` +--- + +A bag is a heterogeneous map-like collection. The collection is similar to iota::table in that +its keys and values are not stored within the Bag value, but instead are stored using Iota's +object system. The Bag struct acts only as a handle into the object system to retrieve those +keys and values. +Note that this means that Bag values with exactly the same key-value mapping will not be +equal, with ==, at runtime. For example +``` +let bag1 = bag::new(); +let bag2 = bag::new(); +bag::add(&mut bag1, 0, false); +bag::add(&mut bag1, 1, true); +bag::add(&mut bag2, 0, false); +bag::add(&mut bag2, 1, true); +// bag1 does not equal bag2, despite having the same entries +assert!(&bag1 != &bag2, 0); +``` +At it's core, iota::bag is a wrapper around UID that allows for access to +iota::dynamic_field while preventing accidentally stranding field values. A UID can be +deleted, even if it has dynamic fields associated with it, but a bag, on the other hand, must be +empty to be destroyed. + + +- [Resource `Bag`](#0x2_bag_Bag) +- [Constants](#@Constants_0) +- [Function `new`](#0x2_bag_new) +- [Function `add`](#0x2_bag_add) +- [Function `borrow`](#0x2_bag_borrow) +- [Function `borrow_mut`](#0x2_bag_borrow_mut) +- [Function `remove`](#0x2_bag_remove) +- [Function `contains`](#0x2_bag_contains) +- [Function `contains_with_type`](#0x2_bag_contains_with_type) +- [Function `length`](#0x2_bag_length) +- [Function `is_empty`](#0x2_bag_is_empty) +- [Function `destroy_empty`](#0x2_bag_destroy_empty) + + +
    use 0x2::dynamic_field;
    +use 0x2::object;
    +use 0x2::tx_context;
    +
    + + + + + +## Resource `Bag` + + + +
    struct Bag has store, key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + the ID of this bag +
    +
    +size: u64 +
    +
    + the number of key-value pairs in the bag +
    +
    + + +
    + + + +## Constants + + + + + + +
    const EBagNotEmpty: u64 = 0;
    +
    + + + + + +## Function `new` + +Creates a new, empty bag + + +
    public fun new(ctx: &mut tx_context::TxContext): bag::Bag
    +
    + + + +
    +Implementation + + +
    public fun new(ctx: &mut TxContext): Bag {
    +    Bag {
    +        id: object::new(ctx),
    +        size: 0,
    +    }
    +}
    +
    + + + +
    + + + +## Function `add` + +Adds a key-value pair to the bag bag: &mut Bag +Aborts with iota::dynamic_field::EFieldAlreadyExists if the bag already has an entry with +that key k: K. + + +
    public fun add<K: copy, drop, store, V: store>(bag: &mut bag::Bag, k: K, v: V)
    +
    + + + +
    +Implementation + + +
    public fun add<K: copy + drop + store, V: store>(bag: &mut Bag, k: K, v: V) {
    +    field::add(&mut bag.id, k, v);
    +    bag.size = bag.size + 1;
    +}
    +
    + + + +
    + + + +## Function `borrow` + +Immutable borrows the value associated with the key in the bag bag: &Bag. +Aborts with iota::dynamic_field::EFieldDoesNotExist if the bag does not have an entry with +that key k: K. +Aborts with iota::dynamic_field::EFieldTypeMismatch if the bag has an entry for the key, but +the value does not have the specified type. + + +
    public fun borrow<K: copy, drop, store, V: store>(bag: &bag::Bag, k: K): &V
    +
    + + + +
    +Implementation + + +
    public fun borrow<K: copy + drop + store, V: store>(bag: &Bag, k: K): &V {
    +    field::borrow(&bag.id, k)
    +}
    +
    + + + +
    + + + +## Function `borrow_mut` + +Mutably borrows the value associated with the key in the bag bag: &mut Bag. +Aborts with iota::dynamic_field::EFieldDoesNotExist if the bag does not have an entry with +that key k: K. +Aborts with iota::dynamic_field::EFieldTypeMismatch if the bag has an entry for the key, but +the value does not have the specified type. + + +
    public fun borrow_mut<K: copy, drop, store, V: store>(bag: &mut bag::Bag, k: K): &mut V
    +
    + + + +
    +Implementation + + +
    public fun borrow_mut<K: copy + drop + store, V: store>(bag: &mut Bag, k: K): &mut V {
    +    field::borrow_mut(&mut bag.id, k)
    +}
    +
    + + + +
    + + + +## Function `remove` + +Mutably borrows the key-value pair in the bag bag: &mut Bag and returns the value. +Aborts with iota::dynamic_field::EFieldDoesNotExist if the bag does not have an entry with +that key k: K. +Aborts with iota::dynamic_field::EFieldTypeMismatch if the bag has an entry for the key, but +the value does not have the specified type. + + +
    public fun remove<K: copy, drop, store, V: store>(bag: &mut bag::Bag, k: K): V
    +
    + + + +
    +Implementation + + +
    public fun remove<K: copy + drop + store, V: store>(bag: &mut Bag, k: K): V {
    +    let v = field::remove(&mut bag.id, k);
    +    bag.size = bag.size - 1;
    +    v
    +}
    +
    + + + +
    + + + +## Function `contains` + +Returns true iff there is an value associated with the key k: K in the bag bag: &Bag + + +
    public fun contains<K: copy, drop, store>(bag: &bag::Bag, k: K): bool
    +
    + + + +
    +Implementation + + +
    public fun contains<K: copy + drop + store>(bag: &Bag, k: K): bool {
    +    field::exists_<K>(&bag.id, k)
    +}
    +
    + + + +
    + + + +## Function `contains_with_type` + +Returns true iff there is an value associated with the key k: K in the bag bag: &Bag +with an assigned value of type V + + +
    public fun contains_with_type<K: copy, drop, store, V: store>(bag: &bag::Bag, k: K): bool
    +
    + + + +
    +Implementation + + +
    public fun contains_with_type<K: copy + drop + store, V: store>(bag: &Bag, k: K): bool {
    +    field::exists_with_type<K, V>(&bag.id, k)
    +}
    +
    + + + +
    + + + +## Function `length` + +Returns the size of the bag, the number of key-value pairs + + +
    public fun length(bag: &bag::Bag): u64
    +
    + + + +
    +Implementation + + +
    public fun length(bag: &Bag): u64 {
    +    bag.size
    +}
    +
    + + + +
    + + + +## Function `is_empty` + +Returns true iff the bag is empty (if length returns 0) + + +
    public fun is_empty(bag: &bag::Bag): bool
    +
    + + + +
    +Implementation + + +
    public fun is_empty(bag: &Bag): bool {
    +    bag.size == 0
    +}
    +
    + + + +
    + + + +## Function `destroy_empty` + +Destroys an empty bag +Aborts with EBagNotEmpty if the bag still contains values + + +
    public fun destroy_empty(bag: bag::Bag)
    +
    + + + +
    +Implementation + + +
    public fun destroy_empty(bag: Bag) {
    +    let Bag { id, size } = bag;
    +    assert!(size == 0, EBagNotEmpty);
    +    id.delete()
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-framework/balance.md b/crates/iota-framework/docs/iota-framework/balance.md new file mode 100644 index 00000000000..f5165ce736a --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/balance.md @@ -0,0 +1,477 @@ +--- +title: Module `0x2::balance` +--- + +A storable handler for Balances in general. Is used in the Coin +module to allow balance operations and can be used to implement +custom coins with Supply and Balances. + + +- [Struct `Supply`](#0x2_balance_Supply) +- [Struct `Balance`](#0x2_balance_Balance) +- [Constants](#@Constants_0) +- [Function `value`](#0x2_balance_value) +- [Function `supply_value`](#0x2_balance_supply_value) +- [Function `create_supply`](#0x2_balance_create_supply) +- [Function `increase_supply`](#0x2_balance_increase_supply) +- [Function `decrease_supply`](#0x2_balance_decrease_supply) +- [Function `zero`](#0x2_balance_zero) +- [Function `join`](#0x2_balance_join) +- [Function `split`](#0x2_balance_split) +- [Function `withdraw_all`](#0x2_balance_withdraw_all) +- [Function `destroy_zero`](#0x2_balance_destroy_zero) +- [Function `create_staking_rewards`](#0x2_balance_create_staking_rewards) +- [Function `destroy_storage_rebates`](#0x2_balance_destroy_storage_rebates) +- [Function `destroy_supply`](#0x2_balance_destroy_supply) + + +
    use 0x2::tx_context;
    +
    + + + + + +## Struct `Supply` + +A Supply of T. Used for minting and burning. +Wrapped into a TreasuryCap in the Coin module. + + +
    struct Supply<T> has store
    +
    + + + +
    +Fields + + +
    +
    +value: u64 +
    +
    + +
    +
    + + +
    + + + +## Struct `Balance` + +Storable balance - an inner struct of a Coin type. +Can be used to store coins which don't need the key ability. + + +
    struct Balance<T> has store
    +
    + + + +
    +Fields + + +
    +
    +value: u64 +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + +Sender is not @0x0 the system address. + + +
    const ENotSystemAddress: u64 = 3;
    +
    + + + + + +For when trying to destroy a non-zero balance. + + +
    const ENonZero: u64 = 0;
    +
    + + + + + +For when trying to withdraw more than there is. + + +
    const ENotEnough: u64 = 2;
    +
    + + + + + +For when an overflow is happening on Supply operations. + + +
    const EOverflow: u64 = 1;
    +
    + + + + + +## Function `value` + +Get the amount stored in a Balance. + + +
    public fun value<T>(self: &balance::Balance<T>): u64
    +
    + + + +
    +Implementation + + +
    public fun value<T>(self: &Balance<T>): u64 {
    +    self.value
    +}
    +
    + + + +
    + + + +## Function `supply_value` + +Get the Supply value. + + +
    public fun supply_value<T>(supply: &balance::Supply<T>): u64
    +
    + + + +
    +Implementation + + +
    public fun supply_value<T>(supply: &Supply<T>): u64 {
    +    supply.value
    +}
    +
    + + + +
    + + + +## Function `create_supply` + +Create a new supply for type T. + + +
    public fun create_supply<T: drop>(_: T): balance::Supply<T>
    +
    + + + +
    +Implementation + + +
    public fun create_supply<T: drop>(_: T): Supply<T> {
    +    Supply { value: 0 }
    +}
    +
    + + + +
    + + + +## Function `increase_supply` + +Increase supply by value and create a new Balance<T> with this value. + + +
    public fun increase_supply<T>(self: &mut balance::Supply<T>, value: u64): balance::Balance<T>
    +
    + + + +
    +Implementation + + +
    public fun increase_supply<T>(self: &mut Supply<T>, value: u64): Balance<T> {
    +    assert!(value < (18446744073709551615u64 - self.value), EOverflow);
    +    self.value = self.value + value;
    +    Balance { value }
    +}
    +
    + + + +
    + + + +## Function `decrease_supply` + +Burn a Balance and decrease Supply. + + +
    public fun decrease_supply<T>(self: &mut balance::Supply<T>, balance: balance::Balance<T>): u64
    +
    + + + +
    +Implementation + + +
    public fun decrease_supply<T>(self: &mut Supply<T>, balance: Balance<T>): u64 {
    +    let Balance { value } = balance;
    +    assert!(self.value >= value, EOverflow);
    +    self.value = self.value - value;
    +    value
    +}
    +
    + + + +
    + + + +## Function `zero` + +Create a zero Balance for type T. + + +
    public fun zero<T>(): balance::Balance<T>
    +
    + + + +
    +Implementation + + +
    public fun zero<T>(): Balance<T> {
    +    Balance { value: 0 }
    +}
    +
    + + + +
    + + + +## Function `join` + +Join two balances together. + + +
    public fun join<T>(self: &mut balance::Balance<T>, balance: balance::Balance<T>): u64
    +
    + + + +
    +Implementation + + +
    public fun join<T>(self: &mut Balance<T>, balance: Balance<T>): u64 {
    +    let Balance { value } = balance;
    +    self.value = self.value + value;
    +    self.value
    +}
    +
    + + + +
    + + + +## Function `split` + +Split a Balance and take a sub balance from it. + + +
    public fun split<T>(self: &mut balance::Balance<T>, value: u64): balance::Balance<T>
    +
    + + + +
    +Implementation + + +
    public fun split<T>(self: &mut Balance<T>, value: u64): Balance<T> {
    +    assert!(self.value >= value, ENotEnough);
    +    self.value = self.value - value;
    +    Balance { value }
    +}
    +
    + + + +
    + + + +## Function `withdraw_all` + +Withdraw all balance. After this the remaining balance must be 0. + + +
    public fun withdraw_all<T>(self: &mut balance::Balance<T>): balance::Balance<T>
    +
    + + + +
    +Implementation + + +
    public fun withdraw_all<T>(self: &mut Balance<T>): Balance<T> {
    +    let value = self.value;
    +    split(self, value)
    +}
    +
    + + + +
    + + + +## Function `destroy_zero` + +Destroy a zero Balance. + + +
    public fun destroy_zero<T>(balance: balance::Balance<T>)
    +
    + + + +
    +Implementation + + +
    public fun destroy_zero<T>(balance: Balance<T>) {
    +    assert!(balance.value == 0, ENonZero);
    +    let Balance { value: _ } = balance;
    +}
    +
    + + + +
    + + + +## Function `create_staking_rewards` + +CAUTION: this function creates a Balance without increasing the supply. +It should only be called by the epoch change system txn to create staking rewards, +and nowhere else. + + +
    fun create_staking_rewards<T>(value: u64, ctx: &tx_context::TxContext): balance::Balance<T>
    +
    + + + +
    +Implementation + + +
    fun create_staking_rewards<T>(value: u64, ctx: &TxContext): Balance<T> {
    +    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    +    Balance { value }
    +}
    +
    + + + +
    + + + +## Function `destroy_storage_rebates` + +CAUTION: this function destroys a Balance without decreasing the supply. +It should only be called by the epoch change system txn to destroy storage rebates, +and nowhere else. + + +
    fun destroy_storage_rebates<T>(self: balance::Balance<T>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    fun destroy_storage_rebates<T>(self: Balance<T>, ctx: &TxContext) {
    +    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    +    let Balance { value: _ } = self;
    +}
    +
    + + + +
    + + + +## Function `destroy_supply` + +Destroy a Supply preventing any further minting and burning. + + +
    public(friend) fun destroy_supply<T>(self: balance::Supply<T>): u64
    +
    + + + +
    +Implementation + + +
    public(package) fun destroy_supply<T>(self: Supply<T>): u64 {
    +    let Supply { value } = self;
    +    value
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/sui-framework/bcs.md b/crates/iota-framework/docs/iota-framework/bcs.md similarity index 99% rename from crates/sui-framework/docs/sui-framework/bcs.md rename to crates/iota-framework/docs/iota-framework/bcs.md index 8d127a265b5..6df6c693e20 100644 --- a/crates/sui-framework/docs/sui-framework/bcs.md +++ b/crates/iota-framework/docs/iota-framework/bcs.md @@ -19,7 +19,7 @@ Usage example: /// This function reads u8 and u64 value from the input /// and returns the rest of the bytes. fun deserialize(bytes: vector): (u8, u64, vector) { -use sui::bcs::{Self, BCS}; +use iota::bcs::{Self, BCS}; let prepared: BCS = bcs::new(bytes); let (u8_value, u64_value) = ( diff --git a/crates/sui-framework/docs/sui-framework/bls12381.md b/crates/iota-framework/docs/iota-framework/bls12381.md similarity index 100% rename from crates/sui-framework/docs/sui-framework/bls12381.md rename to crates/iota-framework/docs/iota-framework/bls12381.md diff --git a/crates/sui-framework/docs/sui-framework/borrow.md b/crates/iota-framework/docs/iota-framework/borrow.md similarity index 100% rename from crates/sui-framework/docs/sui-framework/borrow.md rename to crates/iota-framework/docs/iota-framework/borrow.md diff --git a/crates/iota-framework/docs/iota-framework/clock.md b/crates/iota-framework/docs/iota-framework/clock.md new file mode 100644 index 00000000000..f9bf24ca3e2 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/clock.md @@ -0,0 +1,171 @@ +--- +title: Module `0x2::clock` +--- + +APIs for accessing time from move calls, via the Clock: a unique +shared object that is created at 0x6 during genesis. + + +- [Resource `Clock`](#0x2_clock_Clock) +- [Constants](#@Constants_0) +- [Function `timestamp_ms`](#0x2_clock_timestamp_ms) +- [Function `create`](#0x2_clock_create) +- [Function `consensus_commit_prologue`](#0x2_clock_consensus_commit_prologue) + + +
    use 0x2::object;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +
    + + + + + +## Resource `Clock` + +Singleton shared object that exposes time to Move calls. This +object is found at address 0x6, and can only be read (accessed +via an immutable reference) by entry functions. + +Entry Functions that attempt to accept Clock by mutable +reference or value will fail to verify, and honest validators +will not sign or execute transactions that use Clock as an +input parameter, unless it is passed by immutable reference. + + +
    struct Clock has key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +timestamp_ms: u64 +
    +
    + The clock's timestamp, which is set automatically by a + system transaction every time consensus commits a + schedule, or by iota::clock::increment_for_testing during + testing. +
    +
    + + +
    + + + +## Constants + + + + +Sender is not @0x0 the system address. + + +
    const ENotSystemAddress: u64 = 0;
    +
    + + + + + +## Function `timestamp_ms` + +The clock's current timestamp as a running total of +milliseconds since an arbitrary point in the past. + + +
    public fun timestamp_ms(clock: &clock::Clock): u64
    +
    + + + +
    +Implementation + + +
    public fun timestamp_ms(clock: &Clock): u64 {
    +    clock.timestamp_ms
    +}
    +
    + + + +
    + + + +## Function `create` + +Create and share the singleton Clock -- this function is +called exactly once, during genesis. + + +
    fun create(ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    fun create(ctx: &TxContext) {
    +    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    +
    +    transfer::share_object(Clock {
    +        id: object::clock(),
    +        // Initialised to zero, but set to a real timestamp by a
    +        // system transaction before it can be witnessed by a move
    +        // call.
    +        timestamp_ms: 0,
    +    })
    +}
    +
    + + + +
    + + + +## Function `consensus_commit_prologue` + + + +
    fun consensus_commit_prologue(clock: &mut clock::Clock, timestamp_ms: u64, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    fun consensus_commit_prologue(
    +    clock: &mut Clock,
    +    timestamp_ms: u64,
    +    ctx: &TxContext,
    +) {
    +    // Validator will make a special system call with sender set as 0x0.
    +    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    +
    +    clock.timestamp_ms = timestamp_ms
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-framework/coin.md b/crates/iota-framework/docs/iota-framework/coin.md new file mode 100644 index 00000000000..e300549de0e --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/coin.md @@ -0,0 +1,1354 @@ +--- +title: Module `0x2::coin` +--- + +Defines the Coin type - platform wide representation of fungible +tokens and coins. Coin can be described as a secure wrapper around +Balance type. + + +- [Resource `Coin`](#0x2_coin_Coin) +- [Resource `CoinMetadata`](#0x2_coin_CoinMetadata) +- [Resource `RegulatedCoinMetadata`](#0x2_coin_RegulatedCoinMetadata) +- [Resource `TreasuryCap`](#0x2_coin_TreasuryCap) +- [Resource `DenyCap`](#0x2_coin_DenyCap) +- [Struct `CurrencyCreated`](#0x2_coin_CurrencyCreated) +- [Constants](#@Constants_0) +- [Function `total_supply`](#0x2_coin_total_supply) +- [Function `treasury_into_supply`](#0x2_coin_treasury_into_supply) +- [Function `supply_immut`](#0x2_coin_supply_immut) +- [Function `supply_mut`](#0x2_coin_supply_mut) +- [Function `value`](#0x2_coin_value) +- [Function `balance`](#0x2_coin_balance) +- [Function `balance_mut`](#0x2_coin_balance_mut) +- [Function `from_balance`](#0x2_coin_from_balance) +- [Function `into_balance`](#0x2_coin_into_balance) +- [Function `take`](#0x2_coin_take) +- [Function `put`](#0x2_coin_put) +- [Function `join`](#0x2_coin_join) +- [Function `split`](#0x2_coin_split) +- [Function `divide_into_n`](#0x2_coin_divide_into_n) +- [Function `zero`](#0x2_coin_zero) +- [Function `destroy_zero`](#0x2_coin_destroy_zero) +- [Function `create_currency`](#0x2_coin_create_currency) +- [Function `create_regulated_currency`](#0x2_coin_create_regulated_currency) +- [Function `mint`](#0x2_coin_mint) +- [Function `mint_balance`](#0x2_coin_mint_balance) +- [Function `burn`](#0x2_coin_burn) +- [Function `deny_list_add`](#0x2_coin_deny_list_add) +- [Function `deny_list_remove`](#0x2_coin_deny_list_remove) +- [Function `deny_list_contains`](#0x2_coin_deny_list_contains) +- [Function `mint_and_transfer`](#0x2_coin_mint_and_transfer) +- [Function `update_name`](#0x2_coin_update_name) +- [Function `update_symbol`](#0x2_coin_update_symbol) +- [Function `update_description`](#0x2_coin_update_description) +- [Function `update_icon_url`](#0x2_coin_update_icon_url) +- [Function `get_decimals`](#0x2_coin_get_decimals) +- [Function `get_name`](#0x2_coin_get_name) +- [Function `get_symbol`](#0x2_coin_get_symbol) +- [Function `get_description`](#0x2_coin_get_description) +- [Function `get_icon_url`](#0x2_coin_get_icon_url) +- [Function `supply`](#0x2_coin_supply) + + +
    use 0x1::ascii;
    +use 0x1::option;
    +use 0x1::string;
    +use 0x1::type_name;
    +use 0x2::balance;
    +use 0x2::deny_list;
    +use 0x2::object;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +use 0x2::types;
    +use 0x2::url;
    +
    + + + + + +## Resource `Coin` + +A coin of type T worth value. Transferable and storable + + +
    struct Coin<T> has store, key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +balance: balance::Balance<T> +
    +
    + +
    +
    + + +
    + + + +## Resource `CoinMetadata` + +Each Coin type T created through create_currency function will have a +unique instance of CoinMetadata that stores the metadata for this coin type. + + +
    struct CoinMetadata<T> has store, key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +decimals: u8 +
    +
    + Number of decimal places the coin uses. + A coin with value N and decimals D should be shown as N / 10^D + E.g., a coin with value 7002 and decimals 3 should be displayed as 7.002 + This is metadata for display usage only. +
    +
    +name: string::String +
    +
    + Name for the token +
    +
    +symbol: ascii::String +
    +
    + Symbol for the token +
    +
    +description: string::String +
    +
    + Description of the token +
    +
    +icon_url: option::Option<url::Url> +
    +
    + URL for the token logo +
    +
    + + +
    + + + +## Resource `RegulatedCoinMetadata` + +Similar to CoinMetadata, but created only for regulated coins that use the DenyList. +This object is always immutable. + + +
    struct RegulatedCoinMetadata<T> has key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +coin_metadata_object: object::ID +
    +
    + The ID of the coin's CoinMetadata object. +
    +
    +deny_cap_object: object::ID +
    +
    + The ID of the coin's DenyCap object. +
    +
    + + +
    + + + +## Resource `TreasuryCap` + +Capability allowing the bearer to mint and burn +coins of type T. Transferable + + +
    struct TreasuryCap<T> has store, key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +total_supply: balance::Supply<T> +
    +
    + +
    +
    + + +
    + + + +## Resource `DenyCap` + +Capability allowing the bearer to freeze addresses, preventing those addresses from +interacting with the coin as an input to a transaction. + + +
    struct DenyCap<T> has store, key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    + + +
    + + + +## Struct `CurrencyCreated` + + + +
    struct CurrencyCreated<T> has copy, drop
    +
    + + + +
    +Fields + + +
    +
    +decimals: u8 +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + +Trying to split a coin more times than its balance allows. + + +
    const ENotEnough: u64 = 2;
    +
    + + + + + +The index into the deny list vector for the iota::coin::Coin type. + + +
    const DENY_LIST_COIN_INDEX: u64 = 0;
    +
    + + + + + +A type passed to create_supply is not a one-time witness. + + +
    const EBadWitness: u64 = 0;
    +
    + + + + + +Invalid arguments are passed to a function. + + +
    const EInvalidArg: u64 = 1;
    +
    + + + + + +## Function `total_supply` + +Return the total number of T's in circulation. + + +
    public fun total_supply<T>(cap: &coin::TreasuryCap<T>): u64
    +
    + + + +
    +Implementation + + +
    public fun total_supply<T>(cap: &TreasuryCap<T>): u64 {
    +    balance::supply_value(&cap.total_supply)
    +}
    +
    + + + +
    + + + +## Function `treasury_into_supply` + +Unwrap TreasuryCap getting the Supply. + +Operation is irreversible. Supply cannot be converted into a TreasuryCap due +to different security guarantees (TreasuryCap can be created only once for a type) + + +
    public fun treasury_into_supply<T>(treasury: coin::TreasuryCap<T>): balance::Supply<T>
    +
    + + + +
    +Implementation + + +
    public fun treasury_into_supply<T>(treasury: TreasuryCap<T>): Supply<T> {
    +    let TreasuryCap { id, total_supply } = treasury;
    +    id.delete();
    +    total_supply
    +}
    +
    + + + +
    + + + +## Function `supply_immut` + +Get immutable reference to the treasury's Supply. + + +
    public fun supply_immut<T>(treasury: &coin::TreasuryCap<T>): &balance::Supply<T>
    +
    + + + +
    +Implementation + + +
    public fun supply_immut<T>(treasury: &TreasuryCap<T>): &Supply<T> {
    +    &treasury.total_supply
    +}
    +
    + + + +
    + + + +## Function `supply_mut` + +Get mutable reference to the treasury's Supply. + + +
    public fun supply_mut<T>(treasury: &mut coin::TreasuryCap<T>): &mut balance::Supply<T>
    +
    + + + +
    +Implementation + + +
    public fun supply_mut<T>(treasury: &mut TreasuryCap<T>): &mut Supply<T> {
    +    &mut treasury.total_supply
    +}
    +
    + + + +
    + + + +## Function `value` + +Public getter for the coin's value + + +
    public fun value<T>(self: &coin::Coin<T>): u64
    +
    + + + +
    +Implementation + + +
    public fun value<T>(self: &Coin<T>): u64 {
    +    self.balance.value()
    +}
    +
    + + + +
    + + + +## Function `balance` + +Get immutable reference to the balance of a coin. + + +
    public fun balance<T>(coin: &coin::Coin<T>): &balance::Balance<T>
    +
    + + + +
    +Implementation + + +
    public fun balance<T>(coin: &Coin<T>): &Balance<T> {
    +    &coin.balance
    +}
    +
    + + + +
    + + + +## Function `balance_mut` + +Get a mutable reference to the balance of a coin. + + +
    public fun balance_mut<T>(coin: &mut coin::Coin<T>): &mut balance::Balance<T>
    +
    + + + +
    +Implementation + + +
    public fun balance_mut<T>(coin: &mut Coin<T>): &mut Balance<T> {
    +    &mut coin.balance
    +}
    +
    + + + +
    + + + +## Function `from_balance` + +Wrap a balance into a Coin to make it transferable. + + +
    public fun from_balance<T>(balance: balance::Balance<T>, ctx: &mut tx_context::TxContext): coin::Coin<T>
    +
    + + + +
    +Implementation + + +
    public fun from_balance<T>(balance: Balance<T>, ctx: &mut TxContext): Coin<T> {
    +    Coin { id: object::new(ctx), balance }
    +}
    +
    + + + +
    + + + +## Function `into_balance` + +Destruct a Coin wrapper and keep the balance. + + +
    public fun into_balance<T>(coin: coin::Coin<T>): balance::Balance<T>
    +
    + + + +
    +Implementation + + +
    public fun into_balance<T>(coin: Coin<T>): Balance<T> {
    +    let Coin { id, balance } = coin;
    +    id.delete();
    +    balance
    +}
    +
    + + + +
    + + + +## Function `take` + +Take a Coin worth of value from Balance. +Aborts if value > balance.value + + +
    public fun take<T>(balance: &mut balance::Balance<T>, value: u64, ctx: &mut tx_context::TxContext): coin::Coin<T>
    +
    + + + +
    +Implementation + + +
    public fun take<T>(
    +    balance: &mut Balance<T>, value: u64, ctx: &mut TxContext,
    +): Coin<T> {
    +    Coin {
    +        id: object::new(ctx),
    +        balance: balance.split(value)
    +    }
    +}
    +
    + + + +
    + + + +## Function `put` + +Put a Coin<T> to the Balance<T>. + + +
    public fun put<T>(balance: &mut balance::Balance<T>, coin: coin::Coin<T>)
    +
    + + + +
    +Implementation + + +
    public fun put<T>(balance: &mut Balance<T>, coin: Coin<T>) {
    +    balance.join(into_balance(coin));
    +}
    +
    + + + +
    + + + +## Function `join` + +Consume the coin c and add its value to self. +Aborts if c.value + self.value > U64_MAX + + +
    public entry fun join<T>(self: &mut coin::Coin<T>, c: coin::Coin<T>)
    +
    + + + +
    +Implementation + + +
    public entry fun join<T>(self: &mut Coin<T>, c: Coin<T>) {
    +    let Coin { id, balance } = c;
    +    id.delete();
    +    self.balance.join(balance);
    +}
    +
    + + + +
    + + + +## Function `split` + +Split coin self to two coins, one with balance split_amount, +and the remaining balance is left is self. + + +
    public fun split<T>(self: &mut coin::Coin<T>, split_amount: u64, ctx: &mut tx_context::TxContext): coin::Coin<T>
    +
    + + + +
    +Implementation + + +
    public fun split<T>(
    +    self: &mut Coin<T>, split_amount: u64, ctx: &mut TxContext
    +): Coin<T> {
    +    take(&mut self.balance, split_amount, ctx)
    +}
    +
    + + + +
    + + + +## Function `divide_into_n` + +Split coin self into n - 1 coins with equal balances. The remainder is left in +self. Return newly created coins. + + +
    public fun divide_into_n<T>(self: &mut coin::Coin<T>, n: u64, ctx: &mut tx_context::TxContext): vector<coin::Coin<T>>
    +
    + + + +
    +Implementation + + +
    public fun divide_into_n<T>(
    +    self: &mut Coin<T>, n: u64, ctx: &mut TxContext
    +): vector<Coin<T>> {
    +    assert!(n > 0, EInvalidArg);
    +    assert!(n <= value(self), ENotEnough);
    +
    +    let mut vec = vector[];
    +    let mut i = 0;
    +    let split_amount = value(self) / n;
    +    while (i < n - 1) {
    +        vec.push_back(self.split(split_amount, ctx));
    +        i = i + 1;
    +    };
    +    vec
    +}
    +
    + + + +
    + + + +## Function `zero` + +Make any Coin with a zero value. Useful for placeholding +bids/payments or preemptively making empty balances. + + +
    public fun zero<T>(ctx: &mut tx_context::TxContext): coin::Coin<T>
    +
    + + + +
    +Implementation + + +
    public fun zero<T>(ctx: &mut TxContext): Coin<T> {
    +    Coin { id: object::new(ctx), balance: balance::zero() }
    +}
    +
    + + + +
    + + + +## Function `destroy_zero` + +Destroy a coin with value zero + + +
    public fun destroy_zero<T>(c: coin::Coin<T>)
    +
    + + + +
    +Implementation + + +
    public fun destroy_zero<T>(c: Coin<T>) {
    +    let Coin { id, balance } = c;
    +    id.delete();
    +    balance.destroy_zero()
    +}
    +
    + + + +
    + + + +## Function `create_currency` + +Create a new currency type T as and return the TreasuryCap for +T to the caller. Can only be called with a one-time-witness +type, ensuring that there's only one TreasuryCap per T. + + +
    public fun create_currency<T: drop>(witness: T, decimals: u8, symbol: vector<u8>, name: vector<u8>, description: vector<u8>, icon_url: option::Option<url::Url>, ctx: &mut tx_context::TxContext): (coin::TreasuryCap<T>, coin::CoinMetadata<T>)
    +
    + + + +
    +Implementation + + +
    public fun create_currency<T: drop>(
    +    witness: T,
    +    decimals: u8,
    +    symbol: vector<u8>,
    +    name: vector<u8>,
    +    description: vector<u8>,
    +    icon_url: Option<Url>,
    +    ctx: &mut TxContext
    +): (TreasuryCap<T>, CoinMetadata<T>) {
    +    // Make sure there's only one instance of the type T
    +    assert!(iota::types::is_one_time_witness(&witness), EBadWitness);
    +
    +    (
    +        TreasuryCap {
    +            id: object::new(ctx),
    +            total_supply: balance::create_supply(witness)
    +        },
    +        CoinMetadata {
    +            id: object::new(ctx),
    +            decimals,
    +            name: string::utf8(name),
    +            symbol: ascii::string(symbol),
    +            description: string::utf8(description),
    +            icon_url
    +        }
    +    )
    +}
    +
    + + + +
    + + + +## Function `create_regulated_currency` + +This creates a new currency, via create_currency, but with an extra capability that +allows for specific addresses to have their coins frozen. Those addresses cannot interact +with the coin as input objects. + + +
    public fun create_regulated_currency<T: drop>(witness: T, decimals: u8, symbol: vector<u8>, name: vector<u8>, description: vector<u8>, icon_url: option::Option<url::Url>, ctx: &mut tx_context::TxContext): (coin::TreasuryCap<T>, coin::DenyCap<T>, coin::CoinMetadata<T>)
    +
    + + + +
    +Implementation + + +
    public fun create_regulated_currency<T: drop>(
    +    witness: T,
    +    decimals: u8,
    +    symbol: vector<u8>,
    +    name: vector<u8>,
    +    description: vector<u8>,
    +    icon_url: Option<Url>,
    +    ctx: &mut TxContext
    +): (TreasuryCap<T>, DenyCap<T>, CoinMetadata<T>) {
    +    let (treasury_cap, metadata) = create_currency(
    +        witness,
    +        decimals,
    +        symbol,
    +        name,
    +        description,
    +        icon_url,
    +        ctx
    +    );
    +    let deny_cap = DenyCap {
    +        id: object::new(ctx),
    +    };
    +    transfer::freeze_object(RegulatedCoinMetadata<T> {
    +        id: object::new(ctx),
    +        coin_metadata_object: object::id(&metadata),
    +        deny_cap_object: object::id(&deny_cap),
    +    });
    +    (treasury_cap, deny_cap, metadata)
    +}
    +
    + + + +
    + + + +## Function `mint` + +Create a coin worth value and increase the total supply +in cap accordingly. + + +
    public fun mint<T>(cap: &mut coin::TreasuryCap<T>, value: u64, ctx: &mut tx_context::TxContext): coin::Coin<T>
    +
    + + + +
    +Implementation + + +
    public fun mint<T>(
    +    cap: &mut TreasuryCap<T>, value: u64, ctx: &mut TxContext,
    +): Coin<T> {
    +    Coin {
    +        id: object::new(ctx),
    +        balance: cap.total_supply.increase_supply(value)
    +    }
    +}
    +
    + + + +
    + + + +## Function `mint_balance` + +Mint some amount of T as a Balance and increase the total +supply in cap accordingly. +Aborts if value + cap.total_supply >= U64_MAX + + +
    public fun mint_balance<T>(cap: &mut coin::TreasuryCap<T>, value: u64): balance::Balance<T>
    +
    + + + +
    +Implementation + + +
    public fun mint_balance<T>(
    +    cap: &mut TreasuryCap<T>, value: u64
    +): Balance<T> {
    +    cap.total_supply.increase_supply(value)
    +}
    +
    + + + +
    + + + +## Function `burn` + +Destroy the coin c and decrease the total supply in cap +accordingly. + + +
    public entry fun burn<T>(cap: &mut coin::TreasuryCap<T>, c: coin::Coin<T>): u64
    +
    + + + +
    +Implementation + + +
    public entry fun burn<T>(cap: &mut TreasuryCap<T>, c: Coin<T>): u64 {
    +    let Coin { id, balance } = c;
    +    id.delete();
    +    cap.total_supply.decrease_supply(balance)
    +}
    +
    + + + +
    + + + +## Function `deny_list_add` + +Adds the given address to the deny list, preventing it +from interacting with the specified coin type as an input to a transaction. + + +
    public fun deny_list_add<T>(deny_list: &mut deny_list::DenyList, _deny_cap: &mut coin::DenyCap<T>, addr: address, _ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public fun deny_list_add<T>(
    +   deny_list: &mut DenyList,
    +   _deny_cap: &mut DenyCap<T>,
    +   addr: address,
    +   _ctx: &mut TxContext
    +) {
    +    let `type` =
    +        type_name::into_string(type_name::get_with_original_ids<T>()).into_bytes();
    +    deny_list::add(
    +        deny_list,
    +        DENY_LIST_COIN_INDEX,
    +        `type`,
    +        addr,
    +    )
    +}
    +
    + + + +
    + + + +## Function `deny_list_remove` + +Removes an address from the deny list. +Aborts with ENotFrozen if the address is not already in the list. + + +
    public fun deny_list_remove<T>(deny_list: &mut deny_list::DenyList, _deny_cap: &mut coin::DenyCap<T>, addr: address, _ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public fun deny_list_remove<T>(
    +   deny_list: &mut DenyList,
    +   _deny_cap: &mut DenyCap<T>,
    +   addr: address,
    +   _ctx: &mut TxContext
    +) {
    +    let `type` =
    +        type_name::into_string(type_name::get_with_original_ids<T>()).into_bytes();
    +    deny_list::remove(
    +        deny_list,
    +        DENY_LIST_COIN_INDEX,
    +        `type`,
    +        addr,
    +    )
    +}
    +
    + + + +
    + + + +## Function `deny_list_contains` + +Returns true iff the given address is denied for the given coin type. It will +return false if given a non-coin type. + + +
    public fun deny_list_contains<T>(freezer: &deny_list::DenyList, addr: address): bool
    +
    + + + +
    +Implementation + + +
    public fun deny_list_contains<T>(
    +   freezer: &DenyList,
    +   addr: address,
    +): bool {
    +    let name = type_name::get_with_original_ids<T>();
    +    if (type_name::is_primitive(&name)) return false;
    +
    +    let `type` = type_name::into_string(name).into_bytes();
    +    freezer.contains(DENY_LIST_COIN_INDEX, `type`, addr)
    +}
    +
    + + + +
    + + + +## Function `mint_and_transfer` + +Mint amount of Coin and send it to recipient. Invokes mint(). + + +
    public entry fun mint_and_transfer<T>(c: &mut coin::TreasuryCap<T>, amount: u64, recipient: address, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun mint_and_transfer<T>(
    +    c: &mut TreasuryCap<T>, amount: u64, recipient: address, ctx: &mut TxContext
    +) {
    +    transfer::public_transfer(mint(c, amount, ctx), recipient)
    +}
    +
    + + + +
    + + + +## Function `update_name` + +Update name of the coin in CoinMetadata + + +
    public entry fun update_name<T>(_treasury: &coin::TreasuryCap<T>, metadata: &mut coin::CoinMetadata<T>, name: string::String)
    +
    + + + +
    +Implementation + + +
    public entry fun update_name<T>(
    +    _treasury: &TreasuryCap<T>, metadata: &mut CoinMetadata<T>, name: string::String
    +) {
    +    metadata.name = name;
    +}
    +
    + + + +
    + + + +## Function `update_symbol` + +Update the symbol of the coin in CoinMetadata + + +
    public entry fun update_symbol<T>(_treasury: &coin::TreasuryCap<T>, metadata: &mut coin::CoinMetadata<T>, symbol: ascii::String)
    +
    + + + +
    +Implementation + + +
    public entry fun update_symbol<T>(
    +    _treasury: &TreasuryCap<T>, metadata: &mut CoinMetadata<T>, symbol: ascii::String
    +) {
    +    metadata.symbol = symbol;
    +}
    +
    + + + +
    + + + +## Function `update_description` + +Update the description of the coin in CoinMetadata + + +
    public entry fun update_description<T>(_treasury: &coin::TreasuryCap<T>, metadata: &mut coin::CoinMetadata<T>, description: string::String)
    +
    + + + +
    +Implementation + + +
    public entry fun update_description<T>(
    +    _treasury: &TreasuryCap<T>, metadata: &mut CoinMetadata<T>, description: string::String
    +) {
    +    metadata.description = description;
    +}
    +
    + + + +
    + + + +## Function `update_icon_url` + +Update the url of the coin in CoinMetadata + + +
    public entry fun update_icon_url<T>(_treasury: &coin::TreasuryCap<T>, metadata: &mut coin::CoinMetadata<T>, url: ascii::String)
    +
    + + + +
    +Implementation + + +
    public entry fun update_icon_url<T>(
    +    _treasury: &TreasuryCap<T>, metadata: &mut CoinMetadata<T>, url: ascii::String
    +) {
    +    metadata.icon_url = option::some(url::new_unsafe(url));
    +}
    +
    + + + +
    + + + +## Function `get_decimals` + + + +
    public fun get_decimals<T>(metadata: &coin::CoinMetadata<T>): u8
    +
    + + + +
    +Implementation + + +
    public fun get_decimals<T>(metadata: &CoinMetadata<T>): u8 {
    +    metadata.decimals
    +}
    +
    + + + +
    + + + +## Function `get_name` + + + +
    public fun get_name<T>(metadata: &coin::CoinMetadata<T>): string::String
    +
    + + + +
    +Implementation + + +
    public fun get_name<T>(metadata: &CoinMetadata<T>): string::String {
    +    metadata.name
    +}
    +
    + + + +
    + + + +## Function `get_symbol` + + + +
    public fun get_symbol<T>(metadata: &coin::CoinMetadata<T>): ascii::String
    +
    + + + +
    +Implementation + + +
    public fun get_symbol<T>(metadata: &CoinMetadata<T>): ascii::String {
    +    metadata.symbol
    +}
    +
    + + + +
    + + + +## Function `get_description` + + + +
    public fun get_description<T>(metadata: &coin::CoinMetadata<T>): string::String
    +
    + + + +
    +Implementation + + +
    public fun get_description<T>(metadata: &CoinMetadata<T>): string::String {
    +    metadata.description
    +}
    +
    + + + +
    + + + +## Function `get_icon_url` + + + +
    public fun get_icon_url<T>(metadata: &coin::CoinMetadata<T>): option::Option<url::Url>
    +
    + + + +
    +Implementation + + +
    public fun get_icon_url<T>(metadata: &CoinMetadata<T>): Option<Url> {
    +    metadata.icon_url
    +}
    +
    + + + +
    + + + +## Function `supply` + + + +
    public fun supply<T>(treasury: &mut coin::TreasuryCap<T>): &balance::Supply<T>
    +
    + + + +
    +Implementation + + +
    public fun supply<T>(treasury: &mut TreasuryCap<T>): &Supply<T> {
    +    &treasury.total_supply
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/sui-framework/coin_manager.md b/crates/iota-framework/docs/iota-framework/coin_manager.md similarity index 100% rename from crates/sui-framework/docs/sui-framework/coin_manager.md rename to crates/iota-framework/docs/iota-framework/coin_manager.md diff --git a/crates/iota-framework/docs/iota-framework/deny_list.md b/crates/iota-framework/docs/iota-framework/deny_list.md new file mode 100644 index 00000000000..9ea567bdba2 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/deny_list.md @@ -0,0 +1,411 @@ +--- +title: Module `0x2::deny_list` +--- + +Defines the DenyList type. The DenyList shared object is used to restrict access to +instances of certain core types from being used as inputs by specified addresses in the deny +list. + + +- [Resource `DenyList`](#0x2_deny_list_DenyList) +- [Resource `PerTypeList`](#0x2_deny_list_PerTypeList) +- [Constants](#@Constants_0) +- [Function `add`](#0x2_deny_list_add) +- [Function `per_type_list_add`](#0x2_deny_list_per_type_list_add) +- [Function `remove`](#0x2_deny_list_remove) +- [Function `per_type_list_remove`](#0x2_deny_list_per_type_list_remove) +- [Function `contains`](#0x2_deny_list_contains) +- [Function `per_type_list_contains`](#0x2_deny_list_per_type_list_contains) +- [Function `create`](#0x2_deny_list_create) +- [Function `per_type_list`](#0x2_deny_list_per_type_list) + + +
    use 0x2::bag;
    +use 0x2::object;
    +use 0x2::table;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +use 0x2::vec_set;
    +
    + + + + + +## Resource `DenyList` + +A shared object that stores the addresses that are blocked for a given core type. + + +
    struct DenyList has key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +lists: bag::Bag +
    +
    + The individual deny lists. +
    +
    + + +
    + + + +## Resource `PerTypeList` + +Stores the addresses that are denied for a given core type. + + +
    struct PerTypeList has store, key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +denied_count: table::Table<address, u64> +
    +
    + Number of object types that have been banned for a given address. + Used to quickly skip checks for most addresses. +
    +
    +denied_addresses: table::Table<vector<u8>, vec_set::VecSet<address>> +
    +
    + Set of addresses that are banned for a given type. + For example with iota::coin::Coin: If addresses A and B are banned from using + "0...0123::my_coin::MY_COIN", this will be "0...0123::my_coin::MY_COIN" -> {A, B}. +
    +
    + + +
    + + + +## Constants + + + + +Trying to create a deny list object when not called by the system address. + + +
    const ENotSystemAddress: u64 = 0;
    +
    + + + + + +The index into the deny list vector for the iota::coin::Coin type. + + +
    const COIN_INDEX: u64 = 0;
    +
    + + + + + +The specified address to be removed is not already in the deny list. + + +
    const ENotDenied: u64 = 1;
    +
    + + + + + +## Function `add` + +Adds the given address to the deny list of the specified type, preventing it +from interacting with instances of that type as an input to a transaction. For coins, +the type specified is the type of the coin, not the coin type itself. For example, +"00...0123::my_coin::MY_COIN" would be the type, not "00...02::coin::Coin". + + +
    public(friend) fun add(deny_list: &mut deny_list::DenyList, per_type_index: u64, type: vector<u8>, addr: address)
    +
    + + + +
    +Implementation + + +
    public(package) fun add(
    +    deny_list: &mut DenyList,
    +    per_type_index: u64,
    +    `type`: vector<u8>,
    +    addr: address,
    +) {
    +    let bag_entry: &mut PerTypeList = &mut deny_list.lists[per_type_index];
    +    bag_entry.per_type_list_add(`type`, addr)
    +}
    +
    + + + +
    + + + +## Function `per_type_list_add` + + + +
    fun per_type_list_add(list: &mut deny_list::PerTypeList, type: vector<u8>, addr: address)
    +
    + + + +
    +Implementation + + +
    fun per_type_list_add(
    +    list: &mut PerTypeList,
    +    `type`: vector<u8>,
    +    addr: address,
    +) {
    +    if (!list.denied_addresses.contains(`type`)) {
    +        list.denied_addresses.add(`type`, vec_set::empty());
    +    };
    +    let denied_addresses = &mut list.denied_addresses[`type`];
    +    let already_denied = denied_addresses.contains(&addr);
    +    if (already_denied) return;
    +
    +    denied_addresses.insert(addr);
    +    if (!list.denied_count.contains(addr)) {
    +        list.denied_count.add(addr, 0);
    +    };
    +    let denied_count = &mut list.denied_count[addr];
    +    *denied_count = *denied_count + 1;
    +}
    +
    + + + +
    + + + +## Function `remove` + +Removes a previously denied address from the list. +Aborts with ENotDenied if the address is not on the list. + + +
    public(friend) fun remove(deny_list: &mut deny_list::DenyList, per_type_index: u64, type: vector<u8>, addr: address)
    +
    + + + +
    +Implementation + + +
    public(package) fun remove(
    +    deny_list: &mut DenyList,
    +    per_type_index: u64,
    +    `type`: vector<u8>,
    +    addr: address,
    +) {
    +    per_type_list_remove(&mut deny_list.lists[per_type_index], `type`, addr)
    +}
    +
    + + + +
    + + + +## Function `per_type_list_remove` + + + +
    fun per_type_list_remove(list: &mut deny_list::PerTypeList, type: vector<u8>, addr: address)
    +
    + + + +
    +Implementation + + +
    fun per_type_list_remove(
    +    list: &mut PerTypeList,
    +    `type`: vector<u8>,
    +    addr: address,
    +) {
    +    let denied_addresses = &mut list.denied_addresses[`type`];
    +    assert!(denied_addresses.contains(&addr), ENotDenied);
    +    denied_addresses.remove(&addr);
    +    let denied_count = &mut list.denied_count[addr];
    +    *denied_count = *denied_count - 1;
    +    if (*denied_count == 0) {
    +        list.denied_count.remove(addr);
    +    }
    +}
    +
    + + + +
    + + + +## Function `contains` + +Returns true iff the given address is denied for the given type. + + +
    public(friend) fun contains(deny_list: &deny_list::DenyList, per_type_index: u64, type: vector<u8>, addr: address): bool
    +
    + + + +
    +Implementation + + +
    public(package) fun contains(
    +    deny_list: &DenyList,
    +    per_type_index: u64,
    +    `type`: vector<u8>,
    +    addr: address,
    +): bool {
    +    per_type_list_contains(&deny_list.lists[per_type_index], `type`, addr)
    +}
    +
    + + + +
    + + + +## Function `per_type_list_contains` + + + +
    fun per_type_list_contains(list: &deny_list::PerTypeList, type: vector<u8>, addr: address): bool
    +
    + + + +
    +Implementation + + +
    fun per_type_list_contains(
    +    list: &PerTypeList,
    +    `type`: vector<u8>,
    +    addr: address,
    +): bool {
    +    if (!list.denied_count.contains(addr)) return false;
    +
    +    let denied_count = &list.denied_count[addr];
    +    if (*denied_count == 0) return false;
    +
    +    if (!list.denied_addresses.contains(`type`)) return false;
    +
    +    let denied_addresses = &list.denied_addresses[`type`];
    +    denied_addresses.contains(&addr)
    +}
    +
    + + + +
    + + + +## Function `create` + +Creation of the deny list object is restricted to the system address +via a system transaction. + + +
    fun create(ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    fun create(ctx: &mut TxContext) {
    +    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    +
    +    let mut lists = bag::new(ctx);
    +    lists.add(COIN_INDEX, per_type_list(ctx));
    +    let deny_list_object = DenyList {
    +        id: object::iota_deny_list_object_id(),
    +        lists,
    +    };
    +    transfer::share_object(deny_list_object);
    +}
    +
    + + + +
    + + + +## Function `per_type_list` + + + +
    fun per_type_list(ctx: &mut tx_context::TxContext): deny_list::PerTypeList
    +
    + + + +
    +Implementation + + +
    fun per_type_list(ctx: &mut TxContext): PerTypeList {
    +    PerTypeList {
    +        id: object::new(ctx),
    +        denied_count: table::new(ctx),
    +        denied_addresses: table::new(ctx),
    +    }
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/sui-framework/display.md b/crates/iota-framework/docs/iota-framework/display.md similarity index 99% rename from crates/sui-framework/docs/sui-framework/display.md rename to crates/iota-framework/docs/iota-framework/display.md index ead7cc3bbd6..7d266086d65 100644 --- a/crates/sui-framework/docs/sui-framework/display.md +++ b/crates/iota-framework/docs/iota-framework/display.md @@ -112,7 +112,7 @@ Event: emitted when a new Display object has been created for type T. Type signature of the event corresponds to the type while id serves for the discovery. -Since Sui RPC supports querying events by type, finding a Display for the T +Since Iota RPC supports querying events by type, finding a Display for the T would be as simple as looking for the first event with Display<T>. diff --git a/crates/iota-framework/docs/iota-framework/dynamic_field.md b/crates/iota-framework/docs/iota-framework/dynamic_field.md new file mode 100644 index 00000000000..921b534cbb9 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/dynamic_field.md @@ -0,0 +1,593 @@ +--- +title: Module `0x2::dynamic_field` +--- + +In addition to the fields declared in its type definition, a Iota object can have dynamic fields +that can be added after the object has been constructed. Unlike ordinary field names +(which are always statically declared identifiers) a dynamic field name can be any value with +the copy, drop, and store abilities, e.g. an integer, a boolean, or a string. +This gives Iota programmers the flexibility to extend objects on-the-fly, and it also serves as a +building block for core collection types + + +- [Resource `Field`](#0x2_dynamic_field_Field) +- [Constants](#@Constants_0) +- [Function `add`](#0x2_dynamic_field_add) +- [Function `borrow`](#0x2_dynamic_field_borrow) +- [Function `borrow_mut`](#0x2_dynamic_field_borrow_mut) +- [Function `remove`](#0x2_dynamic_field_remove) +- [Function `exists_`](#0x2_dynamic_field_exists_) +- [Function `remove_if_exists`](#0x2_dynamic_field_remove_if_exists) +- [Function `exists_with_type`](#0x2_dynamic_field_exists_with_type) +- [Function `field_info`](#0x2_dynamic_field_field_info) +- [Function `field_info_mut`](#0x2_dynamic_field_field_info_mut) +- [Function `hash_type_and_key`](#0x2_dynamic_field_hash_type_and_key) +- [Function `add_child_object`](#0x2_dynamic_field_add_child_object) +- [Function `borrow_child_object`](#0x2_dynamic_field_borrow_child_object) +- [Function `borrow_child_object_mut`](#0x2_dynamic_field_borrow_child_object_mut) +- [Function `remove_child_object`](#0x2_dynamic_field_remove_child_object) +- [Function `has_child_object`](#0x2_dynamic_field_has_child_object) +- [Function `has_child_object_with_ty`](#0x2_dynamic_field_has_child_object_with_ty) + + +
    use 0x1::option;
    +use 0x2::object;
    +
    + + + + + +## Resource `Field` + +Internal object used for storing the field and value + + +
    struct Field<Name: copy, drop, store, Value: store> has key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + Determined by the hash of the object ID, the field name value and it's type, + i.e. hash(parent.id || name || Name) +
    +
    +name: Name +
    +
    + The value for the name of this field +
    +
    +value: Value +
    +
    + The value bound to this field +
    +
    + + +
    + + + +## Constants + + + + +Failed to serialize the field's name + + +
    const EBCSSerializationFailure: u64 = 3;
    +
    + + + + + +The object added as a dynamic field was previously a shared object + + +
    const ESharedObjectOperationNotSupported: u64 = 4;
    +
    + + + + + +The object already has a dynamic field with this name (with the value and type specified) + + +
    const EFieldAlreadyExists: u64 = 0;
    +
    + + + + + +Cannot load dynamic field. +The object does not have a dynamic field with this name (with the value and type specified) + + +
    const EFieldDoesNotExist: u64 = 1;
    +
    + + + + + +The object has a field with that name, but the value type does not match + + +
    const EFieldTypeMismatch: u64 = 2;
    +
    + + + + + +## Function `add` + +Adds a dynamic field to the object object: &mut UID at field specified by name: Name. +Aborts with EFieldAlreadyExists if the object already has that field with that name. + + +
    public fun add<Name: copy, drop, store, Value: store>(object: &mut object::UID, name: Name, value: Value)
    +
    + + + +
    +Implementation + + +
    public fun add<Name: copy + drop + store, Value: store>(
    +    // we use &mut UID in several spots for access control
    +    object: &mut UID,
    +    name: Name,
    +    value: Value,
    +) {
    +    let object_addr = object.to_address();
    +    let hash = hash_type_and_key(object_addr, name);
    +    assert!(!has_child_object(object_addr, hash), EFieldAlreadyExists);
    +    let field = Field {
    +        id: object::new_uid_from_hash(hash),
    +        name,
    +        value,
    +    };
    +    add_child_object(object_addr, field)
    +}
    +
    + + + +
    + + + +## Function `borrow` + +Immutably borrows the objects dynamic field with the name specified by name: Name. +Aborts with EFieldDoesNotExist if the object does not have a field with that name. +Aborts with EFieldTypeMismatch if the field exists, but the value does not have the specified +type. + + +
    public fun borrow<Name: copy, drop, store, Value: store>(object: &object::UID, name: Name): &Value
    +
    + + + +
    +Implementation + + +
    public fun borrow<Name: copy + drop + store, Value: store>(
    +    object: &UID,
    +    name: Name,
    +): &Value {
    +    let object_addr = object.to_address();
    +    let hash = hash_type_and_key(object_addr, name);
    +    let field = borrow_child_object<Field<Name, Value>>(object, hash);
    +    &field.value
    +}
    +
    + + + +
    + + + +## Function `borrow_mut` + +Mutably borrows the objects dynamic field with the name specified by name: Name. +Aborts with EFieldDoesNotExist if the object does not have a field with that name. +Aborts with EFieldTypeMismatch if the field exists, but the value does not have the specified +type. + + +
    public fun borrow_mut<Name: copy, drop, store, Value: store>(object: &mut object::UID, name: Name): &mut Value
    +
    + + + +
    +Implementation + + +
    public fun borrow_mut<Name: copy + drop + store, Value: store>(
    +    object: &mut UID,
    +    name: Name,
    +): &mut Value {
    +    let object_addr = object.to_address();
    +    let hash = hash_type_and_key(object_addr, name);
    +    let field = borrow_child_object_mut<Field<Name, Value>>(object, hash);
    +    &mut field.value
    +}
    +
    + + + +
    + + + +## Function `remove` + +Removes the objects dynamic field with the name specified by name: Name and returns the +bound value. +Aborts with EFieldDoesNotExist if the object does not have a field with that name. +Aborts with EFieldTypeMismatch if the field exists, but the value does not have the specified +type. + + +
    public fun remove<Name: copy, drop, store, Value: store>(object: &mut object::UID, name: Name): Value
    +
    + + + +
    +Implementation + + +
    public fun remove<Name: copy + drop + store, Value: store>(
    +    object: &mut UID,
    +    name: Name,
    +): Value {
    +    let object_addr = object.to_address();
    +    let hash = hash_type_and_key(object_addr, name);
    +    let Field { id, name: _, value } = remove_child_object<Field<Name, Value>>(object_addr, hash);
    +    id.delete();
    +    value
    +}
    +
    + + + +
    + + + +## Function `exists_` + +Returns true if and only if the object has a dynamic field with the name specified by +name: Name but without specifying the Value type + + +
    public fun exists_<Name: copy, drop, store>(object: &object::UID, name: Name): bool
    +
    + + + +
    +Implementation + + +
    public fun exists_<Name: copy + drop + store>(
    +    object: &UID,
    +    name: Name,
    +): bool {
    +    let object_addr = object.to_address();
    +    let hash = hash_type_and_key(object_addr, name);
    +    has_child_object(object_addr, hash)
    +}
    +
    + + + +
    + + + +## Function `remove_if_exists` + +Removes the dynamic field if it exists. Returns the some(Value) if it exists or none otherwise. + + +
    public fun remove_if_exists<Name: copy, drop, store, Value: store>(object: &mut object::UID, name: Name): option::Option<Value>
    +
    + + + +
    +Implementation + + +
    public fun remove_if_exists<Name: copy + drop + store, Value: store>(
    +    object: &mut UID,
    +    name: Name
    +): Option<Value> {
    +    if (exists_<Name>(object, name)) {
    +        option::some(remove(object, name))
    +    } else {
    +        option::none()
    +    }
    +}
    +
    + + + +
    + + + +## Function `exists_with_type` + +Returns true if and only if the object has a dynamic field with the name specified by +name: Name with an assigned value of type Value. + + +
    public fun exists_with_type<Name: copy, drop, store, Value: store>(object: &object::UID, name: Name): bool
    +
    + + + +
    +Implementation + + +
    public fun exists_with_type<Name: copy + drop + store, Value: store>(
    +    object: &UID,
    +    name: Name,
    +): bool {
    +    let object_addr = object.to_address();
    +    let hash = hash_type_and_key(object_addr, name);
    +    has_child_object_with_ty<Field<Name, Value>>(object_addr, hash)
    +}
    +
    + + + +
    + + + +## Function `field_info` + + + +
    public(friend) fun field_info<Name: copy, drop, store>(object: &object::UID, name: Name): (&object::UID, address)
    +
    + + + +
    +Implementation + + +
    public(package) fun field_info<Name: copy + drop + store>(
    +    object: &UID,
    +    name: Name,
    +): (&UID, address) {
    +    let object_addr = object.to_address();
    +    let hash = hash_type_and_key(object_addr, name);
    +    let Field { id, name: _, value } = borrow_child_object<Field<Name, ID>>(object, hash);
    +    (id, value.to_address())
    +}
    +
    + + + +
    + + + +## Function `field_info_mut` + + + +
    public(friend) fun field_info_mut<Name: copy, drop, store>(object: &mut object::UID, name: Name): (&mut object::UID, address)
    +
    + + + +
    +Implementation + + +
    public(package) fun field_info_mut<Name: copy + drop + store>(
    +    object: &mut UID,
    +    name: Name,
    +): (&mut UID, address) {
    +    let object_addr = object.to_address();
    +    let hash = hash_type_and_key(object_addr, name);
    +    let Field { id, name: _, value } = borrow_child_object_mut<Field<Name, ID>>(object, hash);
    +    (id, value.to_address())
    +}
    +
    + + + +
    + + + +## Function `hash_type_and_key` + +May abort with EBCSSerializationFailure. + + +
    public(friend) fun hash_type_and_key<K: copy, drop, store>(parent: address, k: K): address
    +
    + + + +
    +Implementation + + +
    public(package) native fun hash_type_and_key<K: copy + drop + store>(parent: address, k: K): address;
    +
    + + + +
    + + + +## Function `add_child_object` + + + +
    public(friend) fun add_child_object<Child: key>(parent: address, child: Child)
    +
    + + + +
    +Implementation + + +
    public(package) native fun add_child_object<Child: key>(parent: address, child: Child);
    +
    + + + +
    + + + +## Function `borrow_child_object` + +throws EFieldDoesNotExist if a child does not exist with that ID +or throws EFieldTypeMismatch if the type does not match, +and may also abort with EBCSSerializationFailure +we need two versions to return a reference or a mutable reference + + +
    public(friend) fun borrow_child_object<Child: key>(object: &object::UID, id: address): &Child
    +
    + + + +
    +Implementation + + +
    public(package) native fun borrow_child_object<Child: key>(object: &UID, id: address): &Child;
    +
    + + + +
    + + + +## Function `borrow_child_object_mut` + + + +
    public(friend) fun borrow_child_object_mut<Child: key>(object: &mut object::UID, id: address): &mut Child
    +
    + + + +
    +Implementation + + +
    public(package) native fun borrow_child_object_mut<Child: key>(object: &mut UID, id: address): &mut Child;
    +
    + + + +
    + + + +## Function `remove_child_object` + +throws EFieldDoesNotExist if a child does not exist with that ID +or throws EFieldTypeMismatch if the type does not match, +and may also abort with EBCSSerializationFailure. + + +
    public(friend) fun remove_child_object<Child: key>(parent: address, id: address): Child
    +
    + + + +
    +Implementation + + +
    public(package) native fun remove_child_object<Child: key>(parent: address, id: address): Child;
    +
    + + + +
    + + + +## Function `has_child_object` + + + +
    public(friend) fun has_child_object(parent: address, id: address): bool
    +
    + + + +
    +Implementation + + +
    public(package) native fun has_child_object(parent: address, id: address): bool;
    +
    + + + +
    + + + +## Function `has_child_object_with_ty` + + + +
    public(friend) fun has_child_object_with_ty<Child: key>(parent: address, id: address): bool
    +
    + + + +
    +Implementation + + +
    public(package) native fun has_child_object_with_ty<Child: key>(parent: address, id: address): bool;
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-framework/dynamic_object_field.md b/crates/iota-framework/docs/iota-framework/dynamic_object_field.md new file mode 100644 index 00000000000..7bb45fae863 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/dynamic_object_field.md @@ -0,0 +1,284 @@ +--- +title: Module `0x2::dynamic_object_field` +--- + +Similar to iota::dynamic_field, this module allows for the access of dynamic fields. But +unlike, iota::dynamic_field the values bound to these dynamic fields _must_ be objects +themselves. This allows for the objects to still exist within in storage, which may be important +for external tools. The difference is otherwise not observable from within Move. + + +- [Struct `Wrapper`](#0x2_dynamic_object_field_Wrapper) +- [Function `add`](#0x2_dynamic_object_field_add) +- [Function `borrow`](#0x2_dynamic_object_field_borrow) +- [Function `borrow_mut`](#0x2_dynamic_object_field_borrow_mut) +- [Function `remove`](#0x2_dynamic_object_field_remove) +- [Function `exists_`](#0x2_dynamic_object_field_exists_) +- [Function `exists_with_type`](#0x2_dynamic_object_field_exists_with_type) +- [Function `id`](#0x2_dynamic_object_field_id) + + +
    use 0x1::option;
    +use 0x2::dynamic_field;
    +use 0x2::object;
    +
    + + + + + +## Struct `Wrapper` + + + +
    struct Wrapper<Name> has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +name: Name +
    +
    + +
    +
    + + +
    + + + +## Function `add` + +Adds a dynamic object field to the object object: &mut UID at field specified by name: Name. +Aborts with EFieldAlreadyExists if the object already has that field with that name. + + +
    public fun add<Name: copy, drop, store, Value: store, key>(object: &mut object::UID, name: Name, value: Value)
    +
    + + + +
    +Implementation + + +
    public fun add<Name: copy + drop + store, Value: key + store>(
    +    // we use &mut UID in several spots for access control
    +    object: &mut UID,
    +    name: Name,
    +    value: Value,
    +) {
    +    let key = Wrapper { name };
    +    let id = object::id(&value);
    +    field::add(object, key, id);
    +    let (field, _) = field::field_info<Wrapper<Name>>(object, key);
    +    add_child_object(field.to_address(), value);
    +}
    +
    + + + +
    + + + +## Function `borrow` + +Immutably borrows the objects dynamic object field with the name specified by name: Name. +Aborts with EFieldDoesNotExist if the object does not have a field with that name. +Aborts with EFieldTypeMismatch if the field exists, but the value object does not have the +specified type. + + +
    public fun borrow<Name: copy, drop, store, Value: store, key>(object: &object::UID, name: Name): &Value
    +
    + + + +
    +Implementation + + +
    public fun borrow<Name: copy + drop + store, Value: key + store>(
    +    object: &UID,
    +    name: Name,
    +): &Value {
    +    let key = Wrapper { name };
    +    let (field, value_id) = field::field_info<Wrapper<Name>>(object, key);
    +    borrow_child_object<Value>(field, value_id)
    +}
    +
    + + + +
    + + + +## Function `borrow_mut` + +Mutably borrows the objects dynamic object field with the name specified by name: Name. +Aborts with EFieldDoesNotExist if the object does not have a field with that name. +Aborts with EFieldTypeMismatch if the field exists, but the value object does not have the +specified type. + + +
    public fun borrow_mut<Name: copy, drop, store, Value: store, key>(object: &mut object::UID, name: Name): &mut Value
    +
    + + + +
    +Implementation + + +
    public fun borrow_mut<Name: copy + drop + store, Value: key + store>(
    +    object: &mut UID,
    +    name: Name,
    +): &mut Value {
    +    let key = Wrapper { name };
    +    let (field, value_id) = field::field_info_mut<Wrapper<Name>>(object, key);
    +    borrow_child_object_mut<Value>(field, value_id)
    +}
    +
    + + + +
    + + + +## Function `remove` + +Removes the objects dynamic object field with the name specified by name: Name and returns +the bound object. +Aborts with EFieldDoesNotExist if the object does not have a field with that name. +Aborts with EFieldTypeMismatch if the field exists, but the value object does not have the +specified type. + + +
    public fun remove<Name: copy, drop, store, Value: store, key>(object: &mut object::UID, name: Name): Value
    +
    + + + +
    +Implementation + + +
    public fun remove<Name: copy + drop + store, Value: key + store>(
    +    object: &mut UID,
    +    name: Name,
    +): Value {
    +    let key = Wrapper { name };
    +    let (field, value_id) = field::field_info<Wrapper<Name>>(object, key);
    +    let value = remove_child_object<Value>(field.to_address(), value_id);
    +    field::remove<Wrapper<Name>, ID>(object, key);
    +    value
    +}
    +
    + + + +
    + + + +## Function `exists_` + +Returns true if and only if the object has a dynamic object field with the name specified by +name: Name. + + +
    public fun exists_<Name: copy, drop, store>(object: &object::UID, name: Name): bool
    +
    + + + +
    +Implementation + + +
    public fun exists_<Name: copy + drop + store>(
    +    object: &UID,
    +    name: Name,
    +): bool {
    +    let key = Wrapper { name };
    +    field::exists_with_type<Wrapper<Name>, ID>(object, key)
    +}
    +
    + + + +
    + + + +## Function `exists_with_type` + +Returns true if and only if the object has a dynamic field with the name specified by +name: Name with an assigned value of type Value. + + +
    public fun exists_with_type<Name: copy, drop, store, Value: store, key>(object: &object::UID, name: Name): bool
    +
    + + + +
    +Implementation + + +
    public fun exists_with_type<Name: copy + drop + store, Value: key + store>(
    +    object: &UID,
    +    name: Name,
    +): bool {
    +    let key = Wrapper { name };
    +    if (!field::exists_with_type<Wrapper<Name>, ID>(object, key)) return false;
    +    let (field, value_id) = field::field_info<Wrapper<Name>>(object, key);
    +    field::has_child_object_with_ty<Value>(field.to_address(), value_id)
    +}
    +
    + + + +
    + + + +## Function `id` + +Returns the ID of the object associated with the dynamic object field +Returns none otherwise + + +
    public fun id<Name: copy, drop, store>(object: &object::UID, name: Name): option::Option<object::ID>
    +
    + + + +
    +Implementation + + +
    public fun id<Name: copy + drop + store>(
    +    object: &UID,
    +    name: Name,
    +): Option<ID> {
    +    let key = Wrapper { name };
    +    if (!field::exists_with_type<Wrapper<Name>, ID>(object, key)) return option::none();
    +    let (_field, value_addr) = field::field_info<Wrapper<Name>>(object, key);
    +    option::some(value_addr.to_id())
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/sui-framework/ecdsa_k1.md b/crates/iota-framework/docs/iota-framework/ecdsa_k1.md similarity index 100% rename from crates/sui-framework/docs/sui-framework/ecdsa_k1.md rename to crates/iota-framework/docs/iota-framework/ecdsa_k1.md diff --git a/crates/sui-framework/docs/sui-framework/ecdsa_r1.md b/crates/iota-framework/docs/iota-framework/ecdsa_r1.md similarity index 100% rename from crates/sui-framework/docs/sui-framework/ecdsa_r1.md rename to crates/iota-framework/docs/iota-framework/ecdsa_r1.md diff --git a/crates/sui-framework/docs/sui-framework/ecvrf.md b/crates/iota-framework/docs/iota-framework/ecvrf.md similarity index 100% rename from crates/sui-framework/docs/sui-framework/ecvrf.md rename to crates/iota-framework/docs/iota-framework/ecvrf.md diff --git a/crates/sui-framework/docs/sui-framework/ed25519.md b/crates/iota-framework/docs/iota-framework/ed25519.md similarity index 100% rename from crates/sui-framework/docs/sui-framework/ed25519.md rename to crates/iota-framework/docs/iota-framework/ed25519.md diff --git a/crates/iota-framework/docs/iota-framework/event.md b/crates/iota-framework/docs/iota-framework/event.md new file mode 100644 index 00000000000..1108c5edf6d --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/event.md @@ -0,0 +1,66 @@ +--- +title: Module `0x2::event` +--- + +Events module. Defines the iota::event::emit function which +creates and sends a custom MoveEvent as a part of the effects +certificate of the transaction. + +Every MoveEvent has the following properties: +- sender +- type signature (T) +- event data (the value of T) +- timestamp (local to a node) +- transaction digest + +Example: +``` +module my::marketplace { +use iota::event; +/* ... */ +struct ItemPurchased has copy, drop { +item_id: ID, buyer: address +} +entry fun buy(/* .... */) { +/* ... */ +event::emit(ItemPurchased { item_id: ..., buyer: .... }) +} +} +``` + + +- [Function `emit`](#0x2_event_emit) + + +
    + + + + + +## Function `emit` + +Emit a custom Move event, sending the data offchain. + +Used for creating custom indexes and tracking onchain +activity in a way that iotats a specific application the most. + +The type T is the main way to index the event, and can contain +phantom parameters, eg emit(MyEvent<phantom T>). + + +
    public fun emit<T: copy, drop>(event: T)
    +
    + + + +
    +Implementation + + +
    public native fun emit<T: copy + drop>(event: T);
    +
    + + + +
    diff --git a/crates/sui-framework/docs/sui-framework/groth16.md b/crates/iota-framework/docs/iota-framework/groth16.md similarity index 100% rename from crates/sui-framework/docs/sui-framework/groth16.md rename to crates/iota-framework/docs/iota-framework/groth16.md diff --git a/crates/sui-framework/docs/sui-framework/group_ops.md b/crates/iota-framework/docs/iota-framework/group_ops.md similarity index 100% rename from crates/sui-framework/docs/sui-framework/group_ops.md rename to crates/iota-framework/docs/iota-framework/group_ops.md diff --git a/crates/sui-framework/docs/sui-framework/hash.md b/crates/iota-framework/docs/iota-framework/hash.md similarity index 100% rename from crates/sui-framework/docs/sui-framework/hash.md rename to crates/iota-framework/docs/iota-framework/hash.md diff --git a/crates/iota-framework/docs/iota-framework/hex.md b/crates/iota-framework/docs/iota-framework/hex.md new file mode 100644 index 00000000000..b59adb328b6 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/hex.md @@ -0,0 +1,150 @@ +--- +title: Module `0x2::hex` +--- + +HEX (Base16) encoding utility. + + +- [Constants](#@Constants_0) +- [Function `encode`](#0x2_hex_encode) +- [Function `decode`](#0x2_hex_decode) +- [Function `decode_byte`](#0x2_hex_decode_byte) + + +
    use 0x1::vector;
    +
    + + + + + +## Constants + + + + + + +
    const EInvalidHexLength: u64 = 0;
    +
    + + + + + + + +
    const ENotValidHexCharacter: u64 = 1;
    +
    + + + + + +Vector of Base16 values from 00 to FF + + +
    const HEX: vector<vector<u8>> = [ByteArray([48, 48]), ByteArray([48, 49]), ByteArray([48, 50]), ByteArray([48, 51]), ByteArray([48, 52]), ByteArray([48, 53]), ByteArray([48, 54]), ByteArray([48, 55]), ByteArray([48, 56]), ByteArray([48, 57]), ByteArray([48, 97]), ByteArray([48, 98]), ByteArray([48, 99]), ByteArray([48, 100]), ByteArray([48, 101]), ByteArray([48, 102]), ByteArray([49, 48]), ByteArray([49, 49]), ByteArray([49, 50]), ByteArray([49, 51]), ByteArray([49, 52]), ByteArray([49, 53]), ByteArray([49, 54]), ByteArray([49, 55]), ByteArray([49, 56]), ByteArray([49, 57]), ByteArray([49, 97]), ByteArray([49, 98]), ByteArray([49, 99]), ByteArray([49, 100]), ByteArray([49, 101]), ByteArray([49, 102]), ByteArray([50, 48]), ByteArray([50, 49]), ByteArray([50, 50]), ByteArray([50, 51]), ByteArray([50, 52]), ByteArray([50, 53]), ByteArray([50, 54]), ByteArray([50, 55]), ByteArray([50, 56]), ByteArray([50, 57]), ByteArray([50, 97]), ByteArray([50, 98]), ByteArray([50, 99]), ByteArray([50, 100]), ByteArray([50, 101]), ByteArray([50, 102]), ByteArray([51, 48]), ByteArray([51, 49]), ByteArray([51, 50]), ByteArray([51, 51]), ByteArray([51, 52]), ByteArray([51, 53]), ByteArray([51, 54]), ByteArray([51, 55]), ByteArray([51, 56]), ByteArray([51, 57]), ByteArray([51, 97]), ByteArray([51, 98]), ByteArray([51, 99]), ByteArray([51, 100]), ByteArray([51, 101]), ByteArray([51, 102]), ByteArray([52, 48]), ByteArray([52, 49]), ByteArray([52, 50]), ByteArray([52, 51]), ByteArray([52, 52]), ByteArray([52, 53]), ByteArray([52, 54]), ByteArray([52, 55]), ByteArray([52, 56]), ByteArray([52, 57]), ByteArray([52, 97]), ByteArray([52, 98]), ByteArray([52, 99]), ByteArray([52, 100]), ByteArray([52, 101]), ByteArray([52, 102]), ByteArray([53, 48]), ByteArray([53, 49]), ByteArray([53, 50]), ByteArray([53, 51]), ByteArray([53, 52]), ByteArray([53, 53]), ByteArray([53, 54]), ByteArray([53, 55]), ByteArray([53, 56]), ByteArray([53, 57]), ByteArray([53, 97]), ByteArray([53, 98]), ByteArray([53, 99]), ByteArray([53, 100]), ByteArray([53, 101]), ByteArray([53, 102]), ByteArray([54, 48]), ByteArray([54, 49]), ByteArray([54, 50]), ByteArray([54, 51]), ByteArray([54, 52]), ByteArray([54, 53]), ByteArray([54, 54]), ByteArray([54, 55]), ByteArray([54, 56]), ByteArray([54, 57]), ByteArray([54, 97]), ByteArray([54, 98]), ByteArray([54, 99]), ByteArray([54, 100]), ByteArray([54, 101]), ByteArray([54, 102]), ByteArray([55, 48]), ByteArray([55, 49]), ByteArray([55, 50]), ByteArray([55, 51]), ByteArray([55, 52]), ByteArray([55, 53]), ByteArray([55, 54]), ByteArray([55, 55]), ByteArray([55, 56]), ByteArray([55, 57]), ByteArray([55, 97]), ByteArray([55, 98]), ByteArray([55, 99]), ByteArray([55, 100]), ByteArray([55, 101]), ByteArray([55, 102]), ByteArray([56, 48]), ByteArray([56, 49]), ByteArray([56, 50]), ByteArray([56, 51]), ByteArray([56, 52]), ByteArray([56, 53]), ByteArray([56, 54]), ByteArray([56, 55]), ByteArray([56, 56]), ByteArray([56, 57]), ByteArray([56, 97]), ByteArray([56, 98]), ByteArray([56, 99]), ByteArray([56, 100]), ByteArray([56, 101]), ByteArray([56, 102]), ByteArray([57, 48]), ByteArray([57, 49]), ByteArray([57, 50]), ByteArray([57, 51]), ByteArray([57, 52]), ByteArray([57, 53]), ByteArray([57, 54]), ByteArray([57, 55]), ByteArray([57, 56]), ByteArray([57, 57]), ByteArray([57, 97]), ByteArray([57, 98]), ByteArray([57, 99]), ByteArray([57, 100]), ByteArray([57, 101]), ByteArray([57, 102]), ByteArray([97, 48]), ByteArray([97, 49]), ByteArray([97, 50]), ByteArray([97, 51]), ByteArray([97, 52]), ByteArray([97, 53]), ByteArray([97, 54]), ByteArray([97, 55]), ByteArray([97, 56]), ByteArray([97, 57]), ByteArray([97, 97]), ByteArray([97, 98]), ByteArray([97, 99]), ByteArray([97, 100]), ByteArray([97, 101]), ByteArray([97, 102]), ByteArray([98, 48]), ByteArray([98, 49]), ByteArray([98, 50]), ByteArray([98, 51]), ByteArray([98, 52]), ByteArray([98, 53]), ByteArray([98, 54]), ByteArray([98, 55]), ByteArray([98, 56]), ByteArray([98, 57]), ByteArray([98, 97]), ByteArray([98, 98]), ByteArray([98, 99]), ByteArray([98, 100]), ByteArray([98, 101]), ByteArray([98, 102]), ByteArray([99, 48]), ByteArray([99, 49]), ByteArray([99, 50]), ByteArray([99, 51]), ByteArray([99, 52]), ByteArray([99, 53]), ByteArray([99, 54]), ByteArray([99, 55]), ByteArray([99, 56]), ByteArray([99, 57]), ByteArray([99, 97]), ByteArray([99, 98]), ByteArray([99, 99]), ByteArray([99, 100]), ByteArray([99, 101]), ByteArray([99, 102]), ByteArray([100, 48]), ByteArray([100, 49]), ByteArray([100, 50]), ByteArray([100, 51]), ByteArray([100, 52]), ByteArray([100, 53]), ByteArray([100, 54]), ByteArray([100, 55]), ByteArray([100, 56]), ByteArray([100, 57]), ByteArray([100, 97]), ByteArray([100, 98]), ByteArray([100, 99]), ByteArray([100, 100]), ByteArray([100, 101]), ByteArray([100, 102]), ByteArray([101, 48]), ByteArray([101, 49]), ByteArray([101, 50]), ByteArray([101, 51]), ByteArray([101, 52]), ByteArray([101, 53]), ByteArray([101, 54]), ByteArray([101, 55]), ByteArray([101, 56]), ByteArray([101, 57]), ByteArray([101, 97]), ByteArray([101, 98]), ByteArray([101, 99]), ByteArray([101, 100]), ByteArray([101, 101]), ByteArray([101, 102]), ByteArray([102, 48]), ByteArray([102, 49]), ByteArray([102, 50]), ByteArray([102, 51]), ByteArray([102, 52]), ByteArray([102, 53]), ByteArray([102, 54]), ByteArray([102, 55]), ByteArray([102, 56]), ByteArray([102, 57]), ByteArray([102, 97]), ByteArray([102, 98]), ByteArray([102, 99]), ByteArray([102, 100]), ByteArray([102, 101]), ByteArray([102, 102])];
    +
    + + + + + +## Function `encode` + +Encode bytes in lowercase hex + + +
    public fun encode(bytes: vector<u8>): vector<u8>
    +
    + + + +
    +Implementation + + +
    public fun encode(bytes: vector<u8>): vector<u8> {
    +    let (mut i, mut r, l) = (0, vector[], bytes.length());
    +    let hex_vector = HEX;
    +    while (i < l) {
    +        r.append(hex_vector[bytes[i] as u64]);
    +        i = i + 1;
    +    };
    +    r
    +}
    +
    + + + +
    + + + +## Function `decode` + +Decode hex into bytes +Takes a hex string (no 0x prefix) (e.g. b"0f3a") +Returns vector of bytes that represents the hex string (e.g. x"0f3a") +Hex string can be case insensitive (e.g. b"0F3A" and b"0f3a" both return x"0f3a") +Aborts if the hex string does not have an even number of characters (as each hex character is 2 characters long) +Aborts if the hex string contains non-valid hex characters (valid characters are 0 - 9, a - f, A - F) + + +
    public fun decode(hex: vector<u8>): vector<u8>
    +
    + + + +
    +Implementation + + +
    public fun decode(hex: vector<u8>): vector<u8> {
    +    let (mut i, mut r, l) = (0, vector[], hex.length());
    +    assert!(l % 2 == 0, EInvalidHexLength);
    +    while (i < l) {
    +        let decimal = decode_byte(hex[i]) * 16 + decode_byte(hex[i + 1]);
    +        r.push_back(decimal);
    +        i = i + 2;
    +    };
    +    r
    +}
    +
    + + + +
    + + + +## Function `decode_byte` + + + +
    fun decode_byte(hex: u8): u8
    +
    + + + +
    +Implementation + + +
    fun decode_byte(hex: u8): u8 {
    +    if (/* 0 .. 9 */ 48 <= hex && hex < 58) {
    +        hex - 48
    +    } else if (/* A .. F */ 65 <= hex && hex < 71) {
    +        10 + hex - 65
    +    } else if (/* a .. f */ 97 <= hex && hex < 103) {
    +        10 + hex - 97
    +    } else {
    +        abort ENotValidHexCharacter
    +    }
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-framework/hmac.md b/crates/iota-framework/docs/iota-framework/hmac.md new file mode 100644 index 00000000000..f2109f777c4 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/hmac.md @@ -0,0 +1,37 @@ +--- +title: Module `0x2::hmac` +--- + + + +- [Function `hmac_sha3_256`](#0x2_hmac_hmac_sha3_256) + + +
    + + + + + +## Function `hmac_sha3_256` + +@param key: HMAC key, arbitrary bytes. +@param msg: message to sign, arbitrary bytes. +Returns the 32 bytes digest of HMAC-SHA3-256(key, msg). + + +
    public fun hmac_sha3_256(key: &vector<u8>, msg: &vector<u8>): vector<u8>
    +
    + + + +
    +Implementation + + +
    public native fun hmac_sha3_256(key: &vector<u8>, msg: &vector<u8>): vector<u8>;
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-framework/iota.md b/crates/iota-framework/docs/iota-framework/iota.md new file mode 100644 index 00000000000..7c76bcebee9 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/iota.md @@ -0,0 +1,173 @@ +--- +title: Module `0x2::iota` +--- + +Coin is the token used to pay for gas in Iota. +It has 9 decimals, and the smallest unit (10^-9) is called "micros". + + +- [Struct `IOTA`](#0x2_iota_IOTA) +- [Constants](#@Constants_0) +- [Function `new`](#0x2_iota_new) +- [Function `transfer`](#0x2_iota_transfer) + + +
    use 0x1::option;
    +use 0x2::balance;
    +use 0x2::coin;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +use 0x2::url;
    +
    + + + + + +## Struct `IOTA` + +Name of the coin + + +
    struct IOTA has drop
    +
    + + + +
    +Fields + + +
    +
    +dummy_field: bool +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + +Sender is not @0x0 the system address. + + +
    const ENotSystemAddress: u64 = 1;
    +
    + + + + + + + +
    const EAlreadyMinted: u64 = 0;
    +
    + + + + + +The amount of Micros per Iota token based on the fact that micros is +10^-9 of a Iota token + + +
    const MICROS_PER_IOTA: u64 = 1000000000;
    +
    + + + + + +The total supply of Iota denominated in whole Iota tokens (10 Billion) + + +
    const TOTAL_SUPPLY_IOTA: u64 = 10000000000;
    +
    + + + + + +The total supply of Iota denominated in Micros (10 Billion * 10^9) + + +
    const TOTAL_SUPPLY_MICROS: u64 = 10000000000000000000;
    +
    + + + + + +## Function `new` + +Register the IOTA Coin to acquire its Supply. +This should be called only once during genesis creation. + + +
    fun new(ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
    +
    + + + +
    +Implementation + + +
    fun new(ctx: &mut TxContext): Balance<IOTA> {
    +    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    +    assert!(ctx.epoch() == 0, EAlreadyMinted);
    +
    +    let (treasury, metadata) = coin::create_currency(
    +        IOTA {},
    +        9,
    +        b"IOTA",
    +        b"Iota",
    +        // TODO: add appropriate description and logo url
    +        b"",
    +        option::none(),
    +        ctx
    +    );
    +    transfer::public_freeze_object(metadata);
    +    let mut supply = treasury.treasury_into_supply();
    +    let total_iota = supply.increase_supply(TOTAL_SUPPLY_MICROS);
    +    supply.destroy_supply();
    +    total_iota
    +}
    +
    + + + +
    + + + +## Function `transfer` + + + +
    public entry fun transfer(c: coin::Coin<iota::IOTA>, recipient: address)
    +
    + + + +
    +Implementation + + +
    public entry fun transfer(c: coin::Coin<IOTA>, recipient: address) {
    +    transfer::public_transfer(c, recipient)
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/sui-framework/kiosk.md b/crates/iota-framework/docs/iota-framework/kiosk.md similarity index 98% rename from crates/sui-framework/docs/sui-framework/kiosk.md rename to crates/iota-framework/docs/iota-framework/kiosk.md index 0df77b64dab..17d50068613 100644 --- a/crates/sui-framework/docs/sui-framework/kiosk.md +++ b/crates/iota-framework/docs/iota-framework/kiosk.md @@ -38,7 +38,7 @@ and borrow_val functions. - locked - Similar to placed except that take is disabled and the only way to move the asset out of the Kiosk is to list it or -list_with_purchase_cap therefore performing a trade (issuing a +list_with_purchase_cap therefore performing a trade (isiotang a TransferRequest). The check on the lock function makes sure that the TransferPolicy exists to not lock the item in a Kiosk forever. @@ -87,7 +87,7 @@ one having its own set of rules. object so they don't have to pay anything - I create and wrap a TransferPolicy so that players of my game can transfer items between Kiosks in game without any charge (and maybe not -even paying the price with a 0 SUI PurchaseCap) +even paying the price with a 0 IOTA PurchaseCap) ``` Kiosk -> (Item, TransferRequest) @@ -163,8 +163,8 @@ See transfer_policyuse 0x2::dynamic_field; use 0x2::dynamic_object_field; use 0x2::event; +use 0x2::iota; use 0x2::object; -use 0x2::sui; use 0x2::transfer; use 0x2::transfer_policy; use 0x2::tx_context; @@ -199,7 +199,7 @@ needs to be approved via the TransferPolicy.
    -profits: balance::Balance<sui::SUI> +profits: balance::Balance<iota::IOTA>
    Balance of the Kiosk - all profits from sales go here. @@ -729,8 +729,8 @@ Creates a new Kiosk in a default configuration: sender receives the
    entry fun default(ctx: &mut TxContext) {
         let (kiosk, cap) = new(ctx);
    -    sui::transfer::transfer(cap, ctx.sender());
    -    sui::transfer::share_object(kiosk);
    +    iota::transfer::transfer(cap, ctx.sender());
    +    iota::transfer::share_object(kiosk);
     }
     
    @@ -785,7 +785,7 @@ Can only be performed by the bearer of the Kiosk is not shared. -
    public fun close_and_withdraw(self: kiosk::Kiosk, cap: kiosk::KioskOwnerCap, ctx: &mut tx_context::TxContext): coin::Coin<sui::SUI>
    +
    public fun close_and_withdraw(self: kiosk::Kiosk, cap: kiosk::KioskOwnerCap, ctx: &mut tx_context::TxContext): coin::Coin<iota::IOTA>
     
    @@ -796,7 +796,7 @@ case where there's no items inside and a close_and_withdraw( self: Kiosk, cap: KioskOwnerCap, ctx: &mut TxContext -): Coin<SUI> { +): Coin<IOTA> { let Kiosk { id, profits, owner: _, item_count, allow_extensions: _ } = self; let KioskOwnerCap { id: cap_id, `for` } = cap; @@ -1080,7 +1080,7 @@ request their approval (by calling some function) so that the trade can be finalized. -
    public fun purchase<T: store, key>(self: &mut kiosk::Kiosk, id: object::ID, payment: coin::Coin<sui::SUI>): (T, transfer_policy::TransferRequest<T>)
    +
    public fun purchase<T: store, key>(self: &mut kiosk::Kiosk, id: object::ID, payment: coin::Coin<iota::IOTA>): (T, transfer_policy::TransferRequest<T>)
     
    @@ -1090,7 +1090,7 @@ finalized.
    public fun purchase<T: key + store>(
    -    self: &mut Kiosk, id: ID, payment: Coin<SUI>
    +    self: &mut Kiosk, id: ID, payment: Coin<IOTA>
     ): (T, TransferRequest<T>) {
         let price = df::remove<Listing, u64>(&mut self.id, Listing { id, is_exclusive: false });
         let inner = dof::remove<Item, T>(&mut self.id, Item { id });
    @@ -1157,7 +1157,7 @@ Unpack the PurchaseCap
     as the price for the listing making sure it's no less than min_amount.
     
     
    -
    public fun purchase_with_cap<T: store, key>(self: &mut kiosk::Kiosk, purchase_cap: kiosk::PurchaseCap<T>, payment: coin::Coin<sui::SUI>): (T, transfer_policy::TransferRequest<T>)
    +
    public fun purchase_with_cap<T: store, key>(self: &mut kiosk::Kiosk, purchase_cap: kiosk::PurchaseCap<T>, payment: coin::Coin<iota::IOTA>): (T, transfer_policy::TransferRequest<T>)
     
    @@ -1167,7 +1167,7 @@ as the price for the listing making sure it's no less than min_amountpublic fun purchase_with_cap<T: key + store>( - self: &mut Kiosk, purchase_cap: PurchaseCap<T>, payment: Coin<SUI> + self: &mut Kiosk, purchase_cap: PurchaseCap<T>, payment: Coin<IOTA> ): (T, TransferRequest<T>) { let PurchaseCap { id, item_id, kiosk_id, min_price } = purchase_cap; id.delete(); @@ -1231,7 +1231,7 @@ allow the item for taking. Can only be returned to its withdraw(self: &mut kiosk::Kiosk, cap: &kiosk::KioskOwnerCap, amount: option::Option<u64>, ctx: &mut tx_context::TxContext): coin::Coin<sui::SUI> +
    public fun withdraw(self: &mut kiosk::Kiosk, cap: &kiosk::KioskOwnerCap, amount: option::Option<u64>, ctx: &mut tx_context::TxContext): coin::Coin<iota::IOTA>
     
    @@ -1242,7 +1242,7 @@ Withdraw profits from the Kiosk.
    public fun withdraw(
         self: &mut Kiosk, cap: &KioskOwnerCap, amount: Option<u64>, ctx: &mut TxContext
    -): Coin<SUI> {
    +): Coin<IOTA> {
         assert!(self.has_access(cap), ENotOwner);
     
         let amount = if (amount.is_some()) {
    @@ -1687,7 +1687,7 @@ Get the amount of profits collected by selling items.
     Get mutable access to profits - owner only action.
     
     
    -
    public fun profits_mut(self: &mut kiosk::Kiosk, cap: &kiosk::KioskOwnerCap): &mut balance::Balance<sui::SUI>
    +
    public fun profits_mut(self: &mut kiosk::Kiosk, cap: &kiosk::KioskOwnerCap): &mut balance::Balance<iota::IOTA>
     
    @@ -1696,7 +1696,7 @@ Get mutable access to profits - owner only action. Implementation -
    public fun profits_mut(self: &mut Kiosk, cap: &KioskOwnerCap): &mut Balance<SUI> {
    +
    public fun profits_mut(self: &mut Kiosk, cap: &KioskOwnerCap): &mut Balance<IOTA> {
         assert!(self.has_access(cap), ENotOwner);
         &mut self.profits
     }
    diff --git a/crates/sui-framework/docs/sui-framework/kiosk_extension.md b/crates/iota-framework/docs/iota-framework/kiosk_extension.md
    similarity index 100%
    rename from crates/sui-framework/docs/sui-framework/kiosk_extension.md
    rename to crates/iota-framework/docs/iota-framework/kiosk_extension.md
    diff --git a/crates/iota-framework/docs/iota-framework/linked_table.md b/crates/iota-framework/docs/iota-framework/linked_table.md
    new file mode 100644
    index 00000000000..c3510deecde
    --- /dev/null
    +++ b/crates/iota-framework/docs/iota-framework/linked_table.md
    @@ -0,0 +1,648 @@
    +---
    +title: Module `0x2::linked_table`
    +---
    +
    +Similar to iota::table but the values are linked together, allowing for ordered insertion and
    +removal
    +
    +
    +-  [Resource `LinkedTable`](#0x2_linked_table_LinkedTable)
    +-  [Struct `Node`](#0x2_linked_table_Node)
    +-  [Constants](#@Constants_0)
    +-  [Function `new`](#0x2_linked_table_new)
    +-  [Function `front`](#0x2_linked_table_front)
    +-  [Function `back`](#0x2_linked_table_back)
    +-  [Function `push_front`](#0x2_linked_table_push_front)
    +-  [Function `push_back`](#0x2_linked_table_push_back)
    +-  [Function `borrow`](#0x2_linked_table_borrow)
    +-  [Function `borrow_mut`](#0x2_linked_table_borrow_mut)
    +-  [Function `prev`](#0x2_linked_table_prev)
    +-  [Function `next`](#0x2_linked_table_next)
    +-  [Function `remove`](#0x2_linked_table_remove)
    +-  [Function `pop_front`](#0x2_linked_table_pop_front)
    +-  [Function `pop_back`](#0x2_linked_table_pop_back)
    +-  [Function `contains`](#0x2_linked_table_contains)
    +-  [Function `length`](#0x2_linked_table_length)
    +-  [Function `is_empty`](#0x2_linked_table_is_empty)
    +-  [Function `destroy_empty`](#0x2_linked_table_destroy_empty)
    +-  [Function `drop`](#0x2_linked_table_drop)
    +
    +
    +
    use 0x1::option;
    +use 0x2::dynamic_field;
    +use 0x2::object;
    +use 0x2::tx_context;
    +
    + + + + + +## Resource `LinkedTable` + + + +
    struct LinkedTable<K: copy, drop, store, V: store> has store, key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + the ID of this table +
    +
    +size: u64 +
    +
    + the number of key-value pairs in the table +
    +
    +head: option::Option<K> +
    +
    + the front of the table, i.e. the key of the first entry +
    +
    +tail: option::Option<K> +
    +
    + the back of the table, i.e. the key of the last entry +
    +
    + + +
    + + + +## Struct `Node` + + + +
    struct Node<K: copy, drop, store, V: store> has store
    +
    + + + +
    +Fields + + +
    +
    +prev: option::Option<K> +
    +
    + the previous key +
    +
    +next: option::Option<K> +
    +
    + the next key +
    +
    +value: V +
    +
    + the value being stored +
    +
    + + +
    + + + +## Constants + + + + + + +
    const ETableNotEmpty: u64 = 0;
    +
    + + + + + + + +
    const ETableIsEmpty: u64 = 1;
    +
    + + + + + +## Function `new` + +Creates a new, empty table + + +
    public fun new<K: copy, drop, store, V: store>(ctx: &mut tx_context::TxContext): linked_table::LinkedTable<K, V>
    +
    + + + +
    +Implementation + + +
    public fun new<K: copy + drop + store, V: store>(ctx: &mut TxContext): LinkedTable<K, V> {
    +    LinkedTable {
    +        id: object::new(ctx),
    +        size: 0,
    +        head: option::none(),
    +        tail: option::none(),
    +    }
    +}
    +
    + + + +
    + + + +## Function `front` + +Returns the key for the first element in the table, or None if the table is empty + + +
    public fun front<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>): &option::Option<K>
    +
    + + + +
    +Implementation + + +
    public fun front<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>): &Option<K> {
    +    &table.head
    +}
    +
    + + + +
    + + + +## Function `back` + +Returns the key for the last element in the table, or None if the table is empty + + +
    public fun back<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>): &option::Option<K>
    +
    + + + +
    +Implementation + + +
    public fun back<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>): &Option<K> {
    +    &table.tail
    +}
    +
    + + + +
    + + + +## Function `push_front` + +Inserts a key-value pair at the front of the table, i.e. the newly inserted pair will be +the first element in the table +Aborts with iota::dynamic_field::EFieldAlreadyExists if the table already has an entry with +that key k: K. + + +
    public fun push_front<K: copy, drop, store, V: store>(table: &mut linked_table::LinkedTable<K, V>, k: K, value: V)
    +
    + + + +
    +Implementation + + +
    public fun push_front<K: copy + drop + store, V: store>(
    +    table: &mut LinkedTable<K, V>,
    +    k: K,
    +    value: V,
    +) {
    +    let old_head = table.head.swap_or_fill(k);
    +    if (table.tail.is_none()) table.tail.fill(k);
    +    let prev = option::none();
    +    let next = if (old_head.is_some()) {
    +        let old_head_k = old_head.destroy_some();
    +        field::borrow_mut<K, Node<K, V>>(&mut table.id, old_head_k).prev = option::some(k);
    +        option::some(old_head_k)
    +    } else {
    +        option::none()
    +    };
    +    field::add(&mut table.id, k, Node { prev, next, value });
    +    table.size = table.size + 1;
    +}
    +
    + + + +
    + + + +## Function `push_back` + +Inserts a key-value pair at the back of the table, i.e. the newly inserted pair will be +the last element in the table +Aborts with iota::dynamic_field::EFieldAlreadyExists if the table already has an entry with +that key k: K. + + +
    public fun push_back<K: copy, drop, store, V: store>(table: &mut linked_table::LinkedTable<K, V>, k: K, value: V)
    +
    + + + +
    +Implementation + + +
    public fun push_back<K: copy + drop + store, V: store>(
    +    table: &mut LinkedTable<K, V>,
    +    k: K,
    +    value: V,
    +) {
    +    if (table.head.is_none()) table.head.fill(k);
    +    let old_tail = table.tail.swap_or_fill(k);
    +    let prev = if (old_tail.is_some()) {
    +        let old_tail_k = old_tail.destroy_some();
    +        field::borrow_mut<K, Node<K, V>>(&mut table.id, old_tail_k).next = option::some(k);
    +        option::some(old_tail_k)
    +    } else {
    +        option::none()
    +    };
    +    let next = option::none();
    +    field::add(&mut table.id, k, Node { prev, next, value });
    +    table.size = table.size + 1;
    +}
    +
    + + + +
    + + + +## Function `borrow` + +Immutable borrows the value associated with the key in the table table: &LinkedTable<K, V>. +Aborts with iota::dynamic_field::EFieldDoesNotExist if the table does not have an entry with +that key k: K. + + +
    public fun borrow<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>, k: K): &V
    +
    + + + +
    +Implementation + + +
    public fun borrow<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>, k: K): &V {
    +    &field::borrow<K, Node<K, V>>(&table.id, k).value
    +}
    +
    + + + +
    + + + +## Function `borrow_mut` + +Mutably borrows the value associated with the key in the table table: &mut LinkedTable<K, V>. +Aborts with iota::dynamic_field::EFieldDoesNotExist if the table does not have an entry with +that key k: K. + + +
    public fun borrow_mut<K: copy, drop, store, V: store>(table: &mut linked_table::LinkedTable<K, V>, k: K): &mut V
    +
    + + + +
    +Implementation + + +
    public fun borrow_mut<K: copy + drop + store, V: store>(
    +    table: &mut LinkedTable<K, V>,
    +    k: K,
    +): &mut V {
    +    &mut field::borrow_mut<K, Node<K, V>>(&mut table.id, k).value
    +}
    +
    + + + +
    + + + +## Function `prev` + +Borrows the key for the previous entry of the specified key k: K in the table +table: &LinkedTable<K, V>. Returns None if the entry does not have a predecessor. +Aborts with iota::dynamic_field::EFieldDoesNotExist if the table does not have an entry with +that key k: K + + +
    public fun prev<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>, k: K): &option::Option<K>
    +
    + + + +
    +Implementation + + +
    public fun prev<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>, k: K): &Option<K> {
    +    &field::borrow<K, Node<K, V>>(&table.id, k).prev
    +}
    +
    + + + +
    + + + +## Function `next` + +Borrows the key for the next entry of the specified key k: K in the table +table: &LinkedTable<K, V>. Returns None if the entry does not have a predecessor. +Aborts with iota::dynamic_field::EFieldDoesNotExist if the table does not have an entry with +that key k: K + + +
    public fun next<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>, k: K): &option::Option<K>
    +
    + + + +
    +Implementation + + +
    public fun next<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>, k: K): &Option<K> {
    +    &field::borrow<K, Node<K, V>>(&table.id, k).next
    +}
    +
    + + + +
    + + + +## Function `remove` + +Removes the key-value pair in the table table: &mut LinkedTable<K, V> and returns the value. +This splices the element out of the ordering. +Aborts with iota::dynamic_field::EFieldDoesNotExist if the table does not have an entry with +that key k: K. Note: this is also what happens when the table is empty. + + +
    public fun remove<K: copy, drop, store, V: store>(table: &mut linked_table::LinkedTable<K, V>, k: K): V
    +
    + + + +
    +Implementation + + +
    public fun remove<K: copy + drop + store, V: store>(table: &mut LinkedTable<K, V>, k: K): V {
    +    let Node<K, V> { prev, next, value } = field::remove(&mut table.id, k);
    +    table.size = table.size - 1;
    +    if (prev.is_some()) {
    +        field::borrow_mut<K, Node<K, V>>(&mut table.id, *prev.borrow()).next = next
    +    };
    +    if (next.is_some()) {
    +        field::borrow_mut<K, Node<K, V>>(&mut table.id, *next.borrow()).prev = prev
    +    };
    +    if (table.head.borrow() == &k) table.head = next;
    +    if (table.tail.borrow() == &k) table.tail = prev;
    +    value
    +}
    +
    + + + +
    + + + +## Function `pop_front` + +Removes the front of the table table: &mut LinkedTable<K, V> and returns the value. +Aborts with ETableIsEmpty if the table is empty + + +
    public fun pop_front<K: copy, drop, store, V: store>(table: &mut linked_table::LinkedTable<K, V>): (K, V)
    +
    + + + +
    +Implementation + + +
    public fun pop_front<K: copy + drop + store, V: store>(table: &mut LinkedTable<K, V>): (K, V) {
    +    assert!(table.head.is_some(), ETableIsEmpty);
    +    let head = *table.head.borrow();
    +    (head, table.remove(head))
    +}
    +
    + + + +
    + + + +## Function `pop_back` + +Removes the back of the table table: &mut LinkedTable<K, V> and returns the value. +Aborts with ETableIsEmpty if the table is empty + + +
    public fun pop_back<K: copy, drop, store, V: store>(table: &mut linked_table::LinkedTable<K, V>): (K, V)
    +
    + + + +
    +Implementation + + +
    public fun pop_back<K: copy + drop + store, V: store>(table: &mut LinkedTable<K, V>): (K, V) {
    +    assert!(table.tail.is_some(), ETableIsEmpty);
    +    let tail = *table.tail.borrow();
    +    (tail, table.remove(tail))
    +}
    +
    + + + +
    + + + +## Function `contains` + +Returns true iff there is a value associated with the key k: K in table +table: &LinkedTable<K, V> + + +
    public fun contains<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>, k: K): bool
    +
    + + + +
    +Implementation + + +
    public fun contains<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>, k: K): bool {
    +    field::exists_with_type<K, Node<K, V>>(&table.id, k)
    +}
    +
    + + + +
    + + + +## Function `length` + +Returns the size of the table, the number of key-value pairs + + +
    public fun length<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>): u64
    +
    + + + +
    +Implementation + + +
    public fun length<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>): u64 {
    +    table.size
    +}
    +
    + + + +
    + + + +## Function `is_empty` + +Returns true iff the table is empty (if length returns 0) + + +
    public fun is_empty<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>): bool
    +
    + + + +
    +Implementation + + +
    public fun is_empty<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>): bool {
    +    table.size == 0
    +}
    +
    + + + +
    + + + +## Function `destroy_empty` + +Destroys an empty table +Aborts with ETableNotEmpty if the table still contains values + + +
    public fun destroy_empty<K: copy, drop, store, V: store>(table: linked_table::LinkedTable<K, V>)
    +
    + + + +
    +Implementation + + +
    public fun destroy_empty<K: copy + drop + store, V: store>(table: LinkedTable<K, V>) {
    +    let LinkedTable { id, size, head: _, tail: _ } = table;
    +    assert!(size == 0, ETableNotEmpty);
    +    id.delete()
    +}
    +
    + + + +
    + + + +## Function `drop` + +Drop a possibly non-empty table. +Usable only if the value type V has the drop ability + + +
    public fun drop<K: copy, drop, store, V: drop, store>(table: linked_table::LinkedTable<K, V>)
    +
    + + + +
    +Implementation + + +
    public fun drop<K: copy + drop + store, V: drop + store>(table: LinkedTable<K, V>) {
    +    let LinkedTable { id, size: _, head: _, tail: _ } = table;
    +    id.delete()
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/sui-framework/math.md b/crates/iota-framework/docs/iota-framework/math.md similarity index 76% rename from crates/sui-framework/docs/sui-framework/math.md rename to crates/iota-framework/docs/iota-framework/math.md index ab60c274331..7ff51e865e9 100644 --- a/crates/sui-framework/docs/sui-framework/math.md +++ b/crates/iota-framework/docs/iota-framework/math.md @@ -25,7 +25,7 @@ Basic math for nicer programmability Return the larger of x and y -
    public fun max(x: u64, y: u64): u64
    +
    public fun max(x: u64, y: u64): u64
     
    @@ -34,7 +34,7 @@ Return the larger of x and y Implementation -
    public fun max(x: u64, y: u64): u64 {
    +
    public fun max(x: u64, y: u64): u64 {
         if (x > y) {
             x
         } else {
    @@ -83,7 +83,7 @@ Return the smaller of x and y
     Return the absolute value of x - y
     
     
    -
    public fun diff(x: u64, y: u64): u64
    +
    public fun diff(x: u64, y: u64): u64
     
    @@ -92,7 +92,7 @@ Return the absolute value of x - y Implementation -
    public fun diff(x: u64, y: u64): u64 {
    +
    public fun diff(x: u64, y: u64): u64 {
         if (x > y) {
             x - y
         } else {
    @@ -112,7 +112,7 @@ Return the absolute value of x - y
     Return the value of a base raised to a power
     
     
    -
    public fun pow(base: u64, exponent: u8): u64
    +
    public fun pow(base: u64, exponent: u8): u64
     
    @@ -121,7 +121,7 @@ Return the value of a base raised to a power Implementation -
    public fun pow(mut base: u64, mut exponent: u8): u64 {
    +
    public fun pow(mut base: u64, mut exponent: u8): u64 {
         let mut res = 1;
         while (exponent >= 1) {
             if (exponent % 2 == 0) {
    @@ -172,7 +172,7 @@ math::sqrt(8 * 1000000) => 2828; // same as above, 2828 / 1000 (2.828)
     ```
     
     
    -
    public fun sqrt(x: u64): u64
    +
    public fun sqrt(x: u64): u64
     
    @@ -181,7 +181,7 @@ math::sqrt(8 * 1000000) => 2828; // same as above, 2828 / 1000 (2.828) Implementation -
    public fun sqrt(x: u64): u64 {
    +
    public fun sqrt(x: u64): u64 {
         let mut bit = 1u128 << 64;
         let mut res = 0u128;
         let mut x = x as u128;
    @@ -235,7 +235,7 @@ math::sqrt_u128(8 * 1000000) => 2828; // same as above, 2828 / 1000 (2.828)
     ```
     
     
    -
    public fun sqrt_u128(x: u128): u128
    +
    public fun sqrt_u128(x: u128): u128
     
    @@ -244,7 +244,7 @@ math::sqrt_u128(8 * 1000000) => 2828; // same as above, 2828 / 1000 (2.828) Implementation -
    public fun sqrt_u128(x: u128): u128 {
    +
    public fun sqrt_u128(x: u128): u128 {
         let mut bit = 1u256 << 128;
         let mut res = 0u256;
         let mut x = x as u256;
    @@ -274,7 +274,7 @@ math::sqrt_u128(8 * 1000000) => 2828; // same as above, 2828 / 1000 (2.828)
     Calculate x / y, but round up the result.
     
     
    -
    public fun divide_and_round_up(x: u64, y: u64): u64
    +
    public fun divide_and_round_up(x: u64, y: u64): u64
     
    @@ -283,7 +283,7 @@ Calculate x / y, but round up the result. Implementation -
    public fun divide_and_round_up(x: u64, y: u64): u64 {
    +
    public fun divide_and_round_up(x: u64, y: u64): u64 {
         if (x % y == 0) {
             x / y
         } else {
    diff --git a/crates/iota-framework/docs/iota-framework/object.md b/crates/iota-framework/docs/iota-framework/object.md
    new file mode 100644
    index 00000000000..b55faf25389
    --- /dev/null
    +++ b/crates/iota-framework/docs/iota-framework/object.md
    @@ -0,0 +1,764 @@
    +---
    +title: Module `0x2::object`
    +---
    +
    +Iota object identifiers
    +
    +
    +-  [Struct `ID`](#0x2_object_ID)
    +-  [Struct `UID`](#0x2_object_UID)
    +-  [Constants](#@Constants_0)
    +-  [Function `id_to_bytes`](#0x2_object_id_to_bytes)
    +-  [Function `id_to_address`](#0x2_object_id_to_address)
    +-  [Function `id_from_bytes`](#0x2_object_id_from_bytes)
    +-  [Function `id_from_address`](#0x2_object_id_from_address)
    +-  [Function `iota_system_state`](#0x2_object_iota_system_state)
    +-  [Function `clock`](#0x2_object_clock)
    +-  [Function `authenticator_state`](#0x2_object_authenticator_state)
    +-  [Function `randomness_state`](#0x2_object_randomness_state)
    +-  [Function `iota_deny_list_object_id`](#0x2_object_iota_deny_list_object_id)
    +-  [Function `uid_as_inner`](#0x2_object_uid_as_inner)
    +-  [Function `uid_to_inner`](#0x2_object_uid_to_inner)
    +-  [Function `uid_to_bytes`](#0x2_object_uid_to_bytes)
    +-  [Function `uid_to_address`](#0x2_object_uid_to_address)
    +-  [Function `new`](#0x2_object_new)
    +-  [Function `delete`](#0x2_object_delete)
    +-  [Function `id`](#0x2_object_id)
    +-  [Function `borrow_id`](#0x2_object_borrow_id)
    +-  [Function `id_bytes`](#0x2_object_id_bytes)
    +-  [Function `id_address`](#0x2_object_id_address)
    +-  [Function `borrow_uid`](#0x2_object_borrow_uid)
    +-  [Function `new_uid_from_hash`](#0x2_object_new_uid_from_hash)
    +-  [Function `delete_impl`](#0x2_object_delete_impl)
    +-  [Function `record_new_uid`](#0x2_object_record_new_uid)
    +
    +
    +
    use 0x1::bcs;
    +use 0x2::address;
    +use 0x2::tx_context;
    +
    + + + + + +## Struct `ID` + +An object ID. This is used to reference Iota Objects. +This is *not* guaranteed to be globally unique--anyone can create an ID from a UID or +from an object, and ID's can be freely copied and dropped. +Here, the values are not globally unique because there can be multiple values of type ID +with the same underlying bytes. For example, object::id(&obj) can be called as many times +as you want for a given obj, and each ID value will be identical. + + +
    struct ID has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +bytes: address +
    +
    + +
    +
    + + +
    + + + +## Struct `UID` + +Globally unique IDs that define an object's ID in storage. Any Iota Object, that is a struct +with the key ability, must have id: UID as its first field. +These are globally unique in the sense that no two values of type UID are ever equal, in +other words for any two values id1: UID and id2: UID, id1 != id2. +This is a privileged type that can only be derived from a TxContext. +UID doesn't have the drop ability, so deleting a UID requires a call to delete. + + +
    struct UID has store
    +
    + + + +
    +Fields + + +
    +
    +id: object::ID +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + +Sender is not @0x0 the system address. + + +
    const ENotSystemAddress: u64 = 0;
    +
    + + + + + +The hardcoded ID for the singleton AuthenticatorState Object. + + +
    const IOTA_AUTHENTICATOR_STATE_ID: address = 7;
    +
    + + + + + +The hardcoded ID for the singleton Clock Object. + + +
    const IOTA_CLOCK_OBJECT_ID: address = 6;
    +
    + + + + + +The hardcoded ID for the singleton DenyList. + + +
    const IOTA_DENY_LIST_OBJECT_ID: address = 403;
    +
    + + + + + +The hardcoded ID for the singleton Random Object. + + +
    const IOTA_RANDOM_ID: address = 8;
    +
    + + + + + +The hardcoded ID for the singleton Iota System State Object. + + +
    const IOTA_SYSTEM_STATE_OBJECT_ID: address = 5;
    +
    + + + + + +## Function `id_to_bytes` + +Get the raw bytes of a ID + + +
    public fun id_to_bytes(id: &object::ID): vector<u8>
    +
    + + + +
    +Implementation + + +
    public fun id_to_bytes(id: &ID): vector<u8> {
    +    bcs::to_bytes(&id.bytes)
    +}
    +
    + + + +
    + + + +## Function `id_to_address` + +Get the inner bytes of id as an address. + + +
    public fun id_to_address(id: &object::ID): address
    +
    + + + +
    +Implementation + + +
    public fun id_to_address(id: &ID): address {
    +    id.bytes
    +}
    +
    + + + +
    + + + +## Function `id_from_bytes` + +Make an ID from raw bytes. + + +
    public fun id_from_bytes(bytes: vector<u8>): object::ID
    +
    + + + +
    +Implementation + + +
    public fun id_from_bytes(bytes: vector<u8>): ID {
    +    address::from_bytes(bytes).to_id()
    +}
    +
    + + + +
    + + + +## Function `id_from_address` + +Make an ID from an address. + + +
    public fun id_from_address(bytes: address): object::ID
    +
    + + + +
    +Implementation + + +
    public fun id_from_address(bytes: address): ID {
    +    ID { bytes }
    +}
    +
    + + + +
    + + + +## Function `iota_system_state` + +Create the UID for the singleton IotaSystemState object. +This should only be called once from iota_system. + + +
    fun iota_system_state(ctx: &tx_context::TxContext): object::UID
    +
    + + + +
    +Implementation + + +
    fun iota_system_state(ctx: &TxContext): UID {
    +    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    +    UID {
    +        id: ID { bytes: IOTA_SYSTEM_STATE_OBJECT_ID },
    +    }
    +}
    +
    + + + +
    + + + +## Function `clock` + +Create the UID for the singleton Clock object. +This should only be called once from clock. + + +
    public(friend) fun clock(): object::UID
    +
    + + + +
    +Implementation + + +
    public(package) fun clock(): UID {
    +    UID {
    +        id: ID { bytes: IOTA_CLOCK_OBJECT_ID }
    +    }
    +}
    +
    + + + +
    + + + +## Function `authenticator_state` + +Create the UID for the singleton AuthenticatorState object. +This should only be called once from authenticator_state. + + +
    public(friend) fun authenticator_state(): object::UID
    +
    + + + +
    +Implementation + + +
    public(package) fun authenticator_state(): UID {
    +    UID {
    +        id: ID { bytes: IOTA_AUTHENTICATOR_STATE_ID }
    +    }
    +}
    +
    + + + +
    + + + +## Function `randomness_state` + +Create the UID for the singleton Random object. +This should only be called once from random. + + +
    public(friend) fun randomness_state(): object::UID
    +
    + + + +
    +Implementation + + +
    public(package) fun randomness_state(): UID {
    +    UID {
    +        id: ID { bytes: IOTA_RANDOM_ID }
    +    }
    +}
    +
    + + + +
    + + + +## Function `iota_deny_list_object_id` + +Create the UID for the singleton DenyList object. +This should only be called once from deny_list. + + +
    public(friend) fun iota_deny_list_object_id(): object::UID
    +
    + + + +
    +Implementation + + +
    public(package) fun iota_deny_list_object_id(): UID {
    +    UID {
    +        id: ID { bytes: IOTA_DENY_LIST_OBJECT_ID }
    +    }
    +}
    +
    + + + +
    + + + +## Function `uid_as_inner` + +Get the inner ID of uid + + +
    public fun uid_as_inner(uid: &object::UID): &object::ID
    +
    + + + +
    +Implementation + + +
    public fun uid_as_inner(uid: &UID): &ID {
    +    &uid.id
    +}
    +
    + + + +
    + + + +## Function `uid_to_inner` + +Get the raw bytes of a uid's inner ID + + +
    public fun uid_to_inner(uid: &object::UID): object::ID
    +
    + + + +
    +Implementation + + +
    public fun uid_to_inner(uid: &UID): ID {
    +    uid.id
    +}
    +
    + + + +
    + + + +## Function `uid_to_bytes` + +Get the raw bytes of a UID + + +
    public fun uid_to_bytes(uid: &object::UID): vector<u8>
    +
    + + + +
    +Implementation + + +
    public fun uid_to_bytes(uid: &UID): vector<u8> {
    +    bcs::to_bytes(&uid.id.bytes)
    +}
    +
    + + + +
    + + + +## Function `uid_to_address` + +Get the inner bytes of id as an address. + + +
    public fun uid_to_address(uid: &object::UID): address
    +
    + + + +
    +Implementation + + +
    public fun uid_to_address(uid: &UID): address {
    +    uid.id.bytes
    +}
    +
    + + + +
    + + + +## Function `new` + +Create a new object. Returns the UID that must be stored in a Iota object. +This is the only way to create UIDs. + + +
    public fun new(ctx: &mut tx_context::TxContext): object::UID
    +
    + + + +
    +Implementation + + +
    public fun new(ctx: &mut TxContext): UID {
    +    UID {
    +        id: ID { bytes: ctx.fresh_object_address() },
    +    }
    +}
    +
    + + + +
    + + + +## Function `delete` + +Delete the object and it's UID. This is the only way to eliminate a UID. + + +
    public fun delete(id: object::UID)
    +
    + + + +
    +Implementation + + +
    public fun delete(id: UID) {
    +    let UID { id: ID { bytes } } = id;
    +    delete_impl(bytes)
    +}
    +
    + + + +
    + + + +## Function `id` + +Get the underlying ID of obj + + +
    public fun id<T: key>(obj: &T): object::ID
    +
    + + + +
    +Implementation + + +
    public fun id<T: key>(obj: &T): ID {
    +    borrow_uid(obj).id
    +}
    +
    + + + +
    + + + +## Function `borrow_id` + +Borrow the underlying ID of obj + + +
    public fun borrow_id<T: key>(obj: &T): &object::ID
    +
    + + + +
    +Implementation + + +
    public fun borrow_id<T: key>(obj: &T): &ID {
    +    &borrow_uid(obj).id
    +}
    +
    + + + +
    + + + +## Function `id_bytes` + +Get the raw bytes for the underlying ID of obj + + +
    public fun id_bytes<T: key>(obj: &T): vector<u8>
    +
    + + + +
    +Implementation + + +
    public fun id_bytes<T: key>(obj: &T): vector<u8> {
    +    bcs::to_bytes(&borrow_uid(obj).id)
    +}
    +
    + + + +
    + + + +## Function `id_address` + +Get the inner bytes for the underlying ID of obj + + +
    public fun id_address<T: key>(obj: &T): address
    +
    + + + +
    +Implementation + + +
    public fun id_address<T: key>(obj: &T): address {
    +    borrow_uid(obj).id.bytes
    +}
    +
    + + + +
    + + + +## Function `borrow_uid` + +Get the UID for obj. +Safe because Iota has an extra bytecode verifier pass that forces every struct with +the key ability to have a distinguished UID field. +Cannot be made public as the access to UID for a given object must be privileged, and +restrictable in the object's module. + + +
    fun borrow_uid<T: key>(obj: &T): &object::UID
    +
    + + + +
    +Implementation + + +
    native fun borrow_uid<T: key>(obj: &T): &UID;
    +
    + + + +
    + + + +## Function `new_uid_from_hash` + +Generate a new UID specifically used for creating a UID from a hash + + +
    public(friend) fun new_uid_from_hash(bytes: address): object::UID
    +
    + + + +
    +Implementation + + +
    public(package) fun new_uid_from_hash(bytes: address): UID {
    +    record_new_uid(bytes);
    +    UID { id: ID { bytes } }
    +}
    +
    + + + +
    + + + +## Function `delete_impl` + + + +
    fun delete_impl(id: address)
    +
    + + + +
    +Implementation + + +
    native fun delete_impl(id: address);
    +
    + + + +
    + + + +## Function `record_new_uid` + + + +
    fun record_new_uid(id: address)
    +
    + + + +
    +Implementation + + +
    native fun record_new_uid(id: address);
    +
    + + + +
    diff --git a/crates/sui-framework/docs/sui-framework/object_bag.md b/crates/iota-framework/docs/iota-framework/object_bag.md similarity index 92% rename from crates/sui-framework/docs/sui-framework/object_bag.md rename to crates/iota-framework/docs/iota-framework/object_bag.md index cfe60c58c8f..7df5f22254f 100644 --- a/crates/sui-framework/docs/sui-framework/object_bag.md +++ b/crates/iota-framework/docs/iota-framework/object_bag.md @@ -2,8 +2,8 @@ title: Module `0x2::object_bag` --- -Similar to sui::bag, an ObjectBag is a heterogeneous map-like collection. But unlike -sui::bag, the values bound to these dynamic fields _must_ be objects themselves. This allows +Similar to iota::bag, an ObjectBag is a heterogeneous map-like collection. But unlike +iota::bag, the values bound to these dynamic fields _must_ be objects themselves. This allows for the objects to still exist in storage, which may be important for external tools. The difference is otherwise not observable from within Move. @@ -111,7 +111,7 @@ Creates a new, empty bag ## Function `add` Adds a key-value pair to the bag bag: &mut ObjectBag -Aborts with sui::dynamic_field::EFieldAlreadyExists if the bag already has an entry with +Aborts with iota::dynamic_field::EFieldAlreadyExists if the bag already has an entry with that key k: K. @@ -139,9 +139,9 @@ that key k: K. ## Function `borrow` Immutably borrows the value associated with the key in the bag bag: &ObjectBag. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the bag does not have an entry with +Aborts with iota::dynamic_field::EFieldDoesNotExist if the bag does not have an entry with that key k: K. -Aborts with sui::dynamic_field::EFieldTypeMismatch if the bag has an entry for the key, but +Aborts with iota::dynamic_field::EFieldTypeMismatch if the bag has an entry for the key, but the value does not have the specified type. @@ -168,9 +168,9 @@ the value does not have the specified type. ## Function `borrow_mut` Mutably borrows the value associated with the key in the bag bag: &mut ObjectBag. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the bag does not have an entry with +Aborts with iota::dynamic_field::EFieldDoesNotExist if the bag does not have an entry with that key k: K. -Aborts with sui::dynamic_field::EFieldTypeMismatch if the bag has an entry for the key, but +Aborts with iota::dynamic_field::EFieldTypeMismatch if the bag has an entry for the key, but the value does not have the specified type. @@ -197,9 +197,9 @@ the value does not have the specified type. ## Function `remove` Mutably borrows the key-value pair in the bag bag: &mut ObjectBag and returns the value. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the bag does not have an entry with +Aborts with iota::dynamic_field::EFieldDoesNotExist if the bag does not have an entry with that key k: K. -Aborts with sui::dynamic_field::EFieldTypeMismatch if the bag has an entry for the key, but +Aborts with iota::dynamic_field::EFieldTypeMismatch if the bag has an entry for the key, but the value does not have the specified type. diff --git a/crates/sui-framework/docs/sui-framework/object_table.md b/crates/iota-framework/docs/iota-framework/object_table.md similarity index 94% rename from crates/sui-framework/docs/sui-framework/object_table.md rename to crates/iota-framework/docs/iota-framework/object_table.md index 344e759fccc..4ecf5918b15 100644 --- a/crates/sui-framework/docs/sui-framework/object_table.md +++ b/crates/iota-framework/docs/iota-framework/object_table.md @@ -2,8 +2,8 @@ title: Module `0x2::object_table` --- -Similar to sui::table, an ObjectTable<K, V> is a map-like collection. But unlike -sui::table, the values bound to these dynamic fields _must_ be objects themselves. This allows +Similar to iota::table, an ObjectTable<K, V> is a map-like collection. But unlike +iota::table, the values bound to these dynamic fields _must_ be objects themselves. This allows for the objects to still exist within in storage, which may be important for external tools. The difference is otherwise not observable from within Move. @@ -110,7 +110,7 @@ Creates a new, empty table ## Function `add` Adds a key-value pair to the table table: &mut ObjectTable<K, V> -Aborts with sui::dynamic_field::EFieldAlreadyExists if the table already has an entry with +Aborts with iota::dynamic_field::EFieldAlreadyExists if the table already has an entry with that key k: K. @@ -138,7 +138,7 @@ that key k: K. ## Function `borrow` Immutable borrows the value associated with the key in the table table: &ObjectTable<K, V>. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the table does not have an entry with +Aborts with iota::dynamic_field::EFieldDoesNotExist if the table does not have an entry with that key k: K. @@ -165,7 +165,7 @@ that key k: K. ## Function `borrow_mut` Mutably borrows the value associated with the key in the table table: &mut ObjectTable<K, V>. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the table does not have an entry with +Aborts with iota::dynamic_field::EFieldDoesNotExist if the table does not have an entry with that key k: K. @@ -195,7 +195,7 @@ that key k: K. ## Function `remove` Removes the key-value pair in the table table: &mut ObjectTable<K, V> and returns the value. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the table does not have an entry with +Aborts with iota::dynamic_field::EFieldDoesNotExist if the table does not have an entry with that key k: K. diff --git a/crates/sui-framework/docs/sui-framework/package.md b/crates/iota-framework/docs/iota-framework/package.md similarity index 99% rename from crates/sui-framework/docs/sui-framework/package.md rename to crates/iota-framework/docs/iota-framework/package.md index a2eeed88461..ba15d25a3fe 100644 --- a/crates/sui-framework/docs/sui-framework/package.md +++ b/crates/iota-framework/docs/iota-framework/package.md @@ -148,7 +148,7 @@ depend against). An UpgradeCap can only issue one ticket at a time, to prevent races between concurrent updates or a change in its upgrade policy after -issuing a ticket, so the ticket is a "Hot Potato" to preserve forward +isiotang a ticket, so the ticket is a "Hot Potato" to preserve forward progress. @@ -373,7 +373,7 @@ the sender is the publisher.
    public fun claim_and_keep<OTW: drop>(otw: OTW, ctx: &mut TxContext) {
    -    sui::transfer::public_transfer(claim(otw, ctx), ctx.sender())
    +    iota::transfer::public_transfer(claim(otw, ctx), ctx.sender())
     }
     
    diff --git a/crates/iota-framework/docs/iota-framework/pay.md b/crates/iota-framework/docs/iota-framework/pay.md new file mode 100644 index 00000000000..1f6877a7722 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/pay.md @@ -0,0 +1,273 @@ +--- +title: Module `0x2::pay` +--- + +This module provides handy functionality for wallets and iota::Coin management. + + +- [Constants](#@Constants_0) +- [Function `keep`](#0x2_pay_keep) +- [Function `split`](#0x2_pay_split) +- [Function `split_vec`](#0x2_pay_split_vec) +- [Function `split_and_transfer`](#0x2_pay_split_and_transfer) +- [Function `divide_and_keep`](#0x2_pay_divide_and_keep) +- [Function `join`](#0x2_pay_join) +- [Function `join_vec`](#0x2_pay_join_vec) +- [Function `join_vec_and_transfer`](#0x2_pay_join_vec_and_transfer) + + +
    use 0x2::coin;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +
    + + + + + +## Constants + + + + +For when empty vector is supplied into join function. + + +
    const ENoCoins: u64 = 0;
    +
    + + + + + +## Function `keep` + +Transfer c to the sender of the current transaction + + +
    public fun keep<T>(c: coin::Coin<T>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public fun keep<T>(c: Coin<T>, ctx: &TxContext) {
    +    transfer::public_transfer(c, ctx.sender())
    +}
    +
    + + + +
    + + + +## Function `split` + +Split coin self to two coins, one with balance split_amount, +and the remaining balance is left is self. + + +
    public entry fun split<T>(coin: &mut coin::Coin<T>, split_amount: u64, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun split<T>(
    +    coin: &mut Coin<T>, split_amount: u64, ctx: &mut TxContext
    +) {
    +    keep(coin.split(split_amount, ctx), ctx)
    +}
    +
    + + + +
    + + + +## Function `split_vec` + +Split coin self into multiple coins, each with balance specified +in split_amounts. Remaining balance is left in self. + + +
    public entry fun split_vec<T>(self: &mut coin::Coin<T>, split_amounts: vector<u64>, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun split_vec<T>(
    +    self: &mut Coin<T>, split_amounts: vector<u64>, ctx: &mut TxContext
    +) {
    +    let (mut i, len) = (0, split_amounts.length());
    +    while (i < len) {
    +        split(self, split_amounts[i], ctx);
    +        i = i + 1;
    +    };
    +}
    +
    + + + +
    + + + +## Function `split_and_transfer` + +Send amount units of c to recipient +Aborts with EVALUE if amount is greater than or equal to amount + + +
    public entry fun split_and_transfer<T>(c: &mut coin::Coin<T>, amount: u64, recipient: address, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun split_and_transfer<T>(
    +    c: &mut Coin<T>, amount: u64, recipient: address, ctx: &mut TxContext
    +) {
    +    transfer::public_transfer(c.split(amount, ctx), recipient)
    +}
    +
    + + + +
    + + + +## Function `divide_and_keep` + +Divide coin self into n - 1 coins with equal balances. If the balance is +not evenly divisible by n, the remainder is left in self. + + +
    public entry fun divide_and_keep<T>(self: &mut coin::Coin<T>, n: u64, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun divide_and_keep<T>(
    +    self: &mut Coin<T>, n: u64, ctx: &mut TxContext
    +) {
    +    let mut vec: vector<Coin<T>> = self.divide_into_n(n, ctx);
    +    let (mut i, len) = (0, vec.length());
    +    while (i < len) {
    +        transfer::public_transfer(vec.pop_back(), ctx.sender());
    +        i = i + 1;
    +    };
    +    vec.destroy_empty();
    +}
    +
    + + + +
    + + + +## Function `join` + +Join coin into self. Re-exports coin::join function. +Deprecated: you should call coin.join(other) directly. + + +
    public entry fun join<T>(self: &mut coin::Coin<T>, coin: coin::Coin<T>)
    +
    + + + +
    +Implementation + + +
    public entry fun join<T>(self: &mut Coin<T>, coin: Coin<T>) {
    +    self.join(coin)
    +}
    +
    + + + +
    + + + +## Function `join_vec` + +Join everything in coins with self + + +
    public entry fun join_vec<T>(self: &mut coin::Coin<T>, coins: vector<coin::Coin<T>>)
    +
    + + + +
    +Implementation + + +
    public entry fun join_vec<T>(self: &mut Coin<T>, mut coins: vector<Coin<T>>) {
    +    let (mut i, len) = (0, coins.length());
    +    while (i < len) {
    +        let coin = coins.pop_back();
    +        self.join(coin);
    +        i = i + 1
    +    };
    +    // safe because we've drained the vector
    +    coins.destroy_empty()
    +}
    +
    + + + +
    + + + +## Function `join_vec_and_transfer` + +Join a vector of Coin into a single object and transfer it to receiver. + + +
    public entry fun join_vec_and_transfer<T>(coins: vector<coin::Coin<T>>, receiver: address)
    +
    + + + +
    +Implementation + + +
    public entry fun join_vec_and_transfer<T>(mut coins: vector<Coin<T>>, receiver: address) {
    +    assert!(coins.length() > 0, ENoCoins);
    +
    +    let mut self = coins.pop_back();
    +    join_vec(&mut self, coins);
    +    transfer::public_transfer(self, receiver)
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/sui-framework/poseidon.md b/crates/iota-framework/docs/iota-framework/poseidon.md similarity index 100% rename from crates/sui-framework/docs/sui-framework/poseidon.md rename to crates/iota-framework/docs/iota-framework/poseidon.md diff --git a/crates/iota-framework/docs/iota-framework/priority_queue.md b/crates/iota-framework/docs/iota-framework/priority_queue.md new file mode 100644 index 00000000000..bf17c850827 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/priority_queue.md @@ -0,0 +1,368 @@ +--- +title: Module `0x2::priority_queue` +--- + +Priority queue implemented using a max heap. + + +- [Struct `PriorityQueue`](#0x2_priority_queue_PriorityQueue) +- [Struct `Entry`](#0x2_priority_queue_Entry) +- [Constants](#@Constants_0) +- [Function `new`](#0x2_priority_queue_new) +- [Function `pop_max`](#0x2_priority_queue_pop_max) +- [Function `insert`](#0x2_priority_queue_insert) +- [Function `new_entry`](#0x2_priority_queue_new_entry) +- [Function `create_entries`](#0x2_priority_queue_create_entries) +- [Function `restore_heap_recursive`](#0x2_priority_queue_restore_heap_recursive) +- [Function `max_heapify_recursive`](#0x2_priority_queue_max_heapify_recursive) +- [Function `priorities`](#0x2_priority_queue_priorities) + + +
    use 0x1::vector;
    +
    + + + + + +## Struct `PriorityQueue` + +Struct representing a priority queue. The entries vector represents a max +heap structure, where entries[0] is the root, entries[1] and entries[2] are the +left child and right child of the root, etc. More generally, the children of +entries[i] are at at i * 2 + 1 and i * 2 + 2. The max heap should have the invariant +that the parent node's priority is always higher than its child nodes' priorities. + + +
    struct PriorityQueue<T: drop> has drop, store
    +
    + + + +
    +Fields + + +
    +
    +entries: vector<priority_queue::Entry<T>> +
    +
    + +
    +
    + + +
    + + + +## Struct `Entry` + + + +
    struct Entry<T: drop> has drop, store
    +
    + + + +
    +Fields + + +
    +
    +priority: u64 +
    +
    + +
    +
    +value: T +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + +For when heap is empty and there's no data to pop. + + +
    const EPopFromEmptyHeap: u64 = 0;
    +
    + + + + + +## Function `new` + +Create a new priority queue from the input entry vectors. + + +
    public fun new<T: drop>(entries: vector<priority_queue::Entry<T>>): priority_queue::PriorityQueue<T>
    +
    + + + +
    +Implementation + + +
    public fun new<T: drop>(mut entries: vector<Entry<T>>) : PriorityQueue<T> {
    +    let len = entries.length();
    +    let mut i = len / 2;
    +    // Max heapify from the first node that is a parent (node at len / 2).
    +    while (i > 0) {
    +        i = i - 1;
    +        max_heapify_recursive(&mut entries, len, i);
    +    };
    +    PriorityQueue { entries }
    +}
    +
    + + + +
    + + + +## Function `pop_max` + +Pop the entry with the highest priority value. + + +
    public fun pop_max<T: drop>(pq: &mut priority_queue::PriorityQueue<T>): (u64, T)
    +
    + + + +
    +Implementation + + +
    public fun pop_max<T: drop>(pq: &mut PriorityQueue<T>) : (u64, T) {
    +    let len = pq.entries.length();
    +    assert!(len > 0, EPopFromEmptyHeap);
    +    // Swap the max element with the last element in the entries and remove the max element.
    +    let Entry { priority, value } = pq.entries.swap_remove(0);
    +    // Now the max heap property has been violated at the root node, but nowhere else
    +    // so we call max heapify on the root node.
    +    max_heapify_recursive(&mut pq.entries, len - 1, 0);
    +    (priority, value)
    +}
    +
    + + + +
    + + + +## Function `insert` + +Insert a new entry into the queue. + + +
    public fun insert<T: drop>(pq: &mut priority_queue::PriorityQueue<T>, priority: u64, value: T)
    +
    + + + +
    +Implementation + + +
    public fun insert<T: drop>(pq: &mut PriorityQueue<T>, priority: u64, value: T) {
    +    pq.entries.push_back(Entry { priority, value});
    +    let index = pq.entries.length() - 1;
    +    restore_heap_recursive(&mut pq.entries, index);
    +}
    +
    + + + +
    + + + +## Function `new_entry` + + + +
    public fun new_entry<T: drop>(priority: u64, value: T): priority_queue::Entry<T>
    +
    + + + +
    +Implementation + + +
    public fun new_entry<T: drop>(priority: u64, value: T): Entry<T> {
    +    Entry { priority, value }
    +}
    +
    + + + +
    + + + +## Function `create_entries` + + + +
    public fun create_entries<T: drop>(p: vector<u64>, v: vector<T>): vector<priority_queue::Entry<T>>
    +
    + + + +
    +Implementation + + +
    public fun create_entries<T: drop>(mut p: vector<u64>, mut v: vector<T>): vector<Entry<T>> {
    +    let len = p.length();
    +    assert!(v.length() == len, 0);
    +    let mut res = vector[];
    +    let mut i = 0;
    +    while (i < len) {
    +        let priority = p.remove(0);
    +        let value = v.remove(0);
    +        res.push_back(Entry { priority, value });
    +        i = i + 1;
    +    };
    +    res
    +}
    +
    + + + +
    + + + +## Function `restore_heap_recursive` + + + +
    fun restore_heap_recursive<T: drop>(v: &mut vector<priority_queue::Entry<T>>, i: u64)
    +
    + + + +
    +Implementation + + +
    fun restore_heap_recursive<T: drop>(v: &mut vector<Entry<T>>, i: u64) {
    +    if (i == 0) {
    +        return
    +    };
    +    let parent = (i - 1) / 2;
    +
    +    // If new elem is greater than its parent, swap them and recursively
    +    // do the restoration upwards.
    +    if (*&v[i].priority > *&v[parent].priority) {
    +        v.swap(i, parent);
    +        restore_heap_recursive(v, parent);
    +    }
    +}
    +
    + + + +
    + + + +## Function `max_heapify_recursive` + +Max heapify the subtree whose root is at index i. That means after this function +finishes, the subtree should have the property that the parent node has higher priority +than both child nodes. +This function assumes that all the other nodes in the subtree (nodes other than the root) +do satisfy the max heap property. + + +
    fun max_heapify_recursive<T: drop>(v: &mut vector<priority_queue::Entry<T>>, len: u64, i: u64)
    +
    + + + +
    +Implementation + + +
    fun max_heapify_recursive<T: drop>(v: &mut vector<Entry<T>>, len: u64, i: u64) {
    +    if (len == 0) {
    +        return
    +    };
    +    assert!(i < len, 1);
    +    let left = i * 2 + 1;
    +    let right = left + 1;
    +    let mut max = i;
    +    // Find the node with highest priority among node `i` and its two children.
    +    if (left < len && *&v[left].priority > *&v[max].priority) {
    +        max = left;
    +    };
    +    if (right < len && *&v[right].priority > *&v[max].priority) {
    +        max = right;
    +    };
    +    // If the parent node (node `i`) doesn't have the highest priority, we swap the parent with the
    +    // max priority node.
    +    if (max != i) {
    +        v.swap(max, i);
    +        // After the swap, we have restored the property at node `i` but now the max heap property
    +        // may be violated at node `max` since this node now has a new value. So we need to now
    +        // max heapify the subtree rooted at node `max`.
    +        max_heapify_recursive(v, len, max);
    +    }
    +}
    +
    + + + +
    + + + +## Function `priorities` + + + +
    public fun priorities<T: drop>(pq: &priority_queue::PriorityQueue<T>): vector<u64>
    +
    + + + +
    +Implementation + + +
    public fun priorities<T: drop>(pq: &PriorityQueue<T>): vector<u64> {
    +    let mut res = vector[];
    +    let mut i = 0;
    +    while (i < pq.entries.length()) {
    +        res.push_back(pq.entries[i].priority);
    +        i = i +1;
    +    };
    +    res
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/sui-framework/prover.md b/crates/iota-framework/docs/iota-framework/prover.md similarity index 100% rename from crates/sui-framework/docs/sui-framework/prover.md rename to crates/iota-framework/docs/iota-framework/prover.md diff --git a/crates/iota-framework/docs/iota-framework/random.md b/crates/iota-framework/docs/iota-framework/random.md new file mode 100644 index 00000000000..38eb3411a2d --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/random.md @@ -0,0 +1,927 @@ +--- +title: Module `0x2::random` +--- + +This module provides functionality for generating secure randomness. + + +- [Resource `Random`](#0x2_random_Random) +- [Struct `RandomInner`](#0x2_random_RandomInner) +- [Struct `RandomGenerator`](#0x2_random_RandomGenerator) +- [Constants](#@Constants_0) +- [Function `create`](#0x2_random_create) +- [Function `load_inner_mut`](#0x2_random_load_inner_mut) +- [Function `load_inner`](#0x2_random_load_inner) +- [Function `update_randomness_state`](#0x2_random_update_randomness_state) +- [Function `new_generator`](#0x2_random_new_generator) +- [Function `derive_next_block`](#0x2_random_derive_next_block) +- [Function `fill_buffer`](#0x2_random_fill_buffer) +- [Function `generate_bytes`](#0x2_random_generate_bytes) +- [Function `u256_from_bytes`](#0x2_random_u256_from_bytes) +- [Function `generate_u256`](#0x2_random_generate_u256) +- [Function `generate_u128`](#0x2_random_generate_u128) +- [Function `generate_u64`](#0x2_random_generate_u64) +- [Function `generate_u32`](#0x2_random_generate_u32) +- [Function `generate_u16`](#0x2_random_generate_u16) +- [Function `generate_u8`](#0x2_random_generate_u8) +- [Function `generate_bool`](#0x2_random_generate_bool) +- [Function `u128_in_range`](#0x2_random_u128_in_range) +- [Function `generate_u128_in_range`](#0x2_random_generate_u128_in_range) +- [Function `generate_u64_in_range`](#0x2_random_generate_u64_in_range) +- [Function `generate_u32_in_range`](#0x2_random_generate_u32_in_range) +- [Function `generate_u16_in_range`](#0x2_random_generate_u16_in_range) +- [Function `generate_u8_in_range`](#0x2_random_generate_u8_in_range) +- [Function `shuffle`](#0x2_random_shuffle) + + +
    use 0x1::bcs;
    +use 0x1::vector;
    +use 0x2::address;
    +use 0x2::hmac;
    +use 0x2::object;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +use 0x2::versioned;
    +
    + + + + + +## Resource `Random` + +Singleton shared object which stores the global randomness state. +The actual state is stored in a versioned inner field. + + +
    struct Random has key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +inner: versioned::Versioned +
    +
    + +
    +
    + + +
    + + + +## Struct `RandomInner` + + + +
    struct RandomInner has store
    +
    + + + +
    +Fields + + +
    +
    +version: u64 +
    +
    + +
    +
    +epoch: u64 +
    +
    + +
    +
    +randomness_round: u64 +
    +
    + +
    +
    +random_bytes: vector<u8> +
    +
    + +
    +
    + + +
    + + + +## Struct `RandomGenerator` + +Unique randomness generator, derived from the global randomness. + + +
    struct RandomGenerator has drop
    +
    + + + +
    +Fields + + +
    +
    +seed: vector<u8> +
    +
    + +
    +
    +counter: u16 +
    +
    + +
    +
    +buffer: vector<u8> +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + + + +
    const ENotSystemAddress: u64 = 0;
    +
    + + + + + + + +
    const EWrongInnerVersion: u64 = 1;
    +
    + + + + + + + +
    const CURRENT_VERSION: u64 = 1;
    +
    + + + + + + + +
    const EInvalidLength: u64 = 4;
    +
    + + + + + + + +
    const EInvalidRandomnessUpdate: u64 = 2;
    +
    + + + + + + + +
    const EInvalidRange: u64 = 3;
    +
    + + + + + + + +
    const RAND_OUTPUT_LEN: u16 = 32;
    +
    + + + + + + + +
    const U16_MAX: u64 = 65535;
    +
    + + + + + +## Function `create` + +Create and share the Random object. This function is called exactly once, when +the Random object is first created. +Can only be called by genesis or change_epoch transactions. + + +
    fun create(ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    fun create(ctx: &mut TxContext) {
    +    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    +
    +    let version = CURRENT_VERSION;
    +
    +    let inner = RandomInner {
    +        version,
    +        epoch: ctx.epoch(),
    +        randomness_round: 0,
    +        random_bytes: vector[],
    +    };
    +
    +    let self = Random {
    +        id: object::randomness_state(),
    +        inner: versioned::create(version, inner, ctx),
    +    };
    +    transfer::share_object(self);
    +}
    +
    + + + +
    + + + +## Function `load_inner_mut` + + + +
    fun load_inner_mut(self: &mut random::Random): &mut random::RandomInner
    +
    + + + +
    +Implementation + + +
    fun load_inner_mut(
    +    self: &mut Random,
    +): &mut RandomInner {
    +    let version = versioned::version(&self.inner);
    +
    +    // Replace this with a lazy update function when we add a new version of the inner object.
    +    assert!(version == CURRENT_VERSION, EWrongInnerVersion);
    +    let inner: &mut RandomInner = versioned::load_value_mut(&mut self.inner);
    +    assert!(inner.version == version, EWrongInnerVersion);
    +    inner
    +}
    +
    + + + +
    + + + +## Function `load_inner` + + + +
    fun load_inner(self: &random::Random): &random::RandomInner
    +
    + + + +
    +Implementation + + +
    fun load_inner(
    +    self: &Random,
    +): &RandomInner {
    +    let version = versioned::version(&self.inner);
    +
    +    // Replace this with a lazy update function when we add a new version of the inner object.
    +    assert!(version == CURRENT_VERSION, EWrongInnerVersion);
    +    let inner: &RandomInner = versioned::load_value(&self.inner);
    +    assert!(inner.version == version, EWrongInnerVersion);
    +    inner
    +}
    +
    + + + +
    + + + +## Function `update_randomness_state` + +Record new randomness. Called when executing the RandomnessStateUpdate system +transaction. + + +
    fun update_randomness_state(self: &mut random::Random, new_round: u64, new_bytes: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    fun update_randomness_state(
    +    self: &mut Random,
    +    new_round: u64,
    +    new_bytes: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    // Validator will make a special system call with sender set as 0x0.
    +    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    +
    +    // Randomness should only be incremented.
    +    let epoch = ctx.epoch();
    +    let inner = self.load_inner_mut();
    +    if (inner.randomness_round == 0 && inner.epoch == 0 && inner.random_bytes.is_empty()) {
    +        // First update should be for round zero.
    +        assert!(new_round == 0, EInvalidRandomnessUpdate);
    +    } else {
    +        // Subsequent updates should either increase epoch or increment randomness_round.
    +        // Note that epoch may increase by more than 1 if an epoch is completed without
    +        // randomness ever being generated in that epoch.
    +        assert!(
    +            (epoch > inner.epoch && new_round == 0) ||
    +                (new_round == inner.randomness_round + 1),
    +            EInvalidRandomnessUpdate
    +        );
    +    };
    +
    +    inner.epoch = ctx.epoch();
    +    inner.randomness_round = new_round;
    +    inner.random_bytes = new_bytes;
    +}
    +
    + + + +
    + + + +## Function `new_generator` + +Create a generator. Can be used to derive up to MAX_U16 * 32 random bytes. + + +
    public fun new_generator(r: &random::Random, ctx: &mut tx_context::TxContext): random::RandomGenerator
    +
    + + + +
    +Implementation + + +
    public fun new_generator(r: &Random, ctx: &mut TxContext): RandomGenerator {
    +    let inner = load_inner(r);
    +    let seed = hmac_sha3_256(
    +        &inner.random_bytes,
    +        &ctx.fresh_object_address().to_bytes()
    +    );
    +    RandomGenerator { seed, counter: 0, buffer: vector[] }
    +}
    +
    + + + +
    + + + +## Function `derive_next_block` + + + +
    fun derive_next_block(g: &mut random::RandomGenerator): vector<u8>
    +
    + + + +
    +Implementation + + +
    fun derive_next_block(g: &mut RandomGenerator): vector<u8> {
    +    g.counter = g.counter + 1;
    +    hmac_sha3_256(&g.seed, &bcs::to_bytes(&g.counter))
    +}
    +
    + + + +
    + + + +## Function `fill_buffer` + + + +
    fun fill_buffer(g: &mut random::RandomGenerator)
    +
    + + + +
    +Implementation + + +
    fun fill_buffer(g: &mut RandomGenerator) {
    +    let next_block = derive_next_block(g);
    +    vector::append(&mut g.buffer, next_block);
    +}
    +
    + + + +
    + + + +## Function `generate_bytes` + +Generate n random bytes. + + +
    public fun generate_bytes(g: &mut random::RandomGenerator, num_of_bytes: u16): vector<u8>
    +
    + + + +
    +Implementation + + +
    public fun generate_bytes(g: &mut RandomGenerator, num_of_bytes: u16): vector<u8> {
    +    let mut result = vector[];
    +    // Append RAND_OUTPUT_LEN size buffers directly without going through the generator's buffer.
    +    let mut num_of_blocks = num_of_bytes / RAND_OUTPUT_LEN;
    +    while (num_of_blocks > 0) {
    +        vector::append(&mut result, derive_next_block(g));
    +        num_of_blocks = num_of_blocks - 1;
    +    };
    +    // Fill the generator's buffer if needed.
    +    let num_of_bytes = num_of_bytes as u64;
    +    if (vector::length(&g.buffer) < (num_of_bytes - vector::length(&result))) {
    +        fill_buffer(g);
    +    };
    +    // Take remaining bytes from the generator's buffer.
    +    while (vector::length(&result) < num_of_bytes) {
    +        vector::push_back(&mut result, vector::pop_back(&mut g.buffer));
    +    };
    +    result
    +}
    +
    + + + +
    + + + +## Function `u256_from_bytes` + + + +
    fun u256_from_bytes(g: &mut random::RandomGenerator, num_of_bytes: u8): u256
    +
    + + + +
    +Implementation + + +
    fun u256_from_bytes(g: &mut RandomGenerator, num_of_bytes: u8): u256 {
    +    if (vector::length(&g.buffer) < num_of_bytes as u64) {
    +        fill_buffer(g);
    +    };
    +    let mut result: u256 = 0;
    +    let mut i = 0;
    +    while (i < num_of_bytes) {
    +        let byte = vector::pop_back(&mut g.buffer);
    +        result = (result << 8) + (byte as u256);
    +        i = i + 1;
    +    };
    +    result
    +}
    +
    + + + +
    + + + +## Function `generate_u256` + +Generate a u256. + + +
    public fun generate_u256(g: &mut random::RandomGenerator): u256
    +
    + + + +
    +Implementation + + +
    public fun generate_u256(g: &mut RandomGenerator): u256 {
    +    u256_from_bytes(g, 32)
    +}
    +
    + + + +
    + + + +## Function `generate_u128` + +Generate a u128. + + +
    public fun generate_u128(g: &mut random::RandomGenerator): u128
    +
    + + + +
    +Implementation + + +
    public fun generate_u128(g: &mut RandomGenerator): u128 {
    +    u256_from_bytes(g, 16) as u128
    +}
    +
    + + + +
    + + + +## Function `generate_u64` + +Generate a u64. + + +
    public fun generate_u64(g: &mut random::RandomGenerator): u64
    +
    + + + +
    +Implementation + + +
    public fun generate_u64(g: &mut RandomGenerator): u64 {
    +    u256_from_bytes(g, 8) as u64
    +}
    +
    + + + +
    + + + +## Function `generate_u32` + +Generate a u32. + + +
    public fun generate_u32(g: &mut random::RandomGenerator): u32
    +
    + + + +
    +Implementation + + +
    public fun generate_u32(g: &mut RandomGenerator): u32 {
    +    u256_from_bytes(g, 4) as u32
    +}
    +
    + + + +
    + + + +## Function `generate_u16` + +Generate a u16. + + +
    public fun generate_u16(g: &mut random::RandomGenerator): u16
    +
    + + + +
    +Implementation + + +
    public fun generate_u16(g: &mut RandomGenerator): u16 {
    +    u256_from_bytes(g, 2) as u16
    +}
    +
    + + + +
    + + + +## Function `generate_u8` + +Generate a u8. + + +
    public fun generate_u8(g: &mut random::RandomGenerator): u8
    +
    + + + +
    +Implementation + + +
    public fun generate_u8(g: &mut RandomGenerator): u8 {
    +    u256_from_bytes(g, 1) as u8
    +}
    +
    + + + +
    + + + +## Function `generate_bool` + +Generate a boolean. + + +
    public fun generate_bool(g: &mut random::RandomGenerator): bool
    +
    + + + +
    +Implementation + + +
    public fun generate_bool(g: &mut RandomGenerator): bool {
    +    (u256_from_bytes(g, 1) & 1) == 1
    +}
    +
    + + + +
    + + + +## Function `u128_in_range` + + + +
    fun u128_in_range(g: &mut random::RandomGenerator, min: u128, max: u128, num_of_bytes: u8): u128
    +
    + + + +
    +Implementation + + +
    fun u128_in_range(g: &mut RandomGenerator, min: u128, max: u128, num_of_bytes: u8): u128 {
    +    assert!(min <= max, EInvalidRange);
    +    if (min == max) {
    +        return min
    +    };
    +    // Pick a random number in [0, max - min] by generating a random number that is larger than max-min, and taking
    +    // the modulo of the random number by the range size. Then add the min to the result to get a number in
    +    // [min, max].
    +    let range_size = (max - min) as u256 + 1;
    +    let rand = u256_from_bytes(g, num_of_bytes);
    +    min + (rand % range_size as u128)
    +}
    +
    + + + +
    + + + +## Function `generate_u128_in_range` + +Generate a random u128 in [min, max] (with a bias of 2^{-64}). + + +
    public fun generate_u128_in_range(g: &mut random::RandomGenerator, min: u128, max: u128): u128
    +
    + + + +
    +Implementation + + +
    public fun generate_u128_in_range(g: &mut RandomGenerator, min: u128, max: u128): u128 {
    +    u128_in_range(g, min, max, 24)
    +}
    +
    + + + +
    + + + +## Function `generate_u64_in_range` + + + +
    public fun generate_u64_in_range(g: &mut random::RandomGenerator, min: u64, max: u64): u64
    +
    + + + +
    +Implementation + + +
    public fun generate_u64_in_range(g: &mut RandomGenerator, min: u64, max: u64): u64 {
    +    u128_in_range(g, min as u128, max as u128, 16) as u64
    +}
    +
    + + + +
    + + + +## Function `generate_u32_in_range` + +Generate a random u32 in [min, max] (with a bias of 2^{-64}). + + +
    public fun generate_u32_in_range(g: &mut random::RandomGenerator, min: u32, max: u32): u32
    +
    + + + +
    +Implementation + + +
    public fun generate_u32_in_range(g: &mut RandomGenerator, min: u32, max: u32): u32 {
    +    u128_in_range(g, min as u128, max as u128, 12) as u32
    +}
    +
    + + + +
    + + + +## Function `generate_u16_in_range` + +Generate a random u16 in [min, max] (with a bias of 2^{-64}). + + +
    public fun generate_u16_in_range(g: &mut random::RandomGenerator, min: u16, max: u16): u16
    +
    + + + +
    +Implementation + + +
    public fun generate_u16_in_range(g: &mut RandomGenerator, min: u16, max: u16): u16 {
    +    u128_in_range(g, min as u128, max as u128, 10) as u16
    +}
    +
    + + + +
    + + + +## Function `generate_u8_in_range` + +Generate a random u8 in [min, max] (with a bias of 2^{-64}). + + +
    public fun generate_u8_in_range(g: &mut random::RandomGenerator, min: u8, max: u8): u8
    +
    + + + +
    +Implementation + + +
    public fun generate_u8_in_range(g: &mut RandomGenerator, min: u8, max: u8): u8 {
    +    u128_in_range(g, min as u128, max as u128, 9) as u8
    +}
    +
    + + + +
    + + + +## Function `shuffle` + +Shuffle a vector using the random generator (Fisher–Yates/Knuth shuffle). + + +
    public fun shuffle<T>(g: &mut random::RandomGenerator, v: &mut vector<T>)
    +
    + + + +
    +Implementation + + +
    public fun shuffle<T>(g: &mut RandomGenerator, v: &mut vector<T>) {
    +    let n = vector::length(v);
    +    if (n == 0) {
    +        return
    +    };
    +    assert!(n <= U16_MAX, EInvalidLength);
    +    let n = n as u16;
    +    let mut i: u16 = 0;
    +    let end = n - 1;
    +    while (i < end) {
    +        let j = generate_u16_in_range(g, i, end);
    +        vector::swap(v, i as u64, j as u64);
    +        i = i + 1;
    +    };
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-framework/table.md b/crates/iota-framework/docs/iota-framework/table.md new file mode 100644 index 00000000000..5c4d1cad1cf --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/table.md @@ -0,0 +1,357 @@ +--- +title: Module `0x2::table` +--- + +A table is a map-like collection. But unlike a traditional collection, it's keys and values are +not stored within the Table value, but instead are stored using Iota's object system. The +Table struct acts only as a handle into the object system to retrieve those keys and values. +Note that this means that Table values with exactly the same key-value mapping will not be +equal, with ==, at runtime. For example +``` +let table1 = table::new(); +let table2 = table::new(); +table::add(&mut table1, 0, false); +table::add(&mut table1, 1, true); +table::add(&mut table2, 0, false); +table::add(&mut table2, 1, true); +// table1 does not equal table2, despite having the same entries +assert!(&table1 != &table2, 0); +``` + + +- [Resource `Table`](#0x2_table_Table) +- [Constants](#@Constants_0) +- [Function `new`](#0x2_table_new) +- [Function `add`](#0x2_table_add) +- [Function `borrow`](#0x2_table_borrow) +- [Function `borrow_mut`](#0x2_table_borrow_mut) +- [Function `remove`](#0x2_table_remove) +- [Function `contains`](#0x2_table_contains) +- [Function `length`](#0x2_table_length) +- [Function `is_empty`](#0x2_table_is_empty) +- [Function `destroy_empty`](#0x2_table_destroy_empty) +- [Function `drop`](#0x2_table_drop) + + +
    use 0x2::dynamic_field;
    +use 0x2::object;
    +use 0x2::tx_context;
    +
    + + + + + +## Resource `Table` + + + +
    struct Table<K: copy, drop, store, V: store> has store, key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + the ID of this table +
    +
    +size: u64 +
    +
    + the number of key-value pairs in the table +
    +
    + + +
    + + + +## Constants + + + + + + +
    const ETableNotEmpty: u64 = 0;
    +
    + + + + + +## Function `new` + +Creates a new, empty table + + +
    public fun new<K: copy, drop, store, V: store>(ctx: &mut tx_context::TxContext): table::Table<K, V>
    +
    + + + +
    +Implementation + + +
    public fun new<K: copy + drop + store, V: store>(ctx: &mut TxContext): Table<K, V> {
    +    Table {
    +        id: object::new(ctx),
    +        size: 0,
    +    }
    +}
    +
    + + + +
    + + + +## Function `add` + +Adds a key-value pair to the table table: &mut Table<K, V> +Aborts with iota::dynamic_field::EFieldAlreadyExists if the table already has an entry with +that key k: K. + + +
    public fun add<K: copy, drop, store, V: store>(table: &mut table::Table<K, V>, k: K, v: V)
    +
    + + + +
    +Implementation + + +
    public fun add<K: copy + drop + store, V: store>(table: &mut Table<K, V>, k: K, v: V) {
    +    field::add(&mut table.id, k, v);
    +    table.size = table.size + 1;
    +}
    +
    + + + +
    + + + +## Function `borrow` + +Immutable borrows the value associated with the key in the table table: &Table<K, V>. +Aborts with iota::dynamic_field::EFieldDoesNotExist if the table does not have an entry with +that key k: K. + + +
    public fun borrow<K: copy, drop, store, V: store>(table: &table::Table<K, V>, k: K): &V
    +
    + + + +
    +Implementation + + +
    public fun borrow<K: copy + drop + store, V: store>(table: &Table<K, V>, k: K): &V {
    +    field::borrow(&table.id, k)
    +}
    +
    + + + +
    + + + +## Function `borrow_mut` + +Mutably borrows the value associated with the key in the table table: &mut Table<K, V>. +Aborts with iota::dynamic_field::EFieldDoesNotExist if the table does not have an entry with +that key k: K. + + +
    public fun borrow_mut<K: copy, drop, store, V: store>(table: &mut table::Table<K, V>, k: K): &mut V
    +
    + + + +
    +Implementation + + +
    public fun borrow_mut<K: copy + drop + store, V: store>(table: &mut Table<K, V>, k: K): &mut V {
    +    field::borrow_mut(&mut table.id, k)
    +}
    +
    + + + +
    + + + +## Function `remove` + +Removes the key-value pair in the table table: &mut Table<K, V> and returns the value. +Aborts with iota::dynamic_field::EFieldDoesNotExist if the table does not have an entry with +that key k: K. + + +
    public fun remove<K: copy, drop, store, V: store>(table: &mut table::Table<K, V>, k: K): V
    +
    + + + +
    +Implementation + + +
    public fun remove<K: copy + drop + store, V: store>(table: &mut Table<K, V>, k: K): V {
    +    let v = field::remove(&mut table.id, k);
    +    table.size = table.size - 1;
    +    v
    +}
    +
    + + + +
    + + + +## Function `contains` + +Returns true iff there is a value associated with the key k: K in table table: &Table<K, V> + + +
    public fun contains<K: copy, drop, store, V: store>(table: &table::Table<K, V>, k: K): bool
    +
    + + + +
    +Implementation + + +
    public fun contains<K: copy + drop + store, V: store>(table: &Table<K, V>, k: K): bool {
    +    field::exists_with_type<K, V>(&table.id, k)
    +}
    +
    + + + +
    + + + +## Function `length` + +Returns the size of the table, the number of key-value pairs + + +
    public fun length<K: copy, drop, store, V: store>(table: &table::Table<K, V>): u64
    +
    + + + +
    +Implementation + + +
    public fun length<K: copy + drop + store, V: store>(table: &Table<K, V>): u64 {
    +    table.size
    +}
    +
    + + + +
    + + + +## Function `is_empty` + +Returns true iff the table is empty (if length returns 0) + + +
    public fun is_empty<K: copy, drop, store, V: store>(table: &table::Table<K, V>): bool
    +
    + + + +
    +Implementation + + +
    public fun is_empty<K: copy + drop + store, V: store>(table: &Table<K, V>): bool {
    +    table.size == 0
    +}
    +
    + + + +
    + + + +## Function `destroy_empty` + +Destroys an empty table +Aborts with ETableNotEmpty if the table still contains values + + +
    public fun destroy_empty<K: copy, drop, store, V: store>(table: table::Table<K, V>)
    +
    + + + +
    +Implementation + + +
    public fun destroy_empty<K: copy + drop + store, V: store>(table: Table<K, V>) {
    +    let Table { id, size } = table;
    +    assert!(size == 0, ETableNotEmpty);
    +    id.delete()
    +}
    +
    + + + +
    + + + +## Function `drop` + +Drop a possibly non-empty table. +Usable only if the value type V has the drop ability + + +
    public fun drop<K: copy, drop, store, V: drop, store>(table: table::Table<K, V>)
    +
    + + + +
    +Implementation + + +
    public fun drop<K: copy + drop + store, V: drop + store>(table: Table<K, V>) {
    +    let Table { id, size: _ } = table;
    +    id.delete()
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-framework/table_vec.md b/crates/iota-framework/docs/iota-framework/table_vec.md new file mode 100644 index 00000000000..1b9f1b324c0 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/table_vec.md @@ -0,0 +1,407 @@ +--- +title: Module `0x2::table_vec` +--- + +A basic scalable vector library implemented using Table. + + +- [Struct `TableVec`](#0x2_table_vec_TableVec) +- [Constants](#@Constants_0) +- [Function `empty`](#0x2_table_vec_empty) +- [Function `singleton`](#0x2_table_vec_singleton) +- [Function `length`](#0x2_table_vec_length) +- [Function `is_empty`](#0x2_table_vec_is_empty) +- [Function `borrow`](#0x2_table_vec_borrow) +- [Function `push_back`](#0x2_table_vec_push_back) +- [Function `borrow_mut`](#0x2_table_vec_borrow_mut) +- [Function `pop_back`](#0x2_table_vec_pop_back) +- [Function `destroy_empty`](#0x2_table_vec_destroy_empty) +- [Function `drop`](#0x2_table_vec_drop) +- [Function `swap`](#0x2_table_vec_swap) +- [Function `swap_remove`](#0x2_table_vec_swap_remove) + + +
    use 0x2::table;
    +use 0x2::tx_context;
    +
    + + + + + +## Struct `TableVec` + + + +
    struct TableVec<Element: store> has store
    +
    + + + +
    +Fields + + +
    +
    +contents: table::Table<u64, Element> +
    +
    + The contents of the table vector. +
    +
    + + +
    + + + +## Constants + + + + + + +
    const EIndexOutOfBound: u64 = 0;
    +
    + + + + + + + +
    const ETableNonEmpty: u64 = 1;
    +
    + + + + + +## Function `empty` + +Create an empty TableVec. + + +
    public fun empty<Element: store>(ctx: &mut tx_context::TxContext): table_vec::TableVec<Element>
    +
    + + + +
    +Implementation + + +
    public fun empty<Element: store>(ctx: &mut TxContext): TableVec<Element> {
    +    TableVec {
    +        contents: table::new(ctx)
    +    }
    +}
    +
    + + + +
    + + + +## Function `singleton` + +Return a TableVec of size one containing element e. + + +
    public fun singleton<Element: store>(e: Element, ctx: &mut tx_context::TxContext): table_vec::TableVec<Element>
    +
    + + + +
    +Implementation + + +
    public fun singleton<Element: store>(e: Element, ctx: &mut TxContext): TableVec<Element> {
    +    let mut t = empty(ctx);
    +    t.push_back(e);
    +    t
    +}
    +
    + + + +
    + + + +## Function `length` + +Return the length of the TableVec. + + +
    public fun length<Element: store>(t: &table_vec::TableVec<Element>): u64
    +
    + + + +
    +Implementation + + +
    public fun length<Element: store>(t: &TableVec<Element>): u64 {
    +    t.contents.length()
    +}
    +
    + + + +
    + + + +## Function `is_empty` + +Return if the TableVec is empty or not. + + +
    public fun is_empty<Element: store>(t: &table_vec::TableVec<Element>): bool
    +
    + + + +
    +Implementation + + +
    public fun is_empty<Element: store>(t: &TableVec<Element>): bool {
    +    t.length() == 0
    +}
    +
    + + + +
    + + + +## Function `borrow` + +Acquire an immutable reference to the ith element of the TableVec t. +Aborts if i is out of bounds. + + +
    public fun borrow<Element: store>(t: &table_vec::TableVec<Element>, i: u64): &Element
    +
    + + + +
    +Implementation + + +
    public fun borrow<Element: store>(t: &TableVec<Element>, i: u64): &Element {
    +    assert!(t.length() > i, EIndexOutOfBound);
    +    &t.contents[i]
    +}
    +
    + + + +
    + + + +## Function `push_back` + +Add element e to the end of the TableVec t. + + +
    public fun push_back<Element: store>(t: &mut table_vec::TableVec<Element>, e: Element)
    +
    + + + +
    +Implementation + + +
    public fun push_back<Element: store>(t: &mut TableVec<Element>, e: Element) {
    +    let key = t.length();
    +    t.contents.add(key, e);
    +}
    +
    + + + +
    + + + +## Function `borrow_mut` + +Return a mutable reference to the ith element in the TableVec t. +Aborts if i is out of bounds. + + +
    public fun borrow_mut<Element: store>(t: &mut table_vec::TableVec<Element>, i: u64): &mut Element
    +
    + + + +
    +Implementation + + +
    public fun borrow_mut<Element: store>(t: &mut TableVec<Element>, i: u64): &mut Element {
    +    assert!(t.length() > i, EIndexOutOfBound);
    +    &mut t.contents[i]
    +}
    +
    + + + +
    + + + +## Function `pop_back` + +Pop an element from the end of TableVec t. +Aborts if t is empty. + + +
    public fun pop_back<Element: store>(t: &mut table_vec::TableVec<Element>): Element
    +
    + + + +
    +Implementation + + +
    public fun pop_back<Element: store>(t: &mut TableVec<Element>): Element {
    +    let length = length(t);
    +    assert!(length > 0, EIndexOutOfBound);
    +    t.contents.remove(length - 1)
    +}
    +
    + + + +
    + + + +## Function `destroy_empty` + +Destroy the TableVec t. +Aborts if t is not empty. + + +
    public fun destroy_empty<Element: store>(t: table_vec::TableVec<Element>)
    +
    + + + +
    +Implementation + + +
    public fun destroy_empty<Element: store>(t: TableVec<Element>) {
    +    assert!(length(&t) == 0, ETableNonEmpty);
    +    let TableVec { contents } = t;
    +    contents.destroy_empty();
    +}
    +
    + + + +
    + + + +## Function `drop` + +Drop a possibly non-empty TableVec t. +Usable only if the value type Element has the drop ability + + +
    public fun drop<Element: drop, store>(t: table_vec::TableVec<Element>)
    +
    + + + +
    +Implementation + + +
    public fun drop<Element: drop + store>(t: TableVec<Element>) {
    +    let TableVec { contents } = t;
    +    contents.drop()
    +}
    +
    + + + +
    + + + +## Function `swap` + +Swaps the elements at the ith and jth indices in the TableVec t. +Aborts if i or j is out of bounds. + + +
    public fun swap<Element: store>(t: &mut table_vec::TableVec<Element>, i: u64, j: u64)
    +
    + + + +
    +Implementation + + +
    public fun swap<Element: store>(t: &mut TableVec<Element>, i: u64, j: u64) {
    +    assert!(t.length() > i, EIndexOutOfBound);
    +    assert!(t.length() > j, EIndexOutOfBound);
    +    if (i == j) { return };
    +    let element_i = t.contents.remove(i);
    +    let element_j = t.contents.remove(j);
    +    t.contents.add(j, element_i);
    +    t.contents.add(i, element_j);
    +}
    +
    + + + +
    + + + +## Function `swap_remove` + +Swap the ith element of the TableVec t with the last element and then pop the TableVec. +This is O(1), but does not preserve ordering of elements in the TableVec. +Aborts if i is out of bounds. + + +
    public fun swap_remove<Element: store>(t: &mut table_vec::TableVec<Element>, i: u64): Element
    +
    + + + +
    +Implementation + + +
    public fun swap_remove<Element: store>(t: &mut TableVec<Element>, i: u64): Element {
    +    assert!(t.length() > i, EIndexOutOfBound);
    +    let last_idx = t.length() - 1;
    +    t.swap(i, last_idx);
    +    t.pop_back()
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/sui-framework/token.md b/crates/iota-framework/docs/iota-framework/token.md similarity index 99% rename from crates/sui-framework/docs/sui-framework/token.md rename to crates/iota-framework/docs/iota-framework/token.md index 46f78b7e8fa..32099e65dbf 100644 --- a/crates/sui-framework/docs/sui-framework/token.md +++ b/crates/iota-framework/docs/iota-framework/token.md @@ -11,7 +11,7 @@ and burning of the Tokens. A companion to existing open-loop (Coin) systems. ``` -Module: sui::balance sui::coin sui::token +Module: iota::balance iota::coin iota::token Main type: Balance Coin Token Capability: Supply <----> TreasuryCap <----> TreasuryCap Abilities: store key + store key diff --git a/crates/iota-framework/docs/iota-framework/transfer.md b/crates/iota-framework/docs/iota-framework/transfer.md new file mode 100644 index 00000000000..8f85f8acced --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/transfer.md @@ -0,0 +1,479 @@ +--- +title: Module `0x2::transfer` +--- + + + +- [Struct `Receiving`](#0x2_transfer_Receiving) +- [Constants](#@Constants_0) +- [Function `transfer`](#0x2_transfer_transfer) +- [Function `public_transfer`](#0x2_transfer_public_transfer) +- [Function `freeze_object`](#0x2_transfer_freeze_object) +- [Function `public_freeze_object`](#0x2_transfer_public_freeze_object) +- [Function `share_object`](#0x2_transfer_share_object) +- [Function `public_share_object`](#0x2_transfer_public_share_object) +- [Function `receive`](#0x2_transfer_receive) +- [Function `public_receive`](#0x2_transfer_public_receive) +- [Function `receiving_object_id`](#0x2_transfer_receiving_object_id) +- [Function `freeze_object_impl`](#0x2_transfer_freeze_object_impl) +- [Function `share_object_impl`](#0x2_transfer_share_object_impl) +- [Function `transfer_impl`](#0x2_transfer_transfer_impl) +- [Function `receive_impl`](#0x2_transfer_receive_impl) + + +
    use 0x2::object;
    +
    + + + + + +## Struct `Receiving` + +This represents the ability to receive an object of type T. +This type is ephemeral per-transaction and cannot be stored on-chain. +This does not represent the obligation to receive the object that it +references, but simply the ability to receive the object with object ID +id at version version if you can prove mutable access to the parent +object during the transaction. +Internals of this struct are opaque outside this module. + + +
    struct Receiving<T: key> has drop
    +
    + + + +
    +Fields + + +
    +
    +id: object::ID +
    +
    + +
    +
    +version: u64 +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + +Serialization of the object failed. + + +
    const EBCSSerializationFailure: u64 = 1;
    +
    + + + + + +The object being received is not of the expected type. + + +
    const EReceivingObjectTypeMismatch: u64 = 2;
    +
    + + + + + +Shared an object that was previously created. Shared objects must currently +be constructed in the transaction they are created. + + +
    const ESharedNonNewObject: u64 = 0;
    +
    + + + + + +Shared object operations such as wrapping, freezing, and converting to owned are not allowed. + + +
    const ESharedObjectOperationNotSupported: u64 = 4;
    +
    + + + + + +Represents both the case where the object does not exist and the case where the object is not +able to be accessed through the parent that is passed-in. + + +
    const EUnableToReceiveObject: u64 = 3;
    +
    + + + + + +## Function `transfer` + +Transfer ownership of obj to recipient. obj must have the key attribute, +which (in turn) ensures that obj has a globally unique ID. Note that if the recipient +address represents an object ID, the obj sent will be inaccessible after the transfer +(though they will be retrievable at a future date once new features are added). +This function has custom rules performed by the Iota Move bytecode verifier that ensures +that T is an object defined in the module where transfer is invoked. Use +public_transfer to transfer an object with store outside of its module. + + +
    public fun transfer<T: key>(obj: T, recipient: address)
    +
    + + + +
    +Implementation + + +
    public fun transfer<T: key>(obj: T, recipient: address) {
    +    transfer_impl(obj, recipient)
    +}
    +
    + + + +
    + + + +## Function `public_transfer` + +Transfer ownership of obj to recipient. obj must have the key attribute, +which (in turn) ensures that obj has a globally unique ID. Note that if the recipient +address represents an object ID, the obj sent will be inaccessible after the transfer +(though they will be retrievable at a future date once new features are added). +The object must have store to be transferred outside of its module. + + +
    public fun public_transfer<T: store, key>(obj: T, recipient: address)
    +
    + + + +
    +Implementation + + +
    public fun public_transfer<T: key + store>(obj: T, recipient: address) {
    +    transfer_impl(obj, recipient)
    +}
    +
    + + + +
    + + + +## Function `freeze_object` + +Freeze obj. After freezing obj becomes immutable and can no longer be transferred or +mutated. +This function has custom rules performed by the Iota Move bytecode verifier that ensures +that T is an object defined in the module where freeze_object is invoked. Use +public_freeze_object to freeze an object with store outside of its module. + + +
    public fun freeze_object<T: key>(obj: T)
    +
    + + + +
    +Implementation + + +
    public fun freeze_object<T: key>(obj: T) {
    +    freeze_object_impl(obj)
    +}
    +
    + + + +
    + + + +## Function `public_freeze_object` + +Freeze obj. After freezing obj becomes immutable and can no longer be transferred or +mutated. +The object must have store to be frozen outside of its module. + + +
    public fun public_freeze_object<T: store, key>(obj: T)
    +
    + + + +
    +Implementation + + +
    public fun public_freeze_object<T: key + store>(obj: T) {
    +    freeze_object_impl(obj)
    +}
    +
    + + + +
    + + + +## Function `share_object` + +Turn the given object into a mutable shared object that everyone can access and mutate. +This is irreversible, i.e. once an object is shared, it will stay shared forever. +Aborts with ESharedNonNewObject of the object being shared was not created in this +transaction. This restriction may be relaxed in the future. +This function has custom rules performed by the Iota Move bytecode verifier that ensures +that T is an object defined in the module where share_object is invoked. Use +public_share_object to share an object with store outside of its module. + + +
    public fun share_object<T: key>(obj: T)
    +
    + + + +
    +Implementation + + +
    public fun share_object<T: key>(obj: T) {
    +    share_object_impl(obj)
    +}
    +
    + + + +
    + + + +## Function `public_share_object` + +Turn the given object into a mutable shared object that everyone can access and mutate. +This is irreversible, i.e. once an object is shared, it will stay shared forever. +Aborts with ESharedNonNewObject of the object being shared was not created in this +transaction. This restriction may be relaxed in the future. +The object must have store to be shared outside of its module. + + +
    public fun public_share_object<T: store, key>(obj: T)
    +
    + + + +
    +Implementation + + +
    public fun public_share_object<T: key + store>(obj: T) {
    +    share_object_impl(obj)
    +}
    +
    + + + +
    + + + +## Function `receive` + +Given mutable (i.e., locked) access to the parent and a Receiving argument +referencing an object of type T owned by parent use the to_receive +argument to receive and return the referenced owned object of type T. +This function has custom rules performed by the Iota Move bytecode verifier that ensures +that T is an object defined in the module where receive is invoked. Use +public_receive to receivne an object with store outside of its module. + + +
    public fun receive<T: key>(parent: &mut object::UID, to_receive: transfer::Receiving<T>): T
    +
    + + + +
    +Implementation + + +
    public fun receive<T: key>(parent: &mut UID, to_receive: Receiving<T>): T {
    +    let Receiving {
    +        id,
    +        version,
    +    } = to_receive;
    +    receive_impl(parent.to_address(), id, version)
    +}
    +
    + + + +
    + + + +## Function `public_receive` + +Given mutable (i.e., locked) access to the parent and a Receiving argument +referencing an object of type T owned by parent use the to_receive +argument to receive and return the referenced owned object of type T. +The object must have store to be received outside of its defining module. + + +
    public fun public_receive<T: store, key>(parent: &mut object::UID, to_receive: transfer::Receiving<T>): T
    +
    + + + +
    +Implementation + + +
    public fun public_receive<T: key + store>(parent: &mut UID, to_receive: Receiving<T>): T {
    +    let Receiving {
    +        id,
    +        version,
    +    } = to_receive;
    +    receive_impl(parent.to_address(), id, version)
    +}
    +
    + + + +
    + + + +## Function `receiving_object_id` + +Return the object ID that the given Receiving argument references. + + +
    public fun receiving_object_id<T: key>(receiving: &transfer::Receiving<T>): object::ID
    +
    + + + +
    +Implementation + + +
    public fun receiving_object_id<T: key>(receiving: &Receiving<T>): ID {
    +    receiving.id
    +}
    +
    + + + +
    + + + +## Function `freeze_object_impl` + + + +
    public(friend) fun freeze_object_impl<T: key>(obj: T)
    +
    + + + +
    +Implementation + + +
    public(package) native fun freeze_object_impl<T: key>(obj: T);
    +
    + + + +
    + + + +## Function `share_object_impl` + + + +
    public(friend) fun share_object_impl<T: key>(obj: T)
    +
    + + + +
    +Implementation + + +
    public(package) native fun share_object_impl<T: key>(obj: T);
    +
    + + + +
    + + + +## Function `transfer_impl` + + + +
    public(friend) fun transfer_impl<T: key>(obj: T, recipient: address)
    +
    + + + +
    +Implementation + + +
    public(package) native fun transfer_impl<T: key>(obj: T, recipient: address);
    +
    + + + +
    + + + +## Function `receive_impl` + + + +
    fun receive_impl<T: key>(parent: address, to_receive: object::ID, version: u64): T
    +
    + + + +
    +Implementation + + +
    native fun receive_impl<T: key>(parent: address, to_receive: ID, version: u64): T;
    +
    + + + +
    diff --git a/crates/sui-framework/docs/sui-framework/transfer_policy.md b/crates/iota-framework/docs/iota-framework/transfer_policy.md similarity index 97% rename from crates/sui-framework/docs/sui-framework/transfer_policy.md rename to crates/iota-framework/docs/iota-framework/transfer_policy.md index 2594fd1d78b..9a29b18e940 100644 --- a/crates/sui-framework/docs/sui-framework/transfer_policy.md +++ b/crates/iota-framework/docs/iota-framework/transfer_policy.md @@ -57,9 +57,9 @@ of the type at once. use 0x2::coin; use 0x2::dynamic_field; use 0x2::event; +use 0x2::iota; use 0x2::object; use 0x2::package; -use 0x2::sui; use 0x2::transfer; use 0x2::tx_context; use 0x2::vec_set; @@ -97,7 +97,7 @@ from the item type (T) owner on purchase attempt. paid: u64
    - Amount of SUI paid for the item. Can be used to + Amount of IOTA paid for the item. Can be used to calculate the fee / transfer policy enforcement.
    @@ -147,10 +147,10 @@ policies can be used to confirm the balance: balance::Balance<sui::SUI> +balance: balance::Balance<iota::IOTA>
    - The Balance of the TransferPolicy which collects SUI. + The Balance of the TransferPolicy which collects IOTA. By default, transfer policy does not collect anything , and it's a matter of an implementation of a specific rule - whether to add to balance and how much. @@ -444,8 +444,8 @@ sender.
    entry fun default<T>(pub: &Publisher, ctx: &mut TxContext) {
         let (policy, cap) = new<T>(pub, ctx);
    -    sui::transfer::share_object(policy);
    -    sui::transfer::transfer(cap, ctx.sender());
    +    iota::transfer::share_object(policy);
    +    iota::transfer::transfer(cap, ctx.sender());
     }
     
    @@ -461,7 +461,7 @@ Withdraw some amount of profits from the withdraw<T>(self: &mut transfer_policy::TransferPolicy<T>, cap: &transfer_policy::TransferPolicyCap<T>, amount: option::Option<u64>, ctx: &mut tx_context::TxContext): coin::Coin<sui::SUI> +
    public fun withdraw<T>(self: &mut transfer_policy::TransferPolicy<T>, cap: &transfer_policy::TransferPolicyCap<T>, amount: option::Option<u64>, ctx: &mut tx_context::TxContext): coin::Coin<iota::IOTA>
     
    @@ -475,7 +475,7 @@ is not specified, all profits are withdrawn. cap: &TransferPolicyCap<T>, amount: Option<u64>, ctx: &mut TxContext -): Coin<SUI> { +): Coin<IOTA> { assert!(object::id(self) == cap.policy_id, ENotOwner); let amount = if (amount.is_some()) { @@ -502,7 +502,7 @@ Destroy a TransferPolicyCap. Can be performed by any party as long as they own it. -
    public fun destroy_and_withdraw<T>(self: transfer_policy::TransferPolicy<T>, cap: transfer_policy::TransferPolicyCap<T>, ctx: &mut tx_context::TxContext): coin::Coin<sui::SUI>
    +
    public fun destroy_and_withdraw<T>(self: transfer_policy::TransferPolicy<T>, cap: transfer_policy::TransferPolicyCap<T>, ctx: &mut tx_context::TxContext): coin::Coin<iota::IOTA>
     
    @@ -513,7 +513,7 @@ Can be performed by any party as long as they own it.
    public fun destroy_and_withdraw<T>(
         self: TransferPolicy<T>, cap: TransferPolicyCap<T>, ctx: &mut TxContext
    -): Coin<SUI> {
    +): Coin<IOTA> {
         assert!(object::id(&self) == cap.policy_id, ENotOwner);
     
         let TransferPolicyCap { id: cap_id, policy_id } = cap;
    @@ -643,10 +643,10 @@ Get the custom Config for the Rule (can be only one per "Rule" type).
     
     ## Function `add_to_balance`
     
    -Add some SUI to the balance of a TransferPolicy.
    +Add some IOTA to the balance of a TransferPolicy.
     
     
    -
    public fun add_to_balance<T, Rule: drop>(_: Rule, policy: &mut transfer_policy::TransferPolicy<T>, coin: coin::Coin<sui::SUI>)
    +
    public fun add_to_balance<T, Rule: drop>(_: Rule, policy: &mut transfer_policy::TransferPolicy<T>, coin: coin::Coin<iota::IOTA>)
     
    @@ -656,7 +656,7 @@ Add some SUI to the balance of a add_to_balance<T, Rule: drop>( - _: Rule, policy: &mut TransferPolicy<T>, coin: Coin<SUI> + _: Rule, policy: &mut TransferPolicy<T>, coin: Coin<IOTA> ) { assert!(has_rule<T, Rule>(policy), EUnknownRequrement); coin::put(&mut policy.balance, coin) diff --git a/crates/iota-framework/docs/iota-framework/tx_context.md b/crates/iota-framework/docs/iota-framework/tx_context.md new file mode 100644 index 00000000000..37c34b59581 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/tx_context.md @@ -0,0 +1,255 @@ +--- +title: Module `0x2::tx_context` +--- + + + +- [Struct `TxContext`](#0x2_tx_context_TxContext) +- [Function `sender`](#0x2_tx_context_sender) +- [Function `digest`](#0x2_tx_context_digest) +- [Function `epoch`](#0x2_tx_context_epoch) +- [Function `epoch_timestamp_ms`](#0x2_tx_context_epoch_timestamp_ms) +- [Function `fresh_object_address`](#0x2_tx_context_fresh_object_address) +- [Function `ids_created`](#0x2_tx_context_ids_created) +- [Function `derive_id`](#0x2_tx_context_derive_id) + + +
    + + + + + +## Struct `TxContext` + +Information about the transaction currently being executed. +This cannot be constructed by a transaction--it is a privileged object created by +the VM and passed in to the entrypoint of the transaction as &mut TxContext. + + +
    struct TxContext has drop
    +
    + + + +
    +Fields + + +
    +
    +sender: address +
    +
    + The address of the user that signed the current transaction +
    +
    +tx_hash: vector<u8> +
    +
    + Hash of the current transaction +
    +
    +epoch: u64 +
    +
    + The current epoch number +
    +
    +epoch_timestamp_ms: u64 +
    +
    + Timestamp that the epoch started at +
    +
    +ids_created: u64 +
    +
    + Counter recording the number of fresh id's created while executing + this transaction. Always 0 at the start of a transaction +
    +
    + + +
    + + + +## Function `sender` + +Return the address of the user that signed the current +transaction + + +
    public fun sender(self: &tx_context::TxContext): address
    +
    + + + +
    +Implementation + + +
    public fun sender(self: &TxContext): address {
    +    self.sender
    +}
    +
    + + + +
    + + + +## Function `digest` + +Return the transaction digest (hash of transaction inputs). +Please do not use as a source of randomness. + + +
    public fun digest(self: &tx_context::TxContext): &vector<u8>
    +
    + + + +
    +Implementation + + +
    public fun digest(self: &TxContext): &vector<u8> {
    +    &self.tx_hash
    +}
    +
    + + + +
    + + + +## Function `epoch` + +Return the current epoch + + +
    public fun epoch(self: &tx_context::TxContext): u64
    +
    + + + +
    +Implementation + + +
    public fun epoch(self: &TxContext): u64 {
    +    self.epoch
    +}
    +
    + + + +
    + + + +## Function `epoch_timestamp_ms` + +Return the epoch start time as a unix timestamp in milliseconds. + + +
    public fun epoch_timestamp_ms(self: &tx_context::TxContext): u64
    +
    + + + +
    +Implementation + + +
    public fun epoch_timestamp_ms(self: &TxContext): u64 {
    +   self.epoch_timestamp_ms
    +}
    +
    + + + +
    + + + +## Function `fresh_object_address` + +Create an address that has not been used. As it is an object address, it will never +occur as the address for a user. +In other words, the generated address is a globally unique object ID. + + +
    public fun fresh_object_address(ctx: &mut tx_context::TxContext): address
    +
    + + + +
    +Implementation + + +
    public fun fresh_object_address(ctx: &mut TxContext): address {
    +    let ids_created = ctx.ids_created;
    +    let id = derive_id(*&ctx.tx_hash, ids_created);
    +    ctx.ids_created = ids_created + 1;
    +    id
    +}
    +
    + + + +
    + + + +## Function `ids_created` + +Return the number of id's created by the current transaction. +Hidden for now, but may expose later + + +
    fun ids_created(self: &tx_context::TxContext): u64
    +
    + + + +
    +Implementation + + +
    fun ids_created(self: &TxContext): u64 {
    +    self.ids_created
    +}
    +
    + + + +
    + + + +## Function `derive_id` + +Native function for deriving an ID via hash(tx_hash || ids_created) + + +
    fun derive_id(tx_hash: vector<u8>, ids_created: u64): address
    +
    + + + +
    +Implementation + + +
    native fun derive_id(tx_hash: vector<u8>, ids_created: u64): address;
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-framework/types.md b/crates/iota-framework/docs/iota-framework/types.md new file mode 100644 index 00000000000..098300d1cb6 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/types.md @@ -0,0 +1,37 @@ +--- +title: Module `0x2::types` +--- + +Iota types helpers and utilities + + +- [Function `is_one_time_witness`](#0x2_types_is_one_time_witness) + + +
    + + + + + +## Function `is_one_time_witness` + +Tests if the argument type is a one-time witness, that is a type with only one instantiation +across the entire code base. + + +
    public fun is_one_time_witness<T: drop>(_: &T): bool
    +
    + + + +
    +Implementation + + +
    public native fun is_one_time_witness<T: drop>(_: &T): bool;
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-framework/url.md b/crates/iota-framework/docs/iota-framework/url.md new file mode 100644 index 00000000000..7e8e433c3cc --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/url.md @@ -0,0 +1,148 @@ +--- +title: Module `0x2::url` +--- + +URL: standard Uniform Resource Locator string + + +- [Struct `Url`](#0x2_url_Url) +- [Function `new_unsafe`](#0x2_url_new_unsafe) +- [Function `new_unsafe_from_bytes`](#0x2_url_new_unsafe_from_bytes) +- [Function `inner_url`](#0x2_url_inner_url) +- [Function `update`](#0x2_url_update) + + +
    use 0x1::ascii;
    +
    + + + + + +## Struct `Url` + +Standard Uniform Resource Locator (URL) string. + + +
    struct Url has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +url: ascii::String +
    +
    + +
    +
    + + +
    + + + +## Function `new_unsafe` + +Create a Url, with no validation + + +
    public fun new_unsafe(url: ascii::String): url::Url
    +
    + + + +
    +Implementation + + +
    public fun new_unsafe(url: String): Url {
    +    Url { url }
    +}
    +
    + + + +
    + + + +## Function `new_unsafe_from_bytes` + +Create a Url with no validation from bytes +Note: this will abort if bytes is not valid ASCII + + +
    public fun new_unsafe_from_bytes(bytes: vector<u8>): url::Url
    +
    + + + +
    +Implementation + + +
    public fun new_unsafe_from_bytes(bytes: vector<u8>): Url {
    +    let url = bytes.to_ascii_string();
    +    Url { url }
    +}
    +
    + + + +
    + + + +## Function `inner_url` + +Get inner URL + + +
    public fun inner_url(self: &url::Url): ascii::String
    +
    + + + +
    +Implementation + + +
    public fun inner_url(self: &Url): String{
    +    self.url
    +}
    +
    + + + +
    + + + +## Function `update` + +Update the inner URL + + +
    public fun update(self: &mut url::Url, url: ascii::String)
    +
    + + + +
    +Implementation + + +
    public fun update(self: &mut Url, url: String) {
    +    self.url = url;
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-framework/vec_map.md b/crates/iota-framework/docs/iota-framework/vec_map.md new file mode 100644 index 00000000000..602072395c6 --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/vec_map.md @@ -0,0 +1,673 @@ +--- +title: Module `0x2::vec_map` +--- + + + +- [Struct `VecMap`](#0x2_vec_map_VecMap) +- [Struct `Entry`](#0x2_vec_map_Entry) +- [Constants](#@Constants_0) +- [Function `empty`](#0x2_vec_map_empty) +- [Function `insert`](#0x2_vec_map_insert) +- [Function `remove`](#0x2_vec_map_remove) +- [Function `pop`](#0x2_vec_map_pop) +- [Function `get_mut`](#0x2_vec_map_get_mut) +- [Function `get`](#0x2_vec_map_get) +- [Function `try_get`](#0x2_vec_map_try_get) +- [Function `contains`](#0x2_vec_map_contains) +- [Function `size`](#0x2_vec_map_size) +- [Function `is_empty`](#0x2_vec_map_is_empty) +- [Function `destroy_empty`](#0x2_vec_map_destroy_empty) +- [Function `into_keys_values`](#0x2_vec_map_into_keys_values) +- [Function `keys`](#0x2_vec_map_keys) +- [Function `get_idx_opt`](#0x2_vec_map_get_idx_opt) +- [Function `get_idx`](#0x2_vec_map_get_idx) +- [Function `get_entry_by_idx`](#0x2_vec_map_get_entry_by_idx) +- [Function `get_entry_by_idx_mut`](#0x2_vec_map_get_entry_by_idx_mut) +- [Function `remove_entry_by_idx`](#0x2_vec_map_remove_entry_by_idx) + + +
    use 0x1::option;
    +use 0x1::vector;
    +
    + + + + + +## Struct `VecMap` + +A map data structure backed by a vector. The map is guaranteed not to contain duplicate keys, but entries +are *not* sorted by key--entries are included in insertion order. +All operations are O(N) in the size of the map--the intention of this data structure is only to provide +the convenience of programming against a map API. +Large maps should use handwritten parent/child relationships instead. +Maps that need sorted iteration rather than insertion order iteration should also be handwritten. + + +
    struct VecMap<K: copy, V> has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +contents: vector<vec_map::Entry<K, V>> +
    +
    + +
    +
    + + +
    + + + +## Struct `Entry` + +An entry in the map + + +
    struct Entry<K: copy, V> has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +key: K +
    +
    + +
    +
    +value: V +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + +This key already exists in the map + + +
    const EKeyAlreadyExists: u64 = 0;
    +
    + + + + + +This key does not exist in the map + + +
    const EKeyDoesNotExist: u64 = 1;
    +
    + + + + + +Trying to access an element of the map at an invalid index + + +
    const EIndexOutOfBounds: u64 = 3;
    +
    + + + + + +Trying to pop from a map that is empty + + +
    const EMapEmpty: u64 = 4;
    +
    + + + + + +Trying to destroy a map that is not empty + + +
    const EMapNotEmpty: u64 = 2;
    +
    + + + + + +## Function `empty` + +Create an empty VecMap + + +
    public fun empty<K: copy, V>(): vec_map::VecMap<K, V>
    +
    + + + +
    +Implementation + + +
    public fun empty<K: copy, V>(): VecMap<K,V> {
    +    VecMap { contents: vector[] }
    +}
    +
    + + + +
    + + + +## Function `insert` + +Insert the entry key |-> value into self. +Aborts if key is already bound in self. + + +
    public fun insert<K: copy, V>(self: &mut vec_map::VecMap<K, V>, key: K, value: V)
    +
    + + + +
    +Implementation + + +
    public fun insert<K: copy, V>(self: &mut VecMap<K,V>, key: K, value: V) {
    +    assert!(!self.contains(&key), EKeyAlreadyExists);
    +    self.contents.push_back(Entry { key, value })
    +}
    +
    + + + +
    + + + +## Function `remove` + +Remove the entry key |-> value from self. Aborts if key is not bound in self. + + +
    public fun remove<K: copy, V>(self: &mut vec_map::VecMap<K, V>, key: &K): (K, V)
    +
    + + + +
    +Implementation + + +
    public fun remove<K: copy, V>(self: &mut VecMap<K,V>, key: &K): (K, V) {
    +    let idx = self.get_idx(key);
    +    let Entry { key, value } = self.contents.remove(idx);
    +    (key, value)
    +}
    +
    + + + +
    + + + +## Function `pop` + +Pop the most recently inserted entry from the map. Aborts if the map is empty. + + +
    public fun pop<K: copy, V>(self: &mut vec_map::VecMap<K, V>): (K, V)
    +
    + + + +
    +Implementation + + +
    public fun pop<K: copy, V>(self: &mut VecMap<K,V>): (K, V) {
    +    assert!(!self.contents.is_empty(), EMapEmpty);
    +    let Entry { key, value } = self.contents.pop_back();
    +    (key, value)
    +}
    +
    + + + +
    + + + +## Function `get_mut` + +Get a mutable reference to the value bound to key in self. +Aborts if key is not bound in self. + + +
    public fun get_mut<K: copy, V>(self: &mut vec_map::VecMap<K, V>, key: &K): &mut V
    +
    + + + +
    +Implementation + + +
    public fun get_mut<K: copy, V>(self: &mut VecMap<K,V>, key: &K): &mut V {
    +    let idx = self.get_idx(key);
    +    let entry = &mut self.contents[idx];
    +    &mut entry.value
    +}
    +
    + + + +
    + + + +## Function `get` + +Get a reference to the value bound to key in self. +Aborts if key is not bound in self. + + +
    public fun get<K: copy, V>(self: &vec_map::VecMap<K, V>, key: &K): &V
    +
    + + + +
    +Implementation + + +
    public fun get<K: copy, V>(self: &VecMap<K,V>, key: &K): &V {
    +    let idx = self.get_idx(key);
    +    let entry = &self.contents[idx];
    +    &entry.value
    +}
    +
    + + + +
    + + + +## Function `try_get` + +Safely try borrow a value bound to key in self. +Return Some(V) if the value exists, None otherwise. +Only works for a "copyable" value as references cannot be stored in vector. + + +
    public fun try_get<K: copy, V: copy>(self: &vec_map::VecMap<K, V>, key: &K): option::Option<V>
    +
    + + + +
    +Implementation + + +
    public fun try_get<K: copy, V: copy>(self: &VecMap<K,V>, key: &K): Option<V> {
    +    if (self.contains(key)) {
    +        option::some(*get(self, key))
    +    } else {
    +        option::none()
    +    }
    +}
    +
    + + + +
    + + + +## Function `contains` + +Return true if self contains an entry for key, false otherwise + + +
    public fun contains<K: copy, V>(self: &vec_map::VecMap<K, V>, key: &K): bool
    +
    + + + +
    +Implementation + + +
    public fun contains<K: copy, V>(self: &VecMap<K, V>, key: &K): bool {
    +    get_idx_opt(self, key).is_some()
    +}
    +
    + + + +
    + + + +## Function `size` + +Return the number of entries in self + + +
    public fun size<K: copy, V>(self: &vec_map::VecMap<K, V>): u64
    +
    + + + +
    +Implementation + + +
    public fun size<K: copy, V>(self: &VecMap<K,V>): u64 {
    +    self.contents.length()
    +}
    +
    + + + +
    + + + +## Function `is_empty` + +Return true if self has 0 elements, false otherwise + + +
    public fun is_empty<K: copy, V>(self: &vec_map::VecMap<K, V>): bool
    +
    + + + +
    +Implementation + + +
    public fun is_empty<K: copy, V>(self: &VecMap<K,V>): bool {
    +    self.size() == 0
    +}
    +
    + + + +
    + + + +## Function `destroy_empty` + +Destroy an empty map. Aborts if self is not empty + + +
    public fun destroy_empty<K: copy, V>(self: vec_map::VecMap<K, V>)
    +
    + + + +
    +Implementation + + +
    public fun destroy_empty<K: copy, V>(self: VecMap<K, V>) {
    +    let VecMap { contents } = self;
    +    assert!(contents.is_empty(), EMapNotEmpty);
    +    contents.destroy_empty()
    +}
    +
    + + + +
    + + + +## Function `into_keys_values` + +Unpack self into vectors of its keys and values. +The output keys and values are stored in insertion order, *not* sorted by key. + + +
    public fun into_keys_values<K: copy, V>(self: vec_map::VecMap<K, V>): (vector<K>, vector<V>)
    +
    + + + +
    +Implementation + + +
    public fun into_keys_values<K: copy, V>(self: VecMap<K, V>): (vector<K>, vector<V>) {
    +    let VecMap { mut contents } = self;
    +    // reverse the vector so the output keys and values will appear in insertion order
    +    contents.reverse();
    +    let mut i = 0;
    +    let n = contents.length();
    +    let mut keys = vector[];
    +    let mut values = vector[];
    +    while (i < n) {
    +        let Entry { key, value } = contents.pop_back();
    +        keys.push_back(key);
    +        values.push_back(value);
    +        i = i + 1;
    +    };
    +    contents.destroy_empty();
    +    (keys, values)
    +}
    +
    + + + +
    + + + +## Function `keys` + +Returns a list of keys in the map. +Do not assume any particular ordering. + + +
    public fun keys<K: copy, V>(self: &vec_map::VecMap<K, V>): vector<K>
    +
    + + + +
    +Implementation + + +
    public fun keys<K: copy, V>(self: &VecMap<K, V>): vector<K> {
    +    let mut i = 0;
    +    let n = self.contents.length();
    +    let mut keys = vector[];
    +    while (i < n) {
    +        let entry = self.contents.borrow(i);
    +        keys.push_back(entry.key);
    +        i = i + 1;
    +    };
    +    keys
    +}
    +
    + + + +
    + + + +## Function `get_idx_opt` + +Find the index of key in self. Return None if key is not in self. +Note that map entries are stored in insertion order, *not* sorted by key. + + +
    public fun get_idx_opt<K: copy, V>(self: &vec_map::VecMap<K, V>, key: &K): option::Option<u64>
    +
    + + + +
    +Implementation + + +
    public fun get_idx_opt<K: copy, V>(self: &VecMap<K,V>, key: &K): Option<u64> {
    +    let mut i = 0;
    +    let n = size(self);
    +    while (i < n) {
    +        if (&self.contents[i].key == key) {
    +            return option::some(i)
    +        };
    +        i = i + 1;
    +    };
    +    option::none()
    +}
    +
    + + + +
    + + + +## Function `get_idx` + +Find the index of key in self. Aborts if key is not in self. +Note that map entries are stored in insertion order, *not* sorted by key. + + +
    public fun get_idx<K: copy, V>(self: &vec_map::VecMap<K, V>, key: &K): u64
    +
    + + + +
    +Implementation + + +
    public fun get_idx<K: copy, V>(self: &VecMap<K,V>, key: &K): u64 {
    +    let idx_opt = self.get_idx_opt(key);
    +    assert!(idx_opt.is_some(), EKeyDoesNotExist);
    +    idx_opt.destroy_some()
    +}
    +
    + + + +
    + + + +## Function `get_entry_by_idx` + +Return a reference to the idxth entry of self. This gives direct access into the backing array of the map--use with caution. +Note that map entries are stored in insertion order, *not* sorted by key. +Aborts if idx is greater than or equal to size(self) + + +
    public fun get_entry_by_idx<K: copy, V>(self: &vec_map::VecMap<K, V>, idx: u64): (&K, &V)
    +
    + + + +
    +Implementation + + +
    public fun get_entry_by_idx<K: copy, V>(self: &VecMap<K, V>, idx: u64): (&K, &V) {
    +    assert!(idx < size(self), EIndexOutOfBounds);
    +    let entry = &self.contents[idx];
    +    (&entry.key, &entry.value)
    +}
    +
    + + + +
    + + + +## Function `get_entry_by_idx_mut` + +Return a mutable reference to the idxth entry of self. This gives direct access into the backing array of the map--use with caution. +Note that map entries are stored in insertion order, *not* sorted by key. +Aborts if idx is greater than or equal to size(self) + + +
    public fun get_entry_by_idx_mut<K: copy, V>(self: &mut vec_map::VecMap<K, V>, idx: u64): (&K, &mut V)
    +
    + + + +
    +Implementation + + +
    public fun get_entry_by_idx_mut<K: copy, V>(self: &mut VecMap<K, V>, idx: u64): (&K, &mut V) {
    +    assert!(idx < size(self), EIndexOutOfBounds);
    +    let entry = &mut self.contents[idx];
    +    (&entry.key, &mut entry.value)
    +}
    +
    + + + +
    + + + +## Function `remove_entry_by_idx` + +Remove the entry at index idx from self. +Aborts if idx is greater than or equal to size(self) + + +
    public fun remove_entry_by_idx<K: copy, V>(self: &mut vec_map::VecMap<K, V>, idx: u64): (K, V)
    +
    + + + +
    +Implementation + + +
    public fun remove_entry_by_idx<K: copy, V>(self: &mut VecMap<K, V>, idx: u64): (K, V) {
    +    assert!(idx < size(self), EIndexOutOfBounds);
    +    let Entry { key, value } = self.contents.remove(idx);
    +    (key, value)
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-framework/vec_set.md b/crates/iota-framework/docs/iota-framework/vec_set.md new file mode 100644 index 00000000000..0beafabfc1d --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/vec_set.md @@ -0,0 +1,377 @@ +--- +title: Module `0x2::vec_set` +--- + + + +- [Struct `VecSet`](#0x2_vec_set_VecSet) +- [Constants](#@Constants_0) +- [Function `empty`](#0x2_vec_set_empty) +- [Function `singleton`](#0x2_vec_set_singleton) +- [Function `insert`](#0x2_vec_set_insert) +- [Function `remove`](#0x2_vec_set_remove) +- [Function `contains`](#0x2_vec_set_contains) +- [Function `size`](#0x2_vec_set_size) +- [Function `is_empty`](#0x2_vec_set_is_empty) +- [Function `into_keys`](#0x2_vec_set_into_keys) +- [Function `keys`](#0x2_vec_set_keys) +- [Function `get_idx_opt`](#0x2_vec_set_get_idx_opt) +- [Function `get_idx`](#0x2_vec_set_get_idx) + + +
    use 0x1::option;
    +use 0x1::vector;
    +
    + + + + + +## Struct `VecSet` + +A set data structure backed by a vector. The set is guaranteed not to +contain duplicate keys. All operations are O(N) in the size of the set +- the intention of this data structure is only to provide the convenience +of programming against a set API. Sets that need sorted iteration rather +than insertion order iteration should be handwritten. + + +
    struct VecSet<K: copy, drop> has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +contents: vector<K> +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + +This key already exists in the map + + +
    const EKeyAlreadyExists: u64 = 0;
    +
    + + + + + +This key does not exist in the map + + +
    const EKeyDoesNotExist: u64 = 1;
    +
    + + + + + +## Function `empty` + +Create an empty VecSet + + +
    public fun empty<K: copy, drop>(): vec_set::VecSet<K>
    +
    + + + +
    +Implementation + + +
    public fun empty<K: copy + drop>(): VecSet<K> {
    +    VecSet { contents: vector[] }
    +}
    +
    + + + +
    + + + +## Function `singleton` + +Create a singleton VecSet that only contains one element. + + +
    public fun singleton<K: copy, drop>(key: K): vec_set::VecSet<K>
    +
    + + + +
    +Implementation + + +
    public fun singleton<K: copy + drop>(key: K): VecSet<K> {
    +    VecSet { contents: vector[key] }
    +}
    +
    + + + +
    + + + +## Function `insert` + +Insert a key into self. +Aborts if key is already present in self. + + +
    public fun insert<K: copy, drop>(self: &mut vec_set::VecSet<K>, key: K)
    +
    + + + +
    +Implementation + + +
    public fun insert<K: copy + drop>(self: &mut VecSet<K>, key: K) {
    +    assert!(!self.contains(&key), EKeyAlreadyExists);
    +    self.contents.push_back(key)
    +}
    +
    + + + +
    + + + +## Function `remove` + +Remove the entry key from self. Aborts if key is not present in self. + + +
    public fun remove<K: copy, drop>(self: &mut vec_set::VecSet<K>, key: &K)
    +
    + + + +
    +Implementation + + +
    public fun remove<K: copy + drop>(self: &mut VecSet<K>, key: &K) {
    +    let idx = get_idx(self, key);
    +    self.contents.remove(idx);
    +}
    +
    + + + +
    + + + +## Function `contains` + +Return true if self contains an entry for key, false otherwise + + +
    public fun contains<K: copy, drop>(self: &vec_set::VecSet<K>, key: &K): bool
    +
    + + + +
    +Implementation + + +
    public fun contains<K: copy + drop>(self: &VecSet<K>, key: &K): bool {
    +    get_idx_opt(self, key).is_some()
    +}
    +
    + + + +
    + + + +## Function `size` + +Return the number of entries in self + + +
    public fun size<K: copy, drop>(self: &vec_set::VecSet<K>): u64
    +
    + + + +
    +Implementation + + +
    public fun size<K: copy + drop>(self: &VecSet<K>): u64 {
    +    self.contents.length()
    +}
    +
    + + + +
    + + + +## Function `is_empty` + +Return true if self has 0 elements, false otherwise + + +
    public fun is_empty<K: copy, drop>(self: &vec_set::VecSet<K>): bool
    +
    + + + +
    +Implementation + + +
    public fun is_empty<K: copy + drop>(self: &VecSet<K>): bool {
    +    size(self) == 0
    +}
    +
    + + + +
    + + + +## Function `into_keys` + +Unpack self into vectors of keys. +The output keys are stored in insertion order, *not* sorted. + + +
    public fun into_keys<K: copy, drop>(self: vec_set::VecSet<K>): vector<K>
    +
    + + + +
    +Implementation + + +
    public fun into_keys<K: copy + drop>(self: VecSet<K>): vector<K> {
    +    let VecSet { contents } = self;
    +    contents
    +}
    +
    + + + +
    + + + +## Function `keys` + +Borrow the contents of the VecSet to access content by index +without unpacking. The contents are stored in insertion order, +*not* sorted. + + +
    public fun keys<K: copy, drop>(self: &vec_set::VecSet<K>): &vector<K>
    +
    + + + +
    +Implementation + + +
    public fun keys<K: copy + drop>(self: &VecSet<K>): &vector<K> {
    +    &self.contents
    +}
    +
    + + + +
    + + + +## Function `get_idx_opt` + +Find the index of key in self. Return None if key is not in self. +Note that keys are stored in insertion order, *not* sorted. + + +
    fun get_idx_opt<K: copy, drop>(self: &vec_set::VecSet<K>, key: &K): option::Option<u64>
    +
    + + + +
    +Implementation + + +
    fun get_idx_opt<K: copy + drop>(self: &VecSet<K>, key: &K): Option<u64> {
    +    let mut i = 0;
    +    let n = size(self);
    +    while (i < n) {
    +        if (&self.contents[i] == key) {
    +            return option::some(i)
    +        };
    +        i = i + 1;
    +    };
    +    option::none()
    +}
    +
    + + + +
    + + + +## Function `get_idx` + +Find the index of key in self. Aborts if key is not in self. +Note that map entries are stored in insertion order, *not* sorted. + + +
    fun get_idx<K: copy, drop>(self: &vec_set::VecSet<K>, key: &K): u64
    +
    + + + +
    +Implementation + + +
    fun get_idx<K: copy + drop>(self: &VecSet<K>, key: &K): u64 {
    +    let idx_opt = get_idx_opt(self, key);
    +    assert!(idx_opt.is_some(), EKeyDoesNotExist);
    +    idx_opt.destroy_some()
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-framework/versioned.md b/crates/iota-framework/docs/iota-framework/versioned.md new file mode 100644 index 00000000000..e2765201cfe --- /dev/null +++ b/crates/iota-framework/docs/iota-framework/versioned.md @@ -0,0 +1,309 @@ +--- +title: Module `0x2::versioned` +--- + + + +- [Resource `Versioned`](#0x2_versioned_Versioned) +- [Struct `VersionChangeCap`](#0x2_versioned_VersionChangeCap) +- [Constants](#@Constants_0) +- [Function `create`](#0x2_versioned_create) +- [Function `version`](#0x2_versioned_version) +- [Function `load_value`](#0x2_versioned_load_value) +- [Function `load_value_mut`](#0x2_versioned_load_value_mut) +- [Function `remove_value_for_upgrade`](#0x2_versioned_remove_value_for_upgrade) +- [Function `upgrade`](#0x2_versioned_upgrade) +- [Function `destroy`](#0x2_versioned_destroy) + + +
    use 0x2::dynamic_field;
    +use 0x2::object;
    +use 0x2::tx_context;
    +
    + + + + + +## Resource `Versioned` + +A wrapper type that supports versioning of the inner type. +The inner type is a dynamic field of the Versioned object, and is keyed using version. +User of this type could load the inner object using corresponding type based on the version. +You can also upgrade the inner object to a new type version. +If you want to support lazy upgrade of the inner type, one caveat is that all APIs would have +to use mutable reference even if it's a read-only API. + + +
    struct Versioned has store, key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +version: u64 +
    +
    + +
    +
    + + +
    + + + +## Struct `VersionChangeCap` + +Represents a hot potato object generated when we take out the dynamic field. +This is to make sure that we always put a new value back. + + +
    struct VersionChangeCap
    +
    + + + +
    +Fields + + +
    +
    +versioned_id: object::ID +
    +
    + +
    +
    +old_version: u64 +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + +Failed to upgrade the inner object due to invalid capability or new version. + + +
    const EInvalidUpgrade: u64 = 0;
    +
    + + + + + +## Function `create` + +Create a new Versioned object that contains a initial value of type T with an initial version. + + +
    public fun create<T: store>(init_version: u64, init_value: T, ctx: &mut tx_context::TxContext): versioned::Versioned
    +
    + + + +
    +Implementation + + +
    public fun create<T: store>(init_version: u64, init_value: T, ctx: &mut TxContext): Versioned {
    +    let mut self = Versioned {
    +        id: object::new(ctx),
    +        version: init_version,
    +    };
    +    dynamic_field::add(&mut self.id, init_version, init_value);
    +    self
    +}
    +
    + + + +
    + + + +## Function `version` + +Get the current version of the inner type. + + +
    public fun version(self: &versioned::Versioned): u64
    +
    + + + +
    +Implementation + + +
    public fun version(self: &Versioned): u64 {
    +    self.version
    +}
    +
    + + + +
    + + + +## Function `load_value` + +Load the inner value based on the current version. Caller specifies an expected type T. +If the type mismatch, the load will fail. + + +
    public fun load_value<T: store>(self: &versioned::Versioned): &T
    +
    + + + +
    +Implementation + + +
    public fun load_value<T: store>(self: &Versioned): &T {
    +    dynamic_field::borrow(&self.id, self.version)
    +}
    +
    + + + +
    + + + +## Function `load_value_mut` + +Similar to load_value, but return a mutable reference. + + +
    public fun load_value_mut<T: store>(self: &mut versioned::Versioned): &mut T
    +
    + + + +
    +Implementation + + +
    public fun load_value_mut<T: store>(self: &mut Versioned): &mut T {
    +    dynamic_field::borrow_mut(&mut self.id, self.version)
    +}
    +
    + + + +
    + + + +## Function `remove_value_for_upgrade` + +Take the inner object out for upgrade. To ensure we always upgrade properly, a capability object is returned +and must be used when we upgrade. + + +
    public fun remove_value_for_upgrade<T: store>(self: &mut versioned::Versioned): (T, versioned::VersionChangeCap)
    +
    + + + +
    +Implementation + + +
    public fun remove_value_for_upgrade<T: store>(self: &mut Versioned): (T, VersionChangeCap) {
    +    (
    +        dynamic_field::remove(&mut self.id, self.version),
    +        VersionChangeCap {
    +            versioned_id: object::id(self),
    +            old_version: self.version,
    +        }
    +    )
    +}
    +
    + + + +
    + + + +## Function `upgrade` + +Upgrade the inner object with a new version and new value. Must use the capability returned +by calling remove_value_for_upgrade. + + +
    public fun upgrade<T: store>(self: &mut versioned::Versioned, new_version: u64, new_value: T, cap: versioned::VersionChangeCap)
    +
    + + + +
    +Implementation + + +
    public fun upgrade<T: store>(self: &mut Versioned, new_version: u64, new_value: T, cap: VersionChangeCap) {
    +    let VersionChangeCap { versioned_id, old_version } = cap;
    +    assert!(versioned_id == object::id(self), EInvalidUpgrade);
    +    assert!(old_version < new_version, EInvalidUpgrade);
    +    dynamic_field::add(&mut self.id, new_version, new_value);
    +    self.version = new_version;
    +}
    +
    + + + +
    + + + +## Function `destroy` + +Destroy this Versioned container, and return the inner object. + + +
    public fun destroy<T: store>(self: versioned::Versioned): T
    +
    + + + +
    +Implementation + + +
    public fun destroy<T: store>(self: Versioned): T {
    +    let Versioned { mut id, version } = self;
    +    let ret = dynamic_field::remove(&mut id, version);
    +    id.delete();
    +    ret
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/sui-framework/zklogin_verified_id.md b/crates/iota-framework/docs/iota-framework/zklogin_verified_id.md similarity index 100% rename from crates/sui-framework/docs/sui-framework/zklogin_verified_id.md rename to crates/iota-framework/docs/iota-framework/zklogin_verified_id.md diff --git a/crates/sui-framework/docs/sui-framework/zklogin_verified_issuer.md b/crates/iota-framework/docs/iota-framework/zklogin_verified_issuer.md similarity index 100% rename from crates/sui-framework/docs/sui-framework/zklogin_verified_issuer.md rename to crates/iota-framework/docs/iota-framework/zklogin_verified_issuer.md diff --git a/crates/iota-framework/docs/iota-system/genesis.md b/crates/iota-framework/docs/iota-system/genesis.md new file mode 100644 index 00000000000..6596d57ac48 --- /dev/null +++ b/crates/iota-framework/docs/iota-system/genesis.md @@ -0,0 +1,563 @@ +--- +title: Module `0x3::genesis` +--- + + + +- [Struct `GenesisValidatorMetadata`](#0x3_genesis_GenesisValidatorMetadata) +- [Struct `GenesisChainParameters`](#0x3_genesis_GenesisChainParameters) +- [Struct `TokenDistributionSchedule`](#0x3_genesis_TokenDistributionSchedule) +- [Struct `TokenAllocation`](#0x3_genesis_TokenAllocation) +- [Constants](#@Constants_0) +- [Function `create`](#0x3_genesis_create) +- [Function `allocate_tokens`](#0x3_genesis_allocate_tokens) +- [Function `activate_validators`](#0x3_genesis_activate_validators) + + +
    use 0x1::option;
    +use 0x1::vector;
    +use 0x2::balance;
    +use 0x2::coin;
    +use 0x2::iota;
    +use 0x2::object;
    +use 0x2::tx_context;
    +use 0x3::iota_system;
    +use 0x3::iota_system_state_inner;
    +use 0x3::stake_subsidy;
    +use 0x3::validator;
    +use 0x3::validator_set;
    +
    + + + + + +## Struct `GenesisValidatorMetadata` + + + +
    struct GenesisValidatorMetadata has copy, drop
    +
    + + + +
    +Fields + + +
    +
    +name: vector<u8> +
    +
    + +
    +
    +description: vector<u8> +
    +
    + +
    +
    +image_url: vector<u8> +
    +
    + +
    +
    +project_url: vector<u8> +
    +
    + +
    +
    +iota_address: address +
    +
    + +
    +
    +gas_price: u64 +
    +
    + +
    +
    +commission_rate: u64 +
    +
    + +
    +
    +protocol_public_key: vector<u8> +
    +
    + +
    +
    +proof_of_possession: vector<u8> +
    +
    + +
    +
    +network_public_key: vector<u8> +
    +
    + +
    +
    +worker_public_key: vector<u8> +
    +
    + +
    +
    +network_address: vector<u8> +
    +
    + +
    +
    +p2p_address: vector<u8> +
    +
    + +
    +
    +primary_address: vector<u8> +
    +
    + +
    +
    +worker_address: vector<u8> +
    +
    + +
    +
    + + +
    + + + +## Struct `GenesisChainParameters` + + + +
    struct GenesisChainParameters has copy, drop
    +
    + + + +
    +Fields + + +
    +
    +protocol_version: u64 +
    +
    + +
    +
    +chain_start_timestamp_ms: u64 +
    +
    + +
    +
    +epoch_duration_ms: u64 +
    +
    + +
    +
    +stake_subsidy_start_epoch: u64 +
    +
    + +
    +
    +stake_subsidy_initial_distribution_amount: u64 +
    +
    + +
    +
    +stake_subsidy_period_length: u64 +
    +
    + +
    +
    +stake_subsidy_decrease_rate: u16 +
    +
    + +
    +
    +max_validator_count: u64 +
    +
    + +
    +
    +min_validator_joining_stake: u64 +
    +
    + +
    +
    +validator_low_stake_threshold: u64 +
    +
    + +
    +
    +validator_very_low_stake_threshold: u64 +
    +
    + +
    +
    +validator_low_stake_grace_period: u64 +
    +
    + +
    +
    + + +
    + + + +## Struct `TokenDistributionSchedule` + + + +
    struct TokenDistributionSchedule
    +
    + + + +
    +Fields + + +
    +
    +stake_subsidy_fund_micros: u64 +
    +
    + +
    +
    +allocations: vector<genesis::TokenAllocation> +
    +
    + +
    +
    + + +
    + + + +## Struct `TokenAllocation` + + + +
    struct TokenAllocation
    +
    + + + +
    +Fields + + +
    +
    +recipient_address: address +
    +
    + +
    +
    +amount_micros: u64 +
    +
    + +
    +
    +staked_with_validator: option::Option<address> +
    +
    + Indicates if this allocation should be staked at genesis and with which validator +
    +
    + + +
    + + + +## Constants + + + + +The create function was called with duplicate validators. + + +
    const EDuplicateValidator: u64 = 1;
    +
    + + + + + +The create function was called at a non-genesis epoch. + + +
    const ENotCalledAtGenesis: u64 = 0;
    +
    + + + + + +## Function `create` + +This function will be explicitly called once at genesis. +It will create a singleton IotaSystemState object, which contains +all the information we need in the system. + + +
    fun create(iota_system_state_id: object::UID, iota_supply: balance::Balance<iota::IOTA>, genesis_chain_parameters: genesis::GenesisChainParameters, genesis_validators: vector<genesis::GenesisValidatorMetadata>, token_distribution_schedule: genesis::TokenDistributionSchedule, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    fun create(
    +    iota_system_state_id: UID,
    +    mut iota_supply: Balance<IOTA>,
    +    genesis_chain_parameters: GenesisChainParameters,
    +    genesis_validators: vector<GenesisValidatorMetadata>,
    +    token_distribution_schedule: TokenDistributionSchedule,
    +    ctx: &mut TxContext,
    +) {
    +    // Ensure this is only called at genesis
    +    assert!(ctx.epoch() == 0, ENotCalledAtGenesis);
    +
    +    let TokenDistributionSchedule {
    +        stake_subsidy_fund_micros,
    +        allocations,
    +    } = token_distribution_schedule;
    +
    +    let subsidy_fund = iota_supply.split(stake_subsidy_fund_micros);
    +    let storage_fund = balance::zero();
    +
    +    // Create all the `Validator` structs
    +    let mut validators = vector[];
    +    let count = genesis_validators.length();
    +    let mut i = 0;
    +    while (i < count) {
    +        let GenesisValidatorMetadata {
    +            name,
    +            description,
    +            image_url,
    +            project_url,
    +            iota_address,
    +            gas_price,
    +            commission_rate,
    +            protocol_public_key,
    +            proof_of_possession,
    +            network_public_key,
    +            worker_public_key,
    +            network_address,
    +            p2p_address,
    +            primary_address,
    +            worker_address,
    +        } = genesis_validators[i];
    +
    +        let validator = validator::new(
    +            iota_address,
    +            protocol_public_key,
    +            network_public_key,
    +            worker_public_key,
    +            proof_of_possession,
    +            name,
    +            description,
    +            image_url,
    +            project_url,
    +            network_address,
    +            p2p_address,
    +            primary_address,
    +            worker_address,
    +            gas_price,
    +            commission_rate,
    +            ctx
    +        );
    +
    +        // Ensure that each validator is unique
    +        assert!(
    +            !validator_set::is_duplicate_validator(&validators, &validator),
    +            EDuplicateValidator,
    +        );
    +
    +        validators.push_back(validator);
    +
    +        i = i + 1;
    +    };
    +
    +    // Allocate tokens and staking operations
    +    allocate_tokens(
    +        iota_supply,
    +        allocations,
    +        &mut validators,
    +        ctx
    +    );
    +
    +    // Activate all validators
    +    activate_validators(&mut validators);
    +
    +    let system_parameters = iota_system_state_inner::create_system_parameters(
    +        genesis_chain_parameters.epoch_duration_ms,
    +        genesis_chain_parameters.stake_subsidy_start_epoch,
    +
    +        // Validator committee parameters
    +        genesis_chain_parameters.max_validator_count,
    +        genesis_chain_parameters.min_validator_joining_stake,
    +        genesis_chain_parameters.validator_low_stake_threshold,
    +        genesis_chain_parameters.validator_very_low_stake_threshold,
    +        genesis_chain_parameters.validator_low_stake_grace_period,
    +
    +        ctx,
    +    );
    +
    +    let stake_subsidy = stake_subsidy::create(
    +        subsidy_fund,
    +        genesis_chain_parameters.stake_subsidy_initial_distribution_amount,
    +        genesis_chain_parameters.stake_subsidy_period_length,
    +        genesis_chain_parameters.stake_subsidy_decrease_rate,
    +        ctx,
    +    );
    +
    +    iota_system::create(
    +        iota_system_state_id,
    +        validators,
    +        storage_fund,
    +        genesis_chain_parameters.protocol_version,
    +        genesis_chain_parameters.chain_start_timestamp_ms,
    +        system_parameters,
    +        stake_subsidy,
    +        ctx,
    +    );
    +}
    +
    + + + +
    + + + +## Function `allocate_tokens` + + + +
    fun allocate_tokens(iota_supply: balance::Balance<iota::IOTA>, allocations: vector<genesis::TokenAllocation>, validators: &mut vector<validator::Validator>, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    fun allocate_tokens(
    +    mut iota_supply: Balance<IOTA>,
    +    mut allocations: vector<TokenAllocation>,
    +    validators: &mut vector<Validator>,
    +    ctx: &mut TxContext,
    +) {
    +
    +    while (!allocations.is_empty()) {
    +        let TokenAllocation {
    +            recipient_address,
    +            amount_micros,
    +            staked_with_validator,
    +        } = allocations.pop_back();
    +
    +        let allocation_balance = iota_supply.split(amount_micros);
    +
    +        if (staked_with_validator.is_some()) {
    +            let validator_address = staked_with_validator.destroy_some();
    +            let validator = validator_set::get_validator_mut(validators, validator_address);
    +            validator.request_add_stake_at_genesis(
    +                allocation_balance,
    +                recipient_address,
    +                ctx
    +            );
    +        } else {
    +            iota::transfer(
    +                allocation_balance.into_coin(ctx),
    +                recipient_address,
    +            );
    +        };
    +    };
    +    allocations.destroy_empty();
    +
    +    // Provided allocations must fully allocate the iota_supply and there
    +    // should be none left at this point.
    +    iota_supply.destroy_zero();
    +}
    +
    + + + +
    + + + +## Function `activate_validators` + + + +
    fun activate_validators(validators: &mut vector<validator::Validator>)
    +
    + + + +
    +Implementation + + +
    fun activate_validators(validators: &mut vector<Validator>) {
    +    // Activate all genesis validators
    +    let count = validators.length();
    +    let mut i = 0;
    +    while (i < count) {
    +        let validator = &mut validators[i];
    +        validator.activate(0);
    +
    +        i = i + 1;
    +    };
    +
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-system/iota_system.md b/crates/iota-framework/docs/iota-system/iota_system.md new file mode 100644 index 00000000000..cf6ab5c3c8a --- /dev/null +++ b/crates/iota-framework/docs/iota-system/iota_system.md @@ -0,0 +1,1492 @@ +--- +title: Module `0x3::iota_system` +--- + +Iota System State Type Upgrade Guide +IotaSystemState is a thin wrapper around IotaSystemStateInner that provides a versioned interface. +The IotaSystemState object has a fixed ID 0x5, and the IotaSystemStateInner object is stored as a dynamic field. +There are a few different ways to upgrade the IotaSystemStateInner type: + +The simplest and one that doesn't involve a real upgrade is to just add dynamic fields to the extra_fields field +of IotaSystemStateInner or any of its sub type. This is useful when we are in a rush, or making a small change, +or still experimenting a new field. + +To properly upgrade the IotaSystemStateInner type, we need to ship a new framework that does the following: +1. Define a new IotaSystemStateInnertype (e.g. IotaSystemStateInnerV2). +2. Define a data migration function that migrates the old IotaSystemStateInner to the new one (i.e. IotaSystemStateInnerV2). +3. Replace all uses of IotaSystemStateInner with IotaSystemStateInnerV2 in both iota_system.move and iota_system_state_inner.move, +with the exception of the iota_system_state_inner::create function, which should always return the genesis type. +4. Inside load_inner_maybe_upgrade function, check the current version in the wrapper, and if it's not the latest version, +call the data migration function to upgrade the inner object. Make sure to also update the version in the wrapper. +A detailed example can be found in iota/tests/framework_upgrades/mock_iota_systems/shallow_upgrade. +Along with the Move change, we also need to update the Rust code to support the new type. This includes: +1. Define a new IotaSystemStateInner struct type that matches the new Move type, and implement the IotaSystemStateTrait. +2. Update the IotaSystemState struct to include the new version as a new enum variant. +3. Update the get_iota_system_state function to handle the new version. +To test that the upgrade will be successful, we need to modify iota_system_state_production_upgrade_test test in +protocol_version_tests and trigger a real upgrade using the new framework. We will need to keep this directory as old version, +put the new framework in a new directory, and run the test to exercise the upgrade. + +To upgrade Validator type, besides everything above, we also need to: +1. Define a new Validator type (e.g. ValidatorV2). +2. Define a data migration function that migrates the old Validator to the new one (i.e. ValidatorV2). +3. Replace all uses of Validator with ValidatorV2 except the genesis creation function. +4. In validator_wrapper::upgrade_to_latest, check the current version in the wrapper, and if it's not the latest version, +call the data migration function to upgrade it. +In Rust, we also need to add a new case in get_validator_from_table. +Note that it is possible to upgrade IotaSystemStateInner without upgrading Validator, but not the other way around. +And when we only upgrade IotaSystemStateInner, the version of Validator in the wrapper will not be updated, and hence may become +inconsistent with the version of IotaSystemStateInner. This is fine as long as we don't use the Validator version to determine +the IotaSystemStateInner version, or vice versa. + + +- [Resource `IotaSystemState`](#0x3_iota_system_IotaSystemState) +- [Constants](#@Constants_0) +- [Function `create`](#0x3_iota_system_create) +- [Function `request_add_validator_candidate`](#0x3_iota_system_request_add_validator_candidate) +- [Function `request_remove_validator_candidate`](#0x3_iota_system_request_remove_validator_candidate) +- [Function `request_add_validator`](#0x3_iota_system_request_add_validator) +- [Function `request_remove_validator`](#0x3_iota_system_request_remove_validator) +- [Function `request_set_gas_price`](#0x3_iota_system_request_set_gas_price) +- [Function `set_candidate_validator_gas_price`](#0x3_iota_system_set_candidate_validator_gas_price) +- [Function `request_set_commission_rate`](#0x3_iota_system_request_set_commission_rate) +- [Function `set_candidate_validator_commission_rate`](#0x3_iota_system_set_candidate_validator_commission_rate) +- [Function `request_add_stake`](#0x3_iota_system_request_add_stake) +- [Function `request_add_stake_non_entry`](#0x3_iota_system_request_add_stake_non_entry) +- [Function `request_add_stake_mul_coin`](#0x3_iota_system_request_add_stake_mul_coin) +- [Function `request_withdraw_stake`](#0x3_iota_system_request_withdraw_stake) +- [Function `request_withdraw_stake_non_entry`](#0x3_iota_system_request_withdraw_stake_non_entry) +- [Function `report_validator`](#0x3_iota_system_report_validator) +- [Function `undo_report_validator`](#0x3_iota_system_undo_report_validator) +- [Function `rotate_operation_cap`](#0x3_iota_system_rotate_operation_cap) +- [Function `update_validator_name`](#0x3_iota_system_update_validator_name) +- [Function `update_validator_description`](#0x3_iota_system_update_validator_description) +- [Function `update_validator_image_url`](#0x3_iota_system_update_validator_image_url) +- [Function `update_validator_project_url`](#0x3_iota_system_update_validator_project_url) +- [Function `update_validator_next_epoch_network_address`](#0x3_iota_system_update_validator_next_epoch_network_address) +- [Function `update_candidate_validator_network_address`](#0x3_iota_system_update_candidate_validator_network_address) +- [Function `update_validator_next_epoch_p2p_address`](#0x3_iota_system_update_validator_next_epoch_p2p_address) +- [Function `update_candidate_validator_p2p_address`](#0x3_iota_system_update_candidate_validator_p2p_address) +- [Function `update_validator_next_epoch_primary_address`](#0x3_iota_system_update_validator_next_epoch_primary_address) +- [Function `update_candidate_validator_primary_address`](#0x3_iota_system_update_candidate_validator_primary_address) +- [Function `update_validator_next_epoch_worker_address`](#0x3_iota_system_update_validator_next_epoch_worker_address) +- [Function `update_candidate_validator_worker_address`](#0x3_iota_system_update_candidate_validator_worker_address) +- [Function `update_validator_next_epoch_protocol_pubkey`](#0x3_iota_system_update_validator_next_epoch_protocol_pubkey) +- [Function `update_candidate_validator_protocol_pubkey`](#0x3_iota_system_update_candidate_validator_protocol_pubkey) +- [Function `update_validator_next_epoch_worker_pubkey`](#0x3_iota_system_update_validator_next_epoch_worker_pubkey) +- [Function `update_candidate_validator_worker_pubkey`](#0x3_iota_system_update_candidate_validator_worker_pubkey) +- [Function `update_validator_next_epoch_network_pubkey`](#0x3_iota_system_update_validator_next_epoch_network_pubkey) +- [Function `update_candidate_validator_network_pubkey`](#0x3_iota_system_update_candidate_validator_network_pubkey) +- [Function `pool_exchange_rates`](#0x3_iota_system_pool_exchange_rates) +- [Function `active_validator_addresses`](#0x3_iota_system_active_validator_addresses) +- [Function `advance_epoch`](#0x3_iota_system_advance_epoch) +- [Function `load_system_state`](#0x3_iota_system_load_system_state) +- [Function `load_system_state_mut`](#0x3_iota_system_load_system_state_mut) +- [Function `load_inner_maybe_upgrade`](#0x3_iota_system_load_inner_maybe_upgrade) + + +
    use 0x1::option;
    +use 0x2::balance;
    +use 0x2::coin;
    +use 0x2::dynamic_field;
    +use 0x2::iota;
    +use 0x2::object;
    +use 0x2::table;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +use 0x3::iota_system_state_inner;
    +use 0x3::stake_subsidy;
    +use 0x3::staking_pool;
    +use 0x3::validator;
    +use 0x3::validator_cap;
    +
    + + + + + +## Resource `IotaSystemState` + + + +
    struct IotaSystemState has key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +version: u64 +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + + + +
    const ENotSystemAddress: u64 = 0;
    +
    + + + + + + + +
    const EWrongInnerVersion: u64 = 1;
    +
    + + + + + +## Function `create` + +Create a new IotaSystemState object and make it shared. +This function will be called only once in genesis. + + +
    public(friend) fun create(id: object::UID, validators: vector<validator::Validator>, storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun create(
    +    id: UID,
    +    validators: vector<Validator>,
    +    storage_fund: Balance<IOTA>,
    +    protocol_version: u64,
    +    epoch_start_timestamp_ms: u64,
    +    parameters: SystemParameters,
    +    stake_subsidy: StakeSubsidy,
    +    ctx: &mut TxContext,
    +) {
    +    let system_state = iota_system_state_inner::create(
    +        validators,
    +        storage_fund,
    +        protocol_version,
    +        epoch_start_timestamp_ms,
    +        parameters,
    +        stake_subsidy,
    +        ctx,
    +    );
    +    let version = iota_system_state_inner::genesis_system_state_version();
    +    let mut self = IotaSystemState {
    +        id,
    +        version,
    +    };
    +    dynamic_field::add(&mut self.id, version, system_state);
    +    transfer::share_object(self);
    +}
    +
    + + + +
    + + + +## Function `request_add_validator_candidate` + +Can be called by anyone who wishes to become a validator candidate and starts accuring delegated +stakes in their staking pool. Once they have at least MIN_VALIDATOR_JOINING_STAKE amount of stake they +can call request_add_validator to officially become an active validator at the next epoch. +Aborts if the caller is already a pending or active validator, or a validator candidate. +Note: proof_of_possession MUST be a valid signature using iota_address and protocol_pubkey_bytes. +To produce a valid PoP, run [fn test_proof_of_possession]. + + +
    public entry fun request_add_validator_candidate(wrapper: &mut iota_system::IotaSystemState, pubkey_bytes: vector<u8>, network_pubkey_bytes: vector<u8>, worker_pubkey_bytes: vector<u8>, proof_of_possession: vector<u8>, name: vector<u8>, description: vector<u8>, image_url: vector<u8>, project_url: vector<u8>, net_address: vector<u8>, p2p_address: vector<u8>, primary_address: vector<u8>, worker_address: vector<u8>, gas_price: u64, commission_rate: u64, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun request_add_validator_candidate(
    +    wrapper: &mut IotaSystemState,
    +    pubkey_bytes: vector<u8>,
    +    network_pubkey_bytes: vector<u8>,
    +    worker_pubkey_bytes: vector<u8>,
    +    proof_of_possession: vector<u8>,
    +    name: vector<u8>,
    +    description: vector<u8>,
    +    image_url: vector<u8>,
    +    project_url: vector<u8>,
    +    net_address: vector<u8>,
    +    p2p_address: vector<u8>,
    +    primary_address: vector<u8>,
    +    worker_address: vector<u8>,
    +    gas_price: u64,
    +    commission_rate: u64,
    +    ctx: &mut TxContext,
    +) {
    +    let self = load_system_state_mut(wrapper);
    +    self.request_add_validator_candidate(
    +        pubkey_bytes,
    +        network_pubkey_bytes,
    +        worker_pubkey_bytes,
    +        proof_of_possession,
    +        name,
    +        description,
    +        image_url,
    +        project_url,
    +        net_address,
    +        p2p_address,
    +        primary_address,
    +        worker_address,
    +        gas_price,
    +        commission_rate,
    +        ctx,
    +    )
    +}
    +
    + + + +
    + + + +## Function `request_remove_validator_candidate` + +Called by a validator candidate to remove themselves from the candidacy. After this call +their staking pool becomes deactivate. + + +
    public entry fun request_remove_validator_candidate(wrapper: &mut iota_system::IotaSystemState, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun request_remove_validator_candidate(
    +    wrapper: &mut IotaSystemState,
    +    ctx: &mut TxContext,
    +) {
    +    let self = load_system_state_mut(wrapper);
    +    self.request_remove_validator_candidate(ctx)
    +}
    +
    + + + +
    + + + +## Function `request_add_validator` + +Called by a validator candidate to add themselves to the active validator set beginning next epoch. +Aborts if the validator is a duplicate with one of the pending or active validators, or if the amount of +stake the validator has doesn't meet the min threshold, or if the number of new validators for the next +epoch has already reached the maximum. + + +
    public entry fun request_add_validator(wrapper: &mut iota_system::IotaSystemState, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun request_add_validator(
    +    wrapper: &mut IotaSystemState,
    +    ctx: &mut TxContext,
    +) {
    +    let self = load_system_state_mut(wrapper);
    +    self.request_add_validator(ctx)
    +}
    +
    + + + +
    + + + +## Function `request_remove_validator` + +A validator can call this function to request a removal in the next epoch. +We use the sender of ctx to look up the validator +(i.e. sender must match the iota_address in the validator). +At the end of the epoch, the validator object will be returned to the iota_address +of the validator. + + +
    public entry fun request_remove_validator(wrapper: &mut iota_system::IotaSystemState, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun request_remove_validator(
    +    wrapper: &mut IotaSystemState,
    +    ctx: &mut TxContext,
    +) {
    +    let self = load_system_state_mut(wrapper);
    +    self.request_remove_validator(ctx)
    +}
    +
    + + + +
    + + + +## Function `request_set_gas_price` + +A validator can call this entry function to submit a new gas price quote, to be +used for the reference gas price calculation at the end of the epoch. + + +
    public entry fun request_set_gas_price(wrapper: &mut iota_system::IotaSystemState, cap: &validator_cap::UnverifiedValidatorOperationCap, new_gas_price: u64)
    +
    + + + +
    +Implementation + + +
    public entry fun request_set_gas_price(
    +    wrapper: &mut IotaSystemState,
    +    cap: &UnverifiedValidatorOperationCap,
    +    new_gas_price: u64,
    +) {
    +    let self = load_system_state_mut(wrapper);
    +    self.request_set_gas_price(cap, new_gas_price)
    +}
    +
    + + + +
    + + + +## Function `set_candidate_validator_gas_price` + +This entry function is used to set new gas price for candidate validators + + +
    public entry fun set_candidate_validator_gas_price(wrapper: &mut iota_system::IotaSystemState, cap: &validator_cap::UnverifiedValidatorOperationCap, new_gas_price: u64)
    +
    + + + +
    +Implementation + + +
    public entry fun set_candidate_validator_gas_price(
    +    wrapper: &mut IotaSystemState,
    +    cap: &UnverifiedValidatorOperationCap,
    +    new_gas_price: u64,
    +) {
    +    let self = load_system_state_mut(wrapper);
    +    self.set_candidate_validator_gas_price(cap, new_gas_price)
    +}
    +
    + + + +
    + + + +## Function `request_set_commission_rate` + +A validator can call this entry function to set a new commission rate, updated at the end of +the epoch. + + +
    public entry fun request_set_commission_rate(wrapper: &mut iota_system::IotaSystemState, new_commission_rate: u64, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun request_set_commission_rate(
    +    wrapper: &mut IotaSystemState,
    +    new_commission_rate: u64,
    +    ctx: &mut TxContext,
    +) {
    +    let self = load_system_state_mut(wrapper);
    +    self.request_set_commission_rate(new_commission_rate, ctx)
    +}
    +
    + + + +
    + + + +## Function `set_candidate_validator_commission_rate` + +This entry function is used to set new commission rate for candidate validators + + +
    public entry fun set_candidate_validator_commission_rate(wrapper: &mut iota_system::IotaSystemState, new_commission_rate: u64, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun set_candidate_validator_commission_rate(
    +    wrapper: &mut IotaSystemState,
    +    new_commission_rate: u64,
    +    ctx: &mut TxContext,
    +) {
    +    let self = load_system_state_mut(wrapper);
    +    self.set_candidate_validator_commission_rate(new_commission_rate, ctx)
    +}
    +
    + + + +
    + + + +## Function `request_add_stake` + +Add stake to a validator's staking pool. + + +
    public entry fun request_add_stake(wrapper: &mut iota_system::IotaSystemState, stake: coin::Coin<iota::IOTA>, validator_address: address, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun request_add_stake(
    +    wrapper: &mut IotaSystemState,
    +    stake: Coin<IOTA>,
    +    validator_address: address,
    +    ctx: &mut TxContext,
    +) {
    +    let staked_iota = request_add_stake_non_entry(wrapper, stake, validator_address, ctx);
    +    transfer::public_transfer(staked_iota, ctx.sender());
    +}
    +
    + + + +
    + + + +## Function `request_add_stake_non_entry` + +The non-entry version of request_add_stake, which returns the staked IOTA instead of transferring it to the sender. + + +
    public fun request_add_stake_non_entry(wrapper: &mut iota_system::IotaSystemState, stake: coin::Coin<iota::IOTA>, validator_address: address, ctx: &mut tx_context::TxContext): staking_pool::StakedIota
    +
    + + + +
    +Implementation + + +
    public fun request_add_stake_non_entry(
    +    wrapper: &mut IotaSystemState,
    +    stake: Coin<IOTA>,
    +    validator_address: address,
    +    ctx: &mut TxContext,
    +): StakedIota {
    +    let self = load_system_state_mut(wrapper);
    +    self.request_add_stake(stake, validator_address, ctx)
    +}
    +
    + + + +
    + + + +## Function `request_add_stake_mul_coin` + +Add stake to a validator's staking pool using multiple coins. + + +
    public entry fun request_add_stake_mul_coin(wrapper: &mut iota_system::IotaSystemState, stakes: vector<coin::Coin<iota::IOTA>>, stake_amount: option::Option<u64>, validator_address: address, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun request_add_stake_mul_coin(
    +    wrapper: &mut IotaSystemState,
    +    stakes: vector<Coin<IOTA>>,
    +    stake_amount: option::Option<u64>,
    +    validator_address: address,
    +    ctx: &mut TxContext,
    +) {
    +    let self = load_system_state_mut(wrapper);
    +    let staked_iota = self.request_add_stake_mul_coin(stakes, stake_amount, validator_address, ctx);
    +    transfer::public_transfer(staked_iota, ctx.sender());
    +}
    +
    + + + +
    + + + +## Function `request_withdraw_stake` + +Withdraw stake from a validator's staking pool. + + +
    public entry fun request_withdraw_stake(wrapper: &mut iota_system::IotaSystemState, staked_iota: staking_pool::StakedIota, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun request_withdraw_stake(
    +    wrapper: &mut IotaSystemState,
    +    staked_iota: StakedIota,
    +    ctx: &mut TxContext,
    +) {
    +    let withdrawn_stake = request_withdraw_stake_non_entry(wrapper, staked_iota, ctx);
    +    transfer::public_transfer(withdrawn_stake.into_coin(ctx), ctx.sender());
    +}
    +
    + + + +
    + + + +## Function `request_withdraw_stake_non_entry` + +Non-entry version of request_withdraw_stake that returns the withdrawn IOTA instead of transferring it to the sender. + + +
    public fun request_withdraw_stake_non_entry(wrapper: &mut iota_system::IotaSystemState, staked_iota: staking_pool::StakedIota, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
    +
    + + + +
    +Implementation + + +
    public fun request_withdraw_stake_non_entry(
    +    wrapper: &mut IotaSystemState,
    +    staked_iota: StakedIota,
    +    ctx: &mut TxContext,
    +) : Balance<IOTA> {
    +    let self = load_system_state_mut(wrapper);
    +    self.request_withdraw_stake(staked_iota, ctx)
    +}
    +
    + + + +
    + + + +## Function `report_validator` + +Report a validator as a bad or non-performant actor in the system. +Succeeds if all the following are satisfied: +1. both the reporter in cap and the input reportee_addr are active validators. +2. reporter and reportee not the same address. +3. the cap object is still valid. +This function is idempotent. + + +
    public entry fun report_validator(wrapper: &mut iota_system::IotaSystemState, cap: &validator_cap::UnverifiedValidatorOperationCap, reportee_addr: address)
    +
    + + + +
    +Implementation + + +
    public entry fun report_validator(
    +    wrapper: &mut IotaSystemState,
    +    cap: &UnverifiedValidatorOperationCap,
    +    reportee_addr: address,
    +) {
    +    let self = load_system_state_mut(wrapper);
    +    self.report_validator(cap, reportee_addr)
    +}
    +
    + + + +
    + + + +## Function `undo_report_validator` + +Undo a report_validator action. Aborts if +1. the reportee is not a currently active validator or +2. the sender has not previously reported the reportee_addr, or +3. the cap is not valid + + +
    public entry fun undo_report_validator(wrapper: &mut iota_system::IotaSystemState, cap: &validator_cap::UnverifiedValidatorOperationCap, reportee_addr: address)
    +
    + + + +
    +Implementation + + +
    public entry fun undo_report_validator(
    +    wrapper: &mut IotaSystemState,
    +    cap: &UnverifiedValidatorOperationCap,
    +    reportee_addr: address,
    +) {
    +    let self = load_system_state_mut(wrapper);
    +    self.undo_report_validator(cap, reportee_addr)
    +}
    +
    + + + +
    + + + +## Function `rotate_operation_cap` + +Create a new UnverifiedValidatorOperationCap, transfer it to the +validator and registers it. The original object is thus revoked. + + +
    public entry fun rotate_operation_cap(self: &mut iota_system::IotaSystemState, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun rotate_operation_cap(
    +    self: &mut IotaSystemState,
    +    ctx: &mut TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.rotate_operation_cap(ctx)
    +}
    +
    + + + +
    + + + +## Function `update_validator_name` + +Update a validator's name. + + +
    public entry fun update_validator_name(self: &mut iota_system::IotaSystemState, name: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_validator_name(
    +    self: &mut IotaSystemState,
    +    name: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_validator_name(name, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_validator_description` + +Update a validator's description + + +
    public entry fun update_validator_description(self: &mut iota_system::IotaSystemState, description: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_validator_description(
    +    self: &mut IotaSystemState,
    +    description: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_validator_description(description, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_validator_image_url` + +Update a validator's image url + + +
    public entry fun update_validator_image_url(self: &mut iota_system::IotaSystemState, image_url: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_validator_image_url(
    +    self: &mut IotaSystemState,
    +    image_url: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_validator_image_url(image_url, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_validator_project_url` + +Update a validator's project url + + +
    public entry fun update_validator_project_url(self: &mut iota_system::IotaSystemState, project_url: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_validator_project_url(
    +    self: &mut IotaSystemState,
    +    project_url: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_validator_project_url(project_url, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_validator_next_epoch_network_address` + +Update a validator's network address. +The change will only take effects starting from the next epoch. + + +
    public entry fun update_validator_next_epoch_network_address(self: &mut iota_system::IotaSystemState, network_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_validator_next_epoch_network_address(
    +    self: &mut IotaSystemState,
    +    network_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_validator_next_epoch_network_address(network_address, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_candidate_validator_network_address` + +Update candidate validator's network address. + + +
    public entry fun update_candidate_validator_network_address(self: &mut iota_system::IotaSystemState, network_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_candidate_validator_network_address(
    +    self: &mut IotaSystemState,
    +    network_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_candidate_validator_network_address(network_address, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_validator_next_epoch_p2p_address` + +Update a validator's p2p address. +The change will only take effects starting from the next epoch. + + +
    public entry fun update_validator_next_epoch_p2p_address(self: &mut iota_system::IotaSystemState, p2p_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_validator_next_epoch_p2p_address(
    +    self: &mut IotaSystemState,
    +    p2p_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_validator_next_epoch_p2p_address(p2p_address, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_candidate_validator_p2p_address` + +Update candidate validator's p2p address. + + +
    public entry fun update_candidate_validator_p2p_address(self: &mut iota_system::IotaSystemState, p2p_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_candidate_validator_p2p_address(
    +    self: &mut IotaSystemState,
    +    p2p_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_candidate_validator_p2p_address(p2p_address, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_validator_next_epoch_primary_address` + +Update a validator's narwhal primary address. +The change will only take effects starting from the next epoch. + + +
    public entry fun update_validator_next_epoch_primary_address(self: &mut iota_system::IotaSystemState, primary_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_validator_next_epoch_primary_address(
    +    self: &mut IotaSystemState,
    +    primary_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_validator_next_epoch_primary_address(primary_address, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_candidate_validator_primary_address` + +Update candidate validator's narwhal primary address. + + +
    public entry fun update_candidate_validator_primary_address(self: &mut iota_system::IotaSystemState, primary_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_candidate_validator_primary_address(
    +    self: &mut IotaSystemState,
    +    primary_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_candidate_validator_primary_address(primary_address, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_validator_next_epoch_worker_address` + +Update a validator's narwhal worker address. +The change will only take effects starting from the next epoch. + + +
    public entry fun update_validator_next_epoch_worker_address(self: &mut iota_system::IotaSystemState, worker_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_validator_next_epoch_worker_address(
    +    self: &mut IotaSystemState,
    +    worker_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_validator_next_epoch_worker_address(worker_address, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_candidate_validator_worker_address` + +Update candidate validator's narwhal worker address. + + +
    public entry fun update_candidate_validator_worker_address(self: &mut iota_system::IotaSystemState, worker_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_candidate_validator_worker_address(
    +    self: &mut IotaSystemState,
    +    worker_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_candidate_validator_worker_address(worker_address, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_validator_next_epoch_protocol_pubkey` + +Update a validator's public key of protocol key and proof of possession. +The change will only take effects starting from the next epoch. + + +
    public entry fun update_validator_next_epoch_protocol_pubkey(self: &mut iota_system::IotaSystemState, protocol_pubkey: vector<u8>, proof_of_possession: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_validator_next_epoch_protocol_pubkey(
    +    self: &mut IotaSystemState,
    +    protocol_pubkey: vector<u8>,
    +    proof_of_possession: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_validator_next_epoch_protocol_pubkey(protocol_pubkey, proof_of_possession, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_candidate_validator_protocol_pubkey` + +Update candidate validator's public key of protocol key and proof of possession. + + +
    public entry fun update_candidate_validator_protocol_pubkey(self: &mut iota_system::IotaSystemState, protocol_pubkey: vector<u8>, proof_of_possession: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_candidate_validator_protocol_pubkey(
    +    self: &mut IotaSystemState,
    +    protocol_pubkey: vector<u8>,
    +    proof_of_possession: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_candidate_validator_protocol_pubkey(protocol_pubkey, proof_of_possession, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_validator_next_epoch_worker_pubkey` + +Update a validator's public key of worker key. +The change will only take effects starting from the next epoch. + + +
    public entry fun update_validator_next_epoch_worker_pubkey(self: &mut iota_system::IotaSystemState, worker_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_validator_next_epoch_worker_pubkey(
    +    self: &mut IotaSystemState,
    +    worker_pubkey: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_validator_next_epoch_worker_pubkey(worker_pubkey, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_candidate_validator_worker_pubkey` + +Update candidate validator's public key of worker key. + + +
    public entry fun update_candidate_validator_worker_pubkey(self: &mut iota_system::IotaSystemState, worker_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_candidate_validator_worker_pubkey(
    +    self: &mut IotaSystemState,
    +    worker_pubkey: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_candidate_validator_worker_pubkey(worker_pubkey, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_validator_next_epoch_network_pubkey` + +Update a validator's public key of network key. +The change will only take effects starting from the next epoch. + + +
    public entry fun update_validator_next_epoch_network_pubkey(self: &mut iota_system::IotaSystemState, network_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_validator_next_epoch_network_pubkey(
    +    self: &mut IotaSystemState,
    +    network_pubkey: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_validator_next_epoch_network_pubkey(network_pubkey, ctx)
    +}
    +
    + + + +
    + + + +## Function `update_candidate_validator_network_pubkey` + +Update candidate validator's public key of network key. + + +
    public entry fun update_candidate_validator_network_pubkey(self: &mut iota_system::IotaSystemState, network_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun update_candidate_validator_network_pubkey(
    +    self: &mut IotaSystemState,
    +    network_pubkey: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let self = load_system_state_mut(self);
    +    self.update_candidate_validator_network_pubkey(network_pubkey, ctx)
    +}
    +
    + + + +
    + + + +## Function `pool_exchange_rates` + +Getter of the pool token exchange rate of a staking pool. Works for both active and inactive pools. + + +
    public fun pool_exchange_rates(wrapper: &mut iota_system::IotaSystemState, pool_id: &object::ID): &table::Table<u64, staking_pool::PoolTokenExchangeRate>
    +
    + + + +
    +Implementation + + +
    public fun pool_exchange_rates(
    +    wrapper: &mut IotaSystemState,
    +    pool_id: &ID
    +): &Table<u64, PoolTokenExchangeRate>  {
    +    let self = load_system_state_mut(wrapper);
    +    self.pool_exchange_rates(pool_id)
    +}
    +
    + + + +
    + + + +## Function `active_validator_addresses` + +Getter returning addresses of the currently active validators. + + +
    public fun active_validator_addresses(wrapper: &mut iota_system::IotaSystemState): vector<address>
    +
    + + + +
    +Implementation + + +
    public fun active_validator_addresses(wrapper: &mut IotaSystemState): vector<address> {
    +    let self = load_system_state(wrapper);
    +    self.active_validator_addresses()
    +}
    +
    + + + +
    + + + +## Function `advance_epoch` + +This function should be called at the end of an epoch, and advances the system to the next epoch. +It does the following things: +1. Add storage charge to the storage fund. +2. Burn the storage rebates from the storage fund. These are already refunded to transaction sender's +gas coins. +3. Distribute computation charge to validator stake. +4. Update all validators. + + +
    fun advance_epoch(storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, wrapper: &mut iota_system::IotaSystemState, new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
    +
    + + + +
    +Implementation + + +
    fun advance_epoch(
    +    storage_reward: Balance<IOTA>,
    +    computation_reward: Balance<IOTA>,
    +    wrapper: &mut IotaSystemState,
    +    new_epoch: u64,
    +    next_protocol_version: u64,
    +    storage_rebate: u64,
    +    non_refundable_storage_fee: u64,
    +    storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested
    +                                     // into storage fund, in basis point.
    +    reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps.
    +    epoch_start_timestamp_ms: u64, // Timestamp of the epoch start
    +    ctx: &mut TxContext,
    +) : Balance<IOTA> {
    +    let self = load_system_state_mut(wrapper);
    +    // Validator will make a special system call with sender set as 0x0.
    +    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    +    let storage_rebate = self.advance_epoch(
    +        new_epoch,
    +        next_protocol_version,
    +        storage_reward,
    +        computation_reward,
    +        storage_rebate,
    +        non_refundable_storage_fee,
    +        storage_fund_reinvest_rate,
    +        reward_slashing_rate,
    +        epoch_start_timestamp_ms,
    +        ctx,
    +    );
    +
    +    storage_rebate
    +}
    +
    + + + +
    + + + +## Function `load_system_state` + + + +
    fun load_system_state(self: &mut iota_system::IotaSystemState): &iota_system_state_inner::IotaSystemStateInnerV2
    +
    + + + +
    +Implementation + + +
    fun load_system_state(self: &mut IotaSystemState): &IotaSystemStateInnerV2 {
    +    load_inner_maybe_upgrade(self)
    +}
    +
    + + + +
    + + + +## Function `load_system_state_mut` + + + +
    fun load_system_state_mut(self: &mut iota_system::IotaSystemState): &mut iota_system_state_inner::IotaSystemStateInnerV2
    +
    + + + +
    +Implementation + + +
    fun load_system_state_mut(self: &mut IotaSystemState): &mut IotaSystemStateInnerV2 {
    +    load_inner_maybe_upgrade(self)
    +}
    +
    + + + +
    + + + +## Function `load_inner_maybe_upgrade` + + + +
    fun load_inner_maybe_upgrade(self: &mut iota_system::IotaSystemState): &mut iota_system_state_inner::IotaSystemStateInnerV2
    +
    + + + +
    +Implementation + + +
    fun load_inner_maybe_upgrade(self: &mut IotaSystemState): &mut IotaSystemStateInnerV2 {
    +    if (self.version == 1) {
    +      let v1: IotaSystemStateInner = dynamic_field::remove(&mut self.id, self.version);
    +      let v2 = v1.v1_to_v2();
    +      self.version = 2;
    +      dynamic_field::add(&mut self.id, self.version, v2);
    +    };
    +
    +    let inner: &mut IotaSystemStateInnerV2 = dynamic_field::borrow_mut(
    +        &mut self.id,
    +        self.version
    +    );
    +    assert!(inner.system_state_version() == self.version, EWrongInnerVersion);
    +    inner
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md new file mode 100644 index 00000000000..457f001f402 --- /dev/null +++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md @@ -0,0 +1,2597 @@ +--- +title: Module `0x3::iota_system_state_inner` +--- + + + +- [Struct `SystemParameters`](#0x3_iota_system_state_inner_SystemParameters) +- [Struct `SystemParametersV2`](#0x3_iota_system_state_inner_SystemParametersV2) +- [Struct `IotaSystemStateInner`](#0x3_iota_system_state_inner_IotaSystemStateInner) +- [Struct `IotaSystemStateInnerV2`](#0x3_iota_system_state_inner_IotaSystemStateInnerV2) +- [Struct `SystemEpochInfoEvent`](#0x3_iota_system_state_inner_SystemEpochInfoEvent) +- [Constants](#@Constants_0) +- [Function `create`](#0x3_iota_system_state_inner_create) +- [Function `create_system_parameters`](#0x3_iota_system_state_inner_create_system_parameters) +- [Function `v1_to_v2`](#0x3_iota_system_state_inner_v1_to_v2) +- [Function `request_add_validator_candidate`](#0x3_iota_system_state_inner_request_add_validator_candidate) +- [Function `request_remove_validator_candidate`](#0x3_iota_system_state_inner_request_remove_validator_candidate) +- [Function `request_add_validator`](#0x3_iota_system_state_inner_request_add_validator) +- [Function `request_remove_validator`](#0x3_iota_system_state_inner_request_remove_validator) +- [Function `request_set_gas_price`](#0x3_iota_system_state_inner_request_set_gas_price) +- [Function `set_candidate_validator_gas_price`](#0x3_iota_system_state_inner_set_candidate_validator_gas_price) +- [Function `request_set_commission_rate`](#0x3_iota_system_state_inner_request_set_commission_rate) +- [Function `set_candidate_validator_commission_rate`](#0x3_iota_system_state_inner_set_candidate_validator_commission_rate) +- [Function `request_add_stake`](#0x3_iota_system_state_inner_request_add_stake) +- [Function `request_add_stake_mul_coin`](#0x3_iota_system_state_inner_request_add_stake_mul_coin) +- [Function `request_withdraw_stake`](#0x3_iota_system_state_inner_request_withdraw_stake) +- [Function `report_validator`](#0x3_iota_system_state_inner_report_validator) +- [Function `undo_report_validator`](#0x3_iota_system_state_inner_undo_report_validator) +- [Function `report_validator_impl`](#0x3_iota_system_state_inner_report_validator_impl) +- [Function `undo_report_validator_impl`](#0x3_iota_system_state_inner_undo_report_validator_impl) +- [Function `rotate_operation_cap`](#0x3_iota_system_state_inner_rotate_operation_cap) +- [Function `update_validator_name`](#0x3_iota_system_state_inner_update_validator_name) +- [Function `update_validator_description`](#0x3_iota_system_state_inner_update_validator_description) +- [Function `update_validator_image_url`](#0x3_iota_system_state_inner_update_validator_image_url) +- [Function `update_validator_project_url`](#0x3_iota_system_state_inner_update_validator_project_url) +- [Function `update_validator_next_epoch_network_address`](#0x3_iota_system_state_inner_update_validator_next_epoch_network_address) +- [Function `update_candidate_validator_network_address`](#0x3_iota_system_state_inner_update_candidate_validator_network_address) +- [Function `update_validator_next_epoch_p2p_address`](#0x3_iota_system_state_inner_update_validator_next_epoch_p2p_address) +- [Function `update_candidate_validator_p2p_address`](#0x3_iota_system_state_inner_update_candidate_validator_p2p_address) +- [Function `update_validator_next_epoch_primary_address`](#0x3_iota_system_state_inner_update_validator_next_epoch_primary_address) +- [Function `update_candidate_validator_primary_address`](#0x3_iota_system_state_inner_update_candidate_validator_primary_address) +- [Function `update_validator_next_epoch_worker_address`](#0x3_iota_system_state_inner_update_validator_next_epoch_worker_address) +- [Function `update_candidate_validator_worker_address`](#0x3_iota_system_state_inner_update_candidate_validator_worker_address) +- [Function `update_validator_next_epoch_protocol_pubkey`](#0x3_iota_system_state_inner_update_validator_next_epoch_protocol_pubkey) +- [Function `update_candidate_validator_protocol_pubkey`](#0x3_iota_system_state_inner_update_candidate_validator_protocol_pubkey) +- [Function `update_validator_next_epoch_worker_pubkey`](#0x3_iota_system_state_inner_update_validator_next_epoch_worker_pubkey) +- [Function `update_candidate_validator_worker_pubkey`](#0x3_iota_system_state_inner_update_candidate_validator_worker_pubkey) +- [Function `update_validator_next_epoch_network_pubkey`](#0x3_iota_system_state_inner_update_validator_next_epoch_network_pubkey) +- [Function `update_candidate_validator_network_pubkey`](#0x3_iota_system_state_inner_update_candidate_validator_network_pubkey) +- [Function `advance_epoch`](#0x3_iota_system_state_inner_advance_epoch) +- [Function `epoch`](#0x3_iota_system_state_inner_epoch) +- [Function `protocol_version`](#0x3_iota_system_state_inner_protocol_version) +- [Function `system_state_version`](#0x3_iota_system_state_inner_system_state_version) +- [Function `genesis_system_state_version`](#0x3_iota_system_state_inner_genesis_system_state_version) +- [Function `epoch_start_timestamp_ms`](#0x3_iota_system_state_inner_epoch_start_timestamp_ms) +- [Function `validator_stake_amount`](#0x3_iota_system_state_inner_validator_stake_amount) +- [Function `validator_staking_pool_id`](#0x3_iota_system_state_inner_validator_staking_pool_id) +- [Function `validator_staking_pool_mappings`](#0x3_iota_system_state_inner_validator_staking_pool_mappings) +- [Function `get_reporters_of`](#0x3_iota_system_state_inner_get_reporters_of) +- [Function `get_storage_fund_total_balance`](#0x3_iota_system_state_inner_get_storage_fund_total_balance) +- [Function `get_storage_fund_object_rebates`](#0x3_iota_system_state_inner_get_storage_fund_object_rebates) +- [Function `pool_exchange_rates`](#0x3_iota_system_state_inner_pool_exchange_rates) +- [Function `active_validator_addresses`](#0x3_iota_system_state_inner_active_validator_addresses) +- [Function `extract_coin_balance`](#0x3_iota_system_state_inner_extract_coin_balance) + + +
    use 0x1::option;
    +use 0x2::bag;
    +use 0x2::balance;
    +use 0x2::coin;
    +use 0x2::event;
    +use 0x2::iota;
    +use 0x2::object;
    +use 0x2::pay;
    +use 0x2::table;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +use 0x2::vec_map;
    +use 0x2::vec_set;
    +use 0x3::stake_subsidy;
    +use 0x3::staking_pool;
    +use 0x3::storage_fund;
    +use 0x3::validator;
    +use 0x3::validator_cap;
    +use 0x3::validator_set;
    +
    + + + + + +## Struct `SystemParameters` + +A list of system config parameters. + + +
    struct SystemParameters has store
    +
    + + + +
    +Fields + + +
    +
    +epoch_duration_ms: u64 +
    +
    + The duration of an epoch, in milliseconds. +
    +
    +stake_subsidy_start_epoch: u64 +
    +
    + The starting epoch in which stake subsidies start being paid out +
    +
    +max_validator_count: u64 +
    +
    + Maximum number of active validators at any moment. + We do not allow the number of validators in any epoch to go above this. +
    +
    +min_validator_joining_stake: u64 +
    +
    + Lower-bound on the amount of stake required to become a validator. +
    +
    +validator_low_stake_threshold: u64 +
    +
    + Validators with stake amount below validator_low_stake_threshold are considered to + have low stake and will be escorted out of the validator set after being below this + threshold for more than validator_low_stake_grace_period number of epochs. +
    +
    +validator_very_low_stake_threshold: u64 +
    +
    + Validators with stake below validator_very_low_stake_threshold will be removed + immediately at epoch change, no grace period. +
    +
    +validator_low_stake_grace_period: u64 +
    +
    + A validator can have stake below validator_low_stake_threshold + for this many epochs before being kicked out. +
    +
    +extra_fields: bag::Bag +
    +
    + Any extra fields that's not defined statically. +
    +
    + + +
    + + + +## Struct `SystemParametersV2` + +Added min_validator_count. + + +
    struct SystemParametersV2 has store
    +
    + + + +
    +Fields + + +
    +
    +epoch_duration_ms: u64 +
    +
    + The duration of an epoch, in milliseconds. +
    +
    +stake_subsidy_start_epoch: u64 +
    +
    + The starting epoch in which stake subsidies start being paid out +
    +
    +min_validator_count: u64 +
    +
    + Minimum number of active validators at any moment. +
    +
    +max_validator_count: u64 +
    +
    + Maximum number of active validators at any moment. + We do not allow the number of validators in any epoch to go above this. +
    +
    +min_validator_joining_stake: u64 +
    +
    + Lower-bound on the amount of stake required to become a validator. +
    +
    +validator_low_stake_threshold: u64 +
    +
    + Validators with stake amount below validator_low_stake_threshold are considered to + have low stake and will be escorted out of the validator set after being below this + threshold for more than validator_low_stake_grace_period number of epochs. +
    +
    +validator_very_low_stake_threshold: u64 +
    +
    + Validators with stake below validator_very_low_stake_threshold will be removed + immediately at epoch change, no grace period. +
    +
    +validator_low_stake_grace_period: u64 +
    +
    + A validator can have stake below validator_low_stake_threshold + for this many epochs before being kicked out. +
    +
    +extra_fields: bag::Bag +
    +
    + Any extra fields that's not defined statically. +
    +
    + + +
    + + + +## Struct `IotaSystemStateInner` + +The top-level object containing all information of the Iota system. + + +
    struct IotaSystemStateInner has store
    +
    + + + +
    +Fields + + +
    +
    +epoch: u64 +
    +
    + The current epoch ID, starting from 0. +
    +
    +protocol_version: u64 +
    +
    + The current protocol version, starting from 1. +
    +
    +system_state_version: u64 +
    +
    + The current version of the system state data structure type. + This is always the same as IotaSystemState.version. Keeping a copy here so that + we know what version it is by inspecting IotaSystemStateInner as well. +
    +
    +validators: validator_set::ValidatorSet +
    +
    + Contains all information about the validators. +
    +
    +storage_fund: storage_fund::StorageFund +
    +
    + The storage fund. +
    +
    +parameters: iota_system_state_inner::SystemParameters +
    +
    + A list of system config parameters. +
    +
    +reference_gas_price: u64 +
    +
    + The reference gas price for the current epoch. +
    +
    +validator_report_records: vec_map::VecMap<address, vec_set::VecSet<address>> +
    +
    + A map storing the records of validator reporting each other. + There is an entry in the map for each validator that has been reported + at least once. The entry VecSet contains all the validators that reported + them. If a validator has never been reported they don't have an entry in this map. + This map persists across epoch: a peer continues being in a reported state until the + reporter doesn't explicitly remove their report. + Note that in case we want to support validator address change in future, + the reports should be based on validator ids +
    +
    +stake_subsidy: stake_subsidy::StakeSubsidy +
    +
    + Schedule of stake subsidies given out each epoch. +
    +
    +safe_mode: bool +
    +
    + Whether the system is running in a downgraded safe mode due to a non-recoverable bug. + This is set whenever we failed to execute advance_epoch, and ended up executing advance_epoch_safe_mode. + It can be reset once we are able to successfully execute advance_epoch. + The rest of the fields starting with safe_mode_ are accmulated during safe mode + when advance_epoch_safe_mode is executed. They will eventually be processed once we + are out of safe mode. +
    +
    +safe_mode_storage_rewards: balance::Balance<iota::IOTA> +
    +
    + +
    +
    +safe_mode_computation_rewards: balance::Balance<iota::IOTA> +
    +
    + +
    +
    +safe_mode_storage_rebates: u64 +
    +
    + +
    +
    +safe_mode_non_refundable_storage_fee: u64 +
    +
    + +
    +
    +epoch_start_timestamp_ms: u64 +
    +
    + Unix timestamp of the current epoch start +
    +
    +extra_fields: bag::Bag +
    +
    + Any extra fields that's not defined statically. +
    +
    + + +
    + + + +## Struct `IotaSystemStateInnerV2` + +Uses SystemParametersV2 as the parameters. + + +
    struct IotaSystemStateInnerV2 has store
    +
    + + + +
    +Fields + + +
    +
    +epoch: u64 +
    +
    + The current epoch ID, starting from 0. +
    +
    +protocol_version: u64 +
    +
    + The current protocol version, starting from 1. +
    +
    +system_state_version: u64 +
    +
    + The current version of the system state data structure type. + This is always the same as IotaSystemState.version. Keeping a copy here so that + we know what version it is by inspecting IotaSystemStateInner as well. +
    +
    +validators: validator_set::ValidatorSet +
    +
    + Contains all information about the validators. +
    +
    +storage_fund: storage_fund::StorageFund +
    +
    + The storage fund. +
    +
    +parameters: iota_system_state_inner::SystemParametersV2 +
    +
    + A list of system config parameters. +
    +
    +reference_gas_price: u64 +
    +
    + The reference gas price for the current epoch. +
    +
    +validator_report_records: vec_map::VecMap<address, vec_set::VecSet<address>> +
    +
    + A map storing the records of validator reporting each other. + There is an entry in the map for each validator that has been reported + at least once. The entry VecSet contains all the validators that reported + them. If a validator has never been reported they don't have an entry in this map. + This map persists across epoch: a peer continues being in a reported state until the + reporter doesn't explicitly remove their report. + Note that in case we want to support validator address change in future, + the reports should be based on validator ids +
    +
    +stake_subsidy: stake_subsidy::StakeSubsidy +
    +
    + Schedule of stake subsidies given out each epoch. +
    +
    +safe_mode: bool +
    +
    + Whether the system is running in a downgraded safe mode due to a non-recoverable bug. + This is set whenever we failed to execute advance_epoch, and ended up executing advance_epoch_safe_mode. + It can be reset once we are able to successfully execute advance_epoch. + The rest of the fields starting with safe_mode_ are accmulated during safe mode + when advance_epoch_safe_mode is executed. They will eventually be processed once we + are out of safe mode. +
    +
    +safe_mode_storage_rewards: balance::Balance<iota::IOTA> +
    +
    + +
    +
    +safe_mode_computation_rewards: balance::Balance<iota::IOTA> +
    +
    + +
    +
    +safe_mode_storage_rebates: u64 +
    +
    + +
    +
    +safe_mode_non_refundable_storage_fee: u64 +
    +
    + +
    +
    +epoch_start_timestamp_ms: u64 +
    +
    + Unix timestamp of the current epoch start +
    +
    +extra_fields: bag::Bag +
    +
    + Any extra fields that's not defined statically. +
    +
    + + +
    + + + +## Struct `SystemEpochInfoEvent` + +Event containing system-level epoch information, emitted during +the epoch advancement transaction. + + +
    struct SystemEpochInfoEvent has copy, drop
    +
    + + + +
    +Fields + + +
    +
    +epoch: u64 +
    +
    + +
    +
    +protocol_version: u64 +
    +
    + +
    +
    +reference_gas_price: u64 +
    +
    + +
    +
    +total_stake: u64 +
    +
    + +
    +
    +storage_fund_reinvestment: u64 +
    +
    + +
    +
    +storage_charge: u64 +
    +
    + +
    +
    +storage_rebate: u64 +
    +
    + +
    +
    +storage_fund_balance: u64 +
    +
    + +
    +
    +stake_subsidy_amount: u64 +
    +
    + +
    +
    +total_gas_fees: u64 +
    +
    + +
    +
    +total_stake_rewards_distributed: u64 +
    +
    + +
    +
    +leftover_storage_fund_inflow: u64 +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + + + +
    const ENotSystemAddress: u64 = 2;
    +
    + + + + + + + +
    const ACTIVE_OR_PENDING_VALIDATOR: u8 = 2;
    +
    + + + + + + + +
    const ACTIVE_VALIDATOR_ONLY: u8 = 1;
    +
    + + + + + + + +
    const ANY_VALIDATOR: u8 = 3;
    +
    + + + + + + + +
    const BASIS_POINT_DENOMINATOR: u128 = 10000;
    +
    + + + + + + + +
    const EAdvancedToWrongEpoch: u64 = 8;
    +
    + + + + + + + +
    const EBpsTooLarge: u64 = 5;
    +
    + + + + + + + +
    const ECannotReportOneself: u64 = 3;
    +
    + + + + + + + +
    const ELimitExceeded: u64 = 1;
    +
    + + + + + + + +
    const ENotValidator: u64 = 0;
    +
    + + + + + + + +
    const EReportRecordNotFound: u64 = 4;
    +
    + + + + + + + +
    const ESafeModeGasNotProcessed: u64 = 7;
    +
    + + + + + + + +
    const EStakeWithdrawBeforeActivation: u64 = 6;
    +
    + + + + + + + +
    const SYSTEM_STATE_VERSION_V1: u64 = 1;
    +
    + + + + + +## Function `create` + +Create a new IotaSystemState object and make it shared. +This function will be called only once in genesis. + + +
    public(friend) fun create(validators: vector<validator::Validator>, initial_storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext): iota_system_state_inner::IotaSystemStateInner
    +
    + + + +
    +Implementation + + +
    public(package) fun create(
    +    validators: vector<Validator>,
    +    initial_storage_fund: Balance<IOTA>,
    +    protocol_version: u64,
    +    epoch_start_timestamp_ms: u64,
    +    parameters: SystemParameters,
    +    stake_subsidy: StakeSubsidy,
    +    ctx: &mut TxContext,
    +): IotaSystemStateInner {
    +    let validators = validator_set::new(validators, ctx);
    +    let reference_gas_price = validators.derive_reference_gas_price();
    +    // This type is fixed as it's created at genesis. It should not be updated during type upgrade.
    +    let system_state = IotaSystemStateInner {
    +        epoch: 0,
    +        protocol_version,
    +        system_state_version: genesis_system_state_version(),
    +        validators,
    +        storage_fund: storage_fund::new(initial_storage_fund),
    +        parameters,
    +        reference_gas_price,
    +        validator_report_records: vec_map::empty(),
    +        stake_subsidy,
    +        safe_mode: false,
    +        safe_mode_storage_rewards: balance::zero(),
    +        safe_mode_computation_rewards: balance::zero(),
    +        safe_mode_storage_rebates: 0,
    +        safe_mode_non_refundable_storage_fee: 0,
    +        epoch_start_timestamp_ms,
    +        extra_fields: bag::new(ctx),
    +    };
    +    system_state
    +}
    +
    + + + +
    + + + +## Function `create_system_parameters` + + + +
    public(friend) fun create_system_parameters(epoch_duration_ms: u64, stake_subsidy_start_epoch: u64, max_validator_count: u64, min_validator_joining_stake: u64, validator_low_stake_threshold: u64, validator_very_low_stake_threshold: u64, validator_low_stake_grace_period: u64, ctx: &mut tx_context::TxContext): iota_system_state_inner::SystemParameters
    +
    + + + +
    +Implementation + + +
    public(package) fun create_system_parameters(
    +    epoch_duration_ms: u64,
    +    stake_subsidy_start_epoch: u64,
    +
    +    // Validator committee parameters
    +    max_validator_count: u64,
    +    min_validator_joining_stake: u64,
    +    validator_low_stake_threshold: u64,
    +    validator_very_low_stake_threshold: u64,
    +    validator_low_stake_grace_period: u64,
    +    ctx: &mut TxContext,
    +): SystemParameters {
    +    SystemParameters {
    +        epoch_duration_ms,
    +        stake_subsidy_start_epoch,
    +        max_validator_count,
    +        min_validator_joining_stake,
    +        validator_low_stake_threshold,
    +        validator_very_low_stake_threshold,
    +        validator_low_stake_grace_period,
    +        extra_fields: bag::new(ctx),
    +    }
    +}
    +
    + + + +
    + + + +## Function `v1_to_v2` + + + +
    public(friend) fun v1_to_v2(self: iota_system_state_inner::IotaSystemStateInner): iota_system_state_inner::IotaSystemStateInnerV2
    +
    + + + +
    +Implementation + + +
    public(package) fun v1_to_v2(self: IotaSystemStateInner): IotaSystemStateInnerV2 {
    +    let IotaSystemStateInner {
    +        epoch,
    +        protocol_version,
    +        system_state_version: _,
    +        validators,
    +        storage_fund,
    +        parameters,
    +        reference_gas_price,
    +        validator_report_records,
    +        stake_subsidy,
    +        safe_mode,
    +        safe_mode_storage_rewards,
    +        safe_mode_computation_rewards,
    +        safe_mode_storage_rebates,
    +        safe_mode_non_refundable_storage_fee,
    +        epoch_start_timestamp_ms,
    +        extra_fields: state_extra_fields,
    +    } = self;
    +    let SystemParameters {
    +        epoch_duration_ms,
    +        stake_subsidy_start_epoch,
    +        max_validator_count,
    +        min_validator_joining_stake,
    +        validator_low_stake_threshold,
    +        validator_very_low_stake_threshold,
    +        validator_low_stake_grace_period,
    +        extra_fields: param_extra_fields,
    +    } = parameters;
    +    IotaSystemStateInnerV2 {
    +        epoch,
    +        protocol_version,
    +        system_state_version: 2,
    +        validators,
    +        storage_fund,
    +        parameters: SystemParametersV2 {
    +            epoch_duration_ms,
    +            stake_subsidy_start_epoch,
    +            min_validator_count: 4,
    +            max_validator_count,
    +            min_validator_joining_stake,
    +            validator_low_stake_threshold,
    +            validator_very_low_stake_threshold,
    +            validator_low_stake_grace_period,
    +            extra_fields: param_extra_fields,
    +        },
    +        reference_gas_price,
    +        validator_report_records,
    +        stake_subsidy,
    +        safe_mode,
    +        safe_mode_storage_rewards,
    +        safe_mode_computation_rewards,
    +        safe_mode_storage_rebates,
    +        safe_mode_non_refundable_storage_fee,
    +        epoch_start_timestamp_ms,
    +        extra_fields: state_extra_fields
    +    }
    +}
    +
    + + + +
    + + + +## Function `request_add_validator_candidate` + +Can be called by anyone who wishes to become a validator candidate and starts accuring delegated +stakes in their staking pool. Once they have at least MIN_VALIDATOR_JOINING_STAKE amount of stake they +can call request_add_validator to officially become an active validator at the next epoch. +Aborts if the caller is already a pending or active validator, or a validator candidate. +Note: proof_of_possession MUST be a valid signature using iota_address and protocol_pubkey_bytes. +To produce a valid PoP, run [fn test_proof_of_possession]. + + +
    public(friend) fun request_add_validator_candidate(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, pubkey_bytes: vector<u8>, network_pubkey_bytes: vector<u8>, worker_pubkey_bytes: vector<u8>, proof_of_possession: vector<u8>, name: vector<u8>, description: vector<u8>, image_url: vector<u8>, project_url: vector<u8>, net_address: vector<u8>, p2p_address: vector<u8>, primary_address: vector<u8>, worker_address: vector<u8>, gas_price: u64, commission_rate: u64, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun request_add_validator_candidate(
    +    self: &mut IotaSystemStateInnerV2,
    +    pubkey_bytes: vector<u8>,
    +    network_pubkey_bytes: vector<u8>,
    +    worker_pubkey_bytes: vector<u8>,
    +    proof_of_possession: vector<u8>,
    +    name: vector<u8>,
    +    description: vector<u8>,
    +    image_url: vector<u8>,
    +    project_url: vector<u8>,
    +    net_address: vector<u8>,
    +    p2p_address: vector<u8>,
    +    primary_address: vector<u8>,
    +    worker_address: vector<u8>,
    +    gas_price: u64,
    +    commission_rate: u64,
    +    ctx: &mut TxContext,
    +) {
    +    let validator = validator::new(
    +        ctx.sender(),
    +        pubkey_bytes,
    +        network_pubkey_bytes,
    +        worker_pubkey_bytes,
    +        proof_of_possession,
    +        name,
    +        description,
    +        image_url,
    +        project_url,
    +        net_address,
    +        p2p_address,
    +        primary_address,
    +        worker_address,
    +        gas_price,
    +        commission_rate,
    +        ctx
    +    );
    +
    +    self.validators.request_add_validator_candidate(validator, ctx);
    +}
    +
    + + + +
    + + + +## Function `request_remove_validator_candidate` + +Called by a validator candidate to remove themselves from the candidacy. After this call +their staking pool becomes deactivate. + + +
    public(friend) fun request_remove_validator_candidate(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun request_remove_validator_candidate(
    +    self: &mut IotaSystemStateInnerV2,
    +    ctx: &mut TxContext,
    +) {
    +    self.validators.request_remove_validator_candidate(ctx);
    +}
    +
    + + + +
    + + + +## Function `request_add_validator` + +Called by a validator candidate to add themselves to the active validator set beginning next epoch. +Aborts if the validator is a duplicate with one of the pending or active validators, or if the amount of +stake the validator has doesn't meet the min threshold, or if the number of new validators for the next +epoch has already reached the maximum. + + +
    public(friend) fun request_add_validator(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun request_add_validator(
    +    self: &mut IotaSystemStateInnerV2,
    +    ctx: &TxContext,
    +) {
    +    assert!(
    +        self.validators.next_epoch_validator_count() < self.parameters.max_validator_count,
    +        ELimitExceeded,
    +    );
    +
    +    self.validators.request_add_validator(self.parameters.min_validator_joining_stake, ctx);
    +}
    +
    + + + +
    + + + +## Function `request_remove_validator` + +A validator can call this function to request a removal in the next epoch. +We use the sender of ctx to look up the validator +(i.e. sender must match the iota_address in the validator). +At the end of the epoch, the validator object will be returned to the iota_address +of the validator. + + +
    public(friend) fun request_remove_validator(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun request_remove_validator(
    +    self: &mut IotaSystemStateInnerV2,
    +    ctx: &TxContext,
    +) {
    +    // Only check min validator condition if the current number of validators satisfy the constraint.
    +    // This is so that if we somehow already are in a state where we have less than min validators, it no longer matters
    +    // and is ok to stay so. This is useful for a test setup.
    +    if (self.validators.active_validators().length() >= self.parameters.min_validator_count) {
    +        assert!(
    +            self.validators.next_epoch_validator_count() > self.parameters.min_validator_count,
    +            ELimitExceeded,
    +        );
    +    };
    +
    +    self.validators.request_remove_validator(ctx)
    +}
    +
    + + + +
    + + + +## Function `request_set_gas_price` + +A validator can call this function to submit a new gas price quote, to be +used for the reference gas price calculation at the end of the epoch. + + +
    public(friend) fun request_set_gas_price(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, cap: &validator_cap::UnverifiedValidatorOperationCap, new_gas_price: u64)
    +
    + + + +
    +Implementation + + +
    public(package) fun request_set_gas_price(
    +    self: &mut IotaSystemStateInnerV2,
    +    cap: &UnverifiedValidatorOperationCap,
    +    new_gas_price: u64,
    +) {
    +    // Verify the represented address is an active or pending validator, and the capability is still valid.
    +    let verified_cap = self.validators.verify_cap(cap, ACTIVE_OR_PENDING_VALIDATOR);
    +    let validator = self.validators.get_validator_mut_with_verified_cap(&verified_cap, false /* include_candidate */);
    +
    +    validator.request_set_gas_price(verified_cap, new_gas_price);
    +}
    +
    + + + +
    + + + +## Function `set_candidate_validator_gas_price` + +This function is used to set new gas price for candidate validators + + +
    public(friend) fun set_candidate_validator_gas_price(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, cap: &validator_cap::UnverifiedValidatorOperationCap, new_gas_price: u64)
    +
    + + + +
    +Implementation + + +
    public(package) fun set_candidate_validator_gas_price(
    +    self: &mut IotaSystemStateInnerV2,
    +    cap: &UnverifiedValidatorOperationCap,
    +    new_gas_price: u64,
    +) {
    +    // Verify the represented address is an active or pending validator, and the capability is still valid.
    +    let verified_cap = self.validators.verify_cap(cap, ANY_VALIDATOR);
    +    let candidate = self.validators.get_validator_mut_with_verified_cap(&verified_cap, true /* include_candidate */);
    +    candidate.set_candidate_gas_price(verified_cap, new_gas_price)
    +}
    +
    + + + +
    + + + +## Function `request_set_commission_rate` + +A validator can call this function to set a new commission rate, updated at the end of +the epoch. + + +
    public(friend) fun request_set_commission_rate(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, new_commission_rate: u64, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun request_set_commission_rate(
    +    self: &mut IotaSystemStateInnerV2,
    +    new_commission_rate: u64,
    +    ctx: &TxContext,
    +) {
    +    self.validators.request_set_commission_rate(
    +        new_commission_rate,
    +        ctx
    +    )
    +}
    +
    + + + +
    + + + +## Function `set_candidate_validator_commission_rate` + +This function is used to set new commission rate for candidate validators + + +
    public(friend) fun set_candidate_validator_commission_rate(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, new_commission_rate: u64, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun set_candidate_validator_commission_rate(
    +    self: &mut IotaSystemStateInnerV2,
    +    new_commission_rate: u64,
    +    ctx: &TxContext,
    +) {
    +    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    +    candidate.set_candidate_commission_rate(new_commission_rate)
    +}
    +
    + + + +
    + + + +## Function `request_add_stake` + +Add stake to a validator's staking pool. + + +
    public(friend) fun request_add_stake(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, stake: coin::Coin<iota::IOTA>, validator_address: address, ctx: &mut tx_context::TxContext): staking_pool::StakedIota
    +
    + + + +
    +Implementation + + +
    public(package) fun request_add_stake(
    +    self: &mut IotaSystemStateInnerV2,
    +    stake: Coin<IOTA>,
    +    validator_address: address,
    +    ctx: &mut TxContext,
    +) : StakedIota {
    +    self.validators.request_add_stake(
    +        validator_address,
    +        stake.into_balance(),
    +        ctx,
    +    )
    +}
    +
    + + + +
    + + + +## Function `request_add_stake_mul_coin` + +Add stake to a validator's staking pool using multiple coins. + + +
    public(friend) fun request_add_stake_mul_coin(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, stakes: vector<coin::Coin<iota::IOTA>>, stake_amount: option::Option<u64>, validator_address: address, ctx: &mut tx_context::TxContext): staking_pool::StakedIota
    +
    + + + +
    +Implementation + + +
    public(package) fun request_add_stake_mul_coin(
    +    self: &mut IotaSystemStateInnerV2,
    +    stakes: vector<Coin<IOTA>>,
    +    stake_amount: option::Option<u64>,
    +    validator_address: address,
    +    ctx: &mut TxContext,
    +) : StakedIota {
    +    let balance = extract_coin_balance(stakes, stake_amount, ctx);
    +    self.validators.request_add_stake(validator_address, balance, ctx)
    +}
    +
    + + + +
    + + + +## Function `request_withdraw_stake` + +Withdraw some portion of a stake from a validator's staking pool. + + +
    public(friend) fun request_withdraw_stake(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, staked_iota: staking_pool::StakedIota, ctx: &tx_context::TxContext): balance::Balance<iota::IOTA>
    +
    + + + +
    +Implementation + + +
    public(package) fun request_withdraw_stake(
    +    self: &mut IotaSystemStateInnerV2,
    +    staked_iota: StakedIota,
    +    ctx: &TxContext,
    +) : Balance<IOTA> {
    +    assert!(
    +        stake_activation_epoch(&staked_iota) <= ctx.epoch(),
    +        EStakeWithdrawBeforeActivation
    +    );
    +    self.validators.request_withdraw_stake(staked_iota, ctx)
    +}
    +
    + + + +
    + + + +## Function `report_validator` + +Report a validator as a bad or non-performant actor in the system. +Succeeds if all the following are satisfied: +1. both the reporter in cap and the input reportee_addr are active validators. +2. reporter and reportee not the same address. +3. the cap object is still valid. +This function is idempotent. + + +
    public(friend) fun report_validator(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, cap: &validator_cap::UnverifiedValidatorOperationCap, reportee_addr: address)
    +
    + + + +
    +Implementation + + +
    public(package) fun report_validator(
    +    self: &mut IotaSystemStateInnerV2,
    +    cap: &UnverifiedValidatorOperationCap,
    +    reportee_addr: address,
    +) {
    +    // Reportee needs to be an active validator
    +    assert!(self.validators.is_active_validator_by_iota_address(reportee_addr), ENotValidator);
    +    // Verify the represented reporter address is an active validator, and the capability is still valid.
    +    let verified_cap = self.validators.verify_cap(cap, ACTIVE_VALIDATOR_ONLY);
    +    report_validator_impl(verified_cap, reportee_addr, &mut self.validator_report_records);
    +}
    +
    + + + +
    + + + +## Function `undo_report_validator` + +Undo a report_validator action. Aborts if +1. the reportee is not a currently active validator or +2. the sender has not previously reported the reportee_addr, or +3. the cap is not valid + + +
    public(friend) fun undo_report_validator(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, cap: &validator_cap::UnverifiedValidatorOperationCap, reportee_addr: address)
    +
    + + + +
    +Implementation + + +
    public(package) fun undo_report_validator(
    +    self: &mut IotaSystemStateInnerV2,
    +    cap: &UnverifiedValidatorOperationCap,
    +    reportee_addr: address,
    +) {
    +    let verified_cap = self.validators.verify_cap(cap, ACTIVE_VALIDATOR_ONLY);
    +    undo_report_validator_impl(verified_cap, reportee_addr, &mut self.validator_report_records);
    +}
    +
    + + + +
    + + + +## Function `report_validator_impl` + + + +
    fun report_validator_impl(verified_cap: validator_cap::ValidatorOperationCap, reportee_addr: address, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>)
    +
    + + + +
    +Implementation + + +
    fun report_validator_impl(
    +    verified_cap: ValidatorOperationCap,
    +    reportee_addr: address,
    +    validator_report_records: &mut VecMap<address, VecSet<address>>,
    +) {
    +    let reporter_address = *verified_cap.verified_operation_cap_address();
    +    assert!(reporter_address != reportee_addr, ECannotReportOneself);
    +    if (!validator_report_records.contains(&reportee_addr)) {
    +        validator_report_records.insert(reportee_addr, vec_set::singleton(reporter_address));
    +    } else {
    +        let reporters = validator_report_records.get_mut(&reportee_addr);
    +        if (!reporters.contains(&reporter_address)) {
    +            reporters.insert(reporter_address);
    +        }
    +    }
    +}
    +
    + + + +
    + + + +## Function `undo_report_validator_impl` + + + +
    fun undo_report_validator_impl(verified_cap: validator_cap::ValidatorOperationCap, reportee_addr: address, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>)
    +
    + + + +
    +Implementation + + +
    fun undo_report_validator_impl(
    +    verified_cap: ValidatorOperationCap,
    +    reportee_addr: address,
    +    validator_report_records: &mut VecMap<address, VecSet<address>>,
    +) {
    +    assert!(validator_report_records.contains(&reportee_addr), EReportRecordNotFound);
    +    let reporters = validator_report_records.get_mut(&reportee_addr);
    +
    +    let reporter_addr = *verified_cap.verified_operation_cap_address();
    +    assert!(reporters.contains(&reporter_addr), EReportRecordNotFound);
    +
    +    reporters.remove(&reporter_addr);
    +    if (reporters.is_empty()) {
    +        validator_report_records.remove(&reportee_addr);
    +    }
    +}
    +
    + + + +
    + + + +## Function `rotate_operation_cap` + +Create a new UnverifiedValidatorOperationCap, transfer it to the +validator and registers it. The original object is thus revoked. + + +
    public(friend) fun rotate_operation_cap(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun rotate_operation_cap(
    +    self: &mut IotaSystemStateInnerV2,
    +    ctx: &mut TxContext,
    +) {
    +    let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    +    validator.new_unverified_validator_operation_cap_and_transfer(ctx);
    +}
    +
    + + + +
    + + + +## Function `update_validator_name` + +Update a validator's name. + + +
    public(friend) fun update_validator_name(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, name: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_validator_name(
    +    self: &mut IotaSystemStateInnerV2,
    +    name: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    +
    +    validator.update_name(name);
    +}
    +
    + + + +
    + + + +## Function `update_validator_description` + +Update a validator's description + + +
    public(friend) fun update_validator_description(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, description: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_validator_description(
    +    self: &mut IotaSystemStateInnerV2,
    +    description: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    +    validator.update_description(description);
    +}
    +
    + + + +
    + + + +## Function `update_validator_image_url` + +Update a validator's image url + + +
    public(friend) fun update_validator_image_url(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, image_url: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_validator_image_url(
    +    self: &mut IotaSystemStateInnerV2,
    +    image_url: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    +    validator.update_image_url(image_url);
    +}
    +
    + + + +
    + + + +## Function `update_validator_project_url` + +Update a validator's project url + + +
    public(friend) fun update_validator_project_url(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, project_url: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_validator_project_url(
    +    self: &mut IotaSystemStateInnerV2,
    +    project_url: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    +    validator.update_project_url(project_url);
    +}
    +
    + + + +
    + + + +## Function `update_validator_next_epoch_network_address` + +Update a validator's network address. +The change will only take effects starting from the next epoch. + + +
    public(friend) fun update_validator_next_epoch_network_address(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, network_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_validator_next_epoch_network_address(
    +    self: &mut IotaSystemStateInnerV2,
    +    network_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let validator = self.validators.get_validator_mut_with_ctx(ctx);
    +    validator.update_next_epoch_network_address(network_address);
    +    let validator :&Validator = validator; // Force immutability for the following call
    +    self.validators.assert_no_pending_or_active_duplicates(validator);
    +}
    +
    + + + +
    + + + +## Function `update_candidate_validator_network_address` + +Update candidate validator's network address. + + +
    public(friend) fun update_candidate_validator_network_address(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, network_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_candidate_validator_network_address(
    +    self: &mut IotaSystemStateInnerV2,
    +    network_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    +    candidate.update_candidate_network_address(network_address);
    +}
    +
    + + + +
    + + + +## Function `update_validator_next_epoch_p2p_address` + +Update a validator's p2p address. +The change will only take effects starting from the next epoch. + + +
    public(friend) fun update_validator_next_epoch_p2p_address(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, p2p_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_validator_next_epoch_p2p_address(
    +    self: &mut IotaSystemStateInnerV2,
    +    p2p_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let validator = self.validators.get_validator_mut_with_ctx(ctx);
    +    validator.update_next_epoch_p2p_address(p2p_address);
    +    let validator :&Validator = validator; // Force immutability for the following call
    +    self.validators.assert_no_pending_or_active_duplicates(validator);
    +}
    +
    + + + +
    + + + +## Function `update_candidate_validator_p2p_address` + +Update candidate validator's p2p address. + + +
    public(friend) fun update_candidate_validator_p2p_address(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, p2p_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_candidate_validator_p2p_address(
    +    self: &mut IotaSystemStateInnerV2,
    +    p2p_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    +    candidate.update_candidate_p2p_address(p2p_address);
    +}
    +
    + + + +
    + + + +## Function `update_validator_next_epoch_primary_address` + +Update a validator's narwhal primary address. +The change will only take effects starting from the next epoch. + + +
    public(friend) fun update_validator_next_epoch_primary_address(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, primary_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_validator_next_epoch_primary_address(
    +    self: &mut IotaSystemStateInnerV2,
    +    primary_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let validator = self.validators.get_validator_mut_with_ctx(ctx);
    +    validator.update_next_epoch_primary_address(primary_address);
    +}
    +
    + + + +
    + + + +## Function `update_candidate_validator_primary_address` + +Update candidate validator's narwhal primary address. + + +
    public(friend) fun update_candidate_validator_primary_address(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, primary_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_candidate_validator_primary_address(
    +    self: &mut IotaSystemStateInnerV2,
    +    primary_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    +    candidate.update_candidate_primary_address(primary_address);
    +}
    +
    + + + +
    + + + +## Function `update_validator_next_epoch_worker_address` + +Update a validator's narwhal worker address. +The change will only take effects starting from the next epoch. + + +
    public(friend) fun update_validator_next_epoch_worker_address(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, worker_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_validator_next_epoch_worker_address(
    +    self: &mut IotaSystemStateInnerV2,
    +    worker_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let validator = self.validators.get_validator_mut_with_ctx(ctx);
    +    validator.update_next_epoch_worker_address(worker_address);
    +}
    +
    + + + +
    + + + +## Function `update_candidate_validator_worker_address` + +Update candidate validator's narwhal worker address. + + +
    public(friend) fun update_candidate_validator_worker_address(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, worker_address: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_candidate_validator_worker_address(
    +    self: &mut IotaSystemStateInnerV2,
    +    worker_address: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    +    candidate.update_candidate_worker_address(worker_address);
    +}
    +
    + + + +
    + + + +## Function `update_validator_next_epoch_protocol_pubkey` + +Update a validator's public key of protocol key and proof of possession. +The change will only take effects starting from the next epoch. + + +
    public(friend) fun update_validator_next_epoch_protocol_pubkey(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, protocol_pubkey: vector<u8>, proof_of_possession: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_validator_next_epoch_protocol_pubkey(
    +    self: &mut IotaSystemStateInnerV2,
    +    protocol_pubkey: vector<u8>,
    +    proof_of_possession: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let validator = self.validators.get_validator_mut_with_ctx(ctx);
    +    validator.update_next_epoch_protocol_pubkey(protocol_pubkey, proof_of_possession);
    +    let validator :&Validator = validator; // Force immutability for the following call
    +    self.validators.assert_no_pending_or_active_duplicates(validator);
    +}
    +
    + + + +
    + + + +## Function `update_candidate_validator_protocol_pubkey` + +Update candidate validator's public key of protocol key and proof of possession. + + +
    public(friend) fun update_candidate_validator_protocol_pubkey(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, protocol_pubkey: vector<u8>, proof_of_possession: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_candidate_validator_protocol_pubkey(
    +    self: &mut IotaSystemStateInnerV2,
    +    protocol_pubkey: vector<u8>,
    +    proof_of_possession: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    +    candidate.update_candidate_protocol_pubkey(protocol_pubkey, proof_of_possession);
    +}
    +
    + + + +
    + + + +## Function `update_validator_next_epoch_worker_pubkey` + +Update a validator's public key of worker key. +The change will only take effects starting from the next epoch. + + +
    public(friend) fun update_validator_next_epoch_worker_pubkey(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, worker_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_validator_next_epoch_worker_pubkey(
    +    self: &mut IotaSystemStateInnerV2,
    +    worker_pubkey: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let validator = self.validators.get_validator_mut_with_ctx(ctx);
    +    validator.update_next_epoch_worker_pubkey(worker_pubkey);
    +    let validator :&Validator = validator; // Force immutability for the following call
    +    self.validators.assert_no_pending_or_active_duplicates(validator);
    +}
    +
    + + + +
    + + + +## Function `update_candidate_validator_worker_pubkey` + +Update candidate validator's public key of worker key. + + +
    public(friend) fun update_candidate_validator_worker_pubkey(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, worker_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_candidate_validator_worker_pubkey(
    +    self: &mut IotaSystemStateInnerV2,
    +    worker_pubkey: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    +    candidate.update_candidate_worker_pubkey(worker_pubkey);
    +}
    +
    + + + +
    + + + +## Function `update_validator_next_epoch_network_pubkey` + +Update a validator's public key of network key. +The change will only take effects starting from the next epoch. + + +
    public(friend) fun update_validator_next_epoch_network_pubkey(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, network_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_validator_next_epoch_network_pubkey(
    +    self: &mut IotaSystemStateInnerV2,
    +    network_pubkey: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let validator = self.validators.get_validator_mut_with_ctx(ctx);
    +    validator.update_next_epoch_network_pubkey(network_pubkey);
    +    let validator :&Validator = validator; // Force immutability for the following call
    +    self.validators.assert_no_pending_or_active_duplicates(validator);
    +}
    +
    + + + +
    + + + +## Function `update_candidate_validator_network_pubkey` + +Update candidate validator's public key of network key. + + +
    public(friend) fun update_candidate_validator_network_pubkey(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, network_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun update_candidate_validator_network_pubkey(
    +    self: &mut IotaSystemStateInnerV2,
    +    network_pubkey: vector<u8>,
    +    ctx: &TxContext,
    +) {
    +    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    +    candidate.update_candidate_network_pubkey(network_pubkey);
    +}
    +
    + + + +
    + + + +## Function `advance_epoch` + +This function should be called at the end of an epoch, and advances the system to the next epoch. +It does the following things: +1. Add storage charge to the storage fund. +2. Burn the storage rebates from the storage fund. These are already refunded to transaction sender's +gas coins. +3. Distribute computation charge to validator stake. +4. Update all validators. + + +
    public(friend) fun advance_epoch(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
    +
    + + + +
    +Implementation + + +
    public(package) fun advance_epoch(
    +    self: &mut IotaSystemStateInnerV2,
    +    new_epoch: u64,
    +    next_protocol_version: u64,
    +    mut storage_reward: Balance<IOTA>,
    +    mut computation_reward: Balance<IOTA>,
    +    mut storage_rebate_amount: u64,
    +    mut non_refundable_storage_fee_amount: u64,
    +    storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested
    +                                     // into storage fund, in basis point.
    +    reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps.
    +    epoch_start_timestamp_ms: u64, // Timestamp of the epoch start
    +    ctx: &mut TxContext,
    +) : Balance<IOTA> {
    +    let prev_epoch_start_timestamp = self.epoch_start_timestamp_ms;
    +    self.epoch_start_timestamp_ms = epoch_start_timestamp_ms;
    +
    +    let bps_denominator_u64 = BASIS_POINT_DENOMINATOR as u64;
    +    // Rates can't be higher than 100%.
    +    assert!(
    +        storage_fund_reinvest_rate <= bps_denominator_u64
    +        && reward_slashing_rate <= bps_denominator_u64,
    +        EBpsTooLarge,
    +    );
    +
    +    // TODO: remove this in later upgrade.
    +    if (self.parameters.stake_subsidy_start_epoch > 0) {
    +        self.parameters.stake_subsidy_start_epoch = 20;
    +    };
    +
    +    // Accumulate the gas summary during safe_mode before processing any rewards:
    +    let safe_mode_storage_rewards = self.safe_mode_storage_rewards.withdraw_all();
    +    storage_reward.join(safe_mode_storage_rewards);
    +    let safe_mode_computation_rewards = self.safe_mode_computation_rewards.withdraw_all();
    +    computation_reward.join(safe_mode_computation_rewards);
    +    storage_rebate_amount = storage_rebate_amount + self.safe_mode_storage_rebates;
    +    self.safe_mode_storage_rebates = 0;
    +    non_refundable_storage_fee_amount = non_refundable_storage_fee_amount + self.safe_mode_non_refundable_storage_fee;
    +    self.safe_mode_non_refundable_storage_fee = 0;
    +
    +    let total_validators_stake = self.validators.total_stake();
    +    let storage_fund_balance = self.storage_fund.total_balance();
    +    let total_stake = storage_fund_balance + total_validators_stake;
    +
    +    let storage_charge = storage_reward.value();
    +    let computation_charge = computation_reward.value();
    +
    +    // Include stake subsidy in the rewards given out to validators and stakers.
    +    // Delay distributing any stake subsidies until after `stake_subsidy_start_epoch`.
    +    // And if this epoch is shorter than the regular epoch duration, don't distribute any stake subsidy.
    +    let stake_subsidy =
    +        if (ctx.epoch() >= self.parameters.stake_subsidy_start_epoch  &&
    +            epoch_start_timestamp_ms >= prev_epoch_start_timestamp + self.parameters.epoch_duration_ms)
    +        {
    +            self.stake_subsidy.advance_epoch()
    +        } else {
    +            balance::zero()
    +        };
    +
    +    let stake_subsidy_amount = stake_subsidy.value();
    +    computation_reward.join(stake_subsidy);
    +
    +    let total_stake_u128 = total_stake as u128;
    +    let computation_charge_u128 = computation_charge as u128;
    +
    +    let storage_fund_reward_amount = storage_fund_balance as u128 * computation_charge_u128 / total_stake_u128;
    +    let mut storage_fund_reward = computation_reward.split(storage_fund_reward_amount as u64);
    +    let storage_fund_reinvestment_amount =
    +        storage_fund_reward_amount * (storage_fund_reinvest_rate as u128) / BASIS_POINT_DENOMINATOR;
    +    let storage_fund_reinvestment = storage_fund_reward.split(
    +        storage_fund_reinvestment_amount as u64,
    +    );
    +
    +    self.epoch = self.epoch + 1;
    +    // Sanity check to make sure we are advancing to the right epoch.
    +    assert!(new_epoch == self.epoch, EAdvancedToWrongEpoch);
    +
    +    let computation_reward_amount_before_distribution = computation_reward.value();
    +    let storage_fund_reward_amount_before_distribution = storage_fund_reward.value();
    +
    +    self.validators.advance_epoch(
    +        &mut computation_reward,
    +        &mut storage_fund_reward,
    +        &mut self.validator_report_records,
    +        reward_slashing_rate,
    +        self.parameters.validator_low_stake_threshold,
    +        self.parameters.validator_very_low_stake_threshold,
    +        self.parameters.validator_low_stake_grace_period,
    +        ctx,
    +    );
    +
    +    let new_total_stake = self.validators.total_stake();
    +
    +    let computation_reward_amount_after_distribution = computation_reward.value();
    +    let storage_fund_reward_amount_after_distribution = storage_fund_reward.value();
    +    let computation_reward_distributed = computation_reward_amount_before_distribution - computation_reward_amount_after_distribution;
    +    let storage_fund_reward_distributed = storage_fund_reward_amount_before_distribution - storage_fund_reward_amount_after_distribution;
    +
    +    self.protocol_version = next_protocol_version;
    +
    +    // Derive the reference gas price for the new epoch
    +    self.reference_gas_price = self.validators.derive_reference_gas_price();
    +    // Because of precision issues with integer divisions, we expect that there will be some
    +    // remaining balance in `storage_fund_reward` and `computation_reward`.
    +    // All of these go to the storage fund.
    +    let mut leftover_staking_rewards = storage_fund_reward;
    +    leftover_staking_rewards.join(computation_reward);
    +    let leftover_storage_fund_inflow = leftover_staking_rewards.value();
    +
    +    let refunded_storage_rebate =
    +        self.storage_fund.advance_epoch(
    +            storage_reward,
    +            storage_fund_reinvestment,
    +            leftover_staking_rewards,
    +            storage_rebate_amount,
    +            non_refundable_storage_fee_amount,
    +        );
    +
    +    event::emit(
    +        SystemEpochInfoEvent {
    +            epoch: self.epoch,
    +            protocol_version: self.protocol_version,
    +            reference_gas_price: self.reference_gas_price,
    +            total_stake: new_total_stake,
    +            storage_charge,
    +            storage_fund_reinvestment: storage_fund_reinvestment_amount as u64,
    +            storage_rebate: storage_rebate_amount,
    +            storage_fund_balance: self.storage_fund.total_balance(),
    +            stake_subsidy_amount,
    +            total_gas_fees: computation_charge,
    +            total_stake_rewards_distributed: computation_reward_distributed + storage_fund_reward_distributed,
    +            leftover_storage_fund_inflow,
    +        }
    +    );
    +    self.safe_mode = false;
    +    // Double check that the gas from safe mode has been processed.
    +    assert!(self.safe_mode_storage_rebates == 0
    +        && self.safe_mode_storage_rewards.value() == 0
    +        && self.safe_mode_computation_rewards.value() == 0, ESafeModeGasNotProcessed);
    +
    +    // Return the storage rebate split from storage fund that's already refunded to the transaction senders.
    +    // This will be burnt at the last step of epoch change programmable transaction.
    +    refunded_storage_rebate
    +}
    +
    + + + +
    + + + +## Function `epoch` + +Return the current epoch number. Useful for applications that need a coarse-grained concept of time, +since epochs are ever-increasing and epoch changes are intended to happen every 24 hours. + + +
    public(friend) fun epoch(self: &iota_system_state_inner::IotaSystemStateInnerV2): u64
    +
    + + + +
    +Implementation + + +
    public(package) fun epoch(self: &IotaSystemStateInnerV2): u64 {
    +    self.epoch
    +}
    +
    + + + +
    + + + +## Function `protocol_version` + + + +
    public(friend) fun protocol_version(self: &iota_system_state_inner::IotaSystemStateInnerV2): u64
    +
    + + + +
    +Implementation + + +
    public(package) fun protocol_version(self: &IotaSystemStateInnerV2): u64 {
    +    self.protocol_version
    +}
    +
    + + + +
    + + + +## Function `system_state_version` + + + +
    public(friend) fun system_state_version(self: &iota_system_state_inner::IotaSystemStateInnerV2): u64
    +
    + + + +
    +Implementation + + +
    public(package) fun system_state_version(self: &IotaSystemStateInnerV2): u64 {
    +    self.system_state_version
    +}
    +
    + + + +
    + + + +## Function `genesis_system_state_version` + +This function always return the genesis system state version, which is used to create the system state in genesis. +It should never change for a given network. + + +
    public(friend) fun genesis_system_state_version(): u64
    +
    + + + +
    +Implementation + + +
    public(package) fun genesis_system_state_version(): u64 {
    +    SYSTEM_STATE_VERSION_V1
    +}
    +
    + + + +
    + + + +## Function `epoch_start_timestamp_ms` + +Returns unix timestamp of the start of current epoch + + +
    public(friend) fun epoch_start_timestamp_ms(self: &iota_system_state_inner::IotaSystemStateInnerV2): u64
    +
    + + + +
    +Implementation + + +
    public(package) fun epoch_start_timestamp_ms(self: &IotaSystemStateInnerV2): u64 {
    +    self.epoch_start_timestamp_ms
    +}
    +
    + + + +
    + + + +## Function `validator_stake_amount` + +Returns the total amount staked with validator_addr. +Aborts if validator_addr is not an active validator. + + +
    public(friend) fun validator_stake_amount(self: &iota_system_state_inner::IotaSystemStateInnerV2, validator_addr: address): u64
    +
    + + + +
    +Implementation + + +
    public(package) fun validator_stake_amount(self: &IotaSystemStateInnerV2, validator_addr: address): u64 {
    +    self.validators.validator_total_stake_amount(validator_addr)
    +}
    +
    + + + +
    + + + +## Function `validator_staking_pool_id` + +Returns the staking pool id of a given validator. +Aborts if validator_addr is not an active validator. + + +
    public(friend) fun validator_staking_pool_id(self: &iota_system_state_inner::IotaSystemStateInnerV2, validator_addr: address): object::ID
    +
    + + + +
    +Implementation + + +
    public(package) fun validator_staking_pool_id(self: &IotaSystemStateInnerV2, validator_addr: address): ID {
    +
    +    self.validators.validator_staking_pool_id(validator_addr)
    +}
    +
    + + + +
    + + + +## Function `validator_staking_pool_mappings` + +Returns reference to the staking pool mappings that map pool ids to active validator addresses + + +
    public(friend) fun validator_staking_pool_mappings(self: &iota_system_state_inner::IotaSystemStateInnerV2): &table::Table<object::ID, address>
    +
    + + + +
    +Implementation + + +
    public(package) fun validator_staking_pool_mappings(self: &IotaSystemStateInnerV2): &Table<ID, address> {
    +
    +    self.validators.staking_pool_mappings()
    +}
    +
    + + + +
    + + + +## Function `get_reporters_of` + +Returns all the validators who are currently reporting addr + + +
    public(friend) fun get_reporters_of(self: &iota_system_state_inner::IotaSystemStateInnerV2, addr: address): vec_set::VecSet<address>
    +
    + + + +
    +Implementation + + +
    public(package) fun get_reporters_of(self: &IotaSystemStateInnerV2, addr: address): VecSet<address> {
    +
    +    if (self.validator_report_records.contains(&addr)) {
    +        self.validator_report_records[&addr]
    +    } else {
    +        vec_set::empty()
    +    }
    +}
    +
    + + + +
    + + + +## Function `get_storage_fund_total_balance` + + + +
    public(friend) fun get_storage_fund_total_balance(self: &iota_system_state_inner::IotaSystemStateInnerV2): u64
    +
    + + + +
    +Implementation + + +
    public(package) fun get_storage_fund_total_balance(self: &IotaSystemStateInnerV2): u64 {
    +    self.storage_fund.total_balance()
    +}
    +
    + + + +
    + + + +## Function `get_storage_fund_object_rebates` + + + +
    public(friend) fun get_storage_fund_object_rebates(self: &iota_system_state_inner::IotaSystemStateInnerV2): u64
    +
    + + + +
    +Implementation + + +
    public(package) fun get_storage_fund_object_rebates(self: &IotaSystemStateInnerV2): u64 {
    +    self.storage_fund.total_object_storage_rebates()
    +}
    +
    + + + +
    + + + +## Function `pool_exchange_rates` + + + +
    public(friend) fun pool_exchange_rates(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, pool_id: &object::ID): &table::Table<u64, staking_pool::PoolTokenExchangeRate>
    +
    + + + +
    +Implementation + + +
    public(package) fun pool_exchange_rates(
    +    self: &mut IotaSystemStateInnerV2,
    +    pool_id: &ID
    +): &Table<u64, PoolTokenExchangeRate>  {
    +    let validators = &mut self.validators;
    +    validators.pool_exchange_rates(pool_id)
    +}
    +
    + + + +
    + + + +## Function `active_validator_addresses` + + + +
    public(friend) fun active_validator_addresses(self: &iota_system_state_inner::IotaSystemStateInnerV2): vector<address>
    +
    + + + +
    +Implementation + + +
    public(package) fun active_validator_addresses(self: &IotaSystemStateInnerV2): vector<address> {
    +    let validator_set = &self.validators;
    +    validator_set.active_validator_addresses()
    +}
    +
    + + + +
    + + + +## Function `extract_coin_balance` + +Extract required Balance from vector of Coin, transfer the remainder back to sender. + + +
    fun extract_coin_balance(coins: vector<coin::Coin<iota::IOTA>>, amount: option::Option<u64>, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
    +
    + + + +
    +Implementation + + +
    fun extract_coin_balance(mut coins: vector<Coin<IOTA>>, amount: option::Option<u64>, ctx: &mut TxContext): Balance<IOTA> {
    +    let mut merged_coin = coins.pop_back();
    +    merged_coin.join_vec(coins);
    +
    +    let mut total_balance = merged_coin.into_balance();
    +    // return the full amount if amount is not specified
    +    if (amount.is_some()) {
    +        let amount = amount.destroy_some();
    +        let balance = total_balance.split(amount);
    +        // transfer back the remainder if non zero.
    +        if (total_balance.value() > 0) {
    +            transfer::public_transfer(total_balance.into_coin(ctx), ctx.sender());
    +        } else {
    +            total_balance.destroy_zero();
    +        };
    +        balance
    +    } else {
    +        total_balance
    +    }
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-system/stake_subsidy.md b/crates/iota-framework/docs/iota-system/stake_subsidy.md new file mode 100644 index 00000000000..fce7bc03cdb --- /dev/null +++ b/crates/iota-framework/docs/iota-system/stake_subsidy.md @@ -0,0 +1,213 @@ +--- +title: Module `0x3::stake_subsidy` +--- + + + +- [Struct `StakeSubsidy`](#0x3_stake_subsidy_StakeSubsidy) +- [Constants](#@Constants_0) +- [Function `create`](#0x3_stake_subsidy_create) +- [Function `advance_epoch`](#0x3_stake_subsidy_advance_epoch) +- [Function `current_epoch_subsidy_amount`](#0x3_stake_subsidy_current_epoch_subsidy_amount) + + +
    use 0x2::bag;
    +use 0x2::balance;
    +use 0x2::iota;
    +use 0x2::math;
    +use 0x2::tx_context;
    +
    + + + + + +## Struct `StakeSubsidy` + + + +
    struct StakeSubsidy has store
    +
    + + + +
    +Fields + + +
    +
    +balance: balance::Balance<iota::IOTA> +
    +
    + Balance of IOTA set aside for stake subsidies that will be drawn down over time. +
    +
    +distribution_counter: u64 +
    +
    + Count of the number of times stake subsidies have been distributed. +
    +
    +current_distribution_amount: u64 +
    +
    + The amount of stake subsidy to be drawn down per distribution. + This amount decays and decreases over time. +
    +
    +stake_subsidy_period_length: u64 +
    +
    + Number of distributions to occur before the distribution amount decays. +
    +
    +stake_subsidy_decrease_rate: u16 +
    +
    + The rate at which the distribution amount decays at the end of each + period. Expressed in basis points. +
    +
    +extra_fields: bag::Bag +
    +
    + Any extra fields that's not defined statically. +
    +
    + + +
    + + + +## Constants + + + + + + +
    const BASIS_POINT_DENOMINATOR: u128 = 10000;
    +
    + + + + + + + +
    const ESubsidyDecreaseRateTooLarge: u64 = 0;
    +
    + + + + + +## Function `create` + + + +
    public(friend) fun create(balance: balance::Balance<iota::IOTA>, initial_distribution_amount: u64, stake_subsidy_period_length: u64, stake_subsidy_decrease_rate: u16, ctx: &mut tx_context::TxContext): stake_subsidy::StakeSubsidy
    +
    + + + +
    +Implementation + + +
    public(package) fun create(
    +    balance: Balance<IOTA>,
    +    initial_distribution_amount: u64,
    +    stake_subsidy_period_length: u64,
    +    stake_subsidy_decrease_rate: u16,
    +    ctx: &mut TxContext,
    +): StakeSubsidy {
    +    // Rate can't be higher than 100%.
    +    assert!(
    +        stake_subsidy_decrease_rate <= BASIS_POINT_DENOMINATOR as u16,
    +        ESubsidyDecreaseRateTooLarge,
    +    );
    +
    +    StakeSubsidy {
    +        balance,
    +        distribution_counter: 0,
    +        current_distribution_amount: initial_distribution_amount,
    +        stake_subsidy_period_length,
    +        stake_subsidy_decrease_rate,
    +        extra_fields: bag::new(ctx),
    +    }
    +}
    +
    + + + +
    + + + +## Function `advance_epoch` + +Advance the epoch counter and draw down the subsidy for the epoch. + + +
    public(friend) fun advance_epoch(self: &mut stake_subsidy::StakeSubsidy): balance::Balance<iota::IOTA>
    +
    + + + +
    +Implementation + + +
    public(package) fun advance_epoch(self: &mut StakeSubsidy): Balance<IOTA> {
    +    // Take the minimum of the reward amount and the remaining balance in
    +    // order to ensure we don't overdraft the remaining stake subsidy
    +    // balance
    +    let to_withdraw = math::min(self.current_distribution_amount, self.balance.value());
    +
    +    // Drawn down the subsidy for this epoch.
    +    let stake_subsidy = self.balance.split(to_withdraw);
    +
    +    self.distribution_counter = self.distribution_counter + 1;
    +
    +    // Decrease the subsidy amount only when the current period ends.
    +    if (self.distribution_counter % self.stake_subsidy_period_length == 0) {
    +        let decrease_amount = self.current_distribution_amount as u128
    +            * (self.stake_subsidy_decrease_rate as u128) / BASIS_POINT_DENOMINATOR;
    +        self.current_distribution_amount = self.current_distribution_amount - (decrease_amount as u64)
    +    };
    +
    +    stake_subsidy
    +}
    +
    + + + +
    + + + +## Function `current_epoch_subsidy_amount` + +Returns the amount of stake subsidy to be added at the end of the current epoch. + + +
    public fun current_epoch_subsidy_amount(self: &stake_subsidy::StakeSubsidy): u64
    +
    + + + +
    +Implementation + + +
    public fun current_epoch_subsidy_amount(self: &StakeSubsidy): u64 {
    +    math::min(self.current_distribution_amount, self.balance.value())
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-system/staking_pool.md b/crates/iota-framework/docs/iota-system/staking_pool.md new file mode 100644 index 00000000000..199a4d2c06c --- /dev/null +++ b/crates/iota-framework/docs/iota-system/staking_pool.md @@ -0,0 +1,1412 @@ +--- +title: Module `0x3::staking_pool` +--- + + + +- [Resource `StakingPool`](#0x3_staking_pool_StakingPool) +- [Struct `PoolTokenExchangeRate`](#0x3_staking_pool_PoolTokenExchangeRate) +- [Resource `StakedIota`](#0x3_staking_pool_StakedIota) +- [Constants](#@Constants_0) +- [Function `new`](#0x3_staking_pool_new) +- [Function `request_add_stake`](#0x3_staking_pool_request_add_stake) +- [Function `request_withdraw_stake`](#0x3_staking_pool_request_withdraw_stake) +- [Function `withdraw_from_principal`](#0x3_staking_pool_withdraw_from_principal) +- [Function `unwrap_staked_iota`](#0x3_staking_pool_unwrap_staked_iota) +- [Function `deposit_rewards`](#0x3_staking_pool_deposit_rewards) +- [Function `process_pending_stakes_and_withdraws`](#0x3_staking_pool_process_pending_stakes_and_withdraws) +- [Function `process_pending_stake_withdraw`](#0x3_staking_pool_process_pending_stake_withdraw) +- [Function `process_pending_stake`](#0x3_staking_pool_process_pending_stake) +- [Function `withdraw_rewards`](#0x3_staking_pool_withdraw_rewards) +- [Function `activate_staking_pool`](#0x3_staking_pool_activate_staking_pool) +- [Function `deactivate_staking_pool`](#0x3_staking_pool_deactivate_staking_pool) +- [Function `iota_balance`](#0x3_staking_pool_iota_balance) +- [Function `pool_id`](#0x3_staking_pool_pool_id) +- [Function `staked_iota_amount`](#0x3_staking_pool_staked_iota_amount) +- [Function `stake_activation_epoch`](#0x3_staking_pool_stake_activation_epoch) +- [Function `is_preactive`](#0x3_staking_pool_is_preactive) +- [Function `is_inactive`](#0x3_staking_pool_is_inactive) +- [Function `split`](#0x3_staking_pool_split) +- [Function `split_staked_iota`](#0x3_staking_pool_split_staked_iota) +- [Function `join_staked_iota`](#0x3_staking_pool_join_staked_iota) +- [Function `is_equal_staking_metadata`](#0x3_staking_pool_is_equal_staking_metadata) +- [Function `pool_token_exchange_rate_at_epoch`](#0x3_staking_pool_pool_token_exchange_rate_at_epoch) +- [Function `pending_stake_amount`](#0x3_staking_pool_pending_stake_amount) +- [Function `pending_stake_withdraw_amount`](#0x3_staking_pool_pending_stake_withdraw_amount) +- [Function `exchange_rates`](#0x3_staking_pool_exchange_rates) +- [Function `iota_amount`](#0x3_staking_pool_iota_amount) +- [Function `pool_token_amount`](#0x3_staking_pool_pool_token_amount) +- [Function `is_preactive_at_epoch`](#0x3_staking_pool_is_preactive_at_epoch) +- [Function `get_iota_amount`](#0x3_staking_pool_get_iota_amount) +- [Function `get_token_amount`](#0x3_staking_pool_get_token_amount) +- [Function `initial_exchange_rate`](#0x3_staking_pool_initial_exchange_rate) +- [Function `check_balance_invariants`](#0x3_staking_pool_check_balance_invariants) + + +
    use 0x1::option;
    +use 0x2::bag;
    +use 0x2::balance;
    +use 0x2::iota;
    +use 0x2::math;
    +use 0x2::object;
    +use 0x2::table;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +
    + + + + + +## Resource `StakingPool` + +A staking pool embedded in each validator struct in the system state object. + + +
    struct StakingPool has store, key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +activation_epoch: option::Option<u64> +
    +
    + The epoch at which this pool became active. + The value is None if the pool is pre-active and Some(<epoch_number>) if active or inactive. +
    +
    +deactivation_epoch: option::Option<u64> +
    +
    + The epoch at which this staking pool ceased to be active. None = {pre-active, active}, + Some(<epoch_number>) if in-active, and it was de-activated at epoch <epoch_number>. +
    +
    +iota_balance: u64 +
    +
    + The total number of IOTA tokens in this pool, including the IOTA in the rewards_pool, as well as in all the principal + in the StakedIota object, updated at epoch boundaries. +
    +
    +rewards_pool: balance::Balance<iota::IOTA> +
    +
    + The epoch stake rewards will be added here at the end of each epoch. +
    +
    +pool_token_balance: u64 +
    +
    + Total number of pool tokens issued by the pool. +
    +
    +exchange_rates: table::Table<u64, staking_pool::PoolTokenExchangeRate> +
    +
    + Exchange rate history of previous epochs. Key is the epoch number. + The entries start from the activation_epoch of this pool and contains exchange rates at the beginning of each epoch, + i.e., right after the rewards for the previous epoch have been deposited into the pool. +
    +
    +pending_stake: u64 +
    +
    + Pending stake amount for this epoch, emptied at epoch boundaries. +
    +
    +pending_total_iota_withdraw: u64 +
    +
    + Pending stake withdrawn during the current epoch, emptied at epoch boundaries. + This includes both the principal and rewards IOTA withdrawn. +
    +
    +pending_pool_token_withdraw: u64 +
    +
    + Pending pool token withdrawn during the current epoch, emptied at epoch boundaries. +
    +
    +extra_fields: bag::Bag +
    +
    + Any extra fields that's not defined statically. +
    +
    + + +
    + + + +## Struct `PoolTokenExchangeRate` + +Struct representing the exchange rate of the stake pool token to IOTA. + + +
    struct PoolTokenExchangeRate has copy, drop, store
    +
    + + + +
    +Fields + + +
    +
    +iota_amount: u64 +
    +
    + +
    +
    +pool_token_amount: u64 +
    +
    + +
    +
    + + +
    + + + +## Resource `StakedIota` + +A self-custodial object holding the staked IOTA tokens. + + +
    struct StakedIota has store, key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +pool_id: object::ID +
    +
    + ID of the staking pool we are staking with. +
    +
    +stake_activation_epoch: u64 +
    +
    + The epoch at which the stake becomes active. +
    +
    +principal: balance::Balance<iota::IOTA> +
    +
    + The staked IOTA tokens. +
    +
    + + +
    + + + +## Constants + + + + + + +
    const EActivationOfInactivePool: u64 = 16;
    +
    + + + + + + + +
    const EDeactivationOfInactivePool: u64 = 11;
    +
    + + + + + + + +
    const EDelegationOfZeroIota: u64 = 17;
    +
    + + + + + + + +
    const EDelegationToInactivePool: u64 = 10;
    +
    + + + + + + + +
    const EDestroyNonzeroBalance: u64 = 5;
    +
    + + + + + + + +
    const EIncompatibleStakedIota: u64 = 12;
    +
    + + + + + + + +
    const EInsufficientIotaTokenBalance: u64 = 3;
    +
    + + + + + + + +
    const EInsufficientPoolTokenBalance: u64 = 0;
    +
    + + + + + + + +
    const EInsufficientRewardsPoolBalance: u64 = 4;
    +
    + + + + + + + +
    const EPendingDelegationDoesNotExist: u64 = 8;
    +
    + + + + + + + +
    const EPoolAlreadyActive: u64 = 14;
    +
    + + + + + + + +
    const EPoolNotPreactive: u64 = 15;
    +
    + + + + + + + +
    const EStakedIotaBelowThreshold: u64 = 18;
    +
    + + + + + + + +
    const ETokenBalancesDoNotMatchExchangeRate: u64 = 9;
    +
    + + + + + + + +
    const ETokenTimeLockIsSome: u64 = 6;
    +
    + + + + + + + +
    const EWithdrawAmountCannotBeZero: u64 = 2;
    +
    + + + + + + + +
    const EWithdrawalInSameEpoch: u64 = 13;
    +
    + + + + + + + +
    const EWrongDelegation: u64 = 7;
    +
    + + + + + + + +
    const EWrongPool: u64 = 1;
    +
    + + + + + +StakedIota objects cannot be split to below this amount. + + +
    const MIN_STAKING_THRESHOLD: u64 = 1000000000;
    +
    + + + + + +## Function `new` + +Create a new, empty staking pool. + + +
    public(friend) fun new(ctx: &mut tx_context::TxContext): staking_pool::StakingPool
    +
    + + + +
    +Implementation + + +
    public(package) fun new(ctx: &mut TxContext) : StakingPool {
    +    let exchange_rates = table::new(ctx);
    +    StakingPool {
    +        id: object::new(ctx),
    +        activation_epoch: option::none(),
    +        deactivation_epoch: option::none(),
    +        iota_balance: 0,
    +        rewards_pool: balance::zero(),
    +        pool_token_balance: 0,
    +        exchange_rates,
    +        pending_stake: 0,
    +        pending_total_iota_withdraw: 0,
    +        pending_pool_token_withdraw: 0,
    +        extra_fields: bag::new(ctx),
    +    }
    +}
    +
    + + + +
    + + + +## Function `request_add_stake` + +Request to stake to a staking pool. The stake starts counting at the beginning of the next epoch, + + +
    public(friend) fun request_add_stake(pool: &mut staking_pool::StakingPool, stake: balance::Balance<iota::IOTA>, stake_activation_epoch: u64, ctx: &mut tx_context::TxContext): staking_pool::StakedIota
    +
    + + + +
    +Implementation + + +
    public(package) fun request_add_stake(
    +    pool: &mut StakingPool,
    +    stake: Balance<IOTA>,
    +    stake_activation_epoch: u64,
    +    ctx: &mut TxContext
    +) : StakedIota {
    +    let iota_amount = stake.value();
    +    assert!(!is_inactive(pool), EDelegationToInactivePool);
    +    assert!(iota_amount > 0, EDelegationOfZeroIota);
    +    let staked_iota = StakedIota {
    +        id: object::new(ctx),
    +        pool_id: object::id(pool),
    +        stake_activation_epoch,
    +        principal: stake,
    +    };
    +    pool.pending_stake = pool.pending_stake + iota_amount;
    +    staked_iota
    +}
    +
    + + + +
    + + + +## Function `request_withdraw_stake` + +Request to withdraw the given stake plus rewards from a staking pool. +Both the principal and corresponding rewards in IOTA are withdrawn. +A proportional amount of pool token withdraw is recorded and processed at epoch change time. + + +
    public(friend) fun request_withdraw_stake(pool: &mut staking_pool::StakingPool, staked_iota: staking_pool::StakedIota, ctx: &tx_context::TxContext): balance::Balance<iota::IOTA>
    +
    + + + +
    +Implementation + + +
    public(package) fun request_withdraw_stake(
    +    pool: &mut StakingPool,
    +    staked_iota: StakedIota,
    +    ctx: &TxContext
    +) : Balance<IOTA> {
    +    let (pool_token_withdraw_amount, mut principal_withdraw) =
    +        withdraw_from_principal(pool, staked_iota);
    +    let principal_withdraw_amount = principal_withdraw.value();
    +
    +    let rewards_withdraw = withdraw_rewards(
    +        pool, principal_withdraw_amount, pool_token_withdraw_amount, ctx.epoch()
    +    );
    +    let total_iota_withdraw_amount = principal_withdraw_amount + rewards_withdraw.value();
    +
    +    pool.pending_total_iota_withdraw = pool.pending_total_iota_withdraw + total_iota_withdraw_amount;
    +    pool.pending_pool_token_withdraw = pool.pending_pool_token_withdraw + pool_token_withdraw_amount;
    +
    +    // If the pool is inactive, we immediately process the withdrawal.
    +    if (is_inactive(pool)) process_pending_stake_withdraw(pool);
    +
    +    // TODO: implement withdraw bonding period here.
    +    principal_withdraw.join(rewards_withdraw);
    +    principal_withdraw
    +}
    +
    + + + +
    + + + +## Function `withdraw_from_principal` + +Withdraw the principal IOTA stored in the StakedIota object, and calculate the corresponding amount of pool +tokens using exchange rate at staking epoch. +Returns values are amount of pool tokens withdrawn and withdrawn principal portion of IOTA. + + +
    public(friend) fun withdraw_from_principal(pool: &staking_pool::StakingPool, staked_iota: staking_pool::StakedIota): (u64, balance::Balance<iota::IOTA>)
    +
    + + + +
    +Implementation + + +
    public(package) fun withdraw_from_principal(
    +    pool: &StakingPool,
    +    staked_iota: StakedIota,
    +) : (u64, Balance<IOTA>) {
    +
    +    // Check that the stake information matches the pool.
    +    assert!(staked_iota.pool_id == object::id(pool), EWrongPool);
    +
    +    let exchange_rate_at_staking_epoch = pool_token_exchange_rate_at_epoch(pool, staked_iota.stake_activation_epoch);
    +    let principal_withdraw = unwrap_staked_iota(staked_iota);
    +    let pool_token_withdraw_amount = get_token_amount(
    +		&exchange_rate_at_staking_epoch,
    +		principal_withdraw.value()
    +	);
    +
    +    (
    +        pool_token_withdraw_amount,
    +        principal_withdraw,
    +    )
    +}
    +
    + + + +
    + + + +## Function `unwrap_staked_iota` + + + +
    fun unwrap_staked_iota(staked_iota: staking_pool::StakedIota): balance::Balance<iota::IOTA>
    +
    + + + +
    +Implementation + + +
    fun unwrap_staked_iota(staked_iota: StakedIota): Balance<IOTA> {
    +    let StakedIota {
    +        id,
    +        pool_id: _,
    +        stake_activation_epoch: _,
    +        principal,
    +    } = staked_iota;
    +    object::delete(id);
    +    principal
    +}
    +
    + + + +
    + + + +## Function `deposit_rewards` + +Called at epoch advancement times to add rewards (in IOTA) to the staking pool. + + +
    public(friend) fun deposit_rewards(pool: &mut staking_pool::StakingPool, rewards: balance::Balance<iota::IOTA>)
    +
    + + + +
    +Implementation + + +
    public(package) fun deposit_rewards(pool: &mut StakingPool, rewards: Balance<IOTA>) {
    +    pool.iota_balance = pool.iota_balance + rewards.value();
    +    pool.rewards_pool.join(rewards);
    +}
    +
    + + + +
    + + + +## Function `process_pending_stakes_and_withdraws` + + + +
    public(friend) fun process_pending_stakes_and_withdraws(pool: &mut staking_pool::StakingPool, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public(package) fun process_pending_stakes_and_withdraws(pool: &mut StakingPool, ctx: &TxContext) {
    +    let new_epoch = ctx.epoch() + 1;
    +    process_pending_stake_withdraw(pool);
    +    process_pending_stake(pool);
    +    pool.exchange_rates.add(
    +        new_epoch,
    +        PoolTokenExchangeRate { iota_amount: pool.iota_balance, pool_token_amount: pool.pool_token_balance },
    +    );
    +    check_balance_invariants(pool, new_epoch);
    +}
    +
    + + + +
    + + + +## Function `process_pending_stake_withdraw` + +Called at epoch boundaries to process pending stake withdraws requested during the epoch. +Also called immediately upon withdrawal if the pool is inactive. + + +
    fun process_pending_stake_withdraw(pool: &mut staking_pool::StakingPool)
    +
    + + + +
    +Implementation + + +
    fun process_pending_stake_withdraw(pool: &mut StakingPool) {
    +    pool.iota_balance = pool.iota_balance - pool.pending_total_iota_withdraw;
    +    pool.pool_token_balance = pool.pool_token_balance - pool.pending_pool_token_withdraw;
    +    pool.pending_total_iota_withdraw = 0;
    +    pool.pending_pool_token_withdraw = 0;
    +}
    +
    + + + +
    + + + +## Function `process_pending_stake` + +Called at epoch boundaries to process the pending stake. + + +
    public(friend) fun process_pending_stake(pool: &mut staking_pool::StakingPool)
    +
    + + + +
    +Implementation + + +
    public(package) fun process_pending_stake(pool: &mut StakingPool) {
    +    // Use the most up to date exchange rate with the rewards deposited and withdraws effectuated.
    +    let latest_exchange_rate =
    +        PoolTokenExchangeRate { iota_amount: pool.iota_balance, pool_token_amount: pool.pool_token_balance };
    +    pool.iota_balance = pool.iota_balance + pool.pending_stake;
    +    pool.pool_token_balance = get_token_amount(&latest_exchange_rate, pool.iota_balance);
    +    pool.pending_stake = 0;
    +}
    +
    + + + +
    + + + +## Function `withdraw_rewards` + +This function does the following: +1. Calculates the total amount of IOTA (including principal and rewards) that the provided pool tokens represent +at the current exchange rate. +2. Using the above number and the given principal_withdraw_amount, calculates the rewards portion of the +stake we should withdraw. +3. Withdraws the rewards portion from the rewards pool at the current exchange rate. We only withdraw the rewards +portion because the principal portion was already taken out of the staker's self custodied StakedIota. + + +
    fun withdraw_rewards(pool: &mut staking_pool::StakingPool, principal_withdraw_amount: u64, pool_token_withdraw_amount: u64, epoch: u64): balance::Balance<iota::IOTA>
    +
    + + + +
    +Implementation + + +
    fun withdraw_rewards(
    +    pool: &mut StakingPool,
    +    principal_withdraw_amount: u64,
    +    pool_token_withdraw_amount: u64,
    +    epoch: u64,
    +) : Balance<IOTA> {
    +    let exchange_rate = pool_token_exchange_rate_at_epoch(pool, epoch);
    +    let total_iota_withdraw_amount = get_iota_amount(&exchange_rate, pool_token_withdraw_amount);
    +    let mut reward_withdraw_amount =
    +        if (total_iota_withdraw_amount >= principal_withdraw_amount)
    +            total_iota_withdraw_amount - principal_withdraw_amount
    +        else 0;
    +    // This may happen when we are withdrawing everything from the pool and
    +    // the rewards pool balance may be less than reward_withdraw_amount.
    +    // TODO: FIGURE OUT EXACTLY WHY THIS CAN HAPPEN.
    +    reward_withdraw_amount = math::min(reward_withdraw_amount, pool.rewards_pool.value());
    +    pool.rewards_pool.split(reward_withdraw_amount)
    +}
    +
    + + + +
    + + + +## Function `activate_staking_pool` + +Called by validator module to activate a staking pool. + + +
    public(friend) fun activate_staking_pool(pool: &mut staking_pool::StakingPool, activation_epoch: u64)
    +
    + + + +
    +Implementation + + +
    public(package) fun activate_staking_pool(pool: &mut StakingPool, activation_epoch: u64) {
    +    // Add the initial exchange rate to the table.
    +    pool.exchange_rates.add(
    +        activation_epoch,
    +        initial_exchange_rate()
    +    );
    +    // Check that the pool is preactive and not inactive.
    +    assert!(is_preactive(pool), EPoolAlreadyActive);
    +    assert!(!is_inactive(pool), EActivationOfInactivePool);
    +    // Fill in the active epoch.
    +    pool.activation_epoch.fill(activation_epoch);
    +}
    +
    + + + +
    + + + +## Function `deactivate_staking_pool` + +Deactivate a staking pool by setting the deactivation_epoch. After +this pool deactivation, the pool stops earning rewards. Only stake +withdraws can be made to the pool. + + +
    public(friend) fun deactivate_staking_pool(pool: &mut staking_pool::StakingPool, deactivation_epoch: u64)
    +
    + + + +
    +Implementation + + +
    public(package) fun deactivate_staking_pool(pool: &mut StakingPool, deactivation_epoch: u64) {
    +    // We can't deactivate an already deactivated pool.
    +    assert!(!is_inactive(pool), EDeactivationOfInactivePool);
    +    pool.deactivation_epoch = option::some(deactivation_epoch);
    +}
    +
    + + + +
    + + + +## Function `iota_balance` + + + +
    public fun iota_balance(pool: &staking_pool::StakingPool): u64
    +
    + + + +
    +Implementation + + +
    public fun iota_balance(pool: &StakingPool): u64 { pool.iota_balance }
    +
    + + + +
    + + + +## Function `pool_id` + + + +
    public fun pool_id(staked_iota: &staking_pool::StakedIota): object::ID
    +
    + + + +
    +Implementation + + +
    public fun pool_id(staked_iota: &StakedIota): ID { staked_iota.pool_id }
    +
    + + + +
    + + + +## Function `staked_iota_amount` + + + +
    public fun staked_iota_amount(staked_iota: &staking_pool::StakedIota): u64
    +
    + + + +
    +Implementation + + +
    public fun staked_iota_amount(staked_iota: &StakedIota): u64 { staked_iota.principal.value() }
    +
    + + + +
    + + + +## Function `stake_activation_epoch` + + + +
    public fun stake_activation_epoch(staked_iota: &staking_pool::StakedIota): u64
    +
    + + + +
    +Implementation + + +
    public fun stake_activation_epoch(staked_iota: &StakedIota): u64 {
    +    staked_iota.stake_activation_epoch
    +}
    +
    + + + +
    + + + +## Function `is_preactive` + +Returns true if the input staking pool is preactive. + + +
    public fun is_preactive(pool: &staking_pool::StakingPool): bool
    +
    + + + +
    +Implementation + + +
    public fun is_preactive(pool: &StakingPool): bool{
    +    pool.activation_epoch.is_none()
    +}
    +
    + + + +
    + + + +## Function `is_inactive` + +Returns true if the input staking pool is inactive. + + +
    public fun is_inactive(pool: &staking_pool::StakingPool): bool
    +
    + + + +
    +Implementation + + +
    public fun is_inactive(pool: &StakingPool): bool {
    +    pool.deactivation_epoch.is_some()
    +}
    +
    + + + +
    + + + +## Function `split` + +Split StakedIota self to two parts, one with principal split_amount, +and the remaining principal is left in self. +All the other parameters of the StakedIota like stake_activation_epoch or pool_id remain the same. + + +
    public fun split(self: &mut staking_pool::StakedIota, split_amount: u64, ctx: &mut tx_context::TxContext): staking_pool::StakedIota
    +
    + + + +
    +Implementation + + +
    public fun split(self: &mut StakedIota, split_amount: u64, ctx: &mut TxContext): StakedIota {
    +    let original_amount = self.principal.value();
    +    assert!(split_amount <= original_amount, EInsufficientIotaTokenBalance);
    +    let remaining_amount = original_amount - split_amount;
    +    // Both resulting parts should have at least MIN_STAKING_THRESHOLD.
    +    assert!(remaining_amount >= MIN_STAKING_THRESHOLD, EStakedIotaBelowThreshold);
    +    assert!(split_amount >= MIN_STAKING_THRESHOLD, EStakedIotaBelowThreshold);
    +    StakedIota {
    +        id: object::new(ctx),
    +        pool_id: self.pool_id,
    +        stake_activation_epoch: self.stake_activation_epoch,
    +        principal: self.principal.split(split_amount),
    +    }
    +}
    +
    + + + +
    + + + +## Function `split_staked_iota` + +Split the given StakedIota to the two parts, one with principal split_amount, +transfer the newly split part to the sender address. + + +
    public entry fun split_staked_iota(stake: &mut staking_pool::StakedIota, split_amount: u64, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun split_staked_iota(stake: &mut StakedIota, split_amount: u64, ctx: &mut TxContext) {
    +    transfer::transfer(split(stake, split_amount, ctx), ctx.sender());
    +}
    +
    + + + +
    + + + +## Function `join_staked_iota` + +Consume the staked iota other and add its value to self. +Aborts if some of the staking parameters are incompatible (pool id, stake activation epoch, etc.) + + +
    public entry fun join_staked_iota(self: &mut staking_pool::StakedIota, other: staking_pool::StakedIota)
    +
    + + + +
    +Implementation + + +
    public entry fun join_staked_iota(self: &mut StakedIota, other: StakedIota) {
    +    assert!(is_equal_staking_metadata(self, &other), EIncompatibleStakedIota);
    +    let StakedIota {
    +        id,
    +        pool_id: _,
    +        stake_activation_epoch: _,
    +        principal,
    +    } = other;
    +
    +    id.delete();
    +    self.principal.join(principal);
    +}
    +
    + + + +
    + + + +## Function `is_equal_staking_metadata` + +Returns true if all the staking parameters of the staked iota except the principal are identical + + +
    public fun is_equal_staking_metadata(self: &staking_pool::StakedIota, other: &staking_pool::StakedIota): bool
    +
    + + + +
    +Implementation + + +
    public fun is_equal_staking_metadata(self: &StakedIota, other: &StakedIota): bool {
    +    (self.pool_id == other.pool_id) &&
    +    (self.stake_activation_epoch == other.stake_activation_epoch)
    +}
    +
    + + + +
    + + + +## Function `pool_token_exchange_rate_at_epoch` + + + +
    public fun pool_token_exchange_rate_at_epoch(pool: &staking_pool::StakingPool, epoch: u64): staking_pool::PoolTokenExchangeRate
    +
    + + + +
    +Implementation + + +
    public fun pool_token_exchange_rate_at_epoch(pool: &StakingPool, epoch: u64): PoolTokenExchangeRate {
    +    // If the pool is preactive then the exchange rate is always 1:1.
    +    if (is_preactive_at_epoch(pool, epoch)) {
    +        return initial_exchange_rate()
    +    };
    +    let clamped_epoch = pool.deactivation_epoch.get_with_default(epoch);
    +    let mut epoch = math::min(clamped_epoch, epoch);
    +    let activation_epoch = *pool.activation_epoch.borrow();
    +
    +    // Find the latest epoch that's earlier than the given epoch with an entry in the table
    +    while (epoch >= activation_epoch) {
    +        if (pool.exchange_rates.contains(epoch)) {
    +            return pool.exchange_rates[epoch]
    +        };
    +        epoch = epoch - 1;
    +    };
    +    // This line really should be unreachable. Do we want an assert false here?
    +    initial_exchange_rate()
    +}
    +
    + + + +
    + + + +## Function `pending_stake_amount` + +Returns the total value of the pending staking requests for this staking pool. + + +
    public fun pending_stake_amount(staking_pool: &staking_pool::StakingPool): u64
    +
    + + + +
    +Implementation + + +
    public fun pending_stake_amount(staking_pool: &StakingPool): u64 {
    +    staking_pool.pending_stake
    +}
    +
    + + + +
    + + + +## Function `pending_stake_withdraw_amount` + +Returns the total withdrawal from the staking pool this epoch. + + +
    public fun pending_stake_withdraw_amount(staking_pool: &staking_pool::StakingPool): u64
    +
    + + + +
    +Implementation + + +
    public fun pending_stake_withdraw_amount(staking_pool: &StakingPool): u64 {
    +    staking_pool.pending_total_iota_withdraw
    +}
    +
    + + + +
    + + + +## Function `exchange_rates` + + + +
    public(friend) fun exchange_rates(pool: &staking_pool::StakingPool): &table::Table<u64, staking_pool::PoolTokenExchangeRate>
    +
    + + + +
    +Implementation + + +
    public(package) fun exchange_rates(pool: &StakingPool): &Table<u64, PoolTokenExchangeRate> {
    +    &pool.exchange_rates
    +}
    +
    + + + +
    + + + +## Function `iota_amount` + + + +
    public fun iota_amount(exchange_rate: &staking_pool::PoolTokenExchangeRate): u64
    +
    + + + +
    +Implementation + + +
    public fun iota_amount(exchange_rate: &PoolTokenExchangeRate): u64 {
    +    exchange_rate.iota_amount
    +}
    +
    + + + +
    + + + +## Function `pool_token_amount` + + + +
    public fun pool_token_amount(exchange_rate: &staking_pool::PoolTokenExchangeRate): u64
    +
    + + + +
    +Implementation + + +
    public fun pool_token_amount(exchange_rate: &PoolTokenExchangeRate): u64 {
    +    exchange_rate.pool_token_amount
    +}
    +
    + + + +
    + + + +## Function `is_preactive_at_epoch` + +Returns true if the provided staking pool is preactive at the provided epoch. + + +
    fun is_preactive_at_epoch(pool: &staking_pool::StakingPool, epoch: u64): bool
    +
    + + + +
    +Implementation + + +
    fun is_preactive_at_epoch(pool: &StakingPool, epoch: u64): bool{
    +    // Either the pool is currently preactive or the pool's starting epoch is later than the provided epoch.
    +    is_preactive(pool) || (*pool.activation_epoch.borrow() > epoch)
    +}
    +
    + + + +
    + + + +## Function `get_iota_amount` + + + +
    fun get_iota_amount(exchange_rate: &staking_pool::PoolTokenExchangeRate, token_amount: u64): u64
    +
    + + + +
    +Implementation + + +
    fun get_iota_amount(exchange_rate: &PoolTokenExchangeRate, token_amount: u64): u64 {
    +    // When either amount is 0, that means we have no stakes with this pool.
    +    // The other amount might be non-zero when there's dust left in the pool.
    +    if (exchange_rate.iota_amount == 0 || exchange_rate.pool_token_amount == 0) {
    +        return token_amount
    +    };
    +    let res = exchange_rate.iota_amount as u128
    +            * (token_amount as u128)
    +            / (exchange_rate.pool_token_amount as u128);
    +    res as u64
    +}
    +
    + + + +
    + + + +## Function `get_token_amount` + + + +
    fun get_token_amount(exchange_rate: &staking_pool::PoolTokenExchangeRate, iota_amount: u64): u64
    +
    + + + +
    +Implementation + + +
    fun get_token_amount(exchange_rate: &PoolTokenExchangeRate, iota_amount: u64): u64 {
    +    // When either amount is 0, that means we have no stakes with this pool.
    +    // The other amount might be non-zero when there's dust left in the pool.
    +    if (exchange_rate.iota_amount == 0 || exchange_rate.pool_token_amount == 0) {
    +        return iota_amount
    +    };
    +    let res = exchange_rate.pool_token_amount as u128
    +            * (iota_amount as u128)
    +            / (exchange_rate.iota_amount as u128);
    +    res as u64
    +}
    +
    + + + +
    + + + +## Function `initial_exchange_rate` + + + +
    fun initial_exchange_rate(): staking_pool::PoolTokenExchangeRate
    +
    + + + +
    +Implementation + + +
    fun initial_exchange_rate(): PoolTokenExchangeRate {
    +    PoolTokenExchangeRate { iota_amount: 0, pool_token_amount: 0 }
    +}
    +
    + + + +
    + + + +## Function `check_balance_invariants` + + + +
    fun check_balance_invariants(pool: &staking_pool::StakingPool, epoch: u64)
    +
    + + + +
    +Implementation + + +
    fun check_balance_invariants(pool: &StakingPool, epoch: u64) {
    +    let exchange_rate = pool_token_exchange_rate_at_epoch(pool, epoch);
    +    // check that the pool token balance and iota balance ratio matches the exchange rate stored.
    +    let expected = get_token_amount(&exchange_rate, pool.iota_balance);
    +    let actual = pool.pool_token_balance;
    +    assert!(expected == actual, ETokenBalancesDoNotMatchExchangeRate)
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/iota-system/storage_fund.md b/crates/iota-framework/docs/iota-system/storage_fund.md new file mode 100644 index 00000000000..a9205a960c8 --- /dev/null +++ b/crates/iota-framework/docs/iota-system/storage_fund.md @@ -0,0 +1,187 @@ +--- +title: Module `0x3::storage_fund` +--- + + + +- [Struct `StorageFund`](#0x3_storage_fund_StorageFund) +- [Function `new`](#0x3_storage_fund_new) +- [Function `advance_epoch`](#0x3_storage_fund_advance_epoch) +- [Function `total_object_storage_rebates`](#0x3_storage_fund_total_object_storage_rebates) +- [Function `total_balance`](#0x3_storage_fund_total_balance) + + +
    use 0x2::balance;
    +use 0x2::iota;
    +
    + + + + + +## Struct `StorageFund` + +Struct representing the storage fund, containing two Balances: +- total_object_storage_rebates has the invariant that it's the sum of storage_rebate of +all objects currently stored on-chain. To maintain this invariant, the only inflow of this +balance is storage charges collected from transactions, and the only outflow is storage rebates +of transactions, including both the portion refunded to the transaction senders as well as +the non-refundable portion taken out and put into non_refundable_balance. +- non_refundable_balance contains any remaining inflow of the storage fund that should not +be taken out of the fund. + + +
    struct StorageFund has store
    +
    + + + +
    +Fields + + +
    +
    +total_object_storage_rebates: balance::Balance<iota::IOTA> +
    +
    + +
    +
    +non_refundable_balance: balance::Balance<iota::IOTA> +
    +
    + +
    +
    + + +
    + + + +## Function `new` + +Called by iota_system at genesis time. + + +
    public(friend) fun new(initial_fund: balance::Balance<iota::IOTA>): storage_fund::StorageFund
    +
    + + + +
    +Implementation + + +
    public(package) fun new(initial_fund: Balance<IOTA>) : StorageFund {
    +    StorageFund {
    +        // At the beginning there's no object in the storage yet
    +        total_object_storage_rebates: balance::zero(),
    +        non_refundable_balance: initial_fund,
    +    }
    +}
    +
    + + + +
    + + + +## Function `advance_epoch` + +Called by iota_system at epoch change times to process the inflows and outflows of storage fund. + + +
    public(friend) fun advance_epoch(self: &mut storage_fund::StorageFund, storage_charges: balance::Balance<iota::IOTA>, storage_fund_reinvestment: balance::Balance<iota::IOTA>, leftover_staking_rewards: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64): balance::Balance<iota::IOTA>
    +
    + + + +
    +Implementation + + +
    public(package) fun advance_epoch(
    +    self: &mut StorageFund,
    +    storage_charges: Balance<IOTA>,
    +    storage_fund_reinvestment: Balance<IOTA>,
    +    leftover_staking_rewards: Balance<IOTA>,
    +    storage_rebate_amount: u64,
    +    non_refundable_storage_fee_amount: u64,
    +) : Balance<IOTA> {
    +    // Both the reinvestment and leftover rewards are not to be refunded so they go to the non-refundable balance.
    +    self.non_refundable_balance.join(storage_fund_reinvestment);
    +    self.non_refundable_balance.join(leftover_staking_rewards);
    +
    +    // The storage charges for the epoch come from the storage rebate of the new objects created
    +    // and the new storage rebates of the objects modified during the epoch so we put the charges
    +    // into `total_object_storage_rebates`.
    +    self.total_object_storage_rebates.join(storage_charges);
    +
    +    // Split out the non-refundable portion of the storage rebate and put it into the non-refundable balance.
    +    let non_refundable_storage_fee = self.total_object_storage_rebates.split(non_refundable_storage_fee_amount);
    +    self.non_refundable_balance.join(non_refundable_storage_fee);
    +
    +    // `storage_rebates` include the already refunded rebates of deleted objects and old rebates of modified objects and
    +    // should be taken out of the `total_object_storage_rebates`.
    +    let storage_rebate = self.total_object_storage_rebates.split(storage_rebate_amount);
    +
    +    // The storage rebate has already been returned to individual transaction senders' gas coins
    +    // so we return the balance to be burnt at the very end of epoch change.
    +    storage_rebate
    +}
    +
    + + + +
    + + + +## Function `total_object_storage_rebates` + + + +
    public fun total_object_storage_rebates(self: &storage_fund::StorageFund): u64
    +
    + + + +
    +Implementation + + +
    public fun total_object_storage_rebates(self: &StorageFund): u64 {
    +    self.total_object_storage_rebates.value()
    +}
    +
    + + + +
    + + + +## Function `total_balance` + + + +
    public fun total_balance(self: &storage_fund::StorageFund): u64
    +
    + + + +
    +Implementation + + +
    public fun total_balance(self: &StorageFund): u64 {
    +    self.total_object_storage_rebates.value() + self.non_refundable_balance.value()
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/sui-system/validator.md b/crates/iota-framework/docs/iota-system/validator.md similarity index 92% rename from crates/sui-framework/docs/sui-system/validator.md rename to crates/iota-framework/docs/iota-system/validator.md index 562d4a5748e..6b32a7ae768 100644 --- a/crates/sui-framework/docs/sui-system/validator.md +++ b/crates/iota-framework/docs/iota-system/validator.md @@ -25,7 +25,7 @@ title: Module `0x3::validator` - [Function `process_pending_stakes_and_withdraws`](#0x3_validator_process_pending_stakes_and_withdraws) - [Function `is_preactive`](#0x3_validator_is_preactive) - [Function `metadata`](#0x3_validator_metadata) -- [Function `sui_address`](#0x3_validator_sui_address) +- [Function `iota_address`](#0x3_validator_iota_address) - [Function `name`](#0x3_validator_name) - [Function `description`](#0x3_validator_description) - [Function `image_url`](#0x3_validator_image_url) @@ -92,14 +92,14 @@ title: Module `0x3::validator` use 0x1::bcs; use 0x1::option; use 0x1::string; -use 0x2::bag; -use 0x2::balance; -use 0x2::event; -use 0x2::object; -use 0x2::sui; -use 0x2::transfer; -use 0x2::tx_context; -use 0x2::url; +use 0x2::bag; +use 0x2::balance; +use 0x2::event; +use 0x2::iota; +use 0x2::object; +use 0x2::transfer; +use 0x2::tx_context; +use 0x2::url; use 0x3::staking_pool; use 0x3::validator_cap;
    @@ -123,10 +123,10 @@ title: Module `0x3::validator`
    -sui_address: address +iota_address: address
    - The Sui Address of the validator. This is the sender that created the Validator object, + The Iota Address of the validator. This is the sender that created the Validator object, and also the address to send validator/coins to during withdraws.
    @@ -168,13 +168,13 @@ title: Module `0x3::validator`
    -image_url: url::Url +image_url: url::Url
    -project_url: url::Url +project_url: url::Url
    @@ -253,7 +253,7 @@ title: Module `0x3::validator`
    -extra_fields: bag::Bag +extra_fields: bag::Bag
    Any extra fields that's not defined statically. @@ -293,7 +293,7 @@ title: Module `0x3::validator` stake amount.
    -operation_cap_id: object::ID +operation_cap_id: object::ID
    The ID of this validator's current valid UnverifiedValidatorOperationCap @@ -335,7 +335,7 @@ title: Module `0x3::validator` The commission rate of the validator starting the next epoch, in basis point.
    -extra_fields: bag::Bag +extra_fields: bag::Bag
    Any extra fields that's not defined statically. @@ -363,7 +363,7 @@ Event emitted when a new stake request is received.
    -pool_id: object::ID +pool_id: object::ID
    @@ -415,7 +415,7 @@ Event emitted when a new unstake request is received.
    -pool_id: object::ID +pool_id: object::ID
    @@ -637,7 +637,7 @@ Validator Metadata is too long -Max gas price a validator can set is 100K MIST. +Max gas price a validator can set is 100K MICROS.
    const MAX_VALIDATOR_GAS_PRICE: u64 = 100000;
    @@ -660,7 +660,7 @@ Max gas price a validator can set is 100K MIST.
     
     
     
    -
    public(friend) fun new_metadata(sui_address: address, protocol_pubkey_bytes: vector<u8>, network_pubkey_bytes: vector<u8>, worker_pubkey_bytes: vector<u8>, proof_of_possession: vector<u8>, name: string::String, description: string::String, image_url: url::Url, project_url: url::Url, net_address: string::String, p2p_address: string::String, primary_address: string::String, worker_address: string::String, extra_fields: bag::Bag): validator::ValidatorMetadata
    +
    public(friend) fun new_metadata(iota_address: address, protocol_pubkey_bytes: vector<u8>, network_pubkey_bytes: vector<u8>, worker_pubkey_bytes: vector<u8>, proof_of_possession: vector<u8>, name: string::String, description: string::String, image_url: url::Url, project_url: url::Url, net_address: string::String, p2p_address: string::String, primary_address: string::String, worker_address: string::String, extra_fields: bag::Bag): validator::ValidatorMetadata
     
    @@ -670,7 +670,7 @@ Max gas price a validator can set is 100K MIST.
    public(package) fun new_metadata(
    -    sui_address: address,
    +    iota_address: address,
         protocol_pubkey_bytes: vector<u8>,
         network_pubkey_bytes: vector<u8>,
         worker_pubkey_bytes: vector<u8>,
    @@ -686,7 +686,7 @@ Max gas price a validator can set is 100K MIST.
         extra_fields: Bag,
     ): ValidatorMetadata {
         let metadata = ValidatorMetadata {
    -        sui_address,
    +        iota_address,
             protocol_pubkey_bytes,
             network_pubkey_bytes,
             worker_pubkey_bytes,
    @@ -723,7 +723,7 @@ Max gas price a validator can set is 100K MIST.
     
     
     
    -
    public(friend) fun new(sui_address: address, protocol_pubkey_bytes: vector<u8>, network_pubkey_bytes: vector<u8>, worker_pubkey_bytes: vector<u8>, proof_of_possession: vector<u8>, name: vector<u8>, description: vector<u8>, image_url: vector<u8>, project_url: vector<u8>, net_address: vector<u8>, p2p_address: vector<u8>, primary_address: vector<u8>, worker_address: vector<u8>, gas_price: u64, commission_rate: u64, ctx: &mut tx_context::TxContext): validator::Validator
    +
    public(friend) fun new(iota_address: address, protocol_pubkey_bytes: vector<u8>, network_pubkey_bytes: vector<u8>, worker_pubkey_bytes: vector<u8>, proof_of_possession: vector<u8>, name: vector<u8>, description: vector<u8>, image_url: vector<u8>, project_url: vector<u8>, net_address: vector<u8>, p2p_address: vector<u8>, primary_address: vector<u8>, worker_address: vector<u8>, gas_price: u64, commission_rate: u64, ctx: &mut tx_context::TxContext): validator::Validator
     
    @@ -733,7 +733,7 @@ Max gas price a validator can set is 100K MIST.
    public(package) fun new(
    -    sui_address: address,
    +    iota_address: address,
         protocol_pubkey_bytes: vector<u8>,
         network_pubkey_bytes: vector<u8>,
         worker_pubkey_bytes: vector<u8>,
    @@ -765,20 +765,20 @@ Max gas price a validator can set is 100K MIST.
         assert!(gas_price < MAX_VALIDATOR_GAS_PRICE, EGasPriceHigherThanThreshold);
     
         let metadata = new_metadata(
    -        sui_address,
    +        iota_address,
             protocol_pubkey_bytes,
             network_pubkey_bytes,
             worker_pubkey_bytes,
             proof_of_possession,
             name.to_ascii_string().to_string(),
             description.to_ascii_string().to_string(),
    -        url::new_unsafe_from_bytes(image_url),
    -        url::new_unsafe_from_bytes(project_url),
    +        url::new_unsafe_from_bytes(image_url),
    +        url::new_unsafe_from_bytes(project_url),
             net_address.to_ascii_string().to_string(),
             p2p_address.to_ascii_string().to_string(),
             primary_address.to_ascii_string().to_string(),
             worker_address.to_ascii_string().to_string(),
    -        bag::new(ctx),
    +        bag::new(ctx),
         );
     
         // Checks that the keys & addresses & PoP are valid.
    @@ -879,7 +879,7 @@ Process pending stake and pending withdraws, and update the gas price.
     Request to add stake to the validator's staking pool, processed at the end of the epoch.
     
     
    -
    public(friend) fun request_add_stake(self: &mut validator::Validator, stake: balance::Balance<sui::SUI>, staker_address: address, ctx: &mut tx_context::TxContext): staking_pool::StakedSui
    +
    public(friend) fun request_add_stake(self: &mut validator::Validator, stake: balance::Balance<iota::IOTA>, staker_address: address, ctx: &mut tx_context::TxContext): staking_pool::StakedIota
     
    @@ -890,29 +890,29 @@ Request to add stake to the validator's staking pool, processed at the end of th
    public(package) fun request_add_stake(
         self: &mut Validator,
    -    stake: Balance<SUI>,
    +    stake: Balance<IOTA>,
         staker_address: address,
         ctx: &mut TxContext,
    -) : StakedSui {
    +) : StakedIota {
         let stake_amount = stake.value();
         assert!(stake_amount > 0, EInvalidStakeAmount);
         let stake_epoch = ctx.epoch() + 1;
    -    let staked_sui = self.staking_pool.request_add_stake(stake, stake_epoch, ctx);
    +    let staked_iota = self.staking_pool.request_add_stake(stake, stake_epoch, ctx);
         // Process stake right away if staking pool is preactive.
         if (self.staking_pool.is_preactive()) {
             self.staking_pool.process_pending_stake();
         };
         self.next_epoch_stake = self.next_epoch_stake + stake_amount;
    -    event::emit(
    +    event::emit(
             StakingRequestEvent {
                 pool_id: staking_pool_id(self),
    -            validator_address: self.metadata.sui_address,
    +            validator_address: self.metadata.iota_address,
                 staker_address,
                 epoch: ctx.epoch(),
                 amount: stake_amount,
             }
         );
    -    staked_sui
    +    staked_iota
     }
     
    @@ -927,7 +927,7 @@ Request to add stake to the validator's staking pool, processed at the end of th Request to add stake to the validator's staking pool at genesis -
    public(friend) fun request_add_stake_at_genesis(self: &mut validator::Validator, stake: balance::Balance<sui::SUI>, staker_address: address, ctx: &mut tx_context::TxContext)
    +
    public(friend) fun request_add_stake_at_genesis(self: &mut validator::Validator, stake: balance::Balance<iota::IOTA>, staker_address: address, ctx: &mut tx_context::TxContext)
     
    @@ -938,7 +938,7 @@ Request to add stake to the validator's staking pool at genesis
    public(package) fun request_add_stake_at_genesis(
         self: &mut Validator,
    -    stake: Balance<SUI>,
    +    stake: Balance<IOTA>,
         staker_address: address,
         ctx: &mut TxContext,
     ) {
    @@ -946,13 +946,13 @@ Request to add stake to the validator's staking pool at genesis
         let stake_amount = stake.value();
         assert!(stake_amount > 0, EInvalidStakeAmount);
     
    -    let staked_sui = self.staking_pool.request_add_stake(
    +    let staked_iota = self.staking_pool.request_add_stake(
             stake,
             0, // epoch 0 -- genesis
             ctx
         );
     
    -    transfer::public_transfer(staked_sui, staker_address);
    +    transfer::public_transfer(staked_iota, staker_address);
     
         // Process stake right away
         self.staking_pool.process_pending_stake();
    @@ -971,7 +971,7 @@ Request to add stake to the validator's staking pool at genesis
     Request to withdraw stake from the validator's staking pool, processed at the end of the epoch.
     
     
    -
    public(friend) fun request_withdraw_stake(self: &mut validator::Validator, staked_sui: staking_pool::StakedSui, ctx: &tx_context::TxContext): balance::Balance<sui::SUI>
    +
    public(friend) fun request_withdraw_stake(self: &mut validator::Validator, staked_iota: staking_pool::StakedIota, ctx: &tx_context::TxContext): balance::Balance<iota::IOTA>
     
    @@ -982,19 +982,19 @@ Request to withdraw stake from the validator's staking pool, processed at the en
    public(package) fun request_withdraw_stake(
         self: &mut Validator,
    -    staked_sui: StakedSui,
    +    staked_iota: StakedIota,
         ctx: &TxContext,
    -) : Balance<SUI> {
    -    let principal_amount = staked_sui.staked_sui_amount();
    -    let stake_activation_epoch = staked_sui.stake_activation_epoch();
    -    let withdrawn_stake = self.staking_pool.request_withdraw_stake(staked_sui, ctx);
    +) : Balance<IOTA> {
    +    let principal_amount = staked_iota.staked_iota_amount();
    +    let stake_activation_epoch = staked_iota.stake_activation_epoch();
    +    let withdrawn_stake = self.staking_pool.request_withdraw_stake(staked_iota, ctx);
         let withdraw_amount = withdrawn_stake.value();
         let reward_amount = withdraw_amount - principal_amount;
         self.next_epoch_stake = self.next_epoch_stake - withdraw_amount;
    -    event::emit(
    +    event::emit(
             UnstakingRequestEvent {
                 pool_id: staking_pool_id(self),
    -            validator_address: self.metadata.sui_address,
    +            validator_address: self.metadata.iota_address,
                 staker_address: ctx.sender(),
                 stake_activation_epoch,
                 unstaking_epoch: ctx.epoch(),
    @@ -1034,7 +1034,7 @@ Need to present a ValidatorOperationCap.
     ) {
         assert!(new_price < MAX_VALIDATOR_GAS_PRICE, EGasPriceHigherThanThreshold);
         let validator_address = *verified_cap.verified_operation_cap_address();
    -    assert!(validator_address == self.metadata.sui_address, EInvalidCap);
    +    assert!(validator_address == self.metadata.iota_address, EInvalidCap);
         self.next_epoch_gas_price = new_price;
     }
     
    @@ -1067,7 +1067,7 @@ Set new gas price for the candidate validator. assert!(is_preactive(self), ENotValidatorCandidate); assert!(new_price < MAX_VALIDATOR_GAS_PRICE, EGasPriceHigherThanThreshold); let validator_address = *verified_cap.verified_operation_cap_address(); - assert!(validator_address == self.metadata.sui_address, EInvalidCap); + assert!(validator_address == self.metadata.iota_address, EInvalidCap); self.next_epoch_gas_price = new_price; self.gas_price = new_price; } @@ -1137,7 +1137,7 @@ Set new commission rate for the candidate validator. Deposit stakes rewards into the validator's staking pool, called at the end of the epoch. -
    public(friend) fun deposit_stake_rewards(self: &mut validator::Validator, reward: balance::Balance<sui::SUI>)
    +
    public(friend) fun deposit_stake_rewards(self: &mut validator::Validator, reward: balance::Balance<iota::IOTA>)
     
    @@ -1146,7 +1146,7 @@ Deposit stakes rewards into the validator's staking pool, called at the end of t Implementation -
    public(package) fun deposit_stake_rewards(self: &mut Validator, reward: Balance<SUI>) {
    +
    public(package) fun deposit_stake_rewards(self: &mut Validator, reward: Balance<IOTA>) {
         self.next_epoch_stake = self.next_epoch_stake + reward.value();
         self.staking_pool.deposit_rewards(reward);
     }
    @@ -1163,7 +1163,7 @@ Deposit stakes rewards into the validator's staking pool, called at the end of t
     Process pending stakes and withdraws, called at the end of the epoch.
     
     
    -
    public(friend) fun process_pending_stakes_and_withdraws(self: &mut validator::Validator, ctx: &tx_context::TxContext)
    +
    public(friend) fun process_pending_stakes_and_withdraws(self: &mut validator::Validator, ctx: &tx_context::TxContext)
     
    @@ -1231,13 +1231,13 @@ Returns true if the validator is preactive. - + -## Function `sui_address` +## Function `iota_address` -
    public fun sui_address(self: &validator::Validator): address
    +
    public fun iota_address(self: &validator::Validator): address
     
    @@ -1246,8 +1246,8 @@ Returns true if the validator is preactive. Implementation -
    public fun sui_address(self: &Validator): address {
    -    self.metadata.sui_address
    +
    public fun iota_address(self: &Validator): address {
    +    self.metadata.iota_address
     }
     
    @@ -1309,7 +1309,7 @@ Returns true if the validator is preactive. -
    public fun image_url(self: &validator::Validator): &url::Url
    +
    public fun image_url(self: &validator::Validator): &url::Url
     
    @@ -1333,7 +1333,7 @@ Returns true if the validator is preactive. -
    public fun project_url(self: &validator::Validator): &url::Url
    +
    public fun project_url(self: &validator::Validator): &url::Url
     
    @@ -1741,7 +1741,7 @@ Returns true if the validator is preactive. -
    public fun operation_cap_id(self: &validator::Validator): &object::ID
    +
    public fun operation_cap_id(self: &validator::Validator): &object::ID
     
    @@ -1799,7 +1799,7 @@ Returns true if the validator is preactive.
    public fun total_stake_amount(self: &Validator): u64 {
    -    self.staking_pool.sui_balance()
    +    self.staking_pool.iota_balance()
     }
     
    @@ -1823,7 +1823,7 @@ Returns true if the validator is preactive.
    public fun stake_amount(self: &Validator): u64 {
    -    self.staking_pool.sui_balance()
    +    self.staking_pool.iota_balance()
     }
     
    @@ -2032,7 +2032,7 @@ Set the voting power of this validator, called only from validator_set. -
    public fun staking_pool_id(self: &validator::Validator): object::ID
    +
    public fun staking_pool_id(self: &validator::Validator): object::ID
     
    @@ -2042,7 +2042,7 @@ Set the voting power of this validator, called only from validator_set.
    public fun staking_pool_id(self: &Validator): ID {
    -    object::id(&self.staking_pool)
    +    object::id(&self.staking_pool)
     }
     
    @@ -2066,7 +2066,7 @@ Set the voting power of this validator, called only from validator_set.
    public fun is_duplicate(self: &Validator, other: &Validator): bool {
    -     self.metadata.sui_address == other.metadata.sui_address
    +     self.metadata.iota_address == other.metadata.iota_address
             || self.metadata.name == other.metadata.name
             || self.metadata.net_address == other.metadata.net_address
             || self.metadata.p2p_address == other.metadata.p2p_address
    @@ -2170,7 +2170,7 @@ Create a new UnverifiedValidatorOperationCap, transfer to the valid
     and registers it, thus revoking the previous cap's permission.
     
     
    -
    public(friend) fun new_unverified_validator_operation_cap_and_transfer(self: &mut validator::Validator, ctx: &mut tx_context::TxContext)
    +
    public(friend) fun new_unverified_validator_operation_cap_and_transfer(self: &mut validator::Validator, ctx: &mut tx_context::TxContext)
     
    @@ -2181,7 +2181,7 @@ and registers it, thus revoking the previous cap's permission.
    public(package) fun new_unverified_validator_operation_cap_and_transfer(self: &mut Validator, ctx: &mut TxContext) {
         let address = ctx.sender();
    -    assert!(address == self.metadata.sui_address, ENewCapNotCreatedByValidatorItself);
    +    assert!(address == self.metadata.iota_address, ENewCapNotCreatedByValidatorItself);
         let new_id = validator_cap::new_unverified_validator_operation_cap_and_transfer(address, ctx);
         self.operation_cap_id = new_id;
     }
    @@ -2270,7 +2270,7 @@ Update image url of the validator.
             image_url.length() <= MAX_VALIDATOR_METADATA_LENGTH,
             EValidatorMetadataExceedingLengthLimit
         );
    -    self.metadata.image_url = url::new_unsafe_from_bytes(image_url);
    +    self.metadata.image_url = url::new_unsafe_from_bytes(image_url);
     }
     
    @@ -2299,7 +2299,7 @@ Update project url of the validator. project_url.length() <= MAX_VALIDATOR_METADATA_LENGTH, EValidatorMetadataExceedingLengthLimit ); - self.metadata.project_url = url::new_unsafe_from_bytes(project_url); + self.metadata.project_url = url::new_unsafe_from_bytes(project_url); }
    @@ -2860,7 +2860,7 @@ Aborts if validator metadata is valid Create a new validator from the given ValidatorMetadata, called by both new and new_for_testing. -
    fun new_from_metadata(metadata: validator::ValidatorMetadata, gas_price: u64, commission_rate: u64, ctx: &mut tx_context::TxContext): validator::Validator
    +
    fun new_from_metadata(metadata: validator::ValidatorMetadata, gas_price: u64, commission_rate: u64, ctx: &mut tx_context::TxContext): validator::Validator
     
    @@ -2875,11 +2875,11 @@ Create a new validator from the given Validator { - let sui_address = metadata.sui_address; + let iota_address = metadata.iota_address; let staking_pool = staking_pool::new(ctx); - let operation_cap_id = validator_cap::new_unverified_validator_operation_cap_and_transfer(sui_address, ctx); + let operation_cap_id = validator_cap::new_unverified_validator_operation_cap_and_transfer(iota_address, ctx); Validator { metadata, // Initialize the voting power to be 0. @@ -2893,7 +2893,7 @@ Create a new validator from the given bag::new(ctx), + extra_fields: bag::new(ctx), } }
    diff --git a/crates/sui-framework/docs/sui-system/validator_cap.md b/crates/iota-framework/docs/iota-system/validator_cap.md similarity index 89% rename from crates/sui-framework/docs/sui-system/validator_cap.md rename to crates/iota-framework/docs/iota-system/validator_cap.md index b38f89a3ea6..97cab57cbbc 100644 --- a/crates/sui-framework/docs/sui-system/validator_cap.md +++ b/crates/iota-framework/docs/iota-system/validator_cap.md @@ -12,9 +12,9 @@ title: Module `0x3::validator_cap` - [Function `new_from_unverified`](#0x3_validator_cap_new_from_unverified) -
    use 0x2::object;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    +
    use 0x2::object;
    +use 0x2::transfer;
    +use 0x2::tx_context;
     
    @@ -46,7 +46,7 @@ the cap object is still valid.
    -id: object::UID +id: object::UID
    @@ -147,7 +147,7 @@ Should be only called by the friend modules when adding a Validator or rotating an existing validaotr's operation_cap_id. -
    public(friend) fun new_unverified_validator_operation_cap_and_transfer(validator_address: address, ctx: &mut tx_context::TxContext): object::ID
    +
    public(friend) fun new_unverified_validator_operation_cap_and_transfer(validator_address: address, ctx: &mut tx_context::TxContext): object::ID
     
    @@ -167,11 +167,11 @@ or rotating an existing validaotr's operation_cap_id. assert!(sender_address == @0x0 || sender_address == validator_address, 0); let operation_cap = UnverifiedValidatorOperationCap { - id: object::new(ctx), + id: object::new(ctx), authorizer_validator_address: validator_address, }; - let operation_cap_id = object::id(&operation_cap); - transfer::public_transfer(operation_cap, validator_address); + let operation_cap_id = object::id(&operation_cap); + transfer::public_transfer(operation_cap, validator_address); operation_cap_id }
    diff --git a/crates/sui-framework/docs/sui-system/validator_set.md b/crates/iota-framework/docs/iota-system/validator_set.md similarity index 89% rename from crates/sui-framework/docs/sui-system/validator_set.md rename to crates/iota-framework/docs/iota-system/validator_set.md index 18abc209f90..98d96d0b20c 100644 --- a/crates/sui-framework/docs/sui-system/validator_set.md +++ b/crates/iota-framework/docs/iota-system/validator_set.md @@ -30,7 +30,7 @@ title: Module `0x3::validator_set` - [Function `staking_pool_mappings`](#0x3_validator_set_staking_pool_mappings) - [Function `pool_exchange_rates`](#0x3_validator_set_pool_exchange_rates) - [Function `next_epoch_validator_count`](#0x3_validator_set_next_epoch_validator_count) -- [Function `is_active_validator_by_sui_address`](#0x3_validator_set_is_active_validator_by_sui_address) +- [Function `is_active_validator_by_iota_address`](#0x3_validator_set_is_active_validator_by_iota_address) - [Function `is_duplicate_with_active_validator`](#0x3_validator_set_is_duplicate_with_active_validator) - [Function `is_duplicate_validator`](#0x3_validator_set_is_duplicate_validator) - [Function `count_duplicates_vec`](#0x3_validator_set_count_duplicates_vec) @@ -73,18 +73,18 @@ title: Module `0x3::validator_set`
    use 0x1::option;
     use 0x1::vector;
    -use 0x2::bag;
    -use 0x2::balance;
    -use 0x2::event;
    -use 0x2::object;
    -use 0x2::priority_queue;
    -use 0x2::sui;
    -use 0x2::table;
    -use 0x2::table_vec;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -use 0x2::vec_map;
    -use 0x2::vec_set;
    +use 0x2::bag;
    +use 0x2::balance;
    +use 0x2::event;
    +use 0x2::iota;
    +use 0x2::object;
    +use 0x2::priority_queue;
    +use 0x2::table;
    +use 0x2::table_vec;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +use 0x2::vec_map;
    +use 0x2::vec_set;
     use 0x3::staking_pool;
     use 0x3::validator;
     use 0x3::validator_cap;
    @@ -123,7 +123,7 @@ title: Module `0x3::validator_set`
      The current list of active validators.
     
    -pending_active_validators: table_vec::TableVec<validator::Validator> +pending_active_validators: table_vec::TableVec<validator::Validator>
    List of new validator candidates added during the current epoch. @@ -137,13 +137,13 @@ title: Module `0x3::validator_set` pointing to active_validators.
    -staking_pool_mappings: table::Table<object::ID, address> +staking_pool_mappings: table::Table<object::ID, address>
    - Mappings from staking pool's ID to the sui address of a validator. + Mappings from staking pool's ID to the iota address of a validator.
    -inactive_validators: table::Table<object::ID, validator_wrapper::ValidatorWrapper> +inactive_validators: table::Table<object::ID, validator_wrapper::ValidatorWrapper>
    Mapping from a staking pool ID to the inactive validator that has that pool as its staking pool. @@ -151,7 +151,7 @@ title: Module `0x3::validator_set` is added to this table so that stakers can continue to withdraw their stake from it.
    -validator_candidates: table::Table<address, validator_wrapper::ValidatorWrapper> +validator_candidates: table::Table<address, validator_wrapper::ValidatorWrapper>
    Table storing preactive/candidate validators, mapping their addresses to their Validator structs. @@ -161,13 +161,13 @@ title: Module `0x3::validator_set` officially add them to the active validator set active_validators next epoch.
    -at_risk_validators: vec_map::VecMap<address, u64> +at_risk_validators: vec_map::VecMap<address, u64>
    Table storing the number of epochs during which a validator's stake has been below the low stake threshold.
    -extra_fields: bag::Bag +extra_fields: bag::Bag
    Any extra fields that's not defined statically. @@ -379,7 +379,7 @@ The epoch value corresponds to the first epoch this change takes place.
    -staking_pool_id: object::ID +staking_pool_id: object::ID
    @@ -420,7 +420,7 @@ The epoch value corresponds to the first epoch this change takes place.
    -staking_pool_id: object::ID +staking_pool_id: object::ID
    @@ -627,7 +627,7 @@ The epoch value corresponds to the first epoch this change takes place. -
    public(friend) fun new(init_active_validators: vector<validator::Validator>, ctx: &mut tx_context::TxContext): validator_set::ValidatorSet
    +
    public(friend) fun new(init_active_validators: vector<validator::Validator>, ctx: &mut tx_context::TxContext): validator_set::ValidatorSet
     
    @@ -638,24 +638,24 @@ The epoch value corresponds to the first epoch this change takes place.
    public(package) fun new(init_active_validators: vector<Validator>, ctx: &mut TxContext): ValidatorSet {
         let total_stake = calculate_total_stakes(&init_active_validators);
    -    let mut staking_pool_mappings = table::new(ctx);
    +    let mut staking_pool_mappings = table::new(ctx);
         let num_validators = init_active_validators.length();
         let mut i = 0;
         while (i < num_validators) {
             let validator = &init_active_validators[i];
    -        staking_pool_mappings.add(staking_pool_id(validator), sui_address(validator));
    +        staking_pool_mappings.add(staking_pool_id(validator), iota_address(validator));
             i = i + 1;
         };
         let mut validators = ValidatorSet {
             total_stake,
             active_validators: init_active_validators,
    -        pending_active_validators: table_vec::empty(ctx),
    +        pending_active_validators: table_vec::empty(ctx),
             pending_removals: vector[],
             staking_pool_mappings,
    -        inactive_validators: table::new(ctx),
    -        validator_candidates: table::new(ctx),
    -        at_risk_validators: vec_map::empty(),
    -        extra_fields: bag::new(ctx),
    +        inactive_validators: table::new(ctx),
    +        validator_candidates: table::new(ctx),
    +        at_risk_validators: vec_map::empty(),
    +        extra_fields: bag::new(ctx),
         };
         voting_power::set_voting_power(&mut validators.active_validators);
         validators
    @@ -670,10 +670,10 @@ The epoch value corresponds to the first epoch this change takes place.
     
     ## Function `request_add_validator_candidate`
     
    -Called by sui_system to add a new validator candidate.
    +Called by iota_system to add a new validator candidate.
     
     
    -
    public(friend) fun request_add_validator_candidate(self: &mut validator_set::ValidatorSet, validator: validator::Validator, ctx: &mut tx_context::TxContext)
    +
    public(friend) fun request_add_validator_candidate(self: &mut validator_set::ValidatorSet, validator: validator::Validator, ctx: &mut tx_context::TxContext)
     
    @@ -693,7 +693,7 @@ Called by sui_system to && !is_duplicate_with_pending_validator(self, &validator), EDuplicateValidator ); - let validator_address = sui_address(&validator); + let validator_address = iota_address(&validator); assert!( !self.validator_candidates.contains(validator_address), EAlreadyValidatorCandidate @@ -704,7 +704,7 @@ Called by sui_system to // staking with this candidate. self.staking_pool_mappings.add(staking_pool_id(&validator), validator_address); self.validator_candidates.add( - sui_address(&validator), + iota_address(&validator), validator_wrapper::create_v1(validator, ctx), ); } @@ -718,10 +718,10 @@ Called by sui_system to ## Function `request_remove_validator_candidate` -Called by sui_system to remove a validator candidate, and move them to inactive_validators. +Called by iota_system to remove a validator candidate, and move them to inactive_validators. -
    public(friend) fun request_remove_validator_candidate(self: &mut validator_set::ValidatorSet, ctx: &mut tx_context::TxContext)
    +
    public(friend) fun request_remove_validator_candidate(self: &mut validator_set::ValidatorSet, ctx: &mut tx_context::TxContext)
     
    @@ -764,11 +764,11 @@ Called by sui_system to ## Function `request_add_validator` -Called by sui_system to add a new validator to pending_active_validators, which will be +Called by iota_system to add a new validator to pending_active_validators, which will be processed at the end of epoch. -
    public(friend) fun request_add_validator(self: &mut validator_set::ValidatorSet, min_joining_stake_amount: u64, ctx: &tx_context::TxContext)
    +
    public(friend) fun request_add_validator(self: &mut validator_set::ValidatorSet, min_joining_stake_amount: u64, ctx: &tx_context::TxContext)
     
    @@ -834,13 +834,13 @@ processed at the end of epoch. ## Function `request_remove_validator` -Called by sui_system, to remove a validator. +Called by iota_system, to remove a validator. The index of the validator is added to pending_removals and will be processed at the end of epoch. Only an active validator can request to be removed. -
    public(friend) fun request_remove_validator(self: &mut validator_set::ValidatorSet, ctx: &tx_context::TxContext)
    +
    public(friend) fun request_remove_validator(self: &mut validator_set::ValidatorSet, ctx: &tx_context::TxContext)
     
    @@ -873,13 +873,13 @@ Only an active validator can request to be removed. ## Function `request_add_stake` -Called by sui_system, to add a new stake to the validator. +Called by iota_system, to add a new stake to the validator. This request is added to the validator's staking pool's pending stake entries, processed at the end of the epoch. Aborts in case the staking amount is smaller than MIN_STAKING_THRESHOLD -
    public(friend) fun request_add_stake(self: &mut validator_set::ValidatorSet, validator_address: address, stake: balance::Balance<sui::SUI>, ctx: &mut tx_context::TxContext): staking_pool::StakedSui
    +
    public(friend) fun request_add_stake(self: &mut validator_set::ValidatorSet, validator_address: address, stake: balance::Balance<iota::IOTA>, ctx: &mut tx_context::TxContext): staking_pool::StakedIota
     
    @@ -891,11 +891,11 @@ Aborts in case the staking amount is smaller than MIN_STAKING_THRESHOLD
    public(package) fun request_add_stake(
         self: &mut ValidatorSet,
         validator_address: address,
    -    stake: Balance<SUI>,
    +    stake: Balance<IOTA>,
         ctx: &mut TxContext,
    -) : StakedSui {
    -    let sui_amount = stake.value();
    -    assert!(sui_amount >= MIN_STAKING_THRESHOLD, EStakingBelowThreshold);
    +) : StakedIota {
    +    let iota_amount = stake.value();
    +    assert!(iota_amount >= MIN_STAKING_THRESHOLD, EStakingBelowThreshold);
         let validator = get_candidate_or_active_validator_mut(self, validator_address);
         validator.request_add_stake(stake, ctx.sender(), ctx)
     }
    @@ -909,15 +909,15 @@ Aborts in case the staking amount is smaller than MIN_STAKING_THRESHOLD
     
     ## Function `request_withdraw_stake`
     
    -Called by sui_system, to withdraw some share of a stake from the validator. The share to withdraw
    +Called by iota_system, to withdraw some share of a stake from the validator. The share to withdraw
     is denoted by principal_withdraw_amount. One of two things occurs in this function:
    -1. If the staked_sui is staked with an active validator, the request is added to the validator's
    +1. If the staked_iota is staked with an active validator, the request is added to the validator's
     staking pool's pending stake withdraw entries, processed at the end of the epoch.
    -2. If the staked_sui was staked with a validator that is no longer active,
    +2. If the staked_iota was staked with a validator that is no longer active,
     the stake and any rewards corresponding to it will be immediately processed.
     
     
    -
    public(friend) fun request_withdraw_stake(self: &mut validator_set::ValidatorSet, staked_sui: staking_pool::StakedSui, ctx: &tx_context::TxContext): balance::Balance<sui::SUI>
    +
    public(friend) fun request_withdraw_stake(self: &mut validator_set::ValidatorSet, staked_iota: staking_pool::StakedIota, ctx: &tx_context::TxContext): balance::Balance<iota::IOTA>
     
    @@ -928,20 +928,20 @@ the stake and any rewards corresponding to it will be immediately processed.
    public(package) fun request_withdraw_stake(
         self: &mut ValidatorSet,
    -    staked_sui: StakedSui,
    +    staked_iota: StakedIota,
         ctx: &TxContext,
    -) : Balance<SUI> {
    -    let staking_pool_id = pool_id(&staked_sui);
    +) : Balance<IOTA> {
    +    let staking_pool_id = pool_id(&staked_iota);
         let validator =
             if (self.staking_pool_mappings.contains(staking_pool_id)) { // This is an active validator.
    -            let validator_address = self.staking_pool_mappings[pool_id(&staked_sui)];
    +            let validator_address = self.staking_pool_mappings[pool_id(&staked_iota)];
                 get_candidate_or_active_validator_mut(self, validator_address)
             } else { // This is an inactive pool.
                 assert!(self.inactive_validators.contains(staking_pool_id), ENoPoolFound);
                 let wrapper = &mut self.inactive_validators[staking_pool_id];
                 wrapper.load_validator_maybe_upgrade()
             };
    -    validator.request_withdraw_stake(staked_sui, ctx)
    +    validator.request_withdraw_stake(staked_iota, ctx)
     }
     
    @@ -955,7 +955,7 @@ the stake and any rewards corresponding to it will be immediately processed. -
    public(friend) fun request_set_commission_rate(self: &mut validator_set::ValidatorSet, new_commission_rate: u64, ctx: &tx_context::TxContext)
    +
    public(friend) fun request_set_commission_rate(self: &mut validator_set::ValidatorSet, new_commission_rate: u64, ctx: &tx_context::TxContext)
     
    @@ -992,7 +992,7 @@ It does the following things: 5. At the end, we calculate the total stake for the new epoch. -
    public(friend) fun advance_epoch(self: &mut validator_set::ValidatorSet, computation_reward: &mut balance::Balance<sui::SUI>, storage_fund_reward: &mut balance::Balance<sui::SUI>, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, reward_slashing_rate: u64, low_stake_threshold: u64, very_low_stake_threshold: u64, low_stake_grace_period: u64, ctx: &mut tx_context::TxContext)
    +
    public(friend) fun advance_epoch(self: &mut validator_set::ValidatorSet, computation_reward: &mut balance::Balance<iota::IOTA>, storage_fund_reward: &mut balance::Balance<iota::IOTA>, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, reward_slashing_rate: u64, low_stake_threshold: u64, very_low_stake_threshold: u64, low_stake_grace_period: u64, ctx: &mut tx_context::TxContext)
     
    @@ -1003,8 +1003,8 @@ It does the following things:
    public(package) fun advance_epoch(
         self: &mut ValidatorSet,
    -    computation_reward: &mut Balance<SUI>,
    -    storage_fund_reward: &mut Balance<SUI>,
    +    computation_reward: &mut Balance<IOTA>,
    +    storage_fund_reward: &mut Balance<IOTA>,
         validator_report_records: &mut VecMap<address, VecSet<address>>,
         reward_slashing_rate: u64,
         low_stake_threshold: u64,
    @@ -1111,7 +1111,7 @@ It does the following things:
     
     
     
    -
    fun update_and_process_low_stake_departures(self: &mut validator_set::ValidatorSet, low_stake_threshold: u64, very_low_stake_threshold: u64, low_stake_grace_period: u64, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, ctx: &mut tx_context::TxContext)
    +
    fun update_and_process_low_stake_departures(self: &mut validator_set::ValidatorSet, low_stake_threshold: u64, very_low_stake_threshold: u64, low_stake_grace_period: u64, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, ctx: &mut tx_context::TxContext)
     
    @@ -1133,7 +1133,7 @@ It does the following things: while (i > 0) { i = i - 1; let validator_ref = &self.active_validators[i]; - let validator_address = validator_ref.sui_address(); + let validator_address = validator_ref.iota_address(); let stake = validator_ref.total_stake_amount(); if (stake >= low_stake_threshold) { // The validator is safe. We remove their entry from the at_risk map if there exists one. @@ -1207,7 +1207,7 @@ Effectutate pending next epoch metadata if they are staged. ## Function `derive_reference_gas_price` -Called by sui_system to derive reference gas price for the new epoch. +Called by iota_system to derive reference gas price for the new epoch. Derive the reference gas price based on the gas price quote submitted by each validator. The returned gas price should be greater than or equal to 2/3 of the validators submitted gas price, weighted by stake. @@ -1332,7 +1332,7 @@ gas price, weighted by stake. -
    public fun validator_staking_pool_id(self: &validator_set::ValidatorSet, validator_address: address): object::ID
    +
    public fun validator_staking_pool_id(self: &validator_set::ValidatorSet, validator_address: address): object::ID
     
    @@ -1357,7 +1357,7 @@ gas price, weighted by stake. -
    public fun staking_pool_mappings(self: &validator_set::ValidatorSet): &table::Table<object::ID, address>
    +
    public fun staking_pool_mappings(self: &validator_set::ValidatorSet): &table::Table<object::ID, address>
     
    @@ -1381,7 +1381,7 @@ gas price, weighted by stake. -
    public(friend) fun pool_exchange_rates(self: &mut validator_set::ValidatorSet, pool_id: &object::ID): &table::Table<u64, staking_pool::PoolTokenExchangeRate>
    +
    public(friend) fun pool_exchange_rates(self: &mut validator_set::ValidatorSet, pool_id: &object::ID): &table::Table<u64, staking_pool::PoolTokenExchangeRate>
     
    @@ -1435,14 +1435,14 @@ Get the total number of validators in the next epoch. - + -## Function `is_active_validator_by_sui_address` +## Function `is_active_validator_by_iota_address` Returns true iff the address exists in active validators. -
    public(friend) fun is_active_validator_by_sui_address(self: &validator_set::ValidatorSet, validator_address: address): bool
    +
    public(friend) fun is_active_validator_by_iota_address(self: &validator_set::ValidatorSet, validator_address: address): bool
     
    @@ -1451,7 +1451,7 @@ Returns true iff the address exists in active validators. Implementation -
    public(package) fun is_active_validator_by_sui_address(
    +
    public(package) fun is_active_validator_by_iota_address(
         self: &ValidatorSet,
         validator_address: address,
     ): bool {
    @@ -1468,8 +1468,8 @@ Returns true iff the address exists in active validators.
     ## Function `is_duplicate_with_active_validator`
     
     Checks whether new_validator is duplicate with any currently active validators.
    -It differs from is_active_validator_by_sui_address in that the former checks
    -only the sui address but this function looks at more metadata.
    +It differs from is_active_validator_by_iota_address in that the former checks
    +only the iota address but this function looks at more metadata.
     
     
     
    fun is_duplicate_with_active_validator(self: &validator_set::ValidatorSet, new_validator: &validator::Validator): bool
    @@ -1579,7 +1579,7 @@ Checks whether new_validator is duplicate with any currently pendin
     
     
     
    -
    fun count_duplicates_tablevec(validators: &table_vec::TableVec<validator::Validator>, validator: &validator::Validator): u64
    +
    fun count_duplicates_tablevec(validators: &table_vec::TableVec<validator::Validator>, validator: &validator::Validator): u64
     
    @@ -1659,7 +1659,7 @@ If not found, returns (false, 0). let mut i = 0; while (i < length) { let v = &validators[i]; - if (v.sui_address() == validator_address) { + if (v.iota_address() == validator_address) { return option::some(i) }; i = i + 1; @@ -1681,7 +1681,7 @@ Returns (true, index) if the validator is found, and the index is its index in t If not found, returns (false, 0). -
    fun find_validator_from_table_vec(validators: &table_vec::TableVec<validator::Validator>, validator_address: address): option::Option<u64>
    +
    fun find_validator_from_table_vec(validators: &table_vec::TableVec<validator::Validator>, validator_address: address): option::Option<u64>
     
    @@ -1695,7 +1695,7 @@ If not found, returns (false, 0). let mut i = 0; while (i < length) { let v = &validators[i]; - if (v.sui_address() == validator_address) { + if (v.iota_address() == validator_address) { return option::some(i) }; i = i + 1; @@ -1853,7 +1853,7 @@ sender has the ability to modify the Validator. -
    public(friend) fun get_validator_mut_with_ctx(self: &mut validator_set::ValidatorSet, ctx: &tx_context::TxContext): &mut validator::Validator
    +
    public(friend) fun get_validator_mut_with_ctx(self: &mut validator_set::ValidatorSet, ctx: &tx_context::TxContext): &mut validator::Validator
     
    @@ -1881,7 +1881,7 @@ sender has the ability to modify the Validator. -
    public(friend) fun get_validator_mut_with_ctx_including_candidates(self: &mut validator_set::ValidatorSet, ctx: &tx_context::TxContext): &mut validator::Validator
    +
    public(friend) fun get_validator_mut_with_ctx_including_candidates(self: &mut validator_set::ValidatorSet, ctx: &tx_context::TxContext): &mut validator::Validator
     
    @@ -2060,7 +2060,7 @@ Otherwise, verify the Cap for au either active or pending validator. get_active_validator_ref(self, cap_address) else get_active_or_pending_or_candidate_validator_ref(self, cap_address, which_validator); - assert!(validator.operation_cap_id() == &object::id(cap), EInvalidCap); + assert!(validator.operation_cap_id() == &object::id(cap), EInvalidCap); validator_cap::new_from_unverified(cap) }
    @@ -2077,7 +2077,7 @@ Process the pending withdraw requests. For each pending request, the validator is removed from validators and its staking pool is put into the inactive_validators table. -
    fun process_pending_removals(self: &mut validator_set::ValidatorSet, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, ctx: &mut tx_context::TxContext)
    +
    fun process_pending_removals(self: &mut validator_set::ValidatorSet, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, ctx: &mut tx_context::TxContext)
     
    @@ -2110,7 +2110,7 @@ is removed from validators and its staking pool is put into the fun process_validator_departure(self: &mut validator_set::ValidatorSet, validator: validator::Validator, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, is_voluntary: bool, ctx: &mut tx_context::TxContext) +
    fun process_validator_departure(self: &mut validator_set::ValidatorSet, validator: validator::Validator, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, is_voluntary: bool, ctx: &mut tx_context::TxContext)
     
    @@ -2127,7 +2127,7 @@ is removed from validators and its staking pool is put into the mut TxContext, ) { let new_epoch = ctx.epoch() + 1; - let validator_address = validator.sui_address(); + let validator_address = validator.iota_address(); let validator_pool_id = staking_pool_id(&validator); // Remove the validator from our tables. @@ -2140,7 +2140,7 @@ is removed from validators and its staking pool is put into the clean_report_records_leaving_validator(validator_report_records, validator_address); - event::emit( + event::emit( ValidatorLeaveEvent { epoch: new_epoch, validator_address, @@ -2168,7 +2168,7 @@ is removed from validators and its staking pool is put into the fun clean_report_records_leaving_validator(validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, leaving_validator_addr: address) +
    fun clean_report_records_leaving_validator(validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, leaving_validator_addr: address)
     
    @@ -2230,10 +2230,10 @@ Process the pending new validators. They are activated and inserted into v while (!self.pending_active_validators.is_empty()) { let mut validator = self.pending_active_validators.pop_back(); validator.activate(new_epoch); - event::emit( + event::emit( ValidatorJoinEvent { epoch: new_epoch, - validator_address: validator.sui_address(), + validator_address: validator.iota_address(), staking_pool_id: staking_pool_id(&validator), } ); @@ -2292,7 +2292,7 @@ Sort all the pending removal indexes. Process all active validators' pending stake deposits and withdraws. -
    fun process_pending_stakes_and_withdraws(validators: &mut vector<validator::Validator>, ctx: &tx_context::TxContext)
    +
    fun process_pending_stakes_and_withdraws(validators: &mut vector<validator::Validator>, ctx: &tx_context::TxContext)
     
    @@ -2390,7 +2390,7 @@ Compute both the individual reward adjustments and total reward adjustment for s as well as storage fund rewards. -
    fun compute_reward_adjustments(slashed_validator_indices: vector<u64>, reward_slashing_rate: u64, unadjusted_staking_reward_amounts: &vector<u64>, unadjusted_storage_fund_reward_amounts: &vector<u64>): (u64, vec_map::VecMap<u64, u64>, u64, vec_map::VecMap<u64, u64>)
    +
    fun compute_reward_adjustments(slashed_validator_indices: vector<u64>, reward_slashing_rate: u64, unadjusted_staking_reward_amounts: &vector<u64>, unadjusted_storage_fund_reward_amounts: &vector<u64>): (u64, vec_map::VecMap<u64, u64>, u64, vec_map::VecMap<u64, u64>)
     
    @@ -2411,9 +2411,9 @@ as well as storage fund rewards. VecMap<u64, u64>, // mapping of individual validator's storage fund reward adjustment from index -> amount ) { let mut total_staking_reward_adjustment = 0; - let mut individual_staking_reward_adjustments = vec_map::empty(); + let mut individual_staking_reward_adjustments = vec_map::empty(); let mut total_storage_fund_reward_adjustment = 0; - let mut individual_storage_fund_reward_adjustments = vec_map::empty(); + let mut individual_storage_fund_reward_adjustments = vec_map::empty(); while (!slashed_validator_indices.is_empty()) { let validator_index = slashed_validator_indices.pop_back(); @@ -2456,7 +2456,7 @@ Process the validator report records of the epoch and return the addresses of th non-performant validators according to the input threshold. -
    fun compute_slashed_validators(self: &validator_set::ValidatorSet, validator_report_records: vec_map::VecMap<address, vec_set::VecSet<address>>): vector<address>
    +
    fun compute_slashed_validators(self: &validator_set::ValidatorSet, validator_report_records: vec_map::VecMap<address, vec_set::VecSet<address>>): vector<address>
     
    @@ -2473,7 +2473,7 @@ non-performant validators according to the input threshold. while (!validator_report_records.is_empty()) { let (validator_address, reporters) = validator_report_records.pop(); assert!( - is_active_validator_by_sui_address(self, validator_address), + is_active_validator_by_iota_address(self, validator_address), ENonValidatorInReportRecords, ); // Sum up the voting power of validators that have reported this validator and check if it has @@ -2550,7 +2550,7 @@ Returns the staking rewards each validator gets and the storage fund rewards eac The staking rewards are shared with the stakers while the storage fund ones are not. -
    fun compute_adjusted_reward_distribution(validators: &vector<validator::Validator>, total_voting_power: u64, total_slashed_validator_voting_power: u64, unadjusted_staking_reward_amounts: vector<u64>, unadjusted_storage_fund_reward_amounts: vector<u64>, total_staking_reward_adjustment: u64, individual_staking_reward_adjustments: vec_map::VecMap<u64, u64>, total_storage_fund_reward_adjustment: u64, individual_storage_fund_reward_adjustments: vec_map::VecMap<u64, u64>): (vector<u64>, vector<u64>)
    +
    fun compute_adjusted_reward_distribution(validators: &vector<validator::Validator>, total_voting_power: u64, total_slashed_validator_voting_power: u64, unadjusted_staking_reward_amounts: vector<u64>, unadjusted_storage_fund_reward_amounts: vector<u64>, total_staking_reward_adjustment: u64, individual_staking_reward_adjustments: vec_map::VecMap<u64, u64>, total_storage_fund_reward_adjustment: u64, individual_storage_fund_reward_adjustments: vec_map::VecMap<u64, u64>): (vector<u64>, vector<u64>)
     
    @@ -2632,7 +2632,7 @@ The staking rewards are shared with the stakers while the storage fund ones are -
    fun distribute_reward(validators: &mut vector<validator::Validator>, adjusted_staking_reward_amounts: &vector<u64>, adjusted_storage_fund_reward_amounts: &vector<u64>, staking_rewards: &mut balance::Balance<sui::SUI>, storage_fund_reward: &mut balance::Balance<sui::SUI>, ctx: &mut tx_context::TxContext)
    +
    fun distribute_reward(validators: &mut vector<validator::Validator>, adjusted_staking_reward_amounts: &vector<u64>, adjusted_storage_fund_reward_amounts: &vector<u64>, staking_rewards: &mut balance::Balance<iota::IOTA>, storage_fund_reward: &mut balance::Balance<iota::IOTA>, ctx: &mut tx_context::TxContext)
     
    @@ -2645,8 +2645,8 @@ The staking rewards are shared with the stakers while the storage fund ones are validators: &mut vector<Validator>, adjusted_staking_reward_amounts: &vector<u64>, adjusted_storage_fund_reward_amounts: &vector<u64>, - staking_rewards: &mut Balance<SUI>, - storage_fund_reward: &mut Balance<SUI>, + staking_rewards: &mut Balance<IOTA>, + storage_fund_reward: &mut Balance<IOTA>, ctx: &mut TxContext ) { let length = validators.length(); @@ -2670,9 +2670,9 @@ The staking rewards are shared with the stakers while the storage fund ones are // Add rewards to the validator. Don't try and distribute rewards though if the payout is zero. if (validator_reward.value() > 0) { - let validator_address = validator.sui_address(); + let validator_address = validator.iota_address(); let rewards_stake = validator.request_add_stake(validator_reward, validator_address, ctx); - transfer::public_transfer(rewards_stake, validator_address); + transfer::public_transfer(rewards_stake, validator_address); } else { validator_reward.destroy_zero(); }; @@ -2696,7 +2696,7 @@ Emit events containing information of each validator for the epoch, including stakes, rewards, performance, etc. -
    fun emit_validator_epoch_events(new_epoch: u64, vs: &vector<validator::Validator>, pool_staking_reward_amounts: &vector<u64>, storage_fund_staking_reward_amounts: &vector<u64>, report_records: &vec_map::VecMap<address, vec_set::VecSet<address>>, slashed_validators: &vector<address>)
    +
    fun emit_validator_epoch_events(new_epoch: u64, vs: &vector<validator::Validator>, pool_staking_reward_amounts: &vector<u64>, storage_fund_staking_reward_amounts: &vector<u64>, report_records: &vec_map::VecMap<address, vec_set::VecSet<address>>, slashed_validators: &vector<address>)
     
    @@ -2717,7 +2717,7 @@ including stakes, rewards, performance, etc. let mut i = 0; while (i < num_validators) { let v = &vs[i]; - let validator_address = v.sui_address(); + let validator_address = v.iota_address(); let tallying_rule_reporters = if (report_records.contains(&validator_address)) { report_records[&validator_address].into_keys() @@ -2727,7 +2727,7 @@ including stakes, rewards, performance, etc. let tallying_rule_global_score = if (slashed_validators.contains(&validator_address)) 0 else 1; - event::emit( + event::emit( ValidatorEpochInfoEventV2 { epoch: new_epoch, validator_address, @@ -2841,7 +2841,7 @@ Returns true if the addr is a validator candidate. Returns true if the staking pool identified by staking_pool_id is of an inactive validator. -
    public fun is_inactive_validator(self: &validator_set::ValidatorSet, staking_pool_id: object::ID): bool
    +
    public fun is_inactive_validator(self: &validator_set::ValidatorSet, staking_pool_id: object::ID): bool
     
    @@ -2880,7 +2880,7 @@ Returns true if the staking pool identified by staking_pool_id is o let mut i = 0; let length = vs.length(); while (i < length) { - let validator_address = vs[i].sui_address(); + let validator_address = vs[i].iota_address(); res.push_back(validator_address); i = i + 1; }; diff --git a/crates/sui-framework/docs/sui-system/validator_wrapper.md b/crates/iota-framework/docs/iota-system/validator_wrapper.md similarity index 84% rename from crates/sui-framework/docs/sui-system/validator_wrapper.md rename to crates/iota-framework/docs/iota-system/validator_wrapper.md index 3b0a08b0827..5195b269302 100644 --- a/crates/sui-framework/docs/sui-system/validator_wrapper.md +++ b/crates/iota-framework/docs/iota-system/validator_wrapper.md @@ -13,8 +13,8 @@ title: Module `0x3::validator_wrapper` - [Function `version`](#0x3_validator_wrapper_version) -
    use 0x2::tx_context;
    -use 0x2::versioned;
    +
    use 0x2::tx_context;
    +use 0x2::versioned;
     use 0x3::validator;
     
    @@ -37,7 +37,7 @@ title: Module `0x3::validator_wrapper`
    -inner: versioned::Versioned +inner: versioned::Versioned
    @@ -67,7 +67,7 @@ title: Module `0x3::validator_wrapper` -
    public(friend) fun create_v1(validator: validator::Validator, ctx: &mut tx_context::TxContext): validator_wrapper::ValidatorWrapper
    +
    public(friend) fun create_v1(validator: validator::Validator, ctx: &mut tx_context::TxContext): validator_wrapper::ValidatorWrapper
     
    @@ -78,7 +78,7 @@ title: Module `0x3::validator_wrapper`
    public(package) fun create_v1(validator: Validator, ctx: &mut TxContext): ValidatorWrapper {
         ValidatorWrapper {
    -        inner: versioned::create(1, validator, ctx)
    +        inner: versioned::create(1, validator, ctx)
         }
     }
     
    @@ -106,7 +106,7 @@ If the inner version is old, we upgrade it lazily in-place.
    public(package) fun load_validator_maybe_upgrade(self: &mut ValidatorWrapper): &mut Validator {
         upgrade_to_latest(self);
    -    versioned::load_value_mut(&mut self.inner)
    +    versioned::load_value_mut(&mut self.inner)
     }
     
    @@ -133,7 +133,7 @@ Destroy the wrapper and retrieve the inner validator object.
    public(package) fun destroy(self: ValidatorWrapper): Validator {
         upgrade_to_latest(&self);
         let ValidatorWrapper { inner } = self;
    -    versioned::destroy(inner)
    +    versioned::destroy(inner)
     }
     
    @@ -183,7 +183,7 @@ Destroy the wrapper and retrieve the inner validator object.
    fun version(self: &ValidatorWrapper): u64 {
    -    versioned::version(&self.inner)
    +    versioned::version(&self.inner)
     }
     
    diff --git a/crates/sui-framework/docs/sui-system/voting_power.md b/crates/iota-framework/docs/iota-system/voting_power.md similarity index 95% rename from crates/sui-framework/docs/sui-system/voting_power.md rename to crates/iota-framework/docs/iota-system/voting_power.md index 81de33763fb..f901144e133 100644 --- a/crates/sui-framework/docs/sui-system/voting_power.md +++ b/crates/iota-framework/docs/iota-system/voting_power.md @@ -19,7 +19,7 @@ title: Module `0x3::voting_power`
    use 0x1::vector;
    -use 0x2::math;
    +use 0x2::math;
     use 0x3::validator;
     
    @@ -194,9 +194,9 @@ at MAX_VOTING_
    public(package) fun set_voting_power(validators: &mut vector<Validator>) {
         // If threshold_pct is too small, it's possible that even when all validators reach the threshold we still don't
         // have 100%. So we bound the threshold_pct to be always enough to find a solution.
    -    let threshold = math::min(
    +    let threshold = math::min(
             TOTAL_VOTING_POWER,
    -        math::max(MAX_VOTING_POWER, divide_and_round_up(TOTAL_VOTING_POWER, validators.length())),
    +        math::max(MAX_VOTING_POWER, divide_and_round_up(TOTAL_VOTING_POWER, validators.length())),
         );
         let (mut info_list, remaining_power) = init_voting_power_info(validators, threshold);
         adjust_voting_power(&mut info_list, threshold, remaining_power);
    @@ -241,7 +241,7 @@ Anything beyond the threshold is added to the remaining_power, which is also ret
             let validator = &validators[i];
             let stake = validator.total_stake();
             let adjusted_stake = stake as u128 * (TOTAL_VOTING_POWER as u128) / (total_stake as u128);
    -        let voting_power = math::min(adjusted_stake as u64, threshold);
    +        let voting_power = math::min(adjusted_stake as u64, threshold);
             let info = VotingPowerInfoV2 {
                 validator_index: i,
                 voting_power,
    @@ -346,9 +346,9 @@ Distribute remaining_power to validators that are not capped at threshold.
             // planned is the amount of extra power we want to distribute to this validator.
             let planned = divide_and_round_up(remaining_power, len - i);
             // target is the targeting power this validator will reach, capped by threshold.
    -        let target = math::min(threshold, v.voting_power + planned);
    +        let target = math::min(threshold, v.voting_power + planned);
             // actual is the actual amount of power we will be distributing to this validator.
    -        let actual = math::min(remaining_power, target - v.voting_power);
    +        let actual = math::min(remaining_power, target - v.voting_power);
             v.voting_power = v.voting_power + actual;
             assert!(v.voting_power <= threshold, EVotingPowerOverThreshold);
             remaining_power = remaining_power - actual;
    diff --git a/crates/iota-framework/docs/move-stdlib/address.md b/crates/iota-framework/docs/move-stdlib/address.md
    new file mode 100644
    index 00000000000..da46104cda7
    --- /dev/null
    +++ b/crates/iota-framework/docs/move-stdlib/address.md
    @@ -0,0 +1,40 @@
    +---
    +title: Module `0x1::address`
    +---
    +
    +Provides a way to get address length since it's a
    +platform-specific parameter.
    +
    +
    +-  [Function `length`](#0x1_address_length)
    +
    +
    +
    + + + + + +## Function `length` + +Should be converted to a native function. +Current implementation only works for Iota. + + +
    public fun length(): u64
    +
    + + + +
    +Implementation + + +
    public fun length(): u64 {
    +    32
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/move-stdlib/ascii.md b/crates/iota-framework/docs/move-stdlib/ascii.md similarity index 100% rename from crates/sui-framework/docs/move-stdlib/ascii.md rename to crates/iota-framework/docs/move-stdlib/ascii.md diff --git a/crates/sui-framework/docs/move-stdlib/bcs.md b/crates/iota-framework/docs/move-stdlib/bcs.md similarity index 100% rename from crates/sui-framework/docs/move-stdlib/bcs.md rename to crates/iota-framework/docs/move-stdlib/bcs.md diff --git a/crates/sui-framework/docs/move-stdlib/fixed_point32.md b/crates/iota-framework/docs/move-stdlib/fixed_point32.md similarity index 98% rename from crates/sui-framework/docs/move-stdlib/fixed_point32.md rename to crates/iota-framework/docs/move-stdlib/fixed_point32.md index fabffdbc562..915f5d97f07 100644 --- a/crates/sui-framework/docs/move-stdlib/fixed_point32.md +++ b/crates/iota-framework/docs/move-stdlib/fixed_point32.md @@ -141,7 +141,7 @@ overflows.
    public fun multiply_u64(val: u64, multiplier: FixedPoint32): u64 {
         // The product of two 64 bit values has 128 bits, so perform the
    -    // multiplication with u128 types and keep the full 128 bit product
    +    // multiplication with u128 types and keep the full 128 bit product
         // to avoid losing accuracy.
         let unscaled_product = val as u128 * (multiplier.value as u128);
         // The unscaled product has 32 fractional bits (from the multiplier)
    diff --git a/crates/sui-framework/docs/move-stdlib/option.md b/crates/iota-framework/docs/move-stdlib/option.md
    similarity index 100%
    rename from crates/sui-framework/docs/move-stdlib/option.md
    rename to crates/iota-framework/docs/move-stdlib/option.md
    diff --git a/crates/sui-framework/docs/move-stdlib/string.md b/crates/iota-framework/docs/move-stdlib/string.md
    similarity index 100%
    rename from crates/sui-framework/docs/move-stdlib/string.md
    rename to crates/iota-framework/docs/move-stdlib/string.md
    diff --git a/crates/sui-framework/docs/move-stdlib/type_name.md b/crates/iota-framework/docs/move-stdlib/type_name.md
    similarity index 100%
    rename from crates/sui-framework/docs/move-stdlib/type_name.md
    rename to crates/iota-framework/docs/move-stdlib/type_name.md
    diff --git a/crates/sui-framework/docs/move-stdlib/vector.md b/crates/iota-framework/docs/move-stdlib/vector.md
    similarity index 100%
    rename from crates/sui-framework/docs/move-stdlib/vector.md
    rename to crates/iota-framework/docs/move-stdlib/vector.md
    diff --git a/crates/sui-framework/docs/stardust/address_unlock_condition.md b/crates/iota-framework/docs/stardust/address_unlock_condition.md
    similarity index 76%
    rename from crates/sui-framework/docs/stardust/address_unlock_condition.md
    rename to crates/iota-framework/docs/stardust/address_unlock_condition.md
    index 9c93dedc9c5..4f06d972ffe 100644
    --- a/crates/sui-framework/docs/stardust/address_unlock_condition.md
    +++ b/crates/iota-framework/docs/stardust/address_unlock_condition.md
    @@ -18,9 +18,9 @@ title: Module `0x107a::address_unlock_condition`
     use 0x107a::basic_output;
     use 0x107a::nft;
     use 0x107a::nft_output;
    -use 0x2::coin;
    -use 0x2::object;
    -use 0x2::transfer;
    +use 0x2::coin;
    +use 0x2::object;
    +use 0x2::transfer;
     
    @@ -32,7 +32,7 @@ title: Module `0x107a::address_unlock_condition` Unlock a BasicOutput locked to the alias address. -
    public fun unlock_alias_address_owned_basic(self: &mut alias::Alias, output_to_unlock: transfer::Receiving<basic_output::BasicOutput>): basic_output::BasicOutput
    +
    public fun unlock_alias_address_owned_basic(self: &mut alias::Alias, output_to_unlock: transfer::Receiving<basic_output::BasicOutput>): basic_output::BasicOutput
     
    @@ -60,7 +60,7 @@ Unlock a BasicOutput locked to the alias address. Unlock an NftOutput locked to the alias address. -
    public fun unlock_alias_address_owned_nft(self: &mut alias::Alias, output_to_unlock: transfer::Receiving<nft_output::NftOutput>): nft_output::NftOutput
    +
    public fun unlock_alias_address_owned_nft(self: &mut alias::Alias, output_to_unlock: transfer::Receiving<nft_output::NftOutput>): nft_output::NftOutput
     
    @@ -88,7 +88,7 @@ Unlock an NftOutput locked to the alias address. Unlock an AliasOutput locked to the alias address. -
    public fun unlock_alias_address_owned_alias(self: &mut alias::Alias, output_to_unlock: transfer::Receiving<alias_output::AliasOutput>): alias_output::AliasOutput
    +
    public fun unlock_alias_address_owned_alias(self: &mut alias::Alias, output_to_unlock: transfer::Receiving<alias_output::AliasOutput>): alias_output::AliasOutput
     
    @@ -116,7 +116,7 @@ Unlock an AliasOutput locked to the alias address. Unlock a TreasuryCap locked to the alias address. -
    public fun unlock_alias_address_owned_treasury<T: store, key>(self: &mut alias::Alias, treasury_to_unlock: transfer::Receiving<coin::TreasuryCap<T>>): coin::TreasuryCap<T>
    +
    public fun unlock_alias_address_owned_treasury<T: store, key>(self: &mut alias::Alias, treasury_to_unlock: transfer::Receiving<coin::TreasuryCap<T>>): coin::TreasuryCap<T>
     
    @@ -129,7 +129,7 @@ Unlock a TreasuryCap locked to the alias address. self: &mut Alias, treasury_to_unlock: Receiving<TreasuryCap<T>>, ): TreasuryCap<T> { - transfer::public_receive(self.id(), treasury_to_unlock) + transfer::public_receive(self.id(), treasury_to_unlock) }
    @@ -144,7 +144,7 @@ Unlock a TreasuryCap locked to the alias address. Unlock a BasicOutput locked to the Nft address. -
    public fun unlock_nft_address_owned_basic(self: &mut nft::Nft, output_to_unlock: transfer::Receiving<basic_output::BasicOutput>): basic_output::BasicOutput
    +
    public fun unlock_nft_address_owned_basic(self: &mut nft::Nft, output_to_unlock: transfer::Receiving<basic_output::BasicOutput>): basic_output::BasicOutput
     
    @@ -172,7 +172,7 @@ Unlock a BasicOutput locked to the Nft address. Unlock an NftOutput locked to the Nft address. -
    public fun unlock_nft_address_owned_nft(self: &mut nft::Nft, output_to_unlock: transfer::Receiving<nft_output::NftOutput>): nft_output::NftOutput
    +
    public fun unlock_nft_address_owned_nft(self: &mut nft::Nft, output_to_unlock: transfer::Receiving<nft_output::NftOutput>): nft_output::NftOutput
     
    @@ -200,7 +200,7 @@ Unlock an NftOutput locked to the Nft address. Unlock an AliasOutput locked to the Nft address. -
    public fun unlock_nft_address_owned_alias(self: &mut nft::Nft, output_to_unlock: transfer::Receiving<alias_output::AliasOutput>): alias_output::AliasOutput
    +
    public fun unlock_nft_address_owned_alias(self: &mut nft::Nft, output_to_unlock: transfer::Receiving<alias_output::AliasOutput>): alias_output::AliasOutput
     
    diff --git a/crates/sui-framework/docs/stardust/alias.md b/crates/iota-framework/docs/stardust/alias.md similarity index 94% rename from crates/sui-framework/docs/stardust/alias.md rename to crates/iota-framework/docs/stardust/alias.md index 7614511692c..a86f642dfa4 100644 --- a/crates/sui-framework/docs/stardust/alias.md +++ b/crates/iota-framework/docs/stardust/alias.md @@ -17,7 +17,7 @@ title: Module `0x107a::alias`
    use 0x1::option;
    -use 0x2::object;
    +use 0x2::object;
     
    @@ -42,7 +42,7 @@ have to be received via this object once extracted from AliasOutput
    -id: object::UID +id: object::UID
    The ID of the Alias = hash of the Output ID that created the Alias Output in Stardust. @@ -123,7 +123,7 @@ Destroy the Alias object, immutable_metadata: _, } = self; - object::delete(id); + object::delete(id); }
    @@ -313,7 +313,7 @@ Get the Alias's immutable_metadata. Get the Alias's id. -
    public(friend) fun id(self: &mut alias::Alias): &mut object::UID
    +
    public(friend) fun id(self: &mut alias::Alias): &mut object::UID
     
    @@ -322,7 +322,7 @@ Get the Alias's id. Implementation -
    public(package) fun id(self: &mut Alias): &mut UID {
    +
    public(package) fun id(self: &mut Alias): &mut UID {
         &mut self.id
     }
     
    diff --git a/crates/iota-framework/docs/stardust/alias_output.md b/crates/iota-framework/docs/stardust/alias_output.md new file mode 100644 index 00000000000..d8eea9b15b5 --- /dev/null +++ b/crates/iota-framework/docs/stardust/alias_output.md @@ -0,0 +1,197 @@ +--- +title: Module `0x107a::alias_output` +--- + + + +- [Resource `AliasOutput`](#0x107a_alias_output_AliasOutput) +- [Constants](#@Constants_0) +- [Function `extract_assets`](#0x107a_alias_output_extract_assets) +- [Function `receive`](#0x107a_alias_output_receive) +- [Function `attach_alias`](#0x107a_alias_output_attach_alias) +- [Function `load_alias`](#0x107a_alias_output_load_alias) + + +
    use 0x107a::alias;
    +use 0x2::bag;
    +use 0x2::balance;
    +use 0x2::dynamic_object_field;
    +use 0x2::iota;
    +use 0x2::object;
    +use 0x2::transfer;
    +
    + + + + + +## Resource `AliasOutput` + +Owned Object controlled by the Governor Address. + + +
    struct AliasOutput has key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + This is a "random" UID, not the AliasID from Stardust. +
    +
    +iota: balance::Balance<iota::IOTA> +
    +
    + The amount of IOTA coins held by the output. +
    +
    +native_tokens: bag::Bag +
    +
    + The Bag holds native tokens, key-ed by the stringified type of the asset. + Example: key: "0xabcded::soon::SOON", value: Balance<0xabcded::soon::SOON>. +
    +
    + + +
    + + + +## Constants + + + + +The Alias dynamic object field name. + + +
    const ALIAS_NAME: vector<u8> = [97, 108, 105, 97, 115];
    +
    + + + + + +## Function `extract_assets` + +The function extracts assets from a legacy AliasOutput. +- returns the IOTA Balance, +- the native tokens Bag, +- and the Alias object that persists the AliasID=ObjectID from Stardust. + + +
    public fun extract_assets(output: alias_output::AliasOutput): (balance::Balance<iota::IOTA>, bag::Bag, alias::Alias)
    +
    + + + +
    +Implementation + + +
    public fun extract_assets(mut output: AliasOutput): (Balance<IOTA>, Bag, Alias) {
    +    // Load the related alias object.
    +    let alias = load_alias(&mut output);
    +
    +    // Unpack the output into its basic part.
    +    let AliasOutput {
    +        id,
    +        iota,
    +        native_tokens
    +    } = output;
    +
    +    // Delete the output.
    +    object::delete(id);
    +
    +    (iota, native_tokens, alias)
    +}
    +
    + + + +
    + + + +## Function `receive` + +Utility function to receive an AliasOutput object in other Stardust modules. +Other modules in the Stardust package can call this function to receive an AliasOutput object (nft). + + +
    public(friend) fun receive(parent: &mut object::UID, output: transfer::Receiving<alias_output::AliasOutput>): alias_output::AliasOutput
    +
    + + + +
    +Implementation + + +
    public(package) fun receive(parent: &mut UID, output: Receiving<AliasOutput>) : AliasOutput {
    +    transfer::receive(parent, output)
    +}
    +
    + + + +
    + + + +## Function `attach_alias` + +Utility function to attach an Alias to an AliasOutput. + + +
    public fun attach_alias(output: &mut alias_output::AliasOutput, alias: alias::Alias)
    +
    + + + +
    +Implementation + + +
    public fun attach_alias(output: &mut AliasOutput, alias: Alias) {
    +    dynamic_object_field::add(&mut output.id, ALIAS_NAME, alias)
    +}
    +
    + + + +
    + + + +## Function `load_alias` + +Loads the Alias object from the dynamic object field. + + +
    fun load_alias(output: &mut alias_output::AliasOutput): alias::Alias
    +
    + + + +
    +Implementation + + +
    fun load_alias(output: &mut AliasOutput): Alias {
    +    dynamic_object_field::remove(&mut output.id, ALIAS_NAME)
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/stardust/basic_output.md b/crates/iota-framework/docs/stardust/basic_output.md new file mode 100644 index 00000000000..8f78d8c4842 --- /dev/null +++ b/crates/iota-framework/docs/stardust/basic_output.md @@ -0,0 +1,198 @@ +--- +title: Module `0x107a::basic_output` +--- + + + +- [Resource `BasicOutput`](#0x107a_basic_output_BasicOutput) +- [Function `extract_assets`](#0x107a_basic_output_extract_assets) +- [Function `receive`](#0x107a_basic_output_receive) + + +
    use 0x107a::expiration_unlock_condition;
    +use 0x107a::storage_deposit_return_unlock_condition;
    +use 0x107a::timelock_unlock_condition;
    +use 0x1::option;
    +use 0x2::bag;
    +use 0x2::balance;
    +use 0x2::iota;
    +use 0x2::object;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +
    + + + + + +## Resource `BasicOutput` + +A basic output that has unlock conditions/features. +- basic outputs with expiration unlock condition must be a shared object, since that's the only +way to handle the two possible addresses that can unlock the output. +- notice that there is no store ability and there is no custom transfer function: +- you can call extract_assets, +- or you can call receive in other models to receive a BasicOutput. + + +
    struct BasicOutput has key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + Hash of the outputId that was migrated. +
    +
    +iota: balance::Balance<iota::IOTA> +
    +
    + The amount of IOTA coins held by the output. +
    +
    +native_tokens: bag::Bag +
    +
    + The Bag holds native tokens, key-ed by the stringified type of the asset. + Example: key: "0xabcded::soon::SOON", value: Balance<0xabcded::soon::SOON>. +
    +
    +storage_deposit_return_uc: option::Option<storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition> +
    +
    + The storage deposit return unlock condition. +
    +
    +timelock_uc: option::Option<timelock_unlock_condition::TimelockUnlockCondition> +
    +
    + The timelock unlock condition. +
    +
    +expiration_uc: option::Option<expiration_unlock_condition::ExpirationUnlockCondition> +
    +
    + The expiration unlock condition. +
    +
    +metadata: option::Option<vector<u8>> +
    +
    + The metadata feature. +
    +
    +tag: option::Option<vector<u8>> +
    +
    + The tag feature. +
    +
    +sender: option::Option<address> +
    +
    + The sender feature. +
    +
    + + +
    + + + +## Function `extract_assets` + +Extract the assets stored inside the output, respecting the unlock conditions. +- The object will be deleted. +- The StorageDepositReturnUnlockCondition will return the deposit. +- Remaining assets (IOTA coins and native tokens) will be returned. + + +
    public fun extract_assets(output: basic_output::BasicOutput, ctx: &mut tx_context::TxContext): (balance::Balance<iota::IOTA>, bag::Bag)
    +
    + + + +
    +Implementation + + +
    public fun extract_assets(output: BasicOutput, ctx: &mut TxContext) : (Balance<IOTA>, Bag) {
    +    // Unpack the output into its basic part.
    +    let BasicOutput {
    +        id,
    +        iota: mut iota,
    +        native_tokens,
    +        storage_deposit_return_uc: mut storage_deposit_return_uc,
    +        timelock_uc: mut timelock_uc,
    +        expiration_uc: mut expiration_uc,
    +        sender: _,
    +        metadata: _,
    +        tag: _
    +    } = output;
    +
    +    // If the output has a timelock unlock condition, then we need to check if the timelock_uc has expired.
    +    if (timelock_uc.is_some()) {
    +        timelock_uc.extract().unlock(ctx);
    +    };
    +
    +    // If the output has an expiration unlock condition, then we need to check who can unlock the output.
    +    if (expiration_uc.is_some()) {
    +        expiration_uc.extract().unlock(ctx);
    +    };
    +
    +    // If the output has an storage deposit return unlock condition, then we need to return the deposit.
    +    if (storage_deposit_return_uc.is_some()) {
    +        storage_deposit_return_uc.extract().unlock(&mut iota, ctx);
    +    };
    +
    +    // Destroy the unlock conditions.
    +    option::destroy_none(timelock_uc);
    +    option::destroy_none(expiration_uc);
    +    option::destroy_none(storage_deposit_return_uc);
    +
    +    // Delete the output.
    +    object::delete(id);
    +
    +    return (iota, native_tokens)
    +}
    +
    + + + +
    + + + +## Function `receive` + +Utility function to receive a basic output in other stardust modules. +Since BasicOutput only has key, it can not be received via public_receive. +The private receiver must be implemented in its defining module (here). +Other modules in the Stardust package can call this function to receive a basic output (alias, NFT). + + +
    public(friend) fun receive(parent: &mut object::UID, output: transfer::Receiving<basic_output::BasicOutput>): basic_output::BasicOutput
    +
    + + + +
    +Implementation + + +
    public(package) fun receive(parent: &mut UID, output: Receiving<BasicOutput>) : BasicOutput {
    +    transfer::receive(parent, output)
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/stardust/capped_coin.md b/crates/iota-framework/docs/stardust/capped_coin.md similarity index 75% rename from crates/sui-framework/docs/stardust/capped_coin.md rename to crates/iota-framework/docs/stardust/capped_coin.md index 887111c6d59..1ab090469dc 100644 --- a/crates/sui-framework/docs/stardust/capped_coin.md +++ b/crates/iota-framework/docs/stardust/capped_coin.md @@ -21,10 +21,10 @@ title: Module `0x107a::capped_coin`
    use 0x1::ascii;
     use 0x1::string;
    -use 0x2::balance;
    -use 0x2::coin;
    -use 0x2::object;
    -use 0x2::tx_context;
    +use 0x2::balance;
    +use 0x2::coin;
    +use 0x2::object;
    +use 0x2::tx_context;
     
    @@ -47,7 +47,7 @@ The policy wrapper that ensures the supply of a Coin never exceeds
    -id: object::UID +id: object::UID
    @@ -59,7 +59,7 @@ The policy wrapper that ensures the supply of a Coin never exceeds The maximum supply.
    -treasury_cap: coin::TreasuryCap<T> +treasury_cap: coin::TreasuryCap<T>
    The wrapped TreasuryCap. @@ -93,7 +93,7 @@ Be careful, once you add a maximum supply you will not be able to change it or g This gives coin holders a guarantee that the maximum supply of that specific coin will never change. -
    public fun create_max_supply_policy<T>(treasury_cap: coin::TreasuryCap<T>, maximum_supply: u64, ctx: &mut tx_context::TxContext): capped_coin::MaxSupplyPolicy<T>
    +
    public fun create_max_supply_policy<T>(treasury_cap: coin::TreasuryCap<T>, maximum_supply: u64, ctx: &mut tx_context::TxContext): capped_coin::MaxSupplyPolicy<T>
     
    @@ -108,7 +108,7 @@ This gives coin holders a guarantee that the maximum supply of that specific coi ctx: &mut TxContext ): MaxSupplyPolicy<T> { MaxSupplyPolicy { - id: object::new(ctx), + id: object::new(ctx), maximum_supply, treasury_cap } @@ -136,7 +136,7 @@ Return the total number of T's in circulation.
    public fun total_supply<T>(policy: &MaxSupplyPolicy<T>): u64 {
    -    coin::total_supply(&policy.treasury_cap)
    +    coin::total_supply(&policy.treasury_cap)
     }
     
    @@ -151,7 +151,7 @@ Return the total number of T's in circulation. Get immutable reference to the treasury's Supply. -
    public fun supply_immut<T>(policy: &capped_coin::MaxSupplyPolicy<T>): &balance::Supply<T>
    +
    public fun supply_immut<T>(policy: &capped_coin::MaxSupplyPolicy<T>): &balance::Supply<T>
     
    @@ -161,7 +161,7 @@ Get immutable reference to the treasury's Supply.
    public fun supply_immut<T>(policy: &MaxSupplyPolicy<T>): &Supply<T> {
    -    coin::supply_immut(&policy.treasury_cap)
    +    coin::supply_immut(&policy.treasury_cap)
     }
     
    @@ -176,7 +176,7 @@ Get immutable reference to the treasury's Supply. Create a Coin worth value and increase the total supply in cap accordingly. -
    public fun mint<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, value: u64, ctx: &mut tx_context::TxContext): coin::Coin<T>
    +
    public fun mint<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, value: u64, ctx: &mut tx_context::TxContext): coin::Coin<T>
     
    @@ -191,7 +191,7 @@ Create a Coin worth value and increase the total suppl ctx: &mut TxContext ): Coin<T> { assert!(total_supply(policy) + value <= policy.maximum_supply, EMaximumSupplyReached); - coin::mint(&mut policy.treasury_cap, value, ctx) + coin::mint(&mut policy.treasury_cap, value, ctx) }
    @@ -207,7 +207,7 @@ Mint some amount of T as a Balance and increase the to Aborts if value + cap.total_supply >= U64_MAX. -
    public fun mint_balance<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, value: u64): balance::Balance<T>
    +
    public fun mint_balance<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, value: u64): balance::Balance<T>
     
    @@ -221,7 +221,7 @@ Aborts if value + cap.total_supply >= U64_MAXassert!(total_supply(policy) + value <= policy.maximum_supply, EMaximumSupplyReached); - coin::mint_balance(&mut policy.treasury_cap, value) + coin::mint_balance(&mut policy.treasury_cap, value) }
    @@ -236,7 +236,7 @@ Aborts if value + cap.total_supply >= U64_MAXc and decrease the total supply in cap accordingly. -
    public entry fun burn<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, c: coin::Coin<T>): u64
    +
    public entry fun burn<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, c: coin::Coin<T>): u64
     
    @@ -246,7 +246,7 @@ Destroy the coin c and decrease the total supply in cappublic entry fun burn<T>(policy: &mut MaxSupplyPolicy<T>, c: Coin<T>): u64 { - coin::burn(&mut policy.treasury_cap, c) + coin::burn(&mut policy.treasury_cap, c) }
    @@ -261,7 +261,7 @@ Destroy the coin c and decrease the total supply in capamount of Coin and send it to the recipient. Invokes mint(). -
    public fun mint_and_transfer<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, amount: u64, recipient: address, ctx: &mut tx_context::TxContext)
    +
    public fun mint_and_transfer<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, amount: u64, recipient: address, ctx: &mut tx_context::TxContext)
     
    @@ -277,7 +277,7 @@ Mint amount of Coin and send it to the recipient ctx: &mut TxContext ) { assert!(total_supply(policy) + amount <= policy.maximum_supply, EMaximumSupplyReached); - coin::mint_and_transfer(&mut policy.treasury_cap, amount, recipient, ctx) + coin::mint_and_transfer(&mut policy.treasury_cap, amount, recipient, ctx) }
    @@ -292,7 +292,7 @@ Mint amount of Coin and send it to the recipient Update the name of the coin in the CoinMetadata. -
    public fun update_name<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, metadata: &mut coin::CoinMetadata<T>, name: string::String)
    +
    public fun update_name<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, metadata: &mut coin::CoinMetadata<T>, name: string::String)
     
    @@ -306,7 +306,7 @@ Update the name of the coin in the CoinMetadata. metadata: &mut CoinMetadata<T>, name: string::String ) { - coin::update_name(&policy.treasury_cap, metadata, name) + coin::update_name(&policy.treasury_cap, metadata, name) }
    @@ -321,7 +321,7 @@ Update the name of the coin in the CoinMetadata. Update the symbol of the coin in the CoinMetadata. -
    public fun update_symbol<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, metadata: &mut coin::CoinMetadata<T>, symbol: ascii::String)
    +
    public fun update_symbol<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, metadata: &mut coin::CoinMetadata<T>, symbol: ascii::String)
     
    @@ -335,7 +335,7 @@ Update the symbol of the coin in the CoinMetadata. metadata: &mut CoinMetadata<T>, symbol: ascii::String ) { - coin::update_symbol(&policy.treasury_cap, metadata, symbol) + coin::update_symbol(&policy.treasury_cap, metadata, symbol) }
    @@ -350,7 +350,7 @@ Update the symbol of the coin in the CoinMetadata. Update the description of the coin in the CoinMetadata. -
    public fun update_description<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, metadata: &mut coin::CoinMetadata<T>, description: string::String)
    +
    public fun update_description<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, metadata: &mut coin::CoinMetadata<T>, description: string::String)
     
    @@ -364,7 +364,7 @@ Update the description of the coin in the CoinMetadata metadata: &mut CoinMetadata<T>, description: string::String ) { - coin::update_description(&policy.treasury_cap, metadata, description) + coin::update_description(&policy.treasury_cap, metadata, description) }
    @@ -376,10 +376,10 @@ Update the description of the coin in the CoinMetadata ## Function `update_icon_url` -Update the url of the coin in the CoinMetadata +Update the url of the coin in the CoinMetadata -
    public fun update_icon_url<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, metadata: &mut coin::CoinMetadata<T>, url: ascii::String)
    +
    public fun update_icon_url<T>(policy: &mut capped_coin::MaxSupplyPolicy<T>, metadata: &mut coin::CoinMetadata<T>, url: ascii::String)
     
    @@ -391,9 +391,9 @@ Update the url of the
    public fun update_icon_url<T>(
         policy: &mut MaxSupplyPolicy<T>,
         metadata: &mut CoinMetadata<T>,
    -    url: ascii::String
    +    url: ascii::String
     ) {
    -    coin::update_icon_url(&policy.treasury_cap, metadata, url)
    +    coin::update_icon_url(&policy.treasury_cap, metadata, url)
     }
     
    diff --git a/crates/sui-framework/docs/stardust/expiration_unlock_condition.md b/crates/iota-framework/docs/stardust/expiration_unlock_condition.md similarity index 93% rename from crates/sui-framework/docs/stardust/expiration_unlock_condition.md rename to crates/iota-framework/docs/stardust/expiration_unlock_condition.md index 77156b45837..637fc7d021d 100644 --- a/crates/sui-framework/docs/stardust/expiration_unlock_condition.md +++ b/crates/iota-framework/docs/stardust/expiration_unlock_condition.md @@ -13,7 +13,7 @@ title: Module `0x107a::expiration_unlock_condition` - [Function `unix_time`](#0x107a_expiration_unlock_condition_unix_time) -
    use 0x2::tx_context;
    +
    use 0x2::tx_context;
     
    @@ -80,7 +80,7 @@ The output can not be unlocked by the sender error. Check the unlock condition. -
    public fun unlock(condition: expiration_unlock_condition::ExpirationUnlockCondition, ctx: &mut tx_context::TxContext)
    +
    public fun unlock(condition: expiration_unlock_condition::ExpirationUnlockCondition, ctx: &mut tx_context::TxContext)
     
    @@ -113,7 +113,7 @@ Check the unlock condition. Return the address that can unlock the related output. -
    public fun can_be_unlocked_by(condition: &expiration_unlock_condition::ExpirationUnlockCondition, ctx: &tx_context::TxContext): address
    +
    public fun can_be_unlocked_by(condition: &expiration_unlock_condition::ExpirationUnlockCondition, ctx: &tx_context::TxContext): address
     
    @@ -124,7 +124,7 @@ Return the address that can unlock the related output.
    public fun can_be_unlocked_by(condition: &ExpirationUnlockCondition, ctx: &TxContext): address {
         // Unix time in seconds.
    -    let current_time = ((tx_context::epoch_timestamp_ms(ctx) / 1000) as u32);
    +    let current_time = ((tx_context::epoch_timestamp_ms(ctx) / 1000) as u32);
     
         if (condition.unix_time() <= current_time) {
             condition.return_address()
    diff --git a/crates/sui-framework/docs/stardust/irc27.md b/crates/iota-framework/docs/stardust/irc27.md
    similarity index 88%
    rename from crates/sui-framework/docs/stardust/irc27.md
    rename to crates/iota-framework/docs/stardust/irc27.md
    index 26c18ed0ec8..12757934eed 100644
    --- a/crates/sui-framework/docs/stardust/irc27.md
    +++ b/crates/iota-framework/docs/stardust/irc27.md
    @@ -21,8 +21,8 @@ title: Module `0x107a::irc27`
     
    use 0x1::fixed_point32;
     use 0x1::option;
     use 0x1::string;
    -use 0x2::url;
    -use 0x2::vec_map;
    +use 0x2::url;
    +use 0x2::vec_map;
     
    @@ -64,7 +64,7 @@ The IRC27 NFT metadata standard schema. - Documents: application/pdf, text/plain, etc.
    -uri: url::Url +uri: url::Url
    URL pointing to the NFT file location. @@ -82,7 +82,7 @@ The IRC27 NFT metadata standard schema. The human-readable collection name of the NFT.
    -royalties: vec_map::VecMap<address, fixed_point32::FixedPoint32> +royalties: vec_map::VecMap<address, fixed_point32::FixedPoint32>
    Royalty payment addresses mapped to the payout percentage. @@ -102,13 +102,13 @@ The IRC27 NFT metadata standard schema. The human-readable description of the NFT.
    -attributes: vec_map::VecMap<string::String, string::String> +attributes: vec_map::VecMap<string::String, string::String>
    Additional attributes which follow [OpenSea Metadata standards](https://docs.opensea.io/docs/metadata-standards).
    -non_standard_fields: vec_map::VecMap<string::String, string::String> +non_standard_fields: vec_map::VecMap<string::String, string::String>
    Legacy non-standard metadata fields. @@ -175,7 +175,7 @@ Get the metadata's media_type. Get the metadata's uri. -
    public fun uri(irc27: &irc27::Irc27Metadata): &url::Url
    +
    public fun uri(irc27: &irc27::Irc27Metadata): &url::Url
     
    @@ -250,7 +250,7 @@ Get the metadata's collection_name. Get the metadata's royalties. -
    public fun royalties(irc27: &irc27::Irc27Metadata): &vec_map::VecMap<address, fixed_point32::FixedPoint32>
    +
    public fun royalties(irc27: &irc27::Irc27Metadata): &vec_map::VecMap<address, fixed_point32::FixedPoint32>
     
    @@ -325,7 +325,7 @@ Get the metadata's description. Get the metadata's attributes. -
    public fun attributes(irc27: &irc27::Irc27Metadata): &vec_map::VecMap<string::String, string::String>
    +
    public fun attributes(irc27: &irc27::Irc27Metadata): &vec_map::VecMap<string::String, string::String>
     
    @@ -350,7 +350,7 @@ Get the metadata's attributes. Get the metadata's non_standard_fields. -
    public fun non_standard_fields(irc27: &irc27::Irc27Metadata): &vec_map::VecMap<string::String, string::String>
    +
    public fun non_standard_fields(irc27: &irc27::Irc27Metadata): &vec_map::VecMap<string::String, string::String>
     
    diff --git a/crates/sui-framework/docs/stardust/nft.md b/crates/iota-framework/docs/stardust/nft.md similarity index 83% rename from crates/sui-framework/docs/stardust/nft.md rename to crates/iota-framework/docs/stardust/nft.md index 34a74d4b0af..97779e5e400 100644 --- a/crates/sui-framework/docs/stardust/nft.md +++ b/crates/iota-framework/docs/stardust/nft.md @@ -19,11 +19,11 @@ title: Module `0x107a::nft`
    use 0x107a::irc27;
     use 0x1::option;
     use 0x1::string;
    -use 0x2::display;
    -use 0x2::object;
    -use 0x2::package;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    +use 0x2::display;
    +use 0x2::object;
    +use 0x2::package;
    +use 0x2::transfer;
    +use 0x2::tx_context;
     
    @@ -74,7 +74,7 @@ The Stardust NFT representation.
    -id: object::UID +id: object::UID
    The Nft's ID is nested from Stardust. @@ -122,7 +122,7 @@ The Stardust NFT representation. The Nft module initializer. -
    fun init(otw: nft::NFT, ctx: &mut tx_context::TxContext)
    +
    fun init(otw: nft::NFT, ctx: &mut tx_context::TxContext)
     
    @@ -133,11 +133,11 @@ The Nft module initializer.
    fun init(otw: NFT, ctx: &mut TxContext) {
         // Claim the module publisher.
    -    let publisher = package::claim(otw, ctx);
    +    let publisher = package::claim(otw, ctx);
     
    -    // Build a `Display` object.
    +    // Build a `Display` object.
         let keys = vector[
    -        // The Sui standard fields.
    +        // The Iota standard fields.
             string::utf8(b"name"),
             string::utf8(b"image_url"),
             string::utf8(b"description"),
    @@ -153,7 +153,7 @@ The Nft module initializer.
         ];
     
         let values = vector[
    -        // The Sui standard fields.
    +        // The Iota standard fields.
             string::utf8(b"{immutable_metadata.name}"),
             string::utf8(b"{immutable_metadata.uri}"),
             string::utf8(b"{immutable_metadata.description}"),
    @@ -168,7 +168,7 @@ The Nft module initializer.
             string::utf8(b"{immutable_issuer}"),
         ];
     
    -    let mut display = display::new_with_fields<Nft>(
    +    let mut display = display::new_with_fields<Nft>(
             &publisher,
             keys,
             values,
    @@ -176,13 +176,13 @@ The Nft module initializer.
         );
     
         // Commit the first version of `Display` to apply changes.
    -    display.update_version();
    +    display.update_version();
     
    -    // Burn the publisher object.
    -    package::burn_publisher(publisher);
    +    // Burn the publisher object.
    +    package::burn_publisher(publisher);
     
    -    // Freeze the display object.
    -    sui::transfer::public_freeze_object(display);
    +    // Freeze the display object.
    +    iota::transfer::public_freeze_object(display);
     }
     
    @@ -218,7 +218,7 @@ Permanently destroy an Nft obje irc27::destroy(immutable_metadata); - object::delete(id); + object::delete(id); }
    @@ -358,7 +358,7 @@ Get the Nft's immutable_metadata. Get the Nft's id. -
    public(friend) fun id(self: &mut nft::Nft): &mut object::UID
    +
    public(friend) fun id(self: &mut nft::Nft): &mut object::UID
     
    @@ -367,7 +367,7 @@ Get the Nft's id. Implementation -
    public(package) fun id(self: &mut Nft): &mut UID {
    +
    public(package) fun id(self: &mut Nft): &mut UID {
         &mut self.id
     }
     
    diff --git a/crates/iota-framework/docs/stardust/nft_output.md b/crates/iota-framework/docs/stardust/nft_output.md new file mode 100644 index 00000000000..407e0f94578 --- /dev/null +++ b/crates/iota-framework/docs/stardust/nft_output.md @@ -0,0 +1,239 @@ +--- +title: Module `0x107a::nft_output` +--- + + + +- [Resource `NftOutput`](#0x107a_nft_output_NftOutput) +- [Constants](#@Constants_0) +- [Function `extract_assets`](#0x107a_nft_output_extract_assets) +- [Function `load_nft`](#0x107a_nft_output_load_nft) +- [Function `attach_nft`](#0x107a_nft_output_attach_nft) +- [Function `receive`](#0x107a_nft_output_receive) + + +
    use 0x107a::expiration_unlock_condition;
    +use 0x107a::nft;
    +use 0x107a::storage_deposit_return_unlock_condition;
    +use 0x107a::timelock_unlock_condition;
    +use 0x1::option;
    +use 0x2::bag;
    +use 0x2::balance;
    +use 0x2::dynamic_object_field;
    +use 0x2::iota;
    +use 0x2::object;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +
    + + + + + +## Resource `NftOutput` + +The Stardust NFT output representation. + + +
    struct NftOutput has key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + This is a "random" UID, not the NFTID from Stardust. +
    +
    +iota: balance::Balance<iota::IOTA> +
    +
    + The amount of IOTA tokens held by the output. +
    +
    +native_tokens: bag::Bag +
    +
    + The Bag holds native tokens, key-ed by the stringified type of the asset. + Example: key: "0xabcded::soon::SOON", value: Balance<0xabcded::soon::SOON>. +
    +
    +storage_deposit_return_uc: option::Option<storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition> +
    +
    + The storage deposit return unlock condition. +
    +
    +timelock_uc: option::Option<timelock_unlock_condition::TimelockUnlockCondition> +
    +
    + The timelock unlock condition. +
    +
    +expiration_uc: option::Option<expiration_unlock_condition::ExpirationUnlockCondition> +
    +
    + The expiration unlock condition. +
    +
    + + +
    + + + +## Constants + + + + +The NFT dynamic field name. + + +
    const NFT_NAME: vector<u8> = [110, 102, 116];
    +
    + + + + + +## Function `extract_assets` + +The function extracts assets from a legacy NFT output. + + +
    public fun extract_assets(output: nft_output::NftOutput, ctx: &mut tx_context::TxContext): (balance::Balance<iota::IOTA>, bag::Bag, nft::Nft)
    +
    + + + +
    +Implementation + + +
    public fun extract_assets(mut output: NftOutput, ctx: &mut TxContext): (Balance<IOTA>, Bag, Nft) {
    +    // Load the related Nft object.
    +    let nft = load_nft(&mut output);
    +
    +    // Unpuck the output.
    +    let NftOutput {
    +        id,
    +        iota: mut iota,
    +        native_tokens,
    +        storage_deposit_return_uc: mut storage_deposit_return_uc,
    +        timelock_uc: mut timelock_uc,
    +        expiration_uc: mut expiration_uc
    +    } = output;
    +
    +    // If the output has a timelock unlock condition, then we need to check if the timelock_uc has expired.
    +    if (timelock_uc.is_some()) {
    +        timelock_uc.extract().unlock(ctx);
    +    };
    +
    +    // If the output has an expiration unlock condition, then we need to check who can unlock the output.
    +    if (expiration_uc.is_some()) {
    +        expiration_uc.extract().unlock(ctx);
    +    };
    +
    +    // If the output has a storage deposit return unlock condition, then we need to return the deposit.
    +    if (storage_deposit_return_uc.is_some()) {
    +        storage_deposit_return_uc.extract().unlock(&mut iota, ctx);
    +    };
    +
    +    // Destroy the output.
    +    option::destroy_none(timelock_uc);
    +    option::destroy_none(expiration_uc);
    +    option::destroy_none(storage_deposit_return_uc);
    +
    +    object::delete(id);
    +
    +    return (iota, native_tokens, nft)
    +}
    +
    + + + +
    + + + +## Function `load_nft` + +Loads the related Nft object. + + +
    fun load_nft(output: &mut nft_output::NftOutput): nft::Nft
    +
    + + + +
    +Implementation + + +
    fun load_nft(output: &mut NftOutput): Nft {
    +    dynamic_object_field::remove(&mut output.id, NFT_NAME)
    +}
    +
    + + + +
    + + + +## Function `attach_nft` + +Utility function to attach an Alias to an AliasOutput. + + +
    public fun attach_nft(output: &mut nft_output::NftOutput, nft: nft::Nft)
    +
    + + + +
    +Implementation + + +
    public fun attach_nft(output: &mut NftOutput, nft: Nft) {
    +    dynamic_object_field::add(&mut output.id, NFT_NAME, nft)
    +}
    +
    + + + +
    + + + +## Function `receive` + +Utility function to receive an NftOutput in other Stardust modules. +Other modules in the stardust package can call this function to receive an NftOutput (alias). + + +
    public(friend) fun receive(parent: &mut object::UID, nft: transfer::Receiving<nft_output::NftOutput>): nft_output::NftOutput
    +
    + + + +
    +Implementation + + +
    public(package) fun receive(parent: &mut UID, nft: Receiving<NftOutput>) : NftOutput {
    +    transfer::receive(parent, nft)
    +}
    +
    + + + +
    diff --git a/crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md b/crates/iota-framework/docs/stardust/storage_deposit_return_unlock_condition.md similarity index 83% rename from crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md rename to crates/iota-framework/docs/stardust/storage_deposit_return_unlock_condition.md index e62df2cdf8d..623067c1e81 100644 --- a/crates/sui-framework/docs/stardust/storage_deposit_return_unlock_condition.md +++ b/crates/iota-framework/docs/stardust/storage_deposit_return_unlock_condition.md @@ -10,11 +10,11 @@ title: Module `0x107a::storage_deposit_return_unlock_condition` - [Function `return_amount`](#0x107a_storage_deposit_return_unlock_condition_return_amount) -
    use 0x2::balance;
    -use 0x2::coin;
    -use 0x2::sui;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    +
    use 0x2::balance;
    +use 0x2::coin;
    +use 0x2::iota;
    +use 0x2::transfer;
    +use 0x2::tx_context;
     
    @@ -60,7 +60,7 @@ The Stardust storage deposit return unlock condition. Check the unlock condition. -
    public fun unlock(condition: storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition, funding: &mut balance::Balance<sui::SUI>, ctx: &mut tx_context::TxContext)
    +
    public fun unlock(condition: storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition, funding: &mut balance::Balance<iota::IOTA>, ctx: &mut tx_context::TxContext)
     
    @@ -69,11 +69,11 @@ Check the unlock condition. Implementation -
    public fun unlock(condition: StorageDepositReturnUnlockCondition, funding: &mut Balance<SUI>, ctx: &mut TxContext) {
    +
    public fun unlock(condition: StorageDepositReturnUnlockCondition, funding: &mut Balance<IOTA>, ctx: &mut TxContext) {
         // Aborts if `funding` is not enough.
         let return_balance = funding.split(condition.return_amount());
     
    -    // Recipient will need to transfer the coin to a normal ed25519 address instead of legacy.
    +    // Recipient will need to transfer the coin to a normal ed25519 address instead of legacy.
         public_transfer(from_balance(return_balance, ctx), condition.return_address());
     
         let StorageDepositReturnUnlockCondition {
    diff --git a/crates/sui-framework/docs/stardust/timelock_unlock_condition.md b/crates/iota-framework/docs/stardust/timelock_unlock_condition.md
    similarity index 90%
    rename from crates/sui-framework/docs/stardust/timelock_unlock_condition.md
    rename to crates/iota-framework/docs/stardust/timelock_unlock_condition.md
    index 4de6931ac98..51b0a5a7cb0 100644
    --- a/crates/sui-framework/docs/stardust/timelock_unlock_condition.md
    +++ b/crates/iota-framework/docs/stardust/timelock_unlock_condition.md
    @@ -11,7 +11,7 @@ title: Module `0x107a::timelock_unlock_condition`
     -  [Function `unix_time`](#0x107a_timelock_unlock_condition_unix_time)
     
     
    -
    use 0x2::tx_context;
    +
    use 0x2::tx_context;
     
    @@ -66,7 +66,7 @@ The timelock is not expired error. Check the unlock condition. -
    public fun unlock(condition: timelock_unlock_condition::TimelockUnlockCondition, ctx: &tx_context::TxContext)
    +
    public fun unlock(condition: timelock_unlock_condition::TimelockUnlockCondition, ctx: &tx_context::TxContext)
     
    @@ -95,7 +95,7 @@ Check the unlock condition. Check if the output is locked by the Timelock condition. -
    public fun is_timelocked(condition: &timelock_unlock_condition::TimelockUnlockCondition, ctx: &tx_context::TxContext): bool
    +
    public fun is_timelocked(condition: &timelock_unlock_condition::TimelockUnlockCondition, ctx: &tx_context::TxContext): bool
     
    @@ -105,7 +105,7 @@ Check if the output is locked by the Timelock condition.
    public fun is_timelocked(condition: &TimelockUnlockCondition, ctx: &TxContext): bool {
    -    condition.unix_time() > ((tx_context::epoch_timestamp_ms(ctx) / 1000) as u32)
    +    condition.unix_time() > ((tx_context::epoch_timestamp_ms(ctx) / 1000) as u32)
     }
     
    diff --git a/crates/iota-framework/docs/stardust/utilities.md b/crates/iota-framework/docs/stardust/utilities.md new file mode 100644 index 00000000000..cc1da4080d1 --- /dev/null +++ b/crates/iota-framework/docs/stardust/utilities.md @@ -0,0 +1,125 @@ +--- +title: Module `0x107a::utilities` +--- + + + +- [Constants](#@Constants_0) +- [Function `extract_and_send_to`](#0x107a_utilities_extract_and_send_to) +- [Function `extract`](#0x107a_utilities_extract) +- [Function `extract_`](#0x107a_utilities_extract_) + + +
    use 0x1::ascii;
    +use 0x1::type_name;
    +use 0x2::bag;
    +use 0x2::balance;
    +use 0x2::coin;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +
    + + + + + +## Constants + + + + +Returned when trying to extract a Balance<T> from a Bag and the balance is zero. + + +
    const EZeroNativeTokenBalance: u64 = 0;
    +
    + + + + + +## Function `extract_and_send_to` + +Extract a Balance<T> from a Bag, create a Coin out of it and send it to the address. +NOTE: We return the Bag by value so the function can be called repeatedly in a PTB. + + +
    public fun extract_and_send_to<T>(bag: bag::Bag, to: address, ctx: &mut tx_context::TxContext): bag::Bag
    +
    + + + +
    +Implementation + + +
    public fun extract_and_send_to<T>(mut bag: Bag, to: address, ctx: &mut TxContext): Bag {
    +    let coin = coin::from_balance(extract_<T>(&mut bag), ctx);
    +    transfer::public_transfer(coin, to);
    +    bag
    +}
    +
    + + + +
    + + + +## Function `extract` + +Extract a Balance<T> from a Bag and return it. Caller can decide what to do with it. +NOTE: We return the Bag by value so the function can be called repeatedly in a PTB. + + +
    public fun extract<T>(bag: bag::Bag): (bag::Bag, balance::Balance<T>)
    +
    + + + +
    +Implementation + + +
    public fun extract<T>(mut bag: Bag): (Bag, Balance<T>) {
    +    let balance = extract_<T>(&mut bag);
    +    (bag, balance)
    +}
    +
    + + + +
    + + + +## Function `extract_` + +Get a Balance<T> from a Bag. +Aborts if the balance is zero or if there is no balance for the type T. + + +
    fun extract_<T>(bag: &mut bag::Bag): balance::Balance<T>
    +
    + + + +
    +Implementation + + +
    fun extract_<T>(bag: &mut Bag): Balance<T> {
    +    let key = type_name::get<T>().into_string();
    +
    +    // This call aborts if the key doesn't exist.
    +    let balance : Balance<T> = bag.remove(key);
    +
    +    assert!(balance.value() != 0, EZeroNativeTokenBalance);
    +
    +    balance
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/timelock/labeler.md b/crates/iota-framework/docs/timelock/labeler.md new file mode 100644 index 00000000000..28e809f4389 --- /dev/null +++ b/crates/iota-framework/docs/timelock/labeler.md @@ -0,0 +1,152 @@ +--- +title: Module `0x10cf::labeler` +--- + + + +- [Resource `LabelerCap`](#0x10cf_labeler_LabelerCap) +- [Constants](#@Constants_0) +- [Function `create_labeler_cap`](#0x10cf_labeler_create_labeler_cap) +- [Function `destroy_labeler_cap`](#0x10cf_labeler_destroy_labeler_cap) +- [Function `type_name`](#0x10cf_labeler_type_name) + + +
    use 0x1::ascii;
    +use 0x1::string;
    +use 0x1::type_name;
    +use 0x2::object;
    +use 0x2::tx_context;
    +use 0x2::types;
    +
    + + + + + +## Resource `LabelerCap` + +LabelerCap allows to create labels of the specific type L. +Can be publicly transferred like any other object. + + +
    struct LabelerCap<L> has store, key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    + + +
    + + + +## Constants + + + + +Error code for when a type passed to the create_labeler_cap function is not a one-time witness. + + +
    const ENotOneTimeWitness: u64 = 0;
    +
    + + + + + +## Function `create_labeler_cap` + +Create a LabelerCap instance. +Can be created only by consuming a one time witness. + + +
    public fun create_labeler_cap<L: drop>(witness: L, ctx: &mut tx_context::TxContext): labeler::LabelerCap<L>
    +
    + + + +
    +Implementation + + +
    public fun create_labeler_cap<L: drop>(witness: L, ctx: &mut TxContext): LabelerCap<L> {
    +    assert!(types::is_one_time_witness(&witness), ENotOneTimeWitness);
    +
    +    LabelerCap<L> {
    +        id: object::new(ctx),
    +    }
    +}
    +
    + + + +
    + + + +## Function `destroy_labeler_cap` + +Delete a LabelerCap instance. +If a capability is destroyed, it is impossible to add the related labels. + + +
    public fun destroy_labeler_cap<L>(cap: labeler::LabelerCap<L>)
    +
    + + + +
    +Implementation + + +
    public fun destroy_labeler_cap<L>(cap: LabelerCap<L>) {
    +    let LabelerCap<L> {
    +        id,
    +    } = cap;
    +
    +    object::delete(id);
    +}
    +
    + + + +
    + + + +## Function `type_name` + +Return a fully qualified type name with the original package IDs +that is used as type related a label value. + + +
    public(friend) fun type_name<L>(): string::String
    +
    + + + +
    +Implementation + + +
    public(package) fun type_name<L>(): String {
    +    string::from_ascii(std::type_name::get_with_original_ids<L>().into_string())
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/timelock/stardust_upgrade_label.md b/crates/iota-framework/docs/timelock/stardust_upgrade_label.md new file mode 100644 index 00000000000..a1ae08af601 --- /dev/null +++ b/crates/iota-framework/docs/timelock/stardust_upgrade_label.md @@ -0,0 +1,42 @@ +--- +title: Module `0x10cf::stardust_upgrade_label` +--- + +All the vested rewards migrated from Stardust are labeled with this label. +It can not be added to an object later after the migration. + + +- [Struct `STARDUST_UPGRADE_LABEL`](#0x10cf_stardust_upgrade_label_STARDUST_UPGRADE_LABEL) + + +
    + + + + + +## Struct `STARDUST_UPGRADE_LABEL` + +Name of the label. + + +
    struct STARDUST_UPGRADE_LABEL has drop
    +
    + + + +
    +Fields + + +
    +
    +dummy_field: bool +
    +
    + +
    +
    + + +
    diff --git a/crates/iota-framework/docs/timelock/timelock.md b/crates/iota-framework/docs/timelock/timelock.md new file mode 100644 index 00000000000..d90c43e6692 --- /dev/null +++ b/crates/iota-framework/docs/timelock/timelock.md @@ -0,0 +1,519 @@ +--- +title: Module `0x10cf::timelock` +--- + +A timelock implementation. + + +- [Resource `TimeLock`](#0x10cf_timelock_TimeLock) +- [Constants](#@Constants_0) +- [Function `lock`](#0x10cf_timelock_lock) +- [Function `lock_with_label`](#0x10cf_timelock_lock_with_label) +- [Function `unlock`](#0x10cf_timelock_unlock) +- [Function `expiration_timestamp_ms`](#0x10cf_timelock_expiration_timestamp_ms) +- [Function `is_locked`](#0x10cf_timelock_is_locked) +- [Function `remaining_time`](#0x10cf_timelock_remaining_time) +- [Function `locked`](#0x10cf_timelock_locked) +- [Function `locked_mut`](#0x10cf_timelock_locked_mut) +- [Function `label`](#0x10cf_timelock_label) +- [Function `is_labeled_with`](#0x10cf_timelock_is_labeled_with) +- [Function `pack`](#0x10cf_timelock_pack) +- [Function `unpack`](#0x10cf_timelock_unpack) +- [Function `transfer`](#0x10cf_timelock_transfer) +- [Function `check_expiration_timestamp_ms`](#0x10cf_timelock_check_expiration_timestamp_ms) + + +
    use 0x10cf::labeler;
    +use 0x1::option;
    +use 0x1::string;
    +use 0x2::object;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +
    + + + + + +## Resource `TimeLock` + +TimeLock struct that holds a locked object. + + +
    struct TimeLock<T: store> has key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +locked: T +
    +
    + The locked object. +
    +
    +expiration_timestamp_ms: u64 +
    +
    + This is the epoch time stamp of when the lock expires. +
    +
    +label: option::Option<string::String> +
    +
    + Timelock related label. +
    +
    + + +
    + + + +## Constants + + + + +Error code for when the expire timestamp of the lock is in the past. + + +
    const EExpireEpochIsPast: u64 = 0;
    +
    + + + + + +Error code for when the lock has not expired yet. + + +
    const ENotExpiredYet: u64 = 1;
    +
    + + + + + +## Function `lock` + +Function to lock an object till a unix timestamp in milliseconds. + + +
    public fun lock<T: store>(locked: T, expiration_timestamp_ms: u64, ctx: &mut tx_context::TxContext): timelock::TimeLock<T>
    +
    + + + +
    +Implementation + + +
    public fun lock<T: store>(locked: T, expiration_timestamp_ms: u64, ctx: &mut TxContext): TimeLock<T> {
    +    // Check that `expiration_timestamp_ms` is valid.
    +    check_expiration_timestamp_ms(expiration_timestamp_ms, ctx);
    +
    +    // Create a timelock.
    +    pack(locked, expiration_timestamp_ms, option::none(), ctx)
    +}
    +
    + + + +
    + + + +## Function `lock_with_label` + +Function to lock a labeled object till a unix timestamp in milliseconds. + + +
    public fun lock_with_label<T: store, L>(_: &labeler::LabelerCap<L>, locked: T, expiration_timestamp_ms: u64, ctx: &mut tx_context::TxContext): timelock::TimeLock<T>
    +
    + + + +
    +Implementation + + +
    public fun lock_with_label<T: store, L>(
    +    _: &LabelerCap<L>,
    +    locked: T,
    +    expiration_timestamp_ms: u64,
    +    ctx: &mut TxContext
    +): TimeLock<T> {
    +    // Check that `expiration_timestamp_ms` is valid.
    +    check_expiration_timestamp_ms(expiration_timestamp_ms, ctx);
    +
    +    // Calculate a label value.
    +    let label = labeler::type_name<L>();
    +
    +    // Create a labeled timelock.
    +    pack(locked, expiration_timestamp_ms, option::some(label), ctx)
    +}
    +
    + + + +
    + + + +## Function `unlock` + +Function to unlock the object from a TimeLock. + + +
    public fun unlock<T: store>(self: timelock::TimeLock<T>, ctx: &tx_context::TxContext): T
    +
    + + + +
    +Implementation + + +
    public fun unlock<T: store>(self: TimeLock<T>, ctx: &TxContext): T {
    +    // Unpack the timelock.
    +    let (locked, expiration_timestamp_ms, _) = unpack(self);
    +
    +    // Check if the lock has expired.
    +    assert!(expiration_timestamp_ms <= ctx.epoch_timestamp_ms(), ENotExpiredYet);
    +
    +    locked
    +}
    +
    + + + +
    + + + +## Function `expiration_timestamp_ms` + +Function to get the expiration timestamp of a TimeLock. + + +
    public fun expiration_timestamp_ms<T: store>(self: &timelock::TimeLock<T>): u64
    +
    + + + +
    +Implementation + + +
    public fun expiration_timestamp_ms<T: store>(self: &TimeLock<T>): u64 {
    +    self.expiration_timestamp_ms
    +}
    +
    + + + +
    + + + +## Function `is_locked` + +Function to check if a TimeLock is locked. + + +
    public fun is_locked<T: store>(self: &timelock::TimeLock<T>, ctx: &tx_context::TxContext): bool
    +
    + + + +
    +Implementation + + +
    public fun is_locked<T: store>(self: &TimeLock<T>, ctx: &TxContext): bool {
    +    self.remaining_time(ctx) > 0
    +}
    +
    + + + +
    + + + +## Function `remaining_time` + +Function to get the remaining time of a TimeLock. +Returns 0 if the lock has expired. + + +
    public fun remaining_time<T: store>(self: &timelock::TimeLock<T>, ctx: &tx_context::TxContext): u64
    +
    + + + +
    +Implementation + + +
    public fun remaining_time<T: store>(self: &TimeLock<T>, ctx: &TxContext): u64 {
    +    // Get the epoch timestamp.
    +    let current_timestamp_ms = ctx.epoch_timestamp_ms();
    +
    +    // Check if the lock has expired.
    +    if (self.expiration_timestamp_ms < current_timestamp_ms) {
    +        return 0
    +    };
    +
    +    // Calculate the remaining time.
    +    self.expiration_timestamp_ms - current_timestamp_ms
    +}
    +
    + + + +
    + + + +## Function `locked` + +Function to get the locked object of a TimeLock. + + +
    public fun locked<T: store>(self: &timelock::TimeLock<T>): &T
    +
    + + + +
    +Implementation + + +
    public fun locked<T: store>(self: &TimeLock<T>): &T {
    +    &self.locked
    +}
    +
    + + + +
    + + + +## Function `locked_mut` + +Function to get a mutable reference to the locked object of a TimeLock. +Must not be callable from the outside, as one could modify the locked object. + + +
    public(friend) fun locked_mut<T: store>(self: &mut timelock::TimeLock<T>): &mut T
    +
    + + + +
    +Implementation + + +
    public(package) fun locked_mut<T: store>(self: &mut TimeLock<T>): &mut T {
    +    &mut self.locked
    +}
    +
    + + + +
    + + + +## Function `label` + +Function to get the label of a TimeLock. + + +
    public fun label<T: store>(self: &timelock::TimeLock<T>): option::Option<string::String>
    +
    + + + +
    +Implementation + + +
    public fun label<T: store>(self: &TimeLock<T>): Option<String> {
    +    self.label
    +}
    +
    + + + +
    + + + +## Function `is_labeled_with` + +Check if a TimeLock is labeled with the type L. + + +
    public fun is_labeled_with<T: store, L>(self: &timelock::TimeLock<T>): bool
    +
    + + + +
    +Implementation + + +
    public fun is_labeled_with<T: store, L>(self: &TimeLock<T>): bool {
    +    if (self.label.is_some()) {
    +        self.label.borrow() == labeler::type_name<L>()
    +    }
    +    else {
    +        false
    +    }
    +}
    +
    + + + +
    + + + +## Function `pack` + +A utility function to pack a TimeLock. + + +
    public(friend) fun pack<T: store>(locked: T, expiration_timestamp_ms: u64, label: option::Option<string::String>, ctx: &mut tx_context::TxContext): timelock::TimeLock<T>
    +
    + + + +
    +Implementation + + +
    public(package) fun pack<T: store>(
    +    locked: T,
    +    expiration_timestamp_ms: u64,
    +    label: Option<String>,
    +    ctx: &mut TxContext): TimeLock<T>
    +{
    +    // Create a timelock.
    +    TimeLock {
    +        id: object::new(ctx),
    +        locked,
    +        expiration_timestamp_ms,
    +        label,
    +    }
    +}
    +
    + + + +
    + + + +## Function `unpack` + +An utility function to unpack a TimeLock. + + +
    public(friend) fun unpack<T: store>(lock: timelock::TimeLock<T>): (T, u64, option::Option<string::String>)
    +
    + + + +
    +Implementation + + +
    public(package) fun unpack<T: store>(lock: TimeLock<T>): (T, u64, Option<String>) {
    +    // Unpack the timelock.
    +    let TimeLock {
    +        id,
    +        locked,
    +        expiration_timestamp_ms,
    +        label,
    +    } = lock;
    +
    +    // Delete the timelock.
    +    object::delete(id);
    +
    +    (locked, expiration_timestamp_ms, label)
    +}
    +
    + + + +
    + + + +## Function `transfer` + +An utility function to transfer a TimeLock. + + +
    public(friend) fun transfer<T: store>(lock: timelock::TimeLock<T>, recipient: address)
    +
    + + + +
    +Implementation + + +
    public(package) fun transfer<T: store>(lock: TimeLock<T>, recipient: address) {
    +    transfer::transfer(lock, recipient);
    +}
    +
    + + + +
    + + + +## Function `check_expiration_timestamp_ms` + +An utility function to check that the expiration_timestamp_ms value is valid. + + +
    fun check_expiration_timestamp_ms(expiration_timestamp_ms: u64, ctx: &tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    fun check_expiration_timestamp_ms(expiration_timestamp_ms: u64, ctx: &TxContext) {
    +    // Get the epoch timestamp.
    +    let epoch_timestamp_ms = ctx.epoch_timestamp_ms();
    +
    +    // Check that `expiration_timestamp_ms` is valid.
    +    assert!(expiration_timestamp_ms > epoch_timestamp_ms, EExpireEpochIsPast);
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/timelock/timelocked_balance.md b/crates/iota-framework/docs/timelock/timelocked_balance.md new file mode 100644 index 00000000000..4c709e5d199 --- /dev/null +++ b/crates/iota-framework/docs/timelock/timelocked_balance.md @@ -0,0 +1,144 @@ +--- +title: Module `0x10cf::timelocked_balance` +--- + +Utility functions for time-locked balance. + + +- [Constants](#@Constants_0) +- [Function `join`](#0x10cf_timelocked_balance_join) +- [Function `join_vec`](#0x10cf_timelocked_balance_join_vec) +- [Function `split`](#0x10cf_timelocked_balance_split) + + +
    use 0x10cf::timelock;
    +use 0x1::option;
    +use 0x1::string;
    +use 0x2::balance;
    +use 0x2::tx_context;
    +
    + + + + + +## Constants + + + + +For when trying to join two time-locked balances with different expiration time. + + +
    const EDifferentExpirationTime: u64 = 0;
    +
    + + + + + +For when trying to join two time-locked balances with different labels. + + +
    const EDifferentLabels: u64 = 1;
    +
    + + + + + +## Function `join` + +Join two TimeLock<Balance<T>> together. + + +
    public fun join<T>(self: &mut timelock::TimeLock<balance::Balance<T>>, other: timelock::TimeLock<balance::Balance<T>>)
    +
    + + + +
    +Implementation + + +
    public fun join<T>(self: &mut TimeLock<Balance<T>>, other: TimeLock<Balance<T>>) {
    +    // Check the preconditions.
    +    assert!(self.expiration_timestamp_ms() == other.expiration_timestamp_ms(), EDifferentExpirationTime);
    +    assert!(self.label() == other.label(), EDifferentLabels);
    +
    +    // Unpack the time-locked balance.
    +    let (value, _, _) = timelock::unpack(other);
    +
    +    // Join the balances.
    +    self.locked_mut().join(value);
    +}
    +
    + + + +
    + + + +## Function `join_vec` + +Join everything in others with self. + + +
    public fun join_vec<T>(self: &mut timelock::TimeLock<balance::Balance<T>>, others: vector<timelock::TimeLock<balance::Balance<T>>>)
    +
    + + + +
    +Implementation + + +
    public fun join_vec<T>(self: &mut TimeLock<Balance<T>>, mut others: vector<TimeLock<Balance<T>>>) {
    +    // Create useful variables.
    +    let (mut i, len) = (0, others.length());
    +
    +    // Join all the balances.
    +    while (i < len) {
    +        let other = others.pop_back();
    +        Self::join(self, other);
    +        i = i + 1
    +    };
    +
    +    // Destroy the empty vector.
    +    vector::destroy_empty(others)
    +}
    +
    + + + +
    + + + +## Function `split` + +Split a TimeLock<Balance<T>> and take a sub balance from it. + + +
    public fun split<T>(self: &mut timelock::TimeLock<balance::Balance<T>>, value: u64, ctx: &mut tx_context::TxContext): timelock::TimeLock<balance::Balance<T>>
    +
    + + + +
    +Implementation + + +
    public fun split<T>(self: &mut TimeLock<Balance<T>>, value: u64, ctx: &mut TxContext): TimeLock<Balance<T>> {
    +    // Split the locked balance.
    +    let value = self.locked_mut().split(value);
    +
    +    // Pack the splitted balance into a timelock.
    +    timelock::pack(value, self.expiration_timestamp_ms(), self.label(), ctx)
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/timelock/timelocked_staked_iota.md b/crates/iota-framework/docs/timelock/timelocked_staked_iota.md new file mode 100644 index 00000000000..ba39a5d0886 --- /dev/null +++ b/crates/iota-framework/docs/timelock/timelocked_staked_iota.md @@ -0,0 +1,462 @@ +--- +title: Module `0x10cf::timelocked_staked_iota` +--- + + + +- [Resource `TimelockedStakedIota`](#0x10cf_timelocked_staked_iota_TimelockedStakedIota) +- [Constants](#@Constants_0) +- [Function `create`](#0x10cf_timelocked_staked_iota_create) +- [Function `pool_id`](#0x10cf_timelocked_staked_iota_pool_id) +- [Function `staked_iota_amount`](#0x10cf_timelocked_staked_iota_staked_iota_amount) +- [Function `stake_activation_epoch`](#0x10cf_timelocked_staked_iota_stake_activation_epoch) +- [Function `expiration_timestamp_ms`](#0x10cf_timelocked_staked_iota_expiration_timestamp_ms) +- [Function `label`](#0x10cf_timelocked_staked_iota_label) +- [Function `is_labeled_with`](#0x10cf_timelocked_staked_iota_is_labeled_with) +- [Function `split`](#0x10cf_timelocked_staked_iota_split) +- [Function `split_staked_iota`](#0x10cf_timelocked_staked_iota_split_staked_iota) +- [Function `join_staked_iota`](#0x10cf_timelocked_staked_iota_join_staked_iota) +- [Function `is_equal_staking_metadata`](#0x10cf_timelocked_staked_iota_is_equal_staking_metadata) +- [Function `unpack`](#0x10cf_timelocked_staked_iota_unpack) +- [Function `transfer`](#0x10cf_timelocked_staked_iota_transfer) + + +
    use 0x10cf::labeler;
    +use 0x1::option;
    +use 0x1::string;
    +use 0x2::object;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +use 0x3::staking_pool;
    +
    + + + + + +## Resource `TimelockedStakedIota` + +A self-custodial object holding the timelocked staked IOTA tokens. + + +
    struct TimelockedStakedIota has key
    +
    + + + +
    +Fields + + +
    +
    +id: object::UID +
    +
    + +
    +
    +staked_iota: staking_pool::StakedIota +
    +
    + A self-custodial object holding the staked IOTA tokens. +
    +
    +expiration_timestamp_ms: u64 +
    +
    + This is the epoch time stamp of when the lock expires. +
    +
    +label: option::Option<string::String> +
    +
    + Timelock related label. +
    +
    + + +
    + + + +## Constants + + + + + + +
    const EIncompatibleTimelockedStakedIota: u64 = 0;
    +
    + + + + + +## Function `create` + +Create a new instance of TimelockedStakedIota. + + +
    public(friend) fun create(staked_iota: staking_pool::StakedIota, expiration_timestamp_ms: u64, label: option::Option<string::String>, ctx: &mut tx_context::TxContext): timelocked_staked_iota::TimelockedStakedIota
    +
    + + + +
    +Implementation + + +
    public(package) fun create(
    +    staked_iota: StakedIota,
    +    expiration_timestamp_ms: u64,
    +    label: Option<String>,
    +    ctx: &mut TxContext
    +): TimelockedStakedIota {
    +    TimelockedStakedIota {
    +        id: object::new(ctx),
    +        staked_iota,
    +        expiration_timestamp_ms,
    +        label,
    +    }
    +}
    +
    + + + +
    + + + +## Function `pool_id` + +Function to get the pool id of a TimelockedStakedIota. + + +
    public fun pool_id(self: &timelocked_staked_iota::TimelockedStakedIota): object::ID
    +
    + + + +
    +Implementation + + +
    public fun pool_id(self: &TimelockedStakedIota): ID { self.staked_iota.pool_id() }
    +
    + + + +
    + + + +## Function `staked_iota_amount` + +Function to get the staked iota amount of a TimelockedStakedIota. + + +
    public fun staked_iota_amount(self: &timelocked_staked_iota::TimelockedStakedIota): u64
    +
    + + + +
    +Implementation + + +
    public fun staked_iota_amount(self: &TimelockedStakedIota): u64 { self.staked_iota.staked_iota_amount() }
    +
    + + + +
    + + + +## Function `stake_activation_epoch` + +Function to get the stake activation epoch of a TimelockedStakedIota. + + +
    public fun stake_activation_epoch(self: &timelocked_staked_iota::TimelockedStakedIota): u64
    +
    + + + +
    +Implementation + + +
    public fun stake_activation_epoch(self: &TimelockedStakedIota): u64 {
    +    self.staked_iota.stake_activation_epoch()
    +}
    +
    + + + +
    + + + +## Function `expiration_timestamp_ms` + +Function to get the expiration timestamp of a TimelockedStakedIota. + + +
    public fun expiration_timestamp_ms(self: &timelocked_staked_iota::TimelockedStakedIota): u64
    +
    + + + +
    +Implementation + + +
    public fun expiration_timestamp_ms(self: &TimelockedStakedIota): u64 {
    +    self.expiration_timestamp_ms
    +}
    +
    + + + +
    + + + +## Function `label` + +Function to get the label of a TimelockedStakedIota. + + +
    public fun label(self: &timelocked_staked_iota::TimelockedStakedIota): option::Option<string::String>
    +
    + + + +
    +Implementation + + +
    public fun label(self: &TimelockedStakedIota): Option<String> {
    +    self.label
    +}
    +
    + + + +
    + + + +## Function `is_labeled_with` + +Check if a TimelockedStakedIota is labeled with the type L. + + +
    public fun is_labeled_with<L>(self: &timelocked_staked_iota::TimelockedStakedIota): bool
    +
    + + + +
    +Implementation + + +
    public fun is_labeled_with<L>(self: &TimelockedStakedIota): bool {
    +    if (self.label.is_some()) {
    +        self.label.borrow() == labeler::type_name<L>()
    +    }
    +    else {
    +        false
    +    }
    +}
    +
    + + + +
    + + + +## Function `split` + +Split TimelockedStakedIota into two parts, one with principal split_amount, +and the remaining principal is left in self. +All the other parameters of the TimelockedStakedIota like stake_activation_epoch or pool_id remain the same. + + +
    public fun split(self: &mut timelocked_staked_iota::TimelockedStakedIota, split_amount: u64, ctx: &mut tx_context::TxContext): timelocked_staked_iota::TimelockedStakedIota
    +
    + + + +
    +Implementation + + +
    public fun split(self: &mut TimelockedStakedIota, split_amount: u64, ctx: &mut TxContext): TimelockedStakedIota {
    +    let splitted_stake = self.staked_iota.split(split_amount, ctx);
    +
    +    TimelockedStakedIota {
    +        id: object::new(ctx),
    +        staked_iota: splitted_stake,
    +        expiration_timestamp_ms: self.expiration_timestamp_ms,
    +        label: self.label,
    +    }
    +}
    +
    + + + +
    + + + +## Function `split_staked_iota` + +Split the given TimelockedStakedIota to the two parts, one with principal split_amount, +transfer the newly split part to the sender address. + + +
    public entry fun split_staked_iota(stake: &mut timelocked_staked_iota::TimelockedStakedIota, split_amount: u64, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun split_staked_iota(stake: &mut TimelockedStakedIota, split_amount: u64, ctx: &mut TxContext) {
    +    transfer::transfer(split(stake, split_amount, ctx), ctx.sender());
    +}
    +
    + + + +
    + + + +## Function `join_staked_iota` + +Consume the staked iota other and add its value to self. +Aborts if some of the staking parameters are incompatible (pool id, stake activation epoch, etc.) + + +
    public entry fun join_staked_iota(self: &mut timelocked_staked_iota::TimelockedStakedIota, other: timelocked_staked_iota::TimelockedStakedIota)
    +
    + + + +
    +Implementation + + +
    public entry fun join_staked_iota(self: &mut TimelockedStakedIota, other: TimelockedStakedIota) {
    +    assert!(self.is_equal_staking_metadata(&other), EIncompatibleTimelockedStakedIota);
    +
    +    let TimelockedStakedIota {
    +        id,
    +        staked_iota,
    +        expiration_timestamp_ms: _,
    +        label: _,
    +    } = other;
    +
    +    id.delete();
    +
    +    self.staked_iota.join(staked_iota);
    +}
    +
    + + + +
    + + + +## Function `is_equal_staking_metadata` + +Returns true if all the staking parameters of the staked iota except the principal are identical + + +
    public fun is_equal_staking_metadata(self: &timelocked_staked_iota::TimelockedStakedIota, other: &timelocked_staked_iota::TimelockedStakedIota): bool
    +
    + + + +
    +Implementation + + +
    public fun is_equal_staking_metadata(self: &TimelockedStakedIota, other: &TimelockedStakedIota): bool {
    +    self.staked_iota.is_equal_staking_metadata(&other.staked_iota) &&
    +    (self.expiration_timestamp_ms == other.expiration_timestamp_ms) &&
    +    (self.label() == other.label())
    +}
    +
    + + + +
    + + + +## Function `unpack` + +A utility function to destroy a TimelockedStakedIota. + + +
    public(friend) fun unpack(self: timelocked_staked_iota::TimelockedStakedIota): (staking_pool::StakedIota, u64, option::Option<string::String>)
    +
    + + + +
    +Implementation + + +
    public(package) fun unpack(self: TimelockedStakedIota): (StakedIota, u64, Option<String>) {
    +    let TimelockedStakedIota {
    +        id,
    +        staked_iota,
    +        expiration_timestamp_ms,
    +        label,
    +    } = self;
    +
    +    object::delete(id);
    +
    +    (staked_iota, expiration_timestamp_ms, label)
    +}
    +
    + + + +
    + + + +## Function `transfer` + +An utility function to transfer a TimelockedStakedIota. + + +
    public(friend) fun transfer(stake: timelocked_staked_iota::TimelockedStakedIota, recipient: address)
    +
    + + + +
    +Implementation + + +
    public(package) fun transfer(stake: TimelockedStakedIota, recipient: address) {
    +    transfer::transfer(stake, recipient);
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/docs/timelock/timelocked_staking.md b/crates/iota-framework/docs/timelock/timelocked_staking.md new file mode 100644 index 00000000000..cb2fa01ce63 --- /dev/null +++ b/crates/iota-framework/docs/timelock/timelocked_staking.md @@ -0,0 +1,314 @@ +--- +title: Module `0x10cf::timelocked_staking` +--- + + + +- [Constants](#@Constants_0) +- [Function `request_add_stake`](#0x10cf_timelocked_staking_request_add_stake) +- [Function `request_add_stake_non_entry`](#0x10cf_timelocked_staking_request_add_stake_non_entry) +- [Function `request_add_stake_mul_bal`](#0x10cf_timelocked_staking_request_add_stake_mul_bal) +- [Function `request_add_stake_mul_bal_non_entry`](#0x10cf_timelocked_staking_request_add_stake_mul_bal_non_entry) +- [Function `request_withdraw_stake`](#0x10cf_timelocked_staking_request_withdraw_stake) +- [Function `request_withdraw_stake_non_entry`](#0x10cf_timelocked_staking_request_withdraw_stake_non_entry) + + +
    use 0x10cf::timelock;
    +use 0x10cf::timelocked_staked_iota;
    +use 0x1::option;
    +use 0x1::string;
    +use 0x2::balance;
    +use 0x2::coin;
    +use 0x2::iota;
    +use 0x2::transfer;
    +use 0x2::tx_context;
    +use 0x3::iota_system;
    +use 0x3::staking_pool;
    +
    + + + + + +## Constants + + + + +For when trying to stake an expired time-locked balance. + + +
    const ETimeLockShouldNotBeExpired: u64 = 0;
    +
    + + + + + +## Function `request_add_stake` + +Add a time-locked stake to a validator's staking pool. + + +
    public entry fun request_add_stake(iota_system: &mut iota_system::IotaSystemState, timelocked_balance: timelock::TimeLock<balance::Balance<iota::IOTA>>, validator_address: address, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun request_add_stake(
    +    iota_system: &mut IotaSystemState,
    +    timelocked_balance: TimeLock<Balance<IOTA>>,
    +    validator_address: address,
    +    ctx: &mut TxContext,
    +) {
    +    // Stake the time-locked balance.
    +    let timelocked_staked_iota = request_add_stake_non_entry(iota_system, timelocked_balance, validator_address, ctx);
    +
    +    // Transfer the receipt to the sender.
    +    timelocked_staked_iota::transfer(timelocked_staked_iota, ctx.sender());
    +}
    +
    + + + +
    + + + +## Function `request_add_stake_non_entry` + +The non-entry version of request_add_stake, which returns the time-locked staked IOTA instead of transferring it to the sender. + + +
    public fun request_add_stake_non_entry(iota_system: &mut iota_system::IotaSystemState, timelocked_balance: timelock::TimeLock<balance::Balance<iota::IOTA>>, validator_address: address, ctx: &mut tx_context::TxContext): timelocked_staked_iota::TimelockedStakedIota
    +
    + + + +
    +Implementation + + +
    public fun request_add_stake_non_entry(
    +    iota_system: &mut IotaSystemState,
    +    timelocked_balance: TimeLock<Balance<IOTA>>,
    +    validator_address: address,
    +    ctx: &mut TxContext,
    +) : TimelockedStakedIota {
    +    // Check the preconditions.
    +    assert!(timelocked_balance.is_locked(ctx), ETimeLockShouldNotBeExpired);
    +
    +    // Unpack the time-locked balance.
    +    let (balance, expiration_timestamp_ms, label) = timelock::unpack(timelocked_balance);
    +
    +    // Stake the time-locked balance.
    +    let staked_iota = iota_system.request_add_stake_non_entry(
    +        balance.into_coin(ctx),
    +        validator_address,
    +        ctx,
    +    );
    +
    +    // Create and return a receipt.
    +    timelocked_staked_iota::create(
    +        staked_iota,
    +        expiration_timestamp_ms,
    +        label,
    +        ctx,
    +    )
    +}
    +
    + + + +
    + + + +## Function `request_add_stake_mul_bal` + +Add a time-locked stake to a validator's staking pool using multiple time-locked balances. + + +
    public entry fun request_add_stake_mul_bal(iota_system: &mut iota_system::IotaSystemState, timelocked_balances: vector<timelock::TimeLock<balance::Balance<iota::IOTA>>>, validator_address: address, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun request_add_stake_mul_bal(
    +    iota_system: &mut IotaSystemState,
    +    timelocked_balances: vector<TimeLock<Balance<IOTA>>>,
    +    validator_address: address,
    +    ctx: &mut TxContext,
    +) {
    +    // Stake the time-locked balances.
    +    let mut receipts = request_add_stake_mul_bal_non_entry(iota_system, timelocked_balances, validator_address, ctx);
    +
    +    // Create useful variables.
    +    let (mut i, len) = (0, receipts.length());
    +
    +    // Send all the receipts to the sender.
    +    while (i < len) {
    +        // Take a receipt.
    +        let receipt = receipts.pop_back();
    +
    +        // Transfer the receipt to the sender.
    +        timelocked_staked_iota::transfer(receipt, ctx.sender());
    +
    +        i = i + 1
    +    };
    +
    +    // Destroy the empty vector.
    +    vector::destroy_empty(receipts)
    +}
    +
    + + + +
    + + + +## Function `request_add_stake_mul_bal_non_entry` + +The non-entry version of request_add_stake_mul_bal, +which returns a list of the time-locked staked IOTAs instead of transferring them to the sender. + + +
    public fun request_add_stake_mul_bal_non_entry(iota_system: &mut iota_system::IotaSystemState, timelocked_balances: vector<timelock::TimeLock<balance::Balance<iota::IOTA>>>, validator_address: address, ctx: &mut tx_context::TxContext): vector<timelocked_staked_iota::TimelockedStakedIota>
    +
    + + + +
    +Implementation + + +
    public fun request_add_stake_mul_bal_non_entry(
    +    iota_system: &mut IotaSystemState,
    +    mut timelocked_balances: vector<TimeLock<Balance<IOTA>>>,
    +    validator_address: address,
    +    ctx: &mut TxContext,
    +) : vector<TimelockedStakedIota> {
    +    // Create a vector to store the results.
    +    let mut result = vector[];
    +
    +    // Create useful variables.
    +    let (mut i, len) = (0, timelocked_balances.length());
    +
    +    // Stake all the time-locked balances.
    +    while (i < len) {
    +        // Take a time-locked balance.
    +        let timelocked_balance = timelocked_balances.pop_back();
    +
    +        // Stake the time-locked balance.
    +        let timelocked_staked_iota = request_add_stake_non_entry(iota_system, timelocked_balance, validator_address, ctx);
    +
    +        // Store the created receipt.
    +        result.push_back(timelocked_staked_iota);
    +
    +        i = i + 1
    +    };
    +
    +    // Destroy the empty vector.
    +    vector::destroy_empty(timelocked_balances);
    +
    +    result
    +}
    +
    + + + +
    + + + +## Function `request_withdraw_stake` + +Withdraw a time-locked stake from a validator's staking pool. + + +
    public entry fun request_withdraw_stake(iota_system: &mut iota_system::IotaSystemState, timelocked_staked_iota: timelocked_staked_iota::TimelockedStakedIota, ctx: &mut tx_context::TxContext)
    +
    + + + +
    +Implementation + + +
    public entry fun request_withdraw_stake(
    +    iota_system: &mut IotaSystemState,
    +    timelocked_staked_iota: TimelockedStakedIota,
    +    ctx: &mut TxContext,
    +) {
    +    // Withdraw the time-locked balance.
    +    let (timelocked_balance, reward) = request_withdraw_stake_non_entry(iota_system, timelocked_staked_iota, ctx);
    +
    +    // Transfer the withdrawn time-locked balance to the sender.
    +    timelock::transfer(timelocked_balance, ctx.sender());
    +
    +    // Send coins only if the reward is not zero.
    +    if (reward.value() > 0) {
    +        transfer::public_transfer(reward.into_coin(ctx), ctx.sender());
    +    }
    +    else {
    +        balance::destroy_zero(reward);
    +    }
    +}
    +
    + + + +
    + + + +## Function `request_withdraw_stake_non_entry` + +Non-entry version of request_withdraw_stake that returns the withdrawn time-locked IOTA and reward +instead of transferring it to the sender. + + +
    public fun request_withdraw_stake_non_entry(iota_system: &mut iota_system::IotaSystemState, timelocked_staked_iota: timelocked_staked_iota::TimelockedStakedIota, ctx: &mut tx_context::TxContext): (timelock::TimeLock<balance::Balance<iota::IOTA>>, balance::Balance<iota::IOTA>)
    +
    + + + +
    +Implementation + + +
    public fun request_withdraw_stake_non_entry(
    +    iota_system: &mut IotaSystemState,
    +    timelocked_staked_iota: TimelockedStakedIota,
    +    ctx: &mut TxContext,
    +) : (TimeLock<Balance<IOTA>>, Balance<IOTA>) {
    +    // Unpack the `TimelockedStakedIota` instance.
    +    let (staked_iota, expiration_timestamp_ms, label) = timelocked_staked_iota.unpack();
    +
    +    // Store the original stake amount.
    +    let principal = staked_iota.staked_iota_amount();
    +
    +    // Withdraw the balance.
    +    let mut withdraw_stake = iota_system.request_withdraw_stake_non_entry(staked_iota, ctx);
    +
    +    // The iota_system withdraw functions return a balance that consists of the original staked amount plus the reward amount;
    +    // In here, it splits the original staked balance to timelock it again.
    +    let principal = withdraw_stake.split(principal);
    +
    +    // Pack and return a time-locked balance, and the reward.
    +    (timelock::pack(principal, expiration_timestamp_ms, label, ctx), withdraw_stake)
    +}
    +
    + + + +
    diff --git a/crates/iota-framework/packages/deepbook/Move.lock b/crates/iota-framework/packages/deepbook/Move.lock new file mode 100644 index 00000000000..ce523fa688f --- /dev/null +++ b/crates/iota-framework/packages/deepbook/Move.lock @@ -0,0 +1,28 @@ +# @generated by Move, please check-in and do not edit manually. + +[move] +version = 1 +manifest_digest = "E7FF1D7441FA0105B981EE018AEF168A18B22984DEABBF2F111AA6FBB3C3CB81" +deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600" + +dependencies = [ + { name = "MoveStdlib" }, + { name = "Iota" }, +] + +[[move.package]] +name = "MoveStdlib" +source = { local = "../move-stdlib" } + +[[move.package]] +name = "Iota" +source = { local = "../iota-framework" } + +dependencies = [ + { name = "MoveStdlib" }, +] + +[move.toolchain-version] +compiler-version = "1.22.0" +edition = "legacy" +flavor = "iota" diff --git a/crates/iota-framework/packages/deepbook/Move.toml b/crates/iota-framework/packages/deepbook/Move.toml new file mode 100644 index 00000000000..3b3caa3baff --- /dev/null +++ b/crates/iota-framework/packages/deepbook/Move.toml @@ -0,0 +1,12 @@ +[package] +name = "DeepBook" +version = "0.0.1" +published-at = "0xdee9" +edition = "2024.beta" + +[dependencies] +MoveStdlib = { local = "../move-stdlib" } +Iota = { local = "../iota-framework" } + +[addresses] +deepbook = "0xdee9" diff --git a/crates/iota-framework/packages/deepbook/README.md b/crates/iota-framework/packages/deepbook/README.md new file mode 100644 index 00000000000..1ad6f745632 --- /dev/null +++ b/crates/iota-framework/packages/deepbook/README.md @@ -0,0 +1,5 @@ +# DeepBook + +DeepBook is a decentralized central limit order book (CLOB) built for the Iota ecosystem. DeepBook provides a one-stop shop for trading digital assets, with a technical design built for Iota’s architecture. DeepBook leverages Iota’s performance and delivers a low latency and high throughput execution engine to spread liquidity across the DeFi ecosystem. + +Designed as permissionless and released as open source, DeepBook will accelerate the development of financial and other apps on Iota. It will give builders an efficient and shared ready-built financial layer for trading fungible assets. \ No newline at end of file diff --git a/crates/sui-framework/packages/deepbook/sources/clob.move b/crates/iota-framework/packages/deepbook/sources/clob.move similarity index 99% rename from crates/sui-framework/packages/deepbook/sources/clob.move rename to crates/iota-framework/packages/deepbook/sources/clob.move index 1902097c6d1..3cba68d3b63 100644 --- a/crates/sui-framework/packages/deepbook/sources/clob.move +++ b/crates/iota-framework/packages/deepbook/sources/clob.move @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[allow(unused_use)] module deepbook::clob { use std::type_name::{Self, TypeName}; - use sui::balance::{Self, Balance}; - use sui::clock::{Self, Clock}; - use sui::coin::{Self, Coin, join}; - use sui::event; - use sui::linked_table::{Self, LinkedTable}; - use sui::sui::SUI; - use sui::table::{Self, Table, contains, add, borrow_mut}; + use iota::balance::{Self, Balance}; + use iota::clock::{Self, Clock}; + use iota::coin::{Self, Coin, join}; + use iota::event; + use iota::linked_table::{Self, LinkedTable}; + use iota::iota::IOTA; + use iota::table::{Self, Table, contains, add, borrow_mut}; use deepbook::critbit::{Self, CritbitTree, is_empty, borrow_mut_leaf_by_index, min_leaf, remove_leaf_by_index, max_leaf, next_leaf, previous_leaf, borrow_leaf_by_index, borrow_leaf_by_key, find_leaf, insert_leaf}; use deepbook::custodian::{Self, Custodian, AccountCap}; @@ -62,7 +63,7 @@ module deepbook::clob { #[test_only] const TIMESTAMP_INF: u64 = (1u128 << 64 - 1) as u64; #[test_only] - const FEE_AMOUNT_FOR_CREATE_POOL: u64 = 100 * 1_000_000_000; // 100 SUI + const FEE_AMOUNT_FOR_CREATE_POOL: u64 = 100 * 1_000_000_000; // 100 IOTA // <<<<<<<<<<<<<<<<<<<<<<<< Constants <<<<<<<<<<<<<<<<<<<<<<<< @@ -131,7 +132,7 @@ module deepbook::clob { // For each pool, order id is incremental and unique for each opening order. // Orders that are submitted earlier has lower order ids. // 64 bits are sufficient for order ids whereas 32 bits are not. - // Assuming a maximum TPS of 100K/s of Sui chain, it would take (1<<63) / 100000 / 3600 / 24 / 365 = 2924712 years to reach the full capacity. + // Assuming a maximum TPS of 100K/s of Iota chain, it would take (1<<63) / 100000 / 3600 / 24 / 365 = 2924712 years to reach the full capacity. // The highest bit of the order id is used to denote the order tyep, 0 for bid, 1 for ask. order_id: u64, // Only used for limit orders. @@ -177,7 +178,7 @@ module deepbook::clob { base_custodian: Custodian, quote_custodian: Custodian, // Stores the fee paid to create this pool. These funds are not accessible. - creation_fee: Balance, + creation_fee: Balance, // Deprecated. base_asset_trading_fees: Balance, // Stores the trading fees paid in `QuoteAsset`. These funds are not accessible. @@ -203,7 +204,7 @@ module deepbook::clob { maker_rebate_rate: u64, tick_size: u64, lot_size: u64, - creation_fee: Balance, + creation_fee: Balance, ctx: &mut TxContext, ) { let base_type_name = type_name::get(); @@ -249,7 +250,7 @@ module deepbook::clob { public fun create_pool( _tick_size: u64, _lot_size: u64, - _creation_fee: Coin, + _creation_fee: Coin, _ctx: &mut TxContext, ) { abort DEPRECATED @@ -1339,7 +1340,7 @@ module deepbook::clob { // Note that open orders and quotes can be directly accessed by loading in the entire Pool. - #[test_only] use sui::test_scenario::{Self, Scenario}; + #[test_only] use iota::test_scenario::{Self, Scenario}; #[test_only] const E_NULL: u64 = 0; @@ -1362,7 +1363,7 @@ module deepbook::clob { test_scenario::next_tx(scenario, sender); { - create_pool_( + create_pool_( taker_fee_rate, maker_rebate_rate, tick_size, diff --git a/crates/sui-framework/packages/deepbook/sources/clob_v2.move b/crates/iota-framework/packages/deepbook/sources/clob_v2.move similarity index 97% rename from crates/sui-framework/packages/deepbook/sources/clob_v2.move rename to crates/iota-framework/packages/deepbook/sources/clob_v2.move index 6d27eb4dc7d..68a9dd5a17d 100644 --- a/crates/sui-framework/packages/deepbook/sources/clob_v2.move +++ b/crates/iota-framework/packages/deepbook/sources/clob_v2.move @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module deepbook::clob_v2 { use std::type_name::{Self, TypeName}; - use sui::balance::{Self, Balance}; - use sui::clock::{Self, Clock}; - use sui::coin::{Self, Coin, join}; - use sui::event; - use sui::linked_table::{Self, LinkedTable}; - use sui::sui::SUI; - use sui::table::{Self, Table, contains, add, borrow_mut}; + use iota::balance::{Self, Balance}; + use iota::clock::{Self, Clock}; + use iota::coin::{Self, Coin, join}; + use iota::event; + use iota::linked_table::{Self, LinkedTable}; + use iota::iota::IOTA; + use iota::table::{Self, Table, contains, add, borrow_mut}; use deepbook::critbit::{Self, CritbitTree, is_empty, borrow_mut_leaf_by_index, min_leaf, remove_leaf_by_index, max_leaf, next_leaf, previous_leaf, borrow_leaf_by_index, borrow_leaf_by_key, find_leaf, insert_leaf}; use deepbook::custodian_v2::{Self as custodian, Custodian, AccountCap, mint_account_cap, account_owner}; @@ -63,7 +64,7 @@ module deepbook::clob_v2 { const TIMESTAMP_INF: u64 = (1u128 << 64 - 1) as u64; const REFERENCE_TAKER_FEE_RATE: u64 = 2_500_000; const REFERENCE_MAKER_REBATE_RATE: u64 = 1_500_000; - const FEE_AMOUNT_FOR_CREATE_POOL: u64 = 100 * 1_000_000_000; // 100 SUI + const FEE_AMOUNT_FOR_CREATE_POOL: u64 = 100 * 1_000_000_000; // 100 IOTA #[test_only] const PREVENT_SELF_MATCHING_DEFAULT: u8 = 0; @@ -207,7 +208,7 @@ module deepbook::clob_v2 { // For each pool, order id is incremental and unique for each opening order. // Orders that are submitted earlier has lower order ids. // 64 bits are sufficient for order ids whereas 32 bits are not. - // Assuming a maximum TPS of 100K/s of Sui chain, it would take (1<<63) / 100000 / 3600 / 24 / 365 = 2924712 years to reach the full capacity. + // Assuming a maximum TPS of 100K/s of Iota chain, it would take (1<<63) / 100000 / 3600 / 24 / 365 = 2924712 years to reach the full capacity. // The highest bit of the order id is used to denote the order type, 0 for bid, 1 for ask. order_id: u64, client_order_id: u64, @@ -257,7 +258,7 @@ module deepbook::clob_v2 { base_custodian: Custodian, quote_custodian: Custodian, // Stores the fee paid to create this pool. These funds are not accessible. - creation_fee: Balance, + creation_fee: Balance, // Deprecated. base_asset_trading_fees: Balance, // Stores the trading fees paid in `QuoteAsset`. These funds are not accessible in the V1 of the Pools, but V2 Pools are accessible. @@ -344,7 +345,7 @@ module deepbook::clob_v2 { maker_rebate_rate: u64, tick_size: u64, lot_size: u64, - creation_fee: Balance, + creation_fee: Balance, ctx: &mut TxContext, ) { let (pool, pool_owner_cap) = create_pool_with_return_( @@ -363,7 +364,7 @@ module deepbook::clob_v2 { public fun create_pool( tick_size: u64, lot_size: u64, - creation_fee: Coin, + creation_fee: Coin, ctx: &mut TxContext, ) { create_customized_pool( @@ -384,7 +385,7 @@ module deepbook::clob_v2 { lot_size: u64, taker_fee_rate: u64, maker_rebate_rate: u64, - creation_fee: Coin, + creation_fee: Coin, ctx: &mut TxContext, ) { create_pool_( @@ -403,7 +404,7 @@ module deepbook::clob_v2 { maker_rebate_rate: u64, tick_size: u64, lot_size: u64, - creation_fee: Balance, + creation_fee: Balance, ctx: &mut TxContext, ): (Pool, PoolOwnerCap) { assert!(balance::value(&creation_fee) == FEE_AMOUNT_FOR_CREATE_POOL, EInvalidFee); @@ -455,7 +456,7 @@ module deepbook::clob_v2 { public fun create_pool_with_return( tick_size: u64, lot_size: u64, - creation_fee: Coin, + creation_fee: Coin, ctx: &mut TxContext, ): Pool { create_customized_pool_with_return( @@ -477,7 +478,7 @@ module deepbook::clob_v2 { lot_size: u64, taker_fee_rate: u64, maker_rebate_rate: u64, - creation_fee: Coin, + creation_fee: Coin, ctx: &mut TxContext, ) : Pool { let (pool, pool_owner_cap) = create_pool_with_return_( @@ -500,7 +501,7 @@ module deepbook::clob_v2 { lot_size: u64, taker_fee_rate: u64, maker_rebate_rate: u64, - creation_fee: Coin, + creation_fee: Coin, ctx: &mut TxContext, ) : (Pool, PoolOwnerCap) { create_pool_with_return_( @@ -2253,9 +2254,9 @@ module deepbook::clob_v2 { // Note that open orders and quotes can be directly accessed by loading in the entire Pool. - #[test_only] use sui::coin::mint_for_testing; + #[test_only] use iota::coin::mint_for_testing; - #[test_only] use sui::test_scenario::{Self, Scenario}; + #[test_only] use iota::test_scenario::{Self, Scenario}; #[test_only] const E_NULL: u64 = 0; @@ -2281,7 +2282,7 @@ module deepbook::clob_v2 { test_scenario::next_tx(scenario, sender); { - create_pool_( + create_pool_( taker_fee_rate, maker_rebate_rate, tick_size, @@ -2323,7 +2324,7 @@ module deepbook::clob_v2 { test_scenario::next_tx(scenario, sender); { - let (pool, pool_owner_cap) = create_pool_with_return_( + let (pool, pool_owner_cap) = create_pool_with_return_( taker_fee_rate, maker_rebate_rate, tick_size, @@ -2697,13 +2698,13 @@ module deepbook::clob_v2 { }; test_scenario::next_tx(&mut test, alice); { - let mut pool = test_scenario::take_shared>(&test); + let mut pool = test_scenario::take_shared>(&test); let clock = test_scenario::take_shared(&test); let account_cap = test_scenario::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); custodian::deposit( &mut pool.base_custodian, - mint_for_testing(1000 * 100000000, test_scenario::ctx(&mut test)), + mint_for_testing(1000 * 100000000, test_scenario::ctx(&mut test)), account_cap_user ); custodian::deposit( @@ -2711,7 +2712,7 @@ module deepbook::clob_v2 { mint_for_testing(10000 * 100000000, test_scenario::ctx(&mut test)), account_cap_user ); - place_limit_order( + place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -2759,13 +2760,13 @@ module deepbook::clob_v2 { }; test_scenario::next_tx(&mut test, alice); { - let mut pool = test_scenario::take_shared>(&test); + let mut pool = test_scenario::take_shared>(&test); let clock = test_scenario::take_shared(&test); let account_cap = test_scenario::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); custodian::deposit( &mut pool.base_custodian, - mint_for_testing(1000 * 100000000, test_scenario::ctx(&mut test)), + mint_for_testing(1000 * 100000000, test_scenario::ctx(&mut test)), account_cap_user ); custodian::deposit( @@ -2773,7 +2774,7 @@ module deepbook::clob_v2 { mint_for_testing(10000 * 100000000, test_scenario::ctx(&mut test)), account_cap_user ); - place_limit_order( + place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -2786,7 +2787,7 @@ module deepbook::clob_v2 { &account_cap, test_scenario::ctx(&mut test) ); - place_limit_order( + place_limit_order( &mut pool, CLIENT_ID_ALICE, 4 * FLOAT_SCALING, @@ -2799,7 +2800,7 @@ module deepbook::clob_v2 { &account_cap, test_scenario::ctx(&mut test) ); - place_limit_order( + place_limit_order( &mut pool, CLIENT_ID_ALICE, 4 * FLOAT_SCALING, @@ -2812,7 +2813,7 @@ module deepbook::clob_v2 { &account_cap, test_scenario::ctx(&mut test) ); - place_limit_order( + place_limit_order( &mut pool, CLIENT_ID_ALICE, 10 * FLOAT_SCALING, @@ -2834,7 +2835,7 @@ module deepbook::clob_v2 { 7400 * 100000000, 2600 * 100000000 ); - custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 0, 1000 * 100000000); + custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 0, 1000 * 100000000); test_scenario::return_shared(pool); test_scenario::return_shared(clock); test_scenario::return_to_address(alice, account_cap); @@ -2842,17 +2843,17 @@ module deepbook::clob_v2 { test_scenario::next_tx(&mut test, bob); { - let mut pool = test_scenario::take_shared>(&test); + let mut pool = test_scenario::take_shared>(&test); let clock = test_scenario::take_shared(&test); let account_cap = test_scenario::take_from_address(&test, bob); let account_cap_user = account_owner(&account_cap); custodian::deposit( &mut pool.base_custodian, - mint_for_testing(900 * 100000000, test_scenario::ctx(&mut test)), + mint_for_testing(900 * 100000000, test_scenario::ctx(&mut test)), account_cap_user ); - custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 900 * 100000000, 0); - place_limit_order( + custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 900 * 100000000, 0); + place_limit_order( &mut pool, CLIENT_ID_BOB, 4 * FLOAT_SCALING, @@ -2900,13 +2901,13 @@ module deepbook::clob_v2 { }; test_scenario::next_tx(&mut test, alice); { - let mut pool = test_scenario::take_shared>(&test); + let mut pool = test_scenario::take_shared>(&test); let clock = test_scenario::take_shared(&test); let account_cap = test_scenario::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); custodian::deposit( &mut pool.base_custodian, - mint_for_testing(1000 * 100000000, test_scenario::ctx(&mut test)), + mint_for_testing(1000 * 100000000, test_scenario::ctx(&mut test)), account_cap_user ); custodian::deposit( @@ -2914,7 +2915,7 @@ module deepbook::clob_v2 { mint_for_testing(10000 * 100000000, test_scenario::ctx(&mut test)), account_cap_user ); - place_limit_order( + place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -2927,7 +2928,7 @@ module deepbook::clob_v2 { &account_cap, test_scenario::ctx(&mut test) ); - place_limit_order( + place_limit_order( &mut pool, CLIENT_ID_ALICE, 4 * FLOAT_SCALING, @@ -2940,7 +2941,7 @@ module deepbook::clob_v2 { &account_cap, test_scenario::ctx(&mut test) ); - place_limit_order( + place_limit_order( &mut pool, CLIENT_ID_ALICE, 4 * FLOAT_SCALING, @@ -2953,7 +2954,7 @@ module deepbook::clob_v2 { &account_cap, test_scenario::ctx(&mut test) ); - place_limit_order( + place_limit_order( &mut pool, CLIENT_ID_ALICE, 10 * FLOAT_SCALING, @@ -2975,7 +2976,7 @@ module deepbook::clob_v2 { 7400 * 100000000, 2600 * 100000000 ); - custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 0, 1000 * 100000000); + custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 0, 1000 * 100000000); test_scenario::return_shared(pool); test_scenario::return_shared(clock); test_scenario::return_to_address(alice, account_cap); @@ -2983,17 +2984,17 @@ module deepbook::clob_v2 { test_scenario::next_tx(&mut test, bob); { - let mut pool = test_scenario::take_shared>(&test); + let mut pool = test_scenario::take_shared>(&test); let clock = test_scenario::take_shared(&test); let account_cap = test_scenario::take_from_address(&test, bob); let account_cap_user = account_owner(&account_cap); custodian::deposit( &mut pool.base_custodian, - mint_for_testing(900 * 100000000, test_scenario::ctx(&mut test)), + mint_for_testing(900 * 100000000, test_scenario::ctx(&mut test)), account_cap_user ); - custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 900 * 100000000, 0); - place_limit_order( + custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 900 * 100000000, 0); + place_limit_order( &mut pool, CLIENT_ID_BOB, 4 * FLOAT_SCALING, @@ -3006,7 +3007,7 @@ module deepbook::clob_v2 { &account_cap, test_scenario::ctx(&mut test) ); - custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 900 * 100000000, 0); + custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 900 * 100000000, 0); test_scenario::return_shared(pool); test_scenario::return_shared(clock); test_scenario::return_to_address(bob, account_cap); @@ -3040,13 +3041,13 @@ module deepbook::clob_v2 { }; test_scenario::next_tx(&mut test, alice); { - let mut pool = test_scenario::take_shared>(&test); + let mut pool = test_scenario::take_shared>(&test); let clock = test_scenario::take_shared(&test); let account_cap = test_scenario::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); custodian::deposit( &mut pool.base_custodian, - mint_for_testing(1000 * 100000000, test_scenario::ctx(&mut test)), + mint_for_testing(1000 * 100000000, test_scenario::ctx(&mut test)), account_cap_user ); custodian::deposit( @@ -3054,7 +3055,7 @@ module deepbook::clob_v2 { mint_for_testing(10000 * 100000000, test_scenario::ctx(&mut test)), account_cap_user ); - place_limit_order( + place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -3067,7 +3068,7 @@ module deepbook::clob_v2 { &account_cap, test_scenario::ctx(&mut test) ); - place_limit_order( + place_limit_order( &mut pool, CLIENT_ID_ALICE, 4 * FLOAT_SCALING, @@ -3080,7 +3081,7 @@ module deepbook::clob_v2 { &account_cap, test_scenario::ctx(&mut test) ); - place_limit_order( + place_limit_order( &mut pool, CLIENT_ID_ALICE, 4 * FLOAT_SCALING, @@ -3094,7 +3095,7 @@ module deepbook::clob_v2 { test_scenario::ctx(&mut test) ); - let (base_filled, quote_filled, maker_injected, maker_order_id) = place_limit_order( + let (base_filled, quote_filled, maker_injected, maker_order_id) = place_limit_order( &mut pool, CLIENT_ID_ALICE, 10 * FLOAT_SCALING, @@ -3121,7 +3122,7 @@ module deepbook::clob_v2 { 7400 * 100000000, 2600 * 100000000 ); - custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 0, 1000 * 100000000); + custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 0, 1000 * 100000000); test_scenario::return_shared(pool); test_scenario::return_shared(clock); test_scenario::return_to_address(alice, account_cap); @@ -3129,18 +3130,18 @@ module deepbook::clob_v2 { test_scenario::next_tx(&mut test, bob); { - let mut pool = test_scenario::take_shared>(&test); + let mut pool = test_scenario::take_shared>(&test); let clock = test_scenario::take_shared(&test); let account_cap = test_scenario::take_from_address(&test, bob); let account_cap_user = account_owner(&account_cap); custodian::deposit( &mut pool.base_custodian, - mint_for_testing(900 * 100000000, test_scenario::ctx(&mut test)), + mint_for_testing(900 * 100000000, test_scenario::ctx(&mut test)), account_cap_user ); - custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 900 * 100000000, 0); + custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 900 * 100000000, 0); - let (base_filled, quote_filled, maker_injected, _) = place_limit_order( + let (base_filled, quote_filled, maker_injected, _) = place_limit_order( &mut pool, CLIENT_ID_ALICE, 4 * FLOAT_SCALING, @@ -3157,7 +3158,7 @@ module deepbook::clob_v2 { assert!(quote_filled == 2600 * 100000000, E_NULL); assert!(!maker_injected, E_NULL); - custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 300 * 100000000, 0); + custodian::assert_user_balance(&pool.base_custodian, account_cap_user, 300 * 100000000, 0); { let (_, _, bids, _) = get_pool_stat(&pool); check_empty_tick_level(bids, 4 * FLOAT_SCALING); @@ -3181,7 +3182,7 @@ module deepbook::clob_v2 { // create pool which is already exist fail test_scenario::next_tx(&mut test, owner); { - create_pool_( + create_pool_( REFERENCE_TAKER_FEE_RATE, REFERENCE_MAKER_REBATE_RATE, 1 * FLOAT_SCALING, @@ -3205,7 +3206,7 @@ module deepbook::clob_v2 { // create pool which is already exist fail test_scenario::next_tx(&mut test, owner); { - create_pool_( + create_pool_( REFERENCE_TAKER_FEE_RATE, REFERENCE_MAKER_REBATE_RATE, 100_000, diff --git a/crates/sui-framework/packages/deepbook/sources/critbit.move b/crates/iota-framework/packages/deepbook/sources/critbit.move similarity index 99% rename from crates/sui-framework/packages/deepbook/sources/critbit.move rename to crates/iota-framework/packages/deepbook/sources/critbit.move index 84de3094215..127521d3469 100644 --- a/crates/sui-framework/packages/deepbook/sources/critbit.move +++ b/crates/iota-framework/packages/deepbook/sources/critbit.move @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module deepbook::critbit { - use sui::table::{Self, Table}; + use iota::table::{Self, Table}; use deepbook::math::{count_leading_zeros}; /* friend deepbook::clob; */ diff --git a/crates/sui-framework/packages/deepbook/sources/custodian.move b/crates/iota-framework/packages/deepbook/sources/custodian.move similarity index 96% rename from crates/sui-framework/packages/deepbook/sources/custodian.move rename to crates/iota-framework/packages/deepbook/sources/custodian.move index 857724d60f8..6e527790c64 100644 --- a/crates/sui-framework/packages/deepbook/sources/custodian.move +++ b/crates/iota-framework/packages/deepbook/sources/custodian.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module deepbook::custodian { - use sui::balance::{Self, Balance, split}; - use sui::coin::{Self, Coin}; - use sui::table::{Self, Table}; + use iota::balance::{Self, Balance, split}; + use iota::coin::{Self, Coin}; + use iota::table::{Self, Table}; /* friend deepbook::clob; */ @@ -161,11 +162,11 @@ module deepbook::custodian { /* #[test_only] */ /* friend deepbook::clob_test; */ #[test_only] - use sui::test_scenario::{Self, Scenario, take_shared, take_from_sender, ctx}; + use iota::test_scenario::{Self, Scenario, take_shared, take_from_sender, ctx}; #[test_only] - use sui::coin::{mint_for_testing}; + use iota::coin::{mint_for_testing}; #[test_only] - use sui::test_utils::assert_eq; + use iota::test_utils::assert_eq; #[test_only] const ENull: u64 = 0; diff --git a/crates/sui-framework/packages/deepbook/sources/custodian_v2.move b/crates/iota-framework/packages/deepbook/sources/custodian_v2.move similarity index 97% rename from crates/sui-framework/packages/deepbook/sources/custodian_v2.move rename to crates/iota-framework/packages/deepbook/sources/custodian_v2.move index 1ed6b237840..c8f74a45a33 100644 --- a/crates/sui-framework/packages/deepbook/sources/custodian_v2.move +++ b/crates/iota-framework/packages/deepbook/sources/custodian_v2.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module deepbook::custodian_v2 { - use sui::balance::{Self, Balance, split}; - use sui::coin::{Self, Coin}; - use sui::table::{Self, Table}; + use iota::balance::{Self, Balance, split}; + use iota::coin::{Self, Coin}; + use iota::table::{Self, Table}; /* friend deepbook::clob_v2; */ @@ -200,11 +201,11 @@ module deepbook::custodian_v2 { /* #[test_only] */ /* friend deepbook::order_query_tests; */ #[test_only] - use sui::test_scenario::{Self, Scenario, take_shared, take_from_sender, ctx}; + use iota::test_scenario::{Self, Scenario, take_shared, take_from_sender, ctx}; #[test_only] - use sui::coin::{mint_for_testing}; + use iota::coin::{mint_for_testing}; #[test_only] - use sui::test_utils::{assert_eq, destroy}; + use iota::test_utils::{assert_eq, destroy}; #[test_only] const ENull: u64 = 0; diff --git a/crates/iota-framework/packages/deepbook/sources/math.move b/crates/iota-framework/packages/deepbook/sources/math.move new file mode 100644 index 00000000000..c2a1e2b6065 --- /dev/null +++ b/crates/iota-framework/packages/deepbook/sources/math.move @@ -0,0 +1,215 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module deepbook::math { + /// scaling setting for float + const FLOAT_SCALING: u64 = 1_000_000_000; + const FLOAT_SCALING_U128: u128 = 1_000_000_000; + + /* friend deepbook::clob; */ + /* friend deepbook::clob_v2; */ + /* friend deepbook::critbit; */ + + // <<<<<<<<<<<<<<<<<<<<<<<< Error codes <<<<<<<<<<<<<<<<<<<<<<<< + const EUnderflow: u64 = 1; + // <<<<<<<<<<<<<<<<<<<<<<<< Error codes <<<<<<<<<<<<<<<<<<<<<<<< + + // multiply two floating numbers + public(package) fun unsafe_mul(x: u64, y: u64): u64 { + let (_, result) = unsafe_mul_round(x, y); + result + } + + // multiply two floating numbers + // also returns whether the result is rounded down + public(package) fun unsafe_mul_round(x: u64, y: u64): (bool, u64) { + let x = x as u128; + let y = y as u128; + let mut is_round_down = true; + if ((x * y) % FLOAT_SCALING_U128 == 0) is_round_down = false; + (is_round_down, (x * y / FLOAT_SCALING_U128) as u64) + } + + // multiply two floating numbers and assert the result is non zero + // Note that this function will still round down + public fun mul(x: u64, y: u64): u64 { + let (_, result) = unsafe_mul_round(x, y); + assert!(result > 0, EUnderflow); + result + } + + // multiply two floating numbers and assert the result is non zero + // also returns whether the result is rounded down + public fun mul_round(x: u64, y: u64): (bool, u64) { + let (is_round_down, result) = unsafe_mul_round(x, y); + assert!(result > 0, EUnderflow); + (is_round_down, result) + } + + // divide two floating numbers + public(package) fun unsafe_div(x: u64, y: u64): u64 { + let (_, result) = unsafe_div_round(x, y); + result + } + + // divide two floating numbers + // also returns whether the result is rounded down + public(package) fun unsafe_div_round(x: u64, y: u64): (bool, u64) { + let x = x as u128; + let y = y as u128; + let mut is_round_down = true; + if ((x * (FLOAT_SCALING as u128) % y) == 0) is_round_down = false; + (is_round_down, (x * (FLOAT_SCALING as u128) / y) as u64) + } + + // divide two floating numbers and assert the result is non zero + // also returns whether the result is rounded down + public fun div_round(x: u64, y: u64): (bool, u64) { + let (is_round_down, result) = unsafe_div_round(x, y); + assert!(result > 0, EUnderflow); + (is_round_down, result) + } + + public(package) fun count_leading_zeros(mut x: u128): u8 { + if (x == 0) { + 128 + } else { + let mut n: u8 = 0; + if (x & 0xFFFFFFFFFFFFFFFF0000000000000000 == 0) { + // x's higher 64 is all zero, shift the lower part over + x = x << 64; + n = n + 64; + }; + if (x & 0xFFFFFFFF000000000000000000000000 == 0) { + // x's higher 32 is all zero, shift the lower part over + x = x << 32; + n = n + 32; + }; + if (x & 0xFFFF0000000000000000000000000000 == 0) { + // x's higher 16 is all zero, shift the lower part over + x = x << 16; + n = n + 16; + }; + if (x & 0xFF000000000000000000000000000000 == 0) { + // x's higher 8 is all zero, shift the lower part over + x = x << 8; + n = n + 8; + }; + if (x & 0xF0000000000000000000000000000000 == 0) { + // x's higher 4 is all zero, shift the lower part over + x = x << 4; + n = n + 4; + }; + if (x & 0xC0000000000000000000000000000000 == 0) { + // x's higher 2 is all zero, shift the lower part over + x = x << 2; + n = n + 2; + }; + if (x & 0x80000000000000000000000000000000 == 0) { + n = n + 1; + }; + + n + } + } + + #[test_only] use iota::test_utils::assert_eq; + + #[test_only] + fun pow(mut base: u128, mut exponent: u8): u128 { + let mut res: u128 = 1; + while (exponent >= 1) { + if (exponent % 2 == 0) { + base = base * base; + exponent = exponent / 2; + } else { + res = res * base; + exponent = exponent - 1; + } + }; + res + } + + #[test] + fun test_count_leading_zeros() { + let mut i: u8 = 0; + while (i <= 127) { + assert_eq(count_leading_zeros(pow(2, i) as u128), 128 - i - 1); + i = i + 1; + }; + + while (i <= 127) { + assert_eq(count_leading_zeros(pow(2, i) as u128 + 1), 128 - i - 1); + i = i + 1; + }; + assert_eq(count_leading_zeros(0), 128); + } + + #[test] + fun test_mul() { + assert_eq(unsafe_mul(1_000_000_000, 1), 1); + assert_eq(unsafe_mul(9_999_999_999, 1), 9); + assert_eq(unsafe_mul(9_000_000_000, 1), 9); + } + + #[test] + #[expected_failure(abort_code = EUnderflow)] + fun test_mul_underflow() { + mul(999_999_999, 1); + } + + #[test] + #[expected_failure(abort_code = EUnderflow)] + fun test_mul_round_check_underflow() { + mul_round(999_999_999, 1); + } + + #[test] + fun test_mul_round() { + let (mut is_round, mut result) = unsafe_mul_round(1_000_000_000, 1); + assert_eq(is_round, false); + assert_eq(result, 1); + (is_round, result) = unsafe_mul_round(9_999_999_999, 1); + assert_eq(is_round, true); + assert_eq(result, 9); + (is_round, result) = mul_round(9_999_999_999, 1); + assert_eq(is_round, true); + assert_eq(result, 9); + } + + #[test] + fun test_div() { + let (mut is_round, mut result) = unsafe_div_round(1, 1_000_000_000); + assert_eq(is_round, false); + assert_eq(result, 1); + (is_round, result) = unsafe_div_round(1, 9_999_999_999); + assert_eq(is_round, true); + assert_eq(result, 0); + (is_round, result) = unsafe_div_round(1, 999_999_999); + assert_eq(is_round, true); + assert_eq(result, 1); + } + + #[test] + fun test_div_round() { + let (mut is_round, mut result) = unsafe_div_round(1, 1_000_000_000); + assert_eq(is_round, false); + assert_eq(result, 1); + (is_round, result) = unsafe_div_round(1, 9_999_999_999); + assert_eq(is_round, true); + assert_eq(result, 0); + (is_round, result) = unsafe_div_round(1, 999_999_999); + assert_eq(is_round, true); + assert_eq(result, 1); + (is_round, result) = div_round(1, 999_999_999); + assert_eq(is_round, true); + assert_eq(result, 1); + } + + #[test] + #[expected_failure(abort_code = EUnderflow)] + fun test_div_round_check_underflow() { + div_round(1, 1_000_000_001); + } +} diff --git a/crates/sui-framework/packages/deepbook/sources/order_query.move b/crates/iota-framework/packages/deepbook/sources/order_query.move similarity index 98% rename from crates/sui-framework/packages/deepbook/sources/order_query.move rename to crates/iota-framework/packages/deepbook/sources/order_query.move index 615ab7994e6..9f08a206420 100644 --- a/crates/sui-framework/packages/deepbook/sources/order_query.move +++ b/crates/iota-framework/packages/deepbook/sources/order_query.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module deepbook::order_query { use std::option::{some, none}; use deepbook::critbit::CritbitTree; - use sui::linked_table; + use iota::linked_table; use deepbook::critbit; use deepbook::clob_v2; use deepbook::clob_v2::{Order, Pool, TickLevel}; diff --git a/crates/sui-framework/packages/deepbook/tests/clob_tests.move b/crates/iota-framework/packages/deepbook/tests/clob_tests.move similarity index 89% rename from crates/sui-framework/packages/deepbook/tests/clob_tests.move rename to crates/iota-framework/packages/deepbook/tests/clob_tests.move index 5043d1adb59..a189d1ee50d 100644 --- a/crates/sui-framework/packages/deepbook/tests/clob_tests.move +++ b/crates/iota-framework/packages/deepbook/tests/clob_tests.move @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] /// Tests for the pool module. /// They are sequential and based on top of each other. module deepbook::clob_test { - use sui::clock::{Self, Clock}; - use sui::coin::{Self, mint_for_testing, burn_for_testing}; - use sui::sui::SUI; - use sui::test_scenario::{Self as test, Scenario, next_tx, ctx, end, TransactionEffects}; - use sui::test_utils::assert_eq; + use iota::clock::{Self, Clock}; + use iota::coin::{Self, mint_for_testing, burn_for_testing}; + use iota::iota::IOTA; + use iota::test_scenario::{Self as test, Scenario, next_tx, ctx, end, TransactionEffects}; + use iota::test_utils::assert_eq; use deepbook::clob_v2::{Self as clob, Pool, PoolOwnerCap, WrappedPool, Order, USD, account_balance, get_pool_stat, order_id_for_test, list_open_orders, mint_account_cap_transfer, borrow_mut_pool}; use deepbook::custodian_v2::{Self as custodian, AccountCap, account_owner}; @@ -200,21 +201,21 @@ module deepbook::clob_test { mint_account_cap_transfer(bob, test::ctx(&mut test)); }; next_tx(&mut test, alice);{ - let pool = test::take_shared>(&test); - let (bid_price, ask_price) = clob::get_market_price(&pool); + let pool = test::take_shared>(&test); + let (bid_price, ask_price) = clob::get_market_price(&pool); assert_eq(option::is_none(&bid_price), true); assert_eq(option::is_none(&ask_price), true); test::return_shared(pool); }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 100000; + let alice_deposit_WIOTA: u64 = 100000; let alice_deposit_USDC: u64 = 100000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, true, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -236,13 +237,13 @@ module deepbook::clob_test { next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 100000; + let alice_deposit_WIOTA: u64 = 100000; let alice_deposit_USDC: u64 = 100000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 15 * FLOAT_SCALING, 500, 500, false, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -263,8 +264,8 @@ module deepbook::clob_test { }; next_tx(&mut test, alice);{ - let pool = test::take_shared>(&test); - let (bid_price, ask_price) = clob::get_market_price(&pool); + let pool = test::take_shared>(&test); + let (bid_price, ask_price) = clob::get_market_price(&pool); assert_eq(*option::borrow(&bid_price), 5 * FLOAT_SCALING); assert_eq(*option::borrow(&ask_price), 12 * FLOAT_SCALING); test::return_shared(pool); @@ -287,7 +288,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let clock = test::take_shared(&test); let (prices, depth) = clob::get_level2_book_status_bid_side( @@ -306,13 +307,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 100000; + let alice_deposit_WIOTA: u64 = 100000; let alice_deposit_USDC: u64 = 100000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, true, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -336,7 +337,7 @@ module deepbook::clob_test { // test get_level2_book_status_bid_side next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let clock = test::take_shared(&test); @@ -374,7 +375,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let clock = test::take_shared(&test); let (prices, depth) = clob::get_level2_book_status_ask_side( @@ -393,13 +394,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 100000; + let alice_deposit_WIOTA: u64 = 100000; let alice_deposit_USDC: u64 = 100000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, false, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -423,7 +424,7 @@ module deepbook::clob_test { // test get_level2_book_status_ask_side next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let clock = test::take_shared(&test); @@ -465,13 +466,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, false, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -487,7 +488,7 @@ module deepbook::clob_test { // test list_open_orders next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let open_orders = list_open_orders(&pool, &account_cap); @@ -516,7 +517,7 @@ module deepbook::clob_test { // test match (bid side) next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_bid( &mut pool, @@ -539,7 +540,7 @@ module deepbook::clob_test { // test list_open_orders after match next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let open_orders = list_open_orders(&pool, &account_cap); @@ -572,13 +573,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, true, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -594,7 +595,7 @@ module deepbook::clob_test { // test list_open_orders before match next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let open_orders = list_open_orders(&pool, &account_cap); @@ -623,7 +624,7 @@ module deepbook::clob_test { // test match (ask side) next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_ask( &mut pool, @@ -642,7 +643,7 @@ module deepbook::clob_test { // test list_open_orders after match next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let open_orders = list_open_orders(&pool, &account_cap); @@ -676,13 +677,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); test::return_shared(pool); test::return_to_address(alice, account_cap); @@ -690,7 +691,7 @@ module deepbook::clob_test { // test list_open_orders next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let open_orders = list_open_orders(&pool, &account_cap); let open_orders_cmp = vector::empty(); @@ -714,22 +715,22 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); - let alice_deposit_WSUI: u64 = 10000; - let alice_withdraw_WSUI: u64 = 5000; + let alice_deposit_WIOTA: u64 = 10000; + let alice_withdraw_WIOTA: u64 = 5000; let alice_deposit_USDC: u64 = 10000; let alice_withdraw_USDC: u64 = 1000; - clob::deposit_base(&mut pool, mint_for_testing(alice_deposit_WSUI, ctx(&mut test)), &account_cap); + clob::deposit_base(&mut pool, mint_for_testing(alice_deposit_WIOTA, ctx(&mut test)), &account_cap); clob::deposit_quote(&mut pool, mint_for_testing(alice_deposit_USDC, ctx(&mut test)), &account_cap); - burn_for_testing(clob::withdraw_base(&mut pool, alice_withdraw_WSUI, &account_cap, ctx(&mut test))); + burn_for_testing(clob::withdraw_base(&mut pool, alice_withdraw_WIOTA, &account_cap, ctx(&mut test))); burn_for_testing(clob::withdraw_quote(&mut pool, alice_withdraw_USDC, &account_cap, ctx(&mut test))); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance( base_custodian, account_cap_user, - alice_deposit_WSUI - alice_withdraw_WSUI, + alice_deposit_WIOTA - alice_withdraw_WIOTA, 0 ); custodian::assert_user_balance( @@ -758,13 +759,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, true, @@ -780,7 +781,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (next_bid_order_id, next_ask_order_id, _, _) = clob::get_pool_stat(&pool); @@ -826,7 +827,7 @@ module deepbook::clob_test { next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let mut orders = vector::empty(); @@ -877,13 +878,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 110000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order_with_expiration(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, true, @@ -901,7 +902,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); clob::check_balance_invariants_for_account(&account_cap, quote_custodian, base_custodian, &pool); @@ -910,13 +911,13 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let bob_deposit_WSUI: u64 = 20000; + let bob_deposit_WIOTA: u64 = 20000; let bob_deposit_USDC: u64 = 35000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, bob_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, bob_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, bob_deposit_USDC); clob::test_inject_limit_order_with_expiration(&mut pool, CLIENT_ID_BOB, 11 * FLOAT_SCALING, 500, 500, false, @@ -934,7 +935,7 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); clob::check_balance_invariants_for_account(&account_cap, quote_custodian, base_custodian, &pool); @@ -943,7 +944,7 @@ module deepbook::clob_test { }; next_tx(&mut test, owner); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap_alice = test::take_from_address(&test, alice); let account_cap_owner_alice = account_owner(&account_cap_alice); let account_cap_bob = test::take_from_address(&test, bob); @@ -966,7 +967,7 @@ module deepbook::clob_test { clob::check_empty_tick_level(bids, 2 * FLOAT_SCALING); clob::check_empty_tick_level(bids, 10 * FLOAT_SCALING); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - custodian::assert_user_balance(base_custodian, account_cap_owner_alice, 10000, 0); + custodian::assert_user_balance(base_custodian, account_cap_owner_alice, 10000, 0); custodian::assert_user_balance(quote_custodian, account_cap_owner_alice, 110000, 0); test::return_shared(pool); @@ -976,7 +977,7 @@ module deepbook::clob_test { }; next_tx(&mut test, owner); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap_bob = test::take_from_address(&test, bob); let account_cap_owner_bob = account_owner(&account_cap_bob); @@ -989,7 +990,7 @@ module deepbook::clob_test { clob::check_empty_tick_level(asks, 13 * FLOAT_SCALING); clob::check_empty_tick_level(asks, 14 * FLOAT_SCALING); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - custodian::assert_user_balance(base_custodian, account_cap_owner_bob, 20000, 0); + custodian::assert_user_balance(base_custodian, account_cap_owner_bob, 20000, 0); custodian::assert_user_balance(quote_custodian, account_cap_owner_bob, 35000, 0); test::return_shared(pool); @@ -1017,13 +1018,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); custodian::deposit( base_custodian, - mint_for_testing(1000 * 100000000, ctx(&mut test)), + mint_for_testing(1000 * 100000000, ctx(&mut test)), account_cap_user ); custodian::deposit( @@ -1038,10 +1039,10 @@ module deepbook::clob_test { // alice places limit orders next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let clock = test::take_shared(&test); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -1054,7 +1055,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 4 * FLOAT_SCALING, @@ -1067,7 +1068,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 4 * FLOAT_SCALING, @@ -1080,7 +1081,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 10 * FLOAT_SCALING, @@ -1102,7 +1103,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); clob::check_balance_invariants_for_account(&account_cap, quote_custodian, base_custodian, &pool); @@ -1111,27 +1112,27 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 7400 * 100000000, 2600 * 100000000); - custodian::assert_user_balance(base_custodian, account_cap_user, 0, 1000 * 100000000); + custodian::assert_user_balance(base_custodian, account_cap_user, 0, 1000 * 100000000); test::return_shared(pool); test::return_to_sender(&test, account_cap); }; next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let account_cap_user = account_owner(&account_cap); let (base_custodian, _) = clob::borrow_mut_custodian(&mut pool); custodian::deposit( base_custodian, - mint_for_testing(300 * 100000000, ctx(&mut test)), + mint_for_testing(300 * 100000000, ctx(&mut test)), account_cap_user ); - custodian::assert_user_balance(base_custodian, account_cap_user, 300 * 100000000, 0); + custodian::assert_user_balance(base_custodian, account_cap_user, 300 * 100000000, 0); test::return_shared(pool); test::return_to_address(bob, account_cap); }; @@ -1139,10 +1140,10 @@ module deepbook::clob_test { // bob places market order next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let clock = test::take_shared(&test); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_BOB, 4 * FLOAT_SCALING, @@ -1161,11 +1162,11 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - custodian::assert_user_balance(base_custodian, account_cap_user, 0, 0); + custodian::assert_user_balance(base_custodian, account_cap_user, 0, 0); custodian::assert_user_balance(quote_custodian, account_cap_user, 1400 * 100000000, 0); test::return_shared(pool); test::return_to_address(bob, account_cap); @@ -1173,7 +1174,7 @@ module deepbook::clob_test { next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); { @@ -1195,7 +1196,7 @@ module deepbook::clob_test { clob::check_tick_level(bids, 4 * FLOAT_SCALING, &open_orders); }; - clob::cancel_order(&mut pool, 2, &account_cap); + clob::cancel_order(&mut pool, 2, &account_cap); { let mut open_orders = vector::empty(); vector::push_back( @@ -1231,11 +1232,11 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); + custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); custodian::deposit(quote_custodian, mint_for_testing(10000, ctx(&mut test)), account_cap_user); test::return_shared(pool); test::return_to_sender(&test, account_cap); @@ -1244,10 +1245,10 @@ module deepbook::clob_test { // alice places limit orders next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let clock = test::take_shared(&test); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -1260,7 +1261,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -1273,7 +1274,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 2 * FLOAT_SCALING, @@ -1286,7 +1287,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 20 * FLOAT_SCALING, @@ -1317,7 +1318,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); clob::check_balance_invariants_for_account(&account_cap, quote_custodian, base_custodian, &pool); @@ -1327,16 +1328,16 @@ module deepbook::clob_test { // bob places market order next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, bob); - let (coin1, coin2) = clob::place_market_order(&mut pool, &account_cap, CLIENT_ID_BOB, 600, + let (coin1, coin2) = clob::place_market_order(&mut pool, &account_cap, CLIENT_ID_BOB, 600, false, - mint_for_testing(600, ctx(&mut test)), + mint_for_testing(600, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test)); - assert!(coin::value(&coin1) == 0, 0); + assert!(coin::value(&coin1) == 0, 0); assert!(coin::value(&coin2) == 2700 - 14, 0); burn_for_testing(coin1); burn_for_testing(coin2); @@ -1345,21 +1346,21 @@ module deepbook::clob_test { test::return_to_address(bob, account_cap); }; - // bob passes in 600sui, and sells 100sui of it through market ask order - // Bob should receive the remaining 500sui, - // and 199 usdt (excluding handling fee) for selling 100sui at a unit price of 2 + // bob passes in 600iota, and sells 100iota of it through market ask order + // Bob should receive the remaining 500iota, + // and 199 usdt (excluding handling fee) for selling 100iota at a unit price of 2 next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, bob); - let (coin1, coin2) =clob::place_market_order(&mut pool, &account_cap, CLIENT_ID_BOB, 100, + let (coin1, coin2) =clob::place_market_order(&mut pool, &account_cap, CLIENT_ID_BOB, 100, false, - mint_for_testing(600, ctx(&mut test)), + mint_for_testing(600, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test)); - assert!(coin::value(&coin1) == 500, 0); + assert!(coin::value(&coin1) == 500, 0); assert!(coin::value(&coin2) == 199, 0); burn_for_testing(coin1); burn_for_testing(coin2); @@ -1389,11 +1390,11 @@ module deepbook::clob_test { next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); + custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); custodian::deposit(quote_custodian, mint_for_testing(10000, ctx(&mut test)), account_cap_user); test::return_shared(pool); test::return_to_sender(&test, account_cap); @@ -1402,10 +1403,10 @@ module deepbook::clob_test { // alice places limit orders next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let clock = test::take_shared(&test); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -1418,7 +1419,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -1431,7 +1432,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 2 * FLOAT_SCALING, @@ -1444,7 +1445,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 20 * FLOAT_SCALING, @@ -1476,11 +1477,11 @@ module deepbook::clob_test { next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); + custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); custodian::deposit(quote_custodian, mint_for_testing(10000, ctx(&mut test)), account_cap_user); test::return_shared(pool); test::return_to_sender(&test, account_cap); @@ -1489,10 +1490,10 @@ module deepbook::clob_test { // bob places limit order of FILL_OR_KILL next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let clock = test::take_shared(&test); - let (base_quantity_filled, quote_quantity_filled, is_placed, order_id) = clob::place_limit_order( + let (base_quantity_filled, quote_quantity_filled, is_placed, order_id) = clob::place_limit_order( &mut pool, CLIENT_ID_BOB, 4 * FLOAT_SCALING, @@ -1518,11 +1519,11 @@ module deepbook::clob_test { // check bob's balance after the limit order is matched next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let clock = test::take_shared(&test); - let (base_avail, base_locked, quote_avail, quote_locked) = account_balance(&pool, &account_cap); + let (base_avail, base_locked, quote_avail, quote_locked) = account_balance(&pool, &account_cap); assert!(base_avail == 600, 0); assert!(base_locked == 0, 0); assert!(quote_avail == 11990, 0); @@ -1554,11 +1555,11 @@ module deepbook::clob_test { next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); + custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); custodian::deposit(quote_custodian, mint_for_testing(10000, ctx(&mut test)), account_cap_user); test::return_shared(pool); test::return_to_sender(&test, account_cap); @@ -1567,10 +1568,10 @@ module deepbook::clob_test { // alice places limit orders next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let clock = test::take_shared(&test); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -1583,7 +1584,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -1596,7 +1597,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 2 * FLOAT_SCALING, @@ -1609,7 +1610,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 20 * FLOAT_SCALING, @@ -1641,11 +1642,11 @@ module deepbook::clob_test { next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); + custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); custodian::deposit(quote_custodian, mint_for_testing(10000, ctx(&mut test)), account_cap_user); test::return_shared(pool); test::return_to_sender(&test, account_cap); @@ -1654,10 +1655,10 @@ module deepbook::clob_test { // bob places limit order of POST OR ABORT next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let clock = test::take_shared(&test); - let (base_quantity_filled, quote_quantity_filled, is_placed, order_id) = clob::place_limit_order( + let (base_quantity_filled, quote_quantity_filled, is_placed, order_id) = clob::place_limit_order( &mut pool, CLIENT_ID_BOB, 6 * FLOAT_SCALING, @@ -1683,11 +1684,11 @@ module deepbook::clob_test { // check bob's balance next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let clock = test::take_shared(&test); - let (base_avail, base_locked, quote_avail, quote_locked) = account_balance(&pool, &account_cap); + let (base_avail, base_locked, quote_avail, quote_locked) = account_balance(&pool, &account_cap); assert!(base_avail == 600, 0); assert!(base_locked == 400, 0); assert!(quote_avail == 10000, 0); @@ -1718,11 +1719,11 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); + custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); custodian::deposit(quote_custodian, mint_for_testing(10000, ctx(&mut test)), account_cap_user); test::return_shared(pool); test::return_to_sender(&test, account_cap); @@ -1731,10 +1732,10 @@ module deepbook::clob_test { // alice places limit orders next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let clock = test::take_shared(&test); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -1747,7 +1748,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -1760,7 +1761,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 2 * FLOAT_SCALING, @@ -1773,7 +1774,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 20 * FLOAT_SCALING, @@ -1806,15 +1807,15 @@ module deepbook::clob_test { // bob places market order next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, bob); - let (coin1, coin2) = clob::place_market_order(&mut pool, &account_cap, CLIENT_ID_BOB, 2000, false, - mint_for_testing(2000, ctx(&mut test)), + let (coin1, coin2) = clob::place_market_order(&mut pool, &account_cap, CLIENT_ID_BOB, 2000, false, + mint_for_testing(2000, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test)); - assert!(coin::value(&coin1) == 500, 0); + assert!(coin::value(&coin1) == 500, 0); assert!(coin::value(&coin2) == 4477, 0); burn_for_testing(coin1); burn_for_testing(coin2); @@ -1843,11 +1844,11 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - custodian::deposit(base_custodian, mint_for_testing(10000, ctx(&mut test)), account_cap_user); + custodian::deposit(base_custodian, mint_for_testing(10000, ctx(&mut test)), account_cap_user); custodian::deposit(quote_custodian, mint_for_testing(10000, ctx(&mut test)), account_cap_user); test::return_shared(pool); test::return_to_sender(&test, account_cap); @@ -1856,10 +1857,10 @@ module deepbook::clob_test { // alice places limit orders next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let clock = test::take_shared(&test); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -1872,7 +1873,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -1885,7 +1886,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 2 * FLOAT_SCALING, @@ -1898,7 +1899,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 1 * FLOAT_SCALING, @@ -1931,15 +1932,15 @@ module deepbook::clob_test { // bob places market order next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, bob); - let (coin1, coin2) = clob::place_market_order(&mut pool, &account_cap, CLIENT_ID_BOB, 5000, true, - mint_for_testing(10000, ctx(&mut test)), + let (coin1, coin2) = clob::place_market_order(&mut pool, &account_cap, CLIENT_ID_BOB, 5000, true, + mint_for_testing(10000, ctx(&mut test)), mint_for_testing(10000, ctx(&mut test)), &clock, ctx(&mut test)); - assert!(coin::value(&coin1) == 12000, 0); + assert!(coin::value(&coin1) == 12000, 0); assert!(coin::value(&coin2) == 10000 - (7000 + 36), 0); burn_for_testing(coin1); burn_for_testing(coin2); @@ -1968,13 +1969,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, false, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -1991,7 +1992,7 @@ module deepbook::clob_test { next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, bob); let (base_coin, quote_coin, _) = clob::swap_exact_quote_for_base( @@ -2038,13 +2039,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE,5 * FLOAT_SCALING, 500, 500, true, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -2060,7 +2061,7 @@ module deepbook::clob_test { next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, bob); let (base_coin, quote_coin, _) = clob::swap_exact_base_for_quote( @@ -2068,7 +2069,7 @@ module deepbook::clob_test { CLIENT_ID_BOB, &account_cap, 1500, - mint_for_testing(1500, ctx(&mut test)), + mint_for_testing(1500, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test) @@ -2107,15 +2108,15 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 1000000000; + let alice_deposit_WIOTA: u64 = 1000000000; let alice_deposit_USDC: u64 = 1000000000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); - // Example selling 0.1 sui, for the price of .719 + // Example selling 0.1 iota, for the price of .719 clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 719000, 1000000000, 1000000000, true, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -2124,7 +2125,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); @@ -2133,9 +2134,9 @@ module deepbook::clob_test { test::return_to_address(alice, account_cap); }; next_tx(&mut test, bob); - // Buys some sui from alice + // Buys some iota from alice { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let clock = test::take_shared(&test); @@ -2144,7 +2145,7 @@ module deepbook::clob_test { CLIENT_ID_BOB, &account_cap, 100000, - mint_for_testing(100000000, ctx(&mut test)), + mint_for_testing(100000000, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test) @@ -2159,7 +2160,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); clob::check_balance_invariants_for_account(&account_cap, quote_custodian, base_custodian, &pool); @@ -2169,7 +2170,7 @@ module deepbook::clob_test { // Alice cancels orders next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (_, quote_custodian) = clob::borrow_mut_custodian(&mut pool); @@ -2188,7 +2189,7 @@ module deepbook::clob_test { next_tx(&mut test, owner); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let pool_cap = test::take_from_address(&test, owner); let fees = clob::withdraw_fees(&pool_cap, &mut pool, test::ctx(&mut test)); let amount = coin::burn_for_testing(fees); @@ -2219,15 +2220,15 @@ module deepbook::clob_test { mint_account_cap_transfer(bob, test::ctx(&mut test)); next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 1000000000; + let alice_deposit_WIOTA: u64 = 1000000000; let alice_deposit_USDC: u64 = 1000000000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); - // Example selling 0.1 sui, for the price of .719 + // Example selling 0.1 iota, for the price of .719 clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 719000, 1000000000, 1000000000, true, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -2236,7 +2237,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); @@ -2245,9 +2246,9 @@ module deepbook::clob_test { test::return_to_address(alice, account_cap); }; - // Buys some sui from alice + // Buys some iota from alice next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let clock = test::take_shared(&test); @@ -2256,7 +2257,7 @@ module deepbook::clob_test { CLIENT_ID_BOB, &account_cap, 100000, - mint_for_testing(100000000, ctx(&mut test)), + mint_for_testing(100000000, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test) @@ -2271,7 +2272,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); clob::check_balance_invariants_for_account(&account_cap, quote_custodian, base_custodian, &pool); @@ -2281,7 +2282,7 @@ module deepbook::clob_test { // Alice cancels orders next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (_, quote_custodian) = clob::borrow_mut_custodian(&mut pool); @@ -2299,7 +2300,7 @@ module deepbook::clob_test { }; next_tx(&mut test, owner); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let pool_cap = test::take_from_address(&test, alice); let fees = clob::withdraw_fees(&pool_cap, &mut pool, test::ctx(&mut test)); let _ = coin::burn_for_testing(fees); @@ -2325,15 +2326,15 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 1000000000; + let alice_deposit_WIOTA: u64 = 1000000000; let alice_deposit_USDC: u64 = 1000000000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); - // Example selling 0.1 sui, for the price of .719 + // Example selling 0.1 iota, for the price of .719 clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 719000, 1000000000, 1000000000, true, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -2342,7 +2343,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); @@ -2351,9 +2352,9 @@ module deepbook::clob_test { test::return_to_address(alice, account_cap); }; next_tx(&mut test, bob); - // Buys some sui from alice + // Buys some iota from alice { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let clock = test::take_shared(&test); @@ -2362,7 +2363,7 @@ module deepbook::clob_test { CLIENT_ID_BOB, &account_cap, 100000, - mint_for_testing(100000000, ctx(&mut test)), + mint_for_testing(100000000, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test) @@ -2377,7 +2378,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); clob::check_balance_invariants_for_account(&account_cap, quote_custodian, base_custodian, &pool); @@ -2387,7 +2388,7 @@ module deepbook::clob_test { // Alice cancels orders next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (_, quote_custodian) = clob::borrow_mut_custodian(&mut pool); @@ -2406,7 +2407,7 @@ module deepbook::clob_test { next_tx(&mut test, owner); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let pool_cap = test::take_from_address(&test, owner); let fees = clob::withdraw_fees(&pool_cap, &mut pool, test::ctx(&mut test)); let amount = coin::burn_for_testing(fees); @@ -2433,13 +2434,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10; + let alice_deposit_WIOTA: u64 = 10; let alice_deposit_USDC: u64 = 100; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 2, 2, true, @@ -2457,7 +2458,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); @@ -2513,7 +2514,7 @@ module deepbook::clob_test { }; custodian::assert_user_balance(quote_custodian, account_cap_user, 35, 65); - custodian::assert_user_balance(base_custodian, account_cap_user, 0, 10); + custodian::assert_user_balance(base_custodian, account_cap_user, 0, 10); // check usr open orders before cancel { @@ -2536,7 +2537,7 @@ module deepbook::clob_test { next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); clob::cancel_order(&mut pool, 1, &account_cap); @@ -2569,16 +2570,16 @@ module deepbook::clob_test { { let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 35 + 10, 65 - 10); - custodian::assert_user_balance(base_custodian, account_cap_user, 0, 10); + custodian::assert_user_balance(base_custodian, account_cap_user, 0, 10); test::return_shared(pool); test::return_to_address(alice, account_cap); }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); clob::cancel_order(&mut pool, 2, &account_cap); @@ -2599,18 +2600,18 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 35 + 10 + 15, 65 - 10 - 15); - custodian::assert_user_balance(base_custodian, account_cap_user, 0, 10); + custodian::assert_user_balance(base_custodian, account_cap_user, 0, 10); test::return_shared(pool); test::return_to_address(alice, account_cap); }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); clob::cancel_order(&mut pool, MIN_ASK_ORDER_ID, &account_cap); @@ -2629,12 +2630,12 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 35 + 10 + 15, 65 - 10 - 15); - custodian::assert_user_balance(base_custodian, account_cap_user, 10, 0); + custodian::assert_user_balance(base_custodian, account_cap_user, 10, 0); test::return_shared(pool); test::return_to_address(alice, account_cap); }; @@ -2659,9 +2660,9 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); - let (base_quantity_filled, quote_quantity_filled) = clob::test_match_bid_with_quote_quantity(&mut pool, &account_cap, CLIENT_ID_BOB, 500, MAX_PRICE, 0); + let (base_quantity_filled, quote_quantity_filled) = clob::test_match_bid_with_quote_quantity(&mut pool, &account_cap, CLIENT_ID_BOB, 500, MAX_PRICE, 0); assert_eq(base_quantity_filled, 0); assert_eq(quote_quantity_filled, 0); test::return_to_address(bob, account_cap); @@ -2669,13 +2670,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, false, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -2692,13 +2693,13 @@ module deepbook::clob_test { // test inject limit order and match (bid side) next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 0, 10000); - custodian::assert_user_balance(base_custodian, account_cap_user, 8000, 2000); + custodian::assert_user_balance(base_custodian, account_cap_user, 8000, 2000); let (next_bid_order_id, next_ask_order_id, _, _) = clob::get_pool_stat(&pool); assert!(next_bid_order_id == clob::order_id_for_test(1, true), 0); assert!(next_ask_order_id == clob::order_id_for_test(3, false), 0); @@ -2743,7 +2744,7 @@ module deepbook::clob_test { // test match (bid side) next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_bid_with_quote_quantity( &mut pool, @@ -2770,13 +2771,13 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap_alice = test::take_from_address(&test, alice); let account_cap_user_alice = account_owner(&account_cap_alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user_alice, 4498 - 10 - 13 + 5 + 6, 10000); - custodian::assert_user_balance(base_custodian, account_cap_user_alice, 8000, 500 + 5); + custodian::assert_user_balance(base_custodian, account_cap_user_alice, 8000, 500 + 5); { let (_, _, _, asks) = get_pool_stat(&pool); clob::check_empty_tick_level(asks, 2 * FLOAT_SCALING); @@ -2826,7 +2827,7 @@ module deepbook::clob_test { next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_bid_with_quote_quantity( @@ -2845,7 +2846,7 @@ module deepbook::clob_test { next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); { let (_, _, _, asks) = get_pool_stat(&pool); clob::check_empty_tick_level(asks, 2 * FLOAT_SCALING); @@ -2879,13 +2880,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, false, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -2900,7 +2901,7 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_bid_with_quote_quantity( &mut pool, @@ -2918,13 +2919,13 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap_alice = test::take_from_address(&test, alice); let account_cap_user_alice = account_owner(&account_cap_alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user_alice, 0, 10000); - custodian::assert_user_balance(base_custodian, account_cap_user_alice, 8000, 2000); + custodian::assert_user_balance(base_custodian, account_cap_user_alice, 8000, 2000); { let mut open_orders = vector::empty(); vector::push_back( @@ -3002,13 +3003,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, false, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -3023,7 +3024,7 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_bid_with_quote_quantity( &mut pool, @@ -3040,13 +3041,13 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap_alice = test::take_from_address(&test, alice); let account_cap_user_alice = account_owner(&account_cap_alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user_alice, 4473 - 10 - 13 + 5 + 6, 10000); - custodian::assert_user_balance(base_custodian, account_cap_user_alice, 8000, 500 + 10); + custodian::assert_user_balance(base_custodian, account_cap_user_alice, 8000, 500 + 10); { let (_, _, _, asks) = get_pool_stat(&pool); clob::check_empty_tick_level(asks, 2 * FLOAT_SCALING); @@ -3114,13 +3115,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, false, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -3135,12 +3136,12 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 0, 10000); - custodian::assert_user_balance(base_custodian, account_cap_user, 8000, 2000); + custodian::assert_user_balance(base_custodian, account_cap_user, 8000, 2000); let (next_bid_order_id, next_ask_order_id, _, _) = clob::get_pool_stat(&pool); assert!(next_bid_order_id == clob::order_id_for_test(1, true), 0); assert!(next_ask_order_id == clob::order_id_for_test(3, false), 0); @@ -3183,7 +3184,7 @@ module deepbook::clob_test { // test match (bid side) next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_bid( &mut pool, @@ -3200,13 +3201,13 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap_alice = test::take_from_address(&test, alice); let account_cap_user_alice = account_owner(&account_cap_alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user_alice, 4500 + 5 + 6, 10000); - custodian::assert_user_balance(base_custodian, account_cap_user_alice, 8000, 500); + custodian::assert_user_balance(base_custodian, account_cap_user_alice, 8000, 500); { let (_, _, _, asks) = get_pool_stat(&pool); clob::check_empty_tick_level(asks, 2 * FLOAT_SCALING); @@ -3254,13 +3255,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, false, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -3275,12 +3276,12 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 0, 10000); - custodian::assert_user_balance(base_custodian, account_cap_user, 8000, 2000); + custodian::assert_user_balance(base_custodian, account_cap_user, 8000, 2000); let (next_bid_order_id, next_ask_order_id, _, _) = clob::get_pool_stat(&pool); assert!(next_bid_order_id == clob::order_id_for_test(1, true), 0); assert!(next_ask_order_id == clob::order_id_for_test(3, false), 0); @@ -3323,7 +3324,7 @@ module deepbook::clob_test { // test match (bid side) next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_bid( &mut pool, @@ -3340,12 +3341,12 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap_alice = test::take_from_address(&test, alice); let account_cap_user_alice = account_owner(&account_cap_alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); - custodian::assert_user_balance(base_custodian, account_cap_user_alice, 8000, 750); + custodian::assert_user_balance(base_custodian, account_cap_user_alice, 8000, 750); custodian::assert_user_balance(quote_custodian, account_cap_user_alice, 3258, 10000); { @@ -3399,13 +3400,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); test::return_shared(pool); test::return_to_address(alice, account_cap); @@ -3413,7 +3414,7 @@ module deepbook::clob_test { // test inject limit order and match (ask side) next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, true, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -3429,12 +3430,12 @@ module deepbook::clob_test { next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 3000, 7000); - custodian::assert_user_balance(base_custodian, account_cap_user, 0, 10000); + custodian::assert_user_balance(base_custodian, account_cap_user, 0, 10000); let (next_bid_order_id, next_ask_order_id, _, _) = clob::get_pool_stat(&pool); assert!(next_bid_order_id == clob::order_id_for_test(3, true), 0); assert!(next_ask_order_id == clob::order_id_for_test(1, false), 0); @@ -3478,7 +3479,7 @@ module deepbook::clob_test { // test match (ask side) next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_ask( &mut pool, @@ -3495,7 +3496,7 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); @@ -3505,7 +3506,7 @@ module deepbook::clob_test { 3000 + 6 + 6 + 2, 7000 - 2500 - 2500 - 1000 ); - custodian::assert_user_balance(base_custodian, account_cap_user, 1500, 10000); + custodian::assert_user_balance(base_custodian, account_cap_user, 1500, 10000); { let (_, _, bids, _) = get_pool_stat(&pool); clob::check_empty_tick_level(bids, 5 * FLOAT_SCALING); @@ -3554,13 +3555,13 @@ module deepbook::clob_test { // test inject limit order and match (bid side) next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order_with_expiration( &mut pool, @@ -3615,13 +3616,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 0, 10000); - custodian::assert_user_balance(base_custodian, account_cap_user, 8000, 2000); + custodian::assert_user_balance(base_custodian, account_cap_user, 8000, 2000); let (next_bid_order_id, next_ask_order_id, _, _) = clob::get_pool_stat(&pool); assert!(next_bid_order_id == clob::order_id_for_test(1, true), 0); assert!(next_ask_order_id == clob::order_id_for_test(3, false), 0); @@ -3684,7 +3685,7 @@ module deepbook::clob_test { // test match (bid side) next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_bid_with_quote_quantity( &mut pool, @@ -3701,13 +3702,13 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); // rebate fee in base asset 3 custodian::assert_user_balance(quote_custodian, account_cap_user, 4498 - 10 - 13 + 5 + 6, 10000); - custodian::assert_user_balance(base_custodian, account_cap_user, 8500, 5); + custodian::assert_user_balance(base_custodian, account_cap_user, 8500, 5); { let (_, _, _, asks) = get_pool_stat(&pool); clob::check_empty_tick_level(asks, 2 * FLOAT_SCALING); @@ -3756,13 +3757,13 @@ module deepbook::clob_test { // test inject limit order and match (bid side) next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order_with_expiration( &mut pool, @@ -3817,14 +3818,14 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 0, 10000); - custodian::assert_user_balance(base_custodian, account_cap_user, 8000, 2000); + custodian::assert_user_balance(base_custodian, account_cap_user, 8000, 2000); let (next_bid_order_id, next_ask_order_id, _, _) = clob::get_pool_stat(&pool); assert!(next_bid_order_id == clob::order_id_for_test(1, true), 0); assert!(next_ask_order_id == clob::order_id_for_test(3, false), 0); @@ -3887,7 +3888,7 @@ module deepbook::clob_test { // test match (bid side) next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_bid( &mut pool, @@ -3904,13 +3905,13 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); // rebate fee in base asset 3 custodian::assert_user_balance(quote_custodian, account_cap_user, 4500 + 5 + 6, 10000); - custodian::assert_user_balance(base_custodian, account_cap_user, 8500, 0); + custodian::assert_user_balance(base_custodian, account_cap_user, 8500, 0); { let (_, _, _, asks) = get_pool_stat(&pool); clob::check_empty_tick_level(asks, 2 * FLOAT_SCALING); @@ -3953,13 +3954,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); test::return_shared(pool); test::return_to_address(alice, account_cap); @@ -3967,7 +3968,7 @@ module deepbook::clob_test { // test inject limit order and match (ask side) next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); clob::test_inject_limit_order_with_expiration( &mut pool, @@ -4022,12 +4023,12 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 500, 9500); - custodian::assert_user_balance(base_custodian, account_cap_user, 0, 10000); + custodian::assert_user_balance(base_custodian, account_cap_user, 0, 10000); let (next_bid_order_id, next_ask_order_id, _, _) = clob::get_pool_stat(&pool); assert!(next_bid_order_id == clob::order_id_for_test(3, true), 0); assert!(next_ask_order_id == clob::order_id_for_test(1, false), 0); @@ -4108,7 +4109,7 @@ module deepbook::clob_test { // test match (ask side) next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_ask( &mut pool, @@ -4125,7 +4126,7 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); @@ -4135,7 +4136,7 @@ module deepbook::clob_test { 5500 + 6 + 5, 9500 - 2500 - 5000 - 2000 ); - custodian::assert_user_balance(base_custodian, account_cap_user, 1500, 10000); + custodian::assert_user_balance(base_custodian, account_cap_user, 1500, 10000); { let (_, _, bids, _) = get_pool_stat(&pool); clob::check_empty_tick_level(bids, 5 * FLOAT_SCALING); @@ -4178,13 +4179,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 100; + let alice_deposit_WIOTA: u64 = 100; let alice_deposit_USDC: u64 = 10; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 2, 2, false, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -4200,12 +4201,12 @@ module deepbook::clob_test { next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 0, 10); - custodian::assert_user_balance(base_custodian, account_cap_user, 85, 15); + custodian::assert_user_balance(base_custodian, account_cap_user, 85, 15); let (next_bid_order_id, next_ask_order_id, _, _) = clob::get_pool_stat(&pool); assert!(next_bid_order_id == clob::order_id_for_test(1, true), 0); assert!(next_ask_order_id == clob::order_id_for_test(3, false), 0); @@ -4250,7 +4251,7 @@ module deepbook::clob_test { // test match with price limit (bid side) next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_bid( &mut pool, @@ -4267,12 +4268,12 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 45, 10); - custodian::assert_user_balance(base_custodian, account_cap_user, 85, 0); + custodian::assert_user_balance(base_custodian, account_cap_user, 85, 0); { let (_, _, _, asks) = get_pool_stat(&pool); clob::check_empty_tick_level(asks, 2 * FLOAT_SCALING); @@ -4316,13 +4317,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10; + let alice_deposit_WIOTA: u64 = 10; let alice_deposit_USDC: u64 = 100; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); test::return_shared(pool); test::return_to_address(alice, account_cap); @@ -4330,7 +4331,7 @@ module deepbook::clob_test { // test inject limit order and match (ask side) next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); // let account_cap_user = get_account_cap_user(&account_cap); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 2, 2, true, @@ -4346,12 +4347,12 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 55, 45); - custodian::assert_user_balance(base_custodian, account_cap_user, 0, 10); + custodian::assert_user_balance(base_custodian, account_cap_user, 0, 10); let (next_bid_order_id, next_ask_order_id, _, _) = clob::get_pool_stat(&pool); assert!(next_bid_order_id == clob::order_id_for_test(3, true), 0); assert!(next_ask_order_id == clob::order_id_for_test(1, false), 0); @@ -4396,7 +4397,7 @@ module deepbook::clob_test { // test match with price limit (ask side) next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_ask( &mut pool, @@ -4413,12 +4414,12 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 55, 20); - custodian::assert_user_balance(base_custodian, account_cap_user, 5, 10); + custodian::assert_user_balance(base_custodian, account_cap_user, 5, 10); { let (_, _, bids, _) = get_pool_stat(&pool); clob::check_empty_tick_level(bids, 5 * FLOAT_SCALING); @@ -4466,14 +4467,14 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut wrapped_pool = test::take_shared>(&test); - let pool = borrow_mut_pool(&mut wrapped_pool); + let mut wrapped_pool = test::take_shared>(&test); + let pool = borrow_mut_pool(&mut wrapped_pool); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(pool); - let alice_deposit_WSUI: u64 = 10; + let alice_deposit_WIOTA: u64 = 10; let alice_deposit_USDC: u64 = 100; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); test::return_shared(wrapped_pool); test::return_to_address(alice, account_cap); @@ -4481,8 +4482,8 @@ module deepbook::clob_test { // test inject limit order and match (ask side) next_tx(&mut test, alice); { - let mut wrapped_pool = test::take_shared>(&test); - let pool = borrow_mut_pool(&mut wrapped_pool); + let mut wrapped_pool = test::take_shared>(&test); + let pool = borrow_mut_pool(&mut wrapped_pool); let account_cap = test::take_from_address(&test, alice); // let account_cap_user = get_account_cap_user(&account_cap); clob::test_inject_limit_order( @@ -4534,13 +4535,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut wrapped_pool = test::take_shared>(&test); - let pool = borrow_mut_pool(&mut wrapped_pool); + let mut wrapped_pool = test::take_shared>(&test); + let pool = borrow_mut_pool(&mut wrapped_pool); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 55, 45); - custodian::assert_user_balance(base_custodian, account_cap_user, 0, 10); + custodian::assert_user_balance(base_custodian, account_cap_user, 0, 10); let (next_bid_order_id, next_ask_order_id, _, _) = clob::get_pool_stat(pool); assert!(next_bid_order_id == clob::order_id_for_test(3, true), 0); assert!(next_ask_order_id == clob::order_id_for_test(1, false), 0); @@ -4585,8 +4586,8 @@ module deepbook::clob_test { // test match with price limit (ask side) next_tx(&mut test, bob); { - let mut wrapped_pool = test::take_shared>(&test); - let pool = borrow_mut_pool(&mut wrapped_pool); + let mut wrapped_pool = test::take_shared>(&test); + let pool = borrow_mut_pool(&mut wrapped_pool); let account_cap = test::take_from_address(&test, bob); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_ask( pool, @@ -4603,13 +4604,13 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); { - let mut wrapped_pool = test::take_shared>(&test); - let pool = borrow_mut_pool(&mut wrapped_pool); + let mut wrapped_pool = test::take_shared>(&test); + let pool = borrow_mut_pool(&mut wrapped_pool); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(pool); custodian::assert_user_balance(quote_custodian, account_cap_user, 55, 20); - custodian::assert_user_balance(base_custodian, account_cap_user, 5, 10); + custodian::assert_user_balance(base_custodian, account_cap_user, 5, 10); { let (_, _, bids, _) = get_pool_stat(pool); clob::check_empty_tick_level(bids, 5 * FLOAT_SCALING); @@ -4652,13 +4653,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10; + let alice_deposit_WIOTA: u64 = 10; let alice_deposit_USDC: u64 = 100; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 2, 2, true, @@ -4801,13 +4802,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10; + let alice_deposit_WIOTA: u64 = 10; let alice_deposit_USDC: u64 = 100; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 2, 2, true, @@ -4936,11 +4937,11 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); + custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); custodian::deposit(quote_custodian, mint_for_testing(10000, ctx(&mut test)), account_cap_user); test::return_shared(pool); test::return_to_sender(&test, account_cap); @@ -4949,10 +4950,10 @@ module deepbook::clob_test { // alice places limit orders next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let clock = test::take_shared(&test); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -4965,7 +4966,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -4978,7 +4979,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 2 * FLOAT_SCALING, @@ -4991,7 +4992,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 20 * FLOAT_SCALING, @@ -5024,16 +5025,16 @@ module deepbook::clob_test { // alice places market order next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, alice); - let (coin1, coin2) =clob::place_market_order(&mut pool, &account_cap, CLIENT_ID_ALICE, 600, + let (coin1, coin2) =clob::place_market_order(&mut pool, &account_cap, CLIENT_ID_ALICE, 600, false, - mint_for_testing(600, ctx(&mut test)), + mint_for_testing(600, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test)); - assert!(coin::value(&coin1) == 600, 0); + assert!(coin::value(&coin1) == 600, 0); assert!(coin::value(&coin2) == 0, 0); burn_for_testing(coin1); burn_for_testing(coin2); @@ -5069,11 +5070,11 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - custodian::deposit(base_custodian, mint_for_testing(1500, ctx(&mut test)), account_cap_user); + custodian::deposit(base_custodian, mint_for_testing(1500, ctx(&mut test)), account_cap_user); custodian::deposit(quote_custodian, mint_for_testing(10000, ctx(&mut test)), account_cap_user); test::return_shared(pool); test::return_to_sender(&test, account_cap); @@ -5082,10 +5083,10 @@ module deepbook::clob_test { // alice places limit orders next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let clock = test::take_shared(&test); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -5098,7 +5099,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -5111,7 +5112,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 2 * FLOAT_SCALING, @@ -5124,7 +5125,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 1 * FLOAT_SCALING, @@ -5157,16 +5158,16 @@ module deepbook::clob_test { // alice places market buy order next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, alice); - let (coin1, coin2) =clob::place_market_order(&mut pool, &account_cap, CLIENT_ID_ALICE, 1, + let (coin1, coin2) =clob::place_market_order(&mut pool, &account_cap, CLIENT_ID_ALICE, 1, true, - mint_for_testing(0, ctx(&mut test)), + mint_for_testing(0, ctx(&mut test)), mint_for_testing(1, ctx(&mut test)), &clock, ctx(&mut test)); - assert!(coin::value(&coin1) == 0, 0); + assert!(coin::value(&coin1) == 0, 0); assert!(coin::value(&coin2) == 1, 0); burn_for_testing(coin1); burn_for_testing(coin2); @@ -5202,11 +5203,11 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); + custodian::deposit(base_custodian, mint_for_testing(1000, ctx(&mut test)), account_cap_user); custodian::deposit(quote_custodian, mint_for_testing(10000, ctx(&mut test)), account_cap_user); test::return_shared(pool); test::return_to_sender(&test, account_cap); @@ -5214,10 +5215,10 @@ module deepbook::clob_test { // alice places limit orders next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let clock = test::take_shared(&test); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -5230,7 +5231,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, @@ -5243,7 +5244,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 2 * FLOAT_SCALING, @@ -5256,7 +5257,7 @@ module deepbook::clob_test { &account_cap, ctx(&mut test) ); - clob::place_limit_order( + clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 20 * FLOAT_SCALING, @@ -5287,21 +5288,21 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let account_cap_user = account_owner(&account_cap); let (base_custodian, _) = clob::borrow_mut_custodian(&mut pool); - custodian::deposit(base_custodian, mint_for_testing(400, ctx(&mut test)), account_cap_user); + custodian::deposit(base_custodian, mint_for_testing(400, ctx(&mut test)), account_cap_user); test::return_shared(pool); test::return_to_sender(&test, account_cap); }; // alice places limit order next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let clock = test::take_shared(&test); - let (base_quantity_filled, quote_quantity_filled, is_placed, order_id) = clob::place_limit_order( + let (base_quantity_filled, quote_quantity_filled, is_placed, order_id) = clob::place_limit_order( &mut pool, CLIENT_ID_ALICE, 4 * FLOAT_SCALING, @@ -5327,11 +5328,11 @@ module deepbook::clob_test { // check alice's balance next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_sender(&test); let clock = test::take_shared(&test); - let (base_avail, base_locked, quote_avail, quote_locked) = account_balance(&pool, &account_cap); + let (base_avail, base_locked, quote_avail, quote_locked) = account_balance(&pool, &account_cap); assert!(base_avail == 0, 0); assert!(base_locked == 1000 + 400, 0); assert!(quote_avail == 8000, 0); @@ -5360,13 +5361,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, false, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -5382,7 +5383,7 @@ module deepbook::clob_test { next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, alice); let (base_coin, quote_coin, _) = clob::swap_exact_quote_for_base( @@ -5401,7 +5402,7 @@ module deepbook::clob_test { let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); - custodian::assert_user_balance(base_custodian, account_cap_user, 10000, 0); + custodian::assert_user_balance(base_custodian, account_cap_user, 10000, 0); custodian::assert_user_balance(quote_custodian, account_cap_user, 0, 10000); test::return_shared(clock); @@ -5430,13 +5431,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, false, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -5452,7 +5453,7 @@ module deepbook::clob_test { // test match (bid side) next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_bid( &mut pool, @@ -5469,11 +5470,11 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); - custodian::assert_user_balance(base_custodian, account_cap_user, 10000, 0); + custodian::assert_user_balance(base_custodian, account_cap_user, 10000, 0); custodian::assert_user_balance(quote_custodian, account_cap_user, 0, 10000); let (next_bid_order_id, next_ask_order_id, _, _) = clob::get_pool_stat(&pool); assert!(next_bid_order_id == clob::order_id_for_test(1, true), 0); @@ -5520,13 +5521,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); test::return_shared(pool); test::return_to_address(alice, account_cap); @@ -5534,7 +5535,7 @@ module deepbook::clob_test { // test inject limit order and match (ask side) next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, true, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -5551,7 +5552,7 @@ module deepbook::clob_test { // test match (ask side) next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let (base_quantity_filled, quote_quantity_filled) = clob::test_match_ask( &mut pool, @@ -5568,7 +5569,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); @@ -5578,7 +5579,7 @@ module deepbook::clob_test { 10000, 0 ); - custodian::assert_user_balance( + custodian::assert_user_balance( base_custodian, account_cap_user, 0, @@ -5626,21 +5627,21 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 1000000000; + let alice_deposit_WIOTA: u64 = 1000000000; let alice_deposit_USDC: u64 = 1000000000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); let(_, _) = custodian::account_balance(quote_custodian, account_cap_user); - // Example buying 0.1 sui, for the price of .719 + // Example buying 0.1 iota, for the price of .719 clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 719000, 1000000000, 1000000000, true, CANCEL_OLDEST, &account_cap,ctx(&mut test)); - // Example selling 0.1 sui for the price of .519 + // Example selling 0.1 iota for the price of .519 clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 519000, 1000000000, 1000000000, false, CANCEL_OLDEST, &account_cap,ctx(&mut test)); test::return_shared(pool); @@ -5650,7 +5651,7 @@ module deepbook::clob_test { next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); clob::check_balance_invariants_for_account(&account_cap, quote_custodian, base_custodian, &pool); @@ -5658,9 +5659,9 @@ module deepbook::clob_test { test::return_to_address(alice, account_cap); }; next_tx(&mut test, bob); - // Buys some sui from alice + // Buys some iota from alice { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let clock = test::take_shared(&test); @@ -5669,7 +5670,7 @@ module deepbook::clob_test { CLIENT_ID_BOB, &account_cap, 100000, - mint_for_testing(100000000, ctx(&mut test)), + mint_for_testing(100000000, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test) @@ -5684,7 +5685,7 @@ module deepbook::clob_test { CLIENT_ID_BOB, &account_cap, 100000, - mint_for_testing(100000000, ctx(&mut test)), + mint_for_testing(100000000, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test) @@ -5699,11 +5700,11 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); // cancel all order - // clob::cancel_order(&mut pool, 1, &account_cap); - // clob::cancel_all_orders(&mut pool, &account_cap); + // clob::cancel_order(&mut pool, 1, &account_cap); + // clob::cancel_all_orders(&mut pool, &account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); clob::check_balance_invariants_for_account(&account_cap, quote_custodian, base_custodian, &pool); test::return_shared(pool); @@ -5712,17 +5713,17 @@ module deepbook::clob_test { next_tx(&mut test, bob); // Sells some USDC to alice { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let clock = test::take_shared(&test); - let (base_coin, quote_coin) = clob::place_market_order( + let (base_coin, quote_coin) = clob::place_market_order( &mut pool, &account_cap, CLIENT_ID_BOB, 100000, true, - mint_for_testing(0, ctx(&mut test)), + mint_for_testing(0, ctx(&mut test)), mint_for_testing(100000, ctx(&mut test)), &clock, ctx(&mut test) @@ -5732,13 +5733,13 @@ module deepbook::clob_test { burn_for_testing(quote_coin); // buy second time - let (base_coin, quote_coin) = clob::place_market_order( + let (base_coin, quote_coin) = clob::place_market_order( &mut pool, &account_cap, CLIENT_ID_BOB, 100000, true, - mint_for_testing(0, ctx(&mut test)), + mint_for_testing(0, ctx(&mut test)), mint_for_testing(100000, ctx(&mut test)), &clock, ctx(&mut test) @@ -5749,13 +5750,13 @@ module deepbook::clob_test { // Buys but this time utilizes a different code path - let (base_coin, quote_coin) = clob::place_market_order( + let (base_coin, quote_coin) = clob::place_market_order( &mut pool, &account_cap, CLIENT_ID_BOB, 100000, false, - mint_for_testing(100000, ctx(&mut test)), + mint_for_testing(100000, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test) @@ -5765,13 +5766,13 @@ module deepbook::clob_test { burn_for_testing(quote_coin); // buy second time - let (base_coin, quote_coin) = clob::place_market_order( + let (base_coin, quote_coin) = clob::place_market_order( &mut pool, &account_cap, CLIENT_ID_BOB, 100000, false, - mint_for_testing(100000, ctx(&mut test)), + mint_for_testing(100000, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test) @@ -5786,7 +5787,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); clob::check_balance_invariants_for_account(&account_cap, quote_custodian, base_custodian, &pool); @@ -5796,10 +5797,10 @@ module deepbook::clob_test { next_tx(&mut test, alice); // Check cancel all orders returns all funds { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); // cancel all order - clob::cancel_all_orders(&mut pool, &account_cap); + clob::cancel_all_orders(&mut pool, &account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); clob::check_balance_invariants_for_account(&account_cap, quote_custodian, base_custodian, &pool); test::return_shared(pool); @@ -5829,17 +5830,17 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 2000000000; + let alice_deposit_WIOTA: u64 = 2000000000; let alice_deposit_USDC: u64 = 2000000000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); let(_, _) = custodian::account_balance(quote_custodian, account_cap_user); - // Example buying 0.1 sui, for the price of .719 + // Example buying 0.1 iota, for the price of .719 clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 719000, 1000000000, 1000000000, true, CANCEL_OLDEST, &account_cap,ctx(&mut test)); @@ -5853,9 +5854,9 @@ module deepbook::clob_test { }; next_tx(&mut test, bob); - // Sell sui to alice, first rounding token cut in match_ask else clause + // Sell iota to alice, first rounding token cut in match_ask else clause { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, bob); let clock = test::take_shared(&test); @@ -5864,7 +5865,7 @@ module deepbook::clob_test { CLIENT_ID_BOB, &account_cap, 100000, - mint_for_testing(100000000, ctx(&mut test)), + mint_for_testing(100000000, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test) @@ -5880,7 +5881,7 @@ module deepbook::clob_test { next_tx(&mut test, alice); // alice self matching, second rounding token cut in match_ask if clause { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let clock = test::take_shared(&test); @@ -5889,7 +5890,7 @@ module deepbook::clob_test { CLIENT_ID_ALICE, &account_cap, 100000, - mint_for_testing(100000000, ctx(&mut test)), + mint_for_testing(100000000, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test) @@ -5904,7 +5905,7 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let pool = test::take_shared>(&test); + let pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); clob::check_balance_invariants_for_account(&account_cap, quote_custodian, base_custodian, &pool); @@ -5914,10 +5915,10 @@ module deepbook::clob_test { next_tx(&mut test, alice); // Check cancel all orders returns all funds { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); // cancel all order - clob::cancel_all_orders(&mut pool, &account_cap); + clob::cancel_all_orders(&mut pool, &account_cap); let (base_custodian, quote_custodian) = clob::borrow_custodian(&pool); clob::check_balance_invariants_for_account(&account_cap, quote_custodian, base_custodian, &pool); test::return_shared(pool); @@ -5944,13 +5945,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, false, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -5960,7 +5961,7 @@ module deepbook::clob_test { next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, bob); let (base_coin, quote_coin, _, of_events) = clob::swap_exact_quote_for_base_with_metadata( @@ -6006,13 +6007,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, true, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -6022,7 +6023,7 @@ module deepbook::clob_test { next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, bob); let (base_coin, quote_coin, _, of_events) = clob::swap_exact_base_for_quote_with_metadata( @@ -6030,7 +6031,7 @@ module deepbook::clob_test { CLIENT_ID_BOB, &account_cap, 500, - mint_for_testing(500, ctx(&mut test)), + mint_for_testing(500, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test) @@ -6069,13 +6070,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, true, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -6085,7 +6086,7 @@ module deepbook::clob_test { next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, bob); let (base_coin, quote_coin, of_events) = clob::place_market_order_with_metadata( @@ -6094,7 +6095,7 @@ module deepbook::clob_test { CLIENT_ID_BOB, 500, false, - mint_for_testing(500, ctx(&mut test)), + mint_for_testing(500, ctx(&mut test)), mint_for_testing(0, ctx(&mut test)), &clock, ctx(&mut test) @@ -6133,13 +6134,13 @@ module deepbook::clob_test { }; next_tx(&mut test, alice); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let account_cap = test::take_from_address(&test, alice); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob::borrow_mut_custodian(&mut pool); - let alice_deposit_WSUI: u64 = 10000; + let alice_deposit_WIOTA: u64 = 10000; let alice_deposit_USDC: u64 = 10000; - custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_cap_user, alice_deposit_WIOTA); custodian::test_increase_user_available_balance(quote_custodian, account_cap_user, alice_deposit_USDC); clob::test_inject_limit_order(&mut pool, CLIENT_ID_ALICE, 5 * FLOAT_SCALING, 500, 500, true, CANCEL_OLDEST, &account_cap, ctx(&mut test)); @@ -6149,12 +6150,12 @@ module deepbook::clob_test { next_tx(&mut test, bob); { - let mut pool = test::take_shared>(&test); + let mut pool = test::take_shared>(&test); let clock = test::take_shared(&test); let account_cap = test::take_from_address(&test, bob); - let bob_deposit_WSUI: u64 = 10000; + let bob_deposit_WIOTA: u64 = 10000; let (base_custodian, _) = clob::borrow_mut_custodian(&mut pool); - custodian::test_increase_user_available_balance(base_custodian, account_owner(&account_cap), bob_deposit_WSUI); + custodian::test_increase_user_available_balance(base_custodian, account_owner(&account_cap), bob_deposit_WIOTA); let (_, _, _, _, of_events) = clob::place_limit_order_with_metadata( &mut pool, CLIENT_ID_BOB, diff --git a/crates/sui-framework/packages/deepbook/tests/critbit_tests.move b/crates/iota-framework/packages/deepbook/tests/critbit_tests.move similarity index 99% rename from crates/sui-framework/packages/deepbook/tests/critbit_tests.move rename to crates/iota-framework/packages/deepbook/tests/critbit_tests.move index 4c62d4404d4..8bcb9f799ec 100644 --- a/crates/sui-framework/packages/deepbook/tests/critbit_tests.move +++ b/crates/iota-framework/packages/deepbook/tests/critbit_tests.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] module deepbook::critbit_test { use deepbook::critbit::{Self, InternalNode, Leaf, check_tree_struct}; - use sui::test_scenario::{Self as test, ctx, Scenario, next_tx, end, TransactionEffects}; - use sui::test_utils::assert_eq; + use iota::test_scenario::{Self as test, ctx, Scenario, next_tx, end, TransactionEffects}; + use iota::test_utils::assert_eq; const PARTITION_INDEX: u64 = 1 << 63; // 9223372036854775808 const MAX_U64: u64 = 0xFFFFFFFFFFFFFFFF; // 18446744073709551615 diff --git a/crates/sui-framework/packages/deepbook/tests/order_query_tests.move b/crates/iota-framework/packages/deepbook/tests/order_query_tests.move similarity index 92% rename from crates/sui-framework/packages/deepbook/tests/order_query_tests.move rename to crates/iota-framework/packages/deepbook/tests/order_query_tests.move index 18bd5aca63f..92330ecacbe 100644 --- a/crates/sui-framework/packages/deepbook/tests/order_query_tests.move +++ b/crates/iota-framework/packages/deepbook/tests/order_query_tests.move @@ -1,21 +1,22 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] module deepbook::order_query_tests { use std::option::{none, some}; - use sui::clock; + use iota::clock; use deepbook::order_query; use deepbook::order_query::iter_bids; use deepbook::custodian_v2; use deepbook::custodian_v2::{AccountCap, account_owner}; - use sui::clock::Clock; - use sui::coin::mint_for_testing; + use iota::clock::Clock; + use iota::coin::mint_for_testing; use deepbook::clob_v2; - use sui::sui::SUI; + use iota::iota::IOTA; use deepbook::clob_v2::{setup_test, USD, mint_account_cap_transfer, Pool}; - use sui::test_scenario; - use sui::test_scenario::{next_tx, end, ctx, Scenario}; + use iota::test_scenario; + use iota::test_scenario::{next_tx, end, ctx, Scenario}; const CLIENT_ID_ALICE: u64 = 0; const FLOAT_SCALING: u64 = 1000000000; @@ -30,7 +31,7 @@ module deepbook::order_query_tests { fun test_order_query_pagination() { let mut scenario = prepare_scenario(); add_orders(200, TIMESTAMP_INF, none(), &mut scenario); - let pool = test_scenario::take_shared>(&scenario); + let pool = test_scenario::take_shared>(&scenario); let page1 = iter_bids(&pool, none(), none(), none(), none(), true); assert!(vector::length(order_query::orders(&page1)) == 100, 0); assert!(order_query::has_next_page(&page1), 0); @@ -67,7 +68,7 @@ module deepbook::order_query_tests { fun test_order_query_pagination_decending() { let mut scenario = prepare_scenario(); add_orders(200, TIMESTAMP_INF, none(), &mut scenario); - let pool = test_scenario::take_shared>(&scenario); + let pool = test_scenario::take_shared>(&scenario); let page1 = iter_bids(&pool, none(), none(), none(), none(), false); assert!(vector::length(order_query::orders(&page1)) == 100, 0); @@ -105,7 +106,7 @@ module deepbook::order_query_tests { fun test_order_query_start_order_id() { let mut scenario = prepare_scenario(); add_orders(200, TIMESTAMP_INF, none(), &mut scenario); - let pool = test_scenario::take_shared>(&scenario); + let pool = test_scenario::take_shared>(&scenario); // test start order id let page = iter_bids(&pool, none(), some(51), none(), none(), true); assert!(vector::length(order_query::orders(&page)) == 100, 0); @@ -151,7 +152,7 @@ module deepbook::order_query_tests { add_orders(50, expired_timestamp, none(), &mut scenario); - let pool = test_scenario::take_shared>(&scenario); + let pool = test_scenario::take_shared>(&scenario); // test get all order excluding expired orders let page = iter_bids(&pool, none(), none(), some(expired_timestamp + 1), none(), true); @@ -173,7 +174,7 @@ module deepbook::order_query_tests { let mut scenario = prepare_scenario(); add_orders(70, TIMESTAMP_INF, none(), &mut scenario); - let pool = test_scenario::take_shared>(&scenario); + let pool = test_scenario::take_shared>(&scenario); // test get all order with id < 50 let page = iter_bids(&pool, none(), none(), none(), some(50), true); @@ -211,7 +212,7 @@ module deepbook::order_query_tests { add_orders(50, TIMESTAMP_INF, none(), &mut scenario); add_orders(50, TIMESTAMP_INF, none(), &mut scenario); - let pool = test_scenario::take_shared>(&scenario); + let pool = test_scenario::take_shared>(&scenario); let page1 = iter_bids(&pool, none(), none(), none(), none(), true); assert!(vector::length(order_query::orders(&page1)) == 100, 0); assert!(order_query::has_next_page(&page1), 0); @@ -264,7 +265,7 @@ module deepbook::order_query_tests { // insert a new order at tick level 10 add_orders(1, TIMESTAMP_INF, some(10), &mut scenario); - let pool = test_scenario::take_shared>(&scenario); + let pool = test_scenario::take_shared>(&scenario); let page = iter_bids(&pool, some(11 * FLOAT_SCALING), none(), none(), none(), true); // this page should start from order id 11 and end at order id 110, contains 100 orders @@ -302,11 +303,11 @@ module deepbook::order_query_tests { mint_account_cap_transfer(BOB, test_scenario::ctx(&mut scenario)); next_tx(&mut scenario, ALICE); - let mut pool = test_scenario::take_shared>(&scenario); + let mut pool = test_scenario::take_shared>(&scenario); let account_cap = test_scenario::take_from_sender(&scenario); let account_cap_user = account_owner(&account_cap); let (base_custodian, quote_custodian) = clob_v2::borrow_mut_custodian(&mut pool); - custodian_v2::deposit(base_custodian, mint_for_testing(1000000, ctx(&mut scenario)), account_cap_user); + custodian_v2::deposit(base_custodian, mint_for_testing(1000000, ctx(&mut scenario)), account_cap_user); custodian_v2::deposit( quote_custodian, mint_for_testing(10000000, ctx(&mut scenario)), @@ -328,9 +329,9 @@ module deepbook::order_query_tests { }; let account_cap = test_scenario::take_from_sender(scenario); - let mut pool = test_scenario::take_shared>(scenario); + let mut pool = test_scenario::take_shared>(scenario); let clock = test_scenario::take_shared(scenario); - clob_v2::place_limit_order( + clob_v2::place_limit_order( &mut pool, CLIENT_ID_ALICE, price, diff --git a/crates/iota-framework/packages/iota-framework/Move.lock b/crates/iota-framework/packages/iota-framework/Move.lock new file mode 100644 index 00000000000..23b95875318 --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/Move.lock @@ -0,0 +1,19 @@ +# @generated by Move, please check-in and do not edit manually. + +[move] +version = 1 +manifest_digest = "ED5DEFBBF556EE89312E639A53F21DE24320F9B13C2087D3BFE2989D5B2B5DAF" +deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082" + +dependencies = [ + { name = "MoveStdlib" }, +] + +[[move.package]] +name = "MoveStdlib" +source = { local = "../move-stdlib" } + +[move.toolchain-version] +compiler-version = "1.22.0" +edition = "legacy" +flavor = "iota" diff --git a/crates/iota-framework/packages/iota-framework/Move.toml b/crates/iota-framework/packages/iota-framework/Move.toml new file mode 100644 index 00000000000..99968b2ef0b --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "Iota" +version = "0.0.1" +published-at = "0x2" +edition = "2024.beta" + +[dependencies] +MoveStdlib = { local = "../move-stdlib" } + +[addresses] +iota = "0x2" diff --git a/crates/iota-framework/packages/iota-framework/sources/address.move b/crates/iota-framework/packages/iota-framework/sources/address.move new file mode 100644 index 00000000000..7dc2aed0873 --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/sources/address.move @@ -0,0 +1,87 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[defines_primitive(address)] +module iota::address { + use iota::hex; + use std::ascii; + use std::bcs; + use std::string; + + /// Allows calling `.to_id()` on an address to get its `ID`. + public use fun iota::object::id_from_address as address.to_id; + + /// The length of an address, in bytes + const LENGTH: u64 = 32; + + // The largest integer that can be represented with 32 bytes: 2^(8*32) - 1 + const MAX: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + #[allow(unused_const)] + /// Error from `from_bytes` when it is supplied too many or too few bytes. + const EAddressParseError: u64 = 0; + + /// Convert `a` into a u256 by interpreting `a` as the bytes of a big-endian integer + /// (e.g., `to_u256(0x1) == 1`) + public native fun to_u256(a: address): u256; + + /// Convert `n` into an address by encoding it as a big-endian integer (e.g., `from_u256(1) = @0x1`) + /// Aborts if `n` > `MAX_ADDRESS` + public native fun from_u256(n: u256): address; + + /// Convert `bytes` into an address. + /// Aborts with `EAddressParseError` if the length of `bytes` is not 32 + public native fun from_bytes(bytes: vector): address; + + /// Convert `a` into BCS-encoded bytes. + public fun to_bytes(a: address): vector { + bcs::to_bytes(&a) + } + + /// Convert `a` to a hex-encoded ASCII string + public fun to_ascii_string(a: address): ascii::String { + hex::encode(to_bytes(a)).to_ascii_string() + } + + /// Convert `a` to a hex-encoded string + public fun to_string(a: address): string::String { + to_ascii_string(a).to_string() + } + + /// Converts an ASCII string to an address, taking the numerical value for each character. The + /// string must be Base16 encoded, and thus exactly 64 characters long. + /// For example, the string "00000000000000000000000000000000000000000000000000000000DEADB33F" + /// will be converted to the address @0xDEADB33F. + /// Aborts with `EAddressParseError` if the length of `s` is not 64, + /// or if an invalid character is encountered. + public fun from_ascii_bytes(bytes: &vector): address { + assert!(bytes.length() == 64, EAddressParseError); + let mut hex_bytes = vector[]; + let mut i = 0; + while (i < 64) { + let hi = hex_char_value(bytes[i]); + let lo = hex_char_value(bytes[i+1]); + hex_bytes.push_back((hi << 4) | lo); + i = i + 2; + }; + from_bytes(hex_bytes) + } + + fun hex_char_value(c: u8): u8 { + if (c >= 48 && c <= 57) c - 48 // 0-9 + else if (c >= 65 && c <= 70) c - 55 // A-F + else if (c >= 97 && c <= 102) c - 87 // a-f + else abort EAddressParseError + } + + /// Length of a Iota address in bytes + public fun length(): u64 { + LENGTH + } + + /// Largest possible address + public fun max(): u256 { + MAX + } +} diff --git a/crates/sui-framework/packages/sui-framework/sources/authenticator_state.move b/crates/iota-framework/packages/iota-framework/sources/authenticator_state.move similarity index 98% rename from crates/sui-framework/packages/sui-framework/sources/authenticator_state.move rename to crates/iota-framework/packages/iota-framework/sources/authenticator_state.move index d6d1b7dcdfd..60ff00066d8 100644 --- a/crates/sui-framework/packages/sui-framework/sources/authenticator_state.move +++ b/crates/iota-framework/packages/iota-framework/sources/authenticator_state.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[allow(unused_use)] @@ -7,11 +8,11 @@ // // This module is not currently accessible from user contracts, and is used only to record the JWK // state to the chain for auditability + restore from snapshot purposes. -module sui::authenticator_state { +module iota::authenticator_state { use std::string; - use sui::dynamic_field; + use iota::dynamic_field; use std::string::{String, utf8}; - use sui::math; + use iota::math; /// Sender is not @0x0 the system address. const ENotSystemAddress: u64 = 0; @@ -291,7 +292,7 @@ module sui::authenticator_state { // any jwk below this epoch is not retained min_epoch: u64, ctx: &TxContext) { - // This will only be called by sui_system::advance_epoch + // This will only be called by iota_system::advance_epoch assert!(ctx.sender() == @0x0, ENotSystemAddress); let inner = load_inner_mut(self); diff --git a/crates/sui-framework/packages/sui-framework/sources/bag.move b/crates/iota-framework/packages/iota-framework/sources/bag.move similarity index 76% rename from crates/sui-framework/packages/sui-framework/sources/bag.move rename to crates/iota-framework/packages/iota-framework/sources/bag.move index 99a59e93722..2b98e939135 100644 --- a/crates/sui-framework/packages/sui-framework/sources/bag.move +++ b/crates/iota-framework/packages/iota-framework/sources/bag.move @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -/// A bag is a heterogeneous map-like collection. The collection is similar to `sui::table` in that -/// its keys and values are not stored within the `Bag` value, but instead are stored using Sui's +/// A bag is a heterogeneous map-like collection. The collection is similar to `iota::table` in that +/// its keys and values are not stored within the `Bag` value, but instead are stored using Iota's /// object system. The `Bag` struct acts only as a handle into the object system to retrieve those /// keys and values. /// Note that this means that `Bag` values with exactly the same key-value mapping will not be @@ -17,12 +18,12 @@ /// // bag1 does not equal bag2, despite having the same entries /// assert!(&bag1 != &bag2, 0); /// ``` -/// At it's core, `sui::bag` is a wrapper around `UID` that allows for access to -/// `sui::dynamic_field` while preventing accidentally stranding field values. A `UID` can be +/// At it's core, `iota::bag` is a wrapper around `UID` that allows for access to +/// `iota::dynamic_field` while preventing accidentally stranding field values. A `UID` can be /// deleted, even if it has dynamic fields associated with it, but a bag, on the other hand, must be /// empty to be destroyed. -module sui::bag { - use sui::dynamic_field as field; +module iota::bag { + use iota::dynamic_field as field; // Attempted to destroy a non-empty bag const EBagNotEmpty: u64 = 0; @@ -43,7 +44,7 @@ module sui::bag { } /// Adds a key-value pair to the bag `bag: &mut Bag` - /// Aborts with `sui::dynamic_field::EFieldAlreadyExists` if the bag already has an entry with + /// Aborts with `iota::dynamic_field::EFieldAlreadyExists` if the bag already has an entry with /// that key `k: K`. public fun add(bag: &mut Bag, k: K, v: V) { field::add(&mut bag.id, k, v); @@ -52,9 +53,9 @@ module sui::bag { #[syntax(index)] /// Immutable borrows the value associated with the key in the bag `bag: &Bag`. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the bag does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the bag does not have an entry with /// that key `k: K`. - /// Aborts with `sui::dynamic_field::EFieldTypeMismatch` if the bag has an entry for the key, but + /// Aborts with `iota::dynamic_field::EFieldTypeMismatch` if the bag has an entry for the key, but /// the value does not have the specified type. public fun borrow(bag: &Bag, k: K): &V { field::borrow(&bag.id, k) @@ -62,18 +63,18 @@ module sui::bag { #[syntax(index)] /// Mutably borrows the value associated with the key in the bag `bag: &mut Bag`. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the bag does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the bag does not have an entry with /// that key `k: K`. - /// Aborts with `sui::dynamic_field::EFieldTypeMismatch` if the bag has an entry for the key, but + /// Aborts with `iota::dynamic_field::EFieldTypeMismatch` if the bag has an entry for the key, but /// the value does not have the specified type. public fun borrow_mut(bag: &mut Bag, k: K): &mut V { field::borrow_mut(&mut bag.id, k) } /// Mutably borrows the key-value pair in the bag `bag: &mut Bag` and returns the value. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the bag does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the bag does not have an entry with /// that key `k: K`. - /// Aborts with `sui::dynamic_field::EFieldTypeMismatch` if the bag has an entry for the key, but + /// Aborts with `iota::dynamic_field::EFieldTypeMismatch` if the bag has an entry for the key, but /// the value does not have the specified type. public fun remove(bag: &mut Bag, k: K): V { let v = field::remove(&mut bag.id, k); diff --git a/crates/sui-framework/packages/sui-framework/sources/balance.move b/crates/iota-framework/packages/iota-framework/sources/balance.move similarity index 94% rename from crates/sui-framework/packages/sui-framework/sources/balance.move rename to crates/iota-framework/packages/iota-framework/sources/balance.move index 57247c21109..456e4eef3f0 100644 --- a/crates/sui-framework/packages/sui-framework/sources/balance.move +++ b/crates/iota-framework/packages/iota-framework/sources/balance.move @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// A storable handler for Balances in general. Is used in the `Coin` /// module to allow balance operations and can be used to implement /// custom coins with `Supply` and `Balance`s. -module sui::balance { +module iota::balance { /// Allows calling `.into_coin()` on a `Balance` to turn it into a coin. - public use fun sui::coin::from_balance as Balance.into_coin; + public use fun iota::coin::from_balance as Balance.into_coin; - /* friend sui::sui; */ + /* friend iota::iota; */ /// For when trying to destroy a non-zero balance. const ENonZero: u64 = 0; @@ -138,14 +139,14 @@ module sui::balance { } #[test_only] -module sui::balance_tests { - use sui::balance; - use sui::sui::SUI; - use sui::test_utils; +module iota::balance_tests { + use iota::balance; + use iota::iota::IOTA; + use iota::test_utils; #[test] fun test_balance() { - let mut balance = balance::zero(); + let mut balance = balance::zero(); let another = balance::create_for_testing(1000); balance.join(another); diff --git a/crates/iota-framework/packages/iota-framework/sources/bcs.move b/crates/iota-framework/packages/iota-framework/sources/bcs.move new file mode 100644 index 00000000000..17b96bb818b --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/sources/bcs.move @@ -0,0 +1,461 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// This module implements BCS (de)serialization in Move. +/// Full specification can be found here: https://github.com/diem/bcs +/// +/// Short summary (for Move-supported types): +/// +/// - address - sequence of X bytes +/// - bool - byte with 0 or 1 +/// - u8 - a single u8 byte +/// - u64 / u128 / u256 - LE bytes +/// - vector - ULEB128 length + LEN elements +/// - option - first byte bool: None (0) or Some (1), then value +/// +/// Usage example: +/// ``` +/// /// This function reads u8 and u64 value from the input +/// /// and returns the rest of the bytes. +/// fun deserialize(bytes: vector): (u8, u64, vector) { +/// use iota::bcs::{Self, BCS}; +/// +/// let prepared: BCS = bcs::new(bytes); +/// let (u8_value, u64_value) = ( +/// prepared.peel_u8(), +/// prepared.peel_u64() +/// ); +/// +/// // unpack bcs struct +/// let leftovers = prepared.into_remainder_bytes(); +/// +/// (u8_value, u64_value, leftovers) +/// } +/// ``` +module iota::bcs { + use iota::address; + use std::bcs; + + /// For when bytes length is less than required for deserialization. + const EOutOfRange: u64 = 0; + /// For when the boolean value different than `0` or `1`. + const ENotBool: u64 = 1; + /// For when ULEB byte is out of range (or not found). + const ELenOutOfRange: u64 = 2; + + /// A helper struct that saves resources on operations. For better + /// vector performance, it stores reversed bytes of the BCS and + /// enables use of `vector::pop_back`. + public struct BCS has store, copy, drop { + bytes: vector + } + + /// Get BCS serialized bytes for any value. + /// Re-exports stdlib `bcs::to_bytes`. + public fun to_bytes(value: &T): vector { + bcs::to_bytes(value) + } + + /// Creates a new instance of BCS wrapper that holds inversed + /// bytes for better performance. + public fun new(mut bytes: vector): BCS { + bytes.reverse(); + BCS { bytes } + } + + /// Unpack the `BCS` struct returning the leftover bytes. + /// Useful for passing the data further after partial deserialization. + public fun into_remainder_bytes(bcs: BCS): vector { + let BCS { mut bytes } = bcs; + bytes.reverse(); + bytes + } + + /// Read address from the bcs-serialized bytes. + public fun peel_address(bcs: &mut BCS): address { + assert!(bcs.bytes.length() >= address::length(), EOutOfRange); + let (mut addr_bytes, mut i) = (vector[], 0); + while (i < address::length()) { + addr_bytes.push_back(bcs.bytes.pop_back()); + i = i + 1; + }; + address::from_bytes(addr_bytes) + } + + /// Read a `bool` value from bcs-serialized bytes. + public fun peel_bool(bcs: &mut BCS): bool { + let value = bcs.peel_u8(); + if (value == 0) { + false + } else if (value == 1) { + true + } else { + abort ENotBool + } + } + + /// Read `u8` value from bcs-serialized bytes. + public fun peel_u8(bcs: &mut BCS): u8 { + assert!(bcs.bytes.length() >= 1, EOutOfRange); + bcs.bytes.pop_back() + } + + /// Read `u64` value from bcs-serialized bytes. + public fun peel_u64(bcs: &mut BCS): u64 { + assert!(bcs.bytes.length() >= 8, EOutOfRange); + + let (mut value, mut i) = (0u64, 0u8); + while (i < 64) { + let byte = bcs.bytes.pop_back() as u64; + value = value + (byte << i); + i = i + 8; + }; + + value + } + + /// Read `u128` value from bcs-serialized bytes. + public fun peel_u128(bcs: &mut BCS): u128 { + assert!(bcs.bytes.length() >= 16, EOutOfRange); + + let (mut value, mut i) = (0u128, 0u8); + while (i < 128) { + let byte = bcs.bytes.pop_back() as u128; + value = value + (byte << i); + i = i + 8; + }; + + value + } + + /// Read `u256` value from bcs-serialized bytes. + public fun peel_u256(bcs: &mut BCS): u256 { + assert!(bcs.bytes.length() >= 32, EOutOfRange); + + let (mut value, mut i) = (0u256, 0u16); + while (i < 256) { + let byte = bcs.bytes.pop_back() as u256; + value = value + (byte << (i as u8)); + i = i + 8; + }; + + value + } + + // === Vector === + + /// Read ULEB bytes expecting a vector length. Result should + /// then be used to perform `peel_*` operation LEN times. + /// + /// In BCS `vector` length is implemented with ULEB128; + /// See more here: https://en.wikipedia.org/wiki/LEB128 + public fun peel_vec_length(bcs: &mut BCS): u64 { + let (mut total, mut shift, mut len) = (0u64, 0, 0); + while (true) { + assert!(len <= 4, ELenOutOfRange); + let byte = bcs.bytes.pop_back() as u64; + len = len + 1; + total = total | ((byte & 0x7f) << shift); + if ((byte & 0x80) == 0) { + break + }; + shift = shift + 7; + }; + total + } + + /// Peel a vector of `address` from serialized bytes. + public fun peel_vec_address(bcs: &mut BCS): vector
    { + let (len, mut i, mut res) = (bcs.peel_vec_length(), 0, vector[]); + while (i < len) { + res.push_back(bcs.peel_address()); + i = i + 1; + }; + res + } + + /// Peel a vector of `address` from serialized bytes. + public fun peel_vec_bool(bcs: &mut BCS): vector { + let (len, mut i, mut res) = (bcs.peel_vec_length(), 0, vector[]); + while (i < len) { + res.push_back(bcs.peel_bool()); + i = i + 1; + }; + res + } + + /// Peel a vector of `u8` (eg string) from serialized bytes. + public fun peel_vec_u8(bcs: &mut BCS): vector { + let (len, mut i, mut res) = (bcs.peel_vec_length(), 0, vector[]); + while (i < len) { + res.push_back(bcs.peel_u8()); + i = i + 1; + }; + res + } + + /// Peel a `vector>` (eg vec of string) from serialized bytes. + public fun peel_vec_vec_u8(bcs: &mut BCS): vector> { + let (len, mut i, mut res) = (bcs.peel_vec_length(), 0, vector[]); + while (i < len) { + res.push_back(bcs.peel_vec_u8()); + i = i + 1; + }; + res + } + + /// Peel a vector of `u64` from serialized bytes. + public fun peel_vec_u64(bcs: &mut BCS): vector { + let (len, mut i, mut res) = (bcs.peel_vec_length(), 0, vector[]); + while (i < len) { + res.push_back(bcs.peel_u64()); + i = i + 1; + }; + res + } + + /// Peel a vector of `u128` from serialized bytes. + public fun peel_vec_u128(bcs: &mut BCS): vector { + let (len, mut i, mut res) = (bcs.peel_vec_length(), 0, vector[]); + while (i < len) { + res.push_back(bcs.peel_u128()); + i = i + 1; + }; + res + } + + // === Option === + + /// Peel `Option
    ` from serialized bytes. + public fun peel_option_address(bcs: &mut BCS): Option
    { + if (bcs.peel_bool()) { + option::some(bcs.peel_address()) + } else { + option::none() + } + } + + /// Peel `Option` from serialized bytes. + public fun peel_option_bool(bcs: &mut BCS): Option { + if (bcs.peel_bool()) { + option::some(bcs.peel_bool()) + } else { + option::none() + } + } + + /// Peel `Option` from serialized bytes. + public fun peel_option_u8(bcs: &mut BCS): Option { + if (bcs.peel_bool()) { + option::some(bcs.peel_u8()) + } else { + option::none() + } + } + + /// Peel `Option` from serialized bytes. + public fun peel_option_u64(bcs: &mut BCS): Option { + if (bcs.peel_bool()) { + option::some(bcs.peel_u64()) + } else { + option::none() + } + } + + /// Peel `Option` from serialized bytes. + public fun peel_option_u128(bcs: &mut BCS): Option { + if (bcs.peel_bool()) { + option::some(bcs.peel_u128()) + } else { + option::none() + } + } + + // === Tests === + + #[test_only] + public struct Info has drop { a: bool, b: u8, c: u64, d: u128, k: vector, s: address } + + #[test] + #[expected_failure(abort_code = ELenOutOfRange)] + fun test_uleb_len_fail() { + let value = vector[0xff, 0xff, 0xff, 0xff, 0xff]; + let mut bytes = new(to_bytes(&value)); + let _fail = bytes.peel_vec_length(); + abort 2 // TODO: make this test fail + } + + #[test] + #[expected_failure(abort_code = ENotBool)] + fun test_bool_fail() { + let mut bytes = new(to_bytes(&10u8)); + let _fail = bytes.peel_bool(); + } + + #[test] + fun test_option() { + { + let value = option::some(true); + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_option_bool(), 0); + }; + + { + let value = option::some(10u8); + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_option_u8(), 0); + }; + + { + let value = option::some(10000u64); + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_option_u64(), 0); + }; + + { + let value = option::some(10000999999u128); + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_option_u128(), 0); + }; + + { + let value = option::some(@0xC0FFEE); + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_option_address(), 0); + }; + + { + let value: Option = option::none(); + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_option_bool(), 0); + }; + } + + #[test] + fun test_bcs() { + { + let value = @0xC0FFEE; + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_address(), 0); + }; + + { // boolean: true + let value = true; + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_bool(), 0); + }; + + { // boolean: false + let value = false; + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_bool(), 0); + }; + + { // u8 + let value = 100u8; + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_u8(), 0); + }; + + { // u64 (4 bytes) + let value = 1000100u64; + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_u64(), 0); + }; + + { // u64 (8 bytes) + let value = 100000000000000u64; + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_u64(), 0); + }; + + { // u128 (16 bytes) + let value = 100000000000000000000000000u128; + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_u128(), 0); + }; + + { // vector length + let value = vector[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + let mut bytes = new(to_bytes(&value)); + assert!(value.length() == bytes.peel_vec_length(), 0); + }; + + { // vector length (more data) + let value = vector[ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + ]; + + let mut bytes = new(to_bytes(&value)); + assert!(value.length() == bytes.peel_vec_length(), 0); + }; + + { // full deserialization test (ordering) + let info = Info { a: true, b: 100, c: 9999, d: 112333, k: vector[true, false, true, false], s: @0xAAAAAAAAAAA }; + let mut bytes = new(to_bytes(&info)); + + assert!(info.a == bytes.peel_bool(), 0); + assert!(info.b == bytes.peel_u8(), 0); + assert!(info.c == bytes.peel_u64(), 0); + assert!(info.d == bytes.peel_u128(), 0); + + let len = bytes.peel_vec_length(); + + assert!(info.k.length() == len, 0); + + let mut i = 0; + while (i < info.k.length()) { + assert!(info.k[i] == bytes.peel_bool(), 0); + i = i + 1; + }; + + assert!(info.s == bytes.peel_address(), 0); + }; + + { // read vector of bytes directly + let value = vector[ + vector[1,2,3,4,5], + vector[1,2,3,4,5], + vector[1,2,3,4,5] + ]; + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_vec_vec_u8(), 0); + }; + + { // read vector of bytes directly + let value = vector[1,2,3,4,5]; + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_vec_u8(), 0); + }; + + { // read vector of bytes directly + let value = vector[1,2,3,4,5]; + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_vec_u64(), 0); + }; + + { // read vector of bytes directly + let value = vector[1,2,3,4,5]; + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_vec_u128(), 0); + }; + + { // read vector of bytes directly + let value = vector[true, false, true, false]; + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_vec_bool(), 0); + }; + + { // read vector of address directly + let value = vector[@0x0, @0x1, @0x2, @0x3]; + let mut bytes = new(to_bytes(&value)); + assert!(value == bytes.peel_vec_address(), 0); + }; + } +} diff --git a/crates/sui-framework/packages/sui-framework/sources/borrow.move b/crates/iota-framework/packages/iota-framework/sources/borrow.move similarity index 94% rename from crates/sui-framework/packages/sui-framework/sources/borrow.move rename to crates/iota-framework/packages/iota-framework/sources/borrow.move index 55eb1e1ae5b..da0bafcaa6f 100644 --- a/crates/sui-framework/packages/sui-framework/sources/borrow.move +++ b/crates/iota-framework/packages/iota-framework/sources/borrow.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// A simple library that enables hot-potato-locked borrow mechanics. @@ -6,7 +7,7 @@ /// With Programmable transactions, it is possible to borrow a value within /// a transaction, use it and put back in the end. Hot-potato `Borrow` makes /// sure the object is returned and was not swapped for another one. -module sui::borrow { +module iota::borrow { /// The `Borrow` does not match the `Referent`. const EWrongBorrow: u64 = 0; @@ -64,7 +65,7 @@ module sui::borrow { #[test] fun test_borrow() { - let ctx = &mut sui::tx_context::dummy(); + let ctx = &mut iota::tx_context::dummy(); let mut ref = new(Test { id: object::new(ctx) }, ctx); let (value, borrow) = borrow(&mut ref); @@ -78,7 +79,7 @@ module sui::borrow { #[expected_failure(abort_code = EWrongValue)] /// The `value` is swapped with another instance of the type `T`. fun test_object_swap() { - let ctx = &mut sui::tx_context::dummy(); + let ctx = &mut iota::tx_context::dummy(); let mut ref_1 = new(Test { id: object::new(ctx) }, ctx); let mut ref_2 = new(Test { id: object::new(ctx) }, ctx); @@ -99,7 +100,7 @@ module sui::borrow { #[expected_failure(abort_code = EWrongBorrow)] /// The both `borrow` and `value` are swapped with another `Referent`. fun test_borrow_fail() { - let ctx = &mut sui::tx_context::dummy(); + let ctx = &mut iota::tx_context::dummy(); let mut ref_1 = new(Test { id: object::new(ctx) }, ctx); let mut ref_2 = new(Test { id: object::new(ctx) }, ctx); diff --git a/crates/iota-framework/packages/iota-framework/sources/clock.move b/crates/iota-framework/packages/iota-framework/sources/clock.move new file mode 100644 index 00000000000..1fc2bf94c1d --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/sources/clock.move @@ -0,0 +1,94 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// APIs for accessing time from move calls, via the `Clock`: a unique +/// shared object that is created at 0x6 during genesis. +module iota::clock { + + /// Sender is not @0x0 the system address. + const ENotSystemAddress: u64 = 0; + + /// Singleton shared object that exposes time to Move calls. This + /// object is found at address 0x6, and can only be read (accessed + /// via an immutable reference) by entry functions. + /// + /// Entry Functions that attempt to accept `Clock` by mutable + /// reference or value will fail to verify, and honest validators + /// will not sign or execute transactions that use `Clock` as an + /// input parameter, unless it is passed by immutable reference. + public struct Clock has key { + id: UID, + /// The clock's timestamp, which is set automatically by a + /// system transaction every time consensus commits a + /// schedule, or by `iota::clock::increment_for_testing` during + /// testing. + timestamp_ms: u64, + } + + /// The `clock`'s current timestamp as a running total of + /// milliseconds since an arbitrary point in the past. + public fun timestamp_ms(clock: &Clock): u64 { + clock.timestamp_ms + } + + #[allow(unused_function)] + /// Create and share the singleton Clock -- this function is + /// called exactly once, during genesis. + fun create(ctx: &TxContext) { + assert!(ctx.sender() == @0x0, ENotSystemAddress); + + transfer::share_object(Clock { + id: object::clock(), + // Initialised to zero, but set to a real timestamp by a + // system transaction before it can be witnessed by a move + // call. + timestamp_ms: 0, + }) + } + + #[allow(unused_function)] + fun consensus_commit_prologue( + clock: &mut Clock, + timestamp_ms: u64, + ctx: &TxContext, + ) { + // Validator will make a special system call with sender set as 0x0. + assert!(ctx.sender() == @0x0, ENotSystemAddress); + + clock.timestamp_ms = timestamp_ms + } + + #[test_only] + /// Expose the functionality of `create()` (usually only done during + /// genesis) for tests that want to create a Clock. + public fun create_for_testing(ctx: &mut TxContext): Clock { + Clock { + id: object::new(ctx), + timestamp_ms: 0, + } + } + + #[test_only] + /// For transactional tests (if a Clock is used as a shared object). + public fun share_for_testing(clock: Clock) { + transfer::share_object(clock) + } + + #[test_only] + public fun increment_for_testing(clock: &mut Clock, tick: u64) { + clock.timestamp_ms = clock.timestamp_ms + tick; + } + + #[test_only] + public fun set_for_testing(clock: &mut Clock, timestamp_ms: u64) { + assert!(timestamp_ms >= clock.timestamp_ms, 0); + clock.timestamp_ms = timestamp_ms; + } + + #[test_only] + public fun destroy_for_testing(clock: Clock) { + let Clock { id, timestamp_ms: _ } = clock; + id.delete(); + } +} diff --git a/crates/iota-framework/packages/iota-framework/sources/coin.move b/crates/iota-framework/packages/iota-framework/sources/coin.move new file mode 100644 index 00000000000..43baec3ce82 --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/sources/coin.move @@ -0,0 +1,449 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Defines the `Coin` type - platform wide representation of fungible +/// tokens and coins. `Coin` can be described as a secure wrapper around +/// `Balance` type. +module iota::coin { + use std::string; + use std::ascii; + use iota::balance::{Self, Balance, Supply}; + use iota::url::{Self, Url}; + use iota::deny_list::{Self, DenyList}; + use std::type_name; + + // Allows calling `.split_vec(amounts, ctx)` on `coin` + public use fun iota::pay::split_vec as Coin.split_vec; + + // Allows calling `.join_vec(coins)` on `coin` + public use fun iota::pay::join_vec as Coin.join_vec; + + // Allows calling `.split_and_transfer(amount, recipient, ctx)` on `coin` + public use fun iota::pay::split_and_transfer as Coin.split_and_transfer; + + // Allows calling `.divide_and_keep(n, ctx)` on `coin` + public use fun iota::pay::divide_and_keep as Coin.divide_and_keep; + + /// A type passed to create_supply is not a one-time witness. + const EBadWitness: u64 = 0; + /// Invalid arguments are passed to a function. + const EInvalidArg: u64 = 1; + /// Trying to split a coin more times than its balance allows. + const ENotEnough: u64 = 2; + + /// A coin of type `T` worth `value`. Transferable and storable + public struct Coin has key, store { + id: UID, + balance: Balance + } + + /// Each Coin type T created through `create_currency` function will have a + /// unique instance of CoinMetadata that stores the metadata for this coin type. + public struct CoinMetadata has key, store { + id: UID, + /// Number of decimal places the coin uses. + /// A coin with `value ` N and `decimals` D should be shown as N / 10^D + /// E.g., a coin with `value` 7002 and decimals 3 should be displayed as 7.002 + /// This is metadata for display usage only. + decimals: u8, + /// Name for the token + name: string::String, + /// Symbol for the token + symbol: ascii::String, + /// Description of the token + description: string::String, + /// URL for the token logo + icon_url: Option + } + + /// Similar to CoinMetadata, but created only for regulated coins that use the DenyList. + /// This object is always immutable. + public struct RegulatedCoinMetadata has key { + id: UID, + /// The ID of the coin's CoinMetadata object. + coin_metadata_object: ID, + /// The ID of the coin's DenyCap object. + deny_cap_object: ID, + } + + /// Capability allowing the bearer to mint and burn + /// coins of type `T`. Transferable + public struct TreasuryCap has key, store { + id: UID, + total_supply: Supply + } + + /// Capability allowing the bearer to freeze addresses, preventing those addresses from + /// interacting with the coin as an input to a transaction. + public struct DenyCap has key, store { + id: UID, + } + + // === Supply <-> TreasuryCap morphing and accessors === + + /// Return the total number of `T`'s in circulation. + public fun total_supply(cap: &TreasuryCap): u64 { + balance::supply_value(&cap.total_supply) + } + + /// Unwrap `TreasuryCap` getting the `Supply`. + /// + /// Operation is irreversible. Supply cannot be converted into a `TreasuryCap` due + /// to different security guarantees (TreasuryCap can be created only once for a type) + public fun treasury_into_supply(treasury: TreasuryCap): Supply { + let TreasuryCap { id, total_supply } = treasury; + id.delete(); + total_supply + } + + /// Get immutable reference to the treasury's `Supply`. + public fun supply_immut(treasury: &TreasuryCap): &Supply { + &treasury.total_supply + } + + /// Get mutable reference to the treasury's `Supply`. + public fun supply_mut(treasury: &mut TreasuryCap): &mut Supply { + &mut treasury.total_supply + } + + // === Balance <-> Coin accessors and type morphing === + + /// Public getter for the coin's value + public fun value(self: &Coin): u64 { + self.balance.value() + } + + /// Get immutable reference to the balance of a coin. + public fun balance(coin: &Coin): &Balance { + &coin.balance + } + + /// Get a mutable reference to the balance of a coin. + public fun balance_mut(coin: &mut Coin): &mut Balance { + &mut coin.balance + } + + /// Wrap a balance into a Coin to make it transferable. + public fun from_balance(balance: Balance, ctx: &mut TxContext): Coin { + Coin { id: object::new(ctx), balance } + } + + /// Destruct a Coin wrapper and keep the balance. + public fun into_balance(coin: Coin): Balance { + let Coin { id, balance } = coin; + id.delete(); + balance + } + + /// Take a `Coin` worth of `value` from `Balance`. + /// Aborts if `value > balance.value` + public fun take( + balance: &mut Balance, value: u64, ctx: &mut TxContext, + ): Coin { + Coin { + id: object::new(ctx), + balance: balance.split(value) + } + } + + /// Put a `Coin` to the `Balance`. + public fun put(balance: &mut Balance, coin: Coin) { + balance.join(into_balance(coin)); + } + + // === Base Coin functionality === + + /// Consume the coin `c` and add its value to `self`. + /// Aborts if `c.value + self.value > U64_MAX` + public entry fun join(self: &mut Coin, c: Coin) { + let Coin { id, balance } = c; + id.delete(); + self.balance.join(balance); + } + + /// Split coin `self` to two coins, one with balance `split_amount`, + /// and the remaining balance is left is `self`. + public fun split( + self: &mut Coin, split_amount: u64, ctx: &mut TxContext + ): Coin { + take(&mut self.balance, split_amount, ctx) + } + + /// Split coin `self` into `n - 1` coins with equal balances. The remainder is left in + /// `self`. Return newly created coins. + public fun divide_into_n( + self: &mut Coin, n: u64, ctx: &mut TxContext + ): vector> { + assert!(n > 0, EInvalidArg); + assert!(n <= value(self), ENotEnough); + + let mut vec = vector[]; + let mut i = 0; + let split_amount = value(self) / n; + while (i < n - 1) { + vec.push_back(self.split(split_amount, ctx)); + i = i + 1; + }; + vec + } + + /// Make any Coin with a zero value. Useful for placeholding + /// bids/payments or preemptively making empty balances. + public fun zero(ctx: &mut TxContext): Coin { + Coin { id: object::new(ctx), balance: balance::zero() } + } + + /// Destroy a coin with value zero + public fun destroy_zero(c: Coin) { + let Coin { id, balance } = c; + id.delete(); + balance.destroy_zero() + } + + // === Registering new coin types and managing the coin supply === + + /// Create a new currency type `T` as and return the `TreasuryCap` for + /// `T` to the caller. Can only be called with a `one-time-witness` + /// type, ensuring that there's only one `TreasuryCap` per `T`. + public fun create_currency( + witness: T, + decimals: u8, + symbol: vector, + name: vector, + description: vector, + icon_url: Option, + ctx: &mut TxContext + ): (TreasuryCap, CoinMetadata) { + // Make sure there's only one instance of the type T + assert!(iota::types::is_one_time_witness(&witness), EBadWitness); + + ( + TreasuryCap { + id: object::new(ctx), + total_supply: balance::create_supply(witness) + }, + CoinMetadata { + id: object::new(ctx), + decimals, + name: string::utf8(name), + symbol: ascii::string(symbol), + description: string::utf8(description), + icon_url + } + ) + } + + /// This creates a new currency, via `create_currency`, but with an extra capability that + /// allows for specific addresses to have their coins frozen. Those addresses cannot interact + /// with the coin as input objects. + public fun create_regulated_currency( + witness: T, + decimals: u8, + symbol: vector, + name: vector, + description: vector, + icon_url: Option, + ctx: &mut TxContext + ): (TreasuryCap, DenyCap, CoinMetadata) { + let (treasury_cap, metadata) = create_currency( + witness, + decimals, + symbol, + name, + description, + icon_url, + ctx + ); + let deny_cap = DenyCap { + id: object::new(ctx), + }; + transfer::freeze_object(RegulatedCoinMetadata { + id: object::new(ctx), + coin_metadata_object: object::id(&metadata), + deny_cap_object: object::id(&deny_cap), + }); + (treasury_cap, deny_cap, metadata) + } + + /// Create a coin worth `value` and increase the total supply + /// in `cap` accordingly. + public fun mint( + cap: &mut TreasuryCap, value: u64, ctx: &mut TxContext, + ): Coin { + Coin { + id: object::new(ctx), + balance: cap.total_supply.increase_supply(value) + } + } + + /// Mint some amount of T as a `Balance` and increase the total + /// supply in `cap` accordingly. + /// Aborts if `value` + `cap.total_supply` >= U64_MAX + public fun mint_balance( + cap: &mut TreasuryCap, value: u64 + ): Balance { + cap.total_supply.increase_supply(value) + } + + /// Destroy the coin `c` and decrease the total supply in `cap` + /// accordingly. + public entry fun burn(cap: &mut TreasuryCap, c: Coin): u64 { + let Coin { id, balance } = c; + id.delete(); + cap.total_supply.decrease_supply(balance) + } + + /// The index into the deny list vector for the `iota::coin::Coin` type. + const DENY_LIST_COIN_INDEX: u64 = 0; // TODO public(package) const + + /// Adds the given address to the deny list, preventing it + /// from interacting with the specified coin type as an input to a transaction. + public fun deny_list_add( + deny_list: &mut DenyList, + _deny_cap: &mut DenyCap, + addr: address, + _ctx: &mut TxContext + ) { + let `type` = + type_name::into_string(type_name::get_with_original_ids()).into_bytes(); + deny_list::add( + deny_list, + DENY_LIST_COIN_INDEX, + `type`, + addr, + ) + } + + /// Removes an address from the deny list. + /// Aborts with `ENotFrozen` if the address is not already in the list. + public fun deny_list_remove( + deny_list: &mut DenyList, + _deny_cap: &mut DenyCap, + addr: address, + _ctx: &mut TxContext + ) { + let `type` = + type_name::into_string(type_name::get_with_original_ids()).into_bytes(); + deny_list::remove( + deny_list, + DENY_LIST_COIN_INDEX, + `type`, + addr, + ) + } + + /// Returns true iff the given address is denied for the given coin type. It will + /// return false if given a non-coin type. + public fun deny_list_contains( + freezer: &DenyList, + addr: address, + ): bool { + let name = type_name::get_with_original_ids(); + if (type_name::is_primitive(&name)) return false; + + let `type` = type_name::into_string(name).into_bytes(); + freezer.contains(DENY_LIST_COIN_INDEX, `type`, addr) + } + + // === Entrypoints === + + /// Mint `amount` of `Coin` and send it to `recipient`. Invokes `mint()`. + public entry fun mint_and_transfer( + c: &mut TreasuryCap, amount: u64, recipient: address, ctx: &mut TxContext + ) { + transfer::public_transfer(mint(c, amount, ctx), recipient) + } + + // === Update coin metadata === + + /// Update name of the coin in `CoinMetadata` + public entry fun update_name( + _treasury: &TreasuryCap, metadata: &mut CoinMetadata, name: string::String + ) { + metadata.name = name; + } + + /// Update the symbol of the coin in `CoinMetadata` + public entry fun update_symbol( + _treasury: &TreasuryCap, metadata: &mut CoinMetadata, symbol: ascii::String + ) { + metadata.symbol = symbol; + } + + /// Update the description of the coin in `CoinMetadata` + public entry fun update_description( + _treasury: &TreasuryCap, metadata: &mut CoinMetadata, description: string::String + ) { + metadata.description = description; + } + + /// Update the url of the coin in `CoinMetadata` + public entry fun update_icon_url( + _treasury: &TreasuryCap, metadata: &mut CoinMetadata, url: ascii::String + ) { + metadata.icon_url = option::some(url::new_unsafe(url)); + } + + // === Get coin metadata fields for on-chain consumption === + + public fun get_decimals(metadata: &CoinMetadata): u8 { + metadata.decimals + } + + public fun get_name(metadata: &CoinMetadata): string::String { + metadata.name + } + + public fun get_symbol(metadata: &CoinMetadata): ascii::String { + metadata.symbol + } + + public fun get_description(metadata: &CoinMetadata): string::String { + metadata.description + } + + public fun get_icon_url(metadata: &CoinMetadata): Option { + metadata.icon_url + } + + // === Test-only code === + + #[test_only] + /// Mint coins of any type for (obviously!) testing purposes only + public fun mint_for_testing(value: u64, ctx: &mut TxContext): Coin { + Coin { id: object::new(ctx), balance: balance::create_for_testing(value) } + } + + #[test_only] + /// Burn coins of any type for testing purposes only + public fun burn_for_testing(coin: Coin): u64 { + let Coin { id, balance } = coin; + id.delete(); + balance.destroy_for_testing() + } + + #[test_only] + /// Create a `TreasuryCap` for any `Coin` for testing purposes. + public fun create_treasury_cap_for_testing( + ctx: &mut TxContext + ): TreasuryCap { + TreasuryCap { + id: object::new(ctx), + total_supply: balance::create_supply_for_testing() + } + } + + // === Deprecated code === + + // oops, wanted treasury: &TreasuryCap + public fun supply(treasury: &mut TreasuryCap): &Supply { + &treasury.total_supply + } + + // deprecated as we have CoinMetadata now + #[allow(unused_field)] + public struct CurrencyCreated has copy, drop { + decimals: u8 + } +} diff --git a/crates/sui-framework/packages/sui-framework/sources/coin_manager.move b/crates/iota-framework/packages/iota-framework/sources/coin_manager.move similarity index 98% rename from crates/sui-framework/packages/sui-framework/sources/coin_manager.move rename to crates/iota-framework/packages/iota-framework/sources/coin_manager.move index da4ecb30169..805a64d0f8e 100644 --- a/crates/sui-framework/packages/sui-framework/sources/coin_manager.move +++ b/crates/iota-framework/packages/iota-framework/sources/coin_manager.move @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// The purpose of a CoinManager is to allow access to all @@ -6,16 +7,16 @@ /// This includes access to the total supply and metadata /// In addition a optional maximum supply can be set and a custom /// additional Metadata field can be added. -module sui::coin_manager { +module iota::coin_manager { - use sui::event; + use iota::event; use std::type_name; use std::string; use std::ascii; - use sui::url::Url; - use sui::coin::{Self, CoinMetadata, TreasuryCap, Coin}; - use sui::balance::{Balance, Supply}; - use sui::dynamic_field as df; + use iota::url::Url; + use iota::coin::{Self, CoinMetadata, TreasuryCap, Coin}; + use iota::balance::{Balance, Supply}; + use iota::dynamic_field as df; /// The error returned when the maximum supply reached. const EMaximumSupplyReached: u64 = 0; diff --git a/crates/sui-framework/packages/sui-framework/sources/crypto/bls12381.move b/crates/iota-framework/packages/iota-framework/sources/crypto/bls12381.move similarity index 98% rename from crates/sui-framework/packages/sui-framework/sources/crypto/bls12381.move rename to crates/iota-framework/packages/iota-framework/sources/crypto/bls12381.move index 0f3805ccf2c..ef81cce86a6 100644 --- a/crates/sui-framework/packages/sui-framework/sources/crypto/bls12381.move +++ b/crates/iota-framework/packages/iota-framework/sources/crypto/bls12381.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Group operations of BLS12-381. -module sui::bls12381 { +module iota::bls12381 { - use sui::group_ops; - use sui::group_ops::Element; + use iota::group_ops; + use iota::group_ops::Element; /// @param signature: A 48-bytes signature that is a point on the G1 subgroup. /// @param public_key: A 96-bytes public key that is a point on the G2 subgroup. diff --git a/crates/sui-framework/packages/sui-framework/sources/crypto/ecdsa_k1.move b/crates/iota-framework/packages/iota-framework/sources/crypto/ecdsa_k1.move similarity index 97% rename from crates/sui-framework/packages/sui-framework/sources/crypto/ecdsa_k1.move rename to crates/iota-framework/packages/iota-framework/sources/crypto/ecdsa_k1.move index 65617560487..54f0668cc6e 100644 --- a/crates/sui-framework/packages/sui-framework/sources/crypto/ecdsa_k1.move +++ b/crates/iota-framework/packages/iota-framework/sources/crypto/ecdsa_k1.move @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui::ecdsa_k1 { +module iota::ecdsa_k1 { #[allow(unused_const)] /// Error if the public key cannot be recovered from the signature. diff --git a/crates/sui-framework/packages/sui-framework/sources/crypto/ecdsa_r1.move b/crates/iota-framework/packages/iota-framework/sources/crypto/ecdsa_r1.move similarity index 96% rename from crates/sui-framework/packages/sui-framework/sources/crypto/ecdsa_r1.move rename to crates/iota-framework/packages/iota-framework/sources/crypto/ecdsa_r1.move index 52214b8fc7d..7695a96101a 100644 --- a/crates/sui-framework/packages/sui-framework/sources/crypto/ecdsa_r1.move +++ b/crates/iota-framework/packages/iota-framework/sources/crypto/ecdsa_r1.move @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui::ecdsa_r1 { +module iota::ecdsa_r1 { #[allow(unused_const)] /// Error if the public key cannot be recovered from the signature. diff --git a/crates/sui-framework/packages/sui-framework/sources/crypto/ecvrf.move b/crates/iota-framework/packages/iota-framework/sources/crypto/ecvrf.move similarity index 92% rename from crates/sui-framework/packages/sui-framework/sources/crypto/ecvrf.move rename to crates/iota-framework/packages/iota-framework/sources/crypto/ecvrf.move index 3864ffa62da..7ea314af095 100644 --- a/crates/sui-framework/packages/sui-framework/sources/crypto/ecvrf.move +++ b/crates/iota-framework/packages/iota-framework/sources/crypto/ecvrf.move @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui::ecvrf { +module iota::ecvrf { #[allow(unused_const)] const EInvalidHashLength: u64 = 1; #[allow(unused_const)] diff --git a/crates/sui-framework/packages/sui-framework/sources/crypto/ed25519.move b/crates/iota-framework/packages/iota-framework/sources/crypto/ed25519.move similarity index 88% rename from crates/sui-framework/packages/sui-framework/sources/crypto/ed25519.move rename to crates/iota-framework/packages/iota-framework/sources/crypto/ed25519.move index 9afcaea2b44..5430f5ceba4 100644 --- a/crates/sui-framework/packages/sui-framework/sources/crypto/ed25519.move +++ b/crates/iota-framework/packages/iota-framework/sources/crypto/ed25519.move @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui::ed25519 { +module iota::ed25519 { /// @param signature: 32-byte signature that is a point on the Ed25519 elliptic curve. /// @param public_key: 32-byte signature that is a point on the Ed25519 elliptic curve. /// @param msg: The message that we test the signature against. diff --git a/crates/sui-framework/packages/sui-framework/sources/crypto/groth16.move b/crates/iota-framework/packages/iota-framework/sources/crypto/groth16.move similarity index 98% rename from crates/sui-framework/packages/sui-framework/sources/crypto/groth16.move rename to crates/iota-framework/packages/iota-framework/sources/crypto/groth16.move index e1b5804028f..2cd5e656cc8 100644 --- a/crates/sui-framework/packages/sui-framework/sources/crypto/groth16.move +++ b/crates/iota-framework/packages/iota-framework/sources/crypto/groth16.move @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui::groth16 { +module iota::groth16 { #[allow(unused_const)] // Error for input is not a valid Arkwork representation of a verifying key. diff --git a/crates/sui-framework/packages/sui-framework/sources/crypto/group_ops.move b/crates/iota-framework/packages/iota-framework/sources/crypto/group_ops.move similarity index 97% rename from crates/sui-framework/packages/sui-framework/sources/crypto/group_ops.move rename to crates/iota-framework/packages/iota-framework/sources/crypto/group_ops.move index ff1d077d02b..8bb462cc5dc 100644 --- a/crates/sui-framework/packages/sui-framework/sources/crypto/group_ops.move +++ b/crates/iota-framework/packages/iota-framework/sources/crypto/group_ops.move @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Generic Move and native functions for group operations. -module sui::group_ops { +module iota::group_ops { - use sui::bcs; + use iota::bcs; - /* friend sui::bls12381; */ + /* friend iota::bls12381; */ #[allow(unused_const)] const ENotSupported: u64 = 0; // Operation is not supported by the network. diff --git a/crates/iota-framework/packages/iota-framework/sources/crypto/hash.move b/crates/iota-framework/packages/iota-framework/sources/crypto/hash.move new file mode 100644 index 00000000000..00b877036b8 --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/sources/crypto/hash.move @@ -0,0 +1,15 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Module which defines hash functions. Note that Sha-256 and Sha3-256 is available in the std::hash module in the +/// standard library. +module iota::hash { + /// @param data: Arbitrary binary data to hash + /// Hash the input bytes using Blake2b-256 and returns 32 bytes. + native public fun blake2b256(data: &vector): vector; + + /// @param data: Arbitrary binary data to hash + /// Hash the input bytes using keccak256 and returns 32 bytes. + native public fun keccak256(data: &vector): vector; +} diff --git a/crates/sui-framework/packages/sui-framework/sources/crypto/hmac.move b/crates/iota-framework/packages/iota-framework/sources/crypto/hmac.move similarity index 82% rename from crates/sui-framework/packages/sui-framework/sources/crypto/hmac.move rename to crates/iota-framework/packages/iota-framework/sources/crypto/hmac.move index 7235658d2bf..79eda24d8a1 100644 --- a/crates/sui-framework/packages/sui-framework/sources/crypto/hmac.move +++ b/crates/iota-framework/packages/iota-framework/sources/crypto/hmac.move @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui::hmac { +module iota::hmac { /// @param key: HMAC key, arbitrary bytes. /// @param msg: message to sign, arbitrary bytes. diff --git a/crates/sui-framework/packages/sui-framework/sources/crypto/poseidon.move b/crates/iota-framework/packages/iota-framework/sources/crypto/poseidon.move similarity index 94% rename from crates/sui-framework/packages/sui-framework/sources/crypto/poseidon.move rename to crates/iota-framework/packages/iota-framework/sources/crypto/poseidon.move index 1a6055c7a0f..afa0a9a5f45 100644 --- a/crates/sui-framework/packages/sui-framework/sources/crypto/poseidon.move +++ b/crates/iota-framework/packages/iota-framework/sources/crypto/poseidon.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Module which defines instances of the poseidon hash functions. -module sui::poseidon { +module iota::poseidon { - use sui::bcs; + use iota::bcs; /// Error if any of the inputs are larger than or equal to the BN254 field size. const ENonCanonicalInput: u64 = 0; diff --git a/crates/sui-framework/packages/sui-framework/sources/crypto/zklogin_verified_id.move b/crates/iota-framework/packages/iota-framework/sources/crypto/zklogin_verified_id.move similarity index 97% rename from crates/sui-framework/packages/sui-framework/sources/crypto/zklogin_verified_id.move rename to crates/iota-framework/packages/iota-framework/sources/crypto/zklogin_verified_id.move index 8a5699e012e..7b05ad0bdb9 100644 --- a/crates/sui-framework/packages/sui-framework/sources/crypto/zklogin_verified_id.move +++ b/crates/iota-framework/packages/iota-framework/sources/crypto/zklogin_verified_id.move @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[allow(unused_const, unused_function)] -module sui::zklogin_verified_id { +module iota::zklogin_verified_id { use std::string::String; const EFunctionDisabled: u64 = 0; diff --git a/crates/sui-framework/packages/sui-framework/sources/crypto/zklogin_verified_issuer.move b/crates/iota-framework/packages/iota-framework/sources/crypto/zklogin_verified_issuer.move similarity index 96% rename from crates/sui-framework/packages/sui-framework/sources/crypto/zklogin_verified_issuer.move rename to crates/iota-framework/packages/iota-framework/sources/crypto/zklogin_verified_issuer.move index 30f9c94d97a..94f2a5e2b6f 100644 --- a/crates/sui-framework/packages/sui-framework/sources/crypto/zklogin_verified_issuer.move +++ b/crates/iota-framework/packages/iota-framework/sources/crypto/zklogin_verified_issuer.move @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[allow(unused_const)] -module sui::zklogin_verified_issuer { +module iota::zklogin_verified_issuer { use std::string::String; /// Error if the proof consisting of the inputs provided to the verification function is invalid. diff --git a/crates/sui-framework/packages/sui-framework/sources/deny_list.move b/crates/iota-framework/packages/iota-framework/sources/deny_list.move similarity index 92% rename from crates/sui-framework/packages/sui-framework/sources/deny_list.move rename to crates/iota-framework/packages/iota-framework/sources/deny_list.move index ae886b2baaa..98f7d3b6912 100644 --- a/crates/sui-framework/packages/sui-framework/sources/deny_list.move +++ b/crates/iota-framework/packages/iota-framework/sources/deny_list.move @@ -1,22 +1,23 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Defines the `DenyList` type. The `DenyList` shared object is used to restrict access to /// instances of certain core types from being used as inputs by specified addresses in the deny /// list. -module sui::deny_list { - use sui::table::{Self, Table}; - use sui::bag::{Self, Bag}; - use sui::vec_set::{Self, VecSet}; +module iota::deny_list { + use iota::table::{Self, Table}; + use iota::bag::{Self, Bag}; + use iota::vec_set::{Self, VecSet}; - /* friend sui::coin; */ + /* friend iota::coin; */ /// Trying to create a deny list object when not called by the system address. const ENotSystemAddress: u64 = 0; /// The specified address to be removed is not already in the deny list. const ENotDenied: u64 = 1; - /// The index into the deny list vector for the `sui::coin::Coin` type. + /// The index into the deny list vector for the `iota::coin::Coin` type. const COIN_INDEX: u64 = 0; /// A shared object that stores the addresses that are blocked for a given core type. @@ -33,7 +34,7 @@ module sui::deny_list { /// Used to quickly skip checks for most addresses. denied_count: Table, /// Set of addresses that are banned for a given type. - /// For example with `sui::coin::Coin`: If addresses A and B are banned from using + /// For example with `iota::coin::Coin`: If addresses A and B are banned from using /// "0...0123::my_coin::MY_COIN", this will be "0...0123::my_coin::MY_COIN" -> {A, B}. denied_addresses: Table, VecSet
    >, } @@ -133,7 +134,7 @@ module sui::deny_list { let mut lists = bag::new(ctx); lists.add(COIN_INDEX, per_type_list(ctx)); let deny_list_object = DenyList { - id: object::sui_deny_list_object_id(), + id: object::iota_deny_list_object_id(), lists, }; transfer::share_object(deny_list_object); diff --git a/crates/iota-framework/packages/iota-framework/sources/display.move b/crates/iota-framework/packages/iota-framework/sources/display.move new file mode 100644 index 00000000000..c02f3d91731 --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/sources/display.move @@ -0,0 +1,228 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Defines a Display struct which defines the way an Object +/// should be displayed. The intention is to keep data as independent +/// from its display as possible, protecting the development process +/// and keeping it separate from the ecosystem agreements. +/// +/// Each of the fields of the Display object should allow for pattern +/// substitution and filling-in the pieces using the data from the object T. +/// +/// More entry functions might be added in the future depending on the use cases. +module iota::display { + use iota::package::Publisher; + use iota::vec_map::{Self, VecMap}; + use iota::event; + use std::string::String; + + /// For when T does not belong to the package `Publisher`. + const ENotOwner: u64 = 0; + + /// For when vectors passed into one of the multiple insert functions + /// don't match in their lengths. + const EVecLengthMismatch: u64 = 1; + + /// The Display object. Defines the way a T instance should be + /// displayed. Display object can only be created and modified with + /// a PublisherCap, making sure that the rules are set by the owner + /// of the type. + /// + /// Each of the display properties should support patterns outside + /// of the system, making it simpler to customize Display based + /// on the property values of an Object. + /// ``` + /// // Example of a display object + /// Display<0x...::capy::Capy> { + /// fields: + /// + /// + /// + /// + /// } + /// ``` + /// + /// Uses only String type due to external-facing nature of the object, + /// the property names have a priority over their types. + public struct Display has key, store { + id: UID, + /// Contains fields for display. Currently supported + /// fields are: name, link, image and description. + fields: VecMap, + /// Version that can only be updated manually by the Publisher. + version: u16 + } + + /// Event: emitted when a new Display object has been created for type T. + /// Type signature of the event corresponds to the type while id serves for + /// the discovery. + /// + /// Since Iota RPC supports querying events by type, finding a Display for the T + /// would be as simple as looking for the first event with `Display`. + public struct DisplayCreated has copy, drop { + id: ID + } + + /// Version of Display got updated - + public struct VersionUpdated has copy, drop { + id: ID, + version: u16, + fields: VecMap, + } + + // === Initializer Methods === + + /// Create an empty Display object. It can either be shared empty or filled + /// with data right away via cheaper `set_owned` method. + public fun new(pub: &Publisher, ctx: &mut TxContext): Display { + assert!(is_authorized(pub), ENotOwner); + create_internal(ctx) + } + + /// Create a new Display object with a set of fields. + public fun new_with_fields( + pub: &Publisher, fields: vector, values: vector, ctx: &mut TxContext + ): Display { + let len = fields.length(); + assert!(len == values.length(), EVecLengthMismatch); + + let mut i = 0; + let mut display = new(pub, ctx); + while (i < len) { + display.add_internal(fields[i], values[i]); + i = i + 1; + }; + + display + } + + // === Entry functions: Create === + + #[allow(lint(self_transfer))] + /// Create a new empty Display object and keep it. + entry public fun create_and_keep(pub: &Publisher, ctx: &mut TxContext) { + transfer::public_transfer(new(pub, ctx), ctx.sender()) + } + + /// Manually bump the version and emit an event with the updated version's contents. + entry public fun update_version( + display: &mut Display + ) { + display.version = display.version + 1; + event::emit(VersionUpdated { + version: display.version, + fields: *&display.fields, + id: display.id.to_inner(), + }) + } + + // === Entry functions: Add/Modify fields === + + /// Sets a custom `name` field with the `value`. + entry public fun add(self: &mut Display, name: String, value: String) { + self.add_internal(name, value) + } + + /// Sets multiple `fields` with `values`. + entry public fun add_multiple( + self: &mut Display, fields: vector, values: vector + ) { + let len = fields.length(); + assert!(len == values.length(), EVecLengthMismatch); + + let mut i = 0; + while (i < len) { + self.add_internal(fields[i], values[i]); + i = i + 1; + }; + } + + /// Change the value of the field. + /// TODO (long run): version changes; + entry public fun edit(self: &mut Display, name: String, value: String) { + let (_, _) = self.fields.remove(&name); + self.add_internal(name, value) + } + + /// Remove the key from the Display. + entry public fun remove(self: &mut Display, name: String) { + self.fields.remove(&name); + } + + // === Access fields === + + /// Authorization check; can be performed externally to implement protection rules for Display. + public fun is_authorized(pub: &Publisher): bool { + pub.from_package() + } + + /// Read the `version` field. + public fun version(d: &Display): u16 { + d.version + } + + /// Read the `fields` field. + public fun fields(d: &Display): &VecMap { + &d.fields + } + + // === Private functions === + + /// Internal function to create a new `Display`. + fun create_internal(ctx: &mut TxContext): Display { + let uid = object::new(ctx); + + event::emit(DisplayCreated { + id: uid.to_inner() + }); + + Display { + id: uid, + fields: vec_map::empty(), + version: 0, + } + } + + /// Private method for inserting fields without security checks. + fun add_internal(display: &mut Display, name: String, value: String) { + display.fields.insert(name, value) + } +} + +#[test_only] +module iota::display_tests { + use iota::test_scenario as test; + use std::string::String; + use iota::package; + use iota::display; + + #[allow(unused_field)] + /// An example object. + /// Purely for visibility. + public struct Capy has key { + id: UID, + name: String + } + + /// Test witness type to create a Publisher object. + public struct CAPY has drop {} + + #[test] + fun capy_init() { + let mut test = test::begin(@0x2); + let pub = package::test_claim(CAPY {}, test::ctx(&mut test)); + + // create a new display object + let mut display = display::new(&pub, test::ctx(&mut test)); + + display.add(b"name".to_string(), b"Capy {name}".to_string()); + display.add(b"link".to_string(), b"https://capy.art/capy/{id}".to_string()); + display.add(b"image".to_string(), b"https://api.capy.art/capy/{id}/svg".to_string()); + display.add(b"description".to_string(), b"A Lovely Capy".to_string()); + + pub.burn_publisher(); + transfer::public_transfer(display, @0x2); + test.end(); + } +} diff --git a/crates/sui-framework/packages/sui-framework/sources/dynamic_field.move b/crates/iota-framework/packages/iota-framework/sources/dynamic_field.move similarity index 96% rename from crates/sui-framework/packages/sui-framework/sources/dynamic_field.move rename to crates/iota-framework/packages/iota-framework/sources/dynamic_field.move index d56422b2e26..6dd12580543 100644 --- a/crates/sui-framework/packages/sui-framework/sources/dynamic_field.move +++ b/crates/iota-framework/packages/iota-framework/sources/dynamic_field.move @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[allow(unused_const)] -/// In addition to the fields declared in its type definition, a Sui object can have dynamic fields +/// In addition to the fields declared in its type definition, a Iota object can have dynamic fields /// that can be added after the object has been constructed. Unlike ordinary field names /// (which are always statically declared identifiers) a dynamic field name can be any value with /// the `copy`, `drop`, and `store` abilities, e.g. an integer, a boolean, or a string. -/// This gives Sui programmers the flexibility to extend objects on-the-fly, and it also serves as a +/// This gives Iota programmers the flexibility to extend objects on-the-fly, and it also serves as a /// building block for core collection types -module sui::dynamic_field { +module iota::dynamic_field { - /* friend sui::dynamic_object_field; */ + /* friend iota::dynamic_object_field; */ /// The object already has a dynamic field with this name (with the value and type specified) const EFieldAlreadyExists: u64 = 0; diff --git a/crates/sui-framework/packages/sui-framework/sources/dynamic_object_field.move b/crates/iota-framework/packages/iota-framework/sources/dynamic_object_field.move similarity index 93% rename from crates/sui-framework/packages/sui-framework/sources/dynamic_object_field.move rename to crates/iota-framework/packages/iota-framework/sources/dynamic_object_field.move index 07207b7af72..8c01f1eac2b 100644 --- a/crates/sui-framework/packages/sui-framework/sources/dynamic_object_field.move +++ b/crates/iota-framework/packages/iota-framework/sources/dynamic_object_field.move @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -/// Similar to `sui::dynamic_field`, this module allows for the access of dynamic fields. But -/// unlike, `sui::dynamic_field` the values bound to these dynamic fields _must_ be objects +/// Similar to `iota::dynamic_field`, this module allows for the access of dynamic fields. But +/// unlike, `iota::dynamic_field` the values bound to these dynamic fields _must_ be objects /// themselves. This allows for the objects to still exist within in storage, which may be important /// for external tools. The difference is otherwise not observable from within Move. -module sui::dynamic_object_field { - use sui::dynamic_field::{ +module iota::dynamic_object_field { + use iota::dynamic_field::{ Self as field, add_child_object, borrow_child_object, diff --git a/crates/sui-framework/packages/sui-framework/sources/event.move b/crates/iota-framework/packages/iota-framework/sources/event.move similarity index 81% rename from crates/sui-framework/packages/sui-framework/sources/event.move rename to crates/iota-framework/packages/iota-framework/sources/event.move index f6478eee618..7327b012c25 100644 --- a/crates/sui-framework/packages/sui-framework/sources/event.move +++ b/crates/iota-framework/packages/iota-framework/sources/event.move @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -/// Events module. Defines the `sui::event::emit` function which +/// Events module. Defines the `iota::event::emit` function which /// creates and sends a custom MoveEvent as a part of the effects /// certificate of the transaction. /// @@ -15,7 +16,7 @@ /// Example: /// ``` /// module my::marketplace { -/// use sui::event; +/// use iota::event; /// /* ... */ /// struct ItemPurchased has copy, drop { /// item_id: ID, buyer: address @@ -26,11 +27,11 @@ /// } /// } /// ``` -module sui::event { +module iota::event { /// Emit a custom Move event, sending the data offchain. /// /// Used for creating custom indexes and tracking onchain - /// activity in a way that suits a specific application the most. + /// activity in a way that iotats a specific application the most. /// /// The type `T` is the main way to index the event, and can contain /// phantom parameters, eg `emit(MyEvent)`. diff --git a/crates/sui-framework/packages/sui-framework/sources/hex.move b/crates/iota-framework/packages/iota-framework/sources/hex.move similarity index 98% rename from crates/sui-framework/packages/sui-framework/sources/hex.move rename to crates/iota-framework/packages/iota-framework/sources/hex.move index cf6e5efb871..261ab3a2116 100644 --- a/crates/sui-framework/packages/sui-framework/sources/hex.move +++ b/crates/iota-framework/packages/iota-framework/sources/hex.move @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// HEX (Base16) encoding utility. -module sui::hex { +module iota::hex { const EInvalidHexLength: u64 = 0; const ENotValidHexCharacter: u64 = 1; diff --git a/crates/iota-framework/packages/iota-framework/sources/iota.move b/crates/iota-framework/packages/iota-framework/sources/iota.move new file mode 100644 index 00000000000..e2ceb1fe3fc --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/sources/iota.move @@ -0,0 +1,57 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Coin is the token used to pay for gas in Iota. +/// It has 9 decimals, and the smallest unit (10^-9) is called "micros". +module iota::iota { + use iota::balance::Balance; + use iota::coin; + + const EAlreadyMinted: u64 = 0; + /// Sender is not @0x0 the system address. + const ENotSystemAddress: u64 = 1; + + #[allow(unused_const)] + /// The amount of Micros per Iota token based on the fact that micros is + /// 10^-9 of a Iota token + const MICROS_PER_IOTA: u64 = 1_000_000_000; + + #[allow(unused_const)] + /// The total supply of Iota denominated in whole Iota tokens (10 Billion) + const TOTAL_SUPPLY_IOTA: u64 = 10_000_000_000; + + /// The total supply of Iota denominated in Micros (10 Billion * 10^9) + const TOTAL_SUPPLY_MICROS: u64 = 10_000_000_000_000_000_000; + + /// Name of the coin + public struct IOTA has drop {} + + #[allow(unused_function)] + /// Register the `IOTA` Coin to acquire its `Supply`. + /// This should be called only once during genesis creation. + fun new(ctx: &mut TxContext): Balance { + assert!(ctx.sender() == @0x0, ENotSystemAddress); + assert!(ctx.epoch() == 0, EAlreadyMinted); + + let (treasury, metadata) = coin::create_currency( + IOTA {}, + 9, + b"IOTA", + b"Iota", + // TODO: add appropriate description and logo url + b"", + option::none(), + ctx + ); + transfer::public_freeze_object(metadata); + let mut supply = treasury.treasury_into_supply(); + let total_iota = supply.increase_supply(TOTAL_SUPPLY_MICROS); + supply.destroy_supply(); + total_iota + } + + public entry fun transfer(c: coin::Coin, recipient: address) { + transfer::public_transfer(c, recipient) + } +} diff --git a/crates/sui-framework/packages/sui-framework/sources/kiosk/kiosk.move b/crates/iota-framework/packages/iota-framework/sources/kiosk/kiosk.move similarity index 97% rename from crates/sui-framework/packages/sui-framework/sources/kiosk/kiosk.move rename to crates/iota-framework/packages/iota-framework/sources/kiosk/kiosk.move index 4a6716c6d9c..970dcf1dfb6 100644 --- a/crates/sui-framework/packages/sui-framework/sources/kiosk/kiosk.move +++ b/crates/iota-framework/packages/iota-framework/sources/kiosk/kiosk.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Kiosk is a primitive for building safe, decentralized and trustless trading @@ -29,7 +30,7 @@ /// /// - `locked` - Similar to `placed` except that `take` is disabled and the only /// way to move the asset out of the Kiosk is to `list` it or -/// `list_with_purchase_cap` therefore performing a trade (issuing a +/// `list_with_purchase_cap` therefore performing a trade (isiotang a /// `TransferRequest`). The check on the `lock` function makes sure that the /// `TransferPolicy` exists to not lock the item in a `Kiosk` forever. /// @@ -70,7 +71,7 @@ /// object so they don't have to pay anything /// - I create and wrap a `TransferPolicy` so that players of my game can /// transfer items between `Kiosk`s in game without any charge (and maybe not -/// even paying the price with a 0 SUI PurchaseCap) +/// even paying the price with a 0 IOTA PurchaseCap) /// /// ``` /// Kiosk -> (Item, TransferRequest) @@ -80,18 +81,18 @@ /// ``` /// /// See `transfer_policy` module for more details on how they function. -module sui::kiosk { - use sui::dynamic_object_field as dof; - use sui::dynamic_field as df; - use sui::transfer_policy::{ +module iota::kiosk { + use iota::dynamic_object_field as dof; + use iota::dynamic_field as df; + use iota::transfer_policy::{ Self, TransferPolicy, TransferRequest }; - use sui::balance::{Self, Balance}; - use sui::coin::{Self, Coin}; - use sui::sui::SUI; - use sui::event; + use iota::balance::{Self, Balance}; + use iota::coin::{Self, Coin}; + use iota::iota::IOTA; + use iota::event; /// Allows calling `cap.kiosk()` to retrieve `for` field from `KioskOwnerCap`. public use fun kiosk_owner_cap_for as KioskOwnerCap.kiosk; @@ -100,7 +101,7 @@ module sui::kiosk { // - `place_internal` // - `lock_internal` // - `uid_mut_internal` - /* friend sui::kiosk_extension; */ + /* friend iota::kiosk_extension; */ /// Trying to withdraw profits and sender is not owner. const ENotOwner: u64 = 0; @@ -136,7 +137,7 @@ module sui::kiosk { public struct Kiosk has key, store { id: UID, /// Balance of the Kiosk - all profits from sales go here. - profits: Balance, + profits: Balance, /// Always point to `sender` of the transaction. /// Can be changed by calling `set_owner` with Cap. owner: address, @@ -237,8 +238,8 @@ module sui::kiosk { /// `KioskOwnerCap` and becomes the Owner, the `Kiosk` is shared. entry fun default(ctx: &mut TxContext) { let (kiosk, cap) = new(ctx); - sui::transfer::transfer(cap, ctx.sender()); - sui::transfer::share_object(kiosk); + iota::transfer::transfer(cap, ctx.sender()); + iota::transfer::share_object(kiosk); } /// Creates a new `Kiosk` with a matching `KioskOwnerCap`. @@ -264,7 +265,7 @@ module sui::kiosk { /// case where there's no items inside and a `Kiosk` is not shared. public fun close_and_withdraw( self: Kiosk, cap: KioskOwnerCap, ctx: &mut TxContext - ): Coin { + ): Coin { let Kiosk { id, profits, owner: _, item_count, allow_extensions: _ } = self; let KioskOwnerCap { id: cap_id, `for` } = cap; @@ -382,7 +383,7 @@ module sui::kiosk { /// request their approval (by calling some function) so that the trade can be /// finalized. public fun purchase( - self: &mut Kiosk, id: ID, payment: Coin + self: &mut Kiosk, id: ID, payment: Coin ): (T, TransferRequest) { let price = df::remove(&mut self.id, Listing { id, is_exclusive: false }); let inner = dof::remove(&mut self.id, Item { id }); @@ -421,7 +422,7 @@ module sui::kiosk { /// Unpack the `PurchaseCap` and call `purchase`. Sets the payment amount /// as the price for the listing making sure it's no less than `min_amount`. public fun purchase_with_cap( - self: &mut Kiosk, purchase_cap: PurchaseCap, payment: Coin + self: &mut Kiosk, purchase_cap: PurchaseCap, payment: Coin ): (T, TransferRequest) { let PurchaseCap { id, item_id, kiosk_id, min_price } = purchase_cap; id.delete(); @@ -456,7 +457,7 @@ module sui::kiosk { /// Withdraw profits from the Kiosk. public fun withdraw( self: &mut Kiosk, cap: &KioskOwnerCap, amount: Option, ctx: &mut TxContext - ): Coin { + ): Coin { assert!(self.has_access(cap), ENotOwner); let amount = if (amount.is_some()) { @@ -574,7 +575,7 @@ module sui::kiosk { } /// Get mutable access to `profits` - owner only action. - public fun profits_mut(self: &mut Kiosk, cap: &KioskOwnerCap): &mut Balance { + public fun profits_mut(self: &mut Kiosk, cap: &KioskOwnerCap): &mut Balance { assert!(self.has_access(cap), ENotOwner); &mut self.profits } diff --git a/crates/sui-framework/packages/sui-framework/sources/kiosk/kiosk_extension.move b/crates/iota-framework/packages/iota-framework/sources/kiosk/kiosk_extension.move similarity index 97% rename from crates/sui-framework/packages/sui-framework/sources/kiosk/kiosk_extension.move rename to crates/iota-framework/packages/iota-framework/sources/kiosk/kiosk_extension.move index dd3ec9e2fe3..f4d1d657b70 100644 --- a/crates/sui-framework/packages/sui-framework/sources/kiosk/kiosk_extension.move +++ b/crates/iota-framework/packages/iota-framework/sources/kiosk/kiosk_extension.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// This module implements the Kiosk Extensions functionality. It allows @@ -38,11 +39,11 @@ /// - `kiosk_extension` is a friend module to `kiosk` and has access to its /// internal functions (such as `place_internal` and `lock_internal` to /// implement custom authorization scheme for `place` and `lock` respectively). -module sui::kiosk_extension { - use sui::bag::{Self, Bag}; - use sui::dynamic_field as df; - use sui::transfer_policy::TransferPolicy; - use sui::kiosk::{Kiosk, KioskOwnerCap}; +module iota::kiosk_extension { + use iota::bag::{Self, Bag}; + use iota::dynamic_field as df; + use iota::transfer_policy::TransferPolicy; + use iota::kiosk::{Kiosk, KioskOwnerCap}; /// Trying to add an extension while not being the owner of the Kiosk. const ENotOwner: u64 = 0; diff --git a/crates/sui-framework/packages/sui-framework/sources/kiosk/transfer_policy.move b/crates/iota-framework/packages/iota-framework/sources/kiosk/transfer_policy.move similarity index 94% rename from crates/sui-framework/packages/sui-framework/sources/kiosk/transfer_policy.move rename to crates/iota-framework/packages/iota-framework/sources/kiosk/transfer_policy.move index 075bfb5969e..36a5a875230 100644 --- a/crates/sui-framework/packages/sui-framework/sources/kiosk/transfer_policy.move +++ b/crates/iota-framework/packages/iota-framework/sources/kiosk/transfer_policy.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Defines the `TransferPolicy` type and the logic to approve `TransferRequest`s. @@ -21,15 +22,15 @@ /// of their types and collect profits if a fee is required on sales. Custom /// policies can be removed at any moment, and the change will affect all instances /// of the type at once. -module sui::transfer_policy { +module iota::transfer_policy { use std::type_name::{Self, TypeName}; - use sui::package::{Self, Publisher}; - use sui::vec_set::{Self, VecSet}; - use sui::dynamic_field as df; - use sui::balance::{Self, Balance}; - use sui::sui::SUI; - use sui::coin::{Self, Coin}; - use sui::event; + use iota::package::{Self, Publisher}; + use iota::vec_set::{Self, VecSet}; + use iota::dynamic_field as df; + use iota::balance::{Self, Balance}; + use iota::iota::IOTA; + use iota::coin::{Self, Coin}; + use iota::event; /// The number of receipts does not match the `TransferPolicy` requirement. const EPolicyNotSatisfied: u64 = 0; @@ -51,7 +52,7 @@ module sui::transfer_policy { /// constraints, the main use case for this module is to work /// with Objects. item: ID, - /// Amount of SUI paid for the item. Can be used to + /// Amount of IOTA paid for the item. Can be used to /// calculate the fee / transfer policy enforcement. paid: u64, /// The ID of the Kiosk / Safe the object is being sold from. @@ -69,11 +70,11 @@ module sui::transfer_policy { /// policies can be used to confirm the `TransferRequest`. public struct TransferPolicy has key, store { id: UID, - /// The Balance of the `TransferPolicy` which collects `SUI`. + /// The Balance of the `TransferPolicy` which collects `IOTA`. /// By default, transfer policy does not collect anything , and it's /// a matter of an implementation of a specific rule - whether to add /// to balance and how much. - balance: Balance, + balance: Balance, /// Set of types of attached rules - used to verify `receipts` when /// a `TransferRequest` is received in `confirm_request` function. /// @@ -134,8 +135,8 @@ module sui::transfer_policy { /// sender. entry fun default(pub: &Publisher, ctx: &mut TxContext) { let (policy, cap) = new(pub, ctx); - sui::transfer::share_object(policy); - sui::transfer::transfer(cap, ctx.sender()); + iota::transfer::share_object(policy); + iota::transfer::transfer(cap, ctx.sender()); } /// Withdraw some amount of profits from the `TransferPolicy`. If amount @@ -145,7 +146,7 @@ module sui::transfer_policy { cap: &TransferPolicyCap, amount: Option, ctx: &mut TxContext - ): Coin { + ): Coin { assert!(object::id(self) == cap.policy_id, ENotOwner); let amount = if (amount.is_some()) { @@ -163,7 +164,7 @@ module sui::transfer_policy { /// Can be performed by any party as long as they own it. public fun destroy_and_withdraw( self: TransferPolicy, cap: TransferPolicyCap, ctx: &mut TxContext - ): Coin { + ): Coin { assert!(object::id(&self) == cap.policy_id, ENotOwner); let TransferPolicyCap { id: cap_id, policy_id } = cap; @@ -226,9 +227,9 @@ module sui::transfer_policy { df::borrow(&policy.id, RuleKey {}) } - /// Add some `SUI` to the balance of a `TransferPolicy`. + /// Add some `IOTA` to the balance of a `TransferPolicy`. public fun add_to_balance( - _: Rule, policy: &mut TransferPolicy, coin: Coin + _: Rule, policy: &mut TransferPolicy, coin: Coin ) { assert!(has_rule(policy), EUnknownRequrement); coin::put(&mut policy.balance, coin) diff --git a/crates/sui-framework/packages/sui-framework/sources/linked_table.move b/crates/iota-framework/packages/iota-framework/sources/linked_table.move similarity index 89% rename from crates/sui-framework/packages/sui-framework/sources/linked_table.move rename to crates/iota-framework/packages/iota-framework/sources/linked_table.move index d7e91b1c78e..6e70d7c80e0 100644 --- a/crates/sui-framework/packages/sui-framework/sources/linked_table.move +++ b/crates/iota-framework/packages/iota-framework/sources/linked_table.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -/// Similar to `sui::table` but the values are linked together, allowing for ordered insertion and +/// Similar to `iota::table` but the values are linked together, allowing for ordered insertion and /// removal -module sui::linked_table { - use sui::dynamic_field as field; +module iota::linked_table { + use iota::dynamic_field as field; // Attempted to destroy a non-empty table const ETableNotEmpty: u64 = 0; @@ -53,7 +54,7 @@ module sui::linked_table { /// Inserts a key-value pair at the front of the table, i.e. the newly inserted pair will be /// the first element in the table - /// Aborts with `sui::dynamic_field::EFieldAlreadyExists` if the table already has an entry with + /// Aborts with `iota::dynamic_field::EFieldAlreadyExists` if the table already has an entry with /// that key `k: K`. public fun push_front( table: &mut LinkedTable, @@ -76,7 +77,7 @@ module sui::linked_table { /// Inserts a key-value pair at the back of the table, i.e. the newly inserted pair will be /// the last element in the table - /// Aborts with `sui::dynamic_field::EFieldAlreadyExists` if the table already has an entry with + /// Aborts with `iota::dynamic_field::EFieldAlreadyExists` if the table already has an entry with /// that key `k: K`. public fun push_back( table: &mut LinkedTable, @@ -99,7 +100,7 @@ module sui::linked_table { #[syntax(index)] /// Immutable borrows the value associated with the key in the table `table: &LinkedTable`. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with /// that key `k: K`. public fun borrow(table: &LinkedTable, k: K): &V { &field::borrow>(&table.id, k).value @@ -107,7 +108,7 @@ module sui::linked_table { #[syntax(index)] /// Mutably borrows the value associated with the key in the table `table: &mut LinkedTable`. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with /// that key `k: K`. public fun borrow_mut( table: &mut LinkedTable, @@ -118,7 +119,7 @@ module sui::linked_table { /// Borrows the key for the previous entry of the specified key `k: K` in the table /// `table: &LinkedTable`. Returns None if the entry does not have a predecessor. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with /// that key `k: K` public fun prev(table: &LinkedTable, k: K): &Option { &field::borrow>(&table.id, k).prev @@ -126,7 +127,7 @@ module sui::linked_table { /// Borrows the key for the next entry of the specified key `k: K` in the table /// `table: &LinkedTable`. Returns None if the entry does not have a predecessor. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with /// that key `k: K` public fun next(table: &LinkedTable, k: K): &Option { &field::borrow>(&table.id, k).next @@ -134,7 +135,7 @@ module sui::linked_table { /// Removes the key-value pair in the table `table: &mut LinkedTable` and returns the value. /// This splices the element out of the ordering. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with /// that key `k: K`. Note: this is also what happens when the table is empty. public fun remove(table: &mut LinkedTable, k: K): V { let Node { prev, next, value } = field::remove(&mut table.id, k); diff --git a/crates/iota-framework/packages/iota-framework/sources/math.move b/crates/iota-framework/packages/iota-framework/sources/math.move new file mode 100644 index 00000000000..2b1a00e8d50 --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/sources/math.move @@ -0,0 +1,145 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Basic math for nicer programmability +module iota::math { + + /// Return the larger of `x` and `y` + public fun max(x: u64, y: u64): u64 { + if (x > y) { + x + } else { + y + } + } + + /// Return the smaller of `x` and `y` + public fun min(x: u64, y: u64): u64 { + if (x < y) { + x + } else { + y + } + } + + /// Return the absolute value of x - y + public fun diff(x: u64, y: u64): u64 { + if (x > y) { + x - y + } else { + y - x + } + } + + /// Return the value of a base raised to a power + public fun pow(mut base: u64, mut exponent: u8): u64 { + let mut res = 1; + while (exponent >= 1) { + if (exponent % 2 == 0) { + base = base * base; + exponent = exponent / 2; + } else { + res = res * base; + exponent = exponent - 1; + } + }; + + res + } + + /// Get a nearest lower integer Square Root for `x`. Given that this + /// function can only operate with integers, it is impossible + /// to get perfect (or precise) integer square root for some numbers. + /// + /// Example: + /// ``` + /// math::sqrt(9) => 3 + /// math::sqrt(8) => 2 // the nearest lower square root is 4; + /// ``` + /// + /// In integer math, one of the possible ways to get results with more + /// precision is to use higher values or temporarily multiply the + /// value by some bigger number. Ideally if this is a square of 10 or 100. + /// + /// Example: + /// ``` + /// math::sqrt(8) => 2; + /// math::sqrt(8 * 10000) => 282; + /// // now we can use this value as if it was 2.82; + /// // but to get the actual result, this value needs + /// // to be divided by 100 (because sqrt(10000)). + /// + /// + /// math::sqrt(8 * 1000000) => 2828; // same as above, 2828 / 1000 (2.828) + /// ``` + public fun sqrt(x: u64): u64 { + let mut bit = 1u128 << 64; + let mut res = 0u128; + let mut x = x as u128; + + while (bit != 0) { + if (x >= res + bit) { + x = x - (res + bit); + res = (res >> 1) + bit; + } else { + res = res >> 1; + }; + bit = bit >> 2; + }; + + res as u64 + } + + /// Similar to math::sqrt, but for u128 numbers. Get a nearest lower integer Square Root for `x`. Given that this + /// function can only operate with integers, it is impossible + /// to get perfect (or precise) integer square root for some numbers. + /// + /// Example: + /// ``` + /// math::sqrt_u128(9) => 3 + /// math::sqrt_u128(8) => 2 // the nearest lower square root is 4; + /// ``` + /// + /// In integer math, one of the possible ways to get results with more + /// precision is to use higher values or temporarily multiply the + /// value by some bigger number. Ideally if this is a square of 10 or 100. + /// + /// Example: + /// ``` + /// math::sqrt_u128(8) => 2; + /// math::sqrt_u128(8 * 10000) => 282; + /// // now we can use this value as if it was 2.82; + /// // but to get the actual result, this value needs + /// // to be divided by 100 (because sqrt_u128(10000)). + /// + /// + /// math::sqrt_u128(8 * 1000000) => 2828; // same as above, 2828 / 1000 (2.828) + /// ``` + public fun sqrt_u128(x: u128): u128 { + let mut bit = 1u256 << 128; + let mut res = 0u256; + let mut x = x as u256; + + while (bit != 0) { + if (x >= res + bit) { + x = x - (res + bit); + res = (res >> 1) + bit; + } else { + res = res >> 1; + }; + bit = bit >> 2; + }; + + res as u128 + } + + /// Calculate x / y, but round up the result. + public fun divide_and_round_up(x: u64, y: u64): u64 { + if (x % y == 0) { + x / y + } else { + x / y + 1 + } + } +} diff --git a/crates/iota-framework/packages/iota-framework/sources/object.move b/crates/iota-framework/packages/iota-framework/sources/object.move new file mode 100644 index 00000000000..0eae9d2b47d --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/sources/object.move @@ -0,0 +1,235 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Iota object identifiers +module iota::object { + use std::bcs; + use iota::address; + + /* friend iota::clock; */ + /* friend iota::coin; */ + /* friend iota::dynamic_field; */ + /* friend iota::dynamic_object_field; */ + /* friend iota::transfer; */ + /* friend iota::authenticator_state; */ + /* friend iota::random; */ + /* friend iota::deny_list; */ + + /// Allows calling `.to_address` on an `ID` to get an `address`. + public use fun id_to_address as ID.to_address; + + /// Allows calling `.to_bytes` on an `ID` to get a `vector`. + public use fun id_to_bytes as ID.to_bytes; + + /// Allows calling `.as_inner` on a `UID` to get an `&ID`. + public use fun uid_as_inner as UID.as_inner; + + /// Allows calling `.to_inner` on a `UID` to get an `ID`. + public use fun uid_to_inner as UID.to_inner; + + /// Allows calling `.to_address` on a `UID` to get an `address`. + public use fun uid_to_address as UID.to_address; + + /// Allows calling `.to_bytes` on a `UID` to get a `vector`. + public use fun uid_to_bytes as UID.to_bytes; + + /* #[test_only] */ + /* friend iota::test_scenario; */ + + /// The hardcoded ID for the singleton Iota System State Object. + const IOTA_SYSTEM_STATE_OBJECT_ID: address = @0x5; + + /// The hardcoded ID for the singleton Clock Object. + const IOTA_CLOCK_OBJECT_ID: address = @0x6; + + /// The hardcoded ID for the singleton AuthenticatorState Object. + const IOTA_AUTHENTICATOR_STATE_ID: address = @0x7; + + /// The hardcoded ID for the singleton Random Object. + const IOTA_RANDOM_ID: address = @0x8; + + /// The hardcoded ID for the singleton DenyList. + const IOTA_DENY_LIST_OBJECT_ID: address = @0x403; + + /// Sender is not @0x0 the system address. + const ENotSystemAddress: u64 = 0; + + /// An object ID. This is used to reference Iota Objects. + /// This is *not* guaranteed to be globally unique--anyone can create an `ID` from a `UID` or + /// from an object, and ID's can be freely copied and dropped. + /// Here, the values are not globally unique because there can be multiple values of type `ID` + /// with the same underlying bytes. For example, `object::id(&obj)` can be called as many times + /// as you want for a given `obj`, and each `ID` value will be identical. + public struct ID has copy, drop, store { + // We use `address` instead of `vector` here because `address` has a more + // compact serialization. `address` is serialized as a BCS fixed-length sequence, + // which saves us the length prefix we would pay for if this were `vector`. + // See https://github.com/diem/bcs#fixed-and-variable-length-sequences. + bytes: address + } + + /// Globally unique IDs that define an object's ID in storage. Any Iota Object, that is a struct + /// with the `key` ability, must have `id: UID` as its first field. + /// These are globally unique in the sense that no two values of type `UID` are ever equal, in + /// other words for any two values `id1: UID` and `id2: UID`, `id1` != `id2`. + /// This is a privileged type that can only be derived from a `TxContext`. + /// `UID` doesn't have the `drop` ability, so deleting a `UID` requires a call to `delete`. + public struct UID has store { + id: ID, + } + + // === id === + + /// Get the raw bytes of a `ID` + public fun id_to_bytes(id: &ID): vector { + bcs::to_bytes(&id.bytes) + } + + /// Get the inner bytes of `id` as an address. + public fun id_to_address(id: &ID): address { + id.bytes + } + + /// Make an `ID` from raw bytes. + public fun id_from_bytes(bytes: vector): ID { + address::from_bytes(bytes).to_id() + } + + /// Make an `ID` from an address. + public fun id_from_address(bytes: address): ID { + ID { bytes } + } + + // === uid === + + #[allow(unused_function)] + /// Create the `UID` for the singleton `IotaSystemState` object. + /// This should only be called once from `iota_system`. + fun iota_system_state(ctx: &TxContext): UID { + assert!(ctx.sender() == @0x0, ENotSystemAddress); + UID { + id: ID { bytes: IOTA_SYSTEM_STATE_OBJECT_ID }, + } + } + + /// Create the `UID` for the singleton `Clock` object. + /// This should only be called once from `clock`. + public(package) fun clock(): UID { + UID { + id: ID { bytes: IOTA_CLOCK_OBJECT_ID } + } + } + + /// Create the `UID` for the singleton `AuthenticatorState` object. + /// This should only be called once from `authenticator_state`. + public(package) fun authenticator_state(): UID { + UID { + id: ID { bytes: IOTA_AUTHENTICATOR_STATE_ID } + } + } + + /// Create the `UID` for the singleton `Random` object. + /// This should only be called once from `random`. + public(package) fun randomness_state(): UID { + UID { + id: ID { bytes: IOTA_RANDOM_ID } + } + } + + /// Create the `UID` for the singleton `DenyList` object. + /// This should only be called once from `deny_list`. + public(package) fun iota_deny_list_object_id(): UID { + UID { + id: ID { bytes: IOTA_DENY_LIST_OBJECT_ID } + } + } + + /// Get the inner `ID` of `uid` + public fun uid_as_inner(uid: &UID): &ID { + &uid.id + } + + /// Get the raw bytes of a `uid`'s inner `ID` + public fun uid_to_inner(uid: &UID): ID { + uid.id + } + + /// Get the raw bytes of a `UID` + public fun uid_to_bytes(uid: &UID): vector { + bcs::to_bytes(&uid.id.bytes) + } + + /// Get the inner bytes of `id` as an address. + public fun uid_to_address(uid: &UID): address { + uid.id.bytes + } + + // === any object === + + /// Create a new object. Returns the `UID` that must be stored in a Iota object. + /// This is the only way to create `UID`s. + public fun new(ctx: &mut TxContext): UID { + UID { + id: ID { bytes: ctx.fresh_object_address() }, + } + } + + /// Delete the object and it's `UID`. This is the only way to eliminate a `UID`. + // This exists to inform Iota of object deletions. When an object + // gets unpacked, the programmer will have to do something with its + // `UID`. The implementation of this function emits a deleted + // system event so Iota knows to process the object deletion + public fun delete(id: UID) { + let UID { id: ID { bytes } } = id; + delete_impl(bytes) + } + + /// Get the underlying `ID` of `obj` + public fun id(obj: &T): ID { + borrow_uid(obj).id + } + + /// Borrow the underlying `ID` of `obj` + public fun borrow_id(obj: &T): &ID { + &borrow_uid(obj).id + } + + /// Get the raw bytes for the underlying `ID` of `obj` + public fun id_bytes(obj: &T): vector { + bcs::to_bytes(&borrow_uid(obj).id) + } + + /// Get the inner bytes for the underlying `ID` of `obj` + public fun id_address(obj: &T): address { + borrow_uid(obj).id.bytes + } + + /// Get the `UID` for `obj`. + /// Safe because Iota has an extra bytecode verifier pass that forces every struct with + /// the `key` ability to have a distinguished `UID` field. + /// Cannot be made public as the access to `UID` for a given object must be privileged, and + /// restrictable in the object's module. + native fun borrow_uid(obj: &T): &UID; + + /// Generate a new UID specifically used for creating a UID from a hash + public(package) fun new_uid_from_hash(bytes: address): UID { + record_new_uid(bytes); + UID { id: ID { bytes } } + } + + // === internal functions === + + // helper for delete + native fun delete_impl(id: address); + + // marks newly created UIDs from hash + native fun record_new_uid(id: address); + + #[test_only] + /// Return the most recent created object ID. + public fun last_created(ctx: &TxContext): ID { + ID { bytes: ctx.last_created_object_id() } + } + +} diff --git a/crates/sui-framework/packages/sui-framework/sources/object_bag.move b/crates/iota-framework/packages/iota-framework/sources/object_bag.move similarity index 76% rename from crates/sui-framework/packages/sui-framework/sources/object_bag.move rename to crates/iota-framework/packages/iota-framework/sources/object_bag.move index 2f01d8a4fc1..6df3d2ecb2e 100644 --- a/crates/sui-framework/packages/sui-framework/sources/object_bag.move +++ b/crates/iota-framework/packages/iota-framework/sources/object_bag.move @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -/// Similar to `sui::bag`, an `ObjectBag` is a heterogeneous map-like collection. But unlike -/// `sui::bag`, the values bound to these dynamic fields _must_ be objects themselves. This allows +/// Similar to `iota::bag`, an `ObjectBag` is a heterogeneous map-like collection. But unlike +/// `iota::bag`, the values bound to these dynamic fields _must_ be objects themselves. This allows /// for the objects to still exist in storage, which may be important for external tools. /// The difference is otherwise not observable from within Move. -module sui::object_bag { - use sui::dynamic_object_field as ofield; +module iota::object_bag { + use iota::dynamic_object_field as ofield; // Attempted to destroy a non-empty bag const EBagNotEmpty: u64 = 0; @@ -27,7 +28,7 @@ module sui::object_bag { } /// Adds a key-value pair to the bag `bag: &mut ObjectBag` - /// Aborts with `sui::dynamic_field::EFieldAlreadyExists` if the bag already has an entry with + /// Aborts with `iota::dynamic_field::EFieldAlreadyExists` if the bag already has an entry with /// that key `k: K`. public fun add(bag: &mut ObjectBag, k: K, v: V) { ofield::add(&mut bag.id, k, v); @@ -36,9 +37,9 @@ module sui::object_bag { #[syntax(index)] /// Immutably borrows the value associated with the key in the bag `bag: &ObjectBag`. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the bag does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the bag does not have an entry with /// that key `k: K`. - /// Aborts with `sui::dynamic_field::EFieldTypeMismatch` if the bag has an entry for the key, but + /// Aborts with `iota::dynamic_field::EFieldTypeMismatch` if the bag has an entry for the key, but /// the value does not have the specified type. public fun borrow(bag: &ObjectBag, k: K): &V { ofield::borrow(&bag.id, k) @@ -46,18 +47,18 @@ module sui::object_bag { #[syntax(index)] /// Mutably borrows the value associated with the key in the bag `bag: &mut ObjectBag`. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the bag does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the bag does not have an entry with /// that key `k: K`. - /// Aborts with `sui::dynamic_field::EFieldTypeMismatch` if the bag has an entry for the key, but + /// Aborts with `iota::dynamic_field::EFieldTypeMismatch` if the bag has an entry for the key, but /// the value does not have the specified type. public fun borrow_mut(bag: &mut ObjectBag, k: K): &mut V { ofield::borrow_mut(&mut bag.id, k) } /// Mutably borrows the key-value pair in the bag `bag: &mut ObjectBag` and returns the value. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the bag does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the bag does not have an entry with /// that key `k: K`. - /// Aborts with `sui::dynamic_field::EFieldTypeMismatch` if the bag has an entry for the key, but + /// Aborts with `iota::dynamic_field::EFieldTypeMismatch` if the bag has an entry for the key, but /// the value does not have the specified type. public fun remove(bag: &mut ObjectBag, k: K): V { let v = ofield::remove(&mut bag.id, k); diff --git a/crates/sui-framework/packages/sui-framework/sources/object_table.move b/crates/iota-framework/packages/iota-framework/sources/object_table.move similarity index 82% rename from crates/sui-framework/packages/sui-framework/sources/object_table.move rename to crates/iota-framework/packages/iota-framework/sources/object_table.move index a6dc52aafb5..09bc719b045 100644 --- a/crates/sui-framework/packages/sui-framework/sources/object_table.move +++ b/crates/iota-framework/packages/iota-framework/sources/object_table.move @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -/// Similar to `sui::table`, an `ObjectTable` is a map-like collection. But unlike -/// `sui::table`, the values bound to these dynamic fields _must_ be objects themselves. This allows +/// Similar to `iota::table`, an `ObjectTable` is a map-like collection. But unlike +/// `iota::table`, the values bound to these dynamic fields _must_ be objects themselves. This allows /// for the objects to still exist within in storage, which may be important for external tools. /// The difference is otherwise not observable from within Move. -module sui::object_table { - use sui::dynamic_object_field as ofield; +module iota::object_table { + use iota::dynamic_object_field as ofield; // Attempted to destroy a non-empty table const ETableNotEmpty: u64 = 0; @@ -27,7 +28,7 @@ module sui::object_table { } /// Adds a key-value pair to the table `table: &mut ObjectTable` - /// Aborts with `sui::dynamic_field::EFieldAlreadyExists` if the table already has an entry with + /// Aborts with `iota::dynamic_field::EFieldAlreadyExists` if the table already has an entry with /// that key `k: K`. public fun add(table: &mut ObjectTable, k: K, v: V) { ofield::add(&mut table.id, k, v); @@ -36,7 +37,7 @@ module sui::object_table { #[syntax(index)] /// Immutable borrows the value associated with the key in the table `table: &ObjectTable`. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with /// that key `k: K`. public fun borrow(table: &ObjectTable, k: K): &V { ofield::borrow(&table.id, k) @@ -44,7 +45,7 @@ module sui::object_table { #[syntax(index)] /// Mutably borrows the value associated with the key in the table `table: &mut ObjectTable`. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with /// that key `k: K`. public fun borrow_mut( table: &mut ObjectTable, @@ -54,7 +55,7 @@ module sui::object_table { } /// Removes the key-value pair in the table `table: &mut ObjectTable` and returns the value. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with /// that key `k: K`. public fun remove(table: &mut ObjectTable, k: K): V { let v = ofield::remove(&mut table.id, k); diff --git a/crates/iota-framework/packages/iota-framework/sources/package.move b/crates/iota-framework/packages/iota-framework/sources/package.move new file mode 100644 index 00000000000..a3cb1caee50 --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/sources/package.move @@ -0,0 +1,314 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Functions for operating on Move packages from within Move: +/// - Creating proof-of-publish objects from one-time witnesses +/// - Administering package upgrades through upgrade policies. +module iota::package { + use std::ascii::String; + use std::type_name; + use iota::types; + + /// Tried to create a `Publisher` using a type that isn't a + /// one-time witness. + const ENotOneTimeWitness: u64 = 0; + /// Tried to set a less restrictive policy than currently in place. + const ETooPermissive: u64 = 1; + /// This `UpgradeCap` has already authorized a pending upgrade. + const EAlreadyAuthorized: u64 = 2; + /// This `UpgradeCap` has not authorized an upgrade. + const ENotAuthorized: u64 = 3; + /// Trying to commit an upgrade to the wrong `UpgradeCap`. + const EWrongUpgradeCap: u64 = 4; + + /// Update any part of the package (function implementations, add new + /// functions or types, change dependencies) + const COMPATIBLE: u8 = 0; + /// Add new functions or types, or change dependencies, existing + /// functions can't change. + const ADDITIVE: u8 = 128; + /// Only be able to change dependencies. + const DEP_ONLY: u8 = 192; + + /// This type can only be created in the transaction that + /// generates a module, by consuming its one-time witness, so it + /// can be used to identify the address that published the package + /// a type originated from. + public struct Publisher has key, store { + id: UID, + package: String, + module_name: String, + } + + /// Capability controlling the ability to upgrade a package. + public struct UpgradeCap has key, store { + id: UID, + /// (Mutable) ID of the package that can be upgraded. + package: ID, + /// (Mutable) The number of upgrades that have been applied + /// successively to the original package. Initially 0. + version: u64, + /// What kind of upgrades are allowed. + policy: u8, + } + + /// Permission to perform a particular upgrade (for a fixed version of + /// the package, bytecode to upgrade with and transitive dependencies to + /// depend against). + /// + /// An `UpgradeCap` can only issue one ticket at a time, to prevent races + /// between concurrent updates or a change in its upgrade policy after + /// isiotang a ticket, so the ticket is a "Hot Potato" to preserve forward + /// progress. + public struct UpgradeTicket { + /// (Immutable) ID of the `UpgradeCap` this originated from. + cap: ID, + /// (Immutable) ID of the package that can be upgraded. + package: ID, + /// (Immutable) The policy regarding what kind of upgrade this ticket + /// permits. + policy: u8, + /// (Immutable) SHA256 digest of the bytecode and transitive + /// dependencies that will be used in the upgrade. + digest: vector, + } + + /// Issued as a result of a successful upgrade, containing the + /// information to be used to update the `UpgradeCap`. This is a "Hot + /// Potato" to ensure that it is used to update its `UpgradeCap` before + /// the end of the transaction that performed the upgrade. + public struct UpgradeReceipt { + /// (Immutable) ID of the `UpgradeCap` this originated from. + cap: ID, + /// (Immutable) ID of the package after it was upgraded. + package: ID, + } + + /// Claim a Publisher object. + /// Requires a One-Time-Witness to prove ownership. Due to this + /// constraint there can be only one Publisher object per module + /// but multiple per package (!). + public fun claim(otw: OTW, ctx: &mut TxContext): Publisher { + assert!(types::is_one_time_witness(&otw), ENotOneTimeWitness); + + let tyname = type_name::get_with_original_ids(); + + Publisher { + id: object::new(ctx), + package: tyname.get_address(), + module_name: tyname.get_module(), + } + } + + #[allow(lint(self_transfer))] + /// Claim a Publisher object and send it to transaction sender. + /// Since this function can only be called in the module initializer, + /// the sender is the publisher. + public fun claim_and_keep(otw: OTW, ctx: &mut TxContext) { + iota::transfer::public_transfer(claim(otw, ctx), ctx.sender()) + } + + /// Destroy a Publisher object effectively removing all privileges + /// associated with it. + public fun burn_publisher(self: Publisher) { + let Publisher { id, package: _, module_name: _ } = self; + id.delete(); + } + + /// Check whether type belongs to the same package as the publisher object. + public fun from_package(self: &Publisher): bool { + type_name::get_with_original_ids().get_address() == self.package + } + + /// Check whether a type belongs to the same module as the publisher object. + public fun from_module(self: &Publisher): bool { + let tyname = type_name::get_with_original_ids(); + + (tyname.get_address() == self.package) && (tyname.get_module() == self.module_name) + } + + /// Read the name of the module. + public fun published_module(self: &Publisher): &String { + &self.module_name + } + + /// Read the package address string. + public fun published_package(self: &Publisher): &String { + &self.package + } + + /// The ID of the package that this cap authorizes upgrades for. + /// Can be `0x0` if the cap cannot currently authorize an upgrade + /// because there is already a pending upgrade in the transaction. + /// Otherwise guaranteed to be the latest version of any given + /// package. + public fun upgrade_package(cap: &UpgradeCap): ID { + cap.package + } + + /// The most recent version of the package, increments by one for each + /// successfully applied upgrade. + public fun version(cap: &UpgradeCap): u64 { + cap.version + } + + /// The most permissive kind of upgrade currently supported by this + /// `cap`. + public fun upgrade_policy(cap: &UpgradeCap): u8 { + cap.policy + } + + /// The package that this ticket is authorized to upgrade + public fun ticket_package(ticket: &UpgradeTicket): ID { + ticket.package + } + + /// The kind of upgrade that this ticket authorizes. + public fun ticket_policy(ticket: &UpgradeTicket): u8 { + ticket.policy + } + + /// ID of the `UpgradeCap` that this `receipt` should be used to + /// update. + public fun receipt_cap(receipt: &UpgradeReceipt): ID { + receipt.cap + } + + /// ID of the package that was upgraded to: the latest version of + /// the package, as of the upgrade represented by this `receipt`. + public fun receipt_package(receipt: &UpgradeReceipt): ID { + receipt.package + } + + /// A hash of the package contents for the new version of the + /// package. This ticket only authorizes an upgrade to a package + /// that matches this digest. A package's contents are identified + /// by two things: + /// + /// - modules: [[u8]] a list of the package's module contents + /// - deps: [[u8; 32]] a list of 32 byte ObjectIDs of the + /// package's transitive dependencies + /// + /// A package's digest is calculated as: + /// + /// sha3_256(sort(modules ++ deps)) + public fun ticket_digest(ticket: &UpgradeTicket): &vector { + &ticket.digest + } + + /// Expose the constants representing various upgrade policies + public fun compatible_policy(): u8 { COMPATIBLE } + public fun additive_policy(): u8 { ADDITIVE } + public fun dep_only_policy(): u8 { DEP_ONLY } + + /// Restrict upgrades through this upgrade `cap` to just add code, or + /// change dependencies. + public entry fun only_additive_upgrades(cap: &mut UpgradeCap) { + cap.restrict(ADDITIVE) + } + + /// Restrict upgrades through this upgrade `cap` to just change + /// dependencies. + public entry fun only_dep_upgrades(cap: &mut UpgradeCap) { + cap.restrict(DEP_ONLY) + } + + /// Discard the `UpgradeCap` to make a package immutable. + public entry fun make_immutable(cap: UpgradeCap) { + let UpgradeCap { id, package: _, version: _, policy: _ } = cap; + id.delete(); + } + + /// Issue a ticket authorizing an upgrade to a particular new bytecode + /// (identified by its digest). A ticket will only be issued if one has + /// not already been issued, and if the `policy` requested is at least as + /// restrictive as the policy set out by the `cap`. + /// + /// The `digest` supplied and the `policy` will both be checked by + /// validators when running the upgrade. I.e. the bytecode supplied in + /// the upgrade must have a matching digest, and the changes relative to + /// the parent package must be compatible with the policy in the ticket + /// for the upgrade to succeed. + public fun authorize_upgrade( + cap: &mut UpgradeCap, + policy: u8, + digest: vector + ): UpgradeTicket { + let id_zero = @0x0.to_id(); + assert!(cap.package != id_zero, EAlreadyAuthorized); + assert!(policy >= cap.policy, ETooPermissive); + + let package = cap.package; + cap.package = id_zero; + + UpgradeTicket { + cap: object::id(cap), + package, + policy, + digest, + } + } + + /// Consume an `UpgradeReceipt` to update its `UpgradeCap`, finalizing + /// the upgrade. + public fun commit_upgrade( + cap: &mut UpgradeCap, + receipt: UpgradeReceipt, + ) { + let UpgradeReceipt { cap: cap_id, package } = receipt; + + assert!(object::id(cap) == cap_id, EWrongUpgradeCap); + assert!(cap.package.to_address() == @0x0, ENotAuthorized); + + cap.package = package; + cap.version = cap.version + 1; + } + + #[test_only] + /// Test-only function to claim a Publisher object bypassing OTW check. + public fun test_claim(_: OTW, ctx: &mut TxContext): Publisher { + let tyname = type_name::get_with_original_ids(); + + Publisher { + id: object::new(ctx), + package: tyname.get_address(), + module_name: tyname.get_module(), + } + } + + #[test_only] + /// Test-only function to simulate publishing a package at address + /// `ID`, to create an `UpgradeCap`. + public fun test_publish(package: ID, ctx: &mut TxContext): UpgradeCap { + UpgradeCap { + id: object::new(ctx), + package, + version: 1, + policy: COMPATIBLE, + } + } + + #[test_only] + /// Test-only function that takes the role of the actual `Upgrade` + /// command, converting the ticket for the pending upgrade to a + /// receipt for a completed upgrade. + public fun test_upgrade(ticket: UpgradeTicket): UpgradeReceipt { + let UpgradeTicket { cap, package, policy: _, digest: _ } = ticket; + + // Generate a fake package ID for the upgraded package by + // hashing the existing package and cap ID. + let mut data = cap.to_bytes(); + data.append(package.to_bytes()); + let package = object::id_from_bytes(iota::hash::blake2b256(&data)); + + UpgradeReceipt { + cap, package + } + } + + fun restrict(cap: &mut UpgradeCap, policy: u8) { + assert!(cap.policy <= policy, ETooPermissive); + cap.policy = policy; + } +} diff --git a/crates/sui-framework/packages/sui-framework/sources/pay.move b/crates/iota-framework/packages/iota-framework/sources/pay.move similarity index 94% rename from crates/sui-framework/packages/sui-framework/sources/pay.move rename to crates/iota-framework/packages/iota-framework/sources/pay.move index a13bab88c68..6775411e7e3 100644 --- a/crates/sui-framework/packages/sui-framework/sources/pay.move +++ b/crates/iota-framework/packages/iota-framework/sources/pay.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -/// This module provides handy functionality for wallets and `sui::Coin` management. -module sui::pay { - use sui::coin::Coin; +/// This module provides handy functionality for wallets and `iota::Coin` management. +module iota::pay { + use iota::coin::Coin; /// For when empty vector is supplied into join function. const ENoCoins: u64 = 0; diff --git a/crates/sui-framework/packages/sui-framework/sources/priority_queue.move b/crates/iota-framework/packages/iota-framework/sources/priority_queue.move similarity index 98% rename from crates/sui-framework/packages/sui-framework/sources/priority_queue.move rename to crates/iota-framework/packages/iota-framework/sources/priority_queue.move index 20061229bce..8f92ab4d842 100644 --- a/crates/sui-framework/packages/sui-framework/sources/priority_queue.move +++ b/crates/iota-framework/packages/iota-framework/sources/priority_queue.move @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Priority queue implemented using a max heap. -module sui::priority_queue { +module iota::priority_queue { /// For when heap is empty and there's no data to pop. const EPopFromEmptyHeap: u64 = 0; diff --git a/crates/iota-framework/packages/iota-framework/sources/prover.move b/crates/iota-framework/packages/iota-framework/sources/prover.move new file mode 100644 index 00000000000..31ee3156ab4 --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/sources/prover.move @@ -0,0 +1,6 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota::prover { +} diff --git a/crates/iota-framework/packages/iota-framework/sources/random.move b/crates/iota-framework/packages/iota-framework/sources/random.move new file mode 100644 index 00000000000..89e83a77309 --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/sources/random.move @@ -0,0 +1,310 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// This module provides functionality for generating secure randomness. +module iota::random { + use std::bcs; + use iota::hmac::hmac_sha3_256; + use iota::versioned::{Self, Versioned}; + + // Sender is not @0x0 the system address. + const ENotSystemAddress: u64 = 0; + const EWrongInnerVersion: u64 = 1; + const EInvalidRandomnessUpdate: u64 = 2; + const EInvalidRange: u64 = 3; + const EInvalidLength: u64 = 4; + + const CURRENT_VERSION: u64 = 1; + const RAND_OUTPUT_LEN: u16 = 32; + const U16_MAX: u64 = 0xFFFF; + + /// Singleton shared object which stores the global randomness state. + /// The actual state is stored in a versioned inner field. + public struct Random has key { + id: UID, + // The inner object must never be accessed outside this module as it could be used for accessing global + // randomness via deserialization of RandomInner. + inner: Versioned, + } + + public struct RandomInner has store { + version: u64, + epoch: u64, + randomness_round: u64, + random_bytes: vector, + } + + #[allow(unused_function)] + /// Create and share the Random object. This function is called exactly once, when + /// the Random object is first created. + /// Can only be called by genesis or change_epoch transactions. + fun create(ctx: &mut TxContext) { + assert!(ctx.sender() == @0x0, ENotSystemAddress); + + let version = CURRENT_VERSION; + + let inner = RandomInner { + version, + epoch: ctx.epoch(), + randomness_round: 0, + random_bytes: vector[], + }; + + let self = Random { + id: object::randomness_state(), + inner: versioned::create(version, inner, ctx), + }; + transfer::share_object(self); + } + + #[test_only] + public fun create_for_testing(ctx: &mut TxContext) { + create(ctx); + } + + fun load_inner_mut( + self: &mut Random, + ): &mut RandomInner { + let version = versioned::version(&self.inner); + + // Replace this with a lazy update function when we add a new version of the inner object. + assert!(version == CURRENT_VERSION, EWrongInnerVersion); + let inner: &mut RandomInner = versioned::load_value_mut(&mut self.inner); + assert!(inner.version == version, EWrongInnerVersion); + inner + } + + fun load_inner( + self: &Random, + ): &RandomInner { + let version = versioned::version(&self.inner); + + // Replace this with a lazy update function when we add a new version of the inner object. + assert!(version == CURRENT_VERSION, EWrongInnerVersion); + let inner: &RandomInner = versioned::load_value(&self.inner); + assert!(inner.version == version, EWrongInnerVersion); + inner + } + + #[allow(unused_function)] + /// Record new randomness. Called when executing the RandomnessStateUpdate system + /// transaction. + fun update_randomness_state( + self: &mut Random, + new_round: u64, + new_bytes: vector, + ctx: &TxContext, + ) { + // Validator will make a special system call with sender set as 0x0. + assert!(ctx.sender() == @0x0, ENotSystemAddress); + + // Randomness should only be incremented. + let epoch = ctx.epoch(); + let inner = self.load_inner_mut(); + if (inner.randomness_round == 0 && inner.epoch == 0 && inner.random_bytes.is_empty()) { + // First update should be for round zero. + assert!(new_round == 0, EInvalidRandomnessUpdate); + } else { + // Subsequent updates should either increase epoch or increment randomness_round. + // Note that epoch may increase by more than 1 if an epoch is completed without + // randomness ever being generated in that epoch. + assert!( + (epoch > inner.epoch && new_round == 0) || + (new_round == inner.randomness_round + 1), + EInvalidRandomnessUpdate + ); + }; + + inner.epoch = ctx.epoch(); + inner.randomness_round = new_round; + inner.random_bytes = new_bytes; + } + + #[test_only] + public fun update_randomness_state_for_testing( + self: &mut Random, + new_round: u64, + new_bytes: vector, + ctx: &TxContext, + ) { + self.update_randomness_state(new_round, new_bytes, ctx); + } + + + /// Unique randomness generator, derived from the global randomness. + public struct RandomGenerator has drop { + seed: vector, + counter: u16, + buffer: vector, + } + + /// Create a generator. Can be used to derive up to MAX_U16 * 32 random bytes. + public fun new_generator(r: &Random, ctx: &mut TxContext): RandomGenerator { + let inner = load_inner(r); + let seed = hmac_sha3_256( + &inner.random_bytes, + &ctx.fresh_object_address().to_bytes() + ); + RandomGenerator { seed, counter: 0, buffer: vector[] } + } + + // Get the next block of random bytes. + fun derive_next_block(g: &mut RandomGenerator): vector { + g.counter = g.counter + 1; + hmac_sha3_256(&g.seed, &bcs::to_bytes(&g.counter)) + } + + // Fill the generator's buffer with 32 random bytes. + fun fill_buffer(g: &mut RandomGenerator) { + let next_block = derive_next_block(g); + vector::append(&mut g.buffer, next_block); + } + + /// Generate n random bytes. + public fun generate_bytes(g: &mut RandomGenerator, num_of_bytes: u16): vector { + let mut result = vector[]; + // Append RAND_OUTPUT_LEN size buffers directly without going through the generator's buffer. + let mut num_of_blocks = num_of_bytes / RAND_OUTPUT_LEN; + while (num_of_blocks > 0) { + vector::append(&mut result, derive_next_block(g)); + num_of_blocks = num_of_blocks - 1; + }; + // Fill the generator's buffer if needed. + let num_of_bytes = num_of_bytes as u64; + if (vector::length(&g.buffer) < (num_of_bytes - vector::length(&result))) { + fill_buffer(g); + }; + // Take remaining bytes from the generator's buffer. + while (vector::length(&result) < num_of_bytes) { + vector::push_back(&mut result, vector::pop_back(&mut g.buffer)); + }; + result + } + + // Helper function that extracts the given number of bytes from the random generator and returns it as u256. + // Assumes that the caller has already checked that num_of_bytes is valid. + // TODO: Replace with a macro when we have support for it. + fun u256_from_bytes(g: &mut RandomGenerator, num_of_bytes: u8): u256 { + if (vector::length(&g.buffer) < num_of_bytes as u64) { + fill_buffer(g); + }; + let mut result: u256 = 0; + let mut i = 0; + while (i < num_of_bytes) { + let byte = vector::pop_back(&mut g.buffer); + result = (result << 8) + (byte as u256); + i = i + 1; + }; + result + } + + /// Generate a u256. + public fun generate_u256(g: &mut RandomGenerator): u256 { + u256_from_bytes(g, 32) + } + + /// Generate a u128. + public fun generate_u128(g: &mut RandomGenerator): u128 { + u256_from_bytes(g, 16) as u128 + } + + /// Generate a u64. + public fun generate_u64(g: &mut RandomGenerator): u64 { + u256_from_bytes(g, 8) as u64 + } + + /// Generate a u32. + public fun generate_u32(g: &mut RandomGenerator): u32 { + u256_from_bytes(g, 4) as u32 + } + + /// Generate a u16. + public fun generate_u16(g: &mut RandomGenerator): u16 { + u256_from_bytes(g, 2) as u16 + } + + /// Generate a u8. + public fun generate_u8(g: &mut RandomGenerator): u8 { + u256_from_bytes(g, 1) as u8 + } + + /// Generate a boolean. + public fun generate_bool(g: &mut RandomGenerator): bool { + (u256_from_bytes(g, 1) & 1) == 1 + } + + // Helper function to generate a random u128 in [min, max] using a random number with num_of_bytes bytes. + // Assumes that the caller verified the inputs, and uses num_of_bytes to control the bias (e.g., 8 bytes larger + // than the actual type used by the caller function to limit the bias by 2^{-64}). + // TODO: Replace with a macro when we have support for it. + fun u128_in_range(g: &mut RandomGenerator, min: u128, max: u128, num_of_bytes: u8): u128 { + assert!(min <= max, EInvalidRange); + if (min == max) { + return min + }; + // Pick a random number in [0, max - min] by generating a random number that is larger than max-min, and taking + // the modulo of the random number by the range size. Then add the min to the result to get a number in + // [min, max]. + let range_size = (max - min) as u256 + 1; + let rand = u256_from_bytes(g, num_of_bytes); + min + (rand % range_size as u128) + } + + /// Generate a random u128 in [min, max] (with a bias of 2^{-64}). + public fun generate_u128_in_range(g: &mut RandomGenerator, min: u128, max: u128): u128 { + u128_in_range(g, min, max, 24) + } + + //// Generate a random u64 in [min, max] (with a bias of 2^{-64}). + public fun generate_u64_in_range(g: &mut RandomGenerator, min: u64, max: u64): u64 { + u128_in_range(g, min as u128, max as u128, 16) as u64 + } + + /// Generate a random u32 in [min, max] (with a bias of 2^{-64}). + public fun generate_u32_in_range(g: &mut RandomGenerator, min: u32, max: u32): u32 { + u128_in_range(g, min as u128, max as u128, 12) as u32 + } + + /// Generate a random u16 in [min, max] (with a bias of 2^{-64}). + public fun generate_u16_in_range(g: &mut RandomGenerator, min: u16, max: u16): u16 { + u128_in_range(g, min as u128, max as u128, 10) as u16 + } + + /// Generate a random u8 in [min, max] (with a bias of 2^{-64}). + public fun generate_u8_in_range(g: &mut RandomGenerator, min: u8, max: u8): u8 { + u128_in_range(g, min as u128, max as u128, 9) as u8 + } + + /// Shuffle a vector using the random generator (Fisher–Yates/Knuth shuffle). + public fun shuffle(g: &mut RandomGenerator, v: &mut vector) { + let n = vector::length(v); + if (n == 0) { + return + }; + assert!(n <= U16_MAX, EInvalidLength); + let n = n as u16; + let mut i: u16 = 0; + let end = n - 1; + while (i < end) { + let j = generate_u16_in_range(g, i, end); + vector::swap(v, i as u64, j as u64); + i = i + 1; + }; + } + + #[test_only] + public fun generator_seed(r: &RandomGenerator): &vector { + &r.seed + } + + #[test_only] + public fun generator_counter(r: &RandomGenerator): u16 { + r.counter + } + + #[test_only] + public fun generator_buffer(r: &RandomGenerator): &vector { + &r.buffer + } +} diff --git a/crates/sui-framework/packages/sui-framework/sources/table.move b/crates/iota-framework/packages/iota-framework/sources/table.move similarity index 87% rename from crates/sui-framework/packages/sui-framework/sources/table.move rename to crates/iota-framework/packages/iota-framework/sources/table.move index 406af388c5a..bf2bcc6fb24 100644 --- a/crates/sui-framework/packages/sui-framework/sources/table.move +++ b/crates/iota-framework/packages/iota-framework/sources/table.move @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// A table is a map-like collection. But unlike a traditional collection, it's keys and values are -/// not stored within the `Table` value, but instead are stored using Sui's object system. The +/// not stored within the `Table` value, but instead are stored using Iota's object system. The /// `Table` struct acts only as a handle into the object system to retrieve those keys and values. /// Note that this means that `Table` values with exactly the same key-value mapping will not be /// equal, with `==`, at runtime. For example @@ -16,8 +17,8 @@ /// // table1 does not equal table2, despite having the same entries /// assert!(&table1 != &table2, 0); /// ``` -module sui::table { - use sui::dynamic_field as field; +module iota::table { + use iota::dynamic_field as field; // Attempted to destroy a non-empty table const ETableNotEmpty: u64 = 0; @@ -38,7 +39,7 @@ module sui::table { } /// Adds a key-value pair to the table `table: &mut Table` - /// Aborts with `sui::dynamic_field::EFieldAlreadyExists` if the table already has an entry with + /// Aborts with `iota::dynamic_field::EFieldAlreadyExists` if the table already has an entry with /// that key `k: K`. public fun add(table: &mut Table, k: K, v: V) { field::add(&mut table.id, k, v); @@ -47,7 +48,7 @@ module sui::table { #[syntax(index)] /// Immutable borrows the value associated with the key in the table `table: &Table`. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with /// that key `k: K`. public fun borrow(table: &Table, k: K): &V { field::borrow(&table.id, k) @@ -55,14 +56,14 @@ module sui::table { #[syntax(index)] /// Mutably borrows the value associated with the key in the table `table: &mut Table`. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with /// that key `k: K`. public fun borrow_mut(table: &mut Table, k: K): &mut V { field::borrow_mut(&mut table.id, k) } /// Removes the key-value pair in the table `table: &mut Table` and returns the value. - /// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with + /// Aborts with `iota::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with /// that key `k: K`. public fun remove(table: &mut Table, k: K): V { let v = field::remove(&mut table.id, k); diff --git a/crates/sui-framework/packages/sui-framework/sources/table_vec.move b/crates/iota-framework/packages/iota-framework/sources/table_vec.move similarity index 96% rename from crates/sui-framework/packages/sui-framework/sources/table_vec.move rename to crates/iota-framework/packages/iota-framework/sources/table_vec.move index 9ae8b9c1a2a..5bf6eabbb49 100644 --- a/crates/sui-framework/packages/sui-framework/sources/table_vec.move +++ b/crates/iota-framework/packages/iota-framework/sources/table_vec.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// A basic scalable vector library implemented using `Table`. -module sui::table_vec { - use sui::table::{Self, Table}; +module iota::table_vec { + use iota::table::{Self, Table}; public struct TableVec has store { /// The contents of the table vector. @@ -106,7 +107,7 @@ module sui::table_vec { #[test] fun test_swap() { - let ctx = &mut sui::tx_context::dummy(); + let ctx = &mut iota::tx_context::dummy(); let mut tv = singleton(0, ctx); tv.push_back(1); tv.push_back(2); diff --git a/crates/sui-framework/packages/sui-framework/sources/test/test_random.move b/crates/iota-framework/packages/iota-framework/sources/test/test_random.move similarity index 98% rename from crates/sui-framework/packages/sui-framework/sources/test/test_random.move rename to crates/iota-framework/packages/iota-framework/sources/test/test_random.move index 1b1ab33faaa..099794c82d2 100644 --- a/crates/sui-framework/packages/sui-framework/sources/test/test_random.move +++ b/crates/iota-framework/packages/iota-framework/sources/test/test_random.move @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::test_random { +module iota::test_random { use std::hash; // Internally, the pseudorandom generator uses a hash chain over Sha3-256 diff --git a/crates/sui-framework/packages/sui-framework/sources/test/test_scenario.move b/crates/iota-framework/packages/iota-framework/sources/test/test_scenario.move similarity index 97% rename from crates/sui-framework/packages/sui-framework/sources/test/test_scenario.move rename to crates/iota-framework/packages/iota-framework/sources/test/test_scenario.move index 346731d63f5..9f1ccf2bea9 100644 --- a/crates/sui-framework/packages/sui-framework/sources/test/test_scenario.move +++ b/crates/iota-framework/packages/iota-framework/sources/test/test_scenario.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::test_scenario { - use sui::vec_map::VecMap; +module iota::test_scenario { + use iota::vec_map::VecMap; #[allow(unused_const)] /// the transaction failed when generating these effects. For example, a circular ownership @@ -28,7 +29,7 @@ module sui::test_scenario { /// Object of that ID was not found in that inventory. It was possibly already taken const EObjectNotFound: u64 = 4; - /// Utility for mocking a multi-transaction Sui execution in a single Move procedure. + /// Utility for mocking a multi-transaction Iota execution in a single Move procedure. /// A `Scenario` maintains a view of the global object pool built up by the execution. /// These objects can be accessed via functions like `take_from_sender`, which gives the /// transaction sender access to objects in (only) their inventory. @@ -246,7 +247,7 @@ module sui::test_scenario { public fun return_to_address(account: address, t: T) { let id = object::id(&t); assert!(was_taken_from_address(account, id), ECantReturnObject); - sui::transfer::transfer_impl(t, account) + iota::transfer::transfer_impl(t, account) } /// Returns true if the object with `ID` id was in the inventory for `account` @@ -315,7 +316,7 @@ module sui::test_scenario { public fun return_immutable(t: T) { let id = object::id(&t); assert!(was_taken_immutable(id), ECantReturnObject); - sui::transfer::freeze_object_impl(t) + iota::transfer::freeze_object_impl(t) } /// Returns true if the object with `ID` id was an immutable object in the global inventory @@ -347,7 +348,7 @@ module sui::test_scenario { public fun return_shared(t: T) { let id = object::id(&t); assert!(was_taken_shared(id), ECantReturnObject); - sui::transfer::share_object_impl(t) + iota::transfer::share_object_impl(t) } /// Returns true if the object with `ID` id was an shared object in the global inventory diff --git a/crates/sui-framework/packages/sui-framework/sources/test/test_utils.move b/crates/iota-framework/packages/iota-framework/sources/test/test_utils.move similarity index 89% rename from crates/sui-framework/packages/sui-framework/sources/test/test_utils.move rename to crates/iota-framework/packages/iota-framework/sources/test/test_utils.move index 4e0c56b4abf..a91f75c8400 100644 --- a/crates/sui-framework/packages/sui-framework/sources/test/test_utils.move +++ b/crates/iota-framework/packages/iota-framework/sources/test/test_utils.move @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::test_utils { +module iota::test_utils { public fun assert_eq(t1: T, t2: T) { assert_ref_eq(&t1, &t2) } diff --git a/crates/sui-framework/packages/sui-framework/sources/token.move b/crates/iota-framework/packages/iota-framework/sources/token.move similarity index 98% rename from crates/sui-framework/packages/sui-framework/sources/token.move rename to crates/iota-framework/packages/iota-framework/sources/token.move index bdc1b63fac1..a471789ed30 100644 --- a/crates/sui-framework/packages/sui-framework/sources/token.move +++ b/crates/iota-framework/packages/iota-framework/sources/token.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// The Token module which implements a Closed Loop Token with a configurable @@ -10,7 +11,7 @@ /// companion to existing open-loop (`Coin`) systems. /// /// ``` -/// Module: sui::balance sui::coin sui::token +/// Module: iota::balance iota::coin iota::token /// Main type: Balance Coin Token /// Capability: Supply <----> TreasuryCap <----> TreasuryCap /// Abilities: store key + store key @@ -19,15 +20,15 @@ /// The Token system allows for fine-grained control over the actions performed /// on the token. And hence it is highly suitable for applications that require /// control over the currency which a simple open-loop system can't provide. -module sui::token { +module iota::token { use std::string::String; use std::type_name::{Self, TypeName}; - use sui::coin::{Coin, TreasuryCap}; - use sui::balance::{Self, Balance}; - use sui::vec_map::{Self, VecMap}; - use sui::vec_set::{Self, VecSet}; - use sui::dynamic_field as df; - use sui::event; + use iota::coin::{Coin, TreasuryCap}; + use iota::balance::{Self, Balance}; + use iota::vec_map::{Self, VecMap}; + use iota::vec_set::{Self, VecSet}; + use iota::dynamic_field as df; + use iota::event; /// The action is not allowed (defined) in the policy. const EUnknownAction: u64 = 0; diff --git a/crates/iota-framework/packages/iota-framework/sources/transfer.move b/crates/iota-framework/packages/iota-framework/sources/transfer.move new file mode 100644 index 00000000000..c4bf3c41aa0 --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/sources/transfer.move @@ -0,0 +1,140 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_const)] +module iota::transfer { + + + /* #[test_only] */ + /* friend iota::test_scenario; */ + + /// This represents the ability to `receive` an object of type `T`. + /// This type is ephemeral per-transaction and cannot be stored on-chain. + /// This does not represent the obligation to receive the object that it + /// references, but simply the ability to receive the object with object ID + /// `id` at version `version` if you can prove mutable access to the parent + /// object during the transaction. + /// Internals of this struct are opaque outside this module. + public struct Receiving has drop { + id: ID, + version: u64, + } + + /// Shared an object that was previously created. Shared objects must currently + /// be constructed in the transaction they are created. + const ESharedNonNewObject: u64 = 0; + + #[allow(unused_const)] + /// Serialization of the object failed. + const EBCSSerializationFailure: u64 = 1; + + #[allow(unused_const)] + /// The object being received is not of the expected type. + const EReceivingObjectTypeMismatch: u64 = 2; + + #[allow(unused_const)] + /// Represents both the case where the object does not exist and the case where the object is not + /// able to be accessed through the parent that is passed-in. + const EUnableToReceiveObject: u64 = 3; + + #[allow(unused_const)] + /// Shared object operations such as wrapping, freezing, and converting to owned are not allowed. + const ESharedObjectOperationNotSupported: u64 = 4; + + + /// Transfer ownership of `obj` to `recipient`. `obj` must have the `key` attribute, + /// which (in turn) ensures that `obj` has a globally unique ID. Note that if the recipient + /// address represents an object ID, the `obj` sent will be inaccessible after the transfer + /// (though they will be retrievable at a future date once new features are added). + /// This function has custom rules performed by the Iota Move bytecode verifier that ensures + /// that `T` is an object defined in the module where `transfer` is invoked. Use + /// `public_transfer` to transfer an object with `store` outside of its module. + public fun transfer(obj: T, recipient: address) { + transfer_impl(obj, recipient) + } + + /// Transfer ownership of `obj` to `recipient`. `obj` must have the `key` attribute, + /// which (in turn) ensures that `obj` has a globally unique ID. Note that if the recipient + /// address represents an object ID, the `obj` sent will be inaccessible after the transfer + /// (though they will be retrievable at a future date once new features are added). + /// The object must have `store` to be transferred outside of its module. + public fun public_transfer(obj: T, recipient: address) { + transfer_impl(obj, recipient) + } + + /// Freeze `obj`. After freezing `obj` becomes immutable and can no longer be transferred or + /// mutated. + /// This function has custom rules performed by the Iota Move bytecode verifier that ensures + /// that `T` is an object defined in the module where `freeze_object` is invoked. Use + /// `public_freeze_object` to freeze an object with `store` outside of its module. + public fun freeze_object(obj: T) { + freeze_object_impl(obj) + } + + /// Freeze `obj`. After freezing `obj` becomes immutable and can no longer be transferred or + /// mutated. + /// The object must have `store` to be frozen outside of its module. + public fun public_freeze_object(obj: T) { + freeze_object_impl(obj) + } + + /// Turn the given object into a mutable shared object that everyone can access and mutate. + /// This is irreversible, i.e. once an object is shared, it will stay shared forever. + /// Aborts with `ESharedNonNewObject` of the object being shared was not created in this + /// transaction. This restriction may be relaxed in the future. + /// This function has custom rules performed by the Iota Move bytecode verifier that ensures + /// that `T` is an object defined in the module where `share_object` is invoked. Use + /// `public_share_object` to share an object with `store` outside of its module. + public fun share_object(obj: T) { + share_object_impl(obj) + } + + /// Turn the given object into a mutable shared object that everyone can access and mutate. + /// This is irreversible, i.e. once an object is shared, it will stay shared forever. + /// Aborts with `ESharedNonNewObject` of the object being shared was not created in this + /// transaction. This restriction may be relaxed in the future. + /// The object must have `store` to be shared outside of its module. + public fun public_share_object(obj: T) { + share_object_impl(obj) + } + + /// Given mutable (i.e., locked) access to the `parent` and a `Receiving` argument + /// referencing an object of type `T` owned by `parent` use the `to_receive` + /// argument to receive and return the referenced owned object of type `T`. + /// This function has custom rules performed by the Iota Move bytecode verifier that ensures + /// that `T` is an object defined in the module where `receive` is invoked. Use + /// `public_receive` to receivne an object with `store` outside of its module. + public fun receive(parent: &mut UID, to_receive: Receiving): T { + let Receiving { + id, + version, + } = to_receive; + receive_impl(parent.to_address(), id, version) + } + + /// Given mutable (i.e., locked) access to the `parent` and a `Receiving` argument + /// referencing an object of type `T` owned by `parent` use the `to_receive` + /// argument to receive and return the referenced owned object of type `T`. + /// The object must have `store` to be received outside of its defining module. + public fun public_receive(parent: &mut UID, to_receive: Receiving): T { + let Receiving { + id, + version, + } = to_receive; + receive_impl(parent.to_address(), id, version) + } + + /// Return the object ID that the given `Receiving` argument references. + public fun receiving_object_id(receiving: &Receiving): ID { + receiving.id + } + + public(package) native fun freeze_object_impl(obj: T); + + public(package) native fun share_object_impl(obj: T); + + public(package) native fun transfer_impl(obj: T, recipient: address); + + native fun receive_impl(parent: address, to_receive: ID, version: u64): T; +} diff --git a/crates/sui-framework/packages/sui-framework/sources/tx_context.move b/crates/iota-framework/packages/iota-framework/sources/tx_context.move similarity index 98% rename from crates/sui-framework/packages/sui-framework/sources/tx_context.move rename to crates/iota-framework/packages/iota-framework/sources/tx_context.move index 56111acecdc..0d539c0eeb2 100644 --- a/crates/sui-framework/packages/sui-framework/sources/tx_context.move +++ b/crates/iota-framework/packages/iota-framework/sources/tx_context.move @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui::tx_context { +module iota::tx_context { #[test_only] /// Number of bytes in an tx hash (which will be the transaction digest) diff --git a/crates/iota-framework/packages/iota-framework/sources/types.move b/crates/iota-framework/packages/iota-framework/sources/types.move new file mode 100644 index 00000000000..4edc5dd3909 --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/sources/types.move @@ -0,0 +1,12 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Iota types helpers and utilities +module iota::types { + // === one-time witness === + + /// Tests if the argument type is a one-time witness, that is a type with only one instantiation + /// across the entire code base. + public native fun is_one_time_witness(_: &T): bool; +} diff --git a/crates/sui-framework/packages/sui-framework/sources/url.move b/crates/iota-framework/packages/iota-framework/sources/url.move similarity index 92% rename from crates/sui-framework/packages/sui-framework/sources/url.move rename to crates/iota-framework/packages/iota-framework/sources/url.move index e4bfb272bf5..03bd39543ef 100644 --- a/crates/sui-framework/packages/sui-framework/sources/url.move +++ b/crates/iota-framework/packages/iota-framework/sources/url.move @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// URL: standard Uniform Resource Locator string -module sui::url { +module iota::url { use std::ascii::String; /// Standard Uniform Resource Locator (URL) string. diff --git a/crates/sui-framework/packages/sui-framework/sources/vec_map.move b/crates/iota-framework/packages/iota-framework/sources/vec_map.move similarity index 99% rename from crates/sui-framework/packages/sui-framework/sources/vec_map.move rename to crates/iota-framework/packages/iota-framework/sources/vec_map.move index 43cb6c8a4f7..ca095ce11c8 100644 --- a/crates/sui-framework/packages/sui-framework/sources/vec_map.move +++ b/crates/iota-framework/packages/iota-framework/sources/vec_map.move @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui::vec_map { +module iota::vec_map { /// This key already exists in the map const EKeyAlreadyExists: u64 = 0; diff --git a/crates/sui-framework/packages/sui-framework/sources/vec_set.move b/crates/iota-framework/packages/iota-framework/sources/vec_set.move similarity index 97% rename from crates/sui-framework/packages/sui-framework/sources/vec_set.move rename to crates/iota-framework/packages/iota-framework/sources/vec_set.move index 611eb7a228b..cb77fa4d920 100644 --- a/crates/sui-framework/packages/sui-framework/sources/vec_set.move +++ b/crates/iota-framework/packages/iota-framework/sources/vec_set.move @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui::vec_set { +module iota::vec_set { /// This key already exists in the map const EKeyAlreadyExists: u64 = 0; diff --git a/crates/sui-framework/packages/sui-framework/sources/versioned.move b/crates/iota-framework/packages/iota-framework/sources/versioned.move similarity index 96% rename from crates/sui-framework/packages/sui-framework/sources/versioned.move rename to crates/iota-framework/packages/iota-framework/sources/versioned.move index ae916fcdef8..bebd59f9d61 100644 --- a/crates/sui-framework/packages/sui-framework/sources/versioned.move +++ b/crates/iota-framework/packages/iota-framework/sources/versioned.move @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui::versioned { - use sui::dynamic_field; +module iota::versioned { + use iota::dynamic_field; /// Failed to upgrade the inner object due to invalid capability or new version. const EInvalidUpgrade: u64 = 0; diff --git a/crates/sui-framework/packages/sui-framework/tests/address_tests.move b/crates/iota-framework/packages/iota-framework/tests/address_tests.move similarity index 94% rename from crates/sui-framework/packages/sui-framework/tests/address_tests.move rename to crates/iota-framework/packages/iota-framework/tests/address_tests.move index 187ef029713..2e19620640d 100644 --- a/crates/sui-framework/packages/sui-framework/tests/address_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/address_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::address_tests { - use sui::address; +module iota::address_tests { + use iota::address; #[test] fun from_bytes_ok() { @@ -17,7 +18,7 @@ module sui::address_tests { } #[test] - #[expected_failure(abort_code = sui::address::EAddressParseError)] + #[expected_failure(abort_code = iota::address::EAddressParseError)] fun from_bytes_too_few_bytes() { let mut ctx = tx_context::dummy(); let uid = object::new(&mut ctx); @@ -31,7 +32,7 @@ module sui::address_tests { } #[test] - #[expected_failure(abort_code = sui::address::EAddressParseError)] + #[expected_failure(abort_code = iota::address::EAddressParseError)] fun test_from_bytes_too_many_bytes() { let mut ctx = tx_context::dummy(); let uid = object::new(&mut ctx); @@ -117,19 +118,19 @@ module sui::address_tests { } #[test] - #[expected_failure(abort_code = sui::address::EAddressParseError)] + #[expected_failure(abort_code = iota::address::EAddressParseError)] fun from_ascii_string_too_short() { address::from_ascii_bytes(&b"0"); } #[test] - #[expected_failure(abort_code = sui::address::EAddressParseError)] + #[expected_failure(abort_code = iota::address::EAddressParseError)] fun from_ascii_string_too_long() { address::from_ascii_bytes(&b"00000000000000000000000000000000000000000000000000000000000000001"); } #[test] - #[expected_failure(abort_code = sui::address::EAddressParseError)] + #[expected_failure(abort_code = iota::address::EAddressParseError)] fun from_ascii_string_non_hex_character() { address::from_ascii_bytes(&b"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffg"); } diff --git a/crates/sui-framework/packages/sui-framework/tests/authenticator_state_tests.move b/crates/iota-framework/packages/iota-framework/tests/authenticator_state_tests.move similarity index 98% rename from crates/sui-framework/packages/sui-framework/tests/authenticator_state_tests.move rename to crates/iota-framework/packages/iota-framework/tests/authenticator_state_tests.move index 92418b17549..084c72b5291 100644 --- a/crates/sui-framework/packages/sui-framework/tests/authenticator_state_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/authenticator_state_tests.move @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] #[allow(unused_use)] -module sui::authenticator_state_tests { +module iota::authenticator_state_tests { use std::string::String; - use sui::test_scenario; - use sui::authenticator_state::{ + use iota::test_scenario; + use iota::authenticator_state::{ Self, AuthenticatorState, create_active_jwk, diff --git a/crates/sui-framework/packages/sui-framework/tests/bag_tests.move b/crates/iota-framework/packages/iota-framework/tests/bag_tests.move similarity index 84% rename from crates/sui-framework/packages/sui-framework/tests/bag_tests.move rename to crates/iota-framework/packages/iota-framework/tests/bag_tests.move index a821e8dab3a..b1667177720 100644 --- a/crates/sui-framework/packages/sui-framework/tests/bag_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/bag_tests.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::bag_tests { - use sui::bag::Self; - use sui::test_scenario; +module iota::bag_tests { + use iota::bag::Self; + use iota::test_scenario; #[test] fun simple_all_functions() { @@ -37,7 +38,7 @@ module sui::bag_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldAlreadyExists)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldAlreadyExists)] fun add_duplicate() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -48,7 +49,7 @@ module sui::bag_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldAlreadyExists)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldAlreadyExists)] fun add_duplicate_mismatched_type() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -59,7 +60,7 @@ module sui::bag_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun borrow_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -69,7 +70,7 @@ module sui::bag_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldTypeMismatch)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldTypeMismatch)] fun borrow_wrong_type() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -80,7 +81,7 @@ module sui::bag_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun borrow_mut_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -90,7 +91,7 @@ module sui::bag_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldTypeMismatch)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldTypeMismatch)] fun borrow_mut_wrong_type() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -101,7 +102,7 @@ module sui::bag_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun remove_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -111,7 +112,7 @@ module sui::bag_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldTypeMismatch)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldTypeMismatch)] fun remove_wrong_type() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -122,7 +123,7 @@ module sui::bag_tests { } #[test] - #[expected_failure(abort_code = sui::bag::EBagNotEmpty)] + #[expected_failure(abort_code = iota::bag::EBagNotEmpty)] fun destroy_non_empty() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); diff --git a/crates/iota-framework/packages/iota-framework/tests/balance_tests.move b/crates/iota-framework/packages/iota-framework/tests/balance_tests.move new file mode 100644 index 00000000000..7027972b259 --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/tests/balance_tests.move @@ -0,0 +1,39 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module iota::coin_balance_tests { + use iota::test_scenario; + use iota::pay; + use iota::coin; + use iota::balance; + use iota::iota::IOTA; + + #[test] + fun type_morphing() { + let mut scenario = test_scenario::begin(@0x1); + + let balance = balance::zero(); + let coin = balance.into_coin(scenario.ctx()); + let balance = coin.into_balance(); + + balance.destroy_zero(); + + let mut coin = coin::mint_for_testing(100, scenario.ctx()); + let balance_mut = coin::balance_mut(&mut coin); + let sub_balance = balance_mut.split(50); + + assert!(sub_balance.value() == 50, 0); + assert!(coin.value() == 50, 0); + + let mut balance = coin.into_balance(); + balance.join(sub_balance); + + assert!(balance.value() == 100, 0); + + let coin = balance.into_coin(scenario.ctx()); + pay::keep(coin, scenario.ctx()); + scenario.end(); + } +} diff --git a/crates/sui-framework/packages/sui-framework/tests/clock_tests.move b/crates/iota-framework/packages/iota-framework/tests/clock_tests.move similarity index 82% rename from crates/sui-framework/packages/sui-framework/tests/clock_tests.move rename to crates/iota-framework/packages/iota-framework/tests/clock_tests.move index 519c88d7ead..47d7102f4a3 100644 --- a/crates/sui-framework/packages/sui-framework/tests/clock_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/clock_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::clock_tests { - use sui::clock; +module iota::clock_tests { + use iota::clock; #[test] fun creating_a_clock_and_incrementing_it() { diff --git a/crates/sui-framework/packages/sui-framework/tests/coin_manager_tests.move b/crates/iota-framework/packages/iota-framework/tests/coin_manager_tests.move similarity index 97% rename from crates/sui-framework/packages/sui-framework/tests/coin_manager_tests.move rename to crates/iota-framework/packages/iota-framework/tests/coin_manager_tests.move index 6a5e7c24390..43794b5b2b6 100644 --- a/crates/sui-framework/packages/sui-framework/tests/coin_manager_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/coin_manager_tests.move @@ -1,13 +1,14 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::coin_manager_tests { +module iota::coin_manager_tests { - use sui::coin_manager; - use sui::coin::{Self, CoinMetadata}; - use sui::test_scenario; - use sui::url::{Self, Url}; + use iota::coin_manager; + use iota::coin::{Self, CoinMetadata}; + use iota::test_scenario; + use iota::url::{Self, Url}; use std::ascii::{string}; public struct COIN_MANAGER_TESTS has drop {} diff --git a/crates/sui-framework/packages/sui-framework/tests/coin_tests.move b/crates/iota-framework/packages/iota-framework/tests/coin_tests.move similarity index 96% rename from crates/sui-framework/packages/sui-framework/tests/coin_tests.move rename to crates/iota-framework/packages/iota-framework/tests/coin_tests.move index 9d683146ab3..e5802290f57 100644 --- a/crates/sui-framework/packages/sui-framework/tests/coin_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/coin_tests.move @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::coin_tests { - use sui::coin::{Self, Coin}; - use sui::pay; - use sui::url; - use sui::test_scenario; - use sui::deny_list; +module iota::coin_tests { + use iota::coin::{Self, Coin}; + use iota::pay; + use iota::url; + use iota::test_scenario; + use iota::deny_list; public struct COIN_TESTS has drop {} diff --git a/crates/sui-framework/packages/sui-framework/tests/crypto/bls12381_tests.move b/crates/iota-framework/packages/iota-framework/tests/crypto/bls12381_tests.move similarity index 99% rename from crates/sui-framework/packages/sui-framework/tests/crypto/bls12381_tests.move rename to crates/iota-framework/packages/iota-framework/tests/crypto/bls12381_tests.move index be03bd38d7e..437fdc1e0fa 100644 --- a/crates/sui-framework/packages/sui-framework/tests/crypto/bls12381_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/crypto/bls12381_tests.move @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[allow(implicit_const_copy)] #[test_only] -module sui::bls12381_tests { - use sui::bls12381; - use sui::group_ops; +module iota::bls12381_tests { + use iota::bls12381; + use iota::group_ops; use std::hash::sha2_256; - use sui::test_utils::assert_eq; + use iota::test_utils::assert_eq; const ORDER_BYTES: vector = x"73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"; const ORDER_MINUS_ONE_BYTES: vector = x"73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000"; diff --git a/crates/sui-framework/packages/sui-framework/tests/crypto/ecdsa_k1_tests.move b/crates/iota-framework/packages/iota-framework/tests/crypto/ecdsa_k1_tests.move similarity index 98% rename from crates/sui-framework/packages/sui-framework/tests/crypto/ecdsa_k1_tests.move rename to crates/iota-framework/packages/iota-framework/tests/crypto/ecdsa_k1_tests.move index e8e72461456..270eeac5b5c 100644 --- a/crates/sui-framework/packages/sui-framework/tests/crypto/ecdsa_k1_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/crypto/ecdsa_k1_tests.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::ecdsa_k1_tests { - use sui::ecdsa_k1; - use sui::hash; +module iota::ecdsa_k1_tests { + use iota::ecdsa_k1; + use iota::hash; #[test] fun test_ecrecover_pubkey() { diff --git a/crates/sui-framework/packages/sui-framework/tests/crypto/ecdsa_r1_tests.move b/crates/iota-framework/packages/iota-framework/tests/crypto/ecdsa_r1_tests.move similarity index 97% rename from crates/sui-framework/packages/sui-framework/tests/crypto/ecdsa_r1_tests.move rename to crates/iota-framework/packages/iota-framework/tests/crypto/ecdsa_r1_tests.move index 11ca6a7a4e0..6aabace0852 100644 --- a/crates/sui-framework/packages/sui-framework/tests/crypto/ecdsa_r1_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/crypto/ecdsa_r1_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::ecdsa_r1_tests { - use sui::ecdsa_r1; +module iota::ecdsa_r1_tests { + use iota::ecdsa_r1; #[test] fun test_ecrecover_pubkey() { diff --git a/crates/sui-framework/packages/sui-framework/tests/crypto/ecvrf_tests.move b/crates/iota-framework/packages/iota-framework/tests/crypto/ecvrf_tests.move similarity index 96% rename from crates/sui-framework/packages/sui-framework/tests/crypto/ecvrf_tests.move rename to crates/iota-framework/packages/iota-framework/tests/crypto/ecvrf_tests.move index 72451d04740..5c1ab227df6 100644 --- a/crates/sui-framework/packages/sui-framework/tests/crypto/ecvrf_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/crypto/ecvrf_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::ecvrf_tests { - use sui::ecvrf; +module iota::ecvrf_tests { + use iota::ecvrf; #[test] fun test_ecvrf_verify() { diff --git a/crates/sui-framework/packages/sui-framework/tests/crypto/ed25519_tests.move b/crates/iota-framework/packages/iota-framework/tests/crypto/ed25519_tests.move similarity index 95% rename from crates/sui-framework/packages/sui-framework/tests/crypto/ed25519_tests.move rename to crates/iota-framework/packages/iota-framework/tests/crypto/ed25519_tests.move index 43b7bf75e66..f4a25ed4844 100644 --- a/crates/sui-framework/packages/sui-framework/tests/crypto/ed25519_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/crypto/ed25519_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::ed25519_tests { - use sui::ed25519; +module iota::ed25519_tests { + use iota::ed25519; #[test] fun test_ed25519_valid_sig() { diff --git a/crates/sui-framework/packages/sui-framework/tests/crypto/groth16_tests.move b/crates/iota-framework/packages/iota-framework/tests/crypto/groth16_tests.move similarity index 99% rename from crates/sui-framework/packages/sui-framework/tests/crypto/groth16_tests.move rename to crates/iota-framework/packages/iota-framework/tests/crypto/groth16_tests.move index a29fc25f283..e9e74771dd7 100644 --- a/crates/sui-framework/packages/sui-framework/tests/crypto/groth16_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/crypto/groth16_tests.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::groth16_tests { - use sui::groth16; - use sui::groth16::{bls12381, bn254}; +module iota::groth16_tests { + use iota::groth16; + use iota::groth16::{bls12381, bn254}; #[test] fun test_prepare_verifying_key_bls12381() { diff --git a/crates/iota-framework/packages/iota-framework/tests/crypto/hash_tests.move b/crates/iota-framework/packages/iota-framework/tests/crypto/hash_tests.move new file mode 100644 index 00000000000..ede11e5ba55 --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/tests/crypto/hash_tests.move @@ -0,0 +1,35 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module iota::hash_tests { + use iota::hash; + + #[test] + fun test_keccak256_hash() { + let msg = b"hello world!"; + let hashed_msg_bytes = x"57caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd6"; + let hashed_msg = hash::keccak256(&msg); + assert!(hashed_msg == hashed_msg_bytes, 0); + + let empty_msg = b""; + let _ = hash::keccak256(&empty_msg); + let long_msg = b"57caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd6"; + let _ = hash::keccak256(&long_msg); + } + + #[test] + fun test_blake2b256_hash() { + let msg = b"hello world!"; + let hashed_msg_bytes = x"4fccfb4d98d069558aa93e9565f997d81c33b080364efd586e77a433ddffc5e2"; + let hashed_msg = hash::blake2b256(&msg); + assert!(hashed_msg == hashed_msg_bytes, 0); + + let empty_msg = b""; + let _ = hash::blake2b256(&empty_msg); + let long_msg = b"57caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd6"; + let _ = hash::blake2b256(&long_msg); + } + +} \ No newline at end of file diff --git a/crates/sui-framework/packages/sui-framework/tests/crypto/hmac_tests.move b/crates/iota-framework/packages/iota-framework/tests/crypto/hmac_tests.move similarity index 89% rename from crates/sui-framework/packages/sui-framework/tests/crypto/hmac_tests.move rename to crates/iota-framework/packages/iota-framework/tests/crypto/hmac_tests.move index 30f9f5ca7b2..c1f802acb9d 100644 --- a/crates/sui-framework/packages/sui-framework/tests/crypto/hmac_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/crypto/hmac_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::hmac_tests { - use sui::hmac; +module iota::hmac_tests { + use iota::hmac; #[test] fun test_hmac_sha3_256() { diff --git a/crates/sui-framework/packages/sui-framework/tests/crypto/poseidon_tests.move b/crates/iota-framework/packages/iota-framework/tests/crypto/poseidon_tests.move similarity index 91% rename from crates/sui-framework/packages/sui-framework/tests/crypto/poseidon_tests.move rename to crates/iota-framework/packages/iota-framework/tests/crypto/poseidon_tests.move index 4a7bae54fac..9c92c12553a 100644 --- a/crates/sui-framework/packages/sui-framework/tests/crypto/poseidon_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/crypto/poseidon_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::poseidon_tests { - use sui::poseidon::poseidon_bn254; +module iota::poseidon_tests { + use iota::poseidon::poseidon_bn254; #[test] fun test_poseidon_bn254_hash() { @@ -49,7 +50,7 @@ module sui::poseidon_tests { } #[test] - #[expected_failure(abort_code = sui::poseidon::ENonCanonicalInput)] + #[expected_failure(abort_code = iota::poseidon::ENonCanonicalInput)] fun test_poseidon_bn254_non_canonical_input() { // Scalar field size. let msg = vector[21888242871839275222246405745257275088548364400416034343698204186575808495617u256]; @@ -57,7 +58,7 @@ module sui::poseidon_tests { } #[test] - #[expected_failure(abort_code = sui::poseidon::EEmptyInput)] + #[expected_failure(abort_code = iota::poseidon::EEmptyInput)] fun test_poseidon_bn254_empty_input() { let msg = vector[]; poseidon_bn254(&msg); diff --git a/crates/sui-framework/packages/sui-framework/tests/crypto/zklogin_verified_id_tests.move b/crates/iota-framework/packages/iota-framework/tests/crypto/zklogin_verified_id_tests.move similarity index 79% rename from crates/sui-framework/packages/sui-framework/tests/crypto/zklogin_verified_id_tests.move rename to crates/iota-framework/packages/iota-framework/tests/crypto/zklogin_verified_id_tests.move index b1c4dbdadf0..caaa8565cfb 100644 --- a/crates/sui-framework/packages/sui-framework/tests/crypto/zklogin_verified_id_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/crypto/zklogin_verified_id_tests.move @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::zklogin_verified_id_tests { - use sui::zklogin_verified_id::{check_zklogin_id, verify_zklogin_id}; - use sui::test_scenario; +module iota::zklogin_verified_id_tests { + use iota::zklogin_verified_id::{check_zklogin_id, verify_zklogin_id}; + use iota::test_scenario; #[test] - #[expected_failure(abort_code = sui::zklogin_verified_id::EFunctionDisabled)] + #[expected_failure(abort_code = iota::zklogin_verified_id::EFunctionDisabled)] fun test_check_zklogin_id() { let address = @0x1c6b623a2f2c91333df730c98d220f11484953b391a3818680f922c264cc0c6b; let kc_name = b"sub".to_string(); @@ -19,7 +20,7 @@ module sui::zklogin_verified_id_tests { } #[test] - #[expected_failure(abort_code = sui::zklogin_verified_id::EFunctionDisabled)] + #[expected_failure(abort_code = iota::zklogin_verified_id::EFunctionDisabled)] fun test_verified_id() { let address = @0x1c6b623a2f2c91333df730c98d220f11484953b391a3818680f922c264cc0c6b; diff --git a/crates/sui-framework/packages/sui-framework/tests/crypto/zklogin_verified_issuer_tests.move b/crates/iota-framework/packages/iota-framework/tests/crypto/zklogin_verified_issuer_tests.move similarity index 87% rename from crates/sui-framework/packages/sui-framework/tests/crypto/zklogin_verified_issuer_tests.move rename to crates/iota-framework/packages/iota-framework/tests/crypto/zklogin_verified_issuer_tests.move index bfefd34ba27..964d1b8db88 100644 --- a/crates/sui-framework/packages/sui-framework/tests/crypto/zklogin_verified_issuer_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/crypto/zklogin_verified_issuer_tests.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::zklogin_verified_issuer_tests { - use sui::zklogin_verified_issuer::{check_zklogin_issuer, delete, verify_zklogin_issuer, VerifiedIssuer}; - use sui::test_scenario; +module iota::zklogin_verified_issuer_tests { + use iota::zklogin_verified_issuer::{check_zklogin_issuer, delete, verify_zklogin_issuer, VerifiedIssuer}; + use iota::test_scenario; #[test] fun test_check_zklogin_issuer() { @@ -45,7 +46,7 @@ module sui::zklogin_verified_issuer_tests { } #[test] - #[expected_failure(abort_code = sui::zklogin_verified_issuer::EInvalidProof)] + #[expected_failure(abort_code = iota::zklogin_verified_issuer::EInvalidProof)] fun test_invalid_verified_issuer() { let other_address = @0x1; let iss = b"https://accounts.google.com".to_string(); diff --git a/crates/sui-framework/packages/sui-framework/tests/dynamic_field_tests.move b/crates/iota-framework/packages/iota-framework/tests/dynamic_field_tests.move similarity index 84% rename from crates/sui-framework/packages/sui-framework/tests/dynamic_field_tests.move rename to crates/iota-framework/packages/iota-framework/tests/dynamic_field_tests.move index 1e341a8e3b6..1285a5bc564 100644 --- a/crates/sui-framework/packages/sui-framework/tests/dynamic_field_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/dynamic_field_tests.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::dynamic_field_tests { - use sui::dynamic_field::{add, exists_with_type, borrow, borrow_mut, remove}; - use sui::test_scenario; +module iota::dynamic_field_tests { + use iota::dynamic_field::{add, exists_with_type, borrow, borrow_mut, remove}; + use iota::test_scenario; #[test] fun simple_all_functions() { @@ -44,7 +45,7 @@ module sui::dynamic_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldAlreadyExists)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldAlreadyExists)] fun add_duplicate() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -55,7 +56,7 @@ module sui::dynamic_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldAlreadyExists)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldAlreadyExists)] fun add_duplicate_mismatched_type() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -66,7 +67,7 @@ module sui::dynamic_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun borrow_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -76,7 +77,7 @@ module sui::dynamic_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldTypeMismatch)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldTypeMismatch)] fun borrow_wrong_type() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -87,7 +88,7 @@ module sui::dynamic_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun borrow_mut_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -97,7 +98,7 @@ module sui::dynamic_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldTypeMismatch)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldTypeMismatch)] fun borrow_mut_wrong_type() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -108,7 +109,7 @@ module sui::dynamic_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun remove_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -118,7 +119,7 @@ module sui::dynamic_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldTypeMismatch)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldTypeMismatch)] fun remove_wrong_type() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); diff --git a/crates/sui-framework/packages/sui-framework/tests/dynamic_object_field_tests.move b/crates/iota-framework/packages/iota-framework/tests/dynamic_object_field_tests.move similarity index 89% rename from crates/sui-framework/packages/sui-framework/tests/dynamic_object_field_tests.move rename to crates/iota-framework/packages/iota-framework/tests/dynamic_object_field_tests.move index 43d5a9ada6d..b7bfeff9187 100644 --- a/crates/sui-framework/packages/sui-framework/tests/dynamic_object_field_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/dynamic_object_field_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::dynamic_object_field_tests { - use sui::dynamic_object_field::{ +module iota::dynamic_object_field_tests { + use iota::dynamic_object_field::{ add, borrow, borrow_mut, @@ -12,7 +13,7 @@ module sui::dynamic_object_field_tests { remove, id as field_id, }; - use sui::test_scenario; + use iota::test_scenario; public struct Counter has key, store { id: UID, @@ -71,7 +72,7 @@ module sui::dynamic_object_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldAlreadyExists)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldAlreadyExists)] fun add_duplicate() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -82,7 +83,7 @@ module sui::dynamic_object_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldAlreadyExists)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldAlreadyExists)] fun add_duplicate_mismatched_type() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -93,7 +94,7 @@ module sui::dynamic_object_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun borrow_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -103,7 +104,7 @@ module sui::dynamic_object_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldTypeMismatch)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldTypeMismatch)] fun borrow_wrong_type() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -114,7 +115,7 @@ module sui::dynamic_object_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun borrow_mut_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -124,7 +125,7 @@ module sui::dynamic_object_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldTypeMismatch)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldTypeMismatch)] fun borrow_mut_wrong_type() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -135,7 +136,7 @@ module sui::dynamic_object_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun remove_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -145,7 +146,7 @@ module sui::dynamic_object_field_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldTypeMismatch)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldTypeMismatch)] fun remove_wrong_type() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); diff --git a/crates/sui-framework/packages/sui-framework/tests/id_tests.move b/crates/iota-framework/packages/iota-framework/tests/id_tests.move similarity index 87% rename from crates/sui-framework/packages/sui-framework/tests/id_tests.move rename to crates/iota-framework/packages/iota-framework/tests/id_tests.move index f44e0d1b33c..cdc07023e04 100644 --- a/crates/sui-framework/packages/sui-framework/tests/id_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/id_tests.move @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::id_tests { +module iota::id_tests { const EIdBytesMismatch: u64 = 0; public struct Object has key { diff --git a/crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_borrow_tests.move b/crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_borrow_tests.move similarity index 86% rename from crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_borrow_tests.move rename to crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_borrow_tests.move index 02392acb642..c8f67756744 100644 --- a/crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_borrow_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_borrow_tests.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] /// Tests for borrowing mechanics. -module sui::kiosk_borrow_tests { - use sui::kiosk_test_utils::{Self as utils, Asset}; +module iota::kiosk_borrow_tests { + use iota::kiosk_test_utils::{Self as utils, Asset}; const AMT: u64 = 1000; @@ -28,7 +29,7 @@ module sui::kiosk_borrow_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::ENotOwner)] + #[expected_failure(abort_code = iota::kiosk::ENotOwner)] fun test_borrow_fail_not_owner() { let ctx = &mut utils::ctx(); let (_item, id) = utils::get_asset(ctx); @@ -41,7 +42,7 @@ module sui::kiosk_borrow_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EItemNotFound)] + #[expected_failure(abort_code = iota::kiosk::EItemNotFound)] fun test_borrow_fail_item_not_found() { let ctx = &mut utils::ctx(); let (_item, id) = utils::get_asset(ctx); @@ -69,7 +70,7 @@ module sui::kiosk_borrow_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::ENotOwner)] + #[expected_failure(abort_code = iota::kiosk::ENotOwner)] fun test_borrow_mut_fail_not_owner() { let ctx = &mut utils::ctx(); let (_item, id) = utils::get_asset(ctx); @@ -81,7 +82,7 @@ module sui::kiosk_borrow_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EItemNotFound)] + #[expected_failure(abort_code = iota::kiosk::EItemNotFound)] fun test_borrow_mut_fail_item_not_found() { let ctx = &mut utils::ctx(); let (_item, id) = utils::get_asset(ctx); @@ -92,7 +93,7 @@ module sui::kiosk_borrow_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EItemIsListed)] + #[expected_failure(abort_code = iota::kiosk::EItemIsListed)] fun test_borrow_mut_fail_item_is_listed() { let ctx = &mut utils::ctx(); let (item, id) = utils::get_asset(ctx); @@ -114,7 +115,7 @@ module sui::kiosk_borrow_tests { kiosk.place(&cap, item); let (item, potato) = kiosk.borrow_val(&cap, id); - assert!(sui::object::id(&item) == id, 0); + assert!(iota::object::id(&item) == id, 0); kiosk.return_val(item, potato); assert!(kiosk.has_item(id), 0); @@ -124,7 +125,7 @@ module sui::kiosk_borrow_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::ENotOwner)] + #[expected_failure(abort_code = iota::kiosk::ENotOwner)] fun test_borrow_val_fail_not_owner() { let ctx = &mut utils::ctx(); let (_item, id) = utils::get_asset(ctx); @@ -136,7 +137,7 @@ module sui::kiosk_borrow_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EItemNotFound)] + #[expected_failure(abort_code = iota::kiosk::EItemNotFound)] fun test_borrow_val_fail_item_not_found() { let ctx = &mut utils::ctx(); let (_item, id) = utils::get_asset(ctx); @@ -147,7 +148,7 @@ module sui::kiosk_borrow_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EItemIsListed)] + #[expected_failure(abort_code = iota::kiosk::EItemIsListed)] fun test_borrow_val_fail_item_is_listed() { let ctx = &mut utils::ctx(); let (item, id) = utils::get_asset(ctx); @@ -160,7 +161,7 @@ module sui::kiosk_borrow_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EWrongKiosk)] + #[expected_failure(abort_code = iota::kiosk::EWrongKiosk)] fun test_borrow_val_fail_wrong_kiosk() { let ctx = &mut utils::ctx(); let (item_1, id_1) = utils::get_asset(ctx); @@ -180,7 +181,7 @@ module sui::kiosk_borrow_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EItemMismatch)] + #[expected_failure(abort_code = iota::kiosk::EItemMismatch)] fun test_borrow_val_fail_item_mismatch() { let ctx = &mut utils::ctx(); let (item_1, id_1) = utils::get_asset(ctx); diff --git a/crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_extension_tests.move b/crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_extension_tests.move similarity index 84% rename from crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_extension_tests.move rename to crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_extension_tests.move index e5c0bb00836..b1864265902 100644 --- a/crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_extension_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_extension_tests.move @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::kiosk_marketplace_ext { - use sui::sui::SUI; - use sui::coin::Coin; - use sui::kiosk_extension as ext; - use sui::kiosk::{Self, KioskOwnerCap, Kiosk, PurchaseCap}; - use sui::transfer_policy::{Self as policy, TransferPolicy, TransferRequest}; +module iota::kiosk_marketplace_ext { + use iota::iota::IOTA; + use iota::coin::Coin; + use iota::kiosk_extension as ext; + use iota::kiosk::{Self, KioskOwnerCap, Kiosk, PurchaseCap}; + use iota::transfer_policy::{Self as policy, TransferPolicy, TransferRequest}; /// Trying to access an owner-only action. const ENotOwner: u64 = 0; - /// Trying to purchase an item with an incorrect amount of SUI. + /// Trying to purchase an item with an incorrect amount of IOTA. const EIncorrectAmount: u64 = 1; /// Trying to accept a bid from an incorrect Kiosk. const EIncorrectKiosk: u64 = 2; @@ -33,11 +34,11 @@ module sui::kiosk_marketplace_ext { // === Collection Bidding === - /// Collection bidding: the Kiosk Owner offers a bid (in SUI) for an item of type `T`. + /// Collection bidding: the Kiosk Owner offers a bid (in IOTA) for an item of type `T`. /// /// There can be only one bid per type. public fun bid( - kiosk: &mut Kiosk, cap: &KioskOwnerCap, bid: Coin + kiosk: &mut Kiosk, cap: &KioskOwnerCap, bid: Coin ) { assert!(kiosk.has_access(cap), ENotOwner); assert!(ext::is_installed>(kiosk), ENotInstalled); @@ -53,7 +54,7 @@ module sui::kiosk_marketplace_ext { policy: &TransferPolicy, lock: bool ): (TransferRequest, TransferRequest) { - let bid: Coin = ext::storage_mut(Ext {}, destination).remove(Bid {}); + let bid: Coin = ext::storage_mut(Ext {}, destination).remove(Bid {}); // form the request while we have all the data (not yet consumed) let market_request = policy::new_request( @@ -91,7 +92,7 @@ module sui::kiosk_marketplace_ext { public fun purchase( kiosk: &mut Kiosk, item_id: ID, - payment: Coin, + payment: Coin, ): (T, TransferRequest, TransferRequest) { let purchase_cap: PurchaseCap = ext::storage_mut(Ext {}, kiosk).remove(item_id); @@ -122,9 +123,9 @@ module sui::kiosk_marketplace_ext { #[test_only] -module sui::kiosk_extensions_tests { - use sui::kiosk_test_utils::{Self as test}; - use sui::kiosk_extension as ext; +module iota::kiosk_extensions_tests { + use iota::kiosk_test_utils::{Self as test}; + use iota::kiosk_extension as ext; /// The `Ext` witness to use for testing. public struct Extension has drop {} @@ -166,7 +167,7 @@ module sui::kiosk_extensions_tests { // - `ext::place` (not allowed | only lock) // - `ext::lock` (not allowed | only place) - #[test, expected_failure(abort_code = sui::kiosk_extension::EExtensionNotAllowed)] + #[test, expected_failure(abort_code = iota::kiosk_extension::EExtensionNotAllowed)] fun test_lock_not_allowed() { let ctx = &mut test::ctx(); let (policy, _policy_cap) = test::get_policy(ctx); @@ -179,7 +180,7 @@ module sui::kiosk_extensions_tests { abort 1337 } - #[test, expected_failure(abort_code = sui::kiosk_extension::EExtensionNotAllowed)] + #[test, expected_failure(abort_code = iota::kiosk_extension::EExtensionNotAllowed)] fun test_lock_not_allowed_but_place() { let ctx = &mut test::ctx(); let (policy, _policy_cap) = test::get_policy(ctx); @@ -192,7 +193,7 @@ module sui::kiosk_extensions_tests { abort 1337 } - #[test, expected_failure(abort_code = sui::kiosk_extension::EExtensionNotAllowed)] + #[test, expected_failure(abort_code = iota::kiosk_extension::EExtensionNotAllowed)] fun test_place_not_allowed() { let ctx = &mut test::ctx(); let (policy, _policy_cap) = test::get_policy(ctx); @@ -233,7 +234,7 @@ module sui::kiosk_extensions_tests { // - `ext::lock` // - `ext::place` - #[test, expected_failure(abort_code = sui::kiosk_extension::EExtensionNotInstalled)] + #[test, expected_failure(abort_code = iota::kiosk_extension::EExtensionNotInstalled)] fun test_enable_not_installed() { let ctx = &mut test::ctx(); let (mut kiosk, owner_cap) = test::get_kiosk(ctx); @@ -243,7 +244,7 @@ module sui::kiosk_extensions_tests { abort 1337 } - #[test, expected_failure(abort_code = sui::kiosk_extension::EExtensionNotInstalled)] + #[test, expected_failure(abort_code = iota::kiosk_extension::EExtensionNotInstalled)] fun test_disable_not_installed() { let ctx = &mut test::ctx(); let (mut kiosk, owner_cap) = test::get_kiosk(ctx); @@ -253,7 +254,7 @@ module sui::kiosk_extensions_tests { abort 1337 } - #[test, expected_failure(abort_code = sui::kiosk_extension::EExtensionNotInstalled)] + #[test, expected_failure(abort_code = iota::kiosk_extension::EExtensionNotInstalled)] fun test_remove_not_installed() { let ctx = &mut test::ctx(); let (mut kiosk, owner_cap) = test::get_kiosk(ctx); @@ -263,7 +264,7 @@ module sui::kiosk_extensions_tests { abort 1337 } - #[test, expected_failure(abort_code = sui::kiosk_extension::EExtensionNotInstalled)] + #[test, expected_failure(abort_code = iota::kiosk_extension::EExtensionNotInstalled)] fun test_storage_not_installed() { let ctx = &mut test::ctx(); let (kiosk, _owner_cap) = test::get_kiosk(ctx); @@ -273,7 +274,7 @@ module sui::kiosk_extensions_tests { abort 1337 } - #[test, expected_failure(abort_code = sui::kiosk_extension::EExtensionNotInstalled)] + #[test, expected_failure(abort_code = iota::kiosk_extension::EExtensionNotInstalled)] fun test_storage_mut_not_installed() { let ctx = &mut test::ctx(); let (mut kiosk, _owner_cap) = test::get_kiosk(ctx); @@ -283,7 +284,7 @@ module sui::kiosk_extensions_tests { abort 1337 } - #[test, expected_failure(abort_code = sui::kiosk_extension::EExtensionNotInstalled)] + #[test, expected_failure(abort_code = iota::kiosk_extension::EExtensionNotInstalled)] fun test_lock_not_installed() { let ctx = &mut test::ctx(); let (policy, _policy_cap) = test::get_policy(ctx); @@ -295,7 +296,7 @@ module sui::kiosk_extensions_tests { abort 1337 } - #[test, expected_failure(abort_code = sui::kiosk_extension::EExtensionNotInstalled)] + #[test, expected_failure(abort_code = iota::kiosk_extension::EExtensionNotInstalled)] fun test_place_not_installed() { let ctx = &mut test::ctx(); let (policy, _policy_cap) = test::get_policy(ctx); diff --git a/crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_locked_tests.move b/crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_locked_tests.move similarity index 87% rename from crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_locked_tests.move rename to crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_locked_tests.move index 59123206ffb..fba6242512a 100644 --- a/crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_locked_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_locked_tests.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] /// Test illustrating how an asset can be forever locked in the Kiosk. -module sui::kiosk_locked_test { - use sui::item_locked_policy as locked_policy; - use sui::kiosk_test_utils::{Self as test, Asset}; +module iota::kiosk_locked_test { + use iota::item_locked_policy as locked_policy; + use iota::kiosk_test_utils::{Self as test, Asset}; #[test] fun test_item_always_locked() { @@ -14,7 +15,7 @@ module sui::kiosk_locked_test { let (mut policy, policy_cap) = test::get_policy(ctx); let (mut kiosk, kiosk_cap) = test::get_kiosk(ctx); let (item, item_id) = test::get_asset(ctx); - let payment = test::get_sui(1000, ctx); + let payment = test::get_iota(1000, ctx); // Alice the Creator // - disallow taking from the Kiosk diff --git a/crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_test_utils.move b/crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_test_utils.move similarity index 83% rename from crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_test_utils.move rename to crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_test_utils.move index 887a6f4cc7c..9db936952b8 100644 --- a/crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_test_utils.move +++ b/crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_test_utils.move @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::kiosk_test_utils { - use sui::sui::SUI; - use sui::coin::{Self, Coin}; - use sui::package::{Self, Publisher}; - use sui::transfer_policy::{Self as policy, TransferPolicy, TransferPolicyCap}; - use sui::kiosk::{Self, Kiosk, KioskOwnerCap}; +module iota::kiosk_test_utils { + use iota::iota::IOTA; + use iota::coin::{Self, Coin}; + use iota::package::{Self, Publisher}; + use iota::transfer_policy::{Self as policy, TransferPolicy, TransferPolicyCap}; + use iota::kiosk::{Self, Kiosk, KioskOwnerCap}; public struct OTW has drop {} public struct Asset has key, store { id: UID } @@ -32,8 +33,8 @@ module sui::kiosk_test_utils { (policy, cap) } - /// Prepare: Get Sui - public fun get_sui(amount: u64, ctx: &mut TxContext): Coin { + /// Prepare: Get Iota + public fun get_iota(amount: u64, ctx: &mut TxContext): Coin { coin::mint_for_testing(amount, ctx) } diff --git a/crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_tests.move b/crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_tests.move similarity index 87% rename from crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_tests.move rename to crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_tests.move index 513335fb9aa..a161112ab8f 100644 --- a/crates/sui-framework/packages/sui-framework/tests/kiosk/kiosk_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/kiosk/kiosk_tests.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] @@ -6,10 +7,10 @@ /// - [ ] test purchase flow /// - [ ] test purchase cap flow /// - [ ] test withdraw methods -module sui::kiosk_tests { - use sui::kiosk_test_utils::{Self as test, Asset}; - use sui::sui::SUI; - use sui::coin; +module iota::kiosk_tests { + use iota::kiosk_test_utils::{Self as test, Asset}; + use iota::iota::IOTA; + use iota::coin; const AMT: u64 = 10_000; @@ -48,7 +49,7 @@ module sui::kiosk_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EItemLocked)] + #[expected_failure(abort_code = iota::kiosk::EItemLocked)] fun test_taking_not_allowed() { let ctx = &mut test::ctx(); let (asset, item_id) = test::get_asset(ctx); @@ -69,7 +70,7 @@ module sui::kiosk_tests { kiosk.place_and_list(&owner_cap, asset, AMT); assert!(kiosk.is_listed(item_id), 0); - let payment = coin::mint_for_testing(AMT, ctx); + let payment = coin::mint_for_testing(AMT, ctx); let (asset, request) = kiosk.purchase(item_id, payment); assert!(!kiosk.is_listed(item_id), 0); policy.confirm_request(request); @@ -98,7 +99,7 @@ module sui::kiosk_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::ENotListed)] + #[expected_failure(abort_code = iota::kiosk::ENotListed)] fun test_delist_not_listed() { let ctx = &mut test::ctx(); let (asset, item_id) = test::get_asset(ctx); @@ -111,7 +112,7 @@ module sui::kiosk_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EListedExclusively)] + #[expected_failure(abort_code = iota::kiosk::EListedExclusively)] fun test_delist_listed_exclusively() { let ctx = &mut test::ctx(); let (asset, item_id) = test::get_asset(ctx); @@ -125,10 +126,10 @@ module sui::kiosk_tests { } #[allow(unused_field)] - public struct WrongAsset has key, store { id: sui::object::UID } + public struct WrongAsset has key, store { id: iota::object::UID } #[test] - #[expected_failure(abort_code = sui::kiosk::EItemNotFound)] + #[expected_failure(abort_code = iota::kiosk::EItemNotFound)] fun test_delist_wrong_type() { let ctx = &mut test::ctx(); let (asset, item_id) = test::get_asset(ctx); @@ -141,7 +142,7 @@ module sui::kiosk_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EItemNotFound)] + #[expected_failure(abort_code = iota::kiosk::EItemNotFound)] fun test_delist_no_item() { let ctx = &mut test::ctx(); let (_asset, item_id) = test::get_asset(ctx); @@ -153,7 +154,7 @@ module sui::kiosk_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EIncorrectAmount)] + #[expected_failure(abort_code = iota::kiosk::EIncorrectAmount)] fun test_purchase_wrong_amount() { let ctx = &mut test::ctx(); let (asset, item_id) = test::get_asset(ctx); @@ -161,7 +162,7 @@ module sui::kiosk_tests { let (policy, _policy_cap) = test::get_policy(ctx); kiosk.place_and_list(&owner_cap, asset, AMT); - let payment = coin::mint_for_testing(AMT + 1, ctx); + let payment = coin::mint_for_testing(AMT + 1, ctx); let (_asset, request) = kiosk.purchase(item_id, payment); policy.confirm_request(request); @@ -177,7 +178,7 @@ module sui::kiosk_tests { kiosk.place(&owner_cap, asset); let purchase_cap = kiosk.list_with_purchase_cap(&owner_cap, item_id, AMT, ctx); - let payment = coin::mint_for_testing(AMT, ctx); + let payment = coin::mint_for_testing(AMT, ctx); assert!(kiosk.is_listed_exclusively(item_id), 0); let (asset, request) = kiosk.purchase_with_cap(purchase_cap, payment); assert!(!kiosk.is_listed_exclusively(item_id), 0); @@ -206,7 +207,7 @@ module sui::kiosk_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EItemNotFound)] + #[expected_failure(abort_code = iota::kiosk::EItemNotFound)] fun test_list_no_item_fail() { let ctx = &mut test::ctx(); let (_asset, item_id) = test::get_asset(ctx); @@ -218,7 +219,7 @@ module sui::kiosk_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EItemNotFound)] + #[expected_failure(abort_code = iota::kiosk::EItemNotFound)] fun test_list_with_purchase_cap_no_item_fail() { let ctx = &mut test::ctx(); let (_asset, item_id) = test::get_asset(ctx); @@ -230,7 +231,7 @@ module sui::kiosk_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EAlreadyListed)] + #[expected_failure(abort_code = iota::kiosk::EAlreadyListed)] fun test_purchase_cap_already_listed_fail() { let ctx = &mut test::ctx(); let (asset, item_id) = test::get_asset(ctx); @@ -243,7 +244,7 @@ module sui::kiosk_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::EListedExclusively)] + #[expected_failure(abort_code = iota::kiosk::EListedExclusively)] fun test_purchase_cap_issued_list_fail() { let ctx = &mut test::ctx(); let (asset, item_id) = test::get_asset(ctx); @@ -258,7 +259,7 @@ module sui::kiosk_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::ENotEmpty)] + #[expected_failure(abort_code = iota::kiosk::ENotEmpty)] fun test_kiosk_has_items() { let ctx = &mut test::ctx(); let (_policy, _cap) = test::get_policy(ctx); @@ -282,7 +283,7 @@ module sui::kiosk_tests { } #[test] - #[expected_failure(abort_code = sui::kiosk::ENotEnough)] + #[expected_failure(abort_code = iota::kiosk::ENotEnough)] fun test_withdraw_more_than_there_is() { let ctx = &mut test::ctx(); let (mut kiosk, owner_cap) = test::get_kiosk(ctx); @@ -307,13 +308,13 @@ module sui::kiosk_tests { let (kiosk, owner_cap) = test::get_kiosk(ctx); let uid = kiosk.uid(); - assert!(sui::object::uid_to_inner(uid) == sui::object::id(&kiosk), 0); + assert!(iota::object::uid_to_inner(uid) == iota::object::id(&kiosk), 0); test::return_kiosk(kiosk, owner_cap, ctx); } #[test] - #[expected_failure(abort_code = sui::kiosk::EUidAccessNotAllowed)] + #[expected_failure(abort_code = iota::kiosk::EUidAccessNotAllowed)] fun test_disallow_extensions_uid_mut() { let ctx = &mut test::ctx(); let (mut kiosk, owner_cap) = test::get_kiosk(ctx); diff --git a/crates/sui-framework/packages/sui-framework/tests/kiosk/policies/dummy_policy.test.move b/crates/iota-framework/packages/iota-framework/tests/kiosk/policies/dummy_policy.test.move similarity index 79% rename from crates/sui-framework/packages/sui-framework/tests/kiosk/policies/dummy_policy.test.move rename to crates/iota-framework/packages/iota-framework/tests/kiosk/policies/dummy_policy.test.move index 9de58f64dd1..f29c31e1e65 100644 --- a/crates/sui-framework/packages/sui-framework/tests/kiosk/policies/dummy_policy.test.move +++ b/crates/iota-framework/packages/iota-framework/tests/kiosk/policies/dummy_policy.test.move @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] /// Dummy policy which showcases all of the methods. -module sui::dummy_policy { - use sui::coin::Coin; - use sui::sui::SUI; - use sui::transfer_policy::{ +module iota::dummy_policy { + use iota::coin::Coin; + use iota::iota::IOTA; + use iota::transfer_policy::{ Self as policy, TransferPolicy, TransferPolicyCap, @@ -26,7 +27,7 @@ module sui::dummy_policy { public fun pay( policy: &mut TransferPolicy, request: &mut TransferRequest, - payment: Coin + payment: Coin ) { policy::add_to_balance(Rule {}, policy, payment); policy::add_receipt(Rule {}, request); diff --git a/crates/sui-framework/packages/sui-framework/tests/kiosk/policies/fixed_commission_policy.test.move b/crates/iota-framework/packages/iota-framework/tests/kiosk/policies/fixed_commission_policy.test.move similarity index 90% rename from crates/sui-framework/packages/sui-framework/tests/kiosk/policies/fixed_commission_policy.test.move rename to crates/iota-framework/packages/iota-framework/tests/kiosk/policies/fixed_commission_policy.test.move index 936b274c919..4823912c833 100644 --- a/crates/sui-framework/packages/sui-framework/tests/kiosk/policies/fixed_commission_policy.test.move +++ b/crates/iota-framework/packages/iota-framework/tests/kiosk/policies/fixed_commission_policy.test.move @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] /// An example module implementing a fixed commission for the `TransferPolicy`. /// Follows the "transfer rules" layout and implements each of the steps. -module sui::fixed_commission { - use sui::sui::SUI; - use sui::coin::Coin; - use sui::transfer_policy::{ +module iota::fixed_commission { + use iota::iota::IOTA; + use iota::coin::Coin; + use iota::transfer_policy::{ Self as policy, TransferPolicy, TransferRequest, @@ -42,7 +43,7 @@ module sui::fixed_commission { /// Buyer action: perform required action; /// Complete the requirement on `TransferRequest`. In this case - pay the fixed fee. public fun pay( - policy: &mut TransferPolicy, request: &mut TransferRequest, coin: Coin + policy: &mut TransferPolicy, request: &mut TransferRequest, coin: Coin ) { let paid = request.paid(); let config: &Commission = policy::get_rule(Rule {}, policy); diff --git a/crates/sui-framework/packages/sui-framework/tests/kiosk/policies/item_placed_policy.test.move b/crates/iota-framework/packages/iota-framework/tests/kiosk/policies/item_placed_policy.test.move similarity index 85% rename from crates/sui-framework/packages/sui-framework/tests/kiosk/policies/item_placed_policy.test.move rename to crates/iota-framework/packages/iota-framework/tests/kiosk/policies/item_placed_policy.test.move index dcbadde29f2..245d80276f4 100644 --- a/crates/sui-framework/packages/sui-framework/tests/kiosk/policies/item_placed_policy.test.move +++ b/crates/iota-framework/packages/iota-framework/tests/kiosk/policies/item_placed_policy.test.move @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] /// A Policy that makes sure an item is placed into the `Kiosk` after `purchase`. /// `Kiosk` can be any. -module sui::item_locked_policy { - use sui::kiosk::{Self, Kiosk}; - use sui::transfer_policy::{ +module iota::item_locked_policy { + use iota::kiosk::{Self, Kiosk}; + use iota::transfer_policy::{ Self as policy, TransferPolicy, TransferPolicyCap, diff --git a/crates/sui-framework/packages/sui-framework/tests/kiosk/policies/royalty_policy.test.move b/crates/iota-framework/packages/iota-framework/tests/kiosk/policies/royalty_policy.test.move similarity index 80% rename from crates/sui-framework/packages/sui-framework/tests/kiosk/policies/royalty_policy.test.move rename to crates/iota-framework/packages/iota-framework/tests/kiosk/policies/royalty_policy.test.move index 237cf2dfefb..5cbc77ab71d 100644 --- a/crates/sui-framework/packages/sui-framework/tests/kiosk/policies/royalty_policy.test.move +++ b/crates/iota-framework/packages/iota-framework/tests/kiosk/policies/royalty_policy.test.move @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] /// A `TransferPolicy` Rule which implements percentage-based royalty fee. -module sui::royalty_policy { - use sui::sui::SUI; - use sui::coin::{Self, Coin}; - use sui::transfer_policy::{ +module iota::royalty_policy { + use iota::iota::IOTA; + use iota::coin::{Self, Coin}; + use iota::transfer_policy::{ Self as policy, TransferPolicy, TransferPolicyCap, @@ -43,7 +44,7 @@ module sui::royalty_policy { public fun pay( policy: &mut TransferPolicy, request: &mut TransferRequest, - payment: &mut Coin, + payment: &mut Coin, ctx: &mut TxContext ) { let config: &Config = policy::get_rule(Rule {}, policy); @@ -59,12 +60,12 @@ module sui::royalty_policy { } #[test_only] -module sui::royalty_policy_tests { - use sui::coin; - use sui::sui::SUI; - use sui::royalty_policy; - use sui::transfer_policy as policy; - use sui::transfer_policy_tests as test; +module iota::royalty_policy_tests { + use iota::coin; + use iota::iota::IOTA; + use iota::royalty_policy; + use iota::transfer_policy as policy; + use iota::transfer_policy_tests as test; #[test] fun test_default_flow() { @@ -75,7 +76,7 @@ module sui::royalty_policy_tests { royalty_policy::set(&mut policy, &cap, 100); let mut request = policy::new_request(test::fresh_id(ctx), 100_000, test::fresh_id(ctx)); - let mut payment = coin::mint_for_testing(2000, ctx); + let mut payment = coin::mint_for_testing(2000, ctx); royalty_policy::pay(&mut policy, &mut request, &mut payment, ctx); policy::confirm_request(&policy, request); @@ -88,7 +89,7 @@ module sui::royalty_policy_tests { } #[test] - #[expected_failure(abort_code = sui::royalty_policy::EIncorrectArgument)] + #[expected_failure(abort_code = iota::royalty_policy::EIncorrectArgument)] fun test_incorrect_config() { let ctx = &mut tx_context::dummy(); let (mut policy, cap) = test::prepare(ctx); @@ -98,7 +99,7 @@ module sui::royalty_policy_tests { } #[test] - #[expected_failure(abort_code = sui::royalty_policy::EInsufficientAmount)] + #[expected_failure(abort_code = iota::royalty_policy::EInsufficientAmount)] fun test_insufficient_amount() { let ctx = &mut tx_context::dummy(); let (mut policy, cap) = test::prepare(ctx); @@ -106,9 +107,9 @@ module sui::royalty_policy_tests { // 1% royalty royalty_policy::set(&mut policy, &cap, 100); - // Requires 1_000 MIST, coin has only 999 + // Requires 1_000 MICROS, coin has only 999 let mut request = policy::new_request(test::fresh_id(ctx), 100_000, test::fresh_id(ctx)); - let mut payment = coin::mint_for_testing(999, ctx); + let mut payment = coin::mint_for_testing(999, ctx); royalty_policy::pay(&mut policy, &mut request, &mut payment, ctx); policy::confirm_request(&policy, request); diff --git a/crates/sui-framework/packages/sui-framework/tests/kiosk/policies/witness_policy.test.move b/crates/iota-framework/packages/iota-framework/tests/kiosk/policies/witness_policy.test.move similarity index 88% rename from crates/sui-framework/packages/sui-framework/tests/kiosk/policies/witness_policy.test.move rename to crates/iota-framework/packages/iota-framework/tests/kiosk/policies/witness_policy.test.move index 7d966713a79..3cabed5d168 100644 --- a/crates/sui-framework/packages/sui-framework/tests/kiosk/policies/witness_policy.test.move +++ b/crates/iota-framework/packages/iota-framework/tests/kiosk/policies/witness_policy.test.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] @@ -10,8 +11,8 @@ /// in the `Kiosk`. When an item is placed into the Kiosk, a `PlacedWitness` /// struct is created which can be used to prove that the `T` was placed /// to the `Kiosk`. -module sui::witness_policy { - use sui::transfer_policy::{ +module iota::witness_policy { + use iota::transfer_policy::{ Self as policy, TransferPolicy, TransferPolicyCap, @@ -46,10 +47,10 @@ module sui::witness_policy { } #[test_only] -module sui::witness_policy_tests { - use sui::witness_policy; - use sui::transfer_policy as policy; - use sui::transfer_policy_tests::{ +module iota::witness_policy_tests { + use iota::witness_policy; + use iota::transfer_policy as policy; + use iota::transfer_policy_tests::{ Self as test, Asset }; @@ -76,7 +77,7 @@ module sui::witness_policy_tests { } #[test] - #[expected_failure(abort_code = sui::transfer_policy::EPolicyNotSatisfied)] + #[expected_failure(abort_code = iota::transfer_policy::EPolicyNotSatisfied)] fun test_no_proof() { let ctx = &mut tx_context::dummy(); let (mut policy, cap) = test::prepare(ctx); @@ -90,7 +91,7 @@ module sui::witness_policy_tests { } #[test] - #[expected_failure(abort_code = sui::witness_policy::ERuleNotFound)] + #[expected_failure(abort_code = iota::witness_policy::ERuleNotFound)] fun test_wrong_proof() { let ctx = &mut tx_context::dummy(); let (mut policy, cap) = test::prepare(ctx); diff --git a/crates/sui-framework/packages/sui-framework/tests/kiosk/transfer_policy_tests.move b/crates/iota-framework/packages/iota-framework/tests/kiosk/transfer_policy_tests.move similarity index 88% rename from crates/sui-framework/packages/sui-framework/tests/kiosk/transfer_policy_tests.move rename to crates/iota-framework/packages/iota-framework/tests/kiosk/transfer_policy_tests.move index c14c60a6764..c9b973b1e71 100644 --- a/crates/sui-framework/packages/sui-framework/tests/kiosk/transfer_policy_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/kiosk/transfer_policy_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::malicious_policy { - use sui::transfer_policy::{Self as policy, TransferRequest}; +module iota::malicious_policy { + use iota::transfer_policy::{Self as policy, TransferRequest}; public struct Rule has drop {} @@ -13,12 +14,12 @@ module sui::malicious_policy { } #[test_only] -module sui::transfer_policy_tests { - use sui::transfer_policy::{Self as policy, TransferPolicy, TransferPolicyCap}; - use sui::dummy_policy; - use sui::malicious_policy; - use sui::package; - use sui::coin; +module iota::transfer_policy_tests { + use iota::transfer_policy::{Self as policy, TransferPolicy, TransferPolicyCap}; + use iota::dummy_policy; + use iota::malicious_policy; + use iota::package; + use iota::coin; public struct OTW has drop {} public struct Asset has key, store { id: UID } @@ -85,7 +86,7 @@ module sui::transfer_policy_tests { } #[test] - #[expected_failure(abort_code = sui::transfer_policy::EPolicyNotSatisfied)] + #[expected_failure(abort_code = iota::transfer_policy::EPolicyNotSatisfied)] /// Policy set but not satisfied; fun test_rule_ignored() { let ctx = &mut tx_context::dummy(); @@ -101,7 +102,7 @@ module sui::transfer_policy_tests { } #[test] - #[expected_failure(abort_code = sui::transfer_policy::ERuleAlreadySet)] + #[expected_failure(abort_code = iota::transfer_policy::ERuleAlreadySet)] /// Attempt to add another policy; fun test_rule_exists() { let ctx = &mut tx_context::dummy(); @@ -118,7 +119,7 @@ module sui::transfer_policy_tests { } #[test] - #[expected_failure(abort_code = sui::transfer_policy::EIllegalRule)] + #[expected_failure(abort_code = iota::transfer_policy::EIllegalRule)] /// Attempt to cheat by using another rule approval; fun test_rule_swap() { let ctx = &mut tx_context::dummy(); diff --git a/crates/sui-framework/packages/sui-framework/tests/linked_table_tests.move b/crates/iota-framework/packages/iota-framework/tests/linked_table_tests.move similarity index 94% rename from crates/sui-framework/packages/sui-framework/tests/linked_table_tests.move rename to crates/iota-framework/packages/iota-framework/tests/linked_table_tests.move index 9ec2f754c8c..080a23de8fa 100644 --- a/crates/sui-framework/packages/sui-framework/tests/linked_table_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/linked_table_tests.move @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::linked_table_tests { - use sui::linked_table::{ +module iota::linked_table_tests { + use iota::linked_table::{ Self, LinkedTable, }; - use sui::test_scenario; + use iota::test_scenario; #[test] fun simple_all_functions() { @@ -104,7 +105,7 @@ module sui::linked_table_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldAlreadyExists)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldAlreadyExists)] fun push_front_duplicate() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -115,7 +116,7 @@ module sui::linked_table_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldAlreadyExists)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldAlreadyExists)] fun push_back_duplicate() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -126,7 +127,7 @@ module sui::linked_table_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldAlreadyExists)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldAlreadyExists)] fun push_mixed_duplicate() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -137,7 +138,7 @@ module sui::linked_table_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun borrow_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -147,7 +148,7 @@ module sui::linked_table_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun borrow_mut_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -157,7 +158,7 @@ module sui::linked_table_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun remove_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); diff --git a/crates/sui-framework/packages/sui-framework/tests/math_tests.move b/crates/iota-framework/packages/iota-framework/tests/math_tests.move similarity index 94% rename from crates/sui-framework/packages/sui-framework/tests/math_tests.move rename to crates/iota-framework/packages/iota-framework/tests/math_tests.move index 5f2272cd624..b87618fa184 100644 --- a/crates/sui-framework/packages/sui-framework/tests/math_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/math_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::math_tests { - use sui::math; +module iota::math_tests { + use iota::math; #[test] fun test_max() { diff --git a/crates/sui-framework/packages/sui-framework/tests/object_bag_tests.move b/crates/iota-framework/packages/iota-framework/tests/object_bag_tests.move similarity index 92% rename from crates/sui-framework/packages/sui-framework/tests/object_bag_tests.move rename to crates/iota-framework/packages/iota-framework/tests/object_bag_tests.move index 0968c8dc2d7..92bbc2d3b58 100644 --- a/crates/sui-framework/packages/sui-framework/tests/object_bag_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/object_bag_tests.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::object_bag_tests { - use sui::object_bag; - use sui::test_scenario; +module iota::object_bag_tests { + use iota::object_bag; + use iota::test_scenario; public struct Counter has key, store { id: UID, @@ -56,7 +57,7 @@ module sui::object_bag_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldAlreadyExists)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldAlreadyExists)] fun add_duplicate() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -67,7 +68,7 @@ module sui::object_bag_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun borrow_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -77,7 +78,7 @@ module sui::object_bag_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun borrow_mut_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -87,7 +88,7 @@ module sui::object_bag_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun remove_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -97,7 +98,7 @@ module sui::object_bag_tests { } #[test] - #[expected_failure(abort_code = sui::object_bag::EBagNotEmpty)] + #[expected_failure(abort_code = iota::object_bag::EBagNotEmpty)] fun destroy_non_empty() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); diff --git a/crates/sui-framework/packages/sui-framework/tests/object_table_tests.move b/crates/iota-framework/packages/iota-framework/tests/object_table_tests.move similarity index 90% rename from crates/sui-framework/packages/sui-framework/tests/object_table_tests.move rename to crates/iota-framework/packages/iota-framework/tests/object_table_tests.move index 2bc1d3523f6..0f416054f32 100644 --- a/crates/sui-framework/packages/sui-framework/tests/object_table_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/object_table_tests.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::object_table_tests { - use sui::object_table::{Self, add}; - use sui::test_scenario; +module iota::object_table_tests { + use iota::object_table::{Self, add}; + use iota::test_scenario; public struct Counter has key, store { id: UID, @@ -49,7 +50,7 @@ module sui::object_table_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldAlreadyExists)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldAlreadyExists)] fun add_duplicate() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -60,7 +61,7 @@ module sui::object_table_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun borrow_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -70,7 +71,7 @@ module sui::object_table_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun borrow_mut_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -80,7 +81,7 @@ module sui::object_table_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun remove_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -90,7 +91,7 @@ module sui::object_table_tests { } #[test] - #[expected_failure(abort_code = sui::object_table::ETableNotEmpty)] + #[expected_failure(abort_code = iota::object_table::ETableNotEmpty)] fun destroy_non_empty() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); diff --git a/crates/sui-framework/packages/sui-framework/tests/object_tests.move b/crates/iota-framework/packages/iota-framework/tests/object_tests.move similarity index 89% rename from crates/sui-framework/packages/sui-framework/tests/object_tests.move rename to crates/iota-framework/packages/iota-framework/tests/object_tests.move index 6b821b1e851..d2ecd63eddb 100644 --- a/crates/sui-framework/packages/sui-framework/tests/object_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/object_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::object_tests { - use sui::address; +module iota::object_tests { + use iota::address; const EDifferentAddress: u64 = 0xF000; const EDifferentBytes: u64 = 0xF001; diff --git a/crates/sui-framework/packages/sui-framework/tests/package_tests.move b/crates/iota-framework/packages/iota-framework/tests/package_tests.move similarity index 85% rename from crates/sui-framework/packages/sui-framework/tests/package_tests.move rename to crates/iota-framework/packages/iota-framework/tests/package_tests.move index 65b7405ff52..bce506cbb46 100644 --- a/crates/sui-framework/packages/sui-framework/tests/package_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/package_tests.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::package_tests { - use sui::package::{Self, UpgradeCap, UpgradeTicket}; - use sui::test_utils; - use sui::test_scenario::{Self, Scenario}; +module iota::package_tests { + use iota::package::{Self, UpgradeCap, UpgradeTicket}; + use iota::test_utils; + use iota::test_scenario::{Self, Scenario}; /// OTW for the package_tests module -- it can't actually be a OTW /// (name matching module name) because we need to be able to @@ -80,7 +81,7 @@ module sui::package_tests { while (!policies.is_empty()) { let policy = policies.pop_back(); - let ticket = check_ticket(&mut cap, policy, sui::hash::blake2b256(&vector[policy])); + let ticket = check_ticket(&mut cap, policy, iota::hash::blake2b256(&vector[policy])); let receipt = ticket.test_upgrade(); cap.commit_upgrade(receipt); }; @@ -99,7 +100,7 @@ module sui::package_tests { let version = cap.version(); let ticket = cap.authorize_upgrade( package::dep_only_policy(), - sui::hash::blake2b256(&b"package contents"), + iota::hash::blake2b256(&b"package contents"), ); test_utils::assert_eq(ticket.ticket_policy(), package::dep_only_policy()); @@ -112,7 +113,7 @@ module sui::package_tests { } #[test] - #[expected_failure(abort_code = sui::package::ETooPermissive)] + #[expected_failure(abort_code = iota::package::ETooPermissive)] fun test_failure_to_widen_upgrade_policy() { let mut scenario = test_scenario::begin(@0x1); let mut cap = package::test_publish(@0x42.to_id(), scenario.ctx()); @@ -125,7 +126,7 @@ module sui::package_tests { } #[test] - #[expected_failure(abort_code = sui::package::ETooPermissive)] + #[expected_failure(abort_code = iota::package::ETooPermissive)] fun test_failure_to_authorize_overly_permissive_upgrade() { let mut scenario = test_scenario::begin(@0x1); let mut cap = package::test_publish(@0x42.to_id(), scenario.ctx()); @@ -133,35 +134,35 @@ module sui::package_tests { let _ticket = cap.authorize_upgrade( package::compatible_policy(), - sui::hash::blake2b256(&b"package contents"), + iota::hash::blake2b256(&b"package contents"), ); abort 0 } #[test] - #[expected_failure(abort_code = sui::package::EAlreadyAuthorized)] + #[expected_failure(abort_code = iota::package::EAlreadyAuthorized)] fun test_failure_to_authorize_multiple_upgrades() { let mut scenario = test_scenario::begin(@0x1); let mut cap = package::test_publish(@0x42.to_id(), scenario.ctx()); let _ticket0 = cap.authorize_upgrade( package::compatible_policy(), - sui::hash::blake2b256(&b"package contents 0"), + iota::hash::blake2b256(&b"package contents 0"), ); // It's an error to try and issue more than one simultaneous // upgrade ticket -- this should abort. let _ticket1 = cap.authorize_upgrade( package::compatible_policy(), - sui::hash::blake2b256(&b"package contents 1"), + iota::hash::blake2b256(&b"package contents 1"), ); abort 0 } #[test] - #[expected_failure(abort_code = sui::package::EWrongUpgradeCap)] + #[expected_failure(abort_code = iota::package::EWrongUpgradeCap)] fun test_failure_to_commit_upgrade_to_wrong_cap() { let mut scenario = test_scenario::begin(@0x1); let mut cap0 = package::test_publish(@0x42.to_id(), scenario.ctx()); @@ -169,7 +170,7 @@ module sui::package_tests { let ticket1 = cap1.authorize_upgrade( package::dep_only_policy(), - sui::hash::blake2b256(&b"package contents 1"), + iota::hash::blake2b256(&b"package contents 1"), ); test_utils::assert_eq(ticket1.ticket_policy(), package::dep_only_policy()); diff --git a/crates/sui-framework/packages/sui-framework/tests/pay_tests.move b/crates/iota-framework/packages/iota-framework/tests/pay_tests.move similarity index 79% rename from crates/sui-framework/packages/sui-framework/tests/pay_tests.move rename to crates/iota-framework/packages/iota-framework/tests/pay_tests.move index 8c79b6e5c57..92a0302897f 100644 --- a/crates/sui-framework/packages/sui-framework/tests/pay_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/pay_tests.move @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::pay_tests { - use sui::test_scenario; - use sui::coin::{Self, Coin}; - use sui::pay; - use sui::balance; - use sui::sui::SUI; - use sui::test_utils; +module iota::pay_tests { + use iota::test_scenario; + use iota::coin::{Self, Coin}; + use iota::pay; + use iota::balance; + use iota::iota::IOTA; + use iota::test_utils; const TEST_SENDER_ADDR: address = @0xA11CE; @@ -16,23 +17,23 @@ module sui::pay_tests { fun test_coin_split_n() { let mut scenario = test_scenario::begin(TEST_SENDER_ADDR); let ctx = scenario.ctx(); - let mut coin = coin::mint_for_testing(10, ctx); + let mut coin = coin::mint_for_testing(10, ctx); scenario.next_tx(TEST_SENDER_ADDR); coin.divide_and_keep(3, scenario.ctx()); scenario.next_tx(TEST_SENDER_ADDR); - let coin1 = scenario.take_from_sender>(); + let coin1 = scenario.take_from_sender>(); scenario.next_tx(TEST_SENDER_ADDR); - let coin2 = scenario.take_from_sender>(); + let coin2 = scenario.take_from_sender>(); scenario.next_tx(TEST_SENDER_ADDR); assert!(coin1.value() == 3, 0); assert!(coin2.value() == 3, 0); assert!(coin.value() == 4, 0); assert!( - !scenario.has_most_recent_for_sender>(), + !scenario.has_most_recent_for_sender>(), 1 ); @@ -46,7 +47,7 @@ module sui::pay_tests { fun test_coin_split_n_to_vec() { let mut scenario = test_scenario::begin(TEST_SENDER_ADDR); let ctx = scenario.ctx(); - let mut coin = coin::mint_for_testing(10, ctx); + let mut coin = coin::mint_for_testing(10, ctx); scenario.next_tx(TEST_SENDER_ADDR); let mut split_coins = coin.divide_into_n(3, scenario.ctx()); @@ -69,17 +70,17 @@ module sui::pay_tests { fun test_split_vec() { let mut scenario = test_scenario::begin(TEST_SENDER_ADDR); let ctx = scenario.ctx(); - let mut coin = coin::mint_for_testing(10, ctx); + let mut coin = coin::mint_for_testing(10, ctx); scenario.next_tx(TEST_SENDER_ADDR); let v = vector[1, 4]; coin.split_vec(v, scenario.ctx()); scenario.next_tx(TEST_SENDER_ADDR); - let coin1 = scenario.take_from_sender>(); + let coin1 = scenario.take_from_sender>(); scenario.next_tx(TEST_SENDER_ADDR); - let coin2 = scenario.take_from_sender>(); + let coin2 = scenario.take_from_sender>(); assert!(coin1.value() == 4, 0); assert!(coin2.value() == 1, 0); @@ -95,14 +96,14 @@ module sui::pay_tests { fun test_split_and_transfer() { let mut scenario = test_scenario::begin(TEST_SENDER_ADDR); let ctx = scenario.ctx(); - let mut coin = coin::mint_for_testing(10, ctx); + let mut coin = coin::mint_for_testing(10, ctx); scenario.next_tx(TEST_SENDER_ADDR); // Send 3 of 10 coin.split_and_transfer(3, TEST_SENDER_ADDR, scenario.ctx()); scenario.next_tx(TEST_SENDER_ADDR); - let coin1 = scenario.take_from_sender>(); + let coin1 = scenario.take_from_sender>(); assert!(coin1.value() == 3, 0); assert!(coin.value() == 7, 0); @@ -116,13 +117,13 @@ module sui::pay_tests { fun test_split_and_transfer_fail() { let mut scenario = test_scenario::begin(TEST_SENDER_ADDR); let ctx = scenario.ctx(); - let mut coin = coin::mint_for_testing(10, ctx); + let mut coin = coin::mint_for_testing(10, ctx); scenario.next_tx(TEST_SENDER_ADDR); // Send 20 of 10 (should fail) coin.split_and_transfer(20, TEST_SENDER_ADDR, scenario.ctx()); scenario.next_tx(TEST_SENDER_ADDR); - let coin_transfer_fail = scenario.take_from_sender>(); + let coin_transfer_fail = scenario.take_from_sender>(); assert!(coin_transfer_fail.value() == 7, 0); test_utils::destroy(coin); @@ -134,7 +135,7 @@ module sui::pay_tests { fun test_join_vec_and_transfer() { let mut scenario = test_scenario::begin(TEST_SENDER_ADDR); let ctx = scenario.ctx(); - let mut coin = coin::mint_for_testing(10, ctx); + let mut coin = coin::mint_for_testing(10, ctx); scenario.next_tx(TEST_SENDER_ADDR); // divide_into_n with `n = 4` creates a vector of `n-1` = `3` coins containing balance `2` @@ -142,7 +143,7 @@ module sui::pay_tests { pay::join_vec_and_transfer(coin_vector, TEST_SENDER_ADDR); scenario.next_tx(TEST_SENDER_ADDR); - let coin1 = scenario.take_from_sender>(); + let coin1 = scenario.take_from_sender>(); // result is `3` coins of balance `2` assert!(coin1.value() == 6, 0); diff --git a/crates/iota-framework/packages/iota-framework/tests/prover_tests.move b/crates/iota-framework/packages/iota-framework/tests/prover_tests.move new file mode 100644 index 00000000000..c5c15ec200e --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/tests/prover_tests.move @@ -0,0 +1,46 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module iota::prover_tests { + + public struct Obj has key, store { + id: UID + } + + // ==================================================================== + // Object ownership + // ==================================================================== + + public fun simple_transfer(o: Obj, recipient: address) { + iota::transfer::public_transfer(o, recipient); + } + + public fun simple_share(o: Obj) { + iota::transfer::public_share_object(o) + } + + public fun simple_freeze(o: Obj) { + iota::transfer::public_freeze_object(o) + } + + public fun simple_delete(o: Obj) { + let Obj { id } = o; + id.delete(); + } + + // ==================================================================== + // Dynamic fields + // ==================================================================== + + public fun simple_field_add(o: &mut Obj, n1: u64, v1: u8, n2: u8, v2: u64) { + iota::dynamic_field::add(&mut o.id, n1, v1); + iota::dynamic_field::add(&mut o.id, n2, v2); + } + + public fun simple_field_remove(o: &mut Obj, n1: u64, n2: u8) { + iota::dynamic_field::remove(&mut o.id, n1); + iota::dynamic_field::remove(&mut o.id, n2); + } +} diff --git a/crates/sui-framework/packages/sui-framework/tests/random_tests.move b/crates/iota-framework/packages/iota-framework/tests/random_tests.move similarity index 99% rename from crates/sui-framework/packages/sui-framework/tests/random_tests.move rename to crates/iota-framework/packages/iota-framework/tests/random_tests.move index f62fc9ca9ef..8719afbb22c 100644 --- a/crates/sui-framework/packages/sui-framework/tests/random_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/random_tests.move @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] #[allow(unused_use)] -module sui::random_tests { - use sui::test_utils::assert_eq; - use sui::bcs; - use sui::test_scenario; - use sui::random::{Self, Random}; +module iota::random_tests { + use iota::test_utils::assert_eq; + use iota::bcs; + use iota::test_scenario; + use iota::random::{Self, Random}; // TODO: add a test from https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-22r1a.pdf ? diff --git a/crates/sui-framework/packages/sui-framework/tests/table_tests.move b/crates/iota-framework/packages/iota-framework/tests/table_tests.move similarity index 87% rename from crates/sui-framework/packages/sui-framework/tests/table_tests.move rename to crates/iota-framework/packages/iota-framework/tests/table_tests.move index 5337b16d915..88bc97c8356 100644 --- a/crates/sui-framework/packages/sui-framework/tests/table_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/table_tests.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::table_tests { - use sui::table; - use sui::test_scenario; +module iota::table_tests { + use iota::table; + use iota::test_scenario; #[test] fun simple_all_functions() { @@ -37,7 +38,7 @@ module sui::table_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldAlreadyExists)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldAlreadyExists)] fun add_duplicate() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -48,7 +49,7 @@ module sui::table_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun borrow_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -58,7 +59,7 @@ module sui::table_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun borrow_mut_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -68,7 +69,7 @@ module sui::table_tests { } #[test] - #[expected_failure(abort_code = sui::dynamic_field::EFieldDoesNotExist)] + #[expected_failure(abort_code = iota::dynamic_field::EFieldDoesNotExist)] fun remove_missing() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); @@ -78,7 +79,7 @@ module sui::table_tests { } #[test] - #[expected_failure(abort_code = sui::table::ETableNotEmpty)] + #[expected_failure(abort_code = iota::table::ETableNotEmpty)] fun destroy_non_empty() { let sender = @0x0; let mut scenario = test_scenario::begin(sender); diff --git a/crates/sui-framework/packages/sui-framework/tests/table_vec_tests.move b/crates/iota-framework/packages/iota-framework/tests/table_vec_tests.move similarity index 83% rename from crates/sui-framework/packages/sui-framework/tests/table_vec_tests.move rename to crates/iota-framework/packages/iota-framework/tests/table_vec_tests.move index 7e4103089d7..43434a67511 100644 --- a/crates/sui-framework/packages/sui-framework/tests/table_vec_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/table_vec_tests.move @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::table_vec_tests { - use sui::table_vec; - use sui::test_scenario; +module iota::table_vec_tests { + use iota::table_vec; + use iota::test_scenario; const TEST_SENDER_ADDR: address = @0x1; @@ -34,7 +35,7 @@ module sui::table_vec_tests { } #[test] - #[expected_failure(abort_code = sui::table_vec::ETableNonEmpty)] + #[expected_failure(abort_code = iota::table_vec::ETableNonEmpty)] fun destroy_non_empty_aborts() { let mut scenario = test_scenario::begin(TEST_SENDER_ADDR); let table_vec = table_vec::singleton(1, scenario.ctx()); @@ -43,7 +44,7 @@ module sui::table_vec_tests { } #[test] - #[expected_failure(abort_code = sui::table_vec::EIndexOutOfBound)] + #[expected_failure(abort_code = iota::table_vec::EIndexOutOfBound)] fun pop_back_empty_aborts() { let mut scenario = test_scenario::begin(TEST_SENDER_ADDR); let mut table_vec = table_vec::empty(scenario.ctx()); @@ -53,7 +54,7 @@ module sui::table_vec_tests { } #[test] - #[expected_failure(abort_code = sui::table_vec::EIndexOutOfBound)] + #[expected_failure(abort_code = iota::table_vec::EIndexOutOfBound)] fun borrow_out_of_bounds_aborts() { let mut scenario = test_scenario::begin(TEST_SENDER_ADDR); let table_vec = table_vec::singleton(1, scenario.ctx()); @@ -63,7 +64,7 @@ module sui::table_vec_tests { } #[test] - #[expected_failure(abort_code = sui::table_vec::EIndexOutOfBound)] + #[expected_failure(abort_code = iota::table_vec::EIndexOutOfBound)] fun borrow_mut_out_of_bounds_aborts() { let mut scenario = test_scenario::begin(TEST_SENDER_ADDR); let mut table_vec = table_vec::singleton(1, scenario.ctx()); @@ -73,7 +74,7 @@ module sui::table_vec_tests { } #[test] - #[expected_failure(abort_code = sui::table_vec::EIndexOutOfBound)] + #[expected_failure(abort_code = iota::table_vec::EIndexOutOfBound)] fun swap_out_of_bounds_aborts() { let mut scenario = test_scenario::begin(TEST_SENDER_ADDR); let mut table_vec = table_vec::singleton(1, scenario.ctx()); @@ -93,7 +94,7 @@ module sui::table_vec_tests { } #[test] - #[expected_failure(abort_code = sui::table_vec::EIndexOutOfBound)] + #[expected_failure(abort_code = iota::table_vec::EIndexOutOfBound)] fun swap_same_index_out_of_bounds_aborts() { let mut scenario = test_scenario::begin(TEST_SENDER_ADDR); let mut table_vec = table_vec::singleton(1, scenario.ctx()); diff --git a/crates/sui-framework/packages/sui-framework/tests/test_random_tests.move b/crates/iota-framework/packages/iota-framework/tests/test_random_tests.move similarity index 98% rename from crates/sui-framework/packages/sui-framework/tests/test_random_tests.move rename to crates/iota-framework/packages/iota-framework/tests/test_random_tests.move index 232b452fd91..f72bf44cbe6 100644 --- a/crates/sui-framework/packages/sui-framework/tests/test_random_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/test_random_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::test_random_tests { - use sui::test_random::new; +module iota::test_random_tests { + use iota::test_random::new; #[test] fun test_next_bytes() { diff --git a/crates/sui-framework/packages/sui-framework/tests/test_scenario_tests.move b/crates/iota-framework/packages/iota-framework/tests/test_scenario_tests.move similarity index 97% rename from crates/sui-framework/packages/sui-framework/tests/test_scenario_tests.move rename to crates/iota-framework/packages/iota-framework/tests/test_scenario_tests.move index 85d5fc0c426..f1c7c35e14e 100644 --- a/crates/sui-framework/packages/sui-framework/tests/test_scenario_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/test_scenario_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::test_scenario_tests { - use sui::test_scenario; +module iota::test_scenario_tests { + use iota::test_scenario; const EIdBytesMismatch: u64 = 0; const EValueMismatch: u64 = 1; @@ -654,8 +655,8 @@ module sui::test_scenario_tests { let sender = @0x0; let mut scenario = test_scenario::begin(sender); let mut parent = scenario.new_object(); - sui::dynamic_field::add(&mut parent, b"", 10); - let r = sui::dynamic_field::borrow, u64>(&parent, b""); + iota::dynamic_field::add(&mut parent, b"", 10); + let r = iota::dynamic_field::borrow, u64>(&parent, b""); scenario.end(); assert!(*r == 10, 0); parent.delete(); @@ -667,8 +668,8 @@ module sui::test_scenario_tests { let mut scenario = test_scenario::begin(sender); let mut parent = scenario.new_object(); let id = scenario.new_object(); - sui::dynamic_object_field::add(&mut parent, b"", Object { id, value: 10}); - let obj = sui::dynamic_object_field::borrow, Object>(&parent, b""); + iota::dynamic_object_field::add(&mut parent, b"", Object { id, value: 10}); + let obj = iota::dynamic_object_field::borrow, Object>(&parent, b""); scenario.end(); assert!(obj.value == 10, 0); parent.delete(); @@ -688,7 +689,7 @@ module sui::test_scenario_tests { let obj = scenario.take_from_sender(); assert!(object::id(&obj) == id, 0); assert!(!test_scenario::has_most_recent_for_address(sender), 0); - sui::dynamic_object_field::add(&mut parent, b"", obj); + iota::dynamic_object_field::add(&mut parent, b"", obj); scenario.next_tx(sender); assert!(!test_scenario::has_most_recent_for_address(sender), 0); scenario.end(); @@ -709,7 +710,7 @@ module sui::test_scenario_tests { let obj = scenario.take_shared(); assert!(object::id(&obj) == id, 0); // wraps the object - sui::dynamic_field::add(&mut parent, b"", obj); + iota::dynamic_field::add(&mut parent, b"", obj); scenario.next_tx(sender); abort 42 } @@ -728,7 +729,7 @@ module sui::test_scenario_tests { let obj = scenario.take_immutable(); assert!(object::id(&obj) == id, 0); // wraps the object - sui::dynamic_field::add(&mut parent, b"", obj); + iota::dynamic_field::add(&mut parent, b"", obj); scenario.next_tx(sender); abort 42 } @@ -746,7 +747,7 @@ module sui::test_scenario_tests { scenario.next_tx(sender); let obj = scenario.take_shared(); assert!(object::id(&obj) == id, 0); - sui::dynamic_object_field::add(&mut parent, b"", obj); + iota::dynamic_object_field::add(&mut parent, b"", obj); scenario.next_tx(sender); abort 42 } @@ -764,7 +765,7 @@ module sui::test_scenario_tests { scenario.next_tx(sender); let obj = scenario.take_immutable(); assert!(object::id(&obj) == id, 0); - sui::dynamic_object_field::add(&mut parent, b"", obj); + iota::dynamic_object_field::add(&mut parent, b"", obj); scenario.next_tx(sender); abort 42 } diff --git a/crates/sui-framework/packages/sui-framework/tests/token/token_actions_tests.move b/crates/iota-framework/packages/iota-framework/tests/token/token_actions_tests.move similarity index 96% rename from crates/sui-framework/packages/sui-framework/tests/token/token_actions_tests.move rename to crates/iota-framework/packages/iota-framework/tests/token/token_actions_tests.move index 628676d9e6a..3931ca8d5af 100644 --- a/crates/sui-framework/packages/sui-framework/tests/token/token_actions_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/token/token_actions_tests.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] @@ -6,9 +7,9 @@ /// intended, that the request is well formed and that APIs are usable. /// /// It also tests custom actions which can be implemented by policy owner. -module sui::token_actions_tests { - use sui::token; - use sui::token_test_utils as test; +module iota::token_actions_tests { + use iota::token; + use iota::token_test_utils as test; #[test] /// Scenario: perform a transfer operation, and confirm that the request diff --git a/crates/sui-framework/packages/sui-framework/tests/token/token_config_tests.move b/crates/iota-framework/packages/iota-framework/tests/token/token_config_tests.move similarity index 96% rename from crates/sui-framework/packages/sui-framework/tests/token/token_config_tests.move rename to crates/iota-framework/packages/iota-framework/tests/token/token_config_tests.move index 426388edd1c..db286bb4796 100644 --- a/crates/sui-framework/packages/sui-framework/tests/token/token_config_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/token/token_config_tests.move @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] /// The goal of this module is to test Rule configuration setting and how Rules /// can read / modify the configuration in 'em. -module sui::token_config_tests { - use sui::token_test_utils::{Self as test, TEST}; - use sui::token; +module iota::token_config_tests { + use iota::token_test_utils::{Self as test, TEST}; + use iota::token; /// Rule witness to store confuration for public struct Rule1 has drop {} diff --git a/crates/sui-framework/packages/sui-framework/tests/token/token_public_actions_tests.move b/crates/iota-framework/packages/iota-framework/tests/token/token_public_actions_tests.move similarity index 88% rename from crates/sui-framework/packages/sui-framework/tests/token/token_public_actions_tests.move rename to crates/iota-framework/packages/iota-framework/tests/token/token_public_actions_tests.move index 270fd964c62..747b4aef889 100644 --- a/crates/sui-framework/packages/sui-framework/tests/token/token_public_actions_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/token/token_public_actions_tests.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] /// This module tests `join`, `split`, `zero` and `destroy_zero` functions -module sui::token_public_actions_tests { - use sui::token_test_utils::{Self as test, TEST}; - use sui::token; +module iota::token_public_actions_tests { + use iota::token_test_utils::{Self as test, TEST}; + use iota::token; #[test] /// Scenario: mint a Token, split it, merge back, then issue a zero and diff --git a/crates/sui-framework/packages/sui-framework/tests/token/token_request_tests.move b/crates/iota-framework/packages/iota-framework/tests/token/token_request_tests.move similarity index 96% rename from crates/sui-framework/packages/sui-framework/tests/token/token_request_tests.move rename to crates/iota-framework/packages/iota-framework/tests/token/token_request_tests.move index b97de4bd2a1..43b15c64e7c 100644 --- a/crates/sui-framework/packages/sui-framework/tests/token/token_request_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/token/token_request_tests.move @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] /// This module implements tests for the request formation and approval in the /// `TokenPolicy`. -module sui::token_request_tests { +module iota::token_request_tests { use std::option::none; - use sui::token; - use sui::token_test_utils::{Self as test, TEST}; + use iota::token; + use iota::token_test_utils::{Self as test, TEST}; public struct Rule1 has drop {} public struct Rule2 has drop {} diff --git a/crates/sui-framework/packages/sui-framework/tests/token/token_test_utils.move b/crates/iota-framework/packages/iota-framework/tests/token/token_test_utils.move similarity index 85% rename from crates/sui-framework/packages/sui-framework/tests/token/token_test_utils.move rename to crates/iota-framework/packages/iota-framework/tests/token/token_test_utils.move index 014fc677f99..4e104e4a742 100644 --- a/crates/sui-framework/packages/sui-framework/tests/token/token_test_utils.move +++ b/crates/iota-framework/packages/iota-framework/tests/token/token_test_utils.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] /// This module defines base testing utilities for the -module sui::token_test_utils { - use sui::coin::{Self, TreasuryCap}; - use sui::token::{Self, Token, TokenPolicy, TokenPolicyCap}; +module iota::token_test_utils { + use iota::coin::{Self, TreasuryCap}; + use iota::token::{Self, Token, TokenPolicy, TokenPolicyCap}; /// The type of the test Token. public struct TEST has drop {} @@ -24,7 +25,7 @@ module sui::token_test_utils { #[allow(lint(share_owned))] /// Return `TreasuryCap` (shares it for now). public fun return_treasury_cap(treasury_cap: TreasuryCap) { - sui::transfer::public_share_object(treasury_cap) + iota::transfer::public_share_object(treasury_cap) } /// Get a policy for testing. diff --git a/crates/sui-framework/packages/sui-framework/tests/token/token_treasury_cap_tests.move b/crates/iota-framework/packages/iota-framework/tests/token/token_treasury_cap_tests.move similarity index 88% rename from crates/sui-framework/packages/sui-framework/tests/token/token_treasury_cap_tests.move rename to crates/iota-framework/packages/iota-framework/tests/token/token_treasury_cap_tests.move index 3d4ec5f0968..d81e884d589 100644 --- a/crates/sui-framework/packages/sui-framework/tests/token/token_treasury_cap_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/token/token_treasury_cap_tests.move @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] /// This module implements tests for the TreasuryCap-related functionality such -/// as spending, "flush"-ing, issuing new coins and performing marketplace-like +/// as spending, "flush"-ing, isiotang new coins and performing marketplace-like /// operations. -module sui::token_treasury_cap_tests { - use sui::token_test_utils as test; - use sui::token; +module iota::token_treasury_cap_tests { + use iota::token_test_utils as test; + use iota::token; #[test] /// Scenario: mint and spend a Token, confirm spending request with the diff --git a/crates/sui-framework/packages/sui-framework/tests/tx_context_tests.move b/crates/iota-framework/packages/iota-framework/tests/tx_context_tests.move similarity index 85% rename from crates/sui-framework/packages/sui-framework/tests/tx_context_tests.move rename to crates/iota-framework/packages/iota-framework/tests/tx_context_tests.move index a4b1bf1c86c..437e191444b 100644 --- a/crates/sui-framework/packages/sui-framework/tests/tx_context_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/tx_context_tests.move @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::tx_context_tests { +module iota::tx_context_tests { #[test] fun test_id_generation() { diff --git a/crates/sui-framework/packages/sui-framework/tests/url_tests.move b/crates/iota-framework/packages/iota-framework/tests/url_tests.move similarity index 80% rename from crates/sui-framework/packages/sui-framework/tests/url_tests.move rename to crates/iota-framework/packages/iota-framework/tests/url_tests.move index a9fea4cc9ba..0ab58a49d7f 100644 --- a/crates/sui-framework/packages/sui-framework/tests/url_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/url_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::url_tests { - use sui::url; +module iota::url_tests { + use iota::url; const EUrlStringMismatch: u64 = 1; diff --git a/crates/sui-framework/packages/sui-framework/tests/vec_map_tests.move b/crates/iota-framework/packages/iota-framework/tests/vec_map_tests.move similarity index 96% rename from crates/sui-framework/packages/sui-framework/tests/vec_map_tests.move rename to crates/iota-framework/packages/iota-framework/tests/vec_map_tests.move index c5128eed7c4..f27a8fa3214 100644 --- a/crates/sui-framework/packages/sui-framework/tests/vec_map_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/vec_map_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::vec_map_tests { - use sui::vec_map::{Self, VecMap}; +module iota::vec_map_tests { + use iota::vec_map::{Self, VecMap}; #[test] #[expected_failure(abort_code = vec_map::EKeyAlreadyExists)] diff --git a/crates/sui-framework/packages/sui-framework/tests/vec_set_tests.move b/crates/iota-framework/packages/iota-framework/tests/vec_set_tests.move similarity index 93% rename from crates/sui-framework/packages/sui-framework/tests/vec_set_tests.move rename to crates/iota-framework/packages/iota-framework/tests/vec_set_tests.move index e916fe82c02..1df21668b5f 100644 --- a/crates/sui-framework/packages/sui-framework/tests/vec_set_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/vec_set_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::vec_set_tests { - use sui::vec_set; +module iota::vec_set_tests { + use iota::vec_set; #[test] #[expected_failure(abort_code = vec_set::EKeyAlreadyExists)] diff --git a/crates/iota-framework/packages/iota-framework/tests/verifier_tests.move b/crates/iota-framework/packages/iota-framework/tests/verifier_tests.move new file mode 100644 index 00000000000..aeb6afcf4a8 --- /dev/null +++ b/crates/iota-framework/packages/iota-framework/tests/verifier_tests.move @@ -0,0 +1,36 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +/// Tests if normally illegal (in terms of Iota bytecode verification) code is allowed in tests. +module iota::verifier_tests { + public struct VERIFIER_TESTS has drop {} + + fun init(otw: VERIFIER_TESTS, _: &mut iota::tx_context::TxContext) { + assert!(iota::types::is_one_time_witness(&otw), 0); + } + + #[test] + fun test_init() { + use iota::test_scenario; + let admin = @0xBABE; + + let mut scenario = test_scenario::begin(admin); + let otw = VERIFIER_TESTS{}; + init(otw, scenario.ctx()); + scenario.end(); + } + + fun is_otw(witness: VERIFIER_TESTS): bool { + iota::types::is_one_time_witness(&witness) + } + + #[test] + fun test_otw() { + // we should be able to construct otw in test code + let otw = VERIFIER_TESTS{}; + assert!(is_otw(otw), 0); + } + +} diff --git a/crates/sui-framework/packages/sui-framework/tests/versioned_tests.move b/crates/iota-framework/packages/iota-framework/tests/versioned_tests.move similarity index 87% rename from crates/sui-framework/packages/sui-framework/tests/versioned_tests.move rename to crates/iota-framework/packages/iota-framework/tests/versioned_tests.move index bafd4f97e3c..eab0d613b9e 100644 --- a/crates/sui-framework/packages/sui-framework/tests/versioned_tests.move +++ b/crates/iota-framework/packages/iota-framework/tests/versioned_tests.move @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui::versioned_tests { - use sui::versioned; +module iota::versioned_tests { + use iota::versioned; #[test] fun test_upgrade() { diff --git a/crates/iota-framework/packages/iota-system/Move.lock b/crates/iota-framework/packages/iota-system/Move.lock new file mode 100644 index 00000000000..9128d14190f --- /dev/null +++ b/crates/iota-framework/packages/iota-system/Move.lock @@ -0,0 +1,28 @@ +# @generated by Move, please check-in and do not edit manually. + +[move] +version = 1 +manifest_digest = "68AEB9354EE1D616F6D2293EC721FE3D7E810FEC4FE34197676ECFA3DA72CAE3" +deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600" + +dependencies = [ + { name = "MoveStdlib" }, + { name = "Iota" }, +] + +[[move.package]] +name = "MoveStdlib" +source = { local = "../move-stdlib" } + +[[move.package]] +name = "Iota" +source = { local = "../iota-framework" } + +dependencies = [ + { name = "MoveStdlib" }, +] + +[move.toolchain-version] +compiler-version = "1.22.0" +edition = "legacy" +flavor = "iota" diff --git a/crates/iota-framework/packages/iota-system/Move.toml b/crates/iota-framework/packages/iota-system/Move.toml new file mode 100644 index 00000000000..361b5a39565 --- /dev/null +++ b/crates/iota-framework/packages/iota-system/Move.toml @@ -0,0 +1,12 @@ +[package] +name = "IotaSystem" +version = "0.0.1" +published-at = "0x3" +edition = "2024.beta" + +[dependencies] +MoveStdlib = { local = "../move-stdlib" } +Iota = { local = "../iota-framework" } + +[addresses] +iota_system = "0x3" diff --git a/crates/iota-framework/packages/iota-system/sources/genesis.move b/crates/iota-framework/packages/iota-system/sources/genesis.move new file mode 100644 index 00000000000..68133f283a7 --- /dev/null +++ b/crates/iota-framework/packages/iota-system/sources/genesis.move @@ -0,0 +1,247 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::genesis { + + use iota::balance::{Self, Balance}; + use iota::iota::{Self, IOTA}; + use iota_system::iota_system; + use iota_system::validator::{Self, Validator}; + use iota_system::validator_set; + use iota_system::iota_system_state_inner; + use iota_system::stake_subsidy; + + public struct GenesisValidatorMetadata has drop, copy { + name: vector, + description: vector, + image_url: vector, + project_url: vector, + + iota_address: address, + + gas_price: u64, + commission_rate: u64, + + protocol_public_key: vector, + proof_of_possession: vector, + + network_public_key: vector, + worker_public_key: vector, + + network_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + } + + public struct GenesisChainParameters has drop, copy { + protocol_version: u64, + chain_start_timestamp_ms: u64, + epoch_duration_ms: u64, + + // Stake Subsidy parameters + stake_subsidy_start_epoch: u64, + stake_subsidy_initial_distribution_amount: u64, + stake_subsidy_period_length: u64, + stake_subsidy_decrease_rate: u16, + + // Validator committee parameters + max_validator_count: u64, + min_validator_joining_stake: u64, + validator_low_stake_threshold: u64, + validator_very_low_stake_threshold: u64, + validator_low_stake_grace_period: u64, + } + + public struct TokenDistributionSchedule { + stake_subsidy_fund_micros: u64, + allocations: vector, + } + + public struct TokenAllocation { + recipient_address: address, + amount_micros: u64, + + /// Indicates if this allocation should be staked at genesis and with which validator + staked_with_validator: Option
    , + } + + // Error codes + /// The `create` function was called at a non-genesis epoch. + const ENotCalledAtGenesis: u64 = 0; + /// The `create` function was called with duplicate validators. + const EDuplicateValidator: u64 = 1; + + #[allow(unused_function)] + /// This function will be explicitly called once at genesis. + /// It will create a singleton IotaSystemState object, which contains + /// all the information we need in the system. + fun create( + iota_system_state_id: UID, + mut iota_supply: Balance, + genesis_chain_parameters: GenesisChainParameters, + genesis_validators: vector, + token_distribution_schedule: TokenDistributionSchedule, + ctx: &mut TxContext, + ) { + // Ensure this is only called at genesis + assert!(ctx.epoch() == 0, ENotCalledAtGenesis); + + let TokenDistributionSchedule { + stake_subsidy_fund_micros, + allocations, + } = token_distribution_schedule; + + let subsidy_fund = iota_supply.split(stake_subsidy_fund_micros); + let storage_fund = balance::zero(); + + // Create all the `Validator` structs + let mut validators = vector[]; + let count = genesis_validators.length(); + let mut i = 0; + while (i < count) { + let GenesisValidatorMetadata { + name, + description, + image_url, + project_url, + iota_address, + gas_price, + commission_rate, + protocol_public_key, + proof_of_possession, + network_public_key, + worker_public_key, + network_address, + p2p_address, + primary_address, + worker_address, + } = genesis_validators[i]; + + let validator = validator::new( + iota_address, + protocol_public_key, + network_public_key, + worker_public_key, + proof_of_possession, + name, + description, + image_url, + project_url, + network_address, + p2p_address, + primary_address, + worker_address, + gas_price, + commission_rate, + ctx + ); + + // Ensure that each validator is unique + assert!( + !validator_set::is_duplicate_validator(&validators, &validator), + EDuplicateValidator, + ); + + validators.push_back(validator); + + i = i + 1; + }; + + // Allocate tokens and staking operations + allocate_tokens( + iota_supply, + allocations, + &mut validators, + ctx + ); + + // Activate all validators + activate_validators(&mut validators); + + let system_parameters = iota_system_state_inner::create_system_parameters( + genesis_chain_parameters.epoch_duration_ms, + genesis_chain_parameters.stake_subsidy_start_epoch, + + // Validator committee parameters + genesis_chain_parameters.max_validator_count, + genesis_chain_parameters.min_validator_joining_stake, + genesis_chain_parameters.validator_low_stake_threshold, + genesis_chain_parameters.validator_very_low_stake_threshold, + genesis_chain_parameters.validator_low_stake_grace_period, + + ctx, + ); + + let stake_subsidy = stake_subsidy::create( + subsidy_fund, + genesis_chain_parameters.stake_subsidy_initial_distribution_amount, + genesis_chain_parameters.stake_subsidy_period_length, + genesis_chain_parameters.stake_subsidy_decrease_rate, + ctx, + ); + + iota_system::create( + iota_system_state_id, + validators, + storage_fund, + genesis_chain_parameters.protocol_version, + genesis_chain_parameters.chain_start_timestamp_ms, + system_parameters, + stake_subsidy, + ctx, + ); + } + + fun allocate_tokens( + mut iota_supply: Balance, + mut allocations: vector, + validators: &mut vector, + ctx: &mut TxContext, + ) { + + while (!allocations.is_empty()) { + let TokenAllocation { + recipient_address, + amount_micros, + staked_with_validator, + } = allocations.pop_back(); + + let allocation_balance = iota_supply.split(amount_micros); + + if (staked_with_validator.is_some()) { + let validator_address = staked_with_validator.destroy_some(); + let validator = validator_set::get_validator_mut(validators, validator_address); + validator.request_add_stake_at_genesis( + allocation_balance, + recipient_address, + ctx + ); + } else { + iota::transfer( + allocation_balance.into_coin(ctx), + recipient_address, + ); + }; + }; + allocations.destroy_empty(); + + // Provided allocations must fully allocate the iota_supply and there + // should be none left at this point. + iota_supply.destroy_zero(); + } + + fun activate_validators(validators: &mut vector) { + // Activate all genesis validators + let count = validators.length(); + let mut i = 0; + while (i < count) { + let validator = &mut validators[i]; + validator.activate(0); + + i = i + 1; + }; + + } +} diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move new file mode 100644 index 00000000000..9906271b539 --- /dev/null +++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move @@ -0,0 +1,773 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Iota System State Type Upgrade Guide +/// `IotaSystemState` is a thin wrapper around `IotaSystemStateInner` that provides a versioned interface. +/// The `IotaSystemState` object has a fixed ID 0x5, and the `IotaSystemStateInner` object is stored as a dynamic field. +/// There are a few different ways to upgrade the `IotaSystemStateInner` type: +/// +/// The simplest and one that doesn't involve a real upgrade is to just add dynamic fields to the `extra_fields` field +/// of `IotaSystemStateInner` or any of its sub type. This is useful when we are in a rush, or making a small change, +/// or still experimenting a new field. +/// +/// To properly upgrade the `IotaSystemStateInner` type, we need to ship a new framework that does the following: +/// 1. Define a new `IotaSystemStateInner`type (e.g. `IotaSystemStateInnerV2`). +/// 2. Define a data migration function that migrates the old `IotaSystemStateInner` to the new one (i.e. IotaSystemStateInnerV2). +/// 3. Replace all uses of `IotaSystemStateInner` with `IotaSystemStateInnerV2` in both iota_system.move and iota_system_state_inner.move, +/// with the exception of the `iota_system_state_inner::create` function, which should always return the genesis type. +/// 4. Inside `load_inner_maybe_upgrade` function, check the current version in the wrapper, and if it's not the latest version, +/// call the data migration function to upgrade the inner object. Make sure to also update the version in the wrapper. +/// A detailed example can be found in iota/tests/framework_upgrades/mock_iota_systems/shallow_upgrade. +/// Along with the Move change, we also need to update the Rust code to support the new type. This includes: +/// 1. Define a new `IotaSystemStateInner` struct type that matches the new Move type, and implement the IotaSystemStateTrait. +/// 2. Update the `IotaSystemState` struct to include the new version as a new enum variant. +/// 3. Update the `get_iota_system_state` function to handle the new version. +/// To test that the upgrade will be successful, we need to modify `iota_system_state_production_upgrade_test` test in +/// protocol_version_tests and trigger a real upgrade using the new framework. We will need to keep this directory as old version, +/// put the new framework in a new directory, and run the test to exercise the upgrade. +/// +/// To upgrade Validator type, besides everything above, we also need to: +/// 1. Define a new Validator type (e.g. ValidatorV2). +/// 2. Define a data migration function that migrates the old Validator to the new one (i.e. ValidatorV2). +/// 3. Replace all uses of Validator with ValidatorV2 except the genesis creation function. +/// 4. In validator_wrapper::upgrade_to_latest, check the current version in the wrapper, and if it's not the latest version, +/// call the data migration function to upgrade it. +/// In Rust, we also need to add a new case in `get_validator_from_table`. +/// Note that it is possible to upgrade IotaSystemStateInner without upgrading Validator, but not the other way around. +/// And when we only upgrade IotaSystemStateInner, the version of Validator in the wrapper will not be updated, and hence may become +/// inconsistent with the version of IotaSystemStateInner. This is fine as long as we don't use the Validator version to determine +/// the IotaSystemStateInner version, or vice versa. + +module iota_system::iota_system { + use iota::balance::Balance; + + use iota::coin::Coin; + use iota_system::staking_pool::StakedIota; + use iota::iota::IOTA; + use iota::table::Table; + use iota_system::validator::Validator; + use iota_system::validator_cap::UnverifiedValidatorOperationCap; + use iota_system::iota_system_state_inner::{Self, SystemParameters, IotaSystemStateInner, IotaSystemStateInnerV2}; + use iota_system::stake_subsidy::StakeSubsidy; + use iota_system::staking_pool::PoolTokenExchangeRate; + use iota::dynamic_field; + + #[test_only] use iota::balance; + #[test_only] use iota_system::validator_set::ValidatorSet; + #[test_only] use iota::vec_set::VecSet; + + /* friend iota_system::genesis; */ + + /* #[test_only] */ + /* friend iota_system::governance_test_utils; */ + /* #[test_only] */ + /* friend iota_system::iota_system_tests; */ + + public struct IotaSystemState has key { + id: UID, + version: u64, + } + + const ENotSystemAddress: u64 = 0; + const EWrongInnerVersion: u64 = 1; + + // ==== functions that can only be called by genesis ==== + + /// Create a new IotaSystemState object and make it shared. + /// This function will be called only once in genesis. + public(package) fun create( + id: UID, + validators: vector, + storage_fund: Balance, + protocol_version: u64, + epoch_start_timestamp_ms: u64, + parameters: SystemParameters, + stake_subsidy: StakeSubsidy, + ctx: &mut TxContext, + ) { + let system_state = iota_system_state_inner::create( + validators, + storage_fund, + protocol_version, + epoch_start_timestamp_ms, + parameters, + stake_subsidy, + ctx, + ); + let version = iota_system_state_inner::genesis_system_state_version(); + let mut self = IotaSystemState { + id, + version, + }; + dynamic_field::add(&mut self.id, version, system_state); + transfer::share_object(self); + } + + // ==== entry functions ==== + + /// Can be called by anyone who wishes to become a validator candidate and starts accuring delegated + /// stakes in their staking pool. Once they have at least `MIN_VALIDATOR_JOINING_STAKE` amount of stake they + /// can call `request_add_validator` to officially become an active validator at the next epoch. + /// Aborts if the caller is already a pending or active validator, or a validator candidate. + /// Note: `proof_of_possession` MUST be a valid signature using iota_address and protocol_pubkey_bytes. + /// To produce a valid PoP, run [fn test_proof_of_possession]. + public entry fun request_add_validator_candidate( + wrapper: &mut IotaSystemState, + pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + proof_of_possession: vector, + name: vector, + description: vector, + image_url: vector, + project_url: vector, + net_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + gas_price: u64, + commission_rate: u64, + ctx: &mut TxContext, + ) { + let self = load_system_state_mut(wrapper); + self.request_add_validator_candidate( + pubkey_bytes, + network_pubkey_bytes, + worker_pubkey_bytes, + proof_of_possession, + name, + description, + image_url, + project_url, + net_address, + p2p_address, + primary_address, + worker_address, + gas_price, + commission_rate, + ctx, + ) + } + + /// Called by a validator candidate to remove themselves from the candidacy. After this call + /// their staking pool becomes deactivate. + public entry fun request_remove_validator_candidate( + wrapper: &mut IotaSystemState, + ctx: &mut TxContext, + ) { + let self = load_system_state_mut(wrapper); + self.request_remove_validator_candidate(ctx) + } + + /// Called by a validator candidate to add themselves to the active validator set beginning next epoch. + /// Aborts if the validator is a duplicate with one of the pending or active validators, or if the amount of + /// stake the validator has doesn't meet the min threshold, or if the number of new validators for the next + /// epoch has already reached the maximum. + public entry fun request_add_validator( + wrapper: &mut IotaSystemState, + ctx: &mut TxContext, + ) { + let self = load_system_state_mut(wrapper); + self.request_add_validator(ctx) + } + + /// A validator can call this function to request a removal in the next epoch. + /// We use the sender of `ctx` to look up the validator + /// (i.e. sender must match the iota_address in the validator). + /// At the end of the epoch, the `validator` object will be returned to the iota_address + /// of the validator. + public entry fun request_remove_validator( + wrapper: &mut IotaSystemState, + ctx: &mut TxContext, + ) { + let self = load_system_state_mut(wrapper); + self.request_remove_validator(ctx) + } + + /// A validator can call this entry function to submit a new gas price quote, to be + /// used for the reference gas price calculation at the end of the epoch. + public entry fun request_set_gas_price( + wrapper: &mut IotaSystemState, + cap: &UnverifiedValidatorOperationCap, + new_gas_price: u64, + ) { + let self = load_system_state_mut(wrapper); + self.request_set_gas_price(cap, new_gas_price) + } + + /// This entry function is used to set new gas price for candidate validators + public entry fun set_candidate_validator_gas_price( + wrapper: &mut IotaSystemState, + cap: &UnverifiedValidatorOperationCap, + new_gas_price: u64, + ) { + let self = load_system_state_mut(wrapper); + self.set_candidate_validator_gas_price(cap, new_gas_price) + } + + /// A validator can call this entry function to set a new commission rate, updated at the end of + /// the epoch. + public entry fun request_set_commission_rate( + wrapper: &mut IotaSystemState, + new_commission_rate: u64, + ctx: &mut TxContext, + ) { + let self = load_system_state_mut(wrapper); + self.request_set_commission_rate(new_commission_rate, ctx) + } + + /// This entry function is used to set new commission rate for candidate validators + public entry fun set_candidate_validator_commission_rate( + wrapper: &mut IotaSystemState, + new_commission_rate: u64, + ctx: &mut TxContext, + ) { + let self = load_system_state_mut(wrapper); + self.set_candidate_validator_commission_rate(new_commission_rate, ctx) + } + + /// Add stake to a validator's staking pool. + public entry fun request_add_stake( + wrapper: &mut IotaSystemState, + stake: Coin, + validator_address: address, + ctx: &mut TxContext, + ) { + let staked_iota = request_add_stake_non_entry(wrapper, stake, validator_address, ctx); + transfer::public_transfer(staked_iota, ctx.sender()); + } + + /// The non-entry version of `request_add_stake`, which returns the staked IOTA instead of transferring it to the sender. + public fun request_add_stake_non_entry( + wrapper: &mut IotaSystemState, + stake: Coin, + validator_address: address, + ctx: &mut TxContext, + ): StakedIota { + let self = load_system_state_mut(wrapper); + self.request_add_stake(stake, validator_address, ctx) + } + + /// Add stake to a validator's staking pool using multiple coins. + public entry fun request_add_stake_mul_coin( + wrapper: &mut IotaSystemState, + stakes: vector>, + stake_amount: option::Option, + validator_address: address, + ctx: &mut TxContext, + ) { + let self = load_system_state_mut(wrapper); + let staked_iota = self.request_add_stake_mul_coin(stakes, stake_amount, validator_address, ctx); + transfer::public_transfer(staked_iota, ctx.sender()); + } + + /// Withdraw stake from a validator's staking pool. + public entry fun request_withdraw_stake( + wrapper: &mut IotaSystemState, + staked_iota: StakedIota, + ctx: &mut TxContext, + ) { + let withdrawn_stake = request_withdraw_stake_non_entry(wrapper, staked_iota, ctx); + transfer::public_transfer(withdrawn_stake.into_coin(ctx), ctx.sender()); + } + + /// Non-entry version of `request_withdraw_stake` that returns the withdrawn IOTA instead of transferring it to the sender. + public fun request_withdraw_stake_non_entry( + wrapper: &mut IotaSystemState, + staked_iota: StakedIota, + ctx: &mut TxContext, + ) : Balance { + let self = load_system_state_mut(wrapper); + self.request_withdraw_stake(staked_iota, ctx) + } + + /// Report a validator as a bad or non-performant actor in the system. + /// Succeeds if all the following are satisfied: + /// 1. both the reporter in `cap` and the input `reportee_addr` are active validators. + /// 2. reporter and reportee not the same address. + /// 3. the cap object is still valid. + /// This function is idempotent. + public entry fun report_validator( + wrapper: &mut IotaSystemState, + cap: &UnverifiedValidatorOperationCap, + reportee_addr: address, + ) { + let self = load_system_state_mut(wrapper); + self.report_validator(cap, reportee_addr) + } + + + /// Undo a `report_validator` action. Aborts if + /// 1. the reportee is not a currently active validator or + /// 2. the sender has not previously reported the `reportee_addr`, or + /// 3. the cap is not valid + public entry fun undo_report_validator( + wrapper: &mut IotaSystemState, + cap: &UnverifiedValidatorOperationCap, + reportee_addr: address, + ) { + let self = load_system_state_mut(wrapper); + self.undo_report_validator(cap, reportee_addr) + } + + // ==== validator metadata management functions ==== + + /// Create a new `UnverifiedValidatorOperationCap`, transfer it to the + /// validator and registers it. The original object is thus revoked. + public entry fun rotate_operation_cap( + self: &mut IotaSystemState, + ctx: &mut TxContext, + ) { + let self = load_system_state_mut(self); + self.rotate_operation_cap(ctx) + } + + /// Update a validator's name. + public entry fun update_validator_name( + self: &mut IotaSystemState, + name: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_validator_name(name, ctx) + } + + /// Update a validator's description + public entry fun update_validator_description( + self: &mut IotaSystemState, + description: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_validator_description(description, ctx) + } + + /// Update a validator's image url + public entry fun update_validator_image_url( + self: &mut IotaSystemState, + image_url: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_validator_image_url(image_url, ctx) + } + + /// Update a validator's project url + public entry fun update_validator_project_url( + self: &mut IotaSystemState, + project_url: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_validator_project_url(project_url, ctx) + } + + /// Update a validator's network address. + /// The change will only take effects starting from the next epoch. + public entry fun update_validator_next_epoch_network_address( + self: &mut IotaSystemState, + network_address: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_validator_next_epoch_network_address(network_address, ctx) + } + + /// Update candidate validator's network address. + public entry fun update_candidate_validator_network_address( + self: &mut IotaSystemState, + network_address: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_candidate_validator_network_address(network_address, ctx) + } + + /// Update a validator's p2p address. + /// The change will only take effects starting from the next epoch. + public entry fun update_validator_next_epoch_p2p_address( + self: &mut IotaSystemState, + p2p_address: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_validator_next_epoch_p2p_address(p2p_address, ctx) + } + + /// Update candidate validator's p2p address. + public entry fun update_candidate_validator_p2p_address( + self: &mut IotaSystemState, + p2p_address: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_candidate_validator_p2p_address(p2p_address, ctx) + } + + /// Update a validator's narwhal primary address. + /// The change will only take effects starting from the next epoch. + public entry fun update_validator_next_epoch_primary_address( + self: &mut IotaSystemState, + primary_address: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_validator_next_epoch_primary_address(primary_address, ctx) + } + + /// Update candidate validator's narwhal primary address. + public entry fun update_candidate_validator_primary_address( + self: &mut IotaSystemState, + primary_address: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_candidate_validator_primary_address(primary_address, ctx) + } + + /// Update a validator's narwhal worker address. + /// The change will only take effects starting from the next epoch. + public entry fun update_validator_next_epoch_worker_address( + self: &mut IotaSystemState, + worker_address: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_validator_next_epoch_worker_address(worker_address, ctx) + } + + /// Update candidate validator's narwhal worker address. + public entry fun update_candidate_validator_worker_address( + self: &mut IotaSystemState, + worker_address: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_candidate_validator_worker_address(worker_address, ctx) + } + + /// Update a validator's public key of protocol key and proof of possession. + /// The change will only take effects starting from the next epoch. + public entry fun update_validator_next_epoch_protocol_pubkey( + self: &mut IotaSystemState, + protocol_pubkey: vector, + proof_of_possession: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_validator_next_epoch_protocol_pubkey(protocol_pubkey, proof_of_possession, ctx) + } + + /// Update candidate validator's public key of protocol key and proof of possession. + public entry fun update_candidate_validator_protocol_pubkey( + self: &mut IotaSystemState, + protocol_pubkey: vector, + proof_of_possession: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_candidate_validator_protocol_pubkey(protocol_pubkey, proof_of_possession, ctx) + } + + /// Update a validator's public key of worker key. + /// The change will only take effects starting from the next epoch. + public entry fun update_validator_next_epoch_worker_pubkey( + self: &mut IotaSystemState, + worker_pubkey: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_validator_next_epoch_worker_pubkey(worker_pubkey, ctx) + } + + /// Update candidate validator's public key of worker key. + public entry fun update_candidate_validator_worker_pubkey( + self: &mut IotaSystemState, + worker_pubkey: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_candidate_validator_worker_pubkey(worker_pubkey, ctx) + } + + /// Update a validator's public key of network key. + /// The change will only take effects starting from the next epoch. + public entry fun update_validator_next_epoch_network_pubkey( + self: &mut IotaSystemState, + network_pubkey: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_validator_next_epoch_network_pubkey(network_pubkey, ctx) + } + + /// Update candidate validator's public key of network key. + public entry fun update_candidate_validator_network_pubkey( + self: &mut IotaSystemState, + network_pubkey: vector, + ctx: &TxContext, + ) { + let self = load_system_state_mut(self); + self.update_candidate_validator_network_pubkey(network_pubkey, ctx) + } + + /// Getter of the pool token exchange rate of a staking pool. Works for both active and inactive pools. + public fun pool_exchange_rates( + wrapper: &mut IotaSystemState, + pool_id: &ID + ): &Table { + let self = load_system_state_mut(wrapper); + self.pool_exchange_rates(pool_id) + } + + /// Getter returning addresses of the currently active validators. + public fun active_validator_addresses(wrapper: &mut IotaSystemState): vector
    { + let self = load_system_state(wrapper); + self.active_validator_addresses() + } + + #[allow(unused_function)] + /// This function should be called at the end of an epoch, and advances the system to the next epoch. + /// It does the following things: + /// 1. Add storage charge to the storage fund. + /// 2. Burn the storage rebates from the storage fund. These are already refunded to transaction sender's + /// gas coins. + /// 3. Distribute computation charge to validator stake. + /// 4. Update all validators. + fun advance_epoch( + storage_reward: Balance, + computation_reward: Balance, + wrapper: &mut IotaSystemState, + new_epoch: u64, + next_protocol_version: u64, + storage_rebate: u64, + non_refundable_storage_fee: u64, + storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested + // into storage fund, in basis point. + reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. + epoch_start_timestamp_ms: u64, // Timestamp of the epoch start + ctx: &mut TxContext, + ) : Balance { + let self = load_system_state_mut(wrapper); + // Validator will make a special system call with sender set as 0x0. + assert!(ctx.sender() == @0x0, ENotSystemAddress); + let storage_rebate = self.advance_epoch( + new_epoch, + next_protocol_version, + storage_reward, + computation_reward, + storage_rebate, + non_refundable_storage_fee, + storage_fund_reinvest_rate, + reward_slashing_rate, + epoch_start_timestamp_ms, + ctx, + ); + + storage_rebate + } + + fun load_system_state(self: &mut IotaSystemState): &IotaSystemStateInnerV2 { + load_inner_maybe_upgrade(self) + } + + fun load_system_state_mut(self: &mut IotaSystemState): &mut IotaSystemStateInnerV2 { + load_inner_maybe_upgrade(self) + } + + fun load_inner_maybe_upgrade(self: &mut IotaSystemState): &mut IotaSystemStateInnerV2 { + if (self.version == 1) { + let v1: IotaSystemStateInner = dynamic_field::remove(&mut self.id, self.version); + let v2 = v1.v1_to_v2(); + self.version = 2; + dynamic_field::add(&mut self.id, self.version, v2); + }; + + let inner: &mut IotaSystemStateInnerV2 = dynamic_field::borrow_mut( + &mut self.id, + self.version + ); + assert!(inner.system_state_version() == self.version, EWrongInnerVersion); + inner + } + + #[test_only] + /// Return the current epoch number. Useful for applications that need a coarse-grained concept of time, + /// since epochs are ever-increasing and epoch changes are intended to happen every 24 hours. + public fun epoch(wrapper: &mut IotaSystemState): u64 { + let self = load_system_state(wrapper); + self.epoch() + } + + #[test_only] + /// Returns unix timestamp of the start of current epoch + public fun epoch_start_timestamp_ms(wrapper: &mut IotaSystemState): u64 { + let self = load_system_state(wrapper); + self.epoch_start_timestamp_ms() + } + + #[test_only] + /// Returns the total amount staked with `validator_addr`. + /// Aborts if `validator_addr` is not an active validator. + public fun validator_stake_amount(wrapper: &mut IotaSystemState, validator_addr: address): u64 { + let self = load_system_state(wrapper); + self.validator_stake_amount(validator_addr) + } + + #[test_only] + /// Returns the staking pool id of a given validator. + /// Aborts if `validator_addr` is not an active validator. + public fun validator_staking_pool_id(wrapper: &mut IotaSystemState, validator_addr: address): ID { + let self = load_system_state(wrapper); + self.validator_staking_pool_id(validator_addr) + } + + #[test_only] + /// Returns reference to the staking pool mappings that map pool ids to active validator addresses + public fun validator_staking_pool_mappings(wrapper: &mut IotaSystemState): &Table { + let self = load_system_state(wrapper); + self.validator_staking_pool_mappings() + } + + #[test_only] + /// Returns all the validators who are currently reporting `addr` + public fun get_reporters_of(wrapper: &mut IotaSystemState, addr: address): VecSet
    { + let self = load_system_state(wrapper); + self.get_reporters_of(addr) + } + + #[test_only] + /// Return the current validator set + public fun validators(wrapper: &mut IotaSystemState): &ValidatorSet { + let self = load_system_state(wrapper); + self.validators() + } + + #[test_only] + /// Return the currently active validator by address + public fun active_validator_by_address(self: &mut IotaSystemState, validator_address: address): &Validator { + validators(self).get_active_validator_ref(validator_address) + } + + #[test_only] + /// Return the currently pending validator by address + public fun pending_validator_by_address(self: &mut IotaSystemState, validator_address: address): &Validator { + validators(self).get_pending_validator_ref(validator_address) + } + + #[test_only] + /// Return the currently candidate validator by address + public fun candidate_validator_by_address(self: &mut IotaSystemState, validator_address: address): &Validator { + validators(self).get_candidate_validator_ref(validator_address) + } + + #[test_only] + public fun set_epoch_for_testing(wrapper: &mut IotaSystemState, epoch_num: u64) { + let self = load_system_state_mut(wrapper); + self.set_epoch_for_testing(epoch_num) + } + + #[test_only] + public fun request_add_validator_for_testing( + wrapper: &mut IotaSystemState, + min_joining_stake_for_testing: u64, + ctx: &TxContext, + ) { + let self = load_system_state_mut(wrapper); + self.request_add_validator_for_testing(min_joining_stake_for_testing, ctx) + } + + #[test_only] + public fun get_storage_fund_total_balance(wrapper: &mut IotaSystemState): u64 { + let self = load_system_state(wrapper); + self.get_storage_fund_total_balance() + } + + #[test_only] + public fun get_storage_fund_object_rebates(wrapper: &mut IotaSystemState): u64 { + let self = load_system_state(wrapper); + self.get_storage_fund_object_rebates() + } + + #[test_only] + public fun get_stake_subsidy_distribution_counter(wrapper: &mut IotaSystemState): u64 { + let self = load_system_state(wrapper); + self.get_stake_subsidy_distribution_counter() + } + + // CAUTION: THIS CODE IS ONLY FOR TESTING AND THIS MACRO MUST NEVER EVER BE REMOVED. Creates a + // candidate validator - bypassing the proof of possession check and other metadata validation + // in the process. + #[test_only] + public entry fun request_add_validator_candidate_for_testing( + wrapper: &mut IotaSystemState, + pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + proof_of_possession: vector, + name: vector, + description: vector, + image_url: vector, + project_url: vector, + net_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + gas_price: u64, + commission_rate: u64, + ctx: &mut TxContext, + ) { + let self = load_system_state_mut(wrapper); + self.request_add_validator_candidate_for_testing( + pubkey_bytes, + network_pubkey_bytes, + worker_pubkey_bytes, + proof_of_possession, + name, + description, + image_url, + project_url, + net_address, + p2p_address, + primary_address, + worker_address, + gas_price, + commission_rate, + ctx + ) + } + + // CAUTION: THIS CODE IS ONLY FOR TESTING AND THIS MACRO MUST NEVER EVER BE REMOVED. + #[test_only] + public(package) fun advance_epoch_for_testing( + wrapper: &mut IotaSystemState, + new_epoch: u64, + next_protocol_version: u64, + storage_charge: u64, + computation_charge: u64, + storage_rebate: u64, + non_refundable_storage_fee: u64, + storage_fund_reinvest_rate: u64, + reward_slashing_rate: u64, + epoch_start_timestamp_ms: u64, + ctx: &mut TxContext, + ): Balance { + let storage_reward = balance::create_for_testing(storage_charge); + let computation_reward = balance::create_for_testing(computation_charge); + let storage_rebate = advance_epoch( + storage_reward, + computation_reward, + wrapper, + new_epoch, + next_protocol_version, + storage_rebate, + non_refundable_storage_fee, + storage_fund_reinvest_rate, + reward_slashing_rate, + epoch_start_timestamp_ms, + ctx, + ); + storage_rebate + } +} diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move new file mode 100644 index 00000000000..f4270501b06 --- /dev/null +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -0,0 +1,1155 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::iota_system_state_inner { + use iota::balance::{Self, Balance}; + use iota::coin::Coin; + use iota_system::staking_pool::{stake_activation_epoch, StakedIota}; + use iota::iota::IOTA; + use iota_system::validator::{Self, Validator}; + use iota_system::validator_set::{Self, ValidatorSet}; + use iota_system::validator_cap::{UnverifiedValidatorOperationCap, ValidatorOperationCap}; + use iota_system::stake_subsidy::StakeSubsidy; + use iota_system::storage_fund::{Self, StorageFund}; + use iota_system::staking_pool::PoolTokenExchangeRate; + use iota::vec_map::{Self, VecMap}; + use iota::vec_set::{Self, VecSet}; + use iota::event; + use iota::table::Table; + use iota::bag::Bag; + use iota::bag; + + /* friend iota_system::genesis; */ + /* friend iota_system::iota_system; */ + + /* #[test_only] */ + /* friend iota_system::governance_test_utils; */ + + // same as in validator_set + const ACTIVE_VALIDATOR_ONLY: u8 = 1; + const ACTIVE_OR_PENDING_VALIDATOR: u8 = 2; + const ANY_VALIDATOR: u8 = 3; + + const SYSTEM_STATE_VERSION_V1: u64 = 1; + + /// A list of system config parameters. + public struct SystemParameters has store { + /// The duration of an epoch, in milliseconds. + epoch_duration_ms: u64, + + /// The starting epoch in which stake subsidies start being paid out + stake_subsidy_start_epoch: u64, + + /// Maximum number of active validators at any moment. + /// We do not allow the number of validators in any epoch to go above this. + max_validator_count: u64, + + /// Lower-bound on the amount of stake required to become a validator. + min_validator_joining_stake: u64, + + /// Validators with stake amount below `validator_low_stake_threshold` are considered to + /// have low stake and will be escorted out of the validator set after being below this + /// threshold for more than `validator_low_stake_grace_period` number of epochs. + validator_low_stake_threshold: u64, + + /// Validators with stake below `validator_very_low_stake_threshold` will be removed + /// immediately at epoch change, no grace period. + validator_very_low_stake_threshold: u64, + + /// A validator can have stake below `validator_low_stake_threshold` + /// for this many epochs before being kicked out. + validator_low_stake_grace_period: u64, + + /// Any extra fields that's not defined statically. + extra_fields: Bag, + } + + /// Added min_validator_count. + public struct SystemParametersV2 has store { + /// The duration of an epoch, in milliseconds. + epoch_duration_ms: u64, + + /// The starting epoch in which stake subsidies start being paid out + stake_subsidy_start_epoch: u64, + + /// Minimum number of active validators at any moment. + min_validator_count: u64, + + /// Maximum number of active validators at any moment. + /// We do not allow the number of validators in any epoch to go above this. + max_validator_count: u64, + + /// Lower-bound on the amount of stake required to become a validator. + min_validator_joining_stake: u64, + + /// Validators with stake amount below `validator_low_stake_threshold` are considered to + /// have low stake and will be escorted out of the validator set after being below this + /// threshold for more than `validator_low_stake_grace_period` number of epochs. + validator_low_stake_threshold: u64, + + /// Validators with stake below `validator_very_low_stake_threshold` will be removed + /// immediately at epoch change, no grace period. + validator_very_low_stake_threshold: u64, + + /// A validator can have stake below `validator_low_stake_threshold` + /// for this many epochs before being kicked out. + validator_low_stake_grace_period: u64, + + /// Any extra fields that's not defined statically. + extra_fields: Bag, + } + + /// The top-level object containing all information of the Iota system. + public struct IotaSystemStateInner has store { + /// The current epoch ID, starting from 0. + epoch: u64, + /// The current protocol version, starting from 1. + protocol_version: u64, + /// The current version of the system state data structure type. + /// This is always the same as IotaSystemState.version. Keeping a copy here so that + /// we know what version it is by inspecting IotaSystemStateInner as well. + system_state_version: u64, + /// Contains all information about the validators. + validators: ValidatorSet, + /// The storage fund. + storage_fund: StorageFund, + /// A list of system config parameters. + parameters: SystemParameters, + /// The reference gas price for the current epoch. + reference_gas_price: u64, + /// A map storing the records of validator reporting each other. + /// There is an entry in the map for each validator that has been reported + /// at least once. The entry VecSet contains all the validators that reported + /// them. If a validator has never been reported they don't have an entry in this map. + /// This map persists across epoch: a peer continues being in a reported state until the + /// reporter doesn't explicitly remove their report. + /// Note that in case we want to support validator address change in future, + /// the reports should be based on validator ids + validator_report_records: VecMap>, + /// Schedule of stake subsidies given out each epoch. + stake_subsidy: StakeSubsidy, + + /// Whether the system is running in a downgraded safe mode due to a non-recoverable bug. + /// This is set whenever we failed to execute advance_epoch, and ended up executing advance_epoch_safe_mode. + /// It can be reset once we are able to successfully execute advance_epoch. + /// The rest of the fields starting with `safe_mode_` are accmulated during safe mode + /// when advance_epoch_safe_mode is executed. They will eventually be processed once we + /// are out of safe mode. + safe_mode: bool, + safe_mode_storage_rewards: Balance, + safe_mode_computation_rewards: Balance, + safe_mode_storage_rebates: u64, + safe_mode_non_refundable_storage_fee: u64, + + /// Unix timestamp of the current epoch start + epoch_start_timestamp_ms: u64, + /// Any extra fields that's not defined statically. + extra_fields: Bag, + } + + /// Uses SystemParametersV2 as the parameters. + public struct IotaSystemStateInnerV2 has store { + /// The current epoch ID, starting from 0. + epoch: u64, + /// The current protocol version, starting from 1. + protocol_version: u64, + /// The current version of the system state data structure type. + /// This is always the same as IotaSystemState.version. Keeping a copy here so that + /// we know what version it is by inspecting IotaSystemStateInner as well. + system_state_version: u64, + /// Contains all information about the validators. + validators: ValidatorSet, + /// The storage fund. + storage_fund: StorageFund, + /// A list of system config parameters. + parameters: SystemParametersV2, + /// The reference gas price for the current epoch. + reference_gas_price: u64, + /// A map storing the records of validator reporting each other. + /// There is an entry in the map for each validator that has been reported + /// at least once. The entry VecSet contains all the validators that reported + /// them. If a validator has never been reported they don't have an entry in this map. + /// This map persists across epoch: a peer continues being in a reported state until the + /// reporter doesn't explicitly remove their report. + /// Note that in case we want to support validator address change in future, + /// the reports should be based on validator ids + validator_report_records: VecMap>, + /// Schedule of stake subsidies given out each epoch. + stake_subsidy: StakeSubsidy, + + /// Whether the system is running in a downgraded safe mode due to a non-recoverable bug. + /// This is set whenever we failed to execute advance_epoch, and ended up executing advance_epoch_safe_mode. + /// It can be reset once we are able to successfully execute advance_epoch. + /// The rest of the fields starting with `safe_mode_` are accmulated during safe mode + /// when advance_epoch_safe_mode is executed. They will eventually be processed once we + /// are out of safe mode. + safe_mode: bool, + safe_mode_storage_rewards: Balance, + safe_mode_computation_rewards: Balance, + safe_mode_storage_rebates: u64, + safe_mode_non_refundable_storage_fee: u64, + + /// Unix timestamp of the current epoch start + epoch_start_timestamp_ms: u64, + /// Any extra fields that's not defined statically. + extra_fields: Bag, + } + + /// Event containing system-level epoch information, emitted during + /// the epoch advancement transaction. + public struct SystemEpochInfoEvent has copy, drop { + epoch: u64, + protocol_version: u64, + reference_gas_price: u64, + total_stake: u64, + storage_fund_reinvestment: u64, + storage_charge: u64, + storage_rebate: u64, + storage_fund_balance: u64, + stake_subsidy_amount: u64, + total_gas_fees: u64, + total_stake_rewards_distributed: u64, + leftover_storage_fund_inflow: u64, + } + + // Errors + const ENotValidator: u64 = 0; + const ELimitExceeded: u64 = 1; + #[allow(unused_const)] + const ENotSystemAddress: u64 = 2; + const ECannotReportOneself: u64 = 3; + const EReportRecordNotFound: u64 = 4; + const EBpsTooLarge: u64 = 5; + const EStakeWithdrawBeforeActivation: u64 = 6; + const ESafeModeGasNotProcessed: u64 = 7; + const EAdvancedToWrongEpoch: u64 = 8; + + const BASIS_POINT_DENOMINATOR: u128 = 10000; + + // ==== functions that can only be called by genesis ==== + + /// Create a new IotaSystemState object and make it shared. + /// This function will be called only once in genesis. + public(package) fun create( + validators: vector, + initial_storage_fund: Balance, + protocol_version: u64, + epoch_start_timestamp_ms: u64, + parameters: SystemParameters, + stake_subsidy: StakeSubsidy, + ctx: &mut TxContext, + ): IotaSystemStateInner { + let validators = validator_set::new(validators, ctx); + let reference_gas_price = validators.derive_reference_gas_price(); + // This type is fixed as it's created at genesis. It should not be updated during type upgrade. + let system_state = IotaSystemStateInner { + epoch: 0, + protocol_version, + system_state_version: genesis_system_state_version(), + validators, + storage_fund: storage_fund::new(initial_storage_fund), + parameters, + reference_gas_price, + validator_report_records: vec_map::empty(), + stake_subsidy, + safe_mode: false, + safe_mode_storage_rewards: balance::zero(), + safe_mode_computation_rewards: balance::zero(), + safe_mode_storage_rebates: 0, + safe_mode_non_refundable_storage_fee: 0, + epoch_start_timestamp_ms, + extra_fields: bag::new(ctx), + }; + system_state + } + + public(package) fun create_system_parameters( + epoch_duration_ms: u64, + stake_subsidy_start_epoch: u64, + + // Validator committee parameters + max_validator_count: u64, + min_validator_joining_stake: u64, + validator_low_stake_threshold: u64, + validator_very_low_stake_threshold: u64, + validator_low_stake_grace_period: u64, + ctx: &mut TxContext, + ): SystemParameters { + SystemParameters { + epoch_duration_ms, + stake_subsidy_start_epoch, + max_validator_count, + min_validator_joining_stake, + validator_low_stake_threshold, + validator_very_low_stake_threshold, + validator_low_stake_grace_period, + extra_fields: bag::new(ctx), + } + } + + public(package) fun v1_to_v2(self: IotaSystemStateInner): IotaSystemStateInnerV2 { + let IotaSystemStateInner { + epoch, + protocol_version, + system_state_version: _, + validators, + storage_fund, + parameters, + reference_gas_price, + validator_report_records, + stake_subsidy, + safe_mode, + safe_mode_storage_rewards, + safe_mode_computation_rewards, + safe_mode_storage_rebates, + safe_mode_non_refundable_storage_fee, + epoch_start_timestamp_ms, + extra_fields: state_extra_fields, + } = self; + let SystemParameters { + epoch_duration_ms, + stake_subsidy_start_epoch, + max_validator_count, + min_validator_joining_stake, + validator_low_stake_threshold, + validator_very_low_stake_threshold, + validator_low_stake_grace_period, + extra_fields: param_extra_fields, + } = parameters; + IotaSystemStateInnerV2 { + epoch, + protocol_version, + system_state_version: 2, + validators, + storage_fund, + parameters: SystemParametersV2 { + epoch_duration_ms, + stake_subsidy_start_epoch, + min_validator_count: 4, + max_validator_count, + min_validator_joining_stake, + validator_low_stake_threshold, + validator_very_low_stake_threshold, + validator_low_stake_grace_period, + extra_fields: param_extra_fields, + }, + reference_gas_price, + validator_report_records, + stake_subsidy, + safe_mode, + safe_mode_storage_rewards, + safe_mode_computation_rewards, + safe_mode_storage_rebates, + safe_mode_non_refundable_storage_fee, + epoch_start_timestamp_ms, + extra_fields: state_extra_fields + } + } + + // ==== public(friend) functions ==== + + /// Can be called by anyone who wishes to become a validator candidate and starts accuring delegated + /// stakes in their staking pool. Once they have at least `MIN_VALIDATOR_JOINING_STAKE` amount of stake they + /// can call `request_add_validator` to officially become an active validator at the next epoch. + /// Aborts if the caller is already a pending or active validator, or a validator candidate. + /// Note: `proof_of_possession` MUST be a valid signature using iota_address and protocol_pubkey_bytes. + /// To produce a valid PoP, run [fn test_proof_of_possession]. + public(package) fun request_add_validator_candidate( + self: &mut IotaSystemStateInnerV2, + pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + proof_of_possession: vector, + name: vector, + description: vector, + image_url: vector, + project_url: vector, + net_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + gas_price: u64, + commission_rate: u64, + ctx: &mut TxContext, + ) { + let validator = validator::new( + ctx.sender(), + pubkey_bytes, + network_pubkey_bytes, + worker_pubkey_bytes, + proof_of_possession, + name, + description, + image_url, + project_url, + net_address, + p2p_address, + primary_address, + worker_address, + gas_price, + commission_rate, + ctx + ); + + self.validators.request_add_validator_candidate(validator, ctx); + } + + /// Called by a validator candidate to remove themselves from the candidacy. After this call + /// their staking pool becomes deactivate. + public(package) fun request_remove_validator_candidate( + self: &mut IotaSystemStateInnerV2, + ctx: &mut TxContext, + ) { + self.validators.request_remove_validator_candidate(ctx); + } + + /// Called by a validator candidate to add themselves to the active validator set beginning next epoch. + /// Aborts if the validator is a duplicate with one of the pending or active validators, or if the amount of + /// stake the validator has doesn't meet the min threshold, or if the number of new validators for the next + /// epoch has already reached the maximum. + public(package) fun request_add_validator( + self: &mut IotaSystemStateInnerV2, + ctx: &TxContext, + ) { + assert!( + self.validators.next_epoch_validator_count() < self.parameters.max_validator_count, + ELimitExceeded, + ); + + self.validators.request_add_validator(self.parameters.min_validator_joining_stake, ctx); + } + + /// A validator can call this function to request a removal in the next epoch. + /// We use the sender of `ctx` to look up the validator + /// (i.e. sender must match the iota_address in the validator). + /// At the end of the epoch, the `validator` object will be returned to the iota_address + /// of the validator. + public(package) fun request_remove_validator( + self: &mut IotaSystemStateInnerV2, + ctx: &TxContext, + ) { + // Only check min validator condition if the current number of validators satisfy the constraint. + // This is so that if we somehow already are in a state where we have less than min validators, it no longer matters + // and is ok to stay so. This is useful for a test setup. + if (self.validators.active_validators().length() >= self.parameters.min_validator_count) { + assert!( + self.validators.next_epoch_validator_count() > self.parameters.min_validator_count, + ELimitExceeded, + ); + }; + + self.validators.request_remove_validator(ctx) + } + + /// A validator can call this function to submit a new gas price quote, to be + /// used for the reference gas price calculation at the end of the epoch. + public(package) fun request_set_gas_price( + self: &mut IotaSystemStateInnerV2, + cap: &UnverifiedValidatorOperationCap, + new_gas_price: u64, + ) { + // Verify the represented address is an active or pending validator, and the capability is still valid. + let verified_cap = self.validators.verify_cap(cap, ACTIVE_OR_PENDING_VALIDATOR); + let validator = self.validators.get_validator_mut_with_verified_cap(&verified_cap, false /* include_candidate */); + + validator.request_set_gas_price(verified_cap, new_gas_price); + } + + /// This function is used to set new gas price for candidate validators + public(package) fun set_candidate_validator_gas_price( + self: &mut IotaSystemStateInnerV2, + cap: &UnverifiedValidatorOperationCap, + new_gas_price: u64, + ) { + // Verify the represented address is an active or pending validator, and the capability is still valid. + let verified_cap = self.validators.verify_cap(cap, ANY_VALIDATOR); + let candidate = self.validators.get_validator_mut_with_verified_cap(&verified_cap, true /* include_candidate */); + candidate.set_candidate_gas_price(verified_cap, new_gas_price) + } + + /// A validator can call this function to set a new commission rate, updated at the end of + /// the epoch. + public(package) fun request_set_commission_rate( + self: &mut IotaSystemStateInnerV2, + new_commission_rate: u64, + ctx: &TxContext, + ) { + self.validators.request_set_commission_rate( + new_commission_rate, + ctx + ) + } + + /// This function is used to set new commission rate for candidate validators + public(package) fun set_candidate_validator_commission_rate( + self: &mut IotaSystemStateInnerV2, + new_commission_rate: u64, + ctx: &TxContext, + ) { + let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); + candidate.set_candidate_commission_rate(new_commission_rate) + } + + /// Add stake to a validator's staking pool. + public(package) fun request_add_stake( + self: &mut IotaSystemStateInnerV2, + stake: Coin, + validator_address: address, + ctx: &mut TxContext, + ) : StakedIota { + self.validators.request_add_stake( + validator_address, + stake.into_balance(), + ctx, + ) + } + + /// Add stake to a validator's staking pool using multiple coins. + public(package) fun request_add_stake_mul_coin( + self: &mut IotaSystemStateInnerV2, + stakes: vector>, + stake_amount: option::Option, + validator_address: address, + ctx: &mut TxContext, + ) : StakedIota { + let balance = extract_coin_balance(stakes, stake_amount, ctx); + self.validators.request_add_stake(validator_address, balance, ctx) + } + + /// Withdraw some portion of a stake from a validator's staking pool. + public(package) fun request_withdraw_stake( + self: &mut IotaSystemStateInnerV2, + staked_iota: StakedIota, + ctx: &TxContext, + ) : Balance { + assert!( + stake_activation_epoch(&staked_iota) <= ctx.epoch(), + EStakeWithdrawBeforeActivation + ); + self.validators.request_withdraw_stake(staked_iota, ctx) + } + + /// Report a validator as a bad or non-performant actor in the system. + /// Succeeds if all the following are satisfied: + /// 1. both the reporter in `cap` and the input `reportee_addr` are active validators. + /// 2. reporter and reportee not the same address. + /// 3. the cap object is still valid. + /// This function is idempotent. + public(package) fun report_validator( + self: &mut IotaSystemStateInnerV2, + cap: &UnverifiedValidatorOperationCap, + reportee_addr: address, + ) { + // Reportee needs to be an active validator + assert!(self.validators.is_active_validator_by_iota_address(reportee_addr), ENotValidator); + // Verify the represented reporter address is an active validator, and the capability is still valid. + let verified_cap = self.validators.verify_cap(cap, ACTIVE_VALIDATOR_ONLY); + report_validator_impl(verified_cap, reportee_addr, &mut self.validator_report_records); + } + + + /// Undo a `report_validator` action. Aborts if + /// 1. the reportee is not a currently active validator or + /// 2. the sender has not previously reported the `reportee_addr`, or + /// 3. the cap is not valid + public(package) fun undo_report_validator( + self: &mut IotaSystemStateInnerV2, + cap: &UnverifiedValidatorOperationCap, + reportee_addr: address, + ) { + let verified_cap = self.validators.verify_cap(cap, ACTIVE_VALIDATOR_ONLY); + undo_report_validator_impl(verified_cap, reportee_addr, &mut self.validator_report_records); + } + + fun report_validator_impl( + verified_cap: ValidatorOperationCap, + reportee_addr: address, + validator_report_records: &mut VecMap>, + ) { + let reporter_address = *verified_cap.verified_operation_cap_address(); + assert!(reporter_address != reportee_addr, ECannotReportOneself); + if (!validator_report_records.contains(&reportee_addr)) { + validator_report_records.insert(reportee_addr, vec_set::singleton(reporter_address)); + } else { + let reporters = validator_report_records.get_mut(&reportee_addr); + if (!reporters.contains(&reporter_address)) { + reporters.insert(reporter_address); + } + } + } + + fun undo_report_validator_impl( + verified_cap: ValidatorOperationCap, + reportee_addr: address, + validator_report_records: &mut VecMap>, + ) { + assert!(validator_report_records.contains(&reportee_addr), EReportRecordNotFound); + let reporters = validator_report_records.get_mut(&reportee_addr); + + let reporter_addr = *verified_cap.verified_operation_cap_address(); + assert!(reporters.contains(&reporter_addr), EReportRecordNotFound); + + reporters.remove(&reporter_addr); + if (reporters.is_empty()) { + validator_report_records.remove(&reportee_addr); + } + } + + // ==== validator metadata management functions ==== + + /// Create a new `UnverifiedValidatorOperationCap`, transfer it to the + /// validator and registers it. The original object is thus revoked. + public(package) fun rotate_operation_cap( + self: &mut IotaSystemStateInnerV2, + ctx: &mut TxContext, + ) { + let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); + validator.new_unverified_validator_operation_cap_and_transfer(ctx); + } + + /// Update a validator's name. + public(package) fun update_validator_name( + self: &mut IotaSystemStateInnerV2, + name: vector, + ctx: &TxContext, + ) { + let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); + + validator.update_name(name); + } + + /// Update a validator's description + public(package) fun update_validator_description( + self: &mut IotaSystemStateInnerV2, + description: vector, + ctx: &TxContext, + ) { + let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); + validator.update_description(description); + } + + /// Update a validator's image url + public(package) fun update_validator_image_url( + self: &mut IotaSystemStateInnerV2, + image_url: vector, + ctx: &TxContext, + ) { + let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); + validator.update_image_url(image_url); + } + + /// Update a validator's project url + public(package) fun update_validator_project_url( + self: &mut IotaSystemStateInnerV2, + project_url: vector, + ctx: &TxContext, + ) { + let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); + validator.update_project_url(project_url); + } + + /// Update a validator's network address. + /// The change will only take effects starting from the next epoch. + public(package) fun update_validator_next_epoch_network_address( + self: &mut IotaSystemStateInnerV2, + network_address: vector, + ctx: &TxContext, + ) { + let validator = self.validators.get_validator_mut_with_ctx(ctx); + validator.update_next_epoch_network_address(network_address); + let validator :&Validator = validator; // Force immutability for the following call + self.validators.assert_no_pending_or_active_duplicates(validator); + } + + /// Update candidate validator's network address. + public(package) fun update_candidate_validator_network_address( + self: &mut IotaSystemStateInnerV2, + network_address: vector, + ctx: &TxContext, + ) { + let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); + candidate.update_candidate_network_address(network_address); + } + + /// Update a validator's p2p address. + /// The change will only take effects starting from the next epoch. + public(package) fun update_validator_next_epoch_p2p_address( + self: &mut IotaSystemStateInnerV2, + p2p_address: vector, + ctx: &TxContext, + ) { + let validator = self.validators.get_validator_mut_with_ctx(ctx); + validator.update_next_epoch_p2p_address(p2p_address); + let validator :&Validator = validator; // Force immutability for the following call + self.validators.assert_no_pending_or_active_duplicates(validator); + } + + /// Update candidate validator's p2p address. + public(package) fun update_candidate_validator_p2p_address( + self: &mut IotaSystemStateInnerV2, + p2p_address: vector, + ctx: &TxContext, + ) { + let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); + candidate.update_candidate_p2p_address(p2p_address); + } + + /// Update a validator's narwhal primary address. + /// The change will only take effects starting from the next epoch. + public(package) fun update_validator_next_epoch_primary_address( + self: &mut IotaSystemStateInnerV2, + primary_address: vector, + ctx: &TxContext, + ) { + let validator = self.validators.get_validator_mut_with_ctx(ctx); + validator.update_next_epoch_primary_address(primary_address); + } + + /// Update candidate validator's narwhal primary address. + public(package) fun update_candidate_validator_primary_address( + self: &mut IotaSystemStateInnerV2, + primary_address: vector, + ctx: &TxContext, + ) { + let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); + candidate.update_candidate_primary_address(primary_address); + } + + /// Update a validator's narwhal worker address. + /// The change will only take effects starting from the next epoch. + public(package) fun update_validator_next_epoch_worker_address( + self: &mut IotaSystemStateInnerV2, + worker_address: vector, + ctx: &TxContext, + ) { + let validator = self.validators.get_validator_mut_with_ctx(ctx); + validator.update_next_epoch_worker_address(worker_address); + } + + /// Update candidate validator's narwhal worker address. + public(package) fun update_candidate_validator_worker_address( + self: &mut IotaSystemStateInnerV2, + worker_address: vector, + ctx: &TxContext, + ) { + let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); + candidate.update_candidate_worker_address(worker_address); + } + + /// Update a validator's public key of protocol key and proof of possession. + /// The change will only take effects starting from the next epoch. + public(package) fun update_validator_next_epoch_protocol_pubkey( + self: &mut IotaSystemStateInnerV2, + protocol_pubkey: vector, + proof_of_possession: vector, + ctx: &TxContext, + ) { + let validator = self.validators.get_validator_mut_with_ctx(ctx); + validator.update_next_epoch_protocol_pubkey(protocol_pubkey, proof_of_possession); + let validator :&Validator = validator; // Force immutability for the following call + self.validators.assert_no_pending_or_active_duplicates(validator); + } + + /// Update candidate validator's public key of protocol key and proof of possession. + public(package) fun update_candidate_validator_protocol_pubkey( + self: &mut IotaSystemStateInnerV2, + protocol_pubkey: vector, + proof_of_possession: vector, + ctx: &TxContext, + ) { + let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); + candidate.update_candidate_protocol_pubkey(protocol_pubkey, proof_of_possession); + } + + /// Update a validator's public key of worker key. + /// The change will only take effects starting from the next epoch. + public(package) fun update_validator_next_epoch_worker_pubkey( + self: &mut IotaSystemStateInnerV2, + worker_pubkey: vector, + ctx: &TxContext, + ) { + let validator = self.validators.get_validator_mut_with_ctx(ctx); + validator.update_next_epoch_worker_pubkey(worker_pubkey); + let validator :&Validator = validator; // Force immutability for the following call + self.validators.assert_no_pending_or_active_duplicates(validator); + } + + /// Update candidate validator's public key of worker key. + public(package) fun update_candidate_validator_worker_pubkey( + self: &mut IotaSystemStateInnerV2, + worker_pubkey: vector, + ctx: &TxContext, + ) { + let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); + candidate.update_candidate_worker_pubkey(worker_pubkey); + } + + /// Update a validator's public key of network key. + /// The change will only take effects starting from the next epoch. + public(package) fun update_validator_next_epoch_network_pubkey( + self: &mut IotaSystemStateInnerV2, + network_pubkey: vector, + ctx: &TxContext, + ) { + let validator = self.validators.get_validator_mut_with_ctx(ctx); + validator.update_next_epoch_network_pubkey(network_pubkey); + let validator :&Validator = validator; // Force immutability for the following call + self.validators.assert_no_pending_or_active_duplicates(validator); + } + + /// Update candidate validator's public key of network key. + public(package) fun update_candidate_validator_network_pubkey( + self: &mut IotaSystemStateInnerV2, + network_pubkey: vector, + ctx: &TxContext, + ) { + let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); + candidate.update_candidate_network_pubkey(network_pubkey); + } + + /// This function should be called at the end of an epoch, and advances the system to the next epoch. + /// It does the following things: + /// 1. Add storage charge to the storage fund. + /// 2. Burn the storage rebates from the storage fund. These are already refunded to transaction sender's + /// gas coins. + /// 3. Distribute computation charge to validator stake. + /// 4. Update all validators. + public(package) fun advance_epoch( + self: &mut IotaSystemStateInnerV2, + new_epoch: u64, + next_protocol_version: u64, + mut storage_reward: Balance, + mut computation_reward: Balance, + mut storage_rebate_amount: u64, + mut non_refundable_storage_fee_amount: u64, + storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested + // into storage fund, in basis point. + reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. + epoch_start_timestamp_ms: u64, // Timestamp of the epoch start + ctx: &mut TxContext, + ) : Balance { + let prev_epoch_start_timestamp = self.epoch_start_timestamp_ms; + self.epoch_start_timestamp_ms = epoch_start_timestamp_ms; + + let bps_denominator_u64 = BASIS_POINT_DENOMINATOR as u64; + // Rates can't be higher than 100%. + assert!( + storage_fund_reinvest_rate <= bps_denominator_u64 + && reward_slashing_rate <= bps_denominator_u64, + EBpsTooLarge, + ); + + // TODO: remove this in later upgrade. + if (self.parameters.stake_subsidy_start_epoch > 0) { + self.parameters.stake_subsidy_start_epoch = 20; + }; + + // Accumulate the gas summary during safe_mode before processing any rewards: + let safe_mode_storage_rewards = self.safe_mode_storage_rewards.withdraw_all(); + storage_reward.join(safe_mode_storage_rewards); + let safe_mode_computation_rewards = self.safe_mode_computation_rewards.withdraw_all(); + computation_reward.join(safe_mode_computation_rewards); + storage_rebate_amount = storage_rebate_amount + self.safe_mode_storage_rebates; + self.safe_mode_storage_rebates = 0; + non_refundable_storage_fee_amount = non_refundable_storage_fee_amount + self.safe_mode_non_refundable_storage_fee; + self.safe_mode_non_refundable_storage_fee = 0; + + let total_validators_stake = self.validators.total_stake(); + let storage_fund_balance = self.storage_fund.total_balance(); + let total_stake = storage_fund_balance + total_validators_stake; + + let storage_charge = storage_reward.value(); + let computation_charge = computation_reward.value(); + + // Include stake subsidy in the rewards given out to validators and stakers. + // Delay distributing any stake subsidies until after `stake_subsidy_start_epoch`. + // And if this epoch is shorter than the regular epoch duration, don't distribute any stake subsidy. + let stake_subsidy = + if (ctx.epoch() >= self.parameters.stake_subsidy_start_epoch && + epoch_start_timestamp_ms >= prev_epoch_start_timestamp + self.parameters.epoch_duration_ms) + { + self.stake_subsidy.advance_epoch() + } else { + balance::zero() + }; + + let stake_subsidy_amount = stake_subsidy.value(); + computation_reward.join(stake_subsidy); + + let total_stake_u128 = total_stake as u128; + let computation_charge_u128 = computation_charge as u128; + + let storage_fund_reward_amount = storage_fund_balance as u128 * computation_charge_u128 / total_stake_u128; + let mut storage_fund_reward = computation_reward.split(storage_fund_reward_amount as u64); + let storage_fund_reinvestment_amount = + storage_fund_reward_amount * (storage_fund_reinvest_rate as u128) / BASIS_POINT_DENOMINATOR; + let storage_fund_reinvestment = storage_fund_reward.split( + storage_fund_reinvestment_amount as u64, + ); + + self.epoch = self.epoch + 1; + // Sanity check to make sure we are advancing to the right epoch. + assert!(new_epoch == self.epoch, EAdvancedToWrongEpoch); + + let computation_reward_amount_before_distribution = computation_reward.value(); + let storage_fund_reward_amount_before_distribution = storage_fund_reward.value(); + + self.validators.advance_epoch( + &mut computation_reward, + &mut storage_fund_reward, + &mut self.validator_report_records, + reward_slashing_rate, + self.parameters.validator_low_stake_threshold, + self.parameters.validator_very_low_stake_threshold, + self.parameters.validator_low_stake_grace_period, + ctx, + ); + + let new_total_stake = self.validators.total_stake(); + + let computation_reward_amount_after_distribution = computation_reward.value(); + let storage_fund_reward_amount_after_distribution = storage_fund_reward.value(); + let computation_reward_distributed = computation_reward_amount_before_distribution - computation_reward_amount_after_distribution; + let storage_fund_reward_distributed = storage_fund_reward_amount_before_distribution - storage_fund_reward_amount_after_distribution; + + self.protocol_version = next_protocol_version; + + // Derive the reference gas price for the new epoch + self.reference_gas_price = self.validators.derive_reference_gas_price(); + // Because of precision issues with integer divisions, we expect that there will be some + // remaining balance in `storage_fund_reward` and `computation_reward`. + // All of these go to the storage fund. + let mut leftover_staking_rewards = storage_fund_reward; + leftover_staking_rewards.join(computation_reward); + let leftover_storage_fund_inflow = leftover_staking_rewards.value(); + + let refunded_storage_rebate = + self.storage_fund.advance_epoch( + storage_reward, + storage_fund_reinvestment, + leftover_staking_rewards, + storage_rebate_amount, + non_refundable_storage_fee_amount, + ); + + event::emit( + SystemEpochInfoEvent { + epoch: self.epoch, + protocol_version: self.protocol_version, + reference_gas_price: self.reference_gas_price, + total_stake: new_total_stake, + storage_charge, + storage_fund_reinvestment: storage_fund_reinvestment_amount as u64, + storage_rebate: storage_rebate_amount, + storage_fund_balance: self.storage_fund.total_balance(), + stake_subsidy_amount, + total_gas_fees: computation_charge, + total_stake_rewards_distributed: computation_reward_distributed + storage_fund_reward_distributed, + leftover_storage_fund_inflow, + } + ); + self.safe_mode = false; + // Double check that the gas from safe mode has been processed. + assert!(self.safe_mode_storage_rebates == 0 + && self.safe_mode_storage_rewards.value() == 0 + && self.safe_mode_computation_rewards.value() == 0, ESafeModeGasNotProcessed); + + // Return the storage rebate split from storage fund that's already refunded to the transaction senders. + // This will be burnt at the last step of epoch change programmable transaction. + refunded_storage_rebate + } + + /// Return the current epoch number. Useful for applications that need a coarse-grained concept of time, + /// since epochs are ever-increasing and epoch changes are intended to happen every 24 hours. + public(package) fun epoch(self: &IotaSystemStateInnerV2): u64 { + self.epoch + } + + public(package) fun protocol_version(self: &IotaSystemStateInnerV2): u64 { + self.protocol_version + } + + public(package) fun system_state_version(self: &IotaSystemStateInnerV2): u64 { + self.system_state_version + } + + /// This function always return the genesis system state version, which is used to create the system state in genesis. + /// It should never change for a given network. + public(package) fun genesis_system_state_version(): u64 { + SYSTEM_STATE_VERSION_V1 + } + + /// Returns unix timestamp of the start of current epoch + public(package) fun epoch_start_timestamp_ms(self: &IotaSystemStateInnerV2): u64 { + self.epoch_start_timestamp_ms + } + + /// Returns the total amount staked with `validator_addr`. + /// Aborts if `validator_addr` is not an active validator. + public(package) fun validator_stake_amount(self: &IotaSystemStateInnerV2, validator_addr: address): u64 { + self.validators.validator_total_stake_amount(validator_addr) + } + + /// Returns the staking pool id of a given validator. + /// Aborts if `validator_addr` is not an active validator. + public(package) fun validator_staking_pool_id(self: &IotaSystemStateInnerV2, validator_addr: address): ID { + + self.validators.validator_staking_pool_id(validator_addr) + } + + /// Returns reference to the staking pool mappings that map pool ids to active validator addresses + public(package) fun validator_staking_pool_mappings(self: &IotaSystemStateInnerV2): &Table { + + self.validators.staking_pool_mappings() + } + + /// Returns all the validators who are currently reporting `addr` + public(package) fun get_reporters_of(self: &IotaSystemStateInnerV2, addr: address): VecSet
    { + + if (self.validator_report_records.contains(&addr)) { + self.validator_report_records[&addr] + } else { + vec_set::empty() + } + } + + public(package) fun get_storage_fund_total_balance(self: &IotaSystemStateInnerV2): u64 { + self.storage_fund.total_balance() + } + + public(package) fun get_storage_fund_object_rebates(self: &IotaSystemStateInnerV2): u64 { + self.storage_fund.total_object_storage_rebates() + } + + public(package) fun pool_exchange_rates( + self: &mut IotaSystemStateInnerV2, + pool_id: &ID + ): &Table { + let validators = &mut self.validators; + validators.pool_exchange_rates(pool_id) + } + + public(package) fun active_validator_addresses(self: &IotaSystemStateInnerV2): vector
    { + let validator_set = &self.validators; + validator_set.active_validator_addresses() + } + + #[allow(lint(self_transfer))] + /// Extract required Balance from vector of Coin, transfer the remainder back to sender. + fun extract_coin_balance(mut coins: vector>, amount: option::Option, ctx: &mut TxContext): Balance { + let mut merged_coin = coins.pop_back(); + merged_coin.join_vec(coins); + + let mut total_balance = merged_coin.into_balance(); + // return the full amount if amount is not specified + if (amount.is_some()) { + let amount = amount.destroy_some(); + let balance = total_balance.split(amount); + // transfer back the remainder if non zero. + if (total_balance.value() > 0) { + transfer::public_transfer(total_balance.into_coin(ctx), ctx.sender()); + } else { + total_balance.destroy_zero(); + }; + balance + } else { + total_balance + } + } + + #[test_only] + /// Return the current validator set + public(package) fun validators(self: &IotaSystemStateInnerV2): &ValidatorSet { + &self.validators + } + + #[test_only] + /// Return the currently active validator by address + public(package) fun active_validator_by_address(self: &IotaSystemStateInnerV2, validator_address: address): &Validator { + self.validators().get_active_validator_ref(validator_address) + } + + #[test_only] + /// Return the currently pending validator by address + public(package) fun pending_validator_by_address(self: &IotaSystemStateInnerV2, validator_address: address): &Validator { + self.validators().get_pending_validator_ref(validator_address) + } + + #[test_only] + /// Return the currently candidate validator by address + public(package) fun candidate_validator_by_address(self: &IotaSystemStateInnerV2, validator_address: address): &Validator { + validators(self).get_candidate_validator_ref(validator_address) + } + + #[test_only] + public(package) fun get_stake_subsidy_distribution_counter(self: &IotaSystemStateInnerV2): u64 { + self.stake_subsidy.get_distribution_counter() + } + + #[test_only] + public(package) fun set_epoch_for_testing(self: &mut IotaSystemStateInnerV2, epoch_num: u64) { + self.epoch = epoch_num + } + + #[test_only] + public(package) fun request_add_validator_for_testing( + self: &mut IotaSystemStateInnerV2, + min_joining_stake_for_testing: u64, + ctx: &TxContext, + ) { + assert!( + self.validators.next_epoch_validator_count() < self.parameters.max_validator_count, + ELimitExceeded, + ); + + self.validators.request_add_validator(min_joining_stake_for_testing, ctx); + } + + // CAUTION: THIS CODE IS ONLY FOR TESTING AND THIS MACRO MUST NEVER EVER BE REMOVED. Creates a + // candidate validator - bypassing the proof of possession check and other metadata validation + // in the process. + #[test_only] + public(package) fun request_add_validator_candidate_for_testing( + self: &mut IotaSystemStateInnerV2, + pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + proof_of_possession: vector, + name: vector, + description: vector, + image_url: vector, + project_url: vector, + net_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + gas_price: u64, + commission_rate: u64, + ctx: &mut TxContext, + ) { + let validator = validator::new_for_testing( + ctx.sender(), + pubkey_bytes, + network_pubkey_bytes, + worker_pubkey_bytes, + proof_of_possession, + name, + description, + image_url, + project_url, + net_address, + p2p_address, + primary_address, + worker_address, + option::none(), + gas_price, + commission_rate, + false, // not an initial validator active at genesis + ctx + ); + + self.validators.request_add_validator_candidate(validator, ctx); + } + +} diff --git a/crates/sui-framework/packages/sui-system/sources/stake_subsidy.move b/crates/iota-framework/packages/iota-system/sources/stake_subsidy.move similarity index 85% rename from crates/sui-framework/packages/sui-system/sources/stake_subsidy.move rename to crates/iota-framework/packages/iota-system/sources/stake_subsidy.move index 7290b5b004b..411503f899e 100644 --- a/crates/sui-framework/packages/sui-system/sources/stake_subsidy.move +++ b/crates/iota-framework/packages/iota-system/sources/stake_subsidy.move @@ -1,22 +1,23 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui_system::stake_subsidy { - use sui::balance::Balance; - use sui::math; - use sui::sui::SUI; - use sui::bag::Bag; - use sui::bag; +module iota_system::stake_subsidy { + use iota::balance::Balance; + use iota::math; + use iota::iota::IOTA; + use iota::bag::Bag; + use iota::bag; - /* friend sui_system::genesis; */ - /* friend sui_system::sui_system_state_inner; */ + /* friend iota_system::genesis; */ + /* friend iota_system::iota_system_state_inner; */ /* #[test_only] */ - /* friend sui_system::governance_test_utils; */ + /* friend iota_system::governance_test_utils; */ public struct StakeSubsidy has store { - /// Balance of SUI set aside for stake subsidies that will be drawn down over time. - balance: Balance, + /// Balance of IOTA set aside for stake subsidies that will be drawn down over time. + balance: Balance, /// Count of the number of times stake subsidies have been distributed. distribution_counter: u64, @@ -41,7 +42,7 @@ module sui_system::stake_subsidy { const ESubsidyDecreaseRateTooLarge: u64 = 0; public(package) fun create( - balance: Balance, + balance: Balance, initial_distribution_amount: u64, stake_subsidy_period_length: u64, stake_subsidy_decrease_rate: u16, @@ -64,7 +65,7 @@ module sui_system::stake_subsidy { } /// Advance the epoch counter and draw down the subsidy for the epoch. - public(package) fun advance_epoch(self: &mut StakeSubsidy): Balance { + public(package) fun advance_epoch(self: &mut StakeSubsidy): Balance { // Take the minimum of the reward amount and the remaining balance in // order to ensure we don't overdraft the remaining stake subsidy // balance diff --git a/crates/iota-framework/packages/iota-system/sources/staking_pool.move b/crates/iota-framework/packages/iota-system/sources/staking_pool.move new file mode 100644 index 00000000000..ebb6ed47fe3 --- /dev/null +++ b/crates/iota-framework/packages/iota-system/sources/staking_pool.move @@ -0,0 +1,473 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_const)] +module iota_system::staking_pool { + use iota::balance::{Self, Balance}; + use iota::iota::IOTA; + use iota::math; + use iota::table::{Self, Table}; + use iota::bag::Bag; + use iota::bag; + + /* friend iota_system::validator; */ + /* friend iota_system::validator_set; */ + + /// StakedIota objects cannot be split to below this amount. + const MIN_STAKING_THRESHOLD: u64 = 1_000_000_000; // 1 IOTA + + const EInsufficientPoolTokenBalance: u64 = 0; + const EWrongPool: u64 = 1; + const EWithdrawAmountCannotBeZero: u64 = 2; + const EInsufficientIotaTokenBalance: u64 = 3; + const EInsufficientRewardsPoolBalance: u64 = 4; + const EDestroyNonzeroBalance: u64 = 5; + const ETokenTimeLockIsSome: u64 = 6; + const EWrongDelegation: u64 = 7; + const EPendingDelegationDoesNotExist: u64 = 8; + const ETokenBalancesDoNotMatchExchangeRate: u64 = 9; + const EDelegationToInactivePool: u64 = 10; + const EDeactivationOfInactivePool: u64 = 11; + const EIncompatibleStakedIota: u64 = 12; + const EWithdrawalInSameEpoch: u64 = 13; + const EPoolAlreadyActive: u64 = 14; + const EPoolNotPreactive: u64 = 15; + const EActivationOfInactivePool: u64 = 16; + const EDelegationOfZeroIota: u64 = 17; + const EStakedIotaBelowThreshold: u64 = 18; + + /// A staking pool embedded in each validator struct in the system state object. + public struct StakingPool has key, store { + id: UID, + /// The epoch at which this pool became active. + /// The value is `None` if the pool is pre-active and `Some()` if active or inactive. + activation_epoch: Option, + /// The epoch at which this staking pool ceased to be active. `None` = {pre-active, active}, + /// `Some()` if in-active, and it was de-activated at epoch ``. + deactivation_epoch: Option, + /// The total number of IOTA tokens in this pool, including the IOTA in the rewards_pool, as well as in all the principal + /// in the `StakedIota` object, updated at epoch boundaries. + iota_balance: u64, + /// The epoch stake rewards will be added here at the end of each epoch. + rewards_pool: Balance, + /// Total number of pool tokens issued by the pool. + pool_token_balance: u64, + /// Exchange rate history of previous epochs. Key is the epoch number. + /// The entries start from the `activation_epoch` of this pool and contains exchange rates at the beginning of each epoch, + /// i.e., right after the rewards for the previous epoch have been deposited into the pool. + exchange_rates: Table, + /// Pending stake amount for this epoch, emptied at epoch boundaries. + pending_stake: u64, + /// Pending stake withdrawn during the current epoch, emptied at epoch boundaries. + /// This includes both the principal and rewards IOTA withdrawn. + pending_total_iota_withdraw: u64, + /// Pending pool token withdrawn during the current epoch, emptied at epoch boundaries. + pending_pool_token_withdraw: u64, + /// Any extra fields that's not defined statically. + extra_fields: Bag, + } + + /// Struct representing the exchange rate of the stake pool token to IOTA. + public struct PoolTokenExchangeRate has store, copy, drop { + iota_amount: u64, + pool_token_amount: u64, + } + + /// A self-custodial object holding the staked IOTA tokens. + public struct StakedIota has key, store { + id: UID, + /// ID of the staking pool we are staking with. + pool_id: ID, + /// The epoch at which the stake becomes active. + stake_activation_epoch: u64, + /// The staked IOTA tokens. + principal: Balance, + } + + // ==== initializer ==== + + /// Create a new, empty staking pool. + public(package) fun new(ctx: &mut TxContext) : StakingPool { + let exchange_rates = table::new(ctx); + StakingPool { + id: object::new(ctx), + activation_epoch: option::none(), + deactivation_epoch: option::none(), + iota_balance: 0, + rewards_pool: balance::zero(), + pool_token_balance: 0, + exchange_rates, + pending_stake: 0, + pending_total_iota_withdraw: 0, + pending_pool_token_withdraw: 0, + extra_fields: bag::new(ctx), + } + } + + // ==== stake requests ==== + + /// Request to stake to a staking pool. The stake starts counting at the beginning of the next epoch, + public(package) fun request_add_stake( + pool: &mut StakingPool, + stake: Balance, + stake_activation_epoch: u64, + ctx: &mut TxContext + ) : StakedIota { + let iota_amount = stake.value(); + assert!(!is_inactive(pool), EDelegationToInactivePool); + assert!(iota_amount > 0, EDelegationOfZeroIota); + let staked_iota = StakedIota { + id: object::new(ctx), + pool_id: object::id(pool), + stake_activation_epoch, + principal: stake, + }; + pool.pending_stake = pool.pending_stake + iota_amount; + staked_iota + } + + /// Request to withdraw the given stake plus rewards from a staking pool. + /// Both the principal and corresponding rewards in IOTA are withdrawn. + /// A proportional amount of pool token withdraw is recorded and processed at epoch change time. + public(package) fun request_withdraw_stake( + pool: &mut StakingPool, + staked_iota: StakedIota, + ctx: &TxContext + ) : Balance { + let (pool_token_withdraw_amount, mut principal_withdraw) = + withdraw_from_principal(pool, staked_iota); + let principal_withdraw_amount = principal_withdraw.value(); + + let rewards_withdraw = withdraw_rewards( + pool, principal_withdraw_amount, pool_token_withdraw_amount, ctx.epoch() + ); + let total_iota_withdraw_amount = principal_withdraw_amount + rewards_withdraw.value(); + + pool.pending_total_iota_withdraw = pool.pending_total_iota_withdraw + total_iota_withdraw_amount; + pool.pending_pool_token_withdraw = pool.pending_pool_token_withdraw + pool_token_withdraw_amount; + + // If the pool is inactive, we immediately process the withdrawal. + if (is_inactive(pool)) process_pending_stake_withdraw(pool); + + // TODO: implement withdraw bonding period here. + principal_withdraw.join(rewards_withdraw); + principal_withdraw + } + + /// Withdraw the principal IOTA stored in the StakedIota object, and calculate the corresponding amount of pool + /// tokens using exchange rate at staking epoch. + /// Returns values are amount of pool tokens withdrawn and withdrawn principal portion of IOTA. + public(package) fun withdraw_from_principal( + pool: &StakingPool, + staked_iota: StakedIota, + ) : (u64, Balance) { + + // Check that the stake information matches the pool. + assert!(staked_iota.pool_id == object::id(pool), EWrongPool); + + let exchange_rate_at_staking_epoch = pool_token_exchange_rate_at_epoch(pool, staked_iota.stake_activation_epoch); + let principal_withdraw = unwrap_staked_iota(staked_iota); + let pool_token_withdraw_amount = get_token_amount( + &exchange_rate_at_staking_epoch, + principal_withdraw.value() + ); + + ( + pool_token_withdraw_amount, + principal_withdraw, + ) + } + + fun unwrap_staked_iota(staked_iota: StakedIota): Balance { + let StakedIota { + id, + pool_id: _, + stake_activation_epoch: _, + principal, + } = staked_iota; + object::delete(id); + principal + } + + /// Allows calling `.into_balance()` on `StakedIota` to invoke `unwrap_staked_iota` + public use fun unwrap_staked_iota as StakedIota.into_balance; + + // ==== functions called at epoch boundaries === + + /// Called at epoch advancement times to add rewards (in IOTA) to the staking pool. + public(package) fun deposit_rewards(pool: &mut StakingPool, rewards: Balance) { + pool.iota_balance = pool.iota_balance + rewards.value(); + pool.rewards_pool.join(rewards); + } + + public(package) fun process_pending_stakes_and_withdraws(pool: &mut StakingPool, ctx: &TxContext) { + let new_epoch = ctx.epoch() + 1; + process_pending_stake_withdraw(pool); + process_pending_stake(pool); + pool.exchange_rates.add( + new_epoch, + PoolTokenExchangeRate { iota_amount: pool.iota_balance, pool_token_amount: pool.pool_token_balance }, + ); + check_balance_invariants(pool, new_epoch); + } + + /// Called at epoch boundaries to process pending stake withdraws requested during the epoch. + /// Also called immediately upon withdrawal if the pool is inactive. + fun process_pending_stake_withdraw(pool: &mut StakingPool) { + pool.iota_balance = pool.iota_balance - pool.pending_total_iota_withdraw; + pool.pool_token_balance = pool.pool_token_balance - pool.pending_pool_token_withdraw; + pool.pending_total_iota_withdraw = 0; + pool.pending_pool_token_withdraw = 0; + } + + /// Called at epoch boundaries to process the pending stake. + public(package) fun process_pending_stake(pool: &mut StakingPool) { + // Use the most up to date exchange rate with the rewards deposited and withdraws effectuated. + let latest_exchange_rate = + PoolTokenExchangeRate { iota_amount: pool.iota_balance, pool_token_amount: pool.pool_token_balance }; + pool.iota_balance = pool.iota_balance + pool.pending_stake; + pool.pool_token_balance = get_token_amount(&latest_exchange_rate, pool.iota_balance); + pool.pending_stake = 0; + } + + /// This function does the following: + /// 1. Calculates the total amount of IOTA (including principal and rewards) that the provided pool tokens represent + /// at the current exchange rate. + /// 2. Using the above number and the given `principal_withdraw_amount`, calculates the rewards portion of the + /// stake we should withdraw. + /// 3. Withdraws the rewards portion from the rewards pool at the current exchange rate. We only withdraw the rewards + /// portion because the principal portion was already taken out of the staker's self custodied StakedIota. + fun withdraw_rewards( + pool: &mut StakingPool, + principal_withdraw_amount: u64, + pool_token_withdraw_amount: u64, + epoch: u64, + ) : Balance { + let exchange_rate = pool_token_exchange_rate_at_epoch(pool, epoch); + let total_iota_withdraw_amount = get_iota_amount(&exchange_rate, pool_token_withdraw_amount); + let mut reward_withdraw_amount = + if (total_iota_withdraw_amount >= principal_withdraw_amount) + total_iota_withdraw_amount - principal_withdraw_amount + else 0; + // This may happen when we are withdrawing everything from the pool and + // the rewards pool balance may be less than reward_withdraw_amount. + // TODO: FIGURE OUT EXACTLY WHY THIS CAN HAPPEN. + reward_withdraw_amount = math::min(reward_withdraw_amount, pool.rewards_pool.value()); + pool.rewards_pool.split(reward_withdraw_amount) + } + + // ==== preactive pool related ==== + + /// Called by `validator` module to activate a staking pool. + public(package) fun activate_staking_pool(pool: &mut StakingPool, activation_epoch: u64) { + // Add the initial exchange rate to the table. + pool.exchange_rates.add( + activation_epoch, + initial_exchange_rate() + ); + // Check that the pool is preactive and not inactive. + assert!(is_preactive(pool), EPoolAlreadyActive); + assert!(!is_inactive(pool), EActivationOfInactivePool); + // Fill in the active epoch. + pool.activation_epoch.fill(activation_epoch); + } + + // ==== inactive pool related ==== + + /// Deactivate a staking pool by setting the `deactivation_epoch`. After + /// this pool deactivation, the pool stops earning rewards. Only stake + /// withdraws can be made to the pool. + public(package) fun deactivate_staking_pool(pool: &mut StakingPool, deactivation_epoch: u64) { + // We can't deactivate an already deactivated pool. + assert!(!is_inactive(pool), EDeactivationOfInactivePool); + pool.deactivation_epoch = option::some(deactivation_epoch); + } + + // ==== getters and misc utility functions ==== + + public fun iota_balance(pool: &StakingPool): u64 { pool.iota_balance } + + public fun pool_id(staked_iota: &StakedIota): ID { staked_iota.pool_id } + + public fun staked_iota_amount(staked_iota: &StakedIota): u64 { staked_iota.principal.value() } + + /// Allows calling `.amount()` on `StakedIota` to invoke `staked_iota_amount` + public use fun staked_iota_amount as StakedIota.amount; + + public fun stake_activation_epoch(staked_iota: &StakedIota): u64 { + staked_iota.stake_activation_epoch + } + + /// Returns true if the input staking pool is preactive. + public fun is_preactive(pool: &StakingPool): bool{ + pool.activation_epoch.is_none() + } + + /// Returns true if the input staking pool is inactive. + public fun is_inactive(pool: &StakingPool): bool { + pool.deactivation_epoch.is_some() + } + + /// Split StakedIota `self` to two parts, one with principal `split_amount`, + /// and the remaining principal is left in `self`. + /// All the other parameters of the StakedIota like `stake_activation_epoch` or `pool_id` remain the same. + public fun split(self: &mut StakedIota, split_amount: u64, ctx: &mut TxContext): StakedIota { + let original_amount = self.principal.value(); + assert!(split_amount <= original_amount, EInsufficientIotaTokenBalance); + let remaining_amount = original_amount - split_amount; + // Both resulting parts should have at least MIN_STAKING_THRESHOLD. + assert!(remaining_amount >= MIN_STAKING_THRESHOLD, EStakedIotaBelowThreshold); + assert!(split_amount >= MIN_STAKING_THRESHOLD, EStakedIotaBelowThreshold); + StakedIota { + id: object::new(ctx), + pool_id: self.pool_id, + stake_activation_epoch: self.stake_activation_epoch, + principal: self.principal.split(split_amount), + } + } + + /// Split the given StakedIota to the two parts, one with principal `split_amount`, + /// transfer the newly split part to the sender address. + public entry fun split_staked_iota(stake: &mut StakedIota, split_amount: u64, ctx: &mut TxContext) { + transfer::transfer(split(stake, split_amount, ctx), ctx.sender()); + } + + /// Allows calling `.split_to_sender()` on `StakedIota` to invoke `split_staked_iota` + public use fun split_staked_iota as StakedIota.split_to_sender; + + /// Consume the staked iota `other` and add its value to `self`. + /// Aborts if some of the staking parameters are incompatible (pool id, stake activation epoch, etc.) + public entry fun join_staked_iota(self: &mut StakedIota, other: StakedIota) { + assert!(is_equal_staking_metadata(self, &other), EIncompatibleStakedIota); + let StakedIota { + id, + pool_id: _, + stake_activation_epoch: _, + principal, + } = other; + + id.delete(); + self.principal.join(principal); + } + + /// Allows calling `.join()` on `StakedIota` to invoke `join_staked_iota` + public use fun join_staked_iota as StakedIota.join; + + /// Returns true if all the staking parameters of the staked iota except the principal are identical + public fun is_equal_staking_metadata(self: &StakedIota, other: &StakedIota): bool { + (self.pool_id == other.pool_id) && + (self.stake_activation_epoch == other.stake_activation_epoch) + } + + public fun pool_token_exchange_rate_at_epoch(pool: &StakingPool, epoch: u64): PoolTokenExchangeRate { + // If the pool is preactive then the exchange rate is always 1:1. + if (is_preactive_at_epoch(pool, epoch)) { + return initial_exchange_rate() + }; + let clamped_epoch = pool.deactivation_epoch.get_with_default(epoch); + let mut epoch = math::min(clamped_epoch, epoch); + let activation_epoch = *pool.activation_epoch.borrow(); + + // Find the latest epoch that's earlier than the given epoch with an entry in the table + while (epoch >= activation_epoch) { + if (pool.exchange_rates.contains(epoch)) { + return pool.exchange_rates[epoch] + }; + epoch = epoch - 1; + }; + // This line really should be unreachable. Do we want an assert false here? + initial_exchange_rate() + } + + /// Returns the total value of the pending staking requests for this staking pool. + public fun pending_stake_amount(staking_pool: &StakingPool): u64 { + staking_pool.pending_stake + } + + /// Returns the total withdrawal from the staking pool this epoch. + public fun pending_stake_withdraw_amount(staking_pool: &StakingPool): u64 { + staking_pool.pending_total_iota_withdraw + } + + public(package) fun exchange_rates(pool: &StakingPool): &Table { + &pool.exchange_rates + } + + public fun iota_amount(exchange_rate: &PoolTokenExchangeRate): u64 { + exchange_rate.iota_amount + } + + public fun pool_token_amount(exchange_rate: &PoolTokenExchangeRate): u64 { + exchange_rate.pool_token_amount + } + + /// Returns true if the provided staking pool is preactive at the provided epoch. + fun is_preactive_at_epoch(pool: &StakingPool, epoch: u64): bool{ + // Either the pool is currently preactive or the pool's starting epoch is later than the provided epoch. + is_preactive(pool) || (*pool.activation_epoch.borrow() > epoch) + } + + fun get_iota_amount(exchange_rate: &PoolTokenExchangeRate, token_amount: u64): u64 { + // When either amount is 0, that means we have no stakes with this pool. + // The other amount might be non-zero when there's dust left in the pool. + if (exchange_rate.iota_amount == 0 || exchange_rate.pool_token_amount == 0) { + return token_amount + }; + let res = exchange_rate.iota_amount as u128 + * (token_amount as u128) + / (exchange_rate.pool_token_amount as u128); + res as u64 + } + + fun get_token_amount(exchange_rate: &PoolTokenExchangeRate, iota_amount: u64): u64 { + // When either amount is 0, that means we have no stakes with this pool. + // The other amount might be non-zero when there's dust left in the pool. + if (exchange_rate.iota_amount == 0 || exchange_rate.pool_token_amount == 0) { + return iota_amount + }; + let res = exchange_rate.pool_token_amount as u128 + * (iota_amount as u128) + / (exchange_rate.iota_amount as u128); + res as u64 + } + + fun initial_exchange_rate(): PoolTokenExchangeRate { + PoolTokenExchangeRate { iota_amount: 0, pool_token_amount: 0 } + } + + fun check_balance_invariants(pool: &StakingPool, epoch: u64) { + let exchange_rate = pool_token_exchange_rate_at_epoch(pool, epoch); + // check that the pool token balance and iota balance ratio matches the exchange rate stored. + let expected = get_token_amount(&exchange_rate, pool.iota_balance); + let actual = pool.pool_token_balance; + assert!(expected == actual, ETokenBalancesDoNotMatchExchangeRate) + } + + // ==== test-related functions ==== + + // Given the `staked_iota` receipt calculate the current rewards (in terms of IOTA) for it. + #[test_only] + public fun calculate_rewards( + pool: &StakingPool, + staked_iota: &StakedIota, + current_epoch: u64, + ): u64 { + let staked_amount = staked_iota_amount(staked_iota); + let pool_token_withdraw_amount = { + let exchange_rate_at_staking_epoch = pool_token_exchange_rate_at_epoch(pool, staked_iota.stake_activation_epoch); + get_token_amount(&exchange_rate_at_staking_epoch, staked_amount) + }; + + let new_epoch_exchange_rate = pool_token_exchange_rate_at_epoch(pool, current_epoch); + let total_iota_withdraw_amount = get_iota_amount(&new_epoch_exchange_rate, pool_token_withdraw_amount); + + let mut reward_withdraw_amount = + if (total_iota_withdraw_amount >= staked_amount) + total_iota_withdraw_amount - staked_amount + else 0; + reward_withdraw_amount = math::min(reward_withdraw_amount, pool.rewards_pool.value()); + + staked_amount + reward_withdraw_amount + } +} diff --git a/crates/sui-framework/packages/sui-system/sources/storage_fund.move b/crates/iota-framework/packages/iota-system/sources/storage_fund.move similarity index 80% rename from crates/sui-framework/packages/sui-system/sources/storage_fund.move rename to crates/iota-framework/packages/iota-system/sources/storage_fund.move index 6356918009c..02b1187b07d 100644 --- a/crates/sui-framework/packages/sui-system/sources/storage_fund.move +++ b/crates/iota-framework/packages/iota-system/sources/storage_fund.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui_system::storage_fund { - use sui::balance::{Self, Balance}; - use sui::sui::SUI; +module iota_system::storage_fund { + use iota::balance::{Self, Balance}; + use iota::iota::IOTA; - /* friend sui_system::sui_system_state_inner; */ + /* friend iota_system::iota_system_state_inner; */ /// Struct representing the storage fund, containing two `Balance`s: /// - `total_object_storage_rebates` has the invariant that it's the sum of `storage_rebate` of @@ -16,12 +17,12 @@ module sui_system::storage_fund { /// - `non_refundable_balance` contains any remaining inflow of the storage fund that should not /// be taken out of the fund. public struct StorageFund has store { - total_object_storage_rebates: Balance, - non_refundable_balance: Balance, + total_object_storage_rebates: Balance, + non_refundable_balance: Balance, } - /// Called by `sui_system` at genesis time. - public(package) fun new(initial_fund: Balance) : StorageFund { + /// Called by `iota_system` at genesis time. + public(package) fun new(initial_fund: Balance) : StorageFund { StorageFund { // At the beginning there's no object in the storage yet total_object_storage_rebates: balance::zero(), @@ -29,15 +30,15 @@ module sui_system::storage_fund { } } - /// Called by `sui_system` at epoch change times to process the inflows and outflows of storage fund. + /// Called by `iota_system` at epoch change times to process the inflows and outflows of storage fund. public(package) fun advance_epoch( self: &mut StorageFund, - storage_charges: Balance, - storage_fund_reinvestment: Balance, - leftover_staking_rewards: Balance, + storage_charges: Balance, + storage_fund_reinvestment: Balance, + leftover_staking_rewards: Balance, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, - ) : Balance { + ) : Balance { // Both the reinvestment and leftover rewards are not to be refunded so they go to the non-refundable balance. self.non_refundable_balance.join(storage_fund_reinvestment); self.non_refundable_balance.join(leftover_staking_rewards); diff --git a/crates/iota-framework/packages/iota-system/sources/validator.move b/crates/iota-framework/packages/iota-system/sources/validator.move new file mode 100644 index 00000000000..fa1b0a925e5 --- /dev/null +++ b/crates/iota-framework/packages/iota-system/sources/validator.move @@ -0,0 +1,957 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_const)] +module iota_system::validator { + use std::bcs; + + use iota::balance::Balance; + use iota::iota::IOTA; + use iota_system::validator_cap::{Self, ValidatorOperationCap}; + use iota_system::staking_pool::{Self, PoolTokenExchangeRate, StakedIota, StakingPool}; + use std::string::String; + use iota::url::Url; + use iota::url; + use iota::event; + use iota::bag::Bag; + use iota::bag; + /* friend iota_system::genesis; */ + /* friend iota_system::iota_system_state_inner; */ + /* friend iota_system::validator_wrapper; */ + /* friend iota_system::validator_set; */ + /* friend iota_system::voting_power; */ + + /* #[test_only] */ + /* friend iota_system::validator_tests; */ + /* #[test_only] */ + /* friend iota_system::validator_set_tests; */ + /* #[test_only] */ + /* friend iota_system::iota_system_tests; */ + /* #[test_only] */ + /* friend iota_system::governance_test_utils; */ + + /// Invalid proof_of_possession field in ValidatorMetadata + const EInvalidProofOfPossession: u64 = 0; + + /// Invalid pubkey_bytes field in ValidatorMetadata + const EMetadataInvalidPubkey: u64 = 1; + + /// Invalid network_pubkey_bytes field in ValidatorMetadata + const EMetadataInvalidNetPubkey: u64 = 2; + + /// Invalid worker_pubkey_bytes field in ValidatorMetadata + const EMetadataInvalidWorkerPubkey: u64 = 3; + + /// Invalid net_address field in ValidatorMetadata + const EMetadataInvalidNetAddr: u64 = 4; + + /// Invalid p2p_address field in ValidatorMetadata + const EMetadataInvalidP2pAddr: u64 = 5; + + /// Invalid primary_address field in ValidatorMetadata + const EMetadataInvalidPrimaryAddr: u64 = 6; + + /// Invalidworker_address field in ValidatorMetadata + const EMetadataInvalidWorkerAddr: u64 = 7; + + /// Commission rate set by the validator is higher than the threshold + const ECommissionRateTooHigh: u64 = 8; + + /// Validator Metadata is too long + const EValidatorMetadataExceedingLengthLimit: u64 = 9; + + /// Intended validator is not a candidate one. + const ENotValidatorCandidate: u64 = 10; + + /// Stake amount is invalid or wrong. + const EInvalidStakeAmount: u64 = 11; + + /// Function called during non-genesis times. + const ECalledDuringNonGenesis: u64 = 12; + + /// New Capability is not created by the validator itself + const ENewCapNotCreatedByValidatorItself: u64 = 100; + + /// Capability code is not valid + const EInvalidCap: u64 = 101; + + /// Validator trying to set gas price higher than threshold. + const EGasPriceHigherThanThreshold: u64 = 102; + + // TODO: potentially move this value to onchain config. + const MAX_COMMISSION_RATE: u64 = 2_000; // Max rate is 20%, which is 2000 base points + + const MAX_VALIDATOR_METADATA_LENGTH: u64 = 256; + + // TODO: Move this to onchain config when we have a good way to do it. + /// Max gas price a validator can set is 100K MICROS. + const MAX_VALIDATOR_GAS_PRICE: u64 = 100_000; + + public struct ValidatorMetadata has store { + /// The Iota Address of the validator. This is the sender that created the Validator object, + /// and also the address to send validator/coins to during withdraws. + iota_address: address, + /// The public key bytes corresponding to the private key that the validator + /// holds to sign transactions. For now, this is the same as AuthorityName. + protocol_pubkey_bytes: vector, + /// The public key bytes corresponding to the private key that the validator + /// uses to establish TLS connections + network_pubkey_bytes: vector, + /// The public key bytes correstponding to the Narwhal Worker + worker_pubkey_bytes: vector, + /// This is a proof that the validator has ownership of the private key + proof_of_possession: vector, + /// A unique human-readable name of this validator. + name: String, + description: String, + image_url: Url, + project_url: Url, + /// The network address of the validator (could also contain extra info such as port, DNS and etc.). + net_address: String, + /// The address of the validator used for p2p activities such as state sync (could also contain extra info such as port, DNS and etc.). + p2p_address: String, + /// The address of the narwhal primary + primary_address: String, + /// The address of the narwhal worker + worker_address: String, + + /// "next_epoch" metadata only takes effects in the next epoch. + /// If none, current value will stay unchanged. + next_epoch_protocol_pubkey_bytes: Option>, + next_epoch_proof_of_possession: Option>, + next_epoch_network_pubkey_bytes: Option>, + next_epoch_worker_pubkey_bytes: Option>, + next_epoch_net_address: Option, + next_epoch_p2p_address: Option, + next_epoch_primary_address: Option, + next_epoch_worker_address: Option, + + /// Any extra fields that's not defined statically. + extra_fields: Bag, + } + + public struct Validator has store { + /// Summary of the validator. + metadata: ValidatorMetadata, + /// The voting power of this validator, which might be different from its + /// stake amount. + voting_power: u64, + /// The ID of this validator's current valid `UnverifiedValidatorOperationCap` + operation_cap_id: ID, + /// Gas price quote, updated only at end of epoch. + gas_price: u64, + /// Staking pool for this validator. + staking_pool: StakingPool, + /// Commission rate of the validator, in basis point. + commission_rate: u64, + /// Total amount of stake that would be active in the next epoch. + next_epoch_stake: u64, + /// This validator's gas price quote for the next epoch. + next_epoch_gas_price: u64, + /// The commission rate of the validator starting the next epoch, in basis point. + next_epoch_commission_rate: u64, + /// Any extra fields that's not defined statically. + extra_fields: Bag, + } + + /// Event emitted when a new stake request is received. + public struct StakingRequestEvent has copy, drop { + pool_id: ID, + validator_address: address, + staker_address: address, + epoch: u64, + amount: u64, + } + + /// Event emitted when a new unstake request is received. + public struct UnstakingRequestEvent has copy, drop { + pool_id: ID, + validator_address: address, + staker_address: address, + stake_activation_epoch: u64, + unstaking_epoch: u64, + principal_amount: u64, + reward_amount: u64, + } + + public(package) fun new_metadata( + iota_address: address, + protocol_pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + proof_of_possession: vector, + name: String, + description: String, + image_url: Url, + project_url: Url, + net_address: String, + p2p_address: String, + primary_address: String, + worker_address: String, + extra_fields: Bag, + ): ValidatorMetadata { + let metadata = ValidatorMetadata { + iota_address, + protocol_pubkey_bytes, + network_pubkey_bytes, + worker_pubkey_bytes, + proof_of_possession, + name, + description, + image_url, + project_url, + net_address, + p2p_address, + primary_address, + worker_address, + next_epoch_protocol_pubkey_bytes: option::none(), + next_epoch_network_pubkey_bytes: option::none(), + next_epoch_worker_pubkey_bytes: option::none(), + next_epoch_proof_of_possession: option::none(), + next_epoch_net_address: option::none(), + next_epoch_p2p_address: option::none(), + next_epoch_primary_address: option::none(), + next_epoch_worker_address: option::none(), + extra_fields, + }; + metadata + } + + public(package) fun new( + iota_address: address, + protocol_pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + proof_of_possession: vector, + name: vector, + description: vector, + image_url: vector, + project_url: vector, + net_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + gas_price: u64, + commission_rate: u64, + ctx: &mut TxContext + ): Validator { + assert!( + net_address.length() <= MAX_VALIDATOR_METADATA_LENGTH + && p2p_address.length() <= MAX_VALIDATOR_METADATA_LENGTH + && primary_address.length() <= MAX_VALIDATOR_METADATA_LENGTH + && worker_address.length() <= MAX_VALIDATOR_METADATA_LENGTH + && name.length() <= MAX_VALIDATOR_METADATA_LENGTH + && description.length() <= MAX_VALIDATOR_METADATA_LENGTH + && image_url.length() <= MAX_VALIDATOR_METADATA_LENGTH + && project_url.length() <= MAX_VALIDATOR_METADATA_LENGTH, + EValidatorMetadataExceedingLengthLimit + ); + assert!(commission_rate <= MAX_COMMISSION_RATE, ECommissionRateTooHigh); + assert!(gas_price < MAX_VALIDATOR_GAS_PRICE, EGasPriceHigherThanThreshold); + + let metadata = new_metadata( + iota_address, + protocol_pubkey_bytes, + network_pubkey_bytes, + worker_pubkey_bytes, + proof_of_possession, + name.to_ascii_string().to_string(), + description.to_ascii_string().to_string(), + url::new_unsafe_from_bytes(image_url), + url::new_unsafe_from_bytes(project_url), + net_address.to_ascii_string().to_string(), + p2p_address.to_ascii_string().to_string(), + primary_address.to_ascii_string().to_string(), + worker_address.to_ascii_string().to_string(), + bag::new(ctx), + ); + + // Checks that the keys & addresses & PoP are valid. + validate_metadata(&metadata); + + new_from_metadata( + metadata, + gas_price, + commission_rate, + ctx + ) + } + + /// Deactivate this validator's staking pool + public(package) fun deactivate(self: &mut Validator, deactivation_epoch: u64) { + self.staking_pool.deactivate_staking_pool(deactivation_epoch) + } + + public(package) fun activate(self: &mut Validator, activation_epoch: u64) { + self.staking_pool.activate_staking_pool(activation_epoch); + } + + /// Process pending stake and pending withdraws, and update the gas price. + public(package) fun adjust_stake_and_gas_price(self: &mut Validator) { + self.gas_price = self.next_epoch_gas_price; + self.commission_rate = self.next_epoch_commission_rate; + } + + /// Request to add stake to the validator's staking pool, processed at the end of the epoch. + public(package) fun request_add_stake( + self: &mut Validator, + stake: Balance, + staker_address: address, + ctx: &mut TxContext, + ) : StakedIota { + let stake_amount = stake.value(); + assert!(stake_amount > 0, EInvalidStakeAmount); + let stake_epoch = ctx.epoch() + 1; + let staked_iota = self.staking_pool.request_add_stake(stake, stake_epoch, ctx); + // Process stake right away if staking pool is preactive. + if (self.staking_pool.is_preactive()) { + self.staking_pool.process_pending_stake(); + }; + self.next_epoch_stake = self.next_epoch_stake + stake_amount; + event::emit( + StakingRequestEvent { + pool_id: staking_pool_id(self), + validator_address: self.metadata.iota_address, + staker_address, + epoch: ctx.epoch(), + amount: stake_amount, + } + ); + staked_iota + } + + /// Request to add stake to the validator's staking pool at genesis + public(package) fun request_add_stake_at_genesis( + self: &mut Validator, + stake: Balance, + staker_address: address, + ctx: &mut TxContext, + ) { + assert!(ctx.epoch() == 0, ECalledDuringNonGenesis); + let stake_amount = stake.value(); + assert!(stake_amount > 0, EInvalidStakeAmount); + + let staked_iota = self.staking_pool.request_add_stake( + stake, + 0, // epoch 0 -- genesis + ctx + ); + + transfer::public_transfer(staked_iota, staker_address); + + // Process stake right away + self.staking_pool.process_pending_stake(); + self.next_epoch_stake = self.next_epoch_stake + stake_amount; + } + + /// Request to withdraw stake from the validator's staking pool, processed at the end of the epoch. + public(package) fun request_withdraw_stake( + self: &mut Validator, + staked_iota: StakedIota, + ctx: &TxContext, + ) : Balance { + let principal_amount = staked_iota.staked_iota_amount(); + let stake_activation_epoch = staked_iota.stake_activation_epoch(); + let withdrawn_stake = self.staking_pool.request_withdraw_stake(staked_iota, ctx); + let withdraw_amount = withdrawn_stake.value(); + let reward_amount = withdraw_amount - principal_amount; + self.next_epoch_stake = self.next_epoch_stake - withdraw_amount; + event::emit( + UnstakingRequestEvent { + pool_id: staking_pool_id(self), + validator_address: self.metadata.iota_address, + staker_address: ctx.sender(), + stake_activation_epoch, + unstaking_epoch: ctx.epoch(), + principal_amount, + reward_amount, + } + ); + withdrawn_stake + } + + /// Request to set new gas price for the next epoch. + /// Need to present a `ValidatorOperationCap`. + public(package) fun request_set_gas_price( + self: &mut Validator, + verified_cap: ValidatorOperationCap, + new_price: u64, + ) { + assert!(new_price < MAX_VALIDATOR_GAS_PRICE, EGasPriceHigherThanThreshold); + let validator_address = *verified_cap.verified_operation_cap_address(); + assert!(validator_address == self.metadata.iota_address, EInvalidCap); + self.next_epoch_gas_price = new_price; + } + + /// Set new gas price for the candidate validator. + public(package) fun set_candidate_gas_price( + self: &mut Validator, + verified_cap: ValidatorOperationCap, + new_price: u64 + ) { + assert!(is_preactive(self), ENotValidatorCandidate); + assert!(new_price < MAX_VALIDATOR_GAS_PRICE, EGasPriceHigherThanThreshold); + let validator_address = *verified_cap.verified_operation_cap_address(); + assert!(validator_address == self.metadata.iota_address, EInvalidCap); + self.next_epoch_gas_price = new_price; + self.gas_price = new_price; + } + + /// Request to set new commission rate for the next epoch. + public(package) fun request_set_commission_rate(self: &mut Validator, new_commission_rate: u64) { + assert!(new_commission_rate <= MAX_COMMISSION_RATE, ECommissionRateTooHigh); + self.next_epoch_commission_rate = new_commission_rate; + } + + /// Set new commission rate for the candidate validator. + public(package) fun set_candidate_commission_rate(self: &mut Validator, new_commission_rate: u64) { + assert!(is_preactive(self), ENotValidatorCandidate); + assert!(new_commission_rate <= MAX_COMMISSION_RATE, ECommissionRateTooHigh); + self.commission_rate = new_commission_rate; + } + + /// Deposit stakes rewards into the validator's staking pool, called at the end of the epoch. + public(package) fun deposit_stake_rewards(self: &mut Validator, reward: Balance) { + self.next_epoch_stake = self.next_epoch_stake + reward.value(); + self.staking_pool.deposit_rewards(reward); + } + + /// Process pending stakes and withdraws, called at the end of the epoch. + public(package) fun process_pending_stakes_and_withdraws(self: &mut Validator, ctx: &TxContext) { + self.staking_pool.process_pending_stakes_and_withdraws(ctx); + assert!(stake_amount(self) == self.next_epoch_stake, EInvalidStakeAmount); + } + + /// Returns true if the validator is preactive. + public fun is_preactive(self: &Validator): bool { + self.staking_pool.is_preactive() + } + + public fun metadata(self: &Validator): &ValidatorMetadata { + &self.metadata + } + + public fun iota_address(self: &Validator): address { + self.metadata.iota_address + } + + public fun name(self: &Validator): &String { + &self.metadata.name + } + + public fun description(self: &Validator): &String { + &self.metadata.description + } + + public fun image_url(self: &Validator): &Url { + &self.metadata.image_url + } + + public fun project_url(self: &Validator): &Url { + &self.metadata.project_url + } + + public fun network_address(self: &Validator): &String { + &self.metadata.net_address + } + + public fun p2p_address(self: &Validator): &String { + &self.metadata.p2p_address + } + + public fun primary_address(self: &Validator): &String { + &self.metadata.primary_address + } + + public fun worker_address(self: &Validator): &String { + &self.metadata.worker_address + } + + public fun protocol_pubkey_bytes(self: &Validator): &vector { + &self.metadata.protocol_pubkey_bytes + } + + public fun proof_of_possession(self: &Validator): &vector { + &self.metadata.proof_of_possession + } + + public fun network_pubkey_bytes(self: &Validator): &vector { + &self.metadata.network_pubkey_bytes + } + + public fun worker_pubkey_bytes(self: &Validator): &vector { + &self.metadata.worker_pubkey_bytes + } + + public fun next_epoch_network_address(self: &Validator): &Option { + &self.metadata.next_epoch_net_address + } + + public fun next_epoch_p2p_address(self: &Validator): &Option { + &self.metadata.next_epoch_p2p_address + } + + public fun next_epoch_primary_address(self: &Validator): &Option { + &self.metadata.next_epoch_primary_address + } + + public fun next_epoch_worker_address(self: &Validator): &Option { + &self.metadata.next_epoch_worker_address + } + + public fun next_epoch_protocol_pubkey_bytes(self: &Validator): &Option> { + &self.metadata.next_epoch_protocol_pubkey_bytes + } + + public fun next_epoch_proof_of_possession(self: &Validator): &Option> { + &self.metadata.next_epoch_proof_of_possession + } + + public fun next_epoch_network_pubkey_bytes(self: &Validator): &Option> { + &self.metadata.next_epoch_network_pubkey_bytes + } + + public fun next_epoch_worker_pubkey_bytes(self: &Validator): &Option> { + &self.metadata.next_epoch_worker_pubkey_bytes + } + + public fun operation_cap_id(self: &Validator): &ID { + &self.operation_cap_id + } + + public fun next_epoch_gas_price(self: &Validator): u64 { + self.next_epoch_gas_price + } + + // TODO: this and `delegate_amount` and `total_stake` all seem to return the same value? + // two of the functions can probably be removed. + public fun total_stake_amount(self: &Validator): u64 { + self.staking_pool.iota_balance() + } + + public fun stake_amount(self: &Validator): u64 { + self.staking_pool.iota_balance() + } + + /// Return the total amount staked with this validator + public fun total_stake(self: &Validator): u64 { + stake_amount(self) + } + + /// Return the voting power of this validator. + public fun voting_power(self: &Validator): u64 { + self.voting_power + } + + /// Set the voting power of this validator, called only from validator_set. + public(package) fun set_voting_power(self: &mut Validator, new_voting_power: u64) { + self.voting_power = new_voting_power; + } + + public fun pending_stake_amount(self: &Validator): u64 { + self.staking_pool.pending_stake_amount() + } + + public fun pending_stake_withdraw_amount(self: &Validator): u64 { + self.staking_pool.pending_stake_withdraw_amount() + } + + public fun gas_price(self: &Validator): u64 { + self.gas_price + } + + public fun commission_rate(self: &Validator): u64 { + self.commission_rate + } + + public fun pool_token_exchange_rate_at_epoch(self: &Validator, epoch: u64): PoolTokenExchangeRate { + self.staking_pool.pool_token_exchange_rate_at_epoch(epoch) + } + + public fun staking_pool_id(self: &Validator): ID { + object::id(&self.staking_pool) + } + + // MUSTFIX: We need to check this when updating metadata as well. + public fun is_duplicate(self: &Validator, other: &Validator): bool { + self.metadata.iota_address == other.metadata.iota_address + || self.metadata.name == other.metadata.name + || self.metadata.net_address == other.metadata.net_address + || self.metadata.p2p_address == other.metadata.p2p_address + || self.metadata.protocol_pubkey_bytes == other.metadata.protocol_pubkey_bytes + || self.metadata.network_pubkey_bytes == other.metadata.network_pubkey_bytes + || self.metadata.network_pubkey_bytes == other.metadata.worker_pubkey_bytes + || self.metadata.worker_pubkey_bytes == other.metadata.worker_pubkey_bytes + || self.metadata.worker_pubkey_bytes == other.metadata.network_pubkey_bytes + // All next epoch parameters. + || is_equal_some(&self.metadata.next_epoch_net_address, &other.metadata.next_epoch_net_address) + || is_equal_some(&self.metadata.next_epoch_p2p_address, &other.metadata.next_epoch_p2p_address) + || is_equal_some(&self.metadata.next_epoch_protocol_pubkey_bytes, &other.metadata.next_epoch_protocol_pubkey_bytes) + || is_equal_some(&self.metadata.next_epoch_network_pubkey_bytes, &other.metadata.next_epoch_network_pubkey_bytes) + || is_equal_some(&self.metadata.next_epoch_network_pubkey_bytes, &other.metadata.next_epoch_worker_pubkey_bytes) + || is_equal_some(&self.metadata.next_epoch_worker_pubkey_bytes, &other.metadata.next_epoch_worker_pubkey_bytes) + || is_equal_some(&self.metadata.next_epoch_worker_pubkey_bytes, &other.metadata.next_epoch_network_pubkey_bytes) + // My next epoch parameters with other current epoch parameters. + || is_equal_some_and_value(&self.metadata.next_epoch_net_address, &other.metadata.net_address) + || is_equal_some_and_value(&self.metadata.next_epoch_p2p_address, &other.metadata.p2p_address) + || is_equal_some_and_value(&self.metadata.next_epoch_protocol_pubkey_bytes, &other.metadata.protocol_pubkey_bytes) + || is_equal_some_and_value(&self.metadata.next_epoch_network_pubkey_bytes, &other.metadata.network_pubkey_bytes) + || is_equal_some_and_value(&self.metadata.next_epoch_network_pubkey_bytes, &other.metadata.worker_pubkey_bytes) + || is_equal_some_and_value(&self.metadata.next_epoch_worker_pubkey_bytes, &other.metadata.worker_pubkey_bytes) + || is_equal_some_and_value(&self.metadata.next_epoch_worker_pubkey_bytes, &other.metadata.network_pubkey_bytes) + // Other next epoch parameters with my current epoch parameters. + || is_equal_some_and_value(&other.metadata.next_epoch_net_address, &self.metadata.net_address) + || is_equal_some_and_value(&other.metadata.next_epoch_p2p_address, &self.metadata.p2p_address) + || is_equal_some_and_value(&other.metadata.next_epoch_protocol_pubkey_bytes, &self.metadata.protocol_pubkey_bytes) + || is_equal_some_and_value(&other.metadata.next_epoch_network_pubkey_bytes, &self.metadata.network_pubkey_bytes) + || is_equal_some_and_value(&other.metadata.next_epoch_network_pubkey_bytes, &self.metadata.worker_pubkey_bytes) + || is_equal_some_and_value(&other.metadata.next_epoch_worker_pubkey_bytes, &self.metadata.worker_pubkey_bytes) + || is_equal_some_and_value(&other.metadata.next_epoch_worker_pubkey_bytes, &self.metadata.network_pubkey_bytes) + } + + fun is_equal_some_and_value(a: &Option, b: &T): bool { + if (a.is_none()) { + false + } else { + a.borrow() == b + } + } + + fun is_equal_some(a: &Option, b: &Option): bool { + if (a.is_none() || b.is_none()) { + false + } else { + a.borrow() == b.borrow() + } + } + + // ==== Validator Metadata Management Functions ==== + + /// Create a new `UnverifiedValidatorOperationCap`, transfer to the validator, + /// and registers it, thus revoking the previous cap's permission. + public(package) fun new_unverified_validator_operation_cap_and_transfer(self: &mut Validator, ctx: &mut TxContext) { + let address = ctx.sender(); + assert!(address == self.metadata.iota_address, ENewCapNotCreatedByValidatorItself); + let new_id = validator_cap::new_unverified_validator_operation_cap_and_transfer(address, ctx); + self.operation_cap_id = new_id; + } + + /// Update name of the validator. + public(package) fun update_name(self: &mut Validator, name: vector) { + assert!( + name.length() <= MAX_VALIDATOR_METADATA_LENGTH, + EValidatorMetadataExceedingLengthLimit + ); + self.metadata.name = name.to_ascii_string().to_string(); + } + + /// Update description of the validator. + public(package) fun update_description(self: &mut Validator, description: vector) { + assert!( + description.length() <= MAX_VALIDATOR_METADATA_LENGTH, + EValidatorMetadataExceedingLengthLimit + ); + self.metadata.description = description.to_ascii_string().to_string(); + } + + /// Update image url of the validator. + public(package) fun update_image_url(self: &mut Validator, image_url: vector) { + assert!( + image_url.length() <= MAX_VALIDATOR_METADATA_LENGTH, + EValidatorMetadataExceedingLengthLimit + ); + self.metadata.image_url = url::new_unsafe_from_bytes(image_url); + } + + /// Update project url of the validator. + public(package) fun update_project_url(self: &mut Validator, project_url: vector) { + assert!( + project_url.length() <= MAX_VALIDATOR_METADATA_LENGTH, + EValidatorMetadataExceedingLengthLimit + ); + self.metadata.project_url = url::new_unsafe_from_bytes(project_url); + } + + /// Update network address of this validator, taking effects from next epoch + public(package) fun update_next_epoch_network_address(self: &mut Validator, net_address: vector) { + assert!( + net_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, + EValidatorMetadataExceedingLengthLimit + ); + let net_address = net_address.to_ascii_string().to_string(); + self.metadata.next_epoch_net_address = option::some(net_address); + validate_metadata(&self.metadata); + } + + /// Update network address of this candidate validator + public(package) fun update_candidate_network_address(self: &mut Validator, net_address: vector) { + assert!(is_preactive(self), ENotValidatorCandidate); + assert!( + net_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, + EValidatorMetadataExceedingLengthLimit + ); + let net_address = net_address.to_ascii_string().to_string(); + self.metadata.net_address = net_address; + validate_metadata(&self.metadata); + } + + /// Update p2p address of this validator, taking effects from next epoch + public(package) fun update_next_epoch_p2p_address(self: &mut Validator, p2p_address: vector) { + assert!( + p2p_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, + EValidatorMetadataExceedingLengthLimit + ); + let p2p_address = p2p_address.to_ascii_string().to_string(); + self.metadata.next_epoch_p2p_address = option::some(p2p_address); + validate_metadata(&self.metadata); + } + + /// Update p2p address of this candidate validator + public(package) fun update_candidate_p2p_address(self: &mut Validator, p2p_address: vector) { + assert!(is_preactive(self), ENotValidatorCandidate); + assert!( + p2p_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, + EValidatorMetadataExceedingLengthLimit + ); + let p2p_address = p2p_address.to_ascii_string().to_string(); + self.metadata.p2p_address = p2p_address; + validate_metadata(&self.metadata); + } + + /// Update primary address of this validator, taking effects from next epoch + public(package) fun update_next_epoch_primary_address(self: &mut Validator, primary_address: vector) { + assert!( + primary_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, + EValidatorMetadataExceedingLengthLimit + ); + let primary_address = primary_address.to_ascii_string().to_string(); + self.metadata.next_epoch_primary_address = option::some(primary_address); + validate_metadata(&self.metadata); + } + + /// Update primary address of this candidate validator + public(package) fun update_candidate_primary_address(self: &mut Validator, primary_address: vector) { + assert!(is_preactive(self), ENotValidatorCandidate); + assert!( + primary_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, + EValidatorMetadataExceedingLengthLimit + ); + let primary_address = primary_address.to_ascii_string().to_string(); + self.metadata.primary_address = primary_address; + validate_metadata(&self.metadata); + } + + /// Update worker address of this validator, taking effects from next epoch + public(package) fun update_next_epoch_worker_address(self: &mut Validator, worker_address: vector) { + assert!( + worker_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, + EValidatorMetadataExceedingLengthLimit + ); + let worker_address = worker_address.to_ascii_string().to_string(); + self.metadata.next_epoch_worker_address = option::some(worker_address); + validate_metadata(&self.metadata); + } + + /// Update worker address of this candidate validator + public(package) fun update_candidate_worker_address(self: &mut Validator, worker_address: vector) { + assert!(is_preactive(self), ENotValidatorCandidate); + assert!( + worker_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, + EValidatorMetadataExceedingLengthLimit + ); + let worker_address = worker_address.to_ascii_string().to_string(); + self.metadata.worker_address = worker_address; + validate_metadata(&self.metadata); + } + + /// Update protocol public key of this validator, taking effects from next epoch + public(package) fun update_next_epoch_protocol_pubkey(self: &mut Validator, protocol_pubkey: vector, proof_of_possession: vector) { + self.metadata.next_epoch_protocol_pubkey_bytes = option::some(protocol_pubkey); + self.metadata.next_epoch_proof_of_possession = option::some(proof_of_possession); + validate_metadata(&self.metadata); + } + + /// Update protocol public key of this candidate validator + public(package) fun update_candidate_protocol_pubkey(self: &mut Validator, protocol_pubkey: vector, proof_of_possession: vector) { + assert!(is_preactive(self), ENotValidatorCandidate); + self.metadata.protocol_pubkey_bytes = protocol_pubkey; + self.metadata.proof_of_possession = proof_of_possession; + validate_metadata(&self.metadata); + } + + /// Update network public key of this validator, taking effects from next epoch + public(package) fun update_next_epoch_network_pubkey(self: &mut Validator, network_pubkey: vector) { + self.metadata.next_epoch_network_pubkey_bytes = option::some(network_pubkey); + validate_metadata(&self.metadata); + } + + /// Update network public key of this candidate validator + public(package) fun update_candidate_network_pubkey(self: &mut Validator, network_pubkey: vector) { + assert!(is_preactive(self), ENotValidatorCandidate); + self.metadata.network_pubkey_bytes = network_pubkey; + validate_metadata(&self.metadata); + } + + /// Update Narwhal worker public key of this validator, taking effects from next epoch + public(package) fun update_next_epoch_worker_pubkey(self: &mut Validator, worker_pubkey: vector) { + self.metadata.next_epoch_worker_pubkey_bytes = option::some(worker_pubkey); + validate_metadata(&self.metadata); + } + + /// Update Narwhal worker public key of this candidate validator + public(package) fun update_candidate_worker_pubkey(self: &mut Validator, worker_pubkey: vector) { + assert!(is_preactive(self), ENotValidatorCandidate); + self.metadata.worker_pubkey_bytes = worker_pubkey; + validate_metadata(&self.metadata); + } + + /// Effectutate all staged next epoch metadata for this validator. + /// NOTE: this function SHOULD ONLY be called by validator_set when + /// advancing an epoch. + public(package) fun effectuate_staged_metadata(self: &mut Validator) { + if (next_epoch_network_address(self).is_some()) { + self.metadata.net_address = self.metadata.next_epoch_net_address.extract(); + self.metadata.next_epoch_net_address = option::none(); + }; + + if (next_epoch_p2p_address(self).is_some()) { + self.metadata.p2p_address = self.metadata.next_epoch_p2p_address.extract(); + self.metadata.next_epoch_p2p_address = option::none(); + }; + + if (next_epoch_primary_address(self).is_some()) { + self.metadata.primary_address = self.metadata.next_epoch_primary_address.extract(); + self.metadata.next_epoch_primary_address = option::none(); + }; + + if (next_epoch_worker_address(self).is_some()) { + self.metadata.worker_address = self.metadata.next_epoch_worker_address.extract(); + self.metadata.next_epoch_worker_address = option::none(); + }; + + if (next_epoch_protocol_pubkey_bytes(self).is_some()) { + self.metadata.protocol_pubkey_bytes = self.metadata.next_epoch_protocol_pubkey_bytes.extract(); + self.metadata.next_epoch_protocol_pubkey_bytes = option::none(); + self.metadata.proof_of_possession = self.metadata.next_epoch_proof_of_possession.extract(); + self.metadata.next_epoch_proof_of_possession = option::none(); + }; + + if (next_epoch_network_pubkey_bytes(self).is_some()) { + self.metadata.network_pubkey_bytes = self.metadata.next_epoch_network_pubkey_bytes.extract(); + self.metadata.next_epoch_network_pubkey_bytes = option::none(); + }; + + if (next_epoch_worker_pubkey_bytes(self).is_some()) { + self.metadata.worker_pubkey_bytes = self.metadata.next_epoch_worker_pubkey_bytes.extract(); + self.metadata.next_epoch_worker_pubkey_bytes = option::none(); + }; + } + + /// Aborts if validator metadata is valid + public fun validate_metadata(metadata: &ValidatorMetadata) { + validate_metadata_bcs(bcs::to_bytes(metadata)); + } + + public native fun validate_metadata_bcs(metadata: vector); + + public(package) fun get_staking_pool_ref(self: &Validator) : &StakingPool { + &self.staking_pool + } + + + /// Create a new validator from the given `ValidatorMetadata`, called by both `new` and `new_for_testing`. + fun new_from_metadata( + metadata: ValidatorMetadata, + gas_price: u64, + commission_rate: u64, + ctx: &mut TxContext + ): Validator { + let iota_address = metadata.iota_address; + + let staking_pool = staking_pool::new(ctx); + + let operation_cap_id = validator_cap::new_unverified_validator_operation_cap_and_transfer(iota_address, ctx); + Validator { + metadata, + // Initialize the voting power to be 0. + // At the epoch change where this validator is actually added to the + // active validator set, the voting power will be updated accordingly. + voting_power: 0, + operation_cap_id, + gas_price, + staking_pool, + commission_rate, + next_epoch_stake: 0, + next_epoch_gas_price: gas_price, + next_epoch_commission_rate: commission_rate, + extra_fields: bag::new(ctx), + } + } + + // CAUTION: THIS CODE IS ONLY FOR TESTING AND THIS MACRO MUST NEVER EVER BE REMOVED. + // Creates a validator - bypassing the proof of possession check and other metadata + // validation in the process. + // Note: `proof_of_possession` MUST be a valid signature using iota_address and + // protocol_pubkey_bytes. To produce a valid PoP, run [fn test_proof_of_possession]. + #[test_only] + public(package) fun new_for_testing( + iota_address: address, + protocol_pubkey_bytes: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + proof_of_possession: vector, + name: vector, + description: vector, + image_url: vector, + project_url: vector, + net_address: vector, + p2p_address: vector, + primary_address: vector, + worker_address: vector, + mut initial_stake_option: Option>, + gas_price: u64, + commission_rate: u64, + is_active_at_genesis: bool, + ctx: &mut TxContext + ): Validator { + let mut validator = new_from_metadata( + new_metadata( + iota_address, + protocol_pubkey_bytes, + network_pubkey_bytes, + worker_pubkey_bytes, + proof_of_possession, + name.to_ascii_string().to_string(), + description.to_ascii_string().to_string(), + url::new_unsafe_from_bytes(image_url), + url::new_unsafe_from_bytes(project_url), + net_address.to_ascii_string().to_string(), + p2p_address.to_ascii_string().to_string(), + primary_address.to_ascii_string().to_string(), + worker_address.to_ascii_string().to_string(), + bag::new(ctx), + ), + gas_price, + commission_rate, + ctx + ); + + // Add the validator's starting stake to the staking pool if there exists one. + if (initial_stake_option.is_some()) { + request_add_stake_at_genesis( + &mut validator, + initial_stake_option.extract(), + iota_address, // give the stake to the validator + ctx + ); + }; + initial_stake_option.destroy_none(); + + if (is_active_at_genesis) { + activate(&mut validator, 0); + }; + + validator + } +} diff --git a/crates/sui-framework/packages/sui-system/sources/validator_cap.move b/crates/iota-framework/packages/iota-system/sources/validator_cap.move similarity index 90% rename from crates/sui-framework/packages/sui-system/sources/validator_cap.move rename to crates/iota-framework/packages/iota-system/sources/validator_cap.move index 35aa8f2adc7..a1c7405691b 100644 --- a/crates/sui-framework/packages/sui-system/sources/validator_cap.move +++ b/crates/iota-framework/packages/iota-system/sources/validator_cap.move @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui_system::validator_cap { - /* friend sui_system::sui_system_state_inner; */ - /* friend sui_system::validator; */ - /* friend sui_system::validator_set; */ +module iota_system::validator_cap { + /* friend iota_system::iota_system_state_inner; */ + /* friend iota_system::validator; */ + /* friend iota_system::validator_set; */ /* #[test_only] */ - /* friend sui_system::sui_system_tests; */ + /* friend iota_system::iota_system_tests; */ /* #[test_only] */ - /* friend sui_system::rewards_distribution_tests; */ + /* friend iota_system::rewards_distribution_tests; */ /// The capability object is created when creating a new `Validator` or when the /// validator explicitly creates a new capability object for rotation/revocation. diff --git a/crates/sui-framework/packages/sui-system/sources/validator_set.move b/crates/iota-framework/packages/iota-system/sources/validator_set.move similarity index 93% rename from crates/sui-framework/packages/sui-system/sources/validator_set.move rename to crates/iota-framework/packages/iota-system/sources/validator_set.move index 5ba98192a96..6ef543868b1 100644 --- a/crates/sui-framework/packages/sui-system/sources/validator_set.move +++ b/crates/iota-framework/packages/iota-system/sources/validator_set.move @@ -1,33 +1,34 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui_system::validator_set { - - use sui::balance::Balance; - use sui::sui::SUI; - use sui_system::validator::{Validator, staking_pool_id, sui_address}; - use sui_system::validator_cap::{Self, UnverifiedValidatorOperationCap, ValidatorOperationCap}; - use sui_system::staking_pool::{PoolTokenExchangeRate, StakedSui, pool_id}; - use sui::priority_queue as pq; - use sui::vec_map::{Self, VecMap}; - use sui::vec_set::VecSet; - use sui::table::{Self, Table}; - use sui::event; - use sui::table_vec::{Self, TableVec}; - use sui_system::voting_power; - use sui_system::validator_wrapper::ValidatorWrapper; - use sui_system::validator_wrapper; - use sui::bag::Bag; - use sui::bag; - - /* friend sui_system::genesis; */ - /* friend sui_system::sui_system_state_inner; */ +module iota_system::validator_set { + + use iota::balance::Balance; + use iota::iota::IOTA; + use iota_system::validator::{Validator, staking_pool_id, iota_address}; + use iota_system::validator_cap::{Self, UnverifiedValidatorOperationCap, ValidatorOperationCap}; + use iota_system::staking_pool::{PoolTokenExchangeRate, StakedIota, pool_id}; + use iota::priority_queue as pq; + use iota::vec_map::{Self, VecMap}; + use iota::vec_set::VecSet; + use iota::table::{Self, Table}; + use iota::event; + use iota::table_vec::{Self, TableVec}; + use iota_system::voting_power; + use iota_system::validator_wrapper::ValidatorWrapper; + use iota_system::validator_wrapper; + use iota::bag::Bag; + use iota::bag; + + /* friend iota_system::genesis; */ + /* friend iota_system::iota_system_state_inner; */ /* #[test_only] */ - /* friend sui_system::validator_set_tests; */ + /* friend iota_system::validator_set_tests; */ /* #[test_only] */ - /* friend sui_system::stake_tests; */ + /* friend iota_system::stake_tests; */ public struct ValidatorSet has store { /// Total amount of stake from all active validators at the beginning of the epoch. @@ -44,7 +45,7 @@ module sui_system::validator_set { /// pointing to `active_validators`. pending_removals: vector, - /// Mappings from staking pool's ID to the sui address of a validator. + /// Mappings from staking pool's ID to the iota address of a validator. staking_pool_mappings: Table, /// Mapping from a staking pool ID to the inactive validator that has that pool as its staking pool. @@ -114,13 +115,13 @@ module sui_system::validator_set { is_voluntary: bool, } - // same as in sui_system + // same as in iota_system const ACTIVE_VALIDATOR_ONLY: u8 = 1; const ACTIVE_OR_PENDING_VALIDATOR: u8 = 2; const ANY_VALIDATOR: u8 = 3; const BASIS_POINT_DENOMINATOR: u128 = 10000; - const MIN_STAKING_THRESHOLD: u64 = 1_000_000_000; // 1 SUI + const MIN_STAKING_THRESHOLD: u64 = 1_000_000_000; // 1 IOTA // Errors const ENonValidatorInReportRecords: u64 = 0; @@ -151,7 +152,7 @@ module sui_system::validator_set { let mut i = 0; while (i < num_validators) { let validator = &init_active_validators[i]; - staking_pool_mappings.add(staking_pool_id(validator), sui_address(validator)); + staking_pool_mappings.add(staking_pool_id(validator), iota_address(validator)); i = i + 1; }; let mut validators = ValidatorSet { @@ -172,7 +173,7 @@ module sui_system::validator_set { // ==== functions to add or remove validators ==== - /// Called by `sui_system` to add a new validator candidate. + /// Called by `iota_system` to add a new validator candidate. public(package) fun request_add_validator_candidate( self: &mut ValidatorSet, validator: Validator, @@ -184,7 +185,7 @@ module sui_system::validator_set { && !is_duplicate_with_pending_validator(self, &validator), EDuplicateValidator ); - let validator_address = sui_address(&validator); + let validator_address = iota_address(&validator); assert!( !self.validator_candidates.contains(validator_address), EAlreadyValidatorCandidate @@ -195,12 +196,12 @@ module sui_system::validator_set { // staking with this candidate. self.staking_pool_mappings.add(staking_pool_id(&validator), validator_address); self.validator_candidates.add( - sui_address(&validator), + iota_address(&validator), validator_wrapper::create_v1(validator, ctx), ); } - /// Called by `sui_system` to remove a validator candidate, and move them to `inactive_validators`. + /// Called by `iota_system` to remove a validator candidate, and move them to `inactive_validators`. public(package) fun request_remove_validator_candidate(self: &mut ValidatorSet, ctx: &mut TxContext) { let validator_address = ctx.sender(); assert!( @@ -226,7 +227,7 @@ module sui_system::validator_set { ); } - /// Called by `sui_system` to add a new validator to `pending_active_validators`, which will be + /// Called by `iota_system` to add a new validator to `pending_active_validators`, which will be /// processed at the end of epoch. public(package) fun request_add_validator(self: &mut ValidatorSet, min_joining_stake_amount: u64, ctx: &TxContext) { let validator_address = ctx.sender(); @@ -256,7 +257,7 @@ module sui_system::validator_set { ); } - /// Called by `sui_system`, to remove a validator. + /// Called by `iota_system`, to remove a validator. /// The index of the validator is added to `pending_removals` and /// will be processed at the end of epoch. /// Only an active validator can request to be removed. @@ -278,44 +279,44 @@ module sui_system::validator_set { // ==== staking related functions ==== - /// Called by `sui_system`, to add a new stake to the validator. + /// Called by `iota_system`, to add a new stake to the validator. /// This request is added to the validator's staking pool's pending stake entries, processed at the end /// of the epoch. /// Aborts in case the staking amount is smaller than MIN_STAKING_THRESHOLD public(package) fun request_add_stake( self: &mut ValidatorSet, validator_address: address, - stake: Balance, + stake: Balance, ctx: &mut TxContext, - ) : StakedSui { - let sui_amount = stake.value(); - assert!(sui_amount >= MIN_STAKING_THRESHOLD, EStakingBelowThreshold); + ) : StakedIota { + let iota_amount = stake.value(); + assert!(iota_amount >= MIN_STAKING_THRESHOLD, EStakingBelowThreshold); let validator = get_candidate_or_active_validator_mut(self, validator_address); validator.request_add_stake(stake, ctx.sender(), ctx) } - /// Called by `sui_system`, to withdraw some share of a stake from the validator. The share to withdraw + /// Called by `iota_system`, to withdraw some share of a stake from the validator. The share to withdraw /// is denoted by `principal_withdraw_amount`. One of two things occurs in this function: - /// 1. If the `staked_sui` is staked with an active validator, the request is added to the validator's + /// 1. If the `staked_iota` is staked with an active validator, the request is added to the validator's /// staking pool's pending stake withdraw entries, processed at the end of the epoch. - /// 2. If the `staked_sui` was staked with a validator that is no longer active, + /// 2. If the `staked_iota` was staked with a validator that is no longer active, /// the stake and any rewards corresponding to it will be immediately processed. public(package) fun request_withdraw_stake( self: &mut ValidatorSet, - staked_sui: StakedSui, + staked_iota: StakedIota, ctx: &TxContext, - ) : Balance { - let staking_pool_id = pool_id(&staked_sui); + ) : Balance { + let staking_pool_id = pool_id(&staked_iota); let validator = if (self.staking_pool_mappings.contains(staking_pool_id)) { // This is an active validator. - let validator_address = self.staking_pool_mappings[pool_id(&staked_sui)]; + let validator_address = self.staking_pool_mappings[pool_id(&staked_iota)]; get_candidate_or_active_validator_mut(self, validator_address) } else { // This is an inactive pool. assert!(self.inactive_validators.contains(staking_pool_id), ENoPoolFound); let wrapper = &mut self.inactive_validators[staking_pool_id]; wrapper.load_validator_maybe_upgrade() }; - validator.request_withdraw_stake(staked_sui, ctx) + validator.request_withdraw_stake(staked_iota, ctx) } // ==== validator config setting functions ==== @@ -342,8 +343,8 @@ module sui_system::validator_set { /// 5. At the end, we calculate the total stake for the new epoch. public(package) fun advance_epoch( self: &mut ValidatorSet, - computation_reward: &mut Balance, - storage_fund_reward: &mut Balance, + computation_reward: &mut Balance, + storage_fund_reward: &mut Balance, validator_report_records: &mut VecMap>, reward_slashing_rate: u64, low_stake_threshold: u64, @@ -452,7 +453,7 @@ module sui_system::validator_set { while (i > 0) { i = i - 1; let validator_ref = &self.active_validators[i]; - let validator_address = validator_ref.sui_address(); + let validator_address = validator_ref.iota_address(); let stake = validator_ref.total_stake_amount(); if (stake >= low_stake_threshold) { // The validator is safe. We remove their entry from the at_risk map if there exists one. @@ -497,7 +498,7 @@ module sui_system::validator_set { } } - /// Called by `sui_system` to derive reference gas price for the new epoch. + /// Called by `iota_system` to derive reference gas price for the new epoch. /// Derive the reference gas price based on the gas price quote submitted by each validator. /// The returned gas price should be greater than or equal to 2/3 of the validators submitted /// gas price, weighted by stake. @@ -572,7 +573,7 @@ module sui_system::validator_set { } /// Returns true iff the address exists in active validators. - public(package) fun is_active_validator_by_sui_address( + public(package) fun is_active_validator_by_iota_address( self: &ValidatorSet, validator_address: address, ): bool { @@ -582,8 +583,8 @@ module sui_system::validator_set { // ==== private helpers ==== /// Checks whether `new_validator` is duplicate with any currently active validators. - /// It differs from `is_active_validator_by_sui_address` in that the former checks - /// only the sui address but this function looks at more metadata. + /// It differs from `is_active_validator_by_iota_address` in that the former checks + /// only the iota address but this function looks at more metadata. fun is_duplicate_with_active_validator(self: &ValidatorSet, new_validator: &Validator): bool { is_duplicate_validator(&self.active_validators, new_validator) } @@ -642,7 +643,7 @@ module sui_system::validator_set { let mut i = 0; while (i < length) { let v = &validators[i]; - if (v.sui_address() == validator_address) { + if (v.iota_address() == validator_address) { return option::some(i) }; i = i + 1; @@ -658,7 +659,7 @@ module sui_system::validator_set { let mut i = 0; while (i < length) { let v = &validators[i]; - if (v.sui_address() == validator_address) { + if (v.iota_address() == validator_address) { return option::some(i) }; i = i + 1; @@ -839,7 +840,7 @@ module sui_system::validator_set { ctx: &mut TxContext, ) { let new_epoch = ctx.epoch() + 1; - let validator_address = validator.sui_address(); + let validator_address = validator.iota_address(); let validator_pool_id = staking_pool_id(&validator); // Remove the validator from our tables. @@ -905,7 +906,7 @@ module sui_system::validator_set { event::emit( ValidatorJoinEvent { epoch: new_epoch, - validator_address: validator.sui_address(), + validator_address: validator.iota_address(), staking_pool_id: staking_pool_id(&validator), } ); @@ -1025,7 +1026,7 @@ module sui_system::validator_set { while (!validator_report_records.is_empty()) { let (validator_address, reporters) = validator_report_records.pop(); assert!( - is_active_validator_by_sui_address(self, validator_address), + is_active_validator_by_iota_address(self, validator_address), ENonValidatorInReportRecords, ); // Sum up the voting power of validators that have reported this validator and check if it has @@ -1137,8 +1138,8 @@ module sui_system::validator_set { validators: &mut vector, adjusted_staking_reward_amounts: &vector, adjusted_storage_fund_reward_amounts: &vector, - staking_rewards: &mut Balance, - storage_fund_reward: &mut Balance, + staking_rewards: &mut Balance, + storage_fund_reward: &mut Balance, ctx: &mut TxContext ) { let length = validators.length(); @@ -1162,7 +1163,7 @@ module sui_system::validator_set { // Add rewards to the validator. Don't try and distribute rewards though if the payout is zero. if (validator_reward.value() > 0) { - let validator_address = validator.sui_address(); + let validator_address = validator.iota_address(); let rewards_stake = validator.request_add_stake(validator_reward, validator_address, ctx); transfer::public_transfer(rewards_stake, validator_address); } else { @@ -1189,7 +1190,7 @@ module sui_system::validator_set { let mut i = 0; while (i < num_validators) { let v = &vs[i]; - let validator_address = v.sui_address(); + let validator_address = v.iota_address(); let tallying_rule_reporters = if (report_records.contains(&validator_address)) { report_records[&validator_address].into_keys() @@ -1252,7 +1253,7 @@ module sui_system::validator_set { let mut i = 0; let length = vs.length(); while (i < length) { - let validator_address = vs[i].sui_address(); + let validator_address = vs[i].iota_address(); res.push_back(validator_address); i = i + 1; }; diff --git a/crates/iota-framework/packages/iota-system/sources/validator_wrapper.move b/crates/iota-framework/packages/iota-system/sources/validator_wrapper.move new file mode 100644 index 00000000000..b76643e5d83 --- /dev/null +++ b/crates/iota-framework/packages/iota-system/sources/validator_wrapper.move @@ -0,0 +1,54 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::validator_wrapper { + use iota::versioned::Versioned; + use iota_system::validator::Validator; + use iota::versioned; + + /* friend iota_system::validator_set; */ + + const EInvalidVersion: u64 = 0; + + public struct ValidatorWrapper has store { + inner: Versioned + } + + // Validator corresponds to version 1. + public(package) fun create_v1(validator: Validator, ctx: &mut TxContext): ValidatorWrapper { + ValidatorWrapper { + inner: versioned::create(1, validator, ctx) + } + } + + /// This function should always return the latest supported version. + /// If the inner version is old, we upgrade it lazily in-place. + public(package) fun load_validator_maybe_upgrade(self: &mut ValidatorWrapper): &mut Validator { + upgrade_to_latest(self); + versioned::load_value_mut(&mut self.inner) + } + + /// Destroy the wrapper and retrieve the inner validator object. + public(package) fun destroy(self: ValidatorWrapper): Validator { + upgrade_to_latest(&self); + let ValidatorWrapper { inner } = self; + versioned::destroy(inner) + } + + #[test_only] + /// Load the inner validator with assumed type. This should be used for testing only. + public(package) fun get_inner_validator_ref(self: &ValidatorWrapper): &Validator { + versioned::load_value(&self.inner) + } + + fun upgrade_to_latest(self: &ValidatorWrapper) { + let version = version(self); + // TODO: When new versions are added, we need to explicitly upgrade here. + assert!(version == 1, EInvalidVersion); + } + + fun version(self: &ValidatorWrapper): u64 { + versioned::version(&self.inner) + } +} diff --git a/crates/sui-framework/packages/sui-system/sources/voting_power.move b/crates/iota-framework/packages/iota-system/sources/voting_power.move similarity index 96% rename from crates/sui-framework/packages/sui-system/sources/voting_power.move rename to crates/iota-framework/packages/iota-system/sources/voting_power.move index 0c5e51c640e..9a638472971 100644 --- a/crates/sui-framework/packages/sui-system/sources/voting_power.move +++ b/crates/iota-framework/packages/iota-system/sources/voting_power.move @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -module sui_system::voting_power { - use sui_system::validator::Validator; - use sui::math; - use sui::math::divide_and_round_up; +module iota_system::voting_power { + use iota_system::validator::Validator; + use iota::math; + use iota::math::divide_and_round_up; - /* friend sui_system::validator_set; */ + /* friend iota_system::validator_set; */ /* #[test_only] */ - /* friend sui_system::voting_power_tests; */ + /* friend iota_system::voting_power_tests; */ #[allow(unused_field)] /// Deprecated. Use VotingPowerInfoV2 instead. diff --git a/crates/iota-framework/packages/iota-system/tests/delegation_tests.move b/crates/iota-framework/packages/iota-system/tests/delegation_tests.move new file mode 100644 index 00000000000..5cd1118b95f --- /dev/null +++ b/crates/iota-framework/packages/iota-system/tests/delegation_tests.move @@ -0,0 +1,564 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module iota_system::stake_tests { + use iota::coin; + use iota::test_scenario; + use iota_system::iota_system::IotaSystemState; + use iota_system::staking_pool::{Self, StakedIota, PoolTokenExchangeRate}; + use iota::test_utils::assert_eq; + use iota_system::validator_set; + use iota::test_utils; + use iota::table::Table; + + use iota_system::governance_test_utils::{ + add_validator, + add_validator_candidate, + advance_epoch, + advance_epoch_with_reward_amounts, + assert_validator_total_stake_amounts, + create_validator_for_testing, + create_iota_system_state_for_testing, + stake_with, + remove_validator, + remove_validator_candidate, + total_iota_balance, + unstake, + }; + + const VALIDATOR_ADDR_1: address = @0x1; + const VALIDATOR_ADDR_2: address = @0x2; + + const STAKER_ADDR_1: address = @0x42; + const STAKER_ADDR_2: address = @0x43; + const STAKER_ADDR_3: address = @0x44; + + const NEW_VALIDATOR_ADDR: address = @0x1a4623343cd42be47d67314fce0ad042f3c82685544bc91d8c11d24e74ba7357; + // Generated with seed [0;32] + const NEW_VALIDATOR_PUBKEY: vector = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; + // Generated using [fn test_proof_of_possession] + const NEW_VALIDATOR_POP: vector = x"8b93fc1b33379e2796d361c4056f0f04ad5aea7f4a8c02eaac57340ff09b6dc158eb1945eece103319167f420daf0cb3"; + + const MICROS_PER_IOTA: u64 = 1_000_000_000; + + #[test] + fun test_split_join_staked_iota() { + // All this is just to generate a dummy StakedIota object to split and join later + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); + let scenario = &mut scenario_val; + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + let mut staked_iota = scenario.take_from_sender(); + let ctx = scenario.ctx(); + staked_iota.split_to_sender(20 * MICROS_PER_IOTA, ctx); + scenario.return_to_sender(staked_iota); + }; + + // Verify the correctness of the split and send the join txn + scenario.next_tx(STAKER_ADDR_1); + { + let staked_iota_ids = scenario.ids_for_sender(); + assert!(staked_iota_ids.length() == 2, 101); // staked iota split to 2 coins + + let mut part1 = scenario.take_from_sender_by_id(staked_iota_ids[0]); + let part2 = scenario.take_from_sender_by_id(staked_iota_ids[1]); + + let amount1 = part1.amount(); + let amount2 = part2.amount(); + assert!(amount1 == 20 * MICROS_PER_IOTA || amount1 == 40 * MICROS_PER_IOTA, 102); + assert!(amount2 == 20 * MICROS_PER_IOTA || amount2 == 40 * MICROS_PER_IOTA, 103); + assert!(amount1 + amount2 == 60 * MICROS_PER_IOTA, 104); + + part1.join(part2); + assert!(part1.amount() == 60 * MICROS_PER_IOTA, 105); + scenario.return_to_sender(part1); + }; + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = staking_pool::EIncompatibleStakedIota)] + fun test_join_different_epochs() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); + let scenario = &mut scenario_val; + // Create two instances of staked iota w/ different epoch activations + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, scenario); + advance_epoch(scenario); + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, scenario); + + // Verify that these cannot be merged + scenario.next_tx(STAKER_ADDR_1); + { + let staked_iota_ids = scenario.ids_for_sender(); + let mut part1 = scenario.take_from_sender_by_id(staked_iota_ids[0]); + let part2 = scenario.take_from_sender_by_id(staked_iota_ids[1]); + + part1.join(part2); + + scenario.return_to_sender(part1); + }; + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = staking_pool::EStakedIotaBelowThreshold)] + fun test_split_below_threshold() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); + let scenario = &mut scenario_val; + // Stake 2 IOTA + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 2, scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + let mut staked_iota = scenario.take_from_sender(); + let ctx = scenario.ctx(); + // The remaining amount after splitting is below the threshold so this should fail. + staked_iota.split_to_sender(1 * MICROS_PER_IOTA + 1, ctx); + scenario.return_to_sender(staked_iota); + }; + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = staking_pool::EStakedIotaBelowThreshold)] + fun test_split_nonentry_below_threshold() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); + let scenario = &mut scenario_val; + // Stake 2 IOTA + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 2, scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + let mut staked_iota = scenario.take_from_sender(); + let ctx = scenario.ctx(); + // The remaining amount after splitting is below the threshold so this should fail. + let stake = staked_iota.split(1 * MICROS_PER_IOTA + 1, ctx); + test_utils::destroy(stake); + scenario.return_to_sender(staked_iota); + }; + scenario_val.end(); + } + + #[test] + fun test_add_remove_stake_flow() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + scenario.next_tx(STAKER_ADDR_1); + { + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + let ctx = scenario.ctx(); + + // Create a stake to VALIDATOR_ADDR_1. + system_state_mut_ref.request_add_stake( + coin::mint_for_testing(60 * MICROS_PER_IOTA, ctx), VALIDATOR_ADDR_1, ctx + ); + + assert!(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1) == 100 * MICROS_PER_IOTA, 101); + assert!(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2) == 100 * MICROS_PER_IOTA, 102); + + test_scenario::return_shared(system_state); + }; + + advance_epoch(scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + + let staked_iota = scenario.take_from_sender(); + assert!(staked_iota.amount() == 60 * MICROS_PER_IOTA, 105); + + + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + assert!(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1) == 160 * MICROS_PER_IOTA, 103); + assert!(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2) == 100 * MICROS_PER_IOTA, 104); + + let ctx = scenario.ctx(); + + // Unstake from VALIDATOR_ADDR_1 + system_state_mut_ref.request_withdraw_stake(staked_iota, ctx); + + assert!(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1) == 160 * MICROS_PER_IOTA, 107); + test_scenario::return_shared(system_state); + }; + + advance_epoch(scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + let mut system_state = scenario.take_shared(); + assert!(system_state.validator_stake_amount(VALIDATOR_ADDR_1) == 100 * MICROS_PER_IOTA, 107); + test_scenario::return_shared(system_state); + }; + scenario_val.end(); + } + + #[test] + fun test_remove_stake_post_active_flow_no_rewards() { + test_remove_stake_post_active_flow(false) + } + + #[test] + fun test_remove_stake_post_active_flow_with_rewards() { + test_remove_stake_post_active_flow(true) + } + + fun test_remove_stake_post_active_flow(should_distribute_rewards: bool) { + set_up_iota_system_state_with_storage_fund(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, scenario); + + advance_epoch(scenario); + + assert_validator_total_stake_amounts( + vector[VALIDATOR_ADDR_1, VALIDATOR_ADDR_2], + vector[200 * MICROS_PER_IOTA, 100 * MICROS_PER_IOTA], + scenario + ); + + if (should_distribute_rewards) { + // Each validator pool gets 30 MICROS and each validator gets an additional 10 MICROS. + advance_epoch_with_reward_amounts(0, 80, scenario); + } else { + advance_epoch(scenario); + }; + + remove_validator(VALIDATOR_ADDR_1, scenario); + + advance_epoch(scenario); + + let reward_amt = if (should_distribute_rewards) 15 * MICROS_PER_IOTA else 0; + let validator_reward_amt = if (should_distribute_rewards) 10 * MICROS_PER_IOTA else 0; + + // Make sure stake withdrawal happens + scenario.next_tx(STAKER_ADDR_1); + { + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + assert!(!system_state_mut_ref.validators().is_active_validator_by_iota_address(VALIDATOR_ADDR_1), 0); + + let staked_iota = scenario.take_from_sender(); + assert_eq(staked_iota.amount(), 100 * MICROS_PER_IOTA); + + // Unstake from VALIDATOR_ADDR_1 + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 0); + let ctx = scenario.ctx(); + system_state_mut_ref.request_withdraw_stake(staked_iota, ctx); + + // Make sure they have all of their stake. + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 100 * MICROS_PER_IOTA + reward_amt); + + test_scenario::return_shared(system_state); + }; + + // Validator unstakes now. + assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 0); + unstake(VALIDATOR_ADDR_1, 0, scenario); + if (should_distribute_rewards) unstake(VALIDATOR_ADDR_1, 0, scenario); + + // Make sure have all of their stake. NB there is no epoch change. This is immediate. + assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 100 * MICROS_PER_IOTA + reward_amt + validator_reward_amt); + + scenario_val.end(); + } + + #[test] + fun test_earns_rewards_at_last_epoch() { + set_up_iota_system_state_with_storage_fund(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, scenario); + + advance_epoch(scenario); + + remove_validator(VALIDATOR_ADDR_1, scenario); + + // Add some rewards after the validator requests to leave. Since the validator is still active + // this epoch, they should get the rewards from this epoch. + advance_epoch_with_reward_amounts(0, 80, scenario); + + // Each validator pool gets 30 MICROS and validators shares the 20 MICROS from the storage fund + // so validator gets another 10 MICROS. + let reward_amt = 15 * MICROS_PER_IOTA; + let validator_reward_amt = 10 * MICROS_PER_IOTA; + + // Make sure stake withdrawal happens + scenario.next_tx(STAKER_ADDR_1); + { + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + let staked_iota = scenario.take_from_sender(); + assert_eq(staked_iota.amount(), 100 * MICROS_PER_IOTA); + + // Unstake from VALIDATOR_ADDR_1 + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 0); + let ctx = scenario.ctx(); + system_state_mut_ref.request_withdraw_stake(staked_iota, ctx); + + // Make sure they have all of their stake. + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 100 * MICROS_PER_IOTA + reward_amt); + + test_scenario::return_shared(system_state); + }; + + // Validator unstakes now. + assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 0); + unstake(VALIDATOR_ADDR_1, 0, scenario); + unstake(VALIDATOR_ADDR_1, 0, scenario); + + // Make sure have all of their stake. NB there is no epoch change. This is immediate. + assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 100 * MICROS_PER_IOTA + reward_amt + validator_reward_amt); + + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = validator_set::ENotAValidator)] + fun test_add_stake_post_active_flow() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, scenario); + + advance_epoch(scenario); + + remove_validator(VALIDATOR_ADDR_1, scenario); + + advance_epoch(scenario); + + // Make sure the validator is no longer active. + scenario.next_tx(STAKER_ADDR_1); + { + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + assert!(!system_state_mut_ref.validators().is_active_validator_by_iota_address(VALIDATOR_ADDR_1), 0); + + test_scenario::return_shared(system_state); + }; + + // Now try and stake to the old validator/staking pool. This should fail! + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, scenario); + + scenario_val.end(); + } + + #[test] + fun test_add_preactive_remove_preactive() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + add_validator_candidate(NEW_VALIDATOR_ADDR, b"name5", b"/ip4/127.0.0.1/udp/85", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); + + // Delegate 100 MICROS to the preactive validator + stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); + + // Advance epoch twice with some rewards + advance_epoch_with_reward_amounts(0, 400, scenario); + advance_epoch_with_reward_amounts(0, 900, scenario); + + // Unstake from the preactive validator. There should be no rewards earned. + unstake(STAKER_ADDR_1, 0, scenario); + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 100 * MICROS_PER_IOTA); + + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = validator_set::ENotAValidator)] + fun test_add_preactive_remove_pending_failure() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + add_validator_candidate(NEW_VALIDATOR_ADDR, b"name4", b"/ip4/127.0.0.1/udp/84", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); + + add_validator(NEW_VALIDATOR_ADDR, scenario); + + // Delegate 100 IOTA to the pending validator. This should fail because pending active validators don't accept + // new stakes or withdraws. + stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); + + scenario_val.end(); + } + + #[test] + fun test_add_preactive_remove_active() { + set_up_iota_system_state_with_storage_fund(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + add_validator_candidate(NEW_VALIDATOR_ADDR, b"name3", b"/ip4/127.0.0.1/udp/83", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); + + // Delegate 100 IOTA to the preactive validator + stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); + advance_epoch_with_reward_amounts(0, 300, scenario); + // At this point we got the following distribution of stake: + // V1: 250, V2: 250, storage fund: 100 + + stake_with(STAKER_ADDR_2, NEW_VALIDATOR_ADDR, 50, scenario); + stake_with(STAKER_ADDR_3, NEW_VALIDATOR_ADDR, 100, scenario); + + // Now the preactive becomes active + add_validator(NEW_VALIDATOR_ADDR, scenario); + advance_epoch(scenario); + + // At this point we got the following distribution of stake: + // V1: 250, V2: 250, V3: 250, storage fund: 100 + + advance_epoch_with_reward_amounts(0, 85, scenario); + + // staker 1 and 3 unstake from the validator and earns about 2/5 * (85 - 10) * 1/3 = 10 IOTA each. + // Although they stake in different epochs, they earn the same rewards as long as they unstake + // in the same epoch because the validator was preactive when they staked. + // So they will both get slightly more than 110 IOTA in total balance. + unstake(STAKER_ADDR_1, 0, scenario); + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 110002000000); + unstake(STAKER_ADDR_3, 0, scenario); + assert_eq(total_iota_balance(STAKER_ADDR_3, scenario), 110002000000); + + advance_epoch_with_reward_amounts(0, 85, scenario); + unstake(STAKER_ADDR_2, 0, scenario); + // staker 2 earns about 5 IOTA from the previous epoch and 24-ish from this one + // so in total she has about 50 + 5 + 24 = 79 IOTA. + assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), 78862939078); + + scenario_val.end(); + } + + #[test] + fun test_add_preactive_remove_post_active() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + add_validator_candidate(NEW_VALIDATOR_ADDR, b"name1", b"/ip4/127.0.0.1/udp/81", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); + + // Delegate 100 IOTA to the preactive validator + stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); + + // Now the preactive becomes active + add_validator(NEW_VALIDATOR_ADDR, scenario); + advance_epoch(scenario); + + // staker 1 earns a bit greater than 30 IOTA here. A bit greater because the new validator's voting power + // is slightly greater than 1/3 of the total voting power. + advance_epoch_with_reward_amounts(0, 90, scenario); + + // And now the validator leaves the validator set. + remove_validator(NEW_VALIDATOR_ADDR, scenario); + + advance_epoch(scenario); + + unstake(STAKER_ADDR_1, 0, scenario); + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 130006000000); + + scenario_val.end(); + } + + #[test] + fun test_add_preactive_candidate_drop_out() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + add_validator_candidate(NEW_VALIDATOR_ADDR, b"name2", b"/ip4/127.0.0.1/udp/82", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); + + // Delegate 100 MICROS to the preactive validator + stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); + + // Advance epoch and give out some rewards. The candidate should get nothing, of course. + advance_epoch_with_reward_amounts(0, 800, scenario); + + // Now the candidate leaves. + remove_validator_candidate(NEW_VALIDATOR_ADDR, scenario); + + // Advance epoch a few times. + advance_epoch(scenario); + advance_epoch(scenario); + advance_epoch(scenario); + + // Unstake now and the staker should get no rewards. + unstake(STAKER_ADDR_1, 0, scenario); + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 100 * MICROS_PER_IOTA); + + scenario_val.end(); + } + + #[test] + fun test_staking_pool_exchange_rate_getter() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + stake_with(@0x42, @0x2, 100, scenario); // stakes 100 IOTA with 0x2 + scenario.next_tx(@0x42); + let staked_iota = scenario.take_from_address(@0x42); + let pool_id = staked_iota.pool_id(); + test_scenario::return_to_address(@0x42, staked_iota); + advance_epoch(scenario); // advances epoch to effectuate the stake + // Each staking pool gets 10 IOTA of rewards. + advance_epoch_with_reward_amounts(0, 20, scenario); + let mut system_state = scenario.take_shared(); + let rates = system_state.pool_exchange_rates(&pool_id); + assert_eq(rates.length(), 3); + assert_exchange_rate_eq(rates, 0, 0, 0); // no tokens at epoch 0 + assert_exchange_rate_eq(rates, 1, 200, 200); // 200 IOTA of self + delegate stake at epoch 1 + assert_exchange_rate_eq(rates, 2, 210, 200); // 10 IOTA of rewards at epoch 2 + test_scenario::return_shared(system_state); + scenario_val.end(); + } + + fun assert_exchange_rate_eq( + rates: &Table, epoch: u64, iota_amount: u64, pool_token_amount: u64 + ) { + let rate = &rates[epoch]; + assert_eq(rate.iota_amount(), iota_amount * MICROS_PER_IOTA); + assert_eq(rate.pool_token_amount(), pool_token_amount * MICROS_PER_IOTA); + } + + fun set_up_iota_system_state() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + let ctx = scenario.ctx(); + + let validators = vector[ + create_validator_for_testing(VALIDATOR_ADDR_1, 100, ctx), + create_validator_for_testing(VALIDATOR_ADDR_2, 100, ctx) + ]; + create_iota_system_state_for_testing(validators, 0, 0, ctx); + scenario_val.end(); + } + + fun set_up_iota_system_state_with_storage_fund() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + let ctx = scenario.ctx(); + + let validators = vector[ + create_validator_for_testing(VALIDATOR_ADDR_1, 100, ctx), + create_validator_for_testing(VALIDATOR_ADDR_2, 100, ctx) + ]; + create_iota_system_state_for_testing(validators, 300, 100, ctx); + scenario_val.end(); + } +} diff --git a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move new file mode 100644 index 00000000000..327418973ac --- /dev/null +++ b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move @@ -0,0 +1,343 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module iota_system::governance_test_utils { + use iota::address; + use iota::balance; + use iota::iota::IOTA; + use iota::coin::{Self, Coin}; + use iota_system::staking_pool::{StakedIota, StakingPool}; + use iota::test_utils::assert_eq; + use iota_system::validator::{Self, Validator}; + use iota_system::iota_system::{Self, IotaSystemState}; + use iota_system::iota_system_state_inner; + use iota_system::stake_subsidy; + use iota::test_scenario::{Self, Scenario}; + use iota::test_utils; + use iota::balance::Balance; + + const MICROS_PER_IOTA: u64 = 1_000_000_000; + + public fun create_validator_for_testing( + addr: address, init_stake_amount_in_iota: u64, ctx: &mut TxContext + ): Validator { + let validator = validator::new_for_testing( + addr, + x"AA", + x"BB", + x"CC", + x"DD", + b"ValidatorName", + b"description", + b"image_url", + b"project_url", + b"/ip4/127.0.0.1/tcp/80", + b"/ip4/127.0.0.1/udp/80", + b"/ip4/127.0.0.1/udp/80", + b"/ip4/127.0.0.1/udp/80", + option::some(balance::create_for_testing(init_stake_amount_in_iota * MICROS_PER_IOTA)), + 1, + 0, + true, + ctx + ); + validator + } + + /// Create a validator set with the given stake amounts + public fun create_validators_with_stakes(stakes: vector, ctx: &mut TxContext): vector { + let mut i = 0; + let mut validators = vector[]; + while (i < stakes.length()) { + let validator = create_validator_for_testing(address::from_u256(i as u256), stakes[i], ctx); + validators.push_back(validator); + i = i + 1 + }; + validators + } + + public fun create_iota_system_state_for_testing( + validators: vector, iota_supply_amount: u64, storage_fund_amount: u64, ctx: &mut TxContext + ) { + let system_parameters = iota_system_state_inner::create_system_parameters( + 42, // epoch_duration_ms, doesn't matter what number we put here + 0, // stake_subsidy_start_epoch + + 150, // max_validator_count + 1, // min_validator_joining_stake + 1, // validator_low_stake_threshold + 0, // validator_very_low_stake_threshold + 7, // validator_low_stake_grace_period + ctx, + ); + + let stake_subsidy = stake_subsidy::create( + balance::create_for_testing(iota_supply_amount * MICROS_PER_IOTA), // iota_supply + 0, // stake subsidy initial distribution amount + 10, // stake_subsidy_period_length + 0, // stake_subsidy_decrease_rate + ctx, + ); + + iota_system::create( + object::new(ctx), // it doesn't matter what ID iota system state has in tests + validators, + balance::create_for_testing(storage_fund_amount * MICROS_PER_IOTA), // storage_fund + 1, // protocol version + 0, // chain_start_timestamp_ms + system_parameters, + stake_subsidy, + ctx, + ) + } + + public fun set_up_iota_system_state(mut addrs: vector
    ) { + let mut scenario = test_scenario::begin(@0x0); + let ctx = scenario.ctx(); + let mut validators = vector[]; + + while (!addrs.is_empty()) { + validators.push_back( + create_validator_for_testing(addrs.pop_back(), 100, ctx) + ); + }; + + create_iota_system_state_for_testing(validators, 1000, 0, ctx); + scenario.end(); + } + + public fun advance_epoch(scenario: &mut Scenario) { + advance_epoch_with_reward_amounts(0, 0, scenario); + } + + public fun advance_epoch_with_reward_amounts_return_rebate( + storage_charge: u64, computation_charge: u64, stoarge_rebate: u64, non_refundable_storage_rebate: u64, scenario: &mut Scenario, + ): Balance { + scenario.next_tx(@0x0); + let new_epoch = scenario.ctx().epoch() + 1; + let mut system_state = scenario.take_shared(); + + let ctx = scenario.ctx(); + + let storage_rebate = system_state.advance_epoch_for_testing( + new_epoch, 1, storage_charge, computation_charge, stoarge_rebate, non_refundable_storage_rebate, 0, 0, 0, ctx, + ); + test_scenario::return_shared(system_state); + scenario.next_epoch(@0x0); + storage_rebate + } + + public fun advance_epoch_with_reward_amounts( + storage_charge: u64, computation_charge: u64, scenario: &mut Scenario + ) { + let storage_rebate = advance_epoch_with_reward_amounts_return_rebate(storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, scenario); + test_utils::destroy(storage_rebate) + } + + public fun advance_epoch_with_reward_amounts_and_slashing_rates( + storage_charge: u64, + computation_charge: u64, + reward_slashing_rate: u64, + scenario: &mut Scenario + ) { + scenario.next_tx(@0x0); + let new_epoch = scenario.ctx().epoch() + 1; + let mut system_state = scenario.take_shared(); + + let ctx = scenario.ctx(); + + let storage_rebate = system_state.advance_epoch_for_testing( + new_epoch, 1, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, 0, reward_slashing_rate, 0, ctx + ); + test_utils::destroy(storage_rebate); + test_scenario::return_shared(system_state); + scenario.next_epoch(@0x0); + } + + public fun stake_with( + staker: address, validator: address, amount: u64, scenario: &mut Scenario + ) { + scenario.next_tx(staker); + let mut system_state = scenario.take_shared(); + + let ctx = scenario.ctx(); + + system_state.request_add_stake(coin::mint_for_testing(amount * MICROS_PER_IOTA, ctx), validator, ctx); + test_scenario::return_shared(system_state); + } + + public fun unstake( + staker: address, staked_iota_idx: u64, scenario: &mut Scenario + ) { + scenario.next_tx(staker); + let stake_iota_ids = scenario.ids_for_sender(); + let staked_iota = scenario.take_from_sender_by_id(stake_iota_ids[staked_iota_idx]); + let mut system_state = scenario.take_shared(); + + let ctx = scenario.ctx(); + system_state.request_withdraw_stake(staked_iota, ctx); + test_scenario::return_shared(system_state); + } + + public fun add_validator_full_flow(validator: address, name: vector, net_addr: vector, init_stake_amount: u64, pubkey: vector, pop: vector, scenario: &mut Scenario) { + scenario.next_tx(validator); + let mut system_state = scenario.take_shared(); + let ctx = scenario.ctx(); + + system_state.request_add_validator_candidate( + pubkey, + vector[171, 2, 39, 3, 139, 105, 166, 171, 153, 151, 102, 197, 151, 186, 140, 116, 114, 90, 213, 225, 20, 167, 60, 69, 203, 12, 180, 198, 9, 217, 117, 38], + vector[171, 3, 39, 3, 139, 105, 166, 171, 153, 151, 102, 197, 151, 186, 140, 116, 114, 90, 213, 225, 20, 167, 60, 69, 203, 12, 180, 198, 9, 217, 117, 38], + pop, + name, + b"description", + b"image_url", + b"project_url", + net_addr, + net_addr, + net_addr, + net_addr, + 1, + 0, + ctx + ); + system_state.request_add_stake(coin::mint_for_testing(init_stake_amount * MICROS_PER_IOTA, ctx), validator, ctx); + system_state.request_add_validator_for_testing(0, ctx); + test_scenario::return_shared(system_state); + } + + public fun add_validator_candidate(validator: address, name: vector, net_addr: vector, pubkey: vector, pop: vector, scenario: &mut Scenario) { + scenario.next_tx(validator); + let mut system_state = scenario.take_shared(); + let ctx = scenario.ctx(); + + system_state.request_add_validator_candidate( + pubkey, + vector[171, 2, 39, 3, 139, 105, 166, 171, 153, 151, 102, 197, 151, 186, 140, 116, 114, 90, 213, 225, 20, 167, 60, 69, 203, 12, 180, 198, 9, 217, 117, 38], + vector[171, 3, 39, 3, 139, 105, 166, 171, 153, 151, 102, 197, 151, 186, 140, 116, 114, 90, 213, 225, 20, 167, 60, 69, 203, 12, 180, 198, 9, 217, 117, 38], + pop, + name, + b"description", + b"image_url", + b"project_url", + net_addr, + net_addr, + net_addr, + net_addr, + 1, + 0, + ctx + ); + test_scenario::return_shared(system_state); + } + + public fun remove_validator_candidate(validator: address, scenario: &mut Scenario) { + scenario.next_tx(validator); + let mut system_state = scenario.take_shared(); + let ctx = scenario.ctx(); + + system_state.request_remove_validator_candidate(ctx); + test_scenario::return_shared(system_state); + } + + public fun add_validator(validator: address, scenario: &mut Scenario) { + scenario.next_tx(validator); + let mut system_state = scenario.take_shared(); + let ctx = scenario.ctx(); + + system_state.request_add_validator_for_testing(0, ctx); + test_scenario::return_shared(system_state); + } + + public fun remove_validator(validator: address, scenario: &mut Scenario) { + scenario.next_tx(validator); + let mut system_state = scenario.take_shared(); + + let ctx = scenario.ctx(); + + system_state.request_remove_validator(ctx); + test_scenario::return_shared(system_state); + } + + public fun assert_validator_self_stake_amounts(validator_addrs: vector
    , stake_amounts: vector, scenario: &mut Scenario) { + let mut i = 0; + while (i < validator_addrs.length()) { + let validator_addr = validator_addrs[i]; + let amount = stake_amounts[i]; + + scenario.next_tx(validator_addr); + let mut system_state = scenario.take_shared(); + let stake_plus_rewards = stake_plus_current_rewards_for_validator(validator_addr, &mut system_state, scenario); + assert_eq(stake_plus_rewards, amount); + test_scenario::return_shared(system_state); + i = i + 1; + }; + } + + public fun assert_validator_total_stake_amounts(validator_addrs: vector
    , stake_amounts: vector, scenario: &mut Scenario) { + let mut i = 0; + while (i < validator_addrs.length()) { + let validator_addr = validator_addrs[i]; + let amount = stake_amounts[i]; + + scenario.next_tx(validator_addr); + let mut system_state = scenario.take_shared(); + let validator_amount = system_state.validator_stake_amount(validator_addr); + assert!(validator_amount == amount, validator_amount); + test_scenario::return_shared(system_state); + i = i + 1; + }; + } + + public fun assert_validator_non_self_stake_amounts(validator_addrs: vector
    , stake_amounts: vector, scenario: &mut Scenario) { + let mut i = 0; + while (i < validator_addrs.length()) { + let validator_addr = validator_addrs[i]; + let amount = stake_amounts[i]; + scenario.next_tx(validator_addr); + let mut system_state = scenario.take_shared(); + let non_self_stake_amount = system_state.validator_stake_amount(validator_addr) - stake_plus_current_rewards_for_validator(validator_addr, &mut system_state, scenario); + assert_eq(non_self_stake_amount, amount); + test_scenario::return_shared(system_state); + i = i + 1; + }; + } + + /// Return the rewards for the validator at `addr` in terms of IOTA. + public fun stake_plus_current_rewards_for_validator(addr: address, system_state: &mut IotaSystemState, scenario: &mut Scenario): u64 { + let validator_ref = system_state.validators().get_active_validator_ref(addr); + let amount = stake_plus_current_rewards(addr, validator_ref.get_staking_pool_ref(), scenario); + amount + } + + public fun stake_plus_current_rewards(addr: address, staking_pool: &StakingPool, scenario: &mut Scenario): u64 { + let mut sum = 0; + scenario.next_tx(addr); + let mut stake_ids = scenario.ids_for_sender(); + let current_epoch = scenario.ctx().epoch(); + + while (!stake_ids.is_empty()) { + let staked_iota_id = stake_ids.pop_back(); + let staked_iota = scenario.take_from_sender_by_id(staked_iota_id); + sum = sum + staking_pool.calculate_rewards(&staked_iota, current_epoch); + scenario.return_to_sender(staked_iota); + }; + sum + } + + public fun total_iota_balance(addr: address, scenario: &mut Scenario): u64 { + let mut sum = 0; + scenario.next_tx(addr); + let coin_ids = scenario.ids_for_sender>(); + let mut i = 0; + while (i < coin_ids.length()) { + let coin = scenario.take_from_sender_by_id>(coin_ids[i]); + sum = sum + coin.value(); + scenario.return_to_sender(coin); + i = i + 1; + }; + sum + } +} diff --git a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move new file mode 100644 index 00000000000..0761eab8301 --- /dev/null +++ b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move @@ -0,0 +1,1006 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// This file contains tests testing functionalities in `iota_system` that are not +// already tested by the other more themed tests such as `stake_tests` or +// `rewards_distribution_tests`. + +#[test_only] +module iota_system::iota_system_tests { + use iota::test_scenario::{Self, Scenario}; + use iota::iota::IOTA; + use iota_system::governance_test_utils::{add_validator_full_flow, advance_epoch, remove_validator, set_up_iota_system_state, create_iota_system_state_for_testing}; + use iota_system::iota_system::IotaSystemState; + use iota_system::iota_system_state_inner; + use iota_system::validator::{Self, Validator}; + use iota_system::validator_set; + use iota_system::validator_cap::UnverifiedValidatorOperationCap; + use iota::balance; + use iota::test_utils::{assert_eq, destroy}; + use iota::url; + + #[test] + fun test_report_validator() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + + set_up_iota_system_state(vector[@0x1, @0x2, @0x3]); + + report_helper(@0x1, @0x2, false, scenario); + assert!(get_reporters_of(@0x2, scenario) == vector[@0x1], 0); + report_helper(@0x3, @0x2, false, scenario); + assert!(get_reporters_of(@0x2, scenario) == vector[@0x1, @0x3], 0); + + // Report again and result should stay the same. + report_helper(@0x1, @0x2, false, scenario); + assert!(get_reporters_of(@0x2, scenario) == vector[@0x1, @0x3], 0); + + // Undo the report. + report_helper(@0x3, @0x2, true, scenario); + assert!(get_reporters_of(@0x2, scenario) == vector[@0x1], 0); + + advance_epoch(scenario); + + // After an epoch ends, report records are still present. + assert!(get_reporters_of(@0x2, scenario) == vector[@0x1], 0); + + report_helper(@0x2, @0x1, false, scenario); + assert!(get_reporters_of(@0x1, scenario) == vector[@0x2], 0); + + + report_helper(@0x3, @0x2, false, scenario); + assert!(get_reporters_of(@0x2, scenario) == vector[@0x1, @0x3], 0); + + // After 0x3 leaves, its reports are gone + remove_validator(@0x3, scenario); + advance_epoch(scenario); + assert!(get_reporters_of(@0x2, scenario) == vector[@0x1], 0); + + // After 0x1 leaves, both its reports and the reports on its name are gone + remove_validator(@0x1, scenario); + advance_epoch(scenario); + assert!(get_reporters_of(@0x1, scenario).is_empty(), 0); + assert!(get_reporters_of(@0x2, scenario).is_empty(), 0); + scenario_val.end(); + } + + #[test] + fun test_validator_ops_by_stakee_ok() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + set_up_iota_system_state(vector[@0x1, @0x2]); + + // @0x1 transfers the cap object to stakee. + let stakee_address = @0xbeef; + scenario.next_tx(@0x1); + let cap = scenario.take_from_sender(); + transfer::public_transfer(cap, stakee_address); + + // With the cap object in hand, stakee could report validators on behalf of @0x1. + report_helper(stakee_address, @0x2, false, scenario); + assert!(get_reporters_of(@0x2, scenario) == vector[@0x1], 0); + + // stakee could also undo report. + report_helper(stakee_address, @0x2, true, scenario); + assert!(get_reporters_of(@0x2, scenario).is_empty(), 0); + + scenario.next_tx(stakee_address); + let cap = scenario.take_from_sender(); + let new_stakee_address = @0xcafe; + transfer::public_transfer(cap, new_stakee_address); + + // New stakee could report validators on behalf of @0x1. + report_helper(new_stakee_address, @0x2, false, scenario); + assert!(get_reporters_of(@0x2, scenario) == vector[@0x1], 0); + + // New stakee could also set reference gas price on behalf of @0x1. + set_gas_price_helper(new_stakee_address, 666, scenario); + + // Add a pending validator + let new_validator_addr = @0x1a4623343cd42be47d67314fce0ad042f3c82685544bc91d8c11d24e74ba7357; + scenario.next_tx(new_validator_addr); + let pubkey = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; + let pop = x"8b93fc1b33379e2796d361c4056f0f04ad5aea7f4a8c02eaac57340ff09b6dc158eb1945eece103319167f420daf0cb3"; + add_validator_full_flow(new_validator_addr, b"name1", b"/ip4/127.0.0.1/udp/81", 100, pubkey, pop, scenario); + + scenario.next_tx(new_validator_addr); + // Pending validator could set reference price as well + set_gas_price_helper(new_validator_addr, 777, scenario); + + scenario.next_tx(new_stakee_address); + let mut system_state = scenario.take_shared(); + let validator = system_state.active_validator_by_address(@0x1); + assert!(validator.next_epoch_gas_price() == 666, 0); + let pending_validator = system_state.pending_validator_by_address(new_validator_addr); + assert!(pending_validator.next_epoch_gas_price() == 777, 0); + test_scenario::return_shared(system_state); + + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = ::iota_system::validator_set::EInvalidCap)] + fun test_report_validator_by_stakee_revoked() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + set_up_iota_system_state(vector[@0x1, @0x2]); + + // @0x1 transfers the cap object to stakee. + let stakee_address = @0xbeef; + scenario.next_tx(@0x1); + let cap = scenario.take_from_sender(); + transfer::public_transfer(cap, stakee_address); + + report_helper(stakee_address, @0x2, false, scenario); + assert!(get_reporters_of(@0x2, scenario) == vector[@0x1], 0); + + // @0x1 revokes stakee's permission by creating a new + // operation cap object. + rotate_operation_cap(@0x1, scenario); + + // stakee no longer has permission to report validators, here it aborts. + report_helper(stakee_address, @0x2, true, scenario); + + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = ::iota_system::validator_set::EInvalidCap)] + fun test_set_reference_gas_price_by_stakee_revoked() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + set_up_iota_system_state(vector[@0x1, @0x2]); + + // @0x1 transfers the cap object to stakee. + let stakee_address = @0xbeef; + scenario.next_tx(@0x1); + let cap = scenario.take_from_sender(); + transfer::public_transfer(cap, stakee_address); + + // With the cap object in hand, stakee could report validators on behalf of @0x1. + set_gas_price_helper(stakee_address, 888, scenario); + + scenario.next_tx(stakee_address); + let mut system_state = scenario.take_shared(); + let validator = system_state.active_validator_by_address(@0x1); + assert!(validator.next_epoch_gas_price() == 888, 0); + test_scenario::return_shared(system_state); + + // @0x1 revokes stakee's permssion by creating a new + // operation cap object. + rotate_operation_cap(@0x1, scenario); + + // stakee no longer has permission to report validators, here it aborts. + set_gas_price_helper(stakee_address, 888, scenario); + + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = validator::EGasPriceHigherThanThreshold)] + fun test_set_gas_price_failure() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + set_up_iota_system_state(vector[@0x1, @0x2]); + + // Fails here since the gas price is too high. + set_gas_price_helper(@0x1, 100_001, scenario); + + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = validator::ECommissionRateTooHigh)] + fun test_set_commission_rate_failure() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + set_up_iota_system_state(vector[@0x1, @0x2]); + + scenario.next_tx(@0x2); + let mut system_state = scenario.take_shared(); + + // Fails here since the commission rate is too high. + system_state.request_set_commission_rate(2001, scenario.ctx()); + test_scenario::return_shared(system_state); + + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = iota_system_state_inner::ENotValidator)] + fun test_report_non_validator_failure() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + + set_up_iota_system_state(vector[@0x1, @0x2, @0x3]); + report_helper(@0x1, @0x42, false, scenario); + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = iota_system_state_inner::ECannotReportOneself)] + fun test_report_self_failure() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + + set_up_iota_system_state(vector[@0x1, @0x2, @0x3]); + report_helper(@0x1, @0x1, false, scenario); + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = iota_system_state_inner::EReportRecordNotFound)] + fun test_undo_report_failure() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + + set_up_iota_system_state(vector[@0x1, @0x2, @0x3]); + report_helper(@0x2, @0x1, true, scenario); + scenario_val.end(); + } + + #[test] + fun test_staking_pool_mappings() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + + set_up_iota_system_state(vector[@0x1, @0x2, @0x3, @0x4]); + scenario.next_tx(@0x1); + let mut system_state = scenario.take_shared(); + let pool_id_1 = system_state.validator_staking_pool_id(@0x1); + let pool_id_2 = system_state.validator_staking_pool_id(@0x2); + let pool_id_3 = system_state.validator_staking_pool_id(@0x3); + let pool_id_4 = system_state.validator_staking_pool_id(@0x4); + let mut pool_mappings = system_state.validator_staking_pool_mappings(); + assert_eq(pool_mappings.length(), 4); + assert_eq(pool_mappings[pool_id_1], @0x1); + assert_eq(pool_mappings[pool_id_2], @0x2); + assert_eq(pool_mappings[pool_id_3], @0x3); + assert_eq(pool_mappings[pool_id_4], @0x4); + test_scenario::return_shared(system_state); + + let new_validator_addr = @0xaf76afe6f866d8426d2be85d6ef0b11f871a251d043b2f11e15563bf418f5a5a; + scenario.next_tx(new_validator_addr); + // Seed [0; 32] + let pubkey = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; + // Generated with [fn test_proof_of_possession] + let pop = x"b01cc86f421beca7ab4cfca87c0799c4d038c199dd399fbec1924d4d4367866dba9e84d514710b91feb65316e4ceef43"; + + // Add a validator + add_validator_full_flow(new_validator_addr, b"name2", b"/ip4/127.0.0.1/udp/82", 100, pubkey, pop, scenario); + advance_epoch(scenario); + + scenario.next_tx(@0x1); + let mut system_state = scenario.take_shared(); + let pool_id_5 = system_state.validator_staking_pool_id(new_validator_addr); + pool_mappings = system_state.validator_staking_pool_mappings(); + // Check that the previous mappings didn't change as well. + assert_eq(pool_mappings.length(), 5); + assert_eq(pool_mappings[pool_id_1], @0x1); + assert_eq(pool_mappings[pool_id_2], @0x2); + assert_eq(pool_mappings[pool_id_3], @0x3); + assert_eq(pool_mappings[pool_id_4], @0x4); + assert_eq(pool_mappings[pool_id_5], new_validator_addr); + test_scenario::return_shared(system_state); + + // Remove one of the original validators. + remove_validator(@0x1, scenario); + advance_epoch(scenario); + + scenario.next_tx(@0x1); + let mut system_state = scenario.take_shared(); + pool_mappings = system_state.validator_staking_pool_mappings(); + // Check that the previous mappings didn't change as well. + assert_eq(pool_mappings.length(), 4); + assert_eq(pool_mappings.contains(pool_id_1), false); + assert_eq(pool_mappings[pool_id_2], @0x2); + assert_eq(pool_mappings[pool_id_3], @0x3); + assert_eq(pool_mappings[pool_id_4], @0x4); + assert_eq(pool_mappings[pool_id_5], new_validator_addr); + test_scenario::return_shared(system_state); + + scenario_val.end(); + } + + fun report_helper(sender: address, reported: address, is_undo: bool, scenario: &mut Scenario) { + scenario.next_tx(sender); + + let mut system_state = scenario.take_shared(); + let cap = scenario.take_from_sender(); + if (is_undo) { + system_state.undo_report_validator(&cap, reported); + } else { + system_state.report_validator(&cap, reported); + }; + scenario.return_to_sender(cap); + test_scenario::return_shared(system_state); + } + + fun set_gas_price_helper( + sender: address, + new_gas_price: u64, + scenario: &mut Scenario, + ) { + scenario.next_tx(sender); + let cap = scenario.take_from_sender(); + let mut system_state = scenario.take_shared(); + system_state.request_set_gas_price(&cap, new_gas_price); + scenario.return_to_sender(cap); + test_scenario::return_shared(system_state); + } + + + fun rotate_operation_cap(sender: address, scenario: &mut Scenario) { + scenario.next_tx(sender); + let mut system_state = scenario.take_shared(); + let ctx = scenario.ctx(); + system_state.rotate_operation_cap(ctx); + test_scenario::return_shared(system_state); + } + + fun get_reporters_of(addr: address, scenario: &mut Scenario): vector
    { + scenario.next_tx(addr); + let mut system_state = scenario.take_shared(); + let res = system_state.get_reporters_of(addr).into_keys(); + test_scenario::return_shared(system_state); + res + } + + fun update_candidate( + scenario: &mut Scenario, + system_state: &mut IotaSystemState, + name: vector, + protocol_pub_key: vector, + pop: vector, + network_address: vector, + p2p_address: vector, + commission_rate: u64, + gas_price: u64, + ) { + let ctx = scenario.ctx(); + system_state.update_validator_name(name, ctx); + system_state.update_validator_description(b"new_desc", ctx); + system_state.update_validator_image_url(b"new_image_url", ctx); + system_state.update_validator_project_url(b"new_project_url", ctx); + system_state.update_candidate_validator_network_address(network_address, ctx); + system_state.update_candidate_validator_p2p_address(p2p_address, ctx); + system_state.update_candidate_validator_primary_address(b"/ip4/127.0.0.1/udp/80", ctx); + system_state.update_candidate_validator_worker_address(b"/ip4/127.0.0.1/udp/80", ctx); + system_state.update_candidate_validator_protocol_pubkey( + protocol_pub_key, + pop, + ctx + ); + system_state.update_candidate_validator_worker_pubkey(vector[68, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], ctx); + system_state.update_candidate_validator_network_pubkey(vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], ctx); + + system_state.set_candidate_validator_commission_rate(commission_rate, ctx); + let cap = scenario.take_from_sender(); + system_state.set_candidate_validator_gas_price(&cap, gas_price); + scenario.return_to_sender(cap); + } + + + fun verify_candidate( + validator: &Validator, + name: vector, + protocol_pub_key: vector, + pop: vector, + network_address: vector, + p2p_address: vector, + commission_rate: u64, + gas_price: u64, + + ) { + verify_current_epoch_metadata( + validator, + name, + protocol_pub_key, + pop, + b"/ip4/127.0.0.1/udp/80", + b"/ip4/127.0.0.1/udp/80", + network_address, + p2p_address, + vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], + vector[68, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], + ); + assert!(validator.commission_rate() == commission_rate, 0); + assert!(validator.gas_price() == gas_price, 0); + + } + + // Note: `pop` MUST be a valid signature using iota_address and protocol_pubkey_bytes. + // To produce a valid PoP, run [fn test_proof_of_possession]. + fun update_metadata( + scenario: &mut Scenario, + system_state: &mut IotaSystemState, + name: vector, + protocol_pub_key: vector, + pop: vector, + network_address: vector, + p2p_address: vector, + network_pubkey: vector, + worker_pubkey: vector, + ) { + let ctx = scenario.ctx(); + system_state.update_validator_name(name, ctx); + system_state.update_validator_description(b"new_desc", ctx); + system_state.update_validator_image_url(b"new_image_url", ctx); + system_state.update_validator_project_url(b"new_project_url", ctx); + system_state.update_validator_next_epoch_network_address(network_address, ctx); + system_state.update_validator_next_epoch_p2p_address(p2p_address, ctx); + system_state.update_validator_next_epoch_primary_address(b"/ip4/168.168.168.168/udp/80", ctx); + system_state.update_validator_next_epoch_worker_address(b"/ip4/168.168.168.168/udp/80", ctx); + system_state.update_validator_next_epoch_protocol_pubkey( + protocol_pub_key, + pop, + ctx + ); + system_state.update_validator_next_epoch_network_pubkey(network_pubkey, ctx); + system_state.update_validator_next_epoch_worker_pubkey(worker_pubkey, ctx); + } + + fun verify_metadata( + validator: &Validator, + name: vector, + protocol_pub_key: vector, + pop: vector, + network_address: vector, + p2p_address: vector, + network_pubkey: vector, + worker_pubkey: vector, + new_protocol_pub_key: vector, + new_pop: vector, + new_network_address: vector, + new_p2p_address: vector, + new_network_pubkey: vector, + new_worker_pubkey: vector, + ) { + // Current epoch + verify_current_epoch_metadata( + validator, + name, + protocol_pub_key, + pop, + b"/ip4/127.0.0.1/udp/80", + b"/ip4/127.0.0.1/udp/80", + network_address, + p2p_address, + network_pubkey, + worker_pubkey, + ); + + // Next epoch + assert!(validator.next_epoch_network_address() == &option::some(new_network_address.to_string()), 0); + assert!(validator.next_epoch_p2p_address() == &option::some(new_p2p_address.to_string()), 0); + assert!(validator.next_epoch_primary_address() == &option::some(b"/ip4/168.168.168.168/udp/80".to_string()), 0); + assert!(validator.next_epoch_worker_address() == &option::some(b"/ip4/168.168.168.168/udp/80".to_string()), 0); + assert!( + validator.next_epoch_protocol_pubkey_bytes() == &option::some(new_protocol_pub_key), + 0 + ); + assert!( + validator.next_epoch_proof_of_possession() == &option::some(new_pop), + 0 + ); + assert!( + validator.next_epoch_worker_pubkey_bytes() == &option::some(new_worker_pubkey), + 0 + ); + assert!( + validator.next_epoch_network_pubkey_bytes() == &option::some(new_network_pubkey), + 0 + ); + } + + fun verify_current_epoch_metadata( + validator: &Validator, + name: vector, + protocol_pub_key: vector, + pop: vector, + primary_address: vector, + worker_address: vector, + network_address: vector, + p2p_address: vector, + network_pubkey_bytes: vector, + worker_pubkey_bytes: vector, + ) { + // Current epoch + assert!(validator.name() == &name.to_string(), 0); + assert!(validator.description() == &b"new_desc".to_string(), 0); + assert!(validator.image_url() == &url::new_unsafe_from_bytes(b"new_image_url"), 0); + assert!(validator.project_url() == &url::new_unsafe_from_bytes(b"new_project_url"), 0); + assert!(validator.network_address() == &network_address.to_string(), 0); + assert!(validator.p2p_address() == &p2p_address.to_string(), 0); + assert!(validator.primary_address() == &primary_address.to_string(), 0); + assert!(validator.worker_address() == &worker_address.to_string(), 0); + assert!(validator.protocol_pubkey_bytes() == &protocol_pub_key, 0); + assert!(validator.proof_of_possession() == &pop, 0); + assert!(validator.worker_pubkey_bytes() == &worker_pubkey_bytes, 0); + assert!(validator.network_pubkey_bytes() == &network_pubkey_bytes, 0); + } + + + fun verify_metadata_after_advancing_epoch( + validator: &Validator, + name: vector, + protocol_pub_key: vector, + pop: vector, + network_address: vector, + p2p_address: vector, + network_pubkey: vector, + worker_pubkey: vector, + ) { + // Current epoch + verify_current_epoch_metadata( + validator, + name, + protocol_pub_key, + pop, + b"/ip4/168.168.168.168/udp/80", + b"/ip4/168.168.168.168/udp/80", + network_address, + p2p_address, + network_pubkey, + worker_pubkey, + ); + + // Next epoch + assert!(validator.next_epoch_network_address().is_none(), 0); + assert!(validator.next_epoch_p2p_address().is_none(), 0); + assert!(validator.next_epoch_primary_address().is_none(), 0); + assert!(validator.next_epoch_worker_address().is_none(), 0); + assert!(validator.next_epoch_protocol_pubkey_bytes().is_none(), 0); + assert!(validator.next_epoch_proof_of_possession().is_none(), 0); + assert!(validator.next_epoch_worker_pubkey_bytes().is_none(), 0); + assert!(validator.next_epoch_network_pubkey_bytes().is_none(), 0); + } + + #[test] + fun test_active_validator_update_metadata() { + let validator_addr = @0xaf76afe6f866d8426d2be85d6ef0b11f871a251d043b2f11e15563bf418f5a5a; + // pubkey generated with protocol key on seed [0; 32] + let pubkey = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; + // pop generated using the protocol key and address with [fn test_proof_of_possession] + let pop = x"b01cc86f421beca7ab4cfca87c0799c4d038c199dd399fbec1924d4d4367866dba9e84d514710b91feb65316e4ceef43"; + + // pubkey generated with protocol key on seed [1; 32] + let pubkey1 = x"96d19c53f1bee2158c3fcfb5bb2f06d3a8237667529d2d8f0fbb22fe5c3b3e64748420b4103674490476d98530d063271222d2a59b0f7932909cc455a30f00c69380e6885375e94243f7468e9563aad29330aca7ab431927540e9508888f0e1c"; + let pop1 = x"a8a0bcaf04e13565914eb22fa9f27a76f297db04446860ee2b923d10224cedb130b30783fb60b12556e7fc50e5b57a86"; + + let new_validator_addr = @0x8e3446145b0c7768839d71840df389ffa3b9742d0baaff326a3d453b595f87d7; + // pubkey generated with protocol key on seed [2; 32] + let new_pubkey = x"adf2e2350fe9a58f3fa50777499f20331c4550ab70f6a4fb25a58c61b50b5366107b5c06332e71bb47aa99ce2d5c07fe0dab04b8af71589f0f292c50382eba6ad4c90acb010ab9db7412988b2aba1018aaf840b1390a8b2bee3fde35b4ab7fdf"; + let new_pop = x"926fdb08b2b46d802e3642044f215dcb049e6c17a376a272ffd7dba32739bb995370966698ab235ee172fbd974985cfe"; + + // pubkey generated with protocol key on seed [3; 32] + let new_pubkey1 = x"91b8de031e0b60861c655c8168596d98b065d57f26f287f8c810590b06a636eff13c4055983e95b2f60a4d6ba5484fa4176923d1f7807cc0b222ddf6179c1db099dba0433f098aae82542b3fd27b411d64a0a35aad01b2c07ac67f7d0a1d2c11"; + let new_pop1 = x"b61913eb4dc7ea1d92f174e1a3c6cad3f49ae8de40b13b69046ce072d8d778bfe87e734349c7394fd1543fff0cb6e2d0"; + + let mut scenario_val = test_scenario::begin(validator_addr); + let scenario = &mut scenario_val; + + // Set up IotaSystemState with an active validator + let mut validators = vector[]; + let ctx = scenario.ctx(); + let validator = validator::new_for_testing( + validator_addr, + pubkey, + vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], + vector[68, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], + pop, + b"ValidatorName", + b"description", + b"image_url", + b"project_url", + b"/ip4/127.0.0.1/tcp/80", + b"/ip4/127.0.0.1/udp/80", + b"/ip4/127.0.0.1/udp/80", + b"/ip4/127.0.0.1/udp/80", + option::some(balance::create_for_testing(100_000_000_000)), + 1, + 0, + true, + ctx + ); + validators.push_back(validator); + create_iota_system_state_for_testing(validators, 1000, 0, ctx); + + scenario.next_tx(validator_addr); + + let mut system_state = scenario.take_shared(); + + // Test active validator metadata changes + scenario.next_tx(validator_addr); + { + update_metadata( + scenario, + &mut system_state, + b"validator_new_name", + pubkey1, + pop1, + b"/ip4/42.42.42.42/tcp/80", + b"/ip4/43.43.43.43/udp/80", + vector[148, 117, 212, 171, 44, 104, 167, 11, 177, 100, 4, 55, 17, 235, 117, 45, 117, 84, 159, 49, 14, 159, 239, 246, 237, 21, 83, 166, 112, 53, 62, 199], + vector[215, 64, 85, 185, 231, 116, 69, 151, 97, 79, 4, 183, 20, 70, 84, 51, 211, 162, 115, 221, 73, 241, 240, 171, 192, 25, 232, 106, 175, 162, 176, 43], + ); + }; + + scenario.next_tx(validator_addr); + let validator = system_state.active_validator_by_address(validator_addr); + verify_metadata( + validator, + b"validator_new_name", + pubkey, + pop, + b"/ip4/127.0.0.1/tcp/80", + b"/ip4/127.0.0.1/udp/80", + vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], + vector[68, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], + pubkey1, + pop1, + b"/ip4/42.42.42.42/tcp/80", + b"/ip4/43.43.43.43/udp/80", + vector[148, 117, 212, 171, 44, 104, 167, 11, 177, 100, 4, 55, 17, 235, 117, 45, 117, 84, 159, 49, 14, 159, 239, 246, 237, 21, 83, 166, 112, 53, 62, 199], + vector[215, 64, 85, 185, 231, 116, 69, 151, 97, 79, 4, 183, 20, 70, 84, 51, 211, 162, 115, 221, 73, 241, 240, 171, 192, 25, 232, 106, 175, 162, 176, 43], + ); + + test_scenario::return_shared(system_state); + scenario_val.end(); + + // Test pending validator metadata changes + let mut scenario_val = test_scenario::begin(new_validator_addr); + let scenario = &mut scenario_val; + let mut system_state = scenario.take_shared(); + scenario.next_tx(new_validator_addr); + { + let ctx = scenario.ctx(); + system_state.request_add_validator_candidate( + new_pubkey, + vector[33, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], + vector[69, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], + new_pop, + b"ValidatorName2", + b"description2", + b"image_url2", + b"project_url2", + b"/ip4/127.0.0.2/tcp/80", + b"/ip4/127.0.0.2/udp/80", + b"/ip4/127.0.0.1/udp/80", + b"/ip4/127.0.0.1/udp/80", + 1, + 0, + ctx, + ); + system_state.request_add_validator_for_testing(0, ctx); + }; + + scenario.next_tx(new_validator_addr); + { + update_metadata( + scenario, + &mut system_state, + b"new_validator_new_name", + new_pubkey1, + new_pop1, + b"/ip4/66.66.66.66/tcp/80", + b"/ip4/77.77.77.77/udp/80", + vector[215, 65, 85, 185, 231, 116, 69, 151, 97, 79, 4, 183, 20, 70, 84, 51, 211, 162, 115, 221, 73, 241, 240, 171, 192, 25, 232, 106, 175, 162, 176, 43], + vector[149, 117, 212, 171, 44, 104, 167, 11, 177, 100, 4, 55, 17, 235, 117, 45, 117, 84, 159, 49, 14, 159, 239, 246, 237, 21, 83, 166, 112, 53, 62, 199], + ); + }; + + scenario.next_tx(new_validator_addr); + let validator = system_state.pending_validator_by_address(new_validator_addr); + verify_metadata( + validator, + b"new_validator_new_name", + new_pubkey, + new_pop, + b"/ip4/127.0.0.2/tcp/80", + b"/ip4/127.0.0.2/udp/80", + vector[33, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], + vector[69, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], + new_pubkey1, + new_pop1, + b"/ip4/66.66.66.66/tcp/80", + b"/ip4/77.77.77.77/udp/80", + vector[215, 65, 85, 185, 231, 116, 69, 151, 97, 79, 4, 183, 20, 70, 84, 51, 211, 162, 115, 221, 73, 241, 240, 171, 192, 25, 232, 106, 175, 162, 176, 43], + vector[149, 117, 212, 171, 44, 104, 167, 11, 177, 100, 4, 55, 17, 235, 117, 45, 117, 84, 159, 49, 14, 159, 239, 246, 237, 21, 83, 166, 112, 53, 62, 199], + ); + + test_scenario::return_shared(system_state); + + // Advance epoch to effectuate the metadata changes. + scenario.next_tx(new_validator_addr); + advance_epoch(scenario); + + // Now both validators are active, verify their metadata. + scenario.next_tx(new_validator_addr); + let mut system_state = scenario.take_shared(); + let validator = system_state.active_validator_by_address(validator_addr); + verify_metadata_after_advancing_epoch( + validator, + b"validator_new_name", + pubkey1, + pop1, + b"/ip4/42.42.42.42/tcp/80", + b"/ip4/43.43.43.43/udp/80", + vector[148, 117, 212, 171, 44, 104, 167, 11, 177, 100, 4, 55, 17, 235, 117, 45, 117, 84, 159, 49, 14, 159, 239, 246, 237, 21, 83, 166, 112, 53, 62, 199], + vector[215, 64, 85, 185, 231, 116, 69, 151, 97, 79, 4, 183, 20, 70, 84, 51, 211, 162, 115, 221, 73, 241, 240, 171, 192, 25, 232, 106, 175, 162, 176, 43], + ); + + let validator = system_state.active_validator_by_address(new_validator_addr); + verify_metadata_after_advancing_epoch( + validator, + b"new_validator_new_name", + new_pubkey1, + new_pop1, + b"/ip4/66.66.66.66/tcp/80", + b"/ip4/77.77.77.77/udp/80", + vector[215, 65, 85, 185, 231, 116, 69, 151, 97, 79, 4, 183, 20, 70, 84, 51, 211, 162, 115, 221, 73, 241, 240, 171, 192, 25, 232, 106, 175, 162, 176, 43], + vector[149, 117, 212, 171, 44, 104, 167, 11, 177, 100, 4, 55, 17, 235, 117, 45, 117, 84, 159, 49, 14, 159, 239, 246, 237, 21, 83, 166, 112, 53, 62, 199], + ); + + test_scenario::return_shared(system_state); + scenario_val.end(); + } + + + #[test] + fun test_validator_candidate_update() { + let validator_addr = @0xaf76afe6f866d8426d2be85d6ef0b11f871a251d043b2f11e15563bf418f5a5a; + // pubkey generated with protocol key on seed [0; 32] + let pubkey = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; + // pop generated using the protocol key and address with [fn test_proof_of_possession] + let pop = x"b01cc86f421beca7ab4cfca87c0799c4d038c199dd399fbec1924d4d4367866dba9e84d514710b91feb65316e4ceef43"; + + // pubkey generated with protocol key on seed [1; 32] + let pubkey1 = x"96d19c53f1bee2158c3fcfb5bb2f06d3a8237667529d2d8f0fbb22fe5c3b3e64748420b4103674490476d98530d063271222d2a59b0f7932909cc455a30f00c69380e6885375e94243f7468e9563aad29330aca7ab431927540e9508888f0e1c"; + let pop1 = x"a8a0bcaf04e13565914eb22fa9f27a76f297db04446860ee2b923d10224cedb130b30783fb60b12556e7fc50e5b57a86"; + + let mut scenario_val = test_scenario::begin(validator_addr); + let scenario = &mut scenario_val; + + set_up_iota_system_state(vector[@0x1, @0x2, @0x3]); + scenario.next_tx(validator_addr); + let mut system_state = scenario.take_shared(); + scenario.next_tx(validator_addr); + { + system_state.request_add_validator_candidate_for_testing( + pubkey, + vector[215, 64, 85, 185, 231, 116, 69, 151, 97, 79, 4, 183, 20, 70, 84, 51, 211, 162, 115, 221, 73, 241, 240, 171, 192, 25, 232, 106, 175, 162, 176, 43], + vector[148, 117, 212, 171, 44, 104, 167, 11, 177, 100, 4, 55, 17, 235, 117, 45, 117, 84, 159, 49, 14, 159, 239, 246, 237, 21, 83, 166, 112, 53, 62, 199], + pop, + b"ValidatorName2", + b"description2", + b"image_url2", + b"project_url2", + b"/ip4/127.0.0.2/tcp/80", + b"/ip4/127.0.0.2/udp/80", + b"/ip4/168.168.168.168/udp/80", + b"/ip4/168.168.168.168/udp/80", + 1, + 0, + scenario.ctx(), + ); + }; + + scenario.next_tx(validator_addr); + update_candidate( + scenario, + &mut system_state, + b"validator_new_name", + pubkey1, + pop1, + b"/ip4/42.42.42.42/tcp/80", + b"/ip4/43.43.43.43/udp/80", + 42, + 7, + ); + + scenario.next_tx(validator_addr); + + let validator = system_state.candidate_validator_by_address(validator_addr); + verify_candidate( + validator, + b"validator_new_name", + pubkey1, + pop1, + b"/ip4/42.42.42.42/tcp/80", + b"/ip4/43.43.43.43/udp/80", + 42, + 7, + ); + + + + test_scenario::return_shared(system_state); + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = validator::EMetadataInvalidWorkerPubkey)] + fun test_add_validator_candidate_failure_invalid_metadata() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + + // Generated using [fn test_proof_of_possession] + let new_validator_addr = @0x8e3446145b0c7768839d71840df389ffa3b9742d0baaff326a3d453b595f87d7; + let pubkey = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; + let pop = x"83809369ce6572be211512d85621a075ee6a8da57fbb2d867d05e6a395e71f10e4e957796944d68a051381eb91720fba"; + + set_up_iota_system_state(vector[@0x1, @0x2, @0x3]); + scenario.next_tx(new_validator_addr); + let mut system_state = scenario.take_shared(); + system_state.request_add_validator_candidate( + pubkey, + vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], + vector[42], // invalid + pop, + b"ValidatorName2", + b"description2", + b"image_url2", + b"project_url2", + b"/ip4/127.0.0.2/tcp/80", + b"/ip4/127.0.0.2/udp/80", + b"/ip4/127.0.0.1/udp/80", + b"/ip4/127.0.0.1/udp/80", + 1, + 0, + scenario.ctx(), + ); + test_scenario::return_shared(system_state); + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = validator_set::EAlreadyValidatorCandidate)] + fun test_add_validator_candidate_failure_double_register() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + let new_validator_addr = @0x8e3446145b0c7768839d71840df389ffa3b9742d0baaff326a3d453b595f87d7; + let pubkey = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; + let pop = x"83809369ce6572be211512d85621a075ee6a8da57fbb2d867d05e6a395e71f10e4e957796944d68a051381eb91720fba"; + + set_up_iota_system_state(vector[@0x1, @0x2, @0x3]); + scenario.next_tx(new_validator_addr); + let mut system_state = scenario.take_shared(); + system_state.request_add_validator_candidate( + pubkey, + vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], + vector[68, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], + pop, + b"ValidatorName2", + b"description2", + b"image_url2", + b"project_url2", + b"/ip4/127.0.0.2/tcp/80", + b"/ip4/127.0.0.2/udp/80", + b"/ip4/127.0.0.1/udp/80", + b"/ip4/127.0.0.1/udp/80", + 1, + 0, + scenario.ctx(), + ); + + // Add the same address as candidate again, should fail this time. + system_state.request_add_validator_candidate( + pubkey, + vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], + vector[68, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], + pop, + b"ValidatorName2", + b"description2", + b"image_url2", + b"project_url2", + b"/ip4/127.0.0.2/tcp/80", + b"/ip4/127.0.0.2/udp/80", + b"/ip4/127.0.0.1/udp/80", + b"/ip4/127.0.0.1/udp/80", + 1, + 0, + scenario.ctx(), + ); + test_scenario::return_shared(system_state); + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = validator_set::EDuplicateValidator)] + fun test_add_validator_candidate_failure_duplicate_with_active() { + let validator_addr = @0xaf76afe6f866d8426d2be85d6ef0b11f871a251d043b2f11e15563bf418f5a5a; + // Seed [0; 32] + let pubkey = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; + let pop = x"b01cc86f421beca7ab4cfca87c0799c4d038c199dd399fbec1924d4d4367866dba9e84d514710b91feb65316e4ceef43"; + + let new_addr = @0x1a4623343cd42be47d67314fce0ad042f3c82685544bc91d8c11d24e74ba7357; + // Seed [1; 32] + let new_pubkey = x"96d19c53f1bee2158c3fcfb5bb2f06d3a8237667529d2d8f0fbb22fe5c3b3e64748420b4103674490476d98530d063271222d2a59b0f7932909cc455a30f00c69380e6885375e94243f7468e9563aad29330aca7ab431927540e9508888f0e1c"; + let new_pop = x"932336c35a8c393019c63eb0f7d385dd4e0bd131f04b54cf45aa9544f14dca4dab53bd70ffcb8e0b34656e4388309720"; + + let mut scenario_val = test_scenario::begin(validator_addr); + let scenario = &mut scenario_val; + + // Set up IotaSystemState with an active validator + let ctx = scenario.ctx(); + let validator = validator::new_for_testing( + validator_addr, + pubkey, + vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], + vector[68, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], + pop, + b"ValidatorName", + b"description", + b"image_url", + b"project_url", + b"/ip4/127.0.0.1/tcp/80", + b"/ip4/127.0.0.1/udp/80", + b"/ip4/127.0.0.1/udp/80", + b"/ip4/127.0.0.1/udp/80", + option::some(balance::create_for_testing(100_000_000_000)), + 1, + 0, + true, + ctx + ); + create_iota_system_state_for_testing(vector[validator], 1000, 0, ctx); + + scenario.next_tx(new_addr); + + let mut system_state = scenario.take_shared(); + + // Add a candidate with the same name. Fails due to duplicating with an already active validator. + system_state.request_add_validator_candidate( + new_pubkey, + vector[115, 220, 238, 151, 134, 159, 173, 41, 80, 2, 66, 196, 61, 17, 191, 76, 103, 39, 246, 127, 171, 85, 19, 235, 210, 106, 97, 97, 116, 48, 244, 191], + vector[149, 128, 161, 13, 11, 183, 96, 45, 89, 20, 188, 205, 26, 127, 147, 254, 184, 229, 184, 102, 64, 170, 104, 29, 191, 171, 91, 99, 58, 178, 41, 156], + new_pop, + // same name + b"ValidatorName", + b"description2", + b"image_url2", + b"project_url2", + b"/ip4/127.0.0.2/tcp/80", + b"/ip4/127.0.0.2/udp/80", + b"/ip4/127.0.0.1/udp/80", + b"/ip4/127.0.0.1/udp/80", + 1, + 0, + scenario.ctx(), + ); + test_scenario::return_shared(system_state); + scenario_val.end(); + } + + #[test] + fun test_skip_stake_subsidy() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + // Epoch duration is set to be 42 here. + set_up_iota_system_state(vector[@0x1, @0x2]); + + // If the epoch length is less than 42 then the stake subsidy distribution counter should not be incremented. Otherwise it should. + advance_epoch_and_check_distribution_counter(scenario, 42, true); + advance_epoch_and_check_distribution_counter(scenario, 32, false); + advance_epoch_and_check_distribution_counter(scenario, 52, true); + scenario_val.end(); + } + + fun advance_epoch_and_check_distribution_counter(scenario: &mut Scenario, epoch_length: u64, should_increment_counter: bool) { + scenario.next_tx(@0x0); + let new_epoch = scenario.ctx().epoch() + 1; + let mut system_state = scenario.take_shared(); + let prev_epoch_time = system_state.epoch_start_timestamp_ms(); + let prev_counter = system_state.get_stake_subsidy_distribution_counter(); + + let rebate = system_state.advance_epoch_for_testing( + new_epoch, 1, 0, 0, 0, 0, 0, 0, prev_epoch_time + epoch_length, scenario.ctx() + ); + destroy(rebate); + assert_eq(system_state.get_stake_subsidy_distribution_counter(), prev_counter + (if (should_increment_counter) 1 else 0)); + test_scenario::return_shared(system_state); + scenario.next_epoch(@0x0); + } +} diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move new file mode 100644 index 00000000000..11c6fa0d8c1 --- /dev/null +++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move @@ -0,0 +1,495 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module iota_system::rewards_distribution_tests { + use iota::test_scenario::{Self, Scenario}; + use iota_system::iota_system::IotaSystemState; + use iota_system::validator_cap::UnverifiedValidatorOperationCap; + use iota_system::governance_test_utils::{ + advance_epoch, + advance_epoch_with_reward_amounts, + advance_epoch_with_reward_amounts_and_slashing_rates, + assert_validator_total_stake_amounts, + assert_validator_non_self_stake_amounts, + assert_validator_self_stake_amounts, + create_validator_for_testing, + create_iota_system_state_for_testing, + stake_with, + total_iota_balance, unstake + }; + use iota::test_utils::assert_eq; + use iota::address; + + const VALIDATOR_ADDR_1: address = @0x1; + const VALIDATOR_ADDR_2: address = @0x2; + const VALIDATOR_ADDR_3: address = @0x3; + const VALIDATOR_ADDR_4: address = @0x4; + + const STAKER_ADDR_1: address = @0x42; + const STAKER_ADDR_2: address = @0x43; + const STAKER_ADDR_3: address = @0x44; + const STAKER_ADDR_4: address = @0x45; + + const MICROS_PER_IOTA: u64 = 1_000_000_000; + + #[test] + fun test_validator_rewards() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + // need to advance epoch so validator's staking starts counting + advance_epoch(scenario); + + advance_epoch_with_reward_amounts(0, 100, scenario); + assert_validator_total_stake_amounts( + validator_addrs(), + vector[125 * MICROS_PER_IOTA, 225 * MICROS_PER_IOTA, 325 * MICROS_PER_IOTA, 425 * MICROS_PER_IOTA], + scenario + ); + + stake_with(VALIDATOR_ADDR_2, VALIDATOR_ADDR_2, 720, scenario); + + advance_epoch(scenario); + advance_epoch_with_reward_amounts(0, 100, scenario); + // Even though validator 2 has a lot more stake now, it should not get more rewards because + // the voting power is capped at 10%. + assert_validator_total_stake_amounts( + validator_addrs(), + vector[150 * MICROS_PER_IOTA, 970 * MICROS_PER_IOTA, 350 * MICROS_PER_IOTA, 450 * MICROS_PER_IOTA], + scenario + ); + scenario_val.end(); + } + + #[test] + fun test_stake_subsidy() { + set_up_iota_system_state_with_big_amounts(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + // need to advance epoch so validator's staking starts counting + advance_epoch(scenario); + + advance_epoch_with_reward_amounts(0, 100, scenario); + assert_validator_total_stake_amounts(validator_addrs(), vector[100_000_025 * MICROS_PER_IOTA, 200_000_025 * MICROS_PER_IOTA, 300_000_025 * MICROS_PER_IOTA, 400_000_025 * MICROS_PER_IOTA], scenario); + scenario_val.end(); + } + + #[test] + fun test_stake_rewards() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 200, scenario); + stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_2, 100, scenario); + advance_epoch(scenario); + + assert_validator_total_stake_amounts(validator_addrs(), vector[300 * MICROS_PER_IOTA, 300 * MICROS_PER_IOTA, 300 * MICROS_PER_IOTA, 400 * MICROS_PER_IOTA], scenario); + assert_validator_self_stake_amounts(validator_addrs(), vector[100 * MICROS_PER_IOTA, 200 * MICROS_PER_IOTA, 300 * MICROS_PER_IOTA, 400 * MICROS_PER_IOTA], scenario); + + // Each pool gets 30 IOTA. + advance_epoch_with_reward_amounts(0, 120, scenario); + assert_validator_self_stake_amounts(validator_addrs(), vector[110 * MICROS_PER_IOTA, 220 * MICROS_PER_IOTA, 330 * MICROS_PER_IOTA, 430 * MICROS_PER_IOTA], scenario); + unstake(STAKER_ADDR_1, 0, scenario); + stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_1, 600, scenario); + // Each pool gets 30 IOTA. + advance_epoch_with_reward_amounts(0, 120, scenario); + // staker 1 receives only 20 IOTA of rewards, not 40 since we are using pre-epoch exchange rate. + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 220 * MICROS_PER_IOTA); + assert_validator_self_stake_amounts(validator_addrs(), vector[140 * MICROS_PER_IOTA, 240 * MICROS_PER_IOTA, 360 * MICROS_PER_IOTA, 460 * MICROS_PER_IOTA], scenario); + unstake(STAKER_ADDR_2, 0, scenario); + assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), 120 * MICROS_PER_IOTA); // 20 IOTA of rewards received + + advance_epoch_with_reward_amounts(0, 40, scenario); + + unstake(STAKER_ADDR_2, 0, scenario); // unstake 600 principal IOTA + // additional 600 IOTA of principal and 46 IOTA of rewards withdrawn to Coin + // For this stake, the staking exchange rate is 100 : 140 and the unstaking + // exchange rate is 528 : 750 -ish so the total iota withdraw will be: + // (600 * 100 / 140) * 750 / 528 = ~608. Together with the 120 IOTA we already have, + // that would be about 728 IOTA. + // TODO: Come up with better numbers and clean it up! + assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), 728108108107); + scenario_val.end(); + } + + #[test] + fun test_stake_tiny_rewards() { + set_up_iota_system_state_with_big_amounts(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + // stake a large amount + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 200000000, scenario); + + advance_epoch(scenario); + + advance_epoch_with_reward_amounts(0, 150000, scenario); + + // stake a small amount + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 10, scenario); + advance_epoch_with_reward_amounts(0, 130, scenario); + + // unstake the stakes + unstake(STAKER_ADDR_1, 1, scenario); + + // and advance epoch should succeed + advance_epoch_with_reward_amounts(0, 150, scenario); + scenario_val.end(); + } + + #[test] + fun test_validator_commission() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, scenario); + stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_2, 100, scenario); + advance_epoch(scenario); + // V1: 200, V2: 300, V3: 300, V4: 400 + + set_commission_rate_and_advance_epoch(VALIDATOR_ADDR_2, 2000, scenario); // 50% commission + advance_epoch_with_reward_amounts(0, 120, scenario); + // V1: 230, V2: 330, V3: 330, V4: 430 + // 2 IOTA, or 20 % of staker_2's rewards, goes to validator_2 + assert_validator_non_self_stake_amounts(validator_addrs(), vector[115 * MICROS_PER_IOTA, 108 * MICROS_PER_IOTA, 0, 0], scenario); + assert_validator_self_stake_amounts(validator_addrs(), vector[115 * MICROS_PER_IOTA, 222 * MICROS_PER_IOTA, 330 * MICROS_PER_IOTA, 430 * MICROS_PER_IOTA], scenario); + + set_commission_rate_and_advance_epoch(VALIDATOR_ADDR_1, 1000, scenario); // 10% commission + + advance_epoch_with_reward_amounts(0, 240, scenario); + assert_validator_total_stake_amounts(validator_addrs(), vector[290 * MICROS_PER_IOTA, 390 * MICROS_PER_IOTA, 390 * MICROS_PER_IOTA, 490 * MICROS_PER_IOTA], scenario); + + // Staker 1 rewards in the recent distribution is 0.9 x 30 = 27 IOTA + // Validator 1 rewards in the recent distribution is 60 - 27 = 33 IOTA + + // Staker 2 amounts for 0.8 * 60 * (108 / 330) + 108 = 123.709 IOTA + // Validator 2 amounts for 390 - 123.709 = 266.291 IOTA + assert_validator_non_self_stake_amounts(validator_addrs(), vector[142 * MICROS_PER_IOTA, 123709090909, 0, 0], scenario); + assert_validator_self_stake_amounts(validator_addrs(), vector[148 * MICROS_PER_IOTA, 266290909091, 390 * MICROS_PER_IOTA, 490 * MICROS_PER_IOTA], scenario); + + scenario_val.end(); + } + + #[test] + fun test_rewards_slashing() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + advance_epoch(scenario); + + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, scenario); + stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_2, 100, scenario); + + advance_epoch(scenario); + + // validator_2 is reported by 3 other validators, so 75% of total stake. + report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_2, scenario); + report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_2, scenario); + report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_2, scenario); + + // validator_1 is reported by only 1 other validator, which is 25% of total stake. + report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_1, scenario); + + // 3600 IOTA of total rewards, 50% threshold and 10% reward slashing. + // So validator_2 is the only one whose rewards should get slashed. + advance_epoch_with_reward_amounts_and_slashing_rates( + 0, 3600, 1000, scenario + ); + + // Without reward slashing, the validator's stakes should be [100+450, 200+600, 300+900, 400+900] + // after the last epoch advancement. + // Since 60 IOTA, or 10% of validator_2's rewards (600) are slashed, she only has 800 - 60 = 740 now. + // There are in total 90 IOTA of rewards slashed (60 from the validator, and 30 from her staker) + // so the unslashed validators each get their share of additional rewards, which is 30. + assert_validator_self_stake_amounts(validator_addrs(), vector[565 * MICROS_PER_IOTA, 740 * MICROS_PER_IOTA, 1230 * MICROS_PER_IOTA, 1330 * MICROS_PER_IOTA], scenario); + + // Unstake so we can check the stake rewards as well. + unstake(STAKER_ADDR_1, 0, scenario); + unstake(STAKER_ADDR_2, 0, scenario); + + // Same analysis as above. Delegator 1 has 3 additional IOTA, and 10% of staker 2's rewards are slashed. + assert!(total_iota_balance(STAKER_ADDR_1, scenario) == 565 * MICROS_PER_IOTA, 0); + assert!(total_iota_balance(STAKER_ADDR_2, scenario) == 370 * MICROS_PER_IOTA, 0); + scenario_val.end(); + } + + #[test] + fun test_entire_rewards_slashing() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + advance_epoch(scenario); + + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, scenario); + stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_2, 100, scenario); + + advance_epoch(scenario); + + // validator_2 is reported by 3 other validators, so 75% of total stake. + report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_2, scenario); + report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_2, scenario); + report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_2, scenario); + + + // 3600 IOTA of total rewards, 100% reward slashing. + // So validator_2 is the only one whose rewards should get slashed. + advance_epoch_with_reward_amounts_and_slashing_rates( + 0, 3600, 10_000, scenario + ); + + // Without reward slashing, the validator's stakes should be [100+450, 200+600, 300+900, 400+900] + // after the last epoch advancement. + // The entire rewards of validator 2's staking pool are slashed, which is 900 IOTA. + // so the unslashed validators each get their share of additional rewards, which is 300. + assert_validator_self_stake_amounts(validator_addrs(), vector[(550 + 150) * MICROS_PER_IOTA, 200 * MICROS_PER_IOTA, (1200 + 300) * MICROS_PER_IOTA, (1300 + 300) * MICROS_PER_IOTA], scenario); + + // Unstake so we can check the stake rewards as well. + unstake(STAKER_ADDR_1, 0, scenario); + unstake(STAKER_ADDR_2, 0, scenario); + + // Same analysis as above. Staker 1 has 150 additional IOTA, and since all of staker 2's rewards are slashed she only gets back her principal. + assert!(total_iota_balance(STAKER_ADDR_1, scenario) == (550 + 150) * MICROS_PER_IOTA, 0); + assert!(total_iota_balance(STAKER_ADDR_2, scenario) == 100 * MICROS_PER_IOTA, 0); + scenario_val.end(); + } + + #[test] + fun test_rewards_slashing_with_storage_fund() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + // Put 300 IOTA into the storage fund. + advance_epoch_with_reward_amounts(300, 0, scenario); + + // Add a few stakes. + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_3, 100, scenario); + stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_4, 100, scenario); + advance_epoch(scenario); + + // validator_4 is reported by 3 other validators, so 75% of total stake. + report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_4, scenario); + report_validator(VALIDATOR_ADDR_2, VALIDATOR_ADDR_4, scenario); + report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_4, scenario); + + // 1000 IOTA of storage rewards, 1500 IOTA of computation rewards, 50% slashing threshold + // and 20% slashing rate + advance_epoch_with_reward_amounts_and_slashing_rates( + 1000, 1500, 2000, scenario + ); + + // Each unslashed validator staking pool gets 300 IOTA of computation rewards + 75 IOTA of storage fund rewards + + // 20 IOTA (1/3) of validator 4's slashed computation reward and 5 IOTA (1/3) of validator 4's slashed + // storage fund reward, so in total it gets 400 IOTA of rewards. + // Validator 3 has a delegator with her so she gets 320 * 3/4 + 75 + 5 = 320 IOTA of rewards. + // Validator 4's should get 300 * 4/5 * (1 - 20%) = 192 in computation rewards and 75 * (1 - 20%) = 60 in storage rewards. + assert_validator_self_stake_amounts(validator_addrs(), vector[500 * MICROS_PER_IOTA, 600 * MICROS_PER_IOTA, 620 * MICROS_PER_IOTA, 652 * MICROS_PER_IOTA], scenario); + + // Unstake so we can check the stake rewards as well. + unstake(STAKER_ADDR_1, 0, scenario); + unstake(STAKER_ADDR_2, 0, scenario); + + // Staker 1 gets 320 * 1/4 = 80 IOTA of rewards. + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), (100 + 80) * MICROS_PER_IOTA); + // Staker 2 gets 300 * 1/5 * (1 - 20%) = 48 IOTA of rewards. + assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), (100 + 48) * MICROS_PER_IOTA); + + scenario_val.end(); + } + + #[test] + fun test_everyone_slashed() { + // This test is to make sure that if everyone is slashed, our protocol works as expected without aborting + // and all rewards go to the storage fund. + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_4, scenario); + report_validator(VALIDATOR_ADDR_2, VALIDATOR_ADDR_4, scenario); + report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_4, scenario); + report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_3, scenario); + report_validator(VALIDATOR_ADDR_2, VALIDATOR_ADDR_3, scenario); + report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_3, scenario); + report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_2, scenario); + report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_2, scenario); + report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_2, scenario); + report_validator(VALIDATOR_ADDR_2, VALIDATOR_ADDR_1, scenario); + report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_1, scenario); + report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_1, scenario); + + advance_epoch_with_reward_amounts_and_slashing_rates( + 1000, 3000, 10_000, scenario + ); + + // All validators should have 0 rewards added so their stake stays the same. + assert_validator_self_stake_amounts(validator_addrs(), vector[100 * MICROS_PER_IOTA, 200 * MICROS_PER_IOTA, 300 * MICROS_PER_IOTA, 400 * MICROS_PER_IOTA], scenario); + + scenario.next_tx(@0x0); + // Storage fund balance should increase by 4000 IOTA. + let mut system_state = scenario.take_shared(); + assert_eq(system_state.get_storage_fund_total_balance(), 4000 * MICROS_PER_IOTA); + + // The entire 1000 IOTA of storage rewards should go to the object rebate portion of the storage fund. + assert_eq(system_state.get_storage_fund_object_rebates(), 1000 * MICROS_PER_IOTA); + + test_scenario::return_shared(system_state); + scenario_val.end(); + } + + #[test] + fun test_mul_rewards_withdraws_at_same_epoch() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 220, scenario); + + advance_epoch_with_reward_amounts(0, 40, scenario); + + stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_1, 480, scenario); + + // Staker 1 gets 2/3 * 1/4 * 120 = 20 IOTA here. + advance_epoch_with_reward_amounts(0, 120, scenario); + + stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 130, scenario); + stake_with(STAKER_ADDR_3, VALIDATOR_ADDR_1, 390, scenario); + + // Staker 1 gets 20 IOTA here and staker 2 gets 40 IOTA here. + advance_epoch_with_reward_amounts(0, 280, scenario); + stake_with(STAKER_ADDR_3, VALIDATOR_ADDR_1, 280, scenario); + stake_with(STAKER_ADDR_4, VALIDATOR_ADDR_1, 1400, scenario); + + // Staker 1 gets 30 IOTA, staker 2 gets 40 IOTA and staker 3 gets 30 IOTA. + advance_epoch_with_reward_amounts(0, 440, scenario); + + scenario.next_tx(@0x0); + let mut system_state = scenario.take_shared(); + // Check that we have the right amount of IOTA in the staking pool. + assert_eq(system_state.validator_stake_amount(VALIDATOR_ADDR_1), 140 * 23 * MICROS_PER_IOTA); + test_scenario::return_shared(system_state); + + // Withdraw all stakes at once. + unstake(STAKER_ADDR_1, 0, scenario); + unstake(STAKER_ADDR_1, 0, scenario); + unstake(STAKER_ADDR_2, 0, scenario); + unstake(STAKER_ADDR_3, 0, scenario); + unstake(STAKER_ADDR_3, 0, scenario); + unstake(STAKER_ADDR_4, 0, scenario); + + // staker 1's first stake was active for 3 epochs so got 20 * 3 = 60 IOTA of rewards + // and her second stake was active for only one epoch and got 10 IOTA of rewards. + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), (220 + 130 + 20 * 3 + 10) * MICROS_PER_IOTA); + // staker 2's stake was active for 2 epochs so got 40 * 2 = 80 IOTA of rewards + assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), (480 + 40 * 2) * MICROS_PER_IOTA); + // staker 3's first stake was active for 1 epoch and got 30 IOTA of rewards + // and her second stake didn't get any rewards. + assert_eq(total_iota_balance(STAKER_ADDR_3, scenario), (390 + 280 + 30) * MICROS_PER_IOTA); + // staker 4 joined and left in an epoch where no rewards were earned so she got no rewards. + assert_eq(total_iota_balance(STAKER_ADDR_4, scenario), 1400 * MICROS_PER_IOTA); + + advance_epoch_with_reward_amounts(0, 0, scenario); + + scenario.next_tx(@0x0); + let mut system_state = scenario.take_shared(); + // Since all the stakes are gone the pool is empty except for the validator's original stake. + assert_eq(system_state.validator_stake_amount(VALIDATOR_ADDR_1), 140 * MICROS_PER_IOTA); + test_scenario::return_shared(system_state); + scenario_val.end(); + } + + #[test] + fun test_uncapped_rewards() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + + let ctx = scenario.ctx(); + let mut validators = vector[]; + + let num_validators = 20; + let mut i = 0; + // Create a set of 20 validators, each with 481 + i * 2 IOTA of stake. + // The stake total sums up to be 481 + 483 + ... + 517 + 519 = 1000 IOTA. + while (i < num_validators) { + let validator = create_validator_for_testing(address::from_u256(i as u256), (481 + i * 2), ctx); + validators.push_back(validator); + i = i + 1; + }; + + create_iota_system_state_for_testing(validators, 0, 0, ctx); + // Each validator's stake gets doubled. + advance_epoch_with_reward_amounts(0, 10000, scenario); + + let mut i = 0; + scenario.next_tx(@0x0); + // Check that each validator has the correct amount of IOTA in their stake pool. + let mut system_state = scenario.take_shared(); + while (i < num_validators) { + let addr = address::from_u256(i as u256); + assert_eq(system_state.validator_stake_amount(addr), (962 + i * 4) * MICROS_PER_IOTA); + i = i + 1; + }; + test_scenario::return_shared(system_state); + scenario_val.end(); + } + + fun set_up_iota_system_state() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + let ctx = scenario.ctx(); + + let validators = vector[ + create_validator_for_testing(VALIDATOR_ADDR_1, 100, ctx), + create_validator_for_testing(VALIDATOR_ADDR_2, 200, ctx), + create_validator_for_testing(VALIDATOR_ADDR_3, 300, ctx), + create_validator_for_testing(VALIDATOR_ADDR_4, 400, ctx), + ]; + create_iota_system_state_for_testing(validators, 1000, 0, ctx); + scenario_val.end(); + } + + fun set_up_iota_system_state_with_big_amounts() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + let ctx = scenario.ctx(); + + let validators = vector[ + create_validator_for_testing(VALIDATOR_ADDR_1, 100000000, ctx), + create_validator_for_testing(VALIDATOR_ADDR_2, 200000000, ctx), + create_validator_for_testing(VALIDATOR_ADDR_3, 300000000, ctx), + create_validator_for_testing(VALIDATOR_ADDR_4, 400000000, ctx), + ]; + create_iota_system_state_for_testing(validators, 1000000000, 0, ctx); + scenario_val.end(); + } + + fun validator_addrs() : vector
    { + vector[VALIDATOR_ADDR_1, VALIDATOR_ADDR_2, VALIDATOR_ADDR_3, VALIDATOR_ADDR_4] + } + + fun set_commission_rate_and_advance_epoch(addr: address, commission_rate: u64, scenario: &mut Scenario) { + scenario.next_tx(addr); + let mut system_state = scenario.take_shared(); + let ctx = scenario.ctx(); + system_state.request_set_commission_rate(commission_rate, ctx); + test_scenario::return_shared(system_state); + advance_epoch(scenario); + } + + fun report_validator(reporter: address, reportee: address, scenario: &mut Scenario) { + scenario.next_tx(reporter); + let mut system_state = scenario.take_shared(); + let cap = scenario.take_from_sender(); + system_state.report_validator(&cap, reportee); + scenario.return_to_sender(cap); + test_scenario::return_shared(system_state); + } +} diff --git a/crates/sui-framework/packages/sui-system/tests/validator_set_tests.move b/crates/iota-framework/packages/iota-system/tests/validator_set_tests.move similarity index 85% rename from crates/sui-framework/packages/sui-system/tests/validator_set_tests.move rename to crates/iota-framework/packages/iota-system/tests/validator_set_tests.move index 3280437b551..87461e3a91f 100644 --- a/crates/sui-framework/packages/sui-system/tests/validator_set_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/validator_set_tests.move @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui_system::validator_set_tests { - use sui::balance; - use sui::coin; - use sui_system::staking_pool::StakedSui; - use sui_system::validator::{Self, Validator, staking_pool_id}; - use sui_system::validator_set::{Self, ValidatorSet, active_validator_addresses}; - use sui::test_scenario::{Self, Scenario}; - use sui::test_utils::{Self, assert_eq}; - use sui::vec_map; - - const MIST_PER_SUI: u64 = 1_000_000_000; // used internally for stakes. +module iota_system::validator_set_tests { + use iota::balance; + use iota::coin; + use iota_system::staking_pool::StakedIota; + use iota_system::validator::{Self, Validator, staking_pool_id}; + use iota_system::validator_set::{Self, ValidatorSet, active_validator_addresses}; + use iota::test_scenario::{Self, Scenario}; + use iota::test_utils::{Self, assert_eq}; + use iota::vec_map; + + const MICROS_PER_IOTA: u64 = 1_000_000_000; // used internally for stakes. #[test] fun test_validator_set_flow() { @@ -27,7 +28,7 @@ module sui_system::validator_set_tests { // Create a validator set with only the first validator in it. let mut validator_set = validator_set::new(vector[validator1], ctx); - assert!(validator_set.total_stake() == 100 * MIST_PER_SUI, 0); + assert!(validator_set.total_stake() == 100 * MICROS_PER_IOTA, 0); // Add the other 3 validators one by one. add_and_activate_validator( @@ -36,7 +37,7 @@ module sui_system::validator_set_tests { scenario ); // Adding validator during the epoch should not affect stake and quorum threshold. - assert!(validator_set.total_stake() == 100 * MIST_PER_SUI, 0); + assert!(validator_set.total_stake() == 100 * MICROS_PER_IOTA, 0); add_and_activate_validator( &mut validator_set, @@ -51,13 +52,13 @@ module sui_system::validator_set_tests { let ctx1 = scenario.ctx(); let stake = validator_set.request_add_stake( @0x1, - coin::mint_for_testing(500 * MIST_PER_SUI, ctx1).into_balance(), + coin::mint_for_testing(500 * MICROS_PER_IOTA, ctx1).into_balance(), ctx1, ); transfer::public_transfer(stake, @0x1); // Adding stake to existing active validator during the epoch // should not change total stake. - assert!(validator_set.total_stake() == 100 * MIST_PER_SUI, 0); + assert!(validator_set.total_stake() == 100 * MICROS_PER_IOTA, 0); }; add_and_activate_validator( @@ -68,7 +69,7 @@ module sui_system::validator_set_tests { advance_epoch_with_dummy_rewards(&mut validator_set, scenario); // Total stake for these should be the starting stake + the 500 staked with validator 1 in addition to the starting stake. - assert!(validator_set.total_stake() == 1500 * MIST_PER_SUI, 0); + assert!(validator_set.total_stake() == 1500 * MICROS_PER_IOTA, 0); scenario.next_tx(@0x1); { @@ -78,10 +79,10 @@ module sui_system::validator_set_tests { }; // Total validator candidate count changes, but total stake remains during epoch. - assert!(validator_set.total_stake() == 1500 * MIST_PER_SUI, 0); + assert!(validator_set.total_stake() == 1500 * MICROS_PER_IOTA, 0); advance_epoch_with_dummy_rewards(&mut validator_set, scenario); // Validator1 is gone. This removes its stake (100) + the 500 staked with it. - assert!(validator_set.total_stake() == 900 * MIST_PER_SUI, 0); + assert!(validator_set.total_stake() == 900 * MICROS_PER_IOTA, 0); test_utils::destroy(validator_set); scenario_val.end(); @@ -148,7 +149,7 @@ module sui_system::validator_set_tests { let validator1 = create_validator(@0x1, 1, 1, true, ctx); let mut validator_set = validator_set::new(vector[validator1], ctx); - assert_eq(validator_set.total_stake(), 100 * MIST_PER_SUI); + assert_eq(validator_set.total_stake(), 100 * MICROS_PER_IOTA); scenario_val.end(); let mut scenario_val = test_scenario::begin(@0x1); @@ -157,7 +158,7 @@ module sui_system::validator_set_tests { let stake = validator_set.request_add_stake( @0x1, - balance::create_for_testing(MIST_PER_SUI - 1), // 1 MIST lower than the threshold + balance::create_for_testing(MICROS_PER_IOTA - 1), // 1 MICROS lower than the threshold ctx1, ); transfer::public_transfer(stake, @0x1); @@ -173,7 +174,7 @@ module sui_system::validator_set_tests { let validator1 = create_validator(@0x1, 1, 1, true, ctx); let mut validator_set = validator_set::new(vector[validator1], ctx); - assert_eq(validator_set.total_stake(), 100 * MIST_PER_SUI); + assert_eq(validator_set.total_stake(), 100 * MICROS_PER_IOTA); scenario_val.end(); let mut scenario_val = test_scenario::begin(@0x1); @@ -181,13 +182,13 @@ module sui_system::validator_set_tests { let ctx1 = scenario.ctx(); let stake = validator_set.request_add_stake( @0x1, - balance::create_for_testing(MIST_PER_SUI), // min possible stake + balance::create_for_testing(MICROS_PER_IOTA), // min possible stake ctx1, ); transfer::public_transfer(stake, @0x1); advance_epoch_with_dummy_rewards(&mut validator_set, scenario); - assert!(validator_set.total_stake() == 101 * MIST_PER_SUI, 0); + assert!(validator_set.total_stake() == 101 * MICROS_PER_IOTA, 0); test_utils::destroy(validator_set); scenario_val.end(); @@ -206,7 +207,7 @@ module sui_system::validator_set_tests { // Create a validator set with only the first validator in it. let mut validator_set = validator_set::new(vector[validator1], ctx); - assert_eq(validator_set.total_stake(), 100 * MIST_PER_SUI); + assert_eq(validator_set.total_stake(), 100 * MICROS_PER_IOTA); scenario_val.end(); let mut scenario_val = test_scenario::begin(@0x1); @@ -219,17 +220,17 @@ module sui_system::validator_set_tests { let ctx = scenario.ctx(); let stake = validator_set.request_add_stake( @0x2, - balance::create_for_testing(500 * MIST_PER_SUI), + balance::create_for_testing(500 * MICROS_PER_IOTA), ctx, ); transfer::public_transfer(stake, @0x42); // Adding stake to a preactive validator should not change total stake. - assert_eq(validator_set.total_stake(), 100 * MIST_PER_SUI); + assert_eq(validator_set.total_stake(), 100 * MICROS_PER_IOTA); }; scenario.next_tx(@0x2); - // Validator 2 now has 700 SUI in stake but that's not enough because we need 701. - validator_set.request_add_validator(701 * MIST_PER_SUI, scenario.ctx()); + // Validator 2 now has 700 IOTA in stake but that's not enough because we need 701. + validator_set.request_add_validator(701 * MICROS_PER_IOTA, scenario.ctx()); test_utils::destroy(validator_set); scenario_val.end(); @@ -247,7 +248,7 @@ module sui_system::validator_set_tests { // Create a validator set with only the first validator in it. let mut validator_set = validator_set::new(vector[validator1], ctx); - assert_eq(validator_set.total_stake(), 100 * MIST_PER_SUI); + assert_eq(validator_set.total_stake(), 100 * MICROS_PER_IOTA); scenario_val.end(); let mut scenario_val = test_scenario::begin(@0x1); @@ -260,17 +261,17 @@ module sui_system::validator_set_tests { let ctx = scenario.ctx(); let stake = validator_set.request_add_stake( @0x2, - balance::create_for_testing(500 * MIST_PER_SUI), + balance::create_for_testing(500 * MICROS_PER_IOTA), ctx, ); transfer::public_transfer(stake, @0x42); // Adding stake to a preactive validator should not change total stake. - assert_eq(validator_set.total_stake(), 100 * MIST_PER_SUI); + assert_eq(validator_set.total_stake(), 100 * MICROS_PER_IOTA); }; scenario.next_tx(@0x2); - // Validator 2 now has 700 SUI in stake and that's just enough. - validator_set.request_add_validator(700 * MIST_PER_SUI, scenario.ctx()); + // Validator 2 now has 700 IOTA in stake and that's just enough. + validator_set.request_add_validator(700 * MICROS_PER_IOTA, scenario.ctx()); test_utils::destroy(validator_set); scenario_val.end(); @@ -290,7 +291,7 @@ module sui_system::validator_set_tests { // Create a validator set with only the first validator in it. let mut validator_set = validator_set::new(vector[validator1], ctx); - assert_eq(validator_set.total_stake(), 100 * MIST_PER_SUI); + assert_eq(validator_set.total_stake(), 100 * MICROS_PER_IOTA); scenario_val.end(); let mut scenario_val = test_scenario::begin(@0x1); @@ -316,10 +317,10 @@ module sui_system::validator_set_tests { let scenario = &mut scenario_val; let ctx = scenario.ctx(); // Create 4 validators. - let v1 = create_validator(@0x1, 1, 1, true, ctx); // 100 SUI of stake - let v2 = create_validator(@0x2, 4, 1, true, ctx); // 400 SUI of stake - let v3 = create_validator(@0x3, 10, 1, true, ctx); // 1000 SUI of stake - let v4 = create_validator(@0x4, 4, 1, true, ctx); // 400 SUI of stake + let v1 = create_validator(@0x1, 1, 1, true, ctx); // 100 IOTA of stake + let v2 = create_validator(@0x2, 4, 1, true, ctx); // 400 IOTA of stake + let v3 = create_validator(@0x3, 10, 1, true, ctx); // 1000 IOTA of stake + let v4 = create_validator(@0x4, 4, 1, true, ctx); // 400 IOTA of stake let mut validator_set = validator_set::new(vector[v1, v2, v3, v4], ctx); scenario_val.end(); @@ -352,7 +353,7 @@ module sui_system::validator_set_tests { let ctx = scenario.ctx(); let stake = validator_set.request_add_stake( @0x4, - balance::create_for_testing(500 * MIST_PER_SUI), + balance::create_for_testing(500 * MICROS_PER_IOTA), ctx, ); transfer::public_transfer(stake, @0x42); @@ -367,7 +368,7 @@ module sui_system::validator_set_tests { // Withdraw the stake from @0x4. scenario.next_tx(@0x42); { - let stake = scenario.take_from_sender(); + let stake = scenario.take_from_sender(); let ctx = scenario.ctx(); let withdrawn_balance = validator_set.request_withdraw_stake( stake, @@ -399,7 +400,7 @@ module sui_system::validator_set_tests { } fun create_validator(addr: address, hint: u8, gas_price: u64, is_initial_validator: bool, ctx: &mut TxContext): Validator { - let stake_value = hint as u64 * 100 * MIST_PER_SUI; + let stake_value = hint as u64 * 100 * MICROS_PER_IOTA; let name = hint_to_ascii(hint); let validator = validator::new_for_testing( addr, @@ -464,8 +465,8 @@ module sui_system::validator_set_tests { &mut dummy_storage_fund_reward, &mut vec_map::empty(), 0, // reward_slashing_rate - low_stake_threshold * MIST_PER_SUI, - very_low_stake_threshold * MIST_PER_SUI, + low_stake_threshold * MICROS_PER_IOTA, + very_low_stake_threshold * MICROS_PER_IOTA, low_stake_grace_period, scenario.ctx() ); @@ -475,7 +476,7 @@ module sui_system::validator_set_tests { } fun add_and_activate_validator(validator_set: &mut ValidatorSet, validator: Validator, scenario: &mut Scenario) { - scenario.next_tx(validator.sui_address()); + scenario.next_tx(validator.iota_address()); let ctx = scenario.ctx(); validator_set.request_add_validator_candidate(validator, ctx); validator_set.request_add_validator(0, ctx); diff --git a/crates/sui-framework/packages/sui-system/tests/validator_tests.move b/crates/iota-framework/packages/iota-system/tests/validator_tests.move similarity index 91% rename from crates/sui-framework/packages/sui-system/tests/validator_tests.move rename to crates/iota-framework/packages/iota-system/tests/validator_tests.move index 1a54bce56aa..fdb450ba2e3 100644 --- a/crates/sui-framework/packages/sui-system/tests/validator_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/validator_tests.move @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui_system::validator_tests { - use sui::bag; - use sui::balance; - use sui::coin::{Self, Coin}; - use sui::sui::SUI; - use sui::test_scenario; - use sui::test_utils; - use sui::url; - use sui_system::staking_pool::StakedSui; - use sui_system::validator::{Self, Validator}; +module iota_system::validator_tests { + use iota::bag; + use iota::balance; + use iota::coin::{Self, Coin}; + use iota::iota::IOTA; + use iota::test_scenario; + use iota::test_utils; + use iota::url; + use iota_system::staking_pool::StakedIota; + use iota_system::validator::{Self, Validator}; const VALID_NET_PUBKEY: vector = vector[171, 2, 39, 3, 139, 105, 166, 171, 153, 151, 102, 197, 151, 186, 140, 116, 114, 90, 213, 225, 20, 167, 60, 69, 203, 12, 180, 198, 9, 217, 117, 38]; @@ -73,7 +74,7 @@ module sui_system::validator_tests { let validator = get_test_validator(ctx); assert!(validator.total_stake_amount() == 10_000_000_000, 0); - assert!(validator.sui_address() == sender, 0); + assert!(validator.iota_address() == sender, 0); test_utils::destroy(validator); }; @@ -81,7 +82,7 @@ module sui_system::validator_tests { // Check that after destroy, the original stake still exists. scenario.next_tx(sender); { - let stake = scenario.take_from_sender(); + let stake = scenario.take_from_sender(); assert!(stake.amount() == 10_000_000_000, 0); scenario.return_to_sender(stake); }; @@ -109,8 +110,8 @@ module sui_system::validator_tests { scenario.next_tx(sender); { - let coin_ids = scenario.ids_for_sender(); - let stake = scenario.take_from_sender_by_id(coin_ids[0]); + let coin_ids = scenario.ids_for_sender(); + let stake = scenario.take_from_sender_by_id(coin_ids[0]); let ctx = scenario.ctx(); let withdrawn_balance = validator.request_withdraw_stake(stake, ctx); transfer::public_transfer(withdrawn_balance.into_coin(ctx), sender); @@ -131,8 +132,8 @@ module sui_system::validator_tests { scenario.next_tx(sender); { - let coin_ids = scenario.ids_for_sender>(); - let withdraw = scenario.take_from_sender_by_id>(coin_ids[0]); + let coin_ids = scenario.ids_for_sender>(); + let withdraw = scenario.take_from_sender_by_id>(coin_ids[0]); assert!(withdraw.value() == 10_000_000_000, 0); scenario.return_to_sender(withdraw); }; @@ -428,7 +429,7 @@ module sui_system::validator_tests { scenario_val.end(); } - #[expected_failure(abort_code = sui_system::validator::EInvalidProofOfPossession)] + #[expected_failure(abort_code = iota_system::validator::EInvalidProofOfPossession)] #[test] fun test_validator_update_metadata_invalid_proof_of_possession() { let (sender, mut scenario, mut validator) = set_up(); @@ -444,7 +445,7 @@ module sui_system::validator_tests { tear_down(validator, scenario); } - #[expected_failure(abort_code = sui_system::validator::EMetadataInvalidNetPubkey)] + #[expected_failure(abort_code = iota_system::validator::EMetadataInvalidNetPubkey)] #[test] fun test_validator_update_metadata_invalid_network_key() { let (sender, mut scenario, mut validator) = set_up(); @@ -457,7 +458,7 @@ module sui_system::validator_tests { tear_down(validator, scenario); } - #[expected_failure(abort_code = sui_system::validator::EMetadataInvalidWorkerPubkey)] + #[expected_failure(abort_code = iota_system::validator::EMetadataInvalidWorkerPubkey)] #[test] fun test_validator_update_metadata_invalid_worker_key() { let (sender, mut scenario, mut validator) = set_up(); @@ -470,7 +471,7 @@ module sui_system::validator_tests { tear_down(validator, scenario); } - #[expected_failure(abort_code = sui_system::validator::EMetadataInvalidNetAddr)] + #[expected_failure(abort_code = iota_system::validator::EMetadataInvalidNetAddr)] #[test] fun test_validator_update_metadata_invalid_network_addr() { let (sender, mut scenario, mut validator) = set_up(); @@ -483,7 +484,7 @@ module sui_system::validator_tests { tear_down(validator, scenario); } - #[expected_failure(abort_code = sui_system::validator::EMetadataInvalidPrimaryAddr)] + #[expected_failure(abort_code = iota_system::validator::EMetadataInvalidPrimaryAddr)] #[test] fun test_validator_update_metadata_invalid_primary_addr() { let (sender, mut scenario, mut validator) = set_up(); @@ -496,7 +497,7 @@ module sui_system::validator_tests { tear_down(validator, scenario); } - #[expected_failure(abort_code = sui_system::validator::EMetadataInvalidWorkerAddr)] + #[expected_failure(abort_code = iota_system::validator::EMetadataInvalidWorkerAddr)] #[test] fun test_validator_update_metadata_invalid_worker_addr() { let (sender, mut scenario, mut validator) = set_up(); @@ -509,7 +510,7 @@ module sui_system::validator_tests { tear_down(validator, scenario); } - #[expected_failure(abort_code = sui_system::validator::EMetadataInvalidP2pAddr)] + #[expected_failure(abort_code = iota_system::validator::EMetadataInvalidP2pAddr)] #[test] fun test_validator_update_metadata_invalid_p2p_address() { let (sender, mut scenario, mut validator) = set_up(); @@ -525,7 +526,7 @@ module sui_system::validator_tests { tear_down(validator, scenario); } - #[expected_failure(abort_code = sui_system::validator::EValidatorMetadataExceedingLengthLimit)] + #[expected_failure(abort_code = iota_system::validator::EValidatorMetadataExceedingLengthLimit)] #[test] fun test_validator_update_metadata_primary_address_too_long() { let (sender, mut scenario, mut validator) = set_up(); @@ -541,7 +542,7 @@ module sui_system::validator_tests { tear_down(validator, scenario); } - #[expected_failure(abort_code = sui_system::validator::EValidatorMetadataExceedingLengthLimit)] + #[expected_failure(abort_code = iota_system::validator::EValidatorMetadataExceedingLengthLimit)] #[test] fun test_validator_update_metadata_net_address_too_long() { let (sender, mut scenario, mut validator) = set_up(); @@ -558,7 +559,7 @@ module sui_system::validator_tests { } - #[expected_failure(abort_code = sui_system::validator::EValidatorMetadataExceedingLengthLimit)] + #[expected_failure(abort_code = iota_system::validator::EValidatorMetadataExceedingLengthLimit)] #[test] fun test_validator_update_metadata_worker_address_too_long() { let (sender, mut scenario, mut validator) = set_up(); @@ -573,7 +574,7 @@ module sui_system::validator_tests { tear_down(validator, scenario); } - #[expected_failure(abort_code = sui_system::validator::EValidatorMetadataExceedingLengthLimit)] + #[expected_failure(abort_code = iota_system::validator::EValidatorMetadataExceedingLengthLimit)] #[test] fun test_validator_update_metadata_p2p_address_too_long() { let (sender, mut scenario, mut validator) = set_up(); @@ -589,7 +590,7 @@ module sui_system::validator_tests { tear_down(validator, scenario); } - #[expected_failure(abort_code = sui_system::validator::EValidatorMetadataExceedingLengthLimit)] + #[expected_failure(abort_code = iota_system::validator::EValidatorMetadataExceedingLengthLimit)] #[test] fun test_validator_update_name_too_long() { let (sender, mut scenario, mut validator) = set_up(); @@ -604,7 +605,7 @@ module sui_system::validator_tests { tear_down(validator, scenario); } - #[expected_failure(abort_code = sui_system::validator::EValidatorMetadataExceedingLengthLimit)] + #[expected_failure(abort_code = iota_system::validator::EValidatorMetadataExceedingLengthLimit)] #[test] fun test_validator_update_description_too_long() { let (sender, mut scenario, mut validator) = set_up(); @@ -619,7 +620,7 @@ module sui_system::validator_tests { tear_down(validator, scenario); } - #[expected_failure(abort_code = sui_system::validator::EValidatorMetadataExceedingLengthLimit)] + #[expected_failure(abort_code = iota_system::validator::EValidatorMetadataExceedingLengthLimit)] #[test] fun test_validator_update_project_url_too_long() { let (sender, mut scenario, mut validator) = set_up(); @@ -634,7 +635,7 @@ module sui_system::validator_tests { tear_down(validator, scenario); } - #[expected_failure(abort_code = sui_system::validator::EValidatorMetadataExceedingLengthLimit)] + #[expected_failure(abort_code = iota_system::validator::EValidatorMetadataExceedingLengthLimit)] #[test] fun test_validator_update_image_url_too_long() { let (sender, mut scenario, mut validator) = set_up(); diff --git a/crates/sui-framework/packages/sui-system/tests/voting_power_tests.move b/crates/iota-framework/packages/iota-system/tests/voting_power_tests.move similarity index 93% rename from crates/sui-framework/packages/sui-system/tests/voting_power_tests.move rename to crates/iota-framework/packages/iota-system/tests/voting_power_tests.move index 8d9e817ccd3..799ca5dc71c 100644 --- a/crates/sui-framework/packages/sui-system/tests/voting_power_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/voting_power_tests.move @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] -module sui_system::voting_power_tests { - use sui_system::governance_test_utils as gtu; - use sui_system::voting_power; - use sui::test_scenario; - use sui::test_utils; - use sui_system::validator::{Self, Validator}; +module iota_system::voting_power_tests { + use iota_system::governance_test_utils as gtu; + use iota_system::voting_power; + use iota::test_scenario; + use iota::test_utils; + use iota_system::validator::{Self, Validator}; const TOTAL_VOTING_POWER: u64 = 10_000; diff --git a/crates/iota-framework/packages/move-stdlib/Move.lock b/crates/iota-framework/packages/move-stdlib/Move.lock new file mode 100644 index 00000000000..6413ab5788f --- /dev/null +++ b/crates/iota-framework/packages/move-stdlib/Move.lock @@ -0,0 +1,11 @@ +# @generated by Move, please check-in and do not edit manually. + +[move] +version = 1 +manifest_digest = "774F1883683AAACD2512A2B6C01188350E10E5A035E065A8CF110CE44A564509" +deps_digest = "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855" + +[move.toolchain-version] +compiler-version = "1.22.0" +edition = "legacy" +flavor = "iota" diff --git a/crates/sui-framework/packages/move-stdlib/Move.toml b/crates/iota-framework/packages/move-stdlib/Move.toml similarity index 100% rename from crates/sui-framework/packages/move-stdlib/Move.toml rename to crates/iota-framework/packages/move-stdlib/Move.toml diff --git a/crates/iota-framework/packages/move-stdlib/sources/address.move b/crates/iota-framework/packages/move-stdlib/sources/address.move new file mode 100644 index 00000000000..924a1d939dd --- /dev/null +++ b/crates/iota-framework/packages/move-stdlib/sources/address.move @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Provides a way to get address length since it's a +/// platform-specific parameter. +module std::address { + /// Should be converted to a native function. + /// Current implementation only works for Iota. + public fun length(): u64 { + 32 + } +} diff --git a/crates/iota-framework/packages/move-stdlib/sources/ascii.move b/crates/iota-framework/packages/move-stdlib/sources/ascii.move new file mode 100644 index 00000000000..b1d0518ec0c --- /dev/null +++ b/crates/iota-framework/packages/move-stdlib/sources/ascii.move @@ -0,0 +1,110 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// The `ASCII` module defines basic string and char newtypes in Move that verify +/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. +module std::ascii { + use std::option::{Self, Option}; + + // Allows calling `.to_string()` to convert an `ascii::String` into as `string::String` + public use fun std::string::from_ascii as String.to_string; + + /// An invalid ASCII character was encountered when creating an ASCII string. + const EINVALID_ASCII_CHARACTER: u64 = 0x10000; + + /// The `String` struct holds a vector of bytes that all represent + /// valid ASCII characters. Note that these ASCII characters may not all + /// be printable. To determine if a `String` contains only "printable" + /// characters you should use the `all_characters_printable` predicate + /// defined in this module. + public struct String has copy, drop, store { + bytes: vector, + } + + /// An ASCII character. + public struct Char has copy, drop, store { + byte: u8, + } + + /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. + public fun char(byte: u8): Char { + assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); + Char { byte } + } + + /// Convert a vector of bytes `bytes` into an `String`. Aborts if + /// `bytes` contains non-ASCII characters. + public fun string(bytes: vector): String { + let x = try_string(bytes); + assert!(x.is_some(), EINVALID_ASCII_CHARACTER); + x.destroy_some() + } + + /// Convert a vector of bytes `bytes` into an `String`. Returns + /// `Some()` if the `bytes` contains all valid ASCII + /// characters. Otherwise returns `None`. + public fun try_string(bytes: vector): Option { + let len = bytes.length(); + let mut i = 0; + while (i < len) { + let possible_byte = bytes[i]; + if (!is_valid_char(possible_byte)) return option::none(); + i = i + 1; + }; + option::some(String { bytes }) + } + + /// Returns `true` if all characters in `string` are printable characters + /// Returns `false` otherwise. Not all `String`s are printable strings. + public fun all_characters_printable(string: &String): bool { + let len = string.bytes.length(); + let mut i = 0; + while (i < len) { + let byte = string.bytes[i]; + if (!is_printable_char(byte)) return false; + i = i + 1; + }; + true + } + + public fun push_char(string: &mut String, char: Char) { + string.bytes.push_back(char.byte); + } + + public fun pop_char(string: &mut String): Char { + Char { byte: string.bytes.pop_back() } + } + + public fun length(string: &String): u64 { + string.as_bytes().length() + } + + /// Get the inner bytes of the `string` as a reference + public fun as_bytes(string: &String): &vector { + &string.bytes + } + + /// Unpack the `string` to get its backing bytes + public fun into_bytes(string: String): vector { + let String { bytes } = string; + bytes + } + + /// Unpack the `char` into its underlying byte. + public fun byte(char: Char): u8 { + let Char { byte } = char; + byte + } + + /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. + public fun is_valid_char(b: u8): bool { + b <= 0x7F + } + + /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. + public fun is_printable_char(byte: u8): bool { + byte >= 0x20 && // Disallow metacharacters + byte <= 0x7E // Don't allow DEL metacharacter + } +} diff --git a/crates/iota-framework/packages/move-stdlib/sources/bcs.move b/crates/iota-framework/packages/move-stdlib/sources/bcs.move new file mode 100644 index 00000000000..2cf47f61382 --- /dev/null +++ b/crates/iota-framework/packages/move-stdlib/sources/bcs.move @@ -0,0 +1,12 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Utility for converting a Move value to its binary representation in BCS (Binary Canonical +/// Serialization). BCS is the binary encoding for Move resources and other non-module values +/// published on-chain. See https://github.com/diem/bcs#binary-canonical-serialization-bcs for more +/// details on BCS. +module std::bcs { + /// Return the binary representation of `v` in BCS (Binary Canonical Serialization) format + native public fun to_bytes(v: &MoveValue): vector; +} diff --git a/crates/sui-framework/packages/move-stdlib/sources/bit_vector.move b/crates/iota-framework/packages/move-stdlib/sources/bit_vector.move similarity index 98% rename from crates/sui-framework/packages/move-stdlib/sources/bit_vector.move rename to crates/iota-framework/packages/move-stdlib/sources/bit_vector.move index 1a56b3d3171..00cbe4e445e 100644 --- a/crates/sui-framework/packages/move-stdlib/sources/bit_vector.move +++ b/crates/iota-framework/packages/move-stdlib/sources/bit_vector.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module std::bit_vector { diff --git a/crates/sui-framework/packages/move-stdlib/sources/debug.move b/crates/iota-framework/packages/move-stdlib/sources/debug.move similarity index 81% rename from crates/sui-framework/packages/move-stdlib/sources/debug.move rename to crates/iota-framework/packages/move-stdlib/sources/debug.move index dc9d236a8d0..c4a59a4ed50 100644 --- a/crates/sui-framework/packages/move-stdlib/sources/debug.move +++ b/crates/iota-framework/packages/move-stdlib/sources/debug.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Module providing debug functionality. diff --git a/crates/sui-framework/packages/move-stdlib/sources/fixed_point32.move b/crates/iota-framework/packages/move-stdlib/sources/fixed_point32.move similarity index 99% rename from crates/sui-framework/packages/move-stdlib/sources/fixed_point32.move rename to crates/iota-framework/packages/move-stdlib/sources/fixed_point32.move index d25eb58ed3b..703aee235fe 100644 --- a/crates/sui-framework/packages/move-stdlib/sources/fixed_point32.move +++ b/crates/iota-framework/packages/move-stdlib/sources/fixed_point32.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Defines a fixed-point numeric type with a 32-bit integer part and diff --git a/crates/iota-framework/packages/move-stdlib/sources/hash.move b/crates/iota-framework/packages/move-stdlib/sources/hash.move new file mode 100644 index 00000000000..af96cf2c7aa --- /dev/null +++ b/crates/iota-framework/packages/move-stdlib/sources/hash.move @@ -0,0 +1,12 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Module which defines SHA hashes for byte vectors. +/// +/// The functions in this module are natively declared both in the Move runtime +/// as in the Move prover's prelude. +module std::hash { + native public fun sha2_256(data: vector): vector; + native public fun sha3_256(data: vector): vector; +} diff --git a/crates/sui-framework/packages/move-stdlib/sources/option.move b/crates/iota-framework/packages/move-stdlib/sources/option.move similarity index 99% rename from crates/sui-framework/packages/move-stdlib/sources/option.move rename to crates/iota-framework/packages/move-stdlib/sources/option.move index 609f6387f32..92e79515e8e 100644 --- a/crates/sui-framework/packages/move-stdlib/sources/option.move +++ b/crates/iota-framework/packages/move-stdlib/sources/option.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// This module defines the Option type and its methods to represent and handle an optional value. diff --git a/crates/iota-framework/packages/move-stdlib/sources/string.move b/crates/iota-framework/packages/move-stdlib/sources/string.move new file mode 100644 index 00000000000..e3b56409d42 --- /dev/null +++ b/crates/iota-framework/packages/move-stdlib/sources/string.move @@ -0,0 +1,110 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// The `string` module defines the `String` type which represents UTF8 encoded strings. +module std::string { + use std::ascii; + use std::option::{Self, Option}; + + /// An invalid UTF8 encoding. + const EINVALID_UTF8: u64 = 1; + + /// Index out of range. + const EINVALID_INDEX: u64 = 2; + + /// A `String` holds a sequence of bytes which is guaranteed to be in utf8 format. + public struct String has copy, drop, store { + bytes: vector, + } + + /// Creates a new string from a sequence of bytes. Aborts if the bytes do not represent valid utf8. + public fun utf8(bytes: vector): String { + assert!(internal_check_utf8(&bytes), EINVALID_UTF8); + String { bytes } + } + + /// Convert an ASCII string to a UTF8 string + public fun from_ascii(s: ascii::String): String { + String { bytes: ascii::into_bytes(s) } + } + + /// Convert an UTF8 string to an ASCII string. + /// Aborts if `s` is not valid ASCII + public fun to_ascii(s: String): ascii::String { + let String { bytes } = s; + ascii::string(bytes) + } + + /// Tries to create a new string from a sequence of bytes. + public fun try_utf8(bytes: vector): Option { + if (internal_check_utf8(&bytes)) { + option::some(String { bytes }) + } else { + option::none() + } + } + + /// Returns a reference to the underlying byte vector. + public fun bytes(s: &String): &vector { + &s.bytes + } + + /// Checks whether this string is empty. + public fun is_empty(s: &String): bool { + s.bytes.is_empty() + } + + /// Returns the length of this string, in bytes. + public fun length(s: &String): u64 { + s.bytes.length() + } + + /// Appends a string. + public fun append(s: &mut String, r: String) { + s.bytes.append(r.bytes) + } + + /// Appends bytes which must be in valid utf8 format. + public fun append_utf8(s: &mut String, bytes: vector) { + s.append(utf8(bytes)) + } + + /// Insert the other string at the byte index in given string. The index must be at a valid utf8 char + /// boundary. + public fun insert(s: &mut String, at: u64, o: String) { + let bytes = &s.bytes; + assert!(at <= bytes.length() && internal_is_char_boundary(bytes, at), EINVALID_INDEX); + let l = s.length(); + let mut front = s.sub_string(0, at); + let end = s.sub_string(at, l); + front.append(o); + front.append(end); + *s = front; + } + + /// Returns a sub-string using the given byte indices, where `i` is the first byte position and `j` is the start + /// of the first byte not included (or the length of the string). The indices must be at valid utf8 char boundaries, + /// guaranteeing that the result is valid utf8. + public fun sub_string(s: &String, i: u64, j: u64): String { + let bytes = &s.bytes; + let l = bytes.length(); + assert!( + j <= l && i <= j && internal_is_char_boundary(bytes, i) && internal_is_char_boundary(bytes, j), + EINVALID_INDEX + ); + String{bytes: internal_sub_string(bytes, i, j)} + } + + /// Computes the index of the first occurrence of a string. Returns `length(s)` if no occurrence found. + public fun index_of(s: &String, r: &String): u64 { + internal_index_of(&s.bytes, &r.bytes) + } + + // Native API + + native fun internal_check_utf8(v: &vector): bool; + native fun internal_is_char_boundary(v: &vector, i: u64): bool; + native fun internal_sub_string(v: &vector, i: u64, j: u64): vector; + native fun internal_index_of(v: &vector, r: &vector): u64; +} diff --git a/crates/sui-framework/packages/move-stdlib/sources/type_name.move b/crates/iota-framework/packages/move-stdlib/sources/type_name.move similarity index 98% rename from crates/sui-framework/packages/move-stdlib/sources/type_name.move rename to crates/iota-framework/packages/move-stdlib/sources/type_name.move index b204de5c802..9525b9dd2f6 100644 --- a/crates/sui-framework/packages/move-stdlib/sources/type_name.move +++ b/crates/iota-framework/packages/move-stdlib/sources/type_name.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[allow(implicit_const_copy)] diff --git a/crates/sui-framework/packages/move-stdlib/sources/unit_test.move b/crates/iota-framework/packages/move-stdlib/sources/unit_test.move similarity index 91% rename from crates/sui-framework/packages/move-stdlib/sources/unit_test.move rename to crates/iota-framework/packages/move-stdlib/sources/unit_test.move index 2b9a13b9d58..293c1173caa 100644 --- a/crates/sui-framework/packages/move-stdlib/sources/unit_test.move +++ b/crates/iota-framework/packages/move-stdlib/sources/unit_test.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] diff --git a/crates/sui-framework/packages/move-stdlib/sources/vector.move b/crates/iota-framework/packages/move-stdlib/sources/vector.move similarity index 99% rename from crates/sui-framework/packages/move-stdlib/sources/vector.move rename to crates/iota-framework/packages/move-stdlib/sources/vector.move index 5805dfd6fcc..b16d7292340 100644 --- a/crates/sui-framework/packages/move-stdlib/sources/vector.move +++ b/crates/iota-framework/packages/move-stdlib/sources/vector.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[defines_primitive(vector)] diff --git a/crates/sui-framework/packages/move-stdlib/tests/ascii_tests.move b/crates/iota-framework/packages/move-stdlib/tests/ascii_tests.move similarity index 98% rename from crates/sui-framework/packages/move-stdlib/tests/ascii_tests.move rename to crates/iota-framework/packages/move-stdlib/tests/ascii_tests.move index 991e87f53a0..64dfbdac6ec 100644 --- a/crates/sui-framework/packages/move-stdlib/tests/ascii_tests.move +++ b/crates/iota-framework/packages/move-stdlib/tests/ascii_tests.move @@ -1,6 +1,7 @@ // Copyright (c) The Diem Core Contributors // Copyright (c) The Move Contributors // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] diff --git a/crates/sui-framework/packages/move-stdlib/tests/bcs_tests.move b/crates/iota-framework/packages/move-stdlib/tests/bcs_tests.move similarity index 98% rename from crates/sui-framework/packages/move-stdlib/tests/bcs_tests.move rename to crates/iota-framework/packages/move-stdlib/tests/bcs_tests.move index 04f3f1aa676..a5269cf93ca 100644 --- a/crates/sui-framework/packages/move-stdlib/tests/bcs_tests.move +++ b/crates/iota-framework/packages/move-stdlib/tests/bcs_tests.move @@ -1,6 +1,7 @@ // Copyright (c) The Diem Core Contributors // Copyright (c) The Move Contributors // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] diff --git a/crates/sui-framework/packages/move-stdlib/tests/bit_vector_tests.move b/crates/iota-framework/packages/move-stdlib/tests/bit_vector_tests.move similarity index 99% rename from crates/sui-framework/packages/move-stdlib/tests/bit_vector_tests.move rename to crates/iota-framework/packages/move-stdlib/tests/bit_vector_tests.move index 83cda51d69f..527f24a7816 100644 --- a/crates/sui-framework/packages/move-stdlib/tests/bit_vector_tests.move +++ b/crates/iota-framework/packages/move-stdlib/tests/bit_vector_tests.move @@ -1,6 +1,7 @@ // Copyright (c) The Diem Core Contributors // Copyright (c) The Move Contributors // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] diff --git a/crates/sui-framework/packages/move-stdlib/tests/fixedpoint32_tests.move b/crates/iota-framework/packages/move-stdlib/tests/fixedpoint32_tests.move similarity index 98% rename from crates/sui-framework/packages/move-stdlib/tests/fixedpoint32_tests.move rename to crates/iota-framework/packages/move-stdlib/tests/fixedpoint32_tests.move index 26e80e7ac81..80373c35bec 100644 --- a/crates/sui-framework/packages/move-stdlib/tests/fixedpoint32_tests.move +++ b/crates/iota-framework/packages/move-stdlib/tests/fixedpoint32_tests.move @@ -1,6 +1,7 @@ // Copyright (c) The Diem Core Contributors // Copyright (c) The Move Contributors // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] diff --git a/crates/iota-framework/packages/move-stdlib/tests/hash_tests.move b/crates/iota-framework/packages/move-stdlib/tests/hash_tests.move new file mode 100644 index 00000000000..265716868fb --- /dev/null +++ b/crates/iota-framework/packages/move-stdlib/tests/hash_tests.move @@ -0,0 +1,24 @@ +// Copyright (c) The Diem Core Contributors +// Copyright (c) The Move Contributors +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module std::hash_tests { + use std::hash; + + #[test] + fun sha2_256_expected_hash() { + let input = x"616263"; + let expected_output = x"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; + assert!(hash::sha2_256(input) == expected_output, 0); + } + + #[test] + fun sha3_256_expected_hash() { + let input = x"616263"; + let expected_output = x"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"; + assert!(hash::sha3_256(input) == expected_output, 0); + } +} diff --git a/crates/sui-framework/packages/move-stdlib/tests/option_tests.move b/crates/iota-framework/packages/move-stdlib/tests/option_tests.move similarity index 98% rename from crates/sui-framework/packages/move-stdlib/tests/option_tests.move rename to crates/iota-framework/packages/move-stdlib/tests/option_tests.move index a5f46190f66..24c3f3b4032 100644 --- a/crates/sui-framework/packages/move-stdlib/tests/option_tests.move +++ b/crates/iota-framework/packages/move-stdlib/tests/option_tests.move @@ -1,6 +1,7 @@ // Copyright (c) The Diem Core Contributors // Copyright (c) The Move Contributors // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] diff --git a/crates/sui-framework/packages/move-stdlib/tests/string_tests.move b/crates/iota-framework/packages/move-stdlib/tests/string_tests.move similarity index 97% rename from crates/sui-framework/packages/move-stdlib/tests/string_tests.move rename to crates/iota-framework/packages/move-stdlib/tests/string_tests.move index bd671050b58..14fce2d75ea 100644 --- a/crates/sui-framework/packages/move-stdlib/tests/string_tests.move +++ b/crates/iota-framework/packages/move-stdlib/tests/string_tests.move @@ -1,6 +1,7 @@ // Copyright (c) The Diem Core Contributors // Copyright (c) The Move Contributors // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] diff --git a/crates/sui-framework/packages/move-stdlib/tests/type_name_tests.move b/crates/iota-framework/packages/move-stdlib/tests/type_name_tests.move similarity index 99% rename from crates/sui-framework/packages/move-stdlib/tests/type_name_tests.move rename to crates/iota-framework/packages/move-stdlib/tests/type_name_tests.move index c9215d2bf01..718c470fed2 100644 --- a/crates/sui-framework/packages/move-stdlib/tests/type_name_tests.move +++ b/crates/iota-framework/packages/move-stdlib/tests/type_name_tests.move @@ -1,6 +1,7 @@ // Copyright (c) The Diem Core Contributors // Copyright (c) The Move Contributors // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // note: intentionally using 0xa here to test non-0x1 module addresses diff --git a/crates/sui-framework/packages/move-stdlib/tests/vector_tests.move b/crates/iota-framework/packages/move-stdlib/tests/vector_tests.move similarity index 99% rename from crates/sui-framework/packages/move-stdlib/tests/vector_tests.move rename to crates/iota-framework/packages/move-stdlib/tests/vector_tests.move index e64322b103d..4ff07ddd6c3 100644 --- a/crates/sui-framework/packages/move-stdlib/tests/vector_tests.move +++ b/crates/iota-framework/packages/move-stdlib/tests/vector_tests.move @@ -1,6 +1,7 @@ // Copyright (c) The Diem Core Contributors // Copyright (c) The Move Contributors // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test_only] diff --git a/crates/iota-framework/packages/stardust/Move.lock b/crates/iota-framework/packages/stardust/Move.lock new file mode 100644 index 00000000000..bd985f45b18 --- /dev/null +++ b/crates/iota-framework/packages/stardust/Move.lock @@ -0,0 +1,28 @@ +# @generated by Move, please check-in and do not edit manually. + +[move] +version = 0 +manifest_digest = "6C1F0F55CC88971254EA38AAC647E0C39D902AAF2D67AC59A332B50B8EDDE68E" +deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600" + +dependencies = [ + { name = "MoveStdlib" }, + { name = "Iota" }, +] + +[[move.package]] +name = "MoveStdlib" +source = { local = "../move-stdlib" } + +[[move.package]] +name = "Iota" +source = { local = "../iota-framework" } + +dependencies = [ + { name = "MoveStdlib" }, +] + +[move.toolchain-version] +compiler-version = "1.22.0" +edition = "legacy" +flavor = "iota" diff --git a/crates/iota-framework/packages/stardust/Move.toml b/crates/iota-framework/packages/stardust/Move.toml new file mode 100644 index 00000000000..a5830ed5b78 --- /dev/null +++ b/crates/iota-framework/packages/stardust/Move.toml @@ -0,0 +1,12 @@ +[package] +name = "Stardust" +version = "0.0.1" +published-at = "0x107a" +edition = "2024.beta" + +[dependencies] +MoveStdlib = { local = "../move-stdlib" } +Iota = { local = "../iota-framework" } + +[addresses] +stardust = "0x107a" diff --git a/crates/sui-framework/packages/stardust/basic_migration_graph.svg b/crates/iota-framework/packages/stardust/basic_migration_graph.svg similarity index 100% rename from crates/sui-framework/packages/stardust/basic_migration_graph.svg rename to crates/iota-framework/packages/stardust/basic_migration_graph.svg diff --git a/crates/sui-framework/packages/stardust/design.md b/crates/iota-framework/packages/stardust/design.md similarity index 100% rename from crates/sui-framework/packages/stardust/design.md rename to crates/iota-framework/packages/stardust/design.md diff --git a/crates/sui-framework/packages/stardust/sources/alias/alias.move b/crates/iota-framework/packages/stardust/sources/alias/alias.move similarity index 98% rename from crates/sui-framework/packages/stardust/sources/alias/alias.move rename to crates/iota-framework/packages/stardust/sources/alias/alias.move index 44e7e753437..3a9fda93a35 100644 --- a/crates/sui-framework/packages/stardust/sources/alias/alias.move +++ b/crates/iota-framework/packages/stardust/sources/alias/alias.move @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::alias { diff --git a/crates/sui-framework/packages/stardust/sources/alias/alias_output.move b/crates/iota-framework/packages/stardust/sources/alias/alias_output.move similarity index 89% rename from crates/sui-framework/packages/stardust/sources/alias/alias_output.move rename to crates/iota-framework/packages/stardust/sources/alias/alias_output.move index 859c001799e..00b994a2702 100644 --- a/crates/sui-framework/packages/stardust/sources/alias/alias_output.move +++ b/crates/iota-framework/packages/stardust/sources/alias/alias_output.move @@ -1,13 +1,14 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::alias_output { - use sui::bag::Bag; - use sui::balance::Balance; - use sui::dynamic_object_field; - use sui::sui::SUI; - use sui::transfer::Receiving; + use iota::bag::Bag; + use iota::balance::Balance; + use iota::dynamic_object_field; + use iota::iota::IOTA; + use iota::transfer::Receiving; use stardust::alias::Alias; @@ -20,7 +21,7 @@ module stardust::alias_output { id: UID, /// The amount of IOTA coins held by the output. - iota: Balance, + iota: Balance, /// The `Bag` holds native tokens, key-ed by the stringified type of the asset. /// Example: key: "0xabcded::soon::SOON", value: Balance<0xabcded::soon::SOON>. @@ -33,7 +34,7 @@ module stardust::alias_output { /// - returns the IOTA Balance, /// - the native tokens Bag, /// - and the `Alias` object that persists the AliasID=ObjectID from Stardust. - public fun extract_assets(mut output: AliasOutput): (Balance, Bag, Alias) { + public fun extract_assets(mut output: AliasOutput): (Balance, Bag, Alias) { // Load the related alias object. let alias = load_alias(&mut output); @@ -74,7 +75,7 @@ module stardust::alias_output { #[test_only] public fun create_for_testing( - iota: Balance, + iota: Balance, native_tokens: Bag, ctx: &mut TxContext ): AliasOutput { diff --git a/crates/sui-framework/packages/stardust/sources/basic/basic_output.move b/crates/iota-framework/packages/stardust/sources/basic/basic_output.move similarity index 94% rename from crates/sui-framework/packages/stardust/sources/basic/basic_output.move rename to crates/iota-framework/packages/stardust/sources/basic/basic_output.move index d70cfbde5ee..945e9427435 100644 --- a/crates/sui-framework/packages/stardust/sources/basic/basic_output.move +++ b/crates/iota-framework/packages/stardust/sources/basic/basic_output.move @@ -1,14 +1,15 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::basic_output { // === Imports === - // Sui imports. - use sui::bag::Bag; - use sui::balance::Balance; - use sui::sui::SUI; - use sui::transfer::Receiving; + // Iota imports. + use iota::bag::Bag; + use iota::balance::Balance; + use iota::iota::IOTA; + use iota::transfer::Receiving; // Package imports. use stardust::expiration_unlock_condition::ExpirationUnlockCondition; @@ -28,7 +29,7 @@ module stardust::basic_output { id: UID, /// The amount of IOTA coins held by the output. - iota: Balance, + iota: Balance, /// The `Bag` holds native tokens, key-ed by the stringified type of the asset. /// Example: key: "0xabcded::soon::SOON", value: Balance<0xabcded::soon::SOON>. @@ -57,7 +58,7 @@ module stardust::basic_output { /// - The object will be deleted. /// - The `StorageDepositReturnUnlockCondition` will return the deposit. /// - Remaining assets (IOTA coins and native tokens) will be returned. - public fun extract_assets(output: BasicOutput, ctx: &mut TxContext) : (Balance, Bag) { + public fun extract_assets(output: BasicOutput, ctx: &mut TxContext) : (Balance, Bag) { // Unpack the output into its basic part. let BasicOutput { id, @@ -112,7 +113,7 @@ module stardust::basic_output { // test only function to create a basic output #[test_only] public fun create_for_testing( - iota: Balance, + iota: Balance, native_tokens: Bag, storage_deposit_return_uc: Option, timelock_uc: Option, diff --git a/crates/sui-framework/packages/stardust/sources/capped_coin.move b/crates/iota-framework/packages/stardust/sources/capped_coin.move similarity index 96% rename from crates/sui-framework/packages/stardust/sources/capped_coin.move rename to crates/iota-framework/packages/stardust/sources/capped_coin.move index 7b2df72d36c..cc49d0013ec 100644 --- a/crates/sui-framework/packages/stardust/sources/capped_coin.move +++ b/crates/iota-framework/packages/stardust/sources/capped_coin.move @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::capped_coin { @@ -6,8 +7,8 @@ module stardust::capped_coin { use std::ascii; use std::string; - use sui::balance::{Supply, Balance}; - use sui::coin::{Self, Coin, TreasuryCap, CoinMetadata}; + use iota::balance::{Supply, Balance}; + use iota::coin::{Self, Coin, TreasuryCap, CoinMetadata}; /// The error returned when the maximum supply reached. const EMaximumSupplyReached: u64 = 0; diff --git a/crates/sui-framework/packages/stardust/sources/nft/irc27.move b/crates/iota-framework/packages/stardust/sources/nft/irc27.move similarity index 97% rename from crates/sui-framework/packages/stardust/sources/nft/irc27.move rename to crates/iota-framework/packages/stardust/sources/nft/irc27.move index f0fc8fb4c9d..696c1f07944 100644 --- a/crates/sui-framework/packages/stardust/sources/nft/irc27.move +++ b/crates/iota-framework/packages/stardust/sources/nft/irc27.move @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::irc27 { @@ -6,8 +7,8 @@ module stardust::irc27 { use std::fixed_point32::FixedPoint32; use std::string::String; - use sui::url::Url; - use sui::vec_map::VecMap; + use iota::url::Url; + use iota::vec_map::VecMap; /// The IRC27 NFT metadata standard schema. public struct Irc27Metadata has store { diff --git a/crates/sui-framework/packages/stardust/sources/nft/nft.move b/crates/iota-framework/packages/stardust/sources/nft/nft.move similarity index 94% rename from crates/sui-framework/packages/stardust/sources/nft/nft.move rename to crates/iota-framework/packages/stardust/sources/nft/nft.move index 1d5988ff685..33814ccb0ef 100644 --- a/crates/sui-framework/packages/stardust/sources/nft/nft.move +++ b/crates/iota-framework/packages/stardust/sources/nft/nft.move @@ -1,12 +1,13 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::nft { use std::string; - use sui::display; - use sui::package; + use iota::display; + use iota::package; use stardust::irc27::{Self, Irc27Metadata}; @@ -39,7 +40,7 @@ module stardust::nft { // Build a `Display` object. let keys = vector[ - // The Sui standard fields. + // The Iota standard fields. string::utf8(b"name"), string::utf8(b"image_url"), string::utf8(b"description"), @@ -55,7 +56,7 @@ module stardust::nft { ]; let values = vector[ - // The Sui standard fields. + // The Iota standard fields. string::utf8(b"{immutable_metadata.name}"), string::utf8(b"{immutable_metadata.uri}"), string::utf8(b"{immutable_metadata.description}"), @@ -84,7 +85,7 @@ module stardust::nft { package::burn_publisher(publisher); // Freeze the display object. - sui::transfer::public_freeze_object(display); + iota::transfer::public_freeze_object(display); } /// Permanently destroy an `Nft` object. diff --git a/crates/sui-framework/packages/stardust/sources/nft/nft_output.move b/crates/iota-framework/packages/stardust/sources/nft/nft_output.move similarity index 92% rename from crates/sui-framework/packages/stardust/sources/nft/nft_output.move rename to crates/iota-framework/packages/stardust/sources/nft/nft_output.move index c0b26d4be83..6147ef48ac2 100644 --- a/crates/sui-framework/packages/stardust/sources/nft/nft_output.move +++ b/crates/iota-framework/packages/stardust/sources/nft/nft_output.move @@ -1,13 +1,14 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::nft_output { - use sui::bag::Bag; - use sui::balance::Balance; - use sui::dynamic_object_field; - use sui::sui::SUI; - use sui::transfer::Receiving; + use iota::bag::Bag; + use iota::balance::Balance; + use iota::dynamic_object_field; + use iota::iota::IOTA; + use iota::transfer::Receiving; use stardust::nft::Nft; @@ -24,7 +25,7 @@ module stardust::nft_output { id: UID, /// The amount of IOTA tokens held by the output. - iota: Balance, + iota: Balance, /// The `Bag` holds native tokens, key-ed by the stringified type of the asset. /// Example: key: "0xabcded::soon::SOON", value: Balance<0xabcded::soon::SOON>. @@ -39,7 +40,7 @@ module stardust::nft_output { } /// The function extracts assets from a legacy NFT output. - public fun extract_assets(mut output: NftOutput, ctx: &mut TxContext): (Balance, Bag, Nft) { + public fun extract_assets(mut output: NftOutput, ctx: &mut TxContext): (Balance, Bag, Nft) { // Load the related Nft object. let nft = load_nft(&mut output); @@ -100,7 +101,7 @@ module stardust::nft_output { #[test_only] public fun create_for_testing( - iota: Balance, + iota: Balance, native_tokens: Bag, storage_deposit_return_uc: Option, timelock_uc: Option, diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/address_unlock_condition.move b/crates/iota-framework/packages/stardust/sources/unlock_condition/address_unlock_condition.move similarity index 95% rename from crates/sui-framework/packages/stardust/sources/unlock_condition/address_unlock_condition.move rename to crates/iota-framework/packages/stardust/sources/unlock_condition/address_unlock_condition.move index bb5fcbe6df3..a9ae88def02 100644 --- a/crates/sui-framework/packages/stardust/sources/unlock_condition/address_unlock_condition.move +++ b/crates/iota-framework/packages/stardust/sources/unlock_condition/address_unlock_condition.move @@ -1,10 +1,11 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::address_unlock_condition { - use sui::coin::TreasuryCap; - use sui::transfer::Receiving; + use iota::coin::TreasuryCap; + use iota::transfer::Receiving; use stardust::alias::Alias; use stardust::alias_output::{Self, AliasOutput}; diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move b/crates/iota-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move similarity index 97% rename from crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move rename to crates/iota-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move index 7fc71b5a388..b12e4a3bc2e 100644 --- a/crates/sui-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move +++ b/crates/iota-framework/packages/stardust/sources/unlock_condition/expiration_unlock_condition.move @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::expiration_unlock_condition { diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move b/crates/iota-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move similarity index 87% rename from crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move rename to crates/iota-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move index 71f934ef806..6b250f054e5 100644 --- a/crates/sui-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move +++ b/crates/iota-framework/packages/stardust/sources/unlock_condition/storage_deposit_return_unlock_condition.move @@ -1,12 +1,13 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::storage_deposit_return_unlock_condition { - use sui::balance::{Balance, split}; - use sui::coin::from_balance; - use sui::sui::SUI; - use sui::transfer::public_transfer; + use iota::balance::{Balance, split}; + use iota::coin::from_balance; + use iota::iota::IOTA; + use iota::transfer::public_transfer; /// The Stardust storage deposit return unlock condition. public struct StorageDepositReturnUnlockCondition has store { @@ -17,7 +18,7 @@ module stardust::storage_deposit_return_unlock_condition { } /// Check the unlock condition. - public fun unlock(condition: StorageDepositReturnUnlockCondition, funding: &mut Balance, ctx: &mut TxContext) { + public fun unlock(condition: StorageDepositReturnUnlockCondition, funding: &mut Balance, ctx: &mut TxContext) { // Aborts if `funding` is not enough. let return_balance = funding.split(condition.return_amount()); diff --git a/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move b/crates/iota-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move similarity index 96% rename from crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move rename to crates/iota-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move index 19e788fdd02..a70f5920210 100644 --- a/crates/sui-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move +++ b/crates/iota-framework/packages/stardust/sources/unlock_condition/timelock_unlock_condition.move @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::timelock_unlock_condition { diff --git a/crates/sui-framework/packages/stardust/sources/utilities.move b/crates/iota-framework/packages/stardust/sources/utilities.move similarity index 92% rename from crates/sui-framework/packages/stardust/sources/utilities.move rename to crates/iota-framework/packages/stardust/sources/utilities.move index b03faa5b04b..d8db42feee4 100644 --- a/crates/sui-framework/packages/stardust/sources/utilities.move +++ b/crates/iota-framework/packages/stardust/sources/utilities.move @@ -1,13 +1,14 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::utilities { // === Imports === use std::type_name; - use sui::bag::Bag; - use sui::balance::Balance; - use sui::coin; + use iota::bag::Bag; + use iota::balance::Balance; + use iota::coin; // === Errors === diff --git a/crates/sui-framework/packages/stardust/tests/alias_tests.move b/crates/iota-framework/packages/stardust/tests/alias_tests.move similarity index 94% rename from crates/sui-framework/packages/stardust/tests/alias_tests.move rename to crates/iota-framework/packages/stardust/tests/alias_tests.move index ab621bb1a6a..c6f91f5f047 100644 --- a/crates/sui-framework/packages/stardust/tests/alias_tests.move +++ b/crates/iota-framework/packages/stardust/tests/alias_tests.move @@ -1,14 +1,15 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::alias_tests { use std::type_name; - use sui::bag; - use sui::balance; - use sui::coin; - use sui::sui::SUI; + use iota::bag; + use iota::balance; + use iota::coin; + use iota::iota::IOTA; use stardust::alias; use stardust::alias_output; @@ -45,7 +46,7 @@ module stardust::alias_tests { ); // Mint some tokens. - let iota = balance::create_for_testing(initial_iota_in_output); + let iota = balance::create_for_testing(initial_iota_in_output); let test_a_balance = balance::create_for_testing(initial_testA_in_output); let test_b_balance = balance::create_for_testing(initial_testB_in_output); diff --git a/crates/sui-framework/packages/stardust/tests/basic_tests.move b/crates/iota-framework/packages/stardust/tests/basic_tests.move similarity index 95% rename from crates/sui-framework/packages/stardust/tests/basic_tests.move rename to crates/iota-framework/packages/stardust/tests/basic_tests.move index 54b685d0464..ccd7865519f 100644 --- a/crates/sui-framework/packages/stardust/tests/basic_tests.move +++ b/crates/iota-framework/packages/stardust/tests/basic_tests.move @@ -1,14 +1,15 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::basic_tests { use std::type_name; - use sui::bag; - use sui::balance; - use sui::coin; - use sui::sui::SUI; + use iota::bag; + use iota::balance; + use iota::coin; + use iota::iota::IOTA; use stardust::basic_output; use stardust::expiration_unlock_condition; @@ -54,7 +55,7 @@ module stardust::basic_tests { ); // Mint some tokens. - let iota = balance::create_for_testing(initial_iota_in_output); + let iota = balance::create_for_testing(initial_iota_in_output); let test_a_balance = balance::create_for_testing(initial_testA_in_output); let test_b_balance = balance::create_for_testing(initial_testB_in_output); diff --git a/crates/sui-framework/packages/stardust/tests/capped_coin_tests.move b/crates/iota-framework/packages/stardust/tests/capped_coin_tests.move similarity index 97% rename from crates/sui-framework/packages/stardust/tests/capped_coin_tests.move rename to crates/iota-framework/packages/stardust/tests/capped_coin_tests.move index f31b4009bab..cf537c21855 100644 --- a/crates/sui-framework/packages/stardust/tests/capped_coin_tests.move +++ b/crates/iota-framework/packages/stardust/tests/capped_coin_tests.move @@ -1,10 +1,11 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::capped_coin_tests { - use sui::coin::{Self, Coin}; - use sui::test_scenario; + use iota::coin::{Self, Coin}; + use iota::test_scenario; use stardust::capped_coin; diff --git a/crates/sui-framework/packages/stardust/tests/nft_tests.move b/crates/iota-framework/packages/stardust/tests/nft_tests.move similarity index 95% rename from crates/sui-framework/packages/stardust/tests/nft_tests.move rename to crates/iota-framework/packages/stardust/tests/nft_tests.move index d0a632f8008..c6d55de57c5 100644 --- a/crates/sui-framework/packages/stardust/tests/nft_tests.move +++ b/crates/iota-framework/packages/stardust/tests/nft_tests.move @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::nft_tests { @@ -8,13 +9,13 @@ module stardust::nft_tests { use std::string; use std::type_name; - use sui::bag; - use sui::balance::{Self, Balance}; - use sui::coin::{Self, Coin}; - use sui::sui::SUI; - use sui::test_scenario; - use sui::url; - use sui::vec_map; + use iota::bag; + use iota::balance::{Self, Balance}; + use iota::coin::{Self, Coin}; + use iota::iota::IOTA; + use iota::test_scenario; + use iota::url; + use iota::vec_map; use stardust::irc27; use stardust::nft_output; @@ -122,7 +123,7 @@ module stardust::nft_tests { // Check the storage deposit return. scenario.next_tx(sender); - let returned_storage_deposit = scenario.take_from_address>(@0xB); + let returned_storage_deposit = scenario.take_from_address>(@0xB); assert!(returned_storage_deposit.value() == 1000, 18); diff --git a/crates/sui-framework/packages/stardust/tests/unlock_condition/address_unlock_condition_tests.move b/crates/iota-framework/packages/stardust/tests/unlock_condition/address_unlock_condition_tests.move similarity index 93% rename from crates/sui-framework/packages/stardust/tests/unlock_condition/address_unlock_condition_tests.move rename to crates/iota-framework/packages/stardust/tests/unlock_condition/address_unlock_condition_tests.move index 0defd502436..6f59fc23d69 100644 --- a/crates/sui-framework/packages/stardust/tests/unlock_condition/address_unlock_condition_tests.move +++ b/crates/iota-framework/packages/stardust/tests/unlock_condition/address_unlock_condition_tests.move @@ -1,12 +1,13 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module stardust::address_unlock_condition_tests { - use sui::bag; - use sui::balance; - use sui::coin; - use sui::sui::SUI; + use iota::bag; + use iota::balance; + use iota::coin; + use iota::iota::IOTA; use stardust::alias; use stardust::alias_output; @@ -46,7 +47,7 @@ module stardust::address_unlock_condition_tests { let mut alias_output = alias_output::create_for_testing( // iota - balance::create_for_testing(initial_iota_in_output), + balance::create_for_testing(initial_iota_in_output), // tokens bag::new(&mut ctx), &mut ctx, @@ -73,7 +74,7 @@ module stardust::address_unlock_condition_tests { alias_output.attach_alias(alias); // `BasicOutput` owned by the alias. - let basic_sui_balance = balance::create_for_testing(initial_iota_in_output); + let basic_iota_balance = balance::create_for_testing(initial_iota_in_output); let timelocked_until = 5; let expiration_after = 20; let sdruc_return_address = @0xB; @@ -81,7 +82,7 @@ module stardust::address_unlock_condition_tests { let expiration_return_address = @0xC; let basic_output = basic_output::create_for_testing( - basic_sui_balance, + basic_iota_balance, bag::new(&mut ctx), option::some(storage_deposit_return_unlock_condition::create_for_testing(sdruc_return_address, sdruc_return_amount)), option::some(timelock_unlock_condition::create_for_testing(timelocked_until)), diff --git a/crates/iota-framework/packages/timelock/Move.lock b/crates/iota-framework/packages/timelock/Move.lock new file mode 100644 index 00000000000..8b1cce8f075 --- /dev/null +++ b/crates/iota-framework/packages/timelock/Move.lock @@ -0,0 +1,37 @@ +# @generated by Move, please check-in and do not edit manually. + +[move] +version = 1 +manifest_digest = "F7B0657885F7F095E7ED4AC0F6A8772A191E3257D870D1C8A0DD84BFD1BE32E8" +deps_digest = "060AD7E57DFB13104F21BE5F5C3759D03F0553FC3229247D9A7A6B45F50D03A3" +dependencies = [ + { name = "MoveStdlib" }, + { name = "Iota" }, + { name = "IotaSystem" }, +] + +[[move.package]] +name = "MoveStdlib" +source = { local = "../move-stdlib" } + +[[move.package]] +name = "Iota" +source = { local = "../iota-framework" } + +dependencies = [ + { name = "MoveStdlib" }, +] + +[[move.package]] +name = "IotaSystem" +source = { local = "../iota-system" } + +dependencies = [ + { name = "MoveStdlib" }, + { name = "Iota" }, +] + +[move.toolchain-version] +compiler-version = "1.22.0" +edition = "legacy" +flavor = "iota" diff --git a/crates/iota-framework/packages/timelock/Move.toml b/crates/iota-framework/packages/timelock/Move.toml new file mode 100644 index 00000000000..1f510ed2509 --- /dev/null +++ b/crates/iota-framework/packages/timelock/Move.toml @@ -0,0 +1,13 @@ +[package] +name = "TimeLock" +version = "0.0.1" +published-at = "0x10cf" +edition = "2024.beta" + +[dependencies] +MoveStdlib = { local = "../move-stdlib" } +Iota = { local = "../iota-framework" } +IotaSystem = { local = "../iota-system" } + +[addresses] +timelock = "0x10cf" diff --git a/crates/iota-framework/packages/timelock/sources/labeler.move b/crates/iota-framework/packages/timelock/sources/labeler.move new file mode 100644 index 00000000000..d2c8a2118f5 --- /dev/null +++ b/crates/iota-framework/packages/timelock/sources/labeler.move @@ -0,0 +1,45 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module timelock::labeler { + + use std::string::{Self, String}; + + use iota::types; + + /// Error code for when a type passed to the `create_labeler_cap` function is not a one-time witness. + const ENotOneTimeWitness: u64 = 0; + + /// `LabelerCap` allows to create labels of the specific type `L`. + /// Can be publicly transferred like any other object. + public struct LabelerCap has key, store { + id: UID, + } + + /// Create a `LabelerCap` instance. + /// Can be created only by consuming a one time witness. + public fun create_labeler_cap(witness: L, ctx: &mut TxContext): LabelerCap { + assert!(types::is_one_time_witness(&witness), ENotOneTimeWitness); + + LabelerCap { + id: object::new(ctx), + } + } + + /// Delete a `LabelerCap` instance. + /// If a capability is destroyed, it is impossible to add the related labels. + public fun destroy_labeler_cap(cap: LabelerCap) { + let LabelerCap { + id, + } = cap; + + object::delete(id); + } + + /// Return a fully qualified type name with the original package IDs + /// that is used as type related a label value. + public(package) fun type_name(): String { + string::from_ascii(std::type_name::get_with_original_ids().into_string()) + } +} diff --git a/crates/iota-framework/packages/timelock/sources/stardust_upgrade_label.move b/crates/iota-framework/packages/timelock/sources/stardust_upgrade_label.move new file mode 100644 index 00000000000..5c2b6bbdc06 --- /dev/null +++ b/crates/iota-framework/packages/timelock/sources/stardust_upgrade_label.move @@ -0,0 +1,11 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// All the vested rewards migrated from Stardust are labeled with this label. +/// It can not be added to an object later after the migration. +module timelock::stardust_upgrade_label { + + /// Name of the label. + public struct STARDUST_UPGRADE_LABEL has drop {} +} diff --git a/crates/iota-framework/packages/timelock/sources/timelock.move b/crates/iota-framework/packages/timelock/sources/timelock.move new file mode 100644 index 00000000000..34800fc80f1 --- /dev/null +++ b/crates/iota-framework/packages/timelock/sources/timelock.move @@ -0,0 +1,161 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// A timelock implementation. +module timelock::timelock { + + use std::string::String; + + use timelock::labeler::{Self, LabelerCap}; + + /// Error code for when the expire timestamp of the lock is in the past. + const EExpireEpochIsPast: u64 = 0; + /// Error code for when the lock has not expired yet. + const ENotExpiredYet: u64 = 1; + + /// `TimeLock` struct that holds a locked object. + public struct TimeLock has key { + id: UID, + /// The locked object. + locked: T, + /// This is the epoch time stamp of when the lock expires. + expiration_timestamp_ms: u64, + /// Timelock related label. + label: Option, + } + + /// Function to lock an object till a unix timestamp in milliseconds. + public fun lock(locked: T, expiration_timestamp_ms: u64, ctx: &mut TxContext): TimeLock { + // Check that `expiration_timestamp_ms` is valid. + check_expiration_timestamp_ms(expiration_timestamp_ms, ctx); + + // Create a timelock. + pack(locked, expiration_timestamp_ms, option::none(), ctx) + } + + /// Function to lock a labeled object till a unix timestamp in milliseconds. + public fun lock_with_label( + _: &LabelerCap, + locked: T, + expiration_timestamp_ms: u64, + ctx: &mut TxContext + ): TimeLock { + // Check that `expiration_timestamp_ms` is valid. + check_expiration_timestamp_ms(expiration_timestamp_ms, ctx); + + // Calculate a label value. + let label = labeler::type_name(); + + // Create a labeled timelock. + pack(locked, expiration_timestamp_ms, option::some(label), ctx) + } + + /// Function to unlock the object from a `TimeLock`. + public fun unlock(self: TimeLock, ctx: &TxContext): T { + // Unpack the timelock. + let (locked, expiration_timestamp_ms, _) = unpack(self); + + // Check if the lock has expired. + assert!(expiration_timestamp_ms <= ctx.epoch_timestamp_ms(), ENotExpiredYet); + + locked + } + + /// Function to get the expiration timestamp of a `TimeLock`. + public fun expiration_timestamp_ms(self: &TimeLock): u64 { + self.expiration_timestamp_ms + } + + /// Function to check if a `TimeLock` is locked. + public fun is_locked(self: &TimeLock, ctx: &TxContext): bool { + self.remaining_time(ctx) > 0 + } + + /// Function to get the remaining time of a `TimeLock`. + /// Returns 0 if the lock has expired. + public fun remaining_time(self: &TimeLock, ctx: &TxContext): u64 { + // Get the epoch timestamp. + let current_timestamp_ms = ctx.epoch_timestamp_ms(); + + // Check if the lock has expired. + if (self.expiration_timestamp_ms < current_timestamp_ms) { + return 0 + }; + + // Calculate the remaining time. + self.expiration_timestamp_ms - current_timestamp_ms + } + + /// Function to get the locked object of a `TimeLock`. + public fun locked(self: &TimeLock): &T { + &self.locked + } + + /// Function to get a mutable reference to the locked object of a `TimeLock`. + /// Must not be callable from the outside, as one could modify the locked object. + public(package) fun locked_mut(self: &mut TimeLock): &mut T { + &mut self.locked + } + + /// Function to get the label of a `TimeLock`. + public fun label(self: &TimeLock): Option { + self.label + } + + /// Check if a `TimeLock` is labeled with the type `L`. + public fun is_labeled_with(self: &TimeLock): bool { + if (self.label.is_some()) { + self.label.borrow() == labeler::type_name() + } + else { + false + } + } + + /// A utility function to pack a `TimeLock`. + public(package) fun pack( + locked: T, + expiration_timestamp_ms: u64, + label: Option, + ctx: &mut TxContext): TimeLock + { + // Create a timelock. + TimeLock { + id: object::new(ctx), + locked, + expiration_timestamp_ms, + label, + } + } + + /// An utility function to unpack a `TimeLock`. + public(package) fun unpack(lock: TimeLock): (T, u64, Option) { + // Unpack the timelock. + let TimeLock { + id, + locked, + expiration_timestamp_ms, + label, + } = lock; + + // Delete the timelock. + object::delete(id); + + (locked, expiration_timestamp_ms, label) + } + + /// An utility function to transfer a `TimeLock`. + public(package) fun transfer(lock: TimeLock, recipient: address) { + transfer::transfer(lock, recipient); + } + + /// An utility function to check that the `expiration_timestamp_ms` value is valid. + fun check_expiration_timestamp_ms(expiration_timestamp_ms: u64, ctx: &TxContext) { + // Get the epoch timestamp. + let epoch_timestamp_ms = ctx.epoch_timestamp_ms(); + + // Check that `expiration_timestamp_ms` is valid. + assert!(expiration_timestamp_ms > epoch_timestamp_ms, EExpireEpochIsPast); + } +} diff --git a/crates/sui-framework/packages/timelock/sources/timelocked_balance.move b/crates/iota-framework/packages/timelock/sources/timelocked_balance.move similarity index 75% rename from crates/sui-framework/packages/timelock/sources/timelocked_balance.move rename to crates/iota-framework/packages/timelock/sources/timelocked_balance.move index cc67e83f976..91976085253 100644 --- a/crates/sui-framework/packages/timelock/sources/timelocked_balance.move +++ b/crates/iota-framework/packages/timelock/sources/timelocked_balance.move @@ -1,23 +1,27 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Utility functions for time-locked balance. module timelock::timelocked_balance { - use sui::balance::Balance; + use iota::balance::Balance; use timelock::timelock::{Self, TimeLock}; - /// For when trying to join two timelocks with different expiration time. + /// For when trying to join two time-locked balances with different expiration time. const EDifferentExpirationTime: u64 = 0; + /// For when trying to join two time-locked balances with different labels. + const EDifferentLabels: u64 = 1; /// Join two `TimeLock>` together. public fun join(self: &mut TimeLock>, other: TimeLock>) { // Check the preconditions. assert!(self.expiration_timestamp_ms() == other.expiration_timestamp_ms(), EDifferentExpirationTime); + assert!(self.label() == other.label(), EDifferentLabels); // Unpack the time-locked balance. - let (value, _) = timelock::unpack(other); + let (value, _, _) = timelock::unpack(other); // Join the balances. self.locked_mut().join(value); @@ -45,6 +49,6 @@ module timelock::timelocked_balance { let value = self.locked_mut().split(value); // Pack the splitted balance into a timelock. - timelock::pack(value, self.expiration_timestamp_ms(), ctx) + timelock::pack(value, self.expiration_timestamp_ms(), self.label(), ctx) } } diff --git a/crates/iota-framework/packages/timelock/sources/timelocked_staked_iota.move b/crates/iota-framework/packages/timelock/sources/timelocked_staked_iota.move new file mode 100644 index 00000000000..66c8c9f56cd --- /dev/null +++ b/crates/iota-framework/packages/timelock/sources/timelocked_staked_iota.move @@ -0,0 +1,142 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module timelock::timelocked_staked_iota { + + use std::string::String; + + use iota_system::staking_pool::StakedIota; + + use timelock::labeler; + + const EIncompatibleTimelockedStakedIota: u64 = 0; + + /// A self-custodial object holding the timelocked staked IOTA tokens. + public struct TimelockedStakedIota has key { + id: UID, + /// A self-custodial object holding the staked IOTA tokens. + staked_iota: StakedIota, + /// This is the epoch time stamp of when the lock expires. + expiration_timestamp_ms: u64, + /// Timelock related label. + label: Option, + } + + /// Create a new instance of `TimelockedStakedIota`. + public(package) fun create( + staked_iota: StakedIota, + expiration_timestamp_ms: u64, + label: Option, + ctx: &mut TxContext + ): TimelockedStakedIota { + TimelockedStakedIota { + id: object::new(ctx), + staked_iota, + expiration_timestamp_ms, + label, + } + } + + /// Function to get the pool id of a `TimelockedStakedIota`. + public fun pool_id(self: &TimelockedStakedIota): ID { self.staked_iota.pool_id() } + + /// Function to get the staked iota amount of a `TimelockedStakedIota`. + public fun staked_iota_amount(self: &TimelockedStakedIota): u64 { self.staked_iota.staked_iota_amount() } + + /// Allows calling `.amount()` on `TimelockedStakedIota` to invoke `staked_iota_amount` + public use fun staked_iota_amount as TimelockedStakedIota.amount; + + /// Function to get the stake activation epoch of a `TimelockedStakedIota`. + public fun stake_activation_epoch(self: &TimelockedStakedIota): u64 { + self.staked_iota.stake_activation_epoch() + } + + /// Function to get the expiration timestamp of a `TimelockedStakedIota`. + public fun expiration_timestamp_ms(self: &TimelockedStakedIota): u64 { + self.expiration_timestamp_ms + } + + /// Function to get the label of a `TimelockedStakedIota`. + public fun label(self: &TimelockedStakedIota): Option { + self.label + } + + /// Check if a `TimelockedStakedIota` is labeled with the type `L`. + public fun is_labeled_with(self: &TimelockedStakedIota): bool { + if (self.label.is_some()) { + self.label.borrow() == labeler::type_name() + } + else { + false + } + } + + /// Split `TimelockedStakedIota` into two parts, one with principal `split_amount`, + /// and the remaining principal is left in `self`. + /// All the other parameters of the `TimelockedStakedIota` like `stake_activation_epoch` or `pool_id` remain the same. + public fun split(self: &mut TimelockedStakedIota, split_amount: u64, ctx: &mut TxContext): TimelockedStakedIota { + let splitted_stake = self.staked_iota.split(split_amount, ctx); + + TimelockedStakedIota { + id: object::new(ctx), + staked_iota: splitted_stake, + expiration_timestamp_ms: self.expiration_timestamp_ms, + label: self.label, + } + } + + /// Split the given `TimelockedStakedIota` to the two parts, one with principal `split_amount`, + /// transfer the newly split part to the sender address. + public entry fun split_staked_iota(stake: &mut TimelockedStakedIota, split_amount: u64, ctx: &mut TxContext) { + transfer::transfer(split(stake, split_amount, ctx), ctx.sender()); + } + + /// Allows calling `.split_to_sender()` on `TimelockedStakedIota` to invoke `split_staked_iota` + public use fun split_staked_iota as TimelockedStakedIota.split_to_sender; + + /// Consume the staked iota `other` and add its value to `self`. + /// Aborts if some of the staking parameters are incompatible (pool id, stake activation epoch, etc.) + public entry fun join_staked_iota(self: &mut TimelockedStakedIota, other: TimelockedStakedIota) { + assert!(self.is_equal_staking_metadata(&other), EIncompatibleTimelockedStakedIota); + + let TimelockedStakedIota { + id, + staked_iota, + expiration_timestamp_ms: _, + label: _, + } = other; + + id.delete(); + + self.staked_iota.join(staked_iota); + } + + /// Allows calling `.join()` on `TimelockedStakedIota` to invoke `join_staked_iota` + public use fun join_staked_iota as TimelockedStakedIota.join; + + /// Returns true if all the staking parameters of the staked iota except the principal are identical + public fun is_equal_staking_metadata(self: &TimelockedStakedIota, other: &TimelockedStakedIota): bool { + self.staked_iota.is_equal_staking_metadata(&other.staked_iota) && + (self.expiration_timestamp_ms == other.expiration_timestamp_ms) && + (self.label() == other.label()) + } + + /// A utility function to destroy a `TimelockedStakedIota`. + public(package) fun unpack(self: TimelockedStakedIota): (StakedIota, u64, Option) { + let TimelockedStakedIota { + id, + staked_iota, + expiration_timestamp_ms, + label, + } = self; + + object::delete(id); + + (staked_iota, expiration_timestamp_ms, label) + } + + /// An utility function to transfer a `TimelockedStakedIota`. + public(package) fun transfer(stake: TimelockedStakedIota, recipient: address) { + transfer::transfer(stake, recipient); + } +} diff --git a/crates/iota-framework/packages/timelock/sources/timelocked_staking.move b/crates/iota-framework/packages/timelock/sources/timelocked_staking.move new file mode 100644 index 00000000000..ee4741b839c --- /dev/null +++ b/crates/iota-framework/packages/timelock/sources/timelocked_staking.move @@ -0,0 +1,167 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module timelock::timelocked_staking { + + use iota::balance::{Self, Balance}; + use iota::iota::IOTA; + + use iota_system::iota_system::{IotaSystemState}; + + use timelock::timelock::{Self, TimeLock}; + use timelock::timelocked_staked_iota::{Self, TimelockedStakedIota}; + + /// For when trying to stake an expired time-locked balance. + const ETimeLockShouldNotBeExpired: u64 = 0; + + /// Add a time-locked stake to a validator's staking pool. + public entry fun request_add_stake( + iota_system: &mut IotaSystemState, + timelocked_balance: TimeLock>, + validator_address: address, + ctx: &mut TxContext, + ) { + // Stake the time-locked balance. + let timelocked_staked_iota = request_add_stake_non_entry(iota_system, timelocked_balance, validator_address, ctx); + + // Transfer the receipt to the sender. + timelocked_staked_iota::transfer(timelocked_staked_iota, ctx.sender()); + } + + /// The non-entry version of `request_add_stake`, which returns the time-locked staked IOTA instead of transferring it to the sender. + public fun request_add_stake_non_entry( + iota_system: &mut IotaSystemState, + timelocked_balance: TimeLock>, + validator_address: address, + ctx: &mut TxContext, + ) : TimelockedStakedIota { + // Check the preconditions. + assert!(timelocked_balance.is_locked(ctx), ETimeLockShouldNotBeExpired); + + // Unpack the time-locked balance. + let (balance, expiration_timestamp_ms, label) = timelock::unpack(timelocked_balance); + + // Stake the time-locked balance. + let staked_iota = iota_system.request_add_stake_non_entry( + balance.into_coin(ctx), + validator_address, + ctx, + ); + + // Create and return a receipt. + timelocked_staked_iota::create( + staked_iota, + expiration_timestamp_ms, + label, + ctx, + ) + } + + /// Add a time-locked stake to a validator's staking pool using multiple time-locked balances. + public entry fun request_add_stake_mul_bal( + iota_system: &mut IotaSystemState, + timelocked_balances: vector>>, + validator_address: address, + ctx: &mut TxContext, + ) { + // Stake the time-locked balances. + let mut receipts = request_add_stake_mul_bal_non_entry(iota_system, timelocked_balances, validator_address, ctx); + + // Create useful variables. + let (mut i, len) = (0, receipts.length()); + + // Send all the receipts to the sender. + while (i < len) { + // Take a receipt. + let receipt = receipts.pop_back(); + + // Transfer the receipt to the sender. + timelocked_staked_iota::transfer(receipt, ctx.sender()); + + i = i + 1 + }; + + // Destroy the empty vector. + vector::destroy_empty(receipts) + } + + /// The non-entry version of `request_add_stake_mul_bal`, + /// which returns a list of the time-locked staked IOTAs instead of transferring them to the sender. + public fun request_add_stake_mul_bal_non_entry( + iota_system: &mut IotaSystemState, + mut timelocked_balances: vector>>, + validator_address: address, + ctx: &mut TxContext, + ) : vector { + // Create a vector to store the results. + let mut result = vector[]; + + // Create useful variables. + let (mut i, len) = (0, timelocked_balances.length()); + + // Stake all the time-locked balances. + while (i < len) { + // Take a time-locked balance. + let timelocked_balance = timelocked_balances.pop_back(); + + // Stake the time-locked balance. + let timelocked_staked_iota = request_add_stake_non_entry(iota_system, timelocked_balance, validator_address, ctx); + + // Store the created receipt. + result.push_back(timelocked_staked_iota); + + i = i + 1 + }; + + // Destroy the empty vector. + vector::destroy_empty(timelocked_balances); + + result + } + + /// Withdraw a time-locked stake from a validator's staking pool. + public entry fun request_withdraw_stake( + iota_system: &mut IotaSystemState, + timelocked_staked_iota: TimelockedStakedIota, + ctx: &mut TxContext, + ) { + // Withdraw the time-locked balance. + let (timelocked_balance, reward) = request_withdraw_stake_non_entry(iota_system, timelocked_staked_iota, ctx); + + // Transfer the withdrawn time-locked balance to the sender. + timelock::transfer(timelocked_balance, ctx.sender()); + + // Send coins only if the reward is not zero. + if (reward.value() > 0) { + transfer::public_transfer(reward.into_coin(ctx), ctx.sender()); + } + else { + balance::destroy_zero(reward); + } + } + + /// Non-entry version of `request_withdraw_stake` that returns the withdrawn time-locked IOTA and reward + /// instead of transferring it to the sender. + public fun request_withdraw_stake_non_entry( + iota_system: &mut IotaSystemState, + timelocked_staked_iota: TimelockedStakedIota, + ctx: &mut TxContext, + ) : (TimeLock>, Balance) { + // Unpack the `TimelockedStakedIota` instance. + let (staked_iota, expiration_timestamp_ms, label) = timelocked_staked_iota.unpack(); + + // Store the original stake amount. + let principal = staked_iota.staked_iota_amount(); + + // Withdraw the balance. + let mut withdraw_stake = iota_system.request_withdraw_stake_non_entry(staked_iota, ctx); + + // The iota_system withdraw functions return a balance that consists of the original staked amount plus the reward amount; + // In here, it splits the original staked balance to timelock it again. + let principal = withdraw_stake.split(principal); + + // Pack and return a time-locked balance, and the reward. + (timelock::pack(principal, expiration_timestamp_ms, label, ctx), withdraw_stake) + } +} diff --git a/crates/iota-framework/packages/timelock/tests/labeler_test.move b/crates/iota-framework/packages/timelock/tests/labeler_test.move new file mode 100644 index 00000000000..1643436e0f6 --- /dev/null +++ b/crates/iota-framework/packages/timelock/tests/labeler_test.move @@ -0,0 +1,32 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module timelock::labeler_tests { + + use iota::test_scenario; + + use timelock::labeler; + + public struct FAKE_WITNESS has drop {} + + #[test] + #[expected_failure(abort_code = labeler::ENotOneTimeWitness)] + fun test_create_cap_with_fake_witness() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Fake one time witness. + let witness = FAKE_WITNESS{}; + + // Create a new capability. + let cap = labeler::create_labeler_cap(witness, scenario.ctx()); + + // Cleanup. + labeler::destroy_labeler_cap(cap); + + scenario.end(); + } +} diff --git a/crates/iota-framework/packages/timelock/tests/test_label_one.move b/crates/iota-framework/packages/timelock/tests/test_label_one.move new file mode 100644 index 00000000000..88bc6f5e95d --- /dev/null +++ b/crates/iota-framework/packages/timelock/tests/test_label_one.move @@ -0,0 +1,24 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module timelock::test_label_one { + + use timelock::labeler; + + /// Name of the label. + public struct TEST_LABEL_ONE has drop {} + + /// Create and transfer a `LabelerCap` object to an authority address. + public fun assign_labeler_cap(to: address, ctx: &mut TxContext) { + // Test one time witness. + let witness = TEST_LABEL_ONE{}; + + // Create a new capability. + let cap = labeler::create_labeler_cap(witness, ctx); + + // Transfer the capability to the specified address. + transfer::public_transfer(cap, to); + } +} diff --git a/crates/iota-framework/packages/timelock/tests/test_label_two.move b/crates/iota-framework/packages/timelock/tests/test_label_two.move new file mode 100644 index 00000000000..8a034edd045 --- /dev/null +++ b/crates/iota-framework/packages/timelock/tests/test_label_two.move @@ -0,0 +1,24 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module timelock::test_label_two { + + use timelock::labeler; + + /// Name of the label. + public struct TEST_LABEL_TWO has drop {} + + /// Create and transfer a `LabelerCap` object to an authority address. + public fun assign_labeler_cap(to: address, ctx: &mut TxContext) { + // Test one time witness. + let witness = TEST_LABEL_TWO{}; + + // Create a new capability. + let cap = labeler::create_labeler_cap(witness, ctx); + + // Transfer the capability to the specified address. + transfer::public_transfer(cap, to); + } +} diff --git a/crates/iota-framework/packages/timelock/tests/timelock_tests.move b/crates/iota-framework/packages/timelock/tests/timelock_tests.move new file mode 100644 index 00000000000..91933d8fd35 --- /dev/null +++ b/crates/iota-framework/packages/timelock/tests/timelock_tests.move @@ -0,0 +1,178 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module timelock::timelock_tests { + + use std::string; + + use iota::balance::{Self, Balance}; + use iota::iota::IOTA; + use iota::test_scenario; + use iota::test_utils::{Self, assert_eq}; + + use timelock::labeler::LabelerCap; + use timelock::timelock; + + use timelock::test_label_one::{Self, TEST_LABEL_ONE}; + use timelock::test_label_two::TEST_LABEL_TWO; + + #[test] + fun test_lock_unlock_flow() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Minting some IOTA. + let iota = balance::create_for_testing(10); + + // Lock the IOTA balance. + let timelock = timelock::lock(iota, 100, scenario.ctx()); + + // Check the locked IOTA. + assert_eq(timelock.locked().value(), 10); + + // Check if the timelock is locked. + assert_eq(timelock.is_locked(scenario.ctx()), true); + assert_eq(timelock.remaining_time(scenario.ctx()), 100); + + // Check the label. + assert_eq(timelock.label().is_none(), true); + assert_eq(timelock.is_labeled_with, TEST_LABEL_ONE>(), false); + + // Increment epoch timestamp. + scenario.ctx().increment_epoch_timestamp(10); + + // Check if the timelock is still locked. + assert_eq(timelock.is_locked(scenario.ctx()), true); + assert_eq(timelock.remaining_time(scenario.ctx()), 90); + + // Increment epoch timestamp again. + scenario.ctx().increment_epoch_timestamp(90); + + // Check if the timelock is unlocked. + assert_eq(timelock.is_locked(scenario.ctx()), false); + assert_eq(timelock.remaining_time(scenario.ctx()), 0); + + // Unlock the IOTA balance. + let balance = timelock::unlock(timelock, scenario.ctx()); + + // Check the unlocked IOTA balance. + assert_eq(balance.value(), 10); + + // Cleanup. + balance::destroy_for_testing(balance); + + scenario.end(); + } + + #[test] + fun test_lock_unlock_labeled_flow() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Initialize a LabelerCap instance. + test_label_one::assign_labeler_cap(sender, scenario.ctx()); + + // Advance the scenario to a new transaction. + scenario.next_tx(sender); + + // Take the capability. + let labeler_one = scenario.take_from_sender>(); + + // Minting some IOTA. + let iota = balance::create_for_testing(10); + + // Lock the IOTA balance. + let timelock = timelock::lock_with_label(&labeler_one, iota, 100, scenario.ctx()); + + // Check the locked IOTA. + assert_eq(timelock.locked().value(), 10); + + // Check if the timelock is locked. + assert_eq(timelock.is_locked(scenario.ctx()), true); + assert_eq(timelock.remaining_time(scenario.ctx()), 100); + + // Check the labels. + assert_eq(timelock.is_labeled_with, TEST_LABEL_ONE>(), true); + assert_eq(timelock.is_labeled_with, TEST_LABEL_TWO>(), false); + + assert_eq(*timelock.label().borrow(), string::utf8(b"00000000000000000000000000000000000000000000000000000000000010cf::test_label_one::TEST_LABEL_ONE")); + + // Increment epoch timestamp. + scenario.ctx().increment_epoch_timestamp(10); + + // Check if the timelock is still locked. + assert_eq(timelock.is_locked(scenario.ctx()), true); + assert_eq(timelock.remaining_time(scenario.ctx()), 90); + + // Increment epoch timestamp again. + scenario.ctx().increment_epoch_timestamp(90); + + // Check if the timelock is unlocked. + assert_eq(timelock.is_locked(scenario.ctx()), false); + assert_eq(timelock.remaining_time(scenario.ctx()), 0); + + // Unlock the IOTA balance. + let balance = timelock::unlock(timelock, scenario.ctx()); + + // Check the unlocked IOTA balance. + assert_eq(balance.value(), 10); + + // Cleanup. + balance::destroy_for_testing(balance); + + scenario.return_to_sender(labeler_one); + + scenario.end(); + } + + #[test] + #[expected_failure(abort_code = timelock::EExpireEpochIsPast)] + fun test_expiration_time_is_passed() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Increment epoch timestamp. + scenario.ctx().increment_epoch_timestamp(100); + + // Minting some IOTA. + let iota = balance::create_for_testing(10); + + // Lock the IOTA balance with a wrong expiration time. + let timelock = timelock::lock(iota, 10, scenario.ctx()); + + // Cleanup. + test_utils::destroy(timelock); + + scenario.end(); + } + + #[test] + #[expected_failure(abort_code = timelock::ENotExpiredYet)] + fun test_unlock_not_expired_object() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Minting some IOTA. + let iota = balance::create_for_testing(10); + + // Lock the IOTA balance. + let timelock = timelock::lock(iota, 100, scenario.ctx()); + + // Increment epoch timestamp. + scenario.ctx().increment_epoch_timestamp(10); + + // Unlock the IOTA balance which is not expired. + let balance = timelock::unlock(timelock, scenario.ctx()); + + // Cleanup. + balance::destroy_for_testing(balance); + + scenario.end(); + } +} diff --git a/crates/iota-framework/packages/timelock/tests/timelocked_balance_tests.move b/crates/iota-framework/packages/timelock/tests/timelocked_balance_tests.move new file mode 100644 index 00000000000..08dcc72ac9e --- /dev/null +++ b/crates/iota-framework/packages/timelock/tests/timelocked_balance_tests.move @@ -0,0 +1,395 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module timelock::timelocked_balance_tests { + + use iota::balance::{Self, Balance}; + use iota::iota::IOTA; + use iota::test_scenario; + use iota::test_utils::{Self, assert_eq}; + + use timelock::labeler::LabelerCap; + use timelock::timelock; + use timelock::timelocked_balance; + + use timelock::test_label_one::{Self, TEST_LABEL_ONE}; + use timelock::test_label_two::{Self, TEST_LABEL_TWO}; + + #[test] + fun test_join_timelocked_balances() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Minting some IOTA. + let iota1 = balance::create_for_testing(10); + let iota2 = balance::create_for_testing(15); + + // Lock the IOTA balances. + let mut timelock1 = timelock::lock(iota1, 100, scenario.ctx()); + let timelock2 = timelock::lock(iota2, 100, scenario.ctx()); + + // Join the timelocks. + timelocked_balance::join(&mut timelock1, timelock2); + + // Check the joined timelock. + assert_eq(timelock1.expiration_timestamp_ms(), 100); + assert_eq(timelock1.locked().value(), 25); + assert_eq(timelock1.label().is_none(), true); + + // Cleanup. + test_utils::destroy(timelock1); + + scenario.end(); + } + + #[test] + fun test_join_labeled_timelocked_balances() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Initialize LabelerCap instances. + test_label_one::assign_labeler_cap(sender, scenario.ctx()); + + // Advance the scenario to a new transaction. + scenario.next_tx(sender); + + // Take the capabilities. + let labeler_one = scenario.take_from_sender>(); + + // Minting some IOTA. + let iota1 = balance::create_for_testing(10); + let iota2 = balance::create_for_testing(15); + + // Lock the IOTA balances. + let mut timelock1 = timelock::lock_with_label(&labeler_one, iota1, 100, scenario.ctx()); + let timelock2 = timelock::lock_with_label(&labeler_one, iota2, 100, scenario.ctx()); + + // Join the timelocks. + timelocked_balance::join(&mut timelock1, timelock2); + + // Check the joined timelock. + assert_eq(timelock1.locked().value(), 25); + assert_eq(timelock1.expiration_timestamp_ms(), 100); + assert_eq(timelock1.is_labeled_with, TEST_LABEL_ONE>(), true); + + // Cleanup. + test_utils::destroy(timelock1); + + scenario.return_to_sender(labeler_one); + + scenario.end(); + } + + #[test] + #[expected_failure(abort_code = timelocked_balance::EDifferentExpirationTime)] + fun test_join_timelocked_balances_with_different_exp_time() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Minting some IOTA. + let iota1 = balance::create_for_testing(10); + let iota2 = balance::create_for_testing(15); + + // Lock the IOTA balances. + let mut timelock1 = timelock::lock(iota1, 100, scenario.ctx()); + let timelock2 = timelock::lock(iota2, 200, scenario.ctx()); + + // Join the timelocks. + timelocked_balance::join(&mut timelock1, timelock2); + + // Cleanup. + test_utils::destroy(timelock1); + + scenario.end(); + } + + #[test] + #[expected_failure(abort_code = timelocked_balance::EDifferentLabels)] + fun test_join_labeled_timelocked_balances_with_different_labels() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Initialize LabelerCap instances. + test_label_one::assign_labeler_cap(sender, scenario.ctx()); + test_label_two::assign_labeler_cap(sender, scenario.ctx()); + + // Advance the scenario to a new transaction. + scenario.next_tx(sender); + + // Take the capabilities. + let labeler_one = scenario.take_from_sender>(); + let labeler_two = scenario.take_from_sender>(); + + // Minting some IOTA. + let iota1 = balance::create_for_testing(10); + let iota2 = balance::create_for_testing(15); + + // Lock the IOTA balance. + let mut timelock1 = timelock::lock_with_label(&labeler_one, iota1, 100, scenario.ctx()); + let timelock2 = timelock::lock_with_label(&labeler_two, iota2, 100, scenario.ctx()); + + // Join the timelocks. + timelocked_balance::join(&mut timelock1, timelock2); + + // Cleanup. + test_utils::destroy(timelock1); + + scenario.return_to_sender(labeler_one); + scenario.return_to_sender(labeler_two); + + scenario.end(); + } + + #[test] + fun test_join_vec_timelocked_balances() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Minting some IOTA. + let iota1 = balance::create_for_testing(10); + let iota2 = balance::create_for_testing(15); + let iota3 = balance::create_for_testing(20); + let iota4 = balance::create_for_testing(25); + + // Lock the IOTA balances. + let mut timelock1 = timelock::lock(iota1, 100, scenario.ctx()); + + let mut others = vector[]; + + others.push_back(timelock::lock(iota2, 100, scenario.ctx())); + others.push_back(timelock::lock(iota3, 100, scenario.ctx())); + others.push_back(timelock::lock(iota4, 100, scenario.ctx())); + + // Join the timelocks. + timelocked_balance::join_vec(&mut timelock1, others); + + // Check the joined timelock. + assert_eq(timelock1.expiration_timestamp_ms(), 100); + assert_eq(timelock1.locked().value(), 70); + + // Cleanup. + test_utils::destroy(timelock1); + + scenario.end(); + } + + #[test] + fun test_join_empty_vec_timelocked_balances() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Minting some IOTA. + let iota = balance::create_for_testing(10); + + // Lock the IOTA balance. + let mut timelock = timelock::lock(iota, 100, scenario.ctx()); + let others = vector[]; + + // Join the timelocks. + timelocked_balance::join_vec(&mut timelock, others); + + // Check the joined timelock. + assert_eq(timelock.expiration_timestamp_ms(), 100); + assert_eq(timelock.locked().value(), 10); + + // Cleanup. + test_utils::destroy(timelock); + + scenario.end(); + } + + #[test] + #[expected_failure(abort_code = timelocked_balance::EDifferentExpirationTime)] + fun test_join_vec_timelocked_balances_with_different_exp_time() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Minting some IOTA. + let iota1 = balance::create_for_testing(10); + let iota2 = balance::create_for_testing(15); + let iota3 = balance::create_for_testing(20); + let iota4 = balance::create_for_testing(25); + + // Lock the IOTA balances. + let mut timelock1 = timelock::lock(iota1, 100, scenario.ctx()); + + let mut others = vector[]; + + others.push_back(timelock::lock(iota2, 100, scenario.ctx())); + others.push_back(timelock::lock(iota3, 200, scenario.ctx())); + others.push_back(timelock::lock(iota4, 100, scenario.ctx())); + + // Join the timelocks. + timelocked_balance::join_vec(&mut timelock1, others); + + // Cleanup. + test_utils::destroy(timelock1); + + scenario.end(); + } + + #[test] + fun test_split_timelocked_balances() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Minting some IOTA. + let iota = balance::create_for_testing(10); + + // Lock the IOTA balance. + let mut original = timelock::lock(iota, 100, scenario.ctx()); + + // Split the timelock. + let splitted = timelocked_balance::split(&mut original, 3, scenario.ctx()); + + // Check the original timelock. + assert_eq(original.expiration_timestamp_ms(), 100); + assert_eq(original.locked().value(), 7); + + // Check the splitted timelock. + assert_eq(splitted.expiration_timestamp_ms(), 100); + assert_eq(splitted.locked().value(), 3); + + // Cleanup. + test_utils::destroy(original); + test_utils::destroy(splitted); + + scenario.end(); + } + + #[test] + fun test_split_zero_value_from_timelocked_balances() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Minting some IOTA. + let iota = balance::create_for_testing(10); + + // Lock the IOTA balance. + let mut original = timelock::lock(iota, 100, scenario.ctx()); + + // Split the timelock. + let splitted = timelocked_balance::split(&mut original, 0, scenario.ctx()); + + // Check the original timelock. + assert_eq(original.expiration_timestamp_ms(), 100); + assert_eq(original.locked().value(), 10); + + // Check the splitted timelock. + assert_eq(splitted.expiration_timestamp_ms(), 100); + assert_eq(splitted.locked().value(), 0); + + // Cleanup. + test_utils::destroy(original); + test_utils::destroy(splitted); + + scenario.end(); + } + + #[test] + fun test_split_same_value_from_timelocked_balances() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Minting some IOTA. + let iota = balance::create_for_testing(10); + + // Lock the IOTA balance. + let mut original = timelock::lock(iota, 100, scenario.ctx()); + + // Split the timelock. + let splitted = timelocked_balance::split(&mut original, 10, scenario.ctx()); + + // Check the original timelock. + assert_eq(original.expiration_timestamp_ms(), 100); + assert_eq(original.locked().value(), 0); + + // Check the splitted timelock. + assert_eq(splitted.expiration_timestamp_ms(), 100); + assert_eq(splitted.locked().value(), 10); + + // Cleanup. + test_utils::destroy(original); + test_utils::destroy(splitted); + + scenario.end(); + } + + #[test] + fun test_split_labeled_timelocked_balances() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Initialize LabelerCap instances. + test_label_one::assign_labeler_cap(sender, scenario.ctx()); + + // Advance the scenario to a new transaction. + scenario.next_tx(sender); + + // Take the capabilities. + let labeler_one = scenario.take_from_sender>(); + + // Minting some IOTA. + let iota = balance::create_for_testing(10); + + // Lock the IOTA balance. + let mut original = timelock::lock_with_label(&labeler_one, iota, 100, scenario.ctx()); + + // Split the timelock. + let splitted = timelocked_balance::split(&mut original, 3, scenario.ctx()); + + // Check the original timelock. + assert_eq(original.locked().value(), 7); + assert_eq(original.expiration_timestamp_ms(), 100); + assert_eq(original.is_labeled_with, TEST_LABEL_ONE>(), true); + + // Check the splitted timelock. + assert_eq(splitted.locked().value(), 3); + assert_eq(splitted.expiration_timestamp_ms(), 100); + assert_eq(splitted.is_labeled_with, TEST_LABEL_ONE>(), true); + + // Cleanup. + test_utils::destroy(original); + test_utils::destroy(splitted); + + scenario.return_to_sender(labeler_one); + + scenario.end(); + } + + #[test] + #[expected_failure(abort_code = balance::ENotEnough)] + fun test_split_bigger_value_from_timelocked_balances() { + // Set up a test environment. + let sender = @0xA; + let mut scenario = test_scenario::begin(sender); + + // Minting some IOTA. + let iota = balance::create_for_testing(10); + + // Lock the IOTA balance. + let mut original = timelock::lock(iota, 100, scenario.ctx()); + + // Split the timelock. + let splitted = timelocked_balance::split(&mut original, 11, scenario.ctx()); + + // Cleanup. + test_utils::destroy(original); + test_utils::destroy(splitted); + + scenario.end(); + } +} diff --git a/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move b/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move new file mode 100644 index 00000000000..6acf1518355 --- /dev/null +++ b/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move @@ -0,0 +1,1050 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module timelock::timelocked_stake_tests { + + use iota::balance; + use iota::balance::Balance; + use iota::coin::Coin; + use iota::iota::IOTA; + use iota::table::Table; + use iota::test_scenario::{Self, Scenario}; + use iota::test_utils::assert_eq; + use iota::test_utils; + + use iota_system::iota_system::IotaSystemState; + use iota_system::staking_pool::{Self, PoolTokenExchangeRate}; + use iota_system::validator_set::{Self, ValidatorSet}; + use iota_system::governance_test_utils::{ + add_validator, + add_validator_candidate, + advance_epoch, + advance_epoch_with_reward_amounts, + assert_validator_total_stake_amounts, + create_validator_for_testing, + create_iota_system_state_for_testing, + remove_validator, + remove_validator_candidate, + total_iota_balance, + unstake, + }; + + use timelock::labeler::LabelerCap; + use timelock::timelock::{Self, TimeLock}; + use timelock::timelocked_staked_iota::{Self, TimelockedStakedIota}; + use timelock::timelocked_staking; + + use timelock::test_label_one::{Self, TEST_LABEL_ONE}; + use timelock::test_label_two::{Self, TEST_LABEL_TWO}; + + const VALIDATOR_ADDR_1: address = @0x1; + const VALIDATOR_ADDR_2: address = @0x2; + + const STAKER_ADDR_1: address = @0x42; + const STAKER_ADDR_2: address = @0x43; + const STAKER_ADDR_3: address = @0x44; + + const NEW_VALIDATOR_ADDR: address = @0x1a4623343cd42be47d67314fce0ad042f3c82685544bc91d8c11d24e74ba7357; + // Generated with seed [0;32] + const NEW_VALIDATOR_PUBKEY: vector = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; + // Generated using [fn test_proof_of_possession] + const NEW_VALIDATOR_POP: vector = x"8b93fc1b33379e2796d361c4056f0f04ad5aea7f4a8c02eaac57340ff09b6dc158eb1945eece103319167f420daf0cb3"; + + const MICROS_PER_IOTA: u64 = 1_000_000_000; + + #[test] + fun test_split_join_staked_iota() { + // All this is just to generate a dummy StakedIota object to split and join later + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); + let scenario = &mut scenario_val; + stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 10, scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + let mut staked_iota = scenario.take_from_sender(); + let ctx = scenario.ctx(); + staked_iota.split_to_sender(20 * MICROS_PER_IOTA, ctx); + scenario.return_to_sender(staked_iota); + }; + + // Verify the correctness of the split and send the join txn + scenario.next_tx(STAKER_ADDR_1); + { + let staked_iota_ids = scenario.ids_for_sender(); + assert!(staked_iota_ids.length() == 2, 101); // staked iota split to 2 coins + + let mut part1 = scenario.take_from_sender_by_id(staked_iota_ids[0]); + let part2 = scenario.take_from_sender_by_id(staked_iota_ids[1]); + + let amount1 = part1.amount(); + let amount2 = part2.amount(); + assert!(amount1 == 20 * MICROS_PER_IOTA || amount1 == 40 * MICROS_PER_IOTA, 102); + assert!(amount2 == 20 * MICROS_PER_IOTA || amount2 == 40 * MICROS_PER_IOTA, 103); + assert!(amount1 + amount2 == 60 * MICROS_PER_IOTA, 104); + + part1.join(part2); + assert!(part1.amount() == 60 * MICROS_PER_IOTA, 105); + scenario.return_to_sender(part1); + }; + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = timelocked_staked_iota::EIncompatibleTimelockedStakedIota)] + fun test_join_different_epochs() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); + let scenario = &mut scenario_val; + // Create two instances of staked iota w/ different epoch activations + stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 10, scenario); + advance_epoch(scenario); + stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 10, scenario); + + // Verify that these cannot be merged + scenario.next_tx(STAKER_ADDR_1); + { + let staked_iota_ids = scenario.ids_for_sender(); + let mut part1 = scenario.take_from_sender_by_id(staked_iota_ids[0]); + let part2 = scenario.take_from_sender_by_id(staked_iota_ids[1]); + + part1.join(part2); + + scenario.return_to_sender(part1); + }; + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = timelocked_staked_iota::EIncompatibleTimelockedStakedIota)] + fun test_join_different_timestamps() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); + let scenario = &mut scenario_val; + // Create two instances of staked iota w/ different epoch activations + stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 10, scenario); + stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 20, scenario); + + // Verify that these cannot be merged + scenario.next_tx(STAKER_ADDR_1); + { + let staked_iota_ids = scenario.ids_for_sender(); + let mut part1 = scenario.take_from_sender_by_id(staked_iota_ids[0]); + let part2 = scenario.take_from_sender_by_id(staked_iota_ids[1]); + + part1.join(part2); + + scenario.return_to_sender(part1); + }; + scenario_val.end(); + } + + #[test] + fun test_join_same_labels() { + set_up_iota_system_state(); + + let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); + let scenario = &mut scenario_val; + + set_up_timelock_labeler_caps(STAKER_ADDR_1, scenario); + + // Create two instances of labeled staked iota w/ different amounts + scenario.next_tx(STAKER_ADDR_1); + { + let labeler_one = scenario.take_from_sender>(); + + stake_labeled_timelocked_with(&labeler_one, STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 10, scenario); + stake_labeled_timelocked_with(&labeler_one, STAKER_ADDR_1, VALIDATOR_ADDR_1, 50, 10, scenario); + + scenario.return_to_sender(labeler_one); + }; + + // Verify that these can be merged + scenario.next_tx(STAKER_ADDR_1); + { + let staked_iota_ids = scenario.ids_for_sender(); + let mut part1 = scenario.take_from_sender_by_id(staked_iota_ids[0]); + let part2 = scenario.take_from_sender_by_id(staked_iota_ids[1]); + + part1.join(part2); + + assert_eq(part1.staked_iota_amount(), 110 * MICROS_PER_IOTA); + assert_eq(part1.expiration_timestamp_ms(), 10); + assert_eq(part1.is_labeled_with(), true); + + scenario.return_to_sender(part1); + }; + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = timelocked_staked_iota::EIncompatibleTimelockedStakedIota)] + fun test_join_different_labels() { + set_up_iota_system_state(); + + let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); + let scenario = &mut scenario_val; + + set_up_timelock_labeler_caps(STAKER_ADDR_1, scenario); + + // Create two instances of labeled staked iota w/ different labels + scenario.next_tx(STAKER_ADDR_1); + { + let labeler_one = scenario.take_from_sender>(); + let labeler_two = scenario.take_from_sender>(); + + stake_labeled_timelocked_with(&labeler_one, STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 10, scenario); + stake_labeled_timelocked_with(&labeler_two, STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 10, scenario); + + scenario.return_to_sender(labeler_one); + scenario.return_to_sender(labeler_two); + }; + + // Verify that these cannot be merged + scenario.next_tx(STAKER_ADDR_1); + { + let staked_iota_ids = scenario.ids_for_sender(); + let mut part1 = scenario.take_from_sender_by_id(staked_iota_ids[0]); + let part2 = scenario.take_from_sender_by_id(staked_iota_ids[1]); + + part1.join(part2); + + scenario.return_to_sender(part1); + }; + scenario_val.end(); + } + + #[test] + fun test_split_with_labels() { + set_up_iota_system_state(); + + let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); + let scenario = &mut scenario_val; + + set_up_timelock_labeler_caps(STAKER_ADDR_1, scenario); + + // Create one instance of labeled staked iota + scenario.next_tx(STAKER_ADDR_1); + { + let labeler_one = scenario.take_from_sender>(); + + stake_labeled_timelocked_with(&labeler_one, STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 10, scenario); + + scenario.return_to_sender(labeler_one); + + advance_epoch(scenario); + }; + + // Verify that it can be splitted + scenario.next_tx(STAKER_ADDR_1); + { + let mut original = scenario.take_from_sender(); + let splitted = original.split(20 * MICROS_PER_IOTA, scenario.ctx()); + + assert_eq(original.staked_iota_amount(), 40 * MICROS_PER_IOTA); + assert_eq(original.expiration_timestamp_ms(), 10); + assert_eq(original.is_labeled_with(), true); + + assert_eq(splitted.staked_iota_amount(), 20 * MICROS_PER_IOTA); + assert_eq(splitted.expiration_timestamp_ms(), 10); + assert_eq(splitted.is_labeled_with(), true); + + scenario.return_to_sender(original); + test_utils::destroy(splitted); + }; + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = staking_pool::EStakedIotaBelowThreshold)] + fun test_split_below_threshold() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); + let scenario = &mut scenario_val; + // Stake 2 IOTA + stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 2, 10, scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + let mut staked_iota = scenario.take_from_sender(); + let ctx = scenario.ctx(); + // The remaining amount after splitting is below the threshold so this should fail. + staked_iota.split_to_sender(1 * MICROS_PER_IOTA + 1, ctx); + scenario.return_to_sender(staked_iota); + }; + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = staking_pool::EStakedIotaBelowThreshold)] + fun test_split_nonentry_below_threshold() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); + let scenario = &mut scenario_val; + // Stake 2 IOTA + stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 2, 10, scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + let mut staked_iota = scenario.take_from_sender(); + let ctx = scenario.ctx(); + // The remaining amount after splitting is below the threshold so this should fail. + let stake = staked_iota.split(1 * MICROS_PER_IOTA + 1, ctx); + test_utils::destroy(stake); + scenario.return_to_sender(staked_iota); + }; + scenario_val.end(); + } + + #[test] + fun test_add_remove_stake_flow() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + scenario.next_tx(STAKER_ADDR_1); + { + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + let ctx = scenario.ctx(); + + // Create a stake to VALIDATOR_ADDR_1. + timelocked_staking::request_add_stake( + system_state_mut_ref, + timelock::lock(balance::create_for_testing(60 * MICROS_PER_IOTA), 10, ctx), + VALIDATOR_ADDR_1, + ctx + ); + + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 100 * MICROS_PER_IOTA); + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2), 100 * MICROS_PER_IOTA); + + test_scenario::return_shared(system_state); + }; + + advance_epoch(scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + let staked_iota = scenario.take_from_sender(); + assert_eq(staked_iota.amount(), 60 * MICROS_PER_IOTA); + + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 160 * MICROS_PER_IOTA); + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2), 100 * MICROS_PER_IOTA); + + let ctx = scenario.ctx(); + + // Unstake from VALIDATOR_ADDR_1 + timelocked_staking::request_withdraw_stake(system_state_mut_ref, staked_iota, ctx); + + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 160 * MICROS_PER_IOTA); + test_scenario::return_shared(system_state); + }; + + advance_epoch(scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + let mut system_state = scenario.take_shared(); + assert_eq(system_state.validator_stake_amount(VALIDATOR_ADDR_1), 100 * MICROS_PER_IOTA); + test_scenario::return_shared(system_state); + }; + scenario_val.end(); + } + + #[test] + fun test_add_remove_labeled_stake_flow() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + set_up_timelock_labeler_caps(STAKER_ADDR_1, scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + let labeler_one = scenario.take_from_sender>(); + + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + let ctx = scenario.ctx(); + + // Create a stake to VALIDATOR_ADDR_1. + timelocked_staking::request_add_stake( + system_state_mut_ref, + timelock::lock_with_label(&labeler_one, balance::create_for_testing(60 * MICROS_PER_IOTA), 10, ctx), + VALIDATOR_ADDR_1, + ctx + ); + + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 100 * MICROS_PER_IOTA); + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2), 100 * MICROS_PER_IOTA); + + test_scenario::return_shared(system_state); + + scenario.return_to_sender(labeler_one); + }; + + advance_epoch(scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + let staked_iota = scenario.take_from_sender(); + assert_eq(staked_iota.amount(), 60 * MICROS_PER_IOTA); + + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 160 * MICROS_PER_IOTA); + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2), 100 * MICROS_PER_IOTA); + + // Unstake from VALIDATOR_ADDR_1 + timelocked_staking::request_withdraw_stake(system_state_mut_ref, staked_iota, scenario.ctx()); + + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 160 * MICROS_PER_IOTA); + test_scenario::return_shared(system_state); + }; + + advance_epoch(scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + let mut system_state = scenario.take_shared(); + + assert_eq(system_state.validator_stake_amount(VALIDATOR_ADDR_1), 100 * MICROS_PER_IOTA); + + // Check the time-locked balance. + let timelock = scenario.take_from_sender>>(); + + assert_eq(timelock.locked().value(), 60 * MICROS_PER_IOTA); + assert_eq(timelock.expiration_timestamp_ms(), 10); + assert_eq(timelock.is_labeled_with, TEST_LABEL_ONE>(), true); + + scenario.return_to_sender(timelock); + + test_scenario::return_shared(system_state); + }; + scenario_val.end(); + } + + #[test] + fun test_add_remove_stake_mul_bal_flow() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + scenario.next_tx(STAKER_ADDR_1); + { + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + let ctx = scenario.ctx(); + + let mut balances = vector[]; + + balances.push_back(timelock::lock(balance::create_for_testing(30 * MICROS_PER_IOTA), 10, ctx)); + balances.push_back(timelock::lock(balance::create_for_testing(60 * MICROS_PER_IOTA), 20, ctx)); + + // Create a stake to VALIDATOR_ADDR_1. + timelocked_staking::request_add_stake_mul_bal( + system_state_mut_ref, + balances, + VALIDATOR_ADDR_1, + ctx + ); + + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 100 * MICROS_PER_IOTA); + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2), 100 * MICROS_PER_IOTA); + + test_scenario::return_shared(system_state); + }; + + advance_epoch(scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + let stake_iota_ids = scenario.ids_for_sender(); + + let staked_iota1 = scenario.take_from_sender_by_id(stake_iota_ids[0]); + assert_eq(staked_iota1.amount(), 30 * MICROS_PER_IOTA); + let staked_iota2 = scenario.take_from_sender_by_id(stake_iota_ids[1]); + assert_eq(staked_iota2.amount(), 60 * MICROS_PER_IOTA); + + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 190 * MICROS_PER_IOTA); + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2), 100 * MICROS_PER_IOTA); + + let ctx = scenario.ctx(); + + // First unstake from VALIDATOR_ADDR_1 + timelocked_staking::request_withdraw_stake(system_state_mut_ref, staked_iota1, ctx); + + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 190 * MICROS_PER_IOTA); + + scenario.return_to_sender(staked_iota2); + test_scenario::return_shared(system_state); + }; + + advance_epoch(scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + let staked_iota = scenario.take_from_sender(); + assert_eq(staked_iota.amount(), 60 * MICROS_PER_IOTA); + + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 160 * MICROS_PER_IOTA); + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2), 100 * MICROS_PER_IOTA); + + let ctx = scenario.ctx(); + + // Second unstake from VALIDATOR_ADDR_1 + timelocked_staking::request_withdraw_stake(system_state_mut_ref, staked_iota, ctx); + + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 160 * MICROS_PER_IOTA); + test_scenario::return_shared(system_state); + }; + + advance_epoch(scenario); + + scenario.next_tx(STAKER_ADDR_1); + { + assert_eq(scenario.has_most_recent_for_sender(), false); + + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 100 * MICROS_PER_IOTA); + assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2), 100 * MICROS_PER_IOTA); + + test_scenario::return_shared(system_state); + }; + + scenario_val.end(); + } + + #[test] + fun test_remove_stake_post_active_flow_no_rewards() { + set_up_iota_system_state_with_storage_fund(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, 10, scenario); + + advance_epoch(scenario); + + assert_validator_total_stake_amounts( + vector[VALIDATOR_ADDR_1, VALIDATOR_ADDR_2], + vector[200 * MICROS_PER_IOTA, 100 * MICROS_PER_IOTA], + scenario + ); + + advance_epoch(scenario); + + remove_validator(VALIDATOR_ADDR_1, scenario); + + advance_epoch(scenario); + + // Make sure stake withdrawal happens + scenario.next_tx(STAKER_ADDR_1); + { + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + assert!(!is_active_validator_by_iota_address(system_state_mut_ref.validators(), VALIDATOR_ADDR_1), 0); + + let staked_iota = scenario.take_from_sender(); + assert_eq(staked_iota.amount(), 100 * MICROS_PER_IOTA); + + // Unstake from VALIDATOR_ADDR_1 + assert!(!has_iota_coins(STAKER_ADDR_1, scenario), 1); + let ctx = scenario.ctx(); + timelocked_staking::request_withdraw_stake(system_state_mut_ref, staked_iota, ctx); + + // Make sure they have all of their stake. + assert_eq(total_timelocked_iota_balance(STAKER_ADDR_1, scenario), 100 * MICROS_PER_IOTA); + assert!(!has_iota_coins(STAKER_ADDR_1, scenario), 2); + + test_scenario::return_shared(system_state); + }; + + // Validator unstakes now. + assert!(!has_iota_coins(VALIDATOR_ADDR_1, scenario), 3); + unstake(VALIDATOR_ADDR_1, 0, scenario); + + // Make sure have all of their stake. NB there is no epoch change. This is immediate. + assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 100 * MICROS_PER_IOTA); + + scenario_val.end(); + } + + #[test] + fun test_remove_stake_post_active_flow_with_rewards() { + set_up_iota_system_state_with_storage_fund(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, 10, scenario); + + advance_epoch(scenario); + + assert_validator_total_stake_amounts( + vector[VALIDATOR_ADDR_1, VALIDATOR_ADDR_2], + vector[200 * MICROS_PER_IOTA, 100 * MICROS_PER_IOTA], + scenario + ); + + // Each validator pool gets 30 MICROS and each validator gets an additional 10 MICROS. + advance_epoch_with_reward_amounts(0, 80, scenario); + + remove_validator(VALIDATOR_ADDR_1, scenario); + + advance_epoch(scenario); + + let reward_amt = 15 * MICROS_PER_IOTA; + let validator_reward_amt = 10 * MICROS_PER_IOTA; + + // Make sure stake withdrawal happens + scenario.next_tx(STAKER_ADDR_1); + { + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + assert!(!is_active_validator_by_iota_address(system_state_mut_ref.validators(), VALIDATOR_ADDR_1), 0); + + let staked_iota = scenario.take_from_sender(); + assert_eq(staked_iota.amount(), 100 * MICROS_PER_IOTA); + + // Unstake from VALIDATOR_ADDR_1 + assert!(!has_iota_coins(STAKER_ADDR_1, scenario), 1); + let ctx = scenario.ctx(); + timelocked_staking::request_withdraw_stake(system_state_mut_ref, staked_iota, ctx); + + // Make sure they have all of their stake. + assert_eq(total_timelocked_iota_balance(STAKER_ADDR_1, scenario), 100 * MICROS_PER_IOTA); + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), reward_amt); + + test_scenario::return_shared(system_state); + }; + + // Validator unstakes now. + assert!(!has_iota_coins(VALIDATOR_ADDR_1, scenario), 2); + unstake(VALIDATOR_ADDR_1, 0, scenario); + unstake(VALIDATOR_ADDR_1, 0, scenario); + + // Make sure have all of their stake. NB there is no epoch change. This is immediate. + assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 100 * MICROS_PER_IOTA + reward_amt + validator_reward_amt); + + scenario_val.end(); + } + + #[test] + fun test_earns_rewards_at_last_epoch() { + set_up_iota_system_state_with_storage_fund(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, 10, scenario); + + advance_epoch(scenario); + + remove_validator(VALIDATOR_ADDR_1, scenario); + + // Add some rewards after the validator requests to leave. Since the validator is still active + // this epoch, they should get the rewards from this epoch. + advance_epoch_with_reward_amounts(0, 80, scenario); + + // Each validator pool gets 30 MICROS and validators shares the 20 MICROS from the storage fund + // so validator gets another 10 MICROS. + let reward_amt = 15 * MICROS_PER_IOTA; + let validator_reward_amt = 10 * MICROS_PER_IOTA; + + // Make sure stake withdrawal happens + scenario.next_tx(STAKER_ADDR_1); + { + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + let staked_iota = scenario.take_from_sender(); + assert_eq(staked_iota.amount(), 100 * MICROS_PER_IOTA); + + // Unstake from VALIDATOR_ADDR_1 + assert!(!has_timelocked_iota_balance(STAKER_ADDR_1, scenario), 0); + assert!(!has_iota_coins(STAKER_ADDR_1, scenario), 1); + let ctx = scenario.ctx(); + timelocked_staking::request_withdraw_stake(system_state_mut_ref, staked_iota, ctx); + + // Make sure they have all of their stake. + assert_eq(total_timelocked_iota_balance(STAKER_ADDR_1, scenario), 100 * MICROS_PER_IOTA); + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), reward_amt); + + test_scenario::return_shared(system_state); + }; + + // Validator unstakes now. + assert!(!has_iota_coins(VALIDATOR_ADDR_1, scenario), 2); + unstake(VALIDATOR_ADDR_1, 0, scenario); + unstake(VALIDATOR_ADDR_1, 0, scenario); + + // Make sure have all of their stake. NB there is no epoch change. This is immediate. + assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 100 * MICROS_PER_IOTA + reward_amt + validator_reward_amt); + + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = validator_set::ENotAValidator)] + fun test_add_stake_post_active_flow() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, 10, scenario); + + advance_epoch(scenario); + + remove_validator(VALIDATOR_ADDR_1, scenario); + + advance_epoch(scenario); + + // Make sure the validator is no longer active. + scenario.next_tx(STAKER_ADDR_1); + { + let mut system_state = scenario.take_shared(); + let system_state_mut_ref = &mut system_state; + + assert!(!is_active_validator_by_iota_address(system_state_mut_ref.validators(), VALIDATOR_ADDR_1), 0); + + test_scenario::return_shared(system_state); + }; + + // Now try and stake to the old validator/staking pool. This should fail! + stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 10, scenario); + + scenario_val.end(); + } + + #[test] + fun test_add_preactive_remove_preactive() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + add_validator_candidate(NEW_VALIDATOR_ADDR, b"name5", b"/ip4/127.0.0.1/udp/85", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); + + // Delegate 100 MICROS to the preactive validator + stake_timelocked_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, 10, scenario); + + // Advance epoch twice with some rewards + advance_epoch_with_reward_amounts(0, 400, scenario); + advance_epoch_with_reward_amounts(0, 900, scenario); + + // Unstake from the preactive validator. There should be no rewards earned. + unstake_timelocked(STAKER_ADDR_1, 0, scenario); + assert!(!has_iota_coins(STAKER_ADDR_1, scenario), 0); + assert_eq(total_timelocked_iota_balance(STAKER_ADDR_1, scenario), 100 * MICROS_PER_IOTA); + + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = validator_set::ENotAValidator)] + fun test_add_preactive_remove_pending_failure() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + add_validator_candidate(NEW_VALIDATOR_ADDR, b"name4", b"/ip4/127.0.0.1/udp/84", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); + + add_validator(NEW_VALIDATOR_ADDR, scenario); + + // Delegate 100 IOTA to the pending validator. This should fail because pending active validators don't accept + // new stakes or withdraws. + stake_timelocked_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, 10, scenario); + + scenario_val.end(); + } + + #[test] + fun test_add_preactive_remove_active() { + set_up_iota_system_state_with_storage_fund(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + add_validator_candidate(NEW_VALIDATOR_ADDR, b"name3", b"/ip4/127.0.0.1/udp/83", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); + + // Delegate 100 IOTA to the preactive validator + stake_timelocked_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, 10, scenario); + advance_epoch_with_reward_amounts(0, 300, scenario); + // At this point we got the following distribution of stake: + // V1: 250, V2: 250, storage fund: 100 + + stake_timelocked_with(STAKER_ADDR_2, NEW_VALIDATOR_ADDR, 50, 10, scenario); + stake_timelocked_with(STAKER_ADDR_3, NEW_VALIDATOR_ADDR, 100, 10, scenario); + + // Now the preactive becomes active + add_validator(NEW_VALIDATOR_ADDR, scenario); + advance_epoch(scenario); + + // At this point we got the following distribution of stake: + // V1: 250, V2: 250, V3: 250, storage fund: 100 + + advance_epoch_with_reward_amounts(0, 85, scenario); + + // staker 1 and 3 unstake from the validator and earns about 2/5 * (85 - 10) * 1/3 = 10 IOTA each. + // Although they stake in different epochs, they earn the same rewards as long as they unstake + // in the same epoch because the validator was preactive when they staked. + // So they will both get slightly more than 110 IOTA in total balance. + unstake_timelocked(STAKER_ADDR_1, 0, scenario); + assert_eq(total_timelocked_iota_balance(STAKER_ADDR_1, scenario), 100 * MICROS_PER_IOTA); + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 10_002_000_000); + + unstake_timelocked(STAKER_ADDR_3, 0, scenario); + assert_eq(total_timelocked_iota_balance(STAKER_ADDR_3, scenario), 100 * MICROS_PER_IOTA); + assert_eq(total_iota_balance(STAKER_ADDR_3, scenario), 10_002_000_000); + + advance_epoch_with_reward_amounts(0, 85, scenario); + + unstake_timelocked(STAKER_ADDR_2, 0, scenario); + // staker 2 earns about 5 IOTA from the previous epoch and 24-ish from this one + // so in total she has about 50 + 5 + 24 = 79 IOTA. + assert_eq(total_timelocked_iota_balance(STAKER_ADDR_2, scenario), 50 * MICROS_PER_IOTA); + assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), 28_862_939_078); + + scenario_val.end(); + } + + #[test] + fun test_add_preactive_remove_post_active() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + add_validator_candidate(NEW_VALIDATOR_ADDR, b"name1", b"/ip4/127.0.0.1/udp/81", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); + + // Delegate 100 IOTA to the preactive validator + stake_timelocked_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, 10, scenario); + + // Now the preactive becomes active + add_validator(NEW_VALIDATOR_ADDR, scenario); + advance_epoch(scenario); + + // staker 1 earns a bit greater than 30 IOTA here. A bit greater because the new validator's voting power + // is slightly greater than 1/3 of the total voting power. + advance_epoch_with_reward_amounts(0, 90, scenario); + + // And now the validator leaves the validator set. + remove_validator(NEW_VALIDATOR_ADDR, scenario); + + advance_epoch(scenario); + + unstake_timelocked(STAKER_ADDR_1, 0, scenario); + assert_eq(total_timelocked_iota_balance(STAKER_ADDR_1, scenario), 100 * MICROS_PER_IOTA); + assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 30_006_000_000); + + scenario_val.end(); + } + + #[test] + fun test_add_preactive_candidate_drop_out() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + add_validator_candidate(NEW_VALIDATOR_ADDR, b"name2", b"/ip4/127.0.0.1/udp/82", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); + + // Delegate 100 MICROS to the preactive validator + stake_timelocked_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, 10, scenario); + + // Advance epoch and give out some rewards. The candidate should get nothing, of course. + advance_epoch_with_reward_amounts(0, 800, scenario); + + // Now the candidate leaves. + remove_validator_candidate(NEW_VALIDATOR_ADDR, scenario); + + // Advance epoch a few times. + advance_epoch(scenario); + advance_epoch(scenario); + advance_epoch(scenario); + + // Unstake now and the staker should get no rewards. + unstake_timelocked(STAKER_ADDR_1, 0, scenario); + assert_eq(total_timelocked_iota_balance(STAKER_ADDR_1, scenario), 100 * MICROS_PER_IOTA); + assert!(!has_iota_coins(STAKER_ADDR_1, scenario), 0); + + scenario_val.end(); + } + + #[test] + fun test_staking_pool_exchange_rate_getter() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + stake_timelocked_with(@0x42, @0x2, 100, 10, scenario); // stakes 100 IOTA with 0x2 + scenario.next_tx(@0x42); + let staked_iota = scenario.take_from_address(@0x42); + let pool_id = staked_iota.pool_id(); + test_scenario::return_to_address(@0x42, staked_iota); + advance_epoch(scenario); // advances epoch to effectuate the stake + // Each staking pool gets 10 IOTA of rewards. + advance_epoch_with_reward_amounts(0, 20, scenario); + let mut system_state = scenario.take_shared(); + let rates = system_state.pool_exchange_rates(&pool_id); + assert_eq(rates.length(), 3); + assert_exchange_rate_eq(rates, 0, 0, 0); // no tokens at epoch 0 + assert_exchange_rate_eq(rates, 1, 200, 200); // 200 IOTA of self + delegate stake at epoch 1 + assert_exchange_rate_eq(rates, 2, 210, 200); // 10 IOTA of rewards at epoch 2 + test_scenario::return_shared(system_state); + scenario_val.end(); + } + + fun assert_exchange_rate_eq( + rates: &Table, epoch: u64, iota_amount: u64, pool_token_amount: u64 + ) { + let rate = &rates[epoch]; + assert_eq(rate.iota_amount(), iota_amount * MICROS_PER_IOTA); + assert_eq(rate.pool_token_amount(), pool_token_amount * MICROS_PER_IOTA); + } + + fun set_up_iota_system_state() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + let ctx = scenario.ctx(); + + let validators = vector[ + create_validator_for_testing(VALIDATOR_ADDR_1, 100, ctx), + create_validator_for_testing(VALIDATOR_ADDR_2, 100, ctx) + ]; + create_iota_system_state_for_testing(validators, 0, 0, ctx); + scenario_val.end(); + } + + fun set_up_timelock_labeler_caps(to: address, scenario: &mut Scenario) { + scenario.next_tx(to); + + test_label_one::assign_labeler_cap(to, scenario.ctx()); + test_label_two::assign_labeler_cap(to, scenario.ctx()); + } + + fun set_up_iota_system_state_with_storage_fund() { + let mut scenario_val = test_scenario::begin(@0x0); + let scenario = &mut scenario_val; + let ctx = scenario.ctx(); + + let validators = vector[ + create_validator_for_testing(VALIDATOR_ADDR_1, 100, ctx), + create_validator_for_testing(VALIDATOR_ADDR_2, 100, ctx) + ]; + create_iota_system_state_for_testing(validators, 300, 100, ctx); + scenario_val.end(); + } + + fun stake_timelocked_with( + staker: address, + validator: address, + amount: u64, + expiration_timestamp_ms: u64, + scenario: &mut Scenario + ) { + scenario.next_tx(staker); + let mut system_state = scenario.take_shared(); + + let ctx = scenario.ctx(); + + timelocked_staking::request_add_stake( + &mut system_state, + timelock::lock(balance::create_for_testing(amount * MICROS_PER_IOTA), expiration_timestamp_ms, ctx), + validator, + ctx); + test_scenario::return_shared(system_state); + } + + fun stake_labeled_timelocked_with( + cap: &LabelerCap, + staker: address, + validator: address, + amount: u64, + expiration_timestamp_ms: u64, + scenario: &mut Scenario + ) { + scenario.next_tx(staker); + + let mut system_state = scenario.take_shared(); + let ctx = scenario.ctx(); + + timelocked_staking::request_add_stake( + &mut system_state, + timelock::lock_with_label( + cap, + balance::create_for_testing(amount * MICROS_PER_IOTA), + expiration_timestamp_ms, + ctx), + validator, + ctx); + + test_scenario::return_shared(system_state); + } + + fun unstake_timelocked( + staker: address, staked_iota_idx: u64, scenario: &mut Scenario + ) { + scenario.next_tx(staker); + let stake_iota_ids = scenario.ids_for_sender(); + let staked_iota = scenario.take_from_sender_by_id(stake_iota_ids[staked_iota_idx]); + let mut system_state = scenario.take_shared(); + + let ctx = scenario.ctx(); + timelocked_staking::request_withdraw_stake(&mut system_state, staked_iota, ctx); + test_scenario::return_shared(system_state); + } + + + fun total_timelocked_iota_balance(addr: address, scenario: &mut Scenario): u64 { + let mut sum = 0; + scenario.next_tx(addr); + let lock_ids = scenario.ids_for_sender>>(); + let mut i = 0; + while (i < lock_ids.length()) { + let coin = scenario.take_from_sender_by_id>>(lock_ids[i]); + sum = sum + coin.locked().value(); + scenario.return_to_sender(coin); + i = i + 1; + }; + sum + } + + fun has_timelocked_iota_balance(addr: address, scenario: &mut Scenario): bool { + scenario.next_tx(addr); + scenario.has_most_recent_for_sender>>() + } + + fun has_iota_coins(addr: address, scenario: &mut Scenario): bool { + scenario.next_tx(addr); + scenario.has_most_recent_for_sender>() + } + + fun is_active_validator_by_iota_address(set: &ValidatorSet, validator_address: address): bool { + let validators = set.active_validators(); + let length = validators.length(); + let mut i = 0; + while (i < length) { + let v = &validators[i]; + if (v.iota_address() == validator_address) { + return true + }; + i = i + 1; + }; + false + } + +} diff --git a/crates/iota-framework/src/lib.rs b/crates/iota-framework/src/lib.rs new file mode 100644 index 00000000000..350d39ef4c3 --- /dev/null +++ b/crates/iota-framework/src/lib.rs @@ -0,0 +1,291 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt::Formatter; + +use iota_types::{ + base_types::{ObjectID, ObjectRef}, + digests::TransactionDigest, + move_package::MovePackage, + object::{Object, OBJECT_START_VERSION}, + storage::ObjectStore, + DEEPBOOK_PACKAGE_ID, IOTA_FRAMEWORK_PACKAGE_ID, IOTA_SYSTEM_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID, + STARDUST_PACKAGE_ID, TIMELOCK_PACKAGE_ID, +}; +use move_binary_format::{ + binary_config::BinaryConfig, + compatibility::Compatibility, + file_format::{Ability, AbilitySet}, + CompiledModule, +}; +use move_core_types::gas_algebra::InternalGas; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; +use tracing::error; + +/// Represents a system package in the framework, that's built from the source +/// code inside iota-framework. +#[derive(Clone, Serialize, PartialEq, Eq, Deserialize)] +pub struct SystemPackage { + pub id: ObjectID, + pub bytes: Vec>, + pub dependencies: Vec, +} + +impl SystemPackage { + pub fn new(id: ObjectID, raw_bytes: &'static [u8], dependencies: &[ObjectID]) -> Self { + let bytes: Vec> = bcs::from_bytes(raw_bytes).unwrap(); + Self { + id, + bytes, + dependencies: dependencies.to_vec(), + } + } + + pub fn id(&self) -> &ObjectID { + &self.id + } + + pub fn bytes(&self) -> &[Vec] { + &self.bytes + } + + pub fn dependencies(&self) -> &[ObjectID] { + &self.dependencies + } + + pub fn modules(&self) -> Vec { + self.bytes + .iter() + .map(|b| CompiledModule::deserialize_with_defaults(b).unwrap()) + .collect() + } + + pub fn genesis_move_package(&self) -> MovePackage { + MovePackage::new_system( + OBJECT_START_VERSION, + &self.modules(), + self.dependencies.iter().copied(), + ) + } + + pub fn genesis_object(&self) -> Object { + Object::new_system_package( + &self.modules(), + OBJECT_START_VERSION, + self.dependencies.to_vec(), + TransactionDigest::genesis_marker(), + ) + } +} + +impl std::fmt::Debug for SystemPackage { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + writeln!(f, "Object ID: {:?}", self.id)?; + writeln!(f, "Size: {}", self.bytes.len())?; + writeln!(f, "Dependencies: {:?}", self.dependencies)?; + Ok(()) + } +} + +macro_rules! define_system_packages { + ([$(($id:expr, $path:expr, $deps:expr)),* $(,)?]) => {{ + static PACKAGES: Lazy> = Lazy::new(|| { + vec![ + $(SystemPackage::new( + $id, + include_bytes!(concat!(env!("OUT_DIR"), "/", $path)), + &$deps, + )),* + ] + }); + Lazy::force(&PACKAGES) + }} +} + +pub struct BuiltInFramework; +impl BuiltInFramework { + /// Dedicated method to iterate on `stardust` packages. + // TODO: integrate to iter_system_packages when we make a new + // system-framework-snapshot with the associated protocol bump:wq + pub fn iter_stardust_packages() -> impl Iterator { + define_system_packages!([ + ( + STARDUST_PACKAGE_ID, + "stardust", + [MOVE_STDLIB_PACKAGE_ID, IOTA_FRAMEWORK_PACKAGE_ID] + ), + ( + TIMELOCK_PACKAGE_ID, + "timelock", + [ + MOVE_STDLIB_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, + IOTA_SYSTEM_PACKAGE_ID + ] + ) + ]) + .iter() + } + + pub fn iter_system_packages() -> impl Iterator { + // All system packages in the current build should be registered here, and this + // is the only place we need to worry about if any of them changes. + // TODO: Is it possible to derive dependencies from the bytecode instead of + // manually specifying them? + define_system_packages!([ + (MOVE_STDLIB_PACKAGE_ID, "move-stdlib", []), + ( + IOTA_FRAMEWORK_PACKAGE_ID, + "iota-framework", + [MOVE_STDLIB_PACKAGE_ID] + ), + ( + IOTA_SYSTEM_PACKAGE_ID, + "iota-system", + [MOVE_STDLIB_PACKAGE_ID, IOTA_FRAMEWORK_PACKAGE_ID] + ), + ( + DEEPBOOK_PACKAGE_ID, + "deepbook", + [MOVE_STDLIB_PACKAGE_ID, IOTA_FRAMEWORK_PACKAGE_ID] + ) + ]) + .iter() + } + + pub fn all_package_ids() -> Vec { + Self::iter_system_packages().map(|p| p.id).collect() + } + + pub fn get_package_by_id(id: &ObjectID) -> &'static SystemPackage { + Self::iter_system_packages().find(|s| &s.id == id).unwrap() + } + + pub fn genesis_move_packages() -> impl Iterator { + Self::iter_system_packages().map(|package| package.genesis_move_package()) + } + + pub fn genesis_objects() -> impl Iterator { + Self::iter_system_packages().map(|package| package.genesis_object()) + } +} + +pub const DEFAULT_FRAMEWORK_PATH: &str = env!("CARGO_MANIFEST_DIR"); + +pub fn legacy_test_cost() -> InternalGas { + InternalGas::new(0) +} + +/// Check whether the framework defined by `modules` is compatible with the +/// framework that is already on-chain (i.e. stored in `object_store`) at `id`. +/// +/// - Returns `None` if the current package at `id` cannot be loaded, or the +/// compatibility check fails (This is grounds not to upgrade). +/// - Panics if the object at `id` can be loaded but is not a package -- this is +/// an invariant violation. +/// - Returns the digest of the current framework (and version) if it is +/// equivalent to the new framework (indicates support for a protocol upgrade +/// without a framework upgrade). +/// - Returns the digest of the new framework (and version) if it is compatible +/// (indicates support for a protocol upgrade with a framework upgrade). +pub async fn compare_system_package( + object_store: &S, + id: &ObjectID, + modules: &[CompiledModule], + dependencies: Vec, + binary_config: &BinaryConfig, +) -> Option { + let cur_object = match object_store.get_object(id) { + Ok(Some(cur_object)) => cur_object, + + Ok(None) => { + // creating a new framework package--nothing to check + return Some( + Object::new_system_package( + modules, + // note: execution_engine assumes any system package with version + // OBJECT_START_VERSION is freshly created rather than + // upgraded + OBJECT_START_VERSION, + dependencies, + // Genesis is fine here, we only use it to calculate an object ref that we can + // use for all validators to commit to the same bytes in + // the update + TransactionDigest::genesis_marker(), + ) + .compute_object_reference(), + ); + } + + Err(e) => { + error!("Error loading framework object at {id}: {e:?}"); + return None; + } + }; + + let cur_ref = cur_object.compute_object_reference(); + let cur_pkg = cur_object + .data + .try_as_package() + .expect("Framework not package"); + + let mut new_object = Object::new_system_package( + modules, + // Start at the same version as the current package, and increment if compatibility is + // successful + cur_object.version(), + dependencies, + cur_object.previous_transaction, + ); + + if cur_ref == new_object.compute_object_reference() { + return Some(cur_ref); + } + + let compatibility = Compatibility { + check_struct_and_pub_function_linking: true, + check_struct_layout: true, + check_friend_linking: false, + // Checking `entry` linkage is required because system packages are updated in-place, and a + // transaction that was rolled back to make way for reconfiguration should still be runnable + // after a reconfiguration that upgraded the framework. + // + // A transaction that calls a system function that was previously `entry` and is now private + // will fail because its entrypoint became no longer callable. A transaction that calls a + // system function that was previously `public entry` and is now just `public` could also + // fail if one of its mutable inputs was being used in another private `entry` function. + check_private_entry_linking: true, + disallowed_new_abilities: AbilitySet::singleton(Ability::Key), + disallow_change_struct_type_params: true, + }; + + let new_pkg = new_object + .data + .try_as_package_mut() + .expect("Created as package"); + + let cur_normalized = match cur_pkg.normalize(binary_config) { + Ok(v) => v, + Err(e) => { + error!("Could not normalize existing package: {e:?}"); + return None; + } + }; + let mut new_normalized = new_pkg.normalize(binary_config).ok()?; + + for (name, cur_module) in cur_normalized { + let Some(new_module) = new_normalized.remove(&name) else { + return None; + }; + + if let Err(e) = compatibility.check(&cur_module, &new_module) { + error!("Compatibility check failed, for new version of {id}::{name}: {e:?}"); + return None; + } + } + + new_pkg.increment_version(); + Some(new_object.compute_object_reference()) +} diff --git a/crates/iota-genesis-builder/Cargo.toml b/crates/iota-genesis-builder/Cargo.toml new file mode 100644 index 00000000000..1cf1661f90b --- /dev/null +++ b/crates/iota-genesis-builder/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "iota-genesis-builder" +version = "0.0.0" +authors = ["IOTA Stiftung"] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +bcs.workspace = true +camino.workspace = true +fastcrypto.workspace = true +hex.workspace = true +move-binary-format.workspace = true +move-core-types.workspace = true +move-package.workspace = true +move-vm-runtime-v2 = { path = "../../external-crates/move/move-execution/v2/crates/move-vm-runtime" } +rand.workspace = true +rand_regex.workspace = true +regex.workspace = true +serde.workspace = true +serde_json.workspace = true +serde_with.workspace = true +serde_yaml.workspace = true +tempfile.workspace = true +thiserror.workspace = true +tracing.workspace = true +prometheus.workspace = true + +bigdecimal = "0.4.3" +fs_extra = "1.3.0" +iota-sdk = { version = "1.1.4", default-features = false, features = ["irc_27", "irc_30", "std"] } +num-rational = "0.4" +packable = { version = "0.8.3", default-features = false, features = ["io"] } +rand_pcg = "0.3.1" +rand_seeder = "0.2.3" + +schemars.workspace = true +shared-crypto.workspace = true +iota-config.workspace = true +iota-execution.workspace = true +iota-adapter-v2 = { path = "../../iota-execution/v2/iota-adapter/" } +iota-framework.workspace = true +iota-framework-snapshot.workspace = true +iota-move-build.workspace = true +iota-move-natives-v2 = { path = "../../iota-execution/v2/iota-move-natives" } +iota-protocol-config.workspace = true +iota-types.workspace = true +[target.'cfg(msim)'.dependencies] +iota-simulator.workspace = true + +[dev-dependencies] +insta.workspace = true +tempfile.workspace = true +iota-types = { workspace = true, features = ["test-utils"] } + +[[example]] +name = "parse_full_snapshot" +path = "examples/parse_full_snapshot.rs" diff --git a/crates/sui-genesis-builder/examples/build_and_compile_native_token.rs b/crates/iota-genesis-builder/examples/build_and_compile_native_token.rs similarity index 94% rename from crates/sui-genesis-builder/examples/build_and_compile_native_token.rs rename to crates/iota-genesis-builder/examples/build_and_compile_native_token.rs index 0550be01bf5..7fc7ebe87d3 100644 --- a/crates/sui-genesis-builder/examples/build_and_compile_native_token.rs +++ b/crates/iota-genesis-builder/examples/build_and_compile_native_token.rs @@ -1,8 +1,13 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! Example demonstrating building and compiling two native token packages. +use iota_genesis_builder::stardust::native_token::{ + package_builder, + package_data::{NativeTokenModuleData, NativeTokenPackageData}, +}; use iota_sdk::{ types::block::{ address::AliasAddress, @@ -10,10 +15,6 @@ use iota_sdk::{ }, Url, }; -use sui_genesis_builder::stardust::native_token::{ - package_builder, - package_data::{NativeTokenModuleData, NativeTokenPackageData}, -}; fn main() -> anyhow::Result<()> { let native_token_a = NativeTokenPackageData::new( diff --git a/crates/sui-genesis-builder/examples/parse_full_snapshot.rs b/crates/iota-genesis-builder/examples/parse_full_snapshot.rs similarity index 90% rename from crates/sui-genesis-builder/examples/parse_full_snapshot.rs rename to crates/iota-genesis-builder/examples/parse_full_snapshot.rs index 41624fa60a6..e798dddce6c 100644 --- a/crates/sui-genesis-builder/examples/parse_full_snapshot.rs +++ b/crates/iota-genesis-builder/examples/parse_full_snapshot.rs @@ -1,11 +1,12 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! Example demonstrating parsing Stardust UTXOs from a snapshot file //! and verifying the total supply. use std::fs::File; -use sui_genesis_builder::stardust::{ +use iota_genesis_builder::stardust::{ parse::FullSnapshotParser, types::snapshot::TOTAL_SUPPLY_IOTA, }; diff --git a/crates/iota-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs new file mode 100644 index 00000000000..06d915772b3 --- /dev/null +++ b/crates/iota-genesis-builder/src/lib.rs @@ -0,0 +1,1217 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{BTreeMap, HashSet}, + fs, + path::Path, + sync::Arc, +}; + +use anyhow::{bail, Context}; +use camino::Utf8Path; +use fastcrypto::{hash::HashFunction, traits::KeyPair}; +use iota_config::genesis::{ + Genesis, GenesisCeremonyParameters, GenesisChainParameters, TokenDistributionSchedule, + UnsignedGenesis, +}; +use iota_execution::{self, Executor}; +use iota_framework::{BuiltInFramework, SystemPackage}; +use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; +use iota_types::{ + base_types::{ + ExecutionDigests, IotaAddress, ObjectID, SequenceNumber, TransactionDigest, TxContext, + }, + committee::Committee, + crypto::{ + AuthorityKeyPair, AuthorityPublicKeyBytes, AuthoritySignInfo, AuthoritySignInfoTrait, + AuthoritySignature, DefaultHash, IotaAuthoritySignature, + }, + deny_list::{DENY_LIST_CREATE_FUNC, DENY_LIST_MODULE}, + digests::ChainIdentifier, + effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, + epoch_data::EpochData, + gas::IotaGasStatus, + gas_coin::GasCoin, + governance::StakedIota, + in_memory_storage::InMemoryStorage, + inner_temporary_store::InnerTemporaryStore, + iota_system_state::{get_iota_system_state, IotaSystemState, IotaSystemStateTrait}, + message_envelope::Message, + messages_checkpoint::{CertifiedCheckpointSummary, CheckpointContents, CheckpointSummary}, + metrics::LimitsMetrics, + object::{Object, Owner}, + programmable_transaction_builder::ProgrammableTransactionBuilder, + transaction::{ + CallArg, CheckedInputObjects, Command, InputObjectKind, ObjectReadResult, Transaction, + }, + IOTA_FRAMEWORK_ADDRESS, IOTA_SYSTEM_ADDRESS, +}; +use move_binary_format::CompiledModule; +use move_core_types::ident_str; +use shared_crypto::intent::{Intent, IntentMessage, IntentScope}; +use tracing::trace; +use validator_info::{GenesisValidatorInfo, GenesisValidatorMetadata, ValidatorInfo}; + +pub mod stardust; +pub mod validator_info; + +const GENESIS_BUILDER_COMMITTEE_DIR: &str = "committee"; +const GENESIS_BUILDER_PARAMETERS_FILE: &str = "parameters"; +const GENESIS_BUILDER_TOKEN_DISTRIBUTION_SCHEDULE_FILE: &str = "token-distribution-schedule"; +const GENESIS_BUILDER_SIGNATURE_DIR: &str = "signatures"; +const GENESIS_BUILDER_UNSIGNED_GENESIS_FILE: &str = "unsigned-genesis"; + +pub struct Builder { + parameters: GenesisCeremonyParameters, + token_distribution_schedule: Option, + objects: BTreeMap, + validators: BTreeMap, + // Validator signatures over checkpoint + signatures: BTreeMap, + built_genesis: Option, +} + +impl Default for Builder { + fn default() -> Self { + Self::new() + } +} + +impl Builder { + pub fn new() -> Self { + Self { + parameters: Default::default(), + token_distribution_schedule: None, + objects: Default::default(), + validators: Default::default(), + signatures: Default::default(), + built_genesis: None, + } + } + + pub fn with_parameters(mut self, parameters: GenesisCeremonyParameters) -> Self { + self.parameters = parameters; + self + } + + pub fn with_token_distribution_schedule( + mut self, + token_distribution_schedule: TokenDistributionSchedule, + ) -> Self { + self.token_distribution_schedule = Some(token_distribution_schedule); + self + } + + pub fn with_protocol_version(mut self, v: ProtocolVersion) -> Self { + self.parameters.protocol_version = v; + self + } + + pub fn add_object(mut self, object: Object) -> Self { + self.objects.insert(object.id(), object); + self + } + + pub fn add_objects(mut self, objects: Vec) -> Self { + for object in objects { + self.objects.insert(object.id(), object); + } + self + } + + pub fn add_validator( + mut self, + validator: ValidatorInfo, + proof_of_possession: AuthoritySignature, + ) -> Self { + self.validators.insert( + validator.protocol_key(), + GenesisValidatorInfo { + info: validator, + proof_of_possession, + }, + ); + self + } + + pub fn validators(&self) -> &BTreeMap { + &self.validators + } + + pub fn add_validator_signature(mut self, keypair: &AuthorityKeyPair) -> Self { + let UnsignedGenesis { checkpoint, .. } = self.build_unsigned_genesis_checkpoint(); + + let name = keypair.public().into(); + assert!( + self.validators.contains_key(&name), + "provided keypair does not correspond to a validator in the validator set" + ); + let checkpoint_signature = { + let intent_msg = IntentMessage::new( + Intent::iota_app(IntentScope::CheckpointSummary), + checkpoint.clone(), + ); + let signature = AuthoritySignature::new_secure(&intent_msg, &checkpoint.epoch, keypair); + AuthoritySignInfo { + epoch: checkpoint.epoch, + authority: name, + signature, + } + }; + + self.signatures.insert(name, checkpoint_signature); + + self + } + + pub fn unsigned_genesis_checkpoint(&self) -> Option { + self.built_genesis.clone() + } + + pub fn build_unsigned_genesis_checkpoint(&mut self) -> UnsignedGenesis { + if let Some(built_genesis) = &self.built_genesis { + return built_genesis.clone(); + } + + // Verify that all input data is valid + self.validate().unwrap(); + + let objects = self.objects.clone().into_values().collect::>(); + let validators = self.validators.clone().into_values().collect::>(); + + let token_distribution_schedule = + if let Some(token_distribution_schedule) = &self.token_distribution_schedule { + token_distribution_schedule.clone() + } else { + TokenDistributionSchedule::new_for_validators_with_default_allocation( + validators.iter().map(|v| v.info.iota_address()), + ) + }; + + self.built_genesis = Some(build_unsigned_genesis_data( + &self.parameters, + &token_distribution_schedule, + &validators, + &objects, + )); + + self.token_distribution_schedule = Some(token_distribution_schedule); + + self.built_genesis.clone().unwrap() + } + + fn committee(objects: &[Object]) -> Committee { + let iota_system_object = + get_iota_system_state(&objects).expect("Iota System State object must always exist"); + iota_system_object.get_current_epoch_committee().committee + } + + pub fn protocol_version(&self) -> ProtocolVersion { + self.parameters.protocol_version + } + + pub fn build(mut self) -> Genesis { + let UnsignedGenesis { + checkpoint, + checkpoint_contents, + transaction, + effects, + events, + objects, + } = self.build_unsigned_genesis_checkpoint(); + + let committee = Self::committee(&objects); + + let checkpoint = { + let signatures = self.signatures.clone().into_values().collect(); + + CertifiedCheckpointSummary::new(checkpoint, signatures, &committee).unwrap() + }; + + let genesis = Genesis::new( + checkpoint, + checkpoint_contents, + transaction, + effects, + events, + objects, + ); + + // Verify that all on-chain state was properly created + self.validate().unwrap(); + + genesis + } + + /// Validates the entire state of the build, no matter what the internal + /// state is (input collection phase or output phase) + pub fn validate(&self) -> anyhow::Result<(), anyhow::Error> { + self.validate_inputs()?; + self.validate_output(); + Ok(()) + } + + /// Runs through validation checks on the input values present in the + /// builder + fn validate_inputs(&self) -> anyhow::Result<(), anyhow::Error> { + if !self.parameters.allow_insertion_of_extra_objects && !self.objects.is_empty() { + bail!("extra objects are disallowed"); + } + + for validator in self.validators.values() { + validator.validate().with_context(|| { + format!( + "metadata for validator {} is invalid", + validator.info.name() + ) + })?; + } + + if let Some(token_distribution_schedule) = &self.token_distribution_schedule { + token_distribution_schedule.validate(); + token_distribution_schedule.check_all_stake_operations_are_for_valid_validators( + self.validators.values().map(|v| v.info.iota_address()), + ); + } + + Ok(()) + } + + /// Runs through validation checks on the generated output (the initial + /// chain state) based on the input values present in the builder + fn validate_output(&self) { + // If genesis hasn't been built yet, just early return as there is nothing to + // validate yet + let Some(unsigned_genesis) = self.unsigned_genesis_checkpoint() else { + return; + }; + + let GenesisChainParameters { + protocol_version, + chain_start_timestamp_ms, + epoch_duration_ms, + stake_subsidy_start_epoch, + stake_subsidy_initial_distribution_amount, + stake_subsidy_period_length, + stake_subsidy_decrease_rate, + max_validator_count, + min_validator_joining_stake, + validator_low_stake_threshold, + validator_very_low_stake_threshold, + validator_low_stake_grace_period, + } = self.parameters.to_genesis_chain_parameters(); + + // In non-testing code, genesis type must always be V1. + let system_state = match unsigned_genesis.iota_system_object() { + IotaSystemState::V1(inner) => inner, + IotaSystemState::V2(_) => unreachable!(), + #[cfg(msim)] + _ => { + // Types other than V1 used in simtests do not need to be validated. + return; + } + }; + + let protocol_config = get_genesis_protocol_config(ProtocolVersion::new(protocol_version)); + + if protocol_config.create_authenticator_state_in_genesis() { + let authenticator_state = unsigned_genesis.authenticator_state_object().unwrap(); + assert!(authenticator_state.active_jwks.is_empty()); + } else { + assert!(unsigned_genesis.authenticator_state_object().is_none()); + } + assert_eq!( + protocol_config.random_beacon(), + unsigned_genesis.has_randomness_state_object() + ); + + assert_eq!( + protocol_config.enable_coin_deny_list(), + unsigned_genesis.coin_deny_list_state().is_some(), + ); + + assert_eq!( + self.validators.len(), + system_state.validators.active_validators.len() + ); + let mut address_to_pool_id = BTreeMap::new(); + for (validator, onchain_validator) in self + .validators + .values() + .zip(system_state.validators.active_validators.iter()) + { + let metadata = onchain_validator.verified_metadata(); + + // Validators should not have duplicate addresses so the result of insertion + // should be None. + assert!( + address_to_pool_id + .insert(metadata.iota_address, onchain_validator.staking_pool.id) + .is_none() + ); + assert_eq!(validator.info.iota_address(), metadata.iota_address); + assert_eq!(validator.info.protocol_key(), metadata.iota_pubkey_bytes()); + assert_eq!(validator.info.network_key, metadata.network_pubkey); + assert_eq!(validator.info.worker_key, metadata.worker_pubkey); + assert_eq!( + validator.proof_of_possession.as_ref().to_vec(), + metadata.proof_of_possession_bytes + ); + assert_eq!(validator.info.name(), &metadata.name); + assert_eq!(validator.info.description, metadata.description); + assert_eq!(validator.info.image_url, metadata.image_url); + assert_eq!(validator.info.project_url, metadata.project_url); + assert_eq!(validator.info.network_address(), &metadata.net_address); + assert_eq!(validator.info.p2p_address, metadata.p2p_address); + assert_eq!( + validator.info.narwhal_primary_address, + metadata.primary_address + ); + assert_eq!( + validator.info.narwhal_worker_address, + metadata.worker_address + ); + + assert_eq!(validator.info.gas_price, onchain_validator.gas_price); + assert_eq!( + validator.info.commission_rate, + onchain_validator.commission_rate + ); + } + + assert_eq!(system_state.epoch, 0); + assert_eq!(system_state.protocol_version, protocol_version); + assert_eq!(system_state.storage_fund.non_refundable_balance.value(), 0); + assert_eq!( + system_state + .storage_fund + .total_object_storage_rebates + .value(), + 0 + ); + + assert_eq!(system_state.parameters.epoch_duration_ms, epoch_duration_ms); + assert_eq!( + system_state.parameters.stake_subsidy_start_epoch, + stake_subsidy_start_epoch, + ); + assert_eq!( + system_state.parameters.max_validator_count, + max_validator_count, + ); + assert_eq!( + system_state.parameters.min_validator_joining_stake, + min_validator_joining_stake, + ); + assert_eq!( + system_state.parameters.validator_low_stake_threshold, + validator_low_stake_threshold, + ); + assert_eq!( + system_state.parameters.validator_very_low_stake_threshold, + validator_very_low_stake_threshold, + ); + assert_eq!( + system_state.parameters.validator_low_stake_grace_period, + validator_low_stake_grace_period, + ); + + assert_eq!(system_state.stake_subsidy.distribution_counter, 0); + assert_eq!( + system_state.stake_subsidy.current_distribution_amount, + stake_subsidy_initial_distribution_amount, + ); + assert_eq!( + system_state.stake_subsidy.stake_subsidy_period_length, + stake_subsidy_period_length, + ); + assert_eq!( + system_state.stake_subsidy.stake_subsidy_decrease_rate, + stake_subsidy_decrease_rate, + ); + + assert!(!system_state.safe_mode); + assert_eq!( + system_state.epoch_start_timestamp_ms, + chain_start_timestamp_ms, + ); + assert_eq!(system_state.validators.pending_removals.len(), 0); + assert_eq!( + system_state + .validators + .pending_active_validators + .contents + .size, + 0 + ); + assert_eq!(system_state.validators.inactive_validators.size, 0); + assert_eq!(system_state.validators.validator_candidates.size, 0); + + // Check distribution is correct + let token_distribution_schedule = self.token_distribution_schedule.clone().unwrap(); + assert_eq!( + system_state.stake_subsidy.balance.value(), + token_distribution_schedule.stake_subsidy_fund_micros + ); + + let mut gas_objects: BTreeMap = unsigned_genesis + .objects() + .iter() + .filter_map(|o| GasCoin::try_from(o).ok().map(|g| (o.id(), (o, g)))) + .collect(); + let mut staked_iota_objects: BTreeMap = unsigned_genesis + .objects() + .iter() + .filter_map(|o| StakedIota::try_from(o).ok().map(|s| (o.id(), (o, s)))) + .collect(); + + for allocation in token_distribution_schedule.allocations { + if let Some(staked_with_validator) = allocation.staked_with_validator { + let staking_pool_id = *address_to_pool_id + .get(&staked_with_validator) + .expect("staking pool should exist"); + let staked_iota_object_id = staked_iota_objects + .iter() + .find(|(_k, (o, s))| { + let Owner::AddressOwner(owner) = &o.owner else { + panic!("gas object owner must be address owner"); + }; + *owner == allocation.recipient_address + && s.principal() == allocation.amount_micros + && s.pool_id() == staking_pool_id + }) + .map(|(k, _)| *k) + .expect("all allocations should be present"); + let staked_iota_object = + staked_iota_objects.remove(&staked_iota_object_id).unwrap(); + assert_eq!( + staked_iota_object.0.owner, + Owner::AddressOwner(allocation.recipient_address) + ); + assert_eq!(staked_iota_object.1.principal(), allocation.amount_micros); + assert_eq!(staked_iota_object.1.pool_id(), staking_pool_id); + assert_eq!(staked_iota_object.1.activation_epoch(), 0); + } else { + let gas_object_id = gas_objects + .iter() + .find(|(_k, (o, g))| { + if let Owner::AddressOwner(owner) = &o.owner { + *owner == allocation.recipient_address + && g.value() == allocation.amount_micros + } else { + false + } + }) + .map(|(k, _)| *k) + .expect("all allocations should be present"); + let gas_object = gas_objects.remove(&gas_object_id).unwrap(); + assert_eq!( + gas_object.0.owner, + Owner::AddressOwner(allocation.recipient_address) + ); + assert_eq!(gas_object.1.value(), allocation.amount_micros,); + } + } + + // All Gas and staked objects should be accounted for + if !self.parameters.allow_insertion_of_extra_objects { + assert!(gas_objects.is_empty()); + assert!(staked_iota_objects.is_empty()); + } + + let committee = system_state.get_current_epoch_committee().committee; + for signature in self.signatures.values() { + if self.validators.get(&signature.authority).is_none() { + panic!("found signature for unknown validator: {:#?}", signature); + } + + signature + .verify_secure( + unsigned_genesis.checkpoint(), + Intent::iota_app(IntentScope::CheckpointSummary), + &committee, + ) + .expect("signature should be valid"); + } + } + + pub fn load>(path: P) -> anyhow::Result { + let path = path.as_ref(); + let path: &Utf8Path = path.try_into()?; + trace!("Reading Genesis Builder from {}", path); + + if !path.is_dir() { + bail!("path must be a directory"); + } + + // Load parameters + let parameters_file = path.join(GENESIS_BUILDER_PARAMETERS_FILE); + let parameters = serde_yaml::from_slice( + &fs::read(parameters_file).context("unable to read genesis parameters file")?, + ) + .context("unable to deserialize genesis parameters")?; + + let token_distribution_schedule_file = + path.join(GENESIS_BUILDER_TOKEN_DISTRIBUTION_SCHEDULE_FILE); + let token_distribution_schedule = if token_distribution_schedule_file.exists() { + Some(TokenDistributionSchedule::from_csv(fs::File::open( + token_distribution_schedule_file, + )?)?) + } else { + None + }; + + // Load validator infos + let mut committee = BTreeMap::new(); + for entry in path.join(GENESIS_BUILDER_COMMITTEE_DIR).read_dir_utf8()? { + let entry = entry?; + if entry.file_name().starts_with('.') { + continue; + } + + let path = entry.path(); + let validator_info_bytes = fs::read(path)?; + let validator_info: GenesisValidatorInfo = + serde_yaml::from_slice(&validator_info_bytes) + .with_context(|| format!("unable to load validator info for {path}"))?; + committee.insert(validator_info.info.protocol_key(), validator_info); + } + + // Load Signatures + let mut signatures = BTreeMap::new(); + for entry in path.join(GENESIS_BUILDER_SIGNATURE_DIR).read_dir_utf8()? { + let entry = entry?; + if entry.file_name().starts_with('.') { + continue; + } + + let path = entry.path(); + let signature_bytes = fs::read(path)?; + let sigs: AuthoritySignInfo = bcs::from_bytes(&signature_bytes) + .with_context(|| format!("unable to load validator signatrue for {path}"))?; + signatures.insert(sigs.authority, sigs); + } + + let mut builder = Self { + parameters, + token_distribution_schedule, + objects: Default::default(), + validators: committee, + signatures, + built_genesis: None, // Leave this as none, will build and compare below + }; + + let unsigned_genesis_file = path.join(GENESIS_BUILDER_UNSIGNED_GENESIS_FILE); + if unsigned_genesis_file.exists() { + let unsigned_genesis_bytes = fs::read(unsigned_genesis_file)?; + let loaded_genesis: UnsignedGenesis = bcs::from_bytes(&unsigned_genesis_bytes)?; + + // If we have a built genesis, then we must have a token_distribution_schedule + // present as well. + assert!( + builder.token_distribution_schedule.is_some(), + "If a built genesis is present, then there must also be a token-distribution-schedule present" + ); + + // Verify loaded genesis matches one build from the constituent parts + let built = builder.build_unsigned_genesis_checkpoint(); + loaded_genesis.checkpoint_contents.digest(); // cache digest before compare + assert_eq!( + built, loaded_genesis, + "loaded genesis does not match built genesis" + ); + + // Just to double check that its set after building above + assert!(builder.unsigned_genesis_checkpoint().is_some()); + } + + Ok(builder) + } + + pub fn save>(self, path: P) -> anyhow::Result<(), anyhow::Error> { + let path = path.as_ref(); + trace!("Writing Genesis Builder to {}", path.display()); + + fs::create_dir_all(path)?; + + // Write parameters + let parameters_file = path.join(GENESIS_BUILDER_PARAMETERS_FILE); + fs::write(parameters_file, serde_yaml::to_string(&self.parameters)?)?; + + if let Some(token_distribution_schedule) = &self.token_distribution_schedule { + token_distribution_schedule.to_csv(fs::File::create( + path.join(GENESIS_BUILDER_TOKEN_DISTRIBUTION_SCHEDULE_FILE), + )?)?; + } + + // Write Signatures + let signature_dir = path.join(GENESIS_BUILDER_SIGNATURE_DIR); + std::fs::create_dir_all(&signature_dir)?; + for (pubkey, sigs) in self.signatures { + let sig_bytes = bcs::to_bytes(&sigs)?; + let name = self.validators.get(&pubkey).unwrap().info.name(); + fs::write(signature_dir.join(name), sig_bytes)?; + } + + // Write validator infos + let committee_dir = path.join(GENESIS_BUILDER_COMMITTEE_DIR); + fs::create_dir_all(&committee_dir)?; + + for (_pubkey, validator) in self.validators { + let validator_info_bytes = serde_yaml::to_string(&validator)?; + fs::write( + committee_dir.join(validator.info.name()), + validator_info_bytes, + )?; + } + + if let Some(genesis) = &self.built_genesis { + let genesis_bytes = bcs::to_bytes(&genesis)?; + fs::write( + path.join(GENESIS_BUILDER_UNSIGNED_GENESIS_FILE), + genesis_bytes, + )?; + } + + Ok(()) + } +} + +// Create a Genesis Txn Context to be used when generating genesis objects by +// hashing all of the inputs into genesis ans using that as our "Txn Digest". +// This is done to ensure that coin objects created between chains are unique +fn create_genesis_context( + epoch_data: &EpochData, + genesis_chain_parameters: &GenesisChainParameters, + genesis_validators: &[GenesisValidatorMetadata], + token_distribution_schedule: &TokenDistributionSchedule, + system_packages: &[SystemPackage], +) -> TxContext { + let mut hasher = DefaultHash::default(); + hasher.update(b"iota-genesis"); + hasher.update(&bcs::to_bytes(genesis_chain_parameters).unwrap()); + hasher.update(&bcs::to_bytes(genesis_validators).unwrap()); + hasher.update(&bcs::to_bytes(token_distribution_schedule).unwrap()); + for system_package in system_packages { + hasher.update(&bcs::to_bytes(system_package.bytes()).unwrap()); + } + + let hash = hasher.finalize(); + let genesis_transaction_digest = TransactionDigest::new(hash.into()); + + TxContext::new( + &IotaAddress::default(), + &genesis_transaction_digest, + epoch_data, + ) +} + +fn get_genesis_protocol_config(version: ProtocolVersion) -> ProtocolConfig { + // We have a circular dependency here. Protocol config depends on chain ID, + // which depends on genesis checkpoint (digest), which depends on genesis + // transaction, which depends on protocol config. + // + // ChainIdentifier::default().chain() which can be overridden by the + // IOTA_PROTOCOL_CONFIG_CHAIN_OVERRIDE if necessary + ProtocolConfig::get_for_version(version, ChainIdentifier::default().chain()) +} + +fn build_unsigned_genesis_data( + parameters: &GenesisCeremonyParameters, + token_distribution_schedule: &TokenDistributionSchedule, + validators: &[GenesisValidatorInfo], + objects: &[Object], +) -> UnsignedGenesis { + if !parameters.allow_insertion_of_extra_objects && !objects.is_empty() { + panic!( + "insertion of extra objects at genesis time is prohibited due to 'allow_insertion_of_extra_objects' parameter" + ); + } + + let genesis_chain_parameters = parameters.to_genesis_chain_parameters(); + let genesis_validators = validators + .iter() + .cloned() + .map(GenesisValidatorMetadata::from) + .collect::>(); + + token_distribution_schedule.validate(); + token_distribution_schedule.check_all_stake_operations_are_for_valid_validators( + genesis_validators.iter().map(|v| v.iota_address), + ); + + let epoch_data = EpochData::new_genesis(genesis_chain_parameters.chain_start_timestamp_ms); + + // Get the correct system packages for our protocol version. If we cannot find + // the snapshot that means that we must be at the latest version and we + // should use the latest version of the framework. + let system_packages = + iota_framework_snapshot::load_bytecode_snapshot(parameters.protocol_version.as_u64()) + .unwrap_or_else(|_| BuiltInFramework::iter_system_packages().cloned().collect()); + + let mut genesis_ctx = create_genesis_context( + &epoch_data, + &genesis_chain_parameters, + &genesis_validators, + token_distribution_schedule, + &system_packages, + ); + + // Use a throwaway metrics registry for genesis transaction execution. + let registry = prometheus::Registry::new(); + let metrics = Arc::new(LimitsMetrics::new(®istry)); + + let objects = create_genesis_objects( + &mut genesis_ctx, + objects, + &genesis_validators, + &genesis_chain_parameters, + token_distribution_schedule, + system_packages, + metrics.clone(), + ); + + let protocol_config = get_genesis_protocol_config(parameters.protocol_version); + + let (genesis_transaction, genesis_effects, genesis_events, objects) = + create_genesis_transaction(objects, &protocol_config, metrics, &epoch_data); + let (checkpoint, checkpoint_contents) = + create_genesis_checkpoint(parameters, &genesis_transaction, &genesis_effects); + + UnsignedGenesis { + checkpoint, + checkpoint_contents, + transaction: genesis_transaction, + effects: genesis_effects, + events: genesis_events, + objects, + } +} + +fn create_genesis_checkpoint( + parameters: &GenesisCeremonyParameters, + transaction: &Transaction, + effects: &TransactionEffects, +) -> (CheckpointSummary, CheckpointContents) { + let execution_digests = ExecutionDigests { + transaction: *transaction.digest(), + effects: effects.digest(), + }; + let contents = + CheckpointContents::new_with_digests_and_signatures([execution_digests], vec![vec![]]); + let checkpoint = CheckpointSummary { + epoch: 0, + sequence_number: 0, + network_total_transactions: contents.size().try_into().unwrap(), + content_digest: *contents.digest(), + previous_digest: None, + epoch_rolling_gas_cost_summary: Default::default(), + end_of_epoch_data: None, + timestamp_ms: parameters.chain_start_timestamp_ms, + version_specific_data: Vec::new(), + checkpoint_commitments: Default::default(), + }; + + (checkpoint, contents) +} + +fn create_genesis_transaction( + objects: Vec, + protocol_config: &ProtocolConfig, + metrics: Arc, + epoch_data: &EpochData, +) -> ( + Transaction, + TransactionEffects, + TransactionEvents, + Vec, +) { + let genesis_transaction = { + let genesis_objects = objects + .into_iter() + .map(|mut object| { + if let Some(o) = object.data.try_as_move_mut() { + o.decrement_version_to(SequenceNumber::MIN); + } + + if let Owner::Shared { + initial_shared_version, + } = &mut object.owner + { + *initial_shared_version = SequenceNumber::MIN; + } + + let object = object.into_inner(); + iota_types::transaction::GenesisObject::RawObject { + data: object.data, + owner: object.owner, + } + }) + .collect(); + + iota_types::transaction::VerifiedTransaction::new_genesis_transaction(genesis_objects) + .into_inner() + }; + + let genesis_digest = *genesis_transaction.digest(); + // execute txn to effects + let (effects, events, objects) = { + let silent = true; + + let executor = iota_execution::executor(protocol_config, silent, None) + .expect("Creating an executor should not fail here"); + + let expensive_checks = false; + let certificate_deny_set = HashSet::new(); + let transaction_data = &genesis_transaction.data().intent_message().value; + let (kind, signer, _) = transaction_data.execution_parts(); + let input_objects = CheckedInputObjects::new_for_genesis(vec![]); + let (inner_temp_store, _, effects, _execution_error) = executor + .execute_transaction_to_effects( + &InMemoryStorage::new(Vec::new()), + protocol_config, + metrics, + expensive_checks, + &certificate_deny_set, + &epoch_data.epoch_id(), + epoch_data.epoch_start_timestamp(), + input_objects, + vec![], + IotaGasStatus::new_unmetered(), + kind, + signer, + genesis_digest, + ); + assert!(inner_temp_store.input_objects.is_empty()); + assert!(inner_temp_store.mutable_inputs.is_empty()); + assert!(effects.mutated().is_empty()); + assert!(effects.unwrapped().is_empty()); + assert!(effects.deleted().is_empty()); + assert!(effects.wrapped().is_empty()); + assert!(effects.unwrapped_then_deleted().is_empty()); + + let objects = inner_temp_store.written.into_values().collect(); + (effects, inner_temp_store.events, objects) + }; + + (genesis_transaction, effects, events, objects) +} + +fn create_genesis_objects( + genesis_ctx: &mut TxContext, + input_objects: &[Object], + validators: &[GenesisValidatorMetadata], + parameters: &GenesisChainParameters, + token_distribution_schedule: &TokenDistributionSchedule, + system_packages: Vec, + metrics: Arc, +) -> Vec { + let mut store = InMemoryStorage::new(Vec::new()); + // We don't know the chain ID here since we haven't yet created the genesis + // checkpoint. However since we know there are no chain specific protool + // config options in genesis, we use Chain::Unknown here. + let protocol_config = ProtocolConfig::get_for_version( + ProtocolVersion::new(parameters.protocol_version), + Chain::Unknown, + ); + + let silent = true; + let executor = iota_execution::executor(&protocol_config, silent, None) + .expect("Creating an executor should not fail here"); + + for system_package in system_packages.into_iter() { + process_package( + &mut store, + executor.as_ref(), + genesis_ctx, + &system_package.modules(), + system_package.dependencies().to_vec(), + &protocol_config, + metrics.clone(), + ) + .unwrap(); + } + + { + for object in input_objects { + store.insert_object(object.to_owned()); + } + } + + generate_genesis_system_object( + &mut store, + executor.as_ref(), + validators, + genesis_ctx, + parameters, + token_distribution_schedule, + metrics, + ) + .unwrap(); + + store.into_inner().into_values().collect() +} + +pub(crate) fn process_package( + store: &mut InMemoryStorage, + executor: &dyn Executor, + ctx: &mut TxContext, + modules: &[CompiledModule], + dependencies: Vec, + protocol_config: &ProtocolConfig, + metrics: Arc, +) -> anyhow::Result<()> { + let dependency_objects = store.get_objects(&dependencies); + // When publishing genesis packages, since the std framework packages all have + // non-zero addresses, [`Transaction::input_objects_in_compiled_modules`] will + // consider them as dependencies even though they are not. Hence + // input_objects contain objects that don't exist on-chain because they are + // yet to be published. + #[cfg(debug_assertions)] + { + use move_core_types::account_address::AccountAddress; + let to_be_published_addresses: HashSet<_> = modules + .iter() + .map(|module| *module.self_id().address()) + .collect(); + assert!( + // An object either exists on-chain, or is one of the packages to be published. + dependencies + .iter() + .zip(dependency_objects.iter()) + .all(|(dependency, obj_opt)| obj_opt.is_some() + || to_be_published_addresses.contains(&AccountAddress::from(*dependency))) + ); + } + let loaded_dependencies: Vec<_> = dependencies + .iter() + .zip(dependency_objects) + .filter_map(|(dependency, object)| { + Some(ObjectReadResult::new( + InputObjectKind::MovePackage(*dependency), + object?.clone().into(), + )) + }) + .collect(); + + let module_bytes = modules + .iter() + .map(|m| { + let mut buf = vec![]; + m.serialize(&mut buf).unwrap(); + buf + }) + .collect(); + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + // executing in Genesis mode does not create an `UpgradeCap`. + builder.command(Command::Publish(module_bytes, dependencies)); + builder.finish() + }; + let InnerTemporaryStore { written, .. } = executor.update_genesis_state( + &*store, + protocol_config, + metrics, + ctx, + CheckedInputObjects::new_for_genesis(loaded_dependencies), + pt, + )?; + + store.finish(written); + + Ok(()) +} + +pub fn generate_genesis_system_object( + store: &mut InMemoryStorage, + executor: &dyn Executor, + genesis_validators: &[GenesisValidatorMetadata], + genesis_ctx: &mut TxContext, + genesis_chain_parameters: &GenesisChainParameters, + token_distribution_schedule: &TokenDistributionSchedule, + metrics: Arc, +) -> anyhow::Result<()> { + let protocol_config = ProtocolConfig::get_for_version( + ProtocolVersion::new(genesis_chain_parameters.protocol_version), + ChainIdentifier::default().chain(), + ); + + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + // Step 1: Create the IotaSystemState UID + let iota_system_state_uid = builder.programmable_move_call( + IOTA_FRAMEWORK_ADDRESS.into(), + ident_str!("object").to_owned(), + ident_str!("iota_system_state").to_owned(), + vec![], + vec![], + ); + + // Step 2: Create and share the Clock. + builder.move_call( + IOTA_FRAMEWORK_ADDRESS.into(), + ident_str!("clock").to_owned(), + ident_str!("create").to_owned(), + vec![], + vec![], + )?; + + // Step 3: Create ProtocolConfig-controlled system objects, unless disabled + // (which only happens in tests). + if protocol_config.create_authenticator_state_in_genesis() { + builder.move_call( + IOTA_FRAMEWORK_ADDRESS.into(), + ident_str!("authenticator_state").to_owned(), + ident_str!("create").to_owned(), + vec![], + vec![], + )?; + } + if protocol_config.random_beacon() { + builder.move_call( + IOTA_FRAMEWORK_ADDRESS.into(), + ident_str!("random").to_owned(), + ident_str!("create").to_owned(), + vec![], + vec![], + )?; + } + if protocol_config.enable_coin_deny_list() { + builder.move_call( + IOTA_FRAMEWORK_ADDRESS.into(), + DENY_LIST_MODULE.to_owned(), + DENY_LIST_CREATE_FUNC.to_owned(), + vec![], + vec![], + )?; + } + + // Step 4: Mint the supply of IOTA. + let iota_supply = builder.programmable_move_call( + IOTA_FRAMEWORK_ADDRESS.into(), + ident_str!("iota").to_owned(), + ident_str!("new").to_owned(), + vec![], + vec![], + ); + + // Step 5: Run genesis. + // The first argument is the system state uid we got from step 1 and the second + // one is the IOTA supply we got from step 3. + let mut arguments = vec![iota_system_state_uid, iota_supply]; + let mut call_arg_arguments = vec![ + CallArg::Pure(bcs::to_bytes(&genesis_chain_parameters).unwrap()), + CallArg::Pure(bcs::to_bytes(&genesis_validators).unwrap()), + CallArg::Pure(bcs::to_bytes(&token_distribution_schedule).unwrap()), + ] + .into_iter() + .map(|a| builder.input(a)) + .collect::>()?; + arguments.append(&mut call_arg_arguments); + builder.programmable_move_call( + IOTA_SYSTEM_ADDRESS.into(), + ident_str!("genesis").to_owned(), + ident_str!("create").to_owned(), + vec![], + arguments, + ); + builder.finish() + }; + + let InnerTemporaryStore { mut written, .. } = executor.update_genesis_state( + &*store, + &protocol_config, + metrics, + genesis_ctx, + CheckedInputObjects::new_for_genesis(vec![]), + pt, + )?; + + // update the value of the clock to match the chain start time + { + let object = written.get_mut(&iota_types::IOTA_CLOCK_OBJECT_ID).unwrap(); + object + .data + .try_as_move_mut() + .unwrap() + .set_clock_timestamp_ms_unsafe(genesis_chain_parameters.chain_start_timestamp_ms); + } + + store.finish(written); + + Ok(()) +} + +#[cfg(test)] +mod test { + use fastcrypto::traits::KeyPair; + use iota_config::{ + genesis::*, + local_ip_utils, + node::{DEFAULT_COMMISSION_RATE, DEFAULT_VALIDATOR_GAS_PRICE}, + }; + use iota_types::{ + base_types::IotaAddress, + crypto::{ + generate_proof_of_possession, get_key_pair_from_rng, AccountKeyPair, AuthorityKeyPair, + NetworkKeyPair, + }, + }; + + use crate::{validator_info::ValidatorInfo, Builder}; + + #[test] + fn allocation_csv() { + let schedule = TokenDistributionSchedule::new_for_validators_with_default_allocation([ + IotaAddress::random_for_testing_only(), + IotaAddress::random_for_testing_only(), + ]); + let mut output = Vec::new(); + + schedule.to_csv(&mut output).unwrap(); + + let parsed_schedule = TokenDistributionSchedule::from_csv(output.as_slice()).unwrap(); + + assert_eq!(schedule, parsed_schedule); + + std::io::Write::write_all(&mut std::io::stdout(), &output).unwrap(); + } + + #[test] + #[cfg_attr(msim, ignore)] + fn ceremony() { + let dir = tempfile::TempDir::new().unwrap(); + + let key: AuthorityKeyPair = get_key_pair_from_rng(&mut rand::rngs::OsRng).1; + let worker_key: NetworkKeyPair = get_key_pair_from_rng(&mut rand::rngs::OsRng).1; + let account_key: AccountKeyPair = get_key_pair_from_rng(&mut rand::rngs::OsRng).1; + let network_key: NetworkKeyPair = get_key_pair_from_rng(&mut rand::rngs::OsRng).1; + let validator = ValidatorInfo { + name: "0".into(), + protocol_key: key.public().into(), + worker_key: worker_key.public().clone(), + account_address: IotaAddress::from(account_key.public()), + network_key: network_key.public().clone(), + gas_price: DEFAULT_VALIDATOR_GAS_PRICE, + commission_rate: DEFAULT_COMMISSION_RATE, + network_address: local_ip_utils::new_local_tcp_address_for_testing(), + p2p_address: local_ip_utils::new_local_udp_address_for_testing(), + narwhal_primary_address: local_ip_utils::new_local_udp_address_for_testing(), + narwhal_worker_address: local_ip_utils::new_local_udp_address_for_testing(), + description: String::new(), + image_url: String::new(), + project_url: String::new(), + }; + let pop = generate_proof_of_possession(&key, account_key.public().into()); + let mut builder = Builder::new().add_validator(validator, pop); + + let genesis = builder.build_unsigned_genesis_checkpoint(); + for object in genesis.objects() { + println!("ObjectID: {} Type: {:?}", object.id(), object.type_()); + } + builder.save(dir.path()).unwrap(); + Builder::load(dir.path()).unwrap(); + } +} diff --git a/crates/iota-genesis-builder/src/stardust/error.rs b/crates/iota-genesis-builder/src/stardust/error.rs new file mode 100644 index 00000000000..1cbe886f8c1 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/error.rs @@ -0,0 +1,45 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! Error types pertaining to deserializing Stardust snapshots +use std::convert::Infallible; + +use iota_sdk::types::block::output::FoundryId; +use packable::error::UnknownTagError; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum StardustError { + #[error("unsupported snapshot version: expected {0}, got {1}")] + UnsupportedSnapshotVersion(u8, u8), + #[error("invalid snapshot kind: {0}")] + InvalidSnapshotKind(u8), + #[error("block error: {0}")] + BlockError(#[from] iota_sdk::types::block::Error), + #[error("{0}")] + UnknownTag(#[from] UnknownTagError), + #[error( + "cannot convert `FoundryOutput` with `FoundryId` {foundry_id} to `NativeTokenPackageData`: {err}" + )] + FoundryConversionError { + foundry_id: FoundryId, + err: anyhow::Error, + }, + #[error("framework packages path not found")] + FrameworkPackagesPathNotFound, + #[error( + "failed to derive valid move identifier from symbol `{symbol}`, invalid identifier: `{identifier}`" + )] + InvalidMoveIdentifierDerived { symbol: String, identifier: String }, + #[error("melting tokens must not be greater than minted tokens")] + MeltingTokensMustNotBeGreaterThanMintedTokens, + #[error("circulating supply must not be greater than maximum supply")] + CirculatingSupplyMustNotBeGreaterThanMaximumSupply, +} + +impl From for StardustError { + fn from(_: Infallible) -> Self { + unreachable!() + } +} diff --git a/crates/iota-genesis-builder/src/stardust/migration/executor.rs b/crates/iota-genesis-builder/src/stardust/migration/executor.rs new file mode 100644 index 00000000000..0722dbc3b31 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/migration/executor.rs @@ -0,0 +1,812 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{BTreeSet, HashMap}, + sync::Arc, +}; + +use anyhow::Result; +use iota_adapter_v2::{ + adapter::new_move_vm, gas_charger::GasCharger, programmable_transactions, + temporary_store::TemporaryStore, +}; +use iota_framework::BuiltInFramework; +use iota_move_build::CompiledPackage; +use iota_move_natives_v2::all_natives; +use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; +use iota_sdk::types::block::output::{ + AliasOutput, BasicOutput, FoundryOutput, NativeTokens, NftOutput, OutputId, TokenId, +}; +use iota_types::{ + balance::Balance, + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber, TxContext}, + collection_types::Bag, + dynamic_field::Field, + execution_mode, + id::UID, + in_memory_storage::InMemoryStorage, + inner_temporary_store::InnerTemporaryStore, + metrics::LimitsMetrics, + move_package::{MovePackage, TypeOrigin, UpgradeCap}, + object::Object, + programmable_transaction_builder::ProgrammableTransactionBuilder, + transaction::{ + Argument, CheckedInputObjects, Command, InputObjectKind, InputObjects, ObjectArg, + ObjectReadResult, ProgrammableTransaction, + }, + TypeTag, IOTA_FRAMEWORK_PACKAGE_ID, STARDUST_ADDRESS, STARDUST_PACKAGE_ID, +}; +use move_core_types::{ident_str, language_storage::StructTag}; +use move_vm_runtime_v2::move_vm::MoveVM; + +use crate::{ + process_package, + stardust::{ + migration::{ + create_migration_context, package_module_bytes, + verification::created_objects::CreatedObjects, PACKAGE_DEPS, + }, + types::{ + foundry::create_foundry_gas_coin, snapshot::OutputHeader, stardust_to_iota_address, + stardust_to_iota_address_owner, timelock, token_scheme::SimpleTokenSchemeU64, Nft, + }, + }, +}; + +/// Creates the objects that map to the stardust UTXO ledger. +/// +/// Internally uses an unmetered Move VM. +pub(super) struct Executor { + protocol_config: ProtocolConfig, + tx_context: TxContext, + /// Stores all the migration objects. + store: InMemoryStorage, + /// Caches the system packages and init objects. Useful for evicting + /// them from the store before creating the snapshot. + system_packages_and_objects: BTreeSet, + move_vm: Arc, + metrics: Arc, + /// Map the stardust token id [`TokenId`] to the on-chain info of the + /// published foundry objects. + native_tokens: HashMap, +} + +impl Executor { + /// Setup the execution environment backed by an in-memory store that holds + /// all the system packages. + pub(super) fn new(protocol_version: ProtocolVersion) -> Result { + let mut tx_context = create_migration_context(); + // Use a throwaway metrics registry for transaction execution. + let metrics = Arc::new(LimitsMetrics::new(&prometheus::Registry::new())); + let mut store = InMemoryStorage::new(Vec::new()); + // We don't know the chain ID here since we haven't yet created the genesis + // checkpoint. However since we know there are no chain specific + // protocol config options in genesis, we use Chain::Unknown here. + let protocol_config = ProtocolConfig::get_for_version(protocol_version, Chain::Unknown); + // Get the correct system packages for our protocol version. If we cannot find + // the snapshot that means that we must be at the latest version and we + // should use the latest version of the framework. + let mut system_packages = + iota_framework_snapshot::load_bytecode_snapshot(protocol_version.as_u64()) + .unwrap_or_else(|_| BuiltInFramework::iter_system_packages().cloned().collect()); + // TODO: Remove when we have bumped the protocol to include the stardust + // packages into the system packages. + // + // See also: https://github.com/iotaledger/kinesis/pull/149 + system_packages.extend(BuiltInFramework::iter_stardust_packages().cloned()); + + let silent = true; + let executor = iota_execution::executor(&protocol_config, silent, None) + .expect("Creating an executor should not fail here"); + for system_package in system_packages.into_iter() { + process_package( + &mut store, + executor.as_ref(), + &mut tx_context, + &system_package.modules(), + system_package.dependencies().to_vec(), + &protocol_config, + metrics.clone(), + )?; + } + let move_vm = Arc::new(new_move_vm(all_natives(silent), &protocol_config, None)?); + + let system_packages_and_objects = store.objects().keys().copied().collect(); + Ok(Self { + protocol_config, + tx_context, + store, + system_packages_and_objects, + move_vm, + metrics, + native_tokens: Default::default(), + }) + } + + pub fn store(&self) -> &InMemoryStorage { + &self.store + } + + pub(crate) fn native_tokens(&self) -> &HashMap { + &self.native_tokens + } + + /// The migration objects. + /// + /// The system packages and underlying `init` objects + /// are filtered out because they will be generated + /// in the genesis process. + pub(super) fn into_objects(self) -> Vec { + self.store + .into_inner() + .into_values() + .filter(|object| !self.system_packages_and_objects.contains(&object.id())) + .collect() + } + + /// Load input objects from the store to be used as checked + /// input while executing a transaction + pub(crate) fn load_input_objects( + &self, + object_refs: impl IntoIterator + 'static, + ) -> impl Iterator + '_ { + object_refs.into_iter().filter_map(|object_ref| { + Some(ObjectReadResult::new( + InputObjectKind::ImmOrOwnedMoveObject(object_ref), + self.store.get_object(&object_ref.0)?.clone().into(), + )) + }) + } + + /// Load packages from the store to be used as checked + /// input while executing a transaction + pub(crate) fn load_packages( + &self, + object_ids: impl IntoIterator + 'static, + ) -> impl Iterator + '_ { + object_ids.into_iter().filter_map(|object_id| { + Some(ObjectReadResult::new( + InputObjectKind::MovePackage(object_id), + self.store.get_object(&object_id)?.clone().into(), + )) + }) + } + + fn checked_system_packages(&self) -> CheckedInputObjects { + CheckedInputObjects::new_for_genesis(self.load_packages(PACKAGE_DEPS).collect()) + } + + pub(crate) fn execute_pt_unmetered( + &mut self, + input_objects: CheckedInputObjects, + pt: ProgrammableTransaction, + ) -> Result { + let input_objects = input_objects.into_inner(); + let mut temporary_store = TemporaryStore::new( + &self.store, + input_objects, + vec![], + self.tx_context.digest(), + &self.protocol_config, + ); + let mut gas_charger = GasCharger::new_unmetered(self.tx_context.digest()); + programmable_transactions::execution::execute::( + &self.protocol_config, + self.metrics.clone(), + &self.move_vm, + &mut temporary_store, + &mut self.tx_context, + &mut gas_charger, + pt, + )?; + temporary_store.update_object_version_and_prev_tx(); + Ok(temporary_store.into_inner()) + } + + /// Process the foundry outputs as follows: + /// + /// * Publish the generated packages using a tailored unmetered executor. + /// * For each native token, map the [`TokenId`] to the [`ObjectID`] of the + /// coin that holds its total supply. + /// * Update the inner store with the created objects. + pub(super) fn create_foundries<'a>( + &mut self, + foundries: impl IntoIterator, + ) -> Result> { + let mut res = Vec::new(); + for (header, foundry, pkg) in foundries { + let mut created_objects = CreatedObjects::default(); + let modules = package_module_bytes(&pkg)?; + let deps = self.checked_system_packages(); + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + let upgrade_cap = builder.command(Command::Publish(modules, PACKAGE_DEPS.into())); + // We make a dummy transfer because the `UpgradeCap` does + // not have the drop ability. + // + // We ignore it in the genesis, to render the package immutable. + builder.transfer_arg(Default::default(), upgrade_cap); + builder.finish() + }; + let InnerTemporaryStore { written, .. } = self.execute_pt_unmetered(deps, pt)?; + // Get on-chain info + let mut minted_coin_id = None::; + let mut foundry_package = None::<&MovePackage>; + for object in written.values() { + if object.is_coin() { + minted_coin_id = Some(object.id()); + created_objects.set_minted_coin(object.id())?; + } else if object.type_().map_or(false, |t| t.is_coin_metadata()) { + created_objects.set_coin_metadata(object.id())? + } else if object.type_().map_or(false, |t| { + t.address() == STARDUST_ADDRESS + && t.module().as_str() == "capped_coin" + && t.name().as_str() == "MaxSupplyPolicy" + }) { + created_objects.set_max_supply_policy(object.id())? + } else if object.is_package() { + foundry_package = Some( + object + .data + .try_as_package() + .expect("already verified this is a package"), + ); + created_objects.set_package(object.id())?; + } + } + let (minted_coin_id, foundry_package) = ( + minted_coin_id.expect("a coin must have been minted"), + foundry_package.expect("there should be a published package"), + ); + self.native_tokens.insert( + foundry.token_id(), + FoundryLedgerData::new( + minted_coin_id, + foundry_package, + SimpleTokenSchemeU64::try_from(foundry.token_scheme().as_simple())?, + ), + ); + + // Create the foundry gas coin object. + let gas_coin = create_foundry_gas_coin( + &header.output_id(), + foundry, + &self.tx_context, + foundry_package.version(), + &self.protocol_config, + )?; + created_objects.set_coin(gas_coin.id())?; + self.store.insert_object(gas_coin); + + self.store.finish( + written + .into_iter() + // We ignore the [`UpgradeCap`] objects. + .filter(|(_, object)| object.struct_tag() != Some(UpgradeCap::type_())) + .collect(), + ); + res.push((header.output_id(), created_objects)); + } + Ok(res) + } + + pub(super) fn create_alias_objects( + &mut self, + header: &OutputHeader, + alias: &AliasOutput, + ) -> Result { + let mut created_objects = CreatedObjects::default(); + + // Take the Alias ID set in the output or, if its zeroized, compute it from the + // Output ID. + let alias_id = ObjectID::new(*alias.alias_id().or_from_output_id(&header.output_id())); + let move_alias = crate::stardust::types::Alias::try_from_stardust(alias_id, alias)?; + + // TODO: We should ensure that no circular ownership exists. + let alias_output_owner = stardust_to_iota_address_owner(alias.governor_address())?; + + let package_deps = InputObjects::new(self.load_packages(PACKAGE_DEPS).collect()); + let version = package_deps.lamport_timestamp(&[]); + + let move_alias_object = move_alias.to_genesis_object( + alias_output_owner, + &self.protocol_config, + &self.tx_context, + version, + )?; + let move_alias_object_ref = move_alias_object.compute_object_reference(); + + self.store.insert_object(move_alias_object); + + let (bag, version, fields) = self.create_bag_with_pt(alias.native_tokens())?; + created_objects.set_native_tokens(fields)?; + + let move_alias_output = crate::stardust::types::AliasOutput::try_from_stardust( + self.tx_context.fresh_id(), + alias, + bag, + )?; + + // The bag will be wrapped into the alias output object, so + // by equating their versions we emulate a ptb. + let move_alias_output_object = move_alias_output.to_genesis_object( + alias_output_owner, + &self.protocol_config, + &self.tx_context, + version, + )?; + let move_alias_output_object_ref = move_alias_output_object.compute_object_reference(); + + created_objects.set_output(move_alias_output_object.id())?; + self.store.insert_object(move_alias_output_object); + + // Attach the Alias to the Alias Output as a dynamic object field via the + // attach_alias convenience method. + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + + let alias_output_arg = + builder.obj(ObjectArg::ImmOrOwnedObject(move_alias_output_object_ref))?; + let alias_arg = builder.obj(ObjectArg::ImmOrOwnedObject(move_alias_object_ref))?; + + builder.programmable_move_call( + STARDUST_PACKAGE_ID, + ident_str!("alias_output").into(), + ident_str!("attach_alias").into(), + vec![], + vec![alias_output_arg, alias_arg], + ); + + builder.finish() + }; + + let input_objects = CheckedInputObjects::new_for_genesis( + self.load_input_objects([move_alias_object_ref, move_alias_output_object_ref]) + .chain(self.load_packages(PACKAGE_DEPS)) + .collect(), + ); + + let InnerTemporaryStore { written, .. } = self.execute_pt_unmetered(input_objects, pt)?; + self.store.finish(written); + + Ok(created_objects) + } + + /// Create a [`Bag`] of balances of native tokens executing a programmable + /// transaction block. + pub(crate) fn create_bag_with_pt( + &mut self, + native_tokens: &NativeTokens, + ) -> Result<(Bag, SequenceNumber, Vec)> { + let mut object_deps = Vec::with_capacity(native_tokens.len()); + let mut foundry_package_deps = Vec::with_capacity(native_tokens.len()); + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + let bag = pt::bag_new(&mut builder); + for token in native_tokens.iter() { + let Some(foundry_ledger_data) = self.native_tokens.get_mut(token.token_id()) else { + anyhow::bail!("foundry for native token has not been published"); + }; + + let Some(foundry_coin) = self.store.get_object(&foundry_ledger_data.minted_coin_id) + else { + anyhow::bail!("foundry coin should exist"); + }; + let object_ref = foundry_coin.compute_object_reference(); + + object_deps.push(object_ref); + foundry_package_deps.push(foundry_ledger_data.package_id); + + let token_type = foundry_ledger_data.canonical_coin_type(); + + let adjusted_amount = foundry_ledger_data + .token_scheme_u64 + .adjust_tokens(token.amount()); + + foundry_ledger_data.minted_value = foundry_ledger_data + .minted_value + .checked_sub(adjusted_amount) + .ok_or_else(|| anyhow::anyhow!("underflow splitting native token balance"))?; + + let balance = pt::coin_balance_split( + &mut builder, + object_ref, + token_type.parse()?, + adjusted_amount, + )?; + pt::bag_add(&mut builder, bag, balance, token_type)?; + } + + // The `Bag` object does not have the `drop` ability so we have to use it + // in the transaction block. Therefore we transfer it to the `0x0` address. + // + // Nevertheless, we only store the contents of the object, and thus the + // ownership metadata are irrelevant to us. This is a dummy transfer + // then to satisfy the VM. + builder.transfer_arg(Default::default(), bag); + builder.finish() + }; + let checked_input_objects = CheckedInputObjects::new_for_genesis( + self.load_packages(PACKAGE_DEPS) + .chain(self.load_packages(foundry_package_deps)) + .chain(self.load_input_objects(object_deps)) + .collect(), + ); + let InnerTemporaryStore { + mut written, + input_objects, + .. + } = self.execute_pt_unmetered(checked_input_objects, pt)?; + let bag_object = written + .iter() + // We filter out the dynamic-field objects that are owned by the bag + // and we should be left with only the bag + .find_map(|(id, object)| { + (!input_objects.contains_key(id) && !object.is_child_object()).then_some(id) + }) + .copied() + .and_then(|id| written.remove(&id)) + .ok_or_else(|| anyhow::anyhow!("the bag should have been created"))?; + written.remove(&bag_object.id()); + let field_ids = written + .iter() + .filter_map(|(id, object)| object.to_rust::>().map(|_| *id)) + .collect(); + // Save the modified coins + self.store.finish(written); + // Return bag + let bag = bcs::from_bytes( + bag_object + .data + .try_as_move() + .expect("this should be a move object") + .contents(), + ) + .expect("this should be a valid Bag Move object"); + Ok((bag, bag_object.version(), field_ids)) + } + + /// Create [`Coin`] objects representing native tokens in the ledger. + fn create_native_token_coins( + &mut self, + native_tokens: &NativeTokens, + owner: IotaAddress, + ) -> Result> { + let mut object_deps = Vec::with_capacity(native_tokens.len()); + let mut foundry_package_deps = Vec::with_capacity(native_tokens.len()); + let mut foundry_coins = Vec::with_capacity(native_tokens.len()); + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + for token in native_tokens.iter() { + let Some(foundry_ledger_data) = self.native_tokens.get_mut(token.token_id()) else { + anyhow::bail!("foundry for native token has not been published"); + }; + + let Some(foundry_coin) = self.store.get_object(&foundry_ledger_data.minted_coin_id) + else { + anyhow::bail!("foundry coin should exist"); + }; + let object_ref = foundry_coin.compute_object_reference(); + foundry_coins.push(foundry_coin.id()); + + object_deps.push(object_ref); + foundry_package_deps.push(foundry_ledger_data.package_id); + + // Pay using that object + let adjusted_amount = foundry_ledger_data + .token_scheme_u64 + .adjust_tokens(token.amount()); + + foundry_ledger_data.minted_value = foundry_ledger_data + .minted_value + .checked_sub(adjusted_amount) + .ok_or_else(|| anyhow::anyhow!("underflow splitting native token balance"))?; + + builder.pay(vec![object_ref], vec![owner], vec![adjusted_amount])?; + } + + builder.finish() + }; + let checked_input_objects = CheckedInputObjects::new_for_genesis( + self.load_packages(PACKAGE_DEPS) + .chain(self.load_packages(foundry_package_deps)) + .chain(self.load_input_objects(object_deps)) + .collect(), + ); + // Execute + let InnerTemporaryStore { written, .. } = + self.execute_pt_unmetered(checked_input_objects, pt)?; + + let coin_ids = written + .keys() + // Linear search is ok due to the expected very small size of + // `foundry_coins` + .filter(|id| !foundry_coins.contains(id)) + .copied() + .collect(); + + // Save the modified coin + self.store.finish(written); + Ok(coin_ids) + } + + /// This implements the control flow in + /// crates/iota-framework/packages/stardust/basic_migration_graph.svg + pub(super) fn create_basic_objects( + &mut self, + header: &OutputHeader, + basic_output: &BasicOutput, + ) -> Result { + let mut data = + crate::stardust::types::output::BasicOutput::new(header.clone(), basic_output)?; + let owner: IotaAddress = basic_output.address().to_string().parse()?; + let mut created_objects = CreatedObjects::default(); + + // The minimum version of the manually created objects + let package_deps = InputObjects::new(self.load_packages(PACKAGE_DEPS).collect()); + let mut version = package_deps.lamport_timestamp(&[]); + let object = if data.is_simple_coin() { + if !basic_output.native_tokens().is_empty() { + let coins = self.create_native_token_coins(basic_output.native_tokens(), owner)?; + created_objects.set_native_tokens(coins)?; + } + let coin = data.into_genesis_coin_object( + owner, + &self.protocol_config, + &self.tx_context, + version, + )?; + created_objects.set_coin(coin.id())?; + coin + } else { + if !basic_output.native_tokens().is_empty() { + let fields; + // The bag will be wrapped into the basic output object, so + // by equating their versions we emulate a ptb. + (data.native_tokens, version, fields) = + self.create_bag_with_pt(basic_output.native_tokens())?; + created_objects.set_native_tokens(fields)?; + } else { + // Overwrite the default 0 UID of `Bag::default()`, since we won't + // be creating a new bag in this code path. + data.native_tokens.id = UID::new(self.tx_context.fresh_id()); + } + let object = + data.to_genesis_object(owner, &self.protocol_config, &self.tx_context, version)?; + created_objects.set_output(object.id())?; + object + }; + + self.store.insert_object(object); + Ok(created_objects) + } + + /// Creates [`TimeLock>`] objects which represent vested + /// rewards that were created during the stardust upgrade on IOTA + /// mainnet. + pub(super) fn create_timelock_object( + &mut self, + output_id: OutputId, + basic_output: &BasicOutput, + target_milestone_timestamp: u32, + ) -> Result { + let mut created_objects = CreatedObjects::default(); + + let owner: IotaAddress = basic_output.address().to_string().parse()?; + + let package_deps = InputObjects::new(self.load_packages(PACKAGE_DEPS).collect()); + let version = package_deps.lamport_timestamp(&[]); + + let timelock = + timelock::try_from_stardust(output_id, basic_output, target_milestone_timestamp)?; + + let object = timelock::to_genesis_object( + timelock, + owner, + &self.protocol_config, + &self.tx_context, + version, + )?; + + created_objects.set_output(object.id())?; + + self.store.insert_object(object); + Ok(created_objects) + } + + pub(super) fn create_nft_objects( + &mut self, + header: &OutputHeader, + nft: &NftOutput, + ) -> Result { + let mut created_objects = CreatedObjects::default(); + + // Take the Nft ID set in the output or, if its zeroized, compute it from the + // Output ID. + let nft_id = ObjectID::new(*nft.nft_id().or_from_output_id(&header.output_id())); + let move_nft = Nft::try_from_stardust(nft_id, nft)?; + + // TODO: We should ensure that no circular ownership exists. + let nft_output_owner_address = stardust_to_iota_address(nft.address())?; + let nft_output_owner = stardust_to_iota_address_owner(nft.address())?; + + let package_deps = InputObjects::new(self.load_packages(PACKAGE_DEPS).collect()); + let version = package_deps.lamport_timestamp(&[]); + let move_nft_object = move_nft.to_genesis_object( + nft_output_owner, + &self.protocol_config, + &self.tx_context, + version, + )?; + + let move_nft_object_ref = move_nft_object.compute_object_reference(); + self.store.insert_object(move_nft_object); + + let (bag, version, fields) = self.create_bag_with_pt(nft.native_tokens())?; + created_objects.set_native_tokens(fields)?; + let move_nft_output = crate::stardust::types::NftOutput::try_from_stardust( + self.tx_context.fresh_id(), + nft, + bag, + )?; + + // The bag will be wrapped into the nft output object, so + // by equating their versions we emulate a ptb. + let move_nft_output_object = move_nft_output.to_genesis_object( + nft_output_owner_address, + &self.protocol_config, + &self.tx_context, + version, + )?; + let move_nft_output_object_ref = move_nft_output_object.compute_object_reference(); + created_objects.set_output(move_nft_output_object.id())?; + self.store.insert_object(move_nft_output_object); + + // Attach the Nft to the Nft Output as a dynamic object field via the attach_nft + // convenience method. + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + + let nft_output_arg = + builder.obj(ObjectArg::ImmOrOwnedObject(move_nft_output_object_ref))?; + let nft_arg = builder.obj(ObjectArg::ImmOrOwnedObject(move_nft_object_ref))?; + builder.programmable_move_call( + STARDUST_PACKAGE_ID, + ident_str!("nft_output").into(), + ident_str!("attach_nft").into(), + vec![], + vec![nft_output_arg, nft_arg], + ); + + builder.finish() + }; + + let input_objects = CheckedInputObjects::new_for_genesis( + self.load_input_objects([move_nft_object_ref, move_nft_output_object_ref]) + .chain(self.load_packages(PACKAGE_DEPS)) + .collect(), + ); + + let InnerTemporaryStore { written, .. } = self.execute_pt_unmetered(input_objects, pt)?; + self.store.finish(written); + + Ok(created_objects) + } +} + +#[cfg(test)] +impl Executor { + /// Set the [`TxContext`] of the [`Executor`]. + pub(crate) fn with_tx_context(mut self, tx_context: TxContext) -> Self { + self.tx_context = tx_context; + self + } + + /// Set the [`InMemoryStorage`] of the [`Executor`]. + pub(crate) fn with_store(mut self, store: InMemoryStorage) -> Self { + self.store = store; + self + } +} + +mod pt { + use super::*; + use crate::stardust::migration::NATIVE_TOKEN_BAG_KEY_TYPE; + + pub fn coin_balance_split( + builder: &mut ProgrammableTransactionBuilder, + foundry_coin_ref: ObjectRef, + token_type_tag: TypeTag, + amount: u64, + ) -> Result { + let foundry_coin_ref = builder.obj(ObjectArg::ImmOrOwnedObject(foundry_coin_ref))?; + let amount = builder.pure(amount)?; + let coin = builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("coin").into(), + ident_str!("split").into(), + vec![token_type_tag.clone()], + vec![foundry_coin_ref, amount], + ); + Ok(builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("coin").into(), + ident_str!("into_balance").into(), + vec![token_type_tag], + vec![coin], + )) + } + + pub fn bag_add( + builder: &mut ProgrammableTransactionBuilder, + bag: Argument, + balance: Argument, + token_type: String, + ) -> Result<()> { + let key_type: StructTag = NATIVE_TOKEN_BAG_KEY_TYPE.parse()?; + let value_type = Balance::type_(token_type.parse::()?); + let token_name = builder.pure(token_type)?; + builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("bag").into(), + ident_str!("add").into(), + vec![key_type.into(), value_type.into()], + vec![bag, token_name, balance], + ); + Ok(()) + } + + pub fn bag_new(builder: &mut ProgrammableTransactionBuilder) -> Argument { + builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("bag").into(), + ident_str!("new").into(), + vec![], + vec![], + ) + } +} + +/// On-chain data about the objects created while +/// publishing foundry packages +pub(crate) struct FoundryLedgerData { + pub(crate) minted_coin_id: ObjectID, + pub(crate) coin_type_origin: TypeOrigin, + pub(crate) package_id: ObjectID, + pub(crate) token_scheme_u64: SimpleTokenSchemeU64, + pub(crate) minted_value: u64, +} + +impl FoundryLedgerData { + /// Store the minted coin `ObjectID` and derive data from the foundry + /// package. + /// + /// # Panic + /// + /// Panics if the package does not contain any [`TypeOrigin`]. + fn new( + minted_coin_id: ObjectID, + foundry_package: &MovePackage, + token_scheme_u64: SimpleTokenSchemeU64, + ) -> Self { + Self { + minted_coin_id, + // There must be only one type created in the foundry package. + coin_type_origin: foundry_package.type_origin_table()[0].clone(), + package_id: foundry_package.id(), + minted_value: token_scheme_u64.circulating_supply(), + token_scheme_u64, + } + } + + pub(crate) fn canonical_coin_type(&self) -> String { + format!( + "{}::{}::{}", + self.coin_type_origin.package, + self.coin_type_origin.module_name, + self.coin_type_origin.struct_name + ) + } +} diff --git a/crates/sui-genesis-builder/src/stardust/migration/migration.rs b/crates/iota-genesis-builder/src/stardust/migration/migration.rs similarity index 95% rename from crates/sui-genesis-builder/src/stardust/migration/migration.rs rename to crates/iota-genesis-builder/src/stardust/migration/migration.rs index e30c9516ac2..76d8500fa6f 100644 --- a/crates/sui-genesis-builder/src/stardust/migration/migration.rs +++ b/crates/iota-genesis-builder/src/stardust/migration/migration.rs @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! Contains the logic for the migration process. @@ -10,16 +11,16 @@ use std::{ use anyhow::Result; use fastcrypto::hash::HashFunction; +use iota_move_build::CompiledPackage; +use iota_protocol_config::ProtocolVersion; use iota_sdk::types::block::output::{FoundryOutput, Output, OutputId}; -use sui_move_build::CompiledPackage; -use sui_protocol_config::ProtocolVersion; -use sui_types::{ - base_types::{ObjectID, SuiAddress, TxContext}, +use iota_types::{ + base_types::{IotaAddress, ObjectID, TxContext}, crypto::DefaultHash, digests::TransactionDigest, epoch_data::EpochData, object::Object, - MOVE_STDLIB_PACKAGE_ID, STARDUST_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID, SUI_SYSTEM_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, IOTA_SYSTEM_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID, STARDUST_PACKAGE_ID, TIMELOCK_PACKAGE_ID, }; @@ -38,8 +39,8 @@ pub const MIGRATION_PROTOCOL_VERSION: u64 = 42; /// The dependencies of the generated packages for native tokens. pub const PACKAGE_DEPS: [ObjectID; 5] = [ MOVE_STDLIB_PACKAGE_ID, - SUI_FRAMEWORK_PACKAGE_ID, - SUI_SYSTEM_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, + IOTA_SYSTEM_PACKAGE_ID, STARDUST_PACKAGE_ID, TIMELOCK_PACKAGE_ID, ]; @@ -251,7 +252,7 @@ pub(super) fn create_migration_context() -> TxContext { let stardust_migration_transaction_digest = TransactionDigest::new(hash.into()); TxContext::new( - &SuiAddress::default(), + &IotaAddress::default(), &stardust_migration_transaction_digest, &EpochData::new_genesis(0), ) diff --git a/crates/iota-genesis-builder/src/stardust/migration/mod.rs b/crates/iota-genesis-builder/src/stardust/migration/mod.rs new file mode 100644 index 00000000000..e89e82204c3 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/migration/mod.rs @@ -0,0 +1,12 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod executor; +#[allow(clippy::module_inception)] +mod migration; +#[cfg(test)] +mod tests; +pub mod verification; + +pub use migration::*; diff --git a/crates/iota-genesis-builder/src/stardust/migration/tests/alias.rs b/crates/iota-genesis-builder/src/stardust/migration/tests/alias.rs new file mode 100644 index 00000000000..a687ca57879 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/migration/tests/alias.rs @@ -0,0 +1,298 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::str::FromStr; + +use iota_sdk::{ + types::block::{ + address::{Address, Ed25519Address}, + output::{ + feature::{Irc30Metadata, IssuerFeature, MetadataFeature, SenderFeature}, + unlock_condition::{ + AddressUnlockCondition, GovernorAddressUnlockCondition, + StateControllerAddressUnlockCondition, + }, + AliasId, AliasOutput as StardustAlias, AliasOutputBuilder, Feature, NativeToken, NftId, + NftOutputBuilder, SimpleTokenScheme, + }, + }, + U256, +}; +use iota_types::{ + base_types::ObjectID, + dynamic_field::{derive_dynamic_field_id, DynamicFieldInfo}, + id::UID, + object::{Object, Owner}, + TypeTag, +}; +use move_core_types::ident_str; + +use super::ExpectedAssets; +use crate::stardust::{ + migration::tests::{ + create_foundry, extract_native_token_from_bag, object_migration_with_object_owner, + random_output_header, run_migration, + }, + types::{ + snapshot::OutputHeader, stardust_to_iota_address, Alias, AliasOutput, + ALIAS_DYNAMIC_OBJECT_FIELD_KEY, ALIAS_DYNAMIC_OBJECT_FIELD_KEY_TYPE, + ALIAS_OUTPUT_MODULE_NAME, NFT_OUTPUT_MODULE_NAME, + }, +}; + +fn migrate_alias( + header: OutputHeader, + stardust_alias: StardustAlias, +) -> anyhow::Result<(ObjectID, Alias, AliasOutput, Object, Object)> { + let output_id = header.output_id(); + let alias_id: AliasId = stardust_alias + .alias_id() + .or_from_output_id(&output_id) + .to_owned(); + + let (executor, objects_map) = run_migration([(header, stardust_alias.into())])?; + + // Ensure the migrated objects exist under the expected identifiers. + let alias_object_id = ObjectID::new(*alias_id); + let created_objects = objects_map + .get(&output_id) + .expect("alias output should have created objects"); + + let alias_object = executor + .store() + .objects() + .values() + .find(|obj| obj.id() == alias_object_id) + .expect("alias object should be present in the migrated snapshot"); + assert_eq!(alias_object.struct_tag().unwrap(), Alias::tag()); + + let alias_output_object = executor + .store() + .get_object(created_objects.output().unwrap()) + .unwrap(); + assert_eq!( + alias_output_object.struct_tag().unwrap(), + AliasOutput::tag() + ); + + // Version is set to 1 when the alias is created based on the computed lamport + // timestamp. When the alias is attached to the alias output, the version + // should be incremented. + assert!( + alias_object.version().value() > 1, + "alias object version should have been incremented" + ); + assert!( + alias_output_object.version().value() > 1, + "alias output object version should have been incremented" + ); + + let alias_output: AliasOutput = + bcs::from_bytes(alias_output_object.data.try_as_move().unwrap().contents()).unwrap(); + let alias: Alias = + bcs::from_bytes(alias_object.data.try_as_move().unwrap().contents()).unwrap(); + + Ok(( + alias_object_id, + alias, + alias_output, + alias_object.clone(), + alias_output_object.clone(), + )) +} + +/// Test that the migrated alias objects in the snapshot contain the expected +/// data. +#[test] +fn alias_migration_with_full_features() { + let alias_id = AliasId::new(rand::random()); + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + let stardust_alias = AliasOutputBuilder::new_with_amount(1_000_000, alias_id) + .add_unlock_condition(StateControllerAddressUnlockCondition::new(random_address)) + .add_unlock_condition(GovernorAddressUnlockCondition::new(random_address)) + .with_state_metadata([0xff; 1]) + .with_features(vec![ + Feature::Metadata(MetadataFeature::new([0xdd; 1]).unwrap()), + Feature::Sender(SenderFeature::new(random_address)), + ]) + .with_immutable_features(vec![ + Feature::Metadata(MetadataFeature::new([0xaa; 1]).unwrap()), + Feature::Issuer(IssuerFeature::new(random_address)), + ]) + .with_state_index(3) + .finish() + .unwrap(); + + let (alias_object_id, alias, alias_output, alias_object, alias_output_object) = + migrate_alias(header, stardust_alias.clone()).unwrap(); + let expected_alias = Alias::try_from_stardust(alias_object_id, &stardust_alias).unwrap(); + + // The bag is tested separately. + assert_eq!(stardust_alias.amount(), alias_output.iota.value()); + // The ID is newly generated, so we don't know the exact value, but it should + // not be zero. + assert_ne!(alias_output.id, UID::new(ObjectID::ZERO)); + assert_ne!( + alias_output.id, + UID::new(ObjectID::new( + stardust_alias.alias_id().as_slice().try_into().unwrap() + )) + ); + + assert_eq!(expected_alias, alias); + + // The Alias Object should be in a dynamic object field. + let alias_owner = derive_dynamic_field_id( + alias_output_object.id(), + &TypeTag::from(DynamicFieldInfo::dynamic_object_field_wrapper( + // The key type of the dynamic object field. + TypeTag::from_str(ALIAS_DYNAMIC_OBJECT_FIELD_KEY_TYPE).unwrap(), + )), + &bcs::to_bytes(ALIAS_DYNAMIC_OBJECT_FIELD_KEY).unwrap(), + ) + .unwrap(); + assert_eq!(alias_object.owner, Owner::ObjectOwner(alias_owner.into())); + + let alias_output_owner = + Owner::AddressOwner(stardust_to_iota_address(stardust_alias.governor_address()).unwrap()); + assert_eq!(alias_output_object.owner, alias_output_owner); +} + +/// Test that an Alias with a zeroed ID is migrated to an Alias Object with its +/// UID set to the hashed Output ID. +#[test] +fn alias_migration_with_zeroed_id() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + let stardust_alias = AliasOutputBuilder::new_with_amount(1_000_000, AliasId::null()) + .add_unlock_condition(StateControllerAddressUnlockCondition::new(random_address)) + .add_unlock_condition(GovernorAddressUnlockCondition::new(random_address)) + .finish() + .unwrap(); + + // If this function does not panic, then the created aliases + // were found at the correct non-zeroed Alias ID. + migrate_alias(header, stardust_alias).unwrap(); +} + +/// Test that an Alias owned by another Alias can be received by the owning +/// object. +/// +/// The PTB sends the extracted assets to the null address since they must be +/// used in the transaction. +#[test] +fn alias_migration_with_alias_owner() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + + let alias1_header = random_output_header(); + let stardust_alias1 = + AliasOutputBuilder::new_with_amount(1_000_000, AliasId::new(rand::random())) + .add_unlock_condition(StateControllerAddressUnlockCondition::new(random_address)) + .add_unlock_condition(GovernorAddressUnlockCondition::new(random_address)) + .finish() + .unwrap(); + + let alias2_header = random_output_header(); + // stardust_alias1 is the owner of stardust_alias2. + let stardust_alias2 = + AliasOutputBuilder::new_with_amount(2_000_000, AliasId::new(rand::random())) + .add_unlock_condition(StateControllerAddressUnlockCondition::new(Address::from( + *stardust_alias1.alias_id(), + ))) + .add_unlock_condition(GovernorAddressUnlockCondition::new(Address::from( + *stardust_alias1.alias_id(), + ))) + .finish() + .unwrap(); + + object_migration_with_object_owner( + alias1_header.output_id(), + alias2_header.output_id(), + [ + (alias1_header.clone(), stardust_alias1.into()), + (alias2_header.clone(), stardust_alias2.into()), + ], + ALIAS_OUTPUT_MODULE_NAME, + ALIAS_OUTPUT_MODULE_NAME, + ident_str!("unlock_alias_address_owned_alias"), + ) + .unwrap(); +} + +/// Test that an Alias owned by an NFT can be received by the owning object. +#[test] +fn alias_migration_with_nft_owner() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + + let nft_header = random_output_header(); + let nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::new(rand::random())) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .finish() + .unwrap(); + + let alias_header = random_output_header(); + // nft is the owner (governor) of alias. + let alias = AliasOutputBuilder::new_with_amount(2_000_000, AliasId::new(rand::random())) + .add_unlock_condition(StateControllerAddressUnlockCondition::new( + Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()), + )) + .add_unlock_condition(GovernorAddressUnlockCondition::new(Address::from( + *nft.nft_id(), + ))) + .finish() + .unwrap(); + + object_migration_with_object_owner( + nft_header.output_id(), + alias_header.output_id(), + [ + (nft_header.clone(), nft.into()), + (alias_header.clone(), alias.into()), + ], + NFT_OUTPUT_MODULE_NAME, + ALIAS_OUTPUT_MODULE_NAME, + ident_str!("unlock_nft_address_owned_alias"), + ) + .unwrap(); +} + +/// Test that an Alias that owns Native Tokens can extract those tokens from the +/// contained bag. +#[test] +fn alias_migration_with_native_tokens() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let (foundry_header, foundry_output) = create_foundry( + 0, + SimpleTokenScheme::new(U256::from(100_000), U256::from(0), U256::from(100_000_000)) + .unwrap(), + Irc30Metadata::new("Rustcoin\u{245}", "Rust''\n\tCöin", 0) + .with_description("The description of Rustcöin.\n Nice!"), + AliasId::null(), + ) + .unwrap(); + let native_token = NativeToken::new(foundry_output.id().into(), 100).unwrap(); + + let alias_header = random_output_header(); + let alias = AliasOutputBuilder::new_with_amount(1_000_000, AliasId::new(rand::random())) + .add_unlock_condition(StateControllerAddressUnlockCondition::new(random_address)) + .add_unlock_condition(GovernorAddressUnlockCondition::new(random_address)) + .add_native_token(native_token) + .finish() + .unwrap(); + + extract_native_token_from_bag( + alias_header.output_id(), + [ + (alias_header.clone(), alias.into()), + (foundry_header, foundry_output.into()), + ], + ALIAS_OUTPUT_MODULE_NAME, + native_token, + ExpectedAssets::BalanceBagObject, + ) + .unwrap(); +} diff --git a/crates/iota-genesis-builder/src/stardust/migration/tests/basic.rs b/crates/iota-genesis-builder/src/stardust/migration/tests/basic.rs new file mode 100644 index 00000000000..07ac3696ff0 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/migration/tests/basic.rs @@ -0,0 +1,336 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_sdk::types::block::{ + address::Ed25519Address, + output::{ + feature::Irc30Metadata, + unlock_condition::{ + AddressUnlockCondition, ExpirationUnlockCondition, StorageDepositReturnUnlockCondition, + TimelockUnlockCondition, + }, + AliasId, BasicOutputBuilder, NativeToken, SimpleTokenScheme, + }, +}; +use iota_types::base_types::{IotaAddress, ObjectID}; + +use super::{ + extract_native_token_from_bag, unlock_object_test, ExpectedAssets, UnlockObjectTestResult, +}; +use crate::stardust::{ + migration::{ + tests::{create_foundry, random_output_header}, + Migration, + }, + types::{output::BASIC_OUTPUT_MODULE_NAME, stardust_to_iota_address}, +}; + +/// Test the id of a `BasicOutput` that is transformed to a simple coin. +/// +/// Skips checks included in the verification step of the migration. +#[test] +fn basic_simple_coin_id() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + let stardust_basic = BasicOutputBuilder::new_with_amount(1_000_000) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .finish() + .unwrap(); + + let mut migration = Migration::new(1).unwrap(); + migration + .run_migration([(header.clone(), stardust_basic.clone().into())]) + .unwrap(); + let migrated_object_id = migration + .output_objects_map + .get(&header.output_id()) + .unwrap() + .coin() + .unwrap(); + let expected_object_id = ObjectID::new(header.output_id().hash()); + assert_eq!(expected_object_id, *migrated_object_id); +} + +/// Test the id of a `BasicOutput` object. +/// +/// Skips checks included in the verification step of the migration. +#[test] +fn basic_id() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + let stardust_basic = BasicOutputBuilder::new_with_amount(1_000_000) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .add_unlock_condition(ExpirationUnlockCondition::new(random_address, 1).unwrap()) + .finish() + .unwrap(); + + let mut migration = Migration::new(1).unwrap(); + migration + .run_migration([(header.clone(), stardust_basic.clone().into())]) + .unwrap(); + let migrated_object_id = migration + .output_objects_map + .get(&header.output_id()) + .unwrap() + .output() + .unwrap(); + let expected_object_id = ObjectID::new(header.output_id().hash()); + assert_eq!(expected_object_id, *migrated_object_id); +} + +#[test] +fn basic_simple_coin_migration_with_native_token() { + let (foundry_header, foundry_output) = create_foundry( + 0, + SimpleTokenScheme::new(100_000, 0, 100_000_000).unwrap(), + Irc30Metadata::new("Rustcoin", "Rust", 0), + AliasId::null(), + ) + .unwrap(); + let native_token = NativeToken::new(foundry_output.id().into(), 100).unwrap(); + + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + let stardust_basic = BasicOutputBuilder::new_with_amount(1_000_000) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .add_native_token(native_token) + .finish() + .unwrap(); + + let outputs = [ + (foundry_header, foundry_output.into()), + (header, stardust_basic.into()), + ]; + let mut migration = Migration::new(1).unwrap(); + migration.run_migration(outputs).unwrap(); +} + +#[test] +fn basic_migration_with_native_token() { + let (foundry_header, foundry_output) = create_foundry( + 0, + SimpleTokenScheme::new(100_000, 0, 100_000_000).unwrap(), + Irc30Metadata::new("Rustcoin", "Rust", 0), + AliasId::null(), + ) + .unwrap(); + let native_token = NativeToken::new(foundry_output.id().into(), 100).unwrap(); + + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + let output_id = header.output_id(); + + let stardust_basic = BasicOutputBuilder::new_with_amount(1_000_000) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .add_unlock_condition( + StorageDepositReturnUnlockCondition::new(random_address, 10, 1000).unwrap(), + ) + .add_native_token(native_token) + .finish() + .unwrap(); + + let outputs = [ + (foundry_header, foundry_output.into()), + (header, stardust_basic.into()), + ]; + + extract_native_token_from_bag( + output_id, + outputs, + BASIC_OUTPUT_MODULE_NAME, + native_token, + ExpectedAssets::BalanceBag, + ) + .unwrap(); +} + +#[test] +fn basic_migration_with_timelock_unlocked() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + // The epoch timestamp that the executor will use for the test. + let epoch_start_timestamp_ms = 100_000; + + let stardust_basic = BasicOutputBuilder::new_with_amount(1_000_000) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .add_unlock_condition( + TimelockUnlockCondition::new(epoch_start_timestamp_ms / 1000).unwrap(), + ) + .finish() + .unwrap(); + + unlock_object_test( + header.output_id(), + [(header, stardust_basic.into())], + // Sender is not important for this test. + &IotaAddress::ZERO, + BASIC_OUTPUT_MODULE_NAME, + epoch_start_timestamp_ms as u64, + UnlockObjectTestResult::Success, + ExpectedAssets::BalanceBag, + ) + .unwrap(); +} + +#[test] +fn basic_migration_with_timelock_still_locked() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + // The epoch timestamp that the executor will use for the test. + let epoch_start_timestamp_ms = 100_000; + + let stardust_basic = BasicOutputBuilder::new_with_amount(1_000_000) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .add_unlock_condition( + TimelockUnlockCondition::new((epoch_start_timestamp_ms / 1000) + 1).unwrap(), + ) + .finish() + .unwrap(); + + unlock_object_test( + header.output_id(), + [(header, stardust_basic.into())], + // Sender is not important for this test. + &IotaAddress::ZERO, + BASIC_OUTPUT_MODULE_NAME, + epoch_start_timestamp_ms as u64, + UnlockObjectTestResult::ERROR_TIMELOCK_NOT_EXPIRED_FAILURE, + ExpectedAssets::BalanceBag, + ) + .unwrap(); +} + +/// Test that a BasicOutput with an expired Expiration Unlock Condition +/// can/cannot be unlocked, depending on the TX sender. +#[test] +fn basic_migration_with_expired_unlock_condition() { + let owner = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let return_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let iota_owner_address = stardust_to_iota_address(owner).unwrap(); + let iota_return_address = stardust_to_iota_address(return_address).unwrap(); + let header = random_output_header(); + + // The epoch timestamp that the executor will use for the test. + let epoch_start_timestamp_ms = 100_000; + + // Expiration Timestamp is exactly at the epoch start timestamp -> object is + // expired -> return address can unlock. + let stardust_basic = BasicOutputBuilder::new_with_amount(1_000_000) + .add_unlock_condition(AddressUnlockCondition::new(owner)) + .add_unlock_condition( + ExpirationUnlockCondition::new(return_address, epoch_start_timestamp_ms / 1000) + .unwrap(), + ) + .finish() + .unwrap(); + + // Owner Address CANNOT unlock. + unlock_object_test( + header.output_id(), + [(header.clone(), stardust_basic.clone().into())], + &iota_owner_address, + BASIC_OUTPUT_MODULE_NAME, + epoch_start_timestamp_ms as u64, + UnlockObjectTestResult::ERROR_WRONG_SENDER_FAILURE, + ExpectedAssets::BalanceBag, + ) + .unwrap(); + + // Return Address CAN unlock. + unlock_object_test( + header.output_id(), + [(header, stardust_basic.into())], + &iota_return_address, + BASIC_OUTPUT_MODULE_NAME, + epoch_start_timestamp_ms as u64, + UnlockObjectTestResult::Success, + ExpectedAssets::BalanceBag, + ) + .unwrap(); +} + +/// Test that a Basic Output with an unexpired Expiration Unlock Condition +/// can/cannot be unlocked, depending on the TX sender. +#[test] +fn basic_migration_with_unexpired_unlock_condition() { + let owner = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let return_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let iota_owner_address = stardust_to_iota_address(owner).unwrap(); + let iota_return_address = stardust_to_iota_address(return_address).unwrap(); + let header = random_output_header(); + + // The epoch timestamp that the executor will use for the test. + let epoch_start_timestamp_ms = 100_000; + + // Expiration Timestamp is after the epoch start timestamp -> object is not + // expired -> owner address can unlock. + let stardust_basic = BasicOutputBuilder::new_with_amount(1_000_000) + .add_unlock_condition(AddressUnlockCondition::new(owner)) + .add_unlock_condition( + ExpirationUnlockCondition::new(return_address, (epoch_start_timestamp_ms / 1000) + 1) + .unwrap(), + ) + .finish() + .unwrap(); + + // Return Address CANNOT unlock. + unlock_object_test( + header.output_id(), + [(header.clone(), stardust_basic.clone().into())], + &iota_return_address, + BASIC_OUTPUT_MODULE_NAME, + epoch_start_timestamp_ms as u64, + UnlockObjectTestResult::ERROR_WRONG_SENDER_FAILURE, + ExpectedAssets::BalanceBag, + ) + .unwrap(); + + // Owner Address CAN unlock. + unlock_object_test( + header.output_id(), + [(header, stardust_basic.into())], + &iota_owner_address, + BASIC_OUTPUT_MODULE_NAME, + epoch_start_timestamp_ms as u64, + UnlockObjectTestResult::Success, + ExpectedAssets::BalanceBag, + ) + .unwrap(); +} + +/// Test that a BasicOutput with a Storage Deposit Return Unlock Condition can +/// be unlocked. +#[test] +fn basic_migration_with_storage_deposit_return_unlock_condition() { + let owner = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let return_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + let stardust_basic = BasicOutputBuilder::new_with_amount(1_000_000) + .add_unlock_condition(AddressUnlockCondition::new(owner)) + .add_unlock_condition( + StorageDepositReturnUnlockCondition::new(return_address, 1_000, 1_000_000_000).unwrap(), + ) + .finish() + .unwrap(); + + // Simply test that the unlock with the SDRUC succeeds. + unlock_object_test( + header.output_id(), + [(header, stardust_basic.into())], + // Sender is not important for this test. + &IotaAddress::ZERO, + BASIC_OUTPUT_MODULE_NAME, + // Epoch start time is not important for this test. + 0, + UnlockObjectTestResult::Success, + ExpectedAssets::BalanceBag, + ) + .unwrap(); +} diff --git a/crates/iota-genesis-builder/src/stardust/migration/tests/executor.rs b/crates/iota-genesis-builder/src/stardust/migration/tests/executor.rs new file mode 100644 index 00000000000..09f44fdd330 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/migration/tests/executor.rs @@ -0,0 +1,121 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_protocol_config::ProtocolVersion; +use iota_sdk::types::block::{ + address::AliasAddress, + output::{ + unlock_condition::ImmutableAliasAddressUnlockCondition, AliasId, FoundryOutputBuilder, + NativeToken, NativeTokens, SimpleTokenScheme, UnlockCondition, + }, +}; +use iota_types::{ + balance::Balance, + dynamic_field::{derive_dynamic_field_id, Field}, + object::Owner, +}; + +use crate::stardust::{ + migration::{ + executor::Executor, migration::NATIVE_TOKEN_BAG_KEY_TYPE, tests::random_output_header, + }, + native_token::{ + package_builder, + package_data::{NativeTokenModuleData, NativeTokenPackageData}, + }, +}; + +#[test] +fn create_bag_with_pt() { + // Mock the foundry + let owner = AliasAddress::new(AliasId::new([0; AliasId::LENGTH])); + let supply = 1_000_000; + let token_scheme = SimpleTokenScheme::new(supply, 0, supply).unwrap(); + let header = random_output_header(); + let foundry = FoundryOutputBuilder::new_with_amount(1000, 1, token_scheme.into()) + .with_unlock_conditions([UnlockCondition::from( + ImmutableAliasAddressUnlockCondition::new(owner), + )]) + .finish_with_params(supply) + .unwrap(); + let foundry_id = foundry.id(); + let foundry_package_data = NativeTokenPackageData::new( + "wat", + NativeTokenModuleData::new( + foundry_id, "wat", "WAT", 0, "WAT", supply, supply, "wat", "wat", None, owner, + ), + ); + let foundry_package = package_builder::build_and_compile(foundry_package_data).unwrap(); + + // Execution + let mut executor = Executor::new(ProtocolVersion::MAX).unwrap(); + let object_count = executor.store().objects().len(); + executor + .create_foundries([(&header, &foundry, foundry_package)]) + .unwrap(); + // Foundry package publication creates five objects + // + // * The package + // * Coin metadata + // * MaxSupplyPolicy + // * The total supply coin + // * The foundry gas coin + assert_eq!(executor.store().objects().len() - object_count, 5); + assert!(executor.native_tokens().get(&foundry_id.into()).is_some()); + let initial_supply_coin_object = executor + .store() + .objects() + .values() + .find(|object| object.is_coin() && !object.is_gas_coin()) + .expect("there should be only a single coin: the total supply of native tokens"); + let coin_type_tag = initial_supply_coin_object.coin_type_maybe().unwrap(); + let initial_supply_coin_data = initial_supply_coin_object.as_coin_maybe().unwrap(); + + // Mock the native token + let token_amount = 10_000; + let native_token = NativeToken::new(foundry_id.into(), token_amount).unwrap(); + + // Create the bag + let (bag, _, _) = executor + .create_bag_with_pt(&NativeTokens::from_vec(vec![native_token]).unwrap()) + .unwrap(); + assert!(executor.store().get_object(bag.id.object_id()).is_none()); + + // Verify the mutation of the foundry coin with the total supply + let mutated_supply_coin = executor + .store() + .get_object(initial_supply_coin_data.id()) + .unwrap() + .as_coin_maybe() + .unwrap(); + assert_eq!(mutated_supply_coin.value(), supply - token_amount); + + // Get the dynamic fields (df) + let tokens = executor + .store() + .objects() + .values() + .filter(|object| object.is_child_object()) + .collect::>(); + assert_eq!(tokens.len(), 1); + assert_eq!( + tokens[0].owner, + Owner::ObjectOwner((*bag.id.object_id()).into()) + ); + let token_as_df = tokens[0].to_rust::>().unwrap(); + // Verify name + let expected_name = coin_type_tag.to_canonical_string(true); + assert_eq!(token_as_df.name, expected_name); + // Verify value + let expected_balance = Balance::new(token_amount); + assert_eq!(token_as_df.value, expected_balance); + // Verify df id + let expected_id = derive_dynamic_field_id( + *bag.id.object_id(), + &NATIVE_TOKEN_BAG_KEY_TYPE.parse().unwrap(), + &bcs::to_bytes(&expected_name).unwrap(), + ) + .unwrap(); + assert_eq!(*token_as_df.id.object_id(), expected_id); +} diff --git a/crates/iota-genesis-builder/src/stardust/migration/tests/foundry.rs b/crates/iota-genesis-builder/src/stardust/migration/tests/foundry.rs new file mode 100644 index 00000000000..1befee7a4e3 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/migration/tests/foundry.rs @@ -0,0 +1,392 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::{anyhow, Result}; +use iota_protocol_config::ProtocolConfigValue::u64; +use iota_sdk::{ + types::block::output::{ + feature::Irc30Metadata, AliasId, FoundryOutput, Output, SimpleTokenScheme, + }, + Url, U256, +}; +use iota_types::{ + balance::Balance, + base_types::{IotaAddress, MoveObjectType, ObjectID}, + coin::CoinMetadata, + gas_coin::GAS, + object::Object, +}; +use move_core_types::language_storage::TypeTag; + +use crate::stardust::{ + migration::tests::{create_foundry, run_migration}, + types::{ + capped_coin::MaxSupplyPolicy, snapshot::OutputHeader, stardust_to_iota_address, + stardust_to_iota_address_owner, + }, +}; + +type PackageObject = Object; +type CoinObject = Object; +type MintedCoinObject = Object; +type CoinMetadataObject = Object; +type MaxSupplyPolicyObject = Object; + +fn migrate_foundry( + header: OutputHeader, + foundry: FoundryOutput, +) -> Result<( + PackageObject, + CoinObject, + MintedCoinObject, + CoinMetadataObject, + MaxSupplyPolicyObject, +)> { + let output_id = header.output_id(); + + let (executor, objects_map) = run_migration([(header, Output::Foundry(foundry))])?; + + let created_objects_ids = objects_map + .get(&output_id) + .ok_or(anyhow!("missing created objects"))?; + + let created_objects = executor.into_objects(); + + assert_eq!(created_objects.len(), 5); + + let package_id = *created_objects_ids.package()?; + let coin_id = *created_objects_ids.coin()?; + let minted_coin_id = *created_objects_ids.minted_coin()?; + let coin_metadata_id = *created_objects_ids.coin_metadata()?; + let max_supply_policy_id = *created_objects_ids.max_supply_policy()?; + + let package_object = created_objects + .iter() + .find(|object| object.id() == package_id) + .ok_or(anyhow!("missing package object"))?; + let coin_object = created_objects + .iter() + .find(|object| object.id() == coin_id) + .ok_or(anyhow!("missing coin object"))?; + let minted_coin_object = created_objects + .iter() + .find(|object| object.id() == minted_coin_id) + .ok_or(anyhow!("missing minted coin object"))?; + let coin_metadata_object = created_objects + .iter() + .find(|object| object.id() == coin_metadata_id) + .ok_or(anyhow!("missing coin metadata object"))?; + let max_supply_policy_object = created_objects + .iter() + .find(|object| object.id() == max_supply_policy_id) + .ok_or(anyhow!("missing max supply policy object"))?; + + Ok(( + package_object.clone(), + coin_object.clone(), + minted_coin_object.clone(), + coin_metadata_object.clone(), + max_supply_policy_object.clone(), + )) +} + +#[test] +fn foundry_with_simple_metadata() -> Result<()> { + let alias_id = AliasId::new(rand::random()); + let (header, foundry) = create_foundry( + 1_000_000, + SimpleTokenScheme::new(U256::from(100_000), U256::from(0), U256::from(100_000_000)) + .unwrap(), + Irc30Metadata::new("Dogecoin", "DOGE", 0), + alias_id, + ) + .unwrap(); + + let ( + package_object, + coin_object, + minted_coin_object, + coin_metadata_object, + max_supply_policy_object, + ) = migrate_foundry(header, foundry)?; + + // Check the package object. + let type_origin_table = package_object + .data + .try_as_package() + .expect("should be a package object") + .type_origin_table(); + assert_eq!(type_origin_table.len(), 1); + let coin_type_origin = type_origin_table[0].clone(); + assert_eq!(coin_type_origin.module_name, "doge"); + assert_eq!(coin_type_origin.struct_name, "DOGE"); + + // Check the coin object. + let coin = coin_object + .as_coin_maybe() + .expect("should be a coin object"); + assert_eq!( + coin_object.owner.get_owner_address().unwrap().to_string(), + alias_id.to_string() + ); + assert_eq!(coin.balance, Balance::new(1_000_000)); + + // Check the minted coin object. + let minted_coin = minted_coin_object + .as_coin_maybe() + .expect("should be a coin object"); + assert_eq!(minted_coin_object.owner, IotaAddress::ZERO); + assert_eq!(minted_coin.balance, Balance::new(100_000)); + + // Check the coin metadata object. + let coin_metadata = coin_metadata_object + .data + .try_as_move() + .expect("should be a move object"); + + let coin_metadata = CoinMetadata::from_bcs_bytes(coin_metadata.contents()).unwrap(); + assert_eq!(coin_metadata.decimals, 0); + assert_eq!(coin_metadata.name, "Dogecoin"); + assert_eq!(coin_metadata.symbol, "doge"); + assert_eq!(coin_metadata.description, ""); + assert!(coin_metadata.icon_url.is_none()); + + // Check the max supply policy object. + let max_supply_policy = max_supply_policy_object + .to_rust::() + .unwrap(); + + assert_eq!( + max_supply_policy_object.owner, + stardust_to_iota_address_owner(alias_id).unwrap() + ); + assert_eq!(max_supply_policy.maximum_supply, 100_000_000); + + let max_supply_policy_object = max_supply_policy_object.data.try_as_move().unwrap(); + let max_supply_policy_object_type = max_supply_policy_object.type_(); + assert_eq!( + max_supply_policy_object_type.module().as_str(), + "capped_coin" + ); + assert_eq!( + max_supply_policy_object_type.name().as_str(), + "MaxSupplyPolicy" + ); + + let max_supply_policy_object_type_params = + max_supply_policy_object_type.clone().into_type_params(); + assert_eq!(max_supply_policy_object_type_params.len(), 1); + let TypeTag::Struct(type_tag) = &max_supply_policy_object_type_params[0] else { + panic!("unexpected type tag") + }; + assert_eq!(type_tag.module.as_str(), "doge"); + assert_eq!(type_tag.name.as_str(), "DOGE"); + assert_eq!(type_tag.type_params.len(), 0); + assert!(max_supply_policy_object.has_public_transfer()); + + Ok(()) +} + +/// Tests the migration of a foundry output with a metadata +/// containing non-ascii characters, overflowing circulating and maximum +/// supplies - basically not the usual cases. +#[test] +fn foundry_with_special_metadata() -> Result<()> { + let alias_id = AliasId::new(rand::random()); + let (header, foundry) = create_foundry( + 1_000_000, + SimpleTokenScheme::new(U256::from(u64::MAX), U256::from(0), U256::MAX).unwrap(), + Irc30Metadata::new("Dogecoin", "DOGE❤", 123) + .with_description("Much wow") + .with_url(Url::parse("https://dogecoin.com").unwrap()) + .with_logo_url(Url::parse("https://dogecoin.com/logo.png").unwrap()) + .with_logo("0x54654"), + alias_id, + ) + .unwrap(); + + let ( + package_object, + coin_object, + minted_coin_object, + coin_metadata_object, + max_supply_policy_object, + ) = migrate_foundry(header, foundry)?; + + // Check the package object. + let type_origin_table = package_object + .data + .try_as_package() + .expect("should be a package object") + .type_origin_table(); + assert_eq!(type_origin_table.len(), 1); + let coin_type_origin = type_origin_table[0].clone(); + assert_eq!(coin_type_origin.module_name, "doge"); + assert_eq!(coin_type_origin.struct_name, "DOGE"); + + // Check the coin object. + let coin = coin_object + .as_coin_maybe() + .expect("should be a coin object"); + assert_eq!( + coin_object.owner.get_owner_address().unwrap().to_string(), + alias_id.to_string() + ); + assert_eq!(coin.balance, Balance::new(1_000_000)); + + // Check the minted coin object. + let minted_coin = minted_coin_object + .as_coin_maybe() + .expect("should be a coin object"); + assert_eq!(minted_coin_object.owner, IotaAddress::ZERO); + assert_eq!(minted_coin.balance, Balance::new(u64::MAX - 1)); + + // Check the coin metadata object. + let coin_metadata = coin_metadata_object + .data + .try_as_move() + .expect("should be a move object"); + + let coin_metadata = CoinMetadata::from_bcs_bytes(coin_metadata.contents()).unwrap(); + assert_eq!(coin_metadata.decimals, 123); + assert_eq!(coin_metadata.name, "Dogecoin"); + assert_eq!(coin_metadata.symbol, "doge"); + assert_eq!(coin_metadata.description, "Much wow"); + assert_eq!( + coin_metadata.icon_url.unwrap().to_string(), + "https://dogecoin.com/logo.png" + ); + + // Check the max supply policy object. + let max_supply_policy = max_supply_policy_object + .to_rust::() + .unwrap(); + + assert_eq!( + max_supply_policy_object.owner, + stardust_to_iota_address_owner(alias_id).unwrap() + ); + assert_eq!(max_supply_policy.maximum_supply, u64::MAX - 1); + + let max_supply_policy_object = max_supply_policy_object.data.try_as_move().unwrap(); + let max_supply_policy_object_type = max_supply_policy_object.type_(); + assert_eq!( + max_supply_policy_object_type.module().as_str(), + "capped_coin" + ); + assert_eq!( + max_supply_policy_object_type.name().as_str(), + "MaxSupplyPolicy" + ); + + let max_supply_policy_object_type_params = + max_supply_policy_object_type.clone().into_type_params(); + assert_eq!(max_supply_policy_object_type_params.len(), 1); + let TypeTag::Struct(type_tag) = &max_supply_policy_object_type_params[0] else { + panic!("unexpected type tag") + }; + assert_eq!(type_tag.module.as_str(), "doge"); + assert_eq!(type_tag.name.as_str(), "DOGE"); + assert_eq!(type_tag.type_params.len(), 0); + assert!(max_supply_policy_object.has_public_transfer()); + + Ok(()) +} + +#[test] +fn coin_ownership() -> Result<()> { + let alias_id = AliasId::new(rand::random()); + let (header, foundry) = create_foundry( + 1_000_000, + SimpleTokenScheme::new(U256::from(100_000), U256::from(0), U256::from(100_000_000)) + .unwrap(), + Irc30Metadata::new("Dogecoin", "DOGE", 0), + alias_id, + ) + .unwrap(); + + let ( + _package_object, + coin_object, + minted_coin_object, + _coin_metadata_object, + max_supply_policy_object, + ) = migrate_foundry(header, foundry)?; + + // Check the owner of the coin object. + assert_eq!( + coin_object.owner.get_owner_address().unwrap().to_string(), + alias_id.to_string() + ); + + // Check the owner of the minted coin object. + assert_eq!(minted_coin_object.owner, IotaAddress::ZERO); + + // Check the owner of the max supply policy object. + assert_eq!( + max_supply_policy_object.owner, + stardust_to_iota_address_owner(alias_id).unwrap() + ); + + Ok(()) +} + +#[test] +fn create_gas_coin() { + let (foundry_header, foundry_output) = create_foundry( + 1_000_000, + SimpleTokenScheme::new(U256::from(100_000), U256::from(0), U256::from(100_000_000)) + .unwrap(), + Irc30Metadata::new("Rustcoin", "Rust", 0), + AliasId::null(), + ) + .unwrap(); + + let output_id = foundry_header.output_id(); + let alias_address = *foundry_output.alias_address(); + + let (executor, _) = run_migration([(foundry_header, foundry_output.into())]).unwrap(); + let objects = executor.into_objects(); + + // Foundry package publication creates five objects + // + // * The package + // * Coin metadata + // * MaxSupplyPolicy + // * The total supply coin + // * The foundry gas coin + assert_eq!(objects.len(), 5); + + // Extract the package object. + let package_object = objects + .iter() + .find(|object| object.is_package()) + .expect("there should be only a single gas coin"); + + // Extract the gas coin object. + let gas_coin_object = objects + .iter() + .find(|object| object.is_gas_coin()) + .expect("there should be only a single gas coin"); + + // Downcast the gas coin object to get the coin. + let coin = gas_coin_object.as_coin_maybe().unwrap(); + + // Check if the gas coin id is the same as the output id. + assert_eq!(gas_coin_object.id(), ObjectID::new(output_id.hash())); + + // Check if the owner of the gas coin is the package object. + assert_eq!( + gas_coin_object.owner.get_owner_address().unwrap(), + stardust_to_iota_address(alias_address).unwrap() + ); + + assert_eq!( + *gas_coin_object.type_().unwrap(), + MoveObjectType::gas_coin() + ); + assert_eq!(gas_coin_object.coin_type_maybe().unwrap(), GAS::type_tag()); + assert_eq!(coin.value(), 1_000_000); + assert_eq!(package_object.version(), gas_coin_object.version()); +} diff --git a/crates/iota-genesis-builder/src/stardust/migration/tests/mod.rs b/crates/iota-genesis-builder/src/stardust/migration/tests/mod.rs new file mode 100644 index 00000000000..ce398f63895 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/migration/tests/mod.rs @@ -0,0 +1,504 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::HashMap, str::FromStr}; + +use anyhow::{anyhow, bail, ensure}; +use iota_sdk::types::block::{ + address::AliasAddress, + output::{ + feature::{Irc30Metadata, MetadataFeature}, + unlock_condition::ImmutableAliasAddressUnlockCondition, + AliasId, Feature, FoundryOutput, FoundryOutputBuilder, NativeToken, Output, OutputId, + SimpleTokenScheme, TokenId, TokenScheme, + }, +}; +use iota_types::{ + balance::Balance, + base_types::{IotaAddress, TxContext}, + coin::Coin, + digests::TransactionDigest, + epoch_data::EpochData, + gas_coin::GAS, + in_memory_storage::InMemoryStorage, + inner_temporary_store::InnerTemporaryStore, + programmable_transaction_builder::ProgrammableTransactionBuilder, + transaction::{Argument, CheckedInputObjects, ObjectArg}, + TypeTag, IOTA_FRAMEWORK_PACKAGE_ID, STARDUST_PACKAGE_ID, +}; +use move_binary_format::errors::VMError; +use move_core_types::{ident_str, identifier::IdentStr, vm_status::StatusCode}; + +use super::MIGRATION_PROTOCOL_VERSION; +use crate::stardust::{ + migration::{ + executor::Executor, + migration::{Migration, NATIVE_TOKEN_BAG_KEY_TYPE, PACKAGE_DEPS}, + verification::created_objects::CreatedObjects, + }, + types::snapshot::OutputHeader, +}; + +mod alias; +mod basic; +mod executor; +mod foundry; +mod nft; + +fn random_output_header() -> OutputHeader { + OutputHeader::new_testing( + rand::random(), + rand::random(), + rand::random(), + rand::random(), + ) +} + +fn run_migration( + outputs: impl IntoIterator, +) -> anyhow::Result<(Executor, HashMap)> { + let mut migration = Migration::new(1)?; + migration.run_migration(outputs)?; + Ok(migration.into_parts()) +} + +fn create_foundry( + iota_amount: u64, + token_scheme: SimpleTokenScheme, + irc_30_metadata: Irc30Metadata, + alias_id: AliasId, +) -> anyhow::Result<(OutputHeader, FoundryOutput)> { + let builder = + FoundryOutputBuilder::new_with_amount(iota_amount, 1, TokenScheme::Simple(token_scheme)) + .add_unlock_condition(ImmutableAliasAddressUnlockCondition::new( + AliasAddress::new(alias_id), + )) + .add_immutable_feature(Feature::Metadata( + MetadataFeature::new(irc_30_metadata).unwrap(), + )); + let foundry_output = builder.finish()?; + + Ok((random_output_header(), foundry_output)) +} + +/// Test that an Object owned by another Object (not to be confused with +/// Owner::ObjectOwner) can be received by the owning object. This means aliases +/// owned by aliases, aliases owned by NFTs, etc. +/// +/// The PTB sends the extracted assets to the null address since they must be +/// used in the transaction. +fn object_migration_with_object_owner( + output_id_owner: OutputId, + output_id_owned: OutputId, + outputs: impl IntoIterator, + output_owner_module_name: &IdentStr, + output_owned_module_name: &IdentStr, + unlock_condition_function: &IdentStr, +) -> anyhow::Result<()> { + let (mut executor, objects_map) = run_migration(outputs)?; + + // Find the corresponding objects to the migrated outputs. + let owner_created_objects = objects_map + .get(&output_id_owner) + .expect("owner output should have created objects"); + let owned_created_objects = objects_map + .get(&output_id_owned) + .expect("owned output should have created objects"); + + let owner_output_object_ref = executor + .store() + .get_object(owner_created_objects.output()?) + .ok_or_else(|| anyhow!("missing owner-created output"))? + .compute_object_reference(); + let owned_output_object_ref = executor + .store() + .get_object(owned_created_objects.output()?) + .ok_or_else(|| anyhow!("missing owned created output"))? + .compute_object_reference(); + + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + let owner_arg = builder.obj(ObjectArg::ImmOrOwnedObject(owner_output_object_ref))?; + + let extracted_assets = builder.programmable_move_call( + STARDUST_PACKAGE_ID, + output_owner_module_name.into(), + ident_str!("extract_assets").into(), + vec![], + vec![owner_arg], + ); + + let Argument::Result(result_idx) = extracted_assets else { + bail!("expected Argument::Result"); + }; + let balance_arg = Argument::NestedResult(result_idx, 0); + let bag_arg = Argument::NestedResult(result_idx, 1); + let owned_arg = Argument::NestedResult(result_idx, 2); + + let receiving_owned_arg = builder.obj(ObjectArg::Receiving(owned_output_object_ref))?; + let received_owned_output = builder.programmable_move_call( + STARDUST_PACKAGE_ID, + ident_str!("address_unlock_condition").into(), + unlock_condition_function.into(), + vec![], + vec![owned_arg, receiving_owned_arg], + ); + + let coin_arg = builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("coin").into(), + ident_str!("from_balance").into(), + vec![TypeTag::from_str(&format!( + "{IOTA_FRAMEWORK_PACKAGE_ID}::iota::IOTA" + ))?], + vec![balance_arg], + ); + + // Destroying the bag only works if it's empty, hence asserting that it is in + // fact empty. + builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("bag").into(), + ident_str!("destroy_empty").into(), + vec![], + vec![bag_arg], + ); + + // Transfer the coin to the zero address since we have to move it somewhere. + builder.transfer_arg(IotaAddress::default(), coin_arg); + + // We have to use extracted object as we cannot transfer it (since it lacks the + // `store` ability), so we extract its assets. + let extracted_assets = builder.programmable_move_call( + STARDUST_PACKAGE_ID, + output_owned_module_name.into(), + ident_str!("extract_assets").into(), + vec![], + vec![received_owned_output], + ); + let Argument::Result(result_idx) = extracted_assets else { + bail!("expected Argument::Result"); + }; + let balance_arg = Argument::NestedResult(result_idx, 0); + let bag_arg = Argument::NestedResult(result_idx, 1); + let inner_owned_arg = Argument::NestedResult(result_idx, 2); + + let coin_arg = builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("coin").into(), + ident_str!("from_balance").into(), + vec![TypeTag::from_str(&format!( + "{IOTA_FRAMEWORK_PACKAGE_ID}::iota::IOTA" + ))?], + vec![balance_arg], + ); + + // Destroying the bag only works if it's empty, hence asserting that it is in + // fact empty. + builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("bag").into(), + ident_str!("destroy_empty").into(), + vec![], + vec![bag_arg], + ); + + // Transfer the coin to the zero address since we have to move it somewhere. + builder.transfer_arg(IotaAddress::default(), coin_arg); + + // We have successfully extracted the owned objects which is what we want to + // test. Transfer to the zero address so the PTB doesn't fail. + builder.transfer_arg(IotaAddress::default(), owned_arg); + builder.transfer_arg(IotaAddress::default(), inner_owned_arg); + + builder.finish() + }; + + let input_objects = CheckedInputObjects::new_for_genesis( + executor + .load_input_objects([owner_output_object_ref]) + .chain(executor.load_packages(PACKAGE_DEPS)) + .collect(), + ); + executor.execute_pt_unmetered(input_objects, pt)?; + Ok(()) +} + +/// Test that an Output that owns Native Tokens can extract those tokens from +/// the contained bag. +fn extract_native_token_from_bag( + output_id: OutputId, + outputs: impl IntoIterator, + module_name: &IdentStr, + native_token: NativeToken, + expected_assets: ExpectedAssets, +) -> anyhow::Result<()> { + let native_token_id: &TokenId = native_token.token_id(); + + let (mut executor, objects_map) = run_migration(outputs)?; + + // Find the corresponding objects to the migrated output. + let output_created_objects = objects_map + .get(&output_id) + .expect("output should have created objects"); + + let output_object_ref = executor + .store() + .get_object(output_created_objects.output()?) + .ok_or_else(|| anyhow!("missing output-created output"))? + .compute_object_reference(); + + // Recreate the key under which the tokens are stored in the bag. + let foundry_ledger_data = executor + .native_tokens() + .get(native_token_id) + .ok_or_else(|| anyhow!("missing native token {native_token_id}"))?; + let token_type = foundry_ledger_data.canonical_coin_type(); + let token_type_tag = token_type.parse::()?; + + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + let inner_object_arg = builder.obj(ObjectArg::ImmOrOwnedObject(output_object_ref))?; + + let extracted_assets = builder.programmable_move_call( + STARDUST_PACKAGE_ID, + module_name.into(), + ident_str!("extract_assets").into(), + vec![], + vec![inner_object_arg], + ); + + let Argument::Result(result_idx) = extracted_assets else { + bail!("expected Argument::Result"); + }; + let balance_arg = Argument::NestedResult(result_idx, 0); + let bag_arg = Argument::NestedResult(result_idx, 1); + if matches!(expected_assets, ExpectedAssets::BalanceBagObject) { + // This is the inner object, i.e. the Alias extracted from an Alias Output + // or NFT extracted from an NFT Output. + let inner_arg = Argument::NestedResult(result_idx, 2); + builder.transfer_arg(IotaAddress::default(), inner_arg); + } + + let coin_arg = builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("coin").into(), + ident_str!("from_balance").into(), + vec![GAS::type_tag()], + vec![balance_arg], + ); + + builder.transfer_arg(IotaAddress::default(), coin_arg); + + let token_type_arg = builder.pure(token_type.clone())?; + let balance_arg = builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("bag").into(), + ident_str!("remove").into(), + vec![ + NATIVE_TOKEN_BAG_KEY_TYPE + .parse() + .expect("should be a valid type tag"), + Balance::type_(token_type_tag.clone()).into(), + ], + vec![bag_arg, token_type_arg], + ); + + let coin_arg = builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("coin").into(), + ident_str!("from_balance").into(), + vec![token_type_tag.clone()], + vec![balance_arg], + ); + + // Destroying the bag only works if it's empty, hence asserting that it is in + // fact empty. + builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("bag").into(), + ident_str!("destroy_empty").into(), + vec![], + vec![bag_arg], + ); + + builder.transfer_arg(IotaAddress::default(), coin_arg); + + builder.finish() + }; + + let input_objects = CheckedInputObjects::new_for_genesis( + executor + .load_input_objects([output_object_ref]) + .chain(executor.load_packages(PACKAGE_DEPS)) + .collect(), + ); + let InnerTemporaryStore { written, .. } = executor.execute_pt_unmetered(input_objects, pt)?; + + let coin_token_struct_tag = Coin::type_(token_type_tag); + let coin_token = written + .values() + .find(|obj| { + obj.struct_tag() + .map(|tag| tag == coin_token_struct_tag) + .unwrap_or(false) + }) + .ok_or_else(|| anyhow!("missing coin object")) + .and_then(|obj| { + obj.as_coin_maybe() + .ok_or_else(|| anyhow!("object is not a coin")) + })?; + + ensure!( + coin_token.balance.value() == native_token.amount().as_u64(), + "coin token balance does not match original native token amount" + ); + Ok(()) +} + +enum UnlockObjectTestResult { + /// The test should succeed. + Success, + /// The test should fail with the given sub_status. + Failure(u64), +} + +impl UnlockObjectTestResult { + /// A copy of `EWrongSender` in the expiration unlock condition smart + /// contract. + pub(crate) const ERROR_WRONG_SENDER_FAILURE: Self = Self::Failure(0); + /// A copy of `ETimelockNotExpired` in the timelock unlock condition smart + /// contract. + pub(crate) const ERROR_TIMELOCK_NOT_EXPIRED_FAILURE: Self = Self::Failure(0); +} + +enum ExpectedAssets { + BalanceBag, + BalanceBagObject, +} + +fn unlock_object_test( + output_id: OutputId, + outputs: impl IntoIterator, + sender: &IotaAddress, + module_name: &IdentStr, + epoch_start_timestamp_ms: u64, + expected_test_result: UnlockObjectTestResult, + expected_assets: ExpectedAssets, +) -> anyhow::Result<()> { + let (migration_executor, objects_map) = run_migration(outputs)?; + + // Recreate the TxContext and Executor so we can set a timestamp greater than 0. + let tx_context = TxContext::new( + sender, + &TransactionDigest::new(rand::random()), + &EpochData::new(0, epoch_start_timestamp_ms, Default::default()), + ); + let store = InMemoryStorage::new( + // Cloning all objects in the store includes the system packages we need for executing + // tests. + migration_executor + .store() + .objects() + .values() + .cloned() + .collect(), + ); + let mut executor = Executor::new(MIGRATION_PROTOCOL_VERSION.into()) + .unwrap() + .with_tx_context(tx_context) + .with_store(store); + + // Find the corresponding objects to the migrated output. + let output_created_objects = objects_map + .get(&output_id) + .expect("output should have created objects"); + + let output_object_ref = executor + .store() + .get_object(output_created_objects.output().unwrap()) + .unwrap() + .compute_object_reference(); + + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + let inner_object_arg = builder + .obj(ObjectArg::ImmOrOwnedObject(output_object_ref)) + .unwrap(); + + let extracted_assets = builder.programmable_move_call( + STARDUST_PACKAGE_ID, + module_name.into(), + ident_str!("extract_assets").into(), + vec![], + vec![inner_object_arg], + ); + + let Argument::Result(result_idx) = extracted_assets else { + bail!("expected Argument::Result"); + }; + let balance_arg = Argument::NestedResult(result_idx, 0); + let bag_arg = Argument::NestedResult(result_idx, 1); + + let coin_arg = builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("coin").into(), + ident_str!("from_balance").into(), + vec![TypeTag::from_str(&format!("{IOTA_FRAMEWORK_PACKAGE_ID}::iota::IOTA")).unwrap()], + vec![balance_arg], + ); + + // Transfer the assets to the zero address since we have to move them somewhere + // in the test. + builder.transfer_arg(IotaAddress::ZERO, coin_arg); + builder.transfer_arg(IotaAddress::ZERO, bag_arg); + + if matches!(expected_assets, ExpectedAssets::BalanceBagObject) { + let object_arg = Argument::NestedResult(result_idx, 2); + builder.transfer_arg(IotaAddress::ZERO, object_arg); + } + + builder.finish() + }; + + let input_objects = CheckedInputObjects::new_for_genesis( + executor + .load_input_objects([output_object_ref]) + .chain(executor.load_packages(PACKAGE_DEPS)) + .collect(), + ); + let result = executor.execute_pt_unmetered(input_objects, pt); + + match (result, expected_test_result) { + (Ok(_), UnlockObjectTestResult::Success) => Ok(()), + (Ok(_), UnlockObjectTestResult::Failure(_)) => { + bail!("expected test failure, but test suceeded") + } + (Err(err), UnlockObjectTestResult::Success) => { + bail!("expected test success, but test failed: {err}") + } + (Err(err), UnlockObjectTestResult::Failure(expected_sub_status)) => { + for cause in err.chain() { + match cause.downcast_ref::() { + Some(vm_error) => { + ensure!(vm_error.major_status() == StatusCode::ABORTED); + let actual_sub_status = vm_error + .sub_status() + .expect("sub_status should be set for aborts"); + ensure!( + actual_sub_status == expected_sub_status, + "actual vm sub_status {actual_sub_status} did not match expected sub_status {expected_sub_status}" + ); + // Finish test successfully. + return Ok(()); + } + None => continue, + } + } + bail!( + "expected test failure, but failed to find expected VMError in error chain, got: {err}" + ); + } + } +} diff --git a/crates/iota-genesis-builder/src/stardust/migration/tests/nft.rs b/crates/iota-genesis-builder/src/stardust/migration/tests/nft.rs new file mode 100644 index 00000000000..412f90a7726 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/migration/tests/nft.rs @@ -0,0 +1,702 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{BTreeMap, BTreeSet}, + str::FromStr, +}; + +use anyhow::anyhow; +use iota_sdk::{ + types::block::{ + address::{AliasAddress, Ed25519Address, Hrp, NftAddress, ToBech32Ext}, + output::{ + feature::{ + Attribute, Irc30Metadata, IssuerFeature, MetadataFeature, SenderFeature, TagFeature, + }, + unlock_condition::{ + AddressUnlockCondition, ExpirationUnlockCondition, GovernorAddressUnlockCondition, + StateControllerAddressUnlockCondition, StorageDepositReturnUnlockCondition, + TimelockUnlockCondition, + }, + AliasId, AliasOutputBuilder, Feature, NativeToken, NftId, NftOutput as StardustNft, + NftOutputBuilder, SimpleTokenScheme, + }, + }, + U256, +}; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + collection_types::VecMap, + dynamic_field::{derive_dynamic_field_id, DynamicFieldInfo}, + id::UID, + object::{Object, Owner}, + TypeTag, +}; +use move_core_types::ident_str; + +use super::{unlock_object_test, ExpectedAssets, UnlockObjectTestResult}; +use crate::stardust::{ + migration::tests::{ + create_foundry, extract_native_token_from_bag, object_migration_with_object_owner, + random_output_header, run_migration, + }, + types::{ + snapshot::OutputHeader, stardust_to_iota_address, FixedPoint32, Irc27Metadata, Nft, + NftOutput, ALIAS_OUTPUT_MODULE_NAME, NFT_DYNAMIC_OBJECT_FIELD_KEY, + NFT_DYNAMIC_OBJECT_FIELD_KEY_TYPE, NFT_OUTPUT_MODULE_NAME, + }, +}; + +fn migrate_nft( + header: OutputHeader, + stardust_nft: StardustNft, +) -> anyhow::Result<(ObjectID, Nft, NftOutput, Object, Object)> { + let output_id = header.output_id(); + let nft_id: NftId = stardust_nft + .nft_id() + .or_from_output_id(&output_id) + .to_owned(); + + let (executor, objects_map) = run_migration([(header, stardust_nft.into())])?; + + // Ensure the migrated objects exist under the expected identifiers. + let nft_object_id = ObjectID::new(*nft_id); + let created_objects = objects_map + .get(&output_id) + .ok_or_else(|| anyhow!("nft output should have created objects"))?; + + let nft_object = executor + .store() + .objects() + .values() + .find(|obj| obj.id() == nft_object_id) + .ok_or_else(|| anyhow!("nft object should be present in the migrated snapshot"))?; + assert_eq!( + nft_object + .struct_tag() + .ok_or_else(|| anyhow!("missing struct tag on nft object"))?, + Nft::tag() + ); + + let nft_output_object = executor + .store() + .get_object(created_objects.output()?) + .ok_or_else(|| anyhow!("missing nft output"))?; + assert_eq!( + nft_output_object + .struct_tag() + .ok_or_else(|| anyhow!("missing struct tag on output nft object"))?, + NftOutput::tag() + ); + + // Version is set to 1 when the nft is created based on the computed lamport + // timestamp. When the nft is attached to the nft output, the version should + // be incremented. + assert!( + nft_object.version().value() > 1, + "nft object version should have been incremented" + ); + assert!( + nft_output_object.version().value() > 1, + "nft output object version should have been incremented" + ); + + let nft_output: NftOutput = bcs::from_bytes( + nft_output_object + .data + .try_as_move() + .ok_or_else(|| anyhow!("nft output is not a move object"))? + .contents(), + )?; + let nft: Nft = bcs::from_bytes( + nft_object + .data + .try_as_move() + .ok_or_else(|| anyhow!("nft is not a move object"))? + .contents(), + )?; + + Ok(( + nft_object_id, + nft, + nft_output, + nft_object.clone(), + nft_output_object.clone(), + )) +} + +/// Test that the migrated nft objects in the snapshot contain the expected +/// data. +#[test] +fn nft_migration_with_full_features() { + let nft_id = NftId::new(rand::random()); + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, nft_id) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .with_features(vec![ + Feature::Metadata(MetadataFeature::new([0xdd; 1]).unwrap()), + Feature::Sender(SenderFeature::new(random_address)), + Feature::Tag(TagFeature::new(b"tag").unwrap()), + ]) + .with_immutable_features(vec![ + Feature::Metadata(MetadataFeature::new([0xaa; 1]).unwrap()), + Feature::Issuer(IssuerFeature::new(random_address)), + ]) + .finish() + .unwrap(); + + let (nft_object_id, nft, nft_output, nft_object, nft_output_object) = + migrate_nft(header, stardust_nft.clone()).unwrap(); + let expected_nft = Nft::try_from_stardust(nft_object_id, &stardust_nft).unwrap(); + + // The bag is tested separately. + assert_eq!(stardust_nft.amount(), nft_output.iota.value()); + // The ID is newly generated, so we don't know the exact value, but it should + // not be zero. + assert_ne!(nft_output.id, UID::new(ObjectID::ZERO)); + assert_ne!( + nft_output.id, + UID::new(ObjectID::new( + stardust_nft.nft_id().as_slice().try_into().unwrap() + )) + ); + + assert!(nft_output.storage_deposit_return.is_none()); + assert!(nft_output.expiration.is_none()); + assert!(nft_output.timelock.is_none()); + + assert_eq!(expected_nft, nft); + + // The NFT Object should be in a dynamic object field. + let nft_owner = derive_dynamic_field_id( + nft_output_object.id(), + &TypeTag::from(DynamicFieldInfo::dynamic_object_field_wrapper( + TypeTag::from_str(NFT_DYNAMIC_OBJECT_FIELD_KEY_TYPE).unwrap(), + )), + &bcs::to_bytes(NFT_DYNAMIC_OBJECT_FIELD_KEY).unwrap(), + ) + .unwrap(); + assert_eq!(nft_object.owner, Owner::ObjectOwner(nft_owner.into())); + + let nft_output_owner = + Owner::AddressOwner(stardust_to_iota_address(stardust_nft.address()).unwrap()); + assert_eq!(nft_output_object.owner, nft_output_owner); +} + +/// Test that an Nft with a zeroed ID is migrated to an Nft Object with its UID +/// set to the hashed Output ID. +#[test] +fn nft_migration_with_zeroed_id() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .finish() + .unwrap(); + + // If this function does not panic, then the created NFTs + // were found at the correct non-zeroed Nft ID. + migrate_nft(header, stardust_nft).unwrap(); +} + +#[test] +fn nft_migration_with_alias_owner() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + + let alias_header = random_output_header(); + let alias = AliasOutputBuilder::new_with_amount(2_000_000, AliasId::new(rand::random())) + .add_unlock_condition(StateControllerAddressUnlockCondition::new(random_address)) + .add_unlock_condition(GovernorAddressUnlockCondition::new(random_address)) + .finish() + .unwrap(); + + let nft_header = random_output_header(); + // alias is the owner of nft. + let nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::new(rand::random())) + .add_unlock_condition(AddressUnlockCondition::new(AliasAddress::from( + *alias.alias_id(), + ))) + .finish() + .unwrap(); + + object_migration_with_object_owner( + alias_header.output_id(), + nft_header.output_id(), + [ + (nft_header.clone(), nft.into()), + (alias_header.clone(), alias.into()), + ], + ALIAS_OUTPUT_MODULE_NAME, + NFT_OUTPUT_MODULE_NAME, + ident_str!("unlock_alias_address_owned_nft"), + ) + .unwrap(); +} + +#[test] +fn nft_migration_with_nft_owner() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + + let nft1_header = random_output_header(); + let nft1 = NftOutputBuilder::new_with_amount(1_000_000, NftId::new(rand::random())) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .finish() + .unwrap(); + + let nft2_header = random_output_header(); + // nft1 is the owner of nft2. + let nft2 = NftOutputBuilder::new_with_amount(1_000_000, NftId::new(rand::random())) + .add_unlock_condition(AddressUnlockCondition::new(NftAddress::from( + *nft1.nft_id(), + ))) + .finish() + .unwrap(); + + object_migration_with_object_owner( + nft1_header.output_id(), + nft2_header.output_id(), + [ + (nft1_header.clone(), nft1.into()), + (nft2_header.clone(), nft2.into()), + ], + NFT_OUTPUT_MODULE_NAME, + NFT_OUTPUT_MODULE_NAME, + ident_str!("unlock_nft_address_owned_nft"), + ) + .unwrap(); +} + +/// Test that an NFT that owns Native Tokens can extract those tokens from the +/// contained bag. +#[test] +fn nft_migration_with_native_tokens() { + let (foundry_header, foundry_output) = create_foundry( + 0, + SimpleTokenScheme::new(U256::from(100_000), U256::from(0), U256::from(100_000)).unwrap(), + Irc30Metadata::new("Rustcoin", "Rust", 0), + AliasId::null(), + ) + .unwrap(); + let native_token = NativeToken::new(foundry_output.id().into(), 100_000).unwrap(); + + let nft_header = random_output_header(); + let nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::new(rand::random())) + .add_unlock_condition(AddressUnlockCondition::new(Ed25519Address::from( + rand::random::<[u8; Ed25519Address::LENGTH]>(), + ))) + .add_native_token(native_token) + .finish() + .unwrap(); + + extract_native_token_from_bag( + nft_header.output_id(), + [ + (nft_header.clone(), nft.into()), + (foundry_header, foundry_output.into()), + ], + NFT_OUTPUT_MODULE_NAME, + native_token, + ExpectedAssets::BalanceBagObject, + ) + .unwrap(); +} + +#[test] +fn nft_migration_with_valid_irc27_metadata() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let random_address2 = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + let hrp = Hrp::from_str_unchecked("atoi"); + let mut attributes = BTreeSet::new(); + attributes.insert(Attribute::new("planet", "earth")); + attributes.insert(Attribute::new("languages", vec!["english", "rust"])); + + let mut royalties = BTreeMap::new(); + royalties.insert(random_address.to_bech32(hrp), 10.0); + royalties.insert(random_address2.to_bech32(hrp), 5.0); + + let metadata = iota_sdk::types::block::output::feature::Irc27Metadata::new( + "image/png", + "https://nft.org/nft.png".parse().unwrap(), + "NFT", + ) + .with_issuer_name("issuer_name") + .with_collection_name("collection_name") + .with_royalties(royalties) + .with_description("description") + .with_attributes(attributes); + + let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::new(rand::random())) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .with_immutable_features(vec![ + Feature::Metadata( + MetadataFeature::new(serde_json::to_vec(&metadata).unwrap()).unwrap(), + ), + Feature::Issuer(IssuerFeature::new(random_address)), + ]) + .finish() + .unwrap(); + + let (_, nft, _, _, _) = migrate_nft(header, stardust_nft.clone()).unwrap(); + + let immutable_metadata = nft.immutable_metadata; + assert_eq!(&immutable_metadata.media_type, metadata.media_type()); + assert_eq!(immutable_metadata.uri.url, metadata.uri().to_string()); + assert_eq!(&immutable_metadata.name, metadata.name()); + assert_eq!(&immutable_metadata.issuer_name, metadata.issuer_name()); + assert_eq!( + &immutable_metadata.collection_name, + metadata.collection_name() + ); + assert_eq!(&immutable_metadata.description, metadata.description()); + + let migrated_royalties = immutable_metadata + .royalties + .contents + .into_iter() + .map(|entry| (entry.key, entry.value)) + .collect::>(); + let converted_royalties = metadata + .royalties() + .iter() + .map(|entry| { + ( + IotaAddress::from_bytes(entry.0.as_ed25519().as_slice()).unwrap(), + FixedPoint32::try_from(*entry.1).unwrap(), + ) + }) + .collect::>(); + + assert_eq!(migrated_royalties, converted_royalties); + + let migrated_attributes = immutable_metadata + .attributes + .contents + .into_iter() + .map(|entry| (entry.key, entry.value)) + .collect::>(); + + let converted_attributes = metadata + .attributes() + .iter() + .map(|entry| (entry.trait_type().to_owned(), entry.value().to_string())) + .collect::>(); + + assert_eq!(migrated_attributes, converted_attributes); +} + +#[test] +fn nft_migration_with_invalid_irc27_metadata() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + let metadata = iota_sdk::types::block::output::feature::Irc27Metadata::new( + "image/png", + "https://nft.org/nft.png".parse().unwrap(), + "NFT", + ); + + let mut metadata = serde_json::to_value(&metadata).unwrap(); + // Make the IRC-27 Metadata invalid by changing the type of the `uri` key. + metadata + .as_object_mut() + .unwrap() + .insert("uri".to_owned(), serde_json::Value::Bool(false)); + let metadata_content = serde_json::to_vec(&metadata).unwrap(); + + let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .with_immutable_features(vec![ + Feature::Metadata(MetadataFeature::new(metadata_content).unwrap()), + Feature::Issuer(IssuerFeature::new(random_address)), + ]) + .finish() + .unwrap(); + + let (_, nft, _, _, _) = migrate_nft(header, stardust_nft.clone()).unwrap(); + + let mut immutable_metadata = nft.immutable_metadata; + let mut non_standard_fields = VecMap { contents: vec![] }; + std::mem::swap( + &mut immutable_metadata.non_standard_fields, + &mut non_standard_fields, + ); + + let non_standard_fields = non_standard_fields + .contents + .into_iter() + .map(|entry| (entry.key, entry.value)) + .collect::>(); + + let converted_metadata = metadata + .as_object() + .unwrap() + .iter() + .map(|entry| (entry.0.to_owned(), entry.1.to_string())) + .collect::>(); + + // Since the metadata is valid JSON, we expect the fields of the object to be in + // the non_standard_fields. + assert_eq!(non_standard_fields, converted_metadata); + + // Since we removed non_standard_fields, the other fields of immutable_metadata + // should be the defaults. + assert_eq!(immutable_metadata, Irc27Metadata::default()); +} + +#[test] +fn nft_migration_with_non_json_metadata() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .with_immutable_features(vec![ + Feature::Metadata(MetadataFeature::new([0xde, 0xca, 0xde]).unwrap()), + Feature::Issuer(IssuerFeature::new(random_address)), + ]) + .finish() + .unwrap(); + + let (_, nft, _, _, _) = migrate_nft(header, stardust_nft.clone()).unwrap(); + + let mut immutable_metadata = nft.immutable_metadata; + let mut non_standard_fields = VecMap { contents: vec![] }; + std::mem::swap( + &mut immutable_metadata.non_standard_fields, + &mut non_standard_fields, + ); + + assert_eq!(non_standard_fields.contents.len(), 1); + let data = non_standard_fields + .contents + .into_iter() + .find_map(|entry| { + if entry.key == "data" { + Some(entry.value) + } else { + None + } + }) + .unwrap(); + + assert_eq!(data, "decade"); + + // Since we removed non_standard_fields, the other fields of immutable_metadata + // should be the defaults. + assert_eq!(immutable_metadata, Irc27Metadata::default()); +} + +#[test] +fn nft_migration_without_metadata() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .with_immutable_features(vec![Feature::Issuer(IssuerFeature::new(random_address))]) + .finish() + .unwrap(); + + let (_, nft, _, _, _) = migrate_nft(header, stardust_nft.clone()).unwrap(); + let immutable_metadata = nft.immutable_metadata; + + assert_eq!(immutable_metadata.non_standard_fields.contents.len(), 0); + + // Since we removed non_standard_fields, the other fields of immutable_metadata + // should be the defaults. + assert_eq!(immutable_metadata, Irc27Metadata::default()); +} + +#[test] +fn nft_migration_with_timelock_unlocked() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + // The epoch timestamp that the executor will use for the test. + let epoch_start_timestamp_ms = 100_000; + + let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .add_unlock_condition( + TimelockUnlockCondition::new(epoch_start_timestamp_ms / 1000).unwrap(), + ) + .finish() + .unwrap(); + + unlock_object_test( + header.output_id(), + [(header, stardust_nft.into())], + // Sender is not important for this test. + &IotaAddress::ZERO, + NFT_OUTPUT_MODULE_NAME, + epoch_start_timestamp_ms as u64, + UnlockObjectTestResult::Success, + ExpectedAssets::BalanceBagObject, + ) + .unwrap(); +} + +#[test] +fn nft_migration_with_timelock_still_locked() { + let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + // The epoch timestamp that the executor will use for the test. + let epoch_start_timestamp_ms = 100_000; + + let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) + .add_unlock_condition(AddressUnlockCondition::new(random_address)) + .add_unlock_condition( + TimelockUnlockCondition::new((epoch_start_timestamp_ms / 1000) + 1).unwrap(), + ) + .finish() + .unwrap(); + + unlock_object_test( + header.output_id(), + [(header, stardust_nft.into())], + // Sender is not important for this test. + &IotaAddress::ZERO, + NFT_OUTPUT_MODULE_NAME, + epoch_start_timestamp_ms as u64, + UnlockObjectTestResult::ERROR_TIMELOCK_NOT_EXPIRED_FAILURE, + ExpectedAssets::BalanceBagObject, + ) + .unwrap(); +} + +/// Test that an NFT with an expired Expiration Unlock Condition can/cannot be +/// unlocked, depending on the TX sender. +#[test] +fn nft_migration_with_expired_unlock_condition() { + let owner = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let return_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let iota_owner_address = stardust_to_iota_address(owner).unwrap(); + let iota_return_address = stardust_to_iota_address(return_address).unwrap(); + let header = random_output_header(); + + // The epoch timestamp that the executor will use for the test. + let epoch_start_timestamp_ms = 100_000; + + // Expiration Timestamp is exactly at the epoch start timestamp -> object is + // expired -> return address can unlock. + let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) + .add_unlock_condition(AddressUnlockCondition::new(owner)) + .add_unlock_condition( + ExpirationUnlockCondition::new(return_address, epoch_start_timestamp_ms / 1000) + .unwrap(), + ) + .finish() + .unwrap(); + + // Owner Address CANNOT unlock. + unlock_object_test( + header.output_id(), + [(header.clone(), stardust_nft.clone().into())], + &iota_owner_address, + NFT_OUTPUT_MODULE_NAME, + epoch_start_timestamp_ms as u64, + UnlockObjectTestResult::ERROR_WRONG_SENDER_FAILURE, + ExpectedAssets::BalanceBagObject, + ) + .unwrap(); + + // Return Address CAN unlock. + unlock_object_test( + header.output_id(), + [(header, stardust_nft.into())], + &iota_return_address, + NFT_OUTPUT_MODULE_NAME, + epoch_start_timestamp_ms as u64, + UnlockObjectTestResult::Success, + ExpectedAssets::BalanceBagObject, + ) + .unwrap(); +} + +/// Test that an NFT with an unexpired Expiration Unlock Condition can/cannot be +/// unlocked, depending on the TX sender. +#[test] +fn nft_migration_with_unexpired_unlock_condition() { + let owner = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let return_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let iota_owner_address = stardust_to_iota_address(owner).unwrap(); + let iota_return_address = stardust_to_iota_address(return_address).unwrap(); + let header = random_output_header(); + + // The epoch timestamp that the executor will use for the test. + let epoch_start_timestamp_ms = 100_000; + + // Expiration Timestamp is after the epoch start timestamp -> object is not + // expired -> owner address can unlock. + let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) + .add_unlock_condition(AddressUnlockCondition::new(owner)) + .add_unlock_condition( + ExpirationUnlockCondition::new(return_address, (epoch_start_timestamp_ms / 1000) + 1) + .unwrap(), + ) + .finish() + .unwrap(); + + // Return Address CANNOT unlock. + unlock_object_test( + header.output_id(), + [(header.clone(), stardust_nft.clone().into())], + &iota_return_address, + NFT_OUTPUT_MODULE_NAME, + epoch_start_timestamp_ms as u64, + UnlockObjectTestResult::ERROR_WRONG_SENDER_FAILURE, + ExpectedAssets::BalanceBagObject, + ) + .unwrap(); + + // Owner Address CAN unlock. + unlock_object_test( + header.output_id(), + [(header, stardust_nft.into())], + &iota_owner_address, + NFT_OUTPUT_MODULE_NAME, + epoch_start_timestamp_ms as u64, + UnlockObjectTestResult::Success, + ExpectedAssets::BalanceBagObject, + ) + .unwrap(); +} + +/// Test that an NFT with a Storage Deposit Return Unlock Condition can be +/// unlocked. +#[test] +fn nft_migration_with_storage_deposit_return_unlock_condition() { + let owner = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let return_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); + let header = random_output_header(); + + let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) + .add_unlock_condition(AddressUnlockCondition::new(owner)) + .add_unlock_condition( + StorageDepositReturnUnlockCondition::new(return_address, 1_000, 1_000_000_000).unwrap(), + ) + .finish() + .unwrap(); + + // Simply test that the unlock with the SDRUC succeeds. + unlock_object_test( + header.output_id(), + [(header.clone(), stardust_nft.clone().into())], + // Sender is not important for this test. + &IotaAddress::ZERO, + NFT_OUTPUT_MODULE_NAME, + // Epoch start time is not important for this test. + 0, + UnlockObjectTestResult::Success, + ExpectedAssets::BalanceBagObject, + ) + .unwrap(); +} diff --git a/crates/iota-genesis-builder/src/stardust/migration/verification/alias.rs b/crates/iota-genesis-builder/src/stardust/migration/verification/alias.rs new file mode 100644 index 00000000000..747f0e62f55 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/migration/verification/alias.rs @@ -0,0 +1,191 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashMap; + +use anyhow::{anyhow, bail, ensure}; +use iota_sdk::types::block::output as stardust; +use iota_types::{ + balance::Balance, + base_types::{IotaAddress, ObjectID}, + dynamic_field::{derive_dynamic_field_id, DynamicFieldInfo, Field}, + in_memory_storage::InMemoryStorage, + object::Owner, + TypeTag, +}; + +use super::util::verify_parent; +use crate::stardust::{ + migration::{ + executor::FoundryLedgerData, + verification::{ + created_objects::CreatedObjects, + util::{ + verify_address_owner, verify_issuer_feature, verify_metadata_feature, + verify_native_tokens, verify_sender_feature, + }, + }, + }, + types::{ + Alias, AliasOutput, ALIAS_DYNAMIC_OBJECT_FIELD_KEY, ALIAS_DYNAMIC_OBJECT_FIELD_KEY_TYPE, + }, +}; + +pub(super) fn verify_alias_output( + output_id: stardust::OutputId, + output: &stardust::AliasOutput, + created_objects: &CreatedObjects, + foundry_data: &HashMap, + storage: &InMemoryStorage, +) -> anyhow::Result<()> { + let alias_id = ObjectID::new(*output.alias_id_non_null(&output_id)); + + let created_output_obj = created_objects.output().and_then(|id| { + storage + .get_object(id) + .ok_or_else(|| anyhow!("missing alias output object")) + })?; + + let created_alias_obj = storage + .get_object(&alias_id) + .ok_or_else(|| anyhow!("missing alias object"))?; + + // Alias Output Owner + verify_address_owner( + output.governor_address(), + created_output_obj, + "alias output", + )?; + + // Alias Owner + let expected_alias_owner = Owner::ObjectOwner( + derive_dynamic_field_id( + created_output_obj.id(), + &DynamicFieldInfo::dynamic_object_field_wrapper( + ALIAS_DYNAMIC_OBJECT_FIELD_KEY_TYPE.parse::()?, + ) + .into(), + &bcs::to_bytes(ALIAS_DYNAMIC_OBJECT_FIELD_KEY)?, + )? + .into(), + ); + + ensure!( + created_alias_obj.owner == expected_alias_owner, + "alias owner mismatch: found {}, expected {}", + created_alias_obj.owner, + expected_alias_owner + ); + + let created_alias = created_alias_obj + .to_rust::() + .ok_or_else(|| anyhow!("invalid alias object"))?; + + let created_output = created_output_obj + .to_rust::() + .ok_or_else(|| anyhow!("invalid alias output object"))?; + + // Amount + ensure!( + created_output.iota.value() == output.amount(), + "amount mismatch: found {}, expected {}", + created_output.iota.value(), + output.amount() + ); + + // Native Tokens + verify_native_tokens::>( + output.native_tokens(), + foundry_data, + created_output.native_tokens, + created_objects.native_tokens().ok(), + storage, + )?; + + // Legacy State Controller + let expected_state_controller = output + .state_controller_address() + .to_string() + .parse::()?; + ensure!( + created_alias.legacy_state_controller == expected_state_controller, + "legacy state controller mismatch: found {}, expected {}", + created_alias.legacy_state_controller, + expected_state_controller + ); + + // State Index + ensure!( + created_alias.state_index == output.state_index(), + "state index mismatch: found {}, expected {}", + created_alias.state_index, + output.state_index() + ); + + // State Metadata + if output.state_metadata().is_empty() { + ensure!( + created_alias.state_metadata.is_none(), + "unexpected state metadata found" + ); + } else { + let Some(state_metadata) = created_alias.state_metadata.as_ref() else { + bail!("missing state metadata") + }; + + ensure!( + state_metadata.as_slice() == output.state_metadata(), + "state metadata mismatch: found {:?}, expected {:?}", + state_metadata, + output.state_metadata() + ); + } + + // Sender Feature + verify_sender_feature(output.features().sender(), created_alias.sender)?; + + // Metadata Feature + verify_metadata_feature( + output.features().metadata(), + created_alias.metadata.as_ref(), + )?; + + // Immutable Issuer Feature + verify_issuer_feature( + output.immutable_features().issuer(), + created_alias.immutable_issuer, + )?; + + // Immutable Metadata Feature + verify_metadata_feature( + output.immutable_features().metadata(), + created_alias.immutable_metadata.as_ref(), + )?; + + verify_parent(output.governor_address(), storage)?; + + ensure!(created_objects.coin().is_err(), "unexpected coin found"); + + ensure!( + created_objects.coin_metadata().is_err(), + "unexpected coin metadata found" + ); + + ensure!( + created_objects.minted_coin().is_err(), + "unexpected minted coin found" + ); + + ensure!( + created_objects.max_supply_policy().is_err(), + "unexpected max supply policy found" + ); + + ensure!( + created_objects.package().is_err(), + "unexpected package found" + ); + + Ok(()) +} diff --git a/crates/iota-genesis-builder/src/stardust/migration/verification/basic.rs b/crates/iota-genesis-builder/src/stardust/migration/verification/basic.rs new file mode 100644 index 00000000000..009e34799a7 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/migration/verification/basic.rs @@ -0,0 +1,178 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashMap; + +use anyhow::{anyhow, ensure, Result}; +use iota_sdk::types::block::output::{BasicOutput, OutputId, TokenId}; +use iota_types::{ + balance::Balance, coin::Coin, dynamic_field::Field, in_memory_storage::InMemoryStorage, + timelock::timelock::TimeLock, TypeTag, +}; + +use crate::stardust::{ + migration::{ + executor::FoundryLedgerData, + verification::{ + created_objects::CreatedObjects, + util::{ + verify_address_owner, verify_coin, verify_expiration_unlock_condition, + verify_metadata_feature, verify_native_tokens, verify_parent, + verify_sender_feature, verify_storage_deposit_unlock_condition, verify_tag_feature, + verify_timelock_unlock_condition, + }, + }, + }, + types::timelock::is_timelocked_vested_reward, +}; + +pub(super) fn verify_basic_output( + output_id: OutputId, + output: &BasicOutput, + created_objects: &CreatedObjects, + foundry_data: &HashMap, + target_milestone_timestamp: u32, + storage: &InMemoryStorage, +) -> Result<()> { + // If this is a timelocked vested reward, a `Timelock` is created. + if is_timelocked_vested_reward(output_id, output, target_milestone_timestamp) { + let created_timelock = created_objects + .output() + .and_then(|id| { + storage + .get_object(id) + .ok_or_else(|| anyhow!("missing timelock object")) + })? + .to_rust::>() + .ok_or_else(|| anyhow!("invalid timelock object"))?; + + // Locked timestamp + ensure!( + created_timelock.expiration_timestamp_ms == target_milestone_timestamp as u64, + "timelock timestamp mismatch: found {}, expected {}", + created_timelock.expiration_timestamp_ms, + target_milestone_timestamp + ); + + // Amount + ensure!( + created_timelock.locked.value() == output.amount(), + "locked amount mismatch: found {}, expected {}", + created_timelock.locked.value(), + output.amount() + ); + + return Ok(()); + } + + // If the output has multiple unlock conditions, then a genesis object should + // have been created. + if output.unlock_conditions().len() > 1 { + ensure!(created_objects.coin().is_err(), "unexpected coin created"); + + let created_output_obj = created_objects.output().and_then(|id| { + storage + .get_object(id) + .ok_or_else(|| anyhow!("missing basic output object")) + })?; + let created_output = created_output_obj + .to_rust::() + .ok_or_else(|| anyhow!("invalid basic output object"))?; + + // Owner + verify_address_owner(output.address(), created_output_obj, "basic output")?; + + // Amount + ensure!( + created_output.iota.value() == output.amount(), + "amount mismatch: found {}, expected {}", + created_output.iota.value(), + output.amount() + ); + + // Native Tokens + verify_native_tokens::>( + output.native_tokens(), + foundry_data, + created_output.native_tokens, + created_objects.native_tokens().ok(), + storage, + )?; + + // Storage Deposit Return Unlock Condition + verify_storage_deposit_unlock_condition( + output.unlock_conditions().storage_deposit_return(), + created_output.storage_deposit_return.as_ref(), + )?; + + // Timelock Unlock Condition + verify_timelock_unlock_condition( + output.unlock_conditions().timelock(), + created_output.timelock.as_ref(), + )?; + + // Expiration Unlock Condition + verify_expiration_unlock_condition( + output.unlock_conditions().expiration(), + created_output.expiration.as_ref(), + output.address(), + )?; + + // Metadata Feature + verify_metadata_feature( + output.features().metadata(), + created_output.metadata.as_ref(), + )?; + + // Tag Feature + verify_tag_feature(output.features().tag(), created_output.tag.as_ref())?; + + // Sender Feature + verify_sender_feature(output.features().sender(), created_output.sender)?; + + // Otherwise the output contains only an address unlock condition and only a + // coin and possibly native tokens should have been created. + } else { + ensure!( + created_objects.output().is_err(), + "unexpected output object created for simple deposit" + ); + + // Coin value and owner + verify_coin(output.amount(), output.address(), created_objects, storage)?; + + // Native Tokens + verify_native_tokens::<(TypeTag, Coin)>( + output.native_tokens(), + foundry_data, + None, + created_objects.native_tokens().ok(), + storage, + )?; + } + + verify_parent(output.address(), storage)?; + + ensure!( + created_objects.coin_metadata().is_err(), + "unexpected coin metadata found" + ); + + ensure!( + created_objects.minted_coin().is_err(), + "unexpected minted coin found" + ); + + ensure!( + created_objects.max_supply_policy().is_err(), + "unexpected max supply policy found" + ); + + ensure!( + created_objects.package().is_err(), + "unexpected package found" + ); + + Ok(()) +} diff --git a/crates/sui-genesis-builder/src/stardust/migration/verification/created_objects.rs b/crates/iota-genesis-builder/src/stardust/migration/verification/created_objects.rs similarity index 97% rename from crates/sui-genesis-builder/src/stardust/migration/verification/created_objects.rs rename to crates/iota-genesis-builder/src/stardust/migration/verification/created_objects.rs index fcc5cbb49f9..4da7b63d089 100644 --- a/crates/sui-genesis-builder/src/stardust/migration/verification/created_objects.rs +++ b/crates/iota-genesis-builder/src/stardust/migration/verification/created_objects.rs @@ -1,8 +1,9 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::{anyhow, bail, Result}; -use sui_types::base_types::ObjectID; +use iota_types::base_types::ObjectID; /// Defines objects that may have been created by migrating an [`Output`]. #[derive(Default)] diff --git a/crates/iota-genesis-builder/src/stardust/migration/verification/foundry.rs b/crates/iota-genesis-builder/src/stardust/migration/verification/foundry.rs new file mode 100644 index 00000000000..b08d8eea851 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/migration/verification/foundry.rs @@ -0,0 +1,227 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashMap; + +use anyhow::{anyhow, ensure, Result}; +use iota_sdk::types::block::output::{FoundryOutput, TokenId}; +use iota_types::{ + base_types::IotaAddress, coin::CoinMetadata, in_memory_storage::InMemoryStorage, object::Owner, + Identifier, +}; +use move_core_types::language_storage::ModuleId; + +use crate::stardust::{ + migration::{ + executor::FoundryLedgerData, + verification::{ + util::{ + truncate_to_max_allowed_u64_supply, verify_address_owner, verify_coin, + verify_parent, + }, + CreatedObjects, + }, + }, + native_token::package_data::NativeTokenPackageData, + types::{capped_coin::MaxSupplyPolicy, token_scheme::SimpleTokenSchemeU64}, +}; + +pub(super) fn verify_foundry_output( + output: &FoundryOutput, + created_objects: &CreatedObjects, + foundry_data: &HashMap, + storage: &InMemoryStorage, +) -> Result<()> { + let foundry_data = foundry_data + .get(&output.token_id()) + .ok_or_else(|| anyhow!("missing foundry data"))?; + + let alias_address = output + .unlock_conditions() + .immutable_alias_address() + .expect("foundry outputs always have an immutable alias address") + .address(); + + // Coin value and owner + verify_coin(output.amount(), alias_address, created_objects, storage)?; + + // Minted coin value + let minted_coin_id = created_objects.minted_coin()?; + let minted_coin_obj = storage + .get_object(minted_coin_id) + .ok_or_else(|| anyhow!("missing coin"))?; + let minted_coin = minted_coin_obj + .as_coin_maybe() + .ok_or_else(|| anyhow!("expected a coin"))?; + + // Minted coins are transferred to `0x0` + let expected_owner = Owner::AddressOwner(SuiAddress::default()); + ensure!( + minted_coin_obj.owner == expected_owner, + "minted coin owner mismatch: found {}, expected {}", + minted_coin_obj.owner, + expected_owner + ); + + ensure!( + foundry_data.minted_coin_id == *minted_coin_id, + "coin ID mismatch: found {}, expected {}", + foundry_data.minted_coin_id, + minted_coin_id + ); + + ensure!( + minted_coin.value() == foundry_data.minted_value, + "minted coin amount mismatch: found {}, expected {}", + minted_coin.value(), + foundry_data.minted_value + ); + + // Package + let package_id = created_objects.package()?; + let created_package = storage + .get_object(package_id) + .ok_or_else(|| anyhow!("missing package"))? + .data + .try_as_package() + .ok_or_else(|| anyhow!("expected a package"))?; + + ensure!( + foundry_data.package_id == *package_id, + "foundry data package ID mismatch: found {}, expected {}", + foundry_data.package_id, + package_id + ); + + let expected_package_data = NativeTokenPackageData::try_from(output)?; + + let module_id = ModuleId::new( + created_package.id().into(), + Identifier::new(expected_package_data.module().module_name.as_ref())?, + ); + + ensure!( + created_package.get_module(&module_id).is_some(), + "package did not create expected module `{}`", + expected_package_data.module().module_name + ); + + let type_origin_map = created_package.type_origin_map(); + + ensure!( + type_origin_map.contains_key(&( + expected_package_data.module().module_name.clone(), + expected_package_data.module().otw_name.clone() + )), + "package did not create expected OTW type `{}` within module `{}`", + expected_package_data.module().otw_name, + expected_package_data.module().module_name, + ); + ensure!( + foundry_data.coin_type_origin.module_name == expected_package_data.module().module_name, + "foundry data module name mismatch: found {}, expected {}", + foundry_data.coin_type_origin.module_name, + expected_package_data.module().module_name + ); + ensure!( + foundry_data.coin_type_origin.struct_name == expected_package_data.module().otw_name, + "foundry data OTW struct name mismatch: found {}, expected {}", + foundry_data.coin_type_origin.struct_name, + expected_package_data.module().otw_name + ); + + // Adjusted Token Scheme + let expected_token_scheme_u64 = + SimpleTokenSchemeU64::try_from(output.token_scheme().as_simple())?; + ensure!( + expected_token_scheme_u64 == foundry_data.token_scheme_u64, + "foundry data token scheme mismatch: found {:?}, expected: {:?}", + foundry_data.token_scheme_u64, + expected_token_scheme_u64 + ); + + // Coin Metadata + let minted_coin = created_objects + .coin_metadata() + .and_then(|id| { + storage + .get_object(id) + .ok_or_else(|| anyhow!("missing coin metadata")) + })? + .to_rust::() + .ok_or_else(|| anyhow!("expected a coin metadata"))?; + + ensure!( + minted_coin.decimals == expected_package_data.module().decimals, + "coin decimals mismatch: expected {}, found {}", + expected_package_data.module().decimals, + minted_coin.decimals + ); + ensure!( + minted_coin.name == expected_package_data.module().coin_name, + "coin name mismatch: expected {}, found {}", + expected_package_data.module().coin_name, + minted_coin.name + ); + ensure!( + minted_coin.symbol == expected_package_data.module().symbol, + "coin symbol mismatch: expected {}, found {}", + expected_package_data.module().symbol, + minted_coin.symbol + ); + ensure!( + minted_coin.description == expected_package_data.module().coin_description, + "coin description mismatch: expected {}, found {}", + expected_package_data.module().coin_description, + minted_coin.description + ); + ensure!( + minted_coin.icon_url + == expected_package_data + .module() + .icon_url + .as_ref() + .map(|u| u.to_string()), + "coin icon url mismatch: expected {:?}, found {:?}", + expected_package_data.module().icon_url, + minted_coin.icon_url + ); + + // Maximum Supply + let max_supply_policy_obj = created_objects.max_supply_policy().and_then(|id| { + storage + .get_object(id) + .ok_or_else(|| anyhow!("missing max supply policy")) + })?; + let max_supply_policy = max_supply_policy_obj + .to_rust::() + .ok_or_else(|| anyhow!("expected a max supply policy"))?; + + ensure!( + max_supply_policy.maximum_supply == expected_package_data.module().maximum_supply, + "maximum supply mismatch: expected {}, found {}", + expected_package_data.module().maximum_supply, + max_supply_policy.maximum_supply + ); + let circulating_supply = + truncate_to_max_allowed_u64_supply(output.token_scheme().as_simple().circulating_supply()); + ensure!( + max_supply_policy.treasury_cap.total_supply.value == circulating_supply, + "treasury total supply mismatch: found {}, expected {}", + max_supply_policy.treasury_cap.total_supply.value, + circulating_supply + ); + + // Alias Address Unlock Condition + verify_address_owner(alias_address, max_supply_policy_obj, "max supply policy")?; + + verify_parent(alias_address, storage)?; + + ensure!( + created_objects.output().is_err(), + "unexpected output object found" + ); + + Ok(()) +} diff --git a/crates/iota-genesis-builder/src/stardust/migration/verification/mod.rs b/crates/iota-genesis-builder/src/stardust/migration/verification/mod.rs new file mode 100644 index 00000000000..2feb5937d6a --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/migration/verification/mod.rs @@ -0,0 +1,85 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! The [`verification`] module contains the validation logic to make sure that +//! the stardust outputs are correctly converted to the move objects. + +use std::collections::HashMap; + +use anyhow::anyhow; +use iota_sdk::types::block::output::{Output, OutputId, TokenId}; +use iota_types::in_memory_storage::InMemoryStorage; + +use self::created_objects::CreatedObjects; +use crate::stardust::{migration::executor::FoundryLedgerData, types::snapshot::OutputHeader}; + +pub mod alias; +pub mod basic; +pub mod created_objects; +pub mod foundry; +pub mod nft; +mod util; + +pub(crate) fn verify_outputs<'a>( + outputs: impl IntoIterator, + output_objects_map: &HashMap, + foundry_data: &HashMap, + target_milestone_timestamp: u32, + storage: &InMemoryStorage, +) -> anyhow::Result<()> { + for (header, output) in outputs { + let created_objects = output_objects_map + .get(&header.output_id()) + .ok_or_else(|| anyhow!("missing created objects for output {}", header.output_id()))?; + verify_output( + header, + output, + created_objects, + foundry_data, + target_milestone_timestamp, + storage, + )?; + } + Ok(()) +} + +fn verify_output( + header: &OutputHeader, + output: &Output, + created_objects: &CreatedObjects, + foundry_data: &HashMap, + target_milestone_timestamp: u32, + storage: &InMemoryStorage, +) -> anyhow::Result<()> { + match output { + Output::Alias(output) => alias::verify_alias_output( + header.output_id(), + output, + created_objects, + foundry_data, + storage, + ), + Output::Basic(output) => basic::verify_basic_output( + header.output_id(), + output, + created_objects, + foundry_data, + target_milestone_timestamp, + storage, + ), + Output::Foundry(output) => { + foundry::verify_foundry_output(output, created_objects, foundry_data, storage) + } + Output::Nft(output) => nft::verify_nft_output( + header.output_id(), + output, + created_objects, + foundry_data, + storage, + ), + // Treasury outputs aren't used since Stardust, so no need to verify anything here. + Output::Treasury(_) => return Ok(()), + } + .map_err(|e| anyhow!("error verifying output {}: {}", header.output_id(), e)) +} diff --git a/crates/iota-genesis-builder/src/stardust/migration/verification/nft.rs b/crates/iota-genesis-builder/src/stardust/migration/verification/nft.rs new file mode 100644 index 00000000000..7ce499de6fa --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/migration/verification/nft.rs @@ -0,0 +1,174 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashMap; + +use anyhow::{anyhow, ensure}; +use iota_sdk::types::block::output::{NftOutput, OutputId, TokenId}; +use iota_types::{ + balance::Balance, + base_types::ObjectID, + dynamic_field::{derive_dynamic_field_id, DynamicFieldInfo, Field}, + in_memory_storage::InMemoryStorage, + object::Owner, + TypeTag, +}; + +use crate::stardust::{ + migration::{ + executor::FoundryLedgerData, + verification::{ + created_objects::CreatedObjects, + util::{ + verify_address_owner, verify_expiration_unlock_condition, verify_issuer_feature, + verify_metadata_feature, verify_native_tokens, verify_parent, + verify_sender_feature, verify_storage_deposit_unlock_condition, verify_tag_feature, + verify_timelock_unlock_condition, + }, + }, + }, + types::{NFT_DYNAMIC_OBJECT_FIELD_KEY, NFT_DYNAMIC_OBJECT_FIELD_KEY_TYPE}, +}; + +pub(super) fn verify_nft_output( + output_id: OutputId, + output: &NftOutput, + created_objects: &CreatedObjects, + foundry_data: &HashMap, + storage: &InMemoryStorage, +) -> anyhow::Result<()> { + let created_output_obj = created_objects.output().and_then(|id| { + storage + .get_object(id) + .ok_or_else(|| anyhow!("missing nft output object for {output_id}")) + })?; + let created_output = created_output_obj + .to_rust::() + .ok_or_else(|| anyhow!("invalid nft output object for {output_id}"))?; + + let created_nft_obj = storage + .get_object(&ObjectID::new(*output.nft_id_non_null(&output_id))) + .ok_or_else(|| anyhow!("missing nft object for {output_id}"))?; + let created_nft = created_nft_obj + .to_rust::() + .ok_or_else(|| anyhow!("invalid nft object for {output_id}"))?; + + // Output Owner + // If there is an expiration unlock condition, the NFT is shared. + if output.unlock_conditions().expiration().is_some() { + ensure!( + matches!(created_output_obj.owner, Owner::Shared { .. }), + "nft output owner mismatch: found {:?}, expected Shared", + created_output_obj.owner, + ); + } else { + verify_address_owner(output.address(), created_output_obj, "nft output")?; + } + + // NFT Owner + let expected_nft_owner = Owner::ObjectOwner( + derive_dynamic_field_id( + created_output_obj.id(), + &DynamicFieldInfo::dynamic_object_field_wrapper( + NFT_DYNAMIC_OBJECT_FIELD_KEY_TYPE.parse::()?, + ) + .into(), + &bcs::to_bytes(NFT_DYNAMIC_OBJECT_FIELD_KEY)?, + )? + .into(), + ); + + ensure!( + created_nft_obj.owner == expected_nft_owner, + "nft owner mismatch: found {}, expected {}", + created_nft_obj.owner, + expected_nft_owner + ); + + // Amount + ensure!( + created_output.iota.value() == output.amount(), + "amount mismatch: found {}, expected {}", + created_output.iota.value(), + output.amount() + ); + + // Native Tokens + verify_native_tokens::>( + output.native_tokens(), + foundry_data, + created_output.native_tokens, + created_objects.native_tokens().ok(), + storage, + )?; + + // Storage Deposit Return Unlock Condition + verify_storage_deposit_unlock_condition( + output.unlock_conditions().storage_deposit_return(), + created_output.storage_deposit_return.as_ref(), + )?; + + // Timelock Unlock Condition + verify_timelock_unlock_condition( + output.unlock_conditions().timelock(), + created_output.timelock.as_ref(), + )?; + + // Expiration Unlock Condition + verify_expiration_unlock_condition( + output.unlock_conditions().expiration(), + created_output.expiration.as_ref(), + output.address(), + )?; + + // Metadata Feature + verify_metadata_feature(output.features().metadata(), created_nft.metadata.as_ref())?; + + // Tag Feature + verify_tag_feature(output.features().tag(), created_nft.tag.as_ref())?; + + // Sender Feature + verify_sender_feature(output.features().sender(), created_nft.legacy_sender)?; + + // Issuer Feature + verify_issuer_feature( + output.immutable_features().issuer(), + created_nft.immutable_issuer, + )?; + + // Immutable Metadata Feature + ensure!( + crate::stardust::types::Nft::convert_immutable_metadata(output)? + == created_nft.immutable_metadata, + "metadata mismatch: found {:x?}, expected {:x?}", + crate::stardust::types::Nft::convert_immutable_metadata(output)?, + created_nft.immutable_metadata + ); + + verify_parent(output.address(), storage)?; + + ensure!(created_objects.coin().is_err(), "unexpected coin found"); + + ensure!( + created_objects.coin_metadata().is_err(), + "unexpected coin metadata found" + ); + + ensure!( + created_objects.minted_coin().is_err(), + "unexpected minted coin found" + ); + + ensure!( + created_objects.max_supply_policy().is_err(), + "unexpected max supply policy found" + ); + + ensure!( + created_objects.package().is_err(), + "unexpected package found" + ); + + Ok(()) +} diff --git a/crates/iota-genesis-builder/src/stardust/migration/verification/util.rs b/crates/iota-genesis-builder/src/stardust/migration/verification/util.rs new file mode 100644 index 00000000000..ec17358eb8d --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/migration/verification/util.rs @@ -0,0 +1,396 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashMap; + +use anyhow::{anyhow, bail, ensure, Result}; +use iota_sdk::{ + types::block::{ + address::Address, + output::{self as sdk_output, NativeTokens, TokenId}, + }, + U256, +}; +use iota_types::{ + balance::Balance, + base_types::{IotaAddress, ObjectID}, + coin::Coin, + collection_types::Bag, + dynamic_field::Field, + in_memory_storage::InMemoryStorage, + object::Object, + TypeTag, +}; + +use crate::stardust::{ + migration::{executor::FoundryLedgerData, verification::CreatedObjects}, + types::{ + output as migration_output, stardust_to_sui_address, stardust_to_sui_address_owner, + token_scheme::MAX_ALLOWED_U64_SUPPLY, Alias, Nft, + }, +}; + +pub(super) fn verify_native_tokens( + native_tokens: &NativeTokens, + foundry_data: &HashMap, + native_tokens_bag: impl Into>, + created_native_tokens: Option<&[ObjectID]>, + storage: &InMemoryStorage, +) -> Result<()> { + // Token types should be unique as the token ID is guaranteed unique within + // NativeTokens + let created_native_tokens = created_native_tokens + .map(|object_ids| { + object_ids + .iter() + .map(|id| { + let obj = storage + .get_object(id) + .ok_or_else(|| anyhow!("missing native token field for {id}"))?; + NtKind::from_object(obj).map(|nt| (nt.token_type(), nt.value())) + }) + .collect::, _>>() + }) + .unwrap_or(Ok(HashMap::new()))?; + + ensure!( + created_native_tokens.len() == native_tokens.len(), + "native token count mismatch: found {}, expected: {}", + created_native_tokens.len(), + native_tokens.len(), + ); + + if let Some(native_tokens_bag) = native_tokens_bag.into() { + ensure!( + native_tokens_bag.size == native_tokens.len() as u64, + "native tokens bag length mismatch: found {}, expected {}", + native_tokens_bag.size, + native_tokens.len() + ); + } + + for native_token in native_tokens.iter() { + let foundry_data = foundry_data + .get(native_token.token_id()) + .ok_or_else(|| anyhow!("missing foundry data for token {}", native_token.token_id()))?; + + let expected_token_type = foundry_data.canonical_coin_type(); + // The token amounts are scaled so that the total circulating supply does not + // exceed `u64::MAX` + let reduced_amount = foundry_data + .token_scheme_u64 + .adjust_tokens(native_token.amount()); + + if let Some(created_value) = created_native_tokens.get(&expected_token_type) { + ensure!( + *created_value == reduced_amount, + "created token amount mismatch: found {created_value}, expected {reduced_amount}" + ); + } else { + bail!( + "native token object was not created for token: {}", + native_token.token_id() + ); + } + } + + Ok(()) +} + +pub(super) fn verify_storage_deposit_unlock_condition( + original: Option<&sdk_output::unlock_condition::StorageDepositReturnUnlockCondition>, + created: Option<&migration_output::StorageDepositReturnUnlockCondition>, +) -> Result<()> { + // Storage Deposit Return Unlock Condition + if let Some(sdruc) = original { + let iota_return_address = stardust_to_iota_address(sdruc.return_address())?; + if let Some(obj_sdruc) = created { + ensure!( + obj_sdruc.return_address == iota_return_address, + "storage deposit return address mismatch: found {}, expected {}", + obj_sdruc.return_address, + iota_return_address + ); + ensure!( + obj_sdruc.return_amount == sdruc.amount(), + "storage deposit return amount mismatch: found {}, expected {}", + obj_sdruc.return_amount, + sdruc.amount() + ); + } else { + bail!("missing storage deposit return on object"); + } + } else { + ensure!( + created.is_none(), + "erroneous storage deposit return on object" + ); + } + Ok(()) +} + +pub(super) fn verify_timelock_unlock_condition( + original: Option<&sdk_output::unlock_condition::TimelockUnlockCondition>, + created: Option<&migration_output::TimelockUnlockCondition>, +) -> Result<()> { + // Timelock Unlock Condition + if let Some(timelock) = original { + if let Some(obj_timelock) = created { + ensure!( + obj_timelock.unix_time == timelock.timestamp(), + "timelock timestamp mismatch: found {}, expected {}", + obj_timelock.unix_time, + timelock.timestamp() + ); + } else { + bail!("missing timelock on object"); + } + } else { + ensure!(created.is_none(), "erroneous timelock on object"); + } + Ok(()) +} + +pub(super) fn verify_expiration_unlock_condition( + original: Option<&sdk_output::unlock_condition::ExpirationUnlockCondition>, + created: Option<&migration_output::ExpirationUnlockCondition>, + address: &Address, +) -> Result<()> { + // Expiration Unlock Condition + if let Some(expiration) = original { + if let Some(obj_expiration) = created { + let iota_address = stardust_to_iota_address(address)?; + let iota_return_address = stardust_to_iota_address(expiration.return_address())?; + ensure!( + obj_expiration.owner == iota_address, + "expiration owner mismatch: found {}, expected {}", + obj_expiration.owner, + iota_address + ); + ensure!( + obj_expiration.return_address == iota_return_address, + "expiration return address mismatch: found {}, expected {}", + obj_expiration.return_address, + iota_return_address + ); + ensure!( + obj_expiration.unix_time == expiration.timestamp(), + "expiration timestamp mismatch: found {}, expected {}", + obj_expiration.unix_time, + expiration.timestamp() + ); + } else { + bail!("missing expiration on object"); + } + } else { + ensure!(created.is_none(), "erroneous expiration on object"); + } + Ok(()) +} + +pub(super) fn verify_metadata_feature( + original: Option<&sdk_output::feature::MetadataFeature>, + created: Option<&Vec>, +) -> Result<()> { + if let Some(metadata) = original { + if let Some(obj_metadata) = created { + ensure!( + obj_metadata.as_slice() == metadata.data(), + "metadata mismatch: found {:x?}, expected {:x?}", + obj_metadata.as_slice(), + metadata.data() + ); + } else { + bail!("missing metadata on object"); + } + } else { + ensure!(created.is_none(), "erroneous metadata on object"); + } + Ok(()) +} + +pub(super) fn verify_tag_feature( + original: Option<&sdk_output::feature::TagFeature>, + created: Option<&Vec>, +) -> Result<()> { + if let Some(tag) = original { + if let Some(obj_tag) = created { + ensure!( + obj_tag.as_slice() == tag.tag(), + "tag mismatch: found {:x?}, expected {:x?}", + obj_tag.as_slice(), + tag.tag() + ); + } else { + bail!("missing tag on object"); + } + } else { + ensure!(created.is_none(), "erroneous tag on object"); + } + Ok(()) +} + +pub(super) fn verify_sender_feature( + original: Option<&sdk_output::feature::SenderFeature>, + created: Option, +) -> Result<()> { + if let Some(sender) = original { + let iota_sender_address = stardust_to_iota_address(sender.address())?; + if let Some(obj_sender) = created { + ensure!( + obj_sender == iota_sender_address, + "sender mismatch: found {}, expected {}", + obj_sender, + iota_sender_address + ); + } else { + bail!("missing sender on object"); + } + } else { + ensure!(created.is_none(), "erroneous sender on object"); + } + Ok(()) +} + +pub(super) fn verify_issuer_feature( + original: Option<&sdk_output::feature::IssuerFeature>, + created: Option, +) -> Result<()> { + if let Some(issuer) = original { + let iota_issuer_address = stardust_to_iota_address(issuer.address())?; + if let Some(obj_issuer) = created { + ensure!( + obj_issuer == iota_issuer_address, + "issuer mismatch: found {}, expected {}", + obj_issuer, + iota_issuer_address + ); + } else { + bail!("missing issuer on object"); + } + } else { + ensure!(created.is_none(), "erroneous issuer on object"); + } + Ok(()) +} + +pub(super) fn verify_address_owner( + owning_address: &Address, + obj: &Object, + name: &str, +) -> Result<()> { + let expected_owner = stardust_to_sui_address_owner(owning_address)?; + ensure!( + obj.owner == expected_owner, + "{name} owner mismatch: found {}, expected {}", + obj.owner, + expected_owner + ); + Ok(()) +} + +// Checks whether an object exists for this address and whether it is the +// expected alias or nft object. We do not expect an object for Ed25519 +// addresses. +pub(super) fn verify_parent(address: &Address, storage: &InMemoryStorage) -> Result<()> { + let object_id = ObjectID::from(stardust_to_iota_address(address)?); + let parent = storage.get_object(&object_id); + match address { + Address::Alias(address) => { + if let Some(parent_obj) = parent { + parent_obj + .to_rust::() + .ok_or_else(|| anyhow!("invalid alias object for {address}"))?; + } + } + Address::Nft(address) => { + if let Some(parent_obj) = parent { + parent_obj + .to_rust::() + .ok_or_else(|| anyhow!("invalid nft object for {address}"))?; + } + } + Address::Ed25519(address) => { + ensure!( + parent.is_none(), + "unexpected parent found for ed25519 address {address}", + ); + } + } + Ok(()) +} + +pub(super) fn verify_coin( + output_amount: u64, + owning_address: &Address, + created_objects: &CreatedObjects, + storage: &InMemoryStorage, +) -> Result<()> { + let created_coin_obj = created_objects.coin().and_then(|id| { + storage + .get_object(id) + .ok_or_else(|| anyhow!("missing coin")) + })?; + let created_coin = created_coin_obj + .as_coin_maybe() + .ok_or_else(|| anyhow!("expected a coin"))?; + + ensure!( + created_coin.value() == output_amount, + "coin amount mismatch: found {}, expected {}", + created_coin.value(), + output_amount + ); + + verify_address_owner(owning_address, created_coin_obj, "coin") +} + +pub(super) trait NativeTokenKind { + fn token_type(&self) -> String; + + fn value(&self) -> u64; + + fn from_object(obj: &Object) -> Result + where + Self: Sized; +} + +impl NativeTokenKind for (TypeTag, Coin) { + fn token_type(&self) -> String { + self.0.to_canonical_string(true) + } + + fn value(&self) -> u64 { + self.1.value() + } + + fn from_object(obj: &Object) -> Result { + obj.coin_type_maybe() + .zip(obj.as_coin_maybe()) + .ok_or_else(|| anyhow!("expected a native token coin, found {:?}", obj.type_())) + } +} + +impl NativeTokenKind for Field { + fn token_type(&self) -> String { + self.name.clone() + } + + fn value(&self) -> u64 { + self.value.value() + } + + fn from_object(obj: &Object) -> Result { + obj.to_rust::>() + .ok_or_else(|| anyhow!("expected a native token field, found {:?}", obj.type_())) + } +} + +pub fn truncate_to_max_allowed_u64_supply(value: U256) -> u64 { + if value > U256::from(MAX_ALLOWED_U64_SUPPLY) { + MAX_ALLOWED_U64_SUPPLY + } else { + value.as_u64() + } +} diff --git a/crates/iota-genesis-builder/src/stardust/mod.rs b/crates/iota-genesis-builder/src/stardust/mod.rs new file mode 100644 index 00000000000..f5c231314a5 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/mod.rs @@ -0,0 +1,13 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! The [`stardust`] module incorporates all the logic necessary for +//! parsing Stardust UTXOs from a full-snapshot file, and converting +//! them to the appropriate genesis objects. + +pub mod error; +pub mod migration; +pub mod native_token; +pub mod parse; +pub mod types; diff --git a/crates/iota-genesis-builder/src/stardust/native_token/mod.rs b/crates/iota-genesis-builder/src/stardust/native_token/mod.rs new file mode 100644 index 00000000000..dfe6145ba59 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/native_token/mod.rs @@ -0,0 +1,9 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! The [`native_token`] module incorporates all the logic necessary for +//! building Stardust native token modules and packages. + +pub mod package_builder; +pub mod package_data; diff --git a/crates/sui-genesis-builder/src/stardust/native_token/package_builder.rs b/crates/iota-genesis-builder/src/stardust/native_token/package_builder.rs similarity index 96% rename from crates/sui-genesis-builder/src/stardust/native_token/package_builder.rs rename to crates/iota-genesis-builder/src/stardust/native_token/package_builder.rs index d2999376e29..8ec0d3d715d 100644 --- a/crates/sui-genesis-builder/src/stardust/native_token/package_builder.rs +++ b/crates/iota-genesis-builder/src/stardust/native_token/package_builder.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! The [`package_builder`] module provides the [`PackageBuilder`] struct, which @@ -10,7 +11,7 @@ use std::{ use anyhow::Result; use fs_extra::dir::{copy, CopyOptions}; -use sui_move_build::{BuildConfig, CompiledPackage, SuiPackageHooks}; +use iota_move_build::{BuildConfig, CompiledPackage, IotaPackageHooks}; use tempfile::tempdir; use crate::stardust::{error::StardustError, native_token::package_data::NativeTokenPackageData}; @@ -28,7 +29,7 @@ pub fn build_and_compile(package: NativeTokenPackageData) -> Result Result format!( - "option::some(sui::url::new_unsafe_from_bytes(b\"{}\"))", + "option::some(iota::url::new_unsafe_from_bytes(b\"{}\"))", url ), None => "option::none()".to_string(), diff --git a/crates/sui-genesis-builder/src/stardust/native_token/package_data.rs b/crates/iota-genesis-builder/src/stardust/native_token/package_data.rs similarity index 99% rename from crates/sui-genesis-builder/src/stardust/native_token/package_data.rs rename to crates/iota-genesis-builder/src/stardust/native_token/package_data.rs index defc2cfc0e2..c4af9ca360a 100644 --- a/crates/sui-genesis-builder/src/stardust/native_token/package_data.rs +++ b/crates/iota-genesis-builder/src/stardust/native_token/package_data.rs @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! The [`package_data`] module provides the [`NativeTokenPackageData`] struct, diff --git a/crates/iota-genesis-builder/src/stardust/native_token/package_template/Move.toml b/crates/iota-genesis-builder/src/stardust/native_token/package_template/Move.toml new file mode 100644 index 00000000000..26f61dfeac9 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/native_token/package_template/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "$PACKAGE_NAME" +version = "0.0.1" +edition = "2024.beta" + +[dependencies] +MoveStdlib = { local = "$FRAMEWORK_PACKAGES_PATH/move-stdlib" } +Iota = { local = "$FRAMEWORK_PACKAGES_PATH/iota-framework" } +Stardust = { local = "$FRAMEWORK_PACKAGES_PATH/stardust" } diff --git a/crates/sui-genesis-builder/src/stardust/native_token/package_template/sources/native_token_template.move b/crates/iota-genesis-builder/src/stardust/native_token/package_template/sources/native_token_template.move similarity index 88% rename from crates/sui-genesis-builder/src/stardust/native_token/package_template/sources/native_token_template.move rename to crates/iota-genesis-builder/src/stardust/native_token/package_template/sources/native_token_template.move index bd6520026cc..55e383c68c7 100644 --- a/crates/sui-genesis-builder/src/stardust/native_token/package_template/sources/native_token_template.move +++ b/crates/iota-genesis-builder/src/stardust/native_token/package_template/sources/native_token_template.move @@ -1,9 +1,10 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module 0x0::$MODULE_NAME { - use sui::coin; - use sui::url::Url; + use iota::coin; + use iota::url::Url; use stardust::capped_coin; /// The type identifier of coin. The coin will have a type @@ -38,7 +39,7 @@ module 0x0::$MODULE_NAME { transfer::public_freeze_object(metadata); // Transfer the policy as a capability to the alias address - transfer::public_transfer(policy, sui::address::from_ascii_bytes(&b"$ALIAS")); + transfer::public_transfer(policy, iota::address::from_ascii_bytes(&b"$ALIAS")); } } diff --git a/crates/sui-genesis-builder/src/stardust/parse.rs b/crates/iota-genesis-builder/src/stardust/parse.rs similarity index 96% rename from crates/sui-genesis-builder/src/stardust/parse.rs rename to crates/iota-genesis-builder/src/stardust/parse.rs index 7ea35c8c17f..08dda3321a1 100644 --- a/crates/sui-genesis-builder/src/stardust/parse.rs +++ b/crates/iota-genesis-builder/src/stardust/parse.rs @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! Types and logic to parse a full Stardust snapshot. diff --git a/crates/iota-genesis-builder/src/stardust/types/address.rs b/crates/iota-genesis-builder/src/stardust/types/address.rs new file mode 100644 index 00000000000..779be833499 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/types/address.rs @@ -0,0 +1,26 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_sdk::types::block::address::Address; +use iota_types::{base_types::IotaAddress, object::Owner}; + +/// Converts a ["Stardust" `Address`](Address) to a [`IotaAddress`]. +/// +/// This is intended as the only conversion function to go from Stardust to Iota +/// addresses, so there is only one place to potentially update it if we decide +/// to change it later. +pub fn stardust_to_iota_address( + stardust_address: impl Into
    , +) -> anyhow::Result { + stardust_address.into().to_string().parse() +} + +/// Converts a ["Stardust" `Address`](Address) to a [`IotaAddress`] and then +/// wraps it into an [`Owner`] which is either address- or object-owned +/// depending on the stardust address. +pub fn stardust_to_iota_address_owner( + stardust_address: impl Into
    , +) -> anyhow::Result { + stardust_to_iota_address(stardust_address.into()).map(Owner::AddressOwner) +} diff --git a/crates/iota-genesis-builder/src/stardust/types/alias.rs b/crates/iota-genesis-builder/src/stardust/types/alias.rs new file mode 100644 index 00000000000..ca8a201f737 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/types/alias.rs @@ -0,0 +1,206 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_protocol_config::ProtocolConfig; +use iota_sdk::types::block::output::AliasOutput as StardustAlias; +use iota_types::{ + balance::Balance, + base_types::{IotaAddress, ObjectID, SequenceNumber, TxContext}, + collection_types::Bag, + id::UID, + object::{Data, MoveObject, Object, Owner}, + STARDUST_PACKAGE_ID, +}; +use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +use super::stardust_to_iota_address; + +pub const ALIAS_MODULE_NAME: &IdentStr = ident_str!("alias"); +pub const ALIAS_OUTPUT_MODULE_NAME: &IdentStr = ident_str!("alias_output"); +pub const ALIAS_OUTPUT_STRUCT_NAME: &IdentStr = ident_str!("AliasOutput"); +pub const ALIAS_STRUCT_NAME: &IdentStr = ident_str!("Alias"); +pub const ALIAS_DYNAMIC_OBJECT_FIELD_KEY: &[u8] = b"alias"; +pub const ALIAS_DYNAMIC_OBJECT_FIELD_KEY_TYPE: &str = "vector"; + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct Alias { + /// The ID of the Alias = hash of the Output ID that created the Alias + /// Output in Stardust. This is the AliasID from Stardust. + pub id: UID, + + /// The last State Controller address assigned before the migration. + pub legacy_state_controller: IotaAddress, + /// A counter increased by 1 every time the alias was state transitioned. + pub state_index: u32, + /// State metadata that can be used to store additional information. + pub state_metadata: Option>, + + /// The sender feature. + pub sender: Option, + /// The metadata feature. + pub metadata: Option>, + + /// The immutable issuer feature. + pub immutable_issuer: Option, + /// The immutable metadata feature. + pub immutable_metadata: Option>, +} + +impl Alias { + pub fn tag() -> StructTag { + StructTag { + address: STARDUST_PACKAGE_ID.into(), + module: ALIAS_MODULE_NAME.to_owned(), + name: ALIAS_STRUCT_NAME.to_owned(), + type_params: Vec::new(), + } + } + + /// Creates the Move-based Alias model from a Stardust-based Alias Output. + pub fn try_from_stardust( + alias_id: ObjectID, + alias: &StardustAlias, + ) -> Result { + if alias_id.as_ref() == [0; 32] { + anyhow::bail!("alias_id must be non-zeroed"); + } + + let state_metadata: Option> = if alias.state_metadata().is_empty() { + None + } else { + Some(alias.state_metadata().to_vec()) + }; + let sender: Option = alias + .features() + .sender() + .map(|sender_feat| stardust_to_iota_address(sender_feat.address())) + .transpose()?; + let metadata: Option> = alias + .features() + .metadata() + .map(|metadata_feat| metadata_feat.data().to_vec()); + let immutable_issuer: Option = alias + .immutable_features() + .issuer() + .map(|issuer_feat| stardust_to_iota_address(issuer_feat.address())) + .transpose()?; + let immutable_metadata: Option> = alias + .immutable_features() + .metadata() + .map(|metadata_feat| metadata_feat.data().to_vec()); + + Ok(Alias { + id: UID::new(alias_id), + legacy_state_controller: stardust_to_iota_address(alias.state_controller_address())?, + state_index: alias.state_index(), + state_metadata, + sender, + metadata, + immutable_issuer, + immutable_metadata, + }) + } + + pub fn to_genesis_object( + &self, + owner: Owner, + protocol_config: &ProtocolConfig, + tx_context: &TxContext, + version: SequenceNumber, + ) -> anyhow::Result { + // Construct the Alias object. + let move_alias_object = unsafe { + // Safety: we know from the definition of `Alias` in the stardust package + // that it has public transfer (`store` ability is present). + MoveObject::new_from_execution( + Self::tag().into(), + true, + version, + bcs::to_bytes(&self)?, + protocol_config, + )? + }; + + let move_alias_object = Object::new_from_genesis( + Data::Move(move_alias_object), + // We will later overwrite the owner we set here since this object will be added + // as a dynamic field on the alias output object. + owner, + tx_context.digest(), + ); + + Ok(move_alias_object) + } +} + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct AliasOutput { + /// This is a "random" UID, not the AliasID from Stardust. + pub id: UID, + + /// The amount of IOTA coins held by the output. + pub iota: Balance, + /// The `Bag` holds native tokens, key-ed by the stringified type of the + /// asset. Example: key: "0xabcded::soon::SOON", value: + /// Balance<0xabcded::soon::SOON>. + pub native_tokens: Bag, +} + +impl AliasOutput { + pub fn tag() -> StructTag { + StructTag { + address: STARDUST_PACKAGE_ID.into(), + module: ALIAS_OUTPUT_MODULE_NAME.to_owned(), + name: ALIAS_OUTPUT_STRUCT_NAME.to_owned(), + type_params: Vec::new(), + } + } + + /// Creates the Move-based Alias Output model from a Stardust-based Alias + /// Output. + pub fn try_from_stardust( + object_id: ObjectID, + alias: &StardustAlias, + native_tokens: Bag, + ) -> Result { + Ok(AliasOutput { + id: UID::new(object_id), + iota: Balance::new(alias.amount()), + native_tokens, + }) + } + + pub fn to_genesis_object( + &self, + owner: Owner, + protocol_config: &ProtocolConfig, + tx_context: &TxContext, + version: SequenceNumber, + ) -> anyhow::Result { + // Construct the Alias Output object. + let move_alias_output_object = unsafe { + // Safety: we know from the definition of `AliasOutput` in the stardust package + // that it does not have public transfer (`store` ability is absent). + MoveObject::new_from_execution( + AliasOutput::tag().into(), + false, + version, + bcs::to_bytes(&self)?, + protocol_config, + )? + }; + + let move_alias_output_object = Object::new_from_genesis( + Data::Move(move_alias_output_object), + owner, + tx_context.digest(), + ); + + Ok(move_alias_output_object) + } +} diff --git a/crates/sui-genesis-builder/src/stardust/types/capped_coin.rs b/crates/iota-genesis-builder/src/stardust/types/capped_coin.rs similarity index 81% rename from crates/sui-genesis-builder/src/stardust/types/capped_coin.rs rename to crates/iota-genesis-builder/src/stardust/types/capped_coin.rs index 2055b2c024b..12150d8eff2 100644 --- a/crates/sui-genesis-builder/src/stardust/types/capped_coin.rs +++ b/crates/iota-genesis-builder/src/stardust/types/capped_coin.rs @@ -1,9 +1,10 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_types::{coin::TreasuryCap, id::UID}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use sui_types::{coin::TreasuryCap, id::UID}; /// The policy wrapper that ensures the supply of a `Coin` never exceeds the /// maximum supply. diff --git a/crates/iota-genesis-builder/src/stardust/types/foundry.rs b/crates/iota-genesis-builder/src/stardust/types/foundry.rs new file mode 100644 index 00000000000..5b0c3dda3bf --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/types/foundry.rs @@ -0,0 +1,30 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_protocol_config::ProtocolConfig; +use iota_sdk::types::block::output::{FoundryOutput, OutputId}; +use iota_types::{ + base_types::{ObjectID, SequenceNumber, TxContext}, + id::UID, + object::Object, +}; + +use crate::{stardust, stardust::types::stardust_to_iota_address}; + +pub(crate) fn create_foundry_gas_coin( + output_id: &OutputId, + foundry: &FoundryOutput, + tx_context: &TxContext, + version: SequenceNumber, + protocol_config: &ProtocolConfig, +) -> anyhow::Result { + stardust::types::output::create_gas_coin( + UID::new(ObjectID::new(output_id.hash())), + stardust_to_iota_address(*foundry.alias_address())?, + foundry.amount(), + tx_context, + version, + protocol_config, + ) +} diff --git a/crates/iota-genesis-builder/src/stardust/types/mod.rs b/crates/iota-genesis-builder/src/stardust/types/mod.rs new file mode 100644 index 00000000000..7fa112bdde0 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/types/mod.rs @@ -0,0 +1,17 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod address; +pub mod alias; +pub mod capped_coin; +pub mod foundry; +pub mod nft; +pub mod output; +pub mod snapshot; +pub mod timelock; +pub mod token_scheme; + +pub use address::*; +pub use alias::*; +pub use nft::*; diff --git a/crates/iota-genesis-builder/src/stardust/types/nft.rs b/crates/iota-genesis-builder/src/stardust/types/nft.rs new file mode 100644 index 00000000000..b20127eb614 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/types/nft.rs @@ -0,0 +1,466 @@ +use anyhow::anyhow; +use iota_protocol_config::ProtocolConfig; +use iota_sdk::types::block::output::{ + feature::Irc27Metadata as StardustIrc27, NftOutput as StardustNft, +}; +use iota_types::{ + balance::Balance, + base_types::{IotaAddress, ObjectID, SequenceNumber, TxContext}, + collection_types::{Bag, Entry, VecMap}, + id::UID, + object::{Data, MoveObject, Object, Owner}, + STARDUST_PACKAGE_ID, +}; +use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; +use num_rational::Ratio; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +use super::{ + output::{ + ExpirationUnlockCondition, StorageDepositReturnUnlockCondition, TimelockUnlockCondition, + }, + stardust_to_iota_address, +}; + +pub const IRC27_MODULE_NAME: &IdentStr = ident_str!("irc27"); +pub const NFT_MODULE_NAME: &IdentStr = ident_str!("nft"); +pub const NFT_OUTPUT_MODULE_NAME: &IdentStr = ident_str!("nft_output"); +pub const NFT_OUTPUT_STRUCT_NAME: &IdentStr = ident_str!("NftOutput"); +pub const NFT_STRUCT_NAME: &IdentStr = ident_str!("Nft"); +pub const IRC27_STRUCT_NAME: &IdentStr = ident_str!("Irc27Metadata"); +pub const NFT_DYNAMIC_OBJECT_FIELD_KEY: &[u8] = b"nft"; +pub const NFT_DYNAMIC_OBJECT_FIELD_KEY_TYPE: &str = "vector"; + +/// Rust version of the Move std::fixed_point32::FixedPoint32 type. +#[derive(Debug, Default, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct FixedPoint32 { + pub value: u64, +} + +impl FixedPoint32 { + /// Create a fixed-point value from a rational number specified by its + /// numerator and denominator. Imported from Move std lib. + /// This will panic if the denominator is zero. It will also + /// abort if the numerator is nonzero and the ratio is not in the range + /// 2^-32 .. 2^32-1. When specifying decimal fractions, be careful about + /// rounding errors: if you round to display N digits after the decimal + /// point, you can use a denominator of 10^N to avoid numbers where the + /// very small imprecision in the binary representation could change the + /// rounding, e.g., 0.0125 will round down to 0.012 instead of up to 0.013. + fn create_from_rational(numerator: u64, denominator: u64) -> Self { + // If the denominator is zero, this will abort. + // Scale the numerator to have 64 fractional bits and the denominator + // to have 32 fractional bits, so that the quotient will have 32 + // fractional bits. + let scaled_numerator = (numerator as u128) << 64; + let scaled_denominator = (denominator as u128) << 32; + assert!(scaled_denominator != 0); + let quotient = scaled_numerator / scaled_denominator; + assert!(quotient != 0 || numerator == 0); + // Return the quotient as a fixed-point number. We first need to check whether + // the cast can succeed. + assert!(quotient <= u64::MAX as u128); + FixedPoint32 { + value: quotient as u64, + } + } +} + +impl TryFrom for FixedPoint32 { + type Error = anyhow::Error; + fn try_from(value: f64) -> Result { + let value = Ratio::from_float(value).ok_or(anyhow!("Missing attribute"))?; + let numerator = value.numer().clone().try_into()?; + let denominator = value.denom().clone().try_into()?; + Ok(FixedPoint32::create_from_rational(numerator, denominator)) + } +} + +/// Rust version of the Move iota::url::Url type. +#[derive(Debug, Default, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct Url { + /// The underlying URL as a string. + /// + /// # SAFETY + /// + /// Note that this String is UTF-8 encoded while the URL type in Move is + /// ascii-encoded. Setting this field requires ensuring that the string + /// consists of only ASCII characters. + pub(crate) url: String, +} + +impl TryFrom for Url { + type Error = anyhow::Error; + + /// Creates a new `Url` ensuring that it only consists of ascii characters. + fn try_from(url: String) -> Result { + if !url.is_ascii() { + anyhow::bail!("url `{url}` does not consist of only ascii characters") + } + Ok(Url { url }) + } +} + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct Irc27Metadata { + /// Version of the metadata standard. + pub version: String, + + /// The media type (MIME) of the asset. + /// + /// ## Examples + /// - Image files: `image/jpeg`, `image/png`, `image/gif`, etc. + /// - Video files: `video/x-msvideo` (avi), `video/mp4`, `video/mpeg`, etc. + /// - Audio files: `audio/mpeg`, `audio/wav`, etc. + /// - 3D Assets: `model/obj`, `model/u3d`, etc. + /// - Documents: `application/pdf`, `text/plain`, etc. + pub media_type: String, + + /// URL pointing to the NFT file location. + pub uri: Url, + + /// Alphanumeric text string defining the human identifiable name for the + /// NFT. + pub name: String, + + /// The human-readable collection name of the NFT. + pub collection_name: Option, + + /// Royalty payment addresses mapped to the payout percentage. + /// Contains a hash of the 32 bytes parsed from the BECH32 encoded IOTA + /// address in the metadata, it is a legacy address. Royalties are not + /// supported by the protocol and needed to be processed by an integrator. + pub royalties: VecMap, + + /// The human-readable name of the NFT creator. + pub issuer_name: Option, + + /// The human-readable description of the NFT. + pub description: Option, + + /// Additional attributes which follow [OpenSea Metadata standards](https://docs.opensea.io/docs/metadata-standards). + pub attributes: VecMap, + + /// Legacy non-standard metadata fields. + pub non_standard_fields: VecMap, +} + +impl TryFrom for Irc27Metadata { + type Error = anyhow::Error; + fn try_from(irc27: StardustIrc27) -> Result { + Ok(Self { + version: irc27.version().to_string(), + media_type: irc27.media_type().to_string(), + // We are converting a `Url` to an ASCII string here (as the URL type in move is based + // on ASCII strings). The `ToString` implementation of the `Url` ensures + // only ascii characters are returned and this conversion is therefore safe + // to do. + uri: Url::try_from(irc27.uri().to_string()) + .expect("url should only contain ascii characters"), + name: irc27.name().to_string(), + collection_name: irc27.collection_name().clone(), + royalties: VecMap { + contents: irc27 + .royalties() + .iter() + .map(|(addr, value)| { + Ok(Entry { + key: stardust_to_iota_address(addr.inner())?, + value: FixedPoint32::try_from(*value)?, + }) + }) + .collect::>, Self::Error>>()?, + }, + issuer_name: irc27.issuer_name().clone(), + description: irc27.description().clone(), + attributes: VecMap { + contents: irc27 + .attributes() + .iter() + .map(|attribute| Entry { + key: attribute.trait_type().to_string(), + value: attribute.value().to_string(), + }) + .collect(), + }, + non_standard_fields: VecMap { + contents: Vec::new(), + }, + }) + } +} + +impl Default for Irc27Metadata { + fn default() -> Self { + // The currently supported version per . + let version = "v1.0".to_owned(); + // Matches the media type of the URI below. + let media_type = "image/png".to_owned(); + // A placeholder for NFTs without metadata from which we can extract a URI. + let uri = Url::try_from( + iota_sdk::Url::parse("https://opensea.io/static/images/placeholder.png") + .expect("should be a valid url") + .to_string(), + ) + .expect("url should only contain ascii characters"); + let name = "NFT".to_owned(); + + Self { + version, + media_type, + uri, + name, + collection_name: Default::default(), + royalties: VecMap { + contents: Vec::new(), + }, + issuer_name: Default::default(), + description: Default::default(), + attributes: VecMap { + contents: Vec::new(), + }, + non_standard_fields: VecMap { + contents: Vec::new(), + }, + } + } +} + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct Nft { + /// The ID of the Nft = hash of the Output ID that created the Nft Output in + /// Stardust. This is the NftID from Stardust. + pub id: UID, + + /// The sender feature holds the last sender address assigned before the + /// migration and is not supported by the protocol after it. + pub legacy_sender: Option, + /// The metadata feature. + pub metadata: Option>, + /// The tag feature. + pub tag: Option>, + + /// The immutable issuer feature. + pub immutable_issuer: Option, + /// The immutable metadata feature. + pub immutable_metadata: Irc27Metadata, +} + +impl Nft { + pub fn tag() -> StructTag { + StructTag { + address: STARDUST_PACKAGE_ID.into(), + module: NFT_MODULE_NAME.to_owned(), + name: NFT_STRUCT_NAME.to_owned(), + type_params: Vec::new(), + } + } + + /// Creates the Move-based Nft model from a Stardust-based Nft Output. + pub fn try_from_stardust(nft_id: ObjectID, nft: &StardustNft) -> Result { + if nft_id.as_ref() == [0; 32] { + anyhow::bail!("nft_id must be non-zeroed"); + } + + let legacy_sender: Option = nft + .features() + .sender() + .map(|sender_feat| stardust_to_iota_address(sender_feat.address())) + .transpose()?; + let metadata: Option> = nft + .features() + .metadata() + .map(|metadata_feat| metadata_feat.data().to_vec()); + let tag: Option> = nft.features().tag().map(|tag_feat| tag_feat.tag().to_vec()); + let immutable_issuer: Option = nft + .immutable_features() + .issuer() + .map(|issuer_feat| stardust_to_iota_address(issuer_feat.address())) + .transpose()?; + let irc27: Irc27Metadata = Self::convert_immutable_metadata(nft)?; + + Ok(Nft { + id: UID::new(nft_id), + legacy_sender, + metadata, + tag, + immutable_issuer, + immutable_metadata: irc27, + }) + } + + /// Converts the immutable metadata of the NFT into an [`Irc27Metadata`]. + /// + /// - If the metadata does not exist returns the default `Irc27Metadata`. + /// - If the metadata can be parsed into [`StardustIrc27`] returns that + /// converted into `Irc27Metadata`. + /// - If the metadata can be parsed into a JSON object returns the default + /// `Irc27Metadata` with `non_standard_fields` set to the fields of the + /// object. + /// - Otherwise, returns the default `Irc27Metadata` with + /// `non_standard_fields` containing a `data` key with the hex-encoded + /// metadata (without `0x` prefix). + /// + /// Note that the metadata feature of the NFT cannot be present _and_ empty + /// per the protocol rules: . + pub(crate) fn convert_immutable_metadata(nft: &StardustNft) -> anyhow::Result { + let Some(metadata) = nft.immutable_features().metadata() else { + return Ok(Irc27Metadata::default()); + }; + + if let Ok(parsed_irc27_metadata) = serde_json::from_slice::(metadata.data()) + { + return Irc27Metadata::try_from(parsed_irc27_metadata); + } + + if let Ok(serde_json::Value::Object(json_object)) = + serde_json::from_slice::(metadata.data()) + { + let mut irc_metadata = Irc27Metadata::default(); + + for (key, value) in json_object.into_iter() { + irc_metadata.non_standard_fields.contents.push(Entry { + key, + value: value.to_string(), + }) + } + + return Ok(irc_metadata); + } + + let mut irc_metadata = Irc27Metadata::default(); + let hex_encoded_metadata = hex::encode(metadata.data()); + irc_metadata.non_standard_fields.contents.push(Entry { + key: "data".to_owned(), + value: hex_encoded_metadata, + }); + Ok(irc_metadata) + } + + pub fn to_genesis_object( + &self, + owner: Owner, + protocol_config: &ProtocolConfig, + tx_context: &TxContext, + version: SequenceNumber, + ) -> anyhow::Result { + // Construct the Nft object. + let move_nft_object = unsafe { + // Safety: we know from the definition of `Nft` in the stardust package + // that it has public transfer (`store` ability is present). + MoveObject::new_from_execution( + Self::tag().into(), + true, + version, + bcs::to_bytes(&self)?, + protocol_config, + )? + }; + + let move_nft_object = Object::new_from_genesis( + Data::Move(move_nft_object), + // We will later overwrite the owner we set here since this object will be added + // as a dynamic field on the nft output object. + owner, + tx_context.digest(), + ); + + Ok(move_nft_object) + } +} + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct NftOutput { + /// This is a "random" UID, not the NftID from Stardust. + pub id: UID, + + /// The amount of IOTA coins held by the output. + pub iota: Balance, + /// The `Bag` holds native tokens, key-ed by the stringified type of the + /// asset. Example: key: "0xabcded::soon::SOON", value: + /// Balance<0xabcded::soon::SOON>. + pub native_tokens: Bag, + + /// The storage deposit return unlock condition. + pub storage_deposit_return: Option, + /// The timelock unlock condition. + pub timelock: Option, + /// The expiration unlock condition. + pub expiration: Option, +} + +impl NftOutput { + pub fn tag() -> StructTag { + StructTag { + address: STARDUST_PACKAGE_ID.into(), + module: NFT_OUTPUT_MODULE_NAME.to_owned(), + name: NFT_OUTPUT_STRUCT_NAME.to_owned(), + type_params: Vec::new(), + } + } + + /// Creates the Move-based Nft Output model from a Stardust-based Nft + /// Output. + pub fn try_from_stardust( + object_id: ObjectID, + nft: &StardustNft, + native_tokens: Bag, + ) -> Result { + let unlock_conditions = nft.unlock_conditions(); + Ok(NftOutput { + id: UID::new(object_id), + iota: Balance::new(nft.amount()), + native_tokens, + storage_deposit_return: unlock_conditions + .storage_deposit_return() + .map(|unlock| unlock.try_into()) + .transpose()?, + timelock: unlock_conditions.timelock().map(|unlock| unlock.into()), + expiration: unlock_conditions + .expiration() + .map(|expiration| ExpirationUnlockCondition::new(nft.address(), expiration)) + .transpose()?, + }) + } + + pub fn to_genesis_object( + &self, + owner: IotaAddress, + protocol_config: &ProtocolConfig, + tx_context: &TxContext, + version: SequenceNumber, + ) -> anyhow::Result { + // Construct the Nft Output object. + let move_nft_output_object = unsafe { + // Safety: we know from the definition of `NftOutput` in the stardust package + // that it does not have public transfer (`store` ability is absent). + MoveObject::new_from_execution( + NftOutput::tag().into(), + false, + version, + bcs::to_bytes(&self)?, + protocol_config, + )? + }; + + let owner = if self.expiration.is_some() { + Owner::Shared { + initial_shared_version: version, + } + } else { + Owner::AddressOwner(owner) + }; + + let move_nft_output_object = Object::new_from_genesis( + Data::Move(move_nft_output_object), + owner, + tx_context.digest(), + ); + + Ok(move_nft_output_object) + } +} diff --git a/crates/sui-genesis-builder/src/stardust/types/output.rs b/crates/iota-genesis-builder/src/stardust/types/output.rs similarity index 93% rename from crates/sui-genesis-builder/src/stardust/types/output.rs rename to crates/iota-genesis-builder/src/stardust/types/output.rs index a48bded5a65..4f1dca6ea22 100644 --- a/crates/sui-genesis-builder/src/stardust/types/output.rs +++ b/crates/iota-genesis-builder/src/stardust/types/output.rs @@ -2,23 +2,23 @@ //! package. use anyhow::Result; +use iota_protocol_config::ProtocolConfig; use iota_sdk::types::block::address::Address; -use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ +use iota_types::{ balance::Balance, - base_types::{MoveObjectType, ObjectID, SequenceNumber, SuiAddress, TxContext}, + base_types::{IotaAddress, MoveObjectType, ObjectID, SequenceNumber, TxContext}, coin::Coin, collection_types::Bag, id::UID, object::{Data, MoveObject, Object, Owner}, STARDUST_PACKAGE_ID, }; +use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; -use super::{snapshot::OutputHeader, stardust_to_sui_address}; +use super::{snapshot::OutputHeader, stardust_to_iota_address}; pub const BASIC_OUTPUT_MODULE_NAME: &IdentStr = ident_str!("basic_output"); pub const BASIC_OUTPUT_STRUCT_NAME: &IdentStr = ident_str!("BasicOutput"); @@ -28,10 +28,10 @@ pub const BASIC_OUTPUT_STRUCT_NAME: &IdentStr = ident_str!("BasicOutput"); #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, JsonSchema)] pub struct ExpirationUnlockCondition { /// The address who owns the output before the timestamp has passed. - pub owner: SuiAddress, + pub owner: IotaAddress, /// The address that is allowed to spend the locked funds after the /// timestamp has passed. - pub return_address: SuiAddress, + pub return_address: IotaAddress, /// Before this unix time, Address Unlock Condition is allowed to unlock the /// output, after that only the address defined in Return Address. pub unix_time: u32, @@ -42,8 +42,9 @@ impl ExpirationUnlockCondition { owner_address: &Address, expiration_unlock_condition: &iota_sdk::types::block::output::unlock_condition::ExpirationUnlockCondition, ) -> anyhow::Result { - let owner = stardust_to_sui_address(owner_address)?; - let return_address = stardust_to_sui_address(expiration_unlock_condition.return_address())?; + let owner = stardust_to_iota_address(owner_address)?; + let return_address = + stardust_to_iota_address(expiration_unlock_condition.return_address())?; let unix_time = expiration_unlock_condition.timestamp(); Ok(Self { @@ -60,7 +61,7 @@ impl ExpirationUnlockCondition { pub struct StorageDepositReturnUnlockCondition { /// The address to which the consuming transaction should deposit the amount /// defined in Return Amount. - pub return_address: SuiAddress, + pub return_address: IotaAddress, /// The amount of IOTA coins the consuming transaction should deposit to the /// address defined in Return Address. pub return_amount: u64, @@ -133,7 +134,7 @@ pub struct BasicOutput { /// The tag feature. pub tag: Option>, /// The sender feature. - pub sender: Option, + pub sender: Option, } impl BasicOutput { @@ -190,7 +191,7 @@ impl BasicOutput { pub fn to_genesis_object( &self, - owner: SuiAddress, + owner: IotaAddress, protocol_config: &ProtocolConfig, tx_context: &TxContext, version: SequenceNumber, @@ -223,7 +224,7 @@ impl BasicOutput { pub fn into_genesis_coin_object( self, - owner: SuiAddress, + owner: IotaAddress, protocol_config: &ProtocolConfig, tx_context: &TxContext, version: SequenceNumber, @@ -241,7 +242,7 @@ impl BasicOutput { pub(crate) fn create_gas_coin( object_id: UID, - owner: SuiAddress, + owner: IotaAddress, amount: u64, tx_context: &TxContext, version: SequenceNumber, diff --git a/crates/sui-genesis-builder/src/stardust/types/snapshot.rs b/crates/iota-genesis-builder/src/stardust/types/snapshot.rs similarity index 99% rename from crates/sui-genesis-builder/src/stardust/types/snapshot.rs rename to crates/iota-genesis-builder/src/stardust/types/snapshot.rs index 0c79aa810ee..f8de004cba3 100644 --- a/crates/sui-genesis-builder/src/stardust/types/snapshot.rs +++ b/crates/iota-genesis-builder/src/stardust/types/snapshot.rs @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! Types representing blocks of data in a Stardust snapshot. diff --git a/crates/iota-genesis-builder/src/stardust/types/timelock.rs b/crates/iota-genesis-builder/src/stardust/types/timelock.rs new file mode 100644 index 00000000000..c7bec1bbbc1 --- /dev/null +++ b/crates/iota-genesis-builder/src/stardust/types/timelock.rs @@ -0,0 +1,392 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_protocol_config::ProtocolConfig; +use iota_sdk::types::block::output::{BasicOutput, OutputId}; +use iota_types::{ + balance::Balance, + base_types::{IotaAddress, MoveObjectType, ObjectID, SequenceNumber, TxContext}, + id::UID, + object::{Data, MoveObject, Object, Owner}, + timelock::timelock::TimeLock, +}; + +/// All basic outputs whose IDs start with this prefix represent vested rewards +/// that were created during the stardust upgrade on IOTA mainnet. +const VESTED_REWARD_ID_PREFIX: &str = "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb18"; + +#[derive(Debug, thiserror::Error)] +pub enum VestedRewardError { + #[error("failed to create genesis move object, owner: {owner}, timelock: {timelock:#?}")] + ObjectCreation { + owner: IotaAddress, + timelock: TimeLock, + source: iota_types::error::ExecutionError, + }, + #[error("a vested reward must not contain native tokens")] + NativeTokensNotSupported, + #[error("a basic output is not a vested reward")] + NotVestedReward, + #[error("a vested reward must have two unlock conditions")] + UnlockConditionsNumberMismatch, + #[error("only timelocked vested rewards can be migrated as `TimeLock>`")] + UnlockedVestedReward, +} + +/// Checks if an output is a timelocked vested reward. +pub fn is_timelocked_vested_reward( + output_id: OutputId, + basic_output: &BasicOutput, + target_milestone_timestamp_sec: u32, +) -> bool { + is_vested_reward(output_id, basic_output) + && basic_output + .unlock_conditions() + .is_time_locked(target_milestone_timestamp_sec) +} + +/// Checks if an output is a vested reward, if it has a specific ID prefix, +/// and if it contains a timelock unlock condition. +fn is_vested_reward(output_id: OutputId, basic_output: &BasicOutput) -> bool { + let has_vesting_prefix = output_id.to_string().starts_with(VESTED_REWARD_ID_PREFIX); + + has_vesting_prefix && basic_output.unlock_conditions().timelock().is_some() +} + +/// Creates a `TimeLock>` from a Stardust-based Basic Output +/// that represents a vested reward. +pub fn try_from_stardust( + output_id: OutputId, + basic_output: &BasicOutput, + target_milestone_timestamp_sec: u32, +) -> Result, VestedRewardError> { + if !is_vested_reward(output_id, basic_output) { + return Err(VestedRewardError::NotVestedReward); + } + + if !basic_output + .unlock_conditions() + .is_time_locked(target_milestone_timestamp_sec) + { + return Err(VestedRewardError::UnlockedVestedReward); + } + + if basic_output.unlock_conditions().len() != 2 { + return Err(VestedRewardError::UnlockConditionsNumberMismatch); + } + + if basic_output.native_tokens().len() > 0 { + return Err(VestedRewardError::NativeTokensNotSupported); + } + + let id = UID::new(ObjectID::new(output_id.hash())); + let locked = Balance::new(basic_output.amount()); + + // We already checked the existence of the timelock unlock condition at this + // point. + let timelock_uc = basic_output + .unlock_conditions() + .timelock() + .expect("a vested reward should contain a timelock unlock condition"); + let expiration_timestamp_ms = Into::::into(timelock_uc.timestamp()) * 1000; + + Ok(iota_types::timelock::timelock::TimeLock::new( + id, + locked, + expiration_timestamp_ms, + )) +} + +/// Creates a genesis object from a time-locked balance. +pub fn to_genesis_object( + timelock: TimeLock, + owner: IotaAddress, + protocol_config: &ProtocolConfig, + tx_context: &TxContext, + version: SequenceNumber, +) -> Result { + let move_object = unsafe { + // Safety: we know from the definition of `TimeLock` in the timelock package + // that it is not publicly transferable (`store` ability is absent). + MoveObject::new_from_execution( + MoveObjectType::timelocked_iota_balance(), + false, + version, + timelock.to_bcs_bytes(), + protocol_config, + ) + .map_err(|source| VestedRewardError::ObjectCreation { + owner, + timelock, + source, + })? + }; + + Ok(Object::new_from_genesis( + Data::Move(move_object), + Owner::AddressOwner(owner), + tx_context.digest(), + )) +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use iota_sdk::types::block::{ + address::Ed25519Address, + output::{ + unlock_condition::{ + AddressUnlockCondition, StorageDepositReturnUnlockCondition, + TimelockUnlockCondition, + }, + BasicOutput, BasicOutputBuilder, NativeToken, OutputId, TokenId, + }, + }; + + use crate::stardust::types::timelock::{self, VestedRewardError}; + + fn vested_reward_output(amount: u64, expiration_time_sec: u32) -> BasicOutput { + BasicOutputBuilder::new_with_amount(amount) + .add_unlock_condition(AddressUnlockCondition::new( + Ed25519Address::from_str( + "0xebe40a263480190dcd7939447ee01aefa73d6f3cc33c90ef7bf905abf8728655", + ) + .unwrap(), + )) + .add_unlock_condition(TimelockUnlockCondition::new(expiration_time_sec).unwrap()) + .finish() + .unwrap() + } + + #[test] + fn is_timelocked_vested_reward_all_correct() { + let output_id = OutputId::from_str( + "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", + ) + .unwrap(); + let output = vested_reward_output(10, 1000); + + assert!(timelock::is_timelocked_vested_reward( + output_id, &output, 100 + )); + } + + #[test] + fn is_timelocked_vested_reward_min_id() { + let output_id = OutputId::from_str( + "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1800000000", + ) + .unwrap(); + let output = vested_reward_output(10, 1000); + + assert!(timelock::is_timelocked_vested_reward( + output_id, &output, 100 + )); + } + + #[test] + fn is_timelocked_vested_reward_max_id() { + let output_id = OutputId::from_str( + "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb18ffffffff", + ) + .unwrap(); + let output = vested_reward_output(10, 1000); + + assert!(timelock::is_timelocked_vested_reward( + output_id, &output, 100 + )); + } + + #[test] + fn is_timelocked_vested_reward_incorrect_id() { + let output_id = OutputId::from_str( + "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1712345678", + ) + .unwrap(); + let output = vested_reward_output(10, 1000); + + assert!(!timelock::is_timelocked_vested_reward( + output_id, &output, 100 + )); + } + + #[test] + fn is_timelocked_vested_reward_no_timelock_unlock_condition() { + let output_id = OutputId::from_str( + "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", + ) + .unwrap(); + let output = BasicOutputBuilder::new_with_amount(10) + .add_unlock_condition(AddressUnlockCondition::new( + Ed25519Address::from_str( + "0xebe40a263480190dcd7939447ee01aefa73d6f3cc33c90ef7bf905abf8728655", + ) + .unwrap(), + )) + .finish() + .unwrap(); + + assert!(!timelock::is_timelocked_vested_reward( + output_id, &output, 100 + )); + } + + #[test] + fn is_timelocked_vested_reward_bigger_milestone_time() { + let output_id = OutputId::from_str( + "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", + ) + .unwrap(); + let output = vested_reward_output(10, 100); + + assert!(!timelock::is_timelocked_vested_reward( + output_id, &output, 1000 + )); + } + + #[test] + fn is_timelocked_vested_reward_same_milestone_time() { + let output_id = OutputId::from_str( + "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", + ) + .unwrap(); + let output = vested_reward_output(10, 1000); + + assert!(!timelock::is_timelocked_vested_reward( + output_id, &output, 1000 + )); + } + + #[test] + fn timelock_from_stardust_all_correct() { + let output_id = OutputId::from_str( + "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", + ) + .unwrap(); + let output = vested_reward_output(10, 1000); + + let timelock = timelock::try_from_stardust(output_id, &output, 100).unwrap(); + + assert!(timelock.locked().value() == 10); + assert!(timelock.expiration_timestamp_ms() == 1_000_000); + } + + #[test] + fn timelock_from_stardust_with_expired_output() { + let output_id = OutputId::from_str( + "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", + ) + .unwrap(); + let output = vested_reward_output(10, 1000); + + let err = timelock::try_from_stardust(output_id, &output, 1000).unwrap_err(); + + assert!(matches!(err, VestedRewardError::UnlockedVestedReward)); + } + + #[test] + fn timelock_from_stardust_with_incorrect_id() { + let output_id = OutputId::from_str( + "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1712345678", + ) + .unwrap(); + let output = vested_reward_output(10, 1000); + + let err = timelock::try_from_stardust(output_id, &output, 100).unwrap_err(); + + assert!(matches!(err, VestedRewardError::NotVestedReward)); + } + + #[test] + fn timelock_from_stardust_without_timelock_unlock_condition() { + let output_id = OutputId::from_str( + "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", + ) + .unwrap(); + let output = BasicOutputBuilder::new_with_amount(10) + .add_unlock_condition(AddressUnlockCondition::new( + Ed25519Address::from_str( + "0xebe40a263480190dcd7939447ee01aefa73d6f3cc33c90ef7bf905abf8728655", + ) + .unwrap(), + )) + .add_unlock_condition( + StorageDepositReturnUnlockCondition::new( + Ed25519Address::from_str( + "0xebe40a263480190dcd7939447ee01aefa73d6f3cc33c90ef7bf905abf8728655", + ) + .unwrap(), + 100, + 100, + ) + .unwrap(), + ) + .finish() + .unwrap(); + + let err = timelock::try_from_stardust(output_id, &output, 1000).unwrap_err(); + + assert!(matches!(err, VestedRewardError::NotVestedReward)); + } + + #[test] + fn timelock_from_stardust_extra_unlock_condition() { + let output_id = OutputId::from_str( + "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", + ) + .unwrap(); + let output = BasicOutputBuilder::new_with_amount(10) + .add_unlock_condition(AddressUnlockCondition::new( + Ed25519Address::from_str( + "0xebe40a263480190dcd7939447ee01aefa73d6f3cc33c90ef7bf905abf8728655", + ) + .unwrap(), + )) + .add_unlock_condition(TimelockUnlockCondition::new(1000).unwrap()) + .add_unlock_condition( + StorageDepositReturnUnlockCondition::new( + Ed25519Address::from_str( + "0xebe40a263480190dcd7939447ee01aefa73d6f3cc33c90ef7bf905abf8728655", + ) + .unwrap(), + 100, + 100, + ) + .unwrap(), + ) + .finish() + .unwrap(); + + let err = timelock::try_from_stardust(output_id, &output, 100).unwrap_err(); + + assert!(matches!( + err, + VestedRewardError::UnlockConditionsNumberMismatch + )); + } + + #[test] + fn timelock_from_stardust_with_native_tokens() { + let output_id = OutputId::from_str( + "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", + ) + .unwrap(); + let output = BasicOutputBuilder::new_with_amount(10) + .add_unlock_condition(AddressUnlockCondition::new( + Ed25519Address::from_str( + "0xebe40a263480190dcd7939447ee01aefa73d6f3cc33c90ef7bf905abf8728655", + ) + .unwrap(), + )) + .add_unlock_condition(TimelockUnlockCondition::new(1000).unwrap()) + .add_native_token(NativeToken::new(TokenId::null(), 1).unwrap()) + .finish() + .unwrap(); + + let err = timelock::try_from_stardust(output_id, &output, 100).unwrap_err(); + + assert!(matches!(err, VestedRewardError::NativeTokensNotSupported)); + } +} diff --git a/crates/sui-genesis-builder/src/stardust/types/token_scheme.rs b/crates/iota-genesis-builder/src/stardust/types/token_scheme.rs similarity index 99% rename from crates/sui-genesis-builder/src/stardust/types/token_scheme.rs rename to crates/iota-genesis-builder/src/stardust/types/token_scheme.rs index 7d16ffbcafa..a3cdb369453 100644 --- a/crates/sui-genesis-builder/src/stardust/types/token_scheme.rs +++ b/crates/iota-genesis-builder/src/stardust/types/token_scheme.rs @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! Types representing token schemes in Stardust. diff --git a/crates/sui-genesis-builder/src/validator_info.rs b/crates/iota-genesis-builder/src/validator_info.rs similarity index 96% rename from crates/sui-genesis-builder/src/validator_info.rs rename to crates/iota-genesis-builder/src/validator_info.rs index 0f14acfae2e..75f2867ead8 100644 --- a/crates/sui-genesis-builder/src/validator_info.rs +++ b/crates/iota-genesis-builder/src/validator_info.rs @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::bail; use fastcrypto::traits::ToFromBytes; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use sui_types::{ - base_types::SuiAddress, +use iota_types::{ + base_types::IotaAddress, crypto::{ verify_proof_of_possession, AuthorityPublicKey, AuthorityPublicKeyBytes, AuthoritySignature, NetworkPublicKey, }, multiaddr::Multiaddr, }; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; const MAX_VALIDATOR_METADATA_LENGTH: usize = 256; @@ -22,7 +23,7 @@ const MAX_VALIDATOR_METADATA_LENGTH: usize = 256; #[serde(rename_all = "kebab-case")] pub struct ValidatorInfo { pub name: String, - pub account_address: SuiAddress, + pub account_address: IotaAddress, pub protocol_key: AuthorityPublicKeyBytes, pub worker_key: NetworkPublicKey, pub network_key: NetworkPublicKey, @@ -42,7 +43,7 @@ impl ValidatorInfo { &self.name } - pub fn sui_address(&self) -> SuiAddress { + pub fn iota_address(&self) -> IotaAddress { self.account_address } @@ -181,7 +182,7 @@ impl From for GenesisValidatorMetadata { description: info.description, image_url: info.image_url, project_url: info.project_url, - sui_address: info.account_address, + iota_address: info.account_address, gas_price: info.gas_price, commission_rate: info.commission_rate, protocol_public_key: info.protocol_key.as_bytes().to_vec(), @@ -204,7 +205,7 @@ pub struct GenesisValidatorMetadata { pub image_url: String, pub project_url: String, - pub sui_address: SuiAddress, + pub iota_address: IotaAddress, pub gas_price: u64, pub commission_rate: u64, diff --git a/crates/iota-graphql-e2e-tests/Cargo.toml b/crates/iota-graphql-e2e-tests/Cargo.toml new file mode 100644 index 00000000000..541cf9d94c3 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "iota-graphql-e2e-tests" +version = "0.1.0" +authors = ["Mysten Labs "] +description = "End to end tests for Iota GraphQL" +license = "Apache-2.0" +publish = false +edition = "2021" + +[dev-dependencies] +datatest-stable.workspace = true +iota-graphql-rpc.workspace = true +iota-transactional-test-runner.workspace = true +tokio.workspace = true + +[[test]] +name = "tests" +harness = false + +[dependencies] + +[features] +default = ["pg_backend"] +pg_integration = [] +pg_backend = [] + +[target.'cfg(msim)'.dependencies] +msim.workspace = true diff --git a/crates/iota-graphql-e2e-tests/README.md b/crates/iota-graphql-e2e-tests/README.md new file mode 100644 index 00000000000..051f93e1d4f --- /dev/null +++ b/crates/iota-graphql-e2e-tests/README.md @@ -0,0 +1,64 @@ +End-to-end tests for GraphQL service, built on top of the transactional test +runner. + +# Local Set-up + +These tests require a running instance of the `postgres` service, with a +database set-up. The instructions below assume that `postgres` has been +installed using `brew`: + +1. See the instructions in the Iota Indexer [README](../iota-indexer/README.md) + for pre-requisites and starting the Postgres service. + +2. When postgres is initially installed, it creates a role for your current + user. We need to use that role to create the role that will access the + database: + +```sh +$ ME=$(whoami) +$ psql "postgres://$ME:$ME@localhost:5432/postgres" \ + -c "CREATE ROLE postgres WITH SUPERUSER LOGIN PASSWORD 'postgrespw';" +``` + +3. Then, create the database that the tests expect, using the `postgres` user + and increase the max connections since many tests might run in parallel. + +```sh +$ psql "postgres://postgres:postgrespw@localhost:5432/postgres" \ + -c "CREATE DATABASE iota_indexer_v2;" -c "ALTER SYSTEM SET max_connections = 500;" +``` + +4. Finally, restart the `postgres` server so the max connections change takes + effect. + +Mac +```sh +brew services restart postgresql@15 + +``` + +Linux +```sh +/etc/init.d/postgresql restart +``` + +# Running Locally + +When running the tests locally, they must be run with the `pg_integration` +feature enabled: + +```sh +$ cargo nextest run --features pg_integration +``` + +# Snapshot Stability + +Tests are pinned to an existing protocol version that has already been used on a +production network. The protocol version controls the protocol config and also +the version of the framework that gets used by tests. By using a version that +has already been used in a production setting, we are guaranteeing that it will +not be changed by later modifications to the protocol or framework (this would +be a bug). + +When adding a new test, **remember to set the `--protocol-version`** for that +test to ensure stability. diff --git a/crates/iota-graphql-e2e-tests/src/lib.rs b/crates/iota-graphql-e2e-tests/src/lib.rs new file mode 100644 index 00000000000..7de55296af9 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/src/lib.rs @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#![forbid(unsafe_code)] + +// Empty src/lib.rs to get rusty-tags working. diff --git a/crates/sui-graphql-e2e-tests/tests/available_range/available_range.exp b/crates/iota-graphql-e2e-tests/tests/available_range/available_range.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/available_range/available_range.exp rename to crates/iota-graphql-e2e-tests/tests/available_range/available_range.exp diff --git a/crates/sui-graphql-e2e-tests/tests/available_range/available_range.move b/crates/iota-graphql-e2e-tests/tests/available_range/available_range.move similarity index 93% rename from crates/sui-graphql-e2e-tests/tests/available_range/available_range.move rename to crates/iota-graphql-e2e-tests/tests/available_range/available_range.move index 86611512c88..52a2256f198 100644 --- a/crates/sui-graphql-e2e-tests/tests/available_range/available_range.move +++ b/crates/iota-graphql-e2e-tests/tests/available_range/available_range.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --simulator diff --git a/crates/sui-graphql-e2e-tests/tests/call/checkpoint_connection_pagination.exp b/crates/iota-graphql-e2e-tests/tests/call/checkpoint_connection_pagination.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/call/checkpoint_connection_pagination.exp rename to crates/iota-graphql-e2e-tests/tests/call/checkpoint_connection_pagination.exp diff --git a/crates/sui-graphql-e2e-tests/tests/call/checkpoint_connection_pagination.move b/crates/iota-graphql-e2e-tests/tests/call/checkpoint_connection_pagination.move similarity index 98% rename from crates/sui-graphql-e2e-tests/tests/call/checkpoint_connection_pagination.move rename to crates/iota-graphql-e2e-tests/tests/call/checkpoint_connection_pagination.move index 1b90a3b8d66..58a6d845a7c 100644 --- a/crates/sui-graphql-e2e-tests/tests/call/checkpoint_connection_pagination.move +++ b/crates/iota-graphql-e2e-tests/tests/call/checkpoint_connection_pagination.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses Test=0x0 --simulator diff --git a/crates/sui-graphql-e2e-tests/tests/call/coin_metadata.exp b/crates/iota-graphql-e2e-tests/tests/call/coin_metadata.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/call/coin_metadata.exp rename to crates/iota-graphql-e2e-tests/tests/call/coin_metadata.exp diff --git a/crates/sui-graphql-e2e-tests/tests/call/coin_metadata.move b/crates/iota-graphql-e2e-tests/tests/call/coin_metadata.move similarity index 88% rename from crates/sui-graphql-e2e-tests/tests/call/coin_metadata.move rename to crates/iota-graphql-e2e-tests/tests/call/coin_metadata.move index 65709474c8e..4e84c1d2c4a 100644 --- a/crates/sui-graphql-e2e-tests/tests/call/coin_metadata.move +++ b/crates/iota-graphql-e2e-tests/tests/call/coin_metadata.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses test=0x0 --accounts A --simulator //# publish --sender A module test::fake { - use sui::coin; + use iota::coin; public struct FAKE has drop {} @@ -33,7 +34,7 @@ module test::fake { //# programmable --sender A --inputs object(1,2) 100 @A -//> 0: sui::coin::mint(Input(0), Input(1)); +//> 0: iota::coin::mint(Input(0), Input(1)); //> TransferObjects([Result(0)], Input(2)) //# create-checkpoint diff --git a/crates/sui-graphql-e2e-tests/tests/call/dynamic_fields.exp b/crates/iota-graphql-e2e-tests/tests/call/dynamic_fields.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/call/dynamic_fields.exp rename to crates/iota-graphql-e2e-tests/tests/call/dynamic_fields.exp diff --git a/crates/iota-graphql-e2e-tests/tests/call/dynamic_fields.move b/crates/iota-graphql-e2e-tests/tests/call/dynamic_fields.move new file mode 100644 index 00000000000..2597e1803a9 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/call/dynamic_fields.move @@ -0,0 +1,177 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// Create some dynamic fields on an object, and then try to query them. +// There should be 1 dynamic object field (MoveObject) and 3 dynamic fields. +// When the object is wrapped, we expect that making the query through Object will return null. +// But it should still be visible through the Owner type. +// This test also demonstrates why we need separate dynamicField and dynamicObjectField APIs. +// It is possible for a dynamic field and a dynamic object field to share the same name lookup. + +//# init --protocol-version 39 --addresses Test=0x0 --accounts A --simulator + +//# publish +module Test::m { + use iota::dynamic_field as field; + use iota::dynamic_object_field as ofield; + + public struct Wrapper has key { + id: object::UID, + o: Parent + } + + public struct Parent has key, store { + id: object::UID, + } + + public struct Child has key, store { + id: object::UID, + } + + public entry fun create_obj(ctx: &mut TxContext){ + let id = object::new(ctx); + iota::transfer::public_transfer(Parent { id }, ctx.sender()) + } + + public entry fun add_df(obj: &mut Parent) { + let id = &mut obj.id; + field::add(id, 0, 0); + field::add, u64>(id, b"", 1); + field::add(id, false, 2); + } + + public entry fun add_dof(parent: &mut Parent, ctx: &mut TxContext) { + let child = Child { id: object::new(ctx) }; + ofield::add(&mut parent.id, 0, child); + } + + public entry fun wrap(parent: Parent, ctx: &mut TxContext) { + let wrapper = Wrapper { id: object::new(ctx), o: parent }; + iota::transfer::transfer(wrapper, ctx.sender()) + } +} + +//# run Test::m::create_obj --sender A + +//# run Test::m::add_df --sender A --args object(2,0) + +//# run Test::m::add_dof --sender A --args object(2,0) + +//# create-checkpoint + +//# run-graphql +{ + object(address: "@{obj_2_0}") { + dynamicFields { + nodes { + name { + type { + repr + } + data + bcs + } + value { + ... on MoveObject { + __typename + } + ... on MoveValue { + __typename + } + } + } + } + } +} + +//# run Test::m::wrap --sender A --args object(2,0) + +//# create-checkpoint + +//# run-graphql +{ + object(address: "@{obj_2_0}") { + dynamicFields { + nodes { + name { + type { + repr + } + data + bcs + } + value { + ... on MoveObject { + __typename + } + ... on MoveValue { + __typename + } + } + } + } + } +} + +//# run-graphql +{ + owner(address: "@{obj_2_0}") { + dynamicFields { + nodes { + name { + type { + repr + } + data + bcs + } + value { + ... on MoveObject { + __typename + } + ... on MoveValue { + bcs + data + __typename + } + } + } + } + } +} + +//# run-graphql +{ + owner(address: "@{obj_2_0}") { + dynamicField(name: {type: "u64", bcs: "AAAAAAAAAAA="}) { + name { + type { + repr + } + data + bcs + } + value { + ... on MoveValue { + __typename + bcs + data + } + } + } + } +} + +//# run-graphql +{ + owner(address: "@{obj_2_0}") { + dynamicObjectField(name: {type: "u64", bcs: "AAAAAAAAAAA="}) { + value { + ... on MoveObject { + __typename + } + } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/call/owned_objects.exp b/crates/iota-graphql-e2e-tests/tests/call/owned_objects.exp similarity index 95% rename from crates/sui-graphql-e2e-tests/tests/call/owned_objects.exp rename to crates/iota-graphql-e2e-tests/tests/call/owned_objects.exp index 8ae4e55705a..4abfbc17bd4 100644 --- a/crates/sui-graphql-e2e-tests/tests/call/owned_objects.exp +++ b/crates/iota-graphql-e2e-tests/tests/call/owned_objects.exp @@ -24,7 +24,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2302800, storage_rebate: task 4 'view-object'. lines 65-65: Owner: Account Address ( A ) Version: 3 -Contents: Test::M1::Object {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, value: 0u64} +Contents: Test::M1::Object {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, value: 0u64} task 5 'create-checkpoint'. lines 67-67: Checkpoint created: 1 diff --git a/crates/sui-graphql-e2e-tests/tests/call/owned_objects.move b/crates/iota-graphql-e2e-tests/tests/call/owned_objects.move similarity index 97% rename from crates/sui-graphql-e2e-tests/tests/call/owned_objects.move rename to crates/iota-graphql-e2e-tests/tests/call/owned_objects.move index c6f9ae8e5ad..ffbb083a34b 100644 --- a/crates/sui-graphql-e2e-tests/tests/call/owned_objects.move +++ b/crates/iota-graphql-e2e-tests/tests/call/owned_objects.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses Test=0x0 A=0x42 --simulator @@ -21,7 +22,7 @@ //# publish module Test::M1 { - use sui::coin::Coin; + use iota::coin::Coin; public struct Object has key, store { id: UID, diff --git a/crates/iota-graphql-e2e-tests/tests/call/simple.exp b/crates/iota-graphql-e2e-tests/tests/call/simple.exp new file mode 100644 index 00000000000..071e4452659 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/call/simple.exp @@ -0,0 +1,271 @@ +processed 25 tasks + +init: +validator_0: object(0,0) + +task 1 'publish'. lines 6-25: +created: object(1,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 5570800, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'run'. lines 27-27: +created: object(2,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 2302800, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'run'. lines 29-29: +created: object(3,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 2302800, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 4 'view-object'. lines 31-31: +Owner: Account Address ( validator_0 ) +Version: 1 +Contents: iota_system::validator_cap::UnverifiedValidatorOperationCap {id: iota::object::UID {id: iota::object::ID {bytes: fake(0,0)}}, authorizer_validator_address: validator_0} + +task 5 'view-object'. lines 33-33: +Owner: Account Address ( A ) +Version: 3 +Contents: Test::M1::Object {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, value: 0u64} + +task 6 'view-object'. lines 35-35: +Owner: Account Address ( validator_0 ) +Version: 4 +Contents: Test::M1::Object {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,0)}}, value: 0u64} + +task 7 'create-checkpoint'. lines 37-37: +Checkpoint created: 4 + +task 8 'view-checkpoint'. lines 39-39: +CheckpointSummary { epoch: 0, seq: 4, content_digest: D3oWLCcqoa1D15gxzvMaDemNNY8YYVspAkYkcmtQKWRt, + epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 3000000, storage_cost: 10176400, storage_rebate: 1956240, non_refundable_storage_fee: 19760 }} + +task 9 'advance-epoch'. lines 41-41: +Epoch advanced: 5 + +task 10 'view-checkpoint'. lines 43-43: +CheckpointSummary { epoch: 5, seq: 10, content_digest: C61cKCJWb9sw7ntgsD6WSAXioh4ogmbNMty8v4oxsjhB, + epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 0, storage_cost: 0, storage_rebate: 0, non_refundable_storage_fee: 0 }} + +task 11 'run-graphql'. lines 45-50: +Response: { + "data": { + "checkpoint": { + "sequenceNumber": 10 + } + } +} + +task 12 'create-checkpoint'. lines 52-52: +Checkpoint created: 11 + +task 13 'view-checkpoint'. lines 54-54: +CheckpointSummary { epoch: 6, seq: 11, content_digest: D3oWLCcqoa1D15gxzvMaDemNNY8YYVspAkYkcmtQKWRt, + epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 0, storage_cost: 0, storage_rebate: 0, non_refundable_storage_fee: 0 }} + +task 14 'run-graphql'. lines 56-61: +Response: { + "data": { + "checkpoint": { + "sequenceNumber": 11 + } + } +} + +task 15 'run-graphql'. lines 63-68: +Headers: { + "content-type": "application/json", + "content-length": "157", + "x-iota-rpc-version": "2024.2.0-testing-no-sha", + "access-control-allow-origin": "*", + "vary": "origin", + "vary": "access-control-request-method", + "vary": "access-control-request-headers", +} +Service version: 2024.2.0-testing-no-sha +Response: { + "data": { + "checkpoint": { + "sequenceNumber": 11 + } + }, + "extensions": { + "usage": { + "inputNodes": 2, + "outputNodes": 2, + "depth": 2, + "variables": 0, + "fragments": 0, + "queryPayload": 41 + } + } +} + +task 16 'view-checkpoint'. lines 70-70: +CheckpointSummary { epoch: 6, seq: 11, content_digest: D3oWLCcqoa1D15gxzvMaDemNNY8YYVspAkYkcmtQKWRt, + epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 0, storage_cost: 0, storage_rebate: 0, non_refundable_storage_fee: 0 }} + +task 17 'advance-epoch'. lines 72-75: +Epoch advanced: 6 + +task 18 'run-graphql'. lines 77-92: +Response: { + "data": { + "address": { + "objects": { + "edges": [ + { + "node": { + "address": "0x127ebc904fc866d4677fca7f7b428bff5b88527c305434c882e712945bbeb630", + "digest": "Cmx2Tcf2RoMqnxriyZFSccHtHk7jA4HVKRKykrNMtKpW", + "owner": { + "__typename": "AddressOwner" + } + } + } + ] + } + } + } +} + +task 19 'run-graphql'. lines 94-149: +Response: { + "data": { + "address": { + "objects": { + "edges": [] + } + }, + "second": { + "objects": { + "edges": [ + { + "node": { + "address": "0x127ebc904fc866d4677fca7f7b428bff5b88527c305434c882e712945bbeb630", + "digest": "Cmx2Tcf2RoMqnxriyZFSccHtHk7jA4HVKRKykrNMtKpW", + "owner": { + "__typename": "AddressOwner" + } + } + } + ] + } + }, + "val_objs": { + "objects": { + "edges": [ + { + "node": { + "address": "0x00ca13a0bf70f8768696ebd40a05bafb132e05f020f4186a17ba90e6737abaca", + "digest": "9R3vvuwUS4Zk1joFrUCAg6azt9kfBGVJgpH5MoEVfu8y", + "owner": { + "__typename": "AddressOwner" + } + } + }, + { + "node": { + "address": "0x76fb11d049dd7b1328f2cfb196f1cb18d444d20c9c5ca59c832e5a15ac80594c", + "digest": "uaafRXthffyBnsd17L6D8wWQtaYrsbyJ9U4fRsu4tJW", + "owner": { + "__typename": "AddressOwner" + } + } + }, + { + "node": { + "address": "0xa75755ab1ad9cc5a1f9e0745d770d7eeb724d30fca9a96d4dc881e2e57aa8c66", + "digest": "AycePHSxuYVtwTaK9xG38Bjb7T1237mEC4U1WUDy1WFW", + "owner": { + "__typename": "AddressOwner" + } + } + }, + { + "node": { + "address": "0xaf12bf78851720ffb7583032490b150ab1c37e430628d91d7e84dbdbc93c17e3", + "digest": "7vsLSSY4ZntwJSkTfB54MGDxbw8RGQtUQjtNX64PDeo1", + "owner": { + "__typename": "AddressOwner" + } + } + }, + { + "node": { + "address": "0xc68bdb786bf1563aaf02ca2ed63d7f7d83c71ff277dde05fbdd962030c6e180f", + "digest": "CvbTB1bRP3ngTtwkE2YSfFaSNWkpUV5YgE3ikqwaiMJa", + "owner": { + "__typename": "AddressOwner" + } + } + }, + { + "node": { + "address": "0xe03a1feb19afc2c173044f6d778432c74c567604e0dcc759ae06680453f460d4", + "digest": "FbF9oAL5jJTFkxUkPSEPyUDDbWEhuFzzem353cRGgCG3", + "owner": { + "__typename": "AddressOwner" + } + } + } + ] + } + }, + "object": { + "version": 3, + "owner": { + "__typename": "AddressOwner", + "owner": { + "address": "0x0000000000000000000000000000000000000000000000000000000000000042" + } + } + } + } +} + +task 20 'run-graphql'. lines 151-167: +Response: { + "data": { + "epoch": { + "validatorSet": { + "activeValidators": { + "nodes": [ + { + "address": { + "address": "0xa7b032703878aa74c3126935789fd1d4d7e111d5911b09247d6963061c312b5a" + } + } + ] + } + } + }, + "address": { + "address": "0xa7b032703878aa74c3126935789fd1d4d7e111d5911b09247d6963061c312b5a" + } + } +} + +task 21 'run-graphql'. lines 169-175: +Response: { + "data": { + "epoch": { + "referenceGasPrice": "234" + } + } +} + +task 22 'run'. lines 177-177: +created: object(22,0) +mutated: object(0,1) +gas summary: computation_cost: 999000, storage_cost: 2302800, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 23 'run'. lines 179-179: +created: object(23,0) +mutated: object(0,1) +gas summary: computation_cost: 1000000, storage_cost: 2302800, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 24 'run'. lines 181-181: +created: object(24,0) +mutated: object(0,1) +gas summary: computation_cost: 235000, storage_cost: 2302800, storage_rebate: 978120, non_refundable_storage_fee: 9880 diff --git a/crates/iota-graphql-e2e-tests/tests/call/simple.move b/crates/iota-graphql-e2e-tests/tests/call/simple.move new file mode 100644 index 00000000000..ad4edf3ea04 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/call/simple.move @@ -0,0 +1,182 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --protocol-version 39 --addresses Test=0x0 A=0x42 --simulator --custom-validator-account --reference-gas-price 234 --default-gas-price 1000 + +//# publish +module Test::M1 { + use iota::coin::Coin; + + public struct Object has key, store { + id: UID, + value: u64, + } + + fun foo(_p1: u64, value1: T, _value2: &Coin, _p2: u64): T { + value1 + } + + public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { + transfer::public_transfer( + Object { id: object::new(ctx), value }, + recipient + ) + } +} + +//# run Test::M1::create --args 0 @A --gas-price 1000 + +//# run Test::M1::create --args 0 @validator_0 + +//# view-object 0,0 + +//# view-object 2,0 + +//# view-object 3,0 + +//# create-checkpoint 4 + +//# view-checkpoint + +//# advance-epoch 6 + +//# view-checkpoint + +//# run-graphql +{ + checkpoint { + sequenceNumber + } +} + +//# create-checkpoint + +//# view-checkpoint + +//# run-graphql +{ + checkpoint { + sequenceNumber + } +} + +//# run-graphql --show-usage --show-headers --show-service-version +{ + checkpoint { + sequenceNumber + } +} + +//# view-checkpoint + +//# advance-epoch + +// Demonstrates using variables +// If the variable ends in _opt, this is the optional variant + +//# run-graphql +{ + address(address: "@{A}") { + objects { + edges { + node { + address + digest + owner { + __typename + } + } + } + } + } +} + +//# run-graphql +{ + address(address: "@{Test}") { + objects { + edges { + node { + address + digest + owner { + __typename + } + } + } + } + } + second: address(address: "@{A}") { + objects { + edges { + node { + address + digest + owner { + __typename + } + } + } + } + } + + val_objs: address(address: "@{validator_0}") { + objects { + edges { + node { + address + digest + owner { + __typename + } + } + } + } + } + + object(address: "@{obj_2_0}") { + version + owner { + __typename + ... on AddressOwner { + owner { + address + } + } + } + } + +} + +//# run-graphql +{ + epoch { + validatorSet { + activeValidators { + nodes { + address { + address + } + } + } + } + } + address(address: "@{validator_0}") { + address + } +} + +//# run-graphql +# Since we set it at the init, it should be the same as 234 +{ + epoch { + referenceGasPrice + } +} + +//# run Test::M1::create --args 0 @A --gas-price 999 + +//# run Test::M1::create --args 0 @A --gas-price 1000 + +//# run Test::M1::create --args 0 @A --gas-price 235 diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/balances.exp b/crates/iota-graphql-e2e-tests/tests/consistency/balances.exp similarity index 96% rename from crates/sui-graphql-e2e-tests/tests/consistency/balances.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/balances.exp index 9d18bb2474c..b5445369176 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/balances.exp +++ b/crates/iota-graphql-e2e-tests/tests/consistency/balances.exp @@ -55,7 +55,7 @@ Response: { "nodes": [ { "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" }, "coinObjectCount": 1, "totalBalance": "299999982296272" @@ -90,7 +90,7 @@ Response: { "nodes": [ { "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" }, "coinObjectCount": 1, "totalBalance": "299999981273168" @@ -125,7 +125,7 @@ Response: { "nodes": [ { "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" }, "coinObjectCount": 1, "totalBalance": "299999980250064" @@ -166,7 +166,7 @@ Response: { "nodes": [ { "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" }, "coinObjectCount": 1, "totalBalance": "299999982296272" @@ -201,7 +201,7 @@ Response: { "nodes": [ { "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" }, "coinObjectCount": 1, "totalBalance": "299999981273168" @@ -236,7 +236,7 @@ Response: { "nodes": [ { "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" }, "coinObjectCount": 1, "totalBalance": "299999980250064" @@ -311,7 +311,7 @@ Response: { "nodes": [ { "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" }, "coinObjectCount": 1, "totalBalance": "299999981273168" @@ -346,7 +346,7 @@ Response: { "nodes": [ { "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" }, "coinObjectCount": 1, "totalBalance": "299999980250064" diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/balances.move b/crates/iota-graphql-e2e-tests/tests/consistency/balances.move similarity index 98% rename from crates/sui-graphql-e2e-tests/tests/consistency/balances.move rename to crates/iota-graphql-e2e-tests/tests/consistency/balances.move index 917c20c10f0..4c5c23bd841 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/balances.move +++ b/crates/iota-graphql-e2e-tests/tests/consistency/balances.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // cp | coins @@ -18,7 +19,7 @@ //# publish --sender A module P0::fake { - use sui::coin; + use iota::coin; public struct FAKE has drop {} @@ -48,7 +49,7 @@ module P0::fake { //# create-checkpoint //# programmable --sender A --inputs object(1,5) 100 object(1,1) -//> 0: sui::coin::mint(Input(0), Input(1)); +//> 0: iota::coin::mint(Input(0), Input(1)); //> MergeCoins(Input(2), [Result(0)]); //# create-checkpoint diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/checkpoints/transaction_blocks.exp b/crates/iota-graphql-e2e-tests/tests/consistency/checkpoints/transaction_blocks.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/consistency/checkpoints/transaction_blocks.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/checkpoints/transaction_blocks.exp diff --git a/crates/iota-graphql-e2e-tests/tests/consistency/checkpoints/transaction_blocks.move b/crates/iota-graphql-e2e-tests/tests/consistency/checkpoints/transaction_blocks.move new file mode 100644 index 00000000000..22725330cfb --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/consistency/checkpoints/transaction_blocks.move @@ -0,0 +1,96 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// checkpoint | transactions from A +// -----------+-------------------- +// 0 | 0 +// 1 | 4 +// 2 | 3 +// 3 | 2 + +//# init --protocol-version 39 --addresses Test=0x0 --accounts A B --simulator + +//# publish +module Test::M1 { + public struct Object has key, store { + id: UID, + value: u64, + } + + public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { + transfer::public_transfer( + Object { id: object::new(ctx), value }, + recipient + ) + } +} + +//# run Test::M1::create --args 0 @A --sender A + +//# run Test::M1::create --args 0 @A --sender A + +//# run Test::M1::create --args 0 @A --sender A + +//# run Test::M1::create --args 0 @A --sender A + +//# create-checkpoint + +//# run Test::M1::create --args 0 @A --sender A + +//# run Test::M1::create --args 0 @A --sender A + +//# run Test::M1::create --args 0 @A --sender A + +//# create-checkpoint + +//# run Test::M1::create --args 0 @A --sender A + +//# run Test::M1::create --args 0 @A --sender A + +//# create-checkpoint + +//# run-graphql +# Each transaction block's sender's last object resolves to the same last object at the latest +# state +{ + checkpoints { + nodes { + sequenceNumber + transactionBlocks(filter: { signAddress: "@{A}"}) { + edges { + cursor + node { + digest + sender { + objects(last: 1) { + edges { + cursor + } + } + } + } + } + } + } + } +} + +//# run-graphql +# Similarly, resolving the checkpoint's epoch will return the epoch the checkpoint belongs in, but +# the nested checkpoints connection will behave as if it was made on the top-level. +{ + checkpoints { + nodes { + sequenceNumber + epoch { + epochId + checkpoints { + nodes { + sequenceNumber + } + } + } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/coins.exp b/crates/iota-graphql-e2e-tests/tests/consistency/coins.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/consistency/coins.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/coins.exp diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/coins.move b/crates/iota-graphql-e2e-tests/tests/consistency/coins.move similarity index 97% rename from crates/sui-graphql-e2e-tests/tests/consistency/coins.move rename to crates/iota-graphql-e2e-tests/tests/consistency/coins.move index 45832e60dfb..37aee9695b2 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/coins.move +++ b/crates/iota-graphql-e2e-tests/tests/consistency/coins.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // chkpt 1 | chkpt 2 | chkpt 3 | chkpt 4 | chkpt 5 | snapshot [0, 4) @@ -11,7 +12,7 @@ //# publish --sender A module P0::fake { - use sui::coin; + use iota::coin; public struct FAKE has drop {} @@ -41,7 +42,7 @@ module P0::fake { //# create-checkpoint //# programmable --sender A --inputs object(1,5) 100000 object(1,1) -//> 0: sui::coin::mint(Input(0), Input(1)); +//> 0: iota::coin::mint(Input(0), Input(1)); //> MergeCoins(Input(2), [Result(0)]); //# create-checkpoint diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_df.exp b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_df.exp similarity index 95% rename from crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_df.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_df.exp index 4a979278d43..da7afce7d65 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_df.exp +++ b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_df.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2302800, storage_rebate: task 3 'view-object'. lines 59-59: Owner: Account Address ( A ) Version: 2 -Contents: Test::M1::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, count: 0u64} +Contents: Test::M1::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, count: 0u64} task 4 'run'. lines 61-61: created: object(4,0), object(4,1), object(4,2) @@ -26,7 +26,7 @@ gas summary: computation_cost: 1000000, storage_cost: 8664000, storage_rebate: task 5 'view-object'. lines 63-63: Owner: Account Address ( A ) Version: 3 -Contents: Test::M1::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, count: 0u64} +Contents: Test::M1::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, count: 0u64} task 6 'run'. lines 65-65: created: object(6,0), object(6,1), object(6,2) @@ -36,7 +36,7 @@ gas summary: computation_cost: 1000000, storage_cost: 8664000, storage_rebate: task 7 'view-object'. lines 67-67: Owner: Account Address ( A ) Version: 4 -Contents: Test::M1::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, count: 0u64} +Contents: Test::M1::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, count: 0u64} task 8 'run'. lines 69-69: mutated: object(0,0), object(2,0) diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_df.move b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_df.move similarity index 98% rename from crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_df.move rename to crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_df.move index ff504407c4f..ab7567d9bd4 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_df.move +++ b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_df.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // version | status @@ -13,7 +14,7 @@ //# publish module Test::M1 { - use sui::dynamic_field as field; + use iota::dynamic_field as field; use std::string::{String, utf8}; public struct Parent has key, store { diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_dof.exp b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_dof.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_dof.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_dof.exp diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_dof.move b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_dof.move similarity index 98% rename from crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_dof.move rename to crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_dof.move index 72d9446e86e..147d85634cb 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_dof.move +++ b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/deleted_dof.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // parent version | child version | status @@ -13,7 +14,7 @@ //# publish module Test::M1 { - use sui::dynamic_object_field as ofield; + use iota::dynamic_object_field as ofield; public struct Parent has key, store { id: UID, diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer.exp b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer.exp diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer.move b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer.move similarity index 97% rename from crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer.move rename to crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer.move index a50671fe601..d009ed6aac9 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer.move +++ b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // The previous implementation sets the newer criteria when the parent version is provided by @@ -18,7 +19,7 @@ //# publish module Test::M1 { - use sui::dynamic_object_field as ofield; + use iota::dynamic_object_field as ofield; public struct Parent has key, store { id: UID, diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer_reclaim_add.exp b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer_reclaim_add.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer_reclaim_add.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer_reclaim_add.exp diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer_reclaim_add.move b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer_reclaim_add.move similarity index 97% rename from crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer_reclaim_add.move rename to crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer_reclaim_add.move index f20d1a863db..1d634e8d679 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer_reclaim_add.move +++ b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dof_add_reclaim_transfer_reclaim_add.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Test that we do not return the child object when it is not owned by the parent or when it is @@ -17,7 +18,7 @@ //# publish module Test::M1 { - use sui::dynamic_object_field as ofield; + use iota::dynamic_object_field as ofield; public struct Parent has key, store { id: UID, diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dynamic_fields.exp b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dynamic_fields.exp similarity index 95% rename from crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dynamic_fields.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dynamic_fields.exp index 32d49b13fbb..0a48b341d2d 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dynamic_fields.exp +++ b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dynamic_fields.exp @@ -16,12 +16,12 @@ gas summary: computation_cost: 1000000, storage_cost: 3549200, storage_rebate: task 3 'view-object'. lines 88-88: Owner: Account Address ( A ) Version: 2 -Contents: Test::M1::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: Test::M1::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 4 'view-object'. lines 90-90: Owner: Account Address ( A ) Version: 2 -Contents: Test::M1::Child {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, count: 0u64} +Contents: Test::M1::Child {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, count: 0u64} task 5 'programmable'. lines 92-94: created: object(5,0) @@ -31,12 +31,12 @@ gas summary: computation_cost: 1000000, storage_cost: 6004000, storage_rebate: task 6 'view-object'. lines 96-96: Owner: Account Address ( A ) Version: 3 -Contents: Test::M1::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: Test::M1::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 7 'view-object'. lines 98-98: Owner: Object ID: ( fake(5,0) ) Version: 3 -Contents: Test::M1::Child {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, count: 1u64} +Contents: Test::M1::Child {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, count: 1u64} task 8 'create-checkpoint'. lines 100-100: Checkpoint created: 1 @@ -97,12 +97,12 @@ gas summary: computation_cost: 1000000, storage_cost: 9910400, storage_rebate: task 11 'view-object'. lines 170-170: Owner: Account Address ( A ) Version: 4 -Contents: Test::M1::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: Test::M1::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 12 'view-object'. lines 172-172: Owner: Object ID: ( fake(5,0) ) Version: 4 -Contents: Test::M1::Child {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, count: 2u64} +Contents: Test::M1::Child {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, count: 2u64} task 13 'create-checkpoint'. lines 174-174: Checkpoint created: 2 @@ -302,12 +302,12 @@ gas summary: computation_cost: 1000000, storage_cost: 8603200, storage_rebate: task 17 'view-object'. lines 281-281: Owner: Account Address ( A ) Version: 5 -Contents: Test::M1::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: Test::M1::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 18 'view-object'. lines 283-283: Owner: Object ID: ( fake(5,0) ) Version: 4 -Contents: Test::M1::Child {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, count: 2u64} +Contents: Test::M1::Child {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, count: 2u64} task 19 'create-checkpoint'. lines 285-285: Checkpoint created: 3 @@ -542,12 +542,12 @@ gas summary: computation_cost: 1000000, storage_cost: 2242000, storage_rebate: task 22 'view-object'. lines 342-342: Owner: Account Address ( A ) Version: 6 -Contents: Test::M1::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} +Contents: Test::M1::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,1)}}} task 23 'view-object'. lines 344-344: Owner: Object ID: ( fake(5,0) ) Version: 4 -Contents: Test::M1::Child {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, count: 2u64} +Contents: Test::M1::Child {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, count: 2u64} task 24 'create-checkpoint'. lines 346-346: Checkpoint created: 4 diff --git a/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dynamic_fields.move b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dynamic_fields.move new file mode 100644 index 00000000000..e8df64c9aef --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/dynamic_fields.move @@ -0,0 +1,529 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// chkpt1: create parent and child @ version 2 +// chkpt1: add dof to parent @ version 3 +// chkpt2: PTB(mutate dof, add df1, 2, 3) - parent and dof @ version 4 +// chkpt3: add df4, 5, 6 parent @ version 5, child @ version 4 +// chkpt4: remove df1, df2, df3 parent @ version 6, child @ version 4 + +//# init --protocol-version 39 --addresses Test=0x0 --accounts A --simulator + +//# publish +module Test::M1 { + use iota::dynamic_object_field as ofield; + use iota::dynamic_field as field; + use std::string::{String, utf8}; + + public struct Parent has key, store { + id: UID, + } + + public struct Child has key, store { + id: UID, + count: u64, + } + + public entry fun parent(recipient: address, ctx: &mut TxContext) { + transfer::public_transfer( + Parent { id: object::new(ctx) }, + recipient + ) + } + + public entry fun child(recipient: address, ctx: &mut TxContext) { + transfer::public_transfer( + Child { id: object::new(ctx), count: 0 }, + recipient + ) + } + + public fun add_child(parent: &mut Parent, child: Child, name: u64) { + ofield::add(&mut parent.id, name, child); + } + + public fun mutate_child(child: &mut Child) { + child.count = child.count + 1; + } + + public fun mutate_child_via_parent(parent: &mut Parent, name: u64) { + mutate_child(ofield::borrow_mut(&mut parent.id, name)) + } + + public fun reclaim_child(parent: &mut Parent, name: u64): Child { + ofield::remove(&mut parent.id, name) + } + + public fun delete_child(parent: &mut Parent, name: u64) { + let Child { id, count: _ } = reclaim_child(parent, name); + object::delete(id); + } + + public entry fun add_df(obj: &mut Parent) { + let id = &mut obj.id; + field::add(id, utf8(b"df1"), utf8(b"df1")); + field::add(id, utf8(b"df2"), utf8(b"df2")); + field::add(id, utf8(b"df3"), utf8(b"df3")); + } + + public entry fun remove_df(obj: &mut Parent) { + let id = &mut obj.id; + field::remove(id, utf8(b"df1")); + field::remove(id, utf8(b"df2")); + field::remove(id, utf8(b"df3")); + } + + public entry fun add_more_df(obj: &mut Parent) { + let id = &mut obj.id; + field::add(id, utf8(b"df4"), utf8(b"df4")); + field::add(id, utf8(b"df5"), utf8(b"df5")); + field::add(id, utf8(b"df6"), utf8(b"df6")); + } +} + +//# programmable --sender A --inputs @A 42 +//> 0: Test::M1::parent(Input(0)); +//> 1: Test::M1::child(Input(0)); + +//# view-object 2,1 + +//# view-object 2,0 + +//# programmable --sender A --inputs object(2,1) object(2,0) 420 +//> Test::M1::add_child(Input(0), Input(1), Input(2)); +//> Test::M1::mutate_child_via_parent(Input(0), Input(2)); + +//# view-object 2,1 + +//# view-object 2,0 + +//# create-checkpoint + +//# run-graphql +fragment DynamicFieldSelect on DynamicField { + name { + bcs + type { + repr + } + } + value { + ... on MoveObject { + contents { + json + } + } + ... on MoveValue { + json + } + } +} + +fragment DynamicFieldsSelect on DynamicFieldConnection { + edges { + cursor + node { + ...DynamicFieldSelect + } + } +} + +{ + parent_version_2_no_dof: object(address: "@{obj_2_1}", version: 2) { + address + dynamicFields { + ...DynamicFieldsSelect + } + } + parent_version_3_has_dof: object(address: "@{obj_2_1}", version: 3) { + dynamicFields { + ...DynamicFieldsSelect + } + } + child_version_2_no_parent: object(address: "@{obj_2_0}", version: 2) { + address + owner { + ... on Parent { + parent { + address + } + } + } + } + # Note that the value object's parent is the field object, not the parent object that we may + # expect + child_version_3_has_parent: object(address: "@{obj_2_0}", version: 3) { + owner { + ... on Parent { + parent { + address + } + } + } + } +} + +//# programmable --sender A --inputs object(2,1) 420 +//> Test::M1::mutate_child_via_parent(Input(0), Input(1)); +//> Test::M1::add_df(Input(0)); + +//# view-object 2,1 + +//# view-object 2,0 + +//# create-checkpoint + +//# run-graphql --cursors @{obj_5_0,1} @{obj_5_0,2} +fragment DynamicFieldSelect on DynamicField { + name { + bcs + type { + repr + } + } + value { + ... on MoveObject { + contents { + json + } + } + ... on MoveValue { + json + } + } +} + +fragment DynamicFieldsSelect on DynamicFieldConnection { + edges { + cursor + node { + ...DynamicFieldSelect + } + } +} + +{ + parent_version_4_show_dof_and_dfs: object(address: "@{obj_2_1}", version: 4) { + dynamicFields { + ...DynamicFieldsSelect + } + } + parent_version_3_only_dof: object(address: "@{obj_2_1}", version: 3) { + dynamicFields { + ...DynamicFieldsSelect + } + } + use_dof_version_3_cursor_at_parent_version_4: object(address: "@{obj_2_1}", version: 4) { + dynamicFields(after: "@{cursor_0}") { + ...DynamicFieldsSelect + } + } + use_dof_version_4_cursor_at_parent_version_4: object(address: "@{obj_2_1}", version: 4) { + dynamicFields(after: "@{cursor_1}") { + ...DynamicFieldsSelect + } + } + use_dof_version_3_cursor_at_parent_version_3: object(address: "@{obj_2_1}", version: 3) { + dynamicFields(after: "@{cursor_0}") { + ...DynamicFieldsSelect + } + } + use_dof_version_4_cursor_at_version_3: object(address: "@{obj_2_1}", version: 3) { + dynamicFields(after: "@{cursor_1}") { + ...DynamicFieldsSelect + } + } +} + +//# run-graphql +fragment DynamicFieldSelect on DynamicField { + name { + bcs + type { + repr + } + } + value { + ... on MoveObject { + contents { + json + } + } + ... on MoveValue { + json + } + } +} + +{ + parent_version_3: object(address: "@{obj_2_1}", version: 3) { + dynamicObjectField(name: {type: "u64", bcs: "pAEAAAAAAAA="}) { + ...DynamicFieldSelect + } + dfNotAvailableYet: dynamicField(name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="}) { + ...DynamicFieldSelect + } + } + parent_version_4: object(address: "@{obj_2_1}", version: 4) { + dynamicObjectField(name: {type: "u64", bcs: "pAEAAAAAAAA="}) { + ...DynamicFieldSelect + } + dfAddedHere: dynamicField(name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="}) { + ...DynamicFieldSelect + } + } +} + + +//# programmable --sender A --inputs object(2,1) +//> Test::M1::add_more_df(Input(0)); + +//# view-object 2,1 + +//# view-object 2,0 + +//# create-checkpoint + +//# run-graphql --cursors @{obj_5_0,2} @{obj_5_0,3} +fragment DynamicFieldSelect on DynamicField { + name { + bcs + type { + repr + } + } + value { + ... on MoveObject { + contents { + json + } + } + ... on MoveValue { + json + } + } +} + +fragment DynamicFieldsSelect on DynamicFieldConnection { + edges { + cursor + node { + ...DynamicFieldSelect + } + } +} + +{ + parent_version_4_has_4_children: object(address: "@{obj_2_1}", version: 4) { + dynamicFields { + ...DynamicFieldsSelect + } + } + parent_version_4_paginated_on_dof_consistent: object(address: "@{obj_2_1}", version: 4) { + dynamicFields(after: "@{cursor_0}") { + ...DynamicFieldsSelect + } + } + parent_version_5_has_7_children: object(address: "@{obj_2_1}", version: 5) { + dynamicFields { + ...DynamicFieldsSelect + } + } + parent_version_5_paginated_on_dof_consistent: object(address: "@{obj_2_1}", version: 5) { + dynamicFields(after: "@{cursor_1}") { + ...DynamicFieldsSelect + } + } +} + +//# programmable --sender A --inputs object(2,1) 420 +//> Test::M1::remove_df(Input(0)); + +//# view-object 2,1 + +//# view-object 2,0 + +//# create-checkpoint + +//# run-graphql --cursors @{obj_5_0,2} @{obj_5_0,4} +fragment DynamicFieldSelect on DynamicField { + name { + bcs + type { + repr + } + } + value { + ... on MoveObject { + contents { + json + } + } + ... on MoveValue { + json + } + } +} + +fragment DynamicFieldsSelect on DynamicFieldConnection { + edges { + cursor + node { + ...DynamicFieldSelect + } + } +} + +{ + parent_version_4_has_df1_2_3: object(address: "@{obj_2_1}", version: 4) { + dynamicFields { + ...DynamicFieldsSelect + } + } + parent_version_4_paginated_on_dof_consistent: object(address: "@{obj_2_1}", version: 4) { + dynamicFields(after: "@{cursor_0}") { + ...DynamicFieldsSelect + } + } + parent_version_6_no_df_1_2_3: object(address: "@{obj_2_1}", version: 6) { + dynamicFields { + ...DynamicFieldsSelect + } + } + parent_version_6_paginated_no_df_1_2_3: object(address: "@{obj_2_1}", version: 6) { + dynamicFields(after: "@{cursor_1}") { + ...DynamicFieldsSelect + } + } +} + +//# run-graphql +fragment DynamicFieldSelect on DynamicField { + name { + bcs + type { + repr + } + } + value { + ... on MoveObject { + contents { + json + } + } + ... on MoveValue { + json + } + } +} + +{ + parent_version_4: object(address: "@{obj_2_1}", version: 4) { + dfAtParentVersion4: dynamicField(name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="}) { + ...DynamicFieldSelect + } + } + parent_version_6: object(address: "@{obj_2_1}", version: 6) { + dfAtParentVersion6: dynamicField(name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="}) { + ...DynamicFieldSelect + } + } +} + +//# advance-clock --duration-ns 1 + +//# create-checkpoint + +//# advance-clock --duration-ns 1 + +//# create-checkpoint + +//# force-object-snapshot-catchup --start-cp 0 --end-cp 5 + +//# create-checkpoint + +//# run-graphql --cursors @{obj_5_0,2} @{obj_5_0,4} +fragment DynamicFieldSelect on DynamicField { + name { + bcs + type { + repr + } + } + value { + ... on MoveObject { + contents { + json + } + } + ... on MoveValue { + json + } + } +} + +fragment DynamicFieldsSelect on DynamicFieldConnection { + edges { + cursor + node { + ...DynamicFieldSelect + } + } +} + +{ + parent_version_4_outside_consistent_range: object(address: "@{obj_2_1}", version: 4) { + dynamicFields { + ...DynamicFieldsSelect + } + } + parent_version_4_paginated_outside_consistent_range: object(address: "@{obj_2_1}", version: 4) { + dynamicFields(after: "@{cursor_0}") { + ...DynamicFieldsSelect + } + } + parent_version_6_no_df_1_2_3: object(address: "@{obj_2_1}", version: 6) { + dynamicFields { + ...DynamicFieldsSelect + } + } + parent_version_6_paginated_no_df_1_2_3: object(address: "@{obj_2_1}", version: 6) { + dynamicFields(after: "@{cursor_1}") { + ...DynamicFieldsSelect + } + } +} + +//# run-graphql +fragment DynamicFieldSelect on DynamicField { + name { + bcs + type { + repr + } + } + value { + ... on MoveObject { + contents { + json + } + } + ... on MoveValue { + json + } + } +} + +{ + parent_version_4: object(address: "@{obj_2_1}", version: 4) { + dfAtParentVersion4_outside_range: dynamicField(name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="}) { + ...DynamicFieldSelect + } + } + parent_version_6: object(address: "@{obj_2_1}", version: 6) { + dfAtParentVersion6: dynamicField(name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="}) { + ...DynamicFieldSelect + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_df.exp b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_df.exp similarity index 88% rename from crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_df.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_df.exp index cf28392974c..57a5c7336db 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_df.exp +++ b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_df.exp @@ -16,7 +16,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2302800, storage_rebate: task 3 'view-object'. lines 49-49: Owner: Account Address ( A ) Version: 2 -Contents: Test::M1::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, count: 0u64} +Contents: Test::M1::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, count: 0u64} task 4 'run'. lines 51-51: created: object(4,0), object(4,1), object(4,2) @@ -26,7 +26,7 @@ gas summary: computation_cost: 1000000, storage_cost: 8664000, storage_rebate: task 5 'view-object'. lines 53-53: Owner: Account Address ( A ) Version: 3 -Contents: Test::M1::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, count: 0u64} +Contents: Test::M1::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, count: 0u64} task 6 'run'. lines 55-55: mutated: object(0,0), object(2,0) @@ -35,7 +35,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2302800, storage_rebate: task 7 'view-object'. lines 57-57: Owner: Account Address ( A ) Version: 4 -Contents: Test::M1::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, count: 42u64} +Contents: Test::M1::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, count: 42u64} task 8 'create-checkpoint'. lines 59-59: Checkpoint created: 1 @@ -112,7 +112,7 @@ Response: { task 10 'view-object'. lines 111-111: Owner: Account Address ( A ) Version: 4 -Contents: Test::M1::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, count: 42u64} +Contents: Test::M1::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, count: 42u64} task 11 'run'. lines 113-113: mutated: object(0,0), object(2,0), object(4,1) @@ -121,7 +121,7 @@ gas summary: computation_cost: 1000000, storage_cost: 4484000, storage_rebate: task 12 'view-object'. lines 115-115: Owner: Account Address ( A ) Version: 5 -Contents: Test::M1::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, count: 42u64} +Contents: Test::M1::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, count: 42u64} task 13 'run'. lines 117-117: mutated: object(0,0), object(2,0) @@ -130,7 +130,7 @@ gas summary: computation_cost: 1000000, storage_cost: 2302800, storage_rebate: task 14 'view-object'. lines 119-119: Owner: Account Address ( A ) Version: 6 -Contents: Test::M1::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, count: 84u64} +Contents: Test::M1::Parent {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,0)}}, count: 84u64} task 15 'create-checkpoint'. lines 121-121: Checkpoint created: 2 diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_df.move b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_df.move similarity index 97% rename from crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_df.move rename to crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_df.move index d18687e36b6..00b0f725cbc 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_df.move +++ b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_df.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // version | status @@ -13,7 +14,7 @@ //# publish module Test::M1 { - use sui::dynamic_field as field; + use iota::dynamic_field as field; use std::string::{String, utf8}; public struct Parent has key, store { diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_dof.exp b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_dof.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_dof.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_dof.exp diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_dof.move b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_dof.move similarity index 98% rename from crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_dof.move rename to crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_dof.move index 34fa899e0af..b635ad412e6 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_dof.move +++ b/crates/iota-graphql-e2e-tests/tests/consistency/dynamic_fields/mutated_dof.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // parent version | child version | status @@ -14,7 +15,7 @@ //# publish module Test::M1 { - use sui::dynamic_object_field as ofield; + use iota::dynamic_object_field as ofield; public struct Parent has key, store { id: UID, diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/epochs/checkpoints.exp b/crates/iota-graphql-e2e-tests/tests/consistency/epochs/checkpoints.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/consistency/epochs/checkpoints.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/epochs/checkpoints.exp diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/epochs/checkpoints.move b/crates/iota-graphql-e2e-tests/tests/consistency/epochs/checkpoints.move similarity index 98% rename from crates/sui-graphql-e2e-tests/tests/consistency/epochs/checkpoints.move rename to crates/iota-graphql-e2e-tests/tests/consistency/epochs/checkpoints.move index db1f6eb8340..7ea33d77ba5 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/epochs/checkpoints.move +++ b/crates/iota-graphql-e2e-tests/tests/consistency/epochs/checkpoints.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // epoch | checkpoints diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/epochs/transaction_blocks.exp b/crates/iota-graphql-e2e-tests/tests/consistency/epochs/transaction_blocks.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/consistency/epochs/transaction_blocks.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/epochs/transaction_blocks.exp diff --git a/crates/iota-graphql-e2e-tests/tests/consistency/epochs/transaction_blocks.move b/crates/iota-graphql-e2e-tests/tests/consistency/epochs/transaction_blocks.move new file mode 100644 index 00000000000..b07e3198f19 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/consistency/epochs/transaction_blocks.move @@ -0,0 +1,283 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// tx | func | checkpoint | epoch +// ---+----------------+------------+------- +// 0 | | 0 | 0 +// 1 | make_immutable | 1 | 0 +// 2 | create | 2 | 0 +// 3 | epoch | 3 | 0 +// 4 | create | 4 | 1 +// 5 | create | 5 | 1 +// 6 | create | 6 | 1 +// 7 | epoch | 7 | 1 +// 8 | create | 8 | 2 +// 9 | create | 9 | 2 +// 10 | create | 10 | 2 +// 11 | epoch | 11 | 2 +// 12 | epoch | 12 | 3 + +//# init --protocol-version 39 --addresses Test=0x0 --accounts A B --simulator + +//# publish +module Test::M1 { + public struct Object has key, store { + id: UID, + value: u64, + } + + public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { + transfer::public_transfer( + Object { id: object::new(ctx), value }, + recipient + ) + } +} + +//# create-checkpoint + +//# run Test::M1::create --args 0 @A --sender A + +//# create-checkpoint + +//# advance-epoch + +//# run-graphql +{ + checkpoint { + sequenceNumber + } + epoch { + epochId + transactionBlocks { + edges { + cursor + node { + digest + } + } + } + } +} + +//# run Test::M1::create --args 0 @A --sender A + +//# create-checkpoint + +//# run Test::M1::create --args 0 @A --sender A + +//# create-checkpoint + +//# run Test::M1::create --args 0 @A --sender A + +//# create-checkpoint + +//# advance-epoch + +//# run Test::M1::create --args 0 @A --sender A + +//# create-checkpoint + +//# run Test::M1::create --args 0 @A --sender A + +//# create-checkpoint + +//# run Test::M1::create --args 0 @A --sender A + +//# create-checkpoint + +//# advance-epoch + +//# advance-epoch + +//# run-graphql --cursors {"t":3,"tc":3,"c":4} {"t":7,"tc":7,"c":8} {"t":11,"tc":11,"c":12} +# View transactions before the last transaction in each epoch, from the perspective of the first +# checkpoint in the next epoch. +{ + checkpoint { + sequenceNumber + } + epoch_0_txs: epoch(id: 0) { + epochId + transactionBlocks { + edges { + cursor + node { + digest + } + } + } + } + txs_epoch_0: transactionBlocks(before: "@{cursor_0}") { + edges { + cursor + node { + digest + } + } + } + epoch_1_txs: epoch(id: 1) { + epochId + transactionBlocks { + edges { + cursor + node { + digest + } + } + } + } + txs_epoch_1: transactionBlocks(before: "@{cursor_1}") { + edges { + cursor + node { + digest + } + } + } + epoch_2_txs: epoch(id: 2) { + epochId + transactionBlocks { + edges { + cursor + node { + digest + } + } + } + } + txs_epoch_2: transactionBlocks(before: "@{cursor_2}") { + edges { + cursor + node { + digest + } + } + } +} + +//# run-graphql --cursors {"t":0,"tc":0,"c":7} {"t":4,"tc":4,"c":11} {"t":8,"tc":8,"c":12} +# View transactions after the first transaction in each epoch, from the perspective of the last +# checkpoint in the next epoch. +{ + checkpoint { + sequenceNumber + } + epoch_0: epoch(id: 0) { + epochId + transactionBlocks(after: "@{cursor_0}") { + edges { + cursor + node { + digest + } + } + } + } + epoch_1: epoch(id: 1) { + epochId + transactionBlocks(after: "@{cursor_1}") { + edges { + cursor + node { + digest + } + } + } + } + epoch_2: epoch(id: 2) { + epochId + transactionBlocks(after: "@{cursor_2}") { + edges { + cursor + node { + digest + } + } + } + } +} + +//# run-graphql --cursors {"t":1,"tc":1,"c":2} {"t":5,"tc":5,"c":6} {"t":9,"tc":9,"c":10} +# View transactions after the second transaction in each epoch, from the perspective of a checkpoint +# around the middle of each epoch. +{ + checkpoint { + sequenceNumber + } + epoch_0: epoch(id: 0) { + epochId + transactionBlocks(after: "@{cursor_0}") { + edges { + cursor + node { + digest + } + } + } + } + epoch_1: epoch(id: 1) { + epochId + transactionBlocks(after: "@{cursor_1}") { + edges { + cursor + node { + digest + } + } + } + } + epoch_2: epoch(id: 2) { + epochId + transactionBlocks(after: "@{cursor_2}") { + edges { + cursor + node { + digest + } + } + } + } +} + +//# run-graphql --cursors {"t":5,"tc":5,"c":6} +# Verify that with a cursor, we are locked into a view as if we were at the checkpoint stored in +# the cursor. Compare against `without_cursor`, which should show the latest state at the actual +# latest checkpoint. There should only be 1 transaction block in the `with_cursor` query, but +# multiple in the second +{ + checkpoint { + sequenceNumber + } + with_cursor: transactionBlocks(after: "@{cursor_0}", filter: {signAddress: "@{A}"}) { + edges { + cursor + node { + digest + sender { + objects { + edges { + cursor + } + } + } + } + } + } + without_cursor: transactionBlocks(filter: {signAddress: "@{A}"}) { + edges { + cursor + node { + digest + sender { + objects { + edges { + cursor + } + } + } + } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/object_at_version.exp b/crates/iota-graphql-e2e-tests/tests/consistency/object_at_version.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/consistency/object_at_version.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/object_at_version.exp diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/object_at_version.move b/crates/iota-graphql-e2e-tests/tests/consistency/object_at_version.move similarity index 98% rename from crates/sui-graphql-e2e-tests/tests/consistency/object_at_version.move rename to crates/iota-graphql-e2e-tests/tests/consistency/object_at_version.move index d0e1c6f8611..3ae5d335b24 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/object_at_version.move +++ b/crates/iota-graphql-e2e-tests/tests/consistency/object_at_version.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Create an object and modify it at checkpoints as follows: diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/objects_pagination.exp b/crates/iota-graphql-e2e-tests/tests/consistency/objects_pagination.exp similarity index 98% rename from crates/sui-graphql-e2e-tests/tests/consistency/objects_pagination.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/objects_pagination.exp index 83de215c650..f84682c5ee0 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/objects_pagination.exp +++ b/crates/iota-graphql-e2e-tests/tests/consistency/objects_pagination.exp @@ -236,7 +236,7 @@ Response: { "value": "1" } }, - "owner_at_latest_state_has_sui_only": { + "owner_at_latest_state_has_iota_only": { "owner": { "objects": { "nodes": [ @@ -292,7 +292,7 @@ Response: { "version": 1, "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" }, "json": { "id": "0xfc621bdc16f6d4ad09a3f27312e147179a93320e48e14ff3e6f4b64e3bec6b67", @@ -318,7 +318,7 @@ Response: { "value": "0" } }, - "owner_at_latest_state_has_sui_only": { + "owner_at_latest_state_has_iota_only": { "owner": { "objects": { "nodes": [ @@ -374,7 +374,7 @@ Response: { "version": 1, "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" }, "json": { "id": "0xfc621bdc16f6d4ad09a3f27312e147179a93320e48e14ff3e6f4b64e3bec6b67", @@ -400,7 +400,7 @@ Response: { "value": "3" } }, - "owner_at_latest_state_has_sui_only": { + "owner_at_latest_state_has_iota_only": { "owner": { "objects": { "nodes": [ @@ -456,7 +456,7 @@ Response: { "version": 1, "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" }, "json": { "id": "0xfc621bdc16f6d4ad09a3f27312e147179a93320e48e14ff3e6f4b64e3bec6b67", diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/objects_pagination.move b/crates/iota-graphql-e2e-tests/tests/consistency/objects_pagination.move similarity index 98% rename from crates/sui-graphql-e2e-tests/tests/consistency/objects_pagination.move rename to crates/iota-graphql-e2e-tests/tests/consistency/objects_pagination.move index c2c67e08241..b02c758f5e3 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/objects_pagination.move +++ b/crates/iota-graphql-e2e-tests/tests/consistency/objects_pagination.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses Test=0x0 --accounts A B --simulator @@ -160,7 +161,7 @@ module Test::M1 { } json } - owner_at_latest_state_has_sui_only: owner { + owner_at_latest_state_has_iota_only: owner { ... on AddressOwner { owner { objects { diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/objects_pagination_single.exp b/crates/iota-graphql-e2e-tests/tests/consistency/objects_pagination_single.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/consistency/objects_pagination_single.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/objects_pagination_single.exp diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/objects_pagination_single.move b/crates/iota-graphql-e2e-tests/tests/consistency/objects_pagination_single.move similarity index 99% rename from crates/sui-graphql-e2e-tests/tests/consistency/objects_pagination_single.move rename to crates/iota-graphql-e2e-tests/tests/consistency/objects_pagination_single.move index d559620a198..a13b717a66c 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/objects_pagination_single.move +++ b/crates/iota-graphql-e2e-tests/tests/consistency/objects_pagination_single.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Simple test case to check that object pagination is bounded by the checkpoint in the cursor. Use diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/performance/many_objects.exp b/crates/iota-graphql-e2e-tests/tests/consistency/performance/many_objects.exp similarity index 98% rename from crates/sui-graphql-e2e-tests/tests/consistency/performance/many_objects.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/performance/many_objects.exp index eaabb1a09f7..ac2ca813248 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/performance/many_objects.exp +++ b/crates/iota-graphql-e2e-tests/tests/consistency/performance/many_objects.exp @@ -149,12 +149,12 @@ gas summary: computation_cost: 1000000, storage_cost: 2302800, storage_rebate: task 8 'view-object'. lines 90-90: Owner: Account Address ( B ) Version: 4 -Contents: Test::M1::Object {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,498)}}, value: 89u64} +Contents: Test::M1::Object {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,498)}}, value: 89u64} task 9 'view-object'. lines 92-92: Owner: Account Address ( B ) Version: 5 -Contents: Test::M1::Object {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,497)}}, value: 142u64} +Contents: Test::M1::Object {id: iota::object::UID {id: iota::object::ID {bytes: fake(2,497)}}, value: 142u64} task 10 'create-checkpoint'. lines 94-94: Checkpoint created: 3 @@ -422,7 +422,7 @@ Response: { } }, "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } }, diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/performance/many_objects.move b/crates/iota-graphql-e2e-tests/tests/consistency/performance/many_objects.move similarity index 98% rename from crates/sui-graphql-e2e-tests/tests/consistency/performance/many_objects.move rename to crates/iota-graphql-e2e-tests/tests/consistency/performance/many_objects.move index a6079fcae90..7904548b960 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/performance/many_objects.move +++ b/crates/iota-graphql-e2e-tests/tests/consistency/performance/many_objects.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Transfer 500 objects to A. The first graphql query fetches the last 4 objects owned by A. Then diff --git a/crates/iota-graphql-e2e-tests/tests/consistency/staked_iota.exp b/crates/iota-graphql-e2e-tests/tests/consistency/staked_iota.exp new file mode 100644 index 00000000000..38590b5e58f --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/consistency/staked_iota.exp @@ -0,0 +1,151 @@ +processed 15 tasks + +init: +C: object(0,0) + +task 1 'run-graphql'. lines 6-18: +Response: { + "data": { + "address": { + "stakedIotas": { + "edges": [] + } + } + } +} + +task 2 'programmable'. lines 20-22: +created: object(2,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'run'. lines 24-24: +events: Event { package_id: iota_system, transaction_module: Identifier("iota_system"), sender: C, type_: StructTag { address: iota_system, module: Identifier("validator"), name: Identifier("StakingRequestEvent"), type_params: [] }, contents: [138, 42, 97, 253, 61, 22, 31, 106, 213, 157, 60, 241, 33, 156, 159, 193, 184, 127, 83, 194, 143, 198, 11, 54, 121, 139, 166, 151, 113, 26, 5, 97, 218, 131, 22, 109, 1, 175, 215, 221, 207, 138, 245, 248, 68, 244, 90, 170, 83, 244, 133, 72, 229, 17, 124, 35, 245, 162, 151, 140, 253, 66, 34, 68, 252, 204, 154, 66, 27, 187, 19, 193, 166, 106, 26, 169, 143, 10, 215, 80, 41, 237, 233, 72, 87, 119, 156, 105, 21, 180, 79, 148, 6, 139, 146, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 11, 84, 2, 0, 0, 0] } +created: object(3,0), object(3,1) +mutated: 0x0000000000000000000000000000000000000000000000000000000000000005, object(0,0) +deleted: object(_), object(2,0) +gas summary: computation_cost: 1000000, storage_cost: 15078400, storage_rebate: 1956240, non_refundable_storage_fee: 19760 + +task 4 'create-checkpoint'. lines 26-26: +Checkpoint created: 1 + +task 5 'advance-epoch'. lines 28-28: +Epoch advanced: 0 + +task 6 'programmable'. lines 30-32: +created: object(6,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 7 'run'. lines 34-34: +events: Event { package_id: iota_system, transaction_module: Identifier("iota_system"), sender: C, type_: StructTag { address: iota_system, module: Identifier("validator"), name: Identifier("StakingRequestEvent"), type_params: [] }, contents: [138, 42, 97, 253, 61, 22, 31, 106, 213, 157, 60, 241, 33, 156, 159, 193, 184, 127, 83, 194, 143, 198, 11, 54, 121, 139, 166, 151, 113, 26, 5, 97, 218, 131, 22, 109, 1, 175, 215, 221, 207, 138, 245, 248, 68, 244, 90, 170, 83, 244, 133, 72, 229, 17, 124, 35, 245, 162, 151, 140, 253, 66, 34, 68, 252, 204, 154, 66, 27, 187, 19, 193, 166, 106, 26, 169, 143, 10, 215, 80, 41, 237, 233, 72, 87, 119, 156, 105, 21, 180, 79, 148, 6, 139, 146, 30, 1, 0, 0, 0, 0, 0, 0, 0, 0, 228, 11, 84, 2, 0, 0, 0] } +created: object(7,0) +mutated: 0x0000000000000000000000000000000000000000000000000000000000000005, object(0,0), object(3,0) +deleted: object(6,0) +gas summary: computation_cost: 1000000, storage_cost: 15078400, storage_rebate: 14626656, non_refundable_storage_fee: 147744 + +task 8 'create-checkpoint'. lines 36-36: +Checkpoint created: 3 + +task 9 'advance-epoch'. lines 38-38: +Epoch advanced: 1 + +task 10 'view-object'. lines 40-40: +Owner: Account Address ( C ) +Version: 3 +Contents: iota_system::staking_pool::StakedIota {id: iota::object::UID {id: iota::object::ID {bytes: fake(3,1)}}, pool_id: iota::object::ID {bytes: _}, stake_activation_epoch: 1u64, principal: iota::balance::Balance {value: 10000000000u64}} + +task 11 'view-object'. lines 42-42: +Owner: Account Address ( C ) +Version: 5 +Contents: iota_system::staking_pool::StakedIota {id: iota::object::UID {id: iota::object::ID {bytes: fake(7,0)}}, pool_id: iota::object::ID {bytes: _}, stake_activation_epoch: 2u64, principal: iota::balance::Balance {value: 10000000000u64}} + +task 12 'run-graphql'. lines 44-56: +Response: { + "data": { + "address": { + "stakedIotas": { + "edges": [ + { + "cursor": "IAk4XNJ325CV4kql8g6oWLdlvSCovGah0C/Ucs4Gg2ayBAAAAAAAAAA=", + "node": { + "principal": "10000000000" + } + }, + { + "cursor": "IBX0DS9yEyPNAQauq4aH+cupD1Spyw3GeIxMiAUZU0iSBAAAAAAAAAA=", + "node": { + "principal": "10000000000" + } + } + ] + } + } + } +} + +task 13 'run-graphql'. lines 58-102: +Response: { + "data": { + "no_coins_after_obj_3_1_chkpt_1": { + "stakedIotas": { + "edges": [] + } + }, + "no_coins_before_obj_3_1_chkpt_1": { + "stakedIotas": { + "edges": [] + } + }, + "no_coins_after_obj_7_0_chkpt_1": { + "stakedIotas": { + "edges": [] + } + }, + "no_coins_before_obj_7_0_chkpt_1": { + "stakedIotas": { + "edges": [] + } + } + } +} + +task 14 'run-graphql'. lines 104-147: +Response: { + "data": { + "coins_after_obj_3_1_chkpt_3": { + "stakedIotas": { + "edges": [] + } + }, + "coins_before_obj_3_1_chkpt_3": { + "stakedIotas": { + "edges": [ + { + "cursor": "IAk4XNJ325CV4kql8g6oWLdlvSCovGah0C/Ucs4Gg2ayAwAAAAAAAAA=", + "node": { + "principal": "10000000000" + } + } + ] + } + }, + "coins_after_obj_7_0_chkpt_3": { + "stakedIotas": { + "edges": [ + { + "cursor": "IBX0DS9yEyPNAQauq4aH+cupD1Spyw3GeIxMiAUZU0iSAwAAAAAAAAA=", + "node": { + "principal": "10000000000" + } + } + ] + } + }, + "coins_before_obj_7_0_chkpt_3": { + "stakedIotas": { + "edges": [] + } + } + } +} diff --git a/crates/iota-graphql-e2e-tests/tests/consistency/staked_iota.move b/crates/iota-graphql-e2e-tests/tests/consistency/staked_iota.move new file mode 100644 index 00000000000..5e6c4f92557 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/consistency/staked_iota.move @@ -0,0 +1,148 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --protocol-version 39 --simulator --accounts C + +//# run-graphql +{ + address(address: "@{C}") { + stakedIotas { + edges { + cursor + node { + principal + } + } + } + } +} + +//# programmable --sender C --inputs 10000000000 @C +//> SplitCoins(Gas, [Input(0)]); +//> TransferObjects([Result(0)], Input(1)) + +//# run 0x3::iota_system::request_add_stake --args object(0x5) object(2,0) @validator_0 --sender C + +//# create-checkpoint + +//# advance-epoch + +//# programmable --sender C --inputs 10000000000 @C +//> SplitCoins(Gas, [Input(0)]); +//> TransferObjects([Result(0)], Input(1)) + +//# run 0x3::iota_system::request_add_stake --args object(0x5) object(6,0) @validator_0 --sender C + +//# create-checkpoint + +//# advance-epoch + +//# view-object 3,1 + +//# view-object 7,0 + +//# run-graphql +{ + address(address: "@{C}") { + stakedIotas { + edges { + cursor + node { + principal + } + } + } + } +} + +//# run-graphql --cursors @{obj_3_1,1} @{obj_7_0,1} +# Even though there is a stake created after the initial one, the cursor locks the upper bound to +# checkpoint 1 - at that point in time, we did not have any additional stakes. +{ + no_coins_after_obj_3_1_chkpt_1: address(address: "@{C}") { + stakedIotas(after: "@{cursor_0}") { + edges { + cursor + node { + principal + } + } + } + } + no_coins_before_obj_3_1_chkpt_1: address(address: "@{C}") { + stakedIotas(before: "@{cursor_0}") { + edges { + cursor + node { + principal + } + } + } + } + no_coins_after_obj_7_0_chkpt_1: address(address: "@{C}") { + stakedIotas(after: "@{cursor_0}") { + edges { + cursor + node { + principal + } + } + } + } + no_coins_before_obj_7_0_chkpt_1: address(address: "@{C}") { + stakedIotas(before: "@{cursor_0}") { + edges { + cursor + node { + principal + } + } + } + } +} + +//# run-graphql --cursors @{obj_3_1,3} @{obj_7_0,3} +# The second stake was created at checkpoint 3, and thus will be visible. +{ + coins_after_obj_3_1_chkpt_3: address(address: "@{C}") { + stakedIotas(after: "@{cursor_0}") { + edges { + cursor + node { + principal + } + } + } + } + coins_before_obj_3_1_chkpt_3: address(address: "@{C}") { + stakedIotas(before: "@{cursor_0}") { + edges { + cursor + node { + principal + } + } + } + } + coins_after_obj_7_0_chkpt_3: address(address: "@{C}") { + stakedIotas(after: "@{cursor_1}") { + edges { + cursor + node { + principal + } + } + } + } + coins_before_obj_7_0_chkpt_3: address(address: "@{C}") { + stakedIotas(before: "@{cursor_1}") { + edges { + cursor + node { + principal + } + } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/tx_address_objects.exp b/crates/iota-graphql-e2e-tests/tests/consistency/tx_address_objects.exp similarity index 99% rename from crates/sui-graphql-e2e-tests/tests/consistency/tx_address_objects.exp rename to crates/iota-graphql-e2e-tests/tests/consistency/tx_address_objects.exp index f73037771dc..36c20fc4b8b 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/tx_address_objects.exp +++ b/crates/iota-graphql-e2e-tests/tests/consistency/tx_address_objects.exp @@ -264,7 +264,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" }, "json": { "id": "0xfc621bdc16f6d4ad09a3f27312e147179a93320e48e14ff3e6f4b64e3bec6b67", @@ -462,7 +462,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" }, "json": { "id": "0xfc621bdc16f6d4ad09a3f27312e147179a93320e48e14ff3e6f4b64e3bec6b67", @@ -596,7 +596,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" }, "json": { "id": "0xfc621bdc16f6d4ad09a3f27312e147179a93320e48e14ff3e6f4b64e3bec6b67", @@ -763,7 +763,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" }, "json": { "id": "0xfc621bdc16f6d4ad09a3f27312e147179a93320e48e14ff3e6f4b64e3bec6b67", @@ -1018,7 +1018,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" }, "json": { "id": "0xfc621bdc16f6d4ad09a3f27312e147179a93320e48e14ff3e6f4b64e3bec6b67", diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/tx_address_objects.move b/crates/iota-graphql-e2e-tests/tests/consistency/tx_address_objects.move similarity index 99% rename from crates/sui-graphql-e2e-tests/tests/consistency/tx_address_objects.move rename to crates/iota-graphql-e2e-tests/tests/consistency/tx_address_objects.move index ca5bf79e5a4..11b2abaffda 100644 --- a/crates/sui-graphql-e2e-tests/tests/consistency/tx_address_objects.move +++ b/crates/iota-graphql-e2e-tests/tests/consistency/tx_address_objects.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Check that if the sender and gas sponsor of a tx are the same, that the historical data returned diff --git a/crates/sui-graphql-e2e-tests/tests/datetime/datetime.exp b/crates/iota-graphql-e2e-tests/tests/datetime/datetime.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/datetime/datetime.exp rename to crates/iota-graphql-e2e-tests/tests/datetime/datetime.exp diff --git a/crates/sui-graphql-e2e-tests/tests/datetime/datetime.move b/crates/iota-graphql-e2e-tests/tests/datetime/datetime.move similarity index 97% rename from crates/sui-graphql-e2e-tests/tests/datetime/datetime.move rename to crates/iota-graphql-e2e-tests/tests/datetime/datetime.move index e9cac001495..e369d3e7f34 100644 --- a/crates/sui-graphql-e2e-tests/tests/datetime/datetime.move +++ b/crates/iota-graphql-e2e-tests/tests/datetime/datetime.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --simulator diff --git a/crates/iota-graphql-e2e-tests/tests/epoch/epoch.exp b/crates/iota-graphql-e2e-tests/tests/epoch/epoch.exp new file mode 100644 index 00000000000..d1833fff4be --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/epoch/epoch.exp @@ -0,0 +1,82 @@ +processed 11 tasks + +init: +C: object(0,0) + +task 1 'create-checkpoint'. lines 8-8: +Checkpoint created: 1 + +task 2 'advance-epoch'. lines 10-10: +Epoch advanced: 0 + +task 3 'programmable'. lines 12-14: +created: object(3,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 4 'run'. lines 16-18: +events: Event { package_id: iota_system, transaction_module: Identifier("iota_system"), sender: C, type_: StructTag { address: iota_system, module: Identifier("validator"), name: Identifier("StakingRequestEvent"), type_params: [] }, contents: [138, 42, 97, 253, 61, 22, 31, 106, 213, 157, 60, 241, 33, 156, 159, 193, 184, 127, 83, 194, 143, 198, 11, 54, 121, 139, 166, 151, 113, 26, 5, 97, 218, 131, 22, 109, 1, 175, 215, 221, 207, 138, 245, 248, 68, 244, 90, 170, 83, 244, 133, 72, 229, 17, 124, 35, 245, 162, 151, 140, 253, 66, 34, 68, 252, 204, 154, 66, 27, 187, 19, 193, 166, 106, 26, 169, 143, 10, 215, 80, 41, 237, 233, 72, 87, 119, 156, 105, 21, 180, 79, 148, 6, 139, 146, 30, 1, 0, 0, 0, 0, 0, 0, 0, 0, 228, 11, 84, 2, 0, 0, 0] } +created: object(4,0) +mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000005, object(0,0) +deleted: object(3,0) +gas summary: computation_cost: 1000000, storage_cost: 15078400, storage_rebate: 1956240, non_refundable_storage_fee: 19760 + +task 5 'create-checkpoint'. lines 19-19: +Checkpoint created: 3 + +task 6 'advance-epoch'. lines 21-23: +Epoch advanced: 1 + +task 7 'programmable'. lines 24-28: +created: object(7,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 8 'create-checkpoint'. lines 29-29: +Checkpoint created: 5 + +task 9 'advance-epoch'. lines 31-32: +Epoch advanced: 2 + +task 10 'run-graphql'. lines 33-62: +Response: { + "data": { + "epoch": { + "validatorSet": { + "totalStake": "20000010002000000", + "activeValidators": { + "nodes": [ + { + "name": "validator-0" + } + ] + }, + "validatorCandidatesSize": 0, + "inactivePoolsId": "0x8713eb91a5cf17ed1c0d8e008aa785666469e7ab693ef8761efa1ee3ebbe3ab9" + }, + "totalGasFees": "1000000", + "totalStakeRewards": "1000000", + "totalStakeSubsidies": "0", + "fundSize": "15098160", + "fundInflow": "1976000", + "fundOutflow": "978120", + "netInflow": "997880", + "transactionBlocks": { + "nodes": [ + { + "kind": { + "__typename": "ProgrammableTransactionBlock" + }, + "digest": "74v5nnByFFTd2kePFY4X2skrHsRojfdnb96562Yr3hWM" + }, + { + "kind": { + "__typename": "EndOfEpochTransaction" + }, + "digest": "5NBZfJP5y3yrNaBesbtkatNSHoYCghaK6uCNP1uf8c2w" + } + ] + } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/epoch/epoch.move b/crates/iota-graphql-e2e-tests/tests/epoch/epoch.move similarity index 88% rename from crates/sui-graphql-e2e-tests/tests/epoch/epoch.move rename to crates/iota-graphql-e2e-tests/tests/epoch/epoch.move index 1394334e534..379b2eb2bc0 100644 --- a/crates/sui-graphql-e2e-tests/tests/epoch/epoch.move +++ b/crates/iota-graphql-e2e-tests/tests/epoch/epoch.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --simulator --accounts C @@ -13,7 +14,7 @@ //> SplitCoins(Gas, [Input(0)]); //> TransferObjects([Result(0)], Input(1)) -//# run 0x3::sui_system::request_add_stake --args object(0x5) object(3,0) @validator_0 --sender C +//# run 0x3::iota_system::request_add_stake --args object(0x5) object(3,0) @validator_0 --sender C // TODO: Short term hack to get around indexer epoch issue //# create-checkpoint diff --git a/crates/iota-graphql-e2e-tests/tests/epoch/system_state.exp b/crates/iota-graphql-e2e-tests/tests/epoch/system_state.exp new file mode 100644 index 00000000000..945e1961213 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/epoch/system_state.exp @@ -0,0 +1,139 @@ +processed 23 tasks + +init: +C: object(0,0), validator_0: object(0,1) + +task 1 'create-checkpoint'. lines 10-10: +Checkpoint created: 1 + +task 2 'advance-epoch'. lines 12-12: +Epoch advanced: 0 + +task 3 'programmable'. lines 14-16: +created: object(3,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 4 'run'. lines 18-18: +events: Event { package_id: iota_system, transaction_module: Identifier("iota_system"), sender: C, type_: StructTag { address: iota_system, module: Identifier("validator"), name: Identifier("StakingRequestEvent"), type_params: [] }, contents: [236, 3, 28, 119, 89, 112, 37, 120, 90, 31, 66, 230, 116, 106, 58, 235, 215, 29, 65, 204, 9, 76, 95, 163, 254, 107, 4, 55, 88, 155, 108, 41, 218, 131, 22, 109, 1, 175, 215, 221, 207, 138, 245, 248, 68, 244, 90, 170, 83, 244, 133, 72, 229, 17, 124, 35, 245, 162, 151, 140, 253, 66, 34, 68, 252, 204, 154, 66, 27, 187, 19, 193, 166, 106, 26, 169, 143, 10, 215, 80, 41, 237, 233, 72, 87, 119, 156, 105, 21, 180, 79, 148, 6, 139, 146, 30, 1, 0, 0, 0, 0, 0, 0, 0, 0, 228, 11, 84, 2, 0, 0, 0] } +created: object(4,0) +mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000005, object(0,0) +deleted: object(3,0) +gas summary: computation_cost: 1000000, storage_cost: 15078400, storage_rebate: 1956240, non_refundable_storage_fee: 19760 + +task 5 'create-checkpoint'. lines 20-20: +Checkpoint created: 3 + +task 6 'advance-epoch'. lines 22-22: +Epoch advanced: 1 + +task 7 'create-checkpoint'. lines 24-24: +Checkpoint created: 5 + +task 8 'advance-epoch'. lines 26-26: +Epoch advanced: 2 + +task 9 'programmable'. lines 28-30: +created: object(9,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 10 'create-checkpoint'. lines 32-32: +Checkpoint created: 7 + +task 11 'advance-epoch'. lines 34-34: +Epoch advanced: 3 + +task 12 'run'. lines 36-36: +events: Event { package_id: iota_system, transaction_module: Identifier("iota_system"), sender: C, type_: StructTag { address: iota_system, module: Identifier("validator"), name: Identifier("UnstakingRequestEvent"), type_params: [] }, contents: [236, 3, 28, 119, 89, 112, 37, 120, 90, 31, 66, 230, 116, 106, 58, 235, 215, 29, 65, 204, 9, 76, 95, 163, 254, 107, 4, 55, 88, 155, 108, 41, 218, 131, 22, 109, 1, 175, 215, 221, 207, 138, 245, 248, 68, 244, 90, 170, 83, 244, 133, 72, 229, 17, 124, 35, 245, 162, 151, 140, 253, 66, 34, 68, 252, 204, 154, 66, 27, 187, 19, 193, 166, 106, 26, 169, 143, 10, 215, 80, 41, 237, 233, 72, 87, 119, 156, 105, 21, 180, 79, 148, 6, 139, 146, 30, 2, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 228, 11, 84, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] } +created: object(12,0) +mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000005, object(0,0) +deleted: object(4,0) +gas summary: computation_cost: 1000000, storage_cost: 14774400, storage_rebate: 14927616, non_refundable_storage_fee: 150784 + +task 13 'create-checkpoint'. lines 38-38: +Checkpoint created: 9 + +task 14 'advance-epoch'. lines 40-40: +Epoch advanced: 4 + +task 15 'programmable'. lines 42-44: +created: object(15,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 16 'create-checkpoint'. lines 46-46: +Checkpoint created: 11 + +task 17 'advance-epoch'. lines 48-48: +Epoch advanced: 5 + +task 18 'run-graphql'. lines 50-60: +Response: { + "data": { + "epoch": { + "epochId": 4, + "systemStateVersion": 2, + "storageFund": { + "totalObjectStorageRebates": "15762400", + "nonRefundableBalance": "180424" + } + } + } +} + +task 19 'run-graphql'. lines 62-72: +Response: { + "data": { + "epoch": { + "epochId": 3, + "systemStateVersion": 2, + "storageFund": { + "totalObjectStorageRebates": "16066400", + "nonRefundableBalance": "29640" + } + } + } +} + +task 20 'run-graphql'. lines 74-84: +Response: { + "data": { + "epoch": { + "epochId": 2, + "systemStateVersion": 2, + "storageFund": { + "totalObjectStorageRebates": "15078400", + "nonRefundableBalance": "19760" + } + } + } +} + +task 21 'run-graphql'. lines 86-96: +Response: { + "data": { + "epoch": { + "epochId": 1, + "systemStateVersion": 2, + "storageFund": { + "totalObjectStorageRebates": "15078400", + "nonRefundableBalance": "19760" + } + } + } +} + +task 22 'run-graphql'. lines 98-108: +Response: { + "data": { + "epoch": { + "epochId": 4, + "systemStateVersion": 2, + "storageFund": { + "totalObjectStorageRebates": "15762400", + "nonRefundableBalance": "180424" + } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/epoch/system_state.move b/crates/iota-graphql-e2e-tests/tests/epoch/system_state.move similarity index 88% rename from crates/sui-graphql-e2e-tests/tests/epoch/system_state.move rename to crates/iota-graphql-e2e-tests/tests/epoch/system_state.move index 2f158276831..b8d9567f395 100644 --- a/crates/sui-graphql-e2e-tests/tests/epoch/system_state.move +++ b/crates/iota-graphql-e2e-tests/tests/epoch/system_state.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --simulator --accounts C --custom-validator-account @@ -15,7 +16,7 @@ //> SplitCoins(Gas, [Input(0)]); //> TransferObjects([Result(0)], Input(1)) -//# run 0x3::sui_system::request_add_stake --args object(0x5) object(3,0) @validator_0 --sender C +//# run 0x3::iota_system::request_add_stake --args object(0x5) object(3,0) @validator_0 --sender C //# create-checkpoint @@ -33,7 +34,7 @@ //# advance-epoch -//# run 0x3::sui_system::request_withdraw_stake --args object(0x5) object(4,0) --sender C +//# run 0x3::iota_system::request_withdraw_stake --args object(0x5) object(4,0) --sender C //# create-checkpoint diff --git a/crates/sui-graphql-e2e-tests/tests/event_connection/event_connection.exp b/crates/iota-graphql-e2e-tests/tests/event_connection/event_connection.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/event_connection/event_connection.exp rename to crates/iota-graphql-e2e-tests/tests/event_connection/event_connection.exp diff --git a/crates/sui-graphql-e2e-tests/tests/event_connection/event_connection.move b/crates/iota-graphql-e2e-tests/tests/event_connection/event_connection.move similarity index 98% rename from crates/sui-graphql-e2e-tests/tests/event_connection/event_connection.move rename to crates/iota-graphql-e2e-tests/tests/event_connection/event_connection.move index 55e86846ea8..d1064730e18 100644 --- a/crates/sui-graphql-e2e-tests/tests/event_connection/event_connection.move +++ b/crates/iota-graphql-e2e-tests/tests/event_connection/event_connection.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Creates an event Test::M1::EventA, Test::M1::EventB, Test::M2::EventA, Test::M2::EventB @@ -13,7 +14,7 @@ //# publish module Test::M1 { - use sui::event; + use iota::event; public struct EventA has copy, drop { new_value: u64 @@ -47,7 +48,7 @@ module Test::M1 { } module Test::M2 { - use sui::event; + use iota::event; public struct EventA has copy, drop { new_value: u64 diff --git a/crates/sui-graphql-e2e-tests/tests/event_connection/nested_emit_event.exp b/crates/iota-graphql-e2e-tests/tests/event_connection/nested_emit_event.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/event_connection/nested_emit_event.exp rename to crates/iota-graphql-e2e-tests/tests/event_connection/nested_emit_event.exp diff --git a/crates/sui-graphql-e2e-tests/tests/event_connection/nested_emit_event.move b/crates/iota-graphql-e2e-tests/tests/event_connection/nested_emit_event.move similarity index 96% rename from crates/sui-graphql-e2e-tests/tests/event_connection/nested_emit_event.move rename to crates/iota-graphql-e2e-tests/tests/event_connection/nested_emit_event.move index 579ecb5fd66..031ecb1aae3 100644 --- a/crates/sui-graphql-e2e-tests/tests/event_connection/nested_emit_event.move +++ b/crates/iota-graphql-e2e-tests/tests/event_connection/nested_emit_event.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // This test demonstrates that one can search for events emitted by a package or module. @@ -9,7 +10,7 @@ //# publish module Test::M1 { - use sui::event; + use iota::event; public struct EventA has copy, drop { new_value: u64 diff --git a/crates/sui-graphql-e2e-tests/tests/event_connection/pagination.exp b/crates/iota-graphql-e2e-tests/tests/event_connection/pagination.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/event_connection/pagination.exp rename to crates/iota-graphql-e2e-tests/tests/event_connection/pagination.exp diff --git a/crates/iota-graphql-e2e-tests/tests/event_connection/pagination.move b/crates/iota-graphql-e2e-tests/tests/event_connection/pagination.move new file mode 100644 index 00000000000..06ee5cabeb8 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/event_connection/pagination.move @@ -0,0 +1,133 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --protocol-version 39 --addresses Test=0x0 --accounts A --simulator + +//# publish +module Test::M1 { + use iota::event; + + public struct EventA has copy, drop { + new_value: u64 + } + + public entry fun emit_1(value: u64) { + event::emit(EventA { new_value: value }) + } + + public entry fun emit_2(value: u64) { + event::emit(EventA { new_value: value }); + event::emit(EventA { new_value: value + 1}) + } +} + +//# run Test::M1::emit_1 --sender A --args 0 + +//# run Test::M1::emit_2 --sender A --args 1 + +//# create-checkpoint + +//# run-graphql +{ + events(filter: {sender: "@{A}"}) { + pageInfo { + hasPreviousPage + hasNextPage + } + edges { + cursor + node { + sendingModule { + name + } + type { + repr + } + sender { + address + } + json + bcs + } + } + } +} + +//# run-graphql --cursors {"tx":2,"e":0,"c":1} +{ + events(first: 2 after: "@{cursor_0}", filter: {sender: "@{A}"}) { + pageInfo { + hasPreviousPage + hasNextPage + } + edges { + cursor + node { + sendingModule { + name + } + type { + repr + } + sender { + address + } + json + bcs + } + } + } +} + +//# run-graphql --cursors {"tx":3,"e":1,"c":1} +{ + events(last: 2 before: "@{cursor_0}", filter: {sender: "@{A}"}) { + pageInfo { + hasPreviousPage + hasNextPage + } + edges { + cursor + node { + sendingModule { + name + } + type { + repr + } + sender { + address + } + json + bcs + } + } + } +} + +//# run-graphql +{ + events(last: 2) { + pageInfo { + hasPreviousPage + hasNextPage + } + edges { + cursor + node { + sendingModule { + name + } + type { + repr + } + sender { + address + } + json + bcs + } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/limits/directives.exp b/crates/iota-graphql-e2e-tests/tests/limits/directives.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/limits/directives.exp rename to crates/iota-graphql-e2e-tests/tests/limits/directives.exp diff --git a/crates/sui-graphql-e2e-tests/tests/limits/directives.move b/crates/iota-graphql-e2e-tests/tests/limits/directives.move similarity index 95% rename from crates/sui-graphql-e2e-tests/tests/limits/directives.move rename to crates/iota-graphql-e2e-tests/tests/limits/directives.move index 5ae88e85c9b..c5fcdc6e8cc 100644 --- a/crates/sui-graphql-e2e-tests/tests/limits/directives.move +++ b/crates/iota-graphql-e2e-tests/tests/limits/directives.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses Test=0x0 --accounts A --simulator diff --git a/crates/sui-graphql-e2e-tests/tests/limits/output_node_estimation.exp b/crates/iota-graphql-e2e-tests/tests/limits/output_node_estimation.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/limits/output_node_estimation.exp rename to crates/iota-graphql-e2e-tests/tests/limits/output_node_estimation.exp diff --git a/crates/sui-graphql-e2e-tests/tests/limits/output_node_estimation.move b/crates/iota-graphql-e2e-tests/tests/limits/output_node_estimation.move similarity index 99% rename from crates/sui-graphql-e2e-tests/tests/limits/output_node_estimation.move rename to crates/iota-graphql-e2e-tests/tests/limits/output_node_estimation.move index 11f867ff4ea..97ae1db64a8 100644 --- a/crates/sui-graphql-e2e-tests/tests/limits/output_node_estimation.move +++ b/crates/iota-graphql-e2e-tests/tests/limits/output_node_estimation.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses A=0x42 --simulator diff --git a/crates/sui-graphql-e2e-tests/tests/objects/coin.exp b/crates/iota-graphql-e2e-tests/tests/objects/coin.exp similarity index 94% rename from crates/sui-graphql-e2e-tests/tests/objects/coin.exp rename to crates/iota-graphql-e2e-tests/tests/objects/coin.exp index 466407dba6a..252d69a7c60 100644 --- a/crates/sui-graphql-e2e-tests/tests/objects/coin.exp +++ b/crates/iota-graphql-e2e-tests/tests/objects/coin.exp @@ -14,7 +14,7 @@ Checkpoint created: 1 task 3 'run-graphql'. lines 37-85: Response: { "data": { - "suiCoins": { + "iotaCoins": { "edges": [ { "cursor": "IFPHnVMghxOScd9ztJZbaHIq4+CLShAZeGVq9lyqYDFiAQAAAAAAAAA=", @@ -22,7 +22,7 @@ Response: { "coinBalance": "299999983336400", "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -33,7 +33,7 @@ Response: { "coinBalance": "30000000000000000", "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -44,7 +44,7 @@ Response: { "coinBalance": "300000000000000", "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -97,7 +97,7 @@ Response: { "coinBalance": "299999983336400", "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -110,7 +110,7 @@ Response: { "cursor": "eyJ0IjoiMHgwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAyOjpzdWk6OlNVSSIsImMiOjF9", "node": { "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" }, "coinObjectCount": 1, "totalBalance": "299999983336400" diff --git a/crates/iota-graphql-e2e-tests/tests/objects/coin.move b/crates/iota-graphql-e2e-tests/tests/objects/coin.move new file mode 100644 index 00000000000..8a56b797fd0 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/objects/coin.move @@ -0,0 +1,86 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --protocol-version 39 --addresses P0=0x0 --accounts A --simulator + +//# publish --sender A +module P0::fake { + use iota::coin; + + public struct FAKE has drop {} + + fun init(witness: FAKE, ctx: &mut TxContext){ + let (mut treasury_cap, metadata) = coin::create_currency( + witness, + 2, + b"FAKE", + b"", + b"", + option::none(), + ctx, + ); + + let c1 = coin::mint(&mut treasury_cap, 1, ctx); + let c2 = coin::mint(&mut treasury_cap, 2, ctx); + let c3 = coin::mint(&mut treasury_cap, 3, ctx); + + transfer::public_freeze_object(metadata); + transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); + transfer::public_transfer(c1, tx_context::sender(ctx)); + transfer::public_transfer(c2, tx_context::sender(ctx)); + transfer::public_transfer(c3, tx_context::sender(ctx)); + } +} + +//# create-checkpoint + +//# run-graphql +fragment C on Coin { + coinBalance + contents { type { repr } } +} + +{ + iotaCoins: coins { + edges { + cursor + node { ...C } + } + } + + fakeCoins: coins(type: "@{P0}::fake::FAKE") { + edges { + cursor + node { ...C } + } + } + + address(address: "@{A}") { + coins { + edges { + cursor + node { ...C } + } + } + + allBalances: balances { + edges { + cursor + node { + coinType { repr } + coinObjectCount + totalBalance + } + } + } + + firstBalance: balances(first: 1) { + edges { cursor } + } + + lastBalance: balances(last: 1) { + edges { cursor } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/objects/data.exp b/crates/iota-graphql-e2e-tests/tests/objects/data.exp similarity index 99% rename from crates/sui-graphql-e2e-tests/tests/objects/data.exp rename to crates/iota-graphql-e2e-tests/tests/objects/data.exp index 92f68b7fd5f..2c2a85e5820 100644 --- a/crates/sui-graphql-e2e-tests/tests/objects/data.exp +++ b/crates/iota-graphql-e2e-tests/tests/objects/data.exp @@ -217,7 +217,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" }, "data": { "Struct": [ diff --git a/crates/iota-graphql-e2e-tests/tests/objects/data.move b/crates/iota-graphql-e2e-tests/tests/objects/data.move new file mode 100644 index 00000000000..e7c04a13a9e --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/objects/data.move @@ -0,0 +1,69 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --protocol-version 39 --addresses P0=0x0 --accounts A --simulator + +//# publish +module P0::m { + use std::ascii::{Self, String as ASCII}; + use std::string::{Self, String as UTF8}; + + public struct Foo has key, store { + id: UID, + f0: ID, + f1: bool, + f2: u8, + f3: u64, + f4: UTF8, + f5: ASCII, + f6: vector
    , + f7: Option, + } + + public struct Bar has key { + id: UID, + } + + public fun foo(ctx: &mut TxContext): Foo { + let id = object::new(ctx); + let f0 = object::uid_to_inner(&id); + let f1 = true; + let f2 = 42; + let f3 = 43; + let f4 = string::utf8(b"hello"); + let f5 = ascii::string(b"world"); + let f6 = vector[object::uid_to_address(&id)]; + let f7 = option::some(44); + Foo { id, f0, f1, f2, f3, f4, f5, f6, f7 } + } +} + +//# programmable --inputs @A +//> 0: P0::m::foo(); +//> TransferObjects([Result(0)], Input(0)) + +//# create-checkpoint + +//# run-graphql +{ + transactionBlocks(last: 1) { + nodes { + effects { + objectChanges { + nodes { + outputState { + asMoveObject { + contents { + type { repr } + data + json + } + } + } + } + } + } + } + } +} diff --git a/crates/iota-graphql-e2e-tests/tests/objects/display.exp b/crates/iota-graphql-e2e-tests/tests/objects/display.exp new file mode 100644 index 00000000000..3043905514c --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/objects/display.exp @@ -0,0 +1,216 @@ +processed 17 tasks + +init: +A: object(0,0) + +task 1 'publish'. lines 6-130: +events: Event { package_id: Test, transaction_module: Identifier("boars"), sender: A, type_: StructTag { address: iota, module: Identifier("display"), name: Identifier("DisplayCreated"), type_params: [Struct(StructTag { address: Test, module: Identifier("boars"), name: Identifier("Boar"), type_params: [] })] }, contents: [157, 80, 190, 33, 119, 59, 45, 238, 34, 126, 254, 191, 25, 36, 11, 95, 217, 30, 133, 175, 214, 221, 149, 84, 133, 67, 247, 141, 240, 193, 184, 229] } +created: object(1,0), object(1,1), object(1,2) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 21470000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 2 'create-checkpoint'. lines 132-132: +Checkpoint created: 1 + +task 3 'view-checkpoint'. lines 134-134: +CheckpointSummary { epoch: 0, seq: 1, content_digest: AvP8uds3916DQnCtsoGY4BBH3Bj8VzaMsVzVTv2LURFb, + epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 1000000, storage_cost: 21470000, storage_rebate: 0, non_refundable_storage_fee: 0 }} + +task 4 'run'. lines 136-136: +created: object(4,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 3556800, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 5 'run'. lines 138-138: +events: Event { package_id: Test, transaction_module: Identifier("boars"), sender: A, type_: StructTag { address: iota, module: Identifier("display"), name: Identifier("VersionUpdated"), type_params: [Struct(StructTag { address: Test, module: Identifier("boars"), name: Identifier("Boar"), type_params: [] })] }, contents: [157, 80, 190, 33, 119, 59, 45, 238, 34, 126, 254, 191, 25, 36, 11, 95, 217, 30, 133, 175, 214, 221, 149, 84, 133, 67, 247, 141, 240, 193, 184, 229, 1, 0, 3, 7, 118, 101, 99, 116, 111, 114, 115, 5, 123, 118, 101, 99, 125, 3, 105, 100, 100, 5, 123, 105, 100, 100, 125, 5, 110, 97, 109, 101, 101, 7, 123, 110, 97, 109, 101, 101, 125] } +mutated: object(0,0), object(1,1) +gas summary: computation_cost: 1000000, storage_cost: 2941200, storage_rebate: 2625876, non_refundable_storage_fee: 26524 + +task 6 'create-checkpoint'. lines 140-140: +Checkpoint created: 2 + +task 7 'view-checkpoint'. lines 142-142: +CheckpointSummary { epoch: 0, seq: 2, content_digest: EMEK1Xy5EePdb6taLpJJWCgNbrvDHTSS3UzY59KrSx1F, + epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 3000000, storage_cost: 27968000, storage_rebate: 3603996, non_refundable_storage_fee: 36404 }} + +task 8 'run-graphql'. lines 144-157: +Response: { + "data": { + "address": { + "objects": { + "nodes": [ + { + "display": [ + { + "key": "vectors", + "value": null, + "error": "Vector of name vec is not supported as a Display value" + }, + { + "key": "idd", + "value": null, + "error": "Field 'idd' not found" + }, + { + "key": "namee", + "value": null, + "error": "Field 'namee' not found" + } + ] + } + ] + } + } + } +} + +task 9 'run'. lines 159-159: +events: Event { package_id: Test, transaction_module: Identifier("boars"), sender: A, type_: StructTag { address: iota, module: Identifier("display"), name: Identifier("VersionUpdated"), type_params: [Struct(StructTag { address: Test, module: Identifier("boars"), name: Identifier("Boar"), type_params: [] })] }, contents: [157, 80, 190, 33, 119, 59, 45, 238, 34, 126, 254, 191, 25, 36, 11, 95, 217, 30, 133, 175, 214, 221, 149, 84, 133, 67, 247, 141, 240, 193, 184, 229, 2, 0, 4, 7, 118, 101, 99, 116, 111, 114, 115, 5, 123, 118, 101, 99, 125, 3, 105, 100, 100, 5, 123, 105, 100, 100, 125, 5, 110, 97, 109, 101, 101, 7, 123, 110, 97, 109, 101, 101, 125, 4, 110, 117, 109, 115, 6, 123, 110, 117, 109, 115, 125] } +mutated: object(0,0), object(1,1) +gas summary: computation_cost: 1000000, storage_cost: 3032400, storage_rebate: 2911788, non_refundable_storage_fee: 29412 + +task 10 'create-checkpoint'. lines 161-161: +Checkpoint created: 3 + +task 11 'view-checkpoint'. lines 163-163: +CheckpointSummary { epoch: 0, seq: 3, content_digest: 3WgfPMSDoyWjhDnFLqkwUqT6fk7Rq3WnJqB8zPH9Ju7X, + epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 4000000, storage_cost: 31000400, storage_rebate: 6515784, non_refundable_storage_fee: 65816 }} + +task 12 'run-graphql'. lines 165-178: +Response: { + "data": { + "address": { + "objects": { + "nodes": [ + { + "display": [ + { + "key": "vectors", + "value": null, + "error": "Vector of name vec is not supported as a Display value" + }, + { + "key": "idd", + "value": null, + "error": "Field 'idd' not found" + }, + { + "key": "namee", + "value": null, + "error": "Field 'namee' not found" + }, + { + "key": "nums", + "value": "420", + "error": null + } + ] + } + ] + } + } + } +} + +task 13 'run'. lines 180-180: +events: Event { package_id: Test, transaction_module: Identifier("boars"), sender: A, type_: StructTag { address: iota, module: Identifier("display"), name: Identifier("VersionUpdated"), type_params: [Struct(StructTag { address: Test, module: Identifier("boars"), name: Identifier("Boar"), type_params: [] })] }, contents: [157, 80, 190, 33, 119, 59, 45, 238, 34, 126, 254, 191, 25, 36, 11, 95, 217, 30, 133, 175, 214, 221, 149, 84, 133, 67, 247, 141, 240, 193, 184, 229, 3, 0, 15, 7, 118, 101, 99, 116, 111, 114, 115, 5, 123, 118, 101, 99, 125, 3, 105, 100, 100, 5, 123, 105, 100, 100, 125, 5, 110, 97, 109, 101, 101, 7, 123, 110, 97, 109, 101, 101, 125, 4, 110, 117, 109, 115, 6, 123, 110, 117, 109, 115, 125, 5, 98, 111, 111, 108, 115, 7, 123, 98, 111, 111, 108, 115, 125, 5, 98, 117, 121, 101, 114, 7, 123, 98, 117, 121, 101, 114, 125, 4, 110, 97, 109, 101, 6, 123, 110, 97, 109, 101, 125, 7, 99, 114, 101, 97, 116, 111, 114, 9, 123, 99, 114, 101, 97, 116, 111, 114, 125, 5, 112, 114, 105, 99, 101, 7, 123, 112, 114, 105, 99, 101, 125, 11, 112, 114, 111, 106, 101, 99, 116, 95, 117, 114, 108, 58, 85, 110, 105, 113, 117, 101, 32, 66, 111, 97, 114, 32, 102, 114, 111, 109, 32, 116, 104, 101, 32, 66, 111, 97, 114, 115, 32, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 32, 119, 105, 116, 104, 32, 123, 110, 97, 109, 101, 125, 32, 97, 110, 100, 32, 123, 105, 100, 125, 8, 98, 97, 115, 101, 95, 117, 114, 108, 32, 104, 116, 116, 112, 115, 58, 47, 47, 103, 101, 116, 45, 97, 45, 98, 111, 97, 114, 46, 99, 111, 109, 47, 123, 105, 109, 103, 95, 117, 114, 108, 125, 11, 110, 111, 95, 116, 101, 109, 112, 108, 97, 116, 101, 23, 104, 116, 116, 112, 115, 58, 47, 47, 103, 101, 116, 45, 97, 45, 98, 111, 97, 114, 46, 99, 111, 109, 47, 3, 97, 103, 101, 21, 123, 109, 101, 116, 97, 100, 97, 116, 97, 46, 110, 101, 115, 116, 101, 100, 46, 97, 103, 101, 125, 8, 102, 117, 108, 108, 95, 117, 114, 108, 10, 123, 102, 117, 108, 108, 95, 117, 114, 108, 125, 13, 101, 115, 99, 97, 112, 101, 95, 115, 121, 110, 116, 97, 120, 8, 92, 123, 110, 97, 109, 101, 92, 125] } +mutated: object(0,0), object(1,1) +gas summary: computation_cost: 1000000, storage_cost: 5236400, storage_rebate: 3002076, non_refundable_storage_fee: 30324 + +task 14 'create-checkpoint'. lines 182-182: +Checkpoint created: 4 + +task 15 'view-checkpoint'. lines 184-184: +CheckpointSummary { epoch: 0, seq: 4, content_digest: Edca7Q6cQmwQkpJTAojfrLh4tjkM9Zvxkbz2imBnUQbK, + epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 5000000, storage_cost: 36236800, storage_rebate: 9517860, non_refundable_storage_fee: 96140 }} + +task 16 'run-graphql'. lines 186-199: +Response: { + "data": { + "address": { + "objects": { + "nodes": [ + { + "display": [ + { + "key": "vectors", + "value": null, + "error": "Vector of name vec is not supported as a Display value" + }, + { + "key": "idd", + "value": null, + "error": "Field 'idd' not found" + }, + { + "key": "namee", + "value": null, + "error": "Field 'namee' not found" + }, + { + "key": "nums", + "value": "420", + "error": null + }, + { + "key": "bools", + "value": "true", + "error": null + }, + { + "key": "buyer", + "value": "0xfccc9a421bbb13c1a66a1aa98f0ad75029ede94857779c6915b44f94068b921e", + "error": null + }, + { + "key": "name", + "value": "First Boar", + "error": null + }, + { + "key": "creator", + "value": "Will", + "error": null + }, + { + "key": "price", + "value": "", + "error": null + }, + { + "key": "project_url", + "value": "Unique Boar from the Boars collection with First Boar and 0x8191fe2b7da69708e88717dddab3af8544a09aa17dcfb2889be64569e68559c7", + "error": null + }, + { + "key": "base_url", + "value": "https://get-a-boar.com/first.png", + "error": null + }, + { + "key": "no_template", + "value": "https://get-a-boar.com/", + "error": null + }, + { + "key": "age", + "value": "10", + "error": null + }, + { + "key": "full_url", + "value": "https://get-a-boar.fullurl.com/", + "error": null + }, + { + "key": "escape_syntax", + "value": "{name}", + "error": null + } + ] + } + ] + } + } + } +} diff --git a/crates/iota-graphql-e2e-tests/tests/objects/display.move b/crates/iota-graphql-e2e-tests/tests/objects/display.move new file mode 100644 index 00000000000..7317e9b63e2 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/objects/display.move @@ -0,0 +1,200 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --protocol-version 39 --addresses Test=0x0 --accounts A --simulator + +//# publish --sender A +module Test::boars { + use iota::package; + use iota::url::{Self, Url}; + use iota::display; + use std::string::{utf8, String}; + + /// For when a witness type passed is not an OTW. + const ENotOneTimeWitness: u64 = 0; + + /// An OTW to use when creating a Publisher + public struct BOARS has drop {} + + public struct Boar has key, store { + id: UID, + img_url: String, + name: String, + description: String, + creator: Option, + price: Option, + metadata: NestedMetadata, + full_url: Url, + nums: u64, + bools: bool, + buyer: address, + vec: vector, + } + + public struct Metadata has store { + age: u64, + } + + public struct NestedMetadata has store { + nested: Metadata + } + + fun init(otw: BOARS, ctx: &mut TxContext) { + let pub = package::claim(otw, ctx); + let display = display::new(&pub, ctx); + + transfer::public_transfer(display, ctx.sender()); + transfer::public_transfer(pub, ctx.sender()); + } + + + public entry fun update_display_faulty(display_obj: &mut display::Display) { + display::add_multiple(display_obj, vector[ + utf8(b"vectors"), + utf8(b"idd"), + utf8(b"namee"), + ], vector[ + utf8(b"{vec}"), + utf8(b"{idd}"), + utf8(b"{namee}"), + ]); + display::update_version(display_obj) + } + + public entry fun single_add(display_obj: &mut display::Display) { + display::add(display_obj, utf8(b"nums"), utf8(b"{nums}")); + display::update_version(display_obj) + } + + public entry fun multi_add(display_obj: &mut display::Display) { + display::add_multiple(display_obj, vector[ + utf8(b"bools"), + utf8(b"buyer"), + utf8(b"name"), + utf8(b"creator"), + utf8(b"price"), + utf8(b"project_url"), + utf8(b"base_url"), + utf8(b"no_template"), + utf8(b"age"), + utf8(b"full_url"), + utf8(b"escape_syntax"), + ], vector[ + // test bool + utf8(b"{bools}"), + // test address + utf8(b"{buyer}"), + // test string + utf8(b"{name}"), + // test optional string w/ Some value + utf8(b"{creator}"), + // test optional string w/ None value + utf8(b"{price}"), + // test multiple fields and UID + utf8(b"Unique Boar from the Boars collection with {name} and {id}"), + utf8(b"https://get-a-boar.com/{img_url}"), + // test no template value + utf8(b"https://get-a-boar.com/"), + // test nested struct + utf8(b"{metadata.nested.age}"), + // test Url type + utf8(b"{full_url}"), + // test escape syntax + utf8(b"\\{name\\}"), + ]); + + display::update_version(display_obj); + } + + public entry fun create_bear(ctx: &mut TxContext) { + let boar = Boar { + id: object::new(ctx), + img_url: utf8(b"first.png"), + name: utf8(b"First Boar"), + description: utf8(b"First Boar from the Boars collection!"), + creator: option::some(utf8(b"Will")), + price: option::none(), + metadata: NestedMetadata { + nested: Metadata { + age: 10, + }, + }, + full_url: url::new_unsafe_from_bytes(b"https://get-a-boar.fullurl.com/"), + nums: 420, + bools: true, + buyer: ctx.sender(), + vec: vector[1, 2, 3], + }; + transfer::transfer(boar, ctx.sender()) + } +} + +//# create-checkpoint + +//# view-checkpoint + +//# run Test::boars::create_bear --sender A + +//# run Test::boars::update_display_faulty --sender A --args object(1,1) + +//# create-checkpoint + +//# view-checkpoint + +//# run-graphql +{ + address(address: "@{A}") { + objects(filter: {type: "@{Test}::boars::Boar"}) { + nodes { + display { + key + value + error + } + } + } + } +} + +//# run Test::boars::single_add --sender A --args object(1,1) + +//# create-checkpoint + +//# view-checkpoint + +//# run-graphql +{ + address(address: "@{A}") { + objects(filter: {type: "@{Test}::boars::Boar"}) { + nodes { + display { + key + value + error + } + } + } + } +} + +//# run Test::boars::multi_add --sender A --args object(1,1) + +//# create-checkpoint + +//# view-checkpoint + +//# run-graphql +{ + address(address: "@{A}") { + objects(filter: {type: "@{Test}::boars::Boar"}) { + nodes { + display { + key + value + error + } + } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/objects/filter_by_type.exp b/crates/iota-graphql-e2e-tests/tests/objects/filter_by_type.exp similarity index 87% rename from crates/sui-graphql-e2e-tests/tests/objects/filter_by_type.exp rename to crates/iota-graphql-e2e-tests/tests/objects/filter_by_type.exp index db3a1167c69..a7dd07fa264 100644 --- a/crates/sui-graphql-e2e-tests/tests/objects/filter_by_type.exp +++ b/crates/iota-graphql-e2e-tests/tests/objects/filter_by_type.exp @@ -15,7 +15,7 @@ mutated: object(0,0) gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 0, non_refundable_storage_fee: 0 task 4 'run'. lines 15-17: -events: Event { package_id: sui_system, transaction_module: Identifier("sui_system"), sender: C, type_: StructTag { address: sui_system, module: Identifier("validator"), name: Identifier("StakingRequestEvent"), type_params: [] }, contents: [138, 42, 97, 253, 61, 22, 31, 106, 213, 157, 60, 241, 33, 156, 159, 193, 184, 127, 83, 194, 143, 198, 11, 54, 121, 139, 166, 151, 113, 26, 5, 97, 218, 131, 22, 109, 1, 175, 215, 221, 207, 138, 245, 248, 68, 244, 90, 170, 83, 244, 133, 72, 229, 17, 124, 35, 245, 162, 151, 140, 253, 66, 34, 68, 252, 204, 154, 66, 27, 187, 19, 193, 166, 106, 26, 169, 143, 10, 215, 80, 41, 237, 233, 72, 87, 119, 156, 105, 21, 180, 79, 148, 6, 139, 146, 30, 1, 0, 0, 0, 0, 0, 0, 0, 0, 228, 11, 84, 2, 0, 0, 0] } +events: Event { package_id: iota_system, transaction_module: Identifier("iota_system"), sender: C, type_: StructTag { address: iota_system, module: Identifier("validator"), name: Identifier("StakingRequestEvent"), type_params: [] }, contents: [138, 42, 97, 253, 61, 22, 31, 106, 213, 157, 60, 241, 33, 156, 159, 193, 184, 127, 83, 194, 143, 198, 11, 54, 121, 139, 166, 151, 113, 26, 5, 97, 218, 131, 22, 109, 1, 175, 215, 221, 207, 138, 245, 248, 68, 244, 90, 170, 83, 244, 133, 72, 229, 17, 124, 35, 245, 162, 151, 140, 253, 66, 34, 68, 252, 204, 154, 66, 27, 187, 19, 193, 166, 106, 26, 169, 143, 10, 215, 80, 41, 237, 233, 72, 87, 119, 156, 105, 21, 180, 79, 148, 6, 139, 146, 30, 1, 0, 0, 0, 0, 0, 0, 0, 0, 228, 11, 84, 2, 0, 0, 0] } created: object(4,0) mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000005, object(0,0) deleted: object(3,0) @@ -37,7 +37,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000003::staking_pool::StakedSui" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000003::staking_pool::StakedIota" } } } @@ -48,7 +48,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000003::staking_pool::StakedSui" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000003::staking_pool::StakedIota" } } } @@ -59,7 +59,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000003::staking_pool::StakedSui" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000003::staking_pool::StakedIota" } } } @@ -146,7 +146,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -157,7 +157,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -168,7 +168,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field" } } } @@ -201,7 +201,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::CoinMetadata<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::CoinMetadata<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -223,7 +223,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -266,7 +266,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -277,7 +277,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -288,7 +288,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::CoinMetadata<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::CoinMetadata<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -299,7 +299,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -320,7 +320,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -331,7 +331,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -342,7 +342,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -363,7 +363,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -374,7 +374,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } @@ -385,7 +385,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } } } diff --git a/crates/sui-graphql-e2e-tests/tests/objects/filter_by_type.move b/crates/iota-graphql-e2e-tests/tests/objects/filter_by_type.move similarity index 90% rename from crates/sui-graphql-e2e-tests/tests/objects/filter_by_type.move rename to crates/iota-graphql-e2e-tests/tests/objects/filter_by_type.move index 29caca88020..2ae2e60022d 100644 --- a/crates/sui-graphql-e2e-tests/tests/objects/filter_by_type.move +++ b/crates/iota-graphql-e2e-tests/tests/objects/filter_by_type.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --simulator --accounts C @@ -12,7 +13,7 @@ //> SplitCoins(Gas, [Input(0)]); //> TransferObjects([Result(0)], Input(1)) -//# run 0x3::sui_system::request_add_stake --args object(0x5) object(3,0) @validator_0 --sender C +//# run 0x3::iota_system::request_add_stake --args object(0x5) object(3,0) @validator_0 --sender C // TODO: Short term hack to get around indexer epoch issue //# create-checkpoint @@ -21,7 +22,7 @@ //# run-graphql { - objects(filter: {type: "0x3::staking_pool::StakedSui"}) { + objects(filter: {type: "0x3::staking_pool::StakedIota"}) { edges { node { asMoveObject { @@ -88,9 +89,9 @@ } //# run-graphql -# Fetch coins of 0x2::sui::SUI inner type +# Fetch coins of 0x2::iota::IOTA inner type { - objects(filter: {type: "0x2::coin::Coin<0x2::sui::SUI>"}) { + objects(filter: {type: "0x2::coin::Coin<0x2::iota::IOTA>"}) { edges { node { asMoveObject { diff --git a/crates/sui-graphql-e2e-tests/tests/objects/pagination.exp b/crates/iota-graphql-e2e-tests/tests/objects/pagination.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/objects/pagination.exp rename to crates/iota-graphql-e2e-tests/tests/objects/pagination.exp diff --git a/crates/iota-graphql-e2e-tests/tests/objects/pagination.move b/crates/iota-graphql-e2e-tests/tests/objects/pagination.move new file mode 100644 index 00000000000..87476a7e827 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/objects/pagination.move @@ -0,0 +1,105 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --protocol-version 39 --addresses Test=0x0 A=0x42 --simulator + +//# publish +module Test::M1 { + public struct Object has key, store { + id: UID, + value: u64, + } + + public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { + transfer::public_transfer( + Object { id: object::new(ctx), value }, + recipient + ) + } +} + +//# run Test::M1::create --args 0 @A + +//# run Test::M1::create --args 1 @A + +//# run Test::M1::create --args 2 @A + +//# run Test::M1::create --args 3 @A + +//# run Test::M1::create --args 4 @A + +//# create-checkpoint + +//# run-graphql +{ + # select all objects owned by A + address(address: "@{A}") { + objects { + edges { + cursor + } + } + } +} + +//# run-graphql +{ + # select the first 2 objects owned by A + address(address: "@{A}") { + objects(first: 2) { + edges { + cursor + } + } + } +} + +//# run-graphql --cursors @{obj_5_0} +{ + address(address: "@{A}") { + # select the 2nd and 3rd objects + # note that order does not correspond + # to order in which objects were created + objects(first: 2 after: "@{cursor_0}") { + edges { + cursor + } + } + } +} + +//# run-graphql --cursors @{obj_4_0} +{ + address(address: "@{A}") { + # select 4th and last object + objects(first: 2 after: "@{cursor_0}") { + edges { + cursor + } + } + } +} + +//# run-graphql --cursors @{obj_3_0} +{ + address(address: "@{A}") { + # select 3rd and 4th object + objects(last: 2 before: "@{cursor_0}") { + edges { + cursor + } + } + } +} + +//# run-graphql +{ + address(address: "@{A}") { + objects(last: 2) { + edges { + cursor + } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/objects/public_transfer.exp b/crates/iota-graphql-e2e-tests/tests/objects/public_transfer.exp similarity index 96% rename from crates/sui-graphql-e2e-tests/tests/objects/public_transfer.exp rename to crates/iota-graphql-e2e-tests/tests/objects/public_transfer.exp index 82fc467b5ce..617dde00173 100644 --- a/crates/sui-graphql-e2e-tests/tests/objects/public_transfer.exp +++ b/crates/iota-graphql-e2e-tests/tests/objects/public_transfer.exp @@ -42,7 +42,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } }, "hasPublicTransfer": true diff --git a/crates/sui-graphql-e2e-tests/tests/objects/public_transfer.move b/crates/iota-graphql-e2e-tests/tests/objects/public_transfer.move similarity index 95% rename from crates/sui-graphql-e2e-tests/tests/objects/public_transfer.move rename to crates/iota-graphql-e2e-tests/tests/objects/public_transfer.move index 5dc1bdb2520..80e4d7ade50 100644 --- a/crates/sui-graphql-e2e-tests/tests/objects/public_transfer.move +++ b/crates/iota-graphql-e2e-tests/tests/objects/public_transfer.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses P0=0x0 --accounts A --simulator diff --git a/crates/sui-graphql-e2e-tests/tests/objects/received.exp b/crates/iota-graphql-e2e-tests/tests/objects/received.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/objects/received.exp rename to crates/iota-graphql-e2e-tests/tests/objects/received.exp diff --git a/crates/sui-graphql-e2e-tests/tests/objects/received.move b/crates/iota-graphql-e2e-tests/tests/objects/received.move similarity index 93% rename from crates/sui-graphql-e2e-tests/tests/objects/received.move rename to crates/iota-graphql-e2e-tests/tests/objects/received.move index dfde1c5a9ac..a6ab8591972 100644 --- a/crates/sui-graphql-e2e-tests/tests/objects/received.move +++ b/crates/iota-graphql-e2e-tests/tests/objects/received.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses P0=0x0 --simulator diff --git a/crates/sui-graphql-e2e-tests/tests/objects/snapshot.exp b/crates/iota-graphql-e2e-tests/tests/objects/snapshot.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/objects/snapshot.exp rename to crates/iota-graphql-e2e-tests/tests/objects/snapshot.exp diff --git a/crates/iota-graphql-e2e-tests/tests/objects/staked_iota.exp b/crates/iota-graphql-e2e-tests/tests/objects/staked_iota.exp new file mode 100644 index 00000000000..b522ad81c90 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/objects/staked_iota.exp @@ -0,0 +1,102 @@ +processed 7 tasks + +init: +C: object(0,0) + +task 1 'run-graphql'. lines 6-31: +Response: { + "data": { + "objects": { + "edges": [ + { + "cursor": "IJWZW/OSvG5lfNwrD5Efh60SfOWYpPQ2klpOeswsoIDnAAAAAAAAAAA=", + "node": { + "asMoveObject": { + "asStakedIota": { + "principal": "20000000000000000" + } + } + } + } + ] + }, + "address": { + "stakedIotas": { + "edges": [] + } + } + } +} + +task 2 'programmable'. lines 33-35: +created: object(2,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 0, non_refundable_storage_fee: 0 + +task 3 'run'. lines 37-37: +events: Event { package_id: iota_system, transaction_module: Identifier("iota_system"), sender: C, type_: StructTag { address: iota_system, module: Identifier("validator"), name: Identifier("StakingRequestEvent"), type_params: [] }, contents: [138, 42, 97, 253, 61, 22, 31, 106, 213, 157, 60, 241, 33, 156, 159, 193, 184, 127, 83, 194, 143, 198, 11, 54, 121, 139, 166, 151, 113, 26, 5, 97, 218, 131, 22, 109, 1, 175, 215, 221, 207, 138, 245, 248, 68, 244, 90, 170, 83, 244, 133, 72, 229, 17, 124, 35, 245, 162, 151, 140, 253, 66, 34, 68, 252, 204, 154, 66, 27, 187, 19, 193, 166, 106, 26, 169, 143, 10, 215, 80, 41, 237, 233, 72, 87, 119, 156, 105, 21, 180, 79, 148, 6, 139, 146, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 11, 84, 2, 0, 0, 0] } +created: object(3,0), object(3,1) +mutated: 0x0000000000000000000000000000000000000000000000000000000000000005, object(0,0) +deleted: object(_), object(2,0) +gas summary: computation_cost: 1000000, storage_cost: 15078400, storage_rebate: 1956240, non_refundable_storage_fee: 19760 + +task 4 'create-checkpoint'. lines 39-39: +Checkpoint created: 1 + +task 5 'advance-epoch'. lines 41-41: +Epoch advanced: 0 + +task 6 'run-graphql'. lines 43-69: +Response: { + "data": { + "objects": { + "edges": [ + { + "cursor": "IBX0DS9yEyPNAQauq4aH+cupD1Spyw3GeIxMiAUZU0iSAgAAAAAAAAA=", + "node": { + "asMoveObject": { + "asStakedIota": { + "principal": "10000000000", + "poolId": "0x8a2a61fd3d161f6ad59d3cf1219c9fc1b87f53c28fc60b36798ba697711a0561" + } + } + } + }, + { + "cursor": "IJWZW/OSvG5lfNwrD5Efh60SfOWYpPQ2klpOeswsoIDnAgAAAAAAAAA=", + "node": { + "asMoveObject": { + "asStakedIota": { + "principal": "20000000000000000", + "poolId": "0x8a2a61fd3d161f6ad59d3cf1219c9fc1b87f53c28fc60b36798ba697711a0561" + } + } + } + }, + { + "cursor": "IM4xOAHc44iKtPoj6VC+X2JPItu/LKLvVeSyLZAGWA+/AgAAAAAAAAA=", + "node": { + "asMoveObject": { + "asStakedIota": { + "principal": "40000", + "poolId": "0x8a2a61fd3d161f6ad59d3cf1219c9fc1b87f53c28fc60b36798ba697711a0561" + } + } + } + } + ] + }, + "address": { + "stakedIotas": { + "edges": [ + { + "cursor": "IBX0DS9yEyPNAQauq4aH+cupD1Spyw3GeIxMiAUZU0iSAgAAAAAAAAA=", + "node": { + "principal": "10000000000" + } + } + ] + } + } + } +} diff --git a/crates/iota-graphql-e2e-tests/tests/objects/staked_iota.move b/crates/iota-graphql-e2e-tests/tests/objects/staked_iota.move new file mode 100644 index 00000000000..2842f24178d --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/objects/staked_iota.move @@ -0,0 +1,70 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --protocol-version 39 --simulator --accounts C + +//# run-graphql +{ # init --protocol-version 39ial query yields only the validator's stake + objects(filter: { type: "0x3::staking_pool::StakedIota" }) { + edges { + cursor + node { + asMoveObject { + asStakedIota { + principal + } + } + } + } + } + + address(address: "@{C}") { + stakedIotas { + edges { + cursor + node { + principal + } + } + } + } +} + +//# programmable --sender C --inputs 10000000000 @C +//> SplitCoins(Gas, [Input(0)]); +//> TransferObjects([Result(0)], Input(1)) + +//# run 0x3::iota_system::request_add_stake --args object(0x5) object(2,0) @validator_0 --sender C + +//# create-checkpoint + +//# advance-epoch + +//# run-graphql +{ # This query should pick up the recently Staked IOTA as well. + objects(filter: { type: "0x3::staking_pool::StakedIota" }) { + edges { + cursor + node { + asMoveObject { + asStakedIota { + principal + poolId + } + } + } + } + } + + address(address: "@{C}") { + stakedIotas { + edges { + cursor + node { + principal + } + } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/owner/downcasts.exp b/crates/iota-graphql-e2e-tests/tests/owner/downcasts.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/owner/downcasts.exp rename to crates/iota-graphql-e2e-tests/tests/owner/downcasts.exp diff --git a/crates/sui-graphql-e2e-tests/tests/owner/downcasts.move b/crates/iota-graphql-e2e-tests/tests/owner/downcasts.move similarity index 90% rename from crates/sui-graphql-e2e-tests/tests/owner/downcasts.move rename to crates/iota-graphql-e2e-tests/tests/owner/downcasts.move index 47cf8908f81..7437830baa3 100644 --- a/crates/sui-graphql-e2e-tests/tests/owner/downcasts.move +++ b/crates/iota-graphql-e2e-tests/tests/owner/downcasts.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses P0=0x0 --accounts A --simulator diff --git a/crates/sui-graphql-e2e-tests/tests/packages/friends.exp b/crates/iota-graphql-e2e-tests/tests/packages/friends.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/packages/friends.exp rename to crates/iota-graphql-e2e-tests/tests/packages/friends.exp diff --git a/crates/sui-graphql-e2e-tests/tests/packages/friends.move b/crates/iota-graphql-e2e-tests/tests/packages/friends.move similarity index 99% rename from crates/sui-graphql-e2e-tests/tests/packages/friends.move rename to crates/iota-graphql-e2e-tests/tests/packages/friends.move index 453daddbfc3..1df0d553b8a 100644 --- a/crates/sui-graphql-e2e-tests/tests/packages/friends.move +++ b/crates/iota-graphql-e2e-tests/tests/packages/friends.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses P0=0x0 P1=0x0 --accounts A --simulator diff --git a/crates/sui-graphql-e2e-tests/tests/packages/functions.exp b/crates/iota-graphql-e2e-tests/tests/packages/functions.exp similarity index 99% rename from crates/sui-graphql-e2e-tests/tests/packages/functions.exp rename to crates/iota-graphql-e2e-tests/tests/packages/functions.exp index 22b1fb037b4..265f4e99b08 100644 --- a/crates/sui-graphql-e2e-tests/tests/packages/functions.exp +++ b/crates/iota-graphql-e2e-tests/tests/packages/functions.exp @@ -49,7 +49,7 @@ Response: { "return": [] } }, - "sui": { + "iota": { "new": { "name": "new", "visibility": "PRIVATE", @@ -62,7 +62,7 @@ Response: { ], "return": [ { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::balance::Balance<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::balance::Balance<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" } ] } diff --git a/crates/sui-graphql-e2e-tests/tests/packages/functions.move b/crates/iota-graphql-e2e-tests/tests/packages/functions.move similarity index 98% rename from crates/sui-graphql-e2e-tests/tests/packages/functions.move rename to crates/iota-graphql-e2e-tests/tests/packages/functions.move index e76bbfa41d8..147a0f8a1bf 100644 --- a/crates/sui-graphql-e2e-tests/tests/packages/functions.move +++ b/crates/iota-graphql-e2e-tests/tests/packages/functions.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses P0=0x0 P1=0x0 --accounts A --simulator @@ -29,7 +30,7 @@ fragment Signature on MoveFunction { } - sui: module(name: "sui") { + iota: module(name: "iota") { # A private function new: function(name: "new") { ...Signature } } diff --git a/crates/sui-graphql-e2e-tests/tests/packages/modules.exp b/crates/iota-graphql-e2e-tests/tests/packages/modules.exp similarity index 95% rename from crates/sui-graphql-e2e-tests/tests/packages/modules.exp rename to crates/iota-graphql-e2e-tests/tests/packages/modules.exp index 85abfd88809..ec5ff1e7cac 100644 --- a/crates/sui-graphql-e2e-tests/tests/packages/modules.exp +++ b/crates/iota-graphql-e2e-tests/tests/packages/modules.exp @@ -28,7 +28,7 @@ Response: { }, "fileFormatVersion": 6, "bytes": "oRzrCwYAAAAIAQAGAgYKAxARBCEEBSUfB0QiCGZADKYBMAAFAQMBBgEADAEAAQIBAgAABAABAQIAAgIBAAEHBQEBAAIEAAYCAwYLAAEJAAEDAQYLAAEIAQABCQABBgsAAQkAAQgBBENvaW4DU1VJA2JhcgRjb2luA2ZvbwFtA3N1aQV2YWx1ZaGf7+LT9VEZNwQORkIUweRkrShKola5B/FJRTeaOMggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAQAAAwULATgACwAWAgEBAAADCAYqAAAAAAAAAAoAOAEGKwAAAAAAAAALADgBGAIA", - "disassembly": "// Move bytecode v6\nmodule a19fefe2d3f5511937040e464214c1e464ad284aa256b907f14945379a38c820.m {\nuse 0000000000000000000000000000000000000000000000000000000000000002::coin;\nuse 0000000000000000000000000000000000000000000000000000000000000002::sui;\n\n\n\n\npublic foo(Arg0: u64, Arg1: &Coin): u64 {\nB0:\n\t0: MoveLoc[1](Arg1: &Coin)\n\t1: Call coin::value(&Coin): u64\n\t2: MoveLoc[0](Arg0: u64)\n\t3: Add\n\t4: Ret\n}\npublic bar(Arg0: &Coin): u64 {\nB0:\n\t0: LdU64(42)\n\t1: CopyLoc[0](Arg0: &Coin)\n\t2: Call foo(u64, &Coin): u64\n\t3: LdU64(43)\n\t4: MoveLoc[0](Arg0: &Coin)\n\t5: Call foo(u64, &Coin): u64\n\t6: Mul\n\t7: Ret\n}\n}" + "disassembly": "// Move bytecode v6\nmodule a19fefe2d3f5511937040e464214c1e464ad284aa256b907f14945379a38c820.m {\nuse 0000000000000000000000000000000000000000000000000000000000000002::coin;\nuse 0000000000000000000000000000000000000000000000000000000000000002::iota;\n\n\n\n\npublic foo(Arg0: u64, Arg1: &Coin): u64 {\nB0:\n\t0: MoveLoc[1](Arg1: &Coin)\n\t1: Call coin::value(&Coin): u64\n\t2: MoveLoc[0](Arg0: u64)\n\t3: Add\n\t4: Ret\n}\npublic bar(Arg0: &Coin): u64 {\nB0:\n\t0: LdU64(42)\n\t1: CopyLoc[0](Arg0: &Coin)\n\t2: Call foo(u64, &Coin): u64\n\t3: LdU64(43)\n\t4: MoveLoc[0](Arg0: &Coin)\n\t5: Call foo(u64, &Coin): u64\n\t6: Mul\n\t7: Ret\n}\n}" } } } diff --git a/crates/iota-graphql-e2e-tests/tests/packages/modules.move b/crates/iota-graphql-e2e-tests/tests/packages/modules.move new file mode 100644 index 00000000000..aa79ec80b3f --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/packages/modules.move @@ -0,0 +1,147 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --protocol-version 39 --addresses pkg=0x0 --simulator + +//# publish + +module pkg::m { + use iota::coin::{Self, Coin}; + use iota::iota::IOTA; + + public fun foo(x: u64, c: &Coin): u64 { + coin::value(c) + x + } + + public fun bar(c: &Coin): u64 { + foo(42, c) * foo(43, c) + } +} + +module pkg::n { + public fun baz(): u32 { + 44 + } +} + +module pkg::o { + public fun qux(): u32 { + 45 + } +} + +//# create-checkpoint + +//# run-graphql + +fragment Modules on Object { + address + asMovePackage { + module(name: "m") { + name + package { address } + + fileFormatVersion + bytes + disassembly + } + } +} + +{ + transactionBlocks(last: 1) { + nodes { + effects { + objectChanges { + nodes { + outputState { + ...Modules + } + } + } + } + } + } +} + +//# run-graphql --cursors {"n":"m","c":1} {"n":"o","c":1} +fragment NodeNames on MoveModuleConnection { + edges { + cursor + node { name } + } + pageInfo { hasNextPage hasPreviousPage } +} + +fragment Modules on Object { + address + asMovePackage { + # Tests to make sure `after` and `before` correctly limit the + # upper and lower bounds on the range of modules, and + # correctly detect the existence of predecessor or successor + # pages. + + all: modules { ...NodeNames } + after: modules(after: "@{cursor_0}") { ...NodeNames } + before: modules(before: "@{cursor_1}") { ...NodeNames } + } +} + +{ + transactionBlocks(last: 1) { + nodes { + effects { + objectChanges { + nodes { + outputState { + ...Modules + } + } + } + } + } + } +} + +//# run-graphql --cursors {"n":"m","c":1} {"n":"o","c":1} +fragment NodeNames on MoveModuleConnection { + edges { + cursor + node { name } + } + pageInfo { hasNextPage hasPreviousPage } +} + +fragment Modules on Object { + address + asMovePackage { + # Tests to make sure `first` and `last` correctly limit the + # number of modules returned and correctly detect the + # existence of predecessor or successor pages. + + prefix: modules(after: "@{cursor_0}", first: 1) { ...NodeNames } + prefixAll: modules(after: "@{cursor_0}", first: 2) { ...NodeNames } + prefixExcess: modules(after: "@{cursor_0}", first: 20) { ...NodeNames } + + suffix: modules(before: "@{cursor_1}", last: 1) { ...NodeNames } + suffixAll: modules(before: "@{cursor_1}", last: 2) { ...NodeNames } + suffixExcess: modules(before: "@{cursor_1}", last: 20) { ...NodeNames } + } +} + +{ + transactionBlocks(last: 1) { + nodes { + effects { + objectChanges { + nodes { + outputState { + ...Modules + } + } + } + } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/packages/structs.exp b/crates/iota-graphql-e2e-tests/tests/packages/structs.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/packages/structs.exp rename to crates/iota-graphql-e2e-tests/tests/packages/structs.exp diff --git a/crates/iota-graphql-e2e-tests/tests/packages/structs.move b/crates/iota-graphql-e2e-tests/tests/packages/structs.move new file mode 100644 index 00000000000..6b43d3ab107 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/packages/structs.move @@ -0,0 +1,301 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --protocol-version 39 --addresses P0=0x0 P1=0x0 --accounts A --simulator + +//# run-graphql + +# Tests on existing system types +{ + object(address: "0x2") { + asMovePackage { + # Look-up a type that has generics, including phantoms. + coin: module(name: "coin") { + struct(name: "Coin") { + name + abilities + typeParameters { + constraints + isPhantom + } + fields { + name + type { + repr + signature + } + } + } + } + + tx_context: module(name: "tx_context") { + struct(name: "TxContext") { + name + abilities + typeParameters { + constraints + isPhantom + } + fields { + name + type { + repr + signature + } + } + } + } + } + } +} + +//# publish --upgradeable --sender A + +module P0::m { + public struct S has copy, drop { x: u64 } +} + +//# create-checkpoint + +//# run-graphql + +# Check the contents of P0::m::S that was just published, this acts as +# a reference for when we run the same transaction against the +# upgraded package. +fragment Structs on Object { + address + asMovePackage { + module(name: "m") { + struct(name: "S") { + name + abilities + typeParameters { + constraints + isPhantom + } + fields { + name + type { + repr + signature + } + } + } + } + } +} + +{ + transactionBlocks(last: 1) { + nodes { + effects { + objectChanges { + nodes { + outputState { + ...Structs + } + } + } + } + } + } +} + +//# upgrade --package P0 --upgrade-capability 2,1 --sender A + +module P1::m { + public struct S has copy, drop { x: u64 } + public struct T { y: u64, s: S, u: U } + public struct V { t: T } +} + +//# create-checkpoint + +//# run-graphql + +# Run a similar query as above again, but on the upgraded package, to +# see the IDs of types as they appear in the new package -- they will +# all be the runtime ID. +fragment FullStruct on MoveStruct { + module { package { address } } + name + abilities + typeParameters { + constraints + isPhantom + } + fields { + name + type { + repr + signature + } + } +} + +fragment Structs on Object { + address + asMovePackage { + module(name: "m") { + s: struct(name: "S") { ...FullStruct } + t: struct(name: "T") { ...FullStruct } + + # V is a special type that exists to show the + # representations of S and T, so we don't need to query as + # many fields for it. + v: struct(name: "V") { + name + fields { + name + type { repr } + } + } + } + } +} + +{ + transactionBlocks(last: 1) { + nodes { + effects { + objectChanges { + nodes { + outputState { + ...Structs + } + } + } + } + } + } +} + +//# run-graphql + +# But we can still confirm that we can roundtrip the `T` public struct from +# its own module, but cannot reach `T` from `S`'s defining module. + +fragment ReachT on MoveStruct { + module { struct(name: "T") { name } } +} + +fragment Structs on Object { + asMovePackage { + module(name: "m") { + # S should not be able to reach T from its own module + s: struct(name: "S") { ...ReachT } + + # But T should + t: struct(name: "T") { ...ReachT } + } + } +} + +{ + transactionBlocks(last: 1) { + nodes { + effects { + objectChanges { + nodes { + outputState { + ...Structs + } + } + } + } + } + } +} + + +//# run-graphql --cursors {"n":"Coin","c":2} {"n":"TreasuryCap","c":2} +{ + object(address: "0x2") { + asMovePackage { + module(name: "coin") { + # Get all the types defined in coin + all: structs { + nodes { + name + fields { + name + type { repr } + } + } + pageInfo { hasNextPage hasPreviousPage } + } + + # After: Coin is the first type and `after` is an + # exclusive lower bound, so this query should indicate + # there is a previous page, and not include `Coin` in + # the output. + after: structs(after: "@{cursor_0}") { + edges { + cursor + node { name } + } + pageInfo { hasNextPage hasPreviousPage } + } + + # Before: Similar to `after` but at the end of the range. + before: structs(before: "@{cursor_1}") { + edges { + cursor + node { name } + } + pageInfo { hasNextPage hasPreviousPage } + } + } + } + } +} + +//# run-graphql --cursors {"n":"Coin","c":2} {"n":"TreasuryCap","c":2} +fragment NodeNames on MoveStructConnection { + edges { + cursor + node { name } + } + pageInfo { hasNextPage hasPreviousPage } +} + +{ + object(address: "0x2") { + asMovePackage { + module(name: "coin") { + # Limit the number of elements in the page using + # `first` and skip elements using `after`. + prefix: structs(after: "@{cursor_0}", first: 2) { + ...NodeNames + } + + # Limit has no effect because it matches the total + # number of entries in the page. + prefixAll: structs(after: "@{cursor_0}", first: 3) { + ...NodeNames + } + + # Limit also has no effect, because it exceeds the + # total number of entries in the page. + prefixExcess: structs(after: "@{cursor_0}", first: 20) { + ...NodeNames + } + + # Remaining tests are similar to after/first but with + # before/last. + suffix: structs(before: "@{cursor_1}", last: 2) { + ...NodeNames + } + + suffixAll: structs(before: "@{cursor_1}", last: 3) { + ...NodeNames + } + + suffixExcess: structs(before: "@{cursor_1}", last: 20) { + ...NodeNames + } + } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/packages/types.exp b/crates/iota-graphql-e2e-tests/tests/packages/types.exp similarity index 97% rename from crates/sui-graphql-e2e-tests/tests/packages/types.exp rename to crates/iota-graphql-e2e-tests/tests/packages/types.exp index c12ac6bff6b..6c4405c68d0 100644 --- a/crates/sui-graphql-e2e-tests/tests/packages/types.exp +++ b/crates/iota-graphql-e2e-tests/tests/packages/types.exp @@ -4,7 +4,7 @@ task 1 'run-graphql'. lines 6-15: Response: { "data": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::priority_queue::PriorityQueue<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>>", + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::priority_queue::PriorityQueue<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>>", "signature": { "datatype": { "package": "0x0000000000000000000000000000000000000000000000000000000000000002", @@ -20,8 +20,8 @@ Response: { { "datatype": { "package": "0x0000000000000000000000000000000000000000000000000000000000000002", - "module": "sui", - "type": "SUI", + "module": "iota", + "type": "IOTA", "typeParameters": [] } } @@ -33,14 +33,14 @@ Response: { }, "layout": { "struct": { - "type": "0x0000000000000000000000000000000000000000000000000000000000000002::priority_queue::PriorityQueue<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>>", + "type": "0x0000000000000000000000000000000000000000000000000000000000000002::priority_queue::PriorityQueue<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>>", "fields": [ { "name": "entries", "layout": { "vector": { "struct": { - "type": "0x0000000000000000000000000000000000000000000000000000000000000002::priority_queue::Entry<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>>", + "type": "0x0000000000000000000000000000000000000000000000000000000000000002::priority_queue::Entry<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>>", "fields": [ { "name": "priority", @@ -50,7 +50,7 @@ Response: { "name": "value", "layout": { "struct": { - "type": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>", + "type": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>", "fields": [ { "name": "id", @@ -80,7 +80,7 @@ Response: { "name": "balance", "layout": { "struct": { - "type": "0x0000000000000000000000000000000000000000000000000000000000000002::balance::Balance<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>", + "type": "0x0000000000000000000000000000000000000000000000000000000000000002::balance::Balance<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>", "fields": [ { "name": "value", diff --git a/crates/iota-graphql-e2e-tests/tests/packages/types.move b/crates/iota-graphql-e2e-tests/tests/packages/types.move new file mode 100644 index 00000000000..ca434bf0dbb --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/packages/types.move @@ -0,0 +1,153 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --protocol-version 39 --addresses P0=0x0 --simulator + +//# run-graphql +# Happy path -- valid type, get everything + +{ + type(type: "0x2::priority_queue::PriorityQueue<0x2::coin::Coin<0x2::iota::IOTA>>") { + repr + signature + layout + } +} + +//# run-graphql +# Happy path -- primitive type + +{ + type(type: "u64") { + repr + signature + layout + } +} + +//# run-graphql +# Happy path -- primitive type with generic parameter + +{ + type(type: "vector") { + repr + signature + layout + } +} + +//# run-graphql +# Unhappy path -- bad type tag (failed to parse) + +{ + type(type: "not_a_type") { + repr + signature + layout + } +} + +//# run-graphql +# Semi-happy path -- the input looks like a type, but that type +# doesn't exist. Depending on which fields you ask for, this request +# may still succeed. + +{ + type(type: "0x42::not::Here") { + repr + signature + } +} + +//# run-graphql +# Unhappy side of semi-happy path -- asking for a layout for a type +# that doesn't exist won't work. +# +# TODO: This currently produces an INTERNAL_SERVER_ERROR, but should +# produce a user error. This because, like other parts of our +# codebase, we don't have enough differentiation in error types for +# MoveType to signal an error in layout calculation and the GraphQL +# field implementations to know that it is a user error or an internal +# error. + +{ + type(type: "0x42::not::Here") { + layout + } +} + +//# run-graphql +# Querying abilities for concrete types + +{ + token: type(type: "0x2::token::Token<0x2::iota::IOTA>") { + abilities + } + + coin: type(type: "0x2::coin::Coin<0x2::iota::IOTA>") { + abilities + } + + balance: type(type: "0x2::balance::Balance<0x2::iota::IOTA>") { + abilities + } + + coin_vector: type(type: "vector<0x2::coin::Coin<0x2::iota::IOTA>>") { + abilities + } + + prim_vector: type(type: "vector") { + abilities + } +} + +//# run-graphql +# Unhappy path, type arguments too deep. + +{ + type(type: """ + vector + >>>> + >>>> + >>>> + >>>> + """) { + abilities + } +} + +//# publish +module P0::m { + public struct S0 { + xs: vector>>> + >>>> + } + + public struct S1 { + xss: S0>>>>>>> + >>>>>>>> + } +} + +//# create-checkpoint + +//# run-graphql + +# Unhappy path, value nesting too deep. + +{ + type(type: "@{P0}::m::S1") { + layout + } +} diff --git a/crates/iota-graphql-e2e-tests/tests/tests.rs b/crates/iota-graphql-e2e-tests/tests/tests.rs new file mode 100644 index 00000000000..2b09d277d35 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/tests.rs @@ -0,0 +1,24 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#![allow(unused_imports)] +#![allow(unused_variables)] +use std::{path::Path, sync::Arc}; + +use iota_transactional_test_runner::{ + run_test_impl, + test_adapter::{IotaTestAdapter, PRE_COMPILED}, +}; +pub const TEST_DIR: &str = "tests"; + +datatest_stable::harness!(run_test, TEST_DIR, r".*\.(mvir|move)$"); + +#[cfg_attr(not(msim), tokio::main)] +#[cfg_attr(msim, msim::main)] +async fn run_test(path: &Path) -> Result<(), Box> { + if cfg!(feature = "pg_integration") { + run_test_impl::(path, Some(Arc::new(PRE_COMPILED.clone()))).await?; + } + Ok(()) +} diff --git a/crates/sui-graphql-e2e-tests/tests/transaction_block_effects/balance_changes.exp b/crates/iota-graphql-e2e-tests/tests/transaction_block_effects/balance_changes.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/transaction_block_effects/balance_changes.exp rename to crates/iota-graphql-e2e-tests/tests/transaction_block_effects/balance_changes.exp diff --git a/crates/sui-graphql-e2e-tests/tests/transaction_block_effects/balance_changes.move b/crates/iota-graphql-e2e-tests/tests/transaction_block_effects/balance_changes.move similarity index 97% rename from crates/sui-graphql-e2e-tests/tests/transaction_block_effects/balance_changes.move rename to crates/iota-graphql-e2e-tests/tests/transaction_block_effects/balance_changes.move index 33e9664ae39..4d907d32482 100644 --- a/crates/sui-graphql-e2e-tests/tests/transaction_block_effects/balance_changes.move +++ b/crates/iota-graphql-e2e-tests/tests/transaction_block_effects/balance_changes.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --simulator --accounts C O P Q R S diff --git a/crates/sui-graphql-e2e-tests/tests/transaction_block_effects/dependencies.exp b/crates/iota-graphql-e2e-tests/tests/transaction_block_effects/dependencies.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/transaction_block_effects/dependencies.exp rename to crates/iota-graphql-e2e-tests/tests/transaction_block_effects/dependencies.exp diff --git a/crates/sui-graphql-e2e-tests/tests/transaction_block_effects/dependencies.move b/crates/iota-graphql-e2e-tests/tests/transaction_block_effects/dependencies.move similarity index 97% rename from crates/sui-graphql-e2e-tests/tests/transaction_block_effects/dependencies.move rename to crates/iota-graphql-e2e-tests/tests/transaction_block_effects/dependencies.move index 5819ff6db39..cbc34ac1458 100644 --- a/crates/sui-graphql-e2e-tests/tests/transaction_block_effects/dependencies.move +++ b/crates/iota-graphql-e2e-tests/tests/transaction_block_effects/dependencies.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses Test=0x0 --accounts A --simulator //# publish module Test::M1 { - use sui::coin::Coin; + use iota::coin::Coin; public struct Object has key, store { id: UID, diff --git a/crates/sui-graphql-e2e-tests/tests/transaction_block_effects/events.exp b/crates/iota-graphql-e2e-tests/tests/transaction_block_effects/events.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/transaction_block_effects/events.exp rename to crates/iota-graphql-e2e-tests/tests/transaction_block_effects/events.exp diff --git a/crates/sui-graphql-e2e-tests/tests/transaction_block_effects/events.move b/crates/iota-graphql-e2e-tests/tests/transaction_block_effects/events.move similarity index 96% rename from crates/sui-graphql-e2e-tests/tests/transaction_block_effects/events.move rename to crates/iota-graphql-e2e-tests/tests/transaction_block_effects/events.move index b13b2ebebad..261b57fb563 100644 --- a/crates/sui-graphql-e2e-tests/tests/transaction_block_effects/events.move +++ b/crates/iota-graphql-e2e-tests/tests/transaction_block_effects/events.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses Test=0x0 --accounts A --simulator //# publish module Test::M1 { - use sui::event; + use iota::event; public struct EventA has copy, drop { new_value: u64 diff --git a/crates/sui-graphql-e2e-tests/tests/transaction_block_effects/object_changes.exp b/crates/iota-graphql-e2e-tests/tests/transaction_block_effects/object_changes.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/transaction_block_effects/object_changes.exp rename to crates/iota-graphql-e2e-tests/tests/transaction_block_effects/object_changes.exp diff --git a/crates/sui-graphql-e2e-tests/tests/transaction_block_effects/object_changes.move b/crates/iota-graphql-e2e-tests/tests/transaction_block_effects/object_changes.move similarity index 94% rename from crates/sui-graphql-e2e-tests/tests/transaction_block_effects/object_changes.move rename to crates/iota-graphql-e2e-tests/tests/transaction_block_effects/object_changes.move index 2180e367979..46c282b27e5 100644 --- a/crates/sui-graphql-e2e-tests/tests/transaction_block_effects/object_changes.move +++ b/crates/iota-graphql-e2e-tests/tests/transaction_block_effects/object_changes.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses Test=0x0 A=0x42 --simulator --custom-validator-account --reference-gas-price 234 --default-gas-price 1000 //# publish module Test::M1 { - use sui::coin::Coin; + use iota::coin::Coin; public struct Object has key, store { id: UID, diff --git a/crates/sui-graphql-e2e-tests/tests/transactions/errors.exp b/crates/iota-graphql-e2e-tests/tests/transactions/errors.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/transactions/errors.exp rename to crates/iota-graphql-e2e-tests/tests/transactions/errors.exp diff --git a/crates/sui-graphql-e2e-tests/tests/transactions/errors.move b/crates/iota-graphql-e2e-tests/tests/transactions/errors.move similarity index 94% rename from crates/sui-graphql-e2e-tests/tests/transactions/errors.move rename to crates/iota-graphql-e2e-tests/tests/transactions/errors.move index cb40254b923..fe92feac9fb 100644 --- a/crates/sui-graphql-e2e-tests/tests/transactions/errors.move +++ b/crates/iota-graphql-e2e-tests/tests/transactions/errors.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses P0=0x0 --simulator diff --git a/crates/sui-graphql-e2e-tests/tests/transactions/programmable.exp b/crates/iota-graphql-e2e-tests/tests/transactions/programmable.exp similarity index 99% rename from crates/sui-graphql-e2e-tests/tests/transactions/programmable.exp rename to crates/iota-graphql-e2e-tests/tests/transactions/programmable.exp index 82acef515ef..db9266a52ba 100644 --- a/crates/sui-graphql-e2e-tests/tests/transactions/programmable.exp +++ b/crates/iota-graphql-e2e-tests/tests/transactions/programmable.exp @@ -105,7 +105,7 @@ Response: { }, "amount": "-7315600", "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" } } ] @@ -376,7 +376,7 @@ Response: { }, "amount": "-4993420", "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" } } ] @@ -737,7 +737,7 @@ Response: { }, "amount": "-3350680", "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" } } ] @@ -754,7 +754,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" }, "json": { "id": "0x53c79d532087139271df73b4965b68722ae3e08b4a101978656af65caa603162", @@ -799,7 +799,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" }, "json": { "id": "0xc4c6a5cf9165265a2ed5613c18c32ac123398077d14f7c188fd24115f70ba08a", @@ -928,7 +928,7 @@ Response: { }, "amount": "-1009880", "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" } } ] diff --git a/crates/sui-graphql-e2e-tests/tests/transactions/programmable.move b/crates/iota-graphql-e2e-tests/tests/transactions/programmable.move similarity index 99% rename from crates/sui-graphql-e2e-tests/tests/transactions/programmable.move rename to crates/iota-graphql-e2e-tests/tests/transactions/programmable.move index eb0b294bc0e..51b2a1afbc3 100644 --- a/crates/sui-graphql-e2e-tests/tests/transactions/programmable.move +++ b/crates/iota-graphql-e2e-tests/tests/transactions/programmable.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --addresses P0=0x0 P1=0x0 --accounts A --simulator @@ -401,7 +402,7 @@ fragment ComprehensivePTB on ProgrammableTransactionBlock { //# programmable --sender A --inputs 41u64 @A //> 0: MakeMoveVec([Input(0)]); //> 1: P0::m::new(Result(0)); -//> sui::transfer::public_transfer(Result(1), Input(1)) +//> iota::transfer::public_transfer(Result(1), Input(1)) //# programmable --sender A --inputs 42u64 43u64 1000 @A //> 0: MakeMoveVec([Input(0), Input(1)]); diff --git a/crates/sui-graphql-e2e-tests/tests/transactions/random.exp b/crates/iota-graphql-e2e-tests/tests/transactions/random.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/transactions/random.exp rename to crates/iota-graphql-e2e-tests/tests/transactions/random.exp diff --git a/crates/iota-graphql-e2e-tests/tests/transactions/random.move b/crates/iota-graphql-e2e-tests/tests/transactions/random.move new file mode 100644 index 00000000000..daa789ceda8 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/transactions/random.move @@ -0,0 +1,70 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --protocol-version 39 --simulator + +//# create-checkpoint + +//# advance-epoch --create-random-state + +//# run-graphql +# Make sure the randomness state was created on the epoch boundary +{ + epoch { + protocolConfigs { + protocolVersion + randomBeacon: featureFlag(key: "random_beacon") { value } + } + } + + object(address: "0x8") { + address + version + asMoveObject { + contents { + type { repr } + json + } + } + } + + transactionBlocks(last: 1) { + nodes { + kind { + __typename + ... on EndOfEpochTransaction { + transactions { + edges { + cursor + node { __typename } + } + } + } + } + } + } +} + + +//# set-random-state --randomness-round 0 --random-bytes SGVsbG8gU3Vp --randomness-initial-version 2 +# Set the contents of the randomness object + +//# create-checkpoint + +//# run-graphql +{ + transactionBlocks(last: 1) { + nodes { + kind { + __typename + ... on RandomnessStateUpdateTransaction { + epoch { epochId } + randomnessRound + randomBytes + randomnessObjInitialSharedVersion + } + } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/transactions/shared.exp b/crates/iota-graphql-e2e-tests/tests/transactions/shared.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/transactions/shared.exp rename to crates/iota-graphql-e2e-tests/tests/transactions/shared.exp diff --git a/crates/iota-graphql-e2e-tests/tests/transactions/shared.move b/crates/iota-graphql-e2e-tests/tests/transactions/shared.move new file mode 100644 index 00000000000..324c662b0a6 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/transactions/shared.move @@ -0,0 +1,85 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# init --protocol-version 39 --addresses P0=0x0 --simulator + +//# publish +module P0::m { + public struct Foo has key { + id: UID, + x: u64, + } + + fun init(ctx: &mut TxContext) { + transfer::share_object(Foo { + id: object::new(ctx), + x: 0, + }) + } + + public fun get(f: &Foo): u64 { f.x } + public fun inc(f: &mut Foo) { f.x = f.x + 1 } +} + +//# programmable --inputs immshared(1,0) +//> 0: P0::m::get(Input(0)) + +//# programmable --inputs object(1,0) +//> 0: P0::m::inc(Input(0)) + +//# programmable --inputs object(1,0) +//> 0: P0::m::get(Input(0)); +//> P0::m::inc(Input(0)) + +//# create-checkpoint + +//# run-graphql +{ + transactionBlocks(last: 3) { + nodes { + kind { + __typename + ... on ProgrammableTransactionBlock { + transactions { + nodes { + ... on MoveCallTransaction { + package + module + functionName + } + } + } + } + } + effects { + status + unchangedSharedObjects { + nodes { + __typename + ... on SharedObjectRead { + address + version + digest + object { + asMoveObject { + contents { + type { + repr + } + json + } + } + } + } + ... on SharedObjectDelete { + address + version + mutable + } + } + } + } + } + } +} diff --git a/crates/sui-graphql-e2e-tests/tests/transactions/system.exp b/crates/iota-graphql-e2e-tests/tests/transactions/system.exp similarity index 98% rename from crates/sui-graphql-e2e-tests/tests/transactions/system.exp rename to crates/iota-graphql-e2e-tests/tests/transactions/system.exp index 41c6d043fb0..662474ff049 100644 --- a/crates/sui-graphql-e2e-tests/tests/transactions/system.exp +++ b/crates/iota-graphql-e2e-tests/tests/transactions/system.exp @@ -272,13 +272,13 @@ Response: { { "cursor": "eyJuIjoic3VpX3N5c3RlbSIsImMiOjB9", "node": { - "name": "sui_system" + "name": "iota_system" } }, { "cursor": "eyJuIjoic3VpX3N5c3RlbV9zdGF0ZV9pbm5lciIsImMiOjB9", "node": { - "name": "sui_system_state_inner" + "name": "iota_system_state_inner" } }, { @@ -323,7 +323,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000003::sui_system::SuiSystemState" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000003::iota_system::IotaSystemState" }, "json": { "id": "0x0000000000000000000000000000000000000000000000000000000000000005", @@ -492,7 +492,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000003::staking_pool::StakedSui" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000003::staking_pool::StakedIota" }, "json": { "id": "0x4750aa886c991cf107dcdfd71b83fa09c859ba8e4aebf9157a748af9c7263c38", @@ -514,7 +514,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field" }, "json": { "id": "0x6af2a2b7ca60bf76174adfd3e9c4957f8e937759603182f9b46c7f6c5f19c6d2", @@ -528,7 +528,7 @@ Response: { "active_validators": [ { "metadata": { - "sui_address": "0xa7b032703878aa74c3126935789fd1d4d7e111d5911b09247d6963061c312b5a", + "iota_address": "0xa7b032703878aa74c3126935789fd1d4d7e111d5911b09247d6963061c312b5a", "protocol_pubkey_bytes": [ 168, 10, @@ -777,7 +777,7 @@ Response: { "id": "0x551af56bdfa15c8686e27c8334811a91251ea6c8c30bb07c8fa9b4d8f8f59ed9", "activation_epoch": "0", "deactivation_epoch": null, - "sui_balance": "20000000000000000", + "iota_balance": "20000000000000000", "rewards_pool": { "value": "0" }, @@ -787,7 +787,7 @@ Response: { "size": "1" }, "pending_stake": "0", - "pending_total_sui_withdraw": "0", + "pending_total_iota_withdraw": "0", "pending_pool_token_withdraw": "0", "extra_fields": { "id": "0x0fd833ba0511b8a6a809bcc1a0cab4be16d29b206e66416ec21a9512353fd4dc", @@ -897,13 +897,13 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::CoinMetadata<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::CoinMetadata<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" }, "json": { "id": "0x7633bb5b398c05b9f3cb8cc1b7ccc344aea9788d53f8081ee970d005f878bbcd", "decimals": 9, - "name": "Sui", - "symbol": "SUI", + "name": "Iota", + "symbol": "IOTA", "description": "", "icon_url": null } @@ -948,7 +948,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" }, "json": { "id": "0xa28ed7ab1775cf6cfe48c43c4529f97ccb0cfce60c1df60e832ca37dd510cf02", @@ -974,7 +974,7 @@ Response: { "id": "0xa7355813f8fee03e2bd0a0c8a26132051725850ca73f5b47fe6141c8695a6e41", "name": "0", "value": { - "sui_amount": "0", + "iota_amount": "0", "pool_token_amount": "0" } } @@ -1055,7 +1055,7 @@ Response: { "asMoveObject": { "contents": { "type": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" }, "json": { "id": "0xf6bda57832c0f4d6dea22862187bc6c3786744d36e7ca288fc67ddd5d37e1a91", @@ -1086,7 +1086,7 @@ Response: { }, "amount": "30000000000000000", "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" } }, { @@ -1095,7 +1095,7 @@ Response: { }, "amount": "300000000000000", "coinType": { - "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI" + "repr": "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" } } ] diff --git a/crates/sui-graphql-e2e-tests/tests/transactions/system.move b/crates/iota-graphql-e2e-tests/tests/transactions/system.move similarity index 99% rename from crates/sui-graphql-e2e-tests/tests/transactions/system.move rename to crates/iota-graphql-e2e-tests/tests/transactions/system.move index 08e34ed5576..953882bf3c7 100644 --- a/crates/sui-graphql-e2e-tests/tests/transactions/system.move +++ b/crates/iota-graphql-e2e-tests/tests/transactions/system.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# init --protocol-version 39 --simulator diff --git a/crates/sui-graphql-e2e-tests/tests/validator/validator.exp b/crates/iota-graphql-e2e-tests/tests/validator/validator.exp similarity index 100% rename from crates/sui-graphql-e2e-tests/tests/validator/validator.exp rename to crates/iota-graphql-e2e-tests/tests/validator/validator.exp diff --git a/crates/iota-graphql-e2e-tests/tests/validator/validator.move b/crates/iota-graphql-e2e-tests/tests/validator/validator.move new file mode 100644 index 00000000000..82b91af20b4 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/tests/validator/validator.move @@ -0,0 +1,119 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// Test the change of APY with heavy transactions + +//# init --protocol-version 39 --simulator --accounts A --addresses P0=0x0 + +//# advance-epoch + +//# create-checkpoint + +//# publish --sender A --gas-budget 9999999999 +module P0::m { + public struct Big has key, store { + id: UID, + weight: vector, + } + + fun weight(): vector { + let mut i = 0; + let mut v = vector[]; + while (i < 248 * 1024) { + vector::push_back(&mut v, 42); + i = i + 1; + }; + v + } + + public entry fun new(ctx: &mut TxContext){ + let id = object::new(ctx); + let w = weight(); + iota::transfer::public_transfer( + Big { id, weight: w }, + ctx.sender() + ) + } +} + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# create-checkpoint + +//# advance-epoch + +//# run-graphql +{ + epoch(id: 1) { + validatorSet { + activeValidators { + nodes { + apy + name + } + } + } + } +} + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# run P0::m::new --sender A + +//# create-checkpoint + +//# advance-epoch + +// check the epoch metrics + +//# run-graphql +{ + epoch(id: 2) { + validatorSet { + activeValidators { + nodes { + apy + name + reportRecords { + nodes { + address + } + } + } + } + } + } +} diff --git a/crates/iota-graphql-rpc-client/Cargo.toml b/crates/iota-graphql-rpc-client/Cargo.toml new file mode 100644 index 00000000000..9e97c730a1b --- /dev/null +++ b/crates/iota-graphql-rpc-client/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "iota-graphql-rpc-client" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +async-graphql = {workspace = true, features = ["dataloader", "apollo_tracing", "tracing", "opentelemetry"] } +axum.workspace = true +hyper.workspace = true +reqwest.workspace = true +serde_json.workspace = true +iota-graphql-rpc-headers.workspace = true +thiserror.workspace = true diff --git a/crates/iota-graphql-rpc-client/src/lib.rs b/crates/iota-graphql-rpc-client/src/lib.rs new file mode 100644 index 00000000000..4f42f044a63 --- /dev/null +++ b/crates/iota-graphql-rpc-client/src/lib.rs @@ -0,0 +1,51 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_graphql::Value; +use hyper::header::ToStrError; +use serde_json::Number; + +pub mod response; +pub mod simple_client; + +#[derive(Debug, thiserror::Error)] +pub enum ClientError { + #[error("Service version header not found")] + ServiceVersionHeaderNotFound, + #[error("Service version header value invalid string: {error}")] + ServiceVersionHeaderValueInvalidString { error: ToStrError }, + #[error("Invalid usage number for {usage_name}: {usage_number}")] + InvalidUsageNumber { + usage_name: String, + usage_number: Number, + }, + #[error("Invalid usage field for {usage_name}: {usage_value}")] + InvalidUsageValue { + usage_name: String, + usage_value: Value, + }, + #[error("{item_type} at pos {idx} must not be empty")] + InvalidEmptyItem { item_type: String, idx: usize }, + #[error( + "Invalid variable name: `{var_name}`. Variable names must be non-empty and start with a letter or underscore, and may only contain letters, digits, and underscores." + )] + InvalidVariableName { var_name: String }, + + #[error( + "Conflicting type definitions for variable {var_name}: {var_type_prev} vs {var_type_curr}" + )] + VariableDefinitionConflict { + var_name: String, + var_type_prev: String, + var_type_curr: String, + }, + #[error("Conflicting values for variable {var_name}: {var_val_prev} vs {var_val_curr}")] + VariableValueConflict { + var_name: String, + var_val_prev: serde_json::Value, + var_val_curr: serde_json::Value, + }, + #[error(transparent)] + InnerClientError(#[from] reqwest::Error), +} diff --git a/crates/iota-graphql-rpc-client/src/response.rs b/crates/iota-graphql-rpc-client/src/response.rs new file mode 100644 index 00000000000..d39663827ac --- /dev/null +++ b/crates/iota-graphql-rpc-client/src/response.rs @@ -0,0 +1,114 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::BTreeMap, net::SocketAddr}; + +use async_graphql::{Response, ServerError, Value}; +use axum::http::HeaderName; +use hyper::HeaderMap; +use iota_graphql_rpc_headers::VERSION_HEADER; +use reqwest::Response as ReqwestResponse; +use serde_json::json; + +use super::ClientError; + +#[derive(Debug)] +pub struct GraphqlResponse { + headers: HeaderMap, + remote_address: Option, + http_version: hyper::Version, + status: hyper::StatusCode, + full_response: Response, +} + +impl GraphqlResponse { + pub async fn from_resp(resp: ReqwestResponse) -> Result { + let headers = resp.headers().clone(); + let remote_address = resp.remote_addr(); + let http_version = resp.version(); + let status = resp.status(); + let full_response: Response = resp.json().await.map_err(ClientError::InnerClientError)?; + + Ok(Self { + headers, + remote_address, + http_version, + status, + full_response, + }) + } + + pub fn graphql_version(&self) -> Result { + Ok(self + .headers + .get(&VERSION_HEADER) + .ok_or(ClientError::ServiceVersionHeaderNotFound)? + .to_str() + .map_err(|e| ClientError::ServiceVersionHeaderValueInvalidString { error: e })? + .to_string()) + } + + pub fn response_body(&self) -> &Response { + &self.full_response + } + + pub fn response_body_json(&self) -> serde_json::Value { + json!(self.full_response) + } + + pub fn response_body_json_pretty(&self) -> String { + serde_json::to_string_pretty(&self.full_response).unwrap() + } + + pub fn http_status(&self) -> hyper::StatusCode { + self.status + } + + pub fn http_version(&self) -> hyper::Version { + self.http_version + } + + pub fn http_headers(&self) -> HeaderMap { + self.headers.clone() + } + + /// Returns the HTTP headers without the `Date` header. + /// The `Date` header is removed because it is not deterministic. + pub fn http_headers_without_date(&self) -> HeaderMap { + let mut headers = self.http_headers().clone(); + headers.remove(HeaderName::from_static("date")); + headers + } + + pub fn remote_address(&self) -> Option { + self.remote_address + } + + pub fn errors(&self) -> Vec { + self.full_response.errors.clone() + } + + pub fn usage(&self) -> Result>, ClientError> { + Ok(match self.full_response.extensions.get("usage").cloned() { + Some(Value::Object(obj)) => Some( + obj.into_iter() + .map(|(k, v)| match v { + Value::Number(n) => { + n.as_u64().ok_or(ClientError::InvalidUsageNumber { + usage_name: k.to_string(), + usage_number: n, + }) + } + .map(|q| (k.to_string(), q)), + _ => Err(ClientError::InvalidUsageValue { + usage_name: k.to_string(), + usage_value: v, + }), + }) + .collect::, ClientError>>()?, + ), + _ => None, + }) + } +} diff --git a/crates/sui-graphql-rpc-client/src/simple_client.rs b/crates/iota-graphql-rpc-client/src/simple_client.rs similarity index 98% rename from crates/sui-graphql-rpc-client/src/simple_client.rs rename to crates/iota-graphql-rpc-client/src/simple_client.rs index cbe8b58c6f3..bbec4eddb23 100644 --- a/crates/sui-graphql-rpc-client/src/simple_client.rs +++ b/crates/iota-graphql-rpc-client/src/simple_client.rs @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeMap; use axum::http::HeaderValue; use hyper::header; +use iota_graphql_rpc_headers::LIMITS_HEADER; use reqwest::Response; use serde_json::Value; -use sui_graphql_rpc_headers::LIMITS_HEADER; use super::response::GraphqlResponse; use crate::ClientError; diff --git a/crates/iota-graphql-rpc-headers/Cargo.toml b/crates/iota-graphql-rpc-headers/Cargo.toml new file mode 100644 index 00000000000..7c5f95e3f0b --- /dev/null +++ b/crates/iota-graphql-rpc-headers/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "iota-graphql-rpc-headers" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +axum.workspace = true diff --git a/crates/iota-graphql-rpc-headers/src/lib.rs b/crates/iota-graphql-rpc-headers/src/lib.rs new file mode 100644 index 00000000000..9db1923605f --- /dev/null +++ b/crates/iota-graphql-rpc-headers/src/lib.rs @@ -0,0 +1,8 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use axum::http::HeaderName; + +pub static VERSION_HEADER: HeaderName = HeaderName::from_static("x-iota-rpc-version"); +pub static LIMITS_HEADER: HeaderName = HeaderName::from_static("x-iota-rpc-show-usage"); diff --git a/crates/iota-graphql-rpc/Cargo.toml b/crates/iota-graphql-rpc/Cargo.toml new file mode 100644 index 00000000000..2995bd63fcd --- /dev/null +++ b/crates/iota-graphql-rpc/Cargo.toml @@ -0,0 +1,92 @@ +[package] +name = "iota-graphql-rpc" +version = "2024.2.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + + +[dependencies] +anyhow.workspace = true +async-graphql = {workspace = true, features = ["dataloader", "apollo_tracing", "tracing", "opentelemetry"] } +async-graphql-axum.workspace = true +async-graphql-value.workspace = true +async-trait.workspace = true +axum.workspace = true +chrono.workspace = true +clap.workspace = true +const-str.workspace = true +diesel.workspace = true +either.workspace = true +fastcrypto = { workspace = true, features = ["copy_key"] } +fastcrypto-zkp.workspace = true +futures.workspace = true +git-version.workspace = true +hex.workspace = true +http.workspace = true +hyper.workspace = true +lru.workspace = true +move-binary-format.workspace = true +move-disassembler.workspace = true +move-ir-types.workspace = true +markdown-gen.workspace = true +mysten-metrics.workspace = true +mysten-network.workspace = true +move-core-types.workspace = true +once_cell.workspace = true +prometheus.workspace = true +rand.workspace = true # todo: cleanup test only deps +regex.workspace = true +reqwest.workspace = true +serial_test.workspace = true +serde.workspace = true +serde_json.workspace = true +serde_with.workspace = true +serde_yaml.workspace = true +shared-crypto.workspace = true +similar.workspace = true +iota-sdk.workspace = true +iota-types.workspace = true +tap.workspace = true +telemetry-subscribers.workspace = true +tracing.workspace = true +tokio = { workspace = true, features = ["rt-multi-thread"] } +tokio-util = { workspace = true, features = ["rt"] } +toml.workspace = true +tower.workspace = true +tower-http.workspace = true +thiserror.workspace = true +uuid.workspace = true +im.workspace = true + +iota-graphql-rpc-headers.workspace = true +iota-graphql-rpc-client.workspace = true + + +# TODO: put these behind feature flag to prevent leakage +# Used for dummy data +bcs.workspace = true +simulacrum.workspace = true # todo: cleanup test only deps +iota-json-rpc.workspace = true +iota-json-rpc-types.workspace = true +iota-indexer.workspace = true +iota-rest-api.workspace = true +iota-swarm-config.workspace = true +test-cluster.workspace = true +iota-protocol-config.workspace = true +move-bytecode-utils.workspace = true +iota-package-resolver.workspace = true + +[dev-dependencies] +expect-test.workspace = true +hyper.workspace = true +insta.workspace = true +serde_json.workspace = true +iota-framework.workspace = true +tower.workspace = true + +[features] +default = ["pg_backend"] +pg_integration = [] +pg_backend = [] diff --git a/crates/iota-graphql-rpc/README.md b/crates/iota-graphql-rpc/README.md new file mode 100644 index 00000000000..df4c4a86287 --- /dev/null +++ b/crates/iota-graphql-rpc/README.md @@ -0,0 +1,73 @@ +# iota-graphql-rpc + +## Dev setup +Note that we use compilation flags to determine the backend for Diesel. If you're using VS Code, make sure to update settings.json with the appropriate features - there should at least be a "pg_backend" (or other backend.) +``` +"rust-analyzer.cargo.features": ["pg_backend"] +``` +Consequently, you'll also need to specify the backend when running cargo commands: +```cargo run --features "pg_backend" --bin iota-graphql-rpc start-server --db-url ``` + +The order is important: +1. --features "pg_backend": This part tells Cargo to enable the pg_backend feature. +2. --bin iota-graphql-rpc: This specifies which binary to run. +3. start-server --db-url: These are arguments to the binary. + +## Spinning up locally + +### Setting up local db + +The graphql service is backed by a db based on the db schema in [iota-indexer](../iota-indexer/src/schema.rs). To spin up a local db, follow the instructions at [iota-indexer](../iota-indexer/README.md) until "Running standalone indexer". + +If you have not created a db yet, you can do so as follows: +```sh +psql -U postgres +CREATE DATABASE iota_indexer_v2; +``` + +You should be able to refer to the db url now: +`psql postgres://postgres:postgrespw@localhost:5432/iota_indexer_v2` + +With the new db, run the following commands (also under `iota/crates/iota-indexer`): + +```sh +diesel setup --database-url="" --migration-dir=migrations +diesel migration run --database-url="" --migration-dir=migrations +``` + +### Launching the server +See [src/commands.rs](src/commands.rs) for all CLI options. + +Example `.toml` config: +```toml +[limits] +max-query-depth = 15 +max-query-nodes = 500 +max-output-nodes = 100000 +max-query-payload-size = 5000 +max-db-query-cost = 20000 +default-page-size = 5 +max-page-size = 10 +request-timeout-ms = 15000 +max-type-argument-depth = 16 +max-type-argument-width = 32 +max-type-nodes = 256 +max-move-value-depth = 128 + +[background-tasks] +watermark-update-ms=500 +``` + +This will build iota-graphql-rpc and start an IDE: +``` +cargo run --bin iota-graphql-rpc start-server [--rpc-url] [--db-url] [--port] [--host] [--config] +``` + +### Launching the server w/ indexer +For local dev, it might be useful to spin up an indexer as well. Instructions are at [Running standalone indexer](../iota-indexer/README.md#running-standalone-indexer). + +## Compatibility with json-rpc + +`cargo run --bin iota-test-validator -- --with-indexer --pg-port 5432 --pg-db-name iota_indexer_v2 --graphql-host 127.0.0.1 --graphql-port 9125` + +`pnpm --filter @iota/graphql-transport test:e2e` diff --git a/crates/sui-graphql-rpc/docs/examples.md b/crates/iota-graphql-rpc/docs/examples.md similarity index 97% rename from crates/sui-graphql-rpc/docs/examples.md rename to crates/iota-graphql-rpc/docs/examples.md index b2276651311..e04cf3a81cf 100644 --- a/crates/sui-graphql-rpc/docs/examples.md +++ b/crates/iota-graphql-rpc/docs/examples.md @@ -1,4 +1,4 @@ -# Sui GraphQL Examples +# Iota GraphQL Examples ### [Address](#0) ####   [Address](#0) ####   [Transaction Block Connection](#1) @@ -56,8 +56,8 @@ ####   [Service Config](#917490) ### [Stake Connection](#15) ####   [Stake Connection](#983025) -### [Sui System State Summary](#16) -####   [Sui System State Summary](#1048560) +### [Iota System State Summary](#16) +####   [Iota System State Summary](#1048560) ### [Transaction Block](#17) ####   [Transaction Block](#1114095) ####   [Transaction Block Kind](#1114096) @@ -468,7 +468,7 @@ ### Coin Metadata >
    query CoinMetadata {
    ->  coinMetadata(coinType: "0x2::sui::SUI") {
    +>  coinMetadata(coinType: "0x2::iota::IOTA") {
     >    decimals
     >    name
     >    symbol
    @@ -529,11 +529,11 @@
     >          }
     >          exchangeRatesSize
     >          stakingPoolActivationEpoch
    ->          stakingPoolSuiBalance
    +>          stakingPoolIotaBalance
     >          rewardsPool
     >          poolTokenBalance
     >          pendingStake
    ->          pendingTotalSuiWithdraw
    +>          pendingTotalIotaWithdraw
     >          pendingPoolTokenWithdraw
     >          votingPower
     >          gasPrice
    @@ -662,7 +662,7 @@
     >
    {
     >  events(
     >    filter: {
    ->      eventType: "0x3164fcf73eb6b41ff3d2129346141bd68469964c2d95a5b1533e8d16e6ea6e13::Market::ChangePriceEvent<0x2::sui::SUI>"
    +>      eventType: "0x3164fcf73eb6b41ff3d2129346141bd68469964c2d95a5b1533e8d16e6ea6e13::Market::ChangePriceEvent<0x2::iota::IOTA>"
     >    }
     >  ) {
     >    nodes {
    @@ -691,7 +691,7 @@
     >    first: 1
     >    after: "eyJ0eCI6Njc2MywiZSI6MCwiYyI6MjI4MDA3NDJ9"
     >    filter: {
    ->      emittingModule: "0x3::sui_system",
    +>      emittingModule: "0x3::iota_system",
     >      eventType: "0x3::validator::StakingRequestEvent"
     >    }
     >  ) {
    @@ -753,21 +753,21 @@
     ### Name Service
     
     >
    {
    ->  resolveSuinsAddress(domain: "example.sui") {
    +>  resolveIotansAddress(domain: "example.iota") {
     >    address
     >  }
     >  address(
     >    address: "0x0b86be5d779fac217b41d484b8040ad5145dc9ba0cba099d083c6cbda50d983e"
     >  ) {
     >    address
    ->    balance(type: "0x2::sui::SUI") {
    +>    balance(type: "0x2::iota::IOTA") {
     >      coinType {
     >        repr
     >      }
     >      coinObjectCount
     >      totalBalance
     >    }
    ->    defaultSuinsName
    +>    defaultIotansName
     >  }
     >}
    @@ -865,7 +865,7 @@ ### Filter On Type >
    {
    ->  objects(filter: {type: "0x3::staking_pool::StakedSui"}) {
    +>  objects(filter: {type: "0x3::staking_pool::StakedIota"}) {
     >    edges {
     >      node {
     >        asMoveObject {
    @@ -925,7 +925,7 @@
     >      storageRebate
     >      previousTransactionBlock {
     >        digest
    ->        sender { defaultSuinsName }
    +>        sender { defaultIotansName }
     >        gasInput {
     >          gasPrice
     >          gasBudget
    @@ -1199,13 +1199,13 @@
     >    address: "0xc0a5b916d0e406ddde11a29558cd91b29c49e644eef597b7424a622955280e1e"
     >  ) {
     >    address
    ->    balance(type: "0x2::sui::SUI") {
    +>    balance(type: "0x2::iota::IOTA") {
     >      coinType {
     >        repr
     >      }
     >      totalBalance
     >    }
    ->    stakedSuis {
    +>    stakedIotas {
     >      nodes {
     >        status
     >        principal
    @@ -1233,10 +1233,10 @@
     >}
    ## -## Sui System State Summary +## Iota System State Summary ### -### Sui System State Summary -#### Get the latest sui system state data +### Iota System State Summary +#### Get the latest iota system state data >
    {
     >  epoch {
    @@ -1471,7 +1471,7 @@
     >
    {
     >  transactionBlocks(
     >    filter: {
    ->      function: "0x3::sui_system"
    +>      function: "0x3::iota_system"
     >    }
     >  ) {
     >    nodes {
    @@ -1493,7 +1493,7 @@
     >
    {
     >  transactionBlocks(
     >    filter: {
    ->      function: "0x3::sui_system::request_withdraw_stake"
    +>      function: "0x3::iota_system::request_withdraw_stake"
     >    }
     >  ) {
     >    nodes {
    @@ -1674,7 +1674,7 @@
     >          nodes {
     >            owner {
     >              address
    ->              balance(type: "0x2::sui::SUI") {
    +>              balance(type: "0x2::iota::IOTA") {
     >                totalBalance
     >              }
     >            }
    diff --git a/crates/sui-graphql-rpc/examples/address/address.graphql b/crates/iota-graphql-rpc/examples/address/address.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/address/address.graphql
    rename to crates/iota-graphql-rpc/examples/address/address.graphql
    diff --git a/crates/sui-graphql-rpc/examples/address/transaction_block_connection.graphql b/crates/iota-graphql-rpc/examples/address/transaction_block_connection.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/address/transaction_block_connection.graphql
    rename to crates/iota-graphql-rpc/examples/address/transaction_block_connection.graphql
    diff --git a/crates/sui-graphql-rpc/examples/balance_connection/balance_connection.graphql b/crates/iota-graphql-rpc/examples/balance_connection/balance_connection.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/balance_connection/balance_connection.graphql
    rename to crates/iota-graphql-rpc/examples/balance_connection/balance_connection.graphql
    diff --git a/crates/sui-graphql-rpc/examples/chain_id/chain_id.graphql b/crates/iota-graphql-rpc/examples/chain_id/chain_id.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/chain_id/chain_id.graphql
    rename to crates/iota-graphql-rpc/examples/chain_id/chain_id.graphql
    diff --git a/crates/sui-graphql-rpc/examples/checkpoint/at_digest.graphql b/crates/iota-graphql-rpc/examples/checkpoint/at_digest.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/checkpoint/at_digest.graphql
    rename to crates/iota-graphql-rpc/examples/checkpoint/at_digest.graphql
    diff --git a/crates/sui-graphql-rpc/examples/checkpoint/at_seq_num.graphql b/crates/iota-graphql-rpc/examples/checkpoint/at_seq_num.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/checkpoint/at_seq_num.graphql
    rename to crates/iota-graphql-rpc/examples/checkpoint/at_seq_num.graphql
    diff --git a/crates/sui-graphql-rpc/examples/checkpoint/first_two_tx_blocks_for_checkpoint.graphql b/crates/iota-graphql-rpc/examples/checkpoint/first_two_tx_blocks_for_checkpoint.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/checkpoint/first_two_tx_blocks_for_checkpoint.graphql
    rename to crates/iota-graphql-rpc/examples/checkpoint/first_two_tx_blocks_for_checkpoint.graphql
    diff --git a/crates/sui-graphql-rpc/examples/checkpoint/latest_checkpoint.graphql b/crates/iota-graphql-rpc/examples/checkpoint/latest_checkpoint.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/checkpoint/latest_checkpoint.graphql
    rename to crates/iota-graphql-rpc/examples/checkpoint/latest_checkpoint.graphql
    diff --git a/crates/sui-graphql-rpc/examples/checkpoint/multiple_selections.graphql b/crates/iota-graphql-rpc/examples/checkpoint/multiple_selections.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/checkpoint/multiple_selections.graphql
    rename to crates/iota-graphql-rpc/examples/checkpoint/multiple_selections.graphql
    diff --git a/crates/sui-graphql-rpc/examples/checkpoint/with_timestamp_tx_block_live_objects.graphql b/crates/iota-graphql-rpc/examples/checkpoint/with_timestamp_tx_block_live_objects.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/checkpoint/with_timestamp_tx_block_live_objects.graphql
    rename to crates/iota-graphql-rpc/examples/checkpoint/with_timestamp_tx_block_live_objects.graphql
    diff --git a/crates/sui-graphql-rpc/examples/checkpoint/with_tx_sent_addr_filter.graphql b/crates/iota-graphql-rpc/examples/checkpoint/with_tx_sent_addr_filter.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/checkpoint/with_tx_sent_addr_filter.graphql
    rename to crates/iota-graphql-rpc/examples/checkpoint/with_tx_sent_addr_filter.graphql
    diff --git a/crates/sui-graphql-rpc/examples/checkpoint_connection/ascending_fetch.graphql b/crates/iota-graphql-rpc/examples/checkpoint_connection/ascending_fetch.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/checkpoint_connection/ascending_fetch.graphql
    rename to crates/iota-graphql-rpc/examples/checkpoint_connection/ascending_fetch.graphql
    diff --git a/crates/sui-graphql-rpc/examples/checkpoint_connection/first_ten_after_checkpoint.graphql b/crates/iota-graphql-rpc/examples/checkpoint_connection/first_ten_after_checkpoint.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/checkpoint_connection/first_ten_after_checkpoint.graphql
    rename to crates/iota-graphql-rpc/examples/checkpoint_connection/first_ten_after_checkpoint.graphql
    diff --git a/crates/sui-graphql-rpc/examples/checkpoint_connection/last_ten_after_checkpoint.graphql b/crates/iota-graphql-rpc/examples/checkpoint_connection/last_ten_after_checkpoint.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/checkpoint_connection/last_ten_after_checkpoint.graphql
    rename to crates/iota-graphql-rpc/examples/checkpoint_connection/last_ten_after_checkpoint.graphql
    diff --git a/crates/sui-graphql-rpc/examples/coin_connection/coin_connection.graphql b/crates/iota-graphql-rpc/examples/coin_connection/coin_connection.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/coin_connection/coin_connection.graphql
    rename to crates/iota-graphql-rpc/examples/coin_connection/coin_connection.graphql
    diff --git a/crates/iota-graphql-rpc/examples/coin_metadata/coin_metadata.graphql b/crates/iota-graphql-rpc/examples/coin_metadata/coin_metadata.graphql
    new file mode 100644
    index 00000000000..dd185d359a6
    --- /dev/null
    +++ b/crates/iota-graphql-rpc/examples/coin_metadata/coin_metadata.graphql
    @@ -0,0 +1,11 @@
    +query CoinMetadata {
    +  coinMetadata(coinType: "0x2::iota::IOTA") {
    +    decimals
    +    name
    +    symbol
    +    description
    +    iconUrl
    +    supply
    +    hasPublicTransfer
    +  }
    +}
    diff --git a/crates/sui-graphql-rpc/examples/epoch/latest_epoch.graphql b/crates/iota-graphql-rpc/examples/epoch/latest_epoch.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/epoch/latest_epoch.graphql
    rename to crates/iota-graphql-rpc/examples/epoch/latest_epoch.graphql
    diff --git a/crates/sui-graphql-rpc/examples/epoch/specific_epoch.graphql b/crates/iota-graphql-rpc/examples/epoch/specific_epoch.graphql
    similarity index 93%
    rename from crates/sui-graphql-rpc/examples/epoch/specific_epoch.graphql
    rename to crates/iota-graphql-rpc/examples/epoch/specific_epoch.graphql
    index 9b5b1a89f27..c83732c6f91 100644
    --- a/crates/sui-graphql-rpc/examples/epoch/specific_epoch.graphql
    +++ b/crates/iota-graphql-rpc/examples/epoch/specific_epoch.graphql
    @@ -27,11 +27,11 @@
               }
               exchangeRatesSize
               stakingPoolActivationEpoch
    -          stakingPoolSuiBalance
    +          stakingPoolIotaBalance
               rewardsPool
               poolTokenBalance
               pendingStake
    -          pendingTotalSuiWithdraw
    +          pendingTotalIotaWithdraw
               pendingPoolTokenWithdraw
               votingPower
               gasPrice
    diff --git a/crates/sui-graphql-rpc/examples/epoch/with_checkpoint_connection.graphql b/crates/iota-graphql-rpc/examples/epoch/with_checkpoint_connection.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/epoch/with_checkpoint_connection.graphql
    rename to crates/iota-graphql-rpc/examples/epoch/with_checkpoint_connection.graphql
    diff --git a/crates/sui-graphql-rpc/examples/epoch/with_tx_block_connection.graphql b/crates/iota-graphql-rpc/examples/epoch/with_tx_block_connection.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/epoch/with_tx_block_connection.graphql
    rename to crates/iota-graphql-rpc/examples/epoch/with_tx_block_connection.graphql
    diff --git a/crates/sui-graphql-rpc/examples/epoch/with_tx_block_connection_latest_epoch.graphql b/crates/iota-graphql-rpc/examples/epoch/with_tx_block_connection_latest_epoch.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/epoch/with_tx_block_connection_latest_epoch.graphql
    rename to crates/iota-graphql-rpc/examples/epoch/with_tx_block_connection_latest_epoch.graphql
    diff --git a/crates/sui-graphql-rpc/examples/event_connection/event_connection.graphql b/crates/iota-graphql-rpc/examples/event_connection/event_connection.graphql
    similarity index 82%
    rename from crates/sui-graphql-rpc/examples/event_connection/event_connection.graphql
    rename to crates/iota-graphql-rpc/examples/event_connection/event_connection.graphql
    index 5a9f5bae4d8..a637f4051fd 100644
    --- a/crates/sui-graphql-rpc/examples/event_connection/event_connection.graphql
    +++ b/crates/iota-graphql-rpc/examples/event_connection/event_connection.graphql
    @@ -1,7 +1,7 @@
     {
       events(
         filter: {
    -      eventType: "0x3164fcf73eb6b41ff3d2129346141bd68469964c2d95a5b1533e8d16e6ea6e13::Market::ChangePriceEvent<0x2::sui::SUI>"
    +      eventType: "0x3164fcf73eb6b41ff3d2129346141bd68469964c2d95a5b1533e8d16e6ea6e13::Market::ChangePriceEvent<0x2::iota::IOTA>"
         }
       ) {
         nodes {
    diff --git a/crates/sui-graphql-rpc/examples/event_connection/filter_by_emitting_package_module_and_event_type.graphql b/crates/iota-graphql-rpc/examples/event_connection/filter_by_emitting_package_module_and_event_type.graphql
    similarity index 91%
    rename from crates/sui-graphql-rpc/examples/event_connection/filter_by_emitting_package_module_and_event_type.graphql
    rename to crates/iota-graphql-rpc/examples/event_connection/filter_by_emitting_package_module_and_event_type.graphql
    index b1df6c65f06..7546bf8cc9b 100644
    --- a/crates/sui-graphql-rpc/examples/event_connection/filter_by_emitting_package_module_and_event_type.graphql
    +++ b/crates/iota-graphql-rpc/examples/event_connection/filter_by_emitting_package_module_and_event_type.graphql
    @@ -3,7 +3,7 @@ query ByEmittingPackageModuleAndEventType {
         first: 1
         after: "eyJ0eCI6Njc2MywiZSI6MCwiYyI6MjI4MDA3NDJ9"
         filter: {
    -      emittingModule: "0x3::sui_system",
    +      emittingModule: "0x3::iota_system",
           eventType: "0x3::validator::StakingRequestEvent"
         }
       ) {
    diff --git a/crates/sui-graphql-rpc/examples/event_connection/filter_by_sender.graphql b/crates/iota-graphql-rpc/examples/event_connection/filter_by_sender.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/event_connection/filter_by_sender.graphql
    rename to crates/iota-graphql-rpc/examples/event_connection/filter_by_sender.graphql
    diff --git a/crates/iota-graphql-rpc/examples/iota_system_state_summary/iota_system_state_summary.graphql b/crates/iota-graphql-rpc/examples/iota_system_state_summary/iota_system_state_summary.graphql
    new file mode 100644
    index 00000000000..4b0129b16ed
    --- /dev/null
    +++ b/crates/iota-graphql-rpc/examples/iota_system_state_summary/iota_system_state_summary.graphql
    @@ -0,0 +1,37 @@
    +# Get the latest iota system state data
    +{
    +  epoch {
    +    storageFund {
    +      totalObjectStorageRebates
    +      nonRefundableBalance
    +    }
    +    safeMode {
    +      enabled
    +      gasSummary {
    +         computationCost
    +         storageCost
    +         storageRebate
    +         nonRefundableStorageFee
    +      }
    +    }
    +    systemStateVersion
    +    systemParameters {
    +      durationMs
    +      stakeSubsidyStartEpoch
    +      minValidatorCount
    +      maxValidatorCount
    +      minValidatorJoiningStake
    +      validatorLowStakeThreshold
    +      validatorVeryLowStakeThreshold
    +      validatorLowStakeGracePeriod
    +    }
    +    systemStakeSubsidy {
    +      balance
    +      distributionCounter
    +      currentDistributionAmount
    +      periodLength
    +      decreaseRate
    +
    +    }
    +  }
    +}
    diff --git a/crates/iota-graphql-rpc/examples/name_service/name_service.graphql b/crates/iota-graphql-rpc/examples/name_service/name_service.graphql
    new file mode 100644
    index 00000000000..e9ea2546931
    --- /dev/null
    +++ b/crates/iota-graphql-rpc/examples/name_service/name_service.graphql
    @@ -0,0 +1,18 @@
    +{
    +  resolveIotansAddress(domain: "example.iota") {
    +    address
    +  }
    +  address(
    +    address: "0x0b86be5d779fac217b41d484b8040ad5145dc9ba0cba099d083c6cbda50d983e"
    +  ) {
    +    address
    +    balance(type: "0x2::iota::IOTA") {
    +      coinType {
    +        repr
    +      }
    +      coinObjectCount
    +      totalBalance
    +    }
    +    defaultIotansName
    +  }
    +}
    diff --git a/crates/sui-graphql-rpc/examples/object/object.graphql b/crates/iota-graphql-rpc/examples/object/object.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/object/object.graphql
    rename to crates/iota-graphql-rpc/examples/object/object.graphql
    diff --git a/crates/sui-graphql-rpc/examples/object_connection/filter_object_ids.graphql b/crates/iota-graphql-rpc/examples/object_connection/filter_object_ids.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/object_connection/filter_object_ids.graphql
    rename to crates/iota-graphql-rpc/examples/object_connection/filter_object_ids.graphql
    diff --git a/crates/sui-graphql-rpc/examples/object_connection/filter_on_generic_type.graphql b/crates/iota-graphql-rpc/examples/object_connection/filter_on_generic_type.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/object_connection/filter_on_generic_type.graphql
    rename to crates/iota-graphql-rpc/examples/object_connection/filter_on_generic_type.graphql
    diff --git a/crates/iota-graphql-rpc/examples/object_connection/filter_on_type.graphql b/crates/iota-graphql-rpc/examples/object_connection/filter_on_type.graphql
    new file mode 100644
    index 00000000000..18034f4789e
    --- /dev/null
    +++ b/crates/iota-graphql-rpc/examples/object_connection/filter_on_type.graphql
    @@ -0,0 +1,15 @@
    +{
    +  objects(filter: {type: "0x3::staking_pool::StakedIota"}) {
    +    edges {
    +      node {
    +        asMoveObject {
    +          contents {
    +            type {
    +              repr
    +            }
    +          }
    +        }
    +      }
    +    }
    +  }
    +}
    diff --git a/crates/sui-graphql-rpc/examples/object_connection/filter_owner.graphql b/crates/iota-graphql-rpc/examples/object_connection/filter_owner.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/object_connection/filter_owner.graphql
    rename to crates/iota-graphql-rpc/examples/object_connection/filter_owner.graphql
    diff --git a/crates/sui-graphql-rpc/examples/object_connection/object_connection.graphql b/crates/iota-graphql-rpc/examples/object_connection/object_connection.graphql
    similarity index 86%
    rename from crates/sui-graphql-rpc/examples/object_connection/object_connection.graphql
    rename to crates/iota-graphql-rpc/examples/object_connection/object_connection.graphql
    index 97714b54a72..d7537077588 100644
    --- a/crates/sui-graphql-rpc/examples/object_connection/object_connection.graphql
    +++ b/crates/iota-graphql-rpc/examples/object_connection/object_connection.graphql
    @@ -6,7 +6,7 @@
           storageRebate
           previousTransactionBlock {
             digest
    -        sender { defaultSuinsName }
    +        sender { defaultIotansName }
             gasInput {
               gasPrice
               gasBudget
    diff --git a/crates/sui-graphql-rpc/examples/owner/dynamic_field.graphql b/crates/iota-graphql-rpc/examples/owner/dynamic_field.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/owner/dynamic_field.graphql
    rename to crates/iota-graphql-rpc/examples/owner/dynamic_field.graphql
    diff --git a/crates/sui-graphql-rpc/examples/owner/dynamic_field_connection.graphql b/crates/iota-graphql-rpc/examples/owner/dynamic_field_connection.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/owner/dynamic_field_connection.graphql
    rename to crates/iota-graphql-rpc/examples/owner/dynamic_field_connection.graphql
    diff --git a/crates/sui-graphql-rpc/examples/owner/dynamic_object_field.graphql b/crates/iota-graphql-rpc/examples/owner/dynamic_object_field.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/owner/dynamic_object_field.graphql
    rename to crates/iota-graphql-rpc/examples/owner/dynamic_object_field.graphql
    diff --git a/crates/sui-graphql-rpc/examples/owner/owner.graphql b/crates/iota-graphql-rpc/examples/owner/owner.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/owner/owner.graphql
    rename to crates/iota-graphql-rpc/examples/owner/owner.graphql
    diff --git a/crates/sui-graphql-rpc/examples/protocol_configs/key_value.graphql b/crates/iota-graphql-rpc/examples/protocol_configs/key_value.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/protocol_configs/key_value.graphql
    rename to crates/iota-graphql-rpc/examples/protocol_configs/key_value.graphql
    diff --git a/crates/sui-graphql-rpc/examples/protocol_configs/key_value_feature_flag.graphql b/crates/iota-graphql-rpc/examples/protocol_configs/key_value_feature_flag.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/protocol_configs/key_value_feature_flag.graphql
    rename to crates/iota-graphql-rpc/examples/protocol_configs/key_value_feature_flag.graphql
    diff --git a/crates/sui-graphql-rpc/examples/protocol_configs/specific_config.graphql b/crates/iota-graphql-rpc/examples/protocol_configs/specific_config.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/protocol_configs/specific_config.graphql
    rename to crates/iota-graphql-rpc/examples/protocol_configs/specific_config.graphql
    diff --git a/crates/sui-graphql-rpc/examples/protocol_configs/specific_feature_flag.graphql b/crates/iota-graphql-rpc/examples/protocol_configs/specific_feature_flag.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/protocol_configs/specific_feature_flag.graphql
    rename to crates/iota-graphql-rpc/examples/protocol_configs/specific_feature_flag.graphql
    diff --git a/crates/sui-graphql-rpc/examples/service_config/service_config.graphql b/crates/iota-graphql-rpc/examples/service_config/service_config.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/service_config/service_config.graphql
    rename to crates/iota-graphql-rpc/examples/service_config/service_config.graphql
    diff --git a/crates/sui-graphql-rpc/examples/stake_connection/stake_connection.graphql b/crates/iota-graphql-rpc/examples/stake_connection/stake_connection.graphql
    similarity index 92%
    rename from crates/sui-graphql-rpc/examples/stake_connection/stake_connection.graphql
    rename to crates/iota-graphql-rpc/examples/stake_connection/stake_connection.graphql
    index e30ebf24f4a..8d798ec6bcf 100644
    --- a/crates/sui-graphql-rpc/examples/stake_connection/stake_connection.graphql
    +++ b/crates/iota-graphql-rpc/examples/stake_connection/stake_connection.graphql
    @@ -4,13 +4,13 @@
         address: "0xc0a5b916d0e406ddde11a29558cd91b29c49e644eef597b7424a622955280e1e"
       ) {
         address
    -    balance(type: "0x2::sui::SUI") {
    +    balance(type: "0x2::iota::IOTA") {
           coinType {
             repr
           }
           totalBalance
         }
    -    stakedSuis {
    +    stakedIotas {
           nodes {
             status
             principal
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block/transaction_block.graphql b/crates/iota-graphql-rpc/examples/transaction_block/transaction_block.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/transaction_block/transaction_block.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block/transaction_block.graphql
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block/transaction_block_kind.graphql b/crates/iota-graphql-rpc/examples/transaction_block/transaction_block_kind.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/transaction_block/transaction_block_kind.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block/transaction_block_kind.graphql
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block_connection/before_after_checkpoint.graphql b/crates/iota-graphql-rpc/examples/transaction_block_connection/before_after_checkpoint.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/transaction_block_connection/before_after_checkpoint.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block_connection/before_after_checkpoint.graphql
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block_connection/changed_object_filter.graphql b/crates/iota-graphql-rpc/examples/transaction_block_connection/changed_object_filter.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/transaction_block_connection/changed_object_filter.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block_connection/changed_object_filter.graphql
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block_connection/input_object_filter.graphql b/crates/iota-graphql-rpc/examples/transaction_block_connection/input_object_filter.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/transaction_block_connection/input_object_filter.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block_connection/input_object_filter.graphql
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block_connection/input_object_sign_addr_filter.graphql b/crates/iota-graphql-rpc/examples/transaction_block_connection/input_object_sign_addr_filter.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/transaction_block_connection/input_object_sign_addr_filter.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block_connection/input_object_sign_addr_filter.graphql
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block_connection/package_filter.graphql b/crates/iota-graphql-rpc/examples/transaction_block_connection/package_filter.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/transaction_block_connection/package_filter.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block_connection/package_filter.graphql
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block_connection/package_module_filter.graphql b/crates/iota-graphql-rpc/examples/transaction_block_connection/package_module_filter.graphql
    similarity index 85%
    rename from crates/sui-graphql-rpc/examples/transaction_block_connection/package_module_filter.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block_connection/package_module_filter.graphql
    index 3cc24c4e00d..34a1ed4a425 100644
    --- a/crates/sui-graphql-rpc/examples/transaction_block_connection/package_module_filter.graphql
    +++ b/crates/iota-graphql-rpc/examples/transaction_block_connection/package_module_filter.graphql
    @@ -2,7 +2,7 @@
     {
       transactionBlocks(
         filter: {
    -      function: "0x3::sui_system"
    +      function: "0x3::iota_system"
         }
       ) {
         nodes {
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block_connection/package_module_func_filter.graphql b/crates/iota-graphql-rpc/examples/transaction_block_connection/package_module_func_filter.graphql
    similarity index 78%
    rename from crates/sui-graphql-rpc/examples/transaction_block_connection/package_module_func_filter.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block_connection/package_module_func_filter.graphql
    index 11bdb384d85..69ec94555ee 100644
    --- a/crates/sui-graphql-rpc/examples/transaction_block_connection/package_module_func_filter.graphql
    +++ b/crates/iota-graphql-rpc/examples/transaction_block_connection/package_module_func_filter.graphql
    @@ -2,7 +2,7 @@
     {
       transactionBlocks(
         filter: {
    -      function: "0x3::sui_system::request_withdraw_stake"
    +      function: "0x3::iota_system::request_withdraw_stake"
         }
       ) {
         nodes {
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block_connection/recv_addr_filter.graphql b/crates/iota-graphql-rpc/examples/transaction_block_connection/recv_addr_filter.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/transaction_block_connection/recv_addr_filter.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block_connection/recv_addr_filter.graphql
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block_connection/sign_addr_filter.graphql b/crates/iota-graphql-rpc/examples/transaction_block_connection/sign_addr_filter.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/transaction_block_connection/sign_addr_filter.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block_connection/sign_addr_filter.graphql
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block_connection/tx_ids_filter.graphql b/crates/iota-graphql-rpc/examples/transaction_block_connection/tx_ids_filter.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/transaction_block_connection/tx_ids_filter.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block_connection/tx_ids_filter.graphql
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block_connection/tx_kind_filter.graphql b/crates/iota-graphql-rpc/examples/transaction_block_connection/tx_kind_filter.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/transaction_block_connection/tx_kind_filter.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block_connection/tx_kind_filter.graphql
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block_connection/with_defaults_ascending.graphql b/crates/iota-graphql-rpc/examples/transaction_block_connection/with_defaults_ascending.graphql
    similarity index 100%
    rename from crates/sui-graphql-rpc/examples/transaction_block_connection/with_defaults_ascending.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block_connection/with_defaults_ascending.graphql
    diff --git a/crates/sui-graphql-rpc/examples/transaction_block_effects/transaction_block_effects.graphql b/crates/iota-graphql-rpc/examples/transaction_block_effects/transaction_block_effects.graphql
    similarity index 95%
    rename from crates/sui-graphql-rpc/examples/transaction_block_effects/transaction_block_effects.graphql
    rename to crates/iota-graphql-rpc/examples/transaction_block_effects/transaction_block_effects.graphql
    index 55f4c71cbd6..5ef96ee0e55 100644
    --- a/crates/sui-graphql-rpc/examples/transaction_block_effects/transaction_block_effects.graphql
    +++ b/crates/iota-graphql-rpc/examples/transaction_block_effects/transaction_block_effects.graphql
    @@ -40,7 +40,7 @@
               nodes {
                 owner {
                   address
    -              balance(type: "0x2::sui::SUI") {
    +              balance(type: "0x2::iota::IOTA") {
                     totalBalance
                   }
                 }
    diff --git a/crates/sui-graphql-rpc/schema/current_progress_schema.graphql b/crates/iota-graphql-rpc/schema/current_progress_schema.graphql
    similarity index 91%
    rename from crates/sui-graphql-rpc/schema/current_progress_schema.graphql
    rename to crates/iota-graphql-rpc/schema/current_progress_schema.graphql
    index 89527bd092f..a4aa2356361 100644
    --- a/crates/sui-graphql-rpc/schema/current_progress_schema.graphql
    +++ b/crates/iota-graphql-rpc/schema/current_progress_schema.graphql
    @@ -1,6 +1,6 @@
     type ActiveJwk {
     	"""
    -	The string (Issuing Authority) that identifies the OIDC provider.
    +	The string (Isiotang Authority) that identifies the OIDC provider.
     	"""
     	iss: String!
     	"""
    @@ -62,14 +62,14 @@ type ActiveJwkEdge {
     The 32-byte address that is an account address (corresponding to a public key).
     """
     type Address implements IOwner {
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	Objects owned by this address, optionally `filter`-ed.
     	"""
     	objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection!
     	"""
     	Total balance of all coins with marker type owned by this address. If type is not supplied,
    -	it defaults to `0x2::sui::SUI`.
    +	it defaults to `0x2::iota::IOTA`.
     	"""
     	balance(type: String): Balance
     	"""
    @@ -79,22 +79,22 @@ type Address implements IOwner {
     	"""
     	The coin objects for this address.
     	
    -	`type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`.
    +	`type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`.
     	"""
     	coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection!
     	"""
    -	The `0x3::staking_pool::StakedSui` objects owned by this address.
    +	The `0x3::staking_pool::StakedIota` objects owned by this address.
     	"""
    -	stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection!
    +	stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection!
     	"""
     	The domain explicitly configured as the default domain pointing to this address.
     	"""
    -	defaultSuinsName(format: DomainFormat): String
    +	defaultIotansName(format: DomainFormat): String
     	"""
    -	The SuinsRegistration NFTs owned by this address. These grant the owner the capability to
    +	The IotansRegistration NFTs owned by this address. These grant the owner the capability to
     	manage the associated domain.
     	"""
    -	suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection!
    +	iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection!
     	"""
     	Similar behavior to the `transactionBlocks` in Query but supporting the additional
     	`AddressTransactionBlockRelationship` filter, which defaults to `SIGN`.
    @@ -210,7 +210,7 @@ The total balance for a particular coin type.
     """
     type Balance {
     	"""
    -	Coin type for the balance, such as 0x2::sui::SUI
    +	Coin type for the balance, such as 0x2::iota::IOTA
     	"""
     	coinType: MoveType!
     	"""
    @@ -232,7 +232,7 @@ type BalanceChange {
     	"""
     	owner: Owner
     	"""
    -	The inner type of the coin whose balance has changed (e.g. `0x2::sui::SUI`).
    +	The inner type of the coin whose balance has changed (e.g. `0x2::iota::IOTA`).
     	"""
     	coinType: MoveType
     	"""
    @@ -327,20 +327,20 @@ type ChangeEpochTransaction {
     	"""
     	protocolVersion: Int!
     	"""
    -	The total amount of gas charged for storage during the previous epoch (in MIST).
    +	The total amount of gas charged for storage during the previous epoch (in MICROS).
     	"""
     	storageCharge: BigInt!
     	"""
    -	The total amount of gas charged for computation during the previous epoch (in MIST).
    +	The total amount of gas charged for computation during the previous epoch (in MICROS).
     	"""
     	computationCharge: BigInt!
     	"""
    -	The SUI returned to transaction senders for cleaning up objects (in MIST).
    +	The IOTA returned to transaction senders for cleaning up objects (in MICROS).
     	"""
     	storageRebate: BigInt!
     	"""
     	The total gas retained from storage fees, that will not be returned by storage rebates when
    -	the relevant objects are cleaned up (in MIST).
    +	the relevant objects are cleaned up (in MICROS).
     	"""
     	nonRefundableStorageFee: BigInt!
     	"""
    @@ -446,14 +446,14 @@ input CheckpointId {
     Some 0x2::coin::Coin Move object.
     """
     type Coin implements IMoveObject & IObject & IOwner {
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	Objects owned by this object, optionally `filter`-ed.
     	"""
     	objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection!
     	"""
     	Total balance of all coins with marker type owned by this object. If type is not supplied,
    -	it defaults to `0x2::sui::SUI`.
    +	it defaults to `0x2::iota::IOTA`.
     	"""
     	balance(type: String): Balance
     	"""
    @@ -463,22 +463,22 @@ type Coin implements IMoveObject & IObject & IOwner {
     	"""
     	The coin objects for this object.
     	
    -	`type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`.
    +	`type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`.
     	"""
     	coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection!
     	"""
    -	The `0x3::staking_pool::StakedSui` objects owned by this object.
    +	The `0x3::staking_pool::StakedIota` objects owned by this object.
     	"""
    -	stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection!
    +	stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection!
     	"""
     	The domain explicitly configured as the default domain pointing to this object.
     	"""
    -	defaultSuinsName(format: DomainFormat): String
    +	defaultIotansName(format: DomainFormat): String
     	"""
    -	The SuinsRegistration NFTs owned by this object. These grant the owner the capability to
    +	The IotansRegistration NFTs owned by this object. These grant the owner the capability to
     	manage the associated domain.
     	"""
    -	suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection!
    +	iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection!
     	version: Int!
     	"""
     	The current status of the object as read from the off-chain store. The possible states are:
    @@ -503,7 +503,7 @@ type Coin implements IMoveObject & IObject & IOwner {
     	"""
     	previousTransactionBlock: TransactionBlock
     	"""
    -	The amount of SUI we would rebate if this object gets deleted or mutated. This number is
    +	The amount of IOTA we would rebate if this object gets deleted or mutated. This number is
     	recalculated based on the present storage gas price.
     	"""
     	storageRebate: BigInt
    @@ -523,7 +523,7 @@ type Coin implements IMoveObject & IObject & IOwner {
     	contents: MoveValue
     	"""
     	Determines whether a transaction can transfer this object, using the TransferObjects
    -	transaction command or `sui::transfer::public_transfer`, both of which require the object to
    +	transaction command or `iota::transfer::public_transfer`, both of which require the object to
     	have the `key` and `store` abilities.
     	"""
     	hasPublicTransfer: Boolean!
    @@ -605,14 +605,14 @@ type CoinEdge {
     The metadata for a coin type.
     """
     type CoinMetadata implements IMoveObject & IObject & IOwner {
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	Objects owned by this object, optionally `filter`-ed.
     	"""
     	objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection!
     	"""
     	Total balance of all coins with marker type owned by this object. If type is not supplied,
    -	it defaults to `0x2::sui::SUI`.
    +	it defaults to `0x2::iota::IOTA`.
     	"""
     	balance(type: String): Balance
     	"""
    @@ -622,22 +622,22 @@ type CoinMetadata implements IMoveObject & IObject & IOwner {
     	"""
     	The coin objects for this object.
     	
    -	`type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`.
    +	`type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`.
     	"""
     	coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection!
     	"""
    -	The `0x3::staking_pool::StakedSui` objects owned by this object.
    +	The `0x3::staking_pool::StakedIota` objects owned by this object.
     	"""
    -	stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection!
    +	stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection!
     	"""
     	The domain explicitly configured as the default domain pointing to this object.
     	"""
    -	defaultSuinsName(format: DomainFormat): String
    +	defaultIotansName(format: DomainFormat): String
     	"""
    -	The SuinsRegistration NFTs owned by this object. These grant the owner the capability to
    +	The IotansRegistration NFTs owned by this object. These grant the owner the capability to
     	manage the associated domain.
     	"""
    -	suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection!
    +	iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection!
     	version: Int!
     	"""
     	The current status of the object as read from the off-chain store. The possible states are:
    @@ -662,7 +662,7 @@ type CoinMetadata implements IMoveObject & IObject & IOwner {
     	"""
     	previousTransactionBlock: TransactionBlock
     	"""
    -	The amount of SUI we would rebate if this object gets deleted or mutated. This number is
    +	The amount of IOTA we would rebate if this object gets deleted or mutated. This number is
     	recalculated based on the present storage gas price.
     	"""
     	storageRebate: BigInt
    @@ -682,7 +682,7 @@ type CoinMetadata implements IMoveObject & IObject & IOwner {
     	contents: MoveValue
     	"""
     	Determines whether a transaction can transfer this object, using the TransferObjects
    -	transaction command or `sui::transfer::public_transfer`, both of which require the object to
    +	transaction command or `iota::transfer::public_transfer`, both of which require the object to
     	have the `key` and `store` abilities.
     	"""
     	hasPublicTransfer: Boolean!
    @@ -870,7 +870,7 @@ fields:
     1) Dynamic Fields can store any value that has the `store` ability, however an object
     stored in this kind of field will be considered wrapped and will not be accessible
     directly via its ID by external tools (explorers, wallets, etc) accessing storage.
    -2) Dynamic Object Fields values must be Sui objects (have the `key` and `store`
    +2) Dynamic Object Fields values must be Iota objects (have the `key` and `store`
     abilities, and id: UID as the first field), but will still be directly accessible off-chain
     via their object ID after being attached.
     """
    @@ -975,7 +975,7 @@ type EndOfEpochTransactionKindEdge {
     }
     
     """
    -Operation of the Sui network is temporally partitioned into non-overlapping epochs,
    +Operation of the Iota network is temporally partitioned into non-overlapping epochs,
     and the network aims to keep epochs roughly the same duration as each other.
     During a particular epoch the following data is fixed:
     
    @@ -1013,11 +1013,11 @@ type Epoch {
     	"""
     	totalTransactions: Int
     	"""
    -	The total amount of gas fees (in MIST) that were paid in this epoch.
    +	The total amount of gas fees (in MICROS) that were paid in this epoch.
     	"""
     	totalGasFees: BigInt
     	"""
    -	The total MIST rewarded as stake.
    +	The total MICROS rewarded as stake.
     	"""
     	totalStakeRewards: BigInt
     	"""
    @@ -1050,7 +1050,7 @@ type Epoch {
     	"""
     	protocolConfigs: ProtocolConfigs!
     	"""
    -	SUI set aside to account for objects stored on-chain, at the start of the epoch.
    +	IOTA set aside to account for objects stored on-chain, at the start of the epoch.
     	This is also used for storage rebates.
     	"""
     	storageFund: StorageFund
    @@ -1060,7 +1060,7 @@ type Epoch {
     	"""
     	safeMode: SafeMode
     	"""
    -	The value of the `version` field of `0x5`, the `0x3::sui::SuiSystemState` object.  This
    +	The value of the `version` field of `0x5`, the `0x3::iota::IotaSystemState` object.  This
     	version changes whenever the fields contained in the system state object (held in a dynamic
     	field attached to `0x5`) change.
     	"""
    @@ -1164,7 +1164,7 @@ type EventEdge {
     }
     
     input EventFilter {
    -	sender: SuiAddress
    +	sender: IotaAddress
     	transactionDigest: String
     	"""
     	Events emitted by a particular module. An event is emitted by a
    @@ -1182,7 +1182,7 @@ input EventFilter {
     	
     	Generic types can be queried by either the generic type name, e.g.
     	`0x2::coin::Coin`, or by the full type name, such as
    -	`0x2::coin::Coin<0x2::sui::SUI>`.
    +	`0x2::coin::Coin<0x2::iota::IOTA>`.
     	"""
     	eventType: String
     }
    @@ -1235,7 +1235,7 @@ enum Feature {
     	"""
     	DYNAMIC_FIELDS
     	"""
    -	SuiNS name and reverse name look-up.
    +	IotaNS name and reverse name look-up.
     	"""
     	NAME_SERVICE
     	"""
    @@ -1266,22 +1266,22 @@ Breakdown of gas costs in effects.
     """
     type GasCostSummary {
     	"""
    -	Gas paid for executing this transaction (in MIST).
    +	Gas paid for executing this transaction (in MICROS).
     	"""
     	computationCost: BigInt
     	"""
    -	Gas paid for the data stored on-chain by this transaction (in MIST).
    +	Gas paid for the data stored on-chain by this transaction (in MICROS).
     	"""
     	storageCost: BigInt
     	"""
     	Part of storage cost that can be reclaimed by cleaning up data created by this transaction
     	(when objects are deleted or an object is modified, which is treated as a deletion followed
    -	by a creation) (in MIST).
    +	by a creation) (in MICROS).
     	"""
     	storageRebate: BigInt
     	"""
     	Part of storage cost that is not reclaimed when data created by this transaction is cleaned
    -	up (in MIST).
    +	up (in MICROS).
     	"""
     	nonRefundableStorageFee: BigInt
     }
    @@ -1308,7 +1308,7 @@ type GasInput {
     	gasPayment(first: Int, after: String, last: Int, before: String): ObjectConnection!
     	"""
     	An unsigned integer specifying the number of native tokens per gas unit this transaction
    -	will pay (in MIST).
    +	will pay (in MICROS).
     	"""
     	gasPrice: BigInt
     	"""
    @@ -1338,7 +1338,7 @@ interface IMoveObject {
     	"""
     	contents: MoveValue
     	"""
    -	Determines whether a transaction can transfer this object, using the TransferObjects transaction command or `sui::transfer::public_transfer`, both of which require the object to have the `key` and `store` abilities.
    +	Determines whether a transaction can transfer this object, using the TransferObjects transaction command or `iota::transfer::public_transfer`, both of which require the object to have the `key` and `store` abilities.
     	"""
     	hasPublicTransfer: Boolean!
     	"""
    @@ -1409,13 +1409,13 @@ object. The same address can only refer to an account or an object, never both,
     possible to know which up-front.
     """
     interface IOwner {
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	Objects owned by this object or address, optionally `filter`-ed.
     	"""
     	objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection!
     	"""
    -	Total balance of all coins with marker type owned by this object or address. If type is not supplied, it defaults to `0x2::sui::SUI`.
    +	Total balance of all coins with marker type owned by this object or address. If type is not supplied, it defaults to `0x2::iota::IOTA`.
     	"""
     	balance(type: String): Balance
     	"""
    @@ -1425,21 +1425,21 @@ interface IOwner {
     	"""
     	The coin objects for this object or address.
     	
    -	`type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`.
    +	`type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`.
     	"""
     	coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection!
     	"""
    -	The `0x3::staking_pool::StakedSui` objects owned by this object or address.
    +	The `0x3::staking_pool::StakedIota` objects owned by this object or address.
     	"""
    -	stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection!
    +	stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection!
     	"""
     	The domain explicitly configured as the default domain pointing to this object or address.
     	"""
    -	defaultSuinsName(format: DomainFormat): String
    +	defaultIotansName(format: DomainFormat): String
     	"""
    -	The SuinsRegistration NFTs owned by this object or address. These grant the owner the capability to manage the associated domain.
    +	The IotansRegistration NFTs owned by this object or address. These grant the owner the capability to manage the associated domain.
     	"""
    -	suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection!
    +	iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection!
     }
     
     """
    @@ -1473,11 +1473,11 @@ type Linkage {
     	"""
     	The ID on-chain of the first version of the dependency.
     	"""
    -	originalId: SuiAddress!
    +	originalId: IotaAddress!
     	"""
     	The ID on-chain of the version of the dependency that this package depends on.
     	"""
    -	upgradedId: SuiAddress!
    +	upgradedId: IotaAddress!
     	"""
     	The version of the dependency that this package depends on.
     	"""
    @@ -1513,7 +1513,7 @@ type MergeCoinsTransaction {
     }
     
     """
    -Abilities are keywords in Sui Move that define how types behave at the compiler level.
    +Abilities are keywords in Iota Move that define how types behave at the compiler level.
     """
     enum MoveAbility {
     	"""
    @@ -1541,7 +1541,7 @@ type MoveCallTransaction {
     	"""
     	The storage ID of the package the function being called is defined in.
     	"""
    -	package: SuiAddress!
    +	package: IotaAddress!
     	"""
     	The name of the module the function being called is defined in.
     	"""
    @@ -1568,9 +1568,9 @@ type MoveCallTransaction {
     The contents of a Move Value, corresponding to the following recursive type:
     
     type MoveData =
    -    { Address: SuiAddress }
    -  | { UID:     SuiAddress }
    -  | { ID:      SuiAddress }
    +    { Address: IotaAddress }
    +  | { UID:     IotaAddress }
    +  | { ID:      IotaAddress }
       | { Bool:    bool }
       | { Number:  BigInt }
       | { String:  string }
    @@ -1742,14 +1742,14 @@ The representation of an object as a Move Object, which exposes additional infor
     (content, module that governs it, version, is transferrable, etc.) about this object.
     """
     type MoveObject implements IMoveObject & IObject & IOwner {
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	Objects owned by this object, optionally `filter`-ed.
     	"""
     	objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection!
     	"""
     	Total balance of all coins with marker type owned by this object. If type is not supplied,
    -	it defaults to `0x2::sui::SUI`.
    +	it defaults to `0x2::iota::IOTA`.
     	"""
     	balance(type: String): Balance
     	"""
    @@ -1759,22 +1759,22 @@ type MoveObject implements IMoveObject & IObject & IOwner {
     	"""
     	The coin objects for this object.
     	
    -	`type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`.
    +	`type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`.
     	"""
     	coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection!
     	"""
    -	The `0x3::staking_pool::StakedSui` objects owned by this object.
    +	The `0x3::staking_pool::StakedIota` objects owned by this object.
     	"""
    -	stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection!
    +	stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection!
     	"""
     	The domain explicitly configured as the default domain pointing to this object.
     	"""
    -	defaultSuinsName(format: DomainFormat): String
    +	defaultIotansName(format: DomainFormat): String
     	"""
    -	The SuinsRegistration NFTs owned by this object. These grant the owner the capability to
    +	The IotansRegistration NFTs owned by this object. These grant the owner the capability to
     	manage the associated domain.
     	"""
    -	suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection!
    +	iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection!
     	version: Int!
     	"""
     	The current status of the object as read from the off-chain store. The possible states are:
    @@ -1799,7 +1799,7 @@ type MoveObject implements IMoveObject & IObject & IOwner {
     	"""
     	previousTransactionBlock: TransactionBlock
     	"""
    -	The amount of SUI we would rebate if this object gets deleted or mutated. This number is
    +	The amount of IOTA we would rebate if this object gets deleted or mutated. This number is
     	recalculated based on the present storage gas price.
     	"""
     	storageRebate: BigInt
    @@ -1819,7 +1819,7 @@ type MoveObject implements IMoveObject & IObject & IOwner {
     	contents: MoveValue
     	"""
     	Determines whether a transaction can transfer this object, using the TransferObjects
    -	transaction command or `sui::transfer::public_transfer`, both of which require the object to
    +	transaction command or `iota::transfer::public_transfer`, both of which require the object to
     	have the `key` and `store` abilities.
     	"""
     	hasPublicTransfer: Boolean!
    @@ -1860,17 +1860,17 @@ type MoveObject implements IMoveObject & IObject & IOwner {
     	"""
     	asCoin: Coin
     	"""
    -	Attempts to convert the Move object into a `0x3::staking_pool::StakedSui`.
    +	Attempts to convert the Move object into a `0x3::staking_pool::StakedIota`.
     	"""
    -	asStakedSui: StakedSui
    +	asStakedIota: StakedIota
     	"""
     	Attempts to convert the Move object into a `0x2::coin::CoinMetadata`.
     	"""
     	asCoinMetadata: CoinMetadata
     	"""
    -	Attempts to convert the Move object into a `SuinsRegistration` object.
    +	Attempts to convert the Move object into a `IotansRegistration` object.
     	"""
    -	asSuinsRegistration: SuinsRegistration
    +	asIotansRegistration: IotansRegistration
     }
     
     type MoveObjectConnection {
    @@ -1907,7 +1907,7 @@ A MovePackage is a kind of Move object that represents code that has been publis
     It exposes information about its modules, type definitions, functions, and dependencies.
     """
     type MovePackage implements IObject & IOwner {
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	Objects owned by this package, optionally `filter`-ed.
     	
    @@ -1917,7 +1917,7 @@ type MovePackage implements IObject & IOwner {
     	objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection!
     	"""
     	Total balance of all coins with marker type owned by this package. If type is not supplied,
    -	it defaults to `0x2::sui::SUI`.
    +	it defaults to `0x2::iota::IOTA`.
     	
     	Note that coins owned by a package are inaccessible, because packages are immutable and
     	cannot be owned by an address.
    @@ -1933,31 +1933,31 @@ type MovePackage implements IObject & IOwner {
     	"""
     	The coin objects owned by this package.
     	
    -	`type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`.
    +	`type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`.
     	
     	Note that coins owned by a package are inaccessible, because packages are immutable and
     	cannot be owned by an address.
     	"""
     	coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection!
     	"""
    -	The `0x3::staking_pool::StakedSui` objects owned by this package.
    +	The `0x3::staking_pool::StakedIota` objects owned by this package.
     	
     	Note that objects owned by a package are inaccessible, because packages are immutable and
     	cannot be owned by an address.
     	"""
    -	stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection!
    +	stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection!
     	"""
     	The domain explicitly configured as the default domain pointing to this object.
     	"""
    -	defaultSuinsName(format: DomainFormat): String
    +	defaultIotansName(format: DomainFormat): String
     	"""
    -	The SuinsRegistration NFTs owned by this package. These grant the owner the capability to
    +	The IotansRegistration NFTs owned by this package. These grant the owner the capability to
     	manage the associated domain.
     	
     	Note that objects owned by a package are inaccessible, because packages are immutable and
     	cannot be owned by an address.
     	"""
    -	suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection!
    +	iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection!
     	version: Int!
     	"""
     	The current status of the object as read from the off-chain store. The possible states are:
    @@ -1983,7 +1983,7 @@ type MovePackage implements IObject & IOwner {
     	"""
     	previousTransactionBlock: TransactionBlock
     	"""
    -	The amount of SUI we would rebate if this object gets deleted or mutated. This number is
    +	The amount of IOTA we would rebate if this object gets deleted or mutated. This number is
     	recalculated based on the present storage gas price.
     	
     	Note that packages cannot be deleted or mutated, so this number is provided purely for
    @@ -2225,7 +2225,7 @@ enum MoveVisibility {
     }
     
     """
    -Mutations are used to write to the Sui network.
    +Mutations are used to write to the Iota network.
     """
     type Mutation {
     	"""
    @@ -2248,19 +2248,19 @@ type Mutation {
     }
     
     """
    -An object in Sui is a package (set of Move bytecode modules) or object (typed data structure
    +An object in Iota is a package (set of Move bytecode modules) or object (typed data structure
     with fields) with additional metadata detailing its id, version, transaction digest, owner
     field indicating how this object can be accessed.
     """
     type Object implements IObject & IOwner {
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	Objects owned by this object, optionally `filter`-ed.
     	"""
     	objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection!
     	"""
     	Total balance of all coins with marker type owned by this object. If type is not supplied,
    -	it defaults to `0x2::sui::SUI`.
    +	it defaults to `0x2::iota::IOTA`.
     	"""
     	balance(type: String): Balance
     	"""
    @@ -2270,22 +2270,22 @@ type Object implements IObject & IOwner {
     	"""
     	The coin objects for this object.
     	
    -	`type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`.
    +	`type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`.
     	"""
     	coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection!
     	"""
    -	The `0x3::staking_pool::StakedSui` objects owned by this object.
    +	The `0x3::staking_pool::StakedIota` objects owned by this object.
     	"""
    -	stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection!
    +	stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection!
     	"""
     	The domain explicitly configured as the default domain pointing to this object.
     	"""
    -	defaultSuinsName(format: DomainFormat): String
    +	defaultIotansName(format: DomainFormat): String
     	"""
    -	The SuinsRegistration NFTs owned by this object. These grant the owner the capability to
    +	The IotansRegistration NFTs owned by this object. These grant the owner the capability to
     	manage the associated domain.
     	"""
    -	suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection!
    +	iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection!
     	version: Int!
     	"""
     	The current status of the object as read from the off-chain store. The possible states are:
    @@ -2311,7 +2311,7 @@ type Object implements IObject & IOwner {
     	"""
     	previousTransactionBlock: TransactionBlock
     	"""
    -	The amount of SUI we would rebate if this object gets deleted or mutated. This number is
    +	The amount of IOTA we would rebate if this object gets deleted or mutated. This number is
     	recalculated based on the present storage gas price.
     	"""
     	storageRebate: BigInt
    @@ -2372,7 +2372,7 @@ type ObjectChange {
     	"""
     	The address of the object that has changed.
     	"""
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	The contents of the object immediately before the transaction.
     	"""
    @@ -2466,17 +2466,17 @@ input ObjectFilter {
     	type name.
     	
     	Generic types can be queried by either the generic type name, e.g. `0x2::coin::Coin`, or by
    -	the full type name, such as `0x2::coin::Coin<0x2::sui::SUI>`.
    +	the full type name, such as `0x2::coin::Coin<0x2::iota::IOTA>`.
     	"""
     	type: String
     	"""
     	Filter for live objects by their current owners.
     	"""
    -	owner: SuiAddress
    +	owner: IotaAddress
     	"""
     	Filter for live objects by their IDs.
     	"""
    -	objectIds: [SuiAddress!]
    +	objectIds: [IotaAddress!]
     	"""
     	Filter for live or potentially historical objects by their ID and version.
     	"""
    @@ -2484,7 +2484,7 @@ input ObjectFilter {
     }
     
     input ObjectKey {
    -	objectId: SuiAddress!
    +	objectId: IotaAddress!
     	version: Int!
     }
     
    @@ -2518,7 +2518,7 @@ input ObjectRef {
     	"""
     	ID of the object.
     	"""
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	Version or sequence number of the object.
     	"""
    @@ -2576,7 +2576,7 @@ type OwnedOrImmutable {
     	"""
     	ID of the object being read.
     	"""
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	Version of the object being read.
     	"""
    @@ -2593,19 +2593,19 @@ type OwnedOrImmutable {
     }
     
     """
    -An Owner is an entity that can own an object. Each Owner is identified by a SuiAddress which
    +An Owner is an entity that can own an object. Each Owner is identified by a IotaAddress which
     represents either an Address (corresponding to a public key of an account) or an Object, but
     never both (it is not known up-front whether a given Owner is an Address or an Object).
     """
     type Owner implements IOwner {
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	Objects owned by this object or address, optionally `filter`-ed.
     	"""
     	objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection!
     	"""
     	Total balance of all coins with marker type owned by this object or address. If type is not
    -	supplied, it defaults to `0x2::sui::SUI`.
    +	supplied, it defaults to `0x2::iota::IOTA`.
     	"""
     	balance(type: String): Balance
     	"""
    @@ -2615,22 +2615,22 @@ type Owner implements IOwner {
     	"""
     	The coin objects for this object or address.
     	
    -	`type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`.
    +	`type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`.
     	"""
     	coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection!
     	"""
    -	The `0x3::staking_pool::StakedSui` objects owned by this object or address.
    +	The `0x3::staking_pool::StakedIota` objects owned by this object or address.
     	"""
    -	stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection!
    +	stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection!
     	"""
     	The domain explicitly configured as the default domain pointing to this object or address.
     	"""
    -	defaultSuinsName(format: DomainFormat): String
    +	defaultIotansName(format: DomainFormat): String
     	"""
    -	The SuinsRegistration NFTs owned by this object or address. These grant the owner the
    +	The IotansRegistration NFTs owned by this object or address. These grant the owner the
     	capability to manage the associated domain.
     	"""
    -	suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection!
    +	iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection!
     	asAddress: Address
     	asObject: Object
     	"""
    @@ -2797,7 +2797,7 @@ type PublishTransaction {
     	"""
     	IDs of the transitive dependencies of the package to be published.
     	"""
    -	dependencies: [SuiAddress!]!
    +	dependencies: [IotaAddress!]!
     }
     
     """
    @@ -2845,16 +2845,16 @@ type Query {
     	non-entry functions, and some other checks.  Defaults to false.
     	"""
     	dryRunTransactionBlock(txBytes: String!, txMeta: TransactionMetadata, skipChecks: Boolean): DryRunResult!
    -	owner(address: SuiAddress!): Owner
    +	owner(address: IotaAddress!): Owner
     	"""
     	The object corresponding to the given address at the (optionally) given version.
     	When no version is given, the latest version is returned.
     	"""
    -	object(address: SuiAddress!, version: Int): Object
    +	object(address: IotaAddress!, version: Int): Object
     	"""
    -	Look-up an Account by its SuiAddress.
    +	Look-up an Account by its IotaAddress.
     	"""
    -	address(address: SuiAddress!): Address
    +	address(address: IotaAddress!): Address
     	"""
     	Fetch a structured representation of a concrete type, including its layout information.
     	Fails if the type is malformed.
    @@ -2877,7 +2877,7 @@ type Query {
     	The coin objects that exist in the network.
     	
     	The type field is a string of the inner type of the coin by which to filter (e.g.
    -	`0x2::sui::SUI`). If no type is provided, it will default to `0x2::sui::SUI`.
    +	`0x2::iota::IOTA`). If no type is provided, it will default to `0x2::iota::IOTA`.
     	"""
     	coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection!
     	"""
    @@ -2902,9 +2902,9 @@ type Query {
     	"""
     	protocolConfig(protocolVersion: Int): ProtocolConfigs!
     	"""
    -	Resolves a SuiNS `domain` name to an address, if it has been bound.
    +	Resolves a IotaNS `domain` name to an address, if it has been bound.
     	"""
    -	resolveSuinsAddress(domain: String!): Address
    +	resolveIotansAddress(domain: String!): Address
     	"""
     	The coin metadata associated with the given coin type.
     	"""
    @@ -2922,7 +2922,7 @@ type Query {
     	- `intentScope` is an enum that specifies the intent scope to be used to parse bytes.
     	- `author` is the address of the signer of the transaction or personal msg.
     	"""
    -	verifyZkloginSignature(bytes: Base64!, signature: Base64!, intentScope: ZkLoginIntentScope!, author: SuiAddress!): ZkLoginVerifyResult!
    +	verifyZkloginSignature(bytes: Base64!, signature: Base64!, intentScope: ZkLoginIntentScope!, author: IotaAddress!): ZkLoginVerifyResult!
     }
     
     type RandomnessStateCreateTransaction {
    @@ -2961,7 +2961,7 @@ type Receiving {
     	"""
     	ID of the object being read.
     	"""
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	Version of the object being read.
     	"""
    @@ -3094,7 +3094,7 @@ type Shared {
     A Move object that's shared.
     """
     type SharedInput {
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	The version that this this object was shared at.
     	"""
    @@ -3117,7 +3117,7 @@ type SharedObjectDelete {
     	"""
     	ID of the shared object.
     	"""
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	The version of the shared object that was assigned to this transaction during by consensus,
     	during sequencing.
    @@ -3137,7 +3137,7 @@ type SharedObjectRead {
     	"""
     	ID of the object being read.
     	"""
    -	address: SuiAddress!
    +	address: IotaAddress!
     	"""
     	Version of the object being read.
     	"""
    @@ -3191,7 +3191,7 @@ Parameters that control the distribution of the stake subsidy.
     """
     type StakeSubsidy {
     	"""
    -	SUI set aside for stake subsidies -- reduces over time as stake subsidies are paid out over
    +	IOTA set aside for stake subsidies -- reduces over time as stake subsidies are paid out over
     	time.
     	"""
     	balance: BigInt
    @@ -3217,17 +3217,17 @@ type StakeSubsidy {
     }
     
     """
    -Represents a `0x3::staking_pool::StakedSui` Move object on-chain.
    +Represents a `0x3::staking_pool::StakedIota` Move object on-chain.
     """
    -type StakedSui implements IMoveObject & IObject & IOwner {
    -	address: SuiAddress!
    +type StakedIota implements IMoveObject & IObject & IOwner {
    +	address: IotaAddress!
     	"""
     	Objects owned by this object, optionally `filter`-ed.
     	"""
     	objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection!
     	"""
     	Total balance of all coins with marker type owned by this object. If type is not supplied,
    -	it defaults to `0x2::sui::SUI`.
    +	it defaults to `0x2::iota::IOTA`.
     	"""
     	balance(type: String): Balance
     	"""
    @@ -3237,22 +3237,22 @@ type StakedSui implements IMoveObject & IObject & IOwner {
     	"""
     	The coin objects for this object.
     	
    -	`type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`.
    +	`type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`.
     	"""
     	coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection!
     	"""
    -	The `0x3::staking_pool::StakedSui` objects owned by this object.
    +	The `0x3::staking_pool::StakedIota` objects owned by this object.
     	"""
    -	stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection!
    +	stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection!
     	"""
     	The domain explicitly configured as the default domain pointing to this object.
     	"""
    -	defaultSuinsName(format: DomainFormat): String
    +	defaultIotansName(format: DomainFormat): String
     	"""
    -	The SuinsRegistration NFTs owned by this object. These grant the owner the capability to
    +	The IotansRegistration NFTs owned by this object. These grant the owner the capability to
     	manage the associated domain.
     	"""
    -	suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection!
    +	iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection!
     	version: Int!
     	"""
     	The current status of the object as read from the off-chain store. The possible states are:
    @@ -3277,7 +3277,7 @@ type StakedSui implements IMoveObject & IObject & IOwner {
     	"""
     	previousTransactionBlock: TransactionBlock
     	"""
    -	The amount of SUI we would rebate if this object gets deleted or mutated. This number is
    +	The amount of IOTA we would rebate if this object gets deleted or mutated. This number is
     	recalculated based on the present storage gas price.
     	"""
     	storageRebate: BigInt
    @@ -3297,7 +3297,7 @@ type StakedSui implements IMoveObject & IObject & IOwner {
     	contents: MoveValue
     	"""
     	Determines whether a transaction can transfer this object, using the TransferObjects
    -	transaction command or `sui::transfer::public_transfer`, both of which require the object to
    +	transaction command or `iota::transfer::public_transfer`, both of which require the object to
     	have the `key` and `store` abilities.
     	"""
     	hasPublicTransfer: Boolean!
    @@ -3348,9 +3348,9 @@ type StakedSui implements IMoveObject & IObject & IOwner {
     	"""
     	The object id of the validator staking pool this stake belongs to.
     	"""
    -	poolId: SuiAddress
    +	poolId: IotaAddress
     	"""
    -	The SUI that was initially staked.
    +	The IOTA that was initially staked.
     	"""
     	principal: BigInt
     	"""
    @@ -3368,7 +3368,7 @@ type StakedSui implements IMoveObject & IObject & IOwner {
     	estimatedReward: BigInt
     }
     
    -type StakedSuiConnection {
    +type StakedIotaConnection {
     	"""
     	Information to aid in pagination.
     	"""
    @@ -3376,21 +3376,21 @@ type StakedSuiConnection {
     	"""
     	A list of edges.
     	"""
    -	edges: [StakedSuiEdge!]!
    +	edges: [StakedIotaEdge!]!
     	"""
     	A list of nodes.
     	"""
    -	nodes: [StakedSui!]!
    +	nodes: [StakedIota!]!
     }
     
     """
     An edge in a connection.
     """
    -type StakedSuiEdge {
    +type StakedIotaEdge {
     	"""
     	The item at the end of the edge
     	"""
    -	node: StakedSui!
    +	node: StakedIota!
     	"""
     	A cursor for use in pagination
     	"""
    @@ -3398,7 +3398,7 @@ type StakedSuiEdge {
     }
     
     """
    -SUI set aside to account for objects stored on-chain.
    +IOTA set aside to account for objects stored on-chain.
     """
     type StorageFund {
     	"""
    @@ -3417,19 +3417,19 @@ type StorageFund {
     
     
     """
    -String containing 32B hex-encoded address, with a leading "0x". Leading zeroes can be omitted on input but will always appear in outputs (SuiAddress in output is guaranteed to be 66 characters long).
    +String containing 32B hex-encoded address, with a leading "0x". Leading zeroes can be omitted on input but will always appear in outputs (IotaAddress in output is guaranteed to be 66 characters long).
     """
    -scalar SuiAddress
    +scalar IotaAddress
     
    -type SuinsRegistration implements IMoveObject & IObject & IOwner {
    -	address: SuiAddress!
    +type IotansRegistration implements IMoveObject & IObject & IOwner {
    +	address: IotaAddress!
     	"""
     	Objects owned by this object, optionally `filter`-ed.
     	"""
     	objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection!
     	"""
     	Total balance of all coins with marker type owned by this object. If type is not supplied,
    -	it defaults to `0x2::sui::SUI`.
    +	it defaults to `0x2::iota::IOTA`.
     	"""
     	balance(type: String): Balance
     	"""
    @@ -3439,22 +3439,22 @@ type SuinsRegistration implements IMoveObject & IObject & IOwner {
     	"""
     	The coin objects for this object.
     	
    -	`type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`.
    +	`type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`.
     	"""
     	coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection!
     	"""
    -	The `0x3::staking_pool::StakedSui` objects owned by this object.
    +	The `0x3::staking_pool::StakedIota` objects owned by this object.
     	"""
    -	stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection!
    +	stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection!
     	"""
     	The domain explicitly configured as the default domain pointing to this object.
     	"""
    -	defaultSuinsName(format: DomainFormat): String
    +	defaultIotansName(format: DomainFormat): String
     	"""
    -	The SuinsRegistration NFTs owned by this object. These grant the owner the capability to
    +	The IotansRegistration NFTs owned by this object. These grant the owner the capability to
     	manage the associated domain.
     	"""
    -	suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection!
    +	iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection!
     	version: Int!
     	"""
     	The current status of the object as read from the off-chain store. The possible states are:
    @@ -3479,7 +3479,7 @@ type SuinsRegistration implements IMoveObject & IObject & IOwner {
     	"""
     	previousTransactionBlock: TransactionBlock
     	"""
    -	The amount of SUI we would rebate if this object gets deleted or mutated. This number is
    +	The amount of IOTA we would rebate if this object gets deleted or mutated. This number is
     	recalculated based on the present storage gas price.
     	"""
     	storageRebate: BigInt
    @@ -3499,7 +3499,7 @@ type SuinsRegistration implements IMoveObject & IObject & IOwner {
     	contents: MoveValue
     	"""
     	Determines whether a transaction can transfer this object, using the TransferObjects
    -	transaction command or `sui::transfer::public_transfer`, both of which require the object to
    +	transaction command or `iota::transfer::public_transfer`, both of which require the object to
     	have the `key` and `store` abilities.
     	"""
     	hasPublicTransfer: Boolean!
    @@ -3536,12 +3536,12 @@ type SuinsRegistration implements IMoveObject & IObject & IOwner {
     	"""
     	dynamicFields(first: Int, after: String, last: Int, before: String): DynamicFieldConnection!
     	"""
    -	Domain name of the SuinsRegistration object
    +	Domain name of the IotansRegistration object
     	"""
     	domain: String!
     }
     
    -type SuinsRegistrationConnection {
    +type IotansRegistrationConnection {
     	"""
     	Information to aid in pagination.
     	"""
    @@ -3549,21 +3549,21 @@ type SuinsRegistrationConnection {
     	"""
     	A list of edges.
     	"""
    -	edges: [SuinsRegistrationEdge!]!
    +	edges: [IotansRegistrationEdge!]!
     	"""
     	A list of nodes.
     	"""
    -	nodes: [SuinsRegistration!]!
    +	nodes: [IotansRegistration!]!
     }
     
     """
     An edge in a connection.
     """
    -type SuinsRegistrationEdge {
    +type IotansRegistrationEdge {
     	"""
     	The item at the end of the edge
     	"""
    -	node: SuinsRegistration!
    +	node: IotansRegistration!
     	"""
     	A cursor for use in pagination
     	"""
    @@ -3763,10 +3763,10 @@ input TransactionBlockFilter {
     	afterCheckpoint: Int
     	atCheckpoint: Int
     	beforeCheckpoint: Int
    -	signAddress: SuiAddress
    -	recvAddress: SuiAddress
    -	inputObject: SuiAddress
    -	changedObject: SuiAddress
    +	signAddress: IotaAddress
    +	recvAddress: IotaAddress
    +	inputObject: IotaAddress
    +	changedObject: IotaAddress
     	transactionIds: [String!]
     }
     
    @@ -3829,11 +3829,11 @@ gas price, `gasBudget` defaults to the max gas budget and `gasSponsor` defaults
     to the sender.
     """
     input TransactionMetadata {
    -	sender: SuiAddress
    +	sender: IotaAddress
     	gasPrice: Int
     	gasObjects: [ObjectRef!]
     	gasBudget: Int
    -	gasSponsor: SuiAddress
    +	gasSponsor: IotaAddress
     }
     
     """
    @@ -3866,7 +3866,7 @@ type TypeOrigin {
     	"""
     	The storage ID of the package that first defined this type.
     	"""
    -	definingId: SuiAddress!
    +	definingId: IotaAddress!
     }
     
     """
    @@ -3917,11 +3917,11 @@ type UpgradeTransaction {
     	"""
     	IDs of the transitive dependencies of the package to be published.
     	"""
    -	dependencies: [SuiAddress!]!
    +	dependencies: [IotaAddress!]!
     	"""
     	ID of the package being upgraded.
     	"""
    -	currentPackage: SuiAddress!
    +	currentPackage: IotaAddress!
     	"""
     	The `UpgradeTicket` authorizing the upgrade.
     	"""
    @@ -3970,7 +3970,7 @@ type Validator {
     	stakingPool: MoveObject
     	"""
     	The validator's current exchange object. The exchange rate is used to determine
    -	the amount of SUI tokens that each past SUI staker can withdraw in the future.
    +	the amount of IOTA tokens that each past IOTA staker can withdraw in the future.
     	"""
     	exchangeRates: MoveObject
     	"""
    @@ -3982,9 +3982,9 @@ type Validator {
     	"""
     	stakingPoolActivationEpoch: Int
     	"""
    -	The total number of SUI tokens in this pool.
    +	The total number of IOTA tokens in this pool.
     	"""
    -	stakingPoolSuiBalance: BigInt
    +	stakingPoolIotaBalance: BigInt
     	"""
     	The epoch stake rewards will be added here at the end of each epoch.
     	"""
    @@ -4000,7 +4000,7 @@ type Validator {
     	"""
     	Pending stake withdrawn during the current epoch, emptied at epoch boundaries.
     	"""
    -	pendingTotalSuiWithdraw: BigInt
    +	pendingTotalIotaWithdraw: BigInt
     	"""
     	Pending pool token withdrawn during the current epoch, emptied at epoch boundaries.
     	"""
    @@ -4018,7 +4018,7 @@ type Validator {
     	"""
     	commissionRate: Int
     	"""
    -	The total number of SUI tokens in this pool plus
    +	The total number of IOTA tokens in this pool plus
     	the pending stake amount for this epoch.
     	"""
     	nextEpochStake: BigInt
    @@ -4105,7 +4105,7 @@ type ValidatorSet {
     	"""
     	Object ID of the wrapped object `TableVec` storing the pending active validators.
     	"""
    -	pendingActiveValidatorsId: SuiAddress
    +	pendingActiveValidatorsId: IotaAddress
     	"""
     	Size of the pending active validators table.
     	"""
    @@ -4115,7 +4115,7 @@ type ValidatorSet {
     	of the corresponding validators. This is needed because a validator's address
     	can potentially change but the object ID of its pool will not.
     	"""
    -	stakingPoolMappingsId: SuiAddress
    +	stakingPoolMappingsId: IotaAddress
     	"""
     	Size of the stake pool mappings `Table`.
     	"""
    @@ -4123,7 +4123,7 @@ type ValidatorSet {
     	"""
     	Object ID of the `Table` storing the inactive staking pools.
     	"""
    -	inactivePoolsId: SuiAddress
    +	inactivePoolsId: IotaAddress
     	"""
     	Size of the inactive pools `Table`.
     	"""
    @@ -4131,7 +4131,7 @@ type ValidatorSet {
     	"""
     	Object ID of the `Table` storing the validator candidates.
     	"""
    -	validatorCandidatesId: SuiAddress
    +	validatorCandidatesId: IotaAddress
     	"""
     	Size of the validator candidates `Table`.
     	"""
    diff --git a/crates/sui-graphql-rpc/schema/draft_target_schema.graphql b/crates/iota-graphql-rpc/schema/draft_target_schema.graphql
    similarity index 93%
    rename from crates/sui-graphql-rpc/schema/draft_target_schema.graphql
    rename to crates/iota-graphql-rpc/schema/draft_target_schema.graphql
    index 7b213509e2c..9a78bf006ac 100644
    --- a/crates/sui-graphql-rpc/schema/draft_target_schema.graphql
    +++ b/crates/iota-graphql-rpc/schema/draft_target_schema.graphql
    @@ -1,6 +1,9 @@
     # Copyright (c) Mysten Labs, Inc.
     # SPDX-License-Identifier: Apache-2.0
     
    +# Modifications Copyright (c) 2024 IOTA Stiftung
    +# SPDX-License-Identifier: Apache-2.0
    +
     # GraphQL Schema Draft
     # --------------------
     #
    @@ -56,9 +59,9 @@ type Query {
         skipChecks: Boolean,
       ): DryRunResult
     
    -  owner(address: SuiAddress!): Owner
    -  object(address: SuiAddress!, version: Int): Object
    -  address(address: SuiAddress!): Address
    +  owner(address: IotaAddress!): Owner
    +  object(address: IotaAddress!, version: Int): Object
    +  address(address: IotaAddress!): Address
       type(type: String!): MoveType!
     
       # Fetch epoch information by ID (defaults to the latest epoch).
    @@ -115,7 +118,7 @@ type Query {
         filter: ObjectFilter,
       ): ObjectConnection!
     
    -  resolveSuinsAddress(name: String!): Address
    +  resolveIotansAddress(name: String!): Address
     
       # NB. Will be moved into a private, explorer-specific extension.
       networkMetrics: NetworkMetrics
    @@ -173,9 +176,9 @@ type Mutation {
     
     # String containing 32B hex-encoded address, with a leading "0x".
     # Leading zeroes can be omitted on input but will always appear in
    -# outputs (SuiAddress in output is guaranteed to be 66 characters
    +# outputs (IotaAddress in output is guaranteed to be 66 characters
     # long).
    -scalar SuiAddress
    +scalar IotaAddress
     
     # String representation of an arbitrary width, possibly signed integer
     scalar BigInt
    @@ -195,9 +198,9 @@ scalar JSON
     # type MoveData =
     #     { Number:  BigInt }
     #   | { Bool:    bool }
    -#   | { Address: SuiAddress }
    -#   | { UID:     SuiAddress }
    -#   | { ID:      SuiAddress }
    +#   | { Address: IotaAddress }
    +#   | { UID:     IotaAddress }
    +#   | { ID:      IotaAddress }
     #   | { String:  string }
     #   | { Vector:  [MoveData] }
     #   | { Option:   MoveData? }
    @@ -268,16 +271,16 @@ scalar OpenMoveTypeSignature
     # The extra data required to turn a `TransactionKind` into a
     # `TransactionData` in a dry-run.
     input TransactionMetadata {
    -  sender: SuiAddress
    +  sender: IotaAddress
       gasPrice: Int
       gasBudget: Int
       gasObjects: [ObjectRef!]
    -  gasSponsor: SuiAddress
    +  gasSponsor: IotaAddress
     }
     
     # A reference to a particular version of an object.
     input ObjectRef {
    -  address: SuiAddress!
    +  address: IotaAddress!
       version: Int!
       digest: String!
     }
    @@ -298,14 +301,14 @@ input ObjectFilter {
       #
       # Generic types can be queried by either the generic type name, e.g.
       # `0x2::coin::Coin`, or by the full type name, such as
    -  # `0x2::coin::Coin<0x2::sui::SUI>`.
    +  # `0x2::coin::Coin<0x2::iota::IOTA>`.
       type: String
     
       # Filter for live objects by their current owners.
    -  owner: SuiAddress
    +  owner: IotaAddress
     
       # Filter for live objects by their IDs.
    -  objectIds: [SuiAddress!]
    +  objectIds: [IotaAddress!]
     
       # Filter for live or potentially historical objects by their ID and version.
       objectKeys: [ObjectKey!]
    @@ -318,12 +321,12 @@ input ObjectFilter {
     }
     
     input ObjectKey {
    -  objectId: SuiAddress!
    +  objectId: IotaAddress!
       version: Int!
     }
     
     input EventFilter {
    -  sender: SuiAddress
    +  sender: IotaAddress
       transactionDigest: String
       # Enhancement (post-MVP), requires compound filters to be useful.
       afterCheckpoint: Int
    @@ -343,7 +346,7 @@ input EventFilter {
       #
       # Generic types can be queried by either the generic type name, e.g.
       # `0x2::coin::Coin`, or by the full type name, such as
    -  # `0x2::coin::Coin<0x2::sui::SUI>`.
    +  # `0x2::coin::Coin<0x2::iota::IOTA>`.
       eventType: String
     
       # Enhancement (post-MVP), requires compound filters to be useful.
    @@ -366,13 +369,13 @@ input TransactionBlockFilter {
       afterCheckpoint: Int
       beforeCheckpoint: Int
     
    -  signAddress: SuiAddress
    -  sentAddress: SuiAddress
    -  recvAddress: SuiAddress
    -  paidAddress: SuiAddress
    +  signAddress: IotaAddress
    +  sentAddress: IotaAddress
    +  recvAddress: IotaAddress
    +  paidAddress: IotaAddress
     
    -  inputObject: SuiAddress
    -  changedObject: SuiAddress
    +  inputObject: IotaAddress
    +  changedObject: IotaAddress
     
       transactionIDs: [String!]
     
    @@ -396,7 +399,7 @@ input DynamicFieldFilter {
       #
       # Generic types can be queried by either the generic type name, e.g.
       # `0x2::coin::Coin`, or by the full type name, such as
    -  # `0x2::coin::Coin<0x2::sui::SUI>`.
    +  # `0x2::coin::Coin<0x2::iota::IOTA>`.
       nameType: String
     
       # Filter the type of dynamic field value.
    @@ -406,7 +409,7 @@ input DynamicFieldFilter {
       #
       # Generic types can be queried by either the generic type name, e.g.
       # `0x2::coin::Coin`, or by the full type name, such as
    -  # `0x2::coin::Coin<0x2::sui::SUI>`.
    +  # `0x2::coin::Coin<0x2::iota::IOTA>`.
       valueType: String
     }
     
    @@ -438,7 +441,7 @@ enum Feature {
     }
     
     interface IOwner {
    -  address: SuiAddress!
    +  address: IotaAddress!
     
       objects(
         first: Int,
    @@ -457,7 +460,7 @@ interface IOwner {
         before: String,
       ): BalanceConnection!
     
    -  # `type` defaults to `0x2::sui::SUI`.
    +  # `type` defaults to `0x2::iota::IOTA`.
       coins(
         first: Int,
         after: String,
    @@ -466,12 +469,12 @@ interface IOwner {
         type: String,
       ): CoinConnection!
     
    -  stakedSuis(
    +  stakedIotas(
         first: Int,
         after: String,
         last: Int,
         before: String,
    -  ): StakedSuiConnection!
    +  ): StakedIotaConnection!
     
       dynamicField(dynamicFieldName: DynamicFieldName!): DynamicField
       dynamicObjectField(dynamicFieldName: DynamicFieldName!): DynamicField
    @@ -484,13 +487,13 @@ interface IOwner {
         filter: DynamicFieldFilter,
       ): DynamicFieldConnection!
     
    -  defaultSuinsName: String
    -  suinsRegistrations(
    +  defaultIotansName: String
    +  iotansRegistrations(
         first: Int,
         after: String,
         last: Int,
         before: String,
    -  ): SuinsRegistrationConnection!
    +  ): IotansRegistrationConnection!
     }
     
     union ObjectOwner = Immutable | Shared | Parent | AddressOwner
    @@ -704,11 +707,11 @@ type Validator {
       exchangeRatesSize: Int
     
       stakingPoolActivationEpoch: Int
    -  stakingPoolSuiBalance: BigInt
    +  stakingPoolIotaBalance: BigInt
       rewardsPool: BigInt
       poolTokenBalance: BigInt
       pendingStake: BigInt
    -  pendingTotalSuiWithdraw: BigInt
    +  pendingTotalIotaWithdraw: BigInt
       pendingPoolTokenWithdraw: BigInt
     
       votingPower: Int
    @@ -724,7 +727,7 @@ type Validator {
       atRisk: Int
     
       # The other validators this validator has reported
    -  reportRecords: [SuiAddress!]
    +  reportRecords: [IotaAddress!]
     
       apy: Int
     }
    @@ -861,20 +864,20 @@ type ProgrammableTransactionBlock {
     union TransactionInput = OwnedOrImmutable | SharedInput | Receiving | Pure
     
     type OwnedOrImmutable {
    -  address: SuiAddress!
    +  address: IotaAddress!
       version: Int!
       digest: String!
       object: Object
     }
     
     type SharedInput {
    -  address: SuiAddress!
    +  address: IotaAddress!
       initialSharedVersion: Int!
       mutable: Boolean!
     }
     
     type Receiving {
    -  address: SuiAddress!
    +  address: IotaAddress!
       version: Int!
       digest: String!
       object: Object
    @@ -900,7 +903,7 @@ union ProgrammableTransaction =
       | MakeMoveVecTransaction
     
     type MoveCallTransaction {
    -  package: SuiAddress!
    +  package: IotaAddress!
       module: String!
       functionName: String!
       function: MoveFunction
    @@ -925,13 +928,13 @@ type MergeCoinsTransaction {
     
     type PublishTransaction {
       modules: [Base64!]!
    -  dependencies: [SuiAddress!]!
    +  dependencies: [IotaAddress!]!
     }
     
     type UpgradeTransaction {
       modules: [Base64!]!
    -  dependencies: [SuiAddress!]!
    -  currentPackage: SuiAddress!
    +  dependencies: [IotaAddress!]!
    +  currentPackage: IotaAddress!
       upgradeTicket: TransactionArgument!
     }
     
    @@ -1025,14 +1028,14 @@ type GasCostSummary {
     union UnchangedSharedObject = SharedObjectRead | SharedObjectDelete
     
     type SharedObjectRead {
    -  address: SuiAddress!
    +  address: IotaAddress!
       version: u64!
       digest: String!
       object: Object
     }
     
     type SharedObjectDelete {
    -  address: SuiAddress!
    +  address: IotaAddress!
       version: u64!
     
       # Whether this transaction intended to use this shared object
    @@ -1041,7 +1044,7 @@ type SharedObjectDelete {
     }
     
     type ObjectChange {
    -  address: SuiAddress!
    +  address: IotaAddress!
     
       inputState: Object
       outputState: Object
    @@ -1079,7 +1082,7 @@ type Coin implements IOwner & IObject {
       coinBalance: BigInt
     }
     
    -type StakedSui implements IOwner & IObject {
    +type StakedIota implements IOwner & IObject {
       stakeStatus: StakeStatus!
       requestEpoch: Epoch
       activeEpoch: Epoch
    @@ -1118,9 +1121,9 @@ union DynamicFieldValue = MoveObject | MoveValue
     
     type MoveObject implements IOwner & IObject & IMoveObject {
       asCoin: Coin
    -  asStakedSui: StakedSui
    +  asStakedIota: StakedIota
       asCoinMetadata: CoinMetadata
    -  asSuinsRegistration: SuinsRegistration
    +  asIotansRegistration: IotansRegistration
     }
     
     type MovePackage implements IOwner & IObject {
    @@ -1139,15 +1142,15 @@ type MovePackage implements IOwner & IObject {
     }
     
     type Linkage {
    -  originalId: SuiAddress!
    -  upgradedId: SuiAddress!
    +  originalId: IotaAddress!
    +  upgradedId: IotaAddress!
       version: Int!
     }
     
     type TypeOrigin {
       module: String!
       struct: String!
    -  definingId: SuiAddress!
    +  definingId: IotaAddress!
     }
     
     enum MoveAbility {
    @@ -1173,7 +1176,7 @@ type MoveFunctionTypeParameter {
     }
     
     type MoveModule {
    -  package: SuiAddress!
    +  package: IotaAddress!
       name: String!
     
       fileFormatVersion: Int!
    @@ -1527,25 +1530,25 @@ type MoveModuleEdge {
       node: MoveModule!
     }
     
    -# SuinsRegistrationConnection
    -type SuinsRegistrationConnection {
    -  edges: [SuinsRegistrationEdge!]!
    -  nodes: [SuinsRegistration!]!
    +# IotansRegistrationConnection
    +type IotansRegistrationConnection {
    +  edges: [IotansRegistrationEdge!]!
    +  nodes: [IotansRegistration!]!
       pageInfo: PageInfo!
     }
     
    -type SuinsRegistrationEdge {
    +type IotansRegistrationEdge {
       cursor: String
    -  node: SuinsRegistration
    +  node: IotansRegistration
     }
     
    -type SuinsRegistration {
    +type IotansRegistration {
     	"""
    -	Domain name of the SuinsRegistration object
    +	Domain name of the IotansRegistration object
     	"""
     	domain: String!
     	"""
    -	Convert the SuinsRegistration object into a Move object
    +	Convert the IotansRegistration object into a Move object
     	"""
     	asMoveObject: MoveObject!
     }
    @@ -1562,16 +1565,16 @@ type AddressMetricEdge {
       node: AddressMetrics!
     }
     
    -# StakedSuiConnection
    -type StakedSuiConnection {
    -  edges: [StakedSuiEdge!]!
    -  nodes: [StakedSui!]!
    +# StakedIotaConnection
    +type StakedIotaConnection {
    +  edges: [StakedIotaEdge!]!
    +  nodes: [StakedIota!]!
       pageInfo: PageInfo!
     }
     
    -type StakedSuiEdge {
    +type StakedIotaEdge {
       cursor: String
    -  node: StakedSui!
    +  node: StakedIota!
     }
     
     # ValidatorConnection
    diff --git a/crates/iota-graphql-rpc/src/commands.rs b/crates/iota-graphql-rpc/src/commands.rs
    new file mode 100644
    index 00000000000..6bbb2bbffae
    --- /dev/null
    +++ b/crates/iota-graphql-rpc/src/commands.rs
    @@ -0,0 +1,57 @@
    +// Copyright (c) Mysten Labs, Inc.
    +// Modifications Copyright (c) 2024 IOTA Stiftung
    +// SPDX-License-Identifier: Apache-2.0
    +
    +use std::path::PathBuf;
    +
    +use clap::*;
    +
    +#[derive(Parser)]
    +#[clap(
    +    name = "iota-graphql-rpc",
    +    about = "Iota GraphQL RPC",
    +    rename_all = "kebab-case",
    +    author,
    +    version
    +)]
    +pub enum Command {
    +    GenerateDocsExamples,
    +    GenerateSchema {
    +        /// Path to output GraphQL schema to, in SDL format.
    +        #[clap(short, long)]
    +        file: Option,
    +    },
    +    GenerateExamples {
    +        /// Path to output examples docs.
    +        #[clap(short, long)]
    +        file: Option,
    +    },
    +    StartServer {
    +        /// The title to display at the top of the page
    +        #[clap(short, long)]
    +        ide_title: Option,
    +        /// DB URL for data fetching
    +        #[clap(short, long)]
    +        db_url: Option,
    +        /// Port to bind the server to
    +        #[clap(short, long)]
    +        port: Option,
    +        /// Host to bind the server to
    +        #[clap(long)]
    +        host: Option,
    +        /// Port to bind the prom server to
    +        #[clap(long)]
    +        prom_port: Option,
    +        /// Host to bind the prom server to
    +        #[clap(long)]
    +        prom_host: Option,
    +
    +        /// Path to TOML file containing configuration for service.
    +        #[clap(short, long)]
    +        config: Option,
    +
    +        /// RPC url to the Node for tx execution
    +        #[clap(long)]
    +        node_rpc_url: Option,
    +    },
    +}
    diff --git a/crates/iota-graphql-rpc/src/config.rs b/crates/iota-graphql-rpc/src/config.rs
    new file mode 100644
    index 00000000000..2fcaf90a1ca
    --- /dev/null
    +++ b/crates/iota-graphql-rpc/src/config.rs
    @@ -0,0 +1,639 @@
    +// Copyright (c) Mysten Labs, Inc.
    +// Modifications Copyright (c) 2024 IOTA Stiftung
    +// SPDX-License-Identifier: Apache-2.0
    +
    +use std::{collections::BTreeSet, fmt::Display, time::Duration};
    +
    +use async_graphql::*;
    +use fastcrypto_zkp::bn254::zk_login_api::ZkLoginEnv;
    +use iota_json_rpc::name_service::NameServiceConfig;
    +use serde::{Deserialize, Serialize};
    +
    +use crate::{functional_group::FunctionalGroup, types::big_int::BigInt};
    +
    +// TODO: calculate proper cost limits
    +
    +/// These values are set to support TS SDK shim layer queries for json-rpc
    +/// compatibility.
    +const MAX_QUERY_NODES: u32 = 300;
    +const MAX_QUERY_PAYLOAD_SIZE: u32 = 5_000;
    +
    +const MAX_QUERY_DEPTH: u32 = 20;
    +const MAX_OUTPUT_NODES: u64 = 100_000; // Maximum number of output nodes allowed in the response
    +const MAX_DB_QUERY_COST: u64 = 20_000; // Max DB query cost (normally f64) truncated
    +const DEFAULT_PAGE_SIZE: u64 = 20; // Default number of elements allowed on a page of a connection
    +const MAX_PAGE_SIZE: u64 = 50; // Maximum number of elements allowed on a page of a connection
    +
    +/// The following limits reflect the max values set in the ProtocolConfig.
    +const MAX_TYPE_ARGUMENT_DEPTH: u32 = 16;
    +const MAX_TYPE_ARGUMENT_WIDTH: u32 = 32;
    +const MAX_TYPE_NODES: u32 = 256;
    +const MAX_MOVE_VALUE_DEPTH: u32 = 128;
    +
    +pub(crate) const DEFAULT_REQUEST_TIMEOUT_MS: u64 = 40_000;
    +
    +const DEFAULT_IDE_TITLE: &str = "Iota GraphQL IDE";
    +
    +pub(crate) const RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD: Duration = Duration::from_millis(10_000);
    +pub(crate) const MAX_CONCURRENT_REQUESTS: usize = 1_000;
    +
    +// Default values for the server connection configuration.
    +pub(crate) const DEFAULT_SERVER_CONNECTION_PORT: u16 = 8000;
    +pub(crate) const DEFAULT_SERVER_CONNECTION_HOST: &str = "127.0.0.1";
    +pub(crate) const DEFAULT_SERVER_DB_URL: &str =
    +    "postgres://postgres:postgrespw@localhost:5432/iota_indexer";
    +pub(crate) const DEFAULT_SERVER_DB_POOL_SIZE: u32 = 3;
    +pub(crate) const DEFAULT_SERVER_PROM_HOST: &str = "0.0.0.0";
    +pub(crate) const DEFAULT_SERVER_PROM_PORT: u16 = 9184;
    +pub(crate) const DEFAULT_WATERMARK_UPDATE_MS: u64 = 500;
    +
    +/// The combination of all configurations for the GraphQL service.
    +#[derive(Serialize, Clone, Deserialize, Debug, Default)]
    +pub struct ServerConfig {
    +    #[serde(default)]
    +    pub service: ServiceConfig,
    +    #[serde(default)]
    +    pub connection: ConnectionConfig,
    +    #[serde(default)]
    +    pub internal_features: InternalFeatureConfig,
    +    #[serde(default)]
    +    pub tx_exec_full_node: TxExecFullNodeConfig,
    +    #[serde(default)]
    +    pub ide: Ide,
    +}
    +
    +/// Configuration for connections for the RPC, passed in as command-line
    +/// arguments. This configures specific connections between this service and
    +/// other services, and might differ from instance to instance of the GraphQL
    +/// service.
    +#[derive(Serialize, Clone, Deserialize, Debug, Eq, PartialEq)]
    +pub struct ConnectionConfig {
    +    /// Port to bind the server to
    +    pub(crate) port: u16,
    +    /// Host to bind the server to
    +    pub(crate) host: String,
    +    pub(crate) db_url: String,
    +    pub(crate) db_pool_size: u32,
    +    pub(crate) prom_url: String,
    +    pub(crate) prom_port: u16,
    +}
    +
    +/// Configuration on features supported by the GraphQL service, passed in a
    +/// TOML-based file. These configurations are shared across fleets of the
    +/// service, i.e. all testnet services will have the same `ServiceConfig`.
    +#[derive(Serialize, Clone, Deserialize, Debug, Eq, PartialEq, Default)]
    +#[serde(rename_all = "kebab-case")]
    +pub struct ServiceConfig {
    +    #[serde(default)]
    +    pub(crate) limits: Limits,
    +
    +    #[serde(default)]
    +    pub(crate) disabled_features: BTreeSet,
    +
    +    #[serde(default)]
    +    pub(crate) experiments: Experiments,
    +
    +    #[serde(default)]
    +    pub(crate) name_service: NameServiceConfig,
    +
    +    #[serde(default)]
    +    pub(crate) background_tasks: BackgroundTasksConfig,
    +
    +    #[serde(default)]
    +    pub(crate) zklogin: ZkLoginConfig,
    +}
    +
    +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Copy)]
    +#[serde(rename_all = "kebab-case")]
    +pub struct Limits {
    +    #[serde(default)]
    +    pub max_query_depth: u32,
    +    #[serde(default)]
    +    pub max_query_nodes: u32,
    +    #[serde(default)]
    +    pub max_output_nodes: u64,
    +    #[serde(default)]
    +    pub max_query_payload_size: u32,
    +    #[serde(default)]
    +    pub max_db_query_cost: u64,
    +    #[serde(default)]
    +    pub default_page_size: u64,
    +    #[serde(default)]
    +    pub max_page_size: u64,
    +    #[serde(default)]
    +    pub request_timeout_ms: u64,
    +    #[serde(default)]
    +    pub max_type_argument_depth: u32,
    +    #[serde(default)]
    +    pub max_type_argument_width: u32,
    +    #[serde(default)]
    +    pub max_type_nodes: u32,
    +    #[serde(default)]
    +    pub max_move_value_depth: u32,
    +}
    +
    +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Copy)]
    +#[serde(rename_all = "kebab-case")]
    +pub struct BackgroundTasksConfig {
    +    #[serde(default)]
    +    pub watermark_update_ms: u64,
    +}
    +
    +/// The Version of the service. `year.month` represents the major release.
    +/// New `patch` versions represent backwards compatible fixes for their major
    +/// release. The `full` version is `year.month.patch-sha`.
    +#[derive(Copy, Clone, Debug)]
    +pub struct Version {
    +    /// The year of this release.
    +    pub year: &'static str,
    +    /// The month of this release.
    +    pub month: &'static str,
    +    /// The patch is a positive number incremented for every compatible release
    +    /// on top of the major.month release.
    +    pub patch: &'static str,
    +    /// The commit sha for this release.
    +    pub sha: &'static str,
    +    /// The full version string.
    +    /// Note that this extra field is used only for the uptime_metric function
    +    /// which requries a &'static str.
    +    pub full: &'static str,
    +}
    +
    +impl Version {
    +    /// Use for testing when you need the Version obj and a year.month &str
    +    pub fn for_testing() -> Self {
    +        Self {
    +            year: env!("CARGO_PKG_VERSION_MAJOR"),
    +            month: env!("CARGO_PKG_VERSION_MINOR"),
    +            patch: env!("CARGO_PKG_VERSION_PATCH"),
    +            sha: "testing-no-sha",
    +            // note that this full field is needed for metrics but not for testing
    +            full: const_str::concat!(
    +                env!("CARGO_PKG_VERSION_MAJOR"),
    +                ".",
    +                env!("CARGO_PKG_VERSION_MINOR"),
    +                ".",
    +                env!("CARGO_PKG_VERSION_PATCH"),
    +                "-testing-no-sha"
    +            ),
    +        }
    +    }
    +}
    +
    +impl Display for Version {
    +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    +        write!(f, "{}", self.full)
    +    }
    +}
    +
    +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
    +#[serde(rename_all = "kebab-case")]
    +pub struct Ide {
    +    #[serde(default)]
    +    pub(crate) ide_title: String,
    +}
    +
    +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Default)]
    +#[serde(rename_all = "kebab-case")]
    +pub struct Experiments {
    +    // Add experimental flags here, to provide access to them through-out the GraphQL
    +    // implementation.
    +    #[cfg(test)]
    +    test_flag: bool,
    +}
    +
    +#[derive(Serialize, Clone, Deserialize, Debug, Eq, PartialEq)]
    +pub struct InternalFeatureConfig {
    +    #[serde(default)]
    +    pub(crate) query_limits_checker: bool,
    +    #[serde(default)]
    +    pub(crate) feature_gate: bool,
    +    #[serde(default)]
    +    pub(crate) logger: bool,
    +    #[serde(default)]
    +    pub(crate) query_timeout: bool,
    +    #[serde(default)]
    +    pub(crate) metrics: bool,
    +    #[serde(default)]
    +    pub(crate) tracing: bool,
    +    #[serde(default)]
    +    pub(crate) apollo_tracing: bool,
    +    #[serde(default)]
    +    pub(crate) open_telemetry: bool,
    +}
    +
    +#[derive(Serialize, Clone, Deserialize, Debug, Eq, PartialEq, Default)]
    +pub struct TxExecFullNodeConfig {
    +    #[serde(default)]
    +    pub(crate) node_rpc_url: Option,
    +}
    +
    +#[derive(Serialize, Clone, Deserialize, Debug, Eq, PartialEq, Default)]
    +#[serde(rename_all = "kebab-case")]
    +pub struct ZkLoginConfig {
    +    pub env: ZkLoginEnv,
    +}
    +
    +/// The enabled features and service limits configured by the server.
    +#[Object]
    +impl ServiceConfig {
    +    /// Check whether `feature` is enabled on this GraphQL service.
    +    async fn is_enabled(&self, feature: FunctionalGroup) -> bool {
    +        !self.disabled_features.contains(&feature)
    +    }
    +
    +    /// List of all features that are enabled on this GraphQL service.
    +    async fn enabled_features(&self) -> Vec {
    +        FunctionalGroup::all()
    +            .iter()
    +            .filter(|g| !self.disabled_features.contains(g))
    +            .copied()
    +            .collect()
    +    }
    +
    +    /// The maximum depth a GraphQL query can be to be accepted by this service.
    +    pub async fn max_query_depth(&self) -> u32 {
    +        self.limits.max_query_depth
    +    }
    +
    +    /// The maximum number of nodes (field names) the service will accept in a
    +    /// single query.
    +    pub async fn max_query_nodes(&self) -> u32 {
    +        self.limits.max_query_nodes
    +    }
    +
    +    /// The maximum number of output nodes in a GraphQL response.
    +    ///
    +    /// Non-connection nodes have a count of 1, while connection nodes are
    +    /// counted as the specified 'first' or 'last' number of items, or the
    +    /// default_page_size as set by the server if those arguments are not
    +    /// set.
    +    ///
    +    /// Counts accumulate multiplicatively down the query tree. For example, if
    +    /// a query starts with a connection of first: 10 and has a field to a
    +    /// connection with last: 20, the count at the second level would be 200
    +    /// nodes. This is then summed to the count of 10 nodes at the first
    +    /// level, for a total of 210 nodes.
    +    pub async fn max_output_nodes(&self) -> u64 {
    +        self.limits.max_output_nodes
    +    }
    +
    +    /// Maximum estimated cost of a database query used to serve a GraphQL
    +    /// request.  This is measured in the same units that the database uses
    +    /// in EXPLAIN queries.
    +    async fn max_db_query_cost(&self) -> BigInt {
    +        BigInt::from(self.limits.max_db_query_cost)
    +    }
    +
    +    /// Default number of elements allowed on a single page of a connection.
    +    async fn default_page_size(&self) -> u64 {
    +        self.limits.default_page_size
    +    }
    +
    +    /// Maximum number of elements allowed on a single page of a connection.
    +    async fn max_page_size(&self) -> u64 {
    +        self.limits.max_page_size
    +    }
    +
    +    /// Maximum time in milliseconds that will be spent to serve one request.
    +    async fn request_timeout_ms(&self) -> u64 {
    +        self.limits.request_timeout_ms
    +    }
    +
    +    /// Maximum length of a query payload string.
    +    async fn max_query_payload_size(&self) -> u32 {
    +        self.limits.max_query_payload_size
    +    }
    +
    +    /// Maximum nesting allowed in type arguments in Move Types resolved by this
    +    /// service.
    +    async fn max_type_argument_depth(&self) -> u32 {
    +        self.limits.max_type_argument_depth
    +    }
    +
    +    /// Maximum number of type arguments passed into a generic instantiation of
    +    /// a Move Type resolved by this service.
    +    async fn max_type_argument_width(&self) -> u32 {
    +        self.limits.max_type_argument_width
    +    }
    +
    +    /// Maximum number of structs that need to be processed when calculating the
    +    /// layout of a single Move Type.
    +    async fn max_type_nodes(&self) -> u32 {
    +        self.limits.max_type_nodes
    +    }
    +
    +    /// Maximum nesting allowed in struct fields when calculating the layout of
    +    /// a single Move Type.
    +    async fn max_move_value_depth(&self) -> u32 {
    +        self.limits.max_move_value_depth
    +    }
    +}
    +
    +impl TxExecFullNodeConfig {
    +    pub fn new(node_rpc_url: Option) -> Self {
    +        Self { node_rpc_url }
    +    }
    +}
    +
    +impl ConnectionConfig {
    +    pub fn new(
    +        port: Option,
    +        host: Option,
    +        db_url: Option,
    +        db_pool_size: Option,
    +        prom_url: Option,
    +        prom_port: Option,
    +    ) -> Self {
    +        let default = Self::default();
    +        Self {
    +            port: port.unwrap_or(default.port),
    +            host: host.unwrap_or(default.host),
    +            db_url: db_url.unwrap_or(default.db_url),
    +            db_pool_size: db_pool_size.unwrap_or(default.db_pool_size),
    +            prom_url: prom_url.unwrap_or(default.prom_url),
    +            prom_port: prom_port.unwrap_or(default.prom_port),
    +        }
    +    }
    +
    +    pub fn ci_integration_test_cfg() -> Self {
    +        Self {
    +            db_url: DEFAULT_SERVER_DB_URL.to_string(),
    +            ..Default::default()
    +        }
    +    }
    +
    +    pub fn ci_integration_test_cfg_with_db_name(
    +        db_name: String,
    +        port: u16,
    +        prom_port: u16,
    +    ) -> Self {
    +        Self {
    +            db_url: format!("postgres://postgres:postgrespw@localhost:5432/{}", db_name),
    +            port,
    +            prom_port,
    +            ..Default::default()
    +        }
    +    }
    +
    +    pub fn db_name(&self) -> String {
    +        self.db_url.split('/').last().unwrap().to_string()
    +    }
    +
    +    pub fn db_url(&self) -> String {
    +        self.db_url.clone()
    +    }
    +
    +    pub fn db_pool_size(&self) -> u32 {
    +        self.db_pool_size
    +    }
    +
    +    pub fn server_address(&self) -> String {
    +        format!("{}:{}", self.host, self.port)
    +    }
    +}
    +
    +impl ServiceConfig {
    +    pub fn read(contents: &str) -> Result {
    +        toml::de::from_str::(contents)
    +    }
    +
    +    pub fn test_defaults() -> Self {
    +        Self {
    +            background_tasks: BackgroundTasksConfig::test_defaults(),
    +            zklogin: ZkLoginConfig {
    +                env: ZkLoginEnv::Test,
    +            },
    +            ..Default::default()
    +        }
    +    }
    +}
    +
    +impl Limits {
    +    /// Extract limits for the package resolver.
    +    pub fn package_resolver_limits(&self) -> iota_package_resolver::Limits {
    +        iota_package_resolver::Limits {
    +            max_type_argument_depth: self.max_type_argument_depth as usize,
    +            max_type_argument_width: self.max_type_argument_width as usize,
    +            max_type_nodes: self.max_type_nodes as usize,
    +            max_move_value_depth: self.max_move_value_depth as usize,
    +        }
    +    }
    +}
    +
    +impl Ide {
    +    pub fn new(ide_title: Option) -> Self {
    +        Self {
    +            ide_title: ide_title.unwrap_or_else(|| DEFAULT_IDE_TITLE.to_string()),
    +        }
    +    }
    +}
    +
    +impl BackgroundTasksConfig {
    +    pub fn test_defaults() -> Self {
    +        Self {
    +            watermark_update_ms: 100, // Set to 100ms for testing
    +        }
    +    }
    +}
    +
    +impl Default for Ide {
    +    fn default() -> Self {
    +        Self {
    +            ide_title: DEFAULT_IDE_TITLE.to_string(),
    +        }
    +    }
    +}
    +
    +impl Default for ConnectionConfig {
    +    fn default() -> Self {
    +        Self {
    +            port: DEFAULT_SERVER_CONNECTION_PORT,
    +            host: DEFAULT_SERVER_CONNECTION_HOST.to_string(),
    +            db_url: DEFAULT_SERVER_DB_URL.to_string(),
    +            db_pool_size: DEFAULT_SERVER_DB_POOL_SIZE,
    +            prom_url: DEFAULT_SERVER_PROM_HOST.to_string(),
    +            prom_port: DEFAULT_SERVER_PROM_PORT,
    +        }
    +    }
    +}
    +
    +impl Default for Limits {
    +    fn default() -> Self {
    +        Self {
    +            max_query_depth: MAX_QUERY_DEPTH,
    +            max_query_nodes: MAX_QUERY_NODES,
    +            max_output_nodes: MAX_OUTPUT_NODES,
    +            max_query_payload_size: MAX_QUERY_PAYLOAD_SIZE,
    +            max_db_query_cost: MAX_DB_QUERY_COST,
    +            default_page_size: DEFAULT_PAGE_SIZE,
    +            max_page_size: MAX_PAGE_SIZE,
    +            request_timeout_ms: DEFAULT_REQUEST_TIMEOUT_MS,
    +            max_type_argument_depth: MAX_TYPE_ARGUMENT_DEPTH,
    +            max_type_argument_width: MAX_TYPE_ARGUMENT_WIDTH,
    +            max_type_nodes: MAX_TYPE_NODES,
    +            max_move_value_depth: MAX_MOVE_VALUE_DEPTH,
    +        }
    +    }
    +}
    +
    +impl Default for InternalFeatureConfig {
    +    fn default() -> Self {
    +        Self {
    +            query_limits_checker: true,
    +            feature_gate: true,
    +            logger: true,
    +            query_timeout: true,
    +            metrics: true,
    +            tracing: false,
    +            apollo_tracing: false,
    +            open_telemetry: false,
    +        }
    +    }
    +}
    +
    +impl Default for BackgroundTasksConfig {
    +    fn default() -> Self {
    +        Self {
    +            watermark_update_ms: DEFAULT_WATERMARK_UPDATE_MS,
    +        }
    +    }
    +}
    +
    +#[cfg(test)]
    +mod tests {
    +    use super::*;
    +
    +    #[test]
    +    fn test_read_empty_service_config() {
    +        let actual = ServiceConfig::read("").unwrap();
    +        let expect = ServiceConfig::default();
    +        assert_eq!(actual, expect);
    +    }
    +
    +    #[test]
    +    fn test_read_limits_in_service_config() {
    +        let actual = ServiceConfig::read(
    +            r#" [limits]
    +                max-query-depth = 100
    +                max-query-nodes = 300
    +                max-output-nodes = 200000
    +                max-query-payload-size = 2000
    +                max-db-query-cost = 50
    +                default-page-size = 20
    +                max-page-size = 50
    +                request-timeout-ms = 27000
    +                max-type-argument-depth = 32
    +                max-type-argument-width = 64
    +                max-type-nodes = 128
    +                max-move-value-depth = 256
    +            "#,
    +        )
    +        .unwrap();
    +
    +        let expect = ServiceConfig {
    +            limits: Limits {
    +                max_query_depth: 100,
    +                max_query_nodes: 300,
    +                max_output_nodes: 200000,
    +                max_query_payload_size: 2000,
    +                max_db_query_cost: 50,
    +                default_page_size: 20,
    +                max_page_size: 50,
    +                request_timeout_ms: 27_000,
    +                max_type_argument_depth: 32,
    +                max_type_argument_width: 64,
    +                max_type_nodes: 128,
    +                max_move_value_depth: 256,
    +            },
    +            ..Default::default()
    +        };
    +
    +        assert_eq!(actual, expect)
    +    }
    +
    +    #[test]
    +    fn test_read_enabled_features_in_service_config() {
    +        let actual = ServiceConfig::read(
    +            r#" disabled-features = [
    +                  "coins",
    +                  "name-service",
    +                ]
    +            "#,
    +        )
    +        .unwrap();
    +
    +        use FunctionalGroup as G;
    +        let expect = ServiceConfig {
    +            disabled_features: BTreeSet::from([G::Coins, G::NameService]),
    +            ..Default::default()
    +        };
    +
    +        assert_eq!(actual, expect)
    +    }
    +
    +    #[test]
    +    fn test_read_experiments_in_service_config() {
    +        let actual = ServiceConfig::read(
    +            r#" [experiments]
    +                test-flag = true
    +            "#,
    +        )
    +        .unwrap();
    +
    +        let expect = ServiceConfig {
    +            experiments: Experiments { test_flag: true },
    +            ..Default::default()
    +        };
    +
    +        assert_eq!(actual, expect)
    +    }
    +
    +    #[test]
    +    fn test_read_everything_in_service_config() {
    +        let actual = ServiceConfig::read(
    +            r#" disabled-features = ["analytics"]
    +
    +                [limits]
    +                max-query-depth = 42
    +                max-query-nodes = 320
    +                max-output-nodes = 200000
    +                max-query-payload-size = 200
    +                max-db-query-cost = 20
    +                default-page-size = 10
    +                max-page-size = 20
    +                request-timeout-ms = 30000
    +                max-type-argument-depth = 32
    +                max-type-argument-width = 64
    +                max-type-nodes = 128
    +                max-move-value-depth = 256
    +
    +                [experiments]
    +                test-flag = true
    +            "#,
    +        )
    +        .unwrap();
    +
    +        let expect = ServiceConfig {
    +            limits: Limits {
    +                max_query_depth: 42,
    +                max_query_nodes: 320,
    +                max_output_nodes: 200000,
    +                max_query_payload_size: 200,
    +                max_db_query_cost: 20,
    +                default_page_size: 10,
    +                max_page_size: 20,
    +                request_timeout_ms: 30_000,
    +                max_type_argument_depth: 32,
    +                max_type_argument_width: 64,
    +                max_type_nodes: 128,
    +                max_move_value_depth: 256,
    +            },
    +            disabled_features: BTreeSet::from([FunctionalGroup::Analytics]),
    +            experiments: Experiments { test_flag: true },
    +            ..Default::default()
    +        };
    +
    +        assert_eq!(actual, expect);
    +    }
    +}
    diff --git a/crates/sui-graphql-rpc/src/consistency.rs b/crates/iota-graphql-rpc/src/consistency.rs
    similarity index 98%
    rename from crates/sui-graphql-rpc/src/consistency.rs
    rename to crates/iota-graphql-rpc/src/consistency.rs
    index 8ac0e44bcea..622face7732 100644
    --- a/crates/sui-graphql-rpc/src/consistency.rs
    +++ b/crates/iota-graphql-rpc/src/consistency.rs
    @@ -1,9 +1,10 @@
     // Copyright (c) Mysten Labs, Inc.
    +// Modifications Copyright (c) 2024 IOTA Stiftung
     // SPDX-License-Identifier: Apache-2.0
     
     use async_graphql::connection::CursorType;
    +use iota_indexer::models::objects::StoredHistoryObject;
     use serde::{Deserialize, Serialize};
    -use sui_indexer::models::objects::StoredHistoryObject;
     
     use crate::{
         data::Conn,
    diff --git a/crates/iota-graphql-rpc/src/context_data/db_data_provider.rs b/crates/iota-graphql-rpc/src/context_data/db_data_provider.rs
    new file mode 100644
    index 00000000000..8ab1dcd4646
    --- /dev/null
    +++ b/crates/iota-graphql-rpc/src/context_data/db_data_provider.rs
    @@ -0,0 +1,169 @@
    +// Copyright (c) Mysten Labs, Inc.
    +// Modifications Copyright (c) 2024 IOTA Stiftung
    +// SPDX-License-Identifier: Apache-2.0
    +
    +use std::{collections::BTreeMap, time::Duration};
    +
    +use iota_indexer::{
    +    apis::GovernanceReadApi, db::PgConnectionPoolConfig, indexer_reader::IndexerReader,
    +};
    +use iota_json_rpc_types::Stake as RpcStakedIota;
    +use iota_types::{
    +    base_types::IotaAddress as NativeIotaAddress,
    +    governance::StakedIota as NativeStakedIota,
    +    iota_system_state::iota_system_state_summary::{
    +        IotaSystemStateSummary as NativeIotaSystemStateSummary, IotaValidatorSummary,
    +    },
    +};
    +
    +use crate::{
    +    config::{DEFAULT_REQUEST_TIMEOUT_MS, DEFAULT_SERVER_DB_POOL_SIZE},
    +    error::Error,
    +    types::{address::Address, iota_address::IotaAddress, validator::Validator},
    +};
    +
    +pub(crate) struct PgManager {
    +    pub inner: IndexerReader,
    +}
    +
    +impl PgManager {
    +    pub(crate) fn new(inner: IndexerReader) -> Self {
    +        Self { inner }
    +    }
    +
    +    /// Create a new underlying reader, which is used by this type as well as
    +    /// other data providers.
    +    pub(crate) fn reader(db_url: impl Into) -> Result {
    +        Self::reader_with_config(
    +            db_url,
    +            DEFAULT_SERVER_DB_POOL_SIZE,
    +            DEFAULT_REQUEST_TIMEOUT_MS,
    +        )
    +    }
    +
    +    pub(crate) fn reader_with_config(
    +        db_url: impl Into,
    +        pool_size: u32,
    +        timeout_ms: u64,
    +    ) -> Result {
    +        let mut config = PgConnectionPoolConfig::default();
    +        config.set_pool_size(pool_size);
    +        config.set_statement_timeout(Duration::from_millis(timeout_ms));
    +        IndexerReader::new_with_config(db_url, config)
    +            .map_err(|e| Error::Internal(format!("Failed to create reader: {e}")))
    +    }
    +}
    +
    +/// Implement methods to be used by graphql resolvers
    +impl PgManager {
    +    /// Retrieve the validator APYs
    +    pub(crate) async fn fetch_validator_apys(
    +        &self,
    +        address: &NativeIotaAddress,
    +    ) -> Result, Error> {
    +        let governance_api = GovernanceReadApi::new(self.inner.clone());
    +
    +        governance_api
    +            .get_validator_apy(address)
    +            .await
    +            .map_err(|e| Error::Internal(format!("{e}")))
    +    }
    +
    +    /// If no epoch was requested or if the epoch requested is in progress,
    +    /// returns the latest iota system state.
    +    pub(crate) async fn fetch_iota_system_state(
    +        &self,
    +        epoch_id: Option,
    +    ) -> Result {
    +        let latest_iota_system_state = self
    +            .inner
    +            .spawn_blocking(move |this| this.get_latest_iota_system_state())
    +            .await?;
    +
    +        if epoch_id.is_some_and(|id| id == latest_iota_system_state.epoch) {
    +            Ok(latest_iota_system_state)
    +        } else {
    +            Ok(self
    +                .inner
    +                .spawn_blocking(move |this| this.get_epoch_iota_system_state(epoch_id))
    +                .await?)
    +        }
    +    }
    +
    +    /// Make a request to the RPC for its representations of the staked iota we
    +    /// parsed out of the object.  Used to implement fields that are
    +    /// implemented in JSON-RPC but not GraphQL (yet).
    +    pub(crate) async fn fetch_rpc_staked_iota(
    +        &self,
    +        stake: NativeStakedIota,
    +    ) -> Result {
    +        let governance_api = GovernanceReadApi::new(self.inner.clone());
    +
    +        let mut delegated_stakes = governance_api
    +            .get_delegated_stakes(vec![stake])
    +            .await
    +            .map_err(|e| Error::Internal(format!("Error fetching delegated stake. {e}")))?;
    +
    +        let Some(mut delegated_stake) = delegated_stakes.pop() else {
    +            return Err(Error::Internal(
    +                "Error fetching delegated stake. No pools returned.".to_string(),
    +            ));
    +        };
    +
    +        let Some(stake) = delegated_stake.stakes.pop() else {
    +            return Err(Error::Internal(
    +                "Error fetching delegated stake. No stake in pool.".to_string(),
    +            ));
    +        };
    +
    +        Ok(stake)
    +    }
    +}
    +
    +/// `checkpoint_viewed_at` represents the checkpoint sequence number at which
    +/// the set of `IotaValidatorSummary` was queried for. Each `Validator` will
    +/// inherit this checkpoint, so that when viewing the `Validator`'s state, it
    +/// will be as if it was read at the same checkpoint.
    +pub(crate) fn convert_to_validators(
    +    validators: Vec,
    +    system_state: Option,
    +    checkpoint_viewed_at: u64,
    +) -> Vec {
    +    let (at_risk, reports) = if let Some(NativeIotaSystemStateSummary {
    +        at_risk_validators,
    +        validator_report_records,
    +        ..
    +    }) = system_state
    +    {
    +        (
    +            BTreeMap::from_iter(at_risk_validators),
    +            BTreeMap::from_iter(validator_report_records),
    +        )
    +    } else {
    +        Default::default()
    +    };
    +
    +    validators
    +        .into_iter()
    +        .map(|validator_summary| {
    +            let at_risk = at_risk.get(&validator_summary.iota_address).copied();
    +            let report_records = reports.get(&validator_summary.iota_address).map(|addrs| {
    +                addrs
    +                    .iter()
    +                    .cloned()
    +                    .map(|a| Address {
    +                        address: IotaAddress::from(a),
    +                        checkpoint_viewed_at: Some(checkpoint_viewed_at),
    +                    })
    +                    .collect()
    +            });
    +
    +            Validator {
    +                validator_summary,
    +                at_risk,
    +                report_records,
    +                checkpoint_viewed_at,
    +            }
    +        })
    +        .collect()
    +}
    diff --git a/crates/iota-graphql-rpc/src/context_data/mod.rs b/crates/iota-graphql-rpc/src/context_data/mod.rs
    new file mode 100644
    index 00000000000..d6d1c9650c9
    --- /dev/null
    +++ b/crates/iota-graphql-rpc/src/context_data/mod.rs
    @@ -0,0 +1,6 @@
    +// Copyright (c) Mysten Labs, Inc.
    +// Modifications Copyright (c) 2024 IOTA Stiftung
    +// SPDX-License-Identifier: Apache-2.0
    +
    +pub(crate) mod db_data_provider;
    +pub(crate) mod package_cache;
    diff --git a/crates/sui-graphql-rpc/src/context_data/package_cache.rs b/crates/iota-graphql-rpc/src/context_data/package_cache.rs
    similarity index 84%
    rename from crates/sui-graphql-rpc/src/context_data/package_cache.rs
    rename to crates/iota-graphql-rpc/src/context_data/package_cache.rs
    index fe9c376ac43..bd8c4f531ff 100644
    --- a/crates/sui-graphql-rpc/src/context_data/package_cache.rs
    +++ b/crates/iota-graphql-rpc/src/context_data/package_cache.rs
    @@ -1,16 +1,17 @@
     // Copyright (c) Mysten Labs, Inc.
    +// Modifications Copyright (c) 2024 IOTA Stiftung
     // SPDX-License-Identifier: Apache-2.0
     
     use std::sync::Arc;
     
     use async_trait::async_trait;
     use diesel::{ExpressionMethods, OptionalExtension, QueryDsl, RunQueryDsl};
    -use move_core_types::account_address::AccountAddress;
    -use sui_indexer::{errors::IndexerError, indexer_reader::IndexerReader, schema::objects};
    -use sui_package_resolver::{
    +use iota_indexer::{errors::IndexerError, indexer_reader::IndexerReader, schema::objects};
    +use iota_package_resolver::{
         error::Error as PackageResolverError, Package, PackageStore, PackageStoreWithLruCache, Result,
     };
    -use sui_types::{base_types::SequenceNumber, object::Object};
    +use iota_types::{base_types::SequenceNumber, object::Object};
    +use move_core_types::account_address::AccountAddress;
     use thiserror::Error;
     
     const STORE: &str = "PostgresDB";
    @@ -51,13 +52,13 @@ impl PackageStore for DbPackageStore {
     
     async fn get_package_version_from_db(
         id: AccountAddress,
    -    sui_indexer: &IndexerReader,
    +    iota_indexer: &IndexerReader,
     ) -> Result {
         let query = objects::dsl::objects
             .select(objects::dsl::object_version)
             .filter(objects::dsl::object_id.eq(id.to_vec()));
     
    -    let Some(version) = sui_indexer
    +    let Some(version) = iota_indexer
             .run_query_async(move |conn| query.get_result::(conn).optional())
             .await
             .map_err(Error::Indexer)?
    @@ -68,12 +69,12 @@ async fn get_package_version_from_db(
         Ok(SequenceNumber::from_u64(version as u64))
     }
     
    -async fn get_package_from_db(id: AccountAddress, sui_indexer: &IndexerReader) -> Result {
    +async fn get_package_from_db(id: AccountAddress, iota_indexer: &IndexerReader) -> Result {
         let query = objects::dsl::objects
             .select(objects::dsl::serialized_object)
             .filter(objects::dsl::object_id.eq(id.to_vec()));
     
    -    let Some(bcs) = sui_indexer
    +    let Some(bcs) = iota_indexer
             .run_query_async(move |conn| query.get_result::>(conn).optional())
             .await
             .map_err(Error::Indexer)?
    diff --git a/crates/sui-graphql-rpc/src/context_data/pg_backend.rs b/crates/iota-graphql-rpc/src/context_data/pg_backend.rs
    similarity index 97%
    rename from crates/sui-graphql-rpc/src/context_data/pg_backend.rs
    rename to crates/iota-graphql-rpc/src/context_data/pg_backend.rs
    index 41d48e7851e..3707e3ee6b8 100644
    --- a/crates/sui-graphql-rpc/src/context_data/pg_backend.rs
    +++ b/crates/iota-graphql-rpc/src/context_data/pg_backend.rs
    @@ -1,4 +1,5 @@
     // Copyright (c) Mysten Labs, Inc.
    +// Modifications Copyright (c) 2024 IOTA Stiftung
     // SPDX-License-Identifier: Apache-2.0
     
     use super::{
    @@ -8,7 +9,7 @@ use super::{
     use crate::{
         context_data::db_data_provider::PgManager,
         error::Error,
    -    types::{object::DeprecatedObjectFilter, sui_address::SuiAddress},
    +    types::{object::DeprecatedObjectFilter, iota_address::IotaAddress},
     };
     use async_trait::async_trait;
     use diesel::{
    @@ -18,11 +19,11 @@ use diesel::{
         TextExpressionMethods,
     };
     use std::str::FromStr;
    -use sui_indexer::{
    +use iota_indexer::{
         schema::{display, objects},
         types::OwnerType,
     };
    -use sui_types::parse_sui_struct_tag;
    +use iota_types::parse_iota_struct_tag;
     use tap::TapFallible;
     use tracing::{info, warn};
     
    @@ -134,7 +135,7 @@ impl GenericQueryBuilder for PgQueryBuilder {
                     // We check for a leading 0x to determine if it is an address
                     // And otherwise process it as a primitive type
                     if parts[0].starts_with("0x") {
    -                    let package = SuiAddress::from_str(parts[0])
    +                    let package = IotaAddress::from_str(parts[0])
                             .map_err(|e| DbValidationError::InvalidType(e.to_string()))?;
                         query = query.filter(objects::dsl::object_type.like(format!("{}::%", package)));
                     } else {
    @@ -142,13 +143,13 @@ impl GenericQueryBuilder for PgQueryBuilder {
                     }
                 } else if parts.len() == 2 {
                     // Only package addresses are allowed if there are two or more parts
    -                let package = SuiAddress::from_str(parts[0])
    +                let package = IotaAddress::from_str(parts[0])
                         .map_err(|e| DbValidationError::InvalidType(e.to_string()))?;
                     query = query.filter(
                         objects::dsl::object_type.like(format!("{}::{}::%", package, parts[1])),
                     );
                 } else if parts.len() == 3 {
    -                let validated_type = parse_sui_struct_tag(&object_type)
    +                let validated_type = parse_iota_struct_tag(&object_type)
                         .map_err(|e| DbValidationError::InvalidType(e.to_string()))?;
     
                     if validated_type.type_params.is_empty() {
    diff --git a/crates/sui-graphql-rpc/src/data.rs b/crates/iota-graphql-rpc/src/data.rs
    similarity index 98%
    rename from crates/sui-graphql-rpc/src/data.rs
    rename to crates/iota-graphql-rpc/src/data.rs
    index be91cf36dae..631454c0aee 100644
    --- a/crates/sui-graphql-rpc/src/data.rs
    +++ b/crates/iota-graphql-rpc/src/data.rs
    @@ -1,4 +1,5 @@
     // Copyright (c) Mysten Labs, Inc.
    +// Modifications Copyright (c) 2024 IOTA Stiftung
     // SPDX-License-Identifier: Apache-2.0
     
     pub(crate) mod pg;
    diff --git a/crates/sui-graphql-rpc/src/data/pg.rs b/crates/iota-graphql-rpc/src/data/pg.rs
    similarity index 97%
    rename from crates/sui-graphql-rpc/src/data/pg.rs
    rename to crates/iota-graphql-rpc/src/data/pg.rs
    index 42c298cb1d6..4a388bb47d4 100644
    --- a/crates/sui-graphql-rpc/src/data/pg.rs
    +++ b/crates/iota-graphql-rpc/src/data/pg.rs
    @@ -1,4 +1,5 @@
     // Copyright (c) Mysten Labs, Inc.
    +// Modifications Copyright (c) 2024 IOTA Stiftung
     // SPDX-License-Identifier: Apache-2.0
     
     use std::time::Instant;
    @@ -10,7 +11,7 @@ use diesel::{
         query_dsl::LoadQuery,
         QueryResult, RunQueryDsl,
     };
    -use sui_indexer::indexer_reader::IndexerReader;
    +use iota_indexer::indexer_reader::IndexerReader;
     use tracing::error;
     
     use super::QueryExecutor;
    @@ -184,8 +185,8 @@ mod query_cost {
     #[cfg(all(test, feature = "pg_integration"))]
     mod tests {
         use diesel::QueryDsl;
    -    use sui_framework::BuiltInFramework;
    -    use sui_indexer::{
    +    use iota_framework::BuiltInFramework;
    +    use iota_indexer::{
             db::{get_pg_pool_connection, new_pg_connection_pool, reset_database},
             models::objects::StoredObject,
             schema::objects,
    diff --git a/crates/iota-graphql-rpc/src/error.rs b/crates/iota-graphql-rpc/src/error.rs
    new file mode 100644
    index 00000000000..a281f85e3c3
    --- /dev/null
    +++ b/crates/iota-graphql-rpc/src/error.rs
    @@ -0,0 +1,105 @@
    +// Copyright (c) Mysten Labs, Inc.
    +// Modifications Copyright (c) 2024 IOTA Stiftung
    +// SPDX-License-Identifier: Apache-2.0
    +
    +use async_graphql::{ErrorExtensionValues, ErrorExtensions, Pos, Response, ServerError};
    +use async_graphql_axum::GraphQLResponse;
    +use iota_indexer::errors::IndexerError;
    +use iota_json_rpc::name_service::NameServiceError;
    +
    +/// Error codes for the `extensions.code` field of a GraphQL error that
    +/// originates from outside GraphQL.
    +/// ``
    +pub(crate) mod code {
    +    pub const BAD_REQUEST: &str = "BAD_REQUEST";
    +    pub const BAD_USER_INPUT: &str = "BAD_USER_INPUT";
    +    pub const INTERNAL_SERVER_ERROR: &str = "INTERNAL_SERVER_ERROR";
    +    pub const REQUEST_TIMEOUT: &str = "REQUEST_TIMEOUT";
    +    pub const UNKNOWN: &str = "UNKNOWN";
    +}
    +
    +/// Create a GraphQL Response containing an Error.
    +///
    +/// Most errors produced by the service will automatically be wrapped in a
    +/// `GraphQLResponse`, because they will originate from within the GraphQL
    +/// implementation.  This function is intended for errors that originated from
    +/// outside of GraphQL (such as in middleware), but that need to be ingested by
    +/// GraphQL clients.
    +pub(crate) fn graphql_error_response(code: &str, message: impl Into) -> GraphQLResponse {
    +    let error = graphql_error(code, message);
    +    Response::from_errors(error.into()).into()
    +}
    +
    +/// Create a generic GraphQL Server Error.
    +///
    +/// This error has no path, source, or locations, just a message and an error
    +/// code.
    +pub(crate) fn graphql_error(code: &str, message: impl Into) -> ServerError {
    +    let mut ext = ErrorExtensionValues::default();
    +    ext.set("code", code);
    +
    +    ServerError {
    +        message: message.into(),
    +        source: None,
    +        locations: vec![],
    +        path: vec![],
    +        extensions: Some(ext),
    +    }
    +}
    +
    +pub(crate) fn graphql_error_at_pos(
    +    code: &str,
    +    message: impl Into,
    +    pos: Pos,
    +) -> ServerError {
    +    let mut ext = ErrorExtensionValues::default();
    +    ext.set("code", code);
    +
    +    ServerError {
    +        message: message.into(),
    +        source: None,
    +        locations: vec![pos],
    +        path: vec![],
    +        extensions: Some(ext),
    +    }
    +}
    +
    +#[derive(Clone, Debug, thiserror::Error)]
    +pub enum Error {
    +    #[error("Unsupported protocol version requested. Min supported: {0}, max supported: {1}")]
    +    ProtocolVersionUnsupported(u64, u64),
    +    #[error(transparent)]
    +    NameService(#[from] NameServiceError),
    +    #[error("'first' and 'last' must not be used together")]
    +    CursorNoFirstLast,
    +    #[error("Connection's page size of {0} exceeds max of {1}")]
    +    PageTooLarge(u64, u64),
    +    // Catch-all for client-fault errors
    +    #[error("{0}")]
    +    Client(String),
    +    #[error("Internal error occurred while processing request: {0}")]
    +    Internal(String),
    +}
    +
    +impl ErrorExtensions for Error {
    +    fn extend(&self) -> async_graphql::Error {
    +        async_graphql::Error::new(format!("{}", self)).extend_with(|_err, e| match self {
    +            Error::NameService(_)
    +            | Error::CursorNoFirstLast
    +            | Error::PageTooLarge(_, _)
    +            | Error::ProtocolVersionUnsupported(_, _)
    +            | Error::Client(_) => {
    +                e.set("code", code::BAD_USER_INPUT);
    +            }
    +            Error::Internal(_) => {
    +                e.set("code", code::INTERNAL_SERVER_ERROR);
    +            }
    +        })
    +    }
    +}
    +
    +impl From for Error {
    +    fn from(e: IndexerError) -> Self {
    +        Error::Internal(e.to_string())
    +    }
    +}
    diff --git a/crates/iota-graphql-rpc/src/examples.rs b/crates/iota-graphql-rpc/src/examples.rs
    new file mode 100644
    index 00000000000..3276276e902
    --- /dev/null
    +++ b/crates/iota-graphql-rpc/src/examples.rs
    @@ -0,0 +1,249 @@
    +// Copyright (c) Mysten Labs, Inc.
    +// Modifications Copyright (c) 2024 IOTA Stiftung
    +// SPDX-License-Identifier: Apache-2.0
    +
    +use std::{
    +    io::{BufWriter, Read},
    +    path::PathBuf,
    +};
    +
    +use anyhow::anyhow;
    +use markdown_gen::markdown::{AsMarkdown, Markdown};
    +
    +#[derive(Debug)]
    +pub struct ExampleQuery {
    +    pub name: String,
    +    pub contents: String,
    +    pub path: PathBuf,
    +}
    +
    +#[derive(Debug)]
    +pub struct ExampleQueryGroup {
    +    pub name: String,
    +    pub queries: Vec,
    +    pub _path: PathBuf,
    +}
    +
    +const QUERY_EXT: &str = "graphql";
    +
    +fn regularize_string(s: &str) -> String {
    +    // Replace underscore with space and make every word first letter uppercase
    +    s.replace('_', " ")
    +        .split_whitespace()
    +        .map(|word| {
    +            let mut chars = word.chars();
    +            match chars.next() {
    +                None => String::new(),
    +                Some(f) => f.to_uppercase().chain(chars).collect(),
    +            }
    +        })
    +        .collect::>()
    +        .join(" ")
    +}
    +
    +pub fn load_examples() -> anyhow::Result> {
    +    let mut buf: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    +    buf.push("examples");
    +
    +    let mut groups = vec![];
    +    for entry in std::fs::read_dir(buf).map_err(|e| anyhow::anyhow!(e))? {
    +        let entry = entry.map_err(|e| anyhow::anyhow!(e))?;
    +        let path = entry.path();
    +        let group_name = path
    +            .file_stem()
    +            .ok_or(anyhow::anyhow!("File stem cannot be read"))?
    +            .to_str()
    +            .ok_or(anyhow::anyhow!("File stem cannot be read"))?
    +            .to_string();
    +
    +        let mut group = ExampleQueryGroup {
    +            name: group_name.clone(),
    +            queries: vec![],
    +            _path: path.clone(),
    +        };
    +
    +        for file in std::fs::read_dir(path).map_err(|e| anyhow::anyhow!(e))? {
    +            assert!(file.is_ok());
    +            let file = file.map_err(|e| anyhow::anyhow!(e))?;
    +            assert!(file.path().extension().is_some());
    +            let ext = file
    +                .path()
    +                .extension()
    +                .ok_or(anyhow!("File extension cannot be read"))?
    +                .to_str()
    +                .ok_or(anyhow!("File extension cannot be read to string"))?
    +                .to_string();
    +            assert_eq!(ext, QUERY_EXT, "wrong file extension for example");
    +
    +            let file_path = file.path();
    +            let query_name = file_path
    +                .file_stem()
    +                .ok_or(anyhow!("File stem cannot be read"))?
    +                .to_str()
    +                .ok_or(anyhow!("File extension cannot be read to string"))?
    +                .to_string();
    +
    +            let mut contents = String::new();
    +            let mut fp = std::fs::File::open(file_path.clone()).map_err(|e| anyhow!(e))?;
    +            fp.read_to_string(&mut contents).map_err(|e| anyhow!(e))?;
    +            group.queries.push(ExampleQuery {
    +                name: query_name,
    +                contents,
    +                path: file_path,
    +            });
    +        }
    +        group.queries.sort_by(|x, y| x.name.cmp(&y.name));
    +
    +        groups.push(group);
    +    }
    +
    +    groups.sort_by(|x, y| x.name.cmp(&y.name));
    +    Ok(groups)
    +}
    +
    +/// This generates a markdown page with all the examples, to be used in the docs
    +/// site
    +pub fn generate_examples_for_docs() -> anyhow::Result {
    +    let groups = load_examples()?;
    +
    +    let mut output = BufWriter::new(Vec::new());
    +    let mut md = Markdown::new(&mut output);
    +    md.write(
    +        r#"---
    +title: Examples
    +description: Query examples for working with the Iota GraphQL RPC.
    +---
    +"#,
    +    )?;
    +    md.write("This page showcases a number of queries to interact with the network. These examples can also be found in the [repository](https://github.com/iotaledger/iota/tree/main/crates/iota-graphql-rpc/examples). You can use the [interactive online IDE](https://mainnet.iota.io/rpc/graphql) to run these examples.")?;
    +    for group in groups.iter() {
    +        let group_name = regularize_string(&group.name);
    +        md.write(group_name.heading(2))
    +            .map_err(|e| anyhow::anyhow!(e))?;
    +        for query in group.queries.iter() {
    +            let name = regularize_string(&query.name);
    +            md.write(name.heading(3)).map_err(|e| anyhow::anyhow!(e))?;
    +            let query = query.contents.lines().collect::>().join("\n");
    +            let content = format!("```graphql\n{}\n```", query);
    +            md.write(content.as_str()).map_err(|e| anyhow::anyhow!(e))?;
    +        }
    +    }
    +    let bytes = output.into_inner().map_err(|e| anyhow::anyhow!(e))?;
    +    Ok(String::from_utf8(bytes)
    +        .map_err(|e| anyhow::anyhow!(e))?
    +        .replace('\\', ""))
    +}
    +
    +pub fn generate_markdown() -> anyhow::Result {
    +    let groups = load_examples()?;
    +
    +    let mut output = BufWriter::new(Vec::new());
    +    let mut md = Markdown::new(&mut output);
    +
    +    md.write("Iota GraphQL Examples".heading(1))
    +        .map_err(|e| anyhow!(e))?;
    +
    +    // TODO: reduce multiple loops
    +    // Generate the table of contents
    +    for (id, group) in groups.iter().enumerate() {
    +        let group_name = regularize_string(&group.name);
    +        let group_name_toc = format!("[{}](#{})", group_name, id);
    +        md.write(group_name_toc.heading(3))
    +            .map_err(|e| anyhow!(e))?;
    +
    +        for (inner, query) in group.queries.iter().enumerate() {
    +            let inner_id = inner + 0xFFFF * id;
    +            let inner_name = regularize_string(&query.name);
    +            let inner_name_toc = format!("  [{}](#{})", inner_name, inner_id);
    +            md.write(inner_name_toc.heading(4))
    +                .map_err(|e| anyhow!(e))?;
    +        }
    +    }
    +
    +    for (id, group) in groups.iter().enumerate() {
    +        let group_name = regularize_string(&group.name);
    +
    +        let id_tag = format!("", id);
    +        md.write(id_tag.heading(2))
    +            .map_err(|e| anyhow::anyhow!(e))?;
    +        md.write(group_name.heading(2))
    +            .map_err(|e| anyhow::anyhow!(e))?;
    +        for (inner, query) in group.queries.iter().enumerate() {
    +            let inner_id = inner + 0xFFFF * id;
    +            let name = regularize_string(&query.name);
    +
    +            let id_tag = format!("", inner_id);
    +            md.write(id_tag.heading(3))
    +                .map_err(|e| anyhow::anyhow!(e))?;
    +            md.write(name.heading(3)).map_err(|e| anyhow::anyhow!(e))?;
    +
    +            // Extract all lines that start with `#` and use them as headers
    +            let mut headers = vec![];
    +            let mut query_start = 0;
    +            for (idx, line) in query.contents.lines().enumerate() {
    +                let line = line.trim();
    +                if line.starts_with('#') {
    +                    headers.push(line.trim_start_matches('#'));
    +                } else if line.starts_with('{') {
    +                    query_start = idx;
    +                    break;
    +                }
    +            }
    +
    +            // Remove headers from query
    +            let query = query
    +                .contents
    +                .lines()
    +                .skip(query_start)
    +                .collect::>()
    +                .join("\n");
    +
    +            let content = format!("
    {}
    ", query); + for header in headers { + md.write(header.heading(4)) + .map_err(|e| anyhow::anyhow!(e))?; + } + md.write(content.quote()).map_err(|e| anyhow::anyhow!(e))?; + } + } + let bytes = output.into_inner().map_err(|e| anyhow::anyhow!(e))?; + Ok(String::from_utf8(bytes) + .map_err(|e| anyhow::anyhow!(e))? + .replace('\\', "")) +} + +#[test] +fn test_generate_markdown() { + use std::fs::File; + + use similar::*; + + let mut buf: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + buf.push("docs"); + buf.push("examples.md"); + let mut out_file: File = File::open(buf).expect("Could not open examples.md"); + + // Read the current content of `out_file` + let mut current_content = String::new(); + out_file + .read_to_string(&mut current_content) + .expect("Could not read examples.md"); + let new_content: String = generate_markdown().expect("Generating examples markdown failed"); + + if current_content != new_content { + let mut res = vec![]; + let diff = TextDiff::from_lines(¤t_content, &new_content); + for change in diff.iter_all_changes() { + let sign = match change.tag() { + ChangeTag::Delete => "---", + ChangeTag::Insert => "+++", + ChangeTag::Equal => " ", + }; + res.push(format!("{}{}", sign, change)); + } + panic!( + "Doc examples have changed. Please run `iota-graphql-rpc generate-examples` to update the docs. Diff: {}", + res.join("") + ); + } +} diff --git a/crates/sui-graphql-rpc/src/extensions/feature_gate.rs b/crates/iota-graphql-rpc/src/extensions/feature_gate.rs similarity index 98% rename from crates/sui-graphql-rpc/src/extensions/feature_gate.rs rename to crates/iota-graphql-rpc/src/extensions/feature_gate.rs index e4e23d29692..74f5ae59c05 100644 --- a/crates/sui-graphql-rpc/src/extensions/feature_gate.rs +++ b/crates/iota-graphql-rpc/src/extensions/feature_gate.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; diff --git a/crates/iota-graphql-rpc/src/extensions/logger.rs b/crates/iota-graphql-rpc/src/extensions/logger.rs new file mode 100644 index 00000000000..46d2055b036 --- /dev/null +++ b/crates/iota-graphql-rpc/src/extensions/logger.rs @@ -0,0 +1,211 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{fmt::Write, net::SocketAddr, sync::Arc}; + +use async_graphql::{ + extensions::{ + Extension, ExtensionContext, ExtensionFactory, NextExecute, NextParseQuery, NextResolve, + NextValidation, ResolveInfo, + }, + parser::types::{ExecutableDocument, OperationType, Selection}, + PathSegment, Response, ServerError, ServerResult, ValidationResult, Variables, +}; +use async_graphql_value::ConstValue; +use tracing::{debug, error, info, warn}; +use uuid::Uuid; + +use crate::{error::code, metrics::Metrics}; + +#[derive(Clone, Debug)] +pub struct LoggerConfig { + pub log_request_query: bool, + pub log_response: bool, + pub log_complexity: bool, +} + +impl Default for LoggerConfig { + fn default() -> Self { + Self { + log_request_query: false, + log_response: true, + log_complexity: true, + } + } +} + +#[derive(Clone, Debug, Default)] +pub struct Logger { + config: LoggerConfig, +} + +impl ExtensionFactory for Logger { + fn create(&self) -> Arc { + Arc::new(LoggerExtension { + config: self.config.clone(), + }) + } +} + +struct LoggerExtension { + config: LoggerConfig, +} + +#[async_trait::async_trait] +impl Extension for LoggerExtension { + // This hook is used to get the top level node name for recording in the metrics + // which top level nodes are being called. + async fn resolve( + &self, + ctx: &ExtensionContext<'_>, + info: ResolveInfo<'_>, + next: NextResolve<'_>, + ) -> ServerResult> { + if info.path_node.parent.is_none() { + ctx.data_unchecked::() + .request_metrics + .num_queries_top_level + .with_label_values(&[info.name]) + .inc(); + } + next.run(ctx, info).await + } + + async fn parse_query( + &self, + ctx: &ExtensionContext<'_>, + query: &str, + variables: &Variables, + next: NextParseQuery<'_>, + ) -> ServerResult { + let document = next.run(ctx, query, variables).await?; + let is_schema = document + .operations + .iter() + .filter(|(_, operation)| operation.node.ty == OperationType::Query) + .any(|(_, operation)| operation.node.selection_set.node.items.iter().any(|selection| matches!(&selection.node, Selection::Field(field) if field.node.name.node == "__schema"))); + let query_id: &Uuid = ctx.data_unchecked(); + let session_id: &SocketAddr = ctx.data_unchecked(); + if !is_schema && self.config.log_request_query { + info!( + %query_id, + %session_id, + "[Query] {}", + ctx.stringify_execute_doc(&document, variables) + ); + } + Ok(document) + } + + async fn validation( + &self, + ctx: &ExtensionContext<'_>, + next: NextValidation<'_>, + ) -> Result> { + let res = next.run(ctx).await?; + let query_id: &Uuid = ctx.data_unchecked(); + let session_id: &SocketAddr = ctx.data_unchecked(); + if self.config.log_complexity { + info!( + %query_id, + %session_id, + complexity = res.complexity, + depth = res.depth, + "[Validation]", + ); + } + Ok(res) + } + + async fn execute( + &self, + ctx: &ExtensionContext<'_>, + operation_name: Option<&str>, + next: NextExecute<'_>, + ) -> Response { + let resp = next.run(ctx, operation_name).await; + let query_id: &Uuid = ctx.data_unchecked(); + let session_id: &SocketAddr = ctx.data_unchecked(); + if resp.is_err() { + for err in &resp.errors { + let error_code = &err.extensions.as_ref().and_then(|x| x.get("code")); + if !err.path.is_empty() { + let mut path = String::new(); + for (idx, s) in err.path.iter().enumerate() { + if idx > 0 { + path.push('.'); + } + match s { + PathSegment::Index(idx) => { + let _ = write!(&mut path, "{}", idx); + } + PathSegment::Field(name) => { + let _ = write!(&mut path, "{}", name); + } + } + } + + if let Some(async_graphql_value::ConstValue::String(error_code)) = error_code { + if error_code.as_str() == code::INTERNAL_SERVER_ERROR { + error!( + %query_id, + %session_id, + error_code, + "[Response] path={} message={}", + path, + err.message, + ); + } else { + info!( + %query_id, + %session_id, + error_code, + "[Response] path={} message={}", + path, + err.message, + ); + } + } else { + warn!( + %query_id, + %session_id, + error_code = code::UNKNOWN, + "[Response] path={} message={}", + path, + err.message, + ); + } + } else { + let error_code = if let Some(error_code) = error_code { + error_code.to_string() + } else { + code::UNKNOWN.to_string() + }; + info!( + %query_id, + %session_id, + error_code, + "[Response] message={}", err.message + ) + } + } + } else if self.config.log_response { + match operation_name { + Some("IntrospectionQuery") => { + debug!( + %query_id, + %session_id, + "[Schema] {}", resp.data + ); + } + _ => info!( + %query_id, + %session_id, + "[Response] {}", resp.data + ), + } + } + resp + } +} diff --git a/crates/iota-graphql-rpc/src/extensions/mod.rs b/crates/iota-graphql-rpc/src/extensions/mod.rs new file mode 100644 index 00000000000..dd6118523b6 --- /dev/null +++ b/crates/iota-graphql-rpc/src/extensions/mod.rs @@ -0,0 +1,8 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub(crate) mod feature_gate; +pub(crate) mod logger; +pub mod query_limits_checker; +pub(crate) mod timeout; diff --git a/crates/sui-graphql-rpc/src/extensions/query_limits_checker.rs b/crates/iota-graphql-rpc/src/extensions/query_limits_checker.rs similarity index 99% rename from crates/sui-graphql-rpc/src/extensions/query_limits_checker.rs rename to crates/iota-graphql-rpc/src/extensions/query_limits_checker.rs index aeb357d293d..c6247ef09ab 100644 --- a/crates/sui-graphql-rpc/src/extensions/query_limits_checker.rs +++ b/crates/iota-graphql-rpc/src/extensions/query_limits_checker.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -20,8 +21,8 @@ use axum::{ headers, http::{HeaderName, HeaderValue}, }; +use iota_graphql_rpc_headers::LIMITS_HEADER; use once_cell::sync::Lazy; -use sui_graphql_rpc_headers::LIMITS_HEADER; use tokio::sync::Mutex; use tracing::info; use uuid::Uuid; diff --git a/crates/sui-graphql-rpc/src/extensions/timeout.rs b/crates/iota-graphql-rpc/src/extensions/timeout.rs similarity index 98% rename from crates/sui-graphql-rpc/src/extensions/timeout.rs rename to crates/iota-graphql-rpc/src/extensions/timeout.rs index eed9ecba168..36b10850e00 100644 --- a/crates/sui-graphql-rpc/src/extensions/timeout.rs +++ b/crates/iota-graphql-rpc/src/extensions/timeout.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/sui-graphql-rpc/src/functional_group.rs b/crates/iota-graphql-rpc/src/functional_group.rs similarity index 92% rename from crates/sui-graphql-rpc/src/functional_group.rs rename to crates/iota-graphql-rpc/src/functional_group.rs index ad8d9406b15..5d25f5a5b0a 100644 --- a/crates/sui-graphql-rpc/src/functional_group.rs +++ b/crates/iota-graphql-rpc/src/functional_group.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeMap; @@ -24,7 +25,7 @@ pub(crate) enum FunctionalGroup { /// Querying an object's dynamic fields. DynamicFields, - /// SuiNS name and reverse name look-up. + /// IotaNS name and reverse name look-up. NameService, /// Transaction and Event subscriptions. @@ -72,8 +73,8 @@ fn functional_groups() -> &'static BTreeMap<(&'static str, &'static str), Functi (("Address", "balance"), G::Coins), (("Address", "balances"), G::Coins), (("Address", "coins"), G::Coins), - (("Address", "defaultSuinsName"), G::NameService), - (("Address", "suinsRegistrations"), G::NameService), + (("Address", "defaultIotansName"), G::NameService), + (("Address", "iotansRegistrations"), G::NameService), (("Checkpoint", "addressMetrics"), G::Analytics), (("Checkpoint", "networkTotalTransactions"), G::Analytics), (("Epoch", "protocolConfigs"), G::SystemState), @@ -82,24 +83,24 @@ fn functional_groups() -> &'static BTreeMap<(&'static str, &'static str), Functi (("Object", "balance"), G::Coins), (("Object", "balances"), G::Coins), (("Object", "coins"), G::Coins), - (("Object", "defaultSuinsName"), G::NameService), + (("Object", "defaultIotansName"), G::NameService), (("Object", "dynamicField"), G::DynamicFields), (("Object", "dynamicObjectField"), G::DynamicFields), (("Object", "dynamicFields"), G::DynamicFields), - (("Object", "suinsRegistrations"), G::NameService), + (("Object", "iotansRegistrations"), G::NameService), (("Owner", "balance"), G::Coins), (("Owner", "balances"), G::Coins), (("Owner", "coins"), G::Coins), - (("Owner", "defaultSuinsName"), G::NameService), + (("Owner", "defaultIotansName"), G::NameService), (("Owner", "dynamicField"), G::DynamicFields), (("Owner", "dynamicObjectField"), G::DynamicFields), (("Owner", "dynamicFields"), G::DynamicFields), - (("Owner", "suinsRegistrations"), G::NameService), + (("Owner", "iotansRegistrations"), G::NameService), (("Query", "coinMetadata"), G::Coins), (("Query", "moveCallMetrics"), G::Analytics), (("Query", "networkMetrics"), G::Analytics), (("Query", "protocolConfig"), G::SystemState), - (("Query", "resolveSuinsAddress"), G::NameService), + (("Query", "resolveIotansAddress"), G::NameService), (("Subscription", "events"), G::Subscriptions), (("Subscription", "transactions"), G::Subscriptions), (("SystemStateSummary", "safeMode"), G::SystemState), diff --git a/crates/iota-graphql-rpc/src/lib.rs b/crates/iota-graphql-rpc/src/lib.rs new file mode 100644 index 00000000000..0d6874154e1 --- /dev/null +++ b/crates/iota-graphql-rpc/src/lib.rs @@ -0,0 +1,20 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub use iota_graphql_rpc_client as client; +pub mod commands; +pub mod config; +pub(crate) mod consistency; +pub mod context_data; +pub(crate) mod data; +mod error; +pub mod examples; +pub mod extensions; +pub(crate) mod functional_group; +mod metrics; +mod mutation; +pub(crate) mod raw_query; +pub mod server; +pub mod test_infra; +mod types; diff --git a/crates/iota-graphql-rpc/src/main.rs b/crates/iota-graphql-rpc/src/main.rs new file mode 100644 index 00000000000..5ca0f243966 --- /dev/null +++ b/crates/iota-graphql-rpc/src/main.rs @@ -0,0 +1,148 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{fs, path::PathBuf}; + +use clap::Parser; +use iota_graphql_rpc::{ + commands::Command, + config::{ConnectionConfig, Ide, ServerConfig, ServiceConfig, TxExecFullNodeConfig, Version}, + server::{builder::export_schema, graphiql_server::start_graphiql_server}, +}; +use tokio_util::{sync::CancellationToken, task::TaskTracker}; + +// WARNING!!! +// +// Do not move or use similar logic to generate git revision information outside +// of a binary entry point (e.g. main.rs). Placing the below logic into a +// library can result in unnecessary builds. +const GIT_REVISION: &str = { + if let Some(revision) = option_env!("GIT_REVISION") { + revision + } else { + git_version::git_version!( + args = ["--always", "--abbrev=40", "--dirty", "--exclude", "*"], + fallback = "DIRTY" + ) + } +}; + +// VERSION mimics what other iota binaries use for the same const +static VERSION: Version = Version { + year: env!("CARGO_PKG_VERSION_MAJOR"), + month: env!("CARGO_PKG_VERSION_MINOR"), + patch: env!("CARGO_PKG_VERSION_PATCH"), + sha: GIT_REVISION, + full: const_str::concat!( + env!("CARGO_PKG_VERSION_MAJOR"), + ".", + env!("CARGO_PKG_VERSION_MINOR"), + ".", + env!("CARGO_PKG_VERSION_PATCH"), + "-", + GIT_REVISION + ), +}; + +#[tokio::main] +async fn main() { + let cmd: Command = Command::parse(); + match cmd { + Command::GenerateDocsExamples => { + let mut buf: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + // we are looking to put examples content in + // iota/docs/content/references/iota-graphql/examples.mdx + let filename = "docs/content/references/iota-graphql/examples.mdx"; + buf.pop(); + buf.pop(); + buf.push(filename); + let content = iota_graphql_rpc::examples::generate_examples_for_docs() + .expect("Generating examples markdown file for docs failed"); + std::fs::write(buf, content).expect("Writing examples markdown failed"); + println!("Generated the docs example.mdx file and copied it to {filename}."); + } + Command::GenerateSchema { file } => { + let out = export_schema(); + if let Some(file) = file { + println!("Write schema to file: {:?}", file); + std::fs::write(file, &out).unwrap(); + } else { + println!("{}", &out); + } + } + Command::GenerateExamples { file } => { + let new_content: String = iota_graphql_rpc::examples::generate_markdown() + .expect("Generating examples markdown failed"); + let mut buf: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + buf.push("docs"); + buf.push("examples.md"); + let file = file.unwrap_or(buf); + + std::fs::write(file.clone(), new_content).expect("Writing examples markdown failed"); + println!("Written examples to file: {:?}", file); + } + Command::StartServer { + ide_title, + db_url, + port, + host, + config, + node_rpc_url, + prom_host, + prom_port, + } => { + let connection = ConnectionConfig::new(port, host, db_url, None, prom_host, prom_port); + let service_config = service_config(config); + let _guard = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .init(); + let tracker = TaskTracker::new(); + let cancellation_token = CancellationToken::new(); + + println!("Starting server..."); + let server_config = ServerConfig { + connection, + service: service_config, + ide: Ide::new(ide_title), + tx_exec_full_node: TxExecFullNodeConfig::new(node_rpc_url), + ..ServerConfig::default() + }; + + let cancellation_token_clone = cancellation_token.clone(); + let graphql_service_handle = tracker.spawn(async move { + start_graphiql_server(&server_config, &VERSION, cancellation_token_clone) + .await + .unwrap(); + }); + + // Wait for shutdown signal + tokio::select! { + result = graphql_service_handle => { + if let Err(e) = result { + println!("GraphQL service crashed or exited with error: {:?}", e); + } + } + _ = tokio::signal::ctrl_c() => { + println!("Ctrl+C signal received."); + }, + } + + println!("Shutting down..."); + + // Send shutdown signal to application + cancellation_token.cancel(); + tracker.close(); + tracker.wait().await; + } + } +} + +fn service_config(path: Option) -> ServiceConfig { + let Some(path) = path else { + return ServiceConfig::default(); + }; + + let contents = fs::read_to_string(path).expect("Reading configuration"); + ServiceConfig::read(&contents).expect("Deserializing configuration") +} diff --git a/crates/iota-graphql-rpc/src/metrics.rs b/crates/iota-graphql-rpc/src/metrics.rs new file mode 100644 index 00000000000..678d501fb99 --- /dev/null +++ b/crates/iota-graphql-rpc/src/metrics.rs @@ -0,0 +1,287 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{sync::Arc, time::Duration}; + +use async_graphql::{PathSegment, ServerError}; +use prometheus::{ + register_gauge_with_registry, register_histogram_vec_with_registry, + register_histogram_with_registry, register_int_counter_vec_with_registry, + register_int_counter_with_registry, Gauge, Histogram, HistogramVec, IntCounter, IntCounterVec, + Registry, +}; + +use crate::error::code; + +// TODO: finetune buckets as we learn more about the distribution of queries +const LATENCY_SEC_BUCKETS: &[f64] = &[ + 0.001, 0.005, 0.01, 0.05, 0.1, 0.25, 0.5, 1., 2.5, 5., 10., 20., 30., 60., 90., +]; +const DB_LATENCY_SEC_BUCKETS: &[f64] = &[ + 0.001, 0.005, 0.01, 0.02, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 2.0, 3.0, + 5.0, 10.0, 20.0, 40.0, 60.0, 80.0, 100.0, 200.0, +]; +const INPUT_NODES_BUCKETS: &[f64] = &[ + 1., 2., 4., 8., 12., 16., 24., 32., 48., 64., 96., 128., 256., 512., 1024., +]; +const OUTPUT_NODES_BUCKETS: &[f64] = &[ + 100., 200., 400., 800., 1200., 1600., 2400., 3200., 4800., 6400., 9600., 12800., 25600., + 51200., 102400., +]; +const QUERY_DEPTH_BUCKETS: &[f64] = &[ + 1., 2., 4., 8., 12., 16., 24., 32., 48., 64., 96., 128., 256., 512., 1024., +]; +const QUERY_PAYLOAD_SIZE_BUCKETS: &[f64] = &[ + 10., 20., 50., 100., 200., 400., 800., 1200., 1600., 2400., 3200., 4800., 6400., 9600., 12800., + 25600., 51200., 102400., +]; +const DB_QUERY_COST_BUCKETS: &[f64] = &[ + 1., 2., 4., 8., 12., 16., 24., 32., 48., 64., 96., 128., 256., 512., 1024., +]; + +#[derive(Clone)] +pub(crate) struct Metrics { + pub db_metrics: Arc, + pub request_metrics: Arc, +} + +#[derive(Clone)] +pub(crate) struct DBMetrics { + /// The number of fetches grouped by result (success or error) + pub db_fetches: IntCounterVec, + /// The fetch latency grouped by result (success or error) + pub db_fetch_latency: HistogramVec, + // TODO make this work, blocked by pg.rs (unclear if to use log function or smth else) + pub _db_query_cost: Histogram, + // TODO determine if we want this metric, and implement it + pub _db_fetch_batch_size: HistogramVec, +} + +#[derive(Clone)] +pub(crate) struct RequestMetrics { + /// The number of nodes for the input query that passed the query limits + /// check + pub input_nodes: Histogram, + /// The number of nodes in the result + pub output_nodes: Histogram, + /// The query depth + pub query_depth: Histogram, + /// The size (in bytes) of the payload that is higher than the maximum + pub query_payload_too_large_size: Histogram, + /// The size (in bytes) of the payload + pub query_payload_size: Histogram, + /// The time it takes to validate the query + pub query_validation_latency: Histogram, + /// The time it takes for the GraphQL service to execute the request + pub query_latency: Histogram, + /// Number of errors by path and type. + pub num_errors: IntCounterVec, + /// Number of queries + pub num_queries: IntCounter, + /// Number of queries by top level path + pub num_queries_top_level: IntCounterVec, + /// Total inflight requests + pub inflight_requests: Gauge, +} + +impl Metrics { + pub(crate) fn new(registry: &Registry) -> Self { + let db_metrics = DBMetrics::new(registry); + let request_metrics = RequestMetrics::new(registry); + + Self { + db_metrics: Arc::new(db_metrics), + request_metrics: Arc::new(request_metrics), + } + } + + /// Updates the DB related metrics (latency, error, success) + pub(crate) fn observe_db_data(&self, time: Duration, succeeded: bool) { + let label = if succeeded { "success" } else { "error" }; + self.db_metrics.db_fetches.with_label_values(&[label]).inc(); + self.db_metrics + .db_fetch_latency + .with_label_values(&[label]) + .observe(time.as_secs_f64()); + } + + /// The total time needed for handling the query + pub(crate) fn query_latency(&self, time: Duration) { + self.request_metrics + .query_latency + .observe(time.as_secs_f64()); + } + + /// The time needed for validating the query + pub(crate) fn query_validation_latency(&self, time: Duration) { + self.request_metrics + .query_validation_latency + .observe(time.as_secs_f64()); + } + + /// Increment the total number of queries by one + pub(crate) fn inc_num_queries(&self) { + self.request_metrics.num_queries.inc(); + } + + /// Use this function to increment the number of errors per path and per + /// error type. The error type is detected automatically from the passed + /// errors. + pub(crate) fn inc_errors(&self, errors: &[ServerError]) { + for err in errors { + if let Some(ext) = &err.extensions { + if let Some(async_graphql_value::ConstValue::String(val)) = ext.get("code") { + self.request_metrics + .num_errors + .with_label_values(&[query_label_for_error(&err.path).as_str(), val]) + .inc(); + } + } else { + self.request_metrics + .num_errors + .with_label_values(&[query_label_for_error(&err.path).as_str(), code::UNKNOWN]) + .inc(); + } + } + } +} + +impl DBMetrics { + pub(crate) fn new(registry: &Registry) -> Self { + Self { + db_fetches: register_int_counter_vec_with_registry!( + "db_fetches", + "The number of fetches grouped by result (success or error)", + &["type"], + registry + ) + .unwrap(), + db_fetch_latency: register_histogram_vec_with_registry!( + "db_fetch_latency", + "The fetch latency grouped by result (success or error)", + &["type"], + DB_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + _db_query_cost: register_histogram_with_registry!( + "db_query_cost", + "Cost of a DB query", + DB_QUERY_COST_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + _db_fetch_batch_size: register_histogram_vec_with_registry!( + "db_fetch_batch_size", + "Number of ids fetched per batch", + &["type"], + registry, + ) + .unwrap(), + } + } +} + +impl RequestMetrics { + pub(crate) fn new(registry: &Registry) -> Self { + Self { + input_nodes: register_histogram_with_registry!( + "input_nodes", + "Number of input nodes in the query", + INPUT_NODES_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + output_nodes: register_histogram_with_registry!( + "output_nodes", + "Number of output nodes in the response", + OUTPUT_NODES_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + query_depth: register_histogram_with_registry!( + "query_depth", + "Depth of the query", + QUERY_DEPTH_BUCKETS.to_vec(), + registry + ) + .unwrap(), + query_payload_too_large_size: register_histogram_with_registry!( + "query_payload_too_large_size", + "Query payload size (bytes), that was rejected due to being larger than maximum", + QUERY_PAYLOAD_SIZE_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + query_payload_size: register_histogram_with_registry!( + "query_payload_size", + "Size of the query payload string", + QUERY_PAYLOAD_SIZE_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + query_validation_latency: register_histogram_with_registry!( + "query_validation_latency", + "The time to validate the query", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + query_latency: register_histogram_with_registry!( + "query_latency", + "The time needed to resolve and get the result for the request", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + num_errors: register_int_counter_vec_with_registry!( + "num_errors", + "Number of errors by path and error type", + &["path", "type"], + registry, + ) + .unwrap(), + num_queries: register_int_counter_with_registry!( + "num_queries", + "Total number of queries", + registry + ) + .unwrap(), + num_queries_top_level: register_int_counter_vec_with_registry!( + "num_queries_top_level", + "Number of queries for each top level node", + &["path"], + registry + ) + .unwrap(), + inflight_requests: register_gauge_with_registry!( + "inflight_requests", + "Number of queries that are being resolved at a moment in time", + registry + ) + .unwrap(), + } + } +} + +/// When an error occurs, GraphQL returns a vector of PathSegments, +/// that we can use to retrieve the last node which contains the error. +pub(crate) fn query_label_for_error(query: &[PathSegment]) -> String { + let fields: Vec<_> = query + .iter() + .filter_map(|s| { + if let PathSegment::Field(name) = s { + Some(name) + } else { + None + } + }) + .collect(); + + match &fields[..] { + [] => "".to_string(), + [seg] => seg.to_string(), + [fst, .., lst] => format!("{fst}..{lst}"), + } +} diff --git a/crates/sui-graphql-rpc/src/mutation.rs b/crates/iota-graphql-rpc/src/mutation.rs similarity index 89% rename from crates/sui-graphql-rpc/src/mutation.rs rename to crates/iota-graphql-rpc/src/mutation.rs index b7a36699c4b..b236b6824a4 100644 --- a/crates/sui-graphql-rpc/src/mutation.rs +++ b/crates/iota-graphql-rpc/src/mutation.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; @@ -6,9 +7,9 @@ use fastcrypto::{ encoding::{Base64, Encoding}, traits::ToFromBytes, }; -use sui_json_rpc_types::SuiTransactionBlockResponseOptions; -use sui_sdk::SuiClient; -use sui_types::{ +use iota_json_rpc_types::IotaTransactionBlockResponseOptions; +use iota_sdk::IotaClient; +use iota_types::{ effects::TransactionEffects as NativeTransactionEffects, event::Event as NativeEvent, quorum_driver_types::ExecuteTransactionRequestType, @@ -25,7 +26,7 @@ use crate::{ }; pub struct Mutation; -/// Mutations are used to write to the Sui network. +/// Mutations are used to write to the Iota network. #[Object] impl Mutation { /// Execute a transaction, committing its effects on chain. @@ -53,13 +54,13 @@ impl Mutation { tx_bytes: String, signatures: Vec, ) -> Result { - let sui_sdk_client: &Option = ctx + let iota_sdk_client: &Option = ctx .data() - .map_err(|_| Error::Internal("Unable to fetch Sui SDK client".to_string())) + .map_err(|_| Error::Internal("Unable to fetch Iota SDK client".to_string())) .extend()?; - let sui_sdk_client = sui_sdk_client + let iota_sdk_client = iota_sdk_client .as_ref() - .ok_or_else(|| Error::Internal("Sui SDK client not initialized".to_string())) + .ok_or_else(|| Error::Internal("Iota SDK client not initialized".to_string())) .extend()?; let tx_data = bcs::from_bytes( &Base64::decode(&tx_bytes) @@ -94,12 +95,12 @@ impl Mutation { ); } let transaction = Transaction::from_generic_sig_data(tx_data, sigs); - let options = SuiTransactionBlockResponseOptions::new() + let options = IotaTransactionBlockResponseOptions::new() .with_events() .with_raw_input() .with_raw_effects(); - let result = sui_sdk_client + let result = iota_sdk_client .quorum_driver_api() .execute_transaction_block( transaction, diff --git a/crates/sui-graphql-rpc/src/raw_query.rs b/crates/iota-graphql-rpc/src/raw_query.rs similarity index 99% rename from crates/sui-graphql-rpc/src/raw_query.rs rename to crates/iota-graphql-rpc/src/raw_query.rs index 2d026a906f8..2d4faa69ccf 100644 --- a/crates/sui-graphql-rpc/src/raw_query.rs +++ b/crates/iota-graphql-rpc/src/raw_query.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use diesel::{ diff --git a/crates/iota-graphql-rpc/src/server/builder.rs b/crates/iota-graphql-rpc/src/server/builder.rs new file mode 100644 index 00000000000..3a1227091df --- /dev/null +++ b/crates/iota-graphql-rpc/src/server/builder.rs @@ -0,0 +1,962 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + any::Any, + convert::Infallible, + net::{SocketAddr, TcpStream}, + sync::{ + atomic::{AtomicU64, Ordering::Relaxed}, + Arc, + }, + time::Instant, +}; + +use async_graphql::{ + dataloader::DataLoader, + extensions::{ApolloTracing, ExtensionFactory, Tracing}, + EmptySubscription, Schema, SchemaBuilder, ServerError, +}; +use async_graphql_axum::{GraphQLRequest, GraphQLResponse}; +use axum::{ + extract::{connect_info::IntoMakeServiceWithConnectInfo, ConnectInfo, FromRef, State}, + headers::Header, + http::{HeaderMap, StatusCode}, + middleware::{self}, + response::IntoResponse, + routing::{post, MethodRouter, Route}, + Router, +}; +use http::{HeaderValue, Method, Request}; +use hyper::{server::conn::AddrIncoming as HyperAddrIncoming, Body, Server as HyperServer}; +use iota_graphql_rpc_headers::{LIMITS_HEADER, VERSION_HEADER}; +use iota_package_resolver::{PackageStoreWithLruCache, Resolver}; +use iota_sdk::IotaClientBuilder; +use mysten_metrics::spawn_monitored_task; +use mysten_network::callback::{CallbackLayer, MakeCallbackHandler, ResponseHandler}; +use tokio::{join, sync::OnceCell}; +use tokio_util::sync::CancellationToken; +use tower::{Layer, Service}; +use tower_http::cors::{AllowOrigin, CorsLayer}; +use tracing::{error, info, warn}; +use uuid::Uuid; + +use crate::{ + config::{ + ConnectionConfig, ServerConfig, ServiceConfig, Version, MAX_CONCURRENT_REQUESTS, + RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD, + }, + consistency::CheckpointViewedAt, + context_data::{db_data_provider::PgManager, package_cache::DbPackageStore}, + data::Db, + error::Error, + extensions::{ + feature_gate::FeatureGate, + logger::Logger, + query_limits_checker::{QueryLimitsChecker, ShowUsage}, + timeout::Timeout, + }, + metrics::Metrics, + mutation::Mutation, + server::version::{check_version_middleware, set_version_middleware}, + types::{ + checkpoint::Checkpoint, + move_object::IMoveObject, + object::IObject, + owner::IOwner, + query::{IotaGraphQLSchema, Query}, + }, +}; + +pub(crate) struct Server { + pub server: HyperServer>, + /// The following fields are internally used for background tasks + checkpoint_watermark: CheckpointWatermark, + state: AppState, + db_reader: Db, +} + +impl Server { + /// Start the GraphQL service and any background tasks it is dependent on. + /// When a cancellation signal is received, the method waits for all + /// tasks to complete before returning. + pub async fn run(self) -> Result<(), Error> { + get_or_init_server_start_time().await; + + // A handle that spawns a background task to periodically update the + // `CheckpointViewedAt`, which is the u64 high watermark of checkpoints + // that the service is guaranteed to produce a consistent result for. + let watermark_task = { + let metrics = self.state.metrics.clone(); + let sleep_ms = self.state.service.background_tasks.watermark_update_ms; + let cancellation_token = self.state.cancellation_token.clone(); + info!("Starting watermark update task"); + spawn_monitored_task!(async move { + update_watermark( + &self.db_reader, + self.checkpoint_watermark, + metrics, + tokio::time::Duration::from_millis(sleep_ms), + cancellation_token, + ) + .await; + }) + }; + + let server_task = { + info!("Starting graphql service"); + let cancellation_token = self.state.cancellation_token.clone(); + spawn_monitored_task!(async move { + self.server + .with_graceful_shutdown(async { + cancellation_token.cancelled().await; + info!("Shutdown signal received, terminating graphql service"); + }) + .await + .map_err(|e| Error::Internal(format!("Server run failed: {}", e))) + }) + }; + + // Wait for both tasks to complete. This ensures that the service doesn't fully + // shut down until both the background task and the server have + // completed their shutdown processes. + let _ = join!(watermark_task, server_task); + + Ok(()) + } +} + +pub(crate) struct ServerBuilder { + state: AppState, + schema: SchemaBuilder, + router: Option, + db_reader: Option, +} + +#[derive(Clone)] +pub(crate) struct AppState { + connection: ConnectionConfig, + service: ServiceConfig, + metrics: Metrics, + cancellation_token: CancellationToken, + pub version: Version, +} + +/// The high checkpoint watermark stamped on each GraphQL request. This is used +/// to ensure cross-query consistency. +#[derive(Clone)] +pub(crate) struct CheckpointWatermark(pub Arc); + +impl AppState { + pub(crate) fn new( + connection: ConnectionConfig, + service: ServiceConfig, + metrics: Metrics, + cancellation_token: CancellationToken, + version: Version, + ) -> Self { + Self { + connection, + service, + metrics, + cancellation_token, + version, + } + } +} + +impl FromRef for ConnectionConfig { + fn from_ref(app_state: &AppState) -> ConnectionConfig { + app_state.connection.clone() + } +} + +impl FromRef for Metrics { + fn from_ref(app_state: &AppState) -> Metrics { + app_state.metrics.clone() + } +} + +impl ServerBuilder { + pub fn new(state: AppState) -> Self { + Self { + state, + schema: schema_builder(), + router: None, + db_reader: None, + } + } + + pub fn address(&self) -> String { + format!( + "{}:{}", + self.state.connection.host, self.state.connection.port + ) + } + + pub fn context_data(mut self, context_data: impl Any + Send + Sync) -> Self { + self.schema = self.schema.data(context_data); + self + } + + pub fn extension(mut self, extension: impl ExtensionFactory) -> Self { + self.schema = self.schema.extension(extension); + self + } + + fn build_schema(self) -> Schema { + self.schema.finish() + } + + /// Prepares the components of the server to be run. Finalizes the graphql + /// schema, and expects the `Db` and `Router` to have been initialized. + fn build_components( + self, + ) -> ( + String, + Schema, + Db, + Router, + ) { + let address = self.address(); + let ServerBuilder { + schema, + db_reader, + router, + .. + } = self; + ( + address, + schema.finish(), + db_reader.expect("DB reader not initialized"), + router.expect("Router not initialized"), + ) + } + + fn init_router(&mut self) { + if self.router.is_none() { + let router: Router = Router::new() + .route("/", post(graphql_handler)) + .route("/graphql", post(graphql_handler)) + .route("/health", axum::routing::get(health_checks)) + .with_state(self.state.clone()) + .route_layer(middleware::from_fn_with_state( + self.state.version, + set_version_middleware, + )) + .route_layer(middleware::from_fn_with_state( + self.state.version, + check_version_middleware, + )) + .route_layer(CallbackLayer::new(MetricsMakeCallbackHandler { + metrics: self.state.metrics.clone(), + })); + self.router = Some(router); + } + } + + pub fn route(mut self, path: &str, method_handler: MethodRouter) -> Self { + self.init_router(); + self.router = self.router.map(|router| router.route(path, method_handler)); + self + } + + pub fn layer(mut self, layer: L) -> Self + where + L: Layer + Clone + Send + 'static, + L::Service: Service> + Clone + Send + 'static, + >>::Response: IntoResponse + 'static, + >>::Error: Into + 'static, + >>::Future: Send + 'static, + { + self.init_router(); + self.router = self.router.map(|router| router.layer(layer)); + self + } + + fn cors() -> Result { + let acl = match std::env::var("ACCESS_CONTROL_ALLOW_ORIGIN") { + Ok(value) => { + let allow_hosts = value + .split(',') + .map(HeaderValue::from_str) + .collect::, _>>() + .map_err(|_| { + Error::Internal( + "Cannot resolve access control origin env variable".to_string(), + ) + })?; + AllowOrigin::list(allow_hosts) + } + _ => AllowOrigin::any(), + }; + info!("Access control allow origin set to: {acl:?}"); + + let cors = CorsLayer::new() + // Allow `POST` when accessing the resource + .allow_methods([Method::POST]) + // Allow requests from any origin + .allow_origin(acl) + .allow_headers([ + hyper::header::CONTENT_TYPE, + VERSION_HEADER.clone(), + LIMITS_HEADER.clone(), + ]); + Ok(cors) + } + + /// Consumes the `ServerBuilder` to create a `Server` that can be run. + pub fn build(self) -> Result { + let state = self.state.clone(); + let (address, schema, db_reader, router) = self.build_components(); + + // Initialize the checkpoint watermark for the background task to update. + let checkpoint_watermark = CheckpointWatermark(Arc::new(AtomicU64::new(0))); + + let app = router + .layer(axum::extract::Extension(schema)) + .layer(axum::extract::Extension(checkpoint_watermark.clone())) + .layer(Self::cors()?); + + Ok(Server { + server: axum::Server::bind( + &address + .parse() + .map_err(|_| Error::Internal(format!("Failed to parse address {}", address)))?, + ) + .serve(app.into_make_service_with_connect_info::()), + checkpoint_watermark, + state, + db_reader, + }) + } + + /// Instantiate a `ServerBuilder` from a `ServerConfig`, typically called + /// when building the graphql service for production usage. + pub async fn from_config( + config: &ServerConfig, + version: &Version, + cancellation_token: CancellationToken, + ) -> Result { + // PROMETHEUS + let prom_addr: SocketAddr = format!( + "{}:{}", + config.connection.prom_url, config.connection.prom_port + ) + .parse() + .map_err(|_| { + Error::Internal(format!( + "Failed to parse url {}, port {} into socket address", + config.connection.prom_url, config.connection.prom_port + )) + })?; + + let registry_service = mysten_metrics::start_prometheus_server(prom_addr); + info!("Starting Prometheus HTTP endpoint at {}", prom_addr); + let registry = registry_service.default_registry(); + registry + .register(mysten_metrics::uptime_metric( + "graphql", + version.full, + "unknown", + )) + .unwrap(); + + // METRICS + let metrics = Metrics::new(®istry); + let state = AppState::new( + config.connection.clone(), + config.service.clone(), + metrics.clone(), + cancellation_token, + *version, + ); + let mut builder = ServerBuilder::new(state); + + let name_service_config = config.service.name_service.clone(); + let zklogin_config = config.service.zklogin.clone(); + let reader = PgManager::reader_with_config( + config.connection.db_url.clone(), + config.connection.db_pool_size, + // Bound each statement in a request with the overall request timeout, to bound DB + // utilisation (in the worst case we will use 2x the request timeout time in DB wall + // time). + config.service.limits.request_timeout_ms, + ) + .map_err(|e| Error::Internal(format!("Failed to create pg connection pool: {}", e)))?; + + // DB + let db = Db::new(reader.clone(), config.service.limits, metrics.clone()); + let pg_conn_pool = PgManager::new(reader.clone()); + let package_store = DbPackageStore(reader.clone()); + let package_cache = PackageStoreWithLruCache::new(package_store); + builder.db_reader = Some(db.clone()); + + // SDK for talking to fullnode. Used for executing transactions only + // TODO: fail fast if no url, once we enable mutations fully + let iota_sdk_client = if let Some(url) = &config.tx_exec_full_node.node_rpc_url { + Some( + IotaClientBuilder::default() + .request_timeout(RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD) + .max_concurrent_requests(MAX_CONCURRENT_REQUESTS) + .build(url) + .await + .map_err(|e| Error::Internal(format!("Failed to create IotaClient: {}", e)))?, + ) + } else { + warn!( + "No fullnode url found in config. `dryRunTransactionBlock` and `executeTransactionBlock` will not work" + ); + None + }; + + builder = builder + .context_data(config.service.clone()) + .context_data(DataLoader::new(db.clone(), tokio::spawn)) + .context_data(db) + .context_data(pg_conn_pool) + .context_data(Resolver::new_with_limits( + package_cache, + config.service.limits.package_resolver_limits(), + )) + .context_data(iota_sdk_client) + .context_data(name_service_config) + .context_data(zklogin_config) + .context_data(metrics.clone()) + .context_data(config.clone()); + + if config.internal_features.feature_gate { + builder = builder.extension(FeatureGate); + } + if config.internal_features.logger { + builder = builder.extension(Logger::default()); + } + if config.internal_features.query_limits_checker { + builder = builder.extension(QueryLimitsChecker::default()); + } + if config.internal_features.query_timeout { + builder = builder.extension(Timeout); + } + if config.internal_features.tracing { + builder = builder.extension(Tracing); + } + if config.internal_features.apollo_tracing { + builder = builder.extension(ApolloTracing); + } + + // TODO: uncomment once impl + // if config.internal_features.open_telemetry { } + + Ok(builder) + } +} + +fn schema_builder() -> SchemaBuilder { + async_graphql::Schema::build(Query, Mutation, EmptySubscription) + .register_output_type::() + .register_output_type::() + .register_output_type::() +} + +/// Return the string representation of the schema used by this server. +pub fn export_schema() -> String { + schema_builder().finish().sdl() +} + +/// Entry point for graphql requests. Each request is stamped with a unique ID, +/// a `ShowUsage` flag if set in the request headers, and the high checkpoint +/// watermark as set by the background task. +async fn graphql_handler( + ConnectInfo(addr): ConnectInfo, + schema: axum::Extension, + watermark: axum::Extension, + headers: HeaderMap, + req: GraphQLRequest, +) -> (axum::http::Extensions, GraphQLResponse) { + let mut req = req.into_inner(); + req.data.insert(Uuid::new_v4()); + if headers.contains_key(ShowUsage::name()) { + req.data.insert(ShowUsage) + } + // Capture the IP address of the client + // Note: if a load balancer is used it must be configured to forward the client + // IP address + req.data.insert(addr); + + let checkpoint_viewed_at = watermark.0.0.load(Relaxed); + + // This wrapping is done to delineate the watermark from potentially other u64 + // types. + req.data.insert(CheckpointViewedAt(checkpoint_viewed_at)); + + let result = schema.execute(req).await; + + // If there are errors, insert them as an extention so that the Metrics callback + // handler can pull it out later. + let mut extensions = axum::http::Extensions::new(); + if result.is_err() { + extensions.insert(GraphqlErrors(std::sync::Arc::new(result.errors.clone()))); + }; + (extensions, result.into()) +} + +#[derive(Clone)] +struct MetricsMakeCallbackHandler { + metrics: Metrics, +} + +impl MakeCallbackHandler for MetricsMakeCallbackHandler { + type Handler = MetricsCallbackHandler; + + fn make_handler(&self, _request: &http::request::Parts) -> Self::Handler { + let start = Instant::now(); + let metrics = self.metrics.clone(); + + metrics.request_metrics.inflight_requests.inc(); + metrics.inc_num_queries(); + + MetricsCallbackHandler { metrics, start } + } +} + +struct MetricsCallbackHandler { + metrics: Metrics, + start: Instant, +} + +impl ResponseHandler for MetricsCallbackHandler { + fn on_response(self, response: &http::response::Parts) { + if let Some(errors) = response.extensions.get::() { + self.metrics.inc_errors(&errors.0); + } + } + + fn on_error(self, _error: &E) { + // Do nothing if the whole service errored + // + // in Axum this isn't possible since all services are required to have + // an error type of Infallible + } +} + +impl Drop for MetricsCallbackHandler { + fn drop(&mut self) { + self.metrics.query_latency(self.start.elapsed()); + self.metrics.request_metrics.inflight_requests.dec(); + } +} + +#[derive(Debug, Clone)] +struct GraphqlErrors(std::sync::Arc>); + +/// Connect via a TCPStream to the DB to check if it is alive +async fn health_checks(State(connection): State) -> StatusCode { + let Ok(url) = reqwest::Url::parse(connection.db_url.as_str()) else { + return StatusCode::INTERNAL_SERVER_ERROR; + }; + + let Some(host) = url.host_str() else { + return StatusCode::INTERNAL_SERVER_ERROR; + }; + + let tcp_url = if let Some(port) = url.port() { + format!("{host}:{port}") + } else { + host.to_string() + }; + + if TcpStream::connect(tcp_url).is_err() { + StatusCode::INTERNAL_SERVER_ERROR + } else { + StatusCode::OK + } +} + +// One server per proc, so this is okay +async fn get_or_init_server_start_time() -> &'static Instant { + static ONCE: OnceCell = OnceCell::const_new(); + ONCE.get_or_init(|| async move { Instant::now() }).await +} + +/// Starts an infinite loop that periodically updates the `checkpoint_viewed_at` +/// high watermark. +pub(crate) async fn update_watermark( + db: &Db, + checkpoint_viewed_at: CheckpointWatermark, + metrics: Metrics, + sleep_ms: tokio::time::Duration, + cancellation_token: CancellationToken, +) { + loop { + tokio::select! { + _ = cancellation_token.cancelled() => { + info!("Shutdown signal received, terminating watermark update task"); + return; + }, + _ = tokio::time::sleep(sleep_ms) => { + let new_checkpoint_viewed_at = + match Checkpoint::query_latest_checkpoint_sequence_number(db).await { + Ok(checkpoint) => Some(checkpoint), + Err(e) => { + error!("{}", e); + metrics.inc_errors(&[ServerError::new(e.to_string(), None)]); + None + } + }; + + if let Some(checkpoint) = new_checkpoint_viewed_at { + checkpoint_viewed_at.0.store(checkpoint, Relaxed); + } + } + } + } +} + +pub mod tests { + use std::{sync::Arc, time::Duration}; + + use async_graphql::{ + extensions::{Extension, ExtensionContext, NextExecute}, + Response, + }; + use uuid::Uuid; + + use super::*; + use crate::{ + config::{ConnectionConfig, Limits, ServiceConfig, Version}, + context_data::db_data_provider::PgManager, + extensions::{query_limits_checker::QueryLimitsChecker, timeout::Timeout}, + }; + + /// Prepares a schema for tests dealing with extensions. Returns a + /// `ServerBuilder` that can be further extended with `context_data` and + /// `extension` for testing. + fn prep_schema( + connection_config: Option, + service_config: Option, + ) -> ServerBuilder { + let connection_config = + connection_config.unwrap_or_else(ConnectionConfig::ci_integration_test_cfg); + let service_config = service_config.unwrap_or_default(); + + let db_url: String = connection_config.db_url.clone(); + let reader = PgManager::reader(db_url).expect("Failed to create pg connection pool"); + let version = Version::for_testing(); + let metrics = metrics(); + let db = Db::new(reader.clone(), service_config.limits, metrics.clone()); + let pg_conn_pool = PgManager::new(reader); + let cancellation_token = CancellationToken::new(); + let watermark = CheckpointViewedAt(1); + let state = AppState::new( + connection_config.clone(), + service_config.clone(), + metrics.clone(), + cancellation_token.clone(), + version, + ); + ServerBuilder::new(state) + .context_data(db) + .context_data(pg_conn_pool) + .context_data(service_config) + .context_data(query_id()) + .context_data(ip_address()) + .context_data(watermark) + .context_data(metrics) + } + + fn metrics() -> Metrics { + let binding_address: SocketAddr = "0.0.0.0:9185".parse().unwrap(); + let registry = mysten_metrics::start_prometheus_server(binding_address).default_registry(); + Metrics::new(®istry) + } + + fn ip_address() -> SocketAddr { + let binding_address: SocketAddr = "0.0.0.0:51515".parse().unwrap(); + binding_address + } + + fn query_id() -> Uuid { + Uuid::new_v4() + } + + pub async fn test_timeout_impl() { + struct TimedExecuteExt { + pub min_req_delay: Duration, + } + + impl ExtensionFactory for TimedExecuteExt { + fn create(&self) -> Arc { + Arc::new(TimedExecuteExt { + min_req_delay: self.min_req_delay, + }) + } + } + + #[async_trait::async_trait] + impl Extension for TimedExecuteExt { + async fn execute( + &self, + ctx: &ExtensionContext<'_>, + operation_name: Option<&str>, + next: NextExecute<'_>, + ) -> Response { + tokio::time::sleep(self.min_req_delay).await; + next.run(ctx, operation_name).await + } + } + + async fn test_timeout(delay: Duration, timeout: Duration) -> Response { + let mut cfg = ServiceConfig::default(); + cfg.limits.request_timeout_ms = timeout.as_millis() as u64; + + let schema = prep_schema(None, Some(cfg)) + .extension(Timeout) + .extension(TimedExecuteExt { + min_req_delay: delay, + }) + .build_schema(); + + schema.execute("{ chainIdentifier }").await + } + + let timeout = Duration::from_millis(1000); + let delay = Duration::from_millis(100); + + test_timeout(delay, timeout) + .await + .into_result() + .expect("Should complete successfully"); + + // Should timeout + let errs: Vec<_> = test_timeout(delay, delay) + .await + .into_result() + .unwrap_err() + .into_iter() + .map(|e| e.message) + .collect(); + let exp = format!("Request timed out. Limit: {}s", delay.as_secs_f32()); + assert_eq!(errs, vec![exp]); + } + + pub async fn test_query_depth_limit_impl() { + async fn exec_query_depth_limit(depth: u32, query: &str) -> Response { + let service_config = ServiceConfig { + limits: Limits { + max_query_depth: depth, + ..Default::default() + }, + ..Default::default() + }; + + let schema = prep_schema(None, Some(service_config)) + .extension(QueryLimitsChecker::default()) + .build_schema(); + schema.execute(query).await + } + + exec_query_depth_limit(1, "{ chainIdentifier }") + .await + .into_result() + .expect("Should complete successfully"); + + exec_query_depth_limit( + 5, + "{ chainIdentifier protocolConfig { configs { value key }} }", + ) + .await + .into_result() + .expect("Should complete successfully"); + + // Should fail + let errs: Vec<_> = exec_query_depth_limit(0, "{ chainIdentifier }") + .await + .into_result() + .unwrap_err() + .into_iter() + .map(|e| e.message) + .collect(); + + assert_eq!( + errs, + vec!["Query has too many levels of nesting 1. The maximum allowed is 0".to_string()] + ); + let errs: Vec<_> = exec_query_depth_limit( + 2, + "{ chainIdentifier protocolConfig { configs { value key }} }", + ) + .await + .into_result() + .unwrap_err() + .into_iter() + .map(|e| e.message) + .collect(); + assert_eq!( + errs, + vec!["Query has too many levels of nesting 3. The maximum allowed is 2".to_string()] + ); + } + + pub async fn test_query_node_limit_impl() { + async fn exec_query_node_limit(nodes: u32, query: &str) -> Response { + let service_config = ServiceConfig { + limits: Limits { + max_query_nodes: nodes, + ..Default::default() + }, + ..Default::default() + }; + + let schema = prep_schema(None, Some(service_config)) + .extension(QueryLimitsChecker::default()) + .build_schema(); + schema.execute(query).await + } + + exec_query_node_limit(1, "{ chainIdentifier }") + .await + .into_result() + .expect("Should complete successfully"); + + exec_query_node_limit( + 5, + "{ chainIdentifier protocolConfig { configs { value key }} }", + ) + .await + .into_result() + .expect("Should complete successfully"); + + // Should fail + let err: Vec<_> = exec_query_node_limit(0, "{ chainIdentifier }") + .await + .into_result() + .unwrap_err() + .into_iter() + .map(|e| e.message) + .collect(); + assert_eq!( + err, + vec!["Query has too many nodes 1. The maximum allowed is 0".to_string()] + ); + + let err: Vec<_> = exec_query_node_limit( + 4, + "{ chainIdentifier protocolConfig { configs { value key }} }", + ) + .await + .into_result() + .unwrap_err() + .into_iter() + .map(|e| e.message) + .collect(); + assert_eq!( + err, + vec!["Query has too many nodes 5. The maximum allowed is 4".to_string()] + ); + } + + pub async fn test_query_default_page_limit_impl() { + let service_config = ServiceConfig { + limits: Limits { + default_page_size: 1, + ..Default::default() + }, + ..Default::default() + }; + let schema = prep_schema(None, Some(service_config)).build_schema(); + + let resp = schema + .execute("{ checkpoints { nodes { sequenceNumber } } }") + .await; + let data = resp.data.clone().into_json().unwrap(); + let checkpoints = data + .get("checkpoints") + .unwrap() + .get("nodes") + .unwrap() + .as_array() + .unwrap(); + assert_eq!( + checkpoints.len(), + 1, + "Checkpoints should have exactly one element" + ); + + let resp = schema + .execute("{ checkpoints(first: 2) { nodes { sequenceNumber } } }") + .await; + let data = resp.data.clone().into_json().unwrap(); + let checkpoints = data + .get("checkpoints") + .unwrap() + .get("nodes") + .unwrap() + .as_array() + .unwrap(); + assert_eq!( + checkpoints.len(), + 2, + "Checkpoints should return two elements" + ); + } + + pub async fn test_query_max_page_limit_impl() { + let schema = prep_schema(None, None).build_schema(); + + schema + .execute("{ objects(first: 1) { nodes { version } } }") + .await + .into_result() + .expect("Should complete successfully"); + + // Should fail + let err: Vec<_> = schema + .execute("{ objects(first: 51) { nodes { version } } }") + .await + .into_result() + .unwrap_err() + .into_iter() + .map(|e| e.message) + .collect(); + assert_eq!( + err, + vec!["Connection's page size of 51 exceeds max of 50".to_string()] + ); + } + + pub async fn test_query_complexity_metrics_impl() { + let server_builder = prep_schema(None, None); + let metrics = server_builder.state.metrics.clone(); + let schema = server_builder + .extension(QueryLimitsChecker::default()) // QueryLimitsChecker is where we actually set the metrics + .build_schema(); + + schema + .execute("{ chainIdentifier }") + .await + .into_result() + .expect("Should complete successfully"); + + let req_metrics = metrics.request_metrics; + assert_eq!(req_metrics.input_nodes.get_sample_count(), 1); + assert_eq!(req_metrics.output_nodes.get_sample_count(), 1); + assert_eq!(req_metrics.query_depth.get_sample_count(), 1); + assert_eq!(req_metrics.input_nodes.get_sample_sum(), 1.); + assert_eq!(req_metrics.output_nodes.get_sample_sum(), 1.); + assert_eq!(req_metrics.query_depth.get_sample_sum(), 1.); + + schema + .execute("{ chainIdentifier protocolConfig { configs { value key }} }") + .await + .into_result() + .expect("Should complete successfully"); + + assert_eq!(req_metrics.input_nodes.get_sample_count(), 2); + assert_eq!(req_metrics.output_nodes.get_sample_count(), 2); + assert_eq!(req_metrics.query_depth.get_sample_count(), 2); + assert_eq!(req_metrics.input_nodes.get_sample_sum(), 2. + 4.); + assert_eq!(req_metrics.output_nodes.get_sample_sum(), 2. + 4.); + assert_eq!(req_metrics.query_depth.get_sample_sum(), 1. + 3.); + } +} diff --git a/crates/sui-graphql-rpc/src/server/graphiql_server.rs b/crates/iota-graphql-rpc/src/server/graphiql_server.rs similarity index 96% rename from crates/sui-graphql-rpc/src/server/graphiql_server.rs rename to crates/iota-graphql-rpc/src/server/graphiql_server.rs index 8ae98c24c2b..99ffb4238af 100644 --- a/crates/sui-graphql-rpc/src/server/graphiql_server.rs +++ b/crates/iota-graphql-rpc/src/server/graphiql_server.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use tokio_util::sync::CancellationToken; diff --git a/crates/iota-graphql-rpc/src/server/mod.rs b/crates/iota-graphql-rpc/src/server/mod.rs new file mode 100644 index 00000000000..5fb95acd6ff --- /dev/null +++ b/crates/iota-graphql-rpc/src/server/mod.rs @@ -0,0 +1,8 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod graphiql_server; + +pub mod builder; +pub mod version; diff --git a/crates/sui-graphql-rpc/src/server/version.rs b/crates/iota-graphql-rpc/src/server/version.rs similarity index 94% rename from crates/sui-graphql-rpc/src/server/version.rs rename to crates/iota-graphql-rpc/src/server/version.rs index 691d6f1ba75..516e416e2f0 100644 --- a/crates/sui-graphql-rpc/src/server/version.rs +++ b/crates/iota-graphql-rpc/src/server/version.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use axum::{ @@ -15,11 +16,11 @@ use crate::{ error::{code, graphql_error_response}, }; -pub(crate) static VERSION_HEADER: HeaderName = HeaderName::from_static("x-sui-rpc-version"); +pub(crate) static VERSION_HEADER: HeaderName = HeaderName::from_static("x-iota-rpc-version"); -pub(crate) struct SuiRpcVersion(Vec, Vec>); +pub(crate) struct IotaRpcVersion(Vec, Vec>); -impl headers::Header for SuiRpcVersion { +impl headers::Header for IotaRpcVersion { fn name() -> &'static HeaderName { &VERSION_HEADER } @@ -37,7 +38,7 @@ impl headers::Header for SuiRpcVersion { // Extract the header values as bytes. Distinguish the first value as we expect // there to be just one under normal operation. Do not attempt to parse // the value, as a header parsing failure produces a generic error. - Ok(SuiRpcVersion(value, values.collect())) + Ok(IotaRpcVersion(value, values.collect())) } fn encode>(&self, _values: &mut E) { @@ -51,12 +52,12 @@ impl headers::Header for SuiRpcVersion { /// software, and it is the responsibility of the load balancer to make sure /// version constraints are met. pub(crate) async fn check_version_middleware( - user_version: Option>, + user_version: Option>, State(version): State, request: Request, next: Next, ) -> Response { - if let Some(TypedHeader(SuiRpcVersion(req_version, rest))) = user_version { + if let Some(TypedHeader(IotaRpcVersion(req_version, rest))) = user_version { if !rest.is_empty() { return ( StatusCode::BAD_REQUEST, @@ -311,7 +312,7 @@ mod tests { "data": null, "errors": [ { - "message": "Failed to parse x-sui-rpc-version: Multiple possible versions found.", + "message": "Failed to parse x-iota-rpc-version: Multiple possible versions found.", "extensions": { "code": "BAD_REQUEST" } @@ -341,7 +342,7 @@ mod tests { "data": null, "errors": [ { - "message": "Failed to parse x-sui-rpc-version: 'not-a-version' not a valid . version.", + "message": "Failed to parse x-iota-rpc-version: 'not-a-version' not a valid . version.", "extensions": { "code": "BAD_REQUEST" } @@ -374,7 +375,7 @@ mod tests { "data": null, "errors": [ { - "message": "Failed to parse x-sui-rpc-version: Not a UTF8 string.", + "message": "Failed to parse x-iota-rpc-version: Not a UTF8 string.", "extensions": { "code": "BAD_REQUEST" } diff --git a/crates/iota-graphql-rpc/src/test_infra/cluster.rs b/crates/iota-graphql-rpc/src/test_infra/cluster.rs new file mode 100644 index 00000000000..8ad0ffa63aa --- /dev/null +++ b/crates/iota-graphql-rpc/src/test_infra/cluster.rs @@ -0,0 +1,359 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{net::SocketAddr, sync::Arc, time::Duration}; + +use iota_graphql_rpc_client::simple_client::SimpleClient; +pub use iota_indexer::handlers::objects_snapshot_processor::SnapshotLagConfig; +use iota_indexer::{ + errors::IndexerError, + store::{indexer_store::IndexerStore, PgIndexerStore}, + test_utils::{ + force_delete_database, start_test_indexer, start_test_indexer_impl, ReaderWriterConfig, + }, +}; +use iota_swarm_config::genesis_config::{AccountConfig, DEFAULT_GAS_AMOUNT}; +use iota_types::storage::ReadStore; +use test_cluster::{TestCluster, TestClusterBuilder}; +use tokio::task::JoinHandle; +use tokio_util::sync::CancellationToken; + +use crate::{ + config::{ConnectionConfig, ServerConfig, ServiceConfig, Version}, + server::graphiql_server::start_graphiql_server, +}; + +const VALIDATOR_COUNT: usize = 7; +const EPOCH_DURATION_MS: u64 = 15000; + +const ACCOUNT_NUM: usize = 20; +const GAS_OBJECT_COUNT: usize = 3; + +pub const DEFAULT_INTERNAL_DATA_SOURCE_PORT: u16 = 3000; + +pub struct ExecutorCluster { + pub executor_server_handle: JoinHandle<()>, + pub indexer_store: PgIndexerStore, + pub indexer_join_handle: JoinHandle>, + pub graphql_server_join_handle: JoinHandle<()>, + pub graphql_client: SimpleClient, + pub snapshot_config: SnapshotLagConfig, + pub graphql_connection_config: ConnectionConfig, + pub cancellation_token: CancellationToken, +} + +pub struct Cluster { + pub validator_fullnode_handle: TestCluster, + pub indexer_store: PgIndexerStore, + pub indexer_join_handle: JoinHandle>, + pub graphql_server_join_handle: JoinHandle<()>, + pub graphql_client: SimpleClient, +} + +/// Starts a validator, fullnode, indexer, and graphql service for testing. +pub async fn start_cluster( + graphql_connection_config: ConnectionConfig, + internal_data_source_rpc_port: Option, +) -> Cluster { + let db_url = graphql_connection_config.db_url.clone(); + // Starts validator+fullnode + let val_fn = start_validator_with_fullnode(internal_data_source_rpc_port).await; + + // Starts indexer + let (pg_store, pg_handle) = start_test_indexer( + Some(db_url), + val_fn.rpc_url().to_string(), + ReaderWriterConfig::writer_mode(None), + ) + .await; + + // Starts graphql server + let fn_rpc_url = val_fn.rpc_url().to_string(); + let graphql_server_handle = start_graphql_server_with_fn_rpc( + graphql_connection_config.clone(), + Some(fn_rpc_url), + // cancellation_token + None, + ) + .await; + + let server_url = format!( + "http://{}:{}/", + graphql_connection_config.host, graphql_connection_config.port + ); + + // Starts graphql client + let client = SimpleClient::new(server_url); + wait_for_graphql_server(&client).await; + + Cluster { + validator_fullnode_handle: val_fn, + indexer_store: pg_store, + indexer_join_handle: pg_handle, + graphql_server_join_handle: graphql_server_handle, + graphql_client: client, + } +} + +/// Takes in a simulated instantiation of a Iota blockchain and builds a cluster +/// around it. This cluster is typically used in e2e tests to emulate and test +/// behaviors. +pub async fn serve_executor( + graphql_connection_config: ConnectionConfig, + internal_data_source_rpc_port: u16, + executor: Arc, + snapshot_config: Option, +) -> ExecutorCluster { + let db_url = graphql_connection_config.db_url.clone(); + let cancellation_token = CancellationToken::new(); + + let executor_server_url: SocketAddr = format!("127.0.0.1:{}", internal_data_source_rpc_port) + .parse() + .unwrap(); + + let executor_server_handle = tokio::spawn(async move { + let chain_id = (*executor + .get_checkpoint_by_sequence_number(0) + .unwrap() + .unwrap() + .digest()) + .into(); + + iota_rest_api::RestService::new_without_version(executor, chain_id) + .start_service(executor_server_url, Some("/rest".to_owned())) + .await; + }); + + let (pg_store, pg_handle) = start_test_indexer_impl( + Some(db_url), + format!("http://{}", executor_server_url), + ReaderWriterConfig::writer_mode(snapshot_config.clone()), + Some(graphql_connection_config.db_name()), + ) + .await; + + // Starts graphql server + let graphql_server_handle = start_graphql_server( + graphql_connection_config.clone(), + cancellation_token.clone(), + ) + .await; + + let server_url = format!( + "http://{}:{}/", + graphql_connection_config.host, graphql_connection_config.port + ); + + // Starts graphql client + let client = SimpleClient::new(server_url); + wait_for_graphql_server(&client).await; + + ExecutorCluster { + executor_server_handle, + indexer_store: pg_store, + indexer_join_handle: pg_handle, + graphql_server_join_handle: graphql_server_handle, + graphql_client: client, + snapshot_config: snapshot_config.unwrap_or_default(), + graphql_connection_config, + cancellation_token, + } +} + +pub async fn start_graphql_server( + graphql_connection_config: ConnectionConfig, + cancellation_token: CancellationToken, +) -> JoinHandle<()> { + start_graphql_server_with_fn_rpc(graphql_connection_config, None, Some(cancellation_token)) + .await +} + +pub async fn start_graphql_server_with_fn_rpc( + graphql_connection_config: ConnectionConfig, + fn_rpc_url: Option, + cancellation_token: Option, +) -> JoinHandle<()> { + let cancellation_token = cancellation_token.unwrap_or_default(); + let mut server_config = ServerConfig { + connection: graphql_connection_config, + service: ServiceConfig::test_defaults(), + ..ServerConfig::default() + }; + if let Some(fn_rpc_url) = fn_rpc_url { + server_config.tx_exec_full_node.node_rpc_url = Some(fn_rpc_url); + }; + + // Starts graphql server + tokio::spawn(async move { + start_graphiql_server(&server_config, &Version::for_testing(), cancellation_token) + .await + .unwrap(); + }) +} + +async fn start_validator_with_fullnode(internal_data_source_rpc_port: Option) -> TestCluster { + let mut test_cluster_builder = TestClusterBuilder::new() + .with_num_validators(VALIDATOR_COUNT) + .with_epoch_duration_ms(EPOCH_DURATION_MS) + .with_accounts(vec![ + AccountConfig { + address: None, + gas_amounts: vec![DEFAULT_GAS_AMOUNT; GAS_OBJECT_COUNT], + }; + ACCOUNT_NUM + ]); + + if let Some(internal_data_source_rpc_port) = internal_data_source_rpc_port { + test_cluster_builder = + test_cluster_builder.with_fullnode_rpc_port(internal_data_source_rpc_port); + }; + test_cluster_builder.build().await +} + +/// Repeatedly ping the GraphQL server for 10s, until it responds +async fn wait_for_graphql_server(client: &SimpleClient) { + tokio::time::timeout(Duration::from_secs(10), async { + while client.ping().await.is_err() { + tokio::time::sleep(Duration::from_millis(500)).await; + } + }) + .await + .expect("Timeout waiting for graphql server to start"); +} + +/// Ping the GraphQL server until its background task has updated the checkpoint +/// watermark to the desired checkpoint. +async fn wait_for_graphql_checkpoint_catchup( + client: &SimpleClient, + checkpoint: u64, + base_timeout: Duration, +) { + let query = r#" + { + availableRange { + last { + sequenceNumber + } + } + }"#; + + let timeout = base_timeout.mul_f64(checkpoint.max(1) as f64); + + tokio::time::timeout(timeout, async { + loop { + let resp = client + .execute_to_graphql(query.to_string(), false, vec![], vec![]) + .await + .unwrap() + .response_body_json(); + + let current_checkpoint = resp["data"]["availableRange"]["last"].get("sequenceNumber"); + + // Indexer has not picked up any checkpoints yet + let Some(current_checkpoint) = current_checkpoint else { + tokio::time::sleep(Duration::from_secs(1)).await; + continue; + }; + + // Indexer has picked up a checkpoint, but it's not the one we're waiting for + let current_checkpoint = current_checkpoint.as_u64().unwrap(); + if current_checkpoint < checkpoint { + tokio::time::sleep(Duration::from_secs(1)).await; + } else { + break; + } + } + }) + .await + .expect("Timeout waiting for graphql to catchup to checkpoint"); +} + +impl Cluster { + /// Waits for the indexer to index up to the given checkpoint, then waits + /// for the graphql service's background task to update the checkpoint + /// watermark to the given checkpoint. + pub async fn wait_for_checkpoint_catchup(&self, checkpoint: u64, base_timeout: Duration) { + wait_for_graphql_checkpoint_catchup(&self.graphql_client, checkpoint, base_timeout).await + } +} + +impl ExecutorCluster { + /// Waits for the indexer to index up to the given checkpoint, then waits + /// for the graphql service's background task to update the checkpoint + /// watermark to the given checkpoint. + pub async fn wait_for_checkpoint_catchup(&self, checkpoint: u64, base_timeout: Duration) { + wait_for_graphql_checkpoint_catchup(&self.graphql_client, checkpoint, base_timeout).await + } + + /// The ObjectsSnapshotProcessor is a long-running task that periodically + /// takes a snapshot of the objects table. This leads to flakiness in + /// tests, so we wait until the objects_snapshot has reached the + /// expected state. + pub async fn wait_for_objects_snapshot_catchup(&self, base_timeout: Duration) { + let mut latest_snapshot_cp = 0; + + let latest_cp = self + .indexer_store + .get_latest_tx_checkpoint_sequence_number() + .await + .unwrap() + .unwrap(); + + tokio::time::timeout(base_timeout, async { + while latest_cp > latest_snapshot_cp + self.snapshot_config.snapshot_max_lag as u64 { + tokio::time::sleep(Duration::from_secs(1)).await; + latest_snapshot_cp = self + .indexer_store + .get_latest_object_snapshot_checkpoint_sequence_number() + .await + .unwrap() + .unwrap_or_default(); + } + }) + .await + .unwrap_or_else(|_| panic!("Timeout waiting for indexer to update objects snapshot - latest_cp: {}, latest_snapshot_cp: {}", + latest_cp, latest_snapshot_cp)); + } + + /// Deletes the database created for the test and sends a cancellation + /// signal to the graphql service. When this function is awaited on, the + /// callsite will wait for the graphql service to terminate its + /// background task and then itself. + pub async fn cleanup_resources(self) { + self.cancellation_token.cancel(); + let db_url = self.graphql_connection_config.db_url.clone(); + force_delete_database(db_url).await; + } + + pub async fn force_objects_snapshot_catchup(&self, start_cp: u64, end_cp: u64) { + self.indexer_store + .persist_object_snapshot(start_cp, end_cp) + .await + .unwrap(); + + let mut latest_snapshot_cp = self + .indexer_store + .get_latest_object_snapshot_checkpoint_sequence_number() + .await + .unwrap() + .unwrap_or_default(); + + tokio::time::timeout(Duration::from_secs(60), async { + while latest_snapshot_cp < end_cp - 1 { + tokio::time::sleep(Duration::from_secs(1)).await; + latest_snapshot_cp = self + .indexer_store + .get_latest_object_snapshot_checkpoint_sequence_number() + .await + .unwrap() + .unwrap_or_default(); + } + }) + .await + .unwrap_or_else(|_| panic!("Timeout waiting for indexer to update objects snapshot - latest_snapshot_cp: {}, end_cp: {}", + latest_snapshot_cp, end_cp)); + + tokio::time::sleep(Duration::from_secs(5)).await; + } +} diff --git a/crates/iota-graphql-rpc/src/test_infra/mod.rs b/crates/iota-graphql-rpc/src/test_infra/mod.rs new file mode 100644 index 00000000000..d64ab07b1e7 --- /dev/null +++ b/crates/iota-graphql-rpc/src/test_infra/mod.rs @@ -0,0 +1,5 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod cluster; diff --git a/crates/iota-graphql-rpc/src/types/address.rs b/crates/iota-graphql-rpc/src/types/address.rs new file mode 100644 index 00000000000..4dda5827987 --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/address.rs @@ -0,0 +1,192 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_graphql::{connection::Connection, *}; + +use super::{ + balance::{self, Balance}, + coin::Coin, + cursor::Page, + iota_address::IotaAddress, + iotans_registration::{DomainFormat, IotansRegistration}, + move_object::MoveObject, + object::{self, ObjectFilter}, + owner::OwnerImpl, + stake::StakedIota, + transaction_block::{self, TransactionBlock, TransactionBlockFilter}, + type_filter::ExactTypeFilter, +}; + +#[derive(Clone, Debug, PartialEq, Eq, Copy)] +pub(crate) struct Address { + pub address: IotaAddress, + /// The checkpoint sequence number at which this was viewed at, or None if + /// the data was requested at the latest checkpoint. + pub checkpoint_viewed_at: Option, +} + +/// The possible relationship types for a transaction block: sign, sent, +/// received, or paid. +#[derive(Enum, Copy, Clone, Eq, PartialEq)] +pub(crate) enum AddressTransactionBlockRelationship { + /// Transactions this address has signed either as a sender or as a sponsor. + Sign, + /// Transactions that sent objects to this address. + Recv, +} + +/// The 32-byte address that is an account address (corresponding to a public +/// key). +#[Object] +impl Address { + pub(crate) async fn address(&self) -> IotaAddress { + OwnerImpl::from(self).address().await + } + + /// Objects owned by this address, optionally `filter`-ed. + pub(crate) async fn objects( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + filter: Option, + ) -> Result> { + OwnerImpl::from(self) + .objects(ctx, first, after, last, before, filter) + .await + } + + /// Total balance of all coins with marker type owned by this address. If + /// type is not supplied, it defaults to `0x2::iota::IOTA`. + pub(crate) async fn balance( + &self, + ctx: &Context<'_>, + type_: Option, + ) -> Result> { + OwnerImpl::from(self).balance(ctx, type_).await + } + + /// The balances of all coin types owned by this address. + pub(crate) async fn balances( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(self) + .balances(ctx, first, after, last, before) + .await + } + + /// The coin objects for this address. + /// + /// `type` is a filter on the coin's type parameter, defaulting to + /// `0x2::iota::IOTA`. + pub(crate) async fn coins( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + type_: Option, + ) -> Result> { + OwnerImpl::from(self) + .coins(ctx, first, after, last, before, type_) + .await + } + + /// The `0x3::staking_pool::StakedIota` objects owned by this address. + pub(crate) async fn staked_iotas( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(self) + .staked_iotas(ctx, first, after, last, before) + .await + } + + /// The domain explicitly configured as the default domain pointing to this + /// address. + pub(crate) async fn default_iotans_name( + &self, + ctx: &Context<'_>, + format: Option, + ) -> Result> { + OwnerImpl::from(self).default_iotans_name(ctx, format).await + } + + /// The IotansRegistration NFTs owned by this address. These grant the owner + /// the capability to manage the associated domain. + pub(crate) async fn iotans_registrations( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(self) + .iotans_registrations(ctx, first, after, last, before) + .await + } + + /// Similar behavior to the `transactionBlocks` in Query but supporting the + /// additional `AddressTransactionBlockRelationship` filter, which + /// defaults to `SIGN`. + async fn transaction_blocks( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + relation: Option, + filter: Option, + ) -> Result> { + use AddressTransactionBlockRelationship as R; + let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; + + let Some(filter) = filter.unwrap_or_default().intersect(match relation { + // Relationship defaults to "signer" if none is supplied. + Some(R::Sign) | None => TransactionBlockFilter { + sign_address: Some(self.address), + ..Default::default() + }, + + Some(R::Recv) => TransactionBlockFilter { + recv_address: Some(self.address), + ..Default::default() + }, + }) else { + return Ok(Connection::new(false, false)); + }; + + TransactionBlock::paginate( + ctx.data_unchecked(), + page, + filter, + self.checkpoint_viewed_at, + ) + .await + .extend() + } +} + +impl From<&Address> for OwnerImpl { + fn from(address: &Address) -> Self { + OwnerImpl { + address: address.address, + checkpoint_viewed_at: address.checkpoint_viewed_at, + } + } +} diff --git a/crates/sui-graphql-rpc/src/types/available_range.rs b/crates/iota-graphql-rpc/src/types/available_range.rs similarity index 94% rename from crates/sui-graphql-rpc/src/types/available_range.rs rename to crates/iota-graphql-rpc/src/types/available_range.rs index d269e47ceb1..21c278c326d 100644 --- a/crates/sui-graphql-rpc/src/types/available_range.rs +++ b/crates/iota-graphql-rpc/src/types/available_range.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; diff --git a/crates/iota-graphql-rpc/src/types/balance.rs b/crates/iota-graphql-rpc/src/types/balance.rs new file mode 100644 index 00000000000..d86f87753d4 --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/balance.rs @@ -0,0 +1,288 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::str::FromStr; + +use async_graphql::{ + connection::{Connection, CursorType, Edge}, + *, +}; +use diesel::{ + sql_types::{BigInt as SqlBigInt, Nullable, Text}, + OptionalExtension, QueryableByName, +}; +use iota_indexer::types::OwnerType; +use iota_types::{parse_iota_type_tag, TypeTag}; +use serde::{Deserialize, Serialize}; + +use super::{ + big_int::BigInt, + cursor::{self, Page, RawPaginated, Target}, + iota_address::IotaAddress, + move_type::MoveType, +}; +use crate::{ + consistency::{consistent_range, Checkpointed}, + data::{Db, DbConnection, QueryExecutor}, + error::Error, + filter, query, + raw_query::RawQuery, +}; + +/// The total balance for a particular coin type. +#[derive(Clone, Debug, SimpleObject)] +pub(crate) struct Balance { + /// Coin type for the balance, such as 0x2::iota::IOTA + pub(crate) coin_type: MoveType, + /// How many coins of this type constitute the balance + pub(crate) coin_object_count: Option, + /// Total balance across all coin objects of the coin type + pub(crate) total_balance: Option, +} + +/// Representation of a row of balance information from the DB. We read the +/// balance as a `String` to deal with the large (bigger than 2^63 - 1) +/// balances. +#[derive(QueryableByName)] +pub struct StoredBalance { + #[diesel(sql_type = Nullable)] + pub balance: Option, + #[diesel(sql_type = Nullable)] + pub count: Option, + #[diesel(sql_type = Text)] + pub coin_type: String, +} + +pub(crate) type Cursor = cursor::JsonCursor; + +/// The inner struct for the `Balance`'s cursor. The `coin_type` is used as the +/// cursor, while the `checkpoint_viewed_at` sets the consistent upper bound for +/// the cursor. +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)] +pub(crate) struct BalanceCursor { + #[serde(rename = "t")] + coin_type: String, + /// The checkpoint sequence number this was viewed at. + #[serde(rename = "c")] + checkpoint_viewed_at: u64, +} + +impl Balance { + /// Query for the balance of coins owned by `address`, of coins with type + /// `coin_type`. Note that `coin_type` is the type of + /// `0x2::coin::Coin`'s type parameter, not the full type of the coin + /// object. + pub(crate) async fn query( + db: &Db, + address: IotaAddress, + coin_type: TypeTag, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + let stored: Option = db + .execute_repeatable(move |conn| { + let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { + return Ok::<_, diesel::result::Error>(None); + }; + + conn.result(move || { + balance_query(address, Some(coin_type.clone()), lhs as i64, rhs as i64) + .into_boxed() + }) + .optional() + }) + .await?; + + stored.map(Balance::try_from).transpose() + } + + /// Query the database for a `page` of coin balances. Each balance + /// represents the total balance for a particular coin type, owned by + /// `address`. + pub(crate) async fn paginate( + db: &Db, + page: Page, + address: IotaAddress, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + // If cursors are provided, defer to the `checkpoint_viewed_at` in the cursor if + // they are consistent. Otherwise, use the value from the parameter, or + // set to None. This is so that paginated queries are consistent with + // the previous query that created the cursor. + let cursor_viewed_at = page.validate_cursor_consistency()?; + let checkpoint_viewed_at: Option = cursor_viewed_at.or(checkpoint_viewed_at); + + let response = db + .execute_repeatable(move |conn| { + let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { + return Ok::<_, diesel::result::Error>(None); + }; + + let result = page.paginate_raw_query::( + conn, + rhs, + balance_query(address, None, lhs as i64, rhs as i64), + )?; + + Ok(Some((result, rhs))) + }) + .await?; + + let Some(((prev, next, results), checkpoint_viewed_at)) = response else { + return Err(Error::Client( + "Requested data is outside the available range".to_string(), + )); + }; + + let mut conn = Connection::new(prev, next); + + for stored in results { + let cursor = stored.cursor(checkpoint_viewed_at).encode_cursor(); + let balance = Balance::try_from(stored)?; + conn.edges.push(Edge::new(cursor, balance)); + } + + Ok(conn) + } +} + +impl RawPaginated for StoredBalance { + fn filter_ge(cursor: &Cursor, query: RawQuery) -> RawQuery { + filter!(query, "coin_type >= {}", cursor.coin_type.clone()) + } + + fn filter_le(cursor: &Cursor, query: RawQuery) -> RawQuery { + filter!(query, "coin_type <= {}", cursor.coin_type.clone()) + } + + fn order(asc: bool, query: RawQuery) -> RawQuery { + if asc { + return query.order_by("coin_type ASC"); + } + query.order_by("coin_type DESC") + } +} + +impl Target for StoredBalance { + fn cursor(&self, checkpoint_viewed_at: u64) -> Cursor { + Cursor::new(BalanceCursor { + coin_type: self.coin_type.clone(), + checkpoint_viewed_at, + }) + } +} + +impl Checkpointed for Cursor { + fn checkpoint_viewed_at(&self) -> u64 { + self.checkpoint_viewed_at + } +} + +impl TryFrom for Balance { + type Error = Error; + + fn try_from(s: StoredBalance) -> Result { + let StoredBalance { + balance, + count, + coin_type, + } = s; + let total_balance = balance + .map(|b| BigInt::from_str(&b)) + .transpose() + .map_err(|_| Error::Internal("Failed to read balance.".to_string()))?; + + let coin_object_count = count.map(|c| c as u64); + + let coin_type = MoveType::new( + parse_iota_type_tag(&coin_type) + .map_err(|e| Error::Internal(format!("Failed to parse coin type: {e}")))?, + ); + + Ok(Balance { + coin_type, + coin_object_count, + total_balance, + }) + } +} + +/// Query the database for a `page` of coin balances. Each balance represents +/// the total balance for a particular coin type, owned by `address`. This +/// function is meant to be called within a thunk and returns a RawQuery that +/// can be converted into a BoxedSqlQuery with `.into_boxed()`. +fn balance_query(address: IotaAddress, coin_type: Option, lhs: i64, rhs: i64) -> RawQuery { + // Construct the filtered inner query - apply the same filtering criteria to + // both objects_snapshot and objects_history tables. + let mut snapshot_objs = query!("SELECT * FROM objects_snapshot"); + snapshot_objs = filter(snapshot_objs, address, coin_type.clone()); + + // Additionally filter objects_history table for results between the available + // range, or checkpoint_viewed_at, if provided. + let mut history_objs = query!("SELECT * FROM objects_history"); + history_objs = filter(history_objs, address, coin_type.clone()); + history_objs = filter!( + history_objs, + format!(r#"checkpoint_sequence_number BETWEEN {} AND {}"#, lhs, rhs) + ); + + // Combine the two queries, and select the most recent version of each object. + let candidates = query!( + r#"SELECT DISTINCT ON (object_id) * FROM (({}) UNION ALL ({})) o"#, + snapshot_objs, + history_objs + ) + .order_by("object_id") + .order_by("object_version DESC"); + + // Objects that fulfill the filtering criteria may not be the most recent + // version available. Left join the candidates table on newer to filter out + // any objects that have a newer version. + let mut newer = query!("SELECT object_id, object_version FROM objects_history"); + newer = filter!( + newer, + format!(r#"checkpoint_sequence_number BETWEEN {} AND {}"#, lhs, rhs) + ); + let final_ = query!( + r#"SELECT + CAST(SUM(coin_balance) AS TEXT) as balance, + COUNT(*) as count, + coin_type + FROM ({}) candidates + LEFT JOIN ({}) newer + ON ( + candidates.object_id = newer.object_id + AND candidates.object_version < newer.object_version + )"#, + candidates, + newer + ); + + // Additionally for balance's query, group coins by coin_type. + filter!(final_, "newer.object_version IS NULL").group_by("coin_type") +} + +/// Applies the filtering criteria for balances to the input `RawQuery` and +/// returns a new `RawQuery`. +fn filter(mut query: RawQuery, owner: IotaAddress, coin_type: Option) -> RawQuery { + query = filter!(query, "coin_type IS NOT NULL"); + + query = filter!( + query, + format!( + "owner_id = '\\x{}'::bytea AND owner_type = {}", + hex::encode(owner.into_vec()), + OwnerType::Address as i16 + ) + ); + + if let Some(coin_type) = coin_type { + query = filter!( + query, + "coin_type = {}", + coin_type.to_canonical_display(/* with_prefix */ true) + ); + }; + + query +} diff --git a/crates/sui-graphql-rpc/src/types/balance_change.rs b/crates/iota-graphql-rpc/src/types/balance_change.rs similarity index 84% rename from crates/sui-graphql-rpc/src/types/balance_change.rs rename to crates/iota-graphql-rpc/src/types/balance_change.rs index ebb75327f6f..087cd204d11 100644 --- a/crates/sui-graphql-rpc/src/types/balance_change.rs +++ b/crates/iota-graphql-rpc/src/types/balance_change.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; -use sui_json_rpc_types::BalanceChange as StoredBalanceChange; -use sui_types::object::Owner as NativeOwner; +use iota_json_rpc_types::BalanceChange as StoredBalanceChange; +use iota_types::object::Owner as NativeOwner; -use super::{big_int::BigInt, move_type::MoveType, owner::Owner, sui_address::SuiAddress}; +use super::{big_int::BigInt, iota_address::IotaAddress, move_type::MoveType, owner::Owner}; use crate::error::Error; pub(crate) struct BalanceChange { @@ -24,7 +25,7 @@ impl BalanceChange { match self.stored.owner { O::AddressOwner(addr) | O::ObjectOwner(addr) => Some(Owner { - address: SuiAddress::from(addr), + address: IotaAddress::from(addr), checkpoint_viewed_at: Some(self.checkpoint_viewed_at), }), @@ -33,7 +34,7 @@ impl BalanceChange { } /// The inner type of the coin whose balance has changed (e.g. - /// `0x2::sui::SUI`). + /// `0x2::iota::IOTA`). async fn coin_type(&self) -> Option { Some(MoveType::new(self.stored.coin_type.clone())) } diff --git a/crates/sui-graphql-rpc/src/types/base64.rs b/crates/iota-graphql-rpc/src/types/base64.rs similarity index 98% rename from crates/sui-graphql-rpc/src/types/base64.rs rename to crates/iota-graphql-rpc/src/types/base64.rs index 3d2f59d501b..6bae69344cf 100644 --- a/crates/sui-graphql-rpc/src/types/base64.rs +++ b/crates/iota-graphql-rpc/src/types/base64.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::str::FromStr; diff --git a/crates/sui-graphql-rpc/src/types/big_int.rs b/crates/iota-graphql-rpc/src/types/big_int.rs similarity index 98% rename from crates/sui-graphql-rpc/src/types/big_int.rs rename to crates/iota-graphql-rpc/src/types/big_int.rs index 51bebb1ee61..7770f8d0a39 100644 --- a/crates/sui-graphql-rpc/src/types/big_int.rs +++ b/crates/iota-graphql-rpc/src/types/big_int.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::str::FromStr; diff --git a/crates/sui-graphql-rpc/src/types/chain_identifier.rs b/crates/iota-graphql-rpc/src/types/chain_identifier.rs similarity index 92% rename from crates/sui-graphql-rpc/src/types/chain_identifier.rs rename to crates/iota-graphql-rpc/src/types/chain_identifier.rs index 829b6103262..c10abbfed7d 100644 --- a/crates/sui-graphql-rpc/src/types/chain_identifier.rs +++ b/crates/iota-graphql-rpc/src/types/chain_identifier.rs @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; use diesel::{ExpressionMethods, QueryDsl}; -use sui_indexer::schema::checkpoints; -use sui_types::{ +use iota_indexer::schema::checkpoints; +use iota_types::{ digests::ChainIdentifier as NativeChainIdentifier, messages_checkpoint::CheckpointDigest, }; diff --git a/crates/sui-graphql-rpc/src/types/checkpoint.rs b/crates/iota-graphql-rpc/src/types/checkpoint.rs similarity index 99% rename from crates/sui-graphql-rpc/src/types/checkpoint.rs rename to crates/iota-graphql-rpc/src/types/checkpoint.rs index 54e8c8f67f7..f5d19b7273c 100644 --- a/crates/sui-graphql-rpc/src/types/checkpoint.rs +++ b/crates/iota-graphql-rpc/src/types/checkpoint.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::{BTreeMap, BTreeSet, HashMap}; @@ -10,12 +11,12 @@ use async_graphql::{ }; use diesel::{CombineDsl, ExpressionMethods, OptionalExtension, QueryDsl}; use fastcrypto::encoding::{Base58, Encoding}; -use serde::{Deserialize, Serialize}; -use sui_indexer::{ +use iota_indexer::{ models::checkpoints::StoredCheckpoint, schema::{checkpoints, objects_snapshot}, }; -use sui_types::messages_checkpoint::CheckpointDigest; +use iota_types::messages_checkpoint::CheckpointDigest; +use serde::{Deserialize, Serialize}; use super::{ base64::Base64, diff --git a/crates/iota-graphql-rpc/src/types/coin.rs b/crates/iota-graphql-rpc/src/types/coin.rs new file mode 100644 index 00000000000..f49391e675c --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/coin.rs @@ -0,0 +1,431 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_graphql::{ + connection::{Connection, CursorType, Edge}, + *, +}; +use iota_indexer::{models::objects::StoredHistoryObject, types::OwnerType}; +use iota_types::{coin::Coin as NativeCoin, TypeTag}; + +use super::{ + balance::{self, Balance}, + base64::Base64, + big_int::BigInt, + cursor::{Page, Target}, + display::DisplayEntry, + dynamic_field::{DynamicField, DynamicFieldName}, + iota_address::IotaAddress, + iotans_registration::{DomainFormat, IotansRegistration}, + move_object::{MoveObject, MoveObjectImpl}, + move_value::MoveValue, + object::{self, Object, ObjectFilter, ObjectImpl, ObjectOwner, ObjectStatus}, + owner::OwnerImpl, + stake::StakedIota, + transaction_block::{self, TransactionBlock, TransactionBlockFilter}, + type_filter::ExactTypeFilter, +}; +use crate::{ + consistency::{build_objects_query, consistent_range, View}, + data::{Db, QueryExecutor}, + error::Error, + filter, + raw_query::RawQuery, +}; + +#[derive(Clone)] +pub(crate) struct Coin { + /// Representation of this Coin as a generic Move Object. + pub super_: MoveObject, + + /// The deserialized representation of the Move Object's contents, as a + /// `0x2::coin::Coin`. + pub native: NativeCoin, +} + +pub(crate) enum CoinDowncastError { + NotACoin, + Bcs(bcs::Error), +} + +/// Some 0x2::coin::Coin Move object. +#[Object] +impl Coin { + pub(crate) async fn address(&self) -> IotaAddress { + OwnerImpl::from(&self.super_.super_).address().await + } + + /// Objects owned by this object, optionally `filter`-ed. + pub(crate) async fn objects( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + filter: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .objects(ctx, first, after, last, before, filter) + .await + } + + /// Total balance of all coins with marker type owned by this object. If + /// type is not supplied, it defaults to `0x2::iota::IOTA`. + pub(crate) async fn balance( + &self, + ctx: &Context<'_>, + type_: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .balance(ctx, type_) + .await + } + + /// The balances of all coin types owned by this object. + pub(crate) async fn balances( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .balances(ctx, first, after, last, before) + .await + } + + /// The coin objects for this object. + /// + /// `type` is a filter on the coin's type parameter, defaulting to + /// `0x2::iota::IOTA`. + pub(crate) async fn coins( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + type_: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .coins(ctx, first, after, last, before, type_) + .await + } + + /// The `0x3::staking_pool::StakedIota` objects owned by this object. + pub(crate) async fn staked_iotas( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .staked_iotas(ctx, first, after, last, before) + .await + } + + /// The domain explicitly configured as the default domain pointing to this + /// object. + pub(crate) async fn default_iotans_name( + &self, + ctx: &Context<'_>, + format: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .default_iotans_name(ctx, format) + .await + } + + /// The IotansRegistration NFTs owned by this object. These grant the owner + /// the capability to manage the associated domain. + pub(crate) async fn iotans_registrations( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .iotans_registrations(ctx, first, after, last, before) + .await + } + + pub(crate) async fn version(&self) -> u64 { + ObjectImpl(&self.super_.super_).version().await + } + + /// The current status of the object as read from the off-chain store. The + /// possible states are: NOT_INDEXED, the object is loaded from + /// serialized data, such as the contents of a genesis or system package + /// upgrade transaction. LIVE, the version returned is the most recent for + /// the object, and it is not deleted or wrapped at that version. + /// HISTORICAL, the object was referenced at a specific version or + /// checkpoint, so is fetched from historical tables and may not be the + /// latest version of the object. WRAPPED_OR_DELETED, the object is deleted + /// or wrapped and only partial information can be loaded." + pub(crate) async fn status(&self) -> ObjectStatus { + ObjectImpl(&self.super_.super_).status().await + } + + /// 32-byte hash that identifies the object's contents, encoded as a Base58 + /// string. + pub(crate) async fn digest(&self) -> Option { + ObjectImpl(&self.super_.super_).digest().await + } + + /// The owner type of this object: Immutable, Shared, Parent, Address + pub(crate) async fn owner(&self, ctx: &Context<'_>) -> Option { + ObjectImpl(&self.super_.super_).owner(ctx).await + } + + /// The transaction block that created this version of the object. + pub(crate) async fn previous_transaction_block( + &self, + ctx: &Context<'_>, + ) -> Result> { + ObjectImpl(&self.super_.super_) + .previous_transaction_block(ctx) + .await + } + + /// The amount of IOTA we would rebate if this object gets deleted or + /// mutated. This number is recalculated based on the present storage + /// gas price. + pub(crate) async fn storage_rebate(&self) -> Option { + ObjectImpl(&self.super_.super_).storage_rebate().await + } + + /// The transaction blocks that sent objects to this object. + pub(crate) async fn received_transaction_blocks( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + filter: Option, + ) -> Result> { + ObjectImpl(&self.super_.super_) + .received_transaction_blocks(ctx, first, after, last, before, filter) + .await + } + + /// The Base64-encoded BCS serialization of the object's content. + pub(crate) async fn bcs(&self) -> Result> { + ObjectImpl(&self.super_.super_).bcs().await + } + + /// Displays the contents of the Move object in a JSON string and through + /// GraphQL types. Also provides the flat representation of the type + /// signature, and the BCS of the corresponding data. + pub(crate) async fn contents(&self) -> Option { + MoveObjectImpl(&self.super_).contents().await + } + + /// Determines whether a transaction can transfer this object, using the + /// TransferObjects transaction command or + /// `iota::transfer::public_transfer`, both of which require the object to + /// have the `key` and `store` abilities. + pub(crate) async fn has_public_transfer(&self, ctx: &Context<'_>) -> Result { + MoveObjectImpl(&self.super_).has_public_transfer(ctx).await + } + + /// The set of named templates defined on-chain for the type of this object, + /// to be handled off-chain. The server substitutes data from the object + /// into these templates to generate a display string per template. + pub(crate) async fn display(&self, ctx: &Context<'_>) -> Result>> { + ObjectImpl(&self.super_.super_).display(ctx).await + } + + /// Access a dynamic field on an object using its name. Names are arbitrary + /// Move values whose type have `copy`, `drop`, and `store`, and are + /// specified using their type, and their BCS contents, Base64 encoded. + /// + /// Dynamic fields on wrapped objects can be accessed by using the same API + /// under the Owner type. + pub(crate) async fn dynamic_field( + &self, + ctx: &Context<'_>, + name: DynamicFieldName, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .dynamic_field(ctx, name, Some(self.super_.super_.version_impl())) + .await + } + + /// Access a dynamic object field on an object using its name. Names are + /// arbitrary Move values whose type have `copy`, `drop`, and `store`, + /// and are specified using their type, and their BCS contents, Base64 + /// encoded. The value of a dynamic object field can also be accessed + /// off-chain directly via its address (e.g. using `Query.object`). + /// + /// Dynamic fields on wrapped objects can be accessed by using the same API + /// under the Owner type. + pub(crate) async fn dynamic_object_field( + &self, + ctx: &Context<'_>, + name: DynamicFieldName, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .dynamic_object_field(ctx, name, Some(self.super_.super_.version_impl())) + .await + } + + /// The dynamic fields and dynamic object fields on an object. + /// + /// Dynamic fields on wrapped objects can be accessed by using the same API + /// under the Owner type. + pub(crate) async fn dynamic_fields( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .dynamic_fields( + ctx, + first, + after, + last, + before, + Some(self.super_.super_.version_impl()), + ) + .await + } + + /// Balance of this coin object. + async fn coin_balance(&self) -> Option { + Some(BigInt::from(self.native.balance.value())) + } +} + +impl Coin { + /// Query the database for a `page` of coins. The page uses the bytes of an + /// Object ID as the cursor, and can optionally be filtered by an owner. + pub(crate) async fn paginate( + db: &Db, + page: Page, + coin_type: TypeTag, + owner: Option, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + // If cursors are provided, defer to the `checkpoint_viewed_at` in the cursor if + // they are consistent. Otherwise, use the value from the parameter, or + // set to None. This is so that paginated queries are consistent with + // the previous query that created the cursor. + let cursor_viewed_at = page.validate_cursor_consistency()?; + let checkpoint_viewed_at: Option = cursor_viewed_at.or(checkpoint_viewed_at); + + let response = db + .execute_repeatable(move |conn| { + let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { + return Ok::<_, diesel::result::Error>(None); + }; + + let result = page.paginate_raw_query::( + conn, + rhs, + coins_query(coin_type, owner, lhs as i64, rhs as i64, &page), + )?; + + Ok(Some((result, rhs))) + }) + .await?; + + let Some(((prev, next, results), checkpoint_viewed_at)) = response else { + return Err(Error::Client( + "Requested data is outside the available range".to_string(), + )); + }; + + let mut conn: Connection = Connection::new(prev, next); + + for stored in results { + // To maintain consistency, the returned cursor should have the same upper-bound + // as the checkpoint found on the cursor. + let cursor = stored.cursor(checkpoint_viewed_at).encode_cursor(); + let object = + Object::try_from_stored_history_object(stored, Some(checkpoint_viewed_at))?; + + let move_ = MoveObject::try_from(&object).map_err(|_| { + Error::Internal(format!( + "Failed to deserialize as Move object: {}", + object.address + )) + })?; + + let coin = Coin::try_from(&move_).map_err(|_| { + Error::Internal(format!("Faild to deserialize as Coin: {}", object.address)) + })?; + + conn.edges.push(Edge::new(cursor, coin)); + } + + Ok(conn) + } +} + +impl TryFrom<&MoveObject> for Coin { + type Error = CoinDowncastError; + + fn try_from(move_object: &MoveObject) -> Result { + if !move_object.native.is_coin() { + return Err(CoinDowncastError::NotACoin); + } + + Ok(Self { + super_: move_object.clone(), + native: bcs::from_bytes(move_object.native.contents()) + .map_err(CoinDowncastError::Bcs)?, + }) + } +} + +/// Constructs a raw query to fetch objects from the database. Since there are +/// no point lookups for the coin query, objects are filtered out if they +/// satisfy the criteria but have a later version in the same checkpoint. +fn coins_query( + coin_type: TypeTag, + owner: Option, + lhs: i64, + rhs: i64, + page: &Page, +) -> RawQuery { + build_objects_query( + View::Consistent, + lhs, + rhs, + page, + move |query| apply_filter(query, &coin_type, owner), + move |newer| newer, + ) +} + +fn apply_filter(mut query: RawQuery, coin_type: &TypeTag, owner: Option) -> RawQuery { + if let Some(owner) = owner { + query = filter!( + query, + format!( + "owner_id = '\\x{}'::bytea AND owner_type = {}", + hex::encode(owner.into_vec()), + OwnerType::Address as i16 + ) + ); + } + + query = filter!( + query, + "coin_type IS NOT NULL AND coin_type = {}", + coin_type.to_canonical_display(/* with_prefix */ true) + ); + + query +} diff --git a/crates/sui-graphql-rpc/src/types/coin_metadata.rs b/crates/iota-graphql-rpc/src/types/coin_metadata.rs similarity index 92% rename from crates/sui-graphql-rpc/src/types/coin_metadata.rs rename to crates/iota-graphql-rpc/src/types/coin_metadata.rs index 7c17589f3eb..008990da6a9 100644 --- a/crates/sui-graphql-rpc/src/types/coin_metadata.rs +++ b/crates/iota-graphql-rpc/src/types/coin_metadata.rs @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::{connection::Connection, *}; -use sui_types::{ +use iota_types::{ coin::{CoinMetadata as NativeCoinMetadata, TreasuryCap}, - gas_coin::{GAS, TOTAL_SUPPLY_SUI}, + gas_coin::{GAS, TOTAL_SUPPLY_IOTA}, TypeTag, }; @@ -15,13 +16,13 @@ use super::{ coin::Coin, display::DisplayEntry, dynamic_field::{DynamicField, DynamicFieldName}, + iota_address::IotaAddress, + iotans_registration::{DomainFormat, IotansRegistration}, move_object::{MoveObject, MoveObjectImpl}, move_value::MoveValue, object::{self, Object, ObjectFilter, ObjectImpl, ObjectOwner, ObjectStatus}, owner::OwnerImpl, - stake::StakedSui, - sui_address::SuiAddress, - suins_registration::{DomainFormat, SuinsRegistration}, + stake::StakedIota, transaction_block::{self, TransactionBlock, TransactionBlockFilter}, type_filter::ExactTypeFilter, }; @@ -40,7 +41,7 @@ pub(crate) enum CoinMetadataDowncastError { /// The metadata for a coin type. #[Object] impl CoinMetadata { - pub(crate) async fn address(&self) -> SuiAddress { + pub(crate) async fn address(&self) -> IotaAddress { OwnerImpl::from(&self.super_.super_).address().await } @@ -60,7 +61,7 @@ impl CoinMetadata { } /// Total balance of all coins with marker type owned by this object. If - /// type is not supplied, it defaults to `0x2::sui::SUI`. + /// type is not supplied, it defaults to `0x2::iota::IOTA`. pub(crate) async fn balance( &self, ctx: &Context<'_>, @@ -88,7 +89,7 @@ impl CoinMetadata { /// The coin objects for this object. /// /// `type` is a filter on the coin's type parameter, defaulting to - /// `0x2::sui::SUI`. + /// `0x2::iota::IOTA`. pub(crate) async fn coins( &self, ctx: &Context<'_>, @@ -103,44 +104,44 @@ impl CoinMetadata { .await } - /// The `0x3::staking_pool::StakedSui` objects owned by this object. - pub(crate) async fn staked_suis( + /// The `0x3::staking_pool::StakedIota` objects owned by this object. + pub(crate) async fn staked_iotas( &self, ctx: &Context<'_>, first: Option, after: Option, last: Option, before: Option, - ) -> Result> { + ) -> Result> { OwnerImpl::from(&self.super_.super_) - .staked_suis(ctx, first, after, last, before) + .staked_iotas(ctx, first, after, last, before) .await } /// The domain explicitly configured as the default domain pointing to this /// object. - pub(crate) async fn default_suins_name( + pub(crate) async fn default_iotans_name( &self, ctx: &Context<'_>, format: Option, ) -> Result> { OwnerImpl::from(&self.super_.super_) - .default_suins_name(ctx, format) + .default_iotans_name(ctx, format) .await } - /// The SuinsRegistration NFTs owned by this object. These grant the owner + /// The IotansRegistration NFTs owned by this object. These grant the owner /// the capability to manage the associated domain. - pub(crate) async fn suins_registrations( + pub(crate) async fn iotans_registrations( &self, ctx: &Context<'_>, first: Option, after: Option, last: Option, before: Option, - ) -> Result> { + ) -> Result> { OwnerImpl::from(&self.super_.super_) - .suins_registrations(ctx, first, after, last, before) + .iotans_registrations(ctx, first, after, last, before) .await } @@ -182,7 +183,7 @@ impl CoinMetadata { .await } - /// The amount of SUI we would rebate if this object gets deleted or + /// The amount of IOTA we would rebate if this object gets deleted or /// mutated. This number is recalculated based on the present storage /// gas price. pub(crate) async fn storage_rebate(&self) -> Option { @@ -218,7 +219,7 @@ impl CoinMetadata { /// Determines whether a transaction can transfer this object, using the /// TransferObjects transaction command or - /// `sui::transfer::public_transfer`, both of which require the object to + /// `iota::transfer::public_transfer`, both of which require the object to /// have the `key` and `store` abilities. pub(crate) async fn has_public_transfer(&self, ctx: &Context<'_>) -> Result { MoveObjectImpl(&self.super_).has_public_transfer(ctx).await @@ -371,7 +372,7 @@ impl CoinMetadata { }; Ok(Some(if GAS::is_gas(coin_struct.as_ref()) { - TOTAL_SUPPLY_SUI + TOTAL_SUPPLY_IOTA } else { let cap_type = TreasuryCap::type_(*coin_struct).into(); let Some(object) = Object::query_singleton(db, cap_type).await? else { diff --git a/crates/sui-graphql-rpc/src/types/cursor.rs b/crates/iota-graphql-rpc/src/types/cursor.rs similarity index 99% rename from crates/sui-graphql-rpc/src/types/cursor.rs rename to crates/iota-graphql-rpc/src/types/cursor.rs index fb79d2a2714..8c2563651ac 100644 --- a/crates/sui-graphql-rpc/src/types/cursor.rs +++ b/crates/iota-graphql-rpc/src/types/cursor.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fmt, ops::Deref, vec}; diff --git a/crates/sui-graphql-rpc/src/types/date_time.rs b/crates/iota-graphql-rpc/src/types/date_time.rs similarity index 98% rename from crates/sui-graphql-rpc/src/types/date_time.rs rename to crates/iota-graphql-rpc/src/types/date_time.rs index f0bb1f54a24..e3edd2ebadb 100644 --- a/crates/sui-graphql-rpc/src/types/date_time.rs +++ b/crates/iota-graphql-rpc/src/types/date_time.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::str::FromStr; diff --git a/crates/sui-graphql-rpc/src/types/digest.rs b/crates/iota-graphql-rpc/src/types/digest.rs similarity index 96% rename from crates/sui-graphql-rpc/src/types/digest.rs rename to crates/iota-graphql-rpc/src/types/digest.rs index 7a58d0dc85a..ae97f9ce51e 100644 --- a/crates/sui-graphql-rpc/src/types/digest.rs +++ b/crates/iota-graphql-rpc/src/types/digest.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fmt, str::FromStr}; use async_graphql::*; use fastcrypto::encoding::{Base58, Encoding}; -use sui_types::digests::{ObjectDigest, TransactionDigest}; +use iota_types::digests::{ObjectDigest, TransactionDigest}; use super::string_input::impl_string_input; diff --git a/crates/iota-graphql-rpc/src/types/display.rs b/crates/iota-graphql-rpc/src/types/display.rs new file mode 100644 index 00000000000..c178abf4081 --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/display.rs @@ -0,0 +1,192 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_graphql::*; +use diesel::{ExpressionMethods, OptionalExtension, QueryDsl}; +use iota_indexer::{models::display::StoredDisplay, schema::display}; +use iota_json_rpc_types::IotaMoveValue; +use iota_types::TypeTag; +use move_core_types::annotated_value::{MoveStruct, MoveValue}; + +use crate::{ + data::{Db, DbConnection, QueryExecutor}, + error::Error, +}; + +pub(crate) struct Display { + pub stored: StoredDisplay, +} + +/// The set of named templates defined on-chain for the type of this object, +/// to be handled off-chain. The server substitutes data from the object +/// into these templates to generate a display string per template. +#[derive(Debug, SimpleObject)] +pub(crate) struct DisplayEntry { + /// The identifier for a particular template string of the Display object. + pub key: String, + /// The template string for the key with placeholder values substituted. + pub value: Option, + /// An error string describing why the template could not be rendered. + pub error: Option, +} + +#[derive(thiserror::Error, Debug)] +pub(crate) enum DisplayRenderError { + #[error("Display template value cannot be empty")] + TemplateValueEmpty, + #[error("Display template value of {0} exceeds maximum depth of {1}")] + ExceedsLookupDepth(usize, u64), + #[error("Vector of name {0} is not supported as a Display value")] + Vector(String), + #[error("Field '{0}' not found")] + FieldNotFound(String), + #[error("Unexpected MoveValue")] + UnexpectedMoveValue, +} + +impl Display { + /// Query for a `Display` object by the type that it is displaying + pub(crate) async fn query(db: &Db, type_: TypeTag) -> Result, Error> { + let stored: Option = db + .execute(move |conn| { + conn.first(move || { + use display::dsl; + dsl::display.filter( + dsl::object_type.eq(type_.to_canonical_string(/* with_prefix */ true)), + ) + }) + .optional() + }) + .await?; + + Ok(stored.map(|stored| Display { stored })) + } + + /// Render the fields defined by this `Display` from the contents of + /// `struct_`. + pub(crate) fn render(&self, struct_: &MoveStruct) -> Result, Error> { + let event = self + .stored + .to_display_update_event() + .map_err(|e| Error::Internal(e.to_string()))?; + + let mut rendered = vec![]; + for entry in event.fields.contents { + rendered.push(match parse_template(&entry.value, struct_) { + Ok(v) => DisplayEntry::create_value(entry.key, v), + Err(e) => DisplayEntry::create_error(entry.key, e.to_string()), + }); + } + + Ok(rendered) + } +} + +impl DisplayEntry { + pub(crate) fn create_value(key: String, value: String) -> Self { + Self { + key, + value: Some(value), + error: None, + } + } + + pub(crate) fn create_error(key: String, error: String) -> Self { + Self { + key, + value: None, + error: Some(error), + } + } +} + +/// Handles the PART of the grammar, defined as: +/// PART ::= '{' CHAIN '}' +/// | '\{' | '\}' +/// | [:utf8:] +/// Defers resolution down to the IDENT to get_value_from_move_struct, +/// and substitutes the result into the PART template. +fn parse_template(template: &str, move_struct: &MoveStruct) -> Result { + let mut output = template.to_string(); + let mut var_name = String::new(); + let mut in_braces = false; + let mut escaped = false; + + for ch in template.chars() { + match ch { + '\\' => { + escaped = true; + continue; + } + '{' if !escaped => { + in_braces = true; + var_name.clear(); + } + '}' if !escaped => { + in_braces = false; + let value = get_value_from_move_struct(move_struct, &var_name)?; + output = output.replace(&format!("{{{}}}", var_name), &value.to_string()); + } + _ if !escaped => { + if in_braces { + var_name.push(ch); + } + } + _ => {} + } + escaped = false; + } + + Ok(output.replace('\\', "")) +} + +/// Handles the CHAIN and IDENT of the grammar, defined as: +/// CHAIN ::= IDENT | CHAIN '.' IDENT +/// IDENT ::= /* Move identifier */ +pub(crate) fn get_value_from_move_struct( + move_struct: &MoveStruct, + var_name: &str, +) -> Result { + let parts: Vec<&str> = var_name.split('.').collect(); + if parts.is_empty() { + return Err(DisplayRenderError::TemplateValueEmpty); + } + // todo: 10 is a carry-over from the iota-json-rpc implementation + // we should introduce this as a new limit on the config + if parts.len() > 10 { + return Err(DisplayRenderError::ExceedsLookupDepth(parts.len(), 10)); + } + + // update this as we iterate through the parts + let start_value = &MoveValue::Struct(move_struct.clone()); + + let result = parts + .iter() + .try_fold(start_value, |current_value, part| match current_value { + MoveValue::Struct(s) => s + .fields + .iter() + .find_map(|(id, value)| { + if id.as_str() == *part { + Some(value) + } else { + None + } + }) + .ok_or_else(|| DisplayRenderError::FieldNotFound(part.to_string())), + _ => Err(DisplayRenderError::UnexpectedMoveValue), + })?; + + // TODO: move off dependency on IotaMoveValue + let iota_move_value: IotaMoveValue = result.clone().into(); + + match iota_move_value { + IotaMoveValue::Option(move_option) => match move_option.as_ref() { + Some(move_value) => Ok(move_value.to_string()), + None => Ok("".to_string()), + }, + IotaMoveValue::Vector(_) => Err(DisplayRenderError::Vector(var_name.to_string())), + _ => Ok(iota_move_value.to_string()), + } +} diff --git a/crates/sui-graphql-rpc/src/types/dry_run_result.rs b/crates/iota-graphql-rpc/src/types/dry_run_result.rs similarity index 94% rename from crates/sui-graphql-rpc/src/types/dry_run_result.rs rename to crates/iota-graphql-rpc/src/types/dry_run_result.rs index 589c958c636..bd337a684c3 100644 --- a/crates/sui-graphql-rpc/src/types/dry_run_result.rs +++ b/crates/iota-graphql-rpc/src/types/dry_run_result.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; -use sui_json_rpc_types::{DevInspectResults, SuiExecutionResult}; -use sui_types::{ +use iota_json_rpc_types::{DevInspectResults, IotaExecutionResult}; +use iota_types::{ effects::TransactionEffects as NativeTransactionEffects, transaction::TransactionData as NativeTransactionData, }; @@ -52,10 +53,10 @@ pub(crate) struct DryRunReturn { pub bcs: Base64, } -impl TryFrom for DryRunEffect { +impl TryFrom for DryRunEffect { type Error = crate::error::Error; - fn try_from(result: SuiExecutionResult) -> Result { + fn try_from(result: IotaExecutionResult) -> Result { let mutated_references = result .mutable_reference_outputs .iter() diff --git a/crates/iota-graphql-rpc/src/types/dynamic_field.rs b/crates/iota-graphql-rpc/src/types/dynamic_field.rs new file mode 100644 index 00000000000..2e981241159 --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/dynamic_field.rs @@ -0,0 +1,382 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_graphql::{ + connection::{Connection, CursorType, Edge}, + *, +}; +use iota_indexer::{models::objects::StoredHistoryObject, types::OwnerType}; +use iota_package_resolver::Resolver; +use iota_types::dynamic_field::{derive_dynamic_field_id, DynamicFieldInfo, DynamicFieldType}; +use move_core_types::annotated_value::{self as A, MoveStruct}; + +use super::{ + base64::Base64, + cursor::{Page, Target}, + iota_address::IotaAddress, + move_object::MoveObject, + move_value::MoveValue, + object::{self, deserialize_move_struct, Object, ObjectKind, ObjectLookupKey}, + type_filter::ExactTypeFilter, +}; +use crate::{ + consistency::{build_objects_query, consistent_range, View}, + context_data::package_cache::PackageCache, + data::{Db, QueryExecutor}, + error::Error, + filter, + raw_query::RawQuery, +}; + +pub(crate) struct DynamicField { + pub super_: MoveObject, + pub df_object_id: IotaAddress, + pub df_kind: DynamicFieldType, +} + +#[derive(Union)] +pub(crate) enum DynamicFieldValue { + MoveObject(MoveObject), // DynamicObject + MoveValue(MoveValue), // DynamicField +} + +#[derive(InputObject)] // used as input object +pub(crate) struct DynamicFieldName { + /// The string type of the DynamicField's 'name' field. + /// A string representation of a Move primitive like 'u64', or a struct type + /// like '0x2::kiosk::Listing' + pub type_: ExactTypeFilter, + /// The Base64 encoded bcs serialization of the DynamicField's 'name' field. + pub bcs: Base64, +} + +/// Dynamic fields are heterogeneous fields that can be added or removed at +/// runtime, and can have arbitrary user-assigned names. There are two sub-types +/// of dynamic fields: +/// +/// 1) Dynamic Fields can store any value that has the `store` ability, however +/// an object stored in this kind of field will be considered wrapped and +/// will not be accessible directly via its ID by external tools (explorers, +/// wallets, etc) accessing storage. +/// 2) Dynamic Object Fields values must be Iota objects (have the `key` and +/// `store` abilities, and id: UID as the first field), but will still be +/// directly accessible off-chain via their object ID after being attached. +#[Object] +impl DynamicField { + /// The string type, data, and serialized value of the DynamicField's 'name' + /// field. This field is used to uniquely identify a child of the parent + /// object. + async fn name(&self, ctx: &Context<'_>) -> Result> { + let resolver: &Resolver = ctx + .data() + .map_err(|_| Error::Internal("Unable to fetch Package Cache.".to_string())) + .extend()?; + + let (struct_tag, move_struct) = deserialize_move_struct(&self.super_.native, resolver) + .await + .extend()?; + + // Get TypeTag of the DynamicField name from StructTag of the MoveStruct + let type_tag = DynamicFieldInfo::try_extract_field_name(&struct_tag, &self.df_kind) + .map_err(|e| Error::Internal(e.to_string())) + .extend()?; + + let name_move_value = extract_field_from_move_struct(move_struct, "name").extend()?; + + let undecorated = if self.df_kind == DynamicFieldType::DynamicObject { + let inner_name_move_value = match name_move_value { + A::MoveValue::Struct(inner_struct) => { + extract_field_from_move_struct(inner_struct, "name") + } + _ => Err(Error::Internal("Expected a wrapper struct".to_string())), + } + .extend()?; + inner_name_move_value.undecorate() + } else { + name_move_value.undecorate() + }; + + let bcs = bcs::to_bytes(&undecorated) + .map_err(|e| Error::Internal(format!("Failed to serialize object: {e}"))) + .extend()?; + + Ok(Some(MoveValue::new(type_tag, Base64::from(bcs)))) + } + + /// The actual data stored in the dynamic field. + /// The returned dynamic field is an object if its return type is + /// MoveObject, in which case it is also accessible off-chain via its + /// address. + async fn value(&self, ctx: &Context<'_>) -> Result> { + if self.df_kind == DynamicFieldType::DynamicObject { + // If `df_kind` is a DynamicObject, the object we are currently on is the field + // object, and we must resolve one more level down to the value + // object. Becuase we only have checkpoint-level granularity, we may + // end up reading a later version of the value object. Thus, we use + // the version of the field object to bound the value object at the + // correct version. + let obj = MoveObject::query( + ctx.data_unchecked(), + self.df_object_id, + ObjectLookupKey::LatestAtParentVersion { + version: self.super_.super_.version_impl(), + checkpoint_viewed_at: self.super_.super_.checkpoint_viewed_at, + }, + ) + .await + .extend()?; + Ok(obj.map(DynamicFieldValue::MoveObject)) + } else { + let resolver: &Resolver = ctx + .data() + .map_err(|_| Error::Internal("Unable to fetch Package Cache.".to_string())) + .extend()?; + + let (struct_tag, move_struct) = deserialize_move_struct(&self.super_.native, resolver) + .await + .extend()?; + + // Get TypeTag of the DynamicField value from StructTag of the MoveStruct + let type_tag = DynamicFieldInfo::try_extract_field_value(&struct_tag) + .map_err(|e| Error::Internal(e.to_string())) + .extend()?; + + let value_move_value = extract_field_from_move_struct(move_struct, "value").extend()?; + + let undecorated = value_move_value.undecorate(); + let bcs = bcs::to_bytes(&undecorated) + .map_err(|e| Error::Internal(format!("Failed to serialize object: {e}"))) + .extend()?; + + Ok(Some(DynamicFieldValue::MoveValue(MoveValue::new( + type_tag, + Base64::from(bcs), + )))) + } + } +} + +impl DynamicField { + /// Fetch a single dynamic field entry from the `db`, on `parent` object, + /// with field name `name`, and kind `kind` (dynamic field or dynamic + /// object field). The dynamic field is bound by the `parent_version` if + /// provided - the fetched field will be the latest version at or before + /// the provided version. If `parent_version` is not provided, the latest + /// version of the field is returned as bounded by the + /// `checkpoint_viewed_at` parameter. + pub(crate) async fn query( + db: &Db, + parent: IotaAddress, + parent_version: Option, + name: DynamicFieldName, + kind: DynamicFieldType, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + let type_ = match kind { + DynamicFieldType::DynamicField => name.type_.0, + DynamicFieldType::DynamicObject => { + DynamicFieldInfo::dynamic_object_field_wrapper(name.type_.0).into() + } + }; + + let field_id = derive_dynamic_field_id(parent, &type_, &name.bcs.0) + .map_err(|e| Error::Internal(format!("Failed to derive dynamic field id: {e}")))?; + + use ObjectLookupKey as K; + let key = match (parent_version, checkpoint_viewed_at) { + (None, None) => K::Latest, + (None, Some(checkpoint_viewed_at)) => K::LatestAt(checkpoint_viewed_at), + (Some(version), checkpoint_viewed_at) => K::LatestAtParentVersion { + version, + checkpoint_viewed_at, + }, + }; + + let super_ = MoveObject::query(db, IotaAddress::from(field_id), key).await?; + + super_.map(Self::try_from).transpose() + } + + /// Query the `db` for a `page` of dynamic fields attached to object with ID + /// `parent`. The returned dynamic fields are bound by the + /// `parent_version` if provided - each field will be the latest version + /// at or before the provided version. If `parent_version` is not provided, + /// the latest version of each field is returned as bounded by the + /// `checkpoint_viewed-at` parameter.` + pub(crate) async fn paginate( + db: &Db, + page: Page, + parent: IotaAddress, + parent_version: Option, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + // If cursors are provided, defer to the `checkpoint_viewed_at` in the cursor if + // they are consistent. Otherwise, use the value from the parameter, or + // set to None. This is so that paginated queries are consistent with + // the previous query that created the cursor. + let cursor_viewed_at = page.validate_cursor_consistency()?; + let checkpoint_viewed_at: Option = cursor_viewed_at.or(checkpoint_viewed_at); + + let Some(((prev, next, results), checkpoint_viewed_at)) = db + .execute_repeatable(move |conn| { + let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { + return Ok::<_, diesel::result::Error>(None); + }; + + let result = page.paginate_raw_query::( + conn, + rhs, + dynamic_fields_query(parent, parent_version, lhs as i64, rhs as i64, &page), + )?; + + Ok(Some((result, rhs))) + }) + .await? + else { + return Err(Error::Client( + "Requested data is outside the available range".to_string(), + )); + }; + + let mut conn: Connection = Connection::new(prev, next); + + for stored in results { + // To maintain consistency, the returned cursor should have the same upper-bound + // as the checkpoint found on the cursor. + let cursor = stored.cursor(checkpoint_viewed_at).encode_cursor(); + + let object = + Object::try_from_stored_history_object(stored, Some(checkpoint_viewed_at))?; + + let move_ = MoveObject::try_from(&object).map_err(|_| { + Error::Internal(format!( + "Failed to deserialize as Move object: {}", + object.address + )) + })?; + + let dynamic_field = DynamicField::try_from(move_)?; + + conn.edges.push(Edge::new(cursor, dynamic_field)); + } + + Ok(conn) + } +} + +impl TryFrom for DynamicField { + type Error = Error; + + fn try_from(stored: MoveObject) -> Result { + let super_ = &stored.super_; + + let (df_object_id, df_kind) = match &super_.kind { + ObjectKind::Live(_, stored) => stored + .df_object_id + .as_ref() + .map(|id| (id, stored.df_kind)) + .ok_or_else(|| Error::Internal("Object is not a dynamic field.".to_string()))?, + ObjectKind::Historical(_, stored) => stored + .df_object_id + .as_ref() + .map(|id| (id, stored.df_kind)) + .ok_or_else(|| Error::Internal("Object is not a dynamic field.".to_string()))?, + _ => { + return Err(Error::Internal( + "A WrappedOrDeleted object cannot be converted into a DynamicField." + .to_string(), + )); + } + }; + + let df_object_id = IotaAddress::from_bytes(df_object_id).map_err(|e| { + Error::Internal(format!("Failed to deserialize dynamic field ID: {e}.")) + })?; + + let df_kind = match df_kind { + Some(0) => DynamicFieldType::DynamicField, + Some(1) => DynamicFieldType::DynamicObject, + Some(k) => { + return Err(Error::Internal(format!( + "Unrecognized dynamic field kind: {k}." + ))); + } + None => return Err(Error::Internal("No dynamic field kind.".to_string())), + }; + + Ok(DynamicField { + super_: stored, + df_object_id, + df_kind, + }) + } +} + +pub fn extract_field_from_move_struct( + move_struct: MoveStruct, + field_name: &str, +) -> Result { + move_struct + .fields + .into_iter() + .find_map(|(id, value)| { + if id.to_string() == field_name { + Some(value) + } else { + None + } + }) + .ok_or_else(|| Error::Internal(format!("Field '{}' not found", field_name))) +} + +/// Builds the `RawQuery` for fetching dynamic fields attached to a parent +/// object. If `parent_version` is null, the latest version of each field within +/// the given checkpoint range [`lhs`, `rhs`] is returned, conditioned on the +/// fact that there is not a more recent version of the field. +/// +/// If `parent_version` is provided, it is used to bound both the `candidates` +/// and `newer` objects subqueries. This is because the dynamic fields of a +/// parent at version v are dynamic fields owned by the parent whose versions +/// are <= v. Unlike object ownership, where owned and owner objects +/// can have arbitrary `object_version`s, dynamic fields on a parent cannot have +/// a version greater than its parent. +fn dynamic_fields_query( + parent: IotaAddress, + parent_version: Option, + lhs: i64, + rhs: i64, + page: &Page, +) -> RawQuery { + build_objects_query( + View::Consistent, + lhs, + rhs, + page, + move |query| apply_filter(query, parent, parent_version), + move |newer| { + if let Some(parent_version) = parent_version { + filter!(newer, format!("object_version <= {}", parent_version)) + } else { + newer + } + }, + ) +} + +fn apply_filter(query: RawQuery, parent: IotaAddress, parent_version: Option) -> RawQuery { + let query = filter!( + query, + format!( + "owner_id = '\\x{}'::bytea AND owner_type = {} AND df_kind IS NOT NULL", + hex::encode(parent.into_vec()), + OwnerType::Object as i16 + ) + ); + + if let Some(version) = parent_version { + filter!(query, format!("object_version <= {}", version)) + } else { + query + } +} diff --git a/crates/iota-graphql-rpc/src/types/epoch.rs b/crates/iota-graphql-rpc/src/types/epoch.rs new file mode 100644 index 00000000000..a158f651da5 --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/epoch.rs @@ -0,0 +1,393 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::{BTreeMap, BTreeSet, HashMap}; + +use async_graphql::{ + connection::Connection, + dataloader::{DataLoader, Loader}, + *, +}; +use diesel::{ExpressionMethods, OptionalExtension, QueryDsl, SelectableHelper}; +use fastcrypto::encoding::{Base58, Encoding}; +use iota_indexer::{models::epoch::QueryableEpochInfo, schema::epochs}; +use iota_types::messages_checkpoint::CheckpointCommitment as EpochCommitment; + +use super::{ + big_int::BigInt, + checkpoint::{self, Checkpoint, CheckpointId}, + cursor::Page, + date_time::DateTime, + protocol_config::ProtocolConfigs, + system_state_summary::SystemStateSummary, + transaction_block::{self, TransactionBlock, TransactionBlockFilter}, + validator_set::ValidatorSet, +}; +use crate::{ + context_data::db_data_provider::{convert_to_validators, PgManager}, + data::{Db, DbConnection, QueryExecutor}, + error::Error, +}; + +#[derive(Clone)] +pub(crate) struct Epoch { + pub stored: QueryableEpochInfo, + pub checkpoint_viewed_at: Option, +} + +/// DataLoader key for fetching an `Epoch` by its ID, optionally constrained by +/// a consistency cursor. +#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)] +struct EpochKey { + pub epoch_id: u64, + pub checkpoint_viewed_at: Option, +} + +/// Operation of the Iota network is temporally partitioned into non-overlapping +/// epochs, and the network aims to keep epochs roughly the same duration as +/// each other. During a particular epoch the following data is fixed: +/// +/// - the protocol version +/// - the reference gas price +/// - the set of participating validators +#[Object] +impl Epoch { + /// The epoch's id as a sequence number that starts at 0 and is incremented + /// by one at every epoch change. + async fn epoch_id(&self) -> u64 { + self.stored.epoch as u64 + } + + /// The minimum gas price that a quorum of validators are guaranteed to sign + /// a transaction for. + async fn reference_gas_price(&self) -> Option { + Some(BigInt::from(self.stored.reference_gas_price as u64)) + } + + /// Validator related properties, including the active validators. + async fn validator_set(&self, ctx: &Context<'_>) -> Result> { + let system_state = ctx + .data_unchecked::() + .fetch_iota_system_state(Some(self.stored.epoch as u64)) + .await?; + + let checkpoint_viewed_at = match self.checkpoint_viewed_at { + Some(value) => Ok(value), + None => Checkpoint::query_latest_checkpoint_sequence_number(ctx.data_unchecked()).await, + }?; + + let active_validators = + convert_to_validators(system_state.active_validators, None, checkpoint_viewed_at); + let validator_set = ValidatorSet { + total_stake: Some(BigInt::from(self.stored.total_stake)), + active_validators: Some(active_validators), + pending_removals: Some(system_state.pending_removals), + pending_active_validators_id: Some(system_state.pending_active_validators_id.into()), + pending_active_validators_size: Some(system_state.pending_active_validators_size), + staking_pool_mappings_id: Some(system_state.staking_pool_mappings_id.into()), + staking_pool_mappings_size: Some(system_state.staking_pool_mappings_size), + inactive_pools_id: Some(system_state.inactive_pools_id.into()), + inactive_pools_size: Some(system_state.inactive_pools_size), + validator_candidates_id: Some(system_state.validator_candidates_id.into()), + validator_candidates_size: Some(system_state.validator_candidates_size), + checkpoint_viewed_at, + }; + Ok(Some(validator_set)) + } + + /// The epoch's starting timestamp. + async fn start_timestamp(&self) -> Result { + DateTime::from_ms(self.stored.epoch_start_timestamp) + } + + /// The epoch's ending timestamp. + async fn end_timestamp(&self) -> Result, Error> { + self.stored + .epoch_end_timestamp + .map(DateTime::from_ms) + .transpose() + } + + /// The total number of checkpoints in this epoch. + async fn total_checkpoints(&self, ctx: &Context<'_>) -> Result> { + let last = match self.stored.last_checkpoint_id { + Some(last) => last as u64, + None => Checkpoint::query(ctx, CheckpointId::default(), None) + .await + .extend()? + .map_or(self.stored.first_checkpoint_id as u64, |c| { + c.sequence_number_impl() + }), + }; + Ok(Some(BigInt::from( + last - self.stored.first_checkpoint_id as u64, + ))) + } + + /// The total number of transaction blocks in this epoch. + async fn total_transactions(&self) -> Result> { + // TODO: this currently returns None for the current epoch. Fix this. + Ok(self.stored.epoch_total_transactions.map(|v| v as u64)) + } + + /// The total amount of gas fees (in MICROS) that were paid in this epoch. + async fn total_gas_fees(&self) -> Option { + self.stored.total_gas_fees.map(BigInt::from) + } + + /// The total MICROS rewarded as stake. + async fn total_stake_rewards(&self) -> Option { + self.stored + .total_stake_rewards_distributed + .map(BigInt::from) + } + + /// The amount added to total gas fees to make up the total stake rewards. + async fn total_stake_subsidies(&self) -> Option { + self.stored.stake_subsidy_amount.map(BigInt::from) + } + + /// The storage fund available in this epoch. + /// This fund is used to redistribute storage fees from past transactions + /// to future validators. + async fn fund_size(&self) -> Option { + Some(BigInt::from(self.stored.storage_fund_balance)) + } + + /// The difference between the fund inflow and outflow, representing + /// the net amount of storage fees accumulated in this epoch. + async fn net_inflow(&self) -> Option { + if let (Some(fund_inflow), Some(fund_outflow)) = + (self.stored.storage_charge, self.stored.storage_rebate) + { + Some(BigInt::from(fund_inflow - fund_outflow)) + } else { + None + } + } + + /// The storage fees paid for transactions executed during the epoch. + async fn fund_inflow(&self) -> Option { + self.stored.storage_charge.map(BigInt::from) + } + + /// The storage fee rebates paid to users who deleted the data associated + /// with past transactions. + async fn fund_outflow(&self) -> Option { + self.stored.storage_rebate.map(BigInt::from) + } + + /// The epoch's corresponding protocol configuration, including the feature + /// flags and the configuration options. + async fn protocol_configs(&self, ctx: &Context<'_>) -> Result { + ProtocolConfigs::query(ctx.data_unchecked(), Some(self.protocol_version())) + .await + .extend() + } + + #[graphql(flatten)] + async fn system_state_summary(&self, ctx: &Context<'_>) -> Result { + let state = ctx + .data_unchecked::() + .fetch_iota_system_state(Some(self.stored.epoch as u64)) + .await?; + Ok(SystemStateSummary { native: state }) + } + + /// A commitment by the committee at the end of epoch on the contents of the + /// live object set at that time. This can be used to verify state + /// snapshots. + async fn live_object_set_digest(&self) -> Result> { + let Some(commitments) = self.stored.epoch_commitments.as_ref() else { + return Ok(None); + }; + let commitments: Vec = bcs::from_bytes(commitments).map_err(|e| { + Error::Internal(format!("Error deserializing commitments: {e}")).extend() + })?; + + let digest = commitments.into_iter().next().map(|commitment| { + let EpochCommitment::ECMHLiveObjectSetDigest(digest) = commitment; + Base58::encode(digest.digest.into_inner()) + }); + + Ok(digest) + } + + /// The epoch's corresponding checkpoints. + async fn checkpoints( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; + let epoch = self.stored.epoch as u64; + Checkpoint::paginate( + ctx.data_unchecked(), + page, + Some(epoch), + self.checkpoint_viewed_at, + ) + .await + .extend() + } + + /// The epoch's corresponding transaction blocks. + async fn transaction_blocks( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + filter: Option, + ) -> Result> { + let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; + + #[allow(clippy::unnecessary_lazy_evaluations)] // rust-lang/rust-clippy#9422 + let Some(filter) = filter + .unwrap_or_default() + .intersect(TransactionBlockFilter { + after_checkpoint: (self.stored.first_checkpoint_id > 0) + .then(|| self.stored.first_checkpoint_id as u64 - 1), + before_checkpoint: self.stored.last_checkpoint_id.map(|id| id as u64 + 1), + ..Default::default() + }) + else { + return Ok(Connection::new(false, false)); + }; + + TransactionBlock::paginate( + ctx.data_unchecked(), + page, + filter, + self.checkpoint_viewed_at, + ) + .await + .extend() + } +} + +impl Epoch { + /// The epoch's protocol version. + pub(crate) fn protocol_version(&self) -> u64 { + self.stored.protocol_version as u64 + } + + /// Look up an `Epoch` in the database, optionally filtered by its Epoch ID. + /// If no ID is supplied, defaults to fetching the latest epoch. + pub(crate) async fn query( + ctx: &Context<'_>, + filter: Option, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + if let Some(epoch_id) = filter { + let dl: &DataLoader = ctx.data_unchecked(); + dl.load_one(EpochKey { + epoch_id, + checkpoint_viewed_at, + }) + .await + } else { + Self::query_latest_at(ctx.data_unchecked(), checkpoint_viewed_at).await + } + } + + /// Look up the latest `Epoch` from the database, optionally filtered by a + /// consistency cursor (querying for a consistency cursor in the past + /// looks for the latest epoch as of that cursor). + pub(crate) async fn query_latest_at( + db: &Db, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + use epochs::dsl; + + let (stored, checkpoint_viewed_at): (Option, u64) = db + .execute_repeatable(move |conn| { + let checkpoint_viewed_at = match checkpoint_viewed_at { + Some(value) => Ok(value), + None => Checkpoint::available_range(conn).map(|(_, rhs)| rhs), + }?; + + let stored = conn + .first(move || { + let mut query = dsl::epochs + .select(QueryableEpochInfo::as_select()) + .order_by(dsl::epoch.desc()) + .into_boxed(); + + // Bound the query on `checkpoint_viewed_at` by filtering for the epoch + // whose `first_checkpoint_id <= checkpoint_viewed_at`, selecting the epoch + // with the largest `first_checkpoint_id` among the filtered set. + query = query + .filter(dsl::first_checkpoint_id.le(checkpoint_viewed_at as i64)) + .order_by(dsl::first_checkpoint_id.desc()); + + query + }) + .optional()?; + + Ok::<_, diesel::result::Error>((stored, checkpoint_viewed_at)) + }) + .await + .map_err(|e| Error::Internal(format!("Failed to fetch epoch: {e}")))?; + + Ok(stored.map(|stored| Epoch { + stored, + checkpoint_viewed_at: Some(checkpoint_viewed_at), + })) + } +} + +#[async_trait::async_trait] +impl Loader for Db { + type Value = Epoch; + type Error = Error; + + async fn load(&self, keys: &[EpochKey]) -> Result, Error> { + use epochs::dsl; + + let epoch_ids: BTreeSet<_> = keys.iter().map(|key| key.epoch_id as i64).collect(); + let epochs: Vec = self + .execute_repeatable(move |conn| { + conn.results(move || { + dsl::epochs + .select(QueryableEpochInfo::as_select()) + .filter(dsl::epoch.eq_any(epoch_ids.iter().cloned())) + }) + }) + .await + .map_err(|e| Error::Internal(format!("Failed to fetch epochs: {e}")))?; + + let epoch_id_to_stored: BTreeMap<_, _> = epochs + .into_iter() + .map(|stored| (stored.epoch as u64, stored)) + .collect(); + + Ok(keys + .iter() + .filter_map(|key| { + let stored = epoch_id_to_stored.get(&key.epoch_id).cloned()?; + let epoch = Epoch { + stored, + checkpoint_viewed_at: key.checkpoint_viewed_at, + }; + + // We filter by checkpoint viewed at in memory because it should be quite rare + // that this query actually filters something (only in edge + // cases), and not trying to encode it in the SQL query makes + // the query much simpler and therefore easier for + // the DB to plan. + let start = epoch.stored.first_checkpoint_id as u64; + if matches!(key.checkpoint_viewed_at, Some(cp) if cp < start) { + None + } else { + Some((*key, epoch)) + } + }) + .collect()) + } +} diff --git a/crates/iota-graphql-rpc/src/types/event.rs b/crates/iota-graphql-rpc/src/types/event.rs new file mode 100644 index 00000000000..790c7154c20 --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/event.rs @@ -0,0 +1,380 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::str::FromStr; + +use async_graphql::{ + connection::{Connection, CursorType, Edge}, + *, +}; +use diesel::{BoolExpressionMethods, ExpressionMethods, NullableExpressionMethods, QueryDsl}; +use iota_indexer::{ + models::{events::StoredEvent, transactions::StoredTransaction}, + schema::{events, transactions, tx_senders}, +}; +use iota_types::{ + base_types::{IotaAddress as NativeIotaAddress, ObjectID}, + event::Event as NativeEvent, + parse_iota_struct_tag, Identifier, +}; +use serde::{Deserialize, Serialize}; + +use super::{ + address::Address, + base64::Base64, + checkpoint::Checkpoint, + cursor::{self, Page, Paginated, Target}, + date_time::DateTime, + digest::Digest, + iota_address::IotaAddress, + move_module::MoveModule, + move_value::MoveValue, + type_filter::{ModuleFilter, TypeFilter}, +}; +use crate::{ + consistency::Checkpointed, + data::{self, Db, QueryExecutor}, + error::Error, +}; + +/// A Iota node emits one of the following events: +/// Move event +/// Publish event +/// Transfer object event +/// Delete object event +/// New object event +/// Epoch change event +#[derive(Clone, Debug)] +pub(crate) struct Event { + pub stored: Option, + pub native: NativeEvent, + /// The checkpoint sequence number this was viewed at. + pub checkpoint_viewed_at: u64, +} + +/// Contents of an Event's cursor. +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] +pub(crate) struct EventKey { + /// Transaction Sequence Number + tx: u64, + + /// Event Sequence Number + e: u64, + + /// The checkpoint sequence number this was viewed at. + #[serde(rename = "c")] + checkpoint_viewed_at: u64, +} + +pub(crate) type Cursor = cursor::JsonCursor; +type Query = data::Query; + +#[derive(InputObject, Clone, Default)] +pub(crate) struct EventFilter { + pub sender: Option, + pub transaction_digest: Option, + // Enhancement (post-MVP) + // after_checkpoint + // before_checkpoint + /// Events emitted by a particular module. An event is emitted by a + /// particular module if some function in the module is called by a + /// PTB and emits an event. + /// + /// Modules can be filtered by their package, or package::module. + pub emitting_module: Option, + + /// This field is used to specify the type of event emitted. + /// + /// Events can be filtered by their type's package, package::module, + /// or their fully qualified type name. + /// + /// Generic types can be queried by either the generic type name, e.g. + /// `0x2::coin::Coin`, or by the full type name, such as + /// `0x2::coin::Coin<0x2::iota::IOTA>`. + pub event_type: Option, + // Enhancement (post-MVP) + // pub start_time + // pub end_time + + // Enhancement (post-MVP) + // pub any + // pub all + // pub not +} + +#[Object] +impl Event { + /// The Move module containing some function that when called by + /// a programmable transaction block (PTB) emitted this event. + /// For example, if a PTB invokes A::m1::foo, which internally + /// calls A::m2::emit_event to emit an event, + /// the sending module would be A::m1. + async fn sending_module(&self, ctx: &Context<'_>) -> Result> { + MoveModule::query( + ctx.data_unchecked(), + self.native.package_id.into(), + &self.native.transaction_module.to_string(), + self.checkpoint_viewed_at, + ) + .await + .extend() + } + + /// Address of the sender of the event + async fn sender(&self) -> Result> { + if self.native.sender == NativeIotaAddress::ZERO { + return Ok(None); + } + + Ok(Some(Address { + address: self.native.sender.into(), + checkpoint_viewed_at: Some(self.checkpoint_viewed_at), + })) + } + + /// UTC timestamp in milliseconds since epoch (1/1/1970) + async fn timestamp(&self) -> Result, Error> { + if let Some(stored) = &self.stored { + Ok(Some(DateTime::from_ms(stored.timestamp_ms)?)) + } else { + Ok(None) + } + } + + #[graphql(flatten)] + async fn move_value(&self) -> Result { + Ok(MoveValue::new( + self.native.type_.clone().into(), + Base64::from(self.native.contents.clone()), + )) + } +} + +impl Event { + /// Query the database for a `page` of events. The Page uses the + /// transaction, event, and checkpoint sequence numbers as the cursor to + /// determine the correct page of results. The query can optionally be + /// further `filter`-ed by the `EventFilter`. + /// + /// The `checkpoint_viewed_at` parameter is an Option representing the + /// checkpoint_sequence_number at which this page was queried for, or `None` + /// if the data was requested at the latest checkpoint. Each entity + /// returned in the connection will inherit this checkpoint, so that + /// when viewing that entity's state, it will be from the reference of this + /// checkpoint_viewed_at parameter. + /// + /// If the `Page` is set, then this function will defer to the + /// `checkpoint_viewed_at` in the cursor if they are consistent. + pub(crate) async fn paginate( + db: &Db, + page: Page, + filter: EventFilter, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + let cursor_viewed_at = page.validate_cursor_consistency()?; + let checkpoint_viewed_at: Option = cursor_viewed_at.or(checkpoint_viewed_at); + + let ((prev, next, results), checkpoint_viewed_at) = db + .execute_repeatable(move |conn| { + let checkpoint_viewed_at = match checkpoint_viewed_at { + Some(value) => Ok(value), + None => Checkpoint::available_range(conn).map(|(_, rhs)| rhs), + }?; + + let result = page.paginate_query::( + conn, + checkpoint_viewed_at, + move || { + let mut query = events::dsl::events.into_boxed(); + + // Bound events by the provided `checkpoint_viewed_at`. From EXPLAIN + // ANALYZE, using the checkpoint sequence number directly instead of + // translating into a transaction sequence number bound is more efficient. + query = query.filter( + events::dsl::checkpoint_sequence_number.le(checkpoint_viewed_at as i64), + ); + + // The transactions table doesn't have an index on the senders column, so + // use `tx_senders`. + if let Some(sender) = &filter.sender { + query = query.filter( + events::dsl::tx_sequence_number.eq_any( + tx_senders::dsl::tx_senders + .select(tx_senders::dsl::tx_sequence_number) + .filter(tx_senders::dsl::sender.eq(sender.into_vec())), + ), + ) + } + + if let Some(digest) = &filter.transaction_digest { + // Since the event filter takes in a single tx_digest, we know that + // there will only be one corresponding transaction. We can use + // single_value() to tell the query planner that we expect only one + // instead of a range of values, which will subsequently speed up query + // execution time. + query = query.filter( + events::dsl::tx_sequence_number.nullable().eq( + transactions::dsl::transactions + .select(transactions::dsl::tx_sequence_number) + .filter( + transactions::dsl::transaction_digest + .eq(digest.to_vec()), + ) + .single_value(), + ), + ) + } + + if let Some(module) = &filter.emitting_module { + query = module.apply(query, events::dsl::package, events::dsl::module); + } + + if let Some(type_) = &filter.event_type { + query = type_.apply(query, events::dsl::event_type); + } + + query + }, + )?; + + Ok::<_, diesel::result::Error>((result, checkpoint_viewed_at)) + }) + .await?; + + let mut conn = Connection::new(prev, next); + + // Defer to the provided checkpoint_viewed_at, but if it is not provided, use + // the current available range. This sets a consistent upper bound for + // the nested queries. + for stored in results { + let cursor = stored.cursor(checkpoint_viewed_at).encode_cursor(); + conn.edges.push(Edge::new( + cursor, + Event::try_from_stored_event(stored, checkpoint_viewed_at)?, + )); + } + + Ok(conn) + } + + pub(crate) fn try_from_stored_transaction( + stored_tx: &StoredTransaction, + idx: usize, + checkpoint_viewed_at: u64, + ) -> Result { + let Some(Some(serialized_event)) = stored_tx.events.get(idx) else { + return Err(Error::Internal(format!( + "Could not find event with event_sequence_number {} at transaction {}", + idx, stored_tx.tx_sequence_number + ))); + }; + + let native_event: NativeEvent = bcs::from_bytes(serialized_event).map_err(|_| { + Error::Internal(format!( + "Failed to deserialize event with {} at transaction {}", + idx, stored_tx.tx_sequence_number + )) + })?; + + let stored_event = StoredEvent { + tx_sequence_number: stored_tx.tx_sequence_number, + event_sequence_number: idx as i64, + transaction_digest: stored_tx.transaction_digest.clone(), + checkpoint_sequence_number: stored_tx.checkpoint_sequence_number, + senders: vec![Some(native_event.sender.to_vec())], + package: native_event.package_id.to_vec(), + module: native_event.transaction_module.to_string(), + event_type: native_event + .type_ + .to_canonical_string(/* with_prefix */ true), + bcs: native_event.contents.clone(), + timestamp_ms: stored_tx.timestamp_ms, + }; + + Ok(Self { + stored: Some(stored_event), + native: native_event, + checkpoint_viewed_at, + }) + } + + fn try_from_stored_event( + stored: StoredEvent, + checkpoint_viewed_at: u64, + ) -> Result { + let Some(Some(sender_bytes)) = stored.senders.first() else { + return Err(Error::Internal("No senders found for event".to_string())); + }; + let sender = NativeIotaAddress::from_bytes(sender_bytes) + .map_err(|e| Error::Internal(e.to_string()))?; + + let package_id = + ObjectID::from_bytes(&stored.package).map_err(|e| Error::Internal(e.to_string()))?; + let type_ = parse_iota_struct_tag(&stored.event_type) + .map_err(|e| Error::Internal(e.to_string()))?; + let transaction_module = + Identifier::from_str(&stored.module).map_err(|e| Error::Internal(e.to_string()))?; + let contents = stored.bcs.clone(); + Ok(Event { + stored: Some(stored), + native: NativeEvent { + sender, + package_id, + transaction_module, + type_, + contents, + }, + checkpoint_viewed_at, + }) + } +} + +impl Paginated for StoredEvent { + type Source = events::table; + + fn filter_ge(cursor: &Cursor, query: Query) -> Query { + use events::dsl::{event_sequence_number as event, tx_sequence_number as tx}; + query.filter( + tx.gt(cursor.tx as i64) + .or(tx.eq(cursor.tx as i64).and(event.ge(cursor.e as i64))), + ) + } + + fn filter_le(cursor: &Cursor, query: Query) -> Query { + use events::dsl::{event_sequence_number as event, tx_sequence_number as tx}; + query.filter( + tx.lt(cursor.tx as i64) + .or(tx.eq(cursor.tx as i64).and(event.le(cursor.e as i64))), + ) + } + + fn order(asc: bool, query: Query) -> Query { + use events::dsl; + if asc { + query + .order_by(dsl::tx_sequence_number.asc()) + .then_order_by(dsl::event_sequence_number.asc()) + } else { + query + .order_by(dsl::tx_sequence_number.desc()) + .then_order_by(dsl::event_sequence_number.desc()) + } + } +} + +impl Target for StoredEvent { + fn cursor(&self, checkpoint_viewed_at: u64) -> Cursor { + Cursor::new(EventKey { + tx: self.tx_sequence_number as u64, + e: self.event_sequence_number as u64, + checkpoint_viewed_at, + }) + } +} + +impl Checkpointed for Cursor { + fn checkpoint_viewed_at(&self) -> u64 { + self.checkpoint_viewed_at + } +} diff --git a/crates/sui-graphql-rpc/src/types/execution_result.rs b/crates/iota-graphql-rpc/src/types/execution_result.rs similarity index 93% rename from crates/sui-graphql-rpc/src/types/execution_result.rs rename to crates/iota-graphql-rpc/src/types/execution_result.rs index 86f0504d934..cad53032557 100644 --- a/crates/sui-graphql-rpc/src/types/execution_result.rs +++ b/crates/iota-graphql-rpc/src/types/execution_result.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; diff --git a/crates/iota-graphql-rpc/src/types/gas.rs b/crates/iota-graphql-rpc/src/types/gas.rs new file mode 100644 index 00000000000..192cb2b112a --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/gas.rs @@ -0,0 +1,207 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_graphql::{connection::Connection, *}; +use iota_types::{ + effects::{TransactionEffects as NativeTransactionEffects, TransactionEffectsAPI}, + gas::GasCostSummary as NativeGasCostSummary, + transaction::GasData, +}; + +use super::{ + address::Address, + big_int::BigInt, + cursor::Page, + iota_address::IotaAddress, + object::{self, ObjectFilter, ObjectKey, ObjectLookupKey}, +}; +use crate::types::object::Object; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) struct GasInput { + pub owner: IotaAddress, + pub price: u64, + pub budget: u64, + pub payment_obj_keys: Vec, + /// The checkpoint sequence number at which this was viewed at, or None if + /// the data was requested at the latest checkpoint. + pub checkpoint_viewed_at: Option, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct GasCostSummary { + pub computation_cost: u64, + pub storage_cost: u64, + pub storage_rebate: u64, + pub non_refundable_storage_fee: u64, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct GasEffects { + pub summary: GasCostSummary, + pub object_id: IotaAddress, + pub object_version: u64, + /// The checkpoint sequence number this was viewed at. + pub checkpoint_viewed_at: u64, +} + +/// Configuration for this transaction's gas price and the coins used to pay for +/// gas. +#[Object] +impl GasInput { + /// Address of the owner of the gas object(s) used + async fn gas_sponsor(&self) -> Option
    { + Some(Address { + address: self.owner, + checkpoint_viewed_at: self.checkpoint_viewed_at, + }) + } + + /// Objects used to pay for a transaction's execution and storage + async fn gas_payment( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + // A possible user error during dry run or execution would be to supply a gas + // payment that is not a Move object (i.e a package). Even though the + // transaction would fail to run, this service will still attempt to + // present execution results. If the return type of this field + // is a `MoveObject`, then GraphQL will fail on the top-level with an internal + // error. Instead, we return an `Object` here, so that the rest of the + // `TransactionBlock` will still be viewable. + let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; + + let filter = ObjectFilter { + object_keys: Some(self.payment_obj_keys.clone()), + ..Default::default() + }; + + Object::paginate( + ctx.data_unchecked(), + page, + filter, + self.checkpoint_viewed_at, + ) + .await + .extend() + } + + /// An unsigned integer specifying the number of native tokens per gas unit + /// this transaction will pay (in MICROS). + async fn gas_price(&self) -> Option { + Some(BigInt::from(self.price)) + } + + /// The maximum number of gas units that can be expended by executing this + /// transaction + async fn gas_budget(&self) -> Option { + Some(BigInt::from(self.budget)) + } +} + +/// Breakdown of gas costs in effects. +#[Object] +impl GasCostSummary { + /// Gas paid for executing this transaction (in MICROS). + async fn computation_cost(&self) -> Option { + Some(BigInt::from(self.computation_cost)) + } + + /// Gas paid for the data stored on-chain by this transaction (in MICROS). + async fn storage_cost(&self) -> Option { + Some(BigInt::from(self.storage_cost)) + } + + /// Part of storage cost that can be reclaimed by cleaning up data created + /// by this transaction (when objects are deleted or an object is + /// modified, which is treated as a deletion followed by a creation) (in + /// MICROS). + async fn storage_rebate(&self) -> Option { + Some(BigInt::from(self.storage_rebate)) + } + + /// Part of storage cost that is not reclaimed when data created by this + /// transaction is cleaned up (in MICROS). + async fn non_refundable_storage_fee(&self) -> Option { + Some(BigInt::from(self.non_refundable_storage_fee)) + } +} + +/// Effects related to gas (costs incurred and the identity of the smashed gas +/// object returned). +#[Object] +impl GasEffects { + async fn gas_object(&self, ctx: &Context<'_>) -> Result> { + Object::query( + ctx.data_unchecked(), + self.object_id, + ObjectLookupKey::VersionAt { + version: self.object_version, + checkpoint_viewed_at: Some(self.checkpoint_viewed_at), + }, + ) + .await + .extend() + } + + async fn gas_summary(&self) -> Option<&GasCostSummary> { + Some(&self.summary) + } +} + +impl GasEffects { + /// `checkpoint_viewed_at` represents the checkpoint sequence number at + /// which this `GasEffects` was queried for, or `None` if the data was + /// requested at the latest checkpoint. This is stored on `GasEffects` + /// so that when viewing that entity's state, it will be as if it was + /// read at the same checkpoint. + pub(crate) fn from(effects: &NativeTransactionEffects, checkpoint_viewed_at: u64) -> Self { + let ((id, version, _digest), _owner) = effects.gas_object(); + Self { + summary: GasCostSummary::from(effects.gas_cost_summary()), + object_id: IotaAddress::from(id), + object_version: version.value(), + checkpoint_viewed_at, + } + } +} + +impl GasInput { + /// `checkpoint_viewed_at` represents the checkpoint sequence number at + /// which this `GasInput` was queried for, or `None` if the data was + /// requested at the latest checkpoint. This is stored on `GasInput` so + /// that when viewing that entity's state, it will be as if it was read + /// at the same checkpoint. + pub(crate) fn from(s: &GasData, checkpoint_viewed_at: Option) -> Self { + Self { + owner: s.owner.into(), + price: s.price, + budget: s.budget, + payment_obj_keys: s + .payment + .iter() + .map(|o| ObjectKey { + object_id: o.0.into(), + version: o.1.value(), + }) + .collect(), + checkpoint_viewed_at, + } + } +} + +impl From<&NativeGasCostSummary> for GasCostSummary { + fn from(gcs: &NativeGasCostSummary) -> Self { + Self { + computation_cost: gcs.computation_cost, + storage_cost: gcs.storage_cost, + storage_rebate: gcs.storage_rebate, + non_refundable_storage_fee: gcs.non_refundable_storage_fee, + } + } +} diff --git a/crates/sui-graphql-rpc/src/types/intersect.rs b/crates/iota-graphql-rpc/src/types/intersect.rs similarity index 96% rename from crates/sui-graphql-rpc/src/types/intersect.rs rename to crates/iota-graphql-rpc/src/types/intersect.rs index d6d10fcd228..abdcd7f8153 100644 --- a/crates/sui-graphql-rpc/src/types/intersect.rs +++ b/crates/iota-graphql-rpc/src/types/intersect.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Merges two filter fields. If both values exist, `merge` is used to combine diff --git a/crates/iota-graphql-rpc/src/types/iota_address.rs b/crates/iota-graphql-rpc/src/types/iota_address.rs new file mode 100644 index 00000000000..2930794ff65 --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/iota_address.rs @@ -0,0 +1,250 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::str::FromStr; + +use async_graphql::*; +use iota_types::base_types::{IotaAddress as NativeIotaAddress, ObjectID}; +use move_core_types::account_address::AccountAddress; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +const IOTA_ADDRESS_LENGTH: usize = 32; + +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Copy)] +pub(crate) struct IotaAddress([u8; IOTA_ADDRESS_LENGTH]); + +#[derive(Error, Debug, Eq, PartialEq)] +pub(crate) enum FromStrError { + #[error("Invalid IotaAddress. Missing 0x prefix.")] + NoPrefix, + + #[error( + "Expected IotaAddress string with between 1 and {} digits ({} bytes), received {0}", + IOTA_ADDRESS_LENGTH * 2, + IOTA_ADDRESS_LENGTH, + )] + WrongLength(usize), + + #[error("Invalid character {0:?} at position {1}")] + BadHex(char, usize), +} + +#[derive(Error, Debug, Eq, PartialEq)] +pub(crate) enum FromVecError { + #[error( + "Expected IotaAddress with {} bytes, received {0}", + IOTA_ADDRESS_LENGTH + )] + WrongLength(usize), +} + +impl IotaAddress { + pub fn from_array(arr: [u8; IOTA_ADDRESS_LENGTH]) -> Self { + IotaAddress(arr) + } + + pub fn into_vec(self) -> Vec { + self.0.to_vec() + } + + pub fn as_slice(&self) -> &[u8] { + &self.0 + } + + pub fn from_bytes>(bytes: T) -> Result { + <[u8; IOTA_ADDRESS_LENGTH]>::try_from(bytes.as_ref()) + .map_err(|_| FromVecError::WrongLength(bytes.as_ref().len())) + .map(IotaAddress) + } +} + +#[Scalar(use_type_description = true)] +impl ScalarType for IotaAddress { + fn parse(value: Value) -> InputValueResult { + let Value::String(s) = value else { + return Err(InputValueError::expected_type(value)); + }; + + Ok(IotaAddress::from_str(&s)?) + } + + fn to_value(&self) -> Value { + Value::String(format!("0x{}", hex::encode(self.0))) + } +} + +impl Description for IotaAddress { + fn description() -> &'static str { + "String containing 32B hex-encoded address, with a leading \"0x\". Leading zeroes can be \ + omitted on input but will always appear in outputs (IotaAddress in output is guaranteed \ + to be 66 characters long)." + } +} + +impl TryFrom> for IotaAddress { + type Error = FromVecError; + + fn try_from(bytes: Vec) -> Result { + Self::from_bytes(bytes) + } +} + +impl From for IotaAddress { + fn from(value: AccountAddress) -> Self { + IotaAddress(value.into_bytes()) + } +} + +impl From for AccountAddress { + fn from(value: IotaAddress) -> Self { + AccountAddress::new(value.0) + } +} + +impl From for IotaAddress { + fn from(value: ObjectID) -> Self { + IotaAddress(value.into_bytes()) + } +} + +impl From for ObjectID { + fn from(value: IotaAddress) -> Self { + ObjectID::new(value.0) + } +} + +impl From for IotaAddress { + fn from(value: NativeIotaAddress) -> Self { + IotaAddress(value.to_inner()) + } +} + +impl From for NativeIotaAddress { + fn from(value: IotaAddress) -> Self { + AccountAddress::from(value).into() + } +} + +impl FromStr for IotaAddress { + type Err = FromStrError; + + fn from_str(s: &str) -> Result { + let Some(s) = s.strip_prefix("0x") else { + return Err(FromStrError::NoPrefix); + }; + + if s.is_empty() || s.len() > IOTA_ADDRESS_LENGTH * 2 { + return Err(FromStrError::WrongLength(s.len())); + } + + let mut arr = [0u8; IOTA_ADDRESS_LENGTH]; + hex::decode_to_slice( + // Left pad with `0`-s up to IOTA_ADDRESS_LENGTH * 2 characters long. + format!("{:0>width$}", s, width = IOTA_ADDRESS_LENGTH * 2), + &mut arr[..], + ) + .map_err(|e| match e { + hex::FromHexError::InvalidHexCharacter { c, index } => { + FromStrError::BadHex(c, index + 2) + } + hex::FromHexError::OddLength => unreachable!("SAFETY: Prevented by padding"), + hex::FromHexError::InvalidStringLength => { + unreachable!("SAFETY: Prevented by bounds check") + } + })?; + + Ok(IotaAddress(arr)) + } +} + +impl std::fmt::Display for IotaAddress { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&format!("0x{}", hex::encode(self.0))) + } +} + +#[cfg(test)] +mod tests { + use async_graphql::Value; + + use super::*; + + const STR_ADDRESS: &str = "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; + const ARR_ADDRESS: [u8; IOTA_ADDRESS_LENGTH] = [ + 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, + 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, + ]; + const IOTA_ADDRESS: IotaAddress = IotaAddress(ARR_ADDRESS); + + #[test] + fn test_parse_valid_iotaaddress() { + let parsed = IotaAddress::from_str(STR_ADDRESS).unwrap(); + assert_eq!(parsed.0, ARR_ADDRESS); + } + + #[test] + fn test_to_value() { + let value = ScalarType::to_value(&IOTA_ADDRESS); + assert_eq!(value, Value::String(STR_ADDRESS.to_string())); + } + + #[test] + fn test_from_array() { + let addr = IotaAddress::from_array(ARR_ADDRESS); + assert_eq!(addr, IOTA_ADDRESS); + } + + #[test] + fn test_as_slice() { + assert_eq!(IOTA_ADDRESS.as_slice(), &ARR_ADDRESS); + } + + #[test] + fn test_round_trip() { + let value = ScalarType::to_value(&IOTA_ADDRESS); + let parsed_back = ScalarType::parse(value).unwrap(); + assert_eq!(IOTA_ADDRESS, parsed_back); + } + + #[test] + fn test_parse_no_prefix() { + let err = IotaAddress::from_str(&STR_ADDRESS[2..]).unwrap_err(); + assert_eq!(FromStrError::NoPrefix, err); + } + + #[test] + fn test_parse_invalid_prefix() { + let input = "1x".to_string() + &STR_ADDRESS[2..]; + let err = IotaAddress::from_str(&input).unwrap_err(); + assert_eq!(FromStrError::NoPrefix, err) + } + + #[test] + fn test_parse_invalid_length() { + let input = STR_ADDRESS.to_string() + "0123"; + let err = IotaAddress::from_str(&input).unwrap_err(); + assert_eq!(FromStrError::WrongLength(68), err) + } + + #[test] + fn test_parse_invalid_characters() { + let input = "0xg".to_string() + &STR_ADDRESS[3..]; + let err = IotaAddress::from_str(&input).unwrap_err(); + assert_eq!(FromStrError::BadHex('g', 2), err); + } + + #[test] + fn test_unicode_gibberish() { + let parsed = IotaAddress::from_str("aAௗ0㌀0"); + assert!(parsed.is_err()); + } + + #[test] + fn bad_scalar_type() { + let input = Value::Number(0x42.into()); + let parsed = ::parse(input); + assert!(parsed.is_err()); + } +} diff --git a/crates/iota-graphql-rpc/src/types/iotans_registration.rs b/crates/iota-graphql-rpc/src/types/iotans_registration.rs new file mode 100644 index 00000000000..42a823be817 --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/iotans_registration.rs @@ -0,0 +1,638 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::str::FromStr; + +use async_graphql::{connection::Connection, *}; +use iota_indexer::models::objects::StoredHistoryObject; +use iota_json_rpc::name_service::{ + Domain as NativeDomain, NameRecord, NameServiceConfig, NameServiceError, +}; +use iota_types::{base_types::IotaAddress as NativeIotaAddress, dynamic_field::Field, id::UID}; +use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; +use serde::{Deserialize, Serialize}; + +use super::{ + balance::{self, Balance}, + base64::Base64, + big_int::BigInt, + checkpoint::Checkpoint, + coin::Coin, + cursor::Page, + display::DisplayEntry, + dynamic_field::{DynamicField, DynamicFieldName}, + iota_address::IotaAddress, + move_object::{MoveObject, MoveObjectImpl}, + move_value::MoveValue, + object::{self, Object, ObjectFilter, ObjectImpl, ObjectLookupKey, ObjectOwner, ObjectStatus}, + owner::OwnerImpl, + stake::StakedIota, + string_input::impl_string_input, + transaction_block::{self, TransactionBlock, TransactionBlockFilter}, + type_filter::ExactTypeFilter, +}; +use crate::{ + consistency::{build_objects_query, consistent_range, View}, + data::{Db, DbConnection, QueryExecutor}, + error::Error, +}; + +const MOD_REGISTRATION: &IdentStr = ident_str!("iotans_registration"); +const TYP_REGISTRATION: &IdentStr = ident_str!("IotansRegistration"); + +/// Represents the "core" of the name service (e.g. the on-chain registry and +/// reverse registry). It doesn't contain any fields because we look them up +/// based on the `NameServiceConfig`. +pub(crate) struct NameService; + +/// Wrap IotaNS Domain type to expose as a string scalar in GraphQL. +#[derive(Debug)] +pub(crate) struct Domain(NativeDomain); + +#[derive(Enum, Copy, Clone, Eq, PartialEq)] +#[graphql(remote = "iota_json_rpc::name_service::DomainFormat")] +pub enum DomainFormat { + At, + Dot, +} + +#[derive(Clone, Serialize, Deserialize)] +pub(crate) struct NativeIotansRegistration { + pub id: UID, + pub domain: NativeDomain, + pub domain_name: String, + pub expiration_timestamp_ms: u64, + pub image_url: String, +} + +#[derive(Clone)] +pub(crate) struct IotansRegistration { + /// Representation of this IotansRegistration as a generic Move object. + pub super_: MoveObject, + + /// The deserialized representation of the Move object's contents. + pub native: NativeIotansRegistration, +} + +/// Represents the results of a query for a domain's `NameRecord` and its +/// parent's `NameRecord`. The `expiration_timestamp_ms` on the name records are +/// compared to the checkpoint's timestamp to check that the domain is not +/// expired. +pub(crate) struct DomainExpiration { + /// The domain's `NameRecord`. + pub name_record: Option, + /// The parent's `NameRecord`, populated only if the domain is a subdomain. + pub parent_name_record: Option, + /// The timestamp of the checkpoint at which the query was made. This is + /// used to check if the `expiration_timestamp_ms` on the name records + /// are expired. + pub checkpoint_timestamp_ms: u64, +} + +pub(crate) enum IotansRegistrationDowncastError { + NotAIotansRegistration, + Bcs(bcs::Error), +} + +#[Object] +impl IotansRegistration { + pub(crate) async fn address(&self) -> IotaAddress { + OwnerImpl::from(&self.super_.super_).address().await + } + + /// Objects owned by this object, optionally `filter`-ed. + pub(crate) async fn objects( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + filter: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .objects(ctx, first, after, last, before, filter) + .await + } + + /// Total balance of all coins with marker type owned by this object. If + /// type is not supplied, it defaults to `0x2::iota::IOTA`. + pub(crate) async fn balance( + &self, + ctx: &Context<'_>, + type_: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .balance(ctx, type_) + .await + } + + /// The balances of all coin types owned by this object. + pub(crate) async fn balances( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .balances(ctx, first, after, last, before) + .await + } + + /// The coin objects for this object. + /// + /// `type` is a filter on the coin's type parameter, defaulting to + /// `0x2::iota::IOTA`. + pub(crate) async fn coins( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + type_: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .coins(ctx, first, after, last, before, type_) + .await + } + + /// The `0x3::staking_pool::StakedIota` objects owned by this object. + pub(crate) async fn staked_iotas( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .staked_iotas(ctx, first, after, last, before) + .await + } + + /// The domain explicitly configured as the default domain pointing to this + /// object. + pub(crate) async fn default_iotans_name( + &self, + ctx: &Context<'_>, + format: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .default_iotans_name(ctx, format) + .await + } + + /// The IotansRegistration NFTs owned by this object. These grant the owner + /// the capability to manage the associated domain. + pub(crate) async fn iotans_registrations( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .iotans_registrations(ctx, first, after, last, before) + .await + } + + pub(crate) async fn version(&self) -> u64 { + ObjectImpl(&self.super_.super_).version().await + } + + /// The current status of the object as read from the off-chain store. The + /// possible states are: NOT_INDEXED, the object is loaded from + /// serialized data, such as the contents of a genesis or system package + /// upgrade transaction. LIVE, the version returned is the most recent for + /// the object, and it is not deleted or wrapped at that version. + /// HISTORICAL, the object was referenced at a specific version or + /// checkpoint, so is fetched from historical tables and may not be the + /// latest version of the object. WRAPPED_OR_DELETED, the object is deleted + /// or wrapped and only partial information can be loaded." + pub(crate) async fn status(&self) -> ObjectStatus { + ObjectImpl(&self.super_.super_).status().await + } + + /// 32-byte hash that identifies the object's contents, encoded as a Base58 + /// string. + pub(crate) async fn digest(&self) -> Option { + ObjectImpl(&self.super_.super_).digest().await + } + + /// The owner type of this object: Immutable, Shared, Parent, Address + pub(crate) async fn owner(&self, ctx: &Context<'_>) -> Option { + ObjectImpl(&self.super_.super_).owner(ctx).await + } + + /// The transaction block that created this version of the object. + pub(crate) async fn previous_transaction_block( + &self, + ctx: &Context<'_>, + ) -> Result> { + ObjectImpl(&self.super_.super_) + .previous_transaction_block(ctx) + .await + } + + /// The amount of IOTA we would rebate if this object gets deleted or + /// mutated. This number is recalculated based on the present storage + /// gas price. + pub(crate) async fn storage_rebate(&self) -> Option { + ObjectImpl(&self.super_.super_).storage_rebate().await + } + + /// The transaction blocks that sent objects to this object. + pub(crate) async fn received_transaction_blocks( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + filter: Option, + ) -> Result> { + ObjectImpl(&self.super_.super_) + .received_transaction_blocks(ctx, first, after, last, before, filter) + .await + } + + /// The Base64-encoded BCS serialization of the object's content. + pub(crate) async fn bcs(&self) -> Result> { + ObjectImpl(&self.super_.super_).bcs().await + } + + /// Displays the contents of the Move object in a JSON string and through + /// GraphQL types. Also provides the flat representation of the type + /// signature, and the BCS of the corresponding data. + pub(crate) async fn contents(&self) -> Option { + MoveObjectImpl(&self.super_).contents().await + } + + /// Determines whether a transaction can transfer this object, using the + /// TransferObjects transaction command or + /// `iota::transfer::public_transfer`, both of which require the object to + /// have the `key` and `store` abilities. + pub(crate) async fn has_public_transfer(&self, ctx: &Context<'_>) -> Result { + MoveObjectImpl(&self.super_).has_public_transfer(ctx).await + } + + /// The set of named templates defined on-chain for the type of this object, + /// to be handled off-chain. The server substitutes data from the object + /// into these templates to generate a display string per template. + pub(crate) async fn display(&self, ctx: &Context<'_>) -> Result>> { + ObjectImpl(&self.super_.super_).display(ctx).await + } + + /// Access a dynamic field on an object using its name. Names are arbitrary + /// Move values whose type have `copy`, `drop`, and `store`, and are + /// specified using their type, and their BCS contents, Base64 encoded. + /// + /// Dynamic fields on wrapped objects can be accessed by using the same API + /// under the Owner type. + pub(crate) async fn dynamic_field( + &self, + ctx: &Context<'_>, + name: DynamicFieldName, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .dynamic_field(ctx, name, Some(self.super_.super_.version_impl())) + .await + } + + /// Access a dynamic object field on an object using its name. Names are + /// arbitrary Move values whose type have `copy`, `drop`, and `store`, + /// and are specified using their type, and their BCS contents, Base64 + /// encoded. The value of a dynamic object field can also be accessed + /// off-chain directly via its address (e.g. using `Query.object`). + /// + /// Dynamic fields on wrapped objects can be accessed by using the same API + /// under the Owner type. + pub(crate) async fn dynamic_object_field( + &self, + ctx: &Context<'_>, + name: DynamicFieldName, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .dynamic_object_field(ctx, name, Some(self.super_.super_.version_impl())) + .await + } + + /// The dynamic fields and dynamic object fields on an object. + /// + /// Dynamic fields on wrapped objects can be accessed by using the same API + /// under the Owner type. + pub(crate) async fn dynamic_fields( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(&self.super_.super_) + .dynamic_fields( + ctx, + first, + after, + last, + before, + Some(self.super_.super_.version_impl()), + ) + .await + } + + /// Domain name of the IotansRegistration object + async fn domain(&self) -> &str { + &self.native.domain_name + } +} + +impl NameService { + /// Lookup the IotaNS NameRecord for the given `domain` name. `config` + /// specifies where to find the domain name registry, and its type. + /// + /// `checkpoint_viewed_at` represents the checkpoint sequence number at + /// which this was queried for, or `None` if the data was requested at + /// the latest checkpoint. + /// + /// The `NameRecord` is returned only if it has not expired as of the + /// `checkpoint_viewed_at` or latest checkpoint's timestamp. + /// + /// For leaf domains, the `NameRecord` is returned only if its parent is + /// valid and not expired. + pub(crate) async fn resolve_to_record( + ctx: &Context<'_>, + domain: &Domain, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + // Query for the domain's NameRecord and parent NameRecord if applicable. The + // checkpoint's timestamp is also fetched. These values are used to + // determine if the domain is expired. + let Some(domain_expiration) = + Self::query_domain_expiration(ctx, domain, checkpoint_viewed_at).await? + else { + return Ok(None); + }; + + // Get the name_record from the query. If we didn't find it, we return as it + // means that the requested name is not registered. + let Some(name_record) = domain_expiration.name_record else { + return Ok(None); + }; + + // If name record is SLD, or Node subdomain, we can check the expiration and + // return the record if not expired. + if !name_record.is_leaf_record() { + return if !name_record.is_node_expired(domain_expiration.checkpoint_timestamp_ms) { + Ok(Some(name_record)) + } else { + Err(Error::NameService(NameServiceError::NameExpired)) + }; + } + + // If we cannot find the parent, then the name is expired. + let Some(parent_name_record) = domain_expiration.parent_name_record else { + return Err(Error::NameService(NameServiceError::NameExpired)); + }; + + // If the parent is valid for this leaf, and not expired, then we can return the + // name record. Otherwise, the name is expired. + if parent_name_record.is_valid_leaf_parent(&name_record) + && !parent_name_record.is_node_expired(domain_expiration.checkpoint_timestamp_ms) + { + Ok(Some(name_record)) + } else { + Err(Error::NameService(NameServiceError::NameExpired)) + } + } + + /// Lookup the IotaNS Domain for the given `address`. `config` specifies + /// where to find the domain name registry, and its type. + /// + /// `checkpoint_viewed_at` represents the checkpoint sequence number at + /// which this was queried for, or `None` if the data was requested at + /// the latest checkpoint. + pub(crate) async fn reverse_resolve_to_name( + ctx: &Context<'_>, + address: IotaAddress, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + let config = ctx.data_unchecked::(); + + let reverse_record_id = config.reverse_record_field_id(address.as_slice()); + + let Some(object) = MoveObject::query( + ctx.data_unchecked(), + reverse_record_id.into(), + match checkpoint_viewed_at { + Some(checkpoint_viewed_at) => ObjectLookupKey::LatestAt(checkpoint_viewed_at), + None => ObjectLookupKey::Latest, + }, + ) + .await? + else { + return Ok(None); + }; + + let field: Field = object + .native + .to_rust() + .ok_or_else(|| Error::Internal("Malformed Iotans Domain".to_string()))?; + + let domain = Domain(field.value); + + // We attempt to resolve the domain to a record, and if it fails, we return + // None. That way we can validate that the name has not expired and is + // still valid. + let Some(_) = Self::resolve_to_record(ctx, &domain, checkpoint_viewed_at).await? else { + return Ok(None); + }; + + Ok(Some(domain.0)) + } + + /// Query for a domain's NameRecord, its parent's NameRecord if supplied, + /// and the timestamp of the checkpoint bound. + async fn query_domain_expiration( + ctx: &Context<'_>, + domain: &Domain, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + let config = ctx.data_unchecked::(); + let db: &crate::data::pg::PgExecutor = ctx.data_unchecked::(); + // Construct the list of `object_id`s to look up. The first element is the + // domain's `NameRecord`. If the domain is a subdomain, there will be a + // second element for the parent's `NameRecord`. + let mut object_ids = vec![IotaAddress::from(config.record_field_id(&domain.0))]; + if domain.0.is_subdomain() { + object_ids.push(IotaAddress::from( + config.record_field_id(&domain.0.parent()), + )); + } + + // Create a page with a bound of `object_ids` length to fetch the relevant + // `NameRecord`s. + let page: Page = Page::from_params( + ctx.data_unchecked(), + Some(object_ids.len() as u64), + None, + None, + None, + ) + .map_err(|_| { + Error::Internal("Page size of 2 is incompatible with configured limits".to_string()) + })?; + + // prepare the filter for the query. + let filter = ObjectFilter { + object_ids: Some(object_ids.clone()), + ..Default::default() + }; + + let response = db + .execute_repeatable(move |conn| { + let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { + return Ok::<_, diesel::result::Error>(None); + }; + + let timestamp_ms = Checkpoint::query_timestamp(conn, rhs)?; + + let sql = build_objects_query( + View::Consistent, + lhs as i64, + rhs as i64, + &page, + move |query| filter.apply(query), + move |newer| newer, + ); + + let objects: Vec = + conn.results(move || sql.clone().into_boxed())?; + + Ok(Some((timestamp_ms, objects))) + }) + .await?; + + let Some((checkpoint_timestamp_ms, results)) = response else { + return Err(Error::Client( + "Requested data is outside the available range".to_string(), + )); + }; + + let mut domain_expiration = DomainExpiration { + parent_name_record: None, + name_record: None, + checkpoint_timestamp_ms, + }; + + // Max size of results is 2. We loop through them, convert to objects, and then + // parse name_record. We then assign it to the correct field on + // `domain_expiration` based on the address. + for result in results { + let object = Object::try_from_stored_history_object(result, None)?; + let move_object = MoveObject::try_from(&object).map_err(|_| { + Error::Internal(format!( + "Expected {0} to be a NameRecord, but it's not a Move Object.", + object.address + )) + })?; + + let record = NameRecord::try_from(move_object.native)?; + + if object.address == object_ids[0] { + domain_expiration.name_record = Some(record); + } else if Some(&object.address) == object_ids.get(1) { + domain_expiration.parent_name_record = Some(record); + } + } + + Ok(Some(domain_expiration)) + } +} + +impl IotansRegistration { + /// Query the database for a `page` of IotaNS registrations. The page uses + /// the same cursor type as is used for `Object`, and is further + /// filtered to a particular `owner`. `config` specifies where to find + /// the domain name registry and its type. + /// + /// `checkpoint_viewed_at` represents the checkpoint sequence number at + /// which this page was queried for, or `None` if the data was requested + /// at the latest checkpoint. Each entity returned in the connection + /// will inherit this checkpoint, so that when viewing that entity's + /// state, it will be as if it was read at the same checkpoint. + pub(crate) async fn paginate( + db: &Db, + config: &NameServiceConfig, + page: Page, + owner: IotaAddress, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + let type_ = IotansRegistration::type_(config.package_address.into()); + + let filter = ObjectFilter { + type_: Some(type_.clone().into()), + owner: Some(owner), + ..Default::default() + }; + + Object::paginate_subtype(db, page, filter, checkpoint_viewed_at, |object| { + let address = object.address; + let move_object = MoveObject::try_from(&object).map_err(|_| { + Error::Internal(format!( + "Expected {address} to be a IotansRegistration, but it's not a Move Object.", + )) + })?; + + IotansRegistration::try_from(&move_object, &type_).map_err(|_| { + Error::Internal(format!( + "Expected {address} to be a IotansRegistration, but it is not." + )) + }) + }) + .await + } + + /// Return the type representing a `IotansRegistration` on chain. This can + /// change from chain to chain (mainnet, testnet, devnet etc). + pub(crate) fn type_(package: IotaAddress) -> StructTag { + StructTag { + address: package.into(), + module: MOD_REGISTRATION.to_owned(), + name: TYP_REGISTRATION.to_owned(), + type_params: vec![], + } + } + + // Because the type of the IotansRegistration object is not constant, + // we need to take it in as a param. + pub(crate) fn try_from( + move_object: &MoveObject, + tag: &StructTag, + ) -> Result { + if !move_object.native.is_type(tag) { + return Err(IotansRegistrationDowncastError::NotAIotansRegistration); + } + + Ok(Self { + super_: move_object.clone(), + native: bcs::from_bytes(move_object.native.contents()) + .map_err(IotansRegistrationDowncastError::Bcs)?, + }) + } +} + +impl_string_input!(Domain); + +impl FromStr for Domain { + type Err = ::Err; + + fn from_str(s: &str) -> Result { + Ok(Domain(NativeDomain::from_str(s)?)) + } +} diff --git a/crates/sui-graphql-rpc/src/types/json.rs b/crates/iota-graphql-rpc/src/types/json.rs similarity index 93% rename from crates/sui-graphql-rpc/src/types/json.rs rename to crates/iota-graphql-rpc/src/types/json.rs index 99e98d1c54e..fd4bc82e9a8 100644 --- a/crates/sui-graphql-rpc/src/types/json.rs +++ b/crates/iota-graphql-rpc/src/types/json.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::fmt; diff --git a/crates/iota-graphql-rpc/src/types/mod.rs b/crates/iota-graphql-rpc/src/types/mod.rs new file mode 100644 index 00000000000..7c1c026ab15 --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/mod.rs @@ -0,0 +1,59 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub(crate) mod address; +pub(crate) mod available_range; +pub(crate) mod balance; +pub(crate) mod balance_change; +pub(crate) mod base64; +pub(crate) mod big_int; +pub(crate) mod chain_identifier; +pub(crate) mod checkpoint; +pub(crate) mod coin; +pub(crate) mod coin_metadata; +pub(crate) mod cursor; +pub(crate) mod date_time; +pub(crate) mod digest; +pub(crate) mod display; +pub(crate) mod dry_run_result; +pub(crate) mod dynamic_field; +pub(crate) mod epoch; +pub(crate) mod event; +pub(crate) mod execution_result; +pub(crate) mod gas; +pub(crate) mod intersect; +pub(crate) mod iota_address; +pub(crate) mod iotans_registration; +pub(crate) mod json; +pub(crate) mod move_function; +pub(crate) mod move_module; +pub(crate) mod move_object; +pub(crate) mod move_package; +pub(crate) mod move_struct; +pub(crate) mod move_type; +pub(crate) mod move_value; +pub(crate) mod object; +pub(crate) mod object_change; +pub(crate) mod object_read; +pub(crate) mod open_move_type; +pub(crate) mod owner; +pub(crate) mod protocol_config; +pub(crate) mod query; +pub(crate) mod safe_mode; +pub(crate) mod stake; +pub(crate) mod stake_subsidy; +pub(crate) mod storage_fund; +pub(crate) mod string_input; +pub(crate) mod system_parameters; +pub(crate) mod system_state_summary; +pub(crate) mod transaction_block; +pub(crate) mod transaction_block_effects; +pub(crate) mod transaction_block_kind; +pub(crate) mod transaction_metadata; +pub(crate) mod type_filter; +pub(crate) mod unchanged_shared_object; +pub(crate) mod validator; +pub(crate) mod validator_credentials; +pub(crate) mod validator_set; +pub(crate) mod zklogin_verify_signature; diff --git a/crates/sui-graphql-rpc/src/types/move_function.rs b/crates/iota-graphql-rpc/src/types/move_function.rs similarity index 95% rename from crates/sui-graphql-rpc/src/types/move_function.rs rename to crates/iota-graphql-rpc/src/types/move_function.rs index 001909d1e97..55c3b4a47da 100644 --- a/crates/sui-graphql-rpc/src/types/move_function.rs +++ b/crates/iota-graphql-rpc/src/types/move_function.rs @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; -use sui_package_resolver::FunctionDef; +use iota_package_resolver::FunctionDef; use super::{ + iota_address::IotaAddress, move_module::MoveModule, open_move_type::{abilities, MoveAbility, MoveVisibility, OpenMoveType}, - sui_address::SuiAddress, }; use crate::{data::Db, error::Error}; pub(crate) struct MoveFunction { - package: SuiAddress, + package: IotaAddress, module: String, name: String, visibility: MoveVisibility, @@ -92,7 +93,7 @@ impl MoveFunction { impl MoveFunction { pub(crate) fn new( - package: SuiAddress, + package: IotaAddress, module: String, name: String, def: FunctionDef, @@ -124,7 +125,7 @@ impl MoveFunction { pub(crate) async fn query( db: &Db, - address: SuiAddress, + address: IotaAddress, module: &str, function: &str, checkpoint_viewed_at: u64, diff --git a/crates/sui-graphql-rpc/src/types/move_module.rs b/crates/iota-graphql-rpc/src/types/move_module.rs similarity index 98% rename from crates/sui-graphql-rpc/src/types/move_module.rs rename to crates/iota-graphql-rpc/src/types/move_module.rs index 4361af3efd9..d800645d69b 100644 --- a/crates/sui-graphql-rpc/src/types/move_module.rs +++ b/crates/iota-graphql-rpc/src/types/move_module.rs @@ -1,23 +1,24 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::{ connection::{Connection, CursorType, Edge}, *, }; +use iota_package_resolver::Module as ParsedMoveModule; use move_binary_format::{access::ModuleAccess, binary_views::BinaryIndexedView}; use move_disassembler::disassembler::Disassembler; use move_ir_types::location::Loc; -use sui_package_resolver::Module as ParsedMoveModule; use super::{ base64::Base64, cursor::{JsonCursor, Page}, + iota_address::IotaAddress, move_function::MoveFunction, move_package::MovePackage, move_struct::MoveStruct, object::ObjectLookupKey, - sui_address::SuiAddress, }; use crate::{ consistency::{ConsistentIndexCursor, ConsistentNamedCursor}, @@ -27,7 +28,7 @@ use crate::{ #[derive(Clone)] pub(crate) struct MoveModule { - pub storage_id: SuiAddress, + pub storage_id: IotaAddress, pub native: Vec, pub parsed: ParsedMoveModule, /// The checkpoint sequence number this was viewed at. @@ -325,7 +326,7 @@ impl MoveModule { pub(crate) async fn query( db: &Db, - address: SuiAddress, + address: IotaAddress, name: &str, checkpoint_viewed_at: u64, ) -> Result, Error> { diff --git a/crates/sui-graphql-rpc/src/types/move_object.rs b/crates/iota-graphql-rpc/src/types/move_object.rs similarity index 87% rename from crates/sui-graphql-rpc/src/types/move_object.rs rename to crates/iota-graphql-rpc/src/types/move_object.rs index e809ad77992..cafc12eff87 100644 --- a/crates/sui-graphql-rpc/src/types/move_object.rs +++ b/crates/iota-graphql-rpc/src/types/move_object.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::{connection::Connection, *}; -use sui_json_rpc::name_service::NameServiceConfig; -use sui_types::{ +use iota_json_rpc::name_service::NameServiceConfig; +use iota_types::{ object::{Data, MoveObject as NativeMoveObject}, TypeTag, }; @@ -17,17 +18,17 @@ use super::{ cursor::Page, display::DisplayEntry, dynamic_field::{DynamicField, DynamicFieldName}, + iota_address::IotaAddress, + iotans_registration::{DomainFormat, IotansRegistration, IotansRegistrationDowncastError}, move_type::MoveType, move_value::MoveValue, object::{self, Object, ObjectFilter, ObjectImpl, ObjectLookupKey, ObjectOwner, ObjectStatus}, owner::OwnerImpl, - stake::StakedSuiDowncastError, - sui_address::SuiAddress, - suins_registration::{DomainFormat, SuinsRegistration, SuinsRegistrationDowncastError}, + stake::StakedIotaDowncastError, transaction_block::{self, TransactionBlock, TransactionBlockFilter}, type_filter::ExactTypeFilter, }; -use crate::{data::Db, error::Error, types::stake::StakedSui}; +use crate::{data::Db, error::Error, types::stake::StakedIota}; #[derive(Clone)] pub(crate) struct MoveObject { @@ -63,7 +64,7 @@ pub(crate) enum MoveObjectDowncastError { name = "has_public_transfer", ty = "bool", desc = "Determines whether a transaction can transfer this object, using the \ - TransferObjects transaction command or `sui::transfer::public_transfer`, both of \ + TransferObjects transaction command or `iota::transfer::public_transfer`, both of \ which require the object to have the `key` and `store` abilities." ), field( @@ -111,8 +112,8 @@ pub(crate) enum IMoveObject { MoveObject(MoveObject), Coin(Coin), CoinMetadata(CoinMetadata), - StakedSui(StakedSui), - SuinsRegistration(SuinsRegistration), + StakedIota(StakedIota), + IotansRegistration(IotansRegistration), } /// The representation of an object as a Move Object, which exposes additional @@ -120,7 +121,7 @@ pub(crate) enum IMoveObject { /// etc.) about this object. #[Object] impl MoveObject { - pub(crate) async fn address(&self) -> SuiAddress { + pub(crate) async fn address(&self) -> IotaAddress { OwnerImpl::from(&self.super_).address().await } @@ -140,7 +141,7 @@ impl MoveObject { } /// Total balance of all coins with marker type owned by this object. If - /// type is not supplied, it defaults to `0x2::sui::SUI`. + /// type is not supplied, it defaults to `0x2::iota::IOTA`. pub(crate) async fn balance( &self, ctx: &Context<'_>, @@ -166,7 +167,7 @@ impl MoveObject { /// The coin objects for this object. /// /// `type` is a filter on the coin's type parameter, defaulting to - /// `0x2::sui::SUI`. + /// `0x2::iota::IOTA`. pub(crate) async fn coins( &self, ctx: &Context<'_>, @@ -181,44 +182,44 @@ impl MoveObject { .await } - /// The `0x3::staking_pool::StakedSui` objects owned by this object. - pub(crate) async fn staked_suis( + /// The `0x3::staking_pool::StakedIota` objects owned by this object. + pub(crate) async fn staked_iotas( &self, ctx: &Context<'_>, first: Option, after: Option, last: Option, before: Option, - ) -> Result> { + ) -> Result> { OwnerImpl::from(&self.super_) - .staked_suis(ctx, first, after, last, before) + .staked_iotas(ctx, first, after, last, before) .await } /// The domain explicitly configured as the default domain pointing to this /// object. - pub(crate) async fn default_suins_name( + pub(crate) async fn default_iotans_name( &self, ctx: &Context<'_>, format: Option, ) -> Result> { OwnerImpl::from(&self.super_) - .default_suins_name(ctx, format) + .default_iotans_name(ctx, format) .await } - /// The SuinsRegistration NFTs owned by this object. These grant the owner + /// The IotansRegistration NFTs owned by this object. These grant the owner /// the capability to manage the associated domain. - pub(crate) async fn suins_registrations( + pub(crate) async fn iotans_registrations( &self, ctx: &Context<'_>, first: Option, after: Option, last: Option, before: Option, - ) -> Result> { + ) -> Result> { OwnerImpl::from(&self.super_) - .suins_registrations(ctx, first, after, last, before) + .iotans_registrations(ctx, first, after, last, before) .await } @@ -260,7 +261,7 @@ impl MoveObject { .await } - /// The amount of SUI we would rebate if this object gets deleted or + /// The amount of IOTA we would rebate if this object gets deleted or /// mutated. This number is recalculated based on the present storage /// gas price. pub(crate) async fn storage_rebate(&self) -> Option { @@ -296,7 +297,7 @@ impl MoveObject { /// Determines whether a transaction can transfer this object, using the /// TransferObjects transaction command or - /// `sui::transfer::public_transfer`, both of which require the object to + /// `iota::transfer::public_transfer`, both of which require the object to /// have the `key` and `store` abilities. pub(crate) async fn has_public_transfer(&self, ctx: &Context<'_>) -> Result { MoveObjectImpl(self).has_public_transfer(ctx).await @@ -379,13 +380,13 @@ impl MoveObject { } /// Attempts to convert the Move object into a - /// `0x3::staking_pool::StakedSui`. - async fn as_staked_sui(&self) -> Result> { - match StakedSui::try_from(self) { + /// `0x3::staking_pool::StakedIota`. + async fn as_staked_iota(&self) -> Result> { + match StakedIota::try_from(self) { Ok(coin) => Ok(Some(coin)), - Err(StakedSuiDowncastError::NotAStakedSui) => Ok(None), - Err(StakedSuiDowncastError::Bcs(e)) => Err(Error::Internal(format!( - "Failed to deserialize StakedSui: {e}" + Err(StakedIotaDowncastError::NotAStakedIota) => Ok(None), + Err(StakedIotaDowncastError::Bcs(e)) => Err(Error::Internal(format!( + "Failed to deserialize StakedIota: {e}" ))) .extend(), } @@ -403,16 +404,19 @@ impl MoveObject { } } - /// Attempts to convert the Move object into a `SuinsRegistration` object. - async fn as_suins_registration(&self, ctx: &Context<'_>) -> Result> { + /// Attempts to convert the Move object into a `IotansRegistration` object. + async fn as_iotans_registration( + &self, + ctx: &Context<'_>, + ) -> Result> { let cfg: &NameServiceConfig = ctx.data_unchecked(); - let tag = SuinsRegistration::type_(cfg.package_address.into()); + let tag = IotansRegistration::type_(cfg.package_address.into()); - match SuinsRegistration::try_from(self, &tag) { + match IotansRegistration::try_from(self, &tag) { Ok(registration) => Ok(Some(registration)), - Err(SuinsRegistrationDowncastError::NotASuinsRegistration) => Ok(None), - Err(SuinsRegistrationDowncastError::Bcs(e)) => Err(Error::Internal(format!( - "Failed to deserialize SuinsRegistration: {e}", + Err(IotansRegistrationDowncastError::NotAIotansRegistration) => Ok(None), + Err(IotansRegistrationDowncastError::Bcs(e)) => Err(Error::Internal(format!( + "Failed to deserialize IotansRegistration: {e}", ))) .extend(), } @@ -435,7 +439,7 @@ impl MoveObjectImpl<'_> { impl MoveObject { pub(crate) async fn query( db: &Db, - address: SuiAddress, + address: IotaAddress, key: ObjectLookupKey, ) -> Result, Error> { let Some(object) = Object::query(db, address, key).await? else { diff --git a/crates/iota-graphql-rpc/src/types/move_package.rs b/crates/iota-graphql-rpc/src/types/move_package.rs new file mode 100644 index 00000000000..a1b91c4d3e0 --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/move_package.rs @@ -0,0 +1,475 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_graphql::{ + connection::{Connection, CursorType, Edge}, + *, +}; +use iota_package_resolver::{error::Error as PackageCacheError, Package as ParsedMovePackage}; +use iota_types::{move_package::MovePackage as NativeMovePackage, object::Data}; + +use super::{ + balance::{self, Balance}, + base64::Base64, + big_int::BigInt, + coin::Coin, + cursor::{JsonCursor, Page}, + iota_address::IotaAddress, + iotans_registration::{DomainFormat, IotansRegistration}, + move_module::MoveModule, + move_object::MoveObject, + object::{self, Object, ObjectFilter, ObjectImpl, ObjectLookupKey, ObjectOwner, ObjectStatus}, + owner::OwnerImpl, + stake::StakedIota, + transaction_block::{self, TransactionBlock, TransactionBlockFilter}, + type_filter::ExactTypeFilter, +}; +use crate::{ + consistency::ConsistentNamedCursor, data::Db, error::Error, types::checkpoint::Checkpoint, +}; + +#[derive(Clone)] +pub(crate) struct MovePackage { + /// Representation of this Move Object as a generic Object. + pub super_: Object, + + /// Move-object-specific data, extracted from the native representation at + /// `graphql_object.native_object.data`. + pub native: NativeMovePackage, + + /// The checkpoint sequence number this package was viewed at. + pub checkpoint_viewed_at: u64, +} + +/// Information used by a package to link to a specific version of its +/// dependency. +#[derive(SimpleObject)] +struct Linkage { + /// The ID on-chain of the first version of the dependency. + original_id: IotaAddress, + + /// The ID on-chain of the version of the dependency that this package + /// depends on. + upgraded_id: IotaAddress, + + /// The version of the dependency that this package depends on. + version: u64, +} + +/// Information about which previous versions of a package introduced its types. +#[derive(SimpleObject)] +struct TypeOrigin { + /// Module defining the type. + module: String, + + /// Name of the struct. + #[graphql(name = "struct")] + struct_: String, + + /// The storage ID of the package that first defined this type. + defining_id: IotaAddress, +} + +pub(crate) struct MovePackageDowncastError; + +pub(crate) type CModule = JsonCursor; + +/// A MovePackage is a kind of Move object that represents code that has been +/// published on chain. It exposes information about its modules, type +/// definitions, functions, and dependencies. +#[Object] +impl MovePackage { + pub(crate) async fn address(&self) -> IotaAddress { + OwnerImpl::from(&self.super_).address().await + } + + /// Objects owned by this package, optionally `filter`-ed. + /// + /// Note that objects owned by a package are inaccessible, because packages + /// are immutable and cannot be owned by an address. + pub(crate) async fn objects( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + filter: Option, + ) -> Result> { + OwnerImpl::from(&self.super_) + .objects(ctx, first, after, last, before, filter) + .await + } + + /// Total balance of all coins with marker type owned by this package. If + /// type is not supplied, it defaults to `0x2::iota::IOTA`. + /// + /// Note that coins owned by a package are inaccessible, because packages + /// are immutable and cannot be owned by an address. + pub(crate) async fn balance( + &self, + ctx: &Context<'_>, + type_: Option, + ) -> Result> { + OwnerImpl::from(&self.super_).balance(ctx, type_).await + } + + /// The balances of all coin types owned by this package. + /// + /// Note that coins owned by a package are inaccessible, because packages + /// are immutable and cannot be owned by an address. + pub(crate) async fn balances( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(&self.super_) + .balances(ctx, first, after, last, before) + .await + } + + /// The coin objects owned by this package. + /// + /// `type` is a filter on the coin's type parameter, defaulting to + /// `0x2::iota::IOTA`. + /// + /// Note that coins owned by a package are inaccessible, because packages + /// are immutable and cannot be owned by an address. + pub(crate) async fn coins( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + type_: Option, + ) -> Result> { + OwnerImpl::from(&self.super_) + .coins(ctx, first, after, last, before, type_) + .await + } + + /// The `0x3::staking_pool::StakedIota` objects owned by this package. + /// + /// Note that objects owned by a package are inaccessible, because packages + /// are immutable and cannot be owned by an address. + pub(crate) async fn staked_iotas( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(&self.super_) + .staked_iotas(ctx, first, after, last, before) + .await + } + + /// The domain explicitly configured as the default domain pointing to this + /// object. + pub(crate) async fn default_iotans_name( + &self, + ctx: &Context<'_>, + format: Option, + ) -> Result> { + OwnerImpl::from(&self.super_) + .default_iotans_name(ctx, format) + .await + } + + /// The IotansRegistration NFTs owned by this package. These grant the owner + /// the capability to manage the associated domain. + /// + /// Note that objects owned by a package are inaccessible, because packages + /// are immutable and cannot be owned by an address. + pub(crate) async fn iotans_registrations( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(&self.super_) + .iotans_registrations(ctx, first, after, last, before) + .await + } + + pub(crate) async fn version(&self) -> u64 { + ObjectImpl(&self.super_).version().await + } + + /// The current status of the object as read from the off-chain store. The + /// possible states are: NOT_INDEXED, the object is loaded from + /// serialized data, such as the contents of a genesis or system package + /// upgrade transaction. LIVE, the version returned is the most recent for + /// the object, and it is not deleted or wrapped at that version. + /// HISTORICAL, the object was referenced at a specific version or + /// checkpoint, so is fetched from historical tables and may not be the + /// latest version of the object. WRAPPED_OR_DELETED, the object is deleted + /// or wrapped and only partial information can be loaded." + pub(crate) async fn status(&self) -> ObjectStatus { + ObjectImpl(&self.super_).status().await + } + + /// 32-byte hash that identifies the package's contents, encoded as a Base58 + /// string. + pub(crate) async fn digest(&self) -> Option { + ObjectImpl(&self.super_).digest().await + } + + /// The owner type of this object: Immutable, Shared, Parent, Address + /// Packages are always Immutable. + pub(crate) async fn owner(&self, ctx: &Context<'_>) -> Option { + ObjectImpl(&self.super_).owner(ctx).await + } + + /// The transaction block that published or upgraded this package. + pub(crate) async fn previous_transaction_block( + &self, + ctx: &Context<'_>, + ) -> Result> { + ObjectImpl(&self.super_) + .previous_transaction_block(ctx) + .await + } + + /// The amount of IOTA we would rebate if this object gets deleted or + /// mutated. This number is recalculated based on the present storage + /// gas price. + /// + /// Note that packages cannot be deleted or mutated, so this number is + /// provided purely for reference. + pub(crate) async fn storage_rebate(&self) -> Option { + ObjectImpl(&self.super_).storage_rebate().await + } + + /// The transaction blocks that sent objects to this package. + /// + /// Note that objects that have been sent to a package become inaccessible. + pub(crate) async fn received_transaction_blocks( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + filter: Option, + ) -> Result> { + ObjectImpl(&self.super_) + .received_transaction_blocks(ctx, first, after, last, before, filter) + .await + } + + /// The Base64-encoded BCS serialization of the package's content. + pub(crate) async fn bcs(&self) -> Result> { + ObjectImpl(&self.super_).bcs().await + } + + /// A representation of the module called `name` in this package, including + /// the structs and functions it defines. + async fn module(&self, name: String) -> Result> { + self.module_impl(&name).extend() + } + + /// Paginate through the MoveModules defined in this package. + pub async fn modules( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result>> { + use std::ops::Bound as B; + + let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; + let cursor_viewed_at = page.validate_cursor_consistency()?; + let checkpoint_viewed_at = cursor_viewed_at.unwrap_or(self.checkpoint_viewed_at); + + let parsed = self.parsed_package()?; + let module_range = parsed.modules().range::(( + page.after().map_or(B::Unbounded, |a| B::Excluded(&a.name)), + page.before().map_or(B::Unbounded, |b| B::Excluded(&b.name)), + )); + + let mut connection = Connection::new(false, false); + let modules = if page.is_from_front() { + module_range.take(page.limit()).collect() + } else { + let mut ms: Vec<_> = module_range.rev().take(page.limit()).collect(); + ms.reverse(); + ms + }; + + connection.has_previous_page = modules.first().is_some_and(|(fst, _)| { + parsed + .modules() + .range::((B::Unbounded, B::Excluded(*fst))) + .next() + .is_some() + }); + + connection.has_next_page = modules.last().is_some_and(|(lst, _)| { + parsed + .modules() + .range::((B::Excluded(*lst), B::Unbounded)) + .next() + .is_some() + }); + + for (name, parsed) in modules { + let Some(native) = self.native.serialized_module_map().get(name) else { + return Err(Error::Internal(format!( + "Module '{name}' exists in PackageCache but not in serialized map.", + )) + .extend()); + }; + + let cursor = JsonCursor::new(ConsistentNamedCursor { + name: name.clone(), + c: checkpoint_viewed_at, + }) + .encode_cursor(); + connection.edges.push(Edge::new( + cursor, + MoveModule { + storage_id: self.super_.address, + native: native.clone(), + parsed: parsed.clone(), + checkpoint_viewed_at, + }, + )) + } + + if connection.edges.is_empty() { + Ok(None) + } else { + Ok(Some(connection)) + } + } + + /// The transitive dependencies of this package. + async fn linkage(&self) -> Option> { + let linkage = self + .native + .linkage_table() + .iter() + .map(|(&runtime_id, upgrade_info)| Linkage { + original_id: runtime_id.into(), + upgraded_id: upgrade_info.upgraded_id.into(), + version: upgrade_info.upgraded_version.value(), + }) + .collect(); + + Some(linkage) + } + + /// The (previous) versions of this package that introduced its types. + async fn type_origins(&self) -> Option> { + let type_origins = self + .native + .type_origin_table() + .iter() + .map(|origin| TypeOrigin { + module: origin.module_name.clone(), + struct_: origin.struct_name.clone(), + defining_id: origin.package.into(), + }) + .collect(); + + Some(type_origins) + } + + /// BCS representation of the package's modules. Modules appear as a + /// sequence of pairs (module name, followed by module bytes), in + /// alphabetic order by module name. + async fn module_bcs(&self) -> Result> { + let bcs = bcs::to_bytes(self.native.serialized_module_map()) + .map_err(|_| { + Error::Internal(format!("Failed to serialize package {}", self.native.id())) + }) + .extend()?; + + Ok(Some(bcs.into())) + } +} + +impl MovePackage { + fn parsed_package(&self) -> Result { + // TODO: Leverage the package cache (attempt to read from it, and if that + // doesn't succeed, write back the parsed Package to the cache as well.) + let Some(native) = self.super_.native_impl() else { + return Err(Error::Internal( + "No native representation of package to parse.".to_string(), + )); + }; + + ParsedMovePackage::read(native) + .map_err(|e| Error::Internal(format!("Error reading package: {e}"))) + } + + pub(crate) fn module_impl(&self, name: &str) -> Result, Error> { + use PackageCacheError as E; + match ( + self.native.serialized_module_map().get(name), + self.parsed_package()?.module(name), + ) { + (Some(native), Ok(parsed)) => Ok(Some(MoveModule { + storage_id: self.super_.address, + native: native.clone(), + parsed: parsed.clone(), + checkpoint_viewed_at: self.checkpoint_viewed_at, + })), + + (None, _) | (_, Err(E::ModuleNotFound(_, _))) => Ok(None), + (_, Err(e)) => Err(Error::Internal(format!( + "Unexpected error fetching module: {e}" + ))), + } + } + + pub(crate) async fn query( + db: &Db, + address: IotaAddress, + key: ObjectLookupKey, + ) -> Result, Error> { + let Some(object) = Object::query(db, address, key).await? else { + return Ok(None); + }; + + let checkpoint_viewed_at = match object.checkpoint_viewed_at { + Some(value) => Ok(value), + None => Checkpoint::query_latest_checkpoint_sequence_number(db).await, + }?; + + Ok(Some( + MovePackage::try_from(&object, checkpoint_viewed_at) + .map_err(|_| Error::Internal(format!("{address} is not a package")))?, + )) + } + + pub(crate) fn try_from( + object: &Object, + checkpoint_viewed_at: u64, + ) -> Result { + let Some(native) = object.native_impl() else { + return Err(MovePackageDowncastError); + }; + + if let Data::Package(move_package) = &native.data { + Ok(Self { + super_: object.clone(), + native: move_package.clone(), + checkpoint_viewed_at, + }) + } else { + Err(MovePackageDowncastError) + } + } +} diff --git a/crates/sui-graphql-rpc/src/types/move_struct.rs b/crates/iota-graphql-rpc/src/types/move_struct.rs similarity index 94% rename from crates/sui-graphql-rpc/src/types/move_struct.rs rename to crates/iota-graphql-rpc/src/types/move_struct.rs index 0a8babd73b4..01c50418661 100644 --- a/crates/sui-graphql-rpc/src/types/move_struct.rs +++ b/crates/iota-graphql-rpc/src/types/move_struct.rs @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; -use sui_package_resolver::StructDef; +use iota_package_resolver::StructDef; use super::{ + iota_address::IotaAddress, move_module::MoveModule, open_move_type::{abilities, MoveAbility, OpenMoveType}, - sui_address::SuiAddress, }; use crate::error::Error; pub(crate) struct MoveStruct { - defining_id: SuiAddress, + defining_id: IotaAddress, module: String, name: String, abilities: Vec, @@ -119,7 +120,7 @@ impl MoveStruct { .collect(); MoveStruct { - defining_id: SuiAddress::from(def.defining_id), + defining_id: IotaAddress::from(def.defining_id), module, name, abilities: abilities(def.abilities), diff --git a/crates/sui-graphql-rpc/src/types/move_type.rs b/crates/iota-graphql-rpc/src/types/move_type.rs similarity index 98% rename from crates/sui-graphql-rpc/src/types/move_type.rs rename to crates/iota-graphql-rpc/src/types/move_type.rs index f3cd07a866c..827a9a10838 100644 --- a/crates/sui-graphql-rpc/src/types/move_type.rs +++ b/crates/iota-graphql-rpc/src/types/move_type.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; +use iota_package_resolver::Resolver; use move_binary_format::file_format::AbilitySet; use move_core_types::{annotated_value as A, language_storage::TypeTag}; use serde::{Deserialize, Serialize}; -use sui_package_resolver::Resolver; use super::open_move_type::MoveAbility; use crate::{context_data::package_cache::PackageCache, error::Error}; @@ -271,7 +272,7 @@ impl TryFrom for MoveFieldLayout { } /// Error from seeing a `signer` value or type, which shouldn't be possible in -/// Sui Move. +/// Iota Move. pub(crate) fn unexpected_signer_error() -> Error { Error::Internal("Unexpected value of type: signer.".to_string()) } diff --git a/crates/sui-graphql-rpc/src/types/move_value.rs b/crates/iota-graphql-rpc/src/types/move_value.rs similarity index 95% rename from crates/sui-graphql-rpc/src/types/move_value.rs rename to crates/iota-graphql-rpc/src/types/move_value.rs index 7f469e112c8..8e4d33b8daf 100644 --- a/crates/sui-graphql-rpc/src/types/move_value.rs +++ b/crates/iota-graphql-rpc/src/types/move_value.rs @@ -1,7 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; +use iota_package_resolver::Resolver; +use iota_types::object::bounded_visitor::BoundedVisitor; use move_core_types::{ account_address::AccountAddress, annotated_value as A, ident_str, @@ -9,10 +12,8 @@ use move_core_types::{ language_storage::{StructTag, TypeTag}, }; use serde::{Deserialize, Serialize}; -use sui_package_resolver::Resolver; -use sui_types::object::bounded_visitor::BoundedVisitor; -use super::{base64::Base64, big_int::BigInt, move_type::MoveType, sui_address::SuiAddress}; +use super::{base64::Base64, big_int::BigInt, iota_address::IotaAddress, move_type::MoveType}; use crate::{ context_data::package_cache::PackageCache, error::Error, @@ -20,7 +21,7 @@ use crate::{ }; const STD: AccountAddress = AccountAddress::ONE; -const SUI: AccountAddress = AccountAddress::TWO; +const IOTA: AccountAddress = AccountAddress::TWO; const MOD_ASCII: &IdentStr = ident_str!("ascii"); const MOD_OBJECT: &IdentStr = ident_str!("object"); @@ -48,9 +49,9 @@ scalar!( "The contents of a Move Value, corresponding to the following recursive type: type MoveData = - { Address: SuiAddress } - | { UID: SuiAddress } - | { ID: SuiAddress } + { Address: IotaAddress } + | { UID: IotaAddress } + | { ID: IotaAddress } | { Bool: bool } | { Number: BigInt } | { String: string } @@ -61,11 +62,11 @@ type MoveData = #[derive(Serialize, Deserialize, Debug)] pub(crate) enum MoveData { - Address(SuiAddress), + Address(IotaAddress), #[serde(rename = "UID")] - Uid(SuiAddress), + Uid(IotaAddress), #[serde(rename = "ID")] - Id(SuiAddress), + Id(IotaAddress), Bool(bool), Number(BigInt), String(String), @@ -184,10 +185,10 @@ impl TryFrom for MoveData { { // 0x1::ascii::String, 0x1::string::String Self::String(extract_string(&type_, fields)?) - } else if is_type(&type_, &SUI, MOD_OBJECT, TYP_UID) { + } else if is_type(&type_, &IOTA, MOD_OBJECT, TYP_UID) { // 0x2::object::UID Self::Uid(extract_uid(&type_, fields)?.into()) - } else if is_type(&type_, &SUI, MOD_OBJECT, TYP_ID) { + } else if is_type(&type_, &IOTA, MOD_OBJECT, TYP_ID) { // 0x2::object::ID Self::Id(extract_id(&type_, fields)?.into()) } else { @@ -198,7 +199,7 @@ impl TryFrom for MoveData { } } - // Sui does not support `signer` as a type. + // Iota does not support `signer` as a type. V::Signer(_) => return Err(unexpected_signer_error()), }) } @@ -247,12 +248,12 @@ fn try_to_json_value(value: A::MoveValue) -> Result { { // 0x1::ascii::String, 0x1::string::String Value::String(extract_string(&type_, fields)?) - } else if is_type(&type_, &SUI, MOD_OBJECT, TYP_UID) { + } else if is_type(&type_, &IOTA, MOD_OBJECT, TYP_UID) { // 0x2::object::UID Value::String( extract_uid(&type_, fields)?.to_canonical_string(/* with_prefix */ true), ) - } else if is_type(&type_, &SUI, MOD_OBJECT, TYP_ID) { + } else if is_type(&type_, &IOTA, MOD_OBJECT, TYP_ID) { // 0x2::object::ID Value::String( extract_id(&type_, fields)?.to_canonical_string(/* with_prefix */ true), @@ -270,7 +271,7 @@ fn try_to_json_value(value: A::MoveValue) -> Result { } } - // Sui does not support `signer` as a type. + // Iota does not support `signer` as a type. V::Signer(_) => return Err(unexpected_signer_error()), }) } @@ -388,7 +389,7 @@ fn extract_uid( }; let A::MoveStruct { type_, fields } = s; - if !is_type(&type_, &SUI, MOD_OBJECT, TYP_ID) { + if !is_type(&type_, &IOTA, MOD_OBJECT, TYP_ID) { return Err(Error::Internal( "Expected UID.id to have type ID.".to_string(), )); @@ -455,8 +456,8 @@ mod tests { }; } - fn address(a: &str) -> SuiAddress { - SuiAddress::from_str(a).unwrap() + fn address(a: &str) -> IotaAddress { + IotaAddress::from_str(a).unwrap() } fn data(layout: A::MoveTypeLayout, data: T) -> Result { @@ -659,7 +660,7 @@ mod tests { fn address_data() { let v = data(L::Address, address("0x42")); let expect = expect![ - "Ok(Address(SuiAddress([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66])))" + "Ok(Address(IotaAddress([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66])))" ]; expect.assert_eq(&format!("{v:?}")); } @@ -682,7 +683,7 @@ mod tests { let v = data(l, address("0x42")); let expect = expect![ - "Ok(Uid(SuiAddress([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66])))" + "Ok(Uid(IotaAddress([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66])))" ]; expect.assert_eq(&format!("{v:?}")); } @@ -764,7 +765,7 @@ mod tests { MoveField { name: "frob", value: Address( - SuiAddress( + IotaAddress( [ 0, 0, @@ -823,7 +824,7 @@ mod tests { MoveField { name: "frob", value: Address( - SuiAddress( + IotaAddress( [ 0, 0, diff --git a/crates/iota-graphql-rpc/src/types/object.rs b/crates/iota-graphql-rpc/src/types/object.rs new file mode 100644 index 00000000000..86f6b205dc8 --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/object.rs @@ -0,0 +1,1562 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::BTreeMap, fmt::Write}; + +use async_graphql::{ + connection::{Connection, CursorType, Edge}, + *, +}; +use diesel::{CombineDsl, ExpressionMethods, OptionalExtension, QueryDsl}; +use iota_indexer::{ + models::objects::{StoredDeletedHistoryObject, StoredHistoryObject, StoredObject}, + schema::{objects, objects_history, objects_snapshot}, + types::{ObjectStatus as NativeObjectStatus, OwnerType}, +}; +use iota_package_resolver::Resolver; +use iota_types::{ + object::{ + bounded_visitor::BoundedVisitor, MoveObject as NativeMoveObject, Object as NativeObject, + Owner as NativeOwner, + }, + TypeTag, +}; +use move_core_types::{ + annotated_value::{MoveStruct, MoveTypeLayout}, + language_storage::StructTag, +}; +use serde::{Deserialize, Serialize}; + +use super::{ + balance::{self, Balance}, + big_int::BigInt, + checkpoint::Checkpoint, + coin::Coin, + coin_metadata::CoinMetadata, + cursor::{self, Page, Paginated, RawPaginated, Target}, + digest::Digest, + display::{Display, DisplayEntry}, + dynamic_field::{DynamicField, DynamicFieldName}, + iota_address::IotaAddress, + iotans_registration::{DomainFormat, IotansRegistration}, + move_object::MoveObject, + move_package::MovePackage, + owner::{Owner, OwnerImpl}, + stake::StakedIota, + transaction_block, + transaction_block::{TransactionBlock, TransactionBlockFilter}, + type_filter::{ExactTypeFilter, TypeFilter}, +}; +use crate::{ + consistency::{build_objects_query, consistent_range, Checkpointed, View}, + context_data::package_cache::PackageCache, + data::{self, Db, DbConnection, QueryExecutor}, + error::Error, + filter, or_filter, + raw_query::RawQuery, + types::{base64::Base64, intersect}, +}; + +#[derive(Clone, Debug)] +pub(crate) struct Object { + pub address: IotaAddress, + pub kind: ObjectKind, + /// The checkpoint sequence number at which this was viewed at, or None if + /// the data was requested at the latest checkpoint. + pub checkpoint_viewed_at: Option, +} + +/// Type to implement GraphQL fields that are shared by all Objects. +pub(crate) struct ObjectImpl<'o>(pub &'o Object); + +#[derive(Clone, Debug)] +pub(crate) enum ObjectKind { + /// An object loaded from serialized data, such as the contents of a + /// transaction. + NotIndexed(NativeObject), + /// An object fetched from the live objects table. + Live(NativeObject, StoredObject), + /// An object fetched from the snapshot or historical objects table. + Historical(NativeObject, StoredHistoryObject), + /// The object is wrapped or deleted and only partial information can be + /// loaded from the indexer. + WrappedOrDeleted(StoredDeletedHistoryObject), +} + +#[derive(Enum, Copy, Clone, Eq, PartialEq, Debug)] +#[graphql(name = "ObjectKind")] +pub enum ObjectStatus { + /// The object is loaded from serialized data, such as the contents of a + /// transaction. + NotIndexed, + /// The object is currently live and is not deleted or wrapped. + Live, + /// The object is referenced at some version, and thus is fetched from the + /// snapshot or historical objects table. + Historical, + /// The object is deleted or wrapped and only partial information can be + /// loaded from the indexer. + WrappedOrDeleted, +} + +#[derive(Clone, Debug, PartialEq, Eq, InputObject)] +pub(crate) struct ObjectRef { + /// ID of the object. + pub address: IotaAddress, + /// Version or sequence number of the object. + pub version: u64, + /// Digest of the object. + pub digest: Digest, +} + +/// Constrains the set of objects returned. All filters are optional, and the +/// resulting set of objects are ones whose +/// +/// - Type matches the `type` filter, +/// - AND, whose owner matches the `owner` filter, +/// - AND, whose ID is in `objectIds` OR whose ID and version is in +/// `objectKeys`. +#[derive(InputObject, Default, Debug, Clone, Eq, PartialEq)] +pub(crate) struct ObjectFilter { + /// This field is used to specify the type of objects that should be + /// included in the query results. + /// + /// Objects can be filtered by their type's package, package::module, or + /// their fully qualified type name. + /// + /// Generic types can be queried by either the generic type name, e.g. + /// `0x2::coin::Coin`, or by the full type name, such as + /// `0x2::coin::Coin<0x2::iota::IOTA>`. + pub type_: Option, + + /// Filter for live objects by their current owners. + pub owner: Option, + + /// Filter for live objects by their IDs. + pub object_ids: Option>, + + /// Filter for live or potentially historical objects by their ID and + /// version. + pub object_keys: Option>, +} + +#[derive(InputObject, Debug, Clone, Eq, PartialEq)] +pub(crate) struct ObjectKey { + pub object_id: IotaAddress, + pub version: u64, +} + +/// The object's owner type: Immutable, Shared, Parent, or Address. +#[derive(Union, Clone)] +pub enum ObjectOwner { + Immutable(Immutable), + Shared(Shared), + Parent(Parent), + Address(AddressOwner), +} + +/// An immutable object is an object that can't be mutated, transferred, or +/// deleted. Immutable objects have no owner, so anyone can use them. +#[derive(SimpleObject, Clone)] +pub struct Immutable { + #[graphql(name = "_")] + dummy: Option, +} + +/// A shared object is an object that is shared using the +/// 0x2::transfer::share_object function. Unlike owned objects, once an object +/// is shared, it stays mutable and is accessible by anyone. +#[derive(SimpleObject, Clone)] +pub struct Shared { + initial_shared_version: u64, +} + +/// If the object's owner is a Parent, this object is part of a dynamic field +/// (it is the value of the dynamic field, or the intermediate Field object +/// itself). Also note that if the owner is a parent, then it's guaranteed to be +/// an object. +#[derive(SimpleObject, Clone)] +pub struct Parent { + parent: Option, +} + +/// An address-owned object is owned by a specific 32-byte address that is +/// either an account address (derived from a particular signature scheme) or +/// an object ID. An address-owned object is accessible only to its owner and no +/// others. +#[derive(SimpleObject, Clone)] +pub struct AddressOwner { + owner: Option, +} + +pub(crate) enum ObjectLookupKey { + Latest, + LatestAt(u64), + VersionAt { + version: u64, + /// The checkpoint sequence number at which this was viewed at, or None + /// if the data was requested at the latest checkpoint. + checkpoint_viewed_at: Option, + }, + LatestAtParentVersion { + /// The parent version to be used as the upper bound for the query. Look + /// for the latest version of a child object that is less than + /// or equal to this upper bound. + version: u64, + /// The checkpoint sequence number at which this was viewed at, or None + /// if the data was requested at the latest checkpoint. + checkpoint_viewed_at: Option, + }, +} + +pub(crate) type Cursor = cursor::BcsCursor; +type Query = data::Query; + +/// The inner struct for the `Object`'s cursor. The `object_id` is used as the +/// cursor, while the `checkpoint_viewed_at` sets the consistent upper bound for +/// the cursor. +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)] +pub(crate) struct HistoricalObjectCursor { + #[serde(rename = "o")] + object_id: Vec, + /// The checkpoint sequence number this was viewed at. + #[serde(rename = "c")] + checkpoint_viewed_at: u64, +} + +/// Interface implemented by on-chain values that are addressable by an ID (also +/// referred to as its address). This includes Move objects and packages. +#[derive(Interface)] +#[graphql( + name = "IObject", + field(name = "version", ty = "u64"), + field( + name = "status", + ty = "ObjectStatus", + desc = "The current status of the object as read from the off-chain store. The possible \ + states are: NOT_INDEXED, the object is loaded from serialized data, such as the \ + contents of a genesis or system package upgrade transaction. LIVE, the version \ + returned is the most recent for the object, and it is not deleted or wrapped at \ + that version. HISTORICAL, the object was referenced at a specific version or \ + checkpoint, so is fetched from historical tables and may not be the latest version \ + of the object. WRAPPED_OR_DELETED, the object is deleted or wrapped and only \ + partial information can be loaded." + ), + field( + name = "digest", + ty = "Option", + desc = "32-byte hash that identifies the object's current contents, encoded as a Base58 \ + string." + ), + field( + name = "owner", + ty = "Option", + desc = "The owner type of this object: Immutable, Shared, Parent, Address\n\ + Immutable and Shared Objects do not have owners." + ), + field( + name = "previous_transaction_block", + ty = "Option", + desc = "The transaction block that created this version of the object." + ), + field(name = "storage_rebate", ty = "Option", desc = "",), + field( + name = "received_transaction_blocks", + arg(name = "first", ty = "Option"), + arg(name = "after", ty = "Option"), + arg(name = "last", ty = "Option"), + arg(name = "before", ty = "Option"), + arg(name = "filter", ty = "Option"), + ty = "Connection", + desc = "The transaction blocks that sent objects to this object." + ), + field( + name = "bcs", + ty = "Option", + desc = "The Base64-encoded BCS serialization of the object's content." + ) +)] +pub(crate) enum IObject { + Object(Object), + MovePackage(MovePackage), + MoveObject(MoveObject), + Coin(Coin), + CoinMetadata(CoinMetadata), + StakedIota(StakedIota), + IotansRegistration(IotansRegistration), +} + +/// An object in Iota is a package (set of Move bytecode modules) or object +/// (typed data structure with fields) with additional metadata detailing its +/// id, version, transaction digest, owner field indicating how this object can +/// be accessed. +#[Object] +impl Object { + pub(crate) async fn address(&self) -> IotaAddress { + OwnerImpl::from(self).address().await + } + + /// Objects owned by this object, optionally `filter`-ed. + pub(crate) async fn objects( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + filter: Option, + ) -> Result> { + OwnerImpl::from(self) + .objects(ctx, first, after, last, before, filter) + .await + } + + /// Total balance of all coins with marker type owned by this object. If + /// type is not supplied, it defaults to `0x2::iota::IOTA`. + pub(crate) async fn balance( + &self, + ctx: &Context<'_>, + type_: Option, + ) -> Result> { + OwnerImpl::from(self).balance(ctx, type_).await + } + + /// The balances of all coin types owned by this object. + pub(crate) async fn balances( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(self) + .balances(ctx, first, after, last, before) + .await + } + + /// The coin objects for this object. + /// + /// `type` is a filter on the coin's type parameter, defaulting to + /// `0x2::iota::IOTA`. + pub(crate) async fn coins( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + type_: Option, + ) -> Result> { + OwnerImpl::from(self) + .coins(ctx, first, after, last, before, type_) + .await + } + + /// The `0x3::staking_pool::StakedIota` objects owned by this object. + pub(crate) async fn staked_iotas( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(self) + .staked_iotas(ctx, first, after, last, before) + .await + } + + /// The domain explicitly configured as the default domain pointing to this + /// object. + pub(crate) async fn default_iotans_name( + &self, + ctx: &Context<'_>, + format: Option, + ) -> Result> { + OwnerImpl::from(self).default_iotans_name(ctx, format).await + } + + /// The IotansRegistration NFTs owned by this object. These grant the owner + /// the capability to manage the associated domain. + pub(crate) async fn iotans_registrations( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(self) + .iotans_registrations(ctx, first, after, last, before) + .await + } + + pub(crate) async fn version(&self) -> u64 { + ObjectImpl(self).version().await + } + + /// The current status of the object as read from the off-chain store. The + /// possible states are: NOT_INDEXED, the object is loaded from + /// serialized data, such as the contents of a genesis or system package + /// upgrade transaction. LIVE, the version returned is the most recent for + /// the object, and it is not deleted or wrapped at that version. + /// HISTORICAL, the object was referenced at a specific version or + /// checkpoint, so is fetched from historical tables and may not be the + /// latest version of the object. WRAPPED_OR_DELETED, the object is deleted + /// or wrapped and only partial information can be loaded." + pub(crate) async fn status(&self) -> ObjectStatus { + ObjectImpl(self).status().await + } + + /// 32-byte hash that identifies the object's current contents, encoded as a + /// Base58 string. + pub(crate) async fn digest(&self) -> Option { + ObjectImpl(self).digest().await + } + + /// The owner type of this object: Immutable, Shared, Parent, Address + /// Immutable and Shared Objects do not have owners. + pub(crate) async fn owner(&self, ctx: &Context<'_>) -> Option { + ObjectImpl(self).owner(ctx).await + } + + /// The transaction block that created this version of the object. + pub(crate) async fn previous_transaction_block( + &self, + ctx: &Context<'_>, + ) -> Result> { + ObjectImpl(self).previous_transaction_block(ctx).await + } + + /// The amount of IOTA we would rebate if this object gets deleted or + /// mutated. This number is recalculated based on the present storage + /// gas price. + pub(crate) async fn storage_rebate(&self) -> Option { + ObjectImpl(self).storage_rebate().await + } + + /// The transaction blocks that sent objects to this object. + pub(crate) async fn received_transaction_blocks( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + filter: Option, + ) -> Result> { + ObjectImpl(self) + .received_transaction_blocks(ctx, first, after, last, before, filter) + .await + } + + /// The Base64-encoded BCS serialization of the object's content. + pub(crate) async fn bcs(&self) -> Result> { + ObjectImpl(self).bcs().await + } + + /// The set of named templates defined on-chain for the type of this object, + /// to be handled off-chain. The server substitutes data from the object + /// into these templates to generate a display string per template. + async fn display(&self, ctx: &Context<'_>) -> Result>> { + ObjectImpl(self).display(ctx).await + } + + /// Access a dynamic field on an object using its name. Names are arbitrary + /// Move values whose type have `copy`, `drop`, and `store`, and are + /// specified using their type, and their BCS contents, Base64 encoded. + /// + /// Dynamic fields on wrapped objects can be accessed by using the same API + /// under the Owner type. + async fn dynamic_field( + &self, + ctx: &Context<'_>, + name: DynamicFieldName, + ) -> Result> { + OwnerImpl::from(self) + .dynamic_field(ctx, name, Some(self.version_impl())) + .await + } + + /// Access a dynamic object field on an object using its name. Names are + /// arbitrary Move values whose type have `copy`, `drop`, and `store`, + /// and are specified using their type, and their BCS contents, Base64 + /// encoded. The value of a dynamic object field can also be accessed + /// off-chain directly via its address (e.g. using `Query.object`). + /// + /// Dynamic fields on wrapped objects can be accessed by using the same API + /// under the Owner type. + async fn dynamic_object_field( + &self, + ctx: &Context<'_>, + name: DynamicFieldName, + ) -> Result> { + OwnerImpl::from(self) + .dynamic_object_field(ctx, name, Some(self.version_impl())) + .await + } + + /// The dynamic fields and dynamic object fields on an object. + /// + /// Dynamic fields on wrapped objects can be accessed by using the same API + /// under the Owner type. + async fn dynamic_fields( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + OwnerImpl::from(self) + .dynamic_fields(ctx, first, after, last, before, Some(self.version_impl())) + .await + } + + /// Attempts to convert the object into a MoveObject + async fn as_move_object(&self) -> Option { + MoveObject::try_from(self).ok() + } + + /// Attempts to convert the object into a MovePackage + async fn as_move_package(&self, ctx: &Context<'_>) -> Option { + let Some(checkpoint_viewed_at) = match self.checkpoint_viewed_at { + Some(value) => Ok(value), + None => Checkpoint::query_latest_checkpoint_sequence_number(ctx.data_unchecked()).await, + } + .ok() else { + return None; + }; + + MovePackage::try_from(self, checkpoint_viewed_at).ok() + } +} + +impl ObjectImpl<'_> { + pub(crate) async fn version(&self) -> u64 { + self.0.version_impl() + } + + pub(crate) async fn status(&self) -> ObjectStatus { + ObjectStatus::from(&self.0.kind) + } + + pub(crate) async fn digest(&self) -> Option { + self.0 + .native_impl() + .map(|native| native.digest().base58_encode()) + } + + pub(crate) async fn owner(&self, ctx: &Context<'_>) -> Option { + use NativeOwner as O; + + let Some(native) = self.0.native_impl() else { + return None; + }; + + match native.owner { + O::AddressOwner(address) => { + let address = IotaAddress::from(address); + Some(ObjectOwner::Address(AddressOwner { + owner: Some(Owner { + address, + checkpoint_viewed_at: self.0.checkpoint_viewed_at, + }), + })) + } + O::Immutable => Some(ObjectOwner::Immutable(Immutable { dummy: None })), + O::ObjectOwner(address) => { + let parent = Object::query( + ctx.data_unchecked(), + address.into(), + ObjectLookupKey::Latest, + ) + .await + .ok() + .flatten(); + + Some(ObjectOwner::Parent(Parent { parent })) + } + O::Shared { + initial_shared_version, + } => Some(ObjectOwner::Shared(Shared { + initial_shared_version: initial_shared_version.value(), + })), + } + } + + pub(crate) async fn previous_transaction_block( + &self, + ctx: &Context<'_>, + ) -> Result> { + let Some(native) = self.0.native_impl() else { + return Ok(None); + }; + let digest = native.previous_transaction; + + TransactionBlock::query( + ctx.data_unchecked(), + digest.into(), + self.0.checkpoint_viewed_at, + ) + .await + .extend() + } + + pub(crate) async fn storage_rebate(&self) -> Option { + self.0 + .native_impl() + .map(|native| BigInt::from(native.storage_rebate)) + } + + pub(crate) async fn received_transaction_blocks( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + filter: Option, + ) -> Result> { + let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; + + let Some(filter) = filter + .unwrap_or_default() + .intersect(TransactionBlockFilter { + recv_address: Some(self.0.address), + ..Default::default() + }) + else { + return Ok(Connection::new(false, false)); + }; + + TransactionBlock::paginate( + ctx.data_unchecked(), + page, + filter, + self.0.checkpoint_viewed_at, + ) + .await + .extend() + } + + pub(crate) async fn bcs(&self) -> Result> { + use ObjectKind as K; + Ok(match &self.0.kind { + K::WrappedOrDeleted(_) => None, + K::Live(_, stored) => Some(Base64::from(&stored.serialized_object)), + + // WrappedOrDeleted objects are also read from the historical objects table, and they do + // not have a serialized object, so the column is also nullable for stored historical + // objects. + K::Historical(_, stored) => stored.serialized_object.as_ref().map(Base64::from), + + K::NotIndexed(native) => { + let bytes = bcs::to_bytes(native) + .map_err(|e| { + Error::Internal(format!( + "Failed to serialize object at {}: {e}", + self.0.address + )) + }) + .extend()?; + Some(Base64::from(&bytes)) + } + }) + } + + /// `display` is part of the `IMoveObject` interface, but is implemented on + /// `ObjectImpl` to allow for a convenience function on `Object`. + pub(crate) async fn display(&self, ctx: &Context<'_>) -> Result>> { + let Some(native) = self.0.native_impl() else { + return Ok(None); + }; + + let move_object = native + .data + .try_as_move() + .ok_or_else(|| Error::Internal("Failed to convert object into MoveObject".to_string())) + .extend()?; + + let (struct_tag, move_struct) = deserialize_move_struct(move_object, ctx.data_unchecked()) + .await + .extend()?; + + let Some(display) = Display::query(ctx.data_unchecked(), struct_tag.into()) + .await + .extend()? + else { + return Ok(None); + }; + + Ok(Some(display.render(&move_struct).extend()?)) + } +} + +impl Object { + /// Construct a GraphQL object from a native object, without its stored + /// (indexed) counterpart. + /// + /// `checkpoint_viewed_at` represents the checkpoint sequence number at + /// which this `Object` was constructed in, or `None` if the data was + /// requested at the latest checkpoint. This is stored on `Object` so + /// that when viewing that entity's state, it will be as if it was + /// read at the same checkpoint. + pub(crate) fn from_native( + address: IotaAddress, + native: NativeObject, + checkpoint_viewed_at: Option, + ) -> Object { + Object { + address, + kind: ObjectKind::NotIndexed(native), + checkpoint_viewed_at, + } + } + + pub(crate) fn native_impl(&self) -> Option<&NativeObject> { + use ObjectKind as K; + + match &self.kind { + K::Live(native, _) | K::NotIndexed(native) | K::Historical(native, _) => Some(native), + K::WrappedOrDeleted(_) => None, + } + } + + pub(crate) fn version_impl(&self) -> u64 { + use ObjectKind as K; + + match &self.kind { + K::Live(native, _) | K::NotIndexed(native) | K::Historical(native, _) => { + native.version().value() + } + K::WrappedOrDeleted(stored) => stored.object_version as u64, + } + } + + /// Query the database for a `page` of objects, optionally `filter`-ed. + /// + /// `checkpoint_viewed_at` represents the checkpoint sequence number at + /// which this page was queried for, or `None` if the data was requested + /// at the latest checkpoint. Each entity returned in the connection + /// will inherit this checkpoint, so that when viewing that entity's + /// state, it will be as if it was read at the same checkpoint. + pub(crate) async fn paginate( + db: &Db, + page: Page, + filter: ObjectFilter, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + Self::paginate_subtype(db, page, filter, checkpoint_viewed_at, Ok).await + } + + /// Query the database for a `page` of some sub-type of Object. The page + /// uses the bytes of an Object ID and the checkpoint when the query was + /// made as the cursor, and can optionally be further `filter`-ed. The + /// subtype is created using the `downcast` function, which is allowed + /// to fail, if the downcast has failed. + /// + /// `checkpoint_viewed_at` represents the checkpoint sequence number at + /// which this page was queried for, or `None` if the data was requested + /// at the latest checkpoint. Each entity returned in the connection + /// will inherit this checkpoint, so that when viewing that entity's + /// state, it will be as if it was read at the same checkpoint. + /// + /// If a `Page` is also provided, then this function will defer to + /// the `checkpoint_viewed_at` in the cursors. Otherwise, use the value + /// from the parameter, or set to None. This is so that paginated + /// queries are consistent with the previous query that created the + /// cursor. + pub(crate) async fn paginate_subtype( + db: &Db, + page: Page, + filter: ObjectFilter, + checkpoint_viewed_at: Option, + downcast: impl Fn(Object) -> Result, + ) -> Result, Error> { + // If cursors are provided, defer to the `checkpoint_viewed_at` in the cursor if + // they are consistent. Otherwise, use the value from the parameter, or + // set to None. This is so that paginated queries are consistent with + // the previous query that created the cursor. + let cursor_viewed_at = page.validate_cursor_consistency()?; + let checkpoint_viewed_at: Option = cursor_viewed_at.or(checkpoint_viewed_at); + + let response = db + .execute_repeatable(move |conn| { + let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { + return Ok::<_, diesel::result::Error>(None); + }; + + let result = page.paginate_raw_query::( + conn, + rhs, + objects_query(&filter, lhs as i64, rhs as i64, &page), + )?; + + Ok(Some((result, rhs))) + }) + .await?; + + let Some(((prev, next, results), checkpoint_viewed_at)) = response else { + return Err(Error::Client( + "Requested data is outside the available range".to_string(), + )); + }; + + let mut conn: Connection = Connection::new(prev, next); + + for stored in results { + // To maintain consistency, the returned cursor should have the same upper-bound + // as the checkpoint found on the cursor. + let cursor = stored.cursor(checkpoint_viewed_at).encode_cursor(); + let object = + Object::try_from_stored_history_object(stored, Some(checkpoint_viewed_at))?; + conn.edges.push(Edge::new(cursor, downcast(object)?)); + } + + Ok(conn) + } + + /// Query for the object at a specific version, at the checkpoint_viewed_at + /// if given, else against the latest checkpoint. + /// + /// `checkpoint_viewed_at` represents the checkpoint sequence number at + /// which this `Object` was queried in, or `None` if the data was + /// requested at the latest checkpoint. This is stored on `Object` so + /// that when viewing that entity's state, it will be as if it was read at + /// the same checkpoint. + async fn query_at_version( + db: &Db, + address: IotaAddress, + version: u64, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + use objects_history::dsl as history; + use objects_snapshot::dsl as snapshot; + + let version = version as i64; + + let stored_objs: Option> = db + .execute_repeatable(move |conn| { + let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { + return Ok::<_, diesel::result::Error>(None); + }; + + conn.results(move || { + // If an object was created or mutated in a checkpoint outside the current + // available range, and never touched again, it will not show up in the + // objects_history table. Thus, we always need to check the objects_snapshot + // table as well. + let snapshot_query = snapshot::objects_snapshot + .filter(snapshot::object_id.eq(address.into_vec())) + .filter(snapshot::object_version.eq(version)); + + let historical_query = history::objects_history + .filter(history::object_id.eq(address.into_vec())) + .filter(history::object_version.eq(version)) + .filter(history::checkpoint_sequence_number.between(lhs as i64, rhs as i64)) + .order_by(history::object_version.desc()) + .limit(1); + + snapshot_query.union(historical_query) + }) + .optional() // Return optional to match the state when checkpoint_viewed_at is out of range + }) + .await?; + + let Some(stored_objs) = stored_objs else { + return Ok(None); + }; + + // Select the max by key after the union query, because Diesel currently does + // not support order_by on union + stored_objs + .into_iter() + .max_by_key(|o| o.object_version) + .map(|obj| Self::try_from_stored_history_object(obj, checkpoint_viewed_at)) + .transpose() + } + + /// Query for the latest version of an object bounded by the provided + /// `parent_version`. + /// + /// `checkpoint_viewed_at` represents the checkpoint sequence number at + /// which this `Object` was queried in, or `None` if the data was + /// requested at the latest checkpoint. This is stored on `Object` so + /// that when viewing that entity's state, it will be as if it was read at + /// the same checkpoint. + async fn query_latest_at_version( + db: &Db, + address: IotaAddress, + parent_version: u64, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + use objects_history::dsl as history; + use objects_snapshot::dsl as snapshot; + + let version = parent_version as i64; + + let stored_objs: Option> = db + .execute_repeatable(move |conn| { + let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { + return Ok::<_, diesel::result::Error>(None); + }; + + conn.results(move || { + // If an object was created or mutated in a checkpoint outside the current + // available range, and never touched again, it will not show up in the + // objects_history table. Thus, we always need to check the objects_snapshot + // table as well. + let snapshot_query = snapshot::objects_snapshot + .filter(snapshot::object_id.eq(address.into_vec())) + .filter(snapshot::object_version.le(version)); + + let historical_query = history::objects_history + .filter(history::object_id.eq(address.into_vec())) + .filter(history::object_version.le(version)) + .filter(history::checkpoint_sequence_number.between(lhs as i64, rhs as i64)) + .order_by(history::object_version.desc()) + .limit(1); + + snapshot_query.union(historical_query) + }) + .optional() // Return optional to match the state when checkpoint_viewed_at is out of range + }) + .await?; + + let Some(stored_objs) = stored_objs else { + return Ok(None); + }; + + // Select the max by key after the union query, because Diesel currently does + // not support order_by on union + stored_objs + .into_iter() + .max_by_key(|o| o.object_version) + .map(|obj| Self::try_from_stored_history_object(obj, checkpoint_viewed_at)) + .transpose() + } + + /// Query for the object at the latest version at the checkpoint sequence + /// number if given, else the latest version of the object against the + /// latest checkpoint. + async fn query_latest_at_checkpoint( + db: &Db, + address: IotaAddress, + checkpoint_viewed_at: Option, + ) -> Result, Error> { + use objects_history::dsl as history; + use objects_snapshot::dsl as snapshot; + + let stored_objs: Option> = db + .execute_repeatable(move |conn| { + let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { + return Ok::<_, diesel::result::Error>(None); + }; + + conn.results(move || { + // If an object was created or mutated in a checkpoint outside the current + // available range, and never touched again, it will not show up in the + // objects_history table. Thus, we always need to check the objects_snapshot + // table as well. + let snapshot_query = snapshot::objects_snapshot + .filter(snapshot::object_id.eq(address.into_vec())); + + let historical_query = history::objects_history + .filter(history::object_id.eq(address.into_vec())) + .filter(history::checkpoint_sequence_number.between(lhs as i64, rhs as i64)) + .order_by(history::object_version.desc()) + .limit(1); + + snapshot_query.union(historical_query) + }) + .optional() // Return optional to match the state when checkpoint_viewed_at is out of range + }) + .await?; + + let Some(stored_objs) = stored_objs else { + return Ok(None); + }; + + // Select the max by key after the union query, because Diesel currently does + // not support order_by on union + stored_objs + .into_iter() + .max_by_key(|o| o.object_version) + .map(|obj| Self::try_from_stored_history_object(obj, checkpoint_viewed_at)) + .transpose() + } + + pub(crate) async fn query( + db: &Db, + address: IotaAddress, + key: ObjectLookupKey, + ) -> Result, Error> { + match key { + ObjectLookupKey::Latest => Self::query_latest_at_checkpoint(db, address, None).await, + ObjectLookupKey::LatestAt(checkpoint_sequence_number) => { + Self::query_latest_at_checkpoint(db, address, Some(checkpoint_sequence_number)) + .await + } + ObjectLookupKey::VersionAt { + version, + checkpoint_viewed_at, + } => Self::query_at_version(db, address, version, checkpoint_viewed_at).await, + ObjectLookupKey::LatestAtParentVersion { + version, + checkpoint_viewed_at, + } => Self::query_latest_at_version(db, address, version, checkpoint_viewed_at).await, + } + .map_err(|e| Error::Internal(format!("Failed to fetch object: {e}"))) + } + + /// Query for a singleton object identified by its type. Note: the object is + /// assumed to be a singleton (we either find at least one object with + /// this type and then return it, or return nothing). + pub(crate) async fn query_singleton(db: &Db, type_: TypeTag) -> Result, Error> { + use objects::dsl; + + let stored_obj: Option = db + .execute(move |conn| { + conn.first(move || { + dsl::objects.filter( + dsl::object_type.eq(type_.to_canonical_string(/* with_prefix */ true)), + ) + }) + .optional() + }) + .await + .map_err(|e| Error::Internal(format!("Failed to fetch singleton: {e}")))?; + + stored_obj + .map(|obj| Object::try_from_stored_object(obj, None)) + .transpose() + } + + /// `checkpoint_viewed_at` represents the checkpoint sequence number at + /// which this `Object` was constructed in, or `None` if the data was + /// requested at the latest checkpoint. This is stored on `Object` so + /// that when viewing that entity's state, it will be as if it was read at + /// the same checkpoint. + pub(crate) fn try_from_stored_object( + stored_object: StoredObject, + checkpoint_viewed_at: Option, + ) -> Result { + let address = addr(&stored_object.object_id)?; + let native_object = bcs::from_bytes(&stored_object.serialized_object) + .map_err(|_| Error::Internal(format!("Failed to deserialize object {address}")))?; + + Ok(Self { + address, + kind: ObjectKind::Live(native_object, stored_object), + checkpoint_viewed_at, + }) + } + + /// `checkpoint_viewed_at` represents the checkpoint sequence number at + /// which this `Object` was constructed in, or `None` if the data was + /// requested at the latest checkpoint. This is stored on `Object` so + /// that when viewing that entity's state, it will be as if it was read at + /// the same checkpoint. + pub(crate) fn try_from_stored_history_object( + history_object: StoredHistoryObject, + checkpoint_viewed_at: Option, + ) -> Result { + let address = addr(&history_object.object_id)?; + + let object_status = + NativeObjectStatus::try_from(history_object.object_status).map_err(|_| { + Error::Internal(format!( + "Unknown object status {} for object {} at version {}", + history_object.object_status, address, history_object.object_version + )) + })?; + + match object_status { + NativeObjectStatus::Active => { + let Some(serialized_object) = &history_object.serialized_object else { + return Err(Error::Internal(format!( + "Live object {} at version {} cannot have missing serialized_object field", + address, history_object.object_version + ))); + }; + + let native_object = bcs::from_bytes(serialized_object).map_err(|_| { + Error::Internal(format!("Failed to deserialize object {address}")) + })?; + + Ok(Self { + address, + kind: ObjectKind::Historical(native_object, history_object), + checkpoint_viewed_at, + }) + } + NativeObjectStatus::WrappedOrDeleted => Ok(Self { + address, + kind: ObjectKind::WrappedOrDeleted(StoredDeletedHistoryObject { + object_id: history_object.object_id, + object_version: history_object.object_version, + object_status: history_object.object_status, + checkpoint_sequence_number: history_object.checkpoint_sequence_number, + }), + checkpoint_viewed_at, + }), + } + } +} + +impl ObjectFilter { + /// Try to create a filter whose results are the intersection of objects in + /// `self`'s results and objects in `other`'s results. This may not be + /// possible if the resulting filter is inconsistent in some way (e.g. a + /// filter that requires one field to be two different values + /// simultaneously). + pub(crate) fn intersect(self, other: ObjectFilter) -> Option { + macro_rules! intersect { + ($field:ident, $body:expr) => { + intersect::field(self.$field, other.$field, $body) + }; + } + + // Treat `object_ids` and `object_keys` as a single filter on IDs, and + // optionally versions, and compute the intersection of that. + let keys = intersect::field(self.keys(), other.keys(), |k, l| { + let mut combined = BTreeMap::new(); + + for (id, v) in k { + if let Some(w) = l.get(&id).copied() { + combined.insert(id, intersect::field(v, w, intersect::by_eq)?); + } + } + + // If the intersection is empty, it means, there were some ID or Key filters in + // both `self` and `other`, but they don't overlap, so the final + // result is inconsistent. + (!combined.is_empty()).then_some(combined) + })?; + + // Extract the ID and Key filters back out. At this point, we know that if there + // were ID/Key filters in both `self` and `other`, then they intersected + // to form a consistent set of constraints, so it is safe to interpret + // the lack of any ID/Key filters respectively as a lack of that kind of + // constraint, rather than a constraint on the empty set. + + let object_ids = { + let partition: Vec<_> = keys + .iter() + .flatten() + .filter_map(|(id, v)| v.is_none().then_some(*id)) + .collect(); + + (!partition.is_empty()).then_some(partition) + }; + + let object_keys = { + let partition: Vec<_> = keys + .iter() + .flatten() + .filter_map(|(id, v)| { + Some(ObjectKey { + object_id: *id, + version: (*v)?, + }) + }) + .collect(); + + (!partition.is_empty()).then_some(partition) + }; + + Some(Self { + type_: intersect!(type_, TypeFilter::intersect)?, + owner: intersect!(owner, intersect::by_eq)?, + object_ids, + object_keys, + }) + } + + /// Extract the Object ID and Key filters into one combined map from Object + /// IDs in this filter, to the versions they should have (or None if the + /// filter mentions the ID but no version for it). + fn keys(&self) -> Option>> { + if self.object_keys.is_none() && self.object_ids.is_none() { + return None; + } + + Some(BTreeMap::from_iter( + self.object_keys + .iter() + .flatten() + .map(|key| (key.object_id, Some(key.version))) + // Chain ID filters after Key filters so if there is overlap, we overwrite the key + // filter with the ID filter. + .chain(self.object_ids.iter().flatten().map(|id| (*id, None))), + )) + } + + /// Applies ObjectFilter to the input `RawQuery` and returns a new + /// `RawQuery`. + pub(crate) fn apply(&self, mut query: RawQuery) -> RawQuery { + // Start by applying the filters on IDs and/or keys because they are combined as + // a disjunction, while the remaining queries are conjunctions. + if let Some(object_ids) = &self.object_ids { + // Maximally strict - match a vec of 0 elements + if object_ids.is_empty() { + query = or_filter!(query, "1=0"); + } else { + let mut inner = String::new(); + let mut prefix = "object_id IN ("; + for id in object_ids { + // SAFETY: Writing to a `String` cannot fail. + write!( + &mut inner, + "{prefix}'\\x{}'::bytea", + hex::encode(id.into_vec()) + ) + .unwrap(); + prefix = ","; + } + inner.push(')'); + query = or_filter!(query, inner); + } + } + + if let Some(object_keys) = &self.object_keys { + // Maximally strict - match a vec of 0 elements + if object_keys.is_empty() { + query = or_filter!(query, "1=0"); + } else { + let mut inner = String::new(); + let mut prefix = "("; + for ObjectKey { object_id, version } in object_keys { + // SAFETY: Writing to a `String` cannot fail. + write!( + &mut inner, + "{prefix}(object_id = '\\x{}'::bytea AND object_version = {})", + hex::encode(object_id.into_vec()), + version + ) + .unwrap(); + prefix = " OR "; + } + inner.push(')'); + query = or_filter!(query, inner); + } + } + + if let Some(owner) = self.owner { + query = filter!( + query, + format!( + "owner_id = '\\x{}'::bytea AND owner_type = {}", + hex::encode(owner.into_vec()), + OwnerType::Address as i16 + ) + ); + } + + if let Some(type_) = &self.type_ { + return type_.apply_raw(query, "object_type"); + } + + query + } + + pub(crate) fn has_filters(&self) -> bool { + self != &Default::default() + } +} + +impl HistoricalObjectCursor { + pub(crate) fn new(object_id: Vec, checkpoint_viewed_at: u64) -> Self { + Self { + object_id, + checkpoint_viewed_at, + } + } +} + +impl Checkpointed for Cursor { + fn checkpoint_viewed_at(&self) -> u64 { + self.checkpoint_viewed_at + } +} + +impl Paginated for StoredObject { + type Source = objects::table; + + fn filter_ge(cursor: &Cursor, query: Query) -> Query { + query.filter(objects::dsl::object_id.ge(cursor.object_id.clone())) + } + + fn filter_le(cursor: &Cursor, query: Query) -> Query { + query.filter(objects::dsl::object_id.le(cursor.object_id.clone())) + } + + fn order(asc: bool, query: Query) -> Query { + use objects::dsl; + if asc { + query.order_by(dsl::object_id.asc()) + } else { + query.order_by(dsl::object_id.desc()) + } + } +} + +impl Target for StoredObject { + fn cursor(&self, checkpoint_viewed_at: u64) -> Cursor { + Cursor::new(HistoricalObjectCursor::new( + self.object_id.clone(), + checkpoint_viewed_at, + )) + } +} + +impl RawPaginated for StoredHistoryObject { + fn filter_ge(cursor: &Cursor, query: RawQuery) -> RawQuery { + filter!( + query, + format!( + "candidates.object_id >= '\\x{}'::bytea", + hex::encode(cursor.object_id.clone()) + ) + ) + } + + fn filter_le(cursor: &Cursor, query: RawQuery) -> RawQuery { + filter!( + query, + format!( + "candidates.object_id <= '\\x{}'::bytea", + hex::encode(cursor.object_id.clone()) + ) + ) + } + + fn order(asc: bool, query: RawQuery) -> RawQuery { + if asc { + query.order_by("candidates.object_id ASC") + } else { + query.order_by("candidates.object_id DESC") + } + } +} + +impl Target for StoredHistoryObject { + fn cursor(&self, checkpoint_viewed_at: u64) -> Cursor { + Cursor::new(HistoricalObjectCursor::new( + self.object_id.clone(), + checkpoint_viewed_at, + )) + } +} + +impl From<&ObjectKind> for ObjectStatus { + fn from(kind: &ObjectKind) -> Self { + match kind { + ObjectKind::NotIndexed(_) => ObjectStatus::NotIndexed, + ObjectKind::Live(_, _) => ObjectStatus::Live, + ObjectKind::Historical(_, _) => ObjectStatus::Historical, + ObjectKind::WrappedOrDeleted(_) => ObjectStatus::WrappedOrDeleted, + } + } +} + +impl From<&Object> for OwnerImpl { + fn from(object: &Object) -> Self { + OwnerImpl { + address: object.address, + checkpoint_viewed_at: object.checkpoint_viewed_at, + } + } +} + +/// Parse a `IotaAddress` from its stored representation. Failure is an +/// internal error: the database should never contain a malformed address +/// (containing the wrong number of bytes). +fn addr(bytes: impl AsRef<[u8]>) -> Result { + IotaAddress::from_bytes(bytes.as_ref()).map_err(|e| { + let bytes = bytes.as_ref().to_vec(); + Error::Internal(format!("Error deserializing address: {bytes:?}: {e}")) + }) +} + +pub(crate) async fn deserialize_move_struct( + move_object: &NativeMoveObject, + resolver: &Resolver, +) -> Result<(StructTag, MoveStruct), Error> { + let struct_tag = StructTag::from(move_object.type_().clone()); + let contents = move_object.contents(); + let move_type_layout = resolver + .type_layout(TypeTag::from(struct_tag.clone())) + .await + .map_err(|e| { + Error::Internal(format!( + "Error fetching layout for type {}: {e}", + struct_tag.to_canonical_string(/* with_prefix */ true) + )) + })?; + + let MoveTypeLayout::Struct(layout) = move_type_layout else { + return Err(Error::Internal("Object is not a move struct".to_string())); + }; + + // TODO (annotated-visitor): Use custom visitors for extracting a dynamic field, + // and for creating a GraphQL MoveValue directly (not via an annotated + // visitor). + let move_struct = BoundedVisitor::deserialize_struct(contents, &layout).map_err(|e| { + Error::Internal(format!( + "Error deserializing move struct for type {}: {e}", + struct_tag.to_canonical_string(/* with_prefix */ true) + )) + })?; + + Ok((struct_tag, move_struct)) +} + +/// Constructs a raw query to fetch objects from the database. Objects are +/// filtered out if they satisfy the criteria but have a later version in the +/// same checkpoint. If object keys are provided, or no filters are specified at +/// all, then this final condition is not applied. +fn objects_query(filter: &ObjectFilter, lhs: i64, rhs: i64, page: &Page) -> RawQuery +where +{ + let view = if filter.object_keys.is_some() || !filter.has_filters() { + View::Historical + } else { + View::Consistent + }; + + build_objects_query( + view, + lhs, + rhs, + page, + move |query| filter.apply(query), + move |newer| newer, + ) +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use super::*; + + #[test] + fn test_owner_filter_intersection() { + let f0 = ObjectFilter { + owner: Some(IotaAddress::from_str("0x1").unwrap()), + ..Default::default() + }; + + let f1 = ObjectFilter { + owner: Some(IotaAddress::from_str("0x2").unwrap()), + ..Default::default() + }; + + assert_eq!(f0.clone().intersect(f0.clone()), Some(f0.clone())); + assert_eq!(f0.clone().intersect(f1.clone()), None); + } + + #[test] + fn test_key_filter_intersection() { + let i1 = IotaAddress::from_str("0x1").unwrap(); + let i2 = IotaAddress::from_str("0x2").unwrap(); + let i3 = IotaAddress::from_str("0x3").unwrap(); + let i4 = IotaAddress::from_str("0x4").unwrap(); + + let f0 = ObjectFilter { + object_ids: Some(vec![i1, i3]), + object_keys: Some(vec![ + ObjectKey { + object_id: i2, + version: 1, + }, + ObjectKey { + object_id: i4, + version: 2, + }, + ]), + ..Default::default() + }; + + let f1 = ObjectFilter { + object_ids: Some(vec![i1, i2]), + object_keys: Some(vec![ObjectKey { + object_id: i4, + version: 2, + }]), + ..Default::default() + }; + + let f2 = ObjectFilter { + object_ids: Some(vec![i1, i3]), + ..Default::default() + }; + + let f3 = ObjectFilter { + object_keys: Some(vec![ + ObjectKey { + object_id: i2, + version: 2, + }, + ObjectKey { + object_id: i4, + version: 2, + }, + ]), + ..Default::default() + }; + + assert_eq!( + f0.clone().intersect(f1.clone()), + Some(ObjectFilter { + object_ids: Some(vec![i1]), + object_keys: Some(vec![ + ObjectKey { + object_id: i2, + version: 1 + }, + ObjectKey { + object_id: i4, + version: 2 + }, + ]), + ..Default::default() + }) + ); + + assert_eq!( + f1.clone().intersect(f2.clone()), + Some(ObjectFilter { + object_ids: Some(vec![i1]), + ..Default::default() + }) + ); + + assert_eq!( + f1.clone().intersect(f3.clone()), + Some(ObjectFilter { + object_keys: Some(vec![ + ObjectKey { + object_id: i2, + version: 2 + }, + ObjectKey { + object_id: i4, + version: 2 + }, + ]), + ..Default::default() + }) + ); + + // i2 got a conflicting version assignment + assert_eq!(f0.clone().intersect(f3.clone()), None); + + // No overlap between these two. + assert_eq!(f2.clone().intersect(f3.clone()), None); + } +} diff --git a/crates/iota-graphql-rpc/src/types/object_change.rs b/crates/iota-graphql-rpc/src/types/object_change.rs new file mode 100644 index 00000000000..5a94df82367 --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/object_change.rs @@ -0,0 +1,72 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_graphql::*; +use iota_types::effects::{IDOperation, ObjectChange as NativeObjectChange}; + +use super::{ + iota_address::IotaAddress, + object::{Object, ObjectLookupKey}, +}; + +pub(crate) struct ObjectChange { + pub native: NativeObjectChange, + /// The checkpoint sequence number this was viewed at. + pub checkpoint_viewed_at: u64, +} + +/// Effect on an individual Object (keyed by its ID). +#[Object] +impl ObjectChange { + /// The address of the object that has changed. + async fn address(&self) -> IotaAddress { + self.native.id.into() + } + + /// The contents of the object immediately before the transaction. + async fn input_state(&self, ctx: &Context<'_>) -> Result> { + let Some(version) = self.native.input_version else { + return Ok(None); + }; + + Object::query( + ctx.data_unchecked(), + self.native.id.into(), + ObjectLookupKey::VersionAt { + version: version.value(), + checkpoint_viewed_at: Some(self.checkpoint_viewed_at), + }, + ) + .await + .extend() + } + + /// The contents of the object immediately after the transaction. + async fn output_state(&self, ctx: &Context<'_>) -> Result> { + let Some(version) = self.native.output_version else { + return Ok(None); + }; + + Object::query( + ctx.data_unchecked(), + self.native.id.into(), + ObjectLookupKey::VersionAt { + version: version.value(), + checkpoint_viewed_at: Some(self.checkpoint_viewed_at), + }, + ) + .await + .extend() + } + + /// Whether the ID was created in this transaction. + async fn id_created(&self) -> Option { + Some(self.native.id_operation == IDOperation::Created) + } + + /// Whether the ID was deleted in this transaction. + async fn id_deleted(&self) -> Option { + Some(self.native.id_operation == IDOperation::Deleted) + } +} diff --git a/crates/sui-graphql-rpc/src/types/object_read.rs b/crates/iota-graphql-rpc/src/types/object_read.rs similarity index 84% rename from crates/sui-graphql-rpc/src/types/object_read.rs rename to crates/iota-graphql-rpc/src/types/object_read.rs index c9d0d909a6a..2ac5a15d17d 100644 --- a/crates/sui-graphql-rpc/src/types/object_read.rs +++ b/crates/iota-graphql-rpc/src/types/object_read.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; -use sui_types::base_types::ObjectRef as NativeObjectRef; +use iota_types::base_types::ObjectRef as NativeObjectRef; use super::{ + iota_address::IotaAddress, object::{Object, ObjectLookupKey}, - sui_address::SuiAddress, }; // A helper type representing the read of a specific version of an object. @@ -21,7 +22,7 @@ pub(crate) struct ObjectRead { #[Object] impl ObjectRead { /// ID of the object being read. - async fn address(&self) -> SuiAddress { + async fn address(&self) -> IotaAddress { self.address_impl() } @@ -52,8 +53,8 @@ impl ObjectRead { } impl ObjectRead { - fn address_impl(&self) -> SuiAddress { - SuiAddress::from(self.native.0) + fn address_impl(&self) -> IotaAddress { + IotaAddress::from(self.native.0) } fn version_impl(&self) -> u64 { diff --git a/crates/sui-graphql-rpc/src/types/open_move_type.rs b/crates/iota-graphql-rpc/src/types/open_move_type.rs similarity index 95% rename from crates/sui-graphql-rpc/src/types/open_move_type.rs rename to crates/iota-graphql-rpc/src/types/open_move_type.rs index 62c74800ed3..39ecf23c204 100644 --- a/crates/sui-graphql-rpc/src/types/open_move_type.rs +++ b/crates/iota-graphql-rpc/src/types/open_move_type.rs @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::fmt; use async_graphql::*; +use iota_package_resolver::{OpenSignature, OpenSignatureBody, Reference}; use move_binary_format::file_format::{Ability, AbilitySet, Visibility}; use serde::{Deserialize, Serialize}; -use sui_package_resolver::{OpenSignature, OpenSignatureBody, Reference}; pub(crate) struct OpenMoveType { signature: OpenMoveTypeSignature, } -/// Abilities are keywords in Sui Move that define how types behave at the +/// Abilities are keywords in Iota Move that define how types behave at the /// compiler level. #[derive(Enum, Copy, Clone, Eq, PartialEq)] pub(crate) enum MoveAbility { @@ -292,8 +293,8 @@ mod tests { use std::str::FromStr; use expect_test::expect; + use iota_package_resolver::{DatatypeKey, DatatypeRef}; use move_core_types::language_storage::StructTag; - use sui_package_resolver::{DatatypeKey, DatatypeRef}; use OpenSignatureBody as S; use super::*; @@ -333,7 +334,7 @@ mod tests { fn instance_signature() { let signature = OpenMoveTypeSignature::from(S::Datatype( struct_key("0x2::coin::Coin"), - vec![S::Datatype(struct_key("0x2::sui::SUI"), vec![])], + vec![S::Datatype(struct_key("0x2::iota::IOTA"), vec![])], )); let expect = expect![[r#" @@ -346,8 +347,8 @@ mod tests { type_parameters: [ Datatype { package: "0x0000000000000000000000000000000000000000000000000000000000000002", - module: "sui", - type_: "SUI", + module: "iota", + type_: "IOTA", type_parameters: [], }, ], @@ -373,11 +374,11 @@ mod tests { fn instance_signature_repr() { let signature = OpenMoveTypeSignature::from(S::Datatype( struct_key("0x2::coin::Coin"), - vec![S::Datatype(struct_key("0x2::sui::SUI"), vec![])], + vec![S::Datatype(struct_key("0x2::iota::IOTA"), vec![])], )); let expect = expect![ - "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" + "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" ]; expect.assert_eq(&format!("{signature}")); } diff --git a/crates/sui-graphql-rpc/src/types/owner.rs b/crates/iota-graphql-rpc/src/types/owner.rs similarity index 87% rename from crates/sui-graphql-rpc/src/types/owner.rs rename to crates/iota-graphql-rpc/src/types/owner.rs index d96a68961d8..4b24775b561 100644 --- a/crates/sui-graphql-rpc/src/types/owner.rs +++ b/crates/iota-graphql-rpc/src/types/owner.rs @@ -1,35 +1,36 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::{connection::Connection, *}; -use sui_json_rpc::name_service::NameServiceConfig; -use sui_types::{dynamic_field::DynamicFieldType, gas_coin::GAS}; +use iota_json_rpc::name_service::NameServiceConfig; +use iota_types::{dynamic_field::DynamicFieldType, gas_coin::GAS}; use super::{ address::Address, coin_metadata::CoinMetadata, cursor::Page, dynamic_field::{DynamicField, DynamicFieldName}, + iotans_registration::{DomainFormat, IotansRegistration, NameService}, move_package::MovePackage, object::ObjectLookupKey, - stake::StakedSui, - suins_registration::{DomainFormat, NameService, SuinsRegistration}, + stake::StakedIota, }; use crate::{ data::Db, types::{ balance::{self, Balance}, coin::Coin, + iota_address::IotaAddress, move_object::MoveObject, object::{self, Object, ObjectFilter}, - sui_address::SuiAddress, type_filter::ExactTypeFilter, }, }; #[derive(Clone, Debug)] pub(crate) struct Owner { - pub address: SuiAddress, + pub address: IotaAddress, /// The checkpoint sequence number at which this was viewed at, or None if /// the data was requested at the latest checkpoint. pub checkpoint_viewed_at: Option, @@ -37,7 +38,7 @@ pub(crate) struct Owner { /// Type to implement GraphQL fields that are shared by all Owners. pub(crate) struct OwnerImpl { - pub address: SuiAddress, + pub address: IotaAddress, /// The checkpoint sequence number at which this was viewed at, or None if /// the data was requested at the latest checkpoint. pub checkpoint_viewed_at: Option, @@ -51,7 +52,7 @@ pub(crate) struct OwnerImpl { #[derive(Interface)] #[graphql( name = "IOwner", - field(name = "address", ty = "SuiAddress"), + field(name = "address", ty = "IotaAddress"), field( name = "objects", arg(name = "first", ty = "Option"), @@ -67,7 +68,7 @@ pub(crate) struct OwnerImpl { arg(name = "type", ty = "Option"), ty = "Option", desc = "Total balance of all coins with marker type owned by this object or address. If \ - type is not supplied, it defaults to `0x2::sui::SUI`." + type is not supplied, it defaults to `0x2::iota::IOTA`." ), field( name = "balances", @@ -87,32 +88,32 @@ pub(crate) struct OwnerImpl { arg(name = "type", ty = "Option"), ty = "Connection", desc = "The coin objects for this object or address.\n\n\ - `type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`." + `type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`." ), field( - name = "staked_suis", + name = "staked_iotas", arg(name = "first", ty = "Option"), arg(name = "after", ty = "Option"), arg(name = "last", ty = "Option"), arg(name = "before", ty = "Option"), - ty = "Connection", - desc = "The `0x3::staking_pool::StakedSui` objects owned by this object or address." + ty = "Connection", + desc = "The `0x3::staking_pool::StakedIota` objects owned by this object or address." ), field( - name = "default_suins_name", + name = "default_iotans_name", arg(name = "format", ty = "Option"), ty = "Option", desc = "The domain explicitly configured as the default domain pointing to this object or \ address." ), field( - name = "suins_registrations", + name = "iotans_registrations", arg(name = "first", ty = "Option"), arg(name = "after", ty = "Option"), arg(name = "last", ty = "Option"), arg(name = "before", ty = "Option"), - ty = "Connection", - desc = "The SuinsRegistration NFTs owned by this object or address. These grant the owner \ + ty = "Connection", + desc = "The IotansRegistration NFTs owned by this object or address. These grant the owner \ the capability to manage the associated domain." ) )] @@ -124,17 +125,17 @@ pub(crate) enum IOwner { MoveObject(MoveObject), Coin(Coin), CoinMetadata(CoinMetadata), - StakedSui(StakedSui), - SuinsRegistration(SuinsRegistration), + StakedIota(StakedIota), + IotansRegistration(IotansRegistration), } /// An Owner is an entity that can own an object. Each Owner is identified by a -/// SuiAddress which represents either an Address (corresponding to a public key -/// of an account) or an Object, but never both (it is not known up-front +/// IotaAddress which represents either an Address (corresponding to a public +/// key of an account) or an Object, but never both (it is not known up-front /// whether a given Owner is an Address or an Object). #[Object] impl Owner { - pub(crate) async fn address(&self) -> SuiAddress { + pub(crate) async fn address(&self) -> IotaAddress { OwnerImpl::from(self).address().await } @@ -154,7 +155,7 @@ impl Owner { } /// Total balance of all coins with marker type owned by this object or - /// address. If type is not supplied, it defaults to `0x2::sui::SUI`. + /// address. If type is not supplied, it defaults to `0x2::iota::IOTA`. pub(crate) async fn balance( &self, ctx: &Context<'_>, @@ -180,7 +181,7 @@ impl Owner { /// The coin objects for this object or address. /// /// `type` is a filter on the coin's type parameter, defaulting to - /// `0x2::sui::SUI`. + /// `0x2::iota::IOTA`. pub(crate) async fn coins( &self, ctx: &Context<'_>, @@ -195,43 +196,43 @@ impl Owner { .await } - /// The `0x3::staking_pool::StakedSui` objects owned by this object or + /// The `0x3::staking_pool::StakedIota` objects owned by this object or /// address. - pub(crate) async fn staked_suis( + pub(crate) async fn staked_iotas( &self, ctx: &Context<'_>, first: Option, after: Option, last: Option, before: Option, - ) -> Result> { + ) -> Result> { OwnerImpl::from(self) - .staked_suis(ctx, first, after, last, before) + .staked_iotas(ctx, first, after, last, before) .await } /// The domain explicitly configured as the default domain pointing to this /// object or address. - pub(crate) async fn default_suins_name( + pub(crate) async fn default_iotans_name( &self, ctx: &Context<'_>, format: Option, ) -> Result> { - OwnerImpl::from(self).default_suins_name(ctx, format).await + OwnerImpl::from(self).default_iotans_name(ctx, format).await } - /// The SuinsRegistration NFTs owned by this object or address. These grant + /// The IotansRegistration NFTs owned by this object or address. These grant /// the owner the capability to manage the associated domain. - pub(crate) async fn suins_registrations( + pub(crate) async fn iotans_registrations( &self, ctx: &Context<'_>, first: Option, after: Option, last: Option, before: Option, - ) -> Result> { + ) -> Result> { OwnerImpl::from(self) - .suins_registrations(ctx, first, after, last, before) + .iotans_registrations(ctx, first, after, last, before) .await } @@ -312,7 +313,7 @@ impl Owner { } impl OwnerImpl { - pub(crate) async fn address(&self) -> SuiAddress { + pub(crate) async fn address(&self) -> IotaAddress { self.address } @@ -401,16 +402,16 @@ impl OwnerImpl { .extend() } - pub(crate) async fn staked_suis( + pub(crate) async fn staked_iotas( &self, ctx: &Context<'_>, first: Option, after: Option, last: Option, before: Option, - ) -> Result> { + ) -> Result> { let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - StakedSui::paginate( + StakedIota::paginate( ctx.data_unchecked(), page, self.address, @@ -420,7 +421,7 @@ impl OwnerImpl { .extend() } - pub(crate) async fn default_suins_name( + pub(crate) async fn default_iotans_name( &self, ctx: &Context<'_>, format: Option, @@ -433,16 +434,16 @@ impl OwnerImpl { ) } - pub(crate) async fn suins_registrations( + pub(crate) async fn iotans_registrations( &self, ctx: &Context<'_>, first: Option, after: Option, last: Option, before: Option, - ) -> Result> { + ) -> Result> { let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - SuinsRegistration::paginate( + IotansRegistration::paginate( ctx.data_unchecked::(), ctx.data_unchecked::(), page, diff --git a/crates/sui-graphql-rpc/src/types/protocol_config.rs b/crates/iota-graphql-rpc/src/types/protocol_config.rs similarity index 95% rename from crates/sui-graphql-rpc/src/types/protocol_config.rs rename to crates/iota-graphql-rpc/src/types/protocol_config.rs index 7165d65cb8f..7d5ac1686cc 100644 --- a/crates/sui-graphql-rpc/src/types/protocol_config.rs +++ b/crates/iota-graphql-rpc/src/types/protocol_config.rs @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; use diesel::{ExpressionMethods, QueryDsl}; -use sui_indexer::schema::{checkpoints, epochs}; -use sui_protocol_config::{ProtocolConfig as NativeProtocolConfig, ProtocolVersion}; +use iota_indexer::schema::{checkpoints, epochs}; +use iota_protocol_config::{ProtocolConfig as NativeProtocolConfig, ProtocolVersion}; use crate::{ data::{Db, DbConnection, QueryExecutor}, diff --git a/crates/iota-graphql-rpc/src/types/query.rs b/crates/iota-graphql-rpc/src/types/query.rs new file mode 100644 index 00000000000..8dab918f351 --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/query.rs @@ -0,0 +1,505 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::str::FromStr; + +use async_graphql::{connection::Connection, *}; +use fastcrypto::encoding::{Base64, Encoding}; +use iota_json_rpc_types::DevInspectArgs; +use iota_sdk::IotaClient; +use iota_types::{ + gas_coin::GAS, + transaction::{TransactionData, TransactionDataAPI, TransactionKind}, + TypeTag, +}; +use move_core_types::account_address::AccountAddress; +use serde::de::DeserializeOwned; + +use super::{ + address::Address, + available_range::AvailableRange, + chain_identifier::ChainIdentifier, + checkpoint::{self, Checkpoint, CheckpointId}, + coin::Coin, + coin_metadata::CoinMetadata, + cursor::Page, + digest::Digest, + dry_run_result::DryRunResult, + epoch::Epoch, + event::{self, Event, EventFilter}, + iota_address::IotaAddress, + iotans_registration::{Domain, NameService}, + move_type::MoveType, + object::{self, Object, ObjectFilter, ObjectLookupKey}, + owner::Owner, + protocol_config::ProtocolConfigs, + transaction_block::{self, TransactionBlock, TransactionBlockFilter}, + transaction_metadata::TransactionMetadata, + type_filter::ExactTypeFilter, +}; +use crate::{ + config::ServiceConfig, + consistency::{consistent_range, CheckpointViewedAt}, + data::{Db, QueryExecutor}, + error::Error, + mutation::Mutation, + types::{ + base64::Base64 as GraphQLBase64, + zklogin_verify_signature::{ + verify_zklogin_signature, ZkLoginIntentScope, ZkLoginVerifyResult, + }, + }, +}; + +pub(crate) struct Query; +pub(crate) type IotaGraphQLSchema = async_graphql::Schema; + +#[Object] +impl Query { + /// First four bytes of the network's genesis checkpoint digest (uniquely + /// identifies the network). + async fn chain_identifier(&self, ctx: &Context<'_>) -> Result { + Ok(ChainIdentifier::query(ctx.data_unchecked()) + .await + .extend()? + .to_string()) + } + + /// Range of checkpoints that the RPC has data available for (for data + /// that can be tied to a particular checkpoint). + async fn available_range(&self, ctx: &Context<'_>) -> Result { + let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; + let result = ctx + .data_unchecked::() + .execute(move |conn| consistent_range(conn, Some(checkpoint_viewed_at))) + .await + .extend()?; + + match result { + Some((first, last)) => Ok(AvailableRange { first, last }), + None => Err(Error::Internal( + "Checkpoint watermark outside of available range from database".to_string(), + ) + .extend()), + } + } + + /// Configuration for this RPC service + async fn service_config(&self, ctx: &Context<'_>) -> Result { + ctx.data() + .map_err(|_| Error::Internal("Unable to fetch service configuration.".to_string())) + .cloned() + .extend() + } + + /// Simulate running a transaction to inspect its effects without + /// committing to them on-chain. + /// + /// `txBytes` either a `TransactionData` struct or a `TransactionKind` + /// struct, BCS-encoded and then Base64-encoded. The expected + /// type is controlled by the presence or absence of `txMeta`: If + /// present, `txBytes` is assumed to be a `TransactionKind`, if + /// absent, then `TransactionData`. + /// + /// `txMeta` the data that is missing from a `TransactionKind` to make + /// a `TransactionData` (sender address and gas information). All + /// its fields are nullable. + /// + /// `skipChecks` optional flag to disable the usual verification + /// checks that prevent access to objects that are owned by + /// addresses other than the sender, and calling non-public, + /// non-entry functions, and some other checks. Defaults to false. + async fn dry_run_transaction_block( + &self, + ctx: &Context<'_>, + tx_bytes: String, + tx_meta: Option, + skip_checks: Option, + ) -> Result { + let skip_checks = skip_checks.unwrap_or(false); + + let iota_sdk_client: &Option = ctx + .data() + .map_err(|_| Error::Internal("Unable to fetch Iota SDK client".to_string())) + .extend()?; + let iota_sdk_client = iota_sdk_client + .as_ref() + .ok_or_else(|| Error::Internal("Iota SDK client not initialized".to_string())) + .extend()?; + + let (sender_address, tx_kind, gas_price, gas_sponsor, gas_budget, gas_objects) = + if let Some(TransactionMetadata { + sender, + gas_price, + gas_objects, + gas_budget, + gas_sponsor, + }) = tx_meta + { + // This implies `TransactionKind` + let tx_kind = deserialize_tx_data::(&tx_bytes)?; + + // Default is 0x0 + let sender_address = sender.unwrap_or_else(|| AccountAddress::ZERO.into()).into(); + + let gas_sponsor = gas_sponsor.map(|addr| addr.into()); + + let gas_objects = gas_objects.map(|objs| { + objs.into_iter() + .map(|obj| (obj.address.into(), obj.version.into(), obj.digest.into())) + .collect() + }); + + ( + sender_address, + tx_kind, + gas_price.map(|p| p.into()), + gas_sponsor, + gas_budget.map(|b| b.into()), + gas_objects, + ) + } else { + // This implies `TransactionData` + let tx_data = deserialize_tx_data::(&tx_bytes)?; + + ( + tx_data.sender(), + tx_data.clone().into_kind(), + Some(tx_data.gas_price().into()), + Some(tx_data.gas_owner()), + Some(tx_data.gas_budget().into()), + Some(tx_data.gas().to_vec()), + ) + }; + + let dev_inspect_args = DevInspectArgs { + gas_sponsor, + gas_budget, + gas_objects, + show_raw_txn_data_and_effects: Some(true), + skip_checks: Some(skip_checks), + }; + + let res = iota_sdk_client + .read_api() + .dev_inspect_transaction_block( + sender_address, + tx_kind, + gas_price, + None, + Some(dev_inspect_args), + ) + .await?; + + DryRunResult::try_from(res).extend() + } + + async fn owner(&self, ctx: &Context<'_>, address: IotaAddress) -> Result> { + let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; + + Ok(Some(Owner { + address, + checkpoint_viewed_at: Some(checkpoint_viewed_at), + })) + } + + /// The object corresponding to the given address at the (optionally) given + /// version. When no version is given, the latest version is returned. + async fn object( + &self, + ctx: &Context<'_>, + address: IotaAddress, + version: Option, + ) -> Result> { + let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; + + match version { + Some(version) => Object::query( + ctx.data_unchecked(), + address, + ObjectLookupKey::VersionAt { + version, + checkpoint_viewed_at: Some(checkpoint_viewed_at), + }, + ) + .await + .extend(), + None => Object::query( + ctx.data_unchecked(), + address, + ObjectLookupKey::LatestAt(checkpoint_viewed_at), + ) + .await + .extend(), + } + } + + /// Look-up an Account by its IotaAddress. + async fn address(&self, ctx: &Context<'_>, address: IotaAddress) -> Result> { + let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; + + Ok(Some(Address { + address, + checkpoint_viewed_at: Some(checkpoint_viewed_at), + })) + } + + /// Fetch a structured representation of a concrete type, including its + /// layout information. Fails if the type is malformed. + async fn type_(&self, type_: String) -> Result { + Ok(MoveType::new( + TypeTag::from_str(&type_) + .map_err(|e| Error::Client(format!("Bad type: {e}"))) + .extend()?, + )) + } + + /// Fetch epoch information by ID (defaults to the latest epoch). + async fn epoch(&self, ctx: &Context<'_>, id: Option) -> Result> { + let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; + + Epoch::query(ctx, id, Some(checkpoint_viewed_at)) + .await + .extend() + } + + /// Fetch checkpoint information by sequence number or digest (defaults to + /// the latest available checkpoint). + async fn checkpoint( + &self, + ctx: &Context<'_>, + id: Option, + ) -> Result> { + let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; + + Checkpoint::query(ctx, id.unwrap_or_default(), Some(checkpoint_viewed_at)) + .await + .extend() + } + + /// Fetch a transaction block by its transaction digest. + async fn transaction_block( + &self, + ctx: &Context<'_>, + digest: Digest, + ) -> Result> { + let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; + + TransactionBlock::query(ctx.data_unchecked(), digest, Some(checkpoint_viewed_at)) + .await + .extend() + } + + /// The coin objects that exist in the network. + /// + /// The type field is a string of the inner type of the coin by which to + /// filter (e.g. `0x2::iota::IOTA`). If no type is provided, it will + /// default to `0x2::iota::IOTA`. + async fn coins( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + type_: Option, + ) -> Result> { + let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; + + let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; + let coin = type_.map_or_else(GAS::type_tag, |t| t.0); + Coin::paginate( + ctx.data_unchecked(), + page, + coin, + // owner + None, + Some(checkpoint_viewed_at), + ) + .await + .extend() + } + + /// The checkpoints that exist in the network. + async fn checkpoints( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; + + let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; + Checkpoint::paginate( + ctx.data_unchecked(), + page, + // epoch + None, + Some(checkpoint_viewed_at), + ) + .await + .extend() + } + + /// The transaction blocks that exist in the network. + async fn transaction_blocks( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + filter: Option, + ) -> Result> { + let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; + + let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; + TransactionBlock::paginate( + ctx.data_unchecked(), + page, + filter.unwrap_or_default(), + Some(checkpoint_viewed_at), + ) + .await + .extend() + } + + /// The events that exist in the network. + async fn events( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + filter: Option, + ) -> Result> { + let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; + + let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; + Event::paginate( + ctx.data_unchecked(), + page, + filter.unwrap_or_default(), + Some(checkpoint_viewed_at), + ) + .await + .extend() + } + + /// The objects that exist in the network. + async fn objects( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + filter: Option, + ) -> Result> { + let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; + + let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; + Object::paginate( + ctx.data_unchecked(), + page, + filter.unwrap_or_default(), + Some(checkpoint_viewed_at), + ) + .await + .extend() + } + + /// Fetch the protocol config by protocol version (defaults to the latest + /// protocol version known to the GraphQL service). + async fn protocol_config( + &self, + ctx: &Context<'_>, + protocol_version: Option, + ) -> Result { + ProtocolConfigs::query(ctx.data_unchecked(), protocol_version) + .await + .extend() + } + + /// Resolves a IotaNS `domain` name to an address, if it has been bound. + async fn resolve_iotans_address( + &self, + ctx: &Context<'_>, + domain: Domain, + ) -> Result> { + let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; + Ok( + NameService::resolve_to_record(ctx, &domain, Some(checkpoint_viewed_at)) + .await + .extend()? + .and_then(|r| r.target_address) + .map(|a| Address { + address: a.into(), + checkpoint_viewed_at: Some(checkpoint_viewed_at), + }), + ) + } + + /// The coin metadata associated with the given coin type. + async fn coin_metadata( + &self, + ctx: &Context<'_>, + coin_type: ExactTypeFilter, + ) -> Result> { + CoinMetadata::query(ctx.data_unchecked(), coin_type.0) + .await + .extend() + } + + /// Verify a zkLogin signature based on the provided transaction or personal + /// message based on current epoch, chain id, and latest JWKs fetched + /// on-chain. If the signature is valid, the function returns a + /// `ZkLoginVerifyResult` with success as true and an empty list of + /// errors. If the signature is invalid, the function returns + /// a `ZkLoginVerifyResult` with success as false with a list of errors. + /// + /// - `bytes` is either the personal message in raw bytes or transaction + /// data bytes in BCS-encoded and then Base64-encoded. + /// - `signature` is a serialized zkLogin signature that is Base64-encoded. + /// - `intentScope` is an enum that specifies the intent scope to be used to + /// parse bytes. + /// - `author` is the address of the signer of the transaction or personal + /// msg. + async fn verify_zklogin_signature( + &self, + ctx: &Context<'_>, + bytes: GraphQLBase64, + signature: GraphQLBase64, + intent_scope: ZkLoginIntentScope, + author: IotaAddress, + ) -> Result { + verify_zklogin_signature(ctx, bytes, signature, intent_scope, author) + .await + .extend() + } +} + +fn deserialize_tx_data(tx_bytes: &str) -> Result +where + T: DeserializeOwned, +{ + bcs::from_bytes( + &Base64::decode(tx_bytes) + .map_err(|e| { + Error::Client(format!( + "Unable to deserialize transaction bytes from Base64: {e}" + )) + }) + .extend()?, + ) + .map_err(|e| { + Error::Client(format!( + "Unable to deserialize transaction bytes as BCS: {e}" + )) + }) + .extend() +} diff --git a/crates/sui-graphql-rpc/src/types/safe_mode.rs b/crates/iota-graphql-rpc/src/types/safe_mode.rs similarity index 93% rename from crates/sui-graphql-rpc/src/types/safe_mode.rs rename to crates/iota-graphql-rpc/src/types/safe_mode.rs index d16f0b3f537..362bc731bce 100644 --- a/crates/sui-graphql-rpc/src/types/safe_mode.rs +++ b/crates/iota-graphql-rpc/src/types/safe_mode.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; diff --git a/crates/sui-graphql-rpc/src/types/stake.rs b/crates/iota-graphql-rpc/src/types/stake.rs similarity index 84% rename from crates/sui-graphql-rpc/src/types/stake.rs rename to crates/iota-graphql-rpc/src/types/stake.rs index 096cc55e054..2ba23cf6cb7 100644 --- a/crates/sui-graphql-rpc/src/types/stake.rs +++ b/crates/iota-graphql-rpc/src/types/stake.rs @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::{connection::Connection, *}; +use iota_json_rpc_types::{Stake as RpcStakedIota, StakeStatus as RpcStakeStatus}; +use iota_types::{base_types::MoveObjectType, governance::StakedIota as NativeStakedIota}; use move_core_types::language_storage::StructTag; -use sui_json_rpc_types::{Stake as RpcStakedSui, StakeStatus as RpcStakeStatus}; -use sui_types::{base_types::MoveObjectType, governance::StakedSui as NativeStakedSui}; use super::{ balance::{self, Balance}, @@ -15,13 +16,13 @@ use super::{ display::DisplayEntry, dynamic_field::{DynamicField, DynamicFieldName}, epoch::Epoch, + iota_address::IotaAddress, + iotans_registration::{DomainFormat, IotansRegistration}, move_object::{MoveObject, MoveObjectImpl}, move_value::MoveValue, object, object::{Object, ObjectFilter, ObjectImpl, ObjectOwner, ObjectStatus}, owner::OwnerImpl, - sui_address::SuiAddress, - suins_registration::{DomainFormat, SuinsRegistration}, transaction_block::{self, TransactionBlock, TransactionBlockFilter}, type_filter::ExactTypeFilter, }; @@ -39,25 +40,25 @@ pub(crate) enum StakeStatus { Unstaked, } -pub(crate) enum StakedSuiDowncastError { - NotAStakedSui, +pub(crate) enum StakedIotaDowncastError { + NotAStakedIota, Bcs(bcs::Error), } #[derive(Clone)] -pub(crate) struct StakedSui { - /// Representation of this StakedSui as a generic Move Object. +pub(crate) struct StakedIota { + /// Representation of this StakedIota as a generic Move Object. pub super_: MoveObject, /// Deserialized representation of the Move Object's contents as a - /// `0x3::staking_pool::StakedSui`. - pub native: NativeStakedSui, + /// `0x3::staking_pool::StakedIota`. + pub native: NativeStakedIota, } -/// Represents a `0x3::staking_pool::StakedSui` Move object on-chain. +/// Represents a `0x3::staking_pool::StakedIota` Move object on-chain. #[Object] -impl StakedSui { - pub(crate) async fn address(&self) -> SuiAddress { +impl StakedIota { + pub(crate) async fn address(&self) -> IotaAddress { OwnerImpl::from(&self.super_.super_).address().await } @@ -77,7 +78,7 @@ impl StakedSui { } /// Total balance of all coins with marker type owned by this object. If - /// type is not supplied, it defaults to `0x2::sui::SUI`. + /// type is not supplied, it defaults to `0x2::iota::IOTA`. pub(crate) async fn balance( &self, ctx: &Context<'_>, @@ -105,7 +106,7 @@ impl StakedSui { /// The coin objects for this object. /// /// `type` is a filter on the coin's type parameter, defaulting to - /// `0x2::sui::SUI`. + /// `0x2::iota::IOTA`. pub(crate) async fn coins( &self, ctx: &Context<'_>, @@ -120,44 +121,44 @@ impl StakedSui { .await } - /// The `0x3::staking_pool::StakedSui` objects owned by this object. - pub(crate) async fn staked_suis( + /// The `0x3::staking_pool::StakedIota` objects owned by this object. + pub(crate) async fn staked_iotas( &self, ctx: &Context<'_>, first: Option, after: Option, last: Option, before: Option, - ) -> Result> { + ) -> Result> { OwnerImpl::from(&self.super_.super_) - .staked_suis(ctx, first, after, last, before) + .staked_iotas(ctx, first, after, last, before) .await } /// The domain explicitly configured as the default domain pointing to this /// object. - pub(crate) async fn default_suins_name( + pub(crate) async fn default_iotans_name( &self, ctx: &Context<'_>, format: Option, ) -> Result> { OwnerImpl::from(&self.super_.super_) - .default_suins_name(ctx, format) + .default_iotans_name(ctx, format) .await } - /// The SuinsRegistration NFTs owned by this object. These grant the owner + /// The IotansRegistration NFTs owned by this object. These grant the owner /// the capability to manage the associated domain. - pub(crate) async fn suins_registrations( + pub(crate) async fn iotans_registrations( &self, ctx: &Context<'_>, first: Option, after: Option, last: Option, before: Option, - ) -> Result> { + ) -> Result> { OwnerImpl::from(&self.super_.super_) - .suins_registrations(ctx, first, after, last, before) + .iotans_registrations(ctx, first, after, last, before) .await } @@ -199,7 +200,7 @@ impl StakedSui { .await } - /// The amount of SUI we would rebate if this object gets deleted or + /// The amount of IOTA we would rebate if this object gets deleted or /// mutated. This number is recalculated based on the present storage /// gas price. pub(crate) async fn storage_rebate(&self) -> Option { @@ -235,7 +236,7 @@ impl StakedSui { /// Determines whether a transaction can transfer this object, using the /// TransferObjects transaction command or - /// `sui::transfer::public_transfer`, both of which require the object to + /// `iota::transfer::public_transfer`, both of which require the object to /// have the `key` and `store` abilities. pub(crate) async fn has_public_transfer(&self, ctx: &Context<'_>) -> Result { MoveObjectImpl(&self.super_).has_public_transfer(ctx).await @@ -338,11 +339,11 @@ impl StakedSui { } /// The object id of the validator staking pool this stake belongs to. - async fn pool_id(&self) -> Option { + async fn pool_id(&self) -> Option { Some(self.native.pool_id().into()) } - /// The SUI that was initially staked. + /// The IOTA that was initially staked. async fn principal(&self) -> Option { Some(BigInt::from(self.native.principal())) } @@ -367,8 +368,8 @@ impl StakedSui { } } -impl StakedSui { - /// Query the database for a `page` of Staked SUI. The page uses the same +impl StakedIota { + /// Query the database for a `page` of Staked IOTA. The page uses the same /// cursor type as is used for `Object`, and is further filtered to a /// particular `owner`. /// @@ -380,10 +381,10 @@ impl StakedSui { pub(crate) async fn paginate( db: &Db, page: Page, - owner: SuiAddress, + owner: IotaAddress, checkpoint_viewed_at: Option, - ) -> Result, Error> { - let type_: StructTag = MoveObjectType::staked_sui().into(); + ) -> Result, Error> { + let type_: StructTag = MoveObjectType::staked_iota().into(); let filter = ObjectFilter { type_: Some(type_.into()), @@ -395,42 +396,42 @@ impl StakedSui { let address = object.address; let move_object = MoveObject::try_from(&object).map_err(|_| { Error::Internal(format!( - "Expected {address} to be a StakedSui, but it's not a Move Object.", + "Expected {address} to be a StakedIota, but it's not a Move Object.", )) })?; - StakedSui::try_from(&move_object).map_err(|_| { + StakedIota::try_from(&move_object).map_err(|_| { Error::Internal(format!( - "Expected {address} to be a StakedSui, but it is not." + "Expected {address} to be a StakedIota, but it is not." )) }) }) .await } - /// The JSON-RPC representation of a StakedSui so that we can "cheat" to + /// The JSON-RPC representation of a StakedIota so that we can "cheat" to /// implement fields that are not yet implemented directly for GraphQL. /// /// TODO: Make this obsolete - async fn rpc_stake(&self, ctx: &Context<'_>) -> Result { + async fn rpc_stake(&self, ctx: &Context<'_>) -> Result { ctx.data_unchecked::() - .fetch_rpc_staked_sui(self.native.clone()) + .fetch_rpc_staked_iota(self.native.clone()) .await } } -impl TryFrom<&MoveObject> for StakedSui { - type Error = StakedSuiDowncastError; +impl TryFrom<&MoveObject> for StakedIota { + type Error = StakedIotaDowncastError; fn try_from(move_object: &MoveObject) -> Result { - if !move_object.native.is_staked_sui() { - return Err(StakedSuiDowncastError::NotAStakedSui); + if !move_object.native.is_staked_iota() { + return Err(StakedIotaDowncastError::NotAStakedIota); } Ok(Self { super_: move_object.clone(), native: bcs::from_bytes(move_object.native.contents()) - .map_err(StakedSuiDowncastError::Bcs)?, + .map_err(StakedIotaDowncastError::Bcs)?, }) } } diff --git a/crates/sui-graphql-rpc/src/types/stake_subsidy.rs b/crates/iota-graphql-rpc/src/types/stake_subsidy.rs similarity index 89% rename from crates/sui-graphql-rpc/src/types/stake_subsidy.rs rename to crates/iota-graphql-rpc/src/types/stake_subsidy.rs index 063ec94f04f..4073c251747 100644 --- a/crates/sui-graphql-rpc/src/types/stake_subsidy.rs +++ b/crates/iota-graphql-rpc/src/types/stake_subsidy.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; @@ -8,7 +9,7 @@ use super::big_int::BigInt; /// Parameters that control the distribution of the stake subsidy. #[derive(Clone, Debug, PartialEq, Eq, SimpleObject)] pub(crate) struct StakeSubsidy { - /// SUI set aside for stake subsidies -- reduces over time as stake + /// IOTA set aside for stake subsidies -- reduces over time as stake /// subsidies are paid out over time. pub balance: Option, diff --git a/crates/sui-graphql-rpc/src/types/storage_fund.rs b/crates/iota-graphql-rpc/src/types/storage_fund.rs similarity index 86% rename from crates/sui-graphql-rpc/src/types/storage_fund.rs rename to crates/iota-graphql-rpc/src/types/storage_fund.rs index 9214f2f749c..3f3e0f696ce 100644 --- a/crates/sui-graphql-rpc/src/types/storage_fund.rs +++ b/crates/iota-graphql-rpc/src/types/storage_fund.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; use super::big_int::BigInt; -/// SUI set aside to account for objects stored on-chain. +/// IOTA set aside to account for objects stored on-chain. #[derive(Clone, Debug, PartialEq, Eq, SimpleObject)] pub(crate) struct StorageFund { /// Sum of storage rebates of live objects on chain. diff --git a/crates/sui-graphql-rpc/src/types/string_input.rs b/crates/iota-graphql-rpc/src/types/string_input.rs similarity index 94% rename from crates/sui-graphql-rpc/src/types/string_input.rs rename to crates/iota-graphql-rpc/src/types/string_input.rs index 1937c9cf95f..a681c27e702 100644 --- a/crates/sui-graphql-rpc/src/types/string_input.rs +++ b/crates/iota-graphql-rpc/src/types/string_input.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Opt-in to an implementation of `ScalarType` for a `$Type` that implements diff --git a/crates/sui-graphql-rpc/src/types/system_parameters.rs b/crates/iota-graphql-rpc/src/types/system_parameters.rs similarity index 96% rename from crates/sui-graphql-rpc/src/types/system_parameters.rs rename to crates/iota-graphql-rpc/src/types/system_parameters.rs index 07177bd993b..f506aa69ef6 100644 --- a/crates/sui-graphql-rpc/src/types/system_parameters.rs +++ b/crates/iota-graphql-rpc/src/types/system_parameters.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; diff --git a/crates/sui-graphql-rpc/src/types/system_state_summary.rs b/crates/iota-graphql-rpc/src/types/system_state_summary.rs similarity index 92% rename from crates/sui-graphql-rpc/src/types/system_state_summary.rs rename to crates/iota-graphql-rpc/src/types/system_state_summary.rs index d70243f9f6b..93c397f9568 100644 --- a/crates/sui-graphql-rpc/src/types/system_state_summary.rs +++ b/crates/iota-graphql-rpc/src/types/system_state_summary.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; -use sui_types::sui_system_state::sui_system_state_summary::SuiSystemStateSummary as NativeSystemStateSummary; +use iota_types::iota_system_state::iota_system_state_summary::IotaSystemStateSummary as NativeSystemStateSummary; use super::{ big_int::BigInt, gas::GasCostSummary, safe_mode::SafeMode, stake_subsidy::StakeSubsidy, @@ -18,7 +19,7 @@ pub(crate) struct SystemStateSummary { /// validators either directly, or through system transactions. #[Object] impl SystemStateSummary { - /// SUI set aside to account for objects stored on-chain, at the start of + /// IOTA set aside to account for objects stored on-chain, at the start of /// the epoch. This is also used for storage rebates. async fn storage_fund(&self) -> Option { Some(StorageFund { @@ -46,7 +47,7 @@ impl SystemStateSummary { } /// The value of the `version` field of `0x5`, the - /// `0x3::sui::SuiSystemState` object. This version changes whenever + /// `0x3::iota::IotaSystemState` object. This version changes whenever /// the fields contained in the system state object (held in a dynamic /// field attached to `0x5`) change. async fn system_state_version(&self) -> Option { diff --git a/crates/sui-graphql-rpc/src/types/transaction_block.rs b/crates/iota-graphql-rpc/src/types/transaction_block.rs similarity index 98% rename from crates/sui-graphql-rpc/src/types/transaction_block.rs rename to crates/iota-graphql-rpc/src/types/transaction_block.rs index ce2c807e4af..ae3ff479102 100644 --- a/crates/sui-graphql-rpc/src/types/transaction_block.rs +++ b/crates/iota-graphql-rpc/src/types/transaction_block.rs @@ -1,6 +1,7 @@ use std::collections::{BTreeMap, BTreeSet}; // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::{ connection::{Connection, CursorType, Edge}, @@ -8,15 +9,14 @@ use async_graphql::{ }; use diesel::{ExpressionMethods, OptionalExtension, QueryDsl}; use fastcrypto::encoding::{Base58, Encoding}; -use serde::{Deserialize, Serialize}; -use sui_indexer::{ +use iota_indexer::{ models::transactions::StoredTransaction, schema::{ transactions, tx_calls, tx_changed_objects, tx_input_objects, tx_recipients, tx_senders, }, }; -use sui_types::{ - base_types::SuiAddress as NativeSuiAddress, +use iota_types::{ + base_types::IotaAddress as NativeIotaAddress, effects::TransactionEffects as NativeTransactionEffects, event::Event as NativeEvent, message_envelope::Message, @@ -25,6 +25,7 @@ use sui_types::{ TransactionDataAPI, TransactionExpiration, }, }; +use serde::{Deserialize, Serialize}; use super::{ address::Address, @@ -34,7 +35,7 @@ use super::{ digest::Digest, epoch::Epoch, gas::GasInput, - sui_address::SuiAddress, + iota_address::IotaAddress, transaction_block_effects::{TransactionBlockEffects, TransactionBlockEffectsKind}, transaction_block_kind::TransactionBlockKind, type_filter::FqNameFilter, @@ -102,11 +103,11 @@ pub(crate) struct TransactionBlockFilter { pub at_checkpoint: Option, pub before_checkpoint: Option, - pub sign_address: Option, - pub recv_address: Option, + pub sign_address: Option, + pub recv_address: Option, - pub input_object: Option, - pub changed_object: Option, + pub input_object: Option, + pub changed_object: Option, pub transaction_ids: Option>, } @@ -144,8 +145,8 @@ impl TransactionBlock { async fn sender(&self) -> Option
    { let sender = self.native().sender(); - (sender != NativeSuiAddress::ZERO).then(|| Address { - address: SuiAddress::from(sender), + (sender != NativeIotaAddress::ZERO).then(|| Address { + address: IotaAddress::from(sender), checkpoint_viewed_at: Some(self.checkpoint_viewed_at), }) } diff --git a/crates/sui-graphql-rpc/src/types/transaction_block_effects.rs b/crates/iota-graphql-rpc/src/types/transaction_block_effects.rs similarity index 99% rename from crates/sui-graphql-rpc/src/types/transaction_block_effects.rs rename to crates/iota-graphql-rpc/src/types/transaction_block_effects.rs index a3797ed20a9..f1b8fcac7eb 100644 --- a/crates/sui-graphql-rpc/src/types/transaction_block_effects.rs +++ b/crates/iota-graphql-rpc/src/types/transaction_block_effects.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::{ connection::{Connection, ConnectionNameType, CursorType, Edge, EdgeNameType, EmptyFields}, *, }; -use sui_indexer::models::transactions::StoredTransaction; -use sui_types::{ +use iota_indexer::models::transactions::StoredTransaction; +use iota_types::{ effects::{TransactionEffects as NativeTransactionEffects, TransactionEffectsAPI}, event::Event as NativeEvent, execution_status::ExecutionStatus as NativeExecutionStatus, diff --git a/crates/sui-graphql-rpc/src/types/transaction_block_kind/authenticator_state_update.rs b/crates/iota-graphql-rpc/src/types/transaction_block_kind/authenticator_state_update.rs similarity index 96% rename from crates/sui-graphql-rpc/src/types/transaction_block_kind/authenticator_state_update.rs rename to crates/iota-graphql-rpc/src/types/transaction_block_kind/authenticator_state_update.rs index 7c2dec66ef0..109ecebd22a 100644 --- a/crates/sui-graphql-rpc/src/types/transaction_block_kind/authenticator_state_update.rs +++ b/crates/iota-graphql-rpc/src/types/transaction_block_kind/authenticator_state_update.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::{ connection::{Connection, CursorType, Edge}, *, }; -use sui_types::{ +use iota_types::{ authenticator_state::ActiveJwk as NativeActiveJwk, transaction::AuthenticatorStateUpdate as NativeAuthenticatorStateUpdateTransaction, }; @@ -98,7 +99,7 @@ impl AuthenticatorStateUpdateTransaction { #[Object] impl ActiveJwk { - /// The string (Issuing Authority) that identifies the OIDC provider. + /// The string (Isiotang Authority) that identifies the OIDC provider. async fn iss(&self) -> &str { &self.native.jwk_id.iss } diff --git a/crates/sui-graphql-rpc/src/types/transaction_block_kind/consensus_commit_prologue.rs b/crates/iota-graphql-rpc/src/types/transaction_block_kind/consensus_commit_prologue.rs similarity index 97% rename from crates/sui-graphql-rpc/src/types/transaction_block_kind/consensus_commit_prologue.rs rename to crates/iota-graphql-rpc/src/types/transaction_block_kind/consensus_commit_prologue.rs index 270724bf066..f3fd77db8be 100644 --- a/crates/sui-graphql-rpc/src/types/transaction_block_kind/consensus_commit_prologue.rs +++ b/crates/iota-graphql-rpc/src/types/transaction_block_kind/consensus_commit_prologue.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; use fastcrypto::encoding::{Base58, Encoding}; -use sui_types::{ +use iota_types::{ digests::ConsensusCommitDigest, messages_checkpoint::CheckpointTimestamp, messages_consensus::{ diff --git a/crates/sui-graphql-rpc/src/types/transaction_block_kind/end_of_epoch.rs b/crates/iota-graphql-rpc/src/types/transaction_block_kind/end_of_epoch.rs similarity index 96% rename from crates/sui-graphql-rpc/src/types/transaction_block_kind/end_of_epoch.rs rename to crates/iota-graphql-rpc/src/types/transaction_block_kind/end_of_epoch.rs index 781d8873ee0..b5570b0702c 100644 --- a/crates/sui-graphql-rpc/src/types/transaction_block_kind/end_of_epoch.rs +++ b/crates/iota-graphql-rpc/src/types/transaction_block_kind/end_of_epoch.rs @@ -1,12 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::{ connection::{Connection, CursorType, Edge}, *, }; -use move_binary_format::{errors::PartialVMResult, CompiledModule}; -use sui_types::{ +use iota_types::{ digests::TransactionDigest, object::Object as NativeObject, transaction::{ @@ -15,6 +15,7 @@ use sui_types::{ EndOfEpochTransactionKind as NativeEndOfEpochTransactionKind, }, }; +use move_binary_format::{errors::PartialVMResult, CompiledModule}; use crate::{ consistency::ConsistentIndexCursor, @@ -24,9 +25,9 @@ use crate::{ cursor::{JsonCursor, Page}, date_time::DateTime, epoch::Epoch, + iota_address::IotaAddress, move_package::MovePackage, object::Object, - sui_address::SuiAddress, }, }; @@ -147,25 +148,25 @@ impl ChangeEpochTransaction { } /// The total amount of gas charged for storage during the previous epoch - /// (in MIST). + /// (in MICROS). async fn storage_charge(&self) -> BigInt { BigInt::from(self.native.storage_charge) } /// The total amount of gas charged for computation during the previous - /// epoch (in MIST). + /// epoch (in MICROS). async fn computation_charge(&self) -> BigInt { BigInt::from(self.native.computation_charge) } - /// The SUI returned to transaction senders for cleaning up objects (in - /// MIST). + /// The IOTA returned to transaction senders for cleaning up objects (in + /// MICROS). async fn storage_rebate(&self) -> BigInt { BigInt::from(self.native.storage_rebate) } /// The total gas retained from storage fees, that will not be returned by - /// storage rebates when the relevant objects are cleaned up (in MIST). + /// storage rebates when the relevant objects are cleaned up (in MICROS). async fn non_refundable_storage_fee(&self) -> BigInt { BigInt::from(self.native.non_refundable_storage_fee) } @@ -217,7 +218,7 @@ impl ChangeEpochTransaction { ); let runtime_id = native.id(); - let object = Object::from_native(SuiAddress::from(runtime_id), native, Some(c.c)); + let object = Object::from_native(IotaAddress::from(runtime_id), native, Some(c.c)); let package = MovePackage::try_from(&object, self.checkpoint_viewed_at) .map_err(|_| Error::Internal("Failed to create system package".to_string())) .extend()?; diff --git a/crates/iota-graphql-rpc/src/types/transaction_block_kind/genesis.rs b/crates/iota-graphql-rpc/src/types/transaction_block_kind/genesis.rs new file mode 100644 index 00000000000..b6e7f2ad3af --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/transaction_block_kind/genesis.rs @@ -0,0 +1,69 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_graphql::{ + connection::{Connection, CursorType, Edge}, + *, +}; +use iota_types::{ + digests::TransactionDigest, + object::Object as NativeObject, + transaction::{GenesisObject, GenesisTransaction as NativeGenesisTransaction}, +}; + +use crate::{ + consistency::ConsistentIndexCursor, + types::{ + cursor::{JsonCursor, Page}, + iota_address::IotaAddress, + object::Object, + }, +}; + +#[derive(Clone, PartialEq, Eq)] +pub(crate) struct GenesisTransaction { + pub native: NativeGenesisTransaction, + /// The checkpoint sequence number this was viewed at. + pub checkpoint_viewed_at: u64, +} + +pub(crate) type CObject = JsonCursor; + +/// System transaction that initializes the network and writes the initial set +/// of objects on-chain. +#[Object] +impl GenesisTransaction { + /// Objects to be created during genesis. + async fn objects( + &self, + ctx: &Context<'_>, + first: Option, + after: Option, + last: Option, + before: Option, + ) -> Result> { + let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; + + let mut connection = Connection::new(false, false); + let Some((prev, next, _, cs)) = + page.paginate_consistent_indices(self.native.objects.len(), self.checkpoint_viewed_at)? + else { + return Ok(connection); + }; + + connection.has_previous_page = prev; + connection.has_next_page = next; + + for c in cs { + let GenesisObject::RawObject { data, owner } = self.native.objects[c.ix].clone(); + let native = + NativeObject::new_from_genesis(data, owner, TransactionDigest::genesis_marker()); + + let object = Object::from_native(IotaAddress::from(native.id()), native, Some(c.c)); + connection.edges.push(Edge::new(c.encode_cursor(), object)); + } + + Ok(connection) + } +} diff --git a/crates/iota-graphql-rpc/src/types/transaction_block_kind/mod.rs b/crates/iota-graphql-rpc/src/types/transaction_block_kind/mod.rs new file mode 100644 index 00000000000..59a5108a2c5 --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/transaction_block_kind/mod.rs @@ -0,0 +1,78 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_graphql::*; +use iota_types::transaction::TransactionKind as NativeTransactionKind; + +use self::{ + consensus_commit_prologue::ConsensusCommitPrologueTransaction, + end_of_epoch::ChangeEpochTransaction, genesis::GenesisTransaction, + randomness_state_update::RandomnessStateUpdateTransaction, +}; +use crate::types::transaction_block_kind::{ + authenticator_state_update::AuthenticatorStateUpdateTransaction, + end_of_epoch::EndOfEpochTransaction, programmable::ProgrammableTransactionBlock, +}; + +pub(crate) mod authenticator_state_update; +pub(crate) mod consensus_commit_prologue; +pub(crate) mod end_of_epoch; +pub(crate) mod genesis; +pub(crate) mod programmable; +pub(crate) mod randomness_state_update; + +/// The kind of transaction block, either a programmable transaction or a system +/// transaction. +#[derive(Union, PartialEq, Clone, Eq)] +pub(crate) enum TransactionBlockKind { + ConsensusCommitPrologue(ConsensusCommitPrologueTransaction), + Genesis(GenesisTransaction), + ChangeEpoch(ChangeEpochTransaction), + Programmable(ProgrammableTransactionBlock), + AuthenticatorState(AuthenticatorStateUpdateTransaction), + Randomness(RandomnessStateUpdateTransaction), + EndOfEpoch(EndOfEpochTransaction), +} + +impl TransactionBlockKind { + pub(crate) fn from(kind: NativeTransactionKind, checkpoint_viewed_at: u64) -> Self { + use NativeTransactionKind as K; + use TransactionBlockKind as T; + + match kind { + K::ProgrammableTransaction(pt) => T::Programmable(ProgrammableTransactionBlock { + native: pt, + checkpoint_viewed_at, + }), + K::ChangeEpoch(ce) => T::ChangeEpoch(ChangeEpochTransaction { + native: ce, + checkpoint_viewed_at, + }), + K::Genesis(g) => T::Genesis(GenesisTransaction { + native: g, + checkpoint_viewed_at, + }), + K::ConsensusCommitPrologue(ccp) => T::ConsensusCommitPrologue( + ConsensusCommitPrologueTransaction::from_v1(ccp, checkpoint_viewed_at), + ), + K::ConsensusCommitPrologueV2(ccp) => T::ConsensusCommitPrologue( + ConsensusCommitPrologueTransaction::from_v2(ccp, checkpoint_viewed_at), + ), + K::AuthenticatorStateUpdate(asu) => { + T::AuthenticatorState(AuthenticatorStateUpdateTransaction { + native: asu, + checkpoint_viewed_at, + }) + } + K::EndOfEpochTransaction(eoe) => T::EndOfEpoch(EndOfEpochTransaction { + native: eoe, + checkpoint_viewed_at, + }), + K::RandomnessStateUpdate(rsu) => T::Randomness(RandomnessStateUpdateTransaction { + native: rsu, + checkpoint_viewed_at, + }), + } + } +} diff --git a/crates/sui-graphql-rpc/src/types/transaction_block_kind/programmable.rs b/crates/iota-graphql-rpc/src/types/transaction_block_kind/programmable.rs similarity index 95% rename from crates/sui-graphql-rpc/src/types/transaction_block_kind/programmable.rs rename to crates/iota-graphql-rpc/src/types/transaction_block_kind/programmable.rs index a18eb9309c7..75d4d09cb74 100644 --- a/crates/sui-graphql-rpc/src/types/transaction_block_kind/programmable.rs +++ b/crates/iota-graphql-rpc/src/types/transaction_block_kind/programmable.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::{ connection::{Connection, CursorType, Edge}, *, }; -use sui_json_rpc_types::SuiArgument; -use sui_types::transaction::{ +use iota_json_rpc_types::IotaArgument; +use iota_types::transaction::{ Argument as NativeArgument, CallArg as NativeCallArg, Command as NativeProgrammableTransaction, ObjectArg as NativeObjectArg, ProgrammableMoveCall as NativeMoveCallTransaction, ProgrammableTransaction as NativeProgrammableTransactionBlock, @@ -17,10 +18,10 @@ use crate::{ types::{ base64::Base64, cursor::{JsonCursor, Page}, + iota_address::IotaAddress, move_function::MoveFunction, move_type::MoveType, object_read::ObjectRead, - sui_address::SuiAddress, }, }; @@ -52,7 +53,7 @@ struct OwnedOrImmutable { /// A Move object that's shared. #[derive(SimpleObject, Clone, Eq, PartialEq)] struct SharedInput { - address: SuiAddress, + address: IotaAddress, /// The version that this this object was shared at. initial_shared_version: u64, /// Controls whether the transaction block can reference the shared object @@ -136,7 +137,7 @@ struct PublishTransaction { modules: Vec, /// IDs of the transitive dependencies of the package to be published. - dependencies: Vec, + dependencies: Vec, } /// Upgrades a Move Package. @@ -147,10 +148,10 @@ struct UpgradeTransaction { modules: Vec, /// IDs of the transitive dependencies of the package to be published. - dependencies: Vec, + dependencies: Vec, /// ID of the package being upgraded. - current_package: SuiAddress, + current_package: IotaAddress, /// The `UpgradeTicket` authorizing the upgrade. upgrade_ticket: TransactionArgument, @@ -275,7 +276,7 @@ impl ProgrammableTransactionBlock { #[Object] impl MoveCallTransaction { /// The storage ID of the package the function being called is defined in. - async fn package(&self) -> SuiAddress { + async fn package(&self) -> IotaAddress { self.native.package.into() } @@ -386,7 +387,7 @@ impl ProgrammableTransaction { N::Publish(modules, dependencies) => P::Publish(PublishTransaction { modules: modules.into_iter().map(Base64::from).collect(), - dependencies: dependencies.into_iter().map(SuiAddress::from).collect(), + dependencies: dependencies.into_iter().map(IotaAddress::from).collect(), }), N::MakeMoveVec(type_, elements) => P::MakeMoveVec(MakeMoveVecTransaction { @@ -400,7 +401,7 @@ impl ProgrammableTransaction { N::Upgrade(modules, dependencies, current_package, upgrade_ticket) => { P::Upgrade(UpgradeTransaction { modules: modules.into_iter().map(Base64::from).collect(), - dependencies: dependencies.into_iter().map(SuiAddress::from).collect(), + dependencies: dependencies.into_iter().map(IotaAddress::from).collect(), current_package: current_package.into(), upgrade_ticket: upgrade_ticket.into(), }) @@ -422,9 +423,9 @@ impl From for TransactionArgument { } } -impl From for TransactionArgument { - fn from(argument: SuiArgument) -> Self { - use SuiArgument as S; +impl From for TransactionArgument { + fn from(argument: IotaArgument) -> Self { + use IotaArgument as S; use TransactionArgument as A; match argument { S::GasCoin => A::GasCoin(GasCoin { dummy: None }), diff --git a/crates/sui-graphql-rpc/src/types/transaction_block_kind/randomness_state_update.rs b/crates/iota-graphql-rpc/src/types/transaction_block_kind/randomness_state_update.rs similarity index 90% rename from crates/sui-graphql-rpc/src/types/transaction_block_kind/randomness_state_update.rs rename to crates/iota-graphql-rpc/src/types/transaction_block_kind/randomness_state_update.rs index a4436552619..5bd2e81df79 100644 --- a/crates/sui-graphql-rpc/src/types/transaction_block_kind/randomness_state_update.rs +++ b/crates/iota-graphql-rpc/src/types/transaction_block_kind/randomness_state_update.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; -use sui_types::transaction::RandomnessStateUpdate as NativeRandomnessStateUpdate; +use iota_types::transaction::RandomnessStateUpdate as NativeRandomnessStateUpdate; use crate::types::{base64::Base64, epoch::Epoch}; diff --git a/crates/sui-graphql-rpc/src/types/transaction_metadata.rs b/crates/iota-graphql-rpc/src/types/transaction_metadata.rs similarity index 77% rename from crates/sui-graphql-rpc/src/types/transaction_metadata.rs rename to crates/iota-graphql-rpc/src/types/transaction_metadata.rs index 1ecc63356a2..6dd4908cf34 100644 --- a/crates/sui-graphql-rpc/src/types/transaction_metadata.rs +++ b/crates/iota-graphql-rpc/src/types/transaction_metadata.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; -use super::{object::ObjectRef, sui_address::SuiAddress}; +use super::{iota_address::IotaAddress, object::ObjectRef}; /// The optional extra data a user can provide to a transaction dry run. /// `sender` defaults to `0x0`. If gasObjects` is not present, or is an empty @@ -12,9 +13,9 @@ use super::{object::ObjectRef, sui_address::SuiAddress}; /// `gasSponsor` defaults to the sender. #[derive(Clone, Debug, PartialEq, Eq, InputObject)] pub(crate) struct TransactionMetadata { - pub sender: Option, + pub sender: Option, pub gas_price: Option, pub gas_objects: Option>, pub gas_budget: Option, - pub gas_sponsor: Option, + pub gas_sponsor: Option, } diff --git a/crates/sui-graphql-rpc/src/types/type_filter.rs b/crates/iota-graphql-rpc/src/types/type_filter.rs similarity index 88% rename from crates/sui-graphql-rpc/src/types/type_filter.rs rename to crates/iota-graphql-rpc/src/types/type_filter.rs index 52de71cad2d..48a0e457bc6 100644 --- a/crates/sui-graphql-rpc/src/types/type_filter.rs +++ b/crates/iota-graphql-rpc/src/types/type_filter.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fmt, result::Result, str::FromStr}; @@ -11,12 +12,12 @@ use diesel::{ AppearsOnTable, BoolExpressionMethods, Expression, ExpressionMethods, QueryDsl, QuerySource, TextExpressionMethods, }; -use move_core_types::language_storage::StructTag; -use sui_types::{ - parse_sui_address, parse_sui_fq_name, parse_sui_module_id, parse_sui_type_tag, TypeTag, +use iota_types::{ + parse_iota_address, parse_iota_fq_name, parse_iota_module_id, parse_iota_type_tag, TypeTag, }; +use move_core_types::language_storage::StructTag; -use super::{string_input::impl_string_input, sui_address::SuiAddress}; +use super::{iota_address::IotaAddress, string_input::impl_string_input}; use crate::{ data::{DieselBackend, Query}, filter, @@ -40,7 +41,7 @@ pub(crate) enum TypeFilter { /// /// 0x2::coin::Coin /// - /// would match both 0x2::coin::Coin and 0x2::coin::Coin<0x2::sui::SUI>. + /// would match both 0x2::coin::Coin and 0x2::coin::Coin<0x2::iota::IOTA>. ByType(TypeTag), } @@ -51,17 +52,17 @@ pub(crate) enum FqNameFilter { ByModule(ModuleFilter), /// Exact match on the module member. - ByFqName(SuiAddress, String, String), + ByFqName(IotaAddress, String, String), } /// GraphQL scalar containing a filter on modules. #[derive(Clone, Debug, Eq, PartialEq)] pub(crate) enum ModuleFilter { /// Filter the module by the package it's from. - ByPackage(SuiAddress), + ByPackage(IotaAddress), /// Exact match on the module. - ByModule(SuiAddress, String), + ByModule(IotaAddress, String), } #[derive(thiserror::Error, Debug)] @@ -178,20 +179,20 @@ impl TypeFilter { (T::ByType(_), T::ByType(_)) => (self == other).then_some(self), (T::ByType(TT::Struct(s)), T::ByModule(M::ByPackage(q))) => { - (SuiAddress::from(s.address) == *q).then_some(self) + (IotaAddress::from(s.address) == *q).then_some(self) } (T::ByType(TT::Struct(s)), T::ByModule(M::ByModule(q, n))) => { - ((SuiAddress::from(s.address), s.module.as_str()) == (*q, n.as_str())) + ((IotaAddress::from(s.address), s.module.as_str()) == (*q, n.as_str())) .then_some(self) } (T::ByModule(M::ByPackage(p)), T::ByType(TT::Struct(t))) => { - (SuiAddress::from(t.address) == *p).then_some(other) + (IotaAddress::from(t.address) == *p).then_some(other) } (T::ByModule(M::ByModule(p, m)), T::ByType(TT::Struct(t))) => { - ((SuiAddress::from(t.address), t.module.as_str()) == (*p, m.as_str())) + ((IotaAddress::from(t.address), t.module.as_str()) == (*p, m.as_str())) .then_some(other) } @@ -315,7 +316,7 @@ impl FromStr for ExactTypeFilter { type Err = Error; fn from_str(s: &str) -> Result { - if let Ok(tag) = parse_sui_type_tag(s) { + if let Ok(tag) = parse_iota_type_tag(s) { Ok(ExactTypeFilter(tag)) } else { Err(Error::InvalidFormat( @@ -328,7 +329,7 @@ impl FromStr for ExactTypeFilter { impl FromStr for TypeFilter { type Err = Error; fn from_str(s: &str) -> Result { - if let Ok(tag) = parse_sui_type_tag(s) { + if let Ok(tag) = parse_iota_type_tag(s) { Ok(TypeFilter::ByType(tag)) } else if let Ok(filter) = ModuleFilter::from_str(s) { Ok(TypeFilter::ByModule(filter)) @@ -343,9 +344,9 @@ impl FromStr for TypeFilter { impl FromStr for FqNameFilter { type Err = Error; fn from_str(s: &str) -> Result { - if let Ok((module, name)) = parse_sui_fq_name(s) { + if let Ok((module, name)) = parse_iota_fq_name(s) { Ok(FqNameFilter::ByFqName( - SuiAddress::from(*module.address()), + IotaAddress::from(*module.address()), module.name().to_string(), name, )) @@ -360,12 +361,12 @@ impl FromStr for FqNameFilter { impl FromStr for ModuleFilter { type Err = Error; fn from_str(s: &str) -> Result { - if let Ok(module) = parse_sui_module_id(s) { + if let Ok(module) = parse_iota_module_id(s) { Ok(ModuleFilter::ByModule( - SuiAddress::from(*module.address()), + IotaAddress::from(*module.address()), module.name().to_string(), )) - } else if let Ok(package) = parse_sui_address(s) { + } else if let Ok(package) = parse_iota_address(s) { Ok(ModuleFilter::ByPackage(package.into())) } else { Err(Error::InvalidFormat("package[::module]")) @@ -433,9 +434,9 @@ mod tests { "address", "bool", "0x2::coin::Coin", - "0x2::coin::Coin<0x2::sui::SUI>", + "0x2::coin::Coin<0x2::iota::IOTA>", "vector", - "vector<0x3::staking_pool::StakedSui>", + "vector<0x3::staking_pool::StakedIota>", ] .into_iter(); @@ -448,9 +449,9 @@ mod tests { address bool 0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin - 0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI> + 0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA> vector - vector<0x0000000000000000000000000000000000000000000000000000000000000003::staking_pool::StakedSui>"#]]; + vector<0x0000000000000000000000000000000000000000000000000000000000000003::staking_pool::StakedIota>"#]]; expect.assert_eq(&filters.join("\n")) } @@ -463,9 +464,9 @@ mod tests { "0x2", "0x2::coin", "0x2::coin::Coin", - "0x2::coin::Coin<0x2::sui::SUI>", + "0x2::coin::Coin<0x2::iota::IOTA>", "vector", - "vector<0x3::staking_pool::StakedSui>", + "vector<0x3::staking_pool::StakedIota>", ] .into_iter(); @@ -480,9 +481,9 @@ mod tests { 0x0000000000000000000000000000000000000000000000000000000000000002:: 0x0000000000000000000000000000000000000000000000000000000000000002::coin:: 0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin - 0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI> + 0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA> vector - vector<0x0000000000000000000000000000000000000000000000000000000000000003::staking_pool::StakedSui>"#]]; + vector<0x0000000000000000000000000000000000000000000000000000000000000003::staking_pool::StakedIota>"#]]; expect.assert_eq(&filters.join("\n")) } @@ -511,9 +512,9 @@ mod tests { #[test] fn test_invalid_function_filters() { for invalid_function_filter in [ - "0x2::coin::Coin<0x2::sui::SUI>", + "0x2::coin::Coin<0x2::iota::IOTA>", "vector", - "vector<0x3::staking_pool::StakedSui>", + "vector<0x3::staking_pool::StakedIota>", ] { assert!(FqNameFilter::from_str(invalid_function_filter).is_err()); } @@ -554,9 +555,9 @@ mod tests { "address", "bool", "0x2::coin::Coin", - "0x2::coin::Coin<0x2::sui::SUI>", + "0x2::coin::Coin<0x2::iota::IOTA>", "vector", - "vector<0x3::staking_pool::StakedSui>", + "vector<0x3::staking_pool::StakedIota>", ] { assert!(ModuleFilter::from_str(invalid_module_filter).is_err()); } @@ -564,7 +565,7 @@ mod tests { #[test] fn test_fqname_intersection() { - let sui = FqNameFilter::from_str("0x2").unwrap(); + let iota = FqNameFilter::from_str("0x2").unwrap(); let coin = FqNameFilter::from_str("0x2::coin").unwrap(); let take = FqNameFilter::from_str("0x2::coin::take").unwrap(); @@ -572,13 +573,13 @@ mod tests { let string = FqNameFilter::from_str("0x1::string").unwrap(); let utf8 = FqNameFilter::from_str("0x1::string::utf8").unwrap(); - assert_eq!(sui.clone().intersect(sui.clone()), Some(sui.clone())); - assert_eq!(sui.clone().intersect(coin.clone()), Some(coin.clone())); - assert_eq!(sui.clone().intersect(take.clone()), Some(take.clone())); + assert_eq!(iota.clone().intersect(iota.clone()), Some(iota.clone())); + assert_eq!(iota.clone().intersect(coin.clone()), Some(coin.clone())); + assert_eq!(iota.clone().intersect(take.clone()), Some(take.clone())); assert_eq!(take.clone().intersect(coin.clone()), Some(take.clone())); - assert_eq!(sui.clone().intersect(std.clone()), None); - assert_eq!(sui.clone().intersect(string.clone()), None); + assert_eq!(iota.clone().intersect(std.clone()), None); + assert_eq!(iota.clone().intersect(string.clone()), None); assert_eq!(utf8.clone().intersect(coin.clone()), None); } @@ -587,10 +588,10 @@ mod tests { let address = TypeFilter::from_str("address").unwrap(); let vec_u8 = TypeFilter::from_str("vector").unwrap(); - let sui = TypeFilter::from_str("0x2").unwrap(); + let iota = TypeFilter::from_str("0x2").unwrap(); let coin_mod = TypeFilter::from_str("0x2::coin").unwrap(); let coin_typ = TypeFilter::from_str("0x2::coin::Coin").unwrap(); - let coin_sui = TypeFilter::from_str("0x2::coin::Coin<0x2::sui::SUI>").unwrap(); + let coin_iota = TypeFilter::from_str("0x2::coin::Coin<0x2::iota::IOTA>").unwrap(); let coin_usd = TypeFilter::from_str("0x2::coin::Coin<0x3::usd::USD>").unwrap(); let std_utf8 = TypeFilter::from_str("0x1::string::String").unwrap(); @@ -605,7 +606,7 @@ mod tests { ); assert_eq!( - sui.clone().intersect(coin_mod.clone()), + iota.clone().intersect(coin_mod.clone()), Some(coin_mod.clone()) ); @@ -615,14 +616,14 @@ mod tests { ); assert_eq!( - coin_sui.clone().intersect(coin_typ.clone()), - Some(coin_sui.clone()) + coin_iota.clone().intersect(coin_typ.clone()), + Some(coin_iota.clone()) ); - assert_eq!(sui.clone().intersect(vec_u8.clone()), None); + assert_eq!(iota.clone().intersect(vec_u8.clone()), None); assert_eq!(coin_typ.clone().intersect(address.clone()), None); - assert_eq!(coin_sui.clone().intersect(coin_usd.clone()), None); + assert_eq!(coin_iota.clone().intersect(coin_usd.clone()), None); assert_eq!(coin_typ.clone().intersect(std_utf8.clone()), None); - assert_eq!(coin_sui.clone().intersect(std_utf8.clone()), None); + assert_eq!(coin_iota.clone().intersect(std_utf8.clone()), None); } } diff --git a/crates/sui-graphql-rpc/src/types/unchanged_shared_object.rs b/crates/iota-graphql-rpc/src/types/unchanged_shared_object.rs similarity index 91% rename from crates/sui-graphql-rpc/src/types/unchanged_shared_object.rs rename to crates/iota-graphql-rpc/src/types/unchanged_shared_object.rs index c9a325a9993..f9db11bd501 100644 --- a/crates/sui-graphql-rpc/src/types/unchanged_shared_object.rs +++ b/crates/iota-graphql-rpc/src/types/unchanged_shared_object.rs @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; -use sui_types::effects::InputSharedObject as NativeInputSharedObject; +use iota_types::effects::InputSharedObject as NativeInputSharedObject; -use super::{object_read::ObjectRead, sui_address::SuiAddress}; +use super::{iota_address::IotaAddress, object_read::ObjectRead}; /// Details pertaining to shared objects that are referenced by but not changed /// by a transaction. This information is considered part of the effects, @@ -28,7 +29,7 @@ pub(crate) struct SharedObjectRead { #[derive(SimpleObject)] pub(crate) struct SharedObjectDelete { /// ID of the shared object. - address: SuiAddress, + address: IotaAddress, /// The version of the shared object that was assigned to this transaction /// during by consensus, during sequencing. diff --git a/crates/iota-graphql-rpc/src/types/validator.rs b/crates/iota-graphql-rpc/src/types/validator.rs new file mode 100644 index 00000000000..7be1c63ed7a --- /dev/null +++ b/crates/iota-graphql-rpc/src/types/validator.rs @@ -0,0 +1,284 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_graphql::{ + connection::{Connection, CursorType, Edge}, + *, +}; +use iota_types::iota_system_state::iota_system_state_summary::IotaValidatorSummary as NativeIotaValidatorSummary; + +use super::{ + address::Address, base64::Base64, big_int::BigInt, iota_address::IotaAddress, + move_object::MoveObject, object::ObjectLookupKey, validator_credentials::ValidatorCredentials, +}; +use crate::{ + consistency::ConsistentIndexCursor, + context_data::db_data_provider::PgManager, + types::cursor::{JsonCursor, Page}, +}; + +#[derive(Clone, Debug)] +pub(crate) struct Validator { + pub validator_summary: NativeIotaValidatorSummary, + pub at_risk: Option, + pub report_records: Option>, + /// The checkpoint sequence number at which this was viewed at. + pub checkpoint_viewed_at: u64, +} + +type CAddr = JsonCursor; + +#[Object] +impl Validator { + /// The validator's address. + async fn address(&self) -> Address { + Address { + address: IotaAddress::from(self.validator_summary.iota_address), + checkpoint_viewed_at: Some(self.checkpoint_viewed_at), + } + } + + /// Validator's set of credentials such as public keys, network addresses + /// and others. + async fn credentials(&self) -> Option { + let v = &self.validator_summary; + let credentials = ValidatorCredentials { + protocol_pub_key: Some(Base64::from(v.protocol_pubkey_bytes.clone())), + network_pub_key: Some(Base64::from(v.network_pubkey_bytes.clone())), + worker_pub_key: Some(Base64::from(v.worker_pubkey_bytes.clone())), + proof_of_possession: Some(Base64::from(v.proof_of_possession_bytes.clone())), + net_address: Some(v.net_address.clone()), + p2p_address: Some(v.p2p_address.clone()), + primary_address: Some(v.primary_address.clone()), + worker_address: Some(v.worker_address.clone()), + }; + Some(credentials) + } + + /// Validator's set of credentials for the next epoch. + async fn next_epoch_credentials(&self) -> Option { + let v = &self.validator_summary; + let credentials = ValidatorCredentials { + protocol_pub_key: v + .next_epoch_protocol_pubkey_bytes + .as_ref() + .map(Base64::from), + network_pub_key: v.next_epoch_network_pubkey_bytes.as_ref().map(Base64::from), + worker_pub_key: v.next_epoch_worker_pubkey_bytes.as_ref().map(Base64::from), + proof_of_possession: v.next_epoch_proof_of_possession.as_ref().map(Base64::from), + net_address: v.next_epoch_net_address.clone(), + p2p_address: v.next_epoch_p2p_address.clone(), + primary_address: v.next_epoch_primary_address.clone(), + worker_address: v.next_epoch_worker_address.clone(), + }; + Some(credentials) + } + + /// Validator's name. + async fn name(&self) -> Option { + Some(self.validator_summary.name.clone()) + } + + /// Validator's description. + async fn description(&self) -> Option { + Some(self.validator_summary.description.clone()) + } + + /// Validator's url containing their custom image. + async fn image_url(&self) -> Option { + Some(self.validator_summary.image_url.clone()) + } + + /// Validator's homepage URL. + async fn project_url(&self) -> Option { + Some(self.validator_summary.project_url.clone()) + } + + /// The validator's current valid `Cap` object. Validators can delegate + /// the operation ability to another address. The address holding this `Cap` + /// object can then update the reference gas price and tallying rule on + /// behalf of the validator. + async fn operation_cap(&self, ctx: &Context<'_>) -> Result> { + MoveObject::query( + ctx.data_unchecked(), + self.operation_cap_id(), + ObjectLookupKey::LatestAt(self.checkpoint_viewed_at), + ) + .await + .extend() + } + + /// The validator's current staking pool object, used to track the amount of + /// stake and to compound staking rewards. + async fn staking_pool(&self, ctx: &Context<'_>) -> Result> { + MoveObject::query( + ctx.data_unchecked(), + self.staking_pool_id(), + ObjectLookupKey::LatestAt(self.checkpoint_viewed_at), + ) + .await + .extend() + } + + /// The validator's current exchange object. The exchange rate is used to + /// determine the amount of IOTA tokens that each past IOTA staker can + /// withdraw in the future. + async fn exchange_rates(&self, ctx: &Context<'_>) -> Result> { + MoveObject::query( + ctx.data_unchecked(), + self.exchange_rates_id(), + ObjectLookupKey::LatestAt(self.checkpoint_viewed_at), + ) + .await + .extend() + } + + /// Number of exchange rates in the table. + async fn exchange_rates_size(&self) -> Option { + Some(self.validator_summary.exchange_rates_size) + } + + /// The epoch at which this pool became active. + async fn staking_pool_activation_epoch(&self) -> Option { + self.validator_summary.staking_pool_activation_epoch + } + + /// The total number of IOTA tokens in this pool. + async fn staking_pool_iota_balance(&self) -> Option { + Some(BigInt::from( + self.validator_summary.staking_pool_iota_balance, + )) + } + + /// The epoch stake rewards will be added here at the end of each epoch. + async fn rewards_pool(&self) -> Option { + Some(BigInt::from(self.validator_summary.rewards_pool)) + } + + /// Total number of pool tokens issued by the pool. + async fn pool_token_balance(&self) -> Option { + Some(BigInt::from(self.validator_summary.pool_token_balance)) + } + + /// Pending stake amount for this epoch. + async fn pending_stake(&self) -> Option { + Some(BigInt::from(self.validator_summary.pending_stake)) + } + + /// Pending stake withdrawn during the current epoch, emptied at epoch + /// boundaries. + async fn pending_total_iota_withdraw(&self) -> Option { + Some(BigInt::from( + self.validator_summary.pending_total_iota_withdraw, + )) + } + + /// Pending pool token withdrawn during the current epoch, emptied at epoch + /// boundaries. + async fn pending_pool_token_withdraw(&self) -> Option { + Some(BigInt::from( + self.validator_summary.pending_pool_token_withdraw, + )) + } + + /// The voting power of this validator in basis points (e.g., 100 = 1% + /// voting power). + async fn voting_power(&self) -> Option { + Some(self.validator_summary.voting_power) + } + + // TODO async fn stake_units(&self) -> Option{} + + /// The reference gas price for this epoch. + async fn gas_price(&self) -> Option { + Some(BigInt::from(self.validator_summary.gas_price)) + } + + /// The fee charged by the validator for staking services. + async fn commission_rate(&self) -> Option { + Some(self.validator_summary.commission_rate) + } + + /// The total number of IOTA tokens in this pool plus + /// the pending stake amount for this epoch. + async fn next_epoch_stake(&self) -> Option { + Some(BigInt::from(self.validator_summary.next_epoch_stake)) + } + + /// The validator's gas price quote for the next epoch. + async fn next_epoch_gas_price(&self) -> Option { + Some(BigInt::from(self.validator_summary.next_epoch_gas_price)) + } + + /// The proposed next epoch fee for the validator's staking services. + async fn next_epoch_commission_rate(&self) -> Option { + Some(self.validator_summary.next_epoch_commission_rate) + } + + /// The number of epochs for which this validator has been below the + /// low stake threshold. + async fn at_risk(&self) -> Option { + self.at_risk + } + + /// The addresses of other validators this validator has reported. + async fn report_records( + &self, + ctx: &Context<'_>, + first: Option, + before: Option, + last: Option, + after: Option, + ) -> Result> { + let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; + + let mut connection = Connection::new(false, false); + let Some(addresses) = &self.report_records else { + return Ok(connection); + }; + + let Some((prev, next, _, cs)) = + page.paginate_consistent_indices(addresses.len(), self.checkpoint_viewed_at)? + else { + return Ok(connection); + }; + + connection.has_previous_page = prev; + connection.has_next_page = next; + + for c in cs { + connection.edges.push(Edge::new( + c.encode_cursor(), + Address { + address: addresses[c.ix].address, + checkpoint_viewed_at: Some(c.c), + }, + )); + } + + Ok(connection) + } + + /// The APY of this validator in basis points. + /// To get the APY in percentage, divide by 100. + async fn apy(&self, ctx: &Context<'_>) -> Result, Error> { + Ok(ctx + .data_unchecked::() + .fetch_validator_apys(&self.validator_summary.iota_address) + .await? + .map(|x| (x * 10000.0) as u64)) + } +} + +impl Validator { + pub fn operation_cap_id(&self) -> IotaAddress { + IotaAddress::from_array(**self.validator_summary.operation_cap_id) + } + pub fn staking_pool_id(&self) -> IotaAddress { + IotaAddress::from_array(**self.validator_summary.staking_pool_id) + } + pub fn exchange_rates_id(&self) -> IotaAddress { + IotaAddress::from_array(**self.validator_summary.exchange_rates_id) + } +} diff --git a/crates/sui-graphql-rpc/src/types/validator_credentials.rs b/crates/iota-graphql-rpc/src/types/validator_credentials.rs similarity index 92% rename from crates/sui-graphql-rpc/src/types/validator_credentials.rs rename to crates/iota-graphql-rpc/src/types/validator_credentials.rs index 04a5c6ef2ad..cf5cb79c502 100644 --- a/crates/sui-graphql-rpc/src/types/validator_credentials.rs +++ b/crates/iota-graphql-rpc/src/types/validator_credentials.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; diff --git a/crates/sui-graphql-rpc/src/types/validator_set.rs b/crates/iota-graphql-rpc/src/types/validator_set.rs similarity index 91% rename from crates/sui-graphql-rpc/src/types/validator_set.rs rename to crates/iota-graphql-rpc/src/types/validator_set.rs index 1b78385ec92..56ee6358f75 100644 --- a/crates/sui-graphql-rpc/src/types/validator_set.rs +++ b/crates/iota-graphql-rpc/src/types/validator_set.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::{ @@ -11,7 +12,7 @@ use crate::{ consistency::ConsistentIndexCursor, types::{ cursor::{JsonCursor, Page}, - sui_address::SuiAddress, + iota_address::IotaAddress, }, }; @@ -35,7 +36,7 @@ pub(crate) struct ValidatorSet { // itself, paginated. /// Object ID of the wrapped object `TableVec` storing the pending active /// validators. - pub pending_active_validators_id: Option, + pub pending_active_validators_id: Option, /// Size of the pending active validators table. pub pending_active_validators_size: Option, @@ -44,19 +45,19 @@ pub(crate) struct ValidatorSet { /// the addresses of the corresponding validators. This is needed /// because a validator's address can potentially change but the object /// ID of its pool will not. - pub staking_pool_mappings_id: Option, + pub staking_pool_mappings_id: Option, /// Size of the stake pool mappings `Table`. pub staking_pool_mappings_size: Option, /// Object ID of the `Table` storing the inactive staking pools. - pub inactive_pools_id: Option, + pub inactive_pools_id: Option, /// Size of the inactive pools `Table`. pub inactive_pools_size: Option, /// Object ID of the `Table` storing the validator candidates. - pub validator_candidates_id: Option, + pub validator_candidates_id: Option, /// Size of the validator candidates `Table`. pub validator_candidates_size: Option, diff --git a/crates/sui-graphql-rpc/src/types/zklogin_verify_signature.rs b/crates/iota-graphql-rpc/src/types/zklogin_verify_signature.rs similarity index 94% rename from crates/sui-graphql-rpc/src/types/zklogin_verify_signature.rs rename to crates/iota-graphql-rpc/src/types/zklogin_verify_signature.rs index 1704a5e40a9..6c0335bada6 100644 --- a/crates/sui-graphql-rpc/src/types/zklogin_verify_signature.rs +++ b/crates/iota-graphql-rpc/src/types/zklogin_verify_signature.rs @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_graphql::*; use im::hashmap::HashMap as ImHashMap; -use shared_crypto::intent::{ - AppId, Intent, IntentMessage, IntentScope, IntentVersion, PersonalMessage, -}; -use sui_types::{ +use iota_types::{ authenticator_state::{ActiveJwk, AuthenticatorStateInner}, crypto::ToFromBytes, dynamic_field::{DynamicFieldType, Field}, signature::{AuthenticatorTrait, GenericSignature, VerifyParams}, transaction::TransactionData, - TypeTag, SUI_AUTHENTICATOR_STATE_ADDRESS, + TypeTag, IOTA_AUTHENTICATOR_STATE_ADDRESS, +}; +use shared_crypto::intent::{ + AppId, Intent, IntentMessage, IntentScope, IntentVersion, PersonalMessage, }; use tracing::warn; @@ -23,7 +24,7 @@ use crate::{ base64::Base64, dynamic_field::{DynamicField, DynamicFieldName}, epoch::Epoch, - sui_address::SuiAddress, + iota_address::IotaAddress, type_filter::ExactTypeFilter, }, }; @@ -55,7 +56,7 @@ pub(crate) async fn verify_zklogin_signature( bytes: Base64, signature: Base64, intent_scope: ZkLoginIntentScope, - author: SuiAddress, + author: IotaAddress, ) -> Result { // get current epoch from db. let Some(curr_epoch) = Epoch::query(ctx, None, None).await? else { @@ -82,7 +83,7 @@ pub(crate) async fn verify_zklogin_signature( // fetch on-chain JWKs from dynamic field of system object. let df = DynamicField::query( ctx.data_unchecked(), - SUI_AUTHENTICATOR_STATE_ADDRESS.into(), + IOTA_AUTHENTICATOR_STATE_ADDRESS.into(), None, DynamicFieldName { type_: ExactTypeFilter(TypeTag::U64), @@ -122,7 +123,7 @@ pub(crate) async fn verify_zklogin_signature( ZkLoginIntentScope::TransactionData => { let tx_data: TransactionData = bcs::from_bytes(&bytes) .map_err(|_| Error::Client("Invalid tx data bytes".to_string()))?; - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data.clone()); let tx_sender = tx_data.execution_parts().1; if tx_sender != author.into() { return Err(Error::Client("Tx sender mismatch author".to_string())); @@ -149,7 +150,7 @@ pub(crate) async fn verify_zklogin_signature( Intent { scope: IntentScope::PersonalMessage, version: IntentVersion::V0, - app_id: AppId::Sui, + app_id: AppId::Iota, }, data, ); diff --git a/crates/sui-graphql-rpc/tests/e2e_tests.rs b/crates/iota-graphql-rpc/tests/e2e_tests.rs similarity index 92% rename from crates/sui-graphql-rpc/tests/e2e_tests.rs rename to crates/iota-graphql-rpc/tests/e2e_tests.rs index ca945c5a3bc..2cd567618b4 100644 --- a/crates/sui-graphql-rpc/tests/e2e_tests.rs +++ b/crates/iota-graphql-rpc/tests/e2e_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[cfg(feature = "pg_integration")] @@ -6,21 +7,21 @@ mod tests { use std::{sync::Arc, time::Duration}; use fastcrypto::encoding::{Base64, Encoding}; - use rand::{rngs::StdRng, SeedableRng}; - use serde_json::json; - use serial_test::serial; - use simulacrum::Simulacrum; - use sui_graphql_rpc::{ + use iota_graphql_rpc::{ client::{simple_client::GraphqlQueryVariable, ClientError}, config::ConnectionConfig, test_infra::cluster::DEFAULT_INTERNAL_DATA_SOURCE_PORT, }; - use sui_types::{ + use iota_types::{ digests::ChainIdentifier, gas_coin::GAS, transaction::{CallArg, ObjectArg, TransactionDataAPI}, - DEEPBOOK_ADDRESS, SUI_FRAMEWORK_ADDRESS, SUI_FRAMEWORK_PACKAGE_ID, + DEEPBOOK_ADDRESS, IOTA_FRAMEWORK_ADDRESS, IOTA_FRAMEWORK_PACKAGE_ID, }; + use rand::{rngs::StdRng, SeedableRng}; + use serde_json::json; + use serial_test::serial; + use simulacrum::Simulacrum; use tokio::time::sleep; #[tokio::test] @@ -33,7 +34,7 @@ mod tests { let connection_config = ConnectionConfig::ci_integration_test_cfg(); let cluster = - sui_graphql_rpc::test_infra::cluster::start_cluster(connection_config, None).await; + iota_graphql_rpc::test_infra::cluster::start_cluster(connection_config, None).await; cluster .wait_for_checkpoint_catchup(0, Duration::from_secs(10)) @@ -52,7 +53,7 @@ mod tests { let chain_id_actual = cluster .validator_fullnode_handle .fullnode_handle - .sui_client + .iota_client .read_api() .get_chain_identifier() .await @@ -86,7 +87,7 @@ mod tests { chain_id_actual ); let connection_config = ConnectionConfig::ci_integration_test_cfg(); - let cluster = sui_graphql_rpc::test_infra::cluster::serve_executor( + let cluster = iota_graphql_rpc::test_infra::cluster::serve_executor( connection_config, DEFAULT_INTERNAL_DATA_SOURCE_PORT, Arc::new(sim), @@ -121,7 +122,7 @@ mod tests { sim.create_checkpoint(); let connection_config = ConnectionConfig::ci_integration_test_cfg(); - let cluster = sui_graphql_rpc::test_infra::cluster::serve_executor( + let cluster = iota_graphql_rpc::test_infra::cluster::serve_executor( connection_config, DEFAULT_INTERNAL_DATA_SOURCE_PORT, Arc::new(sim), @@ -166,7 +167,7 @@ mod tests { sim.create_checkpoint(); let connection_config = ConnectionConfig::ci_integration_test_cfg(); - let cluster = sui_graphql_rpc::test_infra::cluster::serve_executor( + let cluster = iota_graphql_rpc::test_infra::cluster::serve_executor( connection_config, DEFAULT_INTERNAL_DATA_SOURCE_PORT, Arc::new(sim), @@ -182,12 +183,12 @@ mod tests { let variables = vec![ GraphqlQueryVariable { name: "framework_addr".to_string(), - ty: "SuiAddress!".to_string(), + ty: "IotaAddress!".to_string(), value: json!("0x2"), }, GraphqlQueryVariable { name: "deepbook_addr".to_string(), - ty: "SuiAddress!".to_string(), + ty: "IotaAddress!".to_string(), value: json!("0xdee9"), }, ]; @@ -207,7 +208,7 @@ mod tests { .unwrap() .as_str() .unwrap(), - SUI_FRAMEWORK_ADDRESS.to_canonical_string(true) + IOTA_FRAMEWORK_ADDRESS.to_canonical_string(true) ); assert_eq!( data.get("obj2") @@ -222,17 +223,17 @@ mod tests { let bad_variables = vec![ GraphqlQueryVariable { name: "framework_addr".to_string(), - ty: "SuiAddress!".to_string(), + ty: "IotaAddress!".to_string(), value: json!("0x2"), }, GraphqlQueryVariable { name: "deepbook_addr".to_string(), - ty: "SuiAddress!".to_string(), + ty: "IotaAddress!".to_string(), value: json!("0xdee9"), }, GraphqlQueryVariable { name: "deepbook_addr".to_string(), - ty: "SuiAddress!".to_string(), + ty: "IotaAddress!".to_string(), value: json!("0xdee96666666"), }, ]; @@ -246,17 +247,17 @@ mod tests { let bad_variables = vec![ GraphqlQueryVariable { name: "framework_addr".to_string(), - ty: "SuiAddress!".to_string(), + ty: "IotaAddress!".to_string(), value: json!("0x2"), }, GraphqlQueryVariable { name: "deepbook_addr".to_string(), - ty: "SuiAddress!".to_string(), + ty: "IotaAddress!".to_string(), value: json!("0xdee9"), }, GraphqlQueryVariable { name: "deepbook_addr".to_string(), - ty: "SuiAddressP!".to_string(), + ty: "IotaAddressP!".to_string(), value: json!("0xdee9"), }, ]; @@ -270,27 +271,27 @@ mod tests { let bad_variables = vec![ GraphqlQueryVariable { name: "framework addr".to_string(), - ty: "SuiAddress!".to_string(), + ty: "IotaAddress!".to_string(), value: json!("0x2"), }, GraphqlQueryVariable { name: " deepbook_addr".to_string(), - ty: "SuiAddress!".to_string(), + ty: "IotaAddress!".to_string(), value: json!("0xdee9"), }, GraphqlQueryVariable { name: "4deepbook_addr".to_string(), - ty: "SuiAddressP!".to_string(), + ty: "IotaAddressP!".to_string(), value: json!("0xdee9"), }, GraphqlQueryVariable { name: "".to_string(), - ty: "SuiAddress!".to_string(), + ty: "IotaAddress!".to_string(), value: json!("0xdee9"), }, GraphqlQueryVariable { name: " ".to_string(), - ty: "SuiAddress!".to_string(), + ty: "IotaAddress!".to_string(), value: json!("0xdee9"), }, ]; @@ -322,7 +323,7 @@ mod tests { let connection_config = ConnectionConfig::ci_integration_test_cfg(); let cluster = - sui_graphql_rpc::test_infra::cluster::start_cluster(connection_config, None).await; + iota_graphql_rpc::test_infra::cluster::start_cluster(connection_config, None).await; let addresses = cluster.validator_fullnode_handle.wallet.get_addresses(); @@ -332,7 +333,7 @@ mod tests { .validator_fullnode_handle .test_transaction_builder() .await - .transfer_sui(Some(1_000), recipient) + .transfer_iota(Some(1_000), recipient) .build(); let signed_tx = cluster .validator_fullnode_handle @@ -423,7 +424,7 @@ mod tests { let connection_config = ConnectionConfig::ci_integration_test_cfg(); let cluster = - sui_graphql_rpc::test_infra::cluster::start_cluster(connection_config, None).await; + iota_graphql_rpc::test_infra::cluster::start_cluster(connection_config, None).await; // wait for epoch to be indexed, so that current epoch and JWK are populated in // db. @@ -456,7 +457,7 @@ mod tests { }, GraphqlQueryVariable { name: "author".to_string(), - ty: "SuiAddress!".to_string(), + ty: "IotaAddress!".to_string(), value: json!(author), }, ]; @@ -491,7 +492,7 @@ mod tests { }, GraphqlQueryVariable { name: "author".to_string(), - ty: "SuiAddress!".to_string(), + ty: "IotaAddress!".to_string(), value: json!(author), }, ]; @@ -518,7 +519,7 @@ mod tests { let connection_config = ConnectionConfig::ci_integration_test_cfg(); let cluster = - sui_graphql_rpc::test_infra::cluster::start_cluster(connection_config, None).await; + iota_graphql_rpc::test_infra::cluster::start_cluster(connection_config, None).await; let addresses = cluster.validator_fullnode_handle.wallet.get_addresses(); @@ -528,7 +529,7 @@ mod tests { .validator_fullnode_handle .test_transaction_builder() .await - .transfer_sui(Some(1_000), recipient) + .transfer_iota(Some(1_000), recipient) .build(); let tx_bytes = Base64::encode(bcs::to_bytes(&tx).unwrap()); @@ -613,7 +614,7 @@ mod tests { let connection_config = ConnectionConfig::ci_integration_test_cfg(); let cluster = - sui_graphql_rpc::test_infra::cluster::start_cluster(connection_config, None).await; + iota_graphql_rpc::test_infra::cluster::start_cluster(connection_config, None).await; let addresses = cluster.validator_fullnode_handle.wallet.get_addresses(); @@ -622,7 +623,7 @@ mod tests { .validator_fullnode_handle .test_transaction_builder() .await - .transfer_sui(Some(1_000), recipient) + .transfer_iota(Some(1_000), recipient) .build(); let tx_kind_bytes = Base64::encode(bcs::to_bytes(&tx.into_kind()).unwrap()); @@ -684,7 +685,7 @@ mod tests { let connection_config = ConnectionConfig::ci_integration_test_cfg(); let cluster = - sui_graphql_rpc::test_infra::cluster::start_cluster(connection_config, None).await; + iota_graphql_rpc::test_infra::cluster::start_cluster(connection_config, None).await; let addresses = cluster.validator_fullnode_handle.wallet.get_addresses(); @@ -703,7 +704,7 @@ mod tests { .await // A split coin that goes nowhere -> execution failure .move_call( - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, "coin", "split", vec![ @@ -773,7 +774,7 @@ mod tests { let connection_config = ConnectionConfig::ci_integration_test_cfg(); let cluster = - sui_graphql_rpc::test_infra::cluster::start_cluster(connection_config, None).await; + iota_graphql_rpc::test_infra::cluster::start_cluster(connection_config, None).await; cluster .validator_fullnode_handle @@ -811,7 +812,7 @@ mod tests { ); } - use sui_graphql_rpc::server::builder::tests::*; + use iota_graphql_rpc::server::builder::tests::*; #[tokio::test] #[serial] diff --git a/crates/sui-graphql-rpc/tests/examples_validation_tests.rs b/crates/iota-graphql-rpc/tests/examples_validation_tests.rs similarity index 96% rename from crates/sui-graphql-rpc/tests/examples_validation_tests.rs rename to crates/iota-graphql-rpc/tests/examples_validation_tests.rs index 35f22041289..61547280bc4 100644 --- a/crates/sui-graphql-rpc/tests/examples_validation_tests.rs +++ b/crates/iota-graphql-rpc/tests/examples_validation_tests.rs @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[cfg(feature = "pg_integration")] mod tests { use std::{cmp::max, path::PathBuf, sync::Arc}; - use rand::{rngs::StdRng, SeedableRng}; - use serial_test::serial; - use simulacrum::Simulacrum; - use sui_graphql_rpc::{ + use iota_graphql_rpc::{ config::{ConnectionConfig, Limits}, examples::{load_examples, ExampleQuery, ExampleQueryGroup}, test_infra::cluster::{ExecutorCluster, DEFAULT_INTERNAL_DATA_SOURCE_PORT}, }; + use rand::{rngs::StdRng, SeedableRng}; + use serial_test::serial; + use simulacrum::Simulacrum; fn bad_examples() -> ExampleQueryGroup { ExampleQueryGroup { @@ -108,7 +109,7 @@ mod tests { let connection_config = ConnectionConfig::ci_integration_test_cfg(); - let cluster = sui_graphql_rpc::test_infra::cluster::serve_executor( + let cluster = iota_graphql_rpc::test_infra::cluster::serve_executor( connection_config, DEFAULT_INTERNAL_DATA_SOURCE_PORT, Arc::new(sim), @@ -173,7 +174,7 @@ mod tests { let connection_config = ConnectionConfig::ci_integration_test_cfg(); - let cluster = sui_graphql_rpc::test_infra::cluster::serve_executor( + let cluster = iota_graphql_rpc::test_infra::cluster::serve_executor( connection_config, DEFAULT_INTERNAL_DATA_SOURCE_PORT, Arc::new(sim), diff --git a/crates/iota-graphql-rpc/tests/snapshot_tests.rs b/crates/iota-graphql-rpc/tests/snapshot_tests.rs new file mode 100644 index 00000000000..dda5e4c28ee --- /dev/null +++ b/crates/iota-graphql-rpc/tests/snapshot_tests.rs @@ -0,0 +1,20 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{fs::write, path::PathBuf}; + +use insta::assert_snapshot; +use iota_graphql_rpc::server::builder::export_schema; + +#[test] +fn test_schema_sdl_export() { + let sdl = export_schema(); + + // update the current schema file + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.extend(["schema", "current_progress_schema.graphql"]); + write(path, &sdl).unwrap(); + + assert_snapshot!(sdl); +} diff --git a/crates/sui-graphql-rpc/tests/snapshots/snapshot_tests__schema_sdl_export.snap b/crates/iota-graphql-rpc/tests/snapshots/snapshot_tests__schema_sdl_export.snap similarity index 91% rename from crates/sui-graphql-rpc/tests/snapshots/snapshot_tests__schema_sdl_export.snap rename to crates/iota-graphql-rpc/tests/snapshots/snapshot_tests__schema_sdl_export.snap index 784b091d520..752ce4a67ed 100644 --- a/crates/sui-graphql-rpc/tests/snapshots/snapshot_tests__schema_sdl_export.snap +++ b/crates/iota-graphql-rpc/tests/snapshots/snapshot_tests__schema_sdl_export.snap @@ -1,10 +1,10 @@ --- -source: crates/sui-graphql-rpc/tests/snapshot_tests.rs +source: crates/iota-graphql-rpc/tests/snapshot_tests.rs expression: sdl --- type ActiveJwk { """ - The string (Issuing Authority) that identifies the OIDC provider. + The string (Isiotang Authority) that identifies the OIDC provider. """ iss: String! """ @@ -66,14 +66,14 @@ type ActiveJwkEdge { The 32-byte address that is an account address (corresponding to a public key). """ type Address implements IOwner { - address: SuiAddress! + address: IotaAddress! """ Objects owned by this address, optionally `filter`-ed. """ objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection! """ Total balance of all coins with marker type owned by this address. If type is not supplied, - it defaults to `0x2::sui::SUI`. + it defaults to `0x2::iota::IOTA`. """ balance(type: String): Balance """ @@ -83,22 +83,22 @@ type Address implements IOwner { """ The coin objects for this address. - `type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`. + `type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`. """ coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection! """ - The `0x3::staking_pool::StakedSui` objects owned by this address. + The `0x3::staking_pool::StakedIota` objects owned by this address. """ - stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection! + stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection! """ The domain explicitly configured as the default domain pointing to this address. """ - defaultSuinsName(format: DomainFormat): String + defaultIotansName(format: DomainFormat): String """ - The SuinsRegistration NFTs owned by this address. These grant the owner the capability to + The IotansRegistration NFTs owned by this address. These grant the owner the capability to manage the associated domain. """ - suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection! + iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection! """ Similar behavior to the `transactionBlocks` in Query but supporting the additional `AddressTransactionBlockRelationship` filter, which defaults to `SIGN`. @@ -214,7 +214,7 @@ The total balance for a particular coin type. """ type Balance { """ - Coin type for the balance, such as 0x2::sui::SUI + Coin type for the balance, such as 0x2::iota::IOTA """ coinType: MoveType! """ @@ -236,7 +236,7 @@ type BalanceChange { """ owner: Owner """ - The inner type of the coin whose balance has changed (e.g. `0x2::sui::SUI`). + The inner type of the coin whose balance has changed (e.g. `0x2::iota::IOTA`). """ coinType: MoveType """ @@ -331,20 +331,20 @@ type ChangeEpochTransaction { """ protocolVersion: Int! """ - The total amount of gas charged for storage during the previous epoch (in MIST). + The total amount of gas charged for storage during the previous epoch (in MICROS). """ storageCharge: BigInt! """ - The total amount of gas charged for computation during the previous epoch (in MIST). + The total amount of gas charged for computation during the previous epoch (in MICROS). """ computationCharge: BigInt! """ - The SUI returned to transaction senders for cleaning up objects (in MIST). + The IOTA returned to transaction senders for cleaning up objects (in MICROS). """ storageRebate: BigInt! """ The total gas retained from storage fees, that will not be returned by storage rebates when - the relevant objects are cleaned up (in MIST). + the relevant objects are cleaned up (in MICROS). """ nonRefundableStorageFee: BigInt! """ @@ -450,14 +450,14 @@ input CheckpointId { Some 0x2::coin::Coin Move object. """ type Coin implements IMoveObject & IObject & IOwner { - address: SuiAddress! + address: IotaAddress! """ Objects owned by this object, optionally `filter`-ed. """ objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection! """ Total balance of all coins with marker type owned by this object. If type is not supplied, - it defaults to `0x2::sui::SUI`. + it defaults to `0x2::iota::IOTA`. """ balance(type: String): Balance """ @@ -467,22 +467,22 @@ type Coin implements IMoveObject & IObject & IOwner { """ The coin objects for this object. - `type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`. + `type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`. """ coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection! """ - The `0x3::staking_pool::StakedSui` objects owned by this object. + The `0x3::staking_pool::StakedIota` objects owned by this object. """ - stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection! + stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection! """ The domain explicitly configured as the default domain pointing to this object. """ - defaultSuinsName(format: DomainFormat): String + defaultIotansName(format: DomainFormat): String """ - The SuinsRegistration NFTs owned by this object. These grant the owner the capability to + The IotansRegistration NFTs owned by this object. These grant the owner the capability to manage the associated domain. """ - suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection! + iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection! version: Int! """ The current status of the object as read from the off-chain store. The possible states are: @@ -507,7 +507,7 @@ type Coin implements IMoveObject & IObject & IOwner { """ previousTransactionBlock: TransactionBlock """ - The amount of SUI we would rebate if this object gets deleted or mutated. This number is + The amount of IOTA we would rebate if this object gets deleted or mutated. This number is recalculated based on the present storage gas price. """ storageRebate: BigInt @@ -527,7 +527,7 @@ type Coin implements IMoveObject & IObject & IOwner { contents: MoveValue """ Determines whether a transaction can transfer this object, using the TransferObjects - transaction command or `sui::transfer::public_transfer`, both of which require the object to + transaction command or `iota::transfer::public_transfer`, both of which require the object to have the `key` and `store` abilities. """ hasPublicTransfer: Boolean! @@ -609,14 +609,14 @@ type CoinEdge { The metadata for a coin type. """ type CoinMetadata implements IMoveObject & IObject & IOwner { - address: SuiAddress! + address: IotaAddress! """ Objects owned by this object, optionally `filter`-ed. """ objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection! """ Total balance of all coins with marker type owned by this object. If type is not supplied, - it defaults to `0x2::sui::SUI`. + it defaults to `0x2::iota::IOTA`. """ balance(type: String): Balance """ @@ -626,22 +626,22 @@ type CoinMetadata implements IMoveObject & IObject & IOwner { """ The coin objects for this object. - `type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`. + `type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`. """ coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection! """ - The `0x3::staking_pool::StakedSui` objects owned by this object. + The `0x3::staking_pool::StakedIota` objects owned by this object. """ - stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection! + stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection! """ The domain explicitly configured as the default domain pointing to this object. """ - defaultSuinsName(format: DomainFormat): String + defaultIotansName(format: DomainFormat): String """ - The SuinsRegistration NFTs owned by this object. These grant the owner the capability to + The IotansRegistration NFTs owned by this object. These grant the owner the capability to manage the associated domain. """ - suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection! + iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection! version: Int! """ The current status of the object as read from the off-chain store. The possible states are: @@ -666,7 +666,7 @@ type CoinMetadata implements IMoveObject & IObject & IOwner { """ previousTransactionBlock: TransactionBlock """ - The amount of SUI we would rebate if this object gets deleted or mutated. This number is + The amount of IOTA we would rebate if this object gets deleted or mutated. This number is recalculated based on the present storage gas price. """ storageRebate: BigInt @@ -686,7 +686,7 @@ type CoinMetadata implements IMoveObject & IObject & IOwner { contents: MoveValue """ Determines whether a transaction can transfer this object, using the TransferObjects - transaction command or `sui::transfer::public_transfer`, both of which require the object to + transaction command or `iota::transfer::public_transfer`, both of which require the object to have the `key` and `store` abilities. """ hasPublicTransfer: Boolean! @@ -874,7 +874,7 @@ fields: 1) Dynamic Fields can store any value that has the `store` ability, however an object stored in this kind of field will be considered wrapped and will not be accessible directly via its ID by external tools (explorers, wallets, etc) accessing storage. -2) Dynamic Object Fields values must be Sui objects (have the `key` and `store` +2) Dynamic Object Fields values must be Iota objects (have the `key` and `store` abilities, and id: UID as the first field), but will still be directly accessible off-chain via their object ID after being attached. """ @@ -979,7 +979,7 @@ type EndOfEpochTransactionKindEdge { } """ -Operation of the Sui network is temporally partitioned into non-overlapping epochs, +Operation of the Iota network is temporally partitioned into non-overlapping epochs, and the network aims to keep epochs roughly the same duration as each other. During a particular epoch the following data is fixed: @@ -1017,11 +1017,11 @@ type Epoch { """ totalTransactions: Int """ - The total amount of gas fees (in MIST) that were paid in this epoch. + The total amount of gas fees (in MICROS) that were paid in this epoch. """ totalGasFees: BigInt """ - The total MIST rewarded as stake. + The total MICROS rewarded as stake. """ totalStakeRewards: BigInt """ @@ -1054,7 +1054,7 @@ type Epoch { """ protocolConfigs: ProtocolConfigs! """ - SUI set aside to account for objects stored on-chain, at the start of the epoch. + IOTA set aside to account for objects stored on-chain, at the start of the epoch. This is also used for storage rebates. """ storageFund: StorageFund @@ -1064,7 +1064,7 @@ type Epoch { """ safeMode: SafeMode """ - The value of the `version` field of `0x5`, the `0x3::sui::SuiSystemState` object. This + The value of the `version` field of `0x5`, the `0x3::iota::IotaSystemState` object. This version changes whenever the fields contained in the system state object (held in a dynamic field attached to `0x5`) change. """ @@ -1168,7 +1168,7 @@ type EventEdge { } input EventFilter { - sender: SuiAddress + sender: IotaAddress transactionDigest: String """ Events emitted by a particular module. An event is emitted by a @@ -1186,7 +1186,7 @@ input EventFilter { Generic types can be queried by either the generic type name, e.g. `0x2::coin::Coin`, or by the full type name, such as - `0x2::coin::Coin<0x2::sui::SUI>`. + `0x2::coin::Coin<0x2::iota::IOTA>`. """ eventType: String } @@ -1239,7 +1239,7 @@ enum Feature { """ DYNAMIC_FIELDS """ - SuiNS name and reverse name look-up. + IotaNS name and reverse name look-up. """ NAME_SERVICE """ @@ -1270,22 +1270,22 @@ Breakdown of gas costs in effects. """ type GasCostSummary { """ - Gas paid for executing this transaction (in MIST). + Gas paid for executing this transaction (in MICROS). """ computationCost: BigInt """ - Gas paid for the data stored on-chain by this transaction (in MIST). + Gas paid for the data stored on-chain by this transaction (in MICROS). """ storageCost: BigInt """ Part of storage cost that can be reclaimed by cleaning up data created by this transaction (when objects are deleted or an object is modified, which is treated as a deletion followed - by a creation) (in MIST). + by a creation) (in MICROS). """ storageRebate: BigInt """ Part of storage cost that is not reclaimed when data created by this transaction is cleaned - up (in MIST). + up (in MICROS). """ nonRefundableStorageFee: BigInt } @@ -1312,7 +1312,7 @@ type GasInput { gasPayment(first: Int, after: String, last: Int, before: String): ObjectConnection! """ An unsigned integer specifying the number of native tokens per gas unit this transaction - will pay (in MIST). + will pay (in MICROS). """ gasPrice: BigInt """ @@ -1342,7 +1342,7 @@ interface IMoveObject { """ contents: MoveValue """ - Determines whether a transaction can transfer this object, using the TransferObjects transaction command or `sui::transfer::public_transfer`, both of which require the object to have the `key` and `store` abilities. + Determines whether a transaction can transfer this object, using the TransferObjects transaction command or `iota::transfer::public_transfer`, both of which require the object to have the `key` and `store` abilities. """ hasPublicTransfer: Boolean! """ @@ -1413,13 +1413,13 @@ object. The same address can only refer to an account or an object, never both, possible to know which up-front. """ interface IOwner { - address: SuiAddress! + address: IotaAddress! """ Objects owned by this object or address, optionally `filter`-ed. """ objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection! """ - Total balance of all coins with marker type owned by this object or address. If type is not supplied, it defaults to `0x2::sui::SUI`. + Total balance of all coins with marker type owned by this object or address. If type is not supplied, it defaults to `0x2::iota::IOTA`. """ balance(type: String): Balance """ @@ -1429,21 +1429,21 @@ interface IOwner { """ The coin objects for this object or address. - `type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`. + `type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`. """ coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection! """ - The `0x3::staking_pool::StakedSui` objects owned by this object or address. + The `0x3::staking_pool::StakedIota` objects owned by this object or address. """ - stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection! + stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection! """ The domain explicitly configured as the default domain pointing to this object or address. """ - defaultSuinsName(format: DomainFormat): String + defaultIotansName(format: DomainFormat): String """ - The SuinsRegistration NFTs owned by this object or address. These grant the owner the capability to manage the associated domain. + The IotansRegistration NFTs owned by this object or address. These grant the owner the capability to manage the associated domain. """ - suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection! + iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection! } """ @@ -1477,11 +1477,11 @@ type Linkage { """ The ID on-chain of the first version of the dependency. """ - originalId: SuiAddress! + originalId: IotaAddress! """ The ID on-chain of the version of the dependency that this package depends on. """ - upgradedId: SuiAddress! + upgradedId: IotaAddress! """ The version of the dependency that this package depends on. """ @@ -1517,7 +1517,7 @@ type MergeCoinsTransaction { } """ -Abilities are keywords in Sui Move that define how types behave at the compiler level. +Abilities are keywords in Iota Move that define how types behave at the compiler level. """ enum MoveAbility { """ @@ -1545,7 +1545,7 @@ type MoveCallTransaction { """ The storage ID of the package the function being called is defined in. """ - package: SuiAddress! + package: IotaAddress! """ The name of the module the function being called is defined in. """ @@ -1572,9 +1572,9 @@ type MoveCallTransaction { The contents of a Move Value, corresponding to the following recursive type: type MoveData = - { Address: SuiAddress } - | { UID: SuiAddress } - | { ID: SuiAddress } + { Address: IotaAddress } + | { UID: IotaAddress } + | { ID: IotaAddress } | { Bool: bool } | { Number: BigInt } | { String: string } @@ -1746,14 +1746,14 @@ The representation of an object as a Move Object, which exposes additional infor (content, module that governs it, version, is transferrable, etc.) about this object. """ type MoveObject implements IMoveObject & IObject & IOwner { - address: SuiAddress! + address: IotaAddress! """ Objects owned by this object, optionally `filter`-ed. """ objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection! """ Total balance of all coins with marker type owned by this object. If type is not supplied, - it defaults to `0x2::sui::SUI`. + it defaults to `0x2::iota::IOTA`. """ balance(type: String): Balance """ @@ -1763,22 +1763,22 @@ type MoveObject implements IMoveObject & IObject & IOwner { """ The coin objects for this object. - `type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`. + `type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`. """ coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection! """ - The `0x3::staking_pool::StakedSui` objects owned by this object. + The `0x3::staking_pool::StakedIota` objects owned by this object. """ - stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection! + stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection! """ The domain explicitly configured as the default domain pointing to this object. """ - defaultSuinsName(format: DomainFormat): String + defaultIotansName(format: DomainFormat): String """ - The SuinsRegistration NFTs owned by this object. These grant the owner the capability to + The IotansRegistration NFTs owned by this object. These grant the owner the capability to manage the associated domain. """ - suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection! + iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection! version: Int! """ The current status of the object as read from the off-chain store. The possible states are: @@ -1803,7 +1803,7 @@ type MoveObject implements IMoveObject & IObject & IOwner { """ previousTransactionBlock: TransactionBlock """ - The amount of SUI we would rebate if this object gets deleted or mutated. This number is + The amount of IOTA we would rebate if this object gets deleted or mutated. This number is recalculated based on the present storage gas price. """ storageRebate: BigInt @@ -1823,7 +1823,7 @@ type MoveObject implements IMoveObject & IObject & IOwner { contents: MoveValue """ Determines whether a transaction can transfer this object, using the TransferObjects - transaction command or `sui::transfer::public_transfer`, both of which require the object to + transaction command or `iota::transfer::public_transfer`, both of which require the object to have the `key` and `store` abilities. """ hasPublicTransfer: Boolean! @@ -1864,17 +1864,17 @@ type MoveObject implements IMoveObject & IObject & IOwner { """ asCoin: Coin """ - Attempts to convert the Move object into a `0x3::staking_pool::StakedSui`. + Attempts to convert the Move object into a `0x3::staking_pool::StakedIota`. """ - asStakedSui: StakedSui + asStakedIota: StakedIota """ Attempts to convert the Move object into a `0x2::coin::CoinMetadata`. """ asCoinMetadata: CoinMetadata """ - Attempts to convert the Move object into a `SuinsRegistration` object. + Attempts to convert the Move object into a `IotansRegistration` object. """ - asSuinsRegistration: SuinsRegistration + asIotansRegistration: IotansRegistration } type MoveObjectConnection { @@ -1911,7 +1911,7 @@ A MovePackage is a kind of Move object that represents code that has been publis It exposes information about its modules, type definitions, functions, and dependencies. """ type MovePackage implements IObject & IOwner { - address: SuiAddress! + address: IotaAddress! """ Objects owned by this package, optionally `filter`-ed. @@ -1921,7 +1921,7 @@ type MovePackage implements IObject & IOwner { objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection! """ Total balance of all coins with marker type owned by this package. If type is not supplied, - it defaults to `0x2::sui::SUI`. + it defaults to `0x2::iota::IOTA`. Note that coins owned by a package are inaccessible, because packages are immutable and cannot be owned by an address. @@ -1937,31 +1937,31 @@ type MovePackage implements IObject & IOwner { """ The coin objects owned by this package. - `type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`. + `type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`. Note that coins owned by a package are inaccessible, because packages are immutable and cannot be owned by an address. """ coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection! """ - The `0x3::staking_pool::StakedSui` objects owned by this package. + The `0x3::staking_pool::StakedIota` objects owned by this package. Note that objects owned by a package are inaccessible, because packages are immutable and cannot be owned by an address. """ - stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection! + stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection! """ The domain explicitly configured as the default domain pointing to this object. """ - defaultSuinsName(format: DomainFormat): String + defaultIotansName(format: DomainFormat): String """ - The SuinsRegistration NFTs owned by this package. These grant the owner the capability to + The IotansRegistration NFTs owned by this package. These grant the owner the capability to manage the associated domain. Note that objects owned by a package are inaccessible, because packages are immutable and cannot be owned by an address. """ - suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection! + iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection! version: Int! """ The current status of the object as read from the off-chain store. The possible states are: @@ -1987,7 +1987,7 @@ type MovePackage implements IObject & IOwner { """ previousTransactionBlock: TransactionBlock """ - The amount of SUI we would rebate if this object gets deleted or mutated. This number is + The amount of IOTA we would rebate if this object gets deleted or mutated. This number is recalculated based on the present storage gas price. Note that packages cannot be deleted or mutated, so this number is provided purely for @@ -2229,7 +2229,7 @@ enum MoveVisibility { } """ -Mutations are used to write to the Sui network. +Mutations are used to write to the Iota network. """ type Mutation { """ @@ -2252,19 +2252,19 @@ type Mutation { } """ -An object in Sui is a package (set of Move bytecode modules) or object (typed data structure +An object in Iota is a package (set of Move bytecode modules) or object (typed data structure with fields) with additional metadata detailing its id, version, transaction digest, owner field indicating how this object can be accessed. """ type Object implements IObject & IOwner { - address: SuiAddress! + address: IotaAddress! """ Objects owned by this object, optionally `filter`-ed. """ objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection! """ Total balance of all coins with marker type owned by this object. If type is not supplied, - it defaults to `0x2::sui::SUI`. + it defaults to `0x2::iota::IOTA`. """ balance(type: String): Balance """ @@ -2274,22 +2274,22 @@ type Object implements IObject & IOwner { """ The coin objects for this object. - `type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`. + `type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`. """ coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection! """ - The `0x3::staking_pool::StakedSui` objects owned by this object. + The `0x3::staking_pool::StakedIota` objects owned by this object. """ - stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection! + stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection! """ The domain explicitly configured as the default domain pointing to this object. """ - defaultSuinsName(format: DomainFormat): String + defaultIotansName(format: DomainFormat): String """ - The SuinsRegistration NFTs owned by this object. These grant the owner the capability to + The IotansRegistration NFTs owned by this object. These grant the owner the capability to manage the associated domain. """ - suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection! + iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection! version: Int! """ The current status of the object as read from the off-chain store. The possible states are: @@ -2315,7 +2315,7 @@ type Object implements IObject & IOwner { """ previousTransactionBlock: TransactionBlock """ - The amount of SUI we would rebate if this object gets deleted or mutated. This number is + The amount of IOTA we would rebate if this object gets deleted or mutated. This number is recalculated based on the present storage gas price. """ storageRebate: BigInt @@ -2376,7 +2376,7 @@ type ObjectChange { """ The address of the object that has changed. """ - address: SuiAddress! + address: IotaAddress! """ The contents of the object immediately before the transaction. """ @@ -2470,17 +2470,17 @@ input ObjectFilter { type name. Generic types can be queried by either the generic type name, e.g. `0x2::coin::Coin`, or by - the full type name, such as `0x2::coin::Coin<0x2::sui::SUI>`. + the full type name, such as `0x2::coin::Coin<0x2::iota::IOTA>`. """ type: String """ Filter for live objects by their current owners. """ - owner: SuiAddress + owner: IotaAddress """ Filter for live objects by their IDs. """ - objectIds: [SuiAddress!] + objectIds: [IotaAddress!] """ Filter for live or potentially historical objects by their ID and version. """ @@ -2488,7 +2488,7 @@ input ObjectFilter { } input ObjectKey { - objectId: SuiAddress! + objectId: IotaAddress! version: Int! } @@ -2522,7 +2522,7 @@ input ObjectRef { """ ID of the object. """ - address: SuiAddress! + address: IotaAddress! """ Version or sequence number of the object. """ @@ -2580,7 +2580,7 @@ type OwnedOrImmutable { """ ID of the object being read. """ - address: SuiAddress! + address: IotaAddress! """ Version of the object being read. """ @@ -2597,19 +2597,19 @@ type OwnedOrImmutable { } """ -An Owner is an entity that can own an object. Each Owner is identified by a SuiAddress which +An Owner is an entity that can own an object. Each Owner is identified by a IotaAddress which represents either an Address (corresponding to a public key of an account) or an Object, but never both (it is not known up-front whether a given Owner is an Address or an Object). """ type Owner implements IOwner { - address: SuiAddress! + address: IotaAddress! """ Objects owned by this object or address, optionally `filter`-ed. """ objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection! """ Total balance of all coins with marker type owned by this object or address. If type is not - supplied, it defaults to `0x2::sui::SUI`. + supplied, it defaults to `0x2::iota::IOTA`. """ balance(type: String): Balance """ @@ -2619,22 +2619,22 @@ type Owner implements IOwner { """ The coin objects for this object or address. - `type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`. + `type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`. """ coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection! """ - The `0x3::staking_pool::StakedSui` objects owned by this object or address. + The `0x3::staking_pool::StakedIota` objects owned by this object or address. """ - stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection! + stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection! """ The domain explicitly configured as the default domain pointing to this object or address. """ - defaultSuinsName(format: DomainFormat): String + defaultIotansName(format: DomainFormat): String """ - The SuinsRegistration NFTs owned by this object or address. These grant the owner the + The IotansRegistration NFTs owned by this object or address. These grant the owner the capability to manage the associated domain. """ - suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection! + iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection! asAddress: Address asObject: Object """ @@ -2801,7 +2801,7 @@ type PublishTransaction { """ IDs of the transitive dependencies of the package to be published. """ - dependencies: [SuiAddress!]! + dependencies: [IotaAddress!]! } """ @@ -2849,16 +2849,16 @@ type Query { non-entry functions, and some other checks. Defaults to false. """ dryRunTransactionBlock(txBytes: String!, txMeta: TransactionMetadata, skipChecks: Boolean): DryRunResult! - owner(address: SuiAddress!): Owner + owner(address: IotaAddress!): Owner """ The object corresponding to the given address at the (optionally) given version. When no version is given, the latest version is returned. """ - object(address: SuiAddress!, version: Int): Object + object(address: IotaAddress!, version: Int): Object """ - Look-up an Account by its SuiAddress. + Look-up an Account by its IotaAddress. """ - address(address: SuiAddress!): Address + address(address: IotaAddress!): Address """ Fetch a structured representation of a concrete type, including its layout information. Fails if the type is malformed. @@ -2881,7 +2881,7 @@ type Query { The coin objects that exist in the network. The type field is a string of the inner type of the coin by which to filter (e.g. - `0x2::sui::SUI`). If no type is provided, it will default to `0x2::sui::SUI`. + `0x2::iota::IOTA`). If no type is provided, it will default to `0x2::iota::IOTA`. """ coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection! """ @@ -2906,9 +2906,9 @@ type Query { """ protocolConfig(protocolVersion: Int): ProtocolConfigs! """ - Resolves a SuiNS `domain` name to an address, if it has been bound. + Resolves a IotaNS `domain` name to an address, if it has been bound. """ - resolveSuinsAddress(domain: String!): Address + resolveIotansAddress(domain: String!): Address """ The coin metadata associated with the given coin type. """ @@ -2926,7 +2926,7 @@ type Query { - `intentScope` is an enum that specifies the intent scope to be used to parse bytes. - `author` is the address of the signer of the transaction or personal msg. """ - verifyZkloginSignature(bytes: Base64!, signature: Base64!, intentScope: ZkLoginIntentScope!, author: SuiAddress!): ZkLoginVerifyResult! + verifyZkloginSignature(bytes: Base64!, signature: Base64!, intentScope: ZkLoginIntentScope!, author: IotaAddress!): ZkLoginVerifyResult! } type RandomnessStateCreateTransaction { @@ -2965,7 +2965,7 @@ type Receiving { """ ID of the object being read. """ - address: SuiAddress! + address: IotaAddress! """ Version of the object being read. """ @@ -3098,7 +3098,7 @@ type Shared { A Move object that's shared. """ type SharedInput { - address: SuiAddress! + address: IotaAddress! """ The version that this this object was shared at. """ @@ -3121,7 +3121,7 @@ type SharedObjectDelete { """ ID of the shared object. """ - address: SuiAddress! + address: IotaAddress! """ The version of the shared object that was assigned to this transaction during by consensus, during sequencing. @@ -3141,7 +3141,7 @@ type SharedObjectRead { """ ID of the object being read. """ - address: SuiAddress! + address: IotaAddress! """ Version of the object being read. """ @@ -3195,7 +3195,7 @@ Parameters that control the distribution of the stake subsidy. """ type StakeSubsidy { """ - SUI set aside for stake subsidies -- reduces over time as stake subsidies are paid out over + IOTA set aside for stake subsidies -- reduces over time as stake subsidies are paid out over time. """ balance: BigInt @@ -3221,17 +3221,17 @@ type StakeSubsidy { } """ -Represents a `0x3::staking_pool::StakedSui` Move object on-chain. +Represents a `0x3::staking_pool::StakedIota` Move object on-chain. """ -type StakedSui implements IMoveObject & IObject & IOwner { - address: SuiAddress! +type StakedIota implements IMoveObject & IObject & IOwner { + address: IotaAddress! """ Objects owned by this object, optionally `filter`-ed. """ objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection! """ Total balance of all coins with marker type owned by this object. If type is not supplied, - it defaults to `0x2::sui::SUI`. + it defaults to `0x2::iota::IOTA`. """ balance(type: String): Balance """ @@ -3241,22 +3241,22 @@ type StakedSui implements IMoveObject & IObject & IOwner { """ The coin objects for this object. - `type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`. + `type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`. """ coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection! """ - The `0x3::staking_pool::StakedSui` objects owned by this object. + The `0x3::staking_pool::StakedIota` objects owned by this object. """ - stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection! + stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection! """ The domain explicitly configured as the default domain pointing to this object. """ - defaultSuinsName(format: DomainFormat): String + defaultIotansName(format: DomainFormat): String """ - The SuinsRegistration NFTs owned by this object. These grant the owner the capability to + The IotansRegistration NFTs owned by this object. These grant the owner the capability to manage the associated domain. """ - suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection! + iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection! version: Int! """ The current status of the object as read from the off-chain store. The possible states are: @@ -3281,7 +3281,7 @@ type StakedSui implements IMoveObject & IObject & IOwner { """ previousTransactionBlock: TransactionBlock """ - The amount of SUI we would rebate if this object gets deleted or mutated. This number is + The amount of IOTA we would rebate if this object gets deleted or mutated. This number is recalculated based on the present storage gas price. """ storageRebate: BigInt @@ -3301,7 +3301,7 @@ type StakedSui implements IMoveObject & IObject & IOwner { contents: MoveValue """ Determines whether a transaction can transfer this object, using the TransferObjects - transaction command or `sui::transfer::public_transfer`, both of which require the object to + transaction command or `iota::transfer::public_transfer`, both of which require the object to have the `key` and `store` abilities. """ hasPublicTransfer: Boolean! @@ -3352,9 +3352,9 @@ type StakedSui implements IMoveObject & IObject & IOwner { """ The object id of the validator staking pool this stake belongs to. """ - poolId: SuiAddress + poolId: IotaAddress """ - The SUI that was initially staked. + The IOTA that was initially staked. """ principal: BigInt """ @@ -3372,7 +3372,7 @@ type StakedSui implements IMoveObject & IObject & IOwner { estimatedReward: BigInt } -type StakedSuiConnection { +type StakedIotaConnection { """ Information to aid in pagination. """ @@ -3380,21 +3380,21 @@ type StakedSuiConnection { """ A list of edges. """ - edges: [StakedSuiEdge!]! + edges: [StakedIotaEdge!]! """ A list of nodes. """ - nodes: [StakedSui!]! + nodes: [StakedIota!]! } """ An edge in a connection. """ -type StakedSuiEdge { +type StakedIotaEdge { """ The item at the end of the edge """ - node: StakedSui! + node: StakedIota! """ A cursor for use in pagination """ @@ -3402,7 +3402,7 @@ type StakedSuiEdge { } """ -SUI set aside to account for objects stored on-chain. +IOTA set aside to account for objects stored on-chain. """ type StorageFund { """ @@ -3421,19 +3421,19 @@ type StorageFund { """ -String containing 32B hex-encoded address, with a leading "0x". Leading zeroes can be omitted on input but will always appear in outputs (SuiAddress in output is guaranteed to be 66 characters long). +String containing 32B hex-encoded address, with a leading "0x". Leading zeroes can be omitted on input but will always appear in outputs (IotaAddress in output is guaranteed to be 66 characters long). """ -scalar SuiAddress +scalar IotaAddress -type SuinsRegistration implements IMoveObject & IObject & IOwner { - address: SuiAddress! +type IotansRegistration implements IMoveObject & IObject & IOwner { + address: IotaAddress! """ Objects owned by this object, optionally `filter`-ed. """ objects(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): MoveObjectConnection! """ Total balance of all coins with marker type owned by this object. If type is not supplied, - it defaults to `0x2::sui::SUI`. + it defaults to `0x2::iota::IOTA`. """ balance(type: String): Balance """ @@ -3443,22 +3443,22 @@ type SuinsRegistration implements IMoveObject & IObject & IOwner { """ The coin objects for this object. - `type` is a filter on the coin's type parameter, defaulting to `0x2::sui::SUI`. + `type` is a filter on the coin's type parameter, defaulting to `0x2::iota::IOTA`. """ coins(first: Int, after: String, last: Int, before: String, type: String): CoinConnection! """ - The `0x3::staking_pool::StakedSui` objects owned by this object. + The `0x3::staking_pool::StakedIota` objects owned by this object. """ - stakedSuis(first: Int, after: String, last: Int, before: String): StakedSuiConnection! + stakedIotas(first: Int, after: String, last: Int, before: String): StakedIotaConnection! """ The domain explicitly configured as the default domain pointing to this object. """ - defaultSuinsName(format: DomainFormat): String + defaultIotansName(format: DomainFormat): String """ - The SuinsRegistration NFTs owned by this object. These grant the owner the capability to + The IotansRegistration NFTs owned by this object. These grant the owner the capability to manage the associated domain. """ - suinsRegistrations(first: Int, after: String, last: Int, before: String): SuinsRegistrationConnection! + iotansRegistrations(first: Int, after: String, last: Int, before: String): IotansRegistrationConnection! version: Int! """ The current status of the object as read from the off-chain store. The possible states are: @@ -3483,7 +3483,7 @@ type SuinsRegistration implements IMoveObject & IObject & IOwner { """ previousTransactionBlock: TransactionBlock """ - The amount of SUI we would rebate if this object gets deleted or mutated. This number is + The amount of IOTA we would rebate if this object gets deleted or mutated. This number is recalculated based on the present storage gas price. """ storageRebate: BigInt @@ -3503,7 +3503,7 @@ type SuinsRegistration implements IMoveObject & IObject & IOwner { contents: MoveValue """ Determines whether a transaction can transfer this object, using the TransferObjects - transaction command or `sui::transfer::public_transfer`, both of which require the object to + transaction command or `iota::transfer::public_transfer`, both of which require the object to have the `key` and `store` abilities. """ hasPublicTransfer: Boolean! @@ -3540,12 +3540,12 @@ type SuinsRegistration implements IMoveObject & IObject & IOwner { """ dynamicFields(first: Int, after: String, last: Int, before: String): DynamicFieldConnection! """ - Domain name of the SuinsRegistration object + Domain name of the IotansRegistration object """ domain: String! } -type SuinsRegistrationConnection { +type IotansRegistrationConnection { """ Information to aid in pagination. """ @@ -3553,21 +3553,21 @@ type SuinsRegistrationConnection { """ A list of edges. """ - edges: [SuinsRegistrationEdge!]! + edges: [IotansRegistrationEdge!]! """ A list of nodes. """ - nodes: [SuinsRegistration!]! + nodes: [IotansRegistration!]! } """ An edge in a connection. """ -type SuinsRegistrationEdge { +type IotansRegistrationEdge { """ The item at the end of the edge """ - node: SuinsRegistration! + node: IotansRegistration! """ A cursor for use in pagination """ @@ -3767,10 +3767,10 @@ input TransactionBlockFilter { afterCheckpoint: Int atCheckpoint: Int beforeCheckpoint: Int - signAddress: SuiAddress - recvAddress: SuiAddress - inputObject: SuiAddress - changedObject: SuiAddress + signAddress: IotaAddress + recvAddress: IotaAddress + inputObject: IotaAddress + changedObject: IotaAddress transactionIds: [String!] } @@ -3833,11 +3833,11 @@ gas price, `gasBudget` defaults to the max gas budget and `gasSponsor` defaults to the sender. """ input TransactionMetadata { - sender: SuiAddress + sender: IotaAddress gasPrice: Int gasObjects: [ObjectRef!] gasBudget: Int - gasSponsor: SuiAddress + gasSponsor: IotaAddress } """ @@ -3870,7 +3870,7 @@ type TypeOrigin { """ The storage ID of the package that first defined this type. """ - definingId: SuiAddress! + definingId: IotaAddress! } """ @@ -3921,11 +3921,11 @@ type UpgradeTransaction { """ IDs of the transitive dependencies of the package to be published. """ - dependencies: [SuiAddress!]! + dependencies: [IotaAddress!]! """ ID of the package being upgraded. """ - currentPackage: SuiAddress! + currentPackage: IotaAddress! """ The `UpgradeTicket` authorizing the upgrade. """ @@ -3974,7 +3974,7 @@ type Validator { stakingPool: MoveObject """ The validator's current exchange object. The exchange rate is used to determine - the amount of SUI tokens that each past SUI staker can withdraw in the future. + the amount of IOTA tokens that each past IOTA staker can withdraw in the future. """ exchangeRates: MoveObject """ @@ -3986,9 +3986,9 @@ type Validator { """ stakingPoolActivationEpoch: Int """ - The total number of SUI tokens in this pool. + The total number of IOTA tokens in this pool. """ - stakingPoolSuiBalance: BigInt + stakingPoolIotaBalance: BigInt """ The epoch stake rewards will be added here at the end of each epoch. """ @@ -4004,7 +4004,7 @@ type Validator { """ Pending stake withdrawn during the current epoch, emptied at epoch boundaries. """ - pendingTotalSuiWithdraw: BigInt + pendingTotalIotaWithdraw: BigInt """ Pending pool token withdrawn during the current epoch, emptied at epoch boundaries. """ @@ -4022,7 +4022,7 @@ type Validator { """ commissionRate: Int """ - The total number of SUI tokens in this pool plus + The total number of IOTA tokens in this pool plus the pending stake amount for this epoch. """ nextEpochStake: BigInt @@ -4109,7 +4109,7 @@ type ValidatorSet { """ Object ID of the wrapped object `TableVec` storing the pending active validators. """ - pendingActiveValidatorsId: SuiAddress + pendingActiveValidatorsId: IotaAddress """ Size of the pending active validators table. """ @@ -4119,7 +4119,7 @@ type ValidatorSet { of the corresponding validators. This is needed because a validator's address can potentially change but the object ID of its pool will not. """ - stakingPoolMappingsId: SuiAddress + stakingPoolMappingsId: IotaAddress """ Size of the stake pool mappings `Table`. """ @@ -4127,7 +4127,7 @@ type ValidatorSet { """ Object ID of the `Table` storing the inactive staking pools. """ - inactivePoolsId: SuiAddress + inactivePoolsId: IotaAddress """ Size of the inactive pools `Table`. """ @@ -4135,7 +4135,7 @@ type ValidatorSet { """ Object ID of the `Table` storing the validator candidates. """ - validatorCandidatesId: SuiAddress + validatorCandidatesId: IotaAddress """ Size of the validator candidates `Table`. """ diff --git a/crates/iota-indexer/Cargo.toml b/crates/iota-indexer/Cargo.toml new file mode 100644 index 00000000000..7349db5148a --- /dev/null +++ b/crates/iota-indexer/Cargo.toml @@ -0,0 +1,70 @@ +[package] +name = "iota-indexer" +version.workspace = true +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +async-trait.workspace = true +axum.workspace = true +backoff.workspace = true +bcs.workspace = true +chrono.workspace = true +serde_with.workspace = true +clap.workspace = true +tap.workspace = true +diesel.workspace = true +diesel-derive-enum.workspace = true +futures.workspace = true +itertools.workspace = true +jsonrpsee.workspace = true +prometheus.workspace = true +serde.workspace = true +serde_json.workspace = true +rayon.workspace = true +regex.workspace = true +thiserror.workspace = true +tracing.workspace = true +tokio = { workspace = true, features = ["full"] } +url.workspace = true + +fastcrypto = { workspace = true, features = ["copy_key"] } +mysten-metrics.workspace = true +iota-json.workspace = true +iota-json-rpc.workspace = true +iota-json-rpc-api.workspace = true +iota-json-rpc-types.workspace = true +iota-open-rpc.workspace = true +iota-sdk.workspace = true +iota-types.workspace = true +iota-package-resolver.workspace = true +iota-protocol-config.workspace = true +telemetry-subscribers.workspace = true +iota-rest-api.workspace = true +iota-transaction-builder.workspace = true + +move-core-types.workspace = true +move-bytecode-utils.workspace = true +move-binary-format.workspace = true + +diesel_migrations.workspace = true +cached.workspace = true + +[features] +pg_integration = [] + +[dev-dependencies] +iota-keys.workspace = true +iota-move-build.workspace = true +iota-test-transaction-builder.workspace = true +test-cluster.workspace = true +ntest.workspace = true +criterion.workspace = true +simulacrum.workspace = true + +[[bin]] +name = "iota-indexer" +path = "src/main.rs" diff --git a/crates/iota-indexer/README.md b/crates/iota-indexer/README.md new file mode 100644 index 00000000000..808f053d4a1 --- /dev/null +++ b/crates/iota-indexer/README.md @@ -0,0 +1,61 @@ +Iota indexer is an off-fullnode service to serve data from Iota protocol, including both data directly generated from chain and derivative data. + +## Architecture +![enhanced_FN](https://user-images.githubusercontent.com/106119108/221022505-a1d873c6-60e2-45f1-b2aa-e50192c4dfbb.png) + +## Steps to run locally +### Prerequisites +- install local [Postgres server](https://www.postgresql.org/download/). You can also `brew install postgresql@15` and then add the following to your `~/.zshrc` or `~/.zprofile`, etc: +```sh +export LDFLAGS="-L/opt/homebrew/opt/postgresql@15/lib" +export CPPFLAGS="-I/opt/homebrew/opt/postgresql@15/include" +export PATH="/opt/homebrew/opt/postgresql@15/bin:$PATH" +``` +- make sure you have libpq installed: `brew install libpq`, and in your profile, add `export PATH="/opt/homebrew/opt/libpq/bin:$PATH"`. If this doesn't work, try `brew link --force libpq`. + +- install Diesel CLI with `cargo install diesel_cli --no-default-features --features postgres`, refer to [Diesel Getting Started guide](https://diesel.rs/guides/getting-started) for more details +- [optional but handy] Postgres client like [Postico](https://eggerapps.at/postico2/), for local check, query execution etc. + +### Start the Postgres Service + +Postgres must run as a service in the background for other tools to communicate with. If it was installed using homebrew, it can be started as a service with: + +``` sh +brew services start postgresql@version +``` + +### Local Development(Recommended) + +Use [iota-test-validator](../../crates/iota-test-validator/README.md) + +### Running standalone indexer +1. DB setup, under `iota/crates/iota-indexer` run: +```sh +# an example DATABASE_URL is "postgres://postgres:postgres@localhost/gegao" +diesel setup --database-url="" +diesel database reset --database-url="" +``` +Note that you'll need an existing database for the above to work. Replace `gegao` with the name of the database created. + +2. Checkout to your target branch + +For example, if you want to be on the DevNet branch +```sh +git fetch upstream devnet && git reset --hard upstream/devnet +``` +3. Start indexer binary, under `iota/crates/iota-indexer` run: +- run indexer as a writer, which pulls data from fullnode and writes data to DB +```sh +# Change the RPC_CLIENT_URL to http://0.0.0.0:9000 to run indexer against local validator & fullnode +cargo run --bin iota-indexer -- --db-url "" --rpc-client-url "https://fullnode.devnet.iota.io:443" --fullnode-sync-worker --reset-db +``` +- run indexer as a reader, which is a JSON RPC server with the [interface](https://docs.iota.io/iota-api-ref#iotax_getallbalances) +``` +cargo run --bin iota-indexer -- --db-url "" --rpc-client-url "https://fullnode.devnet.iota.io:443" --rpc-server-worker +``` +More flags info can be found in this [file](https://github.com/iotaledger/iota/blob/main/crates/iota-indexer/src/lib.rs#L83-L123). +### DB reset +Run this command under `iota/crates/iota-indexer`, which will wipe DB; In case of schema changes in `.sql` files, this will also update corresponding `schema.rs` file. +```sh +diesel database reset --database-url="" +``` diff --git a/crates/sui-indexer/diesel.toml b/crates/iota-indexer/diesel.toml similarity index 100% rename from crates/sui-indexer/diesel.toml rename to crates/iota-indexer/diesel.toml diff --git a/crates/sui-indexer/migrations/00000000000000_diesel_initial_setup/down.sql b/crates/iota-indexer/migrations/00000000000000_diesel_initial_setup/down.sql similarity index 100% rename from crates/sui-indexer/migrations/00000000000000_diesel_initial_setup/down.sql rename to crates/iota-indexer/migrations/00000000000000_diesel_initial_setup/down.sql diff --git a/crates/sui-indexer/migrations/00000000000000_diesel_initial_setup/up.sql b/crates/iota-indexer/migrations/00000000000000_diesel_initial_setup/up.sql similarity index 100% rename from crates/sui-indexer/migrations/00000000000000_diesel_initial_setup/up.sql rename to crates/iota-indexer/migrations/00000000000000_diesel_initial_setup/up.sql diff --git a/crates/sui-indexer/migrations/2023-08-19-044020_events/down.sql b/crates/iota-indexer/migrations/2023-08-19-044020_events/down.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-08-19-044020_events/down.sql rename to crates/iota-indexer/migrations/2023-08-19-044020_events/down.sql diff --git a/crates/iota-indexer/migrations/2023-08-19-044020_events/up.sql b/crates/iota-indexer/migrations/2023-08-19-044020_events/up.sql new file mode 100644 index 00000000000..f450b1d5fdd --- /dev/null +++ b/crates/iota-indexer/migrations/2023-08-19-044020_events/up.sql @@ -0,0 +1,24 @@ +CREATE TABLE events +( + tx_sequence_number BIGINT NOT NULL, + event_sequence_number BIGINT NOT NULL, + transaction_digest bytea NOT NULL, + checkpoint_sequence_number bigint NOT NULL, + -- array of IotaAddress in bytes. All signers of the transaction. + senders bytea[] NOT NULL, + -- bytes of the entry package ID + package bytea NOT NULL, + -- entry module name + module text NOT NULL, + -- StructTag in Display format + event_type text NOT NULL, + timestamp_ms BIGINT NOT NULL, + -- bcs of the Event contents (Event.contents) + bcs BYTEA NOT NULL, + PRIMARY KEY(tx_sequence_number, event_sequence_number) +); + +CREATE INDEX events_package ON events (package, tx_sequence_number, event_sequence_number); +CREATE INDEX events_package_module ON events (package, module, tx_sequence_number, event_sequence_number); +CREATE INDEX events_event_type ON events (event_type text_pattern_ops, tx_sequence_number, event_sequence_number); +CREATE INDEX events_checkpoint_sequence_number ON events (checkpoint_sequence_number); diff --git a/crates/sui-indexer/migrations/2023-08-19-044023_objects/down.sql b/crates/iota-indexer/migrations/2023-08-19-044023_objects/down.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-08-19-044023_objects/down.sql rename to crates/iota-indexer/migrations/2023-08-19-044023_objects/down.sql diff --git a/crates/iota-indexer/migrations/2023-08-19-044023_objects/up.sql b/crates/iota-indexer/migrations/2023-08-19-044023_objects/up.sql new file mode 100644 index 00000000000..1e59528ae6e --- /dev/null +++ b/crates/iota-indexer/migrations/2023-08-19-044023_objects/up.sql @@ -0,0 +1,89 @@ +CREATE TABLE objects ( + object_id bytea PRIMARY KEY, + object_version bigint NOT NULL, + object_digest bytea NOT NULL, + checkpoint_sequence_number bigint NOT NULL, + -- Immutable/Address/Object/Shared, see types.rs + owner_type smallint NOT NULL, + -- bytes of IotaAddress/ObjectID of the owner ID. + -- Non-null for objects with an owner: Addresso or Objects + owner_id bytea, + -- Object type + object_type text, + -- bcs serialized Object + serialized_object bytea NOT NULL, + -- Non-null when the object is a coin. + -- e.g. `0x2::iota::IOTA` + coin_type text, + -- Non-null when the object is a coin. + coin_balance bigint, + -- DynamicField/DynamicObject, see types.rs + -- Non-null when the object is a dynamic field + df_kind smallint, + -- bcs serialized DynamicFieldName + -- Non-null when the object is a dynamic field + df_name bytea, + -- object_type in DynamicFieldInfo. + df_object_type text, + -- object_id in DynamicFieldInfo. + df_object_id bytea +); + +-- OwnerType: 1: Address, 2: Object, see types.rs +CREATE INDEX objects_owner ON objects (owner_type, owner_id) WHERE owner_type BETWEEN 1 AND 2 AND owner_id IS NOT NULL; +CREATE INDEX objects_coin ON objects (owner_id, coin_type) WHERE coin_type IS NOT NULL AND owner_type = 1; +CREATE INDEX objects_checkpoint_sequence_number ON objects (checkpoint_sequence_number); +CREATE INDEX objects_type ON objects (object_type); + +-- similar to objects table, except that +-- 1. the primary key to store multiple object versions and partitions by checkpoint_sequence_number +-- 2. allow null values in some columns for deleted / wrapped objects +-- 3. object_status to mark the status of the object, which is either Active or WrappedOrDeleted +CREATE TABLE objects_history ( + object_id bytea NOT NULL, + object_version bigint NOT NULL, + object_status smallint NOT NULL, + object_digest bytea, + checkpoint_sequence_number bigint NOT NULL, + owner_type smallint, + owner_id bytea, + object_type text, + serialized_object bytea, + coin_type text, + coin_balance bigint, + df_kind smallint, + df_name bytea, + df_object_type text, + df_object_id bytea, + CONSTRAINT objects_history_pk PRIMARY KEY (checkpoint_sequence_number, object_id, object_version) +) PARTITION BY RANGE (checkpoint_sequence_number); +CREATE INDEX objects_history_owner ON objects_history (checkpoint_sequence_number, owner_type, owner_id) WHERE owner_type BETWEEN 1 AND 2 AND owner_id IS NOT NULL; +CREATE INDEX objects_history_coin ON objects_history (checkpoint_sequence_number, owner_id, coin_type) WHERE coin_type IS NOT NULL AND owner_type = 1; +CREATE INDEX objects_history_type ON objects_history (checkpoint_sequence_number, object_type); +-- init with first partition of the history table +CREATE TABLE objects_history_partition_0 PARTITION OF objects_history FOR VALUES FROM (0) TO (MAXVALUE); + +-- snapshot table by folding objects_history table until certain checkpoint, +-- effectively the snapshot of objects at the same checkpoint, +-- except that it also includes deleted or wrapped objects with the corresponding object_status. +CREATE TABLE objects_snapshot ( + object_id bytea PRIMARY KEY, + object_version bigint NOT NULL, + object_status smallint NOT NULL, + object_digest bytea, + checkpoint_sequence_number bigint NOT NULL, + owner_type smallint, + owner_id bytea, + object_type text, + serialized_object bytea, + coin_type text, + coin_balance bigint, + df_kind smallint, + df_name bytea, + df_object_type text, + df_object_id bytea +); +CREATE INDEX objects_snapshot_checkpoint_sequence_number ON objects_snapshot (checkpoint_sequence_number); +CREATE INDEX objects_snapshot_owner ON objects_snapshot (owner_type, owner_id, object_id) WHERE owner_type BETWEEN 1 AND 2 AND owner_id IS NOT NULL; +CREATE INDEX objects_snapshot_coin ON objects_snapshot (owner_id, coin_type, object_id) WHERE coin_type IS NOT NULL AND owner_type = 1; +CREATE INDEX objects_snapshot_type ON objects_snapshot (object_type, object_id); diff --git a/crates/sui-indexer/migrations/2023-08-19-044026_transactions/down.sql b/crates/iota-indexer/migrations/2023-08-19-044026_transactions/down.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-08-19-044026_transactions/down.sql rename to crates/iota-indexer/migrations/2023-08-19-044026_transactions/down.sql diff --git a/crates/sui-indexer/migrations/2023-08-19-044026_transactions/up.sql b/crates/iota-indexer/migrations/2023-08-19-044026_transactions/up.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-08-19-044026_transactions/up.sql rename to crates/iota-indexer/migrations/2023-08-19-044026_transactions/up.sql diff --git a/crates/sui-indexer/migrations/2023-08-19-044044_checkpoints/down.sql b/crates/iota-indexer/migrations/2023-08-19-044044_checkpoints/down.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-08-19-044044_checkpoints/down.sql rename to crates/iota-indexer/migrations/2023-08-19-044044_checkpoints/down.sql diff --git a/crates/sui-indexer/migrations/2023-08-19-044044_checkpoints/up.sql b/crates/iota-indexer/migrations/2023-08-19-044044_checkpoints/up.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-08-19-044044_checkpoints/up.sql rename to crates/iota-indexer/migrations/2023-08-19-044044_checkpoints/up.sql diff --git a/crates/sui-indexer/migrations/2023-08-19-044052_epochs/down.sql b/crates/iota-indexer/migrations/2023-08-19-044052_epochs/down.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-08-19-044052_epochs/down.sql rename to crates/iota-indexer/migrations/2023-08-19-044052_epochs/down.sql diff --git a/crates/sui-indexer/migrations/2023-08-19-044052_epochs/up.sql b/crates/iota-indexer/migrations/2023-08-19-044052_epochs/up.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-08-19-044052_epochs/up.sql rename to crates/iota-indexer/migrations/2023-08-19-044052_epochs/up.sql diff --git a/crates/sui-indexer/migrations/2023-08-19-060729_packages/down.sql b/crates/iota-indexer/migrations/2023-08-19-060729_packages/down.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-08-19-060729_packages/down.sql rename to crates/iota-indexer/migrations/2023-08-19-060729_packages/down.sql diff --git a/crates/sui-indexer/migrations/2023-08-19-060729_packages/up.sql b/crates/iota-indexer/migrations/2023-08-19-060729_packages/up.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-08-19-060729_packages/up.sql rename to crates/iota-indexer/migrations/2023-08-19-060729_packages/up.sql diff --git a/crates/sui-indexer/migrations/2023-10-06-204335_tx_recipients/down.sql b/crates/iota-indexer/migrations/2023-10-06-204335_tx_recipients/down.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-10-06-204335_tx_recipients/down.sql rename to crates/iota-indexer/migrations/2023-10-06-204335_tx_recipients/down.sql diff --git a/crates/iota-indexer/migrations/2023-10-06-204335_tx_recipients/up.sql b/crates/iota-indexer/migrations/2023-10-06-204335_tx_recipients/up.sql new file mode 100644 index 00000000000..2382e3a47c3 --- /dev/null +++ b/crates/iota-indexer/migrations/2023-10-06-204335_tx_recipients/up.sql @@ -0,0 +1,8 @@ +-- Your SQL goes here +CREATE TABLE tx_recipients ( + tx_sequence_number BIGINT NOT NULL, + -- IotaAddress in bytes. + recipient BYTEA NOT NULL, + PRIMARY KEY(recipient, tx_sequence_number) +); +CREATE INDEX tx_recipients_tx_sequence_number_index ON tx_recipients (tx_sequence_number ASC); diff --git a/crates/sui-indexer/migrations/2023-10-06-204340_tx_senders/down.sql b/crates/iota-indexer/migrations/2023-10-06-204340_tx_senders/down.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-10-06-204340_tx_senders/down.sql rename to crates/iota-indexer/migrations/2023-10-06-204340_tx_senders/down.sql diff --git a/crates/iota-indexer/migrations/2023-10-06-204340_tx_senders/up.sql b/crates/iota-indexer/migrations/2023-10-06-204340_tx_senders/up.sql new file mode 100644 index 00000000000..db140812a55 --- /dev/null +++ b/crates/iota-indexer/migrations/2023-10-06-204340_tx_senders/up.sql @@ -0,0 +1,8 @@ +-- Your SQL goes here +CREATE TABLE tx_senders ( + tx_sequence_number BIGINT NOT NULL, + -- IotaAddress in bytes. + sender BYTEA NOT NULL, + PRIMARY KEY(sender, tx_sequence_number) +); +CREATE INDEX tx_senders_tx_sequence_number_index ON tx_senders (tx_sequence_number ASC); diff --git a/crates/sui-indexer/migrations/2023-10-06-204348_tx_input_objects/down.sql b/crates/iota-indexer/migrations/2023-10-06-204348_tx_input_objects/down.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-10-06-204348_tx_input_objects/down.sql rename to crates/iota-indexer/migrations/2023-10-06-204348_tx_input_objects/down.sql diff --git a/crates/sui-indexer/migrations/2023-10-06-204348_tx_input_objects/up.sql b/crates/iota-indexer/migrations/2023-10-06-204348_tx_input_objects/up.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-10-06-204348_tx_input_objects/up.sql rename to crates/iota-indexer/migrations/2023-10-06-204348_tx_input_objects/up.sql diff --git a/crates/sui-indexer/migrations/2023-10-06-204352_tx_changed_objects/down.sql b/crates/iota-indexer/migrations/2023-10-06-204352_tx_changed_objects/down.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-10-06-204352_tx_changed_objects/down.sql rename to crates/iota-indexer/migrations/2023-10-06-204352_tx_changed_objects/down.sql diff --git a/crates/sui-indexer/migrations/2023-10-06-204352_tx_changed_objects/up.sql b/crates/iota-indexer/migrations/2023-10-06-204352_tx_changed_objects/up.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-10-06-204352_tx_changed_objects/up.sql rename to crates/iota-indexer/migrations/2023-10-06-204352_tx_changed_objects/up.sql diff --git a/crates/sui-indexer/migrations/2023-10-06-204400_tx_calls/down.sql b/crates/iota-indexer/migrations/2023-10-06-204400_tx_calls/down.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-10-06-204400_tx_calls/down.sql rename to crates/iota-indexer/migrations/2023-10-06-204400_tx_calls/down.sql diff --git a/crates/sui-indexer/migrations/2023-10-06-204400_tx_calls/up.sql b/crates/iota-indexer/migrations/2023-10-06-204400_tx_calls/up.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-10-06-204400_tx_calls/up.sql rename to crates/iota-indexer/migrations/2023-10-06-204400_tx_calls/up.sql diff --git a/crates/sui-indexer/migrations/2023-10-07-160139_display/down.sql b/crates/iota-indexer/migrations/2023-10-07-160139_display/down.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-10-07-160139_display/down.sql rename to crates/iota-indexer/migrations/2023-10-07-160139_display/down.sql diff --git a/crates/sui-indexer/migrations/2023-10-07-160139_display/up.sql b/crates/iota-indexer/migrations/2023-10-07-160139_display/up.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-10-07-160139_display/up.sql rename to crates/iota-indexer/migrations/2023-10-07-160139_display/up.sql diff --git a/crates/sui-indexer/migrations/2023-10-24-160139_query_cost_function/down.sql b/crates/iota-indexer/migrations/2023-10-24-160139_query_cost_function/down.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-10-24-160139_query_cost_function/down.sql rename to crates/iota-indexer/migrations/2023-10-24-160139_query_cost_function/down.sql diff --git a/crates/sui-indexer/migrations/2023-10-24-160139_query_cost_function/up.sql b/crates/iota-indexer/migrations/2023-10-24-160139_query_cost_function/up.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-10-24-160139_query_cost_function/up.sql rename to crates/iota-indexer/migrations/2023-10-24-160139_query_cost_function/up.sql diff --git a/crates/sui-indexer/migrations/2023-11-29-193859_advance_partition/down.sql b/crates/iota-indexer/migrations/2023-11-29-193859_advance_partition/down.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-11-29-193859_advance_partition/down.sql rename to crates/iota-indexer/migrations/2023-11-29-193859_advance_partition/down.sql diff --git a/crates/sui-indexer/migrations/2023-11-29-193859_advance_partition/up.sql b/crates/iota-indexer/migrations/2023-11-29-193859_advance_partition/up.sql similarity index 100% rename from crates/sui-indexer/migrations/2023-11-29-193859_advance_partition/up.sql rename to crates/iota-indexer/migrations/2023-11-29-193859_advance_partition/up.sql diff --git a/crates/iota-indexer/src/apis/coin_api.rs b/crates/iota-indexer/src/apis/coin_api.rs new file mode 100644 index 00000000000..ace6e6fbdf9 --- /dev/null +++ b/crates/iota-indexer/src/apis/coin_api.rs @@ -0,0 +1,160 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use iota_json_rpc::{ + coin_api::{parse_to_struct_tag, parse_to_type_tag}, + IotaRpcModule, +}; +use iota_json_rpc_api::{cap_page_limit, CoinReadApiServer}; +use iota_json_rpc_types::{Balance, CoinPage, IotaCoinMetadata, Page}; +use iota_open_rpc::Module; +use iota_types::{ + balance::Supply, + base_types::{IotaAddress, ObjectID}, + gas_coin::{GAS, TOTAL_SUPPLY_MICROS}, +}; +use jsonrpsee::{core::RpcResult, RpcModule}; + +use crate::indexer_reader::IndexerReader; + +pub(crate) struct CoinReadApi { + inner: IndexerReader, +} + +impl CoinReadApi { + pub fn new(inner: IndexerReader) -> Self { + Self { inner } + } +} + +#[async_trait] +impl CoinReadApiServer for CoinReadApi { + async fn get_coins( + &self, + owner: IotaAddress, + coin_type: Option, + cursor: Option, + limit: Option, + ) -> RpcResult { + let limit = cap_page_limit(limit); + if limit == 0 { + return Ok(CoinPage::empty()); + } + + // Normalize coin type tag and default to Gas + let coin_type = + parse_to_type_tag(coin_type)?.to_canonical_string(/* with_prefix */ true); + + let cursor = match cursor { + Some(c) => c, + // If cursor is not specified, we need to start from the beginning of the coin type, + // which is the minimal possible ObjectID. + None => ObjectID::ZERO, + }; + let mut results = self + .inner + .get_owned_coins_in_blocking_task(owner, Some(coin_type), cursor, limit + 1) + .await?; + + let has_next_page = results.len() > limit; + results.truncate(limit); + let next_cursor = results.last().map(|o| o.coin_object_id); + Ok(Page { + data: results, + next_cursor, + has_next_page, + }) + } + + async fn get_all_coins( + &self, + owner: IotaAddress, + cursor: Option, + limit: Option, + ) -> RpcResult { + let limit = cap_page_limit(limit); + if limit == 0 { + return Ok(CoinPage::empty()); + } + + let cursor = match cursor { + Some(c) => c, + // If cursor is not specified, we need to start from the beginning of the coin type, + // which is the minimal possible ObjectID. + None => ObjectID::ZERO, + }; + let mut results = self + .inner + .get_owned_coins_in_blocking_task(owner, None, cursor, limit + 1) + .await?; + + let has_next_page = results.len() > limit; + results.truncate(limit); + let next_cursor = results.last().map(|o| o.coin_object_id); + Ok(Page { + data: results, + next_cursor, + has_next_page, + }) + } + + async fn get_balance( + &self, + owner: IotaAddress, + coin_type: Option, + ) -> RpcResult { + // Normalize coin type tag and default to Gas + let coin_type = + parse_to_type_tag(coin_type)?.to_canonical_string(/* with_prefix */ true); + + let mut results = self + .inner + .get_coin_balances_in_blocking_task(owner, Some(coin_type.clone())) + .await?; + if results.is_empty() { + return Ok(Balance::zero(coin_type)); + } + Ok(results.swap_remove(0)) + } + + async fn get_all_balances(&self, owner: IotaAddress) -> RpcResult> { + self.inner + .get_coin_balances_in_blocking_task(owner, None) + .await + .map_err(Into::into) + } + + async fn get_coin_metadata(&self, coin_type: String) -> RpcResult> { + let coin_struct = parse_to_struct_tag(&coin_type)?; + self.inner + .get_coin_metadata_in_blocking_task(coin_struct) + .await + .map_err(Into::into) + } + + async fn get_total_supply(&self, coin_type: String) -> RpcResult { + let coin_struct = parse_to_struct_tag(&coin_type)?; + if GAS::is_gas(&coin_struct) { + Ok(Supply { + value: TOTAL_SUPPLY_MICROS, + }) + } else { + self.inner + .get_total_supply_in_blocking_task(coin_struct) + .await + .map_err(Into::into) + } + } +} + +impl IotaRpcModule for CoinReadApi { + fn rpc(self) -> RpcModule { + self.into_rpc() + } + + fn rpc_doc_module() -> Module { + iota_json_rpc_api::CoinReadApiOpenRpc::module_doc() + } +} diff --git a/crates/sui-indexer/src/apis/extended_api.rs b/crates/iota-indexer/src/apis/extended_api.rs similarity index 81% rename from crates/sui-indexer/src/apis/extended_api.rs rename to crates/iota-indexer/src/apis/extended_api.rs index f35fa95fef0..2f954d3fd4b 100644 --- a/crates/sui-indexer/src/apis/extended_api.rs +++ b/crates/iota-indexer/src/apis/extended_api.rs @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use jsonrpsee::{core::RpcResult, RpcModule}; -use sui_json_rpc::SuiRpcModule; -use sui_json_rpc_api::{validate_limit, ExtendedApiServer, QUERY_MAX_RESULT_LIMIT_CHECKPOINTS}; -use sui_json_rpc_types::{ - CheckpointedObjectID, EpochInfo, EpochPage, Page, QueryObjectsPage, SuiObjectResponseQuery, +use iota_json_rpc::IotaRpcModule; +use iota_json_rpc_api::{validate_limit, ExtendedApiServer, QUERY_MAX_RESULT_LIMIT_CHECKPOINTS}; +use iota_json_rpc_types::{ + CheckpointedObjectID, EpochInfo, EpochPage, IotaObjectResponseQuery, Page, QueryObjectsPage, }; -use sui_open_rpc::Module; -use sui_types::sui_serde::BigInt; +use iota_open_rpc::Module; +use iota_types::iota_serde::BigInt; +use jsonrpsee::{core::RpcResult, RpcModule}; use crate::indexer_reader::IndexerReader; @@ -62,7 +63,7 @@ impl ExtendedApiServer for ExtendedApi { async fn query_objects( &self, - _query: SuiObjectResponseQuery, + _query: IotaObjectResponseQuery, _cursor: Option, _limit: Option, ) -> RpcResult { @@ -81,12 +82,12 @@ impl ExtendedApiServer for ExtendedApi { } } -impl SuiRpcModule for ExtendedApi { +impl IotaRpcModule for ExtendedApi { fn rpc(self) -> RpcModule { self.into_rpc() } fn rpc_doc_module() -> Module { - sui_json_rpc_api::ExtendedApiOpenRpc::module_doc() + iota_json_rpc_api::ExtendedApiOpenRpc::module_doc() } } diff --git a/crates/iota-indexer/src/apis/governance_api.rs b/crates/iota-indexer/src/apis/governance_api.rs new file mode 100644 index 00000000000..fa2aefe991d --- /dev/null +++ b/crates/iota-indexer/src/apis/governance_api.rs @@ -0,0 +1,469 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use async_trait::async_trait; +use cached::{proc_macro::cached, SizedCache}; +use iota_json_rpc::{governance_api::ValidatorExchangeRates, IotaRpcModule}; +use iota_json_rpc_api::GovernanceReadApiServer; +use iota_json_rpc_types::{ + DelegatedStake, DelegatedTimelockedStake, EpochInfo, IotaCommittee, IotaObjectDataFilter, + StakeStatus, ValidatorApys, +}; +use iota_open_rpc::Module; +use iota_types::{ + base_types::{IotaAddress, MoveObjectType, ObjectID}, + committee::EpochId, + governance::StakedIota, + iota_serde::BigInt, + iota_system_state::{iota_system_state_summary::IotaSystemStateSummary, PoolTokenExchangeRate}, + timelock::timelocked_staked_iota::TimelockedStakedIota, +}; +use jsonrpsee::{core::RpcResult, RpcModule}; + +use crate::{errors::IndexerError, indexer_reader::IndexerReader}; + +/// Maximum amount of staked objects for querying. +const MAX_QUERY_STAKED_OBJECTS: usize = 1000; + +#[derive(Clone)] +pub struct GovernanceReadApi { + inner: IndexerReader, +} + +impl GovernanceReadApi { + pub fn new(inner: IndexerReader) -> Self { + Self { inner } + } + + /// Get a validator's APY by its address + pub async fn get_validator_apy( + &self, + address: &IotaAddress, + ) -> Result, IndexerError> { + let apys = validators_apys_map(self.get_validators_apy().await?); + Ok(apys.get(address).copied()) + } + + async fn get_validators_apy(&self) -> Result { + let system_state_summary: IotaSystemStateSummary = + self.get_latest_iota_system_state().await?; + let epoch = system_state_summary.epoch; + let stake_subsidy_start_epoch = system_state_summary.stake_subsidy_start_epoch; + + let exchange_rate_table = exchange_rates(self, system_state_summary).await?; + + let apys = iota_json_rpc::governance_api::calculate_apys( + stake_subsidy_start_epoch, + exchange_rate_table, + ); + + Ok(ValidatorApys { apys, epoch }) + } + + pub async fn get_epoch_info(&self, epoch: Option) -> Result { + match self + .inner + .spawn_blocking(move |this| this.get_epoch_info(epoch)) + .await + { + Ok(Some(epoch_info)) => Ok(epoch_info), + Ok(None) => Err(IndexerError::InvalidArgumentError(format!( + "Missing epoch {epoch:?}" + ))), + Err(e) => Err(e), + } + } + + async fn get_latest_iota_system_state(&self) -> Result { + self.inner + .spawn_blocking(|this| this.get_latest_iota_system_state()) + .await + } + + async fn get_stakes_by_ids( + &self, + ids: Vec, + ) -> Result, IndexerError> { + let mut stakes = vec![]; + for stored_object in self.inner.multi_get_objects_in_blocking_task(ids).await? { + let object = iota_types::object::Object::try_from(stored_object)?; + let stake_object = StakedIota::try_from(&object)?; + stakes.push(stake_object); + } + + self.get_delegated_stakes(stakes).await + } + + async fn get_staked_by_owner( + &self, + owner: IotaAddress, + ) -> Result, IndexerError> { + let mut stakes = vec![]; + for stored_object in self + .inner + .get_owned_objects_in_blocking_task( + owner, + Some(IotaObjectDataFilter::StructType( + MoveObjectType::staked_iota().into(), + )), + None, + MAX_QUERY_STAKED_OBJECTS, + ) + .await? + { + let object = iota_types::object::Object::try_from(stored_object)?; + let stake_object = StakedIota::try_from(&object)?; + stakes.push(stake_object); + } + + self.get_delegated_stakes(stakes).await + } + + async fn get_timelocked_staked_by_owner( + &self, + owner: IotaAddress, + ) -> Result, IndexerError> { + let mut stakes = vec![]; + for stored_object in self + .inner + .get_owned_objects_in_blocking_task( + owner, + Some(IotaObjectDataFilter::StructType( + MoveObjectType::timelocked_staked_iota().into(), + )), + None, + MAX_QUERY_STAKED_OBJECTS, + ) + .await? + { + let object = iota_types::object::Object::try_from(stored_object)?; + let stake_object = TimelockedStakedIota::try_from(&object)?; + stakes.push(stake_object); + } + + self.get_delegated_timelocked_stakes(stakes).await + } + + pub async fn get_delegated_stakes( + &self, + stakes: Vec, + ) -> Result, IndexerError> { + let pools = stakes + .into_iter() + .fold(BTreeMap::<_, Vec<_>>::new(), |mut pools, stake| { + pools.entry(stake.pool_id()).or_default().push(stake); + pools + }); + + let system_state_summary = self.get_latest_iota_system_state().await?; + let epoch = system_state_summary.epoch; + + let rates = exchange_rates(self, system_state_summary) + .await? + .into_iter() + .map(|rates| (rates.pool_id, rates)) + .collect::>(); + + let mut delegated_stakes = vec![]; + for (pool_id, stakes) in pools { + // Rate table and rate can be null when the pool is not active + let rate_table = rates.get(&pool_id).ok_or_else(|| { + IndexerError::InvalidArgumentError( + "Cannot find rates for staking pool {pool_id}".to_string(), + ) + })?; + let current_rate = rate_table.rates.first().map(|(_, rate)| rate); + + let mut delegations = vec![]; + for stake in stakes { + let status = stake_status( + epoch, + stake.activation_epoch(), + stake.principal(), + rate_table, + current_rate, + ); + + delegations.push(iota_json_rpc_types::Stake { + staked_iota_id: stake.id(), + // TODO: this might change when we implement warm up period. + stake_request_epoch: stake.activation_epoch().saturating_sub(1), + stake_active_epoch: stake.activation_epoch(), + principal: stake.principal(), + status, + }) + } + delegated_stakes.push(DelegatedStake { + validator_address: rate_table.address, + staking_pool: pool_id, + stakes: delegations, + }) + } + Ok(delegated_stakes) + } + + pub async fn get_delegated_timelocked_stakes( + &self, + stakes: Vec, + ) -> Result, IndexerError> { + let pools = stakes + .into_iter() + .fold(BTreeMap::<_, Vec<_>>::new(), |mut pools, stake| { + pools.entry(stake.pool_id()).or_default().push(stake); + pools + }); + + let system_state_summary = self.get_latest_iota_system_state().await?; + let epoch = system_state_summary.epoch; + + let rates = exchange_rates(self, system_state_summary) + .await? + .into_iter() + .map(|rates| (rates.pool_id, rates)) + .collect::>(); + + let mut delegated_stakes = vec![]; + for (pool_id, stakes) in pools { + // Rate table and rate can be null when the pool is not active + let rate_table = rates.get(&pool_id).ok_or_else(|| { + IndexerError::InvalidArgumentError( + "Cannot find rates for staking pool {pool_id}".to_string(), + ) + })?; + let current_rate = rate_table.rates.first().map(|(_, rate)| rate); + + let mut delegations = vec![]; + for stake in stakes { + let status = stake_status( + epoch, + stake.activation_epoch(), + stake.principal(), + rate_table, + current_rate, + ); + + delegations.push(iota_json_rpc_types::TimelockedStake { + timelocked_staked_iota_id: stake.id(), + // TODO: this might change when we implement warm up period. + stake_request_epoch: stake.activation_epoch().saturating_sub(1), + stake_active_epoch: stake.activation_epoch(), + principal: stake.principal(), + status, + expiration_timestamp_ms: stake.expiration_timestamp_ms(), + }) + } + delegated_stakes.push(DelegatedTimelockedStake { + validator_address: rate_table.address, + staking_pool: pool_id, + stakes: delegations, + }) + } + Ok(delegated_stakes) + } +} + +fn stake_status( + epoch: u64, + activation_epoch: u64, + principal: u64, + rate_table: &ValidatorExchangeRates, + current_rate: Option<&PoolTokenExchangeRate>, +) -> StakeStatus { + if epoch >= activation_epoch { + let estimated_reward = if let Some(current_rate) = current_rate { + let stake_rate = rate_table + .rates + .iter() + .find_map(|(epoch, rate)| (*epoch == activation_epoch).then(|| rate.clone())) + .unwrap_or_default(); + let estimated_reward = + ((stake_rate.rate() / current_rate.rate()) - 1.0) * principal as f64; + std::cmp::max(0, estimated_reward.round() as u64) + } else { + 0 + }; + StakeStatus::Active { estimated_reward } + } else { + StakeStatus::Pending + } +} + +/// Cached exchange rates for validators for the given epoch, the cache size is +/// 1, it will be cleared when the epoch changes. rates are in descending order +/// by epoch. +#[cached( + type = "SizedCache>", + create = "{ SizedCache::with_size(1) }", + convert = "{ system_state_summary.epoch }", + result = true +)] +async fn exchange_rates( + state: &GovernanceReadApi, + system_state_summary: IotaSystemStateSummary, +) -> Result, IndexerError> { + // Get validator rate tables + let mut tables = vec![]; + + for validator in system_state_summary.active_validators { + tables.push(( + validator.iota_address, + validator.staking_pool_id, + validator.exchange_rates_id, + validator.exchange_rates_size, + true, + )); + } + + // Get inactive validator rate tables + for df in state + .inner + .get_dynamic_fields_in_blocking_task( + system_state_summary.inactive_pools_id, + None, + system_state_summary.inactive_pools_size as usize, + ) + .await? + { + let pool_id: iota_types::id::ID = bcs::from_bytes(&df.bcs_name).map_err(|e| { + iota_types::error::IotaError::ObjectDeserializationError { + error: e.to_string(), + } + })?; + let inactive_pools_id = system_state_summary.inactive_pools_id; + let validator = state + .inner + .spawn_blocking(move |this| { + iota_types::iota_system_state::get_validator_from_table( + &this, + inactive_pools_id, + &pool_id, + ) + }) + .await?; + tables.push(( + validator.iota_address, + validator.staking_pool_id, + validator.exchange_rates_id, + validator.exchange_rates_size, + false, + )); + } + + let mut exchange_rates = vec![]; + // Get exchange rates for each validator + for (address, pool_id, exchange_rates_id, exchange_rates_size, active) in tables { + let mut rates = vec![]; + for df in state + .inner + .get_dynamic_fields_raw_in_blocking_task( + exchange_rates_id, + None, + exchange_rates_size as usize, + ) + .await? + { + let dynamic_field = df + .to_dynamic_field::() + .ok_or_else( + || iota_types::error::IotaError::ObjectDeserializationError { + error: "dynamic field malformed".to_owned(), + }, + )?; + + rates.push((dynamic_field.name, dynamic_field.value)); + } + + rates.sort_by(|(a, _), (b, _)| a.cmp(b).reverse()); + + exchange_rates.push(ValidatorExchangeRates { + address, + pool_id, + active, + rates, + }); + } + Ok(exchange_rates) +} + +/// Cache a map representing the validators' APYs for this epoch +#[cached( + type = "SizedCache>", + create = "{ SizedCache::with_size(1) }", + convert = " {apys.epoch} " +)] +fn validators_apys_map(apys: ValidatorApys) -> BTreeMap { + BTreeMap::from_iter(apys.apys.iter().map(|x| (x.address, x.apy))) +} + +#[async_trait] +impl GovernanceReadApiServer for GovernanceReadApi { + async fn get_stakes_by_ids( + &self, + staked_iota_ids: Vec, + ) -> RpcResult> { + self.get_stakes_by_ids(staked_iota_ids) + .await + .map_err(Into::into) + } + + async fn get_stakes(&self, owner: IotaAddress) -> RpcResult> { + self.get_staked_by_owner(owner).await.map_err(Into::into) + } + + async fn get_timelocked_stakes_by_ids( + &self, + timelocked_staked_iota_ids: Vec, + ) -> RpcResult> { + self.get_timelocked_stakes_by_ids(timelocked_staked_iota_ids) + .await + .map_err(Into::into) + } + + async fn get_timelocked_stakes( + &self, + owner: IotaAddress, + ) -> RpcResult> { + self.get_timelocked_staked_by_owner(owner) + .await + .map_err(Into::into) + } + + async fn get_committee_info(&self, epoch: Option>) -> RpcResult { + let epoch = self.get_epoch_info(epoch.as_deref().copied()).await?; + Ok(epoch.committee().map_err(IndexerError::from)?.into()) + } + + async fn get_latest_iota_system_state(&self) -> RpcResult { + self.get_latest_iota_system_state() + .await + .map_err(Into::into) + } + + async fn get_reference_gas_price(&self) -> RpcResult> { + let epoch = self.get_epoch_info(None).await?; + Ok(BigInt::from(epoch.reference_gas_price.ok_or_else( + || { + IndexerError::PersistentStorageDataCorruptionError( + "missing latest reference gas price".to_owned(), + ) + }, + )?)) + } + + async fn get_validators_apy(&self) -> RpcResult { + Ok(self.get_validators_apy().await?) + } +} + +impl IotaRpcModule for GovernanceReadApi { + fn rpc(self) -> RpcModule { + self.into_rpc() + } + + fn rpc_doc_module() -> Module { + iota_json_rpc_api::GovernanceReadApiOpenRpc::module_doc() + } +} diff --git a/crates/iota-indexer/src/apis/indexer_api.rs b/crates/iota-indexer/src/apis/indexer_api.rs new file mode 100644 index 00000000000..6ef245698f8 --- /dev/null +++ b/crates/iota-indexer/src/apis/indexer_api.rs @@ -0,0 +1,370 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use iota_json_rpc::{ + name_service::{Domain, NameRecord, NameServiceConfig}, + IotaRpcModule, +}; +use iota_json_rpc_api::{cap_page_limit, IndexerApiServer}; +use iota_json_rpc_types::{ + DynamicFieldPage, EventFilter, EventPage, IotaObjectResponse, IotaObjectResponseQuery, + IotaTransactionBlockResponseQuery, ObjectsPage, Page, TransactionBlocksPage, TransactionFilter, +}; +use iota_open_rpc::Module; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + digests::TransactionDigest, + dynamic_field::{DynamicFieldName, Field}, + error::IotaObjectResponseError, + event::EventID, + object::ObjectRead, + TypeTag, +}; +use jsonrpsee::{ + core::RpcResult, + types::{SubscriptionEmptyError, SubscriptionResult}, + RpcModule, SubscriptionSink, +}; + +use crate::{indexer_reader::IndexerReader, IndexerError}; + +pub(crate) struct IndexerApi { + inner: IndexerReader, + name_service_config: NameServiceConfig, +} + +impl IndexerApi { + pub fn new(inner: IndexerReader) -> Self { + Self { + inner, + // TODO allow configuring for other networks + name_service_config: Default::default(), + } + } + + async fn get_owned_objects_internal( + &self, + address: IotaAddress, + query: Option, + cursor: Option, + limit: usize, + ) -> RpcResult { + let IotaObjectResponseQuery { filter, options } = query.unwrap_or_default(); + let options = options.unwrap_or_default(); + let objects = self + .inner + .get_owned_objects_in_blocking_task(address, filter, cursor, limit + 1) + .await?; + let mut objects = self + .inner + .spawn_blocking(move |this| { + objects + .into_iter() + .map(|object| object.try_into_object_read(&this)) + .collect::, _>>() + }) + .await?; + let has_next_page = objects.len() > limit; + objects.truncate(limit); + + let next_cursor = objects.last().map(|o_read| o_read.object_id()); + let mut parallel_tasks = vec![]; + for o in objects { + let inner_clone = self.inner.clone(); + let options = options.clone(); + parallel_tasks.push(tokio::task::spawn(async move { + match o { + ObjectRead::NotExists(id) => Ok(IotaObjectResponse::new_with_error( + IotaObjectResponseError::NotExists { object_id: id }, + )), + ObjectRead::Exists(object_ref, o, layout) => { + if options.show_display { + match inner_clone.get_display_fields(&o, &layout).await { + Ok(rendered_fields) => Ok(IotaObjectResponse::new_with_data( + (object_ref, o, layout, options, Some(rendered_fields)) + .try_into()?, + )), + Err(e) => Ok(IotaObjectResponse::new( + Some((object_ref, o, layout, options, None).try_into()?), + Some(IotaObjectResponseError::DisplayError { + error: e.to_string(), + }), + )), + } + } else { + Ok(IotaObjectResponse::new_with_data( + (object_ref, o, layout, options, None).try_into()?, + )) + } + } + ObjectRead::Deleted((object_id, version, digest)) => Ok( + IotaObjectResponse::new_with_error(IotaObjectResponseError::Deleted { + object_id, + version, + digest, + }), + ), + } + })); + } + let data = futures::future::join_all(parallel_tasks) + .await + .into_iter() + .collect::, _>>() + .map_err(|e: tokio::task::JoinError| anyhow::anyhow!(e))? + .into_iter() + .collect::, anyhow::Error>>()?; + + Ok(Page { + data, + next_cursor, + has_next_page, + }) + } +} + +#[async_trait] +impl IndexerApiServer for IndexerApi { + async fn get_owned_objects( + &self, + address: IotaAddress, + query: Option, + cursor: Option, + limit: Option, + ) -> RpcResult { + let limit = cap_page_limit(limit); + if limit == 0 { + return Ok(ObjectsPage::empty()); + } + self.get_owned_objects_internal(address, query, cursor, limit) + .await + } + + async fn query_transaction_blocks( + &self, + query: IotaTransactionBlockResponseQuery, + cursor: Option, + limit: Option, + descending_order: Option, + ) -> RpcResult { + let limit = cap_page_limit(limit); + if limit == 0 { + return Ok(TransactionBlocksPage::empty()); + } + let mut results = self + .inner + .query_transaction_blocks_in_blocking_task( + query.filter, + query.options.unwrap_or_default(), + cursor, + limit + 1, + descending_order.unwrap_or(false), + ) + .await + .map_err(|e: IndexerError| anyhow::anyhow!(e))?; + + let has_next_page = results.len() > limit; + results.truncate(limit); + let next_cursor = results.last().map(|o| o.digest); + Ok(Page { + data: results, + next_cursor, + has_next_page, + }) + } + + async fn query_events( + &self, + query: EventFilter, + // exclusive cursor if `Some`, otherwise start from the beginning + cursor: Option, + limit: Option, + descending_order: Option, + ) -> RpcResult { + let limit = cap_page_limit(limit); + if limit == 0 { + return Ok(EventPage::empty()); + } + let descending_order = descending_order.unwrap_or(false); + let mut results = self + .inner + .query_events_in_blocking_task(query, cursor, limit + 1, descending_order) + .await?; + + let has_next_page = results.len() > limit; + results.truncate(limit); + let next_cursor = results.last().map(|o| o.id); + Ok(Page { + data: results, + next_cursor, + has_next_page, + }) + } + + async fn get_dynamic_fields( + &self, + parent_object_id: ObjectID, + cursor: Option, + limit: Option, + ) -> RpcResult { + let limit = cap_page_limit(limit); + if limit == 0 { + return Ok(DynamicFieldPage::empty()); + } + let mut results = self + .inner + .get_dynamic_fields_in_blocking_task(parent_object_id, cursor, limit + 1) + .await?; + + let has_next_page = results.len() > limit; + results.truncate(limit); + let next_cursor = results.last().map(|o| o.object_id); + Ok(Page { + data: results, + next_cursor, + has_next_page, + }) + } + + async fn get_dynamic_field_object( + &self, + parent_object_id: ObjectID, + name: DynamicFieldName, + ) -> RpcResult { + let name_bcs_value = self + .inner + .bcs_name_from_dynamic_field_name_in_blocking_task(&name) + .await?; + + // Try as Dynamic Field + let id = iota_types::dynamic_field::derive_dynamic_field_id( + parent_object_id, + &name.type_, + &name_bcs_value, + ) + .expect("deriving dynamic field id can't fail"); + + let options = iota_json_rpc_types::IotaObjectDataOptions::full_content(); + match self.inner.get_object_read_in_blocking_task(id).await? { + iota_types::object::ObjectRead::NotExists(_) + | iota_types::object::ObjectRead::Deleted(_) => {} + iota_types::object::ObjectRead::Exists(object_ref, o, layout) => { + return Ok(IotaObjectResponse::new_with_data( + (object_ref, o, layout, options, None).try_into()?, + )); + } + } + + // Try as Dynamic Field Object + let dynamic_object_field_struct = + iota_types::dynamic_field::DynamicFieldInfo::dynamic_object_field_wrapper(name.type_); + let dynamic_object_field_type = TypeTag::Struct(Box::new(dynamic_object_field_struct)); + let dynamic_object_field_id = iota_types::dynamic_field::derive_dynamic_field_id( + parent_object_id, + &dynamic_object_field_type, + &name_bcs_value, + ) + .expect("deriving dynamic field id can't fail"); + match self + .inner + .get_object_read_in_blocking_task(dynamic_object_field_id) + .await? + { + iota_types::object::ObjectRead::NotExists(_) + | iota_types::object::ObjectRead::Deleted(_) => {} + iota_types::object::ObjectRead::Exists(object_ref, o, layout) => { + return Ok(IotaObjectResponse::new_with_data( + (object_ref, o, layout, options, None).try_into()?, + )); + } + } + + Ok(IotaObjectResponse::new_with_error( + iota_types::error::IotaObjectResponseError::DynamicFieldNotFound { parent_object_id }, + )) + } + + fn subscribe_event(&self, _sink: SubscriptionSink, _filter: EventFilter) -> SubscriptionResult { + Err(SubscriptionEmptyError) + } + + fn subscribe_transaction( + &self, + _sink: SubscriptionSink, + _filter: TransactionFilter, + ) -> SubscriptionResult { + Err(SubscriptionEmptyError) + } + + async fn resolve_name_service_address(&self, name: String) -> RpcResult> { + // TODO(manos): Implement new logic. + let domain = name + .parse::() + .map_err(IndexerError::NameServiceError)?; + + let record_id = self.name_service_config.record_field_id(&domain); + + let field_record_object = match self.inner.get_object_in_blocking_task(record_id).await? { + Some(o) => o, + None => return Ok(None), + }; + + let record = NameRecord::try_from(field_record_object) + .map_err(|e| IndexerError::PersistentStorageDataCorruptionError(e.to_string()))?; + + Ok(record.target_address) + } + + async fn resolve_name_service_names( + &self, + address: IotaAddress, + _cursor: Option, + _limit: Option, + ) -> RpcResult> { + let reverse_record_id = self + .name_service_config + .reverse_record_field_id(address.as_ref()); + + let field_reverse_record_object = match self + .inner + .get_object_in_blocking_task(reverse_record_id) + .await? + { + Some(o) => o, + None => { + return Ok(Page { + data: vec![], + next_cursor: None, + has_next_page: false, + }); + } + }; + + let domain = field_reverse_record_object + .to_rust::>() + .ok_or_else(|| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "Malformed Object {reverse_record_id}" + )) + })? + .value; + + Ok(Page { + data: vec![domain.to_string()], + next_cursor: None, + has_next_page: false, + }) + } +} + +impl IotaRpcModule for IndexerApi { + fn rpc(self) -> RpcModule { + self.into_rpc() + } + + fn rpc_doc_module() -> Module { + iota_json_rpc_api::IndexerApiOpenRpc::module_doc() + } +} diff --git a/crates/iota-indexer/src/apis/mod.rs b/crates/iota-indexer/src/apis/mod.rs new file mode 100644 index 00000000000..92efdb9da69 --- /dev/null +++ b/crates/iota-indexer/src/apis/mod.rs @@ -0,0 +1,21 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub(crate) use coin_api::CoinReadApi; +pub(crate) use extended_api::ExtendedApi; +pub use governance_api::GovernanceReadApi; +pub(crate) use indexer_api::IndexerApi; +pub(crate) use move_utils::MoveUtilsApi; +pub(crate) use read_api::ReadApi; +pub(crate) use transaction_builder_api::TransactionBuilderApi; +pub(crate) use write_api::WriteApi; + +mod coin_api; +mod extended_api; +mod governance_api; +mod indexer_api; +mod move_utils; +mod read_api; +mod transaction_builder_api; +mod write_api; diff --git a/crates/iota-indexer/src/apis/move_utils.rs b/crates/iota-indexer/src/apis/move_utils.rs new file mode 100644 index 00000000000..e0a1574798a --- /dev/null +++ b/crates/iota-indexer/src/apis/move_utils.rs @@ -0,0 +1,156 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use async_trait::async_trait; +use iota_json_rpc::{error::IotaRpcInputError, IotaRpcModule}; +use iota_json_rpc_api::MoveUtilsServer; +use iota_json_rpc_types::{ + IotaMoveNormalizedFunction, IotaMoveNormalizedModule, IotaMoveNormalizedStruct, + IotaMoveNormalizedType, MoveFunctionArgType, ObjectValueKind, +}; +use iota_open_rpc::Module; +use iota_types::{base_types::ObjectID, move_package::normalize_modules}; +use jsonrpsee::{core::RpcResult, RpcModule}; +use move_binary_format::binary_config::BinaryConfig; + +use crate::indexer_reader::IndexerReader; + +pub struct MoveUtilsApi { + inner: IndexerReader, +} + +impl MoveUtilsApi { + pub fn new(inner: IndexerReader) -> Self { + Self { inner } + } +} + +#[async_trait] +impl MoveUtilsServer for MoveUtilsApi { + async fn get_normalized_move_modules_by_package( + &self, + package_id: ObjectID, + ) -> RpcResult> { + let package = self + .inner + .get_package_in_blocking_task(package_id) + .await + .map_err(|e| IotaRpcInputError::GenericNotFound(e.to_string()))? + .ok_or_else(|| { + IotaRpcInputError::GenericNotFound(format!( + "Package object does not exist with ID {package_id}", + )) + })?; + let binary_config = BinaryConfig::with_extraneous_bytes_check(false); + let modules = + // we are on the read path - it's OK to use VERSION_MAX of the supported Move + // binary format + normalize_modules( + package.serialized_module_map().values(), + &binary_config, + ) + .map_err(|e| IotaRpcInputError::GenericInvalid(e.to_string()))?; + Ok(modules + .into_iter() + .map(|(name, module)| (name, module.into())) + .collect::>()) + } + + async fn get_normalized_move_module( + &self, + package: ObjectID, + module_name: String, + ) -> RpcResult { + let mut modules = self.get_normalized_move_modules_by_package(package).await?; + let module = modules.remove(&module_name).ok_or_else(|| { + IotaRpcInputError::GenericNotFound(format!( + "No module was found with name {module_name}", + )) + })?; + Ok(module) + } + + async fn get_normalized_move_struct( + &self, + package: ObjectID, + module_name: String, + struct_name: String, + ) -> RpcResult { + let mut module = self + .get_normalized_move_module(package, module_name) + .await?; + module + .structs + .remove(&struct_name) + .ok_or_else(|| { + IotaRpcInputError::GenericNotFound(format!( + "No struct was found with struct name {struct_name}" + )) + }) + .map_err(Into::into) + } + + async fn get_normalized_move_function( + &self, + package: ObjectID, + module_name: String, + function_name: String, + ) -> RpcResult { + let mut module = self + .get_normalized_move_module(package, module_name) + .await?; + module + .exposed_functions + .remove(&function_name) + .ok_or_else(|| { + IotaRpcInputError::GenericNotFound(format!( + "No function was found with function name {function_name}", + )) + }) + .map_err(Into::into) + } + + async fn get_move_function_arg_types( + &self, + package: ObjectID, + module: String, + function: String, + ) -> RpcResult> { + let function = self + .get_normalized_move_function(package, module, function) + .await?; + let args = function + .parameters + .iter() + .map(|p| match p { + IotaMoveNormalizedType::Struct { .. } => { + MoveFunctionArgType::Object(ObjectValueKind::ByValue) + } + IotaMoveNormalizedType::Vector(_) => { + MoveFunctionArgType::Object(ObjectValueKind::ByValue) + } + IotaMoveNormalizedType::Reference(_) => { + MoveFunctionArgType::Object(ObjectValueKind::ByImmutableReference) + } + IotaMoveNormalizedType::MutableReference(_) => { + MoveFunctionArgType::Object(ObjectValueKind::ByMutableReference) + } + _ => MoveFunctionArgType::Pure, + }) + .collect::>(); + Ok(args) + } +} + +impl IotaRpcModule for MoveUtilsApi { + fn rpc(self) -> RpcModule { + self.into_rpc() + } + + fn rpc_doc_module() -> Module { + iota_json_rpc_api::MoveUtilsOpenRpc::module_doc() + } +} diff --git a/crates/iota-indexer/src/apis/read_api.rs b/crates/iota-indexer/src/apis/read_api.rs new file mode 100644 index 00000000000..1cf86ea9c78 --- /dev/null +++ b/crates/iota-indexer/src/apis/read_api.rs @@ -0,0 +1,306 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use iota_json_rpc::{error::IotaRpcInputError, IotaRpcModule}; +use iota_json_rpc_api::{ReadApiServer, QUERY_MAX_RESULT_LIMIT}; +use iota_json_rpc_types::{ + Checkpoint, CheckpointId, CheckpointPage, IotaEvent, IotaGetPastObjectRequest, + IotaLoadedChildObjectsResponse, IotaObjectDataOptions, IotaObjectResponse, + IotaPastObjectResponse, IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, + ProtocolConfigResponse, +}; +use iota_open_rpc::Module; +use iota_protocol_config::{ProtocolConfig, ProtocolVersion}; +use iota_types::{ + base_types::{ObjectID, SequenceNumber}, + digests::{ChainIdentifier, TransactionDigest}, + error::IotaObjectResponseError, + iota_serde::BigInt, + object::ObjectRead, +}; +use jsonrpsee::{core::RpcResult, RpcModule}; + +use crate::{errors::IndexerError, indexer_reader::IndexerReader}; + +#[derive(Clone)] +pub(crate) struct ReadApi { + inner: IndexerReader, +} + +impl ReadApi { + pub fn new(inner: IndexerReader) -> Self { + Self { inner } + } + + async fn get_checkpoint(&self, id: CheckpointId) -> Result { + match self + .inner + .spawn_blocking(move |this| this.get_checkpoint(id)) + .await + { + Ok(Some(epoch_info)) => Ok(epoch_info), + Ok(None) => Err(IndexerError::InvalidArgumentError(format!( + "Checkpoint {id:?} not found" + ))), + Err(e) => Err(e), + } + } + + async fn get_latest_checkpoint(&self) -> Result { + self.inner + .spawn_blocking(|this| this.get_latest_checkpoint()) + .await + } + + async fn get_chain_identifier(&self) -> RpcResult { + let genesis_checkpoint = self.get_checkpoint(CheckpointId::SequenceNumber(0)).await?; + Ok(ChainIdentifier::from(genesis_checkpoint.digest)) + } +} + +#[async_trait] +impl ReadApiServer for ReadApi { + async fn get_object( + &self, + object_id: ObjectID, + options: Option, + ) -> RpcResult { + let options = options.unwrap_or_default(); + let object_read = self + .inner + .get_object_read_in_blocking_task(object_id) + .await?; + + match object_read { + ObjectRead::NotExists(id) => Ok(IotaObjectResponse::new_with_error( + IotaObjectResponseError::NotExists { object_id: id }, + )), + ObjectRead::Exists(object_ref, o, layout) => { + let mut display_fields = None; + if options.show_display { + match self.inner.get_display_fields(&o, &layout).await { + Ok(rendered_fields) => display_fields = Some(rendered_fields), + Err(e) => { + return Ok(IotaObjectResponse::new( + Some((object_ref, o, layout, options, None).try_into()?), + Some(IotaObjectResponseError::DisplayError { + error: e.to_string(), + }), + )); + } + } + } + Ok(IotaObjectResponse::new_with_data( + (object_ref, o, layout, options, display_fields).try_into()?, + )) + } + ObjectRead::Deleted((object_id, version, digest)) => Ok( + IotaObjectResponse::new_with_error(IotaObjectResponseError::Deleted { + object_id, + version, + digest, + }), + ), + } + } + + // For ease of implementation we just forward to the single object query, + // although in the future we may want to improve the performance by having a + // more naitive multi_get functionality + async fn multi_get_objects( + &self, + object_ids: Vec, + options: Option, + ) -> RpcResult> { + if object_ids.len() > *QUERY_MAX_RESULT_LIMIT { + return Err( + IotaRpcInputError::SizeLimitExceeded(QUERY_MAX_RESULT_LIMIT.to_string()).into(), + ); + } + + let mut futures = vec![]; + for object_id in object_ids { + futures.push(self.get_object(object_id, options.clone())); + } + + futures::future::join_all(futures) + .await + .into_iter() + .collect::, _>>() + } + + async fn get_total_transaction_blocks(&self) -> RpcResult> { + let checkpoint = self.get_latest_checkpoint().await?; + Ok(BigInt::from(checkpoint.network_total_transactions)) + } + + async fn get_transaction_block( + &self, + digest: TransactionDigest, + options: Option, + ) -> RpcResult { + let mut txn = self + .multi_get_transaction_blocks(vec![digest], options) + .await?; + + let txn = txn.pop().ok_or_else(|| { + IndexerError::InvalidArgumentError(format!("Transaction {digest} not found")) + })?; + + Ok(txn) + } + + async fn multi_get_transaction_blocks( + &self, + digests: Vec, + options: Option, + ) -> RpcResult> { + let num_digests = digests.len(); + if num_digests > *QUERY_MAX_RESULT_LIMIT { + Err(IotaRpcInputError::SizeLimitExceeded( + QUERY_MAX_RESULT_LIMIT.to_string(), + ))? + } + + let options = options.unwrap_or_default(); + let txns = self + .inner + .multi_get_transaction_block_response_in_blocking_task(digests, options) + .await?; + + Ok(txns) + } + + async fn try_get_past_object( + &self, + _object_id: ObjectID, + _version: SequenceNumber, + _options: Option, + ) -> RpcResult { + Err(jsonrpsee::types::error::CallError::Custom( + jsonrpsee::types::error::ErrorCode::MethodNotFound.into(), + ) + .into()) + } + + async fn try_multi_get_past_objects( + &self, + _past_objects: Vec, + _options: Option, + ) -> RpcResult> { + Err(jsonrpsee::types::error::CallError::Custom( + jsonrpsee::types::error::ErrorCode::MethodNotFound.into(), + ) + .into()) + } + + async fn get_latest_checkpoint_sequence_number(&self) -> RpcResult> { + let checkpoint = self.get_latest_checkpoint().await?; + Ok(BigInt::from(checkpoint.sequence_number)) + } + + async fn get_checkpoint(&self, id: CheckpointId) -> RpcResult { + self.get_checkpoint(id).await.map_err(Into::into) + } + + async fn get_checkpoints( + &self, + cursor: Option>, + limit: Option, + descending_order: bool, + ) -> RpcResult { + let cursor = cursor.map(BigInt::into_inner); + let limit = iota_json_rpc_api::validate_limit( + limit, + iota_json_rpc_api::QUERY_MAX_RESULT_LIMIT_CHECKPOINTS, + ) + .map_err(IotaRpcInputError::from)?; + + let mut checkpoints = self + .inner + .spawn_blocking(move |this| this.get_checkpoints(cursor, limit + 1, descending_order)) + .await?; + + let has_next_page = checkpoints.len() > limit; + checkpoints.truncate(limit); + + let next_cursor = checkpoints.last().map(|d| d.sequence_number.into()); + + Ok(CheckpointPage { + data: checkpoints, + next_cursor, + has_next_page, + }) + } + + async fn get_checkpoints_deprecated_limit( + &self, + cursor: Option>, + limit: Option>, + descending_order: bool, + ) -> RpcResult { + self.get_checkpoints( + cursor, + limit.map(|l| l.into_inner() as usize), + descending_order, + ) + .await + } + + async fn get_events(&self, transaction_digest: TransactionDigest) -> RpcResult> { + self.inner + .get_transaction_events_in_blocking_task(transaction_digest) + .await + .map_err(Into::into) + } + + async fn get_loaded_child_objects( + &self, + _digest: TransactionDigest, + ) -> RpcResult { + Err(jsonrpsee::types::error::CallError::Custom( + jsonrpsee::types::error::ErrorCode::MethodNotFound.into(), + ) + .into()) + } + + async fn get_protocol_config( + &self, + version: Option>, + ) -> RpcResult { + let chain = self.get_chain_identifier().await?.chain(); + let version = if let Some(version) = version { + (*version).into() + } else { + let latest_epoch = self + .inner + .spawn_blocking(|this| this.get_latest_epoch_info_from_db()) + .await?; + (latest_epoch.protocol_version as u64).into() + }; + + ProtocolConfig::get_for_version_if_supported(version, chain) + .ok_or(IotaRpcInputError::ProtocolVersionUnsupported( + ProtocolVersion::MIN.as_u64(), + ProtocolVersion::MAX.as_u64(), + )) + .map_err(Into::into) + .map(ProtocolConfigResponse::from) + } + + async fn get_chain_identifier(&self) -> RpcResult { + self.get_chain_identifier().await.map(|id| id.to_string()) + } +} + +impl IotaRpcModule for ReadApi { + fn rpc(self) -> RpcModule { + self.into_rpc() + } + + fn rpc_doc_module() -> Module { + iota_json_rpc_api::ReadApiOpenRpc::module_doc() + } +} diff --git a/crates/iota-indexer/src/apis/transaction_builder_api.rs b/crates/iota-indexer/src/apis/transaction_builder_api.rs new file mode 100644 index 00000000000..7fb62fed9a9 --- /dev/null +++ b/crates/iota-indexer/src/apis/transaction_builder_api.rs @@ -0,0 +1,77 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use iota_json_rpc::transaction_builder_api::TransactionBuilderApi as IotaTransactionBuilderApi; +use iota_json_rpc_types::{IotaObjectDataFilter, IotaObjectDataOptions, IotaObjectResponse}; +use iota_transaction_builder::DataReader; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectInfo}, + object::Object, +}; +use move_core_types::language_storage::StructTag; + +use super::governance_api::GovernanceReadApi; +use crate::indexer_reader::IndexerReader; + +pub(crate) struct TransactionBuilderApi { + inner: IndexerReader, +} + +impl TransactionBuilderApi { + #[allow(clippy::new_ret_no_self)] + pub fn new(inner: IndexerReader) -> IotaTransactionBuilderApi { + IotaTransactionBuilderApi::new_with_data_reader(std::sync::Arc::new(Self { inner })) + } +} + +#[async_trait] +impl DataReader for TransactionBuilderApi { + async fn get_owned_objects( + &self, + address: IotaAddress, + object_type: StructTag, + ) -> Result, anyhow::Error> { + let stored_objects = self + .inner + .get_owned_objects_in_blocking_task( + address, + Some(IotaObjectDataFilter::StructType(object_type)), + None, + 50, // Limit the number of objects returned to 50 + ) + .await?; + + stored_objects + .into_iter() + .map(|object| { + let object = Object::try_from(object)?; + let object_ref = object.compute_object_reference(); + let info = ObjectInfo::new(&object_ref, &object); + Ok(info) + }) + .collect::, _>>() + } + + async fn get_object_with_options( + &self, + object_id: ObjectID, + options: IotaObjectDataOptions, + ) -> Result { + let result = self + .inner + .get_object_read_in_blocking_task(object_id) + .await?; + Ok((result, options).try_into()?) + } + + async fn get_reference_gas_price(&self) -> Result { + let epoch_info = GovernanceReadApi::new(self.inner.clone()) + .get_epoch_info(None) + .await?; + Ok(epoch_info + .reference_gas_price + .ok_or_else(|| anyhow::anyhow!("missing latest reference_gas_price"))?) + } +} diff --git a/crates/iota-indexer/src/apis/write_api.rs b/crates/iota-indexer/src/apis/write_api.rs new file mode 100644 index 00000000000..40d57a3ca8c --- /dev/null +++ b/crates/iota-indexer/src/apis/write_api.rs @@ -0,0 +1,88 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use fastcrypto::encoding::Base64; +use iota_json_rpc::IotaRpcModule; +use iota_json_rpc_api::{WriteApiClient, WriteApiServer}; +use iota_json_rpc_types::{ + DevInspectArgs, DevInspectResults, DryRunTransactionBlockResponse, + IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, +}; +use iota_open_rpc::Module; +use iota_types::{ + base_types::IotaAddress, iota_serde::BigInt, quorum_driver_types::ExecuteTransactionRequestType, +}; +use jsonrpsee::{core::RpcResult, http_client::HttpClient, RpcModule}; + +use crate::types::IotaTransactionBlockResponseWithOptions; + +pub(crate) struct WriteApi { + fullnode: HttpClient, +} + +impl WriteApi { + pub fn new(fullnode_client: HttpClient) -> Self { + Self { + fullnode: fullnode_client, + } + } +} + +#[async_trait] +impl WriteApiServer for WriteApi { + async fn execute_transaction_block( + &self, + tx_bytes: Base64, + signatures: Vec, + options: Option, + request_type: Option, + ) -> RpcResult { + let iota_transaction_response = self + .fullnode + .execute_transaction_block(tx_bytes, signatures, options.clone(), request_type) + .await?; + Ok(IotaTransactionBlockResponseWithOptions { + response: iota_transaction_response, + options: options.unwrap_or_default(), + } + .into()) + } + + async fn dev_inspect_transaction_block( + &self, + sender_address: IotaAddress, + tx_bytes: Base64, + gas_price: Option>, + epoch: Option>, + additional_args: Option, + ) -> RpcResult { + self.fullnode + .dev_inspect_transaction_block( + sender_address, + tx_bytes, + gas_price, + epoch, + additional_args, + ) + .await + } + + async fn dry_run_transaction_block( + &self, + tx_bytes: Base64, + ) -> RpcResult { + self.fullnode.dry_run_transaction_block(tx_bytes).await + } +} + +impl IotaRpcModule for WriteApi { + fn rpc(self) -> RpcModule { + self.into_rpc() + } + + fn rpc_doc_module() -> Module { + iota_json_rpc_api::WriteApiOpenRpc::module_doc() + } +} diff --git a/crates/sui-indexer/src/db.rs b/crates/iota-indexer/src/db.rs similarity index 99% rename from crates/sui-indexer/src/db.rs rename to crates/iota-indexer/src/db.rs index 88bea7111cb..9f48cd3e2cf 100644 --- a/crates/sui-indexer/src/db.rs +++ b/crates/iota-indexer/src/db.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::time::Duration; diff --git a/crates/iota-indexer/src/errors.rs b/crates/iota-indexer/src/errors.rs new file mode 100644 index 00000000000..6f0299d1269 --- /dev/null +++ b/crates/iota-indexer/src/errors.rs @@ -0,0 +1,157 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use fastcrypto::error::FastCryptoError; +use iota_json_rpc::name_service::NameServiceError; +use iota_types::{ + base_types::ObjectIDParseError, + error::{IotaError, IotaObjectResponseError, UserInputError}, +}; +use jsonrpsee::{core::Error as RpcError, types::error::CallError}; +use thiserror::Error; + +#[derive(Debug, Error)] +pub struct DataDownloadError { + pub error: IndexerError, + pub next_checkpoint_sequence_number: u64, +} + +impl std::fmt::Display for DataDownloadError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "next_checkpoint_seq: {}, error: {}", + self.next_checkpoint_sequence_number, self.error + ) + } +} + +#[derive(Debug, Error)] +pub enum IndexerError { + #[error("Indexer failed to convert timestamp to NaiveDateTime with error: `{0}`")] + DateTimeParsingError(String), + + #[error("Indexer failed to deserialize event from events table with error: `{0}`")] + EventDeserializationError(String), + + #[error( + "Fullnode returns unexpected responses, which may block indexers from proceeding, with error: `{0}`" + )] + UnexpectedFullnodeResponseError(String), + + #[error("Indexer failed to transform data with error: `{0}`")] + DataTransformationError(String), + + #[error("Indexer failed to read fullnode with error: `{0}`")] + FullNodeReadingError(String), + + #[error("Indexer failed to convert structs to diesel Insertable with error: `{0}`")] + InsertableParsingError(String), + + #[error("Indexer failed to build JsonRpcServer with error: `{0}`")] + JsonRpcServerError(#[from] iota_json_rpc::error::Error), + + #[error("Indexer failed to find object mutations, which should never happen.")] + ObjectMutationNotAvailable, + + #[error("Indexer failed to build PG connection pool with error: `{0}`")] + PgConnectionPoolInitError(String), + + #[error("Indexer failed to get a pool connection from PG connection pool with error: `{0}`")] + PgPoolConnectionError(String), + + #[error("Indexer failed to read PostgresDB with error: `{0}`")] + PostgresReadError(String), + + #[error("Indexer failed to reset PostgresDB with error: `{0}`")] + PostgresResetError(String), + + #[error("Indexer failed to commit changes to PostgresDB with error: `{0}`")] + PostgresWriteError(String), + + #[error(transparent)] + PostgresError(#[from] diesel::result::Error), + + #[error("Indexer failed to initialize fullnode Http client with error: `{0}`")] + HttpClientInitError(String), + + #[error("Indexer failed to serialize/deserialize with error: `{0}`")] + SerdeError(String), + + #[error("Indexer error related to dynamic field: `{0}`")] + DynamicFieldError(String), + + #[error("Indexer does not support the feature with error: `{0}`")] + NotSupportedError(String), + + #[error("Indexer read corrupted/incompatible data from persistent storage: `{0}`")] + PersistentStorageDataCorruptionError(String), + + #[error("Indexer generic error: `{0}`")] + GenericError(String), + + #[error("Indexer failed to resolve object to move struct with error: `{0}`")] + ResolveMoveStructError(String), + + #[error(transparent)] + UncategorizedError(#[from] anyhow::Error), + + #[error(transparent)] + ObjectIdParseError(#[from] ObjectIDParseError), + + #[error("Invalid transaction digest with error: `{0}`")] + InvalidTransactionDigestError(String), + + #[error(transparent)] + IotaError(#[from] IotaError), + + #[error(transparent)] + BcsError(#[from] bcs::Error), + + #[error("Invalid argument with error: `{0}`")] + InvalidArgumentError(String), + + #[error(transparent)] + UserInputError(#[from] UserInputError), + + #[error("Indexer failed to resolve module with error: `{0}`")] + ModuleResolutionError(String), + + #[error(transparent)] + ObjectResponseError(#[from] IotaObjectResponseError), + + #[error(transparent)] + FastCryptoError(#[from] FastCryptoError), + + #[error("`{0}`: `{1}`")] + ErrorWithContext(String, Box), + + #[error("Indexer failed to send item to channel with error: `{0}`")] + MpscChannelError(String), + + #[error(transparent)] + NameServiceError(#[from] NameServiceError), +} + +pub trait Context { + fn context(self, context: &str) -> Result; +} + +impl Context for Result { + fn context(self, context: &str) -> Result { + self.map_err(|e| IndexerError::ErrorWithContext(context.to_string(), Box::new(e))) + } +} + +impl From for RpcError { + fn from(e: IndexerError) -> Self { + RpcError::Call(CallError::Failed(e.into())) + } +} + +impl From for IndexerError { + fn from(value: tokio::task::JoinError) -> Self { + IndexerError::UncategorizedError(anyhow::Error::from(value)) + } +} diff --git a/crates/iota-indexer/src/framework/builder.rs b/crates/iota-indexer/src/framework/builder.rs new file mode 100644 index 00000000000..5cafaf45d59 --- /dev/null +++ b/crates/iota-indexer/src/framework/builder.rs @@ -0,0 +1,87 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_types::messages_checkpoint::CheckpointSequenceNumber; + +use super::{fetcher::CheckpointFetcher, Handler}; +use crate::metrics::IndexerMetrics; + +pub struct IndexerBuilder { + rest_url: Option, + handlers: Vec>, + last_downloaded_checkpoint: Option, + checkpoint_buffer_size: usize, + metrics: IndexerMetrics, +} + +impl IndexerBuilder { + const DEFAULT_CHECKPOINT_BUFFER_SIZE: usize = 1000; + + #[allow(clippy::new_without_default)] + pub fn new(metrics: IndexerMetrics) -> Self { + Self { + rest_url: None, + handlers: Vec::new(), + last_downloaded_checkpoint: None, + checkpoint_buffer_size: Self::DEFAULT_CHECKPOINT_BUFFER_SIZE, + metrics, + } + } + + pub fn rest_url>(mut self, rest_url: T) -> Self { + self.rest_url = Some(rest_url.into()); + self + } + + pub fn handler(mut self, handler: T) -> Self { + self.handlers.push(Box::new(handler)); + self + } + + pub fn last_downloaded_checkpoint( + mut self, + last_downloaded_checkpoint: Option, + ) -> Self { + self.last_downloaded_checkpoint = last_downloaded_checkpoint; + self + } + + pub fn checkpoint_buffer_size(mut self, checkpoint_buffer_size: usize) -> Self { + self.checkpoint_buffer_size = checkpoint_buffer_size; + self + } + + pub async fn run(self) { + let (downloaded_checkpoint_data_sender, downloaded_checkpoint_data_receiver) = + mysten_metrics::metered_channel::channel( + self.checkpoint_buffer_size, + &mysten_metrics::get_metrics() + .unwrap() + .channels + .with_label_values(&["checkpoint_tx_downloading"]), + ); + + // experimental rest api route is found at `/rest` on the same interface as the + // jsonrpc service + let rest_api_url = format!("{}/rest", self.rest_url.unwrap()); + let fetcher = CheckpointFetcher::new( + iota_rest_api::Client::new(rest_api_url), + self.last_downloaded_checkpoint, + downloaded_checkpoint_data_sender, + self.metrics.clone(), + ); + mysten_metrics::spawn_monitored_task!(fetcher.run()); + + assert!(!self.handlers.is_empty()); + + super::runner::run( + mysten_metrics::metered_channel::ReceiverStream::new( + downloaded_checkpoint_data_receiver, + ), + self.handlers, + self.metrics.clone(), + ) + .await; + } +} diff --git a/crates/sui-indexer/src/framework/fetcher.rs b/crates/iota-indexer/src/framework/fetcher.rs similarity index 96% rename from crates/sui-indexer/src/framework/fetcher.rs rename to crates/iota-indexer/src/framework/fetcher.rs index 2ba32cdb2c8..9bdcb88f49b 100644 --- a/crates/sui-indexer/src/framework/fetcher.rs +++ b/crates/iota-indexer/src/framework/fetcher.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; -use sui_rest_api::{CheckpointData, Client}; -use sui_types::messages_checkpoint::CheckpointSequenceNumber; +use iota_rest_api::{CheckpointData, Client}; +use iota_types::messages_checkpoint::CheckpointSequenceNumber; use tracing::{info, warn}; use crate::metrics::IndexerMetrics; diff --git a/crates/sui-indexer/src/framework/interface.rs b/crates/iota-indexer/src/framework/interface.rs similarity index 90% rename from crates/sui-indexer/src/framework/interface.rs rename to crates/iota-indexer/src/framework/interface.rs index fa3c98215ce..1be5c2b3ef7 100644 --- a/crates/sui-indexer/src/framework/interface.rs +++ b/crates/iota-indexer/src/framework/interface.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; -use sui_rest_api::CheckpointData; -use sui_types::messages_checkpoint::CheckpointSequenceNumber; +use iota_rest_api::CheckpointData; +use iota_types::messages_checkpoint::CheckpointSequenceNumber; #[async_trait::async_trait] pub trait Handler: Send { diff --git a/crates/iota-indexer/src/framework/mod.rs b/crates/iota-indexer/src/framework/mod.rs new file mode 100644 index 00000000000..338b63592d1 --- /dev/null +++ b/crates/iota-indexer/src/framework/mod.rs @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod builder; +pub mod interface; + +// TODO remove the pub(crater) once indexer.rs is renamed to lib.rs +pub(crate) mod fetcher; +pub(crate) mod runner; + +pub use builder::IndexerBuilder; +pub use interface::Handler; diff --git a/crates/sui-indexer/src/framework/runner.rs b/crates/iota-indexer/src/framework/runner.rs similarity index 97% rename from crates/sui-indexer/src/framework/runner.rs rename to crates/iota-indexer/src/framework/runner.rs index 76f45f67867..cf1af3f105e 100644 --- a/crates/sui-indexer/src/framework/runner.rs +++ b/crates/iota-indexer/src/framework/runner.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use super::{fetcher::CheckpointDownloadData, interface::Handler}; diff --git a/crates/iota-indexer/src/handlers/checkpoint_handler.rs b/crates/iota-indexer/src/handlers/checkpoint_handler.rs new file mode 100644 index 00000000000..02570d81e0d --- /dev/null +++ b/crates/iota-indexer/src/handlers/checkpoint_handler.rs @@ -0,0 +1,892 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{hash_map::Entry, BTreeMap, HashMap, HashSet}, + sync::{Arc, Mutex}, +}; + +use async_trait::async_trait; +use iota_json_rpc_types::IotaMoveValue; +use iota_package_resolver::{PackageStore, Resolver}; +use iota_rest_api::{CheckpointData, CheckpointTransaction}; +use iota_types::{ + base_types::{ObjectID, ObjectRef, SequenceNumber}, + dynamic_field::{DynamicFieldInfo, DynamicFieldName, DynamicFieldType}, + effects::{TransactionEffects, TransactionEffectsAPI}, + event::SystemEpochInfoEvent, + iota_system_state::{ + get_iota_system_state, iota_system_state_summary::IotaSystemStateSummary, + IotaSystemStateTrait, + }, + messages_checkpoint::{CertifiedCheckpointSummary, CheckpointContents}, + object::{Object, Owner}, + transaction::TransactionDataAPI, +}; +use itertools::Itertools; +use move_core_types::{ + annotated_value::{MoveStructLayout, MoveTypeLayout}, + language_storage::{StructTag, TypeTag}, +}; +use mysten_metrics::{get_metrics, spawn_monitored_task}; +use tap::tap::TapFallible; +use tokio::sync::watch; +use tracing::{error, info, warn}; + +use super::{ + tx_processor::{EpochEndIndexingObjectStore, TxChangesProcessor}, + CheckpointDataToCommit, EpochToCommit, TransactionObjectChangesToCommit, +}; +use crate::{ + db::PgConnectionPool, + errors::IndexerError, + framework::interface::Handler, + handlers::{committer::start_tx_checkpoint_commit_task, tx_processor::IndexingPackageBuffer}, + metrics::IndexerMetrics, + models::display::StoredDisplay, + store::{ + module_resolver::{IndexerStorePackageModuleResolver, InterimPackageResolver}, + IndexerStore, PgIndexerStore, + }, + types::{ + IndexedCheckpoint, IndexedDeletedObject, IndexedEpochInfo, IndexedEvent, IndexedObject, + IndexedPackage, IndexedTransaction, IndexerResult, TransactionKind, TxIndex, + }, +}; + +const CHECKPOINT_QUEUE_SIZE: usize = 100; + +pub async fn new_handlers( + state: S, + metrics: IndexerMetrics, +) -> Result, IndexerError> +where + S: IndexerStore + Clone + Sync + Send + 'static, +{ + let checkpoint_queue_size = std::env::var("CHECKPOINT_QUEUE_SIZE") + .unwrap_or(CHECKPOINT_QUEUE_SIZE.to_string()) + .parse::() + .unwrap(); + let global_metrics = get_metrics().unwrap(); + let (indexed_checkpoint_sender, indexed_checkpoint_receiver) = + mysten_metrics::metered_channel::channel( + checkpoint_queue_size, + &global_metrics + .channels + .with_label_values(&["checkpoint_indexing"]), + ); + + let state_clone = state.clone(); + let metrics_clone = metrics.clone(); + let (tx, package_tx) = watch::channel(None); + spawn_monitored_task!(start_tx_checkpoint_commit_task( + state_clone, + metrics_clone, + indexed_checkpoint_receiver, + tx, + )); + + let checkpoint_handler = CheckpointHandler { + state, + metrics, + indexed_checkpoint_sender, + package_buffer: IndexingPackageBuffer::start(package_tx), + }; + + Ok(checkpoint_handler) +} + +pub struct CheckpointHandler { + state: S, + metrics: IndexerMetrics, + indexed_checkpoint_sender: mysten_metrics::metered_channel::Sender, + // buffers for packages that are being indexed but not committed to DB, + // they will be periodically GCed to avoid OOM. + package_buffer: Arc>, +} + +#[async_trait] +impl Handler for CheckpointHandler +where + S: IndexerStore + Clone + Sync + Send + 'static, +{ + fn name(&self) -> &str { + "checkpoint-handler" + } + async fn process_checkpoints(&mut self, checkpoints: &[CheckpointData]) -> anyhow::Result<()> { + if checkpoints.is_empty() { + return Ok(()); + } + // Safe to unwrap, checked emptiness above + let first_checkpoint_seq = checkpoints + .first() + .unwrap() + .checkpoint_summary + .sequence_number(); + let last_checkpoint_seq = checkpoints + .last() + .unwrap() + .checkpoint_summary + .sequence_number(); + info!( + first = first_checkpoint_seq, + last = last_checkpoint_seq, + "Checkpoints received by CheckpointHandler" + ); + + let indexing_timer = self.metrics.checkpoint_index_latency.start_timer(); + // It's important to index packages first to populate ModuleResolver + let packages = Self::index_packages(checkpoints, &self.metrics); + let package_objects = Self::get_package_objects(checkpoints); + + let pg_blocking_cp = self.pg_blocking_cp()?; + let module_package_db_resolver = IndexerStorePackageModuleResolver::new(pg_blocking_cp); + let in_mem_package_resolver = InterimPackageResolver::new( + module_package_db_resolver, + self.package_buffer.clone(), + &package_objects, + self.metrics.clone(), + ); + let package_resolver = Arc::new(Resolver::new(in_mem_package_resolver)); + + let mut packages_per_checkpoint: HashMap<_, Vec<_>> = HashMap::new(); + for package in packages { + packages_per_checkpoint + .entry(package.checkpoint_sequence_number) + .or_default() + .push(package); + } + let mut tasks = vec![]; + let state_clone = Arc::new(self.state.clone()); + let metrics_clone = Arc::new(self.metrics.clone()); + for checkpoint in checkpoints { + let packages = packages_per_checkpoint + .remove(checkpoint.checkpoint_summary.sequence_number()) + .unwrap_or_default(); + tasks.push(tokio::task::spawn(Self::index_one_checkpoint( + state_clone.clone(), + checkpoint.clone(), + metrics_clone.clone(), + packages, + package_resolver.clone(), + ))); + } + let checkpoint_data_to_commit = futures::future::join_all(tasks) + .await + .into_iter() + .collect::, _>>() + .tap_err(|e| { + error!( + "Failed to join all checkpoint indexing tasks with error: {}", + e.to_string() + ); + })? + .into_iter() + .collect::, _>>() + .tap_err(|e| { + error!("Failed to index checkpoints with error: {}", e.to_string()); + })?; + let elapsed = indexing_timer.stop_and_record(); + + info!( + first = first_checkpoint_seq, + last = last_checkpoint_seq, + elapsed, + "Checkpoints indexing finished, about to sending to commit handler" + ); + + // NOTE: when the channel is full, checkpoint_sender_guard will wait until the + // channel has space. Checkpoints are sent sequentially to stick to the + // order of checkpoint sequence numbers. + for checkpoint_data in checkpoint_data_to_commit { + let checkpoint_seq = checkpoint_data.checkpoint.sequence_number; + self.indexed_checkpoint_sender + .send(checkpoint_data) + .await + .tap_ok(|_| info!(checkpoint_seq, "Checkpoint sent to commit handler")) + .unwrap_or_else(|e| { + panic!( + "checkpoint channel send should not fail, but got error: {:?}", + e + ) + }); + } + Ok(()) + } +} + +impl CheckpointHandler +where + S: IndexerStore + Clone + Sync + Send + 'static, +{ + async fn index_epoch( + state: Arc, + data: &CheckpointData, + ) -> Result, IndexerError> { + let checkpoint_object_store = EpochEndIndexingObjectStore::new(data); + + let CheckpointData { + transactions, + checkpoint_summary, + checkpoint_contents: _, + } = data; + + // Genesis epoch + if *checkpoint_summary.sequence_number() == 0 { + info!("Processing genesis epoch"); + let system_state: IotaSystemStateSummary = + get_iota_system_state(&checkpoint_object_store)?.into_iota_system_state_summary(); + return Ok(Some(EpochToCommit { + last_epoch: None, + new_epoch: IndexedEpochInfo::from_new_system_state_summary( + system_state, + 0, // first_checkpoint_id + None, + ), + })); + } + + // If not end of epoch, return + if checkpoint_summary.end_of_epoch_data.is_none() { + return Ok(None); + } + + let system_state: IotaSystemStateSummary = + get_iota_system_state(&checkpoint_object_store)?.into_iota_system_state_summary(); + + let epoch_event = transactions + .iter() + .flat_map(|t| t.events.as_ref().map(|e| &e.data)) + .flatten() + .find(|ev| ev.is_system_epoch_info_event()) + .unwrap_or_else(|| { + panic!( + "Can't find SystemEpochInfoEvent in epoch end checkpoint {}", + checkpoint_summary.sequence_number() + ) + }); + + let event = bcs::from_bytes::(&epoch_event.contents)?; + + // Now we just entered epoch X, we want to calculate the diff between + // TotalTransactionsByEndOfEpoch(X-1) and TotalTransactionsByEndOfEpoch(X-2) + let network_tx_count_prev_epoch = match system_state.epoch { + // If first epoch change, this number is 0 + 1 => Ok(0), + _ => { + let last_epoch = system_state.epoch - 2; + state + .get_network_total_transactions_by_end_of_epoch(last_epoch) + .await + } + }?; + + Ok(Some(EpochToCommit { + last_epoch: Some(IndexedEpochInfo::from_end_of_epoch_data( + &system_state, + checkpoint_summary, + &event, + network_tx_count_prev_epoch, + )), + new_epoch: IndexedEpochInfo::from_new_system_state_summary( + system_state, + checkpoint_summary.sequence_number + 1, // first_checkpoint_id + Some(&event), + ), + })) + } + + async fn index_one_checkpoint( + state: Arc, + data: CheckpointData, + metrics: Arc, + packages: Vec, + package_resolver: Arc>, + ) -> Result { + let checkpoint_seq = data.checkpoint_summary.sequence_number; + info!(checkpoint_seq, "Indexing checkpoint data blob"); + + // Index epoch + let epoch = Self::index_epoch(state, &data).await?; + + // Index Objects + let object_changes: TransactionObjectChangesToCommit = + Self::index_objects(data.clone(), &metrics, package_resolver.clone()).await?; + let object_history_changes: TransactionObjectChangesToCommit = + Self::index_objects_history(data.clone(), package_resolver.clone()).await?; + + let (checkpoint, db_transactions, db_events, db_indices, db_displays) = { + let CheckpointData { + transactions, + checkpoint_summary, + checkpoint_contents, + } = data; + + let (db_transactions, db_events, db_indices, db_displays) = Self::index_transactions( + transactions, + &checkpoint_summary, + &checkpoint_contents, + &metrics, + ) + .await?; + + let successful_tx_num: u64 = db_transactions.iter().map(|t| t.successful_tx_num).sum(); + ( + IndexedCheckpoint::from_iota_checkpoint( + &checkpoint_summary, + &checkpoint_contents, + successful_tx_num as usize, + ), + db_transactions, + db_events, + db_indices, + db_displays, + ) + }; + info!(checkpoint_seq, "Indexed one checkpoint."); + Ok(CheckpointDataToCommit { + checkpoint, + transactions: db_transactions, + events: db_events, + tx_indices: db_indices, + display_updates: db_displays, + object_changes, + object_history_changes, + packages, + epoch, + }) + } + + async fn index_transactions( + transactions: Vec, + checkpoint_summary: &CertifiedCheckpointSummary, + checkpoint_contents: &CheckpointContents, + metrics: &IndexerMetrics, + ) -> IndexerResult<( + Vec, + Vec, + Vec, + BTreeMap, + )> { + let checkpoint_seq = checkpoint_summary.sequence_number(); + + let mut tx_seq_num_iter = checkpoint_contents + .enumerate_transactions(checkpoint_summary) + .map(|(seq, execution_digest)| (execution_digest.transaction, seq)); + + if checkpoint_contents.size() != transactions.len() { + return Err(IndexerError::FullNodeReadingError(format!( + "CheckpointContents has different size {} compared to Transactions {} for checkpoint {}", + checkpoint_contents.size(), + transactions.len(), + checkpoint_seq + ))); + } + + let mut db_transactions = Vec::new(); + let mut db_events = Vec::new(); + let mut db_displays = BTreeMap::new(); + let mut db_indices = Vec::new(); + + for tx in transactions { + let CheckpointTransaction { + transaction: sender_signed_data, + effects: fx, + events, + input_objects, + output_objects, + } = tx; + // Unwrap safe - we checked they have equal length above + let (tx_digest, tx_sequence_number) = tx_seq_num_iter.next().unwrap(); + if tx_digest != *sender_signed_data.digest() { + return Err(IndexerError::FullNodeReadingError(format!( + "Transactions has different ordering from CheckpointContents, for checkpoint {}, Mismatch found at {} v.s. {}", + checkpoint_seq, + tx_digest, + sender_signed_data.digest() + ))); + } + let tx = sender_signed_data.transaction_data(); + let events = events + .as_ref() + .map(|events| events.data.clone()) + .unwrap_or_default(); + + let transaction_kind = if tx.is_system_tx() { + TransactionKind::SystemTransaction + } else { + TransactionKind::ProgrammableTransaction + }; + + db_events.extend(events.iter().enumerate().map(|(idx, event)| { + IndexedEvent::from_event( + tx_sequence_number, + idx as u64, + *checkpoint_seq, + tx_digest, + event, + checkpoint_summary.timestamp_ms, + ) + })); + + db_displays.extend( + events + .iter() + .flat_map(StoredDisplay::try_from_event) + .map(|display| (display.object_type.clone(), display)), + ); + + let objects = input_objects + .iter() + .chain(output_objects.iter()) + .collect::>(); + + let (balance_change, object_changes) = + TxChangesProcessor::new(&objects, metrics.clone()) + .get_changes(tx, &fx, &tx_digest) + .await?; + + let db_txn = IndexedTransaction { + tx_sequence_number, + tx_digest, + checkpoint_sequence_number: *checkpoint_summary.sequence_number(), + timestamp_ms: checkpoint_summary.timestamp_ms, + sender_signed_data: sender_signed_data.data().clone(), + effects: fx.clone(), + object_changes, + balance_change, + events, + transaction_kind, + successful_tx_num: if fx.status().is_ok() { + tx.kind().tx_count() as u64 + } else { + 0 + }, + }; + + db_transactions.push(db_txn); + + // Input Objects + let input_objects = tx + .input_objects() + .expect("committed txns have been validated") + .into_iter() + .map(|obj_kind| obj_kind.object_id()) + .collect::>(); + + // Changed Objects + let changed_objects = fx + .all_changed_objects() + .into_iter() + .map(|(object_ref, _owner, _write_kind)| object_ref.0) + .collect::>(); + + // Payers + let payers = vec![tx.gas_owner()]; + + // Senders + let senders = vec![tx.sender()]; + + // Recipients + let recipients = fx + .all_changed_objects() + .into_iter() + .filter_map(|(_object_ref, owner, _write_kind)| match owner { + Owner::AddressOwner(address) => Some(address), + _ => None, + }) + .unique() + .collect::>(); + + // Move Calls + let move_calls = tx + .move_calls() + .iter() + .map(|(p, m, f)| (*<&ObjectID>::clone(p), m.to_string(), f.to_string())) + .collect(); + + db_indices.push(TxIndex { + tx_sequence_number, + transaction_digest: tx_digest, + checkpoint_sequence_number: *checkpoint_seq, + input_objects, + changed_objects, + senders, + payers, + recipients, + move_calls, + }); + } + Ok((db_transactions, db_events, db_indices, db_displays)) + } + + async fn index_objects( + data: CheckpointData, + metrics: &IndexerMetrics, + package_resolver: Arc>, + ) -> Result { + let _timer = metrics.indexing_objects_latency.start_timer(); + let checkpoint_seq = data.checkpoint_summary.sequence_number; + let deleted_objects = data + .transactions + .iter() + .flat_map(|tx| get_deleted_objects(&tx.effects)) + .collect::>(); + let deleted_object_ids = deleted_objects + .iter() + .map(|o| (o.0, o.1)) + .collect::>(); + let indexed_deleted_objects = deleted_objects + .into_iter() + .map(|o| IndexedDeletedObject { + object_id: o.0, + object_version: o.1.value(), + checkpoint_sequence_number: checkpoint_seq, + }) + .collect(); + + let (latest_objects, intermediate_versions) = get_latest_objects(data.output_objects()); + + let live_objects: Vec = data + .transactions + .iter() + .flat_map(|tx| { + let CheckpointTransaction { + transaction: tx, + effects: fx, + .. + } = tx; + fx.all_changed_objects() + .into_iter() + .filter_map(|(oref, _owner, _kind)| { + // We don't care about objects that are deleted or updated more than once + if intermediate_versions.contains(&(oref.0, oref.1)) + || deleted_object_ids.contains(&(oref.0, oref.1)) + { + return None; + } + let object = latest_objects.get(&(oref.0)).unwrap_or_else(|| { + panic!( + "object {:?} not found in CheckpointData (tx_digest: {})", + oref.0, + tx.digest() + ) + }); + assert_eq!(oref.1, object.version()); + Some(object.clone()) + }) + .collect::>() + }) + .collect(); + + let move_struct_layout_map = + get_move_struct_layout_map(&live_objects, package_resolver).await?; + let changed_objects = live_objects + .into_iter() + .map(|o| { + let df_info = + try_create_dynamic_field_info(&o, &move_struct_layout_map, &latest_objects); + df_info.map(|info| IndexedObject::from_object(checkpoint_seq, o, info)) + }) + .collect::, _>>()?; + Ok(TransactionObjectChangesToCommit { + changed_objects, + deleted_objects: indexed_deleted_objects, + }) + } + + // similar to index_objects, but objects_history keeps all versions of objects + async fn index_objects_history( + data: CheckpointData, + package_resolver: Arc>, + ) -> Result { + let checkpoint_seq = data.checkpoint_summary.sequence_number; + let deleted_objects = data + .transactions + .iter() + .flat_map(|tx| get_deleted_objects(&tx.effects)) + .collect::>(); + let indexed_deleted_objects: Vec = deleted_objects + .into_iter() + .map(|o| IndexedDeletedObject { + object_id: o.0, + object_version: o.1.value(), + checkpoint_sequence_number: checkpoint_seq, + }) + .collect(); + + let (latest_objects, _) = get_latest_objects(data.output_objects()); + let history_object_map = data + .output_objects() + .into_iter() + .map(|o| ((o.id(), o.version()), o.clone())) + .collect::>(); + + let history_objects: Vec = data + .transactions + .iter() + .flat_map(|tx| { + let CheckpointTransaction { + transaction: tx, + effects: fx, + .. + } = tx; + fx.all_changed_objects() + .into_iter() + .map(|(oref, _owner, _kind)| { + let history_object = history_object_map.get(&(oref.0, oref.1)).unwrap_or_else(|| { + panic!( + "object {:?} version {:?} not found in CheckpointData (tx_digest: {})", + oref.0, + oref.1, + tx.digest() + ) + }); + assert_eq!(oref.2, history_object.digest()); + history_object.clone() + }) + .collect::>() + }) + .collect(); + + let move_struct_layout_map = + get_move_struct_layout_map(&history_objects, package_resolver).await?; + let changed_objects = history_objects + .into_iter() + .map(|o| { + let df_info = + try_create_dynamic_field_info(&o, &move_struct_layout_map, &latest_objects); + df_info.map(|info| IndexedObject::from_object(checkpoint_seq, o, info)) + }) + .collect::, _>>()?; + + Ok(TransactionObjectChangesToCommit { + changed_objects, + deleted_objects: indexed_deleted_objects, + }) + } + + fn index_packages( + checkpoint_data: &[CheckpointData], + metrics: &IndexerMetrics, + ) -> Vec { + let _timer = metrics.indexing_packages_latency.start_timer(); + checkpoint_data + .iter() + .flat_map(|data| { + let checkpoint_sequence_number = data.checkpoint_summary.sequence_number; + data.output_objects() + .iter() + .filter_map(|o| { + if let iota_types::object::Data::Package(p) = &o.data { + Some(IndexedPackage { + package_id: o.id(), + move_package: p.clone(), + checkpoint_sequence_number, + }) + } else { + None + } + }) + .collect::>() + }) + .collect() + } + + fn get_package_objects(checkpoint_data: &[CheckpointData]) -> Vec<(IndexedPackage, Object)> { + checkpoint_data + .iter() + .flat_map(|data| { + let checkpoint_sequence_number = data.checkpoint_summary.sequence_number; + data.output_objects() + .iter() + .filter_map(|o| { + if let iota_types::object::Data::Package(p) = &o.data { + let indexed_pkg = IndexedPackage { + package_id: o.id(), + move_package: p.clone(), + checkpoint_sequence_number, + }; + Some((indexed_pkg, (**o).clone())) + } else { + None + } + }) + .collect::>() + }) + .collect() + } + + fn pg_blocking_cp(&self) -> Result { + let state_as_any = self.state.as_any(); + if let Some(pg_state) = state_as_any.downcast_ref::() { + return Ok(pg_state.blocking_cp()); + } + Err(IndexerError::UncategorizedError(anyhow::anyhow!( + "Failed to downcast state to PgIndexerStore" + ))) + } +} + +async fn get_move_struct_layout_map( + objects: &[Object], + package_resolver: Arc>, +) -> Result, IndexerError> { + let struct_tags = objects + .iter() + .filter_map(|o| { + let move_object = o.data.try_as_move().cloned(); + move_object.map(|move_object| { + let struct_tag: StructTag = move_object.type_().clone().into(); + struct_tag + }) + }) + .collect::>(); + let struct_tags = struct_tags.into_iter().unique().collect::>(); + info!( + "Resolving Move struct layouts for struct tags of size {}.", + struct_tags.len() + ); + let move_struct_layout_futures = struct_tags + .into_iter() + .map(|struct_tag| { + let package_resolver_clone = package_resolver.clone(); + async move { + let move_type_layout = package_resolver_clone + .type_layout(TypeTag::Struct(Box::new(struct_tag.clone()))) + .await + .map_err(|e| { + IndexerError::DynamicFieldError(format!( + "Fail to resolve struct layout for {:?} with {:?}.", + struct_tag, e + )) + })?; + let move_struct_layout = match move_type_layout { + MoveTypeLayout::Struct(s) => Ok(s), + _ => Err(IndexerError::ResolveMoveStructError( + "MoveTypeLayout is not Struct".to_string(), + )), + }?; + Ok::< + ( + move_core_types::language_storage::StructTag, + move_core_types::annotated_value::MoveStructLayout, + ), + IndexerError, + >((struct_tag, move_struct_layout)) + } + }) + .collect::>(); + let move_struct_layout_map = futures::future::try_join_all(move_struct_layout_futures) + .await? + .into_iter() + .collect::>(); + Ok(move_struct_layout_map) +} + +pub fn get_deleted_objects(effects: &TransactionEffects) -> Vec { + let deleted = effects.deleted().into_iter(); + let wrapped = effects.wrapped().into_iter(); + let unwrapped_then_deleted = effects.unwrapped_then_deleted().into_iter(); + deleted + .chain(wrapped) + .chain(unwrapped_then_deleted) + .collect::>() +} + +pub fn get_latest_objects( + objects: Vec<&Object>, +) -> ( + HashMap, + HashSet<(ObjectID, SequenceNumber)>, +) { + let mut latest_objects = HashMap::new(); + let mut discarded_versions = HashSet::new(); + for object in objects { + match latest_objects.entry(object.id()) { + Entry::Vacant(e) => { + e.insert(object.clone()); + } + Entry::Occupied(mut e) => { + if object.version() > e.get().version() { + discarded_versions.insert((e.get().id(), e.get().version())); + e.insert(object.clone()); + } + } + } + } + (latest_objects, discarded_versions) +} + +fn try_create_dynamic_field_info( + o: &Object, + struct_tag_to_move_struct_layout: &HashMap, + latest_objects: &HashMap, +) -> IndexerResult> { + // Skip if not a move object + let Some(move_object) = o.data.try_as_move().cloned() else { + return Ok(None); + }; + + if !move_object.type_().is_dynamic_field() { + return Ok(None); + } + + let struct_tag: StructTag = move_object.type_().clone().into(); + let move_struct_layout = struct_tag_to_move_struct_layout + .get(&struct_tag) + .cloned() + .ok_or_else(|| { + IndexerError::DynamicFieldError(format!( + "Cannot find struct layout in mapfor {:?}.", + struct_tag + )) + })?; + let move_struct = move_object.to_move_struct(&move_struct_layout)?; + let (name_value, type_, object_id) = + DynamicFieldInfo::parse_move_object(&move_struct).tap_err(|e| warn!("{e}"))?; + let name_type = move_object.type_().try_extract_field_name(&type_)?; + let bcs_name = bcs::to_bytes(&name_value.clone().undecorate()).map_err(|e| { + IndexerError::SerdeError(format!( + "Failed to serialize dynamic field name {:?}: {e}", + name_value + )) + })?; + let name = DynamicFieldName { + type_: name_type, + value: IotaMoveValue::from(name_value).to_json_value(), + }; + Ok(Some(match type_ { + DynamicFieldType::DynamicObject => { + let object = latest_objects + .get(&object_id) + .ok_or(IndexerError::UncategorizedError(anyhow::anyhow!( + "Failed to find object_id {:?} when trying to create dynamic field info", + object_id + )))?; + let version = object.version(); + let digest = object.digest(); + let object_type = object.data.type_().unwrap().clone(); + DynamicFieldInfo { + name, + bcs_name, + type_, + object_type: object_type.to_canonical_string(/* with_prefix */ true), + object_id, + version, + digest, + } + } + DynamicFieldType::DynamicField => DynamicFieldInfo { + name, + bcs_name, + type_, + object_type: move_object.into_type().into_type_params()[1] + .to_canonical_string(/* with_prefix */ true), + object_id: o.id(), + version: o.version(), + digest: o.digest(), + }, + })) +} diff --git a/crates/sui-indexer/src/handlers/committer.rs b/crates/iota-indexer/src/handlers/committer.rs similarity index 98% rename from crates/sui-indexer/src/handlers/committer.rs rename to crates/iota-indexer/src/handlers/committer.rs index 7f92e855bd3..41df65e55de 100644 --- a/crates/sui-indexer/src/handlers/committer.rs +++ b/crates/iota-indexer/src/handlers/committer.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeMap; -use sui_types::messages_checkpoint::CheckpointSequenceNumber; +use iota_types::messages_checkpoint::CheckpointSequenceNumber; use tap::tap::TapFallible; use tokio::sync::watch; use tracing::{error, info, instrument}; diff --git a/crates/iota-indexer/src/handlers/mod.rs b/crates/iota-indexer/src/handlers/mod.rs new file mode 100644 index 00000000000..5839be69eee --- /dev/null +++ b/crates/iota-indexer/src/handlers/mod.rs @@ -0,0 +1,43 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use crate::{ + models::display::StoredDisplay, + types::{ + IndexedCheckpoint, IndexedDeletedObject, IndexedEpochInfo, IndexedEvent, IndexedObject, + IndexedPackage, IndexedTransaction, TxIndex, + }, +}; + +pub mod checkpoint_handler; +pub mod committer; +pub mod objects_snapshot_processor; +pub mod tx_processor; + +#[derive(Debug)] +pub struct CheckpointDataToCommit { + pub checkpoint: IndexedCheckpoint, + pub transactions: Vec, + pub events: Vec, + pub tx_indices: Vec, + pub display_updates: BTreeMap, + pub object_changes: TransactionObjectChangesToCommit, + pub object_history_changes: TransactionObjectChangesToCommit, + pub packages: Vec, + pub epoch: Option, +} + +#[derive(Clone, Debug)] +pub struct TransactionObjectChangesToCommit { + pub changed_objects: Vec, + pub deleted_objects: Vec, +} + +#[derive(Clone, Debug)] +pub struct EpochToCommit { + pub last_epoch: Option, + pub new_epoch: IndexedEpochInfo, +} diff --git a/crates/sui-indexer/src/handlers/objects_snapshot_processor.rs b/crates/iota-indexer/src/handlers/objects_snapshot_processor.rs similarity index 98% rename from crates/sui-indexer/src/handlers/objects_snapshot_processor.rs rename to crates/iota-indexer/src/handlers/objects_snapshot_processor.rs index 50cdcc41487..41236720440 100644 --- a/crates/sui-indexer/src/handlers/objects_snapshot_processor.rs +++ b/crates/iota-indexer/src/handlers/objects_snapshot_processor.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use tracing::info; diff --git a/crates/sui-indexer/src/handlers/tx_processor.rs b/crates/iota-indexer/src/handlers/tx_processor.rs similarity index 95% rename from crates/sui-indexer/src/handlers/tx_processor.rs rename to crates/iota-indexer/src/handlers/tx_processor.rs index f552a9afdfa..2ff3d532ab6 100644 --- a/crates/sui-indexer/src/handlers/tx_processor.rs +++ b/crates/iota-indexer/src/handlers/tx_processor.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // TODO remove the dead_code attribute after integration is done @@ -10,12 +11,9 @@ use std::{ }; use async_trait::async_trait; -use move_binary_format::CompiledModule; -use move_core_types::language_storage::ModuleId; -use mysten_metrics::{monitored_scope, spawn_monitored_task}; -use sui_json_rpc::{get_balance_changes_from_effect, get_object_changes, ObjectProvider}; -use sui_rest_api::CheckpointData; -use sui_types::{ +use iota_json_rpc::{get_balance_changes_from_effect, get_object_changes, ObjectProvider}; +use iota_rest_api::CheckpointData; +use iota_types::{ base_types::{ObjectID, SequenceNumber}, digests::TransactionDigest, effects::{TransactionEffects, TransactionEffectsAPI}, @@ -23,6 +21,9 @@ use sui_types::{ object::Object, transaction::{TransactionData, TransactionDataAPI}, }; +use move_binary_format::CompiledModule; +use move_core_types::language_storage::ModuleId; +use mysten_metrics::{monitored_scope, spawn_monitored_task}; use tokio::{ sync::watch, time::{Duration, Instant}, @@ -250,7 +251,7 @@ impl TxChangesProcessor { effects: &TransactionEffects, tx_digest: &TransactionDigest, ) -> IndexerResult<( - Vec, + Vec, Vec, )> { let _timer = self @@ -355,7 +356,7 @@ impl ObjectProvider for TxChangesProcessor { } } -// This is a struct that is used to extract SuiSystemState and its dynamic +// This is a struct that is used to extract IotaSystemState and its dynamic // children for end-of-epoch indexing. pub(crate) struct EpochEndIndexingObjectStore<'a> { objects: Vec<&'a Object>, @@ -370,11 +371,11 @@ impl<'a> EpochEndIndexingObjectStore<'a> { } } -impl<'a> sui_types::storage::ObjectStore for EpochEndIndexingObjectStore<'a> { +impl<'a> iota_types::storage::ObjectStore for EpochEndIndexingObjectStore<'a> { fn get_object( &self, object_id: &ObjectID, - ) -> Result, sui_types::storage::error::Error> { + ) -> Result, iota_types::storage::error::Error> { Ok(self .objects .iter() @@ -386,8 +387,8 @@ impl<'a> sui_types::storage::ObjectStore for EpochEndIndexingObjectStore<'a> { fn get_object_by_key( &self, object_id: &ObjectID, - version: sui_types::base_types::VersionNumber, - ) -> Result, sui_types::storage::error::Error> { + version: iota_types::base_types::VersionNumber, + ) -> Result, iota_types::storage::error::Error> { Ok(self .objects .iter() diff --git a/crates/iota-indexer/src/indexer.rs b/crates/iota-indexer/src/indexer.rs new file mode 100644 index 00000000000..41ba04d54e5 --- /dev/null +++ b/crates/iota-indexer/src/indexer.rs @@ -0,0 +1,118 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::env; + +use anyhow::Result; +use mysten_metrics::spawn_monitored_task; +use prometheus::Registry; +use tracing::info; + +use crate::{ + build_json_rpc_server, + errors::IndexerError, + framework::fetcher::CheckpointFetcher, + handlers::{ + checkpoint_handler::new_handlers, + objects_snapshot_processor::{ObjectsSnapshotProcessor, SnapshotLagConfig}, + }, + indexer_reader::IndexerReader, + metrics::IndexerMetrics, + store::IndexerStore, + IndexerConfig, +}; + +const DOWNLOAD_QUEUE_SIZE: usize = 200; + +pub struct Indexer; + +impl Indexer { + pub async fn start_writer( + config: &IndexerConfig, + store: S, + metrics: IndexerMetrics, + ) -> Result<(), IndexerError> { + let snapshot_config = SnapshotLagConfig::default(); + Indexer::start_writer_with_config(config, store, metrics, snapshot_config).await + } + + pub async fn start_writer_with_config( + config: &IndexerConfig, + store: S, + metrics: IndexerMetrics, + snapshot_config: SnapshotLagConfig, + ) -> Result<(), IndexerError> { + info!( + "Iota Indexer Writer (version {:?}) started...", + env!("CARGO_PKG_VERSION") + ); + + // None will be returned when checkpoints table is empty. + let last_seq_from_db = store + .get_latest_tx_checkpoint_sequence_number() + .await + .expect("Failed to get latest tx checkpoint sequence number from DB"); + let download_queue_size = env::var("DOWNLOAD_QUEUE_SIZE") + .unwrap_or_else(|_| DOWNLOAD_QUEUE_SIZE.to_string()) + .parse::() + .expect("Invalid DOWNLOAD_QUEUE_SIZE"); + let (downloaded_checkpoint_data_sender, downloaded_checkpoint_data_receiver) = + mysten_metrics::metered_channel::channel( + download_queue_size, + &mysten_metrics::get_metrics() + .unwrap() + .channels + .with_label_values(&["checkpoint_tx_downloading"]), + ); + + let rest_api_url = format!("{}/rest", config.rpc_client_url); + let rest_client = iota_rest_api::Client::new(&rest_api_url); + let fetcher = CheckpointFetcher::new( + rest_client.clone(), + last_seq_from_db, + downloaded_checkpoint_data_sender, + metrics.clone(), + ); + spawn_monitored_task!(fetcher.run()); + + let objects_snapshot_processor = ObjectsSnapshotProcessor::new_with_config( + store.clone(), + metrics.clone(), + snapshot_config, + ); + spawn_monitored_task!(objects_snapshot_processor.start()); + + let checkpoint_handler = new_handlers(store, metrics.clone()).await?; + crate::framework::runner::run( + mysten_metrics::metered_channel::ReceiverStream::new( + downloaded_checkpoint_data_receiver, + ), + vec![Box::new(checkpoint_handler)], + metrics, + ) + .await; + + Ok(()) + } + + pub async fn start_reader( + config: &IndexerConfig, + registry: &Registry, + db_url: String, + ) -> Result<(), IndexerError> { + info!( + "Iota Indexer Reader (version {:?}) started...", + env!("CARGO_PKG_VERSION") + ); + let indexer_reader = IndexerReader::new(db_url)?; + let handle = build_json_rpc_server(registry, indexer_reader, config, None) + .await + .expect("Json rpc server should not run into errors upon start."); + tokio::spawn(async move { handle.stopped().await }) + .await + .expect("Rpc server task failed"); + + Ok(()) + } +} diff --git a/crates/sui-indexer/src/indexer_reader.rs b/crates/iota-indexer/src/indexer_reader.rs similarity index 91% rename from crates/sui-indexer/src/indexer_reader.rs rename to crates/iota-indexer/src/indexer_reader.rs index 5b31180a221..1e8b11a06df 100644 --- a/crates/sui-indexer/src/indexer_reader.rs +++ b/crates/iota-indexer/src/indexer_reader.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -13,26 +14,26 @@ use diesel::{ PgConnection, QueryDsl, RunQueryDsl, TextExpressionMethods, }; use fastcrypto::encoding::{Encoding, Hex}; -use itertools::{any, Itertools}; -use move_core_types::{annotated_value::MoveStructLayout, language_storage::StructTag}; -use sui_json_rpc_types::{ - Balance, CheckpointId, Coin as SuiCoin, DisplayFieldsResponse, EpochInfo, EventFilter, - SuiCoinMetadata, SuiEvent, SuiObjectDataFilter, SuiTransactionBlockEffects, - SuiTransactionBlockEffectsAPI, SuiTransactionBlockResponse, TransactionFilter, +use iota_json_rpc_types::{ + Balance, CheckpointId, Coin as IotaCoin, DisplayFieldsResponse, EpochInfo, EventFilter, + IotaCoinMetadata, IotaEvent, IotaObjectDataFilter, IotaTransactionBlockEffects, + IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponse, TransactionFilter, }; -use sui_types::{ +use iota_types::{ balance::Supply, - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress, VersionNumber}, + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber, VersionNumber}, coin::{CoinMetadata, TreasuryCap}, committee::EpochId, digests::{ObjectDigest, TransactionDigest}, dynamic_field::{DynamicFieldInfo, DynamicFieldName}, event::EventID, + iota_system_state::{iota_system_state_summary::IotaSystemStateSummary, IotaSystemStateTrait}, is_system_package, move_package::MovePackage, object::{MoveObject, Object, ObjectRead}, - sui_system_state::{sui_system_state_summary::SuiSystemStateSummary, SuiSystemStateTrait}, }; +use itertools::{any, Itertools}; +use move_core_types::{annotated_value::MoveStructLayout, language_storage::StructTag}; use crate::{ db::{PgConnectionConfig, PgConnectionPoolConfig, PgPoolConnection}, @@ -404,10 +405,10 @@ impl IndexerReader { .map_err(Into::into) } - pub fn get_latest_sui_system_state(&self) -> Result { - let system_state: SuiSystemStateSummary = - sui_types::sui_system_state::get_sui_system_state(self)? - .into_sui_system_state_summary(); + pub fn get_latest_iota_system_state(&self) -> Result { + let system_state: IotaSystemStateSummary = + iota_types::iota_system_state::get_iota_system_state(self)? + .into_iota_system_state_summary(); Ok(system_state) } @@ -415,19 +416,19 @@ impl IndexerReader { /// given, it will retrieve the latest epoch's data and return the /// system state. System state of the an epoch is written at the end of /// the epoch, so system state of the current epoch is empty until the - /// epoch ends. You can call `get_latest_sui_system_state` for current + /// epoch ends. You can call `get_latest_iota_system_state` for current /// epoch instead. - pub fn get_epoch_sui_system_state( + pub fn get_epoch_iota_system_state( &self, epoch: Option, - ) -> Result { + ) -> Result { let stored_epoch = self.get_epoch_info_from_db(epoch)?; let stored_epoch = match stored_epoch { Some(stored_epoch) => stored_epoch, None => return Err(IndexerError::InvalidArgumentError("Invalid epoch".into())), }; - let system_state: SuiSystemStateSummary = bcs::from_bytes(&stored_epoch.system_state) + let system_state: IotaSystemStateSummary = bcs::from_bytes(&stored_epoch.system_state) .map_err(|_| { IndexerError::PersistentStorageDataCorruptionError(format!( "Failed to deserialize `system_state` for epoch {:?}", @@ -468,20 +469,20 @@ impl IndexerReader { pub fn get_checkpoint( &self, checkpoint_id: CheckpointId, - ) -> Result, IndexerError> { + ) -> Result, IndexerError> { let stored_checkpoint = match self.get_checkpoint_from_db(checkpoint_id)? { Some(stored_checkpoint) => stored_checkpoint, None => return Ok(None), }; - let checkpoint = sui_json_rpc_types::Checkpoint::try_from(stored_checkpoint)?; + let checkpoint = iota_json_rpc_types::Checkpoint::try_from(stored_checkpoint)?; Ok(Some(checkpoint)) } - pub fn get_latest_checkpoint(&self) -> Result { + pub fn get_latest_checkpoint(&self) -> Result { let stored_checkpoint = self.get_latest_checkpoint_from_db()?; - sui_json_rpc_types::Checkpoint::try_from(stored_checkpoint) + iota_json_rpc_types::Checkpoint::try_from(stored_checkpoint) } fn get_checkpoints_from_db( @@ -518,37 +519,37 @@ impl IndexerReader { cursor: Option, limit: usize, descending_order: bool, - ) -> Result, IndexerError> { + ) -> Result, IndexerError> { self.get_checkpoints_from_db(cursor, limit, descending_order)? .into_iter() - .map(sui_json_rpc_types::Checkpoint::try_from) + .map(iota_json_rpc_types::Checkpoint::try_from) .collect() } fn get_transaction_effects_with_digest( &self, digest: TransactionDigest, - ) -> Result { + ) -> Result { let stored_txn: StoredTransaction = self.run_query(|conn| { transactions::table .filter(transactions::transaction_digest.eq(digest.inner().to_vec())) .first::(conn) })?; - stored_txn.try_into_sui_transaction_effects() + stored_txn.try_into_iota_transaction_effects() } fn get_transaction_effects_with_sequence_number( &self, sequence_number: i64, - ) -> Result { + ) -> Result { let stored_txn: StoredTransaction = self.run_query(|conn| { transactions::table .filter(transactions::tx_sequence_number.eq(sequence_number)) .first::(conn) })?; - stored_txn.try_into_sui_transaction_effects() + stored_txn.try_into_iota_transaction_effects() } fn multi_get_transactions( @@ -569,11 +570,11 @@ impl IndexerReader { fn stored_transaction_to_transaction_block( &self, stored_txes: Vec, - options: sui_json_rpc_types::SuiTransactionBlockResponseOptions, - ) -> IndexerResult> { + options: iota_json_rpc_types::IotaTransactionBlockResponseOptions, + ) -> IndexerResult> { stored_txes .into_iter() - .map(|stored_tx| stored_tx.try_into_sui_transaction_block_response(&options, self)) + .map(|stored_tx| stored_tx.try_into_iota_transaction_block_response(&options, self)) .collect::>>() } @@ -600,8 +601,8 @@ impl IndexerReader { pub async fn get_owned_objects_in_blocking_task( &self, - address: SuiAddress, - filter: Option, + address: IotaAddress, + filter: Option, cursor: Option, limit: usize, ) -> Result, IndexerError> { @@ -611,8 +612,8 @@ impl IndexerReader { fn get_owned_objects_impl( &self, - address: SuiAddress, - filter: Option, + address: IotaAddress, + filter: Option, cursor: Option, limit: usize, ) -> Result, IndexerError> { @@ -625,14 +626,14 @@ impl IndexerReader { .into_boxed(); if let Some(filter) = filter { match filter { - SuiObjectDataFilter::StructType (struct_tag ) => { + IotaObjectDataFilter::StructType (struct_tag ) => { let object_type = struct_tag.to_canonical_string(/* with_prefix */ true); query = query.filter(objects::dsl::object_type.like(format!("{}%",object_type))); }, - SuiObjectDataFilter::MatchAny(filters) => { + IotaObjectDataFilter::MatchAny(filters) => { let mut condition = "(".to_string(); for (i, filter) in filters.iter().enumerate() { - if let SuiObjectDataFilter::StructType (struct_tag) = filter { + if let IotaObjectDataFilter::StructType (struct_tag) = filter { let object_type = struct_tag.to_canonical_string(/* with_prefix */ true); if i == 0 { condition += format!("objects.object_type LIKE '{}%'",object_type).as_str(); @@ -648,9 +649,9 @@ impl IndexerReader { condition += ")"; query = query.filter(sql::(&condition)); }, - SuiObjectDataFilter::MatchNone(filters) => { + IotaObjectDataFilter::MatchNone(filters) => { for filter in filters { - if let SuiObjectDataFilter::StructType (struct_tag) = filter { + if let IotaObjectDataFilter::StructType (struct_tag) = filter { let object_type = struct_tag.to_canonical_string(/* with_prefix */ true); query = query.filter(objects::dsl::object_type.not_like(format!("{}%", object_type))); } else { @@ -682,7 +683,7 @@ impl IndexerReader { cursor: Option, limit: usize, descending_order: bool, - ) -> IndexerResult> { + ) -> IndexerResult> { self.spawn_blocking(move |this| { this.query_events_impl(filter, cursor, limit, descending_order) }) @@ -739,11 +740,11 @@ impl IndexerReader { fn query_transaction_blocks_by_checkpoint_impl( &self, checkpoint_seq: u64, - options: sui_json_rpc_types::SuiTransactionBlockResponseOptions, + options: iota_json_rpc_types::IotaTransactionBlockResponseOptions, cursor_tx_seq: Option, limit: usize, is_descending: bool, - ) -> IndexerResult> { + ) -> IndexerResult> { let mut query = transactions::dsl::transactions .filter(transactions::dsl::checkpoint_sequence_number.eq(checkpoint_seq as i64)) .into_boxed(); @@ -771,11 +772,11 @@ impl IndexerReader { pub async fn query_transaction_blocks_in_blocking_task( &self, filter: Option, - options: sui_json_rpc_types::SuiTransactionBlockResponseOptions, + options: iota_json_rpc_types::IotaTransactionBlockResponseOptions, cursor: Option, limit: usize, is_descending: bool, - ) -> IndexerResult> { + ) -> IndexerResult> { self.spawn_blocking(move |this| { this.query_transaction_blocks_impl(filter, options, cursor, limit, is_descending) }) @@ -785,11 +786,11 @@ impl IndexerReader { fn query_transaction_blocks_impl( &self, filter: Option, - options: sui_json_rpc_types::SuiTransactionBlockResponseOptions, + options: iota_json_rpc_types::IotaTransactionBlockResponseOptions, cursor: Option, limit: usize, is_descending: bool, - ) -> IndexerResult> { + ) -> IndexerResult> { let cursor_tx_seq = if let Some(cursor) = cursor { Some(self.run_query(|conn| { transactions::dsl::transactions @@ -985,8 +986,8 @@ impl IndexerReader { fn multi_get_transaction_block_response_impl( &self, digests: &[TransactionDigest], - options: sui_json_rpc_types::SuiTransactionBlockResponseOptions, - ) -> Result, IndexerError> { + options: iota_json_rpc_types::IotaTransactionBlockResponseOptions, + ) -> Result, IndexerError> { let stored_txes = self.multi_get_transactions(digests)?; self.stored_transaction_to_transaction_block(stored_txes, options) } @@ -994,10 +995,10 @@ impl IndexerReader { fn multi_get_transaction_block_response_by_sequence_numbers( &self, tx_sequence_numbers: Vec, - options: sui_json_rpc_types::SuiTransactionBlockResponseOptions, + options: iota_json_rpc_types::IotaTransactionBlockResponseOptions, // Some(true) for desc, Some(false) for asc, None for undefined order is_descending: Option, - ) -> Result, IndexerError> { + ) -> Result, IndexerError> { let stored_txes: Vec = self.multi_get_transactions_with_sequence_numbers(tx_sequence_numbers, is_descending)?; self.stored_transaction_to_transaction_block(stored_txes, options) @@ -1006,8 +1007,8 @@ impl IndexerReader { pub async fn multi_get_transaction_block_response_in_blocking_task( &self, digests: Vec, - options: sui_json_rpc_types::SuiTransactionBlockResponseOptions, - ) -> Result, IndexerError> { + options: iota_json_rpc_types::IotaTransactionBlockResponseOptions, + ) -> Result, IndexerError> { self.spawn_blocking(move |this| { this.multi_get_transaction_block_response_impl(&digests, options) }) @@ -1017,7 +1018,7 @@ impl IndexerReader { fn get_transaction_events_impl( &self, digest: TransactionDigest, - ) -> Result, IndexerError> { + ) -> Result, IndexerError> { let (timestamp_ms, serialized_events) = self.run_query(|conn| { transactions::table .filter(transactions::transaction_digest.eq(digest.into_inner().to_vec())) @@ -1028,7 +1029,7 @@ impl IndexerReader { let events = serialized_events .into_iter() .flatten() - .map(|event| bcs::from_bytes::(&event)) + .map(|event| bcs::from_bytes::(&event)) .collect::, _>>()?; events @@ -1036,7 +1037,7 @@ impl IndexerReader { .enumerate() .map(|(i, event)| { let layout = MoveObject::get_layout_from_struct_tag(event.type_.clone(), self)?; - sui_json_rpc_types::SuiEvent::try_from( + iota_json_rpc_types::IotaEvent::try_from( event, digest, i as u64, @@ -1093,7 +1094,7 @@ impl IndexerReader { cursor: Option, limit: usize, descending_order: bool, - ) -> IndexerResult> { + ) -> IndexerResult> { let (tx_seq, event_seq) = if let Some(cursor) = cursor { let EventID { tx_digest, @@ -1230,14 +1231,14 @@ impl IndexerReader { self.run_query(|conn| diesel::sql_query(query).load::(conn))?; stored_events .into_iter() - .map(|se| se.try_into_sui_event(self)) + .map(|se| se.try_into_iota_event(self)) .collect() } pub async fn get_transaction_events_in_blocking_task( &self, digest: TransactionDigest, - ) -> Result, IndexerError> { + ) -> Result, IndexerError> { self.spawn_blocking(move |this| this.get_transaction_events_impl(digest)) .await } @@ -1340,8 +1341,8 @@ impl IndexerReader { ) -> Result, IndexerError> { let layout = move_bytecode_utils::layout::TypeLayoutBuilder::build_with_types(&name.type_, self)?; - let sui_json_value = sui_json::SuiJsonValue::new(name.value.clone())?; - let name_bcs_value = sui_json_value.to_bcs_bytes(&layout)?; + let iota_json_value = iota_json::IotaJsonValue::new(name.value.clone())?; + let name_bcs_value = iota_json_value.to_bcs_bytes(&layout)?; Ok(name_bcs_value) } @@ -1393,7 +1394,7 @@ impl IndexerReader { pub async fn get_display_object_by_type( &self, object_type: &move_core_types::language_storage::StructTag, - ) -> Result, IndexerError> { + ) -> Result, IndexerError> { let object_type = object_type.to_canonical_string(/* with_prefix */ true); self.spawn_blocking(move |this| this.get_display_update_event(object_type)) .await @@ -1402,7 +1403,7 @@ impl IndexerReader { fn get_display_update_event( &self, object_type: String, - ) -> Result, IndexerError> { + ) -> Result, IndexerError> { let stored_display = self.run_query(|conn| { display::table .filter(display::object_type.eq(object_type)) @@ -1422,23 +1423,23 @@ impl IndexerReader { pub async fn get_owned_coins_in_blocking_task( &self, - owner: SuiAddress, + owner: IotaAddress, coin_type: Option, cursor: ObjectID, limit: usize, - ) -> Result, IndexerError> { + ) -> Result, IndexerError> { self.spawn_blocking(move |this| this.get_owned_coins(owner, coin_type, cursor, limit)) .await } fn get_owned_coins( &self, - owner: SuiAddress, + owner: IotaAddress, // If coin_type is None, look for all coins. coin_type: Option, cursor: ObjectID, limit: usize, - ) -> Result, IndexerError> { + ) -> Result, IndexerError> { let mut query = objects::dsl::objects .filter(objects::dsl::owner_type.eq(OwnerType::Address as i16)) .filter(objects::dsl::owner_id.eq(owner.to_vec())) @@ -1463,7 +1464,7 @@ impl IndexerReader { pub async fn get_coin_balances_in_blocking_task( &self, - owner: SuiAddress, + owner: IotaAddress, // If coin_type is None, look for all coins. coin_type: Option, ) -> Result, IndexerError> { @@ -1473,7 +1474,7 @@ impl IndexerReader { fn get_coin_balances( &self, - owner: SuiAddress, + owner: IotaAddress, // If coin_type is None, look for all coins. coin_type: Option, ) -> Result, IndexerError> { @@ -1511,11 +1512,11 @@ impl IndexerReader { pub(crate) async fn get_display_fields( &self, - original_object: &sui_types::object::Object, + original_object: &iota_types::object::Object, original_layout: &Option, ) -> Result { let (object_type, layout) = if let Some((object_type, layout)) = - sui_json_rpc::read_api::get_object_type_and_struct(original_object, original_layout) + iota_json_rpc::read_api::get_object_type_and_struct(original_object, original_layout) .map_err(|e| IndexerError::GenericError(e.to_string()))? { (object_type, layout) @@ -1527,7 +1528,7 @@ impl IndexerReader { }; if let Some(display_object) = self.get_display_object_by_type(&object_type).await? { - return sui_json_rpc::read_api::get_rendered_fields(display_object.fields, &layout) + return iota_json_rpc::read_api::get_rendered_fields(display_object.fields, &layout) .map_err(|e| IndexerError::GenericError(e.to_string())); } Ok(DisplayFieldsResponse { @@ -1539,7 +1540,7 @@ impl IndexerReader { pub async fn get_coin_metadata_in_blocking_task( &self, coin_struct: StructTag, - ) -> Result, IndexerError> { + ) -> Result, IndexerError> { self.spawn_blocking(move |this| this.get_coin_metadata(coin_struct)) .await } @@ -1547,7 +1548,7 @@ impl IndexerReader { fn get_coin_metadata( &self, coin_struct: StructTag, - ) -> Result, IndexerError> { + ) -> Result, IndexerError> { let package_id = coin_struct.address.into(); let coin_metadata_type = CoinMetadata::type_(coin_struct).to_canonical_string(/* with_prefix */ true); @@ -1555,7 +1556,7 @@ impl IndexerReader { get_single_obj_id_from_package_publish(self, package_id, coin_metadata_type)?; if let Some(id) = coin_metadata_obj_id { let metadata_object = self.get_object(&id, None)?; - Ok(metadata_object.and_then(|v| SuiCoinMetadata::try_from(v).ok())) + Ok(metadata_object.and_then(|v| IotaCoinMetadata::try_from(v).ok())) } else { Ok(None) } @@ -1644,22 +1645,22 @@ impl move_core_types::resolver::ModuleResolver for IndexerReader { } } -impl sui_types::storage::ObjectStore for IndexerReader { +impl iota_types::storage::ObjectStore for IndexerReader { fn get_object( &self, object_id: &ObjectID, - ) -> Result, sui_types::storage::error::Error> { + ) -> Result, iota_types::storage::error::Error> { self.get_object(object_id, None) - .map_err(sui_types::storage::error::Error::custom) + .map_err(iota_types::storage::error::Error::custom) } fn get_object_by_key( &self, object_id: &ObjectID, - version: sui_types::base_types::VersionNumber, - ) -> Result, sui_types::storage::error::Error> { + version: iota_types::base_types::VersionNumber, + ) -> Result, iota_types::storage::error::Error> { self.get_object(object_id, Some(version)) - .map_err(sui_types::storage::error::Error::custom) + .map_err(iota_types::storage::error::Error::custom) } } diff --git a/crates/iota-indexer/src/lib.rs b/crates/iota-indexer/src/lib.rs new file mode 100644 index 00000000000..05a2446d845 --- /dev/null +++ b/crates/iota-indexer/src/lib.rs @@ -0,0 +1,187 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +#![recursion_limit = "256"] + +use std::net::SocketAddr; + +use anyhow::{anyhow, Result}; +use clap::Parser; +use errors::IndexerError; +use iota_json_rpc::{JsonRpcServerBuilder, ServerHandle, ServerType}; +use iota_json_rpc_api::CLIENT_SDK_TYPE_HEADER; +use jsonrpsee::http_client::{HeaderMap, HeaderValue, HttpClient, HttpClientBuilder}; +use metrics::IndexerMetrics; +use prometheus::Registry; +use tokio::runtime::Handle; +use tracing::warn; +use url::Url; + +use crate::{ + apis::{ + CoinReadApi, ExtendedApi, GovernanceReadApi, IndexerApi, MoveUtilsApi, ReadApi, + TransactionBuilderApi, WriteApi, + }, + indexer_reader::IndexerReader, +}; + +pub mod apis; +pub mod db; +pub mod errors; +pub mod framework; +pub mod handlers; +pub mod indexer; +pub mod indexer_reader; +pub mod metrics; +pub mod models; +pub mod schema; +pub mod store; +pub mod test_utils; +pub mod types; + +#[derive(Parser, Clone, Debug)] +#[clap( + name = "Iota indexer", + about = "An off-fullnode service serving data from Iota protocol", + rename_all = "kebab-case" +)] +pub struct IndexerConfig { + #[clap(long)] + pub db_url: Option, + #[clap(long)] + pub db_user_name: Option, + #[clap(long)] + pub db_password: Option, + #[clap(long)] + pub db_host: Option, + #[clap(long)] + pub db_port: Option, + #[clap(long)] + pub db_name: Option, + #[clap(long, default_value = "http://0.0.0.0:9000", global = true)] + pub rpc_client_url: String, + #[clap(long, default_value = "0.0.0.0", global = true)] + pub client_metric_host: String, + #[clap(long, default_value = "9184", global = true)] + pub client_metric_port: u16, + #[clap(long, default_value = "0.0.0.0", global = true)] + pub rpc_server_url: String, + #[clap(long, default_value = "9000", global = true)] + pub rpc_server_port: u16, + #[clap(long)] + pub reset_db: bool, + #[clap(long)] + pub fullnode_sync_worker: bool, + #[clap(long)] + pub rpc_server_worker: bool, +} + +impl IndexerConfig { + /// returns connection url without the db name + pub fn base_connection_url(&self) -> Result { + let url_str = self.get_db_url()?; + let url = Url::parse(&url_str).expect("Failed to parse URL"); + Ok(format!( + "{}://{}:{}@{}:{}/", + url.scheme(), + url.username(), + url.password().unwrap_or_default(), + url.host_str().unwrap_or_default(), + url.port().unwrap_or_default() + )) + } + + pub fn get_db_url(&self) -> Result { + match ( + &self.db_url, + &self.db_user_name, + &self.db_password, + &self.db_host, + &self.db_port, + &self.db_name, + ) { + (Some(db_url), _, _, _, _, _) => Ok(db_url.clone()), + ( + None, + Some(db_user_name), + Some(db_password), + Some(db_host), + Some(db_port), + Some(db_name), + ) => Ok(format!( + "postgres://{}:{}@{}:{}/{}", + db_user_name, db_password, db_host, db_port, db_name + )), + _ => Err(anyhow!( + "Invalid db connection config, either db_url or (db_user_name, db_password, db_host, db_port, db_name) must be provided" + )), + } + } +} + +impl Default for IndexerConfig { + fn default() -> Self { + Self { + db_url: Some("postgres://postgres:postgres@localhost:5432/iota_indexer".to_string()), + db_user_name: None, + db_password: None, + db_host: None, + db_port: None, + db_name: None, + rpc_client_url: "http://127.0.0.1:9000".to_string(), + client_metric_host: "0.0.0.0".to_string(), + client_metric_port: 9184, + rpc_server_url: "0.0.0.0".to_string(), + rpc_server_port: 9000, + reset_db: false, + fullnode_sync_worker: true, + rpc_server_worker: true, + } + } +} + +pub async fn build_json_rpc_server( + prometheus_registry: &Registry, + reader: IndexerReader, + config: &IndexerConfig, + custom_runtime: Option, +) -> Result { + let mut builder = JsonRpcServerBuilder::new(env!("CARGO_PKG_VERSION"), prometheus_registry); + let http_client = crate::get_http_client(config.rpc_client_url.as_str())?; + + builder.register_module(WriteApi::new(http_client.clone()))?; + builder.register_module(IndexerApi::new(reader.clone()))?; + builder.register_module(TransactionBuilderApi::new(reader.clone()))?; + builder.register_module(MoveUtilsApi::new(reader.clone()))?; + builder.register_module(GovernanceReadApi::new(reader.clone()))?; + builder.register_module(ReadApi::new(reader.clone()))?; + builder.register_module(CoinReadApi::new(reader.clone()))?; + builder.register_module(ExtendedApi::new(reader.clone()))?; + + let default_socket_addr: SocketAddr = SocketAddr::new( + // unwrap() here is safe b/c the address is a static config. + config.rpc_server_url.as_str().parse().unwrap(), + config.rpc_server_port, + ); + Ok(builder + .start(default_socket_addr, custom_runtime, Some(ServerType::Http)) + .await?) +} + +fn get_http_client(rpc_client_url: &str) -> Result { + let mut headers = HeaderMap::new(); + headers.insert(CLIENT_SDK_TYPE_HEADER, HeaderValue::from_static("indexer")); + + HttpClientBuilder::default() + .max_request_body_size(2 << 30) + .max_concurrent_requests(usize::MAX) + .set_headers(headers.clone()) + .build(rpc_client_url) + .map_err(|e| { + warn!("Failed to get new Http client with error: {:?}", e); + IndexerError::HttpClientInitError(format!( + "Failed to initialize fullnode RPC client with error: {:?}", + e + )) + }) +} diff --git a/crates/iota-indexer/src/main.rs b/crates/iota-indexer/src/main.rs new file mode 100644 index 00000000000..bca3acdfe82 --- /dev/null +++ b/crates/iota-indexer/src/main.rs @@ -0,0 +1,97 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use clap::Parser; +use iota_indexer::{ + db::{get_pg_pool_connection, new_pg_connection_pool, reset_database}, + errors::IndexerError, + indexer::Indexer, + metrics::{start_prometheus_server, IndexerMetrics}, + store::PgIndexerStore, + IndexerConfig, +}; +use tracing::{error, info}; + +#[tokio::main] +async fn main() -> Result<(), IndexerError> { + // NOTE: this is to print out tracing like info, warn & error. + let _guard = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .init(); + + let indexer_config = IndexerConfig::parse(); + info!("Parsed indexer config: {:#?}", indexer_config); + + let db_url = indexer_config.get_db_url().map_err(|e| { + IndexerError::PgPoolConnectionError(format!( + "Failed parsing database url with error {:?}", + e + )) + })?; + let blocking_cp = new_pg_connection_pool(&db_url, None).map_err(|e| { + error!( + "Failed creating Postgres connection pool with error {:?}", + e + ); + e + })?; + if indexer_config.reset_db { + let mut conn = get_pg_pool_connection(&blocking_cp).map_err(|e| { + error!( + "Failed getting Postgres connection from connection pool with error {:?}", + e + ); + e + })?; + reset_database(&mut conn, /* drop_all */ true).map_err(|e| { + let db_err_msg = format!( + "Failed resetting database with url: {:?} and error: {:?}", + db_url, e + ); + error!("{}", db_err_msg); + IndexerError::PostgresResetError(db_err_msg) + })?; + } + + let (_registry_service, registry) = start_prometheus_server( + // NOTE: this parses the input host addr and port number for socket addr, + // so unwrap() is safe here. + format!( + "{}:{}", + indexer_config.client_metric_host, indexer_config.client_metric_port + ) + .parse() + .unwrap(), + indexer_config.rpc_client_url.as_str(), + )?; + let indexer_metrics = IndexerMetrics::new(®istry); + mysten_metrics::init_metrics(®istry); + + let report_cp = blocking_cp.clone(); + let report_metrics = indexer_metrics.clone(); + tokio::spawn(async move { + loop { + let cp_state = report_cp.state(); + info!( + "DB connection pool size: {}, with idle conn: {}.", + cp_state.connections, cp_state.idle_connections + ); + report_metrics + .db_conn_pool_size + .set(cp_state.connections as i64); + report_metrics + .idle_db_conn + .set(cp_state.idle_connections as i64); + tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; + } + }); + + if indexer_config.fullnode_sync_worker { + let store = PgIndexerStore::new(blocking_cp, indexer_metrics.clone()); + return Indexer::start_writer(&indexer_config, store, indexer_metrics).await; + } else if indexer_config.rpc_server_worker { + return Indexer::start_reader(&indexer_config, ®istry, db_url).await; + } + Ok(()) +} diff --git a/crates/iota-indexer/src/metrics.rs b/crates/iota-indexer/src/metrics.rs new file mode 100644 index 00000000000..69e0c2fdd06 --- /dev/null +++ b/crates/iota-indexer/src/metrics.rs @@ -0,0 +1,671 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::HashMap, net::SocketAddr}; + +use axum::{extract::Extension, http::StatusCode, routing::get, Router}; +use mysten_metrics::RegistryService; +use prometheus::{ + register_histogram_with_registry, register_int_counter_with_registry, + register_int_gauge_with_registry, Histogram, IntCounter, IntGauge, Registry, TextEncoder, +}; +use regex::Regex; +use tracing::{info, warn}; + +const METRICS_ROUTE: &str = "/metrics"; + +pub fn start_prometheus_server( + addr: SocketAddr, + fn_url: &str, +) -> Result<(RegistryService, Registry), anyhow::Error> { + let converted_fn_url = convert_url(fn_url); + if converted_fn_url.is_none() { + warn!( + "Failed to convert full node url {} to a shorter version", + fn_url + ); + } + let fn_url_str = converted_fn_url.unwrap_or_else(|| "unknown_url".to_string()); + + let labels = HashMap::from([("indexer_fullnode".to_string(), fn_url_str)]); + info!("Starting prometheus server with labels: {:?}", labels); + let registry = Registry::new_custom(Some("indexer".to_string()), Some(labels))?; + let registry_service = RegistryService::new(registry.clone()); + + let app = Router::new() + .route(METRICS_ROUTE, get(metrics)) + .layer(Extension(registry_service.clone())); + + tokio::spawn(async move { + axum::Server::bind(&addr) + .serve(app.into_make_service()) + .await + .unwrap(); + }); + Ok((registry_service, registry)) +} + +async fn metrics(Extension(registry_service): Extension) -> (StatusCode, String) { + let metrics_families = registry_service.gather_all(); + match TextEncoder.encode_to_string(&metrics_families) { + Ok(metrics) => (StatusCode::OK, metrics), + Err(error) => ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("unable to encode metrics: {error}"), + ), + } +} + +fn convert_url(url_str: &str) -> Option { + // NOTE: unwrap here is safe because the regex is a constant. + let re = Regex::new(r"https?://([a-z0-9-]+\.[a-z0-9-]+\.[a-z]+)").unwrap(); + let captures = re.captures(url_str)?; + + captures.get(1).map(|m| m.as_str().to_string()) +} + +/// Prometheus metrics for iota-indexer. +// buckets defined in seconds +const LATENCY_SEC_BUCKETS: &[f64] = &[ + 0.001, 0.005, 0.01, 0.02, 0.05, 0.1, 0.25, 0.5, 1.0, 2.0, 3.0, 5.0, 10.0, 20.0, 40.0, 60.0, + 80.0, 100.0, 200.0, +]; + +const DB_COMMIT_LATENCY_SEC_BUCKETS: &[f64] = &[ + 0.001, 0.005, 0.01, 0.02, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 2.0, 3.0, + 5.0, 10.0, 20.0, 40.0, 60.0, 80.0, 100.0, 200.0, +]; + +#[derive(Clone)] +pub struct IndexerMetrics { + pub total_checkpoint_received: IntCounter, + pub total_tx_checkpoint_committed: IntCounter, + pub total_object_checkpoint_committed: IntCounter, + pub total_transaction_committed: IntCounter, + pub total_object_change_committed: IntCounter, + pub total_transaction_chunk_committed: IntCounter, + pub total_object_change_chunk_committed: IntCounter, + pub total_epoch_committed: IntCounter, + pub latest_fullnode_checkpoint_sequence_number: IntGauge, + pub latest_tx_checkpoint_sequence_number: IntGauge, + pub latest_indexer_object_checkpoint_sequence_number: IntGauge, + pub latest_object_snapshot_sequence_number: IntGauge, + // checkpoint E2E latency is: + // fullnode_download_latency + checkpoint_index_latency + db_commit_latency + pub checkpoint_download_bytes_size: IntGauge, + pub fullnode_checkpoint_data_download_latency: Histogram, + pub fullnode_checkpoint_wait_and_download_latency: Histogram, + pub fullnode_transaction_download_latency: Histogram, + pub fullnode_object_download_latency: Histogram, + pub checkpoint_index_latency: Histogram, + pub indexing_batch_size: IntGauge, + pub indexing_tx_object_changes_latency: Histogram, + pub indexing_objects_latency: Histogram, + pub indexing_get_object_in_mem_hit: IntCounter, + pub indexing_get_object_db_hit: IntCounter, + pub indexing_module_resolver_in_mem_hit: IntCounter, + pub indexing_package_resolver_in_mem_hit: IntCounter, + pub indexing_packages_latency: Histogram, + pub checkpoint_objects_index_latency: Histogram, + pub checkpoint_db_commit_latency: Histogram, + pub checkpoint_db_commit_latency_step_1: Histogram, + pub checkpoint_db_commit_latency_transactions: Histogram, + pub checkpoint_db_commit_latency_transactions_chunks: Histogram, + pub checkpoint_db_commit_latency_transactions_chunks_transformation: Histogram, + pub checkpoint_db_commit_latency_objects: Histogram, + pub checkpoint_db_commit_latency_objects_history: Histogram, + pub checkpoint_db_commit_latency_objects_chunks: Histogram, + pub checkpoint_db_commit_latency_objects_history_chunks: Histogram, + pub checkpoint_db_commit_latency_events: Histogram, + pub checkpoint_db_commit_latency_events_chunks: Histogram, + pub checkpoint_db_commit_latency_packages: Histogram, + pub checkpoint_db_commit_latency_tx_indices: Histogram, + pub checkpoint_db_commit_latency_tx_indices_chunks: Histogram, + pub checkpoint_db_commit_latency_checkpoints: Histogram, + pub checkpoint_db_commit_latency_epoch: Histogram, + pub advance_epoch_latency: Histogram, + pub update_object_snapshot_latency: Histogram, + pub tokio_blocking_task_wait_latency: Histogram, + // average latency of committing 1000 transactions. + // 1000 is not necessarily the batch size, it's to roughly map average tx commit latency to + // [0.1, 1] seconds, which is well covered by DB_COMMIT_LATENCY_SEC_BUCKETS. + pub thousand_transaction_avg_db_commit_latency: Histogram, + pub object_db_commit_latency: Histogram, + pub object_mutation_db_commit_latency: Histogram, + pub object_deletion_db_commit_latency: Histogram, + pub epoch_db_commit_latency: Histogram, + // latency of event websocket subscription + pub subscription_process_latency: Histogram, + pub transaction_per_checkpoint: Histogram, + // FN RPC latencies on the read path + // read.rs + pub get_transaction_block_latency: Histogram, + pub multi_get_transaction_blocks_latency: Histogram, + pub get_object_latency: Histogram, + pub multi_get_objects_latency: Histogram, + pub try_get_past_object_latency: Histogram, + pub try_multi_get_past_objects_latency: Histogram, + pub get_checkpoint_latency: Histogram, + pub get_checkpoints_latency: Histogram, + pub get_events_latency: Histogram, + pub get_loaded_child_objects_latency: Histogram, + pub get_total_transaction_blocks_latency: Histogram, + pub get_latest_checkpoint_sequence_number_latency: Histogram, + // indexer.rs + pub get_owned_objects_latency: Histogram, + pub query_transaction_blocks_latency: Histogram, + pub query_events_latency: Histogram, + pub get_dynamic_fields_latency: Histogram, + pub get_dynamic_field_object_latency: Histogram, + pub get_protocol_config_latency: Histogram, + // indexer state metrics + pub db_conn_pool_size: IntGauge, + pub idle_db_conn: IntGauge, + + pub address_processor_failure: IntCounter, + pub checkpoint_metrics_processor_failure: IntCounter, +} + +impl IndexerMetrics { + pub fn new(registry: &Registry) -> Self { + Self { + total_checkpoint_received: register_int_counter_with_registry!( + "total_checkpoint_received", + "Total number of checkpoint received", + registry, + ) + .unwrap(), + total_tx_checkpoint_committed: register_int_counter_with_registry!( + "total_checkpoint_committed", + "Total number of checkpoint committed", + registry, + ) + .unwrap(), + total_object_checkpoint_committed: register_int_counter_with_registry!( + "total_object_checkpoint_committed", + "Total number of object checkpoint committed", + registry, + ) + .unwrap(), + total_transaction_committed: register_int_counter_with_registry!( + "total_transaction_committed", + "Total number of transaction committed", + registry, + ) + .unwrap(), + total_object_change_committed: register_int_counter_with_registry!( + "total_object_change_committed", + "Total number of object change committed", + registry, + ) + .unwrap(), + total_transaction_chunk_committed: register_int_counter_with_registry!( + "total_transaction_chunk_commited", + "Total number of transaction chunk committed", + registry, + ) + .unwrap(), + total_object_change_chunk_committed: register_int_counter_with_registry!( + "total_object_change_chunk_committed", + "Total number of object change chunk committed", + registry, + ) + .unwrap(), + total_epoch_committed: register_int_counter_with_registry!( + "total_epoch_committed", + "Total number of epoch committed", + registry, + ) + .unwrap(), + latest_fullnode_checkpoint_sequence_number: register_int_gauge_with_registry!( + "latest_fullnode_checkpoint_sequence_number", + "Latest checkpoint sequence number from the Full Node", + registry, + ) + .unwrap(), + latest_tx_checkpoint_sequence_number: register_int_gauge_with_registry!( + "latest_indexer_checkpoint_sequence_number", + "Latest checkpoint sequence number from the Indexer", + registry, + ) + .unwrap(), + latest_indexer_object_checkpoint_sequence_number: register_int_gauge_with_registry!( + "latest_indexer_object_checkpoint_sequence_number", + "Latest object checkpoint sequence number from the Indexer", + registry, + ) + .unwrap(), + latest_object_snapshot_sequence_number: register_int_gauge_with_registry!( + "latest_object_snapshot_sequence_number", + "Latest object snapshot sequence number from the Indexer", + registry, + ).unwrap(), + checkpoint_download_bytes_size: register_int_gauge_with_registry!( + "checkpoint_download_bytes_size", + "Size of the downloaded checkpoint in bytes", + registry, + ).unwrap(), + fullnode_checkpoint_data_download_latency: register_histogram_with_registry!( + "fullnode_checkpoint_data_download_latency", + "Time spent in downloading checkpoint and transation for a new checkpoint from the Full Node", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + fullnode_checkpoint_wait_and_download_latency: register_histogram_with_registry!( + "fullnode_checkpoint_wait_and_download_latency", + "Time spent in waiting for a new checkpoint from the Full Node", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + + fullnode_transaction_download_latency: register_histogram_with_registry!( + "fullnode_transaction_download_latency", + "Time spent in waiting for a new transaction from the Full Node", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + fullnode_object_download_latency: register_histogram_with_registry!( + "fullnode_object_download_latency", + "Time spent in waiting for a new epoch from the Full Node", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + checkpoint_index_latency: register_histogram_with_registry!( + "checkpoint_index_latency", + "Time spent in indexing a checkpoint", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + indexing_batch_size: register_int_gauge_with_registry!( + "indexing_batch_size", + "Size of the indexing batch", + registry, + ).unwrap(), + indexing_tx_object_changes_latency: register_histogram_with_registry!( + "indexing_tx_object_changes_latency", + "Time spent in indexing object changes for a transaction", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + indexing_objects_latency: register_histogram_with_registry!( + "indexing_objects_latency", + "Time spent in indexing objects", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + indexing_packages_latency: register_histogram_with_registry!( + "indexing_packages_latency", + "Time spent in indexing packages", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + indexing_get_object_in_mem_hit: register_int_counter_with_registry!( + "indexing_get_object_in_mem_hit", + "Total number get object hit in mem", + registry, + ) + .unwrap(), + indexing_get_object_db_hit: register_int_counter_with_registry!( + "indexing_get_object_db_hit", + "Total number get object hit in db", + registry, + ) + .unwrap(), + indexing_module_resolver_in_mem_hit: register_int_counter_with_registry!( + "indexing_module_resolver_in_mem_hit", + "Total number module resolver hit in mem", + registry, + ) + .unwrap(), + indexing_package_resolver_in_mem_hit: register_int_counter_with_registry!( + "indexing_package_resolver_in_mem_hit", + "Total number package resolver hit in mem", + registry, + ) + .unwrap(), + checkpoint_objects_index_latency: register_histogram_with_registry!( + "checkpoint_object_index_latency", + "Time spent in indexing a checkpoint objects", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + checkpoint_db_commit_latency: register_histogram_with_registry!( + "checkpoint_db_commit_latency", + "Time spent commiting a checkpoint to the db", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + + checkpoint_db_commit_latency_step_1: register_histogram_with_registry!( + "checkpoint_db_commit_latency_step_1", + "Time spent commiting a checkpoint to the db, step 1", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + checkpoint_db_commit_latency_transactions: register_histogram_with_registry!( + "checkpoint_db_commit_latency_transactions", + "Time spent commiting transactions", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + checkpoint_db_commit_latency_transactions_chunks: register_histogram_with_registry!( + "checkpoint_db_commit_latency_transactions_chunks", + "Time spent commiting transactions chunks", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + checkpoint_db_commit_latency_transactions_chunks_transformation: register_histogram_with_registry!( + "checkpoint_db_commit_latency_transactions_transaformation", + "Time spent in transactions chunks transformation prior to commit", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + checkpoint_db_commit_latency_objects: register_histogram_with_registry!( + "checkpoint_db_commit_latency_objects", + "Time spent commiting objects", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + checkpoint_db_commit_latency_objects_history: register_histogram_with_registry!( + "checkpoint_db_commit_latency_objects_history", + "Time spent commiting objects history", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ).unwrap(), + checkpoint_db_commit_latency_objects_chunks: register_histogram_with_registry!( + "checkpoint_db_commit_latency_objects_chunks", + "Time spent commiting objects chunks", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + checkpoint_db_commit_latency_objects_history_chunks: register_histogram_with_registry!( + "checkpoint_db_commit_latency_objects_history_chunks", + "Time spent commiting objects history chunks", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ).unwrap(), + checkpoint_db_commit_latency_events: register_histogram_with_registry!( + "checkpoint_db_commit_latency_events", + "Time spent commiting events", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + checkpoint_db_commit_latency_events_chunks: register_histogram_with_registry!( + "checkpoint_db_commit_latency_events_chunks", + "Time spent commiting events chunks", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + + checkpoint_db_commit_latency_packages: register_histogram_with_registry!( + "checkpoint_db_commit_latency_packages", + "Time spent commiting packages", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + checkpoint_db_commit_latency_tx_indices: register_histogram_with_registry!( + "checkpoint_db_commit_latency_tx_indices", + "Time spent commiting tx indices", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + checkpoint_db_commit_latency_tx_indices_chunks: register_histogram_with_registry!( + "checkpoint_db_commit_latency_tx_indices_chunks", + "Time spent commiting tx_indices chunks", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + checkpoint_db_commit_latency_checkpoints: register_histogram_with_registry!( + "checkpoint_db_commit_latency_checkpoints", + "Time spent commiting checkpoints", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + checkpoint_db_commit_latency_epoch: register_histogram_with_registry!( + "checkpoint_db_commit_latency_epochs", + "Time spent commiting epochs", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + advance_epoch_latency: register_histogram_with_registry!( + "advance_epoch_latency", + "Time spent in advancing epoch", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ).unwrap(), + update_object_snapshot_latency: register_histogram_with_registry!( + "update_object_snapshot_latency", + "Time spent in updating object snapshot", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ).unwrap(), + tokio_blocking_task_wait_latency: register_histogram_with_registry!( + "tokio_blocking_task_wait_latency", + "Time spent to wait for tokio blocking task pool", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ).unwrap(), + thousand_transaction_avg_db_commit_latency: register_histogram_with_registry!( + "transaction_db_commit_latency", + "Average time spent commiting 1000 transactions to the db", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + object_db_commit_latency: register_histogram_with_registry!( + "object_db_commit_latency", + "Time spent commiting a object to the db", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + object_mutation_db_commit_latency: register_histogram_with_registry!( + "object_mutation_db_commit_latency", + "Time spent commiting a object mutation to the db", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + object_deletion_db_commit_latency: register_histogram_with_registry!( + "object_deletion_db_commit_latency", + "Time spent commiting a object deletion to the db", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + epoch_db_commit_latency: register_histogram_with_registry!( + "epoch_db_commit_latency", + "Time spent commiting a epoch to the db", + DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + subscription_process_latency: register_histogram_with_registry!( + "subscription_process_latency", + "Time spent in process Websocket subscription", + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + transaction_per_checkpoint: register_histogram_with_registry!( + "transaction_per_checkpoint", + "Number of transactions per checkpoint", + vec![1.0, 2.0, 5.0, 10.0, 20.0, 50.0, 100.0, 200.0, 500.0, 1000.0, 2000.0, 5000.0], + registry, + ) + .unwrap(), + get_transaction_block_latency: register_histogram_with_registry!( + "get_transaction_block_latency", + "Time spent in get_transaction_block on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + multi_get_transaction_blocks_latency: register_histogram_with_registry!( + "multi_get_transaction_blocks_latency", + "Time spent in multi_get_transaction_blocks on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + get_object_latency: register_histogram_with_registry!( + "get_object_latency", + "Time spent in get_object on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + multi_get_objects_latency: register_histogram_with_registry!( + "multi_get_objects_latency", + "Time spent in multi_get_objects on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + try_get_past_object_latency: register_histogram_with_registry!( + "try_get_past_object_latency", + "Time spent in try_get_past_object on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + try_multi_get_past_objects_latency: register_histogram_with_registry!( + "try_multi_get_past_objects_latency", + "Time spent in try_multi_get_past_objects on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + get_checkpoint_latency: register_histogram_with_registry!( + "get_checkpoint_latency", + "Time spent in get_checkpoint on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + get_checkpoints_latency: register_histogram_with_registry!( + "get_checkpoints_latency", + "Time spent in get_checkpoints on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + get_events_latency: register_histogram_with_registry!( + "get_events_latency", + "Time spent in get_events on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + get_total_transaction_blocks_latency: register_histogram_with_registry!( + "get_total_transaction_blocks_latency", + "Time spent in get_total_transaction_blocks on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + get_latest_checkpoint_sequence_number_latency: register_histogram_with_registry!( + "get_latest_checkpoint_sequence_number_latency", + "Time spent in get_latest_checkpoint_sequence_number on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + get_owned_objects_latency: register_histogram_with_registry!( + "get_owned_objects_latency", + "Time spent in get_owned_objects on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + query_transaction_blocks_latency: register_histogram_with_registry!( + "query_transaction_blocks_latency", + "Time spent in query_transaction_blocks on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + query_events_latency: register_histogram_with_registry!( + "query_events_latency", + "Time spent in query_events on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + get_dynamic_fields_latency: register_histogram_with_registry!( + "get_dynamic_fields_latency", + "Time spent in get_dynamic_fields on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + get_dynamic_field_object_latency: register_histogram_with_registry!( + "get_dynamic_field_object_latency", + "Time spent in get_dynamic_field_object on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + get_loaded_child_objects_latency: register_histogram_with_registry!( + "get_loaded_child_objects_latency", + "Time spent in get_loaded_child_objects_latency on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + get_protocol_config_latency: register_histogram_with_registry!( + "get_protocol_config_latency", + "Time spent in get_protocol_config_latency on the fullnode behind.", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + db_conn_pool_size: register_int_gauge_with_registry!( + "db_conn_pool_size", + "Size of the database connection pool", + registry + ).unwrap(), + idle_db_conn: register_int_gauge_with_registry!( + "idle_db_conn", + "Number of idle database connections", + registry + ).unwrap(), + address_processor_failure: register_int_counter_with_registry!( + "address_processor_failure", + "Total number of address processor failure", + registry, + ) + .unwrap(), + checkpoint_metrics_processor_failure: register_int_counter_with_registry!( + "checkpoint_metrics_processor_failure", + "Total number of checkpoint metrics processor failure", + registry, + ) + .unwrap(), + } + } +} diff --git a/crates/iota-indexer/src/models/checkpoints.rs b/crates/iota-indexer/src/models/checkpoints.rs new file mode 100644 index 00000000000..1471af28b7a --- /dev/null +++ b/crates/iota-indexer/src/models/checkpoints.rs @@ -0,0 +1,151 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use diesel::prelude::*; +use iota_json_rpc_types::Checkpoint as RpcCheckpoint; +use iota_types::{base_types::TransactionDigest, digests::CheckpointDigest, gas::GasCostSummary}; + +use crate::{errors::IndexerError, schema::checkpoints, types::IndexedCheckpoint}; + +#[derive(Queryable, Insertable, Debug, Clone, Default)] +#[diesel(table_name = checkpoints)] +pub struct StoredCheckpoint { + pub sequence_number: i64, + pub checkpoint_digest: Vec, + pub epoch: i64, + pub network_total_transactions: i64, + pub previous_checkpoint_digest: Option>, + pub end_of_epoch: bool, + pub tx_digests: Vec>>, + pub timestamp_ms: i64, + pub total_gas_cost: i64, + pub computation_cost: i64, + pub storage_cost: i64, + pub storage_rebate: i64, + pub non_refundable_storage_fee: i64, + pub checkpoint_commitments: Vec, + pub validator_signature: Vec, + pub end_of_epoch_data: Option>, +} + +impl From<&IndexedCheckpoint> for StoredCheckpoint { + fn from(c: &IndexedCheckpoint) -> Self { + Self { + sequence_number: c.sequence_number as i64, + checkpoint_digest: c.checkpoint_digest.into_inner().to_vec(), + epoch: c.epoch as i64, + tx_digests: c + .tx_digests + .iter() + .map(|tx| Some(tx.into_inner().to_vec())) + .collect(), + network_total_transactions: c.network_total_transactions as i64, + previous_checkpoint_digest: c + .previous_checkpoint_digest + .as_ref() + .map(|d| (*d).into_inner().to_vec()), + timestamp_ms: c.timestamp_ms as i64, + total_gas_cost: c.total_gas_cost, + computation_cost: c.computation_cost as i64, + storage_cost: c.storage_cost as i64, + storage_rebate: c.storage_rebate as i64, + non_refundable_storage_fee: c.non_refundable_storage_fee as i64, + checkpoint_commitments: bcs::to_bytes(&c.checkpoint_commitments).unwrap(), + validator_signature: bcs::to_bytes(&c.validator_signature).unwrap(), + end_of_epoch_data: c + .end_of_epoch_data + .as_ref() + .map(|d| bcs::to_bytes(d).unwrap()), + end_of_epoch: c.end_of_epoch_data.is_some(), + } + } +} + +impl TryFrom for RpcCheckpoint { + type Error = IndexerError; + fn try_from(checkpoint: StoredCheckpoint) -> Result { + let parsed_digest = CheckpointDigest::try_from(checkpoint.checkpoint_digest.clone()) + .map_err(|e| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "Failed to decode checkpoint digest: {:?} with err: {:?}", + checkpoint.checkpoint_digest, e + )) + })?; + + let parsed_previous_digest: Option = checkpoint + .previous_checkpoint_digest + .map(|digest| { + CheckpointDigest::try_from(digest.clone()).map_err(|e| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "Failed to decode previous checkpoint digest: {:?} with err: {:?}", + digest, e + )) + }) + }) + .transpose()?; + + let transactions: Vec = checkpoint + .tx_digests + .into_iter() + .map(|tx_digest| match tx_digest { + None => Err(IndexerError::PersistentStorageDataCorruptionError( + "tx_digests should not contain null elements".to_string(), + )), + Some(tx_digest) => TransactionDigest::try_from(tx_digest.as_slice()).map_err(|e| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "Failed to decode transaction digest: {:?} with err: {:?}", + tx_digest, e + )) + }), + }) + .collect::, IndexerError>>()?; + + let validator_signature = + bcs::from_bytes(&checkpoint.validator_signature).map_err(|e| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "Failed to decode validator signature: {:?} with err: {:?}", + checkpoint.validator_signature, e + )) + })?; + + let checkpoint_commitments = + bcs::from_bytes(&checkpoint.checkpoint_commitments).map_err(|e| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "Failed to decode checkpoint commitments: {:?} with err: {:?}", + checkpoint.checkpoint_commitments, e + )) + })?; + + let end_of_epoch_data = checkpoint + .end_of_epoch_data + .map(|data| { + bcs::from_bytes(&data).map_err(|e| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "Failed to decode end of epoch data: {:?} with err: {:?}", + data, e + )) + }) + }) + .transpose()?; + + Ok(RpcCheckpoint { + epoch: checkpoint.epoch as u64, + sequence_number: checkpoint.sequence_number as u64, + digest: parsed_digest, + previous_digest: parsed_previous_digest, + end_of_epoch_data, + epoch_rolling_gas_cost_summary: GasCostSummary { + computation_cost: checkpoint.computation_cost as u64, + storage_cost: checkpoint.storage_cost as u64, + storage_rebate: checkpoint.storage_rebate as u64, + non_refundable_storage_fee: checkpoint.non_refundable_storage_fee as u64, + }, + network_total_transactions: checkpoint.network_total_transactions as u64, + timestamp_ms: checkpoint.timestamp_ms as u64, + transactions, + validator_signature, + checkpoint_commitments, + }) + } +} diff --git a/crates/iota-indexer/src/models/display.rs b/crates/iota-indexer/src/models/display.rs new file mode 100644 index 00000000000..2bd3c7a7f06 --- /dev/null +++ b/crates/iota-indexer/src/models/display.rs @@ -0,0 +1,34 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use diesel::prelude::*; +use iota_types::display::DisplayVersionUpdatedEvent; + +use crate::schema::display; + +#[derive(Queryable, Insertable, Debug, Clone)] +#[diesel(table_name = display)] +pub struct StoredDisplay { + pub object_type: String, + pub id: Vec, + pub version: i16, + pub bcs: Vec, +} + +impl StoredDisplay { + pub fn try_from_event(event: &iota_types::event::Event) -> Option { + let (ty, display_event) = DisplayVersionUpdatedEvent::try_from_event(event)?; + + Some(Self { + object_type: ty.to_canonical_string(/* with_prefix */ true), + id: display_event.id.bytes.to_vec(), + version: display_event.version as i16, + bcs: event.contents.clone(), + }) + } + + pub fn to_display_update_event(&self) -> Result { + bcs::from_bytes(&self.bcs) + } +} diff --git a/crates/iota-indexer/src/models/epoch.rs b/crates/iota-indexer/src/models/epoch.rs new file mode 100644 index 00000000000..1383e22f884 --- /dev/null +++ b/crates/iota-indexer/src/models/epoch.rs @@ -0,0 +1,158 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use diesel::{Insertable, Queryable, Selectable}; +use iota_json_rpc_types::{EndOfEpochInfo, EpochInfo}; +use iota_types::iota_system_state::iota_system_state_summary::IotaSystemStateSummary; + +use crate::{errors::IndexerError, schema::epochs, types::IndexedEpochInfo}; + +#[derive(Queryable, Insertable, Debug, Clone, Default)] +#[diesel(table_name = epochs)] +pub struct StoredEpochInfo { + pub epoch: i64, + pub first_checkpoint_id: i64, + pub epoch_start_timestamp: i64, + pub reference_gas_price: i64, + pub protocol_version: i64, + pub total_stake: i64, + pub storage_fund_balance: i64, + pub system_state: Vec, + pub epoch_total_transactions: Option, + pub last_checkpoint_id: Option, + pub epoch_end_timestamp: Option, + pub storage_fund_reinvestment: Option, + pub storage_charge: Option, + pub storage_rebate: Option, + pub stake_subsidy_amount: Option, + pub total_gas_fees: Option, + pub total_stake_rewards_distributed: Option, + pub leftover_storage_fund_inflow: Option, + pub epoch_commitments: Option>, +} + +#[derive(Queryable, Selectable, Clone)] +#[diesel(table_name = epochs)] +pub struct QueryableEpochInfo { + pub epoch: i64, + pub first_checkpoint_id: i64, + pub epoch_start_timestamp: i64, + pub reference_gas_price: i64, + pub protocol_version: i64, + pub total_stake: i64, + pub storage_fund_balance: i64, + pub epoch_total_transactions: Option, + pub last_checkpoint_id: Option, + pub epoch_end_timestamp: Option, + pub storage_fund_reinvestment: Option, + pub storage_charge: Option, + pub storage_rebate: Option, + pub stake_subsidy_amount: Option, + pub total_gas_fees: Option, + pub total_stake_rewards_distributed: Option, + pub leftover_storage_fund_inflow: Option, + pub epoch_commitments: Option>, +} + +#[derive(Queryable)] +pub struct QueryableEpochSystemState { + pub epoch: i64, + pub system_state: Vec, +} + +impl StoredEpochInfo { + pub fn from_epoch_beginning_info(e: &IndexedEpochInfo) -> Self { + Self { + epoch: e.epoch as i64, + first_checkpoint_id: e.first_checkpoint_id as i64, + epoch_start_timestamp: e.epoch_start_timestamp as i64, + reference_gas_price: e.reference_gas_price as i64, + protocol_version: e.protocol_version as i64, + total_stake: e.total_stake as i64, + storage_fund_balance: e.storage_fund_balance as i64, + ..Default::default() + } + } + + pub fn from_epoch_end_info(e: &IndexedEpochInfo) -> Self { + Self { + epoch: e.epoch as i64, + system_state: e.system_state.clone(), + epoch_total_transactions: e.epoch_total_transactions.map(|v| v as i64), + last_checkpoint_id: e.last_checkpoint_id.map(|v| v as i64), + epoch_end_timestamp: e.epoch_end_timestamp.map(|v| v as i64), + storage_fund_reinvestment: e.storage_fund_reinvestment.map(|v| v as i64), + storage_charge: e.storage_charge.map(|v| v as i64), + storage_rebate: e.storage_rebate.map(|v| v as i64), + stake_subsidy_amount: e.stake_subsidy_amount.map(|v| v as i64), + total_gas_fees: e.total_gas_fees.map(|v| v as i64), + total_stake_rewards_distributed: e.total_stake_rewards_distributed.map(|v| v as i64), + leftover_storage_fund_inflow: e.leftover_storage_fund_inflow.map(|v| v as i64), + epoch_commitments: e + .epoch_commitments + .as_ref() + .map(|v| bcs::to_bytes(&v).unwrap()), + + // For the following fields: + // we don't update these columns when persisting EndOfEpoch data. + // However if the data is partial, diesel would interpret them + // as Null and hence cause errors. + first_checkpoint_id: 0, + epoch_start_timestamp: 0, + reference_gas_price: 0, + protocol_version: 0, + total_stake: 0, + storage_fund_balance: 0, + } + } +} + +impl From<&StoredEpochInfo> for Option { + fn from(info: &StoredEpochInfo) -> Option { + Some(EndOfEpochInfo { + reference_gas_price: (info.reference_gas_price as u64), + protocol_version: (info.protocol_version as u64), + last_checkpoint_id: info.last_checkpoint_id.map(|v| v as u64)?, + total_stake: info.total_stake as u64, + storage_fund_balance: info.storage_fund_balance as u64, + epoch_end_timestamp: info.epoch_end_timestamp.map(|v| v as u64)?, + storage_fund_reinvestment: info.storage_fund_reinvestment.map(|v| v as u64)?, + storage_charge: info.storage_charge.map(|v| v as u64)?, + storage_rebate: info.storage_rebate.map(|v| v as u64)?, + stake_subsidy_amount: info.stake_subsidy_amount.map(|v| v as u64)?, + total_gas_fees: info.total_gas_fees.map(|v| v as u64)?, + total_stake_rewards_distributed: info + .total_stake_rewards_distributed + .map(|v| v as u64)?, + leftover_storage_fund_inflow: info.leftover_storage_fund_inflow.map(|v| v as u64)?, + }) + } +} + +impl TryFrom for EpochInfo { + type Error = IndexerError; + + fn try_from(value: StoredEpochInfo) -> Result { + let epoch = value.epoch as u64; + let end_of_epoch_info = (&value).into(); + let system_state: Option = bcs::from_bytes(&value.system_state) + .map_err(|_| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "Failed to deserialize `system_state` for epoch {epoch}", + )) + }) + .ok(); + Ok(EpochInfo { + epoch: value.epoch as u64, + validators: system_state + .map(|s| s.active_validators) + .unwrap_or_default(), + epoch_total_transactions: value.epoch_total_transactions.unwrap_or(0) as u64, + first_checkpoint_id: value.first_checkpoint_id as u64, + epoch_start_timestamp: value.epoch_start_timestamp as u64, + end_of_epoch_info, + reference_gas_price: Some(value.reference_gas_price as u64), + }) + } +} diff --git a/crates/iota-indexer/src/models/events.rs b/crates/iota-indexer/src/models/events.rs new file mode 100644 index 00000000000..f1d195c71a1 --- /dev/null +++ b/crates/iota-indexer/src/models/events.rs @@ -0,0 +1,168 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::str::FromStr; + +use diesel::prelude::*; +use iota_json_rpc_types::{IotaEvent, IotaMoveStruct}; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + digests::TransactionDigest, + event::EventID, + object::{bounded_visitor::BoundedVisitor, MoveObject}, + parse_iota_struct_tag, +}; +use move_bytecode_utils::module_cache::GetModule; +use move_core_types::identifier::Identifier; + +use crate::{errors::IndexerError, schema::events, types::IndexedEvent}; + +#[derive(Queryable, QueryableByName, Insertable, Debug, Clone)] +#[diesel(table_name = events)] +pub struct StoredEvent { + #[diesel(sql_type = diesel::sql_types::BigInt)] + pub tx_sequence_number: i64, + + #[diesel(sql_type = diesel::sql_types::BigInt)] + pub event_sequence_number: i64, + + #[diesel(sql_type = diesel::sql_types::Bytea)] + pub transaction_digest: Vec, + + #[diesel(sql_type = diesel::sql_types::BigInt)] + pub checkpoint_sequence_number: i64, + + #[diesel(sql_type = diesel::sql_types::Array>)] + pub senders: Vec>>, + + #[diesel(sql_type = diesel::sql_types::Bytea)] + pub package: Vec, + + #[diesel(sql_type = diesel::sql_types::Text)] + pub module: String, + + #[diesel(sql_type = diesel::sql_types::Text)] + pub event_type: String, + + #[diesel(sql_type = diesel::sql_types::BigInt)] + pub timestamp_ms: i64, + + #[diesel(sql_type = diesel::sql_types::Bytea)] + pub bcs: Vec, +} + +impl From for StoredEvent { + fn from(event: IndexedEvent) -> Self { + Self { + tx_sequence_number: event.tx_sequence_number as i64, + event_sequence_number: event.event_sequence_number as i64, + transaction_digest: event.transaction_digest.into_inner().to_vec(), + checkpoint_sequence_number: event.checkpoint_sequence_number as i64, + senders: event + .senders + .into_iter() + .map(|sender| Some(sender.to_vec())) + .collect(), + package: event.package.to_vec(), + module: event.module.clone(), + event_type: event.event_type.clone(), + bcs: event.bcs.clone(), + timestamp_ms: event.timestamp_ms as i64, + } + } +} + +impl StoredEvent { + pub fn try_into_iota_event( + self, + module_cache: &impl GetModule, + ) -> Result { + let package_id = ObjectID::from_bytes(self.package.clone()).map_err(|_e| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "Failed to parse event package ID: {:?}", + self.package + )) + })?; + // Note: IotaEvent only has one sender today, so we always use the first one. + let sender = self.senders.first().ok_or_else(|| { + IndexerError::PersistentStorageDataCorruptionError( + "Event senders should contain at least one address".to_string(), + ) + })?; + let sender = match sender { + Some(s) => IotaAddress::from_bytes(s).map_err(|_e| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "Failed to parse event sender address: {:?}", + sender + )) + })?, + None => { + return Err(IndexerError::PersistentStorageDataCorruptionError( + "Event senders element should not be null".to_string(), + )); + } + }; + + let type_ = parse_iota_struct_tag(&self.event_type)?; + + let layout = MoveObject::get_layout_from_struct_tag(type_.clone(), module_cache)?; + let move_object = BoundedVisitor::deserialize_struct(&self.bcs, &layout) + .map_err(|e| IndexerError::SerdeError(e.to_string()))?; + let parsed_json = IotaMoveStruct::from(move_object).to_json_value(); + let tx_digest = + TransactionDigest::try_from(self.transaction_digest.as_slice()).map_err(|e| { + IndexerError::SerdeError(format!( + "Failed to parse transaction digest: {:?}, error: {}", + self.transaction_digest, e + )) + })?; + Ok(IotaEvent { + id: EventID { + tx_digest, + event_seq: self.event_sequence_number as u64, + }, + package_id, + transaction_module: Identifier::from_str(&self.module)?, + sender, + type_, + bcs: self.bcs, + parsed_json, + timestamp_ms: Some(self.timestamp_ms as u64), + }) + } +} + +#[cfg(test)] +mod tests { + use iota_types::event::Event; + use move_core_types::{account_address::AccountAddress, language_storage::StructTag}; + + use super::*; + + #[test] + fn test_canonical_string_of_event_type() { + let tx_digest = TransactionDigest::default(); + let event = Event { + package_id: ObjectID::random(), + transaction_module: Identifier::new("test").unwrap(), + sender: AccountAddress::random().into(), + type_: StructTag { + address: AccountAddress::TWO, + module: Identifier::new("test").unwrap(), + name: Identifier::new("test").unwrap(), + type_params: vec![], + }, + contents: vec![], + }; + + let indexed_event = IndexedEvent::from_event(1, 1, 1, tx_digest, &event, 100); + + let stored_event = StoredEvent::from(indexed_event); + + assert_eq!( + stored_event.event_type, + "0x0000000000000000000000000000000000000000000000000000000000000002::test::test" + ); + } +} diff --git a/crates/iota-indexer/src/models/mod.rs b/crates/iota-indexer/src/models/mod.rs new file mode 100644 index 00000000000..cfa32ddb294 --- /dev/null +++ b/crates/iota-indexer/src/models/mod.rs @@ -0,0 +1,12 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod checkpoints; +pub mod display; +pub mod epoch; +pub mod events; +pub mod objects; +pub mod packages; +pub mod transactions; +pub mod tx_indices; diff --git a/crates/iota-indexer/src/models/objects.rs b/crates/iota-indexer/src/models/objects.rs new file mode 100644 index 00000000000..f619eea21cd --- /dev/null +++ b/crates/iota-indexer/src/models/objects.rs @@ -0,0 +1,512 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashMap; + +use diesel::prelude::*; +use iota_json_rpc::coin_api::parse_to_struct_tag; +use iota_json_rpc_types::{Balance, Coin as IotaCoin}; +use iota_types::{ + base_types::{ObjectID, ObjectRef, SequenceNumber}, + digests::ObjectDigest, + dynamic_field::{DynamicFieldInfo, DynamicFieldName, DynamicFieldType, Field}, + object::{Object, ObjectRead}, +}; +use move_bytecode_utils::module_cache::GetModule; +use serde::de::DeserializeOwned; + +use crate::{ + errors::IndexerError, + schema::{objects, objects_history}, + types::{IndexedDeletedObject, IndexedObject, ObjectStatus}, +}; + +#[derive(Queryable)] +pub struct DynamicFieldColumn { + pub object_id: Vec, + pub object_version: i64, + pub object_digest: Vec, + pub df_kind: Option, + pub df_name: Option>, + pub df_object_type: Option, + pub df_object_id: Option>, +} + +#[derive(Queryable)] +pub struct ObjectRefColumn { + pub object_id: Vec, + pub object_version: i64, + pub object_digest: Vec, +} + +// NOTE: please add updating statement like below in pg_indexer_store.rs, +// if new columns are added here: +// objects::epoch.eq(excluded(objects::epoch)) +#[derive(Queryable, Insertable, Debug, Identifiable, Clone, QueryableByName)] +#[diesel(table_name = objects, primary_key(object_id))] +pub struct StoredObject { + pub object_id: Vec, + pub object_version: i64, + pub object_digest: Vec, + pub checkpoint_sequence_number: i64, + pub owner_type: i16, + pub owner_id: Option>, + /// The type of this object. This will be None if the object is a Package + pub object_type: Option, + pub serialized_object: Vec, + pub coin_type: Option, + // TODO deal with overflow + pub coin_balance: Option, + pub df_kind: Option, + pub df_name: Option>, + pub df_object_type: Option, + pub df_object_id: Option>, +} + +#[derive(Queryable, Insertable, Debug, Identifiable, Clone, QueryableByName)] +#[diesel(table_name = objects_history, primary_key(object_id, object_version, checkpoint_sequence_number))] +pub struct StoredHistoryObject { + pub object_id: Vec, + pub object_version: i64, + pub object_status: i16, + pub object_digest: Option>, + pub checkpoint_sequence_number: i64, + pub owner_type: Option, + pub owner_id: Option>, + pub object_type: Option, + pub serialized_object: Option>, + pub coin_type: Option, + pub coin_balance: Option, + pub df_kind: Option, + pub df_name: Option>, + pub df_object_type: Option, + pub df_object_id: Option>, +} + +impl From for StoredHistoryObject { + fn from(o: StoredObject) -> Self { + Self { + object_id: o.object_id, + object_version: o.object_version, + object_status: ObjectStatus::Active as i16, + object_digest: Some(o.object_digest), + checkpoint_sequence_number: o.checkpoint_sequence_number, + owner_type: Some(o.owner_type), + owner_id: o.owner_id, + object_type: o.object_type, + serialized_object: Some(o.serialized_object), + coin_type: o.coin_type, + coin_balance: o.coin_balance, + df_kind: o.df_kind, + df_name: o.df_name, + df_object_type: o.df_object_type, + df_object_id: o.df_object_id, + } + } +} + +#[derive(Queryable, Insertable, Debug, Identifiable, Clone, QueryableByName)] +#[diesel(table_name = objects, primary_key(object_id))] +pub struct StoredDeletedObject { + pub object_id: Vec, + pub object_version: i64, + pub checkpoint_sequence_number: i64, +} + +impl From for StoredDeletedObject { + fn from(o: IndexedDeletedObject) -> Self { + Self { + object_id: o.object_id.to_vec(), + object_version: o.object_version as i64, + checkpoint_sequence_number: o.checkpoint_sequence_number as i64, + } + } +} + +#[derive(Queryable, Insertable, Debug, Identifiable, Clone, QueryableByName)] +#[diesel(table_name = objects_history, primary_key(object_id, object_version, checkpoint_sequence_number))] +pub struct StoredDeletedHistoryObject { + pub object_id: Vec, + pub object_version: i64, + pub object_status: i16, + pub checkpoint_sequence_number: i64, +} + +impl From for StoredDeletedHistoryObject { + fn from(o: StoredDeletedObject) -> Self { + Self { + object_id: o.object_id, + object_version: o.object_version, + object_status: ObjectStatus::WrappedOrDeleted as i16, + checkpoint_sequence_number: o.checkpoint_sequence_number, + } + } +} + +impl From for StoredObject { + fn from(o: IndexedObject) -> Self { + Self { + object_id: o.object_id.to_vec(), + object_version: o.object_version as i64, + object_digest: o.object_digest.into_inner().to_vec(), + checkpoint_sequence_number: o.checkpoint_sequence_number as i64, + owner_type: o.owner_type as i16, + owner_id: o.owner_id.map(|id| id.to_vec()), + object_type: o + .object + .type_() + .map(|t| t.to_canonical_string(/* with_prefix */ true)), + serialized_object: bcs::to_bytes(&o.object).unwrap(), + coin_type: o.coin_type, + coin_balance: o.coin_balance.map(|b| b as i64), + df_kind: o.df_info.as_ref().map(|k| match k.type_ { + DynamicFieldType::DynamicField => 0, + DynamicFieldType::DynamicObject => 1, + }), + df_name: o.df_info.as_ref().map(|n| bcs::to_bytes(&n.name).unwrap()), + df_object_type: o.df_info.as_ref().map(|v| v.object_type.clone()), + df_object_id: o.df_info.as_ref().map(|v| v.object_id.to_vec()), + } + } +} + +impl TryFrom for Object { + type Error = IndexerError; + + fn try_from(o: StoredObject) -> Result { + bcs::from_bytes(&o.serialized_object).map_err(|e| { + IndexerError::SerdeError(format!( + "Failed to deserialize object: {:?}, error: {}", + o.object_id, e + )) + }) + } +} + +impl StoredObject { + pub fn try_into_object_read( + self, + module_cache: &impl GetModule, + ) -> Result { + let oref = self.get_object_ref()?; + let object: iota_types::object::Object = self.try_into()?; + let layout = object.get_layout(module_cache)?; + Ok(ObjectRead::Exists(oref, object, layout)) + } + + pub fn try_into_expectant_dynamic_field_info( + self, + module_cache: &impl GetModule, + ) -> Result { + match self.try_into_dynamic_field_info(module_cache).transpose() { + Some(Ok(info)) => Ok(info), + Some(Err(e)) => Err(e), + None => Err(IndexerError::PersistentStorageDataCorruptionError( + "Dynamic field object has incompatible dynamic field type: empty df_kind".into(), + )), + } + } + + pub fn try_into_dynamic_field_info( + self, + module_cache: &impl GetModule, + ) -> Result, IndexerError> { + if self.df_kind.is_none() { + return Ok(None); + } + + // Past this point, if there is any unexpected field, it's a data corruption + // error + let object_id = ObjectID::from_bytes(&self.object_id).map_err(|_| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "Can't convert {:?} to object_id", + self.object_id + )) + })?; + let object_digest = ObjectDigest::try_from(self.object_digest.as_slice()).map_err(|e| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "object {} has incompatible object digest. Error: {e}", + object_id + )) + })?; + let df_object_id = if let Some(df_object_id) = self.df_object_id { + ObjectID::from_bytes(df_object_id).map_err(|e| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "object {} has incompatible dynamic field type: df_object_id. Error: {e}", + object_id + )) + }) + } else { + return Err(IndexerError::PersistentStorageDataCorruptionError(format!( + "object {} has incompatible dynamic field type: empty df_object_id", + object_id + ))); + }?; + let type_ = match self.df_kind { + Some(0) => DynamicFieldType::DynamicField, + Some(1) => DynamicFieldType::DynamicObject, + _ => { + return Err(IndexerError::PersistentStorageDataCorruptionError(format!( + "object {} has incompatible dynamic field type: empty df_kind", + object_id + ))); + } + }; + let name = if let Some(field_name) = self.df_name { + let name: DynamicFieldName = bcs::from_bytes(&field_name).map_err(|e| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "object {} has incompatible dynamic field type: df_name. Error: {e}", + object_id + )) + })?; + name + } else { + return Err(IndexerError::PersistentStorageDataCorruptionError(format!( + "object {} has incompatible dynamic field type: empty df_name", + object_id + ))); + }; + let layout = move_bytecode_utils::layout::TypeLayoutBuilder::build_with_types( + &name.type_, + module_cache, + )?; + let iota_json_value = iota_json::IotaJsonValue::new(name.value.clone())?; + let bcs_name = iota_json_value.to_bcs_bytes(&layout)?; + let object_type = + self.df_object_type + .ok_or(IndexerError::PersistentStorageDataCorruptionError(format!( + "object {} has incompatible dynamic field type: empty df_object_type", + object_id + )))?; + Ok(Some(DynamicFieldInfo { + version: SequenceNumber::from_u64(self.object_version as u64), + digest: object_digest, + type_, + name, + bcs_name, + object_type, + object_id: df_object_id, + })) + } + + pub fn get_object_ref(&self) -> Result { + let object_id = ObjectID::from_bytes(self.object_id.clone()).map_err(|_| { + IndexerError::SerdeError(format!("Can't convert {:?} to object_id", self.object_id)) + })?; + let object_digest = + ObjectDigest::try_from(self.object_digest.as_slice()).map_err(|_| { + IndexerError::SerdeError(format!( + "Can't convert {:?} to object_digest", + self.object_digest + )) + })?; + Ok(( + object_id, + (self.object_version as u64).into(), + object_digest, + )) + } + + pub fn to_dynamic_field(&self) -> Option> + where + K: DeserializeOwned, + V: DeserializeOwned, + { + let object: Object = bcs::from_bytes(&self.serialized_object).ok()?; + + let object = object.data.try_as_move()?; + let ty = object.type_(); + + if !ty.is_dynamic_field() { + return None; + } + + bcs::from_bytes(object.contents()).ok() + } +} + +impl TryFrom for IotaCoin { + type Error = IndexerError; + + fn try_from(o: StoredObject) -> Result { + let object: Object = o.clone().try_into()?; + let (coin_object_id, version, digest) = o.get_object_ref()?; + let coin_type_canonical = + o.coin_type + .ok_or(IndexerError::PersistentStorageDataCorruptionError(format!( + "Object {} is supposed to be a coin but has an empty coin_type column", + coin_object_id, + )))?; + let coin_type = parse_to_struct_tag(coin_type_canonical.as_str()) + .map_err(|_| { + IndexerError::PersistentStorageDataCorruptionError(format!( + "The type of object {} cannot be parsed as a struct tag", + coin_object_id, + )) + })? + .to_string(); + let balance = o + .coin_balance + .ok_or(IndexerError::PersistentStorageDataCorruptionError(format!( + "Object {} is supposed to be a coin but has an empy coin_balance column", + coin_object_id, + )))?; + Ok(IotaCoin { + coin_type, + coin_object_id, + version, + digest, + balance: balance as u64, + previous_transaction: object.previous_transaction, + }) + } +} + +#[derive(QueryableByName)] +pub struct CoinBalance { + #[diesel(sql_type = diesel::sql_types::Text)] + pub coin_type: String, + #[diesel(sql_type = diesel::sql_types::BigInt)] + pub coin_num: i64, + #[diesel(sql_type = diesel::sql_types::BigInt)] + pub coin_balance: i64, +} + +impl TryFrom for Balance { + type Error = IndexerError; + + fn try_from(c: CoinBalance) -> Result { + let coin_type = parse_to_struct_tag(c.coin_type.as_str()) + .map_err(|_| { + IndexerError::PersistentStorageDataCorruptionError( + "The type of coin balance cannot be parsed as a struct tag".to_string(), + ) + })? + .to_string(); + Ok(Self { + coin_type, + coin_object_count: c.coin_num as usize, + // TODO: deal with overflow + total_balance: c.coin_balance as u128, + locked_balance: HashMap::default(), + }) + } +} + +#[cfg(test)] +mod tests { + use iota_types::{ + coin::Coin, + digests::TransactionDigest, + gas_coin::{GasCoin, GAS}, + object::{Data, MoveObject, ObjectInner, Owner}, + Identifier, TypeTag, + }; + use move_core_types::{account_address::AccountAddress, language_storage::StructTag}; + + use super::*; + + #[test] + fn test_canonical_string_of_object_type_for_coin() { + let test_obj = Object::new_gas_for_testing(); + let indexed_obj = IndexedObject::from_object(1, test_obj, None); + + let stored_obj = StoredObject::from(indexed_obj); + + match stored_obj.object_type { + Some(t) => { + assert_eq!( + t, + "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" + ); + } + None => { + panic!("object_type should not be none"); + } + } + } + + #[test] + fn test_convert_stored_obj_to_iota_coin() { + let test_obj = Object::new_gas_for_testing(); + let indexed_obj = IndexedObject::from_object(1, test_obj, None); + + let stored_obj = StoredObject::from(indexed_obj); + + let iota_coin = IotaCoin::try_from(stored_obj).unwrap(); + assert_eq!(iota_coin.coin_type, "0x2::iota::IOTA"); + } + + #[test] + fn test_output_format_coin_balance() { + let test_obj = Object::new_gas_for_testing(); + let indexed_obj = IndexedObject::from_object(1, test_obj, None); + + let stored_obj = StoredObject::from(indexed_obj); + let test_balance = CoinBalance { + coin_type: stored_obj.coin_type.unwrap(), + coin_num: 1, + coin_balance: 100, + }; + let balance = Balance::try_from(test_balance).unwrap(); + assert_eq!(balance.coin_type, "0x2::iota::IOTA"); + } + + #[test] + fn test_vec_of_coin_iota_conversion() { + // 0xe7::vec_coin::VecCoin>> + let vec_coins_type = TypeTag::Vector(Box::new( + Coin::type_(TypeTag::Struct(Box::new(GAS::type_()))).into(), + )); + let object_type = StructTag { + address: AccountAddress::from_hex_literal("0xe7").unwrap(), + module: Identifier::new("vec_coin").unwrap(), + name: Identifier::new("VecCoin").unwrap(), + type_params: vec![vec_coins_type], + }; + + let id = ObjectID::ZERO; + let gas = 10; + + let contents = bcs::to_bytes(&vec![GasCoin::new(id, gas)]).unwrap(); + let data = Data::Move( + unsafe { + MoveObject::new_from_execution_with_limit( + object_type.into(), + true, + 1.into(), + contents, + 256, + ) + } + .unwrap(), + ); + + let owner = AccountAddress::from_hex_literal("0x1").unwrap(); + + let object = ObjectInner { + owner: Owner::AddressOwner(owner.into()), + data, + previous_transaction: TransactionDigest::genesis_marker(), + storage_rebate: 0, + } + .into(); + + let indexed_obj = IndexedObject::from_object(1, object, None); + + let stored_obj = StoredObject::from(indexed_obj); + + match stored_obj.object_type { + Some(t) => { + assert_eq!( + t, + "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin>>" + ); + } + None => { + panic!("object_type should not be none"); + } + } + } +} diff --git a/crates/sui-indexer/src/models/packages.rs b/crates/iota-indexer/src/models/packages.rs similarity index 92% rename from crates/sui-indexer/src/models/packages.rs rename to crates/iota-indexer/src/models/packages.rs index f2be540fda7..e0e492f961b 100644 --- a/crates/sui-indexer/src/models/packages.rs +++ b/crates/iota-indexer/src/models/packages.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use diesel::prelude::*; diff --git a/crates/sui-indexer/src/models/transactions.rs b/crates/iota-indexer/src/models/transactions.rs similarity index 90% rename from crates/sui-indexer/src/models/transactions.rs rename to crates/iota-indexer/src/models/transactions.rs index 7d496f3aedd..87f641a0c72 100644 --- a/crates/sui-indexer/src/models/transactions.rs +++ b/crates/iota-indexer/src/models/transactions.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use diesel::prelude::*; -use move_bytecode_utils::module_cache::GetModule; -use sui_json_rpc_types::{ - BalanceChange, ObjectChange, SuiTransactionBlock, SuiTransactionBlockEffects, - SuiTransactionBlockEvents, SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, +use iota_json_rpc_types::{ + BalanceChange, IotaTransactionBlock, IotaTransactionBlockEffects, IotaTransactionBlockEvents, + IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, ObjectChange, }; -use sui_types::{ +use iota_types::{ digests::TransactionDigest, effects::{TransactionEffects, TransactionEvents}, event::Event, transaction::SenderSignedData, }; +use move_bytecode_utils::module_cache::GetModule; use crate::{ errors::IndexerError, @@ -97,11 +98,11 @@ impl From<&IndexedTransaction> for StoredTransaction { } impl StoredTransaction { - pub fn try_into_sui_transaction_block_response( + pub fn try_into_iota_transaction_block_response( self, - options: &SuiTransactionBlockResponseOptions, + options: &IotaTransactionBlockResponseOptions, module: &impl GetModule, - ) -> IndexerResult { + ) -> IndexerResult { let tx_digest = TransactionDigest::try_from(self.transaction_digest.as_slice()).map_err(|e| { IndexerError::PersistentStorageDataCorruptionError(format!( @@ -112,14 +113,14 @@ impl StoredTransaction { let transaction = if options.show_input { let sender_signed_data = self.try_into_sender_signed_data()?; - let tx_block = SuiTransactionBlock::try_from(sender_signed_data, module)?; + let tx_block = IotaTransactionBlock::try_from(sender_signed_data, module)?; Some(tx_block) } else { None }; let effects = if options.show_effects { - let effects = self.try_into_sui_transaction_effects()?; + let effects = self.try_into_iota_transaction_effects()?; Some(effects) } else { None @@ -153,7 +154,7 @@ impl StoredTransaction { .collect::, IndexerError>>()?; let timestamp = self.timestamp_ms as u64; let tx_events = TransactionEvents { data: events }; - let tx_events = SuiTransactionBlockEvents::try_from_using_module_resolver( + let tx_events = IotaTransactionBlockEvents::try_from_using_module_resolver( tx_events, tx_digest, Some(timestamp), @@ -202,7 +203,7 @@ impl StoredTransaction { None }; - Ok(SuiTransactionBlockResponse { + Ok(IotaTransactionBlockResponse { digest: tx_digest, transaction, raw_transaction, @@ -229,14 +230,14 @@ impl StoredTransaction { Ok(sender_signed_data) } - pub fn try_into_sui_transaction_effects(&self) -> IndexerResult { + pub fn try_into_iota_transaction_effects(&self) -> IndexerResult { let effects: TransactionEffects = bcs::from_bytes(&self.raw_effects).map_err(|e| { IndexerError::PersistentStorageDataCorruptionError(format!( "Can't convert raw_effects of {} into TransactionEffects. Error: {e}", self.tx_sequence_number )) })?; - let effects = SuiTransactionBlockEffects::try_from(effects)?; + let effects = IotaTransactionBlockEffects::try_from(effects)?; Ok(effects) } } diff --git a/crates/sui-indexer/src/models/tx_indices.rs b/crates/iota-indexer/src/models/tx_indices.rs similarity index 98% rename from crates/sui-indexer/src/models/tx_indices.rs rename to crates/iota-indexer/src/models/tx_indices.rs index 07339e1eb77..760958a7244 100644 --- a/crates/sui-indexer/src/models/tx_indices.rs +++ b/crates/iota-indexer/src/models/tx_indices.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use diesel::prelude::*; diff --git a/crates/iota-indexer/src/schema.patch b/crates/iota-indexer/src/schema.patch new file mode 100644 index 00000000000..414a955703d --- /dev/null +++ b/crates/iota-indexer/src/schema.patch @@ -0,0 +1,7 @@ +diff --git a/crates/iota-indexer/src/schema.rs b/crates/iota-indexer/src/schema.rs +--- a/crates/iota-indexer/src/schema.rs ++++ b/crates/iota-indexer/src/schema.rs +@@ -1 +1,3 @@ ++// Copyright (c) Mysten Labs, Inc. ++// SPDX-License-Identifier: Apache-2.0 + // @generated automatically by Diesel CLI. diff --git a/crates/iota-indexer/src/schema.rs b/crates/iota-indexer/src/schema.rs new file mode 100644 index 00000000000..4bf89cccbaa --- /dev/null +++ b/crates/iota-indexer/src/schema.rs @@ -0,0 +1,247 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +// @generated automatically by Diesel CLI. + +diesel::table! { + checkpoints (sequence_number) { + sequence_number -> Int8, + checkpoint_digest -> Bytea, + epoch -> Int8, + network_total_transactions -> Int8, + previous_checkpoint_digest -> Nullable, + end_of_epoch -> Bool, + tx_digests -> Array>, + timestamp_ms -> Int8, + total_gas_cost -> Int8, + computation_cost -> Int8, + storage_cost -> Int8, + storage_rebate -> Int8, + non_refundable_storage_fee -> Int8, + checkpoint_commitments -> Bytea, + validator_signature -> Bytea, + end_of_epoch_data -> Nullable, + } +} + +diesel::table! { + display (object_type) { + object_type -> Text, + id -> Bytea, + version -> Int2, + bcs -> Bytea, + } +} + +diesel::table! { + epochs (epoch) { + epoch -> Int8, + first_checkpoint_id -> Int8, + epoch_start_timestamp -> Int8, + reference_gas_price -> Int8, + protocol_version -> Int8, + total_stake -> Int8, + storage_fund_balance -> Int8, + system_state -> Bytea, + epoch_total_transactions -> Nullable, + last_checkpoint_id -> Nullable, + epoch_end_timestamp -> Nullable, + storage_fund_reinvestment -> Nullable, + storage_charge -> Nullable, + storage_rebate -> Nullable, + stake_subsidy_amount -> Nullable, + total_gas_fees -> Nullable, + total_stake_rewards_distributed -> Nullable, + leftover_storage_fund_inflow -> Nullable, + epoch_commitments -> Nullable, + } +} + +diesel::table! { + events (tx_sequence_number, event_sequence_number) { + tx_sequence_number -> Int8, + event_sequence_number -> Int8, + transaction_digest -> Bytea, + checkpoint_sequence_number -> Int8, + senders -> Array>, + package -> Bytea, + module -> Text, + event_type -> Text, + timestamp_ms -> Int8, + bcs -> Bytea, + } +} + +diesel::table! { + objects (object_id) { + object_id -> Bytea, + object_version -> Int8, + object_digest -> Bytea, + checkpoint_sequence_number -> Int8, + owner_type -> Int2, + owner_id -> Nullable, + object_type -> Nullable, + serialized_object -> Bytea, + coin_type -> Nullable, + coin_balance -> Nullable, + df_kind -> Nullable, + df_name -> Nullable, + df_object_type -> Nullable, + df_object_id -> Nullable, + } +} + +diesel::table! { + objects_history (checkpoint_sequence_number, object_id, object_version) { + object_id -> Bytea, + object_version -> Int8, + object_status -> Int2, + object_digest -> Nullable, + checkpoint_sequence_number -> Int8, + owner_type -> Nullable, + owner_id -> Nullable, + object_type -> Nullable, + serialized_object -> Nullable, + coin_type -> Nullable, + coin_balance -> Nullable, + df_kind -> Nullable, + df_name -> Nullable, + df_object_type -> Nullable, + df_object_id -> Nullable, + } +} + +diesel::table! { + objects_history_partition_0 (checkpoint_sequence_number, object_id, object_version) { + object_id -> Bytea, + object_version -> Int8, + object_status -> Int2, + object_digest -> Nullable, + checkpoint_sequence_number -> Int8, + owner_type -> Nullable, + owner_id -> Nullable, + object_type -> Nullable, + serialized_object -> Nullable, + coin_type -> Nullable, + coin_balance -> Nullable, + df_kind -> Nullable, + df_name -> Nullable, + df_object_type -> Nullable, + df_object_id -> Nullable, + } +} + +diesel::table! { + objects_snapshot (object_id) { + object_id -> Bytea, + object_version -> Int8, + object_status -> Int2, + object_digest -> Nullable, + checkpoint_sequence_number -> Int8, + owner_type -> Nullable, + owner_id -> Nullable, + object_type -> Nullable, + serialized_object -> Nullable, + coin_type -> Nullable, + coin_balance -> Nullable, + df_kind -> Nullable, + df_name -> Nullable, + df_object_type -> Nullable, + df_object_id -> Nullable, + } +} + +diesel::table! { + packages (package_id) { + package_id -> Bytea, + move_package -> Bytea, + } +} + +diesel::table! { + transactions (tx_sequence_number, checkpoint_sequence_number) { + tx_sequence_number -> Int8, + transaction_digest -> Bytea, + raw_transaction -> Bytea, + raw_effects -> Bytea, + checkpoint_sequence_number -> Int8, + timestamp_ms -> Int8, + object_changes -> Array>, + balance_changes -> Array>, + events -> Array>, + transaction_kind -> Int2, + success_command_count -> Int2, + } +} + +diesel::table! { + transactions_partition_0 (tx_sequence_number, checkpoint_sequence_number) { + tx_sequence_number -> Int8, + transaction_digest -> Bytea, + raw_transaction -> Bytea, + raw_effects -> Bytea, + checkpoint_sequence_number -> Int8, + timestamp_ms -> Int8, + object_changes -> Array>, + balance_changes -> Array>, + events -> Array>, + transaction_kind -> Int2, + success_command_count -> Int2, + } +} + +diesel::table! { + tx_calls (package, tx_sequence_number) { + tx_sequence_number -> Int8, + package -> Bytea, + module -> Text, + func -> Text, + } +} + +diesel::table! { + tx_changed_objects (object_id, tx_sequence_number) { + tx_sequence_number -> Int8, + object_id -> Bytea, + } +} + +diesel::table! { + tx_input_objects (object_id, tx_sequence_number) { + tx_sequence_number -> Int8, + object_id -> Bytea, + } +} + +diesel::table! { + tx_recipients (recipient, tx_sequence_number) { + tx_sequence_number -> Int8, + recipient -> Bytea, + } +} + +diesel::table! { + tx_senders (sender, tx_sequence_number) { + tx_sequence_number -> Int8, + sender -> Bytea, + } +} + +diesel::allow_tables_to_appear_in_same_query!( + checkpoints, + display, + epochs, + events, + objects, + objects_history, + objects_history_partition_0, + objects_snapshot, + packages, + transactions, + transactions_partition_0, + tx_calls, + tx_changed_objects, + tx_input_objects, + tx_recipients, + tx_senders, +); diff --git a/crates/sui-indexer/src/store/indexer_store.rs b/crates/iota-indexer/src/store/indexer_store.rs similarity index 97% rename from crates/sui-indexer/src/store/indexer_store.rs rename to crates/iota-indexer/src/store/indexer_store.rs index 4abf2e61efd..e7e20faf9f6 100644 --- a/crates/sui-indexer/src/store/indexer_store.rs +++ b/crates/iota-indexer/src/store/indexer_store.rs @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{any::Any, collections::BTreeMap, sync::Arc}; use async_trait::async_trait; -use move_binary_format::CompiledModule; -use move_bytecode_utils::module_cache::GetModule; -use sui_types::{ +use iota_types::{ base_types::{ObjectID, SequenceNumber}, object::ObjectRead, }; +use move_binary_format::CompiledModule; +use move_bytecode_utils::module_cache::GetModule; use crate::{ errors::IndexerError, diff --git a/crates/iota-indexer/src/store/mod.rs b/crates/iota-indexer/src/store/mod.rs new file mode 100644 index 00000000000..28e52c1c02a --- /dev/null +++ b/crates/iota-indexer/src/store/mod.rs @@ -0,0 +1,61 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub(crate) use indexer_store::*; +pub use pg_indexer_store::PgIndexerStore; + +pub mod indexer_store; +pub mod module_resolver; +mod pg_indexer_store; +mod pg_partition_manager; +mod query; + +pub(crate) mod diesel_macro { + macro_rules! read_only_blocking { + ($pool:expr, $query:expr) => {{ + let mut pg_pool_conn = crate::db::get_pg_pool_connection($pool)?; + pg_pool_conn + .build_transaction() + .read_only() + .run($query) + .map_err(|e| IndexerError::PostgresReadError(e.to_string())) + }}; + } + + macro_rules! transactional_blocking_with_retry { + ($pool:expr, $query:expr, $max_elapsed:expr) => {{ + let mut backoff = backoff::ExponentialBackoff::default(); + backoff.max_elapsed_time = Some($max_elapsed); + + let result = match backoff::retry(backoff, || { + let mut pg_pool_conn = crate::db::get_pg_pool_connection($pool).map_err(|e| { + backoff::Error::Transient { + err: IndexerError::PostgresWriteError(e.to_string()), + retry_after: None, + } + })?; + pg_pool_conn + .build_transaction() + .read_write() + .run($query) + .map_err(|e| { + tracing::error!("Error with persisting data into DB: {:?}", e); + backoff::Error::Transient { + err: IndexerError::PostgresWriteError(e.to_string()), + retry_after: None, + } + }) + }) { + Ok(v) => Ok(v), + Err(backoff::Error::Transient { err, .. }) => Err(err), + Err(backoff::Error::Permanent(err)) => Err(err), + }; + + result + }}; + } + + pub(crate) use read_only_blocking; + pub(crate) use transactional_blocking_with_retry; +} diff --git a/crates/sui-indexer/src/store/module_resolver.rs b/crates/iota-indexer/src/store/module_resolver.rs similarity index 97% rename from crates/sui-indexer/src/store/module_resolver.rs rename to crates/iota-indexer/src/store/module_resolver.rs index 705fa8acfd0..31e17a6fff3 100644 --- a/crates/sui-indexer/src/store/module_resolver.rs +++ b/crates/iota-indexer/src/store/module_resolver.rs @@ -1,19 +1,20 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::{Arc, Mutex}; use async_trait::async_trait; use diesel::{ExpressionMethods, OptionalExtension, QueryDsl, RunQueryDsl}; -use move_core_types::{ - account_address::AccountAddress, language_storage::ModuleId, resolver::ModuleResolver, -}; -use sui_package_resolver::{error::Error as PackageResolverError, Package, PackageStore}; -use sui_types::{ +use iota_package_resolver::{error::Error as PackageResolverError, Package, PackageStore}; +use iota_types::{ base_types::{ObjectID, SequenceNumber}, move_package::MovePackage, object::Object, }; +use move_core_types::{ + account_address::AccountAddress, language_storage::ModuleId, resolver::ModuleResolver, +}; use crate::{ db::PgConnectionPool, diff --git a/crates/sui-indexer/src/store/pg_indexer_store.rs b/crates/iota-indexer/src/store/pg_indexer_store.rs similarity index 99% rename from crates/sui-indexer/src/store/pg_indexer_store.rs rename to crates/iota-indexer/src/store/pg_indexer_store.rs index d28fe1bc819..246507639cc 100644 --- a/crates/sui-indexer/src/store/pg_indexer_store.rs +++ b/crates/iota-indexer/src/store/pg_indexer_store.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::result::Result::Ok; @@ -13,12 +14,12 @@ use async_trait::async_trait; use diesel::{ dsl::max, upsert::excluded, ExpressionMethods, OptionalExtension, QueryDsl, RunQueryDsl, }; -use itertools::Itertools; -use move_bytecode_utils::module_cache::SyncModuleCache; -use sui_types::{ +use iota_types::{ base_types::{ObjectID, SequenceNumber}, object::ObjectRead, }; +use itertools::Itertools; +use move_bytecode_utils::module_cache::SyncModuleCache; use tap::Tap; use tracing::info; diff --git a/crates/sui-indexer/src/store/pg_partition_manager.rs b/crates/iota-indexer/src/store/pg_partition_manager.rs similarity index 98% rename from crates/sui-indexer/src/store/pg_partition_manager.rs rename to crates/iota-indexer/src/store/pg_partition_manager.rs index bcdca85a2c5..e6e26701133 100644 --- a/crates/sui-indexer/src/store/pg_partition_manager.rs +++ b/crates/iota-indexer/src/store/pg_partition_manager.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, time::Duration}; diff --git a/crates/iota-indexer/src/store/query.rs b/crates/iota-indexer/src/store/query.rs new file mode 100644 index 00000000000..8071873a966 --- /dev/null +++ b/crates/iota-indexer/src/store/query.rs @@ -0,0 +1,332 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_json_rpc_types::IotaObjectDataFilter; +use iota_types::base_types::ObjectID; + +pub trait DBFilter { + fn to_objects_history_sql(&self, cursor: Option, limit: usize, columns: Vec<&str>) + -> String; + fn to_latest_objects_sql(&self, cursor: Option, limit: usize, columns: Vec<&str>) -> String; +} + +impl DBFilter for IotaObjectDataFilter { + fn to_objects_history_sql( + &self, + cursor: Option, + limit: usize, + columns: Vec<&str>, + ) -> String { + let inner_clauses = to_clauses(self); + let inner_clauses = if let Some(inner_clauses) = inner_clauses { + format!("\n AND {inner_clauses}") + } else { + "".to_string() + }; + let outer_clauses = to_outer_clauses(self); + let outer_clauses = if let Some(outer_clauses) = outer_clauses { + format!("\nAND {outer_clauses}") + } else { + "".to_string() + }; + let cursor = if let Some(cursor) = cursor { + format!("\n AND o.object_id > '{cursor}'") + } else { + "".to_string() + }; + + let columns = columns + .iter() + .map(|c| format!("t1.{c}")) + .collect::>() + .join(", "); + // NOTE: order by checkpoint DESC so that whenever a row from checkpoint is + // available, we will pick that over the one from fast-path, which has + // checkpoint of -1. + format!( + "SELECT {columns} +FROM (SELECT DISTINCT ON (o.object_id) * + FROM objects_history o + WHERE o.checkpoint <= $1{cursor}{inner_clauses} + ORDER BY o.object_id, version, o.checkpoint DESC) AS t1 +WHERE t1.object_status NOT IN ('deleted', 'wrapped', 'unwrapped_then_deleted'){outer_clauses} +LIMIT {limit};" + ) + } + + fn to_latest_objects_sql( + &self, + cursor: Option, + limit: usize, + columns: Vec<&str>, + ) -> String { + let columns = columns + .iter() + .map(|c| format!("o.{c}")) + .collect::>() + .join(", "); + + let cursor = if let Some(cursor) = cursor { + format!(" AND o.object_id > '{cursor}'") + } else { + "".to_string() + }; + + let inner_clauses = to_latest_objects_clauses(self); + let inner_clauses = if let Some(inner_clauses) = inner_clauses { + format!(" AND {inner_clauses}") + } else { + "".to_string() + }; + + format!( + "SELECT {columns} +FROM objects o WHERE o.object_status NOT IN ('deleted', 'wrapped', 'unwrapped_then_deleted'){cursor}{inner_clauses} +LIMIT {limit};" + ) + } +} + +fn to_latest_objects_clauses(filter: &IotaObjectDataFilter) -> Option { + match filter { + IotaObjectDataFilter::AddressOwner(a) => Some(format!( + "(o.owner_type = 'address_owner' AND o.owner_address = '{a}')" + )), + _ => None, + } +} + +fn to_clauses(filter: &IotaObjectDataFilter) -> Option { + match filter { + IotaObjectDataFilter::MatchAll(sub_filters) => { + let sub_filters = sub_filters.iter().flat_map(to_clauses).collect::>(); + if sub_filters.is_empty() { + None + } else if sub_filters.len() == 1 { + Some(sub_filters[0].to_string()) + } else { + Some(format!("({})", sub_filters.join(" AND "))) + } + } + IotaObjectDataFilter::MatchAny(sub_filters) => { + let sub_filters = sub_filters.iter().flat_map(to_clauses).collect::>(); + if sub_filters.is_empty() { + // Any default to false + Some("FALSE".to_string()) + } else if sub_filters.len() == 1 { + Some(sub_filters[0].to_string()) + } else { + Some(format!("({})", sub_filters.join(" OR "))) + } + } + IotaObjectDataFilter::MatchNone(sub_filters) => { + let sub_filters = sub_filters.iter().flat_map(to_clauses).collect::>(); + if sub_filters.is_empty() { + None + } else { + Some(format!("NOT ({})", sub_filters.join(" OR "))) + } + } + IotaObjectDataFilter::Package(p) => { + Some(format!("o.object_type LIKE '{}::%'", p.to_hex_literal())) + } + IotaObjectDataFilter::MoveModule { package, module } => Some(format!( + "o.object_type LIKE '{}::{}::%'", + package.to_hex_literal(), + module + )), + IotaObjectDataFilter::StructType(s) => { + // If people do not provide type_params, we will match all type_params + // e.g. `0x2::coin::Coin` can match `0x2::coin::Coin<0x2::iota::IOTA>` + if s.type_params.is_empty() { + Some(format!("o.object_type LIKE '{s}%'")) + } else { + Some(format!("o.object_type = '{s}'")) + } + } + IotaObjectDataFilter::AddressOwner(a) => Some(format!( + "((o.owner_type = 'address_owner' AND o.owner_address = '{a}') OR (o.old_owner_type = 'address_owner' AND o.old_owner_address = '{a}'))" + )), + IotaObjectDataFilter::ObjectOwner(o) => Some(format!( + "((o.owner_type = 'object_owner' AND o.owner_address = '{o}') OR (o.old_owner_type = 'object_owner' AND o.old_owner_address = '{o}'))" + )), + IotaObjectDataFilter::ObjectId(id) => Some(format!("o.object_id = '{id}'")), + IotaObjectDataFilter::ObjectIds(ids) => { + if ids.is_empty() { + None + } else { + let ids = ids + .iter() + .map(|o| o.to_string()) + .collect::>() + .join(", "); + Some(format!("o.object_id IN '{ids}'")) + } + } + IotaObjectDataFilter::Version(v) => Some(format!("o.version = {v}")), + } +} + +fn to_outer_clauses(filter: &IotaObjectDataFilter) -> Option { + match filter { + IotaObjectDataFilter::MatchNone(sub_filters) => { + let sub_filters = sub_filters + .iter() + .flat_map(to_outer_clauses) + .collect::>(); + if sub_filters.is_empty() { + None + } else { + Some(format!("NOT ({})", sub_filters.join(" OR "))) + } + } + IotaObjectDataFilter::MatchAll(sub_filters) => { + let sub_filters = sub_filters + .iter() + .flat_map(to_outer_clauses) + .collect::>(); + if sub_filters.is_empty() { + None + } else if sub_filters.len() == 1 { + Some(sub_filters[0].to_string()) + } else { + Some(format!("({})", sub_filters.join(" AND "))) + } + } + IotaObjectDataFilter::MatchAny(sub_filters) => { + let sub_filters = sub_filters + .iter() + .flat_map(to_outer_clauses) + .collect::>(); + if sub_filters.is_empty() { + None + } else if sub_filters.len() == 1 { + Some(sub_filters[0].to_string()) + } else { + Some(format!("({})", sub_filters.join(" OR "))) + } + } + IotaObjectDataFilter::AddressOwner(a) => Some(format!("t1.owner_address = '{a}'")), + _ => None, + } +} + +#[cfg(test)] +mod test { + use std::str::FromStr; + + use iota_json_rpc_types::IotaObjectDataFilter; + use iota_types::{ + base_types::{IotaAddress, ObjectID}, + parse_iota_struct_tag, + }; + use move_core_types::ident_str; + + use crate::store::query::DBFilter; + + #[test] + fn test_address_filter() { + let address = IotaAddress::from_str( + "0x92dd4d9b0150c251661d821583ef078024ae9e9ee11063e216500861eec7f381", + ) + .unwrap(); + let filter = IotaObjectDataFilter::AddressOwner(address); + + let expected_sql = "SELECT t1.* +FROM (SELECT DISTINCT ON (o.object_id) * + FROM objects_history o + WHERE o.checkpoint <= $1 + AND ((o.owner_type = 'address_owner' AND o.owner_address = '0x92dd4d9b0150c251661d821583ef078024ae9e9ee11063e216500861eec7f381') OR (o.old_owner_type = 'address_owner' AND o.old_owner_address = '0x92dd4d9b0150c251661d821583ef078024ae9e9ee11063e216500861eec7f381')) + ORDER BY o.object_id, version, o.checkpoint DESC) AS t1 +WHERE t1.object_status NOT IN ('deleted', 'wrapped', 'unwrapped_then_deleted') +AND t1.owner_address = '0x92dd4d9b0150c251661d821583ef078024ae9e9ee11063e216500861eec7f381' +LIMIT 100;"; + assert_eq!( + expected_sql, + filter.to_objects_history_sql(None, 100, vec!["*"]) + ); + } + + #[test] + fn test_move_module_filter() { + let filter = IotaObjectDataFilter::MoveModule { + package: ObjectID::from_str( + "0x485d947e293f07e659127dc5196146b49cdf2efbe4b233f4d293fc56aff2aa17", + ) + .unwrap(), + module: ident_str!("test_module").into(), + }; + let expected_sql = "SELECT t1.* +FROM (SELECT DISTINCT ON (o.object_id) * + FROM objects_history o + WHERE o.checkpoint <= $1 + AND o.object_type LIKE '0x485d947e293f07e659127dc5196146b49cdf2efbe4b233f4d293fc56aff2aa17::test_module::%' + ORDER BY o.object_id, version, o.checkpoint DESC) AS t1 +WHERE t1.object_status NOT IN ('deleted', 'wrapped', 'unwrapped_then_deleted') +LIMIT 100;"; + assert_eq!( + expected_sql, + filter.to_objects_history_sql(None, 100, vec!["*"]) + ); + } + + #[test] + fn test_empty_all_filter() { + let filter = IotaObjectDataFilter::MatchAll(vec![]); + let expected_sql = "SELECT t1.* +FROM (SELECT DISTINCT ON (o.object_id) * + FROM objects_history o + WHERE o.checkpoint <= $1 + ORDER BY o.object_id, version, o.checkpoint DESC) AS t1 +WHERE t1.object_status NOT IN ('deleted', 'wrapped', 'unwrapped_then_deleted') +LIMIT 100;"; + assert_eq!( + expected_sql, + filter.to_objects_history_sql(None, 100, vec!["*"]) + ); + } + + #[test] + fn test_empty_any_filter() { + let filter = IotaObjectDataFilter::MatchAny(vec![]); + let expected_sql = "SELECT t1.* +FROM (SELECT DISTINCT ON (o.object_id) * + FROM objects_history o + WHERE o.checkpoint <= $1 + AND FALSE + ORDER BY o.object_id, version, o.checkpoint DESC) AS t1 +WHERE t1.object_status NOT IN ('deleted', 'wrapped', 'unwrapped_then_deleted') +LIMIT 100;"; + assert_eq!( + expected_sql, + filter.to_objects_history_sql(None, 100, vec!["*"]) + ); + } + + #[test] + fn test_all_filter() { + let filter = IotaObjectDataFilter::MatchAll(vec![ + IotaObjectDataFilter::ObjectId( + ObjectID::from_str( + "0xef9fb75a7b3d4cb5551ef0b08c83528b94d5f5cd8be28b1d08a87dbbf3731738", + ) + .unwrap(), + ), + IotaObjectDataFilter::StructType(parse_iota_struct_tag("0x2::test::Test").unwrap()), + ]); + + let expected_sql = "SELECT t1.* +FROM (SELECT DISTINCT ON (o.object_id) * + FROM objects_history o + WHERE o.checkpoint <= $1 + AND (o.object_id = '0xef9fb75a7b3d4cb5551ef0b08c83528b94d5f5cd8be28b1d08a87dbbf3731738' AND o.object_type LIKE '0x2::test::Test%') + ORDER BY o.object_id, version, o.checkpoint DESC) AS t1 +WHERE t1.object_status NOT IN ('deleted', 'wrapped', 'unwrapped_then_deleted') +LIMIT 100;"; + assert_eq!( + expected_sql, + filter.to_objects_history_sql(None, 100, vec!["*"]) + ); + } +} diff --git a/crates/iota-indexer/src/test_utils.rs b/crates/iota-indexer/src/test_utils.rs new file mode 100644 index 00000000000..7f54fed35b7 --- /dev/null +++ b/crates/iota-indexer/src/test_utils.rs @@ -0,0 +1,274 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{env, net::SocketAddr, time::Duration}; + +use diesel::connection::SimpleConnection; +use iota_json_rpc_types::IotaTransactionBlockResponse; +use mysten_metrics::init_metrics; +use tokio::task::JoinHandle; +use tracing::info; + +use crate::{ + db::{new_pg_connection_pool_with_config, reset_database, PgConnectionPoolConfig}, + errors::IndexerError, + handlers::objects_snapshot_processor::SnapshotLagConfig, + indexer::Indexer, + store::PgIndexerStore, + IndexerConfig, IndexerMetrics, +}; + +pub enum ReaderWriterConfig { + Reader { reader_mode_rpc_url: String }, + Writer { snapshot_config: SnapshotLagConfig }, +} + +impl ReaderWriterConfig { + pub fn reader_mode(reader_mode_rpc_url: String) -> Self { + Self::Reader { + reader_mode_rpc_url, + } + } + + pub fn writer_mode(snapshot_config: Option) -> Self { + Self::Writer { + snapshot_config: snapshot_config.unwrap_or_default(), + } + } +} + +pub async fn start_test_indexer( + db_url: Option, + rpc_url: String, + reader_writer_config: ReaderWriterConfig, +) -> (PgIndexerStore, JoinHandle>) { + start_test_indexer_impl(db_url, rpc_url, reader_writer_config, None).await +} + +pub async fn start_test_indexer_impl( + db_url: Option, + rpc_url: String, + reader_writer_config: ReaderWriterConfig, + new_database: Option, +) -> (PgIndexerStore, JoinHandle>) { + // Reduce the connection pool size to 10 for testing + // to prevent maxing out + info!("Setting DB_POOL_SIZE to 10"); + std::env::set_var("DB_POOL_SIZE", "10"); + + let db_url = db_url.unwrap_or_else(|| { + let pg_host = env::var("POSTGRES_HOST").unwrap_or_else(|_| "localhost".into()); + let pg_port = env::var("POSTGRES_PORT").unwrap_or_else(|_| "32770".into()); + let pw = env::var("POSTGRES_PASSWORD").unwrap_or_else(|_| "postgrespw".into()); + format!("postgres://postgres:{pw}@{pg_host}:{pg_port}") + }); + + // dynamically set ports instead of all to 9000 + let base_port = rpc_url + .chars() + .rev() + .take(4) + .collect::() + .chars() + .rev() + .collect::() + .parse::() + .unwrap(); + + // Set connection timeout for tests to 1 second + let mut pool_config = PgConnectionPoolConfig::default(); + pool_config.set_connection_timeout(Duration::from_secs(1)); + + // Default writer mode + let mut config = IndexerConfig { + db_url: Some(db_url.clone()), + rpc_client_url: rpc_url, + reset_db: true, + fullnode_sync_worker: true, + rpc_server_worker: false, + rpc_server_port: base_port + 1, + ..Default::default() + }; + + let registry = prometheus::Registry::default(); + + init_metrics(®istry); + + let indexer_metrics = IndexerMetrics::new(®istry); + + let mut parsed_url = config.get_db_url().unwrap(); + + if let Some(new_database) = new_database { + // Switch to default to create a new database + let (default_db_url, _) = replace_db_name(&parsed_url, "postgres"); + + // Open in default mode + let blocking_pool = + new_pg_connection_pool_with_config(&default_db_url, Some(5), pool_config).unwrap(); + let mut default_conn = blocking_pool.get().unwrap(); + + // Delete the old db if it exists + default_conn + .batch_execute(&format!("DROP DATABASE IF EXISTS {}", new_database)) + .unwrap(); + + // Create the new db + default_conn + .batch_execute(&format!("CREATE DATABASE {}", new_database)) + .unwrap(); + parsed_url = replace_db_name(&parsed_url, &new_database).0; + } + + let blocking_pool = + new_pg_connection_pool_with_config(&parsed_url, Some(5), pool_config).unwrap(); + let store = PgIndexerStore::new(blocking_pool.clone(), indexer_metrics.clone()); + + let handle = match reader_writer_config { + ReaderWriterConfig::Reader { + reader_mode_rpc_url, + } => { + let reader_mode_rpc_url = reader_mode_rpc_url + .parse::() + .expect("Unable to parse fullnode address"); + config.fullnode_sync_worker = false; + config.rpc_server_worker = true; + config.rpc_server_url = reader_mode_rpc_url.ip().to_string(); + config.rpc_server_port = reader_mode_rpc_url.port(); + tokio::spawn(async move { Indexer::start_reader(&config, ®istry, db_url).await }) + } + ReaderWriterConfig::Writer { snapshot_config } => { + if config.reset_db { + reset_database(&mut blocking_pool.get().unwrap(), true).unwrap(); + } + let store_clone = store.clone(); + + tokio::spawn(async move { + Indexer::start_writer_with_config( + &config, + store_clone, + indexer_metrics, + snapshot_config, + ) + .await + }) + } + }; + + (store, handle) +} + +fn replace_db_name(db_url: &str, new_db_name: &str) -> (String, String) { + let pos = db_url.rfind('/').expect("Unable to find / in db_url"); + let old_db_name = &db_url[pos + 1..]; + + ( + format!("{}/{}", &db_url[..pos], new_db_name), + old_db_name.to_string(), + ) +} + +pub async fn force_delete_database(db_url: String) { + // Replace the database name with the default `postgres`, which should be the + // last string after `/` This is necessary because you can't drop a database + // while being connected to it. Hence switch to the default `postgres` + // database to drop the active database. + let (default_db_url, db_name) = replace_db_name(&db_url, "postgres"); + // Set connection timeout for tests to 1 second + let mut pool_config = PgConnectionPoolConfig::default(); + pool_config.set_connection_timeout(Duration::from_secs(1)); + + let blocking_pool = + new_pg_connection_pool_with_config(&default_db_url, Some(5), pool_config).unwrap(); + blocking_pool + .get() + .unwrap() + .batch_execute(&format!("DROP DATABASE IF EXISTS {} WITH (FORCE)", db_name)) + .unwrap(); +} + +#[derive(Clone)] +pub struct IotaTransactionBlockResponseBuilder<'a> { + response: IotaTransactionBlockResponse, + full_response: &'a IotaTransactionBlockResponse, +} + +impl<'a> IotaTransactionBlockResponseBuilder<'a> { + pub fn new(full_response: &'a IotaTransactionBlockResponse) -> Self { + Self { + response: IotaTransactionBlockResponse::default(), + full_response, + } + } + + pub fn with_input(mut self) -> Self { + self.response = IotaTransactionBlockResponse { + transaction: self.full_response.transaction.clone(), + ..self.response + }; + self + } + + pub fn with_raw_input(mut self) -> Self { + self.response = IotaTransactionBlockResponse { + raw_transaction: self.full_response.raw_transaction.clone(), + ..self.response + }; + self + } + + pub fn with_effects(mut self) -> Self { + self.response = IotaTransactionBlockResponse { + effects: self.full_response.effects.clone(), + ..self.response + }; + self + } + + pub fn with_events(mut self) -> Self { + self.response = IotaTransactionBlockResponse { + events: self.full_response.events.clone(), + ..self.response + }; + self + } + + pub fn with_balance_changes(mut self) -> Self { + self.response = IotaTransactionBlockResponse { + balance_changes: self.full_response.balance_changes.clone(), + ..self.response + }; + self + } + + pub fn with_object_changes(mut self) -> Self { + self.response = IotaTransactionBlockResponse { + object_changes: self.full_response.object_changes.clone(), + ..self.response + }; + self + } + + pub fn with_input_and_changes(mut self) -> Self { + self.response = IotaTransactionBlockResponse { + transaction: self.full_response.transaction.clone(), + balance_changes: self.full_response.balance_changes.clone(), + object_changes: self.full_response.object_changes.clone(), + ..self.response + }; + self + } + + pub fn build(self) -> IotaTransactionBlockResponse { + IotaTransactionBlockResponse { + transaction: self.response.transaction, + raw_transaction: self.response.raw_transaction, + effects: self.response.effects, + events: self.response.events, + balance_changes: self.response.balance_changes, + object_changes: self.response.object_changes, + // Use full response for any fields that aren't showable + ..self.full_response.clone() + } + } +} diff --git a/crates/iota-indexer/src/types.rs b/crates/iota-indexer/src/types.rs new file mode 100644 index 00000000000..c6e29053d4c --- /dev/null +++ b/crates/iota-indexer/src/types.rs @@ -0,0 +1,634 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_json_rpc_types::{ + IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, ObjectChange, +}; +use iota_types::{ + base_types::{IotaAddress, ObjectDigest, ObjectID, SequenceNumber}, + crypto::AggregateAuthoritySignature, + digests::TransactionDigest, + dynamic_field::DynamicFieldInfo, + effects::TransactionEffects, + event::SystemEpochInfoEvent, + iota_serde::IotaStructTag, + iota_system_state::iota_system_state_summary::IotaSystemStateSummary, + messages_checkpoint::{ + CertifiedCheckpointSummary, CheckpointCommitment, CheckpointDigest, EndOfEpochData, + }, + move_package::MovePackage, + object::{Object, Owner}, + transaction::SenderSignedData, +}; +use move_core_types::language_storage::StructTag; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +use crate::errors::IndexerError; + +pub type IndexerResult = Result; + +#[derive(Debug)] +pub struct IndexedCheckpoint { + pub sequence_number: u64, + pub checkpoint_digest: CheckpointDigest, + pub epoch: u64, + pub tx_digests: Vec, + pub network_total_transactions: u64, + pub previous_checkpoint_digest: Option, + pub timestamp_ms: u64, + pub total_gas_cost: i64, // total gas cost could be negative + pub computation_cost: u64, + pub storage_cost: u64, + pub storage_rebate: u64, + pub non_refundable_storage_fee: u64, + pub checkpoint_commitments: Vec, + pub validator_signature: AggregateAuthoritySignature, + pub successful_tx_num: usize, + pub end_of_epoch_data: Option, + pub end_of_epoch: bool, +} + +impl IndexedCheckpoint { + pub fn from_iota_checkpoint( + checkpoint: &iota_types::messages_checkpoint::CertifiedCheckpointSummary, + contents: &iota_types::messages_checkpoint::CheckpointContents, + successful_tx_num: usize, + ) -> Self { + let total_gas_cost = checkpoint.epoch_rolling_gas_cost_summary.computation_cost as i64 + + checkpoint.epoch_rolling_gas_cost_summary.storage_cost as i64 + - checkpoint.epoch_rolling_gas_cost_summary.storage_rebate as i64; + let tx_digests = contents.iter().map(|t| t.transaction).collect::>(); + let auth_sig = &checkpoint.auth_sig().signature; + Self { + sequence_number: checkpoint.sequence_number, + checkpoint_digest: *checkpoint.digest(), + epoch: checkpoint.epoch, + tx_digests, + previous_checkpoint_digest: checkpoint.previous_digest, + end_of_epoch_data: checkpoint.end_of_epoch_data.clone(), + end_of_epoch: checkpoint.end_of_epoch_data.clone().is_some(), + total_gas_cost, + computation_cost: checkpoint.epoch_rolling_gas_cost_summary.computation_cost, + storage_cost: checkpoint.epoch_rolling_gas_cost_summary.storage_cost, + storage_rebate: checkpoint.epoch_rolling_gas_cost_summary.storage_rebate, + non_refundable_storage_fee: checkpoint + .epoch_rolling_gas_cost_summary + .non_refundable_storage_fee, + successful_tx_num, + network_total_transactions: checkpoint.network_total_transactions, + timestamp_ms: checkpoint.timestamp_ms, + validator_signature: auth_sig.clone(), + checkpoint_commitments: checkpoint.checkpoint_commitments.clone(), + } + } +} + +#[derive(Clone, Debug, Default)] +pub struct IndexedEpochInfo { + pub epoch: u64, + pub first_checkpoint_id: u64, + pub epoch_start_timestamp: u64, + pub reference_gas_price: u64, + pub protocol_version: u64, + pub total_stake: u64, + pub storage_fund_balance: u64, + pub system_state: Vec, + pub epoch_total_transactions: Option, + pub last_checkpoint_id: Option, + pub epoch_end_timestamp: Option, + pub storage_fund_reinvestment: Option, + pub storage_charge: Option, + pub storage_rebate: Option, + pub stake_subsidy_amount: Option, + pub total_gas_fees: Option, + pub total_stake_rewards_distributed: Option, + pub leftover_storage_fund_inflow: Option, + pub epoch_commitments: Option>, +} + +impl IndexedEpochInfo { + pub fn from_new_system_state_summary( + new_system_state_summary: IotaSystemStateSummary, + first_checkpoint_id: u64, + event: Option<&SystemEpochInfoEvent>, + ) -> IndexedEpochInfo { + Self { + epoch: new_system_state_summary.epoch, + first_checkpoint_id, + epoch_start_timestamp: new_system_state_summary.epoch_start_timestamp_ms, + reference_gas_price: new_system_state_summary.reference_gas_price, + protocol_version: new_system_state_summary.protocol_version, + // NOTE: total_stake and storage_fund_balance are about new epoch, + // although the event is generated at the end of the previous epoch, + // the event is optional b/c no such event for the first epoch. + total_stake: event.map(|e| e.total_stake).unwrap_or(0), + storage_fund_balance: event.map(|e| e.storage_fund_balance).unwrap_or(0), + system_state: bcs::to_bytes(&new_system_state_summary).unwrap(), + ..Default::default() + } + } + + pub fn from_end_of_epoch_data( + system_state_summary: &IotaSystemStateSummary, + last_checkpoint_summary: &CertifiedCheckpointSummary, + event: &SystemEpochInfoEvent, + network_total_tx_num_at_last_epoch_end: u64, + ) -> IndexedEpochInfo { + Self { + epoch: last_checkpoint_summary.epoch, + epoch_total_transactions: Some( + last_checkpoint_summary.network_total_transactions + - network_total_tx_num_at_last_epoch_end, + ), + last_checkpoint_id: Some(*last_checkpoint_summary.sequence_number()), + epoch_end_timestamp: Some(last_checkpoint_summary.timestamp_ms), + storage_fund_reinvestment: Some(event.storage_fund_reinvestment), + storage_charge: Some(event.storage_charge), + storage_rebate: Some(event.storage_rebate), + leftover_storage_fund_inflow: Some(event.leftover_storage_fund_inflow), + stake_subsidy_amount: Some(event.stake_subsidy_amount), + total_gas_fees: Some(event.total_gas_fees), + total_stake_rewards_distributed: Some(event.total_stake_rewards_distributed), + epoch_commitments: last_checkpoint_summary + .end_of_epoch_data + .as_ref() + .map(|e| e.epoch_commitments.clone()), + system_state: bcs::to_bytes(system_state_summary).unwrap(), + // The following felds will not and shall not be upserted + // into DB. We have them below to make compiler and diesel happy + first_checkpoint_id: 0, + epoch_start_timestamp: 0, + reference_gas_price: 0, + protocol_version: 0, + total_stake: 0, + storage_fund_balance: 0, + } + } +} + +#[derive(Debug, Clone)] +pub struct IndexedEvent { + pub tx_sequence_number: u64, + pub event_sequence_number: u64, + pub checkpoint_sequence_number: u64, + pub transaction_digest: TransactionDigest, + pub senders: Vec, + pub package: ObjectID, + pub module: String, + pub event_type: String, + pub bcs: Vec, + pub timestamp_ms: u64, +} + +impl IndexedEvent { + pub fn from_event( + tx_sequence_number: u64, + event_sequence_number: u64, + checkpoint_sequence_number: u64, + transaction_digest: TransactionDigest, + event: &iota_types::event::Event, + timestamp_ms: u64, + ) -> Self { + Self { + tx_sequence_number, + event_sequence_number, + checkpoint_sequence_number, + transaction_digest, + senders: vec![event.sender], + package: event.package_id, + module: event.transaction_module.to_string(), + event_type: event.type_.to_canonical_string(/* with_prefix */ true), + bcs: event.contents.clone(), + timestamp_ms, + } + } +} + +#[derive(Debug, Copy, Clone)] +pub enum OwnerType { + Immutable = 0, + Address = 1, + Object = 2, + Shared = 3, +} + +pub enum ObjectStatus { + Active = 0, + WrappedOrDeleted = 1, +} + +impl TryFrom for ObjectStatus { + type Error = IndexerError; + + fn try_from(value: i16) -> Result { + Ok(match value { + 0 => ObjectStatus::Active, + 1 => ObjectStatus::WrappedOrDeleted, + value => { + return Err(IndexerError::PersistentStorageDataCorruptionError(format!( + "{value} as ObjectStatus" + ))); + } + }) + } +} + +impl TryFrom for OwnerType { + type Error = IndexerError; + + fn try_from(value: i16) -> Result { + Ok(match value { + 0 => OwnerType::Immutable, + 1 => OwnerType::Address, + 2 => OwnerType::Object, + 3 => OwnerType::Shared, + value => { + return Err(IndexerError::PersistentStorageDataCorruptionError(format!( + "{value} as OwnerType" + ))); + } + }) + } +} + +// Returns owner_type, owner_address +pub fn owner_to_owner_info(owner: &Owner) -> (OwnerType, Option) { + match owner { + Owner::AddressOwner(address) => (OwnerType::Address, Some(*address)), + Owner::ObjectOwner(address) => (OwnerType::Object, Some(*address)), + Owner::Shared { .. } => (OwnerType::Shared, None), + Owner::Immutable => (OwnerType::Immutable, None), + } +} + +#[derive(Debug, Copy, Clone)] +pub enum DynamicFieldKind { + DynamicField = 0, + DynamicObject = 1, +} + +#[derive(Clone, Debug)] +pub struct IndexedObject { + pub object_id: ObjectID, + pub object_version: u64, + pub object_digest: ObjectDigest, + pub checkpoint_sequence_number: u64, + pub owner_type: OwnerType, + pub owner_id: Option, + pub object: Object, + pub coin_type: Option, + pub coin_balance: Option, + pub df_info: Option, +} + +impl IndexedObject { + pub fn from_object( + checkpoint_sequence_number: u64, + object: Object, + df_info: Option, + ) -> Self { + let (owner_type, owner_id) = owner_to_owner_info(&object.owner); + let coin_type = object + .coin_type_maybe() + .map(|t| t.to_canonical_string(/* with_prefix */ true)); + let coin_balance = if coin_type.is_some() { + Some(object.get_coin_value_unsafe()) + } else { + None + }; + + Self { + checkpoint_sequence_number, + object_id: object.id(), + object_version: object.version().value(), + object_digest: object.digest(), + owner_type, + owner_id, + object, + coin_type, + coin_balance, + df_info, + } + } +} + +#[derive(Clone, Debug)] +pub struct IndexedDeletedObject { + pub object_id: ObjectID, + pub object_version: u64, + pub checkpoint_sequence_number: u64, +} + +#[derive(Debug)] +pub struct IndexedPackage { + pub package_id: ObjectID, + pub move_package: MovePackage, + pub checkpoint_sequence_number: u64, +} + +#[derive(Debug, Clone)] +pub enum TransactionKind { + SystemTransaction = 0, + ProgrammableTransaction = 1, +} + +#[derive(Debug, Clone)] +pub struct IndexedTransaction { + pub tx_sequence_number: u64, + pub tx_digest: TransactionDigest, + pub sender_signed_data: SenderSignedData, + pub effects: TransactionEffects, + pub checkpoint_sequence_number: u64, + pub timestamp_ms: u64, + pub object_changes: Vec, + pub balance_change: Vec, + pub events: Vec, + pub transaction_kind: TransactionKind, + pub successful_tx_num: u64, +} + +#[derive(Debug, Clone)] +pub struct TxIndex { + pub tx_sequence_number: u64, + pub transaction_digest: TransactionDigest, + pub checkpoint_sequence_number: u64, + pub input_objects: Vec, + pub changed_objects: Vec, + pub payers: Vec, + pub senders: Vec, + pub recipients: Vec, + pub move_calls: Vec<(ObjectID, String, String)>, +} + +// ObjectChange is not bcs deserializable, IndexedObjectChange is. +#[serde_as] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +pub enum IndexedObjectChange { + Published { + package_id: ObjectID, + version: SequenceNumber, + digest: ObjectDigest, + modules: Vec, + }, + Transferred { + sender: IotaAddress, + recipient: Owner, + #[serde_as(as = "IotaStructTag")] + object_type: StructTag, + object_id: ObjectID, + version: SequenceNumber, + digest: ObjectDigest, + }, + /// Object mutated. + Mutated { + sender: IotaAddress, + owner: Owner, + #[serde_as(as = "IotaStructTag")] + object_type: StructTag, + object_id: ObjectID, + version: SequenceNumber, + previous_version: SequenceNumber, + digest: ObjectDigest, + }, + /// Delete object + Deleted { + sender: IotaAddress, + #[serde_as(as = "IotaStructTag")] + object_type: StructTag, + object_id: ObjectID, + version: SequenceNumber, + }, + /// Wrapped object + Wrapped { + sender: IotaAddress, + #[serde_as(as = "IotaStructTag")] + object_type: StructTag, + object_id: ObjectID, + version: SequenceNumber, + }, + /// New object creation + Created { + sender: IotaAddress, + owner: Owner, + #[serde_as(as = "IotaStructTag")] + object_type: StructTag, + object_id: ObjectID, + version: SequenceNumber, + digest: ObjectDigest, + }, +} + +impl From for IndexedObjectChange { + fn from(oc: ObjectChange) -> Self { + match oc { + ObjectChange::Published { + package_id, + version, + digest, + modules, + } => Self::Published { + package_id, + version, + digest, + modules, + }, + ObjectChange::Transferred { + sender, + recipient, + object_type, + object_id, + version, + digest, + } => Self::Transferred { + sender, + recipient, + object_type, + object_id, + version, + digest, + }, + ObjectChange::Mutated { + sender, + owner, + object_type, + object_id, + version, + previous_version, + digest, + } => Self::Mutated { + sender, + owner, + object_type, + object_id, + version, + previous_version, + digest, + }, + ObjectChange::Deleted { + sender, + object_type, + object_id, + version, + } => Self::Deleted { + sender, + object_type, + object_id, + version, + }, + ObjectChange::Wrapped { + sender, + object_type, + object_id, + version, + } => Self::Wrapped { + sender, + object_type, + object_id, + version, + }, + ObjectChange::Created { + sender, + owner, + object_type, + object_id, + version, + digest, + } => Self::Created { + sender, + owner, + object_type, + object_id, + version, + digest, + }, + } + } +} + +impl From for ObjectChange { + fn from(val: IndexedObjectChange) -> Self { + match val { + IndexedObjectChange::Published { + package_id, + version, + digest, + modules, + } => ObjectChange::Published { + package_id, + version, + digest, + modules, + }, + IndexedObjectChange::Transferred { + sender, + recipient, + object_type, + object_id, + version, + digest, + } => ObjectChange::Transferred { + sender, + recipient, + object_type, + object_id, + version, + digest, + }, + IndexedObjectChange::Mutated { + sender, + owner, + object_type, + object_id, + version, + previous_version, + digest, + } => ObjectChange::Mutated { + sender, + owner, + object_type, + object_id, + version, + previous_version, + digest, + }, + IndexedObjectChange::Deleted { + sender, + object_type, + object_id, + version, + } => ObjectChange::Deleted { + sender, + object_type, + object_id, + version, + }, + IndexedObjectChange::Wrapped { + sender, + object_type, + object_id, + version, + } => ObjectChange::Wrapped { + sender, + object_type, + object_id, + version, + }, + IndexedObjectChange::Created { + sender, + owner, + object_type, + object_id, + version, + digest, + } => ObjectChange::Created { + sender, + owner, + object_type, + object_id, + version, + digest, + }, + } + } +} + +// IotaTransactionBlockResponseWithOptions is only used on the reading path +pub struct IotaTransactionBlockResponseWithOptions { + pub response: IotaTransactionBlockResponse, + pub options: IotaTransactionBlockResponseOptions, +} + +impl From for IotaTransactionBlockResponse { + fn from(value: IotaTransactionBlockResponseWithOptions) -> Self { + let IotaTransactionBlockResponseWithOptions { response, options } = value; + + IotaTransactionBlockResponse { + digest: response.digest, + transaction: options.show_input.then_some(response.transaction).flatten(), + raw_transaction: options + .show_raw_input + .then_some(response.raw_transaction) + .unwrap_or_default(), + effects: options.show_effects.then_some(response.effects).flatten(), + events: options.show_events.then_some(response.events).flatten(), + object_changes: options + .show_object_changes + .then_some(response.object_changes) + .flatten(), + balance_changes: options + .show_balance_changes + .then_some(response.balance_changes) + .flatten(), + timestamp_ms: response.timestamp_ms, + confirmed_local_execution: response.confirmed_local_execution, + checkpoint: response.checkpoint, + errors: vec![], + raw_effects: options + .show_raw_effects + .then_some(response.raw_effects) + .unwrap_or_default(), + } + } +} diff --git a/crates/sui-indexer/tests/ingestion_tests.rs b/crates/iota-indexer/tests/ingestion_tests.rs similarity index 93% rename from crates/sui-indexer/tests/ingestion_tests.rs rename to crates/iota-indexer/tests/ingestion_tests.rs index e7e5916d740..3e159204088 100644 --- a/crates/sui-indexer/tests/ingestion_tests.rs +++ b/crates/iota-indexer/tests/ingestion_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[cfg(feature = "pg_integration")] @@ -6,8 +7,7 @@ mod ingestion_tests { use std::{net::SocketAddr, sync::Arc, time::Duration}; use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl}; - use simulacrum::Simulacrum; - use sui_indexer::{ + use iota_indexer::{ db::get_pg_pool_connection, errors::{Context, IndexerError}, models::transactions::StoredTransaction, @@ -15,7 +15,8 @@ mod ingestion_tests { store::{indexer_store::IndexerStore, PgIndexerStore}, test_utils::{start_test_indexer, ReaderWriterConfig}, }; - use sui_types::{base_types::SuiAddress, effects::TransactionEffectsAPI, storage::ReadStore}; + use iota_types::{base_types::IotaAddress, effects::TransactionEffectsAPI, storage::ReadStore}; + use simulacrum::Simulacrum; use tokio::task::JoinHandle; macro_rules! read_only_blocking { @@ -30,7 +31,7 @@ mod ingestion_tests { } const DEFAULT_SERVER_PORT: u16 = 3000; - const DEFAULT_DB_URL: &str = "postgres://postgres:postgrespw@localhost:5432/sui_indexer"; + const DEFAULT_DB_URL: &str = "postgres://postgres:postgrespw@localhost:5432/iota_indexer"; /// Set up a test indexer fetching from a REST endpoint served by the given /// Simulacrum. @@ -53,7 +54,7 @@ mod ingestion_tests { .digest()) .into(); - sui_rest_api::RestService::new_without_version(sim, chain_id) + iota_rest_api::RestService::new_without_version(sim, chain_id) .start_service(server_url, Some("/rest".to_owned())) .await; }); @@ -94,7 +95,7 @@ mod ingestion_tests { let mut sim = Simulacrum::new(); // Execute a simple transaction. - let transfer_recipient = SuiAddress::random_for_testing_only(); + let transfer_recipient = IotaAddress::random_for_testing_only(); let (transaction, _) = sim.transfer_txn(transfer_recipient); let (effects, err) = sim.execute_transaction(transaction.clone()).unwrap(); assert!(err.is_none()); diff --git a/crates/iota-json-rpc-api/Cargo.toml b/crates/iota-json-rpc-api/Cargo.toml new file mode 100644 index 00000000000..dc667f3e976 --- /dev/null +++ b/crates/iota-json-rpc-api/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "iota-json-rpc-api" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +jsonrpsee.workspace = true +once_cell.workspace = true +prometheus.workspace = true +tap.workspace = true +tracing.workspace = true +fastcrypto.workspace = true +mysten-metrics.workspace = true +iota-json.workspace = true +iota-json-rpc-types.workspace = true +iota-open-rpc.workspace = true +iota-open-rpc-macros.workspace = true +iota-types.workspace = true + +# NOTE: It's important to keep the above dependency list short. +# This and the iota-sdk crate are widely used to develop on Iota and it's valuable +# to not have to pull in the entire iota repo for it. + +[dev-dependencies] diff --git a/crates/iota-json-rpc-api/src/coin.rs b/crates/iota-json-rpc-api/src/coin.rs new file mode 100644 index 00000000000..a44db351d31 --- /dev/null +++ b/crates/iota-json-rpc-api/src/coin.rs @@ -0,0 +1,81 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_json_rpc_types::{Balance, CoinPage, IotaCoinMetadata}; +use iota_open_rpc_macros::open_rpc; +use iota_types::{ + balance::Supply, + base_types::{IotaAddress, ObjectID}, +}; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; + +#[open_rpc(namespace = "iotax", tag = "Coin Query API")] +#[rpc(server, client, namespace = "iotax")] +pub trait CoinReadApi { + /// Return all Coin<`coin_type`> objects owned by an address. + #[rustfmt::skip] + #[method(name = "getCoins")] + async fn get_coins( + &self, + /// the owner's Iota address + owner: IotaAddress, + /// optional type name for the coin (e.g., 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC), default to 0x2::iota::IOTA if not specified. + coin_type: Option, + /// optional paging cursor + cursor: Option, + /// maximum number of items per page + limit: Option, + ) -> RpcResult; + + /// Return all Coin objects owned by an address. + #[rustfmt::skip] + #[method(name = "getAllCoins")] + async fn get_all_coins( + &self, + /// the owner's Iota address + owner: IotaAddress, + /// optional paging cursor + cursor: Option, + /// maximum number of items per page + limit: Option, + ) -> RpcResult; + + /// Return the total coin balance for one coin type, owned by the address owner. + #[rustfmt::skip] + #[method(name = "getBalance")] + async fn get_balance( + &self, + /// the owner's Iota address + owner: IotaAddress, + /// optional type names for the coin (e.g., 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC), default to 0x2::iota::IOTA if not specified. + coin_type: Option, + ) -> RpcResult; + + /// Return the total coin balance for all coin type, owned by the address owner. + #[rustfmt::skip] + #[method(name = "getAllBalances")] + async fn get_all_balances( + &self, + /// the owner's Iota address + owner: IotaAddress, + ) -> RpcResult>; + + /// Return metadata(e.g., symbol, decimals) for a coin + #[rustfmt::skip] + #[method(name = "getCoinMetadata")] + async fn get_coin_metadata( + &self, + /// type name for the coin (e.g., 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC) + coin_type: String, + ) -> RpcResult>; + + /// Return total supply for a coin + #[rustfmt::skip] + #[method(name = "getTotalSupply")] + async fn get_total_supply( + &self, + /// type name for the coin (e.g., 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC) + coin_type: String, + ) -> RpcResult; +} diff --git a/crates/sui-json-rpc-api/src/extended.rs b/crates/iota-json-rpc-api/src/extended.rs similarity index 79% rename from crates/sui-json-rpc-api/src/extended.rs rename to crates/iota-json-rpc-api/src/extended.rs index 083431b80b5..a24cf9bac81 100644 --- a/crates/sui-json-rpc-api/src/extended.rs +++ b/crates/iota-json-rpc-api/src/extended.rs @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -use sui_json_rpc_types::{ - CheckpointedObjectID, EpochInfo, EpochPage, QueryObjectsPage, SuiObjectResponseQuery, +use iota_json_rpc_types::{ + CheckpointedObjectID, EpochInfo, EpochPage, IotaObjectResponseQuery, QueryObjectsPage, }; -use sui_open_rpc_macros::open_rpc; -use sui_types::sui_serde::BigInt; +use iota_open_rpc_macros::open_rpc; +use iota_types::iota_serde::BigInt; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -#[open_rpc(namespace = "suix", tag = "Extended API")] -#[rpc(server, client, namespace = "suix")] +#[open_rpc(namespace = "iotax", tag = "Extended API")] +#[rpc(server, client, namespace = "iotax")] pub trait ExtendedApi { /// Return a list of epoch info #[rustfmt::skip] @@ -34,7 +35,7 @@ pub trait ExtendedApi { async fn query_objects( &self, /// the objects query criteria. - query: SuiObjectResponseQuery, + query: IotaObjectResponseQuery, /// An optional paging cursor. If provided, the query will start from the next item after the specified cursor. Default to start from the first item if not specified. cursor: Option, /// Max number of items returned per page, default to [QUERY_MAX_RESULT_LIMIT] if not specified. diff --git a/crates/iota-json-rpc-api/src/governance.rs b/crates/iota-json-rpc-api/src/governance.rs new file mode 100644 index 00000000000..e210d7a9a28 --- /dev/null +++ b/crates/iota-json-rpc-api/src/governance.rs @@ -0,0 +1,63 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_json_rpc_types::{DelegatedStake, DelegatedTimelockedStake, IotaCommittee, ValidatorApys}; +use iota_open_rpc_macros::open_rpc; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + iota_serde::BigInt, + iota_system_state::iota_system_state_summary::IotaSystemStateSummary, +}; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; + +#[open_rpc(namespace = "iotax", tag = "Governance Read API")] +#[rpc(server, client, namespace = "iotax")] +pub trait GovernanceReadApi { + /// Return one or more [DelegatedStake]. If a Stake was withdrawn its status + /// will be Unstaked. + #[method(name = "getStakesByIds")] + async fn get_stakes_by_ids( + &self, + staked_iota_ids: Vec, + ) -> RpcResult>; + + /// Return all [DelegatedStake]. + #[method(name = "getStakes")] + async fn get_stakes(&self, owner: IotaAddress) -> RpcResult>; + + /// Return one or more [DelegatedTimelockedStake]. If a Stake was withdrawn + /// its status will be Unstaked. + #[method(name = "getTimelockedStakesByIds")] + async fn get_timelocked_stakes_by_ids( + &self, + timelocked_staked_iota_ids: Vec, + ) -> RpcResult>; + + /// Return all [DelegatedTimelockedStake]. + #[method(name = "getTimelockedStakes")] + async fn get_timelocked_stakes( + &self, + owner: IotaAddress, + ) -> RpcResult>; + + /// Return the committee information for the asked `epoch`. + #[method(name = "getCommitteeInfo")] + async fn get_committee_info( + &self, + /// The epoch of interest. If None, default to the latest epoch + epoch: Option>, + ) -> RpcResult; + + /// Return the latest IOTA system state object on-chain. + #[method(name = "getLatestIotaSystemState")] + async fn get_latest_iota_system_state(&self) -> RpcResult; + + /// Return the reference gas price for the network + #[method(name = "getReferenceGasPrice")] + async fn get_reference_gas_price(&self) -> RpcResult>; + + /// Return the validator APY + #[method(name = "getValidatorsApy")] + async fn get_validators_apy(&self) -> RpcResult; +} diff --git a/crates/iota-json-rpc-api/src/indexer.rs b/crates/iota-json-rpc-api/src/indexer.rs new file mode 100644 index 00000000000..6a2a9adf93a --- /dev/null +++ b/crates/iota-json-rpc-api/src/indexer.rs @@ -0,0 +1,128 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_json_rpc_types::{ + DynamicFieldPage, EventFilter, EventPage, IotaEvent, IotaObjectResponse, + IotaObjectResponseQuery, IotaTransactionBlockEffects, IotaTransactionBlockResponseQuery, + ObjectsPage, Page, TransactionBlocksPage, TransactionFilter, +}; +use iota_open_rpc_macros::open_rpc; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + digests::TransactionDigest, + dynamic_field::DynamicFieldName, + event::EventID, +}; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; + +#[open_rpc(namespace = "iotax", tag = "Extended API")] +#[rpc(server, client, namespace = "iotax")] +pub trait IndexerApi { + /// Return the list of objects owned by an address. + /// Note that if the address owns more than `QUERY_MAX_RESULT_LIMIT` objects, + /// the pagination is not accurate, because previous page may have been updated when + /// the next page is fetched. + /// Please use iotax_queryObjects if this is a concern. + #[rustfmt::skip] + #[method(name = "getOwnedObjects")] + async fn get_owned_objects( + &self, + /// the owner's Iota address + address: IotaAddress, + /// the objects query criteria. + query: Option, + /// An optional paging cursor. If provided, the query will start from the next item after the specified cursor. Default to start from the first item if not specified. + cursor: Option, + /// Max number of items returned per page, default to [QUERY_MAX_RESULT_LIMIT] if not specified. + limit: Option, + ) -> RpcResult; + + /// Return list of transactions for a specified query criteria. + #[rustfmt::skip] + #[method(name = "queryTransactionBlocks")] + async fn query_transaction_blocks( + &self, + /// the transaction query criteria. + query: IotaTransactionBlockResponseQuery, + /// An optional paging cursor. If provided, the query will start from the next item after the specified cursor. Default to start from the first item if not specified. + cursor: Option, + /// Maximum item returned per page, default to QUERY_MAX_RESULT_LIMIT if not specified. + limit: Option, + /// query result ordering, default to false (ascending order), oldest record first. + descending_order: Option, + ) -> RpcResult; + + /// Return list of events for a specified query criteria. + #[rustfmt::skip] + #[method(name = "queryEvents")] + async fn query_events( + &self, + /// The event query criteria. See [Event filter](https://docs.iota.io/build/event_api#event-filters) documentation for examples. + query: EventFilter, + /// optional paging cursor + cursor: Option, + /// maximum number of items per page, default to [QUERY_MAX_RESULT_LIMIT] if not specified. + limit: Option, + /// query result ordering, default to false (ascending order), oldest record first. + descending_order: Option, + ) -> RpcResult; + + /// Subscribe to a stream of Iota event + #[rustfmt::skip] + #[subscription(name = "subscribeEvent", item = IotaEvent)] + fn subscribe_event( + &self, + /// The filter criteria of the event stream. See [Event filter](https://docs.iota.io/build/event_api#event-filters) documentation for examples. + filter: EventFilter, + ); + + /// Subscribe to a stream of Iota transaction effects + #[subscription(name = "subscribeTransaction", item = IotaTransactionBlockEffects)] + fn subscribe_transaction(&self, filter: TransactionFilter); + + /// Return the list of dynamic field objects owned by an object. + #[rustfmt::skip] + #[method(name = "getDynamicFields")] + async fn get_dynamic_fields( + &self, + /// The ID of the parent object + parent_object_id: ObjectID, + /// An optional paging cursor. If provided, the query will start from the next item after the specified cursor. Default to start from the first item if not specified. + cursor: Option, + /// Maximum item returned per page, default to [QUERY_MAX_RESULT_LIMIT] if not specified. + limit: Option, + ) -> RpcResult; + + /// Return the dynamic field object information for a specified object + #[rustfmt::skip] + #[method(name = "getDynamicFieldObject")] + async fn get_dynamic_field_object( + &self, + /// The ID of the queried parent object + parent_object_id: ObjectID, + /// The Name of the dynamic field + name: DynamicFieldName, + ) -> RpcResult; + + /// Return the resolved address given resolver and name + #[rustfmt::skip] + #[method(name = "resolveNameServiceAddress")] + async fn resolve_name_service_address( + &self, + /// The name to resolve + name: String, + ) -> RpcResult>; + + /// Return the resolved names given address, + /// if multiple names are resolved, the first one is the primary name. + #[rustfmt::skip] + #[method(name = "resolveNameServiceNames")] + async fn resolve_name_service_names( + &self, + /// The address to resolve + address: IotaAddress, + cursor: Option, + limit: Option, + ) -> RpcResult>; +} diff --git a/crates/iota-json-rpc-api/src/lib.rs b/crates/iota-json-rpc-api/src/lib.rs new file mode 100644 index 00000000000..4fc64c6fd18 --- /dev/null +++ b/crates/iota-json-rpc-api/src/lib.rs @@ -0,0 +1,289 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::anyhow; +pub use coin::{CoinReadApiClient, CoinReadApiOpenRpc, CoinReadApiServer}; +pub use extended::{ExtendedApiClient, ExtendedApiOpenRpc, ExtendedApiServer}; +pub use governance::{GovernanceReadApiClient, GovernanceReadApiOpenRpc, GovernanceReadApiServer}; +pub use indexer::{IndexerApiClient, IndexerApiOpenRpc, IndexerApiServer}; +pub use move_utils::{MoveUtilsClient, MoveUtilsOpenRpc, MoveUtilsServer}; +use mysten_metrics::histogram::Histogram; +use once_cell::sync::Lazy; +use prometheus::{register_int_counter_with_registry, IntCounter}; +pub use read::{ReadApiClient, ReadApiOpenRpc, ReadApiServer}; +use tap::TapFallible; +use tracing::warn; +pub use transaction_builder::{ + TransactionBuilderClient, TransactionBuilderOpenRpc, TransactionBuilderServer, +}; +pub use write::{WriteApiClient, WriteApiOpenRpc, WriteApiServer}; + +mod coin; +mod extended; +mod governance; +mod indexer; +mod move_utils; +mod read; +mod transaction_builder; +mod write; + +const RPC_QUERY_MAX_RESULT_LIMIT: &str = "RPC_QUERY_MAX_RESULT_LIMIT"; +const DEFAULT_RPC_QUERY_MAX_RESULT_LIMIT: usize = 50; + +pub static QUERY_MAX_RESULT_LIMIT: Lazy = Lazy::new(|| { + read_size_from_env(RPC_QUERY_MAX_RESULT_LIMIT).unwrap_or(DEFAULT_RPC_QUERY_MAX_RESULT_LIMIT) +}); + +// TODOD(chris): make this configurable +pub const QUERY_MAX_RESULT_LIMIT_CHECKPOINTS: usize = 100; + +pub fn cap_page_limit(limit: Option) -> usize { + let limit = limit.unwrap_or_default(); + if limit > *QUERY_MAX_RESULT_LIMIT || limit == 0 { + *QUERY_MAX_RESULT_LIMIT + } else { + limit + } +} + +pub fn validate_limit(limit: Option, max: usize) -> Result { + match limit { + Some(l) if l > max => Err(anyhow!("Page size limit {l} exceeds max limit {max}")), + Some(0) => Err(anyhow!("Page size limit cannot be smaller than 1")), + Some(l) => Ok(l), + None => Ok(max), + } +} + +#[derive(Clone)] +pub struct JsonRpcMetrics { + pub get_objects_limit: Histogram, + pub get_objects_result_size: Histogram, + pub get_objects_result_size_total: IntCounter, + pub get_tx_blocks_limit: Histogram, + pub get_tx_blocks_result_size: Histogram, + pub get_tx_blocks_result_size_total: IntCounter, + pub get_checkpoints_limit: Histogram, + pub get_checkpoints_result_size: Histogram, + pub get_checkpoints_result_size_total: IntCounter, + pub get_owned_objects_limit: Histogram, + pub get_owned_objects_result_size: Histogram, + pub get_owned_objects_result_size_total: IntCounter, + pub get_coins_limit: Histogram, + pub get_coins_result_size: Histogram, + pub get_coins_result_size_total: IntCounter, + pub get_dynamic_fields_limit: Histogram, + pub get_dynamic_fields_result_size: Histogram, + pub get_dynamic_fields_result_size_total: IntCounter, + pub query_tx_blocks_limit: Histogram, + pub query_tx_blocks_result_size: Histogram, + pub query_tx_blocks_result_size_total: IntCounter, + pub query_events_limit: Histogram, + pub query_events_result_size: Histogram, + pub query_events_result_size_total: IntCounter, + + pub get_stake_iota_result_size: Histogram, + pub get_stake_iota_result_size_total: IntCounter, + + pub get_stake_iota_latency: Histogram, + pub get_delegated_iota_latency: Histogram, + + pub orchestrator_latency_ms: Histogram, + pub post_orchestrator_latency_ms: Histogram, +} + +impl JsonRpcMetrics { + pub fn new(registry: &prometheus::Registry) -> Self { + Self { + get_objects_limit: Histogram::new_in_registry( + "json_rpc_get_objects_limit", + "The input limit for multi_get_objects, after applying the cap", + registry, + ), + get_objects_result_size: Histogram::new_in_registry( + "json_rpc_get_objects_result_size", + "The return size for multi_get_objects", + registry, + ), + get_objects_result_size_total: register_int_counter_with_registry!( + "json_rpc_get_objects_result_size_total", + "The total return size for multi_get_objects", + registry + ) + .unwrap(), + get_tx_blocks_limit: Histogram::new_in_registry( + "json_rpc_get_tx_blocks_limit", + "The input limit for get_tx_blocks, after applying the cap", + registry, + ), + get_tx_blocks_result_size: Histogram::new_in_registry( + "json_rpc_get_tx_blocks_result_size", + "The return size for get_tx_blocks", + registry, + ), + get_tx_blocks_result_size_total: register_int_counter_with_registry!( + "json_rpc_get_tx_blocks_result_size_total", + "The total return size for get_tx_blocks", + registry + ) + .unwrap(), + get_checkpoints_limit: Histogram::new_in_registry( + "json_rpc_get_checkpoints_limit", + "The input limit for get_checkpoints, after applying the cap", + registry, + ), + get_checkpoints_result_size: Histogram::new_in_registry( + "json_rpc_get_checkpoints_result_size", + "The return size for get_checkpoints", + registry, + ), + get_checkpoints_result_size_total: register_int_counter_with_registry!( + "json_rpc_get_checkpoints_result_size_total", + "The total return size for get_checkpoints", + registry + ) + .unwrap(), + get_owned_objects_limit: Histogram::new_in_registry( + "json_rpc_get_owned_objects_limit", + "The input limit for get_owned_objects, after applying the cap", + registry, + ), + get_owned_objects_result_size: Histogram::new_in_registry( + "json_rpc_get_owned_objects_result_size", + "The return size for get_owned_objects", + registry, + ), + get_owned_objects_result_size_total: register_int_counter_with_registry!( + "json_rpc_get_owned_objects_result_size_total", + "The total return size for get_owned_objects", + registry + ) + .unwrap(), + get_coins_limit: Histogram::new_in_registry( + "json_rpc_get_coins_limit", + "The input limit for get_coins, after applying the cap", + registry, + ), + get_coins_result_size: Histogram::new_in_registry( + "json_rpc_get_coins_result_size", + "The return size for get_coins", + registry, + ), + get_coins_result_size_total: register_int_counter_with_registry!( + "json_rpc_get_coins_result_size_total", + "The total return size for get_coins", + registry + ) + .unwrap(), + get_dynamic_fields_limit: Histogram::new_in_registry( + "json_rpc_get_dynamic_fields_limit", + "The input limit for get_dynamic_fields, after applying the cap", + registry, + ), + get_dynamic_fields_result_size: Histogram::new_in_registry( + "json_rpc_get_dynamic_fields_result_size", + "The return size for get_dynamic_fields", + registry, + ), + get_dynamic_fields_result_size_total: register_int_counter_with_registry!( + "json_rpc_get_dynamic_fields_result_size_total", + "The total return size for get_dynamic_fields", + registry + ) + .unwrap(), + query_tx_blocks_limit: Histogram::new_in_registry( + "json_rpc_query_tx_blocks_limit", + "The input limit for query_tx_blocks, after applying the cap", + registry, + ), + query_tx_blocks_result_size: Histogram::new_in_registry( + "json_rpc_query_tx_blocks_result_size", + "The return size for query_tx_blocks", + registry, + ), + query_tx_blocks_result_size_total: register_int_counter_with_registry!( + "json_rpc_query_tx_blocks_result_size_total", + "The total return size for query_tx_blocks", + registry + ) + .unwrap(), + query_events_limit: Histogram::new_in_registry( + "json_rpc_query_events_limit", + "The input limit for query_events, after applying the cap", + registry, + ), + query_events_result_size: Histogram::new_in_registry( + "json_rpc_query_events_result_size", + "The return size for query_events", + registry, + ), + query_events_result_size_total: register_int_counter_with_registry!( + "json_rpc_query_events_result_size_total", + "The total return size for query_events", + registry + ) + .unwrap(), + get_stake_iota_result_size: Histogram::new_in_registry( + "json_rpc_get_stake_iota_result_size", + "The return size for get_stake_iota", + registry, + ), + get_stake_iota_result_size_total: register_int_counter_with_registry!( + "json_rpc_get_stake_iota_result_size_total", + "The total return size for get_stake_iota", + registry + ) + .unwrap(), + get_stake_iota_latency: Histogram::new_in_registry( + "get_stake_iota_latency", + "The latency of get stake iota, in ms", + registry, + ), + get_delegated_iota_latency: Histogram::new_in_registry( + "get_delegated_iota_latency", + "The latency of get delegated iota, in ms", + registry, + ), + orchestrator_latency_ms: Histogram::new_in_registry( + "json_rpc_orchestrator_latency", + "The latency of submitting transaction via transaction orchestrator, in ms", + registry, + ), + post_orchestrator_latency_ms: Histogram::new_in_registry( + "json_rpc_post_orchestrator_latency", + "The latency of response processing after transaction orchestrator, in ms", + registry, + ), + } + } + + pub fn new_for_tests() -> Self { + let registry = prometheus::Registry::new(); + Self::new(®istry) + } +} + +pub fn read_size_from_env(var_name: &str) -> Option { + std::env::var(var_name) + .ok()? + .parse::() + .tap_err(|e| { + warn!( + "Env var {} does not contain valid usize integer: {}", + var_name, e + ) + }) + .ok() +} + +pub const CLIENT_SDK_TYPE_HEADER: &str = "client-sdk-type"; +/// The version number of the SDK itself. This can be different from the API +/// version. +pub const CLIENT_SDK_VERSION_HEADER: &str = "client-sdk-version"; +/// The RPC API version that the client is targeting. Different SDK versions may +/// target the same API version. +pub const CLIENT_TARGET_API_VERSION_HEADER: &str = "client-target-api-version"; + +pub const TRANSIENT_ERROR_CODE: i32 = -32050; +pub const TRANSACTION_EXECUTION_CLIENT_ERROR_CODE: i32 = -32002; diff --git a/crates/iota-json-rpc-api/src/move_utils.rs b/crates/iota-json-rpc-api/src/move_utils.rs new file mode 100644 index 00000000000..1a6397b2a2c --- /dev/null +++ b/crates/iota-json-rpc-api/src/move_utils.rs @@ -0,0 +1,60 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use iota_json_rpc_types::{ + IotaMoveNormalizedFunction, IotaMoveNormalizedModule, IotaMoveNormalizedStruct, + MoveFunctionArgType, +}; +use iota_open_rpc_macros::open_rpc; +use iota_types::base_types::ObjectID; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; + +#[open_rpc(namespace = "iota", tag = "Move Utils")] +#[rpc(server, client, namespace = "iota")] +pub trait MoveUtils { + /// Return the argument types of a Move function, + /// based on normalized Type. + #[method(name = "getMoveFunctionArgTypes")] + async fn get_move_function_arg_types( + &self, + package: ObjectID, + module: String, + function: String, + ) -> RpcResult>; + + /// Return structured representations of all modules in the given package + #[method(name = "getNormalizedMoveModulesByPackage")] + async fn get_normalized_move_modules_by_package( + &self, + package: ObjectID, + ) -> RpcResult>; + + /// Return a structured representation of Move module + #[method(name = "getNormalizedMoveModule")] + async fn get_normalized_move_module( + &self, + package: ObjectID, + module_name: String, + ) -> RpcResult; + + /// Return a structured representation of Move struct + #[method(name = "getNormalizedMoveStruct")] + async fn get_normalized_move_struct( + &self, + package: ObjectID, + module_name: String, + struct_name: String, + ) -> RpcResult; + + /// Return a structured representation of Move function + #[method(name = "getNormalizedMoveFunction")] + async fn get_normalized_move_function( + &self, + package: ObjectID, + module_name: String, + function_name: String, + ) -> RpcResult; +} diff --git a/crates/sui-json-rpc-api/src/read.rs b/crates/iota-json-rpc-api/src/read.rs similarity index 82% rename from crates/sui-json-rpc-api/src/read.rs rename to crates/iota-json-rpc-api/src/read.rs index f3defa59ed2..efdd267d639 100644 --- a/crates/sui-json-rpc-api/src/read.rs +++ b/crates/iota-json-rpc-api/src/read.rs @@ -1,21 +1,22 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -use sui_json_rpc_types::{ - Checkpoint, CheckpointId, CheckpointPage, ProtocolConfigResponse, SuiEvent, - SuiGetPastObjectRequest, SuiLoadedChildObjectsResponse, SuiObjectDataOptions, - SuiObjectResponse, SuiPastObjectResponse, SuiTransactionBlockResponse, - SuiTransactionBlockResponseOptions, +use iota_json_rpc_types::{ + Checkpoint, CheckpointId, CheckpointPage, IotaEvent, IotaGetPastObjectRequest, + IotaLoadedChildObjectsResponse, IotaObjectDataOptions, IotaObjectResponse, + IotaPastObjectResponse, IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, + ProtocolConfigResponse, }; -use sui_open_rpc_macros::open_rpc; -use sui_types::{ +use iota_open_rpc_macros::open_rpc; +use iota_types::{ base_types::{ObjectID, SequenceNumber, TransactionDigest}, - sui_serde::BigInt, + iota_serde::BigInt, }; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -#[open_rpc(namespace = "sui", tag = "Read API")] -#[rpc(server, client, namespace = "sui")] +#[open_rpc(namespace = "iota", tag = "Read API")] +#[rpc(server, client, namespace = "iota")] pub trait ReadApi { /// Return the transaction response object. #[rustfmt::skip] @@ -25,8 +26,8 @@ pub trait ReadApi { /// the digest of the queried transaction digest: TransactionDigest, /// options for specifying the content to be returned - options: Option, - ) -> RpcResult; + options: Option, + ) -> RpcResult; /// Returns an ordered list of transaction responses /// The method will throw an error if the input contains any duplicate or @@ -38,8 +39,8 @@ pub trait ReadApi { /// A list of transaction digests. digests: Vec, /// config options to control which fields to fetch - options: Option, - ) -> RpcResult>; + options: Option, + ) -> RpcResult>; /// Return the object information for a specified object #[rustfmt::skip] @@ -49,8 +50,8 @@ pub trait ReadApi { /// the ID of the queried object object_id: ObjectID, /// options for specifying the content to be returned - options: Option, - ) -> RpcResult; + options: Option, + ) -> RpcResult; /// Return the object data for a list of objects #[rustfmt::skip] @@ -60,8 +61,8 @@ pub trait ReadApi { /// the IDs of the queried objects object_ids: Vec, /// options for specifying the content to be returned - options: Option, - ) -> RpcResult>; + options: Option, + ) -> RpcResult>; /// Note there is no software-level guarantee/SLA that objects with past versions /// can be retrieved by this API, even if the object and version exists/existed. @@ -76,8 +77,8 @@ pub trait ReadApi { /// the version of the queried object. If None, default to the latest known version version: SequenceNumber, /// options for specifying the content to be returned - options: Option, - ) -> RpcResult; + options: Option, + ) -> RpcResult; /// Note there is no software-level guarantee/SLA that objects with past versions /// can be retrieved by this API, even if the object and version exists/existed. @@ -88,16 +89,16 @@ pub trait ReadApi { async fn try_multi_get_past_objects( &self, /// a vector of object and versions to be queried - past_objects: Vec, + past_objects: Vec, /// options for specifying the content to be returned - options: Option, - ) -> RpcResult>; + options: Option, + ) -> RpcResult>; #[method(name = "getLoadedChildObjects")] async fn get_loaded_child_objects( &self, digest: TransactionDigest, - ) -> RpcResult; + ) -> RpcResult; /// Return a checkpoint #[rustfmt::skip] @@ -140,7 +141,7 @@ pub trait ReadApi { &self, /// the event query criteria. transaction_digest: TransactionDigest, - ) -> RpcResult>; + ) -> RpcResult>; /// Return the total number of transaction blocks known to the server. #[method(name = "getTotalTransactionBlocks")] diff --git a/crates/iota-json-rpc-api/src/transaction_builder.rs b/crates/iota-json-rpc-api/src/transaction_builder.rs new file mode 100644 index 00000000000..37e179f96b7 --- /dev/null +++ b/crates/iota-json-rpc-api/src/transaction_builder.rs @@ -0,0 +1,300 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use fastcrypto::encoding::Base64; +use iota_json::IotaJsonValue; +use iota_json_rpc_types::{ + IotaTransactionBlockBuilderMode, IotaTypeTag, RPCTransactionRequestParams, + TransactionBlockBytes, +}; +use iota_open_rpc_macros::open_rpc; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + iota_serde::BigInt, +}; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; + +#[open_rpc(namespace = "unsafe", tag = "Transaction Builder API")] +#[rpc(server, client, namespace = "unsafe")] +pub trait TransactionBuilder { + /// Create an unsigned transaction to transfer an object from one address to another. The object's type + /// must allow public transfers + #[rustfmt::skip] + #[method(name = "transferObject")] + async fn transfer_object( + &self, + /// the transaction signer's Iota address + signer: IotaAddress, + /// the ID of the object to be transferred + object_id: ObjectID, + /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided + gas: Option, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + /// the recipient's Iota address + recipient: IotaAddress, + ) -> RpcResult; + + /// Create an unsigned transaction to send IOTA coin object to a Iota address. The IOTA object is also used as the gas object. + #[rustfmt::skip] + #[method(name = "transferIota")] + async fn transfer_iota( + &self, + /// the transaction signer's Iota address + signer: IotaAddress, + /// the Iota coin object to be used in this transaction + iota_object_id: ObjectID, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + /// the recipient's Iota address + recipient: IotaAddress, + /// the amount to be split out and transferred + amount: Option>, + ) -> RpcResult; + + /// Send `Coin` to a list of addresses, where `T` can be any coin type, following a list of amounts, + /// The object specified in the `gas` field will be used to pay the gas fee for the transaction. + /// The gas object can not appear in `input_coins`. If the gas object is not specified, the RPC server + /// will auto-select one. + #[rustfmt::skip] + #[method(name = "pay")] + async fn pay( + &self, + /// the transaction signer's Iota address + signer: IotaAddress, + /// the Iota coins to be used in this transaction + input_coins: Vec, + /// the recipients' addresses, the length of this vector must be the same as amounts. + recipients: Vec, + /// the amounts to be transferred to recipients, following the same order + amounts: Vec>, + /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided + gas: Option, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + ) -> RpcResult; + + /// Send IOTA coins to a list of addresses, following a list of amounts. + /// This is for IOTA coin only and does not require a separate gas coin object. + /// Specifically, what pay_iota does are: + /// 1. debit each input_coin to create new coin following the order of + /// amounts and assign it to the corresponding recipient. + /// 2. accumulate all residual IOTA from input coins left and deposit all IOTA to the first + /// input coin, then use the first input coin as the gas coin object. + /// 3. the balance of the first input coin after tx is sum(input_coins) - sum(amounts) - actual_gas_cost + /// 4. all other input coints other than the first one are deleted. + #[rustfmt::skip] + #[method(name = "payIota")] + async fn pay_iota( + &self, + /// the transaction signer's Iota address + signer: IotaAddress, + /// the Iota coins to be used in this transaction, including the coin for gas payment. + input_coins: Vec, + /// the recipients' addresses, the length of this vector must be the same as amounts. + recipients: Vec, + /// the amounts to be transferred to recipients, following the same order + amounts: Vec>, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + ) -> RpcResult; + + /// Send all IOTA coins to one recipient. + /// This is for IOTA coin only and does not require a separate gas coin object. + /// Specifically, what pay_all_iota does are: + /// 1. accumulate all IOTA from input coins and deposit all IOTA to the first input coin + /// 2. transfer the updated first coin to the recipient and also use this first coin as gas coin object. + /// 3. the balance of the first input coin after tx is sum(input_coins) - actual_gas_cost. + /// 4. all other input coins other than the first are deleted. + #[rustfmt::skip] + #[method(name = "payAllIota")] + async fn pay_all_iota( + &self, + /// the transaction signer's Iota address + signer: IotaAddress, + /// the Iota coins to be used in this transaction, including the coin for gas payment. + input_coins: Vec, + /// the recipient address, + recipient: IotaAddress, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + ) -> RpcResult; + + /// Create an unsigned transaction to execute a Move call on the network, by calling the specified function in the module of a given package. + #[rustfmt::skip] + #[method(name = "moveCall")] + async fn move_call( + &self, + /// the transaction signer's Iota address + signer: IotaAddress, + /// the Move package ID, e.g. `0x2` + package_object_id: ObjectID, + /// the Move module name, e.g. `pay` + module: String, + /// the move function name, e.g. `split` + function: String, + /// the type arguments of the Move function + type_arguments: Vec, + /// the arguments to be passed into the Move function, in [IotaJson](https://docs.iota.io/build/iota-json) format + arguments: Vec, + /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided + gas: Option, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + /// Whether this is a Normal transaction or a Dev Inspect Transaction. Default to be `IotaTransactionBlockBuilderMode::Commit` when it's None. + execution_mode: Option, + ) -> RpcResult; + + /// Create an unsigned transaction to publish a Move package. + #[rustfmt::skip] + #[method(name = "publish")] + async fn publish( + &self, + /// the transaction signer's Iota address + sender: IotaAddress, + /// the compiled bytes of a Move package + compiled_modules: Vec, + /// a list of transitive dependency addresses that this set of modules depends on. + dependencies: Vec, + /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided + gas: Option, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + ) -> RpcResult; + + /// Create an unsigned transaction to split a coin object into multiple + /// coins. + #[rustfmt::skip] + #[method(name = "splitCoin")] + async fn split_coin( + &self, + /// the transaction signer's Iota address + signer: IotaAddress, + /// the coin object to be spilt + coin_object_id: ObjectID, + /// the amounts to split out from the coin + split_amounts: Vec>, + /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided + gas: Option, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + ) -> RpcResult; + + /// Create an unsigned transaction to split a coin object into multiple equal-size coins. + #[rustfmt::skip] + #[method(name = "splitCoinEqual")] + async fn split_coin_equal( + &self, + /// the transaction signer's Iota address + signer: IotaAddress, + /// the coin object to be spilt + coin_object_id: ObjectID, + /// the number of coins to split into + split_count: BigInt, + /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided + gas: Option, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + ) -> RpcResult; + + /// Create an unsigned transaction to merge multiple coins into one coin. + #[rustfmt::skip] + #[method(name = "mergeCoins")] + async fn merge_coin( + &self, + /// the transaction signer's Iota address + signer: IotaAddress, + /// the coin object to merge into, this coin will remain after the transaction + primary_coin: ObjectID, + /// the coin object to be merged, this coin will be destroyed, the balance will be added to `primary_coin` + coin_to_merge: ObjectID, + /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided + gas: Option, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + ) -> RpcResult; + + /// Create an unsigned batched transaction. + #[rustfmt::skip] + #[method(name = "batchTransaction")] + async fn batch_transaction( + &self, + /// the transaction signer's Iota address + signer: IotaAddress, + /// list of transaction request parameters + single_transaction_params: Vec, + /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided + gas: Option, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + /// Whether this is a regular transaction or a Dev Inspect Transaction + txn_builder_mode: Option, + ) -> RpcResult; + + /// Add stake to a validator's staking pool using multiple coins and amount. + #[rustfmt::skip] + #[method(name = "requestAddStake")] + async fn request_add_stake( + &self, + /// the transaction signer's Iota address + signer: IotaAddress, + /// Coin object to stake + coins: Vec, + /// stake amount + amount: Option>, + /// the validator's Iota address + validator: IotaAddress, + /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided + gas: Option, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + ) -> RpcResult; + + /// Withdraw stake from a validator's staking pool. + #[rustfmt::skip] + #[method(name = "requestWithdrawStake")] + async fn request_withdraw_stake( + &self, + /// the transaction signer's Iota address + signer: IotaAddress, + /// StakedIota object ID + staked_iota: ObjectID, + /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided + gas: Option, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + ) -> RpcResult; + + /// Add timelocked stake to a validator's staking pool using multiple balances and amount. + #[rustfmt::skip] + #[method(name = "requestAddTimelockedStake")] + async fn request_add_timelocked_stake( + &self, + /// the transaction signer's Iota address + signer: IotaAddress, + /// TimeLock> object to stake + locked_balance: ObjectID, + /// the validator's Iota address + validator: IotaAddress, + /// gas object to be used in this transaction + gas: ObjectID, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + ) -> RpcResult; + + /// Withdraw timelocked stake from a validator's staking pool. + #[rustfmt::skip] + #[method(name = "requestWithdrawTimelockedStake")] + async fn request_withdraw_timelocked_stake( + &self, + /// the transaction signer's Iota address + signer: IotaAddress, + /// TimelockedStakedIota object ID + timelocked_staked_iota: ObjectID, + /// gas object to be used in this transaction + gas: ObjectID, + /// the gas budget, the transaction will fail if the gas cost exceed the budget + gas_budget: BigInt, + ) -> RpcResult; +} diff --git a/crates/sui-json-rpc-api/src/write.rs b/crates/iota-json-rpc-api/src/write.rs similarity index 82% rename from crates/sui-json-rpc-api/src/write.rs rename to crates/iota-json-rpc-api/src/write.rs index 822b9ee1271..7df0809e1cb 100644 --- a/crates/sui-json-rpc-api/src/write.rs +++ b/crates/iota-json-rpc-api/src/write.rs @@ -1,19 +1,20 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use fastcrypto::encoding::Base64; -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -use sui_json_rpc_types::{ - DevInspectArgs, DevInspectResults, DryRunTransactionBlockResponse, SuiTransactionBlockResponse, - SuiTransactionBlockResponseOptions, +use iota_json_rpc_types::{ + DevInspectArgs, DevInspectResults, DryRunTransactionBlockResponse, + IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, }; -use sui_open_rpc_macros::open_rpc; -use sui_types::{ - base_types::SuiAddress, quorum_driver_types::ExecuteTransactionRequestType, sui_serde::BigInt, +use iota_open_rpc_macros::open_rpc; +use iota_types::{ + base_types::IotaAddress, iota_serde::BigInt, quorum_driver_types::ExecuteTransactionRequestType, }; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -#[open_rpc(namespace = "sui", tag = "Write API")] -#[rpc(server, client, namespace = "sui")] +#[open_rpc(namespace = "iota", tag = "Write API")] +#[rpc(server, client, namespace = "iota")] pub trait WriteApi { /// Execute the transaction and wait for results if desired. /// Request types: @@ -34,10 +35,10 @@ pub trait WriteApi { /// A list of signatures (`flag || signature || pubkey` bytes, as base-64 encoded string). Signature is committed to the intent message of the transaction data, as base-64 encoded string. signatures: Vec, /// options for specifying the content to be returned - options: Option, - /// The request type, derived from `SuiTransactionBlockResponseOptions` if None + options: Option, + /// The request type, derived from `IotaTransactionBlockResponseOptions` if None request_type: Option, - ) -> RpcResult; + ) -> RpcResult; /// Runs the transaction in dev-inspect mode. Which allows for nearly any /// transaction (or Move call) with any arguments. Detailed results are @@ -46,7 +47,7 @@ pub trait WriteApi { #[method(name = "devInspectTransactionBlock")] async fn dev_inspect_transaction_block( &self, - sender_address: SuiAddress, + sender_address: IotaAddress, /// BCS encoded TransactionKind(as opposed to TransactionData, which include gasBudget and gasPrice) tx_bytes: Base64, /// Gas is not charged, but gas usage is still calculated. Default to use reference gas price diff --git a/crates/iota-json-rpc-tests/Cargo.toml b/crates/iota-json-rpc-tests/Cargo.toml new file mode 100644 index 00000000000..84d578d3b99 --- /dev/null +++ b/crates/iota-json-rpc-tests/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "iota-json-rpc-tests" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] + +[dev-dependencies] +move-package.workspace = true +iota-config.workspace = true +iota-core.workspace = true +iota-keys.workspace = true +iota-move-build.workspace = true +iota-test-transaction-builder.workspace = true +iota-sdk.workspace = true +iota-macros.workspace = true +iota-simulator.workspace = true +iota-json.workspace = true +iota-json-rpc.workspace = true +iota-json-rpc-api.workspace = true +iota-json-rpc-types.workspace = true +iota-open-rpc.workspace = true +iota-open-rpc-macros.workspace = true +iota-protocol-config.workspace = true +iota-swarm-config.workspace = true +iota-types.workspace = true +test-cluster.workspace = true +telemetry-subscribers.workspace = true + +anyhow.workspace = true +async-trait.workspace = true +bcs.workspace = true +hyper.workspace = true +jsonrpsee.workspace = true +prometheus.workspace = true +rand.workspace = true +reqwest.workspace = true +tokio = { workspace = true, features = ["full"] } +tracing.workspace = true + diff --git a/crates/sui-json-rpc-tests/tests/balance_changes_tests.rs b/crates/iota-json-rpc-tests/tests/balance_changes_tests.rs similarity index 87% rename from crates/sui-json-rpc-tests/tests/balance_changes_tests.rs rename to crates/iota-json-rpc-tests/tests/balance_changes_tests.rs index 508d9f10c92..e1745bbc2bf 100644 --- a/crates/sui-json-rpc-tests/tests/balance_changes_tests.rs +++ b/crates/iota-json-rpc-tests/tests/balance_changes_tests.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::PathBuf; -use sui_move_build::{BuildConfig, SuiPackageHooks}; -use sui_sdk::SuiClient; -use sui_types::{ +use iota_move_build::{BuildConfig, IotaPackageHooks}; +use iota_sdk::IotaClient; +use iota_types::{ programmable_transaction_builder::ProgrammableTransactionBuilder, transaction::{TransactionData, TransactionKind}, }; @@ -17,10 +18,10 @@ async fn test_dry_run_publish_with_mocked_coin() -> Result<(), anyhow::Error> { let context = &cluster.wallet; let address = cluster.get_address_0(); - let client: SuiClient = context.get_client().await.unwrap(); + let client: IotaClient = context.get_client().await.unwrap(); // Publish test coin package - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); path.extend(["tests", "data", "dummy_modules_publish"]); let compiled_package = BuildConfig::default().build(path)?; diff --git a/crates/iota-json-rpc-tests/tests/data/dummy_modules_publish/Move.toml b/crates/iota-json-rpc-tests/tests/data/dummy_modules_publish/Move.toml new file mode 100644 index 00000000000..e518fc169a9 --- /dev/null +++ b/crates/iota-json-rpc-tests/tests/data/dummy_modules_publish/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "Examples" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../iota-framework/packages/iota-framework" } + +[addresses] +examples = "0x0" diff --git a/crates/iota-json-rpc-tests/tests/data/dummy_modules_publish/sources/trusted_coin.move b/crates/iota-json-rpc-tests/tests/data/dummy_modules_publish/sources/trusted_coin.move new file mode 100644 index 00000000000..1a53fb598a5 --- /dev/null +++ b/crates/iota-json-rpc-tests/tests/data/dummy_modules_publish/sources/trusted_coin.move @@ -0,0 +1,40 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Example coin with a trusted owner responsible for minting/burning (e.g., a stablecoin) +module examples::trusted_coin { + use std::option; + use iota::coin::{Self, TreasuryCap}; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; + + /// Name of the coin + struct TRUSTED_COIN has drop {} + + /// Register the trusted currency to acquire its `TreasuryCap`. Because + /// this is a module initializer, it ensures the currency only gets + /// registered once. + fun init(witness: TRUSTED_COIN, ctx: &mut TxContext) { + // Get a treasury cap for the coin and give it to the transaction + // sender + let (treasury_cap, metadata) = coin::create_currency(witness, 2, b"TRUSTED", b"Trusted Coin", b"Trusted Coin for test", option::none(), ctx); + transfer::public_freeze_object(metadata); + transfer::public_transfer(treasury_cap, tx_context::sender(ctx)) + } + + public entry fun mint(treasury_cap: &mut TreasuryCap, amount: u64, ctx: &mut TxContext) { + let coin = coin::mint(treasury_cap, amount, ctx); + transfer::public_transfer(coin, tx_context::sender(ctx)); + } + + public entry fun transfer(treasury_cap: TreasuryCap, recipient: address) { + transfer::public_transfer(treasury_cap, recipient); + } + + #[test_only] + /// Wrapper of module initializer for testing + public fun test_init(ctx: &mut TxContext) { + init(TRUSTED_COIN {}, ctx) + } +} diff --git a/crates/iota-json-rpc-tests/tests/name_service_tests.rs b/crates/iota-json-rpc-tests/tests/name_service_tests.rs new file mode 100644 index 00000000000..ad9a9e678b6 --- /dev/null +++ b/crates/iota-json-rpc-tests/tests/name_service_tests.rs @@ -0,0 +1,115 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::str::FromStr; + +use iota_json_rpc::name_service::{self, Domain}; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + collection_types::VecMap, +}; + +#[test] +fn test_parent_extraction() { + let mut name = Domain::from_str("leaf.node.test.iota").unwrap(); + + assert_eq!(name.parent().to_string(), "node.test.iota"); + + name = Domain::from_str("node.test.iota").unwrap(); + + assert_eq!(name.parent().to_string(), "test.iota"); +} + +#[test] +fn test_expirations() { + let system_time: u64 = 100; + + let mut name = name_service::NameRecord { + nft_id: iota_types::id::ID::new(ObjectID::random()), + data: VecMap { contents: vec![] }, + target_address: Some(IotaAddress::random_for_testing_only()), + expiration_timestamp_ms: system_time + 10, + }; + + assert!(!name.is_node_expired(system_time)); + + name.expiration_timestamp_ms = system_time - 10; + + assert!(name.is_node_expired(system_time)); +} + +#[test] +fn test_name_service_outputs() { + assert_eq!("@test".parse::().unwrap().to_string(), "test.iota"); + assert_eq!( + "test.iota".parse::().unwrap().to_string(), + "test.iota" + ); + assert_eq!( + "test@sld".parse::().unwrap().to_string(), + "test.sld.iota" + ); + assert_eq!( + "test.test@example".parse::().unwrap().to_string(), + "test.test.example.iota" + ); + assert_eq!( + "iota@iota".parse::().unwrap().to_string(), + "iota.iota.iota" + ); + + assert_eq!("@iota".parse::().unwrap().to_string(), "iota.iota"); + + assert_eq!( + "test*test@test".parse::().unwrap().to_string(), + "test.test.test.iota" + ); + assert_eq!( + "test.test.iota".parse::().unwrap().to_string(), + "test.test.iota" + ); + assert_eq!( + "test.test.test.iota".parse::().unwrap().to_string(), + "test.test.test.iota" + ); +} + +#[test] +fn test_different_wildcard() { + assert_eq!("test.iota".parse::(), "test*iota".parse::(),); + + assert_eq!("@test".parse::(), "test*iota".parse::(),); +} + +#[test] +fn test_invalid_inputs() { + assert!("*".parse::().is_err()); + assert!(".".parse::().is_err()); + assert!("@".parse::().is_err()); + assert!("@inner.iota".parse::().is_err()); + assert!("@inner*iota".parse::().is_err()); + assert!("test@".parse::().is_err()); + assert!("iota".parse::().is_err()); + assert!("test.test@example.iota".parse::().is_err()); + assert!("test@test@example".parse::().is_err()); +} + +#[test] +fn output_tests() { + let mut domain = "test.iota".parse::().unwrap(); + assert!(domain.format(name_service::DomainFormat::Dot) == "test.iota"); + assert!(domain.format(name_service::DomainFormat::At) == "@test"); + + domain = "test.test.iota".parse::().unwrap(); + assert!(domain.format(name_service::DomainFormat::Dot) == "test.test.iota"); + assert!(domain.format(name_service::DomainFormat::At) == "test@test"); + + domain = "test.test.test.iota".parse::().unwrap(); + assert!(domain.format(name_service::DomainFormat::Dot) == "test.test.test.iota"); + assert!(domain.format(name_service::DomainFormat::At) == "test.test@test"); + + domain = "test.test.test.test.iota".parse::().unwrap(); + assert!(domain.format(name_service::DomainFormat::Dot) == "test.test.test.test.iota"); + assert!(domain.format(name_service::DomainFormat::At) == "test.test.test@test"); +} diff --git a/crates/sui-json-rpc-tests/tests/routing_tests.rs b/crates/iota-json-rpc-tests/tests/routing_tests.rs similarity index 96% rename from crates/sui-json-rpc-tests/tests/routing_tests.rs rename to crates/iota-json-rpc-tests/tests/routing_tests.rs index 3e8295e5b97..39044109fb4 100644 --- a/crates/sui-json-rpc-tests/tests/routing_tests.rs +++ b/crates/iota-json-rpc-tests/tests/routing_tests.rs @@ -1,10 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::env; use async_trait::async_trait; use hyper::{header::HeaderValue, HeaderMap}; +use iota_config::local_ip_utils; +use iota_json_rpc::{IotaRpcModule, JsonRpcServerBuilder}; +use iota_json_rpc_api::CLIENT_TARGET_API_VERSION_HEADER; +use iota_open_rpc::Module; +use iota_open_rpc_macros::open_rpc; use jsonrpsee::{ core::{client::ClientT, RpcResult}, http_client::HttpClientBuilder, @@ -12,11 +18,6 @@ use jsonrpsee::{ rpc_params, RpcModule, }; use prometheus::Registry; -use sui_config::local_ip_utils; -use sui_json_rpc::{JsonRpcServerBuilder, SuiRpcModule}; -use sui_json_rpc_api::CLIENT_TARGET_API_VERSION_HEADER; -use sui_open_rpc::Module; -use sui_open_rpc_macros::open_rpc; #[tokio::test] async fn test_rpc_backward_compatibility() { @@ -225,7 +226,7 @@ impl TestApiServer for TestApiModule { } } -impl SuiRpcModule for TestApiModule { +impl IotaRpcModule for TestApiModule { fn rpc(self) -> RpcModule { self.into_rpc() } diff --git a/crates/sui-json-rpc-tests/tests/rpc_server_tests.rs b/crates/iota-json-rpc-tests/tests/rpc_server_tests.rs similarity index 75% rename from crates/sui-json-rpc-tests/tests/rpc_server_tests.rs rename to crates/iota-json-rpc-tests/tests/rpc_server_tests.rs index 4a97271cc38..a594fe1b2dc 100644 --- a/crates/sui-json-rpc-tests/tests/rpc_server_tests.rs +++ b/crates/iota-json-rpc-tests/tests/rpc_server_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[cfg(not(msim))] @@ -9,24 +10,25 @@ use std::{ time::Duration, }; -use sui_json::{call_args, type_args}; -use sui_json_rpc_api::{ +use iota_json::{call_args, type_args}; +use iota_json_rpc_api::{ CoinReadApiClient, GovernanceReadApiClient, IndexerApiClient, ReadApiClient, TransactionBuilderClient, WriteApiClient, }; -use sui_json_rpc_types::{ - Balance, CoinPage, DelegatedStake, DelegatedTimelockedStake, ObjectChange, ObjectsPage, - StakeStatus, SuiCoinMetadata, SuiExecutionStatus, SuiObjectDataOptions, SuiObjectResponse, - SuiObjectResponseQuery, SuiTransactionBlockEffectsAPI, SuiTransactionBlockResponse, - SuiTransactionBlockResponseOptions, TransactionBlockBytes, +use iota_json_rpc_types::{ + Balance, CoinPage, DelegatedStake, DelegatedTimelockedStake, IotaCoinMetadata, + IotaExecutionStatus, IotaObjectDataOptions, IotaObjectResponse, IotaObjectResponseQuery, + IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponse, + IotaTransactionBlockResponseOptions, ObjectChange, ObjectsPage, StakeStatus, + TransactionBlockBytes, }; -use sui_macros::sim_test; -use sui_move_build::BuildConfig; -use sui_protocol_config::ProtocolConfig; -use sui_swarm_config::genesis_config::{ +use iota_macros::sim_test; +use iota_move_build::BuildConfig; +use iota_protocol_config::ProtocolConfig; +use iota_swarm_config::genesis_config::{ AccountConfig, DEFAULT_GAS_AMOUNT, DEFAULT_NUMBER_OF_OBJECT_PER_ACCOUNT, }; -use sui_types::{ +use iota_types::{ balance::Supply, base_types::{MoveObjectType, ObjectID, SequenceNumber}, coin::{TreasuryCap, COIN_MODULE_NAME}, @@ -35,11 +37,11 @@ use sui_types::{ gas_coin::GAS, id::UID, object::{Data, MoveObject, ObjectInner, Owner, OBJECT_START_VERSION}, - parse_sui_struct_tag, + parse_iota_struct_tag, quorum_driver_types::ExecuteTransactionRequestType, timelock::timelock::TimeLock, utils::to_sender_signed_transaction, - SUI_FRAMEWORK_ADDRESS, + IOTA_FRAMEWORK_ADDRESS, }; use test_cluster::TestClusterBuilder; use tokio::time::sleep; @@ -54,8 +56,8 @@ async fn test_get_objects() -> Result<(), anyhow::Error> { let objects = http_client .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new(), + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new(), )), None, None, @@ -81,12 +83,12 @@ async fn test_get_package_with_display_should_not_fail() -> Result<(), anyhow::E let http_client = cluster.rpc_client(); let response = http_client .get_object( - ObjectID::from(SUI_FRAMEWORK_ADDRESS), - Some(SuiObjectDataOptions::new().with_display()), + ObjectID::from(IOTA_FRAMEWORK_ADDRESS), + Some(IotaObjectDataOptions::new().with_display()), ) .await; assert!(response.is_ok()); - let response: SuiObjectResponse = response?; + let response: IotaObjectResponse = response?; assert!( response .into_object() @@ -108,8 +110,8 @@ async fn test_public_transfer_object() -> Result<(), anyhow::Error> { let objects = http_client .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -134,12 +136,12 @@ async fn test_public_transfer_object() -> Result<(), anyhow::Error> { let tx_bytes1 = tx_bytes.clone(); let dryrun_response = http_client.dry_run_transaction_block(tx_bytes).await?; - let tx_response: SuiTransactionBlockResponse = http_client + let tx_response: IotaTransactionBlockResponse = http_client .execute_transaction_block( tx_bytes1, signatures, Some( - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_effects() .with_object_changes(), ), @@ -190,8 +192,8 @@ async fn test_publish() -> Result<(), anyhow::Error> { let objects = http_client .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -203,7 +205,7 @@ async fn test_publish() -> Result<(), anyhow::Error> { let gas = objects.data.first().unwrap().object().unwrap(); let compiled_package = BuildConfig::new_for_testing() - .build(Path::new("../../sui_programmability/examples/fungible_tokens").to_path_buf())?; + .build(Path::new("../../iota_programmability/examples/fungible_tokens").to_path_buf())?; let compiled_modules_bytes = compiled_package.get_package_base64(/* with_unpublished_deps */ false); let dependencies = compiled_package.get_dependency_original_package_ids(); @@ -227,11 +229,11 @@ async fn test_publish() -> Result<(), anyhow::Error> { .execute_transaction_block( tx_bytes, signatures, - Some(SuiTransactionBlockResponseOptions::new().with_effects()), + Some(IotaTransactionBlockResponseOptions::new().with_effects()), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; - matches!(tx_response, SuiTransactionBlockResponse {effects, ..} if effects.as_ref().unwrap().created().len() == 6); + matches!(tx_response, IotaTransactionBlockResponse {effects, ..} if effects.as_ref().unwrap().created().len() == 6); Ok(()) } @@ -244,8 +246,8 @@ async fn test_move_call() -> Result<(), anyhow::Error> { let objects = http_client .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -260,7 +262,7 @@ async fn test_move_call() -> Result<(), anyhow::Error> { let coin = &objects[1].object()?; // now do the call - let package_id = ObjectID::new(SUI_FRAMEWORK_ADDRESS.into_bytes()); + let package_id = ObjectID::new(IOTA_FRAMEWORK_ADDRESS.into_bytes()); let module = "pay".to_string(); let function = "split".to_string(); @@ -288,11 +290,11 @@ async fn test_move_call() -> Result<(), anyhow::Error> { .execute_transaction_block( tx_bytes, signatures, - Some(SuiTransactionBlockResponseOptions::new().with_effects()), + Some(IotaTransactionBlockResponseOptions::new().with_effects()), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; - matches!(tx_response, SuiTransactionBlockResponse {effects, ..} if effects.as_ref().unwrap().created().len() == 1); + matches!(tx_response, IotaTransactionBlockResponse {effects, ..} if effects.as_ref().unwrap().created().len() == 1); Ok(()) } @@ -304,8 +306,8 @@ async fn test_get_object_info() -> Result<(), anyhow::Error> { let objects = http_client .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -321,11 +323,11 @@ async fn test_get_object_info() -> Result<(), anyhow::Error> { let result = http_client .get_object( oref.object_id, - Some(SuiObjectDataOptions::new().with_owner()), + Some(IotaObjectDataOptions::new().with_owner()), ) .await?; assert!( - matches!(result, SuiObjectResponse { data: Some(object), .. } if oref.object_id == object.object_id && object.owner.unwrap().get_owner_address()? == address) + matches!(result, IotaObjectResponse { data: Some(object), .. } if oref.object_id == object.object_id && object.owner.unwrap().get_owner_address()? == address) ); } Ok(()) @@ -339,8 +341,8 @@ async fn test_get_object_data_with_content() -> Result<(), anyhow::Error> { let objects = http_client .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new().with_content().with_owner(), + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new().with_content().with_owner(), )), None, None, @@ -353,11 +355,11 @@ async fn test_get_object_data_with_content() -> Result<(), anyhow::Error> { let result = http_client .get_object( oref.object_id, - Some(SuiObjectDataOptions::new().with_content().with_owner()), + Some(IotaObjectDataOptions::new().with_content().with_owner()), ) .await?; assert!( - matches!(result, SuiObjectResponse { data: Some(object), .. } if oref.object_id == object.object_id && object.owner.unwrap().get_owner_address()? == address) + matches!(result, IotaObjectResponse { data: Some(object), .. } if oref.object_id == object.object_id && object.owner.unwrap().get_owner_address()? == address) ); } Ok(()) @@ -374,19 +376,19 @@ async fn test_get_coins() -> Result<(), anyhow::Error> { assert!(!result.has_next_page); let result: CoinPage = http_client - .get_coins(address, Some("0x2::sui::TestCoin".into()), None, None) + .get_coins(address, Some("0x2::iota::TestCoin".into()), None, None) .await?; assert_eq!(0, result.data.len()); let result: CoinPage = http_client - .get_coins(address, Some("0x2::sui::SUI".into()), None, None) + .get_coins(address, Some("0x2::iota::IOTA".into()), None, None) .await?; assert_eq!(5, result.data.len()); assert!(!result.has_next_page); // Test paging let result: CoinPage = http_client - .get_coins(address, Some("0x2::sui::SUI".into()), None, Some(3)) + .get_coins(address, Some("0x2::iota::IOTA".into()), None, Some(3)) .await?; assert_eq!(3, result.data.len()); assert!(result.has_next_page); @@ -394,7 +396,7 @@ async fn test_get_coins() -> Result<(), anyhow::Error> { let result: CoinPage = http_client .get_coins( address, - Some("0x2::sui::SUI".into()), + Some("0x2::iota::IOTA".into()), result.next_cursor, Some(3), ) @@ -405,7 +407,7 @@ async fn test_get_coins() -> Result<(), anyhow::Error> { let result: CoinPage = http_client .get_coins( address, - Some("0x2::sui::SUI".into()), + Some("0x2::iota::IOTA".into()), result.next_cursor, None, ) @@ -423,7 +425,7 @@ async fn test_get_balance() -> Result<(), anyhow::Error> { let address = cluster.get_address_0(); let result: Balance = http_client.get_balance(address, None).await?; - assert_eq!("0x2::sui::SUI", result.coin_type); + assert_eq!("0x2::iota::IOTA", result.coin_type); assert_eq!( (DEFAULT_NUMBER_OF_OBJECT_PER_ACCOUNT as u64 * DEFAULT_GAS_AMOUNT) as u128, result.total_balance @@ -447,8 +449,8 @@ async fn test_get_metadata() -> Result<(), anyhow::Error> { let objects = http_client .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -489,7 +491,7 @@ async fn test_get_metadata() -> Result<(), anyhow::Error> { tx_bytes, signatures, Some( - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_object_changes() .with_events(), ), @@ -509,7 +511,7 @@ async fn test_get_metadata() -> Result<(), anyhow::Error> { }) .unwrap(); - let result: SuiCoinMetadata = http_client + let result: IotaCoinMetadata = http_client .get_coin_metadata(format!("{package_id}::trusted_coin::TRUSTED_COIN")) .await? .unwrap(); @@ -532,8 +534,8 @@ async fn test_get_total_supply() -> Result<(), anyhow::Error> { let objects = http_client .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -568,12 +570,12 @@ async fn test_get_total_supply() -> Result<(), anyhow::Error> { .sign_transaction(&transaction_bytes.to_data()?); let (tx_bytes, signatures) = tx.to_tx_bytes_and_signatures(); - let tx_response: SuiTransactionBlockResponse = http_client + let tx_response: IotaTransactionBlockResponse = http_client .execute_transaction_block( tx_bytes, signatures, Some( - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_object_changes() .with_events(), ), @@ -608,7 +610,7 @@ async fn test_get_total_supply() -> Result<(), anyhow::Error> { .. } = e { - if &TreasuryCap::type_(parse_sui_struct_tag(&coin_name).unwrap()) == object_type { + if &TreasuryCap::type_(parse_iota_struct_tag(&coin_name).unwrap()) == object_type { Some(object_id) } else { None @@ -624,7 +626,7 @@ async fn test_get_total_supply() -> Result<(), anyhow::Error> { let transaction_bytes: TransactionBlockBytes = http_client .move_call( address, - SUI_FRAMEWORK_ADDRESS.into(), + IOTA_FRAMEWORK_ADDRESS.into(), COIN_MODULE_NAME.to_string(), "mint_and_transfer".into(), type_args![coin_name]?, @@ -644,14 +646,14 @@ async fn test_get_total_supply() -> Result<(), anyhow::Error> { .execute_transaction_block( tx_bytes, signatures, - Some(SuiTransactionBlockResponseOptions::new().with_effects()), + Some(IotaTransactionBlockResponseOptions::new().with_effects()), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; - let SuiTransactionBlockResponse { effects, .. } = tx_response; + let IotaTransactionBlockResponse { effects, .. } = tx_response; - assert_eq!(SuiExecutionStatus::Success, *effects.unwrap().status()); + assert_eq!(IotaExecutionStatus::Success, *effects.unwrap().status()); let result: Supply = http_client.get_total_supply(coin_name.clone()).await?; assert_eq!(100000, result.value); @@ -669,8 +671,8 @@ async fn test_staking() -> Result<(), anyhow::Error> { let objects: ObjectsPage = http_client .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -681,18 +683,18 @@ async fn test_staking() -> Result<(), anyhow::Error> { .await?; assert_eq!(5, objects.data.len()); - // Check StakedSui object before test - let staked_sui: Vec = http_client.get_stakes(address).await?; - assert!(staked_sui.is_empty()); + // Check StakedIota object before test + let staked_iota: Vec = http_client.get_stakes(address).await?; + assert!(staked_iota.is_empty()); let validator = http_client - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await? .active_validators[0] - .sui_address; + .iota_address; let coin = objects.data[0].object()?.object_id; - // Delegate some SUI + // Delegate some IOTA let transaction_bytes: TransactionBlockBytes = http_client .request_add_stake( address, @@ -713,25 +715,25 @@ async fn test_staking() -> Result<(), anyhow::Error> { .execute_transaction_block( tx_bytes, signatures, - Some(SuiTransactionBlockResponseOptions::new()), + Some(IotaTransactionBlockResponseOptions::new()), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; // Check DelegatedStake object - let staked_sui: Vec = http_client.get_stakes(address).await?; - assert_eq!(1, staked_sui.len()); - assert_eq!(1000000000, staked_sui[0].stakes[0].principal); + let staked_iota: Vec = http_client.get_stakes(address).await?; + assert_eq!(1, staked_iota.len()); + assert_eq!(1000000000, staked_iota[0].stakes[0].principal); assert!(matches!( - staked_sui[0].stakes[0].status, + staked_iota[0].stakes[0].status, StakeStatus::Pending )); - let staked_sui_copy = http_client - .get_stakes_by_ids(vec![staked_sui[0].stakes[0].staked_sui_id]) + let staked_iota_copy = http_client + .get_stakes_by_ids(vec![staked_iota[0].stakes[0].staked_iota_id]) .await?; assert_eq!( - staked_sui[0].stakes[0].staked_sui_id, - staked_sui_copy[0].stakes[0].staked_sui_id + staked_iota[0].stakes[0].staked_iota_id, + staked_iota_copy[0].stakes[0].staked_iota_id ); Ok(()) } @@ -750,17 +752,17 @@ async fn test_unstaking() -> Result<(), anyhow::Error> { let coins: CoinPage = http_client.get_coins(address, None, None, None).await?; assert_eq!(5, coins.data.len()); - // Check StakedSui object before test - let staked_sui: Vec = http_client.get_stakes(address).await?; - assert!(staked_sui.is_empty()); + // Check StakedIota object before test + let staked_iota: Vec = http_client.get_stakes(address).await?; + assert!(staked_iota.is_empty()); let validator = http_client - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await? .active_validators[0] - .sui_address; + .iota_address; - // Delegate some SUI + // Delegate some IOTA for i in 0..3 { let transaction_bytes: TransactionBlockBytes = http_client .request_add_stake( @@ -782,40 +784,40 @@ async fn test_unstaking() -> Result<(), anyhow::Error> { .execute_transaction_block( tx_bytes, signatures, - Some(SuiTransactionBlockResponseOptions::new()), + Some(IotaTransactionBlockResponseOptions::new()), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; } // Check DelegatedStake object - let staked_sui: Vec = http_client.get_stakes(address).await?; - assert_eq!(1, staked_sui.len()); - assert_eq!(1000000000, staked_sui[0].stakes[0].principal); + let staked_iota: Vec = http_client.get_stakes(address).await?; + assert_eq!(1, staked_iota.len()); + assert_eq!(1000000000, staked_iota[0].stakes[0].principal); sleep(Duration::from_millis(10000)).await; - let staked_sui_copy = http_client + let staked_iota_copy = http_client .get_stakes_by_ids(vec![ - staked_sui[0].stakes[0].staked_sui_id, - staked_sui[0].stakes[1].staked_sui_id, - staked_sui[0].stakes[2].staked_sui_id, + staked_iota[0].stakes[0].staked_iota_id, + staked_iota[0].stakes[1].staked_iota_id, + staked_iota[0].stakes[2].staked_iota_id, ]) .await?; assert!(matches!( - &staked_sui_copy[0].stakes[0].status, + &staked_iota_copy[0].stakes[0].status, StakeStatus::Active { estimated_reward: _ } )); assert!(matches!( - &staked_sui_copy[0].stakes[1].status, + &staked_iota_copy[0].stakes[1].status, StakeStatus::Active { estimated_reward: _ } )); assert!(matches!( - &staked_sui_copy[0].stakes[2].status, + &staked_iota_copy[0].stakes[2].status, StakeStatus::Active { estimated_reward: _ } @@ -824,7 +826,7 @@ async fn test_unstaking() -> Result<(), anyhow::Error> { let transaction_bytes: TransactionBlockBytes = http_client .request_withdraw_stake( address, - staked_sui_copy[0].stakes[2].staked_sui_id, + staked_iota_copy[0].stakes[2].staked_iota_id, None, 1_000_000.into(), ) @@ -839,35 +841,35 @@ async fn test_unstaking() -> Result<(), anyhow::Error> { .execute_transaction_block( tx_bytes, signatures, - Some(SuiTransactionBlockResponseOptions::new()), + Some(IotaTransactionBlockResponseOptions::new()), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; sleep(Duration::from_millis(20000)).await; - let staked_sui_copy = http_client + let staked_iota_copy = http_client .get_stakes_by_ids(vec![ - staked_sui[0].stakes[0].staked_sui_id, - staked_sui[0].stakes[1].staked_sui_id, - staked_sui[0].stakes[2].staked_sui_id, + staked_iota[0].stakes[0].staked_iota_id, + staked_iota[0].stakes[1].staked_iota_id, + staked_iota[0].stakes[2].staked_iota_id, ]) .await?; assert!(matches!( - &staked_sui_copy[0].stakes[0].status, + &staked_iota_copy[0].stakes[0].status, StakeStatus::Active { estimated_reward: _ } )); assert!(matches!( - &staked_sui_copy[0].stakes[1].status, + &staked_iota_copy[0].stakes[1].status, StakeStatus::Active { estimated_reward: _ } )); assert!(matches!( - &staked_sui_copy[0].stakes[2].status, + &staked_iota_copy[0].stakes[2].status, StakeStatus::Unstaked )); Ok(()) @@ -885,16 +887,16 @@ async fn test_staking_multiple_coins() -> Result<(), anyhow::Error> { let genesis_coin_amount = coins.data[0].balance; - // Check StakedSui object before test - let staked_sui: Vec = http_client.get_stakes(address).await?; - assert!(staked_sui.is_empty()); + // Check StakedIota object before test + let staked_iota: Vec = http_client.get_stakes(address).await?; + assert!(staked_iota.is_empty()); let validator = http_client - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await? .active_validators[0] - .sui_address; - // Delegate some SUI + .iota_address; + // Delegate some IOTA let transaction_bytes: TransactionBlockBytes = http_client .request_add_stake( address, @@ -924,7 +926,7 @@ async fn test_staking_multiple_coins() -> Result<(), anyhow::Error> { tx_bytes, signatures, Some( - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_balance_changes() .with_input(), ), @@ -945,11 +947,11 @@ async fn test_staking_multiple_coins() -> Result<(), anyhow::Error> { ); // Check DelegatedStake object - let staked_sui: Vec = http_client.get_stakes(address).await?; - assert_eq!(1, staked_sui.len()); - assert_eq!(1000000000, staked_sui[0].stakes[0].principal); + let staked_iota: Vec = http_client.get_stakes(address).await?; + assert_eq!(1, staked_iota.len()); + assert_eq!(1000000000, staked_iota[0].stakes[0].principal); assert!(matches!( - staked_sui[0].stakes[0].status, + staked_iota[0].stakes[0].status, StakeStatus::Pending )); @@ -979,14 +981,14 @@ async fn test_timelocked_staking() -> Result<(), anyhow::Error> { let principal = 100_000_000_000; let expiration_timestamp_ms = u64::MAX; - let timelock_sui = unsafe { + let timelock_iota = unsafe { MoveObject::new_from_execution( - MoveObjectType::timelocked_sui_balance(), + MoveObjectType::timelocked_iota_balance(), false, OBJECT_START_VERSION, - TimeLock::::new( + TimeLock::::new( UID::new(ObjectID::random()), - sui_types::balance::Balance::new(principal), + iota_types::balance::Balance::new(principal), expiration_timestamp_ms, ) .to_bcs_bytes(), @@ -994,9 +996,9 @@ async fn test_timelocked_staking() -> Result<(), anyhow::Error> { ) .unwrap() }; - let timelock_sui = ObjectInner { + let timelock_iota = ObjectInner { owner: Owner::AddressOwner(address), - data: Data::Move(timelock_sui), + data: Data::Move(timelock_iota), previous_transaction: TransactionDigest::genesis_marker(), storage_rebate: 0, }; @@ -1009,7 +1011,7 @@ async fn test_timelocked_staking() -> Result<(), anyhow::Error> { }] .into(), ) - .with_objects([timelock_sui.into()]) + .with_objects([timelock_iota.into()]) .build() .await; @@ -1019,8 +1021,8 @@ async fn test_timelocked_staking() -> Result<(), anyhow::Error> { let objects: ObjectsPage = http_client .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -1034,17 +1036,17 @@ async fn test_timelocked_staking() -> Result<(), anyhow::Error> { let coin = objects.data[0].object()?.object_id; let timelocked_balance = objects.data[1].object()?.object_id; - // Check TimelockedStakedSui object before test - let staked_sui: Vec = + // Check TimelockedStakedIota object before test + let staked_iota: Vec = http_client.get_timelocked_stakes(address).await?; - assert!(staked_sui.is_empty()); + assert!(staked_iota.is_empty()); - // Delegate some timelocked SUI + // Delegate some timelocked IOTA let validator = http_client - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await? .active_validators[0] - .sui_address; + .iota_address; let transaction_bytes: TransactionBlockBytes = http_client .request_add_timelocked_stake( @@ -1064,44 +1066,44 @@ async fn test_timelocked_staking() -> Result<(), anyhow::Error> { .execute_transaction_block( tx_bytes, signatures, - Some(SuiTransactionBlockResponseOptions::new()), + Some(IotaTransactionBlockResponseOptions::new()), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; // Check DelegatedTimelockedStake object - let staked_sui: Vec = + let staked_iota: Vec = http_client.get_timelocked_stakes(address).await?; - assert_eq!(1, staked_sui.len()); - let staked_sui = &staked_sui[0]; - assert_eq!(1, staked_sui.stakes.len()); - let stake = &staked_sui.stakes[0]; + assert_eq!(1, staked_iota.len()); + let staked_iota = &staked_iota[0]; + assert_eq!(1, staked_iota.stakes.len()); + let stake = &staked_iota.stakes[0]; - assert_eq!(validator, staked_sui.validator_address); + assert_eq!(validator, staked_iota.validator_address); assert_eq!(principal, stake.principal); assert!(matches!(stake.status, StakeStatus::Pending)); assert_eq!(expiration_timestamp_ms, stake.expiration_timestamp_ms); // Request the DelegatedTimelockedStake one more time - let staked_sui_copy = http_client - .get_timelocked_stakes_by_ids(vec![stake.timelocked_staked_sui_id]) + let staked_iota_copy = http_client + .get_timelocked_stakes_by_ids(vec![stake.timelocked_staked_iota_id]) .await?; - assert_eq!(1, staked_sui_copy.len()); - let staked_sui_copy = &staked_sui_copy[0]; - assert_eq!(1, staked_sui_copy.stakes.len()); - let stake_copy = &staked_sui_copy.stakes[0]; + assert_eq!(1, staked_iota_copy.len()); + let staked_iota_copy = &staked_iota_copy[0]; + assert_eq!(1, staked_iota_copy.stakes.len()); + let stake_copy = &staked_iota_copy.stakes[0]; // Check both of objects assert_eq!( - staked_sui.validator_address, - staked_sui_copy.validator_address + staked_iota.validator_address, + staked_iota_copy.validator_address ); - assert_eq!(staked_sui.staking_pool, staked_sui_copy.staking_pool); + assert_eq!(staked_iota.staking_pool, staked_iota_copy.staking_pool); assert_eq!( - stake.timelocked_staked_sui_id, - stake_copy.timelocked_staked_sui_id + stake.timelocked_staked_iota_id, + stake_copy.timelocked_staked_iota_id ); assert_eq!(stake.stake_request_epoch, stake_copy.stake_request_epoch); assert_eq!(stake.stake_active_epoch, stake_copy.stake_active_epoch); @@ -1126,14 +1128,14 @@ async fn test_timelocked_unstaking() -> Result<(), anyhow::Error> { let principal = 100_000_000_000; let expiration_timestamp_ms = u64::MAX; - let timelock_sui = unsafe { + let timelock_iota = unsafe { MoveObject::new_from_execution( - MoveObjectType::timelocked_sui_balance(), + MoveObjectType::timelocked_iota_balance(), false, OBJECT_START_VERSION, - TimeLock::::new( + TimeLock::::new( UID::new(ObjectID::random()), - sui_types::balance::Balance::new(principal), + iota_types::balance::Balance::new(principal), expiration_timestamp_ms, ) .to_bcs_bytes(), @@ -1141,9 +1143,9 @@ async fn test_timelocked_unstaking() -> Result<(), anyhow::Error> { ) .unwrap() }; - let timelock_sui = ObjectInner { + let timelock_iota = ObjectInner { owner: Owner::AddressOwner(address), - data: Data::Move(timelock_sui), + data: Data::Move(timelock_iota), previous_transaction: TransactionDigest::genesis_marker(), storage_rebate: 0, }; @@ -1156,7 +1158,7 @@ async fn test_timelocked_unstaking() -> Result<(), anyhow::Error> { }] .into(), ) - .with_objects([timelock_sui.into()]) + .with_objects([timelock_iota.into()]) .with_epoch_duration_ms(10000) .build() .await; @@ -1167,8 +1169,8 @@ async fn test_timelocked_unstaking() -> Result<(), anyhow::Error> { let objects: ObjectsPage = http_client .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -1182,17 +1184,17 @@ async fn test_timelocked_unstaking() -> Result<(), anyhow::Error> { let coin = objects.data[0].object()?.object_id; let timelocked_balance = objects.data[1].object()?.object_id; - // Check TimelockedStakedSui object before test - let staked_sui: Vec = + // Check TimelockedStakedIota object before test + let staked_iota: Vec = http_client.get_timelocked_stakes(address).await?; - assert!(staked_sui.is_empty()); + assert!(staked_iota.is_empty()); - // Delegate some timelocked SUI + // Delegate some timelocked IOTA let validator = http_client - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await? .active_validators[0] - .sui_address; + .iota_address; let transaction_bytes: TransactionBlockBytes = http_client .request_add_timelocked_stake( @@ -1212,21 +1214,21 @@ async fn test_timelocked_unstaking() -> Result<(), anyhow::Error> { .execute_transaction_block( tx_bytes, signatures, - Some(SuiTransactionBlockResponseOptions::full_content()), + Some(IotaTransactionBlockResponseOptions::full_content()), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; // Check DelegatedTimelockedStake object - let staked_sui: Vec = + let staked_iota: Vec = http_client.get_timelocked_stakes(address).await?; - assert_eq!(1, staked_sui.len()); - let staked_sui = &staked_sui[0]; - assert_eq!(1, staked_sui.stakes.len()); - let stake = &staked_sui.stakes[0]; + assert_eq!(1, staked_iota.len()); + let staked_iota = &staked_iota[0]; + assert_eq!(1, staked_iota.stakes.len()); + let stake = &staked_iota.stakes[0]; - assert_eq!(validator, staked_sui.validator_address); + assert_eq!(validator, staked_iota.validator_address); assert_eq!(principal, stake.principal); assert!(matches!(stake.status, StakeStatus::Pending)); assert_eq!(expiration_timestamp_ms, stake.expiration_timestamp_ms); @@ -1235,14 +1237,14 @@ async fn test_timelocked_unstaking() -> Result<(), anyhow::Error> { sleep(Duration::from_millis(10000)).await; // Request the DelegatedTimelockedStake one more time - let staked_sui_copy = http_client - .get_timelocked_stakes_by_ids(vec![stake.timelocked_staked_sui_id]) + let staked_iota_copy = http_client + .get_timelocked_stakes_by_ids(vec![stake.timelocked_staked_iota_id]) .await?; - assert_eq!(1, staked_sui_copy.len()); - let staked_sui_copy = &staked_sui_copy[0]; - assert_eq!(1, staked_sui_copy.stakes.len()); - let stake_copy = &staked_sui_copy.stakes[0]; + assert_eq!(1, staked_iota_copy.len()); + let staked_iota_copy = &staked_iota_copy[0]; + assert_eq!(1, staked_iota_copy.stakes.len()); + let stake_copy = &staked_iota_copy.stakes[0]; assert_eq!(principal, stake_copy.principal); assert!(matches!(&stake_copy.status, StakeStatus::Active { .. })); @@ -1251,7 +1253,7 @@ async fn test_timelocked_unstaking() -> Result<(), anyhow::Error> { let transaction_bytes: TransactionBlockBytes = http_client .request_withdraw_timelocked_stake( address, - stake_copy.timelocked_staked_sui_id, + stake_copy.timelocked_staked_iota_id, coin, 10_000_000.into(), ) @@ -1264,7 +1266,7 @@ async fn test_timelocked_unstaking() -> Result<(), anyhow::Error> { .execute_transaction_block( tx_bytes, signatures, - Some(SuiTransactionBlockResponseOptions::new()), + Some(IotaTransactionBlockResponseOptions::new()), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; @@ -1273,24 +1275,24 @@ async fn test_timelocked_unstaking() -> Result<(), anyhow::Error> { sleep(Duration::from_millis(20000)).await; // Request the DelegatedTimelockedStake one more time - let staked_sui_copy = http_client - .get_timelocked_stakes_by_ids(vec![stake.timelocked_staked_sui_id]) + let staked_iota_copy = http_client + .get_timelocked_stakes_by_ids(vec![stake.timelocked_staked_iota_id]) .await?; - assert_eq!(1, staked_sui_copy.len()); - let staked_sui_copy = &staked_sui_copy[0]; - assert_eq!(1, staked_sui_copy.stakes.len()); - let stake_copy = &staked_sui_copy.stakes[0]; + assert_eq!(1, staked_iota_copy.len()); + let staked_iota_copy = &staked_iota_copy[0]; + assert_eq!(1, staked_iota_copy.stakes.len()); + let stake_copy = &staked_iota_copy.stakes[0]; // Check the result assert_eq!( - staked_sui.validator_address, - staked_sui_copy.validator_address + staked_iota.validator_address, + staked_iota_copy.validator_address ); - assert_eq!(staked_sui.staking_pool, staked_sui_copy.staking_pool); + assert_eq!(staked_iota.staking_pool, staked_iota_copy.staking_pool); assert_eq!( - stake.timelocked_staked_sui_id, - stake_copy.timelocked_staked_sui_id + stake.timelocked_staked_iota_id, + stake_copy.timelocked_staked_iota_id ); assert_eq!(stake.stake_request_epoch, stake_copy.stake_request_epoch); assert_eq!(stake.stake_active_epoch, stake_copy.stake_active_epoch); diff --git a/crates/iota-json-rpc-tests/tests/subscription_tests.rs b/crates/iota-json-rpc-tests/tests/subscription_tests.rs new file mode 100644 index 00000000000..5d98194fb12 --- /dev/null +++ b/crates/iota-json-rpc-tests/tests/subscription_tests.rs @@ -0,0 +1,50 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::time::Duration; + +use iota_core::test_utils::wait_for_tx; +use iota_json_rpc_types::{ + IotaTransactionBlockEffects, IotaTransactionBlockEffectsAPI, TransactionFilter, +}; +use iota_test_transaction_builder::{create_devnet_nft, publish_nfts_package}; +use jsonrpsee::{ + core::client::{Subscription, SubscriptionClientT}, + rpc_params, +}; +use test_cluster::TestClusterBuilder; +use tokio::time::timeout; + +#[tokio::test] +async fn test_subscribe_transaction() -> Result<(), anyhow::Error> { + let cluster = TestClusterBuilder::new().build().await; + + let address = &cluster.get_address_0(); + let wallet = cluster.wallet; + + let ws_client = cluster.fullnode_handle.ws_client().await; + + let package_id = publish_nfts_package(&wallet).await.0; + + let mut sub: Subscription = ws_client + .subscribe( + "iotax_subscribeTransaction", + rpc_params![TransactionFilter::FromAddress(*address)], + "iotax_unsubscribeTransaction", + ) + .await + .unwrap(); + + let (_, _, digest) = create_devnet_nft(&wallet, package_id).await; + wait_for_tx(digest, cluster.fullnode_handle.iota_node.state()).await; + + // Wait for streaming + let effects = match timeout(Duration::from_secs(5), sub.next()).await { + Ok(Some(Ok(tx))) => tx, + _ => panic!("Failed to get tx"), + }; + + assert_eq!(&digest, effects.transaction_digest()); + Ok(()) +} diff --git a/crates/iota-json-rpc-tests/tests/transaction_tests.rs b/crates/iota-json-rpc-tests/tests/transaction_tests.rs new file mode 100644 index 00000000000..384fc14a9dd --- /dev/null +++ b/crates/iota-json-rpc-tests/tests/transaction_tests.rs @@ -0,0 +1,334 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_json_rpc_api::{IndexerApiClient, TransactionBuilderClient, WriteApiClient}; +use iota_json_rpc_types::{ + IotaObjectDataOptions, IotaObjectResponseQuery, IotaTransactionBlockResponse, + IotaTransactionBlockResponseOptions, IotaTransactionBlockResponseQuery, TransactionBlockBytes, + TransactionFilter, +}; +use iota_macros::sim_test; +use iota_types::{ + quorum_driver_types::ExecuteTransactionRequestType, transaction::SenderSignedData, +}; +use test_cluster::TestClusterBuilder; + +#[sim_test] +async fn test_get_transaction_block() -> Result<(), anyhow::Error> { + let cluster = TestClusterBuilder::new().build().await; + let http_client = cluster.rpc_client(); + let address = cluster.get_address_0(); + + let objects = http_client + .get_owned_objects( + address, + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() + .with_type() + .with_owner() + .with_previous_transaction(), + )), + None, + None, + ) + .await? + .data; + let gas_id = objects.last().unwrap().object().unwrap().object_id; + + // Make some transactions + let mut tx_responses: Vec = Vec::new(); + for obj in &objects[..objects.len() - 1] { + let oref = obj.object().unwrap(); + let transaction_bytes: TransactionBlockBytes = http_client + .transfer_object( + address, + oref.object_id, + Some(gas_id), + 1_000_000.into(), + address, + ) + .await?; + let tx = cluster + .wallet + .sign_transaction(&transaction_bytes.to_data()?); + + let (tx_bytes, signatures) = tx.to_tx_bytes_and_signatures(); + + let response = http_client + .execute_transaction_block( + tx_bytes, + signatures, + Some(IotaTransactionBlockResponseOptions::new()), + Some(ExecuteTransactionRequestType::WaitForLocalExecution), + ) + .await?; + + tx_responses.push(response); + } + + // TODO(chris): re-enable after rewriting get_transactions_in_range_deprecated + // with query_transactions test get_transaction_batch + // let batch_responses: Vec = http_client + // .multi_get_transaction_blocks(tx, + // Some(IotaTransactionBlockResponseOptions::new())) .await?; + + // assert_eq!(5, batch_responses.len()); + + // for r in batch_responses.iter().skip(1) { + // assert!(tx_responses + // .iter() + // .any(|resp| matches!(resp, IotaTransactionBlockResponse {digest, ..} + // if *digest == r.digest))) } + + // // test get_transaction + // for tx_digest in tx { + // let response: IotaTransactionBlockResponse = http_client + // .get_transaction_block( + // tx_digest, + // + // Some(IotaTransactionBlockResponseOptions::new().with_raw_input()), + // ) + // .await?; + // assert!(tx_responses.iter().any( + // |resp| matches!(resp, IotaTransactionBlockResponse {digest, ..} if *digest == response.digest) + // )); + // let sender_signed_data: SenderSignedData = + // bcs::from_bytes(&response.raw_transaction).unwrap(); + // assert_eq!(sender_signed_data.digest(), tx_digest); + // } + + Ok(()) +} + +#[sim_test] +async fn test_get_raw_transaction() -> Result<(), anyhow::Error> { + let cluster = TestClusterBuilder::new().build().await; + let http_client = cluster.rpc_client(); + let address = cluster.get_address_0(); + + let objects = http_client + .get_owned_objects( + address, + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new(), + )), + None, + None, + ) + .await? + .data; + let object_to_transfer = objects.first().unwrap().object().unwrap().object_id; + + // Make a transfer transactions + let transaction_bytes: TransactionBlockBytes = http_client + .transfer_object(address, object_to_transfer, None, 1_000_000.into(), address) + .await?; + let tx = cluster + .wallet + .sign_transaction(&transaction_bytes.to_data()?); + let original_sender_signed_data = tx.data().clone(); + + let (tx_bytes, signatures) = tx.to_tx_bytes_and_signatures(); + + let response = http_client + .execute_transaction_block( + tx_bytes, + signatures, + Some(IotaTransactionBlockResponseOptions::new().with_raw_input()), + Some(ExecuteTransactionRequestType::WaitForLocalExecution), + ) + .await?; + + let decode_sender_signed_data: SenderSignedData = + bcs::from_bytes(&response.raw_transaction).unwrap(); + // verify that the raw transaction data returned by the response is the same + // as the original transaction data + assert_eq!(decode_sender_signed_data, original_sender_signed_data); + + Ok(()) +} + +#[sim_test] +async fn test_get_fullnode_transaction() -> Result<(), anyhow::Error> { + let cluster = TestClusterBuilder::new().build().await; + + let context = &cluster.wallet; + + let mut tx_responses: Vec = Vec::new(); + + let client = context.get_client().await.unwrap(); + + for address in cluster.get_addresses() { + let objects = client + .read_api() + .get_owned_objects( + address, + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() + .with_type() + .with_owner() + .with_previous_transaction(), + )), + None, + None, + ) + .await? + .data; + let gas_id = objects.last().unwrap().object().unwrap().object_id; + + // Make some transactions + for obj in &objects[..objects.len() - 1] { + let oref = obj.object().unwrap(); + let data = client + .transaction_builder() + .transfer_object(address, oref.object_id, Some(gas_id), 1_000_000, address) + .await?; + let tx = cluster.wallet.sign_transaction(&data); + + let response = client + .quorum_driver_api() + .execute_transaction_block( + tx, + IotaTransactionBlockResponseOptions::new(), + Some(ExecuteTransactionRequestType::WaitForLocalExecution), + ) + .await + .unwrap(); + + tx_responses.push(response); + } + } + + // test get_recent_transactions with smaller range + let query = IotaTransactionBlockResponseQuery { + options: Some(IotaTransactionBlockResponseOptions { + show_input: true, + show_effects: true, + show_events: true, + ..Default::default() + }), + ..Default::default() + }; + + let tx = client + .read_api() + .query_transaction_blocks(query, None, Some(3), true) + .await + .unwrap(); + assert_eq!(3, tx.data.len()); + assert!(tx.data[0].transaction.is_some()); + assert!(tx.data[0].effects.is_some()); + assert!(tx.data[0].events.is_some()); + assert!(tx.has_next_page); + + // test get all transactions paged + let first_page = client + .read_api() + .query_transaction_blocks( + IotaTransactionBlockResponseQuery::default(), + None, + Some(5), + false, + ) + .await + .unwrap(); + assert_eq!(5, first_page.data.len()); + assert!(first_page.has_next_page); + + let second_page = client + .read_api() + .query_transaction_blocks( + IotaTransactionBlockResponseQuery::default(), + first_page.next_cursor, + None, + false, + ) + .await + .unwrap(); + assert!(second_page.data.len() > 5); + assert!(!second_page.has_next_page); + + let mut all_txs_rev = first_page.data.clone(); + all_txs_rev.extend(second_page.data); + all_txs_rev.reverse(); + + // test get 10 latest transactions paged + let latest = client + .read_api() + .query_transaction_blocks( + IotaTransactionBlockResponseQuery::default(), + None, + Some(10), + true, + ) + .await + .unwrap(); + assert_eq!(10, latest.data.len()); + assert_eq!(Some(all_txs_rev[9].digest), latest.next_cursor); + assert_eq!(all_txs_rev[0..10], latest.data); + assert!(latest.has_next_page); + + // test get from address txs in ascending order + let address_txs_asc = client + .read_api() + .query_transaction_blocks( + IotaTransactionBlockResponseQuery::new_with_filter(TransactionFilter::FromAddress( + cluster.get_address_0(), + )), + None, + None, + false, + ) + .await + .unwrap(); + assert_eq!(4, address_txs_asc.data.len()); + + // test get from address txs in descending order + let address_txs_desc = client + .read_api() + .query_transaction_blocks( + IotaTransactionBlockResponseQuery::new_with_filter(TransactionFilter::FromAddress( + cluster.get_address_0(), + )), + None, + None, + true, + ) + .await + .unwrap(); + assert_eq!(4, address_txs_desc.data.len()); + + // test get from address txs in both ordering are the same. + let mut data_asc = address_txs_asc.data; + data_asc.reverse(); + assert_eq!(data_asc, address_txs_desc.data); + + // test get_recent_transactions + let tx = client + .read_api() + .query_transaction_blocks( + IotaTransactionBlockResponseQuery::default(), + None, + Some(20), + true, + ) + .await + .unwrap(); + assert_eq!(20, tx.data.len()); + + // test get_transaction + for tx_resp in tx.data { + let response: IotaTransactionBlockResponse = client + .read_api() + .get_transaction_with_options( + tx_resp.digest, + IotaTransactionBlockResponseOptions::new(), + ) + .await + .unwrap(); + assert_eq!(tx_resp.digest, response.digest); + } + + Ok(()) +} diff --git a/crates/iota-json-rpc-types/Cargo.toml b/crates/iota-json-rpc-types/Cargo.toml new file mode 100644 index 00000000000..92afca87a0d --- /dev/null +++ b/crates/iota-json-rpc-types/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "iota-json-rpc-types" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +fastcrypto.workspace = true +schemars.workspace = true +serde.workspace = true +serde_json.workspace = true +serde_with.workspace = true +colored.workspace = true +itertools.workspace = true +tracing.workspace = true +bcs.workspace = true +iota-protocol-config.workspace = true +iota-macros.workspace = true +iota-enum-compat-util.workspace = true +enum_dispatch.workspace = true +json_to_table.workspace = true +tabled.workspace = true + +move-binary-format.workspace = true +move-core-types.workspace = true +move-bytecode-utils.workspace = true + +mysten-metrics.workspace = true +iota-types.workspace = true +iota-json.workspace = true + +[dev-dependencies] +iota-types = { workspace = true, features = ["test-utils"] } + +[features] +test-utils = [] diff --git a/crates/iota-json-rpc-types/src/balance_changes.rs b/crates/iota-json-rpc-types/src/balance_changes.rs new file mode 100644 index 00000000000..c2910d8d319 --- /dev/null +++ b/crates/iota-json-rpc-types/src/balance_changes.rs @@ -0,0 +1,37 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use std::fmt::{Display, Formatter, Result}; + +use iota_types::{iota_serde::IotaTypeTag, object::Owner}; +use move_core_types::language_storage::TypeTag; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, DisplayFromStr}; + +#[serde_as] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct BalanceChange { + /// Owner of the balance change + pub owner: Owner, + #[schemars(with = "String")] + #[serde_as(as = "IotaTypeTag")] + pub coin_type: TypeTag, + /// The amount indicate the balance value changes, + /// negative amount means spending coin value and positive means receiving + /// coin value. + #[schemars(with = "String")] + #[serde_as(as = "DisplayFromStr")] + pub amount: i128, +} + +impl Display for BalanceChange { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!( + f, + " ┌──\n │ Owner: {} \n │ CoinType: {} \n │ Amount: {}\n └──", + self.owner, self.coin_type, self.amount + ) + } +} diff --git a/crates/iota-json-rpc-types/src/displays/mod.rs b/crates/iota-json-rpc-types/src/displays/mod.rs new file mode 100644 index 00000000000..a339e483b1b --- /dev/null +++ b/crates/iota-json-rpc-types/src/displays/mod.rs @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod transaction_displays; + +pub struct Pretty<'a, T>(pub &'a T); diff --git a/crates/iota-json-rpc-types/src/displays/transaction_displays.rs b/crates/iota-json-rpc-types/src/displays/transaction_displays.rs new file mode 100644 index 00000000000..66990bfbf33 --- /dev/null +++ b/crates/iota-json-rpc-types/src/displays/transaction_displays.rs @@ -0,0 +1,193 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt::{Display, Formatter}; + +use iota_types::transaction::write_sep; +use tabled::{ + builder::Builder as TableBuilder, + settings::{style::HorizontalLine, Panel as TablePanel, Style as TableStyle}, +}; + +use crate::{ + displays::Pretty, IotaArgument, IotaCallArg, IotaCommand, IotaObjectArg, + IotaProgrammableMoveCall, IotaProgrammableTransactionBlock, +}; + +impl<'a> Display for Pretty<'a, IotaProgrammableTransactionBlock> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let Pretty(ptb) = self; + let IotaProgrammableTransactionBlock { inputs, commands } = ptb; + if !inputs.is_empty() { + let mut builder = TableBuilder::default(); + for (i, input) in inputs.iter().enumerate() { + match input { + IotaCallArg::Pure(v) => { + let pure_arg = if let Some(t) = v.value_type() { + format!( + "{i:<3} Pure Arg: Type: {}, Value: {}", + t, + v.value().to_json_value() + ) + } else { + format!("{i:<3} Pure Arg: {}", v.value().to_json_value()) + }; + builder.push_record(vec![pure_arg]); + } + IotaCallArg::Object(IotaObjectArg::ImmOrOwnedObject { object_id, .. }) => { + builder.push_record(vec![format!( + "{i:<3} Imm/Owned Object ID: {}", + object_id + )]); + } + IotaCallArg::Object(IotaObjectArg::SharedObject { object_id, .. }) => { + builder.push_record(vec![format!( + "{i:<3} Shared Object ID: {}", + object_id + )]); + } + IotaCallArg::Object(IotaObjectArg::Receiving { object_id, .. }) => { + builder.push_record(vec![format!( + "{i:<3} Receiving Object ID: {}", + object_id + )]); + } + } + } + + let mut table = builder.build(); + table.with(TablePanel::header("Input Objects")); + table.with(TableStyle::rounded().horizontals([HorizontalLine::new( + 1, + TableStyle::modern().get_horizontal(), + )])); + write!(f, "\n{}", table)?; + } else { + write!(f, "\n No input objects for this transaction")?; + } + + if !commands.is_empty() { + let mut builder = TableBuilder::default(); + for (i, c) in commands.iter().enumerate() { + if i == commands.len() - 1 { + builder.push_record(vec![format!("{i:<2} {}", Pretty(c))]); + } else { + builder.push_record(vec![format!("{i:<2} {}\n", Pretty(c))]); + } + } + let mut table = builder.build(); + table.with(TablePanel::header("Commands")); + table.with(TableStyle::rounded().horizontals([HorizontalLine::new( + 1, + TableStyle::modern().get_horizontal(), + )])); + write!(f, "\n{}", table) + } else { + write!(f, "\n No commands for this transaction") + } + } +} + +impl<'a> Display for Pretty<'a, IotaCommand> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let Pretty(command) = self; + match command { + IotaCommand::MakeMoveVec(ty_opt, elems) => { + write!(f, "MakeMoveVec:\n ┌")?; + if let Some(ty) = ty_opt { + write!(f, "\n │ Type Tag: {ty}")?; + } + write!(f, "\n │ Arguments:\n │ ")?; + write_sep(f, elems.iter().map(Pretty), "\n │ ")?; + write!(f, "\n └") + } + + IotaCommand::MoveCall(p) => write!(f, "{}", Pretty(&**p)), + + IotaCommand::MergeCoins(target, coins) => { + write!( + f, + "MergeCoins:\n ┌\n │ Target: {}\n │ Coins: \n │ ", + Pretty(target) + )?; + write_sep(f, coins.iter().map(Pretty), "\n │ ")?; + write!(f, "\n └") + } + + IotaCommand::SplitCoins(coin, amounts) => { + write!( + f, + "SplitCoins:\n ┌\n │ Coin: {}\n │ Amounts: \n │ ", + Pretty(coin) + )?; + write_sep(f, amounts.iter().map(Pretty), "\n │ ")?; + write!(f, "\n └") + } + + IotaCommand::Publish(deps) => { + write!(f, "Publish:\n ┌\n │ Dependencies: \n │ ")?; + write_sep(f, deps, "\n │ ")?; + write!(f, "\n └") + } + + IotaCommand::TransferObjects(objs, addr) => { + write!(f, "TransferObjects:\n ┌\n │ Arguments: \n │ ")?; + write_sep(f, objs.iter().map(Pretty), "\n │ ")?; + write!(f, "\n │ Address: {}\n └", Pretty(addr)) + } + + IotaCommand::Upgrade(deps, current_package_id, ticket) => { + write!(f, "Upgrade:\n ┌\n │ Dependencies: \n │ ")?; + write_sep(f, deps, "\n │ ")?; + write!(f, "\n │ Current Package ID: {current_package_id}")?; + write!(f, "\n │ Ticket: {}", Pretty(ticket))?; + write!(f, "\n └") + } + } + } +} + +impl<'a> Display for Pretty<'a, IotaProgrammableMoveCall> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let Pretty(move_call) = self; + let IotaProgrammableMoveCall { + package, + module, + function, + type_arguments, + arguments, + } = move_call; + + write!( + f, + "MoveCall:\n ┌\n │ Function: {} \n │ Module: {}\n │ Package: {}", + function, module, package + )?; + + if !type_arguments.is_empty() { + write!(f, "\n │ Type Arguments: \n │ ")?; + write_sep(f, type_arguments, "\n │ ")?; + } + if !arguments.is_empty() { + write!(f, "\n │ Arguments: \n │ ")?; + write_sep(f, arguments.iter().map(Pretty), "\n │ ")?; + } + + write!(f, "\n └") + } +} + +impl<'a> Display for Pretty<'a, IotaArgument> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let Pretty(argument) = self; + + let output = match argument { + IotaArgument::GasCoin => "GasCoin".to_string(), + IotaArgument::Input(i) => format!("Input {}", i), + IotaArgument::Result(i) => format!("Result {}", i), + IotaArgument::NestedResult(j, k) => format!("Nested Result {}: {}", j, k), + }; + write!(f, "{}", output) + } +} diff --git a/crates/iota-json-rpc-types/src/iota_checkpoint.rs b/crates/iota-json-rpc-types/src/iota_checkpoint.rs new file mode 100644 index 00000000000..97354033b28 --- /dev/null +++ b/crates/iota-json-rpc-types/src/iota_checkpoint.rs @@ -0,0 +1,139 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use fastcrypto::encoding::Base64; +use iota_types::{ + base_types::TransactionDigest, + committee::EpochId, + crypto::AggregateAuthoritySignature, + digests::CheckpointDigest, + gas::GasCostSummary, + iota_serde::BigInt, + message_envelope::Message, + messages_checkpoint::{ + CheckpointCommitment, CheckpointContents, CheckpointSequenceNumber, CheckpointSummary, + CheckpointTimestamp, EndOfEpochData, + }, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +use crate::Page; +pub type CheckpointPage = Page>; + +#[serde_as] +#[derive(Clone, Debug, JsonSchema, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct Checkpoint { + /// Checkpoint's epoch ID + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub epoch: EpochId, + /// Checkpoint sequence number + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub sequence_number: CheckpointSequenceNumber, + /// Checkpoint digest + pub digest: CheckpointDigest, + /// Total number of transactions committed since genesis, including those in + /// this checkpoint. + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub network_total_transactions: u64, + /// Digest of the previous checkpoint + #[serde(skip_serializing_if = "Option::is_none")] + pub previous_digest: Option, + /// The running total gas costs of all transactions included in the current + /// epoch so far until this checkpoint. + pub epoch_rolling_gas_cost_summary: GasCostSummary, + /// Timestamp of the checkpoint - number of milliseconds from the Unix epoch + /// Checkpoint timestamps are monotonic, but not strongly monotonic - + /// subsequent checkpoints can have same timestamp if they originate + /// from the same underlining consensus commit + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub timestamp_ms: CheckpointTimestamp, + /// Present only on the final checkpoint of the epoch. + #[serde(skip_serializing_if = "Option::is_none")] + pub end_of_epoch_data: Option, + /// Transaction digests + pub transactions: Vec, + + /// Commitments to checkpoint state + pub checkpoint_commitments: Vec, + /// Validator Signature + #[schemars(with = "Base64")] + //#[serde_as(as = "Readable")] + pub validator_signature: AggregateAuthoritySignature, +} + +impl + From<( + CheckpointSummary, + CheckpointContents, + AggregateAuthoritySignature, + )> for Checkpoint +{ + fn from( + (summary, contents, signature): ( + CheckpointSummary, + CheckpointContents, + AggregateAuthoritySignature, + ), + ) -> Self { + let digest = summary.digest(); + let CheckpointSummary { + epoch, + sequence_number, + network_total_transactions, + previous_digest, + epoch_rolling_gas_cost_summary, + timestamp_ms, + end_of_epoch_data, + .. + } = summary; + + Checkpoint { + epoch, + sequence_number, + digest, + network_total_transactions, + previous_digest, + epoch_rolling_gas_cost_summary, + timestamp_ms, + end_of_epoch_data, + transactions: contents.iter().map(|digest| digest.transaction).collect(), + // TODO: populate commitment for rpc clients. Most likely, rpc clients don't need this + // info (if they need it, they need to get signed BCS data anyway in order to trust + // it). + checkpoint_commitments: Default::default(), + validator_signature: signature, + } + } +} + +#[serde_as] +#[derive(Clone, Copy, Debug, JsonSchema, Serialize, Deserialize)] +#[serde(untagged)] +pub enum CheckpointId { + SequenceNumber( + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + CheckpointSequenceNumber, + ), + Digest(CheckpointDigest), +} + +impl From for CheckpointId { + fn from(seq: CheckpointSequenceNumber) -> Self { + Self::SequenceNumber(seq) + } +} + +impl From for CheckpointId { + fn from(digest: CheckpointDigest) -> Self { + Self::Digest(digest) + } +} diff --git a/crates/iota-json-rpc-types/src/iota_coin.rs b/crates/iota-json-rpc-types/src/iota_coin.rs new file mode 100644 index 00000000000..216038e9c22 --- /dev/null +++ b/crates/iota-json-rpc-types/src/iota_coin.rs @@ -0,0 +1,108 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashMap; + +use iota_types::{ + base_types::{EpochId, ObjectDigest, ObjectID, ObjectRef, SequenceNumber, TransactionDigest}, + coin::CoinMetadata, + error::IotaError, + iota_serde::{BigInt, SequenceNumber as AsSequenceNumber}, + object::Object, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +use crate::Page; + +pub type CoinPage = Page; + +#[serde_as] +#[derive(Serialize, Deserialize, Debug, JsonSchema, PartialEq, Eq, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Balance { + pub coin_type: String, + pub coin_object_count: usize, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub total_balance: u128, + // TODO: This should be removed + #[schemars(with = "HashMap, BigInt>")] + #[serde_as(as = "HashMap, BigInt>")] + pub locked_balance: HashMap, +} + +impl Balance { + pub fn zero(coin_type: String) -> Self { + Self { + coin_type, + coin_object_count: 0, + total_balance: 0, + locked_balance: HashMap::new(), + } + } +} + +#[serde_as] +#[derive(Serialize, Deserialize, Debug, JsonSchema, PartialEq, Eq, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Coin { + pub coin_type: String, + pub coin_object_id: ObjectID, + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + pub version: SequenceNumber, + pub digest: ObjectDigest, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub balance: u64, + pub previous_transaction: TransactionDigest, +} + +impl Coin { + pub fn object_ref(&self) -> ObjectRef { + (self.coin_object_id, self.version, self.digest) + } +} + +#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct IotaCoinMetadata { + /// Number of decimal places the coin uses. + pub decimals: u8, + /// Name for the token + pub name: String, + /// Symbol for the token + pub symbol: String, + /// Description of the token + pub description: String, + /// URL for the token logo + pub icon_url: Option, + /// Object id for the CoinMetadata object + pub id: Option, +} + +impl TryFrom for IotaCoinMetadata { + type Error = IotaError; + fn try_from(object: Object) -> Result { + let metadata: CoinMetadata = object.try_into()?; + let CoinMetadata { + decimals, + name, + symbol, + description, + icon_url, + id, + } = metadata; + Ok(Self { + id: Some(*id.object_id()), + decimals, + name, + symbol, + description, + icon_url, + }) + } +} diff --git a/crates/iota-json-rpc-types/src/iota_event.rs b/crates/iota-json-rpc-types/src/iota_event.rs new file mode 100644 index 00000000000..71b83b46155 --- /dev/null +++ b/crates/iota-json-rpc-types/src/iota_event.rs @@ -0,0 +1,332 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(any(feature = "test-utils", test))] +use std::str::FromStr; +use std::{fmt, fmt::Display}; + +use fastcrypto::encoding::{Base58, Base64}; +use iota_types::{ + base_types::{IotaAddress, ObjectID, TransactionDigest}, + error::IotaResult, + event::{Event, EventEnvelope, EventID}, + iota_serde::{BigInt, IotaStructTag}, +}; +use json_to_table::json_to_table; +use move_core_types::{ + annotated_value::MoveStructLayout, identifier::Identifier, language_storage::StructTag, +}; +use mysten_metrics::monitored_scope; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Value}; +use serde_with::{serde_as, DisplayFromStr}; +use tabled::settings::Style as TableStyle; + +use crate::{type_and_fields_from_move_struct, Page}; + +pub type EventPage = Page; + +#[serde_as] +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[serde(rename = "Event", rename_all = "camelCase")] +pub struct IotaEvent { + /// Sequential event ID, ie (transaction seq number, event seq number). + /// 1) Serves as a unique event ID for each fullnode + /// 2) Also serves to sequence events for the purposes of pagination and + /// querying. A higher id is an event seen later by that fullnode. + /// This ID is the "cursor" for event querying. + pub id: EventID, + /// Move package where this event was emitted. + pub package_id: ObjectID, + #[schemars(with = "String")] + #[serde_as(as = "DisplayFromStr")] + /// Move module where this event was emitted. + pub transaction_module: Identifier, + /// Sender's Iota address. + pub sender: IotaAddress, + #[schemars(with = "String")] + #[serde_as(as = "IotaStructTag")] + /// Move event type. + pub type_: StructTag, + /// Parsed json value of the event + pub parsed_json: Value, + #[serde_as(as = "Base58")] + #[schemars(with = "Base58")] + /// Base 58 encoded bcs bytes of the move event + pub bcs: Vec, + /// UTC timestamp in milliseconds since epoch (1/1/1970) + #[serde(skip_serializing_if = "Option::is_none")] + #[schemars(with = "Option>")] + #[serde_as(as = "Option>")] + pub timestamp_ms: Option, +} + +impl From for IotaEvent { + fn from(ev: EventEnvelope) -> Self { + Self { + id: EventID { + tx_digest: ev.tx_digest, + event_seq: ev.event_num, + }, + package_id: ev.event.package_id, + transaction_module: ev.event.transaction_module, + sender: ev.event.sender, + type_: ev.event.type_, + parsed_json: ev.parsed_json, + bcs: ev.event.contents, + timestamp_ms: Some(ev.timestamp), + } + } +} + +impl From for Event { + fn from(val: IotaEvent) -> Self { + Event { + package_id: val.package_id, + transaction_module: val.transaction_module, + sender: val.sender, + type_: val.type_, + contents: val.bcs, + } + } +} + +impl IotaEvent { + pub fn try_from( + event: Event, + tx_digest: TransactionDigest, + event_seq: u64, + timestamp_ms: Option, + layout: MoveStructLayout, + ) -> IotaResult { + let Event { + package_id, + transaction_module, + sender, + type_, + contents, + } = event; + + let bcs = contents.to_vec(); + + let move_struct = Event::move_event_to_move_struct(&contents, layout)?; + let (type_, field) = type_and_fields_from_move_struct(&type_, move_struct); + + Ok(IotaEvent { + id: EventID { + tx_digest, + event_seq, + }, + package_id, + transaction_module, + sender, + type_, + parsed_json: field.to_json_value(), + bcs, + timestamp_ms, + }) + } +} + +impl Display for IotaEvent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let parsed_json = &mut self.parsed_json.clone(); + bytes_array_to_base64(parsed_json); + let mut table = json_to_table(parsed_json); + let style = TableStyle::modern(); + table.collapse().with(style); + write!( + f, + " ┌──\n │ EventID: {}:{}\n │ PackageID: {}\n │ Transaction Module: {}\n │ Sender: {}\n │ EventType: {}\n", + self.id.tx_digest, + self.id.event_seq, + self.package_id, + self.transaction_module, + self.sender, + self.type_ + )?; + if let Some(ts) = self.timestamp_ms { + writeln!(f, " │ Timestamp: {}\n └──", ts)?; + } + writeln!(f, " │ ParsedJSON:")?; + let table_string = table.to_string(); + let table_rows = table_string.split_inclusive('\n'); + for r in table_rows { + write!(f, " │ {r}")?; + } + + write!(f, "\n └──") + } +} + +#[cfg(any(feature = "test-utils", test))] +impl IotaEvent { + pub fn random_for_testing() -> Self { + Self { + id: EventID { + tx_digest: TransactionDigest::random(), + event_seq: 0, + }, + package_id: ObjectID::random(), + transaction_module: Identifier::from_str("random_for_testing").unwrap(), + sender: IotaAddress::random_for_testing_only(), + type_: StructTag::from_str("0x6666::random_for_testing::RandomForTesting").unwrap(), + parsed_json: json!({}), + bcs: vec![], + timestamp_ms: None, + } + } +} + +/// Convert a json array of bytes to Base64 +fn bytes_array_to_base64(v: &mut Value) { + match v { + Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => (), + Value::Array(vals) => { + if let Some(vals) = vals.iter().map(try_into_byte).collect::>>() { + *v = json!(Base64::from_bytes(&vals).encoded()) + } else { + for val in vals { + bytes_array_to_base64(val) + } + } + } + Value::Object(map) => { + for val in map.values_mut() { + bytes_array_to_base64(val) + } + } + } +} + +/// Try to convert a json Value object into an u8. +fn try_into_byte(v: &Value) -> Option { + let num = v.as_u64()?; + (num <= 255).then_some(num as u8) +} + +#[serde_as] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub enum EventFilter { + /// Query by sender address. + Sender(IotaAddress), + /// Return events emitted by the given transaction. + Transaction( + /// digest of the transaction, as base-64 encoded string + TransactionDigest, + ), + /// Return events emitted in a specified Package. + Package(ObjectID), + /// Return events emitted in a specified Move module. + /// If the event is defined in Module A but emitted in a tx with Module B, + /// query `MoveModule` by module B returns the event. + /// Query `MoveEventModule` by module A returns the event too. + MoveModule { + /// the Move package ID + package: ObjectID, + /// the module name + #[schemars(with = "String")] + #[serde_as(as = "DisplayFromStr")] + module: Identifier, + }, + /// Return events with the given Move event struct name (struct tag). + /// For example, if the event is defined in `0xabcd::MyModule`, and named + /// `Foo`, then the struct tag is `0xabcd::MyModule::Foo`. + MoveEventType( + #[schemars(with = "String")] + #[serde_as(as = "IotaStructTag")] + StructTag, + ), + /// Return events with the given Move module name where the event struct is + /// defined. If the event is defined in Module A but emitted in a tx + /// with Module B, query `MoveEventModule` by module A returns the + /// event. Query `MoveModule` by module B returns the event too. + MoveEventModule { + /// the Move package ID + package: ObjectID, + /// the module name + #[schemars(with = "String")] + #[serde_as(as = "DisplayFromStr")] + module: Identifier, + }, + MoveEventField { + path: String, + value: Value, + }, + /// Return events emitted in [start_time, end_time] interval + #[serde(rename_all = "camelCase")] + TimeRange { + /// left endpoint of time interval, milliseconds since epoch, inclusive + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + start_time: u64, + /// right endpoint of time interval, milliseconds since epoch, exclusive + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + end_time: u64, + }, + + All(Vec), + Any(Vec), + And(Box, Box), + Or(Box, Box), +} + +impl EventFilter { + fn try_matches(&self, item: &IotaEvent) -> IotaResult { + Ok(match self { + EventFilter::MoveEventType(event_type) => &item.type_ == event_type, + EventFilter::MoveEventField { path, value } => { + matches!(item.parsed_json.pointer(path), Some(v) if v == value) + } + EventFilter::Sender(sender) => &item.sender == sender, + EventFilter::Package(object_id) => &item.package_id == object_id, + EventFilter::MoveModule { package, module } => { + &item.transaction_module == module && &item.package_id == package + } + EventFilter::All(filters) => filters.iter().all(|f| f.matches(item)), + EventFilter::Any(filters) => filters.iter().any(|f| f.matches(item)), + EventFilter::And(f1, f2) => { + EventFilter::All(vec![*(*f1).clone(), *(*f2).clone()]).matches(item) + } + EventFilter::Or(f1, f2) => { + EventFilter::Any(vec![*(*f1).clone(), *(*f2).clone()]).matches(item) + } + EventFilter::Transaction(digest) => digest == &item.id.tx_digest, + + EventFilter::TimeRange { + start_time, + end_time, + } => { + if let Some(timestamp) = &item.timestamp_ms { + start_time <= timestamp && end_time > timestamp + } else { + false + } + } + EventFilter::MoveEventModule { package, module } => { + &item.type_.module == module && &ObjectID::from(item.type_.address) == package + } + }) + } + + pub fn and(self, other_filter: EventFilter) -> Self { + Self::All(vec![self, other_filter]) + } + pub fn or(self, other_filter: EventFilter) -> Self { + Self::Any(vec![self, other_filter]) + } +} + +impl Filter for EventFilter { + fn matches(&self, item: &IotaEvent) -> bool { + let _scope = monitored_scope("EventFilter::matches"); + self.try_matches(item).unwrap_or_default() + } +} + +pub trait Filter { + fn matches(&self, item: &T) -> bool; +} diff --git a/crates/iota-json-rpc-types/src/iota_extended.rs b/crates/iota-json-rpc-types/src/iota_extended.rs new file mode 100644 index 00000000000..5931fc234a6 --- /dev/null +++ b/crates/iota-json-rpc-types/src/iota_extended.rs @@ -0,0 +1,117 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use fastcrypto::traits::ToFromBytes; +use iota_types::{ + base_types::{AuthorityName, EpochId, ObjectID}, + committee::Committee, + iota_serde::BigInt, + iota_system_state::iota_system_state_summary::IotaValidatorSummary, + messages_checkpoint::CheckpointSequenceNumber, +}; +use move_core_types::identifier::Identifier; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, DisplayFromStr}; + +use crate::Page; + +pub type EpochPage = Page>; + +#[serde_as] +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct EpochInfo { + /// epoch number + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub epoch: EpochId, + /// list of validators included in epoch + pub validators: Vec, + /// count of tx in epoch + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub epoch_total_transactions: u64, + /// first, last checkpoint sequence numbers + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub first_checkpoint_id: CheckpointSequenceNumber, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub epoch_start_timestamp: u64, + pub end_of_epoch_info: Option, + pub reference_gas_price: Option, +} + +impl EpochInfo { + pub fn committee(&self) -> Result { + let mut voting_rights = BTreeMap::new(); + for validator in &self.validators { + let name = AuthorityName::from_bytes(&validator.protocol_pubkey_bytes)?; + voting_rights.insert(name, validator.voting_power); + } + Ok(Committee::new(self.epoch, voting_rights)) + } +} + +#[serde_as] +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct EndOfEpochInfo { + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub last_checkpoint_id: CheckpointSequenceNumber, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub epoch_end_timestamp: u64, + /// existing fields from `SystemEpochInfo` + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub protocol_version: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub reference_gas_price: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub total_stake: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub storage_fund_reinvestment: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub storage_charge: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub storage_rebate: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub storage_fund_balance: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub stake_subsidy_amount: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub total_gas_fees: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub total_stake_rewards_distributed: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub leftover_storage_fund_inflow: u64, +} + +#[serde_as] +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct MoveFunctionName { + pub package: ObjectID, + #[schemars(with = "String")] + #[serde_as(as = "DisplayFromStr")] + pub module: Identifier, + #[schemars(with = "String")] + #[serde_as(as = "DisplayFromStr")] + pub function: Identifier, +} diff --git a/crates/iota-json-rpc-types/src/iota_governance.rs b/crates/iota-json-rpc-types/src/iota_governance.rs new file mode 100644 index 00000000000..c9088c2ae40 --- /dev/null +++ b/crates/iota-json-rpc-types/src/iota_governance.rs @@ -0,0 +1,122 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_types::{ + base_types::{AuthorityName, EpochId, IotaAddress, ObjectID}, + committee::{Committee, StakeUnit}, + iota_serde::BigInt, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +/// RPC representation of the [Committee] type. +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +#[serde(rename = "CommitteeInfo")] +pub struct IotaCommittee { + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub epoch: EpochId, + #[schemars(with = "Vec<(AuthorityName, BigInt)>")] + #[serde_as(as = "Vec<(_, BigInt)>")] + pub validators: Vec<(AuthorityName, StakeUnit)>, +} + +impl From for IotaCommittee { + fn from(committee: Committee) -> Self { + Self { + epoch: committee.epoch, + validators: committee.voting_rights, + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct DelegatedStake { + /// Validator's Address. + pub validator_address: IotaAddress, + /// Staking pool object id. + pub staking_pool: ObjectID, + pub stakes: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct DelegatedTimelockedStake { + pub validator_address: IotaAddress, + pub staking_pool: ObjectID, + pub stakes: Vec, +} + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +#[serde(tag = "status")] +pub enum StakeStatus { + Pending, + #[serde(rename_all = "camelCase")] + Active { + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + estimated_reward: u64, + }, + Unstaked, +} + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct Stake { + /// ID of the StakedIota receipt object. + pub staked_iota_id: ObjectID, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub stake_request_epoch: EpochId, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub stake_active_epoch: EpochId, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub principal: u64, + #[serde(flatten)] + pub status: StakeStatus, +} + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct TimelockedStake { + pub timelocked_staked_iota_id: ObjectID, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub stake_request_epoch: EpochId, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub stake_active_epoch: EpochId, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub principal: u64, + #[serde(flatten)] + pub status: StakeStatus, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub expiration_timestamp_ms: u64, +} + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +pub struct ValidatorApys { + pub apys: Vec, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub epoch: EpochId, +} + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +pub struct ValidatorApy { + pub address: IotaAddress, + pub apy: f64, +} diff --git a/crates/iota-json-rpc-types/src/iota_move.rs b/crates/iota-json-rpc-types/src/iota_move.rs new file mode 100644 index 00000000000..b4b9ccc96f1 --- /dev/null +++ b/crates/iota-json-rpc-types/src/iota_move.rs @@ -0,0 +1,558 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::BTreeMap, + fmt, + fmt::{Display, Formatter, Write}, +}; + +use colored::Colorize; +use iota_macros::EnumVariantOrder; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + iota_serde::IotaStructTag, +}; +use itertools::Itertools; +use move_binary_format::{ + file_format::{Ability, AbilitySet, StructTypeParameter, Visibility}, + normalized::{ + Field as NormalizedField, Function as IotaNormalizedFunction, Module as NormalizedModule, + Struct as NormalizedStruct, Type as NormalizedType, + }, +}; +use move_core_types::{ + annotated_value::{MoveStruct, MoveValue}, + identifier::Identifier, + language_storage::StructTag, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Value}; +use serde_with::serde_as; +use tracing::warn; + +pub type IotaMoveTypeParameterIndex = u16; + +#[cfg(test)] +#[path = "unit_tests/iota_move_tests.rs"] +mod iota_move_tests; + +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +pub enum IotaMoveAbility { + Copy, + Drop, + Store, + Key, +} + +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +pub struct IotaMoveAbilitySet { + pub abilities: Vec, +} + +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +pub enum IotaMoveVisibility { + Private, + Public, + Friend, +} + +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct IotaMoveStructTypeParameter { + pub constraints: IotaMoveAbilitySet, + pub is_phantom: bool, +} + +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +pub struct IotaMoveNormalizedField { + pub name: String, + #[serde(rename = "type")] + pub type_: IotaMoveNormalizedType, +} + +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct IotaMoveNormalizedStruct { + pub abilities: IotaMoveAbilitySet, + pub type_parameters: Vec, + pub fields: Vec, +} + +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +pub enum IotaMoveNormalizedType { + Bool, + U8, + U16, + U32, + U64, + U128, + U256, + Address, + Signer, + #[serde(rename_all = "camelCase")] + Struct { + address: String, + module: String, + name: String, + type_arguments: Vec, + }, + Vector(Box), + TypeParameter(IotaMoveTypeParameterIndex), + Reference(Box), + MutableReference(Box), +} + +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct IotaMoveNormalizedFunction { + pub visibility: IotaMoveVisibility, + pub is_entry: bool, + pub type_parameters: Vec, + pub parameters: Vec, + pub return_: Vec, +} + +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +pub struct IotaMoveModuleId { + address: String, + name: String, +} + +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct IotaMoveNormalizedModule { + pub file_format_version: u32, + pub address: String, + pub name: String, + pub friends: Vec, + pub structs: BTreeMap, + pub exposed_functions: BTreeMap, +} + +impl PartialEq for IotaMoveNormalizedModule { + fn eq(&self, other: &Self) -> bool { + self.file_format_version == other.file_format_version + && self.address == other.address + && self.name == other.name + } +} + +impl From for IotaMoveNormalizedModule { + fn from(module: NormalizedModule) -> Self { + Self { + file_format_version: module.file_format_version, + address: module.address.to_hex_literal(), + name: module.name.to_string(), + friends: module + .friends + .into_iter() + .map(|module_id| IotaMoveModuleId { + address: module_id.address().to_hex_literal(), + name: module_id.name().to_string(), + }) + .collect::>(), + structs: module + .structs + .into_iter() + .map(|(name, struct_)| (name.to_string(), IotaMoveNormalizedStruct::from(struct_))) + .collect::>(), + exposed_functions: module + .functions + .into_iter() + .filter_map(|(name, function)| { + // TODO: Do we want to expose the private functions as well? + (function.is_entry || function.visibility != Visibility::Private) + .then(|| (name.to_string(), IotaMoveNormalizedFunction::from(function))) + }) + .collect::>(), + } + } +} + +impl From for IotaMoveNormalizedFunction { + fn from(function: IotaNormalizedFunction) -> Self { + Self { + visibility: match function.visibility { + Visibility::Private => IotaMoveVisibility::Private, + Visibility::Public => IotaMoveVisibility::Public, + Visibility::Friend => IotaMoveVisibility::Friend, + }, + is_entry: function.is_entry, + type_parameters: function + .type_parameters + .into_iter() + .map(|a| a.into()) + .collect::>(), + parameters: function + .parameters + .into_iter() + .map(IotaMoveNormalizedType::from) + .collect::>(), + return_: function + .return_ + .into_iter() + .map(IotaMoveNormalizedType::from) + .collect::>(), + } + } +} + +impl From for IotaMoveNormalizedStruct { + fn from(struct_: NormalizedStruct) -> Self { + Self { + abilities: struct_.abilities.into(), + type_parameters: struct_ + .type_parameters + .into_iter() + .map(IotaMoveStructTypeParameter::from) + .collect::>(), + fields: struct_ + .fields + .into_iter() + .map(IotaMoveNormalizedField::from) + .collect::>(), + } + } +} + +impl From for IotaMoveStructTypeParameter { + fn from(type_parameter: StructTypeParameter) -> Self { + Self { + constraints: type_parameter.constraints.into(), + is_phantom: type_parameter.is_phantom, + } + } +} + +impl From for IotaMoveNormalizedField { + fn from(normalized_field: NormalizedField) -> Self { + Self { + name: normalized_field.name.to_string(), + type_: IotaMoveNormalizedType::from(normalized_field.type_), + } + } +} + +impl From for IotaMoveNormalizedType { + fn from(type_: NormalizedType) -> Self { + match type_ { + NormalizedType::Bool => IotaMoveNormalizedType::Bool, + NormalizedType::U8 => IotaMoveNormalizedType::U8, + NormalizedType::U16 => IotaMoveNormalizedType::U16, + NormalizedType::U32 => IotaMoveNormalizedType::U32, + NormalizedType::U64 => IotaMoveNormalizedType::U64, + NormalizedType::U128 => IotaMoveNormalizedType::U128, + NormalizedType::U256 => IotaMoveNormalizedType::U256, + NormalizedType::Address => IotaMoveNormalizedType::Address, + NormalizedType::Signer => IotaMoveNormalizedType::Signer, + NormalizedType::Struct { + address, + module, + name, + type_arguments, + } => IotaMoveNormalizedType::Struct { + address: address.to_hex_literal(), + module: module.to_string(), + name: name.to_string(), + type_arguments: type_arguments + .into_iter() + .map(IotaMoveNormalizedType::from) + .collect::>(), + }, + NormalizedType::Vector(v) => { + IotaMoveNormalizedType::Vector(Box::new(IotaMoveNormalizedType::from(*v))) + } + NormalizedType::TypeParameter(t) => IotaMoveNormalizedType::TypeParameter(t), + NormalizedType::Reference(r) => { + IotaMoveNormalizedType::Reference(Box::new(IotaMoveNormalizedType::from(*r))) + } + NormalizedType::MutableReference(mr) => IotaMoveNormalizedType::MutableReference( + Box::new(IotaMoveNormalizedType::from(*mr)), + ), + } + } +} + +impl From for IotaMoveAbilitySet { + fn from(set: AbilitySet) -> IotaMoveAbilitySet { + Self { + abilities: set + .into_iter() + .map(|a| match a { + Ability::Copy => IotaMoveAbility::Copy, + Ability::Drop => IotaMoveAbility::Drop, + Ability::Key => IotaMoveAbility::Key, + Ability::Store => IotaMoveAbility::Store, + }) + .collect::>(), + } + } +} + +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +pub enum ObjectValueKind { + ByImmutableReference, + ByMutableReference, + ByValue, +} + +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +pub enum MoveFunctionArgType { + Pure, + Object(ObjectValueKind), +} + +#[serde_as] +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq, EnumVariantOrder)] +#[serde(untagged, rename = "MoveValue")] +pub enum IotaMoveValue { + // u64 and u128 are converted to String to avoid overflow + Number(u32), + Bool(bool), + Address(IotaAddress), + Vector(Vec), + String(String), + UID { id: ObjectID }, + Struct(IotaMoveStruct), + Option(Box>), +} + +impl IotaMoveValue { + /// Extract values from MoveValue without type information in json format + pub fn to_json_value(self) -> Value { + match self { + IotaMoveValue::Struct(move_struct) => move_struct.to_json_value(), + IotaMoveValue::Vector(values) => IotaMoveStruct::Runtime(values).to_json_value(), + IotaMoveValue::Number(v) => json!(v), + IotaMoveValue::Bool(v) => json!(v), + IotaMoveValue::Address(v) => json!(v), + IotaMoveValue::String(v) => json!(v), + IotaMoveValue::UID { id } => json!({ "id": id }), + IotaMoveValue::Option(v) => json!(v), + } + } +} + +impl Display for IotaMoveValue { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let mut writer = String::new(); + match self { + IotaMoveValue::Number(value) => write!(writer, "{}", value)?, + IotaMoveValue::Bool(value) => write!(writer, "{}", value)?, + IotaMoveValue::Address(value) => write!(writer, "{}", value)?, + IotaMoveValue::String(value) => write!(writer, "{}", value)?, + IotaMoveValue::UID { id } => write!(writer, "{id}")?, + IotaMoveValue::Struct(value) => write!(writer, "{}", value)?, + IotaMoveValue::Option(value) => write!(writer, "{:?}", value)?, + IotaMoveValue::Vector(vec) => { + write!( + writer, + "{}", + vec.iter().map(|value| format!("{value}")).join(",\n") + )?; + } + } + write!(f, "{}", writer.trim_end_matches('\n')) + } +} + +impl From for IotaMoveValue { + fn from(value: MoveValue) -> Self { + match value { + MoveValue::U8(value) => IotaMoveValue::Number(value.into()), + MoveValue::U16(value) => IotaMoveValue::Number(value.into()), + MoveValue::U32(value) => IotaMoveValue::Number(value), + MoveValue::U64(value) => IotaMoveValue::String(format!("{value}")), + MoveValue::U128(value) => IotaMoveValue::String(format!("{value}")), + MoveValue::U256(value) => IotaMoveValue::String(format!("{value}")), + MoveValue::Bool(value) => IotaMoveValue::Bool(value), + MoveValue::Vector(values) => { + IotaMoveValue::Vector(values.into_iter().map(|value| value.into()).collect()) + } + MoveValue::Struct(value) => { + // Best effort Iota core type conversion + let MoveStruct { type_, fields } = &value; + if let Some(value) = try_convert_type(type_, fields) { + return value; + } + IotaMoveValue::Struct(value.into()) + } + MoveValue::Signer(value) | MoveValue::Address(value) => { + IotaMoveValue::Address(IotaAddress::from(ObjectID::from(value))) + } + } + } +} + +fn to_bytearray(value: &[MoveValue]) -> Option> { + if value.iter().all(|value| matches!(value, MoveValue::U8(_))) { + let bytearray = value + .iter() + .flat_map(|value| { + if let MoveValue::U8(u8) = value { + Some(*u8) + } else { + None + } + }) + .collect::>(); + Some(bytearray) + } else { + None + } +} + +#[serde_as] +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq, EnumVariantOrder)] +#[serde(untagged, rename = "MoveStruct")] +pub enum IotaMoveStruct { + Runtime(Vec), + WithTypes { + #[schemars(with = "String")] + #[serde(rename = "type")] + #[serde_as(as = "IotaStructTag")] + type_: StructTag, + fields: BTreeMap, + }, + WithFields(BTreeMap), +} + +impl IotaMoveStruct { + /// Extract values from MoveStruct without type information in json format + pub fn to_json_value(self) -> Value { + // Unwrap MoveStructs + match self { + IotaMoveStruct::Runtime(values) => { + let values = values + .into_iter() + .map(|value| value.to_json_value()) + .collect::>(); + json!(values) + } + // We only care about values here, assuming struct type information is known at the + // client side. + IotaMoveStruct::WithTypes { type_: _, fields } | IotaMoveStruct::WithFields(fields) => { + let fields = fields + .into_iter() + .map(|(key, value)| (key, value.to_json_value())) + .collect::>(); + json!(fields) + } + } + } + + pub fn read_dynamic_field_value(&self, field_name: &str) -> Option { + match self { + IotaMoveStruct::WithFields(fields) => fields.get(field_name).cloned(), + IotaMoveStruct::WithTypes { type_: _, fields } => fields.get(field_name).cloned(), + _ => None, + } + } +} + +impl Display for IotaMoveStruct { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let mut writer = String::new(); + match self { + IotaMoveStruct::Runtime(_) => {} + IotaMoveStruct::WithFields(fields) => { + for (name, value) in fields { + writeln!(writer, "{}: {value}", name.bold().bright_black())?; + } + } + IotaMoveStruct::WithTypes { type_, fields } => { + writeln!(writer)?; + writeln!(writer, " {}: {type_}", "type".bold().bright_black())?; + for (name, value) in fields { + let value = format!("{}", value); + let value = if value.starts_with('\n') { + indent(&value, 2) + } else { + value + }; + writeln!(writer, " {}: {value}", name.bold().bright_black())?; + } + } + } + write!(f, "{}", writer.trim_end_matches('\n')) + } +} + +fn indent(d: &T, indent: usize) -> String { + d.to_string() + .lines() + .map(|line| format!("{:indent$}{}", "", line)) + .join("\n") +} + +fn try_convert_type( + type_: &StructTag, + fields: &[(Identifier, MoveValue)], +) -> Option { + let struct_name = format!( + "0x{}::{}::{}", + type_.address.short_str_lossless(), + type_.module, + type_.name + ); + let mut values = fields + .iter() + .map(|(id, value)| (id.to_string(), value)) + .collect::>(); + match struct_name.as_str() { + "0x1::string::String" | "0x1::ascii::String" => { + if let Some(MoveValue::Vector(bytes)) = values.remove("bytes") { + return to_bytearray(bytes) + .and_then(|bytes| String::from_utf8(bytes).ok()) + .map(IotaMoveValue::String); + } + } + "0x2::url::Url" => { + return values.remove("url").cloned().map(IotaMoveValue::from); + } + "0x2::object::ID" => { + return values.remove("bytes").cloned().map(IotaMoveValue::from); + } + "0x2::object::UID" => { + let id = values.remove("id").cloned().map(IotaMoveValue::from); + if let Some(IotaMoveValue::Address(address)) = id { + return Some(IotaMoveValue::UID { + id: ObjectID::from(address), + }); + } + } + "0x2::balance::Balance" => { + return values.remove("value").cloned().map(IotaMoveValue::from); + } + "0x1::option::Option" => { + if let Some(MoveValue::Vector(values)) = values.remove("vec") { + return Some(IotaMoveValue::Option(Box::new( + // in Move option is modeled as vec of 1 element + values.first().cloned().map(IotaMoveValue::from), + ))); + } + } + _ => return None, + } + warn!( + fields =? fields, + "Failed to convert {struct_name} to IotaMoveValue" + ); + None +} + +impl From for IotaMoveStruct { + fn from(move_struct: MoveStruct) -> Self { + IotaMoveStruct::WithTypes { + type_: move_struct.type_, + fields: move_struct + .fields + .into_iter() + .map(|(id, value)| (id.into_string(), value.into())) + .collect(), + } + } +} diff --git a/crates/iota-json-rpc-types/src/iota_object.rs b/crates/iota-json-rpc-types/src/iota_object.rs new file mode 100644 index 00000000000..69cdf7d1f4d --- /dev/null +++ b/crates/iota-json-rpc-types/src/iota_object.rs @@ -0,0 +1,1264 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + cmp::Ordering, + collections::BTreeMap, + fmt, + fmt::{Display, Formatter, Write}, +}; + +use anyhow::anyhow; +use colored::Colorize; +use fastcrypto::encoding::Base64; +use iota_protocol_config::ProtocolConfig; +use iota_types::{ + base_types::{ + IotaAddress, ObjectDigest, ObjectID, ObjectInfo, ObjectRef, ObjectType, SequenceNumber, + TransactionDigest, + }, + error::{ExecutionError, IotaObjectResponseError, UserInputError, UserInputResult}, + gas_coin::GasCoin, + iota_serde::{BigInt, IotaStructTag, SequenceNumber as AsSequenceNumber}, + messages_checkpoint::CheckpointSequenceNumber, + move_package::{MovePackage, TypeOrigin, UpgradeInfo}, + object::{Data, MoveObject, Object, ObjectInner, ObjectRead, Owner}, +}; +use move_bytecode_utils::module_cache::GetModule; +use move_core_types::{ + annotated_value::{MoveStruct, MoveStructLayout}, + identifier::Identifier, + language_storage::StructTag, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use serde_with::{serde_as, DisplayFromStr}; + +use crate::{IotaMoveStruct, IotaMoveValue, Page}; + +#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone, PartialEq, Eq)] +pub struct IotaObjectResponse { + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, +} + +impl IotaObjectResponse { + pub fn new(data: Option, error: Option) -> Self { + Self { data, error } + } + + pub fn new_with_data(data: IotaObjectData) -> Self { + Self { + data: Some(data), + error: None, + } + } + + pub fn new_with_error(error: IotaObjectResponseError) -> Self { + Self { + data: None, + error: Some(error), + } + } +} + +impl Ord for IotaObjectResponse { + fn cmp(&self, other: &Self) -> Ordering { + match (&self.data, &other.data) { + (Some(data), Some(data_2)) => { + if data.object_id.cmp(&data_2.object_id).eq(&Ordering::Greater) { + return Ordering::Greater; + } else if data.object_id.cmp(&data_2.object_id).eq(&Ordering::Less) { + return Ordering::Less; + } + Ordering::Equal + } + // In this ordering those with data will come before IotaObjectResponses that are + // errors. + (Some(_), None) => Ordering::Less, + (None, Some(_)) => Ordering::Greater, + // IotaObjectResponses that are errors are just considered equal. + _ => Ordering::Equal, + } + } +} + +impl PartialOrd for IotaObjectResponse { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl IotaObjectResponse { + pub fn move_object_bcs(&self) -> Option<&Vec> { + match &self.data { + Some(IotaObjectData { + bcs: Some(IotaRawData::MoveObject(obj)), + .. + }) => Some(&obj.bcs_bytes), + _ => None, + } + } + + pub fn owner(&self) -> Option { + if let Some(data) = &self.data { + return data.owner; + } + None + } + + pub fn object_id(&self) -> Result { + match (&self.data, &self.error) { + (Some(obj_data), None) => Ok(obj_data.object_id), + (None, Some(IotaObjectResponseError::NotExists { object_id })) => Ok(*object_id), + ( + None, + Some(IotaObjectResponseError::Deleted { + object_id, + version: _, + digest: _, + }), + ) => Ok(*object_id), + _ => Err(anyhow!( + "Could not get object_id, something went wrong with IotaObjectResponse construction." + )), + } + } + + pub fn object_ref_if_exists(&self) -> Option { + match (&self.data, &self.error) { + (Some(obj_data), None) => Some(obj_data.object_ref()), + _ => None, + } + } +} + +impl TryFrom for ObjectInfo { + type Error = anyhow::Error; + + fn try_from(value: IotaObjectResponse) -> Result { + let IotaObjectData { + object_id, + version, + digest, + type_, + owner, + previous_transaction, + .. + } = value.into_object()?; + + Ok(ObjectInfo { + object_id, + version, + digest, + type_: type_.ok_or_else(|| anyhow!("Object type not found for object."))?, + owner: owner.ok_or_else(|| anyhow!("Owner not found for object."))?, + previous_transaction: previous_transaction + .ok_or_else(|| anyhow!("Transaction digest not found for object."))?, + }) + } +} + +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, Eq, PartialEq)] +pub struct DisplayFieldsResponse { + pub data: Option>, + pub error: Option, +} + +#[serde_as] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, Eq, PartialEq)] +#[serde(rename_all = "camelCase", rename = "ObjectData")] +pub struct IotaObjectData { + pub object_id: ObjectID, + /// Object version. + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + pub version: SequenceNumber, + /// Base64 string representing the object digest + pub digest: ObjectDigest, + /// The type of the object. Default to be None unless + /// IotaObjectDataOptions.showType is set to true + #[schemars(with = "Option")] + #[serde_as(as = "Option")] + #[serde(rename = "type", skip_serializing_if = "Option::is_none")] + pub type_: Option, + // Default to be None because otherwise it will be repeated for the getOwnedObjects endpoint + /// The owner of this object. Default to be None unless + /// IotaObjectDataOptions.showOwner is set to true + #[serde(skip_serializing_if = "Option::is_none")] + pub owner: Option, + /// The digest of the transaction that created or last mutated this object. + /// Default to be None unless IotaObjectDataOptions. + /// showPreviousTransaction is set to true + #[serde(skip_serializing_if = "Option::is_none")] + pub previous_transaction: Option, + /// The amount of IOTA we would rebate if this object gets deleted. + /// This number is re-calculated each time the object is mutated based on + /// the present storage gas price. + #[schemars(with = "Option>")] + #[serde_as(as = "Option>")] + #[serde(skip_serializing_if = "Option::is_none")] + pub storage_rebate: Option, + /// The Display metadata for frontend UI rendering, default to be None + /// unless IotaObjectDataOptions.showContent is set to true This can also + /// be None if the struct type does not have Display defined See more details in + #[serde(skip_serializing_if = "Option::is_none")] + pub display: Option, + /// Move object content or package content, default to be None unless + /// IotaObjectDataOptions.showContent is set to true + #[serde(skip_serializing_if = "Option::is_none")] + pub content: Option, + /// Move object content or package content in BCS, default to be None unless + /// IotaObjectDataOptions.showBcs is set to true + #[serde(skip_serializing_if = "Option::is_none")] + pub bcs: Option, +} + +impl IotaObjectData { + pub fn object_ref(&self) -> ObjectRef { + (self.object_id, self.version, self.digest) + } + + pub fn object_type(&self) -> anyhow::Result { + self.type_ + .as_ref() + .ok_or_else(|| anyhow!("type is missing for object {:?}", self.object_id)) + .cloned() + } + + pub fn is_gas_coin(&self) -> bool { + match self.type_.as_ref() { + Some(ObjectType::Struct(ty)) if ty.is_gas_coin() => true, + Some(_) => false, + None => false, + } + } +} + +impl Display for IotaObjectData { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let type_ = if let Some(type_) = &self.type_ { + type_.to_string() + } else { + "Unknown Type".into() + }; + let mut writer = String::new(); + writeln!( + writer, + "{}", + format!("----- {type_} ({}[{}]) -----", self.object_id, self.version).bold() + )?; + if let Some(owner) = self.owner { + writeln!(writer, "{}: {}", "Owner".bold().bright_black(), owner)?; + } + + writeln!( + writer, + "{}: {}", + "Version".bold().bright_black(), + self.version + )?; + if let Some(storage_rebate) = self.storage_rebate { + writeln!( + writer, + "{}: {}", + "Storage Rebate".bold().bright_black(), + storage_rebate + )?; + } + + if let Some(previous_transaction) = self.previous_transaction { + writeln!( + writer, + "{}: {:?}", + "Previous Transaction".bold().bright_black(), + previous_transaction + )?; + } + if let Some(content) = self.content.as_ref() { + writeln!(writer, "{}", "----- Data -----".bold())?; + write!(writer, "{}", content)?; + } + + write!(f, "{}", writer) + } +} + +impl TryFrom<&IotaObjectData> for GasCoin { + type Error = anyhow::Error; + fn try_from(object: &IotaObjectData) -> Result { + match &object + .content + .as_ref() + .ok_or_else(|| anyhow!("Expect object content to not be empty"))? + { + IotaParsedData::MoveObject(o) => { + if GasCoin::type_() == o.type_ { + return GasCoin::try_from(&o.fields); + } + } + IotaParsedData::Package(_) => {} + } + + Err(anyhow!( + "Gas object type is not a gas coin: {:?}", + object.type_ + )) + } +} + +impl TryFrom<&IotaMoveStruct> for GasCoin { + type Error = anyhow::Error; + fn try_from(move_struct: &IotaMoveStruct) -> Result { + match move_struct { + IotaMoveStruct::WithFields(fields) | IotaMoveStruct::WithTypes { type_: _, fields } => { + if let Some(IotaMoveValue::String(balance)) = fields.get("balance") { + if let Ok(balance) = balance.parse::() { + if let Some(IotaMoveValue::UID { id }) = fields.get("id") { + return Ok(GasCoin::new(*id, balance)); + } + } + } + } + _ => {} + } + Err(anyhow!("Struct is not a gas coin: {move_struct:?}")) + } +} + +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, Eq, PartialEq, Default)] +#[serde(rename_all = "camelCase", rename = "ObjectDataOptions", default)] +pub struct IotaObjectDataOptions { + /// Whether to show the type of the object. Default to be False + pub show_type: bool, + /// Whether to show the owner of the object. Default to be False + pub show_owner: bool, + /// Whether to show the previous transaction digest of the object. Default + /// to be False + pub show_previous_transaction: bool, + /// Whether to show the Display metadata of the object for frontend + /// rendering. Default to be False + pub show_display: bool, + /// Whether to show the content(i.e., package content or Move struct + /// content) of the object. Default to be False + pub show_content: bool, + /// Whether to show the content in BCS format. Default to be False + pub show_bcs: bool, + /// Whether to show the storage rebate of the object. Default to be False + pub show_storage_rebate: bool, +} + +impl IotaObjectDataOptions { + pub fn new() -> Self { + Self::default() + } + + /// return BCS data and all other metadata such as storage rebate + pub fn bcs_lossless() -> Self { + Self { + show_bcs: true, + show_type: true, + show_owner: true, + show_previous_transaction: true, + show_display: false, + show_content: false, + show_storage_rebate: true, + } + } + + /// return full content except bcs + pub fn full_content() -> Self { + Self { + show_bcs: false, + show_type: true, + show_owner: true, + show_previous_transaction: true, + show_display: false, + show_content: true, + show_storage_rebate: true, + } + } + + pub fn with_content(mut self) -> Self { + self.show_content = true; + self + } + + pub fn with_owner(mut self) -> Self { + self.show_owner = true; + self + } + + pub fn with_type(mut self) -> Self { + self.show_type = true; + self + } + + pub fn with_display(mut self) -> Self { + self.show_display = true; + self + } + + pub fn with_bcs(mut self) -> Self { + self.show_bcs = true; + self + } + + pub fn with_previous_transaction(mut self) -> Self { + self.show_previous_transaction = true; + self + } + + pub fn is_not_in_object_info(&self) -> bool { + self.show_bcs || self.show_content || self.show_display || self.show_storage_rebate + } +} + +impl TryFrom<(ObjectRead, IotaObjectDataOptions)> for IotaObjectResponse { + type Error = anyhow::Error; + + fn try_from( + (object_read, options): (ObjectRead, IotaObjectDataOptions), + ) -> Result { + match object_read { + ObjectRead::NotExists(id) => Ok(IotaObjectResponse::new_with_error( + IotaObjectResponseError::NotExists { object_id: id }, + )), + ObjectRead::Exists(object_ref, o, layout) => { + let data = (object_ref, o, layout, options).try_into()?; + Ok(IotaObjectResponse::new_with_data(data)) + } + ObjectRead::Deleted((object_id, version, digest)) => Ok( + IotaObjectResponse::new_with_error(IotaObjectResponseError::Deleted { + object_id, + version, + digest, + }), + ), + } + } +} + +impl TryFrom<(ObjectInfo, IotaObjectDataOptions)> for IotaObjectResponse { + type Error = anyhow::Error; + + fn try_from( + (object_info, options): (ObjectInfo, IotaObjectDataOptions), + ) -> Result { + let IotaObjectDataOptions { + show_type, + show_owner, + show_previous_transaction, + .. + } = options; + + Ok(Self::new_with_data(IotaObjectData { + object_id: object_info.object_id, + version: object_info.version, + digest: object_info.digest, + type_: show_type.then_some(object_info.type_), + owner: show_owner.then_some(object_info.owner), + previous_transaction: show_previous_transaction + .then_some(object_info.previous_transaction), + storage_rebate: None, + display: None, + content: None, + bcs: None, + })) + } +} + +impl + TryFrom<( + ObjectRef, + Object, + Option, + IotaObjectDataOptions, + )> for IotaObjectData +{ + type Error = anyhow::Error; + + fn try_from( + (object_ref, o, layout, options): ( + ObjectRef, + Object, + Option, + IotaObjectDataOptions, + ), + ) -> Result { + let IotaObjectDataOptions { + show_type, + show_owner, + show_previous_transaction, + show_content, + show_bcs, + show_storage_rebate, + .. + } = options; + + let (object_id, version, digest) = object_ref; + let type_ = if show_type { + Some(Into::::into(&o)) + } else { + None + }; + + let bcs: Option = if show_bcs { + let data = match o.data.clone() { + Data::Move(m) => { + let layout = layout.clone().ok_or_else(|| { + anyhow!("Layout is required to convert Move object to json") + })?; + IotaRawData::try_from_object(m, layout)? + } + Data::Package(p) => IotaRawData::try_from_package(p) + .map_err(|e| anyhow!("Error getting raw data from package: {e:#?}"))?, + }; + Some(data) + } else { + None + }; + + let o = o.into_inner(); + + let content: Option = if show_content { + let data = match o.data { + Data::Move(m) => { + let layout = layout.ok_or_else(|| { + anyhow!("Layout is required to convert Move object to json") + })?; + IotaParsedData::try_from_object(m, layout)? + } + Data::Package(p) => IotaParsedData::try_from_package(p)?, + }; + Some(data) + } else { + None + }; + + Ok(IotaObjectData { + object_id, + version, + digest, + type_, + owner: if show_owner { Some(o.owner) } else { None }, + storage_rebate: if show_storage_rebate { + Some(o.storage_rebate) + } else { + None + }, + previous_transaction: if show_previous_transaction { + Some(o.previous_transaction) + } else { + None + }, + content, + bcs, + display: None, + }) + } +} + +impl + TryFrom<( + ObjectRef, + Object, + Option, + IotaObjectDataOptions, + Option, + )> for IotaObjectData +{ + type Error = anyhow::Error; + + fn try_from( + (object_ref, o, layout, options, display_fields): ( + ObjectRef, + Object, + Option, + IotaObjectDataOptions, + Option, + ), + ) -> Result { + let show_display = options.show_display; + let mut data: IotaObjectData = (object_ref, o, layout, options).try_into()?; + if show_display { + data.display = display_fields; + } + Ok(data) + } +} + +impl IotaObjectResponse { + /// Returns a reference to the object if there is any, otherwise an Err if + /// the object does not exist or is deleted. + pub fn object(&self) -> Result<&IotaObjectData, IotaObjectResponseError> { + if let Some(data) = &self.data { + Ok(data) + } else if let Some(error) = &self.error { + Err(error.clone()) + } else { + // We really shouldn't reach this code block since either data, or error field + // should always be filled. + Err(IotaObjectResponseError::Unknown) + } + } + + /// Returns the object value if there is any, otherwise an Err if + /// the object does not exist or is deleted. + pub fn into_object(self) -> Result { + match self.object() { + Ok(data) => Ok(data.clone()), + Err(error) => Err(error), + } + } +} + +impl TryInto for IotaObjectData { + type Error = anyhow::Error; + + fn try_into(self) -> Result { + let protocol_config = ProtocolConfig::get_for_min_version(); + let data = match self.bcs { + Some(IotaRawData::MoveObject(o)) => Data::Move(unsafe { + MoveObject::new_from_execution( + o.type_().clone().into(), + o.has_public_transfer, + o.version, + o.bcs_bytes, + &protocol_config, + )? + }), + Some(IotaRawData::Package(p)) => Data::Package(MovePackage::new( + p.id, + self.version, + p.module_map, + protocol_config.max_move_package_size(), + p.type_origin_table, + p.linkage_table, + )?), + _ => Err(anyhow!( + "BCS data is required to convert IotaObjectData to Object" + ))?, + }; + Ok(ObjectInner { + data, + owner: self + .owner + .ok_or_else(|| anyhow!("Owner is required to convert IotaObjectData to Object"))?, + previous_transaction: self.previous_transaction.ok_or_else(|| { + anyhow!("previous_transaction is required to convert IotaObjectData to Object") + })?, + storage_rebate: self.storage_rebate.ok_or_else(|| { + anyhow!("storage_rebate is required to convert IotaObjectData to Object") + })?, + } + .into()) + } +} + +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, Eq, PartialEq, Ord, PartialOrd)] +#[serde(rename_all = "camelCase", rename = "ObjectRef")] +pub struct IotaObjectRef { + /// Hex code as string representing the object id + pub object_id: ObjectID, + /// Object version. + pub version: SequenceNumber, + /// Base64 string representing the object digest + pub digest: ObjectDigest, +} + +impl IotaObjectRef { + pub fn to_object_ref(&self) -> ObjectRef { + (self.object_id, self.version, self.digest) + } +} + +impl Display for IotaObjectRef { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "Object ID: {}, version: {}, digest: {}", + self.object_id, self.version, self.digest + ) + } +} + +impl From for IotaObjectRef { + fn from(oref: ObjectRef) -> Self { + Self { + object_id: oref.0, + version: oref.1, + digest: oref.2, + } + } +} + +pub trait IotaData: Sized { + type ObjectType; + type PackageType; + fn try_from_object(object: MoveObject, layout: MoveStructLayout) + -> Result; + fn try_from_package(package: MovePackage) -> Result; + fn try_as_move(&self) -> Option<&Self::ObjectType>; + fn try_into_move(self) -> Option; + fn try_as_package(&self) -> Option<&Self::PackageType>; + fn type_(&self) -> Option<&StructTag>; +} + +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)] +#[serde(tag = "dataType", rename_all = "camelCase", rename = "RawData")] +pub enum IotaRawData { + // Manually handle generic schema generation + MoveObject(IotaRawMoveObject), + Package(IotaRawMovePackage), +} + +impl IotaData for IotaRawData { + type ObjectType = IotaRawMoveObject; + type PackageType = IotaRawMovePackage; + + fn try_from_object(object: MoveObject, _: MoveStructLayout) -> Result { + Ok(Self::MoveObject(object.into())) + } + + fn try_from_package(package: MovePackage) -> Result { + Ok(Self::Package(package.into())) + } + + fn try_as_move(&self) -> Option<&Self::ObjectType> { + match self { + Self::MoveObject(o) => Some(o), + Self::Package(_) => None, + } + } + + fn try_into_move(self) -> Option { + match self { + Self::MoveObject(o) => Some(o), + Self::Package(_) => None, + } + } + + fn try_as_package(&self) -> Option<&Self::PackageType> { + match self { + Self::MoveObject(_) => None, + Self::Package(p) => Some(p), + } + } + + fn type_(&self) -> Option<&StructTag> { + match self { + Self::MoveObject(o) => Some(&o.type_), + Self::Package(_) => None, + } + } +} + +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)] +#[serde(tag = "dataType", rename_all = "camelCase", rename = "Data")] +pub enum IotaParsedData { + // Manually handle generic schema generation + MoveObject(IotaParsedMoveObject), + Package(IotaMovePackage), +} + +impl IotaData for IotaParsedData { + type ObjectType = IotaParsedMoveObject; + type PackageType = IotaMovePackage; + + fn try_from_object( + object: MoveObject, + layout: MoveStructLayout, + ) -> Result { + Ok(Self::MoveObject(IotaParsedMoveObject::try_from_layout( + object, layout, + )?)) + } + + fn try_from_package(package: MovePackage) -> Result { + Ok(Self::Package(IotaMovePackage { + disassembled: package.disassemble()?, + })) + } + + fn try_as_move(&self) -> Option<&Self::ObjectType> { + match self { + Self::MoveObject(o) => Some(o), + Self::Package(_) => None, + } + } + + fn try_into_move(self) -> Option { + match self { + Self::MoveObject(o) => Some(o), + Self::Package(_) => None, + } + } + + fn try_as_package(&self) -> Option<&Self::PackageType> { + match self { + Self::MoveObject(_) => None, + Self::Package(p) => Some(p), + } + } + + fn type_(&self) -> Option<&StructTag> { + match self { + Self::MoveObject(o) => Some(&o.type_), + Self::Package(_) => None, + } + } +} + +impl Display for IotaParsedData { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let mut writer = String::new(); + match self { + IotaParsedData::MoveObject(o) => { + writeln!(writer, "{}: {}", "type".bold().bright_black(), o.type_)?; + write!(writer, "{}", &o.fields)?; + } + IotaParsedData::Package(p) => { + write!( + writer, + "{}: {:?}", + "Modules".bold().bright_black(), + p.disassembled.keys() + )?; + } + } + write!(f, "{}", writer) + } +} + +impl IotaParsedData { + pub fn try_from_object_read(object_read: ObjectRead) -> Result { + match object_read { + ObjectRead::NotExists(id) => Err(anyhow::anyhow!("Object {} does not exist", id)), + ObjectRead::Exists(_object_ref, o, layout) => { + let data = match o.into_inner().data { + Data::Move(m) => { + let layout = layout.ok_or_else(|| { + anyhow!("Layout is required to convert Move object to json") + })?; + IotaParsedData::try_from_object(m, layout)? + } + Data::Package(p) => IotaParsedData::try_from_package(p)?, + }; + Ok(data) + } + ObjectRead::Deleted((object_id, version, digest)) => Err(anyhow::anyhow!( + "Object {} was deleted at version {} with digest {}", + object_id, + version, + digest + )), + } + } +} + +pub trait IotaMoveObject: Sized { + fn try_from_layout(object: MoveObject, layout: MoveStructLayout) + -> Result; + + fn try_from(o: MoveObject, resolver: &impl GetModule) -> Result { + let layout = o.get_layout(resolver)?; + Self::try_from_layout(o, layout) + } + + fn type_(&self) -> &StructTag; +} + +#[serde_as] +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)] +#[serde(rename = "MoveObject", rename_all = "camelCase")] +pub struct IotaParsedMoveObject { + #[serde(rename = "type")] + #[serde_as(as = "IotaStructTag")] + #[schemars(with = "String")] + pub type_: StructTag, + pub has_public_transfer: bool, + pub fields: IotaMoveStruct, +} + +impl IotaMoveObject for IotaParsedMoveObject { + fn try_from_layout( + object: MoveObject, + layout: MoveStructLayout, + ) -> Result { + let move_struct = object.to_move_struct(&layout)?.into(); + + Ok( + if let IotaMoveStruct::WithTypes { type_, fields } = move_struct { + IotaParsedMoveObject { + type_, + has_public_transfer: object.has_public_transfer(), + fields: IotaMoveStruct::WithFields(fields), + } + } else { + IotaParsedMoveObject { + type_: object.type_().clone().into(), + has_public_transfer: object.has_public_transfer(), + fields: move_struct, + } + }, + ) + } + + fn type_(&self) -> &StructTag { + &self.type_ + } +} + +impl IotaParsedMoveObject { + pub fn try_from_object_read(object_read: ObjectRead) -> Result { + let parsed_data = IotaParsedData::try_from_object_read(object_read)?; + match parsed_data { + IotaParsedData::MoveObject(o) => Ok(o), + IotaParsedData::Package(_) => Err(anyhow::anyhow!("Object is not a Move object")), + } + } + + pub fn read_dynamic_field_value(&self, field_name: &str) -> Option { + match &self.fields { + IotaMoveStruct::WithFields(fields) => fields.get(field_name).cloned(), + IotaMoveStruct::WithTypes { fields, .. } => fields.get(field_name).cloned(), + _ => None, + } + } +} + +pub fn type_and_fields_from_move_struct( + type_: &StructTag, + move_struct: MoveStruct, +) -> (StructTag, IotaMoveStruct) { + match move_struct.into() { + IotaMoveStruct::WithTypes { type_, fields } => (type_, IotaMoveStruct::WithFields(fields)), + fields => (type_.clone(), fields), + } +} + +#[serde_as] +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)] +#[serde(rename = "RawMoveObject", rename_all = "camelCase")] +pub struct IotaRawMoveObject { + #[schemars(with = "String")] + #[serde(rename = "type")] + #[serde_as(as = "IotaStructTag")] + pub type_: StructTag, + pub has_public_transfer: bool, + pub version: SequenceNumber, + #[serde_as(as = "Base64")] + #[schemars(with = "Base64")] + pub bcs_bytes: Vec, +} + +impl From for IotaRawMoveObject { + fn from(o: MoveObject) -> Self { + Self { + type_: o.type_().clone().into(), + has_public_transfer: o.has_public_transfer(), + version: o.version(), + bcs_bytes: o.into_contents(), + } + } +} + +impl IotaMoveObject for IotaRawMoveObject { + fn try_from_layout( + object: MoveObject, + _layout: MoveStructLayout, + ) -> Result { + Ok(Self { + type_: object.type_().clone().into(), + has_public_transfer: object.has_public_transfer(), + version: object.version(), + bcs_bytes: object.into_contents(), + }) + } + + fn type_(&self) -> &StructTag { + &self.type_ + } +} + +impl IotaRawMoveObject { + pub fn deserialize<'a, T: Deserialize<'a>>(&'a self) -> Result { + Ok(bcs::from_bytes(self.bcs_bytes.as_slice())?) + } +} + +#[serde_as] +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)] +#[serde(rename = "RawMovePackage", rename_all = "camelCase")] +pub struct IotaRawMovePackage { + pub id: ObjectID, + pub version: SequenceNumber, + #[schemars(with = "BTreeMap")] + #[serde_as(as = "BTreeMap<_, Base64>")] + pub module_map: BTreeMap>, + pub type_origin_table: Vec, + pub linkage_table: BTreeMap, +} + +impl From for IotaRawMovePackage { + fn from(p: MovePackage) -> Self { + Self { + id: p.id(), + version: p.version(), + module_map: p.serialized_module_map().clone(), + type_origin_table: p.type_origin_table().clone(), + linkage_table: p.linkage_table().clone(), + } + } +} + +impl IotaRawMovePackage { + pub fn to_move_package( + &self, + max_move_package_size: u64, + ) -> Result { + MovePackage::new( + self.id, + self.version, + self.module_map.clone(), + max_move_package_size, + self.type_origin_table.clone(), + self.linkage_table.clone(), + ) + } +} + +#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone, PartialEq, Eq)] +#[serde(tag = "status", content = "details", rename = "ObjectRead")] +pub enum IotaPastObjectResponse { + /// The object exists and is found with this version + VersionFound(IotaObjectData), + /// The object does not exist + ObjectNotExists(ObjectID), + /// The object is found to be deleted with this version + ObjectDeleted(IotaObjectRef), + /// The object exists but not found with this version + VersionNotFound(ObjectID, SequenceNumber), + /// The asked object version is higher than the latest + VersionTooHigh { + object_id: ObjectID, + asked_version: SequenceNumber, + latest_version: SequenceNumber, + }, +} + +impl IotaPastObjectResponse { + /// Returns a reference to the object if there is any, otherwise an Err + pub fn object(&self) -> UserInputResult<&IotaObjectData> { + match &self { + Self::ObjectDeleted(oref) => Err(UserInputError::ObjectDeleted { + object_ref: oref.to_object_ref(), + }), + Self::ObjectNotExists(id) => Err(UserInputError::ObjectNotFound { + object_id: *id, + version: None, + }), + Self::VersionFound(o) => Ok(o), + Self::VersionNotFound(id, seq_num) => Err(UserInputError::ObjectNotFound { + object_id: *id, + version: Some(*seq_num), + }), + Self::VersionTooHigh { + object_id, + asked_version, + latest_version, + } => Err(UserInputError::ObjectSequenceNumberTooHigh { + object_id: *object_id, + asked_version: *asked_version, + latest_version: *latest_version, + }), + } + } + + /// Returns the object value if there is any, otherwise an Err + pub fn into_object(self) -> UserInputResult { + match self { + Self::ObjectDeleted(oref) => Err(UserInputError::ObjectDeleted { + object_ref: oref.to_object_ref(), + }), + Self::ObjectNotExists(id) => Err(UserInputError::ObjectNotFound { + object_id: id, + version: None, + }), + Self::VersionFound(o) => Ok(o), + Self::VersionNotFound(object_id, version) => Err(UserInputError::ObjectNotFound { + object_id, + version: Some(version), + }), + Self::VersionTooHigh { + object_id, + asked_version, + latest_version, + } => Err(UserInputError::ObjectSequenceNumberTooHigh { + object_id, + asked_version, + latest_version, + }), + } + } +} + +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)] +#[serde(rename = "MovePackage", rename_all = "camelCase")] +pub struct IotaMovePackage { + pub disassembled: BTreeMap, +} + +pub type QueryObjectsPage = Page; +pub type ObjectsPage = Page; + +#[serde_as] +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Copy, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct CheckpointedObjectID { + pub object_id: ObjectID, + #[schemars(with = "Option>")] + #[serde_as(as = "Option>")] + #[serde(skip_serializing_if = "Option::is_none")] + pub at_checkpoint: Option, +} + +#[serde_as] +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)] +#[serde(rename = "GetPastObjectRequest", rename_all = "camelCase")] +pub struct IotaGetPastObjectRequest { + /// the ID of the queried object + pub object_id: ObjectID, + /// the version of the queried object. + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + pub version: SequenceNumber, +} + +#[serde_as] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub enum IotaObjectDataFilter { + MatchAll(Vec), + MatchAny(Vec), + MatchNone(Vec), + /// Query by type a specified Package. + Package(ObjectID), + /// Query by type a specified Move module. + MoveModule { + /// the Move package ID + package: ObjectID, + /// the module name + #[schemars(with = "String")] + #[serde_as(as = "DisplayFromStr")] + module: Identifier, + }, + /// Query by type + StructType( + #[schemars(with = "String")] + #[serde_as(as = "IotaStructTag")] + StructTag, + ), + AddressOwner(IotaAddress), + ObjectOwner(ObjectID), + ObjectId(ObjectID), + // allow querying for multiple object ids + ObjectIds(Vec), + Version( + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + u64, + ), +} + +impl IotaObjectDataFilter { + pub fn gas_coin() -> Self { + Self::StructType(GasCoin::type_()) + } + + pub fn and(self, other: Self) -> Self { + Self::MatchAll(vec![self, other]) + } + pub fn or(self, other: Self) -> Self { + Self::MatchAny(vec![self, other]) + } + pub fn not(self, other: Self) -> Self { + Self::MatchNone(vec![self, other]) + } + + pub fn matches(&self, object: &ObjectInfo) -> bool { + match self { + IotaObjectDataFilter::MatchAll(filters) => !filters.iter().any(|f| !f.matches(object)), + IotaObjectDataFilter::MatchAny(filters) => filters.iter().any(|f| f.matches(object)), + IotaObjectDataFilter::MatchNone(filters) => !filters.iter().any(|f| f.matches(object)), + IotaObjectDataFilter::StructType(s) => { + let obj_tag: StructTag = match &object.type_ { + ObjectType::Package => return false, + ObjectType::Struct(s) => s.clone().into(), + }; + // If people do not provide type_params, we will match all type_params + // e.g. `0x2::coin::Coin` can match `0x2::coin::Coin<0x2::iota::IOTA>` + if !s.type_params.is_empty() && s.type_params != obj_tag.type_params { + false + } else { + obj_tag.address == s.address + && obj_tag.module == s.module + && obj_tag.name == s.name + } + } + IotaObjectDataFilter::MoveModule { package, module } => { + matches!(&object.type_, ObjectType::Struct(s) if &ObjectID::from(s.address()) == package + && s.module() == module.as_ident_str()) + } + IotaObjectDataFilter::Package(p) => { + matches!(&object.type_, ObjectType::Struct(s) if &ObjectID::from(s.address()) == p) + } + IotaObjectDataFilter::AddressOwner(a) => { + matches!(object.owner, Owner::AddressOwner(addr) if &addr == a) + } + IotaObjectDataFilter::ObjectOwner(o) => { + matches!(object.owner, Owner::ObjectOwner(addr) if addr == IotaAddress::from(*o)) + } + IotaObjectDataFilter::ObjectId(id) => &object.object_id == id, + IotaObjectDataFilter::ObjectIds(ids) => ids.contains(&object.object_id), + IotaObjectDataFilter::Version(v) => object.version.value() == *v, + } + } +} + +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, Default)] +#[serde(rename_all = "camelCase", rename = "ObjectResponseQuery", default)] +pub struct IotaObjectResponseQuery { + /// If None, no filter will be applied + pub filter: Option, + /// config which fields to include in the response, by default only digest + /// is included + pub options: Option, +} + +impl IotaObjectResponseQuery { + pub fn new( + filter: Option, + options: Option, + ) -> Self { + Self { filter, options } + } + + pub fn new_with_filter(filter: IotaObjectDataFilter) -> Self { + Self { + filter: Some(filter), + options: None, + } + } + + pub fn new_with_options(options: IotaObjectDataOptions) -> Self { + Self { + filter: None, + options: Some(options), + } + } +} diff --git a/crates/iota-json-rpc-types/src/iota_protocol.rs b/crates/iota-json-rpc-types/src/iota_protocol.rs new file mode 100644 index 00000000000..f4e3d897649 --- /dev/null +++ b/crates/iota-json-rpc-types/src/iota_protocol.rs @@ -0,0 +1,81 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use iota_protocol_config::{ProtocolConfig, ProtocolConfigValue, ProtocolVersion}; +use iota_types::iota_serde::{AsProtocolVersion, BigInt, Readable}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, DisplayFromStr}; + +#[serde_as] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, PartialEq)] +#[serde(rename_all = "camelCase", rename = "ProtocolConfigValue")] +pub enum IotaProtocolConfigValue { + U16( + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + u16, + ), + U32( + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + u32, + ), + U64( + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + u64, + ), + F64( + #[schemars(with = "String")] + #[serde_as(as = "DisplayFromStr")] + f64, + ), +} + +impl From for IotaProtocolConfigValue { + fn from(value: ProtocolConfigValue) -> Self { + match value { + ProtocolConfigValue::u16(y) => IotaProtocolConfigValue::U16(y), + ProtocolConfigValue::u32(y) => IotaProtocolConfigValue::U32(y), + ProtocolConfigValue::u64(x) => IotaProtocolConfigValue::U64(x), + ProtocolConfigValue::f64(z) => IotaProtocolConfigValue::F64(z), + } + } +} + +#[serde_as] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, PartialEq)] +#[serde(rename_all = "camelCase", rename = "ProtocolConfig")] +pub struct ProtocolConfigResponse { + #[schemars(with = "AsProtocolVersion")] + #[serde_as(as = "Readable")] + pub min_supported_protocol_version: ProtocolVersion, + #[schemars(with = "AsProtocolVersion")] + #[serde_as(as = "Readable")] + pub max_supported_protocol_version: ProtocolVersion, + #[schemars(with = "AsProtocolVersion")] + #[serde_as(as = "Readable")] + pub protocol_version: ProtocolVersion, + pub feature_flags: BTreeMap, + pub attributes: BTreeMap>, +} + +impl From for ProtocolConfigResponse { + fn from(config: ProtocolConfig) -> Self { + ProtocolConfigResponse { + protocol_version: config.version, + attributes: config + .attr_map() + .into_iter() + .map(|(k, v)| (k, v.map(IotaProtocolConfigValue::from))) + .collect(), + min_supported_protocol_version: ProtocolVersion::MIN, + max_supported_protocol_version: ProtocolVersion::MAX, + feature_flags: config.feature_map(), + } + } +} diff --git a/crates/iota-json-rpc-types/src/iota_transaction.rs b/crates/iota-json-rpc-types/src/iota_transaction.rs new file mode 100644 index 00000000000..4788d5e7662 --- /dev/null +++ b/crates/iota-json-rpc-types/src/iota_transaction.rs @@ -0,0 +1,2245 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt::{self, Display, Formatter, Write}; + +use enum_dispatch::enum_dispatch; +use fastcrypto::encoding::Base64; +use iota_json::{primitive_type, IotaJsonValue}; +use iota_types::{ + authenticator_state::ActiveJwk, + base_types::{EpochId, IotaAddress, ObjectID, ObjectRef, SequenceNumber, TransactionDigest}, + crypto::IotaSignature, + digests::{ConsensusCommitDigest, ObjectDigest, TransactionEventsDigest}, + effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, + error::{ExecutionError, IotaError, IotaResult}, + execution_status::ExecutionStatus, + gas::GasCostSummary, + iota_serde::{ + BigInt, IotaTypeTag as AsIotaTypeTag, Readable, SequenceNumber as AsSequenceNumber, + }, + messages_checkpoint::CheckpointSequenceNumber, + object::{MoveObject, Owner}, + parse_iota_type_tag, + quorum_driver_types::ExecuteTransactionRequestType, + signature::GenericSignature, + storage::{DeleteKind, WriteKind}, + transaction::{ + Argument, CallArg, ChangeEpoch, Command, EndOfEpochTransactionKind, GenesisObject, + InputObjectKind, ObjectArg, ProgrammableMoveCall, ProgrammableTransaction, + SenderSignedData, TransactionData, TransactionDataAPI, TransactionKind, + VersionedProtocolMessage, + }, + type_resolver::LayoutResolver, + IOTA_FRAMEWORK_ADDRESS, +}; +use move_binary_format::{access::ModuleAccess, binary_views::BinaryIndexedView, CompiledModule}; +use move_bytecode_utils::module_cache::GetModule; +use move_core_types::{ + annotated_value::MoveTypeLayout, + identifier::IdentStr, + language_storage::{ModuleId, StructTag, TypeTag}, +}; +use mysten_metrics::monitored_scope; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; +use tabled::{ + builder::Builder as TableBuilder, + settings::{style::HorizontalLine, Panel as TablePanel, Style as TableStyle}, +}; + +use crate::{ + balance_changes::BalanceChange, iota_transaction::GenericSignature::Signature, + object_changes::ObjectChange, Filter, IotaEvent, IotaObjectRef, Page, +}; + +// similar to EpochId of iota-types but BigInt +pub type IotaEpochId = BigInt; + +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, Default)] +#[serde( + rename_all = "camelCase", + rename = "TransactionBlockResponseQuery", + default +)] +pub struct IotaTransactionBlockResponseQuery { + /// If None, no filter will be applied + pub filter: Option, + /// config which fields to include in the response, by default only digest + /// is included + pub options: Option, +} + +impl IotaTransactionBlockResponseQuery { + pub fn new( + filter: Option, + options: Option, + ) -> Self { + Self { filter, options } + } + + pub fn new_with_filter(filter: TransactionFilter) -> Self { + Self { + filter: Some(filter), + options: None, + } + } +} + +pub type TransactionBlocksPage = Page; + +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, Eq, PartialEq, Default)] +#[serde( + rename_all = "camelCase", + rename = "TransactionBlockResponseOptions", + default +)] +pub struct IotaTransactionBlockResponseOptions { + /// Whether to show transaction input data. Default to be False + pub show_input: bool, + /// Whether to show bcs-encoded transaction input data + pub show_raw_input: bool, + /// Whether to show transaction effects. Default to be False + pub show_effects: bool, + /// Whether to show transaction events. Default to be False + pub show_events: bool, + /// Whether to show object_changes. Default to be False + pub show_object_changes: bool, + /// Whether to show balance_changes. Default to be False + pub show_balance_changes: bool, + /// Whether to show raw transaction effects. Default to be False + pub show_raw_effects: bool, +} + +impl IotaTransactionBlockResponseOptions { + pub fn new() -> Self { + Self::default() + } + + pub fn full_content() -> Self { + Self { + show_effects: true, + show_input: true, + show_raw_input: true, + show_events: true, + show_object_changes: true, + show_balance_changes: true, + // This field is added for graphql execution. We keep it false here + // so current users of `full_content` will not get raw effects unexpectedly. + show_raw_effects: false, + } + } + + pub fn with_input(mut self) -> Self { + self.show_input = true; + self + } + + pub fn with_raw_input(mut self) -> Self { + self.show_raw_input = true; + self + } + + pub fn with_effects(mut self) -> Self { + self.show_effects = true; + self + } + + pub fn with_events(mut self) -> Self { + self.show_events = true; + self + } + + pub fn with_balance_changes(mut self) -> Self { + self.show_balance_changes = true; + self + } + + pub fn with_object_changes(mut self) -> Self { + self.show_object_changes = true; + self + } + + pub fn with_raw_effects(mut self) -> Self { + self.show_raw_effects = true; + self + } + + /// default to return `WaitForEffectsCert` unless some options require + /// local execution + pub fn default_execution_request_type(&self) -> ExecuteTransactionRequestType { + // if people want effects or events, they typically want to wait for local + // execution + if self.require_effects() { + ExecuteTransactionRequestType::WaitForLocalExecution + } else { + ExecuteTransactionRequestType::WaitForEffectsCert + } + } + + pub fn require_local_execution(&self) -> bool { + self.show_balance_changes || self.show_object_changes + } + + pub fn require_input(&self) -> bool { + self.show_input || self.show_raw_input || self.show_object_changes + } + + pub fn require_effects(&self) -> bool { + self.show_effects + || self.show_events + || self.show_balance_changes + || self.show_object_changes + || self.show_raw_effects + } + + pub fn only_digest(&self) -> bool { + self == &Self::default() + } +} + +#[serde_as] +#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone, Default)] +#[serde(rename_all = "camelCase", rename = "TransactionBlockResponse")] +pub struct IotaTransactionBlockResponse { + pub digest: TransactionDigest, + /// Transaction input data + #[serde(skip_serializing_if = "Option::is_none")] + pub transaction: Option, + /// BCS encoded [SenderSignedData] that includes input object references + /// returns empty array if `show_raw_transaction` is false + #[serde_as(as = "Base64")] + #[schemars(with = "Base64")] + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub raw_transaction: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub effects: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub events: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub object_changes: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub balance_changes: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[schemars(with = "Option>")] + #[serde_as(as = "Option>")] + pub timestamp_ms: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub confirmed_local_execution: Option, + /// The checkpoint number when this transaction was included and hence + /// finalized. This is only returned in the read api, not in the + /// transaction execution api. + #[schemars(with = "Option>")] + #[serde_as(as = "Option>")] + #[serde(skip_serializing_if = "Option::is_none")] + pub checkpoint: Option, + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub errors: Vec, + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub raw_effects: Vec, +} + +impl IotaTransactionBlockResponse { + pub fn new(digest: TransactionDigest) -> Self { + Self { + digest, + ..Default::default() + } + } + + pub fn status_ok(&self) -> Option { + self.effects.as_ref().map(|e| e.status().is_ok()) + } +} + +/// We are specifically ignoring events for now until events become more stable. +impl PartialEq for IotaTransactionBlockResponse { + fn eq(&self, other: &Self) -> bool { + self.transaction == other.transaction + && self.effects == other.effects + && self.timestamp_ms == other.timestamp_ms + && self.confirmed_local_execution == other.confirmed_local_execution + && self.checkpoint == other.checkpoint + } +} + +impl Display for IotaTransactionBlockResponse { + fn fmt(&self, writer: &mut Formatter<'_>) -> fmt::Result { + writeln!(writer, "Transaction Digest: {}", &self.digest)?; + + if let Some(t) = &self.transaction { + writeln!(writer, "{}", t)?; + } + + if let Some(e) = &self.effects { + writeln!(writer, "{}", e)?; + } + + if let Some(e) = &self.events { + writeln!(writer, "{}", e)?; + } + + if let Some(object_changes) = &self.object_changes { + let mut builder = TableBuilder::default(); + let ( + mut created, + mut deleted, + mut mutated, + mut published, + mut transferred, + mut wrapped, + ) = (vec![], vec![], vec![], vec![], vec![], vec![]); + + for obj in object_changes { + match obj { + ObjectChange::Created { .. } => created.push(obj), + ObjectChange::Deleted { .. } => deleted.push(obj), + ObjectChange::Mutated { .. } => mutated.push(obj), + ObjectChange::Published { .. } => published.push(obj), + ObjectChange::Transferred { .. } => transferred.push(obj), + ObjectChange::Wrapped { .. } => wrapped.push(obj), + }; + } + + write_obj_changes(created, "Created", &mut builder)?; + write_obj_changes(deleted, "Deleted", &mut builder)?; + write_obj_changes(mutated, "Mutated", &mut builder)?; + write_obj_changes(published, "Published", &mut builder)?; + write_obj_changes(transferred, "Transferred", &mut builder)?; + write_obj_changes(wrapped, "Wrapped", &mut builder)?; + + let mut table = builder.build(); + table.with(TablePanel::header("Object Changes")); + table.with(TableStyle::rounded().horizontals([HorizontalLine::new( + 1, + TableStyle::modern().get_horizontal(), + )])); + writeln!(writer, "{}", table)?; + } + + if let Some(balance_changes) = &self.balance_changes { + let mut builder = TableBuilder::default(); + for balance in balance_changes { + builder.push_record(vec![format!("{}", balance)]); + } + let mut table = builder.build(); + table.with(TablePanel::header("Balance Changes")); + table.with(TableStyle::rounded().horizontals([HorizontalLine::new( + 1, + TableStyle::modern().get_horizontal(), + )])); + writeln!(writer, "{}", table)?; + } + Ok(()) + } +} + +fn write_obj_changes( + values: Vec, + output_string: &str, + builder: &mut TableBuilder, +) -> std::fmt::Result { + if !values.is_empty() { + builder.push_record(vec![format!("{} Objects: ", output_string)]); + for obj in values { + builder.push_record(vec![format!("{}", obj)]); + } + } + Ok(()) +} + +pub fn get_new_package_obj_from_response( + response: &IotaTransactionBlockResponse, +) -> Option { + response.object_changes.as_ref().and_then(|changes| { + changes + .iter() + .find(|change| matches!(change, ObjectChange::Published { .. })) + .map(|change| change.object_ref()) + }) +} + +pub fn get_new_package_upgrade_cap_from_response( + response: &IotaTransactionBlockResponse, +) -> Option { + response.object_changes.as_ref().and_then(|changes| { + changes + .iter() + .find(|change| { + matches!(change, ObjectChange::Created { + owner: Owner::AddressOwner(_), + object_type: StructTag { + address: IOTA_FRAMEWORK_ADDRESS, + module, + name, + .. + }, + .. + } if module.as_str() == "package" && name.as_str() == "UpgradeCap") + }) + .map(|change| change.object_ref()) + }) +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename = "TransactionBlockKind", tag = "kind")] +pub enum IotaTransactionBlockKind { + /// A system transaction that will update epoch information on-chain. + ChangeEpoch(IotaChangeEpoch), + /// A system transaction used for initializing the initial state of the + /// chain. + Genesis(IotaGenesisTransaction), + /// A system transaction marking the start of a series of transactions + /// scheduled as part of a checkpoint + ConsensusCommitPrologue(IotaConsensusCommitPrologue), + /// A series of transactions where the results of one transaction can be + /// used in future transactions + ProgrammableTransaction(IotaProgrammableTransactionBlock), + /// A transaction which updates global authenticator state + AuthenticatorStateUpdate(IotaAuthenticatorStateUpdate), + /// A transaction which updates global randomness state + RandomnessStateUpdate(IotaRandomnessStateUpdate), + /// The transaction which occurs only at the end of the epoch + EndOfEpochTransaction(IotaEndOfEpochTransaction), + ConsensusCommitPrologueV2(IotaConsensusCommitPrologueV2), + // .. more transaction types go here +} + +impl Display for IotaTransactionBlockKind { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let mut writer = String::new(); + match &self { + Self::ChangeEpoch(e) => { + writeln!(writer, "Transaction Kind: Epoch Change")?; + writeln!(writer, "New epoch ID: {}", e.epoch)?; + writeln!(writer, "Storage gas reward: {}", e.storage_charge)?; + writeln!(writer, "Computation gas reward: {}", e.computation_charge)?; + writeln!(writer, "Storage rebate: {}", e.storage_rebate)?; + writeln!(writer, "Timestamp: {}", e.epoch_start_timestamp_ms)?; + } + Self::Genesis(_) => { + writeln!(writer, "Transaction Kind: Genesis Transaction")?; + } + Self::ConsensusCommitPrologue(p) => { + writeln!(writer, "Transaction Kind: Consensus Commit Prologue")?; + writeln!( + writer, + "Epoch: {}, Round: {}, Timestamp: {}", + p.epoch, p.round, p.commit_timestamp_ms + )?; + } + Self::ConsensusCommitPrologueV2(p) => { + writeln!(writer, "Transaction Kind: Consensus Commit Prologue V2")?; + writeln!( + writer, + "Epoch: {}, Round: {}, Timestamp: {}, ConsensusCommitDigest: {}", + p.epoch, p.round, p.commit_timestamp_ms, p.consensus_commit_digest + )?; + } + Self::ProgrammableTransaction(p) => { + write!(writer, "Transaction Kind: Programmable")?; + write!(writer, "{}", crate::displays::Pretty(p))?; + } + Self::AuthenticatorStateUpdate(_) => { + writeln!(writer, "Transaction Kind: Authenticator State Update")?; + } + Self::RandomnessStateUpdate(_) => { + writeln!(writer, "Transaction Kind: Randomness State Update")?; + } + Self::EndOfEpochTransaction(_) => { + writeln!(writer, "Transaction Kind: End of Epoch Transaction")?; + } + } + write!(f, "{}", writer) + } +} + +impl IotaTransactionBlockKind { + fn try_from(tx: TransactionKind, module_cache: &impl GetModule) -> Result { + Ok(match tx { + TransactionKind::ChangeEpoch(e) => Self::ChangeEpoch(e.into()), + TransactionKind::Genesis(g) => Self::Genesis(IotaGenesisTransaction { + objects: g.objects.iter().map(GenesisObject::id).collect(), + }), + TransactionKind::ConsensusCommitPrologue(p) => { + Self::ConsensusCommitPrologue(IotaConsensusCommitPrologue { + epoch: p.epoch, + round: p.round, + commit_timestamp_ms: p.commit_timestamp_ms, + }) + } + TransactionKind::ConsensusCommitPrologueV2(p) => { + Self::ConsensusCommitPrologueV2(IotaConsensusCommitPrologueV2 { + epoch: p.epoch, + round: p.round, + commit_timestamp_ms: p.commit_timestamp_ms, + consensus_commit_digest: p.consensus_commit_digest, + }) + } + TransactionKind::ProgrammableTransaction(p) => Self::ProgrammableTransaction( + IotaProgrammableTransactionBlock::try_from(p, module_cache)?, + ), + TransactionKind::AuthenticatorStateUpdate(update) => { + Self::AuthenticatorStateUpdate(IotaAuthenticatorStateUpdate { + epoch: update.epoch, + round: update.round, + new_active_jwks: update + .new_active_jwks + .into_iter() + .map(IotaActiveJwk::from) + .collect(), + }) + } + TransactionKind::RandomnessStateUpdate(update) => { + Self::RandomnessStateUpdate(IotaRandomnessStateUpdate { + epoch: update.epoch, + randomness_round: update.randomness_round.0, + random_bytes: update.random_bytes, + }) + } + TransactionKind::EndOfEpochTransaction(end_of_epoch_tx) => { + Self::EndOfEpochTransaction(IotaEndOfEpochTransaction { + transactions: end_of_epoch_tx + .into_iter() + .map(|tx| match tx { + EndOfEpochTransactionKind::ChangeEpoch(e) => { + IotaEndOfEpochTransactionKind::ChangeEpoch(e.into()) + } + EndOfEpochTransactionKind::AuthenticatorStateCreate => { + IotaEndOfEpochTransactionKind::AuthenticatorStateCreate + } + EndOfEpochTransactionKind::AuthenticatorStateExpire(expire) => { + IotaEndOfEpochTransactionKind::AuthenticatorStateExpire( + IotaAuthenticatorStateExpire { + min_epoch: expire.min_epoch, + }, + ) + } + EndOfEpochTransactionKind::RandomnessStateCreate => { + IotaEndOfEpochTransactionKind::RandomnessStateCreate + } + EndOfEpochTransactionKind::DenyListStateCreate => { + IotaEndOfEpochTransactionKind::CoinDenyListStateCreate + } + }) + .collect(), + }) + } + }) + } + + pub fn transaction_count(&self) -> usize { + match self { + Self::ProgrammableTransaction(p) => p.commands.len(), + _ => 1, + } + } + + pub fn name(&self) -> &'static str { + match self { + Self::ChangeEpoch(_) => "ChangeEpoch", + Self::Genesis(_) => "Genesis", + Self::ConsensusCommitPrologue(_) => "ConsensusCommitPrologue", + Self::ConsensusCommitPrologueV2(_) => "ConsensusCommitPrologueV2", + Self::ProgrammableTransaction(_) => "ProgrammableTransaction", + Self::AuthenticatorStateUpdate(_) => "AuthenticatorStateUpdate", + Self::RandomnessStateUpdate(_) => "RandomnessStateUpdate", + Self::EndOfEpochTransaction(_) => "EndOfEpochTransaction", + } + } +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct IotaChangeEpoch { + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub epoch: EpochId, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub storage_charge: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub computation_charge: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub storage_rebate: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub epoch_start_timestamp_ms: u64, +} + +impl From for IotaChangeEpoch { + fn from(e: ChangeEpoch) -> Self { + Self { + epoch: e.epoch, + storage_charge: e.storage_charge, + computation_charge: e.computation_charge, + storage_rebate: e.storage_rebate, + epoch_start_timestamp_ms: e.epoch_start_timestamp_ms, + } + } +} + +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, PartialEq, Eq)] +#[enum_dispatch(IotaTransactionBlockEffectsAPI)] +#[serde( + rename = "TransactionBlockEffects", + rename_all = "camelCase", + tag = "messageVersion" +)] +pub enum IotaTransactionBlockEffects { + V1(IotaTransactionBlockEffectsV1), +} + +#[enum_dispatch] +pub trait IotaTransactionBlockEffectsAPI { + fn status(&self) -> &IotaExecutionStatus; + fn into_status(self) -> IotaExecutionStatus; + fn shared_objects(&self) -> &[IotaObjectRef]; + fn created(&self) -> &[OwnedObjectRef]; + fn mutated(&self) -> &[OwnedObjectRef]; + fn unwrapped(&self) -> &[OwnedObjectRef]; + fn deleted(&self) -> &[IotaObjectRef]; + fn unwrapped_then_deleted(&self) -> &[IotaObjectRef]; + fn wrapped(&self) -> &[IotaObjectRef]; + fn gas_object(&self) -> &OwnedObjectRef; + fn events_digest(&self) -> Option<&TransactionEventsDigest>; + fn dependencies(&self) -> &[TransactionDigest]; + fn executed_epoch(&self) -> EpochId; + fn transaction_digest(&self) -> &TransactionDigest; + fn gas_cost_summary(&self) -> &GasCostSummary; + + /// Return an iterator of mutated objects, but excluding the gas object. + fn mutated_excluding_gas(&self) -> Vec; + fn modified_at_versions(&self) -> Vec<(ObjectID, SequenceNumber)>; + fn all_changed_objects(&self) -> Vec<(&OwnedObjectRef, WriteKind)>; + fn all_deleted_objects(&self) -> Vec<(&IotaObjectRef, DeleteKind)>; +} + +#[serde_as] +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[serde( + rename = "TransactionBlockEffectsModifiedAtVersions", + rename_all = "camelCase" +)] +pub struct IotaTransactionBlockEffectsModifiedAtVersions { + object_id: ObjectID, + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + sequence_number: SequenceNumber, +} + +/// The response from processing a transaction or a certified transaction +#[serde_as] +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[serde(rename = "TransactionBlockEffectsV1", rename_all = "camelCase")] +pub struct IotaTransactionBlockEffectsV1 { + /// The status of the execution + pub status: IotaExecutionStatus, + /// The epoch when this transaction was executed. + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub executed_epoch: EpochId, + pub gas_used: GasCostSummary, + /// The version that every modified (mutated or deleted) object had before + /// it was modified by this transaction. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub modified_at_versions: Vec, + /// The object references of the shared objects used in this transaction. + /// Empty if no shared objects were used. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub shared_objects: Vec, + /// The transaction digest + pub transaction_digest: TransactionDigest, + /// ObjectRef and owner of new objects created. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub created: Vec, + /// ObjectRef and owner of mutated objects, including gas object. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub mutated: Vec, + /// ObjectRef and owner of objects that are unwrapped in this transaction. + /// Unwrapped objects are objects that were wrapped into other objects in + /// the past, and just got extracted out. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub unwrapped: Vec, + /// Object Refs of objects now deleted (the old refs). + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub deleted: Vec, + /// Object refs of objects previously wrapped in other objects but now + /// deleted. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub unwrapped_then_deleted: Vec, + /// Object refs of objects now wrapped in other objects. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub wrapped: Vec, + /// The updated gas object reference. Have a dedicated field for convenient + /// access. It's also included in mutated. + pub gas_object: OwnedObjectRef, + /// The digest of the events emitted during execution, + /// can be None if the transaction does not emit any event. + #[serde(skip_serializing_if = "Option::is_none")] + pub events_digest: Option, + /// The set of transaction digests this transaction depends on. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub dependencies: Vec, +} + +impl IotaTransactionBlockEffectsAPI for IotaTransactionBlockEffectsV1 { + fn status(&self) -> &IotaExecutionStatus { + &self.status + } + fn into_status(self) -> IotaExecutionStatus { + self.status + } + fn shared_objects(&self) -> &[IotaObjectRef] { + &self.shared_objects + } + fn created(&self) -> &[OwnedObjectRef] { + &self.created + } + fn mutated(&self) -> &[OwnedObjectRef] { + &self.mutated + } + fn unwrapped(&self) -> &[OwnedObjectRef] { + &self.unwrapped + } + fn deleted(&self) -> &[IotaObjectRef] { + &self.deleted + } + fn unwrapped_then_deleted(&self) -> &[IotaObjectRef] { + &self.unwrapped_then_deleted + } + fn wrapped(&self) -> &[IotaObjectRef] { + &self.wrapped + } + fn gas_object(&self) -> &OwnedObjectRef { + &self.gas_object + } + fn events_digest(&self) -> Option<&TransactionEventsDigest> { + self.events_digest.as_ref() + } + fn dependencies(&self) -> &[TransactionDigest] { + &self.dependencies + } + + fn executed_epoch(&self) -> EpochId { + self.executed_epoch + } + + fn transaction_digest(&self) -> &TransactionDigest { + &self.transaction_digest + } + + fn gas_cost_summary(&self) -> &GasCostSummary { + &self.gas_used + } + + fn mutated_excluding_gas(&self) -> Vec { + self.mutated + .iter() + .filter(|o| *o != &self.gas_object) + .cloned() + .collect() + } + + fn modified_at_versions(&self) -> Vec<(ObjectID, SequenceNumber)> { + self.modified_at_versions + .iter() + .map(|v| (v.object_id, v.sequence_number)) + .collect::>() + } + + fn all_changed_objects(&self) -> Vec<(&OwnedObjectRef, WriteKind)> { + self.mutated + .iter() + .map(|owner_ref| (owner_ref, WriteKind::Mutate)) + .chain( + self.created + .iter() + .map(|owner_ref| (owner_ref, WriteKind::Create)), + ) + .chain( + self.unwrapped + .iter() + .map(|owner_ref| (owner_ref, WriteKind::Unwrap)), + ) + .collect() + } + + fn all_deleted_objects(&self) -> Vec<(&IotaObjectRef, DeleteKind)> { + self.deleted + .iter() + .map(|r| (r, DeleteKind::Normal)) + .chain( + self.unwrapped_then_deleted + .iter() + .map(|r| (r, DeleteKind::UnwrapThenDelete)), + ) + .chain(self.wrapped.iter().map(|r| (r, DeleteKind::Wrap))) + .collect() + } +} + +impl IotaTransactionBlockEffects { + #[cfg(any(feature = "test-utils", test))] + pub fn new_for_testing( + transaction_digest: TransactionDigest, + status: IotaExecutionStatus, + ) -> Self { + Self::V1(IotaTransactionBlockEffectsV1 { + transaction_digest, + status, + gas_object: OwnedObjectRef { + owner: Owner::AddressOwner(IotaAddress::random_for_testing_only()), + reference: iota_types::base_types::random_object_ref().into(), + }, + executed_epoch: 0, + modified_at_versions: vec![], + gas_used: GasCostSummary::default(), + shared_objects: vec![], + created: vec![], + mutated: vec![], + unwrapped: vec![], + deleted: vec![], + unwrapped_then_deleted: vec![], + wrapped: vec![], + events_digest: None, + dependencies: vec![], + }) + } +} + +impl TryFrom for IotaTransactionBlockEffects { + type Error = IotaError; + + fn try_from(effect: TransactionEffects) -> Result { + Ok(IotaTransactionBlockEffects::V1( + IotaTransactionBlockEffectsV1 { + status: effect.status().clone().into(), + executed_epoch: effect.executed_epoch(), + modified_at_versions: effect + .modified_at_versions() + .into_iter() + .map(|(object_id, sequence_number)| { + IotaTransactionBlockEffectsModifiedAtVersions { + object_id, + sequence_number, + } + }) + .collect(), + gas_used: effect.gas_cost_summary().clone(), + shared_objects: to_iota_object_ref( + effect + .input_shared_objects() + .into_iter() + .map(|kind| kind.object_ref()) + .collect(), + ), + transaction_digest: *effect.transaction_digest(), + created: to_owned_ref(effect.created()), + mutated: to_owned_ref(effect.mutated().to_vec()), + unwrapped: to_owned_ref(effect.unwrapped().to_vec()), + deleted: to_iota_object_ref(effect.deleted().to_vec()), + unwrapped_then_deleted: to_iota_object_ref( + effect.unwrapped_then_deleted().to_vec(), + ), + wrapped: to_iota_object_ref(effect.wrapped().to_vec()), + gas_object: OwnedObjectRef { + owner: effect.gas_object().1, + reference: effect.gas_object().0.into(), + }, + events_digest: effect.events_digest().copied(), + dependencies: effect.dependencies().to_vec(), + }, + )) + } +} + +fn owned_objref_string(obj: &OwnedObjectRef) -> String { + format!( + " ┌──\n │ ID: {} \n │ Owner: {} \n │ Version: {} \n │ Digest: {}\n └──", + obj.reference.object_id, + obj.owner, + u64::from(obj.reference.version), + obj.reference.digest + ) +} + +fn objref_string(obj: &IotaObjectRef) -> String { + format!( + " ┌──\n │ ID: {} \n │ Version: {} \n │ Digest: {}\n └──", + obj.object_id, + u64::from(obj.version), + obj.digest + ) +} + +impl Display for IotaTransactionBlockEffects { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let mut builder = TableBuilder::default(); + + builder.push_record(vec![format!("Digest: {}", self.transaction_digest())]); + builder.push_record(vec![format!("Status: {:?}", self.status())]); + builder.push_record(vec![format!("Executed Epoch: {}", self.executed_epoch())]); + + if !self.created().is_empty() { + builder.push_record(vec![format!("\nCreated Objects: ")]); + + for oref in self.created() { + builder.push_record(vec![owned_objref_string(oref)]); + } + } + + if !self.mutated().is_empty() { + builder.push_record(vec![format!("Mutated Objects: ")]); + for oref in self.mutated() { + builder.push_record(vec![owned_objref_string(oref)]); + } + } + + if !self.shared_objects().is_empty() { + builder.push_record(vec![format!("Shared Objects: ")]); + for oref in self.shared_objects() { + builder.push_record(vec![objref_string(oref)]); + } + } + + if !self.deleted().is_empty() { + builder.push_record(vec![format!("Deleted Objects: ")]); + + for oref in self.deleted() { + builder.push_record(vec![objref_string(oref)]); + } + } + + if !self.wrapped().is_empty() { + builder.push_record(vec![format!("Wrapped Objects: ")]); + + for oref in self.wrapped() { + builder.push_record(vec![objref_string(oref)]); + } + } + + if !self.unwrapped().is_empty() { + builder.push_record(vec![format!("Unwrapped Objects: ")]); + for oref in self.unwrapped() { + builder.push_record(vec![owned_objref_string(oref)]); + } + } + + builder.push_record(vec![format!( + "Gas Object: \n{}", + owned_objref_string(self.gas_object()) + )]); + + let gas_cost_summary = self.gas_cost_summary(); + builder.push_record(vec![format!( + "Gas Cost Summary:\n \ + Storage Cost: {} MICROS\n \ + Computation Cost: {} MICROS\n \ + Storage Rebate: {} MICROS\n \ + Non-refundable Storage Fee: {} MICROS", + gas_cost_summary.storage_cost, + gas_cost_summary.computation_cost, + gas_cost_summary.storage_rebate, + gas_cost_summary.non_refundable_storage_fee, + )]); + + let dependencies = self.dependencies(); + if !dependencies.is_empty() { + builder.push_record(vec![format!("\nTransaction Dependencies:")]); + for dependency in dependencies { + builder.push_record(vec![format!(" {}", dependency)]); + } + } + + let mut table = builder.build(); + table.with(TablePanel::header("Transaction Effects")); + table.with(TableStyle::rounded().horizontals([HorizontalLine::new( + 1, + TableStyle::modern().get_horizontal(), + )])); + write!(f, "{}", table) + } +} + +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct DryRunTransactionBlockResponse { + pub effects: IotaTransactionBlockEffects, + pub events: IotaTransactionBlockEvents, + pub object_changes: Vec, + pub balance_changes: Vec, + pub input: IotaTransactionBlockData, +} + +#[derive(Eq, PartialEq, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] +#[serde(rename = "TransactionBlockEvents", transparent)] +pub struct IotaTransactionBlockEvents { + pub data: Vec, +} + +impl IotaTransactionBlockEvents { + pub fn try_from( + events: TransactionEvents, + tx_digest: TransactionDigest, + timestamp_ms: Option, + resolver: &mut dyn LayoutResolver, + ) -> IotaResult { + Ok(Self { + data: events + .data + .into_iter() + .enumerate() + .map(|(seq, event)| { + let layout = resolver.get_annotated_layout(&event.type_)?; + IotaEvent::try_from(event, tx_digest, seq as u64, timestamp_ms, layout) + }) + .collect::>()?, + }) + } + + // TODO: this is only called from the indexer. Remove this once indexer moves to + // its own resolver. + pub fn try_from_using_module_resolver( + events: TransactionEvents, + tx_digest: TransactionDigest, + timestamp_ms: Option, + resolver: &impl GetModule, + ) -> IotaResult { + Ok(Self { + data: events + .data + .into_iter() + .enumerate() + .map(|(seq, event)| { + let layout = + MoveObject::get_layout_from_struct_tag(event.type_.clone(), resolver)?; + IotaEvent::try_from(event, tx_digest, seq as u64, timestamp_ms, layout) + }) + .collect::>()?, + }) + } +} + +impl Display for IotaTransactionBlockEvents { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if self.data.is_empty() { + writeln!(f, "╭─────────────────────────────╮")?; + writeln!(f, "│ No transaction block events │")?; + writeln!(f, "╰─────────────────────────────╯") + } else { + let mut builder = TableBuilder::default(); + + for event in &self.data { + builder.push_record(vec![format!("{}", event)]); + } + + let mut table = builder.build(); + table.with(TablePanel::header("Transaction Block Events")); + table.with(TableStyle::rounded().horizontals([HorizontalLine::new( + 1, + TableStyle::modern().get_horizontal(), + )])); + write!(f, "{}", table) + } + } +} + +// TODO: this file might not be the best place for this struct. +/// Additional rguments supplied to dev inspect beyond what is allowed in +/// today's API. +#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(rename = "DevInspectArgs", rename_all = "camelCase")] +pub struct DevInspectArgs { + /// The sponsor of the gas for the transaction, might be different from the + /// sender. + pub gas_sponsor: Option, + /// The gas budget for the transaction. + pub gas_budget: Option>, + /// The gas objects used to pay for the transaction. + pub gas_objects: Option>, + /// Whether to skip transaction checks for the transaction. + pub skip_checks: Option, + /// Whether to return the raw transaction data and effects. + pub show_raw_txn_data_and_effects: Option, +} + +/// The response from processing a dev inspect transaction +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(rename = "DevInspectResults", rename_all = "camelCase")] +pub struct DevInspectResults { + /// Summary of effects that likely would be generated if the transaction is + /// actually run. Note however, that not all dev-inspect transactions + /// are actually usable as transactions so it might not be possible + /// actually generate these effects from a normal transaction. + pub effects: IotaTransactionBlockEffects, + /// Events that likely would be generated if the transaction is actually + /// run. + pub events: IotaTransactionBlockEvents, + /// Execution results (including return values) from executing the + /// transactions + #[serde(skip_serializing_if = "Option::is_none")] + pub results: Option>, + /// Execution error from executing the transactions + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, + /// The raw transaction data that was dev inspected. + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub raw_txn_data: Vec, + /// The raw effects of the transaction that was dev inspected. + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub raw_effects: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(rename = "IotaExecutionResult", rename_all = "camelCase")] +pub struct IotaExecutionResult { + /// The value of any arguments that were mutably borrowed. + /// Non-mut borrowed values are not included + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub mutable_reference_outputs: Vec<(/* argument */ IotaArgument, Vec, IotaTypeTag)>, + /// The return values from the transaction + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub return_values: Vec<(Vec, IotaTypeTag)>, +} + +type ExecutionResult = ( + // mutable_reference_outputs + Vec<(Argument, Vec, TypeTag)>, + // return_values + Vec<(Vec, TypeTag)>, +); + +impl DevInspectResults { + pub fn new( + effects: TransactionEffects, + events: TransactionEvents, + return_values: Result, ExecutionError>, + raw_txn_data: Vec, + raw_effects: Vec, + resolver: &mut dyn LayoutResolver, + ) -> IotaResult { + let tx_digest = *effects.transaction_digest(); + let mut error = None; + let mut results = None; + match return_values { + Err(e) => error = Some(e.to_string()), + Ok(srvs) => { + results = Some( + srvs.into_iter() + .map(|srv| { + let (mutable_reference_outputs, return_values) = srv; + let mutable_reference_outputs = mutable_reference_outputs + .into_iter() + .map(|(a, bytes, tag)| (a.into(), bytes, IotaTypeTag::from(tag))) + .collect(); + let return_values = return_values + .into_iter() + .map(|(bytes, tag)| (bytes, IotaTypeTag::from(tag))) + .collect(); + IotaExecutionResult { + mutable_reference_outputs, + return_values, + } + }) + .collect(), + ) + } + }; + Ok(Self { + effects: effects.try_into()?, + events: IotaTransactionBlockEvents::try_from(events, tx_digest, None, resolver)?, + results, + error, + raw_txn_data, + raw_effects, + }) + } +} + +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub enum IotaTransactionBlockBuilderMode { + /// Regular Iota Transactions that are committed on chain + Commit, + /// Simulated transaction that allows calling any Move function with + /// arbitrary values. + DevInspect, +} + +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[serde(rename = "ExecutionStatus", rename_all = "camelCase", tag = "status")] +pub enum IotaExecutionStatus { + // Gas used in the success case. + Success, + // Gas used in the failed case, and the error. + Failure { error: String }, +} + +impl IotaExecutionStatus { + pub fn is_ok(&self) -> bool { + matches!(self, IotaExecutionStatus::Success { .. }) + } + pub fn is_err(&self) -> bool { + matches!(self, IotaExecutionStatus::Failure { .. }) + } +} + +impl From for IotaExecutionStatus { + fn from(status: ExecutionStatus) -> Self { + match status { + ExecutionStatus::Success => Self::Success, + ExecutionStatus::Failure { + error, + command: None, + } => Self::Failure { + error: format!("{error:?}"), + }, + ExecutionStatus::Failure { + error, + command: Some(idx), + } => Self::Failure { + error: format!("{error:?} in command {idx}"), + }, + } + } +} + +fn to_iota_object_ref(refs: Vec) -> Vec { + refs.into_iter().map(IotaObjectRef::from).collect() +} + +fn to_owned_ref(owned_refs: Vec<(ObjectRef, Owner)>) -> Vec { + owned_refs + .into_iter() + .map(|(oref, owner)| OwnedObjectRef { + owner, + reference: oref.into(), + }) + .collect() +} + +#[serde_as] +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, PartialEq, Eq)] +#[serde(rename = "GasData", rename_all = "camelCase")] +pub struct IotaGasData { + pub payment: Vec, + pub owner: IotaAddress, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub price: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub budget: u64, +} + +impl Display for IotaGasData { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + writeln!(f, "Gas Owner: {}", self.owner)?; + writeln!(f, "Gas Budget: {} MICROS", self.budget)?; + writeln!(f, "Gas Price: {} MICROS", self.price)?; + writeln!(f, "Gas Payment:")?; + for payment in &self.payment { + write!(f, "{} ", objref_string(payment))?; + } + writeln!(f) + } +} + +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, PartialEq, Eq)] +#[enum_dispatch(IotaTransactionBlockDataAPI)] +#[serde( + rename = "TransactionBlockData", + rename_all = "camelCase", + tag = "messageVersion" +)] +pub enum IotaTransactionBlockData { + V1(IotaTransactionBlockDataV1), +} + +#[enum_dispatch] +pub trait IotaTransactionBlockDataAPI { + fn transaction(&self) -> &IotaTransactionBlockKind; + fn sender(&self) -> &IotaAddress; + fn gas_data(&self) -> &IotaGasData; +} + +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, PartialEq, Eq)] +#[serde(rename = "TransactionBlockDataV1", rename_all = "camelCase")] +pub struct IotaTransactionBlockDataV1 { + pub transaction: IotaTransactionBlockKind, + pub sender: IotaAddress, + pub gas_data: IotaGasData, +} + +impl IotaTransactionBlockDataAPI for IotaTransactionBlockDataV1 { + fn transaction(&self) -> &IotaTransactionBlockKind { + &self.transaction + } + fn sender(&self) -> &IotaAddress { + &self.sender + } + fn gas_data(&self) -> &IotaGasData { + &self.gas_data + } +} + +impl IotaTransactionBlockData { + pub fn move_calls(&self) -> Vec<&IotaProgrammableMoveCall> { + match self { + Self::V1(data) => match &data.transaction { + IotaTransactionBlockKind::ProgrammableTransaction(pt) => pt + .commands + .iter() + .filter_map(|command| match command { + IotaCommand::MoveCall(c) => Some(&**c), + _ => None, + }) + .collect(), + _ => vec![], + }, + } + } +} + +impl Display for IotaTransactionBlockData { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::V1(data) => { + writeln!(f, "Sender: {}", data.sender)?; + writeln!(f, "{}", self.gas_data())?; + writeln!(f, "{}", data.transaction) + } + } + } +} + +impl IotaTransactionBlockData { + pub fn try_from( + data: TransactionData, + module_cache: &impl GetModule, + ) -> Result { + let message_version = data + .message_version() + .expect("TransactionData defines message_version()"); + let sender = data.sender(); + let gas_data = IotaGasData { + payment: data + .gas() + .iter() + .map(|obj_ref| IotaObjectRef::from(*obj_ref)) + .collect(), + owner: data.gas_owner(), + price: data.gas_price(), + budget: data.gas_budget(), + }; + let transaction = IotaTransactionBlockKind::try_from(data.into_kind(), module_cache)?; + match message_version { + 1 => Ok(IotaTransactionBlockData::V1(IotaTransactionBlockDataV1 { + transaction, + sender, + gas_data, + })), + _ => Err(anyhow::anyhow!( + "Support for TransactionData version {} not implemented", + message_version + )), + } + } +} + +#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, PartialEq, Eq)] +#[serde(rename = "TransactionBlock", rename_all = "camelCase")] +pub struct IotaTransactionBlock { + pub data: IotaTransactionBlockData, + pub tx_signatures: Vec, +} + +impl IotaTransactionBlock { + pub fn try_from( + data: SenderSignedData, + module_cache: &impl GetModule, + ) -> Result { + Ok(Self { + data: IotaTransactionBlockData::try_from( + data.intent_message().value.clone(), + module_cache, + )?, + tx_signatures: data.tx_signatures().to_vec(), + }) + } +} + +impl Display for IotaTransactionBlock { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let mut builder = TableBuilder::default(); + + builder.push_record(vec![format!("{}", self.data)]); + builder.push_record(vec![format!("Signatures:")]); + for tx_sig in &self.tx_signatures { + builder.push_record(vec![format!( + " {}\n", + match tx_sig { + Signature(sig) => Base64::from_bytes(sig.signature_bytes()).encoded(), + _ => Base64::from_bytes(tx_sig.as_ref()).encoded(), /* the signatures for + * multisig and zklogin + * are not iotated to be + * parsed out. they + * should be interpreted + * as a whole */ + } + )]); + } + + let mut table = builder.build(); + table.with(TablePanel::header("Transaction Data")); + table.with(TableStyle::rounded().horizontals([HorizontalLine::new( + 1, + TableStyle::modern().get_horizontal(), + )])); + write!(f, "{}", table) + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct IotaGenesisTransaction { + pub objects: Vec, +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct IotaConsensusCommitPrologue { + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub epoch: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub round: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub commit_timestamp_ms: u64, +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct IotaConsensusCommitPrologueV2 { + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub epoch: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub round: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub commit_timestamp_ms: u64, + pub consensus_commit_digest: ConsensusCommitDigest, +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct IotaAuthenticatorStateUpdate { + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub epoch: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub round: u64, + + pub new_active_jwks: Vec, +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct IotaRandomnessStateUpdate { + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub epoch: u64, + + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub randomness_round: u64, + pub random_bytes: Vec, +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct IotaEndOfEpochTransaction { + pub transactions: Vec, +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub enum IotaEndOfEpochTransactionKind { + ChangeEpoch(IotaChangeEpoch), + AuthenticatorStateCreate, + AuthenticatorStateExpire(IotaAuthenticatorStateExpire), + RandomnessStateCreate, + CoinDenyListStateCreate, +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct IotaAuthenticatorStateExpire { + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub min_epoch: u64, +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct IotaActiveJwk { + pub jwk_id: IotaJwkId, + pub jwk: IotaJWK, + + #[schemars(with = "BigInt")] + #[serde_as(as = "BigInt")] + pub epoch: u64, +} + +impl From for IotaActiveJwk { + fn from(active_jwk: ActiveJwk) -> Self { + Self { + jwk_id: IotaJwkId { + iss: active_jwk.jwk_id.iss.clone(), + kid: active_jwk.jwk_id.kid.clone(), + }, + jwk: IotaJWK { + kty: active_jwk.jwk.kty.clone(), + e: active_jwk.jwk.e.clone(), + n: active_jwk.jwk.n.clone(), + alg: active_jwk.jwk.alg.clone(), + }, + epoch: active_jwk.epoch, + } + } +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct IotaJwkId { + pub iss: String, + pub kid: String, +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct IotaJWK { + pub kty: String, + pub e: String, + pub n: String, + pub alg: String, +} + +#[serde_as] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(rename = "InputObjectKind")] +pub enum IotaInputObjectKind { + // A Move package, must be immutable. + MovePackage(ObjectID), + // A Move object, either immutable, or owned mutable. + ImmOrOwnedMoveObject(IotaObjectRef), + // A Move object that's shared and mutable. + SharedMoveObject { + id: ObjectID, + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + initial_shared_version: SequenceNumber, + #[serde(default = "default_shared_object_mutability")] + mutable: bool, + }, +} + +/// A series of commands where the results of one command can be used in future +/// commands +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct IotaProgrammableTransactionBlock { + /// Input objects or primitive values + pub inputs: Vec, + #[serde(rename = "transactions")] + /// The transactions to be executed sequentially. A failure in any + /// transaction will result in the failure of the entire programmable + /// transaction block. + pub commands: Vec, +} + +impl Display for IotaProgrammableTransactionBlock { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let Self { inputs, commands } = self; + writeln!(f, "Inputs: {inputs:?}")?; + writeln!(f, "Commands: [")?; + for c in commands { + writeln!(f, " {c},")?; + } + writeln!(f, "]") + } +} + +impl IotaProgrammableTransactionBlock { + fn try_from( + value: ProgrammableTransaction, + module_cache: &impl GetModule, + ) -> Result { + let ProgrammableTransaction { inputs, commands } = value; + let input_types = Self::resolve_input_type(&inputs, &commands, module_cache); + Ok(IotaProgrammableTransactionBlock { + inputs: inputs + .into_iter() + .zip(input_types) + .map(|(arg, layout)| IotaCallArg::try_from(arg, layout.as_ref())) + .collect::>()?, + commands: commands.into_iter().map(IotaCommand::from).collect(), + }) + } + + fn resolve_input_type( + inputs: &Vec, + commands: &[Command], + module_cache: &impl GetModule, + ) -> Vec> { + let mut result_types = vec![None; inputs.len()]; + for command in commands.iter() { + match command { + Command::MoveCall(c) => { + let id = ModuleId::new(c.package.into(), c.module.clone()); + let Some(types) = + get_signature_types(id, c.function.as_ident_str(), module_cache) + else { + return result_types; + }; + for (arg, type_) in c.arguments.iter().zip(types) { + if let (&Argument::Input(i), Some(type_)) = (arg, type_) { + if let Some(x) = result_types.get_mut(i as usize) { + x.replace(type_); + } + } + } + } + Command::SplitCoins(_, amounts) => { + for arg in amounts { + if let &Argument::Input(i) = arg { + if let Some(x) = result_types.get_mut(i as usize) { + x.replace(MoveTypeLayout::U64); + } + } + } + } + Command::TransferObjects(_, Argument::Input(i)) => { + if let Some(x) = result_types.get_mut((*i) as usize) { + x.replace(MoveTypeLayout::Address); + } + } + _ => {} + } + } + result_types + } +} + +fn get_signature_types( + id: ModuleId, + function: &IdentStr, + module_cache: &impl GetModule, +) -> Option>> { + use std::borrow::Borrow; + if let Ok(Some(module)) = module_cache.get_module_by_id(&id) { + let module: &CompiledModule = module.borrow(); + let view = BinaryIndexedView::Module(module); + let func = module + .function_handles + .iter() + .find(|f| module.identifier_at(f.name) == function)?; + Some( + module + .signature_at(func.parameters) + .0 + .iter() + .map(|s| primitive_type(&view, &[], s).1) + .collect(), + ) + } else { + None + } +} + +/// A single transaction in a programmable transaction block. +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename = "IotaTransaction")] +pub enum IotaCommand { + /// A call to either an entry or a public Move function + MoveCall(Box), + /// `(Vec, address)` + /// It sends n-objects to the specified address. These objects must have + /// store (public transfer) and either the previous owner must be an + /// address or the object must be newly created. + TransferObjects(Vec, IotaArgument), + /// `(&mut Coin, Vec)` -> `Vec>` + /// It splits off some amounts into a new coins with those amounts + SplitCoins(IotaArgument, Vec), + /// `(&mut Coin, Vec>)` + /// It merges n-coins into the first coin + MergeCoins(IotaArgument, Vec), + /// Publishes a Move package. It takes the package bytes and a list of the + /// package's transitive dependencies to link against on-chain. + Publish(Vec), + /// Upgrades a Move package + Upgrade(Vec, ObjectID, IotaArgument), + /// `forall T: Vec -> vector` + /// Given n-values of the same type, it constructs a vector. For non objects + /// or an empty vector, the type tag must be specified. + MakeMoveVec(Option, Vec), +} + +impl Display for IotaCommand { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::MoveCall(p) => { + write!(f, "MoveCall({p})") + } + Self::MakeMoveVec(ty_opt, elems) => { + write!(f, "MakeMoveVec(")?; + if let Some(ty) = ty_opt { + write!(f, "Some{ty}")?; + } else { + write!(f, "None")?; + } + write!(f, ",[")?; + write_sep(f, elems, ",")?; + write!(f, "])") + } + Self::TransferObjects(objs, addr) => { + write!(f, "TransferObjects([")?; + write_sep(f, objs, ",")?; + write!(f, "],{addr})") + } + Self::SplitCoins(coin, amounts) => { + write!(f, "SplitCoins({coin},")?; + write_sep(f, amounts, ",")?; + write!(f, ")") + } + Self::MergeCoins(target, coins) => { + write!(f, "MergeCoins({target},")?; + write_sep(f, coins, ",")?; + write!(f, ")") + } + Self::Publish(deps) => { + write!(f, "Publish(,")?; + write_sep(f, deps, ",")?; + write!(f, ")") + } + Self::Upgrade(deps, current_package_id, ticket) => { + write!(f, "Upgrade(, {ticket},")?; + write_sep(f, deps, ",")?; + write!(f, ", {current_package_id}")?; + write!(f, ")") + } + } + } +} + +impl From for IotaCommand { + fn from(value: Command) -> Self { + match value { + Command::MoveCall(m) => IotaCommand::MoveCall(Box::new((*m).into())), + Command::TransferObjects(args, arg) => IotaCommand::TransferObjects( + args.into_iter().map(IotaArgument::from).collect(), + arg.into(), + ), + Command::SplitCoins(arg, args) => IotaCommand::SplitCoins( + arg.into(), + args.into_iter().map(IotaArgument::from).collect(), + ), + Command::MergeCoins(arg, args) => IotaCommand::MergeCoins( + arg.into(), + args.into_iter().map(IotaArgument::from).collect(), + ), + Command::Publish(_modules, dep_ids) => IotaCommand::Publish(dep_ids), + Command::MakeMoveVec(tag_opt, args) => IotaCommand::MakeMoveVec( + tag_opt.map(|tag| tag.to_string()), + args.into_iter().map(IotaArgument::from).collect(), + ), + Command::Upgrade(_modules, dep_ids, current_package_id, ticket) => { + IotaCommand::Upgrade(dep_ids, current_package_id, IotaArgument::from(ticket)) + } + } + } +} + +/// An argument to a transaction in a programmable transaction block +#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub enum IotaArgument { + /// The gas coin. The gas coin can only be used by-ref, except for with + /// `TransferObjects`, which can use it by-value. + GasCoin, + /// One of the input objects or primitive values (from + /// `ProgrammableTransactionBlock` inputs) + Input(u16), + /// The result of another transaction (from `ProgrammableTransactionBlock` + /// transactions) + Result(u16), + /// Like a `Result` but it accesses a nested result. Currently, the only + /// usage of this is to access a value from a Move call with multiple + /// return values. + NestedResult(u16, u16), +} + +impl Display for IotaArgument { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::GasCoin => write!(f, "GasCoin"), + Self::Input(i) => write!(f, "Input({i})"), + Self::Result(i) => write!(f, "Result({i})"), + Self::NestedResult(i, j) => write!(f, "NestedResult({i},{j})"), + } + } +} + +impl From for IotaArgument { + fn from(value: Argument) -> Self { + match value { + Argument::GasCoin => Self::GasCoin, + Argument::Input(i) => Self::Input(i), + Argument::Result(i) => Self::Result(i), + Argument::NestedResult(i, j) => Self::NestedResult(i, j), + } + } +} + +/// The transaction for calling a Move function, either an entry function or a +/// public function (which cannot return references). +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct IotaProgrammableMoveCall { + /// The package containing the module and function. + pub package: ObjectID, + /// The specific module in the package containing the function. + pub module: String, + /// The function to be called. + pub function: String, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + /// The type arguments to the function. + pub type_arguments: Vec, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + /// The arguments to the function. + pub arguments: Vec, +} + +fn write_sep( + f: &mut Formatter<'_>, + items: impl IntoIterator, + sep: &str, +) -> std::fmt::Result { + let mut xs = items.into_iter().peekable(); + while let Some(x) = xs.next() { + write!(f, "{x}")?; + if xs.peek().is_some() { + write!(f, "{sep}")?; + } + } + Ok(()) +} + +impl Display for IotaProgrammableMoveCall { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let Self { + package, + module, + function, + type_arguments, + arguments, + } = self; + write!(f, "{package}::{module}::{function}")?; + if !type_arguments.is_empty() { + write!(f, "<")?; + write_sep(f, type_arguments, ",")?; + write!(f, ">")?; + } + write!(f, "(")?; + write_sep(f, arguments, ",")?; + write!(f, ")") + } +} + +impl From for IotaProgrammableMoveCall { + fn from(value: ProgrammableMoveCall) -> Self { + let ProgrammableMoveCall { + package, + module, + function, + type_arguments, + arguments, + } = value; + Self { + package, + module: module.to_string(), + function: function.to_string(), + type_arguments: type_arguments.into_iter().map(|t| t.to_string()).collect(), + arguments: arguments.into_iter().map(IotaArgument::from).collect(), + } + } +} + +const fn default_shared_object_mutability() -> bool { + true +} + +impl From for IotaInputObjectKind { + fn from(input: InputObjectKind) -> Self { + match input { + InputObjectKind::MovePackage(id) => Self::MovePackage(id), + InputObjectKind::ImmOrOwnedMoveObject(oref) => Self::ImmOrOwnedMoveObject(oref.into()), + InputObjectKind::SharedMoveObject { + id, + initial_shared_version, + mutable, + } => Self::SharedMoveObject { + id, + initial_shared_version, + mutable, + }, + } + } +} + +#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone)] +#[serde(rename = "TypeTag", rename_all = "camelCase")] +pub struct IotaTypeTag(String); + +impl IotaTypeTag { + pub fn new(tag: String) -> Self { + Self(tag) + } +} + +impl TryInto for IotaTypeTag { + type Error = anyhow::Error; + fn try_into(self) -> Result { + parse_iota_type_tag(&self.0) + } +} + +impl From for IotaTypeTag { + fn from(tag: TypeTag) -> Self { + Self(format!("{}", tag)) + } +} + +#[derive(Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub enum RPCTransactionRequestParams { + TransferObjectRequestParams(TransferObjectParams), + MoveCallRequestParams(MoveCallParams), +} + +#[derive(Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct TransferObjectParams { + pub recipient: IotaAddress, + pub object_id: ObjectID, +} + +#[derive(Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct MoveCallParams { + pub package_object_id: ObjectID, + pub module: String, + pub function: String, + #[serde(default)] + pub type_arguments: Vec, + pub arguments: Vec, +} + +#[serde_as] +#[derive(Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct TransactionBlockBytes { + /// BCS serialized transaction data bytes without its type tag, as base-64 + /// encoded string. + pub tx_bytes: Base64, + /// the gas objects to be used + pub gas: Vec, + /// objects to be used in this transaction + pub input_objects: Vec, +} + +impl TransactionBlockBytes { + pub fn from_data(data: TransactionData) -> Result { + Ok(Self { + tx_bytes: Base64::from_bytes(bcs::to_bytes(&data)?.as_slice()), + gas: data + .gas() + .iter() + .map(|obj_ref| IotaObjectRef::from(*obj_ref)) + .collect(), + input_objects: data + .input_objects()? + .into_iter() + .map(IotaInputObjectKind::from) + .collect(), + }) + } + + pub fn to_data(self) -> Result { + bcs::from_bytes::(&self.tx_bytes.to_vec().map_err(|e| anyhow::anyhow!(e))?) + .map_err(|e| anyhow::anyhow!(e)) + } +} + +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[serde(rename = "OwnedObjectRef")] +pub struct OwnedObjectRef { + pub owner: Owner, + pub reference: IotaObjectRef, +} + +impl OwnedObjectRef { + pub fn object_id(&self) -> ObjectID { + self.reference.object_id + } + pub fn version(&self) -> SequenceNumber { + self.reference.version + } +} + +#[derive(Eq, PartialEq, Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(tag = "type", rename_all = "camelCase")] +pub enum IotaCallArg { + // Needs to become an Object Ref or Object ID, depending on object type + Object(IotaObjectArg), + // pure value, bcs encoded + Pure(IotaPureValue), +} + +impl IotaCallArg { + pub fn try_from( + value: CallArg, + layout: Option<&MoveTypeLayout>, + ) -> Result { + Ok(match value { + CallArg::Pure(p) => IotaCallArg::Pure(IotaPureValue { + value_type: layout.map(|l| l.into()), + value: IotaJsonValue::from_bcs_bytes(layout, &p)?, + }), + CallArg::Object(ObjectArg::ImmOrOwnedObject((id, version, digest))) => { + IotaCallArg::Object(IotaObjectArg::ImmOrOwnedObject { + object_id: id, + version, + digest, + }) + } + CallArg::Object(ObjectArg::SharedObject { + id, + initial_shared_version, + mutable, + }) => IotaCallArg::Object(IotaObjectArg::SharedObject { + object_id: id, + initial_shared_version, + mutable, + }), + CallArg::Object(ObjectArg::Receiving((object_id, version, digest))) => { + IotaCallArg::Object(IotaObjectArg::Receiving { + object_id, + version, + digest, + }) + } + }) + } + + pub fn pure(&self) -> Option<&IotaJsonValue> { + match self { + IotaCallArg::Pure(v) => Some(&v.value), + _ => None, + } + } + + pub fn object(&self) -> Option<&ObjectID> { + match self { + IotaCallArg::Object(IotaObjectArg::SharedObject { object_id, .. }) + | IotaCallArg::Object(IotaObjectArg::ImmOrOwnedObject { object_id, .. }) + | IotaCallArg::Object(IotaObjectArg::Receiving { object_id, .. }) => Some(object_id), + _ => None, + } + } +} + +#[serde_as] +#[derive(Eq, PartialEq, Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct IotaPureValue { + #[schemars(with = "Option")] + #[serde_as(as = "Option")] + value_type: Option, + value: IotaJsonValue, +} + +impl IotaPureValue { + pub fn value(&self) -> IotaJsonValue { + self.value.clone() + } + + pub fn value_type(&self) -> Option { + self.value_type.clone() + } +} + +#[serde_as] +#[derive(Eq, PartialEq, Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(tag = "objectType", rename_all = "camelCase")] +pub enum IotaObjectArg { + // A Move object, either immutable, or owned mutable. + #[serde(rename_all = "camelCase")] + ImmOrOwnedObject { + object_id: ObjectID, + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + version: SequenceNumber, + digest: ObjectDigest, + }, + // A Move object that's shared. + // SharedObject::mutable controls whether caller asks for a mutable reference to shared + // object. + #[serde(rename_all = "camelCase")] + SharedObject { + object_id: ObjectID, + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + initial_shared_version: SequenceNumber, + mutable: bool, + }, + // A reference to a Move object that's going to be received in the transaction. + #[serde(rename_all = "camelCase")] + Receiving { + object_id: ObjectID, + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + version: SequenceNumber, + digest: ObjectDigest, + }, +} + +#[serde_as] +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[serde(rename = "LoadedChildObject", rename_all = "camelCase")] +pub struct IotaLoadedChildObject { + object_id: ObjectID, + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + sequence_number: SequenceNumber, +} + +impl IotaLoadedChildObject { + pub fn new(object_id: ObjectID, sequence_number: SequenceNumber) -> Self { + Self { + object_id, + sequence_number, + } + } + + pub fn object_id(&self) -> ObjectID { + self.object_id + } + + pub fn sequence_number(&self) -> SequenceNumber { + self.sequence_number + } +} + +#[serde_as] +#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone, Default)] +#[serde(rename_all = "camelCase", rename = "LoadedChildObjectsResponse")] +pub struct IotaLoadedChildObjectsResponse { + pub loaded_child_objects: Vec, +} + +#[derive(Clone)] +pub struct EffectsWithInput { + pub effects: IotaTransactionBlockEffects, + pub input: TransactionData, +} + +impl From for IotaTransactionBlockEffects { + fn from(e: EffectsWithInput) -> Self { + e.effects + } +} + +#[serde_as] +#[derive(Clone, Debug, JsonSchema, Serialize, Deserialize)] +pub enum TransactionFilter { + /// Query by checkpoint. + Checkpoint( + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + CheckpointSequenceNumber, + ), + /// Query by move function. + MoveFunction { + package: ObjectID, + module: Option, + function: Option, + }, + /// Query by input object. + InputObject(ObjectID), + /// Query by changed object, including created, mutated and unwrapped + /// objects. + ChangedObject(ObjectID), + /// Query by sender address. + FromAddress(IotaAddress), + /// Query by recipient address. + ToAddress(IotaAddress), + /// Query by sender and recipient address. + FromAndToAddress { from: IotaAddress, to: IotaAddress }, + /// Query txs that have a given address as sender or recipient. + FromOrToAddress { addr: IotaAddress }, + /// Query by transaction kind + TransactionKind(String), + /// Query transactions of any given kind in the input. + TransactionKindIn(Vec), +} + +impl Filter for TransactionFilter { + fn matches(&self, item: &EffectsWithInput) -> bool { + let _scope = monitored_scope("TransactionFilter::matches"); + match self { + TransactionFilter::InputObject(o) => { + let Ok(input_objects) = item.input.input_objects() else { + return false; + }; + input_objects.iter().any(|object| object.object_id() == *o) + } + TransactionFilter::ChangedObject(o) => item + .effects + .mutated() + .iter() + .any(|oref: &OwnedObjectRef| &oref.reference.object_id == o), + TransactionFilter::FromAddress(a) => &item.input.sender() == a, + TransactionFilter::ToAddress(a) => { + let mutated: &[OwnedObjectRef] = item.effects.mutated(); + mutated.iter().chain(item.effects.unwrapped().iter()).any(|oref: &OwnedObjectRef| { + matches!(oref.owner, Owner::AddressOwner(owner) if owner == *a) + }) + } + TransactionFilter::FromAndToAddress { from, to } => { + Self::FromAddress(*from).matches(item) && Self::ToAddress(*to).matches(item) + } + TransactionFilter::MoveFunction { + package, + module, + function, + } => item.input.move_calls().into_iter().any(|(p, m, f)| { + p == package + && (module.is_none() || matches!(module, Some(m2) if m2 == &m.to_string())) + && (function.is_none() || matches!(function, Some(f2) if f2 == &f.to_string())) + }), + TransactionFilter::TransactionKind(kind) => item.input.kind().to_string() == *kind, + TransactionFilter::TransactionKindIn(kinds) => { + kinds.contains(&item.input.kind().to_string()) + } + // these filters are not supported, rpc will reject these filters on subscription + TransactionFilter::Checkpoint(_) => false, + TransactionFilter::FromOrToAddress { addr: _ } => false, + } + } +} diff --git a/crates/iota-json-rpc-types/src/lib.rs b/crates/iota-json-rpc-types/src/lib.rs new file mode 100644 index 00000000000..9a3fe557418 --- /dev/null +++ b/crates/iota-json-rpc-types/src/lib.rs @@ -0,0 +1,57 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub use balance_changes::*; +pub use iota_checkpoint::*; +pub use iota_coin::*; +pub use iota_event::*; +pub use iota_extended::*; +pub use iota_governance::*; +pub use iota_move::*; +pub use iota_object::*; +pub use iota_protocol::*; +pub use iota_transaction::*; +use iota_types::{base_types::ObjectID, dynamic_field::DynamicFieldInfo}; +pub use object_changes::*; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[cfg(test)] +#[path = "unit_tests/rpc_types_tests.rs"] +mod rpc_types_tests; + +mod balance_changes; +mod displays; +mod iota_checkpoint; +mod iota_coin; +mod iota_event; +mod iota_extended; +mod iota_governance; +mod iota_move; +mod iota_object; +mod iota_protocol; +mod iota_transaction; +mod object_changes; + +pub type DynamicFieldPage = Page; +/// `next_cursor` points to the last item in the page; +/// Reading with `next_cursor` will start from the next item after `next_cursor` +/// if `next_cursor` is `Some`, otherwise it will start from the first item. +#[derive(Clone, Debug, JsonSchema, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct Page { + pub data: Vec, + pub next_cursor: Option, + pub has_next_page: bool, +} + +impl Page { + pub fn empty() -> Self { + Self { + data: vec![], + next_cursor: None, + has_next_page: false, + } + } +} diff --git a/crates/iota-json-rpc-types/src/object_changes.rs b/crates/iota-json-rpc-types/src/object_changes.rs new file mode 100644 index 00000000000..6141c99b69d --- /dev/null +++ b/crates/iota-json-rpc-types/src/object_changes.rs @@ -0,0 +1,283 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt::{Display, Formatter, Result}; + +use iota_types::{ + base_types::{IotaAddress, ObjectDigest, ObjectID, ObjectRef, SequenceNumber}, + iota_serde::{IotaStructTag, SequenceNumber as AsSequenceNumber}, + object::Owner, +}; +use move_core_types::language_storage::StructTag; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +/// ObjectChange are derived from the object mutations in the TransactionEffect +/// to provide richer object information. +#[serde_as] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase", tag = "type")] +pub enum ObjectChange { + /// Module published + #[serde(rename_all = "camelCase")] + Published { + package_id: ObjectID, + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + version: SequenceNumber, + digest: ObjectDigest, + modules: Vec, + }, + /// Transfer objects to new address / wrap in another object + #[serde(rename_all = "camelCase")] + Transferred { + sender: IotaAddress, + recipient: Owner, + #[schemars(with = "String")] + #[serde_as(as = "IotaStructTag")] + object_type: StructTag, + object_id: ObjectID, + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + version: SequenceNumber, + digest: ObjectDigest, + }, + /// Object mutated. + #[serde(rename_all = "camelCase")] + Mutated { + sender: IotaAddress, + owner: Owner, + #[schemars(with = "String")] + #[serde_as(as = "IotaStructTag")] + object_type: StructTag, + object_id: ObjectID, + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + version: SequenceNumber, + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + previous_version: SequenceNumber, + digest: ObjectDigest, + }, + /// Delete object + #[serde(rename_all = "camelCase")] + Deleted { + sender: IotaAddress, + #[schemars(with = "String")] + #[serde_as(as = "IotaStructTag")] + object_type: StructTag, + object_id: ObjectID, + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + version: SequenceNumber, + }, + /// Wrapped object + #[serde(rename_all = "camelCase")] + Wrapped { + sender: IotaAddress, + #[schemars(with = "String")] + #[serde_as(as = "IotaStructTag")] + object_type: StructTag, + object_id: ObjectID, + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + version: SequenceNumber, + }, + /// New object creation + #[serde(rename_all = "camelCase")] + Created { + sender: IotaAddress, + owner: Owner, + #[schemars(with = "String")] + #[serde_as(as = "IotaStructTag")] + object_type: StructTag, + object_id: ObjectID, + #[schemars(with = "AsSequenceNumber")] + #[serde_as(as = "AsSequenceNumber")] + version: SequenceNumber, + digest: ObjectDigest, + }, +} + +impl ObjectChange { + pub fn object_id(&self) -> ObjectID { + match self { + ObjectChange::Published { package_id, .. } => *package_id, + ObjectChange::Transferred { object_id, .. } + | ObjectChange::Mutated { object_id, .. } + | ObjectChange::Deleted { object_id, .. } + | ObjectChange::Wrapped { object_id, .. } + | ObjectChange::Created { object_id, .. } => *object_id, + } + } + + pub fn object_ref(&self) -> ObjectRef { + match self { + ObjectChange::Published { + package_id, + version, + digest, + .. + } => (*package_id, *version, *digest), + ObjectChange::Transferred { + object_id, + version, + digest, + .. + } + | ObjectChange::Mutated { + object_id, + version, + digest, + .. + } + | ObjectChange::Created { + object_id, + version, + digest, + .. + } => (*object_id, *version, *digest), + ObjectChange::Deleted { + object_id, version, .. + } => (*object_id, *version, ObjectDigest::OBJECT_DIGEST_DELETED), + ObjectChange::Wrapped { + object_id, version, .. + } => (*object_id, *version, ObjectDigest::OBJECT_DIGEST_WRAPPED), + } + } + + pub fn mask_for_test(&mut self, new_version: SequenceNumber, new_digest: ObjectDigest) { + match self { + ObjectChange::Published { + version, digest, .. + } + | ObjectChange::Transferred { + version, digest, .. + } + | ObjectChange::Mutated { + version, digest, .. + } + | ObjectChange::Created { + version, digest, .. + } => { + *version = new_version; + *digest = new_digest + } + ObjectChange::Deleted { version, .. } | ObjectChange::Wrapped { version, .. } => { + *version = new_version + } + } + } +} + +impl Display for ObjectChange { + fn fmt(&self, f: &mut Formatter) -> Result { + match self { + ObjectChange::Published { + package_id, + version, + digest, + modules, + } => { + write!( + f, + " ┌──\n │ PackageID: {} \n │ Version: {} \n │ Digest: {}\n │ Modules: {}\n └──", + package_id, + u64::from(*version), + digest, + modules.join(", ") + ) + } + ObjectChange::Transferred { + sender, + recipient, + object_type, + object_id, + version, + digest, + } => { + write!( + f, + " ┌──\n │ ObjectID: {}\n │ Sender: {} \n │ Recipient: {}\n │ ObjectType: {} \n │ Version: {}\n │ Digest: {}\n └──", + object_id, + sender, + recipient, + object_type, + u64::from(*version), + digest + ) + } + ObjectChange::Mutated { + sender, + owner, + object_type, + object_id, + version, + previous_version: _, + digest, + } => { + write!( + f, + " ┌──\n │ ObjectID: {}\n │ Sender: {} \n │ Owner: {}\n │ ObjectType: {} \n │ Version: {}\n │ Digest: {}\n └──", + object_id, + sender, + owner, + object_type, + u64::from(*version), + digest + ) + } + ObjectChange::Deleted { + sender, + object_type, + object_id, + version, + } => { + write!( + f, + " ┌──\n │ ObjectID: {}\n │ Sender: {} \n │ ObjectType: {} \n │ Version: {}\n └──", + object_id, + sender, + object_type, + u64::from(*version) + ) + } + ObjectChange::Wrapped { + sender, + object_type, + object_id, + version, + } => { + write!( + f, + " ┌──\n │ ObjectID: {}\n │ Sender: {} \n │ ObjectType: {} \n │ Version: {}\n └──", + object_id, + sender, + object_type, + u64::from(*version) + ) + } + ObjectChange::Created { + sender, + owner, + object_type, + object_id, + version, + digest, + } => { + write!( + f, + " ┌──\n │ ObjectID: {}\n │ Sender: {} \n │ Owner: {}\n │ ObjectType: {} \n │ Version: {}\n │ Digest: {}\n └──", + object_id, + sender, + owner, + object_type, + u64::from(*version), + digest + ) + } + } + } +} diff --git a/crates/iota-json-rpc-types/src/unit_tests/iota_move_tests.rs b/crates/iota-json-rpc-types/src/unit_tests/iota_move_tests.rs new file mode 100644 index 00000000000..9bf5f86e7c7 --- /dev/null +++ b/crates/iota-json-rpc-types/src/unit_tests/iota_move_tests.rs @@ -0,0 +1,18 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_enum_compat_util::*; + +use crate::{IotaMoveStruct, IotaMoveValue}; + +#[test] +fn enforce_order_test() { + let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.extend(["tests", "staged", "iota_move_struct.yaml"]); + check_enum_compat_order::(path); + + let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.extend(["tests", "staged", "iota_move_value.yaml"]); + check_enum_compat_order::(path); +} diff --git a/crates/iota-json-rpc-types/src/unit_tests/rpc_types_tests.rs b/crates/iota-json-rpc-types/src/unit_tests/rpc_types_tests.rs new file mode 100644 index 00000000000..13c751edfc2 --- /dev/null +++ b/crates/iota-json-rpc-types/src/unit_tests/rpc_types_tests.rs @@ -0,0 +1,201 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::str::FromStr; + +use anyhow::anyhow; +use iota_types::{ + base_types::{IotaAddress, ObjectDigest, ObjectID, SequenceNumber}, + gas_coin::GasCoin, + object::{MoveObject, Owner}, + parse_iota_struct_tag, IOTA_FRAMEWORK_ADDRESS, MOVE_STDLIB_ADDRESS, +}; +use move_core_types::{ + annotated_value::{MoveStruct, MoveValue}, + ident_str, + identifier::Identifier, + language_storage::{StructTag, TypeTag}, +}; +use serde_json::json; + +use crate::{IotaMoveStruct, IotaMoveValue, ObjectChange}; + +#[test] +fn test_move_value_to_iota_coin() { + let id = ObjectID::random(); + let value = 10000; + let coin = GasCoin::new(id, value); + + let move_object = MoveObject::new_gas_coin(SequenceNumber::new(), id, value); + let layout = GasCoin::layout(); + + let move_struct = move_object.to_move_struct(&layout).unwrap(); + let iota_struct = IotaMoveStruct::from(move_struct); + let gas_coin = GasCoin::try_from(&iota_struct).unwrap(); + assert_eq!(coin.value(), gas_coin.value()); + assert_eq!(coin.id(), gas_coin.id()); +} + +#[test] +fn test_move_value_to_string() { + let test_string = "Some test string"; + let bytes = test_string.as_bytes(); + let values = bytes + .iter() + .map(|u8| MoveValue::U8(*u8)) + .collect::>(); + + let move_value = MoveValue::Struct(MoveStruct { + type_: StructTag { + address: MOVE_STDLIB_ADDRESS, + module: ident_str!("string").to_owned(), + name: ident_str!("String").to_owned(), + type_params: vec![], + }, + fields: vec![(ident_str!("bytes").to_owned(), MoveValue::Vector(values))], + }); + + let iota_value = IotaMoveValue::from(move_value); + + assert!(matches!(iota_value, IotaMoveValue::String(s) if s == test_string)); +} + +#[test] +fn test_option() { + // bugfix for https://github.com/iotaledger/iota/issues/4995 + let option = MoveValue::Struct(MoveStruct { + type_: StructTag { + address: MOVE_STDLIB_ADDRESS, + module: Identifier::from_str("option").unwrap(), + name: Identifier::from_str("Option").unwrap(), + type_params: vec![TypeTag::U8], + }, + fields: vec![( + Identifier::from_str("vec").unwrap(), + MoveValue::Vector(vec![MoveValue::U8(5)]), + )], + }); + let iota_value = IotaMoveValue::from(option); + assert!(matches!( + iota_value, + IotaMoveValue::Option(value) if *value == Some(IotaMoveValue::Number(5)) + )); +} + +#[test] +fn test_move_value_to_url() { + let test_url = "http://testing.com"; + let bytes = test_url.as_bytes(); + let values = bytes + .iter() + .map(|u8| MoveValue::U8(*u8)) + .collect::>(); + + let string_move_value = MoveValue::Struct(MoveStruct { + type_: StructTag { + address: MOVE_STDLIB_ADDRESS, + module: ident_str!("string").to_owned(), + name: ident_str!("String").to_owned(), + type_params: vec![], + }, + fields: vec![(ident_str!("bytes").to_owned(), MoveValue::Vector(values))], + }); + + let url_move_value = MoveValue::Struct(MoveStruct { + type_: StructTag { + address: IOTA_FRAMEWORK_ADDRESS, + module: ident_str!("url").to_owned(), + name: ident_str!("Url").to_owned(), + type_params: vec![], + }, + fields: vec![(ident_str!("url").to_owned(), string_move_value)], + }); + + let iota_value = IotaMoveValue::from(url_move_value); + + assert!(matches!(iota_value, IotaMoveValue::String(s) if s == test_url)); +} + +#[test] +fn test_serde() { + let test_values = [ + IotaMoveValue::Number(u32::MAX), + IotaMoveValue::UID { + id: ObjectID::random(), + }, + IotaMoveValue::String("some test string".to_string()), + IotaMoveValue::Address(IotaAddress::random_for_testing_only()), + IotaMoveValue::Bool(true), + IotaMoveValue::Option(Box::new(None)), + IotaMoveValue::Vector(vec![ + IotaMoveValue::Number(1000000), + IotaMoveValue::Number(2000000), + IotaMoveValue::Number(3000000), + ]), + ]; + + for value in test_values { + let json = serde_json::to_string(&value).unwrap(); + let serde_value: IotaMoveValue = serde_json::from_str(&json) + .map_err(|e| anyhow!("Serde failed for [{:?}], Error msg : {}", value, e)) + .unwrap(); + assert_eq!( + value, serde_value, + "Error converting {:?} [{json}], got {:?}", + value, serde_value + ) + } +} + +#[test] +fn test_serde_bytearray() { + // ensure that we serialize byte arrays as number array + let test_values = MoveValue::Vector(vec![MoveValue::U8(1), MoveValue::U8(2), MoveValue::U8(3)]); + let iota_move_value = IotaMoveValue::from(test_values); + let json = serde_json::to_value(&iota_move_value).unwrap(); + assert_eq!(json, json!([1, 2, 3])); +} + +#[test] +fn test_serde_number() { + // ensure that we serialize byte arrays as number array + let test_values = MoveValue::U8(1); + let iota_move_value = IotaMoveValue::from(test_values); + let json = serde_json::to_value(&iota_move_value).unwrap(); + assert_eq!(json, json!(1)); + let test_values = MoveValue::U16(1); + let iota_move_value = IotaMoveValue::from(test_values); + let json = serde_json::to_value(&iota_move_value).unwrap(); + assert_eq!(json, json!(1)); + let test_values = MoveValue::U32(1); + let iota_move_value = IotaMoveValue::from(test_values); + let json = serde_json::to_value(&iota_move_value).unwrap(); + assert_eq!(json, json!(1)); +} + +#[test] +fn test_type_tag_struct_tag_devnet_inc_222() { + let offending_tags = [ + "0x1::address::MyType", + "0x1::vector::MyType", + "0x1::address::MyType<0x1::address::OtherType>", + "0x1::address::MyType<0x1::address::OtherType, 0x1::vector::VecTyper>", + "0x1::address::address<0x1::vector::address, 0x1::vector::vector>", + ]; + + for tag in offending_tags { + let oc = ObjectChange::Created { + sender: Default::default(), + owner: Owner::Immutable, + object_type: parse_iota_struct_tag(tag).unwrap(), + object_id: ObjectID::random(), + version: Default::default(), + digest: ObjectDigest::random(), + }; + + let serde_json = serde_json::to_string(&oc).unwrap(); + let deser: ObjectChange = serde_json::from_str(&serde_json).unwrap(); + assert_eq!(oc, deser); + } +} diff --git a/crates/sui-json-rpc-types/tests/staged/sui_move_struct.yaml b/crates/iota-json-rpc-types/tests/staged/iota_move_struct.yaml similarity index 100% rename from crates/sui-json-rpc-types/tests/staged/sui_move_struct.yaml rename to crates/iota-json-rpc-types/tests/staged/iota_move_struct.yaml diff --git a/crates/sui-json-rpc-types/tests/staged/sui_move_value.yaml b/crates/iota-json-rpc-types/tests/staged/iota_move_value.yaml similarity index 100% rename from crates/sui-json-rpc-types/tests/staged/sui_move_value.yaml rename to crates/iota-json-rpc-types/tests/staged/iota_move_value.yaml diff --git a/crates/iota-json-rpc/Cargo.toml b/crates/iota-json-rpc/Cargo.toml new file mode 100644 index 00000000000..a7e95dfb436 --- /dev/null +++ b/crates/iota-json-rpc/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "iota-json-rpc" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +arc-swap.workspace = true +fastcrypto.workspace = true +jsonrpsee.workspace = true +hyper.workspace = true +itertools.workspace = true +indexmap.workspace = true +tower.workspace = true +axum.workspace = true +tower-http.workspace = true +move-binary-format.workspace = true +move-core-types.workspace = true +move-package.workspace = true +move-bytecode-utils.workspace = true +prometheus.workspace = true +anyhow.workspace = true +tracing.workspace = true +async-trait.workspace = true +serde.workspace = true +futures.workspace = true +tokio = { workspace = true, features = ["full"] } +signature.workspace = true +thiserror.workspace = true +bcs.workspace = true +eyre.workspace = true +once_cell.workspace = true +serde_json.workspace = true + +tap.workspace = true + +iota-core.workspace = true +iota-storage.workspace = true +iota-types.workspace = true +iota-json.workspace = true +iota-json-rpc-api.workspace = true +iota-open-rpc.workspace = true +iota-open-rpc-macros.workspace = true +iota-protocol-config.workspace = true +iota-json-rpc-types.workspace = true +iota-transaction-builder.workspace = true +mysten-metrics.workspace = true +shared-crypto.workspace = true +typed-store-error.workspace = true +cached.workspace = true + +[dev-dependencies] +mockall.workspace = true +expect-test.workspace = true +iota-types = { workspace = true, features = ["test-utils"] } +telemetry-subscribers.workspace = true diff --git a/crates/sui-json-rpc/src/authority_state.rs b/crates/iota-json-rpc/src/authority_state.rs similarity index 88% rename from crates/sui-json-rpc/src/authority_state.rs rename to crates/iota-json-rpc/src/authority_state.rs index 2684b43a26c..8b54b93255d 100644 --- a/crates/sui-json-rpc/src/authority_state.rs +++ b/crates/iota-json-rpc/src/authority_state.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -9,45 +10,45 @@ use std::{ use anyhow::anyhow; use arc_swap::Guard; use async_trait::async_trait; -#[cfg(test)] -use mockall::automock; -use move_core_types::language_storage::TypeTag; -use sui_core::{ +use iota_core::{ authority::{authority_per_epoch_store::AuthorityPerEpochStore, AuthorityState}, execution_cache::ExecutionCacheRead, subscription_handler::SubscriptionHandler, }; -use sui_json_rpc_types::{ - Coin as SuiCoin, DevInspectResults, DryRunTransactionBlockResponse, EventFilter, SuiEvent, - SuiObjectDataFilter, TransactionFilter, +use iota_json_rpc_types::{ + Coin as IotaCoin, DevInspectResults, DryRunTransactionBlockResponse, EventFilter, IotaEvent, + IotaObjectDataFilter, TransactionFilter, }; -use sui_storage::{ +use iota_storage::{ indexes::TotalBalance, key_value_store::{ KVStoreCheckpointData, KVStoreTransactionData, TransactionKeyValueStore, TransactionKeyValueStoreTrait, }, }; -use sui_types::{ - base_types::{MoveObjectType, ObjectID, ObjectInfo, ObjectRef, SequenceNumber, SuiAddress}, +use iota_types::{ + base_types::{IotaAddress, MoveObjectType, ObjectID, ObjectInfo, ObjectRef, SequenceNumber}, committee::{Committee, EpochId}, digests::{ChainIdentifier, TransactionDigest, TransactionEventsDigest}, dynamic_field::DynamicFieldInfo, effects::TransactionEffects, - error::{SuiError, UserInputError}, + error::{IotaError, UserInputError}, event::EventID, - governance::StakedSui, + governance::StakedIota, + iota_serde::BigInt, + iota_system_state::IotaSystemState, messages_checkpoint::{ CheckpointContents, CheckpointContentsDigest, CheckpointDigest, CheckpointSequenceNumber, VerifiedCheckpoint, }, object::{Object, ObjectRead, PastObjectRead}, storage::{BackingPackageStore, ObjectStore, WriteKind}, - sui_serde::BigInt, - sui_system_state::SuiSystemState, - timelock::timelocked_staked_sui::TimelockedStakedSui, + timelock::timelocked_staked_iota::TimelockedStakedIota, transaction::{Transaction, TransactionData, TransactionKind}, }; +#[cfg(test)] +use mockall::automock; +use move_core_types::language_storage::TypeTag; use thiserror::Error; use tokio::task::JoinError; @@ -101,9 +102,9 @@ pub trait StateRead: Send + Sync { fn get_owner_objects( &self, - owner: SuiAddress, + owner: IotaAddress, cursor: Option, - filter: Option, + filter: Option, ) -> StateReadResult>; async fn query_events( @@ -114,7 +115,7 @@ pub trait StateRead: Send + Sync { cursor: Option, limit: usize, descending: bool, - ) -> StateReadResult>; + ) -> StateReadResult>; // transaction_execution_api #[allow(clippy::type_complexity)] @@ -131,11 +132,11 @@ pub trait StateRead: Send + Sync { async fn dev_inspect_transaction_block( &self, - sender: SuiAddress, + sender: IotaAddress, transaction_kind: TransactionKind, gas_price: Option, gas_budget: Option, - gas_sponsor: Option, + gas_sponsor: Option, gas_objects: Option>, show_raw_txn_data_and_effects: Option, skip_checks: Option, @@ -146,10 +147,10 @@ pub trait StateRead: Send + Sync { fn get_owner_objects_with_limit( &self, - owner: SuiAddress, + owner: IotaAddress, cursor: Option, limit: usize, - filter: Option, + filter: Option, ) -> StateReadResult>; async fn get_transactions( @@ -169,23 +170,23 @@ pub trait StateRead: Send + Sync { ) -> StateReadResult>; // governance_api - async fn get_staked_sui(&self, owner: SuiAddress) -> StateReadResult>; - async fn get_timelocked_staked_sui( + async fn get_staked_iota(&self, owner: IotaAddress) -> StateReadResult>; + async fn get_timelocked_staked_iota( &self, - owner: SuiAddress, - ) -> StateReadResult>; - fn get_system_state(&self) -> StateReadResult; + owner: IotaAddress, + ) -> StateReadResult>; + fn get_system_state(&self) -> StateReadResult; fn get_or_latest_committee(&self, epoch: Option>) -> StateReadResult; // coin_api fn find_publish_txn_digest(&self, package_id: ObjectID) -> StateReadResult; fn get_owned_coins( &self, - owner: SuiAddress, + owner: IotaAddress, cursor: (String, ObjectID), limit: usize, one_coin_type_only: bool, - ) -> StateReadResult>; + ) -> StateReadResult>; async fn get_executed_transaction_and_effects( &self, digest: TransactionDigest, @@ -193,12 +194,12 @@ pub trait StateRead: Send + Sync { ) -> StateReadResult<(Transaction, TransactionEffects)>; async fn get_balance( &self, - owner: SuiAddress, + owner: IotaAddress, coin_type: TypeTag, ) -> StateReadResult; async fn get_all_balance( &self, - owner: SuiAddress, + owner: IotaAddress, ) -> StateReadResult>>; // read_api @@ -330,9 +331,9 @@ impl StateRead for AuthorityState { fn get_owner_objects( &self, - owner: SuiAddress, + owner: IotaAddress, cursor: Option, - filter: Option, + filter: Option, ) -> StateReadResult> { Ok(self .get_owner_objects_iterator(owner, cursor, filter)? @@ -347,7 +348,7 @@ impl StateRead for AuthorityState { cursor: Option, limit: usize, descending: bool, - ) -> StateReadResult> { + ) -> StateReadResult> { Ok(self .query_events(kv_store, query, cursor, limit, descending) .await?) @@ -371,11 +372,11 @@ impl StateRead for AuthorityState { async fn dev_inspect_transaction_block( &self, - sender: SuiAddress, + sender: IotaAddress, transaction_kind: TransactionKind, gas_price: Option, gas_budget: Option, - gas_sponsor: Option, + gas_sponsor: Option, gas_objects: Option>, show_raw_txn_data_and_effects: Option, skip_checks: Option, @@ -400,10 +401,10 @@ impl StateRead for AuthorityState { fn get_owner_objects_with_limit( &self, - owner: SuiAddress, + owner: IotaAddress, cursor: Option, limit: usize, - filter: Option, + filter: Option, ) -> StateReadResult> { Ok(self.get_owner_objects(owner, cursor, limit, filter)?) } @@ -431,23 +432,23 @@ impl StateRead for AuthorityState { Ok(self.get_dynamic_field_object_id(owner, name_type, name_bcs_bytes)?) } - async fn get_staked_sui(&self, owner: SuiAddress) -> StateReadResult> { + async fn get_staked_iota(&self, owner: IotaAddress) -> StateReadResult> { Ok(self - .get_move_objects(owner, MoveObjectType::staked_sui()) + .get_move_objects(owner, MoveObjectType::staked_iota()) .await?) } - async fn get_timelocked_staked_sui( + async fn get_timelocked_staked_iota( &self, - owner: SuiAddress, - ) -> StateReadResult> { + owner: IotaAddress, + ) -> StateReadResult> { Ok(self - .get_move_objects(owner, MoveObjectType::timelocked_staked_sui()) + .get_move_objects(owner, MoveObjectType::timelocked_staked_iota()) .await?) } - fn get_system_state(&self) -> StateReadResult { + fn get_system_state(&self) -> StateReadResult { Ok(self .get_cache_reader() - .get_sui_system_state_object_unsafe()?) + .get_iota_system_state_object_unsafe()?) } fn get_or_latest_committee(&self, epoch: Option>) -> StateReadResult { Ok(self @@ -460,14 +461,14 @@ impl StateRead for AuthorityState { } fn get_owned_coins( &self, - owner: SuiAddress, + owner: IotaAddress, cursor: (String, ObjectID), limit: usize, one_coin_type_only: bool, - ) -> StateReadResult> { + ) -> StateReadResult> { Ok(self .get_owned_coins_iterator_with_cursor(owner, cursor, limit, one_coin_type_only)? - .map(|(coin_type, coin_object_id, coin)| SuiCoin { + .map(|(coin_type, coin_object_id, coin)| IotaCoin { coin_type, coin_object_id, version: coin.version, @@ -490,25 +491,25 @@ impl StateRead for AuthorityState { async fn get_balance( &self, - owner: SuiAddress, + owner: IotaAddress, coin_type: TypeTag, ) -> StateReadResult { Ok(self .indexes .as_ref() - .ok_or(SuiError::IndexStoreNotAvailable)? + .ok_or(IotaError::IndexStoreNotAvailable)? .get_balance(owner, coin_type) .await?) } async fn get_all_balance( &self, - owner: SuiAddress, + owner: IotaAddress, ) -> StateReadResult>> { Ok(self .indexes .as_ref() - .ok_or(SuiError::IndexStoreNotAvailable)? + .ok_or(IotaError::IndexStoreNotAvailable)? .get_all_balance(owner) .await?) } @@ -650,7 +651,7 @@ impl ObjectProvider for (Arc, Arc for StateReadError { - fn from(e: SuiError) -> Self { +impl From for StateReadError { + fn from(e: IotaError) -> Self { match e { - SuiError::IndexStoreNotAvailable - | SuiError::TransactionNotFound { .. } - | SuiError::UnsupportedFeatureError { .. } - | SuiError::UserInputError { .. } - | SuiError::WrongMessageVersion { .. } => StateReadError::Client(e.into()), + IotaError::IndexStoreNotAvailable + | IotaError::TransactionNotFound { .. } + | IotaError::UnsupportedFeatureError { .. } + | IotaError::UserInputError { .. } + | IotaError::WrongMessageVersion { .. } => StateReadError::Client(e.into()), _ => StateReadError::Internal(e.into()), } } diff --git a/crates/sui-json-rpc/src/axum_router.rs b/crates/iota-json-rpc/src/axum_router.rs similarity index 99% rename from crates/sui-json-rpc/src/axum_router.rs rename to crates/iota-json-rpc/src/axum_router.rs index d2139e4d9dd..462d79eb8d0 100644 --- a/crates/sui-json-rpc/src/axum_router.rs +++ b/crates/iota-json-rpc/src/axum_router.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; @@ -6,6 +7,7 @@ use std::sync::Arc; use axum::extract::{Json, State}; use futures::StreamExt; use hyper::HeaderMap; +use iota_json_rpc_api::CLIENT_TARGET_API_VERSION_HEADER; use jsonrpsee::{ core::server::{ helpers::{BoundedSubscriptions, MethodResponse, MethodSink}, @@ -21,7 +23,6 @@ use jsonrpsee::{ }, }; use serde_json::value::RawValue; -use sui_json_rpc_api::CLIENT_TARGET_API_VERSION_HEADER; use crate::routing_layer::RpcRouter; diff --git a/crates/iota-json-rpc/src/balance_changes.rs b/crates/iota-json-rpc/src/balance_changes.rs new file mode 100644 index 00000000000..e1437b91a67 --- /dev/null +++ b/crates/iota-json-rpc/src/balance_changes.rs @@ -0,0 +1,270 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{BTreeMap, HashMap, HashSet}, + ops::Neg, +}; + +use async_trait::async_trait; +use iota_json_rpc_types::BalanceChange; +use iota_types::{ + base_types::{ObjectID, ObjectRef, SequenceNumber}, + coin::Coin, + digests::ObjectDigest, + effects::{TransactionEffects, TransactionEffectsAPI}, + execution_status::ExecutionStatus, + gas_coin::GAS, + object::{Object, Owner}, + storage::WriteKind, + transaction::InputObjectKind, +}; +use move_core_types::language_storage::TypeTag; +use tokio::sync::RwLock; + +pub async fn get_balance_changes_from_effect, E>( + object_provider: &P, + effects: &TransactionEffects, + input_objs: Vec, + mocked_coin: Option, +) -> Result, E> { + let (_, gas_owner) = effects.gas_object(); + + // Only charge gas when tx fails, skip all object parsing + if effects.status() != &ExecutionStatus::Success { + return Ok(vec![BalanceChange { + owner: gas_owner, + coin_type: GAS::type_tag(), + amount: effects.gas_cost_summary().net_gas_usage().neg() as i128, + }]); + } + + let all_mutated = effects + .all_changed_objects() + .into_iter() + .filter_map(|((id, version, digest), _, _)| { + if matches!(mocked_coin, Some(coin) if id == coin) { + return None; + } + Some((id, version, Some(digest))) + }) + .collect::>(); + + let input_objs_to_digest = input_objs + .iter() + .filter_map(|k| match k { + InputObjectKind::ImmOrOwnedMoveObject(o) => Some((o.0, o.2)), + InputObjectKind::MovePackage(_) | InputObjectKind::SharedMoveObject { .. } => None, + }) + .collect::>(); + let unwrapped_then_deleted = effects + .unwrapped_then_deleted() + .iter() + .map(|e| e.0) + .collect::>(); + get_balance_changes( + object_provider, + &effects + .modified_at_versions() + .into_iter() + .filter_map(|(id, version)| { + if matches!(mocked_coin, Some(coin) if id == coin) { + return None; + } + // We won't be able to get dynamic object from object provider today + if unwrapped_then_deleted.contains(&id) { + return None; + } + Some((id, version, input_objs_to_digest.get(&id).cloned())) + }) + .collect::>(), + &all_mutated, + ) + .await +} + +pub async fn get_balance_changes, E>( + object_provider: &P, + modified_at_version: &[(ObjectID, SequenceNumber, Option)], + all_mutated: &[(ObjectID, SequenceNumber, Option)], +) -> Result, E> { + // 1. subtract all input coins + let balances = fetch_coins(object_provider, modified_at_version) + .await? + .into_iter() + .fold( + BTreeMap::<_, i128>::new(), + |mut acc, (owner, type_, amount)| { + *acc.entry((owner, type_)).or_default() -= amount as i128; + acc + }, + ); + // 2. add all mutated coins + let balances = fetch_coins(object_provider, all_mutated) + .await? + .into_iter() + .fold(balances, |mut acc, (owner, type_, amount)| { + *acc.entry((owner, type_)).or_default() += amount as i128; + acc + }); + + Ok(balances + .into_iter() + .filter_map(|((owner, coin_type), amount)| { + if amount == 0 { + return None; + } + Some(BalanceChange { + owner, + coin_type, + amount, + }) + }) + .collect()) +} + +async fn fetch_coins, E>( + object_provider: &P, + objects: &[(ObjectID, SequenceNumber, Option)], +) -> Result, E> { + let mut all_mutated_coins = vec![]; + for (id, version, digest_opt) in objects { + // TODO: use multi get object + let o = object_provider.get_object(id, version).await?; + if let Some(type_) = o.type_() { + if type_.is_coin() { + if let Some(digest) = digest_opt { + // TODO: can we return Err here instead? + assert_eq!( + *digest, + o.digest(), + "Object digest mismatch--got bad data from object_provider?" + ) + } + let [coin_type]: [TypeTag; 1] = + type_.clone().into_type_params().try_into().unwrap(); + all_mutated_coins.push(( + o.owner, + coin_type, + // we know this is a coin, safe to unwrap + Coin::extract_balance_if_coin(&o).unwrap().unwrap(), + )) + } + } + } + Ok(all_mutated_coins) +} + +#[async_trait] +pub trait ObjectProvider { + type Error; + async fn get_object( + &self, + id: &ObjectID, + version: &SequenceNumber, + ) -> Result; + async fn find_object_lt_or_eq_version( + &self, + id: &ObjectID, + version: &SequenceNumber, + ) -> Result, Self::Error>; +} + +pub struct ObjectProviderCache

    { + object_cache: RwLock>, + last_version_cache: RwLock>, + provider: P, +} + +impl

    ObjectProviderCache

    { + pub fn new(provider: P) -> Self { + Self { + object_cache: Default::default(), + last_version_cache: Default::default(), + provider, + } + } + + pub fn new_with_cache( + provider: P, + written_objects: BTreeMap, + ) -> Self { + let mut object_cache = BTreeMap::new(); + let mut last_version_cache = BTreeMap::new(); + + for (object_id, (object_ref, object, _)) in written_objects { + let key = (object_id, object_ref.1); + object_cache.insert(key, object.clone()); + + match last_version_cache.get_mut(&key) { + Some(existing_seq_number) => { + if object_ref.1 > *existing_seq_number { + *existing_seq_number = object_ref.1 + } + } + None => { + last_version_cache.insert(key, object_ref.1); + } + } + } + + Self { + object_cache: RwLock::new(object_cache), + last_version_cache: RwLock::new(last_version_cache), + provider, + } + } +} + +#[async_trait] +impl ObjectProvider for ObjectProviderCache

    +where + P: ObjectProvider + Sync + Send, + E: Sync + Send, +{ + type Error = P::Error; + + async fn get_object( + &self, + id: &ObjectID, + version: &SequenceNumber, + ) -> Result { + if let Some(o) = self.object_cache.read().await.get(&(*id, *version)) { + return Ok(o.clone()); + } + let o = self.provider.get_object(id, version).await?; + self.object_cache + .write() + .await + .insert((*id, *version), o.clone()); + Ok(o) + } + + async fn find_object_lt_or_eq_version( + &self, + id: &ObjectID, + version: &SequenceNumber, + ) -> Result, Self::Error> { + if let Some(version) = self.last_version_cache.read().await.get(&(*id, *version)) { + return Ok(self.get_object(id, version).await.ok()); + } + if let Some(o) = self + .provider + .find_object_lt_or_eq_version(id, version) + .await? + { + self.object_cache + .write() + .await + .insert((*id, o.version()), o.clone()); + self.last_version_cache + .write() + .await + .insert((*id, *version), o.version()); + Ok(Some(o)) + } else { + Ok(None) + } + } +} diff --git a/crates/iota-json-rpc/src/coin_api.rs b/crates/iota-json-rpc/src/coin_api.rs new file mode 100644 index 00000000000..6b959b6c7eb --- /dev/null +++ b/crates/iota-json-rpc/src/coin_api.rs @@ -0,0 +1,1411 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::HashMap, sync::Arc}; + +use async_trait::async_trait; +use cached::{proc_macro::cached, SizedCache}; +use iota_core::authority::AuthorityState; +use iota_json_rpc_api::{cap_page_limit, CoinReadApiOpenRpc, CoinReadApiServer, JsonRpcMetrics}; +use iota_json_rpc_types::{Balance, CoinPage, IotaCoinMetadata}; +use iota_open_rpc::Module; +use iota_storage::{indexes::TotalBalance, key_value_store::TransactionKeyValueStore}; +use iota_types::{ + balance::Supply, + base_types::{IotaAddress, ObjectID}, + coin::{CoinMetadata, TreasuryCap}, + effects::TransactionEffectsAPI, + gas_coin::{GAS, TOTAL_SUPPLY_MICROS}, + object::Object, + parse_iota_struct_tag, +}; +use jsonrpsee::{core::RpcResult, RpcModule}; +#[cfg(test)] +use mockall::automock; +use move_core_types::language_storage::{StructTag, TypeTag}; +use mysten_metrics::spawn_monitored_task; +use tap::TapFallible; +use tracing::{debug, info, instrument}; + +use crate::{ + authority_state::StateRead, + error::{Error, IotaRpcInputError, RpcInterimResult}, + with_tracing, IotaRpcModule, +}; + +pub fn parse_to_struct_tag(coin_type: &str) -> Result { + parse_iota_struct_tag(coin_type) + .map_err(|e| IotaRpcInputError::CannotParseIotaStructTag(format!("{e}"))) +} + +pub fn parse_to_type_tag(coin_type: Option) -> Result { + Ok(TypeTag::Struct(Box::new(match coin_type { + Some(c) => parse_to_struct_tag(&c)?, + None => GAS::type_(), + }))) +} + +pub struct CoinReadApi { + // Trait object w/ Box as we do not need to share this across multiple threads + internal: Box, +} + +impl CoinReadApi { + pub fn new( + state: Arc, + transaction_kv_store: Arc, + metrics: Arc, + ) -> Self { + Self { + internal: Box::new(CoinReadInternalImpl::new( + state, + transaction_kv_store, + metrics, + )), + } + } +} + +impl IotaRpcModule for CoinReadApi { + fn rpc(self) -> RpcModule { + self.into_rpc() + } + + fn rpc_doc_module() -> Module { + CoinReadApiOpenRpc::module_doc() + } +} + +#[async_trait] +impl CoinReadApiServer for CoinReadApi { + #[instrument(skip(self))] + async fn get_coins( + &self, + owner: IotaAddress, + coin_type: Option, + // exclusive cursor if `Some`, otherwise start from the beginning + cursor: Option, + limit: Option, + ) -> RpcResult { + with_tracing!(async move { + let coin_type_tag = parse_to_type_tag(coin_type)?; + + let cursor = match cursor { + Some(c) => (coin_type_tag.to_string(), c), + // If cursor is not specified, we need to start from the beginning of the coin type, + // which is the minimal possible ObjectID. + None => (coin_type_tag.to_string(), ObjectID::ZERO), + }; + + self.internal + .get_coins_iterator( + owner, cursor, limit, true, // only care about one type of coin + ) + .await + }) + } + + #[instrument(skip(self))] + async fn get_all_coins( + &self, + owner: IotaAddress, + // exclusive cursor if `Some`, otherwise start from the beginning + cursor: Option, + limit: Option, + ) -> RpcResult { + with_tracing!(async move { + let cursor = match cursor { + Some(object_id) => { + let obj = self.internal.get_object(&object_id).await?; + match obj { + Some(obj) => { + let coin_type = obj.coin_type_maybe(); + if coin_type.is_none() { + Err(IotaRpcInputError::GenericInvalid( + "cursor is not a coin".to_string(), + )) + } else { + Ok((coin_type.unwrap().to_string(), object_id)) + } + } + None => Err(IotaRpcInputError::GenericInvalid( + "cursor not found".to_string(), + )), + } + } + None => { + // If cursor is None, start from the beginning + Ok((String::from_utf8([0u8].to_vec()).unwrap(), ObjectID::ZERO)) + } + }?; + + let coins = self + .internal + .get_coins_iterator( + owner, cursor, limit, false, // return all types of coins + ) + .await?; + + Ok(coins) + }) + } + + #[instrument(skip(self))] + async fn get_balance( + &self, + owner: IotaAddress, + coin_type: Option, + ) -> RpcResult { + with_tracing!(async move { + let coin_type_tag = parse_to_type_tag(coin_type)?; + let balance = self + .internal + .get_balance(owner, coin_type_tag.clone()) + .await + .tap_err(|e| { + debug!(?owner, "Failed to get balance with error: {:?}", e); + })?; + Ok(Balance { + coin_type: coin_type_tag.to_string(), + coin_object_count: balance.num_coins as usize, + total_balance: balance.balance as u128, + // note: LockedCoin is deprecated + locked_balance: Default::default(), + }) + }) + } + + #[instrument(skip(self))] + async fn get_all_balances(&self, owner: IotaAddress) -> RpcResult> { + with_tracing!(async move { + let all_balance = self.internal.get_all_balance(owner).await.tap_err(|e| { + debug!(?owner, "Failed to get all balance with error: {:?}", e); + })?; + Ok(all_balance + .iter() + .map(|(coin_type, balance)| { + Balance { + coin_type: coin_type.to_string(), + coin_object_count: balance.num_coins as usize, + total_balance: balance.balance as u128, + // note: LockedCoin is deprecated + locked_balance: Default::default(), + } + }) + .collect()) + }) + } + + #[instrument(skip(self))] + async fn get_coin_metadata(&self, coin_type: String) -> RpcResult> { + with_tracing!(async move { + let coin_struct = parse_to_struct_tag(&coin_type)?; + let metadata_object = self + .internal + .find_package_object( + &coin_struct.address.into(), + CoinMetadata::type_(coin_struct), + ) + .await + .ok(); + Ok(metadata_object.and_then(|v: Object| v.try_into().ok())) + }) + } + + #[instrument(skip(self))] + async fn get_total_supply(&self, coin_type: String) -> RpcResult { + with_tracing!(async move { + let coin_struct = parse_to_struct_tag(&coin_type)?; + Ok(if GAS::is_gas(&coin_struct) { + Supply { + value: TOTAL_SUPPLY_MICROS, + } + } else { + let treasury_cap_object = self + .internal + .find_package_object( + &coin_struct.address.into(), + TreasuryCap::type_(coin_struct), + ) + .await?; + let treasury_cap = TreasuryCap::from_bcs_bytes( + treasury_cap_object.data.try_as_move().unwrap().contents(), + ) + .map_err(Error::from)?; + treasury_cap.total_supply + }) + }) + } +} + +#[cached( + type = "SizedCache", + create = "{ SizedCache::with_size(10000) }", + convert = r#"{ format!("{}{}", package_id, object_struct_tag) }"#, + result = true +)] +async fn find_package_object_id( + state: Arc, + package_id: ObjectID, + object_struct_tag: StructTag, + kv_store: Arc, +) -> RpcInterimResult { + spawn_monitored_task!(async move { + let publish_txn_digest = state.find_publish_txn_digest(package_id)?; + + let (_, effect) = state + .get_executed_transaction_and_effects(publish_txn_digest, kv_store) + .await?; + + for ((id, _, _), _) in effect.created() { + if let Ok(object_read) = state.get_object_read(&id) { + if let Ok(object) = object_read.into_object() { + if matches!(object.type_(), Some(type_) if type_.is(&object_struct_tag)) { + return Ok(id); + } + } + } + } + Err(IotaRpcInputError::GenericNotFound(format!( + "Cannot find object [{}] from [{}] package event.", + object_struct_tag, package_id, + )) + .into()) + }) + .await? +} + +/// CoinReadInternal trait to capture logic of interactions with AuthorityState +/// and metrics This allows us to also mock internal implementation for testing +#[cfg_attr(test, automock)] +#[async_trait] +pub trait CoinReadInternal { + fn get_state(&self) -> Arc; + async fn get_object(&self, object_id: &ObjectID) -> RpcInterimResult>; + async fn get_balance( + &self, + owner: IotaAddress, + coin_type: TypeTag, + ) -> RpcInterimResult; + async fn get_all_balance( + &self, + owner: IotaAddress, + ) -> RpcInterimResult>>; + async fn find_package_object( + &self, + package_id: &ObjectID, + object_struct_tag: StructTag, + ) -> RpcInterimResult; + async fn get_coins_iterator( + &self, + owner: IotaAddress, + cursor: (String, ObjectID), + limit: Option, + one_coin_type_only: bool, + ) -> RpcInterimResult; +} + +pub struct CoinReadInternalImpl { + // Trait object w/ Arc as we have methods that require sharing this across multiple threads + state: Arc, + transaction_kv_store: Arc, + pub metrics: Arc, +} + +impl CoinReadInternalImpl { + pub fn new( + state: Arc, + transaction_kv_store: Arc, + metrics: Arc, + ) -> Self { + Self { + state, + transaction_kv_store, + metrics, + } + } +} + +#[async_trait] +impl CoinReadInternal for CoinReadInternalImpl { + fn get_state(&self) -> Arc { + self.state.clone() + } + + async fn get_object(&self, object_id: &ObjectID) -> RpcInterimResult> { + Ok(self.state.get_object(object_id).await?) + } + + async fn get_balance( + &self, + owner: IotaAddress, + coin_type: TypeTag, + ) -> RpcInterimResult { + Ok(self.state.get_balance(owner, coin_type).await?) + } + + async fn get_all_balance( + &self, + owner: IotaAddress, + ) -> RpcInterimResult>> { + Ok(self.state.get_all_balance(owner).await?) + } + + async fn find_package_object( + &self, + package_id: &ObjectID, + object_struct_tag: StructTag, + ) -> RpcInterimResult { + let state = self.get_state(); + let kv_store = self.transaction_kv_store.clone(); + let object_id = + find_package_object_id(state, *package_id, object_struct_tag, kv_store).await?; + Ok(self.state.get_object_read(&object_id)?.into_object()?) + } + + async fn get_coins_iterator( + &self, + owner: IotaAddress, + cursor: (String, ObjectID), + limit: Option, + one_coin_type_only: bool, + ) -> RpcInterimResult { + let limit = cap_page_limit(limit); + self.metrics.get_coins_limit.report(limit as u64); + let state = self.get_state(); + let mut data = spawn_monitored_task!(async move { + state.get_owned_coins(owner, cursor, limit + 1, one_coin_type_only) + }) + .await??; + + let has_next_page = data.len() > limit; + data.truncate(limit); + + self.metrics.get_coins_result_size.report(data.len() as u64); + self.metrics + .get_coins_result_size_total + .inc_by(data.len() as u64); + let next_cursor = data.last().map(|coin| coin.coin_object_id); + Ok(CoinPage { + data, + next_cursor, + has_next_page, + }) + } +} + +#[cfg(test)] +mod tests { + use expect_test::expect; + use iota_json_rpc_types::Coin; + use iota_storage::{ + key_value_store::{ + KVStoreCheckpointData, KVStoreTransactionData, TransactionKeyValueStoreTrait, + }, + key_value_store_metrics::KeyValueStoreMetrics, + }; + use iota_types::{ + balance::Supply, + base_types::{IotaAddress, ObjectID, SequenceNumber}, + coin::TreasuryCap, + digests::{ObjectDigest, TransactionDigest, TransactionEventsDigest}, + effects::TransactionEffects, + error::{IotaError, IotaResult}, + gas_coin::GAS, + id::UID, + messages_checkpoint::{ + CheckpointContentsDigest, CheckpointDigest, CheckpointSequenceNumber, + }, + object::Object, + parse_iota_struct_tag, + utils::create_fake_transaction, + TypeTag, + }; + use jsonrpsee::types::ErrorObjectOwned; + use mockall::{mock, predicate}; + use move_core_types::{account_address::AccountAddress, language_storage::StructTag}; + + use super::*; + use crate::authority_state::{MockStateRead, StateReadError}; + + mock! { + pub KeyValueStore {} + #[async_trait] + impl TransactionKeyValueStoreTrait for KeyValueStore { + async fn multi_get( + &self, + transactions: &[TransactionDigest], + effects: &[TransactionDigest], + events: &[TransactionEventsDigest], + ) -> IotaResult; + + async fn multi_get_checkpoints( + &self, + checkpoint_summaries: &[CheckpointSequenceNumber], + checkpoint_contents: &[CheckpointSequenceNumber], + checkpoint_summaries_by_digest: &[CheckpointDigest], + checkpoint_contents_by_digest: &[CheckpointContentsDigest], + ) -> IotaResult; + + async fn deprecated_get_transaction_checkpoint( + &self, + digest: TransactionDigest, + ) -> IotaResult>; + + async fn get_object(&self, object_id: ObjectID, version: SequenceNumber) -> IotaResult>; + + async fn multi_get_transaction_checkpoint( + &self, + digests: &[TransactionDigest], + ) -> IotaResult>>; + } + } + + impl CoinReadInternalImpl { + pub fn new_for_tests( + state: Arc, + kv_store: Option>, + ) -> Self { + let kv_store = kv_store.unwrap_or_else(|| Arc::new(MockKeyValueStore::new())); + let metrics = KeyValueStoreMetrics::new_for_tests(); + let transaction_kv_store = + Arc::new(TransactionKeyValueStore::new("rocksdb", metrics, kv_store)); + Self { + state, + transaction_kv_store, + metrics: Arc::new(JsonRpcMetrics::new_for_tests()), + } + } + } + + impl CoinReadApi { + pub fn new_for_tests( + state: Arc, + kv_store: Option>, + ) -> Self { + let kv_store = kv_store.unwrap_or_else(|| Arc::new(MockKeyValueStore::new())); + Self { + internal: Box::new(CoinReadInternalImpl::new_for_tests(state, Some(kv_store))), + } + } + } + + fn get_test_owner() -> IotaAddress { + AccountAddress::ONE.into() + } + + fn get_test_package_id() -> ObjectID { + ObjectID::from_hex_literal("0xf").unwrap() + } + + fn get_test_coin_type(package_id: ObjectID) -> String { + format!("{}::test_coin::TEST_COIN", package_id) + } + + fn get_test_coin_type_tag(coin_type: String) -> TypeTag { + TypeTag::Struct(Box::new(parse_iota_struct_tag(&coin_type).unwrap())) + } + + enum CoinType { + Gas, + Usdc, + } + + fn get_test_coin(id_hex_literal: Option<&str>, coin_type: CoinType) -> Coin { + let (arr, coin_type_string, balance, default_hex) = match coin_type { + CoinType::Gas => ([0; 32], GAS::type_().to_string(), 42, "0xA"), + CoinType::Usdc => ( + [1; 32], + "0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC".to_string(), + 24, + "0xB", + ), + }; + + let object_id = if let Some(literal) = id_hex_literal { + ObjectID::from_hex_literal(literal).unwrap() + } else { + ObjectID::from_hex_literal(default_hex).unwrap() + }; + + Coin { + coin_type: coin_type_string, + coin_object_id: object_id, + version: SequenceNumber::from_u64(1), + digest: ObjectDigest::from(arr), + balance, + previous_transaction: TransactionDigest::from(arr), + } + } + + fn get_test_treasury_cap_peripherals( + package_id: ObjectID, + ) -> (String, StructTag, StructTag, TreasuryCap, Object) { + let coin_name = get_test_coin_type(package_id); + let input_coin_struct = parse_iota_struct_tag(&coin_name).expect("should not fail"); + let treasury_cap_struct = TreasuryCap::type_(input_coin_struct.clone()); + let treasury_cap = TreasuryCap { + id: UID::new(get_test_package_id()), + total_supply: Supply { value: 420 }, + }; + let treasury_cap_object = + Object::treasury_cap_for_testing(input_coin_struct.clone(), treasury_cap.clone()); + ( + coin_name, + input_coin_struct, + treasury_cap_struct, + treasury_cap, + treasury_cap_object, + ) + } + + mod get_coins_tests { + use jsonrpsee::types::ErrorObjectOwned; + + use super::{super::*, *}; + + // Success scenarios + #[tokio::test] + async fn test_gas_coin_no_cursor() { + let owner = get_test_owner(); + let gas_coin = get_test_coin(None, CoinType::Gas); + let gas_coin_clone = gas_coin.clone(); + let mut mock_state = MockStateRead::new(); + mock_state + .expect_get_owned_coins() + .with( + predicate::eq(owner), + predicate::eq((GAS::type_().to_string(), ObjectID::ZERO)), + predicate::eq(51), + predicate::eq(true), + ) + .return_once(move |_, _, _, _| Ok(vec![gas_coin_clone])); + + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api.get_coins(owner, None, None, None).await; + assert!(response.is_ok()); + let result = response.unwrap(); + assert_eq!( + result, + CoinPage { + data: vec![gas_coin.clone()], + next_cursor: Some(gas_coin.coin_object_id), + has_next_page: false, + } + ); + } + + #[tokio::test] + async fn test_gas_coin_with_cursor() { + let owner = get_test_owner(); + let limit = 2; + let coins = vec![ + get_test_coin(Some("0xA"), CoinType::Gas), + get_test_coin(Some("0xAA"), CoinType::Gas), + get_test_coin(Some("0xAAA"), CoinType::Gas), + ]; + let coins_clone = coins.clone(); + let mut mock_state = MockStateRead::new(); + mock_state + .expect_get_owned_coins() + .with( + predicate::eq(owner), + predicate::eq((GAS::type_().to_string(), coins[0].coin_object_id)), + predicate::eq(limit + 1), + predicate::eq(true), + ) + .return_once(move |_, _, _, _| Ok(coins_clone)); + + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_coins(owner, None, Some(coins[0].coin_object_id), Some(limit)) + .await; + assert!(response.is_ok()); + let result = response.unwrap(); + assert_eq!( + result, + CoinPage { + data: coins[..limit].to_vec(), + next_cursor: Some(coins[limit - 1].coin_object_id), + has_next_page: true, + } + ); + } + + #[tokio::test] + async fn test_coin_no_cursor() { + let coin = get_test_coin(None, CoinType::Usdc); + let coin_clone = coin.clone(); + // Build request params + let owner = get_test_owner(); + let coin_type = coin.coin_type.clone(); + + let coin_type_tag = + TypeTag::Struct(Box::new(parse_iota_struct_tag(&coin.coin_type).unwrap())); + let mut mock_state = MockStateRead::new(); + mock_state + .expect_get_owned_coins() + .with( + predicate::eq(owner), + predicate::eq((coin_type_tag.to_string(), ObjectID::ZERO)), + predicate::eq(51), + predicate::eq(true), + ) + .return_once(move |_, _, _, _| Ok(vec![coin_clone])); + + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_coins(owner, Some(coin_type), None, None) + .await; + + assert!(response.is_ok()); + let result = response.unwrap(); + assert_eq!( + result, + CoinPage { + data: vec![coin.clone()], + next_cursor: Some(coin.coin_object_id), + has_next_page: false, + } + ); + } + + #[tokio::test] + async fn test_coin_with_cursor() { + let coins = vec![ + get_test_coin(Some("0xB"), CoinType::Usdc), + get_test_coin(Some("0xBB"), CoinType::Usdc), + get_test_coin(Some("0xBBB"), CoinType::Usdc), + ]; + let coins_clone = coins.clone(); + // Build request params + let owner = get_test_owner(); + let coin_type = coins[0].coin_type.clone(); + let cursor = coins[0].coin_object_id; + let limit = 2; + + let coin_type_tag = TypeTag::Struct(Box::new( + parse_iota_struct_tag(&coins[0].coin_type).unwrap(), + )); + let mut mock_state = MockStateRead::new(); + mock_state + .expect_get_owned_coins() + .with( + predicate::eq(owner), + predicate::eq((coin_type_tag.to_string(), coins[0].coin_object_id)), + predicate::eq(limit + 1), + predicate::eq(true), + ) + .return_once(move |_, _, _, _| Ok(coins_clone)); + + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_coins(owner, Some(coin_type), Some(cursor), Some(limit)) + .await; + + assert!(response.is_ok()); + let result = response.unwrap(); + assert_eq!( + result, + CoinPage { + data: coins[..limit].to_vec(), + next_cursor: Some(coins[limit - 1].coin_object_id), + has_next_page: true, + } + ); + } + + // Expected error scenarios + #[tokio::test] + async fn test_invalid_coin_type() { + let owner = get_test_owner(); + let coin_type = "0x2::invalid::struct::tag"; + let mock_state = MockStateRead::new(); + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_coins(owner, Some(coin_type.to_string()), None, None) + .await; + + assert!(response.is_err()); + let error_result = response.unwrap_err(); + let error_object: ErrorObjectOwned = error_result.into(); + let expected = expect!["-32602"]; + expected.assert_eq(&error_object.code().to_string()); + let expected = expect![ + "Invalid struct type: 0x2::invalid::struct::tag. Got error: Expected end of token stream. Got: ::" + ]; + expected.assert_eq(error_object.message()); + } + + #[tokio::test] + async fn test_unrecognized_token() { + let owner = get_test_owner(); + let coin_type = "0x2::iota:🤵"; + let mock_state = MockStateRead::new(); + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_coins(owner, Some(coin_type.to_string()), None, None) + .await; + + assert!(response.is_err()); + let error_result = response.unwrap_err(); + let error_object: ErrorObjectOwned = error_result.into(); + let expected = expect!["-32602"]; + expected.assert_eq(&error_object.code().to_string()); + let expected = + expect!["Invalid struct type: 0x2::iota:🤵. Got error: unrecognized token: :🤵"]; + expected.assert_eq(error_object.message()); + } + + // Unexpected error scenarios + #[tokio::test] + async fn test_get_coins_iterator_index_store_not_available() { + let owner = get_test_owner(); + let coin_type = get_test_coin_type(get_test_package_id()); + let mut mock_state = MockStateRead::new(); + mock_state + .expect_get_owned_coins() + .returning(move |_, _, _, _| { + Err(StateReadError::Client( + IotaError::IndexStoreNotAvailable.into(), + )) + }); + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_coins(owner, Some(coin_type.to_string()), None, None) + .await; + + assert!(response.is_err()); + let error_result = response.unwrap_err(); + let error_object: ErrorObjectOwned = error_result.into(); + assert_eq!( + error_object.code(), + jsonrpsee::types::error::INVALID_PARAMS_CODE + ); + let expected = expect!["Index store not available on this Fullnode."]; + expected.assert_eq(error_object.message()); + } + + #[tokio::test] + async fn test_get_coins_iterator_typed_store_error() { + let owner = get_test_owner(); + let coin_type = get_test_coin_type(get_test_package_id()); + let mut mock_state = MockStateRead::new(); + mock_state + .expect_get_owned_coins() + .returning(move |_, _, _, _| { + Err(IotaError::Storage("mock rocksdb error".to_string()).into()) + }); + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_coins(owner, Some(coin_type.to_string()), None, None) + .await; + + assert!(response.is_err()); + let error_result = response.unwrap_err(); + let error_object: ErrorObjectOwned = error_result.into(); + assert_eq!( + error_object.code(), + jsonrpsee::types::error::INTERNAL_ERROR_CODE + ); + let expected = expect!["Storage error: mock rocksdb error"]; + expected.assert_eq(error_object.message()); + } + } + + mod get_all_coins_tests { + use iota_types::object::{MoveObject, Owner}; + + use super::{super::*, *}; + + // Success scenarios + #[tokio::test] + async fn test_no_cursor() { + let owner = get_test_owner(); + let gas_coin = get_test_coin(None, CoinType::Gas); + let gas_coin_clone = gas_coin.clone(); + let mut mock_state = MockStateRead::new(); + mock_state + .expect_get_owned_coins() + .with( + predicate::eq(owner), + predicate::eq((String::from_utf8([0u8].to_vec()).unwrap(), ObjectID::ZERO)), + predicate::eq(51), + predicate::eq(false), + ) + .return_once(move |_, _, _, _| Ok(vec![gas_coin_clone])); + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_all_coins(owner, None, Some(51)) + .await + .unwrap(); + assert_eq!(response.data.len(), 1); + assert_eq!(response.data[0], gas_coin); + } + + #[tokio::test] + async fn test_with_cursor() { + let owner = get_test_owner(); + let limit = 2; + let coins = vec![ + get_test_coin(Some("0xA"), CoinType::Gas), + get_test_coin(Some("0xAA"), CoinType::Gas), + get_test_coin(Some("0xAAA"), CoinType::Gas), + ]; + let coins_clone = coins.clone(); + let coin_move_object = MoveObject::new_gas_coin( + coins[0].version, + coins[0].coin_object_id, + coins[0].balance, + ); + let coin_object = Object::new_move( + coin_move_object, + Owner::Immutable, + coins[0].previous_transaction, + ); + let mut mock_state = MockStateRead::new(); + mock_state + .expect_get_object() + .return_once(move |_| Ok(Some(coin_object))); + mock_state + .expect_get_owned_coins() + .with( + predicate::eq(owner), + predicate::eq((coins[0].coin_type.clone(), coins[0].coin_object_id)), + predicate::eq(limit + 1), + predicate::eq(false), + ) + .return_once(move |_, _, _, _| Ok(coins_clone)); + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_all_coins(owner, Some(coins[0].coin_object_id), Some(limit)) + .await + .unwrap(); + assert_eq!(response.data.len(), limit); + assert_eq!(response.data, coins[..limit].to_vec()); + } + + // Expected error scenarios + #[tokio::test] + async fn test_object_is_not_coin() { + let owner = get_test_owner(); + let object_id = get_test_package_id(); + let (_, _, _, _, treasury_cap_object) = get_test_treasury_cap_peripherals(object_id); + let mut mock_state = MockStateRead::new(); + mock_state.expect_get_object().returning(move |obj_id| { + if obj_id == &object_id { + Ok(Some(treasury_cap_object.clone())) + } else { + panic!("should not be called with any other object id") + } + }); + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_all_coins(owner, Some(object_id), None) + .await; + + assert!(response.is_err()); + let error_result = response.unwrap_err(); + let error_object: ErrorObjectOwned = error_result.into(); + assert_eq!(error_object.code(), -32602); + let expected = expect!["-32602"]; + expected.assert_eq(&error_object.code().to_string()); + let expected = expect!["cursor is not a coin"]; + expected.assert_eq(error_object.message()); + } + + #[tokio::test] + async fn test_object_not_found() { + let owner = get_test_owner(); + let object_id = get_test_package_id(); + let mut mock_state = MockStateRead::new(); + mock_state.expect_get_object().returning(move |_| Ok(None)); + + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_all_coins(owner, Some(object_id), None) + .await; + + assert!(response.is_err()); + let error_result = response.unwrap_err(); + let error_object: ErrorObjectOwned = error_result.into(); + let expected = expect!["-32602"]; + expected.assert_eq(&error_object.code().to_string()); + let expected = expect!["cursor not found"]; + expected.assert_eq(error_object.message()); + } + } + + mod get_balance_tests { + use jsonrpsee::types::ErrorObjectOwned; + + use super::{super::*, *}; + // Success scenarios + #[tokio::test] + async fn test_gas_coin() { + let owner = get_test_owner(); + let gas_coin = get_test_coin(None, CoinType::Gas); + let gas_coin_clone = gas_coin.clone(); + let mut mock_state = MockStateRead::new(); + mock_state + .expect_get_balance() + .with( + predicate::eq(owner), + predicate::eq(get_test_coin_type_tag(gas_coin_clone.coin_type)), + ) + .return_once(move |_, _| { + Ok(TotalBalance { + balance: 7, + num_coins: 9, + }) + }); + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api.get_balance(owner, None).await; + + assert!(response.is_ok()); + let result = response.unwrap(); + assert_eq!( + result, + Balance { + coin_type: gas_coin.coin_type, + coin_object_count: 9, + total_balance: 7, + locked_balance: Default::default() + } + ); + } + + #[tokio::test] + async fn test_with_coin_type() { + let owner = get_test_owner(); + let coin = get_test_coin(None, CoinType::Usdc); + let coin_clone = coin.clone(); + let mut mock_state = MockStateRead::new(); + mock_state + .expect_get_balance() + .with( + predicate::eq(owner), + predicate::eq(get_test_coin_type_tag(coin_clone.coin_type)), + ) + .return_once(move |_, _| { + Ok(TotalBalance { + balance: 10, + num_coins: 11, + }) + }); + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_balance(owner, Some(coin.coin_type.clone())) + .await; + + assert!(response.is_ok()); + let result = response.unwrap(); + assert_eq!( + result, + Balance { + coin_type: coin.coin_type, + coin_object_count: 11, + total_balance: 10, + locked_balance: Default::default() + } + ); + } + + // Expected error scenarios + #[tokio::test] + async fn test_invalid_coin_type() { + let owner = get_test_owner(); + let coin_type = "0x2::invalid::struct::tag"; + let mock_state = MockStateRead::new(); + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_balance(owner, Some(coin_type.to_string())) + .await; + + assert!(response.is_err()); + let error_result = response.unwrap_err(); + let error_object: ErrorObjectOwned = error_result.into(); + let expected = expect!["-32602"]; + expected.assert_eq(&error_object.code().to_string()); + let expected = expect![ + "Invalid struct type: 0x2::invalid::struct::tag. Got error: Expected end of token stream. Got: ::" + ]; + expected.assert_eq(error_object.message()); + } + + // Unexpected error scenarios + #[tokio::test] + async fn test_get_balance_index_store_not_available() { + let owner = get_test_owner(); + let coin_type = get_test_coin_type(get_test_package_id()); + let mut mock_state = MockStateRead::new(); + mock_state.expect_get_balance().returning(move |_, _| { + Err(StateReadError::Client( + IotaError::IndexStoreNotAvailable.into(), + )) + }); + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_balance(owner, Some(coin_type.to_string())) + .await; + + assert!(response.is_err()); + let error_result = response.unwrap_err(); + let error_object: ErrorObjectOwned = error_result.into(); + assert_eq!( + error_object.code(), + jsonrpsee::types::error::INVALID_PARAMS_CODE + ); + let expected = expect!["Index store not available on this Fullnode."]; + expected.assert_eq(error_object.message()); + } + + #[tokio::test] + async fn test_get_balance_execution_error() { + // Validate that we handle and return an error message when we encounter an + // unexpected error + let owner = get_test_owner(); + let coin_type = get_test_coin_type(get_test_package_id()); + let mut mock_state = MockStateRead::new(); + mock_state.expect_get_balance().returning(move |_, _| { + Err(IotaError::ExecutionError("mock db error".to_string()).into()) + }); + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_balance(owner, Some(coin_type.to_string())) + .await; + + assert!(response.is_err()); + let error_result = response.unwrap_err(); + let error_object: ErrorObjectOwned = error_result.into(); + + assert_eq!( + error_object.code(), + jsonrpsee::types::error::INTERNAL_ERROR_CODE + ); + let expected = expect!["Error executing mock db error"]; + expected.assert_eq(error_object.message()); + } + } + + mod get_all_balances_tests { + use jsonrpsee::types::ErrorObjectOwned; + + use super::{super::*, *}; + + // Success scenarios + #[tokio::test] + async fn test_success_scenario() { + let owner = get_test_owner(); + let gas_coin = get_test_coin(None, CoinType::Gas); + let gas_coin_type_tag = get_test_coin_type_tag(gas_coin.coin_type.clone()); + let usdc_coin = get_test_coin(None, CoinType::Usdc); + let usdc_coin_type_tag = get_test_coin_type_tag(usdc_coin.coin_type.clone()); + let mut mock_state = MockStateRead::new(); + mock_state + .expect_get_all_balance() + .with(predicate::eq(owner)) + .return_once(move |_| { + let mut hash_map = HashMap::new(); + hash_map.insert( + gas_coin_type_tag, + TotalBalance { + balance: 7, + num_coins: 9, + }, + ); + hash_map.insert( + usdc_coin_type_tag, + TotalBalance { + balance: 10, + num_coins: 11, + }, + ); + Ok(Arc::new(hash_map)) + }); + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api.get_all_balances(owner).await; + + assert!(response.is_ok()); + let expected_result = vec![ + Balance { + coin_type: gas_coin.coin_type, + coin_object_count: 9, + total_balance: 7, + locked_balance: Default::default(), + }, + Balance { + coin_type: usdc_coin.coin_type, + coin_object_count: 11, + total_balance: 10, + locked_balance: Default::default(), + }, + ]; + // This is because the underlying result is a hashmap, so order is not + // guaranteed + let mut result = response.unwrap(); + for item in expected_result { + if let Some(pos) = result.iter().position(|i| *i == item) { + result.remove(pos); + } else { + panic!("{:?} not found in result", item); + } + } + assert!(result.is_empty()); + } + + // Unexpected error scenarios + #[tokio::test] + async fn test_index_store_not_available() { + let owner = get_test_owner(); + let mut mock_state = MockStateRead::new(); + mock_state.expect_get_all_balance().returning(move |_| { + Err(StateReadError::Client( + IotaError::IndexStoreNotAvailable.into(), + )) + }); + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api.get_all_balances(owner).await; + + assert!(response.is_err()); + let error_result = response.unwrap_err(); + let error_object: ErrorObjectOwned = error_result.into(); + assert_eq!( + error_object.code(), + jsonrpsee::types::error::INVALID_PARAMS_CODE + ); + let expected = expect!["Index store not available on this Fullnode."]; + expected.assert_eq(error_object.message()); + } + } + + mod get_coin_metadata_tests { + use iota_types::id::UID; + use mockall::predicate; + + use super::{super::*, *}; + + // Success scenarios + #[tokio::test] + async fn test_valid_coin_metadata_object() { + let package_id = get_test_package_id(); + let coin_name = get_test_coin_type(package_id); + let input_coin_struct = parse_iota_struct_tag(&coin_name).expect("should not fail"); + let coin_metadata_struct = CoinMetadata::type_(input_coin_struct.clone()); + let coin_metadata = CoinMetadata { + id: UID::new(get_test_package_id()), + decimals: 2, + name: "test_coin".to_string(), + symbol: "TEST".to_string(), + description: "test coin".to_string(), + icon_url: Some("unit.test.io".to_string()), + }; + let coin_metadata_object = + Object::coin_metadata_for_testing(input_coin_struct.clone(), coin_metadata); + let metadata = IotaCoinMetadata::try_from(coin_metadata_object.clone()).unwrap(); + let mut mock_internal = MockCoinReadInternal::new(); + // return TreasuryCap instead of CoinMetadata to set up test + mock_internal + .expect_find_package_object() + .with(predicate::always(), predicate::eq(coin_metadata_struct)) + .return_once(move |object_id, _| { + if object_id == &package_id { + Ok(coin_metadata_object) + } else { + panic!("should not be called with any other object id") + } + }); + + let coin_read_api = CoinReadApi { + internal: Box::new(mock_internal), + }; + + let response = coin_read_api.get_coin_metadata(coin_name.clone()).await; + assert!(response.is_ok()); + let result = response.unwrap().unwrap(); + assert_eq!(result, metadata); + } + + #[tokio::test] + async fn test_object_not_found() { + let transaction_digest = TransactionDigest::from([0; 32]); + let transaction_effects = TransactionEffects::default(); + + let mut mock_state = MockStateRead::new(); + mock_state + .expect_find_publish_txn_digest() + .return_once(move |_| Ok(transaction_digest)); + mock_state + .expect_get_executed_transaction_and_effects() + .return_once(move |_, _| Ok((create_fake_transaction(), transaction_effects))); + + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api + .get_coin_metadata("0x2::iota::IOTA".to_string()) + .await; + + assert!(response.is_ok()); + let result = response.unwrap(); + assert_eq!(result, None); + } + + #[tokio::test] + async fn test_find_package_object_not_iota_coin_metadata() { + let package_id = get_test_package_id(); + let coin_name = get_test_coin_type(package_id); + let input_coin_struct = parse_iota_struct_tag(&coin_name).expect("should not fail"); + let coin_metadata_struct = CoinMetadata::type_(input_coin_struct.clone()); + let treasury_cap = TreasuryCap { + id: UID::new(get_test_package_id()), + total_supply: Supply { value: 420 }, + }; + let treasury_cap_object = + Object::treasury_cap_for_testing(input_coin_struct.clone(), treasury_cap); + let mut mock_internal = MockCoinReadInternal::new(); + // return TreasuryCap instead of CoinMetadata to set up test + mock_internal + .expect_find_package_object() + .with(predicate::always(), predicate::eq(coin_metadata_struct)) + .returning(move |object_id, _| { + if object_id == &package_id { + Ok(treasury_cap_object.clone()) + } else { + panic!("should not be called with any other object id") + } + }); + + let coin_read_api = CoinReadApi { + internal: Box::new(mock_internal), + }; + + let response = coin_read_api.get_coin_metadata(coin_name.clone()).await; + assert!(response.is_ok()); + let result = response.unwrap(); + assert!(result.is_none()); + } + } + + mod get_total_supply_tests { + use iota_types::id::UID; + use mockall::predicate; + + use super::{super::*, *}; + + #[tokio::test] + async fn test_success_response_for_gas_coin() { + let coin_type = "0x2::iota::IOTA"; + let mock_internal = MockCoinReadInternal::new(); + let coin_read_api = CoinReadApi { + internal: Box::new(mock_internal), + }; + + let response = coin_read_api.get_total_supply(coin_type.to_string()).await; + + let supply = response.unwrap(); + let expected = expect!["10000000000000000000"]; + expected.assert_eq(&supply.value.to_string()); + } + + #[tokio::test] + async fn test_success_response_for_other_coin() { + let package_id = get_test_package_id(); + let (coin_name, _, treasury_cap_struct, _, treasury_cap_object) = + get_test_treasury_cap_peripherals(package_id); + let mut mock_internal = MockCoinReadInternal::new(); + mock_internal + .expect_find_package_object() + .with(predicate::always(), predicate::eq(treasury_cap_struct)) + .returning(move |object_id, _| { + if object_id == &package_id { + Ok(treasury_cap_object.clone()) + } else { + panic!("should not be called with any other object id") + } + }); + let coin_read_api = CoinReadApi { + internal: Box::new(mock_internal), + }; + + let response = coin_read_api.get_total_supply(coin_name.clone()).await; + + assert!(response.is_ok()); + let result = response.unwrap(); + let expected = expect!["420"]; + expected.assert_eq(&result.value.to_string()); + } + + #[tokio::test] + async fn test_object_not_found() { + let package_id = get_test_package_id(); + let (coin_name, _, _, _, _) = get_test_treasury_cap_peripherals(package_id); + let transaction_digest = TransactionDigest::from([0; 32]); + let transaction_effects = TransactionEffects::default(); + + let mut mock_state = MockStateRead::new(); + mock_state + .expect_find_publish_txn_digest() + .return_once(move |_| Ok(transaction_digest)); + mock_state + .expect_get_executed_transaction_and_effects() + .return_once(move |_, _| Ok((create_fake_transaction(), transaction_effects))); + + let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); + let response = coin_read_api.get_total_supply(coin_name.clone()).await; + + assert!(response.is_err()); + let error_result = response.unwrap_err(); + let error_object: ErrorObjectOwned = error_result.into(); + let expected = expect!["-32602"]; + expected.assert_eq(&error_object.code().to_string()); + let expected = expect![ + "Cannot find object [0x2::coin::TreasuryCap<0xf::test_coin::TEST_COIN>] from [0x000000000000000000000000000000000000000000000000000000000000000f] package event." + ]; + expected.assert_eq(error_object.message()); + } + + #[tokio::test] + async fn test_find_package_object_not_treasury_cap() { + let package_id = get_test_package_id(); + let (coin_name, input_coin_struct, treasury_cap_struct, _, _) = + get_test_treasury_cap_peripherals(package_id); + let coin_metadata = CoinMetadata { + id: UID::new(get_test_package_id()), + decimals: 2, + name: "test_coin".to_string(), + symbol: "TEST".to_string(), + description: "test coin".to_string(), + icon_url: None, + }; + let coin_metadata_object = + Object::coin_metadata_for_testing(input_coin_struct.clone(), coin_metadata); + let mut mock_internal = MockCoinReadInternal::new(); + mock_internal + .expect_find_package_object() + .with(predicate::always(), predicate::eq(treasury_cap_struct)) + .returning(move |object_id, _| { + if object_id == &package_id { + Ok(coin_metadata_object.clone()) + } else { + panic!("should not be called with any other object id") + } + }); + + let coin_read_api = CoinReadApi { + internal: Box::new(mock_internal), + }; + + let response = coin_read_api.get_total_supply(coin_name.clone()).await; + let error_result = response.unwrap_err(); + let error_object: ErrorObjectOwned = error_result.into(); + assert_eq!( + error_object.code(), + jsonrpsee::types::error::CALL_EXECUTION_FAILED_CODE + ); + let expected = expect![ + "Failure deserializing object in the requested format: \"Unable to deserialize TreasuryCap object: remaining input\"" + ]; + expected.assert_eq(error_object.message()); + } + } +} diff --git a/crates/iota-json-rpc/src/error.rs b/crates/iota-json-rpc/src/error.rs new file mode 100644 index 00000000000..c5ed40942fc --- /dev/null +++ b/crates/iota-json-rpc/src/error.rs @@ -0,0 +1,527 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use fastcrypto::error::FastCryptoError; +use hyper::header::InvalidHeaderValue; +use iota_json_rpc_api::{TRANSACTION_EXECUTION_CLIENT_ERROR_CODE, TRANSIENT_ERROR_CODE}; +use iota_types::{ + error::{IotaError, IotaObjectResponseError, UserInputError}, + quorum_driver_types::QuorumDriverError, +}; +use itertools::Itertools; +use jsonrpsee::{ + core::Error as RpcError, + types::{ + error::{CallError, INTERNAL_ERROR_CODE}, + ErrorObject, + }, +}; +use thiserror::Error; +use tokio::task::JoinError; + +use crate::{authority_state::StateReadError, name_service::NameServiceError}; + +pub type RpcInterimResult = Result; + +#[derive(Debug, Error)] +pub enum Error { + #[error(transparent)] + IotaError(IotaError), + + #[error(transparent)] + InternalError(#[from] anyhow::Error), + + #[error("Deserialization error: {0}")] + BcsError(#[from] bcs::Error), + #[error("Unexpected error: {0}")] + UnexpectedError(String), + + #[error(transparent)] + RPCServerError(#[from] jsonrpsee::core::Error), + + #[error(transparent)] + InvalidHeaderValue(#[from] InvalidHeaderValue), + + #[error(transparent)] + UserInputError(#[from] UserInputError), + + #[error(transparent)] + EncodingError(#[from] eyre::Report), + + #[error(transparent)] + TokioJoinError(#[from] JoinError), + + #[error(transparent)] + QuorumDriverError(#[from] QuorumDriverError), + + #[error(transparent)] + FastCryptoError(#[from] FastCryptoError), + + #[error(transparent)] + IotaObjectResponseError(#[from] IotaObjectResponseError), + + #[error(transparent)] + IotaRpcInputError(#[from] IotaRpcInputError), + + // TODO(wlmyng): convert StateReadError::Internal message to generic internal error message. + #[error(transparent)] + StateReadError(#[from] StateReadError), + + #[error("Unsupported Feature: {0}")] + UnsupportedFeature(String), + + #[error("transparent")] + NameServiceError(#[from] NameServiceError), +} + +impl From for Error { + fn from(e: IotaError) -> Self { + match e { + IotaError::UserInputError { error } => Self::UserInputError(error), + IotaError::IotaObjectResponseError { error } => Self::IotaObjectResponseError(error), + IotaError::UnsupportedFeatureError { error } => Self::UnsupportedFeature(error), + IotaError::IndexStoreNotAvailable => Self::UnsupportedFeature( + "Required indexes are not available on this node".to_string(), + ), + other => Self::IotaError(other), + } + } +} + +impl From for RpcError { + /// `InvalidParams`/`INVALID_PARAMS_CODE` for client errors. + fn from(e: Error) -> RpcError { + match e { + Error::UserInputError(_) => RpcError::Call(CallError::InvalidParams(e.into())), + Error::UnsupportedFeature(_) => RpcError::Call(CallError::InvalidParams(e.into())), + Error::IotaObjectResponseError(err) => match err { + IotaObjectResponseError::NotExists { .. } + | IotaObjectResponseError::DynamicFieldNotFound { .. } + | IotaObjectResponseError::Deleted { .. } + | IotaObjectResponseError::DisplayError { .. } => { + RpcError::Call(CallError::InvalidParams(err.into())) + } + _ => RpcError::Call(CallError::Failed(err.into())), + }, + Error::NameServiceError(err) => match err { + NameServiceError::ExceedsMaxLength { .. } + | NameServiceError::InvalidHyphens { .. } + | NameServiceError::InvalidLength { .. } + | NameServiceError::InvalidUnderscore { .. } + | NameServiceError::LabelsEmpty { .. } + | NameServiceError::InvalidSeparator { .. } => { + RpcError::Call(CallError::InvalidParams(err.into())) + } + _ => RpcError::Call(CallError::Failed(err.into())), + }, + Error::IotaRpcInputError(err) => RpcError::Call(CallError::InvalidParams(err.into())), + Error::IotaError(iota_error) => match iota_error { + IotaError::TransactionNotFound { .. } + | IotaError::TransactionsNotFound { .. } + | IotaError::TransactionEventsNotFound { .. } => { + RpcError::Call(CallError::InvalidParams(iota_error.into())) + } + _ => RpcError::Call(CallError::Failed(iota_error.into())), + }, + Error::StateReadError(err) => match err { + StateReadError::Client(_) => RpcError::Call(CallError::InvalidParams(err.into())), + _ => { + let error_object = ErrorObject::owned( + jsonrpsee::types::error::INTERNAL_ERROR_CODE, + err.to_string(), + None::<()>, + ); + RpcError::Call(CallError::Custom(error_object)) + } + }, + Error::QuorumDriverError(err) => { + match err { + QuorumDriverError::InvalidUserSignature(err) => { + let inner_error_str = match err { + // TODO(wlmyng): update IotaError display trait to render UserInputError + // with display + IotaError::UserInputError { error } => error.to_string(), + _ => err.to_string(), + }; + + let error_message = format!("Invalid user signature: {inner_error_str}"); + + let error_object = ErrorObject::owned( + TRANSACTION_EXECUTION_CLIENT_ERROR_CODE, + error_message, + None::<()>, + ); + RpcError::Call(CallError::Custom(error_object)) + } + QuorumDriverError::TxAlreadyFinalizedWithDifferentUserSignatures => { + let error_object = ErrorObject::owned( + TRANSACTION_EXECUTION_CLIENT_ERROR_CODE, + "The transaction is already finalized but with different user signatures", + None::<()>, + ); + RpcError::Call(CallError::Custom(error_object)) + } + QuorumDriverError::TimeoutBeforeFinality + | QuorumDriverError::FailedWithTransientErrorAfterMaximumAttempts { .. } => { + let error_object = + ErrorObject::owned(TRANSIENT_ERROR_CODE, err.to_string(), None::<()>); + RpcError::Call(CallError::Custom(error_object)) + } + QuorumDriverError::ObjectsDoubleUsed { + conflicting_txes, + retried_tx, + retried_tx_success, + } => { + let error_message = format!( + "Failed to sign transaction by a quorum of validators because of locked objects. Retried a conflicting transaction {:?}, success: {:?}", + retried_tx, retried_tx_success + ); + + let new_map = conflicting_txes + .into_iter() + .map(|(digest, (pairs, _))| { + ( + digest, + pairs.into_iter().map(|(_, obj_ref)| obj_ref).collect(), + ) + }) + .collect::>>(); + + let error_object = ErrorObject::owned( + TRANSACTION_EXECUTION_CLIENT_ERROR_CODE, + error_message, + Some(new_map), + ); + RpcError::Call(CallError::Custom(error_object)) + } + QuorumDriverError::NonRecoverableTransactionError { errors } => { + let new_errors: Vec = errors + .into_iter() + // sort by total stake, descending, so users see the most prominent one + // first + .sorted_by(|(_, a, _), (_, b, _)| b.cmp(a)) + .filter_map(|(err, _, _)| { + match &err { + // Special handling of UserInputError: + // ObjectNotFound and DependentPackageNotFound are considered + // retryable errors but they have different treatment + // in AuthorityAggregator. + // The optimal fix would be to examine if the total stake + // of ObjectNotFound/DependentPackageNotFound exceeds the + // quorum threshold, but it takes a Committee here. + // So, we take an easier route and consider them non-retryable + // at all. Combining this with the sorting above, clients will + // see the dominant error first. + IotaError::UserInputError { error } => Some(error.to_string()), + _ => { + if err.is_retryable().0 { + None + } else { + Some(err.to_string()) + } + } + } + }) + .collect(); + + assert!( + !new_errors.is_empty(), + "NonRecoverableTransactionError should have at least one non-retryable error" + ); + + let error_list = new_errors.join(", "); + let error_msg = format!( + "Transaction execution failed due to issues with transaction inputs, please review the errors and try again: {}.", + error_list + ); + + let error_object = ErrorObject::owned( + TRANSACTION_EXECUTION_CLIENT_ERROR_CODE, + error_msg, + None::<()>, + ); + RpcError::Call(CallError::Custom(error_object)) + } + QuorumDriverError::QuorumDriverInternalError(_) => { + let error_object = ErrorObject::owned( + INTERNAL_ERROR_CODE, + "Internal error occurred while executing transaction.", + None::<()>, + ); + RpcError::Call(CallError::Custom(error_object)) + } + QuorumDriverError::SystemOverload { .. } + | QuorumDriverError::SystemOverloadRetryAfter { .. } => { + let error_object = + ErrorObject::owned(TRANSIENT_ERROR_CODE, err.to_string(), None::<()>); + RpcError::Call(CallError::Custom(error_object)) + } + } + } + _ => RpcError::Call(CallError::Failed(e.into())), + } + } +} + +#[derive(Debug, Error)] +pub enum IotaRpcInputError { + #[error("Input contains duplicates")] + ContainsDuplicates, + + #[error("Input exceeds limit of {0}")] + SizeLimitExceeded(String), + + #[error("{0}")] + GenericNotFound(String), + + #[error("{0}")] + GenericInvalid(String), + + #[error( + "request_type` must set to `None` or `WaitForLocalExecution` if effects is required in the response" + )] + InvalidExecuteTransactionRequestType, + + #[error("Unsupported protocol version requested. Min supported: {0}, max supported: {1}")] + ProtocolVersionUnsupported(u64, u64), + + #[error("{0}")] + CannotParseIotaStructTag(String), + + #[error(transparent)] + Base64(#[from] eyre::Report), + + #[error("Deserialization error: {0}")] + Bcs(#[from] bcs::Error), + + #[error(transparent)] + FastCryptoError(#[from] FastCryptoError), + + #[error(transparent)] + Anyhow(#[from] anyhow::Error), + + #[error(transparent)] + UserInputError(#[from] UserInputError), +} + +impl From for RpcError { + fn from(e: IotaRpcInputError) -> Self { + RpcError::Call(CallError::InvalidParams(e.into())) + } +} + +#[cfg(test)] +mod tests { + use expect_test::expect; + use iota_types::{ + base_types::{AuthorityName, ObjectID, ObjectRef, SequenceNumber}, + committee::StakeUnit, + crypto::{AuthorityPublicKey, AuthorityPublicKeyBytes}, + digests::{ObjectDigest, TransactionDigest}, + }; + use jsonrpsee::types::ErrorObjectOwned; + + use super::*; + + fn test_object_ref() -> ObjectRef { + ( + ObjectID::ZERO, + SequenceNumber::from_u64(0), + ObjectDigest::new([0; 32]), + ) + } + + mod match_quorum_driver_error_tests { + use super::*; + + #[test] + fn test_invalid_user_signature() { + let quorum_driver_error = + QuorumDriverError::InvalidUserSignature(IotaError::InvalidSignature { + error: "Test inner invalid signature".to_string(), + }); + + let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); + + let error_object: ErrorObjectOwned = rpc_error.into(); + let expected_code = expect!["-32002"]; + expected_code.assert_eq(&error_object.code().to_string()); + let expected_message = expect![ + "Invalid user signature: Signature is not valid: Test inner invalid signature" + ]; + expected_message.assert_eq(error_object.message()); + } + + #[test] + fn test_timeout_before_finality() { + let quorum_driver_error = QuorumDriverError::TimeoutBeforeFinality; + + let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); + + let error_object: ErrorObjectOwned = rpc_error.into(); + let expected_code = expect!["-32050"]; + expected_code.assert_eq(&error_object.code().to_string()); + let expected_message = expect!["Transaction timed out before reaching finality"]; + expected_message.assert_eq(error_object.message()); + } + + #[test] + fn test_failed_with_transient_error_after_maximum_attempts() { + let quorum_driver_error = + QuorumDriverError::FailedWithTransientErrorAfterMaximumAttempts { + total_attempts: 10, + }; + + let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); + + let error_object: ErrorObjectOwned = rpc_error.into(); + let expected_code = expect!["-32050"]; + expected_code.assert_eq(&error_object.code().to_string()); + let expected_message = expect![ + "Transaction failed to reach finality with transient error after 10 attempts." + ]; + expected_message.assert_eq(error_object.message()); + } + + #[test] + fn test_objects_double_used() { + use iota_types::crypto::VerifyingKey; + let mut conflicting_txes: BTreeMap< + TransactionDigest, + (Vec<(AuthorityName, ObjectRef)>, StakeUnit), + > = BTreeMap::new(); + let tx_digest = TransactionDigest::default(); + let object_ref = test_object_ref(); + let stake_unit: StakeUnit = 10; + let authority_name = AuthorityPublicKeyBytes([0; AuthorityPublicKey::LENGTH]); + conflicting_txes.insert(tx_digest, (vec![(authority_name, object_ref)], stake_unit)); + + let quorum_driver_error = QuorumDriverError::ObjectsDoubleUsed { + conflicting_txes, + retried_tx: Some(TransactionDigest::default()), + retried_tx_success: Some(true), + }; + + let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); + + let error_object: ErrorObjectOwned = rpc_error.into(); + let expected_code = expect!["-32002"]; + expected_code.assert_eq(&error_object.code().to_string()); + let expected_message = expect![ + "Failed to sign transaction by a quorum of validators because of locked objects. Retried a conflicting transaction Some(TransactionDigest(11111111111111111111111111111111)), success: Some(true)" + ]; + expected_message.assert_eq(error_object.message()); + let expected_data = expect![[ + r#"{"11111111111111111111111111111111":[["0x0000000000000000000000000000000000000000000000000000000000000000",0,"11111111111111111111111111111111"]]}"# + ]]; + let actual_data = error_object.data().unwrap().to_string(); + expected_data.assert_eq(&actual_data); + } + + #[test] + fn test_non_recoverable_transaction_error() { + let quorum_driver_error = QuorumDriverError::NonRecoverableTransactionError { + errors: vec![ + ( + IotaError::UserInputError { + error: UserInputError::GasBalanceTooLow { + gas_balance: 10, + needed_gas_amount: 100, + }, + }, + 0, + vec![], + ), + ( + IotaError::UserInputError { + error: UserInputError::ObjectVersionUnavailableForConsumption { + provided_obj_ref: test_object_ref(), + current_version: 10.into(), + }, + }, + 0, + vec![], + ), + ], + }; + + let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); + + let error_object: ErrorObjectOwned = rpc_error.into(); + let expected_code = expect!["-32002"]; + expected_code.assert_eq(&error_object.code().to_string()); + let expected_message = expect![ + "Transaction execution failed due to issues with transaction inputs, please review the errors and try again: Balance of gas object 10 is lower than the needed amount: 100., Object (0x0000000000000000000000000000000000000000000000000000000000000000, SequenceNumber(0), o#11111111111111111111111111111111) is not available for consumption, its current version: SequenceNumber(10).." + ]; + expected_message.assert_eq(error_object.message()); + } + + #[test] + fn test_non_recoverable_transaction_error_with_transient_errors() { + let quorum_driver_error = QuorumDriverError::NonRecoverableTransactionError { + errors: vec![ + ( + IotaError::UserInputError { + error: UserInputError::ObjectNotFound { + object_id: test_object_ref().0, + version: None, + }, + }, + 0, + vec![], + ), + ( + IotaError::RpcError("Hello".to_string(), "Testing".to_string()), + 0, + vec![], + ), + ], + }; + + let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); + + let error_object: ErrorObjectOwned = rpc_error.into(); + let expected_code = expect!["-32002"]; + expected_code.assert_eq(&error_object.code().to_string()); + let expected_message = expect![ + "Transaction execution failed due to issues with transaction inputs, please review the errors and try again: Could not find the referenced object 0x0000000000000000000000000000000000000000000000000000000000000000 at version None.." + ]; + expected_message.assert_eq(error_object.message()); + } + + #[test] + fn test_quorum_driver_internal_error() { + let quorum_driver_error = + QuorumDriverError::QuorumDriverInternalError(IotaError::UnexpectedMessage); + + let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); + + let error_object: ErrorObjectOwned = rpc_error.into(); + let expected_code = expect!["-32603"]; + expected_code.assert_eq(&error_object.code().to_string()); + let expected_message = expect!["Internal error occurred while executing transaction."]; + expected_message.assert_eq(error_object.message()); + } + + #[test] + fn test_system_overload() { + let quorum_driver_error = QuorumDriverError::SystemOverload { + overloaded_stake: 10, + errors: vec![(IotaError::UnexpectedMessage, 0, vec![])], + }; + + let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); + + let error_object: ErrorObjectOwned = rpc_error.into(); + let expected_code = expect!["-32050"]; + expected_code.assert_eq(&error_object.code().to_string()); + let expected_message = expect![ + "Transaction is not processed because 10 of validators by stake are overloaded with certificates pending execution." + ]; + expected_message.assert_eq(error_object.message()); + } + } +} diff --git a/crates/iota-json-rpc/src/governance_api.rs b/crates/iota-json-rpc/src/governance_api.rs new file mode 100644 index 00000000000..f56fb01cb49 --- /dev/null +++ b/crates/iota-json-rpc/src/governance_api.rs @@ -0,0 +1,643 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{cmp::max, collections::BTreeMap, sync::Arc}; + +use async_trait::async_trait; +use cached::{proc_macro::cached, SizedCache}; +use iota_core::authority::AuthorityState; +use iota_json_rpc_api::{GovernanceReadApiOpenRpc, GovernanceReadApiServer, JsonRpcMetrics}; +use iota_json_rpc_types::{ + DelegatedStake, DelegatedTimelockedStake, IotaCommittee, Stake, StakeStatus, TimelockedStake, + ValidatorApy, ValidatorApys, +}; +use iota_open_rpc::Module; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + committee::EpochId, + dynamic_field::get_dynamic_field_from_store, + error::{IotaError, UserInputError}, + governance::StakedIota, + id::ID, + iota_serde::BigInt, + iota_system_state::{ + get_validator_from_table, iota_system_state_summary::IotaSystemStateSummary, + IotaSystemState, IotaSystemStateTrait, PoolTokenExchangeRate, + }, + object::{Object, ObjectRead}, + timelock::timelocked_staked_iota::TimelockedStakedIota, +}; +use itertools::Itertools; +use jsonrpsee::{core::RpcResult, RpcModule}; +use mysten_metrics::spawn_monitored_task; +use tracing::{info, instrument}; + +use crate::{ + authority_state::StateRead, + error::{Error, IotaRpcInputError, RpcInterimResult}, + with_tracing, IotaRpcModule, ObjectProvider, +}; + +#[derive(Clone)] +pub struct GovernanceReadApi { + state: Arc, + pub metrics: Arc, +} + +impl GovernanceReadApi { + pub fn new(state: Arc, metrics: Arc) -> Self { + Self { state, metrics } + } + + async fn get_staked_iota(&self, owner: IotaAddress) -> Result, Error> { + let state = self.state.clone(); + let result = + spawn_monitored_task!(async move { state.get_staked_iota(owner).await }).await??; + + self.metrics + .get_stake_iota_result_size + .report(result.len() as u64); + self.metrics + .get_stake_iota_result_size_total + .inc_by(result.len() as u64); + Ok(result) + } + + async fn get_timelocked_staked_iota( + &self, + owner: IotaAddress, + ) -> Result, Error> { + let state = self.state.clone(); + let result = + spawn_monitored_task!(async move { state.get_timelocked_staked_iota(owner).await }) + .await??; + + self.metrics + .get_stake_iota_result_size + .report(result.len() as u64); + self.metrics + .get_stake_iota_result_size_total + .inc_by(result.len() as u64); + Ok(result) + } + + async fn get_stakes_by_ids( + &self, + staked_iota_ids: Vec, + ) -> Result, Error> { + let state = self.state.clone(); + let stakes_read = spawn_monitored_task!(async move { + staked_iota_ids + .iter() + .map(|id| state.get_object_read(id)) + .collect::, _>>() + }) + .await??; + + if stakes_read.is_empty() { + return Ok(vec![]); + } + + let stakes: Vec<(StakedIota, bool)> = self + .stakes_with_status(stakes_read.into_iter()) + .await? + .into_iter() + .map(|(o, b)| StakedIota::try_from(&o).map(|stake| (stake, b))) + .collect::>()?; + + self.get_delegated_stakes(stakes).await + } + + async fn get_stakes(&self, owner: IotaAddress) -> Result, Error> { + let timer = self.metrics.get_stake_iota_latency.start_timer(); + let stakes = self.get_staked_iota(owner).await?; + if stakes.is_empty() { + return Ok(vec![]); + } + drop(timer); + + let _timer = self.metrics.get_delegated_iota_latency.start_timer(); + + let self_clone = self.clone(); + spawn_monitored_task!( + self_clone.get_delegated_stakes(stakes.into_iter().map(|s| (s, true)).collect()) + ) + .await? + } + + async fn get_timelocked_stakes_by_ids( + &self, + timelocked_staked_iota_ids: Vec, + ) -> Result, Error> { + let state = self.state.clone(); + let stakes_read = spawn_monitored_task!(async move { + timelocked_staked_iota_ids + .iter() + .map(|id| state.get_object_read(id)) + .collect::, _>>() + }) + .await??; + + if stakes_read.is_empty() { + return Ok(vec![]); + } + + let stakes: Vec<(TimelockedStakedIota, bool)> = self + .stakes_with_status(stakes_read.into_iter()) + .await? + .into_iter() + .map(|(o, b)| TimelockedStakedIota::try_from(&o).map(|stake| (stake, b))) + .collect::>()?; + + self.get_delegated_timelocked_stakes(stakes).await + } + + async fn get_timelocked_stakes( + &self, + owner: IotaAddress, + ) -> Result, Error> { + let timer = self.metrics.get_stake_iota_latency.start_timer(); + let stakes = self.get_timelocked_staked_iota(owner).await?; + if stakes.is_empty() { + return Ok(vec![]); + } + drop(timer); + + let _timer = self.metrics.get_delegated_iota_latency.start_timer(); + + let self_clone = self.clone(); + spawn_monitored_task!( + self_clone + .get_delegated_timelocked_stakes(stakes.into_iter().map(|s| (s, true)).collect()) + ) + .await? + } + + async fn get_delegated_stakes( + &self, + stakes: Vec<(StakedIota, bool)>, + ) -> Result, Error> { + let pools = stakes.into_iter().fold( + BTreeMap::<_, Vec<_>>::new(), + |mut pools, (stake, exists)| { + pools + .entry(stake.pool_id()) + .or_default() + .push((stake, exists)); + pools + }, + ); + + let system_state = self.get_system_state()?; + let system_state_summary: IotaSystemStateSummary = + system_state.clone().into_iota_system_state_summary(); + + let rates = exchange_rates(&self.state, system_state_summary.epoch) + .await? + .into_iter() + .map(|rates| (rates.pool_id, rates)) + .collect::>(); + + let mut delegated_stakes = vec![]; + for (pool_id, stakes) in pools { + // Rate table and rate can be null when the pool is not active + let rate_table = rates.get(&pool_id).ok_or_else(|| { + IotaRpcInputError::GenericNotFound( + "Cannot find rates for staking pool {pool_id}".to_string(), + ) + })?; + let current_rate = rate_table.rates.first().map(|(_, rate)| rate); + + let mut delegations = vec![]; + for (stake, exists) in stakes { + let status = stake_status( + system_state_summary.epoch, + stake.activation_epoch(), + stake.principal(), + exists, + current_rate, + rate_table, + ); + delegations.push(Stake { + staked_iota_id: stake.id(), + // TODO: this might change when we implement warm up period. + stake_request_epoch: stake.activation_epoch() - 1, + stake_active_epoch: stake.activation_epoch(), + principal: stake.principal(), + status, + }) + } + delegated_stakes.push(DelegatedStake { + validator_address: rate_table.address, + staking_pool: pool_id, + stakes: delegations, + }) + } + Ok(delegated_stakes) + } + + async fn get_delegated_timelocked_stakes( + &self, + stakes: Vec<(TimelockedStakedIota, bool)>, + ) -> Result, Error> { + let pools = stakes.into_iter().fold( + BTreeMap::<_, Vec<_>>::new(), + |mut pools, (stake, exists)| { + pools + .entry(stake.pool_id()) + .or_default() + .push((stake, exists)); + pools + }, + ); + + let system_state = self.get_system_state()?; + let system_state_summary: IotaSystemStateSummary = + system_state.clone().into_iota_system_state_summary(); + + let rates = exchange_rates(&self.state, system_state_summary.epoch) + .await? + .into_iter() + .map(|rates| (rates.pool_id, rates)) + .collect::>(); + + let mut delegated_stakes = vec![]; + for (pool_id, stakes) in pools { + // Rate table and rate can be null when the pool is not active + let rate_table = rates.get(&pool_id).ok_or_else(|| { + IotaRpcInputError::GenericNotFound( + "Cannot find rates for staking pool {pool_id}".to_string(), + ) + })?; + let current_rate = rate_table.rates.first().map(|(_, rate)| rate); + + let mut delegations = vec![]; + for (stake, exists) in stakes { + let status = stake_status( + system_state_summary.epoch, + stake.activation_epoch(), + stake.principal(), + exists, + current_rate, + rate_table, + ); + delegations.push(TimelockedStake { + timelocked_staked_iota_id: stake.id(), + // TODO: this might change when we implement warm up period. + stake_request_epoch: stake.activation_epoch() - 1, + stake_active_epoch: stake.activation_epoch(), + principal: stake.principal(), + status, + expiration_timestamp_ms: stake.expiration_timestamp_ms(), + }) + } + delegated_stakes.push(DelegatedTimelockedStake { + validator_address: rate_table.address, + staking_pool: pool_id, + stakes: delegations, + }) + } + Ok(delegated_stakes) + } + + async fn stakes_with_status( + &self, + iter: impl Iterator, + ) -> Result, Error> { + let mut stakes = vec![]; + + for stake in iter { + match stake { + ObjectRead::Exists(_, o, _) => stakes.push((o, true)), + ObjectRead::Deleted((object_id, version, _)) => { + let Some(o) = self + .state + .find_object_lt_or_eq_version(&object_id, &version.one_before().unwrap()) + .await? + else { + Err(IotaRpcInputError::UserInputError( + UserInputError::ObjectNotFound { + object_id, + version: None, + }, + ))? + }; + stakes.push((o, false)); + } + ObjectRead::NotExists(id) => Err(IotaRpcInputError::UserInputError( + UserInputError::ObjectNotFound { + object_id: id, + version: None, + }, + ))?, + } + } + + Ok(stakes) + } + + fn get_system_state(&self) -> Result { + Ok(self.state.get_system_state()?) + } +} + +#[async_trait] +impl GovernanceReadApiServer for GovernanceReadApi { + #[instrument(skip(self))] + async fn get_stakes_by_ids( + &self, + staked_iota_ids: Vec, + ) -> RpcResult> { + with_tracing!(async move { self.get_stakes_by_ids(staked_iota_ids).await }) + } + + #[instrument(skip(self))] + async fn get_stakes(&self, owner: IotaAddress) -> RpcResult> { + with_tracing!(async move { self.get_stakes(owner).await }) + } + + #[instrument(skip(self))] + async fn get_timelocked_stakes_by_ids( + &self, + timelocked_staked_iota_ids: Vec, + ) -> RpcResult> { + with_tracing!(async move { + self.get_timelocked_stakes_by_ids(timelocked_staked_iota_ids) + .await + }) + } + + #[instrument(skip(self))] + async fn get_timelocked_stakes( + &self, + owner: IotaAddress, + ) -> RpcResult> { + with_tracing!(async move { self.get_timelocked_stakes(owner).await }) + } + + #[instrument(skip(self))] + async fn get_committee_info(&self, epoch: Option>) -> RpcResult { + with_tracing!(async move { + self.state + .get_or_latest_committee(epoch) + .map(|committee| committee.into()) + .map_err(Error::from) + }) + } + + #[instrument(skip(self))] + async fn get_latest_iota_system_state(&self) -> RpcResult { + with_tracing!(async move { + Ok(self + .state + .get_system_state() + .map_err(Error::from)? + .into_iota_system_state_summary()) + }) + } + + #[instrument(skip(self))] + async fn get_reference_gas_price(&self) -> RpcResult> { + with_tracing!(async move { + let epoch_store = self.state.load_epoch_store_one_call_per_task(); + Ok(epoch_store.reference_gas_price().into()) + }) + } + + #[instrument(skip(self))] + async fn get_validators_apy(&self) -> RpcResult { + info!("get_validator_apy"); + let system_state_summary: IotaSystemStateSummary = + self.get_latest_iota_system_state().await?; + + let exchange_rate_table = exchange_rates(&self.state, system_state_summary.epoch) + .await + .map_err(Error::from)?; + + let apys = calculate_apys( + system_state_summary.stake_subsidy_start_epoch, + exchange_rate_table, + ); + + Ok(ValidatorApys { + apys, + epoch: system_state_summary.epoch, + }) + } +} + +pub fn calculate_apys( + stake_subsidy_start_epoch: u64, + exchange_rate_table: Vec, +) -> Vec { + let mut apys = vec![]; + + for rates in exchange_rate_table.into_iter().filter(|r| r.active) { + // we start the apy calculation from the epoch when the stake subsidy starts + let exchange_rates = rates.rates.into_iter().filter_map(|(epoch, rate)| { + if epoch >= stake_subsidy_start_epoch { + Some(rate) + } else { + None + } + }); + + // we need at least 2 data points to calculate apy + let average_apy = if exchange_rates.clone().count() >= 2 { + // rates are sorted by epoch in descending order. + let er_e = exchange_rates.clone().dropping(1); + // rate e+1 + let er_e_1 = exchange_rates.dropping_back(1); + let apys = er_e + .zip(er_e_1) + .map(calculate_apy) + .filter(|apy| *apy > 0.0 && *apy < 0.1) + .take(30) + .collect::>(); + + let apy_counts = apys.len() as f64; + apys.iter().sum::() / apy_counts + } else { + 0.0 + }; + apys.push(ValidatorApy { + address: rates.address, + apy: average_apy, + }); + } + apys +} + +#[test] +fn test_apys_calculation_filter_outliers() { + // staking pool exchange rates extracted from mainnet + let file = + std::fs::File::open("src/unit_tests/data/validator_exchange_rate/rates.json").unwrap(); + let rates: BTreeMap> = + serde_json::from_reader(file).unwrap(); + + let mut address_map = BTreeMap::new(); + + let exchange_rates = rates + .into_iter() + .map(|(validator, rates)| { + let address = IotaAddress::random_for_testing_only(); + address_map.insert(address, validator); + ValidatorExchangeRates { + address, + pool_id: ObjectID::random(), + active: true, + rates, + } + }) + .collect(); + + let apys = calculate_apys(20, exchange_rates); + + for apy in apys { + println!("{}: {}", address_map[&apy.address], apy.apy); + assert!(apy.apy < 0.07) + } +} + +// APY_e = (ER_e+1 / ER_e) ^ 365 +fn calculate_apy((rate_e, rate_e_1): (PoolTokenExchangeRate, PoolTokenExchangeRate)) -> f64 { + (rate_e.rate() / rate_e_1.rate()).powf(365.0) - 1.0 +} + +fn stake_status( + epoch: u64, + activation_epoch: u64, + principal: u64, + exists: bool, + current_rate: Option<&PoolTokenExchangeRate>, + rate_table: &ValidatorExchangeRates, +) -> StakeStatus { + if !exists { + StakeStatus::Unstaked + } else if epoch >= activation_epoch { + let estimated_reward = if let Some(current_rate) = current_rate { + let stake_rate = rate_table + .rates + .iter() + .find_map(|(epoch, rate)| (*epoch == activation_epoch).then(|| rate.clone())) + .unwrap_or_default(); + let estimated_reward = + ((stake_rate.rate() / current_rate.rate()) - 1.0) * principal as f64; + max(0, estimated_reward.round() as u64) + } else { + 0 + }; + StakeStatus::Active { estimated_reward } + } else { + StakeStatus::Pending + } +} + +/// Cached exchange rates for validators for the given epoch, the cache size is +/// 1, it will be cleared when the epoch changes. rates are in descending order +/// by epoch. +#[cached( + type = "SizedCache>", + create = "{ SizedCache::with_size(1) }", + convert = "{ _current_epoch }", + result = true +)] +async fn exchange_rates( + state: &Arc, + _current_epoch: EpochId, +) -> RpcInterimResult> { + let system_state = state.get_system_state()?; + let system_state_summary: IotaSystemStateSummary = + system_state.into_iota_system_state_summary(); + + // Get validator rate tables + let mut tables = vec![]; + + for validator in system_state_summary.active_validators { + tables.push(( + validator.iota_address, + validator.staking_pool_id, + validator.exchange_rates_id, + validator.exchange_rates_size, + true, + )); + } + + // Get inactive validator rate tables + for df in state.get_dynamic_fields( + system_state_summary.inactive_pools_id, + None, + system_state_summary.inactive_pools_size as usize, + )? { + let pool_id: ID = + bcs::from_bytes(&df.1.bcs_name).map_err(|e| IotaError::ObjectDeserializationError { + error: e.to_string(), + })?; + let validator = get_validator_from_table( + state.get_object_store().as_ref(), + system_state_summary.inactive_pools_id, + &pool_id, + )?; // TODO(wlmyng): roll this into StateReadError + tables.push(( + validator.iota_address, + validator.staking_pool_id, + validator.exchange_rates_id, + validator.exchange_rates_size, + false, + )); + } + + let mut exchange_rates = vec![]; + // Get exchange rates for each validator + for (address, pool_id, exchange_rates_id, exchange_rates_size, active) in tables { + let mut rates = state + .get_dynamic_fields(exchange_rates_id, None, exchange_rates_size as usize)? + .into_iter() + .map(|df| { + let epoch: EpochId = bcs::from_bytes(&df.1.bcs_name).map_err(|e| { + IotaError::ObjectDeserializationError { + error: e.to_string(), + } + })?; + + let exchange_rate: PoolTokenExchangeRate = get_dynamic_field_from_store( + &state.get_object_store().as_ref(), + exchange_rates_id, + &epoch, + )?; + + Ok::<_, IotaError>((epoch, exchange_rate)) + }) + .collect::, _>>()?; + + rates.sort_by(|(a, _), (b, _)| a.cmp(b).reverse()); + + exchange_rates.push(ValidatorExchangeRates { + address, + pool_id, + active, + rates, + }); + } + Ok(exchange_rates) +} + +#[derive(Clone, Debug)] +pub struct ValidatorExchangeRates { + pub address: IotaAddress, + pub pool_id: ObjectID, + pub active: bool, + pub rates: Vec<(EpochId, PoolTokenExchangeRate)>, +} + +impl IotaRpcModule for GovernanceReadApi { + fn rpc(self) -> RpcModule { + self.into_rpc() + } + + fn rpc_doc_module() -> Module { + GovernanceReadApiOpenRpc::module_doc() + } +} diff --git a/crates/iota-json-rpc/src/indexer_api.rs b/crates/iota-json-rpc/src/indexer_api.rs new file mode 100644 index 00000000000..8af5adb7f11 --- /dev/null +++ b/crates/iota-json-rpc/src/indexer_api.rs @@ -0,0 +1,511 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::Arc; + +use anyhow::bail; +use async_trait::async_trait; +use futures::{future, Stream}; +use iota_core::authority::AuthorityState; +use iota_json::IotaJsonValue; +use iota_json_rpc_api::{ + cap_page_limit, validate_limit, IndexerApiOpenRpc, IndexerApiServer, JsonRpcMetrics, + ReadApiServer, QUERY_MAX_RESULT_LIMIT, +}; +use iota_json_rpc_types::{ + DynamicFieldPage, EventFilter, EventPage, IotaObjectDataOptions, IotaObjectResponse, + IotaObjectResponseQuery, IotaTransactionBlockResponse, IotaTransactionBlockResponseQuery, + ObjectsPage, Page, TransactionBlocksPage, TransactionFilter, +}; +use iota_open_rpc::Module; +use iota_storage::key_value_store::TransactionKeyValueStore; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + digests::TransactionDigest, + dynamic_field::{DynamicFieldName, Field}, + error::IotaObjectResponseError, + event::EventID, +}; +use jsonrpsee::{ + core::{error::SubscriptionClosed, RpcResult}, + types::SubscriptionResult, + RpcModule, SubscriptionSink, +}; +use move_bytecode_utils::layout::TypeLayoutBuilder; +use move_core_types::language_storage::TypeTag; +use mysten_metrics::spawn_monitored_task; +use serde::Serialize; +use tokio::sync::{OwnedSemaphorePermit, Semaphore}; +use tracing::{debug, instrument, warn}; + +use crate::{ + authority_state::{StateRead, StateReadResult}, + error::{Error, IotaRpcInputError}, + name_service::{Domain, NameRecord, NameServiceConfig, NameServiceError}, + with_tracing, IotaRpcModule, +}; + +pub fn spawn_subscription( + mut sink: SubscriptionSink, + rx: S, + permit: Option, +) where + S: Stream + Unpin + Send + 'static, + T: Serialize, +{ + spawn_monitored_task!(async move { + let _permit = permit; + match sink.pipe_from_stream(rx).await { + SubscriptionClosed::Success => { + debug!("Subscription completed."); + sink.close(SubscriptionClosed::Success); + } + SubscriptionClosed::RemotePeerAborted => { + debug!("Subscription aborted by remote peer."); + sink.close(SubscriptionClosed::RemotePeerAborted); + } + SubscriptionClosed::Failed(err) => { + debug!("Subscription failed: {err:?}"); + sink.close(err); + } + }; + }); +} +const DEFAULT_MAX_SUBSCRIPTIONS: usize = 100; + +pub struct IndexerApi { + state: Arc, + read_api: R, + transaction_kv_store: Arc, + name_service_config: NameServiceConfig, + pub metrics: Arc, + subscription_semaphore: Arc, +} + +impl IndexerApi { + pub fn new( + state: Arc, + read_api: R, + transaction_kv_store: Arc, + name_service_config: NameServiceConfig, + metrics: Arc, + max_subscriptions: Option, + ) -> Self { + let max_subscriptions = max_subscriptions.unwrap_or(DEFAULT_MAX_SUBSCRIPTIONS); + Self { + state, + transaction_kv_store, + read_api, + name_service_config, + metrics, + subscription_semaphore: Arc::new(Semaphore::new(max_subscriptions)), + } + } + + fn extract_values_from_dynamic_field_name( + &self, + name: DynamicFieldName, + ) -> Result<(TypeTag, Vec), IotaRpcInputError> { + let DynamicFieldName { + type_: name_type, + value, + } = name; + let epoch_store = self.state.load_epoch_store_one_call_per_task(); + let layout = TypeLayoutBuilder::build_with_types(&name_type, epoch_store.module_cache())?; + let iota_json_value = IotaJsonValue::new(value)?; + let name_bcs_value = iota_json_value.to_bcs_bytes(&layout)?; + Ok((name_type, name_bcs_value)) + } + + fn acquire_subscribe_permit(&self) -> anyhow::Result { + match self.subscription_semaphore.clone().try_acquire_owned() { + Ok(p) => Ok(p), + Err(_) => bail!("Resources exhausted"), + } + } + + fn get_latest_checkpoint_timestamp_ms(&self) -> StateReadResult { + let latest_checkpoint = self.state.get_latest_checkpoint_sequence_number()?; + + let checkpoint = self + .state + .get_verified_checkpoint_by_sequence_number(latest_checkpoint)?; + + Ok(checkpoint.timestamp_ms) + } +} + +#[async_trait] +impl IndexerApiServer for IndexerApi { + #[instrument(skip(self))] + async fn get_owned_objects( + &self, + address: IotaAddress, + query: Option, + cursor: Option, + limit: Option, + ) -> RpcResult { + with_tracing!(async move { + let limit = + validate_limit(limit, *QUERY_MAX_RESULT_LIMIT).map_err(IotaRpcInputError::from)?; + self.metrics.get_owned_objects_limit.report(limit as u64); + let IotaObjectResponseQuery { filter, options } = query.unwrap_or_default(); + let options = options.unwrap_or_default(); + let mut objects = self + .state + .get_owner_objects_with_limit(address, cursor, limit + 1, filter) + .map_err(Error::from)?; + + // objects here are of size (limit + 1), where the last one is the cursor for + // the next page + let has_next_page = objects.len() > limit; + objects.truncate(limit); + let next_cursor = objects + .last() + .cloned() + .map_or(cursor, |o_info| Some(o_info.object_id)); + + let data = match options.is_not_in_object_info() { + true => { + let object_ids = objects.iter().map(|obj| obj.object_id).collect(); + self.read_api + .multi_get_objects(object_ids, Some(options)) + .await? + } + false => objects + .into_iter() + .map(|o_info| IotaObjectResponse::try_from((o_info, options.clone()))) + .collect::, _>>()?, + }; + + self.metrics + .get_owned_objects_result_size + .report(data.len() as u64); + self.metrics + .get_owned_objects_result_size_total + .inc_by(data.len() as u64); + Ok(Page { + data, + next_cursor, + has_next_page, + }) + }) + } + + #[instrument(skip(self))] + async fn query_transaction_blocks( + &self, + query: IotaTransactionBlockResponseQuery, + // If `Some`, the query will start from the next item after the specified cursor + cursor: Option, + limit: Option, + descending_order: Option, + ) -> RpcResult { + with_tracing!(async move { + let limit = cap_page_limit(limit); + self.metrics.query_tx_blocks_limit.report(limit as u64); + let descending = descending_order.unwrap_or_default(); + let opts = query.options.unwrap_or_default(); + + // Retrieve 1 extra item for next cursor + let mut digests = self + .state + .get_transactions( + &self.transaction_kv_store, + query.filter, + cursor, + Some(limit + 1), + descending, + ) + .await + .map_err(Error::from)?; + + // extract next cursor + let has_next_page = digests.len() > limit; + digests.truncate(limit); + let next_cursor = digests.last().cloned().map_or(cursor, Some); + + let data: Vec = if opts.only_digest() { + digests + .into_iter() + .map(IotaTransactionBlockResponse::new) + .collect() + } else { + self.read_api + .multi_get_transaction_blocks(digests, Some(opts)) + .await? + }; + + self.metrics + .query_tx_blocks_result_size + .report(data.len() as u64); + self.metrics + .query_tx_blocks_result_size_total + .inc_by(data.len() as u64); + Ok(Page { + data, + next_cursor, + has_next_page, + }) + }) + } + #[instrument(skip(self))] + async fn query_events( + &self, + query: EventFilter, + // exclusive cursor if `Some`, otherwise start from the beginning + cursor: Option, + limit: Option, + descending_order: Option, + ) -> RpcResult { + with_tracing!(async move { + let descending = descending_order.unwrap_or_default(); + let limit = cap_page_limit(limit); + self.metrics.query_events_limit.report(limit as u64); + // Retrieve 1 extra item for next cursor + let mut data = self + .state + .query_events( + &self.transaction_kv_store, + query, + cursor, + limit + 1, + descending, + ) + .await + .map_err(Error::from)?; + let has_next_page = data.len() > limit; + data.truncate(limit); + let next_cursor = data.last().map_or(cursor, |e| Some(e.id)); + self.metrics + .query_events_result_size + .report(data.len() as u64); + self.metrics + .query_events_result_size_total + .inc_by(data.len() as u64); + Ok(EventPage { + data, + next_cursor, + has_next_page, + }) + }) + } + + #[instrument(skip(self))] + fn subscribe_event(&self, sink: SubscriptionSink, filter: EventFilter) -> SubscriptionResult { + let permit = self.acquire_subscribe_permit()?; + spawn_subscription( + sink, + self.state + .get_subscription_handler() + .subscribe_events(filter), + Some(permit), + ); + Ok(()) + } + + fn subscribe_transaction( + &self, + sink: SubscriptionSink, + filter: TransactionFilter, + ) -> SubscriptionResult { + let permit = self.acquire_subscribe_permit()?; + spawn_subscription( + sink, + self.state + .get_subscription_handler() + .subscribe_transactions(filter), + Some(permit), + ); + Ok(()) + } + + #[instrument(skip(self))] + async fn get_dynamic_fields( + &self, + parent_object_id: ObjectID, + // If `Some`, the query will start from the next item after the specified cursor + cursor: Option, + limit: Option, + ) -> RpcResult { + with_tracing!(async move { + let limit = cap_page_limit(limit); + self.metrics.get_dynamic_fields_limit.report(limit as u64); + let mut data = self + .state + .get_dynamic_fields(parent_object_id, cursor, limit + 1) + .map_err(Error::from)?; + let has_next_page = data.len() > limit; + data.truncate(limit); + let next_cursor = data.last().cloned().map_or(cursor, |c| Some(c.0)); + self.metrics + .get_dynamic_fields_result_size + .report(data.len() as u64); + self.metrics + .get_dynamic_fields_result_size_total + .inc_by(data.len() as u64); + Ok(DynamicFieldPage { + data: data.into_iter().map(|(_, w)| w).collect(), + next_cursor, + has_next_page, + }) + }) + } + + #[instrument(skip(self))] + async fn get_dynamic_field_object( + &self, + parent_object_id: ObjectID, + name: DynamicFieldName, + ) -> RpcResult { + with_tracing!(async move { + let (name_type, name_bcs_value) = self.extract_values_from_dynamic_field_name(name)?; + + let id = self + .state + .get_dynamic_field_object_id(parent_object_id, name_type, &name_bcs_value) + .map_err(Error::from)?; + // TODO(chris): add options to `get_dynamic_field_object` API as well + if let Some(id) = id { + self.read_api + .get_object(id, Some(IotaObjectDataOptions::full_content())) + .await + .map_err(Error::from) + } else { + Ok(IotaObjectResponse::new_with_error( + IotaObjectResponseError::DynamicFieldNotFound { parent_object_id }, + )) + } + }) + } + + #[instrument(skip(self))] + async fn resolve_name_service_address(&self, name: String) -> RpcResult> { + with_tracing!(async move { + // prepare the requested domain's field id. + let domain = name.parse::().map_err(Error::from)?; + let record_id = self.name_service_config.record_field_id(&domain); + + // prepare the parent's field id. + let parent_domain = domain.parent(); + let parent_record_id = self.name_service_config.record_field_id(&parent_domain); + + let current_timestamp_ms = self.get_latest_checkpoint_timestamp_ms()?; + + // Do these two reads in parallel. + let mut requests = vec![self.state.get_object(&record_id)]; + + // Also add the parent in the DB reads if the requested domain is a subdomain. + if domain.is_subdomain() { + requests.push(self.state.get_object(&parent_record_id)); + } + + // Couldn't find a `multi_get_object` for this crate (looks like it uses a k,v + // db) Always fetching both parent + child at the same time (even + // for node subdomains), to avoid sequential db reads. We do this + // because we do not know if the requested domain is a node + // subdomain or a leaf subdomain, and we can save a trip to the db. + let mut results = future::try_join_all(requests).await?; + + // Removing without checking vector len, since it is known (== 1 or 2 depending + // on whether it is a subdomain or not). + let Some(object) = results.remove(0) else { + return Ok(None); + }; + + let name_record = NameRecord::try_from(object)?; + + // Handling SLD names & node subdomains is the same (we handle them as `node` + // records) We check their expiration, and and if not expired, + // return the target address. + if !name_record.is_leaf_record() { + return if !name_record.is_node_expired(current_timestamp_ms) { + Ok(name_record.target_address) + } else { + Err(Error::from(NameServiceError::NameExpired)) + }; + } + + // == Handle leaf subdomains case == + // We can remove since we know that if we're here, we have a parent + // (which also means we queried it in the future above). + let Some(parent_object) = results.remove(0) else { + return Err(Error::from(NameServiceError::NameExpired)); + }; + + let parent_name_record = NameRecord::try_from(parent_object)?; + + // For a leaf record, we check that: + // 1. The parent is a valid parent for that leaf record + // 2. The parent is not expired + if parent_name_record.is_valid_leaf_parent(&name_record) + && !parent_name_record.is_node_expired(current_timestamp_ms) + { + Ok(name_record.target_address) + } else { + Err(Error::from(NameServiceError::NameExpired)) + } + }) + } + + #[instrument(skip(self))] + async fn resolve_name_service_names( + &self, + address: IotaAddress, + _cursor: Option, + _limit: Option, + ) -> RpcResult> { + with_tracing!(async move { + let reverse_record_id = self + .name_service_config + .reverse_record_field_id(address.as_ref()); + + let mut result = Page { + data: vec![], + next_cursor: None, + has_next_page: false, + }; + + let Some(field_reverse_record_object) = + self.state.get_object(&reverse_record_id).await? + else { + return Ok(result); + }; + + let domain = field_reverse_record_object + .to_rust::>() + .ok_or_else(|| { + Error::UnexpectedError(format!("Malformed Object {reverse_record_id}")) + })? + .value; + + let domain_name = domain.to_string(); + + let resolved_address = self + .resolve_name_service_address(domain_name.clone()) + .await?; + + // If looking up the domain returns an empty result, we return an empty result. + if resolved_address.is_none() { + return Ok(result); + } + + // TODO(manos): Discuss why is this even a paginated response. + // This API is always going to return a single domain name. + result.data.push(domain_name); + + Ok(result) + }) + } +} + +impl IotaRpcModule for IndexerApi { + fn rpc(self) -> RpcModule { + self.into_rpc() + } + + fn rpc_doc_module() -> Module { + IndexerApiOpenRpc::module_doc() + } +} diff --git a/crates/iota-json-rpc/src/lib.rs b/crates/iota-json-rpc/src/lib.rs new file mode 100644 index 00000000000..dd140f57b2d --- /dev/null +++ b/crates/iota-json-rpc/src/lib.rs @@ -0,0 +1,276 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{env, net::SocketAddr, str::FromStr}; + +pub use balance_changes::*; +use hyper::{ + header::{HeaderName, HeaderValue}, + Body, Method, Request, +}; +use iota_json_rpc_api::{ + CLIENT_SDK_TYPE_HEADER, CLIENT_SDK_VERSION_HEADER, CLIENT_TARGET_API_VERSION_HEADER, +}; +use iota_open_rpc::{Module, Project}; +use jsonrpsee::RpcModule; +pub use object_changes::*; +use prometheus::Registry; +use tokio::runtime::Handle; +use tower_http::{ + cors::{AllowOrigin, CorsLayer}, + trace::TraceLayer, +}; +use tracing::info; + +use crate::{error::Error, metrics::MetricsLogger, routing_layer::RpcRouter}; + +pub mod authority_state; +pub mod axum_router; +mod balance_changes; +pub mod coin_api; +pub mod error; +pub mod governance_api; +pub mod indexer_api; +pub mod logger; +mod metrics; +pub mod move_utils; +pub mod name_service; +mod object_changes; +pub mod read_api; +mod routing_layer; +pub mod transaction_builder_api; +pub mod transaction_execution_api; + +pub const APP_NAME_HEADER: &str = "app-name"; + +pub const MAX_REQUEST_SIZE: u32 = 2 << 30; + +pub struct JsonRpcServerBuilder { + module: RpcModule<()>, + rpc_doc: Project, + registry: Registry, +} + +pub fn iota_rpc_doc(version: &str) -> Project { + Project::new( + version, + "Iota JSON-RPC", + "Iota JSON-RPC API for interaction with Iota Full node. Make RPC calls using https://fullnode.NETWORK.iota.io:443, where NETWORK is the network you want to use (testnet, devnet, mainnet). By default, local networks use port 9000.", + "Mysten Labs", + "https://mystenlabs.com", + "build@mystenlabs.com", + "Apache-2.0", + "https://raw.githubusercontent.com/iotaledger/iota/main/LICENSE", + ) +} + +pub enum ServerType { + WebSocket, + Http, +} + +impl JsonRpcServerBuilder { + pub fn new(version: &str, prometheus_registry: &Registry) -> Self { + Self { + module: RpcModule::new(()), + rpc_doc: iota_rpc_doc(version), + registry: prometheus_registry.clone(), + } + } + + pub fn register_module(&mut self, module: T) -> Result<(), Error> { + self.rpc_doc.add_module(T::rpc_doc_module()); + Ok(self.module.merge(module.rpc())?) + } + + fn cors() -> Result { + let acl = match env::var("ACCESS_CONTROL_ALLOW_ORIGIN") { + Ok(value) => { + let allow_hosts = value + .split(',') + .map(HeaderValue::from_str) + .collect::, _>>()?; + AllowOrigin::list(allow_hosts) + } + _ => AllowOrigin::any(), + }; + info!(?acl); + + let cors = CorsLayer::new() + // Allow `POST` when accessing the resource + .allow_methods([Method::POST]) + // Allow requests from any origin + .allow_origin(acl) + .allow_headers([ + hyper::header::CONTENT_TYPE, + HeaderName::from_static(CLIENT_SDK_TYPE_HEADER), + HeaderName::from_static(CLIENT_SDK_VERSION_HEADER), + HeaderName::from_static(CLIENT_TARGET_API_VERSION_HEADER), + HeaderName::from_static(APP_NAME_HEADER), + ]); + Ok(cors) + } + + fn trace_layer() -> TraceLayer< + tower_http::classify::SharedClassifier, + impl tower_http::trace::MakeSpan + Clone, + (), + (), + (), + (), + (), + > { + TraceLayer::new_for_http() + .make_span_with(|request: &Request| { + let request_id = request + .headers() + .get("x-req-id") + .and_then(|v| v.to_str().ok()) + .map(tracing::field::display); + + tracing::info_span!("json-rpc-request", "x-req-id" = request_id) + }) + .on_request(()) + .on_response(()) + .on_body_chunk(()) + .on_eos(()) + .on_failure(()) + } + + pub fn to_router(&self, server_type: Option) -> Result { + let routing = self.rpc_doc.method_routing.clone(); + + let disable_routing = env::var("DISABLE_BACKWARD_COMPATIBILITY") + .ok() + .and_then(|v| bool::from_str(&v).ok()) + .unwrap_or_default(); + info!( + "Compatibility method routing {}.", + if disable_routing { + "disabled" + } else { + "enabled" + } + ); + let rpc_router = RpcRouter::new(routing, disable_routing); + + let rpc_docs = self.rpc_doc.clone(); + let mut module = self.module.clone(); + module.register_method("rpc.discover", move |_, _| Ok(rpc_docs.clone()))?; + let methods_names = module.method_names().collect::>(); + + let metrics_logger = MetricsLogger::new(&self.registry, &methods_names); + + let middleware = tower::ServiceBuilder::new() + .layer(Self::trace_layer()) + .layer(Self::cors()?); + + let service = + crate::axum_router::JsonRpcService::new(module.into(), rpc_router, metrics_logger); + + let mut router = axum::Router::new(); + + match server_type { + Some(ServerType::WebSocket) => { + router = router + .route( + "/", + axum::routing::get(crate::axum_router::ws::ws_json_rpc_upgrade), + ) + .route( + "/subscribe", + axum::routing::get(crate::axum_router::ws::ws_json_rpc_upgrade), + ); + } + Some(ServerType::Http) => { + router = router + .route( + "/", + axum::routing::post(crate::axum_router::json_rpc_handler), + ) + .route( + "/json-rpc", + axum::routing::post(crate::axum_router::json_rpc_handler), + ) + .route( + "/public", + axum::routing::post(crate::axum_router::json_rpc_handler), + ); + } + None => { + router = router + .route( + "/", + axum::routing::post(crate::axum_router::json_rpc_handler), + ) + .route( + "/", + axum::routing::get(crate::axum_router::ws::ws_json_rpc_upgrade), + ) + .route( + "/subscribe", + axum::routing::get(crate::axum_router::ws::ws_json_rpc_upgrade), + ) + .route( + "/json-rpc", + axum::routing::post(crate::axum_router::json_rpc_handler), + ) + .route( + "/public", + axum::routing::post(crate::axum_router::json_rpc_handler), + ); + } + } + + let app = router.with_state(service).layer(middleware); + + info!("Available JSON-RPC methods : {:?}", methods_names); + + Ok(app) + } + + pub async fn start( + self, + listen_address: SocketAddr, + _custom_runtime: Option, + server_type: Option, + ) -> Result { + let app = self.to_router(server_type)?; + + let server = axum::Server::bind(&listen_address).serve(app.into_make_service()); + + let addr = server.local_addr(); + let handle = tokio::spawn(async move { server.await.unwrap() }); + + let handle = ServerHandle { + handle: ServerHandleInner::Axum(handle), + }; + info!(local_addr =? addr, "Iota JSON-RPC server listening on {addr}"); + Ok(handle) + } +} + +pub struct ServerHandle { + handle: ServerHandleInner, +} + +impl ServerHandle { + pub async fn stopped(self) { + match self.handle { + ServerHandleInner::Axum(handle) => handle.await.unwrap(), + } + } +} + +enum ServerHandleInner { + Axum(tokio::task::JoinHandle<()>), +} + +pub trait IotaRpcModule +where + Self: Sized, +{ + fn rpc(self) -> RpcModule; + fn rpc_doc_module() -> Module; +} diff --git a/crates/iota-json-rpc/src/logger.rs b/crates/iota-json-rpc/src/logger.rs new file mode 100644 index 00000000000..c402cf7a44e --- /dev/null +++ b/crates/iota-json-rpc/src/logger.rs @@ -0,0 +1,40 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[macro_export] +macro_rules! with_tracing { + ($time_spent_threshold:expr, $future:expr) => {{ + use tracing::{info, error, Instrument, Span}; + use jsonrpsee::core::{RpcResult, Error as RpcError}; + use jsonrpsee::types::error::{CallError}; + use $crate::error::RpcInterimResult; + use anyhow::anyhow; + + async move { + let start = std::time::Instant::now(); + let interim_result: RpcInterimResult<_> = $future.await; + let elapsed = start.elapsed(); + let result: RpcResult<_> = interim_result.map_err(|e: Error| { + let anyhow_error = anyhow!("{:?}", e); + + let rpc_error: RpcError = e.into(); + if !matches!(rpc_error, RpcError::Call(CallError::InvalidParams(_))) { + error!(error=?anyhow_error); + } + rpc_error + }); + + if elapsed > $time_spent_threshold { + info!(?elapsed, "RPC took longer than threshold to complete."); + } + result + } + .instrument(Span::current()) + .await + }}; + + ($future:expr) => {{ + with_tracing!(std::time::Duration::from_secs(1), $future) + }}; +} diff --git a/crates/iota-json-rpc/src/metrics.rs b/crates/iota-json-rpc/src/metrics.rs new file mode 100644 index 00000000000..c19616a5538 --- /dev/null +++ b/crates/iota-json-rpc/src/metrics.rs @@ -0,0 +1,275 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::HashSet, net::SocketAddr}; + +use hyper::body::HttpBody; +use iota_json_rpc_api::{ + CLIENT_SDK_TYPE_HEADER, CLIENT_TARGET_API_VERSION_HEADER, TRANSIENT_ERROR_CODE, +}; +use jsonrpsee::{ + server::logger::{HttpRequest, Logger, MethodKind, TransportProtocol}, + types::Params, +}; +use prometheus::{ + register_histogram_vec_with_registry, register_int_counter_vec_with_registry, + register_int_gauge_vec_with_registry, HistogramVec, IntCounterVec, IntGaugeVec, +}; +use tokio::time::Instant; + +const SPAM_LABEL: &str = "SPAM"; +const LATENCY_SEC_BUCKETS: &[f64] = &[ + 0.001, 0.005, 0.01, 0.05, 0.1, 0.25, 0.5, 1., 2.5, 5., 10., 20., 30., 60., 90., +]; + +#[derive(Debug, Clone)] +pub struct Metrics { + /// Counter of requests, route is a label (ie separate timeseries per route) + requests_by_route: IntCounterVec, + /// Gauge of inflight requests, route is a label (ie separate timeseries per + /// route) + inflight_requests_by_route: IntGaugeVec, + /// Request latency, route is a label + req_latency_by_route: HistogramVec, + /// Failed requests by route + errors_by_route: IntCounterVec, + server_errors_by_route: IntCounterVec, + client_errors_by_route: IntCounterVec, + transient_errors_by_route: IntCounterVec, + /// Client info + client: IntCounterVec, + /// Connection count + inflight_connection: IntGaugeVec, + /// Request size + rpc_request_size: HistogramVec, + /// Response size + rpc_response_size: HistogramVec, +} + +#[derive(Clone)] +pub struct MetricsLogger { + metrics: Metrics, + method_whitelist: HashSet, +} + +impl MetricsLogger { + fn check_spam<'a>(&'a self, method_name: &'a str) -> &'a str { + if self.method_whitelist.contains(method_name) { + method_name + } else { + SPAM_LABEL + } + } + + pub fn new(registry: &prometheus::Registry, method_whitelist: &[&str]) -> Self { + let metrics = Metrics { + requests_by_route: register_int_counter_vec_with_registry!( + "rpc_requests_by_route", + "Number of requests by route", + &["route"], + registry, + ) + .unwrap(), + inflight_requests_by_route: register_int_gauge_vec_with_registry!( + "inflight_rpc_requests_by_route", + "Number of inflight requests by route", + &["route"], + registry, + ) + .unwrap(), + req_latency_by_route: register_histogram_vec_with_registry!( + "req_latency_by_route", + "Latency of a request by route", + &["route"], + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + client_errors_by_route: register_int_counter_vec_with_registry!( + "client_errors_by_route", + "Number of client errors by route", + &["route"], + registry, + ) + .unwrap(), + server_errors_by_route: register_int_counter_vec_with_registry!( + "server_errors_by_route", + "Number of server errors by route", + &["route"], + registry, + ) + .unwrap(), + transient_errors_by_route: register_int_counter_vec_with_registry!( + "transient_errors_by_route", + "Number of transient errors by route", + &["route"], + registry, + ) + .unwrap(), + errors_by_route: register_int_counter_vec_with_registry!( + "errors_by_route", + "Number of client and server errors by route", + &["route"], + registry + ) + .unwrap(), + client: register_int_counter_vec_with_registry!( + "rpc_client", + "Connected RPC client's info", + &["client_type", "api_version"], + registry, + ) + .unwrap(), + inflight_connection: register_int_gauge_vec_with_registry!( + "rpc_inflight_connection", + "Number of inflight RPC connection by protocol", + &["protocol"], + registry, + ) + .unwrap(), + rpc_request_size: register_histogram_vec_with_registry!( + "rpc_request_size", + "Request size of rpc requests", + &["protocol"], + prometheus::exponential_buckets(32.0, 2.0, 19) + .unwrap() + .to_vec(), + registry, + ) + .unwrap(), + rpc_response_size: register_histogram_vec_with_registry!( + "rpc_response_size", + "Response size of rpc requests", + &["protocol"], + prometheus::exponential_buckets(1024.0, 2.0, 20) + .unwrap() + .to_vec(), + registry, + ) + .unwrap(), + }; + + Self { + metrics, + method_whitelist: method_whitelist.iter().map(|s| (*s).into()).collect(), + } + } +} + +impl Logger for MetricsLogger { + type Instant = Instant; + + fn on_connect(&self, _remote_addr: SocketAddr, request: &HttpRequest, t: TransportProtocol) { + let client_type = request + .headers() + .get(CLIENT_SDK_TYPE_HEADER) + .and_then(|v| v.to_str().ok()) + .unwrap_or("Unknown"); + + let api_version = request + .headers() + .get(CLIENT_TARGET_API_VERSION_HEADER) + .and_then(|v| v.to_str().ok()) + .unwrap_or("Unknown"); + self.metrics + .client + .with_label_values(&[client_type, api_version]) + .inc(); + self.metrics + .inflight_connection + .with_label_values(&[&t.to_string()]) + .inc(); + + self.metrics + .rpc_request_size + .with_label_values(&[&t.to_string()]) + .observe( + request + .size_hint() + .exact() + .unwrap_or_else(|| request.size_hint().lower()) as f64, + ); + } + + fn on_request(&self, _transport: TransportProtocol) -> Self::Instant { + Instant::now() + } + + fn on_call( + &self, + method_name: &str, + _params: Params, + _kind: MethodKind, + _transport: TransportProtocol, + ) { + let method_name = self.check_spam(method_name); + self.metrics + .inflight_requests_by_route + .with_label_values(&[method_name]) + .inc(); + self.metrics + .requests_by_route + .with_label_values(&[method_name]) + .inc(); + } + + fn on_result( + &self, + method_name: &str, + _success: bool, + error_code: Option, + started_at: Self::Instant, + _transport: TransportProtocol, + ) { + let method_name = self.check_spam(method_name); + self.metrics + .inflight_requests_by_route + .with_label_values(&[method_name]) + .dec(); + let req_latency_secs = (Instant::now() - started_at).as_secs_f64(); + self.metrics + .req_latency_by_route + .with_label_values(&[method_name]) + .observe(req_latency_secs); + + if let Some(code) = error_code { + if code == jsonrpsee::types::error::CALL_EXECUTION_FAILED_CODE + || code == jsonrpsee::types::error::INTERNAL_ERROR_CODE + { + self.metrics + .server_errors_by_route + .with_label_values(&[method_name]) + .inc(); + } else if code == TRANSIENT_ERROR_CODE { + self.metrics + .transient_errors_by_route + .with_label_values(&[method_name]) + .inc(); + } else { + self.metrics + .client_errors_by_route + .with_label_values(&[method_name]) + .inc(); + } + self.metrics + .errors_by_route + .with_label_values(&[method_name]) + .inc(); + } + } + + fn on_response(&self, result: &str, _started_at: Self::Instant, t: TransportProtocol) { + self.metrics + .rpc_response_size + .with_label_values(&[&t.to_string()]) + .observe(std::mem::size_of_val(result) as f64) + } + + fn on_disconnect(&self, _remote_addr: SocketAddr, t: TransportProtocol) { + self.metrics + .inflight_connection + .with_label_values(&[&t.to_string()]) + .dec(); + } +} diff --git a/crates/iota-json-rpc/src/move_utils.rs b/crates/iota-json-rpc/src/move_utils.rs new file mode 100644 index 00000000000..08e96a08ec2 --- /dev/null +++ b/crates/iota-json-rpc/src/move_utils.rs @@ -0,0 +1,351 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::BTreeMap, sync::Arc}; + +use async_trait::async_trait; +use iota_core::authority::AuthorityState; +use iota_json_rpc_api::{MoveUtilsOpenRpc, MoveUtilsServer}; +use iota_json_rpc_types::{ + IotaMoveNormalizedFunction, IotaMoveNormalizedModule, IotaMoveNormalizedStruct, + MoveFunctionArgType, ObjectValueKind, +}; +use iota_open_rpc::Module; +use iota_types::{ + base_types::ObjectID, + move_package::normalize_modules, + object::{Data, ObjectRead}, +}; +use jsonrpsee::{core::RpcResult, RpcModule}; +#[cfg(test)] +use mockall::automock; +use move_binary_format::{ + binary_config::BinaryConfig, + normalized::{Module as NormalizedModule, Type}, +}; +use move_core_types::identifier::Identifier; +use tap::TapFallible; +use tracing::{error, instrument, warn}; + +use crate::{ + authority_state::StateRead, + error::{Error, IotaRpcInputError}, + with_tracing, IotaRpcModule, +}; + +#[cfg_attr(test, automock)] +#[async_trait] +pub trait MoveUtilsInternalTrait { + fn get_state(&self) -> &dyn StateRead; + + async fn get_move_module( + &self, + package: ObjectID, + module_name: String, + ) -> Result; + + async fn get_move_modules_by_package( + &self, + package: ObjectID, + ) -> Result, Error>; + + fn get_object_read(&self, package: ObjectID) -> Result; +} + +pub struct MoveUtilsInternal { + state: Arc, +} + +impl MoveUtilsInternal { + pub fn new(state: Arc) -> Self { + Self { state } + } +} + +#[async_trait] +impl MoveUtilsInternalTrait for MoveUtilsInternal { + fn get_state(&self) -> &dyn StateRead { + Arc::as_ref(&self.state) + } + + async fn get_move_module( + &self, + package: ObjectID, + module_name: String, + ) -> Result { + let normalized = self.get_move_modules_by_package(package).await?; + Ok(match normalized.get(&module_name) { + Some(module) => Ok(module.clone()), + None => Err(IotaRpcInputError::GenericNotFound(format!( + "No module found with module name {}", + module_name + ))), + }?) + } + + async fn get_move_modules_by_package( + &self, + package: ObjectID, + ) -> Result, Error> { + let object_read = self.get_state().get_object_read(&package).tap_err(|_| { + warn!("Failed to call get_move_modules_by_package for package: {package:?}"); + })?; + + match object_read { + ObjectRead::Exists(_obj_ref, object, _layout) => { + match object.into_inner().data { + Data::Package(p) => { + // we are on the read path - it's OK to use VERSION_MAX of the supported + // Move binary format + let binary_config = BinaryConfig::with_extraneous_bytes_check(false); + normalize_modules( + p.serialized_module_map().values(), + &binary_config, + ) + .map_err(|e| { + error!("Failed to call get_move_modules_by_package for package: {package:?}"); + Error::from(e) + }) + } + _ => Err(IotaRpcInputError::GenericInvalid(format!( + "Object is not a package with ID {}", + package + )))?, + } + } + _ => Err(IotaRpcInputError::GenericNotFound(format!( + "Package object does not exist with ID {}", + package + )))?, + } + } + + fn get_object_read(&self, package: ObjectID) -> Result { + self.state.get_object_read(&package).map_err(Error::from) + } +} + +pub struct MoveUtils { + internal: Arc, +} + +impl MoveUtils { + pub fn new(state: Arc) -> Self { + Self { + internal: Arc::new(MoveUtilsInternal::new(state)) + as Arc, + } + } +} + +impl IotaRpcModule for MoveUtils { + fn rpc(self) -> RpcModule { + self.into_rpc() + } + + fn rpc_doc_module() -> Module { + MoveUtilsOpenRpc::module_doc() + } +} + +#[async_trait] +impl MoveUtilsServer for MoveUtils { + #[instrument(skip(self))] + async fn get_normalized_move_modules_by_package( + &self, + package: ObjectID, + ) -> RpcResult> { + with_tracing!(async move { + let modules = self.internal.get_move_modules_by_package(package).await?; + Ok(modules + .into_iter() + .map(|(name, module)| (name, module.into())) + .collect::>()) + }) + } + + #[instrument(skip(self))] + async fn get_normalized_move_module( + &self, + package: ObjectID, + module_name: String, + ) -> RpcResult { + with_tracing!(async move { + let module = self.internal.get_move_module(package, module_name).await?; + Ok(module.into()) + }) + } + + #[instrument(skip(self))] + async fn get_normalized_move_struct( + &self, + package: ObjectID, + module_name: String, + struct_name: String, + ) -> RpcResult { + with_tracing!(async move { + let module = self.internal.get_move_module(package, module_name).await?; + let structs = module.structs; + let identifier = Identifier::new(struct_name.as_str()) + .map_err(|e| IotaRpcInputError::GenericInvalid(format!("{e}")))?; + match structs.get(&identifier) { + Some(struct_) => Ok(struct_.clone().into()), + None => Err(IotaRpcInputError::GenericNotFound(format!( + "No struct was found with struct name {}", + struct_name + )))?, + } + }) + } + + #[instrument(skip(self))] + async fn get_normalized_move_function( + &self, + package: ObjectID, + module_name: String, + function_name: String, + ) -> RpcResult { + with_tracing!(async move { + let module = self.internal.get_move_module(package, module_name).await?; + let functions = module.functions; + let identifier = Identifier::new(function_name.as_str()) + .map_err(|e| IotaRpcInputError::GenericInvalid(format!("{e}")))?; + match functions.get(&identifier) { + Some(function) => Ok(function.clone().into()), + None => Err(IotaRpcInputError::GenericNotFound(format!( + "No function was found with function name {}", + function_name + )))?, + } + }) + } + + #[instrument(skip(self))] + async fn get_move_function_arg_types( + &self, + package: ObjectID, + module: String, + function: String, + ) -> RpcResult> { + with_tracing!(async move { + let object_read = self.internal.get_object_read(package)?; + + let normalized = match object_read { + ObjectRead::Exists(_obj_ref, object, _layout) => match object.into_inner().data { + Data::Package(p) => { + // we are on the read path - it's OK to use VERSION_MAX of the supported + // Move binary format + let binary_config = BinaryConfig::with_extraneous_bytes_check(false); + normalize_modules(p.serialized_module_map().values(), &binary_config) + .map_err(Error::from) + } + _ => Err(IotaRpcInputError::GenericInvalid(format!( + "Object is not a package with ID {}", + package + )))?, + }, + _ => Err(IotaRpcInputError::GenericNotFound(format!( + "Package object does not exist with ID {}", + package + )))?, + }?; + + let identifier = Identifier::new(function.as_str()) + .map_err(|e| IotaRpcInputError::GenericInvalid(format!("{e}")))?; + let parameters = normalized + .get(&module) + .and_then(|m| m.functions.get(&identifier).map(|f| f.parameters.clone())); + + match parameters { + Some(parameters) => Ok(parameters + .iter() + .map(|p| match p { + Type::Struct { + address: _, + module: _, + name: _, + type_arguments: _, + } => MoveFunctionArgType::Object(ObjectValueKind::ByValue), + Type::Reference(_) => { + MoveFunctionArgType::Object(ObjectValueKind::ByImmutableReference) + } + Type::MutableReference(_) => { + MoveFunctionArgType::Object(ObjectValueKind::ByMutableReference) + } + _ => MoveFunctionArgType::Pure, + }) + .collect::>()), + None => Err(IotaRpcInputError::GenericNotFound(format!( + "No parameters found for function {}", + function + )))?, + } + }) + } +} + +#[cfg(test)] +mod tests { + + mod get_normalized_move_module_tests { + use jsonrpsee::types::ErrorObjectOwned; + use move_binary_format::file_format::basic_test_module; + + use super::super::*; + + fn setup() -> (ObjectID, String) { + (ObjectID::random(), String::from("test_module")) + } + + #[tokio::test] + async fn test_success_response() { + let (package, module_name) = setup(); + let mut mock_internal = MockMoveUtilsInternalTrait::new(); + + let m = basic_test_module(); + let normalized_module = NormalizedModule::new(&m); + let expected_module: IotaMoveNormalizedModule = normalized_module.clone().into(); + + mock_internal + .expect_get_move_module() + .return_once(move |_package, _module_name| Ok(normalized_module)); + + let move_utils = MoveUtils { + internal: Arc::new(mock_internal), + }; + + let response = move_utils + .get_normalized_move_module(package, module_name) + .await; + + assert!(response.is_ok()); + let result = response.unwrap(); + assert_eq!(result, expected_module); + } + + #[tokio::test] + async fn test_no_module_found() { + let (package, module_name) = setup(); + let mut mock_internal = MockMoveUtilsInternalTrait::new(); + let error_string = format!("No module found with module name {module_name}"); + let expected_error = + Error::IotaRpcInputError(IotaRpcInputError::GenericNotFound(error_string.clone())); + mock_internal + .expect_get_move_module() + .return_once(move |_package, _module_name| Err(expected_error)); + let move_utils = MoveUtils { + internal: Arc::new(mock_internal), + }; + + let response = move_utils + .get_normalized_move_module(package, module_name) + .await; + let error_result = response.unwrap_err(); + let error_object: ErrorObjectOwned = error_result.into(); + + assert_eq!(error_object.code(), -32602); + assert_eq!(error_object.message(), &error_string); + } + } +} diff --git a/crates/sui-json-rpc/src/name_service.rs b/crates/iota-json-rpc/src/name_service.rs similarity index 89% rename from crates/sui-json-rpc/src/name_service.rs rename to crates/iota-json-rpc/src/name_service.rs index 127af11f73f..f85c97e2349 100644 --- a/crates/sui-json-rpc/src/name_service.rs +++ b/crates/iota-json-rpc/src/name_service.rs @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fmt, marker::PhantomData, str::FromStr}; -use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; -use serde::{Deserialize, Serialize}; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, +use iota_types::{ + base_types::{IotaAddress, ObjectID}, collection_types::VecMap, dynamic_field::Field, id::{ID, UID}, object::{MoveObject, Object}, TypeTag, }; +use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; +use serde::{Deserialize, Serialize}; const NAME_SERVICE_DOMAIN_MODULE: &IdentStr = ident_str!("domain"); const NAME_SERVICE_DOMAIN_STRUCT: &IdentStr = ident_str!("Domain"); @@ -25,12 +26,12 @@ const NAME_SERVICE_DEFAULT_REVERSE_REGISTRY: &str = const _NAME_SERVICE_OBJECT_ADDRESS: &str = "0x6e0ddefc0ad98889c04bab9639e512c21766c5e6366f89e696956d9be6952871"; const LEAF_EXPIRATION_TIMESTAMP: u64 = 0; -const DEFAULT_TLD: &str = "sui"; +const DEFAULT_TLD: &str = "iota"; const ACCEPTED_SEPARATORS: [char; 2] = ['.', '*']; -const SUI_NEW_FORMAT_SEPARATOR: char = '@'; +const IOTA_NEW_FORMAT_SEPARATOR: char = '@'; /// Two different view options for a domain. -/// `At` -> `test@example` | `Dot` -> `test.example.sui` +/// `At` -> `test@example` | `Dot` -> `test.example.iota` #[derive(Clone, Eq, PartialEq, Debug)] pub enum DomainFormat { At, @@ -44,10 +45,10 @@ pub struct Registry { registry: Table, /// The `reverse_registry` table maps `address` to `domain_name`. /// Updated in the `set_reverse_lookup` function. - reverse_registry: Table, + reverse_registry: Table, } -/// Rust version of the Move sui::table::Table type. +/// Rust version of the Move iota::table::Table type. #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct Table { pub id: ObjectID, @@ -65,7 +66,7 @@ pub struct Domain { } impl Domain { - pub fn type_(package_address: SuiAddress) -> StructTag { + pub fn type_(package_address: IotaAddress) -> StructTag { StructTag { address: package_address.into(), module: NAME_SERVICE_DOMAIN_MODULE.to_owned(), @@ -75,7 +76,7 @@ impl Domain { } /// Derive the parent domain for a given domain - /// E.g. `test.example.sui` -> `example.sui` + /// E.g. `test.example.iota` -> `example.iota` /// /// SAFETY: This is a safe operation because we only allow a /// domain's label vector size to be >= 2 (see `Domain::from_str`) @@ -91,7 +92,7 @@ impl Domain { /// Returns the depth for a name. /// Depth is defined by the amount of labels in a domain, including TLD. - /// E.g. `test.example.sui` -> `3` + /// E.g. `test.example.iota` -> `3` /// /// SAFETY: We can safely cast to a u8 as the max depth is 235. pub fn depth(&self) -> u8 { @@ -114,21 +115,21 @@ impl Domain { let _tld = labels.pop(); let sld = labels.pop().unwrap(); - format!("{}{}{}", labels.join(sep), SUI_NEW_FORMAT_SEPARATOR, sld) + format!("{}{}{}", labels.join(sep), IOTA_NEW_FORMAT_SEPARATOR, sld) } } #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] #[serde(rename_all = "kebab-case")] pub struct NameServiceConfig { - pub package_address: SuiAddress, + pub package_address: IotaAddress, pub registry_id: ObjectID, pub reverse_registry_id: ObjectID, } impl NameServiceConfig { pub fn new( - package_address: SuiAddress, + package_address: IotaAddress, registry_id: ObjectID, reverse_registry_id: ObjectID, ) -> Self { @@ -143,7 +144,7 @@ impl NameServiceConfig { let domain_type_tag = Domain::type_(self.package_address); let domain_bytes = bcs::to_bytes(domain).unwrap(); - sui_types::dynamic_field::derive_dynamic_field_id( + iota_types::dynamic_field::derive_dynamic_field_id( self.registry_id, &TypeTag::Struct(Box::new(domain_type_tag)), &domain_bytes, @@ -152,7 +153,7 @@ impl NameServiceConfig { } pub fn reverse_record_field_id(&self, address: &[u8]) -> ObjectID { - sui_types::dynamic_field::derive_dynamic_field_id( + iota_types::dynamic_field::derive_dynamic_field_id( self.reverse_registry_id, &TypeTag::Address, address, @@ -163,7 +164,7 @@ impl NameServiceConfig { impl Default for NameServiceConfig { fn default() -> Self { - let package_address = SuiAddress::from_str(NAME_SERVICE_DEFAULT_PACKAGE_ADDRESS).unwrap(); + let package_address = IotaAddress::from_str(NAME_SERVICE_DEFAULT_PACKAGE_ADDRESS).unwrap(); let registry_id = ObjectID::from_str(NAME_SERVICE_DEFAULT_REGISTRY).unwrap(); let reverse_registry_id = ObjectID::from_str(NAME_SERVICE_DEFAULT_REVERSE_REGISTRY).unwrap(); @@ -205,7 +206,7 @@ impl FromStr for Domain { } /// Parses a separator from the domain string input. -/// E.g. `example.sui` -> `.` | example*sui -> `@` | `example*sui` -> `*` +/// E.g. `example.iota` -> `.` | example*iota -> `@` | `example*iota` -> `*` fn separator(s: &str) -> Result { let mut domain_separator: Option = None; @@ -225,11 +226,11 @@ fn separator(s: &str) -> Result { } } -/// Converts @label ending to label{separator}sui ending. +/// Converts @label ending to label{separator}iota ending. /// -/// E.g. `@example` -> `example.sui` | `test@example` -> `test.example.sui` +/// E.g. `@example` -> `example.iota` | `test@example` -> `test.example.iota` fn convert_from_new_format(s: &str, separator: &char) -> Result { - let mut splits = s.split(SUI_NEW_FORMAT_SEPARATOR); + let mut splits = s.split(IOTA_NEW_FORMAT_SEPARATOR); let Some(before) = splits.next() else { return Err(NameServiceError::InvalidSeparator); @@ -312,7 +313,7 @@ pub struct NameRecord { /// Timestamp in milliseconds when the record expires. pub expiration_timestamp_ms: u64, /// The target address that this domain points to - pub target_address: Option, + pub target_address: Option, /// Additional data which may be stored in a record pub data: VecMap, } @@ -381,9 +382,9 @@ pub enum NameServiceError { MalformedObject(ObjectID), } -/// A SuinsRegistration object to manage an SLD +/// A IotansRegistration object to manage an SLD #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct SuinsRegistration { +pub struct IotansRegistration { pub id: UID, pub domain: Domain, pub domain_name: String, @@ -395,5 +396,5 @@ pub struct SuinsRegistration { #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct SubDomainRegistration { pub id: UID, - pub nft: SuinsRegistration, + pub nft: IotansRegistration, } diff --git a/crates/iota-json-rpc/src/object_changes.rs b/crates/iota-json-rpc/src/object_changes.rs new file mode 100644 index 00000000000..63ea01b2970 --- /dev/null +++ b/crates/iota-json-rpc/src/object_changes.rs @@ -0,0 +1,95 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use iota_json_rpc_types::ObjectChange; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber}, + effects::ObjectRemoveKind, + object::Owner, + storage::WriteKind, +}; + +use crate::ObjectProvider; + +pub async fn get_object_changes, E>( + object_provider: &P, + sender: IotaAddress, + modified_at_versions: Vec<(ObjectID, SequenceNumber)>, + all_changed_objects: Vec<(ObjectRef, Owner, WriteKind)>, + all_removed_objects: Vec<(ObjectRef, ObjectRemoveKind)>, +) -> Result, E> { + let mut object_changes = vec![]; + + let modify_at_version = modified_at_versions.into_iter().collect::>(); + + for ((object_id, version, digest), owner, kind) in all_changed_objects { + let o = object_provider.get_object(&object_id, &version).await?; + if let Some(type_) = o.type_() { + let object_type = type_.clone().into(); + + match kind { + WriteKind::Mutate => object_changes.push(ObjectChange::Mutated { + sender, + owner, + object_type, + object_id, + version, + // modify_at_version should always be available for mutated object + previous_version: modify_at_version + .get(&object_id) + .cloned() + .unwrap_or_default(), + digest, + }), + WriteKind::Create => object_changes.push(ObjectChange::Created { + sender, + owner, + object_type, + object_id, + version, + digest, + }), + _ => {} + } + } else if let Some(p) = o.data.try_as_package() { + if kind == WriteKind::Create { + object_changes.push(ObjectChange::Published { + package_id: p.id(), + version: p.version(), + digest, + modules: p.serialized_module_map().keys().cloned().collect(), + }) + } + }; + } + + for ((id, version, _), kind) in all_removed_objects { + let o = object_provider + .find_object_lt_or_eq_version(&id, &version) + .await?; + if let Some(o) = o { + if let Some(type_) = o.type_() { + let object_type = type_.clone().into(); + match kind { + ObjectRemoveKind::Delete => object_changes.push(ObjectChange::Deleted { + sender, + object_type, + object_id: id, + version, + }), + ObjectRemoveKind::Wrap => object_changes.push(ObjectChange::Wrapped { + sender, + object_type, + object_id: id, + version, + }), + } + } + }; + } + + Ok(object_changes) +} diff --git a/crates/iota-json-rpc/src/read_api.rs b/crates/iota-json-rpc/src/read_api.rs new file mode 100644 index 00000000000..1003b292d37 --- /dev/null +++ b/crates/iota-json-rpc/src/read_api.rs @@ -0,0 +1,1485 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::HashMap, sync::Arc}; + +use anyhow::anyhow; +use async_trait::async_trait; +use futures::future::join_all; +use indexmap::map::IndexMap; +use iota_core::authority::AuthorityState; +use iota_json_rpc_api::{ + validate_limit, JsonRpcMetrics, ReadApiOpenRpc, ReadApiServer, QUERY_MAX_RESULT_LIMIT, + QUERY_MAX_RESULT_LIMIT_CHECKPOINTS, +}; +use iota_json_rpc_types::{ + BalanceChange, Checkpoint, CheckpointId, CheckpointPage, DisplayFieldsResponse, EventFilter, + IotaEvent, IotaGetPastObjectRequest, IotaLoadedChildObject, IotaLoadedChildObjectsResponse, + IotaMoveStruct, IotaMoveValue, IotaObjectDataOptions, IotaObjectResponse, + IotaPastObjectResponse, IotaTransactionBlock, IotaTransactionBlockEvents, + IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, ObjectChange, + ProtocolConfigResponse, +}; +use iota_open_rpc::Module; +use iota_protocol_config::{ProtocolConfig, ProtocolVersion}; +use iota_storage::key_value_store::TransactionKeyValueStore; +use iota_types::{ + base_types::{ObjectID, SequenceNumber, TransactionDigest}, + collection_types::VecMap, + crypto::AggregateAuthoritySignature, + digests::TransactionEventsDigest, + display::DisplayVersionUpdatedEvent, + effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, + error::{IotaError, IotaObjectResponseError}, + iota_serde::BigInt, + messages_checkpoint::{ + CheckpointContents, CheckpointContentsDigest, CheckpointSequenceNumber, CheckpointSummary, + CheckpointTimestamp, + }, + object::{Object, ObjectRead, PastObjectRead}, + transaction::{Transaction, TransactionDataAPI}, +}; +use itertools::Itertools; +use jsonrpsee::{core::RpcResult, RpcModule}; +use move_bytecode_utils::module_cache::GetModule; +use move_core_types::{ + annotated_value::{MoveStruct, MoveStructLayout, MoveValue}, + language_storage::StructTag, +}; +use mysten_metrics::spawn_monitored_task; +use tap::TapFallible; +use tracing::{debug, error, info, instrument, trace, warn}; + +use crate::{ + authority_state::{StateRead, StateReadError, StateReadResult}, + error::{Error, IotaRpcInputError, RpcInterimResult}, + get_balance_changes_from_effect, get_object_changes, with_tracing, IotaRpcModule, + ObjectProviderCache, +}; + +const MAX_DISPLAY_NESTED_LEVEL: usize = 10; + +// An implementation of the read portion of the JSON-RPC interface intended for +// use in Fullnodes. +#[derive(Clone)] +pub struct ReadApi { + pub state: Arc, + pub transaction_kv_store: Arc, + pub metrics: Arc, +} + +// Internal data structure to make it easy to work with data returned from +// authority store and also enable code sharing between +// get_transaction_with_options, multi_get_transaction_with_options, etc. +#[derive(Default)] +struct IntermediateTransactionResponse { + digest: TransactionDigest, + transaction: Option, + effects: Option, + events: Option, + checkpoint_seq: Option, + balance_changes: Option>, + object_changes: Option>, + timestamp: Option, + errors: Vec, +} + +impl IntermediateTransactionResponse { + pub fn new(digest: TransactionDigest) -> Self { + Self { + digest, + ..Default::default() + } + } + + pub fn transaction(&self) -> &Option { + &self.transaction + } +} + +impl ReadApi { + pub fn new( + state: Arc, + transaction_kv_store: Arc, + metrics: Arc, + ) -> Self { + Self { + state, + transaction_kv_store, + metrics, + } + } + + async fn get_checkpoint_internal(&self, id: CheckpointId) -> Result { + Ok(match id { + CheckpointId::SequenceNumber(seq) => { + let verified_summary = self + .transaction_kv_store + .get_checkpoint_summary(seq) + .await?; + let content = self + .transaction_kv_store + .get_checkpoint_contents_by_digest(verified_summary.content_digest) + .await?; + let signature = verified_summary.auth_sig().signature.clone(); + (verified_summary.into_data(), content, signature).into() + } + CheckpointId::Digest(digest) => { + let verified_summary = self + .transaction_kv_store + .get_checkpoint_summary_by_digest(digest) + .await?; + let content = self + .transaction_kv_store + .get_checkpoint_contents_by_digest(verified_summary.content_digest) + .await?; + let signature = verified_summary.auth_sig().signature.clone(); + (verified_summary.into_data(), content, signature).into() + } + }) + } + + pub async fn get_checkpoints_internal( + state: Arc, + transaction_kv_store: Arc, + // If `Some`, the query will start from the next item after the specified cursor + cursor: Option, + limit: u64, + descending_order: bool, + ) -> StateReadResult> { + let max_checkpoint = state.get_latest_checkpoint_sequence_number()?; + let checkpoint_numbers = + calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); + + let verified_checkpoints = transaction_kv_store + .multi_get_checkpoints_summaries(&checkpoint_numbers) + .await?; + + let checkpoint_summaries_and_signatures: Vec<( + CheckpointSummary, + AggregateAuthoritySignature, + )> = verified_checkpoints + .into_iter() + .flatten() + .map(|check| { + ( + check.clone().into_summary_and_sequence().1, + check.get_validator_signature(), + ) + }) + .collect(); + + let checkpoint_contents_digest: Vec = + checkpoint_summaries_and_signatures + .iter() + .map(|summary| summary.0.content_digest) + .collect(); + let checkpoint_contents = transaction_kv_store + .multi_get_checkpoints_contents_by_digest(checkpoint_contents_digest.as_slice()) + .await?; + let contents: Vec = checkpoint_contents.into_iter().flatten().collect(); + + let mut checkpoints: Vec = vec![]; + + for (summary_and_sig, content) in checkpoint_summaries_and_signatures + .into_iter() + .zip(contents.into_iter()) + { + checkpoints.push(Checkpoint::from(( + summary_and_sig.0, + content, + summary_and_sig.1, + ))); + } + + Ok(checkpoints) + } + + async fn multi_get_transaction_blocks_internal( + &self, + digests: Vec, + opts: Option, + ) -> Result, Error> { + trace!("start"); + + let num_digests = digests.len(); + if num_digests > *QUERY_MAX_RESULT_LIMIT { + Err(IotaRpcInputError::SizeLimitExceeded( + QUERY_MAX_RESULT_LIMIT.to_string(), + ))? + } + self.metrics + .get_tx_blocks_limit + .report(digests.len() as u64); + + let opts = opts.unwrap_or_default(); + + // use LinkedHashMap to dedup and can iterate in insertion order. + let mut temp_response: IndexMap<&TransactionDigest, IntermediateTransactionResponse> = + IndexMap::from_iter( + digests + .iter() + .map(|k| (k, IntermediateTransactionResponse::new(*k))), + ); + if temp_response.len() < num_digests { + Err(IotaRpcInputError::ContainsDuplicates)? + } + + if opts.require_input() { + trace!("getting input"); + let digests_clone = digests.clone(); + let transactions = + self.transaction_kv_store.multi_get_tx(&digests_clone).await.tap_err( + |err| debug!(digests=?digests_clone, "Failed to multi get transactions: {:?}", err), + )?; + + for ((_digest, cache_entry), txn) in + temp_response.iter_mut().zip(transactions.into_iter()) + { + cache_entry.transaction = txn; + } + } + + // Fetch effects when `show_events` is true because events relies on effects + if opts.require_effects() { + trace!("getting effects"); + let digests_clone = digests.clone(); + let effects_list = self.transaction_kv_store + .multi_get_fx_by_tx_digest(&digests_clone) + .await + .tap_err( + |err| debug!(digests=?digests_clone, "Failed to multi get effects for transactions: {:?}", err), + )?; + for ((_digest, cache_entry), e) in + temp_response.iter_mut().zip(effects_list.into_iter()) + { + cache_entry.effects = e; + } + } + + trace!("getting checkpoint sequence numbers"); + let checkpoint_seq_list = self + .transaction_kv_store + .multi_get_transaction_checkpoint(&digests) + .await + .tap_err( + |err| debug!(digests=?digests, "Failed to multi get checkpoint sequence number: {:?}", err))?; + for ((_digest, cache_entry), seq) in temp_response + .iter_mut() + .zip(checkpoint_seq_list.into_iter()) + { + cache_entry.checkpoint_seq = seq; + } + + let unique_checkpoint_numbers = temp_response + .values() + .filter_map(|cache_entry| cache_entry.checkpoint_seq.map(::from)) + // It's likely that many transactions have the same checkpoint, so we don't + // need to over-fetch + .unique() + .collect::>(); + + // fetch timestamp from the DB + trace!("getting checkpoint summaries"); + let timestamps = self + .transaction_kv_store + .multi_get_checkpoints_summaries(&unique_checkpoint_numbers) + .await + .map_err(|e| { + Error::UnexpectedError(format!("Failed to fetch checkpoint summaries by these checkpoint ids: {unique_checkpoint_numbers:?} with error: {e:?}")) + })? + .into_iter() + .map(|c| c.map(|checkpoint| checkpoint.timestamp_ms)); + + // construct a hashmap of checkpoint -> timestamp for fast lookup + let checkpoint_to_timestamp = unique_checkpoint_numbers + .into_iter() + .zip(timestamps) + .collect::>(); + + // fill cache with the timestamp + for (_, cache_entry) in temp_response.iter_mut() { + if cache_entry.checkpoint_seq.is_some() { + // safe to unwrap because is_some is checked + cache_entry.timestamp = *checkpoint_to_timestamp + .get( + cache_entry + .checkpoint_seq + .map(::from) + .as_ref() + .unwrap(), + ) + // Safe to unwrap because checkpoint_seq is guaranteed to exist in + // checkpoint_to_timestamp + .unwrap(); + } + } + + if opts.show_events { + trace!("getting events"); + + let event_digests_list = temp_response + .values() + .filter_map(|cache_entry| match &cache_entry.effects { + Some(eff) => eff.events_digest().cloned(), + None => None, + }) + .collect::>(); + + // fetch events from the DB + let events = self + .transaction_kv_store + .multi_get_events(&event_digests_list) + .await + .map_err(|e| { + Error::UnexpectedError(format!("Failed to call multi_get_events for transactions {digests:?} with event digests {event_digests_list:?}: {e:?}")) + })? + .into_iter(); + + // construct a hashmap of event digests -> events for fast lookup + let event_digest_to_events = event_digests_list + .into_iter() + .zip(events) + .collect::>(); + + // fill cache with the events + for (_, cache_entry) in temp_response.iter_mut() { + let transaction_digest = cache_entry.digest; + let event_digest: Option> = cache_entry + .effects + .as_ref() + .map(|e| e.events_digest().cloned()); + let event_digest = event_digest.flatten(); + if event_digest.is_some() { + // safe to unwrap because `is_some` is checked + let event_digest = event_digest.as_ref().unwrap(); + let events= event_digest_to_events + .get(event_digest) + .cloned() + .unwrap_or_else(|| panic!("Expect event digest {event_digest:?} to be found in cache for transaction {transaction_digest}")) + .map(|events| to_iota_transaction_events(self, cache_entry.digest, events)); + match events { + Some(Ok(e)) => cache_entry.events = Some(e), + Some(Err(e)) => cache_entry.errors.push(e.to_string()), + None => { + error!( + "Failed to fetch events with event digest {event_digest:?} for txn {transaction_digest}" + ); + cache_entry.errors.push(format!( + "Failed to fetch events with event digest {event_digest:?}", + )) + } + } + } else { + // events field will be Some if and only if `show_events` is true and + // there is no error in converting fetching events + cache_entry.events = Some(IotaTransactionBlockEvents::default()); + } + } + } + + let object_cache = + ObjectProviderCache::new((self.state.clone(), self.transaction_kv_store.clone())); + if opts.show_balance_changes { + trace!("getting balance changes"); + + let mut results = vec![]; + for resp in temp_response.values() { + let input_objects = if let Some(tx) = resp.transaction() { + tx.data() + .inner() + .intent_message + .value + .input_objects() + .unwrap_or_default() + } else { + // don't have the input tx, so not much we can do. perhaps this is an Err? + Vec::new() + }; + results.push(get_balance_changes_from_effect( + &object_cache, + resp.effects.as_ref().ok_or_else(|| { + IotaRpcInputError::GenericNotFound( + "unable to derive balance changes because effect is empty".to_string(), + ) + })?, + input_objects, + None, + )); + } + let results = join_all(results).await; + for (result, entry) in results.into_iter().zip(temp_response.iter_mut()) { + match result { + Ok(balance_changes) => entry.1.balance_changes = Some(balance_changes), + Err(e) => entry + .1 + .errors + .push(format!("Failed to fetch balance changes {e:?}")), + } + } + } + + if opts.show_object_changes { + trace!("getting object changes"); + + let mut results = vec![]; + for resp in temp_response.values() { + let effects = resp.effects.as_ref().ok_or_else(|| { + IotaRpcInputError::GenericNotFound( + "unable to derive object changes because effect is empty".to_string(), + ) + })?; + + results.push(get_object_changes( + &object_cache, + resp.transaction + .as_ref() + .ok_or_else(|| { + IotaRpcInputError::GenericNotFound( + "unable to derive object changes because transaction is empty" + .to_string(), + ) + })? + .data() + .intent_message() + .value + .sender(), + effects.modified_at_versions(), + effects.all_changed_objects(), + effects.all_removed_objects(), + )); + } + let results = join_all(results).await; + for (result, entry) in results.into_iter().zip(temp_response.iter_mut()) { + match result { + Ok(object_changes) => entry.1.object_changes = Some(object_changes), + Err(e) => entry + .1 + .errors + .push(format!("Failed to fetch object changes {e:?}")), + } + } + } + + let epoch_store = self.state.load_epoch_store_one_call_per_task(); + let converted_tx_block_resps = temp_response + .into_iter() + .map(|c| convert_to_response(c.1, &opts, epoch_store.module_cache())) + .collect::, _>>()?; + + self.metrics + .get_tx_blocks_result_size + .report(converted_tx_block_resps.len() as u64); + self.metrics + .get_tx_blocks_result_size_total + .inc_by(converted_tx_block_resps.len() as u64); + + trace!("done"); + + Ok(converted_tx_block_resps) + } +} + +#[async_trait] +impl ReadApiServer for ReadApi { + #[instrument(skip(self))] + async fn get_object( + &self, + object_id: ObjectID, + options: Option, + ) -> RpcResult { + with_tracing!(async move { + let state = self.state.clone(); + let object_read = spawn_monitored_task!(async move { + state.get_object_read(&object_id).map_err(|e| { + warn!(?object_id, "Failed to get object: {:?}", e); + Error::from(e) + }) + }) + .await + .map_err(Error::from)??; + let options = options.unwrap_or_default(); + + match object_read { + ObjectRead::NotExists(id) => Ok(IotaObjectResponse::new_with_error( + IotaObjectResponseError::NotExists { object_id: id }, + )), + ObjectRead::Exists(object_ref, o, layout) => { + let mut display_fields = None; + if options.show_display { + match get_display_fields(self, &self.transaction_kv_store, &o, &layout) + .await + { + Ok(rendered_fields) => display_fields = Some(rendered_fields), + Err(e) => { + return Ok(IotaObjectResponse::new( + Some((object_ref, o, layout, options, None).try_into()?), + Some(IotaObjectResponseError::DisplayError { + error: e.to_string(), + }), + )); + } + } + } + Ok(IotaObjectResponse::new_with_data( + (object_ref, o, layout, options, display_fields).try_into()?, + )) + } + ObjectRead::Deleted((object_id, version, digest)) => Ok( + IotaObjectResponse::new_with_error(IotaObjectResponseError::Deleted { + object_id, + version, + digest, + }), + ), + } + }) + } + + #[instrument(skip(self))] + async fn multi_get_objects( + &self, + object_ids: Vec, + options: Option, + ) -> RpcResult> { + with_tracing!(async move { + if object_ids.len() <= *QUERY_MAX_RESULT_LIMIT { + self.metrics + .get_objects_limit + .report(object_ids.len() as u64); + let mut futures = vec![]; + for object_id in object_ids { + futures.push(self.get_object(object_id, options.clone())); + } + let results = join_all(futures).await; + + let objects_result: Result, String> = results + .into_iter() + .map(|result| match result { + Ok(response) => Ok(response), + Err(error) => { + error!("Failed to fetch object with error: {error:?}"); + Err(format!("Error: {}", error)) + } + }) + .collect(); + + let objects = objects_result.map_err(|err| { + Error::UnexpectedError(format!("Failed to fetch objects with error: {}", err)) + })?; + + self.metrics + .get_objects_result_size + .report(objects.len() as u64); + self.metrics + .get_objects_result_size_total + .inc_by(objects.len() as u64); + Ok(objects) + } else { + Err(IotaRpcInputError::SizeLimitExceeded( + QUERY_MAX_RESULT_LIMIT.to_string(), + ))? + } + }) + } + + #[instrument(skip(self))] + async fn try_get_past_object( + &self, + object_id: ObjectID, + version: SequenceNumber, + options: Option, + ) -> RpcResult { + with_tracing!(async move { + let state = self.state.clone(); + let past_read = spawn_monitored_task!(async move { + state.get_past_object_read(&object_id, version) + .map_err(|e| { + error!("Failed to call try_get_past_object for object: {object_id:?} version: {version:?} with error: {e:?}"); + Error::from(e) + })}).await.map_err(Error::from)??; + let options = options.unwrap_or_default(); + match past_read { + PastObjectRead::ObjectNotExists(id) => { + Ok(IotaPastObjectResponse::ObjectNotExists(id)) + } + PastObjectRead::VersionFound(object_ref, o, layout) => { + let display_fields = if options.show_display { + // TODO (jian): api breaking change to also modify past objects. + Some( + get_display_fields(self, &self.transaction_kv_store, &o, &layout) + .await + .map_err(|e| { + Error::UnexpectedError(format!( + "Unable to render object at version {version}: {e}" + )) + })?, + ) + } else { + None + }; + Ok(IotaPastObjectResponse::VersionFound( + (object_ref, o, layout, options, display_fields).try_into()?, + )) + } + PastObjectRead::ObjectDeleted(oref) => { + Ok(IotaPastObjectResponse::ObjectDeleted(oref.into())) + } + PastObjectRead::VersionNotFound(id, seq_num) => { + Ok(IotaPastObjectResponse::VersionNotFound(id, seq_num)) + } + PastObjectRead::VersionTooHigh { + object_id, + asked_version, + latest_version, + } => Ok(IotaPastObjectResponse::VersionTooHigh { + object_id, + asked_version, + latest_version, + }), + } + }) + } + + #[instrument(skip(self))] + async fn try_multi_get_past_objects( + &self, + past_objects: Vec, + options: Option, + ) -> RpcResult> { + with_tracing!(async move { + if past_objects.len() <= *QUERY_MAX_RESULT_LIMIT { + let mut futures = vec![]; + for past_object in past_objects { + futures.push(self.try_get_past_object( + past_object.object_id, + past_object.version, + options.clone(), + )); + } + let results = join_all(futures).await; + + let (oks, errs): (Vec<_>, Vec<_>) = results.into_iter().partition(Result::is_ok); + let success = oks.into_iter().filter_map(Result::ok).collect(); + let errors: Vec<_> = errs.into_iter().filter_map(Result::err).collect(); + if !errors.is_empty() { + let error_string = errors + .iter() + .map(|e| e.to_string()) + .collect::>() + .join("; "); + Err(anyhow!("{error_string}").into()) // Collects errors not related to IotaPastObjectResponse variants + } else { + Ok(success) + } + } else { + Err(IotaRpcInputError::SizeLimitExceeded( + QUERY_MAX_RESULT_LIMIT.to_string(), + ))? + } + }) + } + + #[instrument(skip(self))] + async fn get_total_transaction_blocks(&self) -> RpcResult> { + with_tracing!(async move { + Ok(self + .state + .get_total_transaction_blocks() + .map_err(Error::from)? + .into()) // converts into BigInt + }) + } + + #[instrument(skip(self))] + async fn get_transaction_block( + &self, + digest: TransactionDigest, + opts: Option, + ) -> RpcResult { + with_tracing!(async move { + let opts = opts.unwrap_or_default(); + let mut temp_response = IntermediateTransactionResponse::new(digest); + + // Fetch transaction to determine existence + let transaction_kv_store = self.transaction_kv_store.clone(); + let transaction = spawn_monitored_task!(async move { + transaction_kv_store.get_tx(digest).await.map_err(|err| { + debug!(tx_digest=?digest, "Failed to get transaction: {:?}", err); + Error::from(err) + }) + }) + .await + .map_err(Error::from)??; + let input_objects = transaction + .data() + .inner() + .intent_message + .value + .input_objects() + .unwrap_or_default(); + + // the input is needed for object_changes to retrieve the sender address. + if opts.require_input() { + temp_response.transaction = Some(transaction); + } + + // Fetch effects when `show_events` is true because events relies on effects + if opts.require_effects() { + let transaction_kv_store = self.transaction_kv_store.clone(); + temp_response.effects = Some( + spawn_monitored_task!(async move { + transaction_kv_store + .get_fx_by_tx_digest(digest) + .await + .map_err(|err| { + debug!(tx_digest=?digest, "Failed to get effects: {:?}", err); + Error::from(err) + }) + }) + .await + .map_err(Error::from)??, + ); + } + + temp_response.checkpoint_seq = self + .transaction_kv_store + .deprecated_get_transaction_checkpoint(digest) + .await + .map_err(|e| { + error!("Failed to retrieve checkpoint sequence for transaction {digest:?} with error: {e:?}"); + Error::from(e) + })?; + + if let Some(checkpoint_seq) = &temp_response.checkpoint_seq { + let kv_store = self.transaction_kv_store.clone(); + let checkpoint_seq = *checkpoint_seq; + let checkpoint = spawn_monitored_task!(async move { + kv_store + // safe to unwrap because we have checked `is_some` above + .get_checkpoint_summary(checkpoint_seq) + .await + .map_err(|e| { + error!("Failed to get checkpoint by sequence number: {checkpoint_seq:?} with error: {e:?}"); + Error::from(e) + }) + }).await.map_err(Error::from)??; + // TODO(chris): we don't need to fetch the whole checkpoint summary + temp_response.timestamp = Some(checkpoint.timestamp_ms); + } + + if opts.show_events && temp_response.effects.is_some() { + // safe to unwrap because we have checked is_some + if let Some(event_digest) = temp_response.effects.as_ref().unwrap().events_digest() + { + let transaction_kv_store = self.transaction_kv_store.clone(); + let event_digest = *event_digest; + let events = spawn_monitored_task!(async move { + transaction_kv_store + .get_events(event_digest) + .await + .map_err(|e| { + error!("Failed to call get transaction events for events digest: {event_digest:?} with error {e:?}"); + Error::from(e) + }) + }) + .await + .map_err(Error::from)??; + match to_iota_transaction_events(self, digest, events) { + Ok(e) => temp_response.events = Some(e), + Err(e) => temp_response.errors.push(e.to_string()), + }; + } else { + // events field will be Some if and only if `show_events` is true and + // there is no error in converting fetching events + temp_response.events = Some(IotaTransactionBlockEvents::default()); + } + } + + let object_cache = + ObjectProviderCache::new((self.state.clone(), self.transaction_kv_store.clone())); + if opts.show_balance_changes { + if let Some(effects) = &temp_response.effects { + let balance_changes = get_balance_changes_from_effect( + &object_cache, + effects, + input_objects, + None, + ) + .await; + + if let Ok(balance_changes) = balance_changes { + temp_response.balance_changes = Some(balance_changes); + } else { + temp_response.errors.push(format!( + "Cannot retrieve balance changes: {}", + balance_changes.unwrap_err() + )); + } + } + } + + if opts.show_object_changes { + if let (Some(effects), Some(input)) = + (&temp_response.effects, &temp_response.transaction) + { + let sender = input.data().intent_message().value.sender(); + let object_changes = get_object_changes( + &object_cache, + sender, + effects.modified_at_versions(), + effects.all_changed_objects(), + effects.all_removed_objects(), + ) + .await; + + if let Ok(object_changes) = object_changes { + temp_response.object_changes = Some(object_changes); + } else { + temp_response.errors.push(format!( + "Cannot retrieve object changes: {}", + object_changes.unwrap_err() + )); + } + } + } + let epoch_store = self.state.load_epoch_store_one_call_per_task(); + convert_to_response(temp_response, &opts, epoch_store.module_cache()) + }) + } + + #[instrument(skip(self))] + async fn multi_get_transaction_blocks( + &self, + digests: Vec, + opts: Option, + ) -> RpcResult> { + with_tracing!(async move { + let cloned_self = self.clone(); + spawn_monitored_task!(async move { + cloned_self + .multi_get_transaction_blocks_internal(digests, opts) + .await + }) + .await + .map_err(Error::from)? + }) + } + + #[instrument(skip(self))] + async fn get_events(&self, transaction_digest: TransactionDigest) -> RpcResult> { + with_tracing!(async move { + let state = self.state.clone(); + let transaction_kv_store = self.transaction_kv_store.clone(); + spawn_monitored_task!(async move{ + let store = state.load_epoch_store_one_call_per_task(); + let effect = transaction_kv_store + .get_fx_by_tx_digest(transaction_digest) + .await + .map_err(Error::from)?; + let events = if let Some(event_digest) = effect.events_digest() { + transaction_kv_store + .get_events(*event_digest) + .await + .map_err( + |e| { + error!("Failed to get transaction events for event digest {event_digest:?} with error: {e:?}"); + Error::StateReadError(e.into()) + })? + .data + .into_iter() + .enumerate() + .map(|(seq, e)| { + let layout = store.executor().type_layout_resolver(Box::new(&state.get_backing_package_store().as_ref())).get_annotated_layout(&e.type_)?; + IotaEvent::try_from( + e, + *effect.transaction_digest(), + seq as u64, + None, + layout, + ) + }) + .collect::, _>>() + .map_err(Error::IotaError)? + } else { + vec![] + }; + Ok(events) + }).await.map_err(Error::from)? + }) + } + + #[instrument(skip(self))] + async fn get_latest_checkpoint_sequence_number(&self) -> RpcResult> { + with_tracing!(async move { + Ok(self + .state + .get_latest_checkpoint_sequence_number() + .map_err(|e| { + IotaRpcInputError::GenericNotFound(format!( + "Latest checkpoint sequence number was not found with error :{e}" + )) + })? + .into()) + }) + } + + #[instrument(skip(self))] + async fn get_checkpoint(&self, id: CheckpointId) -> RpcResult { + with_tracing!(self.get_checkpoint_internal(id)) + } + + #[instrument(skip(self))] + async fn get_checkpoints( + &self, + // If `Some`, the query will start from the next item after the specified cursor + cursor: Option>, + limit: Option, + descending_order: bool, + ) -> RpcResult { + with_tracing!(async move { + let limit = validate_limit(limit, QUERY_MAX_RESULT_LIMIT_CHECKPOINTS) + .map_err(IotaRpcInputError::from)?; + + let state = self.state.clone(); + let kv_store = self.transaction_kv_store.clone(); + + self.metrics.get_checkpoints_limit.report(limit as u64); + + let mut data = spawn_monitored_task!(Self::get_checkpoints_internal( + state, + kv_store, + cursor.map(|s| *s), + limit as u64 + 1, + descending_order, + )) + .await + .map_err(Error::from)? + .map_err(Error::from)?; + + let has_next_page = data.len() > limit; + data.truncate(limit); + + let next_cursor = if has_next_page { + data.last().cloned().map(|d| d.sequence_number.into()) + } else { + None + }; + + self.metrics + .get_checkpoints_result_size + .report(data.len() as u64); + self.metrics + .get_checkpoints_result_size_total + .inc_by(data.len() as u64); + + Ok(CheckpointPage { + data, + next_cursor, + has_next_page, + }) + }) + } + + #[instrument(skip(self))] + async fn get_checkpoints_deprecated_limit( + &self, + cursor: Option>, + limit: Option>, + descending_order: bool, + ) -> RpcResult { + with_tracing!(async move { + self.get_checkpoints(cursor, limit.map(|l| *l as usize), descending_order) + .await + .map_err(Error::from) + }) + } + + #[instrument(skip(self))] + async fn get_loaded_child_objects( + &self, + digest: TransactionDigest, + ) -> RpcResult { + with_tracing!(async move { + Ok(IotaLoadedChildObjectsResponse { + loaded_child_objects: match self + .state + .loaded_child_object_versions(&digest) + .map_err(|e| { + error!( + "Failed to get loaded child objects at {digest:?} with error: {e:?}" + ); + Error::StateReadError(e) + })? { + Some(v) => v + .into_iter() + .map(|q| IotaLoadedChildObject::new(q.0, q.1)) + .collect::>(), + None => vec![], + }, + }) + }) + } + + #[instrument(skip(self))] + async fn get_protocol_config( + &self, + version: Option>, + ) -> RpcResult { + with_tracing!(async move { + version + .map(|v| { + ProtocolConfig::get_for_version_if_supported( + (*v).into(), + self.state.get_chain_identifier()?.chain(), + ) + .ok_or(IotaRpcInputError::ProtocolVersionUnsupported( + ProtocolVersion::MIN.as_u64(), + ProtocolVersion::MAX.as_u64(), + )) + .map_err(Error::from) + }) + .unwrap_or(Ok(self + .state + .load_epoch_store_one_call_per_task() + .protocol_config() + .clone())) + .map(ProtocolConfigResponse::from) + }) + } + + #[instrument(skip(self))] + async fn get_chain_identifier(&self) -> RpcResult { + with_tracing!(async move { + let ci = self.state.get_chain_identifier()?; + Ok(ci.to_string()) + }) + } +} + +impl IotaRpcModule for ReadApi { + fn rpc(self) -> RpcModule { + self.into_rpc() + } + + fn rpc_doc_module() -> Module { + ReadApiOpenRpc::module_doc() + } +} + +fn to_iota_transaction_events( + fullnode_api: &ReadApi, + tx_digest: TransactionDigest, + events: TransactionEvents, +) -> Result { + let epoch_store = fullnode_api.state.load_epoch_store_one_call_per_task(); + let backing_package_store = fullnode_api.state.get_backing_package_store(); + let mut layout_resolver = epoch_store + .executor() + .type_layout_resolver(Box::new(backing_package_store.as_ref())); + Ok(IotaTransactionBlockEvents::try_from( + events, + tx_digest, + None, + layout_resolver.as_mut(), + )?) +} + +#[derive(Debug, thiserror::Error)] +pub enum ObjectDisplayError { + #[error("Not a move struct")] + NotMoveStruct, + + #[error("Failed to extract layout")] + Layout, + + #[error("Failed to extract Move object")] + MoveObject, + + #[error(transparent)] + Deserialization(#[from] IotaError), + + #[error("Failed to deserialize 'VersionUpdatedEvent': {0}")] + Bcs(#[from] bcs::Error), + + #[error(transparent)] + StateReadError(#[from] StateReadError), +} + +async fn get_display_fields( + fullnode_api: &ReadApi, + kv_store: &Arc, + original_object: &Object, + original_layout: &Option, +) -> Result { + let Some((object_type, layout)) = get_object_type_and_struct(original_object, original_layout)? + else { + return Ok(DisplayFieldsResponse { + data: None, + error: None, + }); + }; + if let Some(display_object) = + get_display_object_by_type(kv_store, fullnode_api, &object_type).await? + { + return get_rendered_fields(display_object.fields, &layout); + } + Ok(DisplayFieldsResponse { + data: None, + error: None, + }) +} + +async fn get_display_object_by_type( + kv_store: &Arc, + fullnode_api: &ReadApi, + object_type: &StructTag, + // TODO: add query version support +) -> Result, ObjectDisplayError> { + let mut events = fullnode_api + .state + .query_events( + kv_store, + EventFilter::MoveEventType(DisplayVersionUpdatedEvent::type_(object_type)), + None, + 1, + true, + ) + .await?; + + // If there's any recent version of Display, give it to the client. + // TODO: add support for version query. + if let Some(event) = events.pop() { + let display: DisplayVersionUpdatedEvent = bcs::from_bytes(&event.bcs[..])?; + Ok(Some(display)) + } else { + Ok(None) + } +} + +pub fn get_object_type_and_struct( + o: &Object, + layout: &Option, +) -> Result, ObjectDisplayError> { + if let Some(object_type) = o.type_() { + let move_struct = get_move_struct(o, layout)?; + Ok(Some((object_type.clone().into(), move_struct))) + } else { + Ok(None) + } +} + +fn get_move_struct( + o: &Object, + layout: &Option, +) -> Result { + let layout = layout.as_ref().ok_or_else(|| ObjectDisplayError::Layout)?; + Ok(o.data + .try_as_move() + .ok_or_else(|| ObjectDisplayError::MoveObject)? + .to_move_struct(layout)?) +} + +pub fn get_rendered_fields( + fields: VecMap, + move_struct: &MoveStruct, +) -> Result { + let iota_move_value: IotaMoveValue = MoveValue::Struct(move_struct.clone()).into(); + if let IotaMoveValue::Struct(move_struct) = iota_move_value { + let fields = + fields + .contents + .iter() + .map(|entry| match parse_template(&entry.value, &move_struct) { + Ok(value) => Ok((entry.key.clone(), value)), + Err(e) => Err(e), + }); + let (oks, errs): (Vec<_>, Vec<_>) = fields.partition(Result::is_ok); + let success = oks.into_iter().filter_map(Result::ok).collect(); + let errors: Vec<_> = errs.into_iter().filter_map(Result::err).collect(); + let error_string = errors + .iter() + .map(|e| e.to_string()) + .collect::>() + .join("; "); + let error = if !error_string.is_empty() { + Some(IotaObjectResponseError::DisplayError { + error: anyhow!("{error_string}").to_string(), + }) + } else { + None + }; + + return Ok(DisplayFieldsResponse { + data: Some(success), + error, + }); + } + Err(ObjectDisplayError::NotMoveStruct)? +} + +fn parse_template(template: &str, move_struct: &IotaMoveStruct) -> Result { + let mut output = template.to_string(); + let mut var_name = String::new(); + let mut in_braces = false; + let mut escaped = false; + + for ch in template.chars() { + match ch { + '\\' => { + escaped = true; + continue; + } + '{' if !escaped => { + in_braces = true; + var_name.clear(); + } + '}' if !escaped => { + in_braces = false; + let value = get_value_from_move_struct(move_struct, &var_name)?; + output = output.replace(&format!("{{{}}}", var_name), &value.to_string()); + } + _ if !escaped => { + if in_braces { + var_name.push(ch); + } + } + _ => {} + } + escaped = false; + } + + Ok(output.replace('\\', "")) +} + +fn get_value_from_move_struct( + move_struct: &IotaMoveStruct, + var_name: &str, +) -> Result { + let parts: Vec<&str> = var_name.split('.').collect(); + if parts.is_empty() { + Err(anyhow!("Display template value cannot be empty"))?; + } + if parts.len() > MAX_DISPLAY_NESTED_LEVEL { + Err(anyhow!( + "Display template value nested depth cannot exist {}", + MAX_DISPLAY_NESTED_LEVEL + ))?; + } + let mut current_value = &IotaMoveValue::Struct(move_struct.clone()); + // iterate over the parts and try to access the corresponding field + for part in parts { + match current_value { + IotaMoveValue::Struct(move_struct) => { + if let IotaMoveStruct::WithTypes { type_: _, fields } + | IotaMoveStruct::WithFields(fields) = move_struct + { + if let Some(value) = fields.get(part) { + current_value = value; + } else { + Err(anyhow!( + "Field value {} cannot be found in struct", + var_name + ))?; + } + } else { + Err(Error::UnexpectedError(format!( + "Unexpected move struct type for field {}", + var_name + )))?; + } + } + _ => { + return Err(Error::UnexpectedError(format!( + "Unexpected move value type for field {}", + var_name + )))?; + } + } + } + + match current_value { + IotaMoveValue::Option(move_option) => match move_option.as_ref() { + Some(move_value) => Ok(move_value.to_string()), + None => Ok("".to_string()), + }, + IotaMoveValue::Vector(_) => Err(anyhow!( + "Vector is not supported as a Display value {}", + var_name + ))?, + + _ => Ok(current_value.to_string()), + } +} + +fn convert_to_response( + cache: IntermediateTransactionResponse, + opts: &IotaTransactionBlockResponseOptions, + module_cache: &impl GetModule, +) -> RpcInterimResult { + let mut response = IotaTransactionBlockResponse::new(cache.digest); + response.errors = cache.errors; + + if opts.show_raw_input && cache.transaction.is_some() { + let sender_signed_data = cache.transaction.as_ref().unwrap().data(); + let raw_tx = bcs::to_bytes(sender_signed_data) + .map_err(|e| anyhow!("Failed to serialize raw transaction with error: {}", e))?; // TODO: is this a client or server error? + response.raw_transaction = raw_tx; + } + + if opts.show_input && cache.transaction.is_some() { + let tx_block = + IotaTransactionBlock::try_from(cache.transaction.unwrap().into_data(), module_cache)?; + response.transaction = Some(tx_block); + } + + if opts.show_effects && cache.effects.is_some() { + let effects = cache.effects.unwrap().try_into().map_err(|e| { + anyhow!( + // TODO: is this a client or server error? + "Failed to convert transaction block effects with error: {}", + e + ) + })?; + response.effects = Some(effects); + } + + response.checkpoint = cache.checkpoint_seq; + response.timestamp_ms = cache.timestamp; + + if opts.show_events { + response.events = cache.events; + } + + if opts.show_balance_changes { + response.balance_changes = cache.balance_changes; + } + + if opts.show_object_changes { + response.object_changes = cache.object_changes; + } + Ok(response) +} + +fn calculate_checkpoint_numbers( + // If `Some`, the query will start from the next item after the specified cursor + cursor: Option, + limit: u64, + descending_order: bool, + max_checkpoint: CheckpointSequenceNumber, +) -> Vec { + let (start_index, end_index) = match cursor { + Some(t) => { + if descending_order { + let start = std::cmp::min(t.saturating_sub(1), max_checkpoint); + let end = start.saturating_sub(limit - 1); + (end, start) + } else { + let start = + std::cmp::min(t.checked_add(1).unwrap_or(max_checkpoint), max_checkpoint); + let end = std::cmp::min( + start.checked_add(limit - 1).unwrap_or(max_checkpoint), + max_checkpoint, + ); + (start, end) + } + } + None => { + if descending_order { + (max_checkpoint.saturating_sub(limit - 1), max_checkpoint) + } else { + (0, std::cmp::min(limit - 1, max_checkpoint)) + } + } + }; + + if descending_order { + (start_index..=end_index).rev().collect() + } else { + (start_index..=end_index).collect() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_calculate_checkpoint_numbers() { + let cursor = Some(10); + let limit = 5; + let descending_order = true; + let max_checkpoint = 15; + + let checkpoint_numbers = + calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); + + assert_eq!(checkpoint_numbers, vec![9, 8, 7, 6, 5]); + } + + #[test] + fn test_calculate_checkpoint_numbers_descending_no_cursor() { + let cursor = None; + let limit = 5; + let descending_order = true; + let max_checkpoint = 15; + + let checkpoint_numbers = + calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); + + assert_eq!(checkpoint_numbers, vec![15, 14, 13, 12, 11]); + } + + #[test] + fn test_calculate_checkpoint_numbers_ascending_no_cursor() { + let cursor = None; + let limit = 5; + let descending_order = false; + let max_checkpoint = 15; + + let checkpoint_numbers = + calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); + + assert_eq!(checkpoint_numbers, vec![0, 1, 2, 3, 4]); + } + + #[test] + fn test_calculate_checkpoint_numbers_ascending_with_cursor() { + let cursor = Some(10); + let limit = 5; + let descending_order = false; + let max_checkpoint = 15; + + let checkpoint_numbers = + calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); + + assert_eq!(checkpoint_numbers, vec![11, 12, 13, 14, 15]); + } + + #[test] + fn test_calculate_checkpoint_numbers_ascending_limit_exceeds_max() { + let cursor = None; + let limit = 20; + let descending_order = false; + let max_checkpoint = 15; + + let checkpoint_numbers = + calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); + + assert_eq!(checkpoint_numbers, (0..=15).collect::>()); + } + + #[test] + fn test_calculate_checkpoint_numbers_descending_limit_exceeds_max() { + let cursor = None; + let limit = 20; + let descending_order = true; + let max_checkpoint = 15; + + let checkpoint_numbers = + calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); + + assert_eq!(checkpoint_numbers, (0..=15).rev().collect::>()); + } +} diff --git a/crates/sui-json-rpc/src/routing_layer.rs b/crates/iota-json-rpc/src/routing_layer.rs similarity index 93% rename from crates/sui-json-rpc/src/routing_layer.rs rename to crates/iota-json-rpc/src/routing_layer.rs index 4d63b50ea31..c4a1b2f255e 100644 --- a/crates/sui-json-rpc/src/routing_layer.rs +++ b/crates/iota-json-rpc/src/routing_layer.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::{HashMap, HashSet}; -use sui_open_rpc::MethodRouting; +use iota_open_rpc::MethodRouting; #[derive(Debug, Clone)] pub struct RpcRouter { diff --git a/crates/iota-json-rpc/src/transaction_builder_api.rs b/crates/iota-json-rpc/src/transaction_builder_api.rs new file mode 100644 index 00000000000..8181cf0eb5e --- /dev/null +++ b/crates/iota-json-rpc/src/transaction_builder_api.rs @@ -0,0 +1,355 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::Arc; + +use async_trait::async_trait; +use fastcrypto::encoding::Base64; +use iota_core::authority::AuthorityState; +use iota_json::IotaJsonValue; +use iota_json_rpc_api::{TransactionBuilderOpenRpc, TransactionBuilderServer}; +use iota_json_rpc_types::{ + IotaObjectDataFilter, IotaObjectDataOptions, IotaObjectResponse, + IotaTransactionBlockBuilderMode, IotaTypeTag, RPCTransactionRequestParams, + TransactionBlockBytes, +}; +use iota_open_rpc::Module; +use iota_transaction_builder::{DataReader, TransactionBuilder}; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectInfo}, + iota_serde::BigInt, +}; +use jsonrpsee::{core::RpcResult, RpcModule}; +use move_core_types::language_storage::StructTag; + +use crate::{authority_state::StateRead, IotaRpcModule}; + +pub struct TransactionBuilderApi(TransactionBuilder); + +impl TransactionBuilderApi { + pub fn new(state: Arc) -> Self { + let reader = Arc::new(AuthorityStateDataReader::new(state)); + Self(TransactionBuilder::new(reader)) + } + + pub fn new_with_data_reader(data_reader: Arc) -> Self { + Self(TransactionBuilder::new(data_reader)) + } +} + +pub struct AuthorityStateDataReader(Arc); + +impl AuthorityStateDataReader { + pub fn new(state: Arc) -> Self { + Self(state) + } +} + +#[async_trait] +impl DataReader for AuthorityStateDataReader { + async fn get_owned_objects( + &self, + address: IotaAddress, + object_type: StructTag, + ) -> Result, anyhow::Error> { + Ok(self + .0 + // DataReader is used internally, don't need a limit + .get_owner_objects( + address, + None, + Some(IotaObjectDataFilter::StructType(object_type)), + )?) + } + + async fn get_object_with_options( + &self, + object_id: ObjectID, + options: IotaObjectDataOptions, + ) -> Result { + let result = self.0.get_object_read(&object_id)?; + Ok((result, options).try_into()?) + } + + async fn get_reference_gas_price(&self) -> Result { + let epoch_store = self.0.load_epoch_store_one_call_per_task(); + Ok(epoch_store.reference_gas_price()) + } +} + +#[async_trait] +impl TransactionBuilderServer for TransactionBuilderApi { + async fn transfer_object( + &self, + signer: IotaAddress, + object_id: ObjectID, + gas: Option, + gas_budget: BigInt, + recipient: IotaAddress, + ) -> RpcResult { + let data = self + .0 + .transfer_object(signer, object_id, gas, *gas_budget, recipient) + .await?; + Ok(TransactionBlockBytes::from_data(data)?) + } + + async fn transfer_iota( + &self, + signer: IotaAddress, + iota_object_id: ObjectID, + gas_budget: BigInt, + recipient: IotaAddress, + amount: Option>, + ) -> RpcResult { + let data = self + .0 + .transfer_iota( + signer, + iota_object_id, + *gas_budget, + recipient, + amount.map(|a| *a), + ) + .await?; + Ok(TransactionBlockBytes::from_data(data)?) + } + + async fn pay( + &self, + signer: IotaAddress, + input_coins: Vec, + recipients: Vec, + amounts: Vec>, + gas: Option, + gas_budget: BigInt, + ) -> RpcResult { + let data = self + .0 + .pay( + signer, + input_coins, + recipients, + amounts.into_iter().map(|a| *a).collect(), + gas, + *gas_budget, + ) + .await?; + Ok(TransactionBlockBytes::from_data(data)?) + } + + async fn pay_iota( + &self, + signer: IotaAddress, + input_coins: Vec, + recipients: Vec, + amounts: Vec>, + gas_budget: BigInt, + ) -> RpcResult { + let data = self + .0 + .pay_iota( + signer, + input_coins, + recipients, + amounts.into_iter().map(|a| *a).collect(), + *gas_budget, + ) + .await?; + Ok(TransactionBlockBytes::from_data(data)?) + } + + async fn pay_all_iota( + &self, + signer: IotaAddress, + input_coins: Vec, + recipient: IotaAddress, + gas_budget: BigInt, + ) -> RpcResult { + let data = self + .0 + .pay_all_iota(signer, input_coins, recipient, *gas_budget) + .await?; + Ok(TransactionBlockBytes::from_data(data)?) + } + + async fn publish( + &self, + sender: IotaAddress, + compiled_modules: Vec, + dependencies: Vec, + gas: Option, + gas_budget: BigInt, + ) -> RpcResult { + let compiled_modules = compiled_modules + .into_iter() + .map(|data| data.to_vec().map_err(|e| anyhow::anyhow!(e))) + .collect::, _>>()?; + let data = self + .0 + .publish(sender, compiled_modules, dependencies, gas, *gas_budget) + .await?; + Ok(TransactionBlockBytes::from_data(data)?) + } + + async fn split_coin( + &self, + signer: IotaAddress, + coin_object_id: ObjectID, + split_amounts: Vec>, + gas: Option, + gas_budget: BigInt, + ) -> RpcResult { + let split_amounts = split_amounts.into_iter().map(|a| *a).collect(); + let data = self + .0 + .split_coin(signer, coin_object_id, split_amounts, gas, *gas_budget) + .await?; + Ok(TransactionBlockBytes::from_data(data)?) + } + + async fn split_coin_equal( + &self, + signer: IotaAddress, + coin_object_id: ObjectID, + split_count: BigInt, + gas: Option, + gas_budget: BigInt, + ) -> RpcResult { + let data = self + .0 + .split_coin_equal(signer, coin_object_id, *split_count, gas, *gas_budget) + .await?; + Ok(TransactionBlockBytes::from_data(data)?) + } + + async fn merge_coin( + &self, + signer: IotaAddress, + primary_coin: ObjectID, + coin_to_merge: ObjectID, + gas: Option, + gas_budget: BigInt, + ) -> RpcResult { + let data = self + .0 + .merge_coins(signer, primary_coin, coin_to_merge, gas, *gas_budget) + .await?; + Ok(TransactionBlockBytes::from_data(data)?) + } + + async fn move_call( + &self, + signer: IotaAddress, + package_object_id: ObjectID, + module: String, + function: String, + type_arguments: Vec, + rpc_arguments: Vec, + gas: Option, + gas_budget: BigInt, + _txn_builder_mode: Option, + ) -> RpcResult { + Ok(TransactionBlockBytes::from_data( + self.0 + .move_call( + signer, + package_object_id, + &module, + &function, + type_arguments, + rpc_arguments, + gas, + *gas_budget, + None, + ) + .await?, + )?) + } + + async fn batch_transaction( + &self, + signer: IotaAddress, + params: Vec, + gas: Option, + gas_budget: BigInt, + _txn_builder_mode: Option, + ) -> RpcResult { + Ok(TransactionBlockBytes::from_data( + self.0 + .batch_transaction(signer, params, gas, *gas_budget) + .await?, + )?) + } + + async fn request_add_stake( + &self, + signer: IotaAddress, + coins: Vec, + amount: Option>, + validator: IotaAddress, + gas: Option, + gas_budget: BigInt, + ) -> RpcResult { + let amount = amount.map(|a| *a); + Ok(TransactionBlockBytes::from_data( + self.0 + .request_add_stake(signer, coins, amount, validator, gas, *gas_budget) + .await?, + )?) + } + + async fn request_withdraw_stake( + &self, + signer: IotaAddress, + staked_iota: ObjectID, + gas: Option, + gas_budget: BigInt, + ) -> RpcResult { + Ok(TransactionBlockBytes::from_data( + self.0 + .request_withdraw_stake(signer, staked_iota, gas, *gas_budget) + .await?, + )?) + } + + async fn request_add_timelocked_stake( + &self, + signer: IotaAddress, + locked_balance: ObjectID, + validator: IotaAddress, + gas: ObjectID, + gas_budget: BigInt, + ) -> RpcResult { + Ok(TransactionBlockBytes::from_data( + self.0 + .request_add_timelocked_stake(signer, locked_balance, validator, gas, *gas_budget) + .await?, + )?) + } + + async fn request_withdraw_timelocked_stake( + &self, + signer: IotaAddress, + timelocked_staked_iota: ObjectID, + gas: ObjectID, + gas_budget: BigInt, + ) -> RpcResult { + Ok(TransactionBlockBytes::from_data( + self.0 + .request_withdraw_timelocked_stake(signer, timelocked_staked_iota, gas, *gas_budget) + .await?, + )?) + } +} + +impl IotaRpcModule for TransactionBuilderApi { + fn rpc(self) -> RpcModule { + self.into_rpc() + } + + fn rpc_doc_module() -> Module { + TransactionBuilderOpenRpc::module_doc() + } +} diff --git a/crates/sui-json-rpc/src/transaction_execution_api.rs b/crates/iota-json-rpc/src/transaction_execution_api.rs similarity index 88% rename from crates/sui-json-rpc/src/transaction_execution_api.rs rename to crates/iota-json-rpc/src/transaction_execution_api.rs index 7199b341a9e..b5588fdc2f7 100644 --- a/crates/sui-json-rpc/src/transaction_execution_api.rs +++ b/crates/iota-json-rpc/src/transaction_execution_api.rs @@ -1,44 +1,45 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{sync::Arc, time::Duration}; use async_trait::async_trait; use fastcrypto::{encoding::Base64, traits::ToFromBytes}; -use jsonrpsee::{core::RpcResult, RpcModule}; -use mysten_metrics::spawn_monitored_task; -use shared_crypto::intent::{AppId, Intent, IntentMessage, IntentScope, IntentVersion}; -use sui_core::{ +use iota_core::{ authority::AuthorityState, authority_client::NetworkAuthorityClient, transaction_orchestrator::TransactiondOrchestrator, }; -use sui_json_rpc_api::{JsonRpcMetrics, WriteApiOpenRpc, WriteApiServer}; -use sui_json_rpc_types::{ - DevInspectArgs, DevInspectResults, DryRunTransactionBlockResponse, SuiTransactionBlock, - SuiTransactionBlockEvents, SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, +use iota_json_rpc_api::{JsonRpcMetrics, WriteApiOpenRpc, WriteApiServer}; +use iota_json_rpc_types::{ + DevInspectArgs, DevInspectResults, DryRunTransactionBlockResponse, IotaTransactionBlock, + IotaTransactionBlockEvents, IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, }; -use sui_open_rpc::Module; -use sui_types::{ - base_types::SuiAddress, +use iota_open_rpc::Module; +use iota_types::{ + base_types::IotaAddress, crypto::default_hash, digests::TransactionDigest, effects::TransactionEffectsAPI, + iota_serde::BigInt, quorum_driver_types::{ ExecuteTransactionRequest, ExecuteTransactionRequestType, ExecuteTransactionResponse, }, signature::GenericSignature, - sui_serde::BigInt, transaction::{ InputObjectKind, Transaction, TransactionData, TransactionDataAPI, TransactionKind, }, }; +use jsonrpsee::{core::RpcResult, RpcModule}; +use mysten_metrics::spawn_monitored_task; +use shared_crypto::intent::{AppId, Intent, IntentMessage, IntentScope, IntentVersion}; use tracing::instrument; use crate::{ authority_state::StateRead, - error::{Error, SuiRpcInputError}, - get_balance_changes_from_effect, get_object_changes, with_tracing, ObjectProviderCache, - SuiRpcModule, + error::{Error, IotaRpcInputError}, + get_balance_changes_from_effect, get_object_changes, with_tracing, IotaRpcModule, + ObjectProviderCache, }; pub struct TransactionExecutionApi { @@ -63,7 +64,7 @@ impl TransactionExecutionApi { pub fn convert_bytes( &self, tx_bytes: Base64, - ) -> Result { + ) -> Result { let data: T = bcs::from_bytes(&tx_bytes.to_vec()?)?; Ok(data) } @@ -73,24 +74,24 @@ impl TransactionExecutionApi { &self, tx_bytes: Base64, signatures: Vec, - opts: Option, + opts: Option, request_type: Option, ) -> Result< ( - SuiTransactionBlockResponseOptions, + IotaTransactionBlockResponseOptions, ExecuteTransactionRequestType, - SuiAddress, + IotaAddress, Vec, Transaction, - Option, + Option, Vec, ), - SuiRpcInputError, + IotaRpcInputError, > { let opts = opts.unwrap_or_default(); let request_type = match (request_type, opts.require_local_execution()) { (Some(ExecuteTransactionRequestType::WaitForEffectsCert), true) => { - Err(SuiRpcInputError::InvalidExecuteTransactionRequestType)? + Err(IotaRpcInputError::InvalidExecuteTransactionRequestType)? } (t, _) => t.unwrap_or_else(|| opts.default_execution_request_type()), }; @@ -110,7 +111,7 @@ impl TransactionExecutionApi { }; let transaction = if opts.show_input { let epoch_store = self.state.load_epoch_store_one_call_per_task(); - Some(SuiTransactionBlock::try_from( + Some(IotaTransactionBlock::try_from( txn.data().clone(), epoch_store.module_cache(), )?) @@ -132,9 +133,9 @@ impl TransactionExecutionApi { &self, tx_bytes: Base64, signatures: Vec, - opts: Option, + opts: Option, request_type: Option, - ) -> Result { + ) -> Result { let (opts, request_type, sender, input_objs, txn, transaction, raw_transaction) = self.prepare_execute_transaction_block(tx_bytes, signatures, opts, request_type)?; let digest = *txn.digest(); @@ -154,14 +155,14 @@ impl TransactionExecutionApi { let _post_orch_timer = self.metrics.post_orchestrator_latency_ms.start_timer(); let ExecuteTransactionResponse::EffectsCert(cert) = response; let (effects, transaction_events, is_executed_locally) = *cert; - let mut events: Option = None; + let mut events: Option = None; if opts.show_events { let epoch_store = self.state.load_epoch_store_one_call_per_task(); let backing_package_store = self.state.get_backing_package_store(); let mut layout_resolver = epoch_store .executor() .type_layout_resolver(Box::new(backing_package_store.as_ref())); - events = Some(SuiTransactionBlockEvents::try_from( + events = Some(IotaTransactionBlockEvents::try_from( transaction_events, digest, None, @@ -199,7 +200,7 @@ impl TransactionExecutionApi { vec![] }; - Ok(SuiTransactionBlockResponse { + Ok(IotaTransactionBlockResponse { digest, transaction, raw_transaction, @@ -218,14 +219,14 @@ impl TransactionExecutionApi { pub fn prepare_dry_run_transaction_block( &self, tx_bytes: Base64, - ) -> Result<(TransactionData, TransactionDigest, Vec), SuiRpcInputError> { + ) -> Result<(TransactionData, TransactionDigest, Vec), IotaRpcInputError> { let tx_data: TransactionData = self.convert_bytes(tx_bytes)?; let input_objs = tx_data.input_objects()?; let intent_msg = IntentMessage::new( Intent { version: IntentVersion::V0, scope: IntentScope::TransactionData, - app_id: AppId::Sui, + app_id: AppId::Iota, }, tx_data, ); @@ -278,9 +279,9 @@ impl WriteApiServer for TransactionExecutionApi { &self, tx_bytes: Base64, signatures: Vec, - opts: Option, + opts: Option, request_type: Option, - ) -> RpcResult { + ) -> RpcResult { with_tracing!(Duration::from_secs(10), async move { self.execute_transaction_block(tx_bytes, signatures, opts, request_type) .await @@ -290,7 +291,7 @@ impl WriteApiServer for TransactionExecutionApi { #[instrument(skip(self))] async fn dev_inspect_transaction_block( &self, - sender_address: SuiAddress, + sender_address: IotaAddress, tx_bytes: Base64, gas_price: Option>, _epoch: Option>, @@ -330,7 +331,7 @@ impl WriteApiServer for TransactionExecutionApi { } } -impl SuiRpcModule for TransactionExecutionApi { +impl IotaRpcModule for TransactionExecutionApi { fn rpc(self) -> RpcModule { self.into_rpc() } diff --git a/crates/iota-json-rpc/src/unit_tests/data/validator_exchange_rate/rates.json b/crates/iota-json-rpc/src/unit_tests/data/validator_exchange_rate/rates.json new file mode 100644 index 00000000000..c03b54916c3 --- /dev/null +++ b/crates/iota-json-rpc/src/unit_tests/data/validator_exchange_rate/rates.json @@ -0,0 +1 @@ +{"01node":[[167,{"iota_amount":35899352829617961,"pool_token_amount":35167964851472947}],[166,{"iota_amount":35894635008379974,"pool_token_amount":35167589707247808}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":35866428578351272,"pool_token_amount":35165428023127803}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":35856795079957317,"pool_token_amount":35164663337242363}],[156,{"iota_amount":35847171423859400,"pool_token_amount":35163907355994735}],[155,{"iota_amount":35842259838498301,"pool_token_amount":35163521931965938}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":35832323095869636,"pool_token_amount":35162550065203222}],[149,{"iota_amount":35813022905267424,"pool_token_amount":35160987430070301}],[148,{"iota_amount":35807463745655398,"pool_token_amount":35159876066304843}],[146,{"iota_amount":35797885586783620,"pool_token_amount":35159170792411269}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":35781672931381071,"pool_token_amount":35161017940266929}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":35776757993525179,"pool_token_amount":35160631564962536}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[130,{"iota_amount":35722772619255235,"pool_token_amount":35156402658387802}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":35711191416942195,"pool_token_amount":35149371306178667}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":35697871063613660,"pool_token_amount":35149442536686591}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":35681930276104481,"pool_token_amount":35146834152140152}],[121,{"iota_amount":35673342931448668,"pool_token_amount":35147104822309087}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":35654083137501737,"pool_token_amount":35145765162012789}],[116,{"iota_amount":35649170657616036,"pool_token_amount":35145378684309259}],[115,{"iota_amount":35644452365695873,"pool_token_amount":35145183937266114}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":35634728237482068,"pool_token_amount":35144510894842630}],[112,{"iota_amount":35628748498077351,"pool_token_amount":35143072321402701}],[109,{"iota_amount":35611905496842073,"pool_token_amount":35140337533651238}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":35589966297680344,"pool_token_amount":35138670365169253}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":35584282756016771,"pool_token_amount":35138225106374292}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":35526717640965292,"pool_token_amount":35131806722393544}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":35521303474503238,"pool_token_amount":35131383868716957}],[91,{"iota_amount":35510474574512078,"pool_token_amount":35130527004684915}],[89,{"iota_amount":35499596115808720,"pool_token_amount":35129581321508401}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":35467230513826377,"pool_token_amount":35126964014889569}],[81,{"iota_amount":35456345039098400,"pool_token_amount":35125918326891889}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":35450769381797069,"pool_token_amount":35125365328264671}],[78,{"iota_amount":35439234897586982,"pool_token_amount":35123670599410786}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":35389945306716957,"pool_token_amount":35119514866241807}],[68,{"iota_amount":35384479435091140,"pool_token_amount":35119163753307465}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[61,{"iota_amount":35346141703824881,"pool_token_amount":35115817084513559}],[60,{"iota_amount":35340805935962004,"pool_token_amount":35115393004614797}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":35278566657180210,"pool_token_amount":35102418052806218}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":35267358941663083,"pool_token_amount":35101033364695387}],[47,{"iota_amount":35262027719785051,"pool_token_amount":35100611713369984}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":35219950114669908,"pool_token_amount":35103411341100541}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":35208904991784491,"pool_token_amount":35102522980624148}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[31,{"iota_amount":35179804004997458,"pool_token_amount":35100742441498602}],[29,{"iota_amount":35467223071507847,"pool_token_amount":35399577747655396}],[26,{"iota_amount":35145181142328545,"pool_token_amount":35097583828526451}],[24,{"iota_amount":35061152124115585,"pool_token_amount":35028470602959208}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":25000000031979264,"pool_token_amount":25000000000639572}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":25000000000000000,"pool_token_amount":25000000000000000}]],"A41":[[167,{"iota_amount":27565797795973335,"pool_token_amount":27028771266450611}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":27570988699825350,"pool_token_amount":27037046929509186}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":27553351035026007,"pool_token_amount":27035670831590609}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"iota_amount":27512312303009122,"pool_token_amount":27031341388344369}],[148,{"iota_amount":27501705047152318,"pool_token_amount":27027479686385565}],[147,{"iota_amount":27497992476580722,"pool_token_amount":27027113946092485}],[146,{"iota_amount":27494285700456241,"pool_token_amount":27026754050027824}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":27487061166244646,"pool_token_amount":27026046529488669}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":27476330254021937,"pool_token_amount":27025080727677398}],[140,{"iota_amount":27472718971359752,"pool_token_amount":27024725529813471}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":27472043566383301,"pool_token_amount":27033661873253587}],[136,{"iota_amount":27468428307748456,"pool_token_amount":27033306115789485}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":27457595374938662,"pool_token_amount":27032245149447796}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":27440490411762611,"pool_token_amount":27031421635223684}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":27436893047193011,"pool_token_amount":27031081831422650}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":27411617845010411,"pool_token_amount":27028598005480033}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":27397175339106152,"pool_token_amount":27027172793016629}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":27393565173970705,"pool_token_amount":27026816651699294}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":27386344762381823,"pool_token_amount":27026104234305114}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":27375500086580902,"pool_token_amount":27025023279725843}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":27384350632639936,"pool_token_amount":27040895219174179}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":27367622471924243,"pool_token_amount":27039243030388432}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[100,{"iota_amount":27350656048228135,"pool_token_amount":27037570842598090}],[98,{"iota_amount":27342410413461125,"pool_token_amount":27036757447809085}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":27313459808425425,"pool_token_amount":27033907906923433}],[90,{"iota_amount":27310957366889275,"pool_token_amount":27035035218211974}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":27306914055767692,"pool_token_amount":27034634971561982}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":27294799187434493,"pool_token_amount":27033435403657578}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":27289494690351082,"pool_token_amount":27031763094695012}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":27271820395297662,"pool_token_amount":27028542724790202}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":27259445090001113,"pool_token_amount":27027193872465250}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":27247432991980248,"pool_token_amount":27025996492303658}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":27247945102257861,"pool_token_amount":27030077055639129}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":27216337605333506,"pool_token_amount":27025314036515480}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":27212003616707252,"pool_token_amount":27024883679550149}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":27191969876884773,"pool_token_amount":27019588521613874}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":27166125409771648,"pool_token_amount":27004638726859948}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":27120210053332182,"pool_token_amount":26995383251432965}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":27107627867288215,"pool_token_amount":27004962454692101}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":27098562165947582,"pool_token_amount":27003305482367730}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":27086218526696561,"pool_token_amount":27002071083781656}],[37,{"iota_amount":27081998987719701,"pool_token_amount":27001659418114157}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":27057970258189577,"pool_token_amount":26997774075236993}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":27044174160138780,"pool_token_amount":26996389240972581}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"iota_amount":20023367414445940,"pool_token_amount":20001786010006704}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":20009758488195300,"pool_token_amount":20000598798782603}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":20004677735991001,"pool_token_amount":20000103331086132}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":20000000015774701,"pool_token_amount":20000000000315481}],[17,{"iota_amount":20000000012328401,"pool_token_amount":20000000000246557}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"ANodes":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":35776912762248031,"pool_token_amount":35076572465911553}],[161,{"iota_amount":35776516365178193,"pool_token_amount":35080336624703625}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":35771787934955269,"pool_token_amount":35079857980153053}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":35766975860986207,"pool_token_amount":35079386080312534}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":35737864137765631,"pool_token_amount":35080564537901476}],[151,{"iota_amount":35727132243792307,"pool_token_amount":35074281080335284}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":35682512508539158,"pool_token_amount":35068759206392545}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":35672882832158783,"pool_token_amount":35067812743747567}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":35629717333082480,"pool_token_amount":35063947453361888}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":35609588069220101,"pool_token_amount":35061413191115062}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":35590331420668866,"pool_token_amount":35059903042806352}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":35580707919696605,"pool_token_amount":35059152832281300}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":35532548771963267,"pool_token_amount":35055335389180914}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":35511677699193499,"pool_token_amount":35053687792337210}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[103,{"iota_amount":35489461473129249,"pool_token_amount":35051952326213164}],[101,{"iota_amount":35478408487180345,"pool_token_amount":35051099340719939}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":35451002516035482,"pool_token_amount":35048932644271300}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":35434715454817781,"pool_token_amount":35047644272561064}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":35429295678033087,"pool_token_amount":35047216336294694}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":35407910958684515,"pool_token_amount":35045496355655081}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":35375745831871334,"pool_token_amount":35042935854596487}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":35327813171723261,"pool_token_amount":35039435486502309}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":35272403621844127,"pool_token_amount":35034778847672262}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":35240406948357111,"pool_token_amount":35032245960105482}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":35229761892216064,"pool_token_amount":35031422287895324}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":35217965961883103,"pool_token_amount":35029455587337167}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":35212630512489798,"pool_token_amount":35029031036092834}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":35187307993908212,"pool_token_amount":35013602723013988}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":35180933395388450,"pool_token_amount":35012143195957992}],[48,{"iota_amount":35175599279093302,"pool_token_amount":35011719430622372}],[47,{"iota_amount":35170264961734642,"pool_token_amount":35011294673397494}],[46,{"iota_amount":35164626028659785,"pool_token_amount":35010566836151741}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"iota_amount":35137822123488198,"pool_token_amount":35008413361728057}],[39,{"iota_amount":35126683731718677,"pool_token_amount":35007299999113715}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":35110084291329007,"pool_token_amount":35005973619213076}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":35085984357790107,"pool_token_amount":35003468850605816}],[31,{"iota_amount":35080051684969255,"pool_token_amount":35002957729714668}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"iota_amount":25042622108777768,"pool_token_amount":25013929985989569}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":25029558797371582,"pool_token_amount":25012207725171793}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":25005943238434252,"pool_token_amount":25000170765339556}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":25000000032208364,"pool_token_amount":25000000000644154}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":25000000019248364,"pool_token_amount":25000000000384956}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":25000000000572400,"pool_token_amount":25000000000011444}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":25000000000000000,"pool_token_amount":25000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Aftermath":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":107326933123545581,"pool_token_amount":105113560956765493}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":107298584497769675,"pool_token_amount":105112451268316333}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":107284450207927809,"pool_token_amount":105111897415382603}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":107255177735401777,"pool_token_amount":105110749211025972}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":107211274260816842,"pool_token_amount":105109027957048783}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"iota_amount":107137043341814663,"pool_token_amount":105105128030477816}],[146,{"iota_amount":107083902945467558,"pool_token_amount":105107869576035515}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":106995939981008817,"pool_token_amount":105103208346478044}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":106981492479992000,"pool_token_amount":105102640668813979}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":106956675962719528,"pool_token_amount":105091895452746007}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":106898755428504594,"pool_token_amount":105089533686362393}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":106855108351198517,"pool_token_amount":105087552026933733}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":106826096685286558,"pool_token_amount":105086328988979437}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":106782736392211683,"pool_token_amount":105084632465584310}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":106768289350353497,"pool_token_amount":105084063773177035}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":106739392924263508,"pool_token_amount":105082926074476266}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":106724942505968547,"pool_token_amount":105082357027388350}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":106667208493604265,"pool_token_amount":105080122453542964}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":106549359730511791,"pool_token_amount":105073286476162634}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":106467649957621572,"pool_token_amount":105069988504145854}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":106453452842122193,"pool_token_amount":105071813402100574}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[99,{"iota_amount":106370409881896138,"pool_token_amount":105068606927363071}],[98,{"iota_amount":106353921370554989,"pool_token_amount":105067956412602915}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":106321131377478568,"pool_token_amount":105066690195265350}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":106222556546129616,"pool_token_amount":105061803015942703}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":106190450231860081,"pool_token_amount":105060533660928540}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":106174297918768752,"pool_token_amount":105059895399080670}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":106042455978565748,"pool_token_amount":104959922101866367}],[84,{"iota_amount":106026130172312016,"pool_token_amount":104958886154088921}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":105994186183246095,"pool_token_amount":104957620214339329}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":105960376666159956,"pool_token_amount":104955034668039030}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":105928274047503014,"pool_token_amount":104953487247633894}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":105896478538823031,"pool_token_amount":104952225140410116}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":105830431648445243,"pool_token_amount":104948628147371969}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":105746277043784963,"pool_token_amount":104945384758770885}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":105729385600945089,"pool_token_amount":104944714218293348}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":105662329319958462,"pool_token_amount":104939681624455969}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":105630763503057974,"pool_token_amount":104938640517845953}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":105564060346189754,"pool_token_amount":104933319889933989}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":105468611464212946,"pool_token_amount":104930608931863046}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":105452777469885941,"pool_token_amount":104930247201362920}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"iota_amount":105327781921035290,"pool_token_amount":104929342106086780}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":105116022491668488,"pool_token_amount":104917061673361592}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":25405902238434252,"pool_token_amount":25400037437186026}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":25000000000691200,"pool_token_amount":25000000000013816}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Ahoy Validator":[[167,{"iota_amount":137536556634519065,"pool_token_amount":134660856618901182}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":137502729281141466,"pool_token_amount":134661693349568612}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":137467077483403773,"pool_token_amount":134660744242601154}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":137432509022301453,"pool_token_amount":134660739742482524}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":137361751793581491,"pool_token_amount":134660682803590203}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":137326119985718382,"pool_token_amount":134660683174765992}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"iota_amount":137236781078120340,"pool_token_amount":134660441933397429}],[149,{"iota_amount":137218955399086884,"pool_token_amount":134660436071910779}],[148,{"iota_amount":137202333399116466,"pool_token_amount":134661517940145946}],[147,{"iota_amount":137183208512157532,"pool_token_amount":134660059933081454}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":137112338487996913,"pool_token_amount":134659775814189883}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":137041806001363114,"pool_token_amount":134659703377109446}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":136989109021061677,"pool_token_amount":134659700344161840}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":136936772699347172,"pool_token_amount":134660203276785633}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":137339542445201749,"pool_token_amount":135160564582719192}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":137269828867400668,"pool_token_amount":135161410832508839}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":137216915522700760,"pool_token_amount":135161421725769360}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":137181613851657855,"pool_token_amount":135161394370760660}],[117,{"iota_amount":137163981416581946,"pool_token_amount":135161395438475736}],[116,{"iota_amount":137146409437449345,"pool_token_amount":135161455363992860}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":137128681207677113,"pool_token_amount":135161456455717408}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":137093212473277407,"pool_token_amount":135161446932863334}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":137057827122667632,"pool_token_amount":135161428019237217}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":136940145602921211,"pool_token_amount":135161337570391070}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":136919784388067637,"pool_token_amount":135161386416538189}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"iota_amount":136858808042889288,"pool_token_amount":135161663539327888}],[97,{"iota_amount":136767365299724206,"pool_token_amount":135150907430503097}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":136747577891802889,"pool_token_amount":135151179946329724}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":136569360774064533,"pool_token_amount":135150949506361963}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":136530160188369629,"pool_token_amount":135150985487653693}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":136471190344212381,"pool_token_amount":135150627503657867}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":136095498533212531,"pool_token_amount":135175309888560686}],[61,{"iota_amount":136076245216832988,"pool_token_amount":135175493000305786}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":136056687938046260,"pool_token_amount":135175482910819079}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":136037299596173487,"pool_token_amount":135175634795734766}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":135850655977030339,"pool_token_amount":135146048253782527}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":135734934931634380,"pool_token_amount":135148626536702810}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":135695392675213274,"pool_token_amount":135148591036333149}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":135675429301120486,"pool_token_amount":135148489202469978}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":135574776878503731,"pool_token_amount":135148133631043139}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":135554263461423538,"pool_token_amount":135148209689437509}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":100526499684542534,"pool_token_amount":100257379408674274}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":100493790983202954,"pool_token_amount":100257245858401769}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":100441120563435796,"pool_token_amount":100253725710004158}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":100423388647635235,"pool_token_amount":100252845829209127}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Allnodes":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":41945226777940910,"pool_token_amount":41058717489928776}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":41933387589231820,"pool_token_amount":41057569157037985}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":41947929794460088,"pool_token_amount":41103354368762468}],[156,{"iota_amount":41942655910180052,"pool_token_amount":41103505187266885}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":41931349675742423,"pool_token_amount":41103064220258078}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"iota_amount":41841638502044587,"pool_token_amount":41046928310421344}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"iota_amount":41843932876285206,"pool_token_amount":41060013976513164}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":41820083443540515,"pool_token_amount":41063268316838961}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":41803813342841935,"pool_token_amount":41057960828336695}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":41775654335610327,"pool_token_amount":41051663915234929}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":41759599461538987,"pool_token_amount":41046567901553573}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":41752200377003645,"pool_token_amount":41044638238708895}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":41742650650682184,"pool_token_amount":41040594749351098}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":41730211471976507,"pool_token_amount":41039058842248097}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":41711760929287013,"pool_token_amount":41026263701797818}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":41703161107376949,"pool_token_amount":41023151631856085}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":41688021114557743,"pool_token_amount":41019024609001103}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":41681957461154797,"pool_token_amount":41018310615762379}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[120,{"iota_amount":41660448525927971,"pool_token_amount":41018248453409150}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":41655075270979316,"pool_token_amount":41018305805930474}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":41650175466005178,"pool_token_amount":41019099119304947}],[117,{"iota_amount":41643536165007314,"pool_token_amount":41017908299252250}],[116,{"iota_amount":41631429336570009,"pool_token_amount":41011331978740780}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":41609283289939211,"pool_token_amount":41005563539552877}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":41553427689994447,"pool_token_amount":40961490972781829}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":41570436019285049,"pool_token_amount":41001388585514539}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":48065107380532829,"pool_token_amount":47500461133153483}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":47925269003691818,"pool_token_amount":47487418020412692}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":47899205590229658,"pool_token_amount":47482854304459720}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":47860299510468105,"pool_token_amount":47489321867141342}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":47851383639288819,"pool_token_amount":47487931328251677}],[65,{"iota_amount":48491364885554483,"pool_token_amount":48130720199721504}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":48389961305918353,"pool_token_amount":48087113334345430}],[56,{"iota_amount":48382835338071581,"pool_token_amount":48087176153055754}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":46363439714269269,"pool_token_amount":46087049435813747}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":45637528012794795,"pool_token_amount":45405762861244766}],[47,{"iota_amount":45614917394395907,"pool_token_amount":45396920176703552}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":45508456906330550,"pool_token_amount":45345917078726522}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":45500322617991066,"pool_token_amount":45344760959613013}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":35580301554891828,"pool_token_amount":35481265429849100}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":35485129761915502,"pool_token_amount":35416306743889336}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":35474352629132506,"pool_token_amount":35411657684784245}],[25,{"iota_amount":25435749166272888,"pool_token_amount":25405778066530643}],[24,{"iota_amount":25205554474744994,"pool_token_amount":25181297927578319}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":25135090838487568,"pool_token_amount":25123107106458969}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":25650000019248364,"pool_token_amount":25649999999894508}],[16,{"iota_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Anchorage Digital-1":[[167,{"iota_amount":30616090018098256,"pool_token_amount":30065177769519725}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[159,{"iota_amount":30579497301791575,"pool_token_amount":30058940988783163}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":30575387543367356,"pool_token_amount":30058698600526780}],[157,{"iota_amount":30571277687624579,"pool_token_amount":30058456175899796}],[156,{"iota_amount":30567168191159251,"pool_token_amount":30058213741830163}],[155,{"iota_amount":30563058484490832,"pool_token_amount":30057971264690708}],[152,{"iota_amount":30550524568810380,"pool_token_amount":30057043702629882}],[151,{"iota_amount":30546414409305347,"pool_token_amount":30056801076089132}],[150,{"iota_amount":30542304421178100,"pool_token_amount":30056558428987848}],[149,{"iota_amount":30538193986235439,"pool_token_amount":30056315724793393}],[148,{"iota_amount":30534043599829442,"pool_token_amount":30056033623938680}],[145,{"iota_amount":30522427466064763,"pool_token_amount":30056018829848775}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":30510138198094224,"pool_token_amount":30055339234123614}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":30498051539468497,"pool_token_amount":30054672527726691}],[138,{"iota_amount":30494081119572262,"pool_token_amount":30054479972351211}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":30467816621944545,"pool_token_amount":30054916236948756}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":30459791890809073,"pool_token_amount":30054450552641164}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":30429898714491600,"pool_token_amount":30073540174854425}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":30432233185012054,"pool_token_amount":30091135159620143}],[111,{"iota_amount":30418236693775841,"pool_token_amount":30081117418103842}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":30414199254081588,"pool_token_amount":30080948525172185}],[109,{"iota_amount":30404846013543378,"pool_token_amount":30075948421509901}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":30365906038700441,"pool_token_amount":30054724899180680}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":30360151498615884,"pool_token_amount":30053456938944156}],[101,{"iota_amount":30315905353895954,"pool_token_amount":30022896535349530}],[100,{"iota_amount":30312201857552185,"pool_token_amount":30023607529927007}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":30286068107266744,"pool_token_amount":30023466990907308}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[88,{"iota_amount":121426725771408009,"pool_token_amount":120512524303800711}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":121390640030155877,"pool_token_amount":120511029711187150}],[85,{"iota_amount":151371443802214618,"pool_token_amount":150301217857128704}],[84,{"iota_amount":151348137636636847,"pool_token_amount":150299372217082560}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":151325321704224328,"pool_token_amount":150298012747241011}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":418194398973115559,"pool_token_amount":415872299316475160}],[73,{"iota_amount":205920313530691210,"pool_token_amount":204864557337488098}],[72,{"iota_amount":30162036770237338,"pool_token_amount":30011760879402318}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[67,{"iota_amount":30136511170752886,"pool_token_amount":30008506235489081}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":30131732371316310,"pool_token_amount":30008220445532962}],[64,{"iota_amount":30122508354655963,"pool_token_amount":30007669233509732}],[61,{"iota_amount":30109178317181310,"pool_token_amount":30006878499594518}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":30100285732944022,"pool_token_amount":30006345783501753}],[58,{"iota_amount":30095840204331590,"pool_token_amount":30006079884222607}],[57,{"iota_amount":30091388777545584,"pool_token_amount":30005807972010196}],[56,{"iota_amount":30086843217197839,"pool_token_amount":30005442682900979}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":30077845551822847,"pool_token_amount":30004908936336770}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":30064174085885139,"pool_token_amount":30004090520926897}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"iota_amount":30045922560270961,"pool_token_amount":30002973925880759}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":30032264350030784,"pool_token_amount":30002165822405313}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[42,{"iota_amount":30023129868417929,"pool_token_amount":30001598541320198}],[41,{"iota_amount":30018358648801955,"pool_token_amount":30001111457703588}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":0,"pool_token_amount":0}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}]],"Anchorage Digital-2":[[167,{"iota_amount":185541314736551107,"pool_token_amount":182261342386316939}],[163,{"iota_amount":78356771142147363,"pool_token_amount":77010096883805943}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":78346277492229607,"pool_token_amount":77009413416231209}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":78342541720780234,"pool_token_amount":77024813858921809}],[158,{"iota_amount":41967546616598638,"pool_token_amount":41272210603053443}],[155,{"iota_amount":41950406218185594,"pool_token_amount":41271199087837047}],[146,{"iota_amount":41898630259021708,"pool_token_amount":41267640635804831}],[145,{"iota_amount":41892907413273460,"pool_token_amount":41267301509697613}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":41881468580414524,"pool_token_amount":41266625384485949}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":41859605112602178,"pool_token_amount":41266265164526663}],[138,{"iota_amount":41853882344943895,"pool_token_amount":41265926664896805}],[137,{"iota_amount":41848155631564404,"pool_token_amount":41265587888249633}],[136,{"iota_amount":41842431472457252,"pool_token_amount":41265249219228351}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":41830991090267079,"pool_token_amount":41264572220407878}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":41813758319199497,"pool_token_amount":41263489993672364}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":41795845707716580,"pool_token_amount":41272361573909075}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[120,{"iota_amount":41761507387857848,"pool_token_amount":41270302285702617}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[115,{"iota_amount":41733266872581162,"pool_token_amount":41268944567901452}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":41721482554731648,"pool_token_amount":41267918132421561}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":41703537255487844,"pool_token_amount":41266115206096109}],[109,{"iota_amount":41697171384383365,"pool_token_amount":41265727958171889}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[103,{"iota_amount":41658281933521508,"pool_token_amount":41263419243124864}],[102,{"iota_amount":41651691245713593,"pool_token_amount":41263029418995973}],[98,{"iota_amount":41625535101707443,"pool_token_amount":41261475274867463}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":41612660771152366,"pool_token_amount":41260671310041890}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":41593545280008979,"pool_token_amount":41259532983353503}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":41586771040094167,"pool_token_amount":41258710188952494}],[91,{"iota_amount":41577945563629037,"pool_token_amount":41255838453720002}],[89,{"iota_amount":41565318531392365,"pool_token_amount":41255045603527479}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":41546420082302621,"pool_token_amount":41253870454006017}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":41531289801904249,"pool_token_amount":41256627563745822}],[81,{"iota_amount":41518825592682724,"pool_token_amount":41255885549089481}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":41499908893301804,"pool_token_amount":41254754771173522}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":41493977799525556,"pool_token_amount":41260494923035693}],[73,{"iota_amount":41475079127096501,"pool_token_amount":41259363483432692}],[72,{"iota_amount":41468410783593773,"pool_token_amount":41258965463775930}],[70,{"iota_amount":41455070320262079,"pool_token_amount":41258168083080432}],[69,{"iota_amount":41448399102459307,"pool_token_amount":41257769711202696}],[67,{"iota_amount":41435065426488955,"pool_token_amount":41256975183168449}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"iota_amount":41420430450792027,"pool_token_amount":41260815718800467}],[63,{"iota_amount":41413884443569930,"pool_token_amount":41260226896182575}],[61,{"iota_amount":40410405673849937,"pool_token_amount":40271920257251776}],[60,{"iota_amount":40404071773175228,"pool_token_amount":40271335434266736}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":40397959745528798,"pool_token_amount":40270969917366796}],[58,{"iota_amount":40391847143688757,"pool_token_amount":40270604314138582}],[57,{"iota_amount":40385733681859852,"pool_token_amount":40270237670279970}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":40342939305879506,"pool_token_amount":40267673163363283}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"iota_amount":40324600351510926,"pool_token_amount":40266573784649205}],[46,{"iota_amount":40318487041911971,"pool_token_amount":40266206763947877}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[40,{"iota_amount":30014044653921477,"pool_token_amount":30000894139882708}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}]],"Ankr":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":27834875247327235,"pool_token_amount":27253033497682335}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":27836880080343632,"pool_token_amount":27283088913768974}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":27832958184081050,"pool_token_amount":27282807317414573}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":27816143848252139,"pool_token_amount":27280577646300312}],[150,{"iota_amount":27811756686295983,"pool_token_amount":27279839827878546}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"iota_amount":27799258180662917,"pool_token_amount":27281849703855080}],[145,{"iota_amount":27795434999842648,"pool_token_amount":27281669830893990}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":27791720839257627,"pool_token_amount":27281596920054668}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":27740483348993766,"pool_token_amount":27263440975355820}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":27736770135156685,"pool_token_amount":27263367987636859}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":27729406225174524,"pool_token_amount":27263285122071558}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":27719418011874332,"pool_token_amount":27264205410898092}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":27700724346843030,"pool_token_amount":27252981680306358}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":27673603141580631,"pool_token_amount":27251352891366267}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":27673880253609058,"pool_token_amount":27262373805472577}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":27658899253699824,"pool_token_amount":27276688633407965}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[102,{"iota_amount":27628348366327421,"pool_token_amount":27275234895506011}],[101,{"iota_amount":27561481532339594,"pool_token_amount":27213342024764992}],[98,{"iota_amount":27548166774698423,"pool_token_amount":27212504720258817}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":27540654495424777,"pool_token_amount":27213220066274005}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":27535971916342781,"pool_token_amount":27212648238627647}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":27527806401533686,"pool_token_amount":27212681985299208}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":27523740821498482,"pool_token_amount":27212601606771544}],[91,{"iota_amount":27494274850780766,"pool_token_amount":27187402284281455}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":27478000667596089,"pool_token_amount":27187085242867303}],[86,{"iota_amount":27473864718774010,"pool_token_amount":27187016297141523}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":27442067093077398,"pool_token_amount":27183522882229672}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":27431395630117394,"pool_token_amount":27176945478949593}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":27410772345158717,"pool_token_amount":27180477410158867}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":29459085552519888,"pool_token_amount":29234601351455807}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":29453846212297206,"pool_token_amount":29233941276367279}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":29415472997908016,"pool_token_amount":29208822588061827}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":29370446211134410,"pool_token_amount":29193636362692127}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":29364840222584189,"pool_token_amount":29192286547298983}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":29362188212849614,"pool_token_amount":29193981633786170}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":29352692988567436,"pool_token_amount":29193205827572392}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"iota_amount":29322845693552819,"pool_token_amount":29189518601526347}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"iota_amount":34229972150543251,"pool_token_amount":34105627318578118}],[39,{"iota_amount":34224816344374222,"pool_token_amount":34105591065961725}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":27214493453369373,"pool_token_amount":27132023725291198}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":27205536146597418,"pool_token_amount":27131890245260586}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":27064716682726903,"pool_token_amount":27023244716152260}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":20018666175233170,"pool_token_amount":20004810987516623}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":20006918736012401,"pool_token_amount":20002343818644342}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":20000000007028393,"pool_token_amount":20000000000140558}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":20000000000550400,"pool_token_amount":20000000000011000}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Artifact":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":137862115188376758,"pool_token_amount":134942434593093588}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":137825567605310661,"pool_token_amount":134941304341510022}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":137807257574032215,"pool_token_amount":134940702905398273}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":137639647395556718,"pool_token_amount":134935366040537214}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":137600958251495320,"pool_token_amount":134933091658482167}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":137507413493465297,"pool_token_amount":134930338997658502}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":137435221409740001,"pool_token_amount":134947934321438351}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":137416665013198772,"pool_token_amount":134947387703979095}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":137379504009657730,"pool_token_amount":134946252825926207}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":137360915116130296,"pool_token_amount":134945690743525593}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":137317750006935155,"pool_token_amount":134938700045816046}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":137299185011390033,"pool_token_amount":134938152744656623}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":137280618944431880,"pool_token_amount":134937605340123618}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":137224865457446643,"pool_token_amount":134935922922175097}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":137206292098193338,"pool_token_amount":134935376455327402}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":137168979606658695,"pool_token_amount":134934140336912606}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":137130750215103629,"pool_token_amount":134931967353104085}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":137056503154335462,"pool_token_amount":134929777159531447}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":137037941301505053,"pool_token_amount":134929227989361407}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":137000882130444594,"pool_token_amount":134928182022431127}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":136926671254663359,"pool_token_amount":134925988009971660}],[114,{"iota_amount":136908119524231652,"pool_token_amount":134925439589627837}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":136871015616318731,"pool_token_amount":134924345398394902}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":136852381954567139,"pool_token_amount":134923717842422098}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":136808082769970247,"pool_token_amount":134937249749042401}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":136787345563496965,"pool_token_amount":134936636139786637}],[106,{"iota_amount":136765950246937607,"pool_token_amount":134936002961078292}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[100,{"iota_amount":136635415376911864,"pool_token_amount":134930142278328766}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":136529688936556445,"pool_token_amount":134926858136946214}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":136385486334008396,"pool_token_amount":134923778058596886}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":136308893885281589,"pool_token_amount":134926972944636903}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":136242330344720848,"pool_token_amount":134920179436748065}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":136147683103649781,"pool_token_amount":134925494178471182}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":136127223847199174,"pool_token_amount":134924877258981885}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":136042033585041869,"pool_token_amount":134921863802792998}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":135997456585594866,"pool_token_amount":134919368391532383}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":135953977689210075,"pool_token_amount":134918155416623725}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":135869517333281209,"pool_token_amount":134915641306189642}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":135761901076415678,"pool_token_amount":134887556663842826}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":135662242669134461,"pool_token_amount":134887621125404356}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":135600106410351783,"pool_token_amount":134885656977453758}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"iota_amount":135398654784451497,"pool_token_amount":134885153738724074}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":105256756576208717,"pool_token_amount":104971505534810890}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":105219464625355488,"pool_token_amount":104968974435030257}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":105149452893004498,"pool_token_amount":104969330822448905}],[27,{"iota_amount":105129879133599505,"pool_token_amount":104968744615556752}],[24,{"iota_amount":80078457195260956,"pool_token_amount":80004203292103525}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80038219627099941,"pool_token_amount":80001036313506367}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Astro-Stakers":[[167,{"iota_amount":35713278970292193,"pool_token_amount":34996053193317523}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":35689423749681498,"pool_token_amount":34993682161632499}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":35680206906493335,"pool_token_amount":34992868768258510}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":35675399916531949,"pool_token_amount":34992449010807307}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":35671975080833742,"pool_token_amount":34997679690444800}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":35652320698112945,"pool_token_amount":34995579486427809}],[151,{"iota_amount":35642620557283760,"pool_token_amount":34994654491113370}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[148,{"iota_amount":35628185488145877,"pool_token_amount":34993426947075393}],[147,{"iota_amount":60577452505114017,"pool_token_amount":26236842628119062}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":35592582142192685,"pool_token_amount":34992997557837346}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":35564198482086036,"pool_token_amount":34999326594715117}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":35516947924316720,"pool_token_amount":34995630254946649}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":35507516617401540,"pool_token_amount":34994884987860295}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":35498088513362556,"pool_token_amount":34994141586952539}],[117,{"iota_amount":35493375375786496,"pool_token_amount":34993769888385284}],[116,{"iota_amount":35488667477271984,"pool_token_amount":34993403132402910}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":35474532566035655,"pool_token_amount":34992292526523222}],[111,{"iota_amount":35471010290962981,"pool_token_amount":34997374727669152}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":90853781868271072,"pool_token_amount":39531943192078969}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":35456003188550117,"pool_token_amount":34996361707123798}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":90592941540681178,"pool_token_amount":39456929245771835}],[101,{"iota_amount":35416877721351908,"pool_token_amount":34992325583302708}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":35396304673824127,"pool_token_amount":34996497599125638}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":35380165758821357,"pool_token_amount":34995252942485528}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":35371510736889665,"pool_token_amount":34996341194194067}],[90,{"iota_amount":35364254744973390,"pool_token_amount":34993970056038254}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":35336084464674732,"pool_token_amount":34990073463073998}],[84,{"iota_amount":35339475110401111,"pool_token_amount":34998197529435746}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":35334243140478538,"pool_token_amount":34997782102725819}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":35323994930424614,"pool_token_amount":34997164786909958}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":35321906905556185,"pool_token_amount":35004836701284836}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":35317442416658004,"pool_token_amount":35005176775559149}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":35312212546762876,"pool_token_amount":35004759357845348}],[76,{"iota_amount":35306991300627034,"pool_token_amount":35004346654768113}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":35296610609115636,"pool_token_amount":35003584483176460}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":35268849953543809,"pool_token_amount":35001306407084036}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":35264100987930229,"pool_token_amount":35001666844050248}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":35165553764197714,"pool_token_amount":35001689027603212}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":35132626204420787,"pool_token_amount":35003112187036668}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":35096772974984347,"pool_token_amount":34997884467147200}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":35082624023242250,"pool_token_amount":35000001506307002}],[32,{"iota_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"iota_amount":35076652400821513,"pool_token_amount":34999451534318999}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":35063056765722483,"pool_token_amount":34997012098735410}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":35049403563688967,"pool_token_amount":34995143489510391}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":25018970896908741,"pool_token_amount":25001568139606424}],[22,{"iota_amount":25012063523938587,"pool_token_amount":25000445971954923}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":25000000031979264,"pool_token_amount":25000000000639572}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":25000000000691200,"pool_token_amount":25000000000013816}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":25000000000572400,"pool_token_amount":25000000000011444}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":25000000000550800,"pool_token_amount":25000000000011015}],[1,{"iota_amount":80000000000000000,"pool_token_amount":80000000000000000}]],"B-Harvest":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":35765158602133587,"pool_token_amount":35051088968862214}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":35751024871142051,"pool_token_amount":35049980709922754}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":35746314182985307,"pool_token_amount":35049611244294572}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":35732286267435756,"pool_token_amount":35048511653839870}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":35722663304652903,"pool_token_amount":35047756500911537}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":35693660996126419,"pool_token_amount":35045360289820211}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":35674353916445634,"pool_token_amount":35043792889878392}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":35659901873578123,"pool_token_amount":35042657034674146}],[143,{"iota_amount":35655087542314004,"pool_token_amount":35042278554275118}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":35644989796184889,"pool_token_amount":35049680686203601}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":35624056671757400,"pool_token_amount":35050532254051576}],[133,{"iota_amount":35619339173630539,"pool_token_amount":35050160929580610}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":35595440804209119,"pool_token_amount":35048280975112915}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":35581127117242251,"pool_token_amount":35047186415298330}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":35543228089945697,"pool_token_amount":35044216934980948}],[116,{"iota_amount":35538114873176832,"pool_token_amount":35043541495178942}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":35528600516191395,"pool_token_amount":35042893073776583}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":35518950774474835,"pool_token_amount":35042111635408411}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":35489146925095486,"pool_token_amount":35031162072947334}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":35483793473825320,"pool_token_amount":35030737588926148}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":35478311672866445,"pool_token_amount":35030313768143641}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[103,{"iota_amount":35461633220746223,"pool_token_amount":35029057169890208}],[102,{"iota_amount":35456198138968843,"pool_token_amount":35028628576063338}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":35417959704071513,"pool_token_amount":35025508708949830}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":35385820100716313,"pool_token_amount":35022752122945458}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":35336371307999881,"pool_token_amount":35017410212679203}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":35335652893883714,"pool_token_amount":35036067175547151}],[74,{"iota_amount":35324968823084977,"pool_token_amount":35035206890575737}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":35308407824094411,"pool_token_amount":35033891784706207}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":35249061890994194,"pool_token_amount":35010299605283561}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":35243712148069340,"pool_token_amount":35009860818271533}],[61,{"iota_amount":35233042996312325,"pool_token_amount":35009012890488731}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":35222111095230316,"pool_token_amount":35007904296682887}],[57,{"iota_amount":35211416948754273,"pool_token_amount":35007031045258756}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":35200727794233377,"pool_token_amount":35006163438280608}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":35190086405486136,"pool_token_amount":35005343344790001}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":35163403385624182,"pool_token_amount":35003211139287678}],[46,{"iota_amount":35152731513682432,"pool_token_amount":35002358471770052}],[45,{"iota_amount":35147397366238596,"pool_token_amount":35001933565404943}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":35136712708223016,"pool_token_amount":35001067702743317}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":35131161700856040,"pool_token_amount":35000427347017464}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":35103821663111259,"pool_token_amount":34998055010017790}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":35062754399343267,"pool_token_amount":34994544079561871}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"iota_amount":35035681401063743,"pool_token_amount":34990912115140125}],[25,{"iota_amount":25031038260567467,"pool_token_amount":25003751495335602}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":25013579004167687,"pool_token_amount":25002019783848360}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":25000000000556200,"pool_token_amount":25000000000011122}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":25000000000000000,"pool_token_amount":25000000000000000}]],"BLRD":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":27583003289648636,"pool_token_amount":27046345869492508}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":27571776452856234,"pool_token_amount":27044890931831286}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":27539204823290162,"pool_token_amount":27042139209187112}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":27535402249425880,"pool_token_amount":27041683369225441}],[151,{"iota_amount":27527953178565894,"pool_token_amount":27040924753865908}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":27513121856075906,"pool_token_amount":27039474715699595}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":27502180492043232,"pool_token_amount":27038397515933725}],[143,{"iota_amount":27498569743462205,"pool_token_amount":27038042529590402}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":27476909914549197,"pool_token_amount":27035927629297368}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":27466069150963047,"pool_token_amount":27034860823619890}],[133,{"iota_amount":27462457774350892,"pool_token_amount":27034507150509510}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":27458849021174011,"pool_token_amount":27034156396238808}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":27448004434973300,"pool_token_amount":27033089481630029}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":27440774126418952,"pool_token_amount":27032377337121289}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":27433650208091656,"pool_token_amount":27031764381956176}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":27422839633208281,"pool_token_amount":27030722221313044}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":27401175660428719,"pool_token_amount":27028586166083839}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":27394055922118103,"pool_token_amount":27027973056580850}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":27390445577332496,"pool_token_amount":27027616846433565}],[112,{"iota_amount":27386835115614161,"pool_token_amount":27027260582491069}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":27350689273576645,"pool_token_amount":27023715499978234}],[100,{"iota_amount":27337809362990484,"pool_token_amount":27022355594034138}],[99,{"iota_amount":27333684099060599,"pool_token_amount":27021947825660448}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":27308667691480606,"pool_token_amount":27019430261698433}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":27300449023153587,"pool_token_amount":27018530675809497}],[90,{"iota_amount":27295366239961235,"pool_token_amount":27017103983430315}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":27287283277054265,"pool_token_amount":27016303873068721}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":27238716888187057,"pool_token_amount":27011309697355408}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":27226602067867611,"pool_token_amount":27010108169249211}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":27218153385511551,"pool_token_amount":27009268174831969}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":27213923456861450,"pool_token_amount":27008843962738348}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":27209587165283514,"pool_token_amount":27008413601320411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":27188235632961521,"pool_token_amount":27006280772034083}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":27184840919599247,"pool_token_amount":27006485709693223}],[61,{"iota_amount":27176839055778768,"pool_token_amount":27005690720535486}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":27160828791718552,"pool_token_amount":27004094115962377}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":27139999171817926,"pool_token_amount":27001584901815219}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":27102806673307910,"pool_token_amount":26997717279493295}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":27086314290010801,"pool_token_amount":26996035941887027}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":27077969626228151,"pool_token_amount":26995203302102022}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":27073726593772775,"pool_token_amount":26994780296248228}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":27042390894325100,"pool_token_amount":26992174712191332}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":27037707419149628,"pool_token_amount":26991706670632558}],[25,{"iota_amount":20023263034545418,"pool_token_amount":20000578545609992}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":20009421066195300,"pool_token_amount":20000261536395933}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":20000000000475400,"pool_token_amount":20000000000009502}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":20000000000445300,"pool_token_amount":20000000000008902}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":20000000000428400,"pool_token_amount":20000000000008567}]],"BartestneT":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":117507085722508773,"pool_token_amount":115091407327147149}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":117475013827648459,"pool_token_amount":115088906132189620}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":117411875248929974,"pool_token_amount":115085809474497376}],[157,{"iota_amount":117395836788729088,"pool_token_amount":115085023438118622}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":117303741557402156,"pool_token_amount":115054483933747444}],[152,{"iota_amount":117287701202352552,"pool_token_amount":115053697293946917}],[149,{"iota_amount":117239582969471468,"pool_token_amount":115051337934664603}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":117175180392260465,"pool_token_amount":115047336398830934}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":117064214969497686,"pool_token_amount":115041886776230445}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":117000764050850904,"pool_token_amount":115038770327267194}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":116921549891928770,"pool_token_amount":115034879725424279}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":116824247801047043,"pool_token_amount":115027605967221918}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":116776893558444729,"pool_token_amount":115025584614418039}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":116758177050419063,"pool_token_amount":115022134246869657}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":116742022067112446,"pool_token_amount":115021206371674357}],[117,{"iota_amount":116726177903400886,"pool_token_amount":115020581946689906}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":116645056291773765,"pool_token_amount":115015587498683988}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":116613358624109126,"pool_token_amount":115014337221559288}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":116560412420590850,"pool_token_amount":115012261424624900}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":116542220680300949,"pool_token_amount":115011543416467491}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[98,{"iota_amount":116396392046862043,"pool_token_amount":115004412054516890}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":116306470954550318,"pool_token_amount":114999891472960489}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":116288741499872194,"pool_token_amount":114999015899317966}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":116147935557915967,"pool_token_amount":114992041621923716}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":116130350595358052,"pool_token_amount":114991171123931149}],[82,{"iota_amount":116112876179452772,"pool_token_amount":114990305973828623}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":115936047996076687,"pool_token_amount":114981520336283687}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":115862034125527143,"pool_token_amount":114977867308741314}],[67,{"iota_amount":115843475418718681,"pool_token_amount":114976946454660674}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":115806360915702993,"pool_token_amount":114975107302040885}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":115754082478085879,"pool_token_amount":114972574530759978}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":115596435605821169,"pool_token_amount":114964506707440225}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":115526304170483845,"pool_token_amount":114961191740252668}],[48,{"iota_amount":115508641603284596,"pool_token_amount":114960339981216908}],[46,{"iota_amount":115473299964996026,"pool_token_amount":114958615389218842}],[45,{"iota_amount":115455618601595035,"pool_token_amount":114957741502911352}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"iota_amount":115366668151935908,"pool_token_amount":114953899061725000}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":105239137148993302,"pool_token_amount":104975934211119013}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":105185795307633888,"pool_token_amount":104973992787873847}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":105129202218291575,"pool_token_amount":104971108666619143}],[25,{"iota_amount":80096058906784554,"pool_token_amount":80006712332966508}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":80059248507012938,"pool_token_amount":80004520970081798}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"iota_amount":80000000049908508,"pool_token_amount":80000000000998159}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":80000000001754400,"pool_token_amount":80000000000035087}]],"BiXinKelePool":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[162,{"iota_amount":42340374111669720,"pool_token_amount":41521842502667070}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":42305707837400262,"pool_token_amount":41518612295669502}],[155,{"iota_amount":42304003382673775,"pool_token_amount":41522132128613802}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":42280426851748501,"pool_token_amount":41519764387052654}],[150,{"iota_amount":42274612722396020,"pool_token_amount":41519250529116154}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":42234957940338748,"pool_token_amount":41521186438267286}],[140,{"iota_amount":42223522699839723,"pool_token_amount":41520174596343228}],[136,{"iota_amount":42203289942160419,"pool_token_amount":41520764568436564}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":42197569916120985,"pool_token_amount":41520258091146304}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":42191045559970246,"pool_token_amount":41518960427124654}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":42177486074264492,"pool_token_amount":41520990088095296}],[130,{"iota_amount":42171763006099532,"pool_token_amount":41520483028633484}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":42166047666719313,"pool_token_amount":41519986566243959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":42154607810705995,"pool_token_amount":41518979979300318}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[122,{"iota_amount":42131124827568450,"pool_token_amount":41521482619108673}],[120,{"iota_amount":42119689255529894,"pool_token_amount":41520468246856456}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":42096823538790465,"pool_token_amount":41518439232144521}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":42085238325951417,"pool_token_amount":41522405011420462}],[109,{"iota_amount":42061676694083832,"pool_token_amount":41520263961219080}],[107,{"iota_amount":42048933867825307,"pool_token_amount":41519102142636544}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[98,{"iota_amount":41994260756087382,"pool_token_amount":41518271188003300}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":41982574827184676,"pool_token_amount":41523981199863461}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[89,{"iota_amount":41944015098773049,"pool_token_amount":41520163358102447}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":41931222961006951,"pool_token_amount":41518895201483001}],[84,{"iota_amount":41924375100018228,"pool_token_amount":41529134652761944}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[78,{"iota_amount":41889611556739718,"pool_token_amount":41528725811902398}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[72,{"iota_amount":41859620862269647,"pool_token_amount":41533407886346002}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":41861352402193453,"pool_token_amount":41553100417333572}],[67,{"iota_amount":41847795170597414,"pool_token_amount":41551755213603120}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[58,{"iota_amount":41799397625107841,"pool_token_amount":41555445764505896}],[55,{"iota_amount":41780392083448999,"pool_token_amount":41553556044641193}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":41774056975706019,"pool_token_amount":41552925973347520}],[53,{"iota_amount":41767721958070670,"pool_token_amount":41552296722117405}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":41749487978781002,"pool_token_amount":41551173180254168}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":41743153143039671,"pool_token_amount":41550542705794559}],[48,{"iota_amount":41739873632174967,"pool_token_amount":41553053934397006}],[46,{"iota_amount":41727204346745637,"pool_token_amount":41551792590227341}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":41711225748197813,"pool_token_amount":41552913348429428}],[41,{"iota_amount":41698331530818861,"pool_token_amount":41551627834534411}],[39,{"iota_amount":35102460727004260,"pool_token_amount":34988799332079983}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":35100462800728419,"pool_token_amount":34991696064706283}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":35089423977843002,"pool_token_amount":34990593730539865}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":35077765096156622,"pool_token_amount":34989441820683982}],[31,{"iota_amount":35063105920818553,"pool_token_amount":34990697774499023}],[28,{"iota_amount":35044302510401945,"pool_token_amount":34988126658221397}],[26,{"iota_amount":35033708955650315,"pool_token_amount":34989740538840425}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":25000000019836964,"pool_token_amount":25000000000396727}],[17,{"iota_amount":25000000015495364,"pool_token_amount":25000000000309897}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":25000000000691200,"pool_token_amount":25000000000013816}],[10,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"BlockEden.xyz":[[167,{"iota_amount":36726098257932527,"pool_token_amount":35997418274243052}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":36721286185188055,"pool_token_amount":35996946614186807}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":36697234918922741,"pool_token_amount":35994588371741247}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":36713402325485080,"pool_token_amount":36023376782171812}],[156,{"iota_amount":36702360957029306,"pool_token_amount":36021305914171443}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":36676922608875615,"pool_token_amount":36018210190155582}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"iota_amount":36657255465077044,"pool_token_amount":36016265183919536}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":36632172107223620,"pool_token_amount":36013800098993296}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":36612104728883417,"pool_token_amount":36011826869126917}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":36607081295999820,"pool_token_amount":36011332761382451}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":36597054705955635,"pool_token_amount":36010357134450204}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":36592036849614676,"pool_token_amount":36009863392588193}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":36587018234622476,"pool_token_amount":36009369515120462}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":36581233027348593,"pool_token_amount":36008121612258155}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":36561152810147210,"pool_token_amount":36006150041836188}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":36551141797998123,"pool_token_amount":36005186536428898}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":36546130464944381,"pool_token_amount":36004697322492802}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":36541109542557706,"pool_token_amount":36004199121686470}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":36536092983028107,"pool_token_amount":36003704836294058}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":36516050366878178,"pool_token_amount":36001748159881534}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":36459939708194725,"pool_token_amount":35996363436761505}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":36443052484019378,"pool_token_amount":35994698630983787}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":36431428578332547,"pool_token_amount":35993549117064649}],[98,{"iota_amount":36402697647983429,"pool_token_amount":35990707075389107}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":36391459319647805,"pool_token_amount":35989600370496064}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":36380346038435370,"pool_token_amount":35988483433167089}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":36347640026133045,"pool_token_amount":35985695229610714}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":36342158426369897,"pool_token_amount":35985165909873277}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":36330671112396717,"pool_token_amount":35983561423219369}],[84,{"iota_amount":36325217444472978,"pool_token_amount":35983021266895089}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":36293320362502507,"pool_token_amount":35995357160305232}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":36275662178674804,"pool_token_amount":35998083238230451}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":36269879697370177,"pool_token_amount":35997508521688108}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":36252533389231561,"pool_token_amount":35995780415671904}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":36213816627490468,"pool_token_amount":35987427687414356}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":36202424436802869,"pool_token_amount":35985848262726344}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":36185515332308174,"pool_token_amount":35983954324672914}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":36179958036887836,"pool_token_amount":35983401690656406}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":36143197509138010,"pool_token_amount":35995591339694884}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":36102290654584148,"pool_token_amount":35989917813028023}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":36084842483334300,"pool_token_amount":35988011249911319}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":36059269811637942,"pool_token_amount":35984667775929741}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":25039782258486216,"pool_token_amount":25003759785108899}],[26,{"iota_amount":25034801958386532,"pool_token_amount":25003283169811624}],[24,{"iota_amount":25024242607987629,"pool_token_amount":25002433641925894}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":25018192297371582,"pool_token_amount":25001793172110713}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"iota_amount":25000000015495364,"pool_token_amount":25000000000309897}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":25000000000556200,"pool_token_amount":25000000000011122}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":25000000000000000,"pool_token_amount":25000000000000000}]],"BlockVision":[[167,{"iota_amount":46607803587975292,"pool_token_amount":45673670729982689}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":46587396047413958,"pool_token_amount":45681080005439287}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":46575958210517682,"pool_token_amount":45680827649645088}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":46556716590362088,"pool_token_amount":45678944730435931}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":46543795515237337,"pool_token_amount":45677596449974285}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":46516950926451233,"pool_token_amount":45673918429053368}],[151,{"iota_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"iota_amount":46497902341046995,"pool_token_amount":45672046977649258}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":46491582640218351,"pool_token_amount":45671426231548280}],[145,{"iota_amount":46646654185460203,"pool_token_amount":45834972334352696}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":46640329074678463,"pool_token_amount":45834349944425657}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":46627693386122617,"pool_token_amount":45833109030994389}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":46621374180460882,"pool_token_amount":45832487878537731}],[140,{"iota_amount":46614715436211159,"pool_token_amount":45831533333613963}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":46481622812681162,"pool_token_amount":45817980000005562}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":46471804078584205,"pool_token_amount":45813907119182523}],[116,{"iota_amount":46472809981708079,"pool_token_amount":45826113253484207}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":46459548968193817,"pool_token_amount":45824250247006539}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":46452697871413456,"pool_token_amount":45823101370510538}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":46419838821696086,"pool_token_amount":45819989676226466}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[103,{"iota_amount":46385419628666925,"pool_token_amount":45818383855626061}],[97,{"iota_amount":46341361368391645,"pool_token_amount":45813407275029996}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":46334129448159712,"pool_token_amount":45812517951052328}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":46305863311208504,"pool_token_amount":45809721695500571}],[91,{"iota_amount":46298763472603576,"pool_token_amount":45809017825187549}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":46284515186775850,"pool_token_amount":45807525827293200}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":46250371461504245,"pool_token_amount":45786326226986529}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":46201001280409080,"pool_token_amount":45781868371492020}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":46144959833852695,"pool_token_amount":45777920426803856}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":46130192463121860,"pool_token_amount":45776662579561301}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":46115298145833641,"pool_token_amount":45775480997819888}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":36219131146128700,"pool_token_amount":35962994828045792}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":36196943377438282,"pool_token_amount":35961166565416945}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":36180387750367603,"pool_token_amount":35959651642335581}],[58,{"iota_amount":36172938977818605,"pool_token_amount":35957227858910484}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":36142397107783807,"pool_token_amount":35952079429877998}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":36131580903692518,"pool_token_amount":35951288294753847}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":36126145451701718,"pool_token_amount":35950864800649017}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":36115241466243832,"pool_token_amount":35949985681950708}],[47,{"iota_amount":36109721026399380,"pool_token_amount":35949477395268828}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":36042050348150236,"pool_token_amount":35943723615283869}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":36027560045494744,"pool_token_amount":35940491951540558}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":35996494613928347,"pool_token_amount":35932265282671106}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":25928292013911136,"pool_token_amount":25905581543356260}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":25000000019836964,"pool_token_amount":25000000000396727}],[16,{"iota_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":25000000000000000,"pool_token_amount":25000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Blockdaemon":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":117288640199503743,"pool_token_amount":115022542115133813}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":117273101265919288,"pool_token_amount":115021323017898189}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":117257564618341846,"pool_token_amount":115020103951444885}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":117210972618313961,"pool_token_amount":115016447268860550}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":71436868631769519,"pool_token_amount":70116922309784292}],[156,{"iota_amount":71438425477812847,"pool_token_amount":70136012438258919}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":71406330842745910,"pool_token_amount":70130853090019222}],[152,{"iota_amount":71393994847305286,"pool_token_amount":70127524146213132}],[151,{"iota_amount":71379386092053931,"pool_token_amount":70121961953584903}],[149,{"iota_amount":71356721085359079,"pool_token_amount":70117272979164092}],[148,{"iota_amount":71346856513304848,"pool_token_amount":70116370957793311}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":71221418224848324,"pool_token_amount":70104227164658824}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":71685072742026922,"pool_token_amount":70594346710692852}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":71675348560626864,"pool_token_amount":70593210628961066}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":69597840175880794,"pool_token_amount":68596183444039653}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":69588514937115838,"pool_token_amount":68595172377006267}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":69579082024997025,"pool_token_amount":68594056585145341}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":69225009616437019,"pool_token_amount":68361166530743031}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":69181666712656893,"pool_token_amount":68356005054540980}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":69159109292616167,"pool_token_amount":68352681647512675}],[101,{"iota_amount":69148293088747823,"pool_token_amount":68351399708348462}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":69072734091495939,"pool_token_amount":68341904524458573}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":69044119588316808,"pool_token_amount":68322834712712927}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":69012691006141175,"pool_token_amount":68319105679448956}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":67532470414976835,"pool_token_amount":66862665199964625}],[88,{"iota_amount":67522262075036777,"pool_token_amount":66861454964004613}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":67501354821424457,"pool_token_amount":66858539235338928}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":67387504858777390,"pool_token_amount":66772367104012764}],[82,{"iota_amount":67377373375645190,"pool_token_amount":66771159808143360}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":67368611543917786,"pool_token_amount":66771309002581518}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":67337767714563755,"pool_token_amount":66767617742143326}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":67180452235726896,"pool_token_amount":66638112742897960}],[74,{"iota_amount":66836887504620136,"pool_token_amount":66306150679380405}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":66805110323109360,"pool_token_amount":66302278113091469}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":66794425819739484,"pool_token_amount":66300996016645965}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":66762152386889836,"pool_token_amount":66296922032996619}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":66183279429175683,"pool_token_amount":65749398369969696}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":66173021786197030,"pool_token_amount":65747952593502821}],[61,{"iota_amount":65952419128535825,"pool_token_amount":65546231424387952}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":56030308367314341,"pool_token_amount":55722510418909828}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":55936306726847350,"pool_token_amount":55710916425978336}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":55927762658267547,"pool_token_amount":55709906674913006}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":55709994950093679,"pool_token_amount":55508087495401772}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":35568778891434308,"pool_token_amount":35518021214312457}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":28458499105190570,"pool_token_amount":28439798063978626}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":20000000000475400,"pool_token_amount":20000000000009502}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":20000000000000000,"pool_token_amount":20000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Blockscope.net":[[167,{"iota_amount":153534198820848694,"pool_token_amount":150274929096901219}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":153518389867009701,"pool_token_amount":150297702297512327}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":153477691897123987,"pool_token_amount":150296109384786094}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":153416655773220935,"pool_token_amount":150293515132567143}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":153426153454153680,"pool_token_amount":150322434056859873}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":153374653949713384,"pool_token_amount":150291586978391208}],[156,{"iota_amount":153333010431509130,"pool_token_amount":150290006041737339}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":153270116568171834,"pool_token_amount":150287407482011017}],[149,{"iota_amount":153185831947258645,"pool_token_amount":150283652880840739}],[148,{"iota_amount":153165664818645081,"pool_token_amount":150283412805022073}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":152978867311361093,"pool_token_amount":150275518009600716}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":152674558008304557,"pool_token_amount":150269033564837113}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":152661552665646693,"pool_token_amount":150275766441977749}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":152599626679559908,"pool_token_amount":150273403651902143}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":152517778996650403,"pool_token_amount":150270936585865692}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":152440611895372564,"pool_token_amount":150253530114421457}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":152326021706340826,"pool_token_amount":150264555288680330}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":152301705707579374,"pool_token_amount":150263108958091891}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"iota_amount":152185142162393659,"pool_token_amount":150261211757025566}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":152066226996732910,"pool_token_amount":150255390759042180}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":152041274043986389,"pool_token_amount":150252958056325315}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":151867187410039168,"pool_token_amount":150256555324569125}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":151821346498510800,"pool_token_amount":150254765741644168}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":151752796156411992,"pool_token_amount":150252061290152323}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":151702169947041477,"pool_token_amount":150246154909996301}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":151656561327572090,"pool_token_amount":150244345480937263}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[75,{"iota_amount":151588172979086253,"pool_token_amount":150241610312275054}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":151500919855600098,"pool_token_amount":150313839951090541}],[67,{"iota_amount":151476693519767621,"pool_token_amount":150312878490635771}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":211569526460800051,"pool_token_amount":210081373524611121}],[62,{"iota_amount":211537677154121410,"pool_token_amount":210080046557786807}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":211168233926581951,"pool_token_amount":209987221128348745}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":210861246511467226,"pool_token_amount":209989206122422742}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":150750193360006689,"pool_token_amount":150215953913045113}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":150701000334755610,"pool_token_amount":150211950366773571}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":170717347131493151,"pool_token_amount":170193186545118769}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":170577906774042100,"pool_token_amount":170193754895966477}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":170547990711068127,"pool_token_amount":170191985905942429}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":200512622418438545,"pool_token_amount":200167865729086964}],[27,{"iota_amount":200278530506479079,"pool_token_amount":199970361652571880}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":150109326426139993,"pool_token_amount":150005218149539212}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":150000000119670491,"pool_token_amount":150000000002393397}],[16,{"iota_amount":150000000053253526,"pool_token_amount":150000000001065061}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":150000000004141300,"pool_token_amount":150000000000082818}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":150000000004043500,"pool_token_amount":150000000000080863}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":150000000003424100,"pool_token_amount":150000000000068478}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":150000000003391500,"pool_token_amount":150000000000067827}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":150000000000000000,"pool_token_amount":150000000000000000}]],"Brightlystake":[[167,{"iota_amount":36769230841564408,"pool_token_amount":36024115216251123}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":36764417768819936,"pool_token_amount":36023737071503661}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":36759606726530334,"pool_token_amount":36023359941883640}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":36754794669380732,"pool_token_amount":36022982687259198}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":36745172404617873,"pool_token_amount":36022228186774669}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":36710403799881928,"pool_token_amount":36019508534723032}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"iota_amount":36675407772585449,"pool_token_amount":36016481019170804}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":36645429186369394,"pool_token_amount":36014143198263539}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":36635398273518208,"pool_token_amount":36013354498697102}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":36625362822615350,"pool_token_amount":36012566161194036}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":36620339389731753,"pool_token_amount":36012171009825574}],[136,{"iota_amount":36615318197448704,"pool_token_amount":36011775984938839}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":36610300630679112,"pool_token_amount":36011381195588743}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":36605282774338153,"pool_token_amount":36010986333672924}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":36580181618111295,"pool_token_amount":36009010341673221}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":36565956601321017,"pool_token_amount":36008645705975036}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":36555918344644827,"pool_token_amount":36007850303815779}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":36536274173648860,"pool_token_amount":36015773660083363}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":36516195572413630,"pool_token_amount":36014169416832669}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":36511181204824278,"pool_token_amount":36013773782051044}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":36479564153868692,"pool_token_amount":36011315430693987}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":36468136936306594,"pool_token_amount":36010412914407764}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":36462333289713413,"pool_token_amount":36009954445906952}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"iota_amount":36444980643223536,"pool_token_amount":36008585988784421}],[100,{"iota_amount":36439244672666878,"pool_token_amount":36008132603310864}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":36395420422834749,"pool_token_amount":36010733690785295}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":36384411269771772,"pool_token_amount":36009863118726027}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":36367938257677045,"pool_token_amount":36008573843613143}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":36362361009068500,"pool_token_amount":36008134829582751}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":36338122943693593,"pool_token_amount":36004309660594371}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":36288172337124500,"pool_token_amount":36000322585914038}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":36282392950205188,"pool_token_amount":35999863902474222}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":36264918787122773,"pool_token_amount":35998457478433048}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":36246932690953432,"pool_token_amount":35996740004231445}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":36235819023465515,"pool_token_amount":35995856985470463}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":36208462896607788,"pool_token_amount":35993668126902994}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"iota_amount":36142783148242106,"pool_token_amount":35988445472046849}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":36074726519212041,"pool_token_amount":35982918324858086}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":25020913919159091,"pool_token_amount":25004513096698381}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":25000000032208364,"pool_token_amount":25000000000644154}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":25000000000691200,"pool_token_amount":25000000000013816}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":25000000000572400,"pool_token_amount":25000000000011444}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":25000000000000000,"pool_token_amount":25000000000000000}]],"Bware Labs":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":146784382780059539,"pool_token_amount":143759286021164538}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":146764938664203343,"pool_token_amount":143758524285208267}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":146706117942754360,"pool_token_amount":143756031291441145}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":146686168570314931,"pool_token_amount":143755247472704417}],[156,{"iota_amount":146647146649979252,"pool_token_amount":143754538305239924}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":146587071106841353,"pool_token_amount":143752155126356036}],[151,{"iota_amount":146545851227910896,"pool_token_amount":143749295073691403}],[150,{"iota_amount":146526517315144242,"pool_token_amount":143749115307613462}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[146,{"iota_amount":146444848995064398,"pool_token_amount":143743891779732159}],[145,{"iota_amount":146425070494820295,"pool_token_amount":143743112403576442}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":146353273485848634,"pool_token_amount":143765769355950655}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":146254697680320373,"pool_token_amount":143762190302938380}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":146206761099925675,"pool_token_amount":143790904798750682}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":146186871572949801,"pool_token_amount":143790018695295506}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":146146416762428695,"pool_token_amount":143787602641459143}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":146106705434014864,"pool_token_amount":143785880948635209}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":146047342527348873,"pool_token_amount":143783480688359384}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":145967928678127705,"pool_token_amount":143780009903919325}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":145924456041829437,"pool_token_amount":143774552790549447}],[116,{"iota_amount":145906203187342510,"pool_token_amount":143775253722463489}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":145865148496314038,"pool_token_amount":143772174670342845}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":145787145441725356,"pool_token_amount":143770076154815515}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":145740894336536112,"pool_token_amount":143766053938314785}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":145696126777616354,"pool_token_amount":143764359171946584}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":145697279566892731,"pool_token_amount":143787225507500204}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":145718666495755034,"pool_token_amount":143831399663630885}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":145671741662335297,"pool_token_amount":143828506414599409}],[98,{"iota_amount":145514818199475423,"pool_token_amount":143759472917433129}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":145469975926808931,"pool_token_amount":143757717053750866}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":145382105024153378,"pool_token_amount":143755617010282070}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":145250460175141421,"pool_token_amount":143750824036867680}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":145085100268633625,"pool_token_amount":143649511101442250}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":144802454097370050,"pool_token_amount":143689353175008581}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":144687462939137379,"pool_token_amount":143683016747743577}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":144511209022757107,"pool_token_amount":143674438204976024}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":144422721809338544,"pool_token_amount":143670481345745795}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"iota_amount":135516576825767879,"pool_token_amount":134909425586675485}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":135476225346396078,"pool_token_amount":134908763697212518}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":135434304858339750,"pool_token_amount":134906755229450777}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":135308191752127750,"pool_token_amount":134902535824410380}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":105230953709859342,"pool_token_amount":104983615062711155}],[32,{"iota_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"iota_amount":105211077441032321,"pool_token_amount":104980926686452397}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":105172345603542116,"pool_token_amount":104976897133465962}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":105153804011626162,"pool_token_amount":104975940299204622}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028266523,"pool_token_amount":80000000000565321}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002203900,"pool_token_amount":80000000000044070}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840600,"pool_token_amount":80000000000036807}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":80000000000000000,"pool_token_amount":80000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Chainbase":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":117577822382942294,"pool_token_amount":115226068340249335}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":117544855034706312,"pool_token_amount":115223937754596019}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":117459107566486304,"pool_token_amount":115215347475905944}],[150,{"iota_amount":117423891982332319,"pool_token_amount":115211011698008326}],[148,{"iota_amount":117391731757489749,"pool_token_amount":115209580610274669}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":117342824433894908,"pool_token_amount":115236374524967167}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":117310881343169523,"pool_token_amount":115234883915398782}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":117214052907431250,"pool_token_amount":115229505488921206}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":117198196482596536,"pool_token_amount":115228881969987401}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":117149243005998327,"pool_token_amount":115225662137422628}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":117061034374164802,"pool_token_amount":115213798874800937}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":117045138758838941,"pool_token_amount":115213131509669069}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":117013757124979704,"pool_token_amount":115212202186977274}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":116982279845293100,"pool_token_amount":115211179953859403}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":116966030389834725,"pool_token_amount":115210158964692172}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":116907456658505668,"pool_token_amount":115197414965439345}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":116875377900396173,"pool_token_amount":115195780994705596}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":116692511695754711,"pool_token_amount":115090511890835526}],[109,{"iota_amount":116674855668016892,"pool_token_amount":115089779365586764}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":116657198408643355,"pool_token_amount":115089042919273080}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":116566136119862675,"pool_token_amount":115085427198329762}],[102,{"iota_amount":116547862632465168,"pool_token_amount":115084706491435934}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":116376621550063788,"pool_token_amount":115018127070662600}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":116340625990072925,"pool_token_amount":115016349109141558}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":116303893136287961,"pool_token_amount":115013442843911597}],[91,{"iota_amount":116286204072287563,"pool_token_amount":115012568206039313}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":116180507604635458,"pool_token_amount":115007280555852187}],[84,{"iota_amount":116163042644200082,"pool_token_amount":115006424625624592}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":116110503770040669,"pool_token_amount":115003817090518355}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":116056837126488637,"pool_token_amount":115000597105914237}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":116004431765947569,"pool_token_amount":114997953427540998}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":115950475001135540,"pool_token_amount":114995229622604707}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":115932024419831869,"pool_token_amount":114994313751514638}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":115913464152626096,"pool_token_amount":114993295243469961}],[69,{"iota_amount":115895107365548365,"pool_token_amount":114992583991658673}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":115860821067273796,"pool_token_amount":114993552138983230}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":115684253912996973,"pool_token_amount":114984917099424926}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":115666797473555976,"pool_token_amount":114984043841091909}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":115614147269467571,"pool_token_amount":114981563931883341}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":115471519716460137,"pool_token_amount":114972857605971538}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":115419816768374564,"pool_token_amount":114971627340963700}],[41,{"iota_amount":115401854213710844,"pool_token_amount":114970669173663083}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"iota_amount":115383958672855189,"pool_token_amount":114969776988466112}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":115330537047612262,"pool_token_amount":114967815907867608}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":115312622363614037,"pool_token_amount":114967405109250343}],[35,{"iota_amount":115292173111324517,"pool_token_amount":114965124004445852}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":105217937553705507,"pool_token_amount":104987313012455525}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":80000000001754400,"pool_token_amount":80000000000035087}]],"Chainflow":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":35409788647552165,"pool_token_amount":34673011613600693}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":35395936634215096,"pool_token_amount":34672315662306405}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":35388263913714077,"pool_token_amount":34673376279431562}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":35378940904241390,"pool_token_amount":34672919516414422}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":35368744997799002,"pool_token_amount":34671699776931458}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":43412076220755621,"pool_token_amount":42579672315151533}],[152,{"iota_amount":43406100319523589,"pool_token_amount":42579322391400740}],[151,{"iota_amount":43400186715335746,"pool_token_amount":42579033289082820}],[148,{"iota_amount":43382543651669465,"pool_token_amount":42578168663061769}],[145,{"iota_amount":43364886136720430,"pool_token_amount":42577303939225812}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":43333752707910066,"pool_token_amount":42574338730776608}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":43309863097317438,"pool_token_amount":42572983955145918}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":43303943380169856,"pool_token_amount":42572693949449936}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":43293097775844878,"pool_token_amount":42573092602169277}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":43269577314513662,"pool_token_amount":42572101231051023}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":43257741837589259,"pool_token_amount":42571532228220360}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":43239982313022100,"pool_token_amount":42570658223200416}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":43228142115069700,"pool_token_amount":42570075338351811}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":43180025902030943,"pool_token_amount":42566977226428050}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":43159963813921007,"pool_token_amount":42563824089264340}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":43134952747046881,"pool_token_amount":42563088615388870}],[106,{"iota_amount":43128201369080241,"pool_token_amount":42562754598675600}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":43100783194272242,"pool_token_amount":42561391032396688}],[99,{"iota_amount":44740551632511322,"pool_token_amount":44200657505248202}],[97,{"iota_amount":44726635591660039,"pool_token_amount":44199971928492274}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":44706239015526958,"pool_token_amount":44198960213459099}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":44685591166087603,"pool_token_amount":44197941275889369}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":44637957349794845,"pool_token_amount":44195770637430755}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":44617630043701898,"pool_token_amount":44194801846126824}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":44610732389955072,"pool_token_amount":44194463072798678}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":44590342039058168,"pool_token_amount":44193419079496894}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":44576782888616309,"pool_token_amount":44192746166622396}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":44570002681448199,"pool_token_amount":44192410076888575}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":44513207083212184,"pool_token_amount":44189488930042610}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":44458144124992273,"pool_token_amount":44186288477748362}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":44424106426037401,"pool_token_amount":44184256236123410}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":44410788056858013,"pool_token_amount":44183611980397196}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"iota_amount":40010415586695381,"pool_token_amount":39834128764147422}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":27084280535194315,"pool_token_amount":27000364782145286}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":27070717142854052,"pool_token_amount":26999388254791990}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":27062066739373944,"pool_token_amount":26999405856747586}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":27050035290237434,"pool_token_amount":27000470516898304}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"iota_amount":20027663030388938,"pool_token_amount":20005529696874868}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":20004800435991001,"pool_token_amount":20000226003028721}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":20000000000539900,"pool_token_amount":20000000000010790}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":20000000000527000,"pool_token_amount":20000000000010533}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":20000000000000000,"pool_token_amount":20000000000000000}]],"Chainode Tech":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":142958035385106038,"pool_token_amount":139960901742283840}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":142900940354411529,"pool_token_amount":139958765634925152}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":142776332324246486,"pool_token_amount":139947569325771903}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":142756531718752408,"pool_token_amount":139946652467509390}],[148,{"iota_amount":142659258755585636,"pool_token_amount":139943666885501185}],[147,{"iota_amount":142639897403471752,"pool_token_amount":139943096149437272}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":142543621961513572,"pool_token_amount":139940304264233264}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":142524866975188698,"pool_token_amount":139940231472076509}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":142447638127662904,"pool_token_amount":139937824111633396}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":142409342823310620,"pool_token_amount":139936937072287062}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":142390094445653040,"pool_token_amount":139936388891757733}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":142333313518421920,"pool_token_amount":139935706810780868}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":142294647485064908,"pool_token_amount":139934471709798009}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":142253265479821093,"pool_token_amount":139930563675223707}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":142234103876536491,"pool_token_amount":139930002081251411}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":142157146190932413,"pool_token_amount":139927443447016322}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":142122225774389379,"pool_token_amount":139929753960386043}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":142039636848081710,"pool_token_amount":139921995730532827}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":141961470077079073,"pool_token_amount":139918588270775806}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"iota_amount":141725591144519983,"pool_token_amount":139911931667913698}],[98,{"iota_amount":141659781200826143,"pool_token_amount":139910177393089223}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":141572281997656820,"pool_token_amount":139907506248129317}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":141550533326995686,"pool_token_amount":139906796295232163}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":141529065008682580,"pool_token_amount":139906257390617125}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":141441806508072543,"pool_token_amount":139902336935083060}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":141398887538260729,"pool_token_amount":139900991027795231}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":141332708183995362,"pool_token_amount":139896880653662348}],[82,{"iota_amount":141312250805055909,"pool_token_amount":139897042681580293}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":141176799641644045,"pool_token_amount":139865723492036040}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":140885262917779334,"pool_token_amount":139872653832979904}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":140793406845571034,"pool_token_amount":139863227514301200}],[58,{"iota_amount":140766159196467334,"pool_token_amount":139856614423578010}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":140701795135978688,"pool_token_amount":139854148826320750}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":140678919157644108,"pool_token_amount":139852092329946144}],[53,{"iota_amount":140656665481057209,"pool_token_amount":139850657079900409}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":140635832113545037,"pool_token_amount":139850633305241600}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":140459767909395486,"pool_token_amount":139820374964068107}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":140373814637831858,"pool_token_amount":139818090649868563}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"iota_amount":290870382900803457,"pool_token_amount":289809012108653824}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":290779039016417747,"pool_token_amount":289805458116930935}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":290587797719274670,"pool_token_amount":289797793882258966}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":290384384402756652,"pool_token_amount":289786004763378889}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":170146493011515008,"pool_token_amount":169988655968295230}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":151135775838466498,"pool_token_amount":151100721529907548}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":150699994193211591,"pool_token_amount":150699994002980605}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":150000000004141300,"pool_token_amount":150000000000082818}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Chorus One":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":54080953251060883,"pool_token_amount":53009458894272051}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":54059101244255698,"pool_token_amount":53007670522545240}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":54051509069056695,"pool_token_amount":53006772864187313}],[151,{"iota_amount":54036687286531284,"pool_token_amount":53005332678897891}],[149,{"iota_amount":54021845426146677,"pool_token_amount":53003872314838807}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":53978613813285079,"pool_token_amount":53019568958822113}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":53944678313504663,"pool_token_amount":53018629802196732}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":53918322510470106,"pool_token_amount":53018653363708625}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":53911195408835416,"pool_token_amount":53018131726872331}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":51941653342512591,"pool_token_amount":51112383188806046}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":51867714425729609,"pool_token_amount":51114426378277846}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":51826146728070822,"pool_token_amount":51113097091343310}],[106,{"iota_amount":51818187169202139,"pool_token_amount":51112457496902602}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":51785741463703203,"pool_token_amount":51109525828067086}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":51731184887840282,"pool_token_amount":51105576309103202}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":51720484649706071,"pool_token_amount":51109181366121324}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":49967424957381648,"pool_token_amount":49403968941287606}],[88,{"iota_amount":48370271690057824,"pool_token_amount":47831423849303516}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":48356039897420181,"pool_token_amount":47830526313133117}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":46697442180664170,"pool_token_amount":46215168262146206}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":46694371007344132,"pool_token_amount":46218374375944796}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":46714166234290421,"pool_token_amount":46250861135939552}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":46709449036105335,"pool_token_amount":46252531926327891}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":46691403512566763,"pool_token_amount":46253584778809393}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":46682149496808985,"pool_token_amount":46270389143939415}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":46676869074466667,"pool_token_amount":46271800767876012}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":47214288054429489,"pool_token_amount":46882942590602223}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":47208604024039500,"pool_token_amount":46896666938780321}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":47274252063377412,"pool_token_amount":46968257093341508}],[53,{"iota_amount":46864340451483726,"pool_token_amount":46567362125753846}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":46783065306639684,"pool_token_amount":46511938436690961}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":46758661389410100,"pool_token_amount":46520006681332185}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":46141628218439155,"pool_token_amount":45912491876469371}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":45274933977311375,"pool_token_amount":45056372515774157}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":43525518579757756,"pool_token_amount":43339675055682412}],[37,{"iota_amount":43402614866097177,"pool_token_amount":43223280974055640}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":61496899062769681,"pool_token_amount":61296782483020231}],[31,{"iota_amount":61363094272544484,"pool_token_amount":61172787370322622}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":50313536902738581,"pool_token_amount":50173513831948263}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":41352630470643454,"pool_token_amount":41244518786446533}],[26,{"iota_amount":94872571850944512,"pool_token_amount":94751612564350375}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":88042403058745881,"pool_token_amount":88003390297898862}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000002273548}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000172313}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000147259}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000147259}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000147259}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000141726}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":80000000001754400,"pool_token_amount":80000000000140351}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Citadel.one":[[167,{"iota_amount":107406082183618986,"pool_token_amount":105129567882884570}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":107391618860056758,"pool_token_amount":105128787738772398}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":107320038369811515,"pool_token_amount":105125581100859966}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":107244042656128262,"pool_token_amount":105119573067406285}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[149,{"iota_amount":107153054092014711,"pool_token_amount":105126798222941140}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[146,{"iota_amount":107103914630372440,"pool_token_amount":105119678770872358}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":107054601088447237,"pool_token_amount":105112125984241578}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":107024831612910544,"pool_token_amount":105110122877981881}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":106979851021198371,"pool_token_amount":105106818125401518}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":106965577215117279,"pool_token_amount":105106439890856073}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":112422352596839808,"pool_token_amount":110541027965248960}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":116709056489353127,"pool_token_amount":114905528769455124}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":116694269987236747,"pool_token_amount":114905858879158388}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":116678179172202629,"pool_token_amount":114904899482915869}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":116576833119589336,"pool_token_amount":114909866352659871}],[112,{"iota_amount":116558594028718868,"pool_token_amount":114906882650251984}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":116401308064499356,"pool_token_amount":114901326300914456}],[100,{"iota_amount":124415995423891311,"pool_token_amount":122869345889362156}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":124298218354724220,"pool_token_amount":122862726179721904}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":138372681131037020,"pool_token_amount":136836900437570441}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":138165218675109114,"pool_token_amount":136830216703539781}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":138143821815058664,"pool_token_amount":136829555057972350}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":138105457604604295,"pool_token_amount":136831114041690491}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":138084758940797735,"pool_token_amount":136830386619147659}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":138001661368642461,"pool_token_amount":136827654384984771}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":137957031989117001,"pool_token_amount":136825084627885541}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":137913136870763346,"pool_token_amount":136823470730751843}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":137891060870463173,"pool_token_amount":136822526093851396}],[67,{"iota_amount":137868259029041346,"pool_token_amount":136820966704251900}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":137752811823759485,"pool_token_amount":136847560126604818}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":137731896982169368,"pool_token_amount":136846601287885984}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":137629864501462707,"pool_token_amount":136824622407835570}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":137565392791742818,"pool_token_amount":136820464179140355}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":135567963800160780,"pool_token_amount":134972106176280701}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":135413845837989264,"pool_token_amount":134958571255683046}],[37,{"iota_amount":135392350864566672,"pool_token_amount":134957488598172650}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":135347619677642545,"pool_token_amount":134955006554861147}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":119180157721560771,"pool_token_amount":118971376586994786}],[26,{"iota_amount":105134187484493701,"pool_token_amount":104994092822569334}],[25,{"iota_amount":80113555197234743,"pool_token_amount":80022944607766672}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":80072220866053486,"pool_token_amount":80016602158353330}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":80000000000000000,"pool_token_amount":80000000000000000}]],"Cogent Crypto":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":107207805969636319,"pool_token_amount":105015247359294744}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":107194424316230440,"pool_token_amount":105015247340614492}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":107113617093432410,"pool_token_amount":105015269934046747}],[157,{"iota_amount":107099860027799498,"pool_token_amount":105015269969364557}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":107072347882255574,"pool_token_amount":105015270318536719}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":107058590091578971,"pool_token_amount":105015270467076362}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":107044663439285133,"pool_token_amount":105015105569926655}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":106921613729711161,"pool_token_amount":105015180450721069}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":106895470215720781,"pool_token_amount":105016170297961646}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":106881893026007289,"pool_token_amount":105016170478698747}],[139,{"iota_amount":106851414698235033,"pool_token_amount":105012908964976826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":106781818704856353,"pool_token_amount":105011291802314570}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":106768232414246738,"pool_token_amount":105011292011510318}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":106687644282284084,"pool_token_amount":105012242777418926}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":106659614664244470,"pool_token_amount":105011389630339426}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":106646036823880220,"pool_token_amount":105011393649042301}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":106632466193037270,"pool_token_amount":105011403800516702}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":106592233103621247,"pool_token_amount":105011903576324070}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"iota_amount":106315911477872597,"pool_token_amount":105010781291881295}],[100,{"iota_amount":106300381952951661,"pool_token_amount":105010780335637485}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":106192344527397873,"pool_token_amount":105010749653772835}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":106131608158666886,"pool_token_amount":105010545312023228}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":106025314460746792,"pool_token_amount":105009488496473232}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":105988030798020476,"pool_token_amount":105002817299634764}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":105973121201740768,"pool_token_amount":105002866415841452}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":105943204635614329,"pool_token_amount":105002844368501292}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":105867514671167587,"pool_token_amount":105003206809088014}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":105820076124741795,"pool_token_amount":105003211792730189}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":105804197670344125,"pool_token_amount":105003211931587851}],[67,{"iota_amount":105787828067497427,"pool_token_amount":105002724452120633}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":105680983825024918,"pool_token_amount":105002650095807499}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":105560931901563905,"pool_token_amount":104988105625592095}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":105545649979922298,"pool_token_amount":104987975020501584}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":105530502973929311,"pool_token_amount":104987976114569684}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":105486551321663789,"pool_token_amount":104989462671472338}],[45,{"iota_amount":105442476767433184,"pool_token_amount":104990824180489232}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":105427333327648932,"pool_token_amount":104990828006620240}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":106354017750438671,"pool_token_amount":105990813326963723}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":106291394426795312,"pool_token_amount":105992020108702764}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":106274422562672731,"pool_token_amount":105991975631158148}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":106257450628970816,"pool_token_amount":105991934296959032}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":106241384456106218,"pool_token_amount":105992928673921661}],[31,{"iota_amount":106222766814646827,"pool_token_amount":105991347733069284}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":106156732660136850,"pool_token_amount":105995912379614449}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002203900,"pool_token_amount":80000000000000000}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001944400,"pool_token_amount":80000000000000000}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840600,"pool_token_amount":80000000000000000}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840600,"pool_token_amount":80000000000000000}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840600,"pool_token_amount":80000000000000000}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":80000000000000000,"pool_token_amount":80000000000000000}]],"Coinbase Cloud":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":88914549388206032,"pool_token_amount":87260808812530140}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[147,{"iota_amount":88814510828742909,"pool_token_amount":87248168714767575}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":88741004170319277,"pool_token_amount":87239822226145181}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":88706062613253975,"pool_token_amount":87237434118232869}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":88645202401443850,"pool_token_amount":87230895712583068}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":88633293439042599,"pool_token_amount":87229845284394832}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":88608840055103019,"pool_token_amount":87227122305512933}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":88579882483035166,"pool_token_amount":87219798847448114}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":88528204939460923,"pool_token_amount":87211332628981351}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":88513146704505513,"pool_token_amount":87207084016899067}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":88477122828887681,"pool_token_amount":87203349956971873}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":88465912329671950,"pool_token_amount":87202977483741604}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":88453875646049197,"pool_token_amount":87201790111371524}],[116,{"iota_amount":88432399549937142,"pool_token_amount":87201971549949104}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":88408130863671535,"pool_token_amount":87199399743615744}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":88385700422339490,"pool_token_amount":87198642480983868}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":88345052711918964,"pool_token_amount":87191796456751209}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":81202538526639672,"pool_token_amount":80175656596058555}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":81160970481248452,"pool_token_amount":80168714468738974}],[102,{"iota_amount":81148250744756966,"pool_token_amount":80167460720204198}],[99,{"iota_amount":81109600770097577,"pool_token_amount":80162959814647964}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":81073315456385888,"pool_token_amount":80160627291947101}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":81034496220253609,"pool_token_amount":80155659737302221}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":80911213280326687,"pool_token_amount":80142981999170688}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":80887257269063737,"pool_token_amount":80141081173918848}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":80739676248268495,"pool_token_amount":80117280120078120}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":80713868200887503,"pool_token_amount":80114701945680810}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":80552635876344416,"pool_token_amount":80076356462862348}],[56,{"iota_amount":80562770503738770,"pool_token_amount":80097374004013606}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":80551331018925673,"pool_token_amount":80096940635231529}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":80500858391837456,"pool_token_amount":80090816635191553}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":80444129029648963,"pool_token_amount":80111697527371606}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":80423911299137841,"pool_token_amount":80113778340557392}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":80374381512812731,"pool_token_amount":80109284997077117}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":80353064920585107,"pool_token_amount":80110840618833373}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":80310991122644322,"pool_token_amount":80105399807338553}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":80272463815920138,"pool_token_amount":80103816694961694}],[29,{"iota_amount":80240265605912857,"pool_token_amount":80084281137364170}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":120121085039220710,"pool_token_amount":120012858608996896}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":80107243722791027,"pool_token_amount":80053240670599132}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80021048452971536,"pool_token_amount":80002423622832443}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":80000000063519457,"pool_token_amount":80000000001270376}],[18,{"iota_amount":80000000061655557,"pool_token_amount":80000000001233099}],[17,{"iota_amount":80000000049632057,"pool_token_amount":80000000000992630}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002203900,"pool_token_amount":80000000000044070}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002152000,"pool_token_amount":80000000000043033}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001944400,"pool_token_amount":80000000000038882}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840600,"pool_token_amount":80000000000036807}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823300,"pool_token_amount":80000000000036462}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"iota_amount":0,"pool_token_amount":0}]],"ComingChat":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":28463675459547091,"pool_token_amount":27926896514497238}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":28452321064330866,"pool_token_amount":27925758693454604}],[157,{"iota_amount":28448511929708881,"pool_token_amount":27925384829118793}],[156,{"iota_amount":28444692724484111,"pool_token_amount":27925000740791627}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":28437044360653470,"pool_token_amount":27924223322007977}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":28432753118023934,"pool_token_amount":27923376217690560}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"iota_amount":28406336891847696,"pool_token_amount":27921006569400592}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":28398379301090006,"pool_token_amount":27919933748339392}],[143,{"iota_amount":28394574032967564,"pool_token_amount":27919565010417363}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":28364020493535311,"pool_token_amount":27916520493301352}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":28360218188438285,"pool_token_amount":27916156243399528}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":28341988836830724,"pool_token_amount":27915112461599480}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":28338179501177277,"pool_token_amount":27914744440325659}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":28318956515283324,"pool_token_amount":27912710996008318}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":28321966749244834,"pool_token_amount":27922444047325507}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":28318186635290983,"pool_token_amount":27922098968228146}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":28291067961775178,"pool_token_amount":27922415380153372}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":28283839004419633,"pool_token_amount":27922052362497950}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":28277688277587911,"pool_token_amount":27923509733753733}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":28264775035487188,"pool_token_amount":27922318877635167}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[101,{"iota_amount":28248105769705079,"pool_token_amount":27921500754936167}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":28187681550346928,"pool_token_amount":27922116234749930}],[84,{"iota_amount":28183863544039400,"pool_token_amount":27922104830836409}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":28170643427567791,"pool_token_amount":27920121767440030}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":28167575233537033,"pool_token_amount":27920952979743226}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[75,{"iota_amount":28158350477344736,"pool_token_amount":27930263756701998}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":28152023187744325,"pool_token_amount":27931528863636878}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":28138655183397713,"pool_token_amount":27930176029048547}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":28129467086288302,"pool_token_amount":27929000134825463}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":28117450693627330,"pool_token_amount":27928986214820019}],[64,{"iota_amount":28113166647153362,"pool_token_amount":27928506155400033}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":28109030604604224,"pool_token_amount":27928173329595839}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":28085166818159359,"pool_token_amount":27923145709454424}],[56,{"iota_amount":28077431531786683,"pool_token_amount":27923013532739940}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":28051964205069460,"pool_token_amount":27920367015285224}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":28047499031664099,"pool_token_amount":27919705862928915}],[47,{"iota_amount":28039239968323626,"pool_token_amount":27919051748586408}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":28023178378932909,"pool_token_amount":27918196709942772}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"iota_amount":28019197404062445,"pool_token_amount":27925592818304495}],[39,{"iota_amount":28014687516890535,"pool_token_amount":27924986210692435}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":28015881366411440,"pool_token_amount":27958747041936385}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":27948628780081799,"pool_token_amount":27909012002583526}],[25,{"iota_amount":20940517851008343,"pool_token_amount":20918348989513696}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":20007327815991001,"pool_token_amount":20002752805100917}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":20000000000475400,"pool_token_amount":20000000000009502}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":20000000000428400,"pool_token_amount":20000000000008567}],[1,{"iota_amount":20000000000000000,"pool_token_amount":20000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"ContributionDAO":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":164384858116336134,"pool_token_amount":160950273799944227}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":166870175485885992,"pool_token_amount":163446829962754937}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":166762664561014249,"pool_token_amount":163449622738997413}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"iota_amount":171656119979301668,"pool_token_amount":168357978272732954}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[146,{"iota_amount":171562619594415091,"pool_token_amount":168354906988604968}],[145,{"iota_amount":171539331063793423,"pool_token_amount":168354126208424638}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":171447044581001781,"pool_token_amount":168351795964222834}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":173817701384548551,"pool_token_amount":170769492956330425}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":173608983078978238,"pool_token_amount":170765940942128741}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":173534204843560009,"pool_token_amount":170781821340314889}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":173441362353087590,"pool_token_amount":170757591756228110}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":173417893293727589,"pool_token_amount":170756898578611854}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":173348450661717623,"pool_token_amount":170755766824265324}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":173230444758528969,"pool_token_amount":170751634255896785}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":173194954378111553,"pool_token_amount":170761538019387817}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":173019039971374319,"pool_token_amount":170767063800148781}],[102,{"iota_amount":172991860562966398,"pool_token_amount":170766259987883938}],[98,{"iota_amount":172886734929657115,"pool_token_amount":170765526691278326}],[97,{"iota_amount":172856411713878258,"pool_token_amount":170761056231547097}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":172803196611882425,"pool_token_amount":170759527399312257}],[94,{"iota_amount":172776618331402674,"pool_token_amount":170758765478366535}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":172724489731257692,"pool_token_amount":170757911534800446}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":172433801337669237,"pool_token_amount":170645900037110253}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":172323977431512483,"pool_token_amount":170636894076567931}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":172296949550218528,"pool_token_amount":170636001854383568}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":172245066371664352,"pool_token_amount":170634414760461696}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":172171324595306711,"pool_token_amount":170636027371623444}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":232014369045137219,"pool_token_amount":230411316005419493}],[61,{"iota_amount":231979679198360030,"pool_token_amount":230410483016542845}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":231944586430933419,"pool_token_amount":230409256275922183}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":231910117154478691,"pool_token_amount":230408638485991881}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":231665017888331586,"pool_token_amount":230402061444264705}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":231437647034198444,"pool_token_amount":230414268347426375}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":231367468786063792,"pool_token_amount":230412657393514363}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":231296993332003246,"pool_token_amount":230411296703256947}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":171216209892595208,"pool_token_amount":170637808821354472}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":171166936577431191,"pool_token_amount":170640973346031054}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":171112348207293251,"pool_token_amount":170642016038660056}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":170979843956704996,"pool_token_amount":170622403747245364}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":200924629241227068,"pool_token_amount":200578604616873409}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":150635151102499971,"pool_token_amount":150600252037017451}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":150399001193211591,"pool_token_amount":150399001003360554}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":150000001116171591,"pool_token_amount":150000001002323420}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":150000000004141300,"pool_token_amount":150000000000082818}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":150000000003652300,"pool_token_amount":150000000000073040}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":150000000003391500,"pool_token_amount":150000000000067827}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":150000000000000000,"pool_token_amount":150000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Cosmostation":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":62519184749121786,"pool_token_amount":61218068270816353}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":62512572583848752,"pool_token_amount":61219578600017324}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":62497185016804999,"pool_token_amount":61212687603700174}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":62283033259586780,"pool_token_amount":61060138298515259}],[151,{"iota_amount":62255343478020503,"pool_token_amount":61041178899081599}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":62126171317968074,"pool_token_amount":60963177780383500}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":62146128885575718,"pool_token_amount":61007084472527030}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":62135726053437039,"pool_token_amount":61004978091254334}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":62104214303974874,"pool_token_amount":60990405242455411}],[138,{"iota_amount":62102568925932558,"pool_token_amount":60996908281103934}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":62014071580228635,"pool_token_amount":60934342927864214}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":61987779166830548,"pool_token_amount":60932864695270223}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61909138043938543,"pool_token_amount":60879939343466564}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":61857524031022491,"pool_token_amount":60845443991475031}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":61823687784102379,"pool_token_amount":60820189869627136}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":61762381327179564,"pool_token_amount":60775938735086494}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":61699118417289499,"pool_token_amount":60778414425113034}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":61797730793895232,"pool_token_amount":60916352565956710}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":61736691419853675,"pool_token_amount":60873529798553550}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":61715277007317657,"pool_token_amount":60861464303559765}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":62640434102520000,"pool_token_amount":61896961428110144}],[94,{"iota_amount":62619420751975078,"pool_token_amount":61885625971831149}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":62592428321710388,"pool_token_amount":61868249035075106}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":62260242577486533,"pool_token_amount":61613151320741684}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":61802460577884500,"pool_token_amount":61196382829439248}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":61732371362429901,"pool_token_amount":61163674309617290}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":61647415656713789,"pool_token_amount":61125468611036690}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":61529044034002753,"pool_token_amount":61102346778432297}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":61558788162134750,"pool_token_amount":61204744041918738}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":61542839706022923,"pool_token_amount":61216292252554819}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":61522094502311688,"pool_token_amount":61213965541379444}],[48,{"iota_amount":60192333450565162,"pool_token_amount":59899937118440345}],[47,{"iota_amount":60186572054858265,"pool_token_amount":59903200695603127}],[45,{"iota_amount":60167518817932864,"pool_token_amount":59902231450720866}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":60137263281299123,"pool_token_amount":59890109384247530}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"iota_amount":45284812687764803,"pool_token_amount":45119375707648245}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":27770541328762752,"pool_token_amount":27695096560602518}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":27711390383903623,"pool_token_amount":27654362412042329}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":27549723497508046,"pool_token_amount":27497598504318174}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"iota_amount":20519078129426077,"pool_token_amount":20491507790020986}],[25,{"iota_amount":20062522493480638,"pool_token_amount":20039702184294168}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":20000000025396901,"pool_token_amount":20000000000507924}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"iota_amount":20000000012328401,"pool_token_amount":20000000000246557}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":20000000000539900,"pool_token_amount":20000000000010790}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":20000000000441000,"pool_token_amount":20000000000008817}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"iota_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Cypher Capital":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":27536875750219004,"pool_token_amount":27000961445357885}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":27523861787362059,"pool_token_amount":27000938673622838}],[161,{"iota_amount":27520620998211608,"pool_token_amount":27000941849579642}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":27514055893754746,"pool_token_amount":27000962690733229}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":27510718991636619,"pool_token_amount":27000963739218610}],[157,{"iota_amount":27507668405587819,"pool_token_amount":27001245910345879}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":27500993881894685,"pool_token_amount":27001247051502824}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"iota_amount":27477138071521897,"pool_token_amount":27000768583039884}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":27473787648484808,"pool_token_amount":27000758789679148}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":27464038440734772,"pool_token_amount":27000764747052716}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":27450750655027401,"pool_token_amount":27000480907624011}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":27447500217935035,"pool_token_amount":27000481196129132}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":27421371187519271,"pool_token_amount":27000376444620660}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":27414684228253039,"pool_token_amount":27000200452602857}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":27405605200240322,"pool_token_amount":27000869811614678}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":27402355668508966,"pool_token_amount":27000870890984506}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":27399248831950581,"pool_token_amount":27001012967319843}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":27392772073344406,"pool_token_amount":27001038005433548}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":27379773313354645,"pool_token_amount":27001038998488234}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":27364760957454912,"pool_token_amount":27002255993532020}],[112,{"iota_amount":27361095495736577,"pool_token_amount":27001845458399758}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":27347435582189446,"pool_token_amount":27001909985820610}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":27343754985326573,"pool_token_amount":27001941672664053}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":27328638824600972,"pool_token_amount":27001939032589038}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":27297890838209768,"pool_token_amount":27001047726338283}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":27290447847016634,"pool_token_amount":27001033658057914}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":27283147384655587,"pool_token_amount":27001042715463291}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":27261013342247848,"pool_token_amount":27000711952536311}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":27209994165049538,"pool_token_amount":27000839902279679}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":27202277096692741,"pool_token_amount":27000828156765046}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":27161550036004983,"pool_token_amount":26997333649082802}],[58,{"iota_amount":27157949148668486,"pool_token_amount":26997333692701212}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":27148032283830513,"pool_token_amount":26998215129700362}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":27140619975178699,"pool_token_amount":26998205838876158}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":27754389969509502,"pool_token_amount":27619970012298412}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":27105854365198213,"pool_token_amount":26996672715681242}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":27083320945488131,"pool_token_amount":26996349150830067}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":27071702202441299,"pool_token_amount":26996357109312650}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":27063121762563623,"pool_token_amount":26995982050313244}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":27047658154124729,"pool_token_amount":26997033952637780}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":27033489747759826,"pool_token_amount":26991994335921175}],[24,{"iota_amount":20020601696933047,"pool_token_amount":20002166498497671}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":20000000007017893,"pool_token_amount":20000000000140348}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":20000000000539900,"pool_token_amount":20000000000010790}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":20000000000527000,"pool_token_amount":20000000000010533}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":20000000000475400,"pool_token_amount":20000000000009502}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":20000000000428400,"pool_token_amount":20000000000008567}]],"DSRV":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":137963016637127908,"pool_token_amount":135102872277069316}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":137926385218785058,"pool_token_amount":135101299111054378}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":137858998325742264,"pool_token_amount":135104840939317018}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":137785716586466793,"pool_token_amount":135103752938575248}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":137766761407287419,"pool_token_amount":135102813451236595}],[151,{"iota_amount":137728947390623029,"pool_token_amount":135101217043191731}],[149,{"iota_amount":137691253746787644,"pool_token_amount":135099737965663351}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":137660896365330409,"pool_token_amount":135105091824639617}],[146,{"iota_amount":137642267461327884,"pool_token_amount":135104389106167030}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":137566741198477203,"pool_token_amount":135117997030388331}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":137517389092589614,"pool_token_amount":135122037273372253}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":137498896878136665,"pool_token_amount":135121399607071910}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":137432569458110987,"pool_token_amount":135126295829319420}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":137376652228232271,"pool_token_amount":135124099250780988}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":137347171984008825,"pool_token_amount":135147746610887320}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":137272650407492204,"pool_token_amount":135144554293457112}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":137198613374795340,"pool_token_amount":135141826156395258}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":137162269507748038,"pool_token_amount":135141116045708697}],[116,{"iota_amount":137144443633324228,"pool_token_amount":135141099423694860}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":137106447223271924,"pool_token_amount":135138947188009398}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":136990975962631765,"pool_token_amount":135134586925819454}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":136968036411680263,"pool_token_amount":135131701760965754}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":136946539095120905,"pool_token_amount":135130756786301341}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[98,{"iota_amount":136775235236496314,"pool_token_amount":135123984074261243}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":136691136657491831,"pool_token_amount":135120797032679676}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":136607454720849562,"pool_token_amount":135117022565421377}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":136566119811591526,"pool_token_amount":135115366206837655}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":136507237924502945,"pool_token_amount":135115922267389648}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":136438102501667544,"pool_token_amount":135125544402614939}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":136350833142315120,"pool_token_amount":135137151519719852}],[74,{"iota_amount":136310910122784457,"pool_token_amount":135136500478169887}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":136179730839072490,"pool_token_amount":135150658434617056}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":136132230454290463,"pool_token_amount":135145020831286122}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":136072080177740536,"pool_token_amount":135143985035282446}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":136028824998582310,"pool_token_amount":135140130048625117}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":135963976501082518,"pool_token_amount":135134529809135353}],[56,{"iota_amount":135942199940277584,"pool_token_amount":135132505730355926}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":135774570172051718,"pool_token_amount":135123798431862670}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":135670452708013156,"pool_token_amount":135099485959960333}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":135628428465983539,"pool_token_amount":135097480468167306}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"iota_amount":135607453813013951,"pool_token_amount":135096676345486694}],[40,{"iota_amount":135586405179843407,"pool_token_amount":135095797405103136}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":105427815284828088,"pool_token_amount":105177837112827071}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":105095578425649817,"pool_token_amount":104915865207057700}],[26,{"iota_amount":130084127584822057,"pool_token_amount":129916052005953240}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":26020681646333831,"pool_token_amount":26014579051656928}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":25000000019248364,"pool_token_amount":25000000000384956}],[16,{"iota_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":25000000000550800,"pool_token_amount":25000000000011015}]],"Dankuzone_w_DAIC":[[167,{"iota_amount":138080083416507696,"pool_token_amount":135167029376847076}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":138061837641894298,"pool_token_amount":135166314942586174}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":138043595774316778,"pool_token_amount":135165600570724121}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":138025350058828201,"pool_token_amount":135164885957495829}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":137879442942225766,"pool_token_amount":135161071809948553}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":137841752093305435,"pool_token_amount":135159593801987374}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":137785112423688894,"pool_token_amount":135157184920686186}],[149,{"iota_amount":137747418779853509,"pool_token_amount":135155705833628269}],[147,{"iota_amount":137710112499552665,"pool_token_amount":135154240620814965}],[146,{"iota_amount":137691453240475021,"pool_token_amount":135153508102373389}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":137544930218913138,"pool_token_amount":135149993801334068}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":137507765109717997,"pool_token_amount":135148532985656918}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":137452066183831292,"pool_token_amount":135146343921982824}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":137433394734349457,"pool_token_amount":135145609591802482}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":137377558006107984,"pool_token_amount":135143411126249089}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":137340414445455947,"pool_token_amount":135141960962194826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":137321819850859809,"pool_token_amount":135141199800307774}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":137229006908621420,"pool_token_amount":135137542449771813}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":137191096683909441,"pool_token_amount":135135292658800142}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":137172542673512735,"pool_token_amount":135134562566531638}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":140267602802911162,"pool_token_amount":138368372478377374}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":140246308144662790,"pool_token_amount":138367532224860138}],[106,{"iota_amount":140224350174350652,"pool_token_amount":138366566219151502}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":140202239569158620,"pool_token_amount":138365702044250767}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":140180185725225756,"pool_token_amount":138364831441564367}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[97,{"iota_amount":140026662576722300,"pool_token_amount":138358150354157529}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":139831339731203777,"pool_token_amount":138347710903317466}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":139767213443742347,"pool_token_amount":138344566569057947}],[84,{"iota_amount":139746047867667554,"pool_token_amount":138343605033759798}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":139724767393719270,"pool_token_amount":138342635008261689}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":139639847237545302,"pool_token_amount":138339269164782443}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":139545255194387667,"pool_token_amount":138345465069493390}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":139412753603668193,"pool_token_amount":138340202867525305}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":139340453392872240,"pool_token_amount":138352307878795715}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":139297464420419605,"pool_token_amount":138349667339099827}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":139126636410988266,"pool_token_amount":138340541714142121}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":139060235386822738,"pool_token_amount":138335311498139311}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"iota_amount":138982126920488357,"pool_token_amount":138338701109536182}],[46,{"iota_amount":138960899838722887,"pool_token_amount":138337855957141578}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":138875862764554333,"pool_token_amount":138334450835922404}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"iota_amount":138832346120875683,"pool_token_amount":138332236713545847}],[39,{"iota_amount":138818442967931451,"pool_token_amount":138339010134456434}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":83738601953438460,"pool_token_amount":83500301328716065}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":80420087405893087,"pool_token_amount":80256121167999926}],[29,{"iota_amount":80161854581012482,"pool_token_amount":80011597637622209}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019005353317487,"pool_token_amount":80000380998369127}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":80000000062001508,"pool_token_amount":80000000001240018}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Durian":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":112267558263135962,"pool_token_amount":110230936368613960}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":112223052049043288,"pool_token_amount":110226565964074639}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":112147889304559927,"pool_token_amount":110219181624430528}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"iota_amount":112025341842676628,"pool_token_amount":110207265934664426}],[149,{"iota_amount":112010002903850323,"pool_token_amount":110205756934143752}],[146,{"iota_amount":111963019072553158,"pool_token_amount":110199849530244235}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":111902415446230020,"pool_token_amount":110193883512725326}],[136,{"iota_amount":111811477203248373,"pool_token_amount":110184925799770217}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":111796324152728200,"pool_token_amount":110183432537771751}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":111781175338271632,"pool_token_amount":110181944044877418}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":111736479321134839,"pool_token_amount":110178228418045972}],[130,{"iota_amount":111721318211706225,"pool_token_amount":110176733449909262}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":111691179754320532,"pool_token_amount":110173761090014635}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":111676021886553934,"pool_token_amount":110172265895985840}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":111660968323272814,"pool_token_amount":110170779033589194}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":111645920333820480,"pool_token_amount":110169295215933111}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":111630869567627884,"pool_token_amount":110167810044976076}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[122,{"iota_amount":111600767370981176,"pool_token_amount":110164839096778408}],[121,{"iota_amount":111585718030759838,"pool_token_amount":110163353525803186}],[120,{"iota_amount":111570575482516635,"pool_token_amount":110161860363946524}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":111540285177472290,"pool_token_amount":110158869395202733}],[115,{"iota_amount":111494853657740427,"pool_token_amount":110154377426622797}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":111463978144692063,"pool_token_amount":110150802286329956}],[111,{"iota_amount":111433690465308719,"pool_token_amount":110147809017034600}],[110,{"iota_amount":111418540924322977,"pool_token_amount":110146311544228286}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[101,{"iota_amount":111262854764800132,"pool_token_amount":110130773163864372}],[100,{"iota_amount":111245533142896723,"pool_token_amount":110129059518019194}],[98,{"iota_amount":111210846873555936,"pool_token_amount":110125543495444120}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":111159227488275607,"pool_token_amount":110120426759873934}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[92,{"iota_amount":111108029005125132,"pool_token_amount":110115354947391209}],[91,{"iota_amount":111091128622996337,"pool_token_amount":110113680007841474}],[88,{"iota_amount":111040592186085280,"pool_token_amount":110108670143997350}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":110906463518233142,"pool_token_amount":110095820351163048}],[78,{"iota_amount":110873091255231928,"pool_token_amount":110092505506146723}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":110856407727769952,"pool_token_amount":110090847111845389}],[74,{"iota_amount":110806130373018823,"pool_token_amount":110085616571945580}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":110735555299407114,"pool_token_amount":110077912873537262}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[63,{"iota_amount":123167566926711444,"pool_token_amount":122559535783128935}],[60,{"iota_amount":123111367164326325,"pool_token_amount":122553480573901455}],[56,{"iota_amount":123037126207873879,"pool_token_amount":122546087720432536}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":122943324541879711,"pool_token_amount":122536748703684554}],[49,{"iota_amount":122905752993538340,"pool_token_amount":122532996540078638}],[48,{"iota_amount":122886968934813259,"pool_token_amount":122531123831150087}],[45,{"iota_amount":122830620970753970,"pool_token_amount":122525500987837353}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":122811837847620318,"pool_token_amount":122523625545853435}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[40,{"iota_amount":122738165301376243,"pool_token_amount":122518085489366982}],[39,{"iota_amount":122719047108522842,"pool_token_amount":122516176199742487}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":122680666455669859,"pool_token_amount":122512344209576959}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":122661126172852919,"pool_token_amount":122510392862215734}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":122619947322425958,"pool_token_amount":122506232213155640}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Everstake":[[167,{"iota_amount":142807814844400421,"pool_token_amount":139915388182180342}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":142755276649338752,"pool_token_amount":139914966400649257}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":142668308449215587,"pool_token_amount":139915395390638255}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":142646923007800151,"pool_token_amount":139911968057284587}],[157,{"iota_amount":142628927969922627,"pool_token_amount":139911866109265261}],[156,{"iota_amount":142612293886035551,"pool_token_amount":139913097806804180}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":142553129466176960,"pool_token_amount":139907712189942118}],[151,{"iota_amount":56044122752153279,"pool_token_amount":24261207903505724}],[150,{"iota_amount":142497353928904084,"pool_token_amount":139905652561190858}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"iota_amount":86799377164006941,"pool_token_amount":85263290878246503}],[145,{"iota_amount":86913965466182396,"pool_token_amount":85386480891838675}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":86891645334307783,"pool_token_amount":85385775249981104}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":86858612950253401,"pool_token_amount":85385143979313986}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":86847814094820369,"pool_token_amount":85385144734298588}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":86814010880531092,"pool_token_amount":85383796119505059}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":86989285207594538,"pool_token_amount":85694716411568756}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":86977543242634697,"pool_token_amount":85693790127055006}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":86931768006466329,"pool_token_amount":85691331250097953}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":86884548024335412,"pool_token_amount":85687709125545605}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":86835643548359176,"pool_token_amount":85682431841782889}],[109,{"iota_amount":86858160445957156,"pool_token_amount":85716599000094488}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":86815010731465766,"pool_token_amount":85710264988386857}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[103,{"iota_amount":86773929952778410,"pool_token_amount":85707097718944487}],[99,{"iota_amount":86718514545540289,"pool_token_amount":85701691549308646}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":86643199287062388,"pool_token_amount":85700317041390445}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":86630799747285777,"pool_token_amount":85700076354670299}],[91,{"iota_amount":86615534451865062,"pool_token_amount":85696972481870354}],[90,{"iota_amount":86597381657834345,"pool_token_amount":85690980801647459}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":86544027634107068,"pool_token_amount":85685991533340907}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":86430991017804854,"pool_token_amount":85585969727140681}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":86370404126001794,"pool_token_amount":85585697406562242}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":86356644537015932,"pool_token_amount":85583932870432048}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[75,{"iota_amount":86322790608735465,"pool_token_amount":85597821608625581}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":36122599071277852,"pool_token_amount":35850174350039561}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":36117875196316832,"pool_token_amount":35850661227931114}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":36057160086425352,"pool_token_amount":35835750307537514}],[57,{"iota_amount":36046229392550506,"pool_token_amount":35834845292752257}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":36033540217560529,"pool_token_amount":35837279833773449}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"iota_amount":35937688889289594,"pool_token_amount":35811986967819966}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":35910852347053993,"pool_token_amount":35806063668195359}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":35877912547779336,"pool_token_amount":35789838643085958}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":35865950143283234,"pool_token_amount":35783526668662324}],[31,{"iota_amount":35862889594629692,"pool_token_amount":35786085908081500}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":35875187600549083,"pool_token_amount":35803974279050581}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":35861744741958327,"pool_token_amount":35802112905141738}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":25000000031979264,"pool_token_amount":25000000000639572}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":25000000000691200,"pool_token_amount":25000000000013816}],[14,{"iota_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Figment":[[167,{"iota_amount":292743642775759795,"pool_token_amount":286983970506020159}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":291523528851287664,"pool_token_amount":285855783676031397}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":291444822731714201,"pool_token_amount":285846548652630199}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":291406029639003614,"pool_token_amount":285877286535784655}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":291325264865836623,"pool_token_amount":285866938319057748}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":290938382323267860,"pool_token_amount":285592204010232568}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":290817896775832045,"pool_token_amount":285578901407950349}],[148,{"iota_amount":283792402875372040,"pool_token_amount":278851178036127116}],[147,{"iota_amount":283752787109841267,"pool_token_amount":278846227777308756}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":283351212973998446,"pool_token_amount":278756435517782366}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":275114149409027680,"pool_token_amount":270850481360075857}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":285040150213521019,"pool_token_amount":280692170187570658}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":285001665349129436,"pool_token_amount":280688374201156796}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":283176416489789132,"pool_token_amount":278992489857477649}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":283108343933225978,"pool_token_amount":278959340778255276}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":282917168595728151,"pool_token_amount":278974341120296874}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":282878796128614259,"pool_token_amount":278970440103571712}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":271607209499381778,"pool_token_amount":267992531521566520}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":271570640782890514,"pool_token_amount":267989133698667147}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":271446068579788185,"pool_token_amount":267931606134779372}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":271409168172897213,"pool_token_amount":267927892801510410}],[109,{"iota_amount":271392679306863261,"pool_token_amount":267947976891255946}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":271344023847870244,"pool_token_amount":267936296423971220}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":207957982878284414,"pool_token_amount":205861336931255317}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":201735598303361325,"pool_token_amount":199918798669038221}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":201704228860793560,"pool_token_amount":199914809728174711}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":126665348941072051,"pool_token_amount":125576284188324766}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":126716705623580901,"pool_token_amount":125695177118723916}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":126664080936609335,"pool_token_amount":125714275263664706}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":125390481226779874,"pool_token_amount":124539861942466116}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":125351323341784029,"pool_token_amount":124535838077392571}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":135175605670953098,"pool_token_amount":134352237904087001}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":135140513307421238,"pool_token_amount":134335556161003829}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":135098025740606303,"pool_token_amount":134329710596287866}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":118803634776285189,"pool_token_amount":118192617498425390}],[53,{"iota_amount":118785430173449732,"pool_token_amount":118190729571815216}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":118767236950132408,"pool_token_amount":118188852267904324}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":117743497393932472,"pool_token_amount":117202212035851224}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":116725062411805344,"pool_token_amount":116204389183489566}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"iota_amount":97425390702465801,"pool_token_amount":97112421153483550}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":71988979532118606,"pool_token_amount":71864217406875960}],[29,{"iota_amount":71976178396788602,"pool_token_amount":71862731076251528}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":153275492884432024,"pool_token_amount":153239949469566931}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":150000000116171591,"pool_token_amount":150000000002323421}],[16,{"iota_amount":150000000053253526,"pool_token_amount":150000000001065062}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":150000000003652300,"pool_token_amount":150000000000073041}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069130}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":150000005003424100,"pool_token_amount":150000005000068478}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":150000005003391500,"pool_token_amount":150000005000067827}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":150000000000000000,"pool_token_amount":150000000000000000}]],"Forbole":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":27642822756141381,"pool_token_amount":27126156519265838}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":27624047329178017,"pool_token_amount":27124110091027145}],[151,{"iota_amount":27620338160797721,"pool_token_amount":27123745886583784}],[150,{"iota_amount":27616601147076411,"pool_token_amount":27123354156736969}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[148,{"iota_amount":27609182356984187,"pool_token_amount":27122625483172203}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":27594428492188599,"pool_token_amount":27121262411449704}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":27583295656833484,"pool_token_amount":27120168083713941}],[140,{"iota_amount":27579584060779168,"pool_token_amount":27119803155449955}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":27572155545207219,"pool_token_amount":27122361915210868}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":27564543863186190,"pool_token_amount":27121451105599050}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":27560830649349109,"pool_token_amount":27121085752615374}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":27553907668126423,"pool_token_amount":27120851770279555}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":27556977028396919,"pool_token_amount":27136960375176111}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":27553298333507867,"pool_token_amount":27136629566186357}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":27542513468714026,"pool_token_amount":27135612883551777}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":27511167000244482,"pool_token_amount":27130787406930810}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"iota_amount":27492111978575890,"pool_token_amount":27128461913238457}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":27488399839040130,"pool_token_amount":27128095609076314}],[109,{"iota_amount":27484296333707292,"pool_token_amount":27127710390235543}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":27486171238866479,"pool_token_amount":27133226187367375}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":27453679858301709,"pool_token_amount":27123847043322726}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":27407942968932371,"pool_token_amount":27119612254177374}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":27399852874618436,"pool_token_amount":27118810810788890}],[88,{"iota_amount":27395815242829627,"pool_token_amount":27118412988216372}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":27383724654869506,"pool_token_amount":27117218174585504}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":27375334554835290,"pool_token_amount":27116150773237697}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":27359581888419338,"pool_token_amount":27115032726579727}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":27358711295251988,"pool_token_amount":27121311958184803}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":27351211208748465,"pool_token_amount":27121015855141326}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":27338870474729039,"pool_token_amount":27119788629564554}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":27312196713693759,"pool_token_amount":27123796589421875}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":27308195656498562,"pool_token_amount":27123399243634706}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":27296122024637149,"pool_token_amount":27122137361330633}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":27222065431237231,"pool_token_amount":27052130393018720}],[57,{"iota_amount":27213830571377595,"pool_token_amount":27051103597167495}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":27208999209961929,"pool_token_amount":27049880818421886}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":27150118059221951,"pool_token_amount":27006053123200235}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"iota_amount":27129018932943452,"pool_token_amount":27003471593888027}],[45,{"iota_amount":27120694150354101,"pool_token_amount":27002552427204267}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":27112422316048740,"pool_token_amount":27001685777781687}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":27086790993747702,"pool_token_amount":27000356993575653}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":27082535860841283,"pool_token_amount":27000260342236597}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":27058841267455243,"pool_token_amount":26998801090726417}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":27046323328515804,"pool_token_amount":26999915133869243}],[26,{"iota_amount":20033267984099894,"pool_token_amount":20006437518766712}],[25,{"iota_amount":20028145911136436,"pool_token_amount":20005458321224873}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":20017852200211770,"pool_token_amount":20003997637414117}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":20004781250991001,"pool_token_amount":20000206822415692}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":20000000000475400,"pool_token_amount":20000000000009502}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Galaxy Digital":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":137919474941004479,"pool_token_amount":135027862106056252}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":137882923907542015,"pool_token_amount":135026370983865984}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":137788892509831649,"pool_token_amount":135020492605667663}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":137751226956119942,"pool_token_amount":135018850521330787}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":137693148386375584,"pool_token_amount":135032483501683058}],[151,{"iota_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":137504146050218934,"pool_token_amount":135022847841416883}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":137467238483144216,"pool_token_amount":135021587935866408}],[140,{"iota_amount":137448235517354948,"pool_token_amount":135020421751653344}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":137410786930262340,"pool_token_amount":135018654358533198}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":137354647613858667,"pool_token_amount":135016061526230850}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":137335212596626860,"pool_token_amount":135014477388800172}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":137056183745821594,"pool_token_amount":135003008641055967}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":136979490575177590,"pool_token_amount":134997637761992548}],[114,{"iota_amount":136958388064933198,"pool_token_amount":134994392619288367}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":136920959365007845,"pool_token_amount":134992612330300394}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":136884146692894480,"pool_token_amount":134991446043851660}],[109,{"iota_amount":136863485999169873,"pool_token_amount":134990600760585485}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":136820200633017719,"pool_token_amount":134987072595211790}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":136775676808803015,"pool_token_amount":134983808483637807}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":136754571231809844,"pool_token_amount":134983324323798159}],[100,{"iota_amount":136674211747637070,"pool_token_amount":134984964748139850}],[97,{"iota_amount":136626067092875576,"pool_token_amount":134997542544118728}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":136604950179177385,"pool_token_amount":134996699313575835}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":136578605884996768,"pool_token_amount":134990636488708488}],[94,{"iota_amount":136546888094715192,"pool_token_amount":134979268009693212}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":136525902032842776,"pool_token_amount":134978454440713915}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":136505169805124573,"pool_token_amount":134977679560799530}],[90,{"iota_amount":136463756148671222,"pool_token_amount":134976037563092790}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":136438151559776759,"pool_token_amount":134970335009884421}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":136309160237052333,"pool_token_amount":134960035788098974}],[82,{"iota_amount":136271641980070343,"pool_token_amount":134942354667655353}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":136228111640555639,"pool_token_amount":134938924654883215}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":136207635061061585,"pool_token_amount":134938113342811545}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":136144558357631838,"pool_token_amount":134933986954662946}],[75,{"iota_amount":136466109184104423,"pool_token_amount":135272291209185669}],[74,{"iota_amount":136438997268724325,"pool_token_amount":135264984187000428}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":136373377517051551,"pool_token_amount":135261279455711091}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":136811022226621543,"pool_token_amount":135757776596121699}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":136767477459046791,"pool_token_amount":135756276779978815}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"iota_amount":136644549050675177,"pool_token_amount":135753082816031755}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":136559433933295295,"pool_token_amount":135747277285928170}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"iota_amount":135904847494610289,"pool_token_amount":135393883200513826}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":105763339498424840,"pool_token_amount":105478989479366670}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":105726237551781905,"pool_token_amount":105476503345668666}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":105688200233411812,"pool_token_amount":105473050298482246}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078923191536673,"pool_token_amount":80005247106203323}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Gaucho":[[167,{"iota_amount":27526361136218989,"pool_token_amount":26994038145237773}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":27517339029170399,"pool_token_amount":26994745906659261}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":27513730517164046,"pool_token_amount":26994391908174855}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":27494344303301326,"pool_token_amount":26994752246283589}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"iota_amount":27463366649778599,"pool_token_amount":26997029694082003}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":27452466620726189,"pool_token_amount":26995904118792013}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":27428108850956138,"pool_token_amount":26997532979638656}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":27418908915533852,"pool_token_amount":26998079793450379}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":27404459008791858,"pool_token_amount":26996665167474833}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":27391980471588136,"pool_token_amount":26993985205535229}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":27388367710766295,"pool_token_amount":26993628291313997}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":27390585658103239,"pool_token_amount":27005428149678431}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":27354426969874864,"pool_token_amount":27001813548604032}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":27325703491140879,"pool_token_amount":26998155943239433}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":27317337374047619,"pool_token_amount":26997331089448439}],[99,{"iota_amount":27301897283427224,"pool_token_amount":26996803081238006}],[98,{"iota_amount":27297777914138532,"pool_token_amount":26996398426784022}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":27289390014911352,"pool_token_amount":26995318074925092}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":27285202390946649,"pool_token_amount":26994820974167471}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":27257428760427077,"pool_token_amount":26999191486490054}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":27253409462385471,"pool_token_amount":26998712432527932}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":27241391121089436,"pool_token_amount":26997285275771218}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":27229156997241884,"pool_token_amount":26995837216389126}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":27221243054819080,"pool_token_amount":26994976078692214}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":27213186924933140,"pool_token_amount":26993969669848666}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":27205070341751182,"pool_token_amount":26993000930717957}],[72,{"iota_amount":27202888391779627,"pool_token_amount":26994523785518684}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":27190550479867904,"pool_token_amount":26993444567070368}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":27184737948929214,"pool_token_amount":26995150115221609}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":27176068388927063,"pool_token_amount":26994115727572704}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":27172067605527914,"pool_token_amount":26993638847947062}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":27168957332397986,"pool_token_amount":26997625122484525}],[61,{"iota_amount":27164955291099788,"pool_token_amount":26997226547782272}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":27160953465200052,"pool_token_amount":26996828836091722}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":27112653177601147,"pool_token_amount":26992465209852314}],[45,{"iota_amount":27101538586374329,"pool_token_amount":26992452884229542}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":27089592147949644,"pool_token_amount":26991612424871262}],[41,{"iota_amount":27085884776131352,"pool_token_amount":26991606482358613}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"iota_amount":27082597079719365,"pool_token_amount":26992018628228272}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":27063191772577468,"pool_token_amount":26991645259036868}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":27055150195916347,"pool_token_amount":26991807663942133}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":27041573553594913,"pool_token_amount":26994743348070854}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":27036867706521641,"pool_token_amount":26994252914124742}],[24,{"iota_amount":20019242481249717,"pool_token_amount":20002312351963101}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":20004772935991001,"pool_token_amount":20000571853482870}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":20000000025396901,"pool_token_amount":20000000002539676}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":20000000000527000,"pool_token_amount":20000000000052693}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000441000,"pool_token_amount":20000000000044097}],[4,{"iota_amount":20000000000441000,"pool_token_amount":20000000000044097}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":20000000000428400,"pool_token_amount":20000000000042839}]],"H2O Nodes":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":27510777003913803,"pool_token_amount":26995000383438210}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":27494172229173946,"pool_token_amount":26994995816745830}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":27487496189921606,"pool_token_amount":26994995956687129}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":27483884809743696,"pool_token_amount":26994727867656870}],[148,{"iota_amount":27467805238473411,"pool_token_amount":26995329276548019}],[146,{"iota_amount":27461305038549391,"pool_token_amount":26995329610323116}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":27424571265840938,"pool_token_amount":26994379788946396}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":27421331176253903,"pool_token_amount":26994391174175311}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":27414466375677658,"pool_token_amount":26994036533760919}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":27404704556452605,"pool_token_amount":26994035892552765}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":27398206005630459,"pool_token_amount":26994044574357438}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":27394834806572048,"pool_token_amount":26993926326163981}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":27391537320103757,"pool_token_amount":26993880153107829}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":27375312064434312,"pool_token_amount":26993907931036430}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":27372062310401493,"pool_token_amount":26993907961507156}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":27368812611663877,"pool_token_amount":26993907940397229}],[116,{"iota_amount":27362313687465359,"pool_token_amount":26993907048777640}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":27359067549313505,"pool_token_amount":26993910060984330}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":27349309592114633,"pool_token_amount":26993900156118938}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":27335382442987823,"pool_token_amount":26993700830039650}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":27331655057309259,"pool_token_amount":26993686318894489}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":27324067647729662,"pool_token_amount":26993681034573353}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":27320230975845488,"pool_token_amount":26993606097502182}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"iota_amount":27308970076620561,"pool_token_amount":26993592000390155}],[99,{"iota_amount":27301625697339957,"pool_token_amount":26993676401422702}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":27275509136406350,"pool_token_amount":26993589296899374}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":27263350289186476,"pool_token_amount":26995973405572351}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":27243418147426284,"pool_token_amount":26994154718801895}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":27233191123406411,"pool_token_amount":26994939341432652}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":27206714979924658,"pool_token_amount":26993788264066668}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":27175572266624339,"pool_token_amount":26993458712542982}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":27157420374076683,"pool_token_amount":26993313158001845}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":27146050475160166,"pool_token_amount":26996329491435200}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":27142076228456426,"pool_token_amount":26995958435863162}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":27123249456097021,"pool_token_amount":26991957563722292}],[50,{"iota_amount":27120302918282739,"pool_token_amount":26992708230940279}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"iota_amount":27109322672932486,"pool_token_amount":26992830633733852}],[45,{"iota_amount":27101065881785060,"pool_token_amount":26991978870030775}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":27089913931250442,"pool_token_amount":26991929803709525}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":27068327488534391,"pool_token_amount":26992772771809520}],[35,{"iota_amount":27063894195705282,"pool_token_amount":26992341903812665}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":27050395123396914,"pool_token_amount":26991159369103250}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":27038083147476398,"pool_token_amount":26991255765256061}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":27034053793249757,"pool_token_amount":26991440755232235}],[27,{"iota_amount":27029515518592186,"pool_token_amount":26991406809668803}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":20000000000527000,"pool_token_amount":20000000000052693}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":20000000000449600,"pool_token_amount":20000000000044955}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":20000000000449600,"pool_token_amount":20000000000044955}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":20000000000449600,"pool_token_amount":20000000000044955}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":20000000000441000,"pool_token_amount":20000000000044097}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"HashQuark":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":27584339390695727,"pool_token_amount":27045526082924395}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":27577122065909678,"pool_token_amount":27044818405872704}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":27555295421496316,"pool_token_amount":27042696084489513}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":27529182221904269,"pool_token_amount":27039999786870388}],[148,{"iota_amount":27518070491058708,"pool_token_amount":27038922438198313}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":27514359942656420,"pool_token_amount":27038558747744807}],[145,{"iota_amount":27507034356508894,"pool_token_amount":27037838812869941}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":27470964197507322,"pool_token_amount":27034342704056893}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":27447387540228726,"pool_token_amount":27033551338016299}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":27423100453843110,"pool_token_amount":27032044725413751}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":27419489828976745,"pool_token_amount":27031688811342289}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":27405045324997703,"pool_token_amount":27030261876194760}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":27393635191949598,"pool_token_amount":27031827431230405}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":27378388134900034,"pool_token_amount":27030325277194999}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":27374262991324440,"pool_token_amount":27029918006762803}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":27365838601043554,"pool_token_amount":27029086099288717}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":27361659974184341,"pool_token_amount":27028673374479649}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":27353194008729705,"pool_token_amount":27027839695838602}],[97,{"iota_amount":27332353359224401,"pool_token_amount":27025780736528803}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":27311533296119395,"pool_token_amount":27023720623049603}],[91,{"iota_amount":27307480233285638,"pool_token_amount":27023322285442151}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":27282259477714264,"pool_token_amount":27019935783286764}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":27270235628391594,"pool_token_amount":27018741682208525}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":27262349888093996,"pool_token_amount":27018272633383940}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":27258342600759624,"pool_token_amount":27017874600348146}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":27254340024918160,"pool_token_amount":27017477873742996}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":27241977926897295,"pool_token_amount":27015933695698477}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":27233864243715337,"pool_token_amount":27015129005891963}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":27212519069856259,"pool_token_amount":27013008221130627}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":27171416736003391,"pool_token_amount":27008842508889411}],[57,{"iota_amount":27167391853389081,"pool_token_amount":27008420959531017}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":27159389258663801,"pool_token_amount":27007625349524305}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":27155272996969054,"pool_token_amount":27007212444826048}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":27141874516661961,"pool_token_amount":27004930201073228}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"iota_amount":27125418188666850,"pool_token_amount":27003285370754058}],[45,{"iota_amount":27117692534004072,"pool_token_amount":27002962599976241}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":27113527590475142,"pool_token_amount":27002500279921431}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":27078261796052896,"pool_token_amount":27001076037915242}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":27068917001028875,"pool_token_amount":26999938606429077}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":27058607333487426,"pool_token_amount":27003030163185747}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":27056244904866752,"pool_token_amount":27009824683347126}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":20000000025418301,"pool_token_amount":20000000000508352}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":20000000015327401,"pool_token_amount":20000000000306536}],[16,{"iota_amount":20000000007028393,"pool_token_amount":20000000000140558}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":20000000000485900,"pool_token_amount":20000000000009712}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":20000000000438600,"pool_token_amount":20000000000008771}],[1,{"iota_amount":20000000000000000,"pool_token_amount":20000000000000000}]],"HashedPotatoes":[[167,{"iota_amount":130557842427601670,"pool_token_amount":127774977072322661}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":130540599168053117,"pool_token_amount":127774470800426095}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":130490434738237381,"pool_token_amount":127774477951986871}],[161,{"iota_amount":130457540905298790,"pool_token_amount":127774999618288570}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":130241380268773155,"pool_token_amount":127697651789898346}],[148,{"iota_amount":130084818506381742,"pool_token_amount":127628413075113258}],[146,{"iota_amount":130049924409814482,"pool_token_amount":127627782950215028}],[145,{"iota_amount":130033664425228507,"pool_token_amount":127628548764085271}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":129980893530669239,"pool_token_amount":127626897630040787}],[141,{"iota_amount":129963838178414911,"pool_token_amount":127626869610727397}],[138,{"iota_amount":129913260504066092,"pool_token_amount":127627384635473391}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":129863761530074859,"pool_token_amount":127628993204915884}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":129846199034273535,"pool_token_amount":127628475396268885}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[130,{"iota_amount":129778135849353840,"pool_token_amount":127628575523769641}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":129760554579365501,"pool_token_amount":127628056821182031}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":129625587529387654,"pool_token_amount":127528834812488938}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[122,{"iota_amount":129537699835082291,"pool_token_amount":127525673520872115}],[121,{"iota_amount":129520078476024586,"pool_token_amount":127524996363106389}],[120,{"iota_amount":129502526828963194,"pool_token_amount":127524477924083613}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":129485480517095677,"pool_token_amount":127524458028006618}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":129467928478667331,"pool_token_amount":127523939441087435}],[117,{"iota_amount":129450379563205289,"pool_token_amount":127523420878280317}],[116,{"iota_amount":129434085473408630,"pool_token_amount":127524137858532092}],[114,{"iota_amount":129398857148361510,"pool_token_amount":127522972312046502}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[110,{"iota_amount":129333380314058782,"pool_token_amount":127525562034877835}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[100,{"iota_amount":129145095508118739,"pool_token_amount":127531487239712885}],[98,{"iota_amount":129104004817310348,"pool_token_amount":127529313875111511}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":129007618940952807,"pool_token_amount":127529414524941091}],[91,{"iota_amount":128968717638287702,"pool_token_amount":127528600070273964}],[88,{"iota_amount":128904295467414258,"pool_token_amount":127521125372399040}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":128884780022582452,"pool_token_amount":127520549215608296}],[85,{"iota_amount":128845777058247299,"pool_token_amount":127519322331517070}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":128640457961715592,"pool_token_amount":127521366486070054}],[72,{"iota_amount":128600170410012772,"pool_token_amount":127520222556593651}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[68,{"iota_amount":128525720351900896,"pool_token_amount":127525305528901313}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":128253143218349294,"pool_token_amount":127519479426653916}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":128171066650086595,"pool_token_amount":127513335737732617}],[49,{"iota_amount":128151571465152672,"pool_token_amount":127512816628775851}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[42,{"iota_amount":127223818889977427,"pool_token_amount":126721134170399022}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":127103711090611124,"pool_token_amount":126716636049287833}],[35,{"iota_amount":117092034728337755,"pool_token_amount":116754259532480528}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[30,{"iota_amount":116988867212019885,"pool_token_amount":116747758846326601}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"iota_amount":88478735265669778,"pool_token_amount":88359670681293343}],[25,{"iota_amount":88459954555207252,"pool_token_amount":88359014054772290}],[24,{"iota_amount":86676843435024461,"pool_token_amount":86596470812715472}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":83835661161998830,"pool_token_amount":83796871811254358}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":80000000001754400,"pool_token_amount":80000000000035087}],[1,{"iota_amount":80000000000000000,"pool_token_amount":80000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Imperator.co":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":35721802088453064,"pool_token_amount":35021896243074698}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":35717091400296320,"pool_token_amount":35021526771482918}],[161,{"iota_amount":35712485744143645,"pool_token_amount":35021165494148675}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":35688149062808508,"pool_token_amount":35018823217866004}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":35663826454004482,"pool_token_amount":35016675611831847}],[150,{"iota_amount":35659019831911417,"pool_token_amount":35016302640769673}],[149,{"iota_amount":35656152866872329,"pool_token_amount":35017835029267002}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":35646024696964571,"pool_token_amount":35016586564201296}],[145,{"iota_amount":35636540118280372,"pool_token_amount":35015885251108976}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":35630744136620430,"pool_token_amount":35023252194233938}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":35619844906704336,"pool_token_amount":35025421582077879}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":35599939217262857,"pool_token_amount":35022924850003715}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":35594385128715362,"pool_token_amount":35026091110862680}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":35570560563984412,"pool_token_amount":35024192804028554}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":35565886493955930,"pool_token_amount":35023864624863013}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":35543491740104567,"pool_token_amount":35023173599247169}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":35538667578358449,"pool_token_amount":35026968863676840}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":35530141956265225,"pool_token_amount":35027115058822499}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":35514151099599560,"pool_token_amount":35024447037869223}],[114,{"iota_amount":35509437956957944,"pool_token_amount":35024075185229755}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":35480785555379158,"pool_token_amount":35022637799040818}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":35458917027415867,"pool_token_amount":35021032739062247}],[101,{"iota_amount":35442489922156353,"pool_token_amount":35019737873706075}],[99,{"iota_amount":35431712349172407,"pool_token_amount":35018885887847740}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":35415728606820556,"pool_token_amount":35017792177789475}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":35361399912124527,"pool_token_amount":35012424052801463}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":35340127926374308,"pool_token_amount":35010536647216213}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":35323421325482242,"pool_token_amount":35008491026316986}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":35315194798961599,"pool_token_amount":35009868969597405}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":35285644961127017,"pool_token_amount":35010173001530498}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":35265071364752478,"pool_token_amount":35010053713520794}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":35242880347469237,"pool_token_amount":35012790769018021}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":35223203032261194,"pool_token_amount":35012746419621431}],[56,{"iota_amount":35212524374377810,"pool_token_amount":35011888946551286}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":35204534370774014,"pool_token_amount":35008824705870293}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":35178643396717086,"pool_token_amount":35007481498947437}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":35173294798197324,"pool_token_amount":35007042875620268}],[46,{"iota_amount":35165732752791722,"pool_token_amount":35014173058756113}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":35094243074800592,"pool_token_amount":35008794028196864}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":35087242259963465,"pool_token_amount":35007227025863986}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":35076061272097820,"pool_token_amount":35006989626794125}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"iota_amount":25046991626220558,"pool_token_amount":25014580852377278}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":25024577933511914,"pool_token_amount":25007293593432911}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":25000000019248364,"pool_token_amount":25000000000384956}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":25000000000572400,"pool_token_amount":25000000000011444}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":25000000000556200,"pool_token_amount":25000000000011122}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"InfStones":[[167,{"iota_amount":27585923008343310,"pool_token_amount":27048243974445277}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":27582313953676653,"pool_token_amount":27047890103028430}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":27567887968996165,"pool_token_amount":27046482311441912}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":27560684888657346,"pool_token_amount":27045784517946125}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":27542245610994133,"pool_token_amount":27044067430100644}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":27534304908944516,"pool_token_amount":27042826093103557}],[150,{"iota_amount":27523094674363220,"pool_token_amount":27041651826645344}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":27497065350079298,"pool_token_amount":27035590897013279}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":27475395863964137,"pool_token_amount":27033459682712452}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":27465549815580439,"pool_token_amount":27033375535497738}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":27457588555905088,"pool_token_amount":27031940716713989}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":27450157573019721,"pool_token_amount":27031029367815716}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":27439323942776406,"pool_token_amount":27029974981087125}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":27414052700987037,"pool_token_amount":27027498180512796}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":27410442076120672,"pool_token_amount":27027142208856486}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":27396110133858122,"pool_token_amount":27025826079693872}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":27389145709991175,"pool_token_amount":27025366152839520}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":27378347677208491,"pool_token_amount":27024330081747657}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":27374838712886973,"pool_token_amount":27024075099777728}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":27366835887606697,"pool_token_amount":27023307246746105}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":27362519746889691,"pool_token_amount":27022711310710498}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":27354089764623168,"pool_token_amount":27021873744960050}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":27345801537389407,"pool_token_amount":27021125988143623}],[99,{"iota_amount":27329272887906381,"pool_token_amount":27019521840625265}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":27312699641903439,"pool_token_amount":27017907191080417}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":27296219031074870,"pool_token_amount":27016283752228417}],[90,{"iota_amount":27292174250428405,"pool_token_amount":27015884314910346}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":27268350358397648,"pool_token_amount":27013845127480386}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":27264375033245508,"pool_token_amount":27013479310998602}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":27256718237080685,"pool_token_amount":27013038766739749}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":27252478792628987,"pool_token_amount":27012609692832604}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":27224408518954837,"pool_token_amount":27021186773553930}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":27142768749228686,"pool_token_amount":27013615985615512}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":27138646662868620,"pool_token_amount":27013196781201883}],[48,{"iota_amount":27134534657711255,"pool_token_amount":27012787936288320}],[45,{"iota_amount":27122239457980975,"pool_token_amount":27011600164260913}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":27113957196175031,"pool_token_amount":27010722885973152}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":27105758279645454,"pool_token_amount":27009929442176529}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"iota_amount":27101675906840736,"pool_token_amount":27009549590435460}],[39,{"iota_amount":27097561487443432,"pool_token_amount":27009137753217744}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":27093446367041789,"pool_token_amount":27008726686933403}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":27071668389919846,"pool_token_amount":27006785076817543}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":20000000025396901,"pool_token_amount":20000000000507924}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":20000000015774701,"pool_token_amount":20000000000315481}],[16,{"iota_amount":20000000007017893,"pool_token_amount":20000000000140348}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":20000000000445300,"pool_token_amount":20000000000008902}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":20000000000441000,"pool_token_amount":20000000000008817}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Juicy Stake":[[167,{"iota_amount":44298253330197315,"pool_token_amount":43409073870845232}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":44270752143795229,"pool_token_amount":43409073602080747}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":44252955510071905,"pool_token_amount":43407888770903965}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":44241768789992107,"pool_token_amount":43407888849001502}],[156,{"iota_amount":44236182904250937,"pool_token_amount":43407895807574124}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":44224802533338675,"pool_token_amount":43407889087045168}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":44213300949142295,"pool_token_amount":43407672980138513}],[150,{"iota_amount":44201884101697189,"pool_token_amount":43407630894546088}],[148,{"iota_amount":44190688991312816,"pool_token_amount":43407624347750799}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":44168058965715120,"pool_token_amount":43407396581373460}],[143,{"iota_amount":44162462245067219,"pool_token_amount":43407396573714025}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":44112062246122329,"pool_token_amount":43407397411683743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":44083884267620089,"pool_token_amount":43407235128422899}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":44055441498673269,"pool_token_amount":43406802411583027}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":44043711529093867,"pool_token_amount":43406278338827790}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":44004894193714422,"pool_token_amount":43406631291103983}],[114,{"iota_amount":43999289623265375,"pool_token_amount":43406622498300499}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[103,{"iota_amount":43932631932569954,"pool_token_amount":43406762093994583}],[102,{"iota_amount":43926177582336617,"pool_token_amount":43406761720731562}],[99,{"iota_amount":43906939435416152,"pool_token_amount":43406740804282871}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":43887972530546628,"pool_token_amount":43406732593018539}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":43852369720234434,"pool_token_amount":43407059386871873}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":43840724774462430,"pool_token_amount":43407071954171689}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":43834804601837643,"pool_token_amount":43407074747603031}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":43805352695436091,"pool_token_amount":43407066845288230}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":43787281212849481,"pool_token_amount":43406725528327826}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":43757343182008108,"pool_token_amount":43406139734873914}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":43696187824423912,"pool_token_amount":43406115243350595}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":43684649441635407,"pool_token_amount":43406311905060368}],[61,{"iota_amount":43679491095902386,"pool_token_amount":43407017432264449}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":43648937363981075,"pool_token_amount":43405812958332984}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":43585672078299269,"pool_token_amount":43407524900324861}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":43579433671385672,"pool_token_amount":43407421419211946}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":43566858008535219,"pool_token_amount":43407218810605913}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":43534937506792891,"pool_token_amount":43406500458933035}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":27055012063530254,"pool_token_amount":26995269015724549}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":27046582618768200,"pool_token_amount":26995044040031765}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":27042229197357008,"pool_token_amount":26994895519663056}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"iota_amount":20029513993995886,"pool_token_amount":20004501126099622}],[25,{"iota_amount":20024962137832010,"pool_token_amount":20003753756616914}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":20011406311485771,"pool_token_amount":20002620042905490}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":20000000015785201,"pool_token_amount":20000000000315691}],[16,{"iota_amount":20000000007028393,"pool_token_amount":20000000000140558}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":20000000000455800,"pool_token_amount":20000000000009112}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":20000000000442900,"pool_token_amount":20000000000008856}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":20000000000000000,"pool_token_amount":20000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"KiligLab":[[167,{"iota_amount":45891858260305156,"pool_token_amount":44978998755003397}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":45889008902946022,"pool_token_amount":44986995711280461}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":45882693580435177,"pool_token_amount":44986200130459935}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":45864360837934499,"pool_token_amount":44984405153987777}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":45858246003087478,"pool_token_amount":44983805402087669}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":45845615161714123,"pool_token_amount":44982566325314073}],[157,{"iota_amount":45839320076814572,"pool_token_amount":44981966382760110}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":45826682570037257,"pool_token_amount":44980719124777067}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[149,{"iota_amount":45798530157417132,"pool_token_amount":44986565295468654}],[145,{"iota_amount":45773795853794426,"pool_token_amount":44984174222095251}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":45748943140640406,"pool_token_amount":44981754404234857}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":45717763158014418,"pool_token_amount":44978634846467979}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":45720848517158409,"pool_token_amount":44987180523973928}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":45671049965011799,"pool_token_amount":44982279566331907}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":45646199912545629,"pool_token_amount":44979860881987182}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":45631874808670059,"pool_token_amount":44987812544853877}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":45625656371933204,"pool_token_amount":44987199477708071}],[117,{"iota_amount":45619439041636130,"pool_token_amount":44986586444481092}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":45594544327905006,"pool_token_amount":44984108876259851}],[112,{"iota_amount":45588325310813907,"pool_token_amount":44983494412449917}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":45575885986085031,"pool_token_amount":44982266020408023}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":45562046261705942,"pool_token_amount":44980887546800181}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":45533597725814349,"pool_token_amount":44978053506040356}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":45528165663263604,"pool_token_amount":44985478762630142}],[101,{"iota_amount":45521031911493030,"pool_token_amount":44984774780435579}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":45446948720988939,"pool_token_amount":44973887882232948}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":45415628578274036,"pool_token_amount":44980048098618786}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":45394926865699806,"pool_token_amount":44977997501706888}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":45360105208176796,"pool_token_amount":44974448001842490}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":45329264438044661,"pool_token_amount":44981460059082168}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":45307473711381475,"pool_token_amount":44979295608014878}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":45292804690352264,"pool_token_amount":44977839225093810}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":45254372959861889,"pool_token_amount":44983188761052699}],[58,{"iota_amount":45247472390515630,"pool_token_amount":44982493893171214}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":45206476910464549,"pool_token_amount":44978433099240215}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":45179238850656564,"pool_token_amount":44975714357443124}],[45,{"iota_amount":45158802354818683,"pool_token_amount":44973889411748608}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":45149010984015784,"pool_token_amount":44982770234936920}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":45106393278005786,"pool_token_amount":44978520876021449}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":45083649385109576,"pool_token_amount":44976292129358451}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":45068258196515068,"pool_token_amount":44974723340602668}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":45057522654885279,"pool_token_amount":44977993270604737}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":45049617420409517,"pool_token_amount":44977214034394033}],[26,{"iota_amount":25036109499423111,"pool_token_amount":25004589769410312}],[25,{"iota_amount":25030883517696156,"pool_token_amount":25004068740176551}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":25000000000691200,"pool_token_amount":25000000000013816}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":25000000000556200,"pool_token_amount":25000000000011122}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":25000000000550800,"pool_token_amount":25000000000011015}]],"Kiln":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":68092362944260716,"pool_token_amount":66744507887485992}],[165,{"iota_amount":68083342240313707,"pool_token_amount":66743623672785197}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":68084749784775352,"pool_token_amount":66769952661699251}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":68066716831307359,"pool_token_amount":66768184084167207}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":38061436208126394,"pool_token_amount":37339927039920280}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"iota_amount":38003974845759561,"pool_token_amount":37334090712704391}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":37987374400357540,"pool_token_amount":37331533162838468}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":37982154499274411,"pool_token_amount":37331020184131221}],[143,{"iota_amount":37976938973782594,"pool_token_amount":37330507572172712}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":37971724205310598,"pool_token_amount":37329994971295040}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":37943586498833499,"pool_token_amount":37334131722175332}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":37933784089975103,"pool_token_amount":37333641186278615}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":29925788356288799,"pool_token_amount":29459452116764855}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":39943721330147832,"pool_token_amount":39337301790329134}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":39938299839843535,"pool_token_amount":39336767168247251}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":39900471704410535,"pool_token_amount":39333125846965452}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":39895166483541688,"pool_token_amount":39332701375389752}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":39867165218258917,"pool_token_amount":39329118888224818}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":39852665007213907,"pool_token_amount":39334052474409869}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":39827972442425321,"pool_token_amount":39331213189292993}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":39821684814769959,"pool_token_amount":39330591379943740}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":39815417882011095,"pool_token_amount":39329973304731433}],[103,{"iota_amount":39827278127086468,"pool_token_amount":39347278476136704}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":38980281642335700,"pool_token_amount":38558897742072399}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":38956275670406692,"pool_token_amount":38556426444199514}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":34962444923840285,"pool_token_amount":34608290724224941}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":34944301701941623,"pool_token_amount":34613755770860622}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":36570386116772559,"pool_token_amount":36275224840498945}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":36564717881061061,"pool_token_amount":36274662591780693}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":36552592981990906,"pool_token_amount":36273152491334687}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":36529003260622861,"pool_token_amount":36270789338347867}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":36523112481209079,"pool_token_amount":36270203530802035}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":36602146132623738,"pool_token_amount":36368909038540045}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":36593111333518516,"pool_token_amount":36374842460118566}],[56,{"iota_amount":36568351190401405,"pool_token_amount":36365144176084912}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":35524197994233215,"pool_token_amount":35364883931745005}],[47,{"iota_amount":35518863676874555,"pool_token_amount":35364352892267574}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"iota_amount":35988430580944185,"pool_token_amount":35861341657942680}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":30965723835787095,"pool_token_amount":30877930252642800}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":30948966153639107,"pool_token_amount":30875186172977120}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":30943708820539110,"pool_token_amount":30874640702364577}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":29282809216264338,"pool_token_amount":29230727372647571}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"iota_amount":21760237236095525,"pool_token_amount":21736531128789764}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":20000000000527000,"pool_token_amount":20000000000010533}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":20000000000428400,"pool_token_amount":20000000000008567}],[0,{"iota_amount":0,"pool_token_amount":0}]],"KingSuper":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":35700011785373341,"pool_token_amount":35001990637668625}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":35679918180059372,"pool_token_amount":34999008837479320}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":35670295217276519,"pool_token_amount":34998159245806681}],[156,{"iota_amount":35665484099536562,"pool_token_amount":34997734403865260}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":35660659735710728,"pool_token_amount":34997296731403765}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":35614539377593803,"pool_token_amount":34999149959295867}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":35590666546683225,"pool_token_amount":34997038011982875}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":35585947773233470,"pool_token_amount":34996620405312062}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":35576364884927390,"pool_token_amount":34995646028481313}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":35552579811823822,"pool_token_amount":34993542706649068}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":35584320235156034,"pool_token_amount":35050347825019472}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":35579495989645478,"pool_token_amount":35049912986996972}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":35574680092477499,"pool_token_amount":35049486007213264}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":35565114914492874,"pool_token_amount":35048698249304797}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":35560403068840825,"pool_token_amount":35048282157148367}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":35555688936409735,"pool_token_amount":35047863994975958}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":35550974960074405,"pool_token_amount":35047445796210260}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":35497059120626255,"pool_token_amount":35038436839726964}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":35486220740709595,"pool_token_amount":35037478415435652}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":35480432623382144,"pool_token_amount":35036784369236054}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":35469279155843067,"pool_token_amount":35035796662704747}],[101,{"iota_amount":35458430472756772,"pool_token_amount":35034828551742043}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":35417951734650529,"pool_token_amount":35034287393707866}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":35412621894888169,"pool_token_amount":35033845608239350}],[91,{"iota_amount":35407326441305730,"pool_token_amount":35033426502517792}],[90,{"iota_amount":35402039449138008,"pool_token_amount":35033003459906483}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":35365821390969013,"pool_token_amount":35026413673105283}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":35321254869558539,"pool_token_amount":35021299167035107}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":35316418665245273,"pool_token_amount":35021370483027896}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":35300078515380193,"pool_token_amount":35020072182926538}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":35294515412572888,"pool_token_amount":35019625188680572}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":35289552361141034,"pool_token_amount":35019775431725579}],[69,{"iota_amount":35283991012969136,"pool_token_amount":35019332099095075}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":35255885092625066,"pool_token_amount":35011730396593624}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":35250550714761084,"pool_token_amount":35011306601698699}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":35244965971836230,"pool_token_amount":35010634415534648}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":35207736377920710,"pool_token_amount":35007778404207118}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":35191748022493328,"pool_token_amount":35006522044644930}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"iota_amount":35158698650613196,"pool_token_amount":35002938460320905}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":35129542246156355,"pool_token_amount":34998340191651267}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"iota_amount":35118630306539844,"pool_token_amount":34997350812738874}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":35096602900833656,"pool_token_amount":34995506340741075}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":35061377465698240,"pool_token_amount":34992818882254452}],[29,{"iota_amount":35055129975064124,"pool_token_amount":34992098773840095}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":25005936738205152,"pool_token_amount":25000164266835462}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Laine":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":27849627234575506,"pool_token_amount":27329538102523327}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":27846018479414373,"pool_token_amount":27329183965957895}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":27838600365871978,"pool_token_amount":27328455878549114}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":27827474141879584,"pool_token_amount":27327363512891423}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":27819764977139917,"pool_token_amount":27326349391322045}],[151,{"iota_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":27800031609628709,"pool_token_amount":27326642767473194}],[145,{"iota_amount":27792605640234784,"pool_token_amount":27325912770711633}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":27782582092804442,"pool_token_amount":27325911389800786}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":27786679166701418,"pool_token_amount":27333227290508963}],[140,{"iota_amount":27782967570647102,"pool_token_amount":27332862187388367}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":27771873656344363,"pool_token_amount":27331815289194064}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":27768157973877504,"pool_token_amount":27331449608016211}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":27753308840273646,"pool_token_amount":27329992274132020}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":27723625880896407,"pool_token_amount":27327096734806734}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":27715700671639335,"pool_token_amount":27325871881175947}],[120,{"iota_amount":27709188362207194,"pool_token_amount":27326038155469354}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":33514374482542776,"pool_token_amount":33055798842098896}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":33503567843795481,"pool_token_amount":33057158466890397}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":33499244436343006,"pool_token_amount":33056900007956366}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":33486183167549064,"pool_token_amount":33056035053656379}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":33482623431897005,"pool_token_amount":33056530731034440}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":33478084667698088,"pool_token_amount":33056061305009295}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":33470482686835669,"pool_token_amount":33057473013794943}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":33451584501243393,"pool_token_amount":33057144045139436}],[99,{"iota_amount":33428848021701014,"pool_token_amount":33057746087376733}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":33405469068265209,"pool_token_amount":33056973769373269}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":33400333657810561,"pool_token_amount":33056316925992262}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":33392131873000627,"pool_token_amount":33056845120418841}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":33381422421684720,"pool_token_amount":33059158412207548}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":33376486684742923,"pool_token_amount":33058571841329799}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":33367247814252812,"pool_token_amount":33058001791136097}],[84,{"iota_amount":33363533407801976,"pool_token_amount":33058591532147315}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":33351142269838022,"pool_token_amount":33059221162010250}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[75,{"iota_amount":33323845540249518,"pool_token_amount":33057967309149189}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":33316077782602017,"pool_token_amount":33058994288667370}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"iota_amount":33276925506416017,"pool_token_amount":33060910149139874}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":33244618925582827,"pool_token_amount":33059033057145344}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"iota_amount":27111810280705155,"pool_token_amount":26999998757379517}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":27099940107438272,"pool_token_amount":26998988072044059}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"iota_amount":27089007273884930,"pool_token_amount":26998912553792797}],[39,{"iota_amount":27085387548947100,"pool_token_amount":26998911826311862}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":27082290207787903,"pool_token_amount":26999433376534695}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":27077930796406896,"pool_token_amount":26998797913434555}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":27041066771050932,"pool_token_amount":26997876361028829}],[26,{"iota_amount":20034545124314116,"pool_token_amount":20009321562600132}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":20000000025396901,"pool_token_amount":20000000000507924}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":20000000015774701,"pool_token_amount":20000000000315481}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":20000000000475400,"pool_token_amount":20000000000009502}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":20000000000445300,"pool_token_amount":20000000000008902}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Latitude.sh":[[167,{"iota_amount":26509070831423817,"pool_token_amount":25989689838865610}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":26505662279770129,"pool_token_amount":25989355661548818}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":26498847955531754,"pool_token_amount":25988689262208225}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":26495359916392142,"pool_token_amount":25988276559299335}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":26491952184426506,"pool_token_amount":25987942307671872}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":26485135144942421,"pool_token_amount":25987269481517081}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":26484434320982063,"pool_token_amount":25989680720990836}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":26480755990558421,"pool_token_amount":25989169617217715}],[156,{"iota_amount":26473739470255868,"pool_token_amount":25988480948779087}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":26447982545543300,"pool_token_amount":25991099625080355}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":26427030850173270,"pool_token_amount":25989143865833310}],[140,{"iota_amount":26423519880903216,"pool_token_amount":25988798585981133}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":26420008335090361,"pool_token_amount":25988453208116423}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":26407020892273870,"pool_token_amount":25991234905142344}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":26392966336543077,"pool_token_amount":25989851328241447}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":26389450082018461,"pool_token_amount":25989505072783709}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":26361250419539814,"pool_token_amount":25992867373795923}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":26359866837697053,"pool_token_amount":25994618594609530}],[117,{"iota_amount":91735889242077333,"pool_token_amount":39881683429017994}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":26349970698786360,"pool_token_amount":25997321055826039}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":26331146925739238,"pool_token_amount":25998148715490680}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":26327244762873680,"pool_token_amount":25997763433703630}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[101,{"iota_amount":26309800324036249,"pool_token_amount":26001646086682463}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":26288035129314738,"pool_token_amount":26000960021254616}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":26279316363398754,"pool_token_amount":26002667360610815}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":26271460763759915,"pool_token_amount":26005176798501219}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":26267533324510600,"pool_token_amount":26004710282326290}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":26250380390803722,"pool_token_amount":26004760392810069}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":26251855854719124,"pool_token_amount":26013016210616327}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":26244427986293075,"pool_token_amount":26012546289351818}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":26231229252176981,"pool_token_amount":26006252780921124}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":26197127018320811,"pool_token_amount":26011225663451224}],[64,{"iota_amount":26189206787522249,"pool_token_amount":26010352986292317}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":26185317877081008,"pool_token_amount":26009890383662064}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":26166177079244200,"pool_token_amount":26011279808720983}],[56,{"iota_amount":26162291889630366,"pool_token_amount":26010820742008980}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":26147160159787446,"pool_token_amount":26009390766892407}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":26141174039987063,"pool_token_amount":26010246347065036}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":26137276228565123,"pool_token_amount":26009851354192931}],[48,{"iota_amount":26133437216266681,"pool_token_amount":26009515166476164}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":26132839292851846,"pool_token_amount":26029938211449149}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":26081111534099511,"pool_token_amount":26019382325951462}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":26072047980030809,"pool_token_amount":26018228276678392}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":26039577625617673,"pool_token_amount":25994222959179611}],[26,{"iota_amount":50072342562650958,"pool_token_amount":50007853545577582}],[25,{"iota_amount":50067275141967916,"pool_token_amount":50012290668024540}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":30038474872136477,"pool_token_amount":30017992831062200}],[22,{"iota_amount":30030681280478123,"pool_token_amount":30016716320129205}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":30009102717457676,"pool_token_amount":30002131759037633}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":30000000015600000,"pool_token_amount":30000000000311998}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":30000000000708500,"pool_token_amount":30000000000014169}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Luganodes":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":96329527998020117,"pool_token_amount":41644204951793117}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":56165165021692366,"pool_token_amount":24292548120612612}],[157,{"iota_amount":56133766379699994,"pool_token_amount":24281972251683936}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":56164461678878119,"pool_token_amount":24307275222852175}],[152,{"iota_amount":56087476777549264,"pool_token_amount":24276965327300506}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"iota_amount":60577452505114017,"pool_token_amount":26236842628119062}],[146,{"iota_amount":61028024757043826,"pool_token_amount":26435261896804474}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":60948493143585976,"pool_token_amount":26416896265984412}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":91751962059697911,"pool_token_amount":39883805121777235}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":91065346618394553,"pool_token_amount":39599820736424146}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":90853781868271072,"pool_token_amount":39531943192078969}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":90592941540681178,"pool_token_amount":39456929245771835}],[102,{"iota_amount":90550852084750085,"pool_token_amount":39444175030853695}],[101,{"iota_amount":90533676868699085,"pool_token_amount":39442243526737071}],[100,{"iota_amount":72314789716618414,"pool_token_amount":31509342874047423}],[99,{"iota_amount":72286345940688156,"pool_token_amount":31501355614297751}],[98,{"iota_amount":71544830309771065,"pool_token_amount":31182574757908908}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":71865033943422279,"pool_token_amount":31335208017305475}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":57225361915554973,"pool_token_amount":24962238505752810}],[91,{"iota_amount":57198594009202988,"pool_token_amount":24953968704899441}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":56134737346669942,"pool_token_amount":24509909200651398}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":56078491158587159,"pool_token_amount":24492000195313410}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":55903534227070337,"pool_token_amount":24435659206860652}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":54994200746248848,"pool_token_amount":24068706805022661}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":51750233583129534,"pool_token_amount":22665000810403999}],[62,{"iota_amount":51827902612488554,"pool_token_amount":22702134927584654}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":51704737391863522,"pool_token_amount":22657467429128359}],[58,{"iota_amount":51641004987674724,"pool_token_amount":22632610654026878}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":51701912027185925,"pool_token_amount":22671719669662475}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":50911749863394918,"pool_token_amount":22340389803748236}],[48,{"iota_amount":50877824927525009,"pool_token_amount":22328576079481569}],[47,{"iota_amount":50870138248218154,"pool_token_amount":22328275305306473}],[46,{"iota_amount":50862143481529370,"pool_token_amount":22327839403634026}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"iota_amount":50743565089263543,"pool_token_amount":22294347438376725}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":50711252482838312,"pool_token_amount":22293532425396754}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":30139769709059235,"pool_token_amount":13267207670651649}],[27,{"iota_amount":30127673471947111,"pool_token_amount":13264086030984455}],[26,{"iota_amount":80113503978686921,"pool_token_amount":80012028484843096}],[25,{"iota_amount":80095591658132118,"pool_token_amount":80009433428161240}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":80058393469495627,"pool_token_amount":80005382967023720}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":80000000063865408,"pool_token_amount":80000000001277295}],[18,{"iota_amount":80000000062001508,"pool_token_amount":80000000001240018}],[17,{"iota_amount":80000000049908508,"pool_token_amount":80000000000998159}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":80000000001754400,"pool_token_amount":80000000000035087}],[1,{"iota_amount":80000000000000000,"pool_token_amount":80000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"MIDL.dev":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":26514232620390599,"pool_token_amount":25996809920720965}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":26480352143627837,"pool_token_amount":25994120017629535}],[154,{"iota_amount":26477192639999892,"pool_token_amount":25994120073590468}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"iota_amount":26464579199632539,"pool_token_amount":25994144680646862}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":26449123513780896,"pool_token_amount":25994489649935088}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":26436826410566017,"pool_token_amount":25994833726627147}],[140,{"iota_amount":26433316443456150,"pool_token_amount":25994491210803470}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":26423823723192198,"pool_token_amount":25994491614978846}],[136,{"iota_amount":26420308888389368,"pool_token_amount":25994147570631742}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":26391766916318452,"pool_token_amount":25978515302287705}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":26385788139283380,"pool_token_amount":25978859912086283}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":26374016091909378,"pool_token_amount":25976619050037459}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":26370504060091888,"pool_token_amount":25976274867807975}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":26354662648784385,"pool_token_amount":25976245401412092}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":26352200252059464,"pool_token_amount":25976934148415455}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":26342018745661308,"pool_token_amount":25976245498705601}],[116,{"iota_amount":26338909714122390,"pool_token_amount":25976296228961696}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":26318375970249814,"pool_token_amount":25978216293027503}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":26296772473658692,"pool_token_amount":25978241938263774}],[102,{"iota_amount":26294322773535058,"pool_token_amount":25979423329565457}],[100,{"iota_amount":26286280910946865,"pool_token_amount":25978633580178512}],[99,{"iota_amount":26282270237614104,"pool_token_amount":25978239186527028}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":26268324026041109,"pool_token_amount":25978623898393372}],[94,{"iota_amount":26264361519067700,"pool_token_amount":25978233976142718}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":26253757508136959,"pool_token_amount":25981804209575796}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":26232198711789899,"pool_token_amount":25981421294997121}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":26230262517415663,"pool_token_amount":25982978146115750}],[82,{"iota_amount":26226366946939410,"pool_token_amount":25982594190959446}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":26218463912443682,"pool_token_amount":25981814202924227}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":26193472412256981,"pool_token_amount":25981454299808908}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":26189064620869205,"pool_token_amount":25984428848146025}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":26175155863343554,"pool_token_amount":25981653581630382}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":26164728530927334,"pool_token_amount":25978653634440603}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":26153771831154259,"pool_token_amount":25978407049933342}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":26139711324806961,"pool_token_amount":25978358605054394}],[57,{"iota_amount":26132695845126980,"pool_token_amount":25978348807157569}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":26119021156186849,"pool_token_amount":25978684953983421}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":26104862152283013,"pool_token_amount":25982024978345426}],[45,{"iota_amount":26092693289041643,"pool_token_amount":25980371592420231}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":26065279909004945,"pool_token_amount":25977990554869562}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":26058014445576270,"pool_token_amount":25978053553023385}],[35,{"iota_amount":26054221044565932,"pool_token_amount":25978063455607839}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":26036568438339148,"pool_token_amount":25976039682707869}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":26023895321856219,"pool_token_amount":25975288338923823}],[27,{"iota_amount":26020115879173464,"pool_token_amount":25975812086636136}],[26,{"iota_amount":50048539506516356,"pool_token_amount":49986060172559477}],[24,{"iota_amount":50026808049006233,"pool_token_amount":49983749030288053}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":30007112717457676,"pool_token_amount":30000711120006228}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":30000000015600000,"pool_token_amount":30000000001559998}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":30000000000708500,"pool_token_amount":30000000000070849}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Moonlet":[[167,{"iota_amount":27619444183493069,"pool_token_amount":27086509728333933}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":27612226847010355,"pool_token_amount":27085801878635158}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":27604657242034010,"pool_token_amount":27084748502772909}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":27593835873508812,"pool_token_amount":27083686621202142}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":27589923566390251,"pool_token_amount":27083123300816787}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":27578797295695347,"pool_token_amount":27082030978343047}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":27571379415098638,"pool_token_amount":27081302506906699}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":27530890444537155,"pool_token_amount":27077615469942829}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":27523468656319991,"pool_token_amount":27076885465325409}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":27498025288383735,"pool_token_amount":27074250321676021}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":27490697671896365,"pool_token_amount":27073528808420494}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":27472564592397012,"pool_token_amount":27071780922237812}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":27461728271751977,"pool_token_amount":27070712971063480}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":27439457893087746,"pool_token_amount":27067982773876777}],[116,{"iota_amount":27432300393206127,"pool_token_amount":27067332152359624}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":27424883133252288,"pool_token_amount":27066603387872280}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":27416356748813961,"pool_token_amount":27064780202568639}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":27412746306184240,"pool_token_amount":27064423787816616}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":27407641721883532,"pool_token_amount":27062593391075865}],[109,{"iota_amount":27403627487306777,"pool_token_amount":27062197020865944}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":27395281793973215,"pool_token_amount":27061188841104119}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":27391049501445544,"pool_token_amount":27060771666576177}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":27386741992993145,"pool_token_amount":27060346104876292}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[99,{"iota_amount":27361537031571394,"pool_token_amount":27057917390757922}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":27311791118763073,"pool_token_amount":27051994475292501}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":27302248434480744,"pool_token_amount":27049563007197822}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":27295333219105092,"pool_token_amount":27049698606252653}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":27258219026628049,"pool_token_amount":27023588560871286}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"iota_amount":27234553753979272,"pool_token_amount":27021078015569396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":27221979822183509,"pool_token_amount":27019567671006230}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":27217652893673630,"pool_token_amount":27018963208054331}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":27200097551506005,"pool_token_amount":27016682044564832}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":27191172600751597,"pool_token_amount":27015102441961639}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":27186532843556400,"pool_token_amount":27013990859797750}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":27155205566796152,"pool_token_amount":27010850041218327}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":27151095306275383,"pool_token_amount":27010361184951979}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":27125637330146448,"pool_token_amount":27006634733075128}],[46,{"iota_amount":27117195965593112,"pool_token_amount":27005435611450736}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":27104630979988421,"pool_token_amount":27003732772049434}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":27086552187395557,"pool_token_amount":27000142199815281}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":27073946992024168,"pool_token_amount":26998702580517597}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":27051219906579858,"pool_token_amount":26996397813319176}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":27041913523291543,"pool_token_amount":26995399821660808}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":20009796366205800,"pool_token_amount":20001104332934567}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":20000000025407401,"pool_token_amount":20000000000508134}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":20000000000550400,"pool_token_amount":20000000000011000}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":20000000000455800,"pool_token_amount":20000000000009112}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":20000000000000000,"pool_token_amount":20000000000000000}]],"MoveFuns DAO":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":27518268768068142,"pool_token_amount":26999617710408116}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":27508714562254921,"pool_token_amount":26999590822546842}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":27499515582435558,"pool_token_amount":26999996189831822}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":27488128364749654,"pool_token_amount":27001633907757788}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":27481923380677570,"pool_token_amount":27001951586934433}],[151,{"iota_amount":27475349532499500,"pool_token_amount":27001906918423424}],[150,{"iota_amount":27473093934582291,"pool_token_amount":27002898046732300}],[148,{"iota_amount":27466573625787492,"pool_token_amount":27002906237500766}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":27438028479567003,"pool_token_amount":27002965325572620}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":27427096358601922,"pool_token_amount":27001600280075282}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":27389845058292017,"pool_token_amount":27002496764326443}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":27401456226524207,"pool_token_amount":27039011550775723}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":27392193163799983,"pool_token_amount":27039276040229354}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":27375608638235519,"pool_token_amount":27039288921867017}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":27357231767264279,"pool_token_amount":27035925597068664}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":27354515342494757,"pool_token_amount":27036967574990327}],[101,{"iota_amount":27345978031137191,"pool_token_amount":27036123689044316}],[100,{"iota_amount":27341534416050110,"pool_token_amount":27035507293047596}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":27326417031108622,"pool_token_amount":27035112950987141}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":27313456342411246,"pool_token_amount":27033220647859966}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":27309887580971637,"pool_token_amount":27033229571355779}],[90,{"iota_amount":27300350479957154,"pool_token_amount":27030846322341405}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":27288587431510602,"pool_token_amount":27029760879299949}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":27256103863125643,"pool_token_amount":27015077405815932}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":27233281772286790,"pool_token_amount":27013607260362906}],[75,{"iota_amount":27229279635149302,"pool_token_amount":27013130004938607}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":27208500399034328,"pool_token_amount":27010660911122942}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":27204684202013482,"pool_token_amount":27010660724992396}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":27187606723060702,"pool_token_amount":27008852546491751}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":27122688268592902,"pool_token_amount":26997303485773077}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":27115450618710864,"pool_token_amount":26997303590982665}],[47,{"iota_amount":27111832195382323,"pool_token_amount":26997303678402433}],[46,{"iota_amount":27108215755461009,"pool_token_amount":26997305901399157}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":27108381879292568,"pool_token_amount":27004679539831335}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":27075202633409557,"pool_token_amount":27000684421622889}],[35,{"iota_amount":27070854956120513,"pool_token_amount":27000250258047668}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":27042883153583434,"pool_token_amount":26996459699710037}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"iota_amount":20027798726725227,"pool_token_amount":20003241077149585}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":20014499841797003,"pool_token_amount":20001593259539134}],[22,{"iota_amount":20009481366205800,"pool_token_amount":20000789467092587}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":20004670736001501,"pool_token_amount":20000096332687010}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"iota_amount":20000000012338901,"pool_token_amount":20000000000246767}],[16,{"iota_amount":20000000007028393,"pool_token_amount":20000000000140558}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":20000000000537500,"pool_token_amount":20000000000010743}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":20000000000442900,"pool_token_amount":20000000000008856}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":20000000000438600,"pool_token_amount":20000000000008771}]],"Mysten-1":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":163441637694686424,"pool_token_amount":159914291668660775}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":163410170306520965,"pool_token_amount":159904264921051253}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":164141481996889669,"pool_token_amount":160724143856099529}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":163983153492818341,"pool_token_amount":160719356462042189}],[150,{"iota_amount":163912427548567797,"pool_token_amount":160714471399808156}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[148,{"iota_amount":163866807778047169,"pool_token_amount":160712610831279196}],[147,{"iota_amount":60577452505114017,"pool_token_amount":26236842628119062}],[146,{"iota_amount":164929923243860802,"pool_token_amount":161798271815226197}],[145,{"iota_amount":164901778494163109,"pool_token_amount":161792090699449538}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":164673983426353488,"pool_token_amount":161632834139475884}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":169354902783913294,"pool_token_amount":166360125375880825}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":169302942652745502,"pool_token_amount":166331119610448187}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":169094848567256891,"pool_token_amount":166148711511411574}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":169545144984646063,"pool_token_amount":166635498787384885}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":169246559494164668,"pool_token_amount":166430302793148498}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":178402948011520949,"pool_token_amount":175482307768133892}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":178389415300718393,"pool_token_amount":175492209556221921}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":178354432811163014,"pool_token_amount":175504230367379829}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":178334228710128626,"pool_token_amount":175530803600049249}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":173082460279549347,"pool_token_amount":170453069607399956}],[116,{"iota_amount":173056613410042654,"pool_token_amount":170450264272264294}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":173027868260943970,"pool_token_amount":170444603421029452}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":173392282829452162,"pool_token_amount":170871876050064016}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":90592941540681178,"pool_token_amount":39456929245771835}],[98,{"iota_amount":187771620682393874,"pool_token_amount":185433113602606250}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":187588973788062152,"pool_token_amount":185392738130168630}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":187197078177877907,"pool_token_amount":185032994348771218}],[91,{"iota_amount":192196546811316816,"pool_token_amount":190003701222146148}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":202030095830817499,"pool_token_amount":199845089498626912}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":202004212759229481,"pool_token_amount":199849169816608936}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":201967921440062492,"pool_token_amount":199842807595652337}],[84,{"iota_amount":201914846972840740,"pool_token_amount":199819757130272081}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":201873981914708426,"pool_token_amount":199808892251715119}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":235800837567320740,"pool_token_amount":233611750365407312}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":237676123514431719,"pool_token_amount":235719612975419901}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":297161394210778727,"pool_token_amount":295133607223623561}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":287258659250032597,"pool_token_amount":285425306378627458}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":281210813905946301,"pool_token_amount":279749936124865325}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"iota_amount":285733287603883689,"pool_token_amount":284378754541901170}],[45,{"iota_amount":285646987364760834,"pool_token_amount":284377850517587650}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":285495001036961726,"pool_token_amount":284311543179653005}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"iota_amount":282132384042115288,"pool_token_amount":281090364834692140}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":278215092903384668,"pool_token_amount":277406161611102295}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":214170578353193153,"pool_token_amount":213583380013958676}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":214098463341352950,"pool_token_amount":213582588184990999}],[32,{"iota_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":212374814522779206,"pool_token_amount":212006446995715987}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":167545672555838728,"pool_token_amount":167428590588548431}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":160834576781276838,"pool_token_amount":160797255768874326}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"iota_amount":150000000093514591,"pool_token_amount":150000000001870281}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":150000000003391500,"pool_token_amount":150000000000067827}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Mysten-2":[[167,{"iota_amount":235295269344792213,"pool_token_amount":230211799601628356}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":235345963753313416,"pool_token_amount":230350805875585554}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":234539352823554067,"pool_token_amount":229864140658159581}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":234504216001323691,"pool_token_amount":229921869429502923}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":234081310004737504,"pool_token_amount":229903098968029510}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":234030175534512311,"pool_token_amount":229913790011766932}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":233976658966869444,"pool_token_amount":229891648360753048}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":233662800007398175,"pool_token_amount":229765790727899017}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":233072043605134557,"pool_token_amount":229245661128241453}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":233015355134655981,"pool_token_amount":229220178161876123}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":232992180849146309,"pool_token_amount":229227655656707688}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":232954271052359226,"pool_token_amount":229250924780744849}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":232709313102081588,"pool_token_amount":229252673157036902}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":232468577896923941,"pool_token_amount":229106713943180969}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":232335927127585332,"pool_token_amount":229104450488548038}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":232209069867521115,"pool_token_amount":229048344240681035}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":239921442285803733,"pool_token_amount":236802885789585849}],[101,{"iota_amount":239890940773046850,"pool_token_amount":236808957773467747}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":287883155287886818,"pool_token_amount":284621886837909687}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":287758648799390383,"pool_token_amount":284583152162775706}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":287716186189924424,"pool_token_amount":284583355320982318}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":287539145051501336,"pool_token_amount":284534569784782025}],[84,{"iota_amount":287466557291069394,"pool_token_amount":284504618940344444}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":284408438314731825,"pool_token_amount":281602589938178045}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":284364856189137730,"pool_token_amount":281602421558179693}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":284322904345084575,"pool_token_amount":281602349684947498}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":285520804788520990,"pool_token_amount":283216310398421781}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":285381403666917506,"pool_token_amount":283211024296396057}],[65,{"iota_amount":285399198463993527,"pool_token_amount":283273117985019265}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":349549100176942886,"pool_token_amount":347161272308717773}],[60,{"iota_amount":345616340111990250,"pool_token_amount":343306013011173866}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":345733180377014204,"pool_token_amount":343472732447453610}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":342307698245778626,"pool_token_amount":340321690461096847}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":346938410364761503,"pool_token_amount":345183316274927609}],[48,{"iota_amount":345043245119861702,"pool_token_amount":343350648477957146}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"iota_amount":279877599324715089,"pool_token_amount":278839536686300588}],[39,{"iota_amount":279830095829099375,"pool_token_amount":278834640957440291}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":251631468245564555,"pool_token_amount":250852300841119746}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":231274834478189325,"pool_token_amount":230672725365119502}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":230720770035458853,"pool_token_amount":230158419225046727}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":182209990407556936,"pool_token_amount":181857432728907603}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":210088091267080309,"pool_token_amount":209762013985346442}],[26,{"iota_amount":179996518744232507,"pool_token_amount":179752613704658111}],[25,{"iota_amount":174813370641117737,"pool_token_amount":174612636113053916}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":158929203575013686,"pool_token_amount":158892390962988946}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"iota_amount":150000000093514591,"pool_token_amount":150000000001870281}],[16,{"iota_amount":150000000053253526,"pool_token_amount":150000000001065061}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":150000000003391500,"pool_token_amount":150000000000067827}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Nelrann":[[167,{"iota_amount":137809475740112083,"pool_token_amount":134902865500725574}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":137755474118990725,"pool_token_amount":134901438645260737}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":137682669617442116,"pool_token_amount":134898535725769531}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":137586271661507734,"pool_token_amount":134927515975351668}],[151,{"iota_amount":137550185366324705,"pool_token_amount":134927425420659788}],[151,{"iota_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":137442580054316943,"pool_token_amount":134927369125372005}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":137424393464003589,"pool_token_amount":134927017159909143}],[143,{"iota_amount":137407083453186081,"pool_token_amount":134927511190178911}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":137389273169165757,"pool_token_amount":134927511436159513}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":137372091630130703,"pool_token_amount":134928132891352699}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":137303013402676284,"pool_token_amount":134930325198012728}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":137139393425748967,"pool_token_amount":134927241114890950}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":137103765210076558,"pool_token_amount":134927261866180950}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":137068106009936109,"pool_token_amount":134927241319123646}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[120,{"iota_amount":136996504638696571,"pool_token_amount":134926917029330686}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":91735889242077333,"pool_token_amount":39881683429017994}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":136851084712296860,"pool_token_amount":134924026874397138}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":136788319290461834,"pool_token_amount":134897273547460118}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[102,{"iota_amount":136634232195334493,"pool_token_amount":134905515298038361}],[98,{"iota_amount":136561331482629768,"pool_token_amount":134914015779595844}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":136509207044537178,"pool_token_amount":134902479207220197}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":136428753350821144,"pool_token_amount":134902454206345491}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":136369595062065220,"pool_token_amount":134902883979505110}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":136208938223207945,"pool_token_amount":134880705055319713}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":136188875991115703,"pool_token_amount":134880305361278396}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":136128595376228089,"pool_token_amount":134879735556080752}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[75,{"iota_amount":136071260855455308,"pool_token_amount":134881292454512521}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":136009697070013226,"pool_token_amount":134880236550997261}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":135934907037741075,"pool_token_amount":134888511732587753}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"iota_amount":135849165100807926,"pool_token_amount":134885156326837817}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":135828715252946961,"pool_token_amount":134884344137541344}],[62,{"iota_amount":135808266604519526,"pool_token_amount":134883531878501105}],[60,{"iota_amount":135766913073955110,"pool_token_amount":134881459837802974}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":135777064619514460,"pool_token_amount":134911051168073684}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":135630094942699792,"pool_token_amount":134902524200320601}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":135609417669094800,"pool_token_amount":134901696008066952}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":135547148135322010,"pool_token_amount":134898975450503458}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":135420689137211322,"pool_token_amount":134892117197055319}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"iota_amount":135399589629070786,"pool_token_amount":134891228107888076}],[39,{"iota_amount":135357419191352053,"pool_token_amount":134889797317261869}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":105240200061506850,"pool_token_amount":104975280522328447}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":105202587531743277,"pool_token_amount":104972069241288095}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"iota_amount":80112926935672189,"pool_token_amount":80006854498085866}],[25,{"iota_amount":80097951021108794,"pool_token_amount":80008042263818632}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":80059867024596320,"pool_token_amount":80004946598047977}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Neuler":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":35683373161066808,"pool_token_amount":34994490394891766}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":35672267369426080,"pool_token_amount":35004440087395369}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":35662645421288504,"pool_token_amount":35003591177397047}],[156,{"iota_amount":35657834303548547,"pool_token_amount":35003166178372890}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":35653022939722713,"pool_token_amount":35002741105396664}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":35643140313591205,"pool_token_amount":35001636639481344}],[148,{"iota_amount":35616028443376967,"pool_token_amount":34996511364336165}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":35547720116812150,"pool_token_amount":34988699062238596}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":35535543557153537,"pool_token_amount":34993710464371625}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":35526101185446392,"pool_token_amount":34992874464360129}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":35521386206958587,"pool_token_amount":34992459204630464}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":35511954695858077,"pool_token_amount":34991622956728828}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":35474237218626610,"pool_token_amount":34988277617412508}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":35454948161905751,"pool_token_amount":34990404576133077}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":35450234528602603,"pool_token_amount":34989939388397839}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":35428567898756390,"pool_token_amount":34996550040770823}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":35412209762026023,"pool_token_amount":34994936615958897}],[101,{"iota_amount":35406801156498106,"pool_token_amount":34994402125739546}],[98,{"iota_amount":35390641586080974,"pool_token_amount":34992804765192307}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":35363606589049442,"pool_token_amount":34990066918972081}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":35353004293942582,"pool_token_amount":34989018709370224}],[90,{"iota_amount":35347724302356720,"pool_token_amount":34988497930191400}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":35345593457950473,"pool_token_amount":34995791103041222}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":35324580332679633,"pool_token_amount":34993715558494393}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":35308895520533857,"pool_token_amount":34992168731029072}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":35304485902829944,"pool_token_amount":34992663164850980}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":35293920887039378,"pool_token_amount":34991518677611392}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":35273122848776624,"pool_token_amount":34994308470972340}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":35254180762654491,"pool_token_amount":34995368138808965}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":35229392268668234,"pool_token_amount":34999954563620544}],[62,{"iota_amount":35224165972598948,"pool_token_amount":34999432655312142}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":35208489779429513,"pool_token_amount":34997870357033418}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":35160566616344537,"pool_token_amount":34992788276251319}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"iota_amount":35139471965681958,"pool_token_amount":34990906972612088}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":35117850015223609,"pool_token_amount":34988498850001897}],[41,{"iota_amount":35118011976131997,"pool_token_amount":34993445031405187}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":35095530372939148,"pool_token_amount":34995706841903712}],[35,{"iota_amount":35089741957335133,"pool_token_amount":34995236939593584}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":35077824004748050,"pool_token_amount":34994162920308389}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":35059848655958500,"pool_token_amount":34992461931344813}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"iota_amount":25029747651635214,"pool_token_amount":25002933540529482}],[24,{"iota_amount":25024234138651360,"pool_token_amount":25002425051304324}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Node Guardians":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":27549387941524800,"pool_token_amount":27022168902974431}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":27534958060993249,"pool_token_amount":27020753278189034}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":27528562404322186,"pool_token_amount":27021028759532416}],[156,{"iota_amount":27521145942685438,"pool_token_amount":27020301627890637}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":27502393269837002,"pool_token_amount":27018277072292323}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"iota_amount":60577452505114017,"pool_token_amount":26236842628119062}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":27487384201233860,"pool_token_amount":27029437512367461}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":27483773976752721,"pool_token_amount":27029082504199523}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":27473017818851890,"pool_token_amount":27028093611184334}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[130,{"iota_amount":27443294401457074,"pool_token_amount":27027653577526474}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":27439677682536288,"pool_token_amount":27027297382731225}],[128,{"iota_amount":27435760170691895,"pool_token_amount":27026644689701177}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":27396876583154162,"pool_token_amount":27026765427911265}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":27393534458616104,"pool_token_amount":27026673739012322}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"iota_amount":27375841229763777,"pool_token_amount":27022039955103829}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":90853781868271072,"pool_token_amount":39531943192078969}],[109,{"iota_amount":27368010833734157,"pool_token_amount":27021085449334992}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":90592941540681178,"pool_token_amount":39456929245771835}],[101,{"iota_amount":27344673232891896,"pool_token_amount":27027785359588034}],[100,{"iota_amount":27340428613976078,"pool_token_amount":27027365814228845}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":27319758840997582,"pool_token_amount":27025371699939035}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":27292274202566033,"pool_token_amount":27016462199406908}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":27272058539074558,"pool_token_amount":27014425172001060}],[84,{"iota_amount":27268013768750358,"pool_token_amount":27013990644589804}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":27251647299013930,"pool_token_amount":27022983851297102}],[76,{"iota_amount":27247697707989586,"pool_token_amount":27022637559355919}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":27243695570852098,"pool_token_amount":27022239758749069}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":27234550890817198,"pool_token_amount":27020412184669709}],[72,{"iota_amount":27230325606596405,"pool_token_amount":27019991192633847}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":27203018872386779,"pool_token_amount":27015922457042914}],[66,{"iota_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":27177321828618797,"pool_token_amount":27012155776517138}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":27150824800568588,"pool_token_amount":27003712663946294}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":27146803902323669,"pool_token_amount":27003394547831230}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":27137876601793015,"pool_token_amount":27001878226260155}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":27129611648690434,"pool_token_amount":27001019101811283}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":27125539649886122,"pool_token_amount":27000649745530941}],[47,{"iota_amount":27128192260536855,"pool_token_amount":27010659490295903}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":27110083096013936,"pool_token_amount":27007366564048671}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"iota_amount":27097700804550695,"pool_token_amount":27006092670552160}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":27088545265609991,"pool_token_amount":27004346883417797}],[37,{"iota_amount":27084214722228984,"pool_token_amount":27003824557641794}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":27079960689322565,"pool_token_amount":27003390546323224}],[36,{"iota_amount":50711252482838312,"pool_token_amount":22293532425396754}],[35,{"iota_amount":27075459896187847,"pool_token_amount":27002892386111750}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":27053458881544443,"pool_token_amount":27001412982505045}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":27044019877524983,"pool_token_amount":27000394992326079}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":20004687736001501,"pool_token_amount":20000113328799675}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":20000000015785201,"pool_token_amount":20000000000315691}],[18,{"iota_amount":20000000015327401,"pool_token_amount":20000000000306536}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":20000000000000000,"pool_token_amount":20000000000000000}],[1,{"iota_amount":80000000000000000,"pool_token_amount":80000000000000000}]],"NodeReal":[[167,{"iota_amount":27585591028843761,"pool_token_amount":27040328439926695}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":27571176284491383,"pool_token_amount":27039074505752318}],[162,{"iota_amount":27567568097727115,"pool_token_amount":27038756035758663}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[155,{"iota_amount":27541813623509680,"pool_token_amount":27036484483614853}],[154,{"iota_amount":27538104502634295,"pool_token_amount":27036156787154624}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":27530336116290323,"pool_token_amount":27035157842308499}],[148,{"iota_amount":27515496144096493,"pool_token_amount":27033843343880050}],[146,{"iota_amount":27508072784951241,"pool_token_amount":27033186895188856}],[145,{"iota_amount":27504460004118292,"pool_token_amount":27032868266900692}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[141,{"iota_amount":27489859278277655,"pool_token_amount":27031437869883073}],[139,{"iota_amount":27482636119938358,"pool_token_amount":27030798587239713}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":27468954579293631,"pool_token_amount":27030283533121817}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":27443676592924012,"pool_token_amount":27028065732652181}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":27440062796214057,"pool_token_amount":27027745415958252}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":27428173578639094,"pool_token_amount":27025747625879371}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":27424561655640837,"pool_token_amount":27025427321840576}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":27403930097928189,"pool_token_amount":27024525894617856}],[115,{"iota_amount":27396736324057543,"pool_token_amount":27023910990946537}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":27348539350570812,"pool_token_amount":27014792269595554}],[98,{"iota_amount":27323650742759822,"pool_token_amount":27012360989953580}],[97,{"iota_amount":27319561207605778,"pool_token_amount":27011958486459938}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":27306986786882489,"pool_token_amount":27010715925176839}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[92,{"iota_amount":27298794557361848,"pool_token_amount":27009951309649590}],[91,{"iota_amount":27294738465080476,"pool_token_amount":27009549991425587}],[90,{"iota_amount":27290692681888124,"pool_token_amount":27009149639801859}],[89,{"iota_amount":27286662691234095,"pool_token_amount":27008762664888870}],[88,{"iota_amount":27281853089448708,"pool_token_amount":27007600704973231}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":27237607568412242,"pool_token_amount":27003321239506881}],[76,{"iota_amount":27233589183155670,"pool_token_amount":27002906805078700}],[74,{"iota_amount":27225905506340878,"pool_token_amount":27002429510230693}],[72,{"iota_amount":27217568972680382,"pool_token_amount":27001601749960647}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[56,{"iota_amount":27160338937569391,"pool_token_amount":27003884254199815}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":27143993833755693,"pool_token_amount":27002253476230554}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":27139880766421816,"pool_token_amount":27001843421951713}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":27127983734451455,"pool_token_amount":27001053215716512}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":27078145873887525,"pool_token_amount":26995870365207456}],[35,{"iota_amount":27073650077267865,"pool_token_amount":26995731871358726}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[32,{"iota_amount":27057051152845784,"pool_token_amount":26992549422006409}],[31,{"iota_amount":27052468438083302,"pool_token_amount":26992433544606514}],[30,{"iota_amount":27047657069735885,"pool_token_amount":26992089456532519}],[26,{"iota_amount":20030294000214454,"pool_token_amount":20003465129949797}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":20004782736001501,"pool_token_amount":20000208307076332}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":20000000025407401,"pool_token_amount":20000000000508134}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":20000000015327401,"pool_token_amount":20000000000306536}],[17,{"iota_amount":20000000012338901,"pool_token_amount":20000000000246767}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":20000000000550400,"pool_token_amount":20000000000011000}],[11,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":20000000000438600,"pool_token_amount":20000000000008771}],[1,{"iota_amount":20000000000000000,"pool_token_amount":20000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Nodeinfra":[[167,{"iota_amount":27559375009982524,"pool_token_amount":27023114402197502}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":27552658634595625,"pool_token_amount":27022897940985306}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":27541827892855012,"pool_token_amount":27021831150986408}],[161,{"iota_amount":27538223466255215,"pool_token_amount":27021477513390935}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"iota_amount":27499952346286940,"pool_token_amount":27019864215793870}],[147,{"iota_amount":27488324010012325,"pool_token_amount":27018281195208317}],[145,{"iota_amount":27481098742458786,"pool_token_amount":27017570980307168}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":27470267029924433,"pool_token_amount":27016508640675664}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":27444971752503706,"pool_token_amount":27014018250337281}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":27405217257893820,"pool_token_amount":27010100968621481}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":27401605334895563,"pool_token_amount":27009744983398486}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":27397992729941081,"pool_token_amount":27009388888707104}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":27387160451948090,"pool_token_amount":27008321796792989}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":27374229577048502,"pool_token_amount":27008387221949382}],[114,{"iota_amount":27372074317960531,"pool_token_amount":27009466574912603}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":27368463973174924,"pool_token_amount":27009110322803380}],[112,{"iota_amount":27364853511456589,"pool_token_amount":27008754016858665}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[99,{"iota_amount":27312192384929801,"pool_token_amount":27003609743056723}],[97,{"iota_amount":27303971457607102,"pool_token_amount":27002790654838127}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":27276918430073200,"pool_token_amount":26998074760871620}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":27244771784203299,"pool_token_amount":26994970395309954}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":27232525983674144,"pool_token_amount":26993754203843731}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":27216597319584065,"pool_token_amount":26992250105515658}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":27231218614348909,"pool_token_amount":27013896738148185}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":27226406364909206,"pool_token_amount":27012794381456514}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":27217858682553146,"pool_token_amount":27011856060338729}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":27209295462325109,"pool_token_amount":27011004372986002}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":27200595071792134,"pool_token_amount":27010111839363411}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":27196261083165880,"pool_token_amount":27009681475549188}],[65,{"iota_amount":27192193458597933,"pool_token_amount":27009515802248531}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":27184191618003587,"pool_token_amount":27008720941198055}],[62,{"iota_amount":27180890384218668,"pool_token_amount":27009018606613222}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":27164672641353807,"pool_token_amount":27007215958583499}],[56,{"iota_amount":27156670394056208,"pool_token_amount":27006420319506660}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":27139409271377577,"pool_token_amount":27003877955426277}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":27135297106402316,"pool_token_amount":27003468705193414}],[50,{"iota_amount":27131183220633612,"pool_token_amount":27003057523961289}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":27122958655832562,"pool_token_amount":27002238903711211}],[45,{"iota_amount":27110518995872938,"pool_token_amount":27000907096808987}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":27106410185946457,"pool_token_amount":27000500597770554}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":27098162824490009,"pool_token_amount":26999658406911454}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"iota_amount":27094046211665189,"pool_token_amount":26999244655137552}],[39,{"iota_amount":27085817385488932,"pool_token_amount":26998421010725256}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":27077549809816872,"pool_token_amount":26997665133070293}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":27073288781514822,"pool_token_amount":26997224139608307}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":27059716145380343,"pool_token_amount":26995860571105599}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":20014265190222270,"pool_token_amount":20001169522666181}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":20000000015785201,"pool_token_amount":20000000000315691}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":20000000000537500,"pool_token_amount":20000000000010743}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Nodes.Guru":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":117686475508155709,"pool_token_amount":115267653332480162}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":117656643199765360,"pool_token_amount":115267346005533449}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":117550084704028124,"pool_token_amount":115251559939281019}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":117516661399016828,"pool_token_amount":115248667501666984}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":117500473527274997,"pool_token_amount":115247736096791087}],[151,{"iota_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":117410802427652665,"pool_token_amount":115249285771423689}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":117349142247463573,"pool_token_amount":115247992529795738}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":117317412206804757,"pool_token_amount":115246399812528423}],[140,{"iota_amount":117301856163328200,"pool_token_amount":115245909655156547}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":117286772808572916,"pool_token_amount":115245886329679640}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":117253632441711201,"pool_token_amount":115242948570419268}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":117237602668038003,"pool_token_amount":115242008810254448}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":117175598050371743,"pool_token_amount":115240293631739007}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":117143655247642915,"pool_token_amount":115238521013833552}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":117020286231247571,"pool_token_amount":115235726223372769}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":116985207290927499,"pool_token_amount":115245663336677806}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":116953154793690429,"pool_token_amount":115243746510513481}],[117,{"iota_amount":91735889242077333,"pool_token_amount":39881683429017994}],[116,{"iota_amount":116932458914536402,"pool_token_amount":115238184464763911}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":116900205381062389,"pool_token_amount":115236066759408840}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":116880747276634126,"pool_token_amount":115231724492410761}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":116844176802042231,"pool_token_amount":115225352517402143}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":116632233851013511,"pool_token_amount":115064185738035447}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":116596598293215343,"pool_token_amount":115062693232664481}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[101,{"iota_amount":116494913854153055,"pool_token_amount":115048178987678343}],[100,{"iota_amount":116476254193041723,"pool_token_amount":115046756588766829}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":116283491639441372,"pool_token_amount":115040955437544956}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":116265380274235427,"pool_token_amount":115039595263943274}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":116230151378895092,"pool_token_amount":115037841004740780}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":116012752828188771,"pool_token_amount":115037419058933300}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":115975543242596101,"pool_token_amount":115035281147655888}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":115920158202729100,"pool_token_amount":115032720922193014}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":115825454813068252,"pool_token_amount":115024125395181210}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":115751037234786463,"pool_token_amount":115016069721124256}],[58,{"iota_amount":115731586493599066,"pool_token_amount":115013213496596261}],[56,{"iota_amount":115696865244205473,"pool_token_amount":115011760715269246}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":115642102941652648,"pool_token_amount":115007181058830997}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":115605746267406187,"pool_token_amount":115004311810474000}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"iota_amount":115557482963744787,"pool_token_amount":115023706236820249}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":115390985947892987,"pool_token_amount":114993716335627981}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":115372104392035525,"pool_token_amount":114991953477763892}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":105249387658034717,"pool_token_amount":105001597031879604}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":105217926973029570,"pool_token_amount":105004241458509192}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":105153641467935837,"pool_token_amount":104993485488856848}],[26,{"iota_amount":80136740927695027,"pool_token_amount":80030085351175731}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"OKXEarn":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":37117193911214958,"pool_token_amount":36299830180084796}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":37098382686898554,"pool_token_amount":36290952530626613}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":37031754388508754,"pool_token_amount":36230579699154831}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[155,{"iota_amount":36691054568484356,"pool_token_amount":35921660419390522}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":36576345684678609,"pool_token_amount":35823876116360722}],[149,{"iota_amount":36832295016221346,"pool_token_amount":36089454557074817}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"iota_amount":60577452505114017,"pool_token_amount":26236842628119062}],[146,{"iota_amount":90637706624017590,"pool_token_amount":88861972057746799}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":91676070457145353,"pool_token_amount":89916978933042797}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":91789575260950215,"pool_token_amount":90040528525810426}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":91611122856196091,"pool_token_amount":89926830106174626}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[130,{"iota_amount":84399389503615740,"pool_token_amount":82926336877593665}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":88429624215059049,"pool_token_amount":86910316373790238}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":85924627861814632,"pool_token_amount":84459821259626824}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":40316111875612709,"pool_token_amount":39672005793691464}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":35940779234887846,"pool_token_amount":35371606219528685}],[116,{"iota_amount":35757488763792394,"pool_token_amount":35200892209887660}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":35754278652756605,"pool_token_amount":35207430402317214}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"iota_amount":35594768774960408,"pool_token_amount":35064867171568191}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":35595148155654409,"pool_token_amount":35070085214521681}],[110,{"iota_amount":90853781868271072,"pool_token_amount":39531943192078969}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":35480073272708419,"pool_token_amount":34972372517598419}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":90592941540681178,"pool_token_amount":39456929245771835}],[98,{"iota_amount":55440878995164449,"pool_token_amount":54734071288674762}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":55390412076583163,"pool_token_amount":54718195271047831}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":55065932487194005,"pool_token_amount":54414254001141609}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":54661766092066391,"pool_token_amount":54072103591064238}],[84,{"iota_amount":54648129937144691,"pool_token_amount":54066762412997276}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":54497589434355597,"pool_token_amount":53925973275156457}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":51605282027759458,"pool_token_amount":51082107620827325}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":51525946690543514,"pool_token_amount":51027034863500756}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":51346918790211696,"pool_token_amount":50945528147776939}],[66,{"iota_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"iota_amount":51361125823217545,"pool_token_amount":50967787819336203}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":51310194421359715,"pool_token_amount":50932687984784971}],[62,{"iota_amount":51291452733995272,"pool_token_amount":50921806331572814}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":53018708705851792,"pool_token_amount":52653007471509033}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":53000418196113380,"pool_token_amount":52642790838179819}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":52595215625265200,"pool_token_amount":52264111366265692}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":50803671852930646,"pool_token_amount":50506838772844657}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":50794839710415273,"pool_token_amount":50505684919807707}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":50798309443646145,"pool_token_amount":50532030244679497}],[46,{"iota_amount":50728803960814566,"pool_token_amount":50486097658412292}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50695288561974175,"pool_token_amount":50468225808107331}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":50774239432369488,"pool_token_amount":50570329505007321}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50748846187197510,"pool_token_amount":50560758518909024}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":50711252482838312,"pool_token_amount":22293532425396754}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":58062561588327535,"pool_token_amount":57895943687738580}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"iota_amount":57394344276014225,"pool_token_amount":57258924062197410}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":41067072549102541,"pool_token_amount":41003176544476025}],[25,{"iota_amount":20055970167260436,"pool_token_amount":20032981601027745}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":20017447026216700,"pool_token_amount":20008283836979363}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":20000000015327401,"pool_token_amount":20000000000306536}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":80000000000000000,"pool_token_amount":80000000000000000}]],"ONBUFF":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":35755553804594748,"pool_token_amount":35058506559768683}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":35732104748007190,"pool_token_amount":35056207722090948}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":35703420042653996,"pool_token_amount":35053378534122671}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":35698608210309877,"pool_token_amount":35052906111223115}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":35693659766522488,"pool_token_amount":35052299677394546}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":35650437962733896,"pool_token_amount":35048057536358684}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":35631180322615120,"pool_token_amount":35046163964578203}],[139,{"iota_amount":35626464818431187,"pool_token_amount":35045700155888273}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":35617024018024647,"pool_token_amount":35044771409110378}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":35564823924500976,"pool_token_amount":35039636678408932}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":35545907540867349,"pool_token_amount":35037725555020282}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":35541192080609846,"pool_token_amount":35037260750035872}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":35536479210585666,"pool_token_amount":35036797033373768}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":35531765078154576,"pool_token_amount":35036332248346953}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":35508022834094689,"pool_token_amount":35034101605106797}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":35489036616644660,"pool_token_amount":35032112504521598}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":35456667239824997,"pool_token_amount":35028914358903676}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[100,{"iota_amount":35434962106102993,"pool_token_amount":35026770467439139}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":35402541559263863,"pool_token_amount":35023567342293244}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":35386653101222386,"pool_token_amount":35022014966751572}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":35370838432684529,"pool_token_amount":35020467479836343}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":35355091766686781,"pool_token_amount":35018945142654994}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":35307687972425842,"pool_token_amount":35014239126206605}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":35297235171560046,"pool_token_amount":35013198002032912}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":35280674163874326,"pool_token_amount":35011554103757100}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":35269253699062733,"pool_token_amount":35010150921555160}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":35241468944455550,"pool_token_amount":35007092342708018}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":35230722045938881,"pool_token_amount":35005756526602261}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":35220274863673652,"pool_token_amount":35004719309521732}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":35199268834721407,"pool_token_amount":35002630247915968}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":35193544977025882,"pool_token_amount":35001613573636610}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":35188210149451895,"pool_token_amount":35001083000273660}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":35177539104634003,"pool_token_amount":35000021498089074}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"iota_amount":35145529604766253,"pool_token_amount":34996833821675267}],[45,{"iota_amount":35140188457322417,"pool_token_amount":34996295693346909}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":35124175931939861,"pool_token_amount":34994692890405050}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":35102601029089741,"pool_token_amount":34992533945057383}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":35091569207686855,"pool_token_amount":34991438633860568}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":35074002871551300,"pool_token_amount":34989684085299975}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":35062198072594542,"pool_token_amount":34988496476530898}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":25023781437987629,"pool_token_amount":25001028637337304}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":25017968127371582,"pool_token_amount":25000625016830827}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":25000000032208364,"pool_token_amount":25000000000644154}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":25000000019248364,"pool_token_amount":25000000000384956}],[16,{"iota_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":25000000000572400,"pool_token_amount":25000000000011444}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":25000000000550800,"pool_token_amount":25000000000011015}],[0,{"iota_amount":0,"pool_token_amount":0}]],"ORBR":[[167,{"iota_amount":37166551428297432,"pool_token_amount":36739934539084584}],[166,{"iota_amount":37161124281809436,"pool_token_amount":36739231388310030}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[163,{"iota_amount":37146692020246402,"pool_token_amount":36738948107480308}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":37141899980829434,"pool_token_amount":36738871616396680}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[158,{"iota_amount":37720878501117888,"pool_token_amount":37331413550568382}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[153,{"iota_amount":37685935182468646,"pool_token_amount":37322104761579782}],[151,{"iota_amount":37675328242194215,"pool_token_amount":37321719046719007}],[150,{"iota_amount":37670115574450640,"pool_token_amount":37321615771401709}],[149,{"iota_amount":37664556083540768,"pool_token_amount":37321169417696832}],[145,{"iota_amount":45812999125957202,"pool_token_amount":45420581514136164}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":45807476144261182,"pool_token_amount":45421152941660251}],[142,{"iota_amount":45794040024733841,"pool_token_amount":45419914601184896}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":45787820113923876,"pool_token_amount":45419790237044066}],[140,{"iota_amount":45781600683066284,"pool_token_amount":45419666847698070}],[138,{"iota_amount":45749025891593452,"pool_token_amount":45399447203893213}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":45731266556735384,"pool_token_amount":45393936511308898}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":45724332183498229,"pool_token_amount":45393105659059332}],[134,{"iota_amount":45696910041769075,"pool_token_amount":45371935689696061}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":45671314415343845,"pool_token_amount":45370747214168143}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":47661002606006315,"pool_token_amount":47360232370765032}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":47632295104678364,"pool_token_amount":47338339005366235}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[125,{"iota_amount":46869983151948425,"pool_token_amount":46593044471280248}],[124,{"iota_amount":46863660829866980,"pool_token_amount":46592917797286589}],[123,{"iota_amount":46857239534986850,"pool_token_amount":46592692260065743}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":46850917476697248,"pool_token_amount":46592566532268605}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[117,{"iota_amount":46819024420911861,"pool_token_amount":46591933983830437}],[116,{"iota_amount":46812606798686281,"pool_token_amount":46591806253556240}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":44806489574726589,"pool_token_amount":44601117865325630}],[112,{"iota_amount":44788225292321188,"pool_token_amount":44600840122651124}],[111,{"iota_amount":44782192609546458,"pool_token_amount":44600802947305149}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":44762256747498687,"pool_token_amount":44600198035195350}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":44755516019574611,"pool_token_amount":44600122484177976}],[105,{"iota_amount":44741335522148600,"pool_token_amount":44599742721578875}],[104,{"iota_amount":36607405114830822,"pool_token_amount":36497225126432413}],[103,{"iota_amount":36601556355737172,"pool_token_amount":36497079187257996}],[102,{"iota_amount":36595773574119664,"pool_token_amount":36496964427572255}],[101,{"iota_amount":36590019738652305,"pool_token_amount":36496849658499637}],[98,{"iota_amount":36572825277692958,"pool_token_amount":36496503805283449}],[97,{"iota_amount":36567142570956670,"pool_token_amount":36496390386792727}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":36561586390033658,"pool_token_amount":36496284140778387}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":36548594108821223,"pool_token_amount":36494166762680151}],[93,{"iota_amount":36542947094847127,"pool_token_amount":36494053011129644}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":36537302453762035,"pool_token_amount":36493942227904212}],[90,{"iota_amount":36516247849461691,"pool_token_amount":36483927056717866}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":36510632139783770,"pool_token_amount":36483814841397702}],[88,{"iota_amount":36505020512493374,"pool_token_amount":36483701711530543}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":30015169822670723,"pool_token_amount":30002035795725712}],[86,{"iota_amount":30010636393852955,"pool_token_amount":30001898147572120}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":30005571973828314,"pool_token_amount":30001208863739583}],[84,{"iota_amount":0,"pool_token_amount":0}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}]],"Omnistake":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":28609683756336419,"pool_token_amount":28004743583313009}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":28605971862184793,"pool_token_amount":28004632112000689}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":28586456680186872,"pool_token_amount":28003227799768482}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"iota_amount":28549792300337147,"pool_token_amount":27999885573763917}],[149,{"iota_amount":28549360574739794,"pool_token_amount":28003086801899093}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":28554577447329977,"pool_token_amount":28026346905253312}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":28530333875668853,"pool_token_amount":28024328434166752}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":28508154519694028,"pool_token_amount":28024351831519103}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":28496520385442474,"pool_token_amount":28023831312883033}],[128,{"iota_amount":28491899208860911,"pool_token_amount":28022928303406095}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":28489459674176497,"pool_token_amount":28024168354951369}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":28443394266123413,"pool_token_amount":27997041978155747}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":28433451936347332,"pool_token_amount":27994534759066199}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":37075407573613345,"pool_token_amount":36528644943698378}],[114,{"iota_amount":37073327634173446,"pool_token_amount":36531483751777509}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":37053210453244984,"pool_token_amount":36531025831543706}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":37036806136951066,"pool_token_amount":36530846805863449}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":37013423129748596,"pool_token_amount":36535924435312521}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":47027926800044093,"pool_token_amount":46465622639475634}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":47020780522216210,"pool_token_amount":46465465929213536}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":47006421112943850,"pool_token_amount":46465182109476554}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":46992636222638200,"pool_token_amount":46465542858922888}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":43449944565865205,"pool_token_amount":43001178945336799}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":43412193445454598,"pool_token_amount":42989290990401509}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":46594225658605383,"pool_token_amount":46168267731461459}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":46580846147807644,"pool_token_amount":46168607781239828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":46559160099871554,"pool_token_amount":46168165202265338}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":46536773040504645,"pool_token_amount":46167680526758754}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":46468540072514688,"pool_token_amount":46135751569220313}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":46454002294426730,"pool_token_amount":46134942830072989}],[61,{"iota_amount":41377742452410679,"pool_token_amount":41099605675352496}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":31322896198533209,"pool_token_amount":31166979922328649}],[45,{"iota_amount":31304210743706198,"pool_token_amount":31166593736249823}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":31289938083883902,"pool_token_amount":31165555568573313}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"iota_amount":36218916656993845,"pool_token_amount":36086749399634529}],[39,{"iota_amount":36213437307298100,"pool_token_amount":36086824903145392}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":27076151112747869,"pool_token_amount":26993934984689386}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":27051774894397587,"pool_token_amount":26991796188445484}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":27047205226050170,"pool_token_amount":26991693263781969}],[29,{"iota_amount":27043237089605684,"pool_token_amount":26992302322216005}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"iota_amount":20027567552081893,"pool_token_amount":20004880247703561}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":20011379893195300,"pool_token_amount":20002219509646472}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"iota_amount":20000000012328401,"pool_token_amount":20000000000246557}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":20000000000539900,"pool_token_amount":20000000000010790}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":20000000000527000,"pool_token_amount":20000000000010533}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":20000000000475400,"pool_token_amount":20000000000009502}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"iota_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":20000000000000000,"pool_token_amount":20000000000000000}]],"Overclock":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":142999389579770529,"pool_token_amount":140049918905452751}],[161,{"iota_amount":142980566463966982,"pool_token_amount":140049181510264273}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":142961667744315645,"pool_token_amount":140048391222678431}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":142848738647059522,"pool_token_amount":140047493504963810}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":142794821295851077,"pool_token_amount":140049548137401985}],[150,{"iota_amount":142775395358253005,"pool_token_amount":140048806116149086}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":142515253062174650,"pool_token_amount":140048083984265495}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":142495986620258156,"pool_token_amount":140047327623070507}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":142443539037406140,"pool_token_amount":140050330445713498}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":142386592048976881,"pool_token_amount":140048937069548647}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":142334484685174936,"pool_token_amount":140052289146787502}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":142315220862856152,"pool_token_amount":140051529909445646}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":142273814138357506,"pool_token_amount":140047180635217814}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":142104623766623584,"pool_token_amount":140044415934398182}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":142072334007002080,"pool_token_amount":140049029951615373}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":142015250628736030,"pool_token_amount":140049471809885579}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":141993817748324883,"pool_token_amount":140048600824923372}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":141907135236627103,"pool_token_amount":140046761905445397}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[99,{"iota_amount":141801390854424873,"pool_token_amount":140047257919027394}],[98,{"iota_amount":141781153913330901,"pool_token_amount":140048117059380185}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":141700499569270507,"pool_token_amount":140051344805212227}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":141682706874274208,"pool_token_amount":140054438142231380}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":141641258692663021,"pool_token_amount":140054357663467990}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":141333114169078173,"pool_token_amount":140054044363732384}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":141182216032082762,"pool_token_amount":140051283879429328}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":141142874908971489,"pool_token_amount":140055226590559006}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":141055657231325881,"pool_token_amount":140052103458879527}],[62,{"iota_amount":141032394265066998,"pool_token_amount":140049238665884212}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":140968954346296688,"pool_token_amount":140046952359552197}],[57,{"iota_amount":140926685338719287,"pool_token_amount":140045556123828752}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":140985829385269786,"pool_token_amount":140145062672926545}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":140966092576964849,"pool_token_amount":140145913655632911}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":140925502393417998,"pool_token_amount":140146510814211497}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"iota_amount":140824275130468155,"pool_token_amount":140148339086110193}],[45,{"iota_amount":140783170430647632,"pool_token_amount":140148627960237007}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":140762444940478916,"pool_token_amount":140148599744574864}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":140739919719869320,"pool_token_amount":140146780382931320}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"iota_amount":140703664649285555,"pool_token_amount":140152224979887424}],[39,{"iota_amount":291172403862715598,"pool_token_amount":290163853029919274}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":290987407824137599,"pool_token_amount":290066450205351398}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":290632780024112799,"pool_token_amount":290039693997968899}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":200545470488099766,"pool_token_amount":200203372949593630}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":150329971659880520,"pool_token_amount":150260697787320436}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":150292350986533445,"pool_token_amount":150257547817221532}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":150000000116171591,"pool_token_amount":150000000002323420}],[16,{"iota_amount":150000000053253526,"pool_token_amount":150000000001065061}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":150000000003391500,"pool_token_amount":150000000000067827}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":150000000000000000,"pool_token_amount":150000000000000000}]],"P-OPS Team":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":117507999616454287,"pool_token_amount":115066175877758327}],[165,{"iota_amount":117492463959942243,"pool_token_amount":115065415236161618}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":117413795378752461,"pool_token_amount":115060630673260775}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":117365444722578103,"pool_token_amount":115058043559176431}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":117301076531251171,"pool_token_amount":115054688731749144}],[150,{"iota_amount":117252927004031719,"pool_token_amount":115052298585385906}],[148,{"iota_amount":117220686006119339,"pool_token_amount":115050474323984981}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":117157265239231932,"pool_token_amount":115047361391440062}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":116949858554748616,"pool_token_amount":115035989811116969}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":116902419693790534,"pool_token_amount":115033628349846384}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":116886566252281967,"pool_token_amount":115032854995181265}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":116642957744414580,"pool_token_amount":115014796392303047}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":116593965502648890,"pool_token_amount":115012685246804737}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":116576360351517112,"pool_token_amount":115011826409528183}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":116485176321630308,"pool_token_amount":115007195451454250}],[97,{"iota_amount":116376438722698525,"pool_token_amount":115001825555964470}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":116339595274818573,"pool_token_amount":114999250154338816}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":116268338264319134,"pool_token_amount":114995732289456757}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":116232982831830309,"pool_token_amount":114993910453241346}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":116160033012008246,"pool_token_amount":114987865478494127}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":116089894117099336,"pool_token_amount":114984268273074527}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":116019343285948774,"pool_token_amount":114980753617300744}],[74,{"iota_amount":115966994021310137,"pool_token_amount":114978156389626168}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":115948892037300831,"pool_token_amount":114977167643851788}],[72,{"iota_amount":115930443457588704,"pool_token_amount":114976253420375035}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":115854411490181571,"pool_token_amount":114970598890074131}],[67,{"iota_amount":115835852783373109,"pool_token_amount":114969678033622305}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":115817289421832312,"pool_token_amount":114968752091534491}],[65,{"iota_amount":115798732284105861,"pool_token_amount":114967832924977867}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":115766378046641741,"pool_token_amount":114968625280906524}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":115677688848886076,"pool_token_amount":114962857964878693}],[57,{"iota_amount":115660262561446509,"pool_token_amount":114962012820749924}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":115324673957084787,"pool_token_amount":114928568281439339}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":115307565977090514,"pool_token_amount":114928572936993589}],[37,{"iota_amount":115290264485871172,"pool_token_amount":114928507177808913}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":105274275401329003,"pool_token_amount":104959913543685611}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":105240694077841743,"pool_token_amount":104959911339347613}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":105155816484799688,"pool_token_amount":104960405580501455}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":80124710617595157,"pool_token_amount":80003429141768846}],[25,{"iota_amount":80092037019762735,"pool_token_amount":80002132413388206}],[24,{"iota_amount":80076374232695145,"pool_token_amount":80003267106809736}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":80056776280851811,"pool_token_amount":80001857206186208}],[22,{"iota_amount":80038209583037116,"pool_token_amount":80001594140761966}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"P2P.ORG":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":232659480398663754,"pool_token_amount":228063512468797756}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":232628734485942527,"pool_token_amount":228060519700181068}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":233226276807079287,"pool_token_amount":228728722043871235}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":233155130173266768,"pool_token_amount":228715040372659305}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":232997551630969843,"pool_token_amount":228700733022766608}],[148,{"iota_amount":289202953612938816,"pool_token_amount":284017178525462232}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":288897112272647680,"pool_token_amount":283958438005597010}],[140,{"iota_amount":288847859266574580,"pool_token_amount":283944546326174875}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":288806048453616593,"pool_token_amount":283937885723380482}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":288767571538732592,"pool_token_amount":283934525975436670}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":288681343656081675,"pool_token_amount":283918717798690755}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":288634218721917840,"pool_token_amount":283906834915618491}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":288480355869737383,"pool_token_amount":283979384195112947}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":288401067611510260,"pool_token_amount":283970381577575968}],[128,{"iota_amount":288357327637111374,"pool_token_amount":283961854833854496}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":289016310521043611,"pool_token_amount":284852994504290249}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":288933579801905464,"pool_token_amount":284840671450151446}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":288854988916870947,"pool_token_amount":284832509545270569}],[116,{"iota_amount":288815685723464798,"pool_token_amount":284828460183233986}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":288694358835989253,"pool_token_amount":284812946488579765}],[112,{"iota_amount":288723576450062383,"pool_token_amount":284876508475425537}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":288467953878970605,"pool_token_amount":284849825940752169}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":288422395462941486,"pool_token_amount":284845189486402309}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":288285892793695342,"pool_token_amount":284831151829094437}],[101,{"iota_amount":288240894021778068,"pool_token_amount":284826702495415625}],[99,{"iota_amount":288151317415176764,"pool_token_amount":284817822744733955}],[98,{"iota_amount":288106658303800354,"pool_token_amount":284813408495757562}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":227690406179096068,"pool_token_amount":225366688318660085}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":227551297911497604,"pool_token_amount":225351551250794161}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":227487110537400031,"pool_token_amount":225348992579373152}],[82,{"iota_amount":227452230235124151,"pool_token_amount":225344903853984477}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":227418147227344030,"pool_token_amount":225341601681707308}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":35366235229697407,"pool_token_amount":35101408355847458}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":35335635512230172,"pool_token_amount":35095654822793532}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":35324523339277213,"pool_token_amount":35094155028242909}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":35313455985824558,"pool_token_amount":35092700596751841}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":35290717854026524,"pool_token_amount":35089188620600728}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":35274495285735541,"pool_token_amount":35087480527576910}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":35263826265629940,"pool_token_amount":35086420107864466}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":35253157328816786,"pool_token_amount":35085358509259351}],[46,{"iota_amount":35248749163291111,"pool_token_amount":35095307685875763}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":35227185584149274,"pool_token_amount":35092958037959521}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":35200644447289464,"pool_token_amount":35091140691570459}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":35159752689687761,"pool_token_amount":35087408140840125}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":25069117160534757,"pool_token_amount":25045377211693528}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":25048370994433130,"pool_token_amount":25030656722899593}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":25000000032208364,"pool_token_amount":25000000000000000}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":25000000019836964,"pool_token_amount":25000000000000000}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":25000000000550800,"pool_token_amount":25000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Parasol":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":28105228053244035,"pool_token_amount":27536160498788316}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":28091871431126661,"pool_token_amount":27538887772305042}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":28084444517315103,"pool_token_amount":27538006615920671}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":28076626338269187,"pool_token_amount":27536914058787744}],[156,{"iota_amount":28072817536635842,"pool_token_amount":27536465788136761}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":28069008540177744,"pool_token_amount":27536017441004312}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":28057214563343112,"pool_token_amount":27534313298563638}],[151,{"iota_amount":28056547857180506,"pool_token_amount":27536949195700017}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"iota_amount":28038251873682442,"pool_token_amount":27535187593397500}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":28033044295129726,"pool_token_amount":27536493663106548}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":28112681500505769,"pool_token_amount":27637267823656994}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":28105254831322450,"pool_token_amount":27636393384224769}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":28101541617485369,"pool_token_amount":27635955231494465}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":28082871194658214,"pool_token_amount":27624022283627387}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":28075027212001431,"pool_token_amount":27638821378783803}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":28067632996623100,"pool_token_amount":27637975437091059}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":28063930052036571,"pool_token_amount":27637546560962875}],[121,{"iota_amount":28060218895940668,"pool_token_amount":27637108867598263}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":28056864329134685,"pool_token_amount":27637021295062126}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":28049608378034057,"pool_token_amount":27639524364416735}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":28042619156010909,"pool_token_amount":27639072060199247}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":27934111927294777,"pool_token_amount":27541782108832332}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":27927405829933619,"pool_token_amount":27538389814066462}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":27907353000476612,"pool_token_amount":27536249737794829}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":27910376229811811,"pool_token_amount":27547552541928937}],[102,{"iota_amount":27900291883127294,"pool_token_amount":27545903541431180}],[101,{"iota_amount":27896034058972133,"pool_token_amount":27545819485371256}],[99,{"iota_amount":27887065845130865,"pool_token_amount":27545174256178643}],[97,{"iota_amount":27874411977067631,"pool_token_amount":27540847686972144}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":27849381322636822,"pool_token_amount":27540420751151143}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":27840674866615040,"pool_token_amount":27539867947540308}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":27787719911747577,"pool_token_amount":27511537907946286}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":27762247029114079,"pool_token_amount":27506399198940400}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":27714901158552257,"pool_token_amount":27504817043634705}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":27679811355469954,"pool_token_amount":27502418996315286}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":27657768377537697,"pool_token_amount":27500536588739527}],[53,{"iota_amount":27653383522729181,"pool_token_amount":27500184345552557}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":27643370837573201,"pool_token_amount":27498242771149748}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"iota_amount":27625325241828109,"pool_token_amount":27496326140878180}],[45,{"iota_amount":27617205990063838,"pool_token_amount":27496266505492534}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":27591776099166270,"pool_token_amount":27495455437639117}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":27587510786321686,"pool_token_amount":27495331366010997}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":27551706625148448,"pool_token_amount":27490620328339613}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":27547028803693176,"pool_token_amount":27490518189373048}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":27032327474120123,"pool_token_amount":26990832958257579}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":20014778685211770,"pool_token_amount":20000925844348894}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":20000000025396901,"pool_token_amount":20000000000507924}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":20000000015774701,"pool_token_amount":20000000000315481}],[17,{"iota_amount":20000000012328401,"pool_token_amount":20000000000246557}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":20000000000428400,"pool_token_amount":20000000000008567}]],"Peeranha":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":35758894183310856,"pool_token_amount":35059584722303078}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":35740154577996887,"pool_token_amount":35058114604866237}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":35730531615214034,"pool_token_amount":35057359411338561}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":35712760133772216,"pool_token_amount":35048608597983111}],[154,{"iota_amount":35707948301428097,"pool_token_amount":35048230809827779}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":35674249429866097,"pool_token_amount":35045573157131616}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":35600706280581514,"pool_token_amount":35038081533126534}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":35586347929643986,"pool_token_amount":35036952729338780}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":35576910378190902,"pool_token_amount":35036211162652818}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":35553334979475706,"pool_token_amount":35034357003091252}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":35534477539224661,"pool_token_amount":35032870155426745}],[117,{"iota_amount":91735889242077333,"pool_token_amount":39881683429017994}],[116,{"iota_amount":35524858921441345,"pool_token_amount":35032118752807723}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":35520545617559264,"pool_token_amount":35032232381766662}],[114,{"iota_amount":35515803294599231,"pool_token_amount":35031922731963921}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":35511012519884878,"pool_token_amount":35031565582343472}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":35506218573566429,"pool_token_amount":35031205400529076}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":35496008901754460,"pool_token_amount":35029872980269025}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[97,{"iota_amount":35424606144160149,"pool_token_amount":35023537077944574}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":35403007903923037,"pool_token_amount":35021849424684213}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":35397702072264658,"pool_token_amount":35021431359272768}],[90,{"iota_amount":35387125626202785,"pool_token_amount":35020595091092075}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":35376572869390470,"pool_token_amount":35019759556506773}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":35355203441000764,"pool_token_amount":35017747773056079}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":35344640004056391,"pool_token_amount":35016919848256162}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":35323442580813547,"pool_token_amount":35015187493469136}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[75,{"iota_amount":35307547006622099,"pool_token_amount":35013926782957597}],[74,{"iota_amount":35302080761635434,"pool_token_amount":35013373602220286}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":35291078870419226,"pool_token_amount":35012501511453523}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":35285521767611921,"pool_token_amount":35012060452512747}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":35268844737064485,"pool_token_amount":35010734612118056}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":35241547224458920,"pool_token_amount":35008502228175824}],[62,{"iota_amount":35236321928389634,"pool_token_amount":35008085140956805}],[61,{"iota_amount":35230987206660724,"pool_token_amount":35007661127587170}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":35214952671244891,"pool_token_amount":35006358888327130}],[57,{"iota_amount":35209602159102672,"pool_token_amount":35005918750020835}],[56,{"iota_amount":35204267008185572,"pool_token_amount":35005494406998279}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":35188102590145810,"pool_token_amount":35004062887966901}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":35182496140752505,"pool_token_amount":35003368701807392}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":35171923464700508,"pool_token_amount":35002615254084999}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":35133989981184742,"pool_token_amount":34999051598883865}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"iota_amount":35123291162317273,"pool_token_amount":34998172737625768}],[40,{"iota_amount":35117843997705116,"pool_token_amount":34997737600067856}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":35054492355530874,"pool_token_amount":34992633808071220}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":35041902797559540,"pool_token_amount":34991493278221693}],[25,{"iota_amount":25031167537251109,"pool_token_amount":25004352851489906}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":25000000019248364,"pool_token_amount":25000000000384956}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Persimmon":[[164,{"iota_amount":112227683037367362,"pool_token_amount":110219866592942141}],[163,{"iota_amount":112212848044823513,"pool_token_amount":110218409633966776}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":112168361201187388,"pool_token_amount":110214040384139651}],[159,{"iota_amount":112153082745924805,"pool_token_amount":110212592250579525}],[158,{"iota_amount":112137746331489804,"pool_token_amount":110211085144072776}],[157,{"iota_amount":112122401453904101,"pool_token_amount":110209569855531985}],[156,{"iota_amount":112107066017044711,"pool_token_amount":110208062474042964}],[155,{"iota_amount":112091729795857642,"pool_token_amount":110206554829842020}],[152,{"iota_amount":112045633103266527,"pool_token_amount":110201949563954170}],[146,{"iota_amount":111954084150651889,"pool_token_amount":110192941661678562}],[145,{"iota_amount":111938926279742138,"pool_token_amount":110191449718713516}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":111863192236624004,"pool_token_amount":110183997214292913}],[136,{"iota_amount":111802547348269505,"pool_token_amount":110178022664719383}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":111787394297749332,"pool_token_amount":110176529377012610}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":111772240372724398,"pool_token_amount":110175035820938328}],[133,{"iota_amount":111757084156599136,"pool_token_amount":110173541856771525}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":111741926151803171,"pool_token_amount":110172047533916426}],[130,{"iota_amount":111713320426136078,"pool_token_amount":110170749562640274}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":111606106091983701,"pool_token_amount":110158648006646530}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":111576024232726264,"pool_token_amount":110155696425068691}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":111530569363589453,"pool_token_amount":110151190480703361}],[115,{"iota_amount":111485142945264110,"pool_token_amount":110146703472966633}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":111454860063083419,"pool_token_amount":110143713785461507}],[112,{"iota_amount":111439716183370166,"pool_token_amount":110142217212247030}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":111392585360485755,"pool_token_amount":110137558412981767}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":111358810039405209,"pool_token_amount":110134224098524191}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":111306070949162748,"pool_token_amount":110128791996608064}],[101,{"iota_amount":111253657870930831,"pool_token_amount":110123606276422893}],[99,{"iota_amount":111219032062719251,"pool_token_amount":110120178621905145}],[97,{"iota_amount":111184581204658067,"pool_token_amount":110116769120924392}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":111065073303964671,"pool_token_amount":110104840784559689}],[88,{"iota_amount":111031394295129591,"pool_token_amount":110101501772695079}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":111014568925803947,"pool_token_amount":110099834224206812}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":110863498586347382,"pool_token_amount":110084945178590118}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":110830146749414945,"pool_token_amount":110081631405103542}],[72,{"iota_amount":110762123888928727,"pool_token_amount":110074870983042892}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":110727005700839138,"pool_token_amount":110071388816803774}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":110656095774589185,"pool_token_amount":110064338285972802}],[65,{"iota_amount":110638614640091332,"pool_token_amount":110062868193081271}],[60,{"iota_amount":110555058643750240,"pool_token_amount":110054374710059572}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":110538289477447614,"pool_token_amount":110052615795473233}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":110471379015976413,"pool_token_amount":110045850638640449}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":110437798651186561,"pool_token_amount":110042493658894013}],[52,{"iota_amount":110421014216654574,"pool_token_amount":110040821223313695}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"iota_amount":110319988540272170,"pool_token_amount":110030748189089607}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[41,{"iota_amount":110236973211213625,"pool_token_amount":110023967832868463}],[39,{"iota_amount":110202741139117584,"pool_token_amount":110020551901244503}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[33,{"iota_amount":110094964850204691,"pool_token_amount":110009727906822850}],[31,{"iota_amount":110057570637844902,"pool_token_amount":110005982016592208}],[30,{"iota_amount":110038784151262396,"pool_token_amount":110004104248529913}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}]],"Qredo":[[167,{"iota_amount":27599107811630911,"pool_token_amount":27058723875922703}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":27595498756964254,"pool_token_amount":27058370036516572}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":27591890475148197,"pool_token_amount":27058016231275616}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":27588281432178205,"pool_token_amount":27057662309719039}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":27577360306807787,"pool_token_amount":27056502784447443}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":27544796417047322,"pool_token_amount":27053939547162182}],[148,{"iota_amount":27529959444853492,"pool_token_amount":27052482023197506}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":27510159761668195,"pool_token_amount":27049175048019860}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":27502938562293733,"pool_token_amount":27048464985708973}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":27488489199243800,"pool_token_amount":27047048146695410}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":27477651438145127,"pool_token_amount":27045984306455959}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":27464515975774454,"pool_token_amount":27042658640711101}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":27461305301950217,"pool_token_amount":27042700474238432}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":27447971639082239,"pool_token_amount":27042385303753672}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":27444359878260398,"pool_token_amount":27042029464185640}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":27437134771008295,"pool_token_amount":27041316615532141}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":27429908324044875,"pool_token_amount":27040602578885700}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":27394481133804883,"pool_token_amount":27034503140709555}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":27387257779722297,"pool_token_amount":27033789277101706}],[109,{"iota_amount":27383230655651339,"pool_token_amount":27033380311076653}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":27371169854306997,"pool_token_amount":27032466162998719}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"iota_amount":27350129740134709,"pool_token_amount":27030437759135852}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":27313218252081368,"pool_token_amount":27027224562043597}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":27288951821799689,"pool_token_amount":27024816837539144}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":27284806368104000,"pool_token_amount":27024292542209565}],[84,{"iota_amount":27280801606684136,"pool_token_amount":27023897686337208}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":27276110027113460,"pool_token_amount":27022822371624461}],[82,{"iota_amount":27272094120287115,"pool_token_amount":27022416455073403}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":27267310736697625,"pool_token_amount":27021249687187487}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":27263909930206789,"pool_token_amount":27021651834861810}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":27235421383449975,"pool_token_amount":27018505050122596}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":27226972701093915,"pool_token_amount":27017665066677253}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":27194179871560463,"pool_token_amount":27015398134428427}],[61,{"iota_amount":27185625007739984,"pool_token_amount":27014053784763418}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":27181624187361666,"pool_token_amount":27013657127064800}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":27168944730890429,"pool_token_amount":27011791261843452}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":27152127916385030,"pool_token_amount":27009591688927958}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":27143907117106444,"pool_token_amount":27008777459760939}],[50,{"iota_amount":27139794231337740,"pool_token_amount":27008367323166028}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":27135660069296138,"pool_token_amount":27007936137062748}],[48,{"iota_amount":27130593672870713,"pool_token_amount":27006577410664521}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":27113919772079627,"pool_token_amount":27004714396463452}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":27087984195364060,"pool_token_amount":27001000872703755}],[37,{"iota_amount":27083752651983053,"pool_token_amount":27000577282926805}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":27074939798215303,"pool_token_amount":26999587348485205}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":27034349053275831,"pool_token_amount":26992853096947182}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":20000000000527000,"pool_token_amount":20000000000010533}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"QuantNode":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":27584178708123104,"pool_token_amount":27058590379361670}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":27562256673518819,"pool_token_amount":27056462570033452}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":27554841344744369,"pool_token_amount":27055736368186019}],[154,{"iota_amount":27551132223868984,"pool_token_amount":27055372174060122}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":27547285860004702,"pool_token_amount":27054873306438337}],[149,{"iota_amount":27532431488476590,"pool_token_amount":27053398739410541}],[148,{"iota_amount":27526746132210402,"pool_token_amount":27051092652392961}],[145,{"iota_amount":27515708975491280,"pool_token_amount":27050007876419024}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":27512095197606132,"pool_token_amount":27049652614309482}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":27479047711490971,"pool_token_amount":27036330883070778}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":27449748567997737,"pool_token_amount":27033110918164541}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":27443534972742359,"pool_token_amount":27043013946484426}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":27413869864191389,"pool_token_amount":27029794688786512}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":27410259039251653,"pool_token_amount":27029438664773628}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":27403038270963458,"pool_token_amount":27028726577097304}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":27396009092377394,"pool_token_amount":27028202725973182}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":27388786680788512,"pool_token_amount":27027488362219339}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":27378005553916819,"pool_token_amount":27026470167206828}],[109,{"iota_amount":27373981319340064,"pool_token_amount":27026064025983141}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":27345259385703128,"pool_token_amount":27023559067487466}],[99,{"iota_amount":27332631663794315,"pool_token_amount":27022310970765038}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":27307668257664995,"pool_token_amount":27019845685944340}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":27299547583990550,"pool_token_amount":27019043014821838}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":27287428914813513,"pool_token_amount":27017852418455666}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":27279353698265701,"pool_token_amount":27017052820401389}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":27263370644235871,"pool_token_amount":27015518685246700}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":27255116716194683,"pool_token_amount":27014684685477184}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":27247148038159528,"pool_token_amount":27013930650453094}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":27235064948176851,"pool_token_amount":27012662915016780}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":27226949264994893,"pool_token_amount":27011856134462129}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":27181644059518491,"pool_token_amount":27008289905212821}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":27144145998919972,"pool_token_amount":27003429726485459}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":27135919189343523,"pool_token_amount":27002609463593674}],[50,{"iota_amount":27131807303574819,"pool_token_amount":27002200295045777}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":27123561730979871,"pool_token_amount":27001360808233130}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":27102628393612395,"pool_token_amount":26998941162758177}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"iota_amount":27089788534258292,"pool_token_amount":26997211441934633}],[39,{"iota_amount":27085565714860988,"pool_token_amount":26996691582657661}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":27077222051078338,"pool_token_amount":26995859896355301}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":27072978018171919,"pool_token_amount":26995435870948281}],[35,{"iota_amount":27068561226098944,"pool_token_amount":26995021490536900}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":27059384431074923,"pool_token_amount":26994051475202143}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":27054694043644871,"pool_token_amount":26993471702404773}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":20032535617404197,"pool_token_amount":20002790034527758}],[26,{"iota_amount":20028489960849676,"pool_token_amount":20002347428849774}],[24,{"iota_amount":20019713178904400,"pool_token_amount":20001278877477511}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":20015043495211770,"pool_token_amount":20001190470087279}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"iota_amount":20000000012328401,"pool_token_amount":20000000000246557}],[16,{"iota_amount":20000000007017893,"pool_token_amount":20000000000140348}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":20000000000000000,"pool_token_amount":20000000000000000}]],"RepublicCrypto":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":27518394127507575,"pool_token_amount":27002626099761244}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":27511073067126818,"pool_token_amount":27001905047644859}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":27492528915835205,"pool_token_amount":27000084509766762}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":27488560151970923,"pool_token_amount":26999465392784663}],[152,{"iota_amount":27484784639491233,"pool_token_amount":26999036056515951}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":27437272211411380,"pool_token_amount":26991018583311625}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":27453709430673486,"pool_token_amount":27013589026104062}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":27439201795195527,"pool_token_amount":27012116986496014}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":27428360250380923,"pool_token_amount":27011049578550259}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":27417512450030962,"pool_token_amount":27009981174517965}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":27413899667232716,"pool_token_amount":27009626164828883}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":27385005526819903,"pool_token_amount":27006778175512439}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":27374164898342820,"pool_token_amount":27005700126390502}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":27286617867340238,"pool_token_amount":26997419556264862}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":27274522069082917,"pool_token_amount":26996303707021622}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":27262208344662218,"pool_token_amount":26994919952538944}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":27250113020474940,"pool_token_amount":26993720060432218}],[84,{"iota_amount":27246097244419589,"pool_token_amount":26993314237854970}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":27234000202662398,"pool_token_amount":26992046956064731}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":27229769758210700,"pool_token_amount":26991626777986109}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":27230094522354776,"pool_token_amount":27002668417978373}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":27222631199291328,"pool_token_amount":27002408679052580}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":27214501516245364,"pool_token_amount":27001587947935496}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":27193063623700910,"pool_token_amount":26999275412290430}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":27184396566623173,"pool_token_amount":26998415715910099}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":27172074058231472,"pool_token_amount":26997203802513422}],[61,{"iota_amount":27164078727035926,"pool_token_amount":26996415207245318}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":27159962901136190,"pool_token_amount":26995904198310273}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":27154651301220999,"pool_token_amount":26994203473907275}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":27118243039153853,"pool_token_amount":26990723640875579}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":27114129952793787,"pool_token_amount":26990313370583526}],[47,{"iota_amount":27118002721444452,"pool_token_amount":27001538161967465}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":27080602536551803,"pool_token_amount":26997463722009625}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":27045211816627500,"pool_token_amount":26994224996840980}],[29,{"iota_amount":27040538101686602,"pool_token_amount":26993756709836426}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":27035856256303972,"pool_token_amount":26993290235514122}],[26,{"iota_amount":20028084520041390,"pool_token_amount":20003446259403312}],[25,{"iota_amount":20024005503451592,"pool_token_amount":20003171079883520}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":20014574675222270,"pool_token_amount":20001852252391789}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":20000000015785201,"pool_token_amount":20000000001578507}],[18,{"iota_amount":20000000015327401,"pool_token_amount":20000000001532728}],[17,{"iota_amount":20000000012338901,"pool_token_amount":20000000001233879}],[16,{"iota_amount":20000000007028393,"pool_token_amount":20000000000702830}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":20000000000537500,"pool_token_amount":20000000000053743}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":20000000000460100,"pool_token_amount":20000000000046005}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":20000000000460100,"pool_token_amount":20000000000046005}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":20000000000460100,"pool_token_amount":20000000000046005}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":20000000000460100,"pool_token_amount":20000000000046005}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000451500,"pool_token_amount":20000000000045147}],[4,{"iota_amount":20000000000451500,"pool_token_amount":20000000000045147}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Restake":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":35717582725975671,"pool_token_amount":35007219033944051}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":35703413994984135,"pool_token_amount":35005937839805020}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":35698703306827391,"pool_token_amount":35005522159738621}],[161,{"iota_amount":35694096650674716,"pool_token_amount":35005114718663386}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":35655478328876849,"pool_token_amount":35001413777721165}],[152,{"iota_amount":35650635236768091,"pool_token_amount":35000958219030582}],[150,{"iota_amount":35641011649457129,"pool_token_amount":35000107826835567}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":35625205569842308,"pool_token_amount":34997399381212711}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":35601176885340147,"pool_token_amount":34995230593969343}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":35604544504016375,"pool_token_amount":35006978275899326}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":35580991263551123,"pool_token_amount":35004928920783392}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":35571458650580629,"pool_token_amount":35004086638446579}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":35554309153394555,"pool_token_amount":35004295058928420}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":35525330041841593,"pool_token_amount":35001120116466332}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":35515884202875397,"pool_token_amount":35000270002985383}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":35501926603725040,"pool_token_amount":34999197277182035}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[103,{"iota_amount":35441922477589680,"pool_token_amount":35007702862211387}],[102,{"iota_amount":35436489411883104,"pool_token_amount":35007168893471447}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":35405019251432707,"pool_token_amount":35004847949929551}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":35367239132873658,"pool_token_amount":35000717729347229}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":35356797552731012,"pool_token_amount":34999777565974945}],[86,{"iota_amount":35351743308628229,"pool_token_amount":34999469832131043}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":35345709285561347,"pool_token_amount":34998169807947148}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":35334418857184595,"pool_token_amount":34996313471800797}],[82,{"iota_amount":35329203780680881,"pool_token_amount":34995811323877697}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":35317882424665424,"pool_token_amount":34994122020282344}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":35304788969244336,"pool_token_amount":34999792715827689}],[74,{"iota_amount":35294650050199905,"pool_token_amount":34999063146874409}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":35283647145321490,"pool_token_amount":34997971994591947}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":35278087042514185,"pool_token_amount":34997417807920068}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":35255814551423449,"pool_token_amount":34995171218703469}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":35244905840822630,"pool_token_amount":34994270915479394}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"iota_amount":35221680559966033,"pool_token_amount":34995330436387159}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":35216313439817731,"pool_token_amount":34995032670618110}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":35190668192976831,"pool_token_amount":34994624547421400}],[53,{"iota_amount":35185114605386545,"pool_token_amount":34994142476951964}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":35164100370475282,"pool_token_amount":34993404481729347}],[48,{"iota_amount":35158766254209608,"pool_token_amount":34993140017057700}],[47,{"iota_amount":35153499914264973,"pool_token_amount":34992942224866677}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":35103421153391202,"pool_token_amount":34988705878533004}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":35094727543853031,"pool_token_amount":34990491700264662}],[35,{"iota_amount":35088894008249016,"pool_token_amount":34990149742164635}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":35082997652691813,"pool_token_amount":34989851017398974}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":35054517425779291,"pool_token_amount":34989478071084203}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":35048373126142559,"pool_token_amount":34989160049621319}],[24,{"iota_amount":25028874952704661,"pool_token_amount":25005890002660342}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":25015591324167687,"pool_token_amount":25004031152199461}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":25000000019248364,"pool_token_amount":25000000000384956}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":25000000000572400,"pool_token_amount":25000000000011444}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Scale3Labs":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":107222357865350365,"pool_token_amount":105000494150105556}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":107208122197127154,"pool_token_amount":104999797115882505}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":107107607234778958,"pool_token_amount":104994974581276331}],[156,{"iota_amount":107092912419194197,"pool_token_amount":104994197525443621}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":107048765814818858,"pool_token_amount":104991810120249031}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"iota_amount":106960093485371249,"pool_token_amount":104986486418307666}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":106857121484892416,"pool_token_amount":104979712216431345}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":106828217467246334,"pool_token_amount":104978293248557867}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":106731822099801048,"pool_token_amount":104991543728152811}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":106717355226093962,"pool_token_amount":104990832178079217}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":106688689784414561,"pool_token_amount":104989661105188292}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":106659744254927597,"pool_token_amount":104988190987957248}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":106630877595296484,"pool_token_amount":104986798023813915}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":106588554165550386,"pool_token_amount":104985665450931528}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":106574110867059171,"pool_token_amount":104984954145595697}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":107703402117528133,"pool_token_amount":106179773178117190}],[112,{"iota_amount":107688739690771181,"pool_token_amount":106179031696277629}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":107609365432363324,"pool_token_amount":106205752690152651}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":107576138953245047,"pool_token_amount":106204779608852885}],[99,{"iota_amount":107508990047880501,"pool_token_amount":106201481199547936}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":107406855753509742,"pool_token_amount":106194206153868299}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":107283263515989368,"pool_token_amount":106194371837270365}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":107250116810080593,"pool_token_amount":106192017672419437}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":107149833228810307,"pool_token_amount":106199464807713232}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":107133711537584103,"pool_token_amount":106198660223290785}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":111517071077289884,"pool_token_amount":110677010907401348}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":111499179484097641,"pool_token_amount":110676123067593298}],[66,{"iota_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":111446346849820957,"pool_token_amount":110672201666522711}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":111378371772431070,"pool_token_amount":110668027709242495}],[58,{"iota_amount":126436300717398597,"pool_token_amount":125650408066685002}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":126438128399750527,"pool_token_amount":125688325522154968}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":126380230194459064,"pool_token_amount":125685247119390386}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":126361301551419031,"pool_token_amount":125684590507196072}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":126306520836068722,"pool_token_amount":125684605634841908}],[45,{"iota_amount":126237539863274624,"pool_token_amount":125688983548105860}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":126198957695699504,"pool_token_amount":125687149871855832}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":126159950446736197,"pool_token_amount":125685107639431452}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":126127670238763111,"pool_token_amount":125690083491351270}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":126088085226035135,"pool_token_amount":125688023995415001}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":126067999650383527,"pool_token_amount":125687035218797835}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":125981750441425048,"pool_token_amount":125681834621982432}],[32,{"iota_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":125920519088971911,"pool_token_amount":125682184437956645}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":100878348090299029,"pool_token_amount":100722094039367962}],[24,{"iota_amount":80120676710549734,"pool_token_amount":80045819984284639}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80039431872812636,"pool_token_amount":80002248108640848}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":80000000001754400,"pool_token_amount":80000000000035087}]],"SenseiNode":[[167,{"iota_amount":27162396517391731,"pool_token_amount":26619852612617942}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":27151855870666605,"pool_token_amount":26619012580476678}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":27148347595093622,"pool_token_amount":26618737425935374}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":27134011764523766,"pool_token_amount":26617426885116120}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":27130403196100028,"pool_token_amount":26617143695337453}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":27115968806450440,"pool_token_amount":26616010580394867}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"iota_amount":27093952870227529,"pool_token_amount":26613954423592405}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":27090352788916733,"pool_token_amount":26613681620634691}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":27079298743478046,"pool_token_amount":26612618379435326}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":27054655694904172,"pool_token_amount":26614531917711992}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":27036997990896381,"pool_token_amount":26613512550813873}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":27026150205630873,"pool_token_amount":26612658227676292}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":27011858579862503,"pool_token_amount":26611675835663857}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":27008246656864246,"pool_token_amount":26611391162253864}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":26997410585034461,"pool_token_amount":26610536001328247}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":26993799760094725,"pool_token_amount":26610251274417663}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":26990189054720514,"pool_token_amount":26609966521907753}],[116,{"iota_amount":26982969079130202,"pool_token_amount":26609397024984589}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":26965302283502734,"pool_token_amount":26608351953044323}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":26961690472049869,"pool_token_amount":26608066832580332}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":26949617108700187,"pool_token_amount":26607084555729423}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":26945498221308261,"pool_token_amount":26606759229573203}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":26928623196264628,"pool_token_amount":26605287826864003}],[98,{"iota_amount":27921532955999946,"pool_token_amount":27601962771733221}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":27913128883057364,"pool_token_amount":27601298092163681}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":27871041910068049,"pool_token_amount":27597584367591736}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":27833762954518448,"pool_token_amount":27594536848853596}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":27825538158344935,"pool_token_amount":27593883563842005}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":27817200682349386,"pool_token_amount":27593220704394446}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":27808529718879052,"pool_token_amount":27592530738187915}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":27804093609044404,"pool_token_amount":27592087322151683}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":27791095195350465,"pool_token_amount":27591060770612979}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":27786761206724211,"pool_token_amount":27590716547130030}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":27774213930399436,"pool_token_amount":27589729767151923}],[62,{"iota_amount":27770080973918336,"pool_token_amount":27589382135138947}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":27753101025248712,"pool_token_amount":27587546650447791}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":27740791811017396,"pool_token_amount":27586593007136325}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":27718718830117940,"pool_token_amount":27583453292628092}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":27714100743757874,"pool_token_amount":27582622400298940}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":27649415410565028,"pool_token_amount":27576575748696065}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":27640034913333078,"pool_token_amount":27575796218381600}],[31,{"iota_amount":27635161034796068,"pool_token_amount":27575219052618349}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"iota_amount":20032226211314164,"pool_token_amount":20005568803634186}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":20018800856834969,"pool_token_amount":20004946069801195}],[22,{"iota_amount":20013666061485663,"pool_token_amount":20004504611660062}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":20000000000550400,"pool_token_amount":20000000000011000}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Shinlabs":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":139611708560290726,"pool_token_amount":136763299300037560}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":139524795178930598,"pool_token_amount":136765082773353556}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":132868400714405272,"pool_token_amount":130307934356827088}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[149,{"iota_amount":132781302015114272,"pool_token_amount":130307043169385011}],[148,{"iota_amount":132764154217177886,"pool_token_amount":130307038885608840}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"iota_amount":132723021619968019,"pool_token_amount":130300153588652790}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":132688780612661779,"pool_token_amount":130300054896609656}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":132654716863609162,"pool_token_amount":130300099514534420}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":139223886130366403,"pool_token_amount":136788748772952893}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":139117847397577901,"pool_token_amount":136789792169450744}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":139080456341026962,"pool_token_amount":136788188188768743}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":139044692193630716,"pool_token_amount":136788191997471619}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":139026856803332103,"pool_token_amount":136788204030916513}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":138991194732180944,"pool_token_amount":136788221359484758}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":138974304790193155,"pool_token_amount":136789142884538911}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":138919887852746577,"pool_token_amount":136788213032796344}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":138902052155119590,"pool_token_amount":136788204783564201}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":138622774492862190,"pool_token_amount":136706713066975721}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":138584152847581472,"pool_token_amount":136705737655804546}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":138564357981472328,"pool_token_amount":136705748814406209}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":138545423046159958,"pool_token_amount":136706817754025842}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":138503004218615786,"pool_token_amount":136705748832838246}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":138482287567639454,"pool_token_amount":136705762772910618}],[102,{"iota_amount":138440833821224606,"pool_token_amount":136705751042294063}],[97,{"iota_amount":138338899111063414,"pool_token_amount":136705748561542417}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":138278904774575410,"pool_token_amount":136706767783363885}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":138098774532810181,"pool_token_amount":136705887887785280}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":138039470627260157,"pool_token_amount":136705901230469171}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":138019740809129886,"pool_token_amount":136705942052512369}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":137529392656175494,"pool_token_amount":136459732738741750}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":137465471371773456,"pool_token_amount":136458531816196650}],[65,{"iota_amount":137444500652830732,"pool_token_amount":136458465783626606}],[64,{"iota_amount":137424863545067882,"pool_token_amount":136458466000488595}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":137226744346358137,"pool_token_amount":136457270916167311}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":137147067434472997,"pool_token_amount":136456998121301762}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":137127220941503317,"pool_token_amount":136457000918202124}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":137028423748931730,"pool_token_amount":136457551057041109}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":136988519637787407,"pool_token_amount":136457557620659479}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"iota_amount":136948199951125878,"pool_token_amount":136457468949489798}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":136907421409009929,"pool_token_amount":136457246144819479}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":111830157316270752,"pool_token_amount":111531576637886176}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80038347680691165,"pool_token_amount":80001732175825940}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019059452971536,"pool_token_amount":80000435085770481}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000102695557,"pool_token_amount":80000000002053897}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":80000000063519457,"pool_token_amount":80000000001270376}],[17,{"iota_amount":80000000049632057,"pool_token_amount":80000000000992630}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002203900,"pool_token_amount":80000000000044070}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840600,"pool_token_amount":80000000000036807}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":80000000001754400,"pool_token_amount":80000000000035087}]],"SpartanLabs":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":27547245658401028,"pool_token_amount":27020192382591089}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":27532661014212797,"pool_token_amount":27018628855789878}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":27508749939811092,"pool_token_amount":27017912889657129}],[154,{"iota_amount":27505782726472684,"pool_token_amount":27018277353467790}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":27501905792608402,"pool_token_amount":27017748320275127}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":27481169500422208,"pool_token_amount":27017056075393402}],[146,{"iota_amount":27477315530442539,"pool_token_amount":27016462622509627}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":27464311563245603,"pool_token_amount":27016462435563941}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":27460204513163930,"pool_token_amount":27018817863562819}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":27446182802874414,"pool_token_amount":27017824936923604}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":27421822133932454,"pool_token_amount":27016257663738559}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":27418407863150306,"pool_token_amount":27016100634346458}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":27409285739967418,"pool_token_amount":27016723472926903}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":27405671805713572,"pool_token_amount":27016365702591967}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":27387469390511232,"pool_token_amount":27014442737013479}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":27378109384114359,"pool_token_amount":27014825460864941}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":27371789843658988,"pool_token_amount":27015001822001450}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":27357285047911629,"pool_token_amount":27013515285971014}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":27336617859745926,"pool_token_amount":27011394293353707}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":27294864112060036,"pool_token_amount":27010060577625171}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":27290799983694214,"pool_token_amount":27009578842830244}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":27282655382139453,"pool_token_amount":27008591615361461}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":27274582318646288,"pool_token_amount":27007646484437601}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":27268975428160200,"pool_token_amount":27009133863609751}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":27245903917334874,"pool_token_amount":27007272553179504}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":27232258655720258,"pool_token_amount":27004421819445083}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":27229667631986378,"pool_token_amount":27005346382791867}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":27221185127402517,"pool_token_amount":27003917039132501}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":27214364252608477,"pool_token_amount":27004233853416931}],[72,{"iota_amount":27209597423387684,"pool_token_amount":27003191624293027}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":27190714086188016,"pool_token_amount":27003090182651467}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":27178984156569400,"pool_token_amount":27002513283122167}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":27166831235553724,"pool_token_amount":27000933047429690}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":27164074351931425,"pool_token_amount":27001693348214883}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":27155969779147988,"pool_token_amount":27000636450881459}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":27141737389968610,"pool_token_amount":26996987571772358}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":27137624127045613,"pool_token_amount":26996495737286529}],[53,{"iota_amount":27133116272237097,"pool_token_amount":26995611815540298}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":27114040991149295,"pool_token_amount":27005441304503609}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":27105504296605873,"pool_token_amount":27004146689362894}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":27076433352218195,"pool_token_amount":27000639615277626}],[35,{"iota_amount":27071987531276152,"pool_token_amount":27000107589839493}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":20004670735991001,"pool_token_amount":20000096332686800}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":20000000000539900,"pool_token_amount":20000000000010790}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":20000000000445300,"pool_token_amount":20000000000008902}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":20000000000000000,"pool_token_amount":20000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"StakeWithUs":[[167,{"iota_amount":35729691752167733,"pool_token_amount":34991691318695007}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":35710596199938210,"pool_token_amount":34990523462019824}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":35729749900219522,"pool_token_amount":35017966599669879}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":35722739167915772,"pool_token_amount":35019869853643073}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":35711566205132919,"pool_token_amount":35017878638762219}],[156,{"iota_amount":35706755087392962,"pool_token_amount":35017642755209708}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":35687267870579759,"pool_token_amount":35016463469652879}],[149,{"iota_amount":35672796306242455,"pool_token_amount":35015720056891954}],[148,{"iota_amount":35667984146630429,"pool_token_amount":35015483880345763}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":35663165136334697,"pool_token_amount":35015243606678772}],[145,{"iota_amount":35653627783207483,"pool_token_amount":35014771657611839}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":35642207505964691,"pool_token_amount":35017034788668077}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":35618425028988118,"pool_token_amount":35015869493881207}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":35600150042070455,"pool_token_amount":35015621205025248}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":35595331603064336,"pool_token_amount":35015384238298189}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":35585795077487345,"pool_token_amount":35014916625891468}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":35581020250208696,"pool_token_amount":35014632171605876}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":35565472042788744,"pool_token_amount":35016973847483581}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":35557726135716247,"pool_token_amount":35013758417460810}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":35553035676713734,"pool_token_amount":35013550971686829}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":35548319220400500,"pool_token_amount":35013318726791130}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":35524592625992763,"pool_token_amount":35012097782546485}],[116,{"iota_amount":35519779409223898,"pool_token_amount":35011860593223620}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":35514965855852814,"pool_token_amount":35011623356749379}],[114,{"iota_amount":35510152433589531,"pool_token_amount":35011386096196211}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":35507548640686428,"pool_token_amount":35013328026376711}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":35397607283699603,"pool_token_amount":35009662524794529}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":35324647948890487,"pool_token_amount":35001988393115768}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":35305378766695231,"pool_token_amount":34997650448005621}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"iota_amount":35294917965829435,"pool_token_amount":34997119688106960}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":35283939368822334,"pool_token_amount":34996598250727260}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":35272791849375334,"pool_token_amount":34996015875520173}],[69,{"iota_amount":35267210201203436,"pool_token_amount":34995717964211492}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":35239709615169573,"pool_token_amount":34994304822950869}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":35202983694291402,"pool_token_amount":34992328606109193}],[56,{"iota_amount":35197759692351585,"pool_token_amount":34992068969029724}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":35170267394573663,"pool_token_amount":34989825177688468}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":35154238340628952,"pool_token_amount":34989004090657681}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":35140039443149765,"pool_token_amount":34995047835089040}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":35111763311607658,"pool_token_amount":34992334126500570}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":35077642794641073,"pool_token_amount":34990565161358095}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":35071178517617621,"pool_token_amount":34989710025511554}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":35053441786161812,"pool_token_amount":34988875404574428}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"iota_amount":25035417722297042,"pool_token_amount":25002574712649377}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":25000000032208364,"pool_token_amount":25000000000644154}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"iota_amount":25000000015495364,"pool_token_amount":25000000000309897}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":25000000000556200,"pool_token_amount":25000000000011122}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":25000000000550800,"pool_token_amount":25000000000011015}]],"Staked":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":36949601339442825,"pool_token_amount":36157498663574861}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":36923039168832917,"pool_token_amount":36154666241495964}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":36682971076521228,"pool_token_amount":35957953831799029}],[152,{"iota_amount":36672313744059013,"pool_token_amount":35952226117725788}],[149,{"iota_amount":36623048972448322,"pool_token_amount":35918086638863669}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"iota_amount":36610561383988330,"pool_token_amount":35920010567189873}],[145,{"iota_amount":36605641592825814,"pool_token_amount":35920009587425340}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":36538889799577763,"pool_token_amount":35864155975761380}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":36506335985090428,"pool_token_amount":35861161371696829}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":36436740216906980,"pool_token_amount":35850289673319021}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":35994589679477176,"pool_token_amount":35434218051395270}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":36004792287292992,"pool_token_amount":35449005665954031}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":35979975845323287,"pool_token_amount":35429314404940052}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":35973962972015437,"pool_token_amount":35428137469376119}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":35948147390913741,"pool_token_amount":35416940650428408}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":35828817005253989,"pool_token_amount":35338824908677144}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":35826590474930167,"pool_token_amount":35347454059997940}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":35821168983204186,"pool_token_amount":35347604405296427}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":35803432143033672,"pool_token_amount":35341096820929709}],[101,{"iota_amount":35797899811889914,"pool_token_amount":35341090569486946}],[100,{"iota_amount":35792403004430765,"pool_token_amount":35341102451276759}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":35675525676224536,"pool_token_amount":35310632243800751}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":35661991272880647,"pool_token_amount":35307821705575196}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":35652407078778878,"pool_token_amount":35303623840096673}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":35601388196022417,"pool_token_amount":35300808583581360}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":35589982575904881,"pool_token_amount":35300301212394958}],[69,{"iota_amount":35384470054329079,"pool_token_amount":35101865277351566}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":35381295957482109,"pool_token_amount":35114928346295341}],[65,{"iota_amount":35376557559410719,"pool_token_amount":35115630269030643}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":35358029061210431,"pool_token_amount":35102427674138110}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":35340820856234910,"pool_token_amount":35100914023964529}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":35313765423063737,"pool_token_amount":35084431436784669}],[57,{"iota_amount":35286280538236279,"pool_token_amount":35067513096334982}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":35253811855045489,"pool_token_amount":35061332420217571}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":35246366328619940,"pool_token_amount":35059126921411452}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":35186469337314982,"pool_token_amount":35041145731854890}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":35180236913437407,"pool_token_amount":35040145761593312}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"iota_amount":35191026240440461,"pool_token_amount":35061527793948450}],[39,{"iota_amount":35182345110274014,"pool_token_amount":35058196225490404}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":35177013853902416,"pool_token_amount":35058313023837521}],[37,{"iota_amount":35171316973611639,"pool_token_amount":35057962139031474}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":35165771071166302,"pool_token_amount":35057887765722777}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":35126902103848439,"pool_token_amount":35036297323031852}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":35106194827453728,"pool_token_amount":35045240623781731}],[27,{"iota_amount":35103941465434498,"pool_token_amount":35049411290733502}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":25000000032208364,"pool_token_amount":25000000000644154}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":25000000000000000,"pool_token_amount":25000000000000000}]],"Stakely":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":27762804674573226,"pool_token_amount":27199200600475944}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":27743098486923114,"pool_token_amount":27196775892784810}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":27732469848657900,"pool_token_amount":27196718482713363}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"iota_amount":27710201021493154,"pool_token_amount":27195612998543851}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[145,{"iota_amount":27683882992364250,"pool_token_amount":27187082002344788}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":27629374598619965,"pool_token_amount":27185523459846181}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":27625655415303010,"pool_token_amount":27185338617921749}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":27603424425082252,"pool_token_amount":27187762942494988}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":27596067377921217,"pool_token_amount":27187462435319588}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":27585533103239935,"pool_token_amount":27187503467571946}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":27556453630039662,"pool_token_amount":27187027624947083}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":27535936260173896,"pool_token_amount":27194598631996849}],[99,{"iota_amount":27511267383932034,"pool_token_amount":27182188529984450}],[98,{"iota_amount":27507792550651420,"pool_token_amount":27182732270956926}],[97,{"iota_amount":27503581441579801,"pool_token_amount":27182518659522367}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":27461600250504285,"pool_token_amount":27179562099774593}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":27434297111797914,"pool_token_amount":27179577440624487}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":27421175524007266,"pool_token_amount":27181964004608183}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":27402305571673416,"pool_token_amount":27182936076681587}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":27397994565696040,"pool_token_amount":27182745919002039}],[69,{"iota_amount":27244236581933108,"pool_token_amount":27034283113713075}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":27235203391400133,"pool_token_amount":27033490810244142}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":27225992980288273,"pool_token_amount":27036295924553270}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":27220480473093076,"pool_token_amount":27034596346580647}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":27209635066632573,"pool_token_amount":27035150867820853}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":27196945826155067,"pool_token_amount":27030095957215174}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":27167878738824695,"pool_token_amount":27024191738104784}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":27162941571490818,"pool_token_amount":27023166485975317}],[50,{"iota_amount":27156202563211104,"pool_token_amount":27020348420524822}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":27153439548901120,"pool_token_amount":27021486381704188}],[47,{"iota_amount":27145158353963145,"pool_token_amount":27021020780682951}],[46,{"iota_amount":27142588929943663,"pool_token_amount":27022351914550034}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":27129697034533784,"pool_token_amount":27021183828583049}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":27116594222406354,"pool_token_amount":27015915627013999}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"iota_amount":27111277814971973,"pool_token_amount":27014511243154113}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":27100623872868049,"pool_token_amount":27011682582791398}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":27092866808465014,"pool_token_amount":27011973927133025}],[35,{"iota_amount":27087770359920184,"pool_token_amount":27011103729559939}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":27068074938619894,"pool_token_amount":27004424290727303}],[32,{"iota_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"iota_amount":27062932318606154,"pool_token_amount":27003613420603570}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":20023317397249717,"pool_token_amount":20004881001927239}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":20000000015316901,"pool_token_amount":20000000000306326}],[16,{"iota_amount":20000000007017893,"pool_token_amount":20000000000140348}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":20000000000475400,"pool_token_amount":20000000000009502}],[12,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":20000000000000000,"pool_token_amount":20000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Staketab":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":27555917617214541,"pool_token_amount":27028831210170886}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":27537897281789926,"pool_token_amount":27027168813617822}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":27533977134068662,"pool_token_amount":27026597389419518}],[156,{"iota_amount":27526407480514259,"pool_token_amount":27025719869659726}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":27522714519445620,"pool_token_amount":27025371253632667}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":27515099203721423,"pool_token_amount":27024449409796747}],[151,{"iota_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"iota_amount":27477392712972315,"pool_token_amount":27010276147430573}],[145,{"iota_amount":27473030428918954,"pool_token_amount":27009185150604109}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":27451174599059268,"pool_token_amount":27006870426367889}],[138,{"iota_amount":27447533288380145,"pool_token_amount":27006488342781624}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":27414922994538640,"pool_token_amount":27003207585342578}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":27390404246196049,"pool_token_amount":27001477710451867}],[120,{"iota_amount":27382011107480852,"pool_token_amount":26999611625474993}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":27374775646369830,"pool_token_amount":26998885777949133}],[117,{"iota_amount":91735889242077333,"pool_token_amount":39881683429017994}],[116,{"iota_amount":27367385078862758,"pool_token_amount":26998005390096765}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":27362481215864858,"pool_token_amount":26996373013833813}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":27344896545444415,"pool_token_amount":26998618211333503}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":27340882941424173,"pool_token_amount":26998221934802815}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[102,{"iota_amount":27315809573589787,"pool_token_amount":26995752363268394}],[101,{"iota_amount":27311666811173158,"pool_token_amount":26995342938273299}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":27289054943396904,"pool_token_amount":26998832561499814}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":27284989813072721,"pool_token_amount":26998430370946556}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":27264745509457303,"pool_token_amount":26996432113353037}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":27229625151539937,"pool_token_amount":26994054599636048}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":27226239705397537,"pool_token_amount":26997842193840795}],[74,{"iota_amount":27215053407122431,"pool_token_amount":26997461837242754}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":27189472265138274,"pool_token_amount":26994710683274801}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"iota_amount":27175727505458259,"pool_token_amount":27010559565408948}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":27158903687748346,"pool_token_amount":27008153575345101}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":27146138918396074,"pool_token_amount":27006402012356652}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":27142024176289873,"pool_token_amount":27005990865758226}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":27125523738314235,"pool_token_amount":27004302272438978}],[45,{"iota_amount":27121971079142759,"pool_token_amount":27011820191091292}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":27113731248697735,"pool_token_amount":27010985160960882}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"iota_amount":27092555696710581,"pool_token_amount":27000950067280571}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":27080108363178739,"pool_token_amount":26999717228605699}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":27071387534543246,"pool_token_amount":26998818996204802}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":27058031309906146,"pool_token_amount":26997778994559239}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":27039340575876393,"pool_token_amount":26995715327430054}],[27,{"iota_amount":27034342941288914,"pool_token_amount":26995222681248733}],[25,{"iota_amount":20025411726048901,"pool_token_amount":20003828758669413}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":20010986044009000,"pool_token_amount":20001825795265510}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":20004689113804701,"pool_token_amount":20000114706287817}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":20000000015327401,"pool_token_amount":20000000000306536}],[17,{"iota_amount":20000000012338901,"pool_token_amount":20000000000246767}],[16,{"iota_amount":20000000007028393,"pool_token_amount":20000000000140558}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":20000000000537500,"pool_token_amount":20000000000010743}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":20000000000455800,"pool_token_amount":20000000000009112}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":20000000000442900,"pool_token_amount":20000000000008856}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Stakin":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":27575508880189594,"pool_token_amount":27061004051953791}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":27566501426013069,"pool_token_amount":27058716161008865}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":27549988859924576,"pool_token_amount":27052335579276793}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"iota_amount":27517424711541047,"pool_token_amount":27043300299443701}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":27513103678217411,"pool_token_amount":27042336575162531}],[146,{"iota_amount":27509371889643755,"pool_token_amount":27041952089102544}],[145,{"iota_amount":27505755239687262,"pool_token_amount":27041594050593172}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":27495399421682722,"pool_token_amount":27040999738079456}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":27486936528327654,"pool_token_amount":27039069271433442}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":27476093400938358,"pool_token_amount":27038002498260332}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":27468850726419136,"pool_token_amount":27037276654950700}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":27461622674899420,"pool_token_amount":27036563575885117}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":27458100601288283,"pool_token_amount":27036298132288842}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":27454555680072654,"pool_token_amount":27036010586084730}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":27446984131365825,"pool_token_amount":27034963386775665}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":27425068856232969,"pool_token_amount":27032594179359398}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":27421456251278487,"pool_token_amount":27032238088340317}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":27399261666862837,"pool_token_amount":27042396941149216}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":27391978430506321,"pool_token_amount":27041623884697743}],[109,{"iota_amount":27387963095929566,"pool_token_amount":27041226509208606}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":27386231461853520,"pool_token_amount":27088072831253007}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":27382043837888817,"pool_token_amount":27087658626962945}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":27365280853188209,"pool_token_amount":27085755709646799}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":27302635193000921,"pool_token_amount":27030956155841233}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":27278821950185709,"pool_token_amount":27025323830464924}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":27278808081704576,"pool_token_amount":27032457683621908}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":27271579123086174,"pool_token_amount":27032639620305906}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":27267571735751802,"pool_token_amount":27032241411265673}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":27255562199026961,"pool_token_amount":27031047987911888}],[75,{"iota_amount":27251680474962789,"pool_token_amount":27030769617816815}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":27239131789191871,"pool_token_amount":27029336014489962}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":27234080908482857,"pool_token_amount":27035743536733032}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":27229746787207876,"pool_token_amount":27035313281007594}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":27221062329323628,"pool_token_amount":27034436320075600}],[65,{"iota_amount":27216728157947731,"pool_token_amount":27034005874416138}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":27212732378521767,"pool_token_amount":27033613453075020}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":27208731321326570,"pool_token_amount":27033215980915191}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":27192024047369767,"pool_token_amount":27030926846579831}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":27159578151927257,"pool_token_amount":27020346281089708}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"iota_amount":27143820725663105,"pool_token_amount":27026768106695547}],[46,{"iota_amount":27139700173170968,"pool_token_amount":27026350211342309}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":27130375940233374,"pool_token_amount":27028121227533376}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"iota_amount":27120986001695752,"pool_token_amount":27026141234095889}],[40,{"iota_amount":27115541647140552,"pool_token_amount":27024404158250367}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":20023961849970848,"pool_token_amount":20006654446950867}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":20004728736001501,"pool_token_amount":20000154319424337}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"iota_amount":20000000012338901,"pool_token_amount":20000000000246767}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Staking Defense League":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":41589390909004724,"pool_token_amount":40779872762468142}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":41573059098495481,"pool_token_amount":40778271180951176}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":41515607426649619,"pool_token_amount":40772179324043950}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"iota_amount":41487423806768891,"pool_token_amount":40769405448992558}],[145,{"iota_amount":41481802344267042,"pool_token_amount":40768853031124541}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":41484241299934774,"pool_token_amount":40786164747535722}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":41428034837938967,"pool_token_amount":40780636542251781}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":41416789910967757,"pool_token_amount":40779529553409871}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":41411163904123583,"pool_token_amount":40778975608609681}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":41405538219391962,"pool_token_amount":40778421627807354}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":41377441713567337,"pool_token_amount":40775653852953090}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":41371822106142396,"pool_token_amount":40775100064840633}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":35498196780249327,"pool_token_amount":34994650837725555}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":35488768671482907,"pool_token_amount":34993721344439502}],[117,{"iota_amount":35484055533906847,"pool_token_amount":34993256604889595}],[116,{"iota_amount":35479429467909791,"pool_token_amount":34992877513166796}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":35451096837039328,"pool_token_amount":34990037873131755}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":35440508063895202,"pool_token_amount":34988896763678047}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":45415904083807471,"pool_token_amount":44857743912401435}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[100,{"iota_amount":45380081969167486,"pool_token_amount":44854211843004424}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":45338035680086889,"pool_token_amount":44849998432518196}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":45331034622984296,"pool_token_amount":44849305862197779}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":45317274901866990,"pool_token_amount":44847946203968320}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":45283031296197958,"pool_token_amount":44844748120281644}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":45254682112820120,"pool_token_amount":44841291120258393}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":45219871280311440,"pool_token_amount":44837752160245628}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":45194810025728462,"pool_token_amount":44850204563661523}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":45173126486028363,"pool_token_amount":44848047074663042}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":45151288109954348,"pool_token_amount":44845728488899256}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":45123822311418323,"pool_token_amount":44842986528506672}],[60,{"iota_amount":45116923277931781,"pool_token_amount":44842294658088747}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":45103522846433733,"pool_token_amount":44841302753665685}],[56,{"iota_amount":45089756271097682,"pool_token_amount":44839947494130659}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":45062502457404793,"pool_token_amount":44837216996102204}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":45059691790172764,"pool_token_amount":44852637337875491}],[48,{"iota_amount":45052799597026860,"pool_token_amount":44851950389732427}],[47,{"iota_amount":45046020568717871,"pool_token_amount":44851275509046702}],[45,{"iota_amount":45032357926560628,"pool_token_amount":44849821402930483}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":45025461810379289,"pool_token_amount":44849129208505913}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"iota_amount":45004051758373241,"pool_token_amount":44846534484016339}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":44982996686817694,"pool_token_amount":44844395232437029}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":35082384491653355,"pool_token_amount":34994678797247816}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":35070561943877156,"pool_token_amount":34993474331145170}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":25000000019836964,"pool_token_amount":25000000001983684}],[16,{"iota_amount":25000000008826354,"pool_token_amount":25000000000882626}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":25000000000577800,"pool_token_amount":25000000000057775}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":25000000000577800,"pool_token_amount":25000000000057775}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":25000000000577800,"pool_token_amount":25000000000057775}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":25000000000572400,"pool_token_amount":25000000000057236}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":25000000000556200,"pool_token_amount":25000000000055618}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Staking Facilities":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":65596897858751769,"pool_token_amount":64288423150902756}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[145,{"iota_amount":65654257542050518,"pool_token_amount":64492508287812106}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":65635634723391625,"pool_token_amount":64490707234424425}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":65617580477757339,"pool_token_amount":64489456367395709}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":65560867847675182,"pool_token_amount":64483237982639866}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":65532936698511152,"pool_token_amount":64480542701123361}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":65524005328117875,"pool_token_amount":64480019135612364}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":65495290562874055,"pool_token_amount":64476383177884223}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":65705961139311638,"pool_token_amount":64716897002302479}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":65697031663730445,"pool_token_amount":64716369298175783}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":65678932368526141,"pool_token_amount":64715078317126431}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":65651952912925215,"pool_token_amount":64713297859251826}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":65583790492388076,"pool_token_amount":64712270280210802}],[109,{"iota_amount":65575653514262477,"pool_token_amount":64713446353294326}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":65554503871618459,"pool_token_amount":64711087491542211}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[97,{"iota_amount":65450807655223615,"pool_token_amount":64702506716907789}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":35435341382817915,"pool_token_amount":35035162493583824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":35424463713391868,"pool_token_amount":35034292449189658}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":35419043539939188,"pool_token_amount":35033863610358739}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":35388894543311478,"pool_token_amount":35028303307286196}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":35383510103052327,"pool_token_amount":35027876940787653}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":35378127588205647,"pool_token_amount":35027450667108266}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":35372768949161209,"pool_token_amount":35027024790555343}],[84,{"iota_amount":35367426593697774,"pool_token_amount":35026601591703889}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":35345935105873218,"pool_token_amount":35024888494730500}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":35340687563593972,"pool_token_amount":35024558370610554}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":35318247425999665,"pool_token_amount":35021778767447313}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":35295552173327280,"pool_token_amount":35019247971593362}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":35284324898515687,"pool_token_amount":35018257434340198}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":35267854799123045,"pool_token_amount":35017131651532658}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":35235121987392150,"pool_token_amount":35014071918194498}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":35229787854173018,"pool_token_amount":35013647864659326}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":35207448553176079,"pool_token_amount":35010956836127238}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":35201359725602092,"pool_token_amount":35009782639848292}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":35169387207701523,"pool_token_amount":35007271886167993}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":35136910938706813,"pool_token_amount":35004254822217761}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"iota_amount":35131153660825246,"pool_token_amount":35003409208225707}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":35098604898359189,"pool_token_amount":35001473583976443}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":35087204785469941,"pool_token_amount":35000916212725753}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":35081064667562852,"pool_token_amount":35000207790819527}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":25007401238205152,"pool_token_amount":25001628428764371}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"iota_amount":25000000015495364,"pool_token_amount":25000000000309897}],[16,{"iota_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":25000000000691200,"pool_token_amount":25000000000013816}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":25000000000550800,"pool_token_amount":25000000000011015}],[0,{"iota_amount":0,"pool_token_amount":0}]],"StakingCabin":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":153253153410074065,"pool_token_amount":150056789711924972}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":153232905650128209,"pool_token_amount":150055996693250359}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":153212659715077485,"pool_token_amount":150055203645477580}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":153087263235998544,"pool_token_amount":150048857899683080}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":153068686571206791,"pool_token_amount":150050271441464400}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":153031485245977317,"pool_token_amount":150072683686244135}],[150,{"iota_amount":152989366284571285,"pool_token_amount":150070638993492354}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":152931118110432845,"pool_token_amount":150072236623617762}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":152524593634717832,"pool_token_amount":150062582648464462}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":152462713432141938,"pool_token_amount":150059983352337341}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":152448679022560641,"pool_token_amount":150065606798658195}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":152290389708022856,"pool_token_amount":150065620752103073}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":152155917411270170,"pool_token_amount":150052562350534343}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":152110750512204785,"pool_token_amount":150051612372469433}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":152039183752302053,"pool_token_amount":150048797635177739}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":152015212491910670,"pool_token_amount":150047853239976803}],[102,{"iota_amount":151991388266654612,"pool_token_amount":150046914504113697}],[101,{"iota_amount":151967682474336265,"pool_token_amount":150045978400469060}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":151858670280952878,"pool_token_amount":150049942044590428}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":151718465648767935,"pool_token_amount":150043325924071795}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":151625780726125033,"pool_token_amount":150060748897046474}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":151593128828421776,"pool_token_amount":150071898370452002}],[82,{"iota_amount":151570034221471092,"pool_token_amount":150070719944872053}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":151546919523532999,"pool_token_amount":150069519351685532}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":151453147635780648,"pool_token_amount":150064119405585092}],[76,{"iota_amount":151429891612838617,"pool_token_amount":150062744927155515}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":151415117448487144,"pool_token_amount":150069780704368660}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":151369196708294556,"pool_token_amount":150068260901878185}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":151320732046712979,"pool_token_amount":150065908629023405}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":211342511247333584,"pool_token_amount":209825360086523094}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":211158031429948576,"pool_token_amount":209793669193123472}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":211031151005243615,"pool_token_amount":209819943500254598}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":210952300310995334,"pool_token_amount":209802869977476433}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"iota_amount":210759081778546902,"pool_token_amount":209794802776820019}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":210694239236732270,"pool_token_amount":209791638127519084}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":210662116757723265,"pool_token_amount":209790354434862410}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":150549849069866022,"pool_token_amount":150016029618847034}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":170517866660301934,"pool_token_amount":169994363346912355}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":170400864064812041,"pool_token_amount":169988919273662947}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"iota_amount":200183190770187480,"pool_token_amount":199955186355126146}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":150108379972026044,"pool_token_amount":150004272677911561}],[22,{"iota_amount":150071728832923326,"pool_token_amount":150002623246420502}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":150036202666533445,"pool_token_amount":150001458813436172}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":150000000116171591,"pool_token_amount":150000000002323420}],[17,{"iota_amount":150000000093514591,"pool_token_amount":150000000001870281}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":150000000004141300,"pool_token_amount":150000000000082818}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":150000000003652300,"pool_token_amount":150000000000073040}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":150000000003391500,"pool_token_amount":150000000000067827}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":150000000003391500,"pool_token_amount":150000000000067827}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Stardust Staking":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":35778494725565083,"pool_token_amount":35073149779274828}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":35759755462514268,"pool_token_amount":35071496197434013}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":35745972448646927,"pool_token_amount":35070682610666804}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":35731538428723176,"pool_token_amount":35069407932593938}],[154,{"iota_amount":35726726596379057,"pool_token_amount":35068982892250647}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":35721685102591668,"pool_token_amount":35068332555397017}],[152,{"iota_amount":35716826985735807,"pool_token_amount":35067862218116071}],[149,{"iota_amount":35703114359368386,"pool_token_amount":35067296656174513}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":35678913876754869,"pool_token_amount":35065049402407726}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":38977559176067445,"pool_token_amount":38335729575021223}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":38966911873477944,"pool_token_amount":38334787037190842}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":38914850412939180,"pool_token_amount":38331203551919356}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":38898930663153034,"pool_token_amount":38329821727562882}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":38881478030281678,"pool_token_amount":38326927683648254}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":38860218949300669,"pool_token_amount":38325043117652156}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":38854900984164735,"pool_token_amount":38324568399426323}],[114,{"iota_amount":38849586163793115,"pool_token_amount":38324096594016597}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":38838927594249111,"pool_token_amount":38323125155925696}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":42151081194056583,"pool_token_amount":41596863519094964}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":42132652750213226,"pool_token_amount":41595227450356746}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":52056444453386477,"pool_token_amount":51415917397116259}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":52031729691151195,"pool_token_amount":51413721015003426}],[100,{"iota_amount":52015416176081777,"pool_token_amount":51412271933639465}],[99,{"iota_amount":52007280241252547,"pool_token_amount":51411548187929750}],[97,{"iota_amount":51991084555344837,"pool_token_amount":51410031789223495}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":51983027266398127,"pool_token_amount":51409235860654308}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":51958936992907766,"pool_token_amount":51406856366059933}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":51919136987398089,"pool_token_amount":51402544426338763}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":51872132630897834,"pool_token_amount":51397889348432529}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":51856213270542124,"pool_token_amount":51396309876980749}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":51825067250368015,"pool_token_amount":51393216482409327}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":51817176459492803,"pool_token_amount":51392336407210705}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":51809395893891385,"pool_token_amount":51391565501470854}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":51793268402749096,"pool_token_amount":51390055677054671}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":51760319291681407,"pool_token_amount":51386947841830299}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":51743680965611324,"pool_token_amount":51385325268277170}],[65,{"iota_amount":51735346020662207,"pool_token_amount":51384498373943926}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51727567726071925,"pool_token_amount":51383727491857613}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":51719863776449724,"pool_token_amount":51383031461021441}],[61,{"iota_amount":51704282609530115,"pool_token_amount":51381465274391862}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":35142602426512309,"pool_token_amount":34999549513637668}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":35137254143016319,"pool_token_amount":34999004844926209}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":35112012086131889,"pool_token_amount":34997877039897905}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"iota_amount":25037590623813189,"pool_token_amount":25005926672795173}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":25000000031979264,"pool_token_amount":25000000000639572}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"iota_amount":0,"pool_token_amount":0}]],"Swiss Staking":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":35798757682239192,"pool_token_amount":35075994939056683}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":35789106773149110,"pool_token_amount":35075032892012643}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":35751864319241262,"pool_token_amount":35068622694459546}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":35742342166202585,"pool_token_amount":35067966628012298}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":35727743941586011,"pool_token_amount":35066674264145731}],[150,{"iota_amount":35722932248248373,"pool_token_amount":35066296450710245}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"iota_amount":35708522545536717,"pool_token_amount":35065191535839632}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":35679157116836484,"pool_token_amount":35062458542959119}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":35669515239420536,"pool_token_amount":35061690532118812}],[138,{"iota_amount":35664696066549928,"pool_token_amount":35061311567354765}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":35645663868674448,"pool_token_amount":35060035794549354}],[133,{"iota_amount":35640752080890717,"pool_token_amount":35059564396435372}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":35616351599469710,"pool_token_amount":35057372822672378}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":35611686971684466,"pool_token_amount":35057053858144059}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":35606872490023622,"pool_token_amount":35056676526531131}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":35582121184840944,"pool_token_amount":35054118734857344}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":35573577872977145,"pool_token_amount":35054429182320264}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":35569270144035536,"pool_token_amount":35054548875250245}],[116,{"iota_amount":35559715110831034,"pool_token_amount":35053860423206290}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":35530439437369558,"pool_token_amount":35051287188644896}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":35490505034413253,"pool_token_amount":35046643261968294}],[99,{"iota_amount":35472148057722636,"pool_token_amount":35048579051835145}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":35435089732182461,"pool_token_amount":35046602393609556}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":35415836398284491,"pool_token_amount":35042191318077688}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":35406637385095450,"pool_token_amount":35042894217087270}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":35392539847304235,"pool_token_amount":35043585127873399}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":35375451118227688,"pool_token_amount":35041263852424451}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":35375340386446450,"pool_token_amount":35055862644462790}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":35376696482687083,"pool_token_amount":35071807296667227}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":35354535502310780,"pool_token_amount":35069806982602916}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":35328353525884868,"pool_token_amount":35059052233532652}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":35316142953283812,"pool_token_amount":35057080681604850}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":35277235088840784,"pool_token_amount":35033276033511741}],[62,{"iota_amount":35272097203286878,"pool_token_amount":35033047448844481}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":35256234315731302,"pool_token_amount":35031916610365508}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":35226209246111928,"pool_token_amount":35032301813125300}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":35220293146133644,"pool_token_amount":35031459078482784}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":35173241016600067,"pool_token_amount":35030024548813202}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"iota_amount":35162886175314225,"pool_token_amount":35029912602016803}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":35114731831469410,"pool_token_amount":35035847571516464}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":35088539377562827,"pool_token_amount":35027124942569709}],[25,{"iota_amount":25048007689290837,"pool_token_amount":25018853767181175}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":25042735627245832,"pool_token_amount":25025089583790887}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":25000000019248364,"pool_token_amount":25000000000384956}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":25000000000000000,"pool_token_amount":25000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"SyncNode":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":35791326818787930,"pool_token_amount":35088758289283253}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":35776243126819896,"pool_token_amount":35090598739302893}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":35766825917489009,"pool_token_amount":35089675010996787}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":35736860359351263,"pool_token_amount":35090017113481804}],[150,{"iota_amount":35722379705184440,"pool_token_amount":35088555353628683}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"iota_amount":35706517766381152,"pool_token_amount":35089997459172609}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":35687053470046859,"pool_token_amount":35088085182445472}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":35682238837034242,"pool_token_amount":35087611799507039}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":35670629457807989,"pool_token_amount":35088984372269655}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":35660987617711495,"pool_token_amount":35088036736921603}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":35620312090612983,"pool_token_amount":35090867179161375}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":35558092116896998,"pool_token_amount":35059369822626981}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":35548589973006855,"pool_token_amount":35058455290773873}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":35541032405475837,"pool_token_amount":35059546792203036}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":35499836029678639,"pool_token_amount":35059409876526470}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":35488637411291369,"pool_token_amount":35058269156714914}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[100,{"iota_amount":35469768370377336,"pool_token_amount":35059338835645355}],[99,{"iota_amount":35464218019281961,"pool_token_amount":35058745741526967}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":35412882376215201,"pool_token_amount":35027408075839729}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":35403201373983190,"pool_token_amount":35027394685535199}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":35389441445370902,"pool_token_amount":35027926176098312}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":35384162678240767,"pool_token_amount":35027403691338491}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":35370232084560203,"pool_token_amount":35027904908125027}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":35355514831869865,"pool_token_amount":35027429296280525}],[82,{"iota_amount":35352852851032402,"pool_token_amount":35029556007176974}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":35336716416343841,"pool_token_amount":35027957808277853}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":35313166294708345,"pool_token_amount":35028415494033305}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":35307720342749960,"pool_token_amount":35027875290222055}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":35287509175790555,"pool_token_amount":35027675460623190}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":35234104166773319,"pool_token_amount":35027883334707887}],[56,{"iota_amount":35192353652691283,"pool_token_amount":34995819929136961}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":35187099794995758,"pool_token_amount":34995270628191435}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":35179632653122472,"pool_token_amount":34997396018077127}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":35164506673181211,"pool_token_amount":34996677605670439}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":35153841962853990,"pool_token_amount":34995620636151989}],[47,{"iota_amount":35150107373352441,"pool_token_amount":34996682350713804}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":35130572101588057,"pool_token_amount":34996352514620615}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":35125218134221081,"pool_token_amount":34995802128743484}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"iota_amount":35115526523032189,"pool_token_amount":34995714188292690}],[39,{"iota_amount":35112118398066697,"pool_token_amount":34997202810688916}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":35064771454393029,"pool_token_amount":34997224177682950}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":35046973389652898,"pool_token_amount":34990606731975758}],[26,{"iota_amount":25036780886670047,"pool_token_amount":25005151890543232}],[25,{"iota_amount":25032018195276228,"pool_token_amount":25005093653707674}],[24,{"iota_amount":25026169049945033,"pool_token_amount":25004250003880932}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":25013264464700365,"pool_token_amount":25002068628317055}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"SynergyNodes":[[167,{"iota_amount":35711973488397131,"pool_token_amount":34999579084893220}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":35703304665126911,"pool_token_amount":34999579173392202}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":35681830274195488,"pool_token_amount":34999587263939251}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":35668550012823683,"pool_token_amount":34999587329457781}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":35650720104633172,"pool_token_amount":34999466522936534}],[151,{"iota_amount":35642251017238150,"pool_token_amount":34999844670304153}],[149,{"iota_amount":35633012080680255,"pool_token_amount":34999466714899788}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"iota_amount":35624242641197734,"pool_token_amount":34999462158956603}],[146,{"iota_amount":35619914147116045,"pool_token_amount":34999471324332348}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":35606628758588605,"pool_token_amount":34999480921655847}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":35567371036903277,"pool_token_amount":34999463940676521}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":35550201038648822,"pool_token_amount":34999836387954911}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":35545479211370173,"pool_token_amount":34999464489192044}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":35510760786316251,"pool_token_amount":34999461996199143}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"iota_amount":35498127188891416,"pool_token_amount":34999833863114390}],[117,{"iota_amount":35493414051315356,"pool_token_amount":34999462104490310}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":35480383466141681,"pool_token_amount":34999440032278676}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":35476047053637811,"pool_token_amount":34999440089795714}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":35448532328213831,"pool_token_amount":34999501848747979}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":35436326440540295,"pool_token_amount":34997409392708235}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":35431327734612563,"pool_token_amount":34997429488963574}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[99,{"iota_amount":35406391217838728,"pool_token_amount":34997417936869707}],[98,{"iota_amount":35397636561402248,"pool_token_amount":34993658705474278}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":35348671269283555,"pool_token_amount":34993821233363631}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":35304576111031336,"pool_token_amount":34993336108694415}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":35281033541493148,"pool_token_amount":34993822729905847}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":35245453304624334,"pool_token_amount":34993828851906497}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":35235610614189585,"pool_token_amount":34994207663716338}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":35204096547790040,"pool_token_amount":34991545896486089}],[57,{"iota_amount":35194485465483141,"pool_token_amount":34991546050149754}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":35175051503562695,"pool_token_amount":34991541281078344}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":35156694455532143,"pool_token_amount":34992810551498211}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":35130331205959595,"pool_token_amount":34990994085135102}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":35125518757533072,"pool_token_amount":34991089049456378}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":35120129616885749,"pool_token_amount":34990609983115475}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":35105248694044705,"pool_token_amount":34990556412617032}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":35074278565517779,"pool_token_amount":34990910392585385}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":35064233564442748,"pool_token_amount":34991714388408580}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":35039628838964770,"pool_token_amount":34989635842359541}],[26,{"iota_amount":35034205124962368,"pool_token_amount":34990615288737785}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":25017678795897347,"pool_token_amount":25001650820581813}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":25006004474400779,"pool_token_amount":25000603107139777}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"iota_amount":25000000015495364,"pool_token_amount":25000000001549526}],[16,{"iota_amount":25000000008826354,"pool_token_amount":25000000000882626}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":25000000000675000,"pool_token_amount":25000000000067493}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":25000000000577800,"pool_token_amount":25000000000057775}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":25000000000577800,"pool_token_amount":25000000000057775}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":25000000000567000,"pool_token_amount":25000000000056697}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":25000000000567000,"pool_token_amount":25000000000056697}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":25000000000556200,"pool_token_amount":25000000000055618}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"TDMTech":[[167,{"iota_amount":27589557383739965,"pool_token_amount":27006016284351285}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":27575115492280906,"pool_token_amount":27005726784817025}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":27564294123755708,"pool_token_amount":27005514798228952}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":27539946807910348,"pool_token_amount":27010152010554934}],[151,{"iota_amount":27536237639530052,"pool_token_amount":27010079253818621}],[149,{"iota_amount":27525953208861926,"pool_token_amount":27007122425584929}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"iota_amount":27512311478767397,"pool_token_amount":27004442229950841}],[145,{"iota_amount":27508697681193527,"pool_token_amount":27004371287515646}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":27496923080337509,"pool_token_amount":27003235797564622}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":27477762695392705,"pool_token_amount":27001805026345815}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":27470551036770165,"pool_token_amount":27001678931973145}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":27462481065649381,"pool_token_amount":27011158301081466}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":27427590861707608,"pool_token_amount":27001223477261830}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":27423978256753126,"pool_token_amount":27001152347846300}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":27416475289877823,"pool_token_amount":27000733940396040}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":27390474461360573,"pool_token_amount":26999517966155011}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":27383304381562531,"pool_token_amount":26999425711441778}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":27375678335532911,"pool_token_amount":26999275317470334}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":27367529586153592,"pool_token_amount":26999104905488694}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":27350740082362819,"pool_token_amount":26998776465634339}],[102,{"iota_amount":27346461613600206,"pool_token_amount":26998692964694853}],[99,{"iota_amount":27333838922544972,"pool_token_amount":26998448545073645}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":27321426128460210,"pool_token_amount":26998203300021873}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":27313049568616745,"pool_token_amount":26998037736128407}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":27308873523706875,"pool_token_amount":26997957120788517}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":27292673832160874,"pool_token_amount":26997647480524988}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":27284595850068398,"pool_token_amount":26997487654799246}],[86,{"iota_amount":27280558963827675,"pool_token_amount":26997407766244965}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":27260240398843856,"pool_token_amount":26996739820062974}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":27255920954392158,"pool_token_amount":26996566918709735}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":27247975512134885,"pool_token_amount":26996471081178388}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":27333689366742490,"pool_token_amount":27096949858228020}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":27312562214718690,"pool_token_amount":27096524044523712}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":27303694024185715,"pool_token_amount":27096153620579071}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":27299360035559461,"pool_token_amount":27096067599671703}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":27282973201066937,"pool_token_amount":27095693575134032}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":27274953333869003,"pool_token_amount":27095517721445269}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":27048393710135736,"pool_token_amount":26992886488521080}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"iota_amount":27027576229189627,"pool_token_amount":26991373615238473}],[24,{"iota_amount":20018898351260217,"pool_token_amount":20000464418682403}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":20000000000537500,"pool_token_amount":20000000000010743}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":20000000000485900,"pool_token_amount":20000000000009712}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":20000000000455800,"pool_token_amount":20000000000009112}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":20000000000442900,"pool_token_amount":20000000000008856}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":20000000000438600,"pool_token_amount":20000000000008771}]],"TPT":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":117499746240642406,"pool_token_amount":115058061432529879}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":117484210584130362,"pool_token_amount":115057300791148522}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":117468671650545907,"pool_token_amount":115056539893710020}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":117453135002968465,"pool_token_amount":115055779012629097}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":117430883382578058,"pool_token_amount":115062883072540807}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":117415345688112094,"pool_token_amount":115062121853356406}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":117399305442574297,"pool_token_amount":115061335914501112}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":117335153965459233,"pool_token_amount":115058191604663668}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":117137973083202030,"pool_token_amount":115057947022319271}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":117090423281810635,"pool_token_amount":115055611447696023}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":117063450766057520,"pool_token_amount":115058735109841484}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":117031728290126876,"pool_token_amount":115057176046966478}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":117015871865292162,"pool_token_amount":115056396601636746}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":116972253781016022,"pool_token_amount":115057956389510601}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":116834124174893672,"pool_token_amount":115054905638482125}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":116711836485066823,"pool_token_amount":115052984218794069}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":116696783380523935,"pool_token_amount":115052984344838624}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":116666476520806176,"pool_token_amount":115052787630317866}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":116654188101776994,"pool_token_amount":115055520585119737}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":116618954805710732,"pool_token_amount":115053782937161860}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":116601231850585116,"pool_token_amount":115052912442796714}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"iota_amount":116496940114595933,"pool_token_amount":115052902093852188}],[98,{"iota_amount":116445324378069792,"pool_token_amount":115052894177834511}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":116376908195592509,"pool_token_amount":115052876149089546}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":116359953317159169,"pool_token_amount":115052870792566143}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":116295878377112979,"pool_token_amount":115055925357985270}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":116243132354310343,"pool_token_amount":115053398777954246}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":116096545293690412,"pool_token_amount":114957754101397365}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":116063379028252635,"pool_token_amount":114957787414592485}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":115996326837235975,"pool_token_amount":114957738593110886}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":115964794374914474,"pool_token_amount":114959343193170555}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":115814786520985803,"pool_token_amount":114948601345629952}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":115796228159445006,"pool_token_amount":114947680367499749}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":115713975562439083,"pool_token_amount":114949352743909091}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":115696510155077672,"pool_token_amount":114948472975594869}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":115608725706055891,"pool_token_amount":114943705785601381}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":115556233467574842,"pool_token_amount":114941279445508607}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":115325914401329057,"pool_token_amount":114946822613603152}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":115291139864358217,"pool_token_amount":114946786358335707}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":105257622392237026,"pool_token_amount":104976716952716637}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":105224512521195147,"pool_token_amount":104977642895881384}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":80057756688790512,"pool_token_amount":80002837191788368}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":80000000062001508,"pool_token_amount":80000000001240018}],[17,{"iota_amount":80000000049908508,"pool_token_amount":80000000000998159}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"iota_amount":0,"pool_token_amount":0}]],"TestnetPride":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":177178709111745073,"pool_token_amount":173413292207400062}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":177131916228080118,"pool_token_amount":173412031848405560}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":177082689656313381,"pool_token_amount":173408384664569309}],[161,{"iota_amount":177059361007521881,"pool_token_amount":173407699326354920}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":177011047893843814,"pool_token_amount":173405428359475633}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":176888633746643387,"pool_token_amount":173399998093165993}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":176864346361206767,"pool_token_amount":173399067833898533}],[151,{"iota_amount":176816389275148742,"pool_token_amount":173398002873527725}],[149,{"iota_amount":176698738437162807,"pool_token_amount":173328400086966604}],[148,{"iota_amount":176674771194357695,"pool_token_amount":173327688408663644}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":176656954633652387,"pool_token_amount":173401225355031251}],[143,{"iota_amount":176631798490337802,"pool_token_amount":173399261018362977}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":176465802758189163,"pool_token_amount":173395136475029286}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":176287522439523524,"pool_token_amount":173379169953361251}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":176190096547649618,"pool_token_amount":173374131090885463}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":176141474241278185,"pool_token_amount":173371680334419857}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":176069648916780400,"pool_token_amount":173369087132984374}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":175952549873027836,"pool_token_amount":173367577802077591}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":175678904178362112,"pool_token_amount":173288181993736959}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":175567985049971171,"pool_token_amount":173284378379731034}],[102,{"iota_amount":175540458657775204,"pool_token_amount":173283564286315090}],[98,{"iota_amount":175430933344871918,"pool_token_amount":173280025226665064}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":175377163391528304,"pool_token_amount":173278817199809780}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":175350113598410558,"pool_token_amount":173278015402677193}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":175058436456472454,"pool_token_amount":173270106952862389}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":174978771924513301,"pool_token_amount":173267015967534966}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":174908907485673130,"pool_token_amount":173274461030400900}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":174830164618878786,"pool_token_amount":173272079415921334}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":234721706499276583,"pool_token_amount":233032101986549935}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":234614903470417633,"pool_token_amount":233028171819224059}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":234470351423429228,"pool_token_amount":233020905176676076}],[56,{"iota_amount":234435276020206761,"pool_token_amount":233020226876596945}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":234397686763977888,"pool_token_amount":233017155972850453}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":234325145049780864,"pool_token_amount":233013851381616593}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":234234500827422372,"pool_token_amount":233026956166094067}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":234055168347464797,"pool_token_amount":233020784253925607}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"iota_amount":173985000713418685,"pool_token_amount":173345267404012439}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":173927420932867858,"pool_token_amount":173366689954421297}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":203449412632413171,"pool_token_amount":203136281767622411}],[26,{"iota_amount":203384427705029963,"pool_token_amount":203111132495227021}],[25,{"iota_amount":203338218887619243,"pool_token_amount":203106570302539433}],[24,{"iota_amount":173297867115400822,"pool_token_amount":173137507758920081}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":153260301729060518,"pool_token_amount":153153971066438216}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"iota_amount":150000000093514591,"pool_token_amount":150000000001870281}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":150000000004141300,"pool_token_amount":150000000000082818}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":150000000004043500,"pool_token_amount":150000000000080863}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":150000000003326900,"pool_token_amount":150000000000066536}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":150000000003294600,"pool_token_amount":150000000000065891}]],"Triton One":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":198991009805458895,"pool_token_amount":194785864649637002}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":198803728897897046,"pool_token_amount":194778876201495653}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":198768027370344087,"pool_token_amount":194872556779211613}],[151,{"iota_amount":198719341333845034,"pool_token_amount":194876309294530149}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":203737325869460339,"pool_token_amount":200086888375657790}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":203560143524387067,"pool_token_amount":199991474108306424}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":203505845699295916,"pool_token_amount":199990554815261384}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":203276280400971599,"pool_token_amount":199974647969004350}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":203412797808014374,"pool_token_amount":200266391800596439}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":203333980585887146,"pool_token_amount":200215037851992091}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":203306498198861744,"pool_token_amount":200214226026559132}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":203224091735731705,"pool_token_amount":200212009473236461}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":203172378702422825,"pool_token_amount":200213770673772247}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":203090108141743260,"pool_token_amount":200211689944467682}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":203062656841151321,"pool_token_amount":200210914993052867}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":202965764665155526,"pool_token_amount":200203247006383330}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":202934080145268489,"pool_token_amount":200202317066556481}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[100,{"iota_amount":202742868116663072,"pool_token_amount":200196394297017248}],[97,{"iota_amount":202648954193533223,"pool_token_amount":200193612818845603}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":202614698798565489,"pool_token_amount":200189786749588769}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":202595567579273229,"pool_token_amount":200200823927421286}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":202491211098378176,"pool_token_amount":200186969630967513}],[91,{"iota_amount":202445950072728454,"pool_token_amount":200171612022406513}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":202329178176887505,"pool_token_amount":200114871742331488}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":202194407932305893,"pool_token_amount":200069722219844067}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":172166816115626413,"pool_token_amount":170382623233018610}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":171822855443734707,"pool_token_amount":170315948414895472}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":171796287535230526,"pool_token_amount":170315153560280824}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":171741750462219965,"pool_token_amount":170313456227177298}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":171714511808886425,"pool_token_amount":170312646843633573}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":231746433387505864,"pool_token_amount":230078225440051694}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"iota_amount":231498962012049306,"pool_token_amount":230067889799375063}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":231428703108166560,"pool_token_amount":230065674515928084}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":231245681084855439,"pool_token_amount":230053602489739875}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":231210111514283364,"pool_token_amount":230052213776373398}],[47,{"iota_amount":231139380498801780,"pool_token_amount":230049950628451325}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":230998199769007888,"pool_token_amount":230045478693494553}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":170872659228154180,"pool_token_amount":170270078109020074}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":170845499009182599,"pool_token_amount":170268807990236286}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":170788779790350746,"pool_token_amount":170264550347116954}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":170729590965583526,"pool_token_amount":170260897998974284}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":170675580515823623,"pool_token_amount":170263223647232491}],[31,{"iota_amount":170642085918564367,"pool_token_amount":170257885411481016}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":150293042126533445,"pool_token_amount":150258238797174382}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":150000000119670491,"pool_token_amount":150000000002393397}],[18,{"iota_amount":150000000116171591,"pool_token_amount":150000000002323420}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":150000000003652300,"pool_token_amount":150000000000073040}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":150000000003456700,"pool_token_amount":150000000000069129}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":150000000003391500,"pool_token_amount":150000000000067827}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":150000000003294600,"pool_token_amount":150000000000065891}]],"XPRV":[[167,{"iota_amount":28433832350657133,"pool_token_amount":27875846984865131}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":28430123044483991,"pool_token_amount":27875483333005919}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":28415270159743620,"pool_token_amount":27874010950271860}],[161,{"iota_amount":28411565610188536,"pool_token_amount":27873647551624501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":28407856611839968,"pool_token_amount":27873283673695788}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":28396378874143627,"pool_token_amount":27872113208804441}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":28380930792358347,"pool_token_amount":27870409842497367}],[151,{"iota_amount":28373321947038933,"pool_token_amount":27869671575611086}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"iota_amount":28354278425753637,"pool_token_amount":27867808553436391}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":28342836972707198,"pool_token_amount":27866683015536441}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":28335221206819440,"pool_token_amount":27865940037890630}],[140,{"iota_amount":28331409297372993,"pool_token_amount":27865565159656615}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":28327596761967368,"pool_token_amount":27865190174444731}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":28323776583305287,"pool_token_amount":27864809965324529}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":28316137667830062,"pool_token_amount":27864053978178374}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":28308510745998865,"pool_token_amount":27863303416345808}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":28263641571739343,"pool_token_amount":27859062577389535}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":28237058775138396,"pool_token_amount":27856437072776569}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":28196478128337676,"pool_token_amount":27852393635110356}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":28187644101162435,"pool_token_amount":27851520057106231}],[101,{"iota_amount":28178877056040005,"pool_token_amount":27850654633191608}],[99,{"iota_amount":28170163272643066,"pool_token_amount":27849793340004021}],[98,{"iota_amount":28165814877641750,"pool_token_amount":27849366120281138}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":28153013194036144,"pool_token_amount":27848216170649063}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":28144419075122907,"pool_token_amount":27847365114938084}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":28098841278417034,"pool_token_amount":27842967945084509}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":28078020626674975,"pool_token_amount":27840889999744788}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":28069794830501462,"pool_token_amount":27840072528342575}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":28061439854505913,"pool_token_amount":27839226853117436}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":28052768891035579,"pool_token_amount":27838364777449858}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":28035087349683527,"pool_token_amount":27836603064909454}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":28030642233143878,"pool_token_amount":27836161700329014}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":28004629189679650,"pool_token_amount":27832677511120410}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":28000517461989130,"pool_token_amount":27832268862996942}],[57,{"iota_amount":27992301344023125,"pool_token_amount":27831459306861029}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":27984053892141673,"pool_token_amount":27830718554664686}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":27975530426034577,"pool_token_amount":27829802754784297}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":27954593676026232,"pool_token_amount":27827880873840843}],[46,{"iota_amount":27946140285737349,"pool_token_amount":27827032858066130}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":27914725117342875,"pool_token_amount":27822342378992317}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":27905986683322338,"pool_token_amount":27821416570911152}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":27901622991657448,"pool_token_amount":27820973448928955}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":27881703017381339,"pool_token_amount":27817776935090289}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":27036225833098401,"pool_token_amount":26995215285790416}],[24,{"iota_amount":20020118981025677,"pool_token_amount":20001684160504849}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":20015286295222270,"pool_token_amount":20001432914590529}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":20000000000442900,"pool_token_amount":20000000000008856}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"iota_amount":20000000000000000,"pool_token_amount":20000000000000000}]],"[NODERS]TEAM x Criterion VC":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":35685512405161687,"pool_token_amount":34990548761264640}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":35680901822951009,"pool_token_amount":34990096681652182}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":35662463274914515,"pool_token_amount":34988288208345689}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":35642456906122631,"pool_token_amount":34989726080558016}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"iota_amount":35621104854325186,"pool_token_amount":34990022922078565}],[149,{"iota_amount":35611480944552159,"pool_token_amount":34989077523002324}],[145,{"iota_amount":35594889267432401,"pool_token_amount":34989542229932358}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":35590171279848642,"pool_token_amount":34989078454243244}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":35581044976198111,"pool_token_amount":34988447645272869}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":35548026481556977,"pool_token_amount":34989379385759977}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":35501793539658555,"pool_token_amount":34989849349375010}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":35487648765784962,"pool_token_amount":34988456000772605}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":35482934633353872,"pool_token_amount":34987991218365342}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":35468034376982322,"pool_token_amount":34990030976442642}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":35453844070558531,"pool_token_amount":34988586502645621}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":35445163166658383,"pool_token_amount":34988394493978352}],[109,{"iota_amount":35439922360567106,"pool_token_amount":34987877166531510}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":35440110211606420,"pool_token_amount":34992719167325704}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":35434758674125628,"pool_token_amount":34992190768893508}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":35418339698927867,"pool_token_amount":34990569140492434}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"iota_amount":35407433979698612,"pool_token_amount":34989491657954172}],[99,{"iota_amount":35391249803911875,"pool_token_amount":34987893899063425}],[98,{"iota_amount":35386401982332557,"pool_token_amount":34987889991339302}],[97,{"iota_amount":35383222820365260,"pool_token_amount":34989500349815882}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":35377775638657477,"pool_token_amount":34988961691698808}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":35372343045750659,"pool_token_amount":34988424401982961}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":35365301066186645,"pool_token_amount":34991022246494472}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":35359994224662397,"pool_token_amount":34990498071016053}],[90,{"iota_amount":35349418781117843,"pool_token_amount":34989453291537979}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":35324124581544146,"pool_token_amount":34987881955006384}],[84,{"iota_amount":35319415609361708,"pool_token_amount":34987881023750211}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":35303911537176922,"pool_token_amount":34986513188134171}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":35295011936511709,"pool_token_amount":34991884415352838}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":35274119560355052,"pool_token_amount":34989817205668296}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":35263207797353194,"pool_token_amount":34988716894055157}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":35239041836218477,"pool_token_amount":34989555962055678}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":35217483964757468,"pool_token_amount":34987416784401823}],[61,{"iota_amount":35207027086995165,"pool_token_amount":34986368916024809}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":35181936707389152,"pool_token_amount":34989466908485596}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"iota_amount":35144558372430937,"pool_token_amount":34990496893732683}],[46,{"iota_amount":35139223817847847,"pool_token_amount":34989965776752999}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":35128550386908021,"pool_token_amount":34988898413175756}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":35090088100129445,"pool_token_amount":34999855819793100}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":35084201632528454,"pool_token_amount":34999274082785235}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":35072407836900776,"pool_token_amount":34998097472524947}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":35056903087806092,"pool_token_amount":34999119511241006}],[27,{"iota_amount":35050340429815906,"pool_token_amount":34998463428624354}],[26,{"iota_amount":25044566109124850,"pool_token_amount":25011994690715090}],[25,{"iota_amount":25039340119345633,"pool_token_amount":25011473670993887}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"iota_amount":25017803301414388,"pool_token_amount":25000952838081825}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"flipside":[[167,{"iota_amount":27532373588994884,"pool_token_amount":26995323800644628}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":27512992500354338,"pool_token_amount":26995423737105904}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":27499708296725803,"pool_token_amount":26995402304595710}],[156,{"iota_amount":27496370603089881,"pool_token_amount":26995402367441105}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":27493032755888594,"pool_token_amount":26995402447128066}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":27482834538446799,"pool_token_amount":26995222616107719}],[150,{"iota_amount":27476129200268487,"pool_token_amount":26995194240137059}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":27451230606734737,"pool_token_amount":26996542467427820}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":27447619631841414,"pool_token_amount":26996187350498645}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":27440400474450271,"pool_token_amount":26995480807183917}],[138,{"iota_amount":27436786094629896,"pool_token_amount":26995125228977740}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":27471345006980257,"pool_token_amount":27038746789141594}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":27467732150258859,"pool_token_amount":27038391192233070}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":27461064798095201,"pool_token_amount":27038230916663063}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":27457450485634085,"pool_token_amount":27037875050059726}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":27428550802606367,"pool_token_amount":27035037065133579}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"iota_amount":27406886151991049,"pool_token_amount":27032902834648847}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":27392465674457751,"pool_token_amount":27031497979236754}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":27385243770109695,"pool_token_amount":27030784374385394}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":27377597724080075,"pool_token_amount":27030011849113484}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":27369458974700756,"pool_token_amount":27029208252576632}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":27365225673870635,"pool_token_amount":27028790182019597}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[102,{"iota_amount":27348390991217020,"pool_token_amount":27027130618303913}],[100,{"iota_amount":27340172278468169,"pool_token_amount":27026570787440683}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"iota_amount":27318548597338802,"pool_token_amount":27023633611815261}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":27293010945122241,"pool_token_amount":27020251629358645}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":27288971293336854,"pool_token_amount":27019851700870231}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":27268866621258136,"pool_token_amount":27017862153907054}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":27253088766137304,"pool_token_amount":27016718970621909}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":27249085196039786,"pool_token_amount":27016321199007480}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":27241079235156409,"pool_token_amount":27015525604577592}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":27220500732480903,"pool_token_amount":27013469059909230}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":27203269321719891,"pool_token_amount":27011756872847752}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"iota_amount":27174554896427157,"pool_token_amount":27008867932340924}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":27166127501878763,"pool_token_amount":27007649397677727}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":27150373744240000,"pool_token_amount":27006407025015528}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":27142126147188912,"pool_token_amount":27005566887576850}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":27087679279503524,"pool_token_amount":26999259034798305}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":27083590231811537,"pool_token_amount":26998873959970908}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":27066003482032974,"pool_token_amount":26997020878411106}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":27061473674306134,"pool_token_amount":26996594665778317}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":27051620169443605,"pool_token_amount":26994956181712961}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":20010541466205800,"pool_token_amount":20001381426613839}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":20000000025407401,"pool_token_amount":20000000000508134}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":20000000015785201,"pool_token_amount":20000000000315691}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":20000000000537500,"pool_token_amount":20000000000010743}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"gumi":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":28089649481105705,"pool_token_amount":27549229553296235}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"iota_amount":28064485933472788,"pool_token_amount":27547373924223226}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":28053054368008802,"pool_token_amount":27546247804964792}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":28049043023242419,"pool_token_amount":27545675569264851}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"iota_amount":28022628323883408,"pool_token_amount":27543041640343834}],[145,{"iota_amount":28018914143063139,"pool_token_amount":27542676578186921}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":28007776053591359,"pool_token_amount":27541579468802480}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":28004064773854762,"pool_token_amount":27541214517874844}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":27988600877241149,"pool_token_amount":27539155075100299}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":27973745206140639,"pool_token_amount":27537693099464101}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":27970030992607222,"pool_token_amount":27537327467278177}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":27966314282594134,"pool_token_amount":27536959773445759}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":27947740289374544,"pool_token_amount":27535132253951162}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":27940288679184536,"pool_token_amount":27534374105151262}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":27936576425005469,"pool_token_amount":27534008272436664}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":27932862469927464,"pool_token_amount":27533641341284628}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":27925440392910477,"pool_token_amount":27532910596400905}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":27921729267289709,"pool_token_amount":27532544699952348}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":27910797961529416,"pool_token_amount":27531644331061758}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":27903978672157769,"pool_token_amount":27531505705898765}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":27900268040029037,"pool_token_amount":27531139595394793}],[112,{"iota_amount":27896577295174092,"pool_token_amount":27530793174323566}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":27880688624499085,"pool_token_amount":27529033886588305}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":27859422089003889,"pool_token_amount":27526933462659154}],[98,{"iota_amount":27836969500709625,"pool_token_amount":27523652198440132}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":27828517434230719,"pool_token_amount":27522773738140656}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":27794576633666186,"pool_token_amount":27518904826715602}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":27790426127529759,"pool_token_amount":27518493892249750}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":27773902642797369,"pool_token_amount":27516849371604790}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":27744873624322560,"pool_token_amount":27513877598687063}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"iota_amount":27735148759807722,"pool_token_amount":27511574195854449}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":27722254405021128,"pool_token_amount":27510293190437566}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":27650316857266168,"pool_token_amount":27502525673774415}],[53,{"iota_amount":27646204002457652,"pool_token_amount":27502116586609965}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":27642091260215080,"pool_token_amount":27501707455871122}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":27637979192881203,"pool_token_amount":27501298337498057}],[50,{"iota_amount":27633867307112499,"pool_token_amount":27500889182409629}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":27625642734517551,"pool_token_amount":27500070628102297}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":27609178230209736,"pool_token_amount":27498416096826301}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":27605066239433305,"pool_token_amount":27498006547388062}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":27583961979008942,"pool_token_amount":27495917674290648}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":27561470974180397,"pool_token_amount":27493464986141190}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":27542688954400532,"pool_token_amount":27491505311441638}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"iota_amount":20024226520465665,"pool_token_amount":20001541198081181}],[24,{"iota_amount":20019503314880995,"pool_token_amount":20001068989964456}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":20000000000537500,"pool_token_amount":20000000000010743}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":20000000000460100,"pool_token_amount":20000000000009197}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":20000000000455800,"pool_token_amount":20000000000009112}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"iota_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"mrgn":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":143781241375204268,"pool_token_amount":140728373974689481}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":143762283318436356,"pool_token_amount":140727898640005615}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":143743307388722593,"pool_token_amount":140727409559102965}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"iota_amount":143626212256738294,"pool_token_amount":140722029232498623}],[156,{"iota_amount":143587095237597251,"pool_token_amount":140720855634157745}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":143564101484413469,"pool_token_amount":140716902184771534}],[154,{"iota_amount":143597778717958572,"pool_token_amount":140768504113805144}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":143577797641885482,"pool_token_amount":140767505580571284}],[149,{"iota_amount":142196869237580888,"pool_token_amount":139487369055511228}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"iota_amount":143441925318899996,"pool_token_amount":140782849002839805}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":143396024740534671,"pool_token_amount":140774671444527960}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":143372554739672573,"pool_token_amount":140770061459112067}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"iota_amount":143313593685504624,"pool_token_amount":140767488136017455}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":143274086953709866,"pool_token_amount":140765619686574362}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":143155919245644861,"pool_token_amount":140760298825871130}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":143135973218894731,"pool_token_amount":140759168799034963}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":142826578361803996,"pool_token_amount":140713484612977550}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"iota_amount":142749002650021331,"pool_token_amount":140711042416771739}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":142710482024021199,"pool_token_amount":140710093249898521}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":142667445911338223,"pool_token_amount":140708822108848609}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":142645827419318108,"pool_token_amount":140708192635477275}],[106,{"iota_amount":142623516795253190,"pool_token_amount":140707532405009780}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[100,{"iota_amount":142488303920234969,"pool_token_amount":140702371943728416}],[99,{"iota_amount":142466187932556592,"pool_token_amount":140701716777744444}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":142355481139597324,"pool_token_amount":140697731424860664}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":142333688531592497,"pool_token_amount":140697086221028453}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"iota_amount":142236644939543520,"pool_token_amount":140642683535537714}],[90,{"iota_amount":142216521203279543,"pool_token_amount":140643481155432065}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":142151924625217515,"pool_token_amount":140641612680325821}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":142108315905709257,"pool_token_amount":140639693942024777}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":141977014802261872,"pool_token_amount":140633684214749104}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":141955701995257903,"pool_token_amount":140633083807176029}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":141824281644694518,"pool_token_amount":140627642536047104}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":141689056436470155,"pool_token_amount":140623982193974760}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"iota_amount":141581048855008034,"pool_token_amount":140620781320569534}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":141343996236636074,"pool_token_amount":140612660096400970}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"iota_amount":141258034926011825,"pool_token_amount":140610795539826013}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":140167814503844322,"pool_token_amount":139609291100031220}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"iota_amount":140123639114120493,"pool_token_amount":139607603527808617}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"iota_amount":140034352402448289,"pool_token_amount":139604517205229291}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":107995433736031548,"pool_token_amount":107753230994049485}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":107465327177211600,"pool_token_amount":107279053971767767}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":81595177526042636,"pool_token_amount":81558627631456920}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019026363317487,"pool_token_amount":80001922034404952}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000010304137}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"iota_amount":80000000062001508,"pool_token_amount":80000000006200139}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000215393}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000184075}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000184075}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000180597}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"n1stake":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":35695884510858364,"pool_token_amount":34999397177594524}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":35682052513059262,"pool_token_amount":34998041704088657}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"iota_amount":35677442052301834,"pool_token_amount":34997589495740220}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":35663414152987650,"pool_token_amount":34996214172156392}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"iota_amount":35638358475438100,"pool_token_amount":34992867428158254}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":35628472854794850,"pool_token_amount":34991665648475076}],[151,{"iota_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"iota_amount":35609224891436473,"pool_token_amount":34989774908603394}],[148,{"iota_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"iota_amount":35599795219329414,"pool_token_amount":34988848288772563}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"iota_amount":35590361238027694,"pool_token_amount":34987922811019785}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":35580933856845646,"pool_token_amount":34986995974482635}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"iota_amount":35589883926123985,"pool_token_amount":34999970316353537}],[140,{"iota_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"iota_amount":35566292970770879,"pool_token_amount":34997649766885778}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":35547326761594003,"pool_token_amount":34995785812494174}],[132,{"iota_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":35537788657287212,"pool_token_amount":34994893671667603}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":35518912126868975,"pool_token_amount":34993223207508904}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":35509480865535750,"pool_token_amount":34992387834479265}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"iota_amount":35495339415527013,"pool_token_amount":34991140290294962}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"iota_amount":35452878920298045,"pool_token_amount":34987340628884302}],[112,{"iota_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":35459098053544175,"pool_token_amount":35001950483034802}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"iota_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":35426838065794494,"pool_token_amount":34999023851407946}],[102,{"iota_amount":35415932356821990,"pool_token_amount":34998000251301289}],[99,{"iota_amount":35399445178722090,"pool_token_amount":34996183045679838}],[97,{"iota_amount":35388746558362346,"pool_token_amount":34995200663423735}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":35383292384933425,"pool_token_amount":34994682021246894}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"iota_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":35335415839966122,"pool_token_amount":34990188332254264}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":35303984229399429,"pool_token_amount":34987237813460523}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":35302790303492847,"pool_token_amount":35000327554196805}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"iota_amount":35281874305664661,"pool_token_amount":34998340487047747}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"iota_amount":35276539495582833,"pool_token_amount":34997837752908948}],[73,{"iota_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"iota_amount":35270977542662803,"pool_token_amount":34997309052626871}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"iota_amount":35248719052239813,"pool_token_amount":34995186785710478}],[67,{"iota_amount":35243162553192326,"pool_token_amount":34994662715071092}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":35237725157518728,"pool_token_amount":34994256757198971}],[64,{"iota_amount":35226826282559102,"pool_token_amount":34993121496684913}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":35221602680111719,"pool_token_amount":34992628546658942}],[62,{"iota_amount":35216379384042433,"pool_token_amount":34992135559388359}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"iota_amount":35185960702377644,"pool_token_amount":34990094273326690}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"iota_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"iota_amount":35166080371835165,"pool_token_amount":34999041352051031}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"iota_amount":35138995641189211,"pool_token_amount":34996108608441680}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":35123076964091264,"pool_token_amount":34994678958666948}],[42,{"iota_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"iota_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":35084613848909738,"pool_token_amount":34990962962551550}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":35066922499685804,"pool_token_amount":34989252208275169}],[31,{"iota_amount":35061020819628992,"pool_token_amount":34988654367370199}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"iota_amount":35049301829058695,"pool_token_amount":34987645711790961}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"iota_amount":35043127530283935,"pool_token_amount":34986991635518040}],[27,{"iota_amount":35036744125201953,"pool_token_amount":34986414567028118}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"iota_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"proofgroup":[[167,{"iota_amount":35772142215430461,"pool_token_amount":35044630444734000}],[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":35762719581942334,"pool_token_amount":35043984234276463}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":35743980318891519,"pool_token_amount":35042698612246563}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":35734554057886969,"pool_token_amount":35042048943705223}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"iota_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"iota_amount":35700696013427073,"pool_token_amount":35039562770667406}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":35638210338012381,"pool_token_amount":35035268828159321}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":35633491564562626,"pool_token_amount":35034944101792459}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":35619333104022033,"pool_token_amount":35033969535367050}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":35614511961912440,"pool_token_amount":35033633942146394}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":35604976024779460,"pool_token_amount":35032977271896757}],[131,{"iota_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"iota_amount":35585937671829082,"pool_token_amount":35031705696880001}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":35566873606110726,"pool_token_amount":35030393612034431}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":35552627797126937,"pool_token_amount":35029413158471376}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":35528845211603282,"pool_token_amount":35027759659204033}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"iota_amount":35525886019425708,"pool_token_amount":35029255900634413}],[114,{"iota_amount":35521070597162425,"pool_token_amount":35028921698855211}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"iota_amount":35496855487637924,"pool_token_amount":35027611692468671}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":35491502013389145,"pool_token_amount":35027240067274166}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":35475070509787718,"pool_token_amount":35026104736170958}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"iota_amount":35452888341247571,"pool_token_amount":35024405988200284}],[98,{"iota_amount":35436284673213118,"pool_token_amount":35023060157927975}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":35409060225899448,"pool_token_amount":35021039061486381}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"iota_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":35371746017007473,"pool_token_amount":35018457367933253}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":35354045531814445,"pool_token_amount":35015395593946908}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":35337527302222253,"pool_token_amount":35013900222920192}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":35332185585793852,"pool_token_amount":35013529727146290}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"iota_amount":35321726128541859,"pool_token_amount":35012797673176745}],[76,{"iota_amount":35316392269509581,"pool_token_amount":35012427568586350}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":35294712270130274,"pool_token_amount":35010916253222684}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"iota_amount":35286594809324366,"pool_token_amount":35013119836907039}],[69,{"iota_amount":35281036465130049,"pool_token_amount":35012734694850448}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"iota_amount":35256003176342132,"pool_token_amount":35008403290394893}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"iota_amount":35245314055553296,"pool_token_amount":35007641785184758}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"iota_amount":35223767014795454,"pool_token_amount":35005951138361062}],[58,{"iota_amount":35218432380461630,"pool_token_amount":35005580023125408}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":35202254199954330,"pool_token_amount":35004294021820698}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"iota_amount":35163661677670141,"pool_token_amount":35000452507330301}],[45,{"iota_amount":35147454666865835,"pool_token_amount":34999134229356807}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":35142113383369845,"pool_token_amount":34998755434776608}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":35131421441483279,"pool_token_amount":34997989159133137}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"iota_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"iota_amount":35041315958748060,"pool_token_amount":34988508064706652}],[25,{"iota_amount":25029360201706229,"pool_token_amount":25001139969309546}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":25011906824167687,"pool_token_amount":25000348354054695}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"iota_amount":25000000019836964,"pool_token_amount":25000000000396727}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"iota_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"iota_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":25000000000550800,"pool_token_amount":25000000000011015}],[1,{"iota_amount":25000000000000000,"pool_token_amount":25000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]],"stakefish":[[167,{"iota_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"iota_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"iota_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"iota_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"iota_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"iota_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"iota_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"iota_amount":56158647597223730,"pool_token_amount":24286724137068177}],[155,{"iota_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"iota_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"iota_amount":29987466294310320,"pool_token_amount":29396693730148779}],[151,{"iota_amount":29979659782829278,"pool_token_amount":29396746064794266}],[149,{"iota_amount":29969296302076027,"pool_token_amount":29394290770324031}],[149,{"iota_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"iota_amount":60577452505114017,"pool_token_amount":26236842628119062}],[145,{"iota_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"iota_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"iota_amount":29926742928748465,"pool_token_amount":29379547446181397}],[142,{"iota_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"iota_amount":29915506088501234,"pool_token_amount":29380097874815043}],[139,{"iota_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"iota_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"iota_amount":29904117564503015,"pool_token_amount":29376646075112161}],[136,{"iota_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"iota_amount":29896952575462895,"pool_token_amount":29377339403359865}],[135,{"iota_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"iota_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"iota_amount":29888849828079269,"pool_token_amount":29377109318607311}],[133,{"iota_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"iota_amount":29884817162144206,"pool_token_amount":29377013381909179}],[130,{"iota_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"iota_amount":29869433137088863,"pool_token_amount":29373499711540314}],[128,{"iota_amount":29864756707821774,"pool_token_amount":29372773558718077}],[128,{"iota_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"iota_amount":29860771210262593,"pool_token_amount":29372723919018755}],[127,{"iota_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"iota_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"iota_amount":29850986614554744,"pool_token_amount":29370836955533486}],[125,{"iota_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"iota_amount":29846154173539812,"pool_token_amount":29369952245583494}],[124,{"iota_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"iota_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"iota_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"iota_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"iota_amount":29837022687388869,"pool_token_amount":29376447741189862}],[120,{"iota_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"iota_amount":29833261047429264,"pool_token_amount":29376615394667133}],[119,{"iota_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"iota_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"iota_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"iota_amount":29793892295406813,"pool_token_amount":29361069801172803}],[111,{"iota_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"iota_amount":90853781868271072,"pool_token_amount":39531943192078969}],[109,{"iota_amount":29766564766399940,"pool_token_amount":29350070552647092}],[109,{"iota_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"iota_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"iota_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"iota_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"iota_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"iota_amount":90592941540681178,"pool_token_amount":39456929245771835}],[97,{"iota_amount":35622556754076862,"pool_token_amount":35189307561422818}],[97,{"iota_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"iota_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"iota_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"iota_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"iota_amount":35605171138173493,"pool_token_amount":35198429693195976}],[90,{"iota_amount":35593350420808782,"pool_token_amount":35197209709578066}],[89,{"iota_amount":35588684905836326,"pool_token_amount":35197820690881089}],[88,{"iota_amount":35579717253618074,"pool_token_amount":35194172033909190}],[88,{"iota_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"iota_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"iota_amount":35560905889181868,"pool_token_amount":35186000649044621}],[86,{"iota_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"iota_amount":35553934892259634,"pool_token_amount":35184297720899163}],[84,{"iota_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"iota_amount":35509889152282837,"pool_token_amount":35151179795604794}],[82,{"iota_amount":35502708655654310,"pool_token_amount":35149254591849708}],[82,{"iota_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"iota_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"iota_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"iota_amount":35462458208177270,"pool_token_amount":35125055580699049}],[79,{"iota_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"iota_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"iota_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"iota_amount":35430972578159967,"pool_token_amount":35114584443905531}],[75,{"iota_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"iota_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"iota_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"iota_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"iota_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"iota_amount":35404646451811103,"pool_token_amount":35131352034301923}],[67,{"iota_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"iota_amount":35387363056137505,"pool_token_amount":35119605286884066}],[66,{"iota_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"iota_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"iota_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"iota_amount":35360029536078967,"pool_token_amount":35113446846709509}],[61,{"iota_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"iota_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"iota_amount":35300503330313385,"pool_token_amount":35075094549986471}],[57,{"iota_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"iota_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"iota_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"iota_amount":35250633848556019,"pool_token_amount":35046426386715321}],[53,{"iota_amount":35242541953131432,"pool_token_amount":35043579960269895}],[53,{"iota_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"iota_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"iota_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"iota_amount":35217819963063001,"pool_token_amount":35039791182265267}],[45,{"iota_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"iota_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"iota_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"iota_amount":41565353909791740,"pool_token_amount":41401171064416038}],[41,{"iota_amount":41578069248243148,"pool_token_amount":41420132016189796}],[41,{"iota_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"iota_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"iota_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"iota_amount":50702614556263042,"pool_token_amount":22293262884852417}],[33,{"iota_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"iota_amount":27076471991557233,"pool_token_amount":27011934871055111}],[32,{"iota_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"iota_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"iota_amount":27055367005343712,"pool_token_amount":26999791776119831}],[29,{"iota_amount":27050707684424655,"pool_token_amount":26999711110626054}],[29,{"iota_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"iota_amount":20034300924308984,"pool_token_amount":20007469271295953}],[24,{"iota_amount":20023379351249717,"pool_token_amount":20004942863108159}],[24,{"iota_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"iota_amount":20011405966195300,"pool_token_amount":20002245765140753}],[22,{"iota_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"iota_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"iota_amount":20000000025396901,"pool_token_amount":20000000000507924}],[20,{"iota_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"iota_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"iota_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"iota_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"iota_amount":20000000000449600,"pool_token_amount":20000000000008987}],[9,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"iota_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"iota_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"iota_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"iota_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"iota_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"iota_amount":20000000000428400,"pool_token_amount":20000000000008567}],[1,{"iota_amount":80000000000000000,"pool_token_amount":80000000000000000}],[0,{"iota_amount":0,"pool_token_amount":0}]]} \ No newline at end of file diff --git a/crates/iota-json/Cargo.toml b/crates/iota-json/Cargo.toml new file mode 100644 index 00000000000..9e6d9fa9469 --- /dev/null +++ b/crates/iota-json/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "iota-json" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +bcs.workspace = true +serde.workspace = true +serde_json.workspace = true +schemars.workspace = true + +iota-framework.workspace = true +iota-types.workspace = true + +move-binary-format.workspace = true +move-bytecode-utils.workspace = true +move-core-types.workspace = true +fastcrypto = { workspace = true } + +[dev-dependencies] +test-fuzz.workspace = true +iota-types = { workspace = true, features = ["test-utils"] } +iota-move-build.workspace = true diff --git a/crates/iota-json/src/lib.rs b/crates/iota-json/src/lib.rs new file mode 100644 index 00000000000..1ac1868be90 --- /dev/null +++ b/crates/iota-json/src/lib.rs @@ -0,0 +1,965 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{BTreeMap, VecDeque}, + fmt::{self, Debug, Formatter}, + str::FromStr, +}; + +use anyhow::{anyhow, bail}; +use fastcrypto::encoding::{Encoding, Hex}; +use iota_types::{ + base_types::{ + is_primitive_type_tag, IotaAddress, ObjectID, TxContext, TxContextKind, RESOLVED_ASCII_STR, + RESOLVED_STD_OPTION, RESOLVED_UTF8_STR, STD_ASCII_MODULE_NAME, STD_ASCII_STRUCT_NAME, + STD_OPTION_MODULE_NAME, STD_OPTION_STRUCT_NAME, STD_UTF8_MODULE_NAME, STD_UTF8_STRUCT_NAME, + }, + id::{ID, RESOLVED_IOTA_ID}, + move_package::MovePackage, + object::bounded_visitor::BoundedVisitor, + transfer::RESOLVED_RECEIVING_STRUCT, + MOVE_STDLIB_ADDRESS, +}; +use move_binary_format::{ + access::ModuleAccess, binary_config::BinaryConfig, binary_views::BinaryIndexedView, + file_format::SignatureToken, +}; +use move_bytecode_utils::resolve_struct; +pub use move_core_types::annotated_value::MoveTypeLayout; +use move_core_types::{ + account_address::AccountAddress, + annotated_value::{MoveFieldLayout, MoveStruct, MoveStructLayout, MoveValue}, + ident_str, + identifier::{IdentStr, Identifier}, + language_storage::{StructTag, TypeTag}, + runtime_value as R, + u256::U256, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Number, Value as JsonValue}; + +const HEX_PREFIX: &str = "0x"; + +#[cfg(test)] +mod tests; + +/// A list of error categories encountered when parsing numbers. +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +pub enum IotaJsonValueErrorKind { + /// JSON value must be of specific types. + ValueTypeNotAllowed, + + /// JSON arrays must be homogeneous. + ArrayNotHomogeneous, +} + +#[derive(Debug)] +pub struct IotaJsonValueError { + kind: IotaJsonValueErrorKind, + val: JsonValue, +} + +impl IotaJsonValueError { + pub fn new(val: &JsonValue, kind: IotaJsonValueErrorKind) -> Self { + Self { + kind, + val: val.clone(), + } + } +} + +impl std::error::Error for IotaJsonValueError {} + +impl fmt::Display for IotaJsonValueError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let err_str = match self.kind { + IotaJsonValueErrorKind::ValueTypeNotAllowed => { + format!("JSON value type {} not allowed.", self.val) + } + IotaJsonValueErrorKind::ArrayNotHomogeneous => { + format!("Array not homogeneous. Mismatched value: {}.", self.val) + } + }; + write!(f, "{err_str}") + } +} + +// Intermediate type to hold resolved args +#[derive(Eq, PartialEq, Debug)] +pub enum ResolvedCallArg { + Object(ObjectID), + Pure(Vec), + ObjVec(Vec), +} + +#[derive(Eq, PartialEq, Clone, Deserialize, Serialize, JsonSchema)] +pub struct IotaJsonValue(JsonValue); +impl IotaJsonValue { + pub fn new(json_value: JsonValue) -> Result { + Self::check_value(&json_value)?; + Ok(Self(json_value)) + } + + fn check_value(json_value: &JsonValue) -> Result<(), anyhow::Error> { + match json_value { + // No checks needed for Bool and String + JsonValue::Bool(_) | JsonValue::String(_) => (), + JsonValue::Number(n) => { + // Must be castable to u64 + if !n.is_u64() { + return Err(anyhow!( + "{n} not allowed. Number must be unsigned integer of at most u32" + )); + } + } + // Must be homogeneous + JsonValue::Array(a) => { + // Fail if not homogeneous + check_valid_homogeneous(&JsonValue::Array(a.to_vec()))? + } + JsonValue::Object(v) => { + for (_, value) in v { + Self::check_value(value)?; + } + } + JsonValue::Null => bail!("Null not allowed."), + }; + Ok(()) + } + + pub fn from_object_id(id: ObjectID) -> IotaJsonValue { + Self(JsonValue::String(id.to_hex_uncompressed())) + } + + pub fn to_bcs_bytes(&self, ty: &MoveTypeLayout) -> Result, anyhow::Error> { + let move_value = Self::to_move_value(&self.0, ty)?; + R::MoveValue::simple_serialize(&move_value) + .ok_or_else(|| anyhow!("Unable to serialize {:?}. Expected {}", move_value, ty)) + } + + pub fn from_bcs_bytes( + layout: Option<&MoveTypeLayout>, + bytes: &[u8], + ) -> Result { + let json = if let Some(layout) = layout { + // Try to convert Vec inputs into string + fn try_parse_string(layout: &MoveTypeLayout, bytes: &[u8]) -> Option { + if let MoveTypeLayout::Vector(t) = layout { + if let MoveTypeLayout::U8 = **t { + return bcs::from_bytes::(bytes).ok(); + } + } + None + } + if let Some(s) = try_parse_string(layout, bytes) { + json!(s) + } else { + let result = BoundedVisitor::deserialize_value(bytes, layout).map_or_else( + |_| { + // fallback to array[u8] if fail to convert to json. + JsonValue::Array( + bytes + .iter() + .map(|b| JsonValue::Number(Number::from(*b))) + .collect(), + ) + }, + |move_value| { + move_value_to_json(&move_value).unwrap_or_else(|| { + // fallback to array[u8] if fail to convert to json. + JsonValue::Array( + bytes + .iter() + .map(|b| JsonValue::Number(Number::from(*b))) + .collect(), + ) + }) + }, + ); + result + } + } else { + json!(bytes) + }; + IotaJsonValue::new(json) + } + + pub fn to_json_value(&self) -> JsonValue { + self.0.clone() + } + + pub fn to_iota_address(&self) -> anyhow::Result { + json_value_to_iota_address(&self.0) + } + + fn handle_inner_struct_layout( + inner_vec: &[MoveFieldLayout], + val: &JsonValue, + ty: &MoveTypeLayout, + s: &String, + ) -> Result { + // delegate MoveValue construction to the case when JsonValue::String and + // MoveTypeLayout::Vector are handled to get an address (with 0x string + // prefix) or a vector of u8s (no prefix) + debug_assert!(matches!(val, JsonValue::String(_))); + + if inner_vec.len() != 1 { + bail!( + "Cannot convert string arg {s} to {ty} which is expected \ + to be a struct with one field" + ); + } + + match &inner_vec[0].layout { + MoveTypeLayout::Vector(inner) => match **inner { + MoveTypeLayout::U8 => Ok(R::MoveValue::Struct(R::MoveStruct(vec![ + Self::to_move_value(val, &inner_vec[0].layout.clone())?, + ]))), + MoveTypeLayout::Address => Ok(R::MoveValue::Struct(R::MoveStruct(vec![ + Self::to_move_value(val, &MoveTypeLayout::Address)?, + ]))), + _ => bail!( + "Cannot convert string arg {s} to {ty} \ + which is expected to be a struct \ + with one field of address or u8 vector type" + ), + }, + MoveTypeLayout::Struct(MoveStructLayout { type_, .. }) if type_ == &ID::type_() => { + Ok(R::MoveValue::Struct(R::MoveStruct(vec![ + Self::to_move_value(val, &inner_vec[0].layout.clone())?, + ]))) + } + _ => bail!( + "Cannot convert string arg {s} to {ty} which is expected \ + to be a struct with one field of a vector type" + ), + } + } + + pub fn to_move_value( + val: &JsonValue, + ty: &MoveTypeLayout, + ) -> Result { + Ok(match (val, ty) { + // Bool to Bool is simple + (JsonValue::Bool(b), MoveTypeLayout::Bool) => R::MoveValue::Bool(*b), + + // In constructor, we have already checked that the JSON number is unsigned int of at + // most U32 + (JsonValue::Number(n), MoveTypeLayout::U8) => match n.as_u64() { + Some(x) => R::MoveValue::U8(u8::try_from(x)?), + None => return Err(anyhow!("{} is not a valid number. Only u8 allowed.", n)), + }, + (JsonValue::Number(n), MoveTypeLayout::U16) => match n.as_u64() { + Some(x) => R::MoveValue::U16(u16::try_from(x)?), + None => return Err(anyhow!("{} is not a valid number. Only u16 allowed.", n)), + }, + (JsonValue::Number(n), MoveTypeLayout::U32) => match n.as_u64() { + Some(x) => R::MoveValue::U32(u32::try_from(x)?), + None => return Err(anyhow!("{} is not a valid number. Only u32 allowed.", n)), + }, + + // u8, u16, u32, u64, u128, u256 can be encoded as String + (JsonValue::String(s), MoveTypeLayout::U8) => { + R::MoveValue::U8(u8::try_from(convert_string_to_u256(s.as_str())?)?) + } + (JsonValue::String(s), MoveTypeLayout::U16) => { + R::MoveValue::U16(u16::try_from(convert_string_to_u256(s.as_str())?)?) + } + (JsonValue::String(s), MoveTypeLayout::U32) => { + R::MoveValue::U32(u32::try_from(convert_string_to_u256(s.as_str())?)?) + } + (JsonValue::String(s), MoveTypeLayout::U64) => { + R::MoveValue::U64(u64::try_from(convert_string_to_u256(s.as_str())?)?) + } + (JsonValue::String(s), MoveTypeLayout::U128) => { + R::MoveValue::U128(u128::try_from(convert_string_to_u256(s.as_str())?)?) + } + (JsonValue::String(s), MoveTypeLayout::U256) => { + R::MoveValue::U256(convert_string_to_u256(s.as_str())?) + } + // For ascii and utf8 strings + ( + JsonValue::String(s), + MoveTypeLayout::Struct(MoveStructLayout { type_, fields: _ }), + ) if is_move_string_type(type_) => { + R::MoveValue::Vector(s.as_bytes().iter().copied().map(R::MoveValue::U8).collect()) + } + // For ID + (JsonValue::String(s), MoveTypeLayout::Struct(MoveStructLayout { type_, fields })) + if type_ == &ID::type_() => + { + if fields.len() != 1 { + bail!( + "Cannot convert string arg {s} to {type_} which is expected to be a struct with one field" + ); + }; + let addr = IotaAddress::from_str(s)?; + R::MoveValue::Address(addr.into()) + } + (JsonValue::Object(o), MoveTypeLayout::Struct(MoveStructLayout { fields, .. })) => { + let mut field_values = vec![]; + for layout in fields { + let field = o + .get(layout.name.as_str()) + .ok_or_else(|| anyhow!("Missing field {} for struct {ty}", layout.name))?; + field_values.push(Self::to_move_value(field, &layout.layout)?); + } + R::MoveValue::Struct(R::MoveStruct(field_values)) + } + // Unnest fields + (value, MoveTypeLayout::Struct(MoveStructLayout { fields, .. })) + if fields.len() == 1 => + { + Self::to_move_value(value, &fields[0].layout)? + } + (JsonValue::String(s), MoveTypeLayout::Vector(t)) => { + match &**t { + MoveTypeLayout::U8 => { + // We can encode U8 Vector as string in 2 ways + // 1. If it starts with 0x, we treat it as hex strings, where each pair is a + // byte + // 2. If it does not start with 0x, we treat each character as an ASCII + // encoded byte + // We have to support both for the convenience of the user. This is because + // sometime we need Strings as arg Other times we need vec of hex bytes for + // address. Issue is both Address and Strings are represented as Vec in + // Move call + let vec = if s.starts_with(HEX_PREFIX) { + // If starts with 0x, treat as hex vector + Hex::decode(s).map_err(|e| anyhow!(e))? + } else { + // Else raw bytes + s.as_bytes().to_vec() + }; + R::MoveValue::Vector(vec.iter().copied().map(R::MoveValue::U8).collect()) + } + MoveTypeLayout::Struct(MoveStructLayout { fields: inner, .. }) => { + Self::handle_inner_struct_layout(inner, val, ty, s)? + } + _ => bail!("Cannot convert string arg {s} to {ty}"), + } + } + + // We have already checked that the array is homogeneous in the constructor + (JsonValue::Array(a), MoveTypeLayout::Vector(inner)) => { + // Recursively build an IntermediateValue array + R::MoveValue::Vector( + a.iter() + .map(|i| Self::to_move_value(i, inner)) + .collect::, _>>()?, + ) + } + + (v, MoveTypeLayout::Address) => { + let addr = json_value_to_iota_address(v)?; + R::MoveValue::Address(addr.into()) + } + + _ => bail!("Unexpected arg {val:?} for expected type {ty:?}"), + }) + } +} + +impl Debug for IotaJsonValue { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +fn json_value_to_iota_address(value: &JsonValue) -> anyhow::Result { + match value { + JsonValue::String(s) => { + let s = s.trim().to_lowercase(); + if !s.starts_with(HEX_PREFIX) { + bail!("Address hex string must start with 0x.",); + } + Ok(IotaAddress::from_str(&s)?) + } + JsonValue::Array(bytes) => { + fn value_to_byte_array(v: &Vec) -> Option> { + let mut bytes = vec![]; + for b in v { + let b = b.as_u64()?; + if b <= u8::MAX as u64 { + bytes.push(b as u8); + } else { + return None; + } + } + Some(bytes) + } + let bytes = value_to_byte_array(bytes) + .ok_or_else(|| anyhow!("Invalid input: Cannot parse input into IotaAddress."))?; + Ok(IotaAddress::try_from(bytes)?) + } + v => bail!("Unexpected arg {v} for expected type address"), + } +} + +fn move_value_to_json(move_value: &MoveValue) -> Option { + Some(match move_value { + MoveValue::Vector(values) => JsonValue::Array( + values + .iter() + .map(move_value_to_json) + .collect::>()?, + ), + MoveValue::Bool(v) => json!(v), + MoveValue::Signer(v) | MoveValue::Address(v) => json!(IotaAddress::from(*v).to_string()), + MoveValue::U8(v) => json!(v), + MoveValue::U64(v) => json!(v.to_string()), + MoveValue::U128(v) => json!(v.to_string()), + MoveValue::U16(v) => json!(v), + MoveValue::U32(v) => json!(v), + MoveValue::U256(v) => json!(v.to_string()), + MoveValue::Struct(move_struct) => match move_struct { + MoveStruct { fields, type_ } if is_move_string_type(type_) => { + // ascii::string and utf8::string has a single bytes field. + let (_, v) = fields.first()?; + let string: String = bcs::from_bytes(&v.simple_serialize()?).ok()?; + json!(string) + } + MoveStruct { fields, type_ } if is_move_option_type(type_) => { + // option has a single vec field. + let (_, v) = fields.first()?; + if let MoveValue::Vector(v) = v { + JsonValue::Array(v.iter().filter_map(move_value_to_json).collect::>()) + } else { + return None; + } + } + MoveStruct { fields, type_ } if type_ == &ID::type_() => { + // option has a single vec field. + let (_, v) = fields.first()?; + if let MoveValue::Address(address) = v { + json!(IotaAddress::from(*address)) + } else { + return None; + } + } + // We only care about values here, assuming struct type information is known at the + // client side. + MoveStruct { fields, .. } => { + let fields = fields + .iter() + .map(|(key, value)| (key, move_value_to_json(value))) + .collect::>(); + json!(fields) + } + }, + }) +} + +fn is_move_string_type(tag: &StructTag) -> bool { + (tag.address == MOVE_STDLIB_ADDRESS + && tag.module.as_ident_str() == STD_UTF8_MODULE_NAME + && tag.name.as_ident_str() == STD_UTF8_STRUCT_NAME) + || (tag.address == MOVE_STDLIB_ADDRESS + && tag.module.as_ident_str() == STD_ASCII_MODULE_NAME + && tag.name.as_ident_str() == STD_ASCII_STRUCT_NAME) +} +fn is_move_option_type(tag: &StructTag) -> bool { + tag.address == MOVE_STDLIB_ADDRESS + && tag.module.as_ident_str() == STD_OPTION_MODULE_NAME + && tag.name.as_ident_str() == STD_OPTION_STRUCT_NAME +} + +impl FromStr for IotaJsonValue { + type Err = anyhow::Error; + fn from_str(s: &str) -> Result { + fn try_escape_array(s: &str) -> JsonValue { + let s = s.trim(); + if s.starts_with('[') && s.ends_with(']') { + if let Some(s) = s.strip_prefix('[').and_then(|s| s.strip_suffix(']')) { + return JsonValue::Array(s.split(',').map(try_escape_array).collect()); + } + } + json!(s) + } + // if serde_json fails, the failure usually cause by missing quote escapes, try + // parse array manually. + IotaJsonValue::new(serde_json::from_str(s).unwrap_or_else(|_| try_escape_array(s))) + } +} + +#[derive(Eq, PartialEq, Debug, Clone, Hash)] +enum ValidJsonType { + Bool, + Number, + String, + Array, + // Matches any type + Any, +} + +/// Check via BFS +/// The invariant is that all types at a given level must be the same or be +/// empty, and all must be valid +pub fn check_valid_homogeneous(val: &JsonValue) -> Result<(), IotaJsonValueError> { + let mut deq: VecDeque<&JsonValue> = VecDeque::new(); + deq.push_back(val); + check_valid_homogeneous_rec(&mut deq) +} + +/// Check via BFS +/// The invariant is that all types at a given level must be the same or be +/// empty +fn check_valid_homogeneous_rec( + curr_q: &mut VecDeque<&JsonValue>, +) -> Result<(), IotaJsonValueError> { + if curr_q.is_empty() { + // Nothing to do + return Ok(()); + } + // Queue for the next level + let mut next_q = VecDeque::new(); + // The types at this level must be the same + let mut level_type = ValidJsonType::Any; + + // Process all in this queue/level + while let Some(v) = curr_q.pop_front() { + let curr = match v { + JsonValue::Bool(_) => ValidJsonType::Bool, + JsonValue::Number(x) if x.is_u64() => ValidJsonType::Number, + JsonValue::String(_) => ValidJsonType::String, + JsonValue::Array(w) => { + // Add to the next level + w.iter().for_each(|t| next_q.push_back(t)); + ValidJsonType::Array + } + // Not valid + _ => { + return Err(IotaJsonValueError::new( + v, + IotaJsonValueErrorKind::ValueTypeNotAllowed, + )); + } + }; + + if level_type == ValidJsonType::Any { + // Update the level with the first found type + level_type = curr; + } else if level_type != curr { + // Mismatch in the level + return Err(IotaJsonValueError::new( + v, + IotaJsonValueErrorKind::ArrayNotHomogeneous, + )); + } + } + // Process the next level + check_valid_homogeneous_rec(&mut next_q) +} + +/// Checks if a give SignatureToken represents a primitive type and, if so, +/// returns MoveTypeLayout for this type (if available). The reason we need to +/// return both information about whether a SignatureToken represents a +/// primitive and an Option representing MoveTypeLayout is that there +/// can be signature tokens that represent primitives but that do not have +/// corresponding MoveTypeLayout (e.g., SignatureToken::StructInstantiation). +pub fn primitive_type( + view: &BinaryIndexedView, + type_args: &[TypeTag], + param: &SignatureToken, +) -> (bool, Option) { + match param { + SignatureToken::Bool => (true, Some(MoveTypeLayout::Bool)), + SignatureToken::U8 => (true, Some(MoveTypeLayout::U8)), + SignatureToken::U16 => (true, Some(MoveTypeLayout::U16)), + SignatureToken::U32 => (true, Some(MoveTypeLayout::U32)), + SignatureToken::U64 => (true, Some(MoveTypeLayout::U64)), + SignatureToken::U128 => (true, Some(MoveTypeLayout::U128)), + SignatureToken::U256 => (true, Some(MoveTypeLayout::U256)), + SignatureToken::Address => (true, Some(MoveTypeLayout::Address)), + SignatureToken::Vector(inner) => { + let (is_primitive, inner_layout_opt) = primitive_type(view, type_args, inner); + match inner_layout_opt { + Some(inner_layout) => ( + is_primitive, + Some(MoveTypeLayout::Vector(Box::new(inner_layout))), + ), + None => (is_primitive, None), + } + } + SignatureToken::Struct(struct_handle_idx) => { + let resolved_struct = resolve_struct(view, *struct_handle_idx); + if resolved_struct == RESOLVED_ASCII_STR { + ( + true, + Some(MoveTypeLayout::Struct(MoveStructLayout { + type_: resolved_to_struct(RESOLVED_ASCII_STR), + fields: vec![MoveFieldLayout::new( + ident_str!("bytes").into(), + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + )], + })), + ) + } else if resolved_struct == RESOLVED_UTF8_STR { + // both structs structs representing strings have one field - a vector of type + // u8 + ( + true, + Some(MoveTypeLayout::Struct(MoveStructLayout { + type_: resolved_to_struct(RESOLVED_UTF8_STR), + fields: vec![MoveFieldLayout::new( + ident_str!("bytes").into(), + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + )], + })), + ) + } else if resolved_struct == RESOLVED_IOTA_ID { + ( + true, + Some(MoveTypeLayout::Struct(MoveStructLayout { + type_: resolved_to_struct(RESOLVED_IOTA_ID), + fields: vec![MoveFieldLayout::new( + ident_str!("bytes").into(), + MoveTypeLayout::Address, + )], + })), + ) + } else { + (false, None) + } + } + SignatureToken::StructInstantiation(struct_inst) => { + let (idx, targs) = &**struct_inst; + let resolved_struct = resolve_struct(view, *idx); + // is option of a primitive + if resolved_struct == RESOLVED_STD_OPTION && targs.len() == 1 { + // there is no MoveLayout for this so while we can still report whether a type + // is primitive or not, we can't return the layout + let (is_primitive, inner_layout) = primitive_type(view, type_args, &targs[0]); + let layout = + inner_layout.map(|inner_layout| MoveTypeLayout::Vector(Box::new(inner_layout))); + (is_primitive, layout) + } else { + (false, None) + } + } + + SignatureToken::TypeParameter(idx) => ( + type_args + .get(*idx as usize) + .map(is_primitive_type_tag) + .unwrap_or(false), + None, + ), + + SignatureToken::Signer + | SignatureToken::Reference(_) + | SignatureToken::MutableReference(_) => (false, None), + } +} + +fn resolved_to_struct(resolved_type: (&AccountAddress, &IdentStr, &IdentStr)) -> StructTag { + StructTag { + address: *resolved_type.0, + module: resolved_type.1.into(), + name: resolved_type.2.into(), + type_params: vec![], + } +} + +fn resolve_object_arg(idx: usize, arg: &JsonValue) -> Result { + // Every elem has to be a string convertible to a ObjectID + match arg { + JsonValue::String(s) => { + let s = s.trim().to_lowercase(); + if !s.starts_with(HEX_PREFIX) { + bail!("ObjectID hex string must start with 0x.",); + } + Ok(ObjectID::from_hex_literal(&s)?) + } + _ => bail!( + "Unable to parse arg {:?} as ObjectID at pos {}. Expected {:?}-byte hex string \ + prefixed with 0x.", + arg, + idx, + ObjectID::LENGTH, + ), + } +} + +fn resolve_object_vec_arg(idx: usize, arg: &IotaJsonValue) -> Result, anyhow::Error> { + // Every elem has to be a string convertible to a ObjectID + match arg.to_json_value() { + JsonValue::Array(a) => { + let mut object_ids = vec![]; + for id in a { + object_ids.push(resolve_object_arg(idx, &id)?); + } + Ok(object_ids) + } + JsonValue::String(s) if s.starts_with('[') && s.ends_with(']') => { + // Due to how escaping of square bracket works, we may be dealing with a JSON + // string representing a JSON array rather than with the array + // itself ("[0x42,0x7]" rather than [0x42,0x7]). + let mut object_ids = vec![]; + for tok in s[1..s.len() - 1].to_string().split(',') { + let id = JsonValue::String(tok.to_string()); + object_ids.push(resolve_object_arg(idx, &id)?); + } + Ok(object_ids) + } + _ => bail!( + "Unable to parse arg {:?} as vector of ObjectIDs at pos {}. \ + Expected a vector of {:?}-byte hex strings prefixed with 0x.\n\ + Consider escaping your curly braces with a backslash (as in \\[0x42,0x7\\]) \ + or enclosing the whole vector in single quotes (as in '[0x42,0x7]')", + arg.to_json_value(), + idx, + ObjectID::LENGTH, + ), + } +} + +fn resolve_call_arg( + view: &BinaryIndexedView, + type_args: &[TypeTag], + idx: usize, + arg: &IotaJsonValue, + param: &SignatureToken, +) -> Result { + let (is_primitive, layout_opt) = primitive_type(view, type_args, param); + if is_primitive { + match layout_opt { + Some(layout) => { + return Ok(ResolvedCallArg::Pure(arg.to_bcs_bytes(&layout).map_err( + |e| { + anyhow!( + "Could not serialize argument of type {:?} at {} into {}. Got error: {:?}", + param, + idx, + layout, + e + ) + }, + )?)); + } + None => { + debug_assert!( + false, + "Should be unreachable. All primitive type function args \ + should have a corresponding MoveLayout" + ); + bail!( + "Could not serialize argument of type {:?} at {}", + param, + idx + ); + } + } + } + + // in terms of non-primitives we only currently support objects and "flat" + // (depth == 1) vectors of objects (but not, for example, vectors of + // references) + match param { + SignatureToken::Struct(_) + | SignatureToken::StructInstantiation(_) + | SignatureToken::TypeParameter(_) + | SignatureToken::Reference(_) + | SignatureToken::MutableReference(_) => Ok(ResolvedCallArg::Object(resolve_object_arg( + idx, + &arg.to_json_value(), + )?)), + SignatureToken::Vector(inner) => match &**inner { + SignatureToken::Struct(_) | SignatureToken::StructInstantiation(_) => { + Ok(ResolvedCallArg::ObjVec(resolve_object_vec_arg(idx, arg)?)) + } + _ => { + bail!( + "Unexpected non-primitive vector arg {:?} at {} with value {:?}", + param, + idx, + arg + ); + } + }, + _ => bail!( + "Unexpected non-primitive arg {:?} at {} with value {:?}", + param, + idx, + arg + ), + } +} + +pub fn is_receiving_argument(view: &BinaryIndexedView, arg_type: &SignatureToken) -> bool { + use SignatureToken as ST; + + // Progress down into references to determine if the underlying type is a + // receiving type or not. + let mut token = arg_type; + while let ST::Reference(inner) | ST::MutableReference(inner) = token { + token = inner; + } + + matches!( + token, + ST::StructInstantiation(struct_inst) if resolve_struct(view, struct_inst.0) == RESOLVED_RECEIVING_STRUCT && struct_inst.1.len() == 1 + ) +} + +fn resolve_call_args( + view: &BinaryIndexedView, + type_args: &[TypeTag], + json_args: &[IotaJsonValue], + parameter_types: &[SignatureToken], +) -> Result, anyhow::Error> { + json_args + .iter() + .zip(parameter_types) + .enumerate() + .map(|(idx, (arg, param))| resolve_call_arg(view, type_args, idx, arg, param)) + .collect() +} + +/// Resolve the JSON args of a function into the expected formats to make them +/// usable by Move call This is because we have special types which we need to +/// specify in other formats +pub fn resolve_move_function_args( + package: &MovePackage, + module_ident: Identifier, + function: Identifier, + type_args: &[TypeTag], + combined_args_json: Vec, +) -> Result, anyhow::Error> { + // Extract the expected function signature + let module = package.deserialize_module(&module_ident, &BinaryConfig::standard())?; + let function_str = function.as_ident_str(); + let fdef = module + .function_defs + .iter() + .find(|fdef| { + module.identifier_at(module.function_handle_at(fdef.function).name) == function_str + }) + .ok_or_else(|| { + anyhow!( + "Could not resolve function {} in module {}", + function, + module_ident + ) + })?; + let function_signature = module.function_handle_at(fdef.function); + let parameters = &module.signature_at(function_signature.parameters).0; + + let view = BinaryIndexedView::Module(&module); + + // Lengths have to match, less one, due to TxContext + let expected_len = match parameters.last() { + Some(param) if TxContext::kind(&view, param) != TxContextKind::None => parameters.len() - 1, + _ => parameters.len(), + }; + if combined_args_json.len() != expected_len { + bail!( + "Expected {} args, found {}", + expected_len, + combined_args_json.len() + ); + } + // Check that the args are valid and convert to the correct format + let call_args = resolve_call_args(&view, type_args, &combined_args_json, parameters)?; + let tupled_call_args = call_args + .into_iter() + .zip(parameters.iter()) + .map(|(arg, expected_type)| (arg, expected_type.clone())) + .collect::>(); + Ok(tupled_call_args) +} + +fn convert_string_to_u256(s: &str) -> Result { + // Try as normal number + if let Ok(v) = s.parse::() { + return Ok(v); + } + + // Check prefix + // For now only Hex supported + // TODO: add support for bin and octal? + + let s = s.trim().to_lowercase(); + if !s.starts_with(HEX_PREFIX) { + bail!("Unable to convert {s} to unsigned int.",); + } + U256::from_str_radix(s.trim_start_matches(HEX_PREFIX), 16).map_err(|e| e.into()) +} + +#[macro_export] +macro_rules! call_args { + ($($value:expr),*) => { + Ok::<_, anyhow::Error>(vec![$(iota_json::call_arg!($value)?,)*]) + }; + } + +#[macro_export] +macro_rules! call_arg { + ($value:expr) => {{ + use iota_json::IotaJsonValue; + trait IotaJsonArg { + fn to_iota_json(&self) -> anyhow::Result; + } + // TODO: anyway to condense this? + impl IotaJsonArg for &str { + fn to_iota_json(&self) -> anyhow::Result { + IotaJsonValue::from_str(self) + } + } + impl IotaJsonArg for String { + fn to_iota_json(&self) -> anyhow::Result { + IotaJsonValue::from_str(&self) + } + } + impl IotaJsonArg for iota_types::base_types::ObjectID { + fn to_iota_json(&self) -> anyhow::Result { + IotaJsonValue::from_str(&self.to_string()) + } + } + impl IotaJsonArg for iota_types::base_types::IotaAddress { + fn to_iota_json(&self) -> anyhow::Result { + IotaJsonValue::from_str(&self.to_string()) + } + } + impl IotaJsonArg for u64 { + fn to_iota_json(&self) -> anyhow::Result { + IotaJsonValue::from_bcs_bytes( + Some(&iota_json::MoveTypeLayout::U64), + &bcs::to_bytes(self)?, + ) + } + } + impl IotaJsonArg for Vec { + fn to_iota_json(&self) -> anyhow::Result { + IotaJsonValue::from_bcs_bytes(None, &self) + } + } + impl IotaJsonArg for &[u8] { + fn to_iota_json(&self) -> anyhow::Result { + IotaJsonValue::from_bcs_bytes(None, self) + } + } + $value.to_iota_json() + }}; +} + +#[macro_export] +macro_rules! type_args { + ($($value:expr), *) => {{ + use iota_json_rpc_types::IotaTypeTag; + use iota_types::TypeTag; + trait IotaJsonTypeArg { + fn to_iota_json(&self) -> anyhow::Result; + } + impl IotaJsonTypeArg for T { + fn to_iota_json(&self) -> anyhow::Result { + Ok(iota_types::parse_iota_type_tag(&self.to_string())?.into()) + } + } + Ok::<_, anyhow::Error>(vec![$($value.to_iota_json()?,)*]) + }}; + } diff --git a/crates/iota-json/src/tests.rs b/crates/iota-json/src/tests.rs new file mode 100644 index 00000000000..29516e846c6 --- /dev/null +++ b/crates/iota-json/src/tests.rs @@ -0,0 +1,942 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{path::Path, str::FromStr}; + +use fastcrypto::encoding::{Encoding, Hex}; +use iota_framework::BuiltInFramework; +use iota_move_build::BuildConfig; +use iota_types::{ + base_types::{ + IotaAddress, ObjectID, TransactionDigest, STD_ASCII_MODULE_NAME, STD_ASCII_STRUCT_NAME, + STD_OPTION_MODULE_NAME, STD_OPTION_STRUCT_NAME, + }, + dynamic_field::derive_dynamic_field_id, + gas_coin::GasCoin, + object::Object, + parse_iota_type_tag, MOVE_STDLIB_ADDRESS, +}; +use move_core_types::{ + account_address::AccountAddress, + annotated_value::{MoveFieldLayout, MoveStructLayout, MoveTypeLayout}, + ident_str, + identifier::Identifier, + language_storage::StructTag, + u256::U256, +}; +use serde_json::{json, Value}; +use test_fuzz::runtime::num_traits::ToPrimitive; + +use super::{check_valid_homogeneous, resolve_move_function_args, IotaJsonValue, HEX_PREFIX}; +use crate::ResolvedCallArg; + +// Negative test cases +#[test] +fn test_json_not_homogeneous() { + let checks = vec![ + (json!([1, 2, 3, true, 5, 6, 7])), + // Although we can encode numbers as strings, we do not allow mixing primitive + // numbers and string encoded numbers + (json!([1, 2, "4", 4, 5, 6, 7])), + (json!([1, 2, 3, 4, "", 6, 7])), + (json!([ + 1, + 2, + 3, + 4, + "456478542957455650244254734723567875646785024425473472356787564678463250089787", + 6, + 7 + ])), + (json!([[], 2, 3, 5, 6, 7])), + (json!([[[9, 53, 434], [0], [300]], [], [300, 4, 5, 6, 7]])), + (json!([1, 2, 3, 4, 5, 6, 0.4])), + (json!([4.2])), + (json!(4.7)), + ]; + // Driver + for arg in checks { + assert!(check_valid_homogeneous(&arg).is_err()); + } +} + +// Positive test cases +#[test] +fn test_json_is_homogeneous() { + let checks = vec![ + (json!([1, 2, 3, 4, 5, 6, 7])), + (json!(["123", "456"])), + (json!([ + "123", + "456478542957455650244254734723567875646785024425473472356787564678463250089787" + ])), + (json!([])), + (json!([[[9, 53, 434], [0], [300]], [], [[332], [4, 5, 6, 7]]])), + (json!([[], [true], [false], []])), + (json!([[[[[2]]]], [], [[]], []])), + (json!([3])), + (json!([])), + (json!(1)), + ]; + + // Driver + for arg in checks { + assert!(check_valid_homogeneous(&arg).is_ok()); + } +} + +#[test] +fn test_json_struct_homogeneous() { + let positive = json!({"inner_vec":[1, 2, 3, 4, 5, 6, 7]}); + assert!(IotaJsonValue::new(positive).is_ok()); + + let negative = json!({"inner_vec":[1, 2, 3, true, 5, 6, 7]}); + assert!(IotaJsonValue::new(negative).is_err()); +} + +#[test] +fn test_json_is_not_valid_iota_json() { + let checks = vec![ + // Not homogeneous + (json!([1, 2, 3, true, 5, 6, 7])), + // Not homogeneous + (json!([1, 2, 3, "123456", 5, 6, 7])), + // Float not allowed + (json!(1.3)), + // Negative not allowed + (json!(-10)), + // Not homogeneous + (json!([[[9, 53, 434], [0], [300]], [], [300, 4, 5, 6, 7]])), + ]; + + // Driver + for arg in checks { + assert!(IotaJsonValue::new(arg).is_err()); + } +} + +#[test] +fn test_json_is_valid_iota_json() { + let checks = vec![ + // Homogeneous + (json!([1, 2, 3, 4, 5, 6, 7])), + // String allowed + (json!("a string")), + // Bool allowed + (json!(true)), + // Uint allowed + (json!(100)), + (json!([])), + // Homogeneous + (json!([[[9, 53, 434], [0], [300]], [], [[332], [4, 5, 6, 7]]])), + ]; + + // Driver + for arg in checks { + assert!(IotaJsonValue::new(arg).is_ok()); + } +} + +#[test] +fn test_basic_args_linter_pure_args_bad() { + let bad_hex_val = "0x1234AB CD"; + + let checks = vec![ + // Although U256 value can be encoded as num, we enforce it must be a string + (Value::from(123), MoveTypeLayout::U256), + // Space not allowed + (Value::from(" 9"), MoveTypeLayout::U8), + // Hex must start with 0x + (Value::from("AB"), MoveTypeLayout::U8), + // Too large + (Value::from("123456789"), MoveTypeLayout::U8), + // Too large + ( + Value::from("123456789123456789123456789123456789"), + MoveTypeLayout::U64, + ), + // Too large + ( + Value::from( + "123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789", + ), + MoveTypeLayout::U128, + ), + // U64 value greater than 255 cannot be used as U8 + (Value::from(900u64), MoveTypeLayout::U8), + // floats cannot be used as U8 + (Value::from(0.4f32), MoveTypeLayout::U8), + // floats cannot be used as U64 + (Value::from(3.4f32), MoveTypeLayout::U64), + // Negative cannot be used as U64 + (Value::from(-19), MoveTypeLayout::U64), + // Negative cannot be used as Unsigned + (Value::from(-1), MoveTypeLayout::U8), + // u8 vector from bad hex repr + ( + Value::from(bad_hex_val), + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + ), + // u8 vector from heterogeneous array + ( + json!([1, 2, 3, true, 5, 6, 7]), + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + ), + // U64 deep nest, bad because heterogeneous array + ( + json!([[[9, 53, 434], [0], [300]], [], [300, 4, 5, 6, 7]]), + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::Vector(Box::new( + MoveTypeLayout::U64, + )))), + ), + ]; + + // Driver + for (arg, expected_type) in checks { + let r = IotaJsonValue::new(arg); + assert!(r.is_err() || r.unwrap().to_bcs_bytes(&expected_type).is_err()); + } +} + +#[test] +fn test_basic_args_linter_pure_args_good() { + let good_ascii_str = "123456789hdffwfof libgude ihibhdede +_))@+"; + let good_utf8_str = "enbeuf√12∫∆∂3456789hdπ˚ffwfof libgude ˚ø˙߃çß +_))@+"; + let good_hex_val = "0x1234ABCD"; + let u128_val = u64::MAX as u128 + 0xff; + let u256_hex_val = "0x1234567812345678877EDA56789098ABCDEF12"; + let u256_val = U256::from_str_radix(u256_hex_val.trim_start_matches("0x"), 16).unwrap(); + + let checks = vec![ + // Expected Bool match + ( + Value::from(true), + MoveTypeLayout::Bool, + bcs::to_bytes(&true).unwrap(), + ), + // Expected U8 match + ( + Value::from(9u8), + MoveTypeLayout::U8, + bcs::to_bytes(&9u8).unwrap(), + ), + // Expected U8 match + ( + Value::from(u8::MAX), + MoveTypeLayout::U8, + bcs::to_bytes(&u8::MAX).unwrap(), + ), + // Expected U16 match + ( + Value::from(9000u16), + MoveTypeLayout::U16, + bcs::to_bytes(&9000u16).unwrap(), + ), + // Expected U32 match + ( + Value::from(1233459000u32), + MoveTypeLayout::U32, + bcs::to_bytes(&1233459000u32).unwrap(), + ), + // Expected U16 match + ( + Value::from(u16::MAX), + MoveTypeLayout::U16, + bcs::to_bytes(&u16::MAX).unwrap(), + ), + // Expected U32 match + ( + Value::from(u32::MAX), + MoveTypeLayout::U32, + bcs::to_bytes(&u32::MAX).unwrap(), + ), + // U64 value less than 256 can be used as U8 + ( + Value::from(9u64), + MoveTypeLayout::U8, + bcs::to_bytes(&9u8).unwrap(), + ), + // U8 value encoded as str + ( + Value::from("89"), + MoveTypeLayout::U8, + bcs::to_bytes(&89u8).unwrap(), + ), + // U16 value encoded as str + ( + Value::from("12389"), + MoveTypeLayout::U16, + bcs::to_bytes(&12389u16).unwrap(), + ), + // U32 value encoded as str + ( + Value::from("123899856"), + MoveTypeLayout::U32, + bcs::to_bytes(&123899856u32).unwrap(), + ), + // U8 value encoded as str promoted to U64 + ( + Value::from("89"), + MoveTypeLayout::U64, + bcs::to_bytes(&89u64).unwrap(), + ), + // U64 value encoded as str + ( + Value::from("890"), + MoveTypeLayout::U64, + bcs::to_bytes(&890u64).unwrap(), + ), + // U64 value encoded as str + ( + Value::from(format!("{}", u64::MAX)), + MoveTypeLayout::U64, + bcs::to_bytes(&u64::MAX).unwrap(), + ), + // U128 value encoded as str + ( + Value::from(format!("{u128_val}")), + MoveTypeLayout::U128, + bcs::to_bytes(&u128_val).unwrap(), + ), + // U128 value encoded as str + ( + Value::from(format!("{}", u128::MAX)), + MoveTypeLayout::U128, + bcs::to_bytes(&u128::MAX).unwrap(), + ), + // U256 value encoded as str + ( + Value::from(format!("{u256_val}")), + MoveTypeLayout::U256, + bcs::to_bytes(&u256_val).unwrap(), + ), + // U8 value encoded as hex str + ( + Value::from("0x12"), + MoveTypeLayout::U8, + bcs::to_bytes(&0x12u8).unwrap(), + ), + // U8 value encoded as hex str promoted to U64 + ( + Value::from("0x12"), + MoveTypeLayout::U64, + bcs::to_bytes(&0x12u64).unwrap(), + ), + // U64 value encoded as hex str + ( + Value::from("0x890"), + MoveTypeLayout::U64, + bcs::to_bytes(&0x890u64).unwrap(), + ), + // U128 value encoded as hex str + ( + Value::from(format!("0x{:02x}", u128_val)), + MoveTypeLayout::U128, + bcs::to_bytes(&u128_val).unwrap(), + ), + // U256 value encoded as hex str + ( + Value::from(u256_hex_val.to_string()), + MoveTypeLayout::U256, + bcs::to_bytes(&u256_val).unwrap(), + ), + // U256 value encoded as hex str + ( + Value::from(format!("0x{:02x}", U256::max_value())), + MoveTypeLayout::U256, + bcs::to_bytes(&U256::max_value()).unwrap(), + ), + // u8 vector can be gotten from string + ( + Value::from(good_ascii_str), + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + bcs::to_bytes(&good_ascii_str.as_bytes()).unwrap(), + ), + // u8 vector from bad string + ( + Value::from(good_utf8_str), + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + bcs::to_bytes(&good_utf8_str.as_bytes()).unwrap(), + ), + // u8 vector from hex repr + ( + Value::from(good_hex_val), + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + bcs::to_bytes(&Hex::decode(good_hex_val.trim_start_matches(HEX_PREFIX)).unwrap()) + .unwrap(), + ), + // u8 vector from u8 array + ( + json!([1, 2, 3, 4, 5, 6, 7]), + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + bcs::to_bytes(&vec![1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8]).unwrap(), + ), + // Vector of vector of u8s + ( + json!([[1, 2, 3], [], [3, 4, 5, 6, 7]]), + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::Vector(Box::new( + MoveTypeLayout::U8, + )))), + bcs::to_bytes(&vec![ + vec![1u8, 2u8, 3u8], + vec![], + vec![3u8, 4u8, 5u8, 6u8, 7u8], + ]) + .unwrap(), + ), + // U64 nest + ( + json!([["1111", "2", "3"], [], ["300", "4", "5", "6", "7"]]), + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::Vector(Box::new( + MoveTypeLayout::U64, + )))), + bcs::to_bytes(&vec![ + vec![1111u64, 2u64, 3u64], + vec![], + vec![300u64, 4u64, 5u64, 6u64, 7u64], + ]) + .unwrap(), + ), + // U32 deep nest, good + ( + json!([[[9, 53, 434], [0], [300]], [], [[332], [4, 5, 6, 7]]]), + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::Vector(Box::new( + MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U32)), + )))), + bcs::to_bytes(&vec![ + vec![vec![9u32, 53u32, 434u32], vec![0u32], vec![300u32]], + vec![], + vec![vec![332u32], vec![4u32, 5u32, 6u32, 7u32]], + ]) + .unwrap(), + ), + ]; + + // Driver + for (arg, expected_type, expected_val) in checks { + let r = IotaJsonValue::new(arg); + // Must conform + assert!(r.is_ok()); + // Must be serializable + let sr = r.unwrap().to_bcs_bytes(&expected_type); + // Must match expected serialized value + assert_eq!(sr.unwrap(), expected_val); + } +} + +#[test] +fn test_basic_args_linter_top_level() { + let path = + Path::new(env!("CARGO_MANIFEST_DIR")).join("../../iota_programmability/examples/nfts"); + let compiled_modules = BuildConfig::new_for_testing() + .build(path) + .unwrap() + .into_modules(); + let example_package = Object::new_package_for_testing( + &compiled_modules, + TransactionDigest::genesis_marker(), + BuiltInFramework::genesis_move_packages(), + ) + .unwrap(); + let example_package = example_package.data.try_as_package().unwrap(); + + let module = Identifier::new("geniteam").unwrap(); + let function = Identifier::new("create_monster").unwrap(); + + // Function signature: + // public fun create_monster( + // _player: &mut Player, + // farm: &mut Farm, + // pet_monsters: &mut Collection, + // monster_name: vector, + // monster_img_index: u64, + // breed: u8, + // monster_affinity: u8, + // monster_description: vector, + // display: vector, + // ctx: &mut TxContext + // ) + + let monster_name_raw = "MonsterName"; + let monster_img_id_raw = "12345678"; + let breed_raw = 89; + let monster_affinity_raw = 200; + let monster_description_raw = "MonsterDescription"; + let display_raw = "DisplayUrl"; + + let player_id = json!(format!("0x{}", ObjectID::random())); + // This is okay since not starting with 0x + let monster_name = json!(monster_name_raw); + // Well within U64 bounds + let monster_img_id = json!(monster_img_id_raw); + // Well within U8 bounds + let breed = json!(breed_raw); + // Well within U8 bounds + let monster_affinity = json!(monster_affinity_raw); + // This is okay since not starting with 0x + let monster_description = json!(monster_description_raw); + // This is okay since not starting with 0x + let display = json!(display_raw); + + // They have to be ordered + let args = vec![ + player_id, + monster_name.clone(), + monster_img_id.clone(), + breed, + monster_affinity.clone(), + monster_description.clone(), + display.clone(), + ] + .iter() + .map(|q| IotaJsonValue::new(q.clone()).unwrap()) + .collect(); + + let json_args = + resolve_move_function_args(example_package, module.clone(), function.clone(), &[], args) + .unwrap(); + + assert!(!json_args.is_empty()); + + assert_eq!( + json_args[1].0, + ResolvedCallArg::Pure(bcs::to_bytes(&monster_name_raw.as_bytes().to_vec()).unwrap()) + ); + assert_eq!( + json_args[2].0, + ResolvedCallArg::Pure( + bcs::to_bytes(&(monster_img_id_raw.parse::().unwrap())).unwrap() + ), + ); + assert_eq!( + json_args[3].0, + ResolvedCallArg::Pure(bcs::to_bytes(&(breed_raw as u8)).unwrap()) + ); + assert_eq!( + json_args[4].0, + ResolvedCallArg::Pure(bcs::to_bytes(&(monster_affinity_raw as u8)).unwrap()), + ); + assert_eq!( + json_args[5].0, + ResolvedCallArg::Pure(bcs::to_bytes(&monster_description_raw.as_bytes().to_vec()).unwrap()), + ); + + // Breed is u8 so too large + let args = vec![ + monster_name, + monster_img_id, + json!(10000u64), + monster_affinity, + monster_description, + display, + ] + .iter() + .map(|q| IotaJsonValue::new(q.clone()).unwrap()) + .collect(); + assert!(resolve_move_function_args(example_package, module, function, &[], args,).is_err()); + + // Test with vecu8 as address + let path = + Path::new(env!("CARGO_MANIFEST_DIR")).join("../../iota_programmability/examples/basics"); + let compiled_modules = BuildConfig::new_for_testing() + .build(path) + .unwrap() + .into_modules(); + let example_package = Object::new_package_for_testing( + &compiled_modules, + TransactionDigest::genesis_marker(), + BuiltInFramework::genesis_move_packages(), + ) + .unwrap(); + let framework_pkg = example_package.data.try_as_package().unwrap(); + + let module = Identifier::new("object_basics").unwrap(); + let function = Identifier::new("create").unwrap(); + + // Function signature: + // public fun create(value: u64, recipient: vector, ctx: &mut TxContext) + let value_raw = "29897"; + let address = IotaAddress::random_for_testing_only(); + + let value = json!(value_raw); + // Encode as hex string + let addr = json!(format!("{address}")); + + // They have to be ordered + let args = [value, addr] + .iter() + .map(|q| IotaJsonValue::new(q.clone()).unwrap()) + .collect(); + + let args = resolve_move_function_args(framework_pkg, module, function, &[], args).unwrap(); + + assert_eq!( + args[0].0, + ResolvedCallArg::Pure(bcs::to_bytes(&(value_raw.parse::().unwrap())).unwrap()) + ); + + // Need to verify this specially + // BCS serialzes addresses like vectors so there's a length prefix, which makes + // the vec longer by 1 + assert_eq!( + args[1].0, + ResolvedCallArg::Pure(bcs::to_bytes(&AccountAddress::from(address)).unwrap()), + ); + + // Test with object args + + let module = Identifier::new("object_basics").unwrap(); + let function = Identifier::new("transfer").unwrap(); + + // Function signature: + // public fun transfer(o: Object, recipient: vector, _ctx: &mut TxContext) + let object_id_raw = ObjectID::random(); + let address = IotaAddress::random_for_testing_only(); + + let object_id = json!(format!("{object_id_raw}")); + // Encode as hex string + let addr = json!(format!("{address}")); + + // They have to be ordered + let args = [object_id, addr] + .iter() + .map(|q| IotaJsonValue::new(q.clone()).unwrap()) + .collect(); + + let args = resolve_move_function_args(framework_pkg, module, function, &[], args).unwrap(); + + assert_eq!( + args[0].0, + ResolvedCallArg::Object( + ObjectID::from_hex_literal(&format!("0x{}", object_id_raw)).unwrap() + ) + ); + + // Need to verify this specially + // BCS serialzes addresses like vectors so there's a length prefix, which makes + // the vec longer by 1 + assert_eq!( + args[1].0, + ResolvedCallArg::Pure(bcs::to_bytes(&AccountAddress::from(address)).unwrap()) + ); + + // Test with object vector args + let path = Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../iota-core/src/unit_tests/data/entry_point_vector"); + let compiled_modules = BuildConfig::new_for_testing() + .build(path) + .unwrap() + .into_modules(); + let example_package = Object::new_package_for_testing( + &compiled_modules, + TransactionDigest::genesis_marker(), + BuiltInFramework::genesis_move_packages(), + ) + .unwrap(); + let example_package = example_package.data.try_as_package().unwrap(); + + let module = Identifier::new("entry_point_vector").unwrap(); + let function = Identifier::new("two_obj_vec_destroy").unwrap(); + + // Function signature: + // public entry fun two_obj_vec_destroy(v: vector, _: &mut TxContext) + let object_id_raw1 = ObjectID::random(); + let object_id_raw2 = ObjectID::random(); + let object_id1 = json!(format!("0x{}", object_id_raw1)); + let object_id2 = json!(format!("0x{}", object_id_raw2)); + + let args = vec![IotaJsonValue::new(Value::Array(vec![object_id1, object_id2])).unwrap()]; + + let args = resolve_move_function_args(example_package, module, function, &[], args).unwrap(); + + assert!(matches!(args[0].0, ResolvedCallArg::ObjVec { .. })); + + if let ResolvedCallArg::ObjVec(vec) = &args[0].0 { + assert_eq!(vec.len(), 2); + assert_eq!( + vec[0], + ObjectID::from_hex_literal(&format!("0x{}", object_id_raw1)).unwrap() + ); + assert_eq!( + vec[1], + ObjectID::from_hex_literal(&format!("0x{}", object_id_raw2)).unwrap() + ); + } +} + +#[test] +fn test_convert_address_from_bcs() { + let bcs_bytes = [ + 50, 134, 111, 1, 9, 250, 27, 169, 17, 57, 45, 205, 45, 66, 96, 241, 216, 36, 49, 51, 22, + 245, 70, 122, 191, 100, 24, 123, 62, 239, 165, 85, + ]; + + let value = IotaJsonValue::from_bcs_bytes(Some(&MoveTypeLayout::Signer), &bcs_bytes).unwrap(); + + assert_eq!( + "0x32866f0109fa1ba911392dcd2d4260f1d824313316f5467abf64187b3eefa555", + value.0.as_str().unwrap() + ); +} + +#[test] +fn test_convert_number_from_bcs() { + let bcs_bytes = [160u8, 134, 1, 0]; + let value = IotaJsonValue::from_bcs_bytes(Some(&MoveTypeLayout::U32), &bcs_bytes).unwrap(); + assert_eq!(100000, value.0.as_u64().unwrap()); +} + +#[test] +fn test_no_address_zero_trimming() { + let bcs_bytes = bcs::to_bytes( + &AccountAddress::from_str( + "0x0000000000000000000000000000011111111111111111111111111111111111", + ) + .unwrap(), + ) + .unwrap(); + let value = IotaJsonValue::from_bcs_bytes(Some(&MoveTypeLayout::Address), &bcs_bytes).unwrap(); + assert_eq!( + "0x0000000000000000000000000000011111111111111111111111111111111111", + value.0.as_str().unwrap() + ); +} + +#[test] +fn test_convert_number_array_from_bcs() { + let bcs_bytes = [ + 5, 80, 195, 0, 0, 80, 195, 0, 0, 80, 195, 0, 0, 80, 195, 0, 0, 80, 195, 0, 0, + ]; + + let value = IotaJsonValue::from_bcs_bytes( + Some(&MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U32))), + &bcs_bytes, + ) + .unwrap(); + + for value in value.0.as_array().unwrap() { + assert_eq!(50000, value.as_u64().unwrap()) + } +} + +#[test] +fn test_from_str() { + // test number + let test = IotaJsonValue::from_str("10000").unwrap(); + assert!(test.0.is_number()); + // Test array + let test = IotaJsonValue::from_str("[10,10,10,10]").unwrap(); + assert!(test.0.is_array()); + assert_eq!( + vec![10, 10, 10, 10], + test.0 + .as_array() + .unwrap() + .iter() + .map(|value| value.as_u64().unwrap().to_u8().unwrap()) + .collect::>() + ); + // test bool + let test = IotaJsonValue::from_str("true").unwrap(); + assert!(test.0.is_boolean()); + + // test id without quotes + let object_id = ObjectID::random().to_hex_uncompressed(); + let test = IotaJsonValue::from_str(&object_id).unwrap(); + assert!(test.0.is_string()); + assert_eq!(object_id, test.0.as_str().unwrap()); + + // test id with quotes + let test = IotaJsonValue::from_str(&format!("\"{}\"", &object_id)).unwrap(); + assert!(test.0.is_string()); + assert_eq!(object_id, test.0.as_str().unwrap()); + + // test string without quotes + let test = IotaJsonValue::from_str("Some string").unwrap(); + assert!(test.0.is_string()); + assert_eq!("Some string", test.0.as_str().unwrap()); + + // test string with quotes + let test = IotaJsonValue::from_str("\"Some string\"").unwrap(); + assert!(test.0.is_string()); + assert_eq!("Some string", test.0.as_str().unwrap()); + + let test = IotaJsonValue::from_object_id( + ObjectID::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") + .unwrap(), + ); + assert!(test.0.is_string()); + assert_eq!( + "0x0000000000000000000000000000000000000000000000000000000000000001", + test.0.as_str().unwrap() + ); +} + +#[test] +fn test_iota_call_arg_string_type() { + let arg1 = bcs::to_bytes("Some String").unwrap(); + + let string_layout = Some(MoveTypeLayout::Struct(MoveStructLayout { + type_: StructTag { + address: MOVE_STDLIB_ADDRESS, + module: STD_ASCII_MODULE_NAME.into(), + name: STD_ASCII_STRUCT_NAME.into(), + type_params: vec![], + }, + fields: vec![MoveFieldLayout { + name: ident_str!("bytes").into(), + layout: MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + }], + })); + let v = IotaJsonValue::from_bcs_bytes(string_layout.as_ref(), &arg1).unwrap(); + + assert_eq!(json! {"Some String"}, v.to_json_value()); +} + +#[test] +fn test_iota_call_arg_option_type() { + let arg1 = bcs::to_bytes(&Some("Some String")).unwrap(); + + let string_layout = MoveTypeLayout::Struct(MoveStructLayout { + type_: StructTag { + address: MOVE_STDLIB_ADDRESS, + module: STD_ASCII_MODULE_NAME.into(), + name: STD_ASCII_STRUCT_NAME.into(), + type_params: vec![], + }, + fields: vec![MoveFieldLayout { + name: ident_str!("bytes").into(), + layout: MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + }], + }); + + let option_layout = MoveTypeLayout::Struct(MoveStructLayout { + type_: StructTag { + address: MOVE_STDLIB_ADDRESS, + module: STD_OPTION_MODULE_NAME.into(), + name: STD_OPTION_STRUCT_NAME.into(), + type_params: vec![], + }, + fields: vec![MoveFieldLayout { + name: ident_str!("vec").into(), + layout: MoveTypeLayout::Vector(Box::new(string_layout.clone())), + }], + }); + + let v = IotaJsonValue::from_bcs_bytes(Some(option_layout).as_ref(), &arg1).unwrap(); + + let bytes = v + .to_bcs_bytes(&MoveTypeLayout::Vector(Box::new(string_layout))) + .unwrap(); + + assert_eq!(json! {["Some String"]}, v.to_json_value()); + assert_eq!(arg1, bytes); + + let s = IotaJsonValue::from_str("[test, test2]").unwrap(); + println!("{s:?}"); +} + +#[test] +fn test_convert_struct() { + let layout = MoveTypeLayout::Struct(GasCoin::layout()); + + let value = json!({"id":"0xf1416fe18c7baa1673187375777a7606708481311cb3548509ec91a5871c6b9a", "balance": "1000000"}); + let iota_json = IotaJsonValue::new(value).unwrap(); + + println!("JS: {:#?}", iota_json); + + let bcs = iota_json.to_bcs_bytes(&layout).unwrap(); + + let coin: GasCoin = bcs::from_bytes(&bcs).unwrap(); + assert_eq!( + coin.0.id.id.bytes, + ObjectID::from_str("0xf1416fe18c7baa1673187375777a7606708481311cb3548509ec91a5871c6b9a") + .unwrap() + ); + assert_eq!(coin.0.balance.value(), 1000000); +} + +#[test] +fn test_convert_string_vec() { + let test_vec = vec!["0xbbb", "test_str"]; + let bcs = bcs::to_bytes(&test_vec).unwrap(); + let string_layout = MoveTypeLayout::Struct(MoveStructLayout { + type_: StructTag { + address: MOVE_STDLIB_ADDRESS, + module: STD_ASCII_MODULE_NAME.into(), + name: STD_ASCII_STRUCT_NAME.into(), + type_params: vec![], + }, + fields: vec![MoveFieldLayout { + name: ident_str!("bytes").into(), + layout: MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + }], + }); + + let layout = MoveTypeLayout::Vector(Box::new(string_layout)); + + let value = json!(test_vec); + let iota_json = IotaJsonValue::new(value).unwrap(); + + let bcs2 = iota_json.to_bcs_bytes(&layout).unwrap(); + + assert_eq!(bcs, bcs2); +} + +#[test] +fn test_string_vec_df_name_child_id_eq() { + let parent_id = + ObjectID::from_str("0x13a3ab664bfbdff0ab03cd1ce8c6fb3f31a8803f2e6e0b14b610f8e94fcb8509") + .unwrap(); + let name = json!({ + "labels": [ + "0x0001", + "iota" + ] + }); + + let string_layout = MoveTypeLayout::Struct(MoveStructLayout { + type_: StructTag { + address: MOVE_STDLIB_ADDRESS, + module: STD_ASCII_MODULE_NAME.into(), + name: STD_ASCII_STRUCT_NAME.into(), + type_params: vec![], + }, + fields: vec![MoveFieldLayout { + name: ident_str!("bytes").into(), + layout: MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), + }], + }); + + let layout = MoveTypeLayout::Struct(MoveStructLayout { + type_: StructTag { + address: MOVE_STDLIB_ADDRESS, + module: STD_ASCII_MODULE_NAME.into(), + name: STD_ASCII_STRUCT_NAME.into(), + type_params: vec![], + }, + fields: vec![MoveFieldLayout::new( + Identifier::from_str("labels").unwrap(), + MoveTypeLayout::Vector(Box::new(string_layout)), + )], + }); + + let iota_json = IotaJsonValue::new(name).unwrap(); + let bcs2 = iota_json.to_bcs_bytes(&layout).unwrap(); + + let child_id = derive_dynamic_field_id( + parent_id, + &parse_iota_type_tag( + "0x3278d6445c6403c96abe9e25cc1213a85de2bd627026ee57906691f9bbf2bf8a::domain::Domain", + ) + .unwrap(), + &bcs2, + ) + .unwrap(); + + assert_eq!( + "0x2c2e361ee262b9f1f9a930e27e092cce5906b1e63a699ee60aec2de452ab9c70", + child_id.to_string() + ); +} diff --git a/crates/iota-keys/Cargo.toml b/crates/iota-keys/Cargo.toml new file mode 100644 index 00000000000..1c425db5b0a --- /dev/null +++ b/crates/iota-keys/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "iota-keys" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +serde.workspace = true +serde_json.workspace = true +signature.workspace = true +rand.workspace = true +tiny-bip39.workspace = true +bip32.workspace = true +slip10_ed25519.workspace = true +fastcrypto = { workspace = true, features = ["copy_key"] } +shared-crypto.workspace = true +iota-types.workspace = true +regex.workspace = true + +[dev-dependencies] +tempfile.workspace = true diff --git a/crates/sui-keys/src/key_derive.rs b/crates/iota-keys/src/key_derive.rs similarity index 78% rename from crates/sui-keys/src/key_derive.rs rename to crates/iota-keys/src/key_derive.rs index c8124932a16..85a70c6bd88 100644 --- a/crates/sui-keys/src/key_derive.rs +++ b/crates/iota-keys/src/key_derive.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::anyhow; @@ -10,12 +11,12 @@ use fastcrypto::{ secp256r1::{Secp256r1KeyPair, Secp256r1PrivateKey}, traits::{KeyPair, ToFromBytes}, }; -use slip10_ed25519::derive_ed25519_private_key; -use sui_types::{ - base_types::SuiAddress, - crypto::{SignatureScheme, SuiKeyPair}, - error::SuiError, +use iota_types::{ + base_types::IotaAddress, + crypto::{IotaKeyPair, SignatureScheme}, + error::IotaError, }; +use slip10_ed25519::derive_ed25519_private_key; pub const DERIVATION_PATH_COIN_TYPE: u32 = 4218; pub const DERVIATION_PATH_PURPOSE_ED25519: u32 = 44; @@ -31,38 +32,38 @@ pub fn derive_key_pair_from_path( seed: &[u8], derivation_path: Option, key_scheme: &SignatureScheme, -) -> Result<(SuiAddress, SuiKeyPair), SuiError> { +) -> Result<(IotaAddress, IotaKeyPair), IotaError> { let path = validate_path(key_scheme, derivation_path)?; match key_scheme { SignatureScheme::ED25519 => { let indexes = path.into_iter().map(|i| i.into()).collect::>(); let derived = derive_ed25519_private_key(seed, &indexes); let sk = Ed25519PrivateKey::from_bytes(&derived) - .map_err(|e| SuiError::SignatureKeyGenError(e.to_string()))?; + .map_err(|e| IotaError::SignatureKeyGenError(e.to_string()))?; let kp: Ed25519KeyPair = sk.into(); - Ok((kp.public().into(), SuiKeyPair::Ed25519(kp))) + Ok((kp.public().into(), IotaKeyPair::Ed25519(kp))) } SignatureScheme::Secp256k1 => { let child_xprv = XPrv::derive_from_path(seed, &path) - .map_err(|e| SuiError::SignatureKeyGenError(e.to_string()))?; + .map_err(|e| IotaError::SignatureKeyGenError(e.to_string()))?; let kp = Secp256k1KeyPair::from( Secp256k1PrivateKey::from_bytes(child_xprv.private_key().to_bytes().as_slice()) - .map_err(|e| SuiError::SignatureKeyGenError(e.to_string()))?, + .map_err(|e| IotaError::SignatureKeyGenError(e.to_string()))?, ); - Ok((kp.public().into(), SuiKeyPair::Secp256k1(kp))) + Ok((kp.public().into(), IotaKeyPair::Secp256k1(kp))) } SignatureScheme::Secp256r1 => { let child_xprv = XPrv::derive_from_path(seed, &path) - .map_err(|e| SuiError::SignatureKeyGenError(e.to_string()))?; + .map_err(|e| IotaError::SignatureKeyGenError(e.to_string()))?; let kp = Secp256r1KeyPair::from( Secp256r1PrivateKey::from_bytes(child_xprv.private_key().to_bytes().as_slice()) - .map_err(|e| SuiError::SignatureKeyGenError(e.to_string()))?, + .map_err(|e| IotaError::SignatureKeyGenError(e.to_string()))?, ); - Ok((kp.public().into(), SuiKeyPair::Secp256r1(kp))) + Ok((kp.public().into(), IotaKeyPair::Secp256r1(kp))) } SignatureScheme::BLS12381 | SignatureScheme::MultiSig - | SignatureScheme::ZkLoginAuthenticator => Err(SuiError::UnsupportedFeatureError { + | SignatureScheme::ZkLoginAuthenticator => Err(IotaError::UnsupportedFeatureError { error: format!("key derivation not supported {:?}", key_scheme), }), } @@ -71,7 +72,7 @@ pub fn derive_key_pair_from_path( pub fn validate_path( key_scheme: &SignatureScheme, path: Option, -) -> Result { +) -> Result { match key_scheme { SignatureScheme::ED25519 => { match path { @@ -89,17 +90,17 @@ pub fn validate_path( { Ok(p) } else { - Err(SuiError::SignatureKeyGenError("Invalid path".to_string())) + Err(IotaError::SignatureKeyGenError("Invalid path".to_string())) } } else { - Err(SuiError::SignatureKeyGenError("Invalid path".to_string())) + Err(IotaError::SignatureKeyGenError("Invalid path".to_string())) } } None => Ok(format!( "m/{DERVIATION_PATH_PURPOSE_ED25519}'/{DERIVATION_PATH_COIN_TYPE}'/0'/0'/0'" ) .parse() - .map_err(|_| SuiError::SignatureKeyGenError("Cannot parse path".to_string()))?), + .map_err(|_| IotaError::SignatureKeyGenError("Cannot parse path".to_string()))?), } } SignatureScheme::Secp256k1 => { @@ -118,17 +119,17 @@ pub fn validate_path( { Ok(p) } else { - Err(SuiError::SignatureKeyGenError("Invalid path".to_string())) + Err(IotaError::SignatureKeyGenError("Invalid path".to_string())) } } else { - Err(SuiError::SignatureKeyGenError("Invalid path".to_string())) + Err(IotaError::SignatureKeyGenError("Invalid path".to_string())) } } None => Ok(format!( "m/{DERVIATION_PATH_PURPOSE_SECP256K1}'/{DERIVATION_PATH_COIN_TYPE}'/0'/0/0" ) .parse() - .map_err(|_| SuiError::SignatureKeyGenError("Cannot parse path".to_string()))?), + .map_err(|_| IotaError::SignatureKeyGenError("Cannot parse path".to_string()))?), } } SignatureScheme::Secp256r1 => { @@ -147,22 +148,22 @@ pub fn validate_path( { Ok(p) } else { - Err(SuiError::SignatureKeyGenError("Invalid path".to_string())) + Err(IotaError::SignatureKeyGenError("Invalid path".to_string())) } } else { - Err(SuiError::SignatureKeyGenError("Invalid path".to_string())) + Err(IotaError::SignatureKeyGenError("Invalid path".to_string())) } } None => Ok(format!( "m/{DERVIATION_PATH_PURPOSE_SECP256R1}'/{DERIVATION_PATH_COIN_TYPE}'/0'/0/0" ) .parse() - .map_err(|_| SuiError::SignatureKeyGenError("Cannot parse path".to_string()))?), + .map_err(|_| IotaError::SignatureKeyGenError("Cannot parse path".to_string()))?), } } SignatureScheme::BLS12381 | SignatureScheme::MultiSig - | SignatureScheme::ZkLoginAuthenticator => Err(SuiError::UnsupportedFeatureError { + | SignatureScheme::ZkLoginAuthenticator => Err(IotaError::UnsupportedFeatureError { error: format!("key derivation not supported {:?}", key_scheme), }), } @@ -172,7 +173,7 @@ pub fn generate_new_key( key_scheme: SignatureScheme, derivation_path: Option, word_length: Option, -) -> Result<(SuiAddress, SuiKeyPair, SignatureScheme, String), anyhow::Error> { +) -> Result<(IotaAddress, IotaKeyPair, SignatureScheme, String), anyhow::Error> { let mnemonic = Mnemonic::new(parse_word_length(word_length)?, Language::English); let seed = Seed::new(&mnemonic, ""); match derive_key_pair_from_path(seed.as_bytes(), derivation_path, &key_scheme) { diff --git a/crates/sui-keys/src/keypair_file.rs b/crates/iota-keys/src/keypair_file.rs similarity index 82% rename from crates/sui-keys/src/keypair_file.rs rename to crates/iota-keys/src/keypair_file.rs index b120b762349..97dc1244e30 100644 --- a/crates/sui-keys/src/keypair_file.rs +++ b/crates/iota-keys/src/keypair_file.rs @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::anyhow; use fastcrypto::traits::EncodeDecodeBase64; -use sui_types::crypto::{AuthorityKeyPair, NetworkKeyPair, SuiKeyPair}; +use iota_types::crypto::{AuthorityKeyPair, IotaKeyPair, NetworkKeyPair}; /// Write Base64 encoded `flag || privkey` to file. pub fn write_keypair_to_file>( - keypair: &SuiKeyPair, + keypair: &IotaKeyPair, path: P, ) -> anyhow::Result<()> { let contents = keypair.encode_base64(); @@ -33,10 +34,10 @@ pub fn read_authority_keypair_from_file>( AuthorityKeyPair::decode_base64(contents.as_str().trim()).map_err(|e| anyhow!(e)) } -/// Read from file as Base64 encoded `flag || privkey` and return a SuiKeypair. -pub fn read_keypair_from_file>(path: P) -> anyhow::Result { +/// Read from file as Base64 encoded `flag || privkey` and return a IotaKeypair. +pub fn read_keypair_from_file>(path: P) -> anyhow::Result { let contents = std::fs::read_to_string(path)?; - SuiKeyPair::decode_base64(contents.as_str().trim()).map_err(|e| anyhow!(e)) + IotaKeyPair::decode_base64(contents.as_str().trim()).map_err(|e| anyhow!(e)) } /// Read from file as Base64 encoded `flag || privkey` and return a @@ -45,7 +46,7 @@ pub fn read_network_keypair_from_file>( path: P, ) -> anyhow::Result { let kp = read_keypair_from_file(path)?; - if let SuiKeyPair::Ed25519(kp) = kp { + if let IotaKeyPair::Ed25519(kp) = kp { Ok(kp) } else { Err(anyhow!("Invalid scheme for network keypair")) diff --git a/crates/sui-keys/src/keystore.rs b/crates/iota-keys/src/keystore.rs similarity index 85% rename from crates/sui-keys/src/keystore.rs rename to crates/iota-keys/src/keystore.rs index e26bb2f467a..dd196a1222d 100644 --- a/crates/sui-keys/src/keystore.rs +++ b/crates/iota-keys/src/keystore.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -13,17 +14,17 @@ use std::{ use anyhow::{anyhow, bail, ensure, Context}; use bip32::DerivationPath; use bip39::{Language, Mnemonic, Seed}; +use iota_types::{ + base_types::IotaAddress, + crypto::{ + enum_dispatch, get_key_pair_from_rng, EncodeDecodeBase64, IotaKeyPair, PublicKey, + Signature, SignatureScheme, + }, +}; use rand::{rngs::StdRng, SeedableRng}; use regex::Regex; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use shared_crypto::intent::{Intent, IntentMessage}; -use sui_types::{ - base_types::SuiAddress, - crypto::{ - enum_dispatch, get_key_pair_from_rng, EncodeDecodeBase64, PublicKey, Signature, - SignatureScheme, SuiKeyPair, - }, -}; use crate::{ key_derive::{derive_key_pair_from_path, generate_new_key}, @@ -38,24 +39,26 @@ pub enum Keystore { } #[enum_dispatch] pub trait AccountKeystore: Send + Sync { - fn add_key(&mut self, alias: Option, keypair: SuiKeyPair) -> Result<(), anyhow::Error>; + fn add_key(&mut self, alias: Option, keypair: IotaKeyPair) + -> Result<(), anyhow::Error>; fn keys(&self) -> Vec; - fn get_key(&self, address: &SuiAddress) -> Result<&SuiKeyPair, anyhow::Error>; + fn get_key(&self, address: &IotaAddress) -> Result<&IotaKeyPair, anyhow::Error>; - fn sign_hashed(&self, address: &SuiAddress, msg: &[u8]) -> Result; + fn sign_hashed(&self, address: &IotaAddress, msg: &[u8]) + -> Result; fn sign_secure( &self, - address: &SuiAddress, + address: &IotaAddress, msg: &T, intent: Intent, ) -> Result where T: Serialize; - fn addresses(&self) -> Vec { + fn addresses(&self) -> Vec { self.keys().iter().map(|k| k.into()).collect() } - fn addresses_with_alias(&self) -> Vec<(&SuiAddress, &Alias)>; + fn addresses_with_alias(&self) -> Vec<(&IotaAddress, &Alias)>; fn aliases(&self) -> Vec<&Alias>; fn aliases_mut(&mut self) -> Vec<&mut Alias>; fn alias_names(&self) -> Vec<&str> { @@ -65,8 +68,8 @@ pub trait AccountKeystore: Send + Sync { .collect() } /// Get alias of address - fn get_alias_by_address(&self, address: &SuiAddress) -> Result; - fn get_address_by_alias(&self, alias: String) -> Result<&SuiAddress, anyhow::Error>; + fn get_alias_by_address(&self, address: &IotaAddress) -> Result; + fn get_address_by_alias(&self, alias: String) -> Result<&IotaAddress, anyhow::Error>; /// Check if an alias exists by its name fn alias_exists(&self, alias: &str) -> bool { self.alias_names().contains(&alias) @@ -117,7 +120,7 @@ pub trait AccountKeystore: Send + Sync { alias: Option, derivation_path: Option, word_length: Option, - ) -> Result<(SuiAddress, String, SignatureScheme), anyhow::Error> { + ) -> Result<(IotaAddress, String, SignatureScheme), anyhow::Error> { let (address, kp, scheme, phrase) = generate_new_key(key_scheme, derivation_path, word_length)?; self.add_key(alias, kp)?; @@ -129,7 +132,7 @@ pub trait AccountKeystore: Send + Sync { phrase: &str, key_scheme: SignatureScheme, derivation_path: Option, - ) -> Result { + ) -> Result { let mnemonic = Mnemonic::from_phrase(phrase, Language::English) .map_err(|e| anyhow::anyhow!("Invalid mnemonic phrase: {:?}", e))?; let seed = Seed::new(&mnemonic, ""); @@ -168,8 +171,8 @@ pub struct Alias { #[derive(Default)] pub struct FileBasedKeystore { - keys: BTreeMap, - aliases: BTreeMap, + keys: BTreeMap, + aliases: BTreeMap, path: Option, } @@ -200,7 +203,11 @@ impl<'de> Deserialize<'de> for FileBasedKeystore { } impl AccountKeystore for FileBasedKeystore { - fn sign_hashed(&self, address: &SuiAddress, msg: &[u8]) -> Result { + fn sign_hashed( + &self, + address: &IotaAddress, + msg: &[u8], + ) -> Result { Ok(Signature::new_hashed( msg, self.keys.get(address).ok_or_else(|| { @@ -210,7 +217,7 @@ impl AccountKeystore for FileBasedKeystore { } fn sign_secure( &self, - address: &SuiAddress, + address: &IotaAddress, msg: &T, intent: Intent, ) -> Result @@ -225,8 +232,12 @@ impl AccountKeystore for FileBasedKeystore { )) } - fn add_key(&mut self, alias: Option, keypair: SuiKeyPair) -> Result<(), anyhow::Error> { - let address: SuiAddress = (&keypair.public()).into(); + fn add_key( + &mut self, + alias: Option, + keypair: IotaKeyPair, + ) -> Result<(), anyhow::Error> { + let address: IotaAddress = (&keypair.public()).into(); let alias = self.create_alias(alias)?; self.aliases.insert( address, @@ -246,7 +257,7 @@ impl AccountKeystore for FileBasedKeystore { self.aliases.values().collect() } - fn addresses_with_alias(&self) -> Vec<(&SuiAddress, &Alias)> { + fn addresses_with_alias(&self) -> Vec<(&IotaAddress, &Alias)> { self.aliases.iter().collect::>() } @@ -280,7 +291,7 @@ impl AccountKeystore for FileBasedKeystore { } /// Get the address by its alias - fn get_address_by_alias(&self, alias: String) -> Result<&SuiAddress, anyhow::Error> { + fn get_address_by_alias(&self, alias: String) -> Result<&IotaAddress, anyhow::Error> { self.addresses_with_alias() .iter() .find(|x| x.1.alias == alias) @@ -289,14 +300,14 @@ impl AccountKeystore for FileBasedKeystore { } /// Get the alias if it exists, or return an error if it does not exist. - fn get_alias_by_address(&self, address: &SuiAddress) -> Result { + fn get_alias_by_address(&self, address: &IotaAddress) -> Result { match self.aliases.get(address) { Some(alias) => Ok(alias.alias.clone()), None => bail!("Cannot find alias for address {address}"), } } - fn get_key(&self, address: &SuiAddress) -> Result<&SuiKeyPair, anyhow::Error> { + fn get_key(&self, address: &IotaAddress) -> Result<&IotaKeyPair, anyhow::Error> { match self.keys.get(address) { Some(key) => Ok(key), None => Err(anyhow!("Cannot find key for address: [{address}]")), @@ -329,8 +340,8 @@ impl FileBasedKeystore { kp_strings .iter() .map(|kpstr| { - let key = SuiKeyPair::decode_base64(kpstr); - key.map(|k| (SuiAddress::from(&k.public()), k)) + let key = IotaKeyPair::decode_base64(kpstr); + key.map(|k| (IotaAddress::from(&k.public()), k)) }) .collect::, _>>() .map_err(|e| anyhow!("Invalid keystore file: {}. {}", path.display(), e))? @@ -361,7 +372,7 @@ impl FileBasedKeystore { .into_iter() .map(|alias| { let key = PublicKey::decode_base64(&alias.public_key_base64); - key.map(|k| (Into::::into(&k), alias)) + key.map(|k| (Into::::into(&k), alias)) }) .collect::, _>>() .map_err(|e| { @@ -378,10 +389,10 @@ impl FileBasedKeystore { let aliases = keys .iter() .zip(names) - .map(|((sui_address, skp), alias)| { + .map(|((iota_address, skp), alias)| { let public_key_base64 = skp.public().encode_base64(); ( - *sui_address, + *iota_address, Alias { alias, public_key_base64, @@ -432,8 +443,8 @@ impl FileBasedKeystore { pub fn save_keystore(&self) -> Result<(), anyhow::Error> { println!( "Keys saved as Base64 with 33 bytes `flag || privkey` ($BASE64_STR). - To see Bech32 format encoding, use `sui keytool export $SUI_ADDRESS` where - $SUI_ADDRESS can be found with `sui keytool list`. Or use `sui keytool convert $BASE64_STR`." + To see Bech32 format encoding, use `iota keytool export $IOTA_ADDRESS` where + $IOTA_ADDRESS can be found with `iota keytool list`. Or use `iota keytool convert $BASE64_STR`." ); if let Some(path) = &self.path { @@ -456,19 +467,23 @@ impl FileBasedKeystore { Ok(()) } - pub fn key_pairs(&self) -> Vec<&SuiKeyPair> { + pub fn key_pairs(&self) -> Vec<&IotaKeyPair> { self.keys.values().collect() } } #[derive(Default, Serialize, Deserialize)] pub struct InMemKeystore { - aliases: BTreeMap, - keys: BTreeMap, + aliases: BTreeMap, + keys: BTreeMap, } impl AccountKeystore for InMemKeystore { - fn sign_hashed(&self, address: &SuiAddress, msg: &[u8]) -> Result { + fn sign_hashed( + &self, + address: &IotaAddress, + msg: &[u8], + ) -> Result { Ok(Signature::new_hashed( msg, self.keys.get(address).ok_or_else(|| { @@ -478,7 +493,7 @@ impl AccountKeystore for InMemKeystore { } fn sign_secure( &self, - address: &SuiAddress, + address: &IotaAddress, msg: &T, intent: Intent, ) -> Result @@ -493,8 +508,12 @@ impl AccountKeystore for InMemKeystore { )) } - fn add_key(&mut self, alias: Option, keypair: SuiKeyPair) -> Result<(), anyhow::Error> { - let address: SuiAddress = (&keypair.public()).into(); + fn add_key( + &mut self, + alias: Option, + keypair: IotaKeyPair, + ) -> Result<(), anyhow::Error> { + let address: IotaAddress = (&keypair.public()).into(); let alias = alias.unwrap_or_else(|| { random_name( &self @@ -520,7 +539,7 @@ impl AccountKeystore for InMemKeystore { self.aliases.values().collect() } - fn addresses_with_alias(&self) -> Vec<(&SuiAddress, &Alias)> { + fn addresses_with_alias(&self) -> Vec<(&IotaAddress, &Alias)> { self.aliases.iter().collect::>() } @@ -528,7 +547,7 @@ impl AccountKeystore for InMemKeystore { self.keys.values().map(|key| key.public()).collect() } - fn get_key(&self, address: &SuiAddress) -> Result<&SuiKeyPair, anyhow::Error> { + fn get_key(&self, address: &IotaAddress) -> Result<&IotaKeyPair, anyhow::Error> { match self.keys.get(address) { Some(key) => Ok(key), None => Err(anyhow!("Cannot find key for address: [{address}]")), @@ -536,7 +555,7 @@ impl AccountKeystore for InMemKeystore { } /// Get alias of address - fn get_alias_by_address(&self, address: &SuiAddress) -> Result { + fn get_alias_by_address(&self, address: &IotaAddress) -> Result { match self.aliases.get(address) { Some(alias) => Ok(alias.alias.clone()), None => bail!("Cannot find alias for address {address}"), @@ -544,7 +563,7 @@ impl AccountKeystore for InMemKeystore { } /// Get the address by its alias - fn get_address_by_alias(&self, alias: String) -> Result<&SuiAddress, anyhow::Error> { + fn get_address_by_alias(&self, alias: String) -> Result<&IotaAddress, anyhow::Error> { self.addresses_with_alias() .iter() .find(|x| x.1.alias == alias) @@ -591,16 +610,16 @@ impl InMemKeystore { let mut rng = StdRng::from_seed([0; 32]); let keys = (0..initial_key_number) .map(|_| get_key_pair_from_rng(&mut rng)) - .map(|(ad, k)| (ad, SuiKeyPair::Ed25519(k))) - .collect::>(); + .map(|(ad, k)| (ad, IotaKeyPair::Ed25519(k))) + .collect::>(); let aliases = keys .iter() .zip(random_names(HashSet::new(), keys.len())) - .map(|((sui_address, skp), alias)| { + .map(|((iota_address, skp), alias)| { let public_key_base64 = skp.public().encode_base64(); ( - *sui_address, + *iota_address, Alias { alias, public_key_base64, @@ -633,7 +652,7 @@ mod tests { // OK assert!(validate_alias("A.B_dash").is_ok()); assert!(validate_alias("A.B-C1_dash").is_ok()); - assert!(validate_alias("abc_123.sui").is_ok()); + assert!(validate_alias("abc_123.iota").is_ok()); // Not allowed assert!(validate_alias("A.B-C_dash!").is_err()); assert!(validate_alias(".B-C_dash!").is_err()); diff --git a/crates/iota-keys/src/lib.rs b/crates/iota-keys/src/lib.rs new file mode 100644 index 00000000000..58e75abb8b6 --- /dev/null +++ b/crates/iota-keys/src/lib.rs @@ -0,0 +1,8 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod key_derive; +pub mod keypair_file; +pub mod keystore; +pub mod random_names; diff --git a/crates/sui-keys/src/random_names.rs b/crates/iota-keys/src/random_names.rs similarity index 98% rename from crates/sui-keys/src/random_names.rs rename to crates/iota-keys/src/random_names.rs index c96bec3788b..d5b91576874 100644 --- a/crates/sui-keys/src/random_names.rs +++ b/crates/iota-keys/src/random_names.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::HashSet; diff --git a/crates/iota-keys/tests/tests.rs b/crates/iota-keys/tests/tests.rs new file mode 100644 index 00000000000..d1896994eed --- /dev/null +++ b/crates/iota-keys/tests/tests.rs @@ -0,0 +1,270 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{fs, str::FromStr}; + +use fastcrypto::{hash::HashFunction, traits::EncodeDecodeBase64}; +use iota_keys::{ + key_derive::generate_new_key, + keystore::{AccountKeystore, FileBasedKeystore, InMemKeystore, Keystore}, +}; +use iota_types::{ + base_types::{IotaAddress, IOTA_ADDRESS_LENGTH}, + crypto::{DefaultHash, Ed25519IotaSignature, IotaSignatureInner, SignatureScheme}, +}; +use tempfile::TempDir; + +#[test] +fn alias_exists_test() { + let temp_dir = TempDir::new().unwrap(); + let keystore_path = temp_dir.path().join("iota.keystore"); + let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + keystore + .generate_and_add_new_key( + SignatureScheme::ED25519, + Some("my_alias_test".to_string()), + None, + None, + ) + .unwrap(); + let aliases = keystore.alias_names(); + assert_eq!(1, aliases.len()); + assert_eq!(vec!["my_alias_test"], aliases); + assert!(!aliases.contains(&"alias_does_not_exist")); +} + +#[test] +fn create_alias_keystore_file_test() { + let temp_dir = TempDir::new().unwrap(); + let mut keystore_path = temp_dir.path().join("iota.keystore"); + let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + keystore + .generate_and_add_new_key(SignatureScheme::ED25519, None, None, None) + .unwrap(); + keystore_path.set_extension("aliases"); + assert!(keystore_path.exists()); + + keystore_path = temp_dir.path().join("myfile.keystore"); + let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + keystore + .generate_and_add_new_key(SignatureScheme::ED25519, None, None, None) + .unwrap(); + keystore_path.set_extension("aliases"); + assert!(keystore_path.exists()); +} + +#[test] +fn check_reading_aliases_file_correctly() { + // when reading the alias file containing alias + public key base 64, + // make sure the addresses are correctly converted back from pk + + let temp_dir = TempDir::new().unwrap(); + let mut keystore_path = temp_dir.path().join("iota.keystore"); + let keystore_path_keep = temp_dir.path().join("iota.keystore"); + let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + let kp = keystore + .generate_and_add_new_key(SignatureScheme::ED25519, None, None, None) + .unwrap(); + keystore_path.set_extension("aliases"); + assert!(keystore_path.exists()); + + let new_keystore = Keystore::from(FileBasedKeystore::new(&keystore_path_keep).unwrap()); + let addresses = new_keystore.addresses_with_alias(); + assert_eq!(kp.0, *addresses.first().unwrap().0) +} + +#[test] +fn create_alias_if_not_exists_test() { + let temp_dir = TempDir::new().unwrap(); + let keystore_path = temp_dir.path().join("iota.keystore"); + let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + + let alias = Some("my_alias_test".to_string()); + keystore + .generate_and_add_new_key(SignatureScheme::ED25519, alias.clone(), None, None) + .unwrap(); + + // test error first + let create_alias_result = keystore.create_alias(alias); + assert!(create_alias_result.is_err()); + // test expected result + let create_alias_result = keystore.create_alias(Some("test".to_string())); + assert_eq!("test".to_string(), create_alias_result.unwrap()); + assert!(keystore.create_alias(Some("_test".to_string())).is_err()); + assert!(keystore.create_alias(Some("-A".to_string())).is_err()); + assert!(keystore.create_alias(Some("1A".to_string())).is_err()); + assert!(keystore.create_alias(Some("&&AA".to_string())).is_err()); +} + +#[test] +fn keystore_no_aliases() { + // this tests if when calling FileBasedKeystore::new, it creates a + // iota.aliases file with the existing address in the iota.keystore, + // and a new alias for it. + // This idea is to test the correct conversion + // from the old type (which only contains keys and an optional path) + // to the new type which contains keys and aliases (and an optional path), and + // if it creates the aliases file. + + let temp_dir = TempDir::new().unwrap(); + let mut keystore_path = temp_dir.path().join("iota.keystore"); + let (_, keypair, _, _) = generate_new_key(SignatureScheme::ED25519, None, None).unwrap(); + let private_keys = vec![keypair.encode_base64()]; + let keystore_data = serde_json::to_string_pretty(&private_keys).unwrap(); + fs::write(&keystore_path, keystore_data).unwrap(); + + let keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + keystore_path.set_extension("aliases"); + assert!(keystore_path.exists()); + assert_eq!(1, keystore.aliases().len()); +} + +#[test] +fn update_alias_test() { + let temp_dir = TempDir::new().unwrap(); + let keystore_path = temp_dir.path().join("iota.keystore"); + let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + keystore + .generate_and_add_new_key( + SignatureScheme::ED25519, + Some("my_alias_test".to_string()), + None, + None, + ) + .unwrap(); + let aliases = keystore.alias_names(); + assert_eq!(1, aliases.len()); + assert_eq!(vec!["my_alias_test"], aliases); + + // read the alias file again and check if it was saved + let keystore1 = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + let aliases1 = keystore1.alias_names(); + assert_eq!(vec!["my_alias_test"], aliases1); + + let update = keystore.update_alias("alias_does_not_exist", None); + assert!(update.is_err()); + + let _ = keystore.update_alias("my_alias_test", Some("new_alias")); + let aliases = keystore.alias_names(); + assert_eq!(vec!["new_alias"], aliases); + + // check that it errors on empty alias + assert!(keystore.update_alias("new_alias", Some(" ")).is_err()); + assert!(keystore.update_alias("new_alias", Some(" ")).is_err()); + // check that alias is trimmed + assert!(keystore.update_alias("new_alias", Some(" o ")).is_ok()); + assert_eq!(vec!["o"], keystore.alias_names()); + // check the regex works and new alias can be only [A-Za-z][A-Za-z0-9-_]* + assert!(keystore.update_alias("o", Some("_alias")).is_err()); + assert!(keystore.update_alias("o", Some("-alias")).is_err()); + assert!(keystore.update_alias("o", Some("123")).is_err()); + + let update = keystore.update_alias("o", None).unwrap(); + let aliases = keystore.alias_names(); + assert_eq!(vec![&update], aliases); +} + +#[test] +fn update_alias_in_memory_test() { + let mut keystore = Keystore::InMem(InMemKeystore::new_insecure_for_tests(0)); + keystore + .generate_and_add_new_key( + SignatureScheme::ED25519, + Some("my_alias_test".to_string()), + None, + None, + ) + .unwrap(); + let aliases = keystore.alias_names(); + assert_eq!(1, aliases.len()); + assert_eq!(vec!["my_alias_test"], aliases); + + let update = keystore.update_alias("alias_does_not_exist", None); + assert!(update.is_err()); + + let _ = keystore.update_alias("my_alias_test", Some("new_alias")); + let aliases = keystore.alias_names(); + assert_eq!(vec!["new_alias"], aliases); + + let update = keystore.update_alias("new_alias", None).unwrap(); + let aliases = keystore.alias_names(); + assert_eq!(vec![&update], aliases); +} + +#[test] +fn mnemonic_test() { + let temp_dir = TempDir::new().unwrap(); + let keystore_path = temp_dir.path().join("iota.keystore"); + let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + let (address, phrase, scheme) = keystore + .generate_and_add_new_key(SignatureScheme::ED25519, None, None, None) + .unwrap(); + + let keystore_path_2 = temp_dir.path().join("iota2.keystore"); + let mut keystore2 = Keystore::from(FileBasedKeystore::new(&keystore_path_2).unwrap()); + let imported_address = keystore2 + .import_from_mnemonic(&phrase, SignatureScheme::ED25519, None) + .unwrap(); + assert_eq!(scheme.flag(), Ed25519IotaSignature::SCHEME.flag()); + assert_eq!(address, imported_address); +} + +/// This test confirms rust's implementation of mnemonic is the same with the +/// Iota Wallet +#[test] +fn iota_wallet_address_mnemonic_test() -> Result<(), anyhow::Error> { + let phrase = "result crisp session latin must fruit genuine question prevent start coconut brave speak student dismiss"; + let expected_address = IotaAddress::from_str( + "0x936accb491f0facaac668baaedcf4d0cfc6da1120b66f77fa6a43af718669973", + )?; + + let temp_dir = TempDir::new().unwrap(); + let keystore_path = temp_dir.path().join("iota.keystore"); + let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + + keystore + .import_from_mnemonic(phrase, SignatureScheme::ED25519, None) + .unwrap(); + + let pubkey = keystore.keys()[0].clone(); + assert_eq!(pubkey.flag(), Ed25519IotaSignature::SCHEME.flag()); + + let mut hasher = DefaultHash::default(); + hasher.update([pubkey.flag()]); + hasher.update(pubkey); + let g_arr = hasher.finalize(); + let mut res = [0u8; IOTA_ADDRESS_LENGTH]; + res.copy_from_slice(&AsRef::<[u8]>::as_ref(&g_arr)[..IOTA_ADDRESS_LENGTH]); + let address = IotaAddress::try_from(res.as_slice())?; + + assert_eq!(expected_address, address); + + Ok(()) +} + +#[test] +fn keystore_display_test() -> Result<(), anyhow::Error> { + let temp_dir = TempDir::new().unwrap(); + let keystore_path = temp_dir.path().join("iota.keystore"); + let keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + assert!(keystore.to_string().contains("iota.keystore")); + assert!(!keystore.to_string().contains("keys:")); + Ok(()) +} + +#[test] +fn get_alias_by_address_test() { + let temp_dir = TempDir::new().unwrap(); + let keystore_path = temp_dir.path().join("iota.keystore"); + let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + let alias = "my_alias_test".to_string(); + let keypair = keystore + .generate_and_add_new_key(SignatureScheme::ED25519, Some(alias.clone()), None, None) + .unwrap(); + assert_eq!(alias, keystore.get_alias_by_address(&keypair.0).unwrap()); + + // Test getting an alias of an address that is not in keystore + let address = generate_new_key(SignatureScheme::ED25519, None, None).unwrap(); + assert!(keystore.get_alias_by_address(&address.0).is_err()) +} diff --git a/crates/iota-light-client/Cargo.toml b/crates/iota-light-client/Cargo.toml new file mode 100644 index 00000000000..baa772f35a6 --- /dev/null +++ b/crates/iota-light-client/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "iota-light-client" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +async-trait.workspace = true +bcs.workspace = true +bytes.workspace = true +clap.workspace = true +move-core-types.workspace = true +serde.workspace = true +tokio = { workspace = true, features = ["full"] } +serde_yaml.workspace = true +serde_json.workspace = true +iota-types.workspace = true +iota-config.workspace = true +iota-rest-api.workspace = true +iota-json.workspace = true +iota-sdk.workspace = true +move-binary-format.workspace = true +iota-json-rpc-types.workspace = true +iota-package-resolver.workspace = true + diff --git a/crates/iota-light-client/README.md b/crates/iota-light-client/README.md new file mode 100644 index 00000000000..6abe82143cc --- /dev/null +++ b/crates/iota-light-client/README.md @@ -0,0 +1,62 @@ +This crate contains a Command Line Interface light client for Iota. + +# What is a light client? + +A light client allows checking the authenticity and validity of on-chain state, such as transactions, their effects including events and object contents, without the cost of running a full node. + +Running a *full node* requires downloading the full sequence of all transaction and re-executing them. Then the full state of the blockchain is available locally to serve reads. This is however an expensive process in terms of network bandwidth needed to download the full sequence of transactions, as well as CPU to re-execute it, and storage to store the full state of the blockchain. + +Alternatively, a *light client* only needs to download minimal information to authenticate blockchain state. Specifically in Iota, the light client needs to *sync* all end-of-epoch checkpoints that contain information about the committee in the next epoch. Sync involves downloading the checkpoints and checking their validity by checking their certificate. + +Once all end-of-epoch checkpoints are downloaded and checked, any event or current object can be checked for its validity. To do that the light client downloads the checkpoint in which the transaction was executed, and the effects structure that summarizes its effects on the system, including events emitted and objects created. The chain of validity from the checkpoint to the effects and its contents is checked via the certificate on the checkpoint and the hashes of all structures. + +## Ensuring valid data display + +A light client can ensure the correctness of the event and object data using the techniques defined above. However, the light client CLI utility also needs to pretty-print the structures in JSON, which requires knowledge of the correct type for each event or object. Types themselves are defined in modules that have been uploaded by past transactions. Therefore to ensure correct display the light client authenticates that all modules needed to display sought items are also correct. + +# Usage + +The light client requires a config file and a directory to cache checkpoints, and then can be used to check the validity of transaction and their events or of objects. + +## Setup + +The config file for the light client takes a URL for a full node, a directory (that must exist) and within the directory to name of the genesis blob for the Iota network. + +``` +full_node_url: "http://ord-mnt-rpcbig-06.mainnet.iota.io:9000" +checkpoint_summary_dir: "checkpoints_dir" +genesis_filename: "genesis.blob" +``` + +The genesis blob for the Iota mainnet can be found here: https://github.com/iotaledger/iota-genesis/blob/main/mainnet/genesis.blob + +## Sync + +Every day there is a need to download new checkpoints through sync by doing: +``` +$ iota-light-client --config light_client.yaml sync +``` + +Where `light_client.yaml` is the config file above. + +This command will download all end-of-epoch checkpoints, and check them for validity. They will be cached within the checkpoint summary directory for use by future invocations. + +## Check Transaction + +To check a transaction was executed, as well as the events it emitted do: +``` +$ iota-light-client --config light_client.yaml transaction -t 8RiKBwuAbtu8zNCtz8SrcfHyEUzto6zi6cMVA9t4WhWk +``` + +Where the base58 encoding of the transaction ID is specified. If the transaction has been executed the transaction ID the effects digest are displayed and all the events are printed in JSON. If not an error is printed. + +## Check Object + +To check an object provide its ID in the following way: + +``` +$ iota-light-client --config light_client.yaml object -o 0xc646887891adfc0540ec271fd0203603fb4c841a119ec1e00c469441 +abfc7078 +``` + +The object ID is represented in Hex as displayed in explorers. If the object exists in the latest state it is printed out in JSON, otherwise an error is printed. \ No newline at end of file diff --git a/crates/sui-light-client/example_config/20873329.yaml b/crates/iota-light-client/example_config/20873329.yaml similarity index 100% rename from crates/sui-light-client/example_config/20873329.yaml rename to crates/iota-light-client/example_config/20873329.yaml diff --git a/crates/sui-light-client/example_config/20958462.bcs b/crates/iota-light-client/example_config/20958462.bcs similarity index 100% rename from crates/sui-light-client/example_config/20958462.bcs rename to crates/iota-light-client/example_config/20958462.bcs diff --git a/crates/sui-light-client/example_config/checkpoints.yaml b/crates/iota-light-client/example_config/checkpoints.yaml similarity index 100% rename from crates/sui-light-client/example_config/checkpoints.yaml rename to crates/iota-light-client/example_config/checkpoints.yaml diff --git a/crates/sui-light-client/example_config/light_client.yaml b/crates/iota-light-client/example_config/light_client.yaml similarity index 100% rename from crates/sui-light-client/example_config/light_client.yaml rename to crates/iota-light-client/example_config/light_client.yaml diff --git a/crates/iota-light-client/src/main.rs b/crates/iota-light-client/src/main.rs new file mode 100644 index 00000000000..6786e113c95 --- /dev/null +++ b/crates/iota-light-client/src/main.rs @@ -0,0 +1,706 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + fs, + io::{Read, Write}, + path::PathBuf, + str::FromStr, + sync::Arc, +}; + +use anyhow::anyhow; +use async_trait::async_trait; +use clap::{Parser, Subcommand}; +use iota_config::genesis::Genesis; +use iota_json::IotaJsonValue; +use iota_json_rpc_types::IotaTransactionBlockResponseOptions; +use iota_package_resolver::{Package, PackageStore, Resolver, Result as ResolverResult}; +use iota_rest_api::{CheckpointData, Client}; +use iota_sdk::IotaClientBuilder; +use iota_types::{ + base_types::{ObjectID, SequenceNumber}, + committee::Committee, + crypto::AuthorityQuorumSignInfo, + digests::TransactionDigest, + effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, + message_envelope::Envelope, + messages_checkpoint::{CertifiedCheckpointSummary, CheckpointSummary, EndOfEpochData}, + object::{Data, Object}, +}; +use move_core_types::account_address::AccountAddress; + +/// A light client for the Iota blockchain +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + /// Sets a custom config file + #[arg(short, long, value_name = "FILE")] + config: Option, + + #[command(subcommand)] + command: Option, +} + +struct RemotePackageStore { + client: Client, + config: Config, +} + +impl RemotePackageStore { + pub fn new(client: Client, config: Config) -> Self { + Self { client, config } + } +} + +#[async_trait] +impl PackageStore for RemotePackageStore { + /// Latest version of the object at `id`. + async fn version(&self, id: AccountAddress) -> ResolverResult { + Ok(self.client.get_object(id.into()).await.unwrap().version()) + } + /// Read package contents. Fails if `id` is not an object, not a package, or + /// is malformed in some way. + async fn fetch(&self, id: AccountAddress) -> ResolverResult> { + let object = get_verified_object(&self.config, id.into()).await.unwrap(); + let package = Package::read(&object).unwrap(); + Ok(Arc::new(package)) + } +} + +#[derive(Subcommand, Debug)] +enum SCommands { + /// Sync all end-of-epoch checkpoints + Sync {}, + + /// Checks a specific transaction using the light client + Transaction { + /// Transaction hash + #[arg(short, long, value_name = "TID")] + tid: String, + }, + + /// Checks a specific object using the light client + Object { + /// Transaction hash + #[arg(short, long, value_name = "OID")] + oid: String, + }, +} + +// The config file for the light client including the root of trust genesis +// digest +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +struct Config { + /// Full node url + full_node_url: String, + + /// Checkpoint summary directory + checkpoint_summary_dir: PathBuf, + + // Genesis file name + genesis_filename: PathBuf, +} + +impl Config { + pub fn rest_url(&self) -> String { + format!("{}/rest", self.full_node_url) + } +} + +// The list of checkpoints at the end of each epoch +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +struct CheckpointsList { + // List of end of epoch checkpoints + checkpoints: Vec, +} + +fn read_checkpoint_list(config: &Config) -> anyhow::Result { + let mut checkpoints_path = config.checkpoint_summary_dir.clone(); + checkpoints_path.push("checkpoints.yaml"); + // Read the resulting file and parse the yaml checkpoint list + let reader = fs::File::open(checkpoints_path.clone())?; + Ok(serde_yaml::from_reader(reader)?) +} + +fn read_checkpoint( + config: &Config, + seq: u64, +) -> anyhow::Result>> { + read_checkpoint_general(config, seq, None) +} + +fn read_checkpoint_general( + config: &Config, + seq: u64, + path: Option<&str>, +) -> anyhow::Result>> { + // Read the resulting file and parse the yaml checkpoint list + let mut checkpoint_path = config.checkpoint_summary_dir.clone(); + if let Some(path) = path { + checkpoint_path.push(path); + } + checkpoint_path.push(format!("{}.yaml", seq)); + let mut reader = fs::File::open(checkpoint_path.clone())?; + let metadata = fs::metadata(&checkpoint_path)?; + let mut buffer = vec![0; metadata.len() as usize]; + reader.read_exact(&mut buffer)?; + bcs::from_bytes(&buffer).map_err(|_| anyhow!("Unable to parse checkpoint file")) +} + +fn write_checkpoint( + config: &Config, + summary: &Envelope>, +) -> anyhow::Result<()> { + write_checkpoint_general(config, summary, None) +} + +fn write_checkpoint_general( + config: &Config, + summary: &Envelope>, + path: Option<&str>, +) -> anyhow::Result<()> { + // Write the checkpoint summary to a file + let mut checkpoint_path = config.checkpoint_summary_dir.clone(); + if let Some(path) = path { + checkpoint_path.push(path); + } + checkpoint_path.push(format!("{}.yaml", summary.sequence_number)); + let mut writer = fs::File::create(checkpoint_path.clone())?; + let bytes = + bcs::to_bytes(&summary).map_err(|_| anyhow!("Unable to serialize checkpoint summary"))?; + writer.write_all(&bytes)?; + Ok(()) +} + +fn write_checkpoint_list( + config: &Config, + checkpoints_list: &CheckpointsList, +) -> anyhow::Result<()> { + // Write the checkpoint list to a file + let mut checkpoints_path = config.checkpoint_summary_dir.clone(); + checkpoints_path.push("checkpoints.yaml"); + let mut writer = fs::File::create(checkpoints_path.clone())?; + let bytes = serde_yaml::to_vec(&checkpoints_list)?; + writer + .write_all(&bytes) + .map_err(|_| anyhow!("Unable to serialize checkpoint list")) +} + +async fn download_checkpoint_summary( + config: &Config, + seq: u64, +) -> anyhow::Result { + // Download the checkpoint from the server + let client = Client::new(config.rest_url()); + client.get_checkpoint_summary(seq).await +} + +/// Run binary search to for each end of epoch checkpoint that is missing +/// between the latest on the list and the latest checkpoint. +async fn sync_checkpoint_list_to_latest(config: &Config) -> anyhow::Result<()> { + // Get the local checkpoint list + let mut checkpoints_list: CheckpointsList = read_checkpoint_list(config)?; + let latest_in_list = checkpoints_list + .checkpoints + .last() + .ok_or(anyhow!("Empty checkpoint list"))?; + + // Download the latest in list checkpoint + let summary = download_checkpoint_summary(config, *latest_in_list).await?; + let mut last_epoch = summary.epoch(); + let mut last_checkpoint_seq = summary.sequence_number; + + // Download the very latest checkpoint + let client = Client::new(config.rest_url()); + let latest = client.get_latest_checkpoint().await?; + + // Binary search to find missing checkpoints + while last_epoch + 1 < latest.epoch() { + let mut start = last_checkpoint_seq; + let mut end = latest.sequence_number; + + let target_epoch = last_epoch + 1; + // Print target + println!("Target Epoch: {}", target_epoch); + let mut found_summary = None; + + while start < end { + let mid = (start + end) / 2; + let summary = download_checkpoint_summary(config, mid).await?; + + // print summary epoch and seq + println!( + "Epoch: {} Seq: {}: {}", + summary.epoch(), + summary.sequence_number, + summary.end_of_epoch_data.is_some() + ); + + if summary.epoch() == target_epoch && summary.end_of_epoch_data.is_some() { + found_summary = Some(summary); + break; + } + + if summary.epoch() <= target_epoch { + start = mid + 1; + } else { + end = mid; + } + } + + if let Some(summary) = found_summary { + // Note: Do not write summary to file, since we must only persist + // checkpoints that have been verified by the previous committee + + // Add to the list + checkpoints_list.checkpoints.push(summary.sequence_number); + write_checkpoint_list(config, &checkpoints_list)?; + + // Update + last_epoch = summary.epoch(); + last_checkpoint_seq = summary.sequence_number; + } + } + + Ok(()) +} + +async fn check_and_sync_checkpoints(config: &Config) -> anyhow::Result<()> { + sync_checkpoint_list_to_latest(config).await?; + + // Get the local checkpoint list + let checkpoints_list: CheckpointsList = read_checkpoint_list(config)?; + + // Load the genesis committee + let mut genesis_path = config.checkpoint_summary_dir.clone(); + genesis_path.push(&config.genesis_filename); + let genesis_committee = Genesis::load(&genesis_path)?.committee()?; + + // Check the signatures of all checkpoints + // And download any missing ones + + let mut prev_committee = genesis_committee; + for ckp_id in &checkpoints_list.checkpoints { + // check if there is a file with this name ckp_id.yaml in the + // checkpoint_summary_dir + let mut checkpoint_path = config.checkpoint_summary_dir.clone(); + checkpoint_path.push(format!("{}.yaml", ckp_id)); + + // If file exists read the file otherwise download it from the server + let summary = if checkpoint_path.exists() { + read_checkpoint(config, *ckp_id)? + } else { + // Download the checkpoint from the server + let summary = download_checkpoint_summary(config, *ckp_id).await?; + summary.clone().verify(&prev_committee)?; + // Write the checkpoint summary to a file + write_checkpoint(config, &summary)?; + summary + }; + + // Print the id of the checkpoint and the epoch number + println!( + "Epoch: {} Checkpoint ID: {}", + summary.epoch(), + summary.digest() + ); + + // Extract the new committee information + if let Some(EndOfEpochData { + next_epoch_committee, + .. + }) = &summary.end_of_epoch_data + { + let next_committee = next_epoch_committee.iter().cloned().collect(); + prev_committee = + Committee::new(summary.epoch().checked_add(1).unwrap(), next_committee); + } else { + return Err(anyhow!( + "Expected all checkpoints to be end-of-epoch checkpoints" + )); + } + } + + Ok(()) +} + +async fn get_full_checkpoint(config: &Config, seq: u64) -> anyhow::Result { + // Downloading the checkpoint from the server + let client: Client = Client::new(config.rest_url()); + let full_checkpoint = client.get_full_checkpoint(seq).await?; + + Ok(full_checkpoint) +} + +fn extract_verified_effects_and_events( + checkpoint: &CheckpointData, + committee: &Committee, + tid: TransactionDigest, +) -> anyhow::Result<(TransactionEffects, Option)> { + let summary = &checkpoint.checkpoint_summary; + + // Verify the checkpoint summary using the committee + summary.verify_with_contents(committee, Some(&checkpoint.checkpoint_contents))?; + + // Check the validity of the transaction + let contents = &checkpoint.checkpoint_contents; + let (matching_tx, _) = checkpoint + .transactions + .iter() + .zip(contents.iter()) + // Note that we get the digest of the effects to ensure this is + // indeed the correct effects that are authenticated in the contents. + .find(|(tx, digest)| { + tx.effects.execution_digests() == **digest && digest.transaction == tid + }) + .ok_or(anyhow!("Transaction not found in checkpoint contents"))?; + + // Check the events are all correct. + let events_digest = matching_tx.events.as_ref().map(|events| events.digest()); + anyhow::ensure!( + events_digest.as_ref() == matching_tx.effects.events_digest(), + "Events digest does not match" + ); + + // Since we do not check objects we do not return them + Ok((matching_tx.effects.clone(), matching_tx.events.clone())) +} + +async fn get_verified_effects_and_events( + config: &Config, + tid: TransactionDigest, +) -> anyhow::Result<(TransactionEffects, Option)> { + let iota_mainnet: Arc = Arc::new( + IotaClientBuilder::default() + .build(config.full_node_url.as_str()) + .await + .unwrap(), + ); + let read_api = iota_mainnet.read_api(); + + // Lookup the transaction id and get the checkpoint sequence number + let options = IotaTransactionBlockResponseOptions::new(); + let seq = read_api + .get_transaction_with_options(tid, options) + .await? + .checkpoint + .ok_or(anyhow!("Transaction not found"))?; + + // Download the full checkpoint for this sequence number + let full_check_point = get_full_checkpoint(config, seq).await?; + + // Load the list of stored checkpoints + let checkpoints_list: CheckpointsList = read_checkpoint_list(config)?; + + // find the stored checkpoint before the seq checkpoint + let prev_ckp_id = checkpoints_list + .checkpoints + .iter() + .filter(|ckp_id| **ckp_id < seq) + .last(); + + let committee = if let Some(prev_ckp_id) = prev_ckp_id { + // Read it from the store + let prev_ckp = read_checkpoint(config, *prev_ckp_id)?; + + // Check we have the right checkpoint + anyhow::ensure!( + prev_ckp.epoch().checked_add(1).unwrap() == full_check_point.checkpoint_summary.epoch(), + "Checkpoint sequence number does not match. Need to Sync." + ); + + // Get the committee from the previous checkpoint + let current_committee = prev_ckp + .end_of_epoch_data + .as_ref() + .ok_or(anyhow!( + "Expected all checkpoints to be end-of-epoch checkpoints" + ))? + .next_epoch_committee + .iter() + .cloned() + .collect(); + + // Make a committee object using this + Committee::new(prev_ckp.epoch().checked_add(1).unwrap(), current_committee) + } else { + // Since we did not find a small committee checkpoint we use the genesis + let mut genesis_path = config.checkpoint_summary_dir.clone(); + genesis_path.push(&config.genesis_filename); + Genesis::load(&genesis_path)?.committee()? + }; + + extract_verified_effects_and_events(&full_check_point, &committee, tid) +} + +async fn get_verified_object(config: &Config, id: ObjectID) -> anyhow::Result { + let client: Client = Client::new(config.rest_url()); + let object = client.get_object(id).await?; + + // Need to authenticate this object + let (effects, _) = get_verified_effects_and_events(config, object.previous_transaction).await?; + + // check that this object ID, version and hash is in the effects + effects + .all_changed_objects() + .iter() + .find(|object_ref| object_ref.0 == object.compute_object_reference()) + .ok_or(anyhow!("Object not found"))?; + + Ok(object) +} + +#[tokio::main] +pub async fn main() { + // Command line arguments and config loading + let args = Args::parse(); + + let path = args + .config + .unwrap_or_else(|| panic!("Need a config file path")); + let reader = fs::File::open(path.clone()) + .unwrap_or_else(|_| panic!("Unable to load config from {}", path.display())); + let config: Config = serde_yaml::from_reader(reader).unwrap(); + + // Print config parameters + println!( + "Checkpoint Dir: {}", + config.checkpoint_summary_dir.display() + ); + + let client: Client = Client::new(config.rest_url()); + let remote_package_store = RemotePackageStore::new(client, config.clone()); + let resolver = Resolver::new(remote_package_store); + + match args.command { + Some(SCommands::Transaction { tid }) => { + let (effects, events) = get_verified_effects_and_events( + &config, + TransactionDigest::from_str(&tid).unwrap(), + ) + .await + .unwrap(); + + let exec_digests = effects.execution_digests(); + println!( + "Executed TID: {} Effects: {}", + exec_digests.transaction, exec_digests.effects + ); + + for event in events.as_ref().unwrap().data.iter() { + let type_layout = resolver + .type_layout(event.type_.clone().into()) + .await + .unwrap(); + + let json_val = + IotaJsonValue::from_bcs_bytes(Some(&type_layout), &event.contents).unwrap(); + + println!( + "Event:\n - Package: {}\n - Module: {}\n - Sender: {}\n - Type: {}\n{}", + event.package_id, + event.transaction_module, + event.sender, + event.type_, + serde_json::to_string_pretty(&json_val.to_json_value()).unwrap() + ); + } + } + Some(SCommands::Object { oid }) => { + let oid = ObjectID::from_str(&oid).unwrap(); + let object = get_verified_object(&config, oid).await.unwrap(); + + if let Data::Move(move_object) = &object.data { + let object_type = move_object.type_().clone(); + + let type_layout = resolver + .type_layout(object_type.clone().into()) + .await + .unwrap(); + + let json_val = + IotaJsonValue::from_bcs_bytes(Some(&type_layout), move_object.contents()) + .unwrap(); + + let (oid, version, hash) = object.compute_object_reference(); + println!( + "OID: {}\n - Version: {}\n - Hash: {}\n - Owner: {}\n - Type: {}\n{}", + oid, + version, + hash, + object.owner, + object_type, + serde_json::to_string_pretty(&json_val.to_json_value()).unwrap() + ); + } + } + + Some(SCommands::Sync {}) => { + check_and_sync_checkpoints(&config) + .await + .expect("Failed to sync checkpoints"); + } + _ => {} + } +} + +// Make a test namespace +#[cfg(test)] +mod tests { + use std::path::{Path, PathBuf}; + + use iota_types::messages_checkpoint::FullCheckpointContents; + + use super::*; + + async fn read_full_checkpoint(checkpoint_path: &PathBuf) -> anyhow::Result { + let mut reader = fs::File::open(checkpoint_path.clone())?; + let metadata = fs::metadata(checkpoint_path)?; + let mut buffer = vec![0; metadata.len() as usize]; + reader.read_exact(&mut buffer)?; + bcs::from_bytes(&buffer).map_err(|_| anyhow!("Unable to parse checkpoint file")) + } + + // clippy ignore dead-code + #[allow(dead_code)] + async fn write_full_checkpoint( + checkpoint_path: &Path, + checkpoint: &CheckpointData, + ) -> anyhow::Result<()> { + let mut writer = fs::File::create(checkpoint_path)?; + let bytes = bcs::to_bytes(&checkpoint) + .map_err(|_| anyhow!("Unable to serialize checkpoint summary"))?; + writer.write_all(&bytes)?; + Ok(()) + } + + async fn read_data() -> (Committee, CheckpointData) { + let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + d.push("example_config/20873329.yaml"); + + let mut reader = fs::File::open(d.clone()).unwrap(); + let metadata = fs::metadata(&d).unwrap(); + let mut buffer = vec![0; metadata.len() as usize]; + reader.read_exact(&mut buffer).unwrap(); + let checkpoint: Envelope> = + bcs::from_bytes(&buffer) + .map_err(|_| anyhow!("Unable to parse checkpoint file")) + .unwrap(); + + let prev_committee = checkpoint + .end_of_epoch_data + .as_ref() + .ok_or(anyhow!( + "Expected all checkpoints to be end-of-epoch checkpoints" + )) + .unwrap() + .next_epoch_committee + .iter() + .cloned() + .collect(); + + // Make a committee object using this + let committee = Committee::new(checkpoint.epoch().checked_add(1).unwrap(), prev_committee); + + let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + d.push("example_config/20958462.bcs"); + + let full_checkpoint = read_full_checkpoint(&d).await.unwrap(); + + (committee, full_checkpoint) + } + + #[tokio::test] + async fn test_checkpoint_all_good() { + let (committee, full_checkpoint) = read_data().await; + + extract_verified_effects_and_events( + &full_checkpoint, + &committee, + TransactionDigest::from_str("8RiKBwuAbtu8zNCtz8SrcfHyEUzto6zi6cMVA9t4WhWk").unwrap(), + ) + .unwrap(); + } + + #[tokio::test] + async fn test_checkpoint_bad_committee() { + let (mut committee, full_checkpoint) = read_data().await; + + // Change committee + committee.epoch += 10; + + assert!( + extract_verified_effects_and_events( + &full_checkpoint, + &committee, + TransactionDigest::from_str("8RiKBwuAbtu8zNCtz8SrcfHyEUzto6zi6cMVA9t4WhWk") + .unwrap(), + ) + .is_err() + ); + } + + #[tokio::test] + async fn test_checkpoint_no_transaction() { + let (committee, full_checkpoint) = read_data().await; + + assert!( + extract_verified_effects_and_events( + &full_checkpoint, + &committee, + TransactionDigest::from_str("8RiKBwuAbtu8zNCtz8SrcfHyEUzto6zj6cMVA9t4WhWk") + .unwrap(), + ) + .is_err() + ); + } + + #[tokio::test] + async fn test_checkpoint_bad_contents() { + let (committee, mut full_checkpoint) = read_data().await; + + // Change contents + let random_contents = FullCheckpointContents::random_for_testing(); + full_checkpoint.checkpoint_contents = random_contents.checkpoint_contents(); + + assert!( + extract_verified_effects_and_events( + &full_checkpoint, + &committee, + TransactionDigest::from_str("8RiKBwuAbtu8zNCtz8SrcfHyEUzto6zj6cMVA9t4WhWk") + .unwrap(), + ) + .is_err() + ); + } + + #[tokio::test] + async fn test_checkpoint_bad_events() { + let (committee, mut full_checkpoint) = read_data().await; + + let event = full_checkpoint.transactions[4] + .events + .as_ref() + .unwrap() + .data[0] + .clone(); + + for t in &mut full_checkpoint.transactions { + if let Some(events) = &mut t.events { + events.data.push(event.clone()); + } + } + + assert!( + extract_verified_effects_and_events( + &full_checkpoint, + &committee, + TransactionDigest::from_str("8RiKBwuAbtu8zNCtz8SrcfHyEUzto6zj6cMVA9t4WhWk") + .unwrap(), + ) + .is_err() + ); + } +} diff --git a/crates/iota-macros/Cargo.toml b/crates/iota-macros/Cargo.toml new file mode 100644 index 00000000000..38ef4da82da --- /dev/null +++ b/crates/iota-macros/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "iota-macros" +version = "0.7.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +iota-proc-macros.workspace = true +once_cell.workspace = true +futures.workspace = true +tracing.workspace = true diff --git a/crates/iota-macros/src/lib.rs b/crates/iota-macros/src/lib.rs new file mode 100644 index 00000000000..395a632ed9f --- /dev/null +++ b/crates/iota-macros/src/lib.rs @@ -0,0 +1,733 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::HashMap, future::Future, sync::Arc}; + +use futures::future::BoxFuture; +pub use iota_proc_macros::*; + +/// Evaluates an expression in a new thread which will not be subject to +/// interception of getrandom(), clock_gettime(), etc. +#[cfg(msim)] +#[macro_export] +macro_rules! nondeterministic { + ($expr: expr) => { + std::thread::scope(move |s| s.spawn(move || $expr).join().unwrap()) + }; +} + +/// Simply evaluates expr. +#[cfg(not(msim))] +#[macro_export] +macro_rules! nondeterministic { + ($expr: expr) => { + $expr + }; +} + +type FpCallback = dyn Fn() -> Box + Send + Sync; +type FpMap = HashMap<&'static str, Arc>; + +#[cfg(msim)] +fn with_fp_map(func: impl FnOnce(&mut FpMap) -> T) -> T { + thread_local! { + static MAP: std::cell::RefCell = Default::default(); + } + + MAP.with(|val| func(&mut val.borrow_mut())) +} + +#[cfg(not(msim))] +fn with_fp_map(func: impl FnOnce(&mut FpMap) -> T) -> T { + use std::sync::Mutex; + + use once_cell::sync::Lazy; + + static MAP: Lazy> = Lazy::new(Default::default); + let mut map = MAP.lock().unwrap(); + func(&mut map) +} + +fn get_callback(identifier: &'static str) -> Option> { + with_fp_map(|map| map.get(identifier).cloned()) +} + +fn get_sync_fp_result(result: Box) { + if result.downcast::<()>().is_err() { + panic!("sync failpoint must return ()"); + } +} + +fn get_async_fp_result(result: Box) -> BoxFuture<'static, ()> { + match result.downcast::>() { + Ok(fut) => *fut, + Err(err) => panic!( + "async failpoint must return BoxFuture<'static, ()> {:?}", + err + ), + } +} + +fn get_fp_if_result(result: Box) -> bool { + match result.downcast::() { + Ok(b) => *b, + Err(_) => panic!("failpoint-if must return bool"), + } +} + +fn get_fp_some_result( + result: Box, +) -> Option { + match result.downcast::>() { + Ok(opt) => *opt, + Err(_) => panic!("failpoint-arg must return Option"), + } +} + +pub fn handle_fail_point(identifier: &'static str) { + if let Some(callback) = get_callback(identifier) { + get_sync_fp_result(callback()); + tracing::trace!("hit failpoint {}", identifier); + } +} + +pub async fn handle_fail_point_async(identifier: &'static str) { + if let Some(callback) = get_callback(identifier) { + tracing::trace!("hit async failpoint {}", identifier); + let fut = get_async_fp_result(callback()); + fut.await; + } +} + +pub fn handle_fail_point_if(identifier: &'static str) -> bool { + if let Some(callback) = get_callback(identifier) { + tracing::trace!("hit failpoint_if {}", identifier); + get_fp_if_result(callback()) + } else { + false + } +} + +pub fn handle_fail_point_arg(identifier: &'static str) -> Option { + if let Some(callback) = get_callback(identifier) { + tracing::trace!("hit failpoint_arg {}", identifier); + get_fp_some_result(callback()) + } else { + None + } +} + +fn register_fail_point_impl(identifier: &'static str, callback: Arc) { + with_fp_map(move |map| { + assert!( + map.insert(identifier, callback).is_none(), + "duplicate fail point registration" + ); + }) +} + +fn clear_fail_point_impl(identifier: &'static str) { + with_fp_map(move |map| { + assert!( + map.remove(identifier).is_some(), + "fail point {:?} does not exist", + identifier + ); + }) +} + +pub fn register_fail_point(identifier: &'static str, callback: impl Fn() + Sync + Send + 'static) { + register_fail_point_impl( + identifier, + Arc::new(move || { + callback(); + Box::new(()) + }), + ); +} + +/// Register an asynchronous fail point. Because it is async it can yield +/// execution of the calling task, e.g. by sleeping. +pub fn register_fail_point_async( + identifier: &'static str, + callback: impl Fn() -> F + Sync + Send + 'static, +) where + F: Future + Send + 'static, +{ + register_fail_point_impl( + identifier, + Arc::new(move || { + let result: BoxFuture<'static, ()> = Box::pin(callback()); + Box::new(result) + }), + ); +} + +/// Register code to run locally if the fail point is hit. Example: +/// +/// In the test: +/// +/// ```ignore +/// register_fail_point_if("foo", || { +/// iota_simulator::current_simnode_id() == 2 +/// }); +/// ``` +/// +/// In the code: +/// +/// ```ignore +/// let mut was_hit = false; +/// fail_point_if("foo", || { +/// was_hit = true; +/// }); +/// ``` +pub fn register_fail_point_if( + identifier: &'static str, + callback: impl Fn() -> bool + Sync + Send + 'static, +) { + register_fail_point_impl(identifier, Arc::new(move || Box::new(callback()))); +} + +/// Register code to run locally if the fail point is hit, with a value provided +/// by the test. If the registered callback returns a Some(v), then the `v` is +/// passed to the callback in the test. +/// +/// In the test: +/// +/// ```ignore +/// register_fail_point_arg("foo", || { +/// Some(42) +/// }); +/// ``` +/// +/// In the code: +/// +/// ```ignore +/// let mut value = 0; +/// fail_point_arg!("foo", |arg| { +/// value = arg; +/// }); +/// ``` +pub fn register_fail_point_arg( + identifier: &'static str, + callback: impl Fn() -> Option + Sync + Send + 'static, +) { + register_fail_point_impl(identifier, Arc::new(move || Box::new(callback()))); +} + +pub fn register_fail_points( + identifiers: &[&'static str], + callback: impl Fn() + Sync + Send + 'static, +) { + let cb: Arc = Arc::new(move || { + callback(); + Box::new(()) + }); + for id in identifiers { + register_fail_point_impl(id, cb.clone()); + } +} + +pub fn clear_fail_point(identifier: &'static str) { + clear_fail_point_impl(identifier); +} + +/// Trigger a fail point. Tests can trigger various behavior when the fail point +/// is hit. +#[cfg(any(msim, fail_points))] +#[macro_export] +macro_rules! fail_point { + ($tag: expr) => { + $crate::handle_fail_point($tag) + }; +} + +/// Trigger an async fail point. Tests can trigger various async behavior when +/// the fail point is hit. +#[cfg(any(msim, fail_points))] +#[macro_export] +macro_rules! fail_point_async { + ($tag: expr) => { + $crate::handle_fail_point_async($tag).await + }; +} + +/// Trigger a failpoint that runs a callback at the callsite if it is enabled. +/// (whether it is enabled is controlled by whether the registration callback +/// returns true/false). +#[cfg(any(msim, fail_points))] +#[macro_export] +macro_rules! fail_point_if { + ($tag: expr, $callback: expr) => { + if $crate::handle_fail_point_if($tag) { + ($callback)(); + } + }; +} + +/// Trigger a failpoint that runs a callback at the callsite if it is enabled. +/// If the registration callback returns Some(v), then the `v` is passed to the +/// callback in the test. Otherwise the failpoint is skipped +#[cfg(any(msim, fail_points))] +#[macro_export] +macro_rules! fail_point_arg { + ($tag: expr, $callback: expr) => { + if let Some(arg) = $crate::handle_fail_point_arg($tag) { + ($callback)(arg); + } + }; +} + +#[cfg(not(any(msim, fail_points)))] +#[macro_export] +macro_rules! fail_point { + ($tag: expr) => {}; +} + +#[cfg(not(any(msim, fail_points)))] +#[macro_export] +macro_rules! fail_point_async { + ($tag: expr) => {}; +} + +#[cfg(not(any(msim, fail_points)))] +#[macro_export] +macro_rules! fail_point_if { + ($tag: expr, $callback: expr) => {}; +} + +#[cfg(not(any(msim, fail_points)))] +#[macro_export] +macro_rules! fail_point_arg { + ($tag: expr, $callback: expr) => {}; +} + +/// Use to write INFO level logs only when REPLAY_LOG +/// environment variable is set. Useful for log lines that +/// are only relevant to test infra which still may need to +/// run a release build. Also note that since logs of a chain +/// replay are exceedingly verbose, this will allow one to bubble +/// up "debug level" info while running with RUST_LOG=info. +#[macro_export] +macro_rules! replay_log { + ($($arg:tt)+) => { + if std::env::var("REPLAY_LOG").is_ok() { + tracing::info!($($arg)+); + } + }; +} + +// These tests need to be run in release mode, since debug mode does overflow +// checks by default! +#[cfg(test)] +mod test { + use super::*; + + // Uncomment to test error messages + // #[with_checked_arithmetic] + // struct TestStruct; + + macro_rules! pass_through { + ($($tt:tt)*) => { + $($tt)* + } + } + + #[with_checked_arithmetic] + #[test] + fn test_skip_checked_arithmetic() { + // comment out this attr to test the error message + #[skip_checked_arithmetic] + pass_through! { + fn unchecked_add(a: i32, b: i32) -> i32 { + a + b + } + } + + // this will not panic even if we pass in (i32::MAX, 1), because we skipped + // processing the item macro, so we also need to make sure it doesn't + // panic in debug mode. + unchecked_add(1, 2); + } + + checked_arithmetic! { + + struct Test { + a: i32, + b: i32, + } + + fn unchecked_add(a: i32, b: i32) -> i32 { + a + b + } + + #[test] + fn test_checked_arithmetic_macro() { + unchecked_add(1, 2); + } + + #[test] + #[should_panic] + fn test_checked_arithmetic_macro_panic() { + unchecked_add(i32::MAX, 1); + } + + fn unchecked_add_hidden(a: i32, b: i32) -> i32 { + let inner = |a: i32, b: i32| a + b; + inner(a, b) + } + + #[test] + #[should_panic] + fn test_checked_arithmetic_macro_panic_hidden() { + unchecked_add_hidden(i32::MAX, 1); + } + + fn unchecked_add_hidden_2(a: i32, b: i32) -> i32 { + fn inner(a: i32, b: i32) -> i32 { + a + b + } + inner(a, b) + } + + #[test] + #[should_panic] + fn test_checked_arithmetic_macro_panic_hidden_2() { + unchecked_add_hidden_2(i32::MAX, 1); + } + + impl Test { + fn add(&self) -> i32 { + self.a + self.b + } + } + + #[test] + #[should_panic] + fn test_checked_arithmetic_impl() { + let t = Test { a: 1, b: i32::MAX }; + t.add(); + } + + #[test] + #[should_panic] + fn test_macro_overflow() { + #[allow(arithmetic_overflow)] + fn f() { + println!("{}", i32::MAX + 1); + } + + f() + } + + // Make sure that we still do addition correctly! + #[test] + fn test_non_overflow() { + fn f() { + assert_eq!(1i32 + 2i32, 3i32); + assert_eq!(3i32 - 1i32, 2i32); + assert_eq!(4i32 * 3i32, 12i32); + assert_eq!(12i32 / 3i32, 4i32); + assert_eq!(12i32 % 5i32, 2i32); + + let mut a = 1i32; + a += 2i32; + assert_eq!(a, 3i32); + + let mut a = 3i32; + a -= 1i32; + assert_eq!(a, 2i32); + + let mut a = 4i32; + a *= 3i32; + assert_eq!(a, 12i32); + + let mut a = 12i32; + a /= 3i32; + assert_eq!(a, 4i32); + + let mut a = 12i32; + a %= 5i32; + assert_eq!(a, 2i32); + } + + f(); + } + + + #[test] + fn test_exprs_evaluated_once_right() { + let mut called = false; + let mut f = || { + if called { + panic!("called twice"); + } + called = true; + 1i32 + }; + + assert_eq!(2i32 + f(), 3); + } + + #[test] + fn test_exprs_evaluated_once_left() { + let mut called = false; + let mut f = || { + if called { + panic!("called twice"); + } + called = true; + 1i32 + }; + + assert_eq!(f() + 2i32, 3); + } + + #[test] + fn test_assign_op_evals_once() { + struct Foo { + a: i32, + called: bool, + } + + impl Foo { + fn get_a_mut(&mut self) -> &mut i32 { + if self.called { + panic!("called twice"); + } + let ret = &mut self.a; + self.called = true; + ret + } + } + + let mut foo = Foo { a: 1, called: false }; + + *foo.get_a_mut() += 2; + assert_eq!(foo.a, 3); + } + + #[test] + fn test_more_macro_syntax() { + struct Foo { + a: i32, + b: i32, + } + + impl Foo { + const BAR: i32 = 1; + + fn new(a: i32, b: i32) -> Foo { + Foo { a, b } + } + } + + fn new_foo(a: i32) -> Foo { + Foo { a, b: 0 } + } + + // verify that we translate the contents of macros correctly + assert_eq!(Foo::BAR + 1, 2); + assert_eq!(Foo::new(1, 2).b, 2); + assert_eq!(new_foo(1).a, 1); + + let v = vec![Foo::new(1, 2), Foo::new(3, 2)]; + + assert_eq!(v[0].a, 1); + assert_eq!(v[1].b, 2); + } + + } + + #[with_checked_arithmetic] + mod with_checked_arithmetic_tests { + + struct Test { + a: i32, + b: i32, + } + + fn unchecked_add(a: i32, b: i32) -> i32 { + a + b + } + + #[test] + fn test_checked_arithmetic_macro() { + unchecked_add(1, 2); + } + + #[test] + #[should_panic] + fn test_checked_arithmetic_macro_panic() { + unchecked_add(i32::MAX, 1); + } + + fn unchecked_add_hidden(a: i32, b: i32) -> i32 { + let inner = |a: i32, b: i32| a + b; + inner(a, b) + } + + #[test] + #[should_panic] + fn test_checked_arithmetic_macro_panic_hidden() { + unchecked_add_hidden(i32::MAX, 1); + } + + fn unchecked_add_hidden_2(a: i32, b: i32) -> i32 { + fn inner(a: i32, b: i32) -> i32 { + a + b + } + inner(a, b) + } + + #[test] + #[should_panic] + fn test_checked_arithmetic_macro_panic_hidden_2() { + unchecked_add_hidden_2(i32::MAX, 1); + } + + impl Test { + fn add(&self) -> i32 { + self.a + self.b + } + } + + #[test] + #[should_panic] + fn test_checked_arithmetic_impl() { + let t = Test { a: 1, b: i32::MAX }; + t.add(); + } + + #[test] + #[should_panic] + fn test_macro_overflow() { + #[allow(arithmetic_overflow)] + fn f() { + println!("{}", i32::MAX + 1); + } + + f() + } + + // Make sure that we still do addition correctly! + #[test] + fn test_non_overflow() { + fn f() { + assert_eq!(1i32 + 2i32, 3i32); + assert_eq!(3i32 - 1i32, 2i32); + assert_eq!(4i32 * 3i32, 12i32); + assert_eq!(12i32 / 3i32, 4i32); + assert_eq!(12i32 % 5i32, 2i32); + + let mut a = 1i32; + a += 2i32; + assert_eq!(a, 3i32); + + let mut a = 3i32; + a -= 1i32; + assert_eq!(a, 2i32); + + let mut a = 4i32; + a *= 3i32; + assert_eq!(a, 12i32); + + let mut a = 12i32; + a /= 3i32; + assert_eq!(a, 4i32); + + let mut a = 12i32; + a %= 5i32; + assert_eq!(a, 2i32); + } + + f(); + } + + #[test] + fn test_exprs_evaluated_once_right() { + let mut called = false; + let mut f = || { + if called { + panic!("called twice"); + } + called = true; + 1i32 + }; + + assert_eq!(2i32 + f(), 3); + } + + #[test] + fn test_exprs_evaluated_once_left() { + let mut called = false; + let mut f = || { + if called { + panic!("called twice"); + } + called = true; + 1i32 + }; + + assert_eq!(f() + 2i32, 3); + } + + #[test] + fn test_assign_op_evals_once() { + struct Foo { + a: i32, + called: bool, + } + + impl Foo { + fn get_a_mut(&mut self) -> &mut i32 { + if self.called { + panic!("called twice"); + } + let ret = &mut self.a; + self.called = true; + ret + } + } + + let mut foo = Foo { + a: 1, + called: false, + }; + + *foo.get_a_mut() += 2; + assert_eq!(foo.a, 3); + } + + #[test] + fn test_more_macro_syntax() { + struct Foo { + a: i32, + b: i32, + } + + impl Foo { + const BAR: i32 = 1; + + fn new(a: i32, b: i32) -> Foo { + Foo { a, b } + } + } + + fn new_foo(a: i32) -> Foo { + Foo { a, b: 0 } + } + + // verify that we translate the contents of macros correctly + assert_eq!(Foo::BAR + 1, 2); + assert_eq!(Foo::new(1, 2).b, 2); + assert_eq!(new_foo(1).a, 1); + + let v = vec![Foo::new(1, 2), Foo::new(3, 2)]; + + assert_eq!(v[0].a, 1); + assert_eq!(v[1].b, 2); + } + } +} diff --git a/crates/iota-metric-checker/Cargo.toml b/crates/iota-metric-checker/Cargo.toml new file mode 100644 index 00000000000..da7257a1451 --- /dev/null +++ b/crates/iota-metric-checker/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "iota-metric-checker" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +backoff.workspace = true +base64.workspace = true +chrono.workspace = true +clap = { version = "4.3.0", features = ["derive"] } +humantime.workspace = true +once_cell.workspace = true +prometheus-http-query.workspace = true +reqwest.workspace = true +serde.workspace = true +serde_yaml = "0.9.21" +strum_macros.workspace = true +telemetry-subscribers.workspace = true +tokio = { workspace = true, features = ["full"] } +tracing.workspace = true diff --git a/crates/iota-metric-checker/README.md b/crates/iota-metric-checker/README.md new file mode 100644 index 00000000000..599b271d082 --- /dev/null +++ b/crates/iota-metric-checker/README.md @@ -0,0 +1,26 @@ +The `iota-metric-checker` crate is used for querying prometheus metrics and validating the results. It will primarily be used to check for performance regressions in nightly deployments. Requires `api_key`, `api_user` & prometheus `url` which can be found in `iota-ops` repo or by asking the PE team. + +## Guide + +### Example Usage + +``` +RUST_LOG=debug cargo run --package iota-metric-checker --bin iota-metric-checker -- --api-key xxxxxxxx --api-user xxxx_metrics --config checks.yaml --url https://xxxx.iota.io/prometheus +``` + +### Example Config + +[example/config.yaml](example/config.yaml#L1-L32) + +### Example Error Output + +``` +Error: Following queries failed to meet threshold conditions: [ + "After 3 retry attempts - Did not get expected response from server for histogram_quantile(0.5, sum by(le) (rate(latency_s_bucket{network=\"private-testnet\"}[15m])))", + "After 3 retry attempts - Did not get expected response from server for histogram_quantile(0.95, sum by(le) (rate(latency_s_bucket{network=\"private-testnet\"}[15m])))", + "After 3 retry attempts - Did not get expected response from server for sum(rate(num_success{network=\"private-testnet\"}[5m]))", + "Query \"histogram_quantile(0.50, sum by(le) (rate(batch_execution_latency_bucket{network=\"private-testnet\"}[15m])))\" returned value of 3.112150385622982 which is Greater 3", + "Query \"avg(rate(total_transaction_effects{network=\"private-testnet\"}[5m]))\" returned value of 1.081275647819765 which is Less 5500", + "Query \"avg (rate(batch_size_sum{network=\"private-testnet\"}[5m]))\" returned value of 0.24698238962944846 which is Less 5500", +] +``` diff --git a/crates/sui-metric-checker/example/config.yaml b/crates/iota-metric-checker/example/config.yaml similarity index 100% rename from crates/sui-metric-checker/example/config.yaml rename to crates/iota-metric-checker/example/config.yaml diff --git a/crates/iota-metric-checker/src/lib.rs b/crates/iota-metric-checker/src/lib.rs new file mode 100644 index 00000000000..fe715149e6f --- /dev/null +++ b/crates/iota-metric-checker/src/lib.rs @@ -0,0 +1,219 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use anyhow::anyhow; +use chrono::{DateTime, Duration, NaiveDateTime, Utc}; +use humantime::parse_duration; +use serde::Deserialize; +use strum_macros::Display; + +pub mod query; + +#[derive(Debug, Display, Deserialize, PartialEq)] +pub enum QueryType { + Instant, + Range { + // Both start & end accepts specific time formats + // - "%Y-%m-%d %H:%M:%S" (UTC) + // Or relative time + offset, i.e. + // - "now" + // - "now-1h" + // - "now-30m 10s" + start: String, + end: String, + // Query resolution step width as float number of seconds + step: f64, + }, +} + +#[derive(Debug, Display, Deserialize, PartialEq)] +pub enum Condition { + Greater, + Equal, + Less, +} + +// Used to specify validation rules for query result e.g. +// +// validate_result: +// threshold: 10 +// failure_condition: Greater +// +// Program will report error if queried value is greater than 10, otherwise +// no error will be reported. +#[derive(Debug, Deserialize, PartialEq)] +pub struct QueryResultValidation { + // Threshold to report error on + pub threshold: f64, + // Program will report error if threshold violates condition specifed by this + // field. + pub failure_condition: Condition, +} + +#[derive(Debug, Deserialize, PartialEq)] +pub struct Query { + // PromQL query to exeute + pub query: String, + // Type of query to execute - Instant or Range. + #[serde(rename = "type")] + pub query_type: QueryType, + // Optional validation rules for the query result, otherwise the query result + // is just to be printed in debug logs. + pub validate_result: Option, +} + +#[derive(Debug, Deserialize)] +pub struct Config { + pub queries: Vec, +} + +// Used to mock now() in tests and use consistent now() return values across +// queries in performance checks. +pub trait NowProvider { + fn now() -> DateTime; +} + +pub struct UtcNowProvider; + +// Basic implementation of NowProvider that returns current time in UTC. +impl NowProvider for UtcNowProvider { + fn now() -> DateTime { + Utc::now() + } +} + +// Convert timestamp string to unix seconds. +// Accepts the following time formats +// - "%Y-%m-%d %H:%M:%S" (UTC) +// Or relative time + offset, i.e. +// - "now" +// - "now-1h" +// - "now-30m 10s" +pub fn timestamp_string_to_unix_seconds( + timestamp: &str, +) -> Result { + if timestamp.starts_with("now") { + if let Some(relative_timestamp) = timestamp.strip_prefix("now-") { + let duration = parse_duration(relative_timestamp)?; + let now = N::now(); + let new_datetime = now.checked_sub_signed(Duration::from_std(duration)?); + + if let Some(datetime) = new_datetime { + return Ok(datetime.timestamp()); + } else { + return Err(anyhow!("Unable to calculate time offset")); + } + } + + return Ok(N::now().timestamp()); + } + + if let Ok(datetime) = NaiveDateTime::parse_from_str(timestamp, "%Y-%m-%d %H:%M:%S") { + let utc_datetime: DateTime = DateTime::from_naive_utc_and_offset(datetime, Utc); + Ok(utc_datetime.timestamp()) + } else { + Err(anyhow!("Invalid timestamp format")) + } +} + +pub fn fails_threshold_condition( + queried_value: f64, + threshold: f64, + failure_condition: &Condition, +) -> bool { + match failure_condition { + Condition::Greater => queried_value > threshold, + Condition::Equal => queried_value == threshold, + Condition::Less => queried_value < threshold, + } +} + +fn unix_seconds_to_timestamp_string(unix_seconds: i64) -> String { + let datetime = NaiveDateTime::from_timestamp_opt(unix_seconds, 0); + let timestamp: DateTime = DateTime::from_naive_utc_and_offset(datetime.unwrap(), Utc); + timestamp.to_string() +} + +#[cfg(test)] +mod tests { + use chrono::TimeZone; + + use super::*; + + struct MockNowProvider; + + impl NowProvider for MockNowProvider { + fn now() -> DateTime { + Utc.timestamp_opt(1628553600, 0).unwrap() + } + } + + #[test] + fn test_parse_timestamp_string_to_unix_seconds() { + let timestamp = "2021-08-10 00:00:00"; + let unix_seconds = timestamp_string_to_unix_seconds::(timestamp).unwrap(); + assert_eq!(unix_seconds, 1628553600); + + let timestamp = "now"; + let unix_seconds = timestamp_string_to_unix_seconds::(timestamp).unwrap(); + assert_eq!(unix_seconds, 1628553600); + + let timestamp = "now-1h"; + let unix_seconds = timestamp_string_to_unix_seconds::(timestamp).unwrap(); + assert_eq!(unix_seconds, 1628553600 - 3600); + + let timestamp = "now-30m 10s"; + let unix_seconds = timestamp_string_to_unix_seconds::(timestamp).unwrap(); + assert_eq!(unix_seconds, 1628553600 - 1810); + } + + #[test] + fn test_unix_seconds_to_timestamp_string() { + let unix_seconds = 1628534400; + let timestamp = unix_seconds_to_timestamp_string(unix_seconds); + assert_eq!(timestamp, "2021-08-09 18:40:00 UTC"); + } + + #[test] + fn test_parse_config() { + let config = r#" + queries: + - query: 'max(current_epoch{network="testnet"})' + type: Instant + + - query: 'histogram_quantile(0.50, sum by(le) (rate(round_latency{network="testnet"}[15m])))' + type: !Range + start: "now-1h" + end: "now" + step: 60.0 + validate_result: + threshold: 3.0 + failure_condition: Greater + "#; + + let config: Config = serde_yaml::from_str(config).unwrap(); + + let expected_range_query = Query { + query: "histogram_quantile(0.50, sum by(le) (rate(round_latency{network=\"testnet\"}[15m])))".to_string(), + query_type: QueryType::Range { + start: "now-1h".to_string(), + end: "now".to_string(), + step: 60.0, + }, + validate_result: Some(QueryResultValidation { + threshold: 3.0, + failure_condition: Condition::Greater, + }), + }; + + let expected_instant_query = Query { + query: "max(current_epoch{network=\"testnet\"})".to_string(), + query_type: QueryType::Instant, + validate_result: None, + }; + + let expected_queries = vec![expected_instant_query, expected_range_query]; + + assert_eq!(config.queries, expected_queries); + } +} diff --git a/crates/iota-metric-checker/src/main.rs b/crates/iota-metric-checker/src/main.rs new file mode 100644 index 00000000000..f529a869c64 --- /dev/null +++ b/crates/iota-metric-checker/src/main.rs @@ -0,0 +1,130 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use std::{fs::File, io::Read, time::Duration}; + +use anyhow::anyhow; +use backoff::{future::retry, ExponentialBackoff}; +use chrono::{DateTime, Utc}; +use clap::*; +use iota_metric_checker::{ + fails_threshold_condition, + query::{instant_query, range_query}, + timestamp_string_to_unix_seconds, Config, NowProvider, QueryType, +}; +use once_cell::sync::Lazy; +use prometheus_http_query::Client; + +#[derive(Parser)] +pub struct Opts { + #[arg(long, required = true)] + api_user: String, + #[arg(long, required = true)] + api_key: String, + // Path to the config file + #[arg(long, required = true)] + config: String, + // URL of the Prometheus server + #[arg(long, required = true)] + url: String, +} + +// This allows us to use the same value for now() for all queries checked during +// the duration of tool. +struct UtcNowOnceProvider {} + +impl NowProvider for UtcNowOnceProvider { + fn now() -> DateTime { + static NOW: Lazy> = Lazy::new(Utc::now); + *NOW + } +} + +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + let opts: Opts = Opts::parse(); + let _guard = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .init(); + + let auth_header = format!("{}:{}", opts.api_user, opts.api_key); + + let mut file = File::open(opts.config)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + let config: Config = serde_yaml::from_str(&contents)?; + + let client = { + let c = reqwest::Client::builder() + .no_proxy() + .timeout(Duration::from_secs(10)) + .build() + .unwrap(); + Client::from(c, &opts.url).unwrap() + }; + + let backoff = ExponentialBackoff { + max_elapsed_time: Some(Duration::from_secs(5)), + ..ExponentialBackoff::default() + }; + + let mut failed_queries = Vec::new(); + for query in config.queries { + let queried_result = match query.query_type { + QueryType::Instant => { + retry(backoff.clone(), || async { + instant_query(&auth_header, client.clone(), &query.query) + .await + .map_err(backoff::Error::transient) + }) + .await + } + QueryType::Range { start, end, step } => { + retry(backoff.clone(), || async { + range_query( + &auth_header, + client.clone(), + &query.query, + timestamp_string_to_unix_seconds::(&start)?, + timestamp_string_to_unix_seconds::(&end)?, + step, + ) + .await + .map_err(backoff::Error::transient) + }) + .await + } + }; + + if let Some(validate_result) = query.validate_result { + match queried_result { + Ok(queried_value) => { + if fails_threshold_condition( + queried_value, + validate_result.threshold, + &validate_result.failure_condition, + ) { + failed_queries.push(format!( + "Query \"{}\" returned value of {queried_value} which is {} {}", + query.query, + validate_result.failure_condition, + validate_result.threshold + )); + } + } + Err(error) => { + failed_queries.push(error.to_string()); + continue; + } + } + } + } + + if !failed_queries.is_empty() { + return Err(anyhow!( + "Following queries failed to meet threshold conditions: {failed_queries:#?}" + )); + } + + Ok(()) +} diff --git a/crates/iota-metric-checker/src/query.rs b/crates/iota-metric-checker/src/query.rs new file mode 100644 index 00000000000..43bb81c5dd4 --- /dev/null +++ b/crates/iota-metric-checker/src/query.rs @@ -0,0 +1,91 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use anyhow::anyhow; +use base64::{engine::general_purpose, Engine}; +use prometheus_http_query::Client; +use reqwest::header::{HeaderValue, AUTHORIZATION}; +use tracing::debug; + +use crate::unix_seconds_to_timestamp_string; + +pub async fn instant_query( + auth_header: &str, + client: Client, + query: &str, +) -> Result { + debug!("Executing {query}"); + let response = client + .query(query) + .header( + AUTHORIZATION, + HeaderValue::from_str(&format!( + "Basic {}", + general_purpose::STANDARD.encode(auth_header) + ))?, + ) + .get() + .await?; + + let result = response + .data() + .as_vector() + .unwrap_or_else(|| panic!("Expected result of type vector for {query}")); + + if !result.is_empty() { + let first = result.first().unwrap(); + debug!("Got value {}", first.sample().value()); + Ok(first.sample().value()) + } else { + Err(anyhow!( + "Did not get expected response from server for {query}" + )) + } +} + +// This will return the average value of the queried metric over the given time +// range. +pub async fn range_query( + auth_header: &str, + client: Client, + query: &str, + start: i64, + end: i64, + step: f64, +) -> Result { + debug!("Executing {query}"); + let response = client + .query_range(query, start, end, step) + .header( + AUTHORIZATION, + HeaderValue::from_str(&format!( + "Basic {}", + general_purpose::STANDARD.encode(auth_header) + ))?, + ) + .get() + .await?; + + let result = response + .data() + .as_matrix() + .unwrap_or_else(|| panic!("Expected result of type matrix for {query}")); + + if !result.is_empty() { + let samples = result.first().unwrap().samples(); + let sum: f64 = samples.iter().map(|sample| sample.value()).sum(); + let count = samples.len(); + + let avg = if count > 0 { sum / count as f64 } else { 0.0 }; + debug!( + "Got average value {avg} over time range {} - {}", + unix_seconds_to_timestamp_string(start), + unix_seconds_to_timestamp_string(end) + ); + Ok(avg) + } else { + Err(anyhow!( + "Did not get expected response from server for {query}" + )) + } +} diff --git a/crates/iota-move-build/Cargo.toml b/crates/iota-move-build/Cargo.toml new file mode 100644 index 00000000000..039c40765a5 --- /dev/null +++ b/crates/iota-move-build/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "iota-move-build" +version.workspace = true +edition = "2021" +authors = ["Mysten Labs "] +description = "Logic for building Iota Move Packages" +license = "Apache-2.0" +publish = false + +[dependencies] +anyhow.workspace = true +fastcrypto.workspace = true +tempfile.workspace = true + +move-bytecode-verifier = { path = "../../external-crates/move/crates/move-bytecode-verifier" } +iota-verifier = { path = "../../iota-execution/latest/iota-verifier", package = "iota-verifier-latest" } + +serde-reflection.workspace = true +iota-types.workspace = true +iota-protocol-config.workspace = true + +move-binary-format.workspace = true +move-bytecode-utils.workspace = true +move-command-line-common.workspace = true +move-compiler.workspace = true +move-core-types.workspace = true +move-ir-types.workspace = true +move-package.workspace = true +move-symbol-pool.workspace = true + +[dev-dependencies] +datatest-stable.workspace = true diff --git a/crates/iota-move-build/src/lib.rs b/crates/iota-move-build/src/lib.rs new file mode 100644 index 00000000000..6bc8257232b --- /dev/null +++ b/crates/iota-move-build/src/lib.rs @@ -0,0 +1,789 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +extern crate move_ir_types; + +use std::{ + collections::{BTreeMap, BTreeSet, HashSet}, + io::Write, + path::{Path, PathBuf}, + str::FromStr, +}; + +use fastcrypto::encoding::Base64; +use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; +use iota_types::{ + base_types::ObjectID, + error::{IotaError, IotaResult}, + is_system_package, + move_package::{FnInfo, FnInfoKey, FnInfoMap, MovePackage}, + DEEPBOOK_ADDRESS, IOTA_FRAMEWORK_ADDRESS, IOTA_SYSTEM_ADDRESS, MOVE_STDLIB_ADDRESS, + STARDUST_ADDRESS, TIMELOCK_ADDRESS, +}; +use iota_verifier::{default_verifier_config, verifier as iota_bytecode_verifier}; +use move_binary_format::{ + access::ModuleAccess, + normalized::{self, Type}, + CompiledModule, +}; +use move_bytecode_utils::{layout::SerdeLayoutBuilder, module_cache::GetModule}; +use move_compiler::{ + compiled_unit::AnnotatedCompiledModule, + diagnostics::{report_diagnostics_to_buffer, report_warnings, Diagnostics, FilesSourceText}, + editions::Edition, + linters::LINT_WARNING_PREFIX, +}; +use move_core_types::{ + account_address::AccountAddress, + language_storage::{ModuleId, StructTag, TypeTag}, +}; +use move_package::{ + compilation::{ + build_plan::BuildPlan, compiled_package::CompiledPackage as MoveCompiledPackage, + }, + package_hooks::{PackageHooks, PackageIdentifier}, + resolution::resolution_graph::{Package, ResolvedGraph}, + source_package::parsed_manifest::{CustomDepInfo, SourceManifest}, + BuildConfig as MoveBuildConfig, +}; +use move_symbol_pool::Symbol; +use serde_reflection::Registry; + +#[cfg(test)] +#[path = "unit_tests/build_tests.rs"] +mod build_tests; + +/// Wrapper around the core Move `CompiledPackage` with some Iota-specific +/// traits and info +#[derive(Debug, Clone)] +pub struct CompiledPackage { + pub package: MoveCompiledPackage, + /// Address the package is recorded as being published at. + pub published_at: Result, + /// The dependency IDs of this package + pub dependency_ids: PackageDependencies, + /// Path to the Move package (i.e., where the Move.toml file is) + pub path: PathBuf, +} + +/// Wrapper around the core Move `BuildConfig` with some Iota-specific info +#[derive(Clone)] +pub struct BuildConfig { + pub config: MoveBuildConfig, + /// If true, run the Move bytecode verifier on the bytecode from a + /// successful build + pub run_bytecode_verifier: bool, + /// If true, print build diagnostics to stderr--no printing if false + pub print_diags_to_stderr: bool, +} + +impl BuildConfig { + pub fn new_for_testing() -> Self { + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); + let mut build_config: Self = Default::default(); + let install_dir = tempfile::tempdir().unwrap().into_path(); + let lock_file = install_dir.join("Move.lock"); + build_config.config.install_dir = Some(install_dir); + build_config.config.lock_file = Some(lock_file); + build_config + .config + .lint_flag + .set(move_compiler::linters::LintLevel::None); + build_config + } + + pub fn new_for_testing_replace_addresses(dep_original_addresses: I) -> Self + where + I: IntoIterator, + S: Into, + { + let mut build_config = Self::new_for_testing(); + for (addr_name, obj_id) in dep_original_addresses { + build_config + .config + .additional_named_addresses + .insert(addr_name.into(), AccountAddress::from(obj_id)); + } + build_config + } + + fn fn_info(units: &[AnnotatedCompiledModule]) -> FnInfoMap { + let mut fn_info_map = BTreeMap::new(); + for u in units { + let mod_addr = u.named_module.address.into_inner(); + let mod_is_test = u.attributes.is_test_or_test_only(); + for (_, s, info) in &u.function_infos { + let fn_name = s.as_str().to_string(); + let is_test = mod_is_test || info.attributes.is_test_or_test_only(); + fn_info_map.insert(FnInfoKey { fn_name, mod_addr }, FnInfo { is_test }); + } + } + + fn_info_map + } + + fn compile_package( + resolution_graph: ResolvedGraph, + writer: &mut W, + ) -> anyhow::Result<(MoveCompiledPackage, FnInfoMap)> { + let build_plan = BuildPlan::create(resolution_graph)?; + let mut fn_info = None; + let compiled_pkg = build_plan.compile_with_driver(writer, |compiler| { + let (files, units_res) = compiler.build()?; + match units_res { + Ok((units, warning_diags)) => { + decorate_warnings(warning_diags, Some(&files)); + fn_info = Some(Self::fn_info(&units)); + Ok((files, units)) + } + Err(error_diags) => { + // with errors present don't even try decorating warnings output to avoid + // clutter + assert!(!error_diags.is_empty()); + let diags_buf = + report_diagnostics_to_buffer(&files, error_diags, /* color */ true); + if let Err(err) = std::io::stderr().write_all(&diags_buf) { + anyhow::bail!("Cannot output compiler diagnostics: {}", err); + } + anyhow::bail!("Compilation error"); + } + } + })?; + Ok((compiled_pkg, fn_info.unwrap())) + } + + /// Given a `path` and a `build_config`, build the package in that path, + /// including its dependencies. If we are building the Iota framework, we + /// skip the check that the addresses should be 0 + pub fn build(self, path: PathBuf) -> IotaResult { + let print_diags_to_stderr = self.print_diags_to_stderr; + let run_bytecode_verifier = self.run_bytecode_verifier; + let resolution_graph = self.resolution_graph(&path)?; + let result = build_from_resolution_graph( + path.clone(), + resolution_graph, + run_bytecode_verifier, + print_diags_to_stderr, + ); + if let Ok(ref compiled) = result { + compiled + .package + .compiled_package_info + .build_flags + .update_lock_file_toolchain_version(&path, env!("CARGO_PKG_VERSION").into()) + .map_err(|e| IotaError::ModuleBuildFailure { + error: format!("Failed to update Move.lock toolchain version: {e}"), + })?; + } + result + } + + pub fn resolution_graph(mut self, path: &Path) -> IotaResult { + if let Some(err_msg) = set_iota_flavor(&mut self.config) { + return Err(IotaError::ModuleBuildFailure { error: err_msg }); + } + + if self.print_diags_to_stderr { + self.config + .resolution_graph_for_package(path, &mut std::io::stderr()) + } else { + self.config + .resolution_graph_for_package(path, &mut std::io::sink()) + } + .map_err(|err| IotaError::ModuleBuildFailure { + error: format!("{:?}", err), + }) + } +} + +/// There may be additional information that needs to be displayed after +/// diagnostics are reported (optionally report diagnostics themselves if files +/// argument is provided). +pub fn decorate_warnings(warning_diags: Diagnostics, files: Option<&FilesSourceText>) { + let any_linter_warnings = warning_diags.any_with_prefix(LINT_WARNING_PREFIX); + let (filtered_diags_num, filtered_categories) = + warning_diags.filtered_source_diags_with_prefix(LINT_WARNING_PREFIX); + if let Some(f) = files { + report_warnings(f, warning_diags); + } + if any_linter_warnings { + eprintln!("Please report feedback on the linter warnings at https://forums.iota.io\n"); + } + if filtered_diags_num > 0 { + eprintln!( + "Total number of linter warnings suppressed: {filtered_diags_num} (filtered categories: {filtered_categories})" + ); + } +} + +/// Sets build config's default flavor to `Flavor::Iota`. Returns error message +/// if the flavor was previously set to something else than `Flavor::Iota`. +pub fn set_iota_flavor(build_config: &mut MoveBuildConfig) -> Option { + use move_compiler::editions::Flavor; + + let flavor = build_config.default_flavor.get_or_insert(Flavor::Iota); + if flavor != &Flavor::Iota { + return Some(format!( + "The flavor of the Move compiler cannot be overridden with anything but \ + \"{}\", but the default override was set to: \"{flavor}\"", + Flavor::Iota, + )); + } + None +} + +pub fn build_from_resolution_graph( + path: PathBuf, + resolution_graph: ResolvedGraph, + run_bytecode_verifier: bool, + print_diags_to_stderr: bool, +) -> IotaResult { + let (published_at, dependency_ids) = gather_published_ids(&resolution_graph); + + let result = if print_diags_to_stderr { + BuildConfig::compile_package(resolution_graph, &mut std::io::stderr()) + } else { + BuildConfig::compile_package(resolution_graph, &mut std::io::sink()) + }; + // write build failure diagnostics to stderr, convert `error` to `String` using + // `Debug` format to include anyhow's error context chain. + let (package, fn_info) = match result { + Err(error) => { + return Err(IotaError::ModuleBuildFailure { + error: format!("{:?}", error), + }); + } + Ok((package, fn_info)) => (package, fn_info), + }; + let compiled_modules = package.root_modules_map(); + if run_bytecode_verifier { + for m in compiled_modules.iter_modules() { + move_bytecode_verifier::verify_module_unmetered(m).map_err(|err| { + IotaError::ModuleVerificationFailure { + error: err.to_string(), + } + })?; + iota_bytecode_verifier::iota_verify_module_unmetered( + m, + &fn_info, + &default_verifier_config( + &ProtocolConfig::get_for_version(ProtocolVersion::MAX, Chain::Unknown), + false, + ), + )?; + } + // TODO(https://github.com/iotaledger/iota/issues/69): Run Move linker + } + Ok(CompiledPackage { + package, + published_at, + dependency_ids, + path, + }) +} + +impl CompiledPackage { + /// Return all of the bytecode modules in this package (not including direct + /// or transitive deps) Note: these are not topologically sorted by + /// dependency--use `get_dependency_sorted_modules` to produce a list of + /// modules suitable for publishing or static analysis + pub fn get_modules(&self) -> impl Iterator { + self.package.root_modules().map(|m| &m.unit.module) + } + + /// Return all of the bytecode modules in this package (not including direct + /// or transitive deps) Note: these are not topologically sorted by + /// dependency--use `get_dependency_sorted_modules` to produce a list of + /// modules suitable for publishing or static analysis + pub fn into_modules(self) -> Vec { + self.package + .root_compiled_units + .into_iter() + .map(|m| m.unit.module) + .collect() + } + + /// Return all of the bytecode modules that this package depends on (both + /// directly and transitively) Note: these are not topologically sorted + /// by dependency. + pub fn get_dependent_modules(&self) -> impl Iterator { + self.package + .deps_compiled_units + .iter() + .map(|(_, m)| &m.unit.module) + } + + /// Return all of the bytecode modules in this package and the modules of + /// its direct and transitive dependencies. Note: these are not + /// topologically sorted by dependency. + pub fn get_modules_and_deps(&self) -> impl Iterator { + self.package.all_modules().map(|m| &m.unit.module) + } + + /// Return the bytecode modules in this package, topologically sorted in + /// dependency order. Optionally include dependencies that have not been + /// published (are at address 0x0), if `with_unpublished_deps` is true. + /// This is the function to call if you would like to publish + /// or statically analyze the modules. + pub fn get_dependency_sorted_modules( + &self, + with_unpublished_deps: bool, + ) -> Vec { + let all_modules = self.package.all_modules_map(); + let graph = all_modules.compute_dependency_graph(); + + // SAFETY: package built successfully + let modules = graph.compute_topological_order().unwrap(); + + if with_unpublished_deps { + // For each transitive dependent module, if they are not to be published, they + // must have a non-zero address (meaning they are already published + // on-chain). + modules + .filter(|module| module.address() == &AccountAddress::ZERO) + .cloned() + .collect() + } else { + // Collect all module IDs from the current package to be published (module names + // are not sufficient as we may have modules with the same names in + // user code and in Iota framework which would result in the latter + // being pulled into a set of modules to be published). + let self_modules: HashSet<_> = self + .package + .root_modules_map() + .iter_modules() + .iter() + .map(|m| m.self_id()) + .collect(); + + modules + .filter(|module| self_modules.contains(&module.self_id())) + .cloned() + .collect() + } + } + + /// Return the set of Object IDs corresponding to this package's transitive + /// dependencies' original package IDs. + pub fn get_dependency_original_package_ids(&self) -> Vec { + let mut ids: BTreeSet<_> = self + .package + .deps_compiled_units + .iter() + .map(|(_, m)| ObjectID::from(*m.unit.module.address())) + .collect(); + + // `0x0` is not a real dependency ID -- it means that the package has + // unpublished dependencies. + ids.remove(&ObjectID::ZERO); + ids.into_iter().collect() + } + + pub fn get_package_digest(&self, with_unpublished_deps: bool) -> [u8; 32] { + let hash_modules = true; + MovePackage::compute_digest_for_modules_and_deps( + &self.get_package_bytes(with_unpublished_deps), + self.dependency_ids.published.values(), + hash_modules, + ) + } + + /// Return a serialized representation of the bytecode modules in this + /// package, topologically sorted in dependency order + pub fn get_package_bytes(&self, with_unpublished_deps: bool) -> Vec> { + self.get_dependency_sorted_modules(with_unpublished_deps) + .iter() + .map(|m| { + let mut bytes = Vec::new(); + m.serialize(&mut bytes).unwrap(); // safe because package built successfully + bytes + }) + .collect() + } + + /// Return the base64-encoded representation of the bytecode modules in this + /// package, topologically sorted in dependency order + pub fn get_package_base64(&self, with_unpublished_deps: bool) -> Vec { + self.get_package_bytes(with_unpublished_deps) + .iter() + .map(|b| Base64::from_bytes(b)) + .collect() + } + + pub fn get_package_dependencies_hex(&self) -> Vec { + self.dependency_ids + .published + .values() + .map(|object_id| object_id.to_hex_uncompressed()) + .collect() + } + + /// Get bytecode modules from DeepBook that are used by this package + pub fn get_deepbook_modules(&self) -> impl Iterator { + self.get_modules_and_deps() + .filter(|m| *m.self_id().address() == DEEPBOOK_ADDRESS) + } + + /// Get bytecode modules from the Iota System that are used by this package + pub fn get_iota_system_modules(&self) -> impl Iterator { + self.get_modules_and_deps() + .filter(|m| *m.self_id().address() == IOTA_SYSTEM_ADDRESS) + } + + /// Get bytecode modules from the Iota Framework that are used by this + /// package + pub fn get_iota_framework_modules(&self) -> impl Iterator { + self.get_modules_and_deps() + .filter(|m| *m.self_id().address() == IOTA_FRAMEWORK_ADDRESS) + } + + /// Get bytecode modules from the Move stdlib that are used by this package + pub fn get_stdlib_modules(&self) -> impl Iterator { + self.get_modules_and_deps() + .filter(|m| *m.self_id().address() == MOVE_STDLIB_ADDRESS) + } + + /// Get bytecode modules from Stardust that are used by this package + pub fn get_stardust_modules(&self) -> impl Iterator { + self.get_modules_and_deps() + .filter(|m| *m.self_id().address() == STARDUST_ADDRESS) + } + + /// Get bytecode modules from Timelock that are used by this package + pub fn get_timelock_modules(&self) -> impl Iterator { + self.get_modules_and_deps() + .filter(|m| *m.self_id().address() == TIMELOCK_ADDRESS) + } + + /// Generate layout schemas for all types declared by this package, as well + /// as all struct types passed into `entry` functions declared by + /// modules in this package (either directly or by reference). + /// These layout schemas can be consumed by clients (e.g., the TypeScript + /// SDK) to enable BCS serialization/deserialization of the package's + /// objects, tx arguments, and events. + pub fn generate_struct_layouts(&self) -> Registry { + let mut package_types = BTreeSet::new(); + for m in self.get_modules() { + let normalized_m = normalized::Module::new(m); + // 1. generate struct layouts for all declared types + 'structs: for (name, s) in normalized_m.structs { + let mut dummy_type_parameters = Vec::new(); + for t in &s.type_parameters { + if t.is_phantom { + // if all of t's type parameters are phantom, we can generate a type layout + // we make this happen by creating a StructTag with dummy `type_params`, + // since the layout generator won't look at them. we + // need to do this because SerdeLayoutBuilder will refuse to generate a + // layout for any open StructTag, but phantom types + // cannot affect the layout of a struct, so we just use dummy values + dummy_type_parameters.push(TypeTag::Signer) + } else { + // open type--do not attempt to generate a layout + // TODO: handle generating layouts for open types? + continue 'structs; + } + } + debug_assert!(dummy_type_parameters.len() == s.type_parameters.len()); + package_types.insert(StructTag { + address: *m.address(), + module: m.name().to_owned(), + name, + type_params: dummy_type_parameters, + }); + } + // 2. generate struct layouts for all parameters of `entry` funs + for (_name, f) in normalized_m.functions { + if f.is_entry { + for t in f.parameters { + let tag_opt = match t.clone() { + Type::Address + | Type::Bool + | Type::Signer + | Type::TypeParameter(_) + | Type::U8 + | Type::U16 + | Type::U32 + | Type::U64 + | Type::U128 + | Type::U256 + | Type::Vector(_) => continue, + Type::Reference(t) | Type::MutableReference(t) => t.into_struct_tag(), + s @ Type::Struct { .. } => s.into_struct_tag(), + }; + if let Some(tag) = tag_opt { + package_types.insert(tag); + } + } + } + } + } + let mut layout_builder = SerdeLayoutBuilder::new(self); + for typ in &package_types { + layout_builder.build_struct_layout(typ).unwrap(); + } + layout_builder.into_registry() + } + + /// Checks whether this package corresponds to a built-in framework + pub fn is_system_package(&self) -> bool { + // System packages always have "published-at" addresses + let Ok(published_at) = self.published_at else { + return false; + }; + + is_system_package(published_at) + } + + /// Checks for root modules with non-zero package addresses. Returns an + /// arbitrary one, if one can can be found, otherwise returns `None`. + pub fn published_root_module(&self) -> Option<&CompiledModule> { + self.package.root_compiled_units.iter().find_map(|unit| { + if unit.unit.module.self_id().address() != &AccountAddress::ZERO { + Some(&unit.unit.module) + } else { + None + } + }) + } + + pub fn verify_unpublished_dependencies( + &self, + unpublished_deps: &BTreeSet, + ) -> IotaResult<()> { + if unpublished_deps.is_empty() { + return Ok(()); + } + + let errors = self + .package + .deps_compiled_units + .iter() + .filter_map(|(p, m)| { + if !unpublished_deps.contains(p) || m.unit.module.address() == &AccountAddress::ZERO + { + return None; + } + Some(format!( + " - {}::{} in dependency {}", + m.unit.module.address(), + m.unit.name, + p + )) + }) + .collect::>(); + + if errors.is_empty() { + return Ok(()); + } + + let mut error_message = vec![]; + error_message.push( + "The following modules in package dependencies set a non-zero self-address:".into(), + ); + error_message.extend(errors); + error_message.push( + "If these packages really are unpublished, their self-addresses should be set \ + to \"0x0\" in the [addresses] section of the manifest when publishing. If they \ + are already published, ensure they specify the address in the `published-at` of \ + their Move.toml manifest." + .into(), + ); + + Err(IotaError::ModulePublishFailure { + error: error_message.join("\n"), + }) + } + + pub fn published_dependency_ids(&self) -> Vec { + self.dependency_ids.published.values().cloned().collect() + } +} + +impl Default for BuildConfig { + fn default() -> Self { + let config = MoveBuildConfig { + default_flavor: Some(move_compiler::editions::Flavor::Iota), + ..MoveBuildConfig::default() + }; + BuildConfig { + config, + run_bytecode_verifier: true, + print_diags_to_stderr: false, + } + } +} + +impl GetModule for CompiledPackage { + type Error = anyhow::Error; + // TODO: return ref here for better efficiency? Borrow checker + + // all_modules_map() make it hard to do this + type Item = CompiledModule; + + fn get_module_by_id(&self, id: &ModuleId) -> Result, Self::Error> { + Ok(self.package.all_modules_map().get_module(id).ok().cloned()) + } +} + +pub const PUBLISHED_AT_MANIFEST_FIELD: &str = "published-at"; + +pub struct IotaPackageHooks; + +impl PackageHooks for IotaPackageHooks { + fn custom_package_info_fields(&self) -> Vec { + vec![ + PUBLISHED_AT_MANIFEST_FIELD.to_string(), + // TODO: remove this once version fields are removed from all manifests + "version".to_string(), + ] + } + + fn custom_dependency_key(&self) -> Option { + None + } + + fn resolve_custom_dependency( + &self, + _dep_name: move_symbol_pool::Symbol, + _info: &CustomDepInfo, + ) -> anyhow::Result<()> { + Ok(()) + } + + fn custom_resolve_pkg_id( + &self, + manifest: &SourceManifest, + ) -> anyhow::Result { + if manifest.package.edition == Some(Edition::DEVELOPMENT) { + return Err(Edition::DEVELOPMENT.unknown_edition_error()); + } + Ok(manifest.package.name) + } + + fn resolve_version(&self, _: &SourceManifest) -> anyhow::Result> { + Ok(None) + } +} + +#[derive(Debug, Clone)] +pub struct PackageDependencies { + /// Set of published dependencies (name and address). + pub published: BTreeMap, + /// Set of unpublished dependencies (name). + pub unpublished: BTreeSet, + /// Set of dependencies with invalid `published-at` addresses. + pub invalid: BTreeMap, +} + +#[derive(Debug, Clone)] +pub enum PublishedAtError { + Invalid(String), + NotPresent, +} + +/// Partition packages in `resolution_graph` into one of four groups: +/// - The ID that the package itself is published at (if it is published) +/// - The IDs of dependencies that have been published +/// - The names of packages that have not been published on chain. +/// - The names of packages that have a `published-at` field that isn't filled +/// with a valid address. +pub fn gather_published_ids( + resolution_graph: &ResolvedGraph, +) -> (Result, PackageDependencies) { + let root = resolution_graph.root_package(); + + let mut published = BTreeMap::new(); + let mut unpublished = BTreeSet::new(); + let mut invalid = BTreeMap::new(); + let mut published_at = Err(PublishedAtError::NotPresent); + + for (name, package) in &resolution_graph.package_table { + let property = published_at_property(package); + if name == &root { + // Separate out the root package as a special case + published_at = property; + continue; + } + + match property { + Ok(id) => { + published.insert(*name, id); + } + Err(PublishedAtError::NotPresent) => { + unpublished.insert(*name); + } + Err(PublishedAtError::Invalid(value)) => { + invalid.insert(*name, value); + } + }; + } + + ( + published_at, + PackageDependencies { + published, + unpublished, + invalid, + }, + ) +} + +pub fn published_at_property(package: &Package) -> Result { + let Some(value) = package + .source_package + .package + .custom_properties + .get(&Symbol::from(PUBLISHED_AT_MANIFEST_FIELD)) + else { + return Err(PublishedAtError::NotPresent); + }; + + ObjectID::from_str(value.as_str()).map_err(|_| PublishedAtError::Invalid(value.to_owned())) +} + +pub fn check_unpublished_dependencies(unpublished: &BTreeSet) -> Result<(), IotaError> { + if unpublished.is_empty() { + return Ok(()); + }; + + let mut error_messages = unpublished + .iter() + .map(|name| { + format!( + "Package dependency \"{name}\" does not specify a published address \ + (the Move.toml manifest for \"{name}\" does not contain a published-at field).", + ) + }) + .collect::>(); + + error_messages.push( + "If this is intentional, you may use the --with-unpublished-dependencies flag to \ + continue publishing these dependencies as part of your package (they won't be \ + linked against existing packages on-chain)." + .into(), + ); + + Err(IotaError::ModulePublishFailure { + error: error_messages.join("\n"), + }) +} + +pub fn check_invalid_dependencies(invalid: &BTreeMap) -> Result<(), IotaError> { + if invalid.is_empty() { + return Ok(()); + } + + let error_messages = invalid + .iter() + .map(|(name, value)| { + format!( + "Package dependency \"{name}\" does not specify a valid published \ + address: could not parse value \"{value}\" for published-at field." + ) + }) + .collect::>(); + + Err(IotaError::ModulePublishFailure { + error: error_messages.join("\n"), + }) +} diff --git a/crates/sui-move-build/src/unit_tests/build_tests.rs b/crates/iota-move-build/src/unit_tests/build_tests.rs similarity index 85% rename from crates/sui-move-build/src/unit_tests/build_tests.rs rename to crates/iota-move-build/src/unit_tests/build_tests.rs index c287ca3f760..16c48c2bfc4 100644 --- a/crates/sui-move-build/src/unit_tests/build_tests.rs +++ b/crates/iota-move-build/src/unit_tests/build_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::Path; @@ -7,15 +8,15 @@ use crate::BuildConfig; #[test] fn generate_struct_layouts() { - // build the Sui framework and generate struct layouts to make sure nothing + // build the Iota framework and generate struct layouts to make sure nothing // crashes let path = Path::new(env!("CARGO_MANIFEST_DIR")) .parent() .unwrap() .to_path_buf() - .join("sui-framework") + .join("iota-framework") .join("packages") - .join("sui-framework"); + .join("iota-framework"); let pkg = BuildConfig::new_for_testing().build(path).unwrap(); let registry = pkg.generate_struct_layouts(); // check for a couple of types that aren't likely to go away diff --git a/crates/sui-move-build/src/unit_tests/data/no_development_mode/Move.toml b/crates/iota-move-build/src/unit_tests/data/no_development_mode/Move.toml similarity index 100% rename from crates/sui-move-build/src/unit_tests/data/no_development_mode/Move.toml rename to crates/iota-move-build/src/unit_tests/data/no_development_mode/Move.toml diff --git a/crates/iota-move/Cargo.toml b/crates/iota-move/Cargo.toml new file mode 100644 index 00000000000..14cf05e4529 --- /dev/null +++ b/crates/iota-move/Cargo.toml @@ -0,0 +1,68 @@ +[package] +name = "iota-move" +version.workspace = true +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +clap.workspace = true +colored.workspace = true +once_cell = { workspace = true, optional = true } +serde_json.workspace = true +serde_yaml.workspace = true +tracing.workspace = true +prometheus.workspace = true +git-version.workspace = true +const-str.workspace = true + +move-binary-format.workspace = true +move-cli.workspace = true +move-compiler.workspace = true +move-disassembler.workspace = true +move-ir-types.workspace = true +move-package.workspace = true +move-prover.workspace = true +move-unit-test.workspace = true +telemetry-subscribers.workspace = true +tokio = { workspace = true, features = ["full"] } + +move-vm-runtime = { path = "../../external-crates/move/crates/move-vm-runtime" } +iota-move-natives = { path = "../../iota-execution/latest/iota-move-natives", package = "iota-move-natives-latest" } + +iota-move-build.workspace = true +iota-protocol-config.workspace = true +iota-types.workspace = true + +[target.'cfg(not(target_env = "msvc"))'.dependencies] +jemalloc-ctl.workspace = true + +[dev-dependencies] +assert_cmd.workspace = true +futures.workspace = true +jsonrpsee.workspace = true +rand.workspace = true +tempfile.workspace = true + +move-package.workspace = true + +mysten-metrics.workspace = true +iota-core.workspace = true +iota-macros.workspace = true +iota-node.workspace = true +iota-simulator.workspace = true + +[package.metadata.cargo-udeps.ignore] +normal = ["jemalloc-ctl"] + +[features] +default = [] +build = [] +coverage = [] +disassemble = [] +prove = [] +unit_test = ["build", "dep:once_cell"] +calibrate = [] +all = ["build", "coverage", "disassemble", "prove", "unit_test", "calibrate"] diff --git a/crates/sui-move/scripts/prover_setup.sh b/crates/iota-move/scripts/prover_setup.sh similarity index 99% rename from crates/sui-move/scripts/prover_setup.sh rename to crates/iota-move/scripts/prover_setup.sh index 27fd0aaf838..97029fad444 100755 --- a/crates/sui-move/scripts/prover_setup.sh +++ b/crates/iota-move/scripts/prover_setup.sh @@ -5,6 +5,9 @@ # Copyright (c) The Move Contributors # SPDX-License-Identifier: Apache-2.0 +# Modifications Copyright (c) 2024 IOTA Stiftung +# SPDX-License-Identifier: Apache-2.0 + # This script draws on the implementation of the dev_setup.sh script in the core Move repository # installing all Move dependencies but restricts installed components to those required by the Move # Prover. diff --git a/crates/iota-move/src/build.rs b/crates/iota-move/src/build.rs new file mode 100644 index 00000000000..28235f1941a --- /dev/null +++ b/crates/iota-move/src/build.rs @@ -0,0 +1,108 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{fs, path::PathBuf}; + +use clap::Parser; +use iota_move_build::{check_invalid_dependencies, check_unpublished_dependencies, BuildConfig}; +use move_cli::base; +use move_package::{source_package::layout::SourcePackageLayout, BuildConfig as MoveBuildConfig}; +use serde_json::json; + +const LAYOUTS_DIR: &str = "layouts"; +const STRUCT_LAYOUTS_FILENAME: &str = "struct_layouts.yaml"; + +#[derive(Parser)] +#[group(id = "iota-move-build")] +pub struct Build { + /// Include the contents of packages in dependencies that haven't been + /// published (only relevant when dumping bytecode as base64) + #[clap(long, global = true)] + pub with_unpublished_dependencies: bool, + /// Whether we are printing in base64. + #[clap(long, global = true)] + pub dump_bytecode_as_base64: bool, + /// If true, generate struct layout schemas for + /// all struct types passed into `entry` functions declared by modules in + /// this package These layout schemas can be consumed by clients (e.g., + /// the TypeScript SDK) to enable serialization/deserialization of + /// transaction arguments and events. + #[clap(long, global = true)] + pub generate_struct_layouts: bool, +} + +impl Build { + pub fn execute( + &self, + path: Option, + build_config: MoveBuildConfig, + ) -> anyhow::Result<()> { + let rerooted_path = base::reroot_path(path.clone())?; + let build_config = resolve_lock_file_path(build_config, path)?; + Self::execute_internal( + rerooted_path, + build_config, + self.with_unpublished_dependencies, + self.dump_bytecode_as_base64, + self.generate_struct_layouts, + ) + } + + pub fn execute_internal( + rerooted_path: PathBuf, + config: MoveBuildConfig, + with_unpublished_deps: bool, + dump_bytecode_as_base64: bool, + generate_struct_layouts: bool, + ) -> anyhow::Result<()> { + let pkg = BuildConfig { + config, + run_bytecode_verifier: true, + print_diags_to_stderr: true, + } + .build(rerooted_path)?; + if dump_bytecode_as_base64 { + check_invalid_dependencies(&pkg.dependency_ids.invalid)?; + if !with_unpublished_deps { + check_unpublished_dependencies(&pkg.dependency_ids.unpublished)?; + } + + let package_dependencies = pkg.get_package_dependencies_hex(); + println!( + "{}", + json!({ + "modules": pkg.get_package_base64(with_unpublished_deps), + "dependencies": json!(package_dependencies), + "digest": pkg.get_package_digest(with_unpublished_deps), + }) + ) + } + + if generate_struct_layouts { + let layout_str = serde_yaml::to_string(&pkg.generate_struct_layouts()).unwrap(); + // store under /build//layouts/struct_layouts.yaml + let mut layout_filename = pkg.path; + layout_filename.push("build"); + layout_filename.push(pkg.package.compiled_package_info.package_name.as_str()); + layout_filename.push(LAYOUTS_DIR); + layout_filename.push(STRUCT_LAYOUTS_FILENAME); + fs::write(layout_filename, layout_str)? + } + + Ok(()) + } +} + +/// Resolve Move.lock file path in package directory (where Move.toml is). +pub fn resolve_lock_file_path( + mut build_config: MoveBuildConfig, + package_path: Option, +) -> Result { + if build_config.lock_file.is_none() { + let package_root = base::reroot_path(package_path)?; + let lock_file_path = package_root.join(SourcePackageLayout::Lock.path()); + build_config.lock_file = Some(lock_file_path); + } + Ok(build_config) +} diff --git a/crates/sui-move/src/coverage.rs b/crates/iota-move/src/coverage.rs similarity index 84% rename from crates/sui-move/src/coverage.rs rename to crates/iota-move/src/coverage.rs index c78b3351e86..c5e43bfa996 100644 --- a/crates/sui-move/src/coverage.rs +++ b/crates/iota-move/src/coverage.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::PathBuf; @@ -8,7 +9,7 @@ use move_cli::base::coverage; use move_package::BuildConfig; #[derive(Parser)] -#[group(id = "sui-move-coverage")] +#[group(id = "iota-move-coverage")] pub struct Coverage { #[clap(flatten)] pub coverage: coverage::Coverage, diff --git a/crates/sui-move/src/disassemble.rs b/crates/iota-move/src/disassemble.rs similarity index 96% rename from crates/sui-move/src/disassemble.rs rename to crates/iota-move/src/disassemble.rs index 89f72eb2bfa..477e15e1ee2 100644 --- a/crates/sui-move/src/disassemble.rs +++ b/crates/iota-move/src/disassemble.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -15,7 +16,7 @@ use move_ir_types::location::Spanned; use move_package::BuildConfig; #[derive(Parser)] -#[group(id = "sui-move-disassemmble")] +#[group(id = "iota-move-disassemmble")] pub struct Disassemble { /// Path to a .mv file to disassemble #[clap(name = "module_path")] diff --git a/crates/iota-move/src/iota-natives.bpl b/crates/iota-move/src/iota-natives.bpl new file mode 100644 index 00000000000..f9825430840 --- /dev/null +++ b/crates/iota-move/src/iota-natives.bpl @@ -0,0 +1,129 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// ================================================================================== +// Native address + + +procedure {:inline 1} $2_address_from_bytes(bytes: Vec (int)) returns (res: int); + +procedure {:inline 1} $2_address_to_u256(addr: int) returns (res: int); + +procedure {:inline 1} $2_address_from_u256(num: int) returns (res: int); + +// ================================================================================== +// Native object + + +procedure {:inline 1} $2_object_delete_impl(id: int); + +procedure {:inline 1} $2_object_record_new_uid(id: int); + +{%- for instance in object_instances %} +{%- set S = "'" ~ instance.suffix ~ "'" -%} +{%- set T = instance.name -%} + +// ---------------------------------------------------------------------------------- +// Native object implementation for object type `{{instance.suffix}}` + +procedure {:inline 1} $2_object_borrow_uid{{S}}(obj: {{T}}) returns (res: $2_object_UID) { + res := $id#{{T}}(obj); +} + +function $2_object_$borrow_uid{{S}}(obj: {{T}}): $2_object_UID { + $id#{{T}}(obj) +} + + +{%- endfor %} + +// ================================================================================== +// Native tx_context + +procedure {:inline 1} $2_tx_context_derive_id(tx_hash: Vec (int), ids_created: int) returns (res: int); + +// ================================================================================== +// Native event + + +{%- for instance in iota_event_instances %} + +{%- set S = "'" ~ instance.suffix ~ "'" -%} +{%- set T = instance.name -%} + +// ---------------------------------------------------------------------------------- +// Native Iota event implementation for object type `{{instance.suffix}}` + +procedure {:inline 1} $2_event_emit{{S}}(event: {{T}}); + +{%- endfor %} + +// ================================================================================== +// Native types + + +{%- for instance in iota_types_instances %} + +{%- set S = "'" ~ instance.suffix ~ "'" -%} +{%- set T = instance.name -%} + +// ---------------------------------------------------------------------------------- +// Native Iota types implementation for object type `{{instance.suffix}}` + +procedure {:inline 1} $2_types_is_one_time_witness{{S}}(_: {{T}}) returns (res: bool); + +{%- endfor %} + +// ================================================================================== +// Native dynamic_field + +procedure {:inline 1} $2_dynamic_field_has_child_object(parent: int, id: int) returns (res: bool); + +{%- for instance in dynamic_field_instances %} + +{%- set S = "'" ~ instance.suffix ~ "'" -%} +{%- set T = instance.name -%} + +// ---------------------------------------------------------------------------------- +// Native dynamic field implementation for object type `{{instance.suffix}}` + +procedure {:inline 1} $2_dynamic_field_hash_type_and_key{{S}}(parent: int, k: {{T}}) returns (res: int); + +procedure {:inline 1} $2_dynamic_field_add_child_object{{S}}(parent: int, child: {{T}}); + +procedure {:inline 1} $2_dynamic_field_borrow_child_object{{S}}(object: $2_object_UID, id: int) returns (res: {{T}}); + +procedure {:inline 1} $2_dynamic_field_borrow_child_object_mut{{S}}(object: $Mutation $2_object_UID, id: int) returns (res: $Mutation ({{T}}), m: $Mutation ($2_object_UID)); + +procedure {:inline 1} $2_dynamic_field_remove_child_object{{S}}(parent: int, id: int) returns (res: {{T}}); + +procedure {:inline 1} $2_dynamic_field_has_child_object_with_ty{{S}}(parent: int, id: int) returns (res: bool); + +{%- endfor %} + +// ================================================================================== +// Native prover + + +{%- for instance in prover_instances %} + +{%- set S = "'" ~ instance.suffix ~ "'" -%} +{%- set T = instance.name -%} + +// ---------------------------------------------------------------------------------- +// Native Iota prover implementation for object type `{{instance.suffix}}` + +function $2_prover_vec_remove{{S}}(v: Vec ({{T}}), elem_idx: int): Vec ({{T}}) { + RemoveAtVec(v, elem_idx) +} + +{%- endfor %} + + +// ================================================================================== +// Reads and writes to dynamic fields (skeletons) + +function GetDynField(o: T, addr: int): V; + +function UpdateDynField(o: T, addr: int, v: V): T; diff --git a/crates/iota-move/src/lib.rs b/crates/iota-move/src/lib.rs new file mode 100644 index 00000000000..259e04a2fbf --- /dev/null +++ b/crates/iota-move/src/lib.rs @@ -0,0 +1,78 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::path::PathBuf; + +use clap::Parser; +use iota_move_build::set_iota_flavor; +#[cfg(feature = "unit_test")] +use move_cli::base::test::UnitTestResult; +use move_package::BuildConfig; + +#[cfg(feature = "build")] +pub mod build; +#[cfg(feature = "coverage")] +pub mod coverage; +#[cfg(feature = "disassemble")] +pub mod disassemble; +pub mod manage_package; +pub mod migrate; +pub mod new; +#[cfg(feature = "unit_test")] +pub mod unit_test; + +#[derive(Parser)] +pub enum Command { + #[cfg(feature = "build")] + Build(build::Build), + #[cfg(feature = "coverage")] + Coverage(coverage::Coverage), + #[cfg(feature = "disassemble")] + Disassemble(disassemble::Disassemble), + ManagePackage(manage_package::ManagePackage), + Migrate(migrate::Migrate), + New(new::New), + #[cfg(feature = "unit_test")] + Test(unit_test::Test), +} +#[derive(Parser)] +pub struct Calib { + #[clap(name = "runs", short = 'r', long = "runs", default_value = "1")] + runs: usize, + #[clap(name = "summarize", short = 's', long = "summarize")] + summarize: bool, +} + +pub fn execute_move_command( + package_path: Option, + mut build_config: BuildConfig, + command: Command, +) -> anyhow::Result<()> { + if let Some(err_msg) = set_iota_flavor(&mut build_config) { + anyhow::bail!(err_msg); + } + match command { + #[cfg(feature = "build")] + Command::Build(c) => c.execute(package_path, build_config), + #[cfg(feature = "coverage")] + Command::Coverage(c) => c.execute(package_path, build_config), + #[cfg(feature = "disassemble")] + Command::Disassemble(c) => c.execute(package_path, build_config), + Command::ManagePackage(c) => c.execute(package_path, build_config), + Command::Migrate(c) => c.execute(package_path, build_config), + Command::New(c) => c.execute(package_path), + + #[cfg(feature = "unit_test")] + Command::Test(c) => { + let result = c.execute(package_path, build_config)?; + + // Return a non-zero exit code if any test failed + if let UnitTestResult::Failure = result { + std::process::exit(1) + } + + Ok(()) + } + } +} diff --git a/crates/iota-move/src/main.rs b/crates/iota-move/src/main.rs new file mode 100644 index 00000000000..1aa142689d3 --- /dev/null +++ b/crates/iota-move/src/main.rs @@ -0,0 +1,88 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::path::PathBuf; + +use clap::*; +use colored::Colorize; +use iota_move::execute_move_command; +use iota_types::exit_main; +use move_package::BuildConfig as MoveBuildConfig; +use tracing::debug; + +const GIT_REVISION: &str = { + if let Some(revision) = option_env!("GIT_REVISION") { + revision + } else { + let version = git_version::git_version!( + args = ["--always", "--dirty", "--exclude", "*"], + fallback = "" + ); + + if version.is_empty() { + panic!("unable to query git revision"); + } + version + } +}; +const VERSION: &str = const_str::concat!(env!("CARGO_PKG_VERSION"), "-", GIT_REVISION); + +#[derive(Parser)] +#[clap( + name = env!("CARGO_BIN_NAME"), + about = "Iota-Move CLI", + rename_all = "kebab-case", + author, + version = VERSION, +)] +struct Args { + /// Path to a package which the command should be run with respect to. + #[clap(long = "path", short = 'p', global = true)] + pub package_path: Option, + /// If true, run the Move bytecode verifier on the bytecode from a + /// successful build + #[clap(long = "path", short = 'p', global = true)] + pub run_bytecode_verifier: bool, + /// If true, print build diagnostics to stderr--no printing if false + #[clap(long = "path", short = 'p', global = true)] + pub print_diags_to_stderr: bool, + /// Package build options + #[clap(flatten)] + pub build_config: MoveBuildConfig, + /// Subcommands. + #[clap(subcommand)] + pub cmd: iota_move::Command, +} + +#[tokio::main] +async fn main() { + #[cfg(windows)] + colored::control::set_virtual_terminal(true).unwrap(); + + let bin_name = env!("CARGO_BIN_NAME"); + let args = Args::parse(); + // let _guard = match args.command { + // IotaCommand::Console { .. } | IotaCommand::Client { .. } => { + // telemetry_subscribers::TelemetryConfig::new() + // .with_log_file(&format!("{bin_name}.log")) + // .with_env() + // .init() + // } + // _ => telemetry_subscribers::TelemetryConfig::new() + // .with_env() + // .init(), + // }; + + let _guard = telemetry_subscribers::TelemetryConfig::new() + .with_log_file(&format!("{bin_name}.log")) + .with_env() + .init(); + debug!("Iota-Move CLI version: {VERSION}"); + + exit_main!(execute_move_command( + args.package_path, + args.build_config, + args.cmd + )); +} diff --git a/crates/sui-move/src/manage_package.rs b/crates/iota-move/src/manage_package.rs similarity index 91% rename from crates/sui-move/src/manage_package.rs rename to crates/iota-move/src/manage_package.rs index 2ac1498bd66..c80eea9aaa1 100644 --- a/crates/sui-move/src/manage_package.rs +++ b/crates/iota-move/src/manage_package.rs @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::PathBuf; use clap::Parser; +use iota_types::base_types::ObjectID; use move_package::BuildConfig; -use sui_types::base_types::ObjectID; /// Record addresses (Object IDs) for where this package is published on chain /// (this command sets variables in Move.lock). #[derive(Parser)] -#[group(id = "sui-move-manage-package")] +#[group(id = "iota-move-manage-package")] pub struct ManagePackage { #[clap(long)] /// The network chain identifer. Use '35834a8a' for mainnet. diff --git a/crates/sui-move/src/migrate.rs b/crates/iota-move/src/migrate.rs similarity index 84% rename from crates/sui-move/src/migrate.rs rename to crates/iota-move/src/migrate.rs index b959e3a12a3..04074fb9fd5 100644 --- a/crates/sui-move/src/migrate.rs +++ b/crates/iota-move/src/migrate.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::PathBuf; @@ -8,7 +9,7 @@ use move_cli::base::migrate; use move_package::BuildConfig as MoveBuildConfig; #[derive(Parser)] -#[group(id = "sui-move-migrate")] +#[group(id = "iota-move-migrate")] pub struct Migrate { #[clap(flatten)] pub migrate: migrate::Migrate, diff --git a/crates/sui-move/src/new.rs b/crates/iota-move/src/new.rs similarity index 84% rename from crates/sui-move/src/new.rs rename to crates/iota-move/src/new.rs index d836387696d..19e68398f5c 100644 --- a/crates/sui-move/src/new.rs +++ b/crates/iota-move/src/new.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -11,14 +12,14 @@ use clap::Parser; use move_cli::base::new; use move_package::source_package::layout::SourcePackageLayout; -const SUI_PKG_NAME: &str = "Sui"; +const IOTA_PKG_NAME: &str = "Iota"; // Use testnet by default. Probably want to add options to make this // configurable later -const SUI_PKG_PATH: &str = "{ git = \"https://github.com/MystenLabs/sui.git\", subdir = \"crates/sui-framework/packages/sui-framework\", rev = \"framework/testnet\" }"; +const IOTA_PKG_PATH: &str = "{ git = \"https://github.com/iotaledger/iota.git\", subdir = \"crates/iota-framework/packages/iota-framework\", rev = \"framework/testnet\" }"; #[derive(Parser)] -#[group(id = "sui-move-new")] +#[group(id = "iota-move-new")] pub struct New { #[clap(flatten)] pub new: new::New, @@ -34,7 +35,7 @@ impl New { self.new.execute( path.clone(), - [(SUI_PKG_NAME, SUI_PKG_PATH)], + [(IOTA_PKG_NAME, IOTA_PKG_PATH)], [(name, "0x0")], "", )?; diff --git a/crates/sui-move/src/unit_test.rs b/crates/iota-move/src/unit_test.rs similarity index 88% rename from crates/sui-move/src/unit_test.rs rename to crates/iota-move/src/unit_test.rs index 4492ac2d92c..026e53dd462 100644 --- a/crates/sui-move/src/unit_test.rs +++ b/crates/iota-move/src/unit_test.rs @@ -1,9 +1,21 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, path::PathBuf, sync::Arc}; use clap::Parser; +use iota_move_build::decorate_warnings; +use iota_move_natives::{object_runtime::ObjectRuntime, NativesCostTable}; +use iota_protocol_config::ProtocolConfig; +use iota_types::{ + base_types::{ObjectID, SequenceNumber}, + error::IotaResult, + gas_model::tables::initial_cost_schedule_for_unit_tests, + metrics::LimitsMetrics, + object::Object, + storage::ChildObjectResolver, +}; use move_cli::base::{ self, test::{self, UnitTestResult}, @@ -12,24 +24,13 @@ use move_package::BuildConfig; use move_unit_test::{extensions::set_extension_hook, UnitTestingConfig}; use move_vm_runtime::native_extensions::NativeContextExtensions; use once_cell::sync::Lazy; -use sui_move_build::decorate_warnings; -use sui_move_natives::{object_runtime::ObjectRuntime, NativesCostTable}; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ - base_types::{ObjectID, SequenceNumber}, - error::SuiResult, - gas_model::tables::initial_cost_schedule_for_unit_tests, - metrics::LimitsMetrics, - object::Object, - storage::ChildObjectResolver, -}; // Move unit tests will halt after executing this many steps. This is a // protection to avoid divergence const MAX_UNIT_TEST_INSTRUCTIONS: u64 = 1_000_000; #[derive(Parser)] -#[group(id = "sui-move-test")] +#[group(id = "iota-move-test")] pub struct Test { #[clap(flatten)] pub test: test::Test, @@ -44,7 +45,7 @@ impl Test { let compute_coverage = self.test.compute_coverage; if !cfg!(debug_assertions) && compute_coverage { return Err(anyhow::anyhow!( - "The --coverage flag is currently supported only in debug builds. Please build the Sui CLI from source in debug mode." + "The --coverage flag is currently supported only in debug builds. Please build the Iota CLI from source in debug mode." )); } // find manifest file directory from a given path or (if missing) from current @@ -68,7 +69,7 @@ impl ChildObjectResolver for DummyChildObjectStore { _parent: &ObjectID, _child: &ObjectID, _child_version_upper_bound: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { Ok(None) } fn get_object_received_at_version( @@ -76,8 +77,8 @@ impl ChildObjectResolver for DummyChildObjectStore { _owner: &ObjectID, _receiving_object_id: &ObjectID, _receive_object_at_version: SequenceNumber, - _epoch_id: sui_types::committee::EpochId, - ) -> SuiResult> { + _epoch_id: iota_types::committee::EpochId, + ) -> IotaResult> { Ok(None) } } @@ -109,7 +110,7 @@ pub fn run_move_unit_tests( report_stacktrace_on_abort: true, ..config }, - sui_move_natives::all_natives(/* silent */ false), + iota_move_natives::all_natives(/* silent */ false), Some(initial_cost_schedule_for_unit_tests()), compute_coverage, &mut std::io::stdout(), diff --git a/crates/iota-network/Cargo.toml b/crates/iota-network/Cargo.toml new file mode 100644 index 00000000000..b51c978f93c --- /dev/null +++ b/crates/iota-network/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "iota-network" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anemo.workspace = true +anemo-tower.workspace = true +governor.workspace = true +serde.workspace = true +tonic.workspace = true +dashmap.workspace = true +tower.workspace = true + +iota-archival.workspace = true +iota-storage.workspace = true +iota-types.workspace = true +iota-config.workspace = true +iota-swarm-config.workspace = true + +arc-swap.workspace = true +bcs.workspace = true +bytes.workspace = true +fastcrypto.workspace = true +fastcrypto-tbls.workspace = true +mysten-network.workspace = true +tokio = { workspace = true, features = ["full"] } +tracing.workspace = true +futures.workspace = true +tap.workspace = true +rand.workspace = true +anyhow.workspace = true +prometheus.workspace = true +mysten-metrics.workspace = true + +[build-dependencies] +anemo-build.workspace = true +tonic-build.workspace = true + +[dev-dependencies] +telemetry-subscribers.workspace = true +tokio = { workspace = true, features = ["test-util"] } +ed25519-consensus.workspace = true +tempfile = "3.3.0" diff --git a/crates/iota-network/README.md b/crates/iota-network/README.md new file mode 100644 index 00000000000..cf869fffaec --- /dev/null +++ b/crates/iota-network/README.md @@ -0,0 +1,11 @@ +# iota-network + +## Changing an RPC service + +The general process for changing an RPC service is as follows: +1. Change the service definition in the `tests/bootstrap.rs` file. +2. Run `cargo test --test bootstrap` to re-run the code generation. + Generated rust files are in the `src/generated` directory. +3. Update any other corresponding logic that would have been affected by + the interface change, e.g. the server implementation of the service or + usages of the generated client. diff --git a/crates/iota-network/build.rs b/crates/iota-network/build.rs new file mode 100644 index 00000000000..500f49e2deb --- /dev/null +++ b/crates/iota-network/build.rs @@ -0,0 +1,190 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + env, + path::{Path, PathBuf}, +}; + +use tonic_build::manual::{Builder, Method, Service}; + +type Result = ::std::result::Result>; + +fn main() -> Result<()> { + let out_dir = if env::var("DUMP_GENERATED_GRPC").is_ok() { + PathBuf::from("") + } else { + PathBuf::from(env::var("OUT_DIR")?) + }; + + let codec_path = "mysten_network::codec::BcsCodec"; + + let validator_service = Service::builder() + .name("Validator") + .package("iota.validator") + .comment("The Validator interface") + .method( + Method::builder() + .name("transaction") + .route_name("Transaction") + .input_type("iota_types::transaction::Transaction") + .output_type("iota_types::messages_grpc::HandleTransactionResponse") + .codec_path(codec_path) + .build(), + ) + .method( + Method::builder() + .name("handle_certificate_v2") + .route_name("CertifiedTransactionV2") + .input_type("iota_types::transaction::CertifiedTransaction") + .output_type("iota_types::messages_grpc::HandleCertificateResponseV2") + .codec_path(codec_path) + .build(), + ) + .method( + Method::builder() + .name("submit_certificate") + .route_name("SubmitCertificate") + .input_type("iota_types::transaction::CertifiedTransaction") + .output_type("iota_types::messages_grpc::SubmitCertificateResponse") + .codec_path(codec_path) + .build(), + ) + .method( + Method::builder() + .name("object_info") + .route_name("ObjectInfo") + .input_type("iota_types::messages_grpc::ObjectInfoRequest") + .output_type("iota_types::messages_grpc::ObjectInfoResponse") + .codec_path(codec_path) + .build(), + ) + .method( + Method::builder() + .name("transaction_info") + .route_name("TransactionInfo") + .input_type("iota_types::messages_grpc::TransactionInfoRequest") + .output_type("iota_types::messages_grpc::TransactionInfoResponse") + .codec_path(codec_path) + .build(), + ) + .method( + Method::builder() + .name("checkpoint") + .route_name("Checkpoint") + .input_type("iota_types::messages_checkpoint::CheckpointRequest") + .output_type("iota_types::messages_checkpoint::CheckpointResponse") + .codec_path(codec_path) + .build(), + ) + .method( + Method::builder() + .name("checkpoint_v2") + .route_name("CheckpointV2") + .input_type("iota_types::messages_checkpoint::CheckpointRequestV2") + .output_type("iota_types::messages_checkpoint::CheckpointResponseV2") + .codec_path(codec_path) + .build(), + ) + .method( + Method::builder() + .name("get_system_state_object") + .route_name("GetSystemStateObject") + .input_type("iota_types::messages_grpc::SystemStateRequest") + .output_type("iota_types::iota_system_state::IotaSystemState") + .codec_path(codec_path) + .build(), + ) + .build(); + + Builder::new() + .out_dir(&out_dir) + .compile(&[validator_service]); + + build_anemo_services(&out_dir); + + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-env-changed=DUMP_GENERATED_GRPC"); + + Ok(()) +} + +fn build_anemo_services(out_dir: &Path) { + let codec_path = "mysten_network::codec::anemo::BcsSnappyCodec"; + + let discovery = anemo_build::manual::Service::builder() + .name("Discovery") + .package("iota") + .method( + anemo_build::manual::Method::builder() + .name("get_known_peers") + .route_name("GetKnownPeers") + .request_type("()") + .response_type("crate::discovery::GetKnownPeersResponse") + .codec_path(codec_path) + .build(), + ) + .build(); + + let state_sync = anemo_build::manual::Service::builder() + .name("StateSync") + .package("iota") + .method( + anemo_build::manual::Method::builder() + .name("push_checkpoint_summary") + .route_name("PushCheckpointSummary") + .request_type("iota_types::messages_checkpoint::CertifiedCheckpointSummary") + .response_type("()") + .codec_path(codec_path) + .build(), + ) + .method( + anemo_build::manual::Method::builder() + .name("get_checkpoint_summary") + .route_name("GetCheckpointSummary") + .request_type("crate::state_sync::GetCheckpointSummaryRequest") + .response_type( + "Option", + ) + .codec_path(codec_path) + .build(), + ) + .method( + anemo_build::manual::Method::builder() + .name("get_checkpoint_contents") + .route_name("GetCheckpointContents") + .request_type("iota_types::messages_checkpoint::CheckpointContentsDigest") + .response_type("Option") + .codec_path(codec_path) + .build(), + ) + .method( + anemo_build::manual::Method::builder() + .name("get_checkpoint_availability") + .route_name("GetCheckpointAvailability") + .request_type("()") + .response_type("crate::state_sync::GetCheckpointAvailabilityResponse") + .codec_path(codec_path) + .build(), + ) + .build(); + + let randomness = anemo_build::manual::Service::builder() + .name("Randomness") + .package("iota") + .method( + anemo_build::manual::Method::builder() + .name("send_signatures") + .route_name("SendSignatures") + .request_type("crate::randomness::SendSignaturesRequest") + .response_type("()") + .codec_path(codec_path) + .build(), + ) + .build(); + + anemo_build::manual::Builder::new() + .out_dir(out_dir) + .compile(&[discovery, state_sync, randomness]); +} diff --git a/crates/iota-network/src/api.rs b/crates/iota-network/src/api.rs new file mode 100644 index 00000000000..c678bc253ec --- /dev/null +++ b/crates/iota-network/src/api.rs @@ -0,0 +1,12 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod validator { + include!(concat!(env!("OUT_DIR"), "/iota.validator.Validator.rs")); +} + +pub use validator::{ + validator_client::ValidatorClient, + validator_server::{Validator, ValidatorServer}, +}; diff --git a/crates/iota-network/src/discovery/builder.rs b/crates/iota-network/src/discovery/builder.rs new file mode 100644 index 00000000000..191d38d4004 --- /dev/null +++ b/crates/iota-network/src/discovery/builder.rs @@ -0,0 +1,176 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::HashMap, + sync::{Arc, RwLock}, +}; + +use anemo::codegen::InboundRequestLayer; +use anemo_tower::rate_limit; +use iota_config::p2p::P2pConfig; +use tap::Pipe; +use tokio::{ + sync::{oneshot, watch}, + task::JoinSet, +}; + +use super::{ + metrics::Metrics, server::Server, Discovery, DiscoveryEventLoop, DiscoveryServer, State, +}; +use crate::discovery::TrustedPeerChangeEvent; + +/// Discovery Service Builder. +pub struct Builder { + config: Option, + metrics: Option, + trusted_peer_change_rx: watch::Receiver, +} + +impl Builder { + #[allow(clippy::new_without_default)] + pub fn new(trusted_peer_change_rx: watch::Receiver) -> Self { + Self { + config: None, + metrics: None, + trusted_peer_change_rx, + } + } + + pub fn config(mut self, config: P2pConfig) -> Self { + self.config = Some(config); + self + } + + pub fn with_metrics(mut self, registry: &prometheus::Registry) -> Self { + self.metrics = Some(Metrics::enabled(registry)); + self + } + + pub fn build(self) -> (UnstartedDiscovery, DiscoveryServer) { + let discovery_config = self + .config + .clone() + .and_then(|config| config.discovery) + .unwrap_or_default(); + let (builder, server) = self.build_internal(); + let mut discovery_server = DiscoveryServer::new(server); + + // Apply rate limits from configuration as needed. + if let Some(limit) = discovery_config.get_known_peers_rate_limit { + discovery_server = discovery_server.add_layer_for_get_known_peers( + InboundRequestLayer::new(rate_limit::RateLimitLayer::new( + governor::Quota::per_second(limit), + rate_limit::WaitMode::Block, + )), + ); + } + (builder, discovery_server) + } + + pub(super) fn build_internal(self) -> (UnstartedDiscovery, Server) { + let Builder { + config, + metrics, + trusted_peer_change_rx, + } = self; + let config = config.unwrap(); + let metrics = metrics.unwrap_or_else(Metrics::disabled); + let (sender, receiver) = oneshot::channel(); + + let handle = Handle { + _shutdown_handle: Arc::new(sender), + }; + + let state = State { + our_info: None, + connected_peers: HashMap::default(), + known_peers: HashMap::default(), + } + .pipe(RwLock::new) + .pipe(Arc::new); + + let server = Server { + state: state.clone(), + }; + + ( + UnstartedDiscovery { + handle, + config, + shutdown_handle: receiver, + state, + trusted_peer_change_rx, + metrics, + }, + server, + ) + } +} + +/// Handle to an unstarted discovery system +pub struct UnstartedDiscovery { + pub(super) handle: Handle, + pub(super) config: P2pConfig, + pub(super) shutdown_handle: oneshot::Receiver<()>, + pub(super) state: Arc>, + pub(super) trusted_peer_change_rx: watch::Receiver, + pub(super) metrics: Metrics, +} + +impl UnstartedDiscovery { + pub(super) fn build(self, network: anemo::Network) -> (DiscoveryEventLoop, Handle) { + let Self { + handle, + config, + shutdown_handle, + state, + trusted_peer_change_rx, + metrics, + } = self; + + let discovery_config = config.discovery.clone().unwrap_or_default(); + let allowlisted_peers = Arc::new( + discovery_config + .allowlisted_peers + .clone() + .into_iter() + .map(|ap| (ap.peer_id, ap.address)) + .chain(config.seed_peers.iter().filter_map(|peer| { + peer.peer_id + .map(|peer_id| (peer_id, Some(peer.address.clone()))) + })) + .collect::>(), + ); + ( + DiscoveryEventLoop { + config, + discovery_config: Arc::new(discovery_config), + allowlisted_peers, + network, + tasks: JoinSet::new(), + pending_dials: Default::default(), + dial_seed_peers_task: None, + shutdown_handle, + state, + trusted_peer_change_rx, + metrics, + }, + handle, + ) + } + + pub fn start(self, network: anemo::Network) -> Handle { + let (event_loop, handle) = self.build(network); + tokio::spawn(event_loop.start()); + + handle + } +} + +/// A Handle to the Discovery subsystem. The Discovery system will be shutdown +/// once its Handle has been dropped. +pub struct Handle { + _shutdown_handle: Arc>, +} diff --git a/crates/iota-network/src/discovery/metrics.rs b/crates/iota-network/src/discovery/metrics.rs new file mode 100644 index 00000000000..e408fbb25b7 --- /dev/null +++ b/crates/iota-network/src/discovery/metrics.rs @@ -0,0 +1,57 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::Arc; + +use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; +use tap::Pipe; + +#[derive(Clone)] +pub(super) struct Metrics(Option>); + +impl std::fmt::Debug for Metrics { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.debug_struct("Metrics").finish() + } +} + +impl Metrics { + pub fn enabled(registry: &Registry) -> Self { + Metrics(Some(Inner::new(registry))) + } + + pub fn disabled() -> Self { + Metrics(None) + } + + pub fn inc_num_peers_with_external_address(&self) { + if let Some(inner) = &self.0 { + inner.num_peers_with_external_address.inc(); + } + } + + pub fn dec_num_peers_with_external_address(&self) { + if let Some(inner) = &self.0 { + inner.num_peers_with_external_address.dec(); + } + } +} + +struct Inner { + num_peers_with_external_address: IntGauge, +} + +impl Inner { + pub fn new(registry: &Registry) -> Arc { + Self { + num_peers_with_external_address: register_int_gauge_with_registry!( + "num_peers_with_external_address", + "Number of peers with an external address configured for discovery", + registry + ) + .unwrap(), + } + .pipe(Arc::new) + } +} diff --git a/crates/iota-network/src/discovery/mod.rs b/crates/iota-network/src/discovery/mod.rs new file mode 100644 index 00000000000..a6a2729f9d1 --- /dev/null +++ b/crates/iota-network/src/discovery/mod.rs @@ -0,0 +1,514 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::HashMap, + sync::{Arc, RwLock}, + time::Duration, +}; + +use anemo::{ + types::{PeerEvent, PeerInfo}, + Network, Peer, PeerId, Request, Response, +}; +use futures::StreamExt; +use iota_config::p2p::{AccessType, DiscoveryConfig, P2pConfig, SeedPeer}; +use iota_types::multiaddr::Multiaddr; +use serde::{Deserialize, Serialize}; +use tap::{Pipe, TapFallible}; +use tokio::{ + sync::{broadcast::error::RecvError, oneshot, watch}, + task::{AbortHandle, JoinSet}, +}; +use tracing::{debug, info, trace}; + +const TIMEOUT: Duration = Duration::from_secs(1); +const ONE_DAY_MILLISECONDS: u64 = 24 * 60 * 60 * 1_000; + +mod generated { + include!(concat!(env!("OUT_DIR"), "/iota.Discovery.rs")); +} +mod builder; +mod metrics; +mod server; +#[cfg(test)] +mod tests; + +pub use builder::{Builder, Handle, UnstartedDiscovery}; +pub use generated::{ + discovery_client::DiscoveryClient, + discovery_server::{Discovery, DiscoveryServer}, +}; +pub use server::GetKnownPeersResponse; + +use self::metrics::Metrics; + +/// The internal discovery state shared between the main event loop and the +/// request handler +struct State { + our_info: Option, + connected_peers: HashMap, + known_peers: HashMap, +} + +/// The information necessary to dial another peer. +/// +/// `NodeInfo` contains all the information that is shared with other nodes via +/// the discovery service to advertise how a node can be reached. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +pub struct NodeInfo { + pub peer_id: PeerId, + pub addresses: Vec, + + /// Creation time. + /// + /// This is used to determine which of two NodeInfo's from the same PeerId + /// should be retained. + pub timestamp_ms: u64, + + /// See docstring for `AccessType`. + pub access_type: AccessType, +} + +#[derive(Clone, Debug, Default)] +pub struct TrustedPeerChangeEvent { + pub new_peers: Vec, +} + +struct DiscoveryEventLoop { + config: P2pConfig, + discovery_config: Arc, + allowlisted_peers: Arc>>, + network: Network, + tasks: JoinSet<()>, + pending_dials: HashMap, + dial_seed_peers_task: Option, + shutdown_handle: oneshot::Receiver<()>, + state: Arc>, + trusted_peer_change_rx: watch::Receiver, + metrics: Metrics, +} + +impl DiscoveryEventLoop { + pub async fn start(mut self) { + info!("Discovery started"); + + self.construct_our_info(); + self.configure_preferred_peers(); + + let mut interval = tokio::time::interval(self.discovery_config.interval_period()); + let mut peer_events = { + let (subscriber, _peers) = self.network.subscribe().unwrap(); + subscriber + }; + + loop { + tokio::select! { + now = interval.tick() => { + let now_unix = now_unix(); + self.handle_tick(now.into_std(), now_unix); + } + peer_event = peer_events.recv() => { + self.handle_peer_event(peer_event); + }, + Ok(()) = self.trusted_peer_change_rx.changed() => { + let event: TrustedPeerChangeEvent = self.trusted_peer_change_rx.borrow_and_update().clone(); + self.handle_trusted_peer_change_event(event); + } + Some(task_result) = self.tasks.join_next() => { + match task_result { + Ok(()) => {}, + Err(e) => { + if e.is_cancelled() { + // avoid crashing on ungraceful shutdown + } else if e.is_panic() { + // propagate panics. + std::panic::resume_unwind(e.into_panic()); + } else { + panic!("task failed: {e}"); + } + }, + }; + }, + // Once the shutdown notification resolves we can terminate the event loop + _ = &mut self.shutdown_handle => { + break; + } + } + } + + info!("Discovery ended"); + } + + fn construct_our_info(&mut self) { + if self.state.read().unwrap().our_info.is_some() { + return; + } + + let address = self + .config + .external_address + .clone() + .and_then(|addr| addr.to_anemo_address().ok().map(|_| addr)) + .into_iter() + .collect(); + let our_info = NodeInfo { + peer_id: self.network.peer_id(), + addresses: address, + timestamp_ms: now_unix(), + access_type: self.discovery_config.access_type(), + }; + + self.state.write().unwrap().our_info = Some(our_info); + } + + fn configure_preferred_peers(&mut self) { + for (peer_id, address) in self + .discovery_config + .allowlisted_peers + .iter() + .map(|sp| (sp.peer_id, sp.address.clone())) + .chain(self.config.seed_peers.iter().filter_map(|ap| { + ap.peer_id + .map(|peer_id| (peer_id, Some(ap.address.clone()))) + })) + { + let anemo_address = if let Some(address) = address { + let Ok(address) = address.to_anemo_address() else { + debug!(p2p_address=?address, "Can't convert p2p address to anemo address"); + continue; + }; + Some(address) + } else { + None + }; + + // TODO: once we have `PeerAffinity::Allowlisted` we should update allowlisted + // peers' affinity. + let peer_info = anemo::types::PeerInfo { + peer_id, + affinity: anemo::types::PeerAffinity::High, + address: anemo_address.into_iter().collect(), + }; + self.network.known_peers().insert(peer_info); + } + } + + fn update_our_info_timestamp(&mut self, now_unix: u64) { + if let Some(our_info) = &mut self.state.write().unwrap().our_info { + our_info.timestamp_ms = now_unix; + } + } + + // TODO: we don't boot out old committee member yets, however we may want to do + // this in the future along with other network management work. + fn handle_trusted_peer_change_event( + &mut self, + trusted_peer_change_event: TrustedPeerChangeEvent, + ) { + for peer_info in trusted_peer_change_event.new_peers { + debug!(?peer_info, "Add committee member as preferred peer."); + self.network.known_peers().insert(peer_info); + } + } + + fn handle_peer_event(&mut self, peer_event: Result) { + match peer_event { + Ok(PeerEvent::NewPeer(peer_id)) => { + if let Some(peer) = self.network.peer(peer_id) { + self.state + .write() + .unwrap() + .connected_peers + .insert(peer_id, ()); + + // Query the new node for any peers + self.tasks.spawn(query_peer_for_their_known_peers( + peer, + self.state.clone(), + self.metrics.clone(), + self.allowlisted_peers.clone(), + )); + } + } + Ok(PeerEvent::LostPeer(peer_id, _)) => { + self.state.write().unwrap().connected_peers.remove(&peer_id); + } + + Err(RecvError::Closed) => { + panic!("PeerEvent channel shouldn't be able to be closed"); + } + + Err(RecvError::Lagged(_)) => { + trace!("State-Sync fell behind processing PeerEvents"); + } + } + } + + fn handle_tick(&mut self, _now: std::time::Instant, now_unix: u64) { + self.update_our_info_timestamp(now_unix); + + self.tasks + .spawn(query_connected_peers_for_their_known_peers( + self.network.clone(), + self.discovery_config.clone(), + self.state.clone(), + self.metrics.clone(), + self.allowlisted_peers.clone(), + )); + + // Cull old peers older than a day + self.state + .write() + .unwrap() + .known_peers + .retain(|_k, v| now_unix.saturating_sub(v.timestamp_ms) < ONE_DAY_MILLISECONDS); + + // Clean out the pending_dials + self.pending_dials.retain(|_k, v| !v.is_finished()); + if let Some(abort_handle) = &self.dial_seed_peers_task { + if abort_handle.is_finished() { + self.dial_seed_peers_task = None; + } + } + + // Spawn some dials + let state = self.state.read().unwrap(); + let eligible = state + .known_peers + .clone() + .into_iter() + .filter(|(peer_id, info)| { + peer_id != &self.network.peer_id() && + !info.addresses.is_empty() // Peer has addresses we can dial + && !state.connected_peers.contains_key(peer_id) // We're not already connected + && !self.pending_dials.contains_key(peer_id) // There is no pending dial to this node + }) + .collect::>(); + + // No need to connect to any more peers if we're already connected to a bunch + let number_of_connections = state.connected_peers.len(); + let number_to_dial = std::cmp::min( + eligible.len(), + self.discovery_config + .target_concurrent_connections() + .saturating_sub(number_of_connections), + ); + + // randomize the order + for (peer_id, info) in rand::seq::SliceRandom::choose_multiple( + eligible.as_slice(), + &mut rand::thread_rng(), + number_to_dial, + ) { + let abort_handle = self.tasks.spawn(try_to_connect_to_peer( + self.network.clone(), + info.to_owned(), + )); + self.pending_dials.insert(*peer_id, abort_handle); + } + + // If we aren't connected to anything and we aren't presently trying to connect + // to anyone we need to try the seed peers + if self.dial_seed_peers_task.is_none() + && state.connected_peers.is_empty() + && self.pending_dials.is_empty() + && !self.config.seed_peers.is_empty() + { + let abort_handle = self.tasks.spawn(try_to_connect_to_seed_peers( + self.network.clone(), + self.discovery_config.clone(), + self.config.seed_peers.clone(), + )); + + self.dial_seed_peers_task = Some(abort_handle); + } + } +} + +async fn try_to_connect_to_peer(network: Network, info: NodeInfo) { + for multiaddr in &info.addresses { + if let Ok(address) = multiaddr.to_anemo_address() { + // Ignore the result and just log the error if there is one + if network + .connect_with_peer_id(address, info.peer_id) + .await + .tap_err(|e| { + debug!( + "error dialing {} at address '{}': {e}", + info.peer_id.short_display(4), + multiaddr + ) + }) + .is_ok() + { + return; + } + } + } +} + +async fn try_to_connect_to_seed_peers( + network: Network, + config: Arc, + seed_peers: Vec, +) { + let network = &network; + + futures::stream::iter(seed_peers.into_iter().filter_map(|seed| { + seed.address + .to_anemo_address() + .ok() + .map(|address| (seed, address)) + })) + .for_each_concurrent( + config.target_concurrent_connections(), + |(seed, address)| async move { + // Ignore the result and just log the error if there is one + let _ = if let Some(peer_id) = seed.peer_id { + network.connect_with_peer_id(address, peer_id).await + } else { + network.connect(address).await + } + .tap_err(|e| debug!("error dialing multiaddr '{}': {e}", seed.address)); + }, + ) + .await; +} + +async fn query_peer_for_their_known_peers( + peer: Peer, + state: Arc>, + metrics: Metrics, + allowlisted_peers: Arc>>, +) { + let mut client = DiscoveryClient::new(peer); + + let request = Request::new(()).with_timeout(TIMEOUT); + if let Some(found_peers) = client + .get_known_peers(request) + .await + .ok() + .map(Response::into_inner) + .map( + |GetKnownPeersResponse { + own_info, + mut known_peers, + }| { + if !own_info.addresses.is_empty() { + known_peers.push(own_info) + } + known_peers + }, + ) + { + update_known_peers(state, metrics, found_peers, allowlisted_peers); + } +} + +async fn query_connected_peers_for_their_known_peers( + network: Network, + config: Arc, + state: Arc>, + metrics: Metrics, + allowlisted_peers: Arc>>, +) { + use rand::seq::IteratorRandom; + + let peers_to_query = network + .peers() + .into_iter() + .flat_map(|id| network.peer(id)) + .choose_multiple(&mut rand::thread_rng(), config.peers_to_query()); + + let found_peers = peers_to_query + .into_iter() + .map(DiscoveryClient::new) + .map(|mut client| async move { + let request = Request::new(()).with_timeout(TIMEOUT); + client + .get_known_peers(request) + .await + .ok() + .map(Response::into_inner) + .map( + |GetKnownPeersResponse { + own_info, + mut known_peers, + }| { + known_peers.push(own_info); + known_peers + }, + ) + }) + .pipe(futures::stream::iter) + .buffer_unordered(config.peers_to_query()) + .filter_map(std::future::ready) + .flat_map(futures::stream::iter) + .collect::>() + .await; + + update_known_peers(state, metrics, found_peers, allowlisted_peers); +} + +fn update_known_peers( + state: Arc>, + metrics: Metrics, + found_peers: Vec, + allowlisted_peers: Arc>>, +) { + use std::collections::hash_map::Entry; + + let now_unix = now_unix(); + let our_peer_id = state.read().unwrap().our_info.clone().unwrap().peer_id; + let known_peers = &mut state.write().unwrap().known_peers; + for peer in found_peers { + // Skip peers whose timestamp is too far in the future from our clock + // or that are too old + if peer.timestamp_ms > now_unix.saturating_add(30 * 1_000) // 30 seconds + || now_unix.saturating_sub(peer.timestamp_ms) > ONE_DAY_MILLISECONDS + { + continue; + } + + if peer.peer_id == our_peer_id { + continue; + } + + // If Peer is Private, and not in our allowlist, skip it. + if peer.access_type == AccessType::Private && !allowlisted_peers.contains_key(&peer.peer_id) + { + continue; + } + + match known_peers.entry(peer.peer_id) { + Entry::Occupied(mut o) => { + if peer.timestamp_ms > o.get().timestamp_ms { + if o.get().addresses.is_empty() && !peer.addresses.is_empty() { + metrics.inc_num_peers_with_external_address(); + } + if !o.get().addresses.is_empty() && peer.addresses.is_empty() { + metrics.dec_num_peers_with_external_address(); + } + o.insert(peer); + } + } + Entry::Vacant(v) => { + if !peer.addresses.is_empty() { + metrics.inc_num_peers_with_external_address(); + } + v.insert(peer); + } + } + } +} + +fn now_unix() -> u64 { + use std::time::{SystemTime, UNIX_EPOCH}; + + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() as u64 +} diff --git a/crates/iota-network/src/discovery/server.rs b/crates/iota-network/src/discovery/server.rs new file mode 100644 index 00000000000..3b3cfd988bc --- /dev/null +++ b/crates/iota-network/src/discovery/server.rs @@ -0,0 +1,40 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::{Arc, RwLock}; + +use anemo::{Request, Response}; +use serde::{Deserialize, Serialize}; + +use super::{Discovery, NodeInfo, State}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct GetKnownPeersResponse { + pub own_info: NodeInfo, + pub known_peers: Vec, +} + +pub(super) struct Server { + pub(super) state: Arc>, +} + +#[anemo::async_trait] +impl Discovery for Server { + async fn get_known_peers( + &self, + _request: Request<()>, + ) -> Result, anemo::rpc::Status> { + let state = self.state.read().unwrap(); + let own_info = state + .our_info + .clone() + .ok_or_else(|| anemo::rpc::Status::internal("own_info has not been initialized yet"))?; + let known_peers = state.known_peers.values().cloned().collect(); + + Ok(Response::new(GetKnownPeersResponse { + own_info, + known_peers, + })) + } +} diff --git a/crates/iota-network/src/discovery/tests.rs b/crates/iota-network/src/discovery/tests.rs new file mode 100644 index 00000000000..3a29ec9a277 --- /dev/null +++ b/crates/iota-network/src/discovery/tests.rs @@ -0,0 +1,722 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashSet; + +use anemo::{types::PeerAffinity, Result}; +use fastcrypto::ed25519::Ed25519PublicKey; +use futures::stream::FuturesUnordered; +use iota_config::p2p::AllowlistedPeer; +use tokio::time::timeout; + +use super::*; +use crate::utils::{build_network, build_network_with_anemo_config}; + +#[tokio::test] +async fn get_known_peers() -> Result<()> { + let config = P2pConfig::default(); + let (UnstartedDiscovery { state, .. }, server) = Builder::new(create_test_channel().1) + .config(config) + .build_internal(); + + // Err when own_info not set + server.get_known_peers(Request::new(())).await.unwrap_err(); + + // Normal response with our_info + let our_info = NodeInfo { + peer_id: PeerId([9; 32]), + addresses: Vec::new(), + timestamp_ms: now_unix(), + access_type: AccessType::Public, + }; + state.write().unwrap().our_info = Some(our_info.clone()); + let response = server + .get_known_peers(Request::new(())) + .await + .unwrap() + .into_inner(); + assert_eq!(response.own_info, our_info); + assert!(response.known_peers.is_empty()); + + // Normal response with some known peers + let other_peer = NodeInfo { + peer_id: PeerId([13; 32]), + addresses: Vec::new(), + timestamp_ms: now_unix(), + access_type: AccessType::Public, + }; + state + .write() + .unwrap() + .known_peers + .insert(other_peer.peer_id, other_peer.clone()); + let response = server + .get_known_peers(Request::new(())) + .await + .unwrap() + .into_inner(); + assert_eq!(response.own_info, our_info); + assert_eq!(response.known_peers, vec![other_peer]); + + Ok(()) +} + +#[tokio::test] +async fn make_connection_to_seed_peer() -> Result<()> { + let config = P2pConfig::default(); + let (builder, server) = Builder::new(create_test_channel().1).config(config).build(); + let network_1 = build_network(|router| router.add_rpc_service(server)); + let (_event_loop_1, _handle_1) = builder.build(network_1.clone()); + + let mut config = P2pConfig::default(); + config.seed_peers.push(SeedPeer { + peer_id: None, + address: format!("/dns/localhost/udp/{}", network_1.local_addr().port()).parse()?, + }); + let (builder, server) = Builder::new(create_test_channel().1).config(config).build(); + let network_2 = build_network(|router| router.add_rpc_service(server)); + let (mut event_loop_2, _handle_2) = builder.build(network_2.clone()); + + let (mut subscriber_1, _) = network_1.subscribe()?; + let (mut subscriber_2, _) = network_2.subscribe()?; + + event_loop_2.handle_tick(std::time::Instant::now(), now_unix()); + + assert_eq!( + subscriber_2.recv().await?, + PeerEvent::NewPeer(network_1.peer_id()) + ); + assert_eq!( + subscriber_1.recv().await?, + PeerEvent::NewPeer(network_2.peer_id()) + ); + + Ok(()) +} + +#[tokio::test] +async fn make_connection_to_seed_peer_with_peer_id() -> Result<()> { + let config = P2pConfig::default(); + let (builder, server) = Builder::new(create_test_channel().1).config(config).build(); + let network_1 = build_network(|router| router.add_rpc_service(server)); + let (_event_loop_1, _handle_1) = builder.build(network_1.clone()); + + let mut config = P2pConfig::default(); + config.seed_peers.push(SeedPeer { + peer_id: Some(network_1.peer_id()), + address: format!("/dns/localhost/udp/{}", network_1.local_addr().port()).parse()?, + }); + let (builder, server) = Builder::new(create_test_channel().1).config(config).build(); + let network_2 = build_network(|router| router.add_rpc_service(server)); + let (mut event_loop_2, _handle_2) = builder.build(network_2.clone()); + + let (mut subscriber_1, _) = network_1.subscribe()?; + let (mut subscriber_2, _) = network_2.subscribe()?; + + event_loop_2.handle_tick(std::time::Instant::now(), now_unix()); + + assert_eq!( + subscriber_2.recv().await?, + PeerEvent::NewPeer(network_1.peer_id()) + ); + assert_eq!( + subscriber_1.recv().await?, + PeerEvent::NewPeer(network_2.peer_id()) + ); + + Ok(()) +} + +#[tokio::test(flavor = "current_thread", start_paused = true)] +async fn three_nodes_can_connect_via_discovery() -> Result<()> { + // Setup the peer that will be the seed for the other two + let config = P2pConfig::default(); + let (builder, server) = Builder::new(create_test_channel().1).config(config).build(); + let network_1 = build_network(|router| router.add_rpc_service(server)); + let (event_loop_1, _handle_1) = builder.build(network_1.clone()); + + let mut config = P2pConfig::default(); + config.seed_peers.push(SeedPeer { + peer_id: Some(network_1.peer_id()), + address: format!("/dns/localhost/udp/{}", network_1.local_addr().port()).parse()?, + }); + let (builder, server) = Builder::new(create_test_channel().1) + .config(config.clone()) + .build(); + let network_2 = build_network(|router| router.add_rpc_service(server)); + let (mut event_loop_2, _handle_2) = builder.build(network_2.clone()); + // Set an external_address address for node 2 so that it can share its address + event_loop_2.config.external_address = + Some(format!("/dns/localhost/udp/{}", network_2.local_addr().port()).parse()?); + + let (builder, server) = Builder::new(create_test_channel().1).config(config).build(); + let network_3 = build_network(|router| router.add_rpc_service(server)); + let (event_loop_3, _handle_3) = builder.build(network_3.clone()); + + let (mut subscriber_1, _) = network_1.subscribe()?; + let (mut subscriber_2, _) = network_2.subscribe()?; + let (mut subscriber_3, _) = network_3.subscribe()?; + + // Start all the event loops + tokio::spawn(event_loop_1.start()); + tokio::spawn(event_loop_2.start()); + tokio::spawn(event_loop_3.start()); + + let peer_id_1 = network_1.peer_id(); + let peer_id_2 = network_2.peer_id(); + let peer_id_3 = network_3.peer_id(); + + // Get two events from node and make sure they're all connected + let peers_1 = [subscriber_1.recv().await?, subscriber_1.recv().await?] + .into_iter() + .map(unwrap_new_peer_event) + .collect::>(); + assert!(peers_1.contains(&peer_id_2)); + assert!(peers_1.contains(&peer_id_3)); + + let peers_2 = [subscriber_2.recv().await?, subscriber_2.recv().await?] + .into_iter() + .map(unwrap_new_peer_event) + .collect::>(); + assert!(peers_2.contains(&peer_id_1)); + assert!(peers_2.contains(&peer_id_3)); + + let peers_3 = [subscriber_3.recv().await?, subscriber_3.recv().await?] + .into_iter() + .map(unwrap_new_peer_event) + .collect::>(); + assert!(peers_3.contains(&peer_id_1)); + assert!(peers_3.contains(&peer_id_2)); + + Ok(()) +} + +#[tokio::test(flavor = "current_thread", start_paused = true)] +async fn peers_are_added_from_reocnfig_channel() -> Result<()> { + let (tx_1, rx_1) = create_test_channel(); + let config = P2pConfig::default(); + let (builder, server) = Builder::new(rx_1).config(config.clone()).build(); + let network_1 = build_network(|router| router.add_rpc_service(server)); + let (event_loop_1, _handle_1) = builder.build(network_1.clone()); + + let (builder, server) = Builder::new(create_test_channel().1) + .config(config.clone()) + .build(); + let network_2 = build_network(|router| router.add_rpc_service(server)); + let (event_loop_2, _handle_2) = builder.build(network_2.clone()); + + let (mut subscriber_1, _) = network_1.subscribe()?; + let (mut subscriber_2, _) = network_2.subscribe()?; + + // Start all the event loops + tokio::spawn(event_loop_1.start()); + tokio::spawn(event_loop_2.start()); + + let peer_id_1 = network_1.peer_id(); + let peer_id_2 = network_2.peer_id(); + + // At this moment peer 1 and peer 2 are not connected. + let mut futures = FuturesUnordered::new(); + futures.push(timeout(Duration::from_secs(2), subscriber_1.recv())); + futures.push(timeout(Duration::from_secs(2), subscriber_2.recv())); + while let Some(result) = futures.next().await { + let _elapse = result.unwrap_err(); + } + + let (mut subscriber_1, _) = network_1.subscribe()?; + let (mut subscriber_2, _) = network_2.subscribe()?; + + // We send peer 1 a new peer info (peer 2) in the channel. + let peer_2_network_pubkey = + Ed25519PublicKey(ed25519_consensus::VerificationKey::try_from(peer_id_2.0).unwrap()); + let peer2_addr: Multiaddr = format!("/dns/localhost/udp/{}", network_2.local_addr().port()) + .parse() + .unwrap(); + tx_1.send(TrustedPeerChangeEvent { + new_peers: vec![PeerInfo { + peer_id: PeerId(peer_2_network_pubkey.0.to_bytes()), + affinity: PeerAffinity::High, + address: vec![peer2_addr.to_anemo_address().unwrap()], + }], + }) + .unwrap(); + + // Now peer 1 and peer 2 are connected. + let new_peer_for_1 = unwrap_new_peer_event(subscriber_1.recv().await.unwrap()); + assert_eq!(new_peer_for_1, peer_id_2); + let new_peer_for_2 = unwrap_new_peer_event(subscriber_2.recv().await.unwrap()); + assert_eq!(new_peer_for_2, peer_id_1); + + Ok(()) +} + +#[tokio::test] +async fn test_access_types() { + // This test case constructs a mesh graph of 11 nodes, with the following + // topology. For allowlisted nodes, `+` means the peer is allowlisted with + // an address, otherwise not. An allowlisted peer with address will be + // proactively connected in anemo network. + // + // + // The topology: + // ------------ 11 (private, seed: 1, + // allowed: 7, 8) / + // ------ 1 (public) ------ + // / \ + // 2 (public, seed: 1, allowed: 7, 8) 3 (private, seed: 1, allowed: + // 4+, 5+) | / \ + // | 4 (private, allowed: 3+, 5, 6) 5 (private, + // allowed: 3, 4+) | \ + // | 6 (private, allowed: 4+) + // 7 (private, allowed: 2+, 8+) + // | + // | + // 8 (private, allowed: 7+, 9+) p.s. 8's max connection is 0 + // | + // | + // 9 (public) + // | + // | + // 10 (private, seed: 9) + + telemetry_subscribers::init_for_testing(); + + let default_discovery_config = DiscoveryConfig { + target_concurrent_connections: Some(100), + interval_period_ms: Some(1000), + ..Default::default() + }; + let default_p2p_config = P2pConfig { + discovery: Some(default_discovery_config.clone()), + ..Default::default() + }; + let default_private_discovery_config = DiscoveryConfig { + target_concurrent_connections: Some(100), + interval_period_ms: Some(1000), + access_type: Some(AccessType::Private), + ..Default::default() + }; + + // None 1, public + let (builder_1, network_1) = set_up_network(default_p2p_config.clone()); + + let mut config = default_p2p_config.clone(); + config.seed_peers.push(SeedPeer { + peer_id: Some(network_1.peer_id()), + address: format!("/dns/localhost/udp/{}", network_1.local_addr().port()) + .parse() + .unwrap(), + }); + + // Node 2, public, seed: Node 1, allowlist: Node 7, Node 8 + let (mut builder_2, network_2) = set_up_network(config.clone()); + + // Node 3, private, seed: Node 1 + let (mut builder_3, network_3) = set_up_network(config.clone()); + + // Node 4, private, allowlist: Node 3, 5, and 6 + let (mut builder_4, network_4) = set_up_network(P2pConfig::default()); + + // Node 5, private, allowlisted: Node 3 and Node 4 + let (builder_5, network_5) = { + let mut private_discovery_config = default_private_discovery_config.clone(); + private_discovery_config.allowlisted_peers = vec![ + // Intitially 5 does not know how to contact 3 or 4. + local_allowlisted_peer(network_3.peer_id(), None), + local_allowlisted_peer(network_4.peer_id(), Some(network_4.local_addr().port())), + ]; + set_up_network(P2pConfig::default().set_discovery_config(private_discovery_config)) + }; + + // Node 6, private, allowlisted: Node 4 + let (builder_6, network_6) = { + let mut private_discovery_config = default_private_discovery_config.clone(); + private_discovery_config.allowlisted_peers = vec![local_allowlisted_peer( + network_4.peer_id(), + Some(network_4.local_addr().port()), + )]; + set_up_network(P2pConfig::default().set_discovery_config(private_discovery_config)) + }; + + // Node 3: Add Node 4 and Node 5 to allowlist + let mut private_discovery_config = default_private_discovery_config.clone(); + private_discovery_config.allowlisted_peers = vec![ + local_allowlisted_peer(network_4.peer_id(), Some(network_4.local_addr().port())), + local_allowlisted_peer(network_5.peer_id(), Some(network_5.local_addr().port())), + ]; + builder_3.config.discovery = Some(private_discovery_config); + + // Node 4: Add Node 3, Node 5, and Node 6 to allowlist + let mut private_discovery_config = default_private_discovery_config.clone(); + private_discovery_config.allowlisted_peers = vec![ + local_allowlisted_peer(network_3.peer_id(), Some(network_3.local_addr().port())), + local_allowlisted_peer(network_5.peer_id(), None), + local_allowlisted_peer(network_6.peer_id(), None), + ]; + builder_4.config.discovery = Some(private_discovery_config); + + // Node 7, private, allowlisted: Node 2, Node 8 + let (mut builder_7, network_7) = set_up_network( + P2pConfig::default().set_discovery_config(default_private_discovery_config.clone()), + ); + + // Node 9, public + let (builder_9, network_9) = set_up_network(default_p2p_config.clone()); + + // Node 8, private, allowlisted: Node 7, Node 9 + let (builder_8, network_8) = { + let mut private_discovery_config = default_private_discovery_config.clone(); + private_discovery_config.allowlisted_peers = vec![ + local_allowlisted_peer(network_7.peer_id(), Some(network_7.local_addr().port())), + local_allowlisted_peer(network_9.peer_id(), Some(network_9.local_addr().port())), + ]; + let mut p2p_config = P2pConfig::default(); + let mut anemo_config = anemo::Config::default(); + anemo_config.max_concurrent_connections = Some(0); + p2p_config.anemo_config = Some(anemo_config); + set_up_network(p2p_config.set_discovery_config(private_discovery_config)) + }; + + // Node 2, Add Node 7 and Node 8 to allowlist + let mut discovery_config = default_discovery_config.clone(); + discovery_config.allowlisted_peers = vec![ + local_allowlisted_peer(network_7.peer_id(), None), + local_allowlisted_peer(network_8.peer_id(), None), + ]; + builder_2.config.discovery = Some(discovery_config); + + // Node 7: Add Node 2, and Node 8 to allowlist + let mut private_discovery_config = default_private_discovery_config.clone(); + private_discovery_config.allowlisted_peers = vec![ + local_allowlisted_peer(network_2.peer_id(), Some(network_2.local_addr().port())), + local_allowlisted_peer(network_8.peer_id(), Some(network_8.local_addr().port())), + ]; + builder_7.config.discovery = Some(private_discovery_config); + + // Node 10, private, seed: 9 + let (builder_10, network_10) = { + let mut p2p_config = default_p2p_config.clone(); + p2p_config.seed_peers.push(SeedPeer { + peer_id: Some(network_9.peer_id()), + address: format!("/dns/localhost/udp/{}", network_9.local_addr().port()) + .parse() + .unwrap(), + }); + p2p_config.discovery = Some(default_private_discovery_config.clone()); + set_up_network(p2p_config.clone()) + }; + + // Node 11, private, seed: 1, allow: 7, 8 + let (builder_11, network_11) = { + let mut p2p_config = default_p2p_config.clone(); + p2p_config.seed_peers.push(SeedPeer { + peer_id: Some(network_1.peer_id()), + address: format!("/dns/localhost/udp/{}", network_1.local_addr().port()) + .parse() + .unwrap(), + }); + let mut private_discovery_config = default_private_discovery_config.clone(); + private_discovery_config.allowlisted_peers = vec![ + local_allowlisted_peer(network_8.peer_id(), None), + local_allowlisted_peer(network_7.peer_id(), None), + ]; + p2p_config.discovery = Some(private_discovery_config); + set_up_network(p2p_config) + }; + + let (event_loop_1, _handle_1, state_1) = start_network(builder_1, network_1.clone()); + let (event_loop_2, _handle_2, state_2) = start_network(builder_2, network_2.clone()); + let (event_loop_3, _handle_3, state_3) = start_network(builder_3, network_3.clone()); + let (event_loop_4, _handle_4, state_4) = start_network(builder_4, network_4.clone()); + let (event_loop_5, _handle_5, state_5) = start_network(builder_5, network_5.clone()); + let (event_loop_6, _handle_6, state_6) = start_network(builder_6, network_6.clone()); + let (event_loop_7, _handle_7, state_7) = start_network(builder_7, network_7.clone()); + let (event_loop_8, _handle_8, state_8) = start_network(builder_8, network_8.clone()); + let (event_loop_9, _handle_9, state_9) = start_network(builder_9, network_9.clone()); + let (event_loop_10, _handle_10, state_10) = start_network(builder_10, network_10.clone()); + let (event_loop_11, _handle_11, state_11) = start_network(builder_11, network_11.clone()); + + // Start all the event loops + tokio::spawn(event_loop_1.start()); + tokio::spawn(event_loop_2.start()); + tokio::spawn(event_loop_3.start()); + tokio::spawn(event_loop_4.start()); + tokio::spawn(event_loop_5.start()); + tokio::spawn(event_loop_6.start()); + tokio::spawn(event_loop_7.start()); + tokio::spawn(event_loop_8.start()); + tokio::spawn(event_loop_9.start()); + tokio::spawn(event_loop_10.start()); + tokio::spawn(event_loop_11.start()); + + let peer_id_1 = network_1.peer_id(); + let peer_id_2 = network_2.peer_id(); + let peer_id_3 = network_3.peer_id(); + let peer_id_4 = network_4.peer_id(); + let peer_id_5 = network_5.peer_id(); + let peer_id_6 = network_6.peer_id(); + let peer_id_7 = network_7.peer_id(); + let peer_id_8 = network_8.peer_id(); + let peer_id_9 = network_9.peer_id(); + let peer_id_10 = network_10.peer_id(); + let peer_id_11 = network_11.peer_id(); + + info!("peer_id_1: {:?}", peer_id_1); + info!("peer_id_2: {:?}", peer_id_2); + info!("peer_id_3: {:?}", peer_id_3); + info!("peer_id_4: {:?}", peer_id_4); + info!("peer_id_5: {:?}", peer_id_5); + info!("peer_id_6: {:?}", peer_id_6); + info!("peer_id_7: {:?}", peer_id_7); + info!("peer_id_8: {:?}", peer_id_8); + info!("peer_id_9: {:?}", peer_id_9); + info!("peer_id_10: {:?}", peer_id_10); + info!("peer_id_11: {:?}", peer_id_11); + + // Let them fully connect + tokio::time::sleep(Duration::from_secs(10)).await; + + // Node 1 is connected to everyone. But it does not "know" private nodes. + assert_peers( + "Node 1", + &network_1, + &state_1, + HashSet::from_iter(vec![]), + HashSet::from_iter(vec![ + peer_id_2, peer_id_3, peer_id_4, peer_id_5, peer_id_6, peer_id_7, peer_id_8, peer_id_9, + peer_id_10, peer_id_11, + ]), + HashSet::from_iter(vec![peer_id_2, peer_id_9]), + HashSet::from_iter(vec![ + peer_id_2, peer_id_3, peer_id_4, peer_id_5, peer_id_6, peer_id_7, peer_id_8, peer_id_9, + peer_id_10, peer_id_11, + ]), + ); + + // Node 1 is connected to everyone. But it does not "know" private nodes except + // the allowlisted ones 7 and 8. + assert_peers( + "Node 2", + &network_2, + &state_2, + HashSet::from_iter(vec![peer_id_1, peer_id_7, peer_id_8]), + HashSet::from_iter(vec![ + peer_id_1, peer_id_3, peer_id_4, peer_id_5, peer_id_6, peer_id_7, peer_id_8, peer_id_9, + peer_id_10, peer_id_11, + ]), + HashSet::from_iter(vec![peer_id_1, peer_id_7, peer_id_8, peer_id_9]), + HashSet::from_iter(vec![ + peer_id_1, peer_id_3, peer_id_4, peer_id_5, peer_id_6, peer_id_7, peer_id_8, peer_id_9, + peer_id_10, peer_id_11, + ]), + ); + + assert_peers( + "Node 3", + &network_3, + &state_3, + HashSet::from_iter(vec![peer_id_1, peer_id_4, peer_id_5]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_4, peer_id_5, peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_4, peer_id_5, peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_4, peer_id_5, peer_id_9]), + ); + + assert_peers( + "Node 4", + &network_4, + &state_4, + HashSet::from_iter(vec![peer_id_3, peer_id_5, peer_id_6]), + HashSet::from_iter(vec![ + peer_id_1, peer_id_2, peer_id_3, peer_id_5, peer_id_6, peer_id_9, + ]), + HashSet::from_iter(vec![ + peer_id_1, peer_id_2, peer_id_3, peer_id_5, peer_id_6, peer_id_9, + ]), + HashSet::from_iter(vec![ + peer_id_1, peer_id_2, peer_id_3, peer_id_5, peer_id_6, peer_id_9, + ]), + ); + + assert_peers( + "Node 5", + &network_5, + &state_5, + HashSet::from_iter(vec![peer_id_3, peer_id_4]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_3, peer_id_4, peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_3, peer_id_4, peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_3, peer_id_4, peer_id_9]), + ); + + assert_peers( + "Node 6", + &network_6, + &state_6, + HashSet::from_iter(vec![peer_id_4]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_4, peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_4, peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_4, peer_id_9]), + ); + + // Node 11 finds Node 7 via Node 2, and invites Node 7 to connect. Node 7 says + // yes. + assert_peers( + "Node 7", + &network_7, + &state_7, + HashSet::from_iter(vec![peer_id_2, peer_id_8]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_8, peer_id_9, peer_id_11]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_8, peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_8, peer_id_9, peer_id_11]), + ); + + // Node 11 finds Node 8 via Node 2, and invites Node 8 to connect. Node 8 said + // No because its `max_concurrent_connections` is 0. + assert_peers( + "Node 8", + &network_8, + &state_8, + HashSet::from_iter(vec![peer_id_7, peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_7, peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_7, peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_7, peer_id_9]), + ); + + assert_peers( + "Node 9", + &network_9, + &state_9, + HashSet::from_iter(vec![]), + HashSet::from_iter(vec![ + peer_id_1, peer_id_2, peer_id_3, peer_id_4, peer_id_5, peer_id_6, peer_id_7, peer_id_8, + peer_id_10, peer_id_11, + ]), + HashSet::from_iter(vec![peer_id_1, peer_id_2]), + HashSet::from_iter(vec![ + peer_id_1, peer_id_2, peer_id_3, peer_id_4, peer_id_5, peer_id_6, peer_id_7, peer_id_8, + peer_id_10, peer_id_11, + ]), + ); + + // Node 10 does not talk to any other private nodes. + assert_peers( + "Node 10", + &network_10, + &state_10, + HashSet::from_iter(vec![peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_9]), + ); + + // 11 allowlists 8 but 8 does not 11, so they can't connect + // although 8 is still in 11's known peer list + assert_peers( + "Node 11", + &network_11, + &state_11, + HashSet::from_iter(vec![peer_id_1, peer_id_7, peer_id_8]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_7, peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_7, peer_id_8, peer_id_9]), + HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_7, peer_id_9]), + ); +} + +fn assert_peers( + self_name: &str, + network: &Network, + state: &Arc>, + expected_network_known_peers: HashSet, + expected_network_connected_peers: HashSet, + expected_discovery_known_peers: HashSet, + expected_discovery_connected_peers: HashSet, +) { + let actual = network + .known_peers() + .get_all() + .iter() + .map(|pi| pi.peer_id) + .collect::>(); + assert_eq!( + actual, expected_network_known_peers, + "{} network known peers mismatch. Expected: {:#?}, actual: {:#?}", + self_name, expected_network_known_peers, actual, + ); + let actual = network.peers().iter().copied().collect::>(); + assert_eq!( + actual, expected_network_connected_peers, + "{} network connected peers mismatch. Expected: {:#?}, actual: {:#?}", + self_name, expected_network_connected_peers, actual, + ); + let actual = state + .read() + .unwrap() + .known_peers + .keys() + .cloned() + .collect::>(); + assert_eq!( + actual, expected_discovery_known_peers, + "{} discovery known peers mismatch. Expected: {:#?}, actual: {:#?}", + self_name, expected_discovery_known_peers, actual, + ); + + let actual = state + .read() + .unwrap() + .connected_peers + .keys() + .cloned() + .collect::>(); + assert_eq!( + actual, expected_discovery_connected_peers, + "{} discovery connected peers mismatch. Expected: {:#?}, actual: {:#?}", + self_name, expected_discovery_connected_peers, actual, + ); +} + +fn unwrap_new_peer_event(event: PeerEvent) -> PeerId { + match event { + PeerEvent::NewPeer(peer_id) => peer_id, + e => panic!("unexpected event: {e:?}"), + } +} + +fn local_allowlisted_peer(peer_id: PeerId, port: Option) -> AllowlistedPeer { + AllowlistedPeer { + peer_id, + address: port.map(|port| format!("/dns/localhost/udp/{}", port).parse().unwrap()), + } +} + +fn set_up_network(p2p_config: P2pConfig) -> (UnstartedDiscovery, Network) { + let anemo_config = p2p_config.anemo_config.clone().unwrap_or_default(); + let (builder, server) = Builder::new(create_test_channel().1) + .config(p2p_config) + .build(); + let network = + build_network_with_anemo_config(|router| router.add_rpc_service(server), anemo_config); + (builder, network) +} + +fn start_network( + builder: UnstartedDiscovery, + network: Network, +) -> (DiscoveryEventLoop, Handle, Arc>) { + let (mut event_loop, handle) = builder.build(network.clone()); + event_loop.config.external_address = Some( + format!("/dns/localhost/udp/{}", network.local_addr().port()) + .parse() + .unwrap(), + ); + let state = event_loop.state.clone(); + (event_loop, handle, state) +} + +fn create_test_channel() -> ( + watch::Sender, + watch::Receiver, +) { + let (tx, rx) = watch::channel(TrustedPeerChangeEvent { new_peers: vec![] }); + (tx, rx) +} diff --git a/crates/iota-network/src/lib.rs b/crates/iota-network/src/lib.rs new file mode 100644 index 00000000000..886cb00221b --- /dev/null +++ b/crates/iota-network/src/lib.rs @@ -0,0 +1,27 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::time::Duration; + +use mysten_network::config::Config; + +pub mod api; +pub mod discovery; +pub mod randomness; +pub mod state_sync; +pub mod utils; + +pub use tonic; + +pub const DEFAULT_CONNECT_TIMEOUT_SEC: Duration = Duration::from_secs(10); +pub const DEFAULT_REQUEST_TIMEOUT_SEC: Duration = Duration::from_secs(30); +pub const DEFAULT_HTTP2_KEEPALIVE_SEC: Duration = Duration::from_secs(5); + +pub fn default_mysten_network_config() -> Config { + let mut net_config = mysten_network::config::Config::new(); + net_config.connect_timeout = Some(DEFAULT_CONNECT_TIMEOUT_SEC); + net_config.request_timeout = Some(DEFAULT_REQUEST_TIMEOUT_SEC); + net_config.http2_keepalive_interval = Some(DEFAULT_HTTP2_KEEPALIVE_SEC); + net_config +} diff --git a/crates/sui-network/src/randomness/auth.rs b/crates/iota-network/src/randomness/auth.rs similarity index 95% rename from crates/sui-network/src/randomness/auth.rs rename to crates/iota-network/src/randomness/auth.rs index 9b008e06a04..fbed9c50563 100644 --- a/crates/sui-network/src/randomness/auth.rs +++ b/crates/iota-network/src/randomness/auth.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashSet, sync::Arc}; diff --git a/crates/iota-network/src/randomness/builder.rs b/crates/iota-network/src/randomness/builder.rs new file mode 100644 index 00000000000..0899c389e62 --- /dev/null +++ b/crates/iota-network/src/randomness/builder.rs @@ -0,0 +1,149 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{BTreeMap, BTreeSet, HashMap, HashSet}, + sync::Arc, +}; + +use anemo::codegen::InboundRequestLayer; +use anemo_tower::{auth::RequireAuthorizationLayer, inflight_limit}; +use iota_config::p2p::RandomnessConfig; +use iota_types::{base_types::AuthorityName, committee::EpochId, crypto::RandomnessRound}; +use tokio::sync::mpsc; + +use super::{ + auth::AllowedPeersUpdatable, metrics::Metrics, server::Server, Handle, RandomnessEventLoop, + RandomnessMessage, RandomnessServer, +}; + +/// Randomness Service Builder. +pub struct Builder { + name: AuthorityName, + config: Option, + metrics: Option, + randomness_tx: mpsc::Sender<(EpochId, RandomnessRound, Vec)>, +} + +impl Builder { + pub fn new( + name: AuthorityName, + randomness_tx: mpsc::Sender<(EpochId, RandomnessRound, Vec)>, + ) -> Self { + Self { + name, + config: None, + metrics: None, + randomness_tx, + } + } + + pub fn config(mut self, config: RandomnessConfig) -> Self { + self.config = Some(config); + self + } + + pub fn with_metrics(mut self, registry: &prometheus::Registry) -> Self { + self.metrics = Some(Metrics::enabled(registry)); + self + } + + pub fn build(self) -> (UnstartedRandomness, anemo::Router) { + let Builder { + name, + config, + metrics, + randomness_tx, + } = self; + let config = config.unwrap_or_default(); + let metrics = metrics.unwrap_or_else(Metrics::disabled); + let (sender, mailbox) = mpsc::channel(config.mailbox_capacity()); + let handle = Handle { + sender: sender.clone(), + }; + let server = Server { + sender: sender.downgrade(), + }; + let randomness_server = RandomnessServer::new(server).add_layer_for_send_signatures( + InboundRequestLayer::new(inflight_limit::InflightLimitLayer::new( + config.send_partial_signatures_inflight_limit(), + inflight_limit::WaitMode::ReturnError, + )), + ); + + let allowed_peers = AllowedPeersUpdatable::new(Arc::new(HashSet::new())); + let router = anemo::Router::new() + .route_layer(RequireAuthorizationLayer::new(allowed_peers.clone())) + .add_rpc_service(randomness_server); + + ( + UnstartedRandomness { + name, + config, + handle, + mailbox, + allowed_peers, + metrics, + randomness_tx, + }, + router, + ) + } +} + +/// Handle to an unstarted randomness network system +pub struct UnstartedRandomness { + pub(super) name: AuthorityName, + pub(super) config: RandomnessConfig, + pub(super) handle: Handle, + pub(super) mailbox: mpsc::Receiver, + pub(super) allowed_peers: AllowedPeersUpdatable, + pub(super) metrics: Metrics, + pub(super) randomness_tx: mpsc::Sender<(EpochId, RandomnessRound, Vec)>, +} + +impl UnstartedRandomness { + pub(super) fn build(self, network: anemo::Network) -> (RandomnessEventLoop, Handle) { + let Self { + name, + config, + handle, + mailbox, + allowed_peers, + metrics, + randomness_tx, + } = self; + ( + RandomnessEventLoop { + name, + config, + mailbox, + network, + allowed_peers, + metrics, + randomness_tx, + + epoch: 0, + authority_info: Arc::new(HashMap::new()), + peer_share_counts: None, + dkg_output: None, + aggregation_threshold: 0, + pending_tasks: BTreeSet::new(), + send_tasks: BTreeMap::new(), + round_request_time: BTreeMap::new(), + received_partial_sigs: BTreeMap::new(), + completed_sigs: BTreeSet::new(), + completed_rounds: BTreeSet::new(), + }, + handle, + ) + } + + pub fn start(self, network: anemo::Network) -> Handle { + let (event_loop, handle) = self.build(network); + tokio::spawn(event_loop.start()); + + handle + } +} diff --git a/crates/iota-network/src/randomness/metrics.rs b/crates/iota-network/src/randomness/metrics.rs new file mode 100644 index 00000000000..9e7172c9944 --- /dev/null +++ b/crates/iota-network/src/randomness/metrics.rs @@ -0,0 +1,111 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::Arc; + +use iota_types::{committee::EpochId, crypto::RandomnessRound}; +use prometheus::{ + register_histogram_with_registry, register_int_gauge_with_registry, Histogram, IntGauge, + Registry, +}; +use tap::Pipe; + +#[derive(Clone)] +pub(super) struct Metrics(Option>); + +impl std::fmt::Debug for Metrics { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.debug_struct("Metrics").finish() + } +} + +impl Metrics { + pub fn enabled(registry: &Registry) -> Self { + Metrics(Some(Inner::new(registry))) + } + + pub fn disabled() -> Self { + Metrics(None) + } + + pub fn set_epoch(&self, epoch: EpochId) { + if let Some(inner) = &self.0 { + inner.current_epoch.set(epoch as i64); + inner.highest_round_generated.set(-1); + } + } + + pub fn record_completed_round(&self, round: RandomnessRound) { + if let Some(inner) = &self.0 { + inner + .highest_round_generated + .set(inner.highest_round_generated.get().max(round.0 as i64)); + } + } + + pub fn set_num_rounds_pending(&self, num_rounds_pending: usize) { + if let Some(inner) = &self.0 { + inner.num_rounds_pending.set(num_rounds_pending as i64); + } + } + + pub fn round_generation_latency_metric(&self) -> Option<&Histogram> { + self.0.as_ref().map(|inner| &inner.round_generation_latency) + } + + pub fn round_observation_latency_metric(&self) -> Option<&Histogram> { + self.0 + .as_ref() + .map(|inner| &inner.round_observation_latency) + } +} + +struct Inner { + current_epoch: IntGauge, + highest_round_generated: IntGauge, + num_rounds_pending: IntGauge, + round_generation_latency: Histogram, + round_observation_latency: Histogram, +} + +const LATENCY_SEC_BUCKETS: &[f64] = &[ + 0.001, 0.005, 0.01, 0.05, 0.1, 0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.2, 1.4, + 1.6, 1.8, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10., + 12.5, 15., 17.5, 20., 25., 30., 60., 90., 120., 180., 300., +]; + +impl Inner { + pub fn new(registry: &Registry) -> Arc { + Self { + current_epoch: register_int_gauge_with_registry!( + "randomness_current_epoch", + "The current epoch for which randomness is being generated (only updated after DKG completes)", + registry + ).unwrap(), + highest_round_generated: register_int_gauge_with_registry!( + "randomness_highest_round_generated", + "The highest round for which randomness has been generated for the current epoch", + registry + ).unwrap(), + num_rounds_pending: register_int_gauge_with_registry!( + "randomness_num_rounds_pending", + "The number of rounds of randomness that are pending generation/observation", + registry + ).unwrap(), + round_generation_latency: register_histogram_with_registry!( + "randomness_round_generation_latency", + "Time taken to generate a single round of randomness, from when the round is requested to when the full signature is aggregated", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ).unwrap(), + round_observation_latency: register_histogram_with_registry!( + "randomness_round_observation_latency", + "Time taken from when partial signatures are sent for a round of randomness to when the value is observed in an executed checkpoint", + LATENCY_SEC_BUCKETS.to_vec(), + registry + ).unwrap(), + } + .pipe(Arc::new) + } +} diff --git a/crates/iota-network/src/randomness/mod.rs b/crates/iota-network/src/randomness/mod.rs new file mode 100644 index 00000000000..a622aeafc25 --- /dev/null +++ b/crates/iota-network/src/randomness/mod.rs @@ -0,0 +1,709 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{btree_map::BTreeMap, BTreeSet, HashMap}, + ops::Bound, + sync::Arc, + time::{self, Duration}, +}; + +use anemo::PeerId; +use anyhow::Result; +use fastcrypto::groups::bls12381; +use fastcrypto_tbls::{dkg, nodes::PartyId, tbls::ThresholdBls, types::ThresholdBls12381MinSig}; +use iota_config::p2p::RandomnessConfig; +use iota_types::{ + base_types::AuthorityName, + committee::EpochId, + crypto::{RandomnessPartialSignature, RandomnessRound, RandomnessSignature}, +}; +use mysten_metrics::spawn_monitored_task; +use mysten_network::anemo_ext::NetworkExt; +use serde::{Deserialize, Serialize}; +use tokio::sync::mpsc; +use tracing::{debug, error, info, instrument, warn}; + +use self::{auth::AllowedPeersUpdatable, metrics::Metrics}; + +mod auth; +mod builder; +mod generated { + include!(concat!(env!("OUT_DIR"), "/iota.Randomness.rs")); +} +mod metrics; +mod server; +#[cfg(test)] +mod tests; + +pub use builder::{Builder, UnstartedRandomness}; +pub use generated::{ + randomness_client::RandomnessClient, + randomness_server::{Randomness, RandomnessServer}, +}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct SendSignaturesRequest { + epoch: EpochId, + round: RandomnessRound, + // BCS-serialized `RandomnessPartialSignature` values. We store raw bytes here to enable + // defenses against too-large messages. + partial_sigs: Vec>, + // TODO: add support for receiving full signature from validators who have already + // reconstructed it. + sig: Option, +} + +/// A handle to the Randomness network subsystem. +/// +/// This handle can be cloned and shared. Once all copies of a Randomness +/// system's Handle have been dropped, the Randomness system will be gracefully +/// shutdown. +#[derive(Clone, Debug)] +pub struct Handle { + sender: mpsc::Sender, +} + +impl Handle { + /// Transitions the Randomness system to a new epoch. Cancels all partial + /// signature sends for prior epochs. + pub fn update_epoch( + &self, + new_epoch: EpochId, + authority_info: HashMap, + dkg_output: dkg::Output, + aggregation_threshold: u16, + ) { + self.sender + .try_send(RandomnessMessage::UpdateEpoch( + new_epoch, + authority_info, + dkg_output, + aggregation_threshold, + )) + .expect("RandomnessEventLoop mailbox should not overflow or be closed") + } + + /// Begins transmitting partial signatures for the given epoch and round + /// until completed. + pub fn send_partial_signatures(&self, epoch: EpochId, round: RandomnessRound) { + self.sender + .try_send(RandomnessMessage::SendPartialSignatures(epoch, round)) + .expect("RandomnessEventLoop mailbox should not overflow or be closed") + } + + /// Records the given round as complete, stopping any partial signature + /// sends. + pub fn complete_round(&self, epoch: EpochId, round: RandomnessRound) { + self.sender + .try_send(RandomnessMessage::CompleteRound(epoch, round)) + .expect("RandomnessEventLoop mailbox should not overflow or be closed") + } + + // For testing. + pub fn new_stub() -> Self { + let (sender, mut receiver) = mpsc::channel(1); + // Keep receiver open until all senders are closed. + tokio::spawn(async move { + loop { + tokio::select! { + m = receiver.recv() => { + if m.is_none() { + break; + } + }, + } + } + }); + Self { sender } + } +} + +#[derive(Clone, Debug)] +enum RandomnessMessage { + UpdateEpoch( + EpochId, + HashMap, + dkg::Output, + u16, // aggregation_threshold + ), + SendPartialSignatures(EpochId, RandomnessRound), + CompleteRound(EpochId, RandomnessRound), + ReceivePartialSignatures(PeerId, EpochId, RandomnessRound, Vec>), +} + +struct RandomnessEventLoop { + name: AuthorityName, + config: RandomnessConfig, + mailbox: mpsc::Receiver, + network: anemo::Network, + allowed_peers: AllowedPeersUpdatable, + metrics: Metrics, + randomness_tx: mpsc::Sender<(EpochId, RandomnessRound, Vec)>, + + epoch: EpochId, + authority_info: Arc>, + peer_share_counts: Option>, + dkg_output: Option>, + aggregation_threshold: u16, + pending_tasks: BTreeSet<(EpochId, RandomnessRound)>, + send_tasks: BTreeMap<(EpochId, RandomnessRound), tokio::task::JoinHandle<()>>, + round_request_time: BTreeMap<(EpochId, RandomnessRound), time::Instant>, + received_partial_sigs: + BTreeMap<(EpochId, RandomnessRound, PeerId), Vec>, + completed_sigs: BTreeSet<(EpochId, RandomnessRound)>, + completed_rounds: BTreeSet<(EpochId, RandomnessRound)>, +} + +impl RandomnessEventLoop { + pub async fn start(mut self) { + info!("Randomness network event loop started"); + + loop { + tokio::select! { + maybe_message = self.mailbox.recv() => { + // Once all handles to our mailbox have been dropped this + // will yield `None` and we can terminate the event loop. + if let Some(message) = maybe_message { + self.handle_message(message); + } else { + break; + } + }, + } + } + + info!("Randomness network event loop ended"); + } + + fn handle_message(&mut self, message: RandomnessMessage) { + match message { + RandomnessMessage::UpdateEpoch( + epoch, + authority_info, + dkg_output, + aggregation_threshold, + ) => { + if let Err(e) = + self.update_epoch(epoch, authority_info, dkg_output, aggregation_threshold) + { + error!("BUG: failed to update epoch in RandomnessEventLoop: {e:?}"); + } + } + RandomnessMessage::SendPartialSignatures(epoch, round) => { + self.send_partial_signatures(epoch, round) + } + RandomnessMessage::CompleteRound(epoch, round) => self.complete_round(epoch, round), + RandomnessMessage::ReceivePartialSignatures(peer_id, epoch, round, sigs) => { + self.receive_partial_signatures(peer_id, epoch, round, sigs) + } + } + } + + #[instrument(level = "debug", skip_all, fields(?new_epoch))] + fn update_epoch( + &mut self, + new_epoch: EpochId, + authority_info: HashMap, + dkg_output: dkg::Output, + aggregation_threshold: u16, + ) -> Result<()> { + assert!(self.dkg_output.is_none() || new_epoch > self.epoch); + + debug!("updating randomness network loop to new epoch"); + + self.peer_share_counts = Some(authority_info.iter().try_fold( + HashMap::new(), + |mut acc, (_name, (peer_id, party_id))| -> Result<_> { + let weight = dkg_output.nodes.node_id_to_node(*party_id)?.weight; + acc.insert(*peer_id, weight); + Ok(acc) + }, + )?); + self.allowed_peers.update(Arc::new( + authority_info + .values() + .map(|(peer_id, _)| *peer_id) + .collect(), + )); + self.epoch = new_epoch; + self.authority_info = Arc::new(authority_info); + self.dkg_output = Some(dkg_output); + self.aggregation_threshold = aggregation_threshold; + for (_, task) in std::mem::take(&mut self.send_tasks) { + task.abort(); + } + self.metrics.set_epoch(new_epoch); + + // Throw away info from old epochs. + self.round_request_time = self + .round_request_time + .split_off(&(new_epoch, RandomnessRound(0))); + self.received_partial_sigs = + self.received_partial_sigs + .split_off(&(new_epoch, RandomnessRound(0), PeerId([0; 32]))); + self.completed_sigs = self + .completed_sigs + .split_off(&(new_epoch, RandomnessRound(0))); + self.completed_rounds = self + .completed_rounds + .split_off(&(new_epoch, RandomnessRound(0))); + + // Start any pending tasks for the new epoch. + self.maybe_start_pending_tasks(); + + // Aggregate any sigs received early from the new epoch. + // (We can't call `maybe_aggregate_partial_signatures` directly while iterating, + // because it takes `&mut self`, so we store in a Vec first.) + let mut aggregate_rounds = BTreeSet::new(); + for (epoch, round, _) in self.received_partial_sigs.keys() { + if *epoch < new_epoch { + error!( + "BUG: received partial sigs for old epoch still present after attempting to remove them" + ); + debug_assert!( + false, + "received partial sigs for old epoch still present after attempting to remove them" + ); + continue; + } + if *epoch > new_epoch { + break; + } + if !self.completed_sigs.contains(&(*epoch, *round)) { + aggregate_rounds.insert(*round); + } + } + for round in aggregate_rounds { + self.maybe_aggregate_partial_signatures(new_epoch, round); + } + + Ok(()) + } + + #[instrument(level = "debug", skip_all, fields(?epoch, ?round))] + fn send_partial_signatures(&mut self, epoch: EpochId, round: RandomnessRound) { + if epoch < self.epoch { + error!( + "BUG: skipping sending partial sigs, we are already up to epoch {}", + self.epoch + ); + debug_assert!( + false, + "skipping sending partial sigs, we are already up to higher epoch" + ); + return; + } + if self.completed_rounds.contains(&(epoch, round)) { + info!("skipping sending partial sigs, we already have completed this round"); + return; + } + + self.pending_tasks.insert((epoch, round)); + self.round_request_time + .insert((epoch, round), time::Instant::now()); + self.maybe_start_pending_tasks(); + } + + #[instrument(level = "debug", skip_all, fields(?epoch, ?round))] + fn complete_round(&mut self, epoch: EpochId, round: RandomnessRound) { + debug!("completing randomness round"); + self.pending_tasks.remove(&(epoch, round)); + self.round_request_time.remove(&(epoch, round)); + self.completed_sigs.insert((epoch, round)); // in case we got it from a checkpoint + self.completed_rounds.insert((epoch, round)); + if let Some(task) = self.send_tasks.remove(&(epoch, round)) { + task.abort(); + self.maybe_start_pending_tasks(); + } else { + self.update_rounds_pending_metric(); + } + } + + #[instrument(level = "debug", skip_all, fields(?peer_id, ?epoch, ?round))] + fn receive_partial_signatures( + &mut self, + peer_id: PeerId, + epoch: EpochId, + round: RandomnessRound, + sig_bytes: Vec>, + ) { + // Big slate of validity checks on received partial signatures. + let peer_share_counts = if let Some(peer_share_counts) = &self.peer_share_counts { + peer_share_counts + } else { + debug!("can't accept partial signatures until DKG has completed"); + return; + }; + if epoch < self.epoch { + debug!( + "skipping received partial sigs, we are already up to epoch {}", + self.epoch + ); + return; + } + if epoch > self.epoch + 1 { + debug!( + "skipping received partial sigs, we are still on epoch {}", + self.epoch + ); + return; + } + if self.completed_sigs.contains(&(epoch, round)) { + debug!("skipping received partial sigs, we already have completed this sig"); + return; + } + let expected_share_count = if let Some(count) = peer_share_counts.get(&peer_id) { + count + } else { + debug!("received partial sigs from unknown peer"); + return; + }; + if sig_bytes.len() != *expected_share_count as usize { + // No need to verify share IDs here as well, since if we receive incorrect IDs, + // we will catch it later when aggregating/verifying the partial + // sigs. + debug!( + "received partial sigs with wrong share count: expected {expected_share_count}, got {}", + sig_bytes.len(), + ); + return; + } + let (last_completed_epoch, last_completed_round) = match self.completed_sigs.last() { + Some((last_completed_epoch, last_completed_round)) => { + (*last_completed_epoch, *last_completed_round) + } + // If we just changed epochs and haven't completed any sigs yet, this will be used. + None => (self.epoch, RandomnessRound(0)), + }; + if epoch == last_completed_epoch + && round.0 + >= last_completed_round + .0 + .saturating_add(self.config.max_partial_sigs_rounds_ahead()) + { + debug!( + "skipping received partial sigs, most recent round we completed was only {last_completed_round}", + ); + return; + } + if epoch > last_completed_epoch && round.0 >= self.config.max_partial_sigs_rounds_ahead() { + debug!( + "skipping received partial sigs, most recent epoch we completed was only {last_completed_epoch}", + ); + return; + } + + // We passed all the checks, deserialize and save the partial sigs. + let partial_sigs = + match sig_bytes + .iter() + .try_fold(Vec::new(), |mut acc, bytes| -> Result<_> { + let sig: RandomnessPartialSignature = bcs::from_bytes(bytes)?; + acc.push(sig); + Ok(acc) + }) { + Ok(partial_sigs) => partial_sigs, + Err(e) => { + debug!("failed to deserialize partial sigs: {e:?}"); + return; + } + }; + debug!("recording received partial signatures"); + self.received_partial_sigs + .insert((epoch, round, peer_id), partial_sigs); + + self.maybe_aggregate_partial_signatures(epoch, round); + } + + #[instrument(level = "debug", skip_all, fields(?epoch, ?round))] + fn maybe_aggregate_partial_signatures(&mut self, epoch: EpochId, round: RandomnessRound) { + if self.completed_sigs.contains(&(epoch, round)) { + error!("BUG: called maybe_aggregate_partial_signatures for already-completed round"); + debug_assert!( + false, + "called maybe_aggregate_partial_signatures for already-completed round" + ); + return; + } + + if !(self.send_tasks.contains_key(&(epoch, round)) + || self.pending_tasks.contains(&(epoch, round))) + { + // We have to wait here, because even if we have enough information from other + // nodes to complete the signature, local shared object versions are + // not set until consensus finishes processing the corresponding + // commit. This function will be called again + // after maybe_start_pending_tasks begins this round locally. + debug!( + "waiting to aggregate randomness partial signatures until local consensus catches up" + ); + return; + } + + let vss_pk = { + let Some(dkg_output) = &self.dkg_output else { + debug!("called maybe_aggregate_partial_signatures before DKG completed"); + return; + }; + &dkg_output.vss_pk + }; + + let sig_bounds = ( + Bound::Included((epoch, round, PeerId([0; 32]))), + Bound::Excluded((epoch, round + 1, PeerId([0; 32]))), + ); + + // If we have enough partial signatures, aggregate them. + let sig_range = self + .received_partial_sigs + .range(sig_bounds) + .flat_map(|(_, sigs)| sigs); + let mut sig = match ThresholdBls12381MinSig::aggregate( + self.aggregation_threshold, + sig_range, + ) { + Ok(sig) => sig, + Err(fastcrypto::error::FastCryptoError::NotEnoughInputs) => return, // wait for more + // input + Err(e) => { + error!("error while aggregating randomness partial signatures: {e:?}"); + return; + } + }; + + // Try to verify the aggregated signature all at once. (Should work in the happy + // path.) + if ThresholdBls12381MinSig::verify(vss_pk.c0(), &round.signature_message(), &sig).is_err() { + // If verifiation fails, some of the inputs must be invalid. We have to go + // through one-by-one to find which. + // TODO: add test for individual sig verification. + self.received_partial_sigs + .retain(|&(e, r, peer_id), partial_sigs| { + if epoch != e || round != r { + return true; + } + if ThresholdBls12381MinSig::partial_verify_batch( + vss_pk, + &round.signature_message(), + partial_sigs.iter(), + &mut rand::thread_rng(), + ) + .is_err() + { + warn!( + "received invalid partial signatures from possibly-Byzantine peer {peer_id}" + ); + // TODO: Ignore future messages from peers sending bad signatures. + return false; + } + true + }); + let sig_range = self + .received_partial_sigs + .range(sig_bounds) + .flat_map(|(_, sigs)| sigs); + sig = match ThresholdBls12381MinSig::aggregate(self.aggregation_threshold, sig_range) { + Ok(sig) => sig, + Err(fastcrypto::error::FastCryptoError::NotEnoughInputs) => return, /* wait for more input */ + Err(e) => { + error!("error while aggregating randomness partial signatures: {e:?}"); + return; + } + }; + if let Err(e) = + ThresholdBls12381MinSig::verify(vss_pk.c0(), &round.signature_message(), &sig) + { + error!( + "error while verifying randomness partial signatures after removing invalid partials: {e:?}" + ); + debug_assert!( + false, + "error while verifying randomness partial signatures after removing invalid partials" + ); + return; + } + } + + debug!("successfully generated randomness full signature"); + self.completed_sigs.insert((epoch, round)); + self.metrics.record_completed_round(round); + if let Some(start_time) = self.round_request_time.get(&(epoch, round)) { + if let Some(metric) = self.metrics.round_generation_latency_metric() { + metric.observe(start_time.elapsed().as_secs_f64()); + } + } + + let keys_to_remove: Vec<_> = self + .received_partial_sigs + .range(sig_bounds) + .map(|(key, _)| *key) + .collect(); + for key in keys_to_remove { + // Have to remove keys one-by-one because BTreeMap does not support + // range-removal. + self.received_partial_sigs.remove(&key); + } + + let bytes = bcs::to_bytes(&sig).expect("signature serialization should not fail"); + self.randomness_tx + .try_send((epoch, round, bytes)) + .expect("RandomnessRoundReceiver mailbox should not overflow or be closed"); + } + + fn maybe_start_pending_tasks(&mut self) { + let dkg_output = if let Some(dkg_output) = &self.dkg_output { + dkg_output + } else { + return; // can't start tasks until first DKG completes + }; + let shares = if let Some(shares) = &dkg_output.shares { + shares + } else { + return; // can't participate in randomness generation without shares + }; + + let mut last_handled_key = None; + let mut rounds_to_aggregate = Vec::new(); + for (epoch, round) in &self.pending_tasks { + if epoch > &self.epoch { + break; // wait for DKG in new epoch + } + + if self.send_tasks.len() >= self.config.max_partial_sigs_concurrent_sends() { + break; // limit concurrent tasks + } + + last_handled_key = Some((*epoch, *round)); + + if epoch < &self.epoch { + info!( + "skipping sending partial sigs for epoch {epoch} round {round}, we are already up to epoch {}", + self.epoch + ); + continue; + } + + if self.completed_rounds.contains(&(*epoch, *round)) { + info!( + "skipping sending partial sigs for epoch {epoch} round {round}, we already have completed this round", + ); + continue; + } + + self.send_tasks.entry((*epoch, *round)).or_insert_with(|| { + let name = self.name; + let network = self.network.clone(); + let retry_interval = self.config.partial_signature_retry_interval(); + let metrics = self.metrics.clone(); + let authority_info = self.authority_info.clone(); + let epoch = *epoch; + let round = *round; + let partial_sigs = ThresholdBls12381MinSig::partial_sign_batch( + shares.iter(), + &round.signature_message(), + ); + + // Record own partial sigs. + if !self.completed_sigs.contains(&(epoch, round)) { + self.received_partial_sigs + .insert((epoch, round, self.network.peer_id()), partial_sigs.clone()); + rounds_to_aggregate.push((epoch, round)); + } + + debug!("sending partial sigs for epoch {epoch}, round {round}"); + spawn_monitored_task!(RandomnessEventLoop::send_partial_signatures_task( + name, + network, + retry_interval, + metrics, + authority_info, + epoch, + round, + partial_sigs + )) + }); + } + + if let Some(last_handled_key) = last_handled_key { + // Remove stuff from the pending_tasks map that we've handled. + let split_point = self + .pending_tasks + .range((Bound::Excluded(last_handled_key), Bound::Unbounded)) + .next() + .cloned(); + if let Some(key) = split_point { + self.pending_tasks = self.pending_tasks.split_off(&key); + } else { + self.pending_tasks.clear(); + } + } + self.update_rounds_pending_metric(); + + // After starting a round, we have generated our own partial sigs. Check if + // that's enough for us to aggregate already. + for (epoch, round) in rounds_to_aggregate { + self.maybe_aggregate_partial_signatures(epoch, round); + } + } + + async fn send_partial_signatures_task( + name: AuthorityName, + network: anemo::Network, + retry_interval: Duration, + metrics: Metrics, + authority_info: Arc>, + epoch: EpochId, + round: RandomnessRound, + partial_sigs: Vec, + ) { + let _metrics_guard = metrics + .round_observation_latency_metric() + .map(|metric| metric.start_timer()); + + let peers: HashMap<_, _> = authority_info + .iter() + .map(|(name, (peer_id, _party_id))| (name, network.waiting_peer(*peer_id))) + .collect(); + let partial_sigs: Vec<_> = partial_sigs + .iter() + .map(|sig| bcs::to_bytes(sig).expect("message serialization should not fail")) + .collect(); + + loop { + let mut requests = Vec::new(); + for (peer_name, peer) in &peers { + if name == **peer_name { + continue; // don't send partial sigs to self + } + let mut client = RandomnessClient::new(peer.clone()); + const SEND_PARTIAL_SIGNATURES_TIMEOUT: Duration = Duration::from_secs(10); + let request = anemo::Request::new(SendSignaturesRequest { + epoch, + round, + partial_sigs: partial_sigs.clone(), + sig: None, + }) + .with_timeout(SEND_PARTIAL_SIGNATURES_TIMEOUT); + requests.push(async move { + let result = client.send_signatures(request).await; + if let Err(e) = result { + debug!("failed to send partial signatures to {peer_name}: {e:?}"); + } + }); + } + + // Process all requests. + futures::future::join_all(requests).await; + + // Keep retrying send to all peers until task is aborted via external message. + tokio::time::sleep(retry_interval).await; + } + } + + fn update_rounds_pending_metric(&self) { + self.metrics + .set_num_rounds_pending(self.pending_tasks.len() + self.send_tasks.len()); + } +} diff --git a/crates/iota-network/src/randomness/server.rs b/crates/iota-network/src/randomness/server.rs new file mode 100644 index 00000000000..1dc6852ba15 --- /dev/null +++ b/crates/iota-network/src/randomness/server.rs @@ -0,0 +1,43 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use anemo::{Request, Response}; +use tokio::sync::mpsc; + +use super::{Randomness, RandomnessMessage, SendSignaturesRequest}; + +pub(super) struct Server { + pub(super) sender: mpsc::WeakSender, +} + +#[anemo::async_trait] +impl Randomness for Server { + async fn send_signatures( + &self, + request: Request, + ) -> Result, anemo::rpc::Status> { + let sender = self + .sender + .upgrade() + .ok_or_else(|| anemo::rpc::Status::internal("shutting down"))?; + let peer_id = *request + .peer_id() + .ok_or_else(|| anemo::rpc::Status::internal("missing peer ID"))?; + let SendSignaturesRequest { + epoch, + round, + partial_sigs, + sig: _, + } = request.into_inner(); + let _ = sender // throw away error, caller will retry + .send(RandomnessMessage::ReceivePartialSignatures( + peer_id, + epoch, + round, + partial_sigs, + )) + .await; + Ok(anemo::Response::new(())) + } +} diff --git a/crates/iota-network/src/randomness/tests.rs b/crates/iota-network/src/randomness/tests.rs new file mode 100644 index 00000000000..8c2adc10e5a --- /dev/null +++ b/crates/iota-network/src/randomness/tests.rs @@ -0,0 +1,237 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use fastcrypto::{groups::bls12381, serde_helpers::ToFromByteArray}; +use fastcrypto_tbls::{mocked_dkg, nodes}; +use iota_swarm_config::test_utils::CommitteeFixture; +use iota_types::{ + base_types::ConciseableName, + committee::Committee, + crypto::{AuthorityPublicKeyBytes, ToFromBytes}, +}; +use tracing::Instrument; + +use crate::{randomness::*, utils}; + +type PkG = bls12381::G2Element; +type EncG = bls12381::G2Element; + +#[tokio::test] +async fn test_multiple_epochs() { + telemetry_subscribers::init_for_testing(); + let committee_fixture = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); + let committee = committee_fixture.committee(); + + let mut randomness_rxs = Vec::new(); + let mut networks: Vec = Vec::new(); + let mut nodes = Vec::new(); + let mut handles = Vec::new(); + let mut authority_info = HashMap::new(); + + for (authority, stake) in committee.members() { + let (tx, rx) = mpsc::channel(3); + randomness_rxs.push(rx); + let (unstarted, router) = Builder::new(*authority, tx).build(); + + let network = utils::build_network(|r| r.merge(router)); + for n in networks.iter() { + network.connect(n.local_addr()).await.unwrap(); + } + networks.push(network.clone()); + + let node = node_from_committee(committee, authority, *stake); + authority_info.insert(*authority, (network.peer_id(), node.id)); + nodes.push(node); + + let (r, handle) = unstarted.build(network); + handles.push((authority, handle)); + + let span = tracing::span!( + tracing::Level::INFO, + "RandomnessEventLoop", + authority = ?authority.concise(), + ); + tokio::spawn(r.start().instrument(span)); + } + info!(?authority_info, "authorities constructed"); + + let nodes = nodes::Nodes::new(nodes).unwrap(); + + // Test first round. + for (authority, handle) in handles.iter() { + let mock_dkg_output = mocked_dkg::generate_mocked_output::( + nodes.clone(), + committee.validity_threshold().try_into().unwrap(), + 0, + committee + .authority_index(authority) + .unwrap() + .try_into() + .unwrap(), + ); + handle.send_partial_signatures(0, RandomnessRound(0)); + handle.update_epoch( + 0, + authority_info.clone(), + mock_dkg_output, + committee.validity_threshold().try_into().unwrap(), + ); + } + for rx in randomness_rxs.iter_mut() { + let (epoch, round, bytes) = rx.recv().await.unwrap(); + assert_eq!(0, epoch); + assert_eq!(0, round.0); + assert_ne!(0, bytes.len()); + } + + // Test a few more rounds. Generation of rounds in epoch 1 should block until + // epoch is updated. + for (_authority, handle) in handles.iter() { + handle.complete_round(0, RandomnessRound(0)); + handle.send_partial_signatures(0, RandomnessRound(1)); + handle.send_partial_signatures(1, RandomnessRound(0)); + handle.send_partial_signatures(1, RandomnessRound(1)); + } + for rx in randomness_rxs.iter_mut() { + let (epoch, round, bytes) = rx.recv().await.unwrap(); + assert_eq!(0, epoch); + assert_eq!(1, round.0); + assert_ne!(0, bytes.len()); + assert!(rx.try_recv().is_err()); // there should not be anything else ready yet + } + for (authority, handle) in handles.iter() { + // update to epoch 1 + let mock_dkg_output = mocked_dkg::generate_mocked_output::( + nodes.clone(), + committee.validity_threshold().try_into().unwrap(), + 1, + committee + .authority_index(authority) + .unwrap() + .try_into() + .unwrap(), + ); + handle.update_epoch( + 1, + authority_info.clone(), + mock_dkg_output, + committee.validity_threshold().try_into().unwrap(), + ); + } + let mut rounds_seen = BTreeSet::new(); // use a set because rounds could be generated out-of-order + for rx in randomness_rxs.iter_mut() { + // now we expect the two rounds we started earlier to be generated + let (epoch, round, bytes) = rx.recv().await.unwrap(); + assert_eq!(1, epoch); + rounds_seen.insert(round); + assert_ne!(0, bytes.len()); + let (epoch, round, bytes) = rx.recv().await.unwrap(); + assert_eq!(1, epoch); + rounds_seen.insert(round); + assert_ne!(0, bytes.len()); + } + assert!(rounds_seen.contains(&RandomnessRound(0))); + assert!(rounds_seen.contains(&RandomnessRound(1))); +} + +#[tokio::test] +async fn test_record_own_partial_sigs() { + telemetry_subscribers::init_for_testing(); + let committee_fixture = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); + let committee = committee_fixture.committee(); + + let mut randomness_rxs = Vec::new(); + let mut networks: Vec = Vec::new(); + let mut nodes = Vec::new(); + let mut handles = Vec::new(); + let mut authority_info = HashMap::new(); + + for (authority, stake) in committee.members() { + let (tx, rx) = mpsc::channel(3); + randomness_rxs.push(rx); + let (unstarted, router) = Builder::new(*authority, tx).build(); + + let network = utils::build_network(|r| r.merge(router)); + for n in networks.iter() { + network.connect(n.local_addr()).await.unwrap(); + } + networks.push(network.clone()); + + let node = node_from_committee(committee, authority, *stake); + authority_info.insert(*authority, (network.peer_id(), node.id)); + nodes.push(node); + + let (r, handle) = unstarted.build(network); + handles.push((authority, handle)); + + let span = tracing::span!( + tracing::Level::INFO, + "RandomnessEventLoop", + authority = ?authority.concise(), + ); + tokio::spawn(r.start().instrument(span)); + } + info!(?authority_info, "authorities constructed"); + + let nodes = nodes::Nodes::new(nodes).unwrap(); + + // Only send partial sigs from authorities 0 and 1. They should still be able to + // reach the threshold to generate full signatures, only if they are + // correctly recording and using their own partial signatures as well. + for (authority, handle) in handles.iter().take(2) { + let mock_dkg_output = mocked_dkg::generate_mocked_output::( + nodes.clone(), + committee.validity_threshold().try_into().unwrap(), + 0, + committee + .authority_index(authority) + .unwrap() + .try_into() + .unwrap(), + ); + handle.send_partial_signatures(0, RandomnessRound(0)); + handle.update_epoch( + 0, + authority_info.clone(), + mock_dkg_output, + committee.validity_threshold().try_into().unwrap(), + ); + } + for (i, rx) in randomness_rxs.iter_mut().enumerate() { + if i < 2 { + let (epoch, round, bytes) = rx.recv().await.unwrap(); + assert_eq!(0, epoch); + assert_eq!(0, round.0); + assert_ne!(0, bytes.len()); + } else { + assert!(rx.try_recv().is_err()); + } + } +} + +fn node_from_committee( + committee: &Committee, + authority: &AuthorityPublicKeyBytes, + stake: u64, +) -> nodes::Node { + let id = committee + .authority_index(authority) + .unwrap() + .try_into() + .unwrap(); + let pk = bls12381::G2Element::from_byte_array( + committee + .public_key(authority) + .expect("lookup of known committee member should succeed") + .as_bytes() + .try_into() + .expect("key length should match"), + ) + .expect("should work to convert BLS key to G2Element"); + fastcrypto_tbls::nodes::Node:: { + id, + pk: fastcrypto_tbls::ecies::PublicKey::from(pk), + weight: stake.try_into().unwrap(), + } +} diff --git a/crates/iota-network/src/state_sync/builder.rs b/crates/iota-network/src/state_sync/builder.rs new file mode 100644 index 00000000000..e156d0c82c2 --- /dev/null +++ b/crates/iota-network/src/state_sync/builder.rs @@ -0,0 +1,233 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::HashMap, + sync::{Arc, RwLock}, + time::Duration, +}; + +use anemo::codegen::InboundRequestLayer; +use anemo_tower::{inflight_limit, rate_limit}; +use iota_archival::reader::ArchiveReaderBalancer; +use iota_config::p2p::StateSyncConfig; +use iota_types::{messages_checkpoint::VerifiedCheckpoint, storage::WriteStore}; +use tap::Pipe; +use tokio::{ + sync::{broadcast, mpsc}, + task::JoinSet, +}; + +use super::{ + metrics::Metrics, + server::{CheckpointContentsDownloadLimitLayer, Server}, + Handle, PeerHeights, StateSync, StateSyncEventLoop, StateSyncMessage, StateSyncServer, +}; + +pub struct Builder { + store: Option, + config: Option, + metrics: Option, + archive_readers: Option, +} + +impl Builder<()> { + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + Self { + store: None, + config: None, + metrics: None, + archive_readers: None, + } + } +} + +impl Builder { + pub fn store(self, store: NewStore) -> Builder { + Builder { + store: Some(store), + config: self.config, + metrics: self.metrics, + archive_readers: self.archive_readers, + } + } + + pub fn config(mut self, config: StateSyncConfig) -> Self { + self.config = Some(config); + self + } + + pub fn with_metrics(mut self, registry: &prometheus::Registry) -> Self { + self.metrics = Some(Metrics::enabled(registry)); + self + } + + pub fn archive_readers(mut self, archive_readers: ArchiveReaderBalancer) -> Self { + self.archive_readers = Some(archive_readers); + self + } +} + +impl Builder +where + S: WriteStore + Clone + Send + Sync + 'static, +{ + pub fn build(self) -> (UnstartedStateSync, StateSyncServer) { + let state_sync_config = self.config.clone().unwrap_or_default(); + let (mut builder, server) = self.build_internal(); + let mut state_sync_server = StateSyncServer::new(server); + + // Apply rate limits from configuration as needed. + if let Some(limit) = state_sync_config.push_checkpoint_summary_rate_limit { + state_sync_server = state_sync_server.add_layer_for_push_checkpoint_summary( + InboundRequestLayer::new(rate_limit::RateLimitLayer::new( + governor::Quota::per_second(limit), + rate_limit::WaitMode::Block, + )), + ); + } + if let Some(limit) = state_sync_config.get_checkpoint_summary_rate_limit { + state_sync_server = state_sync_server.add_layer_for_get_checkpoint_summary( + InboundRequestLayer::new(rate_limit::RateLimitLayer::new( + governor::Quota::per_second(limit), + rate_limit::WaitMode::Block, + )), + ); + } + if let Some(limit) = state_sync_config.get_checkpoint_contents_rate_limit { + state_sync_server = state_sync_server.add_layer_for_get_checkpoint_contents( + InboundRequestLayer::new(rate_limit::RateLimitLayer::new( + governor::Quota::per_second(limit), + rate_limit::WaitMode::Block, + )), + ); + } + if let Some(limit) = state_sync_config.get_checkpoint_contents_inflight_limit { + state_sync_server = state_sync_server.add_layer_for_get_checkpoint_contents( + InboundRequestLayer::new(inflight_limit::InflightLimitLayer::new( + limit, + inflight_limit::WaitMode::ReturnError, + )), + ); + } + if let Some(limit) = state_sync_config.get_checkpoint_contents_per_checkpoint_limit { + let layer = CheckpointContentsDownloadLimitLayer::new(limit); + builder.download_limit_layer = Some(layer.clone()); + state_sync_server = state_sync_server + .add_layer_for_get_checkpoint_contents(InboundRequestLayer::new(layer)); + } + + (builder, state_sync_server) + } + + pub(super) fn build_internal(self) -> (UnstartedStateSync, Server) { + let Builder { + store, + config, + metrics, + archive_readers, + } = self; + let store = store.unwrap(); + let config = config.unwrap_or_default(); + let metrics = metrics.unwrap_or_else(Metrics::disabled); + let archive_readers = archive_readers.unwrap_or_default(); + + let (sender, mailbox) = mpsc::channel(config.mailbox_capacity()); + let (checkpoint_event_sender, _receiver) = + broadcast::channel(config.synced_checkpoint_broadcast_channel_capacity()); + let weak_sender = sender.downgrade(); + let handle = Handle { + sender, + checkpoint_event_sender: checkpoint_event_sender.clone(), + }; + let peer_heights = PeerHeights { + peers: HashMap::new(), + unprocessed_checkpoints: HashMap::new(), + sequence_number_to_digest: HashMap::new(), + wait_interval_when_no_peer_to_sync_content: Duration::from_secs(10), + } + .pipe(RwLock::new) + .pipe(Arc::new); + + let server = Server { + store: store.clone(), + peer_heights: peer_heights.clone(), + sender: weak_sender, + }; + + ( + UnstartedStateSync { + config, + handle, + mailbox, + store, + download_limit_layer: None, + peer_heights, + checkpoint_event_sender, + metrics, + archive_readers, + }, + server, + ) + } +} + +pub struct UnstartedStateSync { + pub(super) config: StateSyncConfig, + pub(super) handle: Handle, + pub(super) mailbox: mpsc::Receiver, + pub(super) download_limit_layer: Option, + pub(super) store: S, + pub(super) peer_heights: Arc>, + pub(super) checkpoint_event_sender: broadcast::Sender, + pub(super) metrics: Metrics, + pub(super) archive_readers: ArchiveReaderBalancer, +} + +impl UnstartedStateSync +where + S: WriteStore + Clone + Send + Sync + 'static, +{ + pub(super) fn build(self, network: anemo::Network) -> (StateSyncEventLoop, Handle) { + let Self { + config, + handle, + mailbox, + download_limit_layer, + store, + peer_heights, + checkpoint_event_sender, + metrics, + archive_readers, + } = self; + + ( + StateSyncEventLoop { + config, + mailbox, + weak_sender: handle.sender.downgrade(), + tasks: JoinSet::new(), + sync_checkpoint_summaries_task: None, + sync_checkpoint_contents_task: None, + download_limit_layer, + store, + peer_heights, + checkpoint_event_sender, + network, + metrics, + archive_readers, + sync_checkpoint_from_archive_task: None, + }, + handle, + ) + } + + pub fn start(self, network: anemo::Network) -> Handle { + let (event_loop, handle) = self.build(network); + tokio::spawn(event_loop.start()); + + handle + } +} diff --git a/crates/iota-network/src/state_sync/metrics.rs b/crates/iota-network/src/state_sync/metrics.rs new file mode 100644 index 00000000000..4e5339fe4cd --- /dev/null +++ b/crates/iota-network/src/state_sync/metrics.rs @@ -0,0 +1,97 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::Arc; + +use iota_types::messages_checkpoint::CheckpointSequenceNumber; +use mysten_metrics::histogram::Histogram; +use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; +use tap::Pipe; + +#[derive(Clone)] +pub(super) struct Metrics(Option>); + +impl std::fmt::Debug for Metrics { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.debug_struct("Metrics").finish() + } +} + +impl Metrics { + pub fn enabled(registry: &Registry) -> Self { + Metrics(Some(Inner::new(registry))) + } + + pub fn disabled() -> Self { + Metrics(None) + } + + pub fn set_highest_known_checkpoint(&self, sequence_number: CheckpointSequenceNumber) { + if let Some(inner) = &self.0 { + inner.highest_known_checkpoint.set(sequence_number as i64); + } + } + + pub fn set_highest_verified_checkpoint(&self, sequence_number: CheckpointSequenceNumber) { + if let Some(inner) = &self.0 { + inner + .highest_verified_checkpoint + .set(sequence_number as i64); + } + } + + pub fn set_highest_synced_checkpoint(&self, sequence_number: CheckpointSequenceNumber) { + if let Some(inner) = &self.0 { + inner.highest_synced_checkpoint.set(sequence_number as i64); + } + } + + pub fn checkpoint_summary_age_metric(&self) -> Option<&Histogram> { + if let Some(inner) = &self.0 { + return Some(&inner.checkpoint_summary_age_ms); + } + None + } +} + +struct Inner { + highest_known_checkpoint: IntGauge, + highest_verified_checkpoint: IntGauge, + highest_synced_checkpoint: IntGauge, + checkpoint_summary_age_ms: Histogram, +} + +impl Inner { + pub fn new(registry: &Registry) -> Arc { + Self { + highest_known_checkpoint: register_int_gauge_with_registry!( + "highest_known_checkpoint", + "Highest known checkpoint", + registry + ) + .unwrap(), + + highest_verified_checkpoint: register_int_gauge_with_registry!( + "highest_verified_checkpoint", + "Highest verified checkpoint", + registry + ) + .unwrap(), + + highest_synced_checkpoint: register_int_gauge_with_registry!( + "highest_synced_checkpoint", + "Highest synced checkpoint", + registry + ) + .unwrap(), + + checkpoint_summary_age_ms: Histogram::new_in_registry( + "checkpoint_summary_age_ms", + "Age of checkpoints summaries when they arrive and are verified.", + registry, + ), + } + .pipe(Arc::new) + } +} diff --git a/crates/iota-network/src/state_sync/mod.rs b/crates/iota-network/src/state_sync/mod.rs new file mode 100644 index 00000000000..b54d29d6152 --- /dev/null +++ b/crates/iota-network/src/state_sync/mod.rs @@ -0,0 +1,1433 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! Peer-to-peer data synchronization of checkpoints. +//! +//! This StateSync module is responsible for the synchronization and +//! dissemination of checkpoints and the transactions, and their effects, +//! contained within. This module is *not* responsible for the execution of the +//! transactions included in a checkpoint, that process is left to another +//! component in the system. +//! +//! # High-level Overview of StateSync +//! +//! StateSync discovers new checkpoints via a few different sources: +//! 1. If this node is a Validator, checkpoints will be produced via consensus +//! at which point consensus can notify state-sync of the new checkpoint via +//! [Handle::send_checkpoint]. +//! 2. A peer notifies us of the latest checkpoint which they have synchronized. +//! State-Sync will also periodically query its peers to discover what their +//! latest checkpoint is. +//! +//! We keep track of two different watermarks: +//! * highest_verified_checkpoint - This is the highest checkpoint header that +//! we've locally verified. This indicated that we have in our persistent +//! store (and have verified) all checkpoint headers up to and including this +//! value. +//! * highest_synced_checkpoint - This is the highest checkpoint that we've +//! fully synchronized, meaning we've downloaded and have in our persistent +//! stores all of the transactions, and their effects (but not the objects), +//! for all checkpoints up to and including this point. This is the watermark +//! that is shared with other peers, either via notification or when they +//! query for our latest checkpoint, and is intended to be used as a guarantee +//! of data availability. +//! +//! The `PeerHeights` struct is used to track the highest_synced_checkpoint +//! watermark for all of our peers. +//! +//! When a new checkpoint is discovered, and we've determined that it is higher +//! than our highest_verified_checkpoint, then StateSync will kick off a task to +//! synchronize and verify all checkpoints between our highest_synced_checkpoint +//! and the newly discovered checkpoint. This process is done by querying one of +//! our peers for the checkpoints we're missing (using the `PeerHeights` struct +//! as a way to intelligently select which peers have the data available for +//! us to query) at which point we will locally verify the signatures on the +//! checkpoint header with the appropriate committee (based on the epoch). As +//! checkpoints are verified, the highest_synced_checkpoint watermark will be +//! ratcheted up. +//! +//! Once we've ratcheted up our highest_verified_checkpoint, and if it is higher +//! than highest_synced_checkpoint, StateSync will then kick off a task to +//! synchronize the contents of all of the checkpoints from +//! highest_synced_checkpoint..=highest_verified_checkpoint. After the +//! contents of each checkpoint is fully downloaded, StateSync will update our +//! highest_synced_checkpoint watermark and send out a notification on a +//! broadcast channel indicating that a new checkpoint has been fully +//! downloaded. Notifications on this broadcast channel will always be made in +//! order. StateSync will also send out a notification to its peers of the newly +//! synchronized checkpoint so that it can help other peers synchronize. + +use std::{ + collections::{HashMap, VecDeque}, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, RwLock, + }, + time::Duration, +}; + +use anemo::{types::PeerEvent, PeerId, Request, Response, Result}; +use futures::{stream::FuturesOrdered, FutureExt, StreamExt}; +use iota_config::p2p::StateSyncConfig; +use iota_types::{ + committee::Committee, + digests::CheckpointDigest, + messages_checkpoint::{ + CertifiedCheckpointSummary as Checkpoint, CheckpointSequenceNumber, EndOfEpochData, + FullCheckpointContents, VerifiedCheckpoint, VerifiedCheckpointContents, + }, + storage::WriteStore, +}; +use rand::Rng; +use tap::{Pipe, TapFallible, TapOptional}; +use tokio::{ + sync::{broadcast, mpsc, oneshot, watch}, + task::{AbortHandle, JoinSet}, +}; +use tracing::{debug, info, instrument, trace, warn}; + +mod generated { + include!(concat!(env!("OUT_DIR"), "/iota.StateSync.rs")); +} +mod builder; +mod metrics; +mod server; +#[cfg(test)] +mod tests; + +pub use builder::{Builder, UnstartedStateSync}; +pub use generated::{ + state_sync_client::StateSyncClient, + state_sync_server::{StateSync, StateSyncServer}, +}; +use iota_archival::reader::ArchiveReaderBalancer; +use iota_storage::verify_checkpoint; +pub use server::{GetCheckpointAvailabilityResponse, GetCheckpointSummaryRequest}; + +use self::{metrics::Metrics, server::CheckpointContentsDownloadLimitLayer}; + +/// A handle to the StateSync subsystem. +/// +/// This handle can be cloned and shared. Once all copies of a StateSync +/// system's Handle have been dropped, the StateSync system will be gracefully +/// shutdown. +#[derive(Clone, Debug)] +pub struct Handle { + sender: mpsc::Sender, + checkpoint_event_sender: broadcast::Sender, +} + +impl Handle { + /// Send a newly minted checkpoint from Consensus to StateSync so that it + /// can be disseminated to other nodes on the network. + /// + /// # Invariant + /// + /// Consensus must only notify StateSync of new checkpoints that have been + /// fully committed to persistent storage. This includes + /// CheckpointContents and all Transactions and TransactionEffects + /// included therein. + pub async fn send_checkpoint(&self, checkpoint: VerifiedCheckpoint) { + self.sender + .send(StateSyncMessage::VerifiedCheckpoint(Box::new(checkpoint))) + .await + .unwrap() + } + + /// Subscribe to the stream of checkpoints that have been fully synchronized + /// and downloaded. + pub fn subscribe_to_synced_checkpoints(&self) -> broadcast::Receiver { + self.checkpoint_event_sender.subscribe() + } +} + +struct PeerHeights { + /// Table used to track the highest checkpoint for each of our peers. + peers: HashMap, + unprocessed_checkpoints: HashMap, + sequence_number_to_digest: HashMap, + + // The amount of time to wait before retry if there are no peers to sync content from. + wait_interval_when_no_peer_to_sync_content: Duration, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +struct PeerStateSyncInfo { + /// The digest of the Peer's genesis checkpoint. + genesis_checkpoint_digest: CheckpointDigest, + /// Indicates if this Peer is on the same chain as us. + on_same_chain_as_us: bool, + /// Highest checkpoint sequence number we know of for this Peer. + height: CheckpointSequenceNumber, + /// lowest available checkpoint watermark for this Peer. + /// This defaults to 0 for now. + lowest: CheckpointSequenceNumber, +} + +impl PeerHeights { + pub fn highest_known_checkpoint(&self) -> Option<&Checkpoint> { + self.highest_known_checkpoint_sequence_number() + .and_then(|s| self.sequence_number_to_digest.get(&s)) + .and_then(|digest| self.unprocessed_checkpoints.get(digest)) + } + + pub fn highest_known_checkpoint_sequence_number(&self) -> Option { + self.peers + .values() + .filter_map(|info| info.on_same_chain_as_us.then_some(info.height)) + .max() + } + + pub fn peers_on_same_chain(&self) -> impl Iterator { + self.peers + .iter() + .filter(|(_peer_id, info)| info.on_same_chain_as_us) + } + + // Returns a bool that indicates if the update was done successfully. + // + // This will return false if the given peer doesn't have an entry or is not on + // the same chain as us + pub fn update_peer_info( + &mut self, + peer_id: PeerId, + checkpoint: Checkpoint, + low_watermark: Option, + ) -> bool { + let info = match self.peers.get_mut(&peer_id) { + Some(info) if info.on_same_chain_as_us => info, + _ => return false, + }; + + info.height = std::cmp::max(*checkpoint.sequence_number(), info.height); + if let Some(low_watermark) = low_watermark { + info.lowest = low_watermark; + } + self.insert_checkpoint(checkpoint); + + true + } + + pub fn insert_peer_info(&mut self, peer_id: PeerId, info: PeerStateSyncInfo) { + use std::collections::hash_map::Entry; + + match self.peers.entry(peer_id) { + Entry::Occupied(mut entry) => { + // If there's already an entry and the genesis checkpoint digests match then + // update the maximum height. Otherwise we'll use the more + // recent one + let entry = entry.get_mut(); + if entry.genesis_checkpoint_digest == info.genesis_checkpoint_digest { + entry.height = std::cmp::max(entry.height, info.height); + } else { + *entry = info; + } + } + Entry::Vacant(entry) => { + entry.insert(info); + } + } + } + + pub fn mark_peer_as_not_on_same_chain(&mut self, peer_id: PeerId) { + if let Some(info) = self.peers.get_mut(&peer_id) { + info.on_same_chain_as_us = false; + } + } + + pub fn cleanup_old_checkpoints(&mut self, sequence_number: CheckpointSequenceNumber) { + self.unprocessed_checkpoints + .retain(|_digest, checkpoint| *checkpoint.sequence_number() > sequence_number); + self.sequence_number_to_digest + .retain(|&s, _digest| s > sequence_number); + } + + // TODO: also record who gives this checkpoint info for peer quality + // measurement? + pub fn insert_checkpoint(&mut self, checkpoint: Checkpoint) { + let digest = *checkpoint.digest(); + let sequence_number = *checkpoint.sequence_number(); + self.unprocessed_checkpoints.insert(digest, checkpoint); + self.sequence_number_to_digest + .insert(sequence_number, digest); + } + + pub fn remove_checkpoint(&mut self, digest: &CheckpointDigest) { + if let Some(checkpoint) = self.unprocessed_checkpoints.remove(digest) { + self.sequence_number_to_digest + .remove(checkpoint.sequence_number()); + } + } + + pub fn get_checkpoint_by_sequence_number( + &self, + sequence_number: CheckpointSequenceNumber, + ) -> Option<&Checkpoint> { + self.sequence_number_to_digest + .get(&sequence_number) + .and_then(|digest| self.get_checkpoint_by_digest(digest)) + } + + pub fn get_checkpoint_by_digest(&self, digest: &CheckpointDigest) -> Option<&Checkpoint> { + self.unprocessed_checkpoints.get(digest) + } + + #[cfg(test)] + pub fn set_wait_interval_when_no_peer_to_sync_content(&mut self, duration: Duration) { + self.wait_interval_when_no_peer_to_sync_content = duration; + } + + pub fn wait_interval_when_no_peer_to_sync_content(&self) -> Duration { + self.wait_interval_when_no_peer_to_sync_content + } +} + +// PeerBalancer is an Iterator that selects peers based on RTT with some added +// randomness. +#[derive(Clone)] +struct PeerBalancer { + peers: VecDeque<(anemo::Peer, PeerStateSyncInfo)>, + requested_checkpoint: Option, + request_type: PeerCheckpointRequestType, +} + +#[derive(Clone)] +enum PeerCheckpointRequestType { + Summary, + Content, +} + +impl PeerBalancer { + pub fn new( + network: &anemo::Network, + peer_heights: Arc>, + request_type: PeerCheckpointRequestType, + ) -> Self { + let mut peers: Vec<_> = peer_heights + .read() + .unwrap() + .peers_on_same_chain() + // Filter out any peers who we aren't connected with. + .filter_map(|(peer_id, info)| network.peer(*peer_id).map(|peer| (peer, *info))) + .collect(); + peers.sort_by(|(peer_a, _), (peer_b, _)| { + peer_a.connection_rtt().cmp(&peer_b.connection_rtt()) + }); + Self { + peers: peers.into(), + requested_checkpoint: None, + request_type, + } + } + + pub fn with_checkpoint(mut self, checkpoint: CheckpointSequenceNumber) -> Self { + self.requested_checkpoint = Some(checkpoint); + self + } +} + +impl Iterator for PeerBalancer { + type Item = StateSyncClient; + + fn next(&mut self) -> Option { + while !self.peers.is_empty() { + const SELECTION_WINDOW: usize = 2; + let idx = + rand::thread_rng().gen_range(0..std::cmp::min(SELECTION_WINDOW, self.peers.len())); + let (peer, info) = self.peers.remove(idx).unwrap(); + let requested_checkpoint = self.requested_checkpoint.unwrap_or(0); + match &self.request_type { + // Summary will never be pruned + PeerCheckpointRequestType::Summary if info.height >= requested_checkpoint => { + return Some(StateSyncClient::new(peer)); + } + PeerCheckpointRequestType::Content + if info.height >= requested_checkpoint + && info.lowest <= requested_checkpoint => + { + return Some(StateSyncClient::new(peer)); + } + _ => {} + } + } + None + } +} + +#[derive(Clone, Debug)] +enum StateSyncMessage { + StartSyncJob, + // Validators will send this to the StateSyncEventLoop in order to kick off notifying our + // peers of the new checkpoint. + VerifiedCheckpoint(Box), + // Notification that the checkpoint content sync task will send to the event loop in the event + // it was able to successfully sync a checkpoint's contents. If multiple checkpoints were + // synced at the same time, only the highest checkpoint is sent. + SyncedCheckpoint(Box), +} + +struct StateSyncEventLoop { + config: StateSyncConfig, + + mailbox: mpsc::Receiver, + /// Weak reference to our own mailbox + weak_sender: mpsc::WeakSender, + + tasks: JoinSet<()>, + sync_checkpoint_summaries_task: Option, + sync_checkpoint_contents_task: Option, + download_limit_layer: Option, + + store: S, + peer_heights: Arc>, + checkpoint_event_sender: broadcast::Sender, + network: anemo::Network, + metrics: Metrics, + + archive_readers: ArchiveReaderBalancer, + sync_checkpoint_from_archive_task: Option, +} + +impl StateSyncEventLoop +where + S: WriteStore + Clone + Send + Sync + 'static, +{ + // Note: A great deal of care is taken to ensure that all event handlers are + // non-asynchronous and that the only "await" points are from the select + // macro picking which event to handle. This ensures that the event loop is + // able to process events at a high speed and reduce the chance for building + // up a backlog of events to process. + pub async fn start(mut self) { + info!("State-Synchronizer started"); + + self.config.pinned_checkpoints.sort(); + + let mut interval = tokio::time::interval(self.config.interval_period()); + let mut peer_events = { + let (subscriber, peers) = self.network.subscribe().unwrap(); + for peer_id in peers { + self.spawn_get_latest_from_peer(peer_id); + } + subscriber + }; + let ( + target_checkpoint_contents_sequence_sender, + target_checkpoint_contents_sequence_receiver, + ) = watch::channel(0); + + // Spawn tokio task to update metrics periodically in the background + let (_sender, receiver) = oneshot::channel(); + tokio::spawn(update_checkpoint_watermark_metrics( + receiver, + self.store.clone(), + self.metrics.clone(), + )); + + // Start checkpoint contents sync loop. + let task = sync_checkpoint_contents( + self.network.clone(), + self.store.clone(), + self.peer_heights.clone(), + self.weak_sender.clone(), + self.checkpoint_event_sender.clone(), + self.config.checkpoint_content_download_concurrency(), + self.config.checkpoint_content_download_tx_concurrency(), + self.config.checkpoint_content_timeout(), + target_checkpoint_contents_sequence_receiver, + ); + let task_handle = self.tasks.spawn(task); + self.sync_checkpoint_contents_task = Some(task_handle); + + // Start archive based checkpoint content sync loop. + // TODO: Consider switching to sync from archive only on startup. + // Right now because the peer set is fixed at startup, a node may eventually + // end up with peers who have all purged their local state. In such a scenario + // it will be stuck until restart when it ends up with a different set + // of peers. Once the discovery mechanism can dynamically identify and + // connect to other peers on the network, we will rely on sync from + // archive as a fall back. + let task = sync_checkpoint_contents_from_archive( + self.network.clone(), + self.archive_readers.clone(), + self.store.clone(), + self.peer_heights.clone(), + ); + let task_handle = self.tasks.spawn(task); + self.sync_checkpoint_from_archive_task = Some(task_handle); + + // Start main loop. + loop { + tokio::select! { + now = interval.tick() => { + self.handle_tick(now.into_std()); + }, + maybe_message = self.mailbox.recv() => { + // Once all handles to our mailbox have been dropped this + // will yield `None` and we can terminate the event loop + if let Some(message) = maybe_message { + self.handle_message(message); + } else { + break; + } + }, + peer_event = peer_events.recv() => { + self.handle_peer_event(peer_event); + }, + Some(task_result) = self.tasks.join_next() => { + match task_result { + Ok(()) => {}, + Err(e) => { + if e.is_cancelled() { + // avoid crashing on ungraceful shutdown + } else if e.is_panic() { + // propagate panics. + std::panic::resume_unwind(e.into_panic()); + } else { + panic!("task failed: {e}"); + } + }, + }; + + if matches!(&self.sync_checkpoint_contents_task, Some(t) if t.is_finished()) { + panic!("sync_checkpoint_contents task unexpectedly terminated") + } + + if matches!(&self.sync_checkpoint_summaries_task, Some(t) if t.is_finished()) { + self.sync_checkpoint_summaries_task = None; + } + + if matches!(&self.sync_checkpoint_from_archive_task, Some(t) if t.is_finished()) { + panic!("sync_checkpoint_from_archive task unexpectedly terminated") + } + }, + } + + self.maybe_start_checkpoint_summary_sync_task(); + self.maybe_trigger_checkpoint_contents_sync_task( + &target_checkpoint_contents_sequence_sender, + ); + } + + info!("State-Synchronizer ended"); + } + + fn handle_message(&mut self, message: StateSyncMessage) { + debug!("Received message: {:?}", message); + match message { + StateSyncMessage::StartSyncJob => self.maybe_start_checkpoint_summary_sync_task(), + StateSyncMessage::VerifiedCheckpoint(checkpoint) => { + self.handle_checkpoint_from_consensus(checkpoint) + } + // After we've successfully synced a checkpoint we can notify our peers + StateSyncMessage::SyncedCheckpoint(checkpoint) => { + self.spawn_notify_peers_of_checkpoint(*checkpoint) + } + } + } + + // Handle a checkpoint that we received from consensus + #[instrument(level = "debug", skip_all)] + fn handle_checkpoint_from_consensus(&mut self, checkpoint: Box) { + // Always check previous_digest matches in case there is a gap between + // state sync and consensus. + let prev_digest = *self.store.get_checkpoint_by_sequence_number(checkpoint.sequence_number() - 1) + .expect("store operation should not fail") + .unwrap_or_else(|| panic!("Got checkpoint {} from consensus but cannot find checkpoint {} in certified_checkpoints", checkpoint.sequence_number(), checkpoint.sequence_number() - 1)) + .digest(); + if checkpoint.previous_digest != Some(prev_digest) { + panic!( + "Checkpoint {} from consensus has mismatched previous_digest, expected: {:?}, actual: {:?}", + checkpoint.sequence_number(), + Some(prev_digest), + checkpoint.previous_digest + ); + } + + let latest_checkpoint = self + .store + .get_highest_verified_checkpoint() + .expect("store operation should not fail"); + + // If this is an older checkpoint, just ignore it + if latest_checkpoint.sequence_number() >= checkpoint.sequence_number() { + return; + } + + let checkpoint = *checkpoint; + let next_sequence_number = latest_checkpoint.sequence_number().checked_add(1).unwrap(); + if *checkpoint.sequence_number() > next_sequence_number { + debug!( + "consensus sent too new of a checkpoint, expecting: {}, got: {}", + next_sequence_number, + checkpoint.sequence_number() + ); + } + + // Because checkpoint from consensus sends in order, when we have checkpoint n, + // we must have all of the checkpoints before n from either state sync or + // consensus. + #[cfg(debug_assertions)] + { + let _ = (next_sequence_number..=*checkpoint.sequence_number()) + .map(|n| { + let checkpoint = self + .store + .get_checkpoint_by_sequence_number(n) + .expect("store operation should not fail") + .unwrap_or_else(|| panic!("store should contain checkpoint {n}")); + self.store + .get_full_checkpoint_contents(&checkpoint.content_digest) + .expect("store operation should not fail") + .unwrap_or_else(|| { + panic!( + "store should contain checkpoint contents for {:?}", + checkpoint.content_digest + ) + }); + }) + .collect::>(); + } + + // If this is the last checkpoint of a epoch, we need to make sure + // new committee is in store before we verify newer checkpoints in next epoch. + // This could happen before this validator's reconfiguration finishes, because + // state sync does not reconfig. + // TODO: make CheckpointAggregator use WriteStore so we don't need to do this + // committee insertion in two places (only in `insert_checkpoint`). + if let Some(EndOfEpochData { + next_epoch_committee, + .. + }) = checkpoint.end_of_epoch_data.as_ref() + { + let next_committee = next_epoch_committee.iter().cloned().collect(); + let committee = + Committee::new(checkpoint.epoch().checked_add(1).unwrap(), next_committee); + self.store + .insert_committee(committee) + .expect("store operation should not fail"); + } + + self.store + .update_highest_verified_checkpoint(&checkpoint) + .expect("store operation should not fail"); + self.store + .update_highest_synced_checkpoint(&checkpoint) + .expect("store operation should not fail"); + + // We don't care if no one is listening as this is a broadcast channel + let _ = self.checkpoint_event_sender.send(checkpoint.clone()); + + self.spawn_notify_peers_of_checkpoint(checkpoint); + } + + fn handle_peer_event( + &mut self, + peer_event: Result, + ) { + use tokio::sync::broadcast::error::RecvError; + + match peer_event { + Ok(PeerEvent::NewPeer(peer_id)) => { + self.spawn_get_latest_from_peer(peer_id); + } + Ok(PeerEvent::LostPeer(peer_id, _)) => { + self.peer_heights.write().unwrap().peers.remove(&peer_id); + } + + Err(RecvError::Closed) => { + panic!("PeerEvent channel shouldn't be able to be closed"); + } + + Err(RecvError::Lagged(_)) => { + trace!("State-Sync fell behind processing PeerEvents"); + } + } + } + + fn spawn_get_latest_from_peer(&mut self, peer_id: PeerId) { + if let Some(peer) = self.network.peer(peer_id) { + let genesis_checkpoint_digest = *self + .store + .get_checkpoint_by_sequence_number(0) + .expect("store operation should not fail") + .expect("store should contain genesis checkpoint") + .digest(); + let task = get_latest_from_peer( + genesis_checkpoint_digest, + peer, + self.peer_heights.clone(), + self.config.timeout(), + ); + self.tasks.spawn(task); + } + } + + fn handle_tick(&mut self, _now: std::time::Instant) { + let task = query_peers_for_their_latest_checkpoint( + self.network.clone(), + self.peer_heights.clone(), + self.weak_sender.clone(), + self.config.timeout(), + ); + self.tasks.spawn(task); + + if let Some(layer) = self.download_limit_layer.as_ref() { + layer.maybe_prune_map(); + } + } + + fn maybe_start_checkpoint_summary_sync_task(&mut self) { + // Only run one sync task at a time + if self.sync_checkpoint_summaries_task.is_some() { + return; + } + + let highest_processed_checkpoint = self + .store + .get_highest_verified_checkpoint() + .expect("store operation should not fail"); + + let highest_known_checkpoint = self + .peer_heights + .read() + .unwrap() + .highest_known_checkpoint() + .cloned(); + + if Some(highest_processed_checkpoint.sequence_number()) + < highest_known_checkpoint + .as_ref() + .map(|x| x.sequence_number()) + { + // start sync job + let task = sync_to_checkpoint( + self.network.clone(), + self.store.clone(), + self.peer_heights.clone(), + self.metrics.clone(), + self.config.pinned_checkpoints.clone(), + self.config.checkpoint_header_download_concurrency(), + self.config.timeout(), + // The if condition should ensure that this is Some + highest_known_checkpoint.unwrap(), + ) + .map(|result| match result { + Ok(()) => {} + Err(e) => { + debug!("error syncing checkpoint {e}"); + } + }); + let task_handle = self.tasks.spawn(task); + self.sync_checkpoint_summaries_task = Some(task_handle); + } + } + + fn maybe_trigger_checkpoint_contents_sync_task( + &mut self, + target_sequence_channel: &watch::Sender, + ) { + let highest_verified_checkpoint = self + .store + .get_highest_verified_checkpoint() + .expect("store operation should not fail"); + let highest_synced_checkpoint = self + .store + .get_highest_synced_checkpoint() + .expect("store operation should not fail"); + + if highest_verified_checkpoint.sequence_number() + > highest_synced_checkpoint.sequence_number() + // skip if we aren't connected to any peers that can help + && self + .peer_heights + .read() + .unwrap() + .highest_known_checkpoint_sequence_number() + > Some(*highest_synced_checkpoint.sequence_number()) + { + let _ = target_sequence_channel.send_if_modified(|num| { + let new_num = *highest_verified_checkpoint.sequence_number(); + if *num == new_num { + return false; + } + *num = new_num; + true + }); + } + } + + fn spawn_notify_peers_of_checkpoint(&mut self, checkpoint: VerifiedCheckpoint) { + let task = notify_peers_of_checkpoint( + self.network.clone(), + self.peer_heights.clone(), + checkpoint, + self.config.timeout(), + ); + self.tasks.spawn(task); + } +} + +async fn notify_peers_of_checkpoint( + network: anemo::Network, + peer_heights: Arc>, + checkpoint: VerifiedCheckpoint, + timeout: Duration, +) { + let futs = peer_heights + .read() + .unwrap() + .peers_on_same_chain() + // Filter out any peers who we know already have a checkpoint higher than this one + .filter_map(|(peer_id, info)| { + (*checkpoint.sequence_number() > info.height).then_some(peer_id) + }) + // Filter out any peers who we aren't connected with + .flat_map(|peer_id| network.peer(*peer_id)) + .map(StateSyncClient::new) + .map(|mut client| { + let request = Request::new(checkpoint.inner().clone()).with_timeout(timeout); + async move { client.push_checkpoint_summary(request).await } + }) + .collect::>(); + futures::future::join_all(futs).await; +} + +async fn get_latest_from_peer( + our_genesis_checkpoint_digest: CheckpointDigest, + peer: anemo::Peer, + peer_heights: Arc>, + timeout: Duration, +) { + let peer_id = peer.peer_id(); + let mut client = StateSyncClient::new(peer); + + let info = { + let maybe_info = peer_heights.read().unwrap().peers.get(&peer_id).copied(); + + if let Some(info) = maybe_info { + info + } else { + // TODO do we want to create a new API just for querying a node's chainid? + // + // We need to query this node's genesis checkpoint to see if they're on the same + // chain as us + let request = Request::new(GetCheckpointSummaryRequest::BySequenceNumber(0)) + .with_timeout(timeout); + let response = client + .get_checkpoint_summary(request) + .await + .map(Response::into_inner); + + let info = match response { + Ok(Some(checkpoint)) => { + let digest = *checkpoint.digest(); + PeerStateSyncInfo { + genesis_checkpoint_digest: digest, + on_same_chain_as_us: our_genesis_checkpoint_digest == digest, + height: *checkpoint.sequence_number(), + lowest: CheckpointSequenceNumber::default(), + } + } + Ok(None) => PeerStateSyncInfo { + genesis_checkpoint_digest: CheckpointDigest::default(), + on_same_chain_as_us: false, + height: CheckpointSequenceNumber::default(), + lowest: CheckpointSequenceNumber::default(), + }, + Err(status) => { + trace!("get_latest_checkpoint_summary request failed: {status:?}"); + return; + } + }; + peer_heights + .write() + .unwrap() + .insert_peer_info(peer_id, info); + info + } + }; + + // Bail early if this node isn't on the same chain as us + if !info.on_same_chain_as_us { + return; + } + let Some((highest_checkpoint, low_watermark)) = + query_peer_for_latest_info(&mut client, timeout).await + else { + return; + }; + peer_heights + .write() + .unwrap() + .update_peer_info(peer_id, highest_checkpoint, low_watermark); +} + +/// Queries a peer for their highest_synced_checkpoint and low checkpoint +/// watermark +async fn query_peer_for_latest_info( + client: &mut StateSyncClient, + timeout: Duration, +) -> Option<(Checkpoint, Option)> { + let request = Request::new(()).with_timeout(timeout); + let response = client + .get_checkpoint_availability(request) + .await + .map(Response::into_inner); + match response { + Ok(GetCheckpointAvailabilityResponse { + highest_synced_checkpoint, + lowest_available_checkpoint, + }) => { + return Some((highest_synced_checkpoint, Some(lowest_available_checkpoint))); + } + Err(status) => { + // If peer hasn't upgraded they would return 404 NotFound error + if status.status() != anemo::types::response::StatusCode::NotFound { + trace!("get_checkpoint_availability request failed: {status:?}"); + return None; + } + } + }; + + // Then we try the old query + // TODO: remove this once the new feature stabilizes + let request = Request::new(GetCheckpointSummaryRequest::Latest).with_timeout(timeout); + let response = client + .get_checkpoint_summary(request) + .await + .map(Response::into_inner); + match response { + Ok(Some(checkpoint)) => Some((checkpoint, None)), + Ok(None) => None, + Err(status) => { + trace!("get_checkpoint_summary (latest) request failed: {status:?}"); + None + } + } +} + +async fn query_peers_for_their_latest_checkpoint( + network: anemo::Network, + peer_heights: Arc>, + sender: mpsc::WeakSender, + timeout: Duration, +) { + let peer_heights = &peer_heights; + let futs = peer_heights + .read() + .unwrap() + .peers_on_same_chain() + // Filter out any peers who we aren't connected with + .flat_map(|(peer_id, _info)| network.peer(*peer_id)) + .map(|peer| { + let peer_id = peer.peer_id(); + let mut client = StateSyncClient::new(peer); + + async move { + let response = query_peer_for_latest_info(&mut client, timeout).await; + match response { + Some((highest_checkpoint, low_watermark)) => peer_heights + .write() + .unwrap() + .update_peer_info(peer_id, highest_checkpoint.clone(), low_watermark) + .then_some(highest_checkpoint), + None => None, + } + } + }) + .collect::>(); + + let checkpoints = futures::future::join_all(futs).await.into_iter().flatten(); + + let highest_checkpoint = checkpoints.max_by_key(|checkpoint| *checkpoint.sequence_number()); + + let our_highest_checkpoint = peer_heights + .read() + .unwrap() + .highest_known_checkpoint() + .cloned(); + + let _new_checkpoint = match (highest_checkpoint, our_highest_checkpoint) { + (Some(theirs), None) => theirs, + (Some(theirs), Some(ours)) if theirs.sequence_number() > ours.sequence_number() => theirs, + _ => return, + }; + + if let Some(sender) = sender.upgrade() { + let _ = sender.send(StateSyncMessage::StartSyncJob).await; + } +} + +async fn sync_to_checkpoint( + network: anemo::Network, + store: S, + peer_heights: Arc>, + metrics: Metrics, + pinned_checkpoints: Vec<(CheckpointSequenceNumber, CheckpointDigest)>, + checkpoint_header_download_concurrency: usize, + timeout: Duration, + checkpoint: Checkpoint, +) -> Result<()> +where + S: WriteStore, +{ + metrics.set_highest_known_checkpoint(*checkpoint.sequence_number()); + + let mut current = store + .get_highest_verified_checkpoint() + .expect("store operation should not fail"); + if current.sequence_number() >= checkpoint.sequence_number() { + return Err(anyhow::anyhow!( + "target checkpoint {} is older than highest verified checkpoint {}", + checkpoint.sequence_number(), + current.sequence_number(), + )); + } + + let peer_balancer = PeerBalancer::new( + &network, + peer_heights.clone(), + PeerCheckpointRequestType::Summary, + ); + // range of the next sequence_numbers to fetch + let mut request_stream = (current.sequence_number().checked_add(1).unwrap() + ..=*checkpoint.sequence_number()) + .map(|next| { + let peers = peer_balancer.clone().with_checkpoint(next); + let peer_heights = peer_heights.clone(); + let pinned_checkpoints = &pinned_checkpoints; + async move { + if let Some(checkpoint) = peer_heights + .read() + .unwrap() + .get_checkpoint_by_sequence_number(next) + { + return (Some(checkpoint.to_owned()), next, None); + } + + // Iterate through peers trying each one in turn until we're able to + // successfully get the target checkpoint + for mut peer in peers { + let request = Request::new(GetCheckpointSummaryRequest::BySequenceNumber(next)) + .with_timeout(timeout); + if let Some(checkpoint) = peer + .get_checkpoint_summary(request) + .await + .tap_err(|e| trace!("{e:?}")) + .ok() + .and_then(Response::into_inner) + .tap_none(|| trace!("peer unable to help sync")) + { + // peer didn't give us a checkpoint with the height that we requested + if *checkpoint.sequence_number() != next { + tracing::debug!( + "peer returned checkpoint with wrong sequence number: expected {next}, got {}", + checkpoint.sequence_number() + ); + continue; + } + + // peer gave us a checkpoint whose digest does not match pinned digest + let checkpoint_digest = checkpoint.digest(); + if let Ok(pinned_digest_index) = pinned_checkpoints.binary_search_by_key( + checkpoint.sequence_number(), + |(seq_num, _digest)| *seq_num + ) { + if pinned_checkpoints[pinned_digest_index].1 != *checkpoint_digest { + tracing::debug!( + "peer returned checkpoint with digest that does not match pinned digest: expected {:?}, got {:?}", + pinned_checkpoints[pinned_digest_index].1, + checkpoint_digest + ); + continue; + } + } + + // Insert in our store in the event that things fail and we need to retry + peer_heights + .write() + .unwrap() + .insert_checkpoint(checkpoint.clone()); + return (Some(checkpoint), next, Some(peer.inner().peer_id())); + } + } + (None, next, None) + } + }) + .pipe(futures::stream::iter) + .buffered(checkpoint_header_download_concurrency); + + while let Some((maybe_checkpoint, next, maybe_peer_id)) = request_stream.next().await { + assert_eq!( + current + .sequence_number() + .checked_add(1) + .expect("exhausted u64"), + next + ); + + // Verify the checkpoint + let checkpoint = 'cp: { + let checkpoint = maybe_checkpoint.ok_or_else(|| { + anyhow::anyhow!("no peers were able to help sync checkpoint {next}") + })?; + // Skip verification for manually pinned checkpoints. + if pinned_checkpoints + .binary_search_by_key(checkpoint.sequence_number(), |(seq_num, _digest)| *seq_num) + .is_ok() + { + break 'cp VerifiedCheckpoint::new_unchecked(checkpoint); + } + match verify_checkpoint(¤t, &store, checkpoint) { + Ok(verified_checkpoint) => verified_checkpoint, + Err(checkpoint) => { + let mut peer_heights = peer_heights.write().unwrap(); + // Remove the checkpoint from our temporary store so that we can try querying + // another peer for a different one + peer_heights.remove_checkpoint(checkpoint.digest()); + + // Mark peer as not on the same chain as us + if let Some(peer_id) = maybe_peer_id { + peer_heights.mark_peer_as_not_on_same_chain(peer_id); + } + + return Err(anyhow::anyhow!( + "unable to verify checkpoint {checkpoint:?}" + )); + } + } + }; + + debug!(checkpoint_seq = ?checkpoint.sequence_number(), "verified checkpoint summary"); + if let Some(checkpoint_summary_age_metric) = metrics.checkpoint_summary_age_metric() { + checkpoint.report_checkpoint_age_ms(checkpoint_summary_age_metric); + } + + current = checkpoint.clone(); + // Insert the newly verified checkpoint into our store, which will bump our + // highest verified checkpoint watermark as well. + store + .insert_checkpoint(&checkpoint) + .expect("store operation should not fail"); + } + + peer_heights + .write() + .unwrap() + .cleanup_old_checkpoints(*checkpoint.sequence_number()); + + Ok(()) +} + +async fn sync_checkpoint_contents_from_archive( + network: anemo::Network, + archive_readers: ArchiveReaderBalancer, + store: S, + peer_heights: Arc>, +) where + S: WriteStore + Clone + Send + Sync + 'static, +{ + loop { + let peers: Vec<_> = peer_heights + .read() + .unwrap() + .peers_on_same_chain() + // Filter out any peers who we aren't connected with. + .filter_map(|(peer_id, info)| network.peer(*peer_id).map(|peer| (peer, *info))) + .collect(); + let lowest_checkpoint_on_peers = peers + .iter() + .map(|(_p, state_sync_info)| state_sync_info.lowest) + .min(); + let highest_synced = store + .get_highest_synced_checkpoint() + .expect("store operation should not fail") + .sequence_number; + let sync_from_archive = if let Some(lowest_checkpoint_on_peers) = lowest_checkpoint_on_peers + { + highest_synced < lowest_checkpoint_on_peers + } else { + false + }; + if sync_from_archive { + let start = highest_synced + .checked_add(1) + .expect("Checkpoint seq num overflow"); + let checkpoint_range = start..lowest_checkpoint_on_peers.unwrap(); + if let Some(archive_reader) = archive_readers + .pick_one_random(checkpoint_range.clone()) + .await + { + let txn_counter = Arc::new(AtomicU64::new(0)); + let checkpoint_counter = Arc::new(AtomicU64::new(0)); + if let Err(err) = archive_reader + .read( + store.clone(), + checkpoint_range, + txn_counter.clone(), + checkpoint_counter.clone(), + true, + ) + .await + { + warn!("State sync from archive failed with error: {:?}", err); + } else { + info!( + "State sync from archive is complete. Checkpoints downloaded = {:?}, Txns downloaded = {:?}", + checkpoint_counter.load(Ordering::Relaxed), + txn_counter.load(Ordering::Relaxed) + ); + } + } else { + warn!("Failed to find an archive reader to complete the state sync request"); + } + } + tokio::time::sleep(Duration::from_secs(5)).await; + } +} + +async fn sync_checkpoint_contents( + network: anemo::Network, + store: S, + peer_heights: Arc>, + sender: mpsc::WeakSender, + checkpoint_event_sender: broadcast::Sender, + checkpoint_content_download_concurrency: usize, + checkpoint_content_download_tx_concurrency: u64, + timeout: Duration, + mut target_sequence_channel: watch::Receiver, +) where + S: WriteStore + Clone, +{ + let mut highest_synced = store + .get_highest_synced_checkpoint() + .expect("store operation should not fail"); + + let mut current_sequence = highest_synced.sequence_number().checked_add(1).unwrap(); + let mut target_sequence_cursor = 0; + let mut highest_started_network_total_transactions = highest_synced.network_total_transactions; + let mut checkpoint_contents_tasks = FuturesOrdered::new(); + + let mut tx_concurrency_remaining = checkpoint_content_download_tx_concurrency; + + loop { + tokio::select! { + result = target_sequence_channel.changed() => { + match result { + Ok(()) => { + target_sequence_cursor = (*target_sequence_channel.borrow_and_update()).checked_add(1).unwrap(); + } + Err(_) => { + // Watch channel is closed, exit loop. + return + } + } + }, + Some(maybe_checkpoint) = checkpoint_contents_tasks.next() => { + match maybe_checkpoint { + Ok(checkpoint) => { + let _: &VerifiedCheckpoint = &checkpoint; // type hint + + store + .update_highest_synced_checkpoint(&checkpoint) + .expect("store operation should not fail"); + // We don't care if no one is listening as this is a broadcast channel + let _ = checkpoint_event_sender.send(checkpoint.clone()); + tx_concurrency_remaining += checkpoint.network_total_transactions - highest_synced.network_total_transactions; + highest_synced = checkpoint; + + } + Err(checkpoint) => { + let _: &VerifiedCheckpoint = &checkpoint; // type hint + if let Some(lowest_peer_checkpoint) = + peer_heights.read().ok().and_then(|x| x.peers.values().map(|state_sync_info| state_sync_info.lowest).min()) { + if checkpoint.sequence_number() >= &lowest_peer_checkpoint { + info!("unable to sync contents of checkpoint through state sync {} with lowest peer checkpoint: {}", checkpoint.sequence_number(), lowest_peer_checkpoint); + } + } else { + info!("unable to sync contents of checkpoint through state sync {}", checkpoint.sequence_number()); + + } + // Retry contents sync on failure. + checkpoint_contents_tasks.push_front(sync_one_checkpoint_contents( + network.clone(), + &store, + peer_heights.clone(), + timeout, + checkpoint, + )); + } + } + }, + } + + // Start new tasks up to configured concurrency limits. + while current_sequence < target_sequence_cursor + && checkpoint_contents_tasks.len() < checkpoint_content_download_concurrency + { + let next_checkpoint = store + .get_checkpoint_by_sequence_number(current_sequence) + .expect("store operation should not fail") + .expect( + "BUG: store should have all checkpoints older than highest_verified_checkpoint", + ); + + // Enforce transaction count concurrency limit. + let tx_count = next_checkpoint.network_total_transactions + - highest_started_network_total_transactions; + if tx_count > tx_concurrency_remaining { + break; + } + tx_concurrency_remaining -= tx_count; + + highest_started_network_total_transactions = next_checkpoint.network_total_transactions; + current_sequence += 1; + checkpoint_contents_tasks.push_back(sync_one_checkpoint_contents( + network.clone(), + &store, + peer_heights.clone(), + timeout, + next_checkpoint, + )); + } + + if highest_synced.sequence_number() % checkpoint_content_download_concurrency as u64 == 0 + || checkpoint_contents_tasks.is_empty() + { + // Periodically notify event loop to notify our peers that we've synced to a new + // checkpoint height + if let Some(sender) = sender.upgrade() { + let message = StateSyncMessage::SyncedCheckpoint(Box::new(highest_synced.clone())); + let _ = sender.send(message).await; + } + } + } +} + +#[instrument(level = "debug", skip_all, fields(sequence_number = ?checkpoint.sequence_number()))] +async fn sync_one_checkpoint_contents( + network: anemo::Network, + store: S, + peer_heights: Arc>, + timeout: Duration, + checkpoint: VerifiedCheckpoint, +) -> Result +where + S: WriteStore + Clone, +{ + debug!("syncing checkpoint contents"); + + // Check if we already have produced this checkpoint locally. If so, we don't + // need to get it from peers anymore. + if store + .get_highest_synced_checkpoint() + .expect("store operation should not fail") + .sequence_number() + >= checkpoint.sequence_number() + { + debug!("checkpoint was already created via consensus output"); + return Ok(checkpoint); + } + + // Request checkpoint contents from peers. + let peers = PeerBalancer::new( + &network, + peer_heights.clone(), + PeerCheckpointRequestType::Content, + ) + .with_checkpoint(*checkpoint.sequence_number()); + let Some(_contents) = get_full_checkpoint_contents(peers, &store, &checkpoint, timeout).await + else { + // Delay completion in case of error so we don't hammer the network with + // retries. + let duration = peer_heights + .read() + .unwrap() + .wait_interval_when_no_peer_to_sync_content(); + info!("retrying checkpoint sync after {:?}", duration); + tokio::time::sleep(duration).await; + return Err(checkpoint); + }; + debug!("completed checkpoint contents sync"); + Ok(checkpoint) +} + +#[instrument(level = "debug", skip_all)] +async fn get_full_checkpoint_contents( + peers: PeerBalancer, + store: S, + checkpoint: &VerifiedCheckpoint, + timeout: Duration, +) -> Option +where + S: WriteStore, +{ + let digest = checkpoint.content_digest; + if let Some(contents) = store + .get_full_checkpoint_contents_by_sequence_number(*checkpoint.sequence_number()) + .expect("store operation should not fail") + .or_else(|| { + store + .get_full_checkpoint_contents(&digest) + .expect("store operation should not fail") + }) + { + debug!("store already contains checkpoint contents"); + return Some(contents); + } + + // Iterate through our selected peers trying each one in turn until we're able + // to successfully get the target checkpoint + for mut peer in peers { + debug!( + ?timeout, + "requesting checkpoint contents from {}", + peer.inner().peer_id(), + ); + let request = Request::new(digest).with_timeout(timeout); + if let Some(contents) = peer + .get_checkpoint_contents(request) + .await + .tap_err(|e| trace!("{e:?}")) + .ok() + .and_then(Response::into_inner) + .tap_none(|| trace!("peer unable to help sync")) + { + if contents.verify_digests(digest).is_ok() { + let verified_contents = VerifiedCheckpointContents::new_unchecked(contents.clone()); + store + .insert_checkpoint_contents(checkpoint, verified_contents) + .expect("store operation should not fail"); + return Some(contents); + } + } + } + debug!("no peers had checkpoint contents"); + None +} + +async fn update_checkpoint_watermark_metrics( + mut recv: oneshot::Receiver<()>, + store: S, + metrics: Metrics, +) -> Result<()> +where + S: WriteStore + Clone + Send + Sync, +{ + let mut interval = tokio::time::interval(Duration::from_secs(5)); + loop { + tokio::select! { + _now = interval.tick() => { + let highest_verified_checkpoint = store.get_highest_verified_checkpoint() + .expect("store operation should not fail"); + metrics.set_highest_verified_checkpoint(highest_verified_checkpoint.sequence_number); + let highest_synced_checkpoint = store.get_highest_synced_checkpoint() + .expect("store operation should not fail"); + metrics.set_highest_synced_checkpoint(highest_synced_checkpoint.sequence_number); + }, + _ = &mut recv => break, + } + } + Ok(()) +} diff --git a/crates/iota-network/src/state_sync/server.rs b/crates/iota-network/src/state_sync/server.rs new file mode 100644 index 00000000000..59edf23df54 --- /dev/null +++ b/crates/iota-network/src/state_sync/server.rs @@ -0,0 +1,238 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + sync::{Arc, RwLock}, + task::{Context, Poll}, +}; + +use anemo::{rpc::Status, types::response::StatusCode, Request, Response, Result}; +use dashmap::DashMap; +use futures::future::BoxFuture; +use iota_types::{ + digests::{CheckpointContentsDigest, CheckpointDigest}, + messages_checkpoint::{ + CertifiedCheckpointSummary as Checkpoint, CheckpointSequenceNumber, FullCheckpointContents, + VerifiedCheckpoint, + }, + storage::WriteStore, +}; +use serde::{Deserialize, Serialize}; +use tokio::sync::{mpsc, OwnedSemaphorePermit, Semaphore}; + +use super::{PeerHeights, StateSync, StateSyncMessage}; + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +pub enum GetCheckpointSummaryRequest { + Latest, + ByDigest(CheckpointDigest), + BySequenceNumber(CheckpointSequenceNumber), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct GetCheckpointAvailabilityResponse { + pub(crate) highest_synced_checkpoint: Checkpoint, + pub(crate) lowest_available_checkpoint: CheckpointSequenceNumber, +} + +pub(super) struct Server { + pub(super) store: S, + pub(super) peer_heights: Arc>, + pub(super) sender: mpsc::WeakSender, +} + +#[anemo::async_trait] +impl StateSync for Server +where + S: WriteStore + Send + Sync + 'static, +{ + async fn push_checkpoint_summary( + &self, + request: Request, + ) -> Result, Status> { + let peer_id = request + .peer_id() + .copied() + .ok_or_else(|| Status::internal("unable to query sender's PeerId"))?; + + let checkpoint = request.into_inner(); + if !self + .peer_heights + .write() + .unwrap() + .update_peer_info(peer_id, checkpoint.clone(), None) + { + return Ok(Response::new(())); + } + + let highest_verified_checkpoint = *self + .store + .get_highest_verified_checkpoint() + .map_err(|e| Status::internal(e.to_string()))? + .sequence_number(); + + // If this checkpoint is higher than our highest verified checkpoint notify the + // event loop to potentially sync it + if *checkpoint.sequence_number() > highest_verified_checkpoint { + if let Some(sender) = self.sender.upgrade() { + sender.send(StateSyncMessage::StartSyncJob).await.unwrap(); + } + } + + Ok(Response::new(())) + } + + async fn get_checkpoint_summary( + &self, + request: Request, + ) -> Result>, Status> { + let checkpoint = match request.inner() { + GetCheckpointSummaryRequest::Latest => { + self.store.get_highest_synced_checkpoint().map(Some) + } + GetCheckpointSummaryRequest::ByDigest(digest) => { + self.store.get_checkpoint_by_digest(digest) + } + GetCheckpointSummaryRequest::BySequenceNumber(sequence_number) => self + .store + .get_checkpoint_by_sequence_number(*sequence_number), + } + .map_err(|e| Status::internal(e.to_string()))? + .map(VerifiedCheckpoint::into_inner); + + Ok(Response::new(checkpoint)) + } + + async fn get_checkpoint_availability( + &self, + _request: Request<()>, + ) -> Result, Status> { + let highest_synced_checkpoint = self + .store + .get_highest_synced_checkpoint() + .map_err(|e| Status::internal(e.to_string())) + .map(VerifiedCheckpoint::into_inner)?; + let lowest_available_checkpoint = self + .store + .get_lowest_available_checkpoint() + .map_err(|e| Status::internal(e.to_string()))?; + + Ok(Response::new(GetCheckpointAvailabilityResponse { + highest_synced_checkpoint, + lowest_available_checkpoint, + })) + } + + async fn get_checkpoint_contents( + &self, + request: Request, + ) -> Result>, Status> { + let contents = self + .store + .get_full_checkpoint_contents(request.inner()) + .map_err(|e| Status::internal(e.to_string()))?; + Ok(Response::new(contents)) + } +} + +/// [`Layer`] for adding a per-checkpoint limit to the number of inflight +/// GetCheckpointContent requests. +#[derive(Clone)] +pub(super) struct CheckpointContentsDownloadLimitLayer { + inflight_per_checkpoint: Arc>>, + max_inflight_per_checkpoint: usize, +} + +impl CheckpointContentsDownloadLimitLayer { + pub(super) fn new(max_inflight_per_checkpoint: usize) -> Self { + Self { + inflight_per_checkpoint: Arc::new(DashMap::new()), + max_inflight_per_checkpoint, + } + } + + pub(super) fn maybe_prune_map(&self) { + const PRUNE_THRESHOLD: usize = 5000; + if self.inflight_per_checkpoint.len() >= PRUNE_THRESHOLD { + self.inflight_per_checkpoint.retain(|_, semaphore| { + semaphore.available_permits() < self.max_inflight_per_checkpoint + }); + } + } +} + +impl tower::layer::Layer for CheckpointContentsDownloadLimitLayer { + type Service = CheckpointContentsDownloadLimit; + + fn layer(&self, inner: S) -> Self::Service { + CheckpointContentsDownloadLimit { + inner, + inflight_per_checkpoint: self.inflight_per_checkpoint.clone(), + max_inflight_per_checkpoint: self.max_inflight_per_checkpoint, + } + } +} + +/// Middleware for adding a per-checkpoint limit to the number of inflight +/// GetCheckpointContent requests. +#[derive(Clone)] +pub(super) struct CheckpointContentsDownloadLimit { + inner: S, + inflight_per_checkpoint: Arc>>, + max_inflight_per_checkpoint: usize, +} + +impl tower::Service> for CheckpointContentsDownloadLimit +where + S: tower::Service< + Request, + Response = Response>, + Error = Status, + > + + 'static + + Clone + + Send, + >>::Future: Send, + Request: 'static + Send + Sync, +{ + type Response = Response>; + type Error = S::Error; + type Future = BoxFuture<'static, Result>; + + #[inline] + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_ready(cx) + } + + fn call(&mut self, req: Request) -> Self::Future { + let inflight_per_checkpoint = self.inflight_per_checkpoint.clone(); + let max_inflight_per_checkpoint = self.max_inflight_per_checkpoint; + let mut inner = self.inner.clone(); + + let fut = async move { + let semaphore = { + let semaphore_entry = inflight_per_checkpoint + .entry(*req.body()) + .or_insert_with(|| Arc::new(Semaphore::new(max_inflight_per_checkpoint))); + semaphore_entry.value().clone() + }; + let permit = semaphore.try_acquire_owned().map_err(|e| match e { + tokio::sync::TryAcquireError::Closed => { + anemo::rpc::Status::new(StatusCode::InternalServerError) + } + tokio::sync::TryAcquireError::NoPermits => { + anemo::rpc::Status::new(StatusCode::TooManyRequests) + } + })?; + + struct SemaphoreExtension(OwnedSemaphorePermit); + inner.call(req).await.map(move |mut response| { + // Insert permit as extension so it's not dropped until the response is sent. + response.extensions_mut().insert(SemaphoreExtension(permit)); + response + }) + }; + Box::pin(fut) + } +} diff --git a/crates/iota-network/src/state_sync/tests.rs b/crates/iota-network/src/state_sync/tests.rs new file mode 100644 index 00000000000..effc7c216a9 --- /dev/null +++ b/crates/iota-network/src/state_sync/tests.rs @@ -0,0 +1,928 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::HashMap, num::NonZeroUsize, time::Duration}; + +use anemo::{PeerId, Request}; +use anyhow::anyhow; +use iota_archival::{reader::ArchiveReaderBalancer, writer::ArchiveWriter}; +use iota_config::{ + node::ArchiveReaderConfig, + object_storage_config::{ObjectStoreConfig, ObjectStoreType}, +}; +use iota_storage::{FileCompression, StorageFormat}; +use iota_swarm_config::test_utils::{empty_contents, CommitteeFixture}; +use iota_types::{ + messages_checkpoint::CheckpointDigest, + storage::{ReadStore, SharedInMemoryStore, WriteStore}, +}; +use prometheus::Registry; +use tempfile::tempdir; +use tokio::time::{timeout, Instant}; + +use crate::{ + state_sync::{ + Builder, GetCheckpointSummaryRequest, PeerStateSyncInfo, StateSync, StateSyncMessage, + UnstartedStateSync, + }, + utils::build_network, +}; + +#[tokio::test] +async fn server_push_checkpoint() { + let committee = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); + let (ordered_checkpoints, _, _sequence_number_to_digest, _checkpoints) = + committee.make_empty_checkpoints(2, None); + let store = SharedInMemoryStore::default(); + store.inner_mut().insert_genesis_state( + ordered_checkpoints.first().cloned().unwrap(), + empty_contents(), + committee.committee().to_owned(), + ); + + let ( + UnstartedStateSync { + handle: _handle, + mut mailbox, + peer_heights, + .. + }, + server, + ) = Builder::new().store(store).build_internal(); + let peer_id = PeerId([9; 32]); // fake PeerId + + peer_heights.write().unwrap().peers.insert( + peer_id, + PeerStateSyncInfo { + genesis_checkpoint_digest: *ordered_checkpoints[0].digest(), + on_same_chain_as_us: true, + height: 0, + lowest: 0, + }, + ); + + let checkpoint = ordered_checkpoints[1].inner().to_owned(); + let request = Request::new(checkpoint.clone()).with_extension(peer_id); + server.push_checkpoint_summary(request).await.unwrap(); + + assert_eq!( + peer_heights.read().unwrap().peers.get(&peer_id), + Some(&PeerStateSyncInfo { + genesis_checkpoint_digest: *ordered_checkpoints[0].digest(), + on_same_chain_as_us: true, + height: 1, + lowest: 0, + }) + ); + assert_eq!( + peer_heights + .read() + .unwrap() + .unprocessed_checkpoints + .get(checkpoint.digest()) + .unwrap() + .data(), + checkpoint.data(), + ); + assert_eq!( + peer_heights + .read() + .unwrap() + .highest_known_checkpoint() + .unwrap() + .data(), + checkpoint.data(), + ); + assert!(matches!( + mailbox.try_recv().unwrap(), + StateSyncMessage::StartSyncJob + )); +} + +#[tokio::test] +async fn server_get_checkpoint() { + let committee = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); + let (ordered_checkpoints, _, _sequence_number_to_digest, _checkpoints) = + committee.make_empty_checkpoints(3, None); + + let (builder, server) = Builder::new() + .store(SharedInMemoryStore::default()) + .build_internal(); + + builder.store.inner_mut().insert_genesis_state( + ordered_checkpoints.first().cloned().unwrap(), + empty_contents(), + committee.committee().to_owned(), + ); + + // Requests for the Latest checkpoint should return the genesis checkpoint + let response = server + .get_checkpoint_summary(Request::new(GetCheckpointSummaryRequest::Latest)) + .await + .unwrap() + .into_inner(); + assert_eq!( + response.unwrap().data(), + ordered_checkpoints.first().unwrap().data(), + ); + + // Requests for checkpoints that aren't in the server's store + let requests = [ + GetCheckpointSummaryRequest::BySequenceNumber(9), + GetCheckpointSummaryRequest::ByDigest(CheckpointDigest::new([10; 32])), + ]; + for request in requests { + let response = server + .get_checkpoint_summary(Request::new(request)) + .await + .unwrap() + .into_inner(); + assert!(response.is_none()); + } + + // Populate the node's store with some checkpoints + for checkpoint in ordered_checkpoints.clone() { + builder.store.inner_mut().insert_checkpoint(&checkpoint) + } + let latest = ordered_checkpoints.last().unwrap().clone(); + builder + .store + .inner_mut() + .update_highest_synced_checkpoint(&latest); + + let request = Request::new(GetCheckpointSummaryRequest::Latest); + let response = server + .get_checkpoint_summary(request) + .await + .unwrap() + .into_inner() + .unwrap(); + assert_eq!(response.data(), latest.data()); + + for checkpoint in ordered_checkpoints { + let request = Request::new(GetCheckpointSummaryRequest::ByDigest(*checkpoint.digest())); + let response = server + .get_checkpoint_summary(request) + .await + .unwrap() + .into_inner() + .unwrap(); + assert_eq!(response.data(), checkpoint.data()); + + let request = Request::new(GetCheckpointSummaryRequest::BySequenceNumber( + *checkpoint.sequence_number(), + )); + let response = server + .get_checkpoint_summary(request) + .await + .unwrap() + .into_inner() + .unwrap(); + assert_eq!(response.data(), checkpoint.data()); + } +} + +#[tokio::test] +async fn isolated_sync_job() { + let committee = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); + // build mock data + let (ordered_checkpoints, _, sequence_number_to_digest, checkpoints) = + committee.make_empty_checkpoints(100, None); + + // Build and connect two nodes + let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); + let network_1 = build_network(|router| router.add_rpc_service(server)); + let (mut event_loop_1, _handle_1) = builder.build(network_1.clone()); + let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); + let network_2 = build_network(|router| router.add_rpc_service(server)); + let (event_loop_2, _handle_2) = builder.build(network_2.clone()); + network_1.connect(network_2.local_addr()).await.unwrap(); + + // Init the root committee in both nodes + event_loop_1.store.inner_mut().insert_genesis_state( + ordered_checkpoints.first().cloned().unwrap(), + empty_contents(), + committee.committee().to_owned(), + ); + event_loop_2.store.inner_mut().insert_genesis_state( + ordered_checkpoints.first().cloned().unwrap(), + empty_contents(), + committee.committee().to_owned(), + ); + + // Node 2 will have all the data + { + let mut store = event_loop_2.store.inner_mut(); + for checkpoint in ordered_checkpoints.clone() { + store.insert_checkpoint(&checkpoint); + } + } + + // Node 1 will know that Node 2 has the data + event_loop_1.peer_heights.write().unwrap().peers.insert( + network_2.peer_id(), + PeerStateSyncInfo { + genesis_checkpoint_digest: *ordered_checkpoints[0].digest(), + on_same_chain_as_us: true, + height: *ordered_checkpoints.last().unwrap().sequence_number(), + lowest: 0, + }, + ); + event_loop_1 + .peer_heights + .write() + .unwrap() + .insert_checkpoint(ordered_checkpoints.last().cloned().unwrap().into_inner()); + + // Sync the data + event_loop_1.maybe_start_checkpoint_summary_sync_task(); + event_loop_1.tasks.join_next().await.unwrap().unwrap(); + assert_eq!( + ordered_checkpoints.last().map(|x| x.data()), + Some( + event_loop_1 + .store + .get_highest_verified_checkpoint() + .unwrap() + .data() + ) + ); + + { + let store = event_loop_1.store.inner(); + let expected = checkpoints + .iter() + .map(|(key, value)| (key, value.data())) + .collect::>(); + let actual = store + .checkpoints() + .iter() + .map(|(key, value)| (key, value.data())) + .collect::>(); + assert_eq!(actual, expected); + assert_eq!( + store.checkpoint_sequence_number_to_digest(), + &sequence_number_to_digest + ); + } +} + +#[tokio::test] +async fn test_state_sync_using_archive() -> anyhow::Result<()> { + let committee = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); + // build mock data + let (ordered_checkpoints, _, sequence_number_to_digest, checkpoints) = + committee.make_empty_checkpoints(100, None); + // Initialize archive store with all checkpoints + let temp_dir = tempdir()?.into_path(); + let local_path = temp_dir.join("local_dir"); + let remote_path = temp_dir.join("remote_dir"); + let local_store_config = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(local_path.clone()), + ..Default::default() + }; + let remote_store_config = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(remote_path.clone()), + ..Default::default() + }; + let archive_writer = ArchiveWriter::new( + local_store_config.clone(), + remote_store_config.clone(), + FileCompression::Zstd, + StorageFormat::Blob, + Duration::from_secs(10), + 20, + &Registry::default(), + ) + .await?; + let test_store = SharedInMemoryStore::default(); + test_store.inner_mut().insert_genesis_state( + ordered_checkpoints.first().cloned().unwrap(), + empty_contents(), + committee.committee().to_owned(), + ); + // We ensure that only a part of the data exists in the archive store (and no + // new checkpoints after sequence number >= 50 are written to the archive + // store). This is to test the fact that a node can download latest + // checkpoints from a peer and back fill missing older data from archive + for checkpoint in &ordered_checkpoints[0..50] { + test_store.inner_mut().insert_checkpoint(checkpoint); + } + let kill = archive_writer.start(test_store).await?; + let archive_reader_config = ArchiveReaderConfig { + remote_store_config, + download_concurrency: NonZeroUsize::new(1).unwrap(), + use_for_pruning_watermark: false, + }; + // We will delete all checkpoints older than this checkpoint on Node 2 + let oldest_checkpoint_to_keep: u64 = 10; + let archive_readers = + ArchiveReaderBalancer::new(vec![archive_reader_config], &Registry::default())?; + let archive_reader = archive_readers.pick_one_random(0..u64::MAX).await.unwrap(); + loop { + archive_reader.sync_manifest_once().await?; + if let Ok(latest_available_checkpoint_in_archive) = + archive_reader.latest_available_checkpoint().await + { + // We only need enough checkpoints to be in archive store for this test + if latest_available_checkpoint_in_archive >= oldest_checkpoint_to_keep { + break; + } + } + tokio::time::sleep(Duration::from_secs(1)).await; + } + // Build and connect two nodes where Node 1 will be given access to an archive + // store Node 2 will prune older checkpoints, so Node 1 is forced to + // backfill from the archive + let (builder, server) = Builder::new() + .store(SharedInMemoryStore::default()) + .archive_readers(archive_readers) + .build(); + let network_1 = build_network(|router| router.add_rpc_service(server)); + let (event_loop_1, _handle_1) = builder.build(network_1.clone()); + let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); + let network_2 = build_network(|router| router.add_rpc_service(server)); + let (event_loop_2, _handle_2) = builder.build(network_2.clone()); + network_1.connect(network_2.local_addr()).await.unwrap(); + + // Init the root committee in both nodes + event_loop_1.store.inner_mut().insert_genesis_state( + ordered_checkpoints.first().cloned().unwrap(), + empty_contents(), + committee.committee().to_owned(), + ); + event_loop_2.store.inner_mut().insert_genesis_state( + ordered_checkpoints.first().cloned().unwrap(), + empty_contents(), + committee.committee().to_owned(), + ); + + // Node 2 will have all the data at first + { + let mut store = event_loop_2.store.inner_mut(); + for checkpoint in ordered_checkpoints.clone() { + store.insert_checkpoint(&checkpoint); + store.insert_checkpoint_contents(&checkpoint, empty_contents()); + store.update_highest_synced_checkpoint(&checkpoint); + } + } + // Prune first 10 checkpoint contents from Node 2 + { + let mut store = event_loop_2.store.inner_mut(); + for checkpoint in &ordered_checkpoints[0..(oldest_checkpoint_to_keep as usize)] { + store.delete_checkpoint_content_test_only(checkpoint.sequence_number)?; + } + // Now Node 2 has deleted checkpoint contents from range [0, 10) on local store + assert_eq!( + store.get_lowest_available_checkpoint(), + oldest_checkpoint_to_keep + ); + assert_eq!( + store + .get_highest_synced_checkpoint() + .unwrap() + .sequence_number, + ordered_checkpoints.last().unwrap().sequence_number + ); + assert_eq!( + store + .get_highest_verified_checkpoint() + .unwrap() + .sequence_number, + ordered_checkpoints.last().unwrap().sequence_number + ); + } + + // Node 1 will know that Node 2 has the data starting checkpoint 10 + event_loop_1.peer_heights.write().unwrap().peers.insert( + network_2.peer_id(), + PeerStateSyncInfo { + genesis_checkpoint_digest: *ordered_checkpoints[0].digest(), + on_same_chain_as_us: true, + height: *ordered_checkpoints.last().unwrap().sequence_number(), + lowest: oldest_checkpoint_to_keep, + }, + ); + + // Get handle to node 1 store + let store_1 = event_loop_1.store.clone(); + + // Sync the data + // Start both event loops + tokio::spawn(event_loop_1.start()); + tokio::spawn(event_loop_2.start()); + + let total_time = Instant::now(); + loop { + { + let store = store_1.inner(); + if let Some(highest_synced_checkpoint) = store.get_highest_synced_checkpoint() { + if highest_synced_checkpoint.sequence_number + == ordered_checkpoints.last().unwrap().sequence_number + { + // Node 1 is fully synced to the latest checkpoint on Node 2 + let expected = checkpoints + .iter() + .map(|(key, value)| (key, value.data())) + .collect::>(); + let actual = store + .checkpoints() + .iter() + .map(|(key, value)| (key, value.data())) + .collect::>(); + assert_eq!(actual, expected); + assert_eq!( + store.checkpoint_sequence_number_to_digest(), + &sequence_number_to_digest + ); + break; + } + } + } + if total_time.elapsed() > Duration::from_secs(120) { + return Err(anyhow!("Test timed out")); + } + tokio::time::sleep(Duration::from_secs(1)).await; + } + kill.send(())?; + Ok(()) +} + +#[tokio::test] +async fn sync_with_checkpoints_being_inserted() { + telemetry_subscribers::init_for_testing(); + let committee = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); + // build mock data + let (ordered_checkpoints, _contents, sequence_number_to_digest, checkpoints) = + committee.make_empty_checkpoints(4, None); + + // Build and connect two nodes + let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); + let network_1 = build_network(|router| router.add_rpc_service(server)); + let (event_loop_1, handle_1) = builder.build(network_1.clone()); + let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); + let network_2 = build_network(|router| router.add_rpc_service(server)); + let (event_loop_2, handle_2) = builder.build(network_2.clone()); + network_1.connect(network_2.local_addr()).await.unwrap(); + + // Init the root committee in both nodes + event_loop_1.store.inner_mut().insert_genesis_state( + ordered_checkpoints.first().cloned().unwrap(), + empty_contents(), + committee.committee().to_owned(), + ); + event_loop_2.store.inner_mut().insert_genesis_state( + ordered_checkpoints.first().cloned().unwrap(), + empty_contents(), + committee.committee().to_owned(), + ); + + // get handles to each node's stores + let store_1 = event_loop_1.store.clone(); + let store_2 = event_loop_2.store.clone(); + // make sure that node_1 knows about node_2 + event_loop_1.peer_heights.write().unwrap().peers.insert( + network_2.peer_id(), + PeerStateSyncInfo { + genesis_checkpoint_digest: *ordered_checkpoints[0].digest(), + on_same_chain_as_us: true, + height: 0, + lowest: 0, + }, + ); + // Start both event loops + tokio::spawn(event_loop_1.start()); + tokio::spawn(event_loop_2.start()); + + let mut subscriber_1 = handle_1.subscribe_to_synced_checkpoints(); + let mut subscriber_2 = handle_2.subscribe_to_synced_checkpoints(); + + // Inject one checkpoint and verify that it was shared with the other node + let mut checkpoint_iter = ordered_checkpoints.clone().into_iter().skip(1); + let checkpoint = checkpoint_iter.next().unwrap(); + store_1 + .insert_checkpoint_contents(&checkpoint, empty_contents()) + .unwrap(); + store_1.insert_certified_checkpoint(&checkpoint); + handle_1.send_checkpoint(checkpoint).await; + + timeout(Duration::from_secs(1), async { + assert_eq!( + subscriber_1.recv().await.unwrap().data(), + ordered_checkpoints[1].data(), + ); + assert_eq!( + subscriber_2.recv().await.unwrap().data(), + ordered_checkpoints[1].data() + ); + }) + .await + .unwrap(); + + // Inject all the checkpoints + for checkpoint in checkpoint_iter { + store_1.insert_certified_checkpoint(&checkpoint); + handle_1.send_checkpoint(checkpoint).await; + } + + timeout(Duration::from_secs(1), async { + for checkpoint in &ordered_checkpoints[2..] { + assert_eq!(subscriber_1.recv().await.unwrap().data(), checkpoint.data()); + assert_eq!(subscriber_2.recv().await.unwrap().data(), checkpoint.data()); + } + }) + .await + .unwrap(); + + let store_1 = store_1.inner(); + let store_2 = store_2.inner(); + assert_eq!( + ordered_checkpoints.last().map(|x| x.digest()), + store_1 + .get_highest_verified_checkpoint() + .as_ref() + .map(|x| x.digest()) + ); + assert_eq!( + ordered_checkpoints.last().map(|x| x.digest()), + store_2 + .get_highest_verified_checkpoint() + .as_ref() + .map(|x| x.digest()) + ); + + let expected = checkpoints + .iter() + .map(|(key, value)| (key, value.data())) + .collect::>(); + let actual_1 = store_1 + .checkpoints() + .iter() + .map(|(key, value)| (key, value.data())) + .collect::>(); + assert_eq!(actual_1, expected); + assert_eq!( + store_1.checkpoint_sequence_number_to_digest(), + &sequence_number_to_digest + ); + + let actual_2 = store_2 + .checkpoints() + .iter() + .map(|(key, value)| (key, value.data())) + .collect::>(); + assert_eq!(actual_2, expected); + assert_eq!( + store_2.checkpoint_sequence_number_to_digest(), + &sequence_number_to_digest + ); +} + +#[tokio::test] +async fn sync_with_checkpoints_watermark() { + telemetry_subscribers::init_for_testing(); + let committee = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); + // build mock data + let (ordered_checkpoints, contents, _sequence_number_to_digest, _checkpoints) = + committee.make_random_checkpoints(4, None); + let last_checkpoint_seq = *ordered_checkpoints + .last() + .cloned() + .unwrap() + .sequence_number(); + // Build and connect two nodes + let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); + let network_1 = build_network(|router| router.add_rpc_service(server)); + let (event_loop_1, handle_1) = builder.build(network_1.clone()); + let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); + let network_2 = build_network(|router| router.add_rpc_service(server)); + let (event_loop_2, handle_2) = builder.build(network_2.clone()); + + // Init the root committee in both nodes + let genesis_checkpoint_content = contents.first().cloned().unwrap(); + event_loop_1.store.inner_mut().insert_genesis_state( + ordered_checkpoints.first().cloned().unwrap(), + genesis_checkpoint_content.clone(), + committee.committee().to_owned(), + ); + event_loop_2.store.inner_mut().insert_genesis_state( + ordered_checkpoints.first().cloned().unwrap(), + genesis_checkpoint_content.clone(), + committee.committee().to_owned(), + ); + + // get handles to each node's stores + let store_1 = event_loop_1.store.clone(); + let store_2 = event_loop_2.store.clone(); + let peer_id_1 = network_1.peer_id(); + + let peer_heights_1 = event_loop_1.peer_heights.clone(); + let peer_heights_2 = event_loop_2.peer_heights.clone(); + peer_heights_1 + .write() + .unwrap() + .set_wait_interval_when_no_peer_to_sync_content(Duration::from_secs(1)); + peer_heights_2 + .write() + .unwrap() + .set_wait_interval_when_no_peer_to_sync_content(Duration::from_secs(1)); + + // Start both event loops + tokio::spawn(event_loop_1.start()); + tokio::spawn(event_loop_2.start()); + + let mut subscriber_1 = handle_1.subscribe_to_synced_checkpoints(); + let mut subscriber_2 = handle_2.subscribe_to_synced_checkpoints(); + + network_1.connect(network_2.local_addr()).await.unwrap(); + + // Inject one checkpoint and verify that it was shared with the other node + let mut checkpoint_iter = ordered_checkpoints.clone().into_iter().skip(1); + let mut contents_iter = contents.clone().into_iter().skip(1); + let checkpoint_1 = checkpoint_iter.next().unwrap(); + let contents_1 = contents_iter.next().unwrap(); + let checkpoint_seq = checkpoint_1.sequence_number(); + store_1 + .insert_checkpoint_contents(&checkpoint_1, contents_1.clone()) + .unwrap(); + store_1.insert_certified_checkpoint(&checkpoint_1); + handle_1.send_checkpoint(checkpoint_1.clone()).await; + + timeout(Duration::from_secs(3), async { + assert_eq!( + subscriber_1.recv().await.unwrap().data(), + ordered_checkpoints[1].data(), + ); + assert_eq!( + subscriber_2.recv().await.unwrap().data(), + ordered_checkpoints[1].data() + ); + }) + .await + .unwrap(); + + assert_eq!( + store_1 + .get_highest_synced_checkpoint() + .unwrap() + .sequence_number(), + checkpoint_seq + ); + assert_eq!( + store_2 + .get_highest_synced_checkpoint() + .unwrap() + .sequence_number(), + checkpoint_seq + ); + assert_eq!( + store_1 + .get_highest_verified_checkpoint() + .unwrap() + .sequence_number(), + &1 + ); + assert_eq!( + store_2 + .get_highest_verified_checkpoint() + .unwrap() + .sequence_number(), + &1 + ); + + // So far so good. + // Now we increase Peer 1's low watermark to a high number. + let a_very_high_checkpoint_seq = 1000; + store_1 + .inner_mut() + .set_lowest_available_checkpoint(a_very_high_checkpoint_seq); + + assert!(peer_heights_2.write().unwrap().update_peer_info( + peer_id_1, + checkpoint_1.clone().into(), + Some(a_very_high_checkpoint_seq), + )); + + // Inject all the checkpoints to Peer 1 + for (checkpoint, contents) in checkpoint_iter.zip(contents_iter) { + store_1 + .insert_checkpoint_contents(&checkpoint, contents) + .unwrap(); + store_1.insert_certified_checkpoint(&checkpoint); + handle_1.send_checkpoint(checkpoint).await; + } + + // Peer 1 has all the checkpoint contents, but not Peer 2 + timeout(Duration::from_secs(1), async { + for (checkpoint, contents) in ordered_checkpoints[2..] + .iter() + .zip(contents.clone().into_iter().skip(2)) + { + assert_eq!(subscriber_1.recv().await.unwrap().data(), checkpoint.data()); + let content_digest = contents.into_checkpoint_contents_digest(); + store_1 + .get_full_checkpoint_contents(&content_digest) + .unwrap() + .unwrap(); + assert_eq!( + store_2 + .get_full_checkpoint_contents(&content_digest) + .unwrap(), + None + ); + } + }) + .await + .unwrap(); + subscriber_2.try_recv().unwrap_err(); + + assert_eq!( + store_1 + .get_highest_synced_checkpoint() + .unwrap() + .sequence_number(), + ordered_checkpoints.last().unwrap().sequence_number() + ); + assert_eq!( + store_2 + .get_highest_synced_checkpoint() + .unwrap() + .sequence_number(), + ordered_checkpoints[1].sequence_number() + ); + + assert_eq!( + store_1 + .get_highest_verified_checkpoint() + .unwrap() + .sequence_number(), + &last_checkpoint_seq + ); + + // Add Peer 3 + let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); + let network_3 = build_network(|router| router.add_rpc_service(server)); + let (event_loop_3, handle_3) = builder.build(network_3.clone()); + + let mut subscriber_3 = handle_3.subscribe_to_synced_checkpoints(); + network_3.connect(network_1.local_addr()).await.unwrap(); + network_3.connect(network_2.local_addr()).await.unwrap(); + let store_3 = event_loop_3.store.clone(); + let peer_heights_3 = event_loop_3.peer_heights.clone(); + peer_heights_3 + .write() + .unwrap() + .set_wait_interval_when_no_peer_to_sync_content(Duration::from_secs(1)); + event_loop_3.store.inner_mut().insert_genesis_state( + ordered_checkpoints.first().cloned().unwrap(), + genesis_checkpoint_content.clone(), + committee.committee().to_owned(), + ); + tokio::spawn(event_loop_3.start()); + + // Peer 3 is able to sync checkpoint 1 with teh help from Peer 2 + timeout(Duration::from_secs(1), async { + assert_eq!( + subscriber_3.recv().await.unwrap().data(), + ordered_checkpoints[1].data() + ); + let content_digest = contents[1].clone().into_checkpoint_contents_digest(); + store_3 + .get_full_checkpoint_contents(&content_digest) + .unwrap() + .unwrap(); + }) + .await + .unwrap(); + subscriber_3.try_recv().unwrap_err(); + subscriber_2.try_recv().unwrap_err(); + + assert_eq!( + store_2 + .get_highest_synced_checkpoint() + .unwrap() + .sequence_number(), + ordered_checkpoints[1].sequence_number(), + ); + assert_eq!( + store_3 + .get_highest_synced_checkpoint() + .unwrap() + .sequence_number(), + ordered_checkpoints[1].sequence_number(), + ); + + // Now set Peer 1's low watermark back to 0 + store_1.inner_mut().set_lowest_available_checkpoint(0); + + // Peer 2 and Peer 3 will know about this change by + // `get_checkpoint_availability` Soon we expect them to have all + // checkpoints's content. + timeout(Duration::from_secs(6), async { + for (checkpoint, contents) in ordered_checkpoints[2..] + .iter() + .zip(contents.clone().into_iter().skip(2)) + { + assert_eq!(subscriber_2.recv().await.unwrap().data(), checkpoint.data()); + assert_eq!(subscriber_3.recv().await.unwrap().data(), checkpoint.data()); + let content_digest = contents.into_checkpoint_contents_digest(); + store_2 + .get_full_checkpoint_contents(&content_digest) + .unwrap() + .unwrap(); + store_3 + .get_full_checkpoint_contents(&content_digest) + .unwrap() + .unwrap(); + } + }) + .await + .unwrap(); + assert_eq!( + store_2 + .get_highest_synced_checkpoint() + .unwrap() + .sequence_number(), + &last_checkpoint_seq + ); + assert_eq!( + store_3 + .get_highest_synced_checkpoint() + .unwrap() + .sequence_number(), + &last_checkpoint_seq + ); + assert_eq!( + store_2 + .get_highest_verified_checkpoint() + .unwrap() + .sequence_number(), + &last_checkpoint_seq + ); + assert_eq!( + store_3 + .get_highest_verified_checkpoint() + .unwrap() + .sequence_number(), + &last_checkpoint_seq + ); + + // Now set Peer 1 and 2's low watermark to a very high number + store_1 + .inner_mut() + .set_lowest_available_checkpoint(a_very_high_checkpoint_seq); + + store_2 + .inner_mut() + .set_lowest_available_checkpoint(a_very_high_checkpoint_seq); + + // Start Peer 4 + let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); + let network_4 = build_network(|router| router.add_rpc_service(server)); + let (event_loop_4, handle_4) = builder.build(network_4.clone()); + + let mut subscriber_4 = handle_4.subscribe_to_synced_checkpoints(); + let store_4 = event_loop_4.store.clone(); + let peer_heights_4 = event_loop_4.peer_heights.clone(); + peer_heights_4 + .write() + .unwrap() + .set_wait_interval_when_no_peer_to_sync_content(Duration::from_secs(1)); + event_loop_4.store.inner_mut().insert_genesis_state( + ordered_checkpoints.first().cloned().unwrap(), + genesis_checkpoint_content, + committee.committee().to_owned(), + ); + tokio::spawn(event_loop_4.start()); + // Need to connect 4 to 1, 2, 3 manually, as it does not have discovery enabled + network_4.connect(network_1.local_addr()).await.unwrap(); + network_4.connect(network_2.local_addr()).await.unwrap(); + network_4.connect(network_3.local_addr()).await.unwrap(); + + // Peer 4 syncs everything with Peer 3 + timeout(Duration::from_secs(3), async { + for (checkpoint, contents) in ordered_checkpoints[1..] + .iter() + .zip(contents.clone().into_iter().skip(1)) + { + assert_eq!(subscriber_4.recv().await.unwrap().data(), checkpoint.data()); + let content_digest = contents.into_checkpoint_contents_digest(); + store_4 + .get_full_checkpoint_contents(&content_digest) + .unwrap() + .unwrap(); + } + }) + .await + .unwrap(); + assert_eq!( + store_4 + .get_highest_synced_checkpoint() + .unwrap() + .sequence_number(), + &last_checkpoint_seq + ); +} diff --git a/crates/iota-network/src/utils.rs b/crates/iota-network/src/utils.rs new file mode 100644 index 00000000000..4ba2c222be7 --- /dev/null +++ b/crates/iota-network/src/utils.rs @@ -0,0 +1,45 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(test)] +pub fn build_network(f: impl FnOnce(anemo::Router) -> anemo::Router) -> anemo::Network { + build_network_impl(f, None) +} + +#[cfg(test)] +pub fn build_network_with_anemo_config( + f: impl FnOnce(anemo::Router) -> anemo::Router, + anemo_config: anemo::Config, +) -> anemo::Network { + build_network_impl(f, Some(anemo_config)) +} + +#[cfg(test)] +fn build_network_impl( + f: impl FnOnce(anemo::Router) -> anemo::Router, + anemo_config: Option, +) -> anemo::Network { + let router = f(anemo::Router::new()); + let network = anemo::Network::bind("localhost:0") + .private_key(random_key()) + .config(anemo_config.unwrap_or_default()) + .server_name("test") + .start(router) + .unwrap(); + + println!( + "starting network {} {}", + network.local_addr(), + network.peer_id(), + ); + network +} + +#[cfg(test)] +fn random_key() -> [u8; 32] { + let mut rng = rand::thread_rng(); + let mut bytes = [0u8; 32]; + rand::RngCore::fill_bytes(&mut rng, &mut bytes[..]); + bytes +} diff --git a/crates/iota-node/Cargo.toml b/crates/iota-node/Cargo.toml new file mode 100644 index 00000000000..2978ce03834 --- /dev/null +++ b/crates/iota-node/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "iota-node" +version.workspace = true +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anemo.workspace = true +anemo-tower.workspace = true +arc-swap.workspace = true +axum.workspace = true +anyhow.workspace = true +clap.workspace = true +prometheus.workspace = true +tokio = { workspace = true, features = ["full"] } +tracing.workspace = true +futures.workspace = true +tower.workspace = true +reqwest.workspace = true +tap.workspace = true +serde.workspace = true +snap.workspace = true +git-version.workspace = true +const-str.workspace = true +url.workspace = true +humantime.workspace = true + +iota-archival.workspace = true +iota-tls.workspace = true +iota-macros.workspace = true +iota-config.workspace = true +iota-core.workspace = true +iota-rest-api.workspace = true +iota-storage.workspace = true +iota-network.workspace = true +iota-json-rpc.workspace = true +iota-json-rpc-api.workspace = true +iota-protocol-config.workspace = true +iota-snapshot.workspace = true +iota-telemetry.workspace = true +iota-types.workspace = true +mysten-metrics.workspace = true +mysten-common.workspace = true +narwhal-network.workspace = true +narwhal-worker.workspace = true +typed-store.workspace = true +mysten-network.workspace = true +telemetry-subscribers.workspace = true +fastcrypto.workspace = true +fastcrypto-zkp.workspace = true +move-vm-profiler.workspace = true + +[target.'cfg(msim)'.dependencies] +iota-simulator.workspace = true diff --git a/crates/iota-node/src/admin.rs b/crates/iota-node/src/admin.rs new file mode 100644 index 00000000000..647d7c359d0 --- /dev/null +++ b/crates/iota-node/src/admin.rs @@ -0,0 +1,296 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + net::{IpAddr, Ipv4Addr, SocketAddr}, + sync::Arc, +}; + +use axum::{ + extract::{Query, State}, + http::StatusCode, + routing::{get, post}, + Router, +}; +use humantime::parse_duration; +use iota_types::error::IotaError; +use serde::Deserialize; +use telemetry_subscribers::TracingHandle; +use tracing::info; + +use crate::IotaNode; + +// Example commands: +// +// Set buffer stake for current epoch 2 to 1500 basis points: +// +// $ curl -X POST 'http://127.0.0.1:1337/set-override-buffer-stake?buffer_bps=1500&epoch=2' +// +// Clear buffer stake override for current epoch 2, use +// ProtocolConfig::buffer_stake_for_protocol_upgrade_bps: +// +// $ curl -X POST 'http://127.0.0.1:1337/clear-override-buffer-stake?epoch=2' +// +// Vote to close epoch 2 early +// +// $ curl -X POST 'http://127.0.0.1:1337/force-close-epoch?epoch=2' +// +// View current all capabilities from all authorities that have been received by +// this node: +// +// $ curl 'http://127.0.0.1:1337/capabilities' +// +// View the node config (private keys will be masked): +// +// $ curl 'http://127.0.0.1:1337/node-config' +// +// Set a time-limited tracing config. After the duration expires, tracing will +// be disabled automatically. +// +// $ curl -X POST 'http://127.0.0.1:1337/enable-tracing?filter=info&duration=10s' +// +// Reset tracing to the TRACE_FILTER env var. +// +// $ curl -X POST 'http://127.0.0.1:1337/reset-tracing' + +const LOGGING_ROUTE: &str = "/logging"; +const TRACING_ROUTE: &str = "/enable-tracing"; +const TRACING_RESET_ROUTE: &str = "/reset-tracing"; +const SET_BUFFER_STAKE_ROUTE: &str = "/set-override-buffer-stake"; +const CLEAR_BUFFER_STAKE_ROUTE: &str = "/clear-override-buffer-stake"; +const FORCE_CLOSE_EPOCH: &str = "/force-close-epoch"; +const CAPABILITIES: &str = "/capabilities"; +const NODE_CONFIG: &str = "/node-config"; + +struct AppState { + node: Arc, + tracing_handle: TracingHandle, +} + +pub async fn run_admin_server(node: Arc, port: u16, tracing_handle: TracingHandle) { + let filter = tracing_handle.get_log().unwrap(); + + let app_state = AppState { + node, + tracing_handle, + }; + + let app = Router::new() + .route(LOGGING_ROUTE, get(get_filter)) + .route(CAPABILITIES, get(capabilities)) + .route(NODE_CONFIG, get(node_config)) + .route(LOGGING_ROUTE, post(set_filter)) + .route( + SET_BUFFER_STAKE_ROUTE, + post(set_override_protocol_upgrade_buffer_stake), + ) + .route( + CLEAR_BUFFER_STAKE_ROUTE, + post(clear_override_protocol_upgrade_buffer_stake), + ) + .route(FORCE_CLOSE_EPOCH, post(force_close_epoch)) + .route(TRACING_ROUTE, post(enable_tracing)) + .route(TRACING_RESET_ROUTE, post(reset_tracing)) + .with_state(Arc::new(app_state)); + + let socket_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port); + info!( + filter =% filter, + address =% socket_address, + "starting admin server" + ); + + axum::Server::bind(&socket_address) + .serve(app.into_make_service()) + .await + .unwrap() +} + +#[derive(Deserialize)] +struct EnableTracing { + // These params change the filter, and reset it after the duration expires. + filter: Option, + duration: Option, + + // Change the trace output file (if file output was enabled at program start) + trace_file: Option, + + // Change the tracing sample rate + sample_rate: Option, +} + +async fn enable_tracing( + State(state): State>, + query: Query, +) -> (StatusCode, String) { + let Query(EnableTracing { + filter, + duration, + trace_file, + sample_rate, + }) = query; + + let mut response = Vec::new(); + + if let Some(sample_rate) = sample_rate { + state.tracing_handle.update_sampling_rate(sample_rate); + response.push(format!("sample rate set to {:?}", sample_rate)); + } + + if let Some(trace_file) = trace_file { + if let Err(err) = state.tracing_handle.update_trace_file(&trace_file) { + response.push(format!("can't update trace file: {:?}", err)); + return (StatusCode::BAD_REQUEST, response.join("\n")); + } else { + response.push(format!("trace file set to {:?}", trace_file)); + } + } + + let Some(filter) = filter else { + return (StatusCode::OK, response.join("\n")); + }; + + // Duration is required if filter is set + let Some(duration) = duration else { + response.push("can't update filter: missing duration".into()); + return (StatusCode::BAD_REQUEST, response.join("\n")); + }; + + let Ok(duration) = parse_duration(&duration) else { + response.push("can't update filter: invalid duration".into()); + return (StatusCode::BAD_REQUEST, response.join("\n")); + }; + + match state.tracing_handle.update_trace_filter(&filter, duration) { + Ok(()) => { + response.push(format!("filter set to {:?}", filter)); + response.push(format!("filter will be reset after {:?}", duration)); + (StatusCode::OK, response.join("\n")) + } + Err(err) => { + response.push(format!("can't update filter: {:?}", err)); + (StatusCode::BAD_REQUEST, response.join("\n")) + } + } +} + +async fn reset_tracing(State(state): State>) -> (StatusCode, String) { + state.tracing_handle.reset_trace(); + ( + StatusCode::OK, + "tracing filter reset to TRACE_FILTER env var".into(), + ) +} + +async fn get_filter(State(state): State>) -> (StatusCode, String) { + match state.tracing_handle.get_log() { + Ok(filter) => (StatusCode::OK, filter), + Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()), + } +} + +async fn set_filter( + State(state): State>, + new_filter: String, +) -> (StatusCode, String) { + match state.tracing_handle.update_log(&new_filter) { + Ok(()) => { + info!(filter =% new_filter, "Log filter updated"); + (StatusCode::OK, "".into()) + } + Err(err) => (StatusCode::BAD_REQUEST, err.to_string()), + } +} + +async fn capabilities(State(state): State>) -> (StatusCode, String) { + let epoch_store = state.node.state().load_epoch_store_one_call_per_task(); + let capabilities = epoch_store.get_capabilities(); + + let mut output = String::new(); + for capability in &capabilities { + output.push_str(&format!("{:?}\n", capability)); + } + + (StatusCode::OK, output) +} + +async fn node_config(State(state): State>) -> (StatusCode, String) { + let node_config = &state.node.config; + + // Note private keys will be masked + (StatusCode::OK, format!("{:#?}\n", node_config)) +} + +#[derive(Deserialize)] +struct Epoch { + epoch: u64, +} + +async fn clear_override_protocol_upgrade_buffer_stake( + State(state): State>, + epoch: Query, +) -> (StatusCode, String) { + let Query(Epoch { epoch }) = epoch; + + match state + .node + .clear_override_protocol_upgrade_buffer_stake(epoch) + { + Ok(()) => ( + StatusCode::OK, + "protocol upgrade buffer stake cleared\n".to_string(), + ), + Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()), + } +} + +#[derive(Deserialize)] +struct SetBufferStake { + buffer_bps: u64, + epoch: u64, +} + +async fn set_override_protocol_upgrade_buffer_stake( + State(state): State>, + buffer_state: Query, +) -> (StatusCode, String) { + let Query(SetBufferStake { buffer_bps, epoch }) = buffer_state; + + match state + .node + .set_override_protocol_upgrade_buffer_stake(epoch, buffer_bps) + { + Ok(()) => ( + StatusCode::OK, + format!("protocol upgrade buffer stake set to '{}'\n", buffer_bps), + ), + Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()), + } +} + +async fn force_close_epoch( + State(state): State>, + epoch: Query, +) -> (StatusCode, String) { + let Query(Epoch { + epoch: expected_epoch, + }) = epoch; + let epoch_store = state.node.state().load_epoch_store_one_call_per_task(); + let actual_epoch = epoch_store.epoch(); + if actual_epoch != expected_epoch { + let err = IotaError::WrongEpoch { + expected_epoch, + actual_epoch, + }; + return (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()); + } + + match state.node.close_epoch(&epoch_store).await { + Ok(()) => ( + StatusCode::OK, + "close_epoch() called successfully\n".to_string(), + ), + Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()), + } +} diff --git a/crates/iota-node/src/handle.rs b/crates/iota-node/src/handle.rs new file mode 100644 index 00000000000..b5228434a5d --- /dev/null +++ b/crates/iota-node/src/handle.rs @@ -0,0 +1,147 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! SuiNodeHandle wraps SuiNode in a way suitable for access by test code. +//! +//! When starting a IotaNode directly, in a test (as opposed to using Swarm), +//! the node may be running inside of a simulator node. It is therefore a +//! microsake to do something like: +//! +//! ```ignore +//! use test_utils::authority::{start_node, spawn_checkpoint_processes}; +//! +//! let node = start_node(config, registry).await; +//! spawn_checkpoint_processes(config, &[node]).await; +//! ``` +//! +//! Because this would cause the checkpointing processes to be running inside +//! the current simulator node rather than the node in which the IotaNode is +//! running. +//! +//! IotaNodeHandle provides an easy way to do the right thing here: +//! +//! ```ignore +//! let node_handle = start_node(config, registry).await; +//! node_handle.with_async(|iota_node| async move { +//! spawn_checkpoint_processes(config, &[iota_node]).await; +//! }); +//! ``` +//! +//! Code executed inside of with or with_async will run in the context of the +//! simulator node. This allows tests to break the simulator abstraction and +//! magically mutate or inspect state that is conceptually running on a +//! different "machine", but without producing extremely confusing behavior that +//! might result otherwise. (For instance, any network connection that is +//! initiated from a task spawned from within a with or with_async will appear +//! to originate from the correct simulator node. +//! +//! It is possible to exfiltrate state: +//! +//! ```ignore +//! let state = node_handle.with(|iota_node| iota_node.state); +//! // DO NOT DO THIS! +//! do_stuff_with_state(state) +//! ``` +//! +//! We can't prevent this completely, but we can at least make the right way the +//! easy way. + +use std::{future::Future, sync::Arc}; + +use iota_core::authority::AuthorityState; + +use super::IotaNode; + +/// Wrap IotaNode to allow correct access to IotaNode in simulator tests. +pub struct IotaNodeHandle { + node: Option>, + shutdown_on_drop: bool, +} + +impl IotaNodeHandle { + pub fn new(node: Arc) -> Self { + Self { + node: Some(node), + shutdown_on_drop: false, + } + } + + pub fn inner(&self) -> &Arc { + self.node.as_ref().unwrap() + } + + pub fn with(&self, cb: impl FnOnce(&IotaNode) -> T) -> T { + let _guard = self.guard(); + cb(self.inner()) + } + + pub fn state(&self) -> Arc { + self.with(|iota_node| iota_node.state()) + } + + pub fn shutdown_on_drop(&mut self) { + self.shutdown_on_drop = true; + } +} + +impl Clone for IotaNodeHandle { + fn clone(&self) -> Self { + Self { + node: self.node.clone(), + shutdown_on_drop: false, + } + } +} + +#[cfg(not(msim))] +impl IotaNodeHandle { + // Must return something to silence lints above at `let _guard = ...` + fn guard(&self) -> u32 { + 0 + } + + pub async fn with_async<'a, F, R, T>(&'a self, cb: F) -> T + where + F: FnOnce(&'a IotaNode) -> R, + R: Future, + { + cb(self.inner()).await + } +} + +#[cfg(msim)] +impl IotaNodeHandle { + fn guard(&self) -> iota_simulator::runtime::NodeEnterGuard { + self.inner().sim_state.sim_node.enter_node() + } + + pub async fn with_async<'a, F, R, T>(&'a self, cb: F) -> T + where + F: FnOnce(&'a IotaNode) -> R, + R: Future, + { + let fut = cb(self.node.as_ref().unwrap()); + self.inner() + .sim_state + .sim_node + .await_future_in_node(fut) + .await + } +} + +#[cfg(msim)] +impl Drop for IotaNodeHandle { + fn drop(&mut self) { + if self.shutdown_on_drop { + let node_id = self.inner().sim_state.sim_node.id(); + iota_simulator::runtime::Handle::try_current().map(|h| h.delete_node(node_id)); + } + } +} + +impl From> for IotaNodeHandle { + fn from(node: Arc) -> Self { + IotaNodeHandle::new(node) + } +} diff --git a/crates/iota-node/src/lib.rs b/crates/iota-node/src/lib.rs new file mode 100644 index 00000000000..16e1997d7a9 --- /dev/null +++ b/crates/iota-node/src/lib.rs @@ -0,0 +1,1965 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(msim)] +use std::sync::atomic::Ordering; +use std::{ + collections::{BTreeSet, HashMap, HashSet}, + fmt, + path::PathBuf, + str::FromStr, + sync::Arc, + time::Duration, +}; + +use anemo::Network; +use anemo_tower::{ + callback::CallbackLayer, + trace::{DefaultMakeSpan, DefaultOnFailure, TraceLayer}, +}; +use anyhow::{anyhow, Result}; +use arc_swap::ArcSwap; +use fastcrypto_zkp::bn254::zk_login::{JwkId, OIDCProvider, JWK}; +use futures::TryFutureExt; +pub use handle::IotaNodeHandle; +use iota_archival::{reader::ArchiveReaderBalancer, writer::ArchiveWriter}; +use iota_config::{ + node::{ConsensusProtocol, DBCheckpointConfig, RunWithRange}, + node_config_metrics::NodeConfigMetrics, + object_storage_config::{ObjectStoreConfig, ObjectStoreType}, + ConsensusConfig, NodeConfig, +}; +use iota_core::{ + authority::{ + authority_per_epoch_store::AuthorityPerEpochStore, + authority_store_tables::AuthorityPerpetualTables, + epoch_start_configuration::{EpochStartConfigTrait, EpochStartConfiguration}, + AuthorityState, AuthorityStore, RandomnessRoundReceiver, CHAIN_IDENTIFIER, + }, + authority_aggregator::AuthorityAggregator, + authority_client::NetworkAuthorityClient, + authority_server::{ValidatorService, ValidatorServiceMetrics}, + checkpoints::{ + checkpoint_executor::{CheckpointExecutor, StopReason}, + CheckpointMetrics, CheckpointService, CheckpointStore, SendCheckpointToStateSync, + SubmitCheckpointToConsensus, + }, + consensus_adapter::{ + CheckConnection, ConnectionMonitorStatus, ConsensusAdapter, ConsensusAdapterMetrics, + SubmitToConsensus, + }, + consensus_manager::{ConsensusManager, ConsensusManagerTrait}, + consensus_throughput_calculator::{ + ConsensusThroughputCalculator, ConsensusThroughputProfiler, ThroughputProfileRanges, + }, + consensus_validator::{IotaTxValidator, IotaTxValidatorMetrics}, + db_checkpoint_handler::DBCheckpointHandler, + epoch::{ + committee_store::CommitteeStore, data_removal::EpochDataRemover, + epoch_metrics::EpochMetrics, randomness::RandomnessManager, + reconfiguration::ReconfigurationInitiator, + }, + execution_cache::{ + ExecutionCache, ExecutionCacheMetrics, ExecutionCacheReconfigAPI, NotifyReadWrapper, + }, + module_cache_metrics::ResolverMetrics, + overload_monitor::overload_monitor, + signature_verifier::SignatureVerifierMetrics, + state_accumulator::StateAccumulator, + storage::RocksDbStore, + transaction_orchestrator::TransactiondOrchestrator, +}; +use iota_json_rpc::{ + coin_api::CoinReadApi, governance_api::GovernanceReadApi, indexer_api::IndexerApi, + move_utils::MoveUtils, read_api::ReadApi, transaction_builder_api::TransactionBuilderApi, + transaction_execution_api::TransactionExecutionApi, JsonRpcServerBuilder, ServerType, +}; +use iota_json_rpc_api::JsonRpcMetrics; +use iota_macros::{fail_point, fail_point_async, replay_log}; +use iota_network::{ + api::ValidatorServer, discovery, discovery::TrustedPeerChangeEvent, randomness, state_sync, +}; +use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion, SupportedProtocolVersions}; +use iota_snapshot::uploader::StateSnapshotUploader; +use iota_storage::{ + http_key_value_store::HttpKVStore, + key_value_store::{FallbackTransactionKVStore, TransactionKeyValueStore}, + key_value_store_metrics::KeyValueStoreMetrics, + FileCompression, IndexStore, StorageFormat, +}; +use iota_types::{ + base_types::{AuthorityName, ConciseableName, EpochId}, + committee::Committee, + crypto::{KeypairTraits, RandomnessRound}, + digests::ChainIdentifier, + error::{IotaError, IotaResult}, + iota_system_state::{ + epoch_start_iota_system_state::{EpochStartSystemState, EpochStartSystemStateTrait}, + IotaSystemState, IotaSystemStateTrait, + }, + message_envelope::get_google_jwk_bytes, + messages_consensus::{check_total_jwk_size, AuthorityCapabilities, ConsensusTransaction}, + quorum_driver_types::QuorumDriverEffectsQueueResult, +}; +use mysten_metrics::{spawn_monitored_task, RegistryService}; +use mysten_network::server::ServerBuilder; +use narwhal_network::metrics::{ + MetricsMakeCallbackHandler, NetworkConnectionMetrics, NetworkMetrics, +}; +use narwhal_worker::LazyNarwhalClient; +use prometheus::Registry; +use tap::tap::TapFallible; +use tokio::{ + runtime::Handle, + sync::{broadcast, mpsc, watch, Mutex}, + task::JoinHandle, +}; +use tower::ServiceBuilder; +use tracing::{debug, error, error_span, info, warn, Instrument}; +use typed_store::{rocks::default_db_options, DBMetrics}; + +use crate::metrics::{GrpcMetrics, IotaNodeMetrics}; + +pub mod admin; +mod handle; +pub mod metrics; + +pub struct ValidatorComponents { + validator_server_handle: JoinHandle>, + validator_overload_monitor_handle: Option>, + consensus_manager: ConsensusManager, + consensus_epoch_data_remover: EpochDataRemover, + consensus_adapter: Arc, + // dropping this will eventually stop checkpoint tasks. The receiver side of this channel + // is copied into each checkpoint service task, and they are listening to any change to this + // channel. When the sender is dropped, a change is triggered and those tasks will exit. + checkpoint_service_exit: watch::Sender<()>, + checkpoint_metrics: Arc, + iota_tx_validator_metrics: Arc, +} + +#[cfg(msim)] +mod simulator { + use std::sync::atomic::AtomicBool; + + use super::*; + pub(super) struct SimState { + pub sim_node: iota_simulator::runtime::NodeHandle, + pub sim_safe_mode_expected: AtomicBool, + _leak_detector: iota_simulator::NodeLeakDetector, + } + + impl Default for SimState { + fn default() -> Self { + Self { + sim_node: iota_simulator::runtime::NodeHandle::current(), + sim_safe_mode_expected: AtomicBool::new(false), + _leak_detector: iota_simulator::NodeLeakDetector::new(), + } + } + } + + type JwkInjector = dyn Fn(AuthorityName, &OIDCProvider) -> IotaResult> + + Send + + Sync + + 'static; + + fn default_fetch_jwks( + _authority: AuthorityName, + _provider: &OIDCProvider, + ) -> IotaResult> { + use fastcrypto_zkp::bn254::zk_login::parse_jwks; + // Just load a default Twitch jwk for testing. + parse_jwks( + iota_types::zk_login_util::DEFAULT_JWK_BYTES, + &OIDCProvider::Twitch, + ) + .map_err(|_| IotaError::JWKRetrievalError) + } + + thread_local! { + static JWK_INJECTOR: std::cell::RefCell> = std::cell::RefCell::new(Arc::new(default_fetch_jwks)); + } + + pub(super) fn get_jwk_injector() -> Arc { + JWK_INJECTOR.with(|injector| injector.borrow().clone()) + } + + pub fn set_jwk_injector(injector: Arc) { + JWK_INJECTOR.with(|cell| *cell.borrow_mut() = injector); + } +} + +use iota_core::{ + consensus_handler::ConsensusHandlerInitializer, mysticeti_adapter::LazyMysticetiClient, +}; +use iota_types::execution_config_utils::to_binary_config; +#[cfg(msim)] +pub use simulator::set_jwk_injector; +#[cfg(msim)] +use simulator::*; + +pub struct IotaNode { + config: NodeConfig, + validator_components: Mutex>, + /// The http server responsible for serving JSON-RPC as well as the + /// experimental rest service + _http_server: Option>, + state: Arc, + transaction_orchestrator: Option>>, + registry_service: RegistryService, + metrics: Arc, + + _discovery: discovery::Handle, + state_sync_handle: state_sync::Handle, + randomness_handle: randomness::Handle, + checkpoint_store: Arc, + accumulator: Arc, + connection_monitor_status: Arc, + + /// Broadcast channel to send the starting system state for the next epoch. + end_of_epoch_channel: broadcast::Sender, + + /// Broadcast channel to notify state-sync for new validator peers. + trusted_peer_change_tx: watch::Sender, + + _db_checkpoint_handle: Option>, + + #[cfg(msim)] + sim_state: SimState, + + _state_archive_handle: Option>, + + _state_snapshot_uploader_handle: Option>, + // Channel to allow signaling upstream to shutdown iota-node + shutdown_channel_tx: broadcast::Sender>, +} + +impl fmt::Debug for IotaNode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("IotaNode") + .field("name", &self.state.name.concise()) + .finish() + } +} + +static MAX_JWK_KEYS_PER_FETCH: usize = 100; + +impl IotaNode { + pub async fn start( + config: NodeConfig, + registry_service: RegistryService, + custom_rpc_runtime: Option, + ) -> Result> { + Self::start_async(config, registry_service, custom_rpc_runtime, "unknown").await + } + + fn start_jwk_updater( + config: &NodeConfig, + metrics: Arc, + authority: AuthorityName, + epoch_store: Arc, + consensus_adapter: Arc, + ) { + let epoch = epoch_store.epoch(); + + let supported_providers = config + .zklogin_oauth_providers + .get(&epoch_store.get_chain_identifier().chain()) + .unwrap_or(&BTreeSet::new()) + .iter() + .map(|s| OIDCProvider::from_str(s).expect("Invalid provider string")) + .collect::>(); + + let fetch_interval = Duration::from_secs(config.jwk_fetch_interval_seconds); + + info!( + ?fetch_interval, + "Starting JWK updater tasks with supported providers: {:?}", supported_providers + ); + + fn validate_jwk( + metrics: &Arc, + provider: &OIDCProvider, + id: &JwkId, + jwk: &JWK, + ) -> bool { + let Ok(iss_provider) = OIDCProvider::from_iss(&id.iss) else { + warn!( + "JWK iss {:?} (retrieved from {:?}) is not a valid provider", + id.iss, provider + ); + metrics + .invalid_jwks + .with_label_values(&[&provider.to_string()]) + .inc(); + return false; + }; + + if iss_provider != *provider { + warn!( + "JWK iss {:?} (retrieved from {:?}) does not match provider {:?}", + id.iss, provider, iss_provider + ); + metrics + .invalid_jwks + .with_label_values(&[&provider.to_string()]) + .inc(); + return false; + } + + if !check_total_jwk_size(id, jwk) { + warn!("JWK {:?} (retrieved from {:?}) is too large", id, provider); + metrics + .invalid_jwks + .with_label_values(&[&provider.to_string()]) + .inc(); + return false; + } + + true + } + + // metrics is: + // pub struct IotaNodeMetrics { + // pub jwk_requests: IntCounterVec, + // pub jwk_request_errors: IntCounterVec, + // pub total_jwks: IntCounterVec, + // pub unique_jwks: IntCounterVec, + // } + + for p in supported_providers.into_iter() { + let provider_str = p.to_string(); + let epoch_store = epoch_store.clone(); + let consensus_adapter = consensus_adapter.clone(); + let metrics = metrics.clone(); + spawn_monitored_task!(epoch_store.clone().within_alive_epoch( + async move { + // note: restart-safe de-duplication happens after consensus, this is + // just best-effort to reduce unneeded submissions. + let mut seen = HashSet::new(); + loop { + info!("fetching JWK for provider {:?}", p); + metrics.jwk_requests.with_label_values(&[&provider_str]).inc(); + match Self::fetch_jwks(authority, &p).await { + Err(e) => { + metrics.jwk_request_errors.with_label_values(&[&provider_str]).inc(); + warn!("Error when fetching JWK for provider {:?} {:?}", p, e); + // Retry in 30 seconds + tokio::time::sleep(Duration::from_secs(30)).await; + continue; + } + Ok(mut keys) => { + metrics.total_jwks + .with_label_values(&[&provider_str]) + .inc_by(keys.len() as u64); + + keys.retain(|(id, jwk)| { + validate_jwk(&metrics, &p, id, jwk) && + !epoch_store.jwk_active_in_current_epoch(id, jwk) && + seen.insert((id.clone(), jwk.clone())) + }); + + metrics.unique_jwks + .with_label_values(&[&provider_str]) + .inc_by(keys.len() as u64); + + // prevent oauth providers from sending too many keys, + // inadvertently or otherwise + if keys.len() > MAX_JWK_KEYS_PER_FETCH { + warn!("Provider {:?} sent too many JWKs, only the first {} will be used", p, MAX_JWK_KEYS_PER_FETCH); + keys.truncate(MAX_JWK_KEYS_PER_FETCH); + } + + for (id, jwk) in keys.into_iter() { + info!("Submitting JWK to consensus: {:?}", id); + + let txn = ConsensusTransaction::new_jwk_fetched(authority, id, jwk); + consensus_adapter.submit(txn, None, &epoch_store) + .tap_err(|e| warn!("Error when submitting JWKs to consensus {:?}", e)) + .ok(); + } + } + } + tokio::time::sleep(fetch_interval).await; + } + } + .instrument(error_span!("jwk_updater_task", epoch)), + )); + } + } + + pub async fn start_async( + config: NodeConfig, + registry_service: RegistryService, + custom_rpc_runtime: Option, + software_version: &'static str, + ) -> Result> { + NodeConfigMetrics::new(®istry_service.default_registry()).record_metrics(&config); + let mut config = config.clone(); + if config.supported_protocol_versions.is_none() { + info!( + "populating config.supported_protocol_versions with default {:?}", + SupportedProtocolVersions::SYSTEM_DEFAULT + ); + config.supported_protocol_versions = Some(SupportedProtocolVersions::SYSTEM_DEFAULT); + } + + let run_with_range = config.run_with_range; + let is_validator = config.consensus_config().is_some(); + let is_full_node = !is_validator; + let prometheus_registry = registry_service.default_registry(); + + info!(node =? config.protocol_public_key(), + "Initializing iota-node listening on {}", config.network_address + ); + + // Initialize metrics to track db usage before creating any stores + DBMetrics::init(&prometheus_registry); + mysten_metrics::init_metrics(&prometheus_registry); + + let genesis = config.genesis()?; + + let secret = Arc::pin(config.protocol_key_pair().copy()); + let genesis_committee = genesis.committee()?; + let committee_store = Arc::new(CommitteeStore::new( + config.db_path().join("epochs"), + &genesis_committee, + None, + )); + + let perpetual_options = default_db_options().optimize_db_for_write_throughput(4); + let perpetual_tables = Arc::new(AuthorityPerpetualTables::open( + &config.db_path().join("store"), + Some(perpetual_options.options), + )); + let is_genesis = perpetual_tables + .database_is_empty() + .expect("Database read should not fail at init."); + let store = AuthorityStore::open( + perpetual_tables, + genesis, + config.indirect_objects_threshold, + config + .expensive_safety_check_config + .enable_epoch_iota_conservation_check(), + &prometheus_registry, + ) + .await?; + let execution_cache_metrics = Arc::new(ExecutionCacheMetrics::new(&prometheus_registry)); + let execution_cache = Arc::new(ExecutionCache::new(store.clone(), execution_cache_metrics)); + + let cur_epoch = store.get_recovery_epoch_at_restart()?; + let committee = committee_store + .get_committee(&cur_epoch)? + .expect("Committee of the current epoch must exist"); + let epoch_start_configuration = store + .get_epoch_start_configuration()? + .expect("EpochStartConfiguration of the current epoch must exist"); + let cache_metrics = Arc::new(ResolverMetrics::new(&prometheus_registry)); + let signature_verifier_metrics = SignatureVerifierMetrics::new(&prometheus_registry); + + let epoch_options = default_db_options().optimize_db_for_write_throughput(4); + let epoch_store = AuthorityPerEpochStore::new( + config.protocol_public_key(), + committee.clone(), + &config.db_path().join("store"), + Some(epoch_options.options), + EpochMetrics::new(®istry_service.default_registry()), + epoch_start_configuration, + execution_cache.clone(), + cache_metrics, + signature_verifier_metrics, + &config.expensive_safety_check_config, + ChainIdentifier::from(*genesis.checkpoint().digest()), + ); + + replay_log!( + "Beginning replay run. Epoch: {:?}, Protocol config: {:?}", + epoch_store.epoch(), + epoch_store.protocol_config() + ); + + // the database is empty at genesis time + if is_genesis { + // When we are opening the db table, the only time when it's safe to + // check IOTA conservation is at genesis. Otherwise we may be in the middle of + // an epoch and the IOTA conservation check will fail. This also initialize + // the expected_network_iota_amount table. + execution_cache + .expensive_check_iota_conservation(&epoch_store) + .expect("IOTA conservation check cannot fail at genesis"); + } + + let effective_buffer_stake = epoch_store.get_effective_buffer_stake_bps(); + let default_buffer_stake = epoch_store + .protocol_config() + .buffer_stake_for_protocol_upgrade_bps(); + if effective_buffer_stake != default_buffer_stake { + warn!( + ?effective_buffer_stake, + ?default_buffer_stake, + "buffer_stake_for_protocol_upgrade_bps is currently overridden" + ); + } + + let checkpoint_store = CheckpointStore::new(&config.db_path().join("checkpoints")); + checkpoint_store.insert_genesis_checkpoint( + genesis.checkpoint(), + genesis.checkpoint_contents().clone(), + &epoch_store, + ); + + let state_sync_store = RocksDbStore::new( + execution_cache.clone(), + committee_store.clone(), + checkpoint_store.clone(), + ); + + let index_store = if is_full_node && config.enable_index_processing { + Some(Arc::new(IndexStore::new( + config.db_path().join("indexes"), + &prometheus_registry, + epoch_store + .protocol_config() + .max_move_identifier_len_as_option(), + ))) + } else { + None + }; + + let chain_identifier = ChainIdentifier::from(*genesis.checkpoint().digest()); + // It's ok if the value is already set due to data races. + let _ = CHAIN_IDENTIFIER.set(chain_identifier); + + // Create network + // TODO only configure validators as seed/preferred peers for validators and not + // for fullnodes once we've had a chance to re-work fullnode + // configuration generation. + let archive_readers = + ArchiveReaderBalancer::new(config.archive_reader_config(), &prometheus_registry)?; + let (trusted_peer_change_tx, trusted_peer_change_rx) = watch::channel(Default::default()); + let (randomness_tx, randomness_rx) = mpsc::channel( + config + .p2p_config + .randomness + .clone() + .unwrap_or_default() + .mailbox_capacity(), + ); + let (p2p_network, discovery_handle, state_sync_handle, randomness_handle) = + Self::create_p2p_network( + &config, + state_sync_store.clone(), + chain_identifier, + trusted_peer_change_rx, + archive_readers.clone(), + randomness_tx, + &prometheus_registry, + )?; + + // We must explicitly send this instead of relying on the initial value to + // trigger watch value change, so that state-sync is able to process it. + send_trusted_peer_change( + &config, + &trusted_peer_change_tx, + epoch_store.epoch_start_state(), + ) + .expect("Initial trusted peers must be set"); + + // Start archiving local state to remote store + let state_archive_handle = + Self::start_state_archival(&config, &prometheus_registry, state_sync_store.clone()) + .await?; + + // Start uploading state snapshot to remote store + let state_snapshot_handle = Self::start_state_snapshot(&config, &prometheus_registry)?; + + // Start uploading db checkpoints to remote store + let (db_checkpoint_config, db_checkpoint_handle) = Self::start_db_checkpoint( + &config, + &prometheus_registry, + state_snapshot_handle.is_some(), + )?; + + let mut pruning_config = config.authority_store_pruning_config; + if !epoch_store + .protocol_config() + .simplified_unwrap_then_delete() + { + // We cannot prune tombstones if simplified_unwrap_then_delete is not enabled. + pruning_config.set_killswitch_tombstone_pruning(true); + } + + let state = AuthorityState::new( + config.protocol_public_key(), + secret, + config.supported_protocol_versions.unwrap(), + store.clone(), + execution_cache, + epoch_store.clone(), + committee_store.clone(), + index_store.clone(), + checkpoint_store.clone(), + &prometheus_registry, + pruning_config, + genesis.objects(), + &db_checkpoint_config, + config.expensive_safety_check_config.clone(), + config.transaction_deny_config.clone(), + config.certificate_deny_config.clone(), + config.indirect_objects_threshold, + config.state_debug_dump_config.clone(), + config.authority_overload_config.clone(), + archive_readers, + ) + .await; + // ensure genesis txn was executed + if epoch_store.epoch() == 0 { + let txn = &genesis.transaction(); + let span = error_span!("genesis_txn", tx_digest = ?txn.digest()); + let transaction = + iota_types::executable_transaction::VerifiedExecutableTransaction::new_unchecked( + iota_types::executable_transaction::ExecutableTransaction::new_from_data_and_sig( + genesis.transaction().data().clone(), + iota_types::executable_transaction::CertificateProof::Checkpoint(0, 0), + ), + ); + state + .try_execute_immediately(&transaction, None, &epoch_store) + .instrument(span) + .await + .unwrap(); + } + + // Start the loop that receives new randomness and generates transactions for + // it. + RandomnessRoundReceiver::spawn(state.clone(), randomness_rx); + + if config + .expensive_safety_check_config + .enable_secondary_index_checks() + { + if let Some(indexes) = state.indexes.clone() { + iota_core::verify_indexes::verify_indexes( + state.get_accumulator_store().as_ref(), + indexes, + ) + .expect("secondary indexes are inconsistent"); + } + } + + let (end_of_epoch_channel, end_of_epoch_receiver) = + broadcast::channel(config.end_of_epoch_broadcast_channel_capacity); + + let transaction_orchestrator = if is_full_node && run_with_range.is_none() { + Some(Arc::new( + TransactiondOrchestrator::new_with_network_clients( + state.clone(), + end_of_epoch_receiver, + &config.db_path(), + &prometheus_registry, + )?, + )) + } else { + None + }; + + let http_server = build_http_server( + state.clone(), + state_sync_store, + &transaction_orchestrator.clone(), + &config, + &prometheus_registry, + custom_rpc_runtime, + software_version, + )?; + + let accumulator = Arc::new(StateAccumulator::new(store)); + + let authority_names_to_peer_ids = epoch_store + .epoch_start_state() + .get_authority_names_to_peer_ids(); + + let network_connection_metrics = + NetworkConnectionMetrics::new("iota", ®istry_service.default_registry()); + + let authority_names_to_peer_ids = ArcSwap::from_pointee(authority_names_to_peer_ids); + + let (_connection_monitor_handle, connection_statuses) = + narwhal_network::connectivity::ConnectionMonitor::spawn( + p2p_network.downgrade(), + network_connection_metrics, + HashMap::new(), + None, + ); + + let connection_monitor_status = ConnectionMonitorStatus { + connection_statuses, + authority_names_to_peer_ids, + }; + + let connection_monitor_status = Arc::new(connection_monitor_status); + let iota_node_metrics = + Arc::new(IotaNodeMetrics::new(®istry_service.default_registry())); + + let validator_components = if state.is_validator(&epoch_store) { + let components = Self::construct_validator_components( + config.clone(), + state.clone(), + committee, + epoch_store.clone(), + checkpoint_store.clone(), + state_sync_handle.clone(), + randomness_handle.clone(), + accumulator.clone(), + connection_monitor_status.clone(), + ®istry_service, + iota_node_metrics.clone(), + ) + .await?; + // This is only needed during cold start. + components.consensus_adapter.submit_recovered(&epoch_store); + + Some(components) + } else { + None + }; + + // setup shutdown channel + let (shutdown_channel, _) = broadcast::channel::>(1); + + let node = Self { + config, + validator_components: Mutex::new(validator_components), + _http_server: http_server, + state, + transaction_orchestrator, + registry_service, + metrics: iota_node_metrics, + + _discovery: discovery_handle, + state_sync_handle, + randomness_handle, + checkpoint_store, + accumulator, + end_of_epoch_channel, + connection_monitor_status, + trusted_peer_change_tx, + + _db_checkpoint_handle: db_checkpoint_handle, + + #[cfg(msim)] + sim_state: Default::default(), + + _state_archive_handle: state_archive_handle, + _state_snapshot_uploader_handle: state_snapshot_handle, + shutdown_channel_tx: shutdown_channel, + }; + + info!("IotaNode started!"); + let node = Arc::new(node); + let node_copy = node.clone(); + spawn_monitored_task!(async move { + let result = Self::monitor_reconfiguration(node_copy).await; + if let Err(error) = result { + warn!("Reconfiguration finished with error {:?}", error); + } + }); + + Ok(node) + } + + pub fn subscribe_to_epoch_change(&self) -> broadcast::Receiver { + self.end_of_epoch_channel.subscribe() + } + + pub fn subscribe_to_shutdown_channel(&self) -> broadcast::Receiver> { + self.shutdown_channel_tx.subscribe() + } + + pub fn current_epoch_for_testing(&self) -> EpochId { + self.state.current_epoch_for_testing() + } + + pub fn db_checkpoint_path(&self) -> PathBuf { + self.config.db_checkpoint_path() + } + + // Init reconfig process by starting to reject user certs + pub async fn close_epoch(&self, epoch_store: &Arc) -> IotaResult { + info!("close_epoch (current epoch = {})", epoch_store.epoch()); + self.validator_components + .lock() + .await + .as_ref() + .ok_or_else(|| IotaError::from("Node is not a validator"))? + .consensus_adapter + .close_epoch(epoch_store); + Ok(()) + } + + pub fn clear_override_protocol_upgrade_buffer_stake(&self, epoch: EpochId) -> IotaResult { + self.state + .clear_override_protocol_upgrade_buffer_stake(epoch) + } + + pub fn set_override_protocol_upgrade_buffer_stake( + &self, + epoch: EpochId, + buffer_stake_bps: u64, + ) -> IotaResult { + self.state + .set_override_protocol_upgrade_buffer_stake(epoch, buffer_stake_bps) + } + + // Testing-only API to start epoch close process. + // For production code, please use the non-testing version. + pub async fn close_epoch_for_testing(&self) -> IotaResult { + let epoch_store = self.state.epoch_store_for_testing(); + self.close_epoch(&epoch_store).await + } + + async fn start_state_archival( + config: &NodeConfig, + prometheus_registry: &Registry, + state_sync_store: RocksDbStore, + ) -> Result>> { + if let Some(remote_store_config) = &config.state_archive_write_config.object_store_config { + let local_store_config = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(config.archive_path()), + ..Default::default() + }; + let archive_writer = ArchiveWriter::new( + local_store_config, + remote_store_config.clone(), + FileCompression::Zstd, + StorageFormat::Blob, + Duration::from_secs(600), + 256 * 1024 * 1024, + prometheus_registry, + ) + .await?; + Ok(Some(archive_writer.start(state_sync_store).await?)) + } else { + Ok(None) + } + } + + fn start_state_snapshot( + config: &NodeConfig, + prometheus_registry: &Registry, + ) -> Result>> { + if let Some(remote_store_config) = &config.state_snapshot_write_config.object_store_config { + let snapshot_uploader = StateSnapshotUploader::new( + &config.db_checkpoint_path(), + &config.snapshot_path(), + remote_store_config.clone(), + 60, + prometheus_registry, + )?; + Ok(Some(snapshot_uploader.start())) + } else { + Ok(None) + } + } + + fn start_db_checkpoint( + config: &NodeConfig, + prometheus_registry: &Registry, + state_snapshot_enabled: bool, + ) -> Result<( + DBCheckpointConfig, + Option>, + )> { + let checkpoint_path = Some( + config + .db_checkpoint_config + .checkpoint_path + .clone() + .unwrap_or_else(|| config.db_checkpoint_path()), + ); + let db_checkpoint_config = if config.db_checkpoint_config.checkpoint_path.is_none() { + DBCheckpointConfig { + checkpoint_path, + perform_db_checkpoints_at_epoch_end: if state_snapshot_enabled { + true + } else { + config + .db_checkpoint_config + .perform_db_checkpoints_at_epoch_end + }, + ..config.db_checkpoint_config.clone() + } + } else { + config.db_checkpoint_config.clone() + }; + + match ( + db_checkpoint_config.object_store_config.as_ref(), + state_snapshot_enabled, + ) { + // If db checkpoint config object store not specified but + // state snapshot object store is specified, create handler + // anyway for marking db checkpoints as completed so that they + // can be uploaded as state snapshots. + (None, false) => Ok((db_checkpoint_config, None)), + (_, _) => { + let handler = DBCheckpointHandler::new( + &db_checkpoint_config.checkpoint_path.clone().unwrap(), + db_checkpoint_config.object_store_config.as_ref(), + 60, + db_checkpoint_config + .prune_and_compact_before_upload + .unwrap_or(true), + config.indirect_objects_threshold, + config.authority_store_pruning_config, + prometheus_registry, + state_snapshot_enabled, + )?; + Ok(( + db_checkpoint_config, + Some(DBCheckpointHandler::start(handler)), + )) + } + } + } + + fn create_p2p_network( + config: &NodeConfig, + state_sync_store: RocksDbStore, + chain_identifier: ChainIdentifier, + trusted_peer_change_rx: watch::Receiver, + archive_readers: ArchiveReaderBalancer, + randomness_tx: mpsc::Sender<(EpochId, RandomnessRound, Vec)>, + prometheus_registry: &Registry, + ) -> Result<( + Network, + discovery::Handle, + state_sync::Handle, + randomness::Handle, + )> { + let (state_sync, state_sync_server) = state_sync::Builder::new() + .config(config.p2p_config.state_sync.clone().unwrap_or_default()) + .store(state_sync_store) + .archive_readers(archive_readers) + .with_metrics(prometheus_registry) + .build(); + + let (discovery, discovery_server) = discovery::Builder::new(trusted_peer_change_rx) + .config(config.p2p_config.clone()) + .build(); + + let (randomness, randomness_router) = + randomness::Builder::new(config.protocol_public_key(), randomness_tx) + .config(config.p2p_config.randomness.clone().unwrap_or_default()) + .with_metrics(prometheus_registry) + .build(); + + let p2p_network = { + let routes = anemo::Router::new() + .add_rpc_service(discovery_server) + .add_rpc_service(state_sync_server); + let routes = routes.merge(randomness_router); + + let inbound_network_metrics = + NetworkMetrics::new("iota", "inbound", prometheus_registry); + let outbound_network_metrics = + NetworkMetrics::new("iota", "outbound", prometheus_registry); + + let service = ServiceBuilder::new() + .layer( + TraceLayer::new_for_server_errors() + .make_span_with(DefaultMakeSpan::new().level(tracing::Level::INFO)) + .on_failure(DefaultOnFailure::new().level(tracing::Level::WARN)), + ) + .layer(CallbackLayer::new(MetricsMakeCallbackHandler::new( + Arc::new(inbound_network_metrics), + config.p2p_config.excessive_message_size(), + ))) + .service(routes); + + let outbound_layer = ServiceBuilder::new() + .layer( + TraceLayer::new_for_client_and_server_errors() + .make_span_with(DefaultMakeSpan::new().level(tracing::Level::INFO)) + .on_failure(DefaultOnFailure::new().level(tracing::Level::WARN)), + ) + .layer(CallbackLayer::new(MetricsMakeCallbackHandler::new( + Arc::new(outbound_network_metrics), + config.p2p_config.excessive_message_size(), + ))) + .into_inner(); + + let mut anemo_config = config.p2p_config.anemo_config.clone().unwrap_or_default(); + // Set the max_frame_size to be 1 GB to work around the issue of there being too + // many staking events in the epoch change txn. + anemo_config.max_frame_size = Some(1 << 30); + + // Set a higher default value for socket send/receive buffers if not already + // configured. + let mut quic_config = anemo_config.quic.unwrap_or_default(); + if quic_config.socket_send_buffer_size.is_none() { + quic_config.socket_send_buffer_size = Some(20 << 20); + } + if quic_config.socket_receive_buffer_size.is_none() { + quic_config.socket_receive_buffer_size = Some(20 << 20); + } + quic_config.allow_failed_socket_buffer_size_setting = true; + + // Set high-performance defaults for quinn transport. + // With 200MiB buffer size and ~500ms RTT, max throughput ~400MiB/s. + if quic_config.stream_receive_window.is_none() { + quic_config.stream_receive_window = Some(100 << 20); + } + if quic_config.receive_window.is_none() { + quic_config.receive_window = Some(200 << 20); + } + if quic_config.send_window.is_none() { + quic_config.send_window = Some(200 << 20); + } + if quic_config.crypto_buffer_size.is_none() { + quic_config.crypto_buffer_size = Some(1 << 20); + } + if quic_config.max_idle_timeout_ms.is_none() { + quic_config.max_idle_timeout_ms = Some(30_000); + } + if quic_config.keep_alive_interval_ms.is_none() { + quic_config.keep_alive_interval_ms = Some(5_000); + } + anemo_config.quic = Some(quic_config); + + let server_name = format!("iota-{}", chain_identifier); + let network = Network::bind(config.p2p_config.listen_address) + .server_name(&server_name) + .private_key(config.network_key_pair().copy().private().0.to_bytes()) + .config(anemo_config) + .outbound_request_layer(outbound_layer) + .start(service)?; + info!( + server_name = server_name, + "P2p network started on {}", + network.local_addr() + ); + + network + }; + + let discovery_handle = discovery.start(p2p_network.clone()); + let state_sync_handle = state_sync.start(p2p_network.clone()); + let randomness_handle = randomness.start(p2p_network.clone()); + + Ok(( + p2p_network, + discovery_handle, + state_sync_handle, + randomness_handle, + )) + } + + async fn construct_validator_components( + config: NodeConfig, + state: Arc, + committee: Arc, + epoch_store: Arc, + checkpoint_store: Arc, + state_sync_handle: state_sync::Handle, + randomness_handle: randomness::Handle, + accumulator: Arc, + connection_monitor_status: Arc, + registry_service: &RegistryService, + iota_node_metrics: Arc, + ) -> Result { + let mut config_clone = config.clone(); + let consensus_config = config_clone + .consensus_config + .as_mut() + .ok_or_else(|| anyhow!("Validator is missing consensus config"))?; + + // Only allow overriding the consensus protocol, if the protocol version + // supports fields needed by Mysticeti. + if epoch_store.protocol_config().version >= ProtocolVersion::new(36) { + if let Ok(consensus_choice) = std::env::var("CONSENSUS") { + let consensus_protocol = match consensus_choice.as_str() { + "narwhal" => ConsensusProtocol::Narwhal, + "mysticeti" => ConsensusProtocol::Mysticeti, + "swap_each_epoch" => { + if epoch_store.epoch() % 2 == 0 { + ConsensusProtocol::Narwhal + } else { + ConsensusProtocol::Mysticeti + } + } + _ => { + let consensus = consensus_config.protocol.clone(); + warn!( + "Consensus env var was set to an invalid choice, using default consensus protocol {consensus:?}" + ); + consensus + } + }; + info!("Constructing consensus protocol {consensus_protocol:?}..."); + consensus_config.protocol = consensus_protocol; + } + } + + // TODO (mysticeti): Move protocol choice to a protocol config flag. + let (consensus_adapter, consensus_manager) = match consensus_config.protocol { + ConsensusProtocol::Narwhal => { + let consensus_adapter = Arc::new(Self::construct_consensus_adapter( + &committee, + consensus_config, + state.name, + connection_monitor_status.clone(), + ®istry_service.default_registry(), + epoch_store.protocol_config().clone(), + Arc::new(LazyNarwhalClient::new( + consensus_config.address().to_owned(), + )), + )); + let consensus_manager = + ConsensusManager::new_narwhal(&config, consensus_config, registry_service); + (consensus_adapter, consensus_manager) + } + ConsensusProtocol::Mysticeti => { + let client = Arc::new(LazyMysticetiClient::new()); + + let consensus_adapter = Arc::new(Self::construct_consensus_adapter( + &committee, + consensus_config, + state.name, + connection_monitor_status.clone(), + ®istry_service.default_registry(), + epoch_store.protocol_config().clone(), + client.clone(), + )); + let consensus_manager = ConsensusManager::new_mysticeti( + &config, + consensus_config, + registry_service, + client, + ); + (consensus_adapter, consensus_manager) + } + }; + + let mut consensus_epoch_data_remover = + EpochDataRemover::new(consensus_manager.get_storage_base_path()); + + // This only gets started up once, not on every epoch. (Make call to remove + // every epoch.) + consensus_epoch_data_remover.run().await; + + let checkpoint_metrics = CheckpointMetrics::new(®istry_service.default_registry()); + let iota_tx_validator_metrics = + IotaTxValidatorMetrics::new(®istry_service.default_registry()); + + let validator_server_handle = Self::start_grpc_validator_service( + &config, + state.clone(), + consensus_adapter.clone(), + ®istry_service.default_registry(), + ) + .await?; + + // Starts an overload monitor that monitors the execution of the authority. + // Don't start the overload monitor when max_load_shedding_percentage is 0. + let validator_overload_monitor_handle = if config + .authority_overload_config + .max_load_shedding_percentage + > 0 + { + let authority_state = Arc::downgrade(&state); + let overload_config = config.authority_overload_config.clone(); + fail_point!("starting_overload_monitor"); + Some(spawn_monitored_task!(overload_monitor( + authority_state, + overload_config, + ))) + } else { + None + }; + + Self::start_epoch_specific_validator_components( + &config, + state.clone(), + consensus_adapter, + checkpoint_store, + epoch_store, + state_sync_handle, + randomness_handle, + consensus_manager, + consensus_epoch_data_remover, + accumulator, + validator_server_handle, + validator_overload_monitor_handle, + checkpoint_metrics, + iota_node_metrics, + iota_tx_validator_metrics, + ) + .await + } + + async fn start_epoch_specific_validator_components( + config: &NodeConfig, + state: Arc, + consensus_adapter: Arc, + checkpoint_store: Arc, + epoch_store: Arc, + state_sync_handle: state_sync::Handle, + randomness_handle: randomness::Handle, + consensus_manager: ConsensusManager, + consensus_epoch_data_remover: EpochDataRemover, + accumulator: Arc, + validator_server_handle: JoinHandle>, + validator_overload_monitor_handle: Option>, + checkpoint_metrics: Arc, + iota_node_metrics: Arc, + iota_tx_validator_metrics: Arc, + ) -> Result { + let (checkpoint_service, checkpoint_service_exit) = Self::start_checkpoint_service( + config, + consensus_adapter.clone(), + checkpoint_store, + epoch_store.clone(), + state.clone(), + state_sync_handle, + accumulator, + checkpoint_metrics.clone(), + ); + + // create a new map that gets injected into both the consensus handler and the + // consensus adapter the consensus handler will write values forwarded + // from consensus, and the consensus adapter will read the values to + // make decisions about which validator submits a transaction to consensus + let low_scoring_authorities = Arc::new(ArcSwap::new(Arc::new(HashMap::new()))); + + consensus_adapter.swap_low_scoring_authorities(low_scoring_authorities.clone()); + + if epoch_store.randomness_state_enabled() { + let randomness_manager = RandomnessManager::try_new( + Arc::downgrade(&epoch_store), + consensus_adapter.clone(), + randomness_handle, + config.protocol_key_pair(), + ) + .await; + if let Some(randomness_manager) = randomness_manager { + epoch_store.set_randomness_manager(randomness_manager)?; + } + } + + let throughput_calculator = Arc::new(ConsensusThroughputCalculator::new( + None, + state.metrics.clone(), + )); + + let throughput_profiler = Arc::new(ConsensusThroughputProfiler::new( + throughput_calculator.clone(), + None, + None, + state.metrics.clone(), + ThroughputProfileRanges::from_chain(epoch_store.get_chain_identifier()), + )); + + consensus_adapter.swap_throughput_profiler(throughput_profiler); + + let consensus_handler_initializer = ConsensusHandlerInitializer::new( + state.clone(), + checkpoint_service.clone(), + epoch_store.clone(), + low_scoring_authorities, + throughput_calculator, + ); + + consensus_manager + .start( + config, + epoch_store.clone(), + consensus_handler_initializer, + IotaTxValidator::new( + epoch_store.clone(), + checkpoint_service.clone(), + state.transaction_manager().clone(), + iota_tx_validator_metrics.clone(), + ), + ) + .await; + + if epoch_store.authenticator_state_enabled() { + Self::start_jwk_updater( + config, + iota_node_metrics, + state.name, + epoch_store.clone(), + consensus_adapter.clone(), + ); + } + + Ok(ValidatorComponents { + validator_server_handle, + validator_overload_monitor_handle, + consensus_manager, + consensus_epoch_data_remover, + consensus_adapter, + checkpoint_service_exit, + checkpoint_metrics, + iota_tx_validator_metrics, + }) + } + + fn start_checkpoint_service( + config: &NodeConfig, + consensus_adapter: Arc, + checkpoint_store: Arc, + epoch_store: Arc, + state: Arc, + state_sync_handle: state_sync::Handle, + accumulator: Arc, + checkpoint_metrics: Arc, + ) -> (Arc, watch::Sender<()>) { + let epoch_start_timestamp_ms = epoch_store.epoch_start_state().epoch_start_timestamp_ms(); + let epoch_duration_ms = epoch_store.epoch_start_state().epoch_duration_ms(); + + debug!( + "Starting checkpoint service with epoch start timestamp {} + and epoch duration {}", + epoch_start_timestamp_ms, epoch_duration_ms + ); + + let checkpoint_output = Box::new(SubmitCheckpointToConsensus { + sender: consensus_adapter, + signer: state.secret.clone(), + authority: config.protocol_public_key(), + next_reconfiguration_timestamp_ms: epoch_start_timestamp_ms + .checked_add(epoch_duration_ms) + .expect("Overflow calculating next_reconfiguration_timestamp_ms"), + metrics: checkpoint_metrics.clone(), + }); + + let certified_checkpoint_output = SendCheckpointToStateSync::new(state_sync_handle); + let max_tx_per_checkpoint = max_tx_per_checkpoint(epoch_store.protocol_config()); + let max_checkpoint_size_bytes = + epoch_store.protocol_config().max_checkpoint_size_bytes() as usize; + + let notify_read: NotifyReadWrapper<_> = state.get_effects_notify_read().clone(); + CheckpointService::spawn( + state.clone(), + checkpoint_store, + epoch_store, + Arc::new(notify_read), + accumulator, + checkpoint_output, + Box::new(certified_checkpoint_output), + checkpoint_metrics, + max_tx_per_checkpoint, + max_checkpoint_size_bytes, + ) + } + + fn construct_consensus_adapter( + committee: &Committee, + consensus_config: &ConsensusConfig, + authority: AuthorityName, + connection_monitor_status: Arc, + prometheus_registry: &Registry, + protocol_config: ProtocolConfig, + consensus_client: Arc, + ) -> ConsensusAdapter { + let ca_metrics = ConsensusAdapterMetrics::new(prometheus_registry); + // The consensus adapter allows the authority to send user certificates through + // consensus. + + ConsensusAdapter::new( + consensus_client, + authority, + connection_monitor_status, + consensus_config.max_pending_transactions(), + consensus_config.max_pending_transactions() * 2 / committee.num_members(), + consensus_config.max_submit_position, + consensus_config.submit_delay_step_override(), + ca_metrics, + protocol_config, + ) + } + + async fn start_grpc_validator_service( + config: &NodeConfig, + state: Arc, + consensus_adapter: Arc, + prometheus_registry: &Registry, + ) -> Result>> { + let validator_service = ValidatorService::new( + state.clone(), + consensus_adapter, + Arc::new(ValidatorServiceMetrics::new(prometheus_registry)), + ); + + let mut server_conf = mysten_network::config::Config::new(); + server_conf.global_concurrency_limit = config.grpc_concurrency_limit; + server_conf.load_shed = config.grpc_load_shed; + let mut server_builder = + ServerBuilder::from_config(&server_conf, GrpcMetrics::new(prometheus_registry)); + + server_builder = server_builder.add_service(ValidatorServer::new(validator_service)); + + let server = server_builder + .bind(config.network_address()) + .await + .map_err(|err| anyhow!(err.to_string()))?; + let local_addr = server.local_addr(); + info!("Listening to traffic on {local_addr}"); + let grpc_server = spawn_monitored_task!(server.serve().map_err(Into::into)); + + Ok(grpc_server) + } + + pub fn state(&self) -> Arc { + self.state.clone() + } + + // Only used for testing because of how epoch store is loaded. + pub fn reference_gas_price_for_testing(&self) -> Result { + self.state.reference_gas_price_for_testing() + } + + pub fn clone_committee_store(&self) -> Arc { + self.state.committee_store().clone() + } + + // pub fn clone_authority_store(&self) -> Arc { + // self.state.db() + // } + + /// Clone an AuthorityAggregator currently used in this node's + /// QuorumDriver, if the node is a fullnode. After reconfig, + /// QuorumDriver builds a new AuthorityAggregator. The caller + /// of this function will mostly likely want to call this again + /// to get a fresh one. + pub fn clone_authority_aggregator( + &self, + ) -> Option>> { + self.transaction_orchestrator + .as_ref() + .map(|to| to.clone_authority_aggregator()) + } + + pub fn transaction_orchestrator( + &self, + ) -> Option>> { + self.transaction_orchestrator.clone() + } + + pub fn get_google_jwk_bytes(&self) -> Result, IotaError> { + Ok(get_google_jwk_bytes() + .read() + .map_err(|_| IotaError::JWKRetrievalError)? + .to_vec()) + } + + pub fn subscribe_to_transaction_orchestrator_effects( + &self, + ) -> Result> { + self.transaction_orchestrator + .as_ref() + .map(|to| to.subscribe_to_effects_queue()) + .ok_or_else(|| anyhow::anyhow!("Transaction Orchestrator is not enabled in this node.")) + } + + /// This function awaits the completion of checkpoint execution of the + /// current epoch, after which it iniitiates reconfiguration of the + /// entire system. + pub async fn monitor_reconfiguration(self: Arc) -> Result<()> { + let mut checkpoint_executor = CheckpointExecutor::new( + self.state_sync_handle.subscribe_to_synced_checkpoints(), + self.checkpoint_store.clone(), + self.state.clone(), + self.accumulator.clone(), + self.config.checkpoint_executor_config.clone(), + &self.registry_service.default_registry(), + ); + + let run_with_range = self.config.run_with_range; + loop { + let cur_epoch_store = self.state.load_epoch_store_one_call_per_task(); + + // Advertise capabilities to committee, if we are a validator. + if let Some(components) = &*self.validator_components.lock().await { + // TODO: without this sleep, the consensus message is not delivered reliably. + tokio::time::sleep(Duration::from_millis(1)).await; + + let config = cur_epoch_store.protocol_config(); + let binary_config = to_binary_config(config); + let transaction = + ConsensusTransaction::new_capability_notification(AuthorityCapabilities::new( + self.state.name, + self.config + .supported_protocol_versions + .expect("Supported versions should be populated"), + self.state + .get_available_system_packages(&binary_config) + .await, + )); + info!(?transaction, "submitting capabilities to consensus"); + components + .consensus_adapter + .submit(transaction, None, &cur_epoch_store)?; + } + + let stop_condition = checkpoint_executor + .run_epoch(cur_epoch_store.clone(), run_with_range) + .await; + + if stop_condition == StopReason::RunWithRangeCondition { + IotaNode::shutdown(&self).await; + self.shutdown_channel_tx + .send(run_with_range) + .expect("RunWithRangeCondition met but failed to send shutdown message"); + return Ok(()); + } + + // Safe to call because we are in the middle of reconfiguration. + let latest_system_state = self + .state + .get_cache_reader() + .get_iota_system_state_object_unsafe() + .expect("Read Iota System State object cannot fail"); + + #[cfg(msim)] + if !self + .sim_state + .sim_safe_mode_expected + .load(Ordering::Relaxed) + { + debug_assert!(!latest_system_state.safe_mode()); + } + + #[cfg(not(msim))] + debug_assert!(!latest_system_state.safe_mode()); + + if let Err(err) = self.end_of_epoch_channel.send(latest_system_state.clone()) { + if self.state.is_fullnode(&cur_epoch_store) { + warn!( + "Failed to send end of epoch notification to subscriber: {:?}", + err + ); + } + } + + cur_epoch_store.record_is_safe_mode_metric(latest_system_state.safe_mode()); + let new_epoch_start_state = latest_system_state.into_epoch_start_state(); + let next_epoch_committee = new_epoch_start_state.get_iota_committee(); + let next_epoch = next_epoch_committee.epoch(); + assert_eq!(cur_epoch_store.epoch() + 1, next_epoch); + + info!( + next_epoch, + "Finished executing all checkpoints in epoch. About to reconfigure the system." + ); + + fail_point_async!("reconfig_delay"); + + // We save the connection monitor status map regardless of validator / fullnode + // status so that we don't need to restart the connection monitor + // every epoch. Update the mappings that will be used by the + // consensus adapter if it exists or is about to be created. + let authority_names_to_peer_ids = + new_epoch_start_state.get_authority_names_to_peer_ids(); + self.connection_monitor_status + .update_mapping_for_epoch(authority_names_to_peer_ids); + + cur_epoch_store.record_epoch_reconfig_start_time_metric(); + + let _ = send_trusted_peer_change( + &self.config, + &self.trusted_peer_change_tx, + &new_epoch_start_state, + ); + + // The following code handles 4 different cases, depending on whether the node + // was a validator in the previous epoch, and whether the node is a validator + // in the new epoch. + let new_validator_components = if let Some(ValidatorComponents { + validator_server_handle, + validator_overload_monitor_handle, + consensus_manager, + consensus_epoch_data_remover, + consensus_adapter, + checkpoint_service_exit, + checkpoint_metrics, + iota_tx_validator_metrics, + }) = self.validator_components.lock().await.take() + { + info!("Reconfiguring the validator."); + // Stop the old checkpoint service. + drop(checkpoint_service_exit); + + consensus_manager.shutdown().await; + + let new_epoch_store = self + .reconfigure_state( + &self.state, + &cur_epoch_store, + next_epoch_committee.clone(), + new_epoch_start_state, + &checkpoint_executor, + ) + .await; + + consensus_epoch_data_remover + .remove_old_data(next_epoch - 1) + .await; + + if self.state.is_validator(&new_epoch_store) { + // Only restart Narwhal if this node is still a validator in the new epoch. + Some( + Self::start_epoch_specific_validator_components( + &self.config, + self.state.clone(), + consensus_adapter, + self.checkpoint_store.clone(), + new_epoch_store.clone(), + self.state_sync_handle.clone(), + self.randomness_handle.clone(), + consensus_manager, + consensus_epoch_data_remover, + self.accumulator.clone(), + validator_server_handle, + validator_overload_monitor_handle, + checkpoint_metrics, + self.metrics.clone(), + iota_tx_validator_metrics, + ) + .await?, + ) + } else { + info!("This node is no longer a validator after reconfiguration"); + None + } + } else { + let new_epoch_store = self + .reconfigure_state( + &self.state, + &cur_epoch_store, + next_epoch_committee.clone(), + new_epoch_start_state, + &checkpoint_executor, + ) + .await; + + if self.state.is_validator(&new_epoch_store) { + info!("Promoting the node from fullnode to validator, starting grpc server"); + + Some( + Self::construct_validator_components( + self.config.clone(), + self.state.clone(), + Arc::new(next_epoch_committee.clone()), + new_epoch_store.clone(), + self.checkpoint_store.clone(), + self.state_sync_handle.clone(), + self.randomness_handle.clone(), + self.accumulator.clone(), + self.connection_monitor_status.clone(), + &self.registry_service, + self.metrics.clone(), + ) + .await?, + ) + } else { + None + } + }; + *self.validator_components.lock().await = new_validator_components; + + // Force releasing current epoch store DB handle, because the + // Arc may linger. + cur_epoch_store.release_db_handles(); + + if cfg!(msim) + && !matches!( + self.config + .authority_store_pruning_config + .num_epochs_to_retain_for_checkpoints(), + None | Some(u64::MAX) | Some(0) + ) + { + self.state + .prune_checkpoints_for_eligible_epochs_for_testing( + self.config.clone(), + iota_core::authority::authority_store_pruner::AuthorityStorePruningMetrics::new_for_test(), + ) + .await?; + } + + info!("Reconfiguration finished"); + } + } + + async fn shutdown(&self) { + if let Some(validator_components) = &*self.validator_components.lock().await { + validator_components.consensus_manager.shutdown().await; + } + } + + async fn reconfigure_state( + &self, + state: &Arc, + cur_epoch_store: &AuthorityPerEpochStore, + next_epoch_committee: Committee, + next_epoch_start_system_state: EpochStartSystemState, + checkpoint_executor: &CheckpointExecutor, + ) -> Arc { + let next_epoch = next_epoch_committee.epoch(); + + let last_checkpoint = self + .checkpoint_store + .get_epoch_last_checkpoint(cur_epoch_store.epoch()) + .expect("Error loading last checkpoint for current epoch") + .expect("Could not load last checkpoint for current epoch"); + + let epoch_start_configuration = EpochStartConfiguration::new( + next_epoch_start_system_state, + *last_checkpoint.digest(), + state.get_object_store().as_ref(), + None, + ) + .expect("EpochStartConfiguration construction cannot fail"); + + let new_epoch_store = self + .state + .reconfigure( + cur_epoch_store, + self.config.supported_protocol_versions.unwrap(), + next_epoch_committee, + epoch_start_configuration, + checkpoint_executor, + self.accumulator.clone(), + &self.config.expensive_safety_check_config, + ) + .await + .expect("Reconfigure authority state cannot fail"); + info!(next_epoch, "Node State has been reconfigured"); + assert_eq!(next_epoch, new_epoch_store.epoch()); + self.state.get_reconfig_api().update_epoch_flags_metrics( + cur_epoch_store.epoch_start_config().flags(), + new_epoch_store.epoch_start_config().flags(), + ); + + new_epoch_store + } + + pub fn get_config(&self) -> &NodeConfig { + &self.config + } +} + +#[cfg(not(msim))] +impl IotaNode { + async fn fetch_jwks( + _authority: AuthorityName, + provider: &OIDCProvider, + ) -> IotaResult> { + use fastcrypto_zkp::bn254::zk_login::fetch_jwks; + let client = reqwest::Client::new(); + fetch_jwks(provider, &client) + .await + .map_err(|_| IotaError::JWKRetrievalError) + } +} + +#[cfg(msim)] +impl IotaNode { + pub fn get_sim_node_id(&self) -> iota_simulator::task::NodeId { + self.sim_state.sim_node.id() + } + + pub fn set_safe_mode_expected(&self, new_value: bool) { + info!("Setting safe mode expected to {}", new_value); + self.sim_state + .sim_safe_mode_expected + .store(new_value, Ordering::Relaxed); + } + + #[allow(unused_variables)] + async fn fetch_jwks( + authority: AuthorityName, + provider: &OIDCProvider, + ) -> IotaResult> { + get_jwk_injector()(authority, provider) + } +} + +/// Notify state-sync that a new list of trusted peers are now available. +fn send_trusted_peer_change( + config: &NodeConfig, + sender: &watch::Sender, + epoch_state_state: &EpochStartSystemState, +) -> Result<(), watch::error::SendError> { + sender + .send(TrustedPeerChangeEvent { + new_peers: epoch_state_state.get_validator_as_p2p_peers(config.protocol_public_key()), + }) + .tap_err(|err| { + warn!( + "Failed to send validator peer information to state sync: {:?}", + err + ); + }) +} + +fn build_kv_store( + state: &Arc, + config: &NodeConfig, + registry: &Registry, +) -> Result> { + let metrics = KeyValueStoreMetrics::new(registry); + let db_store = TransactionKeyValueStore::new("rocksdb", metrics.clone(), state.clone()); + + let base_url = &config.transaction_kv_store_read_config.base_url; + + if base_url.is_empty() { + info!("no http kv store url provided, using local db only"); + return Ok(Arc::new(db_store)); + } + + let base_url: url::Url = base_url.parse().tap_err(|e| { + error!( + "failed to parse config.transaction_kv_store_config.base_url ({:?}) as url: {}", + base_url, e + ) + })?; + + let network_str = match state.get_chain_identifier().map(|c| c.chain()) { + Some(Chain::Mainnet) => "/mainnet", + Some(Chain::Testnet) => "/testnet", + _ => { + info!("using local db only for kv store for unknown chain"); + return Ok(Arc::new(db_store)); + } + }; + + let base_url = base_url.join(network_str)?.to_string(); + let http_store = HttpKVStore::new_kv(&base_url, metrics.clone())?; + info!("using local key-value store with fallback to http key-value store"); + Ok(Arc::new(FallbackTransactionKVStore::new_kv( + db_store, + http_store, + metrics, + "json_rpc_fallback", + ))) +} + +pub fn build_http_server( + state: Arc, + store: RocksDbStore, + transaction_orchestrator: &Option>>, + config: &NodeConfig, + prometheus_registry: &Registry, + _custom_runtime: Option, + software_version: &'static str, +) -> Result>> { + // Validators do not expose these APIs + if config.consensus_config().is_some() { + return Ok(None); + } + + let chain_id = state.get_chain_identifier().unwrap(); + + let mut router = axum::Router::new(); + + let json_rpc_router = { + let mut server = JsonRpcServerBuilder::new(env!("CARGO_PKG_VERSION"), prometheus_registry); + + let kv_store = build_kv_store(&state, config, prometheus_registry)?; + + let metrics = Arc::new(JsonRpcMetrics::new(prometheus_registry)); + server.register_module(ReadApi::new( + state.clone(), + kv_store.clone(), + metrics.clone(), + ))?; + server.register_module(CoinReadApi::new( + state.clone(), + kv_store.clone(), + metrics.clone(), + ))?; + + // if run_with_range is enabled we want to prevent any transactions + // run_with_range = None is normal operating conditions + if config.run_with_range.is_none() { + server.register_module(TransactionBuilderApi::new(state.clone()))?; + } + server.register_module(GovernanceReadApi::new(state.clone(), metrics.clone()))?; + + if let Some(transaction_orchestrator) = transaction_orchestrator { + server.register_module(TransactionExecutionApi::new( + state.clone(), + transaction_orchestrator.clone(), + metrics.clone(), + ))?; + } + + let name_service_config = + if let (Some(package_address), Some(registry_id), Some(reverse_registry_id)) = ( + config.name_service_package_address, + config.name_service_registry_id, + config.name_service_reverse_registry_id, + ) { + iota_json_rpc::name_service::NameServiceConfig::new( + package_address, + registry_id, + reverse_registry_id, + ) + } else { + iota_json_rpc::name_service::NameServiceConfig::default() + }; + + server.register_module(IndexerApi::new( + state.clone(), + ReadApi::new(state.clone(), kv_store.clone(), metrics.clone()), + kv_store, + name_service_config, + metrics, + config.indexer_max_subscriptions, + ))?; + server.register_module(MoveUtils::new(state))?; + + let server_type = if config.websocket_only { + Some(ServerType::WebSocket) + } else { + None + }; + server.to_router(server_type)? + }; + + router = router.merge(json_rpc_router); + + if config.enable_experimental_rest_api { + let rest_router = + iota_rest_api::RestService::new(Arc::new(store.clone()), chain_id, software_version) + .into_router(); + router = router.nest("/rest", rest_router); + } + + let server = axum::Server::bind(&config.json_rpc_address).serve(router.into_make_service()); + + let addr = server.local_addr(); + let handle = tokio::spawn(async move { server.await.unwrap() }); + + info!(local_addr =? addr, "Iota JSON-RPC server listening on {addr}"); + + Ok(Some(handle)) +} + +#[cfg(not(test))] +fn max_tx_per_checkpoint(protocol_config: &ProtocolConfig) -> usize { + protocol_config.max_transactions_per_checkpoint() as usize +} + +#[cfg(test)] +fn max_tx_per_checkpoint(_: &ProtocolConfig) -> usize { + 2 +} diff --git a/crates/iota-node/src/main.rs b/crates/iota-node/src/main.rs new file mode 100644 index 00000000000..5b946f897b0 --- /dev/null +++ b/crates/iota-node/src/main.rs @@ -0,0 +1,228 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{path::PathBuf, sync::Arc, time::Duration}; + +use clap::{ArgGroup, Parser}; +use iota_config::{node::RunWithRange, Config, NodeConfig}; +use iota_core::runtime::IotaRuntimes; +use iota_node::metrics; +use iota_protocol_config::SupportedProtocolVersions; +use iota_telemetry::send_telemetry_event; +use iota_types::{ + committee::EpochId, messages_checkpoint::CheckpointSequenceNumber, multiaddr::Multiaddr, +}; +use mysten_common::sync::async_once_cell::AsyncOnceCell; +use tokio::{sync::broadcast, time::sleep}; +use tracing::{error, info}; + +const GIT_REVISION: &str = { + if let Some(revision) = option_env!("GIT_REVISION") { + revision + } else { + let version = git_version::git_version!( + args = ["--always", "--abbrev=12", "--dirty", "--exclude", "*"], + fallback = "" + ); + + if version.is_empty() { + panic!("unable to query git revision"); + } + version + } +}; +const VERSION: &str = const_str::concat!(env!("CARGO_PKG_VERSION"), "-", GIT_REVISION); + +#[derive(Parser)] +#[clap(rename_all = "kebab-case")] +#[clap(name = env!("CARGO_BIN_NAME"))] +#[clap(version = VERSION)] +#[clap(group(ArgGroup::new("exclusive").required(false)))] +struct Args { + #[clap(long)] + pub config_path: PathBuf, + + #[clap(long, help = "Specify address to listen on")] + listen_address: Option, + + #[clap(long, group = "exclusive")] + run_with_range_epoch: Option, + + #[clap(long, group = "exclusive")] + run_with_range_checkpoint: Option, +} + +fn main() { + // Ensure that a validator never calls + // get_for_min_version/get_for_max_version_UNSAFE. TODO: re-enable after we + // figure out how to eliminate crashes in prod because of this. + // ProtocolConfig::poison_get_for_min_version(); + + move_vm_profiler::gas_profiler_feature_enabled! { + panic!("Cannot run the iota-node binary with gas-profiler feature enabled"); + } + + let args = Args::parse(); + let mut config = NodeConfig::load(&args.config_path).unwrap(); + assert!( + config.supported_protocol_versions.is_none(), + "supported_protocol_versions cannot be read from the config file" + ); + config.supported_protocol_versions = Some(SupportedProtocolVersions::SYSTEM_DEFAULT); + + // match run_with_range args + // this means that we always modify the config used to start the node + // for run_with_range. i.e if this is set in the config, it is ignored. only the + // cli args enable/disable run_with_range + match (args.run_with_range_epoch, args.run_with_range_checkpoint) { + (None, Some(checkpoint)) => { + config.run_with_range = Some(RunWithRange::Checkpoint(checkpoint)) + } + (Some(epoch), None) => config.run_with_range = Some(RunWithRange::Epoch(epoch)), + _ => config.run_with_range = None, + }; + + let runtimes = IotaRuntimes::new(&config); + let metrics_rt = runtimes.metrics.enter(); + let registry_service = mysten_metrics::start_prometheus_server(config.metrics_address); + let prometheus_registry = registry_service.default_registry(); + + // Initialize logging + let (_guard, filter_handle) = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .with_prom_registry(&prometheus_registry) + .init(); + + drop(metrics_rt); + + info!("Iota Node version: {VERSION}"); + info!( + "Supported protocol versions: {:?}", + config.supported_protocol_versions + ); + + info!( + "Started Prometheus HTTP endpoint at {}", + config.metrics_address + ); + + { + let _enter = runtimes.metrics.enter(); + metrics::start_metrics_push_task(&config, registry_service.clone()); + } + + if let Some(listen_address) = args.listen_address { + config.network_address = listen_address; + } + + let is_validator = config.consensus_config().is_some(); + + let admin_interface_port = config.admin_interface_port; + + // Run node in a separate runtime so that admin/monitoring functions continue to + // work if it deadlocks. + let node_once_cell = Arc::new(AsyncOnceCell::>::new()); + let node_once_cell_clone = node_once_cell.clone(); + let rpc_runtime = runtimes.json_rpc.handle().clone(); + + // let iota-node signal main to shutdown runtimes + let (runtime_shutdown_tx, runtime_shutdown_rx) = broadcast::channel::<()>(1); + + runtimes.iota_node.spawn(async move { + match iota_node::IotaNode::start_async(config, registry_service, Some(rpc_runtime), VERSION).await { + Ok(iota_node) => node_once_cell_clone + .set(iota_node) + .expect("Failed to set node in AsyncOnceCell"), + + Err(e) => { + error!("Failed to start node: {e:?}"); + std::process::exit(1); + } + } + + // get node, subscribe to shutdown channel + let node = node_once_cell_clone.get().await; + let mut shutdown_rx = node.subscribe_to_shutdown_channel(); + + // when we get a shutdown signal from iota-node, forward it on to the runtime_shutdown_channel here in + // main to signal runtimes to all shutdown. + tokio::select! { + _ = shutdown_rx.recv() => { + runtime_shutdown_tx.send(()).expect("failed to forward shutdown signal from iota-node to iota-node main"); + } + } + // TODO: Do we want to provide a way for the node to gracefully shutdown? + loop { + tokio::time::sleep(Duration::from_secs(1000)).await; + } + }); + + let node_once_cell_clone = node_once_cell.clone(); + runtimes.metrics.spawn(async move { + let node = node_once_cell_clone.get().await; + let chain_identifier = match node.state().get_chain_identifier() { + Some(chain_identifier) => chain_identifier.to_string(), + None => "unknown".to_string(), + }; + + info!("Iota chain identifier: {chain_identifier}"); + prometheus_registry + .register(mysten_metrics::uptime_metric( + if is_validator { + "validator" + } else { + "fullnode" + }, + VERSION, + chain_identifier.as_str(), + )) + .unwrap(); + + iota_node::admin::run_admin_server(node, admin_interface_port, filter_handle).await + }); + + runtimes.metrics.spawn(async move { + let node = node_once_cell.get().await; + let state = node.state(); + loop { + send_telemetry_event(state.clone(), is_validator).await; + sleep(Duration::from_secs(3600)).await; + } + }); + + // wait for SIGINT on the main thread + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(wait_termination(runtime_shutdown_rx)); + + // Drop and wait all runtimes on main thread + drop(runtimes); +} + +#[cfg(not(unix))] +async fn wait_termination(mut shutdown_rx: tokio::sync::broadcast::Receiver<()>) { + tokio::select! { + _ = tokio::signal::ctrl_c() => {}, + _ = shutdown_rx.recv() => {}, + } +} + +#[cfg(unix)] +async fn wait_termination(mut shutdown_rx: tokio::sync::broadcast::Receiver<()>) { + use futures::FutureExt; + use tokio::signal::unix::*; + + let sigint = tokio::signal::ctrl_c().boxed(); + let mut sigterm = signal(SignalKind::terminate()).unwrap(); + let sigterm_recv = sigterm.recv().boxed(); + let shutdown_recv = shutdown_rx.recv().boxed(); + + tokio::select! { + _ = sigint => {}, + _ = sigterm_recv => {}, + _ = shutdown_recv => {}, + } +} diff --git a/crates/iota-node/src/metrics.rs b/crates/iota-node/src/metrics.rs new file mode 100644 index 00000000000..0ba3f26f90b --- /dev/null +++ b/crates/iota-node/src/metrics.rs @@ -0,0 +1,341 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +use axum::http::header; +use iota_network::tonic::Code; +use mysten_metrics::RegistryService; +use mysten_network::metrics::MetricsCallbackProvider; +use prometheus::{ + register_histogram_vec_with_registry, register_int_counter_vec_with_registry, + register_int_gauge_vec_with_registry, Encoder, HistogramVec, IntCounterVec, IntGaugeVec, + Registry, PROTOBUF_FORMAT, +}; +use tracing::error; + +pub struct MetricsPushClient { + certificate: std::sync::Arc, + client: reqwest::Client, +} + +impl MetricsPushClient { + pub fn new(network_key: iota_types::crypto::NetworkKeyPair) -> Self { + use fastcrypto::traits::KeyPair; + let certificate = std::sync::Arc::new(iota_tls::SelfSignedCertificate::new( + network_key.private(), + iota_tls::IOTA_VALIDATOR_SERVER_NAME, + )); + let identity = certificate.reqwest_identity(); + let client = reqwest::Client::builder() + .identity(identity) + .build() + .unwrap(); + + Self { + certificate, + client, + } + } + + pub fn certificate(&self) -> &iota_tls::SelfSignedCertificate { + &self.certificate + } + + pub fn client(&self) -> &reqwest::Client { + &self.client + } +} + +/// Starts a task to periodically push metrics to a configured endpoint if a +/// metrics push endpoint is configured. +pub fn start_metrics_push_task(config: &iota_config::NodeConfig, registry: RegistryService) { + use fastcrypto::traits::KeyPair; + use iota_config::node::MetricsConfig; + + const DEFAULT_METRICS_PUSH_INTERVAL: Duration = Duration::from_secs(60); + + let (interval, url) = match &config.metrics { + Some(MetricsConfig { + push_interval_seconds, + push_url: Some(url), + }) => { + let interval = push_interval_seconds + .map(Duration::from_secs) + .unwrap_or(DEFAULT_METRICS_PUSH_INTERVAL); + let url = reqwest::Url::parse(url).expect("unable to parse metrics push url"); + (interval, url) + } + _ => return, + }; + + // make a copy so we can make a new client later when we hit errors posting + // metrics + let config_copy = config.clone(); + let mut client = MetricsPushClient::new(config_copy.network_key_pair().copy()); + + async fn push_metrics( + client: &MetricsPushClient, + url: &reqwest::Url, + registry: &RegistryService, + ) -> Result<(), anyhow::Error> { + // now represents a collection timestamp for all of the metrics we send to the + // proxy + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() as i64; + + let mut metric_families = registry.gather_all(); + for mf in metric_families.iter_mut() { + for m in mf.mut_metric() { + m.set_timestamp_ms(now); + } + } + + let mut buf: Vec = vec![]; + let encoder = prometheus::ProtobufEncoder::new(); + encoder.encode(&metric_families, &mut buf)?; + + let mut s = snap::raw::Encoder::new(); + let compressed = s.compress_vec(&buf).map_err(|err| { + error!("unable to snappy encode; {err}"); + err + })?; + + let response = client + .client() + .post(url.to_owned()) + .header(reqwest::header::CONTENT_ENCODING, "snappy") + .header(header::CONTENT_TYPE, PROTOBUF_FORMAT) + .body(compressed) + .send() + .await?; + + if !response.status().is_success() { + let status = response.status(); + let body = match response.text().await { + Ok(body) => body, + Err(error) => format!("couldn't decode response body; {error}"), + }; + return Err(anyhow::anyhow!( + "metrics push failed: [{}]:{}", + status, + body + )); + } + + tracing::debug!("successfully pushed metrics to {url}"); + + Ok(()) + } + + tokio::spawn(async move { + tracing::info!(push_url =% url, interval =? interval, "Started Metrics Push Service"); + + let mut interval = tokio::time::interval(interval); + interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); + + loop { + interval.tick().await; + + if let Err(error) = push_metrics(&client, &url, ®istry).await { + tracing::warn!("unable to push metrics: {error}; new client will be created"); + // aggressively recreate our client connection if we hit an error + // since our tick interval is only every min, this should not be racey + client = MetricsPushClient::new(config_copy.network_key_pair().copy()); + } + } + }); +} + +pub struct IotaNodeMetrics { + pub jwk_requests: IntCounterVec, + pub jwk_request_errors: IntCounterVec, + + pub total_jwks: IntCounterVec, + pub invalid_jwks: IntCounterVec, + pub unique_jwks: IntCounterVec, +} + +impl IotaNodeMetrics { + pub fn new(registry: &Registry) -> Self { + Self { + jwk_requests: register_int_counter_vec_with_registry!( + "jwk_requests", + "Total number of JWK requests", + &["provider"], + registry, + ) + .unwrap(), + jwk_request_errors: register_int_counter_vec_with_registry!( + "jwk_request_errors", + "Total number of JWK request errors", + &["provider"], + registry, + ) + .unwrap(), + total_jwks: register_int_counter_vec_with_registry!( + "total_jwks", + "Total number of JWKs", + &["provider"], + registry, + ) + .unwrap(), + invalid_jwks: register_int_counter_vec_with_registry!( + "invalid_jwks", + "Total number of invalid JWKs", + &["provider"], + registry, + ) + .unwrap(), + unique_jwks: register_int_counter_vec_with_registry!( + "unique_jwks", + "Total number of unique JWKs", + &["provider"], + registry, + ) + .unwrap(), + } + } +} + +#[derive(Clone)] +pub struct GrpcMetrics { + inflight_grpc: IntGaugeVec, + grpc_requests: IntCounterVec, + grpc_request_latency: HistogramVec, +} + +const LATENCY_SEC_BUCKETS: &[f64] = &[ + 0.001, 0.005, 0.01, 0.05, 0.1, 0.25, 0.5, 1., 2.5, 5., 10., 20., 30., 60., 90., +]; + +impl GrpcMetrics { + pub fn new(registry: &Registry) -> Self { + Self { + inflight_grpc: register_int_gauge_vec_with_registry!( + "inflight_grpc", + "Total in-flight GRPC requests per route", + &["path"], + registry, + ) + .unwrap(), + grpc_requests: register_int_counter_vec_with_registry!( + "grpc_requests", + "Total GRPC requests per route", + &["path", "status"], + registry, + ) + .unwrap(), + grpc_request_latency: register_histogram_vec_with_registry!( + "grpc_request_latency", + "Latency of GRPC requests per route", + &["path"], + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + } + } +} + +impl MetricsCallbackProvider for GrpcMetrics { + fn on_request(&self, _path: String) {} + + fn on_response(&self, path: String, latency: Duration, _status: u16, grpc_status_code: Code) { + self.grpc_requests + .with_label_values(&[path.as_str(), format!("{grpc_status_code:?}").as_str()]) + .inc(); + self.grpc_request_latency + .with_label_values(&[path.as_str()]) + .observe(latency.as_secs_f64()); + } + + fn on_start(&self, path: &str) { + self.inflight_grpc.with_label_values(&[path]).inc(); + } + + fn on_drop(&self, path: &str) { + self.inflight_grpc.with_label_values(&[path]).dec(); + } +} + +#[cfg(test)] +mod tests { + use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + + use mysten_metrics::start_prometheus_server; + use prometheus::{IntCounter, Registry}; + + #[tokio::test] + pub async fn test_metrics_endpoint_with_multiple_registries_add_remove() { + let port: u16 = 8081; + let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port); + + let registry_service = start_prometheus_server(socket); + + tokio::task::yield_now().await; + + // now add a few registries to the service along side with metrics + let registry_1 = Registry::new_custom(Some("narwhal".to_string()), None).unwrap(); + let counter_1 = IntCounter::new("counter_1", "a sample counter 1").unwrap(); + registry_1.register(Box::new(counter_1)).unwrap(); + + let registry_2 = Registry::new_custom(Some("iota".to_string()), None).unwrap(); + let counter_2 = IntCounter::new("counter_2", "a sample counter 2").unwrap(); + registry_2.register(Box::new(counter_2.clone())).unwrap(); + + let registry_1_id = registry_service.add(registry_1); + let _registry_2_id = registry_service.add(registry_2); + + // request the endpoint + let result = get_metrics(port).await; + + assert!(result.contains( + "# HELP iota_counter_2 a sample counter 2 +# TYPE iota_counter_2 counter +iota_counter_2 0" + )); + + assert!(result.contains( + "# HELP narwhal_counter_1 a sample counter 1 +# TYPE narwhal_counter_1 counter +narwhal_counter_1 0" + )); + + // Now remove registry 1 + assert!(registry_service.remove(registry_1_id)); + + // AND increase metric 2 + counter_2.inc(); + + // Now pull again metrics + // request the endpoint + let result = get_metrics(port).await; + + // Registry 1 metrics should not be present anymore + assert!(!result.contains( + "# HELP narwhal_counter_1 a sample counter 1 +# TYPE narwhal_counter_1 counter +narwhal_counter_1 0" + )); + + // Registry 2 metric should have increased by 1 + assert!(result.contains( + "# HELP iota_counter_2 a sample counter 2 +# TYPE iota_counter_2 counter +iota_counter_2 1" + )); + } + + async fn get_metrics(port: u16) -> String { + let client = reqwest::Client::new(); + let response = client + .get(format!("http://127.0.0.1:{}/metrics", port)) + .send() + .await + .unwrap(); + response.text().await.unwrap() + } +} diff --git a/crates/iota-open-rpc-macros/Cargo.toml b/crates/iota-open-rpc-macros/Cargo.toml new file mode 100644 index 00000000000..6f949daf626 --- /dev/null +++ b/crates/iota-open-rpc-macros/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "iota-open-rpc-macros" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +proc-macro = true + +[dependencies] +syn.workspace = true +quote.workspace = true +proc-macro2.workspace = true +itertools.workspace = true +derive-syn-parse.workspace = true +unescape.workspace = true diff --git a/crates/iota-open-rpc-macros/src/lib.rs b/crates/iota-open-rpc-macros/src/lib.rs new file mode 100644 index 00000000000..964e1e49bf4 --- /dev/null +++ b/crates/iota-open-rpc-macros/src/lib.rs @@ -0,0 +1,488 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use derive_syn_parse::Parse; +use itertools::Itertools; +use proc_macro::TokenStream; +use proc_macro2::{Ident, Span, TokenStream as TokenStream2, TokenTree}; +use quote::{quote, ToTokens, TokenStreamExt}; +use syn::{ + parse, + parse::{Parse, ParseStream}, + parse_macro_input, + punctuated::Punctuated, + spanned::Spanned, + token::{Comma, Paren}, + Attribute, GenericArgument, LitStr, PatType, Path, PathArguments, Token, TraitItem, Type, +}; +use unescape::unescape; + +const IOTA_RPC_ATTRS: [&str; 2] = ["deprecated", "version"]; + +/// Add a [Service name]OpenRpc struct and implementation providing access to +/// Open RPC doc builder. This proc macro must be use in conjunction with +/// `jsonrpsee_proc_macro::rpc` +/// +/// The generated method `open_rpc` is added to [Service name]OpenRpc, +/// ideally we want to add this to the trait generated by jsonrpsee framework, +/// creating a new struct to provide access to the method is a workaround. +/// +/// TODO: consider contributing the open rpc doc macro to jsonrpsee to simplify +/// the logics. +#[proc_macro_attribute] +pub fn open_rpc(attr: TokenStream, item: TokenStream) -> TokenStream { + let attr: OpenRpcAttributes = parse_macro_input!(attr); + + let mut trait_data: syn::ItemTrait = syn::parse(item).unwrap(); + let rpc_definition = parse_rpc_method(&mut trait_data).unwrap(); + + let namespace = attr + .find_attr("namespace") + .map(|str| str.value()) + .unwrap_or_default(); + + let tag = attr.find_attr("tag").to_quote(); + + let methods = rpc_definition.methods.iter().map(|method|{ + let name = &method.name; + let deprecated = method.deprecated; + let doc = &method.doc; + let mut inputs = Vec::new(); + for (name, ty, description) in &method.params { + let (ty, required) = extract_type_from_option(ty.clone()); + let description = if let Some(description) = description { + quote! {Some(#description.to_string())} + } else { + quote! {None} + }; + + inputs.push(quote! { + let des = builder.create_content_descriptor::<#ty>(#name, None, #description, #required); + inputs.push(des); + }) + } + let returns_ty = if let Some(ty) = &method.returns { + let (ty, required) = extract_type_from_option(ty.clone()); + let name = quote! {#ty}.to_string(); + quote! {Some(builder.create_content_descriptor::<#ty>(#name, None, None, #required));} + } else { + quote! {None;} + }; + + if method.is_pubsub { + quote! { + let mut inputs: Vec = Vec::new(); + #(#inputs)* + let result = #returns_ty + builder.add_subscription(#namespace, #name, inputs, result, #doc, #tag, #deprecated); + } + } else { + quote! { + let mut inputs: Vec = Vec::new(); + #(#inputs)* + let result = #returns_ty + builder.add_method(#namespace, #name, inputs, result, #doc, #tag, #deprecated); + } + } + }).collect::>(); + + let routes = rpc_definition + .version_routing + .into_iter() + .map(|route| { + let name = route.name; + let route_to = route.route_to; + let comparator = route.token.to_string(); + let version = route.version; + quote! { + builder.add_method_routing(#namespace, #name, #route_to, #comparator, #version); + } + }) + .collect::>(); + + let open_rpc_name = quote::format_ident!("{}OpenRpc", &rpc_definition.name); + + quote! { + #trait_data + pub struct #open_rpc_name; + impl #open_rpc_name { + pub fn module_doc() -> iota_open_rpc::Module{ + let mut builder = iota_open_rpc::RpcModuleDocBuilder::default(); + #(#methods)* + #(#routes)* + builder.build() + } + } + } + .into() +} + +trait OptionalQuote { + fn to_quote(&self) -> TokenStream2; + + fn unwrap_quote(&self, quote: F) -> TokenStream2 + where + F: FnOnce(LitStr) -> TokenStream2; +} + +impl OptionalQuote for Option { + fn to_quote(&self) -> TokenStream2 { + if let Some(value) = self { + quote!(Some(#value.to_string())) + } else { + quote!(None) + } + } + + fn unwrap_quote(&self, quote: F) -> TokenStream2 + where + F: FnOnce(LitStr) -> TokenStream2, + { + if let Some(lit_str) = self { + quote(lit_str.clone()) + } else { + quote!() + } + } +} + +struct RpcDefinition { + name: Ident, + methods: Vec, + version_routing: Vec, +} +struct Method { + name: String, + params: Vec<(String, Type, Option)>, + returns: Option, + doc: String, + is_pubsub: bool, + deprecated: bool, +} +struct Routing { + name: String, + route_to: String, + token: TokenStream2, + version: String, +} + +fn parse_rpc_method(trait_data: &mut syn::ItemTrait) -> Result { + let mut methods = Vec::new(); + let mut version_routing = Vec::new(); + for trait_item in &mut trait_data.items { + if let TraitItem::Method(method) = trait_item { + let doc = extract_doc_comments(&method.attrs).to_string(); + let params: Vec<_> = method + .sig + .inputs + .iter_mut() + .filter_map(|arg| { + match arg { + syn::FnArg::Receiver(_) => None, + syn::FnArg::Typed(arg) => { + let description = if let Some(description) = arg.attrs.iter().position(|a|a.path.is_ident("doc")){ + let doc = extract_doc_comments(&arg.attrs); + arg.attrs.remove(description); + Some(doc) + }else{ + None + }; + match *arg.pat.clone() { + syn::Pat::Ident(name) => { + Some(get_type(arg).map(|ty| (name.ident.to_string(), ty, description))) + } + syn::Pat::Wild(wild) => Some(Err(syn::Error::new( + wild.underscore_token.span(), + "Method argument names must be valid Rust identifiers; got `_` instead", + ))), + _ => Some(Err(syn::Error::new( + arg.span(), + format!("Unexpected method signature input; got {:?} ", *arg.pat), + ))), + } + }, + } + }) + .collect::>()?; + + let (method_name, returns, is_pubsub, deprecated) = if let Some(attr) = + find_attr(&mut method.attrs, "method") + { + let token: TokenStream = attr.tokens.clone().into(); + let returns = match &method.sig.output { + syn::ReturnType::Default => None, + syn::ReturnType::Type(_, output) => extract_type_from(output, "RpcResult"), + }; + let mut attributes = parse::(token)?; + let method_name = attributes.get_value("name"); + let deprecated = attributes.find("deprecated").is_some(); + + if let Some(version_attr) = attributes.find("version") { + if let (Some(token), Some(version)) = (&version_attr.token, &version_attr.value) + { + let route_to = + format!("{method_name}_{}", version.value().replace('.', "_")); + version_routing.push(Routing { + name: method_name, + route_to: route_to.clone(), + token: token.to_token_stream(), + version: version.value(), + }); + if let Some(name) = attributes.find_mut("name") { + name.value + .replace(LitStr::new(&route_to, Span::call_site())); + } + attr.tokens = remove_iota_rpc_attributes(attributes); + continue; + } + } + attr.tokens = remove_iota_rpc_attributes(attributes); + (method_name, returns, false, deprecated) + } else if let Some(attr) = find_attr(&mut method.attrs, "subscription") { + let token: TokenStream = attr.tokens.clone().into(); + let attributes = parse::(token)?; + let name = attributes.get_value("name"); + let type_ = attributes + .find("item") + .expect("Subscription should have a [item] attribute") + .type_ + .clone() + .expect("[item] attribute should have a value"); + let deprecated = attributes.find("deprecated").is_some(); + attr.tokens = remove_iota_rpc_attributes(attributes); + (name, Some(type_), true, deprecated) + } else { + panic!("Unknown method name") + }; + + methods.push(Method { + name: method_name, + params, + returns, + doc, + is_pubsub, + deprecated, + }); + } + } + Ok(RpcDefinition { + name: trait_data.ident.clone(), + methods, + version_routing, + }) +} +// Remove Iota rpc specific attributes. +fn remove_iota_rpc_attributes(attributes: Attributes) -> TokenStream2 { + let attrs = attributes + .attrs + .into_iter() + .filter(|r| !IOTA_RPC_ATTRS.contains(&r.key.to_string().as_str())) + .collect::>(); + quote! {(#attrs)} +} + +fn extract_type_from(ty: &Type, from_ty: &str) -> Option { + fn path_is(path: &Path, from_ty: &str) -> bool { + path.leading_colon.is_none() + && path.segments.len() == 1 + && path.segments.iter().next().unwrap().ident == from_ty + } + + if let Type::Path(p) = ty { + if p.qself.is_none() && path_is(&p.path, from_ty) { + if let PathArguments::AngleBracketed(a) = &p.path.segments[0].arguments { + if let Some(GenericArgument::Type(ty)) = a.args.first() { + return Some(ty.clone()); + } + } + } + } + None +} + +fn extract_type_from_option(ty: Type) -> (Type, bool) { + if let Some(ty) = extract_type_from(&ty, "Option") { + (ty, false) + } else { + (ty, true) + } +} + +fn get_type(pat_type: &mut PatType) -> Result { + Ok( + if let Some((pos, attr)) = pat_type + .attrs + .iter() + .find_position(|a| a.path.is_ident("schemars")) + { + let attribute = parse::(attr.tokens.clone().into())?; + + let stream = syn::parse_str(&attribute.value.value())?; + let tokens = respan_token_stream(stream, attribute.value.span()); + + let path = syn::parse2(tokens)?; + pat_type.attrs.remove(pos); + path + } else { + pat_type.ty.as_ref().clone() + }, + ) +} + +fn find_attr<'a>(attrs: &'a mut [Attribute], ident: &str) -> Option<&'a mut Attribute> { + attrs.iter_mut().find(|a| a.path.is_ident(ident)) +} + +fn respan_token_stream(stream: TokenStream2, span: Span) -> TokenStream2 { + stream + .into_iter() + .map(|mut token| { + if let TokenTree::Group(g) = &mut token { + *g = proc_macro2::Group::new(g.delimiter(), respan_token_stream(g.stream(), span)); + } + token.set_span(span); + token + }) + .collect() +} + +fn extract_doc_comments(attrs: &[Attribute]) -> String { + let s = attrs + .iter() + .filter(|attr| { + attr.path.is_ident("doc") + && match attr.parse_meta() { + Ok(syn::Meta::NameValue(meta)) => matches!(&meta.lit, syn::Lit::Str(_)), + _ => false, + } + }) + .map(|attr| { + let s = attr.tokens.to_string(); + s[4..s.len() - 1].to_string() + }) + .join(" "); + unescape(&s).unwrap_or_else(|| panic!("Cannot unescape doc comments : [{s}]")) +} + +#[derive(Parse, Debug)] +struct OpenRpcAttributes { + #[parse_terminated(OpenRpcAttribute::parse)] + fields: Punctuated, +} + +impl OpenRpcAttributes { + fn find_attr(&self, name: &str) -> Option { + self.fields + .iter() + .find(|attr| attr.label == name) + .map(|attr| attr.value.clone()) + } +} + +#[derive(Parse, Debug)] +struct OpenRpcAttribute { + label: Ident, + _eq_token: Token![=], + value: syn::LitStr, +} + +#[derive(Parse, Debug)] +struct NamedAttribute { + #[paren] + _paren_token: Paren, + #[inside(_paren_token)] + _ident: Ident, + #[inside(_paren_token)] + _eq_token: Token![=], + #[inside(_paren_token)] + value: syn::LitStr, +} + +#[derive(Debug)] +struct Attributes { + pub attrs: Punctuated, +} + +impl Attributes { + pub fn find(&self, attr_name: &str) -> Option<&Attr> { + self.attrs.iter().find(|attr| attr.key == attr_name) + } + pub fn find_mut(&mut self, attr_name: &str) -> Option<&mut Attr> { + self.attrs.iter_mut().find(|attr| attr.key == attr_name) + } + pub fn get_value(&self, attr_name: &str) -> String { + self.attrs + .iter() + .find(|attr| attr.key == attr_name) + .unwrap_or_else(|| panic!("Method should have a [{attr_name}] attribute.")) + .value + .as_ref() + .unwrap_or_else(|| panic!("[{attr_name}] attribute should have a value")) + .value() + } +} + +impl Parse for Attributes { + fn parse(input: ParseStream) -> syn::Result { + let content; + let _paren = syn::parenthesized!(content in input); + let attrs = content.parse_terminated(Attr::parse)?; + Ok(Self { attrs }) + } +} + +#[derive(Debug)] +struct Attr { + pub key: Ident, + pub token: Option, + pub value: Option, + pub type_: Option, +} + +impl ToTokens for Attr { + fn to_tokens(&self, tokens: &mut TokenStream2) { + tokens.append(self.key.clone()); + if let Some(token) = &self.token { + tokens.extend(token.to_token_stream()); + } + if let Some(value) = &self.value { + tokens.append(value.token()); + } + if let Some(type_) = &self.type_ { + tokens.extend(type_.to_token_stream()); + } + } +} + +impl Parse for Attr { + fn parse(input: ParseStream) -> syn::Result { + let key = input.parse()?; + let token = if input.peek(Token!(=)) { + Some(input.parse::()?.to_token_stream()) + } else if input.peek(Token!(<=)) { + Some(input.parse::()?.to_token_stream()) + } else { + None + }; + + let value = if token.is_some() && input.peek(syn::LitStr) { + Some(input.parse::()?) + } else { + None + }; + + let type_ = if token.is_some() && input.peek(syn::Ident) { + Some(input.parse::()?) + } else { + None + }; + + Ok(Self { + key, + token, + value, + type_, + }) + } +} diff --git a/crates/iota-open-rpc/Cargo.toml b/crates/iota-open-rpc/Cargo.toml new file mode 100644 index 00000000000..131cb1fa728 --- /dev/null +++ b/crates/iota-open-rpc/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "iota-open-rpc" +version.workspace = true +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +schemars.workspace = true +serde.workspace = true +serde_json.workspace = true +bcs.workspace = true +versions.workspace = true + +[dev-dependencies] +anyhow.workspace = true +clap.workspace = true +pretty_assertions.workspace = true +tokio = { workspace = true, features = ["full"] } +fastcrypto = { workspace = true } +iota-json-rpc.workspace = true +iota-json-rpc-api.workspace = true +iota-json-rpc-types.workspace = true +iota-json.workspace = true +iota-types = { workspace = true, features = ["test-utils"] } +iota-protocol-config.workspace = true +rand.workspace = true + +move-core-types.workspace = true + +[[example]] +name = "generate-json-rpc-spec" +path = "src/generate_json_rpc_spec.rs" +test = false diff --git a/crates/sui-open-rpc/spec/openrpc.json b/crates/iota-open-rpc/spec/openrpc.json similarity index 94% rename from crates/sui-open-rpc/spec/openrpc.json rename to crates/iota-open-rpc/spec/openrpc.json index 840b70ad53e..3f9ed848d3d 100644 --- a/crates/sui-open-rpc/spec/openrpc.json +++ b/crates/iota-open-rpc/spec/openrpc.json @@ -1,8 +1,8 @@ { "openrpc": "1.2.6", "info": { - "title": "Sui JSON-RPC", - "description": "Sui JSON-RPC API for interaction with Sui Full node. Make RPC calls using https://fullnode.NETWORK.sui.io:443, where NETWORK is the network you want to use (testnet, devnet, mainnet). By default, local networks use port 9000.", + "title": "Iota JSON-RPC", + "description": "Iota JSON-RPC API for interaction with Iota Full node. Make RPC calls using https://fullnode.NETWORK.iota.io:443, where NETWORK is the network you want to use (testnet, devnet, mainnet). By default, local networks use port 9000.", "contact": { "name": "Mysten Labs", "url": "https://mystenlabs.com", @@ -10,13 +10,13 @@ }, "license": { "name": "Apache-2.0", - "url": "https://raw.githubusercontent.com/MystenLabs/sui/main/LICENSE" + "url": "https://raw.githubusercontent.com/iotaledger/iota/main/LICENSE" }, "version": "1.22.0" }, "methods": [ { - "name": "sui_devInspectTransactionBlock", + "name": "iota_devInspectTransactionBlock", "tags": [ { "name": "Write API" @@ -28,7 +28,7 @@ "name": "sender_address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { @@ -150,7 +150,7 @@ ] }, { - "name": "sui_dryRunTransactionBlock", + "name": "iota_dryRunTransactionBlock", "tags": [ { "name": "Write API" @@ -305,7 +305,7 @@ ] }, { - "name": "sui_executeTransactionBlock", + "name": "iota_executeTransactionBlock", "tags": [ { "name": "Write API" @@ -341,14 +341,14 @@ }, { "name": "request_type", - "description": "The request type, derived from `SuiTransactionBlockResponseOptions` if None", + "description": "The request type, derived from `IotaTransactionBlockResponseOptions` if None", "schema": { "$ref": "#/components/schemas/ExecuteTransactionRequestType" } } ], "result": { - "name": "SuiTransactionBlockResponse", + "name": "IotaTransactionBlockResponse", "required": true, "schema": { "$ref": "#/components/schemas/TransactionBlockResponse" @@ -508,7 +508,7 @@ ] }, { - "name": "sui_getChainIdentifier", + "name": "iota_getChainIdentifier", "tags": [ { "name": "Read API" @@ -535,7 +535,7 @@ ] }, { - "name": "sui_getCheckpoint", + "name": "iota_getCheckpoint", "tags": [ { "name": "Read API" @@ -594,7 +594,7 @@ ] }, { - "name": "sui_getCheckpoints", + "name": "iota_getCheckpoints", "tags": [ { "name": "Read API" @@ -740,7 +740,7 @@ ] }, { - "name": "sui_getEvents", + "name": "iota_getEvents", "tags": [ { "name": "Read API" @@ -758,7 +758,7 @@ } ], "result": { - "name": "Vec", + "name": "Vec", "required": true, "schema": { "type": "array", @@ -806,7 +806,7 @@ ] }, { - "name": "sui_getLatestCheckpointSequenceNumber", + "name": "iota_getLatestCheckpointSequenceNumber", "tags": [ { "name": "Read API" @@ -833,7 +833,7 @@ ] }, { - "name": "sui_getLoadedChildObjects", + "name": "iota_getLoadedChildObjects", "tags": [ { "name": "Read API" @@ -849,7 +849,7 @@ } ], "result": { - "name": "SuiLoadedChildObjectsResponse", + "name": "IotaLoadedChildObjectsResponse", "required": true, "schema": { "$ref": "#/components/schemas/LoadedChildObjectsResponse" @@ -899,7 +899,7 @@ ] }, { - "name": "sui_getMoveFunctionArgTypes", + "name": "iota_getMoveFunctionArgTypes", "tags": [ { "name": "Move Utils" @@ -949,7 +949,7 @@ }, { "name": "module", - "value": "suifrens" + "value": "iotafrens" }, { "name": "function", @@ -982,7 +982,7 @@ ] }, { - "name": "sui_getNormalizedMoveFunction", + "name": "iota_getNormalizedMoveFunction", "tags": [ { "name": "Move Utils" @@ -1013,10 +1013,10 @@ } ], "result": { - "name": "SuiMoveNormalizedFunction", + "name": "IotaMoveNormalizedFunction", "required": true, "schema": { - "$ref": "#/components/schemas/SuiMoveNormalizedFunction" + "$ref": "#/components/schemas/IotaMoveNormalizedFunction" } }, "examples": [ @@ -1061,7 +1061,7 @@ ] }, { - "name": "sui_getNormalizedMoveModule", + "name": "iota_getNormalizedMoveModule", "tags": [ { "name": "Move Utils" @@ -1085,10 +1085,10 @@ } ], "result": { - "name": "SuiMoveNormalizedModule", + "name": "IotaMoveNormalizedModule", "required": true, "schema": { - "$ref": "#/components/schemas/SuiMoveNormalizedModule" + "$ref": "#/components/schemas/IotaMoveNormalizedModule" } }, "examples": [ @@ -1119,7 +1119,7 @@ ] }, { - "name": "sui_getNormalizedMoveModulesByPackage", + "name": "iota_getNormalizedMoveModulesByPackage", "tags": [ { "name": "Move Utils" @@ -1136,12 +1136,12 @@ } ], "result": { - "name": "BTreeMap", + "name": "BTreeMap", "required": true, "schema": { "type": "object", "additionalProperties": { - "$ref": "#/components/schemas/SuiMoveNormalizedModule" + "$ref": "#/components/schemas/IotaMoveNormalizedModule" } } }, @@ -1169,7 +1169,7 @@ ] }, { - "name": "sui_getNormalizedMoveStruct", + "name": "iota_getNormalizedMoveStruct", "tags": [ { "name": "Move Utils" @@ -1200,10 +1200,10 @@ } ], "result": { - "name": "SuiMoveNormalizedStruct", + "name": "IotaMoveNormalizedStruct", "required": true, "schema": { - "$ref": "#/components/schemas/SuiMoveNormalizedStruct" + "$ref": "#/components/schemas/IotaMoveNormalizedStruct" } }, "examples": [ @@ -1240,7 +1240,7 @@ ] }, { - "name": "sui_getObject", + "name": "iota_getObject", "tags": [ { "name": "Read API" @@ -1265,10 +1265,10 @@ } ], "result": { - "name": "SuiObjectResponse", + "name": "IotaObjectResponse", "required": true, "schema": { - "$ref": "#/components/schemas/SuiObjectResponse" + "$ref": "#/components/schemas/IotaObjectResponse" } }, "examples": [ @@ -1299,7 +1299,7 @@ "objectId": "0x53e4567ccafa5f36ce84c80aa8bc9be64e0d5ae796884274aef3005ae6733809", "version": "1", "digest": "33K5ZXJ3RyubvYaHuEnQ1QXmmbhgtrFwp199dnEbL4n7", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0xc8ec1d5b84dd6289e193b9f88de4a994358c9f856135236c3e75a925e1c77ac3" }, @@ -1307,7 +1307,7 @@ "storageRebate": "100", "content": { "dataType": "moveObject", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "hasPublicTransfer": true, "fields": { "balance": "100000000", @@ -1323,7 +1323,7 @@ ] }, { - "name": "sui_getProtocolConfig", + "name": "iota_getProtocolConfig", "tags": [ { "name": "Read API" @@ -1951,7 +1951,7 @@ ] }, { - "name": "sui_getTotalTransactionBlocks", + "name": "iota_getTotalTransactionBlocks", "tags": [ { "name": "Read API" @@ -1978,7 +1978,7 @@ ] }, { - "name": "sui_getTransactionBlock", + "name": "iota_getTransactionBlock", "tags": [ { "name": "Read API" @@ -2003,7 +2003,7 @@ } ], "result": { - "name": "SuiTransactionBlockResponse", + "name": "IotaTransactionBlockResponse", "required": true, "schema": { "$ref": "#/components/schemas/TransactionBlockResponse" @@ -2153,7 +2153,7 @@ ] }, { - "name": "sui_multiGetObjects", + "name": "iota_multiGetObjects", "tags": [ { "name": "Read API" @@ -2181,12 +2181,12 @@ } ], "result": { - "name": "Vec", + "name": "Vec", "required": true, "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiObjectResponse" + "$ref": "#/components/schemas/IotaObjectResponse" } } }, @@ -2225,7 +2225,7 @@ "objectId": "0xb61439368cd75ebe63d633af32ffb4a022d18b95b4eaa9fd3b22b43f6b2c8e92", "version": "1", "digest": "6D2MGzZN1DnALrbg6y9nQWwuipCa6fJERLXAwNGuGtKQ", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0x090bd6d16522a6fd4fa83ec70a5f197ad656da104dde1de9880be827a1a753e5" }, @@ -2233,7 +2233,7 @@ "storageRebate": "100", "content": { "dataType": "moveObject", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "hasPublicTransfer": true, "fields": { "balance": "100000000", @@ -2249,7 +2249,7 @@ "objectId": "0x6ea7bed8f6c3d80f2a595c2305e12dd6d07c3fbbd3ebef7dbcc7b02346cdf056", "version": "1", "digest": "HCvnds5SSF8Tn2kANyZDeAJuKa7bY6mf1ykzD8nQY42b", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0x74452cc61f316af5d5d7c02b94b02324268500a65bf5fdccb50582333b61721e" }, @@ -2257,7 +2257,7 @@ "storageRebate": "100", "content": { "dataType": "moveObject", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "hasPublicTransfer": true, "fields": { "balance": "100000000", @@ -2273,7 +2273,7 @@ "objectId": "0x75da5e934f672d3da3e003d989075efaecc79b5cd5df0df2a168259b7115a41c", "version": "1", "digest": "7AVTCGjWUFNAZYmcxtKQvAWbyzbFVn9cbr1fMvngbs9S", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0xcc0a372b6fd0026e0c63043492ce4d0c19a63e7f360c51d035a6470f09c8d237" }, @@ -2281,7 +2281,7 @@ "storageRebate": "100", "content": { "dataType": "moveObject", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "hasPublicTransfer": true, "fields": { "balance": "100000000", @@ -2297,7 +2297,7 @@ "objectId": "0x38554a9ff7b4f6b59f9426c321c8013afed093481dd4ef1267c67a8e9a0d074f", "version": "1", "digest": "DumsSGokTELtJXW54HKCRLjFKBeHkaySUZ86DDo8QwvR", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0x90fddb42cd928f74b986c6f539a734f3d7c9a75a9cb227ec315724962ee4193c" }, @@ -2305,7 +2305,7 @@ "storageRebate": "100", "content": { "dataType": "moveObject", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "hasPublicTransfer": true, "fields": { "balance": "100000000", @@ -2321,7 +2321,7 @@ "objectId": "0xe74d1b250d5df2cb5170782a8a438fbf681eded4d1e0a2cd7dfb27e784493fb1", "version": "1", "digest": "94nQ4Tz4nyqcVJmbLMUShkucx3eVfhLXGTCR4d1KP6gL", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0xdccde7893a3ac5c67cd2c4e27540b52ee828096b2aa5fe50a7effd8c23976147" }, @@ -2329,7 +2329,7 @@ "storageRebate": "100", "content": { "dataType": "moveObject", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "hasPublicTransfer": true, "fields": { "balance": "100000000", @@ -2346,7 +2346,7 @@ ] }, { - "name": "sui_multiGetTransactionBlocks", + "name": "iota_multiGetTransactionBlocks", "tags": [ { "name": "Read API" @@ -2374,7 +2374,7 @@ } ], "result": { - "name": "Vec", + "name": "Vec", "required": true, "schema": { "type": "array", @@ -2765,7 +2765,7 @@ ] }, { - "name": "sui_tryGetPastObject", + "name": "iota_tryGetPastObject", "tags": [ { "name": "Read API" @@ -2798,7 +2798,7 @@ } ], "result": { - "name": "SuiPastObjectResponse", + "name": "IotaPastObjectResponse", "required": true, "schema": { "$ref": "#/components/schemas/ObjectRead" @@ -2837,7 +2837,7 @@ "objectId": "0x11af4b844ff94b3fbef6e36b518da3ad4c5856fa686464524a876b463d129760", "version": "4", "digest": "5VPAwDXy3BL72ehFc7gSJoz27ahMd6spUg5YwYc4ibcv", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0x3568c40e814d9d5396d23087a0fd641e91e0e00df6c012cded9ef9ba5e5bf042" }, @@ -2845,7 +2845,7 @@ "storageRebate": "100", "content": { "dataType": "moveObject", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "hasPublicTransfer": true, "fields": { "balance": "10000", @@ -2861,7 +2861,7 @@ ] }, { - "name": "sui_tryMultiGetPastObjects", + "name": "iota_tryMultiGetPastObjects", "tags": [ { "name": "Read API" @@ -2889,7 +2889,7 @@ } ], "result": { - "name": "Vec", + "name": "Vec", "required": true, "schema": { "type": "array", @@ -2937,7 +2937,7 @@ "objectId": "0x5056aa3325512c8af40b9f5fd7065c83ded900657eac70a7979c2541646fa449", "version": "4", "digest": "F34PCnEHm5GAP5ksDKPSdRMKz49JiqrvLUTZsiojqJS2", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0xfde53941b2a08a8bf752c20979842732ac019f52835282744318d6d84f3c52b3" }, @@ -2945,7 +2945,7 @@ "storageRebate": "100", "content": { "dataType": "moveObject", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "hasPublicTransfer": true, "fields": { "balance": "10000", @@ -2962,7 +2962,7 @@ "objectId": "0xe81109dc075f537067726d63dd5287100e177404a969989215da2abfbfc098cf", "version": "12", "digest": "FvrqyqH5yA85sziA2NoPGJ8N23kmTxeXQh4HyJAbB7c2", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0x13090a95287cde98d711fc27217b81e08d494bdb70c3b42f0fe27be8eb500568" }, @@ -2970,7 +2970,7 @@ "storageRebate": "100", "content": { "dataType": "moveObject", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "hasPublicTransfer": true, "fields": { "balance": "20000", @@ -2987,7 +2987,7 @@ ] }, { - "name": "suix_getAllBalances", + "name": "iotax_getAllBalances", "tags": [ { "name": "Coin Query API" @@ -2997,10 +2997,10 @@ "params": [ { "name": "owner", - "description": "the owner's Sui address", + "description": "the owner's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } } ], @@ -3027,7 +3027,7 @@ "name": "Result", "value": [ { - "coinType": "0x2::sui::SUI", + "coinType": "0x2::iota::IOTA", "coinObjectCount": 15, "totalBalance": "3000000000", "lockedBalance": {} @@ -3038,7 +3038,7 @@ ] }, { - "name": "suix_getAllCoins", + "name": "iotax_getAllCoins", "tags": [ { "name": "Coin Query API" @@ -3048,10 +3048,10 @@ "params": [ { "name": "owner", - "description": "the owner's Sui address", + "description": "the owner's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { @@ -3100,7 +3100,7 @@ "value": { "data": [ { - "coinType": "0x2::sui::SUI", + "coinType": "0x2::iota::IOTA", "coinObjectId": "0x91825debff541cf4e08b5c5f7296ff9840e6f0b185af93984cde8cf3870302c0", "version": "103626", "digest": "7dp5WtTmtGp83EXYYFMzjBJRFeSgR67AzqMETLrfgeFx", @@ -3108,7 +3108,7 @@ "previousTransaction": "9WfFUVhjbbh4tWkyUse1QxzbKX952cyXScH7xJNPB2vQ" }, { - "coinType": "0x2::sui::SUI", + "coinType": "0x2::iota::IOTA", "coinObjectId": "0x48a53f22e2e901ea2a5bf44fdd5bb94a1d83b6efc4dd779f0890ca3b1f6ba997", "version": "103626", "digest": "9xLdMXezY8d1yRA2TtN6pYjapyy2EVKHWNriGPFGCFvd", @@ -3116,7 +3116,7 @@ "previousTransaction": "Byq9SyV7x6fvzaf88YRA9JM8vLbVLJAqUX8pESDmKcgw" }, { - "coinType": "0x2::sui::SUI", + "coinType": "0x2::iota::IOTA", "coinObjectId": "0x6867fcc63161269c5c0c73b02229486bbaff319209dfb8299ced3b8609037997", "version": "103626", "digest": "5xexWFq6QpGHBQyC9P2cbAJXq9qm2EjzfuRM9NwS1uyG", @@ -3132,7 +3132,7 @@ ] }, { - "name": "suix_getBalance", + "name": "iotax_getBalance", "tags": [ { "name": "Coin Query API" @@ -3142,15 +3142,15 @@ "params": [ { "name": "owner", - "description": "the owner's Sui address", + "description": "the owner's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { "name": "coin_type", - "description": "optional type names for the coin (e.g., 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC), default to 0x2::sui::SUI if not specified.", + "description": "optional type names for the coin (e.g., 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC), default to 0x2::iota::IOTA if not specified.", "schema": { "type": "string" } @@ -3189,7 +3189,7 @@ ] }, { - "name": "suix_getCoinMetadata", + "name": "iotax_getCoinMetadata", "tags": [ { "name": "Coin Query API" @@ -3207,9 +3207,9 @@ } ], "result": { - "name": "SuiCoinMetadata", + "name": "IotaCoinMetadata", "schema": { - "$ref": "#/components/schemas/SuiCoinMetadata" + "$ref": "#/components/schemas/IotaCoinMetadata" } }, "examples": [ @@ -3236,7 +3236,7 @@ ] }, { - "name": "suix_getCoins", + "name": "iotax_getCoins", "tags": [ { "name": "Coin Query API" @@ -3246,15 +3246,15 @@ "params": [ { "name": "owner", - "description": "the owner's Sui address", + "description": "the owner's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { "name": "coin_type", - "description": "optional type name for the coin (e.g., 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC), default to 0x2::sui::SUI if not specified.", + "description": "optional type name for the coin (e.g., 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC), default to 0x2::iota::IOTA if not specified.", "schema": { "type": "string" } @@ -3285,7 +3285,7 @@ }, "examples": [ { - "name": "Gets all SUI coins owned by the address provided. Return a paginated list of `limit` results per page. Similar to `suix_getAllCoins`, but provides a way to filter by coin type.", + "name": "Gets all IOTA coins owned by the address provided. Return a paginated list of `limit` results per page. Similar to `iotax_getAllCoins`, but provides a way to filter by coin type.", "params": [ { "name": "owner", @@ -3293,7 +3293,7 @@ }, { "name": "coin_type", - "value": "0x2::sui::SUI" + "value": "0x2::iota::IOTA" }, { "name": "cursor", @@ -3309,7 +3309,7 @@ "value": { "data": [ { - "coinType": "0x2::sui::SUI", + "coinType": "0x2::iota::IOTA", "coinObjectId": "0xa5a8e30db5a798a7354340b6ea78a66f50921841ab5359ec7a3dc01f282420ae", "version": "103626", "digest": "tw5DzJTfdxTn4f3rekFrhN7dQTUezBgsEhycDobTBLb", @@ -3317,7 +3317,7 @@ "previousTransaction": "HSein75AFXgdsnbABWLQ5mvjFmPFWrBFi9CMVsNn7gJr" }, { - "coinType": "0x2::sui::SUI", + "coinType": "0x2::iota::IOTA", "coinObjectId": "0x47dfa99496428c65b2054ad7db1872b87ff05b1047bb5e3adf5257cceb08ecb4", "version": "103626", "digest": "AfgFe7ZfjJ5dWV6VAy2LbtvBFhcABkvdvwEjLrRcFqtr", @@ -3325,7 +3325,7 @@ "previousTransaction": "5WHnm9jUZEtDvSvsj7HBrP5BoxA3UY6R57qqumXJXboV" }, { - "coinType": "0x2::sui::SUI", + "coinType": "0x2::iota::IOTA", "coinObjectId": "0xd4f062dbcfc3bf73f5861945592222ff7b090ac21c8a3cf840abdc5b743da778", "version": "103626", "digest": "9er6jxigfuQEKsn9gtPV2oW1zGQRcFtKNijHVe88GUJD", @@ -3341,7 +3341,7 @@ ] }, { - "name": "suix_getCommitteeInfo", + "name": "iotax_getCommitteeInfo", "tags": [ { "name": "Governance Read API" @@ -3358,7 +3358,7 @@ } ], "result": { - "name": "SuiCommittee", + "name": "IotaCommittee", "required": true, "schema": { "$ref": "#/components/schemas/CommitteeInfo" @@ -3401,7 +3401,7 @@ ] }, { - "name": "suix_getDynamicFieldObject", + "name": "iotax_getDynamicFieldObject", "tags": [ { "name": "Extended API" @@ -3427,10 +3427,10 @@ } ], "result": { - "name": "SuiObjectResponse", + "name": "IotaObjectResponse", "required": true, "schema": { - "$ref": "#/components/schemas/SuiObjectResponse" + "$ref": "#/components/schemas/IotaObjectResponse" } }, "examples": [ @@ -3475,7 +3475,7 @@ ] }, { - "name": "suix_getDynamicFields", + "name": "iotax_getDynamicFields", "tags": [ { "name": "Extended API" @@ -3581,19 +3581,19 @@ ] }, { - "name": "suix_getLatestSuiSystemState", + "name": "iotax_getLatestIotaSystemState", "tags": [ { "name": "Governance Read API" } ], - "description": "Return the latest SUI system state object on-chain.", + "description": "Return the latest IOTA system state object on-chain.", "params": [], "result": { - "name": "SuiSystemStateSummary", + "name": "IotaSystemStateSummary", "required": true, "schema": { - "$ref": "#/components/schemas/SuiSystemStateSummary" + "$ref": "#/components/schemas/IotaSystemStateSummary" } }, "examples": [ @@ -3608,20 +3608,20 @@ ] }, { - "name": "suix_getOwnedObjects", + "name": "iotax_getOwnedObjects", "tags": [ { "name": "Extended API" } ], - "description": "Return the list of objects owned by an address. Note that if the address owns more than `QUERY_MAX_RESULT_LIMIT` objects, the pagination is not accurate, because previous page may have been updated when the next page is fetched. Please use suix_queryObjects if this is a concern.", + "description": "Return the list of objects owned by an address. Note that if the address owns more than `QUERY_MAX_RESULT_LIMIT` objects, the pagination is not accurate, because previous page may have been updated when the next page is fetched. Please use iotax_queryObjects if this is a concern.", "params": [ { "name": "address", - "description": "the owner's Sui address", + "description": "the owner's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { @@ -3652,7 +3652,7 @@ "name": "ObjectsPage", "required": true, "schema": { - "$ref": "#/components/schemas/Page_for_SuiObjectResponse_and_ObjectID" + "$ref": "#/components/schemas/Page_for_IotaObjectResponse_and_ObjectID" } }, "examples": [ @@ -3669,7 +3669,7 @@ "filter": { "MatchAll": [ { - "StructType": "0x2::coin::Coin<0x2::sui::SUI>" + "StructType": "0x2::coin::Coin<0x2::iota::IOTA>" }, { "AddressOwner": "0xa69bb635dcee0f33643b4729ae81730d55e5e26860fac6839ce2d7ed7e6f29d2" @@ -3708,7 +3708,7 @@ "objectId": "0x3d6255ff8223c12b0fd985c49d5777a0d65ad3d707164b2a378eee639ebc2690", "version": "13488", "digest": "A6v9pFTLH3PkDSvEGgVjW1JhL7CtcUQKwGmgXK8SQNsc", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0xa69bb635dcee0f33643b4729ae81730d55e5e26860fac6839ce2d7ed7e6f29d2" }, @@ -3721,7 +3721,7 @@ "objectId": "0x1a6e30f43933bbf40f5f5b6ce1f44957337dcb28f32e0355326f8c7d932bd54d", "version": "13488", "digest": "Fn1HG7LyUcLDps6bhYQkPWXpeUXgisznxRJ2qvn7Q1JN", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0xa69bb635dcee0f33643b4729ae81730d55e5e26860fac6839ce2d7ed7e6f29d2" }, @@ -3734,7 +3734,7 @@ "objectId": "0x28628a24386298faa98850887f64da841b87279efd098d59a66a3d9adc87cce8", "version": "13488", "digest": "39aXGAwHaY3CiqWwLiBZ7JRaGSvnpvPbHxMSJAwAUY5i", - "type": "0x2::coin::Coin<0x2::sui::SUI>", + "type": "0x2::coin::Coin<0x2::iota::IOTA>", "owner": { "AddressOwner": "0xa69bb635dcee0f33643b4729ae81730d55e5e26860fac6839ce2d7ed7e6f29d2" }, @@ -3751,7 +3751,7 @@ ] }, { - "name": "suix_getReferenceGasPrice", + "name": "iotax_getReferenceGasPrice", "tags": [ { "name": "Governance Read API" @@ -3778,7 +3778,7 @@ ] }, { - "name": "suix_getStakes", + "name": "iotax_getStakes", "tags": [ { "name": "Governance Read API" @@ -3790,7 +3790,7 @@ "name": "owner", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } } ], @@ -3821,7 +3821,7 @@ "stakingPool": "0xab588374445e72e0402aea014b295610579963ee67e81398729f87d81d62f399", "stakes": [ { - "stakedSuiId": "0xc041b0f8d0938923ea7e3917608ee62df4376710024f81dd33ab6833482ee803", + "stakedIotaId": "0xc041b0f8d0938923ea7e3917608ee62df4376710024f81dd33ab6833482ee803", "stakeRequestEpoch": "62", "stakeActiveEpoch": "63", "principal": "200000000000", @@ -3829,7 +3829,7 @@ "estimatedReward": "520000000" }, { - "stakedSuiId": "0x4e779a48e6ef635c7f856df4905022458bfbd22bbb46f892c42d9ec0ae4de93e", + "stakedIotaId": "0x4e779a48e6ef635c7f856df4905022458bfbd22bbb46f892c42d9ec0ae4de93e", "stakeRequestEpoch": "142", "stakeActiveEpoch": "143", "principal": "200000000000", @@ -3842,7 +3842,7 @@ "stakingPool": "0x2ddec4fb83621d55952d9172fcfcb72feae238b3186a7bb26a1ab2c982a0a9b4", "stakes": [ { - "stakedSuiId": "0x82aa70f5a010fffc60f20194ef0f597474e8ceaf9ee4582d3a233101e322a22c", + "stakedIotaId": "0x82aa70f5a010fffc60f20194ef0f597474e8ceaf9ee4582d3a233101e322a22c", "stakeRequestEpoch": "244", "stakeActiveEpoch": "245", "principal": "200000000000", @@ -3856,7 +3856,7 @@ ] }, { - "name": "suix_getStakesByIds", + "name": "iotax_getStakesByIds", "tags": [ { "name": "Governance Read API" @@ -3865,7 +3865,7 @@ "description": "Return one or more [DelegatedStake]. If a Stake was withdrawn its status will be Unstaked.", "params": [ { - "name": "staked_sui_ids", + "name": "staked_iota_ids", "required": true, "schema": { "type": "array", @@ -3890,7 +3890,7 @@ "name": "Returns the staking information for the address the request provides.", "params": [ { - "name": "staked_sui_ids", + "name": "staked_iota_ids", "value": [ "0xb2a5bea2e681ea5af4e59bd1abb0bb4fcb2747866ff92885a3c21a7703f56472", "0x1c198308aa0c71b771ada6b96c16fc9c0fa754b3c61936f77fcfdaa213c2f7b4" @@ -3904,7 +3904,7 @@ "stakingPool": "0x03d47b901cb7b3177a791cd29bb5304037fea6ced287081357950315a8842c38", "stakes": [ { - "stakedSuiId": "0xb2a5bea2e681ea5af4e59bd1abb0bb4fcb2747866ff92885a3c21a7703f56472", + "stakedIotaId": "0xb2a5bea2e681ea5af4e59bd1abb0bb4fcb2747866ff92885a3c21a7703f56472", "stakeRequestEpoch": "62", "stakeActiveEpoch": "63", "principal": "200000000000", @@ -3912,7 +3912,7 @@ "estimatedReward": "520000000" }, { - "stakedSuiId": "0x1c198308aa0c71b771ada6b96c16fc9c0fa754b3c61936f77fcfdaa213c2f7b4", + "stakedIotaId": "0x1c198308aa0c71b771ada6b96c16fc9c0fa754b3c61936f77fcfdaa213c2f7b4", "stakeRequestEpoch": "244", "stakeActiveEpoch": "245", "principal": "200000000000", @@ -3925,7 +3925,7 @@ ] }, { - "name": "suix_getTotalSupply", + "name": "iotax_getTotalSupply", "tags": [ { "name": "Coin Query API" @@ -3968,7 +3968,7 @@ ] }, { - "name": "suix_getValidatorsApy", + "name": "iotax_getValidatorsApy", "tags": [ { "name": "Governance Read API" @@ -4011,7 +4011,7 @@ ] }, { - "name": "suix_queryEvents", + "name": "iotax_queryEvents", "tags": [ { "name": "Extended API" @@ -4021,7 +4021,7 @@ "params": [ { "name": "query", - "description": "The event query criteria. See [Event filter](https://docs.sui.io/build/event_api#event-filters) documentation for examples.", + "description": "The event query criteria. See [Event filter](https://docs.iota.io/build/event_api#event-filters) documentation for examples.", "required": true, "schema": { "$ref": "#/components/schemas/EventFilter" @@ -4151,7 +4151,7 @@ ] }, { - "name": "suix_queryTransactionBlocks", + "name": "iotax_queryTransactionBlocks", "tags": [ { "name": "Extended API" @@ -4249,7 +4249,7 @@ ] }, { - "name": "suix_resolveNameServiceAddress", + "name": "iotax_resolveNameServiceAddress", "tags": [ { "name": "Extended API" @@ -4267,9 +4267,9 @@ } ], "result": { - "name": "SuiAddress", + "name": "IotaAddress", "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, "examples": [ @@ -4278,7 +4278,7 @@ "params": [ { "name": "name", - "value": "example.sui" + "value": "example.iota" } ], "result": { @@ -4289,7 +4289,7 @@ ] }, { - "name": "suix_resolveNameServiceNames", + "name": "iotax_resolveNameServiceNames", "tags": [ { "name": "Extended API" @@ -4302,7 +4302,7 @@ "description": "The address to resolve", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { @@ -4329,7 +4329,7 @@ }, "examples": [ { - "name": "Returns the SuiNS name for the address the request provides. Currently, the API returns only the first name in cases where there are multiple. Future support will use the cursor ID and limit values in the request to control pagination of the response for addresses with multiple names.", + "name": "Returns the IotaNS name for the address the request provides. Currently, the API returns only the first name in cases where there are multiple. Future support will use the cursor ID and limit values in the request to control pagination of the response for addresses with multiple names.", "params": [ { "name": "address", @@ -4348,7 +4348,7 @@ "name": "Result", "value": { "data": [ - "example.sui" + "example.iota" ], "nextCursor": "0x7d0cd09d3cc1679290f1df2803b32b76ba0395dbb635e3fb7390f04e6567f739", "hasNextPage": false @@ -4358,7 +4358,7 @@ ] }, { - "name": "suix_subscribeEvent", + "name": "iotax_subscribeEvent", "tags": [ { "name": "Extended API" @@ -4370,11 +4370,11 @@ "name": "PubSub" } ], - "description": "Subscribe to a stream of Sui event", + "description": "Subscribe to a stream of Iota event", "params": [ { "name": "filter", - "description": "The filter criteria of the event stream. See [Event filter](https://docs.sui.io/build/event_api#event-filters) documentation for examples.", + "description": "The filter criteria of the event stream. See [Event filter](https://docs.iota.io/build/event_api#event-filters) documentation for examples.", "required": true, "schema": { "$ref": "#/components/schemas/EventFilter" @@ -4382,7 +4382,7 @@ } ], "result": { - "name": "SuiEvent", + "name": "IotaEvent", "required": true, "schema": { "$ref": "#/components/schemas/Event" @@ -4390,7 +4390,7 @@ } }, { - "name": "suix_subscribeTransaction", + "name": "iotax_subscribeTransaction", "tags": [ { "name": "Extended API" @@ -4402,7 +4402,7 @@ "name": "PubSub" } ], - "description": "Subscribe to a stream of Sui transaction effects", + "description": "Subscribe to a stream of Iota transaction effects", "params": [ { "name": "filter", @@ -4413,7 +4413,7 @@ } ], "result": { - "name": "SuiTransactionBlockEffects", + "name": "IotaTransactionBlockEffects", "required": true, "schema": { "$ref": "#/components/schemas/TransactionBlockEffects" @@ -4431,10 +4431,10 @@ "params": [ { "name": "signer", - "description": "the transaction signer's Sui address", + "description": "the transaction signer's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { @@ -4467,7 +4467,7 @@ "name": "txn_builder_mode", "description": "Whether this is a regular transaction or a Dev Inspect Transaction", "schema": { - "$ref": "#/components/schemas/SuiTransactionBlockBuilderMode" + "$ref": "#/components/schemas/IotaTransactionBlockBuilderMode" } } ], @@ -4490,10 +4490,10 @@ "params": [ { "name": "signer", - "description": "the transaction signer's Sui address", + "description": "the transaction signer's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { @@ -4547,10 +4547,10 @@ "params": [ { "name": "signer", - "description": "the transaction signer's Sui address", + "description": "the transaction signer's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { @@ -4590,12 +4590,12 @@ }, { "name": "arguments", - "description": "the arguments to be passed into the Move function, in [SuiJson](https://docs.sui.io/build/sui-json) format", + "description": "the arguments to be passed into the Move function, in [IotaJson](https://docs.iota.io/build/iota-json) format", "required": true, "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiJsonValue" + "$ref": "#/components/schemas/IotaJsonValue" } } }, @@ -4616,9 +4616,9 @@ }, { "name": "execution_mode", - "description": "Whether this is a Normal transaction or a Dev Inspect Transaction. Default to be `SuiTransactionBlockBuilderMode::Commit` when it's None.", + "description": "Whether this is a Normal transaction or a Dev Inspect Transaction. Default to be `IotaTransactionBlockBuilderMode::Commit` when it's None.", "schema": { - "$ref": "#/components/schemas/SuiTransactionBlockBuilderMode" + "$ref": "#/components/schemas/IotaTransactionBlockBuilderMode" } } ], @@ -4641,15 +4641,15 @@ "params": [ { "name": "signer", - "description": "the transaction signer's Sui address", + "description": "the transaction signer's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { "name": "input_coins", - "description": "the Sui coins to be used in this transaction", + "description": "the Iota coins to be used in this transaction", "required": true, "schema": { "type": "array", @@ -4665,7 +4665,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } } }, @@ -4705,25 +4705,25 @@ } }, { - "name": "unsafe_payAllSui", + "name": "unsafe_payAllIota", "tags": [ { "name": "Transaction Builder API" } ], - "description": "Send all SUI coins to one recipient. This is for SUI coin only and does not require a separate gas coin object. Specifically, what pay_all_sui does are: 1. accumulate all SUI from input coins and deposit all SUI to the first input coin 2. transfer the updated first coin to the recipient and also use this first coin as gas coin object. 3. the balance of the first input coin after tx is sum(input_coins) - actual_gas_cost. 4. all other input coins other than the first are deleted.", + "description": "Send all IOTA coins to one recipient. This is for IOTA coin only and does not require a separate gas coin object. Specifically, what pay_all_iota does are: 1. accumulate all IOTA from input coins and deposit all IOTA to the first input coin 2. transfer the updated first coin to the recipient and also use this first coin as gas coin object. 3. the balance of the first input coin after tx is sum(input_coins) - actual_gas_cost. 4. all other input coins other than the first are deleted.", "params": [ { "name": "signer", - "description": "the transaction signer's Sui address", + "description": "the transaction signer's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { "name": "input_coins", - "description": "the Sui coins to be used in this transaction, including the coin for gas payment.", + "description": "the Iota coins to be used in this transaction, including the coin for gas payment.", "required": true, "schema": { "type": "array", @@ -4737,7 +4737,7 @@ "description": "the recipient address,", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { @@ -4758,25 +4758,25 @@ } }, { - "name": "unsafe_paySui", + "name": "unsafe_payIota", "tags": [ { "name": "Transaction Builder API" } ], - "description": "Send SUI coins to a list of addresses, following a list of amounts. This is for SUI coin only and does not require a separate gas coin object. Specifically, what pay_sui does are: 1. debit each input_coin to create new coin following the order of amounts and assign it to the corresponding recipient. 2. accumulate all residual SUI from input coins left and deposit all SUI to the first input coin, then use the first input coin as the gas coin object. 3. the balance of the first input coin after tx is sum(input_coins) - sum(amounts) - actual_gas_cost 4. all other input coints other than the first one are deleted.", + "description": "Send IOTA coins to a list of addresses, following a list of amounts. This is for IOTA coin only and does not require a separate gas coin object. Specifically, what pay_iota does are: 1. debit each input_coin to create new coin following the order of amounts and assign it to the corresponding recipient. 2. accumulate all residual IOTA from input coins left and deposit all IOTA to the first input coin, then use the first input coin as the gas coin object. 3. the balance of the first input coin after tx is sum(input_coins) - sum(amounts) - actual_gas_cost 4. all other input coints other than the first one are deleted.", "params": [ { "name": "signer", - "description": "the transaction signer's Sui address", + "description": "the transaction signer's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { "name": "input_coins", - "description": "the Sui coins to be used in this transaction, including the coin for gas payment.", + "description": "the Iota coins to be used in this transaction, including the coin for gas payment.", "required": true, "schema": { "type": "array", @@ -4792,7 +4792,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } } }, @@ -4835,10 +4835,10 @@ "params": [ { "name": "sender", - "description": "the transaction signer's Sui address", + "description": "the transaction signer's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { @@ -4898,15 +4898,15 @@ "params": [ { "name": "signer", - "description": "the transaction signer's Sui address", + "description": "the transaction signer's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { "name": "coins", - "description": "Coin object to stake", + "description": "Coin object to stake", "required": true, "schema": { "type": "array", @@ -4924,10 +4924,10 @@ }, { "name": "validator", - "description": "the validator's Sui address", + "description": "the validator's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { @@ -4965,15 +4965,15 @@ "params": [ { "name": "signer", - "description": "the transaction signer's Sui address", + "description": "the transaction signer's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { - "name": "staked_sui", - "description": "StakedSui object ID", + "name": "staked_iota", + "description": "StakedIota object ID", "required": true, "schema": { "$ref": "#/components/schemas/ObjectID" @@ -5014,10 +5014,10 @@ "params": [ { "name": "signer", - "description": "the transaction signer's Sui address", + "description": "the transaction signer's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { @@ -5074,10 +5074,10 @@ "params": [ { "name": "signer", - "description": "the transaction signer's Sui address", + "description": "the transaction signer's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { @@ -5131,10 +5131,10 @@ "params": [ { "name": "signer", - "description": "the transaction signer's Sui address", + "description": "the transaction signer's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { @@ -5162,10 +5162,10 @@ }, { "name": "recipient", - "description": "the recipient's Sui address", + "description": "the recipient's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } } ], @@ -5178,25 +5178,25 @@ } }, { - "name": "unsafe_transferSui", + "name": "unsafe_transferIota", "tags": [ { "name": "Transaction Builder API" } ], - "description": "Create an unsigned transaction to send SUI coin object to a Sui address. The SUI object is also used as the gas object.", + "description": "Create an unsigned transaction to send IOTA coin object to a Iota address. The IOTA object is also used as the gas object.", "params": [ { "name": "signer", - "description": "the transaction signer's Sui address", + "description": "the transaction signer's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { - "name": "sui_object_id", - "description": "the Sui coin object to be used in this transaction", + "name": "iota_object_id", + "description": "the Iota coin object to be used in this transaction", "required": true, "schema": { "$ref": "#/components/schemas/ObjectID" @@ -5212,10 +5212,10 @@ }, { "name": "recipient", - "description": "the recipient's Sui address", + "description": "the recipient's Iota address", "required": true, "schema": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, { @@ -5238,7 +5238,7 @@ "components": { "schemas": { "AuthorityPublicKeyBytes": { - "description": "Defines the compressed version of the public key that we pass around in Sui", + "description": "Defines the compressed version of the public key that we pass around in Iota", "allOf": [ { "$ref": "#/components/schemas/Base64" @@ -5676,7 +5676,7 @@ "description": "Validator's Address.", "allOf": [ { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } ] } @@ -5724,7 +5724,7 @@ "description": "The sponsor of the gas for the transaction, might be different from the sender.", "anyOf": [ { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" }, { "type": "null" @@ -5802,7 +5802,7 @@ "null" ], "items": { - "$ref": "#/components/schemas/SuiExecutionResult" + "$ref": "#/components/schemas/IotaExecutionResult" } } } @@ -5949,7 +5949,7 @@ } } }, - "Ed25519SuiSignature": { + "Ed25519IotaSignature": { "$ref": "#/components/schemas/Base64" }, "EndOfEpochData": { @@ -6034,10 +6034,10 @@ "description": "Parsed json value of the event" }, "sender": { - "description": "Sender's Sui address.", + "description": "Sender's Iota address.", "allOf": [ { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } ] }, @@ -6072,7 +6072,7 @@ ], "properties": { "Sender": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, "additionalProperties": false @@ -6312,7 +6312,7 @@ ] }, "EventID": { - "description": "Unique ID of a Sui Event, the ID is a combination of tx seq number and event seq number, the ID is local to this particular fullnode and will be different from other fullnode.", + "description": "Unique ID of a Iota Event, the ID is a combination of tx seq number and event seq number, the ID is local to this particular fullnode and will be different from other fullnode.", "type": "object", "required": [ "eventSeq", @@ -6427,7 +6427,7 @@ "$ref": "#/components/schemas/BigInt_for_uint64" }, "owner": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" }, "payment": { "type": "array", @@ -6619,7 +6619,7 @@ "arguments": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiJsonValue" + "$ref": "#/components/schemas/IotaJsonValue" } }, "function": { @@ -6707,7 +6707,7 @@ "type": "boolean" }, { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" }, { "type": "array", @@ -6943,7 +6943,7 @@ "$ref": "#/components/schemas/Owner" }, "sender": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" }, "type": { "type": "string", @@ -6986,7 +6986,7 @@ "$ref": "#/components/schemas/SequenceNumber" }, "sender": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" }, "type": { "type": "string", @@ -7017,7 +7017,7 @@ "type": "string" }, "sender": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" }, "type": { "type": "string", @@ -7048,7 +7048,7 @@ "type": "string" }, "sender": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" }, "type": { "type": "string", @@ -7087,7 +7087,7 @@ "$ref": "#/components/schemas/Owner" }, "sender": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" }, "type": { "type": "string", @@ -7111,7 +7111,7 @@ ], "properties": { "bcs": { - "description": "Move object content or package content in BCS, default to be None unless SuiObjectDataOptions.showBcs is set to true", + "description": "Move object content or package content in BCS, default to be None unless IotaObjectDataOptions.showBcs is set to true", "anyOf": [ { "$ref": "#/components/schemas/RawData" @@ -7122,7 +7122,7 @@ ] }, "content": { - "description": "Move object content or package content, default to be None unless SuiObjectDataOptions.showContent is set to true", + "description": "Move object content or package content, default to be None unless IotaObjectDataOptions.showContent is set to true", "anyOf": [ { "$ref": "#/components/schemas/Data" @@ -7141,7 +7141,7 @@ ] }, "display": { - "description": "The Display metadata for frontend UI rendering, default to be None unless SuiObjectDataOptions.showContent is set to true This can also be None if the struct type does not have Display defined See more details in ", + "description": "The Display metadata for frontend UI rendering, default to be None unless IotaObjectDataOptions.showContent is set to true This can also be None if the struct type does not have Display defined See more details in ", "anyOf": [ { "$ref": "#/components/schemas/DisplayFieldsResponse" @@ -7155,7 +7155,7 @@ "$ref": "#/components/schemas/ObjectID" }, "owner": { - "description": "The owner of this object. Default to be None unless SuiObjectDataOptions.showOwner is set to true", + "description": "The owner of this object. Default to be None unless IotaObjectDataOptions.showOwner is set to true", "anyOf": [ { "$ref": "#/components/schemas/Owner" @@ -7166,7 +7166,7 @@ ] }, "previousTransaction": { - "description": "The digest of the transaction that created or last mutated this object. Default to be None unless SuiObjectDataOptions.showPreviousTransaction is set to true", + "description": "The digest of the transaction that created or last mutated this object. Default to be None unless IotaObjectDataOptions.showPreviousTransaction is set to true", "anyOf": [ { "$ref": "#/components/schemas/TransactionDigest" @@ -7177,7 +7177,7 @@ ] }, "storageRebate": { - "description": "The amount of SUI we would rebate if this object gets deleted. This number is re-calculated each time the object is mutated based on the present storage gas price.", + "description": "The amount of IOTA we would rebate if this object gets deleted. This number is re-calculated each time the object is mutated based on the present storage gas price.", "anyOf": [ { "$ref": "#/components/schemas/BigInt_for_uint64" @@ -7188,7 +7188,7 @@ ] }, "type": { - "description": "The type of the object. Default to be None unless SuiObjectDataOptions.showType is set to true", + "description": "The type of the object. Default to be None unless IotaObjectDataOptions.showType is set to true", "type": [ "string", "null" @@ -7525,7 +7525,7 @@ "default": null, "anyOf": [ { - "$ref": "#/components/schemas/SuiObjectDataFilter" + "$ref": "#/components/schemas/IotaObjectDataFilter" }, { "type": "null" @@ -7579,20 +7579,20 @@ ], "properties": { "AddressOwner": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, "additionalProperties": false }, { - "description": "Object is exclusively owned by a single object, and is mutable. The object ID is converted to SuiAddress as SuiAddress is universal.", + "description": "Object is exclusively owned by a single object, and is mutable. The object ID is converted to IotaAddress as IotaAddress is universal.", "type": "object", "required": [ "ObjectOwner" ], "properties": { "ObjectOwner": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, "additionalProperties": false @@ -7777,7 +7777,7 @@ } } }, - "Page_for_SuiObjectResponse_and_ObjectID": { + "Page_for_IotaObjectResponse_and_ObjectID": { "description": "`next_cursor` points to the last item in the page; Reading with `next_cursor` will start from the next item after `next_cursor` if `next_cursor` is `Some`, otherwise it will start from the first item.", "type": "object", "required": [ @@ -7788,7 +7788,7 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiObjectResponse" + "$ref": "#/components/schemas/IotaObjectResponse" } }, "hasNextPage": { @@ -8087,10 +8087,10 @@ } ] }, - "Secp256k1SuiSignature": { + "Secp256k1IotaSignature": { "$ref": "#/components/schemas/Base64" }, - "Secp256r1SuiSignature": { + "Secp256r1IotaSignature": { "$ref": "#/components/schemas/Base64" }, "SequenceNumber": { @@ -8103,11 +8103,11 @@ { "type": "object", "required": [ - "Ed25519SuiSignature" + "Ed25519IotaSignature" ], "properties": { - "Ed25519SuiSignature": { - "$ref": "#/components/schemas/Ed25519SuiSignature" + "Ed25519IotaSignature": { + "$ref": "#/components/schemas/Ed25519IotaSignature" } }, "additionalProperties": false @@ -8115,11 +8115,11 @@ { "type": "object", "required": [ - "Secp256k1SuiSignature" + "Secp256k1IotaSignature" ], "properties": { - "Secp256k1SuiSignature": { - "$ref": "#/components/schemas/Secp256k1SuiSignature" + "Secp256k1IotaSignature": { + "$ref": "#/components/schemas/Secp256k1IotaSignature" } }, "additionalProperties": false @@ -8127,11 +8127,11 @@ { "type": "object", "required": [ - "Secp256r1SuiSignature" + "Secp256r1IotaSignature" ], "properties": { - "Secp256r1SuiSignature": { - "$ref": "#/components/schemas/Secp256r1SuiSignature" + "Secp256r1IotaSignature": { + "$ref": "#/components/schemas/Secp256r1IotaSignature" } }, "additionalProperties": false @@ -8192,7 +8192,7 @@ "principal", "stakeActiveEpoch", "stakeRequestEpoch", - "stakedSuiId" + "stakedIotaId" ], "properties": { "principal": { @@ -8204,8 +8204,8 @@ "stakeRequestEpoch": { "$ref": "#/components/schemas/BigInt_for_uint64" }, - "stakedSuiId": { - "description": "ID of the StakedSui receipt object.", + "stakedIotaId": { + "description": "ID of the StakedIota receipt object.", "allOf": [ { "$ref": "#/components/schemas/ObjectID" @@ -8214,7 +8214,7 @@ } } }, - "SuiActiveJwk": { + "IotaActiveJwk": { "type": "object", "required": [ "epoch", @@ -8226,17 +8226,17 @@ "$ref": "#/components/schemas/BigInt_for_uint64" }, "jwk": { - "$ref": "#/components/schemas/SuiJWK" + "$ref": "#/components/schemas/IotaJWK" }, "jwk_id": { - "$ref": "#/components/schemas/SuiJwkId" + "$ref": "#/components/schemas/IotaJwkId" } } }, - "SuiAddress": { + "IotaAddress": { "$ref": "#/components/schemas/Hex" }, - "SuiArgument": { + "IotaArgument": { "description": "An argument to a transaction in a programmable transaction block", "oneOf": [ { @@ -8305,7 +8305,7 @@ } ] }, - "SuiAuthenticatorStateExpire": { + "IotaAuthenticatorStateExpire": { "type": "object", "required": [ "min_epoch" @@ -8316,7 +8316,7 @@ } } }, - "SuiCallArg": { + "IotaCallArg": { "oneOf": [ { "type": "object", @@ -8426,7 +8426,7 @@ ] }, "value": { - "$ref": "#/components/schemas/SuiJsonValue" + "$ref": "#/components/schemas/IotaJsonValue" }, "valueType": { "default": null, @@ -8439,7 +8439,7 @@ } ] }, - "SuiChangeEpoch": { + "IotaChangeEpoch": { "type": "object", "required": [ "computation_charge", @@ -8466,7 +8466,7 @@ } } }, - "SuiCoinMetadata": { + "IotaCoinMetadata": { "type": "object", "required": [ "decimals", @@ -8513,7 +8513,7 @@ } } }, - "SuiEndOfEpochTransactionKind": { + "IotaEndOfEpochTransactionKind": { "oneOf": [ { "type": "string", @@ -8530,7 +8530,7 @@ ], "properties": { "ChangeEpoch": { - "$ref": "#/components/schemas/SuiChangeEpoch" + "$ref": "#/components/schemas/IotaChangeEpoch" } }, "additionalProperties": false @@ -8542,14 +8542,14 @@ ], "properties": { "AuthenticatorStateExpire": { - "$ref": "#/components/schemas/SuiAuthenticatorStateExpire" + "$ref": "#/components/schemas/IotaAuthenticatorStateExpire" } }, "additionalProperties": false } ] }, - "SuiExecutionResult": { + "IotaExecutionResult": { "type": "object", "properties": { "mutableReferenceOutputs": { @@ -8559,7 +8559,7 @@ "type": "array", "items": [ { - "$ref": "#/components/schemas/SuiArgument" + "$ref": "#/components/schemas/IotaArgument" }, { "type": "array", @@ -8601,7 +8601,7 @@ } } }, - "SuiJWK": { + "IotaJWK": { "type": "object", "required": [ "alg", @@ -8624,8 +8624,8 @@ } } }, - "SuiJsonValue": {}, - "SuiJwkId": { + "IotaJsonValue": {}, + "IotaJwkId": { "type": "object", "required": [ "iss", @@ -8640,7 +8640,7 @@ } } }, - "SuiMoveAbility": { + "IotaMoveAbility": { "type": "string", "enum": [ "Copy", @@ -8649,7 +8649,7 @@ "Key" ] }, - "SuiMoveAbilitySet": { + "IotaMoveAbilitySet": { "type": "object", "required": [ "abilities" @@ -8658,12 +8658,12 @@ "abilities": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiMoveAbility" + "$ref": "#/components/schemas/IotaMoveAbility" } } } }, - "SuiMoveModuleId": { + "IotaMoveModuleId": { "type": "object", "required": [ "address", @@ -8678,7 +8678,7 @@ } } }, - "SuiMoveNormalizedField": { + "IotaMoveNormalizedField": { "type": "object", "required": [ "name", @@ -8689,11 +8689,11 @@ "type": "string" }, "type": { - "$ref": "#/components/schemas/SuiMoveNormalizedType" + "$ref": "#/components/schemas/IotaMoveNormalizedType" } } }, - "SuiMoveNormalizedFunction": { + "IotaMoveNormalizedFunction": { "type": "object", "required": [ "isEntry", @@ -8709,27 +8709,27 @@ "parameters": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiMoveNormalizedType" + "$ref": "#/components/schemas/IotaMoveNormalizedType" } }, "return": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiMoveNormalizedType" + "$ref": "#/components/schemas/IotaMoveNormalizedType" } }, "typeParameters": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiMoveAbilitySet" + "$ref": "#/components/schemas/IotaMoveAbilitySet" } }, "visibility": { - "$ref": "#/components/schemas/SuiMoveVisibility" + "$ref": "#/components/schemas/IotaMoveVisibility" } } }, - "SuiMoveNormalizedModule": { + "IotaMoveNormalizedModule": { "type": "object", "required": [ "address", @@ -8746,7 +8746,7 @@ "exposedFunctions": { "type": "object", "additionalProperties": { - "$ref": "#/components/schemas/SuiMoveNormalizedFunction" + "$ref": "#/components/schemas/IotaMoveNormalizedFunction" } }, "fileFormatVersion": { @@ -8757,7 +8757,7 @@ "friends": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiMoveModuleId" + "$ref": "#/components/schemas/IotaMoveModuleId" } }, "name": { @@ -8766,12 +8766,12 @@ "structs": { "type": "object", "additionalProperties": { - "$ref": "#/components/schemas/SuiMoveNormalizedStruct" + "$ref": "#/components/schemas/IotaMoveNormalizedStruct" } } } }, - "SuiMoveNormalizedStruct": { + "IotaMoveNormalizedStruct": { "type": "object", "required": [ "abilities", @@ -8780,23 +8780,23 @@ ], "properties": { "abilities": { - "$ref": "#/components/schemas/SuiMoveAbilitySet" + "$ref": "#/components/schemas/IotaMoveAbilitySet" }, "fields": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiMoveNormalizedField" + "$ref": "#/components/schemas/IotaMoveNormalizedField" } }, "typeParameters": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiMoveStructTypeParameter" + "$ref": "#/components/schemas/IotaMoveStructTypeParameter" } } } }, - "SuiMoveNormalizedType": { + "IotaMoveNormalizedType": { "oneOf": [ { "type": "string", @@ -8839,7 +8839,7 @@ "typeArguments": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiMoveNormalizedType" + "$ref": "#/components/schemas/IotaMoveNormalizedType" } } } @@ -8854,7 +8854,7 @@ ], "properties": { "Vector": { - "$ref": "#/components/schemas/SuiMoveNormalizedType" + "$ref": "#/components/schemas/IotaMoveNormalizedType" } }, "additionalProperties": false @@ -8880,7 +8880,7 @@ ], "properties": { "Reference": { - "$ref": "#/components/schemas/SuiMoveNormalizedType" + "$ref": "#/components/schemas/IotaMoveNormalizedType" } }, "additionalProperties": false @@ -8892,14 +8892,14 @@ ], "properties": { "MutableReference": { - "$ref": "#/components/schemas/SuiMoveNormalizedType" + "$ref": "#/components/schemas/IotaMoveNormalizedType" } }, "additionalProperties": false } ] }, - "SuiMoveStructTypeParameter": { + "IotaMoveStructTypeParameter": { "type": "object", "required": [ "constraints", @@ -8907,14 +8907,14 @@ ], "properties": { "constraints": { - "$ref": "#/components/schemas/SuiMoveAbilitySet" + "$ref": "#/components/schemas/IotaMoveAbilitySet" }, "isPhantom": { "type": "boolean" } } }, - "SuiMoveVisibility": { + "IotaMoveVisibility": { "type": "string", "enum": [ "Private", @@ -8922,7 +8922,7 @@ "Friend" ] }, - "SuiObjectDataFilter": { + "IotaObjectDataFilter": { "oneOf": [ { "type": "object", @@ -8933,7 +8933,7 @@ "MatchAll": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiObjectDataFilter" + "$ref": "#/components/schemas/IotaObjectDataFilter" } } }, @@ -8948,7 +8948,7 @@ "MatchAny": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiObjectDataFilter" + "$ref": "#/components/schemas/IotaObjectDataFilter" } } }, @@ -8963,7 +8963,7 @@ "MatchNone": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiObjectDataFilter" + "$ref": "#/components/schemas/IotaObjectDataFilter" } } }, @@ -9033,7 +9033,7 @@ ], "properties": { "AddressOwner": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, "additionalProperties": false @@ -9091,7 +9091,7 @@ } ] }, - "SuiObjectResponse": { + "IotaObjectResponse": { "type": "object", "properties": { "data": { @@ -9116,7 +9116,7 @@ } } }, - "SuiProgrammableMoveCall": { + "IotaProgrammableMoveCall": { "description": "The transaction for calling a Move function, either an entry function or a public function (which cannot return references).", "type": "object", "required": [ @@ -9129,7 +9129,7 @@ "description": "The arguments to the function.", "type": "array", "items": { - "$ref": "#/components/schemas/SuiArgument" + "$ref": "#/components/schemas/IotaArgument" } }, "function": { @@ -9157,8 +9157,8 @@ } } }, - "SuiSystemStateSummary": { - "description": "This is the JSON-RPC type for the SUI system state object. It flattens all fields to make them top-level fields such that it as minimum dependencies to the internal data structures of the SUI system state type.", + "IotaSystemStateSummary": { + "description": "This is the JSON-RPC type for the IOTA system state object. It flattens all fields to make them top-level fields such that it as minimum dependencies to the internal data structures of the IOTA system state type.", "type": "object", "required": [ "activeValidators", @@ -9204,7 +9204,7 @@ "description": "The list of active validators in the current epoch.", "type": "array", "items": { - "$ref": "#/components/schemas/SuiValidatorSummary" + "$ref": "#/components/schemas/IotaValidatorSummary" } }, "atRiskValidators": { @@ -9214,7 +9214,7 @@ "type": "array", "items": [ { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" }, { "$ref": "#/components/schemas/BigInt_for_uint64" @@ -9356,7 +9356,7 @@ ] }, "stakeSubsidyBalance": { - "description": "Balance of SUI set aside for stake subsidies that will be drawn down over time.", + "description": "Balance of IOTA set aside for stake subsidies that will be drawn down over time.", "allOf": [ { "$ref": "#/components/schemas/BigInt_for_uint64" @@ -9402,7 +9402,7 @@ ] }, "stakingPoolMappingsId": { - "description": "ID of the object that maps from staking pool's ID to the sui address of a validator.", + "description": "ID of the object that maps from staking pool's ID to the iota address of a validator.", "allOf": [ { "$ref": "#/components/schemas/ObjectID" @@ -9488,12 +9488,12 @@ "type": "array", "items": [ { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" }, { "type": "array", "items": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } } ], @@ -9511,7 +9511,7 @@ } } }, - "SuiTransaction": { + "IotaTransaction": { "description": "A single transaction in a programmable transaction block.", "oneOf": [ { @@ -9522,7 +9522,7 @@ ], "properties": { "MoveCall": { - "$ref": "#/components/schemas/SuiProgrammableMoveCall" + "$ref": "#/components/schemas/IotaProgrammableMoveCall" } }, "additionalProperties": false @@ -9540,11 +9540,11 @@ { "type": "array", "items": { - "$ref": "#/components/schemas/SuiArgument" + "$ref": "#/components/schemas/IotaArgument" } }, { - "$ref": "#/components/schemas/SuiArgument" + "$ref": "#/components/schemas/IotaArgument" } ], "maxItems": 2, @@ -9564,12 +9564,12 @@ "type": "array", "items": [ { - "$ref": "#/components/schemas/SuiArgument" + "$ref": "#/components/schemas/IotaArgument" }, { "type": "array", "items": { - "$ref": "#/components/schemas/SuiArgument" + "$ref": "#/components/schemas/IotaArgument" } } ], @@ -9590,12 +9590,12 @@ "type": "array", "items": [ { - "$ref": "#/components/schemas/SuiArgument" + "$ref": "#/components/schemas/IotaArgument" }, { "type": "array", "items": { - "$ref": "#/components/schemas/SuiArgument" + "$ref": "#/components/schemas/IotaArgument" } } ], @@ -9641,7 +9641,7 @@ "$ref": "#/components/schemas/ObjectID" }, { - "$ref": "#/components/schemas/SuiArgument" + "$ref": "#/components/schemas/IotaArgument" } ], "maxItems": 3, @@ -9669,7 +9669,7 @@ { "type": "array", "items": { - "$ref": "#/components/schemas/SuiArgument" + "$ref": "#/components/schemas/IotaArgument" } } ], @@ -9681,10 +9681,10 @@ } ] }, - "SuiTransactionBlockBuilderMode": { + "IotaTransactionBlockBuilderMode": { "oneOf": [ { - "description": "Regular Sui Transactions that are committed on chain", + "description": "Regular Iota Transactions that are committed on chain", "type": "string", "enum": [ "Commit" @@ -9699,8 +9699,8 @@ } ] }, - "SuiValidatorSummary": { - "description": "This is the JSON-RPC type for the SUI validator. It flattens all inner structures to top-level fields so that they are decoupled from the internal definitions.", + "IotaValidatorSummary": { + "description": "This is the JSON-RPC type for the IOTA validator. It flattens all inner structures to top-level fields so that they are decoupled from the internal definitions.", "type": "object", "required": [ "commissionRate", @@ -9719,7 +9719,7 @@ "p2pAddress", "pendingPoolTokenWithdraw", "pendingStake", - "pendingTotalSuiWithdraw", + "pendingTotalIotaWithdraw", "poolTokenBalance", "primaryAddress", "projectUrl", @@ -9727,8 +9727,8 @@ "protocolPubkeyBytes", "rewardsPool", "stakingPoolId", - "stakingPoolSuiBalance", - "suiAddress", + "stakingPoolIotaBalance", + "iotaAddress", "votingPower", "workerAddress", "workerPubkeyBytes" @@ -9870,7 +9870,7 @@ } ] }, - "pendingTotalSuiWithdraw": { + "pendingTotalIotaWithdraw": { "description": "Pending stake withdrawn during the current epoch, emptied at epoch boundaries.", "allOf": [ { @@ -9938,16 +9938,16 @@ } ] }, - "stakingPoolSuiBalance": { - "description": "The total number of SUI tokens in this pool.", + "stakingPoolIotaBalance": { + "description": "The total number of IOTA tokens in this pool.", "allOf": [ { "$ref": "#/components/schemas/BigInt_for_uint64" } ] }, - "suiAddress": { - "$ref": "#/components/schemas/SuiAddress" + "iotaAddress": { + "$ref": "#/components/schemas/IotaAddress" }, "votingPower": { "$ref": "#/components/schemas/BigInt_for_uint64" @@ -10042,7 +10042,7 @@ ] }, "sender": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" }, "transaction": { "$ref": "#/components/schemas/TransactionBlockKind" @@ -10298,7 +10298,7 @@ "description": "Input objects or primitive values", "type": "array", "items": { - "$ref": "#/components/schemas/SuiCallArg" + "$ref": "#/components/schemas/IotaCallArg" } }, "kind": { @@ -10311,7 +10311,7 @@ "description": "The transactions to be executed sequentially. A failure in any transaction will result in the failure of the entire programmable transaction block.", "type": "array", "items": { - "$ref": "#/components/schemas/SuiTransaction" + "$ref": "#/components/schemas/IotaTransaction" } } } @@ -10338,7 +10338,7 @@ "new_active_jwks": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiActiveJwk" + "$ref": "#/components/schemas/IotaActiveJwk" } }, "round": { @@ -10395,7 +10395,7 @@ "transactions": { "type": "array", "items": { - "$ref": "#/components/schemas/SuiEndOfEpochTransactionKind" + "$ref": "#/components/schemas/IotaEndOfEpochTransactionKind" } } } @@ -10702,7 +10702,7 @@ ], "properties": { "FromAddress": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, "additionalProperties": false @@ -10715,7 +10715,7 @@ ], "properties": { "ToAddress": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } }, "additionalProperties": false @@ -10735,10 +10735,10 @@ ], "properties": { "from": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" }, "to": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } } } @@ -10759,7 +10759,7 @@ ], "properties": { "addr": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } } } @@ -10808,7 +10808,7 @@ "$ref": "#/components/schemas/ObjectID" }, "recipient": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" } } }, @@ -10869,7 +10869,7 @@ ], "properties": { "address": { - "$ref": "#/components/schemas/SuiAddress" + "$ref": "#/components/schemas/IotaAddress" }, "apy": { "type": "number", diff --git a/crates/iota-open-rpc/src/examples.rs b/crates/iota-open-rpc/src/examples.rs new file mode 100644 index 00000000000..b9a03577df2 --- /dev/null +++ b/crates/iota-open-rpc/src/examples.rs @@ -0,0 +1,1591 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{BTreeMap, HashMap}, + ops::Range, + str::FromStr, +}; + +use fastcrypto::traits::EncodeDecodeBase64; +use iota_json::IotaJsonValue; +use iota_json_rpc::error::Error; +use iota_json_rpc_types::{ + Balance, Checkpoint, CheckpointId, CheckpointPage, Coin, CoinPage, DelegatedStake, + DevInspectArgs, DevInspectResults, DynamicFieldPage, EventFilter, EventPage, IotaCoinMetadata, + IotaCommittee, IotaData, IotaEvent, IotaExecutionStatus, IotaGetPastObjectRequest, + IotaLoadedChildObject, IotaLoadedChildObjectsResponse, IotaMoveAbility, IotaMoveAbilitySet, + IotaMoveNormalizedFunction, IotaMoveNormalizedModule, IotaMoveNormalizedStruct, + IotaMoveNormalizedType, IotaMoveVisibility, IotaObjectData, IotaObjectDataFilter, + IotaObjectDataOptions, IotaObjectRef, IotaObjectResponse, IotaObjectResponseQuery, + IotaParsedData, IotaPastObjectResponse, IotaTransactionBlock, IotaTransactionBlockData, + IotaTransactionBlockEffects, IotaTransactionBlockEffectsV1, IotaTransactionBlockEvents, + IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, + IotaTransactionBlockResponseQuery, IotaTypeTag, MoveCallParams, MoveFunctionArgType, + ObjectChange, + ObjectValueKind::{ByImmutableReference, ByMutableReference, ByValue}, + ObjectsPage, OwnedObjectRef, Page, ProtocolConfigResponse, RPCTransactionRequestParams, Stake, + StakeStatus, TransactionBlockBytes, TransactionBlocksPage, TransactionFilter, + TransferObjectParams, ValidatorApy, ValidatorApys, +}; +use iota_open_rpc::ExamplePairing; +use iota_protocol_config::{Chain, ProtocolConfig}; +use iota_types::{ + balance::Supply, + base_types::{ + random_object_ref, IotaAddress, MoveObjectType, ObjectDigest, ObjectID, ObjectType, + SequenceNumber, TransactionDigest, + }, + committee::Committee, + crypto::{get_key_pair_from_rng, AccountKeyPair, AggregateAuthoritySignature}, + digests::TransactionEventsDigest, + dynamic_field::{DynamicFieldInfo, DynamicFieldName, DynamicFieldType}, + event::EventID, + gas::GasCostSummary, + gas_coin::GasCoin, + messages_checkpoint::CheckpointDigest, + object::{MoveObject, Owner}, + parse_iota_struct_tag, + programmable_transaction_builder::ProgrammableTransactionBuilder, + quorum_driver_types::ExecuteTransactionRequestType, + signature::GenericSignature, + transaction::{CallArg, ObjectArg, TransactionData, TEST_ONLY_GAS_UNIT_FOR_TRANSFER}, + utils::to_sender_signed_transaction, + IOTA_FRAMEWORK_PACKAGE_ID, +}; +use move_core_types::{ + annotated_value::MoveStructLayout, + identifier::Identifier, + language_storage::{ModuleId, StructTag, TypeTag}, + resolver::ModuleResolver, +}; +use rand::{rngs::StdRng, Rng, SeedableRng}; +use serde_json::json; + +struct Examples { + function_name: String, + examples: Vec, +} + +#[derive(serde::Serialize)] +struct Value { + value: String, +} + +impl Examples { + fn new(name: &str, examples: Vec) -> Self { + Self { + function_name: name.to_string(), + examples, + } + } +} + +pub struct RpcExampleProvider { + rng: StdRng, +} + +impl RpcExampleProvider { + pub fn new() -> Self { + Self { + rng: StdRng::from_seed([0; 32]), + } + } + + pub fn examples(&mut self) -> BTreeMap> { + [ + self.batch_transaction_examples(), + self.get_object_example(), + self.get_past_object_example(), + self.get_owned_objects(), + self.get_total_transaction_blocks(), + self.get_transaction_block(), + self.query_transaction_blocks(), + self.get_events(), + self.execute_transaction_example(), + self.dry_run_transaction_block(), + self.dev_inspect_transaction_block(), + self.get_checkpoint_example(), + self.get_checkpoints(), + self.iota_get_committee_info(), + self.iota_get_reference_gas_price(), + self.iotax_get_all_balances(), + self.iotax_get_all_coins(), + self.iotax_get_balance(), + self.iotax_get_coin_metadata(), + self.iota_get_latest_checkpoint_sequence_number(), + self.iotax_get_coins(), + self.iotax_get_total_supply(), + self.iotax_get_dynamic_fields(), + self.iotax_get_dynamic_field_object(), + self.iotax_get_owned_objects(), + self.iota_get_loaded_child_objects(), + self.iota_get_move_function_arg_types(), + self.iota_get_normalized_move_function(), + self.iota_get_normalized_move_module(), + self.iota_get_normalized_move_modules_by_package(), + self.iota_get_normalized_move_struct(), + self.multi_get_objects_example(), + self.multi_get_transaction_blocks(), + self.iotax_get_validators_apy(), + self.iotax_get_dynamic_fields(), + self.iotax_get_dynamic_field_object(), + self.iotax_get_owned_objects(), + self.iotax_query_events(), + self.iotax_get_latest_iota_system_state(), + self.get_protocol_config(), + self.iota_get_chain_identifier(), + self.iotax_get_stakes(), + self.iotax_get_stakes_by_ids(), + self.iotax_resolve_name_service_address(), + self.iotax_resolve_name_service_names(), + self.iota_try_multi_get_past_objects(), + ] + .into_iter() + .map(|example| (example.function_name, example.examples)) + .collect() + } + + fn batch_transaction_examples(&mut self) -> Examples { + let signer = IotaAddress::from(ObjectID::new(self.rng.gen())); + let recipient = IotaAddress::from(ObjectID::new(self.rng.gen())); + let gas_id = ObjectID::new(self.rng.gen()); + let object_id = ObjectID::new(self.rng.gen()); + let coin_ref = random_object_ref(); + let random_amount: u64 = 10; + + let tx_params = vec![ + RPCTransactionRequestParams::MoveCallRequestParams(MoveCallParams { + package_object_id: IOTA_FRAMEWORK_PACKAGE_ID, + module: "pay".to_string(), + function: "split".to_string(), + type_arguments: vec![IotaTypeTag::new("0x2::iota::IOTA".to_string())], + arguments: vec![ + IotaJsonValue::new(json!(coin_ref.0)).unwrap(), + IotaJsonValue::new(json!(random_amount)).unwrap(), + ], + }), + RPCTransactionRequestParams::TransferObjectRequestParams(TransferObjectParams { + recipient, + object_id, + }), + ]; + + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + builder + .move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + Identifier::from_str("pay").unwrap(), + Identifier::from_str("split").unwrap(), + vec![], + vec![ + CallArg::Object(ObjectArg::ImmOrOwnedObject(coin_ref)), + CallArg::Pure(bcs::to_bytes(&random_amount).unwrap()), + ], + ) + .unwrap(); + builder + .transfer_object( + recipient, + ( + object_id, + SequenceNumber::from_u64(1), + ObjectDigest::new(self.rng.gen()), + ), + ) + .unwrap(); + builder.finish() + }; + let gas_price = 10; + let data = TransactionData::new_programmable( + signer, + vec![( + gas_id, + SequenceNumber::from_u64(1), + ObjectDigest::new(self.rng.gen()), + )], + pt, + TEST_ONLY_GAS_UNIT_FOR_TRANSFER * gas_price, + gas_price, + ); + + let result = TransactionBlockBytes::from_data(data).unwrap(); + + Examples::new( + "iota_batchTransaction", + vec![ExamplePairing::new( + "Creates unsigned batch transaction data.", + vec![ + ("signer", json!(signer)), + ("single_transaction_params", json!(tx_params)), + ("gas", json!(gas_id)), + ("gas_budget", json!(1000)), + ("txn_builder_mode", json!("Commit")), + ], + json!(result), + )], + ) + } + + fn execute_transaction_example(&mut self) -> Examples { + let (data, signatures, _, _, result) = self.get_transfer_data_response(); + let tx_bytes = TransactionBlockBytes::from_data(data).unwrap(); + + Examples::new( + "iota_executeTransactionBlock", + vec![ExamplePairing::new( + "Executes a transaction with serialized signatures.", + vec![ + ("tx_bytes", json!(tx_bytes.tx_bytes)), + ( + "signatures", + json!( + signatures + .into_iter() + .map(|sig| sig.encode_base64()) + .collect::>() + ), + ), + ( + "options", + json!(IotaTransactionBlockResponseOptions::full_content()), + ), + ( + "request_type", + json!(ExecuteTransactionRequestType::WaitForLocalExecution), + ), + ], + json!(result), + )], + ) + } + + fn dry_run_transaction_block(&mut self) -> Examples { + let (data, _, _, _, result) = self.get_transfer_data_response(); + let tx_bytes = TransactionBlockBytes::from_data(data).unwrap(); + + Examples::new( + "iota_dryRunTransactionBlock", + vec![ExamplePairing::new( + "Dry runs a transaction block to get back estimated gas fees and other potential effects.", + vec![("tx_bytes", json!(tx_bytes.tx_bytes))], + json!(result), + )], + ) + } + + fn dev_inspect_transaction_block(&mut self) -> Examples { + let (data, _, _, _, result) = self.get_transfer_data_response(); + let tx_bytes = TransactionBlockBytes::from_data(data).unwrap(); + + let dev_inspect_results = DevInspectResults { + effects: result.effects.unwrap(), + events: IotaTransactionBlockEvents { data: vec![] }, + results: None, + error: None, + raw_txn_data: vec![], + raw_effects: vec![], + }; + + Examples::new( + "iota_devInspectTransactionBlock", + vec![ExamplePairing::new( + "Runs the transaction in dev-inspect mode. Which allows for nearly any transaction (or Move call) with any arguments. Detailed results are provided, including both the transaction effects and any return values.", + vec![ + ( + "sender_address", + json!(IotaAddress::from(ObjectID::new(self.rng.gen()))), + ), + ("tx_bytes", json!(tx_bytes.tx_bytes)), + ("gas_price", json!(1000)), + ("epoch", json!(8888)), + ("additional_args", json!(None::)), + ], + json!(dev_inspect_results), + )], + ) + } + + fn multi_get_objects_example(&mut self) -> Examples { + let objects = self.get_object_responses(5); + let object_ids = objects + .iter() + .map(|o| o.object_id().unwrap()) + .collect::>(); + Examples::new( + "iota_multiGetObjects", + vec![ExamplePairing::new( + "Gets objects by IDs.", + vec![ + ("object_ids", json!(object_ids)), + ("options", json!(IotaObjectDataOptions::full_content())), + ], + json!(objects), + )], + ) + } + + fn get_object_responses(&mut self, object_count: usize) -> Vec { + (0..object_count) + .map(|_| { + let object_id = ObjectID::new(self.rng.gen()); + let coin = GasCoin::new(object_id, 100000000); + + IotaObjectResponse::new_with_data(IotaObjectData { + content: Some( + IotaParsedData::try_from_object( + coin.to_object(SequenceNumber::from_u64(1)), + GasCoin::layout(), + ) + .unwrap(), + ), + owner: Some(Owner::AddressOwner(IotaAddress::from(ObjectID::new( + self.rng.gen(), + )))), + previous_transaction: Some(TransactionDigest::new(self.rng.gen())), + storage_rebate: Some(100), + object_id, + version: SequenceNumber::from_u64(1), + digest: ObjectDigest::new(self.rng.gen()), + type_: Some(ObjectType::Struct(MoveObjectType::gas_coin())), + bcs: None, + display: None, + }) + }) + .collect() + } + + fn get_object_example(&mut self) -> Examples { + let result = self.get_object_responses(1).pop().unwrap(); + Examples::new( + "iota_getObject", + vec![ExamplePairing::new( + "Gets Object data for the ID in the request.", + vec![ + ("object_id", json!(result.object_id().unwrap())), + ("options", json!(IotaObjectDataOptions::full_content())), + ], + json!(result), + )], + ) + } + + fn get_past_object_example(&mut self) -> Examples { + let object_id = ObjectID::new(self.rng.gen()); + + let coin = GasCoin::new(object_id, 10000); + + let result = IotaPastObjectResponse::VersionFound(IotaObjectData { + content: Some( + IotaParsedData::try_from_object( + coin.to_object(SequenceNumber::from_u64(1)), + GasCoin::layout(), + ) + .unwrap(), + ), + owner: Some(Owner::AddressOwner(IotaAddress::from(ObjectID::new( + self.rng.gen(), + )))), + previous_transaction: Some(TransactionDigest::new(self.rng.gen())), + storage_rebate: Some(100), + object_id, + version: SequenceNumber::from_u64(4), + digest: ObjectDigest::new(self.rng.gen()), + type_: Some(ObjectType::Struct(MoveObjectType::gas_coin())), + bcs: None, + display: None, + }); + + Examples::new( + "iota_tryGetPastObject", + vec![ExamplePairing::new( + "Gets Past Object data.", + vec![ + ("object_id", json!(object_id)), + ("version", json!(4)), + ("options", json!(IotaObjectDataOptions::full_content())), + ], + json!(result), + )], + ) + } + + fn get_checkpoint_example(&mut self) -> Examples { + let result = Checkpoint { + epoch: 5000, + sequence_number: 1000, + digest: CheckpointDigest::new(self.rng.gen()), + network_total_transactions: 792385, + previous_digest: Some(CheckpointDigest::new(self.rng.gen())), + epoch_rolling_gas_cost_summary: Default::default(), + timestamp_ms: 1676911928, + end_of_epoch_data: None, + transactions: vec![TransactionDigest::new(self.rng.gen())], + checkpoint_commitments: vec![], + validator_signature: AggregateAuthoritySignature::default(), + }; + + Examples::new( + "iota_getCheckpoint", + vec![ExamplePairing::new( + "Gets checkpoint information for the checkpoint ID in the request.", + vec![("id", json!(CheckpointId::SequenceNumber(1000)))], + json!(result), + )], + ) + } + + fn get_checkpoints(&mut self) -> Examples { + let limit = 4; + let descending_order = false; + let seq = 1004; + let page = (0..4) + .map(|idx| Checkpoint { + epoch: 5000, + sequence_number: seq + 1 + idx, + digest: CheckpointDigest::new(self.rng.gen()), + network_total_transactions: 792385, + previous_digest: Some(CheckpointDigest::new(self.rng.gen())), + epoch_rolling_gas_cost_summary: Default::default(), + timestamp_ms: 1676911928, + end_of_epoch_data: None, + transactions: vec![TransactionDigest::new(self.rng.gen())], + checkpoint_commitments: vec![], + validator_signature: AggregateAuthoritySignature::default(), + }) + .collect::>(); + let pagelen = page.len() as u64; + let result = CheckpointPage { + data: page, + next_cursor: Some((seq + pagelen).into()), + has_next_page: true, + }; + + Examples::new( + "iota_getCheckpoints", + vec![ExamplePairing::new( + "Gets a paginated list in descending order of all checkpoints starting at the provided cursor. Each page of results has a maximum number of checkpoints set by the provided limit.", + vec![ + ("cursor", json!(seq.to_string())), + ("limit", json!(limit)), + ("descending_order", json!(descending_order)), + ], + json!(result), + )], + ) + } + + fn get_owned_objects(&mut self) -> Examples { + let owner = IotaAddress::from(ObjectID::new(self.rng.gen())); + let result = (0..4) + .map(|_| IotaObjectData { + object_id: ObjectID::new(self.rng.gen()), + version: Default::default(), + digest: ObjectDigest::new(self.rng.gen()), + type_: Some(ObjectType::Struct(MoveObjectType::gas_coin())), + owner: Some(Owner::AddressOwner(owner)), + previous_transaction: Some(TransactionDigest::new(self.rng.gen())), + storage_rebate: None, + display: None, + content: None, + bcs: None, + }) + .collect::>(); + + Examples::new( + "iota_getOwnedObjects", + vec![ExamplePairing::new( + "Gets objects owned by the address in the request.", + vec![ + ("address", json!(owner)), + ( + "query", + json!(IotaObjectResponseQuery { + filter: Some(IotaObjectDataFilter::StructType( + StructTag::from_str("0x2::coin::Coin<0x2::iota::IOTA>").unwrap() + )), + options: Some( + IotaObjectDataOptions::new() + .with_type() + .with_owner() + .with_previous_transaction() + ) + }), + ), + ("cursor", json!(ObjectID::new(self.rng.gen()))), + ("limit", json!(100)), + ("at_checkpoint", json!(None::)), + ], + json!(result), + )], + ) + } + + fn get_total_transaction_blocks(&mut self) -> Examples { + Examples::new( + "iota_getTotalTransactionBlocks", + vec![ExamplePairing::new( + "Gets total number of transactions on the network.", + vec![], + json!("2451485"), + )], + ) + } + + fn get_transaction_block(&mut self) -> Examples { + let (_, _, _, _, result) = self.get_transfer_data_response(); + Examples::new( + "iota_getTransactionBlock", + vec![ExamplePairing::new( + "Returns the transaction response object for specified transaction digest.", + vec![ + ("digest", json!(result.digest)), + ( + "options", + json!( + IotaTransactionBlockResponseOptions::new() + .with_input() + .with_effects() + .with_events() + ), + ), + ], + json!(result), + )], + ) + } + + fn query_transaction_blocks(&mut self) -> Examples { + let mut data = self.get_transaction_digests(5..9); + let has_next_page = data.len() > (9 - 5); + data.truncate(9 - 5); + let next_cursor = data.last().cloned(); + let data = data + .into_iter() + .map(IotaTransactionBlockResponse::new) + .collect(); + + let result = TransactionBlocksPage { + data, + next_cursor, + has_next_page, + }; + Examples::new( + "iotax_queryTransactionBlocks", + vec![ExamplePairing::new( + "Returns the transaction digest for specified query criteria.", + vec![ + ( + "query", + json!(IotaTransactionBlockResponseQuery { + filter: Some(TransactionFilter::InputObject(ObjectID::new( + self.rng.gen() + ))), + options: None, + }), + ), + ("cursor", json!(TransactionDigest::new(self.rng.gen()))), + ("limit", json!(100)), + ("descending_order", json!(false)), + ], + json!(result), + )], + ) + } + + fn multi_get_transaction_blocks(&mut self) -> Examples { + let data = (0..3) + .map(|_| self.get_transfer_data_response().4) + .collect::>(); + let digests = data.iter().map(|x| x.digest).collect::>(); + Examples::new( + "iota_multiGetTransactionBlocks", + vec![ExamplePairing::new( + "Returns the transaction data for specified digest.", + vec![ + ("digests", json!(digests)), + ( + "options", + json!( + IotaTransactionBlockResponseOptions::new() + .with_input() + .with_effects() + .with_events() + ), + ), + ], + json!(data), + )], + ) + } + + fn get_transaction_digests(&mut self, range: Range) -> Vec { + range + .into_iter() + .map(|_| TransactionDigest::new(self.rng.gen())) + .collect() + } + + fn get_event_ids(&mut self, range: Range) -> Vec { + range + .into_iter() + .map(|_| EventID { + tx_digest: TransactionDigest::new(self.rng.gen()), + event_seq: 1, + }) + .collect() + } + + fn get_protocol_config(&mut self) -> Examples { + let version = Some(6); + Examples::new( + "iota_getProtocolConfig", + vec![ExamplePairing::new( + "Returns the protocol config for the given protocol version. If none is specified, the node uses the version of the latest epoch it has processed", + vec![("version", json!(version))], + json!(Self::get_protocol_config_impl(version)), + )], + ) + } + + fn get_protocol_config_impl(version: Option) -> ProtocolConfigResponse { + ProtocolConfigResponse::from( + version + .map(|v| { + ProtocolConfig::get_for_version_if_supported(v.into(), Chain::Unknown) + .unwrap_or(ProtocolConfig::get_for_min_version()) + }) + .unwrap_or(ProtocolConfig::get_for_min_version()), + ) + } + + fn get_transfer_data_response( + &mut self, + ) -> ( + TransactionData, + Vec, + IotaAddress, + ObjectID, + IotaTransactionBlockResponse, + ) { + let (signer, kp): (_, AccountKeyPair) = get_key_pair_from_rng(&mut self.rng); + let recipient = IotaAddress::from(ObjectID::new(self.rng.gen())); + let obj_id = ObjectID::new(self.rng.gen()); + let gas_ref = ( + ObjectID::new(self.rng.gen()), + SequenceNumber::from_u64(2), + ObjectDigest::new(self.rng.gen()), + ); + let object_ref = ( + obj_id, + SequenceNumber::from_u64(2), + ObjectDigest::new(self.rng.gen()), + ); + + let data = TransactionData::new_transfer( + recipient, + object_ref, + signer, + gas_ref, + TEST_ONLY_GAS_UNIT_FOR_TRANSFER * 10, + 10, + ); + let data1 = data.clone(); + let data2 = data.clone(); + + let tx = to_sender_signed_transaction(data, &kp); + let signatures = tx.data().tx_signatures().to_vec(); + let raw_transaction = bcs::to_bytes(tx.data()).unwrap(); + + let tx_digest = tx.digest(); + let object_change = ObjectChange::Transferred { + sender: signer, + recipient: Owner::AddressOwner(recipient), + object_type: parse_iota_struct_tag("0x2::example::Object").unwrap(), + object_id: object_ref.0, + version: object_ref.1, + digest: ObjectDigest::new(self.rng.gen()), + }; + struct NoOpsModuleResolver; + impl ModuleResolver for NoOpsModuleResolver { + type Error = Error; + fn get_module(&self, _id: &ModuleId) -> Result>, Self::Error> { + Ok(None) + } + } + let result = IotaTransactionBlockResponse { + digest: *tx_digest, + effects: Some(IotaTransactionBlockEffects::V1( + IotaTransactionBlockEffectsV1 { + status: IotaExecutionStatus::Success, + executed_epoch: 0, + modified_at_versions: vec![], + gas_used: GasCostSummary { + computation_cost: 100, + storage_cost: 100, + storage_rebate: 10, + non_refundable_storage_fee: 0, + }, + shared_objects: vec![], + transaction_digest: TransactionDigest::new(self.rng.gen()), + created: vec![], + mutated: vec![ + OwnedObjectRef { + owner: Owner::AddressOwner(signer), + reference: gas_ref.into(), + }, + OwnedObjectRef { + owner: Owner::AddressOwner(recipient), + reference: object_ref.into(), + }, + ], + unwrapped: vec![], + deleted: vec![], + unwrapped_then_deleted: vec![], + wrapped: vec![], + gas_object: OwnedObjectRef { + owner: Owner::ObjectOwner(signer), + reference: IotaObjectRef::from(gas_ref), + }, + events_digest: Some(TransactionEventsDigest::new(self.rng.gen())), + dependencies: vec![], + }, + )), + events: None, + object_changes: Some(vec![object_change]), + balance_changes: None, + timestamp_ms: None, + transaction: Some(IotaTransactionBlock { + data: IotaTransactionBlockData::try_from(data1, &&mut NoOpsModuleResolver).unwrap(), + tx_signatures: signatures.clone(), + }), + raw_transaction, + confirmed_local_execution: None, + checkpoint: None, + errors: vec![], + raw_effects: vec![], + }; + + (data2, signatures, recipient, obj_id, result) + } + + fn get_events(&mut self) -> Examples { + let tx_dig = + TransactionDigest::from_str("11a72GCQ5hGNpWGh2QhQkkusTEGS6EDqifJqxr7nSYX").unwrap(); + let event = IotaEvent { + id: EventID { + tx_digest: tx_dig, + event_seq: 0, + }, + package_id: ObjectID::new(self.rng.gen()), + transaction_module: Identifier::from_str("test_module").unwrap(), + sender: IotaAddress::from(ObjectID::new(self.rng.gen())), + type_: parse_iota_struct_tag("0x9::test::TestEvent").unwrap(), + parsed_json: json!({"test": "example value"}), + bcs: vec![], + timestamp_ms: None, + }; + + let page = EventPage { + data: vec![event], + next_cursor: Some((tx_dig, 5).into()), + has_next_page: false, + }; + Examples::new( + "iota_getEvents", + vec![ExamplePairing::new( + "Returns the events the transaction in the request emits.", + vec![("transaction_digest", json!(tx_dig))], + json!(page), + )], + ) + } + + fn iota_get_committee_info(&mut self) -> Examples { + let epoch = 5000; + let committee = json!(Committee::new_simple_test_committee_of_size(4)); + let vals = json!(committee[0]["voting_rights"]); + let iotacomm = IotaCommittee { + epoch, + validators: serde_json::from_value(vals).unwrap(), + }; + + Examples::new( + "iotax_getCommitteeInfo", + vec![ExamplePairing::new( + "Gets committee information for epoch 5000.", + vec![("epoch", json!(epoch.to_string()))], + json!(iotacomm), + )], + ) + } + + fn iota_get_reference_gas_price(&mut self) -> Examples { + let result = 1000; + Examples::new( + "iotax_getReferenceGasPrice", + vec![ExamplePairing::new( + "Gets reference gas price information for the network.", + vec![], + json!(result), + )], + ) + } + + fn iotax_get_all_balances(&mut self) -> Examples { + let address = IotaAddress::from(ObjectID::new(self.rng.gen())); + + let result = Balance { + coin_type: "0x2::iota::IOTA".to_string(), + coin_object_count: 15, + total_balance: 3000000000, + locked_balance: HashMap::new(), + }; + Examples::new( + "iotax_getAllBalances", + vec![ExamplePairing::new( + "Gets all balances for the address in the request.", + vec![("owner", json!(address))], + json!(vec![result]), + )], + ) + } + + fn iotax_get_all_coins(&mut self) -> Examples { + let limit = 3; + let owner = IotaAddress::from(ObjectID::new(self.rng.gen())); + let cursor = ObjectID::new(self.rng.gen()); + let next = ObjectID::new(self.rng.gen()); + let coins = (0..3) + .map(|_| Coin { + coin_type: "0x2::iota::IOTA".to_string(), + coin_object_id: ObjectID::new(self.rng.gen()), + version: SequenceNumber::from_u64(103626), + digest: ObjectDigest::new(self.rng.gen()), + balance: 200000000, + // locked_until_epoch: None, + previous_transaction: TransactionDigest::new(self.rng.gen()), + }) + .collect::>(); + let page = CoinPage { + data: coins, + next_cursor: Some(next), + has_next_page: true, + }; + + Examples::new( + "iotax_getAllCoins", + vec![ExamplePairing::new( + "Gets all coins for the address in the request body. Begin listing the coins that are after the provided `cursor` value and return only the `limit` amount of results per page.", + vec![ + ("owner", json!(owner)), + ("cursor", json!(cursor)), + ("limit", json!(limit)), + ], + json!(page), + )], + ) + } + + fn iotax_get_balance(&mut self) -> Examples { + let owner = IotaAddress::from(ObjectID::new(self.rng.gen())); + let coin_type = "0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC".to_string(); + let result = Balance { + coin_type: coin_type.clone(), + coin_object_count: 15, + total_balance: 15, + locked_balance: HashMap::new(), + }; + + Examples::new( + "iotax_getBalance", + vec![ExamplePairing::new( + "Gets the balance of the specified type of coin for the address in the request.", + vec![("owner", json!(owner)), ("coin_type", json!(coin_type))], + json!(result), + )], + ) + } + + fn iotax_get_coin_metadata(&mut self) -> Examples { + let result = IotaCoinMetadata { + decimals: 9, + name: "Usdc".to_string(), + symbol: "USDC".to_string(), + description: "Stable coin.".to_string(), + icon_url: None, + id: Some(ObjectID::new(self.rng.gen())), + }; + + Examples::new( + "iotax_getCoinMetadata", + vec![ExamplePairing::new( + "Gets the metadata for the coin type in the request.", + vec![( + "coin_type", + json!("0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC".to_string()), + )], + json!(result), + )], + ) + } + + fn iota_get_latest_checkpoint_sequence_number(&mut self) -> Examples { + let result = "507021"; + Examples::new( + "iota_getLatestCheckpointSequenceNumber", + vec![ExamplePairing::new( + "Gets the sequence number for the latest checkpoint.", + vec![], + json!(result), + )], + ) + } + + fn iotax_get_coins(&mut self) -> Examples { + let coin_type = "0x2::iota::IOTA".to_string(); + let owner = IotaAddress::from(ObjectID::new(self.rng.gen())); + let coins = (0..3) + .map(|_| Coin { + coin_type: coin_type.clone(), + coin_object_id: ObjectID::new(self.rng.gen()), + version: SequenceNumber::from_u64(103626), + digest: ObjectDigest::new(self.rng.gen()), + balance: 200000000, + // locked_until_epoch: None, + previous_transaction: TransactionDigest::new(self.rng.gen()), + }) + .collect::>(); + + let next_cursor = coins.last().unwrap().coin_object_id; + + let page = CoinPage { + data: coins, + next_cursor: Some(next_cursor), + has_next_page: true, + }; + + Examples::new( + "iotax_getCoins", + vec![ExamplePairing::new( + "Gets all IOTA coins owned by the address provided. Return a paginated list of `limit` results per page. Similar to `iotax_getAllCoins`, but provides a way to filter by coin type.", + vec![ + ("owner", json!(owner)), + ("coin_type", json!(coin_type)), + ("cursor", json!(ObjectID::new(self.rng.gen()))), + ("limit", json!(3)), + ], + json!(page), + )], + ) + } + + fn iotax_get_total_supply(&mut self) -> Examples { + let mut coin = ObjectID::new(self.rng.gen()).to_string(); + coin.push_str("::acoin::ACOIN"); + + let result = Supply { value: 12023692 }; + + Examples::new( + "iotax_getTotalSupply", + vec![ExamplePairing::new( + "Gets total supply for the type of coin provided.", + vec![("coin_type", json!(coin))], + json!(result), + )], + ) + } + + fn iota_get_loaded_child_objects(&mut self) -> Examples { + let mut sequence = SequenceNumber::from_u64(self.rng.gen_range(24506..6450624)); + let seqs = (0..6) + .map(|x| { + if x % 2 == 0 || x % 3 == 0 { + sequence = SequenceNumber::from_u64(self.rng.gen_range(24506..6450624)); + } + + IotaLoadedChildObject::new(ObjectID::new(self.rng.gen()), sequence) + }) + .collect::>(); + let result = { + IotaLoadedChildObjectsResponse { + loaded_child_objects: seqs, + } + }; + + Examples::new( + "iota_getLoadedChildObjects", + vec![ExamplePairing::new( + "Gets loaded child objects associated with the transaction the request provides.", + vec![("digest", json!(ObjectDigest::new(self.rng.gen())))], + json!(result), + )], + ) + } + + fn iota_get_move_function_arg_types(&mut self) -> Examples { + let result = vec![ + MoveFunctionArgType::Object(ByMutableReference), + MoveFunctionArgType::Pure, + MoveFunctionArgType::Pure, + MoveFunctionArgType::Object(ByValue), + MoveFunctionArgType::Object(ByImmutableReference), + MoveFunctionArgType::Object(ByValue), + MoveFunctionArgType::Object(ByMutableReference), + ]; + + Examples::new( + "iota_getMoveFunctionArgTypes", + vec![ExamplePairing::new( + "Returns the argument types for the package and function the request provides.", + vec![ + ("package", json!(ObjectID::new(self.rng.gen()))), + ("module", json!("iotafrens".to_string())), + ("function", json!("mint".to_string())), + ], + json!(result), + )], + ) + } + + fn iota_get_normalized_move_function(&mut self) -> Examples { + let ability_set = IotaMoveAbilitySet { + abilities: vec![IotaMoveAbility::Store, IotaMoveAbility::Key], + }; + + let result = IotaMoveNormalizedFunction { + is_entry: false, + type_parameters: vec![ability_set], + parameters: vec![IotaMoveNormalizedType::U64], + visibility: IotaMoveVisibility::Public, + return_: vec![IotaMoveNormalizedType::U64], + }; + + Examples::new( + "iota_getNormalizedMoveFunction", + vec![ExamplePairing::new( + "Returns the structured representation of the function the request provides.", + vec![ + ("package", json!(ObjectID::new(self.rng.gen()))), + ("module_name", json!("moduleName".to_string())), + ("function_name", json!("functionName".to_string())), + ], + json!(result), + )], + ) + } + + fn iota_get_normalized_move_module(&mut self) -> Examples { + let result = IotaMoveNormalizedModule { + address: ObjectID::new(self.rng.gen()).to_string(), + exposed_functions: BTreeMap::new(), + file_format_version: 6, + friends: vec![], + name: "module".to_string(), + structs: BTreeMap::new(), + }; + + Examples::new( + "iota_getNormalizedMoveModule", + vec![ExamplePairing::new( + "Gets a structured representation of the Move module for the package in the request.", + vec![ + ("package", json!(ObjectID::new(self.rng.gen()))), + ("module_name", json!("module".to_string())), + ], + json!(result), + )], + ) + } + + fn iota_get_normalized_move_modules_by_package(&mut self) -> Examples { + let result = IotaMoveNormalizedModule { + address: ObjectID::new(self.rng.gen()).to_string(), + exposed_functions: BTreeMap::new(), + file_format_version: 6, + friends: vec![], + name: "module".to_string(), + structs: BTreeMap::new(), + }; + + Examples::new( + "iota_getNormalizedMoveModulesByPackage", + vec![ExamplePairing::new( + "Gets structured representations of all the modules for the package in the request.", + vec![("package", json!(ObjectID::new(self.rng.gen())))], + json!(result), + )], + ) + } + + fn iota_get_normalized_move_struct(&mut self) -> Examples { + let abilities = IotaMoveAbilitySet { + abilities: vec![IotaMoveAbility::Store, IotaMoveAbility::Key], + }; + let fields = vec![].into_iter().collect::>(); + let type_parameters = vec![].into_iter().collect::>(); + let result = IotaMoveNormalizedStruct { + abilities, + fields, + type_parameters, + }; + + Examples::new( + "iota_getNormalizedMoveStruct", + vec![ExamplePairing::new( + "Gets a structured representation of the struct in the request.", + vec![ + ("package", json!(ObjectID::new(self.rng.gen()))), + ("module_name", json!("module".to_string())), + ("struct_name", json!("StructName".to_string())), + ], + json!(result), + )], + ) + } + + fn iotax_get_validators_apy(&mut self) -> Examples { + let result = vec![ + ValidatorApy { + address: IotaAddress::from(ObjectID::new(self.rng.gen())), + apy: 0.06, + }, + ValidatorApy { + address: IotaAddress::from(ObjectID::new(self.rng.gen())), + apy: 0.02, + }, + ValidatorApy { + address: IotaAddress::from(ObjectID::new(self.rng.gen())), + apy: 0.05, + }, + ]; + + Examples::new( + "iotax_getValidatorsApy", + vec![ExamplePairing::new( + "Gets the APY for all validators.", + vec![], + json!(ValidatorApys { + apys: result, + epoch: 420 + }), + )], + ) + } + + fn iotax_get_dynamic_fields(&mut self) -> Examples { + let object_id = ObjectID::new(self.rng.gen()); + let dynamic_fields = (0..3) + .map(|_| DynamicFieldInfo { + name: DynamicFieldName { + type_: TypeTag::from_str("0x9::test::TestField").unwrap(), + value: serde_json::Value::String("some_value".to_string()), + }, + bcs_name: bcs::to_bytes("0x9::test::TestField").unwrap(), + type_: DynamicFieldType::DynamicField, + object_type: "test".to_string(), + object_id: ObjectID::new(self.rng.gen()), + version: SequenceNumber::from_u64(1), + digest: ObjectDigest::new(self.rng.gen()), + }) + .collect::>(); + + let next_cursor = ObjectID::new(self.rng.gen()); + + let page = DynamicFieldPage { + data: dynamic_fields, + next_cursor: Some(next_cursor), + has_next_page: true, + }; + + Examples::new( + "iotax_getDynamicFields", + vec![ExamplePairing::new( + "Gets dynamic fields for the object the request provides in a paginated list of `limit` dynamic field results per page. The default limit is 50.", + vec![ + ("parent_object_id", json!(object_id)), + ("cursor", json!(ObjectID::new(self.rng.gen()))), + ("limit", json!(3)), + ], + json!(page), + )], + ) + } + + fn iotax_get_dynamic_field_object(&mut self) -> Examples { + let parent_object_id = ObjectID::new(self.rng.gen()); + let field_name = DynamicFieldName { + type_: TypeTag::from_str("0x9::test::TestField").unwrap(), + value: serde_json::Value::String("some_value".to_string()), + }; + + let struct_tag = parse_iota_struct_tag("0x9::test::TestField").unwrap(); + let resp = IotaObjectResponse::new_with_data(IotaObjectData { + content: Some( + IotaParsedData::try_from_object( + unsafe { + MoveObject::new_from_execution_with_limit( + MoveObjectType::from(struct_tag.clone()), + true, + SequenceNumber::from_u64(1), + Vec::new(), + 5, + ) + .unwrap() + }, + MoveStructLayout { + type_: struct_tag, + fields: Vec::new(), + }, + ) + .unwrap(), + ), + owner: Some(Owner::AddressOwner(IotaAddress::from(ObjectID::new( + self.rng.gen(), + )))), + previous_transaction: Some(TransactionDigest::new(self.rng.gen())), + storage_rebate: Some(100), + object_id: parent_object_id, + version: SequenceNumber::from_u64(1), + digest: ObjectDigest::new(self.rng.gen()), + type_: Some(ObjectType::Struct(MoveObjectType::from( + parse_iota_struct_tag("0x9::test::TestField").unwrap(), + ))), + bcs: None, + display: None, + }); + Examples::new( + "iotax_getDynamicFieldObject", + vec![ExamplePairing::new( + "Gets the information for the dynamic field the request provides.", + vec![ + ("parent_object_id", json!(parent_object_id)), + ("name", json!(field_name)), + ], + json!(resp), + )], + ) + } + + fn iotax_get_owned_objects(&mut self) -> Examples { + let owner = IotaAddress::from(ObjectID::new(self.rng.gen())); + let version: u64 = 13488; + let options = Some( + IotaObjectDataOptions::new() + .with_type() + .with_owner() + .with_previous_transaction(), + ); + let filter = Some(IotaObjectDataFilter::MatchAll(vec![ + IotaObjectDataFilter::StructType( + StructTag::from_str("0x2::coin::Coin<0x2::iota::IOTA>").unwrap(), + ), + IotaObjectDataFilter::AddressOwner(owner), + IotaObjectDataFilter::Version(version), + ])); + let query = json!(IotaObjectResponseQuery { filter, options }); + let object_id = ObjectID::new(self.rng.gen()); + + let items = (0..3) + .map(|_| { + IotaObjectResponse::new_with_data(IotaObjectData { + content: None, + owner: Some(Owner::AddressOwner(owner)), + previous_transaction: Some(TransactionDigest::new(self.rng.gen())), + storage_rebate: Some(100), + object_id: ObjectID::new(self.rng.gen()), + version: SequenceNumber::from_u64(version), + digest: ObjectDigest::new(self.rng.gen()), + type_: Some(ObjectType::Struct(MoveObjectType::gas_coin())), + bcs: None, + display: None, + }) + }) + .collect::>(); + + let next_cursor = items.last().unwrap().object_id(); + let result = ObjectsPage { + data: items, + next_cursor: Some(next_cursor.unwrap()), + has_next_page: true, + }; + + Examples::new( + "iotax_getOwnedObjects", + vec![ExamplePairing::new( + "Returns all the objects the address provided in the request owns and that match the filter. By default, only the digest value is returned, but the request returns additional information by setting the relevant keys to true. A cursor value is also provided, so the list of results begin after that value.", + vec![ + ("address", json!(owner)), + ("query", json!(query)), + ("cursor", json!(object_id)), + ("limit", json!(3)), + ], + json!(result), + )], + ) + } + + fn iotax_query_events(&mut self) -> Examples { + let package_id = ObjectID::new(self.rng.gen()); + let identifier = Identifier::from_str("test").unwrap(); + let mut event_ids = self.get_event_ids(5..9); + let has_next_page = event_ids.len() > (9 - 5); + event_ids.truncate(9 - 5); + let next_cursor = event_ids.last().cloned(); + let cursor = event_ids.last().cloned(); + + let data = event_ids + .into_iter() + .map(|event_id| IotaEvent { + id: event_id, + package_id, + transaction_module: identifier.clone(), + sender: IotaAddress::from(ObjectID::new(self.rng.gen())), + type_: StructTag::from_str("0x3::test::Test<0x3::test::Test>").unwrap(), + parsed_json: serde_json::Value::String("some_value".to_string()), + bcs: vec![], + timestamp_ms: None, + }) + .collect(); + + let result = EventPage { + data, + next_cursor, + has_next_page, + }; + Examples::new( + "iotax_queryEvents", + vec![ExamplePairing::new( + "Returns the events for a specified query criteria.", + vec![ + ( + "query", + json!(EventFilter::MoveModule { + package: ObjectID::new(self.rng.gen()), + module: Identifier::from_str("test").unwrap(), + }), + ), + ("cursor", json!(cursor)), + ("limit", json!(100)), + ("descending_order", json!(false)), + ], + json!(result), + )], + ) + } + + fn iotax_get_latest_iota_system_state(&mut self) -> Examples { + let result = "some_system_state"; + Examples::new( + "iotax_getLatestIotaSystemState", + vec![ExamplePairing::new( + "Gets objects owned by the address in the request.", + vec![], + json!(result), + )], + ) + } + + fn iota_get_chain_identifier(&mut self) -> Examples { + let result = "4c78adac".to_string(); + Examples::new( + "iota_getChainIdentifier", + vec![ExamplePairing::new( + "Gets the identifier for the chain receiving the POST.", + vec![], + json!(result), + )], + ) + } + + fn iotax_get_stakes(&mut self) -> Examples { + let principal = 200000000000; + let owner = IotaAddress::from(ObjectID::new(self.rng.gen())); + let result = vec![ + DelegatedStake { + validator_address: IotaAddress::from(ObjectID::new(self.rng.gen())), + staking_pool: ObjectID::new(self.rng.gen()), + stakes: vec![ + Stake { + staked_iota_id: ObjectID::new(self.rng.gen()), + stake_request_epoch: 62, + stake_active_epoch: 63, + principal, + status: StakeStatus::Active { + estimated_reward: (principal as f64 * 0.0026) as u64, + }, + }, + Stake { + staked_iota_id: ObjectID::new(self.rng.gen()), + stake_request_epoch: 142, + stake_active_epoch: 143, + principal, + status: StakeStatus::Pending, + }, + ], + }, + DelegatedStake { + validator_address: IotaAddress::from(ObjectID::new(self.rng.gen())), + staking_pool: ObjectID::new(self.rng.gen()), + stakes: vec![Stake { + staked_iota_id: ObjectID::new(self.rng.gen()), + stake_request_epoch: 244, + stake_active_epoch: 245, + principal, + status: StakeStatus::Unstaked, + }], + }, + ]; + + Examples::new( + "iotax_getStakes", + vec![ExamplePairing::new( + "Returns the staking information for the address the request provides.", + vec![("owner", json!(owner))], + json!(result), + )], + ) + } + + fn iotax_get_stakes_by_ids(&mut self) -> Examples { + let principal = 200000000000; + let stake1 = ObjectID::new(self.rng.gen()); + let stake2 = ObjectID::new(self.rng.gen()); + let result = DelegatedStake { + validator_address: IotaAddress::from(ObjectID::new(self.rng.gen())), + staking_pool: ObjectID::new(self.rng.gen()), + stakes: vec![ + Stake { + staked_iota_id: stake1, + stake_request_epoch: 62, + stake_active_epoch: 63, + principal, + status: StakeStatus::Active { + estimated_reward: (principal as f64 * 0.0026) as u64, + }, + }, + Stake { + staked_iota_id: stake2, + stake_request_epoch: 244, + stake_active_epoch: 245, + principal, + status: StakeStatus::Unstaked, + }, + ], + }; + Examples::new( + "iotax_getStakesByIds", + vec![ExamplePairing::new( + "Returns the staking information for the address the request provides.", + vec![("staked_iota_ids", json!(vec![stake1, stake2]))], + json!(result), + )], + ) + } + + fn iotax_resolve_name_service_address(&mut self) -> Examples { + let result = ObjectID::new(self.rng.gen()); + Examples::new( + "iotax_resolveNameServiceAddress", + vec![ExamplePairing::new( + "Returns the resolved address for the name the request provides.", + vec![("name", json!("example.iota".to_string()))], + json!(result), + )], + ) + } + + fn iotax_resolve_name_service_names(&mut self) -> Examples { + let next_cursor = Some(ObjectID::new(self.rng.gen())); + let object_id = ObjectID::new(self.rng.gen()); + let result = Page { + data: vec!["example.iota".to_string()], + next_cursor, + has_next_page: false, + }; + Examples::new( + "iotax_resolveNameServiceNames", + vec![ExamplePairing::new( + "Returns the IotaNS name for the address the request provides. Currently, the API returns only the first name in cases where there are multiple. Future support will use the cursor ID and limit values in the request to control pagination of the response for addresses with multiple names.", + vec![ + ("address", json!(object_id)), + ("cursor", json!(next_cursor)), + ("limit", json!(3)), + ], + json!(result), + )], + ) + } + + fn iota_try_multi_get_past_objects(&mut self) -> Examples { + let object_id = ObjectID::new(self.rng.gen()); + let object_id2 = ObjectID::new(self.rng.gen()); + let version = SequenceNumber::from_u64(4); + let version2 = SequenceNumber::from_u64(12); + let objects = vec![ + IotaGetPastObjectRequest { object_id, version }, + IotaGetPastObjectRequest { + object_id: object_id2, + version: version2, + }, + ]; + let coin = GasCoin::new(object_id, 10000); + let coin2 = GasCoin::new(object_id, 20000); + let result = vec![ + IotaPastObjectResponse::VersionFound(IotaObjectData { + content: Some( + IotaParsedData::try_from_object( + coin.to_object(SequenceNumber::from_u64(1)), + GasCoin::layout(), + ) + .unwrap(), + ), + owner: Some(Owner::AddressOwner(IotaAddress::from(ObjectID::new( + self.rng.gen(), + )))), + previous_transaction: Some(TransactionDigest::new(self.rng.gen())), + storage_rebate: Some(100), + object_id, + version: SequenceNumber::from_u64(4), + digest: ObjectDigest::new(self.rng.gen()), + type_: Some(ObjectType::Struct(MoveObjectType::gas_coin())), + bcs: None, + display: None, + }), + IotaPastObjectResponse::VersionFound(IotaObjectData { + content: Some( + IotaParsedData::try_from_object( + coin2.to_object(SequenceNumber::from_u64(4)), + GasCoin::layout(), + ) + .unwrap(), + ), + owner: Some(Owner::AddressOwner(IotaAddress::from(ObjectID::new( + self.rng.gen(), + )))), + previous_transaction: Some(TransactionDigest::new(self.rng.gen())), + storage_rebate: Some(100), + object_id: object_id2, + version: version2, + digest: ObjectDigest::new(self.rng.gen()), + type_: Some(ObjectType::Struct(MoveObjectType::gas_coin())), + bcs: None, + display: None, + }), + ]; + + Examples::new( + "iota_tryMultiGetPastObjects", + vec![ExamplePairing::new( + "Gets Past Object data for a vector of objects.", + vec![ + ("past_objects", json!(objects)), + ("options", json!(IotaObjectDataOptions::full_content())), + ], + json!(result), + )], + ) + } +} diff --git a/crates/sui-open-rpc/src/generate_json_rpc_spec.rs b/crates/iota-open-rpc/src/generate_json_rpc_spec.rs similarity index 82% rename from crates/sui-open-rpc/src/generate_json_rpc_spec.rs rename to crates/iota-open-rpc/src/generate_json_rpc_spec.rs index 5de4ba73d39..e8a5f245308 100644 --- a/crates/sui-open-rpc/src/generate_json_rpc_spec.rs +++ b/crates/iota-open-rpc/src/generate_json_rpc_spec.rs @@ -1,19 +1,20 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fs::File, io::Write}; use clap::{Parser, ValueEnum}; -use pretty_assertions::assert_str_eq; // temporarily remove api ref content for indexer methods -// use sui_json_rpc::api::ExtendedApiOpenRpc; -use sui_json_rpc::coin_api::CoinReadApi; -use sui_json_rpc::{ - governance_api::GovernanceReadApi, read_api::ReadApi, sui_rpc_doc, +// use iota_json_rpc::api::ExtendedApiOpenRpc; +use iota_json_rpc::coin_api::CoinReadApi; +use iota_json_rpc::{ + governance_api::GovernanceReadApi, iota_rpc_doc, read_api::ReadApi, transaction_builder_api::TransactionBuilderApi, - transaction_execution_api::TransactionExecutionApi, SuiRpcModule, + transaction_execution_api::TransactionExecutionApi, IotaRpcModule, }; -use sui_json_rpc_api::{IndexerApiOpenRpc, MoveUtilsOpenRpc}; +use iota_json_rpc_api::{IndexerApiOpenRpc, MoveUtilsOpenRpc}; +use pretty_assertions::assert_str_eq; use crate::examples::RpcExampleProvider; @@ -28,8 +29,8 @@ enum Action { #[derive(Debug, Parser)] #[clap( - name = "Sui format generator", - about = "Trace serde (de)serialization to generate format descriptions for Sui types" + name = "Iota format generator", + about = "Trace serde (de)serialization to generate format descriptions for Iota types" )] struct Options { #[clap(value_enum, default_value = "Record", ignore_case = true)] @@ -45,7 +46,7 @@ const VERSION: &str = env!("CARGO_PKG_VERSION"); async fn main() { let options = Options::parse(); - let mut open_rpc = sui_rpc_doc(VERSION); + let mut open_rpc = iota_rpc_doc(VERSION); open_rpc.add_module(ReadApi::rpc_doc_module()); open_rpc.add_module(CoinReadApi::rpc_doc_module()); open_rpc.add_module(IndexerApiOpenRpc::module_doc()); diff --git a/crates/iota-open-rpc/src/lib.rs b/crates/iota-open-rpc/src/lib.rs new file mode 100644 index 00000000000..c1946a7d4f6 --- /dev/null +++ b/crates/iota-open-rpc/src/lib.rs @@ -0,0 +1,450 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +extern crate core; + +use std::collections::{btree_map::Entry::Occupied, BTreeMap, HashMap}; + +use schemars::{ + gen::{SchemaGenerator, SchemaSettings}, + schema::SchemaObject, + JsonSchema, +}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use versions::Versioning; + +/// OPEN-RPC documentation following the OpenRPC specification +/// The implementation is partial, only required fields and subset of optional +/// fields in the specification are implemented catered to Iota's need. +#[derive(Serialize, Deserialize, Clone)] +pub struct Project { + openrpc: String, + info: Info, + methods: Vec, + components: Components, + // Method routing for backward compatibility, not part of the open rpc spec. + #[serde(skip)] + pub method_routing: HashMap, +} + +impl Project { + pub fn new( + version: &str, + title: &str, + description: &str, + contact_name: &str, + url: &str, + email: &str, + license: &str, + license_url: &str, + ) -> Self { + let openrpc = "1.2.6".to_string(); + Self { + openrpc, + info: Info { + title: title.to_string(), + description: Some(description.to_string()), + contact: Some(Contact { + name: contact_name.to_string(), + url: Some(url.to_string()), + email: Some(email.to_string()), + }), + license: Some(License { + name: license.to_string(), + url: Some(license_url.to_string()), + }), + version: version.to_owned(), + ..Default::default() + }, + methods: vec![], + components: Components { + content_descriptors: Default::default(), + schemas: Default::default(), + }, + method_routing: Default::default(), + } + } + + pub fn add_module(&mut self, module: Module) { + self.methods.extend(module.methods); + + self.methods.sort_by(|m, n| m.name.cmp(&n.name)); + + self.components.schemas.extend(module.components.schemas); + self.components + .content_descriptors + .extend(module.components.content_descriptors); + self.method_routing.extend(module.method_routing); + } + + pub fn add_examples(&mut self, mut example_provider: BTreeMap>) { + for method in &mut self.methods { + if let Occupied(entry) = example_provider.entry(method.name.clone()) { + let examples = entry.remove(); + let param_names = method + .params + .iter() + .map(|p| p.name.clone()) + .collect::>(); + + // Make sure example's parameters are correct. + for example in examples.iter() { + let example_param_names = example + .params + .iter() + .map(|param| param.name.clone()) + .collect::>(); + assert_eq!( + param_names, example_param_names, + "Provided example parameters doesn't match the function parameters." + ); + } + + method.examples = examples + } else { + println!("No example found for method: {}", method.name); + } + } + } +} + +pub struct Module { + methods: Vec, + components: Components, + method_routing: BTreeMap, +} + +pub struct RpcModuleDocBuilder { + schema_generator: SchemaGenerator, + methods: BTreeMap, + method_routing: BTreeMap, + content_descriptors: BTreeMap, +} + +#[derive(Serialize, Deserialize, Default, Clone)] +pub struct ContentDescriptor { + name: String, + #[serde(skip_serializing_if = "Option::is_none")] + summary: Option, + #[serde(skip_serializing_if = "Option::is_none")] + description: Option, + #[serde(skip_serializing_if = "default")] + required: bool, + schema: SchemaObject, + #[serde(skip_serializing_if = "default")] + deprecated: bool, +} + +#[derive(Serialize, Deserialize, Default, Clone)] +struct Method { + name: String, + #[serde(skip_serializing_if = "Vec::is_empty")] + tags: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + description: Option, + params: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + result: Option, + #[serde(skip_serializing_if = "Vec::is_empty")] + examples: Vec, + #[serde(skip_serializing_if = "std::ops::Not::not")] + deprecated: bool, +} +#[derive(Clone, Debug)] +pub struct MethodRouting { + min: Option, + max: Option, + pub route_to: String, +} + +impl MethodRouting { + pub fn le(version: &str, route_to: &str) -> Self { + Self { + min: None, + max: Some(Versioning::new(version).unwrap()), + route_to: route_to.to_string(), + } + } + + pub fn eq(version: &str, route_to: &str) -> Self { + Self { + min: Some(Versioning::new(version).unwrap()), + max: Some(Versioning::new(version).unwrap()), + route_to: route_to.to_string(), + } + } + + pub fn matches(&self, version: &str) -> bool { + let version = Versioning::new(version); + match (&version, &self.min, &self.max) { + (Some(version), None, Some(max)) => version <= max, + (Some(version), Some(min), None) => version >= min, + (Some(version), Some(min), Some(max)) => version >= min && version <= max, + (_, _, _) => false, + } + } +} + +#[test] +fn test_version_matching() { + let routing = MethodRouting::eq("1.5", "test"); + assert!(routing.matches("1.5")); + assert!(!routing.matches("1.6")); + assert!(!routing.matches("1.4")); + + let routing = MethodRouting::le("1.5", "test"); + assert!(routing.matches("1.5")); + assert!(routing.matches("1.4.5")); + assert!(routing.matches("1.4")); + assert!(routing.matches("1.3")); + + assert!(!routing.matches("1.6")); + assert!(!routing.matches("1.5.1")); +} + +#[derive(Serialize, Deserialize, Default, Clone)] +pub struct ExamplePairing { + name: String, + #[serde(skip_serializing_if = "Option::is_none")] + description: Option, + #[serde(skip_serializing_if = "Option::is_none")] + summary: Option, + params: Vec, + result: Example, +} + +impl ExamplePairing { + pub fn new(name: &str, params: Vec<(&str, Value)>, result: Value) -> Self { + Self { + name: name.to_string(), + description: None, + summary: None, + params: params + .into_iter() + .map(|(name, value)| Example { + name: name.to_string(), + summary: None, + description: None, + value, + }) + .collect(), + result: Example { + name: "Result".to_string(), + summary: None, + description: None, + value: result, + }, + } + } +} + +#[derive(Serialize, Deserialize, Default, Clone)] +pub struct Example { + name: String, + #[serde(skip_serializing_if = "Option::is_none")] + summary: Option, + #[serde(skip_serializing_if = "Option::is_none")] + description: Option, + value: Value, +} + +#[derive(Serialize, Deserialize, Default, Clone)] +struct Tag { + name: String, + #[serde(skip_serializing_if = "Option::is_none")] + summary: Option, + #[serde(skip_serializing_if = "Option::is_none")] + description: Option, +} + +impl Tag { + pub fn new(name: &str) -> Self { + Self { + name: name.to_string(), + summary: None, + description: None, + } + } +} + +#[derive(Serialize, Deserialize, Default, Clone)] +#[serde(rename_all = "camelCase")] +struct Info { + title: String, + #[serde(skip_serializing_if = "Option::is_none")] + description: Option, + #[serde(skip_serializing_if = "Option::is_none")] + terms_of_service: Option, + #[serde(skip_serializing_if = "Option::is_none")] + contact: Option, + #[serde(skip_serializing_if = "Option::is_none")] + license: Option, + version: String, +} + +fn default(value: &T) -> bool +where + T: Default + PartialEq, +{ + value == &T::default() +} + +#[derive(Serialize, Deserialize, Default, Clone)] +struct Contact { + name: String, + #[serde(skip_serializing_if = "Option::is_none")] + url: Option, + #[serde(skip_serializing_if = "Option::is_none")] + email: Option, +} +#[derive(Serialize, Deserialize, Default, Clone)] +struct License { + name: String, + #[serde(skip_serializing_if = "Option::is_none")] + url: Option, +} + +impl Default for RpcModuleDocBuilder { + fn default() -> Self { + let schema_generator = SchemaSettings::default() + .with(|s| { + s.definitions_path = "#/components/schemas/".to_string(); + }) + .into_generator(); + + Self { + schema_generator, + methods: BTreeMap::new(), + method_routing: Default::default(), + content_descriptors: BTreeMap::new(), + } + } +} + +impl RpcModuleDocBuilder { + pub fn build(mut self) -> Module { + Module { + methods: self.methods.into_values().collect(), + components: Components { + content_descriptors: self.content_descriptors, + schemas: self + .schema_generator + .root_schema_for::() + .definitions + .into_iter() + .map(|(name, schema)| (name, schema.into_object())) + .collect::>(), + }, + method_routing: self.method_routing, + } + } + + pub fn add_method_routing( + &mut self, + namespace: &str, + name: &str, + route_to: &str, + comparator: &str, + version: &str, + ) { + let name = format!("{namespace}_{name}"); + let route_to = format!("{namespace}_{route_to}"); + let routing = match comparator { + "<=" => MethodRouting::le(version, &route_to), + "=" => MethodRouting::eq(version, &route_to), + _ => panic!("Unsupported version comparator {comparator}"), + }; + if self.method_routing.insert(name.clone(), routing).is_some() { + panic!("Routing for method [{name}] already exists.") + } + } + + pub fn add_method( + &mut self, + namespace: &str, + name: &str, + params: Vec, + result: Option, + doc: &str, + tag: Option, + deprecated: bool, + ) { + let tags = tag.map(|t| Tag::new(&t)).into_iter().collect::>(); + self.add_method_internal(namespace, name, params, result, doc, tags, deprecated) + } + + pub fn add_subscription( + &mut self, + namespace: &str, + name: &str, + params: Vec, + result: Option, + doc: &str, + tag: Option, + deprecated: bool, + ) { + let mut tags = tag.map(|t| Tag::new(&t)).into_iter().collect::>(); + tags.push(Tag::new("Websocket")); + tags.push(Tag::new("PubSub")); + self.add_method_internal(namespace, name, params, result, doc, tags, deprecated) + } + + fn add_method_internal( + &mut self, + namespace: &str, + name: &str, + params: Vec, + result: Option, + doc: &str, + tags: Vec, + deprecated: bool, + ) { + let description = if doc.trim().is_empty() { + None + } else { + Some(doc.trim().to_string()) + }; + let name = format!("{}_{}", namespace, name); + self.methods.insert( + name.clone(), + Method { + name, + description, + params, + result, + tags, + examples: Vec::new(), + deprecated, + }, + ); + } + + pub fn create_content_descriptor( + &mut self, + name: &str, + summary: Option, + description: Option, + required: bool, + ) -> ContentDescriptor { + let schema = self.schema_generator.subschema_for::().into_object(); + ContentDescriptor { + name: name.replace(' ', ""), + summary, + description, + required, + schema, + deprecated: false, + } + } +} + +#[derive(Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +struct Components { + #[serde(skip_serializing_if = "BTreeMap::is_empty")] + content_descriptors: BTreeMap, + #[serde(skip_serializing_if = "BTreeMap::is_empty")] + schemas: BTreeMap, +} diff --git a/crates/sui-open-rpc/tests/generate-spec.rs b/crates/iota-open-rpc/tests/generate-spec.rs similarity index 94% rename from crates/sui-open-rpc/tests/generate-spec.rs rename to crates/iota-open-rpc/tests/generate-spec.rs index 88be94a828b..c16054725c6 100644 --- a/crates/sui-open-rpc/tests/generate-spec.rs +++ b/crates/iota-open-rpc/tests/generate-spec.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[test] diff --git a/crates/iota-oracle/Cargo.toml b/crates/iota-oracle/Cargo.toml new file mode 100644 index 00000000000..acdc1829f49 --- /dev/null +++ b/crates/iota-oracle/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "iota-oracle" +version.workspace = true +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow = { version = "1.0.64", features = ["backtrace"] } +clap.workspace = true +prometheus = "0.13.3" +tokio = { workspace = true, features = ["full"] } +tracing = "0.1.36" +once_cell.workspace = true +reqwest = { version = "0.11.13", default_features = false, features = ["blocking", "json", "rustls-tls"] } +serde = { version = "1.0.144", features = ["derive", "rc"] } +serde_json = { version = "1.0.1" } +jsonpath_lib = "0.3.0" +chrono.workspace = true +tap.workspace = true +bcs.workspace = true + +iota-config = { path = "../iota-config" } +iota-json-rpc-types = { path = "../iota-json-rpc-types" } +iota-sdk = { path = "../iota-sdk" } +iota-types = { path = "../iota-types" } +mysten-metrics = { path = "../mysten-metrics" } +telemetry-subscribers.workspace = true + +[dev-dependencies] +iota-keys = { path = "../iota-keys" } +iota-move-build = { path = "../iota-move-build" } +shared-crypto = { path = "../shared-crypto" } +bcs = "0.1.5" +rand = "0.8.5" +dirs = "4.0.0" diff --git a/crates/iota-oracle/README.md b/crates/iota-oracle/README.md new file mode 100644 index 00000000000..71e58235724 --- /dev/null +++ b/crates/iota-oracle/README.md @@ -0,0 +1,7 @@ +# iota-oracle + +This oracle is intended to serve as general reference and informational purposes only. We make no representations or warranties of any kind, express or implied, about the completeness, accuracy, reliability, iotatability, or availability of the information provided by the oracle. + +Any reliance on such information by a user is strictly at the user’s own risk. We do not assume any responsibility for errors, omissions, or inaccuracies in the information and shall not be liable for any loss or damage arising from or related to its use. + +The information provided through this oracle does not constitute professional, investment or legal advice. diff --git a/crates/iota-oracle/move/oracle/Move.toml b/crates/iota-oracle/move/oracle/Move.toml new file mode 100644 index 00000000000..336b8c285d2 --- /dev/null +++ b/crates/iota-oracle/move/oracle/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "iota-oracle" +version = "0.0.1" + +[dependencies] +Iota = { git = "https://github.com/iotaledger/iota.git", subdir = "crates/iota-framework/packages/iota-framework", rev = "9d0fba4a490e1cf80101bbd4019c7bb1ccfce99b" } + +[addresses] +oracle = "0x0" +iota = "0x2" \ No newline at end of file diff --git a/crates/iota-oracle/move/oracle/sources/data.move b/crates/iota-oracle/move/oracle/sources/data.move new file mode 100644 index 00000000000..baf0d7312a6 --- /dev/null +++ b/crates/iota-oracle/move/oracle/sources/data.move @@ -0,0 +1,53 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module oracle::data { + use std::string::String; + + struct Data has drop, copy { + value: T, + metadata: Metadata, + } + + struct Metadata has drop, copy { + ticker: String, + sequence_number: u64, + timestamp: u64, + oracle: address, + /// An identifier for the reading (for example real time of observation, or sequence number of observation on other chain). + identifier: String, + } + + public fun new( + value: T, + ticker: String, + sequence_number: u64, + timestamp: u64, + oracle: address, + identifier: String + ): Data { + Data { + value, + metadata: Metadata { + ticker, + sequence_number, + timestamp, + oracle, + identifier, + }, + } + } + + public fun value(data: &Data): &T { + &data.value + } + + public fun oracle_address(data: &Data): &address { + &data.metadata.oracle + } + + public fun timestamp(data: &Data): u64 { + data.metadata.timestamp + } +} diff --git a/crates/sui-oracle/move/oracle/sources/decimal_value.move b/crates/iota-oracle/move/oracle/sources/decimal_value.move similarity index 90% rename from crates/sui-oracle/move/oracle/sources/decimal_value.move rename to crates/iota-oracle/move/oracle/sources/decimal_value.move index 53229535397..b428a8d0840 100644 --- a/crates/sui-oracle/move/oracle/sources/decimal_value.move +++ b/crates/iota-oracle/move/oracle/sources/decimal_value.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module oracle::decimal_value { diff --git a/crates/sui-oracle/move/oracle/sources/meta_oracle.move b/crates/iota-oracle/move/oracle/sources/meta_oracle.move similarity index 99% rename from crates/sui-oracle/move/oracle/sources/meta_oracle.move rename to crates/iota-oracle/move/oracle/sources/meta_oracle.move index 0d027c53549..badde6065cc 100644 --- a/crates/sui-oracle/move/oracle/sources/meta_oracle.move +++ b/crates/iota-oracle/move/oracle/sources/meta_oracle.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module oracle::meta_oracle { @@ -10,8 +11,8 @@ module oracle::meta_oracle { use oracle::data::{Self, Data}; use oracle::decimal_value::DecimalValue; use oracle::simple_oracle::SimpleOracle; - use sui::bcs; - use sui::math; + use iota::bcs; + use iota::math; #[test_only] use oracle::decimal_value; diff --git a/crates/sui-oracle/move/oracle/sources/simple_oracle.move b/crates/iota-oracle/move/oracle/sources/simple_oracle.move similarity index 93% rename from crates/sui-oracle/move/oracle/sources/simple_oracle.move rename to crates/iota-oracle/move/oracle/sources/simple_oracle.move index f3c110eb263..4d7c1f7f78c 100644 --- a/crates/sui-oracle/move/oracle/sources/simple_oracle.move +++ b/crates/iota-oracle/move/oracle/sources/simple_oracle.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module oracle::simple_oracle { @@ -7,13 +8,13 @@ module oracle::simple_oracle { use std::string::String; use oracle::data::{Self, Data}; - use sui::clock::{Self, Clock}; - use sui::dynamic_field as df; - use sui::object::{Self, UID}; - use sui::table; - use sui::table::Table; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; + use iota::clock::{Self, Clock}; + use iota::dynamic_field as df; + use iota::object::{Self, UID}; + use iota::table; + use iota::table::Table; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; const ESenderNotOracle: u64 = 0; const ETickerNotExists: u64 = 1; diff --git a/crates/iota-oracle/src/config.rs b/crates/iota-oracle/src/config.rs new file mode 100644 index 00000000000..ba3b58f310e --- /dev/null +++ b/crates/iota-oracle/src/config.rs @@ -0,0 +1,58 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::HashMap, net::SocketAddr, time::Duration}; + +use iota_config::Config; +use iota_types::base_types::ObjectID; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct DataSourceConfig { + pub url: String, + pub json_path: String, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct UploadFeedConfig { + pub submission_interval: Duration, + pub data_source_config: DataSourceConfig, + pub upload_parameters: UploadParameters, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct UploadParameters { + pub write_package_id: ObjectID, + pub write_module_name: String, + pub write_function_name: String, + pub write_data_provider_object_id: ObjectID, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct DownloadFeedConfigs { + pub read_interval: Option, + pub read_feeds: HashMap, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct OracleNodeConfig { + pub gas_object_id: ObjectID, + pub upload_feeds: HashMap>, + pub download_feeds: DownloadFeedConfigs, + + #[serde(default = "default_metrics_address")] + pub metrics_address: SocketAddr, +} + +fn default_metrics_address() -> SocketAddr { + use std::net::{IpAddr, Ipv4Addr}; + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9400) +} + +impl Config for OracleNodeConfig {} diff --git a/crates/iota-oracle/src/lib.rs b/crates/iota-oracle/src/lib.rs new file mode 100644 index 00000000000..63ab94b5e72 --- /dev/null +++ b/crates/iota-oracle/src/lib.rs @@ -0,0 +1,711 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::HashMap, + ops::Add, + str::FromStr, + sync::Arc, + time::{Duration, Instant, SystemTime}, +}; + +use chrono::{DateTime, Utc}; +use config::{DownloadFeedConfigs, UploadFeedConfig, UploadParameters}; +use iota_json_rpc_types::{ + IotaObjectDataOptions, IotaTransactionBlockEffects, IotaTransactionBlockEffectsAPI, + IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, +}; +use iota_sdk::{ + apis::ReadApi, rpc_types::IotaObjectResponse, wallet_context::WalletContext, IotaClient, +}; +use iota_types::{ + base_types::{random_object_ref, IotaAddress, ObjectID, ObjectRef}, + error::UserInputError, + object::{Object, Owner}, + parse_iota_type_tag, + programmable_transaction_builder::ProgrammableTransactionBuilder, + quorum_driver_types::NON_RECOVERABLE_ERROR_MSG, + transaction::{Argument, CallArg, Command, ObjectArg, Transaction, TransactionData}, + Identifier, +}; +use metrics::OracleMetrics; +use mysten_metrics::monitored_scope; +use once_cell::sync::OnceCell; +use prometheus::Registry; +use tap::tap::TapFallible; +use tracing::{debug, error, info, warn}; +pub mod config; +mod metrics; + +// TODO: allow more flexible decimals +const DECIMAL: u8 = 6; +const METRICS_MULTIPLIER: f64 = 10u64.pow(DECIMAL as u32) as f64; +const UPLOAD_FAILURE_RECOVER_SEC: u64 = 10; +static STALE_OBJ_ERROR: OnceCell = OnceCell::new(); + +pub struct OracleNode { + upload_feeds: HashMap>, + gas_obj_id: ObjectID, + download_feeds: DownloadFeedConfigs, + wallet_ctx: WalletContext, + metrics: Arc, +} + +impl OracleNode { + pub fn new( + upload_feeds: HashMap>, + gas_obj_id: ObjectID, + download_feeds: DownloadFeedConfigs, + wallet_ctx: WalletContext, + registry: Registry, + ) -> Self { + Self { + upload_feeds, + gas_obj_id, + download_feeds, + wallet_ctx, + metrics: Arc::new(OracleMetrics::new(®istry)), + } + } + + pub async fn run(mut self) -> anyhow::Result<()> { + info!("Starting OracleNode..."); + let signer_address = self.wallet_ctx.active_address()?; + let client = Arc::new(self.wallet_ctx.get_client().await?); + + let wallet_ctx = Arc::new(self.wallet_ctx); + DataProviderRunner::new( + self.upload_feeds, + self.gas_obj_id, + wallet_ctx, + client.clone(), + signer_address, + self.metrics.clone(), + ) + .await + .spawn(); + + let (sender, mut receiver) = tokio::sync::mpsc::channel(1000); + + // Spawn a reader thread if reader_interval is configured. + if let Some(read_interval) = self.download_feeds.read_interval { + tokio::spawn( + OnChainDataReader { + client: client.clone(), + read_interval, + read_configs: self.download_feeds.read_feeds, + metrics: self.metrics.clone(), + } + .start(sender.clone()), + ); + } + + while let Some((read_feed, object_id, value)) = receiver.recv().await { + info!( + read_feed, + ?object_id, + ?value, + "Received data from on chain reader." + ); + } + + Ok(()) + } +} + +struct DataProviderRunner { + providers: Vec>, + uploader: OnChainDataUploader, +} + +impl DataProviderRunner { + pub async fn new( + upload_feeds: HashMap>, + gas_coin_id: ObjectID, + wallet_ctx: Arc, + client: Arc, + signer_address: IotaAddress, + metrics: Arc, + ) -> Self { + let mut providers = vec![]; + let mut staleness_tolerance = HashMap::new(); + let mut oracle_object_args = HashMap::new(); + let (sender, receiver) = tokio::sync::mpsc::channel(10000); + for (feed_name, upload_feed) in upload_feeds { + for (source_name, data_feed) in upload_feed { + staleness_tolerance.insert( + make_onchain_feed_name(&feed_name, &source_name), + data_feed.submission_interval, + ); + let oracle_obj_id = data_feed.upload_parameters.write_data_provider_object_id; + let data_provider = DataProvider { + feed_name: feed_name.clone(), + source_name: source_name.clone(), + upload_feed: Arc::new(data_feed), + sender: sender.clone(), + metrics: metrics.clone(), + }; + providers.push(Arc::new(data_provider)); + if let std::collections::hash_map::Entry::Vacant(e) = + oracle_object_args.entry(oracle_obj_id) + { + e.insert( + get_object_arg(client.read_api(), oracle_obj_id, true) + .await + .unwrap(), + ); + } + } + } + info!("Staleness tolerance: {:?}", staleness_tolerance); + + let gas_obj_ref = get_gas_obj_ref(client.read_api(), gas_coin_id, signer_address).await; + info!("Gas object: {:?}", gas_obj_ref); + + let uploader = OnChainDataUploader { + wallet_ctx: wallet_ctx.clone(), + client: client.clone(), + receiver, + signer_address, + gas_obj_ref, + staleness_tolerance, + oracle_object_args, + metrics: metrics.clone(), + }; + Self { + providers, + uploader, + } + } + + pub fn spawn(mut self) { + for data_provider in self.providers { + tokio::spawn(async move { + data_provider.run().await; + }); + } + tokio::spawn(async move { + self.uploader.run().await; + }); + } +} + +async fn get_gas_obj_ref( + read_api: &ReadApi, + gas_obj_id: ObjectID, + owner_address: IotaAddress, +) -> ObjectRef { + loop { + match read_api + .get_object_with_options(gas_obj_id, IotaObjectDataOptions::default().with_owner()) + .await + .map(|resp| resp.data) + { + Ok(Some(gas_obj)) => { + assert_eq!( + gas_obj.owner, + Some(Owner::AddressOwner(owner_address)), + "Provided gas obj {:?} does not belong to {}", + gas_obj, + owner_address + ); + return gas_obj.object_ref(); + } + other => { + warn!("Can't get gas object: {:?}: {:?}", gas_obj_id, other); + tokio::time::sleep(Duration::from_secs(5)).await; + } + } + } +} + +struct DataProvider { + pub feed_name: String, + pub source_name: String, + pub upload_feed: Arc, + pub sender: tokio::sync::mpsc::Sender, + metrics: Arc, +} + +impl DataProvider { + pub async fn run(&self) { + info!( + feed_name = self.feed_name, + source_name = self.source_name, + "Starting DataProvider" + ); + let mut interval = tokio::time::interval(self.upload_feed.submission_interval); + interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); + + loop { + interval.tick().await; + self.run_once().await; + } + } + + async fn run_once(&self) { + debug!( + feed_name = self.feed_name, + source_name = self.source_name, + "Running data provider once." + ); + let value = self.retrieve_from_data_source().await; + if value.is_err() { + error!( + feed_name = self.feed_name, + source_name = self.source_name, + "Failed to retrieve data from data source: {:?}", + value + ); + self.metrics + .data_source_errors + .with_label_values(&[&self.feed_name, &self.source_name]) + .inc(); + return; + } + + self.metrics + .data_source_successes + .with_label_values(&[&self.feed_name, &self.source_name]) + .inc(); + + // TODO: allow more flexible multiplers and data types + let value = (value.unwrap() * METRICS_MULTIPLIER) as u64; + self.send_to_uploader(value).await; + } + + async fn retrieve_from_data_source(&self) -> anyhow::Result { + // TODO: support websocket + let url = &self.upload_feed.data_source_config.url; + let json_path = &self.upload_feed.data_source_config.json_path; + let response = reqwest::Client::new().get(url).send().await?; + + if !response.status().is_success() { + anyhow::bail!("Failed to fetch data: {:?}", response); + } + + let json_blob: serde_json::Value = response.json().await.unwrap(); + let data = jsonpath_lib::select(&json_blob, json_path)?; + + if data.is_empty() { + anyhow::bail!( + "Failed to find data from json blob: {:?} with json path: {:?}", + json_blob, + json_path + ); + } + // Assume there is one single value per request + match data[0].as_str() { + Some(value_str) => match value_str.parse::() { + Ok(value) => Ok(value), + Err(_) => anyhow::bail!( + "Failed to parse data {:?} as f64 from json blob: {:?}", + data[0], + json_blob + ), + }, + None => anyhow::bail!( + "Failed to parse data {:?} as string from json blob: {:?}", + data[0], + json_blob + ), + } + } + + async fn send_to_uploader(&self, value: u64) { + let _ = self + .sender + .send(DataPoint { + feed_name: make_onchain_feed_name(&self.feed_name, &self.source_name), + upload_parameters: self.upload_feed.upload_parameters.clone(), + value, + retrieval_timestamp: SystemTime::now(), + retrieval_instant: Instant::now(), + }) + .await + .tap_err(|err| error!("Failed to send data point to uploader: {:?}", err)); + } +} + +fn make_onchain_feed_name(feed_name: &str, source_name: &str) -> String { + format!( + "{}-{}", + feed_name.to_ascii_lowercase(), + source_name.to_ascii_lowercase() + ) +} + +struct OnChainDataUploader { + wallet_ctx: Arc, + client: Arc, + receiver: tokio::sync::mpsc::Receiver, + signer_address: IotaAddress, + gas_obj_ref: ObjectRef, + staleness_tolerance: HashMap, + oracle_object_args: HashMap, + metrics: Arc, +} + +impl OnChainDataUploader { + async fn run(&mut self) { + info!("Starting OnChainDataUploader"); + // The minimal latency is 1 second so we collect data every 1 second + let mut read_interval = tokio::time::interval(Duration::from_millis(500)); + read_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); + loop { + read_interval.tick().await; + let data_points = self.collect().await; + if !data_points.is_empty() { + if let Err(err) = self.upload(data_points).await { + error!( + "Upload failure: {err}. About to resting for {UPLOAD_FAILURE_RECOVER_SEC} sec." + ); + tokio::time::sleep(Duration::from_secs(UPLOAD_FAILURE_RECOVER_SEC)).await; + self.gas_obj_ref = get_gas_obj_ref( + self.client.read_api(), + self.gas_obj_ref.0, + self.signer_address, + ) + .await; + error!("Updated gas object reference: {:?}", self.gas_obj_ref); + } + } + } + } + + async fn collect(&mut self) -> Vec { + let start = Instant::now(); + let mut data_points = vec![]; + while let Ok(Some(data_point)) = + tokio::time::timeout(Duration::from_millis(100), self.receiver.recv()).await + { + let feed_name = &data_point.feed_name; + debug!( + feed_name = data_point.feed_name, + value = data_point.value, + "Received data from data provider." + ); + // TODO: for each source, at most take one value in each submission + let staleness_tolerance = + self.staleness_tolerance.get(feed_name).unwrap_or_else(|| { + panic!("Bug, missing staleness tolerance for feed: {}", feed_name) + }); + let duration_since = data_point.retrieval_instant.elapsed(); + if duration_since > staleness_tolerance.add(Duration::from_secs(1)) { + warn!( + feed_name, + value = data_point.value, + ?duration_since, + ?staleness_tolerance, + "Data is too stale, skipping." + ); + self.metrics + .data_staleness + .with_label_values(&[feed_name]) + .inc(); + } else { + data_points.push(data_point); + } + + // One run only waits for 1 second + // But if we don't have any valid data points, we wait until we do. + if data_points.is_empty() && start.elapsed() >= Duration::from_millis(500) { + break; + } + } + debug!("Collected {} data points", data_points.len()); + data_points + } + + async fn upload( + &mut self, + data_points: Vec, + ) -> anyhow::Result { + let _scope = monitored_scope("Oracle::OnChainDataUploader::upload"); + // TODO add more error handling & polling perhaps + let mut builder = ProgrammableTransactionBuilder::new(); + let mut is_first = true; + for data_point in &data_points { + let package_id = data_point.upload_parameters.write_package_id; + let feed_name = &data_point.feed_name; + let oracle_obj_arg = *self + .oracle_object_args + .get(&data_point.upload_parameters.write_data_provider_object_id) + .unwrap_or_else(|| { + panic!("Bug, missing oracle object arg for feed: {}", feed_name) + }); + let duration_since_start = data_point.retrieval_instant.elapsed(); + let data_point_ts: DateTime = + DateTime::from(data_point.retrieval_timestamp + duration_since_start); + + let mut arguments = if is_first { + vec![ + builder.input(CallArg::Object(oracle_obj_arg)).unwrap(), + builder.input(CallArg::CLOCK_IMM).unwrap(), + ] + } else { + vec![Argument::Input(0), Argument::Input(1)] + }; + + let decimal = builder + .input(CallArg::Pure(bcs::to_bytes(&DECIMAL).unwrap())) + .unwrap(); + let value = builder + .input(CallArg::Pure(bcs::to_bytes(&data_point.value).unwrap())) + .unwrap(); + + arguments.extend_from_slice(&[ + builder + .input(CallArg::Pure(bcs::to_bytes(&feed_name)?)) + .unwrap(), + builder.programmable_move_call( + package_id, + Identifier::from_str("decimal_value").unwrap(), + Identifier::from_str("new").unwrap(), + vec![], + vec![value, decimal], + ), + builder + .input(CallArg::Pure(bcs::to_bytes(&format!("{}", data_point_ts))?)) + .unwrap(), + ]); + + builder.command(Command::move_call( + package_id, + Identifier::new(data_point.upload_parameters.write_module_name.clone()).unwrap(), + Identifier::new(data_point.upload_parameters.write_function_name.clone()).unwrap(), + // TODO: allow more generic data types + vec![ + parse_iota_type_tag(&format!("{package_id}::decimal_value::DecimalValue")) + .unwrap(), + ], + arguments, + )); + is_first = false; + } + let pt = builder.finish(); + let rgp = self + .client + .governance_api() + .get_reference_gas_price() + .await?; + let tx = TransactionData::new_programmable( + self.signer_address, + vec![self.gas_obj_ref], + pt, + // 15_000_000 is a heuristic number + 15_000_000 * data_points.len() as u64, + rgp, + ); + + let signed_tx = self.wallet_ctx.sign_transaction(&tx); + let tx_digest = *signed_tx.digest(); + + let timer_start = Instant::now(); + let response = self.execute(signed_tx).await?; + let time_spend_sec = timer_start.elapsed().as_secs_f32(); + + // We asked for effects. + // But is there a better way to handle this instead of panic? + let effects = response.effects.expect("Expect to see effects in response"); + + // It's critical to update the gas object reference for next transaction + self.gas_obj_ref = effects.gas_object().reference.to_object_ref(); + + let success = effects.status().is_ok(); + + // Update metrics + for data_point in &data_points { + if success { + self.metrics + .upload_successes + .with_label_values(&[&data_point.feed_name]) + .inc(); + self.metrics + .uploaded_values + .with_label_values(&[&data_point.feed_name]) + .observe(data_point.value); + } else { + self.metrics + .upload_data_errors + .with_label_values(&[&data_point.feed_name]) + .inc(); + } + } + + let gas_usage = effects.gas_cost_summary().gas_used(); + let storage_rebate = effects.gas_cost_summary().storage_rebate; + let computation_cost = effects.gas_cost_summary().computation_cost; + let net_gas_usage = effects.gas_cost_summary().net_gas_usage(); + self.metrics.computation_gas_used.observe(computation_cost); + self.metrics.total_gas_cost.inc_by(gas_usage); + self.metrics.total_gas_rebate.inc_by(storage_rebate); + + if success { + self.metrics + .total_data_points_uploaded + .inc_by(data_points.len() as u64); + info!( + ?tx_digest, + net_gas_usage, + time_spend_sec, + "Upload succeeded with {} data points", + data_points.len(), + ); + Ok(effects) + } else { + error!( + ?tx_digest, + net_gas_usage, + "Upload failed with {} data points. Err: {:?}", + data_points.len(), + effects.status(), + ); + anyhow::bail!("Failed to submit data on chain: {:?}", effects.status()); + } + } + + async fn execute(&mut self, tx: Transaction) -> anyhow::Result { + let tx_digest = tx.digest(); + let mut retry_attempts = 3; + loop { + match self + .client + .quorum_driver_api() + .execute_transaction_block( + tx.clone(), + IotaTransactionBlockResponseOptions::new().with_effects(), + // TODO: after 1.4.0, we can simply use `WaitForEffectsCert` which is faster. + // Some(iota_types::quorum_driver_types::ExecuteTransactionRequestType::WaitForEffectsCert), + Some(iota_types::quorum_driver_types::ExecuteTransactionRequestType::WaitForLocalExecution), + ) + .await { + Ok(response) => return Ok(response), + Err(iota_sdk::error::Error::RpcError(err)) => { + // jsonrpsee translate every IotaError into jsonrpsee::core::Error, so we need to further distinguish + if err.to_string().contains(NON_RECOVERABLE_ERROR_MSG) { + let stale_obj_error = STALE_OBJ_ERROR + .get_or_init(|| + String::from(UserInputError::ObjectVersionUnavailableForConsumption { provided_obj_ref: random_object_ref(), current_version: 0.into() }.as_ref()) + ); + if err.to_string().contains(stale_obj_error) { + error!(?tx_digest, "Failed to submit tx, it looks like gas object is stale : {:?}", err); + let new_ref = get_gas_obj_ref(self.client.read_api(), self.gas_obj_ref.0, self.signer_address).await; + self.gas_obj_ref = new_ref; + info!("Gas object updated: {:?}", new_ref); + anyhow::bail!("Gas object is stale, now updated to {:?}. tx_digest={:?}", new_ref, tx_digest); + } else { + error!(?tx_digest, "Failed to submit tx, with non recoverable error: {:?}", err); + anyhow::bail!("Non-retryable error {:?}. tx_digest={:?}", err, tx_digest); + } + } + // Likely retryable error? + error!(?tx_digest, "Failed to submit tx, with (likely) recoverable error: {:?}. Remaining retry times: {}", err, retry_attempts); + retry_attempts -= 1; + if retry_attempts <= 0 { + anyhow::bail!("Too many RPC errors: {}. tx_digest={:?}", err, tx_digest); + } + } + // All other errors are unexpected + Err(err) => { + error!(?tx_digest, "Failed to submit tx, with unexpected error: {:?}", err); + anyhow::bail!("Unexpected error in tx submission {:?}. tx_digest={:?}", err, tx_digest); + } + } + } + } +} + +#[derive(Debug)] +struct DataPoint { + feed_name: String, + upload_parameters: UploadParameters, + value: u64, + retrieval_timestamp: SystemTime, + retrieval_instant: Instant, +} + +struct OnChainDataReader { + pub client: Arc, + // For now we share one read interval for all reads + pub read_interval: Duration, + pub read_configs: HashMap, + metrics: Arc, +} + +impl OnChainDataReader { + pub async fn start(self, sender: tokio::sync::mpsc::Sender<(String, ObjectID, f64)>) { + info!( + "Starting on-chain data reader with interval {:?} and config: {:?}", + self.read_interval, self.read_configs + ); + let mut read_interval = tokio::time::interval(self.read_interval); + read_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); + loop { + read_interval.tick().await; + for (feed_name, object_id) in &self.read_configs { + match self + .client + .read_api() + .get_object_with_options(*object_id, IotaObjectDataOptions::default()) + .await + { + Ok(IotaObjectResponse { + data: Some(_data), .. + }) => { + // TODO parse value based on returned BCS + let value = 5_f64; + let _ = sender.send((feed_name.clone(), *object_id, value)).await; + self.metrics + .downloaded_values + .with_label_values(&[feed_name]) + .observe((value * METRICS_MULTIPLIER) as u64); + self.metrics + .download_successes + .with_label_values(&[feed_name, &object_id.to_string()]) + .inc(); + } + other => { + error!( + read_feed = feed_name, + ?object_id, + "Failed to read data from on-chain: {:?}", + other + ); + self.metrics + .download_data_errors + .with_label_values(&[feed_name, &object_id.to_string()]) + .inc(); + } + } + } + } + } +} + +async fn get_object_arg( + read_api: &ReadApi, + id: ObjectID, + is_mutable_ref: bool, +) -> anyhow::Result { + let response = read_api + .get_object_with_options(id, IotaObjectDataOptions::bcs_lossless()) + .await?; + + let obj: Object = response.into_object()?.try_into()?; + let obj_ref = obj.compute_object_reference(); + let owner = obj.owner; + Ok(match owner { + Owner::Shared { + initial_shared_version, + } => ObjectArg::SharedObject { + id, + initial_shared_version, + mutable: is_mutable_ref, + }, + Owner::AddressOwner(_) | Owner::ObjectOwner(_) | Owner::Immutable => { + ObjectArg::ImmOrOwnedObject(obj_ref) + } + }) +} diff --git a/crates/iota-oracle/src/main.rs b/crates/iota-oracle/src/main.rs new file mode 100644 index 00000000000..56e8fc78644 --- /dev/null +++ b/crates/iota-oracle/src/main.rs @@ -0,0 +1,57 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{path::PathBuf, time::Duration}; + +use clap::Parser; +use iota_config::Config; +use iota_oracle::{config::OracleNodeConfig, OracleNode}; +use iota_sdk::wallet_context::WalletContext; +use mysten_metrics::start_prometheus_server; + +#[derive(Parser)] +#[clap(rename_all = "kebab-case")] +#[clap(name = env!("CARGO_BIN_NAME"))] +struct Args { + #[clap(long)] + pub oracle_config_path: PathBuf, + #[clap(long)] + pub client_config_path: PathBuf, +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let args = Args::parse(); + + let config = OracleNodeConfig::load(&args.oracle_config_path)?; + + let wallet_ctx = WalletContext::new( + &args.client_config_path, + // TODO make this configurable + Some(Duration::from_secs(10)), // request times out after 10 secs + None, + )?; + + // Init metrics server + let registry_service = start_prometheus_server(config.metrics_address); + let prometheus_registry = registry_service.default_registry(); + + // Init logging + let (_guard, _filter_handle) = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .with_prom_registry(&prometheus_registry) + .init(); + + OracleNode::new( + config.upload_feeds, + config.gas_object_id, + config.download_feeds, + wallet_ctx, + prometheus_registry, + ) + .run() + .await?; + + Ok(()) +} diff --git a/crates/iota-oracle/src/metrics.rs b/crates/iota-oracle/src/metrics.rs new file mode 100644 index 00000000000..9bb165e690c --- /dev/null +++ b/crates/iota-oracle/src/metrics.rs @@ -0,0 +1,118 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use mysten_metrics::histogram::{Histogram, HistogramVec}; +use prometheus::{ + register_int_counter_vec_with_registry, register_int_counter_with_registry, IntCounter, + IntCounterVec, Registry, +}; + +#[derive(Clone)] +pub struct OracleMetrics { + pub(crate) data_source_successes: IntCounterVec, + pub(crate) data_source_errors: IntCounterVec, + pub(crate) data_staleness: IntCounterVec, + pub(crate) upload_successes: IntCounterVec, + pub(crate) upload_data_errors: IntCounterVec, + pub(crate) download_successes: IntCounterVec, + pub(crate) download_data_errors: IntCounterVec, + pub(crate) uploaded_values: HistogramVec, + pub(crate) downloaded_values: HistogramVec, + + pub(crate) total_gas_cost: IntCounter, + pub(crate) total_gas_rebate: IntCounter, + pub(crate) computation_gas_used: Histogram, + pub(crate) total_data_points_uploaded: IntCounter, +} + +impl OracleMetrics { + pub fn new(registry: &Registry) -> Self { + Self { + data_source_successes: register_int_counter_vec_with_registry!( + "oracle_data_source_successes", + "Total number of successful data retrieval requests to data sources", + &["feed", "source"], + registry, + ) + .unwrap(), + data_source_errors: register_int_counter_vec_with_registry!( + "oracle_data_source_errors", + "Total number of erroneous data retrieval requests to data sources", + &["feed", "source"], + registry, + ) + .unwrap(), + data_staleness: register_int_counter_vec_with_registry!( + "oracle_data_staleness", + "Total number of stale data that are skipped", + &["feed"], + registry, + ) + .unwrap(), + upload_successes: register_int_counter_vec_with_registry!( + "oracle_upload_successes", + "Total number of successful data upload", + &["feed"], + registry, + ) + .unwrap(), + upload_data_errors: register_int_counter_vec_with_registry!( + "oracle_upload_data_errors", + "Total number of erroneous data upload", + &["feed"], + registry, + ) + .unwrap(), + download_successes: register_int_counter_vec_with_registry!( + "oracle_download_successes", + "Total number of successful data download", + &["feed", "object_id"], + registry, + ) + .unwrap(), + download_data_errors: register_int_counter_vec_with_registry!( + "oracle_download_data_errors", + "Total number of erroneous data download", + &["feed", "object_id"], + registry, + ) + .unwrap(), + uploaded_values: HistogramVec::new_in_registry( + "oracle_uploaded_values", + "Values uploaded on chain", + &["feed"], + registry, + ), + downloaded_values: HistogramVec::new_in_registry( + "oracle_downloaded_values", + "Values downloaded on chain", + &["feed"], + registry, + ), + total_gas_cost: register_int_counter_with_registry!( + "oracle_total_gas_cost", + "Total number of gas used, before gas rebate", + registry, + ) + .unwrap(), + total_gas_rebate: register_int_counter_with_registry!( + "oracle_total_gas_rebate", + "Total number of gas rebate", + registry, + ) + .unwrap(), + computation_gas_used: Histogram::new_in_registry( + "oracle_computation_gas_used", + "computation gas used", + registry, + ), + total_data_points_uploaded: register_int_counter_with_registry!( + "oracle_total_data_points_uploaded", + "Total number of data points uploaded", + registry, + ) + .unwrap(), + } + } +} diff --git a/crates/iota-oracle/tests/data/Test/Move.toml b/crates/iota-oracle/tests/data/Test/Move.toml new file mode 100644 index 00000000000..185317862e8 --- /dev/null +++ b/crates/iota-oracle/tests/data/Test/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "test" +version = "0.0.1" + +[dependencies] +Iota = { git = "https://github.com/iotaledger/iota.git", subdir = "crates/iota-framework/packages/iota-framework", rev = "9d0fba4a490e1cf80101bbd4019c7bb1ccfce99b" } +iota-oracle = { local = "../../../move/oracle" } + +[addresses] +test = "0x0" +iota = "0x2" \ No newline at end of file diff --git a/crates/iota-oracle/tests/data/Test/sources/test_module.move b/crates/iota-oracle/tests/data/Test/sources/test_module.move new file mode 100644 index 00000000000..46d67cf4f5d --- /dev/null +++ b/crates/iota-oracle/tests/data/Test/sources/test_module.move @@ -0,0 +1,86 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module test::test_module { + + use std::option; + use std::option::Option; + use std::string; + + use oracle::data; + use oracle::data::Data; + use oracle::decimal_value; + use oracle::decimal_value::DecimalValue; + use oracle::meta_oracle; + use oracle::simple_oracle; + use oracle::simple_oracle::SimpleOracle; + use iota::object; + use iota::object::UID; + use iota::transfer; + use iota::tx_context; + use iota::tx_context::TxContext; + + struct MockUSD has key, store { + id: UID, + amount: u64, + decimals: u8, + } + + public fun simple_fx_ptb(single_data: Option>, micros_amount: u64, ctx: &mut TxContext) { + let single_data = option::destroy_some(single_data); + let value = data::value(&single_data); + let decimals = decimal_value::decimal(value); + let value = decimal_value::value(value); + + let amount = micros_amount * value; + let usd = MockUSD { + id: object::new(ctx), + amount, + decimals, + }; + transfer::transfer(usd, tx_context::sender(ctx)); + } + + public fun simple_fx(oracle: &SimpleOracle, micros_amount: u64, ctx: &mut TxContext) { + let single_data = simple_oracle::get_latest_data(oracle, string::utf8(b"IOTAUSD")); + let single_data = option::destroy_some(single_data); + let value = data::value(&single_data); + let decimals = decimal_value::decimal(value); + let value = decimal_value::value(value); + + let amount = micros_amount * value; + let usd = MockUSD { + id: object::new(ctx), + amount, + decimals, + }; + transfer::transfer(usd, tx_context::sender(ctx)); + } + + public fun trusted_fx( + oracle1: &SimpleOracle, + oracle2: &SimpleOracle, + oracle3: &SimpleOracle, + micros_amount: u64, + ctx: &mut TxContext + ) { + let meta_oracle = meta_oracle::new(3, 60000, string::utf8(b"IOTAUSD")); + meta_oracle::add_simple_oracle(&mut meta_oracle, oracle1); + meta_oracle::add_simple_oracle(&mut meta_oracle, oracle2); + meta_oracle::add_simple_oracle(&mut meta_oracle, oracle3); + + let trusted_data = meta_oracle::median(meta_oracle); + let value = meta_oracle::value(&trusted_data); + let decimals = decimal_value::decimal(value); + let value = decimal_value::value(value); + + let amount = micros_amount * value; + let usd = MockUSD { + id: object::new(ctx), + amount, + decimals, + }; + transfer::transfer(usd, tx_context::sender(ctx)); + } +} diff --git a/crates/sui-oracle/tests/integration_tests.rs b/crates/iota-oracle/tests/integration_tests.rs similarity index 86% rename from crates/sui-oracle/tests/integration_tests.rs rename to crates/iota-oracle/tests/integration_tests.rs index e33fb8ad9f6..8aa67d09b86 100644 --- a/crates/sui-oracle/tests/integration_tests.rs +++ b/crates/iota-oracle/tests/integration_tests.rs @@ -1,29 +1,30 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{path::PathBuf, str::FromStr}; -use shared_crypto::intent::Intent; -use sui_json_rpc_types::{ObjectChange, SuiExecutionStatus, SuiTransactionBlockEffectsAPI}; -use sui_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; -use sui_move_build::BuildConfig; -use sui_sdk::{ - rpc_types::SuiTransactionBlockResponseOptions, +use iota_json_rpc_types::{IotaExecutionStatus, IotaTransactionBlockEffectsAPI, ObjectChange}; +use iota_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; +use iota_move_build::BuildConfig; +use iota_sdk::{ + rpc_types::IotaTransactionBlockResponseOptions, types::{ - base_types::{ObjectID, SuiAddress}, + base_types::{IotaAddress, ObjectID}, programmable_transaction_builder::ProgrammableTransactionBuilder, quorum_driver_types::ExecuteTransactionRequestType, transaction::{CallArg, ObjectArg, Transaction, TransactionData}, Identifier, }, - SuiClient, SuiClientBuilder, + IotaClient, IotaClientBuilder, }; -use sui_types::{ +use iota_types::{ base_types::{ObjectRef, SequenceNumber}, - parse_sui_type_tag, TypeTag, + parse_iota_type_tag, TypeTag, }; +use shared_crypto::intent::Intent; -// Integration tests for SUI Oracle, these test can be run manually on local or +// Integration tests for IOTA Oracle, these test can be run manually on local or // remote testnet. #[ignore] #[tokio::test] @@ -52,7 +53,7 @@ async fn test_publish_primitive() { let mut builder = ProgrammableTransactionBuilder::new(); for i in 1..200 { - let ticker = format!("SUI {}", i); + let ticker = format!("IOTA {}", i); let value = builder .input(CallArg::Pure( @@ -99,7 +100,7 @@ async fn test_publish_primitive() { let data = TransactionData::new_programmable(sender, vec![gas], pt, 1000000000, gas_price); let signature = keystore - .sign_secure(&sender, &data, Intent::sui_transaction()) + .sign_secure(&sender, &data, Intent::iota_transaction()) .unwrap(); let tx = Transaction::from_data(data.clone(), vec![signature]); @@ -108,7 +109,7 @@ async fn test_publish_primitive() { .quorum_driver_api() .execute_transaction_block( tx, - SuiTransactionBlockResponseOptions::new().with_effects(), + IotaTransactionBlockResponseOptions::new().with_effects(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await @@ -149,7 +150,7 @@ async fn test_publish_complex_value() { .unwrap(); for i in 1..200 { - let ticker = format!("SUI {}", i); + let ticker = format!("IOTA {}", i); let value = builder .input(CallArg::Pure( @@ -194,7 +195,7 @@ async fn test_publish_complex_value() { package, module.clone(), submit_data.clone(), - vec![parse_sui_type_tag(&format!("{package}::decimal_value::DecimalValue")).unwrap()], + vec![parse_iota_type_tag(&format!("{package}::decimal_value::DecimalValue")).unwrap()], vec![simple_oracle, clock, ticker, decimal_value, identifier], ); } @@ -204,7 +205,7 @@ async fn test_publish_complex_value() { let data = TransactionData::new_programmable(sender, vec![gas], pt, 1000000000, gas_price); let signature = keystore - .sign_secure(&sender, &data, Intent::sui_transaction()) + .sign_secure(&sender, &data, Intent::iota_transaction()) .unwrap(); let tx = Transaction::from_data(data.clone(), vec![signature]); @@ -213,7 +214,7 @@ async fn test_publish_complex_value() { .quorum_driver_api() .execute_transaction_block( tx, - SuiTransactionBlockResponseOptions::new().with_effects(), + IotaTransactionBlockResponseOptions::new().with_effects(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await @@ -279,7 +280,7 @@ async fn test_consume_oracle_data() { .unwrap(); let ticker = builder - .input(CallArg::Pure(bcs::to_bytes("SUIUSD".as_bytes()).unwrap())) + .input(CallArg::Pure(bcs::to_bytes("IOTAUSD".as_bytes()).unwrap())) .unwrap(); let identifier = builder .input(CallArg::Pure( @@ -291,7 +292,7 @@ async fn test_consume_oracle_data() { package, module.clone(), submit_data.clone(), - vec![parse_sui_type_tag(&format!("{package}::decimal_value::DecimalValue")).unwrap()], + vec![parse_iota_type_tag(&format!("{package}::decimal_value::DecimalValue")).unwrap()], vec![simple_oracle, clock, ticker, decimal_value, identifier], ); @@ -300,7 +301,7 @@ async fn test_consume_oracle_data() { let data = TransactionData::new_programmable(sender, vec![gas], pt, 1000000000, gas_price); let signature = keystore - .sign_secure(&sender, &data, Intent::sui_transaction()) + .sign_secure(&sender, &data, Intent::iota_transaction()) .unwrap(); let tx = Transaction::from_data(data.clone(), vec![signature]); @@ -309,7 +310,7 @@ async fn test_consume_oracle_data() { .quorum_driver_api() .execute_transaction_block( tx, - SuiTransactionBlockResponseOptions::new().with_effects(), + IotaTransactionBlockResponseOptions::new().with_effects(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await @@ -333,20 +334,20 @@ async fn test_consume_oracle_data() { })) .unwrap(); let ticker = builder - .input(CallArg::Pure(bcs::to_bytes("SUIUSD".as_bytes()).unwrap())) + .input(CallArg::Pure(bcs::to_bytes("IOTAUSD".as_bytes()).unwrap())) .unwrap(); let data = builder.programmable_move_call( package, module, Identifier::from_str("get_latest_data").unwrap(), - vec![parse_sui_type_tag(&format!("{package}::decimal_value::DecimalValue")).unwrap()], + vec![parse_iota_type_tag(&format!("{package}::decimal_value::DecimalValue")).unwrap()], vec![simple_oracle, ticker], ); // call simple_fx_ptb let test_module = Identifier::from_str("test_module").unwrap(); let simple_fx_ptb = Identifier::from_str("simple_fx_ptb").unwrap(); - let mist_amount = builder + let micros_amount = builder .input(CallArg::Pure(bcs::to_bytes(&10000000u64).unwrap())) .unwrap(); builder.programmable_move_call( @@ -354,12 +355,12 @@ async fn test_consume_oracle_data() { test_module.clone(), simple_fx_ptb, vec![], - vec![data, mist_amount], + vec![data, micros_amount], ); // call simple_fx let simple_fx = Identifier::from_str("simple_fx").unwrap(); - let mist_amount = builder + let micros_amount = builder .input(CallArg::Pure(bcs::to_bytes(&10000000u64).unwrap())) .unwrap(); @@ -368,7 +369,7 @@ async fn test_consume_oracle_data() { test_module.clone(), simple_fx, vec![], - vec![simple_oracle, mist_amount], + vec![simple_oracle, micros_amount], ); // Call trusted_fx @@ -391,7 +392,7 @@ async fn test_consume_oracle_data() { test_module, trusted_fx, vec![], - vec![oracles[0], oracles[1], oracles[2], mist_amount], + vec![oracles[0], oracles[1], oracles[2], micros_amount], ); let pt = builder.finish(); @@ -399,7 +400,7 @@ async fn test_consume_oracle_data() { let data = TransactionData::new_programmable(sender, vec![gas], pt, 1000000000, gas_price); let signature = keystore - .sign_secure(&sender, &data, Intent::sui_transaction()) + .sign_secure(&sender, &data, Intent::iota_transaction()) .unwrap(); let tx = Transaction::from_data(data.clone(), vec![signature]); @@ -408,7 +409,7 @@ async fn test_consume_oracle_data() { .quorum_driver_api() .execute_transaction_block( tx, - SuiTransactionBlockResponseOptions::new().with_effects(), + IotaTransactionBlockResponseOptions::new().with_effects(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await @@ -417,7 +418,7 @@ async fn test_consume_oracle_data() { assert!(result.effects.unwrap().status().is_ok()); } -async fn get_gas(client: &SuiClient, sender: SuiAddress) -> (ObjectRef, u64) { +async fn get_gas(client: &IotaClient, sender: IotaAddress) -> (ObjectRef, u64) { let gas = client .coin_read_api() .get_coins(sender, None, None, Some(1)) @@ -433,9 +434,9 @@ async fn get_gas(client: &SuiClient, sender: SuiAddress) -> (ObjectRef, u64) { (gas, gas_price) } -async fn init_test_client() -> (SuiClient, Keystore, SuiAddress) { - let client = SuiClientBuilder::default() - .build("https://rpc.devnet.sui.io:443") +async fn init_test_client() -> (IotaClient, Keystore, IotaAddress) { + let client = IotaClientBuilder::default() + .build("https://rpc.devnet.iota.io:443") .await .unwrap(); @@ -443,11 +444,11 @@ async fn init_test_client() -> (SuiClient, Keystore, SuiAddress) { FileBasedKeystore::new( &dirs::home_dir() .unwrap() - .join(".sui/sui_config/sui.keystore"), + .join(".iota/iota_config/iota.keystore"), ) .unwrap(), ); - let sender: SuiAddress = keystore.addresses()[0]; + let sender: IotaAddress = keystore.addresses()[0]; let gas = client .coin_read_api() .get_coins(sender, None, None, Some(1)) @@ -464,9 +465,9 @@ async fn init_test_client() -> (SuiClient, Keystore, SuiAddress) { } async fn publish_package( - sender: SuiAddress, + sender: IotaAddress, keystore: &Keystore, - client: &SuiClient, + client: &IotaClient, path: PathBuf, ) -> ObjectID { let compiled_package = BuildConfig::new_for_testing().build(path).unwrap(); @@ -487,7 +488,7 @@ async fn publish_package( 1000, ); let signature = keystore - .sign_secure(&sender, &data, Intent::sui_transaction()) + .sign_secure(&sender, &data, Intent::iota_transaction()) .unwrap(); let tx = Transaction::from_data(data.clone(), vec![signature]); @@ -496,7 +497,7 @@ async fn publish_package( .quorum_driver_api() .execute_transaction_block( tx, - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_effects() .with_object_changes(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), @@ -504,7 +505,7 @@ async fn publish_package( .await .unwrap(); assert_eq!( - &SuiExecutionStatus::Success, + &IotaExecutionStatus::Success, result.effects.unwrap().status() ); @@ -523,9 +524,9 @@ async fn publish_package( } async fn create_oracle( - sender: SuiAddress, + sender: IotaAddress, keystore: &Keystore, - client: &SuiClient, + client: &IotaClient, package: ObjectID, module: Identifier, ) -> (ObjectID, SequenceNumber) { @@ -559,14 +560,14 @@ async fn create_oracle( let data = TransactionData::new_programmable(sender, vec![gas], pt, 1000000000, gas_price); let signature = keystore - .sign_secure(&sender, &data, Intent::sui_transaction()) + .sign_secure(&sender, &data, Intent::iota_transaction()) .unwrap(); let tx = Transaction::from_data(data.clone(), vec![signature]); let result = client .quorum_driver_api() .execute_transaction_block( tx, - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_effects() .with_object_changes(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), @@ -574,7 +575,7 @@ async fn create_oracle( .await .unwrap(); assert_eq!( - &SuiExecutionStatus::Success, + &IotaExecutionStatus::Success, result.effects.unwrap().status() ); let simple_oracle = result.object_changes.unwrap().iter().find(|change| matches!(change, ObjectChange::Created {object_type,..} if object_type.name.as_str() == "SimpleOracle")).unwrap().clone(); diff --git a/crates/iota-package-resolver/Cargo.toml b/crates/iota-package-resolver/Cargo.toml new file mode 100644 index 00000000000..b40d76b1680 --- /dev/null +++ b/crates/iota-package-resolver/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "iota-package-resolver" +version = "0.1.0" +edition = "2021" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +async-trait.workspace = true +bcs.workspace = true +move-binary-format.workspace = true +move-core-types.workspace = true +iota-types.workspace = true +thiserror.workspace = true +iota-rest-api.workspace = true +tokio.workspace = true +eyre.workspace = true +serde.workspace = true +lru.workspace = true + +[dev-dependencies] +hyper.workspace = true +insta.workspace = true +move-compiler.workspace = true +serde_json.workspace = true +iota-move-build.workspace = true +tower.workspace = true diff --git a/crates/iota-package-resolver/src/error.rs b/crates/iota-package-resolver/src/error.rs new file mode 100644 index 00000000000..6e83e8850e7 --- /dev/null +++ b/crates/iota-package-resolver/src/error.rs @@ -0,0 +1,84 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_types::TypeTag; +use move_binary_format::errors::VMError; +use move_core_types::account_address::AccountAddress; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error("{0}")] + Bcs(#[from] bcs::Error), + + #[error("Store {} error: {}", store, source)] + Store { + store: &'static str, + source: Box, + }, + + #[error("{0}")] + Deserialize(VMError), + + #[error("Package has no modules: {0}")] + EmptyPackage(AccountAddress), + + #[error("Function not found: {0}::{1}::{2}")] + FunctionNotFound(AccountAddress, String, String), + + #[error( + "Conflicting types for input {0}: {} and {}", + .1.to_canonical_display(/* with_prefix */ true), + .2.to_canonical_display(/* with_prefix */ true), + )] + InputTypeConflict(u16, TypeTag, TypeTag), + + #[error("Linkage not found for package: {0}")] + LinkageNotFound(AccountAddress), + + #[error("Module not found: {0}::{1}")] + ModuleNotFound(AccountAddress, String), + + #[error("No origin package found for {0}::{1}::{2}")] + NoTypeOrigin(AccountAddress, String, String), + + #[error("Not a package: {0}")] + NotAPackage(AccountAddress), + + #[error("Not an identifier: '{0}'")] + NotAnIdentifier(String), + + #[error("Package not found: {0}")] + PackageNotFound(AccountAddress), + + #[error("Struct not found: {0}::{1}::{2}")] + StructNotFound(AccountAddress, String, String), + + #[error("More than {0} struct definitions required to resolve type")] + TooManyTypeNodes(usize, usize), + + #[error("Expected at most {0} type parameters, got {1}")] + TooManyTypeParams(usize, usize), + + #[error("Expected {0} type parameters, but got {1}")] + TypeArityMismatch(usize, usize), + + #[error("Type parameter nesting exceeded limit of {0}")] + TypeParamNesting(usize, usize), + + #[error("Type Parameter {0} out of bounds ({1})")] + TypeParamOOB(u16, usize), + + #[error("Unexpected reference type.")] + UnexpectedReference, + + #[error("Unexpected type: 'signer'.")] + UnexpectedSigner, + + #[error("Unexpected error: {0}")] + UnexpectedError(Box), + + #[error("Type layout nesting exceeded limit of {0}")] + ValueNesting(usize), +} diff --git a/crates/iota-package-resolver/src/lib.rs b/crates/iota-package-resolver/src/lib.rs new file mode 100644 index 00000000000..ad892f8adcd --- /dev/null +++ b/crates/iota-package-resolver/src/lib.rs @@ -0,0 +1,2554 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + borrow::Cow, + collections::{btree_map::Entry, BTreeMap, BTreeSet}, + num::NonZeroUsize, + sync::{Arc, Mutex}, +}; + +use async_trait::async_trait; +use iota_types::{ + base_types::{is_primitive_type_tag, SequenceNumber}, + is_system_package, + move_package::TypeOrigin, + object::Object, + transaction::{Argument, CallArg, Command, ProgrammableTransaction}, + Identifier, +}; +use lru::LruCache; +use move_binary_format::{ + access::ModuleAccess, + errors::Location, + file_format::{ + AbilitySet, FunctionDefinitionIndex, Signature as MoveSignature, SignatureIndex, + SignatureToken, StructDefinitionIndex, StructFieldInformation, StructHandleIndex, + StructTypeParameter, TableIndex, Visibility, + }, + CompiledModule, +}; +use move_core_types::{ + account_address::AccountAddress, + annotated_value::{MoveFieldLayout, MoveStructLayout, MoveTypeLayout}, + language_storage::{StructTag, TypeTag}, +}; + +use crate::error::Error; + +pub mod error; + +// TODO Move to ServiceConfig + +const PACKAGE_CACHE_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(1024) }; + +pub type Result = std::result::Result; + +/// The Resolver is responsible for providing information about types. It relies +/// on its internal `package_store` to load packages and then type definitions +/// from those packages. +#[derive(Debug)] +pub struct Resolver { + package_store: S, + limits: Option, +} + +/// Optional configuration that imposes limits on the work that the resolver can +/// do for each request. +#[derive(Debug)] +pub struct Limits { + /// Maximum recursion depth through type parameters. + pub max_type_argument_depth: usize, + /// Maximum number of type arguments in a single type instantiation. + pub max_type_argument_width: usize, + /// Maximum size for the resolution context. + pub max_type_nodes: usize, + /// Maximum recursion depth through struct fields. + pub max_move_value_depth: usize, +} + +/// Store which fetches package for the given address from the backend db and +/// caches it locally in an lru cache. On every call to `fetch` it checks +/// backend db and if package version is stale locally, it updates the local +/// state before returning to the user +pub struct PackageStoreWithLruCache { + pub(crate) packages: Mutex>>, + pub(crate) inner: T, +} + +#[derive(Clone, Debug)] +pub struct Package { + /// The ID this package was loaded from on-chain. + storage_id: AccountAddress, + + /// The ID that this package is associated with at runtime. Bytecode in + /// other packages refers to types and functions from this package using + /// this ID. + runtime_id: AccountAddress, + + /// The package's transitive dependencies as a mapping from the package's + /// runtime ID (the ID it is referred to by in other packages) to its + /// storage ID (the ID it is loaded from on chain). + linkage: Linkage, + + /// The version this package was loaded at -- necessary for cache + /// invalidation of system packages. + version: SequenceNumber, + + modules: BTreeMap, +} + +type Linkage = BTreeMap; + +#[derive(Clone, Debug)] +pub struct Module { + bytecode: CompiledModule, + + /// Index mapping struct names to their defining ID, and the index for their + /// definition in the bytecode, to speed up definition lookups. + struct_index: BTreeMap, + + /// Index mapping function names to the index for their definition in the + /// bytecode, to speed up definition lookups. + function_index: BTreeMap, +} + +/// Deserialized representation of a struct definition. +#[derive(Debug)] +pub struct StructDef { + /// The storage ID of the package that first introduced this type. + pub defining_id: AccountAddress, + + /// This type's abilities. + pub abilities: AbilitySet, + + /// Ability constraints and phantom status for type parameters + pub type_params: Vec, + + /// Serialized representation of fields (names and deserialized signatures). + /// Signatures refer to packages at their runtime IDs (not their storage + /// ID or defining ID). + pub fields: Vec<(String, OpenSignatureBody)>, +} + +/// Deserialized representation of a function definition +#[derive(Debug)] +pub struct FunctionDef { + /// Whether the function is `public`, `private` or `public(friend)`. + pub visibility: Visibility, + + /// Whether the function is marked `entry` or not. + pub is_entry: bool, + + /// Ability constraints for type parameters + pub type_params: Vec, + + /// Formal parameter types. + pub parameters: Vec, + + /// Return types. + pub return_: Vec, +} + +/// Fully qualified struct identifier. Uses copy-on-write strings so that when +/// it is used as a key to a map, an instance can be created to query the map +/// without having to allocate strings on the heap. +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Hash)] +pub struct DatatypeRef<'m, 'n> { + pub package: AccountAddress, + pub module: Cow<'m, str>, + pub name: Cow<'n, str>, +} + +/// A `StructRef` that owns its strings. +pub type DatatypeKey = DatatypeRef<'static, 'static>; + +#[derive(Copy, Clone, Debug)] +pub enum Reference { + Immutable, + Mutable, +} + +/// A function parameter or return signature, with its type parameters +/// instantiated. +#[derive(Clone, Debug)] +pub struct Signature { + pub ref_: Option, + pub body: TypeTag, +} + +/// Deserialized representation of a type signature that could appear as a +/// function parameter or return. +#[derive(Clone, Debug)] +pub struct OpenSignature { + pub ref_: Option, + pub body: OpenSignatureBody, +} + +/// Deserialized representation of a type signature that could appear as a field +/// type for a struct. +#[derive(Clone, Debug)] +pub enum OpenSignatureBody { + Address, + Bool, + U8, + U16, + U32, + U64, + U128, + U256, + Vector(Box), + Datatype(DatatypeKey, Vec), + TypeParameter(u16), +} + +/// Information necessary to convert a type tag into a type layout. +#[derive(Debug, Default)] +struct ResolutionContext<'l> { + /// Definitions (field information) for structs referred to by types added + /// to this context. + structs: BTreeMap, + /// Limits configuration from the calling resolver. + limits: Option<&'l Limits>, +} + +/// Interface to abstract over access to a store of live packages. Used to +/// override the default store during testing. +#[async_trait] +pub trait PackageStore: Send + Sync + 'static { + /// Latest version of the object at `id`. + async fn version(&self, id: AccountAddress) -> Result; + /// Read package contents. Fails if `id` is not an object, not a package, or + /// is malformed in some way. + async fn fetch(&self, id: AccountAddress) -> Result>; +} + +macro_rules! as_ref_impl { + ($type:ty) => { + #[async_trait] + impl PackageStore for $type { + async fn version(&self, id: AccountAddress) -> Result { + self.as_ref().version(id).await + } + async fn fetch(&self, id: AccountAddress) -> Result> { + self.as_ref().fetch(id).await + } + } + }; +} + +as_ref_impl!(Arc); +as_ref_impl!(Box); + +/// Check $value does not exceed $limit in config, if the limit config exists, +/// returning an error containing the max value and actual value otherwise. +macro_rules! check_max_limit { + ($err:ident, $config:expr; $limit:ident $op:tt $value:expr) => { + if let Some(l) = $config { + let max = l.$limit; + let val = $value; + if !(max $op val) { + return Err(Error::$err(max, val)); + } + } + }; +} + +impl Resolver { + pub fn new(package_store: S) -> Self { + Self { + package_store, + limits: None, + } + } + + pub fn new_with_limits(package_store: S, limits: Limits) -> Self { + Self { + package_store, + limits: Some(limits), + } + } + + pub fn package_store(&self) -> &S { + &self.package_store + } + + pub fn package_store_mut(&mut self) -> &mut S { + &mut self.package_store + } +} + +impl Resolver { + /// Return the type layout corresponding to the given type tag. The layout + /// always refers to structs in terms of their defining ID (i.e. their + /// package ID always points to the first package that introduced them). + pub async fn type_layout(&self, mut tag: TypeTag) -> Result { + let mut context = ResolutionContext::new(self.limits.as_ref()); + + // (1). Fetch all the information from this store that is necessary to resolve + // types referenced by this tag. + context + .add_type_tag( + &mut tag, + &self.package_store, + // visit_fields + true, + // visit_phantoms + true, + ) + .await?; + + // (2). Use that information to resolve the tag into a layout. + let max_depth = self + .limits + .as_ref() + .map_or(usize::MAX, |l| l.max_move_value_depth); + + Ok(context.resolve_type_layout(&tag, max_depth)?.0) + } + + /// Return the abilities of a concrete type, based on the abilities in its + /// type definition, and the abilities of its concrete type parameters: + /// An instance of a generic type has `store`, `copy, or `drop` if its + /// definition has the ability, and all its non-phantom type parameters + /// have the ability as well. Similar rules apply for `key` except that it + /// requires its type parameters to have `store`. + pub async fn abilities(&self, mut tag: TypeTag) -> Result { + let mut context = ResolutionContext::new(self.limits.as_ref()); + + // (1). Fetch all the information from this store that is necessary to resolve + // types referenced by this tag. + context + .add_type_tag( + &mut tag, + &self.package_store, + // visit_fields + false, + // visit_phantoms + false, + ) + .await?; + + // (2). Use that information to calculate the type's abilities. + context.resolve_abilities(&tag) + } + + /// Returns the signatures of parameters to function `pkg::module::function` + /// in the package store, assuming the function exists. + pub async fn function_parameters( + &self, + pkg: AccountAddress, + module: &str, + function: &str, + ) -> Result> { + let mut context = ResolutionContext::new(self.limits.as_ref()); + + let package = self.package_store.fetch(pkg).await?; + let Some(def) = package.module(module)?.function_def(function)? else { + return Err(Error::FunctionNotFound( + pkg, + module.to_string(), + function.to_string(), + )); + }; + + let mut sigs = def.parameters.clone(); + + // (1). Fetch all the information from this store that is necessary to resolve + // types referenced by this tag. + for sig in &sigs { + context + .add_signature( + sig.body.clone(), + &self.package_store, + package.as_ref(), + // visit_fields + false, + ) + .await?; + } + + // (2). Use that information to relocate package IDs in the signature. + for sig in &mut sigs { + context.relocate_signature(&mut sig.body)?; + } + + Ok(sigs) + } + + /// Attempts to infer the type layouts for pure inputs to the programmable + /// transaction. + /// + /// The returned vector contains an element for each input to `tx`. Elements + /// corresponding to pure inputs that are used as arguments to + /// transaction commands will contain `Some(layout)`. Elements for other + /// inputs (non-pure inputs, and unused pure inputs) will be `None`. + /// + /// Layout resolution can fail if a type/module/package doesn't exist, if + /// layout resolution hits a limit, or if a pure input is somehow used + /// in multiple conflicting occasions (with different types). + pub async fn pure_input_layouts( + &self, + tx: &ProgrammableTransaction, + ) -> Result>> { + let mut tags = vec![None; tx.inputs.len()]; + let mut register_type = |arg: &Argument, tag: &TypeTag| { + let &Argument::Input(ix) = arg else { + return Ok(()); + }; + + if !matches!(tx.inputs.get(ix as usize), Some(CallArg::Pure(_))) { + return Ok(()); + } + + let Some(type_) = tags.get_mut(ix as usize) else { + return Ok(()); + }; + + if let Some(prev) = type_.replace(tag.clone()) { + // SAFETY: We just inserted `tag` in here. + let curr = type_.take().unwrap(); + return Err(Error::InputTypeConflict(ix, prev, curr)); + }; + + Ok(()) + }; + + // (1). Infer type tags for pure inputs from their uses. + for cmd in &tx.commands { + match cmd { + Command::MoveCall(call) => { + let params = self + .function_parameters( + call.package.into(), + call.module.as_str(), + call.function.as_str(), + ) + .await?; + + for (open_sig, arg) in params.iter().zip(call.arguments.iter()) { + let sig = open_sig.instantiate(&call.type_arguments)?; + register_type(arg, &sig.body)?; + } + } + + Command::TransferObjects(_, arg) => register_type(arg, &TypeTag::Address)?, + + Command::SplitCoins(_, amounts) => { + for amount in amounts { + register_type(amount, &TypeTag::U64)?; + } + } + + Command::MakeMoveVec(Some(tag), elems) if is_primitive_type_tag(tag) => { + for elem in elems { + register_type(elem, tag)?; + } + } + + _ => { /* nop */ } + } + } + + // (2). Gather all the unique type tags to convert into layouts. There are + // relatively few primitive types so this is worth doing to avoid + // redundant work. + let unique_tags: BTreeSet<_> = tags.iter().filter_map(|t| t.clone()).collect(); + + // (3). Convert the type tags into layouts. + let mut layouts = BTreeMap::new(); + for tag in unique_tags { + let layout = self.type_layout(tag.clone()).await?; + layouts.insert(tag, layout); + } + + // (4) Prepare the result vector. + Ok(tags + .iter() + .map(|t| t.as_ref().and_then(|t| layouts.get(t).cloned())) + .collect()) + } +} + +impl PackageStoreWithLruCache { + pub fn new(inner: T) -> Self { + let packages = Mutex::new(LruCache::new(PACKAGE_CACHE_SIZE)); + Self { packages, inner } + } +} + +#[async_trait] +impl PackageStore for PackageStoreWithLruCache { + async fn version(&self, id: AccountAddress) -> Result { + self.inner.version(id).await + } + + async fn fetch(&self, id: AccountAddress) -> Result> { + let candidate = { + // Release the lock after getting the package + let mut packages = self.packages.lock().unwrap(); + packages.get(&id).map(Arc::clone) + }; + + // System packages can be invalidated in the cache if a newer version exists. + match candidate { + Some(package) if !is_system_package(id) => return Ok(package), + Some(package) if self.version(id).await? <= package.version => return Ok(package), + Some(_) | None => { /* nop */ } + } + + let package = self.inner.fetch(id).await?; + // Try and insert the package into the cache, accounting for races. In most + // cases the racing fetches will produce the same package, but for + // system packages, they may not, so favour the package that has the + // newer version, or if they are the same, the package that is already + // in the cache. + + let mut packages = self.packages.lock().unwrap(); + Ok(match packages.peek(&id) { + Some(prev) if package.version <= prev.version => { + let package = prev.clone(); + packages.promote(&id); + package + } + + Some(_) | None => { + packages.push(id, package.clone()); + package + } + }) + } +} + +impl Package { + pub fn read(object: &Object) -> Result { + let storage_id = AccountAddress::from(object.id()); + let Some(package) = object.data.try_as_package() else { + return Err(Error::NotAPackage(storage_id)); + }; + + let mut type_origins: BTreeMap> = BTreeMap::new(); + for TypeOrigin { + module_name, + struct_name, + package, + } in package.type_origin_table() + { + type_origins + .entry(module_name.to_string()) + .or_default() + .insert(struct_name.to_string(), AccountAddress::from(*package)); + } + + let mut runtime_id = None; + let mut modules = BTreeMap::new(); + for (name, bytes) in package.serialized_module_map() { + let origins = type_origins.remove(name).unwrap_or_default(); + let bytecode = CompiledModule::deserialize_with_defaults(bytes) + .map_err(|e| Error::Deserialize(e.finish(Location::Undefined)))?; + + runtime_id = Some(*bytecode.address()); + + let name = name.clone(); + match Module::read(bytecode, origins) { + Ok(module) => modules.insert(name, module), + Err(struct_) => return Err(Error::NoTypeOrigin(storage_id, name, struct_)), + }; + } + + let Some(runtime_id) = runtime_id else { + return Err(Error::EmptyPackage(storage_id)); + }; + + let linkage = package + .linkage_table() + .iter() + .map(|(&dep, linkage)| (dep.into(), linkage.upgraded_id.into())) + .collect(); + + Ok(Package { + storage_id, + runtime_id, + version: package.version(), + modules, + linkage, + }) + } + + pub fn module(&self, module: &str) -> Result<&Module> { + self.modules + .get(module) + .ok_or_else(|| Error::ModuleNotFound(self.storage_id, module.to_string())) + } + + pub fn modules(&self) -> &BTreeMap { + &self.modules + } + + fn struct_def(&self, module_name: &str, struct_name: &str) -> Result { + let module = self.module(module_name)?; + let Some(struct_def) = module.struct_def(struct_name)? else { + return Err(Error::StructNotFound( + self.storage_id, + module_name.to_string(), + struct_name.to_string(), + )); + }; + + Ok(struct_def) + } + + /// Translate the `runtime_id` of a package to a specific storage ID using + /// this package's linkage table. Returns an error if the package in + /// question is not present in the linkage table. + fn relocate(&self, runtime_id: AccountAddress) -> Result { + // Special case the current package, because it doesn't get an entry in the + // linkage table. + if runtime_id == self.runtime_id { + return Ok(self.storage_id); + } + + self.linkage + .get(&runtime_id) + .ok_or_else(|| Error::LinkageNotFound(runtime_id)) + .copied() + } +} + +impl Module { + /// Deserialize a module from its bytecode, and a table containing the + /// origins of its structs. Fails if the origin table is missing an + /// entry for one of its types, returning the name of the type in that + /// case. + fn read( + bytecode: CompiledModule, + mut origins: BTreeMap, + ) -> std::result::Result { + let mut struct_index = BTreeMap::new(); + for (index, def) in bytecode.struct_defs.iter().enumerate() { + let sh = bytecode.struct_handle_at(def.struct_handle); + let struct_ = bytecode.identifier_at(sh.name).to_string(); + let index = StructDefinitionIndex::new(index as TableIndex); + + let Some(defining_id) = origins.remove(&struct_) else { + return Err(struct_); + }; + + struct_index.insert(struct_, (defining_id, index)); + } + + let mut function_index = BTreeMap::new(); + for (index, def) in bytecode.function_defs.iter().enumerate() { + let fh = bytecode.function_handle_at(def.function); + let function = bytecode.identifier_at(fh.name).to_string(); + let index = FunctionDefinitionIndex::new(index as TableIndex); + + function_index.insert(function, index); + } + + Ok(Module { + bytecode, + struct_index, + function_index, + }) + } + + pub fn bytecode(&self) -> &CompiledModule { + &self.bytecode + } + + /// The module's name + pub fn name(&self) -> &str { + self.bytecode + .identifier_at(self.bytecode.self_handle().name) + .as_str() + } + + /// Iterate over the structs with names strictly after `after` (or from the + /// beginning), and strictly before `before` (or to the end). + pub fn structs( + &self, + after: Option<&str>, + before: Option<&str>, + ) -> impl DoubleEndedIterator + Clone { + use std::ops::Bound as B; + self.struct_index + .range::(( + after.map_or(B::Unbounded, B::Excluded), + before.map_or(B::Unbounded, B::Excluded), + )) + .map(|(name, _)| name.as_str()) + } + + /// Get the struct definition corresponding to the struct with name `name` + /// in this module. Returns `Ok(None)` if the struct cannot be found in + /// this module, `Err(...)` if there was an error deserializing it, and + /// `Ok(Some(def))` on success. + pub fn struct_def(&self, name: &str) -> Result> { + let Some(&(defining_id, index)) = self.struct_index.get(name) else { + return Ok(None); + }; + + let struct_def = self.bytecode.struct_def_at(index); + let struct_handle = self.bytecode.struct_handle_at(struct_def.struct_handle); + let abilities = struct_handle.abilities; + let type_params = struct_handle.type_parameters.clone(); + + let fields = match &struct_def.field_information { + StructFieldInformation::Native => vec![], + StructFieldInformation::Declared(fields) => fields + .iter() + .map(|f| { + Ok(( + self.bytecode.identifier_at(f.name).to_string(), + OpenSignatureBody::read(&f.signature.0, &self.bytecode)?, + )) + }) + .collect::>()?, + }; + + Ok(Some(StructDef { + defining_id, + abilities, + type_params, + fields, + })) + } + + /// Iterate over the functions with names strictly after `after` (or from + /// the beginning), and strictly before `before` (or to the end). + pub fn functions( + &self, + after: Option<&str>, + before: Option<&str>, + ) -> impl DoubleEndedIterator + Clone { + use std::ops::Bound as B; + self.function_index + .range::(( + after.map_or(B::Unbounded, B::Excluded), + before.map_or(B::Unbounded, B::Excluded), + )) + .map(|(name, _)| name.as_str()) + } + + /// Get the function definition corresponding to the function with name + /// `name` in this module. Returns `Ok(None)` if the function cannot be + /// found in this module, `Err(...)` if there was an error deserializing + /// it, and `Ok(Some(def))` on success. + pub fn function_def(&self, name: &str) -> Result> { + let Some(&index) = self.function_index.get(name) else { + return Ok(None); + }; + + let function_def = self.bytecode.function_def_at(index); + let function_handle = self.bytecode.function_handle_at(function_def.function); + + Ok(Some(FunctionDef { + visibility: function_def.visibility, + is_entry: function_def.is_entry, + type_params: function_handle.type_parameters.clone(), + parameters: read_signature(function_handle.parameters, &self.bytecode)?, + return_: read_signature(function_handle.return_, &self.bytecode)?, + })) + } +} + +impl OpenSignature { + fn read(sig: &SignatureToken, bytecode: &CompiledModule) -> Result { + use SignatureToken as S; + Ok(match sig { + S::Reference(sig) => OpenSignature { + ref_: Some(Reference::Immutable), + body: OpenSignatureBody::read(sig, bytecode)?, + }, + + S::MutableReference(sig) => OpenSignature { + ref_: Some(Reference::Mutable), + body: OpenSignatureBody::read(sig, bytecode)?, + }, + + sig => OpenSignature { + ref_: None, + body: OpenSignatureBody::read(sig, bytecode)?, + }, + }) + } + + /// Return a specific instantiation of this signature, with `type_params` as + /// the actual type parameters. This function does not check that the + /// supplied type parameters are valid (meet the ability constraints of + /// the struct or function this signature is part of), but will + /// produce an error if the signature references a type parameter that is + /// out of bounds. + pub fn instantiate(&self, type_params: &[TypeTag]) -> Result { + Ok(Signature { + ref_: self.ref_, + body: self.body.instantiate(type_params)?, + }) + } +} + +impl OpenSignatureBody { + fn read(sig: &SignatureToken, bytecode: &CompiledModule) -> Result { + use OpenSignatureBody as O; + use SignatureToken as S; + + Ok(match sig { + S::Signer => return Err(Error::UnexpectedSigner), + S::Reference(_) | S::MutableReference(_) => return Err(Error::UnexpectedReference), + + S::Address => O::Address, + S::Bool => O::Bool, + S::U8 => O::U8, + S::U16 => O::U16, + S::U32 => O::U32, + S::U64 => O::U64, + S::U128 => O::U128, + S::U256 => O::U256, + S::TypeParameter(ix) => O::TypeParameter(*ix), + + S::Vector(sig) => O::Vector(Box::new(OpenSignatureBody::read(sig, bytecode)?)), + + S::Struct(ix) => O::Datatype(DatatypeKey::read(*ix, bytecode), vec![]), + S::StructInstantiation(struct_inst) => { + let (ix, params) = &**struct_inst; + O::Datatype( + DatatypeKey::read(*ix, bytecode), + params + .iter() + .map(|sig| OpenSignatureBody::read(sig, bytecode)) + .collect::>()?, + ) + } + }) + } + + fn instantiate(&self, type_params: &[TypeTag]) -> Result { + use OpenSignatureBody as O; + use TypeTag as T; + + Ok(match self { + O::Address => T::Address, + O::Bool => T::Bool, + O::U8 => T::U8, + O::U16 => T::U16, + O::U32 => T::U32, + O::U64 => T::U64, + O::U128 => T::U128, + O::U256 => T::U256, + O::Vector(s) => T::Vector(Box::new(s.instantiate(type_params)?)), + + O::Datatype(key, dty_params) => T::Struct(Box::new(StructTag { + address: key.package, + module: ident(&key.module)?, + name: ident(&key.name)?, + type_params: dty_params + .iter() + .map(|p| p.instantiate(type_params)) + .collect::>()?, + })), + + O::TypeParameter(ix) => type_params + .get(*ix as usize) + .cloned() + .ok_or_else(|| Error::TypeParamOOB(*ix, type_params.len()))?, + }) + } +} + +impl<'m, 'n> DatatypeRef<'m, 'n> { + pub fn as_key(&self) -> DatatypeKey { + DatatypeKey { + package: self.package, + module: self.module.to_string().into(), + name: self.name.to_string().into(), + } + } +} + +impl DatatypeKey { + fn read(ix: StructHandleIndex, bytecode: &CompiledModule) -> Self { + let sh = bytecode.struct_handle_at(ix); + let mh = bytecode.module_handle_at(sh.module); + + let package = *bytecode.address_identifier_at(mh.address); + let module = bytecode.identifier_at(mh.name).to_string().into(); + let name = bytecode.identifier_at(sh.name).to_string().into(); + + DatatypeKey { + package, + module, + name, + } + } +} + +impl<'l> ResolutionContext<'l> { + fn new(limits: Option<&'l Limits>) -> Self { + ResolutionContext { + structs: BTreeMap::new(), + limits, + } + } + + /// Gather definitions for types that contribute to the definition of `tag` + /// into this resolution context, fetching data from the `store` as + /// necessary. Also updates package addresses in `tag` to point to + /// runtime IDs instead of storage IDs to ensure queries made using these + /// addresses during the subsequent resolution phase find the relevant type + /// information in the context. + /// + /// The `visit_fields` flag controls whether the traversal looks inside + /// types at their fields (which is necessary for layout resolution) or + /// not (only explores the outer type and any type parameters). + /// + /// The `visit_phantoms` flag controls whether the traversal recurses + /// through phantom type parameters (which is also necessary for type + /// resolution) or not. + async fn add_type_tag( + &mut self, + tag: &mut TypeTag, + store: &S, + visit_fields: bool, + visit_phantoms: bool, + ) -> Result<()> { + use TypeTag as T; + + struct ToVisit<'t> { + tag: &'t mut TypeTag, + depth: usize, + } + + let mut frontier = vec![ToVisit { tag, depth: 0 }]; + while let Some(ToVisit { tag, depth }) = frontier.pop() { + macro_rules! push_ty_param { + ($tag:expr) => {{ + check_max_limit!( + TypeParamNesting, self.limits; + max_type_argument_depth > depth + ); + + frontier.push(ToVisit { tag: $tag, depth: depth + 1 }) + }} + } + + match tag { + T::Address + | T::Bool + | T::U8 + | T::U16 + | T::U32 + | T::U64 + | T::U128 + | T::U256 + | T::Signer => { + // Nothing further to add to context + } + + T::Vector(tag) => push_ty_param!(tag), + + T::Struct(s) => { + let context = store.fetch(s.address).await?; + let def = context + .clone() + .struct_def(s.module.as_str(), s.name.as_str())?; + + // Normalize `address` (the ID of a package that contains the definition of this + // struct) to be a runtime ID, because that's what the resolution context uses + // for keys. Take care to do this before generating the key that is used to + // query and/or write into `self.structs. + s.address = context.runtime_id; + let key = DatatypeRef::from(s.as_ref()).as_key(); + + if def.type_params.len() != s.type_params.len() { + return Err(Error::TypeArityMismatch( + def.type_params.len(), + s.type_params.len(), + )); + } + + check_max_limit!( + TooManyTypeParams, self.limits; + max_type_argument_width >= s.type_params.len() + ); + + for (param, def) in s.type_params.iter_mut().zip(def.type_params.iter()) { + if !def.is_phantom || visit_phantoms { + push_ty_param!(param); + } + } + + if self.structs.contains_key(&key) { + continue; + } + + if visit_fields { + for (_, sig) in &def.fields { + self.add_signature(sig.clone(), store, &context, visit_fields) + .await?; + } + } + + check_max_limit!( + TooManyTypeNodes, self.limits; + max_type_nodes > self.structs.len() + ); + + self.structs.insert(key, def); + } + } + } + + Ok(()) + } + + // Like `add_type_tag` but for type signatures. Needs a linkage table to + // translate runtime IDs into storage IDs. + async fn add_signature( + &mut self, + sig: OpenSignatureBody, + store: &T, + context: &Package, + visit_fields: bool, + ) -> Result<()> { + use OpenSignatureBody as O; + + let mut frontier = vec![sig]; + while let Some(sig) = frontier.pop() { + match sig { + O::Address + | O::Bool + | O::U8 + | O::U16 + | O::U32 + | O::U64 + | O::U128 + | O::U256 + | O::TypeParameter(_) => { + // Nothing further to add to context + } + + O::Vector(sig) => frontier.push(*sig), + + O::Datatype(key, params) => { + check_max_limit!( + TooManyTypeParams, self.limits; + max_type_argument_width >= params.len() + ); + + let params_count = params.len(); + let struct_count = self.structs.len(); + frontier.extend(params.into_iter()); + + let def = match self.structs.entry(key.clone()) { + Entry::Occupied(e) => e.into_mut(), + + Entry::Vacant(e) => { + let storage_id = context.relocate(key.package)?; + let package = store.fetch(storage_id).await?; + let def = package.struct_def(&key.module, &key.name)?; + + if visit_fields { + frontier.extend(def.fields.iter().map(|f| &f.1).cloned()); + } + + check_max_limit!( + TooManyTypeNodes, self.limits; + max_type_nodes > struct_count + ); + + e.insert(def) + } + }; + + if def.type_params.len() != params_count { + return Err(Error::TypeArityMismatch( + def.type_params.len(), + params_count, + )); + } + } + } + } + + Ok(()) + } + + /// Translate a type `tag` into its layout using only the information + /// contained in this context. Requires that the necessary information + /// was added to the context through calls to `add_type_tag` and + /// `add_signature` before being called. + /// + /// `max_depth` controls how deep the layout is allowed to grow to. The + /// actual depth reached is returned alongside the layout (assuming it + /// does not exceed `max_depth`). + fn resolve_type_layout( + &self, + tag: &TypeTag, + max_depth: usize, + ) -> Result<(MoveTypeLayout, usize)> { + use MoveTypeLayout as L; + use TypeTag as T; + + if max_depth == 0 { + return Err(Error::ValueNesting( + self.limits.map_or(0, |l| l.max_move_value_depth), + )); + } + + Ok(match tag { + T::Signer => return Err(Error::UnexpectedSigner), + + T::Address => (L::Address, 1), + T::Bool => (L::Bool, 1), + T::U8 => (L::U8, 1), + T::U16 => (L::U16, 1), + T::U32 => (L::U32, 1), + T::U64 => (L::U64, 1), + T::U128 => (L::U128, 1), + T::U256 => (L::U256, 1), + + T::Vector(tag) => { + let (layout, depth) = self.resolve_type_layout(tag, max_depth - 1)?; + (L::Vector(Box::new(layout)), depth + 1) + } + + T::Struct(s) => { + // TODO (optimization): Could introduce a layout cache to further speed up + // resolution. Relevant entries in that cache would need to be gathered in the + // ResolutionContext as it is built, and then used here to avoid the recursive + // exploration. This optimisation is complicated by the fact that in the cache, + // these layouts are naturally keyed based on defining ID, but during + // resolution, they are keyed by runtime IDs. + + // SAFETY: `add_type_tag` ensures `structs` has an element with this key. + let key = DatatypeRef::from(s.as_ref()); + let def = &self.structs[&key]; + + let StructTag { + module, + name, + type_params, + .. + } = s.as_ref(); + + // TODO (optimization): This could be made more efficient by only generating + // layouts for non-phantom types. This efficiency could be + // extended to the exploration phase (i.e. only explore layouts + // of non-phantom types). But this optimisation is complicated + // by the fact that we still need to create a correct type tag for a + // phantom parameter, which is currently done by converting a type layout into a + // tag. + let param_layouts = type_params + .iter() + // Reduce the max depth because we know these type parameters will be nested + // wthin this struct. + .map(|tag| self.resolve_type_layout(tag, max_depth - 1)) + .collect::>>()?; + + // SAFETY: `param_layouts` contains `MoveTypeLayout`-s that are generated by + // this `ResolutionContext`, which guarantees that struct + // layouts come with types, which is necessary to avoid errors + // when converting layouts into type tags. + let type_params = param_layouts.iter().map(|l| TypeTag::from(&l.0)).collect(); + + let type_ = StructTag { + address: def.defining_id, + module: module.clone(), + name: name.clone(), + type_params, + }; + + let mut fields = Vec::with_capacity(def.fields.len()); + let mut field_depth = 0; + + for (name, sig) in &def.fields { + let (layout, depth) = + self.resolve_signature_layout(sig, ¶m_layouts, max_depth - 1)?; + + field_depth = field_depth.max(depth); + fields.push(MoveFieldLayout { + name: ident(name.as_str())?, + layout, + }) + } + + ( + L::Struct(MoveStructLayout { type_, fields }), + field_depth + 1, + ) + } + }) + } + + /// Like `resolve_type_tag` but for signatures. Needs to be provided the + /// layouts of type parameters which are substituted when a type + /// parameter is encountered. + /// + /// `max_depth` controls how deep the layout is allowed to grow to. The + /// actual depth reached is returned alongside the layout (assuming it + /// does not exceed `max_depth`). + fn resolve_signature_layout( + &self, + sig: &OpenSignatureBody, + param_layouts: &[(MoveTypeLayout, usize)], + max_depth: usize, + ) -> Result<(MoveTypeLayout, usize)> { + use MoveTypeLayout as L; + use OpenSignatureBody as O; + + if max_depth == 0 { + return Err(Error::ValueNesting( + self.limits.map_or(0, |l| l.max_move_value_depth), + )); + } + + Ok(match sig { + O::Address => (L::Address, 1), + O::Bool => (L::Bool, 1), + O::U8 => (L::U8, 1), + O::U16 => (L::U16, 1), + O::U32 => (L::U32, 1), + O::U64 => (L::U64, 1), + O::U128 => (L::U128, 1), + O::U256 => (L::U256, 1), + + O::TypeParameter(ix) => { + let (layout, depth) = param_layouts + .get(*ix as usize) + .ok_or_else(|| Error::TypeParamOOB(*ix, param_layouts.len())) + .cloned()?; + + // We need to re-check the type parameter before we use it because it might have + // been fine when it was created, but result in too deep a layout when we use it + // at this position. + if depth > max_depth { + return Err(Error::ValueNesting( + self.limits.map_or(0, |l| l.max_move_value_depth), + )); + } + + (layout, depth) + } + + O::Vector(sig) => { + let (layout, depth) = + self.resolve_signature_layout(sig.as_ref(), param_layouts, max_depth - 1)?; + + (L::Vector(Box::new(layout)), depth + 1) + } + + O::Datatype(key, params) => { + // SAFETY: `add_signature` ensures `structs` has an element with this key. + let def = &self.structs[key]; + + let param_layouts = params + .iter() + .map(|sig| self.resolve_signature_layout(sig, param_layouts, max_depth - 1)) + .collect::>>()?; + + // SAFETY: `param_layouts` contains `MoveTypeLayout`-s that are generated by + // this `ResolutionContext`, which guarantees that struct + // layouts come with types, which is necessary to avoid errors + // when converting layouts into type tags. + let type_params = param_layouts.iter().map(|l| TypeTag::from(&l.0)).collect(); + + let type_ = StructTag { + address: def.defining_id, + module: ident(&key.module)?, + name: ident(&key.name)?, + type_params, + }; + + let mut fields = Vec::with_capacity(def.fields.len()); + let mut field_depth = 0; + for (name, sig) in &def.fields { + let (layout, depth) = + self.resolve_signature_layout(sig, ¶m_layouts, max_depth - 1)?; + + field_depth = field_depth.max(depth); + fields.push(MoveFieldLayout { + name: ident(name.as_str())?, + layout, + }); + } + + ( + L::Struct(MoveStructLayout { type_, fields }), + field_depth + 1, + ) + } + }) + } + + /// Calculate the abilities for a concrete type `tag`. Requires that the + /// necessary information was added to the context through calls to + /// `add_type_tag` before being called. + fn resolve_abilities(&self, tag: &TypeTag) -> Result { + use TypeTag as T; + Ok(match tag { + T::Signer => return Err(Error::UnexpectedSigner), + + T::Bool | T::U8 | T::U16 | T::U32 | T::U64 | T::U128 | T::U256 | T::Address => { + AbilitySet::PRIMITIVES + } + + T::Vector(tag) => self.resolve_abilities(tag)?.intersect(AbilitySet::VECTOR), + + T::Struct(s) => { + // SAFETY: `add_type_tag` ensures `structs` has an element with this key. + let key = DatatypeRef::from(s.as_ref()); + let def = &self.structs[&key]; + + if def.type_params.len() != s.type_params.len() { + return Err(Error::TypeArityMismatch( + def.type_params.len(), + s.type_params.len(), + )); + } + + let param_abilities: Result> = s + .type_params + .iter() + .zip(def.type_params.iter()) + .map(|(p, d)| { + if d.is_phantom { + Ok(AbilitySet::EMPTY) + } else { + self.resolve_abilities(p) + } + }) + .collect(); + + AbilitySet::polymorphic_abilities( + def.abilities, + def.type_params.iter().map(|p| p.is_phantom), + param_abilities?.into_iter(), + ) + // This error is unexpected because the only reason it would fail is because of a + // type parameter arity mismatch, which we check for above. + .map_err(|e| Error::UnexpectedError(Box::new(e)))? + } + }) + } + + /// Translate the (runtime) package IDs in `sig` to defining IDs using only + /// the information contained in this context. Requires that the + /// necessary information was added to the context through calls to + /// `add_signature` before being called. + fn relocate_signature(&self, sig: &mut OpenSignatureBody) -> Result<()> { + use OpenSignatureBody as O; + + match sig { + O::Address | O::Bool | O::U8 | O::U16 | O::U32 | O::U64 | O::U128 | O::U256 => { + // nop + } + + O::TypeParameter(_) => { /* nop */ } + + O::Vector(sig) => self.relocate_signature(sig.as_mut())?, + + O::Datatype(key, params) => { + // SAFETY: `add_signature` ensures `structs` has an element with this key. + let def = &self.structs[key]; + for param in params { + self.relocate_signature(param)?; + } + + key.package = def.defining_id; + } + } + + Ok(()) + } +} + +impl<'s> From<&'s StructTag> for DatatypeRef<'s, 's> { + fn from(tag: &'s StructTag) -> Self { + DatatypeRef { + package: tag.address, + module: tag.module.as_str().into(), + name: tag.name.as_str().into(), + } + } +} + +/// Translate a string into an `Identifier`, but translating errors into this +/// module's error type. +fn ident(s: &str) -> Result { + Identifier::new(s).map_err(|_| Error::NotAnIdentifier(s.to_string())) +} + +/// Read and deserialize a signature index (from function parameter or return +/// types) into a vector of signatures. +fn read_signature(idx: SignatureIndex, bytecode: &CompiledModule) -> Result> { + let MoveSignature(tokens) = bytecode.signature_at(idx); + let mut sigs = Vec::with_capacity(tokens.len()); + + for token in tokens { + sigs.push(OpenSignature::read(token, bytecode)?); + } + + Ok(sigs) +} + +#[cfg(test)] +mod tests { + use std::{ + path::PathBuf, + str::FromStr, + sync::{Arc, RwLock}, + }; + + use async_trait::async_trait; + use iota_move_build::{BuildConfig, CompiledPackage}; + use iota_types::{ + base_types::random_object_ref, + transaction::{ObjectArg, ProgrammableMoveCall}, + }; + use move_binary_format::file_format::Ability; + use move_compiler::compiled_unit::NamedCompiledModule; + use move_core_types::ident_str; + + use super::*; + + /// Layout for a type that only refers to base types or other types in the + /// same module. + #[tokio::test] + async fn test_simple_type() { + let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); + let package_resolver = Resolver::new(cache); + let layout = package_resolver + .type_layout(type_("0xa0::m::T0")) + .await + .unwrap(); + insta::assert_snapshot!(format!("{layout:#}")); + } + + /// A type that refers to types from other modules in the same package. + #[tokio::test] + async fn test_cross_module() { + let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); + let resolver = Resolver::new(cache); + let layout = resolver.type_layout(type_("0xa0::n::T0")).await.unwrap(); + insta::assert_snapshot!(format!("{layout:#}")); + } + + /// A type that refers to types from other modules in the same package. + #[tokio::test] + async fn test_cross_package() { + let (_, cache) = package_cache([ + (1, build_package("a0"), a0_types()), + (1, build_package("b0"), b0_types()), + ]); + let resolver = Resolver::new(cache); + + let layout = resolver.type_layout(type_("0xb0::m::T0")).await.unwrap(); + insta::assert_snapshot!(format!("{layout:#}")); + } + + /// A type from an upgraded package, mixing structs defined in the original + /// package and the upgraded package. + #[tokio::test] + async fn test_upgraded_package() { + let (_, cache) = package_cache([ + (1, build_package("a0"), a0_types()), + (2, build_package("a1"), a1_types()), + ]); + let resolver = Resolver::new(cache); + + let layout = resolver.type_layout(type_("0xa1::n::T1")).await.unwrap(); + insta::assert_snapshot!(format!("{layout:#}")); + } + + /// A generic type instantiation where the type parameters are resolved + /// relative to linkage contexts from different versions of the same + /// package. + #[tokio::test] + async fn test_multiple_linkage_contexts() { + let (_, cache) = package_cache([ + (1, build_package("a0"), a0_types()), + (2, build_package("a1"), a1_types()), + ]); + let resolver = Resolver::new(cache); + + let layout = resolver + .type_layout(type_("0xa0::m::T1<0xa0::m::T0, 0xa1::m::T3>")) + .await + .unwrap(); + insta::assert_snapshot!(format!("{layout:#}")); + } + + /// Refer to a type, not by its defining ID, but by the ID of some later + /// version of that package. This doesn't currently work during + /// execution but it simplifies making queries: A type can be referred + /// to using the ID of any package that declares it, rather than only the + /// package that first declared it (whose ID is its defining ID). + #[tokio::test] + async fn test_upgraded_package_non_defining_id() { + let (_, cache) = package_cache([ + (1, build_package("a0"), a0_types()), + (2, build_package("a1"), a1_types()), + ]); + let resolver = Resolver::new(cache); + + let layout = resolver + .type_layout(type_("0xa1::m::T1<0xa1::m::T3, 0xa1::m::T0>")) + .await + .unwrap(); + insta::assert_snapshot!(format!("{layout:#}")); + } + + /// A type that refers to a types in a relinked package. C depends on B and + /// overrides its dependency on A from v1 to v2. The type in C refers + /// to types that were defined in both B, A v1, and A v2. + #[tokio::test] + async fn test_relinking() { + let (_, cache) = package_cache([ + (1, build_package("a0"), a0_types()), + (2, build_package("a1"), a1_types()), + (1, build_package("b0"), b0_types()), + (1, build_package("c0"), c0_types()), + ]); + let resolver = Resolver::new(cache); + + let layout = resolver.type_layout(type_("0xc0::m::T0")).await.unwrap(); + insta::assert_snapshot!(format!("{layout:#}")); + } + + #[tokio::test] + async fn test_value_nesting_boundary() { + let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); + + let resolver = Resolver::new_with_limits( + cache, + Limits { + max_type_argument_width: 100, + max_type_argument_depth: 100, + max_type_nodes: 100, + max_move_value_depth: 3, + }, + ); + + // The layout of this type is fine, because it is *just* at the correct depth. + let layout = resolver + .type_layout(type_("0xa0::m::T1")) + .await + .unwrap(); + insta::assert_snapshot!(format!("{layout:#}")); + } + + #[tokio::test] + async fn test_err_value_nesting_simple() { + let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); + + let resolver = Resolver::new_with_limits( + cache, + Limits { + max_type_argument_width: 100, + max_type_argument_depth: 100, + max_type_nodes: 100, + max_move_value_depth: 2, + }, + ); + + // The depth limit is now too low, so this will fail. + let err = resolver + .type_layout(type_("0xa0::m::T1")) + .await + .unwrap_err(); + assert!(matches!(err, Error::ValueNesting(2))) + } + + #[tokio::test] + async fn test_err_value_nesting_big_type_param() { + let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); + + let resolver = Resolver::new_with_limits( + cache, + Limits { + max_type_argument_width: 100, + max_type_argument_depth: 100, + max_type_nodes: 100, + max_move_value_depth: 3, + }, + ); + + // This layout calculation will fail early because we know that the type + // parameter we're calculating will eventually contribute to a layout + // that exceeds the max depth. + let err = resolver + .type_layout(type_("0xa0::m::T1>, u8>")) + .await + .unwrap_err(); + assert!(matches!(err, Error::ValueNesting(3))) + } + + #[tokio::test] + async fn test_err_value_nesting_big_phantom_type_param() { + let (_, cache) = package_cache([ + (1, build_package("iota"), iota_types()), + (1, build_package("d0"), d0_types()), + ]); + + let resolver = Resolver::new_with_limits( + cache, + Limits { + max_type_argument_width: 100, + max_type_argument_depth: 100, + max_type_nodes: 100, + max_move_value_depth: 3, + }, + ); + + // Check that this layout request would succeed. + let _ = resolver + .type_layout(type_("0xd0::m::O")) + .await + .unwrap(); + + // But this one fails, even though the big layout is for a phantom type + // parameter. This may change in future if we optimise the way we handle + // phantom type parameters to not calculate their full layout, just + // their type tag. + let err = resolver + .type_layout(type_("0xd0::m::O>>")) + .await + .unwrap_err(); + assert!(matches!(err, Error::ValueNesting(3))) + } + + #[tokio::test] + async fn test_err_value_nesting_type_param_application() { + let (_, cache) = package_cache([ + (1, build_package("iota"), iota_types()), + (1, build_package("d0"), d0_types()), + ]); + + let resolver = Resolver::new_with_limits( + cache, + Limits { + max_type_argument_width: 100, + max_type_argument_depth: 100, + max_type_nodes: 100, + max_move_value_depth: 3, + }, + ); + + // Make sure that even if all type parameters individually meet the depth + // requirements, that we correctly fail if they extend the layout's + // depth on application. + let err = resolver + .type_layout(type_("0xd0::m::O, u8>")) + .await + .unwrap_err(); + + assert!(matches!(err, Error::ValueNesting(3))) + } + + #[tokio::test] + async fn test_system_package_invalidation() { + let (inner, cache) = package_cache([(1, build_package("s0"), s0_types())]); + let resolver = Resolver::new(cache); + + let not_found = resolver.type_layout(type_("0x1::m::T1")).await.unwrap_err(); + assert!(matches!(not_found, Error::StructNotFound(_, _, _))); + + // Add a new version of the system package into the store underlying the cache. + inner.write().unwrap().replace( + addr("0x1"), + cached_package(2, BTreeMap::new(), &build_package("s1"), &s1_types()), + ); + + let layout = resolver.type_layout(type_("0x1::m::T1")).await.unwrap(); + insta::assert_snapshot!(format!("{layout:#}")); + } + + #[tokio::test] + async fn test_caching() { + let (inner, cache) = package_cache([ + (1, build_package("a0"), a0_types()), + (1, build_package("s0"), s0_types()), + ]); + let resolver = Resolver::new(cache); + + let stats = |inner: &Arc>| { + let i = inner.read().unwrap(); + (i.fetches, i.version_checks) + }; + + assert_eq!(stats(&inner), (0, 0)); + let l0 = resolver.type_layout(type_("0xa0::m::T0")).await.unwrap(); + + // Load A0. + assert_eq!(stats(&inner), (1, 0)); + + // Layouts are the same, no need to reload the package. Not a system package, + // so no version check needed. + let l1 = resolver.type_layout(type_("0xa0::m::T0")).await.unwrap(); + assert_eq!(format!("{l0}"), format!("{l1}")); + assert_eq!(stats(&inner), (1, 0)); + + // Different type, but same package, so no extra fetch. + let l2 = resolver.type_layout(type_("0xa0::m::T2")).await.unwrap(); + assert_ne!(format!("{l0}"), format!("{l2}")); + assert_eq!(stats(&inner), (1, 0)); + + // New package to load. It's a system package, which would need a version check + // if it already existed in the cache, but it doesn't yet, so we only + // see a fetch. + let l3 = resolver.type_layout(type_("0x1::m::T0")).await.unwrap(); + assert_eq!(stats(&inner), (2, 0)); + + // Reload the same system package type, which will cause a version check. + let l4 = resolver.type_layout(type_("0x1::m::T0")).await.unwrap(); + assert_eq!(format!("{l3}"), format!("{l4}")); + assert_eq!(stats(&inner), (2, 1)); + + // Upgrade the system package + inner.write().unwrap().replace( + addr("0x1"), + cached_package(2, BTreeMap::new(), &build_package("s1"), &s1_types()), + ); + + // Reload the same system type again. The version check fails and the system + // package is refetched (even though the type is the same as before). + // This usage pattern (layouts for system types) is why a layout cache + // would be particularly helpful (future optimisation). + let l5 = resolver.type_layout(type_("0x1::m::T0")).await.unwrap(); + assert_eq!(format!("{l4}"), format!("{l5}")); + assert_eq!(stats(&inner), (3, 2)); + } + + #[tokio::test] + async fn test_err_not_a_package() { + let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); + let resolver = Resolver::new(cache); + let err = resolver + .type_layout(type_("0x42::m::T0")) + .await + .unwrap_err(); + assert!(matches!(err, Error::PackageNotFound(_))); + } + + #[tokio::test] + async fn test_err_no_module() { + let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); + let resolver = Resolver::new(cache); + let err = resolver + .type_layout(type_("0xa0::l::T0")) + .await + .unwrap_err(); + assert!(matches!(err, Error::ModuleNotFound(_, _))); + } + + #[tokio::test] + async fn test_err_no_struct() { + let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); + let resolver = Resolver::new(cache); + + let err = resolver + .type_layout(type_("0xa0::m::T9")) + .await + .unwrap_err(); + assert!(matches!(err, Error::StructNotFound(_, _, _))); + } + + #[tokio::test] + async fn test_err_type_arity() { + let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); + let resolver = Resolver::new(cache); + + // Too few + let err = resolver + .type_layout(type_("0xa0::m::T1")) + .await + .unwrap_err(); + assert!(matches!(err, Error::TypeArityMismatch(2, 1))); + + // Too many + let err = resolver + .type_layout(type_("0xa0::m::T1")) + .await + .unwrap_err(); + assert!(matches!(err, Error::TypeArityMismatch(2, 3))); + } + + #[tokio::test] + async fn test_structs() { + let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); + let a0 = cache.fetch(addr("0xa0")).await.unwrap(); + let m = a0.module("m").unwrap(); + + assert_eq!( + m.structs(None, None).collect::>(), + vec!["T0", "T1", "T2"], + ); + + assert_eq!(m.structs(None, Some("T1")).collect::>(), vec!["T0"],); + + assert_eq!( + m.structs(Some("T0"), Some("T2")).collect::>(), + vec!["T1"], + ); + + assert_eq!(m.structs(Some("T1"), None).collect::>(), vec!["T2"],); + + let t0 = m.struct_def("T0").unwrap().unwrap(); + let t1 = m.struct_def("T1").unwrap().unwrap(); + let t2 = m.struct_def("T2").unwrap().unwrap(); + + insta::assert_snapshot!(format!( + "a0::m::T0: {t0:#?}\n\ + a0::m::T1: {t1:#?}\n\ + a0::m::T2: {t2:#?}", + )); + } + + #[tokio::test] + async fn test_functions() { + let (_, cache) = package_cache([ + (1, build_package("a0"), a0_types()), + (2, build_package("a1"), a1_types()), + (1, build_package("b0"), b0_types()), + (1, build_package("c0"), c0_types()), + ]); + + let c0 = cache.fetch(addr("0xc0")).await.unwrap(); + let m = c0.module("m").unwrap(); + + assert_eq!( + m.functions(None, None).collect::>(), + vec!["bar", "baz", "foo"], + ); + + assert_eq!( + m.functions(None, Some("baz")).collect::>(), + vec!["bar"], + ); + + assert_eq!( + m.functions(Some("bar"), Some("foo")).collect::>(), + vec!["baz"], + ); + + assert_eq!( + m.functions(Some("baz"), None).collect::>(), + vec!["foo"], + ); + + let foo = m.function_def("foo").unwrap().unwrap(); + let bar = m.function_def("bar").unwrap().unwrap(); + let baz = m.function_def("baz").unwrap().unwrap(); + + insta::assert_snapshot!(format!( + "c0::m::foo: {foo:#?}\n\ + c0::m::bar: {bar:#?}\n\ + c0::m::baz: {baz:#?}" + )); + } + + #[tokio::test] + async fn test_function_parameters() { + let (_, cache) = package_cache([ + (1, build_package("a0"), a0_types()), + (2, build_package("a1"), a1_types()), + (1, build_package("b0"), b0_types()), + (1, build_package("c0"), c0_types()), + ]); + + let resolver = Resolver::new(cache); + let c0 = addr("0xc0"); + + let foo = resolver.function_parameters(c0, "m", "foo").await.unwrap(); + let bar = resolver.function_parameters(c0, "m", "bar").await.unwrap(); + let baz = resolver.function_parameters(c0, "m", "baz").await.unwrap(); + + insta::assert_snapshot!(format!( + "c0::m::foo: {foo:#?}\n\ + c0::m::bar: {bar:#?}\n\ + c0::m::baz: {baz:#?}" + )); + } + + #[tokio::test] + async fn test_signature_instantiation() { + use OpenSignatureBody as O; + use TypeTag as T; + + let sig = O::Datatype( + key("0x2::table::Table"), + vec![ + O::TypeParameter(1), + O::Vector(Box::new(O::Datatype( + key("0x1::option::Option"), + vec![O::TypeParameter(0)], + ))), + ], + ); + + insta::assert_debug_snapshot!(sig.instantiate(&[T::U64, T::Bool]).unwrap()); + } + + #[tokio::test] + async fn test_signature_instantiation_error() { + use OpenSignatureBody as O; + use TypeTag as T; + + let sig = O::Datatype( + key("0x2::table::Table"), + vec![ + O::TypeParameter(1), + O::Vector(Box::new(O::Datatype( + key("0x1::option::Option"), + vec![O::TypeParameter(99)], + ))), + ], + ); + + insta::assert_display_snapshot!( + sig.instantiate(&[T::U64, T::Bool]).unwrap_err(), + @"Type Parameter 99 out of bounds (2)" + ); + } + + /// Primitive types should have the expected primitive abilities + #[tokio::test] + async fn test_primitive_abilities() { + use Ability as A; + use AbilitySet as S; + + let (_, cache) = package_cache([]); + let resolver = Resolver::new(cache); + + for prim in ["address", "bool", "u8", "u16", "u32", "u64", "u128", "u256"] { + assert_eq!( + resolver.abilities(type_(prim)).await.unwrap(), + S::EMPTY | A::Copy | A::Drop | A::Store, + "Unexpected primitive abilities for: {prim}", + ); + } + } + + /// Generic type abilities depend on the abilities of their type parameters. + #[tokio::test] + async fn test_simple_generic_abilities() { + use Ability as A; + use AbilitySet as S; + + let (_, cache) = package_cache([ + (1, build_package("iota"), iota_types()), + (1, build_package("d0"), d0_types()), + ]); + let resolver = Resolver::new(cache); + + let a1 = resolver + .abilities(type_("0xd0::m::T")) + .await + .unwrap(); + assert_eq!(a1, S::EMPTY | A::Copy | A::Drop | A::Store); + + let a2 = resolver + .abilities(type_("0xd0::m::T<0xd0::m::S, u64>")) + .await + .unwrap(); + assert_eq!(a2, S::EMPTY | A::Drop | A::Store); + + let a3 = resolver + .abilities(type_("0xd0::m::T<0xd0::m::R, 0xd0::m::S>")) + .await + .unwrap(); + assert_eq!(a3, S::EMPTY | A::Drop); + + let a4 = resolver + .abilities(type_("0xd0::m::T<0xd0::m::Q, 0xd0::m::R>")) + .await + .unwrap(); + assert_eq!(a4, S::EMPTY); + } + + /// Generic abilities also need to handle nested type parameters + #[tokio::test] + async fn test_nested_generic_abilities() { + use Ability as A; + use AbilitySet as S; + + let (_, cache) = package_cache([ + (1, build_package("iota"), iota_types()), + (1, build_package("d0"), d0_types()), + ]); + let resolver = Resolver::new(cache); + + let a1 = resolver + .abilities(type_("0xd0::m::T<0xd0::m::T<0xd0::m::R, u32>, u64>")) + .await + .unwrap(); + assert_eq!(a1, S::EMPTY | A::Copy | A::Drop); + } + + /// Key is different from other abilities in that it requires fields to have + /// `store`, rather than itself. + #[tokio::test] + async fn test_key_abilities() { + use Ability as A; + use AbilitySet as S; + + let (_, cache) = package_cache([ + (1, build_package("iota"), iota_types()), + (1, build_package("d0"), d0_types()), + ]); + let resolver = Resolver::new(cache); + + let a1 = resolver + .abilities(type_("0xd0::m::O")) + .await + .unwrap(); + assert_eq!(a1, S::EMPTY | A::Key | A::Store); + + let a2 = resolver + .abilities(type_("0xd0::m::O<0xd0::m::S, u64>")) + .await + .unwrap(); + assert_eq!(a2, S::EMPTY | A::Key | A::Store); + + // We would not be able to get an instance of this type, but in case the + // question is asked, its abilities would be empty. + let a3 = resolver + .abilities(type_("0xd0::m::O<0xd0::m::R, u64>")) + .await + .unwrap(); + assert_eq!(a3, S::EMPTY); + + // Key does not propagate up by itself, so this type is also uninhabitable. + let a4 = resolver + .abilities(type_("0xd0::m::O<0xd0::m::P, u32>")) + .await + .unwrap(); + assert_eq!(a4, S::EMPTY); + } + + /// Phantom types don't impact abilities + #[tokio::test] + async fn test_phantom_abilities() { + use Ability as A; + use AbilitySet as S; + + let (_, cache) = package_cache([ + (1, build_package("iota"), iota_types()), + (1, build_package("d0"), d0_types()), + ]); + let resolver = Resolver::new(cache); + + let a1 = resolver + .abilities(type_("0xd0::m::O")) + .await + .unwrap(); + assert_eq!(a1, S::EMPTY | A::Key | A::Store); + } + + #[tokio::test] + async fn test_err_ability_arity() { + let (_, cache) = package_cache([ + (1, build_package("iota"), iota_types()), + (1, build_package("d0"), d0_types()), + ]); + let resolver = Resolver::new(cache); + + // Too few + let err = resolver + .abilities(type_("0xd0::m::T")) + .await + .unwrap_err(); + assert!(matches!(err, Error::TypeArityMismatch(2, 1))); + + // Too many + let err = resolver + .abilities(type_("0xd0::m::T")) + .await + .unwrap_err(); + assert!(matches!(err, Error::TypeArityMismatch(2, 3))); + } + + #[tokio::test] + async fn test_err_ability_signer() { + let (_, cache) = package_cache([]); + let resolver = Resolver::new(cache); + + let err = resolver.abilities(type_("signer")).await.unwrap_err(); + assert!(matches!(err, Error::UnexpectedSigner)); + } + + #[tokio::test] + async fn test_err_too_many_type_params() { + let (_, cache) = package_cache([ + (1, build_package("iota"), iota_types()), + (1, build_package("d0"), d0_types()), + ]); + + let resolver = Resolver::new_with_limits( + cache, + Limits { + max_type_argument_width: 1, + max_type_argument_depth: 100, + max_type_nodes: 100, + max_move_value_depth: 100, + }, + ); + + let err = resolver + .abilities(type_("0xd0::m::O")) + .await + .unwrap_err(); + assert!(matches!(err, Error::TooManyTypeParams(1, 2))); + } + + #[tokio::test] + async fn test_err_too_many_type_nodes() { + use Ability as A; + use AbilitySet as S; + + let (_, cache) = package_cache([ + (1, build_package("iota"), iota_types()), + (1, build_package("d0"), d0_types()), + ]); + + let resolver = Resolver::new_with_limits( + cache, + Limits { + max_type_argument_width: 100, + max_type_argument_depth: 100, + max_type_nodes: 2, + max_move_value_depth: 100, + }, + ); + + // This request is OK, because one of O's type parameters is phantom, so we can + // avoid loading its definition. + let a1 = resolver + .abilities(type_("0xd0::m::O<0xd0::m::S, 0xd0::m::Q>")) + .await + .unwrap(); + assert_eq!(a1, S::EMPTY | A::Key | A::Store); + + // But this request will hit the limit + let err = resolver + .abilities(type_("0xd0::m::T<0xd0::m::P, 0xd0::m::Q>")) + .await + .unwrap_err(); + assert!(matches!(err, Error::TooManyTypeNodes(2, _))); + } + + #[tokio::test] + async fn test_err_type_param_nesting() { + use Ability as A; + use AbilitySet as S; + + let (_, cache) = package_cache([ + (1, build_package("iota"), iota_types()), + (1, build_package("d0"), d0_types()), + ]); + + let resolver = Resolver::new_with_limits( + cache, + Limits { + max_type_argument_width: 100, + max_type_argument_depth: 2, + max_type_nodes: 100, + max_move_value_depth: 100, + }, + ); + + // This request is OK, because one of O's type parameters is phantom, so we can + // avoid loading its definition. + let a1 = resolver + .abilities(type_( + "0xd0::m::O<0xd0::m::S, 0xd0::m::T, vector>>", + )) + .await + .unwrap(); + assert_eq!(a1, S::EMPTY | A::Key | A::Store); + + // But this request will hit the limit + let err = resolver + .abilities(type_("vector<0xd0::m::T<0xd0::m::O, u16>>")) + .await + .unwrap_err(); + assert!(matches!(err, Error::TypeParamNesting(2, _))); + } + + #[tokio::test] + async fn test_pure_input_layouts() { + use CallArg as I; + use ObjectArg::ImmOrOwnedObject as O; + use TypeTag as T; + + let (_, cache) = package_cache([ + (1, build_package("std"), std_types()), + (1, build_package("iota"), iota_types()), + (1, build_package("e0"), e0_types()), + ]); + + let resolver = Resolver::new(cache); + + // Helper function to generate a PTB calling 0xe0::m::foo. + fn ptb(t: TypeTag, y: CallArg) -> ProgrammableTransaction { + ProgrammableTransaction { + inputs: vec![ + I::Object(O(random_object_ref())), + I::Pure(bcs::to_bytes(&42u64).unwrap()), + I::Object(O(random_object_ref())), + y, + I::Object(O(random_object_ref())), + I::Pure(bcs::to_bytes("hello").unwrap()), + I::Pure(bcs::to_bytes("world").unwrap()), + ], + commands: vec![Command::MoveCall(Box::new(ProgrammableMoveCall { + package: addr("0xe0").into(), + module: ident_str!("m").to_owned(), + function: ident_str!("foo").to_owned(), + type_arguments: vec![t], + arguments: (0..=6).map(Argument::Input).collect(), + }))], + } + } + + let ptb_u64 = ptb(T::U64, I::Pure(bcs::to_bytes(&1u64).unwrap())); + + let ptb_opt = ptb( + TypeTag::Struct(Box::new(StructTag { + address: addr("0x1"), + module: ident_str!("option").to_owned(), + name: ident_str!("Option").to_owned(), + type_params: vec![TypeTag::U64], + })), + I::Pure(bcs::to_bytes(&[vec![1u64], vec![], vec![3]]).unwrap()), + ); + + let ptb_obj = ptb( + TypeTag::Struct(Box::new(StructTag { + address: addr("0xe0"), + module: ident_str!("m").to_owned(), + name: ident_str!("O").to_owned(), + type_params: vec![], + })), + I::Object(O(random_object_ref())), + ); + + let inputs_u64 = resolver.pure_input_layouts(&ptb_u64).await.unwrap(); + let inputs_opt = resolver.pure_input_layouts(&ptb_opt).await.unwrap(); + let inputs_obj = resolver.pure_input_layouts(&ptb_obj).await.unwrap(); + + // Make the output format a little nicer for the snapshot + let mut output = "---\n".to_string(); + for inputs in [inputs_u64, inputs_opt, inputs_obj] { + for input in inputs { + if let Some(layout) = input { + output += &format!("{layout:#}\n"); + } else { + output += "???\n"; + } + } + output += "---\n"; + } + + insta::assert_snapshot!(output); + } + + #[tokio::test] + async fn test_pure_input_layouts_conflicting() { + use CallArg as I; + use ObjectArg::ImmOrOwnedObject as O; + use TypeTag as T; + + let (_, cache) = package_cache([ + (1, build_package("std"), std_types()), + (1, build_package("iota"), iota_types()), + (1, build_package("e0"), e0_types()), + ]); + + let resolver = Resolver::new(cache); + + let ptb = ProgrammableTransaction { + inputs: vec![ + I::Object(O(random_object_ref())), + I::Pure(bcs::to_bytes(&42u64).unwrap()), + I::Object(O(random_object_ref())), + I::Pure(bcs::to_bytes(&43u64).unwrap()), + I::Object(O(random_object_ref())), + I::Pure(bcs::to_bytes("hello").unwrap()), + I::Pure(bcs::to_bytes("world").unwrap()), + ], + commands: vec![ + Command::MoveCall(Box::new(ProgrammableMoveCall { + package: addr("0xe0").into(), + module: ident_str!("m").to_owned(), + function: ident_str!("foo").to_owned(), + type_arguments: vec![T::U64], + arguments: (0..=6).map(Argument::Input).collect(), + })), + // This command is using the input that was previously used as a U64, but now as a + // U32, which will cause an error. + Command::MakeMoveVec(Some(T::U32), vec![Argument::Input(3)]), + ], + }; + + insta::assert_display_snapshot!( + resolver.pure_input_layouts(&ptb).await.unwrap_err(), + @"Conflicting types for input 3: u64 and u32" + ); + } + + /// *** Test Helpers + /// ************************************************************************ + /// ** + + type TypeOriginTable = Vec; + + fn a0_types() -> TypeOriginTable { + vec![ + struct_("0xa0", "m", "T0"), + struct_("0xa0", "m", "T1"), + struct_("0xa0", "m", "T2"), + struct_("0xa0", "n", "T0"), + ] + } + + fn a1_types() -> TypeOriginTable { + let mut types = a0_types(); + + types.extend([ + struct_("0xa1", "m", "T3"), + struct_("0xa1", "m", "T4"), + struct_("0xa1", "n", "T1"), + ]); + + types + } + + fn b0_types() -> TypeOriginTable { + vec![struct_("0xb0", "m", "T0")] + } + + fn c0_types() -> TypeOriginTable { + vec![struct_("0xc0", "m", "T0")] + } + + fn d0_types() -> TypeOriginTable { + vec![ + struct_("0xd0", "m", "O"), + struct_("0xd0", "m", "P"), + struct_("0xd0", "m", "Q"), + struct_("0xd0", "m", "R"), + struct_("0xd0", "m", "S"), + struct_("0xd0", "m", "T"), + ] + } + + fn e0_types() -> TypeOriginTable { + vec![struct_("0xe0", "m", "O")] + } + + fn s0_types() -> TypeOriginTable { + vec![struct_("0x1", "m", "T0")] + } + + fn s1_types() -> TypeOriginTable { + let mut types = s0_types(); + + types.extend([struct_("0x1", "m", "T1")]); + + types + } + + fn iota_types() -> TypeOriginTable { + vec![struct_("0x2", "object", "UID")] + } + + fn std_types() -> TypeOriginTable { + vec![ + struct_("0x1", "ascii", "String"), + struct_("0x1", "option", "Option"), + struct_("0x1", "string", "String"), + ] + } + + /// Build an in-memory package cache from locally compiled packages. + /// Assumes that all packages in `packages` are published (all modules + /// have a non-zero package address and all packages + /// have a 'published-at' address), and their transitive dependencies are + /// also in `packages`. + fn package_cache( + packages: impl IntoIterator, + ) -> (Arc>, Box) { + let packages_by_storage_id: BTreeMap = packages + .into_iter() + .map(|(version, package, origins)| { + (package_storage_id(&package), (version, package, origins)) + }) + .collect(); + + let packages = packages_by_storage_id + .iter() + .map(|(&storage_id, (version, compiled_package, origins))| { + let linkage = compiled_package + .dependency_ids + .published + .values() + .map(|dep_id| { + let storage_id = AccountAddress::from(*dep_id); + let runtime_id = package_runtime_id( + &packages_by_storage_id + .get(&storage_id) + .unwrap_or_else(|| panic!("Dependency {storage_id} not in store")) + .1, + ); + + (runtime_id, storage_id) + }) + .collect(); + + let package = cached_package(*version, linkage, compiled_package, origins); + (storage_id, package) + }) + .collect(); + + let inner = Arc::new(RwLock::new(InnerStore { + packages, + fetches: 0, + version_checks: 0, + })); + + let store = InMemoryPackageStore { + inner: inner.clone(), + }; + + let store_with_cache = PackageStoreWithLruCache::new(store); + + (inner, Box::new(store_with_cache)) + } + + fn cached_package( + version: u64, + linkage: Linkage, + package: &CompiledPackage, + origins: &TypeOriginTable, + ) -> Package { + let storage_id = package_storage_id(package); + let runtime_id = package_runtime_id(package); + let version = SequenceNumber::from_u64(version); + + let mut modules = BTreeMap::new(); + for unit in &package.package.root_compiled_units { + let NamedCompiledModule { name, module, .. } = &unit.unit; + + let origins = origins + .iter() + .filter(|key| key.module == name.as_str()) + .map(|key| (key.name.to_string(), key.package)) + .collect(); + + let module = match Module::read(module.clone(), origins) { + Ok(module) => module, + Err(struct_) => { + panic!("Missing type origin for {}::{struct_}", module.self_id()); + } + }; + + modules.insert(name.to_string(), module); + } + + Package { + storage_id, + runtime_id, + linkage, + version, + modules, + } + } + + fn package_storage_id(package: &CompiledPackage) -> AccountAddress { + AccountAddress::from(*package.published_at.as_ref().unwrap_or_else(|_| { + panic!( + "Package {} doesn't have published-at set", + package.package.compiled_package_info.package_name, + ) + })) + } + + fn package_runtime_id(package: &CompiledPackage) -> AccountAddress { + *package + .published_root_module() + .expect("No compiled module") + .address() + } + + fn build_package(dir: &str) -> CompiledPackage { + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.extend(["tests", "packages", dir]); + BuildConfig::new_for_testing().build(path).unwrap() + } + + fn addr(a: &str) -> AccountAddress { + AccountAddress::from_str(a).unwrap() + } + + fn struct_(a: &str, m: &'static str, n: &'static str) -> DatatypeKey { + DatatypeKey { + package: addr(a), + module: m.into(), + name: n.into(), + } + } + + fn type_(t: &str) -> TypeTag { + TypeTag::from_str(t).unwrap() + } + + fn key(t: &str) -> DatatypeKey { + let tag = StructTag::from_str(t).unwrap(); + DatatypeRef::from(&tag).as_key() + } + + struct InMemoryPackageStore { + /// All the contents are stored in an `InnerStore` that can be probed + /// and queried from outside. + inner: Arc>, + } + + struct InnerStore { + packages: BTreeMap, + fetches: usize, + version_checks: usize, + } + + #[async_trait] + impl PackageStore for InMemoryPackageStore { + async fn version(&self, id: AccountAddress) -> Result { + let mut inner = self.inner.as_ref().write().unwrap(); + inner.version_checks += 1; + inner + .packages + .get(&id) + .ok_or_else(|| Error::PackageNotFound(id)) + .map(|p| p.version) + } + + async fn fetch(&self, id: AccountAddress) -> Result> { + let mut inner = self.inner.as_ref().write().unwrap(); + inner.fetches += 1; + inner + .packages + .get(&id) + .cloned() + .ok_or_else(|| Error::PackageNotFound(id)) + .map(Arc::new) + } + } + + impl InnerStore { + fn replace(&mut self, id: AccountAddress, package: Package) { + self.packages.insert(id, package); + } + } +} diff --git a/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__cross_module.snap b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__cross_module.snap new file mode 100644 index 00000000000..56ea337a9e8 --- /dev/null +++ b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__cross_module.snap @@ -0,0 +1,14 @@ +--- +source: crates/iota-package-resolver/src/lib.rs +expression: "format!(\"{layout:#}\")" +--- +struct 0xa0::n::T0 { + t: struct 0xa0::m::T1 { + a: address, + p: u16, + q: vector, + }, + u: struct 0xa0::m::T2 { + x: u8, + }, +} diff --git a/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__cross_package.snap b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__cross_package.snap new file mode 100644 index 00000000000..ecf1472aa24 --- /dev/null +++ b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__cross_package.snap @@ -0,0 +1,19 @@ +--- +source: crates/iota-package-resolver/src/lib.rs +expression: "format!(\"{layout:#}\")" +--- +struct 0xb0::m::T0 { + m: struct 0xa0::m::T2 { + x: u8, + }, + n: struct 0xa0::n::T0 { + t: struct 0xa0::m::T1 { + a: address, + p: u16, + q: vector, + }, + u: struct 0xa0::m::T2 { + x: u8, + }, + }, +} diff --git a/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__function_parameters.snap b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__function_parameters.snap new file mode 100644 index 00000000000..fd1352e3c80 --- /dev/null +++ b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__function_parameters.snap @@ -0,0 +1,39 @@ +--- +source: crates/iota-package-resolver/src/lib.rs +expression: "format!(\"c0::m::foo: {foo:#?}\\n\\\n c0::m::bar: {bar:#?}\\n\\\n c0::m::baz: {baz:#?}\")" +--- +c0::m::foo: [] +c0::m::bar: [ + OpenSignature { + ref_: Some( + Immutable, + ), + body: Datatype( + DatatypeRef { + package: 00000000000000000000000000000000000000000000000000000000000000c0, + module: "m", + name: "T0", + }, + [], + ), + }, + OpenSignature { + ref_: Some( + Mutable, + ), + body: Datatype( + DatatypeRef { + package: 00000000000000000000000000000000000000000000000000000000000000a1, + module: "n", + name: "T1", + }, + [], + ), + }, +] +c0::m::baz: [ + OpenSignature { + ref_: None, + body: U8, + }, +] diff --git a/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__functions.snap b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__functions.snap new file mode 100644 index 00000000000..1469b485a85 --- /dev/null +++ b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__functions.snap @@ -0,0 +1,71 @@ +--- +source: crates/iota-package-resolver/src/lib.rs +expression: "format!(\"c0::m::foo: {foo:#?}\\n\\\n c0::m::bar: {bar:#?}\\n\\\n c0::m::baz: {baz:#?}\")" +--- +c0::m::foo: FunctionDef { + visibility: Public, + is_entry: false, + type_params: [], + parameters: [], + return_: [], +} +c0::m::bar: FunctionDef { + visibility: Friend, + is_entry: false, + type_params: [], + parameters: [ + OpenSignature { + ref_: Some( + Immutable, + ), + body: Datatype( + DatatypeRef { + package: 00000000000000000000000000000000000000000000000000000000000000c0, + module: "m", + name: "T0", + }, + [], + ), + }, + OpenSignature { + ref_: Some( + Mutable, + ), + body: Datatype( + DatatypeRef { + package: 00000000000000000000000000000000000000000000000000000000000000a0, + module: "n", + name: "T1", + }, + [], + ), + }, + ], + return_: [ + OpenSignature { + ref_: None, + body: U64, + }, + ], +} +c0::m::baz: FunctionDef { + visibility: Private, + is_entry: false, + type_params: [], + parameters: [ + OpenSignature { + ref_: None, + body: U8, + }, + ], + return_: [ + OpenSignature { + ref_: None, + body: U16, + }, + OpenSignature { + ref_: None, + body: U32, + }, + ], +} diff --git a/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__multiple_linkage_contexts.snap b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__multiple_linkage_contexts.snap new file mode 100644 index 00000000000..f4812b7c8e3 --- /dev/null +++ b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__multiple_linkage_contexts.snap @@ -0,0 +1,20 @@ +--- +source: crates/iota-package-resolver/src/lib.rs +expression: "format!(\"{layout:#}\")" +--- +struct 0xa0::m::T1<0xa0::m::T0, 0xa1::m::T3> { + a: address, + p: struct 0xa0::m::T0 { + b: bool, + v: vector { + a: address, + p: struct 0xa0::m::T2 { + x: u8, + }, + q: vector, + }>, + }, + q: vector, +} diff --git a/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__pure_input_layouts.snap b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__pure_input_layouts.snap new file mode 100644 index 00000000000..54dab3d9eeb --- /dev/null +++ b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__pure_input_layouts.snap @@ -0,0 +1,56 @@ +--- +source: crates/iota-package-resolver/src/lib.rs +expression: output +--- +--- +??? +u64 +??? +u64 +??? +struct 0x1::option::Option<0x1::string::String> { + vec: vector, + }>, +} +vector { + vec: vector, + }>, +}> +--- +??? +u64 +??? +struct 0x1::option::Option { + vec: vector, +} +??? +struct 0x1::option::Option<0x1::string::String> { + vec: vector, + }>, +} +vector { + vec: vector, + }>, +}> +--- +??? +u64 +??? +??? +??? +struct 0x1::option::Option<0x1::string::String> { + vec: vector, + }>, +} +vector { + vec: vector, + }>, +}> +--- + diff --git a/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__relinking.snap b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__relinking.snap new file mode 100644 index 00000000000..c1a6cb9a5f1 --- /dev/null +++ b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__relinking.snap @@ -0,0 +1,49 @@ +--- +source: crates/iota-package-resolver/src/lib.rs +expression: "format!(\"{layout:#}\")" +--- +struct 0xc0::m::T0 { + t: struct 0xa0::n::T0 { + t: struct 0xa0::m::T1 { + a: address, + p: u16, + q: vector, + }, + u: struct 0xa0::m::T2 { + x: u8, + }, + }, + u: struct 0xa1::n::T1 { + t: struct 0xa0::m::T1<0xa1::m::T3, u32> { + a: address, + p: struct 0xa1::m::T3 { + y: u16, + }, + q: vector, + }, + u: struct 0xa1::m::T4 { + z: u32, + }, + }, + v: struct 0xa0::m::T2 { + x: u8, + }, + w: struct 0xa1::m::T3 { + y: u16, + }, + x: struct 0xb0::m::T0 { + m: struct 0xa0::m::T2 { + x: u8, + }, + n: struct 0xa0::n::T0 { + t: struct 0xa0::m::T1 { + a: address, + p: u16, + q: vector, + }, + u: struct 0xa0::m::T2 { + x: u8, + }, + }, + }, +} diff --git a/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__signature_instantiation.snap b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__signature_instantiation.snap new file mode 100644 index 00000000000..46a75230b62 --- /dev/null +++ b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__signature_instantiation.snap @@ -0,0 +1,34 @@ +--- +source: crates/iota-package-resolver/src/lib.rs +expression: "sig.instantiate(&[T::U64, T::Bool]).unwrap()" +--- +Struct( + StructTag { + address: 0000000000000000000000000000000000000000000000000000000000000002, + module: Identifier( + "table", + ), + name: Identifier( + "Table", + ), + type_params: [ + Bool, + Vector( + Struct( + StructTag { + address: 0000000000000000000000000000000000000000000000000000000000000001, + module: Identifier( + "option", + ), + name: Identifier( + "Option", + ), + type_params: [ + U64, + ], + }, + ), + ), + ], + }, +) diff --git a/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__simple_type.snap b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__simple_type.snap new file mode 100644 index 00000000000..09992a5b4d4 --- /dev/null +++ b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__simple_type.snap @@ -0,0 +1,14 @@ +--- +source: crates/iota-package-resolver/src/lib.rs +expression: "format!(\"{layout:#}\")" +--- +struct 0xa0::m::T0 { + b: bool, + v: vector { + a: address, + p: struct 0xa0::m::T2 { + x: u8, + }, + q: vector, + }>, +} diff --git a/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__structs.snap b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__structs.snap new file mode 100644 index 00000000000..c19ca3fdc47 --- /dev/null +++ b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__structs.snap @@ -0,0 +1,83 @@ +--- +source: crates/iota-package-resolver/src/lib.rs +expression: "format!(\"a0::m::T0: {t0:#?}\\n\\\n a0::m::T1: {t1:#?}\\n\\\n a0::m::T2: {t2:#?}\",)" +--- +a0::m::T0: StructDef { + defining_id: 00000000000000000000000000000000000000000000000000000000000000a0, + abilities: [], + type_params: [], + fields: [ + ( + "b", + Bool, + ), + ( + "v", + Vector( + Datatype( + DatatypeRef { + package: 00000000000000000000000000000000000000000000000000000000000000a0, + module: "m", + name: "T1", + }, + [ + Datatype( + DatatypeRef { + package: 00000000000000000000000000000000000000000000000000000000000000a0, + module: "m", + name: "T2", + }, + [], + ), + U128, + ], + ), + ), + ), + ], +} +a0::m::T1: StructDef { + defining_id: 00000000000000000000000000000000000000000000000000000000000000a0, + abilities: [], + type_params: [ + StructTypeParameter { + constraints: [], + is_phantom: false, + }, + StructTypeParameter { + constraints: [], + is_phantom: false, + }, + ], + fields: [ + ( + "a", + Address, + ), + ( + "p", + TypeParameter( + 0, + ), + ), + ( + "q", + Vector( + TypeParameter( + 1, + ), + ), + ), + ], +} +a0::m::T2: StructDef { + defining_id: 00000000000000000000000000000000000000000000000000000000000000a0, + abilities: [], + type_params: [], + fields: [ + ( + "x", + U8, + ), + ], +} diff --git a/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__system_package_invalidation.snap b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__system_package_invalidation.snap new file mode 100644 index 00000000000..698891c5922 --- /dev/null +++ b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__system_package_invalidation.snap @@ -0,0 +1,7 @@ +--- +source: crates/iota-package-resolver/src/lib.rs +expression: "format!(\"{layout:#}\")" +--- +struct 0x1::m::T1 { + x: u256, +} diff --git a/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__upgraded_package.snap b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__upgraded_package.snap new file mode 100644 index 00000000000..6a593d824fa --- /dev/null +++ b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__upgraded_package.snap @@ -0,0 +1,16 @@ +--- +source: crates/iota-package-resolver/src/lib.rs +expression: "format!(\"{layout:#}\")" +--- +struct 0xa1::n::T1 { + t: struct 0xa0::m::T1<0xa1::m::T3, u32> { + a: address, + p: struct 0xa1::m::T3 { + y: u16, + }, + q: vector, + }, + u: struct 0xa1::m::T4 { + z: u32, + }, +} diff --git a/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__upgraded_package_non_defining_id.snap b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__upgraded_package_non_defining_id.snap new file mode 100644 index 00000000000..40da9670aa4 --- /dev/null +++ b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__upgraded_package_non_defining_id.snap @@ -0,0 +1,20 @@ +--- +source: crates/iota-package-resolver/src/lib.rs +expression: "format!(\"{layout:#}\")" +--- +struct 0xa0::m::T1<0xa1::m::T3, 0xa0::m::T0> { + a: address, + p: struct 0xa1::m::T3 { + y: u16, + }, + q: vector { + a: address, + p: struct 0xa0::m::T2 { + x: u8, + }, + q: vector, + }>, + }>, +} diff --git a/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__value_nesting_boundary.snap b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__value_nesting_boundary.snap new file mode 100644 index 00000000000..4a0ac078d5f --- /dev/null +++ b/crates/iota-package-resolver/src/snapshots/iota_package_resolver__tests__value_nesting_boundary.snap @@ -0,0 +1,9 @@ +--- +source: crates/iota-package-resolver/src/lib.rs +expression: "format!(\"{layout:#}\")" +--- +struct 0xa0::m::T1 { + a: address, + p: u8, + q: vector, +} diff --git a/crates/sui-package-resolver/tests/packages/a0/Move.toml b/crates/iota-package-resolver/tests/packages/a0/Move.toml similarity index 100% rename from crates/sui-package-resolver/tests/packages/a0/Move.toml rename to crates/iota-package-resolver/tests/packages/a0/Move.toml diff --git a/crates/iota-package-resolver/tests/packages/a0/sources/m.move b/crates/iota-package-resolver/tests/packages/a0/sources/m.move new file mode 100644 index 00000000000..2006fd05f02 --- /dev/null +++ b/crates/iota-package-resolver/tests/packages/a0/sources/m.move @@ -0,0 +1,21 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_field)] +module a::m { + struct T0 { + b: bool, + v: vector>, + } + + struct T1 { + a: address, + p: P0, + q: vector, + } + + struct T2 { + x: u8, + } +} diff --git a/crates/iota-package-resolver/tests/packages/a0/sources/n.move b/crates/iota-package-resolver/tests/packages/a0/sources/n.move new file mode 100644 index 00000000000..63a128250c3 --- /dev/null +++ b/crates/iota-package-resolver/tests/packages/a0/sources/n.move @@ -0,0 +1,11 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_field)] +module a::n { + struct T0 { + t: a::m::T1, + u: a::m::T2, + } +} diff --git a/crates/sui-package-resolver/tests/packages/a1/Move.toml b/crates/iota-package-resolver/tests/packages/a1/Move.toml similarity index 100% rename from crates/sui-package-resolver/tests/packages/a1/Move.toml rename to crates/iota-package-resolver/tests/packages/a1/Move.toml diff --git a/crates/iota-package-resolver/tests/packages/a1/sources/m.move b/crates/iota-package-resolver/tests/packages/a1/sources/m.move new file mode 100644 index 00000000000..eb6b8c07303 --- /dev/null +++ b/crates/iota-package-resolver/tests/packages/a1/sources/m.move @@ -0,0 +1,29 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_field)] +module a::m { + struct T0 { + b: bool, + v: vector>, + } + + struct T1 { + a: address, + p: P0, + q: vector, + } + + struct T2 { + x: u8, + } + + struct T3 { + y: u16, + } + + struct T4 { + z: u32, + } +} diff --git a/crates/iota-package-resolver/tests/packages/a1/sources/n.move b/crates/iota-package-resolver/tests/packages/a1/sources/n.move new file mode 100644 index 00000000000..309f1b0b0e3 --- /dev/null +++ b/crates/iota-package-resolver/tests/packages/a1/sources/n.move @@ -0,0 +1,16 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_field)] +module a::n { + struct T0 { + t: a::m::T1, + u: a::m::T2, + } + + struct T1 { + t: a::m::T1, + u: a::m::T4, + } +} diff --git a/crates/sui-package-resolver/tests/packages/b0/Move.toml b/crates/iota-package-resolver/tests/packages/b0/Move.toml similarity index 100% rename from crates/sui-package-resolver/tests/packages/b0/Move.toml rename to crates/iota-package-resolver/tests/packages/b0/Move.toml diff --git a/crates/iota-package-resolver/tests/packages/b0/sources/m.move b/crates/iota-package-resolver/tests/packages/b0/sources/m.move new file mode 100644 index 00000000000..2793c770dc1 --- /dev/null +++ b/crates/iota-package-resolver/tests/packages/b0/sources/m.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_field)] +module b::m { + use a::m::T2 as M; + use a::n::T0 as N; + + struct T0 { + m: M, + n: N, + } +} diff --git a/crates/sui-package-resolver/tests/packages/c0/Move.toml b/crates/iota-package-resolver/tests/packages/c0/Move.toml similarity index 100% rename from crates/sui-package-resolver/tests/packages/c0/Move.toml rename to crates/iota-package-resolver/tests/packages/c0/Move.toml diff --git a/crates/iota-package-resolver/tests/packages/c0/sources/m.move b/crates/iota-package-resolver/tests/packages/c0/sources/m.move new file mode 100644 index 00000000000..03ca4b777d4 --- /dev/null +++ b/crates/iota-package-resolver/tests/packages/c0/sources/m.move @@ -0,0 +1,21 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module c::m { + #[allow(unused_field)] + struct T0 { + t: a::n::T0, + u: a::n::T1, + v: a::m::T2, + w: a::m::T3, + x: b::m::T0, + } + + public fun foo() {} + + public(friend) fun bar(_t0: &T0, _t1: &mut a::n::T1): u64 { 42 } + + #[allow(unused_function)] + fun baz(x: u8): (u16, u32) { ((x as u16), (x as u32)) } +} diff --git a/crates/iota-package-resolver/tests/packages/d0/Move.toml b/crates/iota-package-resolver/tests/packages/d0/Move.toml new file mode 100644 index 00000000000..8192b90dff2 --- /dev/null +++ b/crates/iota-package-resolver/tests/packages/d0/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "D" +version = "0.0.1" +published-at = "0xd0" + +[dependencies] +Iota = { local = "../iota" } + +[addresses] +d = "0xd0" diff --git a/crates/iota-package-resolver/tests/packages/d0/sources/m.move b/crates/iota-package-resolver/tests/packages/d0/sources/m.move new file mode 100644 index 00000000000..ff48c326bb3 --- /dev/null +++ b/crates/iota-package-resolver/tests/packages/d0/sources/m.move @@ -0,0 +1,24 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_field)] +module d::m { + use iota::object::UID; + + struct O has key, store { + id: UID, + xs: vector, + } + + + struct T has copy, drop, store { + u: U, + v: V, + } + + struct P has key { id: UID } + struct Q { x: u32 } + struct R has copy, drop { x: u16 } + struct S has drop, store { x: u8 } +} diff --git a/crates/iota-package-resolver/tests/packages/e0/Move.toml b/crates/iota-package-resolver/tests/packages/e0/Move.toml new file mode 100644 index 00000000000..d5f5991a401 --- /dev/null +++ b/crates/iota-package-resolver/tests/packages/e0/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "E" +version = "0.0.1" +published-at = "0xe0" + +[dependencies] +Iota = { local = "../iota" } +StdLib = { local = "../std" } + +[addresses] +e = "0xe0" diff --git a/crates/iota-package-resolver/tests/packages/e0/sources/m.move b/crates/iota-package-resolver/tests/packages/e0/sources/m.move new file mode 100644 index 00000000000..9cf075605ee --- /dev/null +++ b/crates/iota-package-resolver/tests/packages/e0/sources/m.move @@ -0,0 +1,23 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_field)] +module e::m { + use std::ascii::String as ASCII; + use std::option::Option; + use std::string::String as UTF8; + use iota::object::UID; + + struct O has key { id: UID } + + public native fun foo( + o: &O, + x: u64, + p: &mut O, + y: T, + q: O, + z: Option, + w: vector>, + ); +} diff --git a/crates/iota-package-resolver/tests/packages/iota/Move.toml b/crates/iota-package-resolver/tests/packages/iota/Move.toml new file mode 100644 index 00000000000..aa083427f2d --- /dev/null +++ b/crates/iota-package-resolver/tests/packages/iota/Move.toml @@ -0,0 +1,7 @@ +[package] +name = "Iota" +version = "0.0.1" +published-at = "0x2" + +[addresses] +iota = "0x2" diff --git a/crates/iota-package-resolver/tests/packages/iota/sources/object.move b/crates/iota-package-resolver/tests/packages/iota/sources/object.move new file mode 100644 index 00000000000..a95ad401da4 --- /dev/null +++ b/crates/iota-package-resolver/tests/packages/iota/sources/object.move @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_field)] +module iota::object { + /// A test version of the UID type to allow us to have types with + /// `key` in these test packages. It has a different structure to + /// the real UID, but that is not relevant. + struct UID has store { + id: address, + } +} diff --git a/crates/sui-package-resolver/tests/packages/s0/Move.toml b/crates/iota-package-resolver/tests/packages/s0/Move.toml similarity index 100% rename from crates/sui-package-resolver/tests/packages/s0/Move.toml rename to crates/iota-package-resolver/tests/packages/s0/Move.toml diff --git a/crates/iota-package-resolver/tests/packages/s0/sources/m.move b/crates/iota-package-resolver/tests/packages/s0/sources/m.move new file mode 100644 index 00000000000..52884ca9bd6 --- /dev/null +++ b/crates/iota-package-resolver/tests/packages/s0/sources/m.move @@ -0,0 +1,10 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_field)] +module s::m { + struct T0 { + x: u64 + } +} diff --git a/crates/sui-package-resolver/tests/packages/s1/Move.toml b/crates/iota-package-resolver/tests/packages/s1/Move.toml similarity index 100% rename from crates/sui-package-resolver/tests/packages/s1/Move.toml rename to crates/iota-package-resolver/tests/packages/s1/Move.toml diff --git a/crates/iota-package-resolver/tests/packages/s1/sources/m.move b/crates/iota-package-resolver/tests/packages/s1/sources/m.move new file mode 100644 index 00000000000..7f9d1568f3e --- /dev/null +++ b/crates/iota-package-resolver/tests/packages/s1/sources/m.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_field)] +module s::m { + struct T0 { + x: u64 + } + + struct T1 { + x: u256 + } +} diff --git a/crates/sui-package-resolver/tests/packages/std/Move.toml b/crates/iota-package-resolver/tests/packages/std/Move.toml similarity index 100% rename from crates/sui-package-resolver/tests/packages/std/Move.toml rename to crates/iota-package-resolver/tests/packages/std/Move.toml diff --git a/crates/sui-package-resolver/tests/packages/std/sources/std.move b/crates/iota-package-resolver/tests/packages/std/sources/std.move similarity index 90% rename from crates/sui-package-resolver/tests/packages/std/sources/std.move rename to crates/iota-package-resolver/tests/packages/std/sources/std.move index 9be5cf76669..076a43b013a 100644 --- a/crates/sui-package-resolver/tests/packages/std/sources/std.move +++ b/crates/iota-package-resolver/tests/packages/std/sources/std.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[allow(unused_field)] diff --git a/crates/iota-proc-macros/Cargo.toml b/crates/iota-proc-macros/Cargo.toml new file mode 100644 index 00000000000..90adaaec093 --- /dev/null +++ b/crates/iota-proc-macros/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "iota-proc-macros" +version = "0.7.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +quote.workspace = true +syn = { version = "2", features = ["full", "fold", "extra-traits"] } +proc-macro2.workspace = true +iota-enum-compat-util.workspace = true + +[target.'cfg(msim)'.dependencies] +msim-macros.workspace = true diff --git a/crates/iota-proc-macros/src/lib.rs b/crates/iota-proc-macros/src/lib.rs new file mode 100644 index 00000000000..a3eb6b0ec6b --- /dev/null +++ b/crates/iota-proc-macros/src/lib.rs @@ -0,0 +1,591 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use proc_macro::TokenStream; +use quote::{quote, quote_spanned, ToTokens}; +use syn::{ + fold::{fold_expr, fold_item_macro, fold_stmt, Fold}, + parse::Parser, + parse2, parse_macro_input, + punctuated::Punctuated, + spanned::Spanned, + Attribute, BinOp, Data, DataEnum, DeriveInput, Expr, ExprBinary, ExprMacro, Item, ItemMacro, + Stmt, StmtMacro, Token, UnOp, +}; + +#[proc_macro_attribute] +pub fn init_static_initializers(_args: TokenStream, item: TokenStream) -> TokenStream { + let mut input = parse_macro_input!(item as syn::ItemFn); + + let body = &input.block; + input.block = syn::parse2(quote! { + { + // We have some lazily-initialized static state in the program. The initializers + // alter the thread-local hash container state any time they create a new hash + // container. Therefore, we need to ensure that these initializers are run in a + // separate thread before the first test thread is launched. Otherwise, they would + // run inside of the first test thread, but not subsequent ones. + // + // Note that none of this has any effect on process-level determinism. Without this + // code, we can still get the same test results from two processes started with the + // same seed. + // + // However, when using sim_test(check_determinism) or MSIM_TEST_CHECK_DETERMINISM=1, + // we want the same test invocation to be deterministic when run twice + // _in the same process_, so we need to take care of this. This will also + // be very important for being able to reproduce a failure that occurs in the Nth + // iteration of a multi-iteration test run. + std::thread::spawn(|| { + use iota_protocol_config::ProtocolConfig; + ::iota_simulator::telemetry_subscribers::init_for_testing(); + ::iota_simulator::iota_types::execution::get_denied_certificates(); + ::iota_simulator::iota_framework::BuiltInFramework::all_package_ids(); + ::iota_simulator::iota_types::gas::IotaGasStatus::new_unmetered(); + + // For reasons I can't understand, LruCache causes divergent behavior the second + // time one is constructed and inserted into, so construct one before the first + // test run for determinism. + let mut cache = ::iota_simulator::lru::LruCache::new(1.try_into().unwrap()); + cache.put(1, 1); + + { + // Initialize the static initializers here: + // https://github.com/move-language/move/blob/652badf6fd67e1d4cc2aa6dc69d63ad14083b673/language/tools/move-package/src/package_lock.rs#L12 + use std::path::PathBuf; + use iota_simulator::iota_move_build::{BuildConfig, IotaPackageHooks}; + use iota_simulator::tempfile::TempDir; + use iota_simulator::move_package::package_hooks::register_package_hooks; + + register_package_hooks(Box::new(IotaPackageHooks {})); + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.extend(["..", "..", "iota_programmability", "examples", "basics"]); + let mut build_config = BuildConfig::default(); + + build_config.config.install_dir = Some(TempDir::new().unwrap().into_path()); + let _all_module_bytes = build_config + .build(path) + .unwrap() + .get_package_bytes(/* with_unpublished_deps */ false); + } + + + use ::iota_simulator::anemo_tower::callback::CallbackLayer; + use ::iota_simulator::anemo_tower::trace::DefaultMakeSpan; + use ::iota_simulator::anemo_tower::trace::DefaultOnFailure; + use ::iota_simulator::anemo_tower::trace::TraceLayer; + use ::iota_simulator::narwhal_network::metrics::MetricsMakeCallbackHandler; + use ::iota_simulator::narwhal_network::metrics::NetworkMetrics; + + use std::sync::Arc; + use ::iota_simulator::fastcrypto::traits::KeyPair; + use ::iota_simulator::rand_crate::rngs::{StdRng, OsRng}; + use ::iota_simulator::rand::SeedableRng; + use ::iota_simulator::tower::ServiceBuilder; + + // anemo uses x509-parser, which has many lazy static variables. start a network to + // initialize all that static state before the first test. + let rt = ::iota_simulator::runtime::Runtime::new(); + rt.block_on(async move { + use ::iota_simulator::anemo::{Network, Request}; + + let make_network = |port: u16| { + let registry = prometheus::Registry::new(); + let inbound_network_metrics = + NetworkMetrics::new("iota", "inbound", ®istry); + let outbound_network_metrics = + NetworkMetrics::new("iota", "outbound", ®istry); + + let service = ServiceBuilder::new() + .layer( + TraceLayer::new_for_server_errors() + .make_span_with(DefaultMakeSpan::new().level(tracing::Level::INFO)) + .on_failure(DefaultOnFailure::new().level(tracing::Level::WARN)), + ) + .layer(CallbackLayer::new(MetricsMakeCallbackHandler::new( + Arc::new(inbound_network_metrics), + usize::MAX, + ))) + .service(::iota_simulator::anemo::Router::new()); + + let outbound_layer = ServiceBuilder::new() + .layer( + TraceLayer::new_for_client_and_server_errors() + .make_span_with(DefaultMakeSpan::new().level(tracing::Level::INFO)) + .on_failure(DefaultOnFailure::new().level(tracing::Level::WARN)), + ) + .layer(CallbackLayer::new(MetricsMakeCallbackHandler::new( + Arc::new(outbound_network_metrics), + usize::MAX, + ))) + .into_inner(); + + + Network::bind(format!("127.0.0.1:{}", port)) + .server_name("static-init-network") + .private_key( + ::iota_simulator::fastcrypto::ed25519::Ed25519KeyPair::generate(&mut StdRng::from_rng(OsRng).unwrap()) + .private() + .0 + .to_bytes(), + ) + .start(service) + .unwrap() + }; + let n1 = make_network(80); + let n2 = make_network(81); + + let _peer = n1.connect(n2.local_addr()).await.unwrap(); + }); + }).join().unwrap(); + + #body + } + }) + .expect("Parsing failure"); + + let result = quote! { + #input + }; + + result.into() +} + +/// The iota_test macro will invoke either `#[msim::test]` or `#[tokio::test]`, +/// depending on whether the simulator config var is enabled. +/// +/// This should be used for tests that can meaningfully run in either +/// environment. +#[proc_macro_attribute] +pub fn iota_test(args: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as syn::ItemFn); + let arg_parser = Punctuated::::parse_terminated; + let args = arg_parser.parse(args).unwrap().into_iter(); + + let header = if cfg!(msim) { + quote! { + #[::iota_simulator::sim_test(crate = "iota_simulator", #(#args)* )] + } + } else { + quote! { + #[::tokio::test(#(#args)*)] + } + }; + + let result = quote! { + #header + #[::iota_macros::init_static_initializers] + #input + }; + + result.into() +} + +/// The sim_test macro will invoke `#[msim::test]` if the simulator config var +/// is enabled. +/// +/// Otherwise, it will emit an ignored test - if forcibly run, the ignored test +/// will panic. +/// +/// This macro must be used in order to pass any simulator-specific arguments, +/// such as `check_determinism`, which is not understood by tokio. +#[proc_macro_attribute] +pub fn sim_test(args: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as syn::ItemFn); + let arg_parser = Punctuated::::parse_terminated; + let args = arg_parser.parse(args).unwrap().into_iter(); + + let ignore = input + .attrs + .iter() + .find(|attr| attr.path().is_ident("ignore")) + .map_or(quote! {}, |_| quote! { #[ignore] }); + + let result = if cfg!(msim) { + let sig = &input.sig; + let return_type = &sig.output; + let body = &input.block; + quote! { + #[::iota_simulator::sim_test(crate = "iota_simulator", #(#args)*)] + #[::iota_macros::init_static_initializers] + #ignore + #sig { + async fn body_fn() #return_type { #body } + + let ret = body_fn().await; + + ::iota_simulator::task::shutdown_all_nodes(); + + // all node handles should have been dropped after the above block exits, but task + // shutdown is asynchronous, so we need a brief delay before checking for leaks. + tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; + + assert_eq!( + iota_simulator::NodeLeakDetector::get_current_node_count(), + 0, + "IotaNode leak detected" + ); + + ret + } + } + } else { + let fn_name = &input.sig.ident; + let sig = &input.sig; + let body = &input.block; + quote! { + #[allow(clippy::needless_return)] + #[tokio::test] + #ignore + #sig { + if std::env::var("IOTA_SKIP_SIMTESTS").is_ok() { + println!("not running test {} in `cargo test`: IOTA_SKIP_SIMTESTS is set", stringify!(#fn_name)); + + struct Ret; + + impl From for () { + fn from(_ret: Ret) -> Self { + } + } + + impl From for Result<(), E> { + fn from(_ret: Ret) -> Self { + Ok(()) + } + } + + return Ret.into(); + } + + #body + } + } + }; + + result.into() +} + +#[proc_macro] +pub fn checked_arithmetic(input: TokenStream) -> TokenStream { + let input_file = CheckArithmetic.fold_file(parse_macro_input!(input)); + + let output_items = input_file.items; + + let output = quote! { + #(#output_items)* + }; + + TokenStream::from(output) +} + +#[proc_macro_attribute] +pub fn with_checked_arithmetic(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input_item = parse_macro_input!(item as Item); + match input_item { + Item::Fn(input_fn) => { + let transformed_fn = CheckArithmetic.fold_item_fn(input_fn); + TokenStream::from(quote! { #transformed_fn }) + } + Item::Impl(input_impl) => { + let transformed_impl = CheckArithmetic.fold_item_impl(input_impl); + TokenStream::from(quote! { #transformed_impl }) + } + item => { + let transformed_impl = CheckArithmetic.fold_item(item); + TokenStream::from(quote! { #transformed_impl }) + } + } +} + +struct CheckArithmetic; + +impl CheckArithmetic { + fn maybe_skip_macro(&self, attrs: &mut Vec) -> bool { + if let Some(idx) = attrs + .iter() + .position(|attr| attr.path().is_ident("skip_checked_arithmetic")) + { + // Skip processing macro because it is annotated with + // #[skip_checked_arithmetic] + attrs.remove(idx); + true + } else { + false + } + } + + fn process_macro_contents( + &mut self, + tokens: proc_macro2::TokenStream, + ) -> syn::Result { + // Parse the macro's contents as a comma-separated list of expressions. + let parser = Punctuated::::parse_terminated; + let Ok(exprs) = parser.parse(tokens.clone().into()) else { + return Err(syn::Error::new_spanned( + tokens, + "could not process macro contents - use #[skip_checked_arithmetic] to skip this macro", + )); + }; + + // Fold each sub expression. + let folded_exprs = exprs + .into_iter() + .map(|expr| self.fold_expr(expr)) + .collect::>(); + + // Convert the folded expressions back into tokens and reconstruct the macro. + let mut folded_tokens = proc_macro2::TokenStream::new(); + for (i, folded_expr) in folded_exprs.into_iter().enumerate() { + if i > 0 { + folded_tokens.extend(std::iter::once::( + proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone).into(), + )); + } + folded_expr.to_tokens(&mut folded_tokens); + } + + Ok(folded_tokens) + } +} + +impl Fold for CheckArithmetic { + fn fold_stmt(&mut self, stmt: Stmt) -> Stmt { + let stmt = fold_stmt(self, stmt); + if let Stmt::Macro(stmt_macro) = stmt { + let StmtMacro { + mut attrs, + mut mac, + semi_token, + } = stmt_macro; + + if self.maybe_skip_macro(&mut attrs) { + Stmt::Macro(StmtMacro { + attrs, + mac, + semi_token, + }) + } else { + match self.process_macro_contents(mac.tokens.clone()) { + Ok(folded_tokens) => { + mac.tokens = folded_tokens; + Stmt::Macro(StmtMacro { + attrs, + mac, + semi_token, + }) + } + Err(error) => parse2(error.to_compile_error()).unwrap(), + } + } + } else { + stmt + } + } + + fn fold_item_macro(&mut self, mut item_macro: ItemMacro) -> ItemMacro { + if !self.maybe_skip_macro(&mut item_macro.attrs) { + let err = syn::Error::new_spanned( + item_macro.to_token_stream(), + "cannot process macros - use #[skip_checked_arithmetic] to skip \ + processing this macro", + ); + + return parse2(err.to_compile_error()).unwrap(); + } + fold_item_macro(self, item_macro) + } + + fn fold_expr(&mut self, expr: Expr) -> Expr { + let span = expr.span(); + let expr = fold_expr(self, expr); + let expr = match expr { + Expr::Macro(expr_macro) => { + let ExprMacro { mut attrs, mut mac } = expr_macro; + + if self.maybe_skip_macro(&mut attrs) { + return Expr::Macro(ExprMacro { attrs, mac }); + } else { + match self.process_macro_contents(mac.tokens.clone()) { + Ok(folded_tokens) => { + mac.tokens = folded_tokens; + let expr_macro = Expr::Macro(ExprMacro { attrs, mac }); + quote!(#expr_macro) + } + Err(error) => { + return Expr::Verbatim(error.to_compile_error()); + } + } + } + } + + Expr::Binary(expr_binary) => { + let ExprBinary { + attrs, + mut left, + op, + mut right, + } = expr_binary; + + fn remove_parens(expr: &mut Expr) { + if let Expr::Paren(paren) = expr { + // i don't even think rust allows this, but just in case + assert!(paren.attrs.is_empty(), "TODO: attrs on parenthesized"); + *expr = *paren.expr.clone(); + } + } + + macro_rules! wrap_op { + ($left: expr, $right: expr, $method: ident, $span: expr) => {{ + // Remove parens from exprs since both sides get assigned to tmp variables. + // otherwise we get lint errors + remove_parens(&mut $left); + remove_parens(&mut $right); + + quote_spanned!($span => { + // assign in one stmt in case either #left or #right contains + // references to `left` or `right` symbols. + let (left, right) = (#left, #right); + left.$method(right) + .unwrap_or_else(|| + panic!( + "Overflow or underflow in {} {} + {}", + stringify!($method), + left, + right, + ) + ) + }) + }}; + } + + macro_rules! wrap_op_assign { + ($left: expr, $right: expr, $method: ident, $span: expr) => {{ + // Remove parens from exprs since both sides get assigned to tmp variables. + // otherwise we get lint errors + remove_parens(&mut $left); + remove_parens(&mut $right); + + quote_spanned!($span => { + // assign in one stmt in case either #left or #right contains + // references to `left` or `right` symbols. + let (left, right) = (&mut #left, #right); + *left = (*left).$method(right) + .unwrap_or_else(|| + panic!( + "Overflow or underflow in {} {} + {}", + stringify!($method), + *left, + right + ) + ) + }) + }}; + } + + match op { + BinOp::Add(_) => { + wrap_op!(left, right, checked_add, span) + } + BinOp::Sub(_) => { + wrap_op!(left, right, checked_sub, span) + } + BinOp::Mul(_) => { + wrap_op!(left, right, checked_mul, span) + } + BinOp::Div(_) => { + wrap_op!(left, right, checked_div, span) + } + BinOp::Rem(_) => { + wrap_op!(left, right, checked_rem, span) + } + BinOp::AddAssign(_) => { + wrap_op_assign!(left, right, checked_add, span) + } + BinOp::SubAssign(_) => { + wrap_op_assign!(left, right, checked_sub, span) + } + BinOp::MulAssign(_) => { + wrap_op_assign!(left, right, checked_mul, span) + } + BinOp::DivAssign(_) => { + wrap_op_assign!(left, right, checked_div, span) + } + BinOp::RemAssign(_) => { + wrap_op_assign!(left, right, checked_rem, span) + } + _ => { + let expr_binary = ExprBinary { + attrs, + left, + op, + right, + }; + quote_spanned!(span => #expr_binary) + } + } + } + Expr::Unary(expr_unary) => { + let op = &expr_unary.op; + let operand = &expr_unary.expr; + match op { + UnOp::Neg(_) => { + quote_spanned!(span => #operand.checked_neg().expect("Overflow or underflow in negation")) + } + _ => quote_spanned!(span => #expr_unary), + } + } + _ => quote_spanned!(span => #expr), + }; + + parse2(expr).unwrap() + } +} + +/// This proc macro generates a function `order_to_variant_map` which returns a +/// map of the position of each variant to the name of the variant. +/// It is intended to catch changes in enum order when backward compat is +/// required. ```rust,ignore +/// /// Example for this enum +/// #[derive(EnumVariantOrder)] +/// pub enum MyEnum { +/// A, +/// B(u64), +/// C{x: bool, y: i8}, +/// } +/// let order_map = MyEnum::order_to_variant_map(); +/// assert!(order_map.get(0).unwrap() == "A"); +/// assert!(order_map.get(1).unwrap() == "B"); +/// assert!(order_map.get(2).unwrap() == "C"); +/// ``` +#[proc_macro_derive(EnumVariantOrder)] +pub fn enum_variant_order_derive(input: TokenStream) -> TokenStream { + let ast = parse_macro_input!(input as DeriveInput); + let name = &ast.ident; + + if let Data::Enum(DataEnum { variants, .. }) = ast.data { + let variant_entries = variants + .iter() + .enumerate() + .map(|(index, variant)| { + let variant_name = variant.ident.to_string(); + quote! { + map.insert( #index as u64, (#variant_name).to_string()); + } + }) + .collect::>(); + + let deriv = quote! { + impl iota_enum_compat_util::EnumOrderMap for #name { + fn order_to_variant_map() -> std::collections::BTreeMap { + let mut map = std::collections::BTreeMap::new(); + #(#variant_entries)* + map + } + } + }; + + deriv.into() + } else { + panic!("EnumVariantOrder can only be used with enums."); + } +} diff --git a/crates/iota-protocol-config-macros/Cargo.toml b/crates/iota-protocol-config-macros/Cargo.toml new file mode 100644 index 00000000000..0a17b959776 --- /dev/null +++ b/crates/iota-protocol-config-macros/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "iota-protocol-config-macros" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2.workspace = true +syn.workspace = true +quote.workspace = true diff --git a/crates/iota-protocol-config-macros/src/lib.rs b/crates/iota-protocol-config-macros/src/lib.rs new file mode 100644 index 00000000000..1a211d43fd1 --- /dev/null +++ b/crates/iota-protocol-config-macros/src/lib.rs @@ -0,0 +1,306 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +extern crate proc_macro; + +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, Data, DeriveInput, Fields, Type}; + +/// This proc macro generates getters, attribute lookup, etc for protocol config +/// fields of type `Option` and for the feature flags +/// Example for a field: `new_constant: Option`, and for feature flags +/// `feature: bool`, we derive ```rust,ignore +/// /// Returns the value of the field if exists at the given version, +/// otherise panic pub fn new_constant(&self) -> u64 { +/// self.new_constant.expect(Self::CONSTANT_ERR_MSG) +/// } +/// /// Returns the value of the field if exists at the given version, +/// otherise None. pub fn new_constant_as_option(&self) -> Option { +/// self.new_constant +/// } +/// // We auto derive an enum such that the variants are all the types of +/// the fields pub enum ProtocolConfigValue { +/// u32(u32), +/// u64(u64), +/// .............. +/// } +/// // This enum is used to return field values so that the type is also +/// encoded in the response +/// +/// /// Returns the value of the field if exists at the given version, +/// otherise None pub fn lookup_attr(&self, value: String) -> +/// Option; +/// +/// /// Returns a map of all configs to values +/// pub fn attr_map(&self) -> std::collections::BTreeMap>; +/// +/// /// Returns a feature by the string name or None if it doesn't exist +/// pub fn lookup_feature(&self, value: String) -> Option; +/// +/// /// Returns a map of all features to values +/// pub fn feature_map(&self) -> std::collections::BTreeMap; +/// ``` +#[proc_macro_derive(ProtocolConfigAccessors)] +pub fn accessors_macro(input: TokenStream) -> TokenStream { + let ast = parse_macro_input!(input as DeriveInput); + + let struct_name = &ast.ident; + let data = &ast.data; + let mut inner_types = vec![]; + + let tokens = match data { + Data::Struct(data_struct) => match &data_struct.fields { + // Operate on each field of the ProtocolConfig struct + Fields::Named(fields_named) => fields_named.named.iter().filter_map(|field| { + // Extract field name and type + let field_name = field.ident.as_ref().expect("Field must be named"); + let field_type = &field.ty; + // Check if field is of type Option + match field_type { + Type::Path(type_path) + if type_path + .path + .segments + .last() + .map_or(false, |segment| segment.ident == "Option") => + { + // Extract inner type T from Option + let inner_type = if let syn::PathArguments::AngleBracketed( + angle_bracketed_generic_arguments, + ) = &type_path.path.segments.last().unwrap().arguments + { + if let Some(syn::GenericArgument::Type(ty)) = + angle_bracketed_generic_arguments.args.first() + { + ty.clone() + } else { + panic!("Expected a type argument."); + } + } else { + panic!("Expected angle bracketed arguments."); + }; + + let as_option_name = format!("{field_name}_as_option"); + let as_option_name: proc_macro2::TokenStream = + as_option_name.parse().unwrap(); + let test_setter_name: proc_macro2::TokenStream = + format!("set_{field_name}_for_testing").parse().unwrap(); + let test_un_setter_name: proc_macro2::TokenStream = + format!("disable_{field_name}_for_testing").parse().unwrap(); + let test_setter_from_str_name: proc_macro2::TokenStream = + format!("set_{field_name}_from_str_for_testing").parse().unwrap(); + + let getter = quote! { + // Derive the getter + pub fn #field_name(&self) -> #inner_type { + self.#field_name.expect(Self::CONSTANT_ERR_MSG) + } + + pub fn #as_option_name(&self) -> #field_type { + self.#field_name + } + }; + + let test_setter = quote! { + // Derive the setter + pub fn #test_setter_name(&mut self, val: #inner_type) { + self.#field_name = Some(val); + } + + // Derive the setter from String + pub fn #test_setter_from_str_name(&mut self, val: String) { + use std::str::FromStr; + self.#test_setter_name(#inner_type::from_str(&val).unwrap()); + } + + // Derive the un-setter + pub fn #test_un_setter_name(&mut self) { + self.#field_name = None; + } + }; + + let value_setter = quote! { + stringify!(#field_name) => self.#test_setter_from_str_name(val), + }; + + + let value_lookup = quote! { + stringify!(#field_name) => self.#field_name.map(|v| ProtocolConfigValue::#inner_type(v)), + }; + + let field_name_str = quote! { + stringify!(#field_name) + }; + + // Track all the types seen + if inner_types.contains(&inner_type) { + None + } else { + inner_types.push(inner_type.clone()); + Some(quote! { + #inner_type + }) + }; + + Some(((getter, (test_setter, value_setter)), (value_lookup, field_name_str))) + } + _ => None, + } + }), + _ => panic!("Only named fields are supported."), + }, + _ => panic!("Only structs supported."), + }; + + #[allow(clippy::type_complexity)] + let ((getters, (test_setters, value_setters)), (value_lookup, field_names_str)): ( + (Vec<_>, (Vec<_>, Vec<_>)), + (Vec<_>, Vec<_>), + ) = tokens.unzip(); + let output = quote! { + // For each getter, expand it out into a function in the impl block + impl #struct_name { + const CONSTANT_ERR_MSG: &'static str = "protocol constant not present in current protocol version"; + #(#getters)* + + /// Lookup a config attribute by its string representation + pub fn lookup_attr(&self, value: String) -> Option { + match value.as_str() { + #(#value_lookup)* + _ => None, + } + } + + /// Get a map of all config attribute from string representations + pub fn attr_map(&self) -> std::collections::BTreeMap> { + vec![ + #(((#field_names_str).to_owned(), self.lookup_attr((#field_names_str).to_owned())),)* + ].into_iter().collect() + } + + /// Get the feature flags + pub fn lookup_feature(&self, value: String) -> Option { + self.feature_flags.lookup_attr(value) + } + + pub fn feature_map(&self) -> std::collections::BTreeMap { + self.feature_flags.attr_map() + } + } + + // For each attr, derive a setter from the raw value and from string repr + impl #struct_name { + #(#test_setters)* + + pub fn set_attr_for_testing(&mut self, attr: String, val: String) { + match attr.as_str() { + #(#value_setters)* + _ => panic!("Attempting to set unknown attribute: {}", attr), + } + } + } + + #[allow(non_camel_case_types)] + #[derive(Clone, Serialize, Debug, PartialEq, Deserialize, schemars::JsonSchema)] + pub enum ProtocolConfigValue { + #(#inner_types(#inner_types),)* + } + + impl std::fmt::Display for ProtocolConfigValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use std::fmt::Write; + let mut writer = String::new(); + match self { + #( + ProtocolConfigValue::#inner_types(x) => { + write!(writer, "{}", x)?; + } + )* + } + write!(f, "{}", writer) + } + } + }; + + TokenStream::from(output) +} + +#[proc_macro_derive(ProtocolConfigFeatureFlagsGetters)] +pub fn feature_flag_getters_macro(input: TokenStream) -> TokenStream { + let ast = parse_macro_input!(input as DeriveInput); + + let struct_name = &ast.ident; + let data = &ast.data; + + let getters = match data { + Data::Struct(data_struct) => match &data_struct.fields { + // Operate on each field of the ProtocolConfig struct + Fields::Named(fields_named) => fields_named.named.iter().filter_map(|field| { + // Extract field name and type + let field_name = field.ident.as_ref().expect("Field must be named"); + let field_type = &field.ty; + // Check if field is of type bool + match field_type { + Type::Path(type_path) + if type_path + .path + .segments + .last() + .map_or(false, |segment| segment.ident == "bool") => + { + Some(( + quote! { + // Derive the getter + pub fn #field_name(&self) -> #field_type { + self.#field_name + } + }, + ( + quote! { + stringify!(#field_name) => Some(self.#field_name), + }, + quote! { + stringify!(#field_name) + }, + ), + )) + } + _ => None, + } + }), + _ => panic!("Only named fields are supported."), + }, + _ => panic!("Only structs supported."), + }; + + let (by_fn_getters, (string_name_getters, field_names)): (Vec<_>, (Vec<_>, Vec<_>)) = + getters.unzip(); + + let output = quote! { + // For each getter, expand it out into a function in the impl block + impl #struct_name { + #(#by_fn_getters)* + + /// Lookup a feature flag by its string representation + pub fn lookup_attr(&self, value: String) -> Option { + match value.as_str() { + #(#string_name_getters)* + _ => None, + } + } + + /// Get a map of all feature flags from string representations + pub fn attr_map(&self) -> std::collections::BTreeMap { + vec![ + // Okay to unwrap since we added all above + #(((#field_names).to_owned(), self.lookup_attr((#field_names).to_owned()).unwrap()),)* + ].into_iter().collect() + } + } + }; + + TokenStream::from(output) +} diff --git a/crates/iota-protocol-config/Cargo.toml b/crates/iota-protocol-config/Cargo.toml new file mode 100644 index 00000000000..3325bf19c27 --- /dev/null +++ b/crates/iota-protocol-config/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "iota-protocol-config" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +serde.workspace = true +tracing.workspace = true +serde_with.workspace = true +iota-protocol-config-macros.workspace = true +schemars.workspace = true +insta.workspace = true +clap.workspace = true + +[dev-dependencies] +insta.workspace = true diff --git a/crates/iota-protocol-config/src/lib.rs b/crates/iota-protocol-config/src/lib.rs new file mode 100644 index 00000000000..5f9fa552e06 --- /dev/null +++ b/crates/iota-protocol-config/src/lib.rs @@ -0,0 +1,2481 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + cell::RefCell, + collections::BTreeSet, + sync::atomic::{AtomicBool, Ordering}, +}; + +use clap::*; +use iota_protocol_config_macros::{ProtocolConfigAccessors, ProtocolConfigFeatureFlagsGetters}; +use serde::{Deserialize, Serialize}; +use serde_with::skip_serializing_none; +use tracing::{info, warn}; + +/// The minimum and maximum protocol versions supported by this build. +const MIN_PROTOCOL_VERSION: u64 = 1; +const MAX_PROTOCOL_VERSION: u64 = 42; + +// Record history of protocol version allocations here: +// +// Version 1: Original version. +// Version 2: Framework changes, including advancing epoch_start_time in +// safemode. Version 3: gas model v2, including all iota conservation fixes. Fix +// for loaded child object changes, enable package upgrades, add +// limits on `max_size_written_objects`, +// `max_size_written_objects_system_tx` Version 4: New reward slashing rate. +// Framework changes to skip stake susbidy when the epoch length is +// short. Version 5: Package upgrade compatibility error fix. New gas cost +// table. New scoring decision mechanism that includes up to f +// scoring authorities. Version 6: Change to how bytes are charged in the gas +// meter, increase buffer stake to 0.5f Version 7: Disallow adding new abilities +// to types during package upgrades, +// disable_invariant_violation_check_in_swap_loc, disable init +// functions becoming entry, hash module bytes individually before +// computing package digest. Version 8: Disallow changing abilities and type +// constraints for type parameters in structs during upgrades. +// Version 9: Limit the length of Move idenfitiers to 128. +// Disallow extraneous module bytes, +// advance_to_highest_supported_protocol_version, +// Version 10:increase bytecode verifier `max_verifier_meter_ticks_per_function` +// and `max_meter_ticks_per_module` limits each from 6_000_000 to +// 16_000_000. iota-system framework changes. +// Version 11: Introduce `std::type_name::get_with_original_ids` to the system +// frameworks. Bound max depth of values within the VM. Version 12: Changes to +// deepbook in framework to add API for querying marketplace. Change +// NW Batch to use versioned metadata field. Changes to iota-system +// package to add PTB-friendly unstake function, and minor cleanup. Version 13: +// System package change deprecating `0xdee9::clob` and `0xdee9::custodian`, +// replaced by `0xdee9::clob_v2` and `0xdee9::custodian_v2`. +// Version 14: Introduce a config variable to allow charging of computation to +// be either bucket base or rounding up. The presence of +// `gas_rounding_step` (or `None`) decides whether rounding is +// applied or not. Version 15: Add reordering of user transactions by gas price +// after consensus. Add `iota::table_vec::drop` to the framework via +// a system package upgrade. Version 16: Enabled simplified_unwrap_then_delete +// feature flag, which allows the execution engine to no longer +// consult the object store when generating unwrapped_then_deleted in the +// effects; this also allows us to stop including wrapped tombstones +// in accumulator. Add self-matching prevention for deepbook. +// Version 17: Enable upgraded multisig support. +// Version 18: Introduce execution layer versioning, preserve all existing +// behaviour in v0. Gas minimum charges moved to be a multiplier +// over the reference gas price. In this protocol version the +// multiplier is the same as the lowest bucket of computation such +// that the minimum transaction cost is the same as the minimum computation +// bucket. +// Add a feature flag to indicate the changes semantics of +// `base_tx_cost_fixed`. Version 19: Changes to iota-system package to enable +// liquid staking. Add limit for total size of events. +// Increase limit for number of events emitted to 1024. +// Version 20: Enables the flag `narwhal_new_leader_election_schedule` for the +// new narwhal leader schedule algorithm for enhanced fault +// tolerance and sets the bad node stake threshold value. Both +// values are set for all the environments except mainnet. Version 21: ZKLogin +// known providers. Version 22: Child object format change. +// Version 23: Enabling the flag `narwhal_new_leader_election_schedule` for the +// new narwhal leader schedule algorithm for enhanced fault +// tolerance and sets the bad node stake threshold value for +// mainnet. Version 24: Re-enable simple gas conservation checks. +// Package publish/upgrade number in a single transaction limited. +// JWK / authenticator state flags. +// Version 25: Add iota::table_vec::swap and iota::table_vec::swap_remove to +// system packages. Version 26: New gas model version. +// Add support for receiving objects off of other objects in devnet +// only. Version 28: Add iota::zklogin::verify_zklogin_id and related functions +// to iota framework. Enable transaction effects v2 in devnet. +// Version 29: Add verify_legacy_zklogin_address flag to iota framework, this +// add ability to verify transactions from a legacy zklogin address. +// Version 30: Enable Narwhal CertificateV2 +// Add support for random beacon. +// Enable transaction effects v2 in testnet. +// Deprecate supported oauth providers from protocol config and rely +// on node config instead. +// In execution, has_public_transfer is recomputed when loading the +// object. Add support for shared obj deletion and receiving objects +// off of other objects in devnet only. Version 31: Add support for shared +// object deletion in devnet only. Add support for getting object ID +// referenced by receiving object in iota framework. Create new +// execution layer version, and preserve previous behavior in v1. +// Update semantics of `iota::transfer::receive` and add +// `iota::transfer::public_receive`. Version 32: Add delete functions for +// VerifiedID and VerifiedIssuer. Add iota::token module to iota +// framework. Enable transfer to object in testnet. +// Enable Narwhal CertificateV2 on mainnet +// Make critbit tree and order getters public in deepbook. +// Version 33: Add support for `receiving_object_id` function in framework +// Hardened OTW check. +// Enable transfer-to-object in mainnet. +// Enable shared object deletion in testnet. +// Enable effects v2 in mainnet. +// Version 34: Framework changes for random beacon. +// Version 35: Add poseidon hash function. +// Enable coin deny list. +// Version 36: Enable group operations native functions in devnet. +// Enable shared object deletion in mainnet. +// Set the consensus accepted transaction size and the included +// transactions size in the proposed block. Version 37: Reject entry functions +// with mutable Random. Version 38: Introduce limits for binary tables size. +// Version 39: Allow skipped epochs for randomness updates. +// Extra version to fix `test_upgrade_compatibility` simtest. +// Version 40: +// Version 41: Enable group operations native functions in testnet and mainnet +// (without msm). Version 42: Migrate iota framework and related code to Move +// 2024 +#[derive(Copy, Clone, Debug, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +pub struct ProtocolVersion(u64); + +impl ProtocolVersion { + // The minimum and maximum protocol version supported by this binary. + // Counterintuitively, this constant may change over time as support for old + // protocol versions is removed from the source. This ensures that when a + // new network (such as a testnet) is created, its genesis committee will + // use a protocol version that is actually supported by the binary. + pub const MIN: Self = Self(MIN_PROTOCOL_VERSION); + + pub const MAX: Self = Self(MAX_PROTOCOL_VERSION); + + #[cfg(not(msim))] + const MAX_ALLOWED: Self = Self::MAX; + + // We create one additional "fake" version in simulator builds so that we can + // test upgrades. + #[cfg(msim)] + pub const MAX_ALLOWED: Self = Self(MAX_PROTOCOL_VERSION + 1); + + pub fn new(v: u64) -> Self { + Self(v) + } + + pub const fn as_u64(&self) -> u64 { + self.0 + } + + // For serde deserialization - we don't define a Default impl because there + // isn't a single universally appropriate default value. + pub fn max() -> Self { + Self::MAX + } +} + +impl From for ProtocolVersion { + fn from(v: u64) -> Self { + Self::new(v) + } +} + +impl std::ops::Sub for ProtocolVersion { + type Output = Self; + fn sub(self, rhs: u64) -> Self::Output { + Self::new(self.0 - rhs) + } +} + +impl std::ops::Add for ProtocolVersion { + type Output = Self; + fn add(self, rhs: u64) -> Self::Output { + Self::new(self.0 + rhs) + } +} + +/// Models the set of protocol versions supported by a validator. +/// The `iota-node` binary will always use the SYSTEM_DEFAULT constant, but for +/// testing we need to be able to inject arbitrary versions into IotaNode. +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub struct SupportedProtocolVersions { + pub min: ProtocolVersion, + pub max: ProtocolVersion, +} + +impl SupportedProtocolVersions { + pub const SYSTEM_DEFAULT: Self = Self { + min: ProtocolVersion::MIN, + max: ProtocolVersion::MAX, + }; + + /// Use by VersionedProtocolMessage implementors to describe in which range + /// of versions a message variant is supported. + pub fn new_for_message(min: u64, max: u64) -> Self { + let min = ProtocolVersion::new(min); + let max = ProtocolVersion::new(max); + Self { min, max } + } + + pub fn new_for_testing(min: u64, max: u64) -> Self { + let min = min.into(); + let max = max.into(); + Self { min, max } + } + + pub fn is_version_supported(&self, v: ProtocolVersion) -> bool { + v.0 >= self.min.0 && v.0 <= self.max.0 + } +} + +#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Copy, PartialOrd, Ord, Eq, ValueEnum)] +pub enum Chain { + Mainnet, + Testnet, + Unknown, +} + +impl Default for Chain { + fn default() -> Self { + Self::Unknown + } +} + +pub struct Error(pub String); + +/// Records on/off feature flags that may vary at each protocol version. +#[derive(Default, Clone, Serialize, Debug, ProtocolConfigFeatureFlagsGetters)] +struct FeatureFlags { + // Add feature flags here, e.g.: + // new_protocol_feature: bool, + #[serde(skip_serializing_if = "is_false")] + package_upgrades: bool, + // If true, validators will commit to the root state digest + // in end of epoch checkpoint proposals + #[serde(skip_serializing_if = "is_false")] + commit_root_state_digest: bool, + // Pass epoch start time to advance_epoch safe mode function. + #[serde(skip_serializing_if = "is_false")] + advance_epoch_start_time_in_safe_mode: bool, + // If true, apply the fix to correctly capturing loaded child object versions in execution's + // object runtime. + #[serde(skip_serializing_if = "is_false")] + loaded_child_objects_fixed: bool, + // If true, treat missing types in the upgraded modules when creating an upgraded package as a + // compatibility error. + #[serde(skip_serializing_if = "is_false")] + missing_type_is_compatibility_error: bool, + // If true, then the scoring decision mechanism will not get disabled when we do have more than + // f low scoring authorities, but it will simply flag as low scoring only up to f authorities. + #[serde(skip_serializing_if = "is_false")] + scoring_decision_with_validity_cutoff: bool, + + // DEPRECATED: this was an ephemeral feature flag only used by consensus handler, which has now + // been deployed everywhere. + #[serde(skip_serializing_if = "is_false")] + consensus_order_end_of_epoch_last: bool, + + // Disallow adding abilities to types during package upgrades. + #[serde(skip_serializing_if = "is_false")] + disallow_adding_abilities_on_upgrade: bool, + // Disables unnecessary invariant check in the Move VM when swapping the value out of a local + #[serde(skip_serializing_if = "is_false")] + disable_invariant_violation_check_in_swap_loc: bool, + // advance to highest supported protocol version at epoch change, instead of the next + // consecutive protocol version. + #[serde(skip_serializing_if = "is_false")] + advance_to_highest_supported_protocol_version: bool, + // If true, disallow entry modifiers on entry functions + #[serde(skip_serializing_if = "is_false")] + ban_entry_init: bool, + // If true, hash module bytes individually when calculating package digests for upgrades + #[serde(skip_serializing_if = "is_false")] + package_digest_hash_module: bool, + // If true, disallow changing struct type parameters during package upgrades + #[serde(skip_serializing_if = "is_false")] + disallow_change_struct_type_params_on_upgrade: bool, + // If true, checks no extra bytes in a compiled module + #[serde(skip_serializing_if = "is_false")] + no_extraneous_module_bytes: bool, + // If true, then use the versioned metadata format in narwhal entities. + #[serde(skip_serializing_if = "is_false")] + narwhal_versioned_metadata: bool, + + // Enable zklogin auth + #[serde(skip_serializing_if = "is_false")] + zklogin_auth: bool, + // How we order transactions coming out of consensus before sending to execution. + #[serde(skip_serializing_if = "ConsensusTransactionOrdering::is_none")] + consensus_transaction_ordering: ConsensusTransactionOrdering, + + // Previously, the unwrapped_then_deleted field in TransactionEffects makes a distinction + // between whether an object has existed in the store previously (i.e. whether there is a + // tombstone). Such dependency makes effects generation inefficient, and requires us to + // include wrapped tombstone in state root hash. + // To prepare for effects V2, with this flag set to true, we simplify the definition of + // unwrapped_then_deleted to always include unwrapped then deleted objects, + // regardless of their previous state in the store. + #[serde(skip_serializing_if = "is_false")] + simplified_unwrap_then_delete: bool, + // Enable upgraded multisig support + #[serde(skip_serializing_if = "is_false")] + upgraded_multisig_supported: bool, + // If true minimum txn charge is a multiplier of the gas price + #[serde(skip_serializing_if = "is_false")] + txn_base_cost_as_multiplier: bool, + + // If true, the ability to delete shared objects is in effect + #[serde(skip_serializing_if = "is_false")] + shared_object_deletion: bool, + + // If true, then the new algorithm for the leader election schedule will be used + #[serde(skip_serializing_if = "is_false")] + narwhal_new_leader_election_schedule: bool, + + // A list of supported OIDC providers that can be used for zklogin. + #[serde(skip_serializing_if = "is_empty")] + zklogin_supported_providers: BTreeSet, + + // If true, use the new child object format + #[serde(skip_serializing_if = "is_false")] + loaded_child_object_format: bool, + + #[serde(skip_serializing_if = "is_false")] + enable_jwk_consensus_updates: bool, + + #[serde(skip_serializing_if = "is_false")] + end_of_epoch_transaction_supported: bool, + + // Perform simple conservation checks keeping into account out of gas scenarios + // while charging for storage. + #[serde(skip_serializing_if = "is_false")] + simple_conservation_checks: bool, + + // If true, use the new child object format type logging + #[serde(skip_serializing_if = "is_false")] + loaded_child_object_format_type: bool, + + // Enable receiving sent objects + #[serde(skip_serializing_if = "is_false")] + receive_objects: bool, + + // Enable random beacon protocol + #[serde(skip_serializing_if = "is_false")] + random_beacon: bool, + + #[serde(skip_serializing_if = "is_false")] + enable_effects_v2: bool, + + // If true, then use CertificateV2 in narwhal. + #[serde(skip_serializing_if = "is_false")] + narwhal_certificate_v2: bool, + + // If true, allow verify with legacy zklogin address + #[serde(skip_serializing_if = "is_false")] + verify_legacy_zklogin_address: bool, + + // Enable throughput aware consensus submission + #[serde(skip_serializing_if = "is_false")] + throughput_aware_consensus_submission: bool, + + // If true, recompute has_public_transfer from the type instead of what is stored in the object + #[serde(skip_serializing_if = "is_false")] + recompute_has_public_transfer_in_execution: bool, + + // If true, multisig containing zkLogin sig is accepted. + #[serde(skip_serializing_if = "is_false")] + accept_zklogin_in_multisig: bool, + + // If true, consensus prologue transaction also includes the consensus output digest. + // It can be used to detect consensus output folk. + #[serde(skip_serializing_if = "is_false")] + include_consensus_digest_in_prologue: bool, + + // If true, use the hardened OTW check + #[serde(skip_serializing_if = "is_false")] + hardened_otw_check: bool, + + // If true allow calling receiving_object_id function + #[serde(skip_serializing_if = "is_false")] + allow_receiving_object_id: bool, + + // Enable the poseidon hash function + #[serde(skip_serializing_if = "is_false")] + enable_poseidon: bool, + + // If true, enable the coin deny list. + #[serde(skip_serializing_if = "is_false")] + enable_coin_deny_list: bool, + + // Enable native functions for group operations. + #[serde(skip_serializing_if = "is_false")] + enable_group_ops_native_functions: bool, + + // Enable native function for msm. + #[serde(skip_serializing_if = "is_false")] + enable_group_ops_native_function_msm: bool, + + // Reject functions with mutable Random. + #[serde(skip_serializing_if = "is_false")] + reject_mutable_random_on_entry_functions: bool, +} + +fn is_false(b: &bool) -> bool { + !b +} + +fn is_empty(b: &BTreeSet) -> bool { + b.is_empty() +} + +/// Ordering mechanism for transactions in one Narwhal consensus output. +#[derive(Default, Copy, Clone, PartialEq, Eq, Serialize, Debug)] +pub enum ConsensusTransactionOrdering { + /// No ordering. Transactions are processed in the order they appear in the + /// consensus output. + #[default] + None, + /// Order transactions by gas price, highest first. + ByGasPrice, +} + +impl ConsensusTransactionOrdering { + pub fn is_none(&self) -> bool { + matches!(self, ConsensusTransactionOrdering::None) + } +} + +/// Constants that change the behavior of the protocol. +/// +/// The value of each constant here must be fixed for a given protocol version. +/// To change the value of a constant, advance the protocol version, and add +/// support for it in `get_for_version` under the new version number. +/// (below). +/// +/// To add a new field to this struct, use the following procedure: +/// - Advance the protocol version. +/// - Add the field as a private `Option` to the struct. +/// - Initialize the field to `None` in prior protocol versions. +/// - Initialize the field to `Some(val)` for your new protocol version. +/// - Add a public getter that simply unwraps the field. +/// - Two public getters of the form `field(&self) -> field_type` and +/// `field_as_option(&self) -> Option` will be automatically +/// generated for you. +/// Example for a field: `new_constant: Option` +/// ```rust,ignore +/// pub fn new_constant(&self) -> u64 { +/// self.new_constant.expect(Self::CONSTANT_ERR_MSG) +/// } +/// pub fn new_constant_as_option(&self) -> Option { +/// self.new_constant.expect(Self::CONSTANT_ERR_MSG) +/// } +/// ``` +/// With `pub fn new_constant(&self) -> u64`, if the constant is accessed in a +/// protocol version in which it is not defined, the validator will crash. +/// (Crashing is necessary because this type of error would almost always result +/// in forking if not prevented here). If you don't want the validator to crash, +/// you can use the `pub fn new_constant_as_option(&self) -> Option` +/// getter, which will return `None` if the field is not defined at that +/// version. +/// - If you want a customized getter, you can add a method in the impl. +#[skip_serializing_none] +#[derive(Clone, Serialize, Debug, ProtocolConfigAccessors)] +pub struct ProtocolConfig { + pub version: ProtocolVersion, + + feature_flags: FeatureFlags, + + // ==== Transaction input limits ==== + /// Maximum serialized size of a transaction (in bytes). + max_tx_size_bytes: Option, + + /// Maximum number of input objects to a transaction. Enforced by the + /// transaction input checker + max_input_objects: Option, + + /// Max size of objects a transaction can write to disk after completion. + /// Enforce by the Iota adapter. This is the sum of the serialized size + /// of all objects written to disk. The max size of individual objects + /// on the other hand is `max_move_object_size`. + max_size_written_objects: Option, + /// Max size of objects a system transaction can write to disk after + /// completion. Enforce by the Iota adapter. Similar to + /// `max_size_written_objects` but for system transactions. + max_size_written_objects_system_tx: Option, + + /// Maximum size of serialized transaction effects. + max_serialized_tx_effects_size_bytes: Option, + + /// Maximum size of serialized transaction effects for system transactions. + max_serialized_tx_effects_size_bytes_system_tx: Option, + + /// Maximum number of gas payment objects for a transaction. + max_gas_payment_objects: Option, + + /// Maximum number of modules in a Publish transaction. + max_modules_in_publish: Option, + + /// Maximum number of transitive dependencies in a package when publishing. + max_package_dependencies: Option, + + /// Maximum number of arguments in a move call or a + /// ProgrammableTransaction's TransferObjects command. + max_arguments: Option, + + /// Maximum number of total type arguments, computed recursively. + max_type_arguments: Option, + + /// Maximum depth of an individual type argument. + max_type_argument_depth: Option, + + /// Maximum size of a Pure CallArg. + max_pure_argument_size: Option, + + /// Maximum number of Commands in a ProgrammableTransaction. + max_programmable_tx_commands: Option, + + // ==== Move VM, Move bytecode verifier, and execution limits === + /// Maximum Move bytecode version the VM understands. All older versions are + /// accepted. + move_binary_format_version: Option, + /// Configuration controlling binary tables size. + binary_module_handles: Option, + binary_struct_handles: Option, + binary_function_handles: Option, + binary_function_instantiations: Option, + binary_signatures: Option, + binary_constant_pool: Option, + binary_identifiers: Option, + binary_address_identifiers: Option, + binary_struct_defs: Option, + binary_struct_def_instantiations: Option, + binary_function_defs: Option, + binary_field_handles: Option, + binary_field_instantiations: Option, + binary_friend_decls: Option, + + /// Maximum size of the `contents` part of an object, in bytes. Enforced by + /// the Iota adapter when effects are produced. + max_move_object_size: Option, + + // TODO: Option 500 KB exceeds the max + // computation gas cost + /// Maximum size of a Move package object, in bytes. Enforced by the Iota + /// adapter at the end of a publish transaction. + max_move_package_size: Option, + + /// Max number of publish or upgrade commands allowed in a programmable + /// transaction block. + max_publish_or_upgrade_per_ptb: Option, + + /// Maximum number of gas units that a single MoveCall transaction can use. + /// Enforced by the Iota adapter. + max_tx_gas: Option, + + /// Maximum amount of the proposed gas price in MICROS (defined in the + /// transaction). + max_gas_price: Option, + + /// The max computation bucket for gas. This is the max that can be charged + /// for computation. + max_gas_computation_bucket: Option, + + // Define the value used to round up computation gas charges + gas_rounding_step: Option, + + /// Maximum number of nested loops. Enforced by the Move bytecode verifier. + max_loop_depth: Option, + + /// Maximum number of type arguments that can be bound to generic type + /// parameters. Enforced by the Move bytecode verifier. + max_generic_instantiation_length: Option, + + /// Maximum number of parameters that a Move function can have. Enforced by + /// the Move bytecode verifier. + max_function_parameters: Option, + + /// Maximum number of basic blocks that a Move function can have. Enforced + /// by the Move bytecode verifier. + max_basic_blocks: Option, + + /// Maximum stack size value. Enforced by the Move bytecode verifier. + max_value_stack_size: Option, + + /// Maximum number of "type nodes", a metric for how big a SignatureToken + /// will be when expanded into a fully qualified type. Enforced by the Move + /// bytecode verifier. + max_type_nodes: Option, + + /// Maximum number of push instructions in one function. Enforced by the + /// Move bytecode verifier. + max_push_size: Option, + + /// Maximum number of struct definitions in a module. Enforced by the Move + /// bytecode verifier. + max_struct_definitions: Option, + + /// Maximum number of function definitions in a module. Enforced by the Move + /// bytecode verifier. + max_function_definitions: Option, + + /// Maximum number of fields allowed in a struct definition. Enforced by the + /// Move bytecode verifier. + max_fields_in_struct: Option, + + /// Maximum dependency depth. Enforced by the Move linker when loading + /// dependent modules. + max_dependency_depth: Option, + + /// Maximum number of Move events that a single transaction can emit. + /// Enforced by the VM during execution. + max_num_event_emit: Option, + + /// Maximum number of new IDs that a single transaction can create. Enforced + /// by the VM during execution. + max_num_new_move_object_ids: Option, + + /// Maximum number of new IDs that a single system transaction can create. + /// Enforced by the VM during execution. + max_num_new_move_object_ids_system_tx: Option, + + /// Maximum number of IDs that a single transaction can delete. Enforced by + /// the VM during execution. + max_num_deleted_move_object_ids: Option, + + /// Maximum number of IDs that a single system transaction can delete. + /// Enforced by the VM during execution. + max_num_deleted_move_object_ids_system_tx: Option, + + /// Maximum number of IDs that a single transaction can transfer. Enforced + /// by the VM during execution. + max_num_transferred_move_object_ids: Option, + + /// Maximum number of IDs that a single system transaction can transfer. + /// Enforced by the VM during execution. + max_num_transferred_move_object_ids_system_tx: Option, + + /// Maximum size of a Move user event. Enforced by the VM during execution. + max_event_emit_size: Option, + + /// Maximum size of a Move user event. Enforced by the VM during execution. + max_event_emit_size_total: Option, + + /// Maximum length of a vector in Move. Enforced by the VM during execution, + /// and for constants, by the verifier. + max_move_vector_len: Option, + + /// Maximum length of an `Identifier` in Move. Enforced by the bytecode + /// verifier at signing. + max_move_identifier_len: Option, + + /// Maximum depth of a Move value within the VM. + max_move_value_depth: Option, + + /// Maximum number of back edges in Move function. Enforced by the bytecode + /// verifier at signing. + max_back_edges_per_function: Option, + + /// Maximum number of back edges in Move module. Enforced by the bytecode + /// verifier at signing. + max_back_edges_per_module: Option, + + /// Maximum number of meter `ticks` spent verifying a Move function. + /// Enforced by the bytecode verifier at signing. + max_verifier_meter_ticks_per_function: Option, + + /// Maximum number of meter `ticks` spent verifying a Move function. + /// Enforced by the bytecode verifier at signing. + max_meter_ticks_per_module: Option, + + // === Object runtime internal operation limits ==== + // These affect dynamic fields + /// Maximum number of cached objects in the object runtime ObjectStore. + /// Enforced by object runtime during execution + object_runtime_max_num_cached_objects: Option, + + /// Maximum number of cached objects in the object runtime ObjectStore in + /// system transaction. Enforced by object runtime during execution + object_runtime_max_num_cached_objects_system_tx: Option, + + /// Maximum number of stored objects accessed by object runtime ObjectStore. + /// Enforced by object runtime during execution + object_runtime_max_num_store_entries: Option, + + /// Maximum number of stored objects accessed by object runtime ObjectStore + /// in system transaction. Enforced by object runtime during execution + object_runtime_max_num_store_entries_system_tx: Option, + + // === Execution gas costs ==== + /// Base cost for any Iota transaction + base_tx_cost_fixed: Option, + + /// Additional cost for a transaction that publishes a package + /// i.e., the base cost of such a transaction is base_tx_cost_fixed + + /// package_publish_cost_fixed + package_publish_cost_fixed: Option, + + /// Cost per byte of a Move call transaction + /// i.e., the cost of such a transaction is base_cost + + /// (base_tx_cost_per_byte * size) + base_tx_cost_per_byte: Option, + + /// Cost per byte for a transaction that publishes a package + package_publish_cost_per_byte: Option, + + // Per-byte cost of reading an object during transaction execution + obj_access_cost_read_per_byte: Option, + + // Per-byte cost of writing an object during transaction execution + obj_access_cost_mutate_per_byte: Option, + + // Per-byte cost of deleting an object during transaction execution + obj_access_cost_delete_per_byte: Option, + + /// Per-byte cost charged for each input object to a transaction. + /// Meant to approximate the cost of checking locks for each object + // TODO: Option tx digest map + obj_access_cost_verify_per_byte: Option, + + /// === Gas version. gas model === + + /// Gas model version, what code we are using to charge gas + gas_model_version: Option, + + /// === Storage gas costs === + + /// Per-byte cost of storing an object in the Iota global object store. Some + /// of this cost may be refundable if the object is later freed + obj_data_cost_refundable: Option, + + // Per-byte cost of storing an object in the Iota transaction log (e.g., in + // CertifiedTransactionEffects) This depends on the size of various fields including the + // effects TODO: Option, + + /// === Tokenomics === + + // TODO: Option, + + /// 5% of the storage fund's share of rewards are reinvested into the + /// storage fund. In basis point. + storage_fund_reinvest_rate: Option, + + /// The share of rewards that will be slashed and redistributed is 50%. + /// In basis point. + reward_slashing_rate: Option, + + /// Unit gas price, Micros per internal gas unit. + storage_gas_price: Option, + + /// === Core Protocol === + + /// Max number of transactions per checkpoint. + /// Note that this is a protocol constant and not a config as validators + /// must have this set to the same value, otherwise they *will* fork. + max_transactions_per_checkpoint: Option, + + /// Max size of a checkpoint in bytes. + /// Note that this is a protocol constant and not a config as validators + /// must have this set to the same value, otherwise they *will* fork. + max_checkpoint_size_bytes: Option, + + /// A protocol upgrade always requires 2f+1 stake to agree. We support a + /// buffer of additional stake (as a fraction of f, expressed in basis + /// points) that is required before an upgrade can happen automatically. + /// 10000bps would indicate that complete unanimity is required (all + /// 3f+1 must vote), while 0bps would indicate that 2f+1 is sufficient. + buffer_stake_for_protocol_upgrade_bps: Option, + + // === Native Function Costs === + + // `address` module + // Cost params for the Move native function `address::from_bytes(bytes: vector)` + address_from_bytes_cost_base: Option, + // Cost params for the Move native function `address::to_u256(address): u256` + address_to_u256_cost_base: Option, + // Cost params for the Move native function `address::from_u256(u256): address` + address_from_u256_cost_base: Option, + + // `dynamic_field` module + // Cost params for the Move native function `hash_type_and_key(parent: + // address, k: K): address` + dynamic_field_hash_type_and_key_cost_base: Option, + dynamic_field_hash_type_and_key_type_cost_per_byte: Option, + dynamic_field_hash_type_and_key_value_cost_per_byte: Option, + dynamic_field_hash_type_and_key_type_tag_cost_per_byte: Option, + // Cost params for the Move native function `add_child_object(parent: address, + // child: Child)` + dynamic_field_add_child_object_cost_base: Option, + dynamic_field_add_child_object_type_cost_per_byte: Option, + dynamic_field_add_child_object_value_cost_per_byte: Option, + dynamic_field_add_child_object_struct_tag_cost_per_byte: Option, + // Cost params for the Move native function `borrow_child_object_mut(parent: &mut + // UID, id: address): &mut Child` + dynamic_field_borrow_child_object_cost_base: Option, + dynamic_field_borrow_child_object_child_ref_cost_per_byte: Option, + dynamic_field_borrow_child_object_type_cost_per_byte: Option, + // Cost params for the Move native function `remove_child_object(parent: address, + // id: address): Child` + dynamic_field_remove_child_object_cost_base: Option, + dynamic_field_remove_child_object_child_cost_per_byte: Option, + dynamic_field_remove_child_object_type_cost_per_byte: Option, + // Cost params for the Move native function `has_child_object(parent: address, id: address): + // bool` + dynamic_field_has_child_object_cost_base: Option, + // Cost params for the Move native function `has_child_object_with_ty(parent: + // address, id: address): bool` + dynamic_field_has_child_object_with_ty_cost_base: Option, + dynamic_field_has_child_object_with_ty_type_cost_per_byte: Option, + dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: Option, + + // `event` module + // Cost params for the Move native function `event::emit(event: T)` + event_emit_cost_base: Option, + event_emit_value_size_derivation_cost_per_byte: Option, + event_emit_tag_size_derivation_cost_per_byte: Option, + event_emit_output_cost_per_byte: Option, + + // `object` module + // Cost params for the Move native function `borrow_uid(obj: &T): &UID` + object_borrow_uid_cost_base: Option, + // Cost params for the Move native function `delete_impl(id: address)` + object_delete_impl_cost_base: Option, + // Cost params for the Move native function `record_new_uid(id: address)` + object_record_new_uid_cost_base: Option, + + // Transfer + // Cost params for the Move native function `transfer_impl(obj: T, recipient: address)` + transfer_transfer_internal_cost_base: Option, + // Cost params for the Move native function `freeze_object(obj: T)` + transfer_freeze_object_cost_base: Option, + // Cost params for the Move native function `share_object(obj: T)` + transfer_share_object_cost_base: Option, + // Cost params for the Move native function + // `receive_object(p: &mut UID, recv: ReceivingT)` + transfer_receive_object_cost_base: Option, + + // TxContext + // Cost params for the Move native function `transfer_impl(obj: T, recipient: address)` + tx_context_derive_id_cost_base: Option, + + // Types + // Cost params for the Move native function `is_one_time_witness(_: &T): bool` + types_is_one_time_witness_cost_base: Option, + types_is_one_time_witness_type_tag_cost_per_byte: Option, + types_is_one_time_witness_type_cost_per_byte: Option, + + // Validator + // Cost params for the Move native function `validate_metadata_bcs(metadata: vector)` + validator_validate_metadata_cost_base: Option, + validator_validate_metadata_data_cost_per_byte: Option, + + // Crypto natives + crypto_invalid_arguments_cost: Option, + // bls12381::bls12381_min_sig_verify + bls12381_bls12381_min_sig_verify_cost_base: Option, + bls12381_bls12381_min_sig_verify_msg_cost_per_byte: Option, + bls12381_bls12381_min_sig_verify_msg_cost_per_block: Option, + + // bls12381::bls12381_min_pk_verify + bls12381_bls12381_min_pk_verify_cost_base: Option, + bls12381_bls12381_min_pk_verify_msg_cost_per_byte: Option, + bls12381_bls12381_min_pk_verify_msg_cost_per_block: Option, + + // ecdsa_k1::ecrecover + ecdsa_k1_ecrecover_keccak256_cost_base: Option, + ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: Option, + ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: Option, + ecdsa_k1_ecrecover_sha256_cost_base: Option, + ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: Option, + ecdsa_k1_ecrecover_sha256_msg_cost_per_block: Option, + + // ecdsa_k1::decompress_pubkey + ecdsa_k1_decompress_pubkey_cost_base: Option, + + // ecdsa_k1::secp256k1_verify + ecdsa_k1_secp256k1_verify_keccak256_cost_base: Option, + ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: Option, + ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: Option, + ecdsa_k1_secp256k1_verify_sha256_cost_base: Option, + ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: Option, + ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: Option, + + // ecdsa_r1::ecrecover + ecdsa_r1_ecrecover_keccak256_cost_base: Option, + ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: Option, + ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: Option, + ecdsa_r1_ecrecover_sha256_cost_base: Option, + ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: Option, + ecdsa_r1_ecrecover_sha256_msg_cost_per_block: Option, + + // ecdsa_r1::secp256k1_verify + ecdsa_r1_secp256r1_verify_keccak256_cost_base: Option, + ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: Option, + ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: Option, + ecdsa_r1_secp256r1_verify_sha256_cost_base: Option, + ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: Option, + ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: Option, + + // ecvrf::verify + ecvrf_ecvrf_verify_cost_base: Option, + ecvrf_ecvrf_verify_alpha_string_cost_per_byte: Option, + ecvrf_ecvrf_verify_alpha_string_cost_per_block: Option, + + // ed25519 + ed25519_ed25519_verify_cost_base: Option, + ed25519_ed25519_verify_msg_cost_per_byte: Option, + ed25519_ed25519_verify_msg_cost_per_block: Option, + + // groth16::prepare_verifying_key + groth16_prepare_verifying_key_bls12381_cost_base: Option, + groth16_prepare_verifying_key_bn254_cost_base: Option, + + // groth16::verify_groth16_proof_internal + groth16_verify_groth16_proof_internal_bls12381_cost_base: Option, + groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: Option, + groth16_verify_groth16_proof_internal_bn254_cost_base: Option, + groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: Option, + groth16_verify_groth16_proof_internal_public_input_cost_per_byte: Option, + + // hash::blake2b256 + hash_blake2b256_cost_base: Option, + hash_blake2b256_data_cost_per_byte: Option, + hash_blake2b256_data_cost_per_block: Option, + + // hash::keccak256 + hash_keccak256_cost_base: Option, + hash_keccak256_data_cost_per_byte: Option, + hash_keccak256_data_cost_per_block: Option, + + // poseidon::poseidon_bn254 + poseidon_bn254_cost_base: Option, + poseidon_bn254_cost_per_block: Option, + + // group_ops + group_ops_bls12381_decode_scalar_cost: Option, + group_ops_bls12381_decode_g1_cost: Option, + group_ops_bls12381_decode_g2_cost: Option, + group_ops_bls12381_decode_gt_cost: Option, + group_ops_bls12381_scalar_add_cost: Option, + group_ops_bls12381_g1_add_cost: Option, + group_ops_bls12381_g2_add_cost: Option, + group_ops_bls12381_gt_add_cost: Option, + group_ops_bls12381_scalar_sub_cost: Option, + group_ops_bls12381_g1_sub_cost: Option, + group_ops_bls12381_g2_sub_cost: Option, + group_ops_bls12381_gt_sub_cost: Option, + group_ops_bls12381_scalar_mul_cost: Option, + group_ops_bls12381_g1_mul_cost: Option, + group_ops_bls12381_g2_mul_cost: Option, + group_ops_bls12381_gt_mul_cost: Option, + group_ops_bls12381_scalar_div_cost: Option, + group_ops_bls12381_g1_div_cost: Option, + group_ops_bls12381_g2_div_cost: Option, + group_ops_bls12381_gt_div_cost: Option, + group_ops_bls12381_g1_hash_to_base_cost: Option, + group_ops_bls12381_g2_hash_to_base_cost: Option, + group_ops_bls12381_g1_hash_to_cost_per_byte: Option, + group_ops_bls12381_g2_hash_to_cost_per_byte: Option, + group_ops_bls12381_g1_msm_base_cost: Option, + group_ops_bls12381_g2_msm_base_cost: Option, + group_ops_bls12381_g1_msm_base_cost_per_input: Option, + group_ops_bls12381_g2_msm_base_cost_per_input: Option, + group_ops_bls12381_msm_max_len: Option, + group_ops_bls12381_pairing_cost: Option, + + // hmac::hmac_sha3_256 + hmac_hmac_sha3_256_cost_base: Option, + hmac_hmac_sha3_256_input_cost_per_byte: Option, + hmac_hmac_sha3_256_input_cost_per_block: Option, + + // zklogin::check_zklogin_id + check_zklogin_id_cost_base: Option, + // zklogin::check_zklogin_issuer + check_zklogin_issuer_cost_base: Option, + + // Const params for consensus scoring decision + // The scaling factor property for the MED outlier detection + scoring_decision_mad_divisor: Option, + // The cutoff value for the MED outlier detection + scoring_decision_cutoff_value: Option, + + /// === Execution Version === + execution_version: Option, + + // Dictates the threshold (percentage of stake) that is used to calculate the "bad" nodes to be + // swapped when creating the consensus schedule. The values should be of the range [0 - 33]. + // Anything above 33 (f) will not be allowed. + consensus_bad_nodes_stake_threshold: Option, + + max_jwk_votes_per_validator_per_epoch: Option, + // The maximum age of a JWK in epochs before it is removed from the AuthenticatorState object. + // Applied at the end of an epoch as a delta from the new epoch value, so setting this to 1 + // will cause the new epoch to start with JWKs from the previous epoch still valid. + max_age_of_jwk_in_epochs: Option, + + /// === random beacon === + + /// Maximum allowed precision loss when reducing voting weights for the + /// random beacon protocol. + random_beacon_reduction_allowed_delta: Option, + + /// Minimum number of shares below which voting weights will not be reduced + /// for the random beacon protocol. + random_beacon_reduction_lower_bound: Option, + + /// Consensus Round after which DKG should be aborted and randomness + /// disabled for the epoch, if it hasn't already completed. + random_beacon_dkg_timeout_round: Option, + + /// The maximum serialised transaction size (in bytes) accepted by + /// consensus. That should be bigger than the `max_tx_size_bytes` with + /// some additional headroom. + consensus_max_transaction_size_bytes: Option, + /// The maximum size of transactions included in a consensus proposed block + consensus_max_transactions_in_block_bytes: Option, +} + +// feature flags +impl ProtocolConfig { + // Add checks for feature flag support here, e.g.: + // pub fn check_new_protocol_feature_supported(&self) -> Result<(), Error> { + // if self.feature_flags.new_protocol_feature_supported { + // Ok(()) + // } else { + // Err(Error(format!( + // "new_protocol_feature is not supported at {:?}", + // self.version + // ))) + // } + // } + + pub fn check_package_upgrades_supported(&self) -> Result<(), Error> { + if self.feature_flags.package_upgrades { + Ok(()) + } else { + Err(Error(format!( + "package upgrades are not supported at {:?}", + self.version + ))) + } + } + + pub fn allow_receiving_object_id(&self) -> bool { + self.feature_flags.allow_receiving_object_id + } + + pub fn receiving_objects_supported(&self) -> bool { + self.feature_flags.receive_objects + } + + pub fn package_upgrades_supported(&self) -> bool { + self.feature_flags.package_upgrades + } + + pub fn check_commit_root_state_digest_supported(&self) -> bool { + self.feature_flags.commit_root_state_digest + } + + pub fn get_advance_epoch_start_time_in_safe_mode(&self) -> bool { + self.feature_flags.advance_epoch_start_time_in_safe_mode + } + + pub fn loaded_child_objects_fixed(&self) -> bool { + self.feature_flags.loaded_child_objects_fixed + } + + pub fn missing_type_is_compatibility_error(&self) -> bool { + self.feature_flags.missing_type_is_compatibility_error + } + + pub fn scoring_decision_with_validity_cutoff(&self) -> bool { + self.feature_flags.scoring_decision_with_validity_cutoff + } + + pub fn narwhal_versioned_metadata(&self) -> bool { + self.feature_flags.narwhal_versioned_metadata + } + + pub fn consensus_order_end_of_epoch_last(&self) -> bool { + self.feature_flags.consensus_order_end_of_epoch_last + } + + pub fn disallow_adding_abilities_on_upgrade(&self) -> bool { + self.feature_flags.disallow_adding_abilities_on_upgrade + } + + pub fn disable_invariant_violation_check_in_swap_loc(&self) -> bool { + self.feature_flags + .disable_invariant_violation_check_in_swap_loc + } + + pub fn advance_to_highest_supported_protocol_version(&self) -> bool { + self.feature_flags + .advance_to_highest_supported_protocol_version + } + + pub fn ban_entry_init(&self) -> bool { + self.feature_flags.ban_entry_init + } + + pub fn package_digest_hash_module(&self) -> bool { + self.feature_flags.package_digest_hash_module + } + + pub fn disallow_change_struct_type_params_on_upgrade(&self) -> bool { + self.feature_flags + .disallow_change_struct_type_params_on_upgrade + } + + pub fn no_extraneous_module_bytes(&self) -> bool { + self.feature_flags.no_extraneous_module_bytes + } + + pub fn zklogin_auth(&self) -> bool { + self.feature_flags.zklogin_auth + } + + pub fn zklogin_supported_providers(&self) -> &BTreeSet { + &self.feature_flags.zklogin_supported_providers + } + + pub fn consensus_transaction_ordering(&self) -> ConsensusTransactionOrdering { + self.feature_flags.consensus_transaction_ordering + } + + pub fn simplified_unwrap_then_delete(&self) -> bool { + self.feature_flags.simplified_unwrap_then_delete + } + + pub fn supports_upgraded_multisig(&self) -> bool { + self.feature_flags.upgraded_multisig_supported + } + + pub fn txn_base_cost_as_multiplier(&self) -> bool { + self.feature_flags.txn_base_cost_as_multiplier + } + + pub fn shared_object_deletion(&self) -> bool { + self.feature_flags.shared_object_deletion + } + + pub fn narwhal_new_leader_election_schedule(&self) -> bool { + self.feature_flags.narwhal_new_leader_election_schedule + } + + pub fn loaded_child_object_format(&self) -> bool { + self.feature_flags.loaded_child_object_format + } + + pub fn enable_jwk_consensus_updates(&self) -> bool { + let ret = self.feature_flags.enable_jwk_consensus_updates; + if ret { + // jwk updates required end-of-epoch transactions + assert!(self.feature_flags.end_of_epoch_transaction_supported); + } + ret + } + + pub fn simple_conservation_checks(&self) -> bool { + self.feature_flags.simple_conservation_checks + } + + pub fn loaded_child_object_format_type(&self) -> bool { + self.feature_flags.loaded_child_object_format_type + } + + pub fn end_of_epoch_transaction_supported(&self) -> bool { + let ret = self.feature_flags.end_of_epoch_transaction_supported; + if !ret { + // jwk updates required end-of-epoch transactions + assert!(!self.feature_flags.enable_jwk_consensus_updates); + } + ret + } + + pub fn recompute_has_public_transfer_in_execution(&self) -> bool { + self.feature_flags + .recompute_has_public_transfer_in_execution + } + + // this function only exists for readability in the genesis code. + pub fn create_authenticator_state_in_genesis(&self) -> bool { + self.enable_jwk_consensus_updates() + } + + pub fn random_beacon(&self) -> bool { + self.feature_flags.random_beacon + } + + pub fn enable_effects_v2(&self) -> bool { + self.feature_flags.enable_effects_v2 + } + + pub fn narwhal_certificate_v2(&self) -> bool { + self.feature_flags.narwhal_certificate_v2 + } + + pub fn verify_legacy_zklogin_address(&self) -> bool { + self.feature_flags.verify_legacy_zklogin_address + } + + pub fn accept_zklogin_in_multisig(&self) -> bool { + self.feature_flags.accept_zklogin_in_multisig + } + + pub fn throughput_aware_consensus_submission(&self) -> bool { + self.feature_flags.throughput_aware_consensus_submission + } + + pub fn include_consensus_digest_in_prologue(&self) -> bool { + self.feature_flags.include_consensus_digest_in_prologue + } + + pub fn hardened_otw_check(&self) -> bool { + self.feature_flags.hardened_otw_check + } + + pub fn enable_poseidon(&self) -> bool { + self.feature_flags.enable_poseidon + } + + pub fn enable_coin_deny_list(&self) -> bool { + self.feature_flags.enable_coin_deny_list + } + + pub fn enable_group_ops_native_functions(&self) -> bool { + self.feature_flags.enable_group_ops_native_functions + } + + pub fn enable_group_ops_native_function_msm(&self) -> bool { + self.feature_flags.enable_group_ops_native_function_msm + } + + pub fn reject_mutable_random_on_entry_functions(&self) -> bool { + self.feature_flags.reject_mutable_random_on_entry_functions + } +} + +#[cfg(not(msim))] +static POISON_VERSION_METHODS: AtomicBool = AtomicBool::new(false); + +// Use a thread local in sim tests for test isolation. +#[cfg(msim)] +thread_local! { + static POISON_VERSION_METHODS: AtomicBool = AtomicBool::new(false); +} + +// Instantiations for each protocol version. +impl ProtocolConfig { + /// Get the value ProtocolConfig that are in effect during the given + /// protocol version. + pub fn get_for_version(version: ProtocolVersion, chain: Chain) -> Self { + // ProtocolVersion can be deserialized so we need to check it here as well. + assert!( + version >= ProtocolVersion::MIN, + "Network protocol version is {:?}, but the minimum supported version by the binary is {:?}. Please upgrade the binary.", + version, + ProtocolVersion::MIN.0, + ); + assert!( + version <= ProtocolVersion::MAX_ALLOWED, + "Network protocol version is {:?}, but the maximum supported version by the binary is {:?}. Please upgrade the binary.", + version, + ProtocolVersion::MAX_ALLOWED.0, + ); + + let mut ret = Self::get_for_version_impl(version, chain); + ret.version = version; + + CONFIG_OVERRIDE.with(|ovr| { + if let Some(override_fn) = &*ovr.borrow() { + warn!( + "overriding ProtocolConfig settings with custom settings (you should not see this log outside of tests)" + ); + override_fn(version, ret) + } else { + ret + } + }) + } + + /// Get the value ProtocolConfig that are in effect during the given + /// protocol version. Or none if the version is not supported. + pub fn get_for_version_if_supported(version: ProtocolVersion, chain: Chain) -> Option { + if version.0 >= ProtocolVersion::MIN.0 && version.0 <= ProtocolVersion::MAX_ALLOWED.0 { + let mut ret = Self::get_for_version_impl(version, chain); + ret.version = version; + Some(ret) + } else { + None + } + } + + #[cfg(not(msim))] + pub fn poison_get_for_min_version() { + POISON_VERSION_METHODS.store(true, Ordering::Relaxed); + } + + #[cfg(not(msim))] + fn load_poison_get_for_min_version() -> bool { + POISON_VERSION_METHODS.load(Ordering::Relaxed) + } + + #[cfg(msim)] + pub fn poison_get_for_min_version() { + POISON_VERSION_METHODS.with(|p| p.store(true, Ordering::Relaxed)); + } + + #[cfg(msim)] + fn load_poison_get_for_min_version() -> bool { + POISON_VERSION_METHODS.with(|p| p.load(Ordering::Relaxed)) + } + + /// Convenience to get the constants at the current minimum supported + /// version. Mainly used by client code that may not yet be + /// protocol-version aware. + pub fn get_for_min_version() -> Self { + if Self::load_poison_get_for_min_version() { + panic!("get_for_min_version called on validator"); + } + ProtocolConfig::get_for_version(ProtocolVersion::MIN, Chain::Unknown) + } + + /// CAREFUL! - You probably want to use `get_for_version` instead. + /// + /// Convenience to get the constants at the current maximum supported + /// version. Mainly used by genesis. Note well that this function uses + /// the max version supported locally by the node, which is not + /// necessarily the current version of the network. ALSO, this function + /// disregards chain specific config (by using Chain::Unknown), thereby + /// potentially returning a protocol config that is incorrect for some + /// feature flags. Definitely safe for testing and for protocol version + /// 11 and prior. + #[allow(non_snake_case)] + pub fn get_for_max_version_UNSAFE() -> Self { + if Self::load_poison_get_for_min_version() { + panic!("get_for_max_version_UNSAFE called on validator"); + } + ProtocolConfig::get_for_version(ProtocolVersion::MAX, Chain::Unknown) + } + + fn get_for_version_impl(version: ProtocolVersion, chain: Chain) -> Self { + #[cfg(msim)] + { + // populate the fake simulator version # with a different base tx cost. + if version == ProtocolVersion::MAX_ALLOWED { + let mut config = Self::get_for_version_impl(version - 1, Chain::Unknown); + config.base_tx_cost_fixed = Some(config.base_tx_cost_fixed() + 1000); + return config; + } + } + + // IMPORTANT: Never modify the value of any constant for a pre-existing protocol + // version. To change the values here you must create a new protocol + // version with the new values! + let mut cfg = Self { + // will be overwritten before being returned + version, + + // All flags are disabled in V1 + feature_flags: Default::default(), + + max_tx_size_bytes: Some(128 * 1024), + // We need this number to be at least 100x less than + // `max_serialized_tx_effects_size_bytes`otherwise effects can be huge + max_input_objects: Some(2048), + max_serialized_tx_effects_size_bytes: Some(512 * 1024), + max_serialized_tx_effects_size_bytes_system_tx: Some(512 * 1024 * 16), + max_gas_payment_objects: Some(256), + max_modules_in_publish: Some(128), + max_package_dependencies: None, + max_arguments: Some(512), + max_type_arguments: Some(16), + max_type_argument_depth: Some(16), + max_pure_argument_size: Some(16 * 1024), + max_programmable_tx_commands: Some(1024), + move_binary_format_version: Some(6), + binary_module_handles: None, + binary_struct_handles: None, + binary_function_handles: None, + binary_function_instantiations: None, + binary_signatures: None, + binary_constant_pool: None, + binary_identifiers: None, + binary_address_identifiers: None, + binary_struct_defs: None, + binary_struct_def_instantiations: None, + binary_function_defs: None, + binary_field_handles: None, + binary_field_instantiations: None, + binary_friend_decls: None, + max_move_object_size: Some(250 * 1024), + max_move_package_size: Some(100 * 1024), + max_publish_or_upgrade_per_ptb: None, + max_tx_gas: Some(10_000_000_000), + max_gas_price: Some(100_000), + max_gas_computation_bucket: Some(5_000_000), + max_loop_depth: Some(5), + max_generic_instantiation_length: Some(32), + max_function_parameters: Some(128), + max_basic_blocks: Some(1024), + max_value_stack_size: Some(1024), + max_type_nodes: Some(256), + max_push_size: Some(10000), + max_struct_definitions: Some(200), + max_function_definitions: Some(1000), + max_fields_in_struct: Some(32), + max_dependency_depth: Some(100), + max_num_event_emit: Some(256), + max_num_new_move_object_ids: Some(2048), + max_num_new_move_object_ids_system_tx: Some(2048 * 16), + max_num_deleted_move_object_ids: Some(2048), + max_num_deleted_move_object_ids_system_tx: Some(2048 * 16), + max_num_transferred_move_object_ids: Some(2048), + max_num_transferred_move_object_ids_system_tx: Some(2048 * 16), + max_event_emit_size: Some(250 * 1024), + max_move_vector_len: Some(256 * 1024), + + // TODO: Is this too low/high? + max_back_edges_per_function: Some(10_000), + + // TODO: Is this too low/high? + max_back_edges_per_module: Some(10_000), + + // TODO: Is this too low/high? + max_verifier_meter_ticks_per_function: Some(6_000_000), + + // TODO: Is this too low/high? + max_meter_ticks_per_module: Some(6_000_000), + + object_runtime_max_num_cached_objects: Some(1000), + object_runtime_max_num_cached_objects_system_tx: Some(1000 * 16), + object_runtime_max_num_store_entries: Some(1000), + object_runtime_max_num_store_entries_system_tx: Some(1000 * 16), + base_tx_cost_fixed: Some(110_000), + package_publish_cost_fixed: Some(1_000), + base_tx_cost_per_byte: Some(0), + package_publish_cost_per_byte: Some(80), + obj_access_cost_read_per_byte: Some(15), + obj_access_cost_mutate_per_byte: Some(40), + obj_access_cost_delete_per_byte: Some(40), + obj_access_cost_verify_per_byte: Some(200), + obj_data_cost_refundable: Some(100), + obj_metadata_cost_non_refundable: Some(50), + gas_model_version: Some(1), + storage_rebate_rate: Some(9900), + storage_fund_reinvest_rate: Some(500), + reward_slashing_rate: Some(5000), + storage_gas_price: Some(1), + max_transactions_per_checkpoint: Some(10_000), + max_checkpoint_size_bytes: Some(30 * 1024 * 1024), + + // For now, perform upgrades with a bare quorum of validators. + // MUSTFIX: This number should be increased to at least 2000 (20%) for mainnet. + buffer_stake_for_protocol_upgrade_bps: Some(0), + + // === Native Function Costs === + // `address` module + // Cost params for the Move native function `address::from_bytes(bytes: vector)` + address_from_bytes_cost_base: Some(52), + // Cost params for the Move native function `address::to_u256(address): u256` + address_to_u256_cost_base: Some(52), + // Cost params for the Move native function `address::from_u256(u256): address` + address_from_u256_cost_base: Some(52), + + // `dynamic_field` module + // Cost params for the Move native function `hash_type_and_key(parent: address, k: K): address` + dynamic_field_hash_type_and_key_cost_base: Some(100), + dynamic_field_hash_type_and_key_type_cost_per_byte: Some(2), + dynamic_field_hash_type_and_key_value_cost_per_byte: Some(2), + dynamic_field_hash_type_and_key_type_tag_cost_per_byte: Some(2), + // Cost params for the Move native function `add_child_object(parent: + // address, child: Child)` + dynamic_field_add_child_object_cost_base: Some(100), + dynamic_field_add_child_object_type_cost_per_byte: Some(10), + dynamic_field_add_child_object_value_cost_per_byte: Some(10), + dynamic_field_add_child_object_struct_tag_cost_per_byte: Some(10), + // Cost params for the Move native function `borrow_child_object_mut(parent: + // &mut UID, id: address): &mut Child` + dynamic_field_borrow_child_object_cost_base: Some(100), + dynamic_field_borrow_child_object_child_ref_cost_per_byte: Some(10), + dynamic_field_borrow_child_object_type_cost_per_byte: Some(10), + // Cost params for the Move native function `remove_child_object(parent: + // address, id: address): Child` + dynamic_field_remove_child_object_cost_base: Some(100), + dynamic_field_remove_child_object_child_cost_per_byte: Some(2), + dynamic_field_remove_child_object_type_cost_per_byte: Some(2), + // Cost params for the Move native function `has_child_object(parent: address, id: + // address): bool` + dynamic_field_has_child_object_cost_base: Some(100), + // Cost params for the Move native function `has_child_object_with_ty(parent: address, id: address): bool` + dynamic_field_has_child_object_with_ty_cost_base: Some(100), + dynamic_field_has_child_object_with_ty_type_cost_per_byte: Some(2), + dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: Some(2), + + // `event` module + // Cost params for the Move native function `event::emit(event: T)` + event_emit_cost_base: Some(52), + event_emit_value_size_derivation_cost_per_byte: Some(2), + event_emit_tag_size_derivation_cost_per_byte: Some(5), + event_emit_output_cost_per_byte: Some(10), + + // `object` module + // Cost params for the Move native function `borrow_uid(obj: &T): &UID` + object_borrow_uid_cost_base: Some(52), + // Cost params for the Move native function `delete_impl(id: address)` + object_delete_impl_cost_base: Some(52), + // Cost params for the Move native function `record_new_uid(id: address)` + object_record_new_uid_cost_base: Some(52), + + // `transfer` module + // Cost params for the Move native function `transfer_impl(obj: T, recipient: + // address)` + transfer_transfer_internal_cost_base: Some(52), + // Cost params for the Move native function `freeze_object(obj: T)` + transfer_freeze_object_cost_base: Some(52), + // Cost params for the Move native function `share_object(obj: T)` + transfer_share_object_cost_base: Some(52), + transfer_receive_object_cost_base: None, + + // `tx_context` module + // Cost params for the Move native function `transfer_impl(obj: T, recipient: + // address)` + tx_context_derive_id_cost_base: Some(52), + + // `types` module + // Cost params for the Move native function `is_one_time_witness(_: &T): bool` + types_is_one_time_witness_cost_base: Some(52), + types_is_one_time_witness_type_tag_cost_per_byte: Some(2), + types_is_one_time_witness_type_cost_per_byte: Some(2), + + // `validator` module + // Cost params for the Move native function `validate_metadata_bcs(metadata: + // vector)` + validator_validate_metadata_cost_base: Some(52), + validator_validate_metadata_data_cost_per_byte: Some(2), + + // Crypto + crypto_invalid_arguments_cost: Some(100), + // bls12381::bls12381_min_pk_verify + bls12381_bls12381_min_sig_verify_cost_base: Some(52), + bls12381_bls12381_min_sig_verify_msg_cost_per_byte: Some(2), + bls12381_bls12381_min_sig_verify_msg_cost_per_block: Some(2), + + // bls12381::bls12381_min_pk_verify + bls12381_bls12381_min_pk_verify_cost_base: Some(52), + bls12381_bls12381_min_pk_verify_msg_cost_per_byte: Some(2), + bls12381_bls12381_min_pk_verify_msg_cost_per_block: Some(2), + + // ecdsa_k1::ecrecover + ecdsa_k1_ecrecover_keccak256_cost_base: Some(52), + ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: Some(2), + ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: Some(2), + ecdsa_k1_ecrecover_sha256_cost_base: Some(52), + ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: Some(2), + ecdsa_k1_ecrecover_sha256_msg_cost_per_block: Some(2), + + // ecdsa_k1::decompress_pubkey + ecdsa_k1_decompress_pubkey_cost_base: Some(52), + + // ecdsa_k1::secp256k1_verify + ecdsa_k1_secp256k1_verify_keccak256_cost_base: Some(52), + ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: Some(2), + ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: Some(2), + ecdsa_k1_secp256k1_verify_sha256_cost_base: Some(52), + ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: Some(2), + ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: Some(2), + + // ecdsa_r1::ecrecover + ecdsa_r1_ecrecover_keccak256_cost_base: Some(52), + ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: Some(2), + ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: Some(2), + ecdsa_r1_ecrecover_sha256_cost_base: Some(52), + ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: Some(2), + ecdsa_r1_ecrecover_sha256_msg_cost_per_block: Some(2), + + // ecdsa_r1::secp256k1_verify + ecdsa_r1_secp256r1_verify_keccak256_cost_base: Some(52), + ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: Some(2), + ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: Some(2), + ecdsa_r1_secp256r1_verify_sha256_cost_base: Some(52), + ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: Some(2), + ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: Some(2), + + // ecvrf::verify + ecvrf_ecvrf_verify_cost_base: Some(52), + ecvrf_ecvrf_verify_alpha_string_cost_per_byte: Some(2), + ecvrf_ecvrf_verify_alpha_string_cost_per_block: Some(2), + + // ed25519 + ed25519_ed25519_verify_cost_base: Some(52), + ed25519_ed25519_verify_msg_cost_per_byte: Some(2), + ed25519_ed25519_verify_msg_cost_per_block: Some(2), + + // groth16::prepare_verifying_key + groth16_prepare_verifying_key_bls12381_cost_base: Some(52), + groth16_prepare_verifying_key_bn254_cost_base: Some(52), + + // groth16::verify_groth16_proof_internal + groth16_verify_groth16_proof_internal_bls12381_cost_base: Some(52), + groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: Some(2), + groth16_verify_groth16_proof_internal_bn254_cost_base: Some(52), + groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: Some(2), + groth16_verify_groth16_proof_internal_public_input_cost_per_byte: Some(2), + + // hash::blake2b256 + hash_blake2b256_cost_base: Some(52), + hash_blake2b256_data_cost_per_byte: Some(2), + hash_blake2b256_data_cost_per_block: Some(2), + // hash::keccak256 + hash_keccak256_cost_base: Some(52), + hash_keccak256_data_cost_per_byte: Some(2), + hash_keccak256_data_cost_per_block: Some(2), + + poseidon_bn254_cost_base: None, + poseidon_bn254_cost_per_block: None, + + // hmac::hmac_sha3_256 + hmac_hmac_sha3_256_cost_base: Some(52), + hmac_hmac_sha3_256_input_cost_per_byte: Some(2), + hmac_hmac_sha3_256_input_cost_per_block: Some(2), + + // group ops + group_ops_bls12381_decode_scalar_cost: None, + group_ops_bls12381_decode_g1_cost: None, + group_ops_bls12381_decode_g2_cost: None, + group_ops_bls12381_decode_gt_cost: None, + group_ops_bls12381_scalar_add_cost: None, + group_ops_bls12381_g1_add_cost: None, + group_ops_bls12381_g2_add_cost: None, + group_ops_bls12381_gt_add_cost: None, + group_ops_bls12381_scalar_sub_cost: None, + group_ops_bls12381_g1_sub_cost: None, + group_ops_bls12381_g2_sub_cost: None, + group_ops_bls12381_gt_sub_cost: None, + group_ops_bls12381_scalar_mul_cost: None, + group_ops_bls12381_g1_mul_cost: None, + group_ops_bls12381_g2_mul_cost: None, + group_ops_bls12381_gt_mul_cost: None, + group_ops_bls12381_scalar_div_cost: None, + group_ops_bls12381_g1_div_cost: None, + group_ops_bls12381_g2_div_cost: None, + group_ops_bls12381_gt_div_cost: None, + group_ops_bls12381_g1_hash_to_base_cost: None, + group_ops_bls12381_g2_hash_to_base_cost: None, + group_ops_bls12381_g1_hash_to_cost_per_byte: None, + group_ops_bls12381_g2_hash_to_cost_per_byte: None, + group_ops_bls12381_g1_msm_base_cost: None, + group_ops_bls12381_g2_msm_base_cost: None, + group_ops_bls12381_g1_msm_base_cost_per_input: None, + group_ops_bls12381_g2_msm_base_cost_per_input: None, + group_ops_bls12381_msm_max_len: None, + group_ops_bls12381_pairing_cost: None, + + // zklogin::check_zklogin_id + check_zklogin_id_cost_base: None, + // zklogin::check_zklogin_issuer + check_zklogin_issuer_cost_base: None, + + max_size_written_objects: None, + max_size_written_objects_system_tx: None, + + // Const params for consensus scoring decision + scoring_decision_mad_divisor: None, + scoring_decision_cutoff_value: None, + + // Limits the length of a Move identifier + max_move_identifier_len: None, + max_move_value_depth: None, + + gas_rounding_step: None, + + execution_version: None, + + max_event_emit_size_total: None, + + consensus_bad_nodes_stake_threshold: None, + + max_jwk_votes_per_validator_per_epoch: None, + + max_age_of_jwk_in_epochs: None, + + random_beacon_reduction_allowed_delta: None, + + random_beacon_reduction_lower_bound: None, + + random_beacon_dkg_timeout_round: None, + + consensus_max_transaction_size_bytes: None, + + consensus_max_transactions_in_block_bytes: None, + // When adding a new constant, set it to None in the earliest version, like this: + // new_constant: None, + }; + for cur in 2..=version.0 { + match cur { + 1 => unreachable!(), + 2 => { + cfg.feature_flags.advance_epoch_start_time_in_safe_mode = true; + } + 3 => { + // changes for gas model + cfg.gas_model_version = Some(2); + // max gas budget is in MICROS and an absolute value 50IOTA + cfg.max_tx_gas = Some(50_000_000_000); + // min gas budget is in MICROS and an absolute value 2000MICROS or 0.000002IOTA + cfg.base_tx_cost_fixed = Some(2_000); + // storage gas price multiplier + cfg.storage_gas_price = Some(76); + cfg.feature_flags.loaded_child_objects_fixed = true; + // max size of written objects during a TXn + // this is a sum of all objects written during a TXn + cfg.max_size_written_objects = Some(5 * 1000 * 1000); + // max size of written objects during a system TXn to allow for larger writes + // akin to `max_size_written_objects` but for system TXns + cfg.max_size_written_objects_system_tx = Some(50 * 1000 * 1000); + cfg.feature_flags.package_upgrades = true; + } + // This is the first protocol version currently possible. + // Mainnet starts with version 4. Previous versions are pre mainnet and have + // all been wiped out. + // Every other chain is after version 4. + 4 => { + // Change reward slashing rate to 100%. + cfg.reward_slashing_rate = Some(10000); + // protect old and new lookup for object version + cfg.gas_model_version = Some(3); + } + 5 => { + cfg.feature_flags.missing_type_is_compatibility_error = true; + cfg.gas_model_version = Some(4); + cfg.feature_flags.scoring_decision_with_validity_cutoff = true; + cfg.scoring_decision_mad_divisor = Some(2.3); + cfg.scoring_decision_cutoff_value = Some(2.5); + } + 6 => { + cfg.gas_model_version = Some(5); + cfg.buffer_stake_for_protocol_upgrade_bps = Some(5000); + cfg.feature_flags.consensus_order_end_of_epoch_last = true; + } + 7 => { + cfg.feature_flags.disallow_adding_abilities_on_upgrade = true; + cfg.feature_flags + .disable_invariant_violation_check_in_swap_loc = true; + cfg.feature_flags.ban_entry_init = true; + cfg.feature_flags.package_digest_hash_module = true; + } + 8 => { + cfg.feature_flags + .disallow_change_struct_type_params_on_upgrade = true; + } + 9 => { + // Limits the length of a Move identifier + cfg.max_move_identifier_len = Some(128); + cfg.feature_flags.no_extraneous_module_bytes = true; + cfg.feature_flags + .advance_to_highest_supported_protocol_version = true; + } + 10 => { + cfg.max_verifier_meter_ticks_per_function = Some(16_000_000); + cfg.max_meter_ticks_per_module = Some(16_000_000); + } + 11 => { + cfg.max_move_value_depth = Some(128); + } + 12 => { + cfg.feature_flags.narwhal_versioned_metadata = true; + if chain != Chain::Mainnet { + cfg.feature_flags.commit_root_state_digest = true; + } + + if chain != Chain::Mainnet && chain != Chain::Testnet { + cfg.feature_flags.zklogin_auth = true; + } + } + 13 => {} + 14 => { + cfg.gas_rounding_step = Some(1_000); + cfg.gas_model_version = Some(6); + } + 15 => { + cfg.feature_flags.consensus_transaction_ordering = + ConsensusTransactionOrdering::ByGasPrice; + } + 16 => { + cfg.feature_flags.simplified_unwrap_then_delete = true; + } + 17 => { + cfg.feature_flags.upgraded_multisig_supported = true; + } + 18 => { + cfg.execution_version = Some(1); + // Following flags are implied by this execution version. Once support for + // earlier protocol versions is dropped, these flags can be + // removed: cfg.feature_flags.package_upgrades = true; + // cfg.feature_flags.disallow_adding_abilities_on_upgrade = true; + // cfg.feature_flags.disallow_change_struct_type_params_on_upgrade = true; + // cfg.feature_flags.loaded_child_objects_fixed = true; + // cfg.feature_flags.ban_entry_init = true; + // cfg.feature_flags.pack_digest_hash_modules = true; + cfg.feature_flags.txn_base_cost_as_multiplier = true; + // this is a multiplier of the gas price + cfg.base_tx_cost_fixed = Some(1_000); + } + 19 => { + cfg.max_num_event_emit = Some(1024); + // We maintain the same total size limit for events, but increase the number of + // events that can be emitted. + cfg.max_event_emit_size_total = Some( + 256 /* former event count limit */ * 250 * 1024, // size limit per event + ); + } + 20 => { + cfg.feature_flags.commit_root_state_digest = true; + + if chain != Chain::Mainnet { + cfg.feature_flags.narwhal_new_leader_election_schedule = true; + cfg.consensus_bad_nodes_stake_threshold = Some(20); + } + } + + 21 => { + if chain != Chain::Mainnet { + cfg.feature_flags.zklogin_supported_providers = BTreeSet::from([ + "Google".to_string(), + "Facebook".to_string(), + "Twitch".to_string(), + ]); + } + } + 22 => { + cfg.feature_flags.loaded_child_object_format = true; + } + 23 => { + cfg.feature_flags.loaded_child_object_format_type = true; + cfg.feature_flags.narwhal_new_leader_election_schedule = true; + // Taking a baby step approach, we consider only 20% by stake as bad nodes so we + // have a 80% by stake of nodes participating in the leader committee. That + // allow us for more redundancy in case we have validators + // under performing - since the responsibility is shared + // amongst more nodes. We can increase that once we do have + // higher confidence. + cfg.consensus_bad_nodes_stake_threshold = Some(20); + } + 24 => { + cfg.feature_flags.simple_conservation_checks = true; + cfg.max_publish_or_upgrade_per_ptb = Some(5); + + cfg.feature_flags.end_of_epoch_transaction_supported = true; + + if chain != Chain::Mainnet { + cfg.feature_flags.enable_jwk_consensus_updates = true; + // Max of 10 votes per hour + cfg.max_jwk_votes_per_validator_per_epoch = Some(240); + cfg.max_age_of_jwk_in_epochs = Some(1); + } + } + 25 => { + // Enable zkLogin for all providers in all networks. + cfg.feature_flags.zklogin_supported_providers = BTreeSet::from([ + "Google".to_string(), + "Facebook".to_string(), + "Twitch".to_string(), + ]); + cfg.feature_flags.zklogin_auth = true; + + // Enable jwk consensus updates + cfg.feature_flags.enable_jwk_consensus_updates = true; + cfg.max_jwk_votes_per_validator_per_epoch = Some(240); + cfg.max_age_of_jwk_in_epochs = Some(1); + } + 26 => { + cfg.gas_model_version = Some(7); + // Only enable receiving objects in devnet + if chain != Chain::Mainnet && chain != Chain::Testnet { + cfg.transfer_receive_object_cost_base = Some(52); + cfg.feature_flags.receive_objects = true; + } + } + 27 => { + cfg.gas_model_version = Some(8); + } + 28 => { + // zklogin::check_zklogin_id + cfg.check_zklogin_id_cost_base = Some(200); + // zklogin::check_zklogin_issuer + cfg.check_zklogin_issuer_cost_base = Some(200); + + // Only enable effects v2 on devnet. + if chain != Chain::Mainnet && chain != Chain::Testnet { + cfg.feature_flags.enable_effects_v2 = true; + } + } + 29 => { + cfg.feature_flags.verify_legacy_zklogin_address = true; + } + 30 => { + // Only enable nw certificate v2 on testnet. + if chain != Chain::Mainnet { + cfg.feature_flags.narwhal_certificate_v2 = true; + } + + cfg.random_beacon_reduction_allowed_delta = Some(800); + // Only enable effects v2 on devnet and testnet. + if chain != Chain::Mainnet { + cfg.feature_flags.enable_effects_v2 = true; + } + + // zklogin_supported_providers config is deprecated, zklogin + // signature verifier will use the fetched jwk map to determine + // whether the provider is supported based on node config. + cfg.feature_flags.zklogin_supported_providers = BTreeSet::default(); + + cfg.feature_flags.recompute_has_public_transfer_in_execution = true; + } + 31 => { + cfg.execution_version = Some(2); + // Only enable shared object deletion on devnet + if chain != Chain::Mainnet && chain != Chain::Testnet { + cfg.feature_flags.shared_object_deletion = true; + } + } + 32 => { + // enable zklogin in multisig in devnet and testnet + if chain != Chain::Mainnet { + cfg.feature_flags.accept_zklogin_in_multisig = true; + } + // enable receiving objects in devnet and testnet + if chain != Chain::Mainnet { + cfg.transfer_receive_object_cost_base = Some(52); + cfg.feature_flags.receive_objects = true; + } + // Only enable random beacon on devnet + if chain != Chain::Mainnet && chain != Chain::Testnet { + cfg.feature_flags.random_beacon = true; + cfg.random_beacon_reduction_lower_bound = Some(1600); + cfg.random_beacon_dkg_timeout_round = Some(200); + } + // Only enable consensus digest in consensus commit prologue in devnet. + if chain != Chain::Testnet && chain != Chain::Mainnet { + cfg.feature_flags.include_consensus_digest_in_prologue = true; + } + + // enable nw cert v2 on mainnet + cfg.feature_flags.narwhal_certificate_v2 = true; + } + 33 => { + cfg.feature_flags.hardened_otw_check = true; + cfg.feature_flags.allow_receiving_object_id = true; + + // Enable transfer-to-object in mainnet + cfg.transfer_receive_object_cost_base = Some(52); + cfg.feature_flags.receive_objects = true; + + // Enable shared object deletion in testnet and devnet + if chain != Chain::Mainnet { + cfg.feature_flags.shared_object_deletion = true; + } + + cfg.feature_flags.enable_effects_v2 = true; + } + 34 => {} + 35 => { + // Add costs for poseidon::poseidon_bn254 + if chain != Chain::Mainnet && chain != Chain::Testnet { + cfg.feature_flags.enable_poseidon = true; + cfg.poseidon_bn254_cost_base = Some(260); + cfg.poseidon_bn254_cost_per_block = Some(10); + } + + cfg.feature_flags.enable_coin_deny_list = true; + } + 36 => { + // Only enable group ops on devnet + if chain != Chain::Mainnet && chain != Chain::Testnet { + cfg.feature_flags.enable_group_ops_native_functions = true; + cfg.feature_flags.enable_group_ops_native_function_msm = true; + // Next values are arbitrary in a similar way as the other crypto native + // functions. + cfg.group_ops_bls12381_decode_scalar_cost = Some(52); + cfg.group_ops_bls12381_decode_g1_cost = Some(52); + cfg.group_ops_bls12381_decode_g2_cost = Some(52); + cfg.group_ops_bls12381_decode_gt_cost = Some(52); + cfg.group_ops_bls12381_scalar_add_cost = Some(52); + cfg.group_ops_bls12381_g1_add_cost = Some(52); + cfg.group_ops_bls12381_g2_add_cost = Some(52); + cfg.group_ops_bls12381_gt_add_cost = Some(52); + cfg.group_ops_bls12381_scalar_sub_cost = Some(52); + cfg.group_ops_bls12381_g1_sub_cost = Some(52); + cfg.group_ops_bls12381_g2_sub_cost = Some(52); + cfg.group_ops_bls12381_gt_sub_cost = Some(52); + cfg.group_ops_bls12381_scalar_mul_cost = Some(52); + cfg.group_ops_bls12381_g1_mul_cost = Some(52); + cfg.group_ops_bls12381_g2_mul_cost = Some(52); + cfg.group_ops_bls12381_gt_mul_cost = Some(52); + cfg.group_ops_bls12381_scalar_div_cost = Some(52); + cfg.group_ops_bls12381_g1_div_cost = Some(52); + cfg.group_ops_bls12381_g2_div_cost = Some(52); + cfg.group_ops_bls12381_gt_div_cost = Some(52); + cfg.group_ops_bls12381_g1_hash_to_base_cost = Some(52); + cfg.group_ops_bls12381_g2_hash_to_base_cost = Some(52); + cfg.group_ops_bls12381_g1_hash_to_cost_per_byte = Some(2); + cfg.group_ops_bls12381_g2_hash_to_cost_per_byte = Some(2); + cfg.group_ops_bls12381_g1_msm_base_cost = Some(52); + cfg.group_ops_bls12381_g2_msm_base_cost = Some(52); + cfg.group_ops_bls12381_g1_msm_base_cost_per_input = Some(52); + cfg.group_ops_bls12381_g2_msm_base_cost_per_input = Some(52); + cfg.group_ops_bls12381_msm_max_len = Some(32); + cfg.group_ops_bls12381_pairing_cost = Some(52); + } + // Enable shared object deletion on all networks. + cfg.feature_flags.shared_object_deletion = true; + + cfg.consensus_max_transaction_size_bytes = Some(256 * 1024); // 256KB + cfg.consensus_max_transactions_in_block_bytes = Some(6 * 1_024 * 1024); + // 6 MB + } + 37 => { + cfg.feature_flags.reject_mutable_random_on_entry_functions = true; + + // Enable consensus digest in consensus commit prologue in testnet and devnet. + if chain != Chain::Mainnet { + cfg.feature_flags.include_consensus_digest_in_prologue = true; + } + } + 38 => { + cfg.binary_module_handles = Some(100); + cfg.binary_struct_handles = Some(300); + cfg.binary_function_handles = Some(1500); + cfg.binary_function_instantiations = Some(750); + cfg.binary_signatures = Some(1000); + // constants and identifiers are proportional to the binary size, + // and they vastly depend on the code, so we are leaving them + // reasonably high + cfg.binary_constant_pool = Some(4000); + cfg.binary_identifiers = Some(10000); + cfg.binary_address_identifiers = Some(100); + cfg.binary_struct_defs = Some(200); + cfg.binary_struct_def_instantiations = Some(100); + cfg.binary_function_defs = Some(1000); + cfg.binary_field_handles = Some(500); + cfg.binary_field_instantiations = Some(250); + cfg.binary_friend_decls = Some(100); + // reduce dependencies maximum + cfg.max_package_dependencies = Some(32); + cfg.max_modules_in_publish = Some(64); + // bump execution version + cfg.execution_version = Some(3); + } + 39 => { + // It is important that we keep this protocol version blank + // due to an issue with random.move. + } + 40 => {} + 41 => { + // Enable group ops and all networks (but not msm) + cfg.feature_flags.enable_group_ops_native_functions = true; + // Next values are arbitrary in a similar way as the other crypto native + // functions. + cfg.group_ops_bls12381_decode_scalar_cost = Some(52); + cfg.group_ops_bls12381_decode_g1_cost = Some(52); + cfg.group_ops_bls12381_decode_g2_cost = Some(52); + cfg.group_ops_bls12381_decode_gt_cost = Some(52); + cfg.group_ops_bls12381_scalar_add_cost = Some(52); + cfg.group_ops_bls12381_g1_add_cost = Some(52); + cfg.group_ops_bls12381_g2_add_cost = Some(52); + cfg.group_ops_bls12381_gt_add_cost = Some(52); + cfg.group_ops_bls12381_scalar_sub_cost = Some(52); + cfg.group_ops_bls12381_g1_sub_cost = Some(52); + cfg.group_ops_bls12381_g2_sub_cost = Some(52); + cfg.group_ops_bls12381_gt_sub_cost = Some(52); + cfg.group_ops_bls12381_scalar_mul_cost = Some(52); + cfg.group_ops_bls12381_g1_mul_cost = Some(52); + cfg.group_ops_bls12381_g2_mul_cost = Some(52); + cfg.group_ops_bls12381_gt_mul_cost = Some(52); + cfg.group_ops_bls12381_scalar_div_cost = Some(52); + cfg.group_ops_bls12381_g1_div_cost = Some(52); + cfg.group_ops_bls12381_g2_div_cost = Some(52); + cfg.group_ops_bls12381_gt_div_cost = Some(52); + cfg.group_ops_bls12381_g1_hash_to_base_cost = Some(52); + cfg.group_ops_bls12381_g2_hash_to_base_cost = Some(52); + cfg.group_ops_bls12381_g1_hash_to_cost_per_byte = Some(2); + cfg.group_ops_bls12381_g2_hash_to_cost_per_byte = Some(2); + cfg.group_ops_bls12381_g1_msm_base_cost = Some(52); + cfg.group_ops_bls12381_g2_msm_base_cost = Some(52); + cfg.group_ops_bls12381_g1_msm_base_cost_per_input = Some(52); + cfg.group_ops_bls12381_g2_msm_base_cost_per_input = Some(52); + cfg.group_ops_bls12381_msm_max_len = Some(32); + cfg.group_ops_bls12381_pairing_cost = Some(52); + } + 42 => {} + // Use this template when making changes: + // + // // modify an existing constant. + // move_binary_format_version: Some(7), + // + // // Add a new constant (which is set to None in prior versions). + // new_constant: Some(new_value), + // + // // Remove a constant (ensure that it is never accessed during this version). + // max_move_object_size: None, + _ => panic!("unsupported version {:?}", version), + } + } + cfg + } + + /// Override one or more settings in the config, for testing. + /// This must be called at the beginning of the test, before + /// get_for_(min|max)_version is called, since those functions cache + /// their return value. + pub fn apply_overrides_for_testing( + override_fn: impl Fn(ProtocolVersion, Self) -> Self + Send + 'static, + ) -> OverrideGuard { + CONFIG_OVERRIDE.with(|ovr| { + let mut cur = ovr.borrow_mut(); + assert!(cur.is_none(), "config override already present"); + *cur = Some(Box::new(override_fn)); + OverrideGuard + }) + } +} + +// Setters for tests +impl ProtocolConfig { + pub fn set_package_upgrades_for_testing(&mut self, val: bool) { + self.feature_flags.package_upgrades = val + } + pub fn set_advance_to_highest_supported_protocol_version_for_testing(&mut self, val: bool) { + self.feature_flags + .advance_to_highest_supported_protocol_version = val + } + pub fn set_commit_root_state_digest_supported(&mut self, val: bool) { + self.feature_flags.commit_root_state_digest = val + } + pub fn set_zklogin_auth_for_testing(&mut self, val: bool) { + self.feature_flags.zklogin_auth = val + } + pub fn set_enable_jwk_consensus_updates_for_testing(&mut self, val: bool) { + self.feature_flags.enable_jwk_consensus_updates = val + } + pub fn set_random_beacon_for_testing(&mut self, val: bool) { + self.feature_flags.random_beacon = val + } + pub fn set_upgraded_multisig_for_testing(&mut self, val: bool) { + self.feature_flags.upgraded_multisig_supported = val + } + pub fn set_accept_zklogin_in_multisig_for_testing(&mut self, val: bool) { + self.feature_flags.accept_zklogin_in_multisig = val + } + #[cfg(msim)] + pub fn set_simplified_unwrap_then_delete(&mut self, val: bool) { + self.feature_flags.simplified_unwrap_then_delete = val; + if val == false { + // Given that we will never enable effect V2 before turning on + // simplified_unwrap_then_delete, we also need to disable effect V2 here. + self.set_enable_effects_v2(false); + } + } + pub fn set_shared_object_deletion(&mut self, val: bool) { + self.feature_flags.shared_object_deletion = val; + } + + pub fn set_narwhal_new_leader_election_schedule(&mut self, val: bool) { + self.feature_flags.narwhal_new_leader_election_schedule = val; + } + + pub fn set_consensus_bad_nodes_stake_threshold(&mut self, val: u64) { + self.consensus_bad_nodes_stake_threshold = Some(val); + } + pub fn set_receive_object_for_testing(&mut self, val: bool) { + self.feature_flags.receive_objects = val + } + pub fn set_narwhal_certificate_v2(&mut self, val: bool) { + self.feature_flags.narwhal_certificate_v2 = val + } + pub fn set_verify_legacy_zklogin_address(&mut self, val: bool) { + self.feature_flags.verify_legacy_zklogin_address = val + } + pub fn set_enable_effects_v2(&mut self, val: bool) { + self.feature_flags.enable_effects_v2 = val; + } + pub fn set_consensus_max_transaction_size_bytes(&mut self, val: u64) { + self.consensus_max_transaction_size_bytes = Some(val); + } + pub fn set_consensus_max_transactions_in_block_bytes(&mut self, val: u64) { + self.consensus_max_transactions_in_block_bytes = Some(val); + } +} + +type OverrideFn = dyn Fn(ProtocolVersion, ProtocolConfig) -> ProtocolConfig + Send; + +thread_local! { + static CONFIG_OVERRIDE: RefCell>> = RefCell::new(None); +} + +#[must_use] +pub struct OverrideGuard; + +impl Drop for OverrideGuard { + fn drop(&mut self) { + info!("restoring override fn"); + CONFIG_OVERRIDE.with(|ovr| { + *ovr.borrow_mut() = None; + }); + } +} + +/// Defines which limit got crossed. +/// The value which crossed the limit and value of the limit crossed are +/// embedded +#[derive(PartialEq, Eq)] +pub enum LimitThresholdCrossed { + None, + Soft(u128, u128), + Hard(u128, u128), +} + +/// Convenience function for comparing limit ranges +/// V::MAX must be at >= U::MAX and T::MAX +pub fn check_limit_in_range, U: Into, V: PartialOrd + Into>( + x: T, + soft_limit: U, + hard_limit: V, +) -> LimitThresholdCrossed { + let x: V = x.into(); + let soft_limit: V = soft_limit.into(); + + debug_assert!(soft_limit <= hard_limit); + + // It is important to preserve this comparison order because if soft_limit == + // hard_limit we want LimitThresholdCrossed::Hard + if x >= hard_limit { + LimitThresholdCrossed::Hard(x.into(), hard_limit.into()) + } else if x < soft_limit { + LimitThresholdCrossed::None + } else { + LimitThresholdCrossed::Soft(x.into(), soft_limit.into()) + } +} + +#[macro_export] +macro_rules! check_limit { + ($x:expr, $hard:expr) => { + check_limit!($x, $hard, $hard) + }; + ($x:expr, $soft:expr, $hard:expr) => { + check_limit_in_range($x as u64, $soft, $hard) + }; +} + +/// Used to check which limits were crossed if the TX is metered (not system tx) +/// Args are: is_metered, value_to_check, metered_limit, unmetered_limit +/// metered_limit is always less than or equal to unmetered_hard_limit +#[macro_export] +macro_rules! check_limit_by_meter { + ($is_metered:expr, $x:expr, $metered_limit:expr, $unmetered_hard_limit:expr, $metric:expr) => {{ + // If this is metered, we use the metered_limit limit as the upper bound + let (h, metered_str) = if $is_metered { + ($metered_limit, "metered") + } else { + // Unmetered gets more headroom + ($unmetered_hard_limit, "unmetered") + }; + use iota_protocol_config::check_limit_in_range; + let result = check_limit_in_range($x as u64, $metered_limit, h); + match result { + LimitThresholdCrossed::None => {} + LimitThresholdCrossed::Soft(_, _) => { + $metric.with_label_values(&[metered_str, "soft"]).inc(); + } + LimitThresholdCrossed::Hard(_, _) => { + $metric.with_label_values(&[metered_str, "hard"]).inc(); + } + }; + result + }}; +} + +#[cfg(all(test, not(msim)))] +mod test { + use insta::assert_yaml_snapshot; + + use super::*; + + #[test] + fn snapshot_tests() { + println!("\n============================================================================"); + println!("! !"); + println!("! IMPORTANT: never update snapshots from this test. only add new versions! !"); + println!("! !"); + println!("============================================================================\n"); + for chain_id in &[Chain::Unknown, Chain::Mainnet, Chain::Testnet] { + // make Chain::Unknown snapshots compatible with pre-chain-id snapshots so that + // we don't break the release-time compatibility tests. Once Chain + // Id configs have been released everywhere, we can remove this and + // only test Mainnet and Testnet + let chain_str = match chain_id { + Chain::Unknown => "".to_string(), + _ => format!("{:?}_", chain_id), + }; + for i in MIN_PROTOCOL_VERSION..=MAX_PROTOCOL_VERSION { + let cur = ProtocolVersion::new(i); + assert_yaml_snapshot!( + format!("{}version_{}", chain_str, cur.as_u64()), + ProtocolConfig::get_for_version(cur, *chain_id) + ); + } + } + } + + #[test] + fn test_getters() { + let prot: ProtocolConfig = + ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Unknown); + assert_eq!( + prot.max_arguments(), + prot.max_arguments_as_option().unwrap() + ); + } + + #[test] + fn test_setters() { + let mut prot: ProtocolConfig = + ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Unknown); + prot.set_max_arguments_for_testing(123); + assert_eq!(prot.max_arguments(), 123); + + prot.set_max_arguments_from_str_for_testing("321".to_string()); + assert_eq!(prot.max_arguments(), 321); + + prot.disable_max_arguments_for_testing(); + assert_eq!(prot.max_arguments_as_option(), None); + + prot.set_attr_for_testing("max_arguments".to_string(), "456".to_string()); + assert_eq!(prot.max_arguments(), 456); + } + + #[test] + fn lookup_by_string_test() { + let prot: ProtocolConfig = + ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Unknown); + // Does not exist + assert!(prot.lookup_attr("some random string".to_string()).is_none()); + + assert!( + prot.lookup_attr("max_arguments".to_string()) + == Some(ProtocolConfigValue::u32(prot.max_arguments())), + ); + + // We didnt have this in version 1 + assert!( + prot.lookup_attr("max_move_identifier_len".to_string()) + .is_none() + ); + + // But we did in version 9 + let prot: ProtocolConfig = + ProtocolConfig::get_for_version(ProtocolVersion::new(9), Chain::Unknown); + assert!( + prot.lookup_attr("max_move_identifier_len".to_string()) + == Some(ProtocolConfigValue::u64(prot.max_move_identifier_len())) + ); + + let prot: ProtocolConfig = + ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Unknown); + // We didnt have this in version 1 + assert!( + prot.attr_map() + .get("max_move_identifier_len") + .unwrap() + .is_none() + ); + // We had this in version 1 + assert!( + prot.attr_map().get("max_arguments").unwrap() + == &Some(ProtocolConfigValue::u32(prot.max_arguments())) + ); + + // Check feature flags + let prot: ProtocolConfig = + ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Unknown); + // Does not exist + assert!( + prot.feature_flags + .lookup_attr("some random string".to_owned()) + .is_none() + ); + assert!( + prot.feature_flags + .attr_map() + .get("some random string") + .is_none() + ); + + // Was false in v1 + assert!( + prot.feature_flags + .lookup_attr("package_upgrades".to_owned()) + == Some(false) + ); + assert!( + prot.feature_flags + .attr_map() + .get("package_upgrades") + .unwrap() + == &false + ); + let prot: ProtocolConfig = + ProtocolConfig::get_for_version(ProtocolVersion::new(4), Chain::Unknown); + // Was true from v3 and up + assert!( + prot.feature_flags + .lookup_attr("package_upgrades".to_owned()) + == Some(true) + ); + assert!( + prot.feature_flags + .attr_map() + .get("package_upgrades") + .unwrap() + == &true + ); + } + + #[test] + fn limit_range_fn_test() { + let low = 100u32; + let high = 10000u64; + + assert!(check_limit!(1u8, low, high) == LimitThresholdCrossed::None); + assert!(matches!( + check_limit!(255u16, low, high), + LimitThresholdCrossed::Soft(255u128, 100) + )); + // This wont compile because lossy + // assert!(check_limit!(100000000u128, low, high) == + // LimitThresholdCrossed::None); This wont compile because lossy + // assert!(check_limit!(100000000usize, low, high) == + // LimitThresholdCrossed::None); + + assert!(matches!( + check_limit!(2550000u64, low, high), + LimitThresholdCrossed::Hard(2550000, 10000) + )); + + assert!(matches!( + check_limit!(2550000u64, high, high), + LimitThresholdCrossed::Hard(2550000, 10000) + )); + + assert!(matches!( + check_limit!(1u8, high), + LimitThresholdCrossed::None + )); + + assert!(check_limit!(255u16, high) == LimitThresholdCrossed::None); + + assert!(matches!( + check_limit!(2550000u64, high), + LimitThresholdCrossed::Hard(2550000, 10000) + )); + } +} diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_1.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_1.snap new file mode 100644 index 00000000000..d9ef0bee941 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_1.snap @@ -0,0 +1,161 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 1 +feature_flags: {} +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 10000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 110000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 1 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 5000 +storage_gas_price: 1 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_10.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_10.snap new file mode 100644 index 00000000000..e9a4a37fbbb --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_10.snap @@ -0,0 +1,179 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 10 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_11.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_11.snap new file mode 100644 index 00000000000..3132d737af7 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_11.snap @@ -0,0 +1,180 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 11 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_12.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_12.snap new file mode 100644 index 00000000000..9bd808003ee --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_12.snap @@ -0,0 +1,181 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 12 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_13.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_13.snap new file mode 100644 index 00000000000..e68ab0d28eb --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_13.snap @@ -0,0 +1,181 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 13 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_14.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_14.snap new file mode 100644 index 00000000000..bae0a8a2d38 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_14.snap @@ -0,0 +1,182 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 14 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_15.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_15.snap new file mode 100644 index 00000000000..02857e4d282 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_15.snap @@ -0,0 +1,183 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 15 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_16.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_16.snap new file mode 100644 index 00000000000..40034255474 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_16.snap @@ -0,0 +1,184 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 16 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_17.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_17.snap new file mode 100644 index 00000000000..d467e0c48d9 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_17.snap @@ -0,0 +1,185 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 17 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_18.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_18.snap new file mode 100644 index 00000000000..ce9899d3361 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_18.snap @@ -0,0 +1,187 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 18 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_19.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_19.snap new file mode 100644 index 00000000000..30e07e1a33b --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_19.snap @@ -0,0 +1,188 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 19 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_2.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_2.snap new file mode 100644 index 00000000000..d8c2b93b03e --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_2.snap @@ -0,0 +1,162 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 2 +feature_flags: + advance_epoch_start_time_in_safe_mode: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 10000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 110000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 1 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 5000 +storage_gas_price: 1 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_20.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_20.snap new file mode 100644 index 00000000000..c35a6baf754 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_20.snap @@ -0,0 +1,189 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 20 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_21.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_21.snap new file mode 100644 index 00000000000..20c65939d28 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_21.snap @@ -0,0 +1,190 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +assertion_line: 1578 +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 21 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_22.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_22.snap new file mode 100644 index 00000000000..15d5bc0808e --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_22.snap @@ -0,0 +1,190 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 22 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + loaded_child_object_format: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_23.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_23.snap new file mode 100644 index 00000000000..4605b655353 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_23.snap @@ -0,0 +1,193 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 23 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_24.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_24.snap new file mode 100644 index 00000000000..5092f4ae3b5 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_24.snap @@ -0,0 +1,196 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 24 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_25.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_25.snap new file mode 100644 index 00000000000..57e26f4e9ae --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_25.snap @@ -0,0 +1,204 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 25 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_26.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_26.snap new file mode 100644 index 00000000000..3214cd55a99 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_26.snap @@ -0,0 +1,204 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 26 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 7 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_27.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_27.snap new file mode 100644 index 00000000000..fe4b75a92f5 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_27.snap @@ -0,0 +1,204 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 27 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_28.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_28.snap new file mode 100644 index 00000000000..74c057bde09 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_28.snap @@ -0,0 +1,206 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 28 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_29.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_29.snap new file mode 100644 index 00000000000..b39a2235b4e --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_29.snap @@ -0,0 +1,207 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 29 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + verify_legacy_zklogin_address: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_3.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_3.snap new file mode 100644 index 00000000000..8f493bad38a --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_3.snap @@ -0,0 +1,166 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 3 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 2 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 5000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_30.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_30.snap new file mode 100644 index 00000000000..67706808097 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_30.snap @@ -0,0 +1,205 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 30 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_31.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_31.snap new file mode 100644 index 00000000000..08752335978 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_31.snap @@ -0,0 +1,205 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 31 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_32.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_32.snap new file mode 100644 index 00000000000..32132c1b624 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_32.snap @@ -0,0 +1,206 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 32 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_33.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_33.snap new file mode 100644 index 00000000000..81ec418767b --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_33.snap @@ -0,0 +1,211 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 33 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + hardened_otw_check: true + allow_receiving_object_id: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_34.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_34.snap new file mode 100644 index 00000000000..e5c8d55ce82 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_34.snap @@ -0,0 +1,211 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 34 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + hardened_otw_check: true + allow_receiving_object_id: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_35.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_35.snap new file mode 100644 index 00000000000..d2f9d225008 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_35.snap @@ -0,0 +1,212 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 35 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_36.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_36.snap new file mode 100644 index 00000000000..895ba300dc9 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_36.snap @@ -0,0 +1,215 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 36 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_37.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_37.snap new file mode 100644 index 00000000000..8fcfde0ad8d --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_37.snap @@ -0,0 +1,216 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 37 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_38.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_38.snap new file mode 100644 index 00000000000..2cf50496055 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_38.snap @@ -0,0 +1,231 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 38 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_39.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_39.snap new file mode 100644 index 00000000000..2ff24bec702 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_39.snap @@ -0,0 +1,231 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 39 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_4.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_4.snap new file mode 100644 index 00000000000..06ce7086ca2 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_4.snap @@ -0,0 +1,166 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 4 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 3 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_40.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_40.snap new file mode 100644 index 00000000000..3a78eb29ccd --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_40.snap @@ -0,0 +1,231 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 40 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_41.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_41.snap new file mode 100644 index 00000000000..1f5cf04881f --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_41.snap @@ -0,0 +1,262 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 41 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true + enable_group_ops_native_functions: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +group_ops_bls12381_decode_scalar_cost: 52 +group_ops_bls12381_decode_g1_cost: 52 +group_ops_bls12381_decode_g2_cost: 52 +group_ops_bls12381_decode_gt_cost: 52 +group_ops_bls12381_scalar_add_cost: 52 +group_ops_bls12381_g1_add_cost: 52 +group_ops_bls12381_g2_add_cost: 52 +group_ops_bls12381_gt_add_cost: 52 +group_ops_bls12381_scalar_sub_cost: 52 +group_ops_bls12381_g1_sub_cost: 52 +group_ops_bls12381_g2_sub_cost: 52 +group_ops_bls12381_gt_sub_cost: 52 +group_ops_bls12381_scalar_mul_cost: 52 +group_ops_bls12381_g1_mul_cost: 52 +group_ops_bls12381_g2_mul_cost: 52 +group_ops_bls12381_gt_mul_cost: 52 +group_ops_bls12381_scalar_div_cost: 52 +group_ops_bls12381_g1_div_cost: 52 +group_ops_bls12381_g2_div_cost: 52 +group_ops_bls12381_gt_div_cost: 52 +group_ops_bls12381_g1_hash_to_base_cost: 52 +group_ops_bls12381_g2_hash_to_base_cost: 52 +group_ops_bls12381_g1_hash_to_cost_per_byte: 2 +group_ops_bls12381_g2_hash_to_cost_per_byte: 2 +group_ops_bls12381_g1_msm_base_cost: 52 +group_ops_bls12381_g2_msm_base_cost: 52 +group_ops_bls12381_g1_msm_base_cost_per_input: 52 +group_ops_bls12381_g2_msm_base_cost_per_input: 52 +group_ops_bls12381_msm_max_len: 32 +group_ops_bls12381_pairing_cost: 52 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_42.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_42.snap new file mode 100644 index 00000000000..587575b9962 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_42.snap @@ -0,0 +1,262 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 42 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true + enable_group_ops_native_functions: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +group_ops_bls12381_decode_scalar_cost: 52 +group_ops_bls12381_decode_g1_cost: 52 +group_ops_bls12381_decode_g2_cost: 52 +group_ops_bls12381_decode_gt_cost: 52 +group_ops_bls12381_scalar_add_cost: 52 +group_ops_bls12381_g1_add_cost: 52 +group_ops_bls12381_g2_add_cost: 52 +group_ops_bls12381_gt_add_cost: 52 +group_ops_bls12381_scalar_sub_cost: 52 +group_ops_bls12381_g1_sub_cost: 52 +group_ops_bls12381_g2_sub_cost: 52 +group_ops_bls12381_gt_sub_cost: 52 +group_ops_bls12381_scalar_mul_cost: 52 +group_ops_bls12381_g1_mul_cost: 52 +group_ops_bls12381_g2_mul_cost: 52 +group_ops_bls12381_gt_mul_cost: 52 +group_ops_bls12381_scalar_div_cost: 52 +group_ops_bls12381_g1_div_cost: 52 +group_ops_bls12381_g2_div_cost: 52 +group_ops_bls12381_gt_div_cost: 52 +group_ops_bls12381_g1_hash_to_base_cost: 52 +group_ops_bls12381_g2_hash_to_base_cost: 52 +group_ops_bls12381_g1_hash_to_cost_per_byte: 2 +group_ops_bls12381_g2_hash_to_cost_per_byte: 2 +group_ops_bls12381_g1_msm_base_cost: 52 +group_ops_bls12381_g2_msm_base_cost: 52 +group_ops_bls12381_g1_msm_base_cost_per_input: 52 +group_ops_bls12381_g2_msm_base_cost_per_input: 52 +group_ops_bls12381_msm_max_len: 32 +group_ops_bls12381_pairing_cost: 52 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_5.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_5.snap new file mode 100644 index 00000000000..993c1f64639 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_5.snap @@ -0,0 +1,170 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 5 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 4 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_6.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_6.snap new file mode 100644 index 00000000000..fe538776cb1 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_6.snap @@ -0,0 +1,171 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 6 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_7.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_7.snap new file mode 100644 index 00000000000..3f730ffed18 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_7.snap @@ -0,0 +1,175 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 7 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + ban_entry_init: true + package_digest_hash_module: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_8.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_8.snap new file mode 100644 index 00000000000..c6886e7126b --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_8.snap @@ -0,0 +1,176 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 8 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_9.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_9.snap new file mode 100644 index 00000000000..db51202aa3d --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Mainnet_version_9.snap @@ -0,0 +1,179 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 9 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_1.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_1.snap new file mode 100644 index 00000000000..d9ef0bee941 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_1.snap @@ -0,0 +1,161 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 1 +feature_flags: {} +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 10000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 110000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 1 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 5000 +storage_gas_price: 1 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_10.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_10.snap new file mode 100644 index 00000000000..e9a4a37fbbb --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_10.snap @@ -0,0 +1,179 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 10 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_11.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_11.snap new file mode 100644 index 00000000000..3132d737af7 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_11.snap @@ -0,0 +1,180 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 11 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_12.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_12.snap new file mode 100644 index 00000000000..9627c09b9cf --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_12.snap @@ -0,0 +1,182 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 12 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_13.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_13.snap new file mode 100644 index 00000000000..b827c35bc3d --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_13.snap @@ -0,0 +1,182 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 13 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_14.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_14.snap new file mode 100644 index 00000000000..db238ff3829 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_14.snap @@ -0,0 +1,183 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 14 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_15.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_15.snap new file mode 100644 index 00000000000..0b9e7a35898 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_15.snap @@ -0,0 +1,184 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 15 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_16.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_16.snap new file mode 100644 index 00000000000..5366ff1934c --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_16.snap @@ -0,0 +1,185 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 16 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_17.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_17.snap new file mode 100644 index 00000000000..df0ff71dd74 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_17.snap @@ -0,0 +1,186 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 17 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_18.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_18.snap new file mode 100644 index 00000000000..3c193fdf4f5 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_18.snap @@ -0,0 +1,188 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 18 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_19.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_19.snap new file mode 100644 index 00000000000..89d94462e6b --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_19.snap @@ -0,0 +1,189 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 19 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_2.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_2.snap new file mode 100644 index 00000000000..d8c2b93b03e --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_2.snap @@ -0,0 +1,162 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 2 +feature_flags: + advance_epoch_start_time_in_safe_mode: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 10000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 110000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 1 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 5000 +storage_gas_price: 1 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_20.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_20.snap new file mode 100644 index 00000000000..35f486948c7 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_20.snap @@ -0,0 +1,191 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 20 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_21.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_21.snap new file mode 100644 index 00000000000..6606865affa --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_21.snap @@ -0,0 +1,195 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 21 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_22.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_22.snap new file mode 100644 index 00000000000..55466d369e6 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_22.snap @@ -0,0 +1,196 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 22 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_23.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_23.snap new file mode 100644 index 00000000000..ac33e96fde7 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_23.snap @@ -0,0 +1,197 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 23 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_24.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_24.snap new file mode 100644 index 00000000000..a9f5345fdee --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_24.snap @@ -0,0 +1,203 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 24 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_25.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_25.snap new file mode 100644 index 00000000000..57e26f4e9ae --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_25.snap @@ -0,0 +1,204 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 25 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_26.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_26.snap new file mode 100644 index 00000000000..3214cd55a99 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_26.snap @@ -0,0 +1,204 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 26 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 7 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_27.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_27.snap new file mode 100644 index 00000000000..fe4b75a92f5 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_27.snap @@ -0,0 +1,204 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 27 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_28.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_28.snap new file mode 100644 index 00000000000..74c057bde09 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_28.snap @@ -0,0 +1,206 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 28 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_29.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_29.snap new file mode 100644 index 00000000000..b39a2235b4e --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_29.snap @@ -0,0 +1,207 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 29 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + verify_legacy_zklogin_address: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_3.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_3.snap new file mode 100644 index 00000000000..8f493bad38a --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_3.snap @@ -0,0 +1,166 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 3 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 2 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 5000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_30.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_30.snap new file mode 100644 index 00000000000..bc2b8ec38ce --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_30.snap @@ -0,0 +1,207 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 30 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_31.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_31.snap new file mode 100644 index 00000000000..f427700ea55 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_31.snap @@ -0,0 +1,207 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 31 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_32.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_32.snap new file mode 100644 index 00000000000..d957bf84533 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_32.snap @@ -0,0 +1,210 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 32 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_33.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_33.snap new file mode 100644 index 00000000000..1ecc9477dda --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_33.snap @@ -0,0 +1,213 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 33 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + hardened_otw_check: true + allow_receiving_object_id: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_34.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_34.snap new file mode 100644 index 00000000000..94bba6ed58a --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_34.snap @@ -0,0 +1,213 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 34 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + hardened_otw_check: true + allow_receiving_object_id: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_35.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_35.snap new file mode 100644 index 00000000000..c1ff811bf65 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_35.snap @@ -0,0 +1,214 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 35 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_36.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_36.snap new file mode 100644 index 00000000000..60995b70c8c --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_36.snap @@ -0,0 +1,216 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 36 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_37.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_37.snap new file mode 100644 index 00000000000..1ee441db805 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_37.snap @@ -0,0 +1,218 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 37 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_38.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_38.snap new file mode 100644 index 00000000000..249e6972b89 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_38.snap @@ -0,0 +1,233 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 38 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_39.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_39.snap new file mode 100644 index 00000000000..9cfc6ea5aa7 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_39.snap @@ -0,0 +1,233 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 39 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_4.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_4.snap new file mode 100644 index 00000000000..06ce7086ca2 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_4.snap @@ -0,0 +1,166 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 4 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 3 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_40.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_40.snap new file mode 100644 index 00000000000..6bf7efeb614 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_40.snap @@ -0,0 +1,233 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 40 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_41.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_41.snap new file mode 100644 index 00000000000..11c644a72a4 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_41.snap @@ -0,0 +1,264 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 41 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true + enable_group_ops_native_functions: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +group_ops_bls12381_decode_scalar_cost: 52 +group_ops_bls12381_decode_g1_cost: 52 +group_ops_bls12381_decode_g2_cost: 52 +group_ops_bls12381_decode_gt_cost: 52 +group_ops_bls12381_scalar_add_cost: 52 +group_ops_bls12381_g1_add_cost: 52 +group_ops_bls12381_g2_add_cost: 52 +group_ops_bls12381_gt_add_cost: 52 +group_ops_bls12381_scalar_sub_cost: 52 +group_ops_bls12381_g1_sub_cost: 52 +group_ops_bls12381_g2_sub_cost: 52 +group_ops_bls12381_gt_sub_cost: 52 +group_ops_bls12381_scalar_mul_cost: 52 +group_ops_bls12381_g1_mul_cost: 52 +group_ops_bls12381_g2_mul_cost: 52 +group_ops_bls12381_gt_mul_cost: 52 +group_ops_bls12381_scalar_div_cost: 52 +group_ops_bls12381_g1_div_cost: 52 +group_ops_bls12381_g2_div_cost: 52 +group_ops_bls12381_gt_div_cost: 52 +group_ops_bls12381_g1_hash_to_base_cost: 52 +group_ops_bls12381_g2_hash_to_base_cost: 52 +group_ops_bls12381_g1_hash_to_cost_per_byte: 2 +group_ops_bls12381_g2_hash_to_cost_per_byte: 2 +group_ops_bls12381_g1_msm_base_cost: 52 +group_ops_bls12381_g2_msm_base_cost: 52 +group_ops_bls12381_g1_msm_base_cost_per_input: 52 +group_ops_bls12381_g2_msm_base_cost_per_input: 52 +group_ops_bls12381_msm_max_len: 32 +group_ops_bls12381_pairing_cost: 52 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_42.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_42.snap new file mode 100644 index 00000000000..0efb8049e32 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_42.snap @@ -0,0 +1,264 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 42 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true + enable_group_ops_native_functions: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +group_ops_bls12381_decode_scalar_cost: 52 +group_ops_bls12381_decode_g1_cost: 52 +group_ops_bls12381_decode_g2_cost: 52 +group_ops_bls12381_decode_gt_cost: 52 +group_ops_bls12381_scalar_add_cost: 52 +group_ops_bls12381_g1_add_cost: 52 +group_ops_bls12381_g2_add_cost: 52 +group_ops_bls12381_gt_add_cost: 52 +group_ops_bls12381_scalar_sub_cost: 52 +group_ops_bls12381_g1_sub_cost: 52 +group_ops_bls12381_g2_sub_cost: 52 +group_ops_bls12381_gt_sub_cost: 52 +group_ops_bls12381_scalar_mul_cost: 52 +group_ops_bls12381_g1_mul_cost: 52 +group_ops_bls12381_g2_mul_cost: 52 +group_ops_bls12381_gt_mul_cost: 52 +group_ops_bls12381_scalar_div_cost: 52 +group_ops_bls12381_g1_div_cost: 52 +group_ops_bls12381_g2_div_cost: 52 +group_ops_bls12381_gt_div_cost: 52 +group_ops_bls12381_g1_hash_to_base_cost: 52 +group_ops_bls12381_g2_hash_to_base_cost: 52 +group_ops_bls12381_g1_hash_to_cost_per_byte: 2 +group_ops_bls12381_g2_hash_to_cost_per_byte: 2 +group_ops_bls12381_g1_msm_base_cost: 52 +group_ops_bls12381_g2_msm_base_cost: 52 +group_ops_bls12381_g1_msm_base_cost_per_input: 52 +group_ops_bls12381_g2_msm_base_cost_per_input: 52 +group_ops_bls12381_msm_max_len: 32 +group_ops_bls12381_pairing_cost: 52 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_5.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_5.snap new file mode 100644 index 00000000000..993c1f64639 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_5.snap @@ -0,0 +1,170 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 5 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 4 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_6.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_6.snap new file mode 100644 index 00000000000..fe538776cb1 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_6.snap @@ -0,0 +1,171 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 6 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_7.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_7.snap new file mode 100644 index 00000000000..3f730ffed18 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_7.snap @@ -0,0 +1,175 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 7 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + ban_entry_init: true + package_digest_hash_module: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_8.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_8.snap new file mode 100644 index 00000000000..c6886e7126b --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_8.snap @@ -0,0 +1,176 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 8 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_9.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_9.snap new file mode 100644 index 00000000000..db51202aa3d --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__Testnet_version_9.snap @@ -0,0 +1,179 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 9 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_1.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_1.snap new file mode 100644 index 00000000000..d9ef0bee941 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_1.snap @@ -0,0 +1,161 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 1 +feature_flags: {} +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 10000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 110000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 1 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 5000 +storage_gas_price: 1 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_10.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_10.snap new file mode 100644 index 00000000000..e9a4a37fbbb --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_10.snap @@ -0,0 +1,179 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 10 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_11.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_11.snap new file mode 100644 index 00000000000..3132d737af7 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_11.snap @@ -0,0 +1,180 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 11 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_12.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_12.snap new file mode 100644 index 00000000000..410af67cb05 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_12.snap @@ -0,0 +1,183 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 12 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_13.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_13.snap new file mode 100644 index 00000000000..af3e968e4da --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_13.snap @@ -0,0 +1,183 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 13 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_14.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_14.snap new file mode 100644 index 00000000000..7b2bdee6243 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_14.snap @@ -0,0 +1,184 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 14 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_15.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_15.snap new file mode 100644 index 00000000000..5f75bdaaefb --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_15.snap @@ -0,0 +1,185 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 15 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_16.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_16.snap new file mode 100644 index 00000000000..89afd4f2a4d --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_16.snap @@ -0,0 +1,186 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 16 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_17.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_17.snap new file mode 100644 index 00000000000..0fb985a80e2 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_17.snap @@ -0,0 +1,187 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 17 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_18.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_18.snap new file mode 100644 index 00000000000..f273c44f0ff --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_18.snap @@ -0,0 +1,189 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 18 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_19.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_19.snap new file mode 100644 index 00000000000..59db4c234fb --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_19.snap @@ -0,0 +1,190 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 19 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_2.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_2.snap new file mode 100644 index 00000000000..d8c2b93b03e --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_2.snap @@ -0,0 +1,162 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 2 +feature_flags: + advance_epoch_start_time_in_safe_mode: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 10000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 110000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 1 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 5000 +storage_gas_price: 1 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_20.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_20.snap new file mode 100644 index 00000000000..26481420752 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_20.snap @@ -0,0 +1,192 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 20 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_21.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_21.snap new file mode 100644 index 00000000000..6222bf54d62 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_21.snap @@ -0,0 +1,196 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 21 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_22.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_22.snap new file mode 100644 index 00000000000..71ceec8820f --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_22.snap @@ -0,0 +1,197 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 22 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_23.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_23.snap new file mode 100644 index 00000000000..d4d5cbe4d93 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_23.snap @@ -0,0 +1,198 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 23 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_24.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_24.snap new file mode 100644 index 00000000000..cd7589dc464 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_24.snap @@ -0,0 +1,204 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 24 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_25.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_25.snap new file mode 100644 index 00000000000..57e26f4e9ae --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_25.snap @@ -0,0 +1,204 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 25 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 6 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_26.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_26.snap new file mode 100644 index 00000000000..60cadf6957b --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_26.snap @@ -0,0 +1,206 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 26 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 7 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_27.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_27.snap new file mode 100644 index 00000000000..cc856beb07c --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_27.snap @@ -0,0 +1,206 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 27 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_28.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_28.snap new file mode 100644 index 00000000000..7f03c97ce5b --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_28.snap @@ -0,0 +1,209 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 28 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_29.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_29.snap new file mode 100644 index 00000000000..c553d92c1a8 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_29.snap @@ -0,0 +1,210 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 29 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + zklogin_supported_providers: + - Facebook + - Google + - Twitch + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + verify_legacy_zklogin_address: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_3.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_3.snap new file mode 100644 index 00000000000..8f493bad38a --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_3.snap @@ -0,0 +1,166 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 3 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 2 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 5000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_30.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_30.snap new file mode 100644 index 00000000000..79aac948306 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_30.snap @@ -0,0 +1,209 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 30 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 1 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_31.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_31.snap new file mode 100644 index 00000000000..3a9949ca005 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_31.snap @@ -0,0 +1,210 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 31 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_32.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_32.snap new file mode 100644 index 00000000000..96962235d6c --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_32.snap @@ -0,0 +1,215 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 32 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + random_beacon: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +random_beacon_reduction_lower_bound: 1600 +random_beacon_dkg_timeout_round: 200 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_33.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_33.snap new file mode 100644 index 00000000000..38de8656083 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_33.snap @@ -0,0 +1,217 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 33 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + random_beacon: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +random_beacon_reduction_lower_bound: 1600 +random_beacon_dkg_timeout_round: 200 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_34.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_34.snap new file mode 100644 index 00000000000..8d7bc555d65 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_34.snap @@ -0,0 +1,217 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 34 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + random_beacon: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +random_beacon_reduction_lower_bound: 1600 +random_beacon_dkg_timeout_round: 200 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_35.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_35.snap new file mode 100644 index 00000000000..c29afe72c27 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_35.snap @@ -0,0 +1,221 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 35 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + random_beacon: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_poseidon: true + enable_coin_deny_list: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +poseidon_bn254_cost_base: 260 +poseidon_bn254_cost_per_block: 10 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +random_beacon_reduction_lower_bound: 1600 +random_beacon_dkg_timeout_round: 200 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_36.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_36.snap new file mode 100644 index 00000000000..1faceb6e345 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_36.snap @@ -0,0 +1,255 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 36 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + random_beacon: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_poseidon: true + enable_coin_deny_list: true + enable_group_ops_native_functions: true + enable_group_ops_native_function_msm: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +poseidon_bn254_cost_base: 260 +poseidon_bn254_cost_per_block: 10 +group_ops_bls12381_decode_scalar_cost: 52 +group_ops_bls12381_decode_g1_cost: 52 +group_ops_bls12381_decode_g2_cost: 52 +group_ops_bls12381_decode_gt_cost: 52 +group_ops_bls12381_scalar_add_cost: 52 +group_ops_bls12381_g1_add_cost: 52 +group_ops_bls12381_g2_add_cost: 52 +group_ops_bls12381_gt_add_cost: 52 +group_ops_bls12381_scalar_sub_cost: 52 +group_ops_bls12381_g1_sub_cost: 52 +group_ops_bls12381_g2_sub_cost: 52 +group_ops_bls12381_gt_sub_cost: 52 +group_ops_bls12381_scalar_mul_cost: 52 +group_ops_bls12381_g1_mul_cost: 52 +group_ops_bls12381_g2_mul_cost: 52 +group_ops_bls12381_gt_mul_cost: 52 +group_ops_bls12381_scalar_div_cost: 52 +group_ops_bls12381_g1_div_cost: 52 +group_ops_bls12381_g2_div_cost: 52 +group_ops_bls12381_gt_div_cost: 52 +group_ops_bls12381_g1_hash_to_base_cost: 52 +group_ops_bls12381_g2_hash_to_base_cost: 52 +group_ops_bls12381_g1_hash_to_cost_per_byte: 2 +group_ops_bls12381_g2_hash_to_cost_per_byte: 2 +group_ops_bls12381_g1_msm_base_cost: 52 +group_ops_bls12381_g2_msm_base_cost: 52 +group_ops_bls12381_g1_msm_base_cost_per_input: 52 +group_ops_bls12381_g2_msm_base_cost_per_input: 52 +group_ops_bls12381_msm_max_len: 32 +group_ops_bls12381_pairing_cost: 52 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +random_beacon_reduction_lower_bound: 1600 +random_beacon_dkg_timeout_round: 200 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_37.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_37.snap new file mode 100644 index 00000000000..d5dfe2f403c --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_37.snap @@ -0,0 +1,256 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 37 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + random_beacon: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_poseidon: true + enable_coin_deny_list: true + enable_group_ops_native_functions: true + enable_group_ops_native_function_msm: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +poseidon_bn254_cost_base: 260 +poseidon_bn254_cost_per_block: 10 +group_ops_bls12381_decode_scalar_cost: 52 +group_ops_bls12381_decode_g1_cost: 52 +group_ops_bls12381_decode_g2_cost: 52 +group_ops_bls12381_decode_gt_cost: 52 +group_ops_bls12381_scalar_add_cost: 52 +group_ops_bls12381_g1_add_cost: 52 +group_ops_bls12381_g2_add_cost: 52 +group_ops_bls12381_gt_add_cost: 52 +group_ops_bls12381_scalar_sub_cost: 52 +group_ops_bls12381_g1_sub_cost: 52 +group_ops_bls12381_g2_sub_cost: 52 +group_ops_bls12381_gt_sub_cost: 52 +group_ops_bls12381_scalar_mul_cost: 52 +group_ops_bls12381_g1_mul_cost: 52 +group_ops_bls12381_g2_mul_cost: 52 +group_ops_bls12381_gt_mul_cost: 52 +group_ops_bls12381_scalar_div_cost: 52 +group_ops_bls12381_g1_div_cost: 52 +group_ops_bls12381_g2_div_cost: 52 +group_ops_bls12381_gt_div_cost: 52 +group_ops_bls12381_g1_hash_to_base_cost: 52 +group_ops_bls12381_g2_hash_to_base_cost: 52 +group_ops_bls12381_g1_hash_to_cost_per_byte: 2 +group_ops_bls12381_g2_hash_to_cost_per_byte: 2 +group_ops_bls12381_g1_msm_base_cost: 52 +group_ops_bls12381_g2_msm_base_cost: 52 +group_ops_bls12381_g1_msm_base_cost_per_input: 52 +group_ops_bls12381_g2_msm_base_cost_per_input: 52 +group_ops_bls12381_msm_max_len: 32 +group_ops_bls12381_pairing_cost: 52 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 2 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +random_beacon_reduction_lower_bound: 1600 +random_beacon_dkg_timeout_round: 200 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_38.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_38.snap new file mode 100644 index 00000000000..d9a54b5d2f5 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_38.snap @@ -0,0 +1,271 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 38 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + random_beacon: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_poseidon: true + enable_coin_deny_list: true + enable_group_ops_native_functions: true + enable_group_ops_native_function_msm: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +poseidon_bn254_cost_base: 260 +poseidon_bn254_cost_per_block: 10 +group_ops_bls12381_decode_scalar_cost: 52 +group_ops_bls12381_decode_g1_cost: 52 +group_ops_bls12381_decode_g2_cost: 52 +group_ops_bls12381_decode_gt_cost: 52 +group_ops_bls12381_scalar_add_cost: 52 +group_ops_bls12381_g1_add_cost: 52 +group_ops_bls12381_g2_add_cost: 52 +group_ops_bls12381_gt_add_cost: 52 +group_ops_bls12381_scalar_sub_cost: 52 +group_ops_bls12381_g1_sub_cost: 52 +group_ops_bls12381_g2_sub_cost: 52 +group_ops_bls12381_gt_sub_cost: 52 +group_ops_bls12381_scalar_mul_cost: 52 +group_ops_bls12381_g1_mul_cost: 52 +group_ops_bls12381_g2_mul_cost: 52 +group_ops_bls12381_gt_mul_cost: 52 +group_ops_bls12381_scalar_div_cost: 52 +group_ops_bls12381_g1_div_cost: 52 +group_ops_bls12381_g2_div_cost: 52 +group_ops_bls12381_gt_div_cost: 52 +group_ops_bls12381_g1_hash_to_base_cost: 52 +group_ops_bls12381_g2_hash_to_base_cost: 52 +group_ops_bls12381_g1_hash_to_cost_per_byte: 2 +group_ops_bls12381_g2_hash_to_cost_per_byte: 2 +group_ops_bls12381_g1_msm_base_cost: 52 +group_ops_bls12381_g2_msm_base_cost: 52 +group_ops_bls12381_g1_msm_base_cost_per_input: 52 +group_ops_bls12381_g2_msm_base_cost_per_input: 52 +group_ops_bls12381_msm_max_len: 32 +group_ops_bls12381_pairing_cost: 52 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +random_beacon_reduction_lower_bound: 1600 +random_beacon_dkg_timeout_round: 200 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_39.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_39.snap new file mode 100644 index 00000000000..3890997c316 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_39.snap @@ -0,0 +1,271 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 39 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + random_beacon: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_poseidon: true + enable_coin_deny_list: true + enable_group_ops_native_functions: true + enable_group_ops_native_function_msm: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +poseidon_bn254_cost_base: 260 +poseidon_bn254_cost_per_block: 10 +group_ops_bls12381_decode_scalar_cost: 52 +group_ops_bls12381_decode_g1_cost: 52 +group_ops_bls12381_decode_g2_cost: 52 +group_ops_bls12381_decode_gt_cost: 52 +group_ops_bls12381_scalar_add_cost: 52 +group_ops_bls12381_g1_add_cost: 52 +group_ops_bls12381_g2_add_cost: 52 +group_ops_bls12381_gt_add_cost: 52 +group_ops_bls12381_scalar_sub_cost: 52 +group_ops_bls12381_g1_sub_cost: 52 +group_ops_bls12381_g2_sub_cost: 52 +group_ops_bls12381_gt_sub_cost: 52 +group_ops_bls12381_scalar_mul_cost: 52 +group_ops_bls12381_g1_mul_cost: 52 +group_ops_bls12381_g2_mul_cost: 52 +group_ops_bls12381_gt_mul_cost: 52 +group_ops_bls12381_scalar_div_cost: 52 +group_ops_bls12381_g1_div_cost: 52 +group_ops_bls12381_g2_div_cost: 52 +group_ops_bls12381_gt_div_cost: 52 +group_ops_bls12381_g1_hash_to_base_cost: 52 +group_ops_bls12381_g2_hash_to_base_cost: 52 +group_ops_bls12381_g1_hash_to_cost_per_byte: 2 +group_ops_bls12381_g2_hash_to_cost_per_byte: 2 +group_ops_bls12381_g1_msm_base_cost: 52 +group_ops_bls12381_g2_msm_base_cost: 52 +group_ops_bls12381_g1_msm_base_cost_per_input: 52 +group_ops_bls12381_g2_msm_base_cost_per_input: 52 +group_ops_bls12381_msm_max_len: 32 +group_ops_bls12381_pairing_cost: 52 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +random_beacon_reduction_lower_bound: 1600 +random_beacon_dkg_timeout_round: 200 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_4.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_4.snap new file mode 100644 index 00000000000..06ce7086ca2 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_4.snap @@ -0,0 +1,166 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 4 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 3 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_40.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_40.snap new file mode 100644 index 00000000000..86c449c653d --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_40.snap @@ -0,0 +1,271 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 40 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + random_beacon: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_poseidon: true + enable_coin_deny_list: true + enable_group_ops_native_functions: true + enable_group_ops_native_function_msm: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +poseidon_bn254_cost_base: 260 +poseidon_bn254_cost_per_block: 10 +group_ops_bls12381_decode_scalar_cost: 52 +group_ops_bls12381_decode_g1_cost: 52 +group_ops_bls12381_decode_g2_cost: 52 +group_ops_bls12381_decode_gt_cost: 52 +group_ops_bls12381_scalar_add_cost: 52 +group_ops_bls12381_g1_add_cost: 52 +group_ops_bls12381_g2_add_cost: 52 +group_ops_bls12381_gt_add_cost: 52 +group_ops_bls12381_scalar_sub_cost: 52 +group_ops_bls12381_g1_sub_cost: 52 +group_ops_bls12381_g2_sub_cost: 52 +group_ops_bls12381_gt_sub_cost: 52 +group_ops_bls12381_scalar_mul_cost: 52 +group_ops_bls12381_g1_mul_cost: 52 +group_ops_bls12381_g2_mul_cost: 52 +group_ops_bls12381_gt_mul_cost: 52 +group_ops_bls12381_scalar_div_cost: 52 +group_ops_bls12381_g1_div_cost: 52 +group_ops_bls12381_g2_div_cost: 52 +group_ops_bls12381_gt_div_cost: 52 +group_ops_bls12381_g1_hash_to_base_cost: 52 +group_ops_bls12381_g2_hash_to_base_cost: 52 +group_ops_bls12381_g1_hash_to_cost_per_byte: 2 +group_ops_bls12381_g2_hash_to_cost_per_byte: 2 +group_ops_bls12381_g1_msm_base_cost: 52 +group_ops_bls12381_g2_msm_base_cost: 52 +group_ops_bls12381_g1_msm_base_cost_per_input: 52 +group_ops_bls12381_g2_msm_base_cost_per_input: 52 +group_ops_bls12381_msm_max_len: 32 +group_ops_bls12381_pairing_cost: 52 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +random_beacon_reduction_lower_bound: 1600 +random_beacon_dkg_timeout_round: 200 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_41.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_41.snap new file mode 100644 index 00000000000..e5afdcaf7c5 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_41.snap @@ -0,0 +1,271 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 41 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + random_beacon: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_poseidon: true + enable_coin_deny_list: true + enable_group_ops_native_functions: true + enable_group_ops_native_function_msm: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +poseidon_bn254_cost_base: 260 +poseidon_bn254_cost_per_block: 10 +group_ops_bls12381_decode_scalar_cost: 52 +group_ops_bls12381_decode_g1_cost: 52 +group_ops_bls12381_decode_g2_cost: 52 +group_ops_bls12381_decode_gt_cost: 52 +group_ops_bls12381_scalar_add_cost: 52 +group_ops_bls12381_g1_add_cost: 52 +group_ops_bls12381_g2_add_cost: 52 +group_ops_bls12381_gt_add_cost: 52 +group_ops_bls12381_scalar_sub_cost: 52 +group_ops_bls12381_g1_sub_cost: 52 +group_ops_bls12381_g2_sub_cost: 52 +group_ops_bls12381_gt_sub_cost: 52 +group_ops_bls12381_scalar_mul_cost: 52 +group_ops_bls12381_g1_mul_cost: 52 +group_ops_bls12381_g2_mul_cost: 52 +group_ops_bls12381_gt_mul_cost: 52 +group_ops_bls12381_scalar_div_cost: 52 +group_ops_bls12381_g1_div_cost: 52 +group_ops_bls12381_g2_div_cost: 52 +group_ops_bls12381_gt_div_cost: 52 +group_ops_bls12381_g1_hash_to_base_cost: 52 +group_ops_bls12381_g2_hash_to_base_cost: 52 +group_ops_bls12381_g1_hash_to_cost_per_byte: 2 +group_ops_bls12381_g2_hash_to_cost_per_byte: 2 +group_ops_bls12381_g1_msm_base_cost: 52 +group_ops_bls12381_g2_msm_base_cost: 52 +group_ops_bls12381_g1_msm_base_cost_per_input: 52 +group_ops_bls12381_g2_msm_base_cost_per_input: 52 +group_ops_bls12381_msm_max_len: 32 +group_ops_bls12381_pairing_cost: 52 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +random_beacon_reduction_lower_bound: 1600 +random_beacon_dkg_timeout_round: 200 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_42.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_42.snap new file mode 100644 index 00000000000..0bd78e479c4 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_42.snap @@ -0,0 +1,271 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 42 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + random_beacon: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_poseidon: true + enable_coin_deny_list: true + enable_group_ops_native_functions: true + enable_group_ops_native_function_msm: true + reject_mutable_random_on_entry_functions: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +poseidon_bn254_cost_base: 260 +poseidon_bn254_cost_per_block: 10 +group_ops_bls12381_decode_scalar_cost: 52 +group_ops_bls12381_decode_g1_cost: 52 +group_ops_bls12381_decode_g2_cost: 52 +group_ops_bls12381_decode_gt_cost: 52 +group_ops_bls12381_scalar_add_cost: 52 +group_ops_bls12381_g1_add_cost: 52 +group_ops_bls12381_g2_add_cost: 52 +group_ops_bls12381_gt_add_cost: 52 +group_ops_bls12381_scalar_sub_cost: 52 +group_ops_bls12381_g1_sub_cost: 52 +group_ops_bls12381_g2_sub_cost: 52 +group_ops_bls12381_gt_sub_cost: 52 +group_ops_bls12381_scalar_mul_cost: 52 +group_ops_bls12381_g1_mul_cost: 52 +group_ops_bls12381_g2_mul_cost: 52 +group_ops_bls12381_gt_mul_cost: 52 +group_ops_bls12381_scalar_div_cost: 52 +group_ops_bls12381_g1_div_cost: 52 +group_ops_bls12381_g2_div_cost: 52 +group_ops_bls12381_gt_div_cost: 52 +group_ops_bls12381_g1_hash_to_base_cost: 52 +group_ops_bls12381_g2_hash_to_base_cost: 52 +group_ops_bls12381_g1_hash_to_cost_per_byte: 2 +group_ops_bls12381_g2_hash_to_cost_per_byte: 2 +group_ops_bls12381_g1_msm_base_cost: 52 +group_ops_bls12381_g2_msm_base_cost: 52 +group_ops_bls12381_g1_msm_base_cost_per_input: 52 +group_ops_bls12381_g2_msm_base_cost_per_input: 52 +group_ops_bls12381_msm_max_len: 32 +group_ops_bls12381_pairing_cost: 52 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +random_beacon_reduction_lower_bound: 1600 +random_beacon_dkg_timeout_round: 200 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 6291456 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_5.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_5.snap new file mode 100644 index 00000000000..993c1f64639 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_5.snap @@ -0,0 +1,170 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 5 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 4 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 0 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_6.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_6.snap new file mode 100644 index 00000000000..fe538776cb1 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_6.snap @@ -0,0 +1,171 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 6 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_7.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_7.snap new file mode 100644 index 00000000000..3f730ffed18 --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_7.snap @@ -0,0 +1,175 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 7 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + ban_entry_init: true + package_digest_hash_module: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_8.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_8.snap new file mode 100644 index 00000000000..c6886e7126b --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_8.snap @@ -0,0 +1,176 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 8 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_9.snap b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_9.snap new file mode 100644 index 00000000000..db51202aa3d --- /dev/null +++ b/crates/iota-protocol-config/src/snapshots/iota_protocol_config__test__version_9.snap @@ -0,0 +1,179 @@ +--- +source: crates/iota-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 9 +feature_flags: + package_upgrades: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 128 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 6 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 256 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 6000000 +max_meter_ticks_per_module: 6000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 2000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +gas_model_version: 5 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +scoring_decision_mad_divisor: 2.3 +scoring_decision_cutoff_value: 2.5 + diff --git a/crates/iota-proxy/Cargo.toml b/crates/iota-proxy/Cargo.toml new file mode 100644 index 00000000000..3de8c5b23a0 --- /dev/null +++ b/crates/iota-proxy/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "iota-proxy" +version = "0.0.2" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +axum.workspace = true +axum-server.workspace = true +anyhow.workspace = true +bytes.workspace = true +clap.workspace = true +protobuf.workspace = true +tokio = { workspace = true, features = ["full"] } +tracing.workspace = true +const-str.workspace = true +tower-http.workspace = true +tower.workspace = true +serde.workspace = true +serde_with.workspace = true +serde_json.workspace = true +serde_yaml.workspace = true +git-version.workspace = true +itertools.workspace = true +rand.workspace = true +reqwest.workspace = true +hyper.workspace = true +iota-tls.workspace = true +iota-types.workspace = true +mysten-metrics.workspace = true +multiaddr.workspace = true +prometheus.workspace = true +snap.workspace = true +rustls.workspace = true +rustls-pemfile.workspace = true +prost.workspace = true +once_cell.workspace = true +http-body.workspace = true +hex.workspace = true +ipnetwork.workspace = true + + +telemetry-subscribers.workspace = true +fastcrypto.workspace = true + +[dev-dependencies] +mime.workspace = true +serde_json.workspace = true +tower.workspace = true +axum-server.workspace = true +iota-types = { workspace = true, features = ["test-utils"] } + +[build-dependencies] +prost-build.workspace = true diff --git a/crates/iota-proxy/build.rs b/crates/iota-proxy/build.rs new file mode 100644 index 00000000000..7041c848102 --- /dev/null +++ b/crates/iota-proxy/build.rs @@ -0,0 +1,18 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use std::io::Result; +fn main() -> Result<()> { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-env-changed=BUILD_REMOTE_WRITE"); + + // add this env var to build. you'll need protoc installed locally and a copy of + // the proto files + if option_env!("BUILD_REMOTE_WRITE").is_some() { + prost_build::compile_protos( + &["protobufs/remote.proto", "protobufs/types.proto"], + &["protobufs/"], + )?; + } + Ok(()) +} diff --git a/crates/iota-proxy/src/admin.rs b/crates/iota-proxy/src/admin.rs new file mode 100644 index 00000000000..54f93b5edab --- /dev/null +++ b/crates/iota-proxy/src/admin.rs @@ -0,0 +1,272 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use std::{ + fs, + io::BufReader, + net::{IpAddr, SocketAddr}, + sync::Arc, + time::Duration, +}; + +use anyhow::{Error, Result}; +use axum::{extract::DefaultBodyLimit, middleware, routing::post, Extension, Router}; +use fastcrypto::{ + ed25519::{Ed25519KeyPair, Ed25519PublicKey}, + traits::{KeyPair, ToFromBytes}, +}; +use iota_tls::{rustls::ServerConfig, AllowAll, CertVerifier, SelfSignedCertificate, TlsAcceptor}; +use tokio::signal; +use tower::ServiceBuilder; +use tower_http::{ + trace::{DefaultOnResponse, TraceLayer}, + LatencyUnit, +}; +use tracing::{error, info, Level}; + +use crate::{ + config::{DynamicPeerValidationConfig, RemoteWriteConfig, StaticPeerValidationConfig}, + handlers::publish_metrics, + histogram_relay::HistogramRelay, + ip::{is_private, to_multiaddr}, + middleware::{expect_content_length, expect_mysten_proxy_header, expect_valid_public_key}, + peers::{IotaNodeProvider, IotaPeer}, + var, +}; + +/// Configure our graceful shutdown scenarios +pub async fn shutdown_signal(h: axum_server::Handle) { + let ctrl_c = async { + signal::ctrl_c() + .await + .expect("failed to install Ctrl+C handler"); + }; + + #[cfg(unix)] + let terminate = async { + signal::unix::signal(signal::unix::SignalKind::terminate()) + .expect("failed to install signal handler") + .recv() + .await; + }; + + #[cfg(not(unix))] + let terminate = std::future::pending::<()>(); + + tokio::select! { + _ = ctrl_c => {}, + _ = terminate => {}, + } + + let grace = 30; + info!( + "signal received, starting graceful shutdown, grace period {} seconds, if needed", + &grace + ); + h.graceful_shutdown(Some(Duration::from_secs(grace))) +} + +/// Reqwest client holds the global client for remote_push api calls +/// it also holds the username and password. The client has an underlying +/// connection pool. See reqwest documentation for details +#[derive(Clone)] +pub struct ReqwestClient { + pub client: reqwest::Client, + pub settings: RemoteWriteConfig, +} + +pub fn make_reqwest_client(settings: RemoteWriteConfig, user_agent: &str) -> ReqwestClient { + ReqwestClient { + client: reqwest::Client::builder() + .user_agent(user_agent) + .pool_max_idle_per_host(settings.pool_max_idle_per_host) + .timeout(Duration::from_secs(var!("MIMIR_CLIENT_TIMEOUT", 30))) + .build() + .expect("cannot create reqwest client"), + settings, + } +} + +// Labels are adhoc labels we will inject per our config +#[derive(Clone)] +pub struct Labels { + pub network: String, + pub inventory_hostname: String, +} + +/// App will configure our routes. This fn is also used to instrument our tests +pub fn app( + labels: Labels, + client: ReqwestClient, + relay: HistogramRelay, + allower: Option, +) -> Router { + // build our application with a route and our sender mpsc + let mut router = Router::new() + .route("/publish/metrics", post(publish_metrics)) + .route_layer(DefaultBodyLimit::max(var!( + "MAX_BODY_SIZE", + 1024 * 1024 * 5 + ))) + .route_layer(middleware::from_fn(expect_mysten_proxy_header)) + .route_layer(middleware::from_fn(expect_content_length)); + if let Some(allower) = allower { + router = router + .route_layer(middleware::from_fn(expect_valid_public_key)) + .layer(Extension(Arc::new(allower))); + } + router + .layer(Extension(relay)) + .layer(Extension(labels)) + .layer(Extension(client)) + .layer( + ServiceBuilder::new().layer( + TraceLayer::new_for_http().on_response( + DefaultOnResponse::new() + .level(Level::INFO) + .latency_unit(LatencyUnit::Seconds), + ), + ), + ) +} + +/// Server creates our http/https server +pub async fn server( + listener: std::net::TcpListener, + app: Router, + acceptor: Option, +) -> std::io::Result<()> { + // setup our graceful shutdown + let handle = axum_server::Handle::new(); + // Spawn a task to gracefully shutdown server. + tokio::spawn(shutdown_signal(handle.clone())); + + if let Some(verify_peers) = acceptor { + axum_server::Server::from_tcp(listener) + .acceptor(verify_peers) + .handle(handle) + .serve(app.into_make_service_with_connect_info::()) + .await + } else { + axum_server::Server::from_tcp(listener) + .handle(handle) + .serve(app.into_make_service_with_connect_info::()) + .await + } +} + +/// CertKeyPair wraps a self signed certificate and the corresponding public key +pub struct CertKeyPair(pub SelfSignedCertificate, pub Ed25519PublicKey); + +/// Generate server certs for use with peer verification +pub fn generate_self_cert(hostname: String) -> CertKeyPair { + let mut rng = rand::thread_rng(); + let keypair = Ed25519KeyPair::generate(&mut rng); + CertKeyPair( + SelfSignedCertificate::new(keypair.copy().private(), &hostname), + keypair.public().to_owned(), + ) +} + +/// Load a certificate for use by the listening service +fn load_certs(filename: &str) -> Vec { + let certfile = fs::File::open(filename) + .unwrap_or_else(|e| panic!("cannot open certificate file: {}; {}", filename, e)); + let mut reader = BufReader::new(certfile); + rustls_pemfile::certs(&mut reader) + .unwrap() + .iter() + .map(|v| rustls::Certificate(v.clone())) + .collect() +} + +/// Load a private key +fn load_private_key(filename: &str) -> rustls::PrivateKey { + let keyfile = fs::File::open(filename) + .unwrap_or_else(|e| panic!("cannot open private key file {}; {}", filename, e)); + let mut reader = BufReader::new(keyfile); + + loop { + match rustls_pemfile::read_one(&mut reader).expect("cannot parse private key .pem file") { + Some(rustls_pemfile::Item::RSAKey(key)) => return rustls::PrivateKey(key), + Some(rustls_pemfile::Item::PKCS8Key(key)) => return rustls::PrivateKey(key), + Some(rustls_pemfile::Item::ECKey(key)) => return rustls::PrivateKey(key), + None => break, + _ => {} + } + } + + panic!( + "no keys found in {:?} (encrypted keys not supported)", + filename + ); +} + +/// load the static keys we'll use to allow external non-validator nodes to push +/// metrics +fn load_static_peers( + static_peers: Option, +) -> Result, Error> { + let Some(static_peers) = static_peers else { + return Ok(vec![]); + }; + let static_keys = static_peers.pub_keys.into_iter().filter_map(|spk|{ + let p2p_address: IpAddr = spk.p2p_address.parse().unwrap(); + if is_private(p2p_address) { + error!("{} appears to be a private address. We only allow 169.254.0.0/16 addresses to be private; ignoring this entry", p2p_address); + dbg!("skipping {}", spk); + return None; + } + Some(spk) + }).map(|spk|{ + let peer_id = hex::decode(spk.peer_id).unwrap(); + let public_key = Ed25519PublicKey::from_bytes(peer_id.as_ref()).unwrap(); + let p2p_address: IpAddr = spk.p2p_address.parse().unwrap(); + let s = IotaPeer{ + name:spk.name.clone(), + p2p_address: to_multiaddr(p2p_address), + public_key, + }; + info!("loaded static peer: {} public key: {} p2p address: {}", &s.name, &s.public_key, &s.p2p_address); + s + }).collect(); + Ok(static_keys) +} + +/// Default allow mode for server, we don't verify clients, everything is +/// accepted +pub fn create_server_cert_default_allow( + hostname: String, +) -> Result { + let CertKeyPair(server_certificate, _) = generate_self_cert(hostname); + + CertVerifier::new(AllowAll).rustls_server_config( + vec![server_certificate.rustls_certificate()], + server_certificate.rustls_private_key(), + ) +} + +/// Verify clients against iota blockchain, clients that are not found in +/// iota_getValidators will be rejected +pub fn create_server_cert_enforce_peer( + dynamic_peers: DynamicPeerValidationConfig, + static_peers: Option, +) -> Result<(ServerConfig, Option), iota_tls::rustls::Error> { + let (Some(certificate_path), Some(private_key_path)) = + (dynamic_peers.certificate_file, dynamic_peers.private_key) + else { + return Err(iota_tls::rustls::Error::General( + "missing certs to initialize server".into(), + )); + }; + let static_peers = load_static_peers(static_peers).map_err(|e| { + iota_tls::rustls::Error::General(format!("unable to load static pub keys: {}", e)) + })?; + let allower = IotaNodeProvider::new(dynamic_peers.url, dynamic_peers.interval, static_peers); + allower.poll_peer_list(); + let c = CertVerifier::new(allower.clone()).rustls_server_config( + load_certs(&certificate_path), + load_private_key(&private_key_path), + )?; + Ok((c, Some(allower))) +} diff --git a/crates/iota-proxy/src/config.rs b/crates/iota-proxy/src/config.rs new file mode 100644 index 00000000000..8a05ac8a646 --- /dev/null +++ b/crates/iota-proxy/src/config.rs @@ -0,0 +1,126 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use core::time::Duration; +use std::net::SocketAddr; + +use anyhow::{Context, Result}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde_with::{serde_as, DurationSeconds}; +use tracing::debug; + +#[serde_as] +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct ProxyConfig { + pub network: String, + pub listen_address: SocketAddr, + pub remote_write: RemoteWriteConfig, + pub dynamic_peers: DynamicPeerValidationConfig, + pub static_peers: Option, + pub metrics_address: String, + pub histogram_address: String, +} + +#[serde_as] +#[derive(Clone, Debug, Deserialize, Serialize, Default)] +#[serde(rename_all = "kebab-case")] +pub struct RemoteWriteConfig { + // TODO upgrade to https + /// the remote_write url to post data to + #[serde(default = "remote_write_url")] + pub url: String, + /// username is used for posting data to the remote_write api + pub username: String, + pub password: String, + + /// Sets the maximum idle connection per host allowed in the pool. + /// + #[serde(default = "pool_max_idle_per_host_default")] + pub pool_max_idle_per_host: usize, +} + +/// DynamicPeerValidationConfig controls what iota-node binaries that are +/// functioning as a validator that we'll speak with. Peer in this case is peers +/// within the consensus committee, for each epoch. This membership is +/// determined dynamically for each epoch via json-rpc calls to a full node. +#[serde_as] +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct DynamicPeerValidationConfig { + /// url is the json-rpc url we use to obtain valid peers on the blockchain + pub url: String, + #[serde_as(as = "DurationSeconds")] + pub interval: Duration, + /// if certificate_file and private_key are not provided, we'll create a + /// self-signed cert using this hostname + #[serde(default = "hostname_default")] + pub hostname: Option, + + /// incoming client connections to this proxy will be presented with this + /// pub key please use an absolute path + pub certificate_file: Option, + /// private key for tls + /// please use an absolute path + pub private_key: Option, +} + +/// StaticPeerValidationConfig, unlike the DynamicPeerValidationConfig, is not +/// determined dynamically from rpc calls. It instead searches a local +/// directory for pub keys that we will add to an allow list. +#[serde_as] +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct StaticPeerValidationConfig { + pub pub_keys: Vec, +} + +/// StaticPubKey holds a human friendly name, ip and the key file for the pub +/// key if you don't have a valid public routable ip, use an ip from +/// 169.254.0.0/16. +#[serde_as] +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct StaticPubKey { + /// friendly name we will see in metrics + pub name: String, + /// friendly ip address we may see in metrics + pub p2p_address: String, + /// the peer_id from a node config file (Ed25519 PublicKey) + pub peer_id: String, +} + +/// the default idle worker per host (reqwest to remote write url call) +fn pool_max_idle_per_host_default() -> usize { + 8 +} + +/// the default hostname we will use if not provided +fn hostname_default() -> Option { + Some("localhost".to_string()) +} + +/// the default remote write url +fn remote_write_url() -> String { + "http://metrics-gw.testnet.iota.io/api/v1/push".to_string() +} + +/// load our config file from a path +pub fn load, T: DeserializeOwned + Serialize>(path: P) -> Result { + let path = path.as_ref(); + debug!("Reading config from {:?}", path); + Ok(serde_yaml::from_reader( + std::fs::File::open(path).context(format!("cannot open {:?}", path))?, + )?) +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn config_load() { + const TEMPLATE: &str = include_str!("./data/config.yaml"); + + let _template: ProxyConfig = serde_yaml::from_str(TEMPLATE).unwrap(); + } +} diff --git a/crates/sui-proxy/src/consumer.rs b/crates/iota-proxy/src/consumer.rs similarity index 99% rename from crates/sui-proxy/src/consumer.rs rename to crates/iota-proxy/src/consumer.rs index 53e231171ff..a8952c45943 100644 --- a/crates/sui-proxy/src/consumer.rs +++ b/crates/iota-proxy/src/consumer.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::io::Read; @@ -71,7 +72,7 @@ static CONSUMER_OPERATION_DURATION: Lazy = Lazy::new(|| { #[derive(Debug)] pub struct NodeMetric { pub peer_addr: Multiaddr, // the sockaddr source address from the incoming request - pub public_key: Ed25519PublicKey, // the public key from the sui blockchain + pub public_key: Ed25519PublicKey, // the public key from the iota blockchain pub data: Vec, // decoded protobuf of prometheus data } @@ -87,7 +88,7 @@ impl ProtobufDecoder { Self { buf } } /// parse a delimited buffer of protobufs. this is used to consume data sent - /// from a sui-node + /// from a iota-node pub fn parse(&mut self) -> Result> { let timer = CONSUMER_OPERATION_DURATION .with_label_values(&["decode_len_delim_protobuf"]) diff --git a/crates/sui-proxy/src/data/config.yaml b/crates/iota-proxy/src/data/config.yaml similarity index 100% rename from crates/sui-proxy/src/data/config.yaml rename to crates/iota-proxy/src/data/config.yaml diff --git a/crates/sui-proxy/src/handlers.rs b/crates/iota-proxy/src/handlers.rs similarity index 94% rename from crates/sui-proxy/src/handlers.rs rename to crates/iota-proxy/src/handlers.rs index 42809fd7dcf..07342068f8e 100644 --- a/crates/sui-proxy/src/handlers.rs +++ b/crates/iota-proxy/src/handlers.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::net::SocketAddr; @@ -15,7 +16,7 @@ use crate::{ consumer::{convert_to_remote_write, populate_labels, NodeMetric}, histogram_relay::HistogramRelay, middleware::LenDelimProtobuf, - peers::SuiPeer, + peers::IotaPeer, }; static HANDLER_HITS: Lazy = Lazy::new(|| { @@ -49,9 +50,9 @@ pub async fn publish_metrics( Extension(labels): Extension, Extension(client): Extension, ConnectInfo(addr): ConnectInfo, - Extension(SuiPeer { + Extension(IotaPeer { name, public_key, .. - }): Extension, + }): Extension, Extension(relay): Extension, LenDelimProtobuf(data): LenDelimProtobuf, ) -> (StatusCode, &'static str) { diff --git a/crates/sui-proxy/src/histogram_relay.rs b/crates/iota-proxy/src/histogram_relay.rs similarity index 99% rename from crates/sui-proxy/src/histogram_relay.rs rename to crates/iota-proxy/src/histogram_relay.rs index f88d3f122d7..45c29a28c90 100644 --- a/crates/sui-proxy/src/histogram_relay.rs +++ b/crates/iota-proxy/src/histogram_relay.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ collections::VecDeque, diff --git a/crates/sui-proxy/src/ip.rs b/crates/iota-proxy/src/ip.rs similarity index 98% rename from crates/sui-proxy/src/ip.rs rename to crates/iota-proxy/src/ip.rs index 2e5625551e7..abe54a146d3 100644 --- a/crates/sui-proxy/src/ip.rs +++ b/crates/iota-proxy/src/ip.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; diff --git a/crates/iota-proxy/src/lib.rs b/crates/iota-proxy/src/lib.rs new file mode 100644 index 00000000000..c71fe57e242 --- /dev/null +++ b/crates/iota-proxy/src/lib.rs @@ -0,0 +1,189 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +pub mod admin; +pub mod config; +pub mod consumer; +pub mod handlers; +pub mod histogram_relay; +mod ip; +pub mod metrics; +pub mod middleware; +pub mod peers; +pub mod prom_to_mimir; +pub mod remote_write; + +/// var extracts environment variables at runtime with a default fallback value +/// if a default is not provided, the value is simply an empty string if not +/// found This function will return the provided default if env::var cannot find +/// the key or if the key is somehow malformed. +#[macro_export] +macro_rules! var { + ($key:expr) => { + match std::env::var($key) { + Ok(val) => val, + Err(_) => "".into(), + } + }; + ($key:expr, $default:expr) => { + match std::env::var($key) { + Ok(val) => val.parse::<_>().unwrap(), + Err(_) => $default, + } + }; +} + +#[cfg(test)] +mod tests { + use std::{net::TcpListener, time::Duration}; + + use axum::{ + http::{header, StatusCode}, + routing::post, + Router, + }; + use iota_tls::{CertVerifier, TlsAcceptor}; + use multiaddr::Multiaddr; + use prometheus::{Encoder, PROTOBUF_FORMAT}; + use protobuf::RepeatedField; + + use super::*; + use crate::{ + admin::{CertKeyPair, Labels}, + config::RemoteWriteConfig, + histogram_relay::HistogramRelay, + peers::IotaNodeProvider, + prom_to_mimir::tests::*, + }; + + async fn run_dummy_remote_write(listener: TcpListener) { + /// i accept everything, send me the trash + async fn handler() -> StatusCode { + StatusCode::OK + } + + // build our application with a route + let app = Router::new().route("/v1/push", post(handler)); + + // run it + axum::Server::from_tcp(listener) + .unwrap() + .serve(app.into_make_service()) + .await + .unwrap(); + } + + /// axum_acceptor is a basic e2e test that creates a mock remote_write post + /// endpoint and has a simple iota-node client that posts data to the + /// proxy using the protobuf format. The server processes this data and + /// sends it to the mock remote_write which accepts everything. Future work + /// is to make this more robust and expand the scope of coverage, + /// probabaly moving this test elsewhere and renaming it. + #[tokio::test] + async fn axum_acceptor() { + // generate self-signed certificates + let CertKeyPair(client_priv_cert, client_pub_key) = + admin::generate_self_cert("iota".into()); + let CertKeyPair(server_priv_cert, _) = admin::generate_self_cert("localhost".into()); + + // create a fake rpc server + let dummy_remote_write_listener = std::net::TcpListener::bind("localhost:0").unwrap(); + let dummy_remote_write_address = dummy_remote_write_listener.local_addr().unwrap(); + let dummy_remote_write_url = format!( + "http://localhost:{}/v1/push", + dummy_remote_write_address.port() + ); + + let _dummy_remote_write = + tokio::spawn(async move { run_dummy_remote_write(dummy_remote_write_listener).await }); + + // init the tls config and allower + let mut allower = IotaNodeProvider::new("".into(), Duration::from_secs(30), vec![]); + let tls_config = CertVerifier::new(allower.clone()) + .rustls_server_config( + vec![server_priv_cert.rustls_certificate()], + server_priv_cert.rustls_private_key(), + ) + .unwrap(); + + let client = admin::make_reqwest_client( + RemoteWriteConfig { + url: dummy_remote_write_url.to_owned(), + username: "bar".into(), + password: "foo".into(), + ..Default::default() + }, + "dummy user agent", + ); + + let app = admin::app( + Labels { + network: "unittest-network".into(), + inventory_hostname: "ansible_inventory_name".into(), + }, + client, + HistogramRelay::new(), + Some(allower.clone()), + ); + + let listener = std::net::TcpListener::bind("localhost:0").unwrap(); + let server_address = listener.local_addr().unwrap(); + let server_url = format!( + "https://localhost:{}/publish/metrics", + server_address.port() + ); + + let acceptor = TlsAcceptor::new(tls_config); + let _server = tokio::spawn(async move { + admin::server(listener, app, Some(acceptor)).await.unwrap(); + }); + + // build a client + let client = reqwest::Client::builder() + .add_root_certificate(server_priv_cert.reqwest_certificate()) + .identity(client_priv_cert.reqwest_identity()) + .https_only(true) + .build() + .unwrap(); + + // Client request is rejected because it isn't in the allowlist + client.get(&server_url).send().await.unwrap_err(); + + // Insert the client's public key into the allowlist and verify the request is + // successful + allower.get_mut().write().unwrap().insert( + client_pub_key.to_owned(), + peers::IotaPeer { + name: "some-node".into(), + p2p_address: Multiaddr::empty(), + public_key: client_pub_key.to_owned(), + }, + ); + + let mf = create_metric_family( + "foo_metric", + "some help this is", + None, + RepeatedField::from_vec(vec![create_metric_counter( + RepeatedField::from_vec(create_labels(vec![("some", "label")])), + create_counter(2046.0), + )]), + ); + + let mut buf = vec![]; + let encoder = prometheus::ProtobufEncoder::new(); + encoder.encode(&[mf], &mut buf).unwrap(); + + let res = client + .post(&server_url) + .header(header::CONTENT_TYPE, PROTOBUF_FORMAT) + .body(buf) + .send() + .await + .expect("expected a successful post with a self-signed certificate"); + let status = res.status(); + let body = res.text().await.unwrap(); + assert_eq!("created", body); + assert_eq!(status, StatusCode::CREATED); + } +} diff --git a/crates/iota-proxy/src/main.rs b/crates/iota-proxy/src/main.rs new file mode 100644 index 00000000000..3d781789b97 --- /dev/null +++ b/crates/iota-proxy/src/main.rs @@ -0,0 +1,118 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use std::env; + +use anyhow::Result; +use clap::Parser; +use iota_proxy::{ + admin::{ + app, create_server_cert_default_allow, create_server_cert_enforce_peer, + make_reqwest_client, server, Labels, + }, + config::{load, ProxyConfig}, + histogram_relay, metrics, +}; +use iota_tls::TlsAcceptor; +use telemetry_subscribers::TelemetryConfig; +use tracing::info; + +// WARNING!!! +// +// Do not move or use similar logic to generate git revision information outside +// of a binary entry point (e.g. main.rs). Placing the below logic into a +// library can result in unessesary builds. +const GIT_REVISION: &str = { + if let Some(revision) = option_env!("GIT_REVISION") { + revision + } else { + git_version::git_version!( + args = ["--always", "--abbrev=12", "--dirty", "--exclude", "*"], + fallback = "DIRTY" + ) + } +}; + +// VERSION mimics what other iota binaries use for the same const +pub const VERSION: &str = const_str::concat!(env!("CARGO_PKG_VERSION"), "-", GIT_REVISION); + +/// user agent we use when posting to mimir +static APP_USER_AGENT: &str = const_str::concat!( + env!("CARGO_PKG_NAME"), + "/", + env!("CARGO_PKG_VERSION"), + "/", + VERSION +); + +#[derive(Parser, Debug)] +#[clap(rename_all = "kebab-case")] +#[clap(name = env!("CARGO_BIN_NAME"))] +#[clap(version = VERSION)] +struct Args { + #[clap( + long, + short, + default_value = "./iota-proxy.yaml", + help = "Specify the config file path to use" + )] + config: String, +} + +#[tokio::main] +async fn main() -> Result<()> { + let (_guard, _handle) = TelemetryConfig::new().init(); + + let args = Args::parse(); + + let config: ProxyConfig = load(args.config)?; + + info!( + "listen on {:?} send to {:?}", + config.listen_address, config.remote_write.url + ); + + let listener = std::net::TcpListener::bind(config.listen_address).unwrap(); + + let (tls_config, allower) = + // we'll only use the dynamic peers in some cases - it makes little sense to run with the statics + // since this first mode allows all. + if config.dynamic_peers.certificate_file.is_none() || config.dynamic_peers.private_key.is_none() { + ( + create_server_cert_default_allow(config.dynamic_peers.hostname.unwrap()) + .expect("unable to create self-signed server cert"), + None, + ) + } else { + create_server_cert_enforce_peer(config.dynamic_peers, config.static_peers) + .expect("unable to create tls server config") + }; + let histogram_listener = std::net::TcpListener::bind(config.histogram_address).unwrap(); + let metrics_listener = std::net::TcpListener::bind(config.metrics_address).unwrap(); + let acceptor = TlsAcceptor::new(tls_config); + let client = make_reqwest_client(config.remote_write, APP_USER_AGENT); + let histogram_relay = histogram_relay::start_prometheus_server(histogram_listener); + let registry_service = metrics::start_prometheus_server(metrics_listener); + let prometheus_registry = registry_service.default_registry(); + prometheus_registry + .register(mysten_metrics::uptime_metric( + "iota-proxy", + VERSION, + "unavailable", + )) + .unwrap(); + let app = app( + Labels { + network: config.network, + inventory_hostname: env::var("INVENTORY_HOSTNAME") + .expect("INVENTORY_HOSTNAME not found in environment"), + }, + client, + histogram_relay, + allower, + ); + + server(listener, app, Some(acceptor)).await.unwrap(); + + Ok(()) +} diff --git a/crates/iota-proxy/src/metrics.rs b/crates/iota-proxy/src/metrics.rs new file mode 100644 index 00000000000..0dfa004c3a6 --- /dev/null +++ b/crates/iota-proxy/src/metrics.rs @@ -0,0 +1,63 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use std::net::TcpListener; + +use axum::{extract::Extension, http::StatusCode, routing::get, Router}; +use mysten_metrics::RegistryService; +use prometheus::{Registry, TextEncoder}; +use tower::ServiceBuilder; +use tower_http::{ + trace::{DefaultOnResponse, TraceLayer}, + LatencyUnit, +}; +use tracing::Level; + +const METRICS_ROUTE: &str = "/metrics"; + +// Creates a new http server that has as a sole purpose to expose +// and endpoint that prometheus agent can use to poll for the metrics. +// A RegistryService is returned that can be used to get access in prometheus +// Registries. +pub fn start_prometheus_server(addr: TcpListener) -> RegistryService { + let registry = Registry::new(); + + let registry_service = RegistryService::new(registry); + + let app = Router::new() + .route(METRICS_ROUTE, get(metrics)) + .layer(Extension(registry_service.clone())) + .layer( + ServiceBuilder::new().layer( + TraceLayer::new_for_http().on_response( + DefaultOnResponse::new() + .level(Level::INFO) + .latency_unit(LatencyUnit::Seconds), + ), + ), + ); + + tokio::spawn(async move { + axum::Server::from_tcp(addr) + .unwrap() + .serve(app.into_make_service()) + .await + .unwrap(); + }); + + registry_service +} + +// DO NOT remove this handler, it is not compatible with the +// mysten_metrics::metric equivalent +async fn metrics(Extension(registry_service): Extension) -> (StatusCode, String) { + let mut metric_families = registry_service.gather_all(); + metric_families.extend(prometheus::gather()); + match TextEncoder.encode_to_string(&metric_families) { + Ok(metrics) => (StatusCode::OK, metrics), + Err(error) => ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("unable to encode metrics: {error}"), + ), + } +} diff --git a/crates/sui-proxy/src/middleware.rs b/crates/iota-proxy/src/middleware.rs similarity index 92% rename from crates/sui-proxy/src/middleware.rs rename to crates/iota-proxy/src/middleware.rs index 86d523f6a1a..f175b9e2e55 100644 --- a/crates/sui-proxy/src/middleware.rs +++ b/crates/iota-proxy/src/middleware.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; @@ -14,12 +15,12 @@ use axum::{ }; use bytes::Buf; use hyper::header::CONTENT_ENCODING; +use iota_tls::TlsConnectionInfo; use once_cell::sync::Lazy; use prometheus::{proto::MetricFamily, register_counter_vec, CounterVec}; -use sui_tls::TlsConnectionInfo; use tracing::error; -use crate::{consumer::ProtobufDecoder, peers::SuiNodeProvider}; +use crate::{consumer::ProtobufDecoder, peers::IotaNodeProvider}; static MIDDLEWARE_OPS: Lazy = Lazy::new(|| { register_counter_vec!( @@ -39,7 +40,7 @@ static MIDDLEWARE_HEADERS: Lazy = Lazy::new(|| { .unwrap() }); -/// we expect sui-node to send us an http header content-length encoding. +/// we expect iota-node to send us an http header content-length encoding. pub async fn expect_content_length( TypedHeader(content_length): TypedHeader, request: Request, @@ -49,7 +50,7 @@ pub async fn expect_content_length( Ok(next.run(request).await) } -/// we expect sui-node to send us an http header content-type encoding. +/// we expect iota-node to send us an http header content-type encoding. pub async fn expect_mysten_proxy_header( TypedHeader(content_type): TypedHeader, request: Request, @@ -67,10 +68,10 @@ pub async fn expect_mysten_proxy_header( } } -/// we expect that calling sui-nodes are known on the blockchain and we enforce +/// we expect that calling iota-nodes are known on the blockchain and we enforce /// their pub key tls creds here pub async fn expect_valid_public_key( - Extension(allower): Extension>, + Extension(allower): Extension>, Extension(tls_connect_info): Extension, mut request: Request, next: Next, diff --git a/crates/sui-proxy/src/peers.rs b/crates/iota-proxy/src/peers.rs similarity index 81% rename from crates/sui-proxy/src/peers.rs rename to crates/iota-proxy/src/peers.rs index 7b8bcf5f13b..a9adfc290e6 100644 --- a/crates/sui-proxy/src/peers.rs +++ b/crates/iota-proxy/src/peers.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ collections::HashMap, @@ -8,12 +9,12 @@ use std::{ use anyhow::{bail, Context, Result}; use fastcrypto::{ed25519::Ed25519PublicKey, traits::ToFromBytes}; +use iota_tls::Allower; +use iota_types::iota_system_state::iota_system_state_summary::IotaSystemStateSummary; use multiaddr::Multiaddr; use once_cell::sync::Lazy; use prometheus::{register_counter_vec, register_histogram_vec, CounterVec, HistogramVec}; use serde::Deserialize; -use sui_tls::Allower; -use sui_types::sui_system_state::sui_system_state_summary::SuiSystemStateSummary; use tracing::{debug, error, info}; static JSON_RPC_STATE: Lazy = Lazy::new(|| { @@ -37,43 +38,43 @@ static JSON_RPC_DURATION: Lazy = Lazy::new(|| { .unwrap() }); -/// SuiNods a mapping of public key to SuiPeer data -pub type SuiPeers = Arc>>; +/// IotaNods a mapping of public key to IotaPeer data +pub type IotaPeers = Arc>>; -/// A SuiPeer is the collated sui chain data we have about validators +/// A IotaPeer is the collated iota chain data we have about validators #[derive(Hash, PartialEq, Eq, Debug, Clone)] -pub struct SuiPeer { +pub struct IotaPeer { pub name: String, pub p2p_address: Multiaddr, pub public_key: Ed25519PublicKey, } -/// SuiNodeProvider queries the sui blockchain and keeps a record of known -/// validators based on the response from sui_getValidators. The node name, +/// IotaNodeProvider queries the iota blockchain and keeps a record of known +/// validators based on the response from iota_getValidators. The node name, /// public key and other info is extracted from the chain and stored in this /// data structure. We pass this struct to the tls verifier and it depends on /// the state contained within. Handlers also use this data in an Extractor /// extension to check incoming clients on the http api against known keys. #[derive(Debug, Clone)] -pub struct SuiNodeProvider { - nodes: SuiPeers, - static_nodes: SuiPeers, +pub struct IotaNodeProvider { + nodes: IotaPeers, + static_nodes: IotaPeers, rpc_url: String, rpc_poll_interval: Duration, } -impl Allower for SuiNodeProvider { +impl Allower for IotaNodeProvider { fn allowed(&self, key: &Ed25519PublicKey) -> bool { self.static_nodes.read().unwrap().contains_key(key) || self.nodes.read().unwrap().contains_key(key) } } -impl SuiNodeProvider { - pub fn new(rpc_url: String, rpc_poll_interval: Duration, static_peers: Vec) -> Self { +impl IotaNodeProvider { + pub fn new(rpc_url: String, rpc_poll_interval: Duration, static_peers: Vec) -> Self { // build our hashmap with the static pub keys. we only do this one time at // binary startup. - let static_nodes: HashMap = static_peers + let static_nodes: HashMap = static_peers .into_iter() .map(|v| (v.public_key.clone(), v)) .collect(); @@ -88,11 +89,11 @@ impl SuiNodeProvider { } /// get is used to retrieve peer info in our handlers - pub fn get(&self, key: &Ed25519PublicKey) -> Option { + pub fn get(&self, key: &Ed25519PublicKey) -> Option { debug!("look for {:?}", key); // check static nodes first if let Some(v) = self.static_nodes.read().unwrap().get(key) { - return Some(SuiPeer { + return Some(IotaPeer { name: v.name.to_owned(), p2p_address: v.p2p_address.to_owned(), public_key: v.public_key.to_owned(), @@ -100,7 +101,7 @@ impl SuiNodeProvider { } // check dynamic nodes if let Some(v) = self.nodes.read().unwrap().get(key) { - return Some(SuiPeer { + return Some(IotaPeer { name: v.name.to_owned(), p2p_address: v.p2p_address.to_owned(), public_key: v.public_key.to_owned(), @@ -109,18 +110,18 @@ impl SuiNodeProvider { None } /// Get a reference to the inner service - pub fn get_ref(&self) -> &SuiPeers { + pub fn get_ref(&self) -> &IotaPeers { &self.nodes } /// Get a mutable reference to the inner service - pub fn get_mut(&mut self) -> &mut SuiPeers { + pub fn get_mut(&mut self) -> &mut IotaPeers { &mut self.nodes } /// get_validators will retrieve known validators - async fn get_validators(url: String) -> Result { - let rpc_method = "suix_getLatestSuiSystemState"; + async fn get_validators(url: String) -> Result { + let rpc_method = "iotax_getLatestIotaSystemState"; let observe = || { let timer = JSON_RPC_DURATION .with_label_values(&[rpc_method]) @@ -159,7 +160,7 @@ impl SuiNodeProvider { #[derive(Debug, Deserialize)] struct ResponseBody { - result: SuiSystemStateSummary, + result: IotaSystemStateSummary, } let body: ResponseBody = match serde_json::from_slice(&raw) { @@ -220,11 +221,11 @@ impl SuiNodeProvider { } } -/// extract will get the network pubkey bytes from a SuiValidatorSummary type. +/// extract will get the network pubkey bytes from a IotaValidatorSummary type. /// This type comes from a full node rpc result. See get_validators for /// details. The key here, if extracted successfully, will ultimately be stored /// in the allow list and let us communicate with those actual peers via tls. -fn extract(summary: SuiSystemStateSummary) -> impl Iterator { +fn extract(summary: IotaSystemStateSummary) -> impl Iterator { summary.active_validators.into_iter().filter_map(|vm| { match Ed25519PublicKey::from_bytes(&vm.network_pubkey_bytes) { Ok(public_key) => { @@ -241,7 +242,7 @@ fn extract(summary: SuiSystemStateSummary) -> impl Iterator impl Iterator { error!( - "unable to decode public key for name: {:?} sui_address: {:?} error: {error}", - vm.name, vm.sui_address + "unable to decode public key for name: {:?} iota_address: {:?} error: {error}", + vm.name, vm.iota_address ); None // scoped to filter_map } @@ -261,28 +262,28 @@ fn extract(summary: SuiSystemStateSummary) -> impl Iterator(&r) - .expect("expected to deserialize ResponseBody{SuiSystemStateSummary}"); + .expect("expected to deserialize ResponseBody{IotaSystemStateSummary}"); let peers = extract(deserialized.result); assert_eq!(peers.count(), 1, "peers should have been a length of 1"); diff --git a/crates/sui-proxy/src/prom_to_mimir.rs b/crates/iota-proxy/src/prom_to_mimir.rs similarity index 98% rename from crates/sui-proxy/src/prom_to_mimir.rs rename to crates/iota-proxy/src/prom_to_mimir.rs index d5436465476..fd8db7ceb11 100644 --- a/crates/sui-proxy/src/prom_to_mimir.rs +++ b/crates/iota-proxy/src/prom_to_mimir.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use itertools::Itertools; use prometheus::proto::{Counter, Gauge, Histogram, Metric, MetricFamily, MetricType}; @@ -389,7 +390,7 @@ pub mod tests { "sample values do not match" ); - // timestamps are injected on the sui-node and we copy it to our sample + // timestamps are injected on the iota-node and we copy it to our sample // make sure that works assert_eq!( actual_sample.timestamp, expected_sample.timestamp, diff --git a/crates/sui-proxy/src/remote_write.rs b/crates/iota-proxy/src/remote_write.rs similarity index 99% rename from crates/sui-proxy/src/remote_write.rs rename to crates/iota-proxy/src/remote_write.rs index 99d60db7f61..60bb50906e7 100644 --- a/crates/sui-proxy/src/remote_write.rs +++ b/crates/iota-proxy/src/remote_write.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/crates/iota-replay/Cargo.toml b/crates/iota-replay/Cargo.toml new file mode 100644 index 00000000000..6387fd53804 --- /dev/null +++ b/crates/iota-replay/Cargo.toml @@ -0,0 +1,50 @@ +[package] +name = "iota-replay" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +bcs.workspace = true +prometheus.workspace = true +async-trait.workspace = true +jsonrpsee.workspace = true +async-recursion.workspace = true +clap = { version = "4.1.4", features = ["derive"] } +futures.workspace = true +serde.workspace = true +serde_json.workspace = true +similar.workspace = true +thiserror.workspace = true +tracing.workspace = true +rand.workspace = true +lru.workspace = true +parking_lot.workspace = true +serde_with.workspace = true +serde_yaml.workspace = true +shellexpand.workspace = true +tempfile.workspace = true +http.workspace = true + +move-vm-config.workspace = true +move-binary-format.workspace = true +move-bytecode-utils.workspace = true +move-core-types.workspace = true +tokio.workspace = true +tabled.workspace = true + +shared-crypto.workspace = true +iota-config.workspace = true +iota-core.workspace = true +iota-execution.workspace = true +iota-framework.workspace = true +iota-json-rpc.workspace = true +iota-json-rpc-api.workspace = true +iota-json-rpc-types.workspace = true +iota-protocol-config.workspace = true +iota-sdk.workspace = true +iota-storage.workspace = true +iota-types.workspace = true diff --git a/crates/iota-replay/src/config.rs b/crates/iota-replay/src/config.rs new file mode 100644 index 00000000000..6b7a59fe825 --- /dev/null +++ b/crates/iota-replay/src/config.rs @@ -0,0 +1,166 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr}; + +use http::Uri; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; +use tracing::log::warn; + +use crate::types::ReplayEngineError; + +pub const DEFAULT_CONFIG_PATH: &str = "~/.iota-replay/network-config.yaml"; + +#[serde_as] +#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] +#[serde(rename_all = "kebab-case")] +pub struct ReplayableNetworkConfigSet { + #[serde(skip)] + path: Option, + #[serde(default)] + pub base_network_configs: Vec, +} + +#[serde_as] +#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] +#[serde(rename_all = "kebab-case")] +pub struct ReplayableNetworkBaseConfig { + #[serde(default)] + pub name: String, + #[serde(default)] + pub epoch_zero_start_timestamp: u64, + #[serde(default)] + pub epoch_zero_rgp: u64, + #[serde(default = "default_full_node_address")] + pub public_full_node: String, +} + +impl ReplayableNetworkConfigSet { + pub fn load_config(override_path: Option) -> Result { + let path = override_path.unwrap_or_else(|| { + warn!( + "No network config path specified, using default path: {}", + DEFAULT_CONFIG_PATH + ); + DEFAULT_CONFIG_PATH.to_string() + }); + let path = shellexpand::tilde(&path).to_string(); + let path = PathBuf::from_str(&path).unwrap(); + ReplayableNetworkConfigSet::from_file(path.clone()).map_err(|err| { + ReplayEngineError::UnableToOpenYamlFile { + path: path.as_os_str().to_string_lossy().to_string(), + err: err.to_string(), + } + }) + } + + pub fn save_config(&self, override_path: Option) -> Result { + let path = override_path.unwrap_or_else(|| DEFAULT_CONFIG_PATH.to_string()); + let path = shellexpand::tilde(&path).to_string(); + let path = PathBuf::from_str(&path).unwrap(); + self.to_file(path.clone()) + .map_err(|err| ReplayEngineError::UnableToOpenYamlFile { + path: path.as_os_str().to_string_lossy().to_string(), + err: err.to_string(), + })?; + Ok(path) + } + + pub fn from_file(path: PathBuf) -> Result { + let file = + File::open(path.clone()).map_err(|err| ReplayEngineError::UnableToOpenYamlFile { + path: path.as_os_str().to_string_lossy().to_string(), + err: err.to_string(), + })?; + let reader = BufReader::new(file); + let mut config: ReplayableNetworkConfigSet = + serde_yaml::from_reader(reader).map_err(|err| { + ReplayEngineError::UnableToOpenYamlFile { + path: path.as_os_str().to_string_lossy().to_string(), + err: err.to_string(), + } + })?; + config.path = Some(path); + Ok(config) + } + + pub fn to_file(&self, path: PathBuf) -> Result<(), ReplayEngineError> { + let prefix = path.parent().unwrap(); + std::fs::create_dir_all(prefix).unwrap(); + let file = + File::create(path.clone()).map_err(|err| ReplayEngineError::UnableToOpenYamlFile { + path: path.as_os_str().to_string_lossy().to_string(), + err: err.to_string(), + })?; + serde_yaml::to_writer(file, self).map_err(|err| { + ReplayEngineError::UnableToWriteYamlFile { + path: path.as_os_str().to_string_lossy().to_string(), + err: err.to_string(), + } + })?; + Ok(()) + } +} + +impl Default for ReplayableNetworkConfigSet { + fn default() -> Self { + let testnet = ReplayableNetworkBaseConfig { + name: "testnet".to_string(), + epoch_zero_start_timestamp: 0, + epoch_zero_rgp: 0, + public_full_node: url_from_str("https://fullnode.testnet.iota.io:443") + .expect("invalid socket address") + .to_string(), + }; + let devnet = ReplayableNetworkBaseConfig { + name: "devnet".to_string(), + epoch_zero_start_timestamp: 0, + epoch_zero_rgp: 0, + public_full_node: url_from_str("https://fullnode.devnet.iota.io:443") + .expect("invalid socket address") + .to_string(), + }; + let mainnet = ReplayableNetworkBaseConfig { + name: "mainnet".to_string(), + epoch_zero_start_timestamp: 0, + epoch_zero_rgp: 0, + public_full_node: url_from_str("https://fullnode.mainnet.iota.io:443") + .expect("invalid socket address") + .to_string(), + }; + + Self { + path: None, + base_network_configs: vec![testnet, devnet, mainnet], + } + } +} + +pub fn default_full_node_address() -> String { + // Assume local node + "0.0.0.0:9000".to_string() +} + +pub fn url_from_str(s: &str) -> Result { + Uri::from_str(s).map_err(|e| ReplayEngineError::InvalidUrl { + err: e.to_string(), + url: s.to_string(), + }) +} + +#[test] +fn test_yaml() { + let mut set = ReplayableNetworkConfigSet::default(); + + let path = tempfile::tempdir().unwrap().path().to_path_buf(); + let path_str = path.to_str().unwrap().to_owned(); + + let final_path = set.save_config(Some(path_str.clone())).unwrap(); + + // Read from file + let data = ReplayableNetworkConfigSet::load_config(Some(path_str)).unwrap(); + set.path = Some(final_path); + assert!(set == data); +} diff --git a/crates/sui-replay/src/data_fetcher.rs b/crates/iota-replay/src/data_fetcher.rs similarity index 91% rename from crates/sui-replay/src/data_fetcher.rs rename to crates/iota-replay/src/data_fetcher.rs index a2763ce205d..24051439d09 100644 --- a/crates/sui-replay/src/data_fetcher.rs +++ b/crates/iota-replay/src/data_fetcher.rs @@ -1,23 +1,20 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, num::NonZeroUsize, str::FromStr}; use async_trait::async_trait; use futures::future::join_all; -use lru::LruCache; -use move_core_types::parser::parse_struct_tag; -use parking_lot::RwLock; -use rand::Rng; -use sui_core::authority::NodeStateDump; -use sui_json_rpc_api::QUERY_MAX_RESULT_LIMIT; -use sui_json_rpc_types::{ - EventFilter, SuiEvent, SuiGetPastObjectRequest, SuiObjectData, SuiObjectDataOptions, - SuiObjectResponse, SuiPastObjectResponse, SuiTransactionBlockResponse, - SuiTransactionBlockResponseOptions, +use iota_core::authority::NodeStateDump; +use iota_json_rpc_api::QUERY_MAX_RESULT_LIMIT; +use iota_json_rpc_types::{ + EventFilter, IotaEvent, IotaGetPastObjectRequest, IotaObjectData, IotaObjectDataOptions, + IotaObjectResponse, IotaPastObjectResponse, IotaTransactionBlockResponse, + IotaTransactionBlockResponseOptions, }; -use sui_sdk::SuiClient; -use sui_types::{ +use iota_sdk::IotaClient; +use iota_types::{ base_types::{ObjectID, SequenceNumber, VersionNumber}, digests::TransactionDigest, object::Object, @@ -25,6 +22,10 @@ use sui_types::{ EndOfEpochTransactionKind, SenderSignedData, TransactionDataAPI, TransactionKind, }, }; +use lru::LruCache; +use move_core_types::parser::parse_struct_tag; +use parking_lot::RwLock; +use rand::Rng; use tracing::error; use crate::types::{ReplayEngineError, EPOCH_CHANGE_STRUCT_TAG}; @@ -56,7 +57,7 @@ pub(crate) trait DataFetcher { async fn get_transaction( &self, tx_digest: &TransactionDigest, - ) -> Result; + ) -> Result; async fn get_loaded_child_objects( &self, @@ -80,7 +81,7 @@ pub(crate) trait DataFetcher { async fn get_epoch_change_events( &self, reverse: bool, - ) -> Result, ReplayEngineError>; + ) -> Result, ReplayEngineError>; async fn get_chain_id(&self) -> Result; } @@ -150,7 +151,7 @@ impl DataFetcher for Fetchers { async fn get_transaction( &self, tx_digest: &TransactionDigest, - ) -> Result { + ) -> Result { match self { Fetchers::Remote(q) => q.get_transaction(tx_digest).await, Fetchers::NodeStateDump(q) => q.get_transaction(tx_digest).await, @@ -204,7 +205,7 @@ impl DataFetcher for Fetchers { async fn get_epoch_change_events( &self, reverse: bool, - ) -> Result, ReplayEngineError> { + ) -> Result, ReplayEngineError> { match self { Fetchers::Remote(q) => q.get_epoch_change_events(reverse).await, Fetchers::NodeStateDump(q) => q.get_epoch_change_events(reverse).await, @@ -224,7 +225,7 @@ const EPOCH_INFO_CACHE_CAPACITY: Option = NonZeroUsize::new(10_000 pub struct RemoteFetcher { /// This is used to download items not in store - pub rpc_client: SuiClient, + pub rpc_client: IotaClient, /// Cache versioned objects pub versioned_object_cache: RwLock>, /// Cache non-versioned objects @@ -265,7 +266,7 @@ impl Clone for RemoteFetcher { } impl RemoteFetcher { - pub fn new(rpc_client: SuiClient) -> Self { + pub fn new(rpc_client: IotaClient) -> Self { Self { rpc_client, versioned_object_cache: RwLock::new(LruCache::new( @@ -326,11 +327,11 @@ impl DataFetcher for RemoteFetcher { // First check which we have in cache let (cached, to_fetch) = self.check_versioned_cache(objects); - let options = SuiObjectDataOptions::bcs_lossless(); + let options = IotaObjectDataOptions::bcs_lossless(); let objs: Vec<_> = to_fetch .iter() - .map(|(object_id, version)| SuiGetPastObjectRequest { + .map(|(object_id, version)| IotaGetPastObjectRequest { object_id: *object_id, version: *version, }) @@ -372,7 +373,7 @@ impl DataFetcher for RemoteFetcher { // First check which we have in cache let (cached, to_fetch) = self.check_latest_cache(objects); - let options = SuiObjectDataOptions::bcs_lossless(); + let options = IotaObjectDataOptions::bcs_lossless(); let objectsx = to_fetch.chunks(*QUERY_MAX_RESULT_LIMIT).map(|q| { self.rpc_client @@ -387,7 +388,7 @@ impl DataFetcher for RemoteFetcher { .map_err(ReplayEngineError::from)? .iter() .flatten() - .map(obj_from_sui_obj_response) + .map(obj_from_iota_obj_response) .collect::, _>>() .map(|mut x| { // Add the cached objects to the result @@ -409,15 +410,15 @@ impl DataFetcher for RemoteFetcher { .read_api() .get_checkpoint(id.into()) .await - .map_err(|q| ReplayEngineError::SuiRpcError { err: q.to_string() })? + .map_err(|q| ReplayEngineError::IotaRpcError { err: q.to_string() })? .transactions) } async fn get_transaction( &self, tx_digest: &TransactionDigest, - ) -> Result { - let tx_fetch_opts = SuiTransactionBlockResponseOptions::full_content(); + ) -> Result { + let tx_fetch_opts = IotaTransactionBlockResponseOptions::full_content(); self.rpc_client .read_api() @@ -547,11 +548,11 @@ impl DataFetcher for RemoteFetcher { async fn get_epoch_change_events( &self, reverse: bool, - ) -> Result, ReplayEngineError> { + ) -> Result, ReplayEngineError> { let struct_tag_str = EPOCH_CHANGE_STRUCT_TAG.to_string(); let struct_tag = parse_struct_tag(&struct_tag_str)?; - let mut epoch_change_events: Vec = vec![]; + let mut epoch_change_events: Vec = vec![]; let mut has_next_page = true; let mut cursor = None; @@ -588,19 +589,21 @@ impl DataFetcher for RemoteFetcher { } } -fn convert_past_obj_response(resp: SuiPastObjectResponse) -> Result { +fn convert_past_obj_response(resp: IotaPastObjectResponse) -> Result { match resp { - SuiPastObjectResponse::VersionFound(o) => obj_from_sui_obj_data(&o), - SuiPastObjectResponse::ObjectDeleted(r) => Err(ReplayEngineError::ObjectDeleted { + IotaPastObjectResponse::VersionFound(o) => obj_from_iota_obj_data(&o), + IotaPastObjectResponse::ObjectDeleted(r) => Err(ReplayEngineError::ObjectDeleted { id: r.object_id, version: r.version, digest: r.digest, }), - SuiPastObjectResponse::ObjectNotExists(id) => Err(ReplayEngineError::ObjectNotExist { id }), - SuiPastObjectResponse::VersionNotFound(id, version) => { + IotaPastObjectResponse::ObjectNotExists(id) => { + Err(ReplayEngineError::ObjectNotExist { id }) + } + IotaPastObjectResponse::VersionNotFound(id, version) => { Err(ReplayEngineError::ObjectVersionNotFound { id, version }) } - SuiPastObjectResponse::VersionTooHigh { + IotaPastObjectResponse::VersionTooHigh { object_id, asked_version, latest_version, @@ -612,19 +615,19 @@ fn convert_past_obj_response(resp: SuiPastObjectResponse) -> Result Result { +fn obj_from_iota_obj_response(o: &IotaObjectResponse) -> Result { let o = o.object().map_err(ReplayEngineError::from)?.clone(); - obj_from_sui_obj_data(&o) + obj_from_iota_obj_data(&o) } -fn obj_from_sui_obj_data(o: &SuiObjectData) -> Result { +fn obj_from_iota_obj_data(o: &IotaObjectData) -> Result { match TryInto::::try_into(o.clone()) { Ok(obj) => Ok(obj), Err(e) => Err(e.into()), } } -pub fn extract_epoch_and_version(ev: SuiEvent) -> Result<(u64, u64), ReplayEngineError> { +pub fn extract_epoch_and_version(ev: IotaEvent) -> Result<(u64, u64), ReplayEngineError> { if let serde_json::Value::Object(w) = ev.parsed_json { let epoch = u64::from_str(&w["epoch"].to_string().replace('\"', "")).unwrap(); let version = u64::from_str(&w["protocol_version"].to_string().replace('\"', "")).unwrap(); @@ -746,7 +749,7 @@ impl DataFetcher for NodeStateDumpFetcher { async fn get_transaction( &self, _tx_digest: &TransactionDigest, - ) -> Result { + ) -> Result { unimplemented!("get_transaction for state dump is not implemented") } @@ -789,7 +792,7 @@ impl DataFetcher for NodeStateDumpFetcher { async fn get_epoch_change_events( &self, _reverse: bool, - ) -> Result, ReplayEngineError> { + ) -> Result, ReplayEngineError> { unimplemented!("get_epoch_change_events for state dump is not implemented") } diff --git a/crates/iota-replay/src/displays/gas_status_displays.rs b/crates/iota-replay/src/displays/gas_status_displays.rs new file mode 100644 index 00000000000..a0896bb599b --- /dev/null +++ b/crates/iota-replay/src/displays/gas_status_displays.rs @@ -0,0 +1,79 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt::{Display, Formatter}; + +use iota_types::{gas::IotaGasStatus, gas_model::gas_v2::IotaGasStatus as GasStatusV2}; +use tabled::{ + builder::Builder as TableBuilder, + settings::{style::HorizontalLine, Style as TableStyle}, +}; + +use crate::displays::Pretty; + +impl<'a> Display for Pretty<'a, IotaGasStatus> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let Pretty(iota_gas_status) = self; + match iota_gas_status { + IotaGasStatus::V2(s) => { + display_info(f, s)?; + per_object_storage_table(f, s)?; + } + }; + Ok(()) + } +} + +fn per_object_storage_table(f: &mut Formatter, iota_gas_status: &GasStatusV2) -> std::fmt::Result { + let mut builder = TableBuilder::default(); + builder.push_record(vec!["Object ID", "Bytes", "Old Rebate", "New Rebate"]); + for (object_id, per_obj_storage) in iota_gas_status.per_object_storage() { + builder.push_record(vec![ + object_id.to_string(), + per_obj_storage.new_size.to_string(), + per_obj_storage.storage_rebate.to_string(), + per_obj_storage.storage_cost.to_string(), + ]); + } + let mut table = builder.build(); + + table.with(TableStyle::rounded().horizontals([HorizontalLine::new( + 1, + TableStyle::modern().get_horizontal(), + )])); + write!(f, "\n{}\n", table) +} + +fn display_info(f: &mut Formatter<'_>, iota_gas_status: &GasStatusV2) -> std::fmt::Result { + let mut builder = TableBuilder::default(); + builder.push_record(vec!["Gas Info".to_string()]); + builder.push_record(vec![format!( + "Reference Gas Price: {}", + iota_gas_status.reference_gas_price() + )]); + builder.push_record(vec![format!( + "Gas Price: {}", + iota_gas_status.gas_status.gas_price() + )]); + + builder.push_record(vec![format!( + "Max Gas Stack Height: {}", + iota_gas_status.gas_status.stack_height_high_water_mark() + )]); + + builder.push_record(vec![format!( + "Max Gas Stack Size: {}", + iota_gas_status.gas_status.stack_size_high_water_mark() + )]); + + builder.push_record(vec![format!( + "Number of Bytecode Instructions Executed: {}", + iota_gas_status.gas_status.instructions_executed() + )]); + + let mut table = builder.build(); + table.with(TableStyle::rounded()); + + write!(f, "\n{}\n", table) +} diff --git a/crates/iota-replay/src/displays/mod.rs b/crates/iota-replay/src/displays/mod.rs new file mode 100644 index 00000000000..24d64ddd04c --- /dev/null +++ b/crates/iota-replay/src/displays/mod.rs @@ -0,0 +1,8 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod gas_status_displays; +pub mod transaction_displays; + +pub struct Pretty<'a, T>(pub &'a T); diff --git a/crates/iota-replay/src/displays/transaction_displays.rs b/crates/iota-replay/src/displays/transaction_displays.rs new file mode 100644 index 00000000000..7f5512964b2 --- /dev/null +++ b/crates/iota-replay/src/displays/transaction_displays.rs @@ -0,0 +1,359 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + fmt::{Display, Formatter}, + sync::Arc, +}; + +use iota_execution::Executor; +use iota_types::{ + execution_mode::ExecutionResult, + object::bounded_visitor::BoundedVisitor, + transaction::{ + write_sep, Argument, CallArg, CallArg::Pure, Command, ObjectArg, ProgrammableMoveCall, + ProgrammableTransaction, + }, +}; +use move_core_types::{ + annotated_value::{MoveTypeLayout, MoveValue}, + language_storage::TypeTag, +}; +use tabled::{ + builder::Builder as TableBuilder, + settings::{style::HorizontalLine, Panel as TablePanel, Style as TableStyle}, +}; + +use crate::{displays::Pretty, replay::LocalExec}; + +pub struct FullPTB { + pub ptb: ProgrammableTransaction, + pub results: Vec, +} + +pub struct ResolvedResults { + pub mutable_reference_outputs: Vec<(Argument, MoveValue)>, + pub return_values: Vec, +} + +/// These Display implementations provide alternate displays that are used to +/// format info contained in these Structs when calling the CLI replay command +/// with an additional provided flag. +impl<'a> Display for Pretty<'a, FullPTB> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let Pretty(full_ptb) = self; + let FullPTB { ptb, results } = full_ptb; + + let ProgrammableTransaction { inputs, commands } = ptb; + + // write input objects section + if !inputs.is_empty() { + let mut builder = TableBuilder::default(); + for (i, input) in inputs.iter().enumerate() { + match input { + Pure(v) => { + if v.len() <= 16 { + builder.push_record(vec![format!("{i:<3} Pure Arg {:?}", v)]); + } else { + builder.push_record(vec![format!( + "{i:<3} Pure Arg [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, ...]", + v[0], + v[1], + v[2], + v[3], + v[4], + v[5], + v[6], + v[7], + v[8], + v[9], + v[10], + v[11], + v[12], + v[13], + v[14], + )]); + } + } + + CallArg::Object(ObjectArg::ImmOrOwnedObject(o)) => { + builder.push_record(vec![format!("{i:<3} Imm/Owned Object ID: {}", o.0)]); + } + CallArg::Object(ObjectArg::SharedObject { id, .. }) => { + builder.push_record(vec![format!("{i:<3} Shared Object ID: {}", id)]); + } + CallArg::Object(ObjectArg::Receiving(o)) => { + builder.push_record(vec![format!("{i:<3} Receiving Object ID: {}", o.0)]); + } + }; + } + + let mut table = builder.build(); + table.with(TablePanel::header("Input Objects")); + table.with(TableStyle::rounded().horizontals([HorizontalLine::new( + 1, + TableStyle::modern().get_horizontal(), + )])); + write!(f, "\n{}\n", table)?; + } else { + write!(f, "\n No input objects for this transaction")?; + } + + // write command results section + if !results.is_empty() { + write!(f, "\n\n")?; + } + for (i, result) in results.iter().enumerate() { + if i == results.len() - 1 { + write!( + f, + "╭───────────────────╮\n│ Command {i:<2} Output │\n╰───────────────────╯{}\n\n\n", + Pretty(result) + )? + } else { + write!( + f, + "╭───────────────────╮\n│ Command {i:<2} Output │\n╰───────────────────╯{}\n", + Pretty(result) + )? + } + } + + // write ptb functions section + let mut builder = TableBuilder::default(); + if !commands.is_empty() { + for (i, c) in commands.iter().enumerate() { + if i == commands.len() - 1 { + builder.push_record(vec![format!("{i:<2} {}", Pretty(c))]); + } else { + builder.push_record(vec![format!("{i:<2} {}\n", Pretty(c))]); + } + } + + let mut table = builder.build(); + table.with(TablePanel::header("Commands")); + table.with(TableStyle::rounded().horizontals([HorizontalLine::new( + 1, + TableStyle::modern().get_horizontal(), + )])); + write!(f, "\n{}\n", table)?; + } else { + write!(f, "\n No commands for this transaction")?; + } + + Ok(()) + } +} + +impl<'a> Display for Pretty<'a, Command> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let Pretty(command) = self; + match command { + Command::MoveCall(p) => { + write!(f, "{}", Pretty(&**p)) + } + Command::MakeMoveVec(ty_opt, elems) => { + write!(f, "MakeMoveVec:\n ┌")?; + if let Some(ty) = ty_opt { + write!(f, "\n │ Type Tag: {ty}")?; + } + write!(f, "\n │ Arguments:\n │ ")?; + write_sep(f, elems.iter().map(Pretty), "\n │ ")?; + write!(f, "\n └") + } + Command::TransferObjects(objs, addr) => { + write!(f, "TransferObjects:\n ┌\n │ Arguments: \n │ ")?; + write_sep(f, objs.iter().map(Pretty), "\n │ ")?; + write!(f, "\n │ Address: {}\n └", Pretty(addr)) + } + Command::SplitCoins(coin, amounts) => { + write!( + f, + "SplitCoins:\n ┌\n │ Coin: {}\n │ Amounts: \n │ ", + Pretty(coin) + )?; + write_sep(f, amounts.iter().map(Pretty), "\n │ ")?; + write!(f, "\n └") + } + Command::MergeCoins(target, coins) => { + write!( + f, + "MergeCoins:\n ┌\n │ Target: {}\n │ Coins: \n │ ", + Pretty(target) + )?; + write_sep(f, coins.iter().map(Pretty), "\n │ ")?; + write!(f, "\n └") + } + Command::Publish(_bytes, deps) => { + write!(f, "Publish:\n ┌\n │ Dependencies: \n │ ")?; + write_sep(f, deps, "\n │ ")?; + write!(f, "\n └") + } + Command::Upgrade(_bytes, deps, current_package_id, ticket) => { + write!(f, "Upgrade:\n ┌\n │ Dependencies: \n │ ")?; + write_sep(f, deps, "\n │ ")?; + write!(f, "\n │ Current Package ID: {current_package_id}")?; + write!(f, "\n │ Ticket: {}", Pretty(ticket))?; + write!(f, "\n └") + } + } + } +} + +impl<'a> Display for Pretty<'a, ProgrammableMoveCall> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let Pretty(move_call) = self; + let ProgrammableMoveCall { + package, + module, + function, + type_arguments, + arguments, + } = move_call; + + write!( + f, + "MoveCall:\n ┌\n │ Function: {} \n │ Module: {}\n │ Package: {}", + function, module, package + )?; + + if !type_arguments.is_empty() { + write!(f, "\n │ Type Arguments: \n │ ")?; + write_sep(f, type_arguments, "\n │ ")?; + } + if !arguments.is_empty() { + write!(f, "\n │ Arguments: \n │ ")?; + write_sep(f, arguments.iter().map(Pretty), "\n │ ")?; + } + + write!(f, "\n └") + } +} + +impl<'a> Display for Pretty<'a, Argument> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let Pretty(argument) = self; + + let output = match argument { + Argument::GasCoin => "GasCoin".to_string(), + Argument::Input(i) => format!("Input {}", i), + Argument::Result(i) => format!("Result {}", i), + Argument::NestedResult(j, k) => format!("Result {}: {}", j, k), + }; + write!(f, "{}", output) + } +} +impl<'a> Display for Pretty<'a, ResolvedResults> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let Pretty(ResolvedResults { + mutable_reference_outputs, + return_values, + }) = self; + + let len_m_ref = mutable_reference_outputs.len(); + let len_ret_vals = return_values.len(); + + if len_ret_vals > 0 { + write!(f, "\n Return Values:\n ──────────────")?; + } + + for (i, value) in return_values.iter().enumerate() { + write!(f, "\n • Result {i:<2} ")?; + write!(f, "\n{:#}\n", value)?; + } + + if len_m_ref > 0 { + write!( + f, + "\n Mutable Reference Outputs:\n ──────────────────────────" + )?; + } + + for (arg, value) in mutable_reference_outputs { + write!(f, "\n • {} ", arg)?; + write!(f, "\n{:#}\n", value)?; + } + + if len_ret_vals == 0 && len_m_ref == 0 { + write!(f, "\n No return values")?; + } + + Ok(()) + } +} + +impl<'a> Display for Pretty<'a, TypeTag> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let Pretty(type_tag) = self; + match type_tag { + TypeTag::Vector(v) => { + write!(f, "Vector of {}", Pretty(&**v)) + } + TypeTag::Struct(s) => { + write!(f, "{}::{}", s.module, s.name) + } + _ => { + write!(f, "{}", type_tag) + } + } + } +} + +fn resolve_to_layout( + type_tag: &TypeTag, + executor: &Arc, + store_factory: &LocalExec, +) -> MoveTypeLayout { + match type_tag { + TypeTag::Vector(inner) => { + MoveTypeLayout::Vector(Box::from(resolve_to_layout(inner, executor, store_factory))) + } + TypeTag::Struct(inner) => { + let mut layout_resolver = executor.type_layout_resolver(Box::new(store_factory)); + MoveTypeLayout::Struct(layout_resolver.get_annotated_layout(inner).unwrap()) + } + TypeTag::Bool => MoveTypeLayout::Bool, + TypeTag::U8 => MoveTypeLayout::U8, + TypeTag::U64 => MoveTypeLayout::U64, + TypeTag::U128 => MoveTypeLayout::U128, + TypeTag::Address => MoveTypeLayout::Address, + TypeTag::Signer => MoveTypeLayout::Signer, + TypeTag::U16 => MoveTypeLayout::U16, + TypeTag::U32 => MoveTypeLayout::U32, + TypeTag::U256 => MoveTypeLayout::U256, + } +} + +fn resolve_value( + bytes: &[u8], + type_tag: &TypeTag, + executor: &Arc, + store_factory: &LocalExec, +) -> anyhow::Result { + let layout = resolve_to_layout(type_tag, executor, store_factory); + BoundedVisitor::deserialize_value(bytes, &layout) +} + +pub fn transform_command_results_to_annotated( + executor: &Arc, + store_factory: &LocalExec, + results: Vec, +) -> anyhow::Result> { + let mut output = Vec::new(); + for (m_refs, return_vals) in results.iter() { + let mut m_refs_out = Vec::new(); + let mut return_vals_out = Vec::new(); + for (arg, bytes, tag) in m_refs { + m_refs_out.push((*arg, resolve_value(bytes, tag, executor, store_factory)?)); + } + for (bytes, tag) in return_vals { + return_vals_out.push(resolve_value(bytes, tag, executor, store_factory)?); + } + output.push(ResolvedResults { + mutable_reference_outputs: m_refs_out, + return_values: return_vals_out, + }); + } + Ok(output) +} diff --git a/crates/sui-replay/src/fuzz.rs b/crates/iota-replay/src/fuzz.rs similarity index 98% rename from crates/sui-replay/src/fuzz.rs rename to crates/iota-replay/src/fuzz.rs index d3e997cfc2f..4bf929f3a63 100644 --- a/crates/sui-replay/src/fuzz.rs +++ b/crates/iota-replay/src/fuzz.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use sui_config::node::ExpensiveSafetyCheckConfig; -use sui_types::{ +use iota_config::node::ExpensiveSafetyCheckConfig; +use iota_types::{ digests::TransactionDigest, execution_status::ExecutionFailureStatus, transaction::TransactionKind, }; diff --git a/crates/sui-replay/src/fuzz_mutations.rs b/crates/iota-replay/src/fuzz_mutations.rs similarity index 97% rename from crates/sui-replay/src/fuzz_mutations.rs rename to crates/iota-replay/src/fuzz_mutations.rs index 6341aede6c8..c60d8fb21aa 100644 --- a/crates/sui-replay/src/fuzz_mutations.rs +++ b/crates/iota-replay/src/fuzz_mutations.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_types::transaction::TransactionKind; use rand::{seq::SliceRandom, SeedableRng}; -use sui_types::transaction::TransactionKind; use crate::fuzz::TransactionKindMutator; diff --git a/crates/sui-replay/src/fuzz_mutations/drop_random_command_suffix.rs b/crates/iota-replay/src/fuzz_mutations/drop_random_command_suffix.rs similarity index 92% rename from crates/sui-replay/src/fuzz_mutations/drop_random_command_suffix.rs rename to crates/iota-replay/src/fuzz_mutations/drop_random_command_suffix.rs index 0d65f231c3d..297733563da 100644 --- a/crates/sui-replay/src/fuzz_mutations/drop_random_command_suffix.rs +++ b/crates/iota-replay/src/fuzz_mutations/drop_random_command_suffix.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_types::transaction::TransactionKind; use rand::Rng; -use sui_types::transaction::TransactionKind; use tracing::info; use crate::fuzz::TransactionKindMutator; diff --git a/crates/sui-replay/src/fuzz_mutations/drop_random_commands.rs b/crates/iota-replay/src/fuzz_mutations/drop_random_commands.rs similarity index 92% rename from crates/sui-replay/src/fuzz_mutations/drop_random_commands.rs rename to crates/iota-replay/src/fuzz_mutations/drop_random_commands.rs index 243b2e7cb92..beb4b2781a9 100644 --- a/crates/sui-replay/src/fuzz_mutations/drop_random_commands.rs +++ b/crates/iota-replay/src/fuzz_mutations/drop_random_commands.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_types::transaction::TransactionKind; use rand::seq::SliceRandom; -use sui_types::transaction::TransactionKind; use tracing::info; use crate::fuzz::TransactionKindMutator; diff --git a/crates/sui-replay/src/fuzz_mutations/shuffle_command_inputs.rs b/crates/iota-replay/src/fuzz_mutations/shuffle_command_inputs.rs similarity index 94% rename from crates/sui-replay/src/fuzz_mutations/shuffle_command_inputs.rs rename to crates/iota-replay/src/fuzz_mutations/shuffle_command_inputs.rs index 5826dc00816..b2ca7094f57 100644 --- a/crates/sui-replay/src/fuzz_mutations/shuffle_command_inputs.rs +++ b/crates/iota-replay/src/fuzz_mutations/shuffle_command_inputs.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_types::transaction::{Command, TransactionKind}; use rand::seq::SliceRandom; -use sui_types::transaction::{Command, TransactionKind}; use tracing::info; use crate::fuzz::TransactionKindMutator; diff --git a/crates/sui-replay/src/fuzz_mutations/shuffle_commands.rs b/crates/iota-replay/src/fuzz_mutations/shuffle_commands.rs similarity index 91% rename from crates/sui-replay/src/fuzz_mutations/shuffle_commands.rs rename to crates/iota-replay/src/fuzz_mutations/shuffle_commands.rs index 2ec895b6d80..8e7468ad73e 100644 --- a/crates/sui-replay/src/fuzz_mutations/shuffle_commands.rs +++ b/crates/iota-replay/src/fuzz_mutations/shuffle_commands.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_types::transaction::TransactionKind; use rand::seq::SliceRandom; -use sui_types::transaction::TransactionKind; use tracing::info; use crate::fuzz::TransactionKindMutator; diff --git a/crates/sui-replay/src/fuzz_mutations/shuffle_transaction_inputs.rs b/crates/iota-replay/src/fuzz_mutations/shuffle_transaction_inputs.rs similarity index 91% rename from crates/sui-replay/src/fuzz_mutations/shuffle_transaction_inputs.rs rename to crates/iota-replay/src/fuzz_mutations/shuffle_transaction_inputs.rs index 53eb0d4b9d5..3027d84dccf 100644 --- a/crates/sui-replay/src/fuzz_mutations/shuffle_transaction_inputs.rs +++ b/crates/iota-replay/src/fuzz_mutations/shuffle_transaction_inputs.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_types::transaction::TransactionKind; use rand::seq::SliceRandom; -use sui_types::transaction::TransactionKind; use tracing::info; use crate::fuzz::TransactionKindMutator; diff --git a/crates/sui-replay/src/fuzz_mutations/shuffle_types.rs b/crates/iota-replay/src/fuzz_mutations/shuffle_types.rs similarity index 92% rename from crates/sui-replay/src/fuzz_mutations/shuffle_types.rs rename to crates/iota-replay/src/fuzz_mutations/shuffle_types.rs index 0e9afa5c57c..45232015b2d 100644 --- a/crates/sui-replay/src/fuzz_mutations/shuffle_types.rs +++ b/crates/iota-replay/src/fuzz_mutations/shuffle_types.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_types::transaction::{Command, TransactionKind}; use rand::seq::SliceRandom; -use sui_types::transaction::{Command, TransactionKind}; use tracing::info; use crate::fuzz::TransactionKindMutator; diff --git a/crates/iota-replay/src/lib.rs b/crates/iota-replay/src/lib.rs new file mode 100644 index 00000000000..d864eee20f3 --- /dev/null +++ b/crates/iota-replay/src/lib.rs @@ -0,0 +1,606 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{env, io::BufRead, path::PathBuf, str::FromStr}; + +use async_recursion::async_recursion; +use clap::Parser; +use config::ReplayableNetworkConfigSet; +use fuzz::{ReplayFuzzer, ReplayFuzzerConfig}; +use fuzz_mutations::base_fuzzers; +use iota_config::node::ExpensiveSafetyCheckConfig; +use iota_protocol_config::Chain; +use iota_types::{ + digests::{get_mainnet_chain_identifier, get_testnet_chain_identifier, TransactionDigest}, + message_envelope::Message, +}; +use move_vm_config::runtime::get_default_output_filepath; +use tracing::{error, info, warn}; +use transaction_provider::{FuzzStartPoint, TransactionSource}; + +use crate::replay::{ExecutionSandboxState, LocalExec, ProtocolVersionSummary}; +pub mod config; +mod data_fetcher; +mod displays; +pub mod fuzz; +pub mod fuzz_mutations; +mod replay; +pub mod transaction_provider; +pub mod types; + +static DEFAULT_SANDBOX_BASE_PATH: &str = + concat!(env!("CARGO_MANIFEST_DIR"), "/tests/sandbox_snapshots"); + +#[cfg(test)] +mod tests; + +#[derive(Parser, Clone)] +#[command(rename_all = "kebab-case")] +pub enum ReplayToolCommand { + /// Generate a new network config file + #[command(name = "gen")] + GenerateDefaultConfig, + + /// Persist sandbox state + #[command(name = "ps")] + PersistSandbox { + #[arg(long, short)] + tx_digest: String, + #[arg(long, short, default_value = DEFAULT_SANDBOX_BASE_PATH)] + base_path: PathBuf, + }, + + /// Replay from sandbox state file + /// This is a completely local execution + #[command(name = "rs")] + ReplaySandbox { + #[arg(long, short)] + path: PathBuf, + }, + + /// Profile transaction + #[command(name = "rp")] + ProfileTransaction { + #[arg(long, short)] + tx_digest: String, + /// Optional version of the executor to use, if not specified defaults + /// to the one originally used for the transaction. + #[arg(long, short, allow_hyphen_values = true)] + executor_version: Option, + /// Optional protocol version to use, if not specified defaults to the + /// one originally used for the transaction. + #[arg(long, short, allow_hyphen_values = true)] + protocol_version: Option, + /// Optional output filepath for the profile generated by this run, if + /// not specified defaults to + /// `gas_profile_{tx_digest}_{unix_timestamp}.json in the working + /// directory. + #[arg(long, short, allow_hyphen_values = true)] + profile_output: Option, + }, + + /// Replay transaction + #[command(name = "tx")] + ReplayTransaction { + #[arg(long, short)] + tx_digest: String, + #[arg(long, short)] + show_effects: bool, + #[arg(long, short)] + diag: bool, + /// Optional version of the executor to use, if not specified defaults + /// to the one originally used for the transaction. + #[arg(long, short, allow_hyphen_values = true)] + executor_version: Option, + /// Optional protocol version to use, if not specified defaults to the + /// one originally used for the transaction. + #[arg(long, short, allow_hyphen_values = true)] + protocol_version: Option, + }, + + /// Replay transactions listed in a file + #[command(name = "rb")] + ReplayBatch { + #[arg(long, short)] + path: PathBuf, + #[arg(long, short)] + terminate_early: bool, + #[arg(long, short, default_value = "16")] + batch_size: u64, + }, + + /// Replay a transaction from a node state dump + #[command(name = "rd")] + ReplayDump { + #[arg(long, short)] + path: String, + #[arg(long, short)] + show_effects: bool, + }, + + /// Replay all transactions in a range of checkpoints + #[command(name = "ch")] + ReplayCheckpoints { + #[arg(long, short)] + start: u64, + #[arg(long, short)] + end: u64, + #[arg(long, short)] + terminate_early: bool, + #[arg(long, short, default_value = "16")] + max_tasks: u64, + }, + + /// Replay all transactions in an epoch + #[command(name = "ep")] + ReplayEpoch { + #[arg(long, short)] + epoch: u64, + #[arg(long, short)] + terminate_early: bool, + #[arg(long, short, default_value = "16")] + max_tasks: u64, + }, + + /// Run the replay based fuzzer + #[command(name = "fz")] + Fuzz { + #[arg(long, short)] + start: Option, + #[arg(long, short)] + num_mutations_per_base: u64, + #[arg(long, short = 'b', default_value = "18446744073709551614")] + num_base_transactions: u64, + }, + + #[command(name = "report")] + Report, +} + +#[async_recursion] +pub async fn execute_replay_command( + rpc_url: Option, + safety_checks: bool, + use_authority: bool, + cfg_path: Option, + cmd: ReplayToolCommand, +) -> anyhow::Result> { + let safety = if safety_checks { + ExpensiveSafetyCheckConfig::new_enable_all() + } else { + ExpensiveSafetyCheckConfig::default() + }; + Ok(match cmd { + ReplayToolCommand::ReplaySandbox { path } => { + let contents = std::fs::read_to_string(path)?; + let sandbox_state: ExecutionSandboxState = serde_json::from_str(&contents)?; + info!("Executing tx: {}", sandbox_state.transaction_info.tx_digest); + let sandbox_state = LocalExec::certificate_execute_with_sandbox_state( + &sandbox_state, + None, + &sandbox_state.pre_exec_diag, + ) + .await?; + sandbox_state.check_effects()?; + info!("Execution finished successfully. Local and on-chain effects match."); + None + } + ReplayToolCommand::PersistSandbox { + tx_digest, + base_path, + } => { + let tx_digest = TransactionDigest::from_str(&tx_digest)?; + info!("Executing tx: {}", tx_digest); + let sandbox_state = LocalExec::replay_with_network_config( + rpc_url, + cfg_path.map(|p| p.to_str().unwrap().to_string()), + tx_digest, + safety, + use_authority, + None, + None, + None, + ) + .await?; + + let out = serde_json::to_string(&sandbox_state).unwrap(); + let path = base_path.join(format!("{}.json", tx_digest)); + std::fs::write(path, out)?; + None + } + ReplayToolCommand::GenerateDefaultConfig => { + let set = ReplayableNetworkConfigSet::default(); + let path = set.save_config(None).unwrap(); + println!("Default config saved to: {}", path.to_str().unwrap()); + warn!("Note: default config nodes might prune epochs/objects"); + None + } + ReplayToolCommand::Fuzz { + start, + num_mutations_per_base, + num_base_transactions, + } => { + let config = ReplayFuzzerConfig { + num_mutations_per_base, + mutator: Box::new(base_fuzzers(num_mutations_per_base)), + tx_source: TransactionSource::TailLatest { start }, + fail_over_on_err: false, + expensive_safety_check_config: Default::default(), + }; + let fuzzer = ReplayFuzzer::new(rpc_url.expect("Url must be provided"), config) + .await + .unwrap(); + fuzzer.run(num_base_transactions).await.unwrap(); + None + } + ReplayToolCommand::ReplayDump { path, show_effects } => { + let mut lx = LocalExec::new_for_state_dump(&path, rpc_url).await?; + let (sandbox_state, node_dump_state) = lx.execute_state_dump(safety).await?; + if show_effects { + println!("{:#?}", sandbox_state.local_exec_effects); + } + + sandbox_state.check_effects()?; + + let effects = node_dump_state.computed_effects.digest(); + if effects != node_dump_state.expected_effects_digest { + error!( + "Effects digest mismatch for {}: expected: {:?}, got: {:?}", + node_dump_state.tx_digest, node_dump_state.expected_effects_digest, effects, + ); + anyhow::bail!("Effects mismatch"); + } + + info!("Execution finished successfully. Local and on-chain effects match."); + Some((1u64, 1u64)) + } + ReplayToolCommand::ReplayBatch { + path, + terminate_early, + batch_size, + } => { + async fn exec_batch( + rpc_url: Option, + safety: ExpensiveSafetyCheckConfig, + use_authority: bool, + cfg_path: Option, + tx_digests: &[TransactionDigest], + ) -> anyhow::Result<()> { + let mut handles = vec![]; + for tx_digest in tx_digests { + let tx_digest = *tx_digest; + let rpc_url = rpc_url.clone(); + let cfg_path = cfg_path.clone(); + let safety = safety.clone(); + handles.push(tokio::spawn(async move { + info!("Executing tx: {}", tx_digest); + let sandbox_state = LocalExec::replay_with_network_config( + rpc_url, + cfg_path.map(|p| p.to_str().unwrap().to_string()), + tx_digest, + safety, + use_authority, + None, + None, + None, + ) + .await?; + + sandbox_state.check_effects()?; + + info!("Execution finished successfully: {}. Local and on-chain effects match.", tx_digest); + Ok::<_, anyhow::Error>(()) + })); + } + futures::future::join_all(handles) + .await + .into_iter() + .collect::, _>>() + .expect("Join all failed") + .into_iter() + .collect::, _>>()?; + Ok(()) + } + + // While file end not reached, read up to max_tasks lines from path + let file = std::fs::File::open(path).unwrap(); + let reader = std::io::BufReader::new(file); + + let mut chunk = Vec::new(); + for tx_digest in reader.lines() { + chunk.push( + match TransactionDigest::from_str(&tx_digest.expect("Unable to readline")) { + Ok(digest) => digest, + Err(e) => { + panic!("Error parsing tx digest: {:?}", e); + } + }, + ); + if chunk.len() == batch_size as usize { + println!("Executing batch: {:?}", chunk); + // execute all in chunk + match exec_batch( + rpc_url.clone(), + safety.clone(), + use_authority, + cfg_path.clone(), + &chunk, + ) + .await + { + Ok(_) => info!("Batch executed successfully: {:?}", chunk), + Err(e) => { + error!("Error executing batch: {:?}", e); + if terminate_early { + return Err(e); + } + } + } + println!("Finished batch execution"); + + chunk.clear(); + } + } + if !chunk.is_empty() { + println!("Executing batch: {:?}", chunk); + match exec_batch( + rpc_url.clone(), + safety, + use_authority, + cfg_path.clone(), + &chunk, + ) + .await + { + Ok(_) => info!("Batch executed successfully: {:?}", chunk), + Err(e) => { + error!("Error executing batch: {:?}", e); + if terminate_early { + return Err(e); + } + } + } + println!("Finished batch execution"); + } + + // TODO: clean this up + Some((0u64, 0u64)) + } + ReplayToolCommand::ProfileTransaction { + tx_digest, + executor_version, + protocol_version, + profile_output, + } => { + let output_path = profile_output.or(Some(get_default_output_filepath())); + + let tx_digest = TransactionDigest::from_str(&tx_digest)?; + info!("Executing tx: {}", tx_digest); + let _sandbox_state = LocalExec::replay_with_network_config( + rpc_url, + cfg_path.map(|p| p.to_str().unwrap().to_string()), + tx_digest, + safety, + use_authority, + executor_version, + protocol_version, + output_path, + ) + .await?; + + println!("Execution finished successfully."); + Some((1u64, 1u64)) + } + + ReplayToolCommand::ReplayTransaction { + tx_digest, + show_effects, + diag, + executor_version, + protocol_version, + } => { + let tx_digest = TransactionDigest::from_str(&tx_digest)?; + info!("Executing tx: {}", tx_digest); + let sandbox_state = LocalExec::replay_with_network_config( + rpc_url, + cfg_path.map(|p| p.to_str().unwrap().to_string()), + tx_digest, + safety, + use_authority, + executor_version, + protocol_version, + None, + ) + .await?; + + if diag { + println!("{:#?}", sandbox_state.pre_exec_diag); + } + if show_effects { + println!("{}", sandbox_state.local_exec_effects); + } + + sandbox_state.check_effects()?; + + println!("Execution finished successfully. Local and on-chain effects match."); + Some((1u64, 1u64)) + } + + ReplayToolCommand::Report => { + let mut lx = + LocalExec::new_from_fn_url(&rpc_url.expect("Url must be provided")).await?; + let epoch_table = lx.protocol_ver_to_epoch_map().await?; + + // We need this for other activities in this session + lx.current_protocol_version = *epoch_table.keys().peekable().last().unwrap(); + + println!( + " Protocol Version | Epoch Change TX | Epoch Range | Checkpoint Range " + ); + println!( + "---------------------------------------------------------------------------------------------------------------" + ); + + for ( + protocol_version, + ProtocolVersionSummary { + epoch_change_tx: tx_digest, + epoch_start: start_epoch, + epoch_end: end_epoch, + checkpoint_start, + checkpoint_end, + .. + }, + ) in epoch_table + { + println!( + " {:^16} | {:^43} | {:^10}-{:^10}| {:^10}-{:^10} ", + protocol_version, + tx_digest, + start_epoch, + end_epoch, + checkpoint_start.unwrap_or(u64::MAX), + checkpoint_end.unwrap_or(u64::MAX) + ); + } + + lx.populate_protocol_version_tables().await?; + for x in lx.protocol_version_system_package_table { + println!("Protocol version: {}", x.0); + for (package_id, seq_num) in x.1 { + println!("Package: {} Seq: {}", package_id, seq_num); + } + } + None + } + + ReplayToolCommand::ReplayCheckpoints { + start, + end, + terminate_early, + max_tasks, + } => { + assert!(start <= end, "Start checkpoint must be <= end checkpoint"); + assert!(max_tasks > 0, "Max tasks must be > 0"); + let checkpoints_per_task = ((end - start + max_tasks) / max_tasks) as usize; + let mut handles = vec![]; + info!( + "Executing checkpoints {} to {} with at most {} tasks and at most {} checkpoints per task", + start, end, max_tasks, checkpoints_per_task + ); + + let range: Vec<_> = (start..=end).collect(); + for (task_count, checkpoints) in range.chunks(checkpoints_per_task).enumerate() { + let checkpoints = checkpoints.to_vec(); + let rpc_url = rpc_url.clone(); + let safety = safety.clone(); + handles.push(tokio::spawn(async move { + info!("Spawning task {task_count} for checkpoints {checkpoints:?}"); + let time = std::time::Instant::now(); + let (succeeded, total) = LocalExec::new_from_fn_url(&rpc_url.expect("Url must be provided")) + .await + .unwrap() + .init_for_execution() + .await + .unwrap() + .execute_all_in_checkpoints(&checkpoints, &safety, terminate_early, use_authority) + .await + .unwrap(); + let time = time.elapsed(); + info!( + "Task {task_count}: executed checkpoints {:?} @ {} total transactions, {} succeeded", + checkpoints, total, succeeded + ); + (succeeded, total, time) + })); + } + + let mut total_tx = 0; + let mut total_time_ms = 0; + let mut total_succeeded = 0; + futures::future::join_all(handles) + .await + .into_iter() + .for_each(|x| match x { + Ok((suceeded, total, time)) => { + total_tx += total; + total_time_ms += time.as_millis() as u64; + total_succeeded += suceeded; + } + Err(e) => { + error!("Task failed: {:?}", e); + } + }); + info!( + "Executed {} checkpoints @ {}/{} total TXs succeeded in {} ms ({}) avg TX/s", + end - start + 1, + total_succeeded, + total_tx, + total_time_ms, + (total_tx as f64) / (total_time_ms as f64 / 1000.0) + ); + Some((total_succeeded, total_tx)) + } + ReplayToolCommand::ReplayEpoch { + epoch, + terminate_early, + max_tasks, + } => { + let lx = + LocalExec::new_from_fn_url(&rpc_url.clone().expect("Url must be provided")).await?; + + let (start, end) = lx.checkpoints_for_epoch(epoch).await?; + + info!( + "Executing epoch {} (checkpoint range {}-{}) with at most {} tasks", + epoch, start, end, max_tasks + ); + let status = execute_replay_command( + rpc_url, + safety_checks, + use_authority, + cfg_path, + ReplayToolCommand::ReplayCheckpoints { + start, + end, + terminate_early, + max_tasks, + }, + ) + .await; + match status { + Ok(Some((succeeded, total))) => { + info!( + "Epoch {} replay finished {} out of {} TXs", + epoch, succeeded, total + ); + + return Ok(Some((succeeded, total))); + } + Ok(None) => { + return Ok(None); + } + Err(e) => { + error!("Epoch {} replay failed: {:?}", epoch, e); + return Err(e); + } + } + } + }) +} + +pub(crate) fn chain_from_chain_id(chain: &str) -> Chain { + let mainnet_chain_id = format!("{}", get_mainnet_chain_identifier()); + // TODO: Since testnet periodically resets, we need to ensure that the chain id + // is updated to the latest one. + let testnet_chain_id = format!("{}", get_testnet_chain_identifier()); + + if mainnet_chain_id == chain { + Chain::Mainnet + } else if testnet_chain_id == chain { + Chain::Testnet + } else { + Chain::Unknown + } +} diff --git a/crates/sui-replay/src/replay.rs b/crates/iota-replay/src/replay.rs similarity index 95% rename from crates/sui-replay/src/replay.rs rename to crates/iota-replay/src/replay.rs index 68883a69bec..f3cd23efd85 100644 --- a/crates/sui-replay/src/replay.rs +++ b/crates/iota-replay/src/replay.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -8,19 +9,8 @@ use std::{ }; use futures::executor::block_on; -use move_binary_format::CompiledModule; -use move_bytecode_utils::module_cache::GetModule; -use move_core_types::{ - account_address::AccountAddress, - language_storage::{ModuleId, StructTag}, - resolver::{ModuleResolver, ResourceResolver}, -}; -use prometheus::Registry; -use serde::{Deserialize, Serialize}; -use shared_crypto::intent::Intent; -use similar::{ChangeTag, TextDiff}; -use sui_config::node::ExpensiveSafetyCheckConfig; -use sui_core::{ +use iota_config::node::ExpensiveSafetyCheckConfig; +use iota_core::{ authority::{ authority_per_epoch_store::AuthorityPerEpochStore, epoch_start_configuration::EpochStartConfiguration, @@ -30,26 +20,26 @@ use sui_core::{ module_cache_metrics::ResolverMetrics, signature_verifier::SignatureVerifierMetrics, }; -use sui_execution::Executor; -use sui_framework::BuiltInFramework; -use sui_json_rpc_types::{SuiTransactionBlockEffects, SuiTransactionBlockEffectsAPI}; -use sui_protocol_config::{Chain, ProtocolConfig}; -use sui_sdk::{SuiClient, SuiClientBuilder}; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress, VersionNumber}, +use iota_execution::Executor; +use iota_framework::BuiltInFramework; +use iota_json_rpc_types::{IotaTransactionBlockEffects, IotaTransactionBlockEffectsAPI}; +use iota_protocol_config::{Chain, ProtocolConfig}; +use iota_sdk::{IotaClient, IotaClientBuilder}; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber, VersionNumber}, committee::EpochId, digests::{ChainIdentifier, CheckpointDigest, ObjectDigest, TransactionDigest}, - error::{ExecutionError, SuiError, SuiResult}, + error::{ExecutionError, IotaError, IotaResult}, executable_transaction::VerifiedExecutableTransaction, - gas::SuiGasStatus, + gas::IotaGasStatus, inner_temporary_store::InnerTemporaryStore, + iota_system_state::epoch_start_iota_system_state::EpochStartSystemState, metrics::LimitsMetrics, object::{Data, Object, Owner}, storage::{ get_module, get_module_by_id, BackingPackageStore, ChildObjectResolver, ObjectStore, PackageObject, ParentSync, }, - sui_system_state::epoch_start_sui_system_state::EpochStartSystemState, transaction::{ CertifiedTransaction, CheckedInputObjects, InputObjectKind, InputObjects, ObjectReadResult, ObjectReadResultKind, SenderSignedData, Transaction, TransactionData, TransactionDataAPI, @@ -58,6 +48,17 @@ use sui_types::{ }, DEEPBOOK_PACKAGE_ID, }; +use move_binary_format::CompiledModule; +use move_bytecode_utils::module_cache::GetModule; +use move_core_types::{ + account_address::AccountAddress, + language_storage::{ModuleId, StructTag}, + resolver::{ModuleResolver, ResourceResolver}, +}; +use prometheus::Registry; +use serde::{Deserialize, Serialize}; +use shared_crypto::intent::Intent; +use similar::{ChangeTag, TextDiff}; use tracing::{error, info, trace, warn}; use crate::{ @@ -86,7 +87,7 @@ pub struct ExecutionSandboxState { #[serde(skip)] pub local_exec_temporary_store: Option, /// Effects from executing this locally in `execute_transaction_to_effects` - pub local_exec_effects: SuiTransactionBlockEffects, + pub local_exec_effects: IotaTransactionBlockEffects, /// Status from executing this locally in `execute_transaction_to_effects` #[serde(skip)] pub local_exec_status: Option>, @@ -220,7 +221,7 @@ impl Storage { #[derive(Clone)] pub struct LocalExec { - pub client: Option, + pub client: Option, // For a given protocol version, what TX created it, and what is the valid range of epochs // at this protocol version. pub protocol_version_epoch_table: BTreeMap, @@ -264,7 +265,7 @@ impl LocalExec { while num_retries_for_timeout >= 0 { match self.fetcher.multi_get_versioned(objs).await { Ok(objs) => return Ok(objs), - Err(ReplayEngineError::SuiRpcRequestTimeout) => { + Err(ReplayEngineError::IotaRpcRequestTimeout) => { warn!( "RPC request timed out. Retries left {}. Sleeping for {}s", num_retries_for_timeout, @@ -276,7 +277,7 @@ impl LocalExec { Err(e) => return Err(e), } } - Err(ReplayEngineError::SuiRpcRequestTimeout) + Err(ReplayEngineError::IotaRpcRequestTimeout) } /// Wrapper around fetcher in case we want to add more functionality /// Such as fetching from local DB from snapshot @@ -288,7 +289,7 @@ impl LocalExec { while num_retries_for_timeout >= 0 { match self.fetcher.multi_get_latest(objs).await { Ok(objs) => return Ok(objs), - Err(ReplayEngineError::SuiRpcRequestTimeout) => { + Err(ReplayEngineError::IotaRpcRequestTimeout) => { warn!( "RPC request timed out. Retries left {}. Sleeping for {}s", num_retries_for_timeout, @@ -300,7 +301,7 @@ impl LocalExec { Err(e) => return Err(e), } } - Err(ReplayEngineError::SuiRpcRequestTimeout) + Err(ReplayEngineError::IotaRpcRequestTimeout) } pub async fn fetch_loaded_child_refs( @@ -313,7 +314,7 @@ impl LocalExec { pub async fn new_from_fn_url(http_url: &str) -> Result { Self::new_for_remote( - SuiClientBuilder::default() + IotaClientBuilder::default() .request_timeout(RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD) .max_concurrent_requests(MAX_CONCURRENT_REQUESTS) .build(http_url) @@ -371,7 +372,7 @@ impl LocalExec { .await { Ok(exec_state) => Ok(exec_state), - Err(e) => Err(ReplayEngineError::SuiRpcError { + Err(e) => Err(ReplayEngineError::IotaRpcError { err: format!( "Failed to execute transaction with provided RPC URL: Error {}", e @@ -434,7 +435,7 @@ impl LocalExec { } pub async fn new_for_remote( - client: SuiClient, + client: IotaClient, remote_fetcher: Option, ) -> Result { // Use a throwaway metrics registry for local execution. @@ -476,7 +477,7 @@ impl LocalExec { Some(url) => NodeStateDumpFetcher::new( state, Some(RemoteFetcher::new( - SuiClientBuilder::default() + IotaClientBuilder::default() .request_timeout(RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD) .max_concurrent_requests(MAX_CONCURRENT_REQUESTS) .build(url) @@ -648,7 +649,7 @@ impl LocalExec { error!("Object {id} {version} {digest} was deleted on RPC server."); Ok(None) } - Err(err) => Err(ReplayEngineError::SuiRpcError { + Err(err) => Err(ReplayEngineError::IotaRpcError { err: err.to_string(), }), } @@ -661,7 +662,7 @@ impl LocalExec { self.fetcher .get_checkpoint_txs(checkpoint_id) .await - .map_err(|e| ReplayEngineError::SuiRpcError { err: e.to_string() }) + .map_err(|e| ReplayEngineError::IotaRpcError { err: e.to_string() }) } pub async fn execute_all_in_checkpoints( @@ -714,7 +715,8 @@ impl LocalExec { ) -> Result { let tx_digest = &tx_info.tx_digest; // A lot of the logic here isnt designed for genesis - if *tx_digest == TransactionDigest::genesis_marker() || tx_info.sender == SuiAddress::ZERO { + if *tx_digest == TransactionDigest::genesis_marker() || tx_info.sender == IotaAddress::ZERO + { // Genesis. warn!( "Genesis/system TX replay not supported: {}, skipping transaction", @@ -772,7 +774,7 @@ impl LocalExec { let transaction_kind = override_transaction_kind.unwrap_or(tx_info.kind.clone()); let certificate_deny_set = HashSet::new(); let (inner_store, gas_status, effects, result) = if let Ok(gas_status) = - SuiGasStatus::new(tx_info.gas_budget, tx_info.gas_price, rgp, protocol_config) + IotaGasStatus::new(tx_info.gas_budget, tx_info.gas_price, rgp, protocol_config) { executor.execute_transaction_to_effects( &self, @@ -812,7 +814,7 @@ impl LocalExec { epoch_start_timestamp, CheckedInputObjects::new_for_replay(input_objects), tx_info.gas.clone(), - SuiGasStatus::new(tx_info.gas_budget, tx_info.gas_price, rgp, protocol_config)?, + IotaGasStatus::new(tx_info.gas_budget, tx_info.gas_price, rgp, protocol_config)?, transaction_kind.clone(), tx_info.sender, *tx_digest, @@ -823,7 +825,7 @@ impl LocalExec { let all_required_objects = self.storage.all_objects(); let effects = - SuiTransactionBlockEffects::try_from(effects).map_err(ReplayEngineError::from)?; + IotaTransactionBlockEffects::try_from(effects).map_err(ReplayEngineError::from)?; Ok(ExecutionSandboxState { transaction_info: tx_info.clone(), @@ -895,7 +897,7 @@ impl LocalExec { .sender_signed_data .intent_message() .intent, - Intent::sui_transaction() + Intent::iota_transaction() ); let transaction_signatures = pre_run_sandbox .transaction_info @@ -978,7 +980,7 @@ impl LocalExec { None => Ok(()), }; let effects = - SuiTransactionBlockEffects::try_from(res.0).map_err(ReplayEngineError::from)?; + IotaTransactionBlockEffects::try_from(res.0).map_err(ReplayEngineError::from)?; Ok(ExecutionSandboxState { transaction_info: pre_run_sandbox.transaction_info.clone(), @@ -992,7 +994,7 @@ impl LocalExec { /// Must be called after `init_for_execution` /// This executes from - /// `sui_core::authority::AuthorityState::try_execute_immediately` + /// `iota_core::authority::AuthorityState::try_execute_immediately` pub async fn certificate_execute( &mut self, tx_digest: &TransactionDigest, @@ -1007,7 +1009,7 @@ impl LocalExec { /// Must be called after `init_for_execution` /// This executes from - /// `sui_adapter::execution_engine::execute_transaction_to_effects` + /// `iota_adapter::execution_engine::execute_transaction_to_effects` pub async fn execution_engine_execute( &mut self, tx_digest: &TransactionDigest, @@ -1483,9 +1485,9 @@ impl LocalExec { // Fetch full transaction content let tx_info = self.fetcher.get_transaction(tx_digest).await?; let sender = match tx_info.clone().transaction.unwrap().data { - sui_json_rpc_types::SuiTransactionBlockData::V1(tx) => tx.sender, + iota_json_rpc_types::IotaTransactionBlockData::V1(tx) => tx.sender, }; - let SuiTransactionBlockEffects::V1(effects) = tx_info.clone().effects.unwrap(); + let IotaTransactionBlockEffects::V1(effects) = tx_info.clone().effects.unwrap(); let raw_tx_bytes = tx_info.clone().raw_transaction; let orig_tx: SenderSignedData = bcs::from_bytes(&raw_tx_bytes).unwrap(); @@ -1512,7 +1514,7 @@ impl LocalExec { }) .collect(); let gas_data = match tx_info.clone().transaction.unwrap().data { - sui_json_rpc_types::SuiTransactionBlockData::V1(tx) => tx.gas_data, + iota_json_rpc_types::IotaTransactionBlockData::V1(tx) => tx.gas_data, }; let gas_object_refs: Vec<_> = gas_data .payment @@ -1538,7 +1540,7 @@ impl LocalExec { gas_price: gas_data.price, executed_epoch: epoch_id, dependencies: effects.dependencies().to_vec(), - effects: SuiTransactionBlockEffects::V1(effects), + effects: IotaTransactionBlockEffects::V1(effects), // Find the protocol version for this epoch // This assumes we already initialized the protocol version table // `protocol_version_epoch_table` @@ -1566,7 +1568,7 @@ impl LocalExec { .sender(); let orig_tx = dp.node_state_dump.sender_signed_data.clone(); let effects = dp.node_state_dump.computed_effects.clone(); - let effects = SuiTransactionBlockEffects::try_from(effects).unwrap(); + let effects = IotaTransactionBlockEffects::try_from(effects).unwrap(); // Fetch full transaction content // let tx_info = self.fetcher.get_transaction(tx_digest).await?; @@ -1809,12 +1811,12 @@ impl BackingPackageStore for LocalExec { /// In this case we might need to download a dependency package which was /// not present in the modified at versions list because packages are /// immutable - fn get_package_object(&self, package_id: &ObjectID) -> SuiResult> { - fn inner(self_: &LocalExec, package_id: &ObjectID) -> SuiResult> { + fn get_package_object(&self, package_id: &ObjectID) -> IotaResult> { + fn inner(self_: &LocalExec, package_id: &ObjectID) -> IotaResult> { // If package not present fetch it from the network self_ .get_or_download_object(package_id, true /* we expect a Move package */) - .map_err(|e| SuiError::Storage(e.to_string())) + .map_err(|e| IotaError::Storage(e.to_string())) } let res = inner(self, package_id); @@ -1837,27 +1839,27 @@ impl ChildObjectResolver for LocalExec { parent: &ObjectID, child: &ObjectID, child_version_upper_bound: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { fn inner( self_: &LocalExec, parent: &ObjectID, child: &ObjectID, child_version_upper_bound: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { let child_object = match self_.get_object(child)? { None => return Ok(None), Some(o) => o, }; let child_version = child_object.version(); if child_object.version() > child_version_upper_bound { - return Err(SuiError::Unknown(format!( + return Err(IotaError::Unknown(format!( "Invariant Violation. Replay loaded child_object {child} at version \ {child_version} but expected the version to be <= {child_version_upper_bound}" ))); } let parent = *parent; if child_object.owner != Owner::ObjectOwner(parent.into()) { - return Err(SuiError::InvalidChildObjectAccess { + return Err(IotaError::InvalidChildObjectAccess { object: *child, given_parent: parent, actual_owner: child_object.owner, @@ -1886,19 +1888,19 @@ impl ChildObjectResolver for LocalExec { receiving_object_id: &ObjectID, receive_object_at_version: SequenceNumber, _epoch_id: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { fn inner( self_: &LocalExec, owner: &ObjectID, receiving_object_id: &ObjectID, receive_object_at_version: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { let recv_object = match self_.get_object(receiving_object_id)? { None => return Ok(None), Some(o) => o, }; if recv_object.version() != receive_object_at_version { - return Err(SuiError::Unknown(format!( + return Err(IotaError::Unknown(format!( "Invariant Violation. Replay loaded child_object {receiving_object_id} at version \ {receive_object_at_version} but expected the version to be == {receive_object_at_version}" ))); @@ -1929,8 +1931,8 @@ impl ParentSync for LocalExec { fn get_latest_parent_entry_ref_deprecated( &self, object_id: ObjectID, - ) -> SuiResult> { - fn inner(self_: &LocalExec, object_id: ObjectID) -> SuiResult> { + ) -> IotaResult> { + fn inner(self_: &LocalExec, object_id: ObjectID) -> IotaResult> { if let Some(v) = self_.storage.live_objects_store.get(&object_id) { return Ok(Some(v.compute_object_reference())); } @@ -1951,7 +1953,7 @@ impl ParentSync for LocalExec { } impl ResourceResolver for LocalExec { - type Error = SuiError; + type Error = IotaError; /// In this case we might need to download a Move object on the fly which /// was not present in the modified at versions list because packages @@ -1960,12 +1962,12 @@ impl ResourceResolver for LocalExec { &self, address: &AccountAddress, typ: &StructTag, - ) -> SuiResult>> { + ) -> IotaResult>> { fn inner( self_: &LocalExec, address: &AccountAddress, typ: &StructTag, - ) -> SuiResult>> { + ) -> IotaResult>> { // If package not present fetch it from the network or some remote location let Some(object) = self_.get_or_download_object( &ObjectID::from(*address), @@ -2005,12 +2007,12 @@ impl ResourceResolver for LocalExec { } impl ModuleResolver for LocalExec { - type Error = SuiError; + type Error = IotaError; /// This fetches a module which must already be present in the store /// We do not download - fn get_module(&self, module_id: &ModuleId) -> SuiResult>> { - fn inner(self_: &LocalExec, module_id: &ModuleId) -> SuiResult>> { + fn get_module(&self, module_id: &ModuleId) -> IotaResult>> { + fn inner(self_: &LocalExec, module_id: &ModuleId) -> IotaResult>> { get_module(self_, module_id) } @@ -2027,9 +2029,9 @@ impl ModuleResolver for LocalExec { } impl ModuleResolver for &mut LocalExec { - type Error = SuiError; + type Error = IotaError; - fn get_module(&self, module_id: &ModuleId) -> SuiResult>> { + fn get_module(&self, module_id: &ModuleId) -> IotaResult>> { // Recording event here will be double-counting since its already recorded in // the get_module fn (**self).get_module(module_id) @@ -2042,7 +2044,7 @@ impl ObjectStore for LocalExec { fn get_object( &self, object_id: &ObjectID, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { let res = self.storage.live_objects_store.get(object_id).cloned(); self.exec_store_events .lock() @@ -2060,7 +2062,7 @@ impl ObjectStore for LocalExec { &self, object_id: &ObjectID, version: VersionNumber, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { let res = self .storage .live_objects_store @@ -2090,7 +2092,7 @@ impl ObjectStore for &mut LocalExec { fn get_object( &self, object_id: &ObjectID, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { // Recording event here will be double-counting since its already recorded in // the get_module fn (**self).get_object(object_id) @@ -2100,7 +2102,7 @@ impl ObjectStore for &mut LocalExec { &self, object_id: &ObjectID, version: VersionNumber, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { // Recording event here will be double-counting since its already recorded in // the get_module fn (**self).get_object_by_key(object_id, version) @@ -2108,10 +2110,10 @@ impl ObjectStore for &mut LocalExec { } impl GetModule for LocalExec { - type Error = SuiError; + type Error = IotaError; type Item = CompiledModule; - fn get_module_by_id(&self, id: &ModuleId) -> SuiResult> { + fn get_module_by_id(&self, id: &ModuleId) -> IotaResult> { let res = get_module_by_id(self, id); self.exec_store_events @@ -2148,7 +2150,7 @@ pub fn get_executor( .unwrap_or(protocol_config.clone()); let silent = true; - sui_execution::executor(&protocol_config, silent, enable_profiler) + iota_execution::executor(&protocol_config, silent, enable_profiler) .expect("Creating an executor should not fail here") } diff --git a/crates/iota-replay/src/tests.rs b/crates/iota-replay/src/tests.rs new file mode 100644 index 00000000000..8b1c6f180c4 --- /dev/null +++ b/crates/iota-replay/src/tests.rs @@ -0,0 +1,175 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_config::node::ExpensiveSafetyCheckConfig; +use iota_json_rpc_api::QUERY_MAX_RESULT_LIMIT; +use iota_json_rpc_types::IotaTransactionBlockResponseOptions; +use iota_sdk::{IotaClient, IotaClientBuilder}; +use iota_types::{base_types::IotaAddress, digests::TransactionDigest}; + +use crate::{ + config::ReplayableNetworkConfigSet, + types::{ReplayEngineError, MAX_CONCURRENT_REQUESTS, RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD}, + LocalExec, +}; + +/// Keep searching for non-system TXs in the checkppints for this long +/// Very unlikely to take this long, but we want to be sure we find one +const NUM_CHECKPOINTS_TO_ATTEMPT: usize = 1_000; + +/// Checks that replaying the latest tx on each testnet and mainnet does not +/// fail +#[ignore] +#[tokio::test] +async fn verify_latest_tx_replay_testnet_mainnet() { + let _ = verify_latest_tx_replay_impl().await; +} +async fn verify_latest_tx_replay_impl() { + let default_cfg = ReplayableNetworkConfigSet::default(); + let urls: Vec<_> = default_cfg + .base_network_configs + .iter() + .filter(|q| q.name != "devnet") // Devnet is not always stable + .map(|c| c.public_full_node.clone()) + .collect(); + + let mut handles = vec![]; + for url in urls { + handles.push(tokio::spawn(async move { + { + let mut num_checkpoint_trials_left = NUM_CHECKPOINTS_TO_ATTEMPT; + let rpc_client = IotaClientBuilder::default() + .request_timeout(RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD) + .max_concurrent_requests(MAX_CONCURRENT_REQUESTS) + .build(&url) + .await + .unwrap(); + + let chain_id = rpc_client.read_api().get_chain_identifier().await.unwrap(); + + let mut subject_checkpoint = rpc_client + .read_api() + .get_latest_checkpoint_sequence_number() + .await + .unwrap(); + let txs = rpc_client + .read_api() + .get_checkpoint(subject_checkpoint.into()) + .await + .unwrap() + .transactions; + + let mut non_system_txs = extract_one_system_tx(&rpc_client, txs).await; + num_checkpoint_trials_left -= 1; + while non_system_txs.is_none() && num_checkpoint_trials_left > 0 { + num_checkpoint_trials_left -= 1; + subject_checkpoint -= 1; + let txs = rpc_client + .read_api() + .get_checkpoint(subject_checkpoint.into()) + .await + .unwrap() + .transactions; + non_system_txs = extract_one_system_tx(&rpc_client, txs).await; + } + + if non_system_txs.is_none() { + panic!( + "No non-system txs found in the last {} checkpoints for network {} using rpc url {}", + NUM_CHECKPOINTS_TO_ATTEMPT, chain_id, url + ); + } + let tx: TransactionDigest = non_system_txs.unwrap(); + (url.clone(), execute_replay(&url, &tx) + .await + ) + } + })); + } + + let rets = futures::future::join_all(handles) + .await + .into_iter() + .collect::, _>>() + .expect("Join all failed"); + + for (url, ret) in rets { + if let Err(e) = ret { + panic!("Replay failed for network {} with error {:?}", url, e); + } + } +} + +async fn extract_one_system_tx( + rpc_client: &IotaClient, + mut txs: Vec, +) -> Option { + let opts = IotaTransactionBlockResponseOptions::full_content(); + txs.retain(|q| *q != TransactionDigest::genesis_marker()); + + for ch in txs.chunks(*QUERY_MAX_RESULT_LIMIT) { + match rpc_client + .read_api() + .multi_get_transactions_with_options(ch.to_vec(), opts.clone()) + .await + .unwrap() + .into_iter() + .filter_map(|x| { + if match x.transaction.unwrap().data { + iota_json_rpc_types::IotaTransactionBlockData::V1(tx) => tx.sender, + } != IotaAddress::ZERO + { + Some(x.digest) + } else { + None + } + }) + .next() + { + Some(tx) => { + tokio::task::yield_now().await; + return Some(tx); + } + None => { + continue; + } + } + } + None +} + +async fn execute_replay(url: &str, tx: &TransactionDigest) -> Result<(), ReplayEngineError> { + LocalExec::new_from_fn_url(url) + .await? + .init_for_execution() + .await? + .execute_transaction( + tx, + ExpensiveSafetyCheckConfig::default(), + true, + None, + None, + None, + ) + .await? + .check_effects()?; + tokio::task::yield_now().await; + LocalExec::new_from_fn_url(url) + .await? + .init_for_execution() + .await? + .execute_transaction( + tx, + ExpensiveSafetyCheckConfig::default(), + false, + None, + None, + None, + ) + .await? + .check_effects()?; + tokio::task::yield_now().await; + + Ok(()) +} diff --git a/crates/sui-replay/src/transaction_provider.rs b/crates/iota-replay/src/transaction_provider.rs similarity index 97% rename from crates/sui-replay/src/transaction_provider.rs rename to crates/iota-replay/src/transaction_provider.rs index 6fb0a4128f5..055ee99b719 100644 --- a/crates/sui-replay/src/transaction_provider.rs +++ b/crates/iota-replay/src/transaction_provider.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -7,8 +8,8 @@ use std::{ str::FromStr, }; -use sui_sdk::SuiClientBuilder; -use sui_types::digests::TransactionDigest; +use iota_sdk::IotaClientBuilder; +use iota_types::digests::TransactionDigest; use tracing::info; use crate::{ @@ -83,7 +84,7 @@ impl TransactionProvider { pub async fn new(http_url: &str, source: TransactionSource) -> Result { Ok(Self { fetcher: RemoteFetcher::new( - SuiClientBuilder::default() + IotaClientBuilder::default() .request_timeout(RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD) .max_concurrent_requests(MAX_CONCURRENT_REQUESTS) .build(http_url) diff --git a/crates/iota-replay/src/types.rs b/crates/iota-replay/src/types.rs new file mode 100644 index 00000000000..8f5e89c4d5f --- /dev/null +++ b/crates/iota-replay/src/types.rs @@ -0,0 +1,301 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt::Debug; + +use iota_json_rpc_types::{IotaEvent, IotaTransactionBlockEffects}; +use iota_protocol_config::{Chain, ProtocolVersion}; +use iota_sdk::error::Error as IotaRpcError; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber, VersionNumber}, + digests::{ObjectDigest, TransactionDigest}, + error::{IotaError, IotaObjectResponseError, IotaResult, UserInputError}, + object::Object, + transaction::{InputObjectKind, SenderSignedData, TransactionKind}, +}; +use jsonrpsee::core::Error as JsonRpseeError; +use move_binary_format::CompiledModule; +use move_core_types::{ + account_address::AccountAddress, + language_storage::{ModuleId, StructTag}, +}; +use serde::{Deserialize, Serialize}; +use thiserror::Error; +use tokio::time::Duration; +use tracing::{error, warn}; + +use crate::config::ReplayableNetworkConfigSet; + +// TODO: make these configurable +pub(crate) const RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD: Duration = Duration::from_millis(100_000); +pub(crate) const RPC_TIMEOUT_ERR_NUM_RETRIES: u32 = 3; +pub(crate) const MAX_CONCURRENT_REQUESTS: usize = 1_000; + +// Struct tag used in system epoch change events +pub(crate) const EPOCH_CHANGE_STRUCT_TAG: &str = + "0x3::iota_system_state_inner::SystemEpochInfoEvent"; + +pub(crate) const ONE_DAY_MS: u64 = 24 * 60 * 60 * 1000; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct OnChainTransactionInfo { + pub tx_digest: TransactionDigest, + pub sender_signed_data: SenderSignedData, + pub sender: IotaAddress, + pub input_objects: Vec, + pub kind: TransactionKind, + pub modified_at_versions: Vec<(ObjectID, SequenceNumber)>, + pub shared_object_refs: Vec, + pub gas: Vec<(ObjectID, SequenceNumber, ObjectDigest)>, + pub gas_budget: u64, + pub gas_price: u64, + pub executed_epoch: u64, + pub dependencies: Vec, + pub effects: IotaTransactionBlockEffects, + pub protocol_version: ProtocolVersion, + pub epoch_start_timestamp: u64, + pub reference_gas_price: u64, + #[serde(default = "unspecified_chain")] + pub chain: Chain, +} + +fn unspecified_chain() -> Chain { + warn!("Unable to determine chain id. Defaulting to unknown"); + Chain::Unknown +} + +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct DiagInfo { + pub loaded_child_objects: Vec<(ObjectID, VersionNumber)>, +} + +#[allow(clippy::large_enum_variant)] +#[derive(Debug, Error, Clone)] +pub enum ReplayEngineError { + #[error("IotaError: {:#?}", err)] + IotaError { err: IotaError }, + + #[error("IotaRpcError: {:#?}", err)] + IotaRpcError { err: String }, + + #[error("IotaObjectResponseError: {:#?}", err)] + IotaObjectResponseError { err: IotaObjectResponseError }, + + #[error("UserInputError: {:#?}", err)] + UserInputError { err: UserInputError }, + + #[error("GeneralError: {:#?}", err)] + GeneralError { err: String }, + + #[error("IotaRpcRequestTimeout")] + IotaRpcRequestTimeout, + + #[error("ObjectNotExist: {:#?}", id)] + ObjectNotExist { id: ObjectID }, + + #[error("ObjectVersionNotFound: {:#?} version {}", id, version)] + ObjectVersionNotFound { + id: ObjectID, + version: SequenceNumber, + }, + + #[error( + "ObjectVersionTooHigh: {:#?}, requested version {}, latest version found {}", + id, + asked_version, + latest_version + )] + ObjectVersionTooHigh { + id: ObjectID, + asked_version: SequenceNumber, + latest_version: SequenceNumber, + }, + + #[error( + "ObjectDeleted: {:#?} at version {:#?} digest {:#?}", + id, + version, + digest + )] + ObjectDeleted { + id: ObjectID, + version: SequenceNumber, + digest: ObjectDigest, + }, + + #[error( + "EffectsForked: Effects for digest {} forked with diff {}", + digest, + diff + )] + EffectsForked { + digest: TransactionDigest, + diff: String, + on_chain: Box, + local: Box, + }, + + #[error("Genesis replay not supported digest {:#?}", digest)] + GenesisReplayNotSupported { digest: TransactionDigest }, + + #[error( + "Fatal! No framework versions for protocol version {protocol_version}. Make sure version tables are populated" + )] + FrameworkObjectVersionTableNotPopulated { protocol_version: u64 }, + + #[error("Protocol version not found for epoch {epoch}")] + ProtocolVersionNotFound { epoch: u64 }, + + #[error("Error querying system events for epoch {epoch}")] + ErrorQueryingSystemEvents { epoch: u64 }, + + #[error("Invalid epoch change transaction in events for epoch {epoch}")] + InvalidEpochChangeTx { epoch: u64 }, + + #[error("Unexpected event format {:#?}", event)] + UnexpectedEventFormat { event: IotaEvent }, + + #[error("Unable to find event for epoch {epoch}")] + EventNotFound { epoch: u64 }, + + #[error("Unable to find checkpoints for epoch {epoch}")] + UnableToDetermineCheckpoint { epoch: u64 }, + + #[error("Unable to query system events; {}", rpc_err)] + UnableToQuerySystemEvents { rpc_err: String }, + + #[error("Internal error or cache corrupted! Object {id}{} should be in cache.", version.map(|q| format!(" version {:#?}", q)).unwrap_or_default() )] + InternalCacheInvariantViolation { + id: ObjectID, + version: Option, + }, + + #[error("Error getting dynamic fields loaded objects: {}", rpc_err)] + UnableToGetDynamicFieldLoadedObjects { rpc_err: String }, + + #[error("Unsupported epoch in replay engine: {epoch}")] + EpochNotSupported { epoch: u64 }, + + #[error("Unable to open yaml cfg file at {}: {}", path, err)] + UnableToOpenYamlFile { path: String, err: String }, + + #[error("Unable to write yaml file at {}: {}", path, err)] + UnableToWriteYamlFile { path: String, err: String }, + + #[error("Unable to convert string {} to URL {}", url, err)] + InvalidUrl { url: String, err: String }, + + #[error( + "Unable to execute transaction with existing network configs {:#?}", + cfgs + )] + UnableToExecuteWithNetworkConfigs { cfgs: ReplayableNetworkConfigSet }, + + #[error("Unable to get chain id: {}", err)] + UnableToGetChainId { err: String }, +} + +impl From for ReplayEngineError { + fn from(err: IotaObjectResponseError) -> Self { + match err { + IotaObjectResponseError::NotExists { object_id } => { + ReplayEngineError::ObjectNotExist { id: object_id } + } + IotaObjectResponseError::Deleted { + object_id, + digest, + version, + } => ReplayEngineError::ObjectDeleted { + id: object_id, + version, + digest, + }, + _ => ReplayEngineError::IotaObjectResponseError { err }, + } + } +} + +impl From for IotaError { + fn from(err: ReplayEngineError) -> Self { + IotaError::Unknown(format!("{:#?}", err)) + } +} + +impl From for ReplayEngineError { + fn from(err: IotaError) -> Self { + ReplayEngineError::IotaError { err } + } +} +impl From for ReplayEngineError { + fn from(err: IotaRpcError) -> Self { + match err { + IotaRpcError::RpcError(JsonRpseeError::RequestTimeout) => { + ReplayEngineError::IotaRpcRequestTimeout + } + _ => ReplayEngineError::IotaRpcError { + err: format!("{:?}", err), + }, + } + } +} + +impl From for ReplayEngineError { + fn from(err: UserInputError) -> Self { + ReplayEngineError::UserInputError { err } + } +} + +impl From for ReplayEngineError { + fn from(err: anyhow::Error) -> Self { + ReplayEngineError::GeneralError { + err: format!("{:#?}", err), + } + } +} + +/// TODO: Limited set but will add more +#[derive(Debug)] +pub enum ExecutionStoreEvent { + BackingPackageGetPackageObject { + package_id: ObjectID, + result: IotaResult>, + }, + ChildObjectResolverStoreReadChildObject { + parent: ObjectID, + child: ObjectID, + result: IotaResult>, + }, + ParentSyncStoreGetLatestParentEntryRef { + object_id: ObjectID, + result: IotaResult>, + }, + ResourceResolverGetResource { + address: AccountAddress, + typ: StructTag, + result: IotaResult>>, + }, + ModuleResolverGetModule { + module_id: ModuleId, + result: IotaResult>>, + }, + ObjectStoreGetObject { + object_id: ObjectID, + result: IotaResult>, + }, + ObjectStoreGetObjectByKey { + object_id: ObjectID, + version: VersionNumber, + result: IotaResult>, + }, + GetModuleGetModuleByModuleId { + id: ModuleId, + result: IotaResult>, + }, + ReceiveObject { + owner: ObjectID, + receive: ObjectID, + receive_at_version: SequenceNumber, + result: IotaResult>, + }, +} diff --git a/crates/sui-replay/tests/regression_replay.rs b/crates/iota-replay/tests/regression_replay.rs similarity index 85% rename from crates/sui-replay/tests/regression_replay.rs rename to crates/iota-replay/tests/regression_replay.rs index 4c90dbdaf8d..481f5d4194d 100644 --- a/crates/sui-replay/tests/regression_replay.rs +++ b/crates/iota-replay/tests/regression_replay.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::PathBuf; -use sui_replay::{execute_replay_command, ReplayToolCommand}; +use iota_replay::{execute_replay_command, ReplayToolCommand}; #[tokio::test] async fn replay_sandboxes() { diff --git a/crates/iota-replay/tests/sandbox_snapshots/4fxF3X4N8D6JGByWdbJvCCv1iuoT8GSEhXgPHJnzNHWP.json b/crates/iota-replay/tests/sandbox_snapshots/4fxF3X4N8D6JGByWdbJvCCv1iuoT8GSEhXgPHJnzNHWP.json new file mode 100644 index 00000000000..4f15afc5759 --- /dev/null +++ b/crates/iota-replay/tests/sandbox_snapshots/4fxF3X4N8D6JGByWdbJvCCv1iuoT8GSEhXgPHJnzNHWP.json @@ -0,0 +1 @@ +{"transaction_info":{"tx_digest":"4fxF3X4N8D6JGByWdbJvCCv1iuoT8GSEhXgPHJnzNHWP","sender_signed_data":[{"intent_message":{"intent":{"scope":0,"version":0,"app_id":0},"value":{"V1":{"kind":{"ProgrammableTransaction":{"inputs":[{"Object":{"ImmOrOwnedObject":["0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623",10941462,"97EMwmR1yvKzotocnPsNs5gLiHPkDztrM5WsVeE9d1y"]}},{"Pure":[0]},{"Pure":[32,246,193,86,67,237,66,165,149,9,252,108,46,208,117,166,90,184,114,112,210,57,76,234,29,82,22,132,25,179,156,59,27]}],"commands":[{"MoveCall":{"package":"0x0000000000000000000000000000000000000000000000000000000000000002","module":"package","function":"authorize_upgrade","type_arguments":[],"arguments":[{"Input":0},{"Input":1},{"Input":2}]}},{"Upgrade":[[[161,28,235,11,6,0,0,0,7,1,0,2,3,2,30,5,32,6,7,38,34,8,72,32,6,104,50,12,154,1,163,2,0,5,0,0,0,1,0,0,6,0,1,0,0,4,0,1,0,0,1,0,1,0,0,3,0,1,0,0,2,0,1,0,2,15,15,1,15,0,3,97,100,100,3,100,105,118,3,109,105,110,3,109,111,100,3,109,117,108,9,115,97,102,101,95,109,97,116,104,3,115,117,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,233,3,0,0,0,0,0,0,3,8,234,3,0,0,0,0,0,0,3,8,235,3,0,0,0,0,0,0,3,8,236,3,0,0,0,0,0,0,3,8,237,3,0,0,0,0,0,0,0,1,0,0,1,13,10,0,11,1,22,12,2,10,2,11,0,38,4,9,5,11,7,0,39,11,2,2,1,1,0,0,2,11,10,1,10,0,37,4,5,5,7,7,1,39,11,0,11,1,23,2,2,1,0,0,1,21,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,10,1,24,12,2,10,2,11,0,26,11,1,33,4,17,5,19,7,2,39,11,2,2,3,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,5,5,7,7,3,39,11,0,11,1,26,2,4,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,4,39,11,0,11,1,25,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,0],[161,28,235,11,6,0,0,0,9,1,0,10,2,10,16,3,26,47,4,73,12,5,85,63,7,148,1,156,1,8,176,2,64,6,240,2,20,12,132,3,114,0,14,1,3,1,4,1,12,1,13,1,0,4,1,0,1,2,1,12,1,0,1,4,2,2,0,0,10,0,1,1,0,0,11,0,2,1,0,2,5,1,8,1,0,2,6,1,2,1,0,2,9,7,1,1,0,2,15,5,6,1,0,3,7,11,8,1,12,4,8,9,10,0,5,4,4,4,2,4,6,1,0,4,3,4,3,11,1,1,9,0,3,7,8,2,1,11,1,1,9,0,1,11,0,1,9,0,2,3,11,1,1,9,0,1,9,0,1,6,11,1,1,9,0,1,3,3,7,11,1,1,9,0,3,7,8,2,0,1,6,8,2,1,5,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,4,99,111,105,110,12,100,101,115,116,114,111,121,95,122,101,114,111,12,105,110,116,111,95,98,97,108,97,110,99,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,10,115,112,108,105,116,95,99,111,105,110,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,117,116,105,108,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,176,179,0,0,0,0,0,0,3,8,177,179,0,0,0,0,0,0,0,1,0,0,3,44,14,0,56,0,12,3,10,1,6,0,0,0,0,0,0,0,0,36,4,8,5,12,11,2,1,7,0,39,11,3,10,1,38,4,17,5,21,11,2,1,7,1,39,13,0,11,1,10,2,56,1,12,4,14,0,56,0,6,0,0,0,0,0,0,0,0,33,4,37,11,2,1,11,0,56,2,11,4,2,11,0,11,2,46,17,7,56,3,11,4,2,1,1,0,0,8,6,11,0,11,1,11,2,56,4,56,5,2,0],[161,28,235,11,6,0,0,0,14,1,0,18,2,18,54,3,72,145,1,4,217,1,30,5,247,1,203,1,7,194,3,145,4,8,211,7,96,6,179,8,20,10,199,8,67,11,138,9,2,12,140,9,146,3,13,158,12,6,14,164,12,6,15,170,12,4,0,37,1,13,1,47,2,14,2,15,2,23,2,36,2,44,2,46,0,2,12,1,0,1,0,3,12,0,0,5,3,0,0,4,3,0,0,6,3,0,0,7,3,0,1,8,7,0,2,10,7,0,3,0,4,1,0,1,4,1,12,1,0,1,6,11,4,0,8,9,2,0,0,28,0,1,0,0,17,2,1,1,0,0,20,3,1,1,0,0,50,4,1,1,0,0,21,5,1,1,0,0,52,6,1,1,0,0,51,7,1,1,0,0,26,8,9,1,0,0,16,10,11,0,0,35,12,11,1,0,0,48,12,11,1,0,2,25,1,26,1,0,2,30,26,27,0,3,31,25,11,1,0,3,42,29,19,1,0,3,49,32,11,1,0,3,53,1,19,1,0,4,24,30,24,1,0,4,29,24,19,1,0,4,49,23,11,1,0,5,22,18,1,1,3,6,33,0,13,0,7,38,17,1,1,12,7,41,18,1,1,8,8,40,14,15,0,22,16,16,18,23,20,20,21,19,18,18,18,13,18,11,18,20,28,14,18,17,18,20,31,22,24,15,18,7,18,1,7,8,11,0,3,6,8,1,2,7,8,11,3,7,11,0,1,9,0,11,9,1,9,0,7,8,11,4,7,11,0,1,9,0,3,5,7,8,11,2,7,11,0,1,9,0,3,5,7,8,1,7,11,0,1,9,0,3,5,7,8,11,5,6,8,1,7,11,0,1,9,0,3,5,7,8,11,1,6,11,0,1,9,0,1,2,3,3,2,2,1,3,2,6,11,0,1,9,0,3,1,8,10,1,6,8,11,1,5,1,8,1,2,9,0,5,1,9,0,1,11,8,1,9,0,1,11,0,1,9,0,1,8,2,2,11,8,1,9,0,3,1,6,11,9,1,9,0,1,11,9,1,9,0,2,7,11,8,1,9,0,11,8,1,9,0,1,8,7,1,8,6,1,8,4,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,11,1,8,5,1,6,11,8,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,19,80,111,111,108,66,97,108,97,110,99,101,82,101,103,105,115,116,101,114,10,80,111,111,108,67,114,101,97,116,101,11,80,111,111,108,68,101,112,111,115,105,116,12,80,111,111,108,87,105,116,104,100,114,97,119,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,7,99,114,101,97,116,111,114,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,2,105,100,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,7,108,101,110,100,105,110,103,3,110,101,119,10,110,101,119,95,97,109,111,117,110,116,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,9,114,101,99,105,112,105,101,110,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,7,115,116,111,114,97,103,101,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,17,164,0,0,0,0,0,0,3,8,18,164,0,0,0,0,0,0,0,2,4,27,8,10,14,11,8,1,9,0,45,11,8,1,9,0,19,2,1,2,2,27,8,10,18,5,2,2,1,18,5,3,2,4,40,5,12,3,34,3,37,8,6,4,2,3,40,5,12,3,37,8,6,5,2,4,40,5,39,5,12,3,37,8,6,0,18,0,0,0,0,1,11,10,0,17,21,10,0,46,17,24,18,1,11,0,46,17,24,56,0,2,1,3,0,0,1,13,10,2,17,21,56,1,56,1,11,1,57,0,56,2,11,2,46,17,24,18,2,56,3,2,2,3,0,0,22,20,14,1,56,4,12,4,11,1,56,5,12,3,11,0,54,0,11,3,56,6,1,11,2,46,17,24,11,4,56,7,17,12,18,4,56,8,2,3,3,0,0,24,20,11,0,54,0,10,1,56,9,10,3,56,10,12,4,11,3,46,17,24,10,2,11,1,56,7,17,12,18,5,56,11,11,4,11,2,56,12,2,4,3,0,0,19,22,10,0,55,0,56,13,10,1,38,4,7,5,11,11,0,1,7,1,39,10,0,54,0,11,1,56,9,12,2,11,0,54,1,11,2,56,6,1,2,5,1,0,0,1,22,10,1,55,1,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,1,11,2,56,9,11,4,56,10,11,3,56,12,2,6,3,0,0,1,22,10,1,55,0,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,0,11,2,56,9,11,4,56,10,11,3,56,12,2,7,1,0,0,1,4,11,0,55,2,20,2,8,1,0,0,1,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,9,1,0,0,9,8,11,0,56,14,12,2,11,1,11,2,49,9,17,8,2,10,1,0,0,9,8,11,0,56,14,12,2,11,1,49,9,11,2,17,8,2,0,1,0,2,0,3,0,18,1,18,2,18,0,32,0,43,0],[161,28,235,11,6,0,0,0,7,1,0,4,3,4,55,5,59,8,7,67,101,8,168,1,64,6,232,1,200,1,12,176,3,168,5,0,6,1,0,0,4,0,1,0,0,9,0,1,0,0,1,0,1,0,0,2,0,1,0,0,11,2,1,0,0,10,2,1,0,0,7,2,1,0,0,5,2,1,0,0,8,1,1,0,0,12,1,1,0,1,3,0,1,0,0,1,15,2,15,15,1,1,7,97,100,100,114,101,115,115,8,104,97,108,102,95,114,97,121,8,104,97,108,102,95,119,97,100,3,109,97,120,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,10,114,97,121,95,116,111,95,119,97,100,3,119,97,100,7,119,97,100,95,100,105,118,7,119,97,100,95,109,117,108,10,119,97,100,95,116,111,95,114,97,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,100,167,179,182,224,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,178,211,89,91,240,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,77,4,0,0,0,0,0,0,3,8,78,4,0,0,0,0,0,0,3,8,79,4,0,0,0,0,0,0,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,0,2,2,1,0,0,0,2,7,3,2,3,1,0,0,0,2,7,1,2,4,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,1,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,1,22,7,0,26,2,5,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,0,26,37,4,20,5,22,7,5,39,11,0,7,0,24,11,2,22,11,1,26,2,6,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,3,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,3,22,7,2,26,2,7,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,2,26,37,4,20,5,22,7,5,39,11,0,7,2,24,11,2,22,11,1,26,2,8,1,0,0,2,19,7,4,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,1,10,1,11,0,22,12,2,10,2,11,1,38,4,13,5,15,7,6,39,11,2,7,4,26,2,9,1,0,0,1,15,10,0,7,4,24,12,1,10,1,7,4,26,11,0,33,4,11,5,13,7,5,39,11,1,2,0],[161,28,235,11,6,0,0,0,12,1,0,29,2,29,92,3,121,144,3,4,137,4,54,5,191,4,153,3,7,216,7,131,16,8,219,23,96,6,187,24,93,10,152,25,164,1,12,188,26,186,19,13,246,45,66,15,184,46,2,0,120,0,90,0,94,1,22,1,131,1,1,141,1,2,30,2,31,2,47,2,85,2,123,2,127,2,130,1,0,4,12,0,0,11,12,0,0,10,12,0,0,9,4,0,0,20,4,0,0,8,5,0,0,19,5,0,0,15,4,0,0,0,4,0,0,3,4,0,0,12,3,0,0,5,3,0,1,6,12,1,0,1,1,7,12,0,3,13,7,0,4,17,7,0,6,1,8,0,7,2,12,1,0,1,9,18,4,0,10,14,12,2,7,1,4,1,12,16,2,0,0,73,0,1,0,0,144,1,2,1,0,0,143,1,3,1,0,0,74,4,1,1,0,0,115,5,1,0,0,117,6,1,0,0,107,6,1,0,0,112,6,1,0,0,118,6,1,0,0,106,6,1,0,0,113,6,1,0,0,108,6,1,0,0,116,6,1,0,0,114,6,1,0,0,110,6,1,0,0,109,6,1,0,0,111,6,1,0,0,102,2,1,1,0,0,88,2,7,0,0,59,2,8,0,0,64,9,10,0,0,58,11,8,0,0,52,11,12,0,0,60,13,14,0,0,50,13,14,0,0,53,13,15,0,0,55,13,15,0,0,61,13,15,0,0,65,16,15,0,0,56,11,17,0,0,49,11,14,0,0,63,13,14,0,0,62,11,14,0,0,51,13,18,0,0,57,13,19,0,0,133,1,20,1,0,0,134,1,21,1,0,0,68,20,1,0,0,70,22,1,0,0,44,22,1,0,0,69,22,1,0,0,43,22,1,0,0,67,23,1,0,0,42,23,1,0,0,71,24,1,0,0,136,1,16,1,0,0,97,16,1,0,0,135,1,16,1,0,0,96,16,1,0,0,146,1,25,1,1,0,0,45,3,1,0,1,36,43,1,1,0,1,132,1,62,17,1,0,1,145,1,63,1,1,0,2,93,1,14,0,4,48,1,38,1,0,4,75,38,12,0,5,35,57,7,1,0,5,72,57,59,1,0,5,95,60,36,1,0,6,125,40,17,0,7,54,42,8,1,0,8,46,36,1,1,3,9,84,0,26,0,10,21,41,1,2,7,4,10,25,49,50,2,7,4,10,28,46,47,2,7,4,10,35,49,7,2,7,4,10,84,0,33,2,7,4,10,95,46,55,2,7,4,11,91,30,1,1,12,11,119,36,1,1,8,12,105,27,28,0,70,29,70,31,68,32,68,34,71,35,17,36,55,36,68,39,64,32,61,36,51,36,62,44,66,32,65,32,67,34,65,34,67,39,65,39,69,39,64,39,64,34,66,34,57,8,58,8,59,8,52,36,53,36,1,7,8,20,0,1,6,8,2,2,6,8,1,7,8,2,20,6,8,1,6,8,13,6,8,16,7,8,2,2,1,15,15,15,15,15,15,15,15,15,15,15,15,6,11,17,1,9,0,7,8,20,3,6,8,0,7,8,2,1,4,6,8,0,7,8,2,2,15,1,1,1,2,2,6,8,2,5,2,10,2,10,2,2,6,8,2,2,1,8,14,2,7,8,2,2,1,15,2,15,15,3,7,8,2,2,5,1,3,5,15,15,15,15,15,3,15,15,15,4,7,8,2,2,15,15,6,7,8,2,2,15,15,3,15,4,7,8,2,2,5,15,3,7,8,7,5,15,3,7,8,2,2,15,8,6,8,1,6,8,13,7,8,2,2,7,11,12,1,9,0,3,5,7,8,20,1,8,18,1,6,8,20,1,5,1,8,1,2,9,0,5,1,8,0,2,2,8,3,1,11,19,2,9,0,9,1,2,5,8,4,1,8,2,1,9,0,18,2,15,15,15,8,7,8,7,3,8,8,8,9,2,8,14,1,15,15,15,2,2,8,3,1,8,15,2,5,15,1,6,8,16,3,7,11,19,2,9,0,9,1,9,0,9,1,1,6,11,17,1,9,0,3,6,8,13,2,7,8,20,1,8,11,1,7,8,3,2,7,11,19,2,9,0,9,1,9,0,1,7,9,1,3,2,2,8,14,2,6,11,19,2,9,0,9,1,9,0,1,6,9,1,1,6,8,4,1,6,8,3,3,15,6,8,3,15,3,7,8,7,7,8,3,7,8,7,1,9,1,3,10,2,8,4,7,8,4,2,6,10,9,0,6,9,0,2,3,7,8,4,2,1,3,2,7,10,9,0,3,5,2,3,7,15,3,3,2,6,11,12,1,9,0,3,5,6,8,13,7,11,12,1,9,0,3,5,7,8,20,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,12,67,111,105,110,77,101,116,97,100,97,116,97,18,76,105,113,117,105,100,97,116,105,111,110,70,97,99,116,111,114,115,8,79,119,110,101,114,67,97,112,6,80,97,117,115,101,100,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,23,82,101,115,101,114,118,101,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,11,82,101,115,101,114,118,101,68,97,116,97,7,83,116,111,114,97,103,101,15,83,116,111,114,97,103,101,65,100,109,105,110,67,97,112,26,83,116,111,114,97,103,101,67,111,110,102,105,103,117,114,97,116,111,114,83,101,116,116,105,110,103,6,83,116,114,105,110,103,5,84,97,98,108,101,12,84,111,107,101,110,66,97,108,97,110,99,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,20,85,115,101,114,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,8,85,115,101,114,73,110,102,111,3,97,100,100,5,97,115,99,105,105,9,98,97,115,101,95,114,97,116,101,5,98,111,110,117,115,6,98,111,114,114,111,119,14,98,111,114,114,111,119,95,98,97,108,97,110,99,101,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,5,99,108,111,99,107,4,99,111,105,110,9,99,111,105,110,95,116,121,112,101,11,99,111,108,108,97,116,101,114,97,108,115,12,99,111,110,102,105,103,117,114,97,116,111,114,8,99,111,110,116,97,105,110,115,11,99,114,101,97,116,101,95,112,111,111,108,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,20,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,114,97,116,101,4,100,97,116,97,16,100,101,99,114,101,97,115,101,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,12,100,101,115,116,111,114,121,95,117,115,101,114,4,101,109,105,116,5,101,118,101,110,116,3,103,101,116,13,103,101,116,95,97,115,115,101,116,95,108,116,118,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,13,103,101,116,95,99,111,105,110,95,116,121,112,101,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,12,103,101,116,95,100,101,99,105,109,97,108,115,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,20,103,101,116,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,16,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,114,101,115,101,114,118,101,11,105,110,116,111,95,115,116,114,105,110,103,11,105,115,95,105,115,111,108,97,116,101,100,20,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,5,108,111,97,110,115,5,108,111,103,105,99,3,108,116,118,10,109,117,108,116,105,112,108,105,101,114,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,111,114,97,99,108,101,95,105,100,5,112,97,117,115,101,6,112,97,117,115,101,100,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,105,111,3,114,97,121,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,14,114,101,115,101,114,118,101,95,102,97,99,116,111,114,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,97,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,98,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,99,18,114,101,115,101,114,118,101,95,118,97,108,105,100,97,116,105,111,110,8,114,101,115,101,114,118,101,115,14,114,101,115,101,114,118,101,115,95,99,111,117,110,116,6,115,101,110,100,101,114,13,115,101,116,95,98,97,115,101,95,114,97,116,101,14,115,101,116,95,98,111,114,114,111,119,95,99,97,112,24,115,101,116,95,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,98,111,110,117,115,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,114,97,116,105,111,25,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,7,115,101,116,95,108,116,118,14,115,101,116,95,109,117,108,116,105,112,108,105,101,114,23,115,101,116,95,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,115,101,116,95,112,97,117,115,101,18,115,101,116,95,114,101,115,101,114,118,101,95,102,97,99,116,111,114,14,115,101,116,95,115,117,112,112,108,121,95,99,97,112,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,7,115,116,111,114,97,103,101,14,115,117,112,112,108,121,95,98,97,108,97,110,99,101,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,9,116,104,114,101,115,104,111,108,100,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,9,117,115,101,114,95,105,110,102,111,10,117,115,101,114,95,115,116,97,116,101,5,117,115,101,114,115,5,118,97,108,117,101,6,118,101,99,116,111,114,7,118,101,114,115,105,111,110,15,118,101,114,115,105,111,110,95,109,105,103,114,97,116,101,20,118,101,114,115,105,111,110,95,118,101,114,105,102,105,99,97,116,105,111,110,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,3,0,0,0,0,0,0,0,3,8,248,167,0,0,0,0,0,0,3,8,249,167,0,0,0,0,0,0,3,8,250,167,0,0,0,0,0,0,3,8,251,167,0,0,0,0,0,0,3,8,252,167,0,0,0,0,0,0,3,8,253,167,0,0,0,0,0,0,3,8,254,167,0,0,0,0,0,0,3,8,255,167,0,0,0,0,0,0,2,1,255,0,2,1,66,8,18,1,2,1,66,8,18,2,2,7,66,8,18,142,1,3,89,1,103,11,19,2,2,8,3,104,2,139,1,10,5,137,1,11,19,2,5,8,4,3,2,21,66,2,87,2,32,8,14,76,1,122,15,27,15,40,15,38,15,39,15,37,15,121,8,7,26,8,7,78,3,82,15,129,1,15,128,1,15,29,8,8,79,8,9,99,15,100,15,101,15,4,2,2,33,10,2,80,10,2,5,2,1,41,15,6,2,1,41,15,7,2,2,138,1,11,19,2,5,15,126,15,8,2,5,23,15,83,15,77,15,98,15,86,15,9,2,3,92,15,24,15,124,15,10,2,3,105,5,34,5,140,1,1,11,2,1,89,1,0,0,0,0,1,27,10,0,17,63,18,1,10,0,46,17,72,56,0,10,0,17,63,18,0,10,0,46,17,72,56,1,10,0,17,63,7,0,9,10,0,56,2,49,0,64,28,0,0,0,0,0,0,0,0,11,0,56,3,18,2,56,4,2,1,0,0,0,1,10,11,0,16,0,20,7,0,33,4,7,5,9,7,1,39,2,2,1,4,0,1,16,10,1,16,0,20,7,0,35,4,7,5,11,11,1,1,7,2,39,7,0,11,1,15,0,21,2,3,1,4,0,37,117,10,3,46,17,1,10,3,16,1,20,12,35,10,35,7,9,35,4,12,5,24,11,3,1,11,1,1,11,19,1,11,18,1,11,2,1,7,5,39,10,3,46,56,5,10,3,16,1,20,12,20,11,4,12,29,56,6,17,56,12,30,11,5,12,31,11,6,12,32,11,7,12,33,17,54,12,34,17,54,12,21,11,13,12,22,11,14,12,23,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,24,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,25,11,2,17,60,12,26,11,8,11,10,11,11,11,12,11,9,18,8,12,27,11,15,11,16,11,17,18,9,12,28,11,20,11,29,11,30,11,31,11,32,11,33,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,34,11,21,11,24,11,25,11,26,11,22,11,23,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,27,11,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,12,37,10,3,15,2,10,35,11,37,56,8,11,35,49,1,22,11,3,15,1,21,11,18,56,9,12,36,11,1,11,36,11,19,56,10,2,4,1,4,0,1,11,10,1,46,17,1,10,2,11,1,15,3,21,11,2,18,11,56,11,2,5,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,4,21,2,6,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,5,21,2,7,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,6,21,2,8,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,7,21,2,9,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,9,21,2,10,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,10,21,2,11,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,11,21,2,12,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,12,21,2,13,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,13,21,2,14,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,15,21,2,15,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,16,21,2,16,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,17,21,2,17,1,0,0,48,36,56,6,17,56,12,3,10,0,16,1,20,12,1,49,0,12,2,10,2,10,1,35,4,33,5,14,10,0,16,2,10,2,56,13,16,18,20,10,3,34,4,24,5,28,11,0,1,7,7,39,11,2,49,1,22,12,2,5,9,11,0,1,2,18,1,0,0,1,4,11,0,16,3,20,2,19,1,0,0,1,4,11,0,16,1,20,2,20,1,0,0,51,23,10,0,16,19,10,1,56,14,32,4,11,11,0,1,64,8,0,0,0,0,0,0,0,0,64,8,0,0,0,0,0,0,0,0,2,11,0,16,19,11,1,56,15,12,2,10,2,16,20,20,11,2,16,21,20,2,21,1,0,0,1,7,11,0,16,2,11,1,56,13,16,22,20,2,22,1,0,0,1,7,11,0,16,2,11,1,56,13,16,18,20,2,23,1,0,0,1,7,11,0,16,2,11,1,56,13,16,4,20,2,24,1,0,0,1,7,11,0,16,2,11,1,56,13,16,5,20,2,25,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,23,20,11,2,16,24,20,2,26,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,25,20,11,2,16,26,20,2,27,1,0,0,52,14,11,0,16,2,11,1,56,13,12,2,10,2,16,27,16,28,20,11,2,16,29,16,28,20,2,28,1,0,0,53,41,11,0,16,2,11,1,56,13,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,4,16,27,16,30,10,2,56,16,4,22,10,4,16,27,16,30,10,2,56,17,20,12,5,10,4,16,29,16,30,10,2,56,16,4,36,11,4,16,29,16,30,11,2,56,17,20,12,3,5,38,11,4,1,11,5,11,3,2,29,1,0,0,1,7,11,0,16,2,11,1,56,13,16,31,20,2,30,1,0,0,1,7,11,0,16,2,11,1,56,13,16,6,20,2,31,1,0,0,1,7,11,0,16,2,11,1,56,13,16,7,20,2,32,1,0,0,1,7,11,0,16,2,11,1,56,13,16,32,20,2,33,1,0,0,52,26,11,0,16,2,11,1,56,13,12,2,10,2,16,8,16,9,20,10,2,16,8,16,10,20,10,2,16,8,16,11,20,10,2,16,8,16,12,20,11,2,16,8,16,13,20,2,34,1,0,0,52,18,11,0,16,2,11,1,56,13,12,2,10,2,16,14,16,15,20,10,2,16,14,16,16,20,11,2,16,14,16,17,20,2,35,3,0,0,45,17,10,0,46,17,1,11,0,15,2,11,1,56,12,12,4,11,3,10,4,15,23,21,11,2,11,4,15,24,21,2,36,3,0,0,45,29,10,0,46,17,1,11,0,15,2,11,1,56,12,12,6,11,2,10,6,15,26,21,11,3,10,6,15,25,21,11,4,10,6,15,31,21,10,6,16,32,20,11,5,22,11,6,15,32,21,2,37,3,0,0,54,31,10,0,46,17,1,11,0,15,2,11,1,56,12,12,5,10,5,15,27,12,6,11,5,15,29,12,4,10,6,16,28,20,11,2,22,11,6,15,28,21,10,4,16,28,20,11,3,22,11,4,15,28,21,2,38,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,42,2,39,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,43,2,40,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,42,2,41,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,43,2,42,0,0,0,14,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,0,15,30,11,1,11,3,10,2,22,56,19,10,0,16,28,20,11,2,22,11,0,15,28,21,2,43,0,0,0,14,37,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,3,10,2,38,4,17,5,21,11,0,1,7,6,39,10,0,15,30,11,1,11,3,10,2,23,56,19,10,0,16,28,20,11,2,23,11,0,15,28,21,2,44,3,0,0,45,14,11,0,15,2,11,1,56,12,12,3,10,3,16,32,20,11,2,22,11,3,15,32,21,2,45,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,64,8,0,0,0,0,0,0,0,0,11,3,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,21,14,1,56,22,32,4,37,11,5,15,21,11,1,68,8,5,39,11,5,1,2,46,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,21,14,1,56,23,12,3,4,17,11,4,15,21,11,3,56,24,1,5,19,11,4,1,2,47,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,11,3,64,8,0,0,0,0,0,0,0,0,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,20,14,1,56,22,32,4,37,11,5,15,20,11,1,68,8,5,39,11,5,1,2,48,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,20,14,1,56,23,12,3,4,17,11,4,15,20,11,3,56,24,1,5,19,11,4,1,2,49,1,0,0,61,58,10,2,10,3,12,8,46,11,8,17,22,56,6,17,56,33,4,11,5,21,11,2,1,11,1,1,11,4,1,11,7,1,7,8,39,11,2,15,2,11,3,56,12,15,32,12,10,10,4,10,10,20,52,12,9,46,11,9,56,25,12,11,10,5,12,12,11,5,10,11,35,4,44,11,11,12,12,10,10,20,10,12,77,23,11,10,21,11,1,11,4,11,12,11,6,11,7,56,26,2,50,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,2,1,2,4,2,3,2,2,3,4,3,5,3,13,3,14,3,16,8,0,8,1,8,2,8,3,8,4,3,17,9,0,9,1,9,2,3,2,2,6,4,0,4,1,3,1,3,6,3,7,3,8,3,9,3,10,7,1,3,11,7,0,3,12,3,15,0,81,0],[161,28,235,11,6,0,0,0,8,1,0,12,2,12,12,3,24,75,5,99,67,7,166,1,189,2,8,227,3,96,6,195,4,44,12,239,4,164,5,0,10,0,23,0,21,2,17,1,11,1,16,1,2,12,0,3,1,8,0,4,0,8,0,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,6,3,1,0,0,7,3,1,0,0,9,4,1,0,0,4,4,1,0,1,12,0,8,0,1,13,0,3,0,1,15,0,3,0,2,19,6,1,0,2,20,3,1,0,2,22,3,1,0,3,14,10,11,0,5,18,12,13,0,2,7,8,0,2,1,15,3,7,8,0,2,15,2,15,15,4,6,8,2,6,8,1,15,2,7,15,15,15,15,15,15,15,0,6,15,15,15,15,15,15,5,15,15,15,15,15,2,2,15,3,6,8,2,6,8,1,2,3,1,15,2,2,3,2,1,3,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,20,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,9,103,101,116,95,105,110,100,101,120,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,4,109,97,116,104,6,111,114,97,99,108,101,3,112,111,119,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,153,183,0,0,0,0,0,0,0,1,0,0,5,31,10,0,10,1,17,9,12,7,12,8,11,0,11,1,17,8,12,3,12,4,11,7,11,3,17,12,12,5,11,8,11,4,17,12,12,6,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,29,11,5,11,6,17,11,12,2,11,2,2,1,1,0,0,7,37,10,0,10,1,17,7,12,6,1,12,4,12,5,12,3,11,0,11,1,17,0,12,7,10,7,10,6,35,4,23,11,3,11,7,11,5,17,12,22,12,2,5,35,11,3,10,6,11,5,17,12,22,11,7,11,6,23,11,4,17,12,22,12,2,11,2,2,2,1,0,0,3,20,10,0,10,1,17,7,1,12,3,1,1,1,11,0,11,1,17,0,12,4,11,2,11,4,17,12,17,10,11,3,23,17,12,2,3,1,0,0,5,60,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,17,10,2,10,0,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,5,11,1,7,0,26,12,6,10,6,10,6,17,12,12,3,10,3,10,6,17,12,12,2,10,0,10,4,24,11,3,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,7,10,0,11,4,24,11,5,24,11,2,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,17,10,11,6,11,0,24,22,11,7,22,11,8,22,2,4,1,0,0,6,8,17,10,11,1,11,0,24,7,0,26,22,2,5,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,11,5,24,6,10,0,0,0,0,0,0,0,11,4,17,14,77,26,2,6,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,6,10,0,0,0,0,0,0,0,11,4,17,14,77,24,11,5,26,2,0],[161,28,235,11,6,0,0,0,9,1,0,18,2,18,18,3,36,169,1,4,205,1,4,5,209,1,165,2,7,246,3,149,6,8,139,10,128,1,6,139,11,10,12,149,11,225,14,0,16,0,9,0,38,0,43,0,41,3,37,1,45,2,4,2,10,2,1,12,1,0,1,3,3,12,0,5,2,8,0,8,0,8,0,0,17,0,1,1,0,0,21,2,1,0,0,22,2,1,0,0,20,3,1,0,0,24,3,1,0,0,19,4,1,0,0,23,4,1,0,0,18,5,1,0,0,6,6,7,0,0,13,8,7,1,0,0,14,9,1,0,0,15,10,1,0,0,12,9,1,0,1,5,7,1,0,1,7,7,1,0,1,8,25,1,0,2,36,13,14,1,0,3,25,22,1,0,3,26,28,34,0,3,27,28,7,0,3,28,28,7,0,3,29,22,14,0,3,30,28,29,0,3,31,22,19,0,3,32,28,7,0,3,33,17,18,0,3,34,26,7,0,4,39,15,1,0,4,40,7,1,0,4,42,7,1,0,6,11,20,21,1,0,7,35,15,1,0,8,44,31,14,0,16,12,30,19,9,6,8,3,7,8,1,6,8,2,7,11,0,1,9,0,5,2,3,3,1,1,15,7,6,8,3,6,8,2,7,8,1,5,2,15,1,7,6,8,3,6,8,2,7,8,1,2,5,15,1,6,6,8,3,7,8,1,2,5,15,1,7,6,8,3,7,8,1,6,8,2,5,2,15,1,3,6,8,3,7,8,1,2,2,15,15,7,6,8,3,7,8,1,7,11,0,1,9,0,2,3,3,1,6,6,8,3,7,8,1,2,15,15,1,7,6,8,3,7,8,1,2,15,15,15,1,9,1,3,3,15,15,15,15,3,3,1,9,0,2,6,11,0,1,9,0,3,1,3,0,11,5,2,6,2,10,2,15,10,2,15,3,3,15,15,2,6,8,1,5,2,10,2,10,2,1,2,2,6,10,9,0,6,9,0,1,1,2,6,8,1,2,9,5,6,2,15,3,10,2,3,15,10,2,15,3,2,15,2,4,6,8,3,6,8,2,15,2,3,7,8,1,2,5,11,5,6,2,10,2,15,15,10,2,15,3,3,15,15,2,7,8,1,2,3,15,15,15,10,2,15,15,15,15,3,3,15,15,15,1,6,8,3,7,1,3,3,15,3,3,15,6,15,15,15,15,15,15,5,15,15,15,15,15,7,15,15,15,15,15,15,15,5,67,108,111,99,107,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,23,99,97,108,99,117,108,97,116,101,95,99,117,114,114,101,110,116,95,105,110,100,101,120,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,28,100,121,110,97,109,105,99,95,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,21,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,97,112,121,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,18,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,111,114,21,100,121,110,97,109,105,99,95,104,101,97,108,116,104,95,102,97,99,116,111,114,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,31,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,36,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,30,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,25,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,23,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,3,109,97,120,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,4,112,111,111,108,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,201,175,0,0,0,0,0,0,0,1,0,0,11,99,10,6,6,0,0,0,0,0,0,0,0,36,4,9,10,7,6,0,0,0,0,0,0,0,0,36,12,9,5,11,9,12,9,11,9,32,4,15,5,25,11,1,1,11,3,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,17,10,6,6,0,0,0,0,0,0,0,0,36,4,38,10,3,11,6,12,10,46,11,10,56,0,12,17,6,0,0,0,0,0,0,0,0,12,16,10,7,6,0,0,0,0,0,0,0,0,36,4,52,11,3,11,7,12,11,46,11,11,56,0,12,16,5,54,11,3,1,10,0,10,2,10,1,10,4,10,5,10,17,77,10,8,17,1,12,13,10,0,10,2,10,1,10,4,10,5,11,16,77,10,8,17,2,12,14,11,0,11,1,11,2,11,4,11,5,11,17,77,11,8,17,7,12,15,10,14,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,95,11,13,11,14,17,28,11,15,17,29,12,12,5,97,17,31,12,12,11,12,2,1,1,0,0,16,86,10,2,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,17,6,0,0,0,0,0,0,0,0,12,14,10,12,12,10,14,12,14,4,56,1,32,4,31,10,6,4,31,13,10,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,10,14,10,15,35,4,78,5,36,14,10,10,14,66,19,12,9,10,2,10,9,20,12,8,46,11,8,17,17,12,16,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,9,20,33,4,57,10,5,12,13,10,0,10,1,10,2,11,9,20,10,3,11,13,10,6,17,3,12,11,11,17,11,11,11,16,17,29,22,12,17,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,2,1,11,1,1,11,0,1,11,17,2,2,1,0,0,23,76,10,2,10,3,12,7,46,11,7,17,25,12,14,1,14,14,65,19,12,12,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,6,0,0,0,0,0,0,0,0,12,10,10,14,12,11,14,14,14,4,56,1,32,4,31,10,6,4,31,13,11,10,4,68,19,11,12,6,1,0,0,0,0,0,0,0,22,12,12,10,10,10,12,35,4,68,5,36,14,11,10,10,66,19,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,10,4,10,8,20,33,4,49,10,5,12,9,10,0,10,1,10,2,11,8,20,10,3,11,9,10,6,17,4,12,13,11,15,11,13,22,12,15,11,10,6,1,0,0,0,0,0,0,0,22,12,10,5,31,11,2,1,11,1,1,11,0,1,11,15,2,3,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,5,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,4,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,6,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,5,1,0,0,7,27,10,1,10,2,11,3,17,26,1,12,7,11,5,4,13,11,7,11,4,22,12,7,5,17,11,7,11,4,23,12,7,11,0,11,1,11,2,17,8,1,12,6,11,7,11,6,17,29,2,6,1,0,0,7,27,10,1,10,2,11,3,17,26,12,6,1,11,5,4,13,11,6,11,4,22,12,6,5,17,11,6,11,4,23,12,6,11,0,11,1,11,2,17,8,12,7,1,11,6,11,7,17,29,2,7,1,0,0,27,91,10,1,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,6,0,0,0,0,0,0,0,0,12,14,10,12,12,9,14,12,14,4,56,1,32,4,27,13,9,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,10,14,10,15,35,4,81,5,36,14,9,10,14,66,19,12,8,10,1,10,8,20,17,22,12,16,1,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,8,20,33,4,56,10,5,12,13,10,0,10,2,10,1,11,8,20,10,3,11,13,10,6,17,3,12,17,11,10,10,17,11,16,17,29,22,12,10,11,11,11,17,22,12,11,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,1,1,11,2,1,11,0,1,11,10,11,11,17,28,2,8,1,0,0,30,42,11,0,17,32,12,8,10,1,10,2,12,3,46,11,3,17,21,12,9,10,1,10,2,17,20,12,4,12,6,11,1,11,2,17,19,12,5,12,7,11,8,11,9,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,12,10,12,11,5,17,13,11,4,17,29,12,10,11,12,11,7,17,14,11,6,17,29,12,11,11,10,11,11,2,9,1,0,0,32,76,10,4,6,0,0,0,0,0,0,0,0,36,4,9,10,5,6,0,0,0,0,0,0,0,0,36,12,7,5,11,9,12,7,11,7,32,4,15,5,23,11,1,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,12,10,4,6,0,0,0,0,0,0,0,0,36,4,36,10,2,11,4,12,8,46,11,8,56,0,12,12,6,0,0,0,0,0,0,0,0,12,11,10,5,6,0,0,0,0,0,0,0,0,36,4,50,11,2,11,5,12,9,46,11,9,56,0,12,11,5,52,11,2,1,10,0,10,1,10,3,10,12,77,10,11,77,10,6,17,10,12,10,11,0,11,1,11,3,10,10,11,12,77,11,11,77,11,6,17,11,12,13,11,10,11,13,2,10,1,0,0,33,41,10,1,10,2,17,18,12,10,1,12,8,12,9,12,7,11,0,11,1,11,2,11,3,11,4,11,5,17,12,12,11,10,11,10,10,35,4,27,11,7,11,11,11,9,17,29,22,12,6,5,39,11,7,10,11,11,9,17,29,22,11,11,11,10,23,11,8,17,29,22,12,6,11,6,2,11,1,0,0,7,24,10,1,10,2,17,18,1,12,7,1,1,1,11,0,11,1,11,2,11,4,11,5,11,6,17,12,12,8,11,3,11,8,17,29,17,27,11,7,23,17,29,2,12,1,0,0,35,62,10,1,10,2,17,24,12,11,12,12,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,5,4,16,11,12,11,3,22,12,12,5,20,11,12,11,3,23,12,12,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,35,11,5,4,31,11,11,11,4,22,12,11,5,35,11,11,11,4,23,12,11,11,0,11,1,11,2,17,8,12,7,12,8,11,12,11,8,17,29,12,10,11,11,11,7,17,29,12,9,10,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,56,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,5,60,11,9,11,10,17,28,12,6,11,6,2,0],[161,28,235,11,6,0,0,0,14,1,0,30,2,30,66,3,96,181,1,4,149,2,46,5,195,2,164,3,7,231,5,187,6,8,162,12,96,6,130,13,94,10,224,13,116,11,212,14,2,12,214,14,189,15,13,147,30,40,14,187,30,8,15,195,30,2,0,44,0,72,0,62,0,64,1,18,1,78,2,21,2,26,2,27,2,36,2,53,2,73,2,76,2,77,0,82,0,4,12,1,0,1,0,6,4,0,0,3,12,0,0,7,3,0,0,5,3,0,1,8,12,0,4,9,7,0,5,12,7,0,6,0,4,1,0,1,7,1,8,0,8,2,12,1,0,1,10,13,4,0,11,10,12,2,7,1,4,1,13,11,2,0,0,47,0,1,0,0,67,2,1,0,0,66,2,1,0,0,15,3,1,1,0,0,79,4,1,0,0,24,5,6,0,0,25,7,1,1,0,0,39,8,9,0,0,40,10,11,0,0,33,12,13,0,1,41,46,37,0,1,42,47,37,0,2,60,1,34,0,2,61,37,34,0,3,51,37,34,0,5,38,1,36,1,0,5,48,36,33,0,6,69,49,40,1,0,7,74,32,9,0,8,37,50,51,1,0,9,34,22,1,1,3,10,52,0,14,0,11,14,26,1,2,7,4,11,22,24,45,2,7,4,11,23,27,28,2,7,4,11,29,24,25,2,7,4,11,52,0,18,2,7,4,11,63,27,43,2,7,4,12,58,52,1,1,12,12,68,22,1,1,8,13,65,15,16,0,14,70,39,40,1,0,26,17,26,19,29,21,25,17,22,17,24,17,20,29,20,30,25,19,22,19,24,19,15,22,26,38,31,22,29,41,25,38,27,38,22,38,23,19,23,38,17,22,19,22,28,51,1,7,8,13,0,4,7,8,2,15,1,7,8,13,9,7,8,2,6,8,9,2,3,3,11,10,1,9,0,3,2,7,8,13,5,7,8,2,6,8,9,7,8,5,2,5,5,6,8,2,7,8,5,3,2,5,2,10,15,10,15,6,7,8,2,7,11,0,1,9,0,6,8,9,7,8,5,5,7,8,13,2,6,8,2,2,1,3,3,6,8,2,2,3,4,3,3,15,2,5,6,8,2,7,8,5,6,8,9,2,5,3,10,8,6,10,15,10,2,1,8,11,1,6,8,13,1,5,2,15,1,1,11,12,2,9,0,9,1,2,2,8,1,1,2,1,8,2,1,9,0,1,7,1,2,6,11,12,2,9,0,9,1,9,0,1,1,3,7,11,12,2,9,0,9,1,9,0,9,1,2,7,11,12,2,9,0,9,1,9,0,1,7,9,1,1,8,3,1,8,4,4,1,11,8,1,9,0,3,7,8,1,1,6,8,9,1,8,6,1,15,1,11,12,2,5,15,1,8,7,2,15,15,2,5,15,3,11,10,1,9,0,3,7,8,13,1,11,8,1,9,0,1,11,0,1,9,0,17,7,8,5,3,2,5,5,5,3,3,7,15,15,10,15,7,11,12,2,5,15,3,7,8,1,15,10,15,7,11,12,2,5,15,1,9,1,18,6,11,12,2,5,15,3,3,15,15,10,15,15,6,11,12,2,5,15,3,6,8,1,15,15,3,15,15,15,15,10,15,1,6,9,1,2,7,8,5,2,3,7,8,5,2,5,9,5,15,3,7,8,1,15,15,6,11,12,2,5,15,15,7,11,12,2,5,15,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,13,1,11,10,1,9,0,2,9,0,5,1,6,8,1,10,10,8,6,3,3,3,10,2,6,8,1,10,15,15,6,11,12,2,5,15,10,15,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,9,73,110,99,101,110,116,105,118,101,12,73,110,99,101,110,116,105,118,101,66,97,108,16,80,111,111,108,65,100,109,105,110,83,101,116,116,105,110,103,8,80,111,111,108,73,110,102,111,16,80,111,111,108,79,119,110,101,114,83,101,116,116,105,110,103,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,3,97,100,100,8,97,100,100,95,112,111,111,108,5,97,100,109,105,110,6,97,100,109,105,110,115,5,97,115,99,105,105,5,97,115,115,101,116,6,97,115,115,101,116,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,24,99,97,108,99,95,112,111,111,108,95,117,112,100,97,116,101,95,114,101,119,97,114,100,115,12,99,108,97,105,109,95,114,101,119,97,114,100,5,99,108,111,99,107,4,99,111,105,110,10,99,111,105,110,95,116,121,112,101,115,8,99,111,110,116,97,105,110,115,7,99,114,101,97,116,111,114,11,99,117,114,114,101,110,116,95,105,100,120,18,100,105,115,116,114,105,98,117,116,101,100,95,97,109,111,117,110,116,6,101,97,114,110,101,100,4,101,109,105,116,9,101,110,100,95,116,105,109,101,115,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,14,103,101,116,95,112,111,111,108,95,99,111,117,110,116,13,103,101,116,95,112,111,111,108,95,105,110,102,111,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,9,105,110,99,101,110,116,105,118,101,13,105,110,100,101,120,95,114,101,119,97,114,100,115,19,105,110,100,101,120,95,114,101,119,97,114,100,115,95,112,97,105,100,115,4,105,110,105,116,11,105,110,116,111,95,115,116,114,105,110,103,16,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,7,108,101,110,100,105,110,103,3,109,117,108,3,110,101,119,6,111,98,106,101,99,116,10,111,114,97,99,108,101,95,105,100,115,5,111,119,110,101,114,6,111,119,110,101,114,115,5,112,111,111,108,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,9,115,97,102,101,95,109,97,116,104,6,115,101,110,100,101,114,9,115,101,116,95,97,100,109,105,110,9,115,101,116,95,111,119,110,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,11,115,116,97,114,116,95,116,105,109,101,115,7,115,116,111,114,97,103,101,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,13,116,111,116,97,108,95,115,117,112,112,108,121,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,13,117,112,100,97,116,101,95,114,101,119,97,114,100,16,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,22,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,95,112,97,105,100,115,5,117,116,105,108,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,153,183,0,0,0,0,0,0,3,8,154,183,0,0,0,0,0,0,3,8,155,183,0,0,0,0,0,0,3,8,156,183,0,0,0,0,0,0,3,8,157,183,0,0,0,0,0,0,3,8,158,183,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,43,8,11,19,2,31,3,32,15,21,11,8,1,9,0,1,2,12,43,2,49,3,28,10,8,6,71,10,3,35,10,3,75,10,15,59,10,15,45,10,15,46,10,11,12,2,5,15,80,10,11,12,2,5,15,81,10,11,12,2,5,15,54,10,2,2,2,6,43,8,11,30,5,56,11,12,2,15,1,17,11,12,2,15,1,57,11,12,2,2,8,1,20,10,2,3,2,3,65,5,55,15,83,1,4,2,3,65,5,16,15,83,1,0,22,0,0,0,0,1,15,10,0,17,21,10,0,46,17,30,10,0,56,0,10,0,56,0,11,0,56,1,64,20,0,0,0,0,0,0,0,0,18,2,56,2,2,1,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,1,10,1,56,3,32,4,27,11,0,15,1,10,1,10,2,56,4,5,35,11,0,15,1,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,3,56,6,2,2,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,2,10,1,56,3,32,4,27,11,0,15,2,10,1,10,2,56,4,5,35,11,0,15,2,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,4,56,7,2,3,1,4,0,31,139,1,10,0,16,0,20,10,8,46,17,30,33,4,9,5,17,11,0,1,11,8,1,11,1,1,7,0,39,10,3,11,1,17,18,36,4,27,10,4,10,3,36,12,9,5,29,9,12,9,11,9,4,32,5,38,11,0,1,11,8,1,7,1,39,10,0,16,3,10,2,56,8,32,4,65,10,0,15,3,10,2,10,2,6,0,0,0,0,0,0,0,0,64,33,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,20,0,0,0,0,0,0,0,0,18,1,56,9,10,0,15,4,10,2,68,20,11,0,15,3,10,2,56,10,12,12,10,12,16,5,65,33,12,11,10,12,15,5,56,11,17,16,68,33,10,12,15,6,10,3,68,9,10,12,15,7,10,4,68,9,10,12,15,8,10,6,77,68,34,10,12,15,9,10,6,77,11,4,11,3,23,77,17,13,68,34,10,12,15,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,34,10,12,15,11,10,8,56,12,68,35,10,12,15,12,10,8,56,12,68,35,10,12,15,13,10,8,56,12,68,35,11,12,15,14,11,7,68,20,11,5,11,6,10,8,56,13,12,10,11,8,17,21,11,2,11,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,10,57,0,56,14,2,4,3,0,0,42,118,10,0,16,3,10,3,56,8,4,111,11,1,17,18,12,11,10,0,11,2,10,11,10,3,10,4,12,8,12,7,12,6,12,5,46,11,5,11,6,11,7,11,8,17,5,12,20,12,15,11,0,15,3,11,3,56,10,12,18,11,11,10,18,15,15,21,10,18,16,5,65,33,12,17,6,0,0,0,0,0,0,0,0,12,12,10,12,10,17,35,4,108,5,45,14,15,10,12,66,34,20,12,14,14,20,10,12,66,34,20,12,19,10,18,15,10,10,12,67,34,12,13,10,14,11,13,21,10,18,15,11,10,12,67,35,12,16,10,16,10,4,12,9,46,11,9,56,15,4,79,10,16,10,4,56,16,1,11,16,10,4,11,14,56,17,10,18,15,12,10,12,67,35,12,21,10,21,10,4,12,10,46,11,10,56,15,4,99,10,21,10,4,56,16,1,11,21,10,4,11,19,56,17,11,12,6,1,0,0,0,0,0,0,0,22,12,12,5,40,11,18,1,5,117,11,2,1,11,0,1,11,1,1,2,5,0,0,0,44,166,1,11,0,16,3,10,3,56,18,12,14,10,14,16,5,65,33,12,13,6,0,0,0,0,0,0,0,0,12,7,64,34,0,0,0,0,0,0,0,0,12,10,64,34,0,0,0,0,0,0,0,0,12,22,10,7,10,13,35,4,159,1,5,20,10,14,16,6,10,7,66,9,20,12,17,10,17,10,14,16,15,20,35,4,36,10,14,16,15,20,12,17,10,14,16,7,10,7,66,9,20,12,6,10,2,10,6,35,4,48,10,2,12,6,10,14,16,9,10,7,66,34,20,12,15,10,14,16,10,10,7,66,34,20,12,9,10,17,10,6,35,4,90,11,6,11,17,23,77,12,19,10,1,10,3,17,10,1,12,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,10,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,15,11,19,17,14,11,20,26,12,8,11,9,11,8,22,12,9,13,10,10,9,68,34,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,21,10,4,7,6,34,4,151,1,10,14,16,12,10,7,66,35,12,5,10,5,10,4,56,15,4,114,11,5,10,4,56,19,20,12,21,5,116,11,5,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,14,16,11,10,7,66,35,12,12,10,12,10,4,56,15,4,133,1,11,12,10,4,56,19,20,12,11,5,135,1,11,12,1,10,1,10,3,10,4,17,11,1,12,18,11,9,11,11,23,11,18,24,12,16,11,21,11,16,22,12,21,13,22,11,21,68,34,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,15,11,1,1,11,14,1,11,10,11,22,2,6,1,4,0,48,105,10,0,11,2,11,3,10,1,55,0,20,10,4,17,4,11,0,15,3,10,1,55,0,20,56,10,12,9,10,1,55,1,20,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,9,16,12,10,8,66,35,12,12,10,12,10,4,56,15,4,36,11,12,10,4,56,19,20,12,11,5,38,11,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,9,15,13,10,8,67,35,12,14,10,14,10,4,12,6,46,11,6,56,15,4,56,10,14,10,4,56,16,12,13,11,14,10,4,10,11,56,17,11,11,11,13,23,17,12,26,12,7,11,9,16,8,11,8,66,34,20,12,10,10,1,55,2,20,10,7,22,11,10,37,4,81,5,87,11,5,1,11,1,1,7,4,39,10,1,55,2,20,10,7,22,10,1,54,2,21,11,1,54,3,11,7,52,56,20,11,5,56,21,11,4,56,22,2,7,1,0,0,9,19,6,0,0,0,0,0,0,0,0,12,2,10,0,16,3,10,1,56,8,4,15,11,0,16,3,11,1,56,18,16,5,65,33,12,2,5,17,11,0,1,11,2,2,8,1,0,0,53,47,10,0,16,3,10,1,56,8,4,6,5,10,11,0,1,7,2,39,11,0,16,3,11,1,56,18,12,3,10,3,16,5,65,33,10,2,36,4,22,5,26,11,3,1,7,2,39,10,3,16,6,10,2,66,9,20,10,3,16,7,10,2,66,9,20,10,3,16,9,10,2,66,34,20,11,3,16,14,11,2,66,20,20,2,9,1,0,0,54,97,64,33,0,0,0,0,0,0,0,0,12,5,64,34,0,0,0,0,0,0,0,0,12,14,64,20,0,0,0,0,0,0,0,0,12,9,10,0,16,3,10,3,56,8,4,87,11,2,17,18,12,6,10,0,11,1,11,6,10,3,10,4,17,5,12,11,1,11,0,16,3,11,3,56,18,12,10,10,10,16,5,65,33,12,8,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,84,5,38,10,10,16,13,10,7,66,35,12,13,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,10,13,10,4,56,15,4,55,11,13,10,4,56,19,20,12,12,5,57,11,13,1,13,5,10,10,16,5,10,7,66,33,20,68,33,13,14,14,11,10,7,66,34,20,11,12,23,68,34,13,9,10,10,16,14,10,7,66,20,20,68,20,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,33,11,10,1,5,93,11,1,1,11,0,1,11,2,1,11,5,11,14,11,9,2,2,1,2,2,2,3,2,4,2,5,1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,1,11,1,1,0,1,0,2,0,3,0,4,16,22,17,22,18,22,19,22,0,50,0],[161,28,235,11,6,0,0,0,9,1,0,10,2,10,12,3,22,82,4,104,4,5,108,83,7,191,1,154,2,8,217,3,64,6,153,4,70,12,223,4,237,4,0,22,0,15,0,13,1,3,1,16,1,0,12,0,3,1,7,0,4,2,7,0,0,18,0,1,1,0,0,21,0,1,1,0,0,17,0,1,1,0,0,20,0,1,1,0,0,19,2,1,2,0,0,1,5,8,10,0,1,6,7,6,0,1,7,8,9,0,1,8,8,10,0,1,9,8,9,0,2,11,1,10,0,2,12,9,10,0,2,14,9,10,0,4,4,1,5,1,0,4,10,5,6,0,13,4,13,14,3,7,8,0,2,15,0,4,7,8,0,2,2,15,7,7,8,0,2,15,15,15,15,15,1,9,0,1,8,2,1,8,1,2,6,8,0,2,2,7,8,0,2,2,15,15,1,15,8,7,8,0,2,15,15,15,15,15,15,9,7,8,0,2,15,15,15,15,15,15,15,4,7,8,0,2,7,8,0,2,1,9,1,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,5,97,115,99,105,105,3,103,101,116,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,13,103,101,116,95,99,111,105,110,95,116,121,112,101,9,103,101,116,95,105,110,100,101,120,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,11,105,110,116,111,95,115,116,114,105,110,103,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,9,116,121,112,101,95,110,97,109,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,225,171,0,0,0,0,0,0,3,8,226,171,0,0,0,0,0,0,3,8,227,171,0,0,0,0,0,0,3,8,228,171,0,0,0,0,0,0,3,8,229,171,0,0,0,0,0,0,3,8,230,171,0,0,0,0,0,0,3,8,231,171,0,0,0,0,0,0,0,1,0,0,3,58,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,1,12,8,10,0,10,1,17,7,1,12,5,11,8,11,5,17,12,12,7,11,0,11,1,17,8,12,9,11,7,11,2,22,17,10,24,12,6,11,9,11,6,38,4,55,5,57,7,1,39,2,1,1,0,0,11,54,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,10,11,0,11,1,17,7,12,6,12,7,11,10,11,7,17,12,12,9,11,5,11,6,17,12,12,8,11,9,11,8,11,2,22,38,4,51,5,53,7,3,39,2,2,1,0,0,12,71,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,11,10,0,10,1,17,7,12,6,12,8,11,11,11,8,17,12,12,10,11,5,11,6,17,12,12,9,10,9,10,2,22,10,10,35,4,51,5,55,11,0,1,7,3,39,11,9,11,2,22,11,10,17,11,12,7,11,0,11,1,17,5,11,7,38,4,68,5,70,7,2,39,2,3,1,0,0,8,23,11,0,11,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,15,7,4,39,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,20,5,22,7,0,39,2,4,1,0,0,13,40,10,0,11,1,12,5,12,4,56,0,17,14,11,4,46,11,5,17,6,33,4,13,5,17,11,0,1,7,4,39,11,0,11,2,12,7,12,6,56,1,17,14,11,6,46,11,7,17,6,33,4,30,5,32,7,4,39,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,37,5,39,7,0,39,2,0],[161,28,235,11,6,0,0,0,10,1,0,20,2,20,12,3,32,220,2,4,252,2,12,5,136,3,214,2,7,222,5,205,9,8,171,15,128,1,6,171,16,60,12,231,16,222,18,15,197,35,2,0,42,0,11,0,53,0,73,0,48,0,52,3,45,1,74,2,3,2,12,2,2,12,0,6,1,8,0,9,0,8,0,0,18,0,1,1,0,0,21,2,3,1,0,0,17,2,1,1,0,0,20,2,4,1,0,0,19,5,6,2,0,0,0,57,7,1,0,0,56,8,1,0,0,55,9,1,0,0,36,10,1,0,0,15,10,1,0,0,35,10,1,0,0,14,10,1,0,0,39,11,12,0,0,64,13,14,0,0,63,15,4,0,0,16,15,4,0,0,62,11,4,0,0,65,11,4,0,0,67,16,4,0,0,61,16,4,0,0,60,17,4,0,0,66,17,4,0,0,38,17,12,0,0,40,17,12,0,0,8,18,19,0,1,4,44,4,0,1,5,9,4,0,1,6,22,4,0,1,7,22,4,0,1,9,21,4,0,1,10,44,4,0,2,14,10,1,0,2,15,10,1,0,2,22,31,4,0,2,23,9,32,0,2,24,9,22,0,2,25,9,22,0,2,26,31,3,0,2,27,9,6,0,2,28,31,28,0,2,29,27,28,0,2,30,9,22,0,2,31,9,4,0,2,32,39,40,0,2,33,17,22,0,2,34,34,1,0,2,35,10,1,0,2,36,10,1,0,2,37,21,1,0,2,50,17,1,0,2,51,17,1,0,2,55,34,1,0,2,56,33,1,0,2,58,17,1,0,2,59,17,1,0,3,68,21,1,1,0,3,69,21,1,1,0,3,70,25,1,2,0,0,3,71,21,1,1,0,3,72,21,1,1,0,4,46,1,4,0,4,47,22,4,0,4,49,22,4,0,5,44,22,4,0,7,13,46,12,1,0,8,43,1,4,0,9,54,30,3,0,56,20,59,20,55,20,58,20,57,24,64,28,5,6,8,2,7,8,0,2,5,15,0,6,6,8,2,6,8,1,7,8,0,2,5,15,1,3,1,15,7,6,8,2,6,8,1,7,8,0,5,2,2,15,3,15,15,15,2,6,8,2,7,8,0,3,6,8,2,7,8,0,2,2,7,8,0,2,4,7,8,0,2,5,15,4,6,8,2,6,8,1,7,8,0,5,1,1,4,6,8,2,6,8,1,7,8,0,10,5,1,10,15,4,6,8,2,7,8,0,6,8,1,5,5,6,8,2,6,8,1,7,8,0,2,5,3,7,8,0,2,5,7,6,8,2,7,8,0,6,8,1,5,2,2,15,6,15,15,15,15,15,1,1,9,0,3,7,8,0,2,15,2,15,15,6,15,15,1,15,15,15,2,9,0,9,1,4,7,8,0,2,2,15,2,2,2,1,6,8,0,1,2,18,2,15,15,15,15,3,15,15,3,15,15,15,15,15,15,15,15,15,1,6,8,2,2,6,8,0,2,5,15,15,15,15,15,6,7,8,0,2,15,15,3,15,4,7,8,0,2,15,15,4,15,3,3,10,15,1,5,4,15,15,15,15,9,5,6,2,15,15,10,2,3,3,15,15,2,6,8,0,5,2,10,2,10,2,9,5,2,6,2,15,10,2,3,3,15,15,7,5,6,2,3,3,15,10,2,15,3,2,15,2,4,6,8,2,6,8,1,15,2,2,5,10,2,2,6,10,9,0,6,9,0,18,2,15,15,15,15,1,15,15,15,15,15,2,15,15,15,15,15,15,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,7,105,115,95,108,111,97,110,7,108,101,110,100,105,110,103,5,108,111,103,105,99,3,109,97,120,3,109,105,110,6,111,114,97,99,108,101,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,9,115,97,102,101,95,109,97,116,104,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,19,117,112,100,97,116,101,95,115,116,97,116,101,95,111,102,95,97,108,108,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,24,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,95,98,97,116,99,104,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,33,78,0,0,0,0,0,0,3,8,34,78,0,0,0,0,0,0,3,8,35,78,0,0,0,0,0,0,3,8,36,78,0,0,0,0,0,0,3,8,37,78,0,0,0,0,0,0,3,8,38,78,0,0,0,0,0,0,0,3,0,0,1,26,11,0,10,1,17,5,10,1,10,2,10,4,56,0,10,1,10,2,10,3,11,4,17,8,10,1,10,2,10,3,17,22,32,4,22,10,1,10,2,11,3,17,53,11,1,11,2,17,7,2,1,3,0,0,22,92,10,2,10,3,10,4,17,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,16,11,2,1,11,1,1,11,0,1,7,4,39,10,0,10,2,17,5,10,2,10,3,10,5,56,1,10,2,10,3,10,4,17,20,12,7,11,5,10,7,17,63,12,6,10,2,10,3,10,4,10,6,17,9,11,0,11,1,10,2,10,4,17,12,4,44,5,48,11,2,1,7,0,39,10,6,10,7,33,4,61,10,2,10,3,10,4,17,22,4,61,10,2,10,3,10,4,17,49,10,7,10,6,36,4,86,10,7,10,6,23,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,4,86,10,2,10,3,11,7,10,6,23,17,48,10,2,10,3,10,4,17,22,4,86,10,2,10,3,11,4,17,49,11,2,11,3,17,7,11,6,52,2,2,3,0,0,1,37,10,0,10,2,17,5,10,2,10,3,10,5,56,2,10,2,10,3,10,4,11,5,17,10,10,2,10,3,10,4,17,23,32,4,22,10,2,10,3,10,4,17,54,11,0,11,1,10,2,11,4,17,12,4,29,5,33,11,2,1,7,0,39,11,2,11,3,17,7,2,3,3,0,0,6,58,10,2,10,3,10,4,17,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,14,11,2,1,11,0,1,7,5,39,11,0,10,2,17,5,10,2,10,3,10,5,56,3,10,2,10,3,10,4,17,21,12,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,5,12,8,10,6,10,5,35,4,40,10,6,12,8,11,5,10,6,23,12,7,10,2,10,3,10,4,10,8,17,11,11,8,11,6,33,4,53,10,2,10,3,11,4,17,50,11,2,11,3,17,7,11,7,2,4,3,0,0,23,92,10,2,10,5,10,3,17,23,4,6,5,14,11,2,1,11,1,1,11,0,1,7,3,39,10,2,10,4,10,3,17,22,4,20,5,28,11,2,1,11,1,1,11,0,1,7,2,39,10,0,10,2,17,5,10,2,10,5,10,4,10,6,56,4,10,0,10,1,10,2,10,3,17,12,32,4,44,5,52,11,2,1,11,1,1,11,0,1,7,1,39,11,0,10,2,11,1,10,3,10,4,10,5,11,6,17,24,12,9,12,8,12,12,12,7,12,11,12,10,10,2,10,5,10,3,11,11,17,11,10,2,10,4,10,3,11,10,17,9,11,9,4,82,10,2,10,5,11,3,17,50,10,2,11,4,17,7,11,2,11,5,17,7,11,7,11,8,11,12,2,5,0,0,0,26,25,10,1,46,17,40,12,2,49,0,12,3,10,3,10,2,35,4,20,5,11,10,0,10,1,10,3,17,6,11,3,49,1,22,12,3,5,6,11,1,1,11,0,1,2,6,0,0,0,29,97,11,0,17,66,12,8,10,1,10,2,12,3,46,11,3,17,37,12,11,10,8,11,11,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,18,10,1,10,2,17,36,12,4,12,6,10,1,10,2,17,35,12,5,12,7,10,18,11,7,17,28,10,6,17,62,12,13,11,18,11,5,17,27,10,4,17,62,12,12,10,1,10,2,17,34,1,12,14,1,1,1,10,1,10,2,17,41,12,19,12,20,10,19,10,12,10,4,23,17,62,12,9,11,20,10,13,11,6,23,17,62,12,10,11,9,10,12,17,61,12,15,11,10,10,13,17,61,12,17,11,19,10,12,11,4,23,17,62,11,14,17,62,10,12,17,61,12,16,10,1,10,2,11,12,11,13,11,8,10,16,17,52,11,1,11,2,11,17,11,15,11,16,22,17,45,2,7,0,0,0,22,15,10,0,10,1,17,26,12,2,10,0,10,1,10,2,17,29,12,3,11,0,11,1,11,2,11,3,17,51,2,8,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,47,2,9,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,32,2,10,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,46,2,11,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,31,2,12,1,0,0,1,8,11,0,11,2,11,1,11,3,17,14,17,60,38,2,13,1,0,0,35,37,14,3,65,36,12,6,6,0,0,0,0,0,0,0,0,12,5,64,4,0,0,0,0,0,0,0,0,12,7,10,5,10,6,35,4,29,5,12,10,0,10,2,10,1,14,3,10,5,66,36,20,17,14,12,4,13,7,11,4,68,4,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,7,11,2,1,11,1,1,11,0,1,11,7,2,14,1,0,0,37,33,10,0,10,2,10,1,10,3,17,16,12,6,10,0,10,1,10,2,10,3,17,15,12,5,11,0,11,2,11,1,11,3,17,17,12,7,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,29,11,6,11,7,17,61,11,5,17,62,12,4,5,31,17,65,12,4,11,4,2,15,1,0,0,38,72,10,1,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,6,0,0,0,0,0,0,0,0,12,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,10,9,10,10,35,4,56,5,22,14,8,10,9,66,28,12,5,10,1,10,5,20,17,38,12,11,1,1,10,0,10,2,10,1,11,5,20,10,3,17,19,12,12,11,6,10,12,11,11,17,62,22,12,6,11,7,11,12,22,12,7,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,17,11,1,1,11,2,1,11,0,1,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,11,6,11,7,17,61,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,16,1,0,0,41,59,10,2,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,6,0,0,0,0,0,0,0,0,12,9,10,9,10,10,35,4,51,5,20,14,8,10,9,66,28,12,6,10,2,10,6,20,12,5,46,11,5,17,33,12,11,10,0,10,1,10,2,11,6,20,10,3,17,19,12,7,11,12,11,7,11,11,17,62,22,12,12,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,15,11,2,1,11,1,1,11,0,1,11,12,2,17,1,0,0,42,49,10,2,10,3,12,4,46,11,4,17,43,12,9,1,14,9,65,28,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,41,5,20,14,9,10,6,66,28,12,5,10,0,10,1,10,2,11,5,20,10,3,17,18,12,8,11,10,11,8,22,12,10,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,15,11,2,1,11,1,1,11,0,1,11,10,2,18,1,0,0,43,18,10,2,10,3,11,4,17,21,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,19,1,0,0,43,18,10,2,10,3,11,4,17,20,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,20,1,0,0,22,15,10,0,10,1,11,2,17,44,1,12,3,11,0,11,1,17,36,1,12,4,11,3,11,4,17,62,2,21,1,0,0,22,15,10,0,10,1,11,2,17,44,12,3,1,11,0,11,1,17,36,12,4,1,11,3,11,4,17,62,2,22,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,1,12,4,14,4,14,1,56,5,2,23,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,12,4,1,14,4,14,1,56,5,2,24,0,0,0,47,113,10,1,10,4,17,38,1,12,15,12,16,10,0,10,2,10,1,10,4,10,3,17,19,11,16,17,62,12,20,10,0,10,2,10,1,10,5,11,3,17,18,12,19,9,12,12,10,19,10,20,35,4,32,11,19,12,20,8,12,12,10,1,10,5,12,7,46,11,7,17,39,12,18,10,0,10,2,11,6,11,18,17,30,12,21,10,21,10,20,36,4,54,11,21,10,20,23,12,11,5,58,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,11,21,12,20,10,20,11,15,17,62,12,8,11,1,10,4,17,42,12,22,10,8,11,22,17,62,12,23,10,20,10,23,23,12,17,10,0,10,2,10,20,10,4,17,25,12,13,10,0,10,2,11,20,10,5,17,25,12,14,10,0,10,2,11,17,10,4,17,25,12,9,10,0,10,2,11,23,11,4,17,25,12,24,11,0,11,2,11,11,11,8,22,11,5,17,25,12,10,11,13,11,14,11,9,11,24,11,10,11,12,2,0,41,0],[161,28,235,11,6,0,0,0,10,1,0,22,2,22,52,3,74,130,1,4,204,1,38,5,242,1,222,2,7,208,4,238,3,8,190,8,96,6,158,9,10,10,168,9,49,12,217,9,201,4,0,26,0,25,0,30,0,34,0,39,2,32,1,14,1,15,1,19,1,41,0,44,0,3,3,0,0,11,3,0,0,0,3,0,0,8,3,0,0,5,3,0,1,4,12,0,3,6,12,1,0,1,4,9,12,0,5,7,8,0,6,1,8,0,7,2,12,1,0,1,9,10,2,0,0,46,0,1,0,0,16,2,1,1,0,0,47,3,1,1,0,0,13,4,1,1,0,0,35,5,1,1,0,0,29,6,1,2,0,0,1,43,11,1,0,2,20,22,1,1,0,2,21,19,1,1,0,2,22,32,33,2,0,0,2,23,22,28,1,0,2,24,22,16,1,0,3,16,17,1,1,0,3,17,35,1,1,0,3,31,18,16,1,0,3,42,18,16,1,0,3,47,23,1,1,0,4,33,0,7,0,7,45,15,16,1,0,8,18,12,1,1,3,9,37,9,10,0,10,38,13,14,1,0,21,12,18,12,12,12,14,12,8,12,19,20,11,12,15,12,16,12,19,24,7,12,19,26,10,12,19,29,9,31,15,34,16,34,13,34,19,36,1,6,8,7,0,8,6,8,9,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,5,7,8,11,9,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,5,7,8,5,7,8,11,7,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,7,8,11,8,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,11,12,6,8,9,6,8,8,7,8,7,2,7,11,6,1,9,0,2,7,11,6,1,9,1,11,10,1,9,0,5,3,7,8,5,7,8,11,1,1,5,3,3,3,5,11,10,1,9,0,1,6,8,11,1,5,5,7,8,5,6,8,9,7,8,7,2,5,1,9,0,3,11,10,1,9,0,3,7,8,11,1,11,10,1,9,0,1,6,11,10,1,9,0,1,3,3,7,11,6,1,9,0,11,10,1,9,0,7,8,11,2,6,11,6,1,9,0,3,5,6,8,9,7,8,7,2,5,15,1,8,0,6,3,3,3,3,3,5,6,6,8,9,6,8,8,7,8,7,2,5,15,4,7,11,6,1,9,0,3,5,7,8,11,1,8,1,3,3,3,5,1,8,2,8,3,3,15,3,3,3,5,11,10,1,9,0,1,15,1,8,3,14,3,3,3,3,15,15,3,3,3,3,3,5,11,10,1,9,0,15,2,9,0,9,1,7,6,8,9,6,8,8,7,8,7,5,2,2,15,3,15,15,15,1,9,1,2,7,11,6,1,9,0,3,1,8,4,11,66,111,114,114,111,119,69,118,101,110,116,5,67,108,111,99,107,4,67,111,105,110,12,68,101,112,111,115,105,116,69,118,101,110,116,9,73,110,99,101,110,116,105,118,101,20,76,105,113,117,105,100,97,116,105,111,110,67,97,108,108,69,118,101,110,116,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,112,97,121,69,118,101,110,116,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,13,87,105,116,104,100,114,97,119,69,118,101,110,116,6,97,109,111,117,110,116,6,98,111,114,114,111,119,5,99,108,111,99,107,4,99,111,105,110,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,9,105,110,99,101,110,116,105,118,101,7,108,101,110,100,105,110,103,16,108,105,113,117,105,100,97,116,101,95,97,109,111,117,110,116,14,108,105,113,117,105,100,97,116,101,95,117,115,101,114,16,108,105,113,117,105,100,97,116,105,111,110,95,99,97,108,108,5,108,111,103,105,99,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,5,112,97,117,115,101,4,112,111,111,108,5,114,101,112,97,121,7,114,101,115,101,114,118,101,6,115,101,110,100,101,114,10,115,112,108,105,116,95,99,111,105,110,7,115,116,111,114,97,103,101,2,116,111,10,116,120,95,99,111,110,116,101,120,116,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,13,117,112,100,97,116,101,95,114,101,119,97,114,100,5,117,116,105,108,115,5,118,97,108,117,101,15,119,104,101,110,95,110,111,116,95,112,97,117,115,101,100,8,119,105,116,104,100,114,97,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,41,160,0,0,0,0,0,0,0,2,3,36,2,37,5,12,3,1,2,4,36,2,37,5,40,5,12,3,2,2,3,36,2,37,5,12,3,3,2,3,36,2,37,5,12,3,4,2,4,36,2,37,5,28,5,27,3,0,0,0,0,1,8,11,0,17,17,32,4,5,5,7,7,0,39,2,1,1,4,0,8,45,10,1,46,17,0,10,7,46,17,20,12,11,11,6,10,0,10,1,10,3,10,11,17,6,11,4,11,5,10,7,56,0,12,12,14,12,56,1,12,9,10,2,11,12,11,7,56,2,11,2,10,9,12,8,46,11,8,56,3,12,10,11,0,11,1,10,3,10,11,11,10,77,56,4,11,3,11,11,11,9,18,0,56,5,2,2,1,4,0,21,50,10,2,46,17,0,10,8,46,17,20,12,14,11,7,10,0,10,2,10,4,10,14,17,6,10,3,11,5,12,9,46,11,9,56,3,12,13,11,0,11,1,11,2,10,4,11,14,11,13,77,56,6,12,11,10,3,11,11,12,10,46,11,10,56,7,12,12,11,3,10,12,10,6,10,8,56,8,11,4,11,8,46,17,20,11,6,11,12,18,1,56,9,2,3,1,4,0,25,35,10,2,46,17,0,10,6,46,17,20,12,9,10,3,10,5,12,7,46,11,7,56,3,12,8,11,0,11,1,11,2,10,4,10,9,11,8,77,56,10,11,3,10,5,11,9,10,6,56,8,11,4,11,6,46,17,20,11,5,18,2,56,11,2,4,1,4,0,27,65,10,2,46,17,0,10,7,46,17,20,12,14,11,5,11,6,10,7,56,0,12,15,14,15,56,1,12,13,10,3,11,15,10,7,56,2,10,3,10,13,12,8,46,11,8,56,3,12,12,11,0,11,1,11,2,10,4,10,14,11,12,77,56,12,12,10,10,3,11,10,52,12,9,46,11,9,56,7,12,11,10,11,6,0,0,0,0,0,0,0,0,36,4,53,11,3,10,11,11,14,10,7,56,8,5,55,11,3,1,11,4,11,7,46,17,20,11,13,11,11,23,18,3,56,13,2,5,1,4,0,30,90,10,2,46,17,0,10,11,46,17,20,12,23,11,10,10,0,10,2,10,5,10,8,17,6,11,7,11,9,10,11,56,0,12,24,14,24,56,1,12,18,10,4,11,24,10,11,56,2,10,4,11,18,12,12,46,11,12,56,3,12,21,11,0,11,1,11,2,10,8,10,5,11,3,11,21,77,56,14,12,25,12,17,12,16,10,4,11,17,52,12,13,46,11,13,56,7,12,20,11,4,11,20,10,23,10,11,56,8,10,6,11,16,52,12,14,46,11,14,56,15,12,19,10,6,10,19,10,23,11,11,56,16,10,6,11,25,52,12,15,46,11,15,56,15,12,22,11,6,10,22,56,17,11,5,11,23,11,8,11,19,11,22,22,18,4,56,18,2,0]],["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"],"0xb2345915de1f9bd661e9ab27eb27e376cdf6391359ea64fbfdb4550b092c1aa0",{"Result":0}]},{"MoveCall":{"package":"0x0000000000000000000000000000000000000000000000000000000000000002","module":"package","function":"commit_upgrade","type_arguments":[],"arguments":[{"Input":0},{"Result":1}]}}]}},"sender":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57","gas_data":{"payment":[["0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1",26932892,"Ex867bCQkeiTCvcRqhkbAtZWPyVPcMbNRj1acbfyZdAs"]],"owner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57","price":750,"budget":300000000},"expiration":"None"}}},"tx_signatures":["AI5U6xMfN2yyPDsdvVvw1AFxBXD4cd6wejUm9G9Edx8Rnj28g4Hz8Lz2nFW1hEiwVYDED+VQ9Qrkl7DXLfoODwUcypkmsYEh2xu++z3ojPaRBoPqgLGIm3/ZtoRgRAd5fw=="]}],"sender":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57","input_objects":[{"ImmOrOwnedMoveObject":["0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623",10941462,"97EMwmR1yvKzotocnPsNs5gLiHPkDztrM5WsVeE9d1y"]},{"MovePackage":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"MovePackage":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"MovePackage":"0xb2345915de1f9bd661e9ab27eb27e376cdf6391359ea64fbfdb4550b092c1aa0"},{"MovePackage":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"},{"ImmOrOwnedMoveObject":["0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1",26932892,"Ex867bCQkeiTCvcRqhkbAtZWPyVPcMbNRj1acbfyZdAs"]}],"kind":{"ProgrammableTransaction":{"inputs":[{"Object":{"ImmOrOwnedObject":["0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623",10941462,"97EMwmR1yvKzotocnPsNs5gLiHPkDztrM5WsVeE9d1y"]}},{"Pure":[0]},{"Pure":[32,246,193,86,67,237,66,165,149,9,252,108,46,208,117,166,90,184,114,112,210,57,76,234,29,82,22,132,25,179,156,59,27]}],"commands":[{"MoveCall":{"package":"0x0000000000000000000000000000000000000000000000000000000000000002","module":"package","function":"authorize_upgrade","type_arguments":[],"arguments":[{"Input":0},{"Input":1},{"Input":2}]}},{"Upgrade":[[[161,28,235,11,6,0,0,0,7,1,0,2,3,2,30,5,32,6,7,38,34,8,72,32,6,104,50,12,154,1,163,2,0,5,0,0,0,1,0,0,6,0,1,0,0,4,0,1,0,0,1,0,1,0,0,3,0,1,0,0,2,0,1,0,2,15,15,1,15,0,3,97,100,100,3,100,105,118,3,109,105,110,3,109,111,100,3,109,117,108,9,115,97,102,101,95,109,97,116,104,3,115,117,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,233,3,0,0,0,0,0,0,3,8,234,3,0,0,0,0,0,0,3,8,235,3,0,0,0,0,0,0,3,8,236,3,0,0,0,0,0,0,3,8,237,3,0,0,0,0,0,0,0,1,0,0,1,13,10,0,11,1,22,12,2,10,2,11,0,38,4,9,5,11,7,0,39,11,2,2,1,1,0,0,2,11,10,1,10,0,37,4,5,5,7,7,1,39,11,0,11,1,23,2,2,1,0,0,1,21,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,10,1,24,12,2,10,2,11,0,26,11,1,33,4,17,5,19,7,2,39,11,2,2,3,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,5,5,7,7,3,39,11,0,11,1,26,2,4,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,4,39,11,0,11,1,25,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,0],[161,28,235,11,6,0,0,0,9,1,0,10,2,10,16,3,26,47,4,73,12,5,85,63,7,148,1,156,1,8,176,2,64,6,240,2,20,12,132,3,114,0,14,1,3,1,4,1,12,1,13,1,0,4,1,0,1,2,1,12,1,0,1,4,2,2,0,0,10,0,1,1,0,0,11,0,2,1,0,2,5,1,8,1,0,2,6,1,2,1,0,2,9,7,1,1,0,2,15,5,6,1,0,3,7,11,8,1,12,4,8,9,10,0,5,4,4,4,2,4,6,1,0,4,3,4,3,11,1,1,9,0,3,7,8,2,1,11,1,1,9,0,1,11,0,1,9,0,2,3,11,1,1,9,0,1,9,0,1,6,11,1,1,9,0,1,3,3,7,11,1,1,9,0,3,7,8,2,0,1,6,8,2,1,5,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,4,99,111,105,110,12,100,101,115,116,114,111,121,95,122,101,114,111,12,105,110,116,111,95,98,97,108,97,110,99,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,10,115,112,108,105,116,95,99,111,105,110,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,117,116,105,108,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,176,179,0,0,0,0,0,0,3,8,177,179,0,0,0,0,0,0,0,1,0,0,3,44,14,0,56,0,12,3,10,1,6,0,0,0,0,0,0,0,0,36,4,8,5,12,11,2,1,7,0,39,11,3,10,1,38,4,17,5,21,11,2,1,7,1,39,13,0,11,1,10,2,56,1,12,4,14,0,56,0,6,0,0,0,0,0,0,0,0,33,4,37,11,2,1,11,0,56,2,11,4,2,11,0,11,2,46,17,7,56,3,11,4,2,1,1,0,0,8,6,11,0,11,1,11,2,56,4,56,5,2,0],[161,28,235,11,6,0,0,0,14,1,0,18,2,18,54,3,72,145,1,4,217,1,30,5,247,1,203,1,7,194,3,145,4,8,211,7,96,6,179,8,20,10,199,8,67,11,138,9,2,12,140,9,146,3,13,158,12,6,14,164,12,6,15,170,12,4,0,37,1,13,1,47,2,14,2,15,2,23,2,36,2,44,2,46,0,2,12,1,0,1,0,3,12,0,0,5,3,0,0,4,3,0,0,6,3,0,0,7,3,0,1,8,7,0,2,10,7,0,3,0,4,1,0,1,4,1,12,1,0,1,6,11,4,0,8,9,2,0,0,28,0,1,0,0,17,2,1,1,0,0,20,3,1,1,0,0,50,4,1,1,0,0,21,5,1,1,0,0,52,6,1,1,0,0,51,7,1,1,0,0,26,8,9,1,0,0,16,10,11,0,0,35,12,11,1,0,0,48,12,11,1,0,2,25,1,26,1,0,2,30,26,27,0,3,31,25,11,1,0,3,42,29,19,1,0,3,49,32,11,1,0,3,53,1,19,1,0,4,24,30,24,1,0,4,29,24,19,1,0,4,49,23,11,1,0,5,22,18,1,1,3,6,33,0,13,0,7,38,17,1,1,12,7,41,18,1,1,8,8,40,14,15,0,22,16,16,18,23,20,20,21,19,18,18,18,13,18,11,18,20,28,14,18,17,18,20,31,22,24,15,18,7,18,1,7,8,11,0,3,6,8,1,2,7,8,11,3,7,11,0,1,9,0,11,9,1,9,0,7,8,11,4,7,11,0,1,9,0,3,5,7,8,11,2,7,11,0,1,9,0,3,5,7,8,1,7,11,0,1,9,0,3,5,7,8,11,5,6,8,1,7,11,0,1,9,0,3,5,7,8,11,1,6,11,0,1,9,0,1,2,3,3,2,2,1,3,2,6,11,0,1,9,0,3,1,8,10,1,6,8,11,1,5,1,8,1,2,9,0,5,1,9,0,1,11,8,1,9,0,1,11,0,1,9,0,1,8,2,2,11,8,1,9,0,3,1,6,11,9,1,9,0,1,11,9,1,9,0,2,7,11,8,1,9,0,11,8,1,9,0,1,8,7,1,8,6,1,8,4,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,11,1,8,5,1,6,11,8,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,19,80,111,111,108,66,97,108,97,110,99,101,82,101,103,105,115,116,101,114,10,80,111,111,108,67,114,101,97,116,101,11,80,111,111,108,68,101,112,111,115,105,116,12,80,111,111,108,87,105,116,104,100,114,97,119,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,7,99,114,101,97,116,111,114,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,2,105,100,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,7,108,101,110,100,105,110,103,3,110,101,119,10,110,101,119,95,97,109,111,117,110,116,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,9,114,101,99,105,112,105,101,110,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,7,115,116,111,114,97,103,101,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,17,164,0,0,0,0,0,0,3,8,18,164,0,0,0,0,0,0,0,2,4,27,8,10,14,11,8,1,9,0,45,11,8,1,9,0,19,2,1,2,2,27,8,10,18,5,2,2,1,18,5,3,2,4,40,5,12,3,34,3,37,8,6,4,2,3,40,5,12,3,37,8,6,5,2,4,40,5,39,5,12,3,37,8,6,0,18,0,0,0,0,1,11,10,0,17,21,10,0,46,17,24,18,1,11,0,46,17,24,56,0,2,1,3,0,0,1,13,10,2,17,21,56,1,56,1,11,1,57,0,56,2,11,2,46,17,24,18,2,56,3,2,2,3,0,0,22,20,14,1,56,4,12,4,11,1,56,5,12,3,11,0,54,0,11,3,56,6,1,11,2,46,17,24,11,4,56,7,17,12,18,4,56,8,2,3,3,0,0,24,20,11,0,54,0,10,1,56,9,10,3,56,10,12,4,11,3,46,17,24,10,2,11,1,56,7,17,12,18,5,56,11,11,4,11,2,56,12,2,4,3,0,0,19,22,10,0,55,0,56,13,10,1,38,4,7,5,11,11,0,1,7,1,39,10,0,54,0,11,1,56,9,12,2,11,0,54,1,11,2,56,6,1,2,5,1,0,0,1,22,10,1,55,1,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,1,11,2,56,9,11,4,56,10,11,3,56,12,2,6,3,0,0,1,22,10,1,55,0,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,0,11,2,56,9,11,4,56,10,11,3,56,12,2,7,1,0,0,1,4,11,0,55,2,20,2,8,1,0,0,1,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,9,1,0,0,9,8,11,0,56,14,12,2,11,1,11,2,49,9,17,8,2,10,1,0,0,9,8,11,0,56,14,12,2,11,1,49,9,11,2,17,8,2,0,1,0,2,0,3,0,18,1,18,2,18,0,32,0,43,0],[161,28,235,11,6,0,0,0,7,1,0,4,3,4,55,5,59,8,7,67,101,8,168,1,64,6,232,1,200,1,12,176,3,168,5,0,6,1,0,0,4,0,1,0,0,9,0,1,0,0,1,0,1,0,0,2,0,1,0,0,11,2,1,0,0,10,2,1,0,0,7,2,1,0,0,5,2,1,0,0,8,1,1,0,0,12,1,1,0,1,3,0,1,0,0,1,15,2,15,15,1,1,7,97,100,100,114,101,115,115,8,104,97,108,102,95,114,97,121,8,104,97,108,102,95,119,97,100,3,109,97,120,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,10,114,97,121,95,116,111,95,119,97,100,3,119,97,100,7,119,97,100,95,100,105,118,7,119,97,100,95,109,117,108,10,119,97,100,95,116,111,95,114,97,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,100,167,179,182,224,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,178,211,89,91,240,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,77,4,0,0,0,0,0,0,3,8,78,4,0,0,0,0,0,0,3,8,79,4,0,0,0,0,0,0,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,0,2,2,1,0,0,0,2,7,3,2,3,1,0,0,0,2,7,1,2,4,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,1,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,1,22,7,0,26,2,5,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,0,26,37,4,20,5,22,7,5,39,11,0,7,0,24,11,2,22,11,1,26,2,6,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,3,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,3,22,7,2,26,2,7,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,2,26,37,4,20,5,22,7,5,39,11,0,7,2,24,11,2,22,11,1,26,2,8,1,0,0,2,19,7,4,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,1,10,1,11,0,22,12,2,10,2,11,1,38,4,13,5,15,7,6,39,11,2,7,4,26,2,9,1,0,0,1,15,10,0,7,4,24,12,1,10,1,7,4,26,11,0,33,4,11,5,13,7,5,39,11,1,2,0],[161,28,235,11,6,0,0,0,12,1,0,29,2,29,92,3,121,144,3,4,137,4,54,5,191,4,153,3,7,216,7,131,16,8,219,23,96,6,187,24,93,10,152,25,164,1,12,188,26,186,19,13,246,45,66,15,184,46,2,0,120,0,90,0,94,1,22,1,131,1,1,141,1,2,30,2,31,2,47,2,85,2,123,2,127,2,130,1,0,4,12,0,0,11,12,0,0,10,12,0,0,9,4,0,0,20,4,0,0,8,5,0,0,19,5,0,0,15,4,0,0,0,4,0,0,3,4,0,0,12,3,0,0,5,3,0,1,6,12,1,0,1,1,7,12,0,3,13,7,0,4,17,7,0,6,1,8,0,7,2,12,1,0,1,9,18,4,0,10,14,12,2,7,1,4,1,12,16,2,0,0,73,0,1,0,0,144,1,2,1,0,0,143,1,3,1,0,0,74,4,1,1,0,0,115,5,1,0,0,117,6,1,0,0,107,6,1,0,0,112,6,1,0,0,118,6,1,0,0,106,6,1,0,0,113,6,1,0,0,108,6,1,0,0,116,6,1,0,0,114,6,1,0,0,110,6,1,0,0,109,6,1,0,0,111,6,1,0,0,102,2,1,1,0,0,88,2,7,0,0,59,2,8,0,0,64,9,10,0,0,58,11,8,0,0,52,11,12,0,0,60,13,14,0,0,50,13,14,0,0,53,13,15,0,0,55,13,15,0,0,61,13,15,0,0,65,16,15,0,0,56,11,17,0,0,49,11,14,0,0,63,13,14,0,0,62,11,14,0,0,51,13,18,0,0,57,13,19,0,0,133,1,20,1,0,0,134,1,21,1,0,0,68,20,1,0,0,70,22,1,0,0,44,22,1,0,0,69,22,1,0,0,43,22,1,0,0,67,23,1,0,0,42,23,1,0,0,71,24,1,0,0,136,1,16,1,0,0,97,16,1,0,0,135,1,16,1,0,0,96,16,1,0,0,146,1,25,1,1,0,0,45,3,1,0,1,36,43,1,1,0,1,132,1,62,17,1,0,1,145,1,63,1,1,0,2,93,1,14,0,4,48,1,38,1,0,4,75,38,12,0,5,35,57,7,1,0,5,72,57,59,1,0,5,95,60,36,1,0,6,125,40,17,0,7,54,42,8,1,0,8,46,36,1,1,3,9,84,0,26,0,10,21,41,1,2,7,4,10,25,49,50,2,7,4,10,28,46,47,2,7,4,10,35,49,7,2,7,4,10,84,0,33,2,7,4,10,95,46,55,2,7,4,11,91,30,1,1,12,11,119,36,1,1,8,12,105,27,28,0,70,29,70,31,68,32,68,34,71,35,17,36,55,36,68,39,64,32,61,36,51,36,62,44,66,32,65,32,67,34,65,34,67,39,65,39,69,39,64,39,64,34,66,34,57,8,58,8,59,8,52,36,53,36,1,7,8,20,0,1,6,8,2,2,6,8,1,7,8,2,20,6,8,1,6,8,13,6,8,16,7,8,2,2,1,15,15,15,15,15,15,15,15,15,15,15,15,6,11,17,1,9,0,7,8,20,3,6,8,0,7,8,2,1,4,6,8,0,7,8,2,2,15,1,1,1,2,2,6,8,2,5,2,10,2,10,2,2,6,8,2,2,1,8,14,2,7,8,2,2,1,15,2,15,15,3,7,8,2,2,5,1,3,5,15,15,15,15,15,3,15,15,15,4,7,8,2,2,15,15,6,7,8,2,2,15,15,3,15,4,7,8,2,2,5,15,3,7,8,7,5,15,3,7,8,2,2,15,8,6,8,1,6,8,13,7,8,2,2,7,11,12,1,9,0,3,5,7,8,20,1,8,18,1,6,8,20,1,5,1,8,1,2,9,0,5,1,8,0,2,2,8,3,1,11,19,2,9,0,9,1,2,5,8,4,1,8,2,1,9,0,18,2,15,15,15,8,7,8,7,3,8,8,8,9,2,8,14,1,15,15,15,2,2,8,3,1,8,15,2,5,15,1,6,8,16,3,7,11,19,2,9,0,9,1,9,0,9,1,1,6,11,17,1,9,0,3,6,8,13,2,7,8,20,1,8,11,1,7,8,3,2,7,11,19,2,9,0,9,1,9,0,1,7,9,1,3,2,2,8,14,2,6,11,19,2,9,0,9,1,9,0,1,6,9,1,1,6,8,4,1,6,8,3,3,15,6,8,3,15,3,7,8,7,7,8,3,7,8,7,1,9,1,3,10,2,8,4,7,8,4,2,6,10,9,0,6,9,0,2,3,7,8,4,2,1,3,2,7,10,9,0,3,5,2,3,7,15,3,3,2,6,11,12,1,9,0,3,5,6,8,13,7,11,12,1,9,0,3,5,7,8,20,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,12,67,111,105,110,77,101,116,97,100,97,116,97,18,76,105,113,117,105,100,97,116,105,111,110,70,97,99,116,111,114,115,8,79,119,110,101,114,67,97,112,6,80,97,117,115,101,100,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,23,82,101,115,101,114,118,101,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,11,82,101,115,101,114,118,101,68,97,116,97,7,83,116,111,114,97,103,101,15,83,116,111,114,97,103,101,65,100,109,105,110,67,97,112,26,83,116,111,114,97,103,101,67,111,110,102,105,103,117,114,97,116,111,114,83,101,116,116,105,110,103,6,83,116,114,105,110,103,5,84,97,98,108,101,12,84,111,107,101,110,66,97,108,97,110,99,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,20,85,115,101,114,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,8,85,115,101,114,73,110,102,111,3,97,100,100,5,97,115,99,105,105,9,98,97,115,101,95,114,97,116,101,5,98,111,110,117,115,6,98,111,114,114,111,119,14,98,111,114,114,111,119,95,98,97,108,97,110,99,101,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,5,99,108,111,99,107,4,99,111,105,110,9,99,111,105,110,95,116,121,112,101,11,99,111,108,108,97,116,101,114,97,108,115,12,99,111,110,102,105,103,117,114,97,116,111,114,8,99,111,110,116,97,105,110,115,11,99,114,101,97,116,101,95,112,111,111,108,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,20,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,114,97,116,101,4,100,97,116,97,16,100,101,99,114,101,97,115,101,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,12,100,101,115,116,111,114,121,95,117,115,101,114,4,101,109,105,116,5,101,118,101,110,116,3,103,101,116,13,103,101,116,95,97,115,115,101,116,95,108,116,118,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,13,103,101,116,95,99,111,105,110,95,116,121,112,101,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,12,103,101,116,95,100,101,99,105,109,97,108,115,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,20,103,101,116,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,16,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,114,101,115,101,114,118,101,11,105,110,116,111,95,115,116,114,105,110,103,11,105,115,95,105,115,111,108,97,116,101,100,20,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,5,108,111,97,110,115,5,108,111,103,105,99,3,108,116,118,10,109,117,108,116,105,112,108,105,101,114,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,111,114,97,99,108,101,95,105,100,5,112,97,117,115,101,6,112,97,117,115,101,100,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,105,111,3,114,97,121,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,14,114,101,115,101,114,118,101,95,102,97,99,116,111,114,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,97,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,98,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,99,18,114,101,115,101,114,118,101,95,118,97,108,105,100,97,116,105,111,110,8,114,101,115,101,114,118,101,115,14,114,101,115,101,114,118,101,115,95,99,111,117,110,116,6,115,101,110,100,101,114,13,115,101,116,95,98,97,115,101,95,114,97,116,101,14,115,101,116,95,98,111,114,114,111,119,95,99,97,112,24,115,101,116,95,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,98,111,110,117,115,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,114,97,116,105,111,25,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,7,115,101,116,95,108,116,118,14,115,101,116,95,109,117,108,116,105,112,108,105,101,114,23,115,101,116,95,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,115,101,116,95,112,97,117,115,101,18,115,101,116,95,114,101,115,101,114,118,101,95,102,97,99,116,111,114,14,115,101,116,95,115,117,112,112,108,121,95,99,97,112,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,7,115,116,111,114,97,103,101,14,115,117,112,112,108,121,95,98,97,108,97,110,99,101,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,9,116,104,114,101,115,104,111,108,100,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,9,117,115,101,114,95,105,110,102,111,10,117,115,101,114,95,115,116,97,116,101,5,117,115,101,114,115,5,118,97,108,117,101,6,118,101,99,116,111,114,7,118,101,114,115,105,111,110,15,118,101,114,115,105,111,110,95,109,105,103,114,97,116,101,20,118,101,114,115,105,111,110,95,118,101,114,105,102,105,99,97,116,105,111,110,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,3,0,0,0,0,0,0,0,3,8,248,167,0,0,0,0,0,0,3,8,249,167,0,0,0,0,0,0,3,8,250,167,0,0,0,0,0,0,3,8,251,167,0,0,0,0,0,0,3,8,252,167,0,0,0,0,0,0,3,8,253,167,0,0,0,0,0,0,3,8,254,167,0,0,0,0,0,0,3,8,255,167,0,0,0,0,0,0,2,1,255,0,2,1,66,8,18,1,2,1,66,8,18,2,2,7,66,8,18,142,1,3,89,1,103,11,19,2,2,8,3,104,2,139,1,10,5,137,1,11,19,2,5,8,4,3,2,21,66,2,87,2,32,8,14,76,1,122,15,27,15,40,15,38,15,39,15,37,15,121,8,7,26,8,7,78,3,82,15,129,1,15,128,1,15,29,8,8,79,8,9,99,15,100,15,101,15,4,2,2,33,10,2,80,10,2,5,2,1,41,15,6,2,1,41,15,7,2,2,138,1,11,19,2,5,15,126,15,8,2,5,23,15,83,15,77,15,98,15,86,15,9,2,3,92,15,24,15,124,15,10,2,3,105,5,34,5,140,1,1,11,2,1,89,1,0,0,0,0,1,27,10,0,17,63,18,1,10,0,46,17,72,56,0,10,0,17,63,18,0,10,0,46,17,72,56,1,10,0,17,63,7,0,9,10,0,56,2,49,0,64,28,0,0,0,0,0,0,0,0,11,0,56,3,18,2,56,4,2,1,0,0,0,1,10,11,0,16,0,20,7,0,33,4,7,5,9,7,1,39,2,2,1,4,0,1,16,10,1,16,0,20,7,0,35,4,7,5,11,11,1,1,7,2,39,7,0,11,1,15,0,21,2,3,1,4,0,37,117,10,3,46,17,1,10,3,16,1,20,12,35,10,35,7,9,35,4,12,5,24,11,3,1,11,1,1,11,19,1,11,18,1,11,2,1,7,5,39,10,3,46,56,5,10,3,16,1,20,12,20,11,4,12,29,56,6,17,56,12,30,11,5,12,31,11,6,12,32,11,7,12,33,17,54,12,34,17,54,12,21,11,13,12,22,11,14,12,23,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,24,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,25,11,2,17,60,12,26,11,8,11,10,11,11,11,12,11,9,18,8,12,27,11,15,11,16,11,17,18,9,12,28,11,20,11,29,11,30,11,31,11,32,11,33,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,34,11,21,11,24,11,25,11,26,11,22,11,23,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,27,11,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,12,37,10,3,15,2,10,35,11,37,56,8,11,35,49,1,22,11,3,15,1,21,11,18,56,9,12,36,11,1,11,36,11,19,56,10,2,4,1,4,0,1,11,10,1,46,17,1,10,2,11,1,15,3,21,11,2,18,11,56,11,2,5,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,4,21,2,6,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,5,21,2,7,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,6,21,2,8,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,7,21,2,9,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,9,21,2,10,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,10,21,2,11,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,11,21,2,12,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,12,21,2,13,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,13,21,2,14,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,15,21,2,15,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,16,21,2,16,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,17,21,2,17,1,0,0,48,36,56,6,17,56,12,3,10,0,16,1,20,12,1,49,0,12,2,10,2,10,1,35,4,33,5,14,10,0,16,2,10,2,56,13,16,18,20,10,3,34,4,24,5,28,11,0,1,7,7,39,11,2,49,1,22,12,2,5,9,11,0,1,2,18,1,0,0,1,4,11,0,16,3,20,2,19,1,0,0,1,4,11,0,16,1,20,2,20,1,0,0,51,23,10,0,16,19,10,1,56,14,32,4,11,11,0,1,64,8,0,0,0,0,0,0,0,0,64,8,0,0,0,0,0,0,0,0,2,11,0,16,19,11,1,56,15,12,2,10,2,16,20,20,11,2,16,21,20,2,21,1,0,0,1,7,11,0,16,2,11,1,56,13,16,22,20,2,22,1,0,0,1,7,11,0,16,2,11,1,56,13,16,18,20,2,23,1,0,0,1,7,11,0,16,2,11,1,56,13,16,4,20,2,24,1,0,0,1,7,11,0,16,2,11,1,56,13,16,5,20,2,25,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,23,20,11,2,16,24,20,2,26,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,25,20,11,2,16,26,20,2,27,1,0,0,52,14,11,0,16,2,11,1,56,13,12,2,10,2,16,27,16,28,20,11,2,16,29,16,28,20,2,28,1,0,0,53,41,11,0,16,2,11,1,56,13,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,4,16,27,16,30,10,2,56,16,4,22,10,4,16,27,16,30,10,2,56,17,20,12,5,10,4,16,29,16,30,10,2,56,16,4,36,11,4,16,29,16,30,11,2,56,17,20,12,3,5,38,11,4,1,11,5,11,3,2,29,1,0,0,1,7,11,0,16,2,11,1,56,13,16,31,20,2,30,1,0,0,1,7,11,0,16,2,11,1,56,13,16,6,20,2,31,1,0,0,1,7,11,0,16,2,11,1,56,13,16,7,20,2,32,1,0,0,1,7,11,0,16,2,11,1,56,13,16,32,20,2,33,1,0,0,52,26,11,0,16,2,11,1,56,13,12,2,10,2,16,8,16,9,20,10,2,16,8,16,10,20,10,2,16,8,16,11,20,10,2,16,8,16,12,20,11,2,16,8,16,13,20,2,34,1,0,0,52,18,11,0,16,2,11,1,56,13,12,2,10,2,16,14,16,15,20,10,2,16,14,16,16,20,11,2,16,14,16,17,20,2,35,3,0,0,45,17,10,0,46,17,1,11,0,15,2,11,1,56,12,12,4,11,3,10,4,15,23,21,11,2,11,4,15,24,21,2,36,3,0,0,45,29,10,0,46,17,1,11,0,15,2,11,1,56,12,12,6,11,2,10,6,15,26,21,11,3,10,6,15,25,21,11,4,10,6,15,31,21,10,6,16,32,20,11,5,22,11,6,15,32,21,2,37,3,0,0,54,31,10,0,46,17,1,11,0,15,2,11,1,56,12,12,5,10,5,15,27,12,6,11,5,15,29,12,4,10,6,16,28,20,11,2,22,11,6,15,28,21,10,4,16,28,20,11,3,22,11,4,15,28,21,2,38,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,42,2,39,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,43,2,40,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,42,2,41,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,43,2,42,0,0,0,14,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,0,15,30,11,1,11,3,10,2,22,56,19,10,0,16,28,20,11,2,22,11,0,15,28,21,2,43,0,0,0,14,37,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,3,10,2,38,4,17,5,21,11,0,1,7,6,39,10,0,15,30,11,1,11,3,10,2,23,56,19,10,0,16,28,20,11,2,23,11,0,15,28,21,2,44,3,0,0,45,14,11,0,15,2,11,1,56,12,12,3,10,3,16,32,20,11,2,22,11,3,15,32,21,2,45,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,64,8,0,0,0,0,0,0,0,0,11,3,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,21,14,1,56,22,32,4,37,11,5,15,21,11,1,68,8,5,39,11,5,1,2,46,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,21,14,1,56,23,12,3,4,17,11,4,15,21,11,3,56,24,1,5,19,11,4,1,2,47,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,11,3,64,8,0,0,0,0,0,0,0,0,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,20,14,1,56,22,32,4,37,11,5,15,20,11,1,68,8,5,39,11,5,1,2,48,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,20,14,1,56,23,12,3,4,17,11,4,15,20,11,3,56,24,1,5,19,11,4,1,2,49,1,0,0,61,58,10,2,10,3,12,8,46,11,8,17,22,56,6,17,56,33,4,11,5,21,11,2,1,11,1,1,11,4,1,11,7,1,7,8,39,11,2,15,2,11,3,56,12,15,32,12,10,10,4,10,10,20,52,12,9,46,11,9,56,25,12,11,10,5,12,12,11,5,10,11,35,4,44,11,11,12,12,10,10,20,10,12,77,23,11,10,21,11,1,11,4,11,12,11,6,11,7,56,26,2,50,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,2,1,2,4,2,3,2,2,3,4,3,5,3,13,3,14,3,16,8,0,8,1,8,2,8,3,8,4,3,17,9,0,9,1,9,2,3,2,2,6,4,0,4,1,3,1,3,6,3,7,3,8,3,9,3,10,7,1,3,11,7,0,3,12,3,15,0,81,0],[161,28,235,11,6,0,0,0,8,1,0,12,2,12,12,3,24,75,5,99,67,7,166,1,189,2,8,227,3,96,6,195,4,44,12,239,4,164,5,0,10,0,23,0,21,2,17,1,11,1,16,1,2,12,0,3,1,8,0,4,0,8,0,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,6,3,1,0,0,7,3,1,0,0,9,4,1,0,0,4,4,1,0,1,12,0,8,0,1,13,0,3,0,1,15,0,3,0,2,19,6,1,0,2,20,3,1,0,2,22,3,1,0,3,14,10,11,0,5,18,12,13,0,2,7,8,0,2,1,15,3,7,8,0,2,15,2,15,15,4,6,8,2,6,8,1,15,2,7,15,15,15,15,15,15,15,0,6,15,15,15,15,15,15,5,15,15,15,15,15,2,2,15,3,6,8,2,6,8,1,2,3,1,15,2,2,3,2,1,3,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,20,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,9,103,101,116,95,105,110,100,101,120,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,4,109,97,116,104,6,111,114,97,99,108,101,3,112,111,119,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,153,183,0,0,0,0,0,0,0,1,0,0,5,31,10,0,10,1,17,9,12,7,12,8,11,0,11,1,17,8,12,3,12,4,11,7,11,3,17,12,12,5,11,8,11,4,17,12,12,6,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,29,11,5,11,6,17,11,12,2,11,2,2,1,1,0,0,7,37,10,0,10,1,17,7,12,6,1,12,4,12,5,12,3,11,0,11,1,17,0,12,7,10,7,10,6,35,4,23,11,3,11,7,11,5,17,12,22,12,2,5,35,11,3,10,6,11,5,17,12,22,11,7,11,6,23,11,4,17,12,22,12,2,11,2,2,2,1,0,0,3,20,10,0,10,1,17,7,1,12,3,1,1,1,11,0,11,1,17,0,12,4,11,2,11,4,17,12,17,10,11,3,23,17,12,2,3,1,0,0,5,60,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,17,10,2,10,0,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,5,11,1,7,0,26,12,6,10,6,10,6,17,12,12,3,10,3,10,6,17,12,12,2,10,0,10,4,24,11,3,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,7,10,0,11,4,24,11,5,24,11,2,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,17,10,11,6,11,0,24,22,11,7,22,11,8,22,2,4,1,0,0,6,8,17,10,11,1,11,0,24,7,0,26,22,2,5,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,11,5,24,6,10,0,0,0,0,0,0,0,11,4,17,14,77,26,2,6,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,6,10,0,0,0,0,0,0,0,11,4,17,14,77,24,11,5,26,2,0],[161,28,235,11,6,0,0,0,9,1,0,18,2,18,18,3,36,169,1,4,205,1,4,5,209,1,165,2,7,246,3,149,6,8,139,10,128,1,6,139,11,10,12,149,11,225,14,0,16,0,9,0,38,0,43,0,41,3,37,1,45,2,4,2,10,2,1,12,1,0,1,3,3,12,0,5,2,8,0,8,0,8,0,0,17,0,1,1,0,0,21,2,1,0,0,22,2,1,0,0,20,3,1,0,0,24,3,1,0,0,19,4,1,0,0,23,4,1,0,0,18,5,1,0,0,6,6,7,0,0,13,8,7,1,0,0,14,9,1,0,0,15,10,1,0,0,12,9,1,0,1,5,7,1,0,1,7,7,1,0,1,8,25,1,0,2,36,13,14,1,0,3,25,22,1,0,3,26,28,34,0,3,27,28,7,0,3,28,28,7,0,3,29,22,14,0,3,30,28,29,0,3,31,22,19,0,3,32,28,7,0,3,33,17,18,0,3,34,26,7,0,4,39,15,1,0,4,40,7,1,0,4,42,7,1,0,6,11,20,21,1,0,7,35,15,1,0,8,44,31,14,0,16,12,30,19,9,6,8,3,7,8,1,6,8,2,7,11,0,1,9,0,5,2,3,3,1,1,15,7,6,8,3,6,8,2,7,8,1,5,2,15,1,7,6,8,3,6,8,2,7,8,1,2,5,15,1,6,6,8,3,7,8,1,2,5,15,1,7,6,8,3,7,8,1,6,8,2,5,2,15,1,3,6,8,3,7,8,1,2,2,15,15,7,6,8,3,7,8,1,7,11,0,1,9,0,2,3,3,1,6,6,8,3,7,8,1,2,15,15,1,7,6,8,3,7,8,1,2,15,15,15,1,9,1,3,3,15,15,15,15,3,3,1,9,0,2,6,11,0,1,9,0,3,1,3,0,11,5,2,6,2,10,2,15,10,2,15,3,3,15,15,2,6,8,1,5,2,10,2,10,2,1,2,2,6,10,9,0,6,9,0,1,1,2,6,8,1,2,9,5,6,2,15,3,10,2,3,15,10,2,15,3,2,15,2,4,6,8,3,6,8,2,15,2,3,7,8,1,2,5,11,5,6,2,10,2,15,15,10,2,15,3,3,15,15,2,7,8,1,2,3,15,15,15,10,2,15,15,15,15,3,3,15,15,15,1,6,8,3,7,1,3,3,15,3,3,15,6,15,15,15,15,15,15,5,15,15,15,15,15,7,15,15,15,15,15,15,15,5,67,108,111,99,107,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,23,99,97,108,99,117,108,97,116,101,95,99,117,114,114,101,110,116,95,105,110,100,101,120,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,28,100,121,110,97,109,105,99,95,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,21,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,97,112,121,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,18,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,111,114,21,100,121,110,97,109,105,99,95,104,101,97,108,116,104,95,102,97,99,116,111,114,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,31,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,36,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,30,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,25,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,23,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,3,109,97,120,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,4,112,111,111,108,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,201,175,0,0,0,0,0,0,0,1,0,0,11,99,10,6,6,0,0,0,0,0,0,0,0,36,4,9,10,7,6,0,0,0,0,0,0,0,0,36,12,9,5,11,9,12,9,11,9,32,4,15,5,25,11,1,1,11,3,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,17,10,6,6,0,0,0,0,0,0,0,0,36,4,38,10,3,11,6,12,10,46,11,10,56,0,12,17,6,0,0,0,0,0,0,0,0,12,16,10,7,6,0,0,0,0,0,0,0,0,36,4,52,11,3,11,7,12,11,46,11,11,56,0,12,16,5,54,11,3,1,10,0,10,2,10,1,10,4,10,5,10,17,77,10,8,17,1,12,13,10,0,10,2,10,1,10,4,10,5,11,16,77,10,8,17,2,12,14,11,0,11,1,11,2,11,4,11,5,11,17,77,11,8,17,7,12,15,10,14,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,95,11,13,11,14,17,28,11,15,17,29,12,12,5,97,17,31,12,12,11,12,2,1,1,0,0,16,86,10,2,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,17,6,0,0,0,0,0,0,0,0,12,14,10,12,12,10,14,12,14,4,56,1,32,4,31,10,6,4,31,13,10,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,10,14,10,15,35,4,78,5,36,14,10,10,14,66,19,12,9,10,2,10,9,20,12,8,46,11,8,17,17,12,16,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,9,20,33,4,57,10,5,12,13,10,0,10,1,10,2,11,9,20,10,3,11,13,10,6,17,3,12,11,11,17,11,11,11,16,17,29,22,12,17,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,2,1,11,1,1,11,0,1,11,17,2,2,1,0,0,23,76,10,2,10,3,12,7,46,11,7,17,25,12,14,1,14,14,65,19,12,12,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,6,0,0,0,0,0,0,0,0,12,10,10,14,12,11,14,14,14,4,56,1,32,4,31,10,6,4,31,13,11,10,4,68,19,11,12,6,1,0,0,0,0,0,0,0,22,12,12,10,10,10,12,35,4,68,5,36,14,11,10,10,66,19,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,10,4,10,8,20,33,4,49,10,5,12,9,10,0,10,1,10,2,11,8,20,10,3,11,9,10,6,17,4,12,13,11,15,11,13,22,12,15,11,10,6,1,0,0,0,0,0,0,0,22,12,10,5,31,11,2,1,11,1,1,11,0,1,11,15,2,3,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,5,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,4,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,6,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,5,1,0,0,7,27,10,1,10,2,11,3,17,26,1,12,7,11,5,4,13,11,7,11,4,22,12,7,5,17,11,7,11,4,23,12,7,11,0,11,1,11,2,17,8,1,12,6,11,7,11,6,17,29,2,6,1,0,0,7,27,10,1,10,2,11,3,17,26,12,6,1,11,5,4,13,11,6,11,4,22,12,6,5,17,11,6,11,4,23,12,6,11,0,11,1,11,2,17,8,12,7,1,11,6,11,7,17,29,2,7,1,0,0,27,91,10,1,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,6,0,0,0,0,0,0,0,0,12,14,10,12,12,9,14,12,14,4,56,1,32,4,27,13,9,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,10,14,10,15,35,4,81,5,36,14,9,10,14,66,19,12,8,10,1,10,8,20,17,22,12,16,1,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,8,20,33,4,56,10,5,12,13,10,0,10,2,10,1,11,8,20,10,3,11,13,10,6,17,3,12,17,11,10,10,17,11,16,17,29,22,12,10,11,11,11,17,22,12,11,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,1,1,11,2,1,11,0,1,11,10,11,11,17,28,2,8,1,0,0,30,42,11,0,17,32,12,8,10,1,10,2,12,3,46,11,3,17,21,12,9,10,1,10,2,17,20,12,4,12,6,11,1,11,2,17,19,12,5,12,7,11,8,11,9,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,12,10,12,11,5,17,13,11,4,17,29,12,10,11,12,11,7,17,14,11,6,17,29,12,11,11,10,11,11,2,9,1,0,0,32,76,10,4,6,0,0,0,0,0,0,0,0,36,4,9,10,5,6,0,0,0,0,0,0,0,0,36,12,7,5,11,9,12,7,11,7,32,4,15,5,23,11,1,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,12,10,4,6,0,0,0,0,0,0,0,0,36,4,36,10,2,11,4,12,8,46,11,8,56,0,12,12,6,0,0,0,0,0,0,0,0,12,11,10,5,6,0,0,0,0,0,0,0,0,36,4,50,11,2,11,5,12,9,46,11,9,56,0,12,11,5,52,11,2,1,10,0,10,1,10,3,10,12,77,10,11,77,10,6,17,10,12,10,11,0,11,1,11,3,10,10,11,12,77,11,11,77,11,6,17,11,12,13,11,10,11,13,2,10,1,0,0,33,41,10,1,10,2,17,18,12,10,1,12,8,12,9,12,7,11,0,11,1,11,2,11,3,11,4,11,5,17,12,12,11,10,11,10,10,35,4,27,11,7,11,11,11,9,17,29,22,12,6,5,39,11,7,10,11,11,9,17,29,22,11,11,11,10,23,11,8,17,29,22,12,6,11,6,2,11,1,0,0,7,24,10,1,10,2,17,18,1,12,7,1,1,1,11,0,11,1,11,2,11,4,11,5,11,6,17,12,12,8,11,3,11,8,17,29,17,27,11,7,23,17,29,2,12,1,0,0,35,62,10,1,10,2,17,24,12,11,12,12,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,5,4,16,11,12,11,3,22,12,12,5,20,11,12,11,3,23,12,12,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,35,11,5,4,31,11,11,11,4,22,12,11,5,35,11,11,11,4,23,12,11,11,0,11,1,11,2,17,8,12,7,12,8,11,12,11,8,17,29,12,10,11,11,11,7,17,29,12,9,10,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,56,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,5,60,11,9,11,10,17,28,12,6,11,6,2,0],[161,28,235,11,6,0,0,0,14,1,0,30,2,30,66,3,96,181,1,4,149,2,46,5,195,2,164,3,7,231,5,187,6,8,162,12,96,6,130,13,94,10,224,13,116,11,212,14,2,12,214,14,189,15,13,147,30,40,14,187,30,8,15,195,30,2,0,44,0,72,0,62,0,64,1,18,1,78,2,21,2,26,2,27,2,36,2,53,2,73,2,76,2,77,0,82,0,4,12,1,0,1,0,6,4,0,0,3,12,0,0,7,3,0,0,5,3,0,1,8,12,0,4,9,7,0,5,12,7,0,6,0,4,1,0,1,7,1,8,0,8,2,12,1,0,1,10,13,4,0,11,10,12,2,7,1,4,1,13,11,2,0,0,47,0,1,0,0,67,2,1,0,0,66,2,1,0,0,15,3,1,1,0,0,79,4,1,0,0,24,5,6,0,0,25,7,1,1,0,0,39,8,9,0,0,40,10,11,0,0,33,12,13,0,1,41,46,37,0,1,42,47,37,0,2,60,1,34,0,2,61,37,34,0,3,51,37,34,0,5,38,1,36,1,0,5,48,36,33,0,6,69,49,40,1,0,7,74,32,9,0,8,37,50,51,1,0,9,34,22,1,1,3,10,52,0,14,0,11,14,26,1,2,7,4,11,22,24,45,2,7,4,11,23,27,28,2,7,4,11,29,24,25,2,7,4,11,52,0,18,2,7,4,11,63,27,43,2,7,4,12,58,52,1,1,12,12,68,22,1,1,8,13,65,15,16,0,14,70,39,40,1,0,26,17,26,19,29,21,25,17,22,17,24,17,20,29,20,30,25,19,22,19,24,19,15,22,26,38,31,22,29,41,25,38,27,38,22,38,23,19,23,38,17,22,19,22,28,51,1,7,8,13,0,4,7,8,2,15,1,7,8,13,9,7,8,2,6,8,9,2,3,3,11,10,1,9,0,3,2,7,8,13,5,7,8,2,6,8,9,7,8,5,2,5,5,6,8,2,7,8,5,3,2,5,2,10,15,10,15,6,7,8,2,7,11,0,1,9,0,6,8,9,7,8,5,5,7,8,13,2,6,8,2,2,1,3,3,6,8,2,2,3,4,3,3,15,2,5,6,8,2,7,8,5,6,8,9,2,5,3,10,8,6,10,15,10,2,1,8,11,1,6,8,13,1,5,2,15,1,1,11,12,2,9,0,9,1,2,2,8,1,1,2,1,8,2,1,9,0,1,7,1,2,6,11,12,2,9,0,9,1,9,0,1,1,3,7,11,12,2,9,0,9,1,9,0,9,1,2,7,11,12,2,9,0,9,1,9,0,1,7,9,1,1,8,3,1,8,4,4,1,11,8,1,9,0,3,7,8,1,1,6,8,9,1,8,6,1,15,1,11,12,2,5,15,1,8,7,2,15,15,2,5,15,3,11,10,1,9,0,3,7,8,13,1,11,8,1,9,0,1,11,0,1,9,0,17,7,8,5,3,2,5,5,5,3,3,7,15,15,10,15,7,11,12,2,5,15,3,7,8,1,15,10,15,7,11,12,2,5,15,1,9,1,18,6,11,12,2,5,15,3,3,15,15,10,15,15,6,11,12,2,5,15,3,6,8,1,15,15,3,15,15,15,15,10,15,1,6,9,1,2,7,8,5,2,3,7,8,5,2,5,9,5,15,3,7,8,1,15,15,6,11,12,2,5,15,15,7,11,12,2,5,15,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,13,1,11,10,1,9,0,2,9,0,5,1,6,8,1,10,10,8,6,3,3,3,10,2,6,8,1,10,15,15,6,11,12,2,5,15,10,15,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,9,73,110,99,101,110,116,105,118,101,12,73,110,99,101,110,116,105,118,101,66,97,108,16,80,111,111,108,65,100,109,105,110,83,101,116,116,105,110,103,8,80,111,111,108,73,110,102,111,16,80,111,111,108,79,119,110,101,114,83,101,116,116,105,110,103,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,3,97,100,100,8,97,100,100,95,112,111,111,108,5,97,100,109,105,110,6,97,100,109,105,110,115,5,97,115,99,105,105,5,97,115,115,101,116,6,97,115,115,101,116,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,24,99,97,108,99,95,112,111,111,108,95,117,112,100,97,116,101,95,114,101,119,97,114,100,115,12,99,108,97,105,109,95,114,101,119,97,114,100,5,99,108,111,99,107,4,99,111,105,110,10,99,111,105,110,95,116,121,112,101,115,8,99,111,110,116,97,105,110,115,7,99,114,101,97,116,111,114,11,99,117,114,114,101,110,116,95,105,100,120,18,100,105,115,116,114,105,98,117,116,101,100,95,97,109,111,117,110,116,6,101,97,114,110,101,100,4,101,109,105,116,9,101,110,100,95,116,105,109,101,115,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,14,103,101,116,95,112,111,111,108,95,99,111,117,110,116,13,103,101,116,95,112,111,111,108,95,105,110,102,111,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,9,105,110,99,101,110,116,105,118,101,13,105,110,100,101,120,95,114,101,119,97,114,100,115,19,105,110,100,101,120,95,114,101,119,97,114,100,115,95,112,97,105,100,115,4,105,110,105,116,11,105,110,116,111,95,115,116,114,105,110,103,16,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,7,108,101,110,100,105,110,103,3,109,117,108,3,110,101,119,6,111,98,106,101,99,116,10,111,114,97,99,108,101,95,105,100,115,5,111,119,110,101,114,6,111,119,110,101,114,115,5,112,111,111,108,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,9,115,97,102,101,95,109,97,116,104,6,115,101,110,100,101,114,9,115,101,116,95,97,100,109,105,110,9,115,101,116,95,111,119,110,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,11,115,116,97,114,116,95,116,105,109,101,115,7,115,116,111,114,97,103,101,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,13,116,111,116,97,108,95,115,117,112,112,108,121,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,13,117,112,100,97,116,101,95,114,101,119,97,114,100,16,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,22,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,95,112,97,105,100,115,5,117,116,105,108,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,153,183,0,0,0,0,0,0,3,8,154,183,0,0,0,0,0,0,3,8,155,183,0,0,0,0,0,0,3,8,156,183,0,0,0,0,0,0,3,8,157,183,0,0,0,0,0,0,3,8,158,183,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,43,8,11,19,2,31,3,32,15,21,11,8,1,9,0,1,2,12,43,2,49,3,28,10,8,6,71,10,3,35,10,3,75,10,15,59,10,15,45,10,15,46,10,11,12,2,5,15,80,10,11,12,2,5,15,81,10,11,12,2,5,15,54,10,2,2,2,6,43,8,11,30,5,56,11,12,2,15,1,17,11,12,2,15,1,57,11,12,2,2,8,1,20,10,2,3,2,3,65,5,55,15,83,1,4,2,3,65,5,16,15,83,1,0,22,0,0,0,0,1,15,10,0,17,21,10,0,46,17,30,10,0,56,0,10,0,56,0,11,0,56,1,64,20,0,0,0,0,0,0,0,0,18,2,56,2,2,1,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,1,10,1,56,3,32,4,27,11,0,15,1,10,1,10,2,56,4,5,35,11,0,15,1,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,3,56,6,2,2,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,2,10,1,56,3,32,4,27,11,0,15,2,10,1,10,2,56,4,5,35,11,0,15,2,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,4,56,7,2,3,1,4,0,31,139,1,10,0,16,0,20,10,8,46,17,30,33,4,9,5,17,11,0,1,11,8,1,11,1,1,7,0,39,10,3,11,1,17,18,36,4,27,10,4,10,3,36,12,9,5,29,9,12,9,11,9,4,32,5,38,11,0,1,11,8,1,7,1,39,10,0,16,3,10,2,56,8,32,4,65,10,0,15,3,10,2,10,2,6,0,0,0,0,0,0,0,0,64,33,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,20,0,0,0,0,0,0,0,0,18,1,56,9,10,0,15,4,10,2,68,20,11,0,15,3,10,2,56,10,12,12,10,12,16,5,65,33,12,11,10,12,15,5,56,11,17,16,68,33,10,12,15,6,10,3,68,9,10,12,15,7,10,4,68,9,10,12,15,8,10,6,77,68,34,10,12,15,9,10,6,77,11,4,11,3,23,77,17,13,68,34,10,12,15,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,34,10,12,15,11,10,8,56,12,68,35,10,12,15,12,10,8,56,12,68,35,10,12,15,13,10,8,56,12,68,35,11,12,15,14,11,7,68,20,11,5,11,6,10,8,56,13,12,10,11,8,17,21,11,2,11,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,10,57,0,56,14,2,4,3,0,0,42,118,10,0,16,3,10,3,56,8,4,111,11,1,17,18,12,11,10,0,11,2,10,11,10,3,10,4,12,8,12,7,12,6,12,5,46,11,5,11,6,11,7,11,8,17,5,12,20,12,15,11,0,15,3,11,3,56,10,12,18,11,11,10,18,15,15,21,10,18,16,5,65,33,12,17,6,0,0,0,0,0,0,0,0,12,12,10,12,10,17,35,4,108,5,45,14,15,10,12,66,34,20,12,14,14,20,10,12,66,34,20,12,19,10,18,15,10,10,12,67,34,12,13,10,14,11,13,21,10,18,15,11,10,12,67,35,12,16,10,16,10,4,12,9,46,11,9,56,15,4,79,10,16,10,4,56,16,1,11,16,10,4,11,14,56,17,10,18,15,12,10,12,67,35,12,21,10,21,10,4,12,10,46,11,10,56,15,4,99,10,21,10,4,56,16,1,11,21,10,4,11,19,56,17,11,12,6,1,0,0,0,0,0,0,0,22,12,12,5,40,11,18,1,5,117,11,2,1,11,0,1,11,1,1,2,5,0,0,0,44,166,1,11,0,16,3,10,3,56,18,12,14,10,14,16,5,65,33,12,13,6,0,0,0,0,0,0,0,0,12,7,64,34,0,0,0,0,0,0,0,0,12,10,64,34,0,0,0,0,0,0,0,0,12,22,10,7,10,13,35,4,159,1,5,20,10,14,16,6,10,7,66,9,20,12,17,10,17,10,14,16,15,20,35,4,36,10,14,16,15,20,12,17,10,14,16,7,10,7,66,9,20,12,6,10,2,10,6,35,4,48,10,2,12,6,10,14,16,9,10,7,66,34,20,12,15,10,14,16,10,10,7,66,34,20,12,9,10,17,10,6,35,4,90,11,6,11,17,23,77,12,19,10,1,10,3,17,10,1,12,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,10,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,15,11,19,17,14,11,20,26,12,8,11,9,11,8,22,12,9,13,10,10,9,68,34,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,21,10,4,7,6,34,4,151,1,10,14,16,12,10,7,66,35,12,5,10,5,10,4,56,15,4,114,11,5,10,4,56,19,20,12,21,5,116,11,5,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,14,16,11,10,7,66,35,12,12,10,12,10,4,56,15,4,133,1,11,12,10,4,56,19,20,12,11,5,135,1,11,12,1,10,1,10,3,10,4,17,11,1,12,18,11,9,11,11,23,11,18,24,12,16,11,21,11,16,22,12,21,13,22,11,21,68,34,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,15,11,1,1,11,14,1,11,10,11,22,2,6,1,4,0,48,105,10,0,11,2,11,3,10,1,55,0,20,10,4,17,4,11,0,15,3,10,1,55,0,20,56,10,12,9,10,1,55,1,20,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,9,16,12,10,8,66,35,12,12,10,12,10,4,56,15,4,36,11,12,10,4,56,19,20,12,11,5,38,11,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,9,15,13,10,8,67,35,12,14,10,14,10,4,12,6,46,11,6,56,15,4,56,10,14,10,4,56,16,12,13,11,14,10,4,10,11,56,17,11,11,11,13,23,17,12,26,12,7,11,9,16,8,11,8,66,34,20,12,10,10,1,55,2,20,10,7,22,11,10,37,4,81,5,87,11,5,1,11,1,1,7,4,39,10,1,55,2,20,10,7,22,10,1,54,2,21,11,1,54,3,11,7,52,56,20,11,5,56,21,11,4,56,22,2,7,1,0,0,9,19,6,0,0,0,0,0,0,0,0,12,2,10,0,16,3,10,1,56,8,4,15,11,0,16,3,11,1,56,18,16,5,65,33,12,2,5,17,11,0,1,11,2,2,8,1,0,0,53,47,10,0,16,3,10,1,56,8,4,6,5,10,11,0,1,7,2,39,11,0,16,3,11,1,56,18,12,3,10,3,16,5,65,33,10,2,36,4,22,5,26,11,3,1,7,2,39,10,3,16,6,10,2,66,9,20,10,3,16,7,10,2,66,9,20,10,3,16,9,10,2,66,34,20,11,3,16,14,11,2,66,20,20,2,9,1,0,0,54,97,64,33,0,0,0,0,0,0,0,0,12,5,64,34,0,0,0,0,0,0,0,0,12,14,64,20,0,0,0,0,0,0,0,0,12,9,10,0,16,3,10,3,56,8,4,87,11,2,17,18,12,6,10,0,11,1,11,6,10,3,10,4,17,5,12,11,1,11,0,16,3,11,3,56,18,12,10,10,10,16,5,65,33,12,8,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,84,5,38,10,10,16,13,10,7,66,35,12,13,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,10,13,10,4,56,15,4,55,11,13,10,4,56,19,20,12,12,5,57,11,13,1,13,5,10,10,16,5,10,7,66,33,20,68,33,13,14,14,11,10,7,66,34,20,11,12,23,68,34,13,9,10,10,16,14,10,7,66,20,20,68,20,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,33,11,10,1,5,93,11,1,1,11,0,1,11,2,1,11,5,11,14,11,9,2,2,1,2,2,2,3,2,4,2,5,1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,1,11,1,1,0,1,0,2,0,3,0,4,16,22,17,22,18,22,19,22,0,50,0],[161,28,235,11,6,0,0,0,9,1,0,10,2,10,12,3,22,82,4,104,4,5,108,83,7,191,1,154,2,8,217,3,64,6,153,4,70,12,223,4,237,4,0,22,0,15,0,13,1,3,1,16,1,0,12,0,3,1,7,0,4,2,7,0,0,18,0,1,1,0,0,21,0,1,1,0,0,17,0,1,1,0,0,20,0,1,1,0,0,19,2,1,2,0,0,1,5,8,10,0,1,6,7,6,0,1,7,8,9,0,1,8,8,10,0,1,9,8,9,0,2,11,1,10,0,2,12,9,10,0,2,14,9,10,0,4,4,1,5,1,0,4,10,5,6,0,13,4,13,14,3,7,8,0,2,15,0,4,7,8,0,2,2,15,7,7,8,0,2,15,15,15,15,15,1,9,0,1,8,2,1,8,1,2,6,8,0,2,2,7,8,0,2,2,15,15,1,15,8,7,8,0,2,15,15,15,15,15,15,9,7,8,0,2,15,15,15,15,15,15,15,4,7,8,0,2,7,8,0,2,1,9,1,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,5,97,115,99,105,105,3,103,101,116,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,13,103,101,116,95,99,111,105,110,95,116,121,112,101,9,103,101,116,95,105,110,100,101,120,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,11,105,110,116,111,95,115,116,114,105,110,103,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,9,116,121,112,101,95,110,97,109,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,225,171,0,0,0,0,0,0,3,8,226,171,0,0,0,0,0,0,3,8,227,171,0,0,0,0,0,0,3,8,228,171,0,0,0,0,0,0,3,8,229,171,0,0,0,0,0,0,3,8,230,171,0,0,0,0,0,0,3,8,231,171,0,0,0,0,0,0,0,1,0,0,3,58,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,1,12,8,10,0,10,1,17,7,1,12,5,11,8,11,5,17,12,12,7,11,0,11,1,17,8,12,9,11,7,11,2,22,17,10,24,12,6,11,9,11,6,38,4,55,5,57,7,1,39,2,1,1,0,0,11,54,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,10,11,0,11,1,17,7,12,6,12,7,11,10,11,7,17,12,12,9,11,5,11,6,17,12,12,8,11,9,11,8,11,2,22,38,4,51,5,53,7,3,39,2,2,1,0,0,12,71,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,11,10,0,10,1,17,7,12,6,12,8,11,11,11,8,17,12,12,10,11,5,11,6,17,12,12,9,10,9,10,2,22,10,10,35,4,51,5,55,11,0,1,7,3,39,11,9,11,2,22,11,10,17,11,12,7,11,0,11,1,17,5,11,7,38,4,68,5,70,7,2,39,2,3,1,0,0,8,23,11,0,11,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,15,7,4,39,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,20,5,22,7,0,39,2,4,1,0,0,13,40,10,0,11,1,12,5,12,4,56,0,17,14,11,4,46,11,5,17,6,33,4,13,5,17,11,0,1,7,4,39,11,0,11,2,12,7,12,6,56,1,17,14,11,6,46,11,7,17,6,33,4,30,5,32,7,4,39,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,37,5,39,7,0,39,2,0],[161,28,235,11,6,0,0,0,10,1,0,20,2,20,12,3,32,220,2,4,252,2,12,5,136,3,214,2,7,222,5,205,9,8,171,15,128,1,6,171,16,60,12,231,16,222,18,15,197,35,2,0,42,0,11,0,53,0,73,0,48,0,52,3,45,1,74,2,3,2,12,2,2,12,0,6,1,8,0,9,0,8,0,0,18,0,1,1,0,0,21,2,3,1,0,0,17,2,1,1,0,0,20,2,4,1,0,0,19,5,6,2,0,0,0,57,7,1,0,0,56,8,1,0,0,55,9,1,0,0,36,10,1,0,0,15,10,1,0,0,35,10,1,0,0,14,10,1,0,0,39,11,12,0,0,64,13,14,0,0,63,15,4,0,0,16,15,4,0,0,62,11,4,0,0,65,11,4,0,0,67,16,4,0,0,61,16,4,0,0,60,17,4,0,0,66,17,4,0,0,38,17,12,0,0,40,17,12,0,0,8,18,19,0,1,4,44,4,0,1,5,9,4,0,1,6,22,4,0,1,7,22,4,0,1,9,21,4,0,1,10,44,4,0,2,14,10,1,0,2,15,10,1,0,2,22,31,4,0,2,23,9,32,0,2,24,9,22,0,2,25,9,22,0,2,26,31,3,0,2,27,9,6,0,2,28,31,28,0,2,29,27,28,0,2,30,9,22,0,2,31,9,4,0,2,32,39,40,0,2,33,17,22,0,2,34,34,1,0,2,35,10,1,0,2,36,10,1,0,2,37,21,1,0,2,50,17,1,0,2,51,17,1,0,2,55,34,1,0,2,56,33,1,0,2,58,17,1,0,2,59,17,1,0,3,68,21,1,1,0,3,69,21,1,1,0,3,70,25,1,2,0,0,3,71,21,1,1,0,3,72,21,1,1,0,4,46,1,4,0,4,47,22,4,0,4,49,22,4,0,5,44,22,4,0,7,13,46,12,1,0,8,43,1,4,0,9,54,30,3,0,56,20,59,20,55,20,58,20,57,24,64,28,5,6,8,2,7,8,0,2,5,15,0,6,6,8,2,6,8,1,7,8,0,2,5,15,1,3,1,15,7,6,8,2,6,8,1,7,8,0,5,2,2,15,3,15,15,15,2,6,8,2,7,8,0,3,6,8,2,7,8,0,2,2,7,8,0,2,4,7,8,0,2,5,15,4,6,8,2,6,8,1,7,8,0,5,1,1,4,6,8,2,6,8,1,7,8,0,10,5,1,10,15,4,6,8,2,7,8,0,6,8,1,5,5,6,8,2,6,8,1,7,8,0,2,5,3,7,8,0,2,5,7,6,8,2,7,8,0,6,8,1,5,2,2,15,6,15,15,15,15,15,1,1,9,0,3,7,8,0,2,15,2,15,15,6,15,15,1,15,15,15,2,9,0,9,1,4,7,8,0,2,2,15,2,2,2,1,6,8,0,1,2,18,2,15,15,15,15,3,15,15,3,15,15,15,15,15,15,15,15,15,1,6,8,2,2,6,8,0,2,5,15,15,15,15,15,6,7,8,0,2,15,15,3,15,4,7,8,0,2,15,15,4,15,3,3,10,15,1,5,4,15,15,15,15,9,5,6,2,15,15,10,2,3,3,15,15,2,6,8,0,5,2,10,2,10,2,9,5,2,6,2,15,10,2,3,3,15,15,7,5,6,2,3,3,15,10,2,15,3,2,15,2,4,6,8,2,6,8,1,15,2,2,5,10,2,2,6,10,9,0,6,9,0,18,2,15,15,15,15,1,15,15,15,15,15,2,15,15,15,15,15,15,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,7,105,115,95,108,111,97,110,7,108,101,110,100,105,110,103,5,108,111,103,105,99,3,109,97,120,3,109,105,110,6,111,114,97,99,108,101,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,9,115,97,102,101,95,109,97,116,104,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,19,117,112,100,97,116,101,95,115,116,97,116,101,95,111,102,95,97,108,108,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,24,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,95,98,97,116,99,104,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,33,78,0,0,0,0,0,0,3,8,34,78,0,0,0,0,0,0,3,8,35,78,0,0,0,0,0,0,3,8,36,78,0,0,0,0,0,0,3,8,37,78,0,0,0,0,0,0,3,8,38,78,0,0,0,0,0,0,0,3,0,0,1,26,11,0,10,1,17,5,10,1,10,2,10,4,56,0,10,1,10,2,10,3,11,4,17,8,10,1,10,2,10,3,17,22,32,4,22,10,1,10,2,11,3,17,53,11,1,11,2,17,7,2,1,3,0,0,22,92,10,2,10,3,10,4,17,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,16,11,2,1,11,1,1,11,0,1,7,4,39,10,0,10,2,17,5,10,2,10,3,10,5,56,1,10,2,10,3,10,4,17,20,12,7,11,5,10,7,17,63,12,6,10,2,10,3,10,4,10,6,17,9,11,0,11,1,10,2,10,4,17,12,4,44,5,48,11,2,1,7,0,39,10,6,10,7,33,4,61,10,2,10,3,10,4,17,22,4,61,10,2,10,3,10,4,17,49,10,7,10,6,36,4,86,10,7,10,6,23,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,4,86,10,2,10,3,11,7,10,6,23,17,48,10,2,10,3,10,4,17,22,4,86,10,2,10,3,11,4,17,49,11,2,11,3,17,7,11,6,52,2,2,3,0,0,1,37,10,0,10,2,17,5,10,2,10,3,10,5,56,2,10,2,10,3,10,4,11,5,17,10,10,2,10,3,10,4,17,23,32,4,22,10,2,10,3,10,4,17,54,11,0,11,1,10,2,11,4,17,12,4,29,5,33,11,2,1,7,0,39,11,2,11,3,17,7,2,3,3,0,0,6,58,10,2,10,3,10,4,17,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,14,11,2,1,11,0,1,7,5,39,11,0,10,2,17,5,10,2,10,3,10,5,56,3,10,2,10,3,10,4,17,21,12,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,5,12,8,10,6,10,5,35,4,40,10,6,12,8,11,5,10,6,23,12,7,10,2,10,3,10,4,10,8,17,11,11,8,11,6,33,4,53,10,2,10,3,11,4,17,50,11,2,11,3,17,7,11,7,2,4,3,0,0,23,92,10,2,10,5,10,3,17,23,4,6,5,14,11,2,1,11,1,1,11,0,1,7,3,39,10,2,10,4,10,3,17,22,4,20,5,28,11,2,1,11,1,1,11,0,1,7,2,39,10,0,10,2,17,5,10,2,10,5,10,4,10,6,56,4,10,0,10,1,10,2,10,3,17,12,32,4,44,5,52,11,2,1,11,1,1,11,0,1,7,1,39,11,0,10,2,11,1,10,3,10,4,10,5,11,6,17,24,12,9,12,8,12,12,12,7,12,11,12,10,10,2,10,5,10,3,11,11,17,11,10,2,10,4,10,3,11,10,17,9,11,9,4,82,10,2,10,5,11,3,17,50,10,2,11,4,17,7,11,2,11,5,17,7,11,7,11,8,11,12,2,5,0,0,0,26,25,10,1,46,17,40,12,2,49,0,12,3,10,3,10,2,35,4,20,5,11,10,0,10,1,10,3,17,6,11,3,49,1,22,12,3,5,6,11,1,1,11,0,1,2,6,0,0,0,29,97,11,0,17,66,12,8,10,1,10,2,12,3,46,11,3,17,37,12,11,10,8,11,11,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,18,10,1,10,2,17,36,12,4,12,6,10,1,10,2,17,35,12,5,12,7,10,18,11,7,17,28,10,6,17,62,12,13,11,18,11,5,17,27,10,4,17,62,12,12,10,1,10,2,17,34,1,12,14,1,1,1,10,1,10,2,17,41,12,19,12,20,10,19,10,12,10,4,23,17,62,12,9,11,20,10,13,11,6,23,17,62,12,10,11,9,10,12,17,61,12,15,11,10,10,13,17,61,12,17,11,19,10,12,11,4,23,17,62,11,14,17,62,10,12,17,61,12,16,10,1,10,2,11,12,11,13,11,8,10,16,17,52,11,1,11,2,11,17,11,15,11,16,22,17,45,2,7,0,0,0,22,15,10,0,10,1,17,26,12,2,10,0,10,1,10,2,17,29,12,3,11,0,11,1,11,2,11,3,17,51,2,8,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,47,2,9,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,32,2,10,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,46,2,11,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,31,2,12,1,0,0,1,8,11,0,11,2,11,1,11,3,17,14,17,60,38,2,13,1,0,0,35,37,14,3,65,36,12,6,6,0,0,0,0,0,0,0,0,12,5,64,4,0,0,0,0,0,0,0,0,12,7,10,5,10,6,35,4,29,5,12,10,0,10,2,10,1,14,3,10,5,66,36,20,17,14,12,4,13,7,11,4,68,4,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,7,11,2,1,11,1,1,11,0,1,11,7,2,14,1,0,0,37,33,10,0,10,2,10,1,10,3,17,16,12,6,10,0,10,1,10,2,10,3,17,15,12,5,11,0,11,2,11,1,11,3,17,17,12,7,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,29,11,6,11,7,17,61,11,5,17,62,12,4,5,31,17,65,12,4,11,4,2,15,1,0,0,38,72,10,1,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,6,0,0,0,0,0,0,0,0,12,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,10,9,10,10,35,4,56,5,22,14,8,10,9,66,28,12,5,10,1,10,5,20,17,38,12,11,1,1,10,0,10,2,10,1,11,5,20,10,3,17,19,12,12,11,6,10,12,11,11,17,62,22,12,6,11,7,11,12,22,12,7,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,17,11,1,1,11,2,1,11,0,1,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,11,6,11,7,17,61,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,16,1,0,0,41,59,10,2,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,6,0,0,0,0,0,0,0,0,12,9,10,9,10,10,35,4,51,5,20,14,8,10,9,66,28,12,6,10,2,10,6,20,12,5,46,11,5,17,33,12,11,10,0,10,1,10,2,11,6,20,10,3,17,19,12,7,11,12,11,7,11,11,17,62,22,12,12,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,15,11,2,1,11,1,1,11,0,1,11,12,2,17,1,0,0,42,49,10,2,10,3,12,4,46,11,4,17,43,12,9,1,14,9,65,28,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,41,5,20,14,9,10,6,66,28,12,5,10,0,10,1,10,2,11,5,20,10,3,17,18,12,8,11,10,11,8,22,12,10,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,15,11,2,1,11,1,1,11,0,1,11,10,2,18,1,0,0,43,18,10,2,10,3,11,4,17,21,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,19,1,0,0,43,18,10,2,10,3,11,4,17,20,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,20,1,0,0,22,15,10,0,10,1,11,2,17,44,1,12,3,11,0,11,1,17,36,1,12,4,11,3,11,4,17,62,2,21,1,0,0,22,15,10,0,10,1,11,2,17,44,12,3,1,11,0,11,1,17,36,12,4,1,11,3,11,4,17,62,2,22,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,1,12,4,14,4,14,1,56,5,2,23,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,12,4,1,14,4,14,1,56,5,2,24,0,0,0,47,113,10,1,10,4,17,38,1,12,15,12,16,10,0,10,2,10,1,10,4,10,3,17,19,11,16,17,62,12,20,10,0,10,2,10,1,10,5,11,3,17,18,12,19,9,12,12,10,19,10,20,35,4,32,11,19,12,20,8,12,12,10,1,10,5,12,7,46,11,7,17,39,12,18,10,0,10,2,11,6,11,18,17,30,12,21,10,21,10,20,36,4,54,11,21,10,20,23,12,11,5,58,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,11,21,12,20,10,20,11,15,17,62,12,8,11,1,10,4,17,42,12,22,10,8,11,22,17,62,12,23,10,20,10,23,23,12,17,10,0,10,2,10,20,10,4,17,25,12,13,10,0,10,2,11,20,10,5,17,25,12,14,10,0,10,2,11,17,10,4,17,25,12,9,10,0,10,2,11,23,11,4,17,25,12,24,11,0,11,2,11,11,11,8,22,11,5,17,25,12,10,11,13,11,14,11,9,11,24,11,10,11,12,2,0,41,0],[161,28,235,11,6,0,0,0,10,1,0,22,2,22,52,3,74,130,1,4,204,1,38,5,242,1,222,2,7,208,4,238,3,8,190,8,96,6,158,9,10,10,168,9,49,12,217,9,201,4,0,26,0,25,0,30,0,34,0,39,2,32,1,14,1,15,1,19,1,41,0,44,0,3,3,0,0,11,3,0,0,0,3,0,0,8,3,0,0,5,3,0,1,4,12,0,3,6,12,1,0,1,4,9,12,0,5,7,8,0,6,1,8,0,7,2,12,1,0,1,9,10,2,0,0,46,0,1,0,0,16,2,1,1,0,0,47,3,1,1,0,0,13,4,1,1,0,0,35,5,1,1,0,0,29,6,1,2,0,0,1,43,11,1,0,2,20,22,1,1,0,2,21,19,1,1,0,2,22,32,33,2,0,0,2,23,22,28,1,0,2,24,22,16,1,0,3,16,17,1,1,0,3,17,35,1,1,0,3,31,18,16,1,0,3,42,18,16,1,0,3,47,23,1,1,0,4,33,0,7,0,7,45,15,16,1,0,8,18,12,1,1,3,9,37,9,10,0,10,38,13,14,1,0,21,12,18,12,12,12,14,12,8,12,19,20,11,12,15,12,16,12,19,24,7,12,19,26,10,12,19,29,9,31,15,34,16,34,13,34,19,36,1,6,8,7,0,8,6,8,9,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,5,7,8,11,9,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,5,7,8,5,7,8,11,7,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,7,8,11,8,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,11,12,6,8,9,6,8,8,7,8,7,2,7,11,6,1,9,0,2,7,11,6,1,9,1,11,10,1,9,0,5,3,7,8,5,7,8,11,1,1,5,3,3,3,5,11,10,1,9,0,1,6,8,11,1,5,5,7,8,5,6,8,9,7,8,7,2,5,1,9,0,3,11,10,1,9,0,3,7,8,11,1,11,10,1,9,0,1,6,11,10,1,9,0,1,3,3,7,11,6,1,9,0,11,10,1,9,0,7,8,11,2,6,11,6,1,9,0,3,5,6,8,9,7,8,7,2,5,15,1,8,0,6,3,3,3,3,3,5,6,6,8,9,6,8,8,7,8,7,2,5,15,4,7,11,6,1,9,0,3,5,7,8,11,1,8,1,3,3,3,5,1,8,2,8,3,3,15,3,3,3,5,11,10,1,9,0,1,15,1,8,3,14,3,3,3,3,15,15,3,3,3,3,3,5,11,10,1,9,0,15,2,9,0,9,1,7,6,8,9,6,8,8,7,8,7,5,2,2,15,3,15,15,15,1,9,1,2,7,11,6,1,9,0,3,1,8,4,11,66,111,114,114,111,119,69,118,101,110,116,5,67,108,111,99,107,4,67,111,105,110,12,68,101,112,111,115,105,116,69,118,101,110,116,9,73,110,99,101,110,116,105,118,101,20,76,105,113,117,105,100,97,116,105,111,110,67,97,108,108,69,118,101,110,116,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,112,97,121,69,118,101,110,116,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,13,87,105,116,104,100,114,97,119,69,118,101,110,116,6,97,109,111,117,110,116,6,98,111,114,114,111,119,5,99,108,111,99,107,4,99,111,105,110,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,9,105,110,99,101,110,116,105,118,101,7,108,101,110,100,105,110,103,16,108,105,113,117,105,100,97,116,101,95,97,109,111,117,110,116,14,108,105,113,117,105,100,97,116,101,95,117,115,101,114,16,108,105,113,117,105,100,97,116,105,111,110,95,99,97,108,108,5,108,111,103,105,99,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,5,112,97,117,115,101,4,112,111,111,108,5,114,101,112,97,121,7,114,101,115,101,114,118,101,6,115,101,110,100,101,114,10,115,112,108,105,116,95,99,111,105,110,7,115,116,111,114,97,103,101,2,116,111,10,116,120,95,99,111,110,116,101,120,116,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,13,117,112,100,97,116,101,95,114,101,119,97,114,100,5,117,116,105,108,115,5,118,97,108,117,101,15,119,104,101,110,95,110,111,116,95,112,97,117,115,101,100,8,119,105,116,104,100,114,97,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,41,160,0,0,0,0,0,0,0,2,3,36,2,37,5,12,3,1,2,4,36,2,37,5,40,5,12,3,2,2,3,36,2,37,5,12,3,3,2,3,36,2,37,5,12,3,4,2,4,36,2,37,5,28,5,27,3,0,0,0,0,1,8,11,0,17,17,32,4,5,5,7,7,0,39,2,1,1,4,0,8,45,10,1,46,17,0,10,7,46,17,20,12,11,11,6,10,0,10,1,10,3,10,11,17,6,11,4,11,5,10,7,56,0,12,12,14,12,56,1,12,9,10,2,11,12,11,7,56,2,11,2,10,9,12,8,46,11,8,56,3,12,10,11,0,11,1,10,3,10,11,11,10,77,56,4,11,3,11,11,11,9,18,0,56,5,2,2,1,4,0,21,50,10,2,46,17,0,10,8,46,17,20,12,14,11,7,10,0,10,2,10,4,10,14,17,6,10,3,11,5,12,9,46,11,9,56,3,12,13,11,0,11,1,11,2,10,4,11,14,11,13,77,56,6,12,11,10,3,11,11,12,10,46,11,10,56,7,12,12,11,3,10,12,10,6,10,8,56,8,11,4,11,8,46,17,20,11,6,11,12,18,1,56,9,2,3,1,4,0,25,35,10,2,46,17,0,10,6,46,17,20,12,9,10,3,10,5,12,7,46,11,7,56,3,12,8,11,0,11,1,11,2,10,4,10,9,11,8,77,56,10,11,3,10,5,11,9,10,6,56,8,11,4,11,6,46,17,20,11,5,18,2,56,11,2,4,1,4,0,27,65,10,2,46,17,0,10,7,46,17,20,12,14,11,5,11,6,10,7,56,0,12,15,14,15,56,1,12,13,10,3,11,15,10,7,56,2,10,3,10,13,12,8,46,11,8,56,3,12,12,11,0,11,1,11,2,10,4,10,14,11,12,77,56,12,12,10,10,3,11,10,52,12,9,46,11,9,56,7,12,11,10,11,6,0,0,0,0,0,0,0,0,36,4,53,11,3,10,11,11,14,10,7,56,8,5,55,11,3,1,11,4,11,7,46,17,20,11,13,11,11,23,18,3,56,13,2,5,1,4,0,30,90,10,2,46,17,0,10,11,46,17,20,12,23,11,10,10,0,10,2,10,5,10,8,17,6,11,7,11,9,10,11,56,0,12,24,14,24,56,1,12,18,10,4,11,24,10,11,56,2,10,4,11,18,12,12,46,11,12,56,3,12,21,11,0,11,1,11,2,10,8,10,5,11,3,11,21,77,56,14,12,25,12,17,12,16,10,4,11,17,52,12,13,46,11,13,56,7,12,20,11,4,11,20,10,23,10,11,56,8,10,6,11,16,52,12,14,46,11,14,56,15,12,19,10,6,10,19,10,23,11,11,56,16,10,6,11,25,52,12,15,46,11,15,56,15,12,22,11,6,10,22,56,17,11,5,11,23,11,8,11,19,11,22,22,18,4,56,18,2,0]],["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"],"0xb2345915de1f9bd661e9ab27eb27e376cdf6391359ea64fbfdb4550b092c1aa0",{"Result":0}]},{"MoveCall":{"package":"0x0000000000000000000000000000000000000000000000000000000000000002","module":"package","function":"commit_upgrade","type_arguments":[],"arguments":[{"Input":0},{"Result":1}]}}]}},"modified_at_versions":[["0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1",26932892],["0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623",10941462]],"shared_object_refs":[],"gas":[["0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1",26932892,"Ex867bCQkeiTCvcRqhkbAtZWPyVPcMbNRj1acbfyZdAs"]],"gas_budget":300000000,"gas_price":750,"executed_epoch":158,"dependencies":["3fqrGiknVvk82qum6zLYR749UTTyavaoH8TLU6bym8di","5rr1KbGr5ht2kWrPwgArYuaYsauoDG8CpuJLnaKnkgL6","7SuYS2Zphhb7KFnoanQBArUmXUQjKhehZ5fQkET4wNcN","ACKQVv64dXCmpxE1QPU2QMLxVpmtbzrFGMtWYY6szJrQ","BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn"],"effects":{"messageVersion":"v1","status":{"status":"success"},"executedEpoch":"158","gasUsed":{"computationCost":"750000","storageCost":"216204800","storageRebate":"2595780","nonRefundableStorageFee":"26220"},"modifiedAtVersions":[{"objectId":"0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1","sequenceNumber":"26932892"},{"objectId":"0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623","sequenceNumber":"10941462"}],"transactionDigest":"4fxF3X4N8D6JGByWdbJvCCv1iuoT8GSEhXgPHJnzNHWP","created":[{"owner":"Immutable","reference":{"objectId":"0x0440aedc27c9a57ea357bd8fe1525a00d60d7f442a380924a7e7c1d79853bb8b","version":5,"digest":"Gm4LuFuwBvgmBuLSMAxEp2zkp1RLsfgwzv8xdscmzowH"}}],"mutated":[{"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"reference":{"objectId":"0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1","version":26932893,"digest":"J4QwR5VqcZDAekVtbABBjvZ6n1sCi4nDS7hBiaDkex37"}},{"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"reference":{"objectId":"0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623","version":26932893,"digest":"Bt3M5wQ3RStRoKWwioJ8vJUQvxL453r9HWBH2MpBzQaA"}}],"gasObject":{"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"reference":{"objectId":"0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1","version":26932893,"digest":"J4QwR5VqcZDAekVtbABBjvZ6n1sCi4nDS7hBiaDkex37"}},"dependencies":["3fqrGiknVvk82qum6zLYR749UTTyavaoH8TLU6bym8di","5rr1KbGr5ht2kWrPwgArYuaYsauoDG8CpuJLnaKnkgL6","7SuYS2Zphhb7KFnoanQBArUmXUQjKhehZ5fQkET4wNcN","ACKQVv64dXCmpxE1QPU2QMLxVpmtbzrFGMtWYY6szJrQ","BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn"]},"protocol_version":23,"epoch_start_timestamp":1694970685122,"reference_gas_price":750},"required_objects":[{"data":{"Move":{"type_":"GasCoin","has_public_transfer":true,"version":26932892,"contents":[179,30,221,225,60,75,107,81,44,23,235,191,230,227,135,11,211,138,190,145,151,205,207,128,30,246,4,231,19,97,15,161,200,98,235,223,0,0,0,0]}},"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"previous_transaction":"7SuYS2Zphhb7KFnoanQBArUmXUQjKhehZ5fQkET4wNcN","storage_rebate":988000},{"data":{"Move":{"type_":{"Other":{"address":"0000000000000000000000000000000000000000000000000000000000000002","module":"package","name":"UpgradeCap","type_args":[]}},"has_public_transfer":true,"version":10941462,"contents":[219,161,180,15,53,55,68,27,81,210,132,143,192,161,73,97,14,72,230,124,28,196,140,106,214,65,118,118,34,0,6,35,178,52,89,21,222,31,155,214,97,233,171,39,235,39,227,118,205,246,57,19,89,234,100,251,253,180,85,11,9,44,26,160,4,0,0,0,0,0,0,0,0]}},"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"previous_transaction":"3fqrGiknVvk82qum6zLYR749UTTyavaoH8TLU6bym8di","storage_rebate":1634000},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000001","version":2,"module_map":{"address":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,3,7,10,15,8,25,32,12,57,16,0,0,0,1,0,1,0,0,1,3,7,97,100,100,114,101,115,115,6,108,101,110,103,116,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,6,32,0,0,0,0,0,0,0,2,0],"ascii":[161,28,235,11,6,0,0,0,11,1,0,4,2,4,14,3,18,84,4,102,8,5,110,59,7,169,1,200,1,8,241,2,32,6,145,3,10,10,155,3,11,12,166,3,186,2,13,224,5,4,0,5,0,16,0,2,7,0,0,0,7,0,1,1,7,1,0,0,0,8,0,1,0,0,20,2,3,0,0,21,2,4,0,0,3,5,6,0,0,18,7,8,0,0,17,9,1,0,0,14,5,10,0,0,4,5,11,0,0,10,3,2,0,0,6,1,0,0,0,13,0,6,0,0,11,0,6,0,1,9,13,14,1,0,1,12,12,6,1,0,1,15,8,13,1,0,1,19,14,13,1,0,13,3,12,3,14,3,15,3,1,2,1,8,1,1,10,2,1,8,0,1,11,2,1,8,0,1,6,8,0,1,1,2,7,8,0,8,1,0,1,7,8,0,1,3,1,6,10,2,1,6,11,2,1,9,0,1,11,2,1,9,0,1,9,0,2,3,3,4,67,104,97,114,6,79,112,116,105,111,110,6,83,116,114,105,110,103,24,97,108,108,95,99,104,97,114,97,99,116,101,114,115,95,112,114,105,110,116,97,98,108,101,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,4,98,121,116,101,5,98,121,116,101,115,4,99,104,97,114,12,100,101,115,116,114,111,121,95,115,111,109,101,10,105,110,116,111,95,98,121,116,101,115,17,105,115,95,112,114,105,110,116,97,98,108,101,95,99,104,97,114,7,105,115,95,115,111,109,101,13,105,115,95,118,97,108,105,100,95,99,104,97,114,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,8,112,111,112,95,99,104,97,114,9,112,117,115,104,95,99,104,97,114,4,115,111,109,101,6,115,116,114,105,110,103,10,116,114,121,95,115,116,114,105,110,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,1,0,0,0,0,0,0,2,1,7,10,2,1,2,1,6,2,0,1,0,0,8,9,10,0,17,10,4,4,5,6,7,0,39,11,0,18,1,2,1,1,0,0,4,12,11,0,17,2,12,1,14,1,56,0,4,7,5,9,7,0,39,11,1,56,1,2,2,1,0,0,15,30,14,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,25,5,11,14,0,10,1,66,0,20,17,10,32,4,20,56,2,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,5,40,11,0,18,0,56,3,2,3,1,0,0,15,32,10,0,16,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,29,5,12,10,0,16,0,10,1,66,0,20,17,11,32,4,24,11,0,1,9,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,40,8,2,4,1,0,0,8,7,11,0,15,0,14,1,16,1,20,68,0,2,5,1,0,0,8,5,11,0,15,0,69,0,18,1,2,6,1,0,0,8,4,11,0,17,7,65,0,2,7,1,0,0,8,3,11,0,16,0,2,8,1,0,0,8,3,11,0,19,0,2,9,1,0,0,8,3,11,0,19,1,2,10,1,0,0,8,4,11,0,49,127,37,2,11,1,0,0,6,13,10,0,49,32,38,4,9,11,0,49,126,37,12,1,5,11,9,12,1,11,1,2,0,0,1,0,0],"bcs":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,7,7,15,13,8,28,32,12,60,4,0,0,0,1,0,1,1,0,1,6,9,0,1,10,2,3,98,99,115,8,116,111,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,0],"bit_vector":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,36,7,77,109,8,186,1,32,6,218,1,40,10,130,2,8,12,138,2,239,3,13,249,5,4,0,2,0,0,7,0,0,6,0,1,0,0,7,2,3,0,0,9,2,3,0,0,8,2,3,0,0,3,4,5,0,0,4,6,0,0,0,5,4,0,0,1,3,1,8,0,2,7,8,0,3,0,2,6,8,0,3,1,1,1,6,8,0,2,10,1,3,1,7,1,5,3,7,1,3,3,3,9,66,105,116,86,101,99,116,111,114,9,98,105,116,95,102,105,101,108,100,10,98,105,116,95,118,101,99,116,111,114,12,105,115,95,105,110,100,101,120,95,115,101,116,6,108,101,110,103,116,104,32,108,111,110,103,101,115,116,95,115,101,116,95,115,101,113,117,101,110,99,101,95,115,116,97,114,116,105,110,103,95,97,116,3,110,101,119,3,115,101,116,10,115,104,105,102,116,95,108,101,102,116,5,117,110,115,101,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,3,8,1,0,2,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,4,0,0,0,0,0,0,0,2,2,4,3,1,10,1,0,1,0,0,7,37,10,0,6,0,0,0,0,0,0,0,0,36,4,5,5,7,7,1,39,10,0,7,3,35,4,12,5,14,7,1,39,6,0,0,0,0,0,0,0,0,12,2,64,5,0,0,0,0,0,0,0,0,12,1,40,10,2,10,0,35,4,32,5,24,13,1,9,68,5,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,18,40,11,0,11,1,18,0,2,1,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,8,11,2,21,2,2,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,9,11,2,21,2,3,1,0,0,9,89,10,1,10,0,16,1,20,38,4,33,10,0,16,0,65,5,12,6,6,0,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,30,5,17,10,0,15,0,10,4,67,5,12,3,9,11,3,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,12,11,0,1,5,88,10,1,12,5,10,5,10,0,16,1,20,35,4,65,5,42,10,0,10,5,12,2,46,11,2,17,4,4,55,10,0,10,5,10,1,23,17,1,5,60,10,0,10,5,10,1,23,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,35,10,0,16,1,20,11,1,23,12,5,10,5,10,0,16,1,20,35,4,86,5,78,10,0,10,5,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,71,11,0,1,2,4,1,0,0,3,17,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,16,0,11,1,66,5,20,2,5,1,0,0,3,4,11,0,16,0,65,5,2,6,1,0,0,0,37,10,1,10,0,16,1,20,35,4,7,5,11,11,0,1,7,0,39,10,1,12,2,10,2,10,0,16,1,20,35,4,33,5,20,10,0,10,2,17,4,32,4,28,11,0,1,5,33,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,13,11,2,11,1,23,2,0,1,0,0,0],"debug":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,11,5,13,5,7,18,30,8,48,32,12,80,8,0,0,0,1,0,1,1,0,0,2,1,1,0,1,6,9,0,0,5,100,101,98,117,103,5,112,114,105,110,116,17,112,114,105,110,116,95,115,116,97,99,107,95,116,114,97,99,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"fixed_point32":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,30,5,36,22,7,58,122,8,180,1,32,6,212,1,68,10,152,2,5,12,157,2,137,2,13,166,4,2,0,4,0,0,7,0,0,7,0,1,0,0,3,0,1,0,0,1,2,3,0,0,2,1,3,0,0,5,3,1,0,0,6,3,4,0,2,3,8,0,1,3,2,3,3,1,8,0,1,1,1,4,4,1,4,4,4,0,12,70,105,120,101,100,80,111,105,110,116,51,50,20,99,114,101,97,116,101,95,102,114,111,109,95,114,97,116,105,111,110,97,108,21,99,114,101,97,116,101,95,102,114,111,109,95,114,97,119,95,118,97,108,117,101,10,100,105,118,105,100,101,95,117,54,52,13,102,105,120,101,100,95,112,111,105,110,116,51,50,13,103,101,116,95,114,97,119,95,118,97,108,117,101,7,105,115,95,122,101,114,111,12,109,117,108,116,105,112,108,121,95,117,54,52,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,16,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,3,8,1,0,1,0,0,0,0,0,3,8,2,0,2,0,0,0,0,0,3,8,3,0,2,0,0,0,0,0,3,8,4,0,1,0,0,0,0,0,3,8,5,0,2,0,0,0,0,0,0,2,1,8,3,0,1,0,0,5,20,11,0,53,14,1,16,0,20,53,24,49,32,48,12,2,10,2,7,0,37,4,15,5,17,7,3,39,11,2,52,2,1,1,0,0,5,29,14,1,16,0,20,6,0,0,0,0,0,0,0,0,34,4,7,5,9,7,4,39,11,0,53,49,32,47,14,1,16,0,20,53,26,12,2,10,2,7,0,37,4,24,5,26,7,2,39,11,2,52,2,2,1,0,0,6,48,10,0,53,49,64,47,12,5,11,1,53,49,32,47,12,4,10,4,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,15,5,17,7,1,39,11,5,11,4,26,12,3,10,3,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,8,12,2,5,32,11,0,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,35,5,37,7,5,39,10,3,7,0,37,4,42,5,44,7,5,39,11,3,52,18,0,2,3,1,0,0,7,3,11,0,18,0,2,4,1,0,0,7,4,14,0,16,0,20,2,5,1,0,0,7,6,14,0,16,0,20,6,0,0,0,0,0,0,0,0,33,2,0,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,3,7,15,23,8,38,32,12,70,8,0,0,0,1,0,0,0,0,2,0,0,0,1,10,2,4,104,97,115,104,8,115,104,97,50,95,50,53,54,8,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"option":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,6,3,10,120,4,130,1,14,5,144,1,135,1,7,151,2,219,1,8,242,3,32,6,146,4,20,10,166,4,7,11,173,4,2,12,175,4,128,4,13,175,8,2,14,177,8,2,0,15,0,22,0,0,7,1,0,0,0,14,0,1,1,0,0,17,2,1,1,0,0,12,3,4,1,0,0,13,3,4,1,0,0,4,5,4,1,0,0,1,3,6,1,0,0,3,5,6,1,0,0,10,7,2,1,3,0,9,8,0,1,0,0,8,9,2,1,0,0,2,9,10,1,0,0,18,8,2,1,0,0,19,8,1,1,0,0,7,11,2,1,2,0,6,1,2,1,0,0,5,1,0,1,0,0,20,1,12,1,0,1,4,14,4,1,0,1,11,13,4,1,0,1,16,2,12,1,0,19,2,18,2,17,2,3,2,0,2,1,2,2,2,0,1,11,0,1,9,0,1,9,0,1,6,11,0,1,9,0,1,1,2,6,11,0,1,9,0,6,9,0,1,6,9,0,2,6,11,0,1,9,0,9,0,2,7,11,0,1,9,0,9,0,1,7,11,0,1,9,0,1,7,9,0,2,11,0,1,9,0,9,0,1,10,9,0,1,6,10,9,0,2,6,10,9,0,6,9,0,2,6,9,0,6,10,9,0,2,9,0,6,10,9,0,1,7,10,9,0,2,9,0,7,10,9,0,3,11,0,1,9,0,11,0,1,9,0,7,10,9,0,2,9,0,10,9,0,6,79,112,116,105,111,110,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,119,105,116,104,95,100,101,102,97,117,108,116,8,99,111,110,116,97,105,110,115,12,100,101,115,116,114,111,121,95,110,111,110,101,12,100,101,115,116,114,111,121,95,115,111,109,101,20,100,101,115,116,114,111,121,95,119,105,116,104,95,100,101,102,97,117,108,116,7,101,120,116,114,97,99,116,4,102,105,108,108,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,4,110,111,110,101,6,111,112,116,105,111,110,9,115,105,110,103,108,101,116,111,110,4,115,111,109,101,4,115,119,97,112,12,115,119,97,112,95,111,114,95,102,105,108,108,6,116,111,95,118,101,99,3,118,101,99,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,4,0,0,0,0,0,3,8,1,0,4,0,0,0,0,0,0,2,1,21,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,0,4,11,0,55,0,56,1,2,3,1,0,0,0,5,11,0,55,0,56,1,32,2,4,1,0,0,0,5,11,0,55,0,11,1,56,2,2,5,1,0,0,0,13,10,0,56,3,4,4,5,8,11,0,1,7,1,39,11,0,55,0,6,0,0,0,0,0,0,0,0,66,2,2,6,1,0,0,15,19,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,17,11,1,1,11,3,6,0,0,0,0,0,0,0,0,66,2,12,2,11,2,2,7,1,0,0,16,18,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,16,11,3,6,0,0,0,0,0,0,0,0,66,2,20,12,2,11,2,2,8,1,0,0,17,16,11,0,54,0,12,2,10,2,46,56,1,4,8,5,12,11,2,1,7,0,39,11,2,11,1,68,2,2,9,1,0,0,0,13,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,69,2,2,10,1,0,0,0,14,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,6,0,0,0,0,0,0,0,0,67,2,2,11,1,0,0,18,20,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,12,3,10,3,69,2,12,2,11,3,11,1,68,2,11,2,2,12,1,0,0,19,21,11,0,54,0,12,4,10,4,46,56,1,4,10,56,4,12,2,5,14,10,4,69,2,56,5,12,2,11,2,12,3,11,4,11,1,68,2,11,3,2,13,1,0,0,20,15,11,0,58,0,12,3,13,3,46,56,1,4,10,11,1,12,2,5,13,13,3,69,2,12,2,11,2,2,14,1,0,0,20,16,14,0,56,3,4,4,5,6,7,1,39,11,0,58,0,12,2,13,2,69,2,12,1,11,2,70,2,0,0,0,0,0,0,0,0,11,1,2,15,1,0,0,0,10,14,0,56,6,4,4,5,6,7,0,39,11,0,58,0,70,2,0,0,0,0,0,0,0,0,2,16,1,0,0,0,3,11,0,58,0,2,0,0,0,2,0],"string":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,14,3,22,114,4,136,1,8,5,144,1,123,7,139,2,248,1,8,131,4,32,6,163,4,20,10,183,4,6,12,189,4,133,3,13,194,7,2,0,19,0,4,0,17,0,24,0,1,7,0,1,1,7,0,2,0,7,1,0,0,0,23,0,1,0,0,6,2,1,0,0,21,1,2,0,0,22,0,3,0,0,5,4,5,0,0,14,4,6,0,0,15,4,7,0,0,2,8,9,0,0,3,10,9,0,0,8,11,9,0,0,20,12,1,0,0,7,13,7,0,0,9,5,6,0,0,11,14,6,0,0,12,15,0,0,0,10,16,7,0,1,13,2,0,0,1,19,0,2,0,2,16,9,18,1,0,2,18,17,18,1,0,3,2,21,9,1,0,3,14,20,6,1,0,19,1,18,1,21,19,20,19,1,10,2,1,8,0,1,8,1,1,11,2,1,8,0,1,6,8,0,1,6,10,2,1,1,1,3,2,7,8,0,8,0,0,2,7,8,0,10,2,3,7,8,0,3,8,0,3,6,8,0,3,3,2,6,8,0,6,8,0,2,6,10,2,3,3,6,10,2,3,3,2,6,10,2,6,10,2,1,9,0,1,11,2,1,9,0,1,2,1,6,10,9,0,2,7,10,9,0,10,9,0,8,1,3,3,3,6,10,2,8,0,8,0,3,5,1,1,1,6,10,2,3,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,97,112,112,101,110,100,11,97,112,112,101,110,100,95,117,116,102,56,5,97,115,99,105,105,5,98,121,116,101,115,10,102,114,111,109,95,97,115,99,105,105,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,19,105,110,116,101,114,110,97,108,95,99,104,101,99,107,95,117,116,102,56,17,105,110,116,101,114,110,97,108,95,105,110,100,101,120,95,111,102,25,105,110,116,101,114,110,97,108,95,105,115,95,99,104,97,114,95,98,111,117,110,100,97,114,121,19,105,110,116,101,114,110,97,108,95,115,117,98,95,115,116,114,105,110,103,10,105,110,116,111,95,98,121,116,101,115,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,4,115,111,109,101,6,115,116,114,105,110,103,10,115,117,98,95,115,116,114,105,110,103,8,116,111,95,97,115,99,105,105,8,116,114,121,95,117,116,102,56,4,117,116,102,56,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,5,10,2,0,1,0,0,9,9,14,0,17,12,4,4,5,6,7,0,39,11,0,18,0,2,1,1,0,0,9,4,11,0,17,16,18,0,2,2,1,0,0,9,4,11,0,19,0,17,17,2,3,1,0,0,3,12,14,0,17,12,4,8,11,0,18,0,56,0,12,1,5,10,56,1,12,1,11,1,2,4,1,0,0,9,3,11,0,16,0,2,5,1,0,0,9,4,11,0,16,0,56,2,2,6,1,0,0,9,4,11,0,16,0,65,19,2,7,1,0,0,9,7,11,0,15,0,14,1,16,0,20,56,3,2,8,1,0,0,9,5,11,0,11,1,17,0,17,7,2,9,1,0,0,22,56,10,0,16,0,12,7,10,1,10,7,65,19,37,4,13,11,7,10,1,17,13,12,3,5,17,11,7,1,9,12,3,11,3,4,20,5,24,11,0,1,7,1,39,10,0,46,17,6,12,10,10,0,10,1,12,4,46,6,0,0,0,0,0,0,0,0,11,4,17,10,12,9,10,0,11,1,11,10,12,6,12,5,46,11,5,11,6,17,10,12,8,13,9,11,2,17,7,13,9,11,8,17,7,11,9,11,0,21,2,10,1,0,0,23,48,11,0,16,0,12,6,10,6,65,19,12,7,10,2,11,7,37,4,15,10,1,10,2,37,12,3,5,17,9,12,3,11,3,4,24,10,6,10,1,17,13,12,4,5,26,9,12,4,11,4,4,33,10,6,10,2,17,13,12,5,5,35,9,12,5,11,5,4,38,5,42,11,6,1,7,1,39,11,6,11,1,11,2,17,14,18,0,2,11,1,0,0,9,6,11,0,16,0,11,1,16,0,17,15,2,12,0,2,0,13,0,2,0,14,0,2,0,15,0,2,0,0,0,0],"type_name":[161,28,235,11,6,0,0,0,10,1,0,6,2,6,8,3,14,47,5,61,44,7,105,143,1,8,248,1,32,6,152,2,7,10,159,2,6,12,165,2,215,1,13,252,3,2,0,14,0,2,0,4,0,1,7,0,2,0,7,0,0,6,0,1,1,0,0,9,0,1,1,0,0,5,2,3,0,0,7,2,4,0,0,8,2,4,0,0,10,1,4,0,1,11,0,6,0,2,3,3,7,0,2,13,9,4,0,0,1,8,0,1,6,8,0,1,6,8,1,1,8,1,4,10,2,3,3,6,10,2,1,3,1,6,10,2,1,2,1,10,2,5,2,6,2,3,10,2,6,10,2,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,13,98,111,114,114,111,119,95,115,116,114,105,110,103,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,11,105,110,116,111,95,115,116,114,105,110,103,6,108,101,110,103,116,104,4,110,97,109,101,6,115,116,114,105,110,103,9,116,121,112,101,95,110,97,109,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,58,10,2,1,0,0,2,1,12,8,1,0,1,2,0,1,1,2,0,2,1,0,0,0,3,11,0,16,0,2,3,1,0,0,5,33,17,6,6,2,0,0,0,0,0,0,0,24,12,3,11,0,16,0,17,7,12,4,7,1,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,28,5,17,13,1,10,4,10,2,66,8,20,68,8,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,4,1,11,1,17,8,2,4,1,0,0,10,39,17,6,6,2,0,0,0,0,0,0,0,24,6,2,0,0,0,0,0,0,0,22,12,3,11,0,16,0,17,7,12,5,7,1,12,4,10,5,10,3,66,8,12,2,7,0,12,1,10,2,14,1,34,4,32,5,23,13,4,11,2,20,68,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,12,11,5,1,11,2,1,11,4,17,8,2,5,1,0,0,0,4,14,0,16,0,20,2,0,0,0],"vector":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,102,4,104,4,5,108,97,7,205,1,154,1,8,231,2,32,6,135,3,10,12,145,3,216,4,0,17,0,5,0,1,1,0,0,9,2,3,1,0,0,1,4,5,1,0,0,11,6,0,1,0,0,2,7,8,1,0,0,10,9,10,1,0,0,4,1,0,1,0,0,15,11,0,1,0,0,14,10,1,1,0,0,13,9,0,1,0,0,0,12,0,1,0,0,8,2,13,1,0,0,3,14,13,1,0,0,6,14,15,1,0,0,12,7,10,1,0,0,7,16,0,1,0,0,16,7,10,1,0,9,10,11,10,0,1,10,9,0,1,6,10,9,0,1,3,2,6,10,9,0,3,1,6,9,0,2,7,10,9,0,9,0,2,7,10,9,0,3,1,7,9,0,1,7,10,9,0,1,9,0,3,7,10,9,0,3,3,2,7,10,9,0,10,9,0,1,1,2,6,10,9,0,6,9,0,2,1,3,3,7,10,9,0,9,0,3,3,3,3,3,2,3,3,3,3,7,10,9,0,3,6,97,112,112,101,110,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,5,101,109,112,116,121,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,7,114,101,118,101,114,115,101,9,115,105,110,103,108,101,116,111,110,4,115,119,97,112,11,115,119,97,112,95,114,101,109,111,118,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,2,0,4,1,2,0,5,1,2,0,6,1,2,0,7,1,2,0,8,1,0,0,1,7,64,10,0,0,0,0,0,0,0,0,12,1,13,1,11,0,68,10,11,1,2,9,1,0,0,17,38,10,0,46,65,10,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,2,6,0,0,0,0,0,0,0,0,12,2,11,3,6,1,0,0,0,0,0,0,0,23,12,1,10,2,10,1,35,4,35,5,22,10,0,10,2,10,1,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,1,6,1,0,0,0,0,0,0,0,23,12,1,5,17,11,0,1,2,10,1,0,0,0,17,13,1,56,0,14,1,56,1,32,4,12,5,7,10,0,13,1,69,10,68,10,5,2,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,11,1,0,0,0,5,11,0,65,10,6,0,0,0,0,0,0,0,0,33,2,12,1,0,0,18,33,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,27,5,10,10,0,10,2,66,10,10,1,33,4,22,11,0,1,11,1,1,8,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,2,13,1,0,0,18,35,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,28,5,10,10,0,10,2,66,10,10,1,33,4,23,11,0,1,11,1,1,8,11,2,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,6,0,0,0,0,0,0,0,0,2,14,1,0,0,19,37,10,0,46,65,10,12,4,10,1,10,4,38,4,12,11,0,1,7,0,39,11,4,6,1,0,0,0,0,0,0,0,23,12,4,10,1,10,4,35,4,34,5,21,10,0,12,3,10,1,12,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,11,3,11,2,10,1,71,10,5,16,11,0,69,10,2,15,1,0,0,3,32,10,0,46,65,10,12,3,10,2,10,3,36,4,12,11,0,1,7,0,39,10,0,11,1,68,10,10,2,10,3,35,4,29,5,20,10,0,10,2,10,3,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,2,16,1,0,0,3,23,10,0,46,56,1,32,4,6,5,10,11,0,1,7,0,39,10,0,46,65,10,6,1,0,0,0,0,0,0,0,23,12,2,10,0,11,1,11,2,71,10,11,0,69,10,2,0]},"type_origin_table":[{"module_name":"fixed_point32","struct_name":"FixedPoint32","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"option","struct_name":"Option","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"Char","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"bit_vector","struct_name":"BitVector","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"string","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"type_name","struct_name":"TypeName","package":"0x0000000000000000000000000000000000000000000000000000000000000001"}],"linkage_table":{}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000002","version":10,"module_map":{"address":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,8,3,18,61,4,79,2,5,81,20,7,101,129,1,8,230,1,64,6,166,2,54,12,220,2,69,0,1,1,2,1,3,1,11,0,8,1,0,7,0,3,0,7,0,0,15,0,1,0,0,7,1,0,0,0,6,2,0,0,0,13,0,2,0,0,12,0,3,0,0,14,0,4,0,0,9,5,6,0,0,10,5,1,0,1,11,2,3,0,2,13,7,2,1,0,3,5,3,4,0,4,4,2,2,0,9,0,1,5,1,15,1,10,2,1,8,0,1,8,1,0,1,3,1,6,9,0,6,83,116,114,105,110,103,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,6,101,110,99,111,100,101,10,102,114,111,109,95,97,115,99,105,105,10,102,114,111,109,95,98,121,116,101,115,9,102,114,111,109,95,117,50,53,54,3,104,101,120,6,108,101,110,103,116,104,3,109,97,120,6,115,116,114,105,110,103,15,116,111,95,97,115,99,105,105,95,115,116,114,105,110,103,8,116,111,95,98,121,116,101,115,9,116,111,95,115,116,114,105,110,103,7,116,111,95,117,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,32,0,0,0,0,0,0,0,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,3,8,0,0,0,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,0,0,5,3,14,0,56,0,2,4,1,0,0,5,5,11,0,17,3,17,11,17,8,2,5,1,0,0,5,4,11,0,17,4,17,10,2,6,1,0,0,5,2,7,0,2,7,1,0,0,5,2,7,1,2,0],"bag":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,112,4,132,1,12,5,144,1,82,7,226,1,185,1,8,155,3,32,6,187,3,10,10,197,3,8,12,205,3,230,1,13,179,5,4,0,4,0,11,0,18,0,21,0,0,12,0,2,2,4,0,3,1,2,0,0,17,0,1,0,0,3,2,3,2,7,4,0,5,4,5,2,7,4,0,6,6,7,2,7,4,0,19,6,8,2,7,4,0,7,4,9,1,7,0,8,4,9,2,7,4,0,16,10,11,0,0,15,10,9,0,0,10,1,3,0,1,3,14,3,2,7,4,1,5,15,5,2,7,4,1,6,16,7,2,7,4,1,12,15,9,1,7,1,13,15,9,2,7,4,1,19,16,8,2,7,4,2,9,12,3,0,2,17,0,12,0,10,13,11,13,12,13,15,13,13,17,14,13,1,7,8,2,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,1,9,0,2,8,1,3,3,66,97,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,3,98,97,103,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,14,8,1,20,3,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,18,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,0,0,0,1,0],"balance":[161,28,235,11,6,0,0,0,14,1,0,4,2,4,16,3,20,83,4,103,2,5,105,99,7,204,1,224,1,8,172,3,32,6,204,3,74,10,150,4,10,11,160,4,4,12,164,4,219,2,13,255,6,4,14,131,7,4,15,135,7,2,0,3,0,16,0,1,4,1,0,1,0,0,4,1,0,1,1,2,2,0,0,17,0,1,1,0,0,15,2,1,1,0,0,5,3,4,1,2,0,10,5,6,1,0,0,6,7,1,1,0,0,19,8,6,1,0,0,11,9,1,1,0,0,13,10,6,1,0,0,18,11,6,1,0,0,9,6,8,1,0,0,4,12,6,1,0,0,7,13,8,1,0,0,8,4,1,1,0,1,12,14,15,0,7,3,1,6,11,1,1,9,0,1,3,1,6,11,0,1,9,0,1,9,0,1,11,0,1,9,0,2,7,11,0,1,9,0,3,1,11,1,1,9,0,2,7,11,0,1,9,0,11,1,1,9,0,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,7,11,1,1,9,0,2,3,6,8,2,2,11,1,1,9,0,6,8,2,1,6,8,2,1,5,7,66,97,108,97,110,99,101,6,83,117,112,112,108,121,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,22,99,114,101,97,116,101,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,115,13,99,114,101,97,116,101,95,115,117,112,112,108,121,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,23,100,101,115,116,114,111,121,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,12,100,101,115,116,114,111,121,95,122,101,114,111,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,4,106,111,105,110,6,115,101,110,100,101,114,5,115,112,108,105,116,3,115,117,105,12,115,117,112,112,108,121,95,118,97,108,117,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,17,3,1,2,1,17,3,0,3,1,3,0,1,0,0,8,4,11,0,55,0,20,2,1,1,0,0,8,4,11,0,55,1,20,2,2,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,0,2,3,1,0,0,8,24,10,1,6,255,255,255,255,255,255,255,255,10,0,55,1,20,23,35,4,9,5,13,11,0,1,7,1,39,10,0,55,1,20,10,1,22,11,0,54,1,21,11,1,57,1,2,4,1,0,0,1,24,11,1,58,1,12,2,10,0,55,1,20,10,2,38,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,10,2,23,11,0,54,1,21,11,2,2,5,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,1,2,6,1,0,0,1,15,11,1,58,1,12,2,10,0,55,0,20,11,2,22,10,0,54,0,21,11,0,55,0,20,2,7,1,0,0,8,22,10,0,55,0,20,10,1,38,4,7,5,11,11,0,1,7,2,39,10,0,55,0,20,10,1,23,11,0,54,0,21,11,1,57,1,2,8,1,0,0,1,8,10,0,55,0,20,12,1,11,0,11,1,56,0,2,9,1,0,0,8,13,14,0,55,0,20,6,0,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,11,0,58,1,1,2,10,0,0,0,8,11,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,57,1,2,11,0,0,0,8,12,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,58,1,1,2,12,3,0,0,8,3,11,0,58,0,2,1,0,0,0,0,3,1,3,0,14,0],"bcs":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,10,3,20,135,1,4,155,1,24,5,179,1,131,1,7,182,2,222,2,8,148,5,64,6,212,5,55,10,139,6,6,12,145,6,203,8,13,220,14,2,0,3,1,3,1,10,1,31,0,2,0,0,7,0,2,1,7,1,0,0,0,30,0,1,1,0,0,8,1,2,0,0,6,2,1,0,0,11,3,4,0,0,12,3,5,0,0,20,3,6,0,0,19,3,7,0,0,18,3,8,0,0,23,3,7,0,0,21,3,9,0,0,22,3,10,0,0,26,3,1,0,0,27,3,11,0,0,25,3,12,0,0,24,3,13,0,0,13,3,14,0,0,14,3,15,0,0,17,3,16,0,0,16,3,17,0,0,15,3,18,0,1,30,0,1,1,0,2,9,19,33,1,0,2,29,20,33,1,0,3,28,21,19,1,0,4,5,1,4,0,4,7,19,7,0,20,20,23,6,22,4,21,4,22,5,21,5,22,6,21,6,22,7,21,7,22,8,21,8,1,6,9,0,1,10,2,1,8,0,1,7,8,0,1,5,1,1,1,2,1,3,1,4,1,10,5,1,10,1,1,10,10,2,1,10,3,1,10,4,1,11,1,1,5,1,11,1,1,1,1,11,1,1,2,1,11,1,1,3,1,11,1,1,4,0,1,9,0,1,7,10,9,0,2,10,2,3,2,1,2,3,3,2,3,3,4,2,4,4,3,3,2,3,3,3,3,10,5,3,3,3,10,1,3,3,3,10,2,3,3,3,10,10,2,3,3,3,10,3,3,3,3,10,4,1,11,1,1,9,0,3,66,67,83,6,79,112,116,105,111,110,7,97,100,100,114,101,115,115,3,98,99,115,5,98,121,116,101,115,10,102,114,111,109,95,98,121,116,101,115,20,105,110,116,111,95,114,101,109,97,105,110,100,101,114,95,98,121,116,101,115,6,108,101,110,103,116,104,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,12,112,101,101,108,95,97,100,100,114,101,115,115,9,112,101,101,108,95,98,111,111,108,19,112,101,101,108,95,111,112,116,105,111,110,95,97,100,100,114,101,115,115,16,112,101,101,108,95,111,112,116,105,111,110,95,98,111,111,108,16,112,101,101,108,95,111,112,116,105,111,110,95,117,49,50,56,15,112,101,101,108,95,111,112,116,105,111,110,95,117,54,52,14,112,101,101,108,95,111,112,116,105,111,110,95,117,56,9,112,101,101,108,95,117,49,50,56,8,112,101,101,108,95,117,54,52,7,112,101,101,108,95,117,56,16,112,101,101,108,95,118,101,99,95,97,100,100,114,101,115,115,13,112,101,101,108,95,118,101,99,95,98,111,111,108,15,112,101,101,108,95,118,101,99,95,108,101,110,103,116,104,13,112,101,101,108,95,118,101,99,95,117,49,50,56,12,112,101,101,108,95,118,101,99,95,117,54,52,11,112,101,101,108,95,118,101,99,95,117,56,15,112,101,101,108,95,118,101,99,95,118,101,99,95,117,56,7,114,101,118,101,114,115,101,4,115,111,109,101,8,116,111,95,98,121,116,101,115,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,10,5,1,0,10,1,1,0,10,2,1,0,10,10,2,1,0,10,3,1,0,10,4,1,0,0,2,1,4,10,2,0,1,0,0,19,3,11,0,56,0,2,1,1,0,0,19,5,13,0,56,1,11,0,18,0,2,2,1,0,0,1,7,11,0,19,0,12,1,13,1,56,1,11,1,2,3,1,0,0,22,35,10,0,16,0,65,6,17,25,38,4,7,5,11,11,0,1,7,0,39,64,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,12,2,12,1,10,2,17,25,35,4,30,5,20,13,1,10,0,15,0,69,6,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,11,1,17,24,2,4,1,0,0,23,21,11,0,17,5,12,2,10,2,49,0,33,4,10,9,12,1,5,19,11,2,49,1,33,4,15,5,17,7,1,39,8,12,1,11,1,2,5,1,0,0,19,15,10,0,16,0,65,6,6,1,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,11,0,15,0,69,6,2,6,1,0,0,24,40,10,0,16,0,65,6,6,8,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,64,35,4,36,5,20,10,0,15,0,69,6,52,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,7,1,0,0,25,40,10,0,16,0,65,6,6,16,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,128,35,4,36,5,20,10,0,15,0,69,6,53,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,8,1,0,0,26,48,6,0,0,0,0,0,0,0,0,49,0,6,0,0,0,0,0,0,0,0,12,2,12,3,12,4,10,2,6,4,0,0,0,0,0,0,0,37,4,11,5,15,11,0,1,7,2,39,10,0,15,0,69,6,52,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,4,10,1,6,127,0,0,0,0,0,0,0,28,10,3,47,27,12,4,11,1,6,128,0,0,0,0,0,0,0,28,6,0,0,0,0,0,0,0,0,33,4,39,5,44,11,3,49,7,22,12,3,5,6,11,0,1,11,4,2,9,1,0,0,27,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,3,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,3,68,4,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,10,1,0,0,28,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,4,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,4,68,5,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,11,1,0,0,29,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,5,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,5,68,6,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,12,1,0,0,30,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,6,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,11,68,1,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,13,1,0,0,31,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,7,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,6,68,7,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,14,1,0,0,32,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,8,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,7,68,8,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,15,1,0,0,14,14,10,0,17,4,4,8,11,0,17,3,56,2,12,1,5,12,11,0,1,56,3,12,1,11,1,2,16,1,0,0,15,14,10,0,17,4,4,8,11,0,17,4,56,4,12,1,5,12,11,0,1,56,5,12,1,11,1,2,17,1,0,0,16,14,10,0,17,4,4,8,11,0,17,5,56,6,12,1,5,12,11,0,1,56,7,12,1,11,1,2,18,1,0,0,17,14,10,0,17,4,4,8,11,0,17,6,56,8,12,1,5,12,11,0,1,56,9,12,1,11,1,2,19,1,0,0,18,14,10,0,17,4,4,8,11,0,17,7,56,10,12,1,5,12,11,0,1,56,11,12,1,11,1,2,0,0,0],"bls12381":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,12,7,24,56,8,80,32,12,112,8,0,0,0,2,0,1,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,8,98,108,115,49,50,51,56,49,22,98,108,115,49,50,51,56,49,95,109,105,110,95,112,107,95,118,101,114,105,102,121,23,98,108,115,49,50,51,56,49,95,109,105,110,95,115,105,103,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"borrow":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,24,3,32,59,4,91,10,5,101,83,7,184,1,158,1,8,214,2,64,6,150,3,20,10,170,3,19,11,189,3,2,12,191,3,125,13,188,4,4,14,192,4,4,0,5,1,15,0,14,0,19,0,3,4,1,12,0,0,0,0,0,1,2,7,1,0,0,2,1,7,0,3,4,2,0,0,12,0,1,1,12,0,5,2,3,1,12,0,16,4,5,1,12,0,6,1,6,1,12,1,7,9,6,1,0,1,8,11,6,1,0,1,9,15,5,1,0,1,18,6,9,1,0,2,11,12,13,1,8,3,10,7,8,0,7,6,5,6,8,6,6,6,4,6,2,9,0,7,8,4,1,11,0,1,9,0,1,7,11,0,1,9,0,2,9,0,8,1,3,7,11,0,1,9,0,9,0,8,1,0,1,9,0,1,7,8,4,1,5,1,11,2,1,9,0,2,8,3,9,0,1,7,11,2,1,9,0,1,6,9,0,1,8,3,2,8,3,5,2,7,11,2,1,9,0,9,0,6,66,111,114,114,111,119,2,73,68,6,79,112,116,105,111,110,8,82,101,102,101,114,101,110,116,9,84,120,67,111,110,116,101,120,116,6,98,111,114,114,111,119,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,7,101,120,116,114,97,99,116,4,102,105,108,108,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,3,111,98,106,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,117,116,95,98,97,99,107,3,114,101,102,4,115,111,109,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,2,11,5,20,11,2,1,9,0,1,2,2,17,5,13,8,3,0,6,0,1,0,0,5,6,11,1,17,9,11,0,56,0,57,0,2,1,1,0,0,10,14,10,0,54,0,56,1,12,2,14,2,56,2,12,1,11,2,11,0,55,1,20,11,1,18,1,2,2,1,0,0,14,30,11,2,19,1,12,3,12,4,14,1,56,2,11,3,33,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,11,4,33,4,21,5,25,11,0,1,7,0,39,11,0,54,0,11,1,56,3,2,3,1,0,0,9,7,11,0,58,0,12,1,1,11,1,56,4,2,0,1,0,0,0,6,1,6,0],"clock":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,31,4,51,2,5,53,30,7,83,122,8,205,1,32,6,237,1,44,10,153,2,8,12,161,2,79,13,240,2,2,0,3,0,7,0,11,0,12,0,0,8,0,1,2,4,0,3,1,2,0,0,10,0,1,0,0,5,2,3,0,0,4,4,3,0,1,3,3,6,0,2,9,8,3,1,8,3,8,2,5,0,4,7,1,6,8,0,1,3,1,6,8,2,0,3,7,8,0,3,6,8,2,1,5,1,8,1,1,8,0,1,9,0,5,67,108,111,99,107,9,84,120,67,111,110,116,101,120,116,3,85,73,68,5,99,108,111,99,107,25,99,111,110,115,101,110,115,117,115,95,99,111,109,109,105,116,95,112,114,111,108,111,103,117,101,6,99,114,101,97,116,101,2,105,100,6,111,98,106,101,99,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,1,10,3,0,1,0,0,3,4,11,0,16,0,20,2,1,0,0,0,3,13,11,0,17,5,7,1,33,4,6,5,8,7,0,39,17,3,6,0,0,0,0,0,0,0,0,18,0,56,0,2,2,0,0,0,3,15,11,2,17,5,7,1,33,4,6,5,10,11,0,1,7,0,39,11,1,11,0,15,0,21,2,0,1,0],"coin":[161,28,235,11,6,0,0,0,13,1,0,20,2,20,62,3,82,155,2,4,237,2,34,5,143,3,221,2,7,236,5,164,5,8,144,11,64,6,208,11,30,10,238,11,52,11,162,12,6,12,168,12,249,4,13,161,17,14,14,175,17,14,0,15,1,11,1,43,1,48,0,12,0,42,0,56,0,58,0,59,0,64,0,1,12,1,0,1,0,2,12,1,0,1,0,7,12,1,0,1,0,3,3,1,0,1,1,5,7,0,2,4,7,1,0,0,3,5,7,0,4,0,4,1,0,1,4,6,4,1,0,1,5,9,4,0,7,8,2,0,9,10,7,0,0,55,0,1,1,0,0,57,2,3,1,0,0,50,0,4,1,0,0,51,5,6,1,0,0,66,7,1,1,0,0,12,7,8,1,0,0,13,9,10,1,0,0,24,11,12,1,0,0,33,12,13,1,0,0,54,14,12,1,0,0,45,15,16,1,0,0,35,17,16,1,0,0,47,18,12,1,0,0,23,18,19,1,0,0,67,20,12,1,0,0,22,12,16,1,0,0,16,21,22,1,2,0,36,23,12,1,0,0,38,24,13,1,0,0,14,25,1,1,0,0,37,26,16,1,0,0,62,27,16,1,0,0,63,28,16,1,0,0,60,27,16,1,0,0,61,28,16,1,0,0,25,29,30,1,0,0,28,29,31,1,0,0,29,29,32,1,0,0,26,29,31,1,0,0,27,29,33,1,0,0,49,5,4,1,0,1,48,41,32,0,2,46,34,46,1,0,3,65,41,31,0,4,17,34,3,1,2,4,19,43,1,1,0,4,22,13,16,1,0,4,32,42,13,1,0,4,35,37,1,1,0,4,47,36,13,1,0,4,52,4,1,1,0,4,66,8,1,1,0,4,67,16,13,1,0,5,20,35,16,0,5,40,20,35,0,6,44,44,16,1,12,8,34,39,40,1,2,9,41,32,45,0,40,34,41,34,39,34,8,34,38,34,9,34,4,34,12,34,42,34,36,34,46,34,34,34,37,34,35,34,17,34,45,12,32,45,1,6,11,2,1,9,0,1,3,1,11,2,1,9,0,1,11,8,1,9,0,1,6,11,8,1,9,0,1,7,11,2,1,9,0,1,7,11,8,1,9,0,1,6,11,0,1,9,0,1,6,11,7,1,9,0,1,7,11,0,1,9,0,1,7,11,7,1,9,0,2,11,7,1,9,0,7,8,10,1,11,0,1,9,0,1,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,10,2,7,11,7,1,9,0,11,0,1,9,0,0,2,7,11,0,1,9,0,11,0,1,9,0,3,7,11,0,1,9,0,3,7,8,10,1,10,11,0,1,9,0,1,7,8,10,7,9,0,2,10,2,10,2,10,2,11,5,1,8,11,7,8,10,2,11,2,1,9,0,11,1,1,9,0,3,7,11,2,1,9,0,3,7,8,10,2,7,11,2,1,9,0,3,2,7,11,2,1,9,0,11,0,1,9,0,4,7,11,2,1,9,0,3,5,7,8,10,3,6,11,2,1,9,0,7,11,1,1,9,0,8,6,3,6,11,2,1,9,0,7,11,1,1,9,0,8,4,1,6,11,1,1,9,0,1,2,1,8,6,1,8,4,1,11,5,1,8,11,1,9,0,1,8,9,2,7,11,7,1,9,0,3,2,7,11,7,1,9,0,11,7,1,9,0,3,3,3,10,11,0,1,9,0,1,6,9,0,1,1,1,10,2,2,7,11,8,1,9,0,3,2,7,11,8,1,9,0,11,7,1,9,0,2,9,0,5,1,8,11,1,11,5,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,15,67,117,114,114,101,110,99,121,67,114,101,97,116,101,100,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,85,114,108,5,97,115,99,105,105,7,98,97,108,97,110,99,101,11,98,97,108,97,110,99,101,95,109,117,116,4,98,117,114,110,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,13,99,114,101,97,116,101,95,115,117,112,112,108,121,8,100,101,99,105,109,97,108,115,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,6,100,101,108,101,116,101,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,122,101,114,111,13,100,105,118,105,100,101,95,105,110,116,111,95,110,12,102,114,111,109,95,98,97,108,97,110,99,101,12,103,101,116,95,100,101,99,105,109,97,108,115,15,103,101,116,95,100,101,115,99,114,105,112,116,105,111,110,12,103,101,116,95,105,99,111,110,95,117,114,108,8,103,101,116,95,110,97,109,101,10,103,101,116,95,115,121,109,98,111,108,8,105,99,111,110,95,117,114,108,2,105,100,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,12,105,110,116,111,95,98,97,108,97,110,99,101,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,4,106,111,105,110,4,109,105,110,116,17,109,105,110,116,95,97,110,100,95,116,114,97,110,115,102,101,114,12,109,105,110,116,95,98,97,108,97,110,99,101,4,110,97,109,101,3,110,101,119,10,110,101,119,95,117,110,115,97,102,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,3,112,117,116,4,115,111,109,101,5,115,112,108,105,116,6,115,116,114,105,110,103,6,115,117,112,112,108,121,12,115,117,112,112,108,121,95,105,109,109,117,116,10,115,117,112,112,108,121,95,109,117,116,12,115,117,112,112,108,121,95,118,97,108,117,101,6,115,121,109,98,111,108,4,116,97,107,101,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,5,116,121,112,101,115,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,15,117,112,100,97,116,101,95,105,99,111,110,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,13,117,112,100,97,116,101,95,115,121,109,98,111,108,3,117,114,108,4,117,116,102,56,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,2,31,8,9,12,11,7,1,9,0,1,2,6,31,8,9,18,2,39,8,6,53,8,4,21,8,6,30,11,5,1,8,11,2,2,2,31,8,9,55,11,8,1,9,0,3,2,1,18,2,2,34,0,34,1,34,0,1,0,0,16,4,11,0,55,0,56,0,2,1,1,0,0,3,6,11,0,58,0,12,1,17,43,11,1,2,2,1,0,0,16,3,11,0,55,0,2,3,1,0,0,16,3,11,0,54,0,2,4,1,0,0,16,4,11,0,55,1,56,1,2,5,1,0,0,16,3,11,0,55,1,2,6,1,0,0,16,3,11,0,54,1,2,7,1,0,0,16,5,11,1,17,44,11,0,57,1,2,8,1,0,0,13,6,11,0,58,1,12,1,17,43,11,1,2,9,1,0,0,16,7,11,2,17,44,11,0,11,1,56,2,57,1,2,10,1,0,0,16,6,11,0,11,1,56,3,56,4,1,2,11,1,4,0,13,10,11,1,58,1,12,2,17,43,11,0,54,1,11,2,56,4,1,2,12,1,0,0,16,6,11,0,54,1,11,1,11,2,56,5,2,13,1,0,0,38,59,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,11,11,0,1,11,2,1,7,1,39,10,1,10,0,46,56,6,37,4,18,5,24,11,0,1,11,2,1,7,2,39,64,12,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,3,10,0,46,56,6,10,1,26,12,4,40,10,3,10,1,6,1,0,0,0,0,0,0,0,23,35,4,53,5,42,13,5,10,0,10,4,10,2,56,7,68,12,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,34,11,0,1,11,2,1,11,5,2,14,1,0,0,16,5,11,0,17,44,56,8,57,1,2,15,1,0,0,13,7,11,0,58,1,12,1,17,43,11,1,56,9,2,16,1,0,0,16,25,14,0,56,10,4,4,5,8,11,6,1,7,0,39,10,6,17,44,11,0,56,11,57,0,11,6,17,44,11,1,11,3,17,33,11,2,17,31,11,4,17,33,11,5,57,2,2,17,1,0,0,16,8,11,2,17,44,11,0,54,0,11,1,56,12,57,1,2,18,1,0,0,16,5,11,0,54,0,11,1,56,12,2,19,1,4,0,13,9,11,1,58,1,12,2,17,43,11,0,54,0,11,2,56,13,2,20,1,4,0,16,7,11,0,11,1,11,3,56,14,11,2,56,15,2,21,1,4,0,16,5,11,2,11,1,54,2,21,2,22,1,4,0,16,5,11,2,11,1,54,3,21,2,23,1,4,0,16,5,11,2,11,1,54,4,21,2,24,1,4,0,16,7,11,2,17,47,56,16,11,1,54,5,21,2,25,1,0,0,16,4,11,0,55,6,20,2,26,1,0,0,16,4,11,0,55,2,20,2,27,1,0,0,16,4,11,0,55,3,20,2,28,1,0,0,16,4,11,0,55,4,20,2,29,1,0,0,16,4,11,0,55,5,20,2,30,1,0,0,16,3,11,0,55,0,2,2,1,0,1,1,2,1,3,1,4,1,5,1,1,0,34,1,34,2,34,3,34,4,34,5,34,6,34,0],"display":[161,28,235,11,6,0,0,0,13,1,0,16,2,16,46,3,62,132,1,4,194,1,22,5,216,1,196,1,7,156,3,223,2,8,251,5,64,6,187,6,20,10,207,6,38,11,245,6,6,12,251,6,160,3,13,155,10,6,14,161,10,6,0,14,1,31,0,18,0,26,0,27,0,32,0,33,0,36,0,0,12,1,8,1,0,1,3,1,8,1,0,8,3,1,8,1,1,4,7,0,3,2,7,0,3,6,4,0,4,3,12,0,6,5,2,0,7,7,7,2,1,0,0,0,0,24,0,1,1,8,0,25,2,1,1,8,0,12,0,3,1,8,0,35,4,3,1,8,0,9,5,3,1,8,0,11,6,3,1,8,0,15,5,3,1,8,0,29,7,3,1,8,0,23,8,9,1,8,0,37,10,11,1,8,0,19,10,12,1,8,0,13,13,1,1,8,0,10,5,3,1,8,2,16,14,3,1,3,3,24,13,28,0,3,34,21,22,0,4,20,8,9,1,0,5,28,19,3,1,12,6,30,17,18,0,7,17,3,30,2,1,0,7,22,31,3,2,1,0,7,29,26,27,2,1,0,8,14,11,14,0,14,12,14,17,1,13,23,21,25,16,14,13,29,19,25,20,25,2,6,8,6,7,8,7,1,11,0,1,9,0,4,6,8,6,10,8,3,10,8,3,7,8,7,0,1,7,11,0,1,9,0,3,7,11,0,1,9,0,8,3,8,3,3,7,11,0,1,9,0,10,8,3,10,8,3,2,7,11,0,1,9,0,8,3,1,6,8,6,1,1,1,6,11,0,1,9,0,1,13,1,6,11,8,2,8,3,8,3,1,7,8,7,1,9,0,3,11,0,1,9,0,3,3,1,8,3,1,6,8,7,1,5,2,9,0,5,2,13,11,8,2,8,3,8,3,1,6,8,5,1,8,4,1,11,2,1,9,0,2,3,3,2,8,3,8,3,2,7,11,8,2,9,0,9,1,6,9,0,2,9,0,9,1,1,8,5,1,11,1,1,9,0,1,11,8,2,9,0,9,1,3,7,11,8,2,9,0,9,1,9,0,9,1,7,68,105,115,112,108,97,121,14,68,105,115,112,108,97,121,67,114,101,97,116,101,100,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,6,86,101,99,77,97,112,14,86,101,114,115,105,111,110,85,112,100,97,116,101,100,3,97,100,100,12,97,100,100,95,105,110,116,101,114,110,97,108,12,97,100,100,95,109,117,108,116,105,112,108,101,15,99,114,101,97,116,101,95,97,110,100,95,107,101,101,112,15,99,114,101,97,116,101,95,105,110,116,101,114,110,97,108,7,100,105,115,112,108,97,121,4,101,100,105,116,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,6,102,105,101,108,100,115,12,102,114,111,109,95,112,97,99,107,97,103,101,2,105,100,6,105,110,115,101,114,116,13,105,115,95,97,117,116,104,111,114,105,122,101,100,3,110,101,119,15,110,101,119,95,119,105,116,104,95,102,105,101,108,100,115,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,6,115,101,110,100,101,114,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,112,100,97,116,101,95,118,101,114,115,105,111,110,7,118,101,99,95,109,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,3,21,8,5,19,11,8,2,8,3,8,3,37,13,1,2,1,21,8,4,2,2,3,21,8,4,37,13,19,11,8,2,8,3,8,3,2,14,1,14,0,14,0,1,0,0,3,11,11,0,56,0,4,4,5,8,11,1,1,7,0,39,11,1,56,1,2,1,1,0,0,15,43,14,1,65,16,12,6,10,6,14,2,65,16,33,4,9,5,15,11,0,1,11,3,1,7,1,39,6,0,0,0,0,0,0,0,0,12,5,11,0,11,3,56,2,12,4,10,5,10,6,35,4,41,5,26,13,4,14,1,10,5,66,16,20,14,2,10,5,66,16,20,56,3,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,21,11,4,2,2,1,4,0,3,8,11,0,10,1,56,2,11,1,46,17,18,56,4,2,3,1,4,0,20,24,10,0,55,0,20,72,1,0,22,10,0,54,0,21,10,0,55,0,20,12,1,10,0,55,1,20,12,2,11,0,55,2,17,15,11,1,11,2,57,0,56,5,2,4,1,4,0,3,5,11,0,11,1,11,2,56,3,2,5,1,4,0,24,38,14,1,65,16,12,4,10,4,14,2,65,16,33,4,9,5,13,11,0,1,7,1,39,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,35,5,20,10,0,14,1,10,3,66,16,20,14,2,10,3,66,16,20,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,15,11,0,1,2,6,1,4,0,3,11,10,0,54,1,14,1,56,6,1,1,11,0,11,1,11,2,56,3,2,7,1,4,0,3,7,11,0,54,1,14,1,56,6,1,1,2,8,1,0,0,3,3,11,0,56,7,2,9,1,0,0,3,4,11,0,55,0,20,2,10,1,0,0,3,3,11,0,55,1,2,11,0,0,0,28,12,11,0,17,14,12,1,14,1,17,15,57,1,56,8,11,1,56,9,72,0,0,57,2,2,12,0,0,0,3,6,11,0,54,1,11,1,11,2,56,10,2,0,2,0,1,0,0,0,14,1,14,2,14,0],"dynamic_field":[161,28,235,11,6,0,0,0,14,1,0,6,2,6,22,3,28,133,1,4,161,1,24,5,185,1,168,1,7,225,2,129,3,8,226,5,64,6,162,6,40,10,202,6,12,11,214,6,2,12,216,6,235,2,13,195,9,6,14,201,9,8,15,209,9,2,0,11,1,26,0,25,0,0,8,2,7,0,4,0,1,2,7,1,0,0,2,1,7,0,2,3,4,0,0,4,0,1,2,7,4,0,6,2,3,2,7,4,0,9,4,5,2,7,4,0,27,4,6,2,7,4,0,13,2,7,1,7,0,29,4,8,2,7,4,0,14,2,7,2,7,4,0,15,2,9,1,7,0,16,4,10,1,7,0,19,11,12,1,7,0,5,11,1,1,8,0,7,9,13,1,8,0,8,10,14,1,8,0,28,15,16,1,8,0,17,15,7,0,0,18,15,7,1,8,1,24,1,24,1,0,1,30,16,24,1,0,2,10,19,1,0,2,21,28,12,0,2,23,12,19,0,2,31,18,12,0,9,16,10,21,11,21,12,21,13,21,4,16,3,20,17,6,16,6,15,21,11,26,12,26,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,9,1,2,6,8,3,5,2,7,8,3,5,2,5,9,0,1,5,1,6,9,0,1,7,9,0,2,5,5,1,9,0,3,11,0,2,9,0,9,1,5,5,1,6,8,3,1,8,3,2,9,0,9,1,1,11,0,2,9,0,9,1,3,5,5,9,1,2,9,0,11,1,1,9,1,1,11,1,1,9,0,4,6,11,0,2,9,0,8,2,5,6,8,3,6,8,2,1,11,0,2,9,0,8,2,2,9,0,8,2,1,6,8,2,4,7,11,0,2,9,0,8,2,5,7,8,3,7,8,2,5,70,105,101,108,100,2,73,68,6,79,112,116,105,111,110,3,85,73,68,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,6,100,101,108,101,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,16,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,17,104,97,115,104,95,116,121,112,101,95,97,110,100,95,107,101,121,2,105,100,13,105,100,95,116,111,95,97,100,100,114,101,115,115,4,110,97,109,101,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,3,20,8,3,22,9,0,32,9,1,0,20,0,1,0,0,17,26,11,0,46,17,21,12,5,10,5,10,1,56,0,12,4,10,5,10,4,17,14,32,4,14,5,16,7,0,39,11,4,17,20,11,1,11,2,57,0,12,3,11,5,11,3,56,1,2,1,1,0,0,12,10,10,0,17,21,11,1,56,0,12,2,11,0,11,2,56,2,55,0,2,2,1,0,0,12,11,10,0,46,17,21,11,1,56,0,12,2,11,0,11,2,56,3,54,0,2,3,1,0,0,22,17,11,0,46,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,4,58,0,12,4,1,17,18,11,4,2,4,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,17,14,2,5,1,0,0,23,19,10,0,10,1,12,2,46,11,2,56,5,4,13,11,0,11,1,56,6,56,7,12,3,5,17,11,0,1,56,8,12,3,11,3,2,6,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,9,2,7,3,0,0,25,22,10,0,17,21,11,1,56,0,12,3,11,0,11,3,56,10,12,2,10,2,55,1,12,4,10,2,55,2,1,11,2,55,3,12,5,11,4,11,5,17,19,2,8,3,0,0,29,24,10,0,46,17,21,11,1,56,0,12,3,11,0,11,3,56,11,12,2,10,2,54,1,12,4,10,2,54,2,1,11,2,54,3,12,5,11,4,11,5,46,17,19,2,9,3,2,0,10,3,2,0,11,3,2,0,12,3,2,0,13,3,2,0,14,3,2,0,15,3,2,0,0,2,0,0,0,1,0,20,1,27,2,27,0,27,0,12,0],"dynamic_object_field":[161,28,235,11,6,0,0,0,10,1,0,8,2,8,20,3,28,138,1,4,166,1,26,5,192,1,131,1,7,195,2,178,2,8,245,4,64,10,181,5,6,11,187,5,2,12,189,5,233,1,0,11,1,22,0,10,0,21,0,3,7,1,0,0,1,1,7,1,0,0,3,0,7,0,3,2,4,0,0,4,0,1,2,7,12,0,6,2,3,2,7,12,0,9,4,5,2,7,12,0,23,4,6,2,7,12,0,12,2,7,1,7,0,13,2,7,2,7,12,0,17,2,8,1,7,1,20,1,24,1,0,1,25,10,24,1,0,2,4,0,1,2,7,4,2,5,18,1,1,8,2,7,15,11,1,8,2,8,19,20,1,8,2,13,2,7,2,7,4,2,14,2,15,1,7,2,15,4,19,1,7,2,16,22,7,1,8,2,23,4,6,2,7,4,2,24,22,10,1,8,3,17,11,12,1,8,3,18,17,12,0,3,26,16,17,0,19,6,9,13,14,14,10,6,11,6,15,14,12,6,18,6,17,13,13,13,16,6,7,12,8,12,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,8,2,3,11,0,1,9,0,8,2,11,0,1,9,0,1,9,0,1,6,9,0,1,8,2,2,11,0,1,9,0,8,2,1,11,0,1,9,0,2,6,8,3,5,1,6,8,3,1,5,2,5,9,0,2,7,8,3,5,1,7,9,0,4,11,0,1,9,0,11,0,1,9,0,9,1,5,2,5,5,2,11,0,1,9,0,5,1,11,1,1,9,0,2,73,68,6,79,112,116,105,111,110,3,85,73,68,7,87,114,97,112,112,101,114,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,4,110,97,109,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,19,9,0,0,10,0,1,0,0,9,21,11,1,57,0,12,5,14,2,56,0,12,4,10,0,10,5,11,4,56,1,11,0,11,5,12,3,46,11,3,56,2,1,17,21,11,2,56,3,2,1,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,2,56,4,2,2,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,5,56,6,2,3,1,0,0,21,20,11,1,57,0,12,3,10,0,10,3,12,2,46,11,2,56,2,12,5,17,21,11,5,56,7,12,4,11,0,11,3,56,8,1,11,4,2,4,1,0,0,14,7,11,1,57,0,12,2,11,0,11,2,56,9,2,5,1,0,0,23,20,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,9,2,11,0,11,2,56,2,12,3,17,21,11,3,56,10,2,6,1,0,0,23,21,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,56,11,2,11,0,11,2,56,2,12,3,1,11,3,17,20,56,12,2,0],"ecdsa_k1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,15,5,17,28,7,45,64,8,109,32,6,141,1,26,12,167,1,12,0,1,0,2,0,1,0,0,0,2,1,0,0,3,3,4,0,3,6,10,2,6,10,2,2,1,10,2,1,6,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,17,100,101,99,111,109,112,114,101,115,115,95,112,117,98,107,101,121,8,101,99,100,115,97,95,107,49,19,115,101,99,112,50,53,54,107,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,107,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,2,1,2,0,0],"ecdsa_r1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,10,5,12,24,7,36,46,8,82,32,6,114,26,12,140,1,8,0,0,0,1,0,1,0,0,2,2,3,0,3,6,10,2,6,10,2,2,1,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,8,101,99,100,115,97,95,114,49,19,115,101,99,112,50,53,54,114,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,114,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,0],"ecvrf":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,5,5,7,15,7,22,19,8,41,32,6,73,30,12,103,4,0,0,0,1,0,1,0,4,6,10,2,6,10,2,6,10,2,6,10,2,1,1,5,101,99,118,114,102,12,101,99,118,114,102,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,1,2,0,0],"ed25519":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,12,7,19,23,8,42,32,12,74,4,0,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,7,101,100,50,53,53,49,57,14,101,100,50,53,53,49,57,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"event":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,4,7,12,11,8,23,32,12,55,4,0,1,0,0,0,1,1,3,1,9,0,0,4,101,109,105,116,5,101,118,101,110,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"groth16":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,16,3,18,50,5,68,76,7,144,1,237,2,8,253,3,32,6,157,4,30,10,187,4,32,12,219,4,180,1,13,143,6,14,0,10,0,0,7,0,0,1,7,0,0,3,7,0,0,2,7,0,0,5,0,1,0,0,6,0,1,0,0,16,2,3,0,0,17,3,4,0,0,15,5,6,0,0,14,5,7,0,0,12,8,3,0,0,13,9,3,0,0,18,10,11,0,0,19,12,11,0,0,1,8,0,4,10,2,10,2,10,2,10,2,1,8,1,1,10,10,2,1,10,2,1,8,2,1,8,3,2,6,8,0,6,10,2,2,2,6,10,2,4,6,8,0,6,8,1,6,8,2,6,8,3,1,1,7,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,5,67,117,114,118,101,20,80,114,101,112,97,114,101,100,86,101,114,105,102,121,105,110,103,75,101,121,11,80,114,111,111,102,80,111,105,110,116,115,17,80,117,98,108,105,99,80,114,111,111,102,73,110,112,117,116,115,22,97,108,112,104,97,95,103,49,95,98,101,116,97,95,103,50,95,98,121,116,101,115,8,98,108,115,49,50,51,56,49,5,98,110,50,53,52,5,98,121,116,101,115,21,100,101,108,116,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,21,103,97,109,109,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,7,103,114,111,116,104,49,54,2,105,100,21,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,30,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,95,105,110,116,101,114,110,97,108,23,112,114,111,111,102,95,112,111,105,110,116,115,95,102,114,111,109,95,98,121,116,101,115,30,112,117,98,108,105,99,95,112,114,111,111,102,95,105,110,112,117,116,115,95,102,114,111,109,95,98,121,116,101,115,14,112,118,107,95,102,114,111,109,95,98,121,116,101,115,12,112,118,107,95,116,111,95,98,121,116,101,115,20,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,29,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,95,105,110,116,101,114,110,97,108,21,118,107,95,103,97,109,109,97,95,97,98,99,95,103,49,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,11,2,1,2,4,20,10,2,4,10,2,9,10,2,8,10,2,2,2,1,7,10,2,3,2,1,7,10,2,0,1,0,0,0,3,49,0,18,0,2,1,1,0,0,0,3,49,1,18,0,2,2,1,0,0,0,6,11,0,11,1,11,2,11,3,18,1,2,3,1,0,0,4,24,64,5,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,68,5,13,1,14,0,16,1,20,68,5,13,1,14,0,16,2,20,68,5,13,1,14,0,16,3,20,68,5,11,1,2,4,1,0,0,0,3,11,0,18,2,2,5,1,0,0,0,3,11,0,18,3,2,6,1,0,0,0,6,11,0,16,4,20,11,1,17,7,2,7,0,2,0,8,1,0,0,0,17,11,0,16,4,20,10,1,16,0,10,1,16,1,10,1,16,2,11,1,16,3,11,2,16,5,11,3,16,6,17,9,2,9,0,2,0,1,0,1,1,1,2,1,3,0,0,2,0,3,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,7,7,19,26,8,45,32,12,77,8,0,1,0,0,0,1,0,0,2,0,1,0,1,6,10,2,1,10,2,10,98,108,97,107,101,50,98,50,53,54,4,104,97,115,104,9,107,101,99,99,97,107,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"hex":[161,28,235,11,6,0,0,0,8,1,0,4,3,4,21,4,25,2,5,27,37,7,64,44,8,108,64,6,172,1,159,6,12,203,7,194,2,0,4,1,5,0,3,0,0,0,0,1,0,0,0,0,2,1,1,0,1,0,3,4,1,0,3,1,1,10,2,1,2,5,10,10,2,7,10,2,3,3,10,2,2,7,10,9,0,10,9,0,0,4,2,3,3,10,2,5,1,1,1,2,2,6,97,112,112,101,110,100,6,100,101,99,111,100,101,11,100,101,99,111,100,101,95,98,121,116,101,6,101,110,99,111,100,101,3,104,101,120,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,10,10,2,130,6,128,2,2,48,48,2,48,49,2,48,50,2,48,51,2,48,52,2,48,53,2,48,54,2,48,55,2,48,56,2,48,57,2,48,97,2,48,98,2,48,99,2,48,100,2,48,101,2,48,102,2,49,48,2,49,49,2,49,50,2,49,51,2,49,52,2,49,53,2,49,54,2,49,55,2,49,56,2,49,57,2,49,97,2,49,98,2,49,99,2,49,100,2,49,101,2,49,102,2,50,48,2,50,49,2,50,50,2,50,51,2,50,52,2,50,53,2,50,54,2,50,55,2,50,56,2,50,57,2,50,97,2,50,98,2,50,99,2,50,100,2,50,101,2,50,102,2,51,48,2,51,49,2,51,50,2,51,51,2,51,52,2,51,53,2,51,54,2,51,55,2,51,56,2,51,57,2,51,97,2,51,98,2,51,99,2,51,100,2,51,101,2,51,102,2,52,48,2,52,49,2,52,50,2,52,51,2,52,52,2,52,53,2,52,54,2,52,55,2,52,56,2,52,57,2,52,97,2,52,98,2,52,99,2,52,100,2,52,101,2,52,102,2,53,48,2,53,49,2,53,50,2,53,51,2,53,52,2,53,53,2,53,54,2,53,55,2,53,56,2,53,57,2,53,97,2,53,98,2,53,99,2,53,100,2,53,101,2,53,102,2,54,48,2,54,49,2,54,50,2,54,51,2,54,52,2,54,53,2,54,54,2,54,55,2,54,56,2,54,57,2,54,97,2,54,98,2,54,99,2,54,100,2,54,101,2,54,102,2,55,48,2,55,49,2,55,50,2,55,51,2,55,52,2,55,53,2,55,54,2,55,55,2,55,56,2,55,57,2,55,97,2,55,98,2,55,99,2,55,100,2,55,101,2,55,102,2,56,48,2,56,49,2,56,50,2,56,51,2,56,52,2,56,53,2,56,54,2,56,55,2,56,56,2,56,57,2,56,97,2,56,98,2,56,99,2,56,100,2,56,101,2,56,102,2,57,48,2,57,49,2,57,50,2,57,51,2,57,52,2,57,53,2,57,54,2,57,55,2,57,56,2,57,57,2,57,97,2,57,98,2,57,99,2,57,100,2,57,101,2,57,102,2,97,48,2,97,49,2,97,50,2,97,51,2,97,52,2,97,53,2,97,54,2,97,55,2,97,56,2,97,57,2,97,97,2,97,98,2,97,99,2,97,100,2,97,101,2,97,102,2,98,48,2,98,49,2,98,50,2,98,51,2,98,52,2,98,53,2,98,54,2,98,55,2,98,56,2,98,57,2,98,97,2,98,98,2,98,99,2,98,100,2,98,101,2,98,102,2,99,48,2,99,49,2,99,50,2,99,51,2,99,52,2,99,53,2,99,54,2,99,55,2,99,56,2,99,57,2,99,97,2,99,98,2,99,99,2,99,100,2,99,101,2,99,102,2,100,48,2,100,49,2,100,50,2,100,51,2,100,52,2,100,53,2,100,54,2,100,55,2,100,56,2,100,57,2,100,97,2,100,98,2,100,99,2,100,100,2,100,101,2,100,102,2,101,48,2,101,49,2,101,50,2,101,51,2,101,52,2,101,53,2,101,54,2,101,55,2,101,56,2,101,57,2,101,97,2,101,98,2,101,99,2,101,100,2,101,101,2,101,102,2,102,48,2,102,49,2,102,50,2,102,51,2,102,52,2,102,53,2,102,54,2,102,55,2,102,56,2,102,57,2,102,97,2,102,98,2,102,99,2,102,100,2,102,101,2,102,102,10,2,1,0,0,1,0,0,2,33,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,4,12,5,12,3,10,3,10,4,35,4,31,5,12,13,5,12,2,7,2,12,1,11,2,14,1,14,0,10,3,66,1,20,52,66,0,20,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,5,2,1,1,0,0,5,47,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,3,12,4,12,2,10,3,6,2,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,14,5,16,7,0,39,10,2,10,3,35,4,45,5,21,14,0,10,2,66,1,20,17,2,49,16,24,14,0,10,2,6,1,0,0,0,0,0,0,0,22,66,1,20,17,2,22,12,1,13,4,11,1,68,1,11,2,6,2,0,0,0,0,0,0,0,22,12,2,5,16,11,4,2,2,0,0,0,6,64,49,48,10,0,37,4,9,10,0,49,58,35,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,5,5,62,49,65,10,0,37,4,27,10,0,49,71,35,12,2,5,29,9,12,2,11,2,4,38,49,10,11,0,22,49,65,23,12,4,5,60,49,97,10,0,37,4,47,10,0,49,103,35,12,3,5,49,9,12,3,11,3,4,52,5,54,7,1,39,49,10,11,0,22,49,97,23,12,4,11,4,12,5,11,5,2,0],"hmac":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,10,7,17,19,8,36,32,12,68,4,0,0,0,1,0,1,0,2,6,10,2,6,10,2,1,10,2,4,104,109,97,99,13,104,109,97,99,95,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"kiosk":[161,28,235,11,6,0,0,0,14,1,0,24,2,24,94,3,118,135,3,4,253,3,68,5,193,4,137,4,7,202,8,159,8,8,233,16,64,6,169,17,130,1,10,171,18,101,11,144,19,8,12,152,19,146,14,13,170,33,18,14,188,33,6,15,194,33,2,0,50,1,62,0,21,0,26,0,31,0,32,0,34,0,61,0,86,0,88,0,89,0,90,0,8,12,0,0,9,12,0,0,13,12,1,12,1,0,1,0,0,0,4,7,0,0,10,7,0,0,11,7,0,0,6,3,1,12,1,0,7,3,1,12,1,0,5,3,1,12,1,1,12,7,1,0,0,2,0,4,1,0,1,3,2,12,1,0,1,7,3,7,0,7,18,4,0,8,14,2,0,10,15,12,1,0,1,10,16,0,1,0,1,11,17,2,0,0,27,0,1,0,0,59,0,2,0,0,25,3,4,0,0,83,5,1,0,0,84,6,1,0,0,64,7,1,1,12,0,56,8,1,1,12,0,87,9,10,1,12,0,54,11,1,1,12,0,65,12,1,1,12,0,29,9,1,1,12,0,71,13,14,1,12,0,55,15,16,1,12,0,75,17,14,1,12,0,79,18,1,1,12,0,97,19,4,0,0,57,20,1,1,12,0,66,20,1,1,12,0,94,21,22,0,0,40,23,24,0,0,41,23,24,1,12,0,46,23,24,0,0,44,23,24,0,0,45,23,24,0,0,39,25,24,0,0,93,25,22,0,0,82,26,1,0,0,91,27,28,0,0,92,21,22,0,0,63,27,29,0,0,48,27,30,0,0,69,27,31,0,0,70,25,32,0,0,22,33,34,1,12,0,23,9,35,1,12,0,24,9,36,1,12,0,80,37,1,1,12,0,53,38,39,0,0,73,40,39,1,12,0,72,40,39,1,12,0,74,40,31,1,12,1,30,74,10,1,0,1,47,73,24,1,0,2,96,75,31,1,0,2,98,1,48,1,0,3,38,50,51,1,0,3,76,65,1,1,0,3,87,76,51,1,0,3,96,63,31,1,0,4,19,59,1,2,7,4,4,35,78,24,1,7,4,77,54,57,2,7,4,4,78,54,55,2,7,4,5,19,59,1,2,7,12,5,22,78,81,2,7,12,5,23,54,82,2,7,12,5,35,78,24,1,7,5,36,78,24,2,7,12,5,77,54,57,2,7,12,6,33,10,1,1,3,7,28,46,1,0,7,42,34,39,1,8,7,59,0,46,0,7,95,28,39,0,9,85,10,1,1,8,9,88,44,1,1,8,10,60,67,68,1,0,11,81,42,29,0,65,43,64,45,44,47,61,45,45,47,17,10,16,10,52,53,58,56,20,10,49,53,59,60,61,10,5,10,8,10,51,53,59,61,48,47,52,64,46,47,59,66,66,10,42,31,41,31,43,47,47,47,49,64,53,56,56,77,57,56,50,79,50,80,54,56,55,56,1,7,8,18,0,2,8,0,8,1,3,8,0,8,1,7,8,18,1,11,12,1,8,15,3,7,8,0,6,8,1,6,8,18,3,7,8,0,6,8,1,5,3,7,8,0,6,8,1,9,0,4,7,8,0,6,8,1,6,11,16,1,9,0,9,0,3,7,8,0,6,8,1,8,13,1,9,0,4,7,8,0,6,8,1,8,13,3,4,7,8,0,6,8,1,9,0,3,3,7,8,0,8,13,11,12,1,8,15,2,9,0,11,17,1,9,0,5,7,8,0,6,8,1,8,13,3,7,8,18,1,11,2,1,9,0,3,7,8,0,11,2,1,9,0,11,12,1,8,15,2,7,8,0,11,2,1,9,0,4,7,8,0,6,8,1,11,10,1,3,7,8,18,2,7,8,0,9,0,1,7,8,0,1,7,8,14,2,6,8,0,8,13,1,1,2,7,8,0,6,8,1,3,7,8,0,6,8,1,1,1,6,8,0,1,6,8,14,1,5,1,14,1,3,1,7,11,11,1,8,15,3,6,8,0,6,8,1,8,13,1,6,9,0,1,7,9,0,2,9,0,8,3,3,7,8,0,9,0,8,3,1,6,8,1,1,8,13,1,6,11,2,1,9,0,2,8,1,8,0,1,6,8,18,1,8,1,2,9,0,5,1,8,0,1,8,14,1,8,15,1,11,11,1,9,0,5,8,14,8,13,8,14,14,11,11,1,8,15,2,11,11,1,9,0,7,8,18,1,11,12,1,9,0,3,8,13,8,13,8,13,2,8,5,3,2,7,8,14,9,0,1,11,10,1,9,1,2,8,4,9,0,1,9,1,2,8,13,8,13,3,7,8,14,9,0,9,1,1,11,7,1,9,0,1,11,9,1,9,0,2,9,0,3,1,6,11,12,1,9,0,2,8,6,1,2,7,11,11,1,9,0,11,12,1,9,0,1,11,8,1,9,0,3,8,13,3,8,13,1,11,17,1,9,0,6,8,13,8,13,3,8,13,8,14,8,13,5,8,13,8,13,8,13,3,3,3,8,14,8,13,8,13,3,3,3,3,1,6,11,10,1,9,0,1,11,10,1,9,0,1,6,11,11,1,9,0,3,7,11,11,1,9,0,3,7,8,18,1,8,4,2,6,8,14,9,0,1,8,6,1,8,5,1,6,9,1,1,7,9,1,7,66,97,108,97,110,99,101,6,66,111,114,114,111,119,4,67,111,105,110,2,73,68,4,73,116,101,109,12,73,116,101,109,68,101,108,105,115,116,101,100,10,73,116,101,109,76,105,115,116,101,100,13,73,116,101,109,80,117,114,99,104,97,115,101,100,5,75,105,111,115,107,13,75,105,111,115,107,79,119,110,101,114,67,97,112,7,76,105,115,116,105,110,103,4,76,111,99,107,6,79,112,116,105,111,110,11,80,117,114,99,104,97,115,101,67,97,112,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,16,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,10,98,111,114,114,111,119,95,118,97,108,18,99,108,111,115,101,95,97,110,100,95,119,105,116,104,100,114,97,119,4,99,111,105,110,7,100,101,102,97,117,108,116,6,100,101,108,101,116,101,6,100,101,108,105,115,116,12,100,101,115,116,114,111,121,95,115,111,109,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,4,101,109,105,116,5,101,118,101,110,116,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,3,102,111,114,12,102,114,111,109,95,98,97,108,97,110,99,101,10,104,97,115,95,97,99,99,101,115,115,8,104,97,115,95,105,116,101,109,18,104,97,115,95,105,116,101,109,95,119,105,116,104,95,116,121,112,101,2,105,100,12,105,115,95,101,120,99,108,117,115,105,118,101,9,105,115,95,108,105,115,116,101,100,21,105,115,95,108,105,115,116,101,100,95,101,120,99,108,117,115,105,118,101,108,121,9,105,115,95,108,111,99,107,101,100,7,105,115,95,115,111,109,101,10,105,116,101,109,95,99,111,117,110,116,7,105,116,101,109,95,105,100,5,107,105,111,115,107,15,107,105,111,115,107,95,101,120,116,101,110,115,105,111,110,8,107,105,111,115,107,95,105,100,19,107,105,111,115,107,95,111,119,110,101,114,95,99,97,112,95,102,111,114,4,108,105,115,116,22,108,105,115,116,95,119,105,116,104,95,112,117,114,99,104,97,115,101,95,99,97,112,4,108,111,99,107,13,108,111,99,107,95,105,110,116,101,114,110,97,108,9,109,105,110,95,112,114,105,99,101,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,5,111,119,110,101,114,5,112,108,97,99,101,14,112,108,97,99,101,95,97,110,100,95,108,105,115,116,14,112,108,97,99,101,95,105,110,116,101,114,110,97,108,5,112,114,105,99,101,7,112,114,111,102,105,116,115,14,112,114,111,102,105,116,115,95,97,109,111,117,110,116,11,112,114,111,102,105,116,115,95,109,117,116,8,112,117,114,99,104,97,115,101,17,112,117,114,99,104,97,115,101,95,99,97,112,95,105,116,101,109,18,112,117,114,99,104,97,115,101,95,99,97,112,95,107,105,111,115,107,22,112,117,114,99,104,97,115,101,95,99,97,112,95,109,105,110,95,112,114,105,99,101,17,112,117,114,99,104,97,115,101,95,119,105,116,104,95,99,97,112,3,112,117,116,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,19,114,101,116,117,114,110,95,112,117,114,99,104,97,115,101,95,99,97,112,10,114,101,116,117,114,110,95,118,97,108,6,115,101,110,100,101,114,20,115,101,116,95,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,9,115,101,116,95,111,119,110,101,114,16,115,101,116,95,111,119,110,101,114,95,99,117,115,116,111,109,12,115,104,97,114,101,95,111,98,106,101,99,116,3,115,117,105,4,116,97,107,101,8,116,114,97,110,115,102,101,114,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,3,117,105,100,7,117,105,100,95,109,117,116,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,16,117,105,100,95,109,117,116,95,105,110,116,101,114,110,97,108,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,0,2,5,42,8,14,68,11,11,1,8,15,63,5,48,14,20,1,1,2,2,42,8,14,37,8,13,2,2,4,42,8,14,52,8,13,49,8,13,58,3,3,2,2,52,8,13,49,8,13,4,2,1,42,8,13,5,2,2,42,8,13,43,1,6,2,1,42,8,13,7,2,3,50,8,13,42,8,13,67,3,8,2,3,50,8,13,42,8,13,67,3,9,2,2,50,8,13,42,8,13,7,10,9,10,8,10,2,10,0,0,4,0,41,12,10,0,17,1,12,1,12,2,11,1,11,0,46,17,67,56,0,11,2,56,1,2,1,1,0,0,41,19,10,0,17,62,56,2,10,0,46,17,67,73,0,0,0,0,9,18,0,12,2,11,0,17,62,14,2,56,3,18,1,12,1,11,2,11,1,2,2,1,0,0,49,38,11,0,19,0,1,12,6,1,12,7,12,5,11,1,19,1,12,4,12,3,14,5,17,63,11,4,33,4,17,5,21,11,2,1,7,0,39,11,6,73,0,0,0,0,33,4,26,5,30,11,2,1,7,3,39,11,3,17,60,11,5,17,60,11,7,11,2,56,4,2,3,1,0,0,1,17,10,0,11,1,17,24,4,5,5,11,11,0,1,11,2,1,7,0,39,11,2,17,67,11,0,15,0,21,2,4,1,0,0,1,14,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,2,11,0,15,0,21,2,5,1,0,0,1,13,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,11,2,56,5,2,6,1,0,0,1,13,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,11,3,56,6,2,7,1,0,0,52,68,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,21,32,4,18,5,22,11,0,1,7,8,39,10,0,10,2,12,4,46,11,4,17,23,32,4,31,5,35,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,19,4,43,5,47,11,0,1,7,11,39,10,0,16,1,20,73,1,0,0,0,23,10,0,15,1,21,10,0,15,2,10,2,9,18,5,56,7,1,11,0,15,2,11,2,18,4,56,8,2,8,1,0,0,58,49,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,4,46,11,4,56,9,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,5,46,11,5,17,23,32,4,30,5,34,11,0,1,7,4,39,10,0,15,2,10,2,9,18,5,10,3,56,10,11,0,46,56,3,11,2,11,3,57,0,56,11,2,9,1,0,0,39,13,14,2,56,12,12,4,10,0,10,1,11,2,56,13,11,0,11,1,11,4,11,3,56,14,2,10,1,0,0,52,60,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,56,9,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,23,32,4,30,5,34,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,22,4,42,5,46,11,0,1,7,12,39,10,0,15,2,10,2,9,18,5,56,15,1,11,0,46,56,3,11,2,57,1,56,16,2,11,1,0,0,62,56,10,0,15,2,10,1,9,18,5,56,15,12,4,10,0,15,2,10,1,18,4,56,8,12,3,10,0,16,1,20,73,1,0,0,0,23,10,0,15,1,21,10,4,14,2,56,17,33,4,27,5,31,11,0,1,7,1,39,10,0,15,2,10,1,18,6,56,18,1,10,0,15,3,11,2,56,19,10,0,46,56,3,10,1,10,4,57,2,56,20,11,3,11,1,11,4,11,0,46,56,3,56,21,2,12,1,0,0,69,64,10,0,11,1,17,24,4,5,5,11,11,0,1,11,4,1,7,0,39,10,0,10,2,12,5,46,11,5,56,9,4,19,5,25,11,0,1,11,4,1,7,11,39,10,0,10,2,12,6,46,11,6,17,22,32,4,34,5,40,11,0,1,11,4,1,7,6,39,10,0,15,2,10,2,8,18,5,10,3,56,10,11,3,12,7,11,2,12,8,11,4,17,62,12,9,11,0,46,56,3,12,10,11,9,11,10,11,8,11,7,57,3,2,13,1,0,0,70,68,11,1,58,3,12,6,12,4,12,5,17,60,11,4,12,3,14,2,56,17,12,7,10,7,11,6,38,4,16,5,20,11,0,1,7,1,39,10,0,46,56,3,11,5,33,4,27,5,31,11,0,1,7,5,39,10,0,15,2,10,3,8,18,5,56,15,1,10,0,15,3,11,2,56,19,10,0,16,1,20,73,1,0,0,0,23,10,0,15,1,21,10,0,15,2,10,3,18,6,56,18,1,10,0,15,2,10,3,18,4,56,8,11,3,11,7,11,0,46,56,3,56,21,2,14,1,0,0,71,27,11,1,58,3,1,12,3,12,4,12,2,10,0,46,56,3,11,4,33,4,13,5,17,11,0,1,7,5,39,11,0,15,2,11,3,8,18,5,56,15,1,11,2,17,60,2,15,1,0,0,72,45,10,0,11,1,17,24,4,5,5,11,11,0,1,11,3,1,7,0,39,14,2,56,22,4,33,11,2,56,23,12,6,10,6,10,0,16,3,56,24,37,4,24,5,30,11,0,1,11,3,1,7,2,39,11,6,12,4,5,37,10,0,16,3,56,24,12,4,11,4,12,5,11,0,15,3,11,5,11,3,56,25,2,16,3,0,0,1,11,10,0,15,2,14,1,56,12,18,6,8,56,26,11,0,11,1,56,5,2,17,3,0,0,1,16,10,0,16,1,20,73,1,0,0,0,22,10,0,15,1,21,11,0,15,2,14,1,56,12,18,4,11,1,56,27,2,18,3,0,0,1,3,11,0,15,2,2,19,1,0,0,1,6,11,0,16,2,11,1,18,4,56,28,2,20,1,0,0,1,6,11,0,16,2,11,1,18,4,56,29,2,21,1,0,0,1,6,11,0,16,2,11,1,18,6,56,30,2,22,1,0,0,24,18,10,0,16,2,10,1,9,18,5,56,31,4,12,11,0,1,8,12,2,5,16,11,0,11,1,17,23,12,2,11,2,2,23,1,0,0,1,7,11,0,16,2,11,1,8,18,5,56,31,2,24,1,0,0,1,8,11,0,46,56,3,11,1,16,4,20,33,2,25,1,0,0,1,12,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,15,2,2,26,1,0,0,1,14,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,2,11,0,15,5,21,2,27,1,0,0,1,3,11,0,16,2,2,28,1,0,0,1,12,10,0,16,5,20,4,5,5,9,11,0,1,7,7,39,11,0,15,2,2,29,1,0,0,1,4,11,0,16,0,20,2,30,1,0,0,1,4,11,0,16,1,20,2,31,1,0,0,1,4,11,0,16,3,56,24,2,32,1,0,0,1,12,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,15,3,2,33,1,0,0,1,27,10,0,56,3,11,1,16,4,20,33,4,8,5,12,11,0,1,7,0,39,10,0,10,2,17,19,4,17,5,21,11,0,1,7,11,39,11,0,16,2,11,2,18,4,56,32,2,34,1,0,0,58,40,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,19,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,22,32,4,30,5,34,11,0,1,7,9,39,11,0,15,2,11,2,18,4,56,33,2,35,1,0,0,58,45,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,19,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,22,32,4,30,5,34,11,0,1,7,9,39,10,0,15,2,10,2,18,4,56,8,11,0,46,56,3,11,2,18,3,2,36,1,0,0,58,32,11,2,19,3,12,3,12,4,10,0,46,56,3,11,4,33,4,11,5,15,11,0,1,7,5,39,14,1,56,12,10,3,33,4,21,5,25,11,0,1,7,10,39,11,0,15,2,11,3,18,4,11,1,56,27,2,37,1,0,0,1,4,11,0,16,4,20,2,38,1,0,0,1,4,11,0,55,0,20,2,39,1,0,0,1,4,11,0,55,1,20,2,40,1,0,0,1,4,11,0,55,2,20,2,0,2,0,3,0,0,0,1,1,1,0,4,2,1,2,2,2,3,6,10,7,10,8,10,0,51,0],"kiosk_extension":[161,28,235,11,6,0,0,0,12,1,0,14,2,14,36,3,50,162,1,4,212,1,26,5,238,1,142,1,7,252,2,164,3,8,160,6,32,6,192,6,76,10,140,7,15,11,155,7,2,12,157,7,143,4,13,172,11,6,0,26,0,9,0,17,0,25,0,30,0,37,0,38,0,1,4,0,0,2,7,1,0,1,1,0,12,0,3,3,12,0,3,4,12,0,4,7,4,0,5,5,12,1,0,1,6,6,2,0,0,8,0,1,1,2,0,15,2,1,1,2,0,18,2,1,1,2,0,34,2,1,1,2,0,35,3,4,1,2,0,36,5,6,1,2,0,32,7,1,2,2,12,0,27,7,1,2,2,12,0,24,8,9,1,2,0,23,8,9,1,2,0,13,8,9,1,2,0,12,8,9,1,2,0,20,8,10,1,2,0,21,11,12,1,2,1,14,16,1,0,1,29,15,16,0,2,8,18,1,2,7,4,2,10,24,25,2,7,4,2,11,19,26,2,7,4,2,19,24,9,1,7,2,34,19,20,2,7,4,3,22,2,9,0,3,28,21,1,1,12,3,33,21,1,1,12,3,39,8,22,0,3,40,2,13,0,3,41,11,13,0,16,17,8,14,13,14,20,17,12,14,10,14,11,14,23,20,22,20,19,23,9,14,17,17,18,17,5,9,0,7,8,3,6,8,4,4,7,8,7,0,2,7,8,3,6,8,4,2,9,0,6,8,3,1,6,8,2,2,9,0,7,8,3,1,7,8,2,4,9,0,7,8,3,9,1,6,11,6,1,9,1,1,6,8,3,1,1,1,6,8,0,1,7,8,3,1,7,8,0,1,7,8,5,1,9,0,1,7,8,7,1,8,2,2,11,1,1,9,0,8,0,3,7,8,5,9,0,9,1,2,7,8,5,9,0,1,9,1,2,7,8,3,9,0,1,6,8,5,1,11,1,1,9,0,2,6,8,5,9,0,1,6,9,1,1,7,9,1,3,66,97,103,9,69,120,116,101,110,115,105,111,110,12,69,120,116,101,110,115,105,111,110,75,101,121,5,75,105,111,115,107,13,75,105,111,115,107,79,119,110,101,114,67,97,112,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,3,98,97,103,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,97,110,95,108,111,99,107,9,99,97,110,95,112,108,97,99,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,7,100,105,115,97,98,108,101,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,6,101,110,97,98,108,101,7,101,120,105,115,116,115,95,9,101,120,116,101,110,115,105,111,110,13,101,120,116,101,110,115,105,111,110,95,109,117,116,10,104,97,115,95,97,99,99,101,115,115,10,105,115,95,101,110,97,98,108,101,100,12,105,115,95,105,110,115,116,97,108,108,101,100,5,107,105,111,115,107,15,107,105,111,115,107,95,101,120,116,101,110,115,105,111,110,4,108,111,99,107,13,108,111,99,107,95,105,110,116,101,114,110,97,108,3,110,101,119,6,111,98,106,101,99,116,11,112,101,114,109,105,115,115,105,111,110,115,5,112,108,97,99,101,14,112,108,97,99,101,95,105,110,116,101,114,110,97,108,6,114,101,109,111,118,101,7,115,116,111,114,97,103,101,11,115,116,111,114,97,103,101,95,109,117,116,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,3,117,105,100,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,16,117,105,100,95,109,117,116,95,105,110,116,101,114,110,97,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,4,16,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,16,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,35,8,2,31,4,23,1,1,2,1,16,1,1,14,0,1,0,0,1,25,10,1,10,2,17,21,4,5,5,13,11,1,1,11,4,1,11,2,1,7,0,39,11,1,11,2,17,25,9,57,0,11,4,17,15,11,3,8,18,0,56,0,2,1,1,0,0,1,24,10,0,11,1,17,21,4,5,5,9,11,0,1,7,0,39,10,0,46,56,1,4,14,5,18,11,0,1,7,3,39,9,11,0,56,2,15,0,21,2,2,1,0,0,1,24,10,0,11,1,17,21,4,5,5,9,11,0,1,7,0,39,10,0,46,56,1,4,14,5,18,11,0,1,7,3,39,8,11,0,56,2,15,0,21,2,3,1,0,0,1,33,10,0,10,1,17,21,4,5,5,11,11,0,1,11,1,1,7,0,39,10,0,46,56,1,4,16,5,22,11,0,1,11,1,1,7,3,39,11,0,11,1,17,25,9,57,0,56,3,19,0,1,1,17,14,2,4,1,0,0,1,12,10,1,56,1,4,4,5,8,11,1,1,7,3,39,11,1,56,4,16,1,2,5,1,0,0,1,13,10,1,46,56,1,4,5,5,9,11,1,1,7,3,39,11,1,56,2,15,1,2,6,1,0,0,9,31,10,1,46,56,1,4,5,5,9,11,1,1,7,3,39,10,1,46,56,5,4,16,8,12,4,5,20,10,1,46,56,6,12,4,11,4,4,23,5,27,11,1,1,7,2,39,11,1,11,2,56,7,2,7,1,0,0,1,22,10,1,46,56,1,4,5,5,9,11,1,1,7,3,39,10,1,46,56,6,4,14,5,18,11,1,1,7,2,39,11,1,11,2,56,8,2,8,1,0,0,1,6,11,0,17,24,9,57,0,56,9,2,9,1,0,0,1,5,11,0,56,4,16,0,20,2,10,1,0,0,9,19,10,0,56,10,4,13,11,0,56,4,16,2,20,7,4,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,12,1,5,17,11,0,1,9,12,1,11,1,2,11,1,0,0,9,19,10,0,56,10,4,13,11,0,56,4,16,2,20,7,5,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,12,1,5,17,11,0,1,9,12,1,11,1,2,12,0,0,0,1,6,11,0,17,24,9,57,0,56,11,2,13,0,0,0,1,6,11,0,17,26,9,57,0,56,12,2,0,2,0,0,0,1,0],"linked_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,30,3,40,212,1,4,252,1,28,5,152,2,188,1,7,212,3,205,2,8,161,6,64,6,225,6,20,10,245,6,38,11,155,7,4,12,159,7,151,5,13,182,12,14,14,196,12,14,0,24,1,29,0,14,0,28,0,40,0,0,12,2,7,0,4,1,0,1,4,2,7,0,4,0,1,2,7,1,0,0,3,4,4,0,4,3,2,0,0,25,0,1,2,7,4,0,17,2,3,2,7,4,0,6,2,3,2,7,4,0,34,4,5,2,7,4,0,33,4,5,2,7,4,0,7,6,7,2,7,4,0,8,8,9,2,7,4,0,32,6,3,2,7,4,0,26,6,3,2,7,4,0,35,8,10,2,7,4,0,31,11,12,2,7,4,0,30,11,12,2,7,4,0,9,6,13,2,7,4,0,23,2,14,2,7,4,0,20,2,13,2,7,4,0,11,1,5,2,7,4,0,13,1,5,2,7,6,1,7,3,25,1,0,1,12,17,16,1,0,1,16,19,5,1,0,1,21,3,13,1,0,1,22,3,13,1,0,1,27,5,17,1,0,1,37,16,17,1,0,1,38,19,17,1,0,2,5,22,5,2,7,4,2,7,23,7,2,7,4,2,8,21,9,2,7,4,2,15,23,13,2,7,4,2,35,21,10,2,7,4,3,10,15,5,0,3,25,0,15,0,22,16,24,16,20,16,19,16,21,16,18,16,23,16,27,20,25,20,26,20,29,20,17,16,9,12,28,20,1,7,8,4,1,11,0,2,9,0,9,1,1,6,11,0,2,9,0,9,1,1,6,11,2,1,9,0,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,7,11,0,2,9,0,9,1,2,9,0,9,1,1,1,1,3,1,8,3,1,9,0,1,11,2,1,9,0,5,11,2,1,9,0,11,2,1,9,0,11,2,1,9,0,9,0,11,2,1,9,0,2,7,11,2,1,9,0,9,0,2,9,0,11,1,2,9,0,9,1,2,7,8,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,3,11,2,1,9,0,11,2,1,9,0,9,1,1,6,9,0,2,8,3,3,11,76,105,110,107,101,100,84,97,98,108,101,4,78,111,100,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,4,98,97,99,107,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,4,102,105,108,108,5,102,114,111,110,116,4,104,101,97,100,2,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,6,108,101,110,103,116,104,12,108,105,110,107,101,100,95,116,97,98,108,101,3,110,101,119,4,110,101,120,116,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,111,112,95,98,97,99,107,9,112,111,112,95,102,114,111,110,116,4,112,114,101,118,9,112,117,115,104,95,98,97,99,107,10,112,117,115,104,95,102,114,111,110,116,6,114,101,109,111,118,101,4,115,105,122,101,4,115,111,109,101,12,115,119,97,112,95,111,114,95,102,105,108,108,4,116,97,105,108,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,19,8,3,36,3,18,11,2,1,9,0,39,11,2,1,9,0,1,2,3,32,11,2,1,9,0,26,11,2,1,9,0,41,9,1,0,12,1,12,0,1,0,0,5,7,11,0,17,31,6,0,0,0,0,0,0,0,0,56,0,56,0,57,0,2,1,1,0,0,5,3,11,0,55,0,2,2,1,0,0,5,3,11,0,55,1,2,3,1,0,0,18,54,10,0,54,0,10,1,56,1,12,5,10,0,55,1,56,2,4,13,10,0,54,1,10,1,56,3,56,0,12,7,14,5,56,4,4,33,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,3,21,11,6,56,6,12,3,5,35,56,0,12,3,11,3,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,4,1,0,0,18,54,10,0,55,0,56,2,4,8,10,0,54,0,10,1,56,3,10,0,54,1,10,1,56,1,12,5,14,5,56,4,4,31,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,5,21,11,6,56,6,12,3,5,33,56,0,12,3,11,3,12,7,56,0,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,5,1,0,0,5,6,11,0,55,2,11,1,56,9,55,6,2,6,1,0,0,5,6,11,0,54,2,11,1,56,7,54,6,2,7,1,0,0,5,6,11,0,55,2,11,1,56,9,55,3,2,8,1,0,0,5,6,11,0,55,2,11,1,56,9,55,5,2,9,1,0,0,24,65,10,0,54,2,10,1,56,10,58,1,12,4,12,2,12,3,10,0,55,4,20,6,1,0,0,0,0,0,0,0,23,10,0,54,4,21,14,3,56,4,4,28,10,2,10,0,54,2,14,3,56,11,20,56,7,54,5,21,14,2,56,4,4,40,10,3,10,0,54,2,14,2,56,11,20,56,7,54,3,21,10,0,55,0,56,11,14,1,33,4,50,11,2,10,0,54,0,21,10,0,55,1,56,11,14,1,33,4,61,11,3,11,0,54,1,21,5,63,11,0,1,11,4,2,10,1,0,0,16,19,10,0,55,0,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,0,56,11,20,12,1,10,1,11,0,11,1,56,12,2,11,1,0,0,16,19,10,0,55,1,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,1,56,11,20,12,1,10,1,11,0,11,1,56,12,2,12,1,0,0,5,5,11,0,55,2,11,1,56,13,2,13,1,0,0,5,4,11,0,55,4,20,2,14,1,0,0,5,6,11,0,55,4,20,6,0,0,0,0,0,0,0,0,33,2,15,1,0,0,26,16,11,0,58,0,1,1,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,11,5,13,7,0,39,11,1,17,30,2,16,1,0,0,5,7,11,0,58,0,1,1,1,17,30,2,0,2,0,3,0,0,1,0,0,1,1,1,1,2,0,12,1,12,2,12,3,12,4,12,5,12,6,12,0],"math":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,35,5,37,18,7,55,57,8,112,32,12,144,1,249,3,0,2,0,3,0,1,0,0,4,0,1,0,0,0,0,1,0,0,5,2,1,0,0,6,1,1,0,0,7,3,3,0,0,1,0,1,0,2,3,3,1,3,2,3,2,1,4,3,4,4,4,3,15,15,15,4,100,105,102,102,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,4,109,97,116,104,3,109,97,120,3,109,105,110,3,112,111,119,4,115,113,114,116,9,115,113,114,116,95,117,49,50,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,1,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,2,1,0,0,1,15,10,0,10,1,36,4,9,11,0,11,1,23,12,2,5,13,11,1,11,0,23,12,2,11,2,2,3,1,0,0,1,33,6,1,0,0,0,0,0,0,0,12,2,10,1,49,1,38,4,31,5,7,10,1,49,2,25,49,0,33,4,22,10,0,11,0,24,12,0,11,1,49,2,26,12,1,5,30,11,2,10,0,24,12,2,11,1,49,1,23,12,1,5,2,11,2,2,4,1,0,0,4,43,50,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,12,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,53,12,3,10,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,52,2,5,1,0,0,5,43,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,77,12,3,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,53,2,6,1,0,0,1,19,10,0,10,1,25,6,0,0,0,0,0,0,0,0,33,4,11,11,0,11,1,26,12,2,5,17,11,0,11,1,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,2,0],"object":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,126,4,146,1,6,5,152,1,35,7,187,1,250,2,8,181,4,64,6,245,4,112,10,229,5,11,12,240,5,130,2,13,242,7,4,15,246,7,8,0,24,1,4,0,3,0,30,0,0,7,0,0,2,4,0,3,1,2,0,0,21,0,1,0,0,20,0,2,0,0,19,1,3,0,0,18,2,3,0,0,27,4,5,0,0,8,6,5,0,0,31,7,0,0,0,34,7,3,0,0,33,7,1,0,0,32,7,2,0,0,22,8,5,0,0,9,5,6,0,0,15,9,3,1,8,0,5,9,0,1,8,0,17,9,1,1,8,0,16,9,2,1,8,0,6,9,7,1,8,0,23,2,5,0,0,10,2,6,0,0,25,2,6,0,1,28,9,1,1,0,2,14,1,2,0,3,13,8,2,0,3,26,4,2,0,20,2,16,10,20,3,1,6,8,0,1,10,2,1,5,1,8,0,1,6,8,2,1,8,1,0,1,6,8,1,1,7,8,2,1,6,9,0,1,9,0,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,100,100,114,101,115,115,3,98,99,115,9,98,111,114,114,111,119,95,105,100,10,98,111,114,114,111,119,95,117,105,100,5,98,121,116,101,115,5,99,108,111,99,107,6,100,101,108,101,116,101,11,100,101,108,101,116,101,95,105,109,112,108,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,2,105,100,10,105,100,95,97,100,100,114,101,115,115,8,105,100,95,98,121,116,101,115,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,102,114,111,109,95,98,121,116,101,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,11,105,100,95,116,111,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,6,111,98,106,101,99,116,14,114,101,99,111,114,100,95,110,101,119,95,117,105,100,6,115,101,110,100,101,114,16,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,12,117,105,100,95,116,111,95,98,121,116,101,115,12,117,105,100,95,116,111,95,105,110,110,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,7,5,1,2,1,15,8,0,0,1,0,0,6,4,11,0,16,0,56,0,2,1,1,0,0,6,4,11,0,16,0,20,2,2,1,0,0,6,4,11,0,17,21,17,3,2,3,1,0,0,6,3,11,0,18,0,2,4,0,0,0,6,12,11,0,17,23,7,3,33,4,6,5,8,7,2,39,7,0,18,0,18,1,2,5,3,0,0,6,4,7,1,18,0,18,1,2,6,1,0,0,6,3,11,0,16,1,2,7,1,0,0,6,4,11,0,16,1,20,2,8,1,0,0,6,5,11,0,16,1,16,0,56,0,2,9,1,0,0,6,5,11,0,16,1,16,0,20,2,10,1,0,0,6,5,11,0,17,22,18,0,18,1,2,11,1,0,0,6,5,11,0,19,1,19,0,17,18,2,12,1,0,0,6,5,11,0,56,1,16,1,20,2,13,1,0,0,6,4,11,0,56,1,16,1,2,14,1,0,0,6,5,11,0,56,1,16,1,56,2,2,15,1,0,0,6,6,11,0,56,1,16,1,16,0,20,2,16,0,2,0,17,3,0,0,6,6,10,0,17,19,11,0,18,0,18,1,2,18,0,2,0,19,0,2,0,0,0,1,0,0,8,0,11,0,12,0,29,0],"object_bag":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,22,3,32,124,4,156,1,14,5,170,1,88,7,130,2,231,1,8,233,3,64,6,169,4,10,10,179,4,8,12,187,4,245,1,13,176,6,4,0,20,1,21,0,12,0,19,0,24,0,1,12,0,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,18,0,1,0,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,22,6,8,2,7,12,0,8,4,9,1,7,0,9,4,9,2,7,12,0,17,10,11,0,0,16,10,9,0,0,11,1,3,0,0,25,4,12,1,7,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,13,16,9,1,7,2,14,16,9,2,7,12,2,15,16,12,1,7,2,22,17,8,2,7,12,3,10,13,3,0,3,18,0,13,0,11,14,12,14,13,14,17,14,14,18,15,14,16,18,1,7,8,4,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,9,79,98,106,101,99,116,66,97,103,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,10,111,98,106,101,99,116,95,98,97,103,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,15,8,3,23,3,0,1,0,0,3,5,11,0,17,19,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,19,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,18,2,10,1,0,0,3,5,11,0,16,0,11,1,56,6,2,0,0,0,1,0],"object_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,26,3,36,120,4,156,1,12,5,168,1,113,7,153,2,199,1,8,224,3,64,6,160,4,10,10,170,4,8,11,178,4,2,12,180,4,230,1,13,154,6,4,14,158,6,4,0,18,1,19,0,11,0,17,0,22,0,1,12,2,7,1,12,1,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,16,0,1,2,7,12,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,20,6,8,2,7,12,0,8,4,9,2,7,12,0,15,10,11,2,7,12,0,14,10,9,2,7,12,0,10,1,3,2,7,12,0,23,4,12,2,7,12,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,12,16,9,1,7,2,13,16,12,1,7,2,20,17,8,2,7,12,3,9,13,3,0,3,16,0,13,0,10,14,11,14,12,14,15,14,13,18,14,18,1,7,8,4,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,13,8,3,21,3,0,14,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,19,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,9,1,0,0,3,5,11,0,55,0,11,1,56,5,2,0,0,0,1,0,14,1,14,0],"package":[161,28,235,11,6,0,0,0,11,1,0,14,2,14,36,3,50,183,1,4,233,1,10,5,243,1,118,7,233,2,144,5,8,249,7,64,6,185,8,93,10,150,9,48,12,198,9,129,4,13,199,13,20,0,36,1,10,1,50,0,33,0,48,0,49,0,51,0,1,12,0,0,6,12,0,0,8,0,0,0,7,0,0,1,2,7,0,2,4,7,0,3,0,7,0,3,5,4,0,5,3,2,0,0,14,0,1,1,2,0,15,0,2,1,2,0,12,1,2,0,0,22,3,4,1,0,0,21,3,4,1,0,0,39,3,5,0,0,40,3,5,0,0,52,6,7,0,0,54,6,8,0,0,53,6,9,0,0,46,10,7,0,0,47,10,9,0,0,41,11,7,0,0,42,11,7,0,0,45,10,12,0,0,17,2,9,0,0,9,2,9,0,0,19,2,9,0,0,34,13,2,0,0,35,13,2,0,0,30,14,2,0,0,11,15,16,0,0,16,17,2,0,0,43,18,2,0,2,23,24,25,0,2,24,24,25,0,2,25,2,19,1,0,3,18,23,2,0,3,26,21,7,1,8,3,27,27,7,0,3,28,31,27,0,3,32,22,23,0,4,38,28,2,1,12,5,44,26,27,0,6,29,21,4,1,2,34,20,26,20,0,20,32,1,28,14,2,9,0,7,8,8,1,8,0,0,1,6,8,0,1,1,1,6,8,4,1,6,8,1,1,8,6,1,3,1,2,1,6,8,2,1,6,8,3,1,6,10,2,1,7,8,1,1,8,1,3,7,8,1,2,10,2,1,8,2,2,7,8,1,8,3,2,7,8,1,2,1,8,5,1,9,0,1,6,9,0,1,7,8,8,1,8,7,1,6,8,5,1,8,4,1,6,8,8,1,5,2,9,0,5,2,1,8,5,2,8,6,8,6,1,6,8,6,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,15,97,100,100,105,116,105,118,101,95,112,111,108,105,99,121,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,14,98,117,114,110,95,112,117,98,108,105,115,104,101,114,3,99,97,112,5,99,108,97,105,109,14,99,108,97,105,109,95,97,110,100,95,107,101,101,112,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,17,99,111,109,112,97,116,105,98,108,101,95,112,111,108,105,99,121,6,100,101,108,101,116,101,15,100,101,112,95,111,110,108,121,95,112,111,108,105,99,121,6,100,105,103,101,115,116,11,102,114,111,109,95,109,111,100,117,108,101,12,102,114,111,109,95,112,97,99,107,97,103,101,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,14,109,97,107,101,95,105,109,109,117,116,97,98,108,101,11,109,111,100,117,108,101,95,110,97,109,101,3,110,101,119,6,111,98,106,101,99,116,22,111,110,108,121,95,97,100,100,105,116,105,118,101,95,117,112,103,114,97,100,101,115,17,111,110,108,121,95,100,101,112,95,117,112,103,114,97,100,101,115,7,112,97,99,107,97,103,101,6,112,111,108,105,99,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,16,112,117,98,108,105,115,104,101,100,95,109,111,100,117,108,101,17,112,117,98,108,105,115,104,101,100,95,112,97,99,107,97,103,101,11,114,101,99,101,105,112,116,95,99,97,112,15,114,101,99,101,105,112,116,95,112,97,99,107,97,103,101,8,114,101,115,116,114,105,99,116,6,115,101,110,100,101,114,13,116,105,99,107,101,116,95,100,105,103,101,115,116,14,116,105,99,107,101,116,95,112,97,99,107,97,103,101,13,116,105,99,107,101,116,95,112,111,108,105,99,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,5,116,121,112,101,115,15,117,112,103,114,97,100,101,95,112,97,99,107,97,103,101,14,117,112,103,114,97,100,101,95,112,111,108,105,99,121,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,2,1,0,2,1,128,2,1,192,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,26,8,7,36,8,4,31,8,4,1,2,4,26,8,7,36,8,6,54,3,37,2,2,2,4,13,8,6,36,8,6,37,2,20,10,2,3,2,2,13,8,6,36,8,6,0,1,0,0,19,18,14,0,56,0,4,4,5,8,11,1,1,7,0,39,56,1,12,2,11,1,17,31,14,2,17,24,14,2,17,25,18,0,2,1,1,0,0,2,8,11,0,10,1,56,2,11,1,46,17,33,56,3,2,2,1,0,0,2,6,11,0,19,0,1,1,17,27,2,3,1,0,0,19,9,56,1,12,1,14,1,17,24,11,0,16,0,20,33,2,4,1,0,0,29,23,56,1,12,2,14,2,17,24,10,0,16,0,20,33,4,17,14,2,17,25,11,0,16,1,20,33,12,1,5,21,11,0,1,9,12,1,11,1,2,5,1,0,0,2,3,11,0,16,1,2,6,1,0,0,2,3,11,0,16,0,2,7,1,0,0,2,4,11,0,16,2,20,2,8,1,0,0,2,4,11,0,16,3,20,2,9,1,0,0,2,4,11,0,16,4,20,2,10,1,0,0,2,4,11,0,16,5,20,2,11,1,0,0,2,4,11,0,16,6,20,2,12,1,0,0,2,4,11,0,16,7,20,2,13,1,0,0,2,4,11,0,16,8,20,2,14,1,0,0,2,3,11,0,16,9,2,15,1,0,0,2,2,7,5,2,16,1,0,0,2,2,7,6,2,17,1,0,0,2,2,7,7,2,18,1,4,0,2,4,11,0,7,6,17,23,2,19,1,4,0,2,4,11,0,7,7,17,23,2,20,1,4,0,2,7,11,0,19,1,1,1,1,17,27,2,21,1,0,0,30,41,7,8,17,29,12,3,10,0,16,2,20,10,3,34,4,10,5,14,11,0,1,7,2,39,10,1,10,0,16,4,20,38,4,21,5,25,11,0,1,7,1,39,10,0,16,2,20,12,4,11,3,10,0,15,2,21,11,0,46,56,4,11,4,11,1,11,2,18,2,2,22,1,0,0,30,39,11,1,19,3,12,3,12,2,10,0,46,56,4,11,2,33,4,11,5,15,11,0,1,7,4,39,10,0,16,2,17,30,7,8,33,4,22,5,26,11,0,1,7,3,39,11,3,10,0,15,2,21,10,0,16,3,20,6,1,0,0,0,0,0,0,0,22,11,0,15,3,21,2,23,0,0,0,2,16,10,0,16,4,20,10,1,37,4,7,5,11,11,0,1,7,1,39,11,1,11,0,15,4,21,2,0,1,0,2,1,1,1,2,1,3,2,1,2,2,3,0,3,1,2,3,0],"pay":[161,28,235,11,6,0,0,0,9,1,0,8,2,8,10,3,18,77,4,95,14,5,109,126,7,235,1,173,1,8,152,3,32,6,184,3,10,12,194,3,214,2,0,9,0,2,0,15,0,16,1,0,12,1,0,1,3,1,2,0,0,8,0,1,1,0,0,12,2,1,1,0,0,14,3,1,1,0,0,13,4,1,1,0,0,3,2,1,1,0,0,5,5,1,1,0,0,6,6,1,1,0,0,7,7,1,1,0,1,4,2,16,1,0,1,5,5,1,1,0,1,12,2,10,1,0,2,10,11,1,1,12,3,11,8,9,0,11,10,10,12,0,12,1,12,8,12,9,12,6,12,2,11,0,1,9,0,6,8,1,0,3,7,11,0,1,9,0,3,7,8,1,3,7,11,0,1,9,0,10,3,7,8,1,4,7,11,0,1,9,0,3,5,7,8,1,2,7,11,0,1,9,0,11,0,1,9,0,2,7,11,0,1,9,0,10,11,0,1,9,0,2,10,11,0,1,9,0,5,1,6,8,1,1,5,1,11,0,1,9,0,2,9,0,5,1,9,0,2,3,3,1,3,3,3,3,10,11,0,1,9,0,1,10,11,0,1,9,0,3,11,0,1,9,0,3,3,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,15,100,105,118,105,100,101,95,97,110,100,95,107,101,101,112,13,100,105,118,105,100,101,95,105,110,116,111,95,110,4,106,111,105,110,8,106,111,105,110,95,118,101,99,21,106,111,105,110,95,118,101,99,95,97,110,100,95,116,114,97,110,115,102,101,114,4,107,101,101,112,3,112,97,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,18,115,112,108,105,116,95,97,110,100,95,116,114,97,110,115,102,101,114,9,115,112,108,105,116,95,118,101,99,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,5,11,0,11,1,17,12,56,0,2,1,1,4,0,1,8,11,0,11,1,10,2,56,1,11,2,46,56,2,2,2,1,4,0,13,27,6,0,0,0,0,0,0,0,0,14,1,65,14,12,4,12,3,10,3,10,4,35,4,22,5,10,10,0,14,1,10,3,66,14,20,10,2,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,2,1,2,3,1,4,0,1,7,11,0,11,1,11,3,56,1,11,2,56,0,2,4,1,4,0,15,31,11,0,11,1,10,2,56,4,12,5,6,0,0,0,0,0,0,0,0,14,5,65,10,12,4,12,3,10,3,10,4,35,4,26,5,15,13,5,69,10,10,2,46,17,12,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,10,11,2,1,11,5,70,10,0,0,0,0,0,0,0,0,2,5,1,4,0,1,4,11,0,11,1,56,5,2,6,1,4,0,17,26,6,0,0,0,0,0,0,0,0,14,1,65,10,12,4,12,3,10,3,10,4,35,4,21,5,10,13,1,69,10,12,2,10,0,11,2,56,5,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,7,1,4,0,10,18,14,0,65,10,6,0,0,0,0,0,0,0,0,36,4,6,5,8,7,0,39,13,0,69,10,12,2,13,2,11,0,56,6,11,2,11,1,56,0,2,0],"priority_queue":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,12,3,16,60,4,76,10,5,86,167,1,7,253,1,184,1,8,181,3,64,6,245,3,14,10,131,4,18,11,149,4,4,12,153,4,243,5,13,140,10,4,14,144,10,4,0,11,1,16,0,1,6,1,2,0,0,0,6,1,2,0,0,6,0,1,1,2,0,8,2,3,1,2,0,4,4,5,1,2,0,7,3,6,1,2,0,2,7,0,1,2,0,13,8,5,1,2,0,5,9,5,1,2,0,9,10,11,1,2,1,12,15,13,1,0,1,14,15,13,1,0,6,13,9,6,5,13,8,16,8,13,1,10,11,1,1,9,0,1,11,0,1,9,0,1,7,11,0,1,9,0,2,3,9,0,3,7,11,0,1,9,0,3,9,0,0,1,11,1,1,9,0,2,10,3,10,9,0,2,7,10,11,1,1,9,0,3,3,7,10,11,1,1,9,0,3,3,1,6,11,0,1,9,0,1,10,3,2,3,3,1,9,0,3,3,3,9,0,2,7,10,9,0,3,1,3,5,3,3,3,10,11,1,1,9,0,9,0,5,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,13,7,10,11,1,1,9,0,1,3,7,10,11,1,1,9,0,3,1,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,3,3,2,3,10,3,5,69,110,116,114,121,13,80,114,105,111,114,105,116,121,81,117,101,117,101,14,99,114,101,97,116,101,95,101,110,116,114,105,101,115,7,101,110,116,114,105,101,115,6,105,110,115,101,114,116,21,109,97,120,95,104,101,97,112,105,102,121,95,114,101,99,117,114,115,105,118,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,7,112,111,112,95,109,97,120,10,112,114,105,111,114,105,116,105,101,115,8,112,114,105,111,114,105,116,121,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,6,114,101,109,111,118,101,22,114,101,115,116,111,114,101,95,104,101,97,112,95,114,101,99,117,114,115,105,118,101,11,115,119,97,112,95,114,101,109,111,118,101,5,118,97,108,117,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,10,3,1,0,0,2,1,3,10,11,1,1,9,0,1,2,2,10,3,15,9,0,0,13,1,13,0,1,0,0,12,24,14,0,65,6,12,2,10,2,6,2,0,0,0,0,0,0,0,26,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,21,5,12,11,1,6,1,0,0,0,0,0,0,0,23,12,1,13,0,10,2,10,1,56,0,5,7,11,0,57,0,2,1,1,0,0,14,30,10,0,55,0,65,6,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,10,0,54,0,6,0,0,0,0,0,0,0,0,56,1,58,1,12,3,12,2,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,6,0,0,0,0,0,0,0,0,56,0,11,2,11,3,2,2,1,0,0,16,17,10,0,54,0,11,1,11,2,57,1,68,6,10,0,55,0,65,6,6,1,0,0,0,0,0,0,0,23,12,3,11,0,54,0,11,3,56,2,2,3,1,0,0,5,4,11,0,11,1,57,1,2,4,1,0,0,17,40,14,0,65,16,12,3,14,1,65,13,10,3,33,4,9,5,11,6,0,0,0,0,0,0,0,0,39,64,6,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,38,5,20,13,0,6,0,0,0,0,0,0,0,0,56,3,12,4,13,1,6,0,0,0,0,0,0,0,0,56,4,12,6,13,5,11,4,11,6,57,1,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,5,2,5,0,0,0,18,46,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,1,6,1,0,0,0,0,0,0,0,23,6,2,0,0,0,0,0,0,0,26,12,6,10,0,10,1,12,3,12,2,10,0,10,6,12,5,12,4,11,2,46,11,3,66,6,55,1,20,11,4,46,11,5,66,6,55,1,20,36,4,43,10,0,11,1,10,6,71,6,11,0,11,6,56,2,5,45,11,0,1,2,6,0,0,0,19,110,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,2,10,1,35,4,12,5,16,11,0,1,6,1,0,0,0,0,0,0,0,39,10,2,6,2,0,0,0,0,0,0,0,24,6,1,0,0,0,0,0,0,0,22,12,13,10,13,6,1,0,0,0,0,0,0,0,22,12,15,10,2,12,14,10,13,10,1,35,4,55,10,0,10,13,12,5,12,3,10,0,10,14,12,7,12,6,11,3,46,11,5,66,6,55,1,20,11,6,46,11,7,66,6,55,1,20,36,12,8,5,57,9,12,8,11,8,4,61,11,13,12,14,10,15,10,1,35,4,88,10,0,10,15,12,10,12,9,10,0,10,14,12,12,12,11,11,9,46,11,10,66,6,55,1,20,11,11,46,11,12,66,6,55,1,20,36,12,4,5,90,9,12,4,11,4,4,94,11,15,12,14,10,14,10,2,34,4,107,10,0,10,14,11,2,71,6,11,0,11,1,11,14,56,0,5,109,11,0,1,2,7,1,0,0,20,28,7,1,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,0,55,0,65,6,35,4,24,5,11,13,2,10,0,55,0,10,1,66,6,55,1,20,68,16,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,4,11,0,1,11,2,2,0,0,1,0,0,13,1,13,0],"prover":[161,28,235,11,6,0,0,0,4,1,0,2,7,2,7,8,9,32,6,41,30,0,0,6,112,114,111,118,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0],"iota":[161,28,235,11,6,0,0,0,10,1,0,14,2,14,48,3,62,62,4,124,14,5,138,1,133,1,7,143,2,129,2,8,144,4,64,6,208,4,102,10,182,5,5,12,187,5,109,0,22,1,18,0,9,0,10,0,23,0,25,0,26,0,4,2,0,1,3,7,1,0,0,2,0,4,1,0,1,2,5,4,1,0,1,3,1,12,1,0,1,3,2,12,1,0,1,3,6,12,1,0,1,5,7,2,0,6,8,7,0,0,16,0,1,0,0,23,2,3,0,1,17,3,9,1,0,2,12,16,7,1,0,2,15,17,18,1,0,3,11,11,12,1,2,3,24,15,16,1,0,4,19,14,3,1,12,4,20,20,3,1,12,5,14,5,7,0,5,21,5,6,0,2,8,5,10,7,13,6,10,4,10,3,10,8,19,1,7,8,7,1,11,2,1,8,0,2,11,4,1,8,0,5,0,4,11,5,1,8,0,11,3,1,8,0,11,2,1,8,0,11,6,1,8,0,1,6,8,7,1,5,1,3,1,8,8,1,11,1,1,9,0,1,8,0,7,9,0,2,10,2,10,2,10,2,11,1,1,8,8,7,8,7,2,11,6,1,9,0,11,5,1,9,0,1,11,5,1,8,0,1,9,0,1,11,6,1,9,0,1,11,3,1,9,0,2,7,11,3,1,9,0,3,1,11,2,1,9,0,1,11,4,1,8,0,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,114,108,7,98,97,108,97,110,99,101,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,11,100,117,109,109,121,95,102,105,101,108,100,5,101,112,111,99,104,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,3,115,117,105,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,228,11,84,2,0,0,0,3,8,0,0,232,137,4,35,199,138,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,2,4,3,83,85,73,10,2,4,3,83,117,105,10,2,1,0,0,2,1,13,1,0,0,0,0,4,47,10,0,46,17,10,7,5,33,4,7,5,11,11,0,1,7,1,39,10,0,46,17,9,6,0,0,0,0,0,0,0,0,33,4,18,5,22,11,0,1,7,0,39,9,18,0,49,9,7,6,7,7,7,8,56,0,11,0,56,1,12,1,12,4,11,1,56,2,11,4,56,3,12,2,13,2,7,4,56,4,12,3,11,2,56,5,1,11,3,2,1,1,4,0,3,4,11,0,11,1,56,6,2,0],"table":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,16,3,24,115,4,139,1,10,5,149,1,104,7,253,1,167,1,8,164,3,32,6,196,3,10,10,206,3,8,11,214,3,2,12,216,3,229,1,13,189,5,4,14,193,5,4,0,19,0,10,0,16,0,20,0,0,12,2,7,1,4,1,2,2,4,0,3,1,2,0,0,15,0,1,2,7,4,0,3,2,3,2,7,4,0,4,4,5,2,7,4,0,5,6,7,2,7,4,0,17,6,8,2,7,4,0,6,4,9,2,7,4,0,14,10,11,2,7,4,0,13,10,9,2,7,4,0,8,1,3,2,7,4,0,9,1,3,2,7,6,1,3,14,3,2,7,4,1,4,15,5,2,7,4,1,5,16,7,2,7,4,1,11,15,9,2,7,4,1,17,16,8,2,7,4,2,7,12,3,0,2,15,0,12,0,10,13,11,13,12,13,14,13,13,13,1,7,8,2,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,2,8,1,3,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,1,18,3,0,13,0,1,0,0,3,5,11,0,17,16,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,17,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,15,2,9,1,0,0,3,5,11,0,58,0,1,17,15,2,0,0,0,1,0,13,1,13,0],"table_vec":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,18,3,24,116,4,140,1,22,5,162,1,138,1,7,172,2,164,1,8,208,3,32,6,240,3,20,10,132,4,10,11,142,4,2,12,144,4,130,2,13,146,6,2,14,148,6,2,0,18,0,17,0,19,0,1,4,1,4,1,1,0,12,2,7,1,4,1,2,2,2,0,0,9,0,1,1,4,0,16,2,1,1,4,0,11,3,4,1,4,0,10,3,5,1,4,0,4,6,7,1,4,0,14,8,9,1,4,0,5,10,11,1,4,0,13,12,13,1,4,0,7,1,9,1,4,0,8,1,9,1,6,1,3,19,9,2,7,4,1,4,17,18,2,7,4,1,5,20,21,2,7,4,1,7,15,9,2,7,4,1,8,15,9,2,7,6,1,11,16,4,2,7,4,1,12,0,15,2,7,4,1,15,20,22,2,7,4,16,14,0,13,5,13,15,14,2,13,11,14,10,14,12,14,17,14,13,14,14,14,1,7,8,2,1,11,0,1,9,0,2,9,0,7,8,2,1,6,11,0,1,9,0,1,3,1,1,2,6,11,0,1,9,0,3,1,6,9,0,2,7,11,0,1,9,0,9,0,0,2,7,11,0,1,9,0,3,1,7,9,0,1,7,11,0,1,9,0,1,9,0,2,3,9,0,1,11,1,2,9,0,9,1,1,6,11,1,2,9,0,9,1,2,6,11,1,2,9,0,9,1,9,0,1,6,9,1,3,7,11,1,2,9,0,9,1,9,0,9,1,2,7,11,1,2,9,0,9,1,9,0,1,7,9,1,1,9,1,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,5,101,109,112,116,121,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,6,11,1,2,3,9,0,0,13,0,1,0,0,9,4,11,0,56,0,57,0,2,1,1,0,0,1,8,11,1,56,1,12,2,13,2,11,0,56,2,11,2,2,2,1,0,0,9,4,11,0,55,0,56,3,2,3,1,0,0,9,5,11,0,56,4,6,0,0,0,0,0,0,0,0,33,2,4,1,0,0,9,15,10,0,56,4,10,1,36,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,5,2,5,1,0,0,4,10,10,0,46,56,4,12,2,11,0,54,0,11,2,11,1,56,6,2,6,1,0,0,9,16,10,0,46,56,4,10,1,36,4,7,5,11,11,0,1,7,0,39,11,0,54,0,11,1,56,7,2,7,1,0,0,4,20,10,0,46,56,4,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,56,8,2,8,1,0,0,9,12,14,0,56,4,6,0,0,0,0,0,0,0,0,33,4,6,5,8,7,1,39,11,0,58,0,56,9,2,9,1,0,0,9,4,11,0,58,0,56,10,2,0,0,0,13,0],"transfer":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,54,4,56,6,5,62,8,7,70,144,1,8,214,1,32,6,246,1,10,12,128,2,82,0,7,0,7,0,1,1,8,0,4,0,1,1,12,0,0,2,1,1,8,0,2,2,1,1,12,0,5,2,1,1,8,0,3,2,1,1,12,0,1,2,1,1,8,0,6,2,1,1,8,0,8,0,1,1,8,8,2,6,2,7,2,2,9,0,5,0,1,9,0,13,102,114,101,101,122,101,95,111,98,106,101,99,116,18,102,114,101,101,122,101,95,111,98,106,101,99,116,95,105,109,112,108,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,17,115,104,97,114,101,95,111,98,106,101,99,116,95,105,109,112,108,8,116,114,97,110,115,102,101,114,13,116,114,97,110,115,102,101,114,95,105,109,112,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,56,0,2,1,1,0,0,1,4,11,0,11,1,56,0,2,2,1,0,0,1,3,11,0,56,1,2,3,1,0,0,1,3,11,0,56,1,2,4,1,0,0,1,3,11,0,56,2,2,5,1,0,0,1,3,11,0,56,2,2,6,3,2,0,7,3,2,0,8,3,2,0,0],"transfer_policy":[161,28,235,11,6,0,0,0,13,1,0,26,2,26,78,3,104,150,2,4,254,2,50,5,176,3,192,3,7,240,6,138,5,8,250,11,64,6,186,12,60,10,246,12,55,11,173,13,10,12,183,13,150,5,13,205,18,16,14,221,18,16,0,63,1,48,1,65,0,19,0,21,0,29,0,32,0,47,0,49,0,60,0,62,0,64,0,70,0,10,0,1,0,1,0,7,12,1,0,1,0,8,12,1,0,1,0,9,3,1,0,1,0,5,7,1,2,1,1,3,7,1,0,0,2,12,7,0,3,0,4,1,0,1,4,1,12,1,0,1,7,2,7,0,7,13,4,0,8,4,12,0,9,6,2,0,11,11,2,0,12,14,7,1,3,0,0,46,0,1,1,0,0,45,2,3,1,0,0,24,2,4,1,0,0,71,5,6,1,0,0,26,7,6,1,0,0,22,8,0,1,0,0,17,9,4,3,0,2,6,0,38,10,11,3,0,2,6,0,18,12,4,2,0,2,0,16,13,4,2,0,2,0,39,14,15,2,0,2,0,55,16,4,3,0,2,6,0,66,14,17,1,0,0,67,16,18,1,0,0,56,14,19,1,0,0,44,20,21,1,0,0,50,20,22,1,0,0,34,20,21,1,0,1,27,41,25,1,0,1,43,40,15,1,0,2,37,4,23,1,0,3,69,42,22,1,0,3,72,4,32,1,0,4,35,46,44,1,0,4,52,58,4,1,0,4,61,43,44,1,0,5,15,54,4,2,7,4,5,20,56,57,2,7,4,5,33,56,15,1,7,5,54,61,52,2,7,4,6,30,25,4,1,3,7,25,29,4,0,7,40,39,21,1,8,7,45,28,29,0,7,68,17,21,0,8,36,27,15,1,0,10,58,25,4,1,8,10,62,37,4,1,8,11,57,35,36,0,12,23,50,15,1,3,12,31,4,24,1,3,12,41,55,4,1,3,12,42,24,48,1,3,12,54,62,4,1,3,12,59,49,22,1,3,40,23,35,25,30,30,22,31,1,25,36,34,37,33,32,34,19,22,18,22,21,31,25,31,23,31,42,23,44,23,39,23,10,51,26,53,20,52,41,23,27,53,24,31,28,59,29,53,43,23,3,8,9,3,8,9,1,11,0,1,9,0,2,6,8,11,7,8,13,2,11,1,1,9,0,11,2,1,9,0,0,4,7,11,1,1,9,0,6,11,2,1,9,0,11,5,1,3,7,8,13,1,11,8,1,8,12,3,11,1,1,9,0,11,2,1,9,0,7,8,13,2,6,11,1,1,9,0,11,0,1,9,0,4,9,1,7,11,1,1,9,0,6,11,2,1,9,0,9,2,2,9,1,6,11,1,1,9,0,1,6,9,2,3,9,1,7,11,1,1,9,0,11,8,1,8,12,2,9,1,7,11,0,1,9,0,1,6,11,1,1,9,0,1,1,2,7,11,1,1,9,0,6,11,2,1,9,0,1,6,8,10,1,7,8,10,1,6,11,14,1,8,6,1,6,11,0,1,9,0,1,8,9,1,3,1,8,6,1,11,14,1,9,0,1,9,0,5,8,10,11,14,1,8,6,11,7,1,8,12,8,10,8,9,1,6,8,11,1,7,8,13,1,8,10,1,11,3,1,9,0,1,8,12,1,11,7,1,9,0,1,11,2,1,9,0,1,11,1,1,9,0,1,6,8,13,1,5,2,9,0,5,3,3,3,3,1,6,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,1,6,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,13,1,11,8,1,9,0,2,11,7,1,8,12,8,10,2,11,7,1,9,0,7,8,13,7,10,8,6,8,9,8,9,3,11,14,1,8,6,8,6,3,1,10,9,0,1,6,11,14,1,9,0,2,6,11,14,1,9,0,6,9,0,2,9,0,9,1,1,9,1,2,11,4,1,9,1,9,2,3,7,8,10,9,0,9,1,2,7,11,14,1,9,0,9,0,2,6,8,10,9,0,1,6,9,1,2,7,11,7,1,9,0,11,8,1,9,0,1,11,4,1,9,1,2,8,6,7,11,14,1,8,6,2,7,8,10,9,0,2,7,11,14,1,9,0,6,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,9,80,117,98,108,105,115,104,101,114,7,82,117,108,101,75,101,121,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,17,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,97,112,21,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,114,101,97,116,101,100,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,86,101,99,83,101,116,3,97,100,100,11,97,100,100,95,114,101,99,101,105,112,116,8,97,100,100,95,114,117,108,101,14,97,100,100,95,116,111,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,4,99,111,105,110,15,99,111,110,102,105,114,109,95,114,101,113,117,101,115,116,8,99,111,110,116,97,105,110,115,7,100,101,102,97,117,108,116,6,100,101,108,101,116,101,20,100,101,115,116,114,111,121,95,97,110,100,95,119,105,116,104,100,114,97,119,12,100,101,115,116,114,111,121,95,115,111,109,101,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,7,101,120,105,115,116,115,95,4,102,114,111,109,12,102,114,111,109,95,98,97,108,97,110,99,101,12,102,114,111,109,95,112,97,99,107,97,103,101,3,103,101,116,8,103,101,116,95,114,117,108,101,8,104,97,115,95,114,117,108,101,2,105,100,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,7,105,115,95,115,111,109,101,4,105,116,101,109,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,4,112,97,105,100,9,112,111,108,105,99,121,95,105,100,3,112,117,116,8,114,101,99,101,105,112,116,115,6,114,101,109,111,118,101,11,114,101,109,111,118,101,95,114,117,108,101,5,114,117,108,101,115,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,105,122,101,3,115,117,105,4,116,97,107,101,8,116,114,97,110,115,102,101,114,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,3,117,105,100,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,7,118,101,99,95,115,101,116,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,4,44,8,9,50,3,34,8,9,53,11,14,1,8,6,1,2,3,40,8,10,19,11,7,1,8,12,56,11,14,1,8,6,2,2,2,40,8,10,51,8,9,3,2,1,40,8,9,4,2,1,28,1,0,25,3,25,1,25,2,25,4,52,0,1,0,0,4,6,11,0,11,1,11,2,56,0,57,0,2,1,1,0,0,26,32,11,0,56,1,4,4,5,8,11,1,1,6,0,0,0,0,0,0,0,0,39,10,1,17,33,12,5,14,5,17,34,12,6,10,6,57,1,56,2,11,5,12,2,56,0,12,3,56,3,12,4,11,2,11,4,11,3,57,2,11,1,17,33,11,6,57,3,2,2,0,4,0,33,11,11,0,10,1,56,4,12,2,56,5,11,2,11,1,46,17,38,56,6,2,3,1,0,0,38,49,10,0,46,56,7,11,1,55,0,20,33,4,9,5,15,11,0,1,11,3,1,7,4,39,14,2,56,8,4,37,11,2,56,9,12,6,10,6,10,0,55,1,56,10,37,4,28,5,34,11,0,1,11,3,1,7,5,39,11,6,12,4,5,41,10,0,55,1,56,10,12,4,11,4,12,5,11,0,54,1,11,5,11,3,56,11,2,4,1,0,0,45,27,14,0,56,7,14,1,55,0,20,33,4,8,5,12,11,2,1,7,4,39,11,1,58,3,1,12,4,11,0,58,2,1,12,3,17,31,11,4,17,31,11,3,11,2,56,12,2,5,1,0,0,47,52,11,1,58,0,12,6,12,3,12,5,12,4,11,6,56,13,12,2,14,2,65,23,12,8,10,8,10,0,55,2,56,14,33,4,19,5,23,11,0,1,7,0,39,10,8,6,0,0,0,0,0,0,0,0,36,4,46,5,28,13,2,69,23,12,7,10,0,55,2,14,7,56,15,4,37,5,41,11,0,1,7,1,39,11,8,6,1,0,0,0,0,0,0,0,23,12,8,5,23,11,0,1,11,4,11,5,11,3,2,6,1,0,0,4,34,10,1,46,56,7,11,2,55,0,20,33,4,9,5,13,11,1,1,7,4,39,10,1,46,56,16,32,4,19,5,23,11,1,1,7,3,39,10,1,54,3,9,57,4,11,3,56,17,11,1,54,2,56,18,56,19,2,7,1,0,0,4,6,11,1,55,3,9,57,4,56,20,2,8,1,0,0,4,14,10,1,46,56,16,4,5,5,9,11,1,1,7,2,39,11,1,54,1,11,2,56,21,2,9,1,0,0,4,5,11,1,54,4,56,18,56,19,2,10,1,0,0,4,6,11,0,55,3,9,57,4,56,22,2,11,1,0,0,60,28,10,0,46,56,7,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,10,0,54,3,9,57,4,56,23,1,11,0,54,2,12,3,56,18,12,2,11,3,14,2,56,24,2,12,1,0,0,4,3,11,0,55,3,2,13,1,0,0,4,16,10,0,46,56,7,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,11,0,54,3,2,14,1,0,0,4,3,11,0,55,2,2,15,1,0,0,4,4,11,0,55,5,20,2,16,1,0,0,4,4,11,0,55,6,20,2,17,1,0,0,4,4,11,0,55,7,20,2,2,1,1,1,1,2,1,0,0,3,0,0,0,1,0,2,0,25,1,25,2,25,3,25,4,25,5,25,6,25,7,25,0],"tx_context":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,24,7,65,111,8,176,1,32,6,208,1,20,10,228,1,14,12,242,1,107,13,221,2,10,0,8,0,0,2,0,0,7,0,1,0,0,2,0,2,0,0,3,0,3,0,0,4,0,3,0,0,5,4,1,0,0,6,0,3,0,0,1,5,1,0,1,6,8,0,1,5,1,6,10,2,1,3,1,7,8,0,2,10,2,3,0,2,5,3,9,84,120,67,111,110,116,101,120,116,9,100,101,114,105,118,101,95,105,100,6,100,105,103,101,115,116,5,101,112,111,99,104,18,101,112,111,99,104,95,116,105,109,101,115,116,97,109,112,95,109,115,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,11,105,100,115,95,99,114,101,97,116,101,100,6,115,101,110,100,101,114,10,116,120,95,99,111,110,116,101,120,116,7,116,120,95,104,97,115,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,32,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,5,7,5,9,10,2,3,3,4,3,6,3,0,1,0,0,6,4,11,0,16,0,20,2,1,1,0,0,6,3,11,0,16,1,2,2,1,0,0,6,4,11,0,16,2,20,2,3,1,0,0,6,4,11,0,16,3,20,2,4,1,0,0,7,18,10,0,16,4,20,12,2,10,0,16,1,20,10,2,17,6,12,1,11,2,6,1,0,0,0,0,0,0,0,22,11,0,15,4,21,11,1,2,5,0,0,0,6,4,11,0,16,4,20,2,6,0,2,0,0,0,0,1,0,2,0,3,0,4,0],"types":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,6,7,14,26,8,40,32,12,72,4,0,1,0,0,0,1,1,2,1,6,9,0,1,1,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,5,116,121,112,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"url":[161,28,235,11,6,0,0,0,9,1,0,4,2,4,8,3,12,25,5,37,20,7,57,78,8,135,1,64,10,199,1,6,12,205,1,50,13,255,1,2,0,8,1,2,0,1,7,0,1,0,7,0,0,4,0,1,0,0,5,2,1,0,0,3,3,0,0,0,7,4,5,0,1,6,2,0,0,1,8,1,1,8,0,1,10,2,1,6,8,0,2,7,8,0,8,1,0,6,83,116,114,105,110,103,3,85,114,108,5,97,115,99,105,105,9,105,110,110,101,114,95,117,114,108,10,110,101,119,95,117,110,115,97,102,101,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,6,115,116,114,105,110,103,6,117,112,100,97,116,101,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,8,8,1,0,1,0,0,5,3,11,0,18,0,2,1,1,0,0,5,4,11,0,17,4,18,0,2,2,1,0,0,5,4,11,0,16,0,20,2,3,1,0,0,5,5,11,1,11,0,15,0,21,2,0,0,0],"vec_map":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,22,3,28,168,1,4,196,1,28,5,224,1,254,1,7,222,3,153,2,8,247,5,64,6,183,6,50,10,233,6,21,11,254,6,4,12,130,7,235,5,13,237,12,6,14,243,12,6,0,30,1,21,1,31,0,2,7,2,1,0,0,0,0,0,7,2,1,0,0,0,1,1,7,1,0,0,0,7,0,1,2,1,0,0,14,2,0,2,1,0,0,23,3,4,2,1,0,0,22,5,4,2,1,0,0,13,3,6,2,1,0,0,8,7,8,2,1,0,0,28,7,9,2,1,1,0,3,7,10,2,1,0,0,26,11,12,2,1,0,0,16,11,10,2,1,0,0,5,1,0,2,1,0,0,15,1,13,2,1,0,0,19,11,14,2,1,0,0,12,7,15,2,1,0,0,11,7,12,2,1,0,0,9,16,17,2,1,0,0,10,18,19,2,1,0,0,24,18,4,2,1,0,1,6,27,24,1,0,1,17,28,10,1,0,1,20,0,27,1,0,1,27,24,27,1,0,2,16,25,10,1,0,2,23,23,24,1,0,2,25,31,0,1,0,7,4,14,4,23,20,22,20,5,4,21,26,20,26,13,4,19,12,8,4,24,20,21,12,20,12,18,12,0,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,2,7,11,0,2,9,0,9,1,6,9,0,2,9,0,9,1,1,7,11,0,2,9,0,9,1,1,7,9,1,2,6,11,0,2,9,0,9,1,6,9,0,1,6,9,1,1,11,2,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,2,10,9,0,10,9,1,1,10,9,0,1,11,2,1,3,2,6,11,0,2,9,0,9,1,3,2,6,9,0,6,9,1,2,7,11,0,2,9,0,9,1,3,2,6,9,0,7,9,1,1,11,1,2,9,0,9,1,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,9,0,1,6,10,9,0,1,9,1,1,11,2,1,9,0,1,6,11,2,1,9,0,1,10,11,1,2,9,0,9,1,7,10,11,1,2,9,0,9,1,3,9,0,10,9,0,3,9,1,10,9,1,1,7,10,9,0,4,6,11,1,2,9,0,9,1,3,10,9,0,3,2,3,3,1,6,11,1,2,9,0,9,1,1,7,11,1,2,9,0,9,1,5,69,110,116,114,121,6,79,112,116,105,111,110,6,86,101,99,77,97,112,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,3,103,101,116,16,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,20,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,95,109,117,116,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,7,103,101,116,95,109,117,116,6,105,110,115,101,114,116,16,105,110,116,111,95,107,101,121,115,95,118,97,108,117,101,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,3,107,101,121,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,3,112,111,112,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,101,110,116,114,121,95,98,121,95,105,100,120,7,114,101,118,101,114,115,101,4,115,105,122,101,4,115,111,109,101,7,116,114,121,95,103,101,116,5,118,97,108,117,101,7,118,101,99,95,109,97,112,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,1,4,10,11,1,2,9,0,9,1,1,2,2,18,9,0,29,9,1,0,4,1,4,0,1,0,0,0,3,64,20,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,21,20,10,0,14,1,12,3,46,11,3,56,0,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,11,2,57,1,68,20,2,2,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,56,2,58,1,2,3,1,0,0,0,15,10,0,55,0,56,3,32,4,6,5,10,11,0,1,7,4,39,11,0,54,0,69,20,58,1,2,4,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,67,20,54,1,2,5,1,0,0,12,10,10,0,11,1,56,1,12,2,11,0,55,0,11,2,66,20,55,1,2,6,1,0,0,9,19,10,0,10,1,56,0,4,11,11,0,11,1,56,4,20,56,5,12,2,5,17,11,0,1,11,1,1,56,6,12,2,11,2,2,7,1,0,0,15,7,11,0,11,1,56,7,12,2,14,2,56,8,2,8,1,0,0,0,4,11,0,55,0,65,20,2,9,1,0,0,0,5,11,0,56,9,6,0,0,0,0,0,0,0,0,33,2,10,1,0,0,29,12,11,0,58,0,12,1,14,1,56,3,4,7,5,9,7,2,39,11,1,70,20,0,0,0,0,0,0,0,0,2,11,1,0,0,30,40,11,0,58,0,12,1,13,1,56,10,6,0,0,0,0,0,0,0,0,12,2,14,1,65,20,12,5,64,24,0,0,0,0,0,0,0,0,12,4,64,26,0,0,0,0,0,0,0,0,12,7,10,2,10,5,35,4,35,5,19,13,1,69,20,58,1,12,6,12,3,13,4,11,3,68,24,13,7,11,6,68,26,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,14,11,1,70,20,0,0,0,0,0,0,0,0,11,4,11,7,2,12,1,0,0,32,32,6,0,0,0,0,0,0,0,0,12,2,10,0,55,0,65,20,12,4,64,24,0,0,0,0,0,0,0,0,12,3,10,2,10,4,35,4,28,5,13,10,0,55,0,10,2,66,20,12,1,13,3,11,1,55,2,20,68,24,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,8,11,0,1,11,3,2,13,1,0,0,33,36,6,0,0,0,0,0,0,0,0,12,2,10,0,56,9,12,3,10,2,10,3,35,4,30,5,10,10,0,55,0,10,2,66,20,55,2,10,1,33,4,25,11,0,1,11,1,1,11,2,56,11,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,12,2,14,1,0,0,15,13,11,0,11,1,56,7,12,2,14,2,56,8,4,8,5,10,7,1,39,11,2,56,13,2,15,1,0,0,34,20,10,1,10,0,56,9,35,4,6,5,10,11,0,1,7,3,39,11,0,55,0,11,1,66,20,12,2,10,2,55,2,11,2,55,1,2,16,1,0,0,35,21,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,67,20,12,2,10,2,55,2,11,2,54,1,2,17,1,0,0,0,17,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,56,2,58,1,2,0,0,1,1,1,0,0,4,1,4,2,4,0],"vec_set":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,12,3,18,102,4,120,20,5,140,1,95,7,235,1,164,1,8,143,3,64,6,207,3,20,10,227,3,7,11,234,3,2,12,236,3,156,2,13,136,6,2,14,138,6,2,0,19,1,14,1,20,0,1,7,1,3,0,1,0,7,1,0,0,0,5,0,1,1,3,0,16,2,1,1,3,0,8,3,0,1,3,0,15,4,0,1,3,0,2,5,6,1,3,0,17,7,8,1,3,0,10,7,6,1,3,0,9,1,9,1,3,0,12,7,10,1,3,0,7,5,11,1,3,0,6,5,8,1,3,1,4,17,2,1,0,1,11,15,6,1,0,1,13,0,17,1,0,1,18,2,17,1,0,2,15,14,2,1,0,2,16,2,9,1,0,16,2,4,2,10,2,15,2,9,2,12,8,5,2,14,8,13,8,11,8,0,1,11,0,1,9,0,1,9,0,2,7,11,0,1,9,0,9,0,2,7,11,0,1,9,0,6,9,0,2,6,11,0,1,9,0,6,9,0,1,1,1,6,11,0,1,9,0,1,3,1,10,9,0,1,6,10,9,0,1,11,1,1,3,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,6,11,1,1,9,0,2,3,3,1,11,1,1,9,0,6,79,112,116,105,111,110,6,86,101,99,83,101,116,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,4,115,105,122,101,4,115,111,109,101,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,3,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,12,18,10,0,14,1,12,2,46,11,2,56,1,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,68,2,2,3,1,0,0,13,13,10,0,11,1,12,2,46,11,2,56,2,12,3,11,0,54,0,11,3,56,3,1,2,4,1,0,0,11,7,11,0,11,1,56,4,12,2,14,2,56,5,2,5,1,0,0,0,4,11,0,55,0,65,2,2,6,1,0,0,0,5,11,0,56,6,6,0,0,0,0,0,0,0,0,33,2,7,1,0,0,0,3,11,0,58,0,2,8,1,0,0,0,3,11,0,55,0,2,9,0,0,0,16,35,6,0,0,0,0,0,0,0,0,12,2,10,0,56,6,12,3,10,2,10,3,35,4,29,5,10,10,0,55,0,10,2,66,2,10,1,33,4,24,11,0,1,11,1,1,11,2,56,7,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,8,2,10,0,0,0,11,13,11,0,11,1,56,4,12,2,14,2,56,5,4,8,5,10,7,1,39,11,2,56,9,2,0,0,0,2,0],"versioned":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,20,3,28,85,4,113,10,5,123,97,7,220,1,236,1,8,200,3,32,6,232,3,10,10,242,3,16,12,130,4,197,1,13,199,5,4,0,23,0,11,0,16,0,20,0,4,12,0,0,3,0,0,2,0,7,0,2,2,4,0,3,1,2,0,0,8,0,1,1,4,0,22,2,3,0,0,13,2,4,1,4,0,14,5,6,1,4,0,19,5,7,1,4,0,21,8,9,1,4,0,10,1,10,1,4,1,5,14,9,2,7,4,1,6,15,16,2,7,4,1,7,17,18,2,7,4,1,18,17,19,2,7,4,2,9,12,9,0,2,12,4,20,1,8,2,15,11,12,0,7,13,8,13,9,13,10,13,12,1,3,3,9,0,7,8,4,1,8,0,1,6,8,0,1,3,1,6,9,0,1,7,8,0,1,7,9,0,2,9,0,8,1,4,7,8,0,3,9,0,8,1,0,1,9,0,1,7,8,4,1,8,3,2,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,8,2,3,8,3,9,0,3,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,16,86,101,114,115,105,111,110,67,104,97,110,103,101,67,97,112,9,86,101,114,115,105,111,110,101,100,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,2,105,100,10,108,111,97,100,95,118,97,108,117,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,3,110,101,119,6,111,98,106,101,99,116,11,111,108,100,95,118,101,114,115,105,111,110,6,114,101,109,111,118,101,24,114,101,109,111,118,101,95,118,97,108,117,101,95,102,111,114,95,117,112,103,114,97,100,101,10,116,120,95,99,111,110,116,101,120,116,7,117,112,103,114,97,100,101,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,12,118,101,114,115,105,111,110,101,100,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,3,22,3,1,2,2,24,8,2,17,3,0,1,0,0,1,12,11,2,17,13,10,0,18,0,12,3,13,3,15,0,11,0,11,1,56,0,11,3,2,1,1,0,0,9,4,11,0,16,1,20,2,2,1,0,0,9,7,10,0,16,0,11,0,16,1,20,56,1,2,3,1,0,0,9,7,10,0,15,0,11,0,16,1,20,56,2,2,4,1,0,0,9,14,10,0,15,0,10,0,16,1,20,56,3,10,0,46,56,4,11,0,16,1,20,18,1,2,5,1,0,0,3,32,11,3,19,1,12,4,10,0,46,56,4,33,4,9,5,13,11,0,1,7,0,39,11,4,10,1,35,4,18,5,22,11,0,1,7,0,39,10,0,15,0,10,1,11,2,56,0,11,1,11,0,15,1,21,2,6,1,0,0,21,12,11,0,19,0,12,3,12,1,13,1,11,3,56,3,12,2,11,1,17,11,11,2,2,0,0,0,1,0]},"type_origin_table":[{"module_name":"tx_context","struct_name":"TxContext","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"ID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"UID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_field","struct_name":"Field","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bag","struct_name":"Bag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Supply","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Balance","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bcs","struct_name":"BCS","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Referent","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"clock","struct_name":"Clock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"url","struct_name":"Url","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"Coin","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CoinMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"TreasuryCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CurrencyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"VecMap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"Publisher","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeTicket","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeReceipt","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"Display","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"DisplayCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"VersionUpdated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_object_field","struct_name":"Wrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"Curve","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PreparedVerifyingKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PublicProofInputs","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"ProofPoints","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_set","struct_name":"VecSet","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"iota","struct_name":"IOTA","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferRequest","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicy","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"RuleKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Kiosk","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"KioskOwnerCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"PurchaseCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Item","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Listing","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Lock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemListed","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemPurchased","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemDelisted","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk_extension","struct_name":"Extension","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk_extension","struct_name":"ExtensionKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"LinkedTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"Node","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_bag","struct_name":"ObjectBag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_table","struct_name":"ObjectTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"PriorityQueue","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table","struct_name":"Table","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table_vec","struct_name":"TableVec","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"Versioned","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"VersionChangeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"ACKQVv64dXCmpxE1QPU2QMLxVpmtbzrFGMtWYY6szJrQ","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000003","version":7,"module_map":{"genesis":[161,28,235,11,6,0,0,0,11,1,0,26,2,26,58,3,84,107,4,191,1,14,5,205,1,176,2,7,253,3,137,9,8,134,13,96,6,230,13,20,10,250,13,93,12,215,14,219,3,13,178,18,24,0,31,1,44,1,72,2,18,2,20,2,43,2,61,2,66,0,54,0,63,0,64,0,67,0,70,0,3,3,0,0,2,3,0,0,9,0,0,0,8,0,0,1,4,7,1,0,0,3,0,4,1,0,1,4,1,12,1,0,1,5,11,4,0,6,5,2,0,7,10,2,0,8,6,4,0,10,7,4,0,11,12,4,0,0,22,0,1,0,0,15,2,1,0,0,14,3,1,0,1,25,25,26,1,0,1,36,24,14,1,0,2,35,22,14,1,0,3,26,9,1,1,0,3,53,8,9,1,0,3,75,1,9,1,0,4,29,30,31,1,0,6,65,32,1,0,7,27,5,6,0,8,22,17,18,0,9,22,19,1,0,10,23,15,16,0,11,13,34,1,0,11,42,12,10,0,11,52,29,1,0,12,32,27,28,0,12,34,13,14,0,7,7,8,7,5,21,4,23,3,23,9,7,6,7,6,8,7,11,5,1,8,8,8,1,10,8,0,8,2,7,8,9,0,4,11,5,1,8,8,10,8,3,7,10,8,12,7,8,9,1,7,10,8,12,25,10,8,3,3,3,10,2,3,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,8,10,3,11,5,1,8,8,11,5,1,8,8,5,8,11,8,12,10,8,12,10,2,10,2,1,6,8,9,1,3,1,8,8,2,7,11,5,1,9,0,3,1,11,5,1,9,0,1,8,12,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,9,2,6,10,8,12,6,8,12,1,1,8,3,3,3,3,3,3,3,7,8,9,1,8,11,5,11,5,1,8,8,3,3,13,7,8,9,1,8,10,8,8,7,10,8,12,11,5,1,8,8,3,3,8,11,8,10,7,8,9,5,11,5,1,8,8,3,5,11,4,1,5,5,1,8,3,1,6,10,9,0,1,5,1,6,11,4,1,9,0,1,11,4,1,9,0,1,9,0,2,7,10,8,12,5,1,7,8,12,4,7,8,12,11,5,1,8,8,5,7,8,9,2,11,5,1,9,0,7,8,9,1,11,6,1,9,0,2,11,6,1,8,8,5,2,3,3,2,7,8,12,3,7,66,97,108,97,110,99,101,4,67,111,105,110,22,71,101,110,101,115,105,115,67,104,97,105,110,80,97,114,97,109,101,116,101,114,115,24,71,101,110,101,115,105,115,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,15,84,111,107,101,110,65,108,108,111,99,97,116,105,111,110,25,84,111,107,101,110,68,105,115,116,114,105,98,117,116,105,111,110,83,99,104,101,100,117,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,9,86,97,108,105,100,97,116,111,114,8,97,99,116,105,118,97,116,101,19,97,99,116,105,118,97,116,101,95,118,97,108,105,100,97,116,111,114,115,15,97,108,108,111,99,97,116,101,95,116,111,107,101,110,115,11,97,108,108,111,99,97,116,105,111,110,115,11,97,109,111,117,110,116,95,109,105,115,116,7,98,97,108,97,110,99,101,24,99,104,97,105,110,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,4,99,111,105,110,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,12,102,114,111,109,95,98,97,108,97,110,99,101,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,9,105,109,97,103,101,95,117,114,108,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,4,110,97,109,101,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,18,110,101,116,119,111,114,107,95,112,117,98,108,105,99,95,107,101,121,3,110,101,119,6,111,98,106,101,99,116,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,19,112,114,111,116,111,99,111,108,95,112,117,98,108,105,99,95,107,101,121,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,17,114,101,99,105,112,105,101,110,116,95,97,100,100,114,101,115,115,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,23,115,116,97,107,101,95,115,117,98,115,105,100,121,95,102,117,110,100,95,109,105,115,116,41,115,116,97,107,101,95,115,117,98,115,105,100,121,95,105,110,105,116,105,97,108,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,21,115,116,97,107,101,100,95,119,105,116,104,95,118,97,108,105,100,97,116,111,114,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,118,97,108,105,100,97,116,111,114,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,13,118,97,108,105,100,97,116,111,114,95,115,101,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,6,118,101,99,116,111,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,17,119,111,114,107,101,114,95,112,117,98,108,105,99,95,107,101,121,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,15,39,10,2,24,10,2,33,10,2,47,10,2,62,5,30,3,21,3,49,10,2,48,10,2,41,10,2,74,10,2,40,10,2,45,10,2,46,10,2,73,10,2,1,2,12,50,3,19,3,28,3,59,3,57,3,58,3,55,13,37,3,38,3,69,3,71,3,68,3,2,2,2,56,3,16,10,8,3,3,2,3,51,5,17,3,60,11,4,1,5,0,0,0,0,4,147,1,10,5,46,17,11,6,0,0,0,0,0,0,0,0,33,4,7,5,11,11,5,1,7,0,39,11,4,19,2,12,6,12,22,13,1,11,22,56,0,12,24,56,1,12,23,64,10,0,0,0,0,0,0,0,0,12,28,14,3,65,11,12,8,6,0,0,0,0,0,0,0,0,12,11,10,11,10,8,35,4,89,5,33,14,3,10,11,66,11,20,19,0,12,29,12,17,12,16,12,14,12,30,12,15,12,19,12,20,12,7,12,10,12,25,12,18,12,12,12,9,12,13,11,25,11,20,11,15,11,30,11,19,11,13,11,9,11,12,11,18,11,14,11,16,11,17,11,29,11,10,11,7,10,5,17,16,12,27,14,28,14,27,17,19,32,4,77,5,81,11,5,1,7,1,39,13,28,11,27,68,10,11,11,6,1,0,0,0,0,0,0,0,22,12,11,5,28,11,1,11,6,13,28,10,5,17,1,13,28,17,2,14,2,16,0,20,14,2,16,1,20,14,2,16,2,20,14,2,16,3,20,14,2,16,4,20,14,2,16,5,20,14,2,16,6,20,10,5,17,14,12,26,11,24,14,2,16,7,20,14,2,16,8,20,14,2,16,9,20,10,5,17,12,12,21,11,0,11,28,11,23,14,2,16,10,20,14,2,16,11,20,11,26,11,21,11,5,17,13,2,1,0,0,0,20,44,14,1,56,2,32,4,35,5,5,13,1,69,21,19,3,12,7,12,5,12,6,13,0,11,5,56,0,12,4,14,7,56,3,4,29,11,7,56,4,12,8,10,2,11,8,17,18,11,4,11,6,10,3,17,17,5,34,11,4,10,3,56,5,11,6,17,10,5,0,11,2,1,11,3,1,11,1,70,21,0,0,0,0,0,0,0,0,11,0,56,6,2,2,0,0,0,33,24,10,0,46,65,10,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,1,35,4,21,5,11,10,0,10,2,67,10,6,0,0,0,0,0,0,0,0,17,15,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,2,1,2,1,3,1,7,1,8,1,9,1,10,1,11,1,4,1,5,1,6,1,0,1,1,0],"stake_subsidy":[161,28,235,11,6,0,0,0,12,1,0,12,2,12,22,3,34,37,4,71,4,5,75,74,7,149,1,176,2,8,197,3,64,6,133,4,28,10,161,4,20,12,181,4,180,1,13,233,5,10,15,243,5,4,0,18,1,6,1,7,1,14,1,21,1,23,0,3,4,0,1,0,12,0,2,1,4,1,0,1,4,2,2,0,5,4,2,0,0,8,0,1,0,0,5,2,3,0,0,10,4,5,0,1,16,7,8,0,2,17,13,14,1,0,2,24,11,5,1,0,3,15,12,5,0,5,10,4,10,5,11,2,1,8,3,3,3,13,7,8,4,1,8,0,1,7,8,0,1,11,2,1,8,3,1,6,8,0,1,3,0,1,7,8,4,1,8,1,3,4,11,2,1,8,3,3,1,8,3,1,6,11,2,1,9,0,2,3,3,2,7,11,2,1,9,0,3,1,11,2,1,9,0,3,66,97,103,7,66,97,108,97,110,99,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,84,120,67,111,110,116,101,120,116,13,97,100,118,97,110,99,101,95,101,112,111,99,104,3,98,97,103,7,98,97,108,97,110,99,101,6,99,114,101,97,116,101,27,99,117,114,114,101,110,116,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,28,99,117,114,114,101,110,116,95,101,112,111,99,104,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,20,100,105,115,116,114,105,98,117,116,105,111,110,95,99,111,117,110,116,101,114,12,101,120,116,114,97,95,102,105,101,108,100,115,7,103,101,110,101,115,105,115,4,109,97,116,104,3,109,105,110,3,110,101,119,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,6,7,11,2,1,8,3,11,3,9,3,20,3,19,13,12,8,1,0,3,0,0,6,19,10,3,7,0,75,37,4,6,5,10,11,4,1,7,1,39,11,0,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,11,4,17,3,18,0,2,1,3,0,0,9,57,10,0,16,0,20,10,0,16,1,56,0,17,6,12,3,10,0,15,1,11,3,56,1,12,2,10,0,16,2,20,6,1,0,0,0,0,0,0,0,22,10,0,15,2,21,10,0,16,2,20,10,0,16,3,20,25,6,0,0,0,0,0,0,0,0,33,4,53,10,0,16,0,20,53,10,0,16,4,20,53,24,7,0,26,12,1,10,0,16,0,20,11,1,52,23,11,0,15,0,21,5,55,11,0,1,11,2,2,2,1,0,0,6,8,10,0,16,0,20,11,0,16,1,56,0,17,6,2,0,2,0,0,0,1,0,3,0,4,0,13,0,22,0],"staking_pool":[161,28,235,11,6,0,0,0,12,1,0,20,2,20,52,3,72,173,2,4,245,2,34,5,151,3,205,2,7,228,5,200,8,8,172,14,96,6,140,15,200,1,10,212,16,66,12,150,17,145,11,13,167,28,28,15,195,28,4,0,68,1,45,2,14,2,15,2,40,2,44,2,69,2,72,2,73,2,74,0,7,12,0,0,4,7,0,0,6,12,0,1,3,7,1,0,0,2,0,12,0,3,1,4,1,0,1,5,2,7,0,5,10,4,0,6,5,2,0,7,8,12,2,7,1,4,1,9,9,2,0,0,42,0,1,0,0,59,2,3,0,0,60,4,5,0,0,79,6,7,0,0,75,3,5,0,0,22,8,9,0,0,58,10,9,0,0,57,11,9,0,0,56,11,9,0,0,80,12,5,0,0,11,13,9,0,0,19,13,9,0,0,71,14,15,0,0,51,16,17,0,0,67,16,15,0,0,66,16,15,0,0,35,14,18,0,0,33,14,18,0,0,64,19,3,0,0,65,19,9,0,0,39,20,9,0,0,32,21,18,0,0,54,22,23,0,0,48,14,15,0,0,49,14,15,0,0,24,14,24,0,0,70,25,15,0,0,52,25,15,0,0,36,22,18,0,0,27,26,15,0,0,28,26,15,0,0,31,9,23,0,0,17,22,9,0,1,16,48,37,1,0,1,26,46,9,1,0,1,29,52,47,1,3,1,34,48,18,1,0,1,37,48,18,1,0,1,43,9,31,1,0,1,63,47,31,1,0,2,42,0,34,0,3,38,40,15,1,0,3,64,45,33,1,0,3,78,36,15,1,0,3,81,9,33,1,0,4,41,42,15,0,5,21,30,9,0,5,30,37,17,1,8,5,42,0,30,0,7,13,43,9,2,7,4,7,16,53,54,2,7,4,7,18,53,18,2,7,4,7,42,0,29,2,7,4,8,73,50,9,1,8,9,23,39,15,0,9,62,39,49,0,52,28,38,15,44,32,43,32,47,1,41,32,49,28,42,32,34,15,39,15,36,15,37,15,53,3,35,15,33,15,51,28,50,28,1,7,8,10,1,8,0,4,7,8,0,11,5,1,8,8,3,7,8,10,1,8,2,3,7,8,0,8,2,7,8,10,1,11,5,1,8,8,2,7,8,0,8,2,2,3,11,5,1,8,8,2,7,8,0,11,5,1,8,8,0,2,7,8,0,7,8,10,1,7,8,0,4,7,8,0,3,3,3,2,7,8,0,3,1,6,8,0,1,3,1,6,8,2,1,8,6,1,1,3,7,8,2,3,7,8,10,2,7,8,2,8,2,2,6,8,2,6,8,2,2,6,8,0,3,1,8,1,1,6,11,9,2,3,8,1,1,6,8,1,2,6,8,1,3,1,11,9,2,3,8,1,2,3,8,1,1,11,9,2,9,0,9,1,1,8,7,1,11,3,1,9,0,1,8,8,1,11,5,1,9,0,1,8,4,2,8,2,3,1,6,11,5,1,9,0,1,6,9,0,5,3,11,5,1,8,8,3,11,5,1,8,8,3,1,6,8,10,2,7,11,5,1,9,0,11,5,1,9,0,3,3,8,1,11,5,1,8,8,2,3,3,3,7,11,9,2,9,0,9,1,9,0,9,1,5,3,3,8,1,3,3,2,7,11,5,1,9,0,3,2,7,11,3,1,9,0,9,0,1,9,0,1,6,11,3,1,9,0,1,5,2,9,0,5,2,6,8,2,11,5,1,8,8,2,6,11,3,1,9,0,9,0,2,6,11,9,2,9,0,9,1,9,0,1,6,9,1,3,3,8,1,3,3,66,97,103,7,66,97,108,97,110,99,101,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,16,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,3,97,100,100,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,24,99,104,101,99,107,95,98,97,108,97,110,99,101,95,105,110,118,97,114,105,97,110,116,115,8,99,111,110,116,97,105,110,115,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,18,100,101,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,6,100,101,108,101,116,101,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,5,101,112,111,99,104,14,101,120,99,104,97,110,103,101,95,114,97,116,101,115,12,101,120,116,114,97,95,102,105,101,108,100,115,4,102,105,108,108,14,103,101,116,95,115,117,105,95,97,109,111,117,110,116,16,103,101,116,95,116,111,107,101,110,95,97,109,111,117,110,116,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,2,105,100,21,105,110,105,116,105,97,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,25,105,115,95,101,113,117,97,108,95,115,116,97,107,105,110,103,95,109,101,116,97,100,97,116,97,11,105,115,95,105,110,97,99,116,105,118,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,21,105,115,95,112,114,101,97,99,116,105,118,101,95,97,116,95,101,112,111,99,104,7,105,115,95,115,111,109,101,4,106,111,105,110,15,106,111,105,110,95,115,116,97,107,101,100,95,115,117,105,4,109,97,116,104,3,109,105,110,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,27,112,101,110,100,105,110,103,95,112,111,111,108,95,116,111,107,101,110,95,119,105,116,104,100,114,97,119,13,112,101,110,100,105,110,103,95,115,116,97,107,101,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,26,112,101,110,100,105,110,103,95,116,111,116,97,108,95,115,117,105,95,119,105,116,104,100,114,97,119,7,112,111,111,108,95,105,100,17,112,111,111,108,95,116,111,107,101,110,95,97,109,111,117,110,116,18,112,111,111,108,95,116,111,107,101,110,95,98,97,108,97,110,99,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,9,112,114,105,110,99,105,112,97,108,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,30,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,12,114,101,119,97,114,100,115,95,112,111,111,108,6,115,101,110,100,101,114,4,115,111,109,101,5,115,112,108,105,116,16,115,112,108,105,116,95,115,116,97,107,101,100,95,115,117,105,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,97,109,111,117,110,116,11,115,117,105,95,98,97,108,97,110,99,101,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,17,117,110,119,114,97,112,95,115,116,97,107,101,100,95,115,117,105,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,5,118,97,108,117,101,23,119,105,116,104,100,114,97,119,95,102,114,111,109,95,112,114,105,110,99,105,112,97,108,16,119,105,116,104,100,114,97,119,95,114,101,119,97,114,100,115,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,0,2,11,30,8,7,12,11,3,1,3,20,11,3,1,3,71,3,61,11,5,1,8,8,53,3,24,11,9,2,3,8,1,47,3,50,3,46,3,25,8,4,1,2,2,70,3,52,3,2,2,4,30,8,7,51,8,6,66,3,55,11,5,1,8,8,0,3,0,0,27,18,10,0,56,0,12,1,10,0,17,48,56,1,56,1,6,0,0,0,0,0,0,0,0,56,2,6,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,0,17,40,18,0,2,1,3,0,0,35,45,14,1,56,3,12,5,10,0,46,17,17,32,4,9,5,15,11,0,1,11,3,1,7,11,39,10,5,6,0,0,0,0,0,0,0,0,36,4,20,5,26,11,0,1,11,3,1,7,18,39,11,3,17,48,10,0,46,56,4,11,2,11,1,18,2,12,4,10,0,16,0,20,11,5,22,11,0,15,0,21,11,4,2,2,3,0,0,38,52,10,0,11,1,17,3,12,4,12,3,14,4,56,3,12,5,10,0,10,5,10,3,11,2,46,17,54,17,9,12,6,11,5,14,6,56,3,22,12,7,10,0,16,1,20,11,7,22,10,0,15,1,21,10,0,16,2,20,11,3,22,10,0,15,2,21,10,0,46,17,17,4,44,11,0,17,7,5,46,11,0,1,13,4,11,6,56,5,1,11,4,2,3,3,0,0,41,31,14,1,16,3,20,10,0,46,56,4,33,4,9,5,13,11,0,1,7,2,39,11,0,14,1,16,4,20,12,2,46,11,2,17,22,12,3,11,1,17,4,12,4,14,3,14,4,56,3,17,30,11,4,2,4,0,0,0,5,8,11,0,19,2,12,1,1,1,17,46,11,1,2,5,3,0,0,9,15,10,0,16,5,20,14,1,56,3,22,10,0,15,5,21,11,0,15,6,11,1,56,5,1,2,6,3,0,0,42,28,11,1,46,17,54,6,1,0,0,0,0,0,0,0,22,12,3,10,0,17,7,10,0,17,8,10,0,15,7,10,3,10,0,16,5,20,10,0,16,8,20,18,1,56,6,11,0,11,3,12,2,46,11,2,17,32,2,7,0,0,0,9,29,10,0,16,5,20,10,0,16,1,20,23,10,0,15,5,21,10,0,16,8,20,10,0,16,2,20,23,10,0,15,8,21,6,0,0,0,0,0,0,0,0,10,0,15,1,21,6,0,0,0,0,0,0,0,0,11,0,15,2,21,2,8,3,0,0,23,31,10,0,16,5,20,10,0,16,8,20,18,1,12,1,10,0,16,5,20,10,0,16,0,20,22,10,0,15,5,21,14,1,10,0,16,5,20,17,30,10,0,15,8,21,6,0,0,0,0,0,0,0,0,11,0,15,0,21,2,9,0,0,0,44,33,10,0,11,3,12,4,46,11,4,17,22,12,6,14,6,11,2,17,29,12,8,10,8,10,1,38,4,20,11,8,11,1,23,12,5,5,22,6,0,0,0,0,0,0,0,0,12,5,11,5,10,0,16,6,56,3,17,45,12,7,11,0,15,6,11,7,56,7,2,10,3,0,0,9,29,10,0,15,7,10,1,17,31,56,6,10,0,46,17,16,4,10,5,14,11,0,1,7,15,39,10,0,46,17,17,32,4,20,5,24,11,0,1,7,17,39,11,0,15,9,11,1,56,8,2,11,3,0,0,9,16,10,0,46,17,17,32,4,6,5,10,11,0,1,7,12,39,11,1,56,9,11,0,15,10,21,2,12,1,0,0,9,4,11,0,16,5,20,2,13,1,0,0,9,4,11,0,16,3,20,2,14,1,0,0,9,4,11,0,16,11,56,3,2,15,1,0,0,9,4,11,0,16,4,20,2,16,1,0,0,9,4,11,0,16,9,56,10,2,17,1,0,0,9,4,11,0,16,10,56,11,2,18,1,0,0,15,53,10,0,16,11,56,3,12,3,10,1,10,3,37,4,9,5,15,11,0,1,11,2,1,7,4,39,11,3,10,1,23,7,0,38,4,22,5,28,11,0,1,11,2,1,7,19,39,10,1,7,0,38,4,33,5,39,11,0,1,11,2,1,7,19,39,11,2,17,48,10,0,16,3,20,10,0,16,4,20,11,0,15,11,11,1,56,7,18,2,2,19,1,4,0,9,9,11,0,11,1,10,2,17,18,11,2,46,17,55,56,12,2,20,1,4,0,51,24,10,0,14,1,12,2,46,11,2,17,21,4,8,5,12,11,0,1,7,13,39,11,1,19,2,12,3,1,1,17,46,11,0,15,11,11,3,56,5,1,2,21,1,0,0,18,25,10,0,16,3,20,10,1,16,3,20,33,4,17,11,0,16,4,20,11,1,16,4,20,33,12,2,5,23,11,0,1,11,1,1,9,12,2,11,2,2,22,1,0,0,42,45,10,0,10,1,17,28,4,8,11,0,1,17,31,2,10,0,16,10,10,1,56,13,11,1,17,45,12,3,10,0,16,9,56,14,20,12,2,10,3,10,2,38,4,41,5,25,10,0,16,7,10,3,56,15,4,36,11,0,16,7,11,3,56,16,20,2,11,3,6,1,0,0,0,0,0,0,0,23,12,3,5,20,11,0,1,17,31,2,23,1,0,0,9,4,11,0,16,0,20,2,24,1,0,0,9,4,11,0,16,1,20,2,25,3,0,0,9,3,11,0,16,7,2,26,1,0,0,9,4,11,0,16,12,20,2,27,1,0,0,9,4,11,0,16,13,20,2,28,0,0,0,18,17,10,0,17,16,4,8,11,0,1,8,12,2,5,15,11,0,16,9,56,14,20,11,1,36,12,2,11,2,2,29,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,12,20,53,11,1,53,24,11,0,16,13,20,53,26,52,2,30,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,13,20,53,11,1,53,24,11,0,16,12,20,53,26,52,2,31,0,0,0,9,4,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,18,1,2,32,0,0,0,55,22,10,0,11,1,17,22,12,3,14,3,10,0,16,5,20,17,30,12,4,11,0,16,8,20,12,2,11,4,11,2,33,4,19,5,21,7,10,39,2,0,7,0,8,0,9,2,1,2,2,0,3,0,4,0,6,0,5,0,1,0,2,2,3,1,0,1,1,0,76,0,77,0],"storage_fund":[161,28,235,11,6,0,0,0,11,1,0,6,2,6,14,3,20,44,4,64,8,5,72,73,7,145,1,178,1,8,195,2,64,10,131,3,15,12,146,3,107,13,253,3,4,15,129,4,2,0,9,1,4,1,10,0,2,4,0,1,0,4,1,0,1,2,1,2,0,0,6,0,1,0,0,3,2,0,0,0,13,3,4,0,0,12,3,4,0,1,5,8,4,1,0,1,8,9,7,1,0,1,14,10,4,1,0,1,15,5,7,1,0,7,6,4,6,5,6,6,6,1,11,1,1,8,2,1,8,0,6,7,8,0,11,1,1,8,2,11,1,1,8,2,11,1,1,8,2,3,3,1,6,8,0,1,3,0,1,8,2,1,11,1,1,9,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,6,11,1,1,9,0,7,66,97,108,97,110,99,101,3,83,85,73,11,83,116,111,114,97,103,101,70,117,110,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,4,106,111,105,110,3,110,101,119,22,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,98,97,108,97,110,99,101,5,115,112,108,105,116,12,115,116,111,114,97,103,101,95,102,117,110,100,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,13,116,111,116,97,108,95,98,97,108,97,110,99,101,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,11,1,1,8,2,7,11,1,1,8,2,0,3,0,0,5,4,56,0,11,0,18,0,2,1,3,0,0,0,30,10,0,15,0,11,2,56,1,1,10,0,15,0,11,3,56,1,1,10,0,15,1,11,1,56,1,1,10,0,15,1,11,5,56,2,12,6,10,0,15,0,11,6,56,1,1,11,0,15,1,11,4,56,2,2,2,1,0,0,5,4,11,0,16,1,56,3,2,3,1,0,0,5,8,10,0,16,1,56,3,11,0,16,0,56,3,22,2,0,1,0,0,0,11,0],"iota_system":[161,28,235,11,6,0,0,0,12,1,0,30,2,30,78,3,108,188,3,4,168,4,16,5,184,4,214,3,7,142,8,237,13,8,251,21,96,6,219,22,54,10,145,23,8,12,153,23,251,6,13,148,30,4,15,152,30,2,0,57,1,33,2,20,2,22,2,24,2,32,2,56,2,60,2,61,2,62,0,54,0,55,0,58,0,83,0,84,0,8,8,0,1,3,7,1,0,0,2,0,4,1,0,1,3,1,12,1,0,1,5,2,7,0,5,14,4,0,6,5,2,0,7,12,12,2,7,1,4,1,9,13,2,0,10,6,4,0,11,4,7,0,11,7,12,0,12,9,4,0,12,10,4,0,12,11,4,0,13,16,4,0,14,15,12,0,0,23,0,1,0,0,42,2,1,0,0,44,3,1,0,0,41,3,1,0,0,43,3,1,0,0,46,4,1,0,0,52,4,1,0,0,45,5,1,0,0,51,5,1,0,0,38,6,1,0,0,40,6,7,0,0,39,8,1,0,0,47,9,1,0,0,48,9,10,0,0,37,11,1,0,0,63,11,1,0,0,49,3,1,0,0,73,12,1,0,0,71,12,1,0,0,72,12,1,0,0,81,12,1,0,0,74,12,1,0,0,64,12,1,0,0,76,12,1,0,0,66,12,1,0,0,77,12,1,0,0,67,12,1,0,0,79,12,1,0,0,69,12,1,0,0,78,13,1,0,0,68,13,1,0,0,80,12,1,0,0,70,12,1,0,0,75,12,1,0,0,65,12,1,0,0,34,14,15,0,0,17,16,17,0,0,19,18,10,0,0,30,16,19,0,0,31,16,20,0,0,29,16,20,0,3,25,39,40,1,0,4,18,26,1,2,7,4,4,21,49,53,2,7,4,4,36,49,50,2,7,4,8,35,35,1,1,12,8,53,28,1,1,8,9,50,33,34,0,12,17,19,17,0,12,19,47,10,0,12,23,22,23,0,12,27,1,24,0,12,34,46,15,0,12,37,43,1,0,12,38,36,7,0,12,39,37,7,0,12,41,30,1,0,12,42,29,1,0,12,43,30,1,0,12,44,30,1,0,12,45,32,1,0,12,46,31,1,0,12,47,42,10,0,12,49,30,1,0,12,51,32,1,0,12,52,31,1,0,12,59,19,24,0,12,63,43,1,0,12,64,44,1,0,12,65,44,1,0,12,66,44,1,0,12,67,44,1,0,12,68,45,1,0,12,69,44,1,0,12,70,44,1,0,12,71,44,1,0,12,72,44,1,0,12,73,44,1,0,12,74,44,1,0,12,75,44,1,0,12,76,44,1,0,12,77,44,1,0,12,78,45,1,0,12,79,44,1,0,12,80,44,1,0,12,81,44,1,0,12,82,23,51,0,42,25,46,27,45,7,41,38,45,41,44,25,42,52,43,52,8,8,5,10,8,15,11,2,1,8,6,3,3,8,14,8,9,7,8,8,0,16,7,8,0,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,8,2,7,8,0,7,8,8,3,7,8,0,6,8,16,3,3,7,8,0,3,7,8,8,4,7,8,0,11,3,1,8,6,5,7,8,8,1,8,11,5,7,8,0,10,11,3,1,8,6,11,1,1,3,5,7,8,8,3,7,8,0,8,11,7,8,8,1,11,2,1,8,6,3,7,8,0,6,8,16,5,3,7,8,0,10,2,6,8,8,4,7,8,0,10,2,10,2,6,8,8,2,7,8,0,6,8,4,1,6,11,7,2,3,8,10,1,7,8,0,1,10,5,11,11,2,1,8,6,11,2,1,8,6,7,8,0,3,3,3,3,3,3,3,7,8,8,1,6,8,13,1,7,8,13,3,8,0,8,12,3,7,10,8,15,11,2,1,8,6,3,3,8,14,8,9,7,8,8,1,8,12,1,3,2,3,8,12,3,7,8,5,9,0,9,1,1,8,0,1,9,0,16,7,8,13,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,8,2,7,8,13,7,8,8,3,7,8,13,6,8,16,3,3,7,8,13,3,7,8,8,1,6,8,8,1,5,2,9,0,5,4,7,8,13,11,3,1,8,6,5,7,8,8,5,7,8,13,10,11,3,1,8,6,11,1,1,3,5,7,8,8,1,8,6,2,11,2,1,9,0,7,8,8,1,11,3,1,9,0,1,11,3,1,8,6,3,7,8,13,8,11,7,8,8,3,7,8,13,6,8,16,5,3,7,8,13,10,2,6,8,8,4,7,8,13,10,2,10,2,6,8,8,2,7,8,13,6,8,4,11,7,8,13,3,3,11,2,1,8,6,11,2,1,8,6,3,3,3,3,3,7,8,8,2,7,8,13,8,13,2,7,8,5,9,0,1,9,1,1,8,13,2,3,8,13,1,7,9,1,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,14,83,117,105,83,121,115,116,101,109,83,116,97,116,101,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,26,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,101,115,3,97,100,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,4,99,111,105,110,6,99,114,101,97,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,2,105,100,24,108,111,97,100,95,105,110,110,101,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,17,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,21,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,95,109,117,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,19,112,111,111,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,27,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,110,111,110,95,101,110,116,114,121,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,32,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,95,110,111,110,95,101,110,116,114,121,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,6,115,101,110,100,101,114,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,28,8,5,85,3,0,3,0,0,21,23,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,50,12,9,17,51,12,10,11,0,10,10,18,0,12,8,13,8,15,0,11,10,11,9,56,0,11,8,56,1,2,1,1,4,0,1,19,11,0,17,39,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,11,15,17,57,2,2,1,4,0,1,5,11,0,17,39,11,1,17,59,2,3,1,4,0,1,5,11,0,17,39,11,1,17,56,2,4,1,4,0,1,5,11,0,17,39,11,1,17,58,2,5,1,4,0,1,6,11,0,17,39,11,1,11,2,17,61,2,6,1,4,0,1,6,11,0,17,39,11,1,11,2,17,65,2,7,1,4,0,1,6,11,0,17,39,11,1,11,2,17,60,2,8,1,4,0,1,6,11,0,17,39,11,1,11,2,17,64,2,9,1,4,0,1,10,11,0,11,1,11,2,10,3,17,10,11,3,46,17,47,56,2,2,10,1,0,0,1,7,11,0,17,39,11,1,11,2,11,3,17,54,2,11,1,4,0,1,12,11,0,17,39,11,1,11,2,11,3,10,4,17,55,11,4,46,17,47,56,2,2,12,1,4,0,1,11,11,0,11,1,10,2,17,13,10,2,56,3,11,2,46,17,47,56,4,2,13,1,0,0,1,6,11,0,17,39,11,1,11,2,17,62,2,14,1,4,0,1,6,11,0,17,39,11,1,11,2,17,53,2,15,1,4,0,1,6,11,0,17,39,11,1,11,2,17,67,2,16,1,4,0,1,5,11,0,17,39,11,1,17,63,2,17,1,4,0,1,6,11,0,17,39,11,1,11,2,17,77,2,18,1,4,0,1,6,11,0,17,39,11,1,11,2,17,75,2,19,1,4,0,1,6,11,0,17,39,11,1,11,2,17,76,2,20,1,4,0,1,6,11,0,17,39,11,1,11,2,17,85,2,21,1,4,0,1,6,11,0,17,39,11,1,11,2,17,78,2,22,1,4,0,1,6,11,0,17,39,11,1,11,2,17,68,2,23,1,4,0,1,6,11,0,17,39,11,1,11,2,17,80,2,24,1,4,0,1,6,11,0,17,39,11,1,11,2,17,70,2,25,1,4,0,1,6,11,0,17,39,11,1,11,2,17,81,2,26,1,4,0,1,6,11,0,17,39,11,1,11,2,17,71,2,27,1,4,0,1,6,11,0,17,39,11,1,11,2,17,83,2,28,1,4,0,1,6,11,0,17,39,11,1,11,2,17,73,2,29,1,4,0,1,7,11,0,17,39,11,1,11,2,11,3,17,82,2,30,1,4,0,1,7,11,0,17,39,11,1,11,2,11,3,17,72,2,31,1,4,0,1,6,11,0,17,39,11,1,11,2,17,84,2,32,1,4,0,1,6,11,0,17,39,11,1,11,2,17,74,2,33,1,4,0,1,6,11,0,17,39,11,1,11,2,17,79,2,34,1,4,0,1,6,11,0,17,39,11,1,11,2,17,69,2,35,1,0,0,1,5,11,0,17,39,11,1,17,52,2,36,1,0,0,1,4,11,0,17,38,17,48,2,37,0,0,0,20,29,11,2,17,39,12,11,10,10,46,17,47,7,2,33,4,10,5,16,11,11,1,11,10,1,7,0,39,11,11,11,3,11,4,11,0,11,1,11,5,11,6,11,7,11,8,11,9,11,10,17,49,2,38,0,0,0,1,4,11,0,17,40,46,2,39,0,0,0,1,3,11,0,17,40,2,40,0,0,0,48,47,10,0,16,1,20,6,1,0,0,0,0,0,0,0,33,4,25,10,0,15,0,10,0,16,1,20,56,5,17,86,12,2,6,2,0,0,0,0,0,0,0,10,0,15,1,21,10,0,15,0,10,0,16,1,20,11,2,56,6,10,0,15,0,10,0,16,1,20,56,7,12,1,10,1,46,17,66,11,0,16,1,20,33,4,41,5,45,11,1,1,7,1,39,11,1,2,0,0,0,1,0,26,0],"iota_system_state_inner":[161,28,235,11,6,0,0,0,12,1,0,45,2,45,108,3,153,1,235,5,4,132,7,50,5,182,7,151,7,7,205,14,129,30,8,206,44,96,6,174,45,117,10,163,46,189,1,12,224,47,134,18,13,230,65,46,15,148,66,4,0,115,1,70,2,27,2,28,2,29,2,41,2,69,2,72,2,113,2,117,2,123,2,124,2,177,1,2,178,1,0,103,0,106,0,109,0,164,1,0,165,1,0,169,1,0,13,4,0,0,14,4,0,0,10,4,0,0,11,4,0,0,12,3,0,1,4,7,1,0,0,2,0,12,0,3,1,4,1,0,1,4,2,12,1,0,1,6,3,7,0,8,6,2,0,9,15,12,2,7,1,4,1,11,16,2,0,12,21,7,2,1,0,0,0,13,22,7,1,3,0,14,7,4,0,15,5,7,0,15,8,12,0,16,9,4,0,17,18,4,0,18,17,12,0,18,19,2,0,19,20,4,0,0,31,0,1,0,0,32,2,3,0,0,163,1,1,4,0,0,83,5,6,0,0,85,7,6,0,0,82,7,6,0,0,84,7,6,0,0,87,8,6,0,0,99,8,6,0,0,86,9,6,0,0,98,9,6,0,0,80,10,11,0,0,81,12,11,0,0,88,13,14,0,0,78,15,6,0,0,125,15,6,0,0,79,16,6,0,0,126,16,6,0,0,89,7,6,0,0,154,1,17,6,0,0,152,1,17,6,0,0,153,1,17,6,0,0,162,1,17,6,0,0,155,1,17,6,0,0,132,1,17,6,0,0,157,1,17,6,0,0,134,1,17,6,0,0,158,1,17,6,0,0,135,1,17,6,0,0,160,1,17,6,0,0,137,1,17,6,0,0,159,1,18,6,0,0,136,1,18,6,0,0,161,1,17,6,0,0,138,1,17,6,0,0,156,1,17,6,0,0,133,1,17,6,0,0,25,19,14,0,0,38,20,21,0,0,74,20,21,0,0,116,20,21,0,0,46,6,21,0,0,40,20,21,0,0,170,1,22,21,0,0,171,1,22,23,0,0,172,1,20,24,0,0,49,22,25,0,0,51,20,21,0,0,50,20,21,0,0,73,26,27,0,0,23,20,28,0,0,43,29,14,0,1,34,99,68,1,0,1,59,98,63,1,0,2,66,39,40,0,3,35,38,6,1,0,3,60,85,21,1,0,3,101,89,38,1,0,3,176,1,87,21,1,0,3,181,1,84,38,1,0,3,182,1,6,38,1,0,4,44,100,58,1,0,4,56,58,38,1,0,5,36,68,6,1,3,7,61,97,6,1,0,10,75,101,6,1,12,11,38,43,21,0,11,95,43,44,0,12,30,67,63,2,1,0,12,37,6,36,2,1,0,12,47,67,93,2,1,0,12,48,71,72,2,1,0,12,55,70,6,2,1,0,12,77,71,77,2,1,0,13,30,73,63,1,3,13,37,6,69,1,3,13,55,74,6,1,3,13,58,76,63,1,3,13,77,75,6,1,3,13,100,68,69,1,3,14,25,88,14,0,15,102,60,21,0,16,25,91,14,0,16,66,14,34,0,16,118,86,21,0,16,120,86,21,0,17,66,45,42,0,17,67,78,6,0,17,87,54,6,0,17,96,57,6,0,17,97,54,6,0,17,127,79,6,0,17,128,1,79,6,0,17,129,1,79,6,0,17,130,1,79,6,0,17,131,1,82,6,0,17,139,1,79,6,0,17,140,1,79,6,0,17,141,1,79,6,0,17,142,1,79,6,0,17,143,1,79,6,0,17,144,1,79,6,0,17,145,1,79,6,0,17,146,1,79,6,0,17,147,1,79,6,0,17,148,1,82,6,0,17,149,1,79,6,0,17,150,1,79,6,0,17,151,1,79,6,0,18,179,1,65,66,0,19,23,33,28,0,19,24,33,49,0,19,25,90,6,0,19,26,81,6,0,19,33,33,21,0,19,52,56,53,0,19,53,56,53,0,19,54,52,53,0,19,57,62,63,0,19,66,31,32,0,19,68,33,21,0,19,73,94,27,0,19,80,59,11,0,19,82,48,6,0,19,83,46,6,0,19,84,47,6,0,19,85,47,6,0,19,86,55,6,0,19,88,61,14,0,19,107,33,24,0,19,121,33,21,0,19,171,1,62,23,0,19,173,1,62,21,0,19,180,1,51,50,0,69,35,60,37,62,37,68,35,79,44,72,35,71,35,74,44,76,44,78,44,77,44,73,35,59,37,56,37,58,37,57,37,63,92,70,35,75,44,64,37,53,21,52,21,61,37,65,96,55,37,7,10,8,19,11,7,1,8,10,3,3,8,0,8,15,7,8,12,1,8,2,8,3,3,3,3,3,3,3,7,8,12,1,8,0,1,8,3,16,7,8,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,0,2,7,8,3,7,8,12,3,7,8,3,6,8,20,3,3,7,8,3,3,7,8,12,4,7,8,3,11,8,1,8,10,5,7,8,12,1,8,17,5,7,8,3,10,11,8,1,8,10,11,5,1,3,5,7,8,12,3,7,8,3,8,17,7,8,12,1,11,7,1,8,10,3,7,8,3,6,8,20,5,3,8,21,5,7,11,13,2,5,11,14,1,5,3,7,8,3,10,2,6,8,12,4,7,8,3,10,2,10,2,6,8,12,11,7,8,3,3,3,11,7,1,8,10,11,7,1,8,10,3,3,3,3,3,7,8,12,1,6,8,3,1,3,2,6,8,3,5,1,8,9,1,6,11,11,2,8,9,5,1,11,14,1,5,2,7,8,3,6,8,9,1,6,11,11,2,3,8,16,1,10,5,3,10,11,8,1,8,10,11,5,1,3,7,8,12,2,3,8,22,2,10,8,19,7,8,12,1,8,22,1,6,8,22,1,8,18,2,5,11,14,1,5,1,11,13,2,9,0,9,1,1,8,10,1,11,7,1,9,0,1,7,8,12,1,8,6,23,3,3,3,3,3,8,6,8,0,3,3,1,11,7,1,8,10,3,3,11,7,1,8,10,8,15,3,8,6,8,18,3,3,11,13,2,5,11,14,1,5,3,8,22,1,8,19,1,6,8,12,1,5,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,3,7,8,22,8,19,7,8,12,2,7,8,22,7,8,12,3,7,8,22,3,7,8,12,1,6,10,8,19,1,8,21,3,7,8,22,6,8,20,2,3,7,8,22,6,8,21,1,1,7,8,19,3,7,8,19,8,21,3,3,7,8,22,3,6,8,12,2,7,8,22,6,8,12,2,7,8,19,3,1,11,8,1,9,0,4,7,8,22,5,11,7,1,8,10,7,8,12,1,6,8,17,3,7,8,22,8,17,7,8,12,2,6,8,22,5,1,1,4,6,5,6,5,5,7,11,14,1,5,1,6,8,21,1,6,5,2,6,11,13,2,9,0,9,1,6,9,0,1,9,0,1,11,14,1,9,0,3,7,11,13,2,9,0,9,1,9,0,9,1,2,7,11,13,2,9,0,9,1,6,9,0,1,7,9,1,2,6,11,14,1,9,0,6,9,0,2,7,11,14,1,9,0,9,0,2,7,11,14,1,9,0,6,9,0,1,6,11,14,1,9,0,2,9,0,9,1,2,7,8,19,7,8,12,2,7,8,19,10,2,2,7,8,19,6,8,19,2,6,8,22,6,8,19,3,7,8,19,10,2,10,2,44,1,3,3,3,3,3,3,1,1,1,11,7,1,8,10,3,3,3,3,3,3,3,3,4,3,3,3,11,7,1,8,10,3,3,3,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,3,11,7,1,8,10,4,11,7,1,8,10,4,3,3,3,3,4,3,1,7,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,1,6,8,18,1,6,11,7,1,9,0,1,7,8,15,2,7,11,7,1,9,0,3,9,7,8,22,7,11,7,1,8,10,7,11,7,1,8,10,7,11,13,2,5,11,14,1,5,3,3,3,3,7,8,12,6,7,8,18,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,1,8,4,1,6,9,1,2,7,8,22,6,8,9,5,11,7,1,8,10,3,11,7,1,8,10,11,8,1,8,10,11,7,1,8,10,1,11,8,1,8,10,2,7,11,8,1,9,0,10,11,8,1,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,2,11,7,1,9,0,7,8,12,2,9,0,5,3,66,97,103,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,11,83,116,111,114,97,103,101,70,117,110,100,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,20,83,121,115,116,101,109,69,112,111,99,104,73,110,102,111,69,118,101,110,116,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,18,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,86,50,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,6,86,101,99,77,97,112,6,86,101,99,83,101,116,26,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,101,115,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,3,98,97,103,7,98,97,108,97,110,99,101,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,5,101,109,112,116,121,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,24,101,112,111,99,104,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,20,101,120,116,114,97,99,116,95,99,111,105,110,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,3,103,101,116,7,103,101,116,95,109,117,116,16,103,101,116,95,114,101,112,111,114,116,101,114,115,95,111,102,31,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,111,98,106,101,99,116,95,114,101,98,97,116,101,115,30,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,116,111,116,97,108,95,98,97,108,97,110,99,101,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,6,105,110,115,101,114,116,12,105,110,116,111,95,98,97,108,97,110,99,101,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,106,111,105,110,8,106,111,105,110,95,118,101,99,28,108,101,102,116,111,118,101,114,95,115,116,111,114,97,103,101,95,102,117,110,100,95,105,110,102,108,111,119,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,19,109,105,110,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,3,110,101,119,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,114,97,109,101,116,101,114,115,3,112,97,121,19,112,111,111,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,115,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,19,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,21,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,9,115,97,102,101,95,109,111,100,101,29,115,97,102,101,95,109,111,100,101,95,99,111,109,112,117,116,97,116,105,111,110,95,114,101,119,97,114,100,115,36,115,97,102,101,95,109,111,100,101,95,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,115,116,111,114,97,103,101,95,102,101,101,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,119,97,114,100,115,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,9,115,105,110,103,108,101,116,111,110,5,115,112,108,105,116,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,13,115,116,97,107,101,95,115,117,98,115,105,100,121,20,115,116,97,107,101,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,12,115,116,97,107,105,110,103,95,112,111,111,108,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,14,115,116,111,114,97,103,101,95,99,104,97,114,103,101,12,115,116,111,114,97,103,101,95,102,117,110,100,20,115,116,111,114,97,103,101,95,102,117,110,100,95,98,97,108,97,110,99,101,25,115,116,111,114,97,103,101,95,102,117,110,100,95,114,101,105,110,118,101,115,116,109,101,110,116,14,115,116,111,114,97,103,101,95,114,101,98,97,116,101,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,5,116,97,98,108,101,13,116,111,116,97,108,95,98,97,108,97,110,99,101,14,116,111,116,97,108,95,103,97,115,95,102,101,101,115,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,31,116,111,116,97,108,95,115,116,97,107,101,95,114,101,119,97,114,100,115,95,100,105,115,116,114,105,98,117,116,101,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,26,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,24,118,97,108,105,100,97,116,111,114,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,31,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,10,118,97,108,105,100,97,116,111,114,115,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,3,8,1,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,8,39,3,105,3,63,3,65,3,167,1,3,174,1,3,166,1,3,42,8,6,1,2,9,39,3,105,3,64,3,63,3,65,3,167,1,3,174,1,3,166,1,3,42,8,6,2,2,16,38,3,74,3,116,3,175,1,8,22,109,8,18,71,8,0,76,3,168,1,11,13,2,5,11,14,1,5,103,8,15,90,1,94,11,7,1,8,10,91,11,7,1,8,10,93,3,92,3,40,3,42,8,6,3,2,16,38,3,74,3,116,3,175,1,8,22,109,8,18,71,8,1,76,3,168,1,11,13,2,5,11,14,1,5,103,8,15,90,1,94,11,7,1,8,10,91,11,7,1,8,10,93,3,92,3,40,3,42,8,6,4,2,12,38,3,74,3,76,3,121,3,111,3,108,3,112,3,110,3,104,3,119,3,122,3,62,3,0,3,0,0,30,27,11,0,10,6,17,119,12,8,14,8,17,114,12,7,6,0,0,0,0,0,0,0,0,11,2,17,41,11,8,11,1,17,83,11,4,11,7,56,0,11,5,9,56,1,56,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,3,11,6,17,54,18,2,2,1,3,0,0,6,11,11,0,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,54,18,0,2,2,3,0,0,41,55,11,0,19,2,12,17,12,3,12,12,12,13,12,11,12,14,12,10,12,15,12,21,12,9,12,7,12,18,12,23,1,12,8,12,1,11,7,19,0,12,6,12,19,12,22,12,20,12,5,12,4,12,16,12,2,11,1,11,8,6,2,0,0,0,0,0,0,0,11,23,11,18,11,2,11,16,6,4,0,0,0,0,0,0,0,11,4,11,5,11,20,11,22,11,19,11,6,18,1,11,9,11,21,11,15,11,10,11,14,11,11,11,13,11,12,11,3,11,17,18,3,2,3,3,0,0,42,26,10,15,46,17,67,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,10,15,17,86,12,16,11,0,15,0,11,16,11,15,17,124,2,4,3,0,0,6,5,11,0,15,0,11,1,17,126,2,5,3,0,0,6,25,10,0,16,0,17,120,10,0,16,1,16,2,20,35,4,10,5,16,11,0,1,11,1,1,7,3,39,10,0,15,0,11,0,16,1,16,3,20,11,1,17,123,2,6,3,0,0,6,31,10,0,16,0,17,111,65,42,10,0,16,1,16,4,20,38,4,26,10,0,16,0,17,120,10,0,16,1,16,4,20,36,4,20,5,26,11,0,1,11,1,1,7,3,39,11,0,15,0,11,1,17,125,2,7,3,0,0,50,15,10,0,15,0,11,1,7,1,17,133,1,12,3,11,0,15,0,14,3,9,17,117,11,3,11,2,17,88,2,8,3,0,0,50,15,10,0,15,0,11,1,7,2,17,133,1,12,3,11,0,15,0,14,3,8,17,117,11,3,11,2,17,90,2,9,3,0,0,6,7,11,0,15,0,11,1,11,2,46,17,127,2,10,3,0,0,6,8,11,0,15,0,11,2,46,17,116,11,1,17,89,2,11,3,0,0,6,8,11,0,15,0,11,2,11,1,56,2,11,3,17,122,2,12,3,0,0,14,12,11,1,11,2,10,4,17,51,12,5,11,0,15,0,11,3,11,5,11,4,17,122,2,13,3,0,0,6,20,14,1,17,81,10,2,46,17,66,37,4,8,5,14,11,0,1,11,2,1,7,9,39,11,0,15,0,11,1,11,2,17,128,1,2,14,3,0,0,6,22,10,0,16,0,10,2,17,118,4,6,5,12,11,0,1,11,1,1,7,4,39,10,0,15,0,11,1,7,0,17,133,1,11,2,11,0,15,5,17,16,2,15,3,0,0,6,10,10,0,15,0,11,1,7,0,17,133,1,11,2,11,0,15,5,17,17,2,16,0,0,0,64,46,14,0,17,109,20,12,5,10,5,10,1,34,4,9,5,13,11,2,1,7,6,39,10,2,14,1,12,3,46,11,3,56,3,32,4,27,11,2,11,1,11,5,56,4,56,5,5,45,11,2,14,1,56,6,12,6,10,6,14,5,12,4,46,11,4,56,7,32,4,43,11,6,11,5,56,8,5,45,11,6,1,2,17,0,0,0,64,50,10,2,14,1,12,3,46,11,3,56,3,4,8,5,12,11,2,1,7,7,39,10,2,14,1,56,6,12,6,14,0,17,109,20,12,5,10,6,14,5,12,4,46,11,4,56,7,4,28,5,34,11,2,1,11,6,1,7,7,39,10,6,14,5,56,9,11,6,46,56,10,4,47,11,2,14,1,56,11,1,1,5,49,11,2,1,2,18,3,0,0,6,8,11,0,15,0,10,1,46,17,116,11,1,17,87,2,19,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,100,2,20,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,98,2,21,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,99,2,22,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,108,2,23,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,101,11,3,46,12,4,11,0,16,0,11,4,17,113,2,24,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,91,2,25,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,103,11,3,46,12,4,11,0,16,0,11,4,17,113,2,26,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,93,2,27,3,0,0,6,7,11,0,15,0,11,2,17,115,11,1,17,104,2,28,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,94,2,29,3,0,0,6,7,11,0,15,0,11,2,17,115,11,1,17,106,2,30,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,96,2,31,3,0,0,80,17,10,0,15,0,11,3,17,115,12,4,10,4,11,1,11,2,17,105,11,4,46,12,5,11,0,16,0,11,5,17,113,2,32,3,0,0,6,8,11,0,15,0,11,3,17,116,11,1,11,2,17,95,2,33,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,107,11,3,46,12,4,11,0,16,0,11,4,17,113,2,34,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,97,2,35,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,102,11,3,46,12,4,11,0,16,0,11,4,17,113,2,36,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,92,2,37,3,0,0,83,220,2,10,0,16,6,20,12,37,10,9,10,0,15,6,21,7,12,52,12,28,10,7,10,28,37,4,20,10,8,11,28,37,12,11,5,22,9,12,11,11,11,4,25,5,31,11,0,1,11,10,1,7,8,39,10,0,16,1,16,7,20,6,0,0,0,0,0,0,0,0,36,4,43,6,20,0,0,0,0,0,0,0,10,0,15,1,15,7,21,10,0,15,8,56,12,12,40,13,3,11,40,56,13,1,10,0,15,9,56,12,12,39,13,4,11,39,56,13,1,11,5,10,0,16,10,20,22,12,5,6,0,0,0,0,0,0,0,0,10,0,15,10,21,11,6,10,0,16,11,20,22,12,6,6,0,0,0,0,0,0,0,0,10,0,15,11,21,10,0,16,0,17,130,1,12,54,10,0,16,12,17,84,12,44,10,44,11,54,22,12,52,14,3,56,14,12,43,14,4,56,14,12,29,10,10,46,17,66,10,0,16,1,16,7,20,38,4,116,11,9,11,37,10,0,16,1,16,13,20,22,38,12,20,5,118,9,12,20,11,20,4,125,10,0,15,14,17,80,12,21,5,127,56,1,12,21,11,21,12,41,14,41,56,14,12,42,13,4,11,41,56,13,1,11,52,53,12,53,10,29,53,12,30,11,44,53,11,30,24,11,53,26,12,48,13,4,10,48,52,56,15,12,47,11,48,11,7,53,24,7,12,26,12,46,13,47,10,46,52,56,15,12,45,10,0,16,15,20,6,1,0,0,0,0,0,0,0,22,10,0,15,15,21,11,1,10,0,16,15,20,33,4,181,1,5,187,1,11,0,1,11,10,1,7,11,39,14,4,56,14,12,32,14,47,56,14,12,50,10,0,15,0,13,4,13,47,10,0,15,5,11,8,10,0,16,1,16,16,20,10,0,16,1,16,17,20,10,0,16,1,16,18,20,11,10,17,112,10,0,16,0,17,130,1,12,36,14,4,56,14,12,31,14,47,56,14,12,49,11,32,11,31,23,12,33,11,50,11,49,23,12,51,11,2,10,0,15,19,21,10,0,16,0,17,114,10,0,15,20,21,11,47,12,34,13,34,11,4,56,13,1,14,34,56,14,12,35,10,0,15,12,11,3,11,45,11,34,10,5,11,6,17,82,12,38,10,0,16,15,20,12,22,10,0,16,19,20,12,23,10,0,16,20,20,12,24,11,36,12,25,11,43,12,26,11,46,52,12,27,11,5,12,12,10,0,16,12,17,84,12,13,11,42,12,14,11,29,12,15,11,33,11,51,22,12,16,11,35,12,17,11,22,11,23,11,24,11,25,11,27,11,26,11,12,11,13,11,14,11,15,11,16,11,17,18,4,56,16,9,10,0,15,21,21,10,0,16,10,20,6,0,0,0,0,0,0,0,0,33,4,198,2,10,0,16,8,56,14,6,0,0,0,0,0,0,0,0,33,12,18,5,200,2,9,12,18,11,18,4,209,2,11,0,16,9,56,14,6,0,0,0,0,0,0,0,0,33,12,19,5,213,2,11,0,1,9,12,19,11,19,4,216,2,5,218,2,7,10,39,11,38,2,38,3,0,0,6,4,11,0,16,15,20,2,39,3,0,0,6,4,11,0,16,19,20,2,40,3,0,0,6,4,11,0,16,22,20,2,41,3,0,0,6,2,7,3,2,42,3,0,0,6,4,11,0,16,6,20,2,43,3,0,0,6,5,11,0,16,0,11,1,17,132,1,2,44,3,0,0,6,5,11,0,16,0,11,1,17,131,1,2,45,3,0,0,6,4,11,0,16,0,17,129,1,2,46,3,0,0,25,18,10,0,16,5,14,1,56,3,4,12,11,0,16,5,14,1,56,17,20,12,2,5,16,11,0,1,56,18,12,2,11,2,2,47,3,0,0,6,4,11,0,16,12,17,84,2,48,3,0,0,6,4,11,0,16,12,17,85,2,49,3,0,0,6,5,11,0,15,0,11,1,17,121,2,50,3,0,0,6,4,11,0,16,0,17,110,2,51,0,0,0,95,45,13,0,69,96,12,6,13,6,11,0,56,19,11,6,56,2,12,7,14,1,56,20,4,39,11,1,56,21,12,4,13,7,11,4,56,15,12,5,14,7,56,14,6,0,0,0,0,0,0,0,0,36,4,32,11,7,10,2,56,22,11,2,46,17,67,56,23,5,36,11,2,1,11,7,56,24,11,5,12,3,5,43,11,2,1,11,7,12,3,11,3,2,3,3,3,5,1,3,1,4,1,2,3,7,3,14,1,1,3,10,3,11,3,12,3,13,3,4,1,0,3,8,3,0,1,5,1,6,1,7,3,1,3,6,3,9,3,2,0,45,0,114,0],"validator":[161,28,235,11,6,0,0,0,12,1,0,33,2,33,72,3,105,197,4,4,174,5,40,5,214,5,131,4,7,217,9,247,19,8,208,29,96,6,176,30,190,1,10,238,31,156,1,12,138,33,237,27,13,247,60,60,15,179,61,13,0,137,1,1,20,1,23,1,74,1,105,2,21,2,22,2,34,2,72,2,106,2,113,2,114,2,134,1,0,103,0,139,1,0,14,4,0,0,13,4,0,0,8,3,0,0,11,3,0,1,9,7,0,3,3,7,1,0,0,4,9,7,0,5,0,12,0,6,1,4,1,0,1,8,2,7,0,9,5,2,0,11,10,2,0,12,12,7,0,13,4,7,0,13,6,12,0,13,7,12,0,14,15,2,0,0,56,0,1,0,0,54,2,3,0,0,26,4,5,0,0,16,4,5,0,0,18,6,5,0,0,88,7,8,0,0,89,7,5,0,0,92,9,10,0,0,91,11,5,0,0,96,11,5,0,0,90,4,5,0,0,95,4,5,0,0,29,12,5,0,0,83,13,5,0,0,47,14,15,0,0,49,14,16,0,0,107,14,17,0,0,50,14,18,0,0,30,14,18,0,0,42,14,19,0,0,84,14,19,0,0,52,14,18,0,0,75,14,18,0,0,80,14,18,0,0,145,1,14,18,0,0,86,14,20,0,0,85,14,20,0,0,53,14,20,0,0,146,1,14,20,0,0,62,14,21,0,0,64,14,21,0,0,65,14,21,0,0,69,14,21,0,0,67,14,22,0,0,66,14,22,0,0,63,14,22,0,0,70,14,22,0,0,73,14,23,0,0,60,14,24,0,0,112,14,24,0,0,100,14,24,0,0,111,14,24,0,0,144,1,14,24,0,0,97,4,5,0,0,76,14,24,0,0,77,14,24,0,0,38,14,24,0,0,25,14,24,0,0,79,25,26,0,0,104,14,27,0,0,43,28,15,0,0,45,29,15,1,0,0,44,30,15,1,0,0,58,13,5,0,0,125,31,5,0,0,123,31,5,0,0,124,31,5,0,0,133,1,31,5,0,0,126,31,5,0,0,116,31,5,0,0,128,1,31,5,0,0,118,31,5,0,0,129,1,31,5,0,0,119,31,5,0,0,131,1,31,5,0,0,121,31,5,0,0,130,1,32,5,0,0,120,32,5,0,0,127,31,5,0,0,117,31,5,0,0,132,1,31,5,0,0,122,31,5,0,0,31,6,5,0,0,135,1,16,5,0,0,136,1,33,5,0,0,40,14,34,0,0,55,35,3,0,1,105,33,41,0,2,110,65,33,1,0,3,24,67,65,1,0,3,36,70,53,1,0,3,46,67,15,1,0,3,48,67,15,1,0,3,71,5,37,1,0,3,98,53,37,1,0,4,37,41,38,0,5,54,43,44,0,6,142,1,48,24,1,0,7,32,53,5,1,3,8,41,65,27,1,8,10,87,54,5,1,12,11,33,49,24,0,11,94,49,17,0,12,57,33,42,0,13,17,45,5,0,13,27,45,5,0,13,28,61,5,0,13,47,34,15,0,13,54,43,64,0,13,76,34,24,0,13,77,34,24,0,13,79,63,26,0,13,82,51,5,0,13,83,62,5,0,13,88,50,8,0,13,92,57,10,0,13,99,56,24,0,13,101,56,24,0,13,108,34,24,0,14,58,69,27,0,14,143,1,59,60,0,83,33,83,38,87,47,88,52,90,8,88,58,89,64,52,38,52,33,51,38,51,33,81,53,79,53,84,38,84,33,82,38,80,38,82,33,80,33,78,1,14,5,10,2,10,2,10,2,10,2,8,6,8,6,8,12,8,12,8,6,8,6,8,6,8,6,8,7,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,11,1,8,1,2,7,8,1,3,0,1,7,8,1,4,7,8,1,11,8,1,8,10,5,7,8,11,1,8,14,3,7,8,1,8,14,7,8,11,1,11,8,1,8,10,3,7,8,1,8,16,3,2,7,8,1,11,8,1,8,10,2,7,8,1,7,8,11,1,6,8,1,1,1,1,6,8,0,1,5,1,6,8,6,1,6,8,12,1,6,10,2,1,6,11,5,1,8,6,1,6,11,5,1,10,2,1,6,8,9,1,3,2,6,8,1,3,1,8,13,1,8,9,2,6,8,1,6,8,1,2,6,11,5,1,9,0,6,9,0,2,6,11,5,1,9,0,6,11,5,1,9,0,2,7,8,1,10,2,3,7,8,1,10,2,10,2,1,10,2,1,6,8,15,4,8,0,3,3,7,8,11,22,5,8,6,8,6,8,6,8,6,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,8,6,11,5,1,8,6,10,2,11,5,1,8,6,11,5,1,8,6,8,7,10,2,10,2,10,2,8,6,8,6,8,12,8,12,1,11,5,1,9,0,1,8,6,8,1,1,1,1,1,1,1,8,0,1,2,1,8,4,1,8,12,1,7,8,11,1,8,7,2,7,8,15,3,3,3,3,8,14,1,8,10,1,6,11,8,1,9,0,1,6,8,11,4,7,8,15,11,8,1,8,10,3,7,8,11,1,7,8,15,1,8,2,1,9,0,2,9,0,5,5,3,3,3,3,11,8,1,8,10,1,6,8,14,3,7,8,15,8,14,7,8,11,1,8,3,1,6,8,16,1,6,5,2,7,8,15,11,8,1,8,10,2,7,8,15,7,8,11,2,6,8,15,3,1,8,15,1,6,9,0,29,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,6,11,5,1,9,0,2,1,1,2,5,7,8,11,1,7,11,5,1,9,0,3,8,9,8,15,5,3,66,97,103,7,66,97,108,97,110,99,101,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,19,83,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,21,85,110,115,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,3,85,114,108,9,86,97,108,105,100,97,116,111,114,17,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,8,97,99,116,105,118,97,116,101,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,6,97,109,111,117,110,116,5,97,115,99,105,105,3,98,97,103,7,98,97,108,97,110,99,101,3,98,99,115,6,98,111,114,114,111,119,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,10,100,101,97,99,116,105,118,97,116,101,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,11,100,101,115,99,114,105,112,116,105,111,110,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,5,101,112,111,99,104,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,10,102,114,111,109,95,97,115,99,105,105,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,20,103,101,116,95,115,116,97,107,105,110,103,95,112,111,111,108,95,114,101,102,2,105,100,9,105,109,97,103,101,95,117,114,108,12,105,115,95,100,117,112,108,105,99,97,116,101,13,105,115,95,101,113,117,97,108,95,115,111,109,101,23,105,115,95,101,113,117,97,108,95,115,111,109,101,95,97,110,100,95,118,97,108,117,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,8,109,101,116,97,100,97,116,97,4,110,97,109,101,11,110,101,116,95,97,100,100,114,101,115,115,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,20,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,102,114,111,109,95,109,101,116,97,100,97,116,97,12,110,101,119,95,109,101,116,97,100,97,116,97,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,20,110,101,120,116,95,101,112,111,99,104,95,103,97,115,95,112,114,105,99,101,22,110,101,120,116,95,101,112,111,99,104,95,110,101,116,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,22,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,32,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,16,110,101,120,116,95,101,112,111,99,104,95,115,116,97,107,101,25,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,7,112,111,111,108,95,105,100,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,16,112,114,105,110,99,105,112,97,108,95,97,109,111,117,110,116,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,21,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,13,114,101,119,97,114,100,95,97,109,111,117,110,116,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,111,109,101,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,12,115,116,97,107,101,95,97,109,111,117,110,116,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,14,115,116,97,107,101,114,95,97,100,100,114,101,115,115,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,6,115,116,114,105,110,103,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,11,115,117,105,95,98,97,108,97,110,99,101,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,111,95,98,121,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,15,117,110,115,116,97,107,105,110,103,95,101,112,111,99,104,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,3,117,114,108,17,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,21,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,95,98,99,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,12,118,111,116,105,110,103,95,112,111,119,101,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,19,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,100,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,3,8,102,0,0,0,0,0,0,0,3,8,208,7,0,0,0,0,0,0,3,8,0,1,0,0,0,0,0,0,3,8,160,134,1,0,0,0,0,0,0,2,22,107,5,86,10,2,53,10,2,146,1,10,2,85,10,2,50,8,6,30,8,6,42,8,12,84,8,12,51,8,6,75,8,6,80,8,6,145,1,8,6,67,11,5,1,10,2,66,11,5,1,10,2,63,11,5,1,10,2,70,11,5,1,10,2,61,11,5,1,8,6,64,11,5,1,8,6,65,11,5,1,8,6,69,11,5,1,8,6,35,8,7,1,2,10,49,8,0,144,1,3,73,8,9,38,3,103,8,15,25,3,68,3,60,3,59,3,35,8,7,2,2,5,78,8,9,138,1,5,102,5,33,3,19,3,3,2,7,78,8,9,138,1,5,102,5,99,3,115,3,81,3,93,3,0,3,0,0,36,68,11,0,12,14,11,1,12,25,11,2,12,29,11,3,12,30,11,4,12,31,11,5,12,32,11,6,12,33,11,7,12,34,11,8,12,35,11,9,12,15,11,10,12,16,11,11,12,17,11,12,12,18,56,0,12,19,56,0,12,20,56,0,12,21,56,0,12,22,56,1,12,23,56,1,12,24,56,1,12,26,56,1,12,27,11,13,12,28,11,14,11,25,11,29,11,30,11,31,11,32,11,33,11,34,11,35,11,15,11,16,11,17,11,18,11,19,11,22,11,20,11,21,11,23,11,24,11,26,11,27,11,28,18,0,2,1,3,0,0,39,137,1,14,9,65,40,7,17,37,4,11,14,10,65,40,7,17,37,12,16,5,13,9,12,16,11,16,4,21,14,11,65,40,7,17,37,12,17,5,23,9,12,17,11,17,4,31,14,12,65,40,7,17,37,12,18,5,33,9,12,18,11,18,4,41,14,5,65,40,7,17,37,12,19,5,43,9,12,19,11,19,4,51,14,6,65,40,7,17,37,12,20,5,53,9,12,20,11,20,4,61,14,7,65,40,7,17,37,12,21,5,63,9,12,21,11,21,4,71,14,8,65,40,7,17,37,12,22,5,73,9,12,22,11,22,4,76,5,80,11,15,1,7,9,39,10,14,7,16,37,4,85,5,89,11,15,1,7,8,39,10,13,7,18,35,4,94,5,98,11,15,1,7,15,39,11,0,11,1,11,2,11,3,11,4,11,5,17,77,17,85,11,6,17,77,17,85,11,7,17,93,11,8,17,93,11,9,17,77,17,85,11,10,17,77,17,85,11,11,17,77,17,85,11,12,17,77,17,85,10,15,17,86,17,0,12,23,14,23,17,73,11,23,11,13,11,14,11,15,17,76,2,2,3,0,0,5,5,11,0,15,0,11,1,17,95,2,3,3,0,0,5,5,11,0,15,0,11,1,17,94,2,4,3,0,0,5,13,10,0,16,1,20,10,0,15,2,21,10,0,16,3,20,11,0,15,4,21,2,5,3,0,0,46,58,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,8,5,14,11,0,1,11,3,1,7,11,39,10,3,46,17,91,6,1,0,0,0,0,0,0,0,22,12,5,10,0,15,0,11,1,11,5,10,3,17,104,12,6,10,0,16,0,17,97,4,34,10,0,15,0,17,102,10,0,16,5,20,10,4,22,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,11,2,11,3,46,17,91,11,4,18,2,56,3,11,6,2,6,3,0,0,24,47,10,3,46,17,91,6,0,0,0,0,0,0,0,0,33,4,7,5,13,11,0,1,11,3,1,7,12,39,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,21,5,27,11,0,1,11,3,1,7,11,39,10,0,15,0,11,1,6,0,0,0,0,0,0,0,0,11,3,17,104,11,2,56,4,10,0,15,0,17,102,10,0,16,5,20,11,4,22,11,0,15,5,21,2,7,3,0,0,55,47,14,1,17,107,12,3,14,1,17,106,12,5,10,0,15,0,11,1,10,2,17,105,12,7,14,7,56,2,12,6,10,6,10,3,23,12,4,10,0,16,5,20,11,6,23,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,10,2,46,17,92,11,5,11,2,46,17,91,11,3,11,4,18,3,56,5,11,7,2,8,3,0,0,5,28,10,2,7,18,35,4,5,5,9,11,0,1,7,15,39,14,1,17,110,20,10,0,16,6,16,7,20,33,4,19,5,23,11,0,1,7,14,39,11,2,11,0,15,1,21,2,9,3,0,0,5,41,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,2,7,18,35,4,14,5,18,11,0,1,7,15,39,14,1,17,110,20,10,0,16,6,16,7,20,33,4,28,5,32,11,0,1,7,14,39,10,2,10,0,15,1,21,11,2,11,0,15,2,21,2,10,3,0,0,5,14,10,1,7,16,37,4,5,5,9,11,0,1,7,8,39,11,1,11,0,15,3,21,2,11,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,1,7,16,37,4,14,5,18,11,0,1,7,8,39,11,1,11,0,15,4,21,2,12,3,0,0,5,14,10,0,16,5,20,14,1,56,2,22,10,0,15,5,21,11,0,15,0,11,1,17,96,2,13,3,0,0,5,16,10,0,15,0,11,1,17,103,10,0,46,17,40,11,0,16,5,20,33,4,13,5,15,7,11,39,2,14,1,0,0,5,4,11,0,16,0,17,97,2,15,1,0,0,5,3,11,0,16,6,2,16,1,0,0,5,5,11,0,16,6,16,7,20,2,17,1,0,0,5,4,11,0,16,6,16,8,2,18,1,0,0,5,4,11,0,16,6,16,9,2,19,1,0,0,5,4,11,0,16,6,16,10,2,20,1,0,0,5,4,11,0,16,6,16,11,2,21,1,0,0,5,4,11,0,16,6,16,12,2,22,1,0,0,5,4,11,0,16,6,16,13,2,23,1,0,0,5,4,11,0,16,6,16,14,2,24,1,0,0,5,4,11,0,16,6,16,15,2,25,1,0,0,5,4,11,0,16,6,16,16,2,26,1,0,0,5,4,11,0,16,6,16,17,2,27,1,0,0,5,4,11,0,16,6,16,18,2,28,1,0,0,5,4,11,0,16,6,16,19,2,29,1,0,0,5,4,11,0,16,6,16,20,2,30,1,0,0,5,4,11,0,16,6,16,21,2,31,1,0,0,5,4,11,0,16,6,16,22,2,32,1,0,0,5,4,11,0,16,6,16,23,2,33,1,0,0,5,4,11,0,16,6,16,24,2,34,1,0,0,5,4,11,0,16,6,16,25,2,35,1,0,0,5,4,11,0,16,6,16,26,2,36,1,0,0,5,4,11,0,16,6,16,27,2,37,1,0,0,5,3,11,0,16,28,2,38,1,0,0,5,4,11,0,16,1,20,2,39,1,0,0,5,5,40,11,0,16,0,17,108,2,40,1,0,0,5,4,11,0,16,0,17,108,2,41,1,0,0,5,3,11,0,17,40,2,42,1,0,0,5,4,11,0,16,29,20,2,43,3,0,0,5,5,11,1,11,0,15,29,21,2,44,1,0,0,5,4,11,0,16,0,17,99,2,45,1,0,0,5,4,11,0,16,0,17,100,2,46,1,0,0,5,4,11,0,16,2,20,2,47,1,0,0,5,4,11,0,16,4,20,2,48,1,0,0,5,5,11,0,16,0,11,1,17,101,2,49,1,0,0,5,4,11,0,16,0,56,6,2,50,1,0,0,66,151,3,10,0,16,6,16,7,20,10,1,16,6,16,7,20,33,4,13,8,12,2,5,23,10,0,16,6,16,8,20,10,1,16,6,16,8,20,33,12,2,11,2,4,28,8,12,13,5,38,10,0,16,6,16,12,20,10,1,16,6,16,12,20,33,12,13,11,13,4,43,8,12,24,5,53,10,0,16,6,16,13,20,10,1,16,6,16,13,20,33,12,24,11,24,4,58,8,12,25,5,68,10,0,16,6,16,16,20,10,1,16,6,16,16,20,33,12,25,11,25,4,73,8,12,26,5,83,10,0,16,6,16,18,20,10,1,16,6,16,18,20,33,12,26,11,26,4,88,8,12,27,5,98,10,0,16,6,16,18,20,10,1,16,6,16,19,20,33,12,27,11,27,4,103,8,12,28,5,113,10,0,16,6,16,19,20,10,1,16,6,16,19,20,33,12,28,11,28,4,118,8,12,29,5,128,1,10,0,16,6,16,19,20,10,1,16,6,16,18,20,33,12,29,11,29,4,133,1,8,12,30,5,141,1,10,0,16,6,16,20,10,1,16,6,16,20,56,7,12,30,11,30,4,146,1,8,12,3,5,154,1,10,0,16,6,16,21,10,1,16,6,16,21,56,7,12,3,11,3,4,159,1,8,12,4,5,167,1,10,0,16,6,16,24,10,1,16,6,16,24,56,8,12,4,11,4,4,172,1,8,12,5,5,180,1,10,0,16,6,16,26,10,1,16,6,16,26,56,8,12,5,11,5,4,185,1,8,12,6,5,193,1,10,0,16,6,16,26,10,1,16,6,16,27,56,8,12,6,11,6,4,198,1,8,12,7,5,206,1,10,0,16,6,16,27,10,1,16,6,16,27,56,8,12,7,11,7,4,211,1,8,12,8,5,219,1,10,0,16,6,16,27,10,1,16,6,16,26,56,8,12,8,11,8,4,224,1,8,12,9,5,232,1,10,0,16,6,16,20,10,1,16,6,16,12,56,9,12,9,11,9,4,237,1,8,12,10,5,245,1,10,0,16,6,16,21,10,1,16,6,16,13,56,9,12,10,11,10,4,250,1,8,12,11,5,130,2,10,0,16,6,16,24,10,1,16,6,16,16,56,10,12,11,11,11,4,135,2,8,12,12,5,143,2,10,0,16,6,16,26,10,1,16,6,16,18,56,10,12,12,11,12,4,148,2,8,12,14,5,156,2,10,0,16,6,16,26,10,1,16,6,16,19,56,10,12,14,11,14,4,161,2,8,12,15,5,169,2,10,0,16,6,16,27,10,1,16,6,16,19,56,10,12,15,11,15,4,174,2,8,12,16,5,182,2,10,0,16,6,16,27,10,1,16,6,16,18,56,10,12,16,11,16,4,187,2,8,12,17,5,195,2,10,1,16,6,16,20,10,0,16,6,16,12,56,9,12,17,11,17,4,200,2,8,12,18,5,208,2,10,1,16,6,16,21,10,0,16,6,16,13,56,9,12,18,11,18,4,213,2,8,12,19,5,221,2,10,1,16,6,16,24,10,0,16,6,16,16,56,10,12,19,11,19,4,226,2,8,12,20,5,234,2,10,1,16,6,16,26,10,0,16,6,16,18,56,10,12,20,11,20,4,239,2,8,12,21,5,247,2,10,1,16,6,16,26,10,0,16,6,16,19,56,10,12,21,11,21,4,252,2,8,12,22,5,132,3,10,1,16,6,16,27,10,0,16,6,16,19,56,10,12,22,11,22,4,141,3,11,0,1,11,1,1,8,12,23,5,149,3,11,1,16,6,16,27,11,0,16,6,16,18,56,10,12,23,11,23,2,51,0,0,0,15,17,10,0,56,11,4,10,11,1,1,11,0,1,9,12,2,5,15,11,0,56,12,11,1,33,12,2,11,2,2,52,0,0,0,68,26,10,0,56,11,4,6,8,12,2,5,9,10,1,56,11,12,2,11,2,4,18,11,1,1,11,0,1,9,12,3,5,24,11,0,56,12,11,1,56,12,33,12,3,11,3,2,53,3,0,0,17,25,10,1,46,17,92,12,2,10,2,10,0,16,6,16,7,20,33,4,12,5,18,11,0,1,11,1,1,7,13,39,11,2,11,1,17,109,11,0,15,28,21,2,54,3,0,0,5,18,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,11,0,15,6,15,8,21,2,55,3,0,0,5,18,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,11,0,15,6,15,9,21,2,56,3,0,0,5,17,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,93,11,0,15,6,15,10,21,2,57,3,0,0,5,17,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,93,11,0,15,6,15,11,21,2,58,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,20,21,11,0,16,6,17,73,2,59,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,12,21,11,0,16,6,17,73,2,60,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,21,21,11,0,16,6,17,73,2,61,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,13,21,11,0,16,6,17,73,2,62,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,22,21,11,0,16,6,17,73,2,63,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,14,21,11,0,16,6,17,73,2,64,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,23,21,11,0,16,6,17,73,2,65,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,15,21,11,0,16,6,17,73,2,66,3,0,0,5,16,11,1,56,14,10,0,15,6,15,24,21,11,2,56,14,10,0,15,6,15,25,21,11,0,16,6,17,73,2,67,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,16,21,11,2,10,0,15,6,15,17,21,11,0,16,6,17,73,2,68,3,0,0,5,10,11,1,56,14,10,0,15,6,15,26,21,11,0,16,6,17,73,2,69,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,18,21,11,0,16,6,17,73,2,70,3,0,0,5,10,11,1,56,14,10,0,15,6,15,27,21,11,0,16,6,17,73,2,71,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,19,21,11,0,16,6,17,73,2,72,3,0,0,5,143,1,10,0,46,17,29,56,15,4,18,10,0,15,6,15,20,56,16,10,0,15,6,15,12,21,56,1,10,0,15,6,15,20,21,10,0,46,17,30,56,15,4,36,10,0,15,6,15,21,56,16,10,0,15,6,15,13,21,56,1,10,0,15,6,15,21,21,10,0,46,17,31,56,15,4,54,10,0,15,6,15,22,56,16,10,0,15,6,15,14,21,56,1,10,0,15,6,15,22,21,10,0,46,17,32,56,15,4,72,10,0,15,6,15,23,56,16,10,0,15,6,15,15,21,56,1,10,0,15,6,15,23,21,10,0,46,17,33,56,17,4,103,10,0,15,6,15,24,56,18,10,0,15,6,15,16,21,56,0,10,0,15,6,15,24,21,10,0,15,6,15,25,56,18,10,0,15,6,15,17,21,56,0,10,0,15,6,15,25,21,10,0,46,17,35,56,17,4,121,10,0,15,6,15,26,56,18,10,0,15,6,15,18,21,56,0,10,0,15,6,15,26,21,10,0,46,17,36,56,17,4,140,1,10,0,15,6,15,27,56,18,10,0,15,6,15,19,21,56,0,11,0,15,6,15,27,21,5,142,1,11,0,1,2,73,1,0,0,5,4,11,0,56,19,17,74,2,74,1,2,0,75,3,0,0,5,3,11,0,16,0,2,76,0,0,0,71,24,14,0,16,7,20,12,6,10,3,17,98,12,5,11,6,10,3,17,109,12,4,11,0,6,0,0,0,0,0,0,0,0,11,4,10,1,11,5,10,2,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,17,86,18,1,2,1,4,1,7,1,3,1,8,1,5,1,6,1,0,0,0,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,1,0,4,0,2,0,3,0,17,0,18,0,19,0,20,0,13,0,14,0,15,0,16,1,2,1,1,0,39,0,109,0,140,1,0,141,1,0,144,1,0],"validator_cap":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,20,3,28,42,4,70,4,5,74,54,7,128,1,226,2,8,226,3,64,6,162,4,34,10,196,4,13,12,209,4,112,13,193,5,4,15,197,5,6,0,18,1,10,1,14,1,15,0,3,12,0,0,4,2,0,1,0,7,0,1,2,4,0,3,1,2,0,0,16,0,1,0,0,20,2,1,0,0,9,3,4,0,0,8,0,5,0,1,6,13,4,1,8,1,7,10,11,0,2,11,14,6,1,12,3,12,8,9,0,4,12,6,12,1,6,8,0,1,6,5,1,6,8,1,2,5,7,8,4,1,8,2,1,8,1,0,4,1,8,0,8,2,5,1,6,8,4,1,5,1,7,8,4,1,8,3,1,8,0,1,6,9,0,2,9,0,5,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,28,97,117,116,104,111,114,105,122,101,114,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,6,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,3,5,5,1,2,1,5,5,0,3,0,0,6,3,11,0,16,0,2,1,3,0,0,6,3,11,0,16,1,2,2,3,0,0,7,35,10,1,46,17,7,12,5,10,5,7,0,33,4,11,8,12,2,5,15,11,5,10,0,33,12,2,11,2,4,18,5,22,11,1,1,6,0,0,0,0,0,0,0,0,39,11,1,17,5,10,0,18,0,12,3,14,3,56,0,12,4,11,3,11,0,56,1,11,4,2,3,3,0,0,6,5,11,0,16,0,20,18,1,2,0,1,1,0,0,13,0,17,0,19,0],"validator_set":[161,28,235,11,6,0,0,0,12,1,0,54,2,54,116,3,170,1,173,6,4,215,7,137,1,5,224,8,136,10,7,232,18,175,24,8,151,43,96,6,247,43,195,1,10,186,45,141,1,12,199,46,159,36,13,230,82,16,15,246,82,5,0,166,1,1,107,1,174,1,2,32,2,33,2,59,2,105,2,118,2,147,1,2,151,1,2,152,1,2,158,1,2,159,1,2,172,1,2,173,1,0,143,1,0,162,1,0,165,1,0,170,1,0,177,1,0,20,4,0,0,15,3,0,0,16,3,0,0,17,3,0,0,18,3,0,1,4,7,1,0,0,3,0,12,0,4,1,4,1,0,1,6,3,7,0,7,2,6,1,2,0,7,6,6,1,2,0,8,7,2,0,9,10,12,2,7,1,4,1,10,11,4,1,4,1,12,12,2,0,13,22,7,2,1,0,0,0,14,23,7,1,3,0,15,5,7,0,15,8,12,0,15,9,12,0,16,14,4,0,17,13,12,0,17,19,2,0,18,21,4,0,0,100,0,1,0,0,130,1,2,3,0,0,132,1,4,3,0,0,129,1,5,3,0,0,30,6,3,0,0,131,1,4,3,0,0,128,1,7,8,0,0,134,1,9,10,0,0,133,1,11,3,0,0,29,12,3,0,0,161,1,13,3,0,0,54,14,3,0,0,49,15,16,0,0,155,1,15,16,0,0,169,1,17,16,0,0,167,1,17,16,0,0,168,1,17,18,0,0,145,1,15,19,0,0,110,20,21,0,0,103,15,16,0,0,85,17,22,0,0,88,6,22,0,0,87,23,22,0,0,45,23,16,0,0,89,6,22,0,0,44,24,16,0,0,71,25,26,0,0,63,27,28,0,0,64,29,28,0,0,75,30,31,0,0,76,32,26,0,0,68,33,26,0,0,79,34,26,0,0,77,35,26,0,0,78,35,26,0,0,80,27,36,0,0,69,37,36,0,0,70,17,36,0,0,73,17,36,0,0,176,1,38,39,0,0,119,40,3,0,0,122,41,3,0,0,37,42,3,0,0,121,43,3,0,0,139,1,44,3,0,0,120,45,3,0,0,36,46,16,0,0,28,47,3,0,0,40,48,49,0,0,41,50,51,0,0,42,52,53,0,0,39,54,53,0,0,53,55,3,0,0,56,56,3,0,0,150,1,30,16,0,0,26,15,46,0,0,94,17,22,0,0,91,57,22,0,0,25,15,51,0,1,51,118,85,1,0,1,62,84,85,1,0,1,93,83,22,1,0,1,104,3,118,1,0,1,138,1,85,118,1,0,2,43,86,22,1,0,2,90,132,1,22,1,0,2,127,102,85,1,0,3,100,60,70,0,4,52,155,1,3,1,0,4,96,156,1,16,1,0,4,140,1,154,1,155,1,1,0,4,171,1,88,16,1,0,5,55,85,3,1,3,6,81,117,18,1,8,7,100,108,109,1,2,7,101,106,107,1,2,7,117,110,106,1,2,9,27,64,3,2,7,4,9,34,72,92,2,7,4,9,35,77,93,2,7,4,9,43,72,22,2,7,4,9,100,60,61,2,7,4,9,127,77,78,2,7,4,10,34,116,117,1,4,10,35,121,122,1,4,10,57,60,65,1,4,10,90,113,22,1,4,10,98,113,16,1,4,10,116,142,1,85,1,4,10,124,81,3,1,4,11,123,157,1,3,1,12,12,58,76,16,0,12,135,1,76,63,0,13,43,98,22,2,1,0,13,57,3,69,2,1,0,13,67,98,92,2,1,0,13,72,99,93,2,1,0,13,83,101,3,2,1,0,13,90,137,1,22,2,1,0,13,97,137,1,138,1,2,1,0,13,115,149,1,100,2,1,0,13,127,99,100,2,1,0,13,137,1,137,1,16,2,1,0,14,43,139,1,22,1,3,14,84,150,1,138,1,1,3,14,90,141,1,22,1,3,14,127,140,1,3,1,3,15,60,112,21,0,15,111,91,18,0,16,24,79,3,0,16,28,26,3,0,16,38,36,16,0,16,47,79,3,0,16,48,158,1,3,0,16,54,26,3,0,16,65,36,16,0,16,74,36,112,0,16,86,115,22,0,16,92,36,22,0,16,106,36,130,1,0,16,114,160,1,161,1,0,16,120,145,1,3,0,16,128,1,89,8,0,16,133,1,79,3,0,16,134,1,95,10,0,16,142,1,36,16,0,16,144,1,36,18,0,16,148,1,36,63,0,16,156,1,36,16,0,16,177,1,36,16,0,17,102,128,1,39,0,17,160,1,128,1,124,0,17,175,1,123,124,0,18,46,73,74,0,18,50,74,62,0,18,99,94,26,0,19,125,3,16,0,19,136,1,47,3,0,19,157,1,3,16,0,81,59,77,59,85,62,81,66,81,67,94,68,80,67,77,67,82,67,82,59,77,66,89,62,61,16,60,16,64,16,71,87,80,59,78,59,80,66,79,66,93,68,101,68,96,68,97,68,66,62,75,16,74,16,76,16,87,62,83,62,79,67,63,16,62,16,59,16,84,62,73,129,1,65,16,72,134,1,93,136,1,101,136,1,99,136,1,96,136,1,103,63,106,63,105,63,86,62,88,62,72,143,1,94,103,97,103,98,136,1,100,136,1,104,63,102,103,93,103,95,103,70,87,69,87,90,8,68,87,95,136,1,64,63,72,162,1,2,10,8,20,7,8,14,1,8,0,3,7,8,0,8,20,7,8,14,0,2,7,8,0,7,8,14,3,7,8,0,3,7,8,14,2,6,8,0,6,8,20,4,7,8,0,5,11,7,1,8,11,7,8,14,1,8,18,3,7,8,0,8,18,7,8,14,1,11,7,1,8,11,3,7,8,0,3,6,8,14,9,7,8,0,7,11,7,1,8,11,7,11,7,1,8,11,7,11,15,2,5,11,16,1,5,3,3,3,3,7,8,14,6,7,8,0,3,3,3,7,11,15,2,5,11,16,1,5,7,8,14,1,7,8,0,1,6,8,0,1,3,2,6,8,0,5,1,8,8,1,6,11,12,2,8,8,5,2,7,8,0,6,8,8,1,6,11,12,2,3,8,17,1,1,2,6,10,8,20,6,8,20,2,6,11,13,1,8,20,6,8,20,2,7,8,0,5,1,7,8,20,2,6,10,8,20,5,1,11,5,1,3,2,6,11,13,1,8,20,5,2,6,10,8,20,6,10,5,1,10,3,2,7,10,8,20,5,3,7,8,0,5,1,3,7,8,0,6,8,22,1,2,7,8,0,6,8,14,1,6,8,20,3,7,8,0,5,2,3,7,8,0,6,8,21,2,1,8,22,3,7,8,0,7,11,15,2,5,11,16,1,5,7,8,14,5,7,8,0,8,20,7,11,15,2,5,11,16,1,5,1,7,8,14,2,7,11,15,2,5,11,16,1,5,5,2,7,8,0,3,1,7,10,3,2,7,10,8,20,7,8,14,1,6,10,8,20,1,7,10,8,20,4,10,3,3,6,10,3,6,10,3,4,3,11,15,2,3,3,3,11,15,2,3,3,2,6,8,0,11,15,2,5,11,16,1,5,1,10,5,4,6,10,8,20,3,3,3,2,10,3,10,3,9,6,10,8,20,3,3,10,3,10,3,3,11,15,2,3,3,3,11,15,2,3,3,6,7,10,8,20,6,10,3,6,10,3,7,11,7,1,8,11,7,11,7,1,8,11,7,8,14,6,3,6,10,8,20,6,10,3,6,10,3,6,11,15,2,5,11,16,1,5,6,10,5,2,6,8,0,8,8,6,3,3,11,12,2,8,8,5,3,6,8,20,8,0,2,8,8,5,1,7,8,14,1,11,12,2,9,0,9,1,1,8,20,1,5,3,7,11,12,2,9,0,9,1,9,0,9,1,1,11,13,1,9,0,2,8,8,8,23,2,5,8,23,2,5,3,1,11,15,2,9,0,9,1,1,8,6,4,6,8,20,6,8,20,1,5,2,6,11,12,2,9,0,9,1,9,0,2,8,20,7,8,14,1,8,23,3,8,8,8,20,5,1,6,8,14,2,7,11,12,2,9,0,9,1,9,0,1,9,1,2,7,8,20,3,5,6,8,20,6,8,20,1,8,20,5,2,7,11,13,1,9,0,9,0,3,5,3,11,5,1,3,1,6,11,5,1,9,0,1,7,11,5,1,9,0,1,9,0,2,6,10,9,0,6,9,0,1,8,11,1,6,11,7,1,9,0,4,7,8,20,11,7,1,8,11,5,7,8,14,3,7,8,20,8,8,5,1,6,8,18,1,6,9,1,1,7,9,1,1,7,8,23,3,7,8,20,8,18,7,8,14,14,11,15,2,5,11,16,1,5,6,10,5,10,3,10,3,11,15,2,3,3,11,15,2,3,3,3,10,5,3,3,3,3,10,3,10,3,8,3,3,7,3,3,8,20,8,20,5,6,8,20,2,6,11,15,2,9,0,9,1,6,9,0,2,7,11,15,2,9,0,9,1,6,9,0,2,9,0,9,1,3,7,11,15,2,9,0,9,1,9,0,9,1,2,7,10,9,0,3,2,3,3,10,10,11,9,1,3,3,3,11,10,1,3,3,3,3,6,8,20,3,6,10,8,20,1,11,9,1,3,2,3,9,0,1,11,9,1,9,0,1,10,11,9,1,9,0,1,11,10,1,9,0,1,7,11,10,1,9,0,2,6,8,20,5,1,6,8,19,1,6,11,13,1,9,0,3,3,3,3,2,6,8,20,6,8,20,2,6,11,13,1,9,0,3,1,6,9,0,1,11,5,1,9,0,5,5,3,11,5,1,3,3,10,3,4,3,3,11,5,1,3,11,5,1,3,2,7,11,13,1,9,0,3,1,7,9,0,1,6,8,22,1,6,5,2,3,11,5,1,3,6,1,1,3,3,11,5,1,3,11,5,1,3,5,5,6,8,20,8,8,5,6,8,20,1,6,8,21,1,8,21,1,6,8,8,2,3,8,20,1,6,10,9,0,3,3,5,8,8,1,8,4,7,6,5,6,5,3,3,6,5,10,5,7,11,16,1,5,2,5,11,16,1,5,1,6,11,15,2,9,0,9,1,1,10,9,0,2,6,11,16,1,9,0,6,9,0,2,7,11,16,1,9,0,6,9,0,1,6,11,16,1,9,0,1,7,11,13,1,9,0,1,8,3,6,3,3,3,3,3,3,2,7,8,20,7,8,14,4,3,3,3,6,8,20,7,11,15,2,3,3,11,15,2,3,3,4,4,3,3,3,5,10,5,6,10,8,20,11,16,1,5,10,5,5,1,7,11,15,2,9,0,9,1,1,11,16,1,9,0,6,3,3,4,10,3,10,3,3,17,3,3,3,10,3,3,10,3,3,4,3,3,3,3,3,3,3,3,4,8,3,3,11,7,1,8,11,3,7,8,20,5,4,11,7,1,8,11,2,7,11,7,1,9,0,3,1,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,2,9,0,5,2,7,8,20,11,7,1,8,11,8,10,5,3,3,3,3,10,5,6,8,20,5,2,6,8,20,3,1,8,17,1,8,2,5,3,3,10,5,5,6,10,8,20,3,66,97,103,7,66,97,108,97,110,99,101,5,69,110,116,114,121,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,13,80,114,105,111,114,105,116,121,81,117,101,117,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,23,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,25,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,86,50,18,86,97,108,105,100,97,116,111,114,74,111,105,110,69,118,101,110,116,19,86,97,108,105,100,97,116,111,114,76,101,97,118,101,69,118,101,110,116,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,6,86,101,99,77,97,112,6,86,101,99,83,101,116,8,97,99,116,105,118,97,116,101,26,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,101,115,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,3,97,100,100,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,18,97,116,95,114,105,115,107,95,118,97,108,105,100,97,116,111,114,115,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,22,99,97,108,99,117,108,97,116,101,95,116,111,116,97,108,95,115,116,97,107,101,115,38,99,108,101,97,110,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,95,108,101,97,118,105,110,103,95,118,97,108,105,100,97,116,111,114,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,36,99,111,109,112,117,116,101,95,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,26,99,111,109,112,117,116,101,95,114,101,119,97,114,100,95,97,100,106,117,115,116,109,101,110,116,115,26,99,111,109,112,117,116,101,95,115,108,97,115,104,101,100,95,118,97,108,105,100,97,116,111,114,115,38,99,111,109,112,117,116,101,95,117,110,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,8,99,111,110,116,97,105,110,115,25,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,116,97,98,108,101,118,101,99,20,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,118,101,99,9,99,114,101,97,116,101,95,118,49,10,100,101,97,99,116,105,118,97,116,101,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,17,100,105,115,116,114,105,98,117,116,101,95,114,101,119,97,114,100,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,27,101,109,105,116,95,118,97,108,105,100,97,116,111,114,95,101,112,111,99,104,95,101,118,101,110,116,115,5,101,109,112,116,121,5,101,112,111,99,104,5,101,118,101,110,116,14,101,120,99,104,97,110,103,101,95,114,97,116,101,115,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,14,102,105,110,100,95,118,97,108,105,100,97,116,111,114,29,102,105,110,100,95,118,97,108,105,100,97,116,111,114,95,102,114,111,109,95,116,97,98,108,101,95,118,101,99,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,3,103,101,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,24,103,101,116,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,37,103,101,116,95,99,97,110,100,105,100,97,116,101,95,111,114,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,7,103,101,116,95,109,117,116,25,103,101,116,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,95,114,101,102,20,103,101,116,95,115,116,97,107,105,110,103,95,112,111,111,108,95,114,101,102,21,103,101,116,95,118,97,108,105,100,97,116,111,114,95,105,110,100,105,99,101,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,114,101,102,2,105,100,19,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,12,105,115,95,100,117,112,108,105,99,97,116,101,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,34,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,35,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,21,105,115,95,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,22,105,115,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,12,105,115,95,118,111,108,117,110,116,97,114,121,4,106,111,105,110,4,107,101,121,115,6,108,101,110,103,116,104,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,25,112,101,110,100,105,110,103,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,16,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,19,112,111,111,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,115,7,112,111,111,108,95,105,100,19,112,111,111,108,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,24,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,3,112,111,112,8,112,111,112,95,98,97,99,107,7,112,111,112,95,109,97,120,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,24,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,26,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,115,27,112,114,111,99,101,115,115,95,118,97,108,105,100,97,116,111,114,95,100,101,112,97,114,116,117,114,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,9,112,117,115,104,95,98,97,99,107,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,26,114,101,102,101,114,101,110,99,101,95,103,97,115,95,115,117,114,118,101,121,95,113,117,111,116,101,6,114,101,109,111,118,101,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,6,115,101,110,100,101,114,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,105,122,101,4,115,111,109,101,17,115,111,114,116,95,114,101,109,111,118,97,108,95,108,105,115,116,5,115,112,108,105,116,5,115,116,97,107,101,12,115,116,97,107,101,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,27,115,116,111,114,97,103,101,95,102,117,110,100,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,29,115,117,109,95,118,111,116,105,110,103,95,112,111,119,101,114,95,98,121,95,97,100,100,114,101,115,115,101,115,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,26,116,97,108,108,121,105,110,103,95,114,117,108,101,95,103,108,111,98,97,108,95,115,99,111,114,101,23,116,97,108,108,121,105,110,103,95,114,117,108,101,95,114,101,112,111,114,116,101,114,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,39,117,112,100,97,116,101,95,97,110,100,95,112,114,111,99,101,115,115,95,108,111,119,95,115,116,97,107,101,95,100,101,112,97,114,116,117,114,101,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,20,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,10,3,1,0,10,5,1,0,0,2,9,155,1,3,26,10,8,20,108,11,13,1,8,20,109,10,3,145,1,11,12,2,8,8,5,82,11,12,2,8,8,8,23,164,1,11,12,2,5,8,23,31,11,15,2,5,3,61,8,6,1,2,10,58,3,163,1,5,126,3,141,1,3,38,3,112,3,146,1,3,113,8,17,154,1,10,5,153,1,3,2,2,11,58,3,163,1,5,126,3,141,1,3,177,1,3,38,3,112,3,146,1,3,113,8,17,154,1,10,5,153,1,3,3,2,3,58,3,163,1,5,144,1,8,8,4,2,4,58,3,163,1,5,144,1,8,8,95,1,0,3,0,0,58,51,14,0,17,46,12,5,10,1,56,0,12,4,14,0,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,16,14,0,10,2,66,62,12,6,13,4,10,6,17,126,11,6,17,127,56,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,11,5,11,0,10,1,56,2,64,16,0,0,0,0,0,0,0,0,11,4,10,1,56,3,10,1,56,4,56,5,11,1,17,67,18,0,12,7,13,7,15,0,17,137,1,11,7,2,1,3,0,0,71,69,10,0,14,1,12,3,46,11,3,17,21,32,4,17,10,0,14,1,12,4,46,11,4,17,24,32,12,5,5,19,9,12,5,11,5,4,22,5,28,11,0,1,11,2,1,7,7,39,14,1,17,127,12,6,10,0,16,1,10,6,56,6,32,4,38,5,44,11,0,1,11,2,1,7,11,39,14,1,17,118,4,48,5,54,11,0,1,11,2,1,7,12,39,10,0,15,2,14,1,17,126,11,6,56,1,11,0,15,1,14,1,17,127,11,1,11,2,17,133,1,56,7,2,2,3,0,0,75,53,10,1,46,17,92,12,4,10,0,16,1,10,4,56,6,4,10,5,16,11,0,1,11,1,1,7,13,39,10,0,15,1,11,4,56,8,17,134,1,12,3,14,3,17,118,4,26,5,32,11,0,1,11,1,1,7,12,39,14,3,17,126,12,2,10,0,15,2,10,2,56,9,1,13,3,10,1,46,17,91,17,112,11,0,15,3,11,2,11,3,11,1,17,133,1,56,10,2,3,3,0,0,80,69,11,2,46,17,92,12,7,10,0,16,1,10,7,56,6,4,10,5,14,11,0,1,7,13,39,10,0,15,1,11,7,56,8,17,134,1,12,6,10,0,14,6,12,3,46,11,3,17,21,32,4,37,10,0,14,6,12,4,46,11,4,17,24,32,12,5,5,39,9,12,5,11,5,4,42,5,46,11,0,1,7,7,39,14,6,17,118,4,50,5,54,11,0,1,7,12,39,14,6,17,128,1,11,1,38,4,60,5,64,11,0,1,7,10,39,11,0,15,4,11,6,56,11,2,4,3,0,0,3,16,10,0,16,0,10,1,17,23,11,0,16,4,11,1,17,25,22,6,1,0,0,0,0,0,0,0,33,4,13,5,15,7,7,39,2,5,3,0,0,82,36,11,1,46,17,92,12,2,10,0,16,0,11,2,17,27,12,4,14,4,56,12,4,13,5,17,11,0,1,7,9,39,13,4,56,13,12,3,10,0,16,5,14,3,56,14,32,4,27,5,31,11,0,1,7,16,39,11,0,15,5,11,3,68,16,2,6,3,0,0,3,22,14,2,56,15,7,4,38,4,6,5,12,11,0,1,11,3,1,7,15,39,11,0,11,1,17,26,11,2,10,3,46,17,92,11,3,17,122,2,7,3,0,0,90,43,14,1,17,108,12,4,10,0,16,2,10,4,56,16,4,20,10,0,16,2,14,1,17,108,56,17,20,12,5,11,0,11,5,17,26,12,3,5,38,10,0,16,3,10,4,56,18,4,26,5,32,11,0,1,11,2,1,7,8,39,11,0,15,3,11,4,56,19,17,135,1,12,3,11,3,11,1,11,2,17,124,2,8,3,0,0,63,10,11,2,17,92,12,3,11,0,15,0,11,3,17,30,11,1,17,123,2,9,3,0,0,96,110,10,8,46,17,91,6,1,0,0,0,0,0,0,0,22,12,15,17,138,1,12,20,10,0,16,0,10,20,10,1,46,56,15,10,2,46,56,15,17,50,12,22,12,21,10,0,10,3,20,12,9,46,11,9,17,49,12,16,10,0,16,0,14,16,17,54,12,17,10,0,16,0,14,16,17,29,11,4,14,21,14,22,17,48,12,14,12,19,12,13,12,18,10,0,16,0,11,20,11,17,11,21,11,22,11,18,11,13,11,19,11,14,17,51,12,12,12,11,10,0,15,0,14,11,14,12,11,1,11,2,10,8,17,52,10,0,15,0,17,47,10,0,15,0,10,8,17,45,10,15,10,0,16,0,14,11,14,12,10,3,14,16,12,10,46,11,10,17,53,10,0,11,15,17,43,10,0,10,3,10,8,17,40,10,0,11,5,11,6,11,7,11,3,11,8,17,10,10,0,16,0,17,46,10,0,15,6,21,10,0,15,0,17,137,1,11,0,17,11,2,10,0,0,0,97,106,10,0,16,0,65,62,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,99,5,9,11,7,6,1,0,0,0,0,0,0,0,23,12,7,10,0,16,0,10,7,66,62,12,13,10,13,17,127,12,12,11,13,17,128,1,12,9,10,9,10,1,38,4,40,10,0,16,7,14,12,56,20,4,39,10,0,15,7,14,12,56,21,1,1,5,98,11,9,10,2,38,4,87,10,0,16,7,14,12,56,20,4,64,10,0,15,7,14,12,56,22,12,8,10,8,20,6,1,0,0,0,0,0,0,0,22,10,8,21,11,8,20,12,6,5,71,10,0,15,7,11,12,6,1,0,0,0,0,0,0,0,56,23,6,1,0,0,0,0,0,0,0,12,6,11,6,10,3,36,4,86,10,0,15,0,10,7,56,24,12,10,10,0,11,10,10,4,9,10,5,17,41,5,98,10,0,15,0,10,7,56,24,12,11,10,0,11,11,10,4,9,10,5,17,41,5,4,11,4,1,11,0,1,11,5,1,2,11,0,0,0,103,24,10,0,16,0,65,62,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,21,5,11,10,0,15,0,10,1,67,62,17,114,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,12,1,0,0,104,60,11,0,16,0,12,10,10,10,65,62,12,3,64,105,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,15,10,10,10,2,66,62,12,8,13,1,10,8,17,115,11,8,17,129,1,56,25,68,105,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,10,11,10,1,11,1,56,26,12,4,6,0,0,0,0,0,0,0,0,12,6,17,138,1,17,136,1,23,12,7,6,0,0,0,0,0,0,0,0,12,5,10,6,10,7,35,4,58,5,49,13,4,56,27,12,9,12,5,11,6,11,9,22,12,6,5,44,11,5,2,13,1,0,0,3,4,11,0,16,6,20,2,14,1,0,0,3,6,11,0,16,0,11,1,17,35,17,128,1,2,15,1,0,0,3,6,11,0,16,0,11,1,17,35,17,125,2,16,1,0,0,3,6,11,0,16,0,11,1,17,35,17,126,2,17,1,0,0,3,3,11,0,16,2,2,18,3,0,0,111,31,10,0,16,2,10,1,20,56,16,4,19,10,0,16,2,11,1,20,56,17,20,12,3,11,0,11,3,7,2,17,36,12,2,5,27,11,0,15,3,11,1,20,56,19,17,135,1,46,12,2,11,2,17,116,17,107,2,19,3,0,0,3,12,10,0,16,0,65,62,10,0,16,5,65,16,23,11,0,16,4,56,28,22,2,20,3,0,0,28,8,11,0,16,0,11,1,17,27,12,2,14,2,56,12,2,21,0,0,0,3,5,11,0,16,0,11,1,17,22,2,22,3,0,0,3,6,11,0,11,1,17,23,6,0,0,0,0,0,0,0,0,36,2,23,0,0,0,114,33,10,0,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,66,62,10,1,17,117,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,24,0,0,0,3,7,11,0,16,4,11,1,17,25,6,0,0,0,0,0,0,0,0,36,2,25,0,0,0,114,33,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,56,29,10,1,17,117,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,26,0,0,0,3,16,10,0,16,1,10,1,56,6,4,11,11,0,15,1,11,1,56,30,17,135,1,2,11,0,15,0,11,1,17,30,2,27,0,0,0,103,31,10,0,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,66,62,17,127,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,28,0,0,0,103,31,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,56,29,17,127,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,29,0,0,0,119,46,10,1,65,63,12,5,6,0,0,0,0,0,0,0,0,12,3,7,20,12,6,10,3,10,5,35,4,40,5,12,10,1,10,3,66,63,20,12,2,10,0,11,2,17,27,12,4,14,4,56,12,4,25,5,31,11,0,1,11,1,1,7,9,39,13,6,11,4,56,33,68,16,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,0,1,11,1,1,11,6,2,30,3,0,0,82,22,10,0,11,1,12,2,46,11,2,17,27,12,4,14,4,56,12,4,11,5,15,11,0,1,7,9,39,13,4,56,13,12,3,11,0,11,3,67,62,2,31,0,0,0,120,45,10,0,16,0,10,1,17,27,12,5,14,5,56,12,4,16,13,5,56,13,12,3,11,0,15,0,11,3,67,62,2,10,0,16,4,10,1,17,28,12,6,14,6,56,12,4,32,13,6,56,13,12,4,11,0,15,4,11,4,56,34,2,11,2,4,35,5,39,11,0,1,7,14,39,11,0,15,1,11,1,56,30,17,135,1,2,32,3,0,0,3,7,11,0,11,1,17,132,1,20,11,2,17,31,2,33,3,0,0,63,8,11,1,17,92,12,2,11,0,11,2,9,17,31,2,34,3,0,0,63,8,11,1,17,92,12,2,11,0,11,2,8,17,31,2,35,0,0,0,125,19,10,0,11,1,17,27,12,3,14,3,56,12,4,8,5,12,11,0,1,7,9,39,13,3,56,13,12,2,11,0,11,2,66,62,2,36,3,0,0,126,57,10,0,16,0,10,1,17,27,12,7,14,7,56,12,4,11,8,12,3,5,15,10,2,7,0,33,12,3,11,3,4,25,13,7,56,13,12,5,11,0,16,0,11,5,66,62,2,10,0,16,4,10,1,17,28,12,8,14,8,56,12,4,36,8,12,4,5,40,11,2,7,1,33,12,4,11,4,4,50,13,8,56,13,12,6,11,0,16,4,11,6,56,29,2,11,0,15,1,11,1,56,30,17,135,1,46,2,37,1,0,0,125,21,10,0,16,0,11,1,17,27,12,3,14,3,56,12,4,9,5,13,11,0,1,7,9,39,13,3,56,13,12,2,11,0,16,0,11,2,66,62,2,38,1,0,0,125,21,10,0,16,4,11,1,17,28,12,3,14,3,56,12,4,9,5,13,11,0,1,7,17,39,13,3,56,13,12,2,11,0,16,4,11,2,56,29,2,39,3,0,0,127,39,10,1,17,131,1,20,12,6,10,2,7,0,33,4,16,11,0,11,6,12,3,46,11,3,17,37,12,4,5,21,11,0,11,6,11,2,17,36,12,4,11,4,12,7,10,1,56,35,12,5,11,7,17,119,14,5,33,4,32,5,36,11,1,1,7,19,39,11,1,17,130,1,2,40,0,0,0,131,1,32,10,0,15,5,17,44,10,0,16,5,56,36,32,4,25,5,9,10,0,15,5,69,16,12,3,10,0,15,0,11,3,56,24,12,4,10,0,11,4,10,1,8,10,2,17,41,5,3,11,1,1,11,0,1,11,2,1,2,41,0,0,0,133,1,58,10,4,46,17,91,6,1,0,0,0,0,0,0,0,22,12,5,14,1,17,127,12,6,14,1,17,126,12,7,10,0,15,2,10,7,56,9,1,10,0,16,7,14,6,56,20,4,28,10,0,15,7,14,6,56,21,1,1,10,0,16,6,20,14,1,17,128,1,23,10,0,15,6,21,11,2,10,6,17,42,10,5,11,6,14,1,17,126,11,3,18,4,56,37,13,1,11,5,17,112,11,0,15,3,11,7,11,1,11,4,17,133,1,56,10,2,42,0,0,0,135,1,69,10,0,14,1,12,2,46,11,2,56,38,4,12,10,0,14,1,56,39,1,1,10,0,46,56,40,12,7,14,7,65,63,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,66,5,26,14,7,10,4,66,63,12,6,10,0,10,6,56,41,12,8,10,8,14,1,12,3,46,11,3,56,42,4,57,10,8,14,1,56,43,11,8,46,56,44,4,54,10,0,11,6,56,39,1,1,5,56,11,6,1,5,61,11,8,1,11,6,1,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,21,11,0,1,2,43,0,0,0,62,28,10,0,16,4,56,45,32,4,25,5,6,10,0,15,4,56,46,12,2,13,2,10,1,17,109,10,1,14,2,17,127,14,2,17,126,18,3,56,47,10,0,15,0,11,2,68,62,5,0,11,0,1,2,44,0,0,0,144,1,57,10,0,46,65,16,12,6,6,1,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,54,5,11,10,0,10,4,12,1,46,11,1,66,16,20,12,3,10,4,12,5,10,5,6,0,0,0,0,0,0,0,0,36,4,49,5,26,11,5,6,1,0,0,0,0,0,0,0,23,12,5,10,0,10,5,12,2,46,11,2,66,16,20,10,3,36,4,41,5,42,5,49,10,0,10,5,10,5,6,1,0,0,0,0,0,0,0,22,71,16,5,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,1,2,45,0,0,0,103,26,10,0,46,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,21,5,11,10,0,10,2,67,62,10,1,17,121,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,11,1,1,2,46,0,0,0,146,1,30,6,0,0,0,0,0,0,0,0,12,3,10,0,65,62,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,26,5,12,10,0,10,1,66,62,12,4,11,3,11,4,17,128,1,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,47,0,0,0,103,23,10,0,46,65,62,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,20,5,11,10,0,10,1,67,62,17,110,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,48,0,0,0,147,1,69,6,0,0,0,0,0,0,0,0,12,8,56,48,12,4,6,0,0,0,0,0,0,0,0,12,9,56,48,12,5,13,0,46,56,36,32,4,60,5,14,13,0,69,16,12,10,10,2,10,10,66,16,20,53,10,1,53,24,7,3,26,12,6,13,4,10,10,10,6,52,56,49,11,8,11,6,52,22,12,8,10,3,10,10,66,16,20,53,10,1,53,24,7,3,26,12,7,13,5,11,10,10,7,52,56,49,11,9,11,7,52,22,12,9,5,8,11,3,1,11,2,1,11,8,11,4,11,9,11,5,2,49,0,0,0,148,1,40,7,21,12,5,14,1,56,50,32,4,36,5,7,13,1,56,51,12,4,12,6,10,0,10,6,17,20,4,16,5,20,11,0,1,7,5,39,10,0,16,0,12,3,11,4,56,52,12,2,11,3,14,2,17,54,17,136,1,38,4,35,13,5,11,6,68,63,5,2,11,0,1,11,5,2,50,0,0,0,151,1,47,64,16,0,0,0,0,0,0,0,0,12,7,64,16,0,0,0,0,0,0,0,0,12,8,10,0,65,62,12,5,11,3,10,5,26,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,42,5,18,10,0,10,4,66,62,17,129,1,53,10,2,53,24,10,1,53,26,12,6,13,7,11,6,52,68,16,13,8,10,9,68,16,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,13,11,0,1,11,7,11,8,2,51,0,0,0,152,1,108,11,1,11,2,23,12,22,64,16,0,0,0,0,0,0,0,0,12,12,64,16,0,0,0,0,0,0,0,0,12,14,10,0,65,62,12,20,10,20,14,6,56,53,23,12,21,6,0,0,0,0,0,0,0,0,12,19,10,19,10,20,35,4,103,5,23,10,0,10,19,66,62,17,129,1,53,12,25,14,3,10,19,66,16,20,12,23,14,6,14,19,56,54,4,48,14,6,14,19,56,55,20,12,15,11,23,11,15,23,12,9,5,61,10,5,53,11,25,24,10,22,53,26,12,16,11,23,11,16,52,22,12,9,11,9,12,11,13,12,11,11,68,16,14,4,10,19,66,16,20,12,24,14,8,14,19,56,54,4,85,14,8,14,19,56,55,20,12,17,11,24,11,17,23,12,10,5,93,10,7,10,21,26,12,18,11,24,11,18,22,12,10,11,10,12,13,13,14,11,13,68,16,11,19,6,1,0,0,0,0,0,0,0,22,12,19,5,18,11,0,1,11,12,11,14,2,52,0,0,0,153,1,107,10,0,46,65,62,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,9,5,23,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,7,18,39,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,94,5,30,10,0,10,6,67,62,12,10,10,1,10,6,66,16,20,12,9,10,3,10,9,56,56,12,8,11,9,53,10,10,46,17,111,53,24,7,3,26,12,12,13,8,11,12,52,56,56,12,13,13,13,10,4,10,2,10,6,66,16,20,56,56,56,57,1,14,13,56,15,6,0,0,0,0,0,0,0,0,36,4,84,10,10,46,17,127,12,11,10,10,11,13,10,11,10,5,17,122,11,11,56,58,5,86,11,13,56,59,11,10,11,8,17,113,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,25,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,2,53,0,0,0,159,1,84,10,1,65,62,12,9,6,0,0,0,0,0,0,0,0,12,8,10,8,10,9,35,4,73,5,10,10,1,10,8,66,62,12,12,10,12,17,127,12,13,10,4,14,13,56,38,4,28,10,4,14,13,56,60,20,56,52,12,6,5,30,7,21,12,6,11,6,12,11,10,5,14,13,56,61,4,39,6,0,0,0,0,0,0,0,0,12,7,5,41,6,1,0,0,0,0,0,0,0,12,7,11,7,12,10,10,0,11,13,10,12,17,115,10,12,17,128,1,10,12,17,129,1,10,12,17,111,10,2,10,8,66,16,20,10,3,10,8,66,16,20,11,12,10,0,17,120,11,11,11,10,18,2,56,62,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,5,11,1,1,11,3,1,11,5,1,11,4,1,11,2,1,2,54,1,0,0,146,1,35,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,1,65,63,12,3,10,2,10,3,35,4,29,5,12,10,0,10,1,10,2,66,63,20,17,35,12,5,11,4,11,5,17,129,1,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,55,1,0,0,3,3,11,0,16,0,2,56,1,0,0,3,5,11,0,16,1,11,1,56,6,2,57,1,0,0,3,5,11,0,16,3,11,1,56,18,2,58,3,0,0,163,1,32,11,0,16,0,12,5,7,21,12,3,6,0,0,0,0,0,0,0,0,12,1,10,5,65,62,12,2,10,1,10,2,35,4,28,5,15,10,5,10,1,66,62,17,127,12,4,13,3,11,4,68,63,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,10,11,5,1,11,3,2,0,1,0,6,0,4,0,5,0,2,0,3,0,0,0,7,0,66,0,149,1,0],"validator_wrapper":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,16,3,24,48,4,72,6,5,78,52,7,130,1,211,1,8,213,2,64,6,149,3,10,10,159,3,6,12,165,3,100,13,137,4,2,15,139,4,2,0,14,1,10,1,16,0,12,0,2,4,0,1,0,2,0,2,3,12,0,3,1,4,0,0,5,0,1,0,0,8,2,3,0,0,6,1,4,0,0,11,2,5,0,0,15,6,7,0,2,4,8,9,1,4,2,6,9,12,1,4,2,9,10,11,1,4,2,15,13,7,0,5,4,7,4,6,4,2,8,3,7,8,1,1,8,0,1,7,8,0,1,7,8,3,1,8,3,0,1,6,8,0,1,3,3,3,9,0,7,8,1,1,8,2,1,7,8,2,1,7,9,0,1,9,0,1,6,8,2,9,84,120,67,111,110,116,101,120,116,9,86,97,108,105,100,97,116,111,114,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,9,86,101,114,115,105,111,110,101,100,6,99,114,101,97,116,101,9,99,114,101,97,116,101,95,118,49,7,100,101,115,116,114,111,121,5,105,110,110,101,114,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,10,116,120,95,99,111,110,116,101,120,116,17,117,112,103,114,97,100,101,95,116,111,95,108,97,116,101,115,116,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,1,7,8,2,0,3,0,0,5,6,6,1,0,0,0,0,0,0,0,11,0,11,1,56,0,18,0,2,1,3,0,0,5,6,10,0,17,3,11,0,15,0,56,1,2,2,3,0,0,5,6,13,0,17,3,11,0,19,0,56,2,2,3,0,0,0,5,10,11,0,46,17,4,6,1,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,2,4,0,0,0,5,4,11,0,16,0,17,8,2,0,0,0,13,0],"voting_power":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,87,4,107,4,5,111,134,1,7,245,1,176,2,8,165,4,96,6,133,5,70,10,203,5,16,12,219,5,254,6,13,217,12,4,15,221,12,2,0,22,1,21,2,9,0,18,0,1,2,0,0,2,2,0,3,0,4,0,0,13,0,1,0,0,6,2,3,0,0,15,4,5,0,0,7,6,1,0,0,3,7,1,0,0,17,8,1,0,0,4,4,1,0,0,16,1,5,0,0,12,1,5,0,1,7,17,1,1,0,1,8,19,20,1,0,2,5,11,5,0,2,10,11,5,0,2,11,11,5,0,3,13,21,1,0,3,15,14,5,0,3,22,14,5,0,9,13,10,13,1,7,10,8,2,0,2,6,10,8,2,3,2,10,8,1,3,1,6,10,8,2,1,3,2,7,10,8,1,8,1,3,7,10,8,1,3,3,2,7,10,8,2,10,8,1,4,3,10,8,1,3,3,1,8,2,2,3,3,8,3,8,1,3,10,8,1,3,3,3,3,1,8,1,1,6,8,2,3,3,3,3,4,3,1,3,3,3,7,10,9,0,9,0,3,7,1,3,3,3,3,3,7,8,1,1,6,10,9,0,1,1,2,7,8,2,3,12,3,3,3,3,3,3,3,3,3,6,8,2,6,8,2,3,9,86,97,108,105,100,97,116,111,114,15,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,17,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,86,50,19,97,100,106,117,115,116,95,118,111,116,105,110,103,95,112,111,119,101,114,16,99,104,101,99,107,95,105,110,118,97,114,105,97,110,116,115,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,22,105,110,105,116,95,118,111,116,105,110,103,95,112,111,119,101,114,95,105,110,102,111,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,4,109,97,116,104,3,109,97,120,3,109,105,110,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,5,115,116,97,107,101,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,19,117,112,100,97,116,101,95,118,111,116,105,110,103,95,112,111,119,101,114,9,118,97,108,105,100,97,116,111,114,15,118,97,108,105,100,97,116,111,114,95,105,110,100,101,120,13,118,97,108,105,100,97,116,111,114,95,115,101,116,6,118,101,99,116,111,114,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,16,39,0,0,0,0,0,0,3,8,11,26,0,0,0,0,0,0,3,8,232,3,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,2,19,3,22,3,1,2,3,19,3,22,3,14,3,0,3,0,0,9,29,7,0,7,2,7,0,10,0,46,65,10,17,11,17,12,17,13,12,4,10,0,10,4,12,1,46,11,1,17,1,12,3,12,2,13,2,11,4,11,3,17,4,10,0,11,2,17,5,11,0,46,17,6,2,1,0,0,0,12,58,10,0,17,2,12,8,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,7,64,13,0,0,0,0,0,0,0,0,12,5,10,2,10,4,35,4,51,5,17,10,0,10,2,66,10,17,15,12,6,10,6,53,7,0,53,24,10,8,53,26,52,10,1,17,13,12,9,10,2,10,9,11,6,18,1,12,3,13,5,11,3,17,3,11,7,11,9,22,12,7,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,0,1,11,5,7,0,11,7,23,2,2,0,0,0,15,28,6,0,0,0,0,0,0,0,0,12,1,10,0,65,10,12,2,6,0,0,0,0,0,0,0,0,12,3,10,1,10,2,35,4,24,5,12,11,3,10,0,10,1,66,10,17,15,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,3,0,0,0,16,39,6,0,0,0,0,0,0,0,0,12,4,10,0,46,65,13,12,5,10,4,10,5,35,4,25,5,11,10,0,10,4,12,2,46,11,2,66,13,16,0,20,14,1,16,0,20,36,12,3,5,27,9,12,3,11,3,4,34,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,11,1,11,4,56,0,2,4,0,0,0,18,84,6,0,0,0,0,0,0,0,0,12,5,10,0,46,65,13,12,6,10,5,10,6,35,4,16,5,11,10,2,6,0,0,0,0,0,0,0,0,36,12,3,5,18,9,12,3,11,3,4,74,10,0,10,5,67,13,12,9,10,2,10,6,10,5,23,17,11,12,7,10,1,10,9,16,1,20,11,7,22,17,13,12,8,10,2,11,8,10,9,16,1,20,23,17,13,12,4,10,9,16,1,20,10,4,22,10,9,15,1,21,11,9,16,1,20,10,1,37,4,61,5,65,11,0,1,7,5,39,11,2,11,4,23,12,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,6,11,0,1,11,2,6,0,0,0,0,0,0,0,0,33,4,81,5,83,7,3,39,2,5,0,0,0,11,22,14,1,56,1,32,4,17,5,5,13,1,69,13,19,1,1,12,3,12,2,10,0,11,2,67,10,11,3,17,14,5,0,11,0,1,11,1,70,13,0,0,0,0,0,0,0,0,2,6,0,0,0,22,119,6,0,0,0,0,0,0,0,0,12,3,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,9,10,3,10,4,35,4,35,5,12,10,0,10,3,66,10,17,16,12,12,10,12,6,0,0,0,0,0,0,0,0,36,4,22,5,26,11,0,1,7,6,39,11,9,11,12,22,12,9,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,9,7,0,33,4,40,5,44,11,0,1,7,3,39,6,0,0,0,0,0,0,0,0,12,1,10,1,10,4,35,4,116,5,51,10,1,6,1,0,0,0,0,0,0,0,22,12,2,10,2,10,4,35,4,111,5,60,10,0,10,1,66,10,12,10,10,0,10,2,66,10,12,11,10,10,17,15,12,7,10,11,17,15,12,8,11,10,17,16,12,5,11,11,17,16,12,6,10,7,10,8,36,4,93,10,5,10,6,38,4,89,5,93,11,0,1,7,4,39,11,7,11,8,35,4,106,11,5,11,6,37,4,102,5,106,11,0,1,7,4,39,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,55,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,46,11,0,1,2,7,1,0,0,1,2,7,0,2,8,1,0,0,1,2,7,1,2,1,2,1,1,0,20,0]},"type_origin_table":[{"module_name":"validator_cap","struct_name":"UnverifiedValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_cap","struct_name":"ValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakingPool","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"PoolTokenExchangeRate","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakedIota","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"ValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"Validator","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"StakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"UnstakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfo","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfoV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_wrapper","struct_name":"ValidatorWrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorSet","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEventV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorJoinEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorLeaveEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"storage_fund","struct_name":"StorageFund","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"stake_subsidy","struct_name":"StakeSubsidy","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"SystemParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"SystemParametersV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"IotaSystemStateInner","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"IotaSystemStateInnerV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"SystemEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system","struct_name":"IotaSystemState","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisChainParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenDistributionSchedule","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenAllocation","package":"0x0000000000000000000000000000000000000000000000000000000000000003"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"F8GGcAVhtPumDoXzc6z9N8Hf9zoTNFx1BPiCy7FJNZsQ","storage_rebate":0},{"data":{"Package":{"id":"0x000000000000000000000000000000000000000000000000000000000000dee9","version":10,"module_map":{"clob":[161,28,235,11,6,0,0,0,13,1,0,35,2,35,134,1,3,169,1,195,4,4,236,5,178,1,5,158,7,249,9,7,151,17,237,14,8,132,32,96,6,228,32,147,2,10,247,34,226,1,11,217,36,8,12,225,36,179,39,13,148,76,40,14,188,76,26,0,45,0,53,0,54,0,94,1,105,1,135,1,2,28,2,46,2,47,2,64,2,85,2,103,2,124,2,127,2,133,1,2,134,1,0,16,7,0,0,14,7,2,0,1,0,1,0,10,7,2,0,1,0,1,0,12,7,2,0,1,0,1,0,9,6,0,0,19,4,0,0,15,8,2,0,1,0,1,0,13,7,2,0,1,0,1,0,11,7,2,0,1,0,1,1,4,4,1,4,0,2,0,12,0,2,5,12,1,0,1,4,8,7,1,0,0,5,21,7,0,6,1,4,1,0,1,7,2,8,0,8,3,12,1,0,1,10,7,12,2,7,0,4,1,11,6,7,0,11,22,4,0,12,17,2,0,13,18,12,2,7,1,4,1,15,20,2,0,0,60,0,1,0,0,49,2,3,0,0,51,4,1,2,0,0,0,50,5,1,2,0,0,0,57,6,1,2,0,0,0,58,7,1,2,0,0,0,144,1,8,9,2,0,0,0,145,1,8,10,2,0,0,0,125,11,12,2,0,0,0,126,13,12,2,0,0,0,93,14,15,2,0,0,0,92,14,15,2,0,0,0,91,16,15,2,0,0,0,110,17,18,2,0,0,0,78,19,20,2,0,0,0,109,21,22,2,0,0,0,107,20,23,0,0,62,24,1,2,0,0,0,63,25,1,2,0,0,0,44,26,1,2,0,0,0,121,27,28,2,0,0,0,43,29,1,2,0,0,0,36,30,1,2,0,0,0,86,31,32,2,0,0,0,24,31,33,2,0,0,0,74,34,35,2,0,0,0,73,36,37,2,0,0,0,72,36,37,2,0,0,0,71,38,20,2,0,0,0,75,39,40,2,0,0,1,39,84,60,1,4,1,40,84,60,1,4,1,42,71,72,1,4,1,66,84,20,1,4,1,67,84,78,1,4,1,79,91,20,1,4,1,82,70,23,1,4,1,95,70,35,1,4,1,96,70,35,1,4,1,98,2,51,1,4,1,102,84,35,1,4,1,112,84,35,1,4,1,120,71,45,1,4,2,23,97,20,1,0,2,24,97,35,1,0,2,55,90,55,1,0,2,56,77,55,1,0,2,77,62,1,1,0,2,87,90,1,1,0,2,98,2,54,1,0,2,137,1,77,1,1,0,2,143,1,63,9,1,0,3,97,35,20,0,3,138,1,35,20,0,3,139,1,35,20,0,3,140,1,35,78,0,4,38,74,60,1,0,4,83,74,23,1,0,5,70,1,46,1,0,6,84,80,20,1,0,6,123,79,55,1,0,6,142,1,67,20,1,0,6,146,1,1,55,1,0,7,131,1,66,20,0,8,68,68,9,1,0,8,80,9,55,1,0,8,84,88,1,1,0,8,142,1,59,20,1,0,9,61,45,1,1,3,10,27,73,74,2,7,4,10,38,75,76,2,7,4,10,41,83,82,2,7,4,10,48,75,23,2,7,4,10,59,43,1,2,7,4,10,69,73,74,2,7,4,10,82,73,23,2,7,4,10,98,2,43,2,7,4,10,99,75,74,2,7,4,10,114,92,1,2,7,4,10,119,83,47,2,7,4,11,76,60,61,1,8,11,98,2,48,0,11,136,1,49,50,0,13,25,95,1,2,7,4,13,38,94,76,2,7,4,13,41,81,82,2,7,4,13,48,94,23,2,7,4,13,98,2,53,2,7,4,14,122,45,1,1,8,73,42,58,45,58,47,39,0,87,52,49,45,49,47,62,45,62,47,88,57,68,58,67,45,80,3,65,45,47,45,67,47,65,47,47,47,51,45,51,47,13,56,10,56,61,45,64,45,64,47,36,0,38,0,32,0,74,42,56,20,75,42,70,42,50,45,17,56,46,45,60,47,59,47,59,45,18,56,77,42,57,20,85,52,79,35,79,42,71,42,40,0,42,0,34,0,37,0,50,47,46,47,60,45,41,0,11,56,66,45,12,56,66,47,48,47,48,45,76,42,35,0,78,42,68,93,86,52,76,35,83,52,78,35,43,47,45,47,61,47,45,45,14,56,68,98,68,99,72,35,70,35,20,56,30,0,72,42,75,35,69,35,84,52,74,35,31,0,77,35,44,45,44,47,33,0,28,56,1,8,5,0,1,7,8,22,1,8,10,6,3,3,3,3,11,14,1,8,20,7,8,22,4,3,3,11,16,1,8,20,7,8,22,3,7,11,6,2,9,0,9,1,11,16,1,9,0,6,8,10,3,7,11,6,2,9,0,9,1,11,16,1,9,1,6,8,10,4,7,11,6,2,9,0,9,1,3,6,8,10,7,8,22,1,11,16,1,9,0,1,11,16,1,9,1,6,7,11,6,2,9,0,9,1,3,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,3,11,16,1,9,0,11,16,1,9,1,3,5,7,11,6,2,9,0,9,1,3,6,8,15,11,16,1,9,1,7,8,22,5,7,11,6,2,9,0,9,1,3,3,3,11,14,1,9,1,2,11,14,1,9,0,11,14,1,9,1,4,7,11,6,2,9,0,9,1,3,3,11,14,1,9,0,7,7,11,6,2,9,0,9,1,3,1,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,2,11,16,1,9,0,11,16,1,9,1,7,7,11,6,2,9,0,9,1,3,3,1,3,6,8,10,7,8,22,1,3,9,7,11,6,2,9,0,9,1,3,3,1,3,2,6,8,15,6,8,10,7,8,22,4,3,3,1,3,1,1,2,8,18,6,8,4,5,8,18,6,8,4,3,3,3,3,7,11,6,2,9,0,9,1,3,6,8,10,5,7,11,9,1,8,5,7,11,17,2,3,3,3,3,8,18,1,8,4,2,7,11,6,2,9,0,9,1,6,8,10,3,7,11,6,2,9,0,9,1,10,3,6,8,10,2,6,11,6,2,9,0,9,1,6,8,10,1,10,8,4,4,3,3,3,3,1,6,11,6,2,9,0,9,1,2,3,3,4,6,11,6,2,9,0,9,1,3,3,6,8,15,2,10,3,10,3,3,6,11,9,1,8,5,3,3,3,6,11,6,2,9,0,9,1,3,6,8,10,1,6,8,4,1,11,17,2,3,8,4,2,3,8,4,1,11,17,2,9,0,9,1,4,8,13,8,18,8,19,8,13,1,9,0,1,8,13,1,9,1,1,8,19,1,6,8,19,1,6,8,18,1,11,9,1,9,0,2,8,18,11,17,2,3,3,1,11,21,2,9,0,9,1,1,11,11,1,9,0,1,11,14,1,9,0,2,9,0,9,1,1,11,6,2,9,0,9,1,1,8,0,1,6,11,16,1,9,0,1,6,9,0,1,8,18,3,7,11,11,1,9,0,8,18,11,14,1,9,0,4,7,11,11,1,9,0,3,6,8,10,7,8,22,4,3,11,16,1,9,0,11,16,1,9,1,3,3,11,14,1,9,0,11,14,1,9,1,3,1,6,8,15,1,6,11,14,1,9,0,2,11,14,1,9,0,7,8,22,30,1,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,11,14,1,9,1,1,3,3,3,1,3,7,8,5,3,1,6,11,9,1,9,0,2,7,11,9,1,9,0,3,1,7,9,0,1,6,11,17,2,9,0,9,1,1,6,11,12,1,9,0,2,6,11,17,2,9,0,9,1,9,0,1,6,9,1,3,7,11,11,1,9,0,8,18,3,2,1,3,2,7,11,14,1,9,0,3,2,7,11,14,1,9,0,11,14,1,9,0,2,7,11,21,2,9,0,9,1,9,0,1,7,9,1,2,7,11,17,2,9,0,9,1,9,0,2,6,11,9,1,9,0,3,26,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,27,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,1,3,6,8,4,7,8,4,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,3,11,14,1,9,0,11,14,1,9,1,11,14,1,9,1,2,7,11,16,1,9,0,11,16,1,9,0,7,3,7,11,9,1,8,5,8,4,3,3,3,8,18,3,7,11,11,1,9,0,6,8,10,3,3,7,11,9,1,9,0,3,9,0,3,7,11,17,2,9,0,9,1,9,0,9,1,1,11,1,2,9,0,9,1,2,6,11,21,2,9,0,9,1,9,0,3,7,11,21,2,9,0,9,1,9,0,9,1,11,11,14,1,9,0,11,14,1,9,0,11,14,1,9,0,3,3,11,14,1,9,1,11,14,1,9,1,11,14,1,9,1,3,3,8,18,2,6,11,11,1,9,0,8,18,1,11,2,2,9,0,9,1,1,11,3,2,9,0,9,1,11,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,1,8,4,3,3,8,18,7,11,17,2,3,3,3,3,7,8,5,8,4,13,3,7,11,9,1,8,5,3,3,1,7,11,9,1,8,5,8,4,3,3,8,18,3,8,18,7,11,17,2,3,3,17,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,3,1,3,3,3,8,4,3,8,18,3,3,8,18,7,11,17,2,3,3,7,6,8,5,10,8,4,6,8,4,6,11,12,1,3,3,8,18,6,11,17,2,3,3,5,3,3,3,3,8,18,6,3,10,3,3,3,3,10,3,4,3,6,8,4,6,11,12,1,3,6,11,17,2,3,8,4,4,6,11,9,1,8,5,3,8,18,6,11,17,2,3,3,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,11,67,114,105,116,98,105,116,84,114,101,101,9,67,117,115,116,111,100,105,97,110,2,73,68,11,76,105,110,107,101,100,84,97,98,108,101,6,79,112,116,105,111,110,5,79,114,100,101,114,13,79,114,100,101,114,67,97,110,99,101,108,101,100,11,79,114,100,101,114,70,105,108,108,101,100,13,79,114,100,101,114,70,105,108,108,101,100,86,50,11,79,114,100,101,114,80,108,97,99,101,100,13,79,114,100,101,114,80,108,97,99,101,100,86,50,4,80,111,111,108,11,80,111,111,108,67,114,101,97,116,101,100,3,83,85,73,5,84,97,98,108,101,9,84,105,99,107,76,101,118,101,108,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,3,97,100,100,4,97,115,107,115,4,98,97,99,107,7,98,97,108,97,110,99,101,10,98,97,115,101,95,97,115,115,101,116,28,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,99,97,110,99,101,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,102,105,108,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,112,108,97,99,101,100,29,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,114,101,109,97,105,110,105,110,103,23,98,97,115,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,14,98,97,115,101,95,99,117,115,116,111,100,105,97,110,18,98,97,116,99,104,95,99,97,110,99,101,108,95,111,114,100,101,114,4,98,105,100,115,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,17,99,97,110,99,101,108,95,97,108,108,95,111,114,100,101,114,115,12,99,97,110,99,101,108,95,111,114,100,101,114,4,99,108,111,98,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,14,99,114,101,97,116,101,95,97,99,99,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,12,99,114,101,97,116,101,95,112,111,111,108,95,12,99,114,101,97,116,105,111,110,95,102,101,101,7,99,114,105,116,98,105,116,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,100,101,112,111,115,105,116,95,98,97,115,101,13,100,101,112,111,115,105,116,95,113,117,111,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,19,100,101,115,116,114,111,121,95,101,109,112,116,121,95,108,101,118,101,108,4,101,109,105,116,19,101,109,105,116,95,111,114,100,101,114,95,99,97,110,99,101,108,101,100,17,101,109,105,116,95,111,114,100,101,114,95,102,105,108,108,101,100,5,101,118,101,110,116,16,101,120,112,105,114,101,95,116,105,109,101,115,116,97,109,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,12,102,114,111,109,95,98,97,108,97,110,99,101,5,102,114,111,110,116,3,103,101,116,22,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,97,115,107,95,115,105,100,101,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,98,105,100,95,115,105,100,101,16,103,101,116,95,109,97,114,107,101,116,95,112,114,105,99,101,16,103,101,116,95,111,114,100,101,114,95,115,116,97,116,117,115,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,18,105,110,106,101,99,116,95,108,105,109,105,116,95,111,114,100,101,114,11,105,110,115,101,114,116,95,108,101,97,102,12,105,110,116,111,95,98,97,108,97,110,99,101,6,105,115,95,98,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,4,106,111,105,110,12,108,105,110,107,101,100,95,116,97,98,108,101,16,108,105,115,116,95,111,112,101,110,95,111,114,100,101,114,115,12,108,111,99,107,95,98,97,108,97,110,99,101,8,108,111,116,95,115,105,122,101,17,109,97,107,101,114,95,114,101,98,97,116,101,95,114,97,116,101,13,109,97,107,101,114,95,114,101,98,97,116,101,115,9,109,97,116,99,104,95,97,115,107,9,109,97,116,99,104,95,98,105,100,29,109,97,116,99,104,95,98,105,100,95,119,105,116,104,95,113,117,111,116,101,95,113,117,97,110,116,105,116,121,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,3,109,117,108,3,110,101,119,4,110,101,120,116,17,110,101,120,116,95,97,115,107,95,111,114,100,101,114,95,105,100,17,110,101,120,116,95,98,105,100,95,111,114,100,101,114,95,105,100,9,110,101,120,116,95,108,101,97,102,6,111,98,106,101,99,116,11,111,112,101,110,95,111,114,100,101,114,115,6,111,112,116,105,111,110,8,111,114,100,101,114,95,105,100,12,111,114,100,101,114,95,105,115,95,98,105,100,5,111,119,110,101,114,17,112,108,97,99,101,95,108,105,109,105,116,95,111,114,100,101,114,18,112,108,97,99,101,95,109,97,114,107,101,116,95,111,114,100,101,114,7,112,111,111,108,95,105,100,13,112,114,101,118,105,111,117,115,95,108,101,97,102,5,112,114,105,99,101,9,112,117,115,104,95,98,97,99,107,8,113,117,97,110,116,105,116,121,11,113,117,111,116,101,95,97,115,115,101,116,24,113,117,111,116,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,15,113,117,111,116,101,95,99,117,115,116,111,100,105,97,110,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,12,114,101,109,111,118,101,95,111,114,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,3,115,117,105,25,115,119,97,112,95,101,120,97,99,116,95,98,97,115,101,95,102,111,114,95,113,117,111,116,101,25,115,119,97,112,95,101,120,97,99,116,95,113,117,111,116,101,95,102,111,114,95,98,97,115,101,5,116,97,98,108,101,16,116,97,107,101,114,95,99,111,109,109,105,115,115,105,111,110,14,116,97,107,101,114,95,102,101,101,95,114,97,116,101,9,116,105,99,107,95,115,105,122,101,12,116,105,109,101,115,116,97,109,112,95,109,115,14,116,111,116,97,108,95,113,117,97,110,116,105,116,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,10,117,110,115,97,102,101,95,100,105,118,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,15,117,115,114,95,111,112,101,110,95,111,114,100,101,114,115,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,13,119,105,116,104,100,114,97,119,95,98,97,115,101,14,119,105,116,104,100,114,97,119,95,113,117,111,116,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,3,8,19,0,0,0,0,0,0,0,3,8,20,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,2,1,4,2,1,0,2,1,1,2,1,2,2,1,3,3,8,0,0,0,0,0,0,0,128,3,8,64,75,76,0,0,0,0,0,3,8,160,37,38,0,0,0,0,0,3,8,0,232,118,72,23,0,0,0,0,2,7,111,8,18,29,8,13,116,8,13,129,1,3,89,3,130,1,3,88,3,1,2,7,111,8,18,106,3,81,1,108,8,18,32,3,113,3,65,3,2,2,6,111,8,18,106,3,81,1,108,8,18,30,3,113,3,3,2,10,111,8,18,106,3,81,1,108,8,18,132,1,3,31,3,33,3,113,3,128,1,3,90,3,4,2,6,106,3,113,3,115,3,81,1,108,8,18,65,3,5,2,2,113,3,104,11,17,2,3,8,4,6,2,15,76,8,19,37,11,9,1,8,5,26,11,9,1,8,5,101,3,100,3,141,1,11,21,2,8,18,11,17,2,3,3,129,1,3,89,3,130,1,3,88,3,35,11,11,1,9,0,118,11,11,1,9,1,52,11,14,1,8,20,34,11,14,1,9,0,117,11,14,1,9,1,7,2,6,111,8,18,106,3,81,1,108,8,18,32,3,113,3,8,2,8,111,8,18,106,3,81,1,108,8,18,132,1,3,31,3,33,3,113,3,6,56,1,56,2,56,3,56,0,0,0,0,41,7,11,0,19,5,12,1,1,11,1,56,0,2,1,1,0,0,1,2,7,0,39,2,0,0,0,44,72,56,1,12,6,56,2,12,9,10,3,10,2,17,54,6,0,0,0,0,0,0,0,0,36,4,11,5,15,11,5,1,7,20,39,10,6,10,9,34,4,20,5,24,11,5,1,7,16,39,10,0,10,1,38,4,29,5,33,11,5,1,7,2,39,10,5,17,81,12,8,14,8,17,82,20,12,7,11,8,10,5,56,3,10,5,56,3,7,1,7,27,10,5,56,4,10,0,10,1,10,2,10,3,10,5,56,5,11,5,56,6,11,4,56,7,56,8,57,0,56,9,11,7,11,6,11,9,11,0,11,1,11,2,11,3,18,0,56,10,2,3,1,0,0,1,2,7,0,39,4,1,0,0,1,20,14,1,56,11,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,7,39,11,0,54,0,11,2,56,12,11,1,56,13,56,14,2,5,1,0,0,1,20,14,1,56,15,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,8,39,11,0,54,1,11,2,56,12,11,1,56,16,56,17,2,6,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,6,39,11,0,54,0,11,1,11,2,11,3,56,18,2,7,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,6,39,11,0,54,1,11,1,11,2,11,3,56,19,2,8,1,0,0,64,49,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,5,1,11,4,1,7,6,39,14,2,56,11,10,1,38,4,19,5,27,11,0,1,11,5,1,11,4,1,7,7,39,14,3,56,15,12,6,11,0,11,1,9,11,2,11,3,11,4,11,5,56,20,12,8,12,7,14,8,56,15,12,9,11,7,11,8,11,9,11,6,23,2,9,1,0,0,65,48,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,4,1,11,2,1,7,6,39,14,3,56,15,10,1,38,4,19,5,27,11,0,1,11,4,1,11,2,1,7,8,39,11,0,11,1,7,27,11,2,17,63,11,3,56,16,56,21,12,6,12,5,14,5,56,22,12,7,11,5,10,4,56,23,11,6,11,4,56,24,11,7,2,10,0,0,0,69,193,2,10,0,55,2,17,82,20,12,24,11,1,12,30,56,7,12,10,11,4,12,26,10,0,54,3,12,9,10,9,46,56,25,4,25,11,0,1,11,9,1,11,10,11,26,2,10,9,46,56,26,12,32,12,34,9,12,31,10,9,46,56,25,32,4,43,5,38,10,34,10,2,37,12,5,5,45,9,12,5,11,5,4,190,2,10,9,10,32,56,27,12,33,10,33,16,4,56,28,56,29,20,12,23,10,33,16,4,56,30,32,4,158,2,5,63,10,33,16,4,10,23,56,31,12,16,10,16,16,5,20,12,15,9,12,27,10,16,16,6,20,10,3,37,4,95,8,12,27,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,32,10,24,10,16,56,33,5,227,1,10,15,10,16,16,8,20,17,52,12,19,10,19,10,0,55,4,20,17,55,12,28,4,112,11,28,6,1,0,0,0,0,0,0,0,22,12,28,10,19,11,28,22,12,18,10,30,10,18,36,4,127,11,18,12,12,11,19,12,13,10,15,12,11,5,170,1,8,12,31,10,30,7,21,10,0,55,4,20,22,17,53,10,16,16,8,20,17,53,10,0,55,5,20,26,10,0,55,5,20,24,12,11,10,11,10,16,16,8,20,17,54,12,13,10,13,10,0,55,4,20,17,55,12,29,4,166,1,11,29,6,1,0,0,0,0,0,0,0,22,12,29,10,13,11,29,22,12,12,10,13,10,0,55,6,20,17,54,12,20,11,15,10,11,23,12,15,11,30,10,12,23,12,30,10,0,54,0,10,16,16,7,20,10,11,56,34,12,14,13,26,10,12,56,35,12,25,10,0,54,1,10,16,16,7,20,13,25,10,20,10,13,22,56,35,56,17,10,0,54,7,11,25,56,36,1,13,10,11,14,56,37,1,10,0,55,2,17,82,20,10,16,11,11,11,12,11,13,23,11,20,56,38,11,27,4,232,1,8,12,6,5,236,1,10,15,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,143,2,10,23,12,22,10,33,16,4,10,23,56,39,12,21,10,21,56,40,32,4,254,1,11,21,56,29,20,12,23,5,128,2,11,21,1,10,0,54,8,11,16,16,7,20,56,41,10,22,56,42,1,10,33,15,4,11,22,56,43,1,5,154,2,11,16,1,10,33,15,4,10,23,56,44,12,17,11,15,11,17,15,5,21,10,31,4,157,2,5,158,2,5,57,11,33,16,4,56,30,4,182,2,10,9,11,34,12,7,46,11,7,56,45,1,12,34,10,9,11,32,56,46,17,0,10,9,10,34,12,8,46,11,8,56,47,12,32,1,10,31,4,189,2,11,0,1,11,9,1,5,190,2,5,32,11,10,11,26,2,11,0,0,0,85,153,2,10,0,55,2,17,82,20,12,22,11,1,12,25,56,7,12,11,11,4,12,23,10,0,54,3,12,10,10,10,46,56,25,4,25,11,0,1,11,10,1,11,11,11,23,2,10,10,46,56,26,12,28,12,30,10,10,46,56,25,32,4,41,5,36,10,30,10,2,37,12,5,5,43,9,12,5,11,5,4,150,2,10,10,10,28,56,27,12,29,10,29,16,4,56,28,56,29,20,12,21,10,29,16,4,56,30,32,4,244,1,5,61,10,29,16,4,10,21,56,31,12,16,10,16,16,5,20,12,15,9,12,24,10,16,16,6,20,10,3,37,4,93,8,12,24,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,32,10,22,10,16,56,33,5,183,1,10,25,10,15,36,4,100,10,15,12,6,5,102,10,25,12,6,11,6,12,12,10,12,10,16,16,8,20,17,52,12,13,10,13,10,0,55,6,20,17,54,12,18,10,13,10,0,55,4,20,17,55,12,26,4,127,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,15,10,12,23,12,15,11,25,10,12,23,12,25,10,0,54,0,10,16,16,7,20,10,12,56,34,12,14,13,23,10,26,56,35,12,27,10,0,54,1,10,16,16,7,20,13,27,10,18,56,35,56,17,10,0,54,7,11,27,56,36,1,13,11,11,14,56,37,1,10,0,54,1,10,16,16,7,20,13,23,11,13,56,35,56,17,10,0,55,2,17,82,20,10,16,11,12,11,26,11,18,56,38,11,24,4,188,1,8,12,7,5,192,1,10,15,6,0,0,0,0,0,0,0,0,33,12,7,11,7,4,227,1,10,21,12,20,10,29,16,4,10,21,56,39,12,19,10,19,56,40,32,4,210,1,11,19,56,29,20,12,21,5,212,1,11,19,1,10,0,54,8,11,16,16,7,20,56,41,10,20,56,42,1,10,29,15,4,11,20,56,43,1,5,238,1,11,16,1,10,29,15,4,10,21,56,44,12,17,11,15,11,17,15,5,21,10,25,6,0,0,0,0,0,0,0,0,33,4,243,1,5,244,1,5,55,11,29,16,4,56,30,4,140,2,10,10,11,30,12,8,46,11,8,56,45,1,12,30,10,10,11,28,56,46,17,0,10,10,10,30,12,9,46,11,9,56,47,12,28,1,10,25,6,0,0,0,0,0,0,0,0,33,4,149,2,11,0,1,11,10,1,5,150,2,5,30,11,11,11,23,2,12,0,0,0,86,158,2,10,0,55,2,17,82,20,12,22,11,3,12,10,56,8,12,23,10,0,54,9,12,9,10,9,46,56,25,4,23,11,0,1,11,9,1,11,10,11,23,2,10,9,46,56,48,12,28,12,30,10,9,46,56,25,32,4,39,5,34,10,30,10,1,38,12,4,5,41,9,12,4,11,4,4,155,2,10,9,10,28,56,27,12,29,10,29,16,4,56,28,56,29,20,12,21,10,29,16,4,56,30,32,4,248,1,5,59,10,29,16,4,10,21,56,31,12,15,10,15,16,5,20,12,14,9,12,24,10,15,16,6,20,10,2,37,4,97,8,12,24,10,15,16,5,20,10,15,16,8,20,17,52,12,17,10,0,54,1,10,15,16,7,20,11,17,56,49,10,22,10,15,56,33,5,186,1,14,10,56,22,12,25,10,25,10,14,38,4,107,10,14,12,5,5,109,11,25,12,5,11,5,12,11,10,11,10,15,16,8,20,17,52,12,12,10,12,10,0,55,6,20,17,54,12,18,10,12,10,0,55,4,20,17,55,12,26,4,134,1,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,14,10,11,23,12,14,10,0,54,1,10,15,16,7,20,11,12,56,50,12,13,13,13,10,26,56,35,12,27,10,0,54,1,10,15,16,7,20,13,27,10,18,56,35,56,17,10,0,54,7,11,27,56,36,1,13,23,11,13,56,36,1,10,0,54,0,10,15,16,7,20,13,10,10,11,56,51,56,14,10,0,55,2,17,82,20,10,15,11,11,11,26,11,18,56,38,11,24,4,191,1,8,12,6,5,195,1,10,14,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,230,1,10,21,12,20,10,29,16,4,10,21,56,39,12,19,10,19,56,40,32,4,213,1,11,19,56,29,20,12,21,5,215,1,11,19,1,10,0,54,8,11,15,16,7,20,56,41,10,20,56,42,1,10,29,15,4,11,20,56,43,1,5,241,1,11,15,1,10,29,15,4,10,21,56,44,12,16,11,14,11,16,15,5,21,14,10,56,22,6,0,0,0,0,0,0,0,0,33,4,247,1,5,248,1,5,53,11,29,16,4,56,30,4,144,2,10,9,11,30,12,7,46,11,7,56,52,1,12,30,10,9,11,28,56,46,17,0,10,9,10,30,12,8,46,11,8,56,47,12,28,1,14,10,56,22,6,0,0,0,0,0,0,0,0,33,4,154,2,11,0,1,11,9,1,5,155,2,5,28,11,10,11,23,2,13,1,0,0,87,85,10,1,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,9,5,17,11,0,1,11,6,1,11,5,1,7,6,39,10,1,6,0,0,0,0,0,0,0,0,34,4,22,5,30,11,0,1,11,6,1,11,5,1,7,6,39,11,2,4,52,11,0,11,1,7,27,11,5,17,63,11,4,56,16,56,53,12,9,12,7,13,3,11,7,10,6,56,23,56,54,11,9,11,6,56,24,12,4,5,82,11,1,14,3,56,11,37,4,58,5,66,11,0,1,11,6,1,11,5,1,7,7,39,11,0,7,0,11,5,17,63,11,3,56,13,56,55,12,8,10,6,56,23,12,3,13,4,11,8,11,6,56,24,56,56,11,3,11,4,2,14,0,0,0,89,118,10,5,56,12,12,13,10,3,4,30,10,2,10,1,17,52,12,11,10,0,54,1,11,5,11,11,56,57,10,0,55,10,20,12,10,10,0,55,10,20,6,1,0,0,0,0,0,0,0,22,10,0,54,10,21,10,0,54,9,12,8,5,50,10,0,54,0,11,5,10,2,56,58,10,0,55,11,20,12,10,10,0,55,11,20,6,1,0,0,0,0,0,0,0,22,10,0,54,11,21,10,0,54,3,12,8,10,10,10,1,10,2,10,3,10,13,10,4,18,4,12,9,10,8,10,1,12,7,46,11,7,56,47,12,12,32,4,75,10,8,10,1,10,1,10,6,56,59,18,5,56,60,12,12,11,8,11,12,56,27,15,4,10,10,11,9,56,61,10,0,55,2,17,82,20,10,10,11,3,10,13,11,2,10,1,11,4,57,1,56,62,10,0,55,8,10,13,56,63,32,4,107,10,0,54,8,10,13,11,6,56,64,56,65,5,109,11,6,1,11,0,54,8,11,13,56,41,10,10,11,1,56,66,11,10,2,15,1,0,0,96,144,2,10,2,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,8,1,11,6,1,11,7,1,7,6,39,10,1,6,0,0,0,0,0,0,0,0,36,4,20,5,30,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,1,10,0,55,12,20,25,6,0,0,0,0,0,0,0,0,33,4,39,5,49,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,2,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,58,5,68,11,0,1,11,8,1,11,6,1,11,7,1,7,6,39,10,4,10,6,17,63,36,4,74,5,84,11,0,1,11,8,1,11,6,1,11,7,1,7,19,39,10,7,56,12,12,19,10,3,4,128,1,10,0,55,1,10,19,56,67,12,18,10,0,54,1,10,7,10,18,56,68,12,14,10,0,10,2,10,1,11,6,17,63,11,14,56,53,12,16,12,10,14,10,56,22,12,12,11,18,14,16,56,69,23,12,17,10,0,54,0,10,19,11,10,56,14,10,0,54,1,11,19,11,16,56,17,5,160,1,10,0,54,0,10,7,10,2,56,70,12,9,10,0,10,1,11,6,17,63,11,9,56,55,12,15,12,11,10,2,14,11,56,22,23,12,12,14,15,56,69,12,17,10,0,54,0,10,19,11,11,56,14,10,0,54,1,11,19,11,15,56,17,10,5,7,24,33,4,175,1,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,25,33,4,197,1,11,0,1,11,8,1,11,7,1,10,12,11,2,33,4,190,1,5,192,1,7,9,39,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,26,33,4,228,1,10,12,6,0,0,0,0,0,0,0,0,33,4,206,1,5,214,1,11,0,1,11,8,1,11,7,1,7,10,39,11,0,11,1,11,2,11,3,11,4,11,7,11,8,56,71,12,13,11,12,11,17,8,11,13,2,11,5,7,23,33,4,233,1,5,241,1,11,0,1,11,8,1,11,7,1,7,14,39,10,2,10,12,36,4,133,2,11,0,11,1,11,2,10,12,23,11,3,11,4,11,7,11,8,56,71,12,13,11,12,11,17,8,11,13,2,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,16,0,0,0,1,4,11,0,7,27,35,2,17,0,0,0,1,19,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,11,1,16,8,20,57,2,56,72,2,18,0,0,0,1,27,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,10,2,10,1,16,5,20,11,2,23,11,1,16,8,20,11,3,11,4,57,3,56,73,2,19,1,0,0,100,110,11,2,56,12,12,12,10,0,55,8,10,12,56,63,4,9,5,13,11,0,1,7,12,39,10,0,54,8,10,12,56,41,12,13,10,13,10,1,12,3,46,11,3,56,74,4,26,5,32,11,13,1,11,0,1,7,3,39,10,13,10,1,12,4,46,11,4,56,75,20,12,11,10,1,17,16,12,8,10,8,4,49,10,0,55,9,12,5,5,52,10,0,55,3,12,5,11,5,11,11,56,47,12,10,4,58,5,64,11,13,1,11,0,1,7,3,39,10,8,4,70,10,0,54,9,12,6,5,73,10,0,54,3,12,6,11,6,11,13,11,10,11,1,10,12,56,76,12,9,11,8,4,96,14,9,16,5,20,14,9,16,8,20,17,52,12,7,10,0,54,1,11,12,11,7,56,49,5,103,10,0,54,0,11,12,14,9,16,5,20,56,32,11,0,55,2,17,82,20,14,9,56,33,2,20,0,0,0,101,54,11,1,10,3,56,42,1,10,0,10,2,12,5,46,11,5,56,77,16,4,10,3,56,78,4,15,5,19,11,0,1,7,3,39,10,0,10,2,56,27,12,6,10,6,15,4,11,3,56,43,12,7,14,7,16,7,20,11,4,33,4,35,5,41,11,0,1,11,6,1,7,4,39,11,6,16,4,56,30,4,50,11,0,11,2,56,46,17,0,5,52,11,0,1,11,7,2,21,1,0,0,102,104,10,0,55,2,17,82,20,12,11,11,1,56,12,12,13,10,0,55,8,10,13,56,63,4,14,5,18,11,0,1,7,12,39,10,0,54,8,10,13,56,41,12,14,10,14,46,56,79,32,4,99,5,29,10,14,46,56,80,56,29,20,12,9,10,14,10,9,12,2,46,11,2,56,75,20,12,10,10,9,17,16,12,6,10,6,4,52,10,0,54,9,12,3,5,55,10,0,54,3,12,3,11,3,12,7,10,7,11,10,12,4,46,11,4,56,47,12,12,1,11,7,10,14,11,12,11,9,10,13,56,76,12,8,11,6,4,88,14,8,16,5,20,14,8,16,8,20,17,52,12,5,10,0,54,1,10,13,11,5,56,49,5,95,10,0,54,0,10,13,14,8,16,5,20,56,32,10,11,14,8,56,33,5,23,11,14,1,11,0,1,2,22,1,0,0,103,148,1,10,0,55,2,17,82,20,12,15,11,2,56,12,12,18,10,0,55,8,10,18,56,63,4,14,5,18,11,0,1,6,0,0,0,0,0,0,0,0,39,6,0,0,0,0,0,0,0,0,12,16,6,0,0,0,0,0,0,0,0,12,17,14,1,65,20,12,10,6,0,0,0,0,0,0,0,0,12,8,10,0,54,8,10,18,56,41,12,19,10,8,10,10,35,4,143,1,5,37,14,1,10,8,66,20,20,12,14,10,19,10,14,12,3,46,11,3,56,74,4,50,5,56,11,19,1,11,0,1,7,3,39,10,19,10,14,12,4,46,11,4,56,75,20,12,12,10,14,17,16,12,9,10,12,10,17,34,4,96,11,12,12,17,10,9,4,79,10,0,55,9,12,5,5,82,10,0,55,3,12,5,11,5,10,17,56,47,12,11,4,88,5,94,11,19,1,11,0,1,7,11,39,11,11,12,16,10,9,4,102,10,0,54,9,12,6,5,105,10,0,54,3,12,6,11,6,10,19,10,16,11,14,10,18,56,76,12,13,11,9,4,128,1,14,13,16,5,20,14,13,16,8,20,17,52,12,7,10,0,54,1,10,18,11,7,56,49,5,135,1,10,0,54,0,10,18,14,13,16,5,20,56,32,10,15,14,13,56,33,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,32,11,19,1,11,0,1,2,23,1,0,0,104,84,11,1,56,12,12,7,10,0,55,8,11,7,56,81,12,8,64,28,0,0,0,0,0,0,0,0,12,3,10,8,56,82,12,5,10,5,56,40,32,4,76,5,18,10,8,10,5,56,29,20,56,75,20,12,6,10,5,56,29,20,17,16,4,36,10,0,55,9,11,6,56,83,12,2,5,41,10,0,55,3,11,6,56,83,12,2,11,2,16,4,10,5,56,29,20,56,31,12,4,13,3,10,4,16,18,20,10,4,16,8,20,10,4,16,5,20,10,4,16,19,20,10,4,16,7,20,11,4,16,6,20,18,4,68,28,10,8,11,5,56,29,20,56,84,12,5,5,13,11,8,1,11,0,1,11,5,1,11,3,2,24,1,0,0,105,20,11,1,56,12,12,6,10,0,55,0,10,6,56,85,12,3,12,2,11,0,55,1,11,6,56,86,12,5,12,4,11,2,11,3,11,4,11,5,2,25,1,0,0,35,13,10,0,55,9,56,48,1,12,2,11,0,55,3,56,26,1,12,1,11,2,11,1,2,26,1,0,0,106,86,10,0,55,9,56,26,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,9,56,48,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,9,11,1,56,87,12,1,10,0,55,9,11,2,56,87,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,9,10,1,10,3,17,63,56,88,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,9,11,1,56,45,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,27,1,0,0,106,86,10,0,55,3,56,26,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,3,56,48,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,3,11,1,56,87,12,1,10,0,55,3,11,2,56,87,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,3,10,1,10,3,17,63,56,88,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,3,11,1,56,45,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,28,0,0,0,107,49,11,0,11,1,56,83,16,4,12,6,6,0,0,0,0,0,0,0,0,12,3,10,6,56,28,12,5,10,5,56,40,32,4,43,5,15,10,6,10,5,56,29,20,56,31,12,4,10,4,16,6,20,10,2,36,4,34,11,3,11,4,16,5,20,22,12,3,5,36,11,4,1,10,6,11,5,56,29,20,56,39,12,5,5,10,11,6,1,11,5,1,11,3,2,29,1,0,0,108,52,11,2,56,12,12,5,10,0,55,8,10,5,56,63,4,9,5,13,11,0,1,7,12,39,10,0,55,8,11,5,56,81,12,6,10,6,10,1,56,74,4,23,5,29,11,6,1,11,0,1,7,3,39,11,6,10,1,56,75,20,12,4,10,1,7,27,35,4,42,11,0,55,9,12,3,5,45,11,0,55,3,12,3,11,3,11,4,56,83,16,4,11,1,56,31,2,6,10,6,11,6,0,6,2,5,1,4,2,4,5,4,4,4,1,6,6,6,9,6,7,6,14,6,5,6,1,6,3,6,4,6,8,4,0,4,3,0,56,1,56,2,56,3,56,9,56,10,56,11,56,12,56,13,56,14,56,15,56,16,56,17,56,0],"clob_v2":[161,28,235,11,6,0,0,0,13,1,0,40,2,40,146,1,3,186,1,246,4,4,176,6,202,1,5,250,7,210,12,7,204,20,130,17,8,206,37,96,6,174,38,157,2,10,203,40,131,2,11,206,42,20,12,226,42,169,51,13,139,94,46,14,185,94,26,0,50,0,59,0,60,0,102,1,115,1,150,1,1,158,1,2,31,2,51,2,52,2,70,2,91,2,113,2,138,1,2,141,1,2,148,1,2,149,1,0,17,7,0,0,15,7,2,0,1,0,1,0,13,7,2,0,1,0,1,0,2,7,2,0,1,0,1,0,1,7,2,0,1,0,1,0,14,7,2,0,1,0,1,0,8,7,1,0,1,0,24,7,1,0,1,0,12,6,0,0,20,4,0,0,16,8,2,0,1,0,1,1,6,4,1,4,0,2,0,12,0,2,7,12,1,0,1,4,11,7,1,0,0,5,22,7,0,7,3,4,1,0,1,8,4,8,0,9,5,12,1,0,1,11,10,12,2,7,0,4,1,12,9,7,0,12,23,4,0,13,18,2,0,14,19,12,2,7,1,4,1,16,21,2,0,0,66,0,1,0,0,54,2,3,0,0,57,4,1,2,0,0,0,56,5,1,2,0,0,0,55,6,1,2,0,0,0,63,7,1,2,0,0,0,64,8,1,2,0,0,0,160,1,9,10,2,0,0,0,161,1,9,11,2,0,0,0,139,1,12,13,2,0,0,0,140,1,14,13,2,0,0,0,101,15,16,2,0,0,0,100,15,16,2,0,0,0,99,17,16,2,0,0,0,122,18,19,2,0,0,0,84,20,21,2,0,0,0,121,22,23,2,0,0,0,117,21,24,0,0,68,25,1,2,0,0,0,69,26,1,2,0,0,0,47,27,1,2,0,0,0,133,1,28,29,2,0,0,0,46,30,1,2,0,0,0,39,31,1,2,0,0,0,48,32,1,2,0,0,0,92,33,34,2,0,0,0,26,33,35,2,0,0,0,80,36,37,2,0,0,0,79,38,39,2,0,0,0,78,38,39,2,0,0,0,77,40,21,2,0,0,0,81,41,42,2,0,0,1,42,94,84,1,4,1,43,94,84,1,4,1,45,80,81,1,4,1,72,94,21,1,4,1,73,94,88,1,4,1,85,104,21,1,4,1,88,78,24,1,4,1,103,78,50,1,4,1,104,78,50,1,4,1,107,2,54,1,4,1,111,94,50,1,4,1,124,94,50,1,4,1,132,1,80,47,1,4,2,25,110,21,1,0,2,26,110,50,1,0,2,27,64,65,0,2,61,103,58,1,0,2,62,87,58,1,0,2,83,66,1,1,0,2,93,103,1,1,0,2,105,2,3,0,2,107,2,57,1,0,2,152,1,87,1,1,0,2,159,1,70,10,1,0,3,106,50,21,0,3,153,1,50,21,0,3,154,1,50,21,0,3,155,1,50,88,0,4,41,83,84,1,0,4,89,83,24,1,0,4,112,1,123,1,0,4,136,1,47,123,1,0,5,76,1,48,1,0,6,88,95,24,1,0,7,90,90,21,1,0,7,137,1,89,58,1,0,7,157,1,75,21,1,0,7,162,1,1,58,1,0,8,147,1,74,21,0,9,74,76,10,1,0,9,86,10,58,1,0,9,90,100,1,1,0,9,137,1,101,10,1,0,9,157,1,63,21,1,0,10,67,47,1,1,3,11,30,82,83,2,7,4,11,41,85,86,2,7,4,11,44,93,92,2,7,4,11,53,85,24,2,7,4,11,65,45,1,2,7,4,11,75,82,83,2,7,4,11,88,82,24,2,7,4,11,107,2,45,2,7,4,11,108,85,83,2,7,4,11,126,105,1,2,7,4,11,131,1,93,49,2,7,4,12,107,2,51,0,12,151,1,52,53,0,14,28,108,1,2,7,4,14,41,107,86,2,7,4,14,44,91,92,2,7,4,14,53,107,24,2,7,4,14,107,2,56,2,7,4,15,135,1,47,1,1,8,81,44,64,47,64,49,41,0,94,55,53,47,53,49,69,47,69,49,95,60,76,61,75,62,4,59,72,62,2,59,75,47,72,47,50,47,76,67,75,49,72,49,50,49,76,68,76,69,55,47,76,71,55,49,14,59,11,59,68,47,71,47,71,49,38,0,40,0,34,0,82,44,60,21,83,44,78,44,54,47,18,59,49,47,67,49,66,49,66,47,19,59,85,44,61,21,92,55,87,50,87,44,79,44,42,0,44,0,36,0,65,79,76,96,39,0,54,49,49,49,67,47,43,0,12,59,73,47,74,47,13,59,73,49,51,49,51,47,84,44,37,0,86,44,76,106,93,55,84,50,90,55,86,50,45,49,48,49,68,49,48,47,15,59,76,112,76,114,80,50,78,50,21,59,32,0,80,44,83,50,77,50,91,55,82,50,33,0,85,50,46,47,46,49,63,21,62,21,35,0,30,59,1,8,9,0,1,7,8,24,1,8,12,6,3,3,3,3,11,16,1,8,22,7,8,24,4,3,3,11,18,1,8,22,7,8,24,6,3,3,3,3,11,18,1,8,22,7,8,24,3,7,11,10,2,9,0,9,1,11,18,1,9,0,6,8,12,3,7,11,10,2,9,0,9,1,11,18,1,9,1,6,8,12,4,7,11,10,2,9,0,9,1,3,6,8,12,7,8,24,1,11,18,1,9,0,1,11,18,1,9,1,8,7,11,10,2,9,0,9,1,3,6,8,12,3,11,18,1,9,0,11,18,1,9,1,6,8,17,7,8,24,3,11,18,1,9,0,11,18,1,9,1,3,7,7,11,10,2,9,0,9,1,3,6,8,12,3,6,8,17,11,18,1,9,1,7,8,24,7,7,11,10,2,9,0,9,1,6,8,12,3,3,3,3,11,16,1,9,1,2,11,16,1,9,0,11,16,1,9,1,6,7,11,10,2,9,0,9,1,6,8,12,3,3,3,11,16,1,9,0,9,7,11,10,2,9,0,9,1,6,8,12,3,3,1,11,18,1,9,0,11,18,1,9,1,6,8,17,7,8,24,2,11,18,1,9,0,11,18,1,9,1,10,7,11,10,2,9,0,9,1,3,3,3,3,1,2,3,6,8,12,7,8,24,1,3,11,7,11,10,2,9,0,9,1,3,3,3,2,1,3,2,6,8,17,6,8,12,7,8,24,4,3,3,1,3,1,1,2,8,20,6,8,8,7,8,20,3,5,6,8,8,3,3,3,3,7,11,10,2,9,0,9,1,3,6,8,12,5,7,11,11,1,8,9,7,11,19,2,3,3,3,3,5,1,8,8,2,7,11,10,2,9,0,9,1,6,8,12,3,7,11,10,2,9,0,9,1,10,3,6,8,12,4,7,11,10,2,9,0,9,1,6,8,17,10,3,10,5,2,6,11,10,2,9,0,9,1,6,8,12,1,10,8,8,4,3,3,3,3,1,6,11,10,2,9,0,9,1,2,11,14,1,3,11,14,1,3,4,6,11,10,2,9,0,9,1,3,3,6,8,17,2,10,3,10,3,3,6,11,11,1,8,9,3,3,3,6,11,10,2,9,0,9,1,3,6,8,12,1,6,8,8,1,11,19,2,3,8,8,2,3,8,8,1,11,19,2,9,0,9,1,4,8,15,8,20,8,21,8,15,1,9,0,1,8,15,1,9,1,2,3,3,1,8,21,1,6,8,21,1,6,8,20,1,11,11,1,9,0,2,5,11,19,2,3,3,1,11,23,2,9,0,9,1,1,11,13,1,9,0,1,11,16,1,9,0,2,9,0,9,1,1,11,10,2,9,0,9,1,1,8,0,1,8,22,1,6,11,18,1,9,0,1,6,8,12,1,5,3,7,11,13,1,9,0,5,11,16,1,9,0,1,11,6,1,9,0,1,11,6,1,9,1,1,11,7,1,9,0,4,7,11,13,1,9,0,3,6,8,12,7,8,24,1,11,7,1,9,1,4,3,11,18,1,9,0,11,18,1,9,1,3,3,11,16,1,9,0,11,16,1,9,1,3,1,6,8,17,1,6,11,16,1,9,0,2,11,16,1,9,0,7,8,24,40,1,1,3,3,1,3,3,1,5,3,3,3,7,11,11,1,8,9,11,16,1,9,0,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,3,3,11,16,1,9,0,3,6,8,8,7,8,8,3,3,3,6,11,14,1,3,3,3,8,20,11,16,1,9,1,11,16,1,9,1,1,3,3,3,1,3,7,8,9,3,1,6,11,11,1,9,0,1,11,3,2,9,0,9,1,2,7,11,11,1,9,0,3,1,7,9,0,1,6,11,19,2,9,0,9,1,1,6,11,14,1,9,0,1,6,9,0,2,6,11,19,2,9,0,9,1,9,0,1,6,9,1,3,7,11,13,1,9,0,5,3,2,1,3,2,7,11,16,1,9,0,3,2,7,11,16,1,9,0,11,16,1,9,0,2,7,11,23,2,9,0,9,1,9,0,1,7,9,1,2,7,11,19,2,9,0,9,1,9,0,2,6,11,11,1,9,0,3,1,6,10,9,0,1,11,4,2,9,0,9,1,36,1,3,1,3,3,1,3,3,1,5,3,3,3,7,11,11,1,8,9,11,16,1,9,0,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,3,11,16,1,9,0,3,6,8,8,7,8,8,3,6,11,14,1,3,3,3,8,20,11,16,1,9,1,1,3,3,11,16,1,9,1,3,7,8,9,3,37,1,3,1,3,3,1,3,3,1,5,3,3,3,7,11,11,1,8,9,11,16,1,9,0,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,3,11,16,1,9,1,3,6,8,8,7,8,8,3,3,6,11,14,1,3,3,3,8,20,11,16,1,9,1,1,3,3,11,16,1,9,1,3,7,8,9,3,5,11,16,1,9,0,11,16,1,9,0,11,18,1,9,0,11,16,1,9,1,11,16,1,9,1,2,7,11,18,1,9,0,11,18,1,9,0,3,7,11,18,1,9,0,3,7,8,24,7,3,7,11,11,1,8,9,8,8,3,5,3,3,3,7,11,13,1,9,0,6,8,12,3,3,7,11,11,1,9,0,3,9,0,3,7,11,19,2,9,0,9,1,9,0,9,1,1,11,1,2,9,0,9,1,2,6,11,23,2,9,0,9,1,9,0,3,7,11,23,2,9,0,9,1,9,0,9,1,12,11,16,1,9,0,11,16,1,9,0,11,16,1,9,0,3,3,3,5,11,16,1,9,1,11,16,1,9,1,11,16,1,9,1,3,3,2,6,11,13,1,9,0,5,8,8,20,3,3,1,5,3,3,3,1,11,2,2,9,0,9,1,13,8,20,3,3,3,3,3,3,5,3,1,5,3,3,1,11,5,2,9,0,9,1,11,3,3,6,11,11,1,8,9,7,11,11,1,8,9,3,1,8,8,5,3,3,7,11,19,2,3,3,3,3,7,8,9,8,8,22,3,3,3,3,7,11,11,1,8,9,3,3,3,1,5,3,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,1,7,11,11,1,8,9,8,8,3,3,5,8,20,3,7,11,19,2,3,3,26,5,3,3,3,3,3,6,11,11,1,8,9,7,11,11,1,8,9,3,3,1,3,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,1,3,3,3,8,8,3,5,8,20,3,3,7,11,19,2,3,3,28,1,5,3,3,3,3,3,7,11,11,1,8,9,3,3,3,3,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,1,3,3,3,3,7,11,11,1,8,9,8,8,3,5,8,20,3,3,7,11,19,2,3,3,7,6,8,9,10,8,8,6,8,8,6,11,14,1,3,3,5,6,11,19,2,3,3,5,3,3,5,3,3,4,11,14,1,3,11,14,1,3,11,14,1,3,11,14,1,3,1,11,14,1,9,0,6,3,10,3,3,3,3,10,3,4,3,6,8,8,6,11,14,1,3,6,11,19,2,3,8,8,4,6,11,11,1,8,9,3,5,6,11,19,2,3,3,10,65,99,99,111,117,110,116,67,97,112,17,65,108,108,79,114,100,101,114,115,67,97,110,99,101,108,101,100,26,65,108,108,79,114,100,101,114,115,67,97,110,99,101,108,101,100,67,111,109,112,111,110,101,110,116,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,11,67,114,105,116,98,105,116,84,114,101,101,9,67,117,115,116,111,100,105,97,110,12,68,101,112,111,115,105,116,65,115,115,101,116,2,73,68,11,76,105,110,107,101,100,84,97,98,108,101,6,79,112,116,105,111,110,5,79,114,100,101,114,13,79,114,100,101,114,67,97,110,99,101,108,101,100,11,79,114,100,101,114,70,105,108,108,101,100,11,79,114,100,101,114,80,108,97,99,101,100,4,80,111,111,108,11,80,111,111,108,67,114,101,97,116,101,100,3,83,85,73,5,84,97,98,108,101,9,84,105,99,107,76,101,118,101,108,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,13,87,105,116,104,100,114,97,119,65,115,115,101,116,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,13,97,99,99,111,117,110,116,95,111,119,110,101,114,3,97,100,100,4,97,115,107,115,4,98,97,99,107,7,98,97,108,97,110,99,101,10,98,97,115,101,95,97,115,115,101,116,28,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,99,97,110,99,101,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,102,105,108,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,112,108,97,99,101,100,29,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,114,101,109,97,105,110,105,110,103,23,98,97,115,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,14,98,97,115,101,95,99,117,115,116,111,100,105,97,110,18,98,97,116,99,104,95,99,97,110,99,101,108,95,111,114,100,101,114,4,98,105,100,115,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,17,99,97,110,99,101,108,95,97,108,108,95,111,114,100,101,114,115,12,99,97,110,99,101,108,95,111,114,100,101,114,23,99,108,101,97,110,95,117,112,95,101,120,112,105,114,101,100,95,111,114,100,101,114,115,15,99,108,105,101,110,116,95,111,114,100,101,114,95,105,100,7,99,108,111,98,95,118,50,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,14,99,114,101,97,116,101,95,97,99,99,111,117,110,116,22,99,114,101,97,116,101,95,99,117,115,116,111,109,105,122,101,100,95,112,111,111,108,11,99,114,101,97,116,101,95,112,111,111,108,12,99,114,101,97,116,101,95,112,111,111,108,95,12,99,114,101,97,116,105,111,110,95,102,101,101,7,99,114,105,116,98,105,116,12,99,117,115,116,111,100,105,97,110,95,118,50,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,100,101,112,111,115,105,116,95,98,97,115,101,13,100,101,112,111,115,105,116,95,113,117,111,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,19,100,101,115,116,114,111,121,95,101,109,112,116,121,95,108,101,118,101,108,4,101,109,105,116,19,101,109,105,116,95,111,114,100,101,114,95,99,97,110,99,101,108,101,100,17,101,109,105,116,95,111,114,100,101,114,95,102,105,108,108,101,100,5,101,118,101,110,116,16,101,120,112,105,114,101,95,116,105,109,101,115,116,97,109,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,12,102,114,111,109,95,98,97,108,97,110,99,101,5,102,114,111,110,116,3,103,101,116,22,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,97,115,107,95,115,105,100,101,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,98,105,100,95,115,105,100,101,16,103,101,116,95,109,97,114,107,101,116,95,112,114,105,99,101,16,103,101,116,95,111,114,100,101,114,95,115,116,97,116,117,115,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,18,105,110,106,101,99,116,95,108,105,109,105,116,95,111,114,100,101,114,11,105,110,115,101,114,116,95,108,101,97,102,12,105,110,116,111,95,98,97,108,97,110,99,101,6,105,115,95,98,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,4,106,111,105,110,12,108,105,110,107,101,100,95,116,97,98,108,101,16,108,105,115,116,95,111,112,101,110,95,111,114,100,101,114,115,12,108,111,99,107,95,98,97,108,97,110,99,101,8,108,111,116,95,115,105,122,101,13,109,97,107,101,114,95,97,100,100,114,101,115,115,21,109,97,107,101,114,95,99,108,105,101,110,116,95,111,114,100,101,114,95,105,100,17,109,97,107,101,114,95,114,101,98,97,116,101,95,114,97,116,101,13,109,97,107,101,114,95,114,101,98,97,116,101,115,9,109,97,116,99,104,95,97,115,107,9,109,97,116,99,104,95,98,105,100,29,109,97,116,99,104,95,98,105,100,95,119,105,116,104,95,113,117,111,116,101,95,113,117,97,110,116,105,116,121,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,109,117,108,3,110,101,119,4,110,101,120,116,17,110,101,120,116,95,97,115,107,95,111,114,100,101,114,95,105,100,17,110,101,120,116,95,98,105,100,95,111,114,100,101,114,95,105,100,9,110,101,120,116,95,108,101,97,102,4,110,111,110,101,6,111,98,106,101,99,116,11,111,112,101,110,95,111,114,100,101,114,115,6,111,112,116,105,111,110,8,111,114,100,101,114,95,105,100,12,111,114,100,101,114,95,105,115,95,98,105,100,15,111,114,100,101,114,115,95,99,97,110,99,101,108,101,100,17,111,114,105,103,105,110,97,108,95,113,117,97,110,116,105,116,121,5,111,119,110,101,114,17,112,108,97,99,101,95,108,105,109,105,116,95,111,114,100,101,114,18,112,108,97,99,101,95,109,97,114,107,101,116,95,111,114,100,101,114,7,112,111,111,108,95,105,100,13,112,114,101,118,105,111,117,115,95,108,101,97,102,5,112,114,105,99,101,9,112,117,115,104,95,98,97,99,107,8,113,117,97,110,116,105,116,121,11,113,117,111,116,101,95,97,115,115,101,116,24,113,117,111,116,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,15,113,117,111,116,101,95,99,117,115,116,111,100,105,97,110,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,12,114,101,109,111,118,101,95,111,114,100,101,114,24,115,101,108,102,95,109,97,116,99,104,105,110,103,95,112,114,101,118,101,110,116,105,111,110,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,115,112,108,105,116,3,115,117,105,25,115,119,97,112,95,101,120,97,99,116,95,98,97,115,101,95,102,111,114,95,113,117,111,116,101,25,115,119,97,112,95,101,120,97,99,116,95,113,117,111,116,101,95,102,111,114,95,98,97,115,101,5,116,97,98,108,101,13,116,97,107,101,114,95,97,100,100,114,101,115,115,21,116,97,107,101,114,95,99,108,105,101,110,116,95,111,114,100,101,114,95,105,100,16,116,97,107,101,114,95,99,111,109,109,105,115,115,105,111,110,14,116,97,107,101,114,95,102,101,101,95,114,97,116,101,9,116,105,99,107,95,115,105,122,101,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,10,117,110,115,97,102,101,95,100,105,118,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,15,117,115,114,95,111,112,101,110,95,111,114,100,101,114,115,5,118,97,108,117,101,6,118,101,99,116,111,114,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,13,119,105,116,104,100,114,97,119,95,98,97,115,101,14,119,105,116,104,100,114,97,119,95,113,117,111,116,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,3,8,19,0,0,0,0,0,0,0,3,8,20,0,0,0,0,0,0,0,3,8,21,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,2,1,0,2,1,4,2,1,1,2,1,2,2,1,3,3,8,0,0,0,0,0,0,0,128,3,8,0,0,0,0,0,0,0,0,3,8,160,37,38,0,0,0,0,0,3,8,96,227,22,0,0,0,0,0,3,8,0,232,118,72,23,0,0,0,0,2,7,123,8,20,32,8,15,128,1,8,15,145,1,3,97,3,146,1,3,94,3,1,2,9,123,8,20,116,3,49,3,87,1,120,5,119,3,35,3,125,3,71,3,2,2,8,123,8,20,116,3,49,3,87,1,120,5,119,3,33,3,125,3,3,2,7,116,3,49,3,87,1,120,5,119,3,33,3,125,3,4,2,2,123,8,20,118,10,11,3,2,9,0,9,1,5,2,13,123,8,20,116,3,143,1,3,96,3,87,1,142,1,5,95,5,119,3,34,3,36,3,125,3,144,1,3,98,3,6,2,3,123,8,20,127,3,120,5,7,2,3,123,8,20,127,3,120,5,8,2,9,116,3,49,3,125,3,119,3,127,3,87,1,120,5,71,3,134,1,2,9,2,2,125,3,114,11,19,2,3,8,8,10,2,15,82,8,21,40,11,11,1,8,9,29,11,11,1,8,9,110,3,109,3,156,1,11,23,2,5,11,19,2,3,3,145,1,3,97,3,146,1,3,94,3,38,11,13,1,9,0,130,1,11,13,1,9,1,58,11,16,1,8,22,37,11,16,1,9,0,129,1,11,16,1,9,1,10,59,6,47,6,49,7,47,7,49,3,59,4,59,1,59,2,59,5,59,0,0,0,0,43,7,11,0,19,9,12,1,1,11,1,56,0,2,1,1,0,0,1,3,11,0,17,52,2,2,0,0,0,46,72,56,1,12,6,56,2,12,9,10,3,10,2,17,58,6,0,0,0,0,0,0,0,0,36,4,11,5,15,11,5,1,7,19,39,10,6,10,9,34,4,20,5,24,11,5,1,7,15,39,10,0,10,1,38,4,29,5,33,11,5,1,7,1,39,10,5,17,88,12,8,14,8,17,89,20,12,7,11,8,10,5,56,3,10,5,56,3,7,0,7,27,10,5,56,4,10,0,10,1,10,2,10,3,10,5,56,5,11,5,56,6,11,4,56,7,56,8,57,0,56,9,11,7,11,6,11,9,11,0,11,1,11,2,11,3,18,0,56,10,2,3,1,0,0,1,18,14,2,56,11,7,31,33,4,6,5,10,11,3,1,7,17,39,11,0,11,1,7,29,7,30,11,2,11,3,56,12,2,4,1,0,0,1,19,14,4,56,11,7,31,33,4,6,5,10,11,5,1,7,17,39,11,2,11,3,11,0,11,1,11,4,56,13,11,5,56,14,2,5,1,0,0,21,31,14,1,56,15,12,3,10,3,6,0,0,0,0,0,0,0,0,34,4,8,5,14,11,0,1,11,2,1,7,6,39,10,0,54,0,10,2,17,47,11,1,56,16,56,17,11,0,55,1,17,89,20,11,3,11,2,17,47,57,1,56,18,2,6,1,0,0,21,31,14,1,56,19,12,3,10,3,6,0,0,0,0,0,0,0,0,34,4,8,5,14,11,0,1,11,2,1,7,7,39,10,0,54,2,10,2,17,47,11,1,56,20,56,21,11,0,55,1,17,89,20,11,3,11,2,17,47,57,2,56,22,2,7,1,0,0,1,29,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,10,0,55,1,17,89,20,10,1,10,2,17,47,57,3,56,23,11,0,54,0,11,1,11,2,11,3,56,24,2,8,1,0,0,1,29,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,10,0,55,1,17,89,20,10,1,10,2,17,47,57,4,56,25,11,0,54,2,11,1,11,2,11,3,56,26,2,9,1,0,0,72,55,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,7,1,11,6,1,11,2,1,7,5,39,14,4,56,15,10,3,38,4,21,5,31,11,0,1,11,7,1,11,6,1,11,2,1,7,6,39,14,5,56,19,12,8,11,0,11,2,11,1,11,3,9,11,4,11,5,11,6,11,7,56,27,12,10,12,9,14,10,56,19,12,11,11,9,11,10,11,11,11,8,23,2,10,1,0,0,73,54,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,6,1,11,4,1,11,2,1,7,5,39,14,5,56,19,10,3,38,4,21,5,31,11,0,1,11,6,1,11,4,1,11,2,1,7,7,39,11,0,11,2,11,1,11,3,7,27,11,4,17,70,11,5,56,20,56,28,12,8,12,7,14,7,56,29,12,9,11,7,10,6,56,30,11,8,11,6,56,31,11,9,2,11,0,0,0,77,134,3,10,0,55,1,17,89,20,12,36,11,3,12,42,56,7,12,20,11,6,12,38,10,0,54,3,12,19,10,19,46,56,32,4,27,11,0,1,11,19,1,11,1,1,11,20,11,38,2,10,19,46,56,33,12,44,12,46,9,12,43,64,79,0,0,0,0,0,0,0,0,12,22,10,19,46,56,32,32,4,47,5,42,10,46,10,4,37,12,7,5,49,9,12,7,11,7,4,251,2,10,19,10,44,56,34,12,45,10,45,16,4,56,35,56,36,20,12,35,10,45,16,4,56,37,32,4,217,2,5,67,10,45,16,4,10,35,56,38,12,28,10,28,16,5,20,12,27,9,12,39,10,28,16,6,20,10,5,37,4,87,8,12,11,5,94,10,1,17,47,10,28,16,7,20,33,12,11,11,11,4,151,1,8,12,39,10,0,54,0,10,28,16,7,20,10,28,16,5,20,56,39,10,36,10,28,56,40,10,28,16,8,20,12,12,10,28,16,9,20,12,13,10,28,16,10,20,12,14,10,28,16,7,20,12,15,10,28,16,11,20,12,16,10,28,16,5,20,12,17,10,28,16,12,20,12,18,11,13,11,12,11,14,11,15,11,16,11,17,11,18,57,5,12,21,13,22,11,21,68,79,5,158,2,10,27,10,28,16,12,20,17,56,12,31,10,31,10,0,55,4,20,17,59,12,40,4,168,1,11,40,6,1,0,0,0,0,0,0,0,22,12,40,10,31,11,40,22,12,30,10,42,10,30,36,4,183,1,11,30,12,24,11,31,12,25,10,27,12,23,5,226,1,8,12,43,10,42,7,21,10,0,55,4,20,22,17,57,10,28,16,12,20,17,57,10,0,55,5,20,26,10,0,55,5,20,24,12,23,10,23,10,28,16,12,20,17,58,12,25,10,25,10,0,55,4,20,17,59,12,41,4,222,1,11,41,6,1,0,0,0,0,0,0,0,22,12,41,10,25,11,41,22,12,24,10,25,10,0,55,6,20,17,58,12,32,11,27,10,23,23,12,27,11,42,10,24,23,12,42,10,0,54,0,10,28,16,7,20,10,23,56,41,12,26,13,38,10,24,56,42,12,37,10,0,54,2,10,28,16,7,20,13,37,10,32,10,25,22,56,42,56,21,10,0,54,7,11,37,56,43,1,13,20,11,26,56,44,1,10,0,55,1,17,89,20,10,2,10,1,17,47,10,28,11,23,11,24,11,25,23,11,32,56,45,11,39,4,163,2,8,12,8,5,167,2,10,27,6,0,0,0,0,0,0,0,0,33,12,8,11,8,4,202,2,10,35,12,34,10,45,16,4,10,35,56,46,12,33,10,33,56,47,32,4,185,2,11,33,56,36,20,12,35,5,187,2,11,33,1,10,0,54,8,11,28,16,7,20,56,48,10,34,56,49,1,10,45,15,4,11,34,56,50,1,5,213,2,11,28,1,10,45,15,4,10,35,56,51,12,29,11,27,11,29,15,5,21,10,43,4,216,2,5,217,2,5,61,11,45,16,4,56,37,4,241,2,10,19,11,46,12,9,46,11,9,56,52,1,12,46,10,19,11,44,56,53,17,0,10,19,10,46,12,10,46,11,10,56,54,12,44,1,10,43,4,250,2,11,0,1,11,19,1,11,1,1,5,251,2,5,36,14,22,56,55,32,4,131,3,11,36,11,22,57,6,56,56,11,20,11,38,2,12,0,0,0,97,222,2,10,0,55,1,17,89,20,12,34,11,3,12,37,56,7,12,21,11,6,12,35,10,0,54,3,12,20,10,20,46,56,32,4,27,11,0,1,11,20,1,11,1,1,11,21,11,35,2,10,20,46,56,33,12,40,12,42,64,79,0,0,0,0,0,0,0,0,12,23,10,20,46,56,32,32,4,45,5,40,10,42,10,4,37,12,7,5,47,9,12,7,11,7,4,211,2,10,20,10,40,56,34,12,41,10,41,16,4,56,35,56,36,20,12,33,10,41,16,4,56,37,32,4,175,2,5,65,10,41,16,4,10,33,56,38,12,28,10,28,16,5,20,12,27,9,12,36,10,28,16,6,20,10,5,37,4,85,8,12,12,5,92,10,1,17,47,10,28,16,7,20,33,12,12,11,12,4,149,1,8,12,36,10,0,54,0,10,28,16,7,20,10,28,16,5,20,56,39,10,34,10,28,56,40,10,28,16,8,20,12,13,10,28,16,9,20,12,14,10,28,16,10,20,12,15,10,28,16,7,20,12,16,10,28,16,11,20,12,17,10,28,16,5,20,12,18,10,28,16,12,20,12,19,11,14,11,13,11,15,11,16,11,17,11,18,11,19,57,5,12,22,13,23,11,22,68,79,5,242,1,10,37,10,27,36,4,156,1,10,27,12,8,5,158,1,10,37,12,8,11,8,12,24,10,24,10,28,16,12,20,17,56,12,25,10,25,10,0,55,6,20,17,58,12,30,10,25,10,0,55,4,20,17,59,12,38,4,183,1,11,38,6,1,0,0,0,0,0,0,0,22,12,38,11,27,10,24,23,12,27,11,37,10,24,23,12,37,10,0,54,0,10,28,16,7,20,10,24,56,41,12,26,13,35,10,38,56,42,12,39,10,0,54,2,10,28,16,7,20,13,39,10,30,56,42,56,21,10,0,54,7,11,39,56,43,1,13,21,11,26,56,44,1,10,0,54,2,10,28,16,7,20,13,35,11,25,56,42,56,21,10,0,55,1,17,89,20,10,2,10,1,17,47,10,28,11,24,11,38,11,30,56,45,11,36,4,247,1,8,12,9,5,251,1,10,27,6,0,0,0,0,0,0,0,0,33,12,9,11,9,4,158,2,10,33,12,32,10,41,16,4,10,33,56,46,12,31,10,31,56,47,32,4,141,2,11,31,56,36,20,12,33,5,143,2,11,31,1,10,0,54,8,11,28,16,7,20,56,48,10,32,56,49,1,10,41,15,4,11,32,56,50,1,5,169,2,11,28,1,10,41,15,4,10,33,56,51,12,29,11,27,11,29,15,5,21,10,37,6,0,0,0,0,0,0,0,0,33,4,174,2,5,175,2,5,59,11,41,16,4,56,37,4,199,2,10,20,11,42,12,10,46,11,10,56,52,1,12,42,10,20,11,40,56,53,17,0,10,20,10,42,12,11,46,11,11,56,54,12,40,1,10,37,6,0,0,0,0,0,0,0,0,33,4,210,2,11,0,1,11,20,1,11,1,1,5,211,2,5,34,14,23,56,55,32,4,219,2,11,34,11,23,57,6,56,56,11,21,11,35,2,13,0,0,0,98,227,2,10,0,55,1,17,89,20,12,34,11,5,12,20,56,8,12,35,10,0,54,9,12,19,10,19,46,56,32,4,25,11,0,1,11,19,1,11,1,1,11,20,11,35,2,10,19,46,56,57,12,40,12,42,64,79,0,0,0,0,0,0,0,0,12,22,10,19,46,56,32,32,4,43,5,38,10,42,10,3,38,12,6,5,45,9,12,6,11,6,4,216,2,10,19,10,40,56,34,12,41,10,41,16,4,56,35,56,36,20,12,33,10,41,16,4,56,37,32,4,179,2,5,63,10,41,16,4,10,33,56,38,12,27,10,27,16,5,20,12,26,9,12,36,10,27,16,6,20,10,4,37,4,83,8,12,11,5,90,10,1,17,47,10,27,16,7,20,33,12,11,11,11,4,153,1,8,12,36,10,27,16,5,20,10,27,16,12,20,17,56,12,29,10,0,54,2,10,27,16,7,20,11,29,56,58,10,34,10,27,56,40,10,27,16,8,20,12,12,10,27,16,9,20,12,13,10,27,16,10,20,12,14,10,27,16,7,20,12,15,10,27,16,11,20,12,16,10,27,16,5,20,12,17,10,27,16,12,20,12,18,11,13,11,12,11,14,11,15,11,16,11,17,11,18,57,5,12,21,13,22,11,21,68,79,5,245,1,14,20,56,29,12,37,10,37,10,26,38,4,163,1,10,26,12,7,5,165,1,11,37,12,7,11,7,12,23,10,23,10,27,16,12,20,17,56,12,24,10,24,10,0,55,6,20,17,58,12,30,10,24,10,0,55,4,20,17,59,12,38,4,190,1,11,38,6,1,0,0,0,0,0,0,0,22,12,38,11,26,10,23,23,12,26,10,0,54,2,10,27,16,7,20,11,24,56,59,12,25,13,25,10,38,56,42,12,39,10,0,54,2,10,27,16,7,20,13,39,10,30,56,42,56,21,10,0,54,7,11,39,56,43,1,13,35,11,25,56,43,1,10,0,54,0,10,27,16,7,20,13,20,10,23,56,60,56,17,10,0,55,1,17,89,20,10,2,10,1,17,47,10,27,11,23,11,38,11,30,56,45,11,36,4,250,1,8,12,8,5,254,1,10,26,6,0,0,0,0,0,0,0,0,33,12,8,11,8,4,161,2,10,33,12,32,10,41,16,4,10,33,56,46,12,31,10,31,56,47,32,4,144,2,11,31,56,36,20,12,33,5,146,2,11,31,1,10,0,54,8,11,27,16,7,20,56,48,10,32,56,49,1,10,41,15,4,11,32,56,50,1,5,172,2,11,27,1,10,41,15,4,10,33,56,51,12,28,11,26,11,28,15,5,21,14,20,56,29,6,0,0,0,0,0,0,0,0,33,4,178,2,5,179,2,5,57,11,41,16,4,56,37,4,203,2,10,19,11,42,12,9,46,11,9,56,61,1,12,42,10,19,11,40,56,53,17,0,10,19,10,42,12,10,46,11,10,56,54,12,40,1,14,20,56,29,6,0,0,0,0,0,0,0,0,33,4,215,2,11,0,1,11,19,1,11,1,1,5,216,2,5,32,14,22,56,55,32,4,224,2,11,34,11,22,57,6,56,56,11,20,11,35,2,14,1,0,0,99,103,10,3,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,9,5,19,11,0,1,11,8,1,11,7,1,11,1,1,7,5,39,10,3,6,0,0,0,0,0,0,0,0,34,4,24,5,34,11,0,1,11,8,1,11,7,1,11,1,1,7,5,39,11,4,4,58,11,0,11,1,11,2,11,3,7,27,11,7,17,70,11,6,56,20,56,62,12,13,12,9,13,5,11,9,10,8,56,30,56,63,11,13,11,8,56,31,12,6,5,100,10,3,14,5,56,15,37,4,64,5,74,11,0,1,11,8,1,11,7,1,11,1,1,7,6,39,13,5,11,3,10,8,56,64,12,11,11,0,11,1,11,2,7,28,11,7,17,70,11,11,56,16,56,65,12,12,12,10,13,5,11,10,10,8,56,30,56,63,13,6,11,12,11,8,56,31,56,66,11,5,11,6,2,15,0,0,0,102,123,10,8,17,47,12,14,10,5,4,30,10,4,10,2,17,56,12,15,10,0,54,2,11,8,11,15,56,67,10,0,55,10,20,12,13,10,0,55,10,20,6,1,0,0,0,0,0,0,0,22,10,0,54,10,21,10,0,54,9,12,11,5,50,10,0,54,0,11,8,10,4,56,68,10,0,55,11,20,12,13,10,0,55,11,20,6,1,0,0,0,0,0,0,0,22,10,0,54,11,21,10,0,54,3,12,11,10,13,10,1,10,2,10,3,10,4,10,5,10,14,10,7,11,6,18,8,12,12,10,11,10,2,12,10,46,11,10,56,54,12,16,32,4,78,10,11,10,2,10,2,10,9,56,69,18,9,56,70,12,16,11,11,11,16,56,34,15,4,10,13,11,12,56,71,10,0,55,1,17,89,20,10,13,11,1,11,5,10,14,11,3,11,4,10,2,11,7,57,7,56,72,10,0,55,8,10,14,56,73,32,4,112,10,0,54,8,10,14,11,9,56,74,56,75,5,114,11,9,1,11,0,54,8,11,14,56,48,10,13,11,2,56,76,11,13,2,16,1,0,0,109,171,2,10,4,7,22,33,4,5,5,15,11,0,1,11,10,1,11,8,1,11,9,1,7,20,39,10,3,6,0,0,0,0,0,0,0,0,36,4,20,5,30,11,0,1,11,10,1,11,8,1,11,9,1,7,5,39,10,2,6,0,0,0,0,0,0,0,0,36,4,35,5,45,11,0,1,11,10,1,11,8,1,11,9,1,7,4,39,10,2,10,0,55,12,20,25,6,0,0,0,0,0,0,0,0,33,4,54,5,64,11,0,1,11,10,1,11,8,1,11,9,1,7,4,39,10,3,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,73,5,83,11,0,1,11,10,1,11,8,1,11,9,1,7,5,39,10,6,10,8,17,70,36,4,89,5,99,11,0,1,11,10,1,11,8,1,11,9,1,7,18,39,10,9,17,47,12,17,10,3,12,16,10,5,4,147,1,10,0,55,2,10,17,56,77,12,22,10,0,54,2,10,9,10,22,56,78,12,18,10,0,10,9,10,1,10,3,10,2,11,8,17,70,11,18,56,62,12,20,12,12,14,12,56,29,12,14,11,22,14,20,56,79,23,12,21,10,0,54,0,10,17,11,12,56,17,10,0,54,2,11,17,11,20,56,21,5,181,1,10,0,54,0,10,9,10,3,56,80,12,11,10,0,10,9,10,1,10,2,11,8,17,70,11,11,56,65,12,19,12,13,10,3,14,13,56,29,23,12,14,14,19,56,79,12,21,10,0,54,0,10,17,11,13,56,17,10,0,54,2,11,17,11,19,56,21,10,7,7,24,33,4,196,1,11,0,1,11,10,1,11,9,1,11,14,11,21,9,6,0,0,0,0,0,0,0,0,2,10,7,7,25,33,4,218,1,11,0,1,11,10,1,11,9,1,10,14,11,3,33,4,211,1,5,213,1,7,8,39,11,14,11,21,9,6,0,0,0,0,0,0,0,0,2,10,7,7,26,33,4,252,1,10,14,6,0,0,0,0,0,0,0,0,33,4,227,1,5,235,1,11,0,1,11,10,1,11,9,1,7,9,39,11,0,11,1,11,2,11,16,11,3,11,5,11,4,11,6,11,9,11,10,56,81,12,15,11,14,11,21,8,11,15,2,11,7,7,22,33,4,129,2,5,137,2,11,0,1,11,10,1,11,9,1,7,13,39,10,3,10,14,36,4,160,2,11,0,11,1,11,2,11,16,11,3,10,14,23,11,5,11,4,11,6,11,9,11,10,56,81,12,15,11,14,11,21,8,11,15,2,11,0,1,11,10,1,11,9,1,11,14,11,21,9,6,0,0,0,0,0,0,0,0,2,17,0,0,0,1,4,11,0,7,27,35,2,18,0,0,0,111,41,11,0,12,2,10,1,16,8,20,12,3,10,1,16,9,20,12,4,10,1,16,10,20,12,5,10,1,16,7,20,12,6,10,1,16,11,20,12,7,10,1,16,5,20,12,8,11,1,16,12,20,12,9,11,2,11,4,11,3,11,5,11,6,11,7,11,8,11,9,57,8,56,82,2,19,0,0,0,113,58,11,0,12,7,10,3,16,9,20,12,12,11,1,12,13,11,2,12,14,10,3,16,8,20,12,15,10,3,16,10,20,12,16,10,3,16,7,20,12,17,10,3,16,11,20,12,18,10,4,12,19,10,3,16,5,20,11,4,23,12,8,11,3,16,12,20,12,9,11,5,12,10,11,6,12,11,11,7,11,12,11,13,11,15,11,16,11,14,11,17,11,18,11,19,11,8,11,9,11,10,11,11,57,9,56,83,2,20,1,0,0,115,115,11,2,17,47,12,10,10,0,55,8,10,10,56,73,4,9,5,13,11,0,1,7,11,39,10,0,54,8,10,10,56,48,12,13,10,13,10,1,12,3,46,11,3,56,84,4,26,5,32,11,13,1,11,0,1,7,2,39,10,13,10,1,12,4,46,11,4,56,85,20,12,12,10,1,17,17,12,8,10,8,4,49,10,0,55,9,12,5,5,52,10,0,55,3,12,5,11,5,11,12,56,54,12,11,4,58,5,64,11,13,1,11,0,1,7,2,39,10,8,4,70,10,0,54,9,12,6,5,73,10,0,54,3,12,6,11,6,11,13,11,11,11,1,10,10,56,86,12,9,11,8,4,101,14,9,16,5,20,14,9,16,12,20,17,59,12,7,4,95,11,7,6,1,0,0,0,0,0,0,0,22,12,7,10,0,54,2,11,10,11,7,56,58,5,108,10,0,54,0,11,10,14,9,16,5,20,56,39,11,0,55,1,17,89,20,14,9,56,40,2,21,0,0,0,116,54,11,1,10,3,56,49,1,10,0,10,2,12,5,46,11,5,56,87,16,4,10,3,56,88,4,15,5,19,11,0,1,7,2,39,10,0,10,2,56,34,12,6,10,6,15,4,11,3,56,50,12,7,14,7,16,7,20,11,4,33,4,35,5,41,11,0,1,11,6,1,7,3,39,11,6,16,4,56,37,4,50,11,0,11,2,56,53,17,0,5,52,11,0,1,11,7,2,22,1,0,0,117,154,1,10,0,55,1,17,89,20,12,21,11,1,17,47,12,20,10,0,55,8,10,20,56,73,4,14,5,18,11,0,1,7,11,39,10,0,54,8,10,20,56,48,12,23,64,79,0,0,0,0,0,0,0,0,12,14,10,23,46,56,89,32,4,141,1,5,31,10,23,46,56,90,56,36,20,12,18,10,23,10,18,12,5,46,11,5,56,85,20,12,19,10,18,17,17,12,15,10,15,4,54,10,0,54,9,12,6,5,57,10,0,54,3,12,6,11,6,12,16,10,16,11,19,12,7,46,11,7,56,54,12,22,1,11,16,10,23,11,22,11,18,10,20,56,86,12,17,11,15,4,90,14,17,16,5,20,14,17,16,12,20,17,56,12,12,10,0,54,2,10,20,11,12,56,58,5,97,10,0,54,0,10,20,14,17,16,5,20,56,39,10,21,14,17,56,40,14,17,16,8,20,12,8,14,17,16,9,20,12,9,14,17,16,10,20,12,10,14,17,16,7,20,12,11,14,17,16,11,20,12,2,14,17,16,5,20,12,3,14,17,16,12,20,12,4,11,9,11,8,11,10,11,11,11,2,11,3,11,4,57,5,12,13,13,14,11,13,68,79,5,25,11,23,1,11,0,1,14,14,56,55,32,4,153,1,11,21,11,14,57,6,56,56,2,23,1,0,0,118,203,1,10,0,55,1,17,89,20,12,25,11,2,17,47,12,24,10,0,55,8,10,24,56,73,4,14,5,18,11,0,1,6,0,0,0,0,0,0,0,0,39,6,0,0,0,0,0,0,0,0,12,26,6,0,0,0,0,0,0,0,0,12,27,14,1,65,21,12,19,6,0,0,0,0,0,0,0,0,12,17,10,0,54,8,10,24,56,48,12,28,64,79,0,0,0,0,0,0,0,0,12,16,10,17,10,19,35,4,190,1,5,39,14,1,10,17,66,21,20,12,23,10,28,10,23,12,7,46,11,7,56,84,4,52,5,58,11,28,1,11,0,1,7,2,39,10,28,10,23,12,8,46,11,8,56,85,20,12,21,10,23,17,17,12,18,10,21,10,27,34,4,98,11,21,12,27,10,18,4,81,10,0,55,9,12,9,5,84,10,0,55,3,12,9,11,9,10,27,56,54,12,20,4,90,5,96,11,28,1,11,0,1,7,10,39,11,20,12,26,10,18,4,104,10,0,54,9,12,10,5,107,10,0,54,3,12,10,11,10,10,28,10,26,11,23,10,24,56,86,12,22,11,18,4,135,1,14,22,16,5,20,14,22,16,12,20,17,59,12,14,4,129,1,11,14,6,1,0,0,0,0,0,0,0,22,12,14,10,0,54,2,10,24,11,14,56,58,5,142,1,10,0,54,0,10,24,14,22,16,5,20,56,39,10,25,14,22,56,40,14,22,16,8,20,12,11,14,22,16,9,20,12,12,14,22,16,10,20,12,13,14,22,16,7,20,12,3,14,22,16,11,20,12,4,14,22,16,5,20,12,5,14,22,16,12,20,12,6,11,12,11,11,11,13,11,3,11,4,11,5,11,6,57,5,12,15,13,16,11,15,68,79,11,17,6,1,0,0,0,0,0,0,0,22,12,17,5,34,11,28,1,11,0,1,14,16,56,55,32,4,202,1,11,25,11,16,57,6,56,56,2,24,1,0,0,119,214,1,10,0,55,1,17,89,20,12,28,11,1,17,70,12,23,14,2,65,21,12,20,10,20,14,3,65,65,33,4,17,5,21,11,0,1,7,12,39,6,0,0,0,0,0,0,0,0,12,18,6,0,0,0,0,0,0,0,0,12,29,6,0,0,0,0,0,0,0,0,12,30,64,79,0,0,0,0,0,0,0,0,12,17,10,18,10,20,35,4,203,1,5,34,14,2,10,18,66,21,20,12,26,14,3,10,18,66,65,20,12,27,10,0,55,8,10,27,56,73,32,4,51,5,29,10,0,54,8,10,27,56,48,12,31,10,31,10,26,12,9,46,11,9,56,84,32,4,67,11,31,1,5,29,10,31,10,26,12,10,46,11,10,56,85,20,12,22,10,26,17,17,12,19,10,19,4,84,10,0,54,9,12,11,5,87,10,0,54,3,12,11,11,11,12,24,10,22,10,30,34,4,114,11,22,12,30,10,24,10,30,12,12,46,11,12,56,54,12,21,4,104,5,112,11,31,1,11,0,1,11,24,1,7,10,39,11,21,12,29,11,24,11,31,10,29,11,26,10,27,56,86,12,25,14,25,16,6,20,10,23,35,4,128,1,5,132,1,11,0,1,7,18,39,11,19,4,148,1,14,25,16,5,20,14,25,16,12,20,17,56,12,15,10,0,54,2,11,27,11,15,56,58,5,155,1,10,0,54,0,11,27,14,25,16,5,20,56,39,10,28,14,25,56,40,14,25,16,8,20,12,13,14,25,16,9,20,12,14,14,25,16,10,20,12,4,14,25,16,7,20,12,5,14,25,16,11,20,12,6,14,25,16,5,20,12,7,14,25,16,12,20,12,8,11,14,11,13,11,4,11,5,11,6,11,7,11,8,57,5,12,16,13,17,11,16,68,79,11,18,6,1,0,0,0,0,0,0,0,22,12,18,5,29,11,0,1,14,17,56,55,32,4,213,1,11,28,11,17,57,6,56,56,2,25,1,0,0,120,93,11,1,17,47,12,7,10,0,55,8,11,7,56,91,12,8,64,29,0,0,0,0,0,0,0,0,12,3,10,8,56,92,12,5,10,5,56,47,32,4,85,5,18,10,8,10,5,56,36,20,56,85,20,12,6,10,5,56,36,20,17,17,4,36,10,0,55,9,11,6,56,93,12,2,5,41,10,0,55,3,11,6,56,93,12,2,11,2,16,4,10,5,56,36,20,56,38,12,4,13,3,10,4,16,9,20,10,4,16,8,20,10,4,16,12,20,10,4,16,11,20,10,4,16,5,20,10,4,16,10,20,10,4,16,7,20,10,4,16,6,20,11,4,16,22,20,18,8,68,29,10,8,11,5,56,36,20,56,94,12,5,5,13,11,8,1,11,0,1,11,5,1,11,3,2,26,1,0,0,121,20,11,1,17,47,12,4,10,0,55,0,10,4,56,95,12,3,12,2,11,0,55,2,11,4,56,96,12,6,12,5,11,2,11,3,11,5,11,6,2,27,1,0,0,122,37,10,0,55,9,56,32,32,4,12,10,0,55,9,56,57,1,56,97,12,1,5,14,56,98,12,1,11,1,12,4,10,0,55,3,56,32,32,4,28,11,0,55,3,56,33,1,56,97,12,2,5,32,11,0,1,56,98,12,2,11,2,12,3,11,4,11,3,2,28,1,0,0,124,90,64,21,0,0,0,0,0,0,0,0,12,9,64,21,0,0,0,0,0,0,0,0,12,5,10,0,55,9,56,32,4,15,11,0,1,11,3,1,11,9,11,5,2,10,0,55,9,56,33,1,12,8,10,1,10,8,35,4,26,11,8,12,1,10,0,55,9,56,57,1,12,7,10,2,10,7,36,4,37,11,7,12,2,10,0,55,9,11,1,56,99,12,1,10,0,55,9,11,2,56,99,12,2,10,1,10,2,37,4,87,5,52,10,0,55,9,10,1,10,3,17,70,56,100,12,4,10,4,6,0,0,0,0,0,0,0,0,34,4,69,13,9,10,1,68,21,13,5,11,4,68,21,10,0,55,9,11,1,56,52,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,84,11,0,1,11,3,1,5,87,11,6,12,1,5,47,11,9,11,5,2,29,1,0,0,124,90,64,21,0,0,0,0,0,0,0,0,12,9,64,21,0,0,0,0,0,0,0,0,12,5,10,0,55,3,56,32,4,15,11,0,1,11,3,1,11,9,11,5,2,10,0,55,3,56,33,1,12,8,10,1,10,8,35,4,26,11,8,12,1,10,0,55,3,56,57,1,12,7,10,2,10,7,36,4,37,11,7,12,2,10,0,55,3,11,1,56,99,12,1,10,0,55,3,11,2,56,99,12,2,10,1,10,2,37,4,87,5,52,10,0,55,3,10,1,10,3,17,70,56,100,12,4,10,4,6,0,0,0,0,0,0,0,0,34,4,69,13,9,10,1,68,21,13,5,11,4,68,21,10,0,55,3,11,1,56,52,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,84,11,0,1,11,3,1,5,87,11,6,12,1,5,47,11,9,11,5,2,30,0,0,0,125,49,11,0,11,1,56,93,16,4,12,6,6,0,0,0,0,0,0,0,0,12,3,10,6,56,35,12,5,10,5,56,47,32,4,43,5,15,10,6,10,5,56,36,20,56,38,12,4,10,4,16,6,20,10,2,36,4,34,11,3,11,4,16,5,20,22,12,3,5,36,11,4,1,10,6,11,5,56,36,20,56,46,12,5,5,10,11,6,1,11,5,1,11,3,2,31,1,0,0,126,52,11,2,17,47,12,5,10,0,55,8,10,5,56,73,4,9,5,13,11,0,1,7,11,39,10,0,55,8,11,5,56,91,12,6,10,6,10,1,56,84,4,23,5,29,11,6,1,11,0,1,7,2,39,11,6,10,1,56,85,20,12,4,10,1,7,27,35,4,42,11,0,55,9,12,3,5,45,11,0,55,3,12,3,11,3,11,4,56,93,16,4,11,1,56,38,2,10,10,10,0,10,11,10,2,9,1,8,4,8,7,8,6,8,1,8,0,8,5,8,3,8,2,10,6,10,9,10,7,10,14,10,5,10,1,10,3,10,4,10,8,8,8,0,59,1,59,2,59,3,59,13,59,14,59,15,59,16,59,17,59,18,59,19,59,20,59,21,59,0],"critbit":[161,28,235,11,6,0,0,0,14,1,0,8,2,8,28,3,36,194,1,4,230,1,54,5,156,2,232,1,7,132,4,166,4,8,170,8,64,6,234,8,120,10,226,9,51,11,149,10,4,12,153,10,173,14,13,198,24,28,14,226,24,20,15,246,24,4,0,14,0,30,1,45,1,46,0,2,6,1,0,0,0,1,6,0,0,0,4,1,4,0,2,3,12,2,7,1,4,1,3,4,2,0,0,33,0,1,1,4,0,44,2,3,1,4,0,22,2,4,1,4,0,32,2,5,1,4,0,31,2,5,1,4,0,38,6,5,1,4,0,35,6,5,1,4,0,27,6,3,1,4,0,42,6,3,1,4,0,20,7,3,1,4,0,18,6,8,1,4,0,17,6,3,1,4,0,40,9,10,1,4,0,10,9,11,1,4,0,7,6,12,1,4,0,8,6,12,1,4,0,16,1,13,1,6,0,15,1,13,1,4,0,19,6,3,1,4,0,47,14,13,1,4,0,23,15,4,1,4,1,13,25,26,0,2,5,24,13,2,7,4,2,6,20,21,2,7,4,2,9,28,30,2,7,4,2,15,17,13,2,7,4,2,16,17,13,2,7,6,2,22,19,4,2,7,4,2,28,19,3,2,7,4,2,33,0,17,2,7,4,2,39,28,29,2,7,4,29,16,29,18,28,18,27,18,2,10,23,18,10,10,20,10,23,16,8,10,7,10,22,18,18,10,22,16,19,10,6,10,5,10,30,18,1,10,24,16,24,18,30,16,14,10,26,16,26,18,25,18,25,16,1,7,8,4,1,11,2,1,9,0,1,6,11,2,1,9,0,1,3,1,1,2,3,3,2,6,11,2,1,9,0,3,3,7,11,2,1,9,0,3,9,0,2,1,3,2,7,11,2,1,9,0,3,1,9,0,1,7,9,0,1,6,9,0,0,4,7,11,2,1,9,0,3,3,1,3,6,11,2,1,9,0,3,3,2,3,8,1,1,11,3,2,9,0,9,1,2,3,11,0,1,9,0,1,6,11,3,2,9,0,9,1,2,6,11,3,2,9,0,9,1,9,0,1,6,9,1,4,1,3,3,3,16,3,3,3,3,3,2,6,8,1,1,1,8,1,3,3,11,0,1,9,0,3,3,3,3,7,11,3,2,9,0,9,1,9,0,9,1,1,4,1,2,16,3,3,3,3,3,3,3,3,3,1,3,3,6,8,1,3,3,9,0,2,7,11,3,2,9,0,9,1,9,0,1,9,1,1,7,9,1,2,11,3,2,3,8,1,11,3,2,3,11,0,1,9,0,2,6,8,1,3,11,67,114,105,116,98,105,116,84,114,101,101,12,73,110,116,101,114,110,97,108,78,111,100,101,4,76,101,97,102,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,4,99,108,111,98,7,99,108,111,98,95,118,50,19,99,111,117,110,116,95,108,101,97,100,105,110,103,95,122,101,114,111,115,7,99,114,105,116,98,105,116,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,29,103,101,116,95,99,108,111,115,101,115,116,95,108,101,97,102,95,105,110,100,101,120,95,98,121,95,107,101,121,11,105,110,115,101,114,116,95,108,101,97,102,14,105,110,116,101,114,110,97,108,95,110,111,100,101,115,8,105,115,95,101,109,112,116,121,13,105,115,95,108,101,102,116,95,99,104,105,108,100,3,107,101,121,6,108,101,97,118,101,115,10,108,101,102,116,95,99,104,105,108,100,14,108,101,102,116,95,109,111,115,116,95,108,101,97,102,6,108,101,110,103,116,104,4,109,97,115,107,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,3,110,101,119,24,110,101,120,116,95,105,110,116,101,114,110,97,108,95,110,111,100,101,95,105,110,100,101,120,9,110,101,120,116,95,108,101,97,102,15,110,101,120,116,95,108,101,97,102,95,105,110,100,101,120,6,112,97,114,101,110,116,13,112,114,101,118,105,111,117,115,95,108,101,97,102,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,11,114,105,103,104,116,95,99,104,105,108,100,15,114,105,103,104,116,95,109,111,115,116,95,108,101,97,102,4,114,111,111,116,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,112,100,97,116,101,95,99,104,105,108,100,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,128,3,8,255,255,255,255,255,255,255,255,3,8,255,255,255,255,255,255,255,127,0,2,3,24,3,48,9,0,37,3,1,2,4,29,3,26,3,41,3,37,3,2,2,7,43,3,21,11,3,2,3,8,1,25,11,3,2,3,11,0,1,9,0,32,3,31,3,34,3,36,3,2,10,0,10,0,3,0,0,13,11,7,9,10,0,56,0,11,0,56,1,7,9,7,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,57,0,2,1,3,0,0,13,4,11,0,55,0,56,2,2,2,3,0,0,13,4,11,0,55,0,56,3,2,3,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,1,20,56,5,55,2,20,11,0,55,1,20,2,4,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,0,55,3,20,2,5,1,0,0,22,78,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,36,5,30,10,0,10,4,11,5,56,7,12,2,5,38,9,12,2,11,2,4,50,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,59,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,7,20,56,9,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,6,3,0,0,22,79,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,37,5,30,10,0,10,4,11,5,56,7,32,12,2,5,39,9,12,2,11,2,4,51,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,60,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,8,20,56,10,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,7,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,7,20,12,2,5,2,11,0,1,11,2,2,8,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,8,20,12,2,5,2,11,0,1,11,2,2,9,3,0,0,23,247,1,10,1,11,2,7,9,57,1,12,15,10,0,55,6,20,12,16,10,0,55,6,20,6,1,0,0,0,0,0,0,0,22,10,0,54,6,21,10,16,7,11,6,1,0,0,0,0,0,0,0,23,35,4,24,5,28,11,0,1,7,1,39,10,0,54,0,10,16,11,15,56,11,10,0,10,1,12,3,46,11,3,56,12,12,7,10,7,7,9,33,4,69,10,16,6,0,0,0,0,0,0,0,0,33,4,49,5,53,11,0,1,7,2,39,7,10,10,16,23,10,0,54,7,21,10,16,10,0,54,1,21,11,16,11,0,54,3,21,6,0,0,0,0,0,0,0,0,2,10,0,55,0,11,7,56,5,55,2,20,12,6,10,6,10,1,34,4,81,5,85,11,0,1,7,3,39,49,64,11,6,10,1,29,53,17,21,49,64,23,23,12,8,6,1,0,0,0,0,0,0,0,11,8,49,1,23,47,12,17,10,17,7,9,7,9,7,9,18,1,12,12,10,0,55,8,20,12,13,10,0,55,8,20,6,1,0,0,0,0,0,0,0,22,10,0,54,8,21,10,0,54,5,10,13,11,12,56,13,10,0,55,7,20,12,18,7,9,12,14,10,18,7,9,35,4,169,1,5,135,1,10,0,55,5,10,18,56,8,12,9,10,17,10,9,16,12,20,36,4,149,1,11,9,1,5,169,1,11,18,12,14,10,1,10,9,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,164,1,11,9,16,7,20,12,18,5,168,1,11,9,16,8,20,12,18,5,130,1,10,14,7,9,33,4,178,1,10,13,10,0,54,7,21,5,193,1,10,0,10,14,10,18,12,5,12,4,46,11,4,11,5,56,7,12,10,10,0,11,14,10,13,11,10,56,14,11,17,10,1,28,6,0,0,0,0,0,0,0,0,33,12,11,10,0,10,13,7,10,10,16,23,10,11,56,14,10,0,11,13,11,18,11,11,32,56,14,10,0,55,0,10,0,55,1,20,56,5,55,2,20,10,1,36,4,227,1,10,16,10,0,54,1,21,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,1,35,4,243,1,10,16,11,0,54,3,21,5,245,1,11,0,1,11,16,2,10,3,0,0,3,27,10,0,56,4,4,8,11,0,1,9,7,9,2,10,0,10,1,56,12,12,2,11,0,55,0,10,2,56,5,55,2,20,11,1,34,4,24,9,7,9,2,8,11,2,2,11,3,0,0,3,18,10,0,56,4,4,7,11,0,1,6,0,0,0,0,0,0,0,0,2,10,0,11,1,56,12,12,2,11,0,55,0,11,2,56,5,55,2,20,2,12,3,0,0,27,171,1,10,0,55,0,10,1,56,5,55,2,20,12,12,10,0,55,1,20,10,1,33,4,25,10,0,10,12,12,4,46,11,4,56,15,12,9,1,11,9,10,0,54,1,21,10,0,55,3,20,10,1,33,4,43,10,0,11,12,12,5,46,11,5,56,16,12,10,1,11,10,10,0,54,3,21,10,0,54,0,10,1,56,17,58,1,12,15,12,17,1,10,0,46,56,18,6,0,0,0,0,0,0,0,0,33,4,78,7,9,10,0,54,7,21,7,9,10,0,54,1,21,7,9,10,0,54,3,21,6,0,0,0,0,0,0,0,0,10,0,54,8,21,6,0,0,0,0,0,0,0,0,11,0,54,6,21,5,169,1,10,15,7,9,34,4,83,5,87,11,0,1,7,6,39,10,0,55,5,10,15,56,8,12,14,10,14,16,6,20,12,13,10,0,10,15,7,10,11,1,23,12,7,12,6,46,11,6,11,7,56,7,4,113,11,14,16,8,20,12,8,5,117,11,14,16,7,20,12,8,11,8,12,16,10,13,7,9,33,4,149,1,10,16,7,9,35,4,135,1,7,9,10,0,54,5,10,16,56,19,15,6,21,5,144,1,7,9,10,0,54,0,7,10,10,16,23,56,20,54,4,21,11,16,10,0,54,7,21,5,164,1,10,0,10,13,10,15,12,3,12,2,46,11,2,11,3,56,7,12,11,10,0,11,13,11,16,11,11,56,14,11,0,54,5,11,15,56,21,1,11,17,2,13,3,0,0,13,6,11,0,54,0,11,1,56,20,54,9,2,14,3,0,0,13,6,11,0,55,0,11,1,56,5,55,9,2,15,3,0,0,3,14,10,0,11,1,56,6,12,2,4,6,5,10,11,0,1,7,4,39,11,0,11,2,56,22,2,16,3,0,0,31,14,11,0,58,0,1,1,1,1,12,2,12,1,1,11,1,56,23,11,2,56,24,2,17,3,0,0,31,23,14,0,55,0,56,2,6,0,0,0,0,0,0,0,0,33,4,7,5,9,6,0,0,0,0,0,0,0,0,39,11,0,58,0,1,1,1,1,12,2,12,1,1,11,2,56,25,11,1,56,26,2,18,0,0,0,32,46,10,0,55,7,20,12,3,10,3,7,9,33,4,12,11,0,1,7,9,2,10,3,7,9,35,4,40,5,17,10,0,55,5,11,3,56,8,12,2,10,1,10,2,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,35,11,2,16,7,20,12,3,5,39,11,2,16,8,20,12,3,5,12,11,0,1,7,10,11,3,23,2,19,0,0,0,13,48,10,1,7,9,34,4,5,5,9,11,0,1,7,7,39,11,3,4,19,10,2,10,0,54,5,10,1,56,19,15,7,21,5,26,10,2,10,0,54,5,10,1,56,19,15,8,21,10,2,7,9,36,4,40,11,1,11,0,54,0,7,10,11,2,23,56,20,54,4,21,5,47,11,1,11,0,54,5,11,2,56,19,15,6,21,2,20,0,0,0,13,9,11,0,55,5,11,1,56,8,16,7,20,11,2,33,2,2,2,2,3,0,0,2,4,0,2,2,1,1,3,1,1,1,2,2,6,2,0,2,5,1,0,0,1,0,10,1,10,2,10,3,10,4,10,5,10,9,10,10,10,11,10,13,10,0,11,0,12,0],"custodian":[161,28,235,11,6,0,0,0,14,1,0,12,2,12,48,3,60,158,1,4,218,1,30,5,248,1,246,1,7,238,3,166,4,8,148,8,64,6,212,8,10,10,222,8,38,11,132,9,4,12,136,9,238,2,13,246,11,8,14,254,11,6,15,132,12,2,0,23,1,15,1,21,1,35,1,37,1,38,0,0,4,1,0,1,0,1,12,0,0,4,12,1,0,1,1,2,4,1,0,1,2,3,12,1,0,1,3,5,7,0,3,8,4,0,4,6,12,2,7,1,4,1,5,7,2,0,0,33,0,1,0,0,10,2,3,1,0,0,34,0,4,1,0,0,42,5,6,1,0,0,28,7,8,1,0,0,24,9,10,1,0,0,29,11,8,1,0,0,25,12,10,1,0,0,31,9,8,1,0,0,40,12,8,1,0,0,9,2,13,1,0,0,12,2,13,1,0,0,19,14,15,1,0,0,17,2,16,1,0,1,30,27,13,1,0,1,36,30,10,1,0,1,41,24,13,1,0,1,43,8,10,1,0,2,26,26,6,1,0,3,34,0,17,0,3,39,28,29,0,4,13,31,8,2,7,4,4,16,21,23,2,7,4,4,18,32,33,2,7,4,4,22,21,22,2,7,4,4,34,0,25,2,7,4,24,20,22,20,16,19,25,20,5,19,18,19,12,19,14,19,15,19,6,19,7,19,4,19,17,19,21,20,23,20,1,7,8,8,1,8,1,2,6,11,2,1,9,0,8,5,2,3,3,1,11,2,1,9,0,4,7,11,2,1,9,0,3,6,8,1,7,8,8,1,11,4,1,9,0,3,7,11,2,1,9,0,8,5,11,3,1,9,0,0,3,7,11,2,1,9,0,6,8,1,3,1,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,11,3,1,9,0,3,7,11,2,1,9,0,8,5,3,1,3,2,7,11,2,1,9,0,8,5,1,7,11,0,1,9,0,1,6,11,0,1,9,0,1,8,6,3,6,11,0,1,9,0,3,3,1,9,0,2,8,5,11,0,1,9,0,2,6,11,7,2,9,0,9,1,9,0,1,1,1,6,9,1,1,6,11,3,1,9,0,1,11,7,2,9,0,9,1,2,11,3,1,9,0,7,8,8,2,7,11,3,1,9,0,11,3,1,9,0,1,6,8,6,1,8,5,2,7,11,3,1,9,0,3,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,7,9,1,7,65,99,99,111,117,110,116,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,4,67,111,105,110,9,67,117,115,116,111,100,105,97,110,2,73,68,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,16,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,115,22,97,99,99,111,117,110,116,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,3,97,100,100,17,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,22,98,111,114,114,111,119,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,26,98,111,114,114,111,119,95,109,117,116,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,4,99,108,111,98,4,99,111,105,110,8,99,111,110,116,97,105,110,115,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,105,110,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,4,106,111,105,110,12,108,111,99,107,95,98,97,108,97,110,99,101,14,108,111,99,107,101,100,95,98,97,108,97,110,99,101,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,110,101,119,6,111,98,106,101,99,116,5,115,112,108,105,116,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,0,2,2,14,11,3,1,9,0,32,11,3,1,9,0,1,2,1,27,8,6,2,2,2,27,8,6,11,11,7,2,8,5,11,0,1,9,0,2,19,0,19,0,1,0,0,8,4,11,0,17,19,18,1,2,1,3,0,0,18,27,10,0,55,0,10,1,56,0,32,4,11,11,0,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,2,11,0,55,0,11,1,56,1,12,2,10,2,55,1,56,2,12,3,11,2,55,2,56,2,12,4,11,3,11,4,2,2,3,0,0,8,6,10,0,17,19,11,0,56,3,57,0,2,3,3,0,0,8,7,11,0,11,2,11,1,56,4,11,3,56,5,2,4,3,0,0,8,8,11,0,11,1,56,6,54,1,11,2,56,7,1,2,5,3,0,0,8,9,11,0,11,1,16,3,17,20,56,6,54,1,11,2,56,8,2,6,3,0,0,8,10,11,0,11,1,16,3,17,20,56,6,54,2,11,2,56,7,1,2,7,3,0,0,8,7,11,0,11,1,56,6,54,2,11,2,56,8,2,8,3,0,0,10,10,10,0,10,1,11,2,56,4,12,3,11,0,11,1,11,3,56,9,2,9,3,0,0,10,10,10,0,10,1,11,2,56,10,12,3,11,0,11,1,11,3,56,11,2,10,3,0,0,8,7,11,0,55,0,11,1,56,1,55,1,56,2,2,11,3,0,0,8,7,11,0,55,0,11,1,56,1,55,2,56,2,2,12,0,0,0,8,18,10,0,55,0,10,1,56,0,32,4,13,10,0,54,0,10,1,56,12,56,12,57,1,56,13,11,0,54,0,11,1,56,14,2,13,0,0,0,8,15,10,0,55,0,10,1,56,0,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,1,2,2,1,0,0,0,1,1,0,0,19,1,19,2,19,0,20,0],"custodian_v2":[161,28,235,11,6,0,0,0,14,1,0,12,2,12,44,3,56,178,1,4,234,1,30,5,136,2,255,1,7,135,4,242,4,8,249,8,64,6,185,9,20,10,205,9,39,11,244,9,4,12,248,9,189,3,13,181,13,10,14,191,13,6,15,197,13,2,0,24,1,15,1,21,1,38,1,41,1,42,0,0,4,1,0,1,0,1,12,0,0,4,12,1,0,1,1,2,4,1,0,1,2,3,12,1,0,1,3,7,4,0,4,5,12,2,7,1,4,1,5,6,2,0,0,36,0,1,0,0,23,2,1,0,0,28,1,3,0,0,12,4,5,0,0,9,6,7,1,0,0,37,0,8,1,0,0,46,9,10,1,0,0,31,11,3,1,0,0,25,12,13,1,0,0,32,14,3,1,0,0,26,15,13,1,0,0,34,12,3,1,0,0,44,15,3,1,0,0,8,6,16,1,0,0,11,6,16,1,0,0,19,17,18,1,0,0,17,6,19,1,0,1,33,32,16,1,0,1,40,33,13,1,0,1,45,29,16,1,0,1,47,3,13,1,0,2,29,31,10,1,0,3,27,21,3,0,3,37,0,21,0,3,43,22,5,0,4,13,34,3,2,7,4,4,16,26,28,2,7,4,4,18,35,36,2,7,4,4,22,26,27,2,7,4,4,37,0,30,2,7,4,28,25,26,25,19,24,29,25,8,24,21,24,15,24,17,24,18,24,9,24,10,24,7,24,20,24,25,25,27,25,1,7,8,7,1,8,1,2,6,8,1,7,8,7,0,1,6,8,1,1,5,2,6,11,2,1,9,0,5,2,3,3,1,11,2,1,9,0,4,7,11,2,1,9,0,3,6,8,1,7,8,7,1,11,4,1,9,0,3,7,11,2,1,9,0,5,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,3,1,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,11,3,1,9,0,3,7,11,2,1,9,0,5,3,1,3,2,7,11,2,1,9,0,5,1,7,11,0,1,9,0,1,6,11,0,1,9,0,2,8,5,5,1,8,5,1,6,8,5,3,6,11,0,1,9,0,3,3,1,9,0,2,5,11,0,1,9,0,2,6,11,6,2,9,0,9,1,9,0,1,1,1,6,9,1,1,6,11,3,1,9,0,1,11,6,2,9,0,9,1,2,11,3,1,9,0,7,8,7,2,7,11,3,1,9,0,11,3,1,9,0,2,7,11,3,1,9,0,3,3,7,11,6,2,9,0,9,1,9,0,9,1,2,7,11,6,2,9,0,9,1,9,0,1,7,9,1,7,65,99,99,111,117,110,116,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,4,67,111,105,110,9,67,117,115,116,111,100,105,97,110,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,16,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,115,22,97,99,99,111,117,110,116,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,13,97,99,99,111,117,110,116,95,111,119,110,101,114,3,97,100,100,17,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,22,98,111,114,114,111,119,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,26,98,111,114,114,111,119,95,109,117,116,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,7,99,108,111,98,95,118,50,4,99,111,105,110,8,99,111,110,116,97,105,110,115,24,99,114,101,97,116,101,95,99,104,105,108,100,95,97,99,99,111,117,110,116,95,99,97,112,12,99,117,115,116,111,100,105,97,110,95,118,50,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,6,100,101,108,101,116,101,18,100,101,108,101,116,101,95,97,99,99,111,117,110,116,95,99,97,112,12,102,114,111,109,95,98,97,108,97,110,99,101,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,105,110,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,4,106,111,105,110,12,108,111,99,107,95,98,97,108,97,110,99,101,14,108,111,99,107,101,100,95,98,97,108,97,110,99,101,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,110,101,119,6,111,98,106,101,99,116,5,111,119,110,101,114,5,115,112,108,105,116,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,2,14,11,3,1,9,0,35,11,3,1,9,0,1,2,2,30,8,5,39,5,2,2,2,30,8,5,10,11,6,2,5,11,0,1,9,0,2,24,0,24,0,3,0,0,20,10,11,0,17,23,12,1,14,1,17,24,12,2,11,1,11,2,18,1,2,1,1,0,0,3,22,10,0,16,0,17,24,10,0,16,1,20,33,4,9,5,15,11,1,1,11,0,1,7,1,39,11,1,17,23,11,0,16,1,20,18,1,2,2,1,0,0,3,5,11,0,19,1,1,17,22,2,3,1,0,0,3,4,11,0,16,1,20,2,4,3,0,0,23,27,10,0,55,0,10,1,56,0,32,4,11,11,0,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,2,11,0,55,0,11,1,56,1,12,2,10,2,55,1,56,2,12,3,11,2,55,2,56,2,12,4,11,3,11,4,2,5,3,0,0,3,6,10,0,17,23,11,0,56,3,57,0,2,6,3,0,0,3,7,11,0,11,2,11,1,56,4,11,3,56,5,2,7,3,0,0,3,8,11,0,11,1,56,6,54,1,11,2,56,7,1,2,8,3,0,0,3,9,11,0,11,1,16,1,20,56,6,54,1,11,2,56,8,2,9,3,0,0,3,10,11,0,11,1,16,1,20,56,6,54,2,11,2,56,7,1,2,10,3,0,0,3,7,11,0,11,1,56,6,54,2,11,2,56,8,2,11,3,0,0,13,10,10,0,10,1,11,2,56,4,12,3,11,0,11,1,11,3,56,9,2,12,3,0,0,13,10,10,0,10,1,11,2,56,10,12,3,11,0,11,1,11,3,56,11,2,13,3,0,0,3,7,11,0,55,0,11,1,56,1,55,1,56,2,2,14,3,0,0,3,7,11,0,55,0,11,1,56,1,55,2,56,2,2,15,0,0,0,3,18,10,0,55,0,10,1,56,0,32,4,13,10,0,54,0,10,1,56,12,56,12,57,1,56,13,11,0,54,0,11,1,56,14,2,16,0,0,0,3,15,10,0,55,0,10,1,56,0,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,1,2,1,0,1,1,2,1,0,0,0,1,2,24,3,24,4,24,0,20,0],"math":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,40,5,42,20,7,62,126,8,188,1,32,6,220,1,38,12,130,2,183,5,15,185,7,6,0,5,0,10,0,1,0,0,11,0,2,0,0,6,0,1,0,0,7,0,2,0,0,8,0,1,0,0,9,0,2,0,0,4,0,2,0,0,2,3,4,0,2,3,3,1,3,2,1,3,1,4,1,2,0,3,1,4,4,2,2,2,4,99,108,111,98,7,99,108,111,98,95,118,50,19,99,111,117,110,116,95,108,101,97,100,105,110,103,95,122,101,114,111,115,7,99,114,105,116,98,105,116,9,100,105,118,95,114,111,117,110,100,4,109,97,116,104,3,109,117,108,9,109,117,108,95,114,111,117,110,100,10,117,110,115,97,102,101,95,100,105,118,16,117,110,115,97,102,101,95,100,105,118,95,114,111,117,110,100,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,3,8,0,202,154,59,0,0,0,0,4,16,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,3,0,0,1,7,11,0,11,1,17,1,12,2,1,11,2,2,1,3,0,0,6,26,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,10,4,24,7,1,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,18,9,12,2,11,2,11,3,11,4,24,7,1,26,52,2,2,1,0,0,1,14,11,0,11,1,17,1,12,2,1,10,2,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,2,3,1,0,0,2,15,11,0,11,1,17,1,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,4,3,0,0,1,7,11,0,11,1,17,5,12,2,1,11,2,2,5,3,0,0,6,28,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,7,0,53,24,10,4,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,9,12,2,11,2,11,3,7,0,53,24,11,4,26,52,2,6,1,0,0,2,15,11,0,11,1,17,5,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,7,3,0,0,7,107,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,49,128,12,1,5,105,49,0,12,2,10,0,50,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,23,11,0,49,64,47,12,0,11,2,49,64,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,37,11,0,49,32,47,12,0,11,2,49,32,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,51,11,0,49,16,47,12,0,11,2,49,16,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,65,11,0,49,8,47,12,0,11,2,49,8,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,79,11,0,49,4,47,12,0,11,2,49,4,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,93,11,0,49,2,47,12,0,11,2,49,2,22,12,2,11,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,103,11,2,49,1,22,12,2,11,2,12,1,11,1,2,0,0,0,1,0,3,0]},"type_origin_table":[{"module_name":"custodian","struct_name":"Account","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"AccountCap","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"Custodian","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"Leaf","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"InternalNode","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"CritbitTree","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"PoolCreated","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlacedV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilledV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Order","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"TickLevel","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Pool","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlaced","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian_v2","struct_name":"Account","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian_v2","struct_name":"AccountCap","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian_v2","struct_name":"Custodian","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"PoolCreated","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"OrderPlaced","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"OrderCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"AllOrdersCanceledComponent","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"AllOrdersCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"OrderFilled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"DepositAsset","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"WithdrawAsset","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"Order","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"TickLevel","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"Pool","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"ACKQVv64dXCmpxE1QPU2QMLxVpmtbzrFGMtWYY6szJrQ","storage_rebate":0},{"data":{"Package":{"id":"0xb2345915de1f9bd661e9ab27eb27e376cdf6391359ea64fbfdb4550b092c1aa0","version":4,"module_map":{"calculator":[161,28,235,11,6,0,0,0,8,1,0,12,2,12,12,3,24,75,5,99,67,7,166,1,189,2,8,227,3,96,6,195,4,44,12,239,4,164,5,0,10,0,23,0,21,2,17,1,11,1,16,1,2,12,0,3,1,8,0,4,0,8,0,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,6,3,1,0,0,7,3,1,0,0,9,4,1,0,0,4,4,1,0,1,12,0,8,0,1,13,0,3,0,1,15,0,3,0,2,19,6,1,0,2,20,3,1,0,2,22,3,1,0,3,14,10,11,0,5,18,12,13,0,2,7,8,0,2,1,15,3,7,8,0,2,15,2,15,15,4,6,8,2,6,8,1,15,2,7,15,15,15,15,15,15,15,0,6,15,15,15,15,15,15,5,15,15,15,15,15,2,2,15,3,6,8,2,6,8,1,2,3,1,15,2,2,3,2,1,3,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,20,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,9,103,101,116,95,105,110,100,101,120,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,4,109,97,116,104,6,111,114,97,99,108,101,3,112,111,119,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,153,183,0,0,0,0,0,0,0,1,0,0,5,31,10,0,10,1,17,9,12,7,12,8,11,0,11,1,17,8,12,3,12,4,11,7,11,3,17,12,12,5,11,8,11,4,17,12,12,6,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,29,11,5,11,6,17,11,12,2,11,2,2,1,1,0,0,7,37,10,0,10,1,17,7,12,6,1,12,4,12,5,12,3,11,0,11,1,17,0,12,7,10,7,10,6,35,4,23,11,3,11,7,11,5,17,12,22,12,2,5,35,11,3,10,6,11,5,17,12,22,11,7,11,6,23,11,4,17,12,22,12,2,11,2,2,2,1,0,0,3,20,10,0,10,1,17,7,1,12,3,1,1,1,11,0,11,1,17,0,12,4,11,2,11,4,17,12,17,10,11,3,23,17,12,2,3,1,0,0,5,60,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,17,10,2,10,0,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,5,11,1,7,0,26,12,6,10,6,10,6,17,12,12,3,10,3,10,6,17,12,12,2,10,0,10,4,24,11,3,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,7,10,0,11,4,24,11,5,24,11,2,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,17,10,11,6,11,0,24,22,11,7,22,11,8,22,2,4,1,0,0,6,8,17,10,11,1,11,0,24,7,0,26,22,2,5,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,11,5,24,6,10,0,0,0,0,0,0,0,11,4,17,14,77,26,2,6,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,6,10,0,0,0,0,0,0,0,11,4,17,14,77,24,11,5,26,2,0],"dynamic_calculator":[161,28,235,11,6,0,0,0,9,1,0,18,2,18,18,3,36,169,1,4,205,1,4,5,209,1,165,2,7,246,3,149,6,8,139,10,128,1,6,139,11,10,12,149,11,225,14,0,16,0,9,0,38,0,43,0,41,3,37,1,45,2,4,2,10,2,1,12,1,0,1,3,3,12,0,5,2,8,0,8,0,8,0,0,17,0,1,1,0,0,21,2,1,0,0,22,2,1,0,0,20,3,1,0,0,24,3,1,0,0,19,4,1,0,0,23,4,1,0,0,18,5,1,0,0,6,6,7,0,0,13,8,7,1,0,0,14,9,1,0,0,15,10,1,0,0,12,9,1,0,1,5,7,1,0,1,7,7,1,0,1,8,25,1,0,2,36,13,14,1,0,3,25,22,1,0,3,26,28,34,0,3,27,28,7,0,3,28,28,7,0,3,29,22,14,0,3,30,28,29,0,3,31,22,19,0,3,32,28,7,0,3,33,17,18,0,3,34,26,7,0,4,39,15,1,0,4,40,7,1,0,4,42,7,1,0,6,11,20,21,1,0,7,35,15,1,0,8,44,31,14,0,16,12,30,19,9,6,8,3,7,8,1,6,8,2,7,11,0,1,9,0,5,2,3,3,1,1,15,7,6,8,3,6,8,2,7,8,1,5,2,15,1,7,6,8,3,6,8,2,7,8,1,2,5,15,1,6,6,8,3,7,8,1,2,5,15,1,7,6,8,3,7,8,1,6,8,2,5,2,15,1,3,6,8,3,7,8,1,2,2,15,15,7,6,8,3,7,8,1,7,11,0,1,9,0,2,3,3,1,6,6,8,3,7,8,1,2,15,15,1,7,6,8,3,7,8,1,2,15,15,15,1,9,1,3,3,15,15,15,15,3,3,1,9,0,2,6,11,0,1,9,0,3,1,3,0,11,5,2,6,2,10,2,15,10,2,15,3,3,15,15,2,6,8,1,5,2,10,2,10,2,1,2,2,6,10,9,0,6,9,0,1,1,2,6,8,1,2,9,5,6,2,15,3,10,2,3,15,10,2,15,3,2,15,2,4,6,8,3,6,8,2,15,2,3,7,8,1,2,5,11,5,6,2,10,2,15,15,10,2,15,3,3,15,15,2,7,8,1,2,3,15,15,15,10,2,15,15,15,15,3,3,15,15,15,1,6,8,3,7,1,3,3,15,3,3,15,6,15,15,15,15,15,15,5,15,15,15,15,15,7,15,15,15,15,15,15,15,5,67,108,111,99,107,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,23,99,97,108,99,117,108,97,116,101,95,99,117,114,114,101,110,116,95,105,110,100,101,120,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,28,100,121,110,97,109,105,99,95,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,21,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,97,112,121,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,18,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,111,114,21,100,121,110,97,109,105,99,95,104,101,97,108,116,104,95,102,97,99,116,111,114,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,31,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,36,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,30,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,25,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,23,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,3,109,97,120,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,4,112,111,111,108,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,6,118,101,99,116,111,114,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,201,175,0,0,0,0,0,0,0,1,0,0,11,99,10,6,6,0,0,0,0,0,0,0,0,36,4,9,10,7,6,0,0,0,0,0,0,0,0,36,12,9,5,11,9,12,9,11,9,32,4,15,5,25,11,1,1,11,3,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,17,10,6,6,0,0,0,0,0,0,0,0,36,4,38,10,3,11,6,12,10,46,11,10,56,0,12,17,6,0,0,0,0,0,0,0,0,12,16,10,7,6,0,0,0,0,0,0,0,0,36,4,52,11,3,11,7,12,11,46,11,11,56,0,12,16,5,54,11,3,1,10,0,10,2,10,1,10,4,10,5,10,17,77,10,8,17,1,12,13,10,0,10,2,10,1,10,4,10,5,11,16,77,10,8,17,2,12,14,11,0,11,1,11,2,11,4,11,5,11,17,77,11,8,17,7,12,15,10,14,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,95,11,13,11,14,17,28,11,15,17,29,12,12,5,97,17,31,12,12,11,12,2,1,1,0,0,16,86,10,2,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,17,6,0,0,0,0,0,0,0,0,12,14,10,12,12,10,14,12,14,4,56,1,32,4,31,10,6,4,31,13,10,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,10,14,10,15,35,4,78,5,36,14,10,10,14,66,19,12,9,10,2,10,9,20,12,8,46,11,8,17,17,12,16,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,9,20,33,4,57,10,5,12,13,10,0,10,1,10,2,11,9,20,10,3,11,13,10,6,17,3,12,11,11,17,11,11,11,16,17,29,22,12,17,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,2,1,11,1,1,11,0,1,11,17,2,2,1,0,0,23,76,10,2,10,3,12,7,46,11,7,17,25,12,14,1,14,14,65,19,12,12,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,6,0,0,0,0,0,0,0,0,12,10,10,14,12,11,14,14,14,4,56,1,32,4,31,10,6,4,31,13,11,10,4,68,19,11,12,6,1,0,0,0,0,0,0,0,22,12,12,10,10,10,12,35,4,68,5,36,14,11,10,10,66,19,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,10,4,10,8,20,33,4,49,10,5,12,9,10,0,10,1,10,2,11,8,20,10,3,11,9,10,6,17,4,12,13,11,15,11,13,22,12,15,11,10,6,1,0,0,0,0,0,0,0,22,12,10,5,31,11,2,1,11,1,1,11,0,1,11,15,2,3,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,5,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,4,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,6,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,5,1,0,0,7,27,10,1,10,2,11,3,17,26,1,12,7,11,5,4,13,11,7,11,4,22,12,7,5,17,11,7,11,4,23,12,7,11,0,11,1,11,2,17,8,1,12,6,11,7,11,6,17,29,2,6,1,0,0,7,27,10,1,10,2,11,3,17,26,12,6,1,11,5,4,13,11,6,11,4,22,12,6,5,17,11,6,11,4,23,12,6,11,0,11,1,11,2,17,8,12,7,1,11,6,11,7,17,29,2,7,1,0,0,27,91,10,1,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,6,0,0,0,0,0,0,0,0,12,14,10,12,12,9,14,12,14,4,56,1,32,4,27,13,9,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,10,14,10,15,35,4,81,5,36,14,9,10,14,66,19,12,8,10,1,10,8,20,17,22,12,16,1,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,8,20,33,4,56,10,5,12,13,10,0,10,2,10,1,11,8,20,10,3,11,13,10,6,17,3,12,17,11,10,10,17,11,16,17,29,22,12,10,11,11,11,17,22,12,11,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,1,1,11,2,1,11,0,1,11,10,11,11,17,28,2,8,1,0,0,30,42,11,0,17,32,12,8,10,1,10,2,12,3,46,11,3,17,21,12,9,10,1,10,2,17,20,12,4,12,6,11,1,11,2,17,19,12,5,12,7,11,8,11,9,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,12,10,12,11,5,17,13,11,4,17,29,12,10,11,12,11,7,17,14,11,6,17,29,12,11,11,10,11,11,2,9,1,0,0,32,76,10,4,6,0,0,0,0,0,0,0,0,36,4,9,10,5,6,0,0,0,0,0,0,0,0,36,12,7,5,11,9,12,7,11,7,32,4,15,5,23,11,1,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,12,10,4,6,0,0,0,0,0,0,0,0,36,4,36,10,2,11,4,12,8,46,11,8,56,0,12,12,6,0,0,0,0,0,0,0,0,12,11,10,5,6,0,0,0,0,0,0,0,0,36,4,50,11,2,11,5,12,9,46,11,9,56,0,12,11,5,52,11,2,1,10,0,10,1,10,3,10,12,77,10,11,77,10,6,17,10,12,10,11,0,11,1,11,3,10,10,11,12,77,11,11,77,11,6,17,11,12,13,11,10,11,13,2,10,1,0,0,33,41,10,1,10,2,17,18,12,10,1,12,8,12,9,12,7,11,0,11,1,11,2,11,3,11,4,11,5,17,12,12,11,10,11,10,10,35,4,27,11,7,11,11,11,9,17,29,22,12,6,5,39,11,7,10,11,11,9,17,29,22,11,11,11,10,23,11,8,17,29,22,12,6,11,6,2,11,1,0,0,7,24,10,1,10,2,17,18,1,12,7,1,1,1,11,0,11,1,11,2,11,4,11,5,11,6,17,12,12,8,11,3,11,8,17,29,17,27,11,7,23,17,29,2,12,1,0,0,35,62,10,1,10,2,17,24,12,11,12,12,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,5,4,16,11,12,11,3,22,12,12,5,20,11,12,11,3,23,12,12,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,35,11,5,4,31,11,11,11,4,22,12,11,5,35,11,11,11,4,23,12,11,11,0,11,1,11,2,17,8,12,7,12,8,11,12,11,8,17,29,12,10,11,11,11,7,17,29,12,9,10,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,56,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,5,60,11,9,11,10,17,28,12,6,11,6,2,0],"incentive":[161,28,235,11,6,0,0,0,14,1,0,30,2,30,66,3,96,181,1,4,149,2,46,5,195,2,164,3,7,231,5,187,6,8,162,12,96,6,130,13,94,10,224,13,116,11,212,14,2,12,214,14,189,15,13,147,30,40,14,187,30,8,15,195,30,2,0,44,0,72,0,62,0,64,1,18,1,78,2,21,2,26,2,27,2,36,2,53,2,73,2,76,2,77,0,82,0,4,12,1,0,1,0,6,4,0,0,3,12,0,0,7,3,0,0,5,3,0,1,8,12,0,4,9,7,0,5,12,7,0,6,0,4,1,0,1,7,1,8,0,8,2,12,1,0,1,10,13,4,0,11,10,12,2,7,1,4,1,13,11,2,0,0,47,0,1,0,0,67,2,1,0,0,66,2,1,0,0,15,3,1,1,0,0,79,4,1,0,0,24,5,6,0,0,25,7,1,1,0,0,39,8,9,0,0,40,10,11,0,0,33,12,13,0,1,41,46,37,0,1,42,47,37,0,2,60,1,34,0,2,61,37,34,0,3,51,37,34,0,5,38,1,36,1,0,5,48,36,33,0,6,69,49,40,1,0,7,74,32,9,0,8,37,50,51,1,0,9,34,22,1,1,3,10,52,0,14,0,11,14,26,1,2,7,4,11,22,24,45,2,7,4,11,23,27,28,2,7,4,11,29,24,25,2,7,4,11,52,0,18,2,7,4,11,63,27,43,2,7,4,12,58,52,1,1,12,12,68,22,1,1,8,13,65,15,16,0,14,70,39,40,1,0,26,17,26,19,29,21,25,17,22,17,24,17,20,29,20,30,25,19,22,19,24,19,15,22,26,38,31,22,29,41,25,38,27,38,22,38,23,19,23,38,17,22,19,22,28,51,1,7,8,13,0,4,7,8,2,15,1,7,8,13,9,7,8,2,6,8,9,2,3,3,11,10,1,9,0,3,2,7,8,13,5,7,8,2,6,8,9,7,8,5,2,5,5,6,8,2,7,8,5,3,2,5,2,10,15,10,15,6,7,8,2,7,11,0,1,9,0,6,8,9,7,8,5,5,7,8,13,2,6,8,2,2,1,3,3,6,8,2,2,3,4,3,3,15,2,5,6,8,2,7,8,5,6,8,9,2,5,3,10,8,6,10,15,10,2,1,8,11,1,6,8,13,1,5,2,15,1,1,11,12,2,9,0,9,1,2,2,8,1,1,2,1,8,2,1,9,0,1,7,1,2,6,11,12,2,9,0,9,1,9,0,1,1,3,7,11,12,2,9,0,9,1,9,0,9,1,2,7,11,12,2,9,0,9,1,9,0,1,7,9,1,1,8,3,1,8,4,4,1,11,8,1,9,0,3,7,8,1,1,6,8,9,1,8,6,1,15,1,11,12,2,5,15,1,8,7,2,15,15,2,5,15,3,11,10,1,9,0,3,7,8,13,1,11,8,1,9,0,1,11,0,1,9,0,17,7,8,5,3,2,5,5,5,3,3,7,15,15,10,15,7,11,12,2,5,15,3,7,8,1,15,10,15,7,11,12,2,5,15,1,9,1,18,6,11,12,2,5,15,3,3,15,15,10,15,15,6,11,12,2,5,15,3,6,8,1,15,15,3,15,15,15,15,10,15,1,6,9,1,2,7,8,5,2,3,7,8,5,2,5,9,5,15,3,7,8,1,15,15,6,11,12,2,5,15,15,7,11,12,2,5,15,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,13,1,11,10,1,9,0,2,9,0,5,1,6,8,1,10,10,8,6,3,3,3,10,2,6,8,1,10,15,15,6,11,12,2,5,15,10,15,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,9,73,110,99,101,110,116,105,118,101,12,73,110,99,101,110,116,105,118,101,66,97,108,16,80,111,111,108,65,100,109,105,110,83,101,116,116,105,110,103,8,80,111,111,108,73,110,102,111,16,80,111,111,108,79,119,110,101,114,83,101,116,116,105,110,103,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,3,97,100,100,8,97,100,100,95,112,111,111,108,5,97,100,109,105,110,6,97,100,109,105,110,115,5,97,115,99,105,105,5,97,115,115,101,116,6,97,115,115,101,116,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,24,99,97,108,99,95,112,111,111,108,95,117,112,100,97,116,101,95,114,101,119,97,114,100,115,12,99,108,97,105,109,95,114,101,119,97,114,100,5,99,108,111,99,107,4,99,111,105,110,10,99,111,105,110,95,116,121,112,101,115,8,99,111,110,116,97,105,110,115,7,99,114,101,97,116,111,114,11,99,117,114,114,101,110,116,95,105,100,120,18,100,105,115,116,114,105,98,117,116,101,100,95,97,109,111,117,110,116,6,101,97,114,110,101,100,4,101,109,105,116,9,101,110,100,95,116,105,109,101,115,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,14,103,101,116,95,112,111,111,108,95,99,111,117,110,116,13,103,101,116,95,112,111,111,108,95,105,110,102,111,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,9,105,110,99,101,110,116,105,118,101,13,105,110,100,101,120,95,114,101,119,97,114,100,115,19,105,110,100,101,120,95,114,101,119,97,114,100,115,95,112,97,105,100,115,4,105,110,105,116,11,105,110,116,111,95,115,116,114,105,110,103,16,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,7,108,101,110,100,105,110,103,3,109,117,108,3,110,101,119,6,111,98,106,101,99,116,10,111,114,97,99,108,101,95,105,100,115,5,111,119,110,101,114,6,111,119,110,101,114,115,5,112,111,111,108,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,9,115,97,102,101,95,109,97,116,104,6,115,101,110,100,101,114,9,115,101,116,95,97,100,109,105,110,9,115,101,116,95,111,119,110,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,11,115,116,97,114,116,95,116,105,109,101,115,7,115,116,111,114,97,103,101,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,13,116,111,116,97,108,95,115,117,112,112,108,121,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,13,117,112,100,97,116,101,95,114,101,119,97,114,100,16,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,22,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,95,112,97,105,100,115,5,117,116,105,108,115,5,118,97,108,117,101,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,153,183,0,0,0,0,0,0,3,8,154,183,0,0,0,0,0,0,3,8,155,183,0,0,0,0,0,0,3,8,156,183,0,0,0,0,0,0,3,8,157,183,0,0,0,0,0,0,3,8,158,183,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,43,8,11,19,2,31,3,32,15,21,11,8,1,9,0,1,2,12,43,2,49,3,28,10,8,6,71,10,3,35,10,3,75,10,15,59,10,15,45,10,15,46,10,11,12,2,5,15,80,10,11,12,2,5,15,81,10,11,12,2,5,15,54,10,2,2,2,6,43,8,11,30,5,56,11,12,2,15,1,17,11,12,2,15,1,57,11,12,2,2,8,1,20,10,2,3,2,3,65,5,55,15,83,1,4,2,3,65,5,16,15,83,1,0,22,0,0,0,0,1,15,10,0,17,21,10,0,46,17,30,10,0,56,0,10,0,56,0,11,0,56,1,64,20,0,0,0,0,0,0,0,0,18,2,56,2,2,1,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,1,10,1,56,3,32,4,27,11,0,15,1,10,1,10,2,56,4,5,35,11,0,15,1,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,3,56,6,2,2,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,2,10,1,56,3,32,4,27,11,0,15,2,10,1,10,2,56,4,5,35,11,0,15,2,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,4,56,7,2,3,1,4,0,31,139,1,10,0,16,0,20,10,8,46,17,30,33,4,9,5,17,11,0,1,11,8,1,11,1,1,7,0,39,10,3,11,1,17,18,36,4,27,10,4,10,3,36,12,9,5,29,9,12,9,11,9,4,32,5,38,11,0,1,11,8,1,7,1,39,10,0,16,3,10,2,56,8,32,4,65,10,0,15,3,10,2,10,2,6,0,0,0,0,0,0,0,0,64,33,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,20,0,0,0,0,0,0,0,0,18,1,56,9,10,0,15,4,10,2,68,20,11,0,15,3,10,2,56,10,12,12,10,12,16,5,65,33,12,11,10,12,15,5,56,11,17,16,68,33,10,12,15,6,10,3,68,9,10,12,15,7,10,4,68,9,10,12,15,8,10,6,77,68,34,10,12,15,9,10,6,77,11,4,11,3,23,77,17,13,68,34,10,12,15,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,34,10,12,15,11,10,8,56,12,68,35,10,12,15,12,10,8,56,12,68,35,10,12,15,13,10,8,56,12,68,35,11,12,15,14,11,7,68,20,11,5,11,6,10,8,56,13,12,10,11,8,17,21,11,2,11,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,10,57,0,56,14,2,4,3,0,0,42,118,10,0,16,3,10,3,56,8,4,111,11,1,17,18,12,11,10,0,11,2,10,11,10,3,10,4,12,8,12,7,12,6,12,5,46,11,5,11,6,11,7,11,8,17,5,12,20,12,15,11,0,15,3,11,3,56,10,12,18,11,11,10,18,15,15,21,10,18,16,5,65,33,12,17,6,0,0,0,0,0,0,0,0,12,12,10,12,10,17,35,4,108,5,45,14,15,10,12,66,34,20,12,14,14,20,10,12,66,34,20,12,19,10,18,15,10,10,12,67,34,12,13,10,14,11,13,21,10,18,15,11,10,12,67,35,12,16,10,16,10,4,12,9,46,11,9,56,15,4,79,10,16,10,4,56,16,1,11,16,10,4,11,14,56,17,10,18,15,12,10,12,67,35,12,21,10,21,10,4,12,10,46,11,10,56,15,4,99,10,21,10,4,56,16,1,11,21,10,4,11,19,56,17,11,12,6,1,0,0,0,0,0,0,0,22,12,12,5,40,11,18,1,5,117,11,2,1,11,0,1,11,1,1,2,5,0,0,0,44,166,1,11,0,16,3,10,3,56,18,12,14,10,14,16,5,65,33,12,13,6,0,0,0,0,0,0,0,0,12,7,64,34,0,0,0,0,0,0,0,0,12,10,64,34,0,0,0,0,0,0,0,0,12,22,10,7,10,13,35,4,159,1,5,20,10,14,16,6,10,7,66,9,20,12,17,10,17,10,14,16,15,20,35,4,36,10,14,16,15,20,12,17,10,14,16,7,10,7,66,9,20,12,6,10,2,10,6,35,4,48,10,2,12,6,10,14,16,9,10,7,66,34,20,12,15,10,14,16,10,10,7,66,34,20,12,9,10,17,10,6,35,4,90,11,6,11,17,23,77,12,19,10,1,10,3,17,10,1,12,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,10,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,15,11,19,17,14,11,20,26,12,8,11,9,11,8,22,12,9,13,10,10,9,68,34,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,21,10,4,7,6,34,4,151,1,10,14,16,12,10,7,66,35,12,5,10,5,10,4,56,15,4,114,11,5,10,4,56,19,20,12,21,5,116,11,5,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,14,16,11,10,7,66,35,12,12,10,12,10,4,56,15,4,133,1,11,12,10,4,56,19,20,12,11,5,135,1,11,12,1,10,1,10,3,10,4,17,11,1,12,18,11,9,11,11,23,11,18,24,12,16,11,21,11,16,22,12,21,13,22,11,21,68,34,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,15,11,1,1,11,14,1,11,10,11,22,2,6,1,4,0,48,105,10,0,11,2,11,3,10,1,55,0,20,10,4,17,4,11,0,15,3,10,1,55,0,20,56,10,12,9,10,1,55,1,20,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,9,16,12,10,8,66,35,12,12,10,12,10,4,56,15,4,36,11,12,10,4,56,19,20,12,11,5,38,11,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,9,15,13,10,8,67,35,12,14,10,14,10,4,12,6,46,11,6,56,15,4,56,10,14,10,4,56,16,12,13,11,14,10,4,10,11,56,17,11,11,11,13,23,17,12,26,12,7,11,9,16,8,11,8,66,34,20,12,10,10,1,55,2,20,10,7,22,11,10,37,4,81,5,87,11,5,1,11,1,1,7,4,39,10,1,55,2,20,10,7,22,10,1,54,2,21,11,1,54,3,11,7,52,56,20,11,5,56,21,11,4,56,22,2,7,1,0,0,9,19,6,0,0,0,0,0,0,0,0,12,2,10,0,16,3,10,1,56,8,4,15,11,0,16,3,11,1,56,18,16,5,65,33,12,2,5,17,11,0,1,11,2,2,8,1,0,0,53,47,10,0,16,3,10,1,56,8,4,6,5,10,11,0,1,7,2,39,11,0,16,3,11,1,56,18,12,3,10,3,16,5,65,33,10,2,36,4,22,5,26,11,3,1,7,2,39,10,3,16,6,10,2,66,9,20,10,3,16,7,10,2,66,9,20,10,3,16,9,10,2,66,34,20,11,3,16,14,11,2,66,20,20,2,9,1,0,0,54,97,64,33,0,0,0,0,0,0,0,0,12,5,64,34,0,0,0,0,0,0,0,0,12,14,64,20,0,0,0,0,0,0,0,0,12,9,10,0,16,3,10,3,56,8,4,87,11,2,17,18,12,6,10,0,11,1,11,6,10,3,10,4,17,5,12,11,1,11,0,16,3,11,3,56,18,12,10,10,10,16,5,65,33,12,8,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,84,5,38,10,10,16,13,10,7,66,35,12,13,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,10,13,10,4,56,15,4,55,11,13,10,4,56,19,20,12,12,5,57,11,13,1,13,5,10,10,16,5,10,7,66,33,20,68,33,13,14,14,11,10,7,66,34,20,11,12,23,68,34,13,9,10,10,16,14,10,7,66,20,20,68,20,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,33,11,10,1,5,93,11,1,1,11,0,1,11,2,1,11,5,11,14,11,9,2,2,1,2,2,2,3,2,4,2,5,1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,1,11,1,1,0,1,0,2,0,3,0,4,16,22,17,22,18,22,19,22,0,50,0],"lending":[161,28,235,11,6,0,0,0,10,1,0,22,2,22,52,3,74,130,1,4,204,1,38,5,242,1,222,2,7,208,4,238,3,8,190,8,96,6,158,9,10,10,168,9,49,12,217,9,201,4,0,26,0,25,0,30,0,34,0,39,2,32,1,14,1,15,1,19,1,41,0,44,0,3,3,0,0,11,3,0,0,0,3,0,0,8,3,0,0,5,3,0,1,4,12,0,3,6,12,1,0,1,4,9,12,0,5,7,8,0,6,1,8,0,7,2,12,1,0,1,9,10,2,0,0,46,0,1,0,0,16,2,1,1,0,0,47,3,1,1,0,0,13,4,1,1,0,0,35,5,1,1,0,0,29,6,1,2,0,0,1,43,11,1,0,2,20,22,1,1,0,2,21,19,1,1,0,2,22,32,33,2,0,0,2,23,22,28,1,0,2,24,22,16,1,0,3,16,17,1,1,0,3,17,35,1,1,0,3,31,18,16,1,0,3,42,18,16,1,0,3,47,23,1,1,0,4,33,0,7,0,7,45,15,16,1,0,8,18,12,1,1,3,9,37,9,10,0,10,38,13,14,1,0,21,12,18,12,12,12,14,12,8,12,19,20,11,12,15,12,16,12,19,24,7,12,19,26,10,12,19,29,9,31,15,34,16,34,13,34,19,36,1,6,8,7,0,8,6,8,9,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,5,7,8,11,9,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,5,7,8,5,7,8,11,7,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,7,8,11,8,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,11,12,6,8,9,6,8,8,7,8,7,2,7,11,6,1,9,0,2,7,11,6,1,9,1,11,10,1,9,0,5,3,7,8,5,7,8,11,1,1,5,3,3,3,5,11,10,1,9,0,1,6,8,11,1,5,5,7,8,5,6,8,9,7,8,7,2,5,1,9,0,3,11,10,1,9,0,3,7,8,11,1,11,10,1,9,0,1,6,11,10,1,9,0,1,3,3,7,11,6,1,9,0,11,10,1,9,0,7,8,11,2,6,11,6,1,9,0,3,5,6,8,9,7,8,7,2,5,15,1,8,0,6,3,3,3,3,3,5,6,6,8,9,6,8,8,7,8,7,2,5,15,4,7,11,6,1,9,0,3,5,7,8,11,1,8,1,3,3,3,5,1,8,2,8,3,3,15,3,3,3,5,11,10,1,9,0,1,15,1,8,3,14,3,3,3,3,15,15,3,3,3,3,3,5,11,10,1,9,0,15,2,9,0,9,1,7,6,8,9,6,8,8,7,8,7,5,2,2,15,3,15,15,15,1,9,1,2,7,11,6,1,9,0,3,1,8,4,11,66,111,114,114,111,119,69,118,101,110,116,5,67,108,111,99,107,4,67,111,105,110,12,68,101,112,111,115,105,116,69,118,101,110,116,9,73,110,99,101,110,116,105,118,101,20,76,105,113,117,105,100,97,116,105,111,110,67,97,108,108,69,118,101,110,116,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,112,97,121,69,118,101,110,116,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,13,87,105,116,104,100,114,97,119,69,118,101,110,116,6,97,109,111,117,110,116,6,98,111,114,114,111,119,5,99,108,111,99,107,4,99,111,105,110,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,9,105,110,99,101,110,116,105,118,101,7,108,101,110,100,105,110,103,16,108,105,113,117,105,100,97,116,101,95,97,109,111,117,110,116,14,108,105,113,117,105,100,97,116,101,95,117,115,101,114,16,108,105,113,117,105,100,97,116,105,111,110,95,99,97,108,108,5,108,111,103,105,99,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,5,112,97,117,115,101,4,112,111,111,108,5,114,101,112,97,121,7,114,101,115,101,114,118,101,6,115,101,110,100,101,114,10,115,112,108,105,116,95,99,111,105,110,7,115,116,111,114,97,103,101,2,116,111,10,116,120,95,99,111,110,116,101,120,116,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,13,117,112,100,97,116,101,95,114,101,119,97,114,100,5,117,116,105,108,115,5,118,97,108,117,101,15,119,104,101,110,95,110,111,116,95,112,97,117,115,101,100,8,119,105,116,104,100,114,97,119,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,41,160,0,0,0,0,0,0,0,2,3,36,2,37,5,12,3,1,2,4,36,2,37,5,40,5,12,3,2,2,3,36,2,37,5,12,3,3,2,3,36,2,37,5,12,3,4,2,4,36,2,37,5,28,5,27,3,0,0,0,0,1,8,11,0,17,17,32,4,5,5,7,7,0,39,2,1,1,4,0,8,45,10,1,46,17,0,10,7,46,17,20,12,11,11,6,10,0,10,1,10,3,10,11,17,6,11,4,11,5,10,7,56,0,12,12,14,12,56,1,12,9,10,2,11,12,11,7,56,2,11,2,10,9,12,8,46,11,8,56,3,12,10,11,0,11,1,10,3,10,11,11,10,77,56,4,11,3,11,11,11,9,18,0,56,5,2,2,1,4,0,21,50,10,2,46,17,0,10,8,46,17,20,12,14,11,7,10,0,10,2,10,4,10,14,17,6,10,3,11,5,12,9,46,11,9,56,3,12,13,11,0,11,1,11,2,10,4,11,14,11,13,77,56,6,12,11,10,3,11,11,12,10,46,11,10,56,7,12,12,11,3,10,12,10,6,10,8,56,8,11,4,11,8,46,17,20,11,6,11,12,18,1,56,9,2,3,1,4,0,25,35,10,2,46,17,0,10,6,46,17,20,12,9,10,3,10,5,12,7,46,11,7,56,3,12,8,11,0,11,1,11,2,10,4,10,9,11,8,77,56,10,11,3,10,5,11,9,10,6,56,8,11,4,11,6,46,17,20,11,5,18,2,56,11,2,4,1,4,0,27,65,10,2,46,17,0,10,7,46,17,20,12,14,11,5,11,6,10,7,56,0,12,15,14,15,56,1,12,13,10,3,11,15,10,7,56,2,10,3,10,13,12,8,46,11,8,56,3,12,12,11,0,11,1,11,2,10,4,10,14,11,12,77,56,12,12,10,10,3,11,10,52,12,9,46,11,9,56,7,12,11,10,11,6,0,0,0,0,0,0,0,0,36,4,53,11,3,10,11,11,14,10,7,56,8,5,55,11,3,1,11,4,11,7,46,17,20,11,13,11,11,23,18,3,56,13,2,5,1,4,0,30,90,10,2,46,17,0,10,11,46,17,20,12,23,11,10,10,0,10,2,10,5,10,8,17,6,11,7,11,9,10,11,56,0,12,24,14,24,56,1,12,18,10,4,11,24,10,11,56,2,10,4,11,18,12,12,46,11,12,56,3,12,21,11,0,11,1,11,2,10,8,10,5,11,3,11,21,77,56,14,12,25,12,17,12,16,10,4,11,17,52,12,13,46,11,13,56,7,12,20,11,4,11,20,10,23,10,11,56,8,10,6,11,16,52,12,14,46,11,14,56,15,12,19,10,6,10,19,10,23,11,11,56,16,10,6,11,25,52,12,15,46,11,15,56,15,12,22,11,6,10,22,56,17,11,5,11,23,11,8,11,19,11,22,22,18,4,56,18,2,0],"logic":[161,28,235,11,6,0,0,0,10,1,0,20,2,20,12,3,32,220,2,4,252,2,12,5,136,3,214,2,7,222,5,205,9,8,171,15,128,1,6,171,16,60,12,231,16,222,18,15,197,35,2,0,42,0,11,0,53,0,73,0,48,0,52,3,45,1,74,2,3,2,12,2,2,12,0,6,1,8,0,9,0,8,0,0,18,0,1,1,0,0,21,2,3,1,0,0,17,2,1,1,0,0,20,2,4,1,0,0,19,5,6,2,0,0,0,57,7,1,0,0,56,8,1,0,0,55,9,1,0,0,36,10,1,0,0,15,10,1,0,0,35,10,1,0,0,14,10,1,0,0,39,11,12,0,0,64,13,14,0,0,63,15,4,0,0,16,15,4,0,0,62,11,4,0,0,65,11,4,0,0,67,16,4,0,0,61,16,4,0,0,60,17,4,0,0,66,17,4,0,0,38,17,12,0,0,40,17,12,0,0,8,18,19,0,1,4,44,4,0,1,5,9,4,0,1,6,22,4,0,1,7,22,4,0,1,9,21,4,0,1,10,44,4,0,2,14,10,1,0,2,15,10,1,0,2,22,31,4,0,2,23,9,32,0,2,24,9,22,0,2,25,9,22,0,2,26,31,3,0,2,27,9,6,0,2,28,31,28,0,2,29,27,28,0,2,30,9,22,0,2,31,9,4,0,2,32,39,40,0,2,33,17,22,0,2,34,34,1,0,2,35,10,1,0,2,36,10,1,0,2,37,21,1,0,2,50,17,1,0,2,51,17,1,0,2,55,34,1,0,2,56,33,1,0,2,58,17,1,0,2,59,17,1,0,3,68,21,1,1,0,3,69,21,1,1,0,3,70,25,1,2,0,0,3,71,21,1,1,0,3,72,21,1,1,0,4,46,1,4,0,4,47,22,4,0,4,49,22,4,0,5,44,22,4,0,7,13,46,12,1,0,8,43,1,4,0,9,54,30,3,0,56,20,59,20,55,20,58,20,57,24,64,28,5,6,8,2,7,8,0,2,5,15,0,6,6,8,2,6,8,1,7,8,0,2,5,15,1,3,1,15,7,6,8,2,6,8,1,7,8,0,5,2,2,15,3,15,15,15,2,6,8,2,7,8,0,3,6,8,2,7,8,0,2,2,7,8,0,2,4,7,8,0,2,5,15,4,6,8,2,6,8,1,7,8,0,5,1,1,4,6,8,2,6,8,1,7,8,0,10,5,1,10,15,4,6,8,2,7,8,0,6,8,1,5,5,6,8,2,6,8,1,7,8,0,2,5,3,7,8,0,2,5,7,6,8,2,7,8,0,6,8,1,5,2,2,15,6,15,15,15,15,15,1,1,9,0,3,7,8,0,2,15,2,15,15,6,15,15,1,15,15,15,2,9,0,9,1,4,7,8,0,2,2,15,2,2,2,1,6,8,0,1,2,18,2,15,15,15,15,3,15,15,3,15,15,15,15,15,15,15,15,15,1,6,8,2,2,6,8,0,2,5,15,15,15,15,15,6,7,8,0,2,15,15,3,15,4,7,8,0,2,15,15,4,15,3,3,10,15,1,5,4,15,15,15,15,9,5,6,2,15,15,10,2,3,3,15,15,2,6,8,0,5,2,10,2,10,2,9,5,2,6,2,15,10,2,3,3,15,15,7,5,6,2,3,3,15,10,2,15,3,2,15,2,4,6,8,2,6,8,1,15,2,2,5,10,2,2,6,10,9,0,6,9,0,18,2,15,15,15,15,1,15,15,15,15,15,2,15,15,15,15,15,15,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,7,105,115,95,108,111,97,110,7,108,101,110,100,105,110,103,5,108,111,103,105,99,3,109,97,120,3,109,105,110,6,111,114,97,99,108,101,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,9,115,97,102,101,95,109,97,116,104,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,19,117,112,100,97,116,101,95,115,116,97,116,101,95,111,102,95,97,108,108,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,24,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,95,98,97,116,99,104,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,6,118,101,99,116,111,114,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,33,78,0,0,0,0,0,0,3,8,34,78,0,0,0,0,0,0,3,8,35,78,0,0,0,0,0,0,3,8,36,78,0,0,0,0,0,0,3,8,37,78,0,0,0,0,0,0,3,8,38,78,0,0,0,0,0,0,0,3,0,0,1,26,11,0,10,1,17,5,10,1,10,2,10,4,56,0,10,1,10,2,10,3,11,4,17,8,10,1,10,2,10,3,17,22,32,4,22,10,1,10,2,11,3,17,53,11,1,11,2,17,7,2,1,3,0,0,22,92,10,2,10,3,10,4,17,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,16,11,2,1,11,1,1,11,0,1,7,4,39,10,0,10,2,17,5,10,2,10,3,10,5,56,1,10,2,10,3,10,4,17,20,12,7,11,5,10,7,17,63,12,6,10,2,10,3,10,4,10,6,17,9,11,0,11,1,10,2,10,4,17,12,4,44,5,48,11,2,1,7,0,39,10,6,10,7,33,4,61,10,2,10,3,10,4,17,22,4,61,10,2,10,3,10,4,17,49,10,7,10,6,36,4,86,10,7,10,6,23,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,4,86,10,2,10,3,11,7,10,6,23,17,48,10,2,10,3,10,4,17,22,4,86,10,2,10,3,11,4,17,49,11,2,11,3,17,7,11,6,52,2,2,3,0,0,1,37,10,0,10,2,17,5,10,2,10,3,10,5,56,2,10,2,10,3,10,4,11,5,17,10,10,2,10,3,10,4,17,23,32,4,22,10,2,10,3,10,4,17,54,11,0,11,1,10,2,11,4,17,12,4,29,5,33,11,2,1,7,0,39,11,2,11,3,17,7,2,3,3,0,0,6,58,10,2,10,3,10,4,17,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,14,11,2,1,11,0,1,7,5,39,11,0,10,2,17,5,10,2,10,3,10,5,56,3,10,2,10,3,10,4,17,21,12,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,5,12,8,10,6,10,5,35,4,40,10,6,12,8,11,5,10,6,23,12,7,10,2,10,3,10,4,10,8,17,11,11,8,11,6,33,4,53,10,2,10,3,11,4,17,50,11,2,11,3,17,7,11,7,2,4,3,0,0,23,92,10,2,10,5,10,3,17,23,4,6,5,14,11,2,1,11,1,1,11,0,1,7,3,39,10,2,10,4,10,3,17,22,4,20,5,28,11,2,1,11,1,1,11,0,1,7,2,39,10,0,10,2,17,5,10,2,10,5,10,4,10,6,56,4,10,0,10,1,10,2,10,3,17,12,32,4,44,5,52,11,2,1,11,1,1,11,0,1,7,1,39,11,0,10,2,11,1,10,3,10,4,10,5,11,6,17,24,12,9,12,8,12,12,12,7,12,11,12,10,10,2,10,5,10,3,11,11,17,11,10,2,10,4,10,3,11,10,17,9,11,9,4,82,10,2,10,5,11,3,17,50,10,2,11,4,17,7,11,2,11,5,17,7,11,7,11,8,11,12,2,5,0,0,0,26,25,10,1,46,17,40,12,2,49,0,12,3,10,3,10,2,35,4,20,5,11,10,0,10,1,10,3,17,6,11,3,49,1,22,12,3,5,6,11,1,1,11,0,1,2,6,0,0,0,29,97,11,0,17,66,12,8,10,1,10,2,12,3,46,11,3,17,37,12,11,10,8,11,11,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,18,10,1,10,2,17,36,12,4,12,6,10,1,10,2,17,35,12,5,12,7,10,18,11,7,17,28,10,6,17,62,12,13,11,18,11,5,17,27,10,4,17,62,12,12,10,1,10,2,17,34,1,12,14,1,1,1,10,1,10,2,17,41,12,19,12,20,10,19,10,12,10,4,23,17,62,12,9,11,20,10,13,11,6,23,17,62,12,10,11,9,10,12,17,61,12,15,11,10,10,13,17,61,12,17,11,19,10,12,11,4,23,17,62,11,14,17,62,10,12,17,61,12,16,10,1,10,2,11,12,11,13,11,8,10,16,17,52,11,1,11,2,11,17,11,15,11,16,22,17,45,2,7,0,0,0,22,15,10,0,10,1,17,26,12,2,10,0,10,1,10,2,17,29,12,3,11,0,11,1,11,2,11,3,17,51,2,8,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,47,2,9,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,32,2,10,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,46,2,11,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,31,2,12,1,0,0,1,8,11,0,11,2,11,1,11,3,17,14,17,60,38,2,13,1,0,0,35,37,14,3,65,36,12,6,6,0,0,0,0,0,0,0,0,12,5,64,4,0,0,0,0,0,0,0,0,12,7,10,5,10,6,35,4,29,5,12,10,0,10,2,10,1,14,3,10,5,66,36,20,17,14,12,4,13,7,11,4,68,4,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,7,11,2,1,11,1,1,11,0,1,11,7,2,14,1,0,0,37,33,10,0,10,2,10,1,10,3,17,16,12,6,10,0,10,1,10,2,10,3,17,15,12,5,11,0,11,2,11,1,11,3,17,17,12,7,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,29,11,6,11,7,17,61,11,5,17,62,12,4,5,31,17,65,12,4,11,4,2,15,1,0,0,38,72,10,1,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,6,0,0,0,0,0,0,0,0,12,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,10,9,10,10,35,4,56,5,22,14,8,10,9,66,28,12,5,10,1,10,5,20,17,38,12,11,1,1,10,0,10,2,10,1,11,5,20,10,3,17,19,12,12,11,6,10,12,11,11,17,62,22,12,6,11,7,11,12,22,12,7,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,17,11,1,1,11,2,1,11,0,1,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,11,6,11,7,17,61,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,16,1,0,0,41,59,10,2,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,6,0,0,0,0,0,0,0,0,12,9,10,9,10,10,35,4,51,5,20,14,8,10,9,66,28,12,6,10,2,10,6,20,12,5,46,11,5,17,33,12,11,10,0,10,1,10,2,11,6,20,10,3,17,19,12,7,11,12,11,7,11,11,17,62,22,12,12,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,15,11,2,1,11,1,1,11,0,1,11,12,2,17,1,0,0,42,49,10,2,10,3,12,4,46,11,4,17,43,12,9,1,14,9,65,28,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,41,5,20,14,9,10,6,66,28,12,5,10,0,10,1,10,2,11,5,20,10,3,17,18,12,8,11,10,11,8,22,12,10,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,15,11,2,1,11,1,1,11,0,1,11,10,2,18,1,0,0,43,18,10,2,10,3,11,4,17,21,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,19,1,0,0,43,18,10,2,10,3,11,4,17,20,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,20,1,0,0,22,15,10,0,10,1,11,2,17,44,1,12,3,11,0,11,1,17,36,1,12,4,11,3,11,4,17,62,2,21,1,0,0,22,15,10,0,10,1,11,2,17,44,12,3,1,11,0,11,1,17,36,12,4,1,11,3,11,4,17,62,2,22,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,1,12,4,14,4,14,1,56,5,2,23,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,12,4,1,14,4,14,1,56,5,2,24,0,0,0,47,113,10,1,10,4,17,38,1,12,15,12,16,10,0,10,2,10,1,10,4,10,3,17,19,11,16,17,62,12,20,10,0,10,2,10,1,10,5,11,3,17,18,12,19,9,12,12,10,19,10,20,35,4,32,11,19,12,20,8,12,12,10,1,10,5,12,7,46,11,7,17,39,12,18,10,0,10,2,11,6,11,18,17,30,12,21,10,21,10,20,36,4,54,11,21,10,20,23,12,11,5,58,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,11,21,12,20,10,20,11,15,17,62,12,8,11,1,10,4,17,42,12,22,10,8,11,22,17,62,12,23,10,20,10,23,23,12,17,10,0,10,2,10,20,10,4,17,25,12,13,10,0,10,2,11,20,10,5,17,25,12,14,10,0,10,2,11,17,10,4,17,25,12,9,10,0,10,2,11,23,11,4,17,25,12,24,11,0,11,2,11,11,11,8,22,11,5,17,25,12,10,11,13,11,14,11,9,11,24,11,10,11,12,2,0,41,0],"pool":[161,28,235,11,6,0,0,0,14,1,0,18,2,18,54,3,72,145,1,4,217,1,30,5,247,1,203,1,7,194,3,145,4,8,211,7,96,6,179,8,20,10,199,8,67,11,138,9,2,12,140,9,146,3,13,158,12,6,14,164,12,6,15,170,12,4,0,37,1,13,1,47,2,14,2,15,2,23,2,36,2,44,2,46,0,2,12,1,0,1,0,3,12,0,0,5,3,0,0,4,3,0,0,6,3,0,0,7,3,0,1,8,7,0,2,10,7,0,3,0,4,1,0,1,4,1,12,1,0,1,6,11,4,0,8,9,2,0,0,28,0,1,0,0,17,2,1,1,0,0,20,3,1,1,0,0,50,4,1,1,0,0,21,5,1,1,0,0,52,6,1,1,0,0,51,7,1,1,0,0,26,8,9,1,0,0,16,10,11,0,0,35,12,11,1,0,0,48,12,11,1,0,2,25,1,26,1,0,2,30,26,27,0,3,31,25,11,1,0,3,42,29,19,1,0,3,49,32,11,1,0,3,53,1,19,1,0,4,24,30,24,1,0,4,29,24,19,1,0,4,49,23,11,1,0,5,22,18,1,1,3,6,33,0,13,0,7,38,17,1,1,12,7,41,18,1,1,8,8,40,14,15,0,22,16,16,18,23,20,20,21,19,18,18,18,13,18,11,18,20,28,14,18,17,18,20,31,22,24,15,18,7,18,1,7,8,11,0,3,6,8,1,2,7,8,11,3,7,11,0,1,9,0,11,9,1,9,0,7,8,11,4,7,11,0,1,9,0,3,5,7,8,11,2,7,11,0,1,9,0,3,5,7,8,1,7,11,0,1,9,0,3,5,7,8,11,5,6,8,1,7,11,0,1,9,0,3,5,7,8,11,1,6,11,0,1,9,0,1,2,3,3,2,2,1,3,2,6,11,0,1,9,0,3,1,8,10,1,6,8,11,1,5,1,8,1,2,9,0,5,1,9,0,1,11,8,1,9,0,1,11,0,1,9,0,1,8,2,2,11,8,1,9,0,3,1,6,11,9,1,9,0,1,11,9,1,9,0,2,7,11,8,1,9,0,11,8,1,9,0,1,8,7,1,8,6,1,8,4,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,11,1,8,5,1,6,11,8,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,19,80,111,111,108,66,97,108,97,110,99,101,82,101,103,105,115,116,101,114,10,80,111,111,108,67,114,101,97,116,101,11,80,111,111,108,68,101,112,111,115,105,116,12,80,111,111,108,87,105,116,104,100,114,97,119,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,7,99,114,101,97,116,111,114,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,2,105,100,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,7,108,101,110,100,105,110,103,3,110,101,119,10,110,101,119,95,97,109,111,117,110,116,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,9,114,101,99,105,112,105,101,110,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,7,115,116,111,114,97,103,101,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,4,122,101,114,111,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,17,164,0,0,0,0,0,0,3,8,18,164,0,0,0,0,0,0,0,2,4,27,8,10,14,11,8,1,9,0,45,11,8,1,9,0,19,2,1,2,2,27,8,10,18,5,2,2,1,18,5,3,2,4,40,5,12,3,34,3,37,8,6,4,2,3,40,5,12,3,37,8,6,5,2,4,40,5,39,5,12,3,37,8,6,0,18,0,0,0,0,1,11,10,0,17,21,10,0,46,17,24,18,1,11,0,46,17,24,56,0,2,1,3,0,0,1,13,10,2,17,21,56,1,56,1,11,1,57,0,56,2,11,2,46,17,24,18,2,56,3,2,2,3,0,0,22,20,14,1,56,4,12,4,11,1,56,5,12,3,11,0,54,0,11,3,56,6,1,11,2,46,17,24,11,4,56,7,17,12,18,4,56,8,2,3,3,0,0,24,20,11,0,54,0,10,1,56,9,10,3,56,10,12,4,11,3,46,17,24,10,2,11,1,56,7,17,12,18,5,56,11,11,4,11,2,56,12,2,4,3,0,0,19,22,10,0,55,0,56,13,10,1,38,4,7,5,11,11,0,1,7,1,39,10,0,54,0,11,1,56,9,12,2,11,0,54,1,11,2,56,6,1,2,5,1,0,0,1,22,10,1,55,1,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,1,11,2,56,9,11,4,56,10,11,3,56,12,2,6,3,0,0,1,22,10,1,55,0,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,0,11,2,56,9,11,4,56,10,11,3,56,12,2,7,1,0,0,1,4,11,0,55,2,20,2,8,1,0,0,1,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,9,1,0,0,9,8,11,0,56,14,12,2,11,1,11,2,49,9,17,8,2,10,1,0,0,9,8,11,0,56,14,12,2,11,1,49,9,11,2,17,8,2,0,1,0,2,0,3,0,18,1,18,2,18,0,32,0,43,0],"ray_math":[161,28,235,11,6,0,0,0,7,1,0,4,3,4,55,5,59,8,7,67,101,8,168,1,64,6,232,1,200,1,12,176,3,168,5,0,6,1,0,0,4,0,1,0,0,9,0,1,0,0,1,0,1,0,0,2,0,1,0,0,11,2,1,0,0,10,2,1,0,0,7,2,1,0,0,5,2,1,0,0,8,1,1,0,0,12,1,1,0,1,3,0,1,0,0,1,15,2,15,15,1,1,7,97,100,100,114,101,115,115,8,104,97,108,102,95,114,97,121,8,104,97,108,102,95,119,97,100,3,109,97,120,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,10,114,97,121,95,116,111,95,119,97,100,3,119,97,100,7,119,97,100,95,100,105,118,7,119,97,100,95,109,117,108,10,119,97,100,95,116,111,95,114,97,121,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,100,167,179,182,224,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,178,211,89,91,240,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,77,4,0,0,0,0,0,0,3,8,78,4,0,0,0,0,0,0,3,8,79,4,0,0,0,0,0,0,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,0,2,2,1,0,0,0,2,7,3,2,3,1,0,0,0,2,7,1,2,4,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,1,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,1,22,7,0,26,2,5,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,0,26,37,4,20,5,22,7,5,39,11,0,7,0,24,11,2,22,11,1,26,2,6,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,3,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,3,22,7,2,26,2,7,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,2,26,37,4,20,5,22,7,5,39,11,0,7,2,24,11,2,22,11,1,26,2,8,1,0,0,2,19,7,4,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,1,10,1,11,0,22,12,2,10,2,11,1,38,4,13,5,15,7,6,39,11,2,7,4,26,2,9,1,0,0,1,15,10,0,7,4,24,12,1,10,1,7,4,26,11,0,33,4,11,5,13,7,5,39,11,1,2,0],"safe_math":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,30,5,32,6,7,38,34,8,72,32,6,104,50,12,154,1,163,2,0,5,0,0,0,1,0,0,6,0,1,0,0,4,0,1,0,0,1,0,1,0,0,3,0,1,0,0,2,0,1,0,2,15,15,1,15,0,3,97,100,100,3,100,105,118,3,109,105,110,3,109,111,100,3,109,117,108,9,115,97,102,101,95,109,97,116,104,3,115,117,98,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,3,8,233,3,0,0,0,0,0,0,3,8,234,3,0,0,0,0,0,0,3,8,235,3,0,0,0,0,0,0,3,8,236,3,0,0,0,0,0,0,3,8,237,3,0,0,0,0,0,0,0,1,0,0,1,13,10,0,11,1,22,12,2,10,2,11,0,38,4,9,5,11,7,0,39,11,2,2,1,1,0,0,2,11,10,1,10,0,37,4,5,5,7,7,1,39,11,0,11,1,23,2,2,1,0,0,1,21,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,10,1,24,12,2,10,2,11,0,26,11,1,33,4,17,5,19,7,2,39,11,2,2,3,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,5,5,7,7,3,39,11,0,11,1,26,2,4,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,4,39,11,0,11,1,25,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,0],"storage":[161,28,235,11,6,0,0,0,12,1,0,29,2,29,92,3,121,144,3,4,137,4,54,5,191,4,153,3,7,216,7,131,16,8,219,23,96,6,187,24,93,10,152,25,164,1,12,188,26,186,19,13,246,45,66,15,184,46,2,0,120,0,90,0,94,1,22,1,131,1,1,141,1,2,30,2,31,2,47,2,85,2,123,2,127,2,130,1,0,4,12,0,0,11,12,0,0,10,12,0,0,9,4,0,0,20,4,0,0,8,5,0,0,19,5,0,0,15,4,0,0,0,4,0,0,3,4,0,0,12,3,0,0,5,3,0,1,6,12,1,0,1,1,7,12,0,3,13,7,0,4,17,7,0,6,1,8,0,7,2,12,1,0,1,9,18,4,0,10,14,12,2,7,1,4,1,12,16,2,0,0,73,0,1,0,0,144,1,2,1,0,0,143,1,3,1,0,0,74,4,1,1,0,0,115,5,1,0,0,117,6,1,0,0,107,6,1,0,0,112,6,1,0,0,118,6,1,0,0,106,6,1,0,0,113,6,1,0,0,108,6,1,0,0,116,6,1,0,0,114,6,1,0,0,110,6,1,0,0,109,6,1,0,0,111,6,1,0,0,102,2,1,1,0,0,88,2,7,0,0,59,2,8,0,0,64,9,10,0,0,58,11,8,0,0,52,11,12,0,0,60,13,14,0,0,50,13,14,0,0,53,13,15,0,0,55,13,15,0,0,61,13,15,0,0,65,16,15,0,0,56,11,17,0,0,49,11,14,0,0,63,13,14,0,0,62,11,14,0,0,51,13,18,0,0,57,13,19,0,0,133,1,20,1,0,0,134,1,21,1,0,0,68,20,1,0,0,70,22,1,0,0,44,22,1,0,0,69,22,1,0,0,43,22,1,0,0,67,23,1,0,0,42,23,1,0,0,71,24,1,0,0,136,1,16,1,0,0,97,16,1,0,0,135,1,16,1,0,0,96,16,1,0,0,146,1,25,1,1,0,0,45,3,1,0,1,36,43,1,1,0,1,132,1,62,17,1,0,1,145,1,63,1,1,0,2,93,1,14,0,4,48,1,38,1,0,4,75,38,12,0,5,35,57,7,1,0,5,72,57,59,1,0,5,95,60,36,1,0,6,125,40,17,0,7,54,42,8,1,0,8,46,36,1,1,3,9,84,0,26,0,10,21,41,1,2,7,4,10,25,49,50,2,7,4,10,28,46,47,2,7,4,10,35,49,7,2,7,4,10,84,0,33,2,7,4,10,95,46,55,2,7,4,11,91,30,1,1,12,11,119,36,1,1,8,12,105,27,28,0,70,29,70,31,68,32,68,34,71,35,17,36,55,36,68,39,64,32,61,36,51,36,62,44,66,32,65,32,67,34,65,34,67,39,65,39,69,39,64,39,64,34,66,34,57,8,58,8,59,8,52,36,53,36,1,7,8,20,0,1,6,8,2,2,6,8,1,7,8,2,20,6,8,1,6,8,13,6,8,16,7,8,2,2,1,15,15,15,15,15,15,15,15,15,15,15,15,6,11,17,1,9,0,7,8,20,3,6,8,0,7,8,2,1,4,6,8,0,7,8,2,2,15,1,1,1,2,2,6,8,2,5,2,10,2,10,2,2,6,8,2,2,1,8,14,2,7,8,2,2,1,15,2,15,15,3,7,8,2,2,5,1,3,5,15,15,15,15,15,3,15,15,15,4,7,8,2,2,15,15,6,7,8,2,2,15,15,3,15,4,7,8,2,2,5,15,3,7,8,7,5,15,3,7,8,2,2,15,8,6,8,1,6,8,13,7,8,2,2,7,11,12,1,9,0,3,5,7,8,20,1,8,18,1,6,8,20,1,5,1,8,1,2,9,0,5,1,8,0,2,2,8,3,1,11,19,2,9,0,9,1,2,5,8,4,1,8,2,1,9,0,18,2,15,15,15,8,7,8,7,3,8,8,8,9,2,8,14,1,15,15,15,2,2,8,3,1,8,15,2,5,15,1,6,8,16,3,7,11,19,2,9,0,9,1,9,0,9,1,1,6,11,17,1,9,0,3,6,8,13,2,7,8,20,1,8,11,1,7,8,3,2,7,11,19,2,9,0,9,1,9,0,1,7,9,1,3,2,2,8,14,2,6,11,19,2,9,0,9,1,9,0,1,6,9,1,1,6,8,4,1,6,8,3,3,15,6,8,3,15,3,7,8,7,7,8,3,7,8,7,1,9,1,3,10,2,8,4,7,8,4,2,6,10,9,0,6,9,0,2,3,7,8,4,2,1,3,2,7,10,9,0,3,5,2,3,7,15,3,3,2,6,11,12,1,9,0,3,5,6,8,13,7,11,12,1,9,0,3,5,7,8,20,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,12,67,111,105,110,77,101,116,97,100,97,116,97,18,76,105,113,117,105,100,97,116,105,111,110,70,97,99,116,111,114,115,8,79,119,110,101,114,67,97,112,6,80,97,117,115,101,100,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,23,82,101,115,101,114,118,101,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,11,82,101,115,101,114,118,101,68,97,116,97,7,83,116,111,114,97,103,101,15,83,116,111,114,97,103,101,65,100,109,105,110,67,97,112,26,83,116,111,114,97,103,101,67,111,110,102,105,103,117,114,97,116,111,114,83,101,116,116,105,110,103,6,83,116,114,105,110,103,5,84,97,98,108,101,12,84,111,107,101,110,66,97,108,97,110,99,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,20,85,115,101,114,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,8,85,115,101,114,73,110,102,111,3,97,100,100,5,97,115,99,105,105,9,98,97,115,101,95,114,97,116,101,5,98,111,110,117,115,6,98,111,114,114,111,119,14,98,111,114,114,111,119,95,98,97,108,97,110,99,101,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,5,99,108,111,99,107,4,99,111,105,110,9,99,111,105,110,95,116,121,112,101,11,99,111,108,108,97,116,101,114,97,108,115,12,99,111,110,102,105,103,117,114,97,116,111,114,8,99,111,110,116,97,105,110,115,11,99,114,101,97,116,101,95,112,111,111,108,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,20,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,114,97,116,101,4,100,97,116,97,16,100,101,99,114,101,97,115,101,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,12,100,101,115,116,111,114,121,95,117,115,101,114,4,101,109,105,116,5,101,118,101,110,116,3,103,101,116,13,103,101,116,95,97,115,115,101,116,95,108,116,118,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,13,103,101,116,95,99,111,105,110,95,116,121,112,101,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,12,103,101,116,95,100,101,99,105,109,97,108,115,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,20,103,101,116,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,16,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,114,101,115,101,114,118,101,11,105,110,116,111,95,115,116,114,105,110,103,11,105,115,95,105,115,111,108,97,116,101,100,20,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,5,108,111,97,110,115,5,108,111,103,105,99,3,108,116,118,10,109,117,108,116,105,112,108,105,101,114,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,111,114,97,99,108,101,95,105,100,5,112,97,117,115,101,6,112,97,117,115,101,100,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,105,111,3,114,97,121,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,14,114,101,115,101,114,118,101,95,102,97,99,116,111,114,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,97,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,98,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,99,18,114,101,115,101,114,118,101,95,118,97,108,105,100,97,116,105,111,110,8,114,101,115,101,114,118,101,115,14,114,101,115,101,114,118,101,115,95,99,111,117,110,116,6,115,101,110,100,101,114,13,115,101,116,95,98,97,115,101,95,114,97,116,101,14,115,101,116,95,98,111,114,114,111,119,95,99,97,112,24,115,101,116,95,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,98,111,110,117,115,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,114,97,116,105,111,25,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,7,115,101,116,95,108,116,118,14,115,101,116,95,109,117,108,116,105,112,108,105,101,114,23,115,101,116,95,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,115,101,116,95,112,97,117,115,101,18,115,101,116,95,114,101,115,101,114,118,101,95,102,97,99,116,111,114,14,115,101,116,95,115,117,112,112,108,121,95,99,97,112,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,7,115,116,111,114,97,103,101,14,115,117,112,112,108,121,95,98,97,108,97,110,99,101,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,9,116,104,114,101,115,104,111,108,100,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,9,117,115,101,114,95,105,110,102,111,10,117,115,101,114,95,115,116,97,116,101,5,117,115,101,114,115,5,118,97,108,117,101,6,118,101,99,116,111,114,7,118,101,114,115,105,111,110,15,118,101,114,115,105,111,110,95,109,105,103,114,97,116,101,20,118,101,114,115,105,111,110,95,118,101,114,105,102,105,99,97,116,105,111,110,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,3,0,0,0,0,0,0,0,3,8,248,167,0,0,0,0,0,0,3,8,249,167,0,0,0,0,0,0,3,8,250,167,0,0,0,0,0,0,3,8,251,167,0,0,0,0,0,0,3,8,252,167,0,0,0,0,0,0,3,8,253,167,0,0,0,0,0,0,3,8,254,167,0,0,0,0,0,0,3,8,255,167,0,0,0,0,0,0,2,1,255,0,2,1,66,8,18,1,2,1,66,8,18,2,2,7,66,8,18,142,1,3,89,1,103,11,19,2,2,8,3,104,2,139,1,10,5,137,1,11,19,2,5,8,4,3,2,21,66,2,87,2,32,8,14,76,1,122,15,27,15,40,15,38,15,39,15,37,15,121,8,7,26,8,7,78,3,82,15,129,1,15,128,1,15,29,8,8,79,8,9,99,15,100,15,101,15,4,2,2,33,10,2,80,10,2,5,2,1,41,15,6,2,1,41,15,7,2,2,138,1,11,19,2,5,15,126,15,8,2,5,23,15,83,15,77,15,98,15,86,15,9,2,3,92,15,24,15,124,15,10,2,3,105,5,34,5,140,1,1,11,2,1,89,1,0,0,0,0,1,27,10,0,17,63,18,1,10,0,46,17,72,56,0,10,0,17,63,18,0,10,0,46,17,72,56,1,10,0,17,63,7,0,9,10,0,56,2,49,0,64,28,0,0,0,0,0,0,0,0,11,0,56,3,18,2,56,4,2,1,0,0,0,1,10,11,0,16,0,20,7,0,33,4,7,5,9,7,1,39,2,2,1,4,0,1,16,10,1,16,0,20,7,0,35,4,7,5,11,11,1,1,7,2,39,7,0,11,1,15,0,21,2,3,1,4,0,37,117,10,3,46,17,1,10,3,16,1,20,12,35,10,35,7,9,35,4,12,5,24,11,3,1,11,1,1,11,19,1,11,18,1,11,2,1,7,5,39,10,3,46,56,5,10,3,16,1,20,12,20,11,4,12,29,56,6,17,56,12,30,11,5,12,31,11,6,12,32,11,7,12,33,17,54,12,34,17,54,12,21,11,13,12,22,11,14,12,23,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,24,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,25,11,2,17,60,12,26,11,8,11,10,11,11,11,12,11,9,18,8,12,27,11,15,11,16,11,17,18,9,12,28,11,20,11,29,11,30,11,31,11,32,11,33,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,34,11,21,11,24,11,25,11,26,11,22,11,23,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,27,11,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,12,37,10,3,15,2,10,35,11,37,56,8,11,35,49,1,22,11,3,15,1,21,11,18,56,9,12,36,11,1,11,36,11,19,56,10,2,4,1,4,0,1,11,10,1,46,17,1,10,2,11,1,15,3,21,11,2,18,11,56,11,2,5,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,4,21,2,6,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,5,21,2,7,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,6,21,2,8,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,7,21,2,9,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,9,21,2,10,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,10,21,2,11,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,11,21,2,12,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,12,21,2,13,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,13,21,2,14,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,15,21,2,15,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,16,21,2,16,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,17,21,2,17,1,0,0,48,36,56,6,17,56,12,3,10,0,16,1,20,12,1,49,0,12,2,10,2,10,1,35,4,33,5,14,10,0,16,2,10,2,56,13,16,18,20,10,3,34,4,24,5,28,11,0,1,7,7,39,11,2,49,1,22,12,2,5,9,11,0,1,2,18,1,0,0,1,4,11,0,16,3,20,2,19,1,0,0,1,4,11,0,16,1,20,2,20,1,0,0,51,23,10,0,16,19,10,1,56,14,32,4,11,11,0,1,64,8,0,0,0,0,0,0,0,0,64,8,0,0,0,0,0,0,0,0,2,11,0,16,19,11,1,56,15,12,2,10,2,16,20,20,11,2,16,21,20,2,21,1,0,0,1,7,11,0,16,2,11,1,56,13,16,22,20,2,22,1,0,0,1,7,11,0,16,2,11,1,56,13,16,18,20,2,23,1,0,0,1,7,11,0,16,2,11,1,56,13,16,4,20,2,24,1,0,0,1,7,11,0,16,2,11,1,56,13,16,5,20,2,25,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,23,20,11,2,16,24,20,2,26,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,25,20,11,2,16,26,20,2,27,1,0,0,52,14,11,0,16,2,11,1,56,13,12,2,10,2,16,27,16,28,20,11,2,16,29,16,28,20,2,28,1,0,0,53,41,11,0,16,2,11,1,56,13,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,4,16,27,16,30,10,2,56,16,4,22,10,4,16,27,16,30,10,2,56,17,20,12,5,10,4,16,29,16,30,10,2,56,16,4,36,11,4,16,29,16,30,11,2,56,17,20,12,3,5,38,11,4,1,11,5,11,3,2,29,1,0,0,1,7,11,0,16,2,11,1,56,13,16,31,20,2,30,1,0,0,1,7,11,0,16,2,11,1,56,13,16,6,20,2,31,1,0,0,1,7,11,0,16,2,11,1,56,13,16,7,20,2,32,1,0,0,1,7,11,0,16,2,11,1,56,13,16,32,20,2,33,1,0,0,52,26,11,0,16,2,11,1,56,13,12,2,10,2,16,8,16,9,20,10,2,16,8,16,10,20,10,2,16,8,16,11,20,10,2,16,8,16,12,20,11,2,16,8,16,13,20,2,34,1,0,0,52,18,11,0,16,2,11,1,56,13,12,2,10,2,16,14,16,15,20,10,2,16,14,16,16,20,11,2,16,14,16,17,20,2,35,3,0,0,45,17,10,0,46,17,1,11,0,15,2,11,1,56,12,12,4,11,3,10,4,15,23,21,11,2,11,4,15,24,21,2,36,3,0,0,45,29,10,0,46,17,1,11,0,15,2,11,1,56,12,12,6,11,2,10,6,15,26,21,11,3,10,6,15,25,21,11,4,10,6,15,31,21,10,6,16,32,20,11,5,22,11,6,15,32,21,2,37,3,0,0,54,31,10,0,46,17,1,11,0,15,2,11,1,56,12,12,5,10,5,15,27,12,6,11,5,15,29,12,4,10,6,16,28,20,11,2,22,11,6,15,28,21,10,4,16,28,20,11,3,22,11,4,15,28,21,2,38,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,42,2,39,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,43,2,40,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,42,2,41,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,43,2,42,0,0,0,14,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,0,15,30,11,1,11,3,10,2,22,56,19,10,0,16,28,20,11,2,22,11,0,15,28,21,2,43,0,0,0,14,37,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,3,10,2,38,4,17,5,21,11,0,1,7,6,39,10,0,15,30,11,1,11,3,10,2,23,56,19,10,0,16,28,20,11,2,23,11,0,15,28,21,2,44,3,0,0,45,14,11,0,15,2,11,1,56,12,12,3,10,3,16,32,20,11,2,22,11,3,15,32,21,2,45,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,64,8,0,0,0,0,0,0,0,0,11,3,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,21,14,1,56,22,32,4,37,11,5,15,21,11,1,68,8,5,39,11,5,1,2,46,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,21,14,1,56,23,12,3,4,17,11,4,15,21,11,3,56,24,1,5,19,11,4,1,2,47,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,11,3,64,8,0,0,0,0,0,0,0,0,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,20,14,1,56,22,32,4,37,11,5,15,20,11,1,68,8,5,39,11,5,1,2,48,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,20,14,1,56,23,12,3,4,17,11,4,15,20,11,3,56,24,1,5,19,11,4,1,2,49,1,0,0,61,58,10,2,10,3,12,8,46,11,8,17,22,56,6,17,56,33,4,11,5,21,11,2,1,11,1,1,11,4,1,11,7,1,7,8,39,11,2,15,2,11,3,56,12,15,32,12,10,10,4,10,10,20,52,12,9,46,11,9,56,25,12,11,10,5,12,12,11,5,10,11,35,4,44,11,11,12,12,10,10,20,10,12,77,23,11,10,21,11,1,11,4,11,12,11,6,11,7,56,26,2,50,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,2,1,2,4,2,3,2,2,3,4,3,5,3,13,3,14,3,16,8,0,8,1,8,2,8,3,8,4,3,17,9,0,9,1,9,2,3,2,2,6,4,0,4,1,3,1,3,6,3,7,3,8,3,9,3,10,7,1,3,11,7,0,3,12,3,15,0,81,0],"utils":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,16,3,26,47,4,73,12,5,85,63,7,148,1,156,1,8,176,2,64,6,240,2,20,12,132,3,114,0,14,1,3,1,4,1,12,1,13,1,0,4,1,0,1,2,1,12,1,0,1,4,2,2,0,0,10,0,1,1,0,0,11,0,2,1,0,2,5,1,8,1,0,2,6,1,2,1,0,2,9,7,1,1,0,2,15,5,6,1,0,3,7,11,8,1,12,4,8,9,10,0,5,4,4,4,2,4,6,1,0,4,3,4,3,11,1,1,9,0,3,7,8,2,1,11,1,1,9,0,1,11,0,1,9,0,2,3,11,1,1,9,0,1,9,0,1,6,11,1,1,9,0,1,3,3,7,11,1,1,9,0,3,7,8,2,0,1,6,8,2,1,5,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,4,99,111,105,110,12,100,101,115,116,114,111,121,95,122,101,114,111,12,105,110,116,111,95,98,97,108,97,110,99,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,10,115,112,108,105,116,95,99,111,105,110,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,117,116,105,108,115,5,118,97,108,117,101,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,176,179,0,0,0,0,0,0,3,8,177,179,0,0,0,0,0,0,0,1,0,0,3,44,14,0,56,0,12,3,10,1,6,0,0,0,0,0,0,0,0,36,4,8,5,12,11,2,1,7,0,39,11,3,10,1,38,4,17,5,21,11,2,1,7,1,39,13,0,11,1,10,2,56,1,12,4,14,0,56,0,6,0,0,0,0,0,0,0,0,33,4,37,11,2,1,11,0,56,2,11,4,2,11,0,11,2,46,17,7,56,3,11,4,2,1,1,0,0,8,6,11,0,11,1,11,2,56,4,56,5,2,0],"validation":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,12,3,22,82,4,104,4,5,108,83,7,191,1,154,2,8,217,3,64,6,153,4,70,12,223,4,237,4,0,22,0,15,0,13,1,3,1,16,1,0,12,0,3,1,7,0,4,2,7,0,0,18,0,1,1,0,0,21,0,1,1,0,0,17,0,1,1,0,0,20,0,1,1,0,0,19,2,1,2,0,0,1,5,8,10,0,1,6,7,6,0,1,7,8,9,0,1,8,8,10,0,1,9,8,9,0,2,11,1,10,0,2,12,9,10,0,2,14,9,10,0,4,4,1,5,1,0,4,10,5,6,0,13,4,13,14,3,7,8,0,2,15,0,4,7,8,0,2,2,15,7,7,8,0,2,15,15,15,15,15,1,9,0,1,8,2,1,8,1,2,6,8,0,2,2,7,8,0,2,2,15,15,1,15,8,7,8,0,2,15,15,15,15,15,15,9,7,8,0,2,15,15,15,15,15,15,15,4,7,8,0,2,7,8,0,2,1,9,1,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,5,97,115,99,105,105,3,103,101,116,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,13,103,101,116,95,99,111,105,110,95,116,121,112,101,9,103,101,116,95,105,110,100,101,120,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,11,105,110,116,111,95,115,116,114,105,110,103,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,9,116,121,112,101,95,110,97,109,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,225,171,0,0,0,0,0,0,3,8,226,171,0,0,0,0,0,0,3,8,227,171,0,0,0,0,0,0,3,8,228,171,0,0,0,0,0,0,3,8,229,171,0,0,0,0,0,0,3,8,230,171,0,0,0,0,0,0,3,8,231,171,0,0,0,0,0,0,0,1,0,0,3,58,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,1,12,8,10,0,10,1,17,7,1,12,5,11,8,11,5,17,12,12,7,11,0,11,1,17,8,12,9,11,7,11,2,22,17,10,24,12,6,11,9,11,6,38,4,55,5,57,7,1,39,2,1,1,0,0,11,54,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,10,11,0,11,1,17,7,12,6,12,7,11,10,11,7,17,12,12,9,11,5,11,6,17,12,12,8,11,9,11,8,11,2,22,38,4,51,5,53,7,3,39,2,2,1,0,0,12,71,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,11,10,0,10,1,17,7,12,6,12,8,11,11,11,8,17,12,12,10,11,5,11,6,17,12,12,9,10,9,10,2,22,10,10,35,4,51,5,55,11,0,1,7,3,39,11,9,11,2,22,11,10,17,11,12,7,11,0,11,1,17,5,11,7,38,4,68,5,70,7,2,39,2,3,1,0,0,8,23,11,0,11,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,15,7,4,39,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,20,5,22,7,0,39,2,4,1,0,0,13,40,10,0,11,1,12,5,12,4,56,0,17,14,11,4,46,11,5,17,6,33,4,13,5,17,11,0,1,7,4,39,11,0,11,2,12,7,12,6,56,1,17,14,11,6,46,11,7,17,6,33,4,30,5,32,7,4,39,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,37,5,39,7,0,39,2,0]},"type_origin_table":[{"module_name":"pool","struct_name":"Pool","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolAdminCap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolCreate","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolBalanceRegister","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolDeposit","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolWithdraw","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"OwnerCap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"StorageAdminCap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"Storage","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"ReserveData","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"UserInfo","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"ReserveConfigurationMap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"UserConfigurationMap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"TokenBalance","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"BorrowRateFactors","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"LiquidationFactors","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"StorageConfiguratorSetting","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"Paused","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"IncentiveBal","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"PoolInfo","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"Incentive","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"PoolOwnerSetting","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"PoolAdminSetting","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"DepositEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"WithdrawEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"BorrowEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"RepayEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"LiquidationCallEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":9},"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f":{"upgraded_id":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f","upgraded_version":1}}}},"owner":"Immutable","previous_transaction":"3fqrGiknVvk82qum6zLYR749UTTyavaoH8TLU6bym8di","storage_rebate":213582800},{"data":{"Package":{"id":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f","version":1,"module_map":{"oracle":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,36,3,48,102,4,150,1,16,5,166,1,216,1,7,254,2,157,3,8,155,6,64,6,219,6,70,10,161,7,38,12,199,7,251,3,13,194,11,12,0,19,1,11,1,18,1,26,1,29,1,30,0,1,12,0,0,2,12,0,0,4,8,0,0,3,4,0,1,0,8,0,2,7,4,0,3,5,12,2,7,1,4,1,5,6,2,0,0,16,0,1,0,0,37,2,1,0,0,36,3,1,0,0,24,4,1,0,0,22,5,1,0,0,32,6,1,0,0,33,7,1,0,0,14,8,9,0,1,28,24,25,0,2,17,0,11,0,3,8,26,1,2,7,4,3,9,22,34,2,7,4,3,10,28,29,2,7,4,3,12,22,23,2,7,4,3,17,0,18,2,7,4,4,21,15,1,1,12,4,25,20,1,1,8,5,23,12,13,0,15,14,15,16,14,17,16,19,13,17,10,17,12,17,11,17,1,7,8,7,0,1,6,8,2,2,6,8,0,7,8,2,3,6,8,0,7,8,2,3,6,6,8,0,6,8,4,7,8,2,2,15,2,5,6,8,1,6,8,4,7,8,2,2,15,5,6,8,1,6,8,4,7,8,2,10,2,10,15,3,6,8,4,6,8,2,2,3,1,15,2,2,8,5,11,6,2,2,8,3,1,8,5,1,6,8,7,1,5,1,8,0,2,9,0,5,1,8,1,2,2,8,3,1,11,6,2,9,0,9,1,1,8,2,1,9,0,2,2,7,11,6,2,2,8,3,2,6,11,6,2,9,0,9,1,9,0,1,1,1,6,8,4,1,3,3,7,11,6,2,9,0,9,1,9,0,9,1,3,2,7,8,3,7,11,6,2,2,8,3,2,7,11,6,2,9,0,9,1,9,0,1,7,9,1,3,3,3,6,2,1,2,1,15,5,1,3,6,11,6,2,2,8,3,6,8,3,1,1,6,9,1,5,67,108,111,99,107,14,79,114,97,99,108,101,65,100,109,105,110,67,97,112,15,79,114,97,99,108,101,70,101,101,100,101,114,67,97,112,5,80,114,105,99,101,11,80,114,105,99,101,79,114,97,99,108,101,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,7,100,101,99,105,109,97,108,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,2,105,100,4,105,110,105,116,3,110,101,119,6,111,98,106,101,99,116,6,111,114,97,99,108,101,13,112,114,105,99,101,95,111,114,97,99,108,101,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,20,114,101,103,105,115,116,101,114,95,116,111,107,101,110,95,112,114,105,99,101,6,115,101,110,100,101,114,19,115,101,116,95,117,112,100,97,116,101,95,105,110,116,101,114,118,97,108,12,115,104,97,114,101,95,111,98,106,101,99,116,5,116,97,98,108,101,9,116,105,109,101,115,116,97,109,112,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,15,117,112,100,97,116,101,95,105,110,116,101,114,118,97,108,18,117,112,100,97,116,101,95,116,111,107,101,110,95,112,114,105,99,101,24,117,112,100,97,116,101,95,116,111,107,101,110,95,112,114,105,99,101,95,98,97,116,99,104,5,118,97,108,117,101,7,118,101,114,115,105,111,110,15,118,101,114,115,105,111,110,95,109,105,103,114,97,116,101,20,118,101,114,115,105,111,110,95,118,101,114,105,102,105,99,97,116,105,111,110,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,48,117,0,0,0,0,0,0,3,8,80,195,0,0,0,0,0,0,3,8,81,195,0,0,0,0,0,0,3,8,82,195,0,0,0,0,0,0,3,8,83,195,0,0,0,0,0,0,3,8,84,195,0,0,0,0,0,0,0,2,1,15,8,5,1,2,1,15,8,5,2,2,4,15,8,5,35,3,31,3,20,11,6,2,2,8,3,3,2,3,34,15,13,2,27,3,0,0,0,0,10,27,10,0,17,9,18,0,10,0,46,17,17,56,0,10,0,17,9,18,1,10,0,46,17,17,56,1,10,0,17,9,12,1,11,0,56,2,12,2,11,1,7,0,7,1,11,2,18,2,56,3,2,1,0,0,0,1,10,11,0,16,0,20,7,0,33,4,7,5,9,7,2,39,2,2,0,4,0,1,16,10,1,16,0,20,7,0,35,4,7,5,11,11,1,1,7,3,39,7,0,11,1,15,0,21,2,3,1,4,0,1,8,10,1,46,17,1,11,2,11,1,15,1,21,2,4,1,4,0,21,30,10,2,46,17,1,11,2,15,2,12,7,10,7,10,3,12,6,46,11,6,56,4,32,4,15,5,21,11,7,1,11,1,1,7,6,39,11,7,11,3,11,4,11,5,11,1,17,8,18,3,56,5,2,5,1,4,0,27,34,10,2,46,17,1,11,2,15,2,12,7,10,7,10,3,12,5,46,11,5,56,4,4,14,5,20,11,7,1,11,1,1,7,5,39,11,7,11,3,56,6,12,6,11,4,10,6,15,3,21,11,1,17,8,11,6,15,4,21,2,6,1,4,0,30,53,10,2,46,17,1,14,3,65,31,12,6,10,6,14,4,65,32,33,4,12,5,20,11,2,1,11,1,1,11,0,1,7,4,39,6,0,0,0,0,0,0,0,0,12,5,10,5,10,6,35,4,46,5,27,14,3,10,5,66,31,12,7,10,0,10,1,10,2,11,7,20,14,4,10,5,66,32,20,17,5,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,22,11,2,1,11,1,1,11,0,1,2,7,1,0,0,33,60,10,1,17,1,10,1,16,2,12,5,10,5,10,2,56,4,4,10,5,18,11,5,1,11,1,1,11,0,1,7,5,39,11,5,11,2,56,7,12,6,11,0,17,8,12,4,9,12,7,10,6,16,3,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,44,11,4,10,6,16,4,20,23,11,1,16,1,20,37,12,3,5,48,11,1,1,9,12,3,11,3,4,52,8,12,7,11,7,10,6,16,3,20,11,6,16,5,20,2,2,1,2,2,2,3,3,0,3,2,3,1,0]},"type_origin_table":[{"module_name":"oracle","struct_name":"OracleAdminCap","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"},{"module_name":"oracle","struct_name":"OracleFeederCap","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"},{"module_name":"oracle","struct_name":"PriceOracle","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"},{"module_name":"oracle","struct_name":"Price","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":8}}}},"owner":"Immutable","previous_transaction":"5rr1KbGr5ht2kWrPwgArYuaYsauoDG8CpuJLnaKnkgL6","storage_rebate":15010000},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000001","version":2,"module_map":{"address":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,3,7,10,15,8,25,32,12,57,16,0,0,0,1,0,1,0,0,1,3,7,97,100,100,114,101,115,115,6,108,101,110,103,116,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,6,32,0,0,0,0,0,0,0,2,0],"ascii":[161,28,235,11,6,0,0,0,11,1,0,4,2,4,14,3,18,84,4,102,8,5,110,59,7,169,1,200,1,8,241,2,32,6,145,3,10,10,155,3,11,12,166,3,186,2,13,224,5,4,0,5,0,16,0,2,7,0,0,0,7,0,1,1,7,1,0,0,0,8,0,1,0,0,20,2,3,0,0,21,2,4,0,0,3,5,6,0,0,18,7,8,0,0,17,9,1,0,0,14,5,10,0,0,4,5,11,0,0,10,3,2,0,0,6,1,0,0,0,13,0,6,0,0,11,0,6,0,1,9,13,14,1,0,1,12,12,6,1,0,1,15,8,13,1,0,1,19,14,13,1,0,13,3,12,3,14,3,15,3,1,2,1,8,1,1,10,2,1,8,0,1,11,2,1,8,0,1,6,8,0,1,1,2,7,8,0,8,1,0,1,7,8,0,1,3,1,6,10,2,1,6,11,2,1,9,0,1,11,2,1,9,0,1,9,0,2,3,3,4,67,104,97,114,6,79,112,116,105,111,110,6,83,116,114,105,110,103,24,97,108,108,95,99,104,97,114,97,99,116,101,114,115,95,112,114,105,110,116,97,98,108,101,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,4,98,121,116,101,5,98,121,116,101,115,4,99,104,97,114,12,100,101,115,116,114,111,121,95,115,111,109,101,10,105,110,116,111,95,98,121,116,101,115,17,105,115,95,112,114,105,110,116,97,98,108,101,95,99,104,97,114,7,105,115,95,115,111,109,101,13,105,115,95,118,97,108,105,100,95,99,104,97,114,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,8,112,111,112,95,99,104,97,114,9,112,117,115,104,95,99,104,97,114,4,115,111,109,101,6,115,116,114,105,110,103,10,116,114,121,95,115,116,114,105,110,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,1,0,0,0,0,0,0,2,1,7,10,2,1,2,1,6,2,0,1,0,0,8,9,10,0,17,10,4,4,5,6,7,0,39,11,0,18,1,2,1,1,0,0,4,12,11,0,17,2,12,1,14,1,56,0,4,7,5,9,7,0,39,11,1,56,1,2,2,1,0,0,15,30,14,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,25,5,11,14,0,10,1,66,0,20,17,10,32,4,20,56,2,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,5,40,11,0,18,0,56,3,2,3,1,0,0,15,32,10,0,16,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,29,5,12,10,0,16,0,10,1,66,0,20,17,11,32,4,24,11,0,1,9,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,40,8,2,4,1,0,0,8,7,11,0,15,0,14,1,16,1,20,68,0,2,5,1,0,0,8,5,11,0,15,0,69,0,18,1,2,6,1,0,0,8,4,11,0,17,7,65,0,2,7,1,0,0,8,3,11,0,16,0,2,8,1,0,0,8,3,11,0,19,0,2,9,1,0,0,8,3,11,0,19,1,2,10,1,0,0,8,4,11,0,49,127,37,2,11,1,0,0,6,13,10,0,49,32,38,4,9,11,0,49,126,37,12,1,5,11,9,12,1,11,1,2,0,0,1,0,0],"bcs":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,7,7,15,13,8,28,32,12,60,4,0,0,0,1,0,1,1,0,1,6,9,0,1,10,2,3,98,99,115,8,116,111,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,0],"bit_vector":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,36,7,77,109,8,186,1,32,6,218,1,40,10,130,2,8,12,138,2,239,3,13,249,5,4,0,2,0,0,7,0,0,6,0,1,0,0,7,2,3,0,0,9,2,3,0,0,8,2,3,0,0,3,4,5,0,0,4,6,0,0,0,5,4,0,0,1,3,1,8,0,2,7,8,0,3,0,2,6,8,0,3,1,1,1,6,8,0,2,10,1,3,1,7,1,5,3,7,1,3,3,3,9,66,105,116,86,101,99,116,111,114,9,98,105,116,95,102,105,101,108,100,10,98,105,116,95,118,101,99,116,111,114,12,105,115,95,105,110,100,101,120,95,115,101,116,6,108,101,110,103,116,104,32,108,111,110,103,101,115,116,95,115,101,116,95,115,101,113,117,101,110,99,101,95,115,116,97,114,116,105,110,103,95,97,116,3,110,101,119,3,115,101,116,10,115,104,105,102,116,95,108,101,102,116,5,117,110,115,101,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,3,8,1,0,2,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,4,0,0,0,0,0,0,0,2,2,4,3,1,10,1,0,1,0,0,7,37,10,0,6,0,0,0,0,0,0,0,0,36,4,5,5,7,7,1,39,10,0,7,3,35,4,12,5,14,7,1,39,6,0,0,0,0,0,0,0,0,12,2,64,5,0,0,0,0,0,0,0,0,12,1,40,10,2,10,0,35,4,32,5,24,13,1,9,68,5,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,18,40,11,0,11,1,18,0,2,1,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,8,11,2,21,2,2,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,9,11,2,21,2,3,1,0,0,9,89,10,1,10,0,16,1,20,38,4,33,10,0,16,0,65,5,12,6,6,0,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,30,5,17,10,0,15,0,10,4,67,5,12,3,9,11,3,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,12,11,0,1,5,88,10,1,12,5,10,5,10,0,16,1,20,35,4,65,5,42,10,0,10,5,12,2,46,11,2,17,4,4,55,10,0,10,5,10,1,23,17,1,5,60,10,0,10,5,10,1,23,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,35,10,0,16,1,20,11,1,23,12,5,10,5,10,0,16,1,20,35,4,86,5,78,10,0,10,5,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,71,11,0,1,2,4,1,0,0,3,17,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,16,0,11,1,66,5,20,2,5,1,0,0,3,4,11,0,16,0,65,5,2,6,1,0,0,0,37,10,1,10,0,16,1,20,35,4,7,5,11,11,0,1,7,0,39,10,1,12,2,10,2,10,0,16,1,20,35,4,33,5,20,10,0,10,2,17,4,32,4,28,11,0,1,5,33,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,13,11,2,11,1,23,2,0,1,0,0,0],"debug":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,11,5,13,5,7,18,30,8,48,32,12,80,8,0,0,0,1,0,1,1,0,0,2,1,1,0,1,6,9,0,0,5,100,101,98,117,103,5,112,114,105,110,116,17,112,114,105,110,116,95,115,116,97,99,107,95,116,114,97,99,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"fixed_point32":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,30,5,36,22,7,58,122,8,180,1,32,6,212,1,68,10,152,2,5,12,157,2,137,2,13,166,4,2,0,4,0,0,7,0,0,7,0,1,0,0,3,0,1,0,0,1,2,3,0,0,2,1,3,0,0,5,3,1,0,0,6,3,4,0,2,3,8,0,1,3,2,3,3,1,8,0,1,1,1,4,4,1,4,4,4,0,12,70,105,120,101,100,80,111,105,110,116,51,50,20,99,114,101,97,116,101,95,102,114,111,109,95,114,97,116,105,111,110,97,108,21,99,114,101,97,116,101,95,102,114,111,109,95,114,97,119,95,118,97,108,117,101,10,100,105,118,105,100,101,95,117,54,52,13,102,105,120,101,100,95,112,111,105,110,116,51,50,13,103,101,116,95,114,97,119,95,118,97,108,117,101,7,105,115,95,122,101,114,111,12,109,117,108,116,105,112,108,121,95,117,54,52,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,16,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,3,8,1,0,1,0,0,0,0,0,3,8,2,0,2,0,0,0,0,0,3,8,3,0,2,0,0,0,0,0,3,8,4,0,1,0,0,0,0,0,3,8,5,0,2,0,0,0,0,0,0,2,1,8,3,0,1,0,0,5,20,11,0,53,14,1,16,0,20,53,24,49,32,48,12,2,10,2,7,0,37,4,15,5,17,7,3,39,11,2,52,2,1,1,0,0,5,29,14,1,16,0,20,6,0,0,0,0,0,0,0,0,34,4,7,5,9,7,4,39,11,0,53,49,32,47,14,1,16,0,20,53,26,12,2,10,2,7,0,37,4,24,5,26,7,2,39,11,2,52,2,2,1,0,0,6,48,10,0,53,49,64,47,12,5,11,1,53,49,32,47,12,4,10,4,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,15,5,17,7,1,39,11,5,11,4,26,12,3,10,3,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,8,12,2,5,32,11,0,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,35,5,37,7,5,39,10,3,7,0,37,4,42,5,44,7,5,39,11,3,52,18,0,2,3,1,0,0,7,3,11,0,18,0,2,4,1,0,0,7,4,14,0,16,0,20,2,5,1,0,0,7,6,14,0,16,0,20,6,0,0,0,0,0,0,0,0,33,2,0,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,3,7,15,23,8,38,32,12,70,8,0,0,0,1,0,0,0,0,2,0,0,0,1,10,2,4,104,97,115,104,8,115,104,97,50,95,50,53,54,8,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"option":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,6,3,10,120,4,130,1,14,5,144,1,135,1,7,151,2,219,1,8,242,3,32,6,146,4,20,10,166,4,7,11,173,4,2,12,175,4,128,4,13,175,8,2,14,177,8,2,0,15,0,22,0,0,7,1,0,0,0,14,0,1,1,0,0,17,2,1,1,0,0,12,3,4,1,0,0,13,3,4,1,0,0,4,5,4,1,0,0,1,3,6,1,0,0,3,5,6,1,0,0,10,7,2,1,3,0,9,8,0,1,0,0,8,9,2,1,0,0,2,9,10,1,0,0,18,8,2,1,0,0,19,8,1,1,0,0,7,11,2,1,2,0,6,1,2,1,0,0,5,1,0,1,0,0,20,1,12,1,0,1,4,14,4,1,0,1,11,13,4,1,0,1,16,2,12,1,0,19,2,18,2,17,2,3,2,0,2,1,2,2,2,0,1,11,0,1,9,0,1,9,0,1,6,11,0,1,9,0,1,1,2,6,11,0,1,9,0,6,9,0,1,6,9,0,2,6,11,0,1,9,0,9,0,2,7,11,0,1,9,0,9,0,1,7,11,0,1,9,0,1,7,9,0,2,11,0,1,9,0,9,0,1,10,9,0,1,6,10,9,0,2,6,10,9,0,6,9,0,2,6,9,0,6,10,9,0,2,9,0,6,10,9,0,1,7,10,9,0,2,9,0,7,10,9,0,3,11,0,1,9,0,11,0,1,9,0,7,10,9,0,2,9,0,10,9,0,6,79,112,116,105,111,110,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,119,105,116,104,95,100,101,102,97,117,108,116,8,99,111,110,116,97,105,110,115,12,100,101,115,116,114,111,121,95,110,111,110,101,12,100,101,115,116,114,111,121,95,115,111,109,101,20,100,101,115,116,114,111,121,95,119,105,116,104,95,100,101,102,97,117,108,116,7,101,120,116,114,97,99,116,4,102,105,108,108,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,4,110,111,110,101,6,111,112,116,105,111,110,9,115,105,110,103,108,101,116,111,110,4,115,111,109,101,4,115,119,97,112,12,115,119,97,112,95,111,114,95,102,105,108,108,6,116,111,95,118,101,99,3,118,101,99,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,4,0,0,0,0,0,3,8,1,0,4,0,0,0,0,0,0,2,1,21,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,0,4,11,0,55,0,56,1,2,3,1,0,0,0,5,11,0,55,0,56,1,32,2,4,1,0,0,0,5,11,0,55,0,11,1,56,2,2,5,1,0,0,0,13,10,0,56,3,4,4,5,8,11,0,1,7,1,39,11,0,55,0,6,0,0,0,0,0,0,0,0,66,2,2,6,1,0,0,15,19,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,17,11,1,1,11,3,6,0,0,0,0,0,0,0,0,66,2,12,2,11,2,2,7,1,0,0,16,18,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,16,11,3,6,0,0,0,0,0,0,0,0,66,2,20,12,2,11,2,2,8,1,0,0,17,16,11,0,54,0,12,2,10,2,46,56,1,4,8,5,12,11,2,1,7,0,39,11,2,11,1,68,2,2,9,1,0,0,0,13,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,69,2,2,10,1,0,0,0,14,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,6,0,0,0,0,0,0,0,0,67,2,2,11,1,0,0,18,20,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,12,3,10,3,69,2,12,2,11,3,11,1,68,2,11,2,2,12,1,0,0,19,21,11,0,54,0,12,4,10,4,46,56,1,4,10,56,4,12,2,5,14,10,4,69,2,56,5,12,2,11,2,12,3,11,4,11,1,68,2,11,3,2,13,1,0,0,20,15,11,0,58,0,12,3,13,3,46,56,1,4,10,11,1,12,2,5,13,13,3,69,2,12,2,11,2,2,14,1,0,0,20,16,14,0,56,3,4,4,5,6,7,1,39,11,0,58,0,12,2,13,2,69,2,12,1,11,2,70,2,0,0,0,0,0,0,0,0,11,1,2,15,1,0,0,0,10,14,0,56,6,4,4,5,6,7,0,39,11,0,58,0,70,2,0,0,0,0,0,0,0,0,2,16,1,0,0,0,3,11,0,58,0,2,0,0,0,2,0],"string":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,14,3,22,114,4,136,1,8,5,144,1,123,7,139,2,248,1,8,131,4,32,6,163,4,20,10,183,4,6,12,189,4,133,3,13,194,7,2,0,19,0,4,0,17,0,24,0,1,7,0,1,1,7,0,2,0,7,1,0,0,0,23,0,1,0,0,6,2,1,0,0,21,1,2,0,0,22,0,3,0,0,5,4,5,0,0,14,4,6,0,0,15,4,7,0,0,2,8,9,0,0,3,10,9,0,0,8,11,9,0,0,20,12,1,0,0,7,13,7,0,0,9,5,6,0,0,11,14,6,0,0,12,15,0,0,0,10,16,7,0,1,13,2,0,0,1,19,0,2,0,2,16,9,18,1,0,2,18,17,18,1,0,3,2,21,9,1,0,3,14,20,6,1,0,19,1,18,1,21,19,20,19,1,10,2,1,8,0,1,8,1,1,11,2,1,8,0,1,6,8,0,1,6,10,2,1,1,1,3,2,7,8,0,8,0,0,2,7,8,0,10,2,3,7,8,0,3,8,0,3,6,8,0,3,3,2,6,8,0,6,8,0,2,6,10,2,3,3,6,10,2,3,3,2,6,10,2,6,10,2,1,9,0,1,11,2,1,9,0,1,2,1,6,10,9,0,2,7,10,9,0,10,9,0,8,1,3,3,3,6,10,2,8,0,8,0,3,5,1,1,1,6,10,2,3,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,97,112,112,101,110,100,11,97,112,112,101,110,100,95,117,116,102,56,5,97,115,99,105,105,5,98,121,116,101,115,10,102,114,111,109,95,97,115,99,105,105,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,19,105,110,116,101,114,110,97,108,95,99,104,101,99,107,95,117,116,102,56,17,105,110,116,101,114,110,97,108,95,105,110,100,101,120,95,111,102,25,105,110,116,101,114,110,97,108,95,105,115,95,99,104,97,114,95,98,111,117,110,100,97,114,121,19,105,110,116,101,114,110,97,108,95,115,117,98,95,115,116,114,105,110,103,10,105,110,116,111,95,98,121,116,101,115,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,4,115,111,109,101,6,115,116,114,105,110,103,10,115,117,98,95,115,116,114,105,110,103,8,116,111,95,97,115,99,105,105,8,116,114,121,95,117,116,102,56,4,117,116,102,56,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,5,10,2,0,1,0,0,9,9,14,0,17,12,4,4,5,6,7,0,39,11,0,18,0,2,1,1,0,0,9,4,11,0,17,16,18,0,2,2,1,0,0,9,4,11,0,19,0,17,17,2,3,1,0,0,3,12,14,0,17,12,4,8,11,0,18,0,56,0,12,1,5,10,56,1,12,1,11,1,2,4,1,0,0,9,3,11,0,16,0,2,5,1,0,0,9,4,11,0,16,0,56,2,2,6,1,0,0,9,4,11,0,16,0,65,19,2,7,1,0,0,9,7,11,0,15,0,14,1,16,0,20,56,3,2,8,1,0,0,9,5,11,0,11,1,17,0,17,7,2,9,1,0,0,22,56,10,0,16,0,12,7,10,1,10,7,65,19,37,4,13,11,7,10,1,17,13,12,3,5,17,11,7,1,9,12,3,11,3,4,20,5,24,11,0,1,7,1,39,10,0,46,17,6,12,10,10,0,10,1,12,4,46,6,0,0,0,0,0,0,0,0,11,4,17,10,12,9,10,0,11,1,11,10,12,6,12,5,46,11,5,11,6,17,10,12,8,13,9,11,2,17,7,13,9,11,8,17,7,11,9,11,0,21,2,10,1,0,0,23,48,11,0,16,0,12,6,10,6,65,19,12,7,10,2,11,7,37,4,15,10,1,10,2,37,12,3,5,17,9,12,3,11,3,4,24,10,6,10,1,17,13,12,4,5,26,9,12,4,11,4,4,33,10,6,10,2,17,13,12,5,5,35,9,12,5,11,5,4,38,5,42,11,6,1,7,1,39,11,6,11,1,11,2,17,14,18,0,2,11,1,0,0,9,6,11,0,16,0,11,1,16,0,17,15,2,12,0,2,0,13,0,2,0,14,0,2,0,15,0,2,0,0,0,0],"type_name":[161,28,235,11,6,0,0,0,10,1,0,6,2,6,8,3,14,47,5,61,44,7,105,143,1,8,248,1,32,6,152,2,7,10,159,2,6,12,165,2,215,1,13,252,3,2,0,14,0,2,0,4,0,1,7,0,2,0,7,0,0,6,0,1,1,0,0,9,0,1,1,0,0,5,2,3,0,0,7,2,4,0,0,8,2,4,0,0,10,1,4,0,1,11,0,6,0,2,3,3,7,0,2,13,9,4,0,0,1,8,0,1,6,8,0,1,6,8,1,1,8,1,4,10,2,3,3,6,10,2,1,3,1,6,10,2,1,2,1,10,2,5,2,6,2,3,10,2,6,10,2,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,13,98,111,114,114,111,119,95,115,116,114,105,110,103,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,11,105,110,116,111,95,115,116,114,105,110,103,6,108,101,110,103,116,104,4,110,97,109,101,6,115,116,114,105,110,103,9,116,121,112,101,95,110,97,109,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,58,10,2,1,0,0,2,1,12,8,1,0,1,2,0,1,1,2,0,2,1,0,0,0,3,11,0,16,0,2,3,1,0,0,5,33,17,6,6,2,0,0,0,0,0,0,0,24,12,3,11,0,16,0,17,7,12,4,7,1,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,28,5,17,13,1,10,4,10,2,66,8,20,68,8,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,4,1,11,1,17,8,2,4,1,0,0,10,39,17,6,6,2,0,0,0,0,0,0,0,24,6,2,0,0,0,0,0,0,0,22,12,3,11,0,16,0,17,7,12,5,7,1,12,4,10,5,10,3,66,8,12,2,7,0,12,1,10,2,14,1,34,4,32,5,23,13,4,11,2,20,68,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,12,11,5,1,11,2,1,11,4,17,8,2,5,1,0,0,0,4,14,0,16,0,20,2,0,0,0],"vector":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,102,4,104,4,5,108,97,7,205,1,154,1,8,231,2,32,6,135,3,10,12,145,3,216,4,0,17,0,5,0,1,1,0,0,9,2,3,1,0,0,1,4,5,1,0,0,11,6,0,1,0,0,2,7,8,1,0,0,10,9,10,1,0,0,4,1,0,1,0,0,15,11,0,1,0,0,14,10,1,1,0,0,13,9,0,1,0,0,0,12,0,1,0,0,8,2,13,1,0,0,3,14,13,1,0,0,6,14,15,1,0,0,12,7,10,1,0,0,7,16,0,1,0,0,16,7,10,1,0,9,10,11,10,0,1,10,9,0,1,6,10,9,0,1,3,2,6,10,9,0,3,1,6,9,0,2,7,10,9,0,9,0,2,7,10,9,0,3,1,7,9,0,1,7,10,9,0,1,9,0,3,7,10,9,0,3,3,2,7,10,9,0,10,9,0,1,1,2,6,10,9,0,6,9,0,2,1,3,3,7,10,9,0,9,0,3,3,3,3,3,2,3,3,3,3,7,10,9,0,3,6,97,112,112,101,110,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,5,101,109,112,116,121,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,7,114,101,118,101,114,115,101,9,115,105,110,103,108,101,116,111,110,4,115,119,97,112,11,115,119,97,112,95,114,101,109,111,118,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,2,0,4,1,2,0,5,1,2,0,6,1,2,0,7,1,2,0,8,1,0,0,1,7,64,10,0,0,0,0,0,0,0,0,12,1,13,1,11,0,68,10,11,1,2,9,1,0,0,17,38,10,0,46,65,10,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,2,6,0,0,0,0,0,0,0,0,12,2,11,3,6,1,0,0,0,0,0,0,0,23,12,1,10,2,10,1,35,4,35,5,22,10,0,10,2,10,1,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,1,6,1,0,0,0,0,0,0,0,23,12,1,5,17,11,0,1,2,10,1,0,0,0,17,13,1,56,0,14,1,56,1,32,4,12,5,7,10,0,13,1,69,10,68,10,5,2,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,11,1,0,0,0,5,11,0,65,10,6,0,0,0,0,0,0,0,0,33,2,12,1,0,0,18,33,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,27,5,10,10,0,10,2,66,10,10,1,33,4,22,11,0,1,11,1,1,8,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,2,13,1,0,0,18,35,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,28,5,10,10,0,10,2,66,10,10,1,33,4,23,11,0,1,11,1,1,8,11,2,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,6,0,0,0,0,0,0,0,0,2,14,1,0,0,19,37,10,0,46,65,10,12,4,10,1,10,4,38,4,12,11,0,1,7,0,39,11,4,6,1,0,0,0,0,0,0,0,23,12,4,10,1,10,4,35,4,34,5,21,10,0,12,3,10,1,12,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,11,3,11,2,10,1,71,10,5,16,11,0,69,10,2,15,1,0,0,3,32,10,0,46,65,10,12,3,10,2,10,3,36,4,12,11,0,1,7,0,39,10,0,11,1,68,10,10,2,10,3,35,4,29,5,20,10,0,10,2,10,3,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,2,16,1,0,0,3,23,10,0,46,56,1,32,4,6,5,10,11,0,1,7,0,39,10,0,46,65,10,6,1,0,0,0,0,0,0,0,23,12,2,10,0,11,1,11,2,71,10,11,0,69,10,2,0]},"type_origin_table":[{"module_name":"fixed_point32","struct_name":"FixedPoint32","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"option","struct_name":"Option","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"Char","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"bit_vector","struct_name":"BitVector","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"string","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"type_name","struct_name":"TypeName","package":"0x0000000000000000000000000000000000000000000000000000000000000001"}],"linkage_table":{}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000002","version":10,"module_map":{"address":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,8,3,18,61,4,79,2,5,81,20,7,101,129,1,8,230,1,64,6,166,2,54,12,220,2,69,0,1,1,2,1,3,1,11,0,8,1,0,7,0,3,0,7,0,0,15,0,1,0,0,7,1,0,0,0,6,2,0,0,0,13,0,2,0,0,12,0,3,0,0,14,0,4,0,0,9,5,6,0,0,10,5,1,0,1,11,2,3,0,2,13,7,2,1,0,3,5,3,4,0,4,4,2,2,0,9,0,1,5,1,15,1,10,2,1,8,0,1,8,1,0,1,3,1,6,9,0,6,83,116,114,105,110,103,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,6,101,110,99,111,100,101,10,102,114,111,109,95,97,115,99,105,105,10,102,114,111,109,95,98,121,116,101,115,9,102,114,111,109,95,117,50,53,54,3,104,101,120,6,108,101,110,103,116,104,3,109,97,120,6,115,116,114,105,110,103,15,116,111,95,97,115,99,105,105,95,115,116,114,105,110,103,8,116,111,95,98,121,116,101,115,9,116,111,95,115,116,114,105,110,103,7,116,111,95,117,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,32,0,0,0,0,0,0,0,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,3,8,0,0,0,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,0,0,5,3,14,0,56,0,2,4,1,0,0,5,5,11,0,17,3,17,11,17,8,2,5,1,0,0,5,4,11,0,17,4,17,10,2,6,1,0,0,5,2,7,0,2,7,1,0,0,5,2,7,1,2,0],"bag":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,112,4,132,1,12,5,144,1,82,7,226,1,185,1,8,155,3,32,6,187,3,10,10,197,3,8,12,205,3,230,1,13,179,5,4,0,4,0,11,0,18,0,21,0,0,12,0,2,2,4,0,3,1,2,0,0,17,0,1,0,0,3,2,3,2,7,4,0,5,4,5,2,7,4,0,6,6,7,2,7,4,0,19,6,8,2,7,4,0,7,4,9,1,7,0,8,4,9,2,7,4,0,16,10,11,0,0,15,10,9,0,0,10,1,3,0,1,3,14,3,2,7,4,1,5,15,5,2,7,4,1,6,16,7,2,7,4,1,12,15,9,1,7,1,13,15,9,2,7,4,1,19,16,8,2,7,4,2,9,12,3,0,2,17,0,12,0,10,13,11,13,12,13,15,13,13,17,14,13,1,7,8,2,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,1,9,0,2,8,1,3,3,66,97,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,3,98,97,103,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,14,8,1,20,3,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,18,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,0,0,0,1,0],"balance":[161,28,235,11,6,0,0,0,14,1,0,4,2,4,16,3,20,83,4,103,2,5,105,99,7,204,1,224,1,8,172,3,32,6,204,3,74,10,150,4,10,11,160,4,4,12,164,4,219,2,13,255,6,4,14,131,7,4,15,135,7,2,0,3,0,16,0,1,4,1,0,1,0,0,4,1,0,1,1,2,2,0,0,17,0,1,1,0,0,15,2,1,1,0,0,5,3,4,1,2,0,10,5,6,1,0,0,6,7,1,1,0,0,19,8,6,1,0,0,11,9,1,1,0,0,13,10,6,1,0,0,18,11,6,1,0,0,9,6,8,1,0,0,4,12,6,1,0,0,7,13,8,1,0,0,8,4,1,1,0,1,12,14,15,0,7,3,1,6,11,1,1,9,0,1,3,1,6,11,0,1,9,0,1,9,0,1,11,0,1,9,0,2,7,11,0,1,9,0,3,1,11,1,1,9,0,2,7,11,0,1,9,0,11,1,1,9,0,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,7,11,1,1,9,0,2,3,6,8,2,2,11,1,1,9,0,6,8,2,1,6,8,2,1,5,7,66,97,108,97,110,99,101,6,83,117,112,112,108,121,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,22,99,114,101,97,116,101,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,115,13,99,114,101,97,116,101,95,115,117,112,112,108,121,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,23,100,101,115,116,114,111,121,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,12,100,101,115,116,114,111,121,95,122,101,114,111,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,4,106,111,105,110,6,115,101,110,100,101,114,5,115,112,108,105,116,3,115,117,105,12,115,117,112,112,108,121,95,118,97,108,117,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,17,3,1,2,1,17,3,0,3,1,3,0,1,0,0,8,4,11,0,55,0,20,2,1,1,0,0,8,4,11,0,55,1,20,2,2,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,0,2,3,1,0,0,8,24,10,1,6,255,255,255,255,255,255,255,255,10,0,55,1,20,23,35,4,9,5,13,11,0,1,7,1,39,10,0,55,1,20,10,1,22,11,0,54,1,21,11,1,57,1,2,4,1,0,0,1,24,11,1,58,1,12,2,10,0,55,1,20,10,2,38,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,10,2,23,11,0,54,1,21,11,2,2,5,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,1,2,6,1,0,0,1,15,11,1,58,1,12,2,10,0,55,0,20,11,2,22,10,0,54,0,21,11,0,55,0,20,2,7,1,0,0,8,22,10,0,55,0,20,10,1,38,4,7,5,11,11,0,1,7,2,39,10,0,55,0,20,10,1,23,11,0,54,0,21,11,1,57,1,2,8,1,0,0,1,8,10,0,55,0,20,12,1,11,0,11,1,56,0,2,9,1,0,0,8,13,14,0,55,0,20,6,0,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,11,0,58,1,1,2,10,0,0,0,8,11,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,57,1,2,11,0,0,0,8,12,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,58,1,1,2,12,3,0,0,8,3,11,0,58,0,2,1,0,0,0,0,3,1,3,0,14,0],"bcs":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,10,3,20,135,1,4,155,1,24,5,179,1,131,1,7,182,2,222,2,8,148,5,64,6,212,5,55,10,139,6,6,12,145,6,203,8,13,220,14,2,0,3,1,3,1,10,1,31,0,2,0,0,7,0,2,1,7,1,0,0,0,30,0,1,1,0,0,8,1,2,0,0,6,2,1,0,0,11,3,4,0,0,12,3,5,0,0,20,3,6,0,0,19,3,7,0,0,18,3,8,0,0,23,3,7,0,0,21,3,9,0,0,22,3,10,0,0,26,3,1,0,0,27,3,11,0,0,25,3,12,0,0,24,3,13,0,0,13,3,14,0,0,14,3,15,0,0,17,3,16,0,0,16,3,17,0,0,15,3,18,0,1,30,0,1,1,0,2,9,19,33,1,0,2,29,20,33,1,0,3,28,21,19,1,0,4,5,1,4,0,4,7,19,7,0,20,20,23,6,22,4,21,4,22,5,21,5,22,6,21,6,22,7,21,7,22,8,21,8,1,6,9,0,1,10,2,1,8,0,1,7,8,0,1,5,1,1,1,2,1,3,1,4,1,10,5,1,10,1,1,10,10,2,1,10,3,1,10,4,1,11,1,1,5,1,11,1,1,1,1,11,1,1,2,1,11,1,1,3,1,11,1,1,4,0,1,9,0,1,7,10,9,0,2,10,2,3,2,1,2,3,3,2,3,3,4,2,4,4,3,3,2,3,3,3,3,10,5,3,3,3,10,1,3,3,3,10,2,3,3,3,10,10,2,3,3,3,10,3,3,3,3,10,4,1,11,1,1,9,0,3,66,67,83,6,79,112,116,105,111,110,7,97,100,100,114,101,115,115,3,98,99,115,5,98,121,116,101,115,10,102,114,111,109,95,98,121,116,101,115,20,105,110,116,111,95,114,101,109,97,105,110,100,101,114,95,98,121,116,101,115,6,108,101,110,103,116,104,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,12,112,101,101,108,95,97,100,100,114,101,115,115,9,112,101,101,108,95,98,111,111,108,19,112,101,101,108,95,111,112,116,105,111,110,95,97,100,100,114,101,115,115,16,112,101,101,108,95,111,112,116,105,111,110,95,98,111,111,108,16,112,101,101,108,95,111,112,116,105,111,110,95,117,49,50,56,15,112,101,101,108,95,111,112,116,105,111,110,95,117,54,52,14,112,101,101,108,95,111,112,116,105,111,110,95,117,56,9,112,101,101,108,95,117,49,50,56,8,112,101,101,108,95,117,54,52,7,112,101,101,108,95,117,56,16,112,101,101,108,95,118,101,99,95,97,100,100,114,101,115,115,13,112,101,101,108,95,118,101,99,95,98,111,111,108,15,112,101,101,108,95,118,101,99,95,108,101,110,103,116,104,13,112,101,101,108,95,118,101,99,95,117,49,50,56,12,112,101,101,108,95,118,101,99,95,117,54,52,11,112,101,101,108,95,118,101,99,95,117,56,15,112,101,101,108,95,118,101,99,95,118,101,99,95,117,56,7,114,101,118,101,114,115,101,4,115,111,109,101,8,116,111,95,98,121,116,101,115,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,10,5,1,0,10,1,1,0,10,2,1,0,10,10,2,1,0,10,3,1,0,10,4,1,0,0,2,1,4,10,2,0,1,0,0,19,3,11,0,56,0,2,1,1,0,0,19,5,13,0,56,1,11,0,18,0,2,2,1,0,0,1,7,11,0,19,0,12,1,13,1,56,1,11,1,2,3,1,0,0,22,35,10,0,16,0,65,6,17,25,38,4,7,5,11,11,0,1,7,0,39,64,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,12,2,12,1,10,2,17,25,35,4,30,5,20,13,1,10,0,15,0,69,6,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,11,1,17,24,2,4,1,0,0,23,21,11,0,17,5,12,2,10,2,49,0,33,4,10,9,12,1,5,19,11,2,49,1,33,4,15,5,17,7,1,39,8,12,1,11,1,2,5,1,0,0,19,15,10,0,16,0,65,6,6,1,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,11,0,15,0,69,6,2,6,1,0,0,24,40,10,0,16,0,65,6,6,8,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,64,35,4,36,5,20,10,0,15,0,69,6,52,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,7,1,0,0,25,40,10,0,16,0,65,6,6,16,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,128,35,4,36,5,20,10,0,15,0,69,6,53,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,8,1,0,0,26,48,6,0,0,0,0,0,0,0,0,49,0,6,0,0,0,0,0,0,0,0,12,2,12,3,12,4,10,2,6,4,0,0,0,0,0,0,0,37,4,11,5,15,11,0,1,7,2,39,10,0,15,0,69,6,52,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,4,10,1,6,127,0,0,0,0,0,0,0,28,10,3,47,27,12,4,11,1,6,128,0,0,0,0,0,0,0,28,6,0,0,0,0,0,0,0,0,33,4,39,5,44,11,3,49,7,22,12,3,5,6,11,0,1,11,4,2,9,1,0,0,27,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,3,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,3,68,4,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,10,1,0,0,28,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,4,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,4,68,5,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,11,1,0,0,29,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,5,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,5,68,6,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,12,1,0,0,30,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,6,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,11,68,1,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,13,1,0,0,31,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,7,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,6,68,7,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,14,1,0,0,32,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,8,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,7,68,8,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,15,1,0,0,14,14,10,0,17,4,4,8,11,0,17,3,56,2,12,1,5,12,11,0,1,56,3,12,1,11,1,2,16,1,0,0,15,14,10,0,17,4,4,8,11,0,17,4,56,4,12,1,5,12,11,0,1,56,5,12,1,11,1,2,17,1,0,0,16,14,10,0,17,4,4,8,11,0,17,5,56,6,12,1,5,12,11,0,1,56,7,12,1,11,1,2,18,1,0,0,17,14,10,0,17,4,4,8,11,0,17,6,56,8,12,1,5,12,11,0,1,56,9,12,1,11,1,2,19,1,0,0,18,14,10,0,17,4,4,8,11,0,17,7,56,10,12,1,5,12,11,0,1,56,11,12,1,11,1,2,0,0,0],"bls12381":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,12,7,24,56,8,80,32,12,112,8,0,0,0,2,0,1,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,8,98,108,115,49,50,51,56,49,22,98,108,115,49,50,51,56,49,95,109,105,110,95,112,107,95,118,101,114,105,102,121,23,98,108,115,49,50,51,56,49,95,109,105,110,95,115,105,103,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"borrow":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,24,3,32,59,4,91,10,5,101,83,7,184,1,158,1,8,214,2,64,6,150,3,20,10,170,3,19,11,189,3,2,12,191,3,125,13,188,4,4,14,192,4,4,0,5,1,15,0,14,0,19,0,3,4,1,12,0,0,0,0,0,1,2,7,1,0,0,2,1,7,0,3,4,2,0,0,12,0,1,1,12,0,5,2,3,1,12,0,16,4,5,1,12,0,6,1,6,1,12,1,7,9,6,1,0,1,8,11,6,1,0,1,9,15,5,1,0,1,18,6,9,1,0,2,11,12,13,1,8,3,10,7,8,0,7,6,5,6,8,6,6,6,4,6,2,9,0,7,8,4,1,11,0,1,9,0,1,7,11,0,1,9,0,2,9,0,8,1,3,7,11,0,1,9,0,9,0,8,1,0,1,9,0,1,7,8,4,1,5,1,11,2,1,9,0,2,8,3,9,0,1,7,11,2,1,9,0,1,6,9,0,1,8,3,2,8,3,5,2,7,11,2,1,9,0,9,0,6,66,111,114,114,111,119,2,73,68,6,79,112,116,105,111,110,8,82,101,102,101,114,101,110,116,9,84,120,67,111,110,116,101,120,116,6,98,111,114,114,111,119,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,7,101,120,116,114,97,99,116,4,102,105,108,108,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,3,111,98,106,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,117,116,95,98,97,99,107,3,114,101,102,4,115,111,109,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,2,11,5,20,11,2,1,9,0,1,2,2,17,5,13,8,3,0,6,0,1,0,0,5,6,11,1,17,9,11,0,56,0,57,0,2,1,1,0,0,10,14,10,0,54,0,56,1,12,2,14,2,56,2,12,1,11,2,11,0,55,1,20,11,1,18,1,2,2,1,0,0,14,30,11,2,19,1,12,3,12,4,14,1,56,2,11,3,33,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,11,4,33,4,21,5,25,11,0,1,7,0,39,11,0,54,0,11,1,56,3,2,3,1,0,0,9,7,11,0,58,0,12,1,1,11,1,56,4,2,0,1,0,0,0,6,1,6,0],"clock":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,31,4,51,2,5,53,30,7,83,122,8,205,1,32,6,237,1,44,10,153,2,8,12,161,2,79,13,240,2,2,0,3,0,7,0,11,0,12,0,0,8,0,1,2,4,0,3,1,2,0,0,10,0,1,0,0,5,2,3,0,0,4,4,3,0,1,3,3,6,0,2,9,8,3,1,8,3,8,2,5,0,4,7,1,6,8,0,1,3,1,6,8,2,0,3,7,8,0,3,6,8,2,1,5,1,8,1,1,8,0,1,9,0,5,67,108,111,99,107,9,84,120,67,111,110,116,101,120,116,3,85,73,68,5,99,108,111,99,107,25,99,111,110,115,101,110,115,117,115,95,99,111,109,109,105,116,95,112,114,111,108,111,103,117,101,6,99,114,101,97,116,101,2,105,100,6,111,98,106,101,99,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,1,10,3,0,1,0,0,3,4,11,0,16,0,20,2,1,0,0,0,3,13,11,0,17,5,7,1,33,4,6,5,8,7,0,39,17,3,6,0,0,0,0,0,0,0,0,18,0,56,0,2,2,0,0,0,3,15,11,2,17,5,7,1,33,4,6,5,10,11,0,1,7,0,39,11,1,11,0,15,0,21,2,0,1,0],"coin":[161,28,235,11,6,0,0,0,13,1,0,20,2,20,62,3,82,155,2,4,237,2,34,5,143,3,221,2,7,236,5,164,5,8,144,11,64,6,208,11,30,10,238,11,52,11,162,12,6,12,168,12,249,4,13,161,17,14,14,175,17,14,0,15,1,11,1,43,1,48,0,12,0,42,0,56,0,58,0,59,0,64,0,1,12,1,0,1,0,2,12,1,0,1,0,7,12,1,0,1,0,3,3,1,0,1,1,5,7,0,2,4,7,1,0,0,3,5,7,0,4,0,4,1,0,1,4,6,4,1,0,1,5,9,4,0,7,8,2,0,9,10,7,0,0,55,0,1,1,0,0,57,2,3,1,0,0,50,0,4,1,0,0,51,5,6,1,0,0,66,7,1,1,0,0,12,7,8,1,0,0,13,9,10,1,0,0,24,11,12,1,0,0,33,12,13,1,0,0,54,14,12,1,0,0,45,15,16,1,0,0,35,17,16,1,0,0,47,18,12,1,0,0,23,18,19,1,0,0,67,20,12,1,0,0,22,12,16,1,0,0,16,21,22,1,2,0,36,23,12,1,0,0,38,24,13,1,0,0,14,25,1,1,0,0,37,26,16,1,0,0,62,27,16,1,0,0,63,28,16,1,0,0,60,27,16,1,0,0,61,28,16,1,0,0,25,29,30,1,0,0,28,29,31,1,0,0,29,29,32,1,0,0,26,29,31,1,0,0,27,29,33,1,0,0,49,5,4,1,0,1,48,41,32,0,2,46,34,46,1,0,3,65,41,31,0,4,17,34,3,1,2,4,19,43,1,1,0,4,22,13,16,1,0,4,32,42,13,1,0,4,35,37,1,1,0,4,47,36,13,1,0,4,52,4,1,1,0,4,66,8,1,1,0,4,67,16,13,1,0,5,20,35,16,0,5,40,20,35,0,6,44,44,16,1,12,8,34,39,40,1,2,9,41,32,45,0,40,34,41,34,39,34,8,34,38,34,9,34,4,34,12,34,42,34,36,34,46,34,34,34,37,34,35,34,17,34,45,12,32,45,1,6,11,2,1,9,0,1,3,1,11,2,1,9,0,1,11,8,1,9,0,1,6,11,8,1,9,0,1,7,11,2,1,9,0,1,7,11,8,1,9,0,1,6,11,0,1,9,0,1,6,11,7,1,9,0,1,7,11,0,1,9,0,1,7,11,7,1,9,0,2,11,7,1,9,0,7,8,10,1,11,0,1,9,0,1,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,10,2,7,11,7,1,9,0,11,0,1,9,0,0,2,7,11,0,1,9,0,11,0,1,9,0,3,7,11,0,1,9,0,3,7,8,10,1,10,11,0,1,9,0,1,7,8,10,7,9,0,2,10,2,10,2,10,2,11,5,1,8,11,7,8,10,2,11,2,1,9,0,11,1,1,9,0,3,7,11,2,1,9,0,3,7,8,10,2,7,11,2,1,9,0,3,2,7,11,2,1,9,0,11,0,1,9,0,4,7,11,2,1,9,0,3,5,7,8,10,3,6,11,2,1,9,0,7,11,1,1,9,0,8,6,3,6,11,2,1,9,0,7,11,1,1,9,0,8,4,1,6,11,1,1,9,0,1,2,1,8,6,1,8,4,1,11,5,1,8,11,1,9,0,1,8,9,2,7,11,7,1,9,0,3,2,7,11,7,1,9,0,11,7,1,9,0,3,3,3,10,11,0,1,9,0,1,6,9,0,1,1,1,10,2,2,7,11,8,1,9,0,3,2,7,11,8,1,9,0,11,7,1,9,0,2,9,0,5,1,8,11,1,11,5,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,15,67,117,114,114,101,110,99,121,67,114,101,97,116,101,100,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,85,114,108,5,97,115,99,105,105,7,98,97,108,97,110,99,101,11,98,97,108,97,110,99,101,95,109,117,116,4,98,117,114,110,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,13,99,114,101,97,116,101,95,115,117,112,112,108,121,8,100,101,99,105,109,97,108,115,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,6,100,101,108,101,116,101,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,122,101,114,111,13,100,105,118,105,100,101,95,105,110,116,111,95,110,12,102,114,111,109,95,98,97,108,97,110,99,101,12,103,101,116,95,100,101,99,105,109,97,108,115,15,103,101,116,95,100,101,115,99,114,105,112,116,105,111,110,12,103,101,116,95,105,99,111,110,95,117,114,108,8,103,101,116,95,110,97,109,101,10,103,101,116,95,115,121,109,98,111,108,8,105,99,111,110,95,117,114,108,2,105,100,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,12,105,110,116,111,95,98,97,108,97,110,99,101,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,4,106,111,105,110,4,109,105,110,116,17,109,105,110,116,95,97,110,100,95,116,114,97,110,115,102,101,114,12,109,105,110,116,95,98,97,108,97,110,99,101,4,110,97,109,101,3,110,101,119,10,110,101,119,95,117,110,115,97,102,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,3,112,117,116,4,115,111,109,101,5,115,112,108,105,116,6,115,116,114,105,110,103,6,115,117,112,112,108,121,12,115,117,112,112,108,121,95,105,109,109,117,116,10,115,117,112,112,108,121,95,109,117,116,12,115,117,112,112,108,121,95,118,97,108,117,101,6,115,121,109,98,111,108,4,116,97,107,101,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,5,116,121,112,101,115,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,15,117,112,100,97,116,101,95,105,99,111,110,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,13,117,112,100,97,116,101,95,115,121,109,98,111,108,3,117,114,108,4,117,116,102,56,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,2,31,8,9,12,11,7,1,9,0,1,2,6,31,8,9,18,2,39,8,6,53,8,4,21,8,6,30,11,5,1,8,11,2,2,2,31,8,9,55,11,8,1,9,0,3,2,1,18,2,2,34,0,34,1,34,0,1,0,0,16,4,11,0,55,0,56,0,2,1,1,0,0,3,6,11,0,58,0,12,1,17,43,11,1,2,2,1,0,0,16,3,11,0,55,0,2,3,1,0,0,16,3,11,0,54,0,2,4,1,0,0,16,4,11,0,55,1,56,1,2,5,1,0,0,16,3,11,0,55,1,2,6,1,0,0,16,3,11,0,54,1,2,7,1,0,0,16,5,11,1,17,44,11,0,57,1,2,8,1,0,0,13,6,11,0,58,1,12,1,17,43,11,1,2,9,1,0,0,16,7,11,2,17,44,11,0,11,1,56,2,57,1,2,10,1,0,0,16,6,11,0,11,1,56,3,56,4,1,2,11,1,4,0,13,10,11,1,58,1,12,2,17,43,11,0,54,1,11,2,56,4,1,2,12,1,0,0,16,6,11,0,54,1,11,1,11,2,56,5,2,13,1,0,0,38,59,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,11,11,0,1,11,2,1,7,1,39,10,1,10,0,46,56,6,37,4,18,5,24,11,0,1,11,2,1,7,2,39,64,12,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,3,10,0,46,56,6,10,1,26,12,4,40,10,3,10,1,6,1,0,0,0,0,0,0,0,23,35,4,53,5,42,13,5,10,0,10,4,10,2,56,7,68,12,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,34,11,0,1,11,2,1,11,5,2,14,1,0,0,16,5,11,0,17,44,56,8,57,1,2,15,1,0,0,13,7,11,0,58,1,12,1,17,43,11,1,56,9,2,16,1,0,0,16,25,14,0,56,10,4,4,5,8,11,6,1,7,0,39,10,6,17,44,11,0,56,11,57,0,11,6,17,44,11,1,11,3,17,33,11,2,17,31,11,4,17,33,11,5,57,2,2,17,1,0,0,16,8,11,2,17,44,11,0,54,0,11,1,56,12,57,1,2,18,1,0,0,16,5,11,0,54,0,11,1,56,12,2,19,1,4,0,13,9,11,1,58,1,12,2,17,43,11,0,54,0,11,2,56,13,2,20,1,4,0,16,7,11,0,11,1,11,3,56,14,11,2,56,15,2,21,1,4,0,16,5,11,2,11,1,54,2,21,2,22,1,4,0,16,5,11,2,11,1,54,3,21,2,23,1,4,0,16,5,11,2,11,1,54,4,21,2,24,1,4,0,16,7,11,2,17,47,56,16,11,1,54,5,21,2,25,1,0,0,16,4,11,0,55,6,20,2,26,1,0,0,16,4,11,0,55,2,20,2,27,1,0,0,16,4,11,0,55,3,20,2,28,1,0,0,16,4,11,0,55,4,20,2,29,1,0,0,16,4,11,0,55,5,20,2,30,1,0,0,16,3,11,0,55,0,2,2,1,0,1,1,2,1,3,1,4,1,5,1,1,0,34,1,34,2,34,3,34,4,34,5,34,6,34,0],"display":[161,28,235,11,6,0,0,0,13,1,0,16,2,16,46,3,62,132,1,4,194,1,22,5,216,1,196,1,7,156,3,223,2,8,251,5,64,6,187,6,20,10,207,6,38,11,245,6,6,12,251,6,160,3,13,155,10,6,14,161,10,6,0,14,1,31,0,18,0,26,0,27,0,32,0,33,0,36,0,0,12,1,8,1,0,1,3,1,8,1,0,8,3,1,8,1,1,4,7,0,3,2,7,0,3,6,4,0,4,3,12,0,6,5,2,0,7,7,7,2,1,0,0,0,0,24,0,1,1,8,0,25,2,1,1,8,0,12,0,3,1,8,0,35,4,3,1,8,0,9,5,3,1,8,0,11,6,3,1,8,0,15,5,3,1,8,0,29,7,3,1,8,0,23,8,9,1,8,0,37,10,11,1,8,0,19,10,12,1,8,0,13,13,1,1,8,0,10,5,3,1,8,2,16,14,3,1,3,3,24,13,28,0,3,34,21,22,0,4,20,8,9,1,0,5,28,19,3,1,12,6,30,17,18,0,7,17,3,30,2,1,0,7,22,31,3,2,1,0,7,29,26,27,2,1,0,8,14,11,14,0,14,12,14,17,1,13,23,21,25,16,14,13,29,19,25,20,25,2,6,8,6,7,8,7,1,11,0,1,9,0,4,6,8,6,10,8,3,10,8,3,7,8,7,0,1,7,11,0,1,9,0,3,7,11,0,1,9,0,8,3,8,3,3,7,11,0,1,9,0,10,8,3,10,8,3,2,7,11,0,1,9,0,8,3,1,6,8,6,1,1,1,6,11,0,1,9,0,1,13,1,6,11,8,2,8,3,8,3,1,7,8,7,1,9,0,3,11,0,1,9,0,3,3,1,8,3,1,6,8,7,1,5,2,9,0,5,2,13,11,8,2,8,3,8,3,1,6,8,5,1,8,4,1,11,2,1,9,0,2,3,3,2,8,3,8,3,2,7,11,8,2,9,0,9,1,6,9,0,2,9,0,9,1,1,8,5,1,11,1,1,9,0,1,11,8,2,9,0,9,1,3,7,11,8,2,9,0,9,1,9,0,9,1,7,68,105,115,112,108,97,121,14,68,105,115,112,108,97,121,67,114,101,97,116,101,100,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,6,86,101,99,77,97,112,14,86,101,114,115,105,111,110,85,112,100,97,116,101,100,3,97,100,100,12,97,100,100,95,105,110,116,101,114,110,97,108,12,97,100,100,95,109,117,108,116,105,112,108,101,15,99,114,101,97,116,101,95,97,110,100,95,107,101,101,112,15,99,114,101,97,116,101,95,105,110,116,101,114,110,97,108,7,100,105,115,112,108,97,121,4,101,100,105,116,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,6,102,105,101,108,100,115,12,102,114,111,109,95,112,97,99,107,97,103,101,2,105,100,6,105,110,115,101,114,116,13,105,115,95,97,117,116,104,111,114,105,122,101,100,3,110,101,119,15,110,101,119,95,119,105,116,104,95,102,105,101,108,100,115,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,6,115,101,110,100,101,114,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,112,100,97,116,101,95,118,101,114,115,105,111,110,7,118,101,99,95,109,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,3,21,8,5,19,11,8,2,8,3,8,3,37,13,1,2,1,21,8,4,2,2,3,21,8,4,37,13,19,11,8,2,8,3,8,3,2,14,1,14,0,14,0,1,0,0,3,11,11,0,56,0,4,4,5,8,11,1,1,7,0,39,11,1,56,1,2,1,1,0,0,15,43,14,1,65,16,12,6,10,6,14,2,65,16,33,4,9,5,15,11,0,1,11,3,1,7,1,39,6,0,0,0,0,0,0,0,0,12,5,11,0,11,3,56,2,12,4,10,5,10,6,35,4,41,5,26,13,4,14,1,10,5,66,16,20,14,2,10,5,66,16,20,56,3,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,21,11,4,2,2,1,4,0,3,8,11,0,10,1,56,2,11,1,46,17,18,56,4,2,3,1,4,0,20,24,10,0,55,0,20,72,1,0,22,10,0,54,0,21,10,0,55,0,20,12,1,10,0,55,1,20,12,2,11,0,55,2,17,15,11,1,11,2,57,0,56,5,2,4,1,4,0,3,5,11,0,11,1,11,2,56,3,2,5,1,4,0,24,38,14,1,65,16,12,4,10,4,14,2,65,16,33,4,9,5,13,11,0,1,7,1,39,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,35,5,20,10,0,14,1,10,3,66,16,20,14,2,10,3,66,16,20,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,15,11,0,1,2,6,1,4,0,3,11,10,0,54,1,14,1,56,6,1,1,11,0,11,1,11,2,56,3,2,7,1,4,0,3,7,11,0,54,1,14,1,56,6,1,1,2,8,1,0,0,3,3,11,0,56,7,2,9,1,0,0,3,4,11,0,55,0,20,2,10,1,0,0,3,3,11,0,55,1,2,11,0,0,0,28,12,11,0,17,14,12,1,14,1,17,15,57,1,56,8,11,1,56,9,72,0,0,57,2,2,12,0,0,0,3,6,11,0,54,1,11,1,11,2,56,10,2,0,2,0,1,0,0,0,14,1,14,2,14,0],"dynamic_field":[161,28,235,11,6,0,0,0,14,1,0,6,2,6,22,3,28,133,1,4,161,1,24,5,185,1,168,1,7,225,2,129,3,8,226,5,64,6,162,6,40,10,202,6,12,11,214,6,2,12,216,6,235,2,13,195,9,6,14,201,9,8,15,209,9,2,0,11,1,26,0,25,0,0,8,2,7,0,4,0,1,2,7,1,0,0,2,1,7,0,2,3,4,0,0,4,0,1,2,7,4,0,6,2,3,2,7,4,0,9,4,5,2,7,4,0,27,4,6,2,7,4,0,13,2,7,1,7,0,29,4,8,2,7,4,0,14,2,7,2,7,4,0,15,2,9,1,7,0,16,4,10,1,7,0,19,11,12,1,7,0,5,11,1,1,8,0,7,9,13,1,8,0,8,10,14,1,8,0,28,15,16,1,8,0,17,15,7,0,0,18,15,7,1,8,1,24,1,24,1,0,1,30,16,24,1,0,2,10,19,1,0,2,21,28,12,0,2,23,12,19,0,2,31,18,12,0,9,16,10,21,11,21,12,21,13,21,4,16,3,20,17,6,16,6,15,21,11,26,12,26,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,9,1,2,6,8,3,5,2,7,8,3,5,2,5,9,0,1,5,1,6,9,0,1,7,9,0,2,5,5,1,9,0,3,11,0,2,9,0,9,1,5,5,1,6,8,3,1,8,3,2,9,0,9,1,1,11,0,2,9,0,9,1,3,5,5,9,1,2,9,0,11,1,1,9,1,1,11,1,1,9,0,4,6,11,0,2,9,0,8,2,5,6,8,3,6,8,2,1,11,0,2,9,0,8,2,2,9,0,8,2,1,6,8,2,4,7,11,0,2,9,0,8,2,5,7,8,3,7,8,2,5,70,105,101,108,100,2,73,68,6,79,112,116,105,111,110,3,85,73,68,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,6,100,101,108,101,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,16,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,17,104,97,115,104,95,116,121,112,101,95,97,110,100,95,107,101,121,2,105,100,13,105,100,95,116,111,95,97,100,100,114,101,115,115,4,110,97,109,101,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,3,20,8,3,22,9,0,32,9,1,0,20,0,1,0,0,17,26,11,0,46,17,21,12,5,10,5,10,1,56,0,12,4,10,5,10,4,17,14,32,4,14,5,16,7,0,39,11,4,17,20,11,1,11,2,57,0,12,3,11,5,11,3,56,1,2,1,1,0,0,12,10,10,0,17,21,11,1,56,0,12,2,11,0,11,2,56,2,55,0,2,2,1,0,0,12,11,10,0,46,17,21,11,1,56,0,12,2,11,0,11,2,56,3,54,0,2,3,1,0,0,22,17,11,0,46,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,4,58,0,12,4,1,17,18,11,4,2,4,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,17,14,2,5,1,0,0,23,19,10,0,10,1,12,2,46,11,2,56,5,4,13,11,0,11,1,56,6,56,7,12,3,5,17,11,0,1,56,8,12,3,11,3,2,6,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,9,2,7,3,0,0,25,22,10,0,17,21,11,1,56,0,12,3,11,0,11,3,56,10,12,2,10,2,55,1,12,4,10,2,55,2,1,11,2,55,3,12,5,11,4,11,5,17,19,2,8,3,0,0,29,24,10,0,46,17,21,11,1,56,0,12,3,11,0,11,3,56,11,12,2,10,2,54,1,12,4,10,2,54,2,1,11,2,54,3,12,5,11,4,11,5,46,17,19,2,9,3,2,0,10,3,2,0,11,3,2,0,12,3,2,0,13,3,2,0,14,3,2,0,15,3,2,0,0,2,0,0,0,1,0,20,1,27,2,27,0,27,0,12,0],"dynamic_object_field":[161,28,235,11,6,0,0,0,10,1,0,8,2,8,20,3,28,138,1,4,166,1,26,5,192,1,131,1,7,195,2,178,2,8,245,4,64,10,181,5,6,11,187,5,2,12,189,5,233,1,0,11,1,22,0,10,0,21,0,3,7,1,0,0,1,1,7,1,0,0,3,0,7,0,3,2,4,0,0,4,0,1,2,7,12,0,6,2,3,2,7,12,0,9,4,5,2,7,12,0,23,4,6,2,7,12,0,12,2,7,1,7,0,13,2,7,2,7,12,0,17,2,8,1,7,1,20,1,24,1,0,1,25,10,24,1,0,2,4,0,1,2,7,4,2,5,18,1,1,8,2,7,15,11,1,8,2,8,19,20,1,8,2,13,2,7,2,7,4,2,14,2,15,1,7,2,15,4,19,1,7,2,16,22,7,1,8,2,23,4,6,2,7,4,2,24,22,10,1,8,3,17,11,12,1,8,3,18,17,12,0,3,26,16,17,0,19,6,9,13,14,14,10,6,11,6,15,14,12,6,18,6,17,13,13,13,16,6,7,12,8,12,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,8,2,3,11,0,1,9,0,8,2,11,0,1,9,0,1,9,0,1,6,9,0,1,8,2,2,11,0,1,9,0,8,2,1,11,0,1,9,0,2,6,8,3,5,1,6,8,3,1,5,2,5,9,0,2,7,8,3,5,1,7,9,0,4,11,0,1,9,0,11,0,1,9,0,9,1,5,2,5,5,2,11,0,1,9,0,5,1,11,1,1,9,0,2,73,68,6,79,112,116,105,111,110,3,85,73,68,7,87,114,97,112,112,101,114,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,4,110,97,109,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,19,9,0,0,10,0,1,0,0,9,21,11,1,57,0,12,5,14,2,56,0,12,4,10,0,10,5,11,4,56,1,11,0,11,5,12,3,46,11,3,56,2,1,17,21,11,2,56,3,2,1,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,2,56,4,2,2,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,5,56,6,2,3,1,0,0,21,20,11,1,57,0,12,3,10,0,10,3,12,2,46,11,2,56,2,12,5,17,21,11,5,56,7,12,4,11,0,11,3,56,8,1,11,4,2,4,1,0,0,14,7,11,1,57,0,12,2,11,0,11,2,56,9,2,5,1,0,0,23,20,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,9,2,11,0,11,2,56,2,12,3,17,21,11,3,56,10,2,6,1,0,0,23,21,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,56,11,2,11,0,11,2,56,2,12,3,1,11,3,17,20,56,12,2,0],"ecdsa_k1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,15,5,17,28,7,45,64,8,109,32,6,141,1,26,12,167,1,12,0,1,0,2,0,1,0,0,0,2,1,0,0,3,3,4,0,3,6,10,2,6,10,2,2,1,10,2,1,6,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,17,100,101,99,111,109,112,114,101,115,115,95,112,117,98,107,101,121,8,101,99,100,115,97,95,107,49,19,115,101,99,112,50,53,54,107,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,107,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,2,1,2,0,0],"ecdsa_r1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,10,5,12,24,7,36,46,8,82,32,6,114,26,12,140,1,8,0,0,0,1,0,1,0,0,2,2,3,0,3,6,10,2,6,10,2,2,1,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,8,101,99,100,115,97,95,114,49,19,115,101,99,112,50,53,54,114,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,114,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,0],"ecvrf":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,5,5,7,15,7,22,19,8,41,32,6,73,30,12,103,4,0,0,0,1,0,1,0,4,6,10,2,6,10,2,6,10,2,6,10,2,1,1,5,101,99,118,114,102,12,101,99,118,114,102,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,1,2,0,0],"ed25519":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,12,7,19,23,8,42,32,12,74,4,0,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,7,101,100,50,53,53,49,57,14,101,100,50,53,53,49,57,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"event":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,4,7,12,11,8,23,32,12,55,4,0,1,0,0,0,1,1,3,1,9,0,0,4,101,109,105,116,5,101,118,101,110,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"groth16":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,16,3,18,50,5,68,76,7,144,1,237,2,8,253,3,32,6,157,4,30,10,187,4,32,12,219,4,180,1,13,143,6,14,0,10,0,0,7,0,0,1,7,0,0,3,7,0,0,2,7,0,0,5,0,1,0,0,6,0,1,0,0,16,2,3,0,0,17,3,4,0,0,15,5,6,0,0,14,5,7,0,0,12,8,3,0,0,13,9,3,0,0,18,10,11,0,0,19,12,11,0,0,1,8,0,4,10,2,10,2,10,2,10,2,1,8,1,1,10,10,2,1,10,2,1,8,2,1,8,3,2,6,8,0,6,10,2,2,2,6,10,2,4,6,8,0,6,8,1,6,8,2,6,8,3,1,1,7,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,5,67,117,114,118,101,20,80,114,101,112,97,114,101,100,86,101,114,105,102,121,105,110,103,75,101,121,11,80,114,111,111,102,80,111,105,110,116,115,17,80,117,98,108,105,99,80,114,111,111,102,73,110,112,117,116,115,22,97,108,112,104,97,95,103,49,95,98,101,116,97,95,103,50,95,98,121,116,101,115,8,98,108,115,49,50,51,56,49,5,98,110,50,53,52,5,98,121,116,101,115,21,100,101,108,116,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,21,103,97,109,109,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,7,103,114,111,116,104,49,54,2,105,100,21,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,30,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,95,105,110,116,101,114,110,97,108,23,112,114,111,111,102,95,112,111,105,110,116,115,95,102,114,111,109,95,98,121,116,101,115,30,112,117,98,108,105,99,95,112,114,111,111,102,95,105,110,112,117,116,115,95,102,114,111,109,95,98,121,116,101,115,14,112,118,107,95,102,114,111,109,95,98,121,116,101,115,12,112,118,107,95,116,111,95,98,121,116,101,115,20,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,29,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,95,105,110,116,101,114,110,97,108,21,118,107,95,103,97,109,109,97,95,97,98,99,95,103,49,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,11,2,1,2,4,20,10,2,4,10,2,9,10,2,8,10,2,2,2,1,7,10,2,3,2,1,7,10,2,0,1,0,0,0,3,49,0,18,0,2,1,1,0,0,0,3,49,1,18,0,2,2,1,0,0,0,6,11,0,11,1,11,2,11,3,18,1,2,3,1,0,0,4,24,64,5,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,68,5,13,1,14,0,16,1,20,68,5,13,1,14,0,16,2,20,68,5,13,1,14,0,16,3,20,68,5,11,1,2,4,1,0,0,0,3,11,0,18,2,2,5,1,0,0,0,3,11,0,18,3,2,6,1,0,0,0,6,11,0,16,4,20,11,1,17,7,2,7,0,2,0,8,1,0,0,0,17,11,0,16,4,20,10,1,16,0,10,1,16,1,10,1,16,2,11,1,16,3,11,2,16,5,11,3,16,6,17,9,2,9,0,2,0,1,0,1,1,1,2,1,3,0,0,2,0,3,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,7,7,19,26,8,45,32,12,77,8,0,1,0,0,0,1,0,0,2,0,1,0,1,6,10,2,1,10,2,10,98,108,97,107,101,50,98,50,53,54,4,104,97,115,104,9,107,101,99,99,97,107,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"hex":[161,28,235,11,6,0,0,0,8,1,0,4,3,4,21,4,25,2,5,27,37,7,64,44,8,108,64,6,172,1,159,6,12,203,7,194,2,0,4,1,5,0,3,0,0,0,0,1,0,0,0,0,2,1,1,0,1,0,3,4,1,0,3,1,1,10,2,1,2,5,10,10,2,7,10,2,3,3,10,2,2,7,10,9,0,10,9,0,0,4,2,3,3,10,2,5,1,1,1,2,2,6,97,112,112,101,110,100,6,100,101,99,111,100,101,11,100,101,99,111,100,101,95,98,121,116,101,6,101,110,99,111,100,101,3,104,101,120,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,10,10,2,130,6,128,2,2,48,48,2,48,49,2,48,50,2,48,51,2,48,52,2,48,53,2,48,54,2,48,55,2,48,56,2,48,57,2,48,97,2,48,98,2,48,99,2,48,100,2,48,101,2,48,102,2,49,48,2,49,49,2,49,50,2,49,51,2,49,52,2,49,53,2,49,54,2,49,55,2,49,56,2,49,57,2,49,97,2,49,98,2,49,99,2,49,100,2,49,101,2,49,102,2,50,48,2,50,49,2,50,50,2,50,51,2,50,52,2,50,53,2,50,54,2,50,55,2,50,56,2,50,57,2,50,97,2,50,98,2,50,99,2,50,100,2,50,101,2,50,102,2,51,48,2,51,49,2,51,50,2,51,51,2,51,52,2,51,53,2,51,54,2,51,55,2,51,56,2,51,57,2,51,97,2,51,98,2,51,99,2,51,100,2,51,101,2,51,102,2,52,48,2,52,49,2,52,50,2,52,51,2,52,52,2,52,53,2,52,54,2,52,55,2,52,56,2,52,57,2,52,97,2,52,98,2,52,99,2,52,100,2,52,101,2,52,102,2,53,48,2,53,49,2,53,50,2,53,51,2,53,52,2,53,53,2,53,54,2,53,55,2,53,56,2,53,57,2,53,97,2,53,98,2,53,99,2,53,100,2,53,101,2,53,102,2,54,48,2,54,49,2,54,50,2,54,51,2,54,52,2,54,53,2,54,54,2,54,55,2,54,56,2,54,57,2,54,97,2,54,98,2,54,99,2,54,100,2,54,101,2,54,102,2,55,48,2,55,49,2,55,50,2,55,51,2,55,52,2,55,53,2,55,54,2,55,55,2,55,56,2,55,57,2,55,97,2,55,98,2,55,99,2,55,100,2,55,101,2,55,102,2,56,48,2,56,49,2,56,50,2,56,51,2,56,52,2,56,53,2,56,54,2,56,55,2,56,56,2,56,57,2,56,97,2,56,98,2,56,99,2,56,100,2,56,101,2,56,102,2,57,48,2,57,49,2,57,50,2,57,51,2,57,52,2,57,53,2,57,54,2,57,55,2,57,56,2,57,57,2,57,97,2,57,98,2,57,99,2,57,100,2,57,101,2,57,102,2,97,48,2,97,49,2,97,50,2,97,51,2,97,52,2,97,53,2,97,54,2,97,55,2,97,56,2,97,57,2,97,97,2,97,98,2,97,99,2,97,100,2,97,101,2,97,102,2,98,48,2,98,49,2,98,50,2,98,51,2,98,52,2,98,53,2,98,54,2,98,55,2,98,56,2,98,57,2,98,97,2,98,98,2,98,99,2,98,100,2,98,101,2,98,102,2,99,48,2,99,49,2,99,50,2,99,51,2,99,52,2,99,53,2,99,54,2,99,55,2,99,56,2,99,57,2,99,97,2,99,98,2,99,99,2,99,100,2,99,101,2,99,102,2,100,48,2,100,49,2,100,50,2,100,51,2,100,52,2,100,53,2,100,54,2,100,55,2,100,56,2,100,57,2,100,97,2,100,98,2,100,99,2,100,100,2,100,101,2,100,102,2,101,48,2,101,49,2,101,50,2,101,51,2,101,52,2,101,53,2,101,54,2,101,55,2,101,56,2,101,57,2,101,97,2,101,98,2,101,99,2,101,100,2,101,101,2,101,102,2,102,48,2,102,49,2,102,50,2,102,51,2,102,52,2,102,53,2,102,54,2,102,55,2,102,56,2,102,57,2,102,97,2,102,98,2,102,99,2,102,100,2,102,101,2,102,102,10,2,1,0,0,1,0,0,2,33,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,4,12,5,12,3,10,3,10,4,35,4,31,5,12,13,5,12,2,7,2,12,1,11,2,14,1,14,0,10,3,66,1,20,52,66,0,20,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,5,2,1,1,0,0,5,47,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,3,12,4,12,2,10,3,6,2,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,14,5,16,7,0,39,10,2,10,3,35,4,45,5,21,14,0,10,2,66,1,20,17,2,49,16,24,14,0,10,2,6,1,0,0,0,0,0,0,0,22,66,1,20,17,2,22,12,1,13,4,11,1,68,1,11,2,6,2,0,0,0,0,0,0,0,22,12,2,5,16,11,4,2,2,0,0,0,6,64,49,48,10,0,37,4,9,10,0,49,58,35,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,5,5,62,49,65,10,0,37,4,27,10,0,49,71,35,12,2,5,29,9,12,2,11,2,4,38,49,10,11,0,22,49,65,23,12,4,5,60,49,97,10,0,37,4,47,10,0,49,103,35,12,3,5,49,9,12,3,11,3,4,52,5,54,7,1,39,49,10,11,0,22,49,97,23,12,4,11,4,12,5,11,5,2,0],"hmac":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,10,7,17,19,8,36,32,12,68,4,0,0,0,1,0,1,0,2,6,10,2,6,10,2,1,10,2,4,104,109,97,99,13,104,109,97,99,95,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"kiosk":[161,28,235,11,6,0,0,0,14,1,0,24,2,24,94,3,118,135,3,4,253,3,68,5,193,4,137,4,7,202,8,159,8,8,233,16,64,6,169,17,130,1,10,171,18,101,11,144,19,8,12,152,19,146,14,13,170,33,18,14,188,33,6,15,194,33,2,0,50,1,62,0,21,0,26,0,31,0,32,0,34,0,61,0,86,0,88,0,89,0,90,0,8,12,0,0,9,12,0,0,13,12,1,12,1,0,1,0,0,0,4,7,0,0,10,7,0,0,11,7,0,0,6,3,1,12,1,0,7,3,1,12,1,0,5,3,1,12,1,1,12,7,1,0,0,2,0,4,1,0,1,3,2,12,1,0,1,7,3,7,0,7,18,4,0,8,14,2,0,10,15,12,1,0,1,10,16,0,1,0,1,11,17,2,0,0,27,0,1,0,0,59,0,2,0,0,25,3,4,0,0,83,5,1,0,0,84,6,1,0,0,64,7,1,1,12,0,56,8,1,1,12,0,87,9,10,1,12,0,54,11,1,1,12,0,65,12,1,1,12,0,29,9,1,1,12,0,71,13,14,1,12,0,55,15,16,1,12,0,75,17,14,1,12,0,79,18,1,1,12,0,97,19,4,0,0,57,20,1,1,12,0,66,20,1,1,12,0,94,21,22,0,0,40,23,24,0,0,41,23,24,1,12,0,46,23,24,0,0,44,23,24,0,0,45,23,24,0,0,39,25,24,0,0,93,25,22,0,0,82,26,1,0,0,91,27,28,0,0,92,21,22,0,0,63,27,29,0,0,48,27,30,0,0,69,27,31,0,0,70,25,32,0,0,22,33,34,1,12,0,23,9,35,1,12,0,24,9,36,1,12,0,80,37,1,1,12,0,53,38,39,0,0,73,40,39,1,12,0,72,40,39,1,12,0,74,40,31,1,12,1,30,74,10,1,0,1,47,73,24,1,0,2,96,75,31,1,0,2,98,1,48,1,0,3,38,50,51,1,0,3,76,65,1,1,0,3,87,76,51,1,0,3,96,63,31,1,0,4,19,59,1,2,7,4,4,35,78,24,1,7,4,77,54,57,2,7,4,4,78,54,55,2,7,4,5,19,59,1,2,7,12,5,22,78,81,2,7,12,5,23,54,82,2,7,12,5,35,78,24,1,7,5,36,78,24,2,7,12,5,77,54,57,2,7,12,6,33,10,1,1,3,7,28,46,1,0,7,42,34,39,1,8,7,59,0,46,0,7,95,28,39,0,9,85,10,1,1,8,9,88,44,1,1,8,10,60,67,68,1,0,11,81,42,29,0,65,43,64,45,44,47,61,45,45,47,17,10,16,10,52,53,58,56,20,10,49,53,59,60,61,10,5,10,8,10,51,53,59,61,48,47,52,64,46,47,59,66,66,10,42,31,41,31,43,47,47,47,49,64,53,56,56,77,57,56,50,79,50,80,54,56,55,56,1,7,8,18,0,2,8,0,8,1,3,8,0,8,1,7,8,18,1,11,12,1,8,15,3,7,8,0,6,8,1,6,8,18,3,7,8,0,6,8,1,5,3,7,8,0,6,8,1,9,0,4,7,8,0,6,8,1,6,11,16,1,9,0,9,0,3,7,8,0,6,8,1,8,13,1,9,0,4,7,8,0,6,8,1,8,13,3,4,7,8,0,6,8,1,9,0,3,3,7,8,0,8,13,11,12,1,8,15,2,9,0,11,17,1,9,0,5,7,8,0,6,8,1,8,13,3,7,8,18,1,11,2,1,9,0,3,7,8,0,11,2,1,9,0,11,12,1,8,15,2,7,8,0,11,2,1,9,0,4,7,8,0,6,8,1,11,10,1,3,7,8,18,2,7,8,0,9,0,1,7,8,0,1,7,8,14,2,6,8,0,8,13,1,1,2,7,8,0,6,8,1,3,7,8,0,6,8,1,1,1,6,8,0,1,6,8,14,1,5,1,14,1,3,1,7,11,11,1,8,15,3,6,8,0,6,8,1,8,13,1,6,9,0,1,7,9,0,2,9,0,8,3,3,7,8,0,9,0,8,3,1,6,8,1,1,8,13,1,6,11,2,1,9,0,2,8,1,8,0,1,6,8,18,1,8,1,2,9,0,5,1,8,0,1,8,14,1,8,15,1,11,11,1,9,0,5,8,14,8,13,8,14,14,11,11,1,8,15,2,11,11,1,9,0,7,8,18,1,11,12,1,9,0,3,8,13,8,13,8,13,2,8,5,3,2,7,8,14,9,0,1,11,10,1,9,1,2,8,4,9,0,1,9,1,2,8,13,8,13,3,7,8,14,9,0,9,1,1,11,7,1,9,0,1,11,9,1,9,0,2,9,0,3,1,6,11,12,1,9,0,2,8,6,1,2,7,11,11,1,9,0,11,12,1,9,0,1,11,8,1,9,0,3,8,13,3,8,13,1,11,17,1,9,0,6,8,13,8,13,3,8,13,8,14,8,13,5,8,13,8,13,8,13,3,3,3,8,14,8,13,8,13,3,3,3,3,1,6,11,10,1,9,0,1,11,10,1,9,0,1,6,11,11,1,9,0,3,7,11,11,1,9,0,3,7,8,18,1,8,4,2,6,8,14,9,0,1,8,6,1,8,5,1,6,9,1,1,7,9,1,7,66,97,108,97,110,99,101,6,66,111,114,114,111,119,4,67,111,105,110,2,73,68,4,73,116,101,109,12,73,116,101,109,68,101,108,105,115,116,101,100,10,73,116,101,109,76,105,115,116,101,100,13,73,116,101,109,80,117,114,99,104,97,115,101,100,5,75,105,111,115,107,13,75,105,111,115,107,79,119,110,101,114,67,97,112,7,76,105,115,116,105,110,103,4,76,111,99,107,6,79,112,116,105,111,110,11,80,117,114,99,104,97,115,101,67,97,112,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,16,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,10,98,111,114,114,111,119,95,118,97,108,18,99,108,111,115,101,95,97,110,100,95,119,105,116,104,100,114,97,119,4,99,111,105,110,7,100,101,102,97,117,108,116,6,100,101,108,101,116,101,6,100,101,108,105,115,116,12,100,101,115,116,114,111,121,95,115,111,109,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,4,101,109,105,116,5,101,118,101,110,116,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,3,102,111,114,12,102,114,111,109,95,98,97,108,97,110,99,101,10,104,97,115,95,97,99,99,101,115,115,8,104,97,115,95,105,116,101,109,18,104,97,115,95,105,116,101,109,95,119,105,116,104,95,116,121,112,101,2,105,100,12,105,115,95,101,120,99,108,117,115,105,118,101,9,105,115,95,108,105,115,116,101,100,21,105,115,95,108,105,115,116,101,100,95,101,120,99,108,117,115,105,118,101,108,121,9,105,115,95,108,111,99,107,101,100,7,105,115,95,115,111,109,101,10,105,116,101,109,95,99,111,117,110,116,7,105,116,101,109,95,105,100,5,107,105,111,115,107,15,107,105,111,115,107,95,101,120,116,101,110,115,105,111,110,8,107,105,111,115,107,95,105,100,19,107,105,111,115,107,95,111,119,110,101,114,95,99,97,112,95,102,111,114,4,108,105,115,116,22,108,105,115,116,95,119,105,116,104,95,112,117,114,99,104,97,115,101,95,99,97,112,4,108,111,99,107,13,108,111,99,107,95,105,110,116,101,114,110,97,108,9,109,105,110,95,112,114,105,99,101,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,5,111,119,110,101,114,5,112,108,97,99,101,14,112,108,97,99,101,95,97,110,100,95,108,105,115,116,14,112,108,97,99,101,95,105,110,116,101,114,110,97,108,5,112,114,105,99,101,7,112,114,111,102,105,116,115,14,112,114,111,102,105,116,115,95,97,109,111,117,110,116,11,112,114,111,102,105,116,115,95,109,117,116,8,112,117,114,99,104,97,115,101,17,112,117,114,99,104,97,115,101,95,99,97,112,95,105,116,101,109,18,112,117,114,99,104,97,115,101,95,99,97,112,95,107,105,111,115,107,22,112,117,114,99,104,97,115,101,95,99,97,112,95,109,105,110,95,112,114,105,99,101,17,112,117,114,99,104,97,115,101,95,119,105,116,104,95,99,97,112,3,112,117,116,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,19,114,101,116,117,114,110,95,112,117,114,99,104,97,115,101,95,99,97,112,10,114,101,116,117,114,110,95,118,97,108,6,115,101,110,100,101,114,20,115,101,116,95,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,9,115,101,116,95,111,119,110,101,114,16,115,101,116,95,111,119,110,101,114,95,99,117,115,116,111,109,12,115,104,97,114,101,95,111,98,106,101,99,116,3,115,117,105,4,116,97,107,101,8,116,114,97,110,115,102,101,114,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,3,117,105,100,7,117,105,100,95,109,117,116,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,16,117,105,100,95,109,117,116,95,105,110,116,101,114,110,97,108,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,0,2,5,42,8,14,68,11,11,1,8,15,63,5,48,14,20,1,1,2,2,42,8,14,37,8,13,2,2,4,42,8,14,52,8,13,49,8,13,58,3,3,2,2,52,8,13,49,8,13,4,2,1,42,8,13,5,2,2,42,8,13,43,1,6,2,1,42,8,13,7,2,3,50,8,13,42,8,13,67,3,8,2,3,50,8,13,42,8,13,67,3,9,2,2,50,8,13,42,8,13,7,10,9,10,8,10,2,10,0,0,4,0,41,12,10,0,17,1,12,1,12,2,11,1,11,0,46,17,67,56,0,11,2,56,1,2,1,1,0,0,41,19,10,0,17,62,56,2,10,0,46,17,67,73,0,0,0,0,9,18,0,12,2,11,0,17,62,14,2,56,3,18,1,12,1,11,2,11,1,2,2,1,0,0,49,38,11,0,19,0,1,12,6,1,12,7,12,5,11,1,19,1,12,4,12,3,14,5,17,63,11,4,33,4,17,5,21,11,2,1,7,0,39,11,6,73,0,0,0,0,33,4,26,5,30,11,2,1,7,3,39,11,3,17,60,11,5,17,60,11,7,11,2,56,4,2,3,1,0,0,1,17,10,0,11,1,17,24,4,5,5,11,11,0,1,11,2,1,7,0,39,11,2,17,67,11,0,15,0,21,2,4,1,0,0,1,14,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,2,11,0,15,0,21,2,5,1,0,0,1,13,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,11,2,56,5,2,6,1,0,0,1,13,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,11,3,56,6,2,7,1,0,0,52,68,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,21,32,4,18,5,22,11,0,1,7,8,39,10,0,10,2,12,4,46,11,4,17,23,32,4,31,5,35,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,19,4,43,5,47,11,0,1,7,11,39,10,0,16,1,20,73,1,0,0,0,23,10,0,15,1,21,10,0,15,2,10,2,9,18,5,56,7,1,11,0,15,2,11,2,18,4,56,8,2,8,1,0,0,58,49,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,4,46,11,4,56,9,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,5,46,11,5,17,23,32,4,30,5,34,11,0,1,7,4,39,10,0,15,2,10,2,9,18,5,10,3,56,10,11,0,46,56,3,11,2,11,3,57,0,56,11,2,9,1,0,0,39,13,14,2,56,12,12,4,10,0,10,1,11,2,56,13,11,0,11,1,11,4,11,3,56,14,2,10,1,0,0,52,60,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,56,9,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,23,32,4,30,5,34,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,22,4,42,5,46,11,0,1,7,12,39,10,0,15,2,10,2,9,18,5,56,15,1,11,0,46,56,3,11,2,57,1,56,16,2,11,1,0,0,62,56,10,0,15,2,10,1,9,18,5,56,15,12,4,10,0,15,2,10,1,18,4,56,8,12,3,10,0,16,1,20,73,1,0,0,0,23,10,0,15,1,21,10,4,14,2,56,17,33,4,27,5,31,11,0,1,7,1,39,10,0,15,2,10,1,18,6,56,18,1,10,0,15,3,11,2,56,19,10,0,46,56,3,10,1,10,4,57,2,56,20,11,3,11,1,11,4,11,0,46,56,3,56,21,2,12,1,0,0,69,64,10,0,11,1,17,24,4,5,5,11,11,0,1,11,4,1,7,0,39,10,0,10,2,12,5,46,11,5,56,9,4,19,5,25,11,0,1,11,4,1,7,11,39,10,0,10,2,12,6,46,11,6,17,22,32,4,34,5,40,11,0,1,11,4,1,7,6,39,10,0,15,2,10,2,8,18,5,10,3,56,10,11,3,12,7,11,2,12,8,11,4,17,62,12,9,11,0,46,56,3,12,10,11,9,11,10,11,8,11,7,57,3,2,13,1,0,0,70,68,11,1,58,3,12,6,12,4,12,5,17,60,11,4,12,3,14,2,56,17,12,7,10,7,11,6,38,4,16,5,20,11,0,1,7,1,39,10,0,46,56,3,11,5,33,4,27,5,31,11,0,1,7,5,39,10,0,15,2,10,3,8,18,5,56,15,1,10,0,15,3,11,2,56,19,10,0,16,1,20,73,1,0,0,0,23,10,0,15,1,21,10,0,15,2,10,3,18,6,56,18,1,10,0,15,2,10,3,18,4,56,8,11,3,11,7,11,0,46,56,3,56,21,2,14,1,0,0,71,27,11,1,58,3,1,12,3,12,4,12,2,10,0,46,56,3,11,4,33,4,13,5,17,11,0,1,7,5,39,11,0,15,2,11,3,8,18,5,56,15,1,11,2,17,60,2,15,1,0,0,72,45,10,0,11,1,17,24,4,5,5,11,11,0,1,11,3,1,7,0,39,14,2,56,22,4,33,11,2,56,23,12,6,10,6,10,0,16,3,56,24,37,4,24,5,30,11,0,1,11,3,1,7,2,39,11,6,12,4,5,37,10,0,16,3,56,24,12,4,11,4,12,5,11,0,15,3,11,5,11,3,56,25,2,16,3,0,0,1,11,10,0,15,2,14,1,56,12,18,6,8,56,26,11,0,11,1,56,5,2,17,3,0,0,1,16,10,0,16,1,20,73,1,0,0,0,22,10,0,15,1,21,11,0,15,2,14,1,56,12,18,4,11,1,56,27,2,18,3,0,0,1,3,11,0,15,2,2,19,1,0,0,1,6,11,0,16,2,11,1,18,4,56,28,2,20,1,0,0,1,6,11,0,16,2,11,1,18,4,56,29,2,21,1,0,0,1,6,11,0,16,2,11,1,18,6,56,30,2,22,1,0,0,24,18,10,0,16,2,10,1,9,18,5,56,31,4,12,11,0,1,8,12,2,5,16,11,0,11,1,17,23,12,2,11,2,2,23,1,0,0,1,7,11,0,16,2,11,1,8,18,5,56,31,2,24,1,0,0,1,8,11,0,46,56,3,11,1,16,4,20,33,2,25,1,0,0,1,12,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,15,2,2,26,1,0,0,1,14,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,2,11,0,15,5,21,2,27,1,0,0,1,3,11,0,16,2,2,28,1,0,0,1,12,10,0,16,5,20,4,5,5,9,11,0,1,7,7,39,11,0,15,2,2,29,1,0,0,1,4,11,0,16,0,20,2,30,1,0,0,1,4,11,0,16,1,20,2,31,1,0,0,1,4,11,0,16,3,56,24,2,32,1,0,0,1,12,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,15,3,2,33,1,0,0,1,27,10,0,56,3,11,1,16,4,20,33,4,8,5,12,11,0,1,7,0,39,10,0,10,2,17,19,4,17,5,21,11,0,1,7,11,39,11,0,16,2,11,2,18,4,56,32,2,34,1,0,0,58,40,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,19,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,22,32,4,30,5,34,11,0,1,7,9,39,11,0,15,2,11,2,18,4,56,33,2,35,1,0,0,58,45,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,19,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,22,32,4,30,5,34,11,0,1,7,9,39,10,0,15,2,10,2,18,4,56,8,11,0,46,56,3,11,2,18,3,2,36,1,0,0,58,32,11,2,19,3,12,3,12,4,10,0,46,56,3,11,4,33,4,11,5,15,11,0,1,7,5,39,14,1,56,12,10,3,33,4,21,5,25,11,0,1,7,10,39,11,0,15,2,11,3,18,4,11,1,56,27,2,37,1,0,0,1,4,11,0,16,4,20,2,38,1,0,0,1,4,11,0,55,0,20,2,39,1,0,0,1,4,11,0,55,1,20,2,40,1,0,0,1,4,11,0,55,2,20,2,0,2,0,3,0,0,0,1,1,1,0,4,2,1,2,2,2,3,6,10,7,10,8,10,0,51,0],"kiosk_extension":[161,28,235,11,6,0,0,0,12,1,0,14,2,14,36,3,50,162,1,4,212,1,26,5,238,1,142,1,7,252,2,164,3,8,160,6,32,6,192,6,76,10,140,7,15,11,155,7,2,12,157,7,143,4,13,172,11,6,0,26,0,9,0,17,0,25,0,30,0,37,0,38,0,1,4,0,0,2,7,1,0,1,1,0,12,0,3,3,12,0,3,4,12,0,4,7,4,0,5,5,12,1,0,1,6,6,2,0,0,8,0,1,1,2,0,15,2,1,1,2,0,18,2,1,1,2,0,34,2,1,1,2,0,35,3,4,1,2,0,36,5,6,1,2,0,32,7,1,2,2,12,0,27,7,1,2,2,12,0,24,8,9,1,2,0,23,8,9,1,2,0,13,8,9,1,2,0,12,8,9,1,2,0,20,8,10,1,2,0,21,11,12,1,2,1,14,16,1,0,1,29,15,16,0,2,8,18,1,2,7,4,2,10,24,25,2,7,4,2,11,19,26,2,7,4,2,19,24,9,1,7,2,34,19,20,2,7,4,3,22,2,9,0,3,28,21,1,1,12,3,33,21,1,1,12,3,39,8,22,0,3,40,2,13,0,3,41,11,13,0,16,17,8,14,13,14,20,17,12,14,10,14,11,14,23,20,22,20,19,23,9,14,17,17,18,17,5,9,0,7,8,3,6,8,4,4,7,8,7,0,2,7,8,3,6,8,4,2,9,0,6,8,3,1,6,8,2,2,9,0,7,8,3,1,7,8,2,4,9,0,7,8,3,9,1,6,11,6,1,9,1,1,6,8,3,1,1,1,6,8,0,1,7,8,3,1,7,8,0,1,7,8,5,1,9,0,1,7,8,7,1,8,2,2,11,1,1,9,0,8,0,3,7,8,5,9,0,9,1,2,7,8,5,9,0,1,9,1,2,7,8,3,9,0,1,6,8,5,1,11,1,1,9,0,2,6,8,5,9,0,1,6,9,1,1,7,9,1,3,66,97,103,9,69,120,116,101,110,115,105,111,110,12,69,120,116,101,110,115,105,111,110,75,101,121,5,75,105,111,115,107,13,75,105,111,115,107,79,119,110,101,114,67,97,112,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,3,98,97,103,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,97,110,95,108,111,99,107,9,99,97,110,95,112,108,97,99,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,7,100,105,115,97,98,108,101,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,6,101,110,97,98,108,101,7,101,120,105,115,116,115,95,9,101,120,116,101,110,115,105,111,110,13,101,120,116,101,110,115,105,111,110,95,109,117,116,10,104,97,115,95,97,99,99,101,115,115,10,105,115,95,101,110,97,98,108,101,100,12,105,115,95,105,110,115,116,97,108,108,101,100,5,107,105,111,115,107,15,107,105,111,115,107,95,101,120,116,101,110,115,105,111,110,4,108,111,99,107,13,108,111,99,107,95,105,110,116,101,114,110,97,108,3,110,101,119,6,111,98,106,101,99,116,11,112,101,114,109,105,115,115,105,111,110,115,5,112,108,97,99,101,14,112,108,97,99,101,95,105,110,116,101,114,110,97,108,6,114,101,109,111,118,101,7,115,116,111,114,97,103,101,11,115,116,111,114,97,103,101,95,109,117,116,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,3,117,105,100,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,16,117,105,100,95,109,117,116,95,105,110,116,101,114,110,97,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,4,16,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,16,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,35,8,2,31,4,23,1,1,2,1,16,1,1,14,0,1,0,0,1,25,10,1,10,2,17,21,4,5,5,13,11,1,1,11,4,1,11,2,1,7,0,39,11,1,11,2,17,25,9,57,0,11,4,17,15,11,3,8,18,0,56,0,2,1,1,0,0,1,24,10,0,11,1,17,21,4,5,5,9,11,0,1,7,0,39,10,0,46,56,1,4,14,5,18,11,0,1,7,3,39,9,11,0,56,2,15,0,21,2,2,1,0,0,1,24,10,0,11,1,17,21,4,5,5,9,11,0,1,7,0,39,10,0,46,56,1,4,14,5,18,11,0,1,7,3,39,8,11,0,56,2,15,0,21,2,3,1,0,0,1,33,10,0,10,1,17,21,4,5,5,11,11,0,1,11,1,1,7,0,39,10,0,46,56,1,4,16,5,22,11,0,1,11,1,1,7,3,39,11,0,11,1,17,25,9,57,0,56,3,19,0,1,1,17,14,2,4,1,0,0,1,12,10,1,56,1,4,4,5,8,11,1,1,7,3,39,11,1,56,4,16,1,2,5,1,0,0,1,13,10,1,46,56,1,4,5,5,9,11,1,1,7,3,39,11,1,56,2,15,1,2,6,1,0,0,9,31,10,1,46,56,1,4,5,5,9,11,1,1,7,3,39,10,1,46,56,5,4,16,8,12,4,5,20,10,1,46,56,6,12,4,11,4,4,23,5,27,11,1,1,7,2,39,11,1,11,2,56,7,2,7,1,0,0,1,22,10,1,46,56,1,4,5,5,9,11,1,1,7,3,39,10,1,46,56,6,4,14,5,18,11,1,1,7,2,39,11,1,11,2,56,8,2,8,1,0,0,1,6,11,0,17,24,9,57,0,56,9,2,9,1,0,0,1,5,11,0,56,4,16,0,20,2,10,1,0,0,9,19,10,0,56,10,4,13,11,0,56,4,16,2,20,7,4,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,12,1,5,17,11,0,1,9,12,1,11,1,2,11,1,0,0,9,19,10,0,56,10,4,13,11,0,56,4,16,2,20,7,5,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,12,1,5,17,11,0,1,9,12,1,11,1,2,12,0,0,0,1,6,11,0,17,24,9,57,0,56,11,2,13,0,0,0,1,6,11,0,17,26,9,57,0,56,12,2,0,2,0,0,0,1,0],"linked_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,30,3,40,212,1,4,252,1,28,5,152,2,188,1,7,212,3,205,2,8,161,6,64,6,225,6,20,10,245,6,38,11,155,7,4,12,159,7,151,5,13,182,12,14,14,196,12,14,0,24,1,29,0,14,0,28,0,40,0,0,12,2,7,0,4,1,0,1,4,2,7,0,4,0,1,2,7,1,0,0,3,4,4,0,4,3,2,0,0,25,0,1,2,7,4,0,17,2,3,2,7,4,0,6,2,3,2,7,4,0,34,4,5,2,7,4,0,33,4,5,2,7,4,0,7,6,7,2,7,4,0,8,8,9,2,7,4,0,32,6,3,2,7,4,0,26,6,3,2,7,4,0,35,8,10,2,7,4,0,31,11,12,2,7,4,0,30,11,12,2,7,4,0,9,6,13,2,7,4,0,23,2,14,2,7,4,0,20,2,13,2,7,4,0,11,1,5,2,7,4,0,13,1,5,2,7,6,1,7,3,25,1,0,1,12,17,16,1,0,1,16,19,5,1,0,1,21,3,13,1,0,1,22,3,13,1,0,1,27,5,17,1,0,1,37,16,17,1,0,1,38,19,17,1,0,2,5,22,5,2,7,4,2,7,23,7,2,7,4,2,8,21,9,2,7,4,2,15,23,13,2,7,4,2,35,21,10,2,7,4,3,10,15,5,0,3,25,0,15,0,22,16,24,16,20,16,19,16,21,16,18,16,23,16,27,20,25,20,26,20,29,20,17,16,9,12,28,20,1,7,8,4,1,11,0,2,9,0,9,1,1,6,11,0,2,9,0,9,1,1,6,11,2,1,9,0,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,7,11,0,2,9,0,9,1,2,9,0,9,1,1,1,1,3,1,8,3,1,9,0,1,11,2,1,9,0,5,11,2,1,9,0,11,2,1,9,0,11,2,1,9,0,9,0,11,2,1,9,0,2,7,11,2,1,9,0,9,0,2,9,0,11,1,2,9,0,9,1,2,7,8,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,3,11,2,1,9,0,11,2,1,9,0,9,1,1,6,9,0,2,8,3,3,11,76,105,110,107,101,100,84,97,98,108,101,4,78,111,100,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,4,98,97,99,107,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,4,102,105,108,108,5,102,114,111,110,116,4,104,101,97,100,2,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,6,108,101,110,103,116,104,12,108,105,110,107,101,100,95,116,97,98,108,101,3,110,101,119,4,110,101,120,116,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,111,112,95,98,97,99,107,9,112,111,112,95,102,114,111,110,116,4,112,114,101,118,9,112,117,115,104,95,98,97,99,107,10,112,117,115,104,95,102,114,111,110,116,6,114,101,109,111,118,101,4,115,105,122,101,4,115,111,109,101,12,115,119,97,112,95,111,114,95,102,105,108,108,4,116,97,105,108,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,19,8,3,36,3,18,11,2,1,9,0,39,11,2,1,9,0,1,2,3,32,11,2,1,9,0,26,11,2,1,9,0,41,9,1,0,12,1,12,0,1,0,0,5,7,11,0,17,31,6,0,0,0,0,0,0,0,0,56,0,56,0,57,0,2,1,1,0,0,5,3,11,0,55,0,2,2,1,0,0,5,3,11,0,55,1,2,3,1,0,0,18,54,10,0,54,0,10,1,56,1,12,5,10,0,55,1,56,2,4,13,10,0,54,1,10,1,56,3,56,0,12,7,14,5,56,4,4,33,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,3,21,11,6,56,6,12,3,5,35,56,0,12,3,11,3,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,4,1,0,0,18,54,10,0,55,0,56,2,4,8,10,0,54,0,10,1,56,3,10,0,54,1,10,1,56,1,12,5,14,5,56,4,4,31,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,5,21,11,6,56,6,12,3,5,33,56,0,12,3,11,3,12,7,56,0,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,5,1,0,0,5,6,11,0,55,2,11,1,56,9,55,6,2,6,1,0,0,5,6,11,0,54,2,11,1,56,7,54,6,2,7,1,0,0,5,6,11,0,55,2,11,1,56,9,55,3,2,8,1,0,0,5,6,11,0,55,2,11,1,56,9,55,5,2,9,1,0,0,24,65,10,0,54,2,10,1,56,10,58,1,12,4,12,2,12,3,10,0,55,4,20,6,1,0,0,0,0,0,0,0,23,10,0,54,4,21,14,3,56,4,4,28,10,2,10,0,54,2,14,3,56,11,20,56,7,54,5,21,14,2,56,4,4,40,10,3,10,0,54,2,14,2,56,11,20,56,7,54,3,21,10,0,55,0,56,11,14,1,33,4,50,11,2,10,0,54,0,21,10,0,55,1,56,11,14,1,33,4,61,11,3,11,0,54,1,21,5,63,11,0,1,11,4,2,10,1,0,0,16,19,10,0,55,0,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,0,56,11,20,12,1,10,1,11,0,11,1,56,12,2,11,1,0,0,16,19,10,0,55,1,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,1,56,11,20,12,1,10,1,11,0,11,1,56,12,2,12,1,0,0,5,5,11,0,55,2,11,1,56,13,2,13,1,0,0,5,4,11,0,55,4,20,2,14,1,0,0,5,6,11,0,55,4,20,6,0,0,0,0,0,0,0,0,33,2,15,1,0,0,26,16,11,0,58,0,1,1,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,11,5,13,7,0,39,11,1,17,30,2,16,1,0,0,5,7,11,0,58,0,1,1,1,17,30,2,0,2,0,3,0,0,1,0,0,1,1,1,1,2,0,12,1,12,2,12,3,12,4,12,5,12,6,12,0],"math":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,35,5,37,18,7,55,57,8,112,32,12,144,1,249,3,0,2,0,3,0,1,0,0,4,0,1,0,0,0,0,1,0,0,5,2,1,0,0,6,1,1,0,0,7,3,3,0,0,1,0,1,0,2,3,3,1,3,2,3,2,1,4,3,4,4,4,3,15,15,15,4,100,105,102,102,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,4,109,97,116,104,3,109,97,120,3,109,105,110,3,112,111,119,4,115,113,114,116,9,115,113,114,116,95,117,49,50,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,1,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,2,1,0,0,1,15,10,0,10,1,36,4,9,11,0,11,1,23,12,2,5,13,11,1,11,0,23,12,2,11,2,2,3,1,0,0,1,33,6,1,0,0,0,0,0,0,0,12,2,10,1,49,1,38,4,31,5,7,10,1,49,2,25,49,0,33,4,22,10,0,11,0,24,12,0,11,1,49,2,26,12,1,5,30,11,2,10,0,24,12,2,11,1,49,1,23,12,1,5,2,11,2,2,4,1,0,0,4,43,50,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,12,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,53,12,3,10,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,52,2,5,1,0,0,5,43,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,77,12,3,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,53,2,6,1,0,0,1,19,10,0,10,1,25,6,0,0,0,0,0,0,0,0,33,4,11,11,0,11,1,26,12,2,5,17,11,0,11,1,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,2,0],"object":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,126,4,146,1,6,5,152,1,35,7,187,1,250,2,8,181,4,64,6,245,4,112,10,229,5,11,12,240,5,130,2,13,242,7,4,15,246,7,8,0,24,1,4,0,3,0,30,0,0,7,0,0,2,4,0,3,1,2,0,0,21,0,1,0,0,20,0,2,0,0,19,1,3,0,0,18,2,3,0,0,27,4,5,0,0,8,6,5,0,0,31,7,0,0,0,34,7,3,0,0,33,7,1,0,0,32,7,2,0,0,22,8,5,0,0,9,5,6,0,0,15,9,3,1,8,0,5,9,0,1,8,0,17,9,1,1,8,0,16,9,2,1,8,0,6,9,7,1,8,0,23,2,5,0,0,10,2,6,0,0,25,2,6,0,1,28,9,1,1,0,2,14,1,2,0,3,13,8,2,0,3,26,4,2,0,20,2,16,10,20,3,1,6,8,0,1,10,2,1,5,1,8,0,1,6,8,2,1,8,1,0,1,6,8,1,1,7,8,2,1,6,9,0,1,9,0,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,100,100,114,101,115,115,3,98,99,115,9,98,111,114,114,111,119,95,105,100,10,98,111,114,114,111,119,95,117,105,100,5,98,121,116,101,115,5,99,108,111,99,107,6,100,101,108,101,116,101,11,100,101,108,101,116,101,95,105,109,112,108,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,2,105,100,10,105,100,95,97,100,100,114,101,115,115,8,105,100,95,98,121,116,101,115,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,102,114,111,109,95,98,121,116,101,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,11,105,100,95,116,111,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,6,111,98,106,101,99,116,14,114,101,99,111,114,100,95,110,101,119,95,117,105,100,6,115,101,110,100,101,114,16,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,12,117,105,100,95,116,111,95,98,121,116,101,115,12,117,105,100,95,116,111,95,105,110,110,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,7,5,1,2,1,15,8,0,0,1,0,0,6,4,11,0,16,0,56,0,2,1,1,0,0,6,4,11,0,16,0,20,2,2,1,0,0,6,4,11,0,17,21,17,3,2,3,1,0,0,6,3,11,0,18,0,2,4,0,0,0,6,12,11,0,17,23,7,3,33,4,6,5,8,7,2,39,7,0,18,0,18,1,2,5,3,0,0,6,4,7,1,18,0,18,1,2,6,1,0,0,6,3,11,0,16,1,2,7,1,0,0,6,4,11,0,16,1,20,2,8,1,0,0,6,5,11,0,16,1,16,0,56,0,2,9,1,0,0,6,5,11,0,16,1,16,0,20,2,10,1,0,0,6,5,11,0,17,22,18,0,18,1,2,11,1,0,0,6,5,11,0,19,1,19,0,17,18,2,12,1,0,0,6,5,11,0,56,1,16,1,20,2,13,1,0,0,6,4,11,0,56,1,16,1,2,14,1,0,0,6,5,11,0,56,1,16,1,56,2,2,15,1,0,0,6,6,11,0,56,1,16,1,16,0,20,2,16,0,2,0,17,3,0,0,6,6,10,0,17,19,11,0,18,0,18,1,2,18,0,2,0,19,0,2,0,0,0,1,0,0,8,0,11,0,12,0,29,0],"object_bag":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,22,3,32,124,4,156,1,14,5,170,1,88,7,130,2,231,1,8,233,3,64,6,169,4,10,10,179,4,8,12,187,4,245,1,13,176,6,4,0,20,1,21,0,12,0,19,0,24,0,1,12,0,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,18,0,1,0,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,22,6,8,2,7,12,0,8,4,9,1,7,0,9,4,9,2,7,12,0,17,10,11,0,0,16,10,9,0,0,11,1,3,0,0,25,4,12,1,7,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,13,16,9,1,7,2,14,16,9,2,7,12,2,15,16,12,1,7,2,22,17,8,2,7,12,3,10,13,3,0,3,18,0,13,0,11,14,12,14,13,14,17,14,14,18,15,14,16,18,1,7,8,4,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,9,79,98,106,101,99,116,66,97,103,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,10,111,98,106,101,99,116,95,98,97,103,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,15,8,3,23,3,0,1,0,0,3,5,11,0,17,19,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,19,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,18,2,10,1,0,0,3,5,11,0,16,0,11,1,56,6,2,0,0,0,1,0],"object_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,26,3,36,120,4,156,1,12,5,168,1,113,7,153,2,199,1,8,224,3,64,6,160,4,10,10,170,4,8,11,178,4,2,12,180,4,230,1,13,154,6,4,14,158,6,4,0,18,1,19,0,11,0,17,0,22,0,1,12,2,7,1,12,1,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,16,0,1,2,7,12,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,20,6,8,2,7,12,0,8,4,9,2,7,12,0,15,10,11,2,7,12,0,14,10,9,2,7,12,0,10,1,3,2,7,12,0,23,4,12,2,7,12,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,12,16,9,1,7,2,13,16,12,1,7,2,20,17,8,2,7,12,3,9,13,3,0,3,16,0,13,0,10,14,11,14,12,14,15,14,13,18,14,18,1,7,8,4,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,13,8,3,21,3,0,14,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,19,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,9,1,0,0,3,5,11,0,55,0,11,1,56,5,2,0,0,0,1,0,14,1,14,0],"package":[161,28,235,11,6,0,0,0,11,1,0,14,2,14,36,3,50,183,1,4,233,1,10,5,243,1,118,7,233,2,144,5,8,249,7,64,6,185,8,93,10,150,9,48,12,198,9,129,4,13,199,13,20,0,36,1,10,1,50,0,33,0,48,0,49,0,51,0,1,12,0,0,6,12,0,0,8,0,0,0,7,0,0,1,2,7,0,2,4,7,0,3,0,7,0,3,5,4,0,5,3,2,0,0,14,0,1,1,2,0,15,0,2,1,2,0,12,1,2,0,0,22,3,4,1,0,0,21,3,4,1,0,0,39,3,5,0,0,40,3,5,0,0,52,6,7,0,0,54,6,8,0,0,53,6,9,0,0,46,10,7,0,0,47,10,9,0,0,41,11,7,0,0,42,11,7,0,0,45,10,12,0,0,17,2,9,0,0,9,2,9,0,0,19,2,9,0,0,34,13,2,0,0,35,13,2,0,0,30,14,2,0,0,11,15,16,0,0,16,17,2,0,0,43,18,2,0,2,23,24,25,0,2,24,24,25,0,2,25,2,19,1,0,3,18,23,2,0,3,26,21,7,1,8,3,27,27,7,0,3,28,31,27,0,3,32,22,23,0,4,38,28,2,1,12,5,44,26,27,0,6,29,21,4,1,2,34,20,26,20,0,20,32,1,28,14,2,9,0,7,8,8,1,8,0,0,1,6,8,0,1,1,1,6,8,4,1,6,8,1,1,8,6,1,3,1,2,1,6,8,2,1,6,8,3,1,6,10,2,1,7,8,1,1,8,1,3,7,8,1,2,10,2,1,8,2,2,7,8,1,8,3,2,7,8,1,2,1,8,5,1,9,0,1,6,9,0,1,7,8,8,1,8,7,1,6,8,5,1,8,4,1,6,8,8,1,5,2,9,0,5,2,1,8,5,2,8,6,8,6,1,6,8,6,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,15,97,100,100,105,116,105,118,101,95,112,111,108,105,99,121,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,14,98,117,114,110,95,112,117,98,108,105,115,104,101,114,3,99,97,112,5,99,108,97,105,109,14,99,108,97,105,109,95,97,110,100,95,107,101,101,112,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,17,99,111,109,112,97,116,105,98,108,101,95,112,111,108,105,99,121,6,100,101,108,101,116,101,15,100,101,112,95,111,110,108,121,95,112,111,108,105,99,121,6,100,105,103,101,115,116,11,102,114,111,109,95,109,111,100,117,108,101,12,102,114,111,109,95,112,97,99,107,97,103,101,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,14,109,97,107,101,95,105,109,109,117,116,97,98,108,101,11,109,111,100,117,108,101,95,110,97,109,101,3,110,101,119,6,111,98,106,101,99,116,22,111,110,108,121,95,97,100,100,105,116,105,118,101,95,117,112,103,114,97,100,101,115,17,111,110,108,121,95,100,101,112,95,117,112,103,114,97,100,101,115,7,112,97,99,107,97,103,101,6,112,111,108,105,99,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,16,112,117,98,108,105,115,104,101,100,95,109,111,100,117,108,101,17,112,117,98,108,105,115,104,101,100,95,112,97,99,107,97,103,101,11,114,101,99,101,105,112,116,95,99,97,112,15,114,101,99,101,105,112,116,95,112,97,99,107,97,103,101,8,114,101,115,116,114,105,99,116,6,115,101,110,100,101,114,13,116,105,99,107,101,116,95,100,105,103,101,115,116,14,116,105,99,107,101,116,95,112,97,99,107,97,103,101,13,116,105,99,107,101,116,95,112,111,108,105,99,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,5,116,121,112,101,115,15,117,112,103,114,97,100,101,95,112,97,99,107,97,103,101,14,117,112,103,114,97,100,101,95,112,111,108,105,99,121,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,2,1,0,2,1,128,2,1,192,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,26,8,7,36,8,4,31,8,4,1,2,4,26,8,7,36,8,6,54,3,37,2,2,2,4,13,8,6,36,8,6,37,2,20,10,2,3,2,2,13,8,6,36,8,6,0,1,0,0,19,18,14,0,56,0,4,4,5,8,11,1,1,7,0,39,56,1,12,2,11,1,17,31,14,2,17,24,14,2,17,25,18,0,2,1,1,0,0,2,8,11,0,10,1,56,2,11,1,46,17,33,56,3,2,2,1,0,0,2,6,11,0,19,0,1,1,17,27,2,3,1,0,0,19,9,56,1,12,1,14,1,17,24,11,0,16,0,20,33,2,4,1,0,0,29,23,56,1,12,2,14,2,17,24,10,0,16,0,20,33,4,17,14,2,17,25,11,0,16,1,20,33,12,1,5,21,11,0,1,9,12,1,11,1,2,5,1,0,0,2,3,11,0,16,1,2,6,1,0,0,2,3,11,0,16,0,2,7,1,0,0,2,4,11,0,16,2,20,2,8,1,0,0,2,4,11,0,16,3,20,2,9,1,0,0,2,4,11,0,16,4,20,2,10,1,0,0,2,4,11,0,16,5,20,2,11,1,0,0,2,4,11,0,16,6,20,2,12,1,0,0,2,4,11,0,16,7,20,2,13,1,0,0,2,4,11,0,16,8,20,2,14,1,0,0,2,3,11,0,16,9,2,15,1,0,0,2,2,7,5,2,16,1,0,0,2,2,7,6,2,17,1,0,0,2,2,7,7,2,18,1,4,0,2,4,11,0,7,6,17,23,2,19,1,4,0,2,4,11,0,7,7,17,23,2,20,1,4,0,2,7,11,0,19,1,1,1,1,17,27,2,21,1,0,0,30,41,7,8,17,29,12,3,10,0,16,2,20,10,3,34,4,10,5,14,11,0,1,7,2,39,10,1,10,0,16,4,20,38,4,21,5,25,11,0,1,7,1,39,10,0,16,2,20,12,4,11,3,10,0,15,2,21,11,0,46,56,4,11,4,11,1,11,2,18,2,2,22,1,0,0,30,39,11,1,19,3,12,3,12,2,10,0,46,56,4,11,2,33,4,11,5,15,11,0,1,7,4,39,10,0,16,2,17,30,7,8,33,4,22,5,26,11,0,1,7,3,39,11,3,10,0,15,2,21,10,0,16,3,20,6,1,0,0,0,0,0,0,0,22,11,0,15,3,21,2,23,0,0,0,2,16,10,0,16,4,20,10,1,37,4,7,5,11,11,0,1,7,1,39,11,1,11,0,15,4,21,2,0,1,0,2,1,1,1,2,1,3,2,1,2,2,3,0,3,1,2,3,0],"pay":[161,28,235,11,6,0,0,0,9,1,0,8,2,8,10,3,18,77,4,95,14,5,109,126,7,235,1,173,1,8,152,3,32,6,184,3,10,12,194,3,214,2,0,9,0,2,0,15,0,16,1,0,12,1,0,1,3,1,2,0,0,8,0,1,1,0,0,12,2,1,1,0,0,14,3,1,1,0,0,13,4,1,1,0,0,3,2,1,1,0,0,5,5,1,1,0,0,6,6,1,1,0,0,7,7,1,1,0,1,4,2,16,1,0,1,5,5,1,1,0,1,12,2,10,1,0,2,10,11,1,1,12,3,11,8,9,0,11,10,10,12,0,12,1,12,8,12,9,12,6,12,2,11,0,1,9,0,6,8,1,0,3,7,11,0,1,9,0,3,7,8,1,3,7,11,0,1,9,0,10,3,7,8,1,4,7,11,0,1,9,0,3,5,7,8,1,2,7,11,0,1,9,0,11,0,1,9,0,2,7,11,0,1,9,0,10,11,0,1,9,0,2,10,11,0,1,9,0,5,1,6,8,1,1,5,1,11,0,1,9,0,2,9,0,5,1,9,0,2,3,3,1,3,3,3,3,10,11,0,1,9,0,1,10,11,0,1,9,0,3,11,0,1,9,0,3,3,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,15,100,105,118,105,100,101,95,97,110,100,95,107,101,101,112,13,100,105,118,105,100,101,95,105,110,116,111,95,110,4,106,111,105,110,8,106,111,105,110,95,118,101,99,21,106,111,105,110,95,118,101,99,95,97,110,100,95,116,114,97,110,115,102,101,114,4,107,101,101,112,3,112,97,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,18,115,112,108,105,116,95,97,110,100,95,116,114,97,110,115,102,101,114,9,115,112,108,105,116,95,118,101,99,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,5,11,0,11,1,17,12,56,0,2,1,1,4,0,1,8,11,0,11,1,10,2,56,1,11,2,46,56,2,2,2,1,4,0,13,27,6,0,0,0,0,0,0,0,0,14,1,65,14,12,4,12,3,10,3,10,4,35,4,22,5,10,10,0,14,1,10,3,66,14,20,10,2,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,2,1,2,3,1,4,0,1,7,11,0,11,1,11,3,56,1,11,2,56,0,2,4,1,4,0,15,31,11,0,11,1,10,2,56,4,12,5,6,0,0,0,0,0,0,0,0,14,5,65,10,12,4,12,3,10,3,10,4,35,4,26,5,15,13,5,69,10,10,2,46,17,12,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,10,11,2,1,11,5,70,10,0,0,0,0,0,0,0,0,2,5,1,4,0,1,4,11,0,11,1,56,5,2,6,1,4,0,17,26,6,0,0,0,0,0,0,0,0,14,1,65,10,12,4,12,3,10,3,10,4,35,4,21,5,10,13,1,69,10,12,2,10,0,11,2,56,5,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,7,1,4,0,10,18,14,0,65,10,6,0,0,0,0,0,0,0,0,36,4,6,5,8,7,0,39,13,0,69,10,12,2,13,2,11,0,56,6,11,2,11,1,56,0,2,0],"priority_queue":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,12,3,16,60,4,76,10,5,86,167,1,7,253,1,184,1,8,181,3,64,6,245,3,14,10,131,4,18,11,149,4,4,12,153,4,243,5,13,140,10,4,14,144,10,4,0,11,1,16,0,1,6,1,2,0,0,0,6,1,2,0,0,6,0,1,1,2,0,8,2,3,1,2,0,4,4,5,1,2,0,7,3,6,1,2,0,2,7,0,1,2,0,13,8,5,1,2,0,5,9,5,1,2,0,9,10,11,1,2,1,12,15,13,1,0,1,14,15,13,1,0,6,13,9,6,5,13,8,16,8,13,1,10,11,1,1,9,0,1,11,0,1,9,0,1,7,11,0,1,9,0,2,3,9,0,3,7,11,0,1,9,0,3,9,0,0,1,11,1,1,9,0,2,10,3,10,9,0,2,7,10,11,1,1,9,0,3,3,7,10,11,1,1,9,0,3,3,1,6,11,0,1,9,0,1,10,3,2,3,3,1,9,0,3,3,3,9,0,2,7,10,9,0,3,1,3,5,3,3,3,10,11,1,1,9,0,9,0,5,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,13,7,10,11,1,1,9,0,1,3,7,10,11,1,1,9,0,3,1,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,3,3,2,3,10,3,5,69,110,116,114,121,13,80,114,105,111,114,105,116,121,81,117,101,117,101,14,99,114,101,97,116,101,95,101,110,116,114,105,101,115,7,101,110,116,114,105,101,115,6,105,110,115,101,114,116,21,109,97,120,95,104,101,97,112,105,102,121,95,114,101,99,117,114,115,105,118,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,7,112,111,112,95,109,97,120,10,112,114,105,111,114,105,116,105,101,115,8,112,114,105,111,114,105,116,121,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,6,114,101,109,111,118,101,22,114,101,115,116,111,114,101,95,104,101,97,112,95,114,101,99,117,114,115,105,118,101,11,115,119,97,112,95,114,101,109,111,118,101,5,118,97,108,117,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,10,3,1,0,0,2,1,3,10,11,1,1,9,0,1,2,2,10,3,15,9,0,0,13,1,13,0,1,0,0,12,24,14,0,65,6,12,2,10,2,6,2,0,0,0,0,0,0,0,26,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,21,5,12,11,1,6,1,0,0,0,0,0,0,0,23,12,1,13,0,10,2,10,1,56,0,5,7,11,0,57,0,2,1,1,0,0,14,30,10,0,55,0,65,6,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,10,0,54,0,6,0,0,0,0,0,0,0,0,56,1,58,1,12,3,12,2,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,6,0,0,0,0,0,0,0,0,56,0,11,2,11,3,2,2,1,0,0,16,17,10,0,54,0,11,1,11,2,57,1,68,6,10,0,55,0,65,6,6,1,0,0,0,0,0,0,0,23,12,3,11,0,54,0,11,3,56,2,2,3,1,0,0,5,4,11,0,11,1,57,1,2,4,1,0,0,17,40,14,0,65,16,12,3,14,1,65,13,10,3,33,4,9,5,11,6,0,0,0,0,0,0,0,0,39,64,6,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,38,5,20,13,0,6,0,0,0,0,0,0,0,0,56,3,12,4,13,1,6,0,0,0,0,0,0,0,0,56,4,12,6,13,5,11,4,11,6,57,1,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,5,2,5,0,0,0,18,46,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,1,6,1,0,0,0,0,0,0,0,23,6,2,0,0,0,0,0,0,0,26,12,6,10,0,10,1,12,3,12,2,10,0,10,6,12,5,12,4,11,2,46,11,3,66,6,55,1,20,11,4,46,11,5,66,6,55,1,20,36,4,43,10,0,11,1,10,6,71,6,11,0,11,6,56,2,5,45,11,0,1,2,6,0,0,0,19,110,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,2,10,1,35,4,12,5,16,11,0,1,6,1,0,0,0,0,0,0,0,39,10,2,6,2,0,0,0,0,0,0,0,24,6,1,0,0,0,0,0,0,0,22,12,13,10,13,6,1,0,0,0,0,0,0,0,22,12,15,10,2,12,14,10,13,10,1,35,4,55,10,0,10,13,12,5,12,3,10,0,10,14,12,7,12,6,11,3,46,11,5,66,6,55,1,20,11,6,46,11,7,66,6,55,1,20,36,12,8,5,57,9,12,8,11,8,4,61,11,13,12,14,10,15,10,1,35,4,88,10,0,10,15,12,10,12,9,10,0,10,14,12,12,12,11,11,9,46,11,10,66,6,55,1,20,11,11,46,11,12,66,6,55,1,20,36,12,4,5,90,9,12,4,11,4,4,94,11,15,12,14,10,14,10,2,34,4,107,10,0,10,14,11,2,71,6,11,0,11,1,11,14,56,0,5,109,11,0,1,2,7,1,0,0,20,28,7,1,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,0,55,0,65,6,35,4,24,5,11,13,2,10,0,55,0,10,1,66,6,55,1,20,68,16,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,4,11,0,1,11,2,2,0,0,1,0,0,13,1,13,0],"prover":[161,28,235,11,6,0,0,0,4,1,0,2,7,2,7,8,9,32,6,41,30,0,0,6,112,114,111,118,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0],"iota":[161,28,235,11,6,0,0,0,10,1,0,14,2,14,48,3,62,62,4,124,14,5,138,1,133,1,7,143,2,129,2,8,144,4,64,6,208,4,102,10,182,5,5,12,187,5,109,0,22,1,18,0,9,0,10,0,23,0,25,0,26,0,4,2,0,1,3,7,1,0,0,2,0,4,1,0,1,2,5,4,1,0,1,3,1,12,1,0,1,3,2,12,1,0,1,3,6,12,1,0,1,5,7,2,0,6,8,7,0,0,16,0,1,0,0,23,2,3,0,1,17,3,9,1,0,2,12,16,7,1,0,2,15,17,18,1,0,3,11,11,12,1,2,3,24,15,16,1,0,4,19,14,3,1,12,4,20,20,3,1,12,5,14,5,7,0,5,21,5,6,0,2,8,5,10,7,13,6,10,4,10,3,10,8,19,1,7,8,7,1,11,2,1,8,0,2,11,4,1,8,0,5,0,4,11,5,1,8,0,11,3,1,8,0,11,2,1,8,0,11,6,1,8,0,1,6,8,7,1,5,1,3,1,8,8,1,11,1,1,9,0,1,8,0,7,9,0,2,10,2,10,2,10,2,11,1,1,8,8,7,8,7,2,11,6,1,9,0,11,5,1,9,0,1,11,5,1,8,0,1,9,0,1,11,6,1,9,0,1,11,3,1,9,0,2,7,11,3,1,9,0,3,1,11,2,1,9,0,1,11,4,1,8,0,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,114,108,7,98,97,108,97,110,99,101,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,11,100,117,109,109,121,95,102,105,101,108,100,5,101,112,111,99,104,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,3,115,117,105,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,228,11,84,2,0,0,0,3,8,0,0,232,137,4,35,199,138,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,2,4,3,83,85,73,10,2,4,3,83,117,105,10,2,1,0,0,2,1,13,1,0,0,0,0,4,47,10,0,46,17,10,7,5,33,4,7,5,11,11,0,1,7,1,39,10,0,46,17,9,6,0,0,0,0,0,0,0,0,33,4,18,5,22,11,0,1,7,0,39,9,18,0,49,9,7,6,7,7,7,8,56,0,11,0,56,1,12,1,12,4,11,1,56,2,11,4,56,3,12,2,13,2,7,4,56,4,12,3,11,2,56,5,1,11,3,2,1,1,4,0,3,4,11,0,11,1,56,6,2,0],"table":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,16,3,24,115,4,139,1,10,5,149,1,104,7,253,1,167,1,8,164,3,32,6,196,3,10,10,206,3,8,11,214,3,2,12,216,3,229,1,13,189,5,4,14,193,5,4,0,19,0,10,0,16,0,20,0,0,12,2,7,1,4,1,2,2,4,0,3,1,2,0,0,15,0,1,2,7,4,0,3,2,3,2,7,4,0,4,4,5,2,7,4,0,5,6,7,2,7,4,0,17,6,8,2,7,4,0,6,4,9,2,7,4,0,14,10,11,2,7,4,0,13,10,9,2,7,4,0,8,1,3,2,7,4,0,9,1,3,2,7,6,1,3,14,3,2,7,4,1,4,15,5,2,7,4,1,5,16,7,2,7,4,1,11,15,9,2,7,4,1,17,16,8,2,7,4,2,7,12,3,0,2,15,0,12,0,10,13,11,13,12,13,14,13,13,13,1,7,8,2,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,2,8,1,3,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,1,18,3,0,13,0,1,0,0,3,5,11,0,17,16,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,17,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,15,2,9,1,0,0,3,5,11,0,58,0,1,17,15,2,0,0,0,1,0,13,1,13,0],"table_vec":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,18,3,24,116,4,140,1,22,5,162,1,138,1,7,172,2,164,1,8,208,3,32,6,240,3,20,10,132,4,10,11,142,4,2,12,144,4,130,2,13,146,6,2,14,148,6,2,0,18,0,17,0,19,0,1,4,1,4,1,1,0,12,2,7,1,4,1,2,2,2,0,0,9,0,1,1,4,0,16,2,1,1,4,0,11,3,4,1,4,0,10,3,5,1,4,0,4,6,7,1,4,0,14,8,9,1,4,0,5,10,11,1,4,0,13,12,13,1,4,0,7,1,9,1,4,0,8,1,9,1,6,1,3,19,9,2,7,4,1,4,17,18,2,7,4,1,5,20,21,2,7,4,1,7,15,9,2,7,4,1,8,15,9,2,7,6,1,11,16,4,2,7,4,1,12,0,15,2,7,4,1,15,20,22,2,7,4,16,14,0,13,5,13,15,14,2,13,11,14,10,14,12,14,17,14,13,14,14,14,1,7,8,2,1,11,0,1,9,0,2,9,0,7,8,2,1,6,11,0,1,9,0,1,3,1,1,2,6,11,0,1,9,0,3,1,6,9,0,2,7,11,0,1,9,0,9,0,0,2,7,11,0,1,9,0,3,1,7,9,0,1,7,11,0,1,9,0,1,9,0,2,3,9,0,1,11,1,2,9,0,9,1,1,6,11,1,2,9,0,9,1,2,6,11,1,2,9,0,9,1,9,0,1,6,9,1,3,7,11,1,2,9,0,9,1,9,0,9,1,2,7,11,1,2,9,0,9,1,9,0,1,7,9,1,1,9,1,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,5,101,109,112,116,121,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,6,11,1,2,3,9,0,0,13,0,1,0,0,9,4,11,0,56,0,57,0,2,1,1,0,0,1,8,11,1,56,1,12,2,13,2,11,0,56,2,11,2,2,2,1,0,0,9,4,11,0,55,0,56,3,2,3,1,0,0,9,5,11,0,56,4,6,0,0,0,0,0,0,0,0,33,2,4,1,0,0,9,15,10,0,56,4,10,1,36,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,5,2,5,1,0,0,4,10,10,0,46,56,4,12,2,11,0,54,0,11,2,11,1,56,6,2,6,1,0,0,9,16,10,0,46,56,4,10,1,36,4,7,5,11,11,0,1,7,0,39,11,0,54,0,11,1,56,7,2,7,1,0,0,4,20,10,0,46,56,4,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,56,8,2,8,1,0,0,9,12,14,0,56,4,6,0,0,0,0,0,0,0,0,33,4,6,5,8,7,1,39,11,0,58,0,56,9,2,9,1,0,0,9,4,11,0,58,0,56,10,2,0,0,0,13,0],"transfer":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,54,4,56,6,5,62,8,7,70,144,1,8,214,1,32,6,246,1,10,12,128,2,82,0,7,0,7,0,1,1,8,0,4,0,1,1,12,0,0,2,1,1,8,0,2,2,1,1,12,0,5,2,1,1,8,0,3,2,1,1,12,0,1,2,1,1,8,0,6,2,1,1,8,0,8,0,1,1,8,8,2,6,2,7,2,2,9,0,5,0,1,9,0,13,102,114,101,101,122,101,95,111,98,106,101,99,116,18,102,114,101,101,122,101,95,111,98,106,101,99,116,95,105,109,112,108,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,17,115,104,97,114,101,95,111,98,106,101,99,116,95,105,109,112,108,8,116,114,97,110,115,102,101,114,13,116,114,97,110,115,102,101,114,95,105,109,112,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,56,0,2,1,1,0,0,1,4,11,0,11,1,56,0,2,2,1,0,0,1,3,11,0,56,1,2,3,1,0,0,1,3,11,0,56,1,2,4,1,0,0,1,3,11,0,56,2,2,5,1,0,0,1,3,11,0,56,2,2,6,3,2,0,7,3,2,0,8,3,2,0,0],"transfer_policy":[161,28,235,11,6,0,0,0,13,1,0,26,2,26,78,3,104,150,2,4,254,2,50,5,176,3,192,3,7,240,6,138,5,8,250,11,64,6,186,12,60,10,246,12,55,11,173,13,10,12,183,13,150,5,13,205,18,16,14,221,18,16,0,63,1,48,1,65,0,19,0,21,0,29,0,32,0,47,0,49,0,60,0,62,0,64,0,70,0,10,0,1,0,1,0,7,12,1,0,1,0,8,12,1,0,1,0,9,3,1,0,1,0,5,7,1,2,1,1,3,7,1,0,0,2,12,7,0,3,0,4,1,0,1,4,1,12,1,0,1,7,2,7,0,7,13,4,0,8,4,12,0,9,6,2,0,11,11,2,0,12,14,7,1,3,0,0,46,0,1,1,0,0,45,2,3,1,0,0,24,2,4,1,0,0,71,5,6,1,0,0,26,7,6,1,0,0,22,8,0,1,0,0,17,9,4,3,0,2,6,0,38,10,11,3,0,2,6,0,18,12,4,2,0,2,0,16,13,4,2,0,2,0,39,14,15,2,0,2,0,55,16,4,3,0,2,6,0,66,14,17,1,0,0,67,16,18,1,0,0,56,14,19,1,0,0,44,20,21,1,0,0,50,20,22,1,0,0,34,20,21,1,0,1,27,41,25,1,0,1,43,40,15,1,0,2,37,4,23,1,0,3,69,42,22,1,0,3,72,4,32,1,0,4,35,46,44,1,0,4,52,58,4,1,0,4,61,43,44,1,0,5,15,54,4,2,7,4,5,20,56,57,2,7,4,5,33,56,15,1,7,5,54,61,52,2,7,4,6,30,25,4,1,3,7,25,29,4,0,7,40,39,21,1,8,7,45,28,29,0,7,68,17,21,0,8,36,27,15,1,0,10,58,25,4,1,8,10,62,37,4,1,8,11,57,35,36,0,12,23,50,15,1,3,12,31,4,24,1,3,12,41,55,4,1,3,12,42,24,48,1,3,12,54,62,4,1,3,12,59,49,22,1,3,40,23,35,25,30,30,22,31,1,25,36,34,37,33,32,34,19,22,18,22,21,31,25,31,23,31,42,23,44,23,39,23,10,51,26,53,20,52,41,23,27,53,24,31,28,59,29,53,43,23,3,8,9,3,8,9,1,11,0,1,9,0,2,6,8,11,7,8,13,2,11,1,1,9,0,11,2,1,9,0,0,4,7,11,1,1,9,0,6,11,2,1,9,0,11,5,1,3,7,8,13,1,11,8,1,8,12,3,11,1,1,9,0,11,2,1,9,0,7,8,13,2,6,11,1,1,9,0,11,0,1,9,0,4,9,1,7,11,1,1,9,0,6,11,2,1,9,0,9,2,2,9,1,6,11,1,1,9,0,1,6,9,2,3,9,1,7,11,1,1,9,0,11,8,1,8,12,2,9,1,7,11,0,1,9,0,1,6,11,1,1,9,0,1,1,2,7,11,1,1,9,0,6,11,2,1,9,0,1,6,8,10,1,7,8,10,1,6,11,14,1,8,6,1,6,11,0,1,9,0,1,8,9,1,3,1,8,6,1,11,14,1,9,0,1,9,0,5,8,10,11,14,1,8,6,11,7,1,8,12,8,10,8,9,1,6,8,11,1,7,8,13,1,8,10,1,11,3,1,9,0,1,8,12,1,11,7,1,9,0,1,11,2,1,9,0,1,11,1,1,9,0,1,6,8,13,1,5,2,9,0,5,3,3,3,3,1,6,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,1,6,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,13,1,11,8,1,9,0,2,11,7,1,8,12,8,10,2,11,7,1,9,0,7,8,13,7,10,8,6,8,9,8,9,3,11,14,1,8,6,8,6,3,1,10,9,0,1,6,11,14,1,9,0,2,6,11,14,1,9,0,6,9,0,2,9,0,9,1,1,9,1,2,11,4,1,9,1,9,2,3,7,8,10,9,0,9,1,2,7,11,14,1,9,0,9,0,2,6,8,10,9,0,1,6,9,1,2,7,11,7,1,9,0,11,8,1,9,0,1,11,4,1,9,1,2,8,6,7,11,14,1,8,6,2,7,8,10,9,0,2,7,11,14,1,9,0,6,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,9,80,117,98,108,105,115,104,101,114,7,82,117,108,101,75,101,121,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,17,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,97,112,21,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,114,101,97,116,101,100,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,86,101,99,83,101,116,3,97,100,100,11,97,100,100,95,114,101,99,101,105,112,116,8,97,100,100,95,114,117,108,101,14,97,100,100,95,116,111,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,4,99,111,105,110,15,99,111,110,102,105,114,109,95,114,101,113,117,101,115,116,8,99,111,110,116,97,105,110,115,7,100,101,102,97,117,108,116,6,100,101,108,101,116,101,20,100,101,115,116,114,111,121,95,97,110,100,95,119,105,116,104,100,114,97,119,12,100,101,115,116,114,111,121,95,115,111,109,101,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,7,101,120,105,115,116,115,95,4,102,114,111,109,12,102,114,111,109,95,98,97,108,97,110,99,101,12,102,114,111,109,95,112,97,99,107,97,103,101,3,103,101,116,8,103,101,116,95,114,117,108,101,8,104,97,115,95,114,117,108,101,2,105,100,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,7,105,115,95,115,111,109,101,4,105,116,101,109,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,4,112,97,105,100,9,112,111,108,105,99,121,95,105,100,3,112,117,116,8,114,101,99,101,105,112,116,115,6,114,101,109,111,118,101,11,114,101,109,111,118,101,95,114,117,108,101,5,114,117,108,101,115,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,105,122,101,3,115,117,105,4,116,97,107,101,8,116,114,97,110,115,102,101,114,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,3,117,105,100,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,7,118,101,99,95,115,101,116,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,4,44,8,9,50,3,34,8,9,53,11,14,1,8,6,1,2,3,40,8,10,19,11,7,1,8,12,56,11,14,1,8,6,2,2,2,40,8,10,51,8,9,3,2,1,40,8,9,4,2,1,28,1,0,25,3,25,1,25,2,25,4,52,0,1,0,0,4,6,11,0,11,1,11,2,56,0,57,0,2,1,1,0,0,26,32,11,0,56,1,4,4,5,8,11,1,1,6,0,0,0,0,0,0,0,0,39,10,1,17,33,12,5,14,5,17,34,12,6,10,6,57,1,56,2,11,5,12,2,56,0,12,3,56,3,12,4,11,2,11,4,11,3,57,2,11,1,17,33,11,6,57,3,2,2,0,4,0,33,11,11,0,10,1,56,4,12,2,56,5,11,2,11,1,46,17,38,56,6,2,3,1,0,0,38,49,10,0,46,56,7,11,1,55,0,20,33,4,9,5,15,11,0,1,11,3,1,7,4,39,14,2,56,8,4,37,11,2,56,9,12,6,10,6,10,0,55,1,56,10,37,4,28,5,34,11,0,1,11,3,1,7,5,39,11,6,12,4,5,41,10,0,55,1,56,10,12,4,11,4,12,5,11,0,54,1,11,5,11,3,56,11,2,4,1,0,0,45,27,14,0,56,7,14,1,55,0,20,33,4,8,5,12,11,2,1,7,4,39,11,1,58,3,1,12,4,11,0,58,2,1,12,3,17,31,11,4,17,31,11,3,11,2,56,12,2,5,1,0,0,47,52,11,1,58,0,12,6,12,3,12,5,12,4,11,6,56,13,12,2,14,2,65,23,12,8,10,8,10,0,55,2,56,14,33,4,19,5,23,11,0,1,7,0,39,10,8,6,0,0,0,0,0,0,0,0,36,4,46,5,28,13,2,69,23,12,7,10,0,55,2,14,7,56,15,4,37,5,41,11,0,1,7,1,39,11,8,6,1,0,0,0,0,0,0,0,23,12,8,5,23,11,0,1,11,4,11,5,11,3,2,6,1,0,0,4,34,10,1,46,56,7,11,2,55,0,20,33,4,9,5,13,11,1,1,7,4,39,10,1,46,56,16,32,4,19,5,23,11,1,1,7,3,39,10,1,54,3,9,57,4,11,3,56,17,11,1,54,2,56,18,56,19,2,7,1,0,0,4,6,11,1,55,3,9,57,4,56,20,2,8,1,0,0,4,14,10,1,46,56,16,4,5,5,9,11,1,1,7,2,39,11,1,54,1,11,2,56,21,2,9,1,0,0,4,5,11,1,54,4,56,18,56,19,2,10,1,0,0,4,6,11,0,55,3,9,57,4,56,22,2,11,1,0,0,60,28,10,0,46,56,7,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,10,0,54,3,9,57,4,56,23,1,11,0,54,2,12,3,56,18,12,2,11,3,14,2,56,24,2,12,1,0,0,4,3,11,0,55,3,2,13,1,0,0,4,16,10,0,46,56,7,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,11,0,54,3,2,14,1,0,0,4,3,11,0,55,2,2,15,1,0,0,4,4,11,0,55,5,20,2,16,1,0,0,4,4,11,0,55,6,20,2,17,1,0,0,4,4,11,0,55,7,20,2,2,1,1,1,1,2,1,0,0,3,0,0,0,1,0,2,0,25,1,25,2,25,3,25,4,25,5,25,6,25,7,25,0],"tx_context":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,24,7,65,111,8,176,1,32,6,208,1,20,10,228,1,14,12,242,1,107,13,221,2,10,0,8,0,0,2,0,0,7,0,1,0,0,2,0,2,0,0,3,0,3,0,0,4,0,3,0,0,5,4,1,0,0,6,0,3,0,0,1,5,1,0,1,6,8,0,1,5,1,6,10,2,1,3,1,7,8,0,2,10,2,3,0,2,5,3,9,84,120,67,111,110,116,101,120,116,9,100,101,114,105,118,101,95,105,100,6,100,105,103,101,115,116,5,101,112,111,99,104,18,101,112,111,99,104,95,116,105,109,101,115,116,97,109,112,95,109,115,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,11,105,100,115,95,99,114,101,97,116,101,100,6,115,101,110,100,101,114,10,116,120,95,99,111,110,116,101,120,116,7,116,120,95,104,97,115,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,32,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,5,7,5,9,10,2,3,3,4,3,6,3,0,1,0,0,6,4,11,0,16,0,20,2,1,1,0,0,6,3,11,0,16,1,2,2,1,0,0,6,4,11,0,16,2,20,2,3,1,0,0,6,4,11,0,16,3,20,2,4,1,0,0,7,18,10,0,16,4,20,12,2,10,0,16,1,20,10,2,17,6,12,1,11,2,6,1,0,0,0,0,0,0,0,22,11,0,15,4,21,11,1,2,5,0,0,0,6,4,11,0,16,4,20,2,6,0,2,0,0,0,0,1,0,2,0,3,0,4,0],"types":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,6,7,14,26,8,40,32,12,72,4,0,1,0,0,0,1,1,2,1,6,9,0,1,1,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,5,116,121,112,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"url":[161,28,235,11,6,0,0,0,9,1,0,4,2,4,8,3,12,25,5,37,20,7,57,78,8,135,1,64,10,199,1,6,12,205,1,50,13,255,1,2,0,8,1,2,0,1,7,0,1,0,7,0,0,4,0,1,0,0,5,2,1,0,0,3,3,0,0,0,7,4,5,0,1,6,2,0,0,1,8,1,1,8,0,1,10,2,1,6,8,0,2,7,8,0,8,1,0,6,83,116,114,105,110,103,3,85,114,108,5,97,115,99,105,105,9,105,110,110,101,114,95,117,114,108,10,110,101,119,95,117,110,115,97,102,101,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,6,115,116,114,105,110,103,6,117,112,100,97,116,101,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,8,8,1,0,1,0,0,5,3,11,0,18,0,2,1,1,0,0,5,4,11,0,17,4,18,0,2,2,1,0,0,5,4,11,0,16,0,20,2,3,1,0,0,5,5,11,1,11,0,15,0,21,2,0,0,0],"vec_map":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,22,3,28,168,1,4,196,1,28,5,224,1,254,1,7,222,3,153,2,8,247,5,64,6,183,6,50,10,233,6,21,11,254,6,4,12,130,7,235,5,13,237,12,6,14,243,12,6,0,30,1,21,1,31,0,2,7,2,1,0,0,0,0,0,7,2,1,0,0,0,1,1,7,1,0,0,0,7,0,1,2,1,0,0,14,2,0,2,1,0,0,23,3,4,2,1,0,0,22,5,4,2,1,0,0,13,3,6,2,1,0,0,8,7,8,2,1,0,0,28,7,9,2,1,1,0,3,7,10,2,1,0,0,26,11,12,2,1,0,0,16,11,10,2,1,0,0,5,1,0,2,1,0,0,15,1,13,2,1,0,0,19,11,14,2,1,0,0,12,7,15,2,1,0,0,11,7,12,2,1,0,0,9,16,17,2,1,0,0,10,18,19,2,1,0,0,24,18,4,2,1,0,1,6,27,24,1,0,1,17,28,10,1,0,1,20,0,27,1,0,1,27,24,27,1,0,2,16,25,10,1,0,2,23,23,24,1,0,2,25,31,0,1,0,7,4,14,4,23,20,22,20,5,4,21,26,20,26,13,4,19,12,8,4,24,20,21,12,20,12,18,12,0,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,2,7,11,0,2,9,0,9,1,6,9,0,2,9,0,9,1,1,7,11,0,2,9,0,9,1,1,7,9,1,2,6,11,0,2,9,0,9,1,6,9,0,1,6,9,1,1,11,2,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,2,10,9,0,10,9,1,1,10,9,0,1,11,2,1,3,2,6,11,0,2,9,0,9,1,3,2,6,9,0,6,9,1,2,7,11,0,2,9,0,9,1,3,2,6,9,0,7,9,1,1,11,1,2,9,0,9,1,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,9,0,1,6,10,9,0,1,9,1,1,11,2,1,9,0,1,6,11,2,1,9,0,1,10,11,1,2,9,0,9,1,7,10,11,1,2,9,0,9,1,3,9,0,10,9,0,3,9,1,10,9,1,1,7,10,9,0,4,6,11,1,2,9,0,9,1,3,10,9,0,3,2,3,3,1,6,11,1,2,9,0,9,1,1,7,11,1,2,9,0,9,1,5,69,110,116,114,121,6,79,112,116,105,111,110,6,86,101,99,77,97,112,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,3,103,101,116,16,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,20,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,95,109,117,116,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,7,103,101,116,95,109,117,116,6,105,110,115,101,114,116,16,105,110,116,111,95,107,101,121,115,95,118,97,108,117,101,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,3,107,101,121,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,3,112,111,112,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,101,110,116,114,121,95,98,121,95,105,100,120,7,114,101,118,101,114,115,101,4,115,105,122,101,4,115,111,109,101,7,116,114,121,95,103,101,116,5,118,97,108,117,101,7,118,101,99,95,109,97,112,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,1,4,10,11,1,2,9,0,9,1,1,2,2,18,9,0,29,9,1,0,4,1,4,0,1,0,0,0,3,64,20,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,21,20,10,0,14,1,12,3,46,11,3,56,0,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,11,2,57,1,68,20,2,2,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,56,2,58,1,2,3,1,0,0,0,15,10,0,55,0,56,3,32,4,6,5,10,11,0,1,7,4,39,11,0,54,0,69,20,58,1,2,4,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,67,20,54,1,2,5,1,0,0,12,10,10,0,11,1,56,1,12,2,11,0,55,0,11,2,66,20,55,1,2,6,1,0,0,9,19,10,0,10,1,56,0,4,11,11,0,11,1,56,4,20,56,5,12,2,5,17,11,0,1,11,1,1,56,6,12,2,11,2,2,7,1,0,0,15,7,11,0,11,1,56,7,12,2,14,2,56,8,2,8,1,0,0,0,4,11,0,55,0,65,20,2,9,1,0,0,0,5,11,0,56,9,6,0,0,0,0,0,0,0,0,33,2,10,1,0,0,29,12,11,0,58,0,12,1,14,1,56,3,4,7,5,9,7,2,39,11,1,70,20,0,0,0,0,0,0,0,0,2,11,1,0,0,30,40,11,0,58,0,12,1,13,1,56,10,6,0,0,0,0,0,0,0,0,12,2,14,1,65,20,12,5,64,24,0,0,0,0,0,0,0,0,12,4,64,26,0,0,0,0,0,0,0,0,12,7,10,2,10,5,35,4,35,5,19,13,1,69,20,58,1,12,6,12,3,13,4,11,3,68,24,13,7,11,6,68,26,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,14,11,1,70,20,0,0,0,0,0,0,0,0,11,4,11,7,2,12,1,0,0,32,32,6,0,0,0,0,0,0,0,0,12,2,10,0,55,0,65,20,12,4,64,24,0,0,0,0,0,0,0,0,12,3,10,2,10,4,35,4,28,5,13,10,0,55,0,10,2,66,20,12,1,13,3,11,1,55,2,20,68,24,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,8,11,0,1,11,3,2,13,1,0,0,33,36,6,0,0,0,0,0,0,0,0,12,2,10,0,56,9,12,3,10,2,10,3,35,4,30,5,10,10,0,55,0,10,2,66,20,55,2,10,1,33,4,25,11,0,1,11,1,1,11,2,56,11,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,12,2,14,1,0,0,15,13,11,0,11,1,56,7,12,2,14,2,56,8,4,8,5,10,7,1,39,11,2,56,13,2,15,1,0,0,34,20,10,1,10,0,56,9,35,4,6,5,10,11,0,1,7,3,39,11,0,55,0,11,1,66,20,12,2,10,2,55,2,11,2,55,1,2,16,1,0,0,35,21,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,67,20,12,2,10,2,55,2,11,2,54,1,2,17,1,0,0,0,17,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,56,2,58,1,2,0,0,1,1,1,0,0,4,1,4,2,4,0],"vec_set":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,12,3,18,102,4,120,20,5,140,1,95,7,235,1,164,1,8,143,3,64,6,207,3,20,10,227,3,7,11,234,3,2,12,236,3,156,2,13,136,6,2,14,138,6,2,0,19,1,14,1,20,0,1,7,1,3,0,1,0,7,1,0,0,0,5,0,1,1,3,0,16,2,1,1,3,0,8,3,0,1,3,0,15,4,0,1,3,0,2,5,6,1,3,0,17,7,8,1,3,0,10,7,6,1,3,0,9,1,9,1,3,0,12,7,10,1,3,0,7,5,11,1,3,0,6,5,8,1,3,1,4,17,2,1,0,1,11,15,6,1,0,1,13,0,17,1,0,1,18,2,17,1,0,2,15,14,2,1,0,2,16,2,9,1,0,16,2,4,2,10,2,15,2,9,2,12,8,5,2,14,8,13,8,11,8,0,1,11,0,1,9,0,1,9,0,2,7,11,0,1,9,0,9,0,2,7,11,0,1,9,0,6,9,0,2,6,11,0,1,9,0,6,9,0,1,1,1,6,11,0,1,9,0,1,3,1,10,9,0,1,6,10,9,0,1,11,1,1,3,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,6,11,1,1,9,0,2,3,3,1,11,1,1,9,0,6,79,112,116,105,111,110,6,86,101,99,83,101,116,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,4,115,105,122,101,4,115,111,109,101,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,3,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,12,18,10,0,14,1,12,2,46,11,2,56,1,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,68,2,2,3,1,0,0,13,13,10,0,11,1,12,2,46,11,2,56,2,12,3,11,0,54,0,11,3,56,3,1,2,4,1,0,0,11,7,11,0,11,1,56,4,12,2,14,2,56,5,2,5,1,0,0,0,4,11,0,55,0,65,2,2,6,1,0,0,0,5,11,0,56,6,6,0,0,0,0,0,0,0,0,33,2,7,1,0,0,0,3,11,0,58,0,2,8,1,0,0,0,3,11,0,55,0,2,9,0,0,0,16,35,6,0,0,0,0,0,0,0,0,12,2,10,0,56,6,12,3,10,2,10,3,35,4,29,5,10,10,0,55,0,10,2,66,2,10,1,33,4,24,11,0,1,11,1,1,11,2,56,7,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,8,2,10,0,0,0,11,13,11,0,11,1,56,4,12,2,14,2,56,5,4,8,5,10,7,1,39,11,2,56,9,2,0,0,0,2,0],"versioned":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,20,3,28,85,4,113,10,5,123,97,7,220,1,236,1,8,200,3,32,6,232,3,10,10,242,3,16,12,130,4,197,1,13,199,5,4,0,23,0,11,0,16,0,20,0,4,12,0,0,3,0,0,2,0,7,0,2,2,4,0,3,1,2,0,0,8,0,1,1,4,0,22,2,3,0,0,13,2,4,1,4,0,14,5,6,1,4,0,19,5,7,1,4,0,21,8,9,1,4,0,10,1,10,1,4,1,5,14,9,2,7,4,1,6,15,16,2,7,4,1,7,17,18,2,7,4,1,18,17,19,2,7,4,2,9,12,9,0,2,12,4,20,1,8,2,15,11,12,0,7,13,8,13,9,13,10,13,12,1,3,3,9,0,7,8,4,1,8,0,1,6,8,0,1,3,1,6,9,0,1,7,8,0,1,7,9,0,2,9,0,8,1,4,7,8,0,3,9,0,8,1,0,1,9,0,1,7,8,4,1,8,3,2,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,8,2,3,8,3,9,0,3,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,16,86,101,114,115,105,111,110,67,104,97,110,103,101,67,97,112,9,86,101,114,115,105,111,110,101,100,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,2,105,100,10,108,111,97,100,95,118,97,108,117,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,3,110,101,119,6,111,98,106,101,99,116,11,111,108,100,95,118,101,114,115,105,111,110,6,114,101,109,111,118,101,24,114,101,109,111,118,101,95,118,97,108,117,101,95,102,111,114,95,117,112,103,114,97,100,101,10,116,120,95,99,111,110,116,101,120,116,7,117,112,103,114,97,100,101,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,12,118,101,114,115,105,111,110,101,100,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,3,22,3,1,2,2,24,8,2,17,3,0,1,0,0,1,12,11,2,17,13,10,0,18,0,12,3,13,3,15,0,11,0,11,1,56,0,11,3,2,1,1,0,0,9,4,11,0,16,1,20,2,2,1,0,0,9,7,10,0,16,0,11,0,16,1,20,56,1,2,3,1,0,0,9,7,10,0,15,0,11,0,16,1,20,56,2,2,4,1,0,0,9,14,10,0,15,0,10,0,16,1,20,56,3,10,0,46,56,4,11,0,16,1,20,18,1,2,5,1,0,0,3,32,11,3,19,1,12,4,10,0,46,56,4,33,4,9,5,13,11,0,1,7,0,39,11,4,10,1,35,4,18,5,22,11,0,1,7,0,39,10,0,15,0,10,1,11,2,56,0,11,1,11,0,15,1,21,2,6,1,0,0,21,12,11,0,19,0,12,3,12,1,13,1,11,3,56,3,12,2,11,1,17,11,11,2,2,0,0,0,1,0]},"type_origin_table":[{"module_name":"tx_context","struct_name":"TxContext","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"ID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"UID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_field","struct_name":"Field","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bag","struct_name":"Bag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Supply","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Balance","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bcs","struct_name":"BCS","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Referent","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"clock","struct_name":"Clock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"url","struct_name":"Url","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"Coin","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CoinMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"TreasuryCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CurrencyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"VecMap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"Publisher","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeTicket","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeReceipt","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"Display","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"DisplayCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"VersionUpdated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_object_field","struct_name":"Wrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"Curve","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PreparedVerifyingKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PublicProofInputs","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"ProofPoints","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_set","struct_name":"VecSet","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"iota","struct_name":"IOTA","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferRequest","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicy","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"RuleKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Kiosk","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"KioskOwnerCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"PurchaseCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Item","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Listing","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Lock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemListed","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemPurchased","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemDelisted","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk_extension","struct_name":"Extension","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk_extension","struct_name":"ExtensionKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"LinkedTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"Node","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_bag","struct_name":"ObjectBag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_table","struct_name":"ObjectTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"PriorityQueue","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table","struct_name":"Table","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table_vec","struct_name":"TableVec","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"Versioned","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"VersionChangeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"ACKQVv64dXCmpxE1QPU2QMLxVpmtbzrFGMtWYY6szJrQ","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000003","version":7,"module_map":{"genesis":[161,28,235,11,6,0,0,0,11,1,0,26,2,26,58,3,84,107,4,191,1,14,5,205,1,176,2,7,253,3,137,9,8,134,13,96,6,230,13,20,10,250,13,93,12,215,14,219,3,13,178,18,24,0,31,1,44,1,72,2,18,2,20,2,43,2,61,2,66,0,54,0,63,0,64,0,67,0,70,0,3,3,0,0,2,3,0,0,9,0,0,0,8,0,0,1,4,7,1,0,0,3,0,4,1,0,1,4,1,12,1,0,1,5,11,4,0,6,5,2,0,7,10,2,0,8,6,4,0,10,7,4,0,11,12,4,0,0,22,0,1,0,0,15,2,1,0,0,14,3,1,0,1,25,25,26,1,0,1,36,24,14,1,0,2,35,22,14,1,0,3,26,9,1,1,0,3,53,8,9,1,0,3,75,1,9,1,0,4,29,30,31,1,0,6,65,32,1,0,7,27,5,6,0,8,22,17,18,0,9,22,19,1,0,10,23,15,16,0,11,13,34,1,0,11,42,12,10,0,11,52,29,1,0,12,32,27,28,0,12,34,13,14,0,7,7,8,7,5,21,4,23,3,23,9,7,6,7,6,8,7,11,5,1,8,8,8,1,10,8,0,8,2,7,8,9,0,4,11,5,1,8,8,10,8,3,7,10,8,12,7,8,9,1,7,10,8,12,25,10,8,3,3,3,10,2,3,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,8,10,3,11,5,1,8,8,11,5,1,8,8,5,8,11,8,12,10,8,12,10,2,10,2,1,6,8,9,1,3,1,8,8,2,7,11,5,1,9,0,3,1,11,5,1,9,0,1,8,12,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,9,2,6,10,8,12,6,8,12,1,1,8,3,3,3,3,3,3,3,7,8,9,1,8,11,5,11,5,1,8,8,3,3,13,7,8,9,1,8,10,8,8,7,10,8,12,11,5,1,8,8,3,3,8,11,8,10,7,8,9,5,11,5,1,8,8,3,5,11,4,1,5,5,1,8,3,1,6,10,9,0,1,5,1,6,11,4,1,9,0,1,11,4,1,9,0,1,9,0,2,7,10,8,12,5,1,7,8,12,4,7,8,12,11,5,1,8,8,5,7,8,9,2,11,5,1,9,0,7,8,9,1,11,6,1,9,0,2,11,6,1,8,8,5,2,3,3,2,7,8,12,3,7,66,97,108,97,110,99,101,4,67,111,105,110,22,71,101,110,101,115,105,115,67,104,97,105,110,80,97,114,97,109,101,116,101,114,115,24,71,101,110,101,115,105,115,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,15,84,111,107,101,110,65,108,108,111,99,97,116,105,111,110,25,84,111,107,101,110,68,105,115,116,114,105,98,117,116,105,111,110,83,99,104,101,100,117,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,9,86,97,108,105,100,97,116,111,114,8,97,99,116,105,118,97,116,101,19,97,99,116,105,118,97,116,101,95,118,97,108,105,100,97,116,111,114,115,15,97,108,108,111,99,97,116,101,95,116,111,107,101,110,115,11,97,108,108,111,99,97,116,105,111,110,115,11,97,109,111,117,110,116,95,109,105,115,116,7,98,97,108,97,110,99,101,24,99,104,97,105,110,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,4,99,111,105,110,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,12,102,114,111,109,95,98,97,108,97,110,99,101,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,9,105,109,97,103,101,95,117,114,108,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,4,110,97,109,101,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,18,110,101,116,119,111,114,107,95,112,117,98,108,105,99,95,107,101,121,3,110,101,119,6,111,98,106,101,99,116,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,19,112,114,111,116,111,99,111,108,95,112,117,98,108,105,99,95,107,101,121,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,17,114,101,99,105,112,105,101,110,116,95,97,100,100,114,101,115,115,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,23,115,116,97,107,101,95,115,117,98,115,105,100,121,95,102,117,110,100,95,109,105,115,116,41,115,116,97,107,101,95,115,117,98,115,105,100,121,95,105,110,105,116,105,97,108,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,21,115,116,97,107,101,100,95,119,105,116,104,95,118,97,108,105,100,97,116,111,114,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,118,97,108,105,100,97,116,111,114,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,13,118,97,108,105,100,97,116,111,114,95,115,101,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,6,118,101,99,116,111,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,17,119,111,114,107,101,114,95,112,117,98,108,105,99,95,107,101,121,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,15,39,10,2,24,10,2,33,10,2,47,10,2,62,5,30,3,21,3,49,10,2,48,10,2,41,10,2,74,10,2,40,10,2,45,10,2,46,10,2,73,10,2,1,2,12,50,3,19,3,28,3,59,3,57,3,58,3,55,13,37,3,38,3,69,3,71,3,68,3,2,2,2,56,3,16,10,8,3,3,2,3,51,5,17,3,60,11,4,1,5,0,0,0,0,4,147,1,10,5,46,17,11,6,0,0,0,0,0,0,0,0,33,4,7,5,11,11,5,1,7,0,39,11,4,19,2,12,6,12,22,13,1,11,22,56,0,12,24,56,1,12,23,64,10,0,0,0,0,0,0,0,0,12,28,14,3,65,11,12,8,6,0,0,0,0,0,0,0,0,12,11,10,11,10,8,35,4,89,5,33,14,3,10,11,66,11,20,19,0,12,29,12,17,12,16,12,14,12,30,12,15,12,19,12,20,12,7,12,10,12,25,12,18,12,12,12,9,12,13,11,25,11,20,11,15,11,30,11,19,11,13,11,9,11,12,11,18,11,14,11,16,11,17,11,29,11,10,11,7,10,5,17,16,12,27,14,28,14,27,17,19,32,4,77,5,81,11,5,1,7,1,39,13,28,11,27,68,10,11,11,6,1,0,0,0,0,0,0,0,22,12,11,5,28,11,1,11,6,13,28,10,5,17,1,13,28,17,2,14,2,16,0,20,14,2,16,1,20,14,2,16,2,20,14,2,16,3,20,14,2,16,4,20,14,2,16,5,20,14,2,16,6,20,10,5,17,14,12,26,11,24,14,2,16,7,20,14,2,16,8,20,14,2,16,9,20,10,5,17,12,12,21,11,0,11,28,11,23,14,2,16,10,20,14,2,16,11,20,11,26,11,21,11,5,17,13,2,1,0,0,0,20,44,14,1,56,2,32,4,35,5,5,13,1,69,21,19,3,12,7,12,5,12,6,13,0,11,5,56,0,12,4,14,7,56,3,4,29,11,7,56,4,12,8,10,2,11,8,17,18,11,4,11,6,10,3,17,17,5,34,11,4,10,3,56,5,11,6,17,10,5,0,11,2,1,11,3,1,11,1,70,21,0,0,0,0,0,0,0,0,11,0,56,6,2,2,0,0,0,33,24,10,0,46,65,10,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,1,35,4,21,5,11,10,0,10,2,67,10,6,0,0,0,0,0,0,0,0,17,15,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,2,1,2,1,3,1,7,1,8,1,9,1,10,1,11,1,4,1,5,1,6,1,0,1,1,0],"stake_subsidy":[161,28,235,11,6,0,0,0,12,1,0,12,2,12,22,3,34,37,4,71,4,5,75,74,7,149,1,176,2,8,197,3,64,6,133,4,28,10,161,4,20,12,181,4,180,1,13,233,5,10,15,243,5,4,0,18,1,6,1,7,1,14,1,21,1,23,0,3,4,0,1,0,12,0,2,1,4,1,0,1,4,2,2,0,5,4,2,0,0,8,0,1,0,0,5,2,3,0,0,10,4,5,0,1,16,7,8,0,2,17,13,14,1,0,2,24,11,5,1,0,3,15,12,5,0,5,10,4,10,5,11,2,1,8,3,3,3,13,7,8,4,1,8,0,1,7,8,0,1,11,2,1,8,3,1,6,8,0,1,3,0,1,7,8,4,1,8,1,3,4,11,2,1,8,3,3,1,8,3,1,6,11,2,1,9,0,2,3,3,2,7,11,2,1,9,0,3,1,11,2,1,9,0,3,66,97,103,7,66,97,108,97,110,99,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,84,120,67,111,110,116,101,120,116,13,97,100,118,97,110,99,101,95,101,112,111,99,104,3,98,97,103,7,98,97,108,97,110,99,101,6,99,114,101,97,116,101,27,99,117,114,114,101,110,116,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,28,99,117,114,114,101,110,116,95,101,112,111,99,104,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,20,100,105,115,116,114,105,98,117,116,105,111,110,95,99,111,117,110,116,101,114,12,101,120,116,114,97,95,102,105,101,108,100,115,7,103,101,110,101,115,105,115,4,109,97,116,104,3,109,105,110,3,110,101,119,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,6,7,11,2,1,8,3,11,3,9,3,20,3,19,13,12,8,1,0,3,0,0,6,19,10,3,7,0,75,37,4,6,5,10,11,4,1,7,1,39,11,0,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,11,4,17,3,18,0,2,1,3,0,0,9,57,10,0,16,0,20,10,0,16,1,56,0,17,6,12,3,10,0,15,1,11,3,56,1,12,2,10,0,16,2,20,6,1,0,0,0,0,0,0,0,22,10,0,15,2,21,10,0,16,2,20,10,0,16,3,20,25,6,0,0,0,0,0,0,0,0,33,4,53,10,0,16,0,20,53,10,0,16,4,20,53,24,7,0,26,12,1,10,0,16,0,20,11,1,52,23,11,0,15,0,21,5,55,11,0,1,11,2,2,2,1,0,0,6,8,10,0,16,0,20,11,0,16,1,56,0,17,6,2,0,2,0,0,0,1,0,3,0,4,0,13,0,22,0],"staking_pool":[161,28,235,11,6,0,0,0,12,1,0,20,2,20,52,3,72,173,2,4,245,2,34,5,151,3,205,2,7,228,5,200,8,8,172,14,96,6,140,15,200,1,10,212,16,66,12,150,17,145,11,13,167,28,28,15,195,28,4,0,68,1,45,2,14,2,15,2,40,2,44,2,69,2,72,2,73,2,74,0,7,12,0,0,4,7,0,0,6,12,0,1,3,7,1,0,0,2,0,12,0,3,1,4,1,0,1,5,2,7,0,5,10,4,0,6,5,2,0,7,8,12,2,7,1,4,1,9,9,2,0,0,42,0,1,0,0,59,2,3,0,0,60,4,5,0,0,79,6,7,0,0,75,3,5,0,0,22,8,9,0,0,58,10,9,0,0,57,11,9,0,0,56,11,9,0,0,80,12,5,0,0,11,13,9,0,0,19,13,9,0,0,71,14,15,0,0,51,16,17,0,0,67,16,15,0,0,66,16,15,0,0,35,14,18,0,0,33,14,18,0,0,64,19,3,0,0,65,19,9,0,0,39,20,9,0,0,32,21,18,0,0,54,22,23,0,0,48,14,15,0,0,49,14,15,0,0,24,14,24,0,0,70,25,15,0,0,52,25,15,0,0,36,22,18,0,0,27,26,15,0,0,28,26,15,0,0,31,9,23,0,0,17,22,9,0,1,16,48,37,1,0,1,26,46,9,1,0,1,29,52,47,1,3,1,34,48,18,1,0,1,37,48,18,1,0,1,43,9,31,1,0,1,63,47,31,1,0,2,42,0,34,0,3,38,40,15,1,0,3,64,45,33,1,0,3,78,36,15,1,0,3,81,9,33,1,0,4,41,42,15,0,5,21,30,9,0,5,30,37,17,1,8,5,42,0,30,0,7,13,43,9,2,7,4,7,16,53,54,2,7,4,7,18,53,18,2,7,4,7,42,0,29,2,7,4,8,73,50,9,1,8,9,23,39,15,0,9,62,39,49,0,52,28,38,15,44,32,43,32,47,1,41,32,49,28,42,32,34,15,39,15,36,15,37,15,53,3,35,15,33,15,51,28,50,28,1,7,8,10,1,8,0,4,7,8,0,11,5,1,8,8,3,7,8,10,1,8,2,3,7,8,0,8,2,7,8,10,1,11,5,1,8,8,2,7,8,0,8,2,2,3,11,5,1,8,8,2,7,8,0,11,5,1,8,8,0,2,7,8,0,7,8,10,1,7,8,0,4,7,8,0,3,3,3,2,7,8,0,3,1,6,8,0,1,3,1,6,8,2,1,8,6,1,1,3,7,8,2,3,7,8,10,2,7,8,2,8,2,2,6,8,2,6,8,2,2,6,8,0,3,1,8,1,1,6,11,9,2,3,8,1,1,6,8,1,2,6,8,1,3,1,11,9,2,3,8,1,2,3,8,1,1,11,9,2,9,0,9,1,1,8,7,1,11,3,1,9,0,1,8,8,1,11,5,1,9,0,1,8,4,2,8,2,3,1,6,11,5,1,9,0,1,6,9,0,5,3,11,5,1,8,8,3,11,5,1,8,8,3,1,6,8,10,2,7,11,5,1,9,0,11,5,1,9,0,3,3,8,1,11,5,1,8,8,2,3,3,3,7,11,9,2,9,0,9,1,9,0,9,1,5,3,3,8,1,3,3,2,7,11,5,1,9,0,3,2,7,11,3,1,9,0,9,0,1,9,0,1,6,11,3,1,9,0,1,5,2,9,0,5,2,6,8,2,11,5,1,8,8,2,6,11,3,1,9,0,9,0,2,6,11,9,2,9,0,9,1,9,0,1,6,9,1,3,3,8,1,3,3,66,97,103,7,66,97,108,97,110,99,101,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,16,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,3,97,100,100,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,24,99,104,101,99,107,95,98,97,108,97,110,99,101,95,105,110,118,97,114,105,97,110,116,115,8,99,111,110,116,97,105,110,115,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,18,100,101,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,6,100,101,108,101,116,101,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,5,101,112,111,99,104,14,101,120,99,104,97,110,103,101,95,114,97,116,101,115,12,101,120,116,114,97,95,102,105,101,108,100,115,4,102,105,108,108,14,103,101,116,95,115,117,105,95,97,109,111,117,110,116,16,103,101,116,95,116,111,107,101,110,95,97,109,111,117,110,116,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,2,105,100,21,105,110,105,116,105,97,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,25,105,115,95,101,113,117,97,108,95,115,116,97,107,105,110,103,95,109,101,116,97,100,97,116,97,11,105,115,95,105,110,97,99,116,105,118,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,21,105,115,95,112,114,101,97,99,116,105,118,101,95,97,116,95,101,112,111,99,104,7,105,115,95,115,111,109,101,4,106,111,105,110,15,106,111,105,110,95,115,116,97,107,101,100,95,115,117,105,4,109,97,116,104,3,109,105,110,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,27,112,101,110,100,105,110,103,95,112,111,111,108,95,116,111,107,101,110,95,119,105,116,104,100,114,97,119,13,112,101,110,100,105,110,103,95,115,116,97,107,101,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,26,112,101,110,100,105,110,103,95,116,111,116,97,108,95,115,117,105,95,119,105,116,104,100,114,97,119,7,112,111,111,108,95,105,100,17,112,111,111,108,95,116,111,107,101,110,95,97,109,111,117,110,116,18,112,111,111,108,95,116,111,107,101,110,95,98,97,108,97,110,99,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,9,112,114,105,110,99,105,112,97,108,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,30,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,12,114,101,119,97,114,100,115,95,112,111,111,108,6,115,101,110,100,101,114,4,115,111,109,101,5,115,112,108,105,116,16,115,112,108,105,116,95,115,116,97,107,101,100,95,115,117,105,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,97,109,111,117,110,116,11,115,117,105,95,98,97,108,97,110,99,101,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,17,117,110,119,114,97,112,95,115,116,97,107,101,100,95,115,117,105,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,5,118,97,108,117,101,23,119,105,116,104,100,114,97,119,95,102,114,111,109,95,112,114,105,110,99,105,112,97,108,16,119,105,116,104,100,114,97,119,95,114,101,119,97,114,100,115,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,0,2,11,30,8,7,12,11,3,1,3,20,11,3,1,3,71,3,61,11,5,1,8,8,53,3,24,11,9,2,3,8,1,47,3,50,3,46,3,25,8,4,1,2,2,70,3,52,3,2,2,4,30,8,7,51,8,6,66,3,55,11,5,1,8,8,0,3,0,0,27,18,10,0,56,0,12,1,10,0,17,48,56,1,56,1,6,0,0,0,0,0,0,0,0,56,2,6,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,0,17,40,18,0,2,1,3,0,0,35,45,14,1,56,3,12,5,10,0,46,17,17,32,4,9,5,15,11,0,1,11,3,1,7,11,39,10,5,6,0,0,0,0,0,0,0,0,36,4,20,5,26,11,0,1,11,3,1,7,18,39,11,3,17,48,10,0,46,56,4,11,2,11,1,18,2,12,4,10,0,16,0,20,11,5,22,11,0,15,0,21,11,4,2,2,3,0,0,38,52,10,0,11,1,17,3,12,4,12,3,14,4,56,3,12,5,10,0,10,5,10,3,11,2,46,17,54,17,9,12,6,11,5,14,6,56,3,22,12,7,10,0,16,1,20,11,7,22,10,0,15,1,21,10,0,16,2,20,11,3,22,10,0,15,2,21,10,0,46,17,17,4,44,11,0,17,7,5,46,11,0,1,13,4,11,6,56,5,1,11,4,2,3,3,0,0,41,31,14,1,16,3,20,10,0,46,56,4,33,4,9,5,13,11,0,1,7,2,39,11,0,14,1,16,4,20,12,2,46,11,2,17,22,12,3,11,1,17,4,12,4,14,3,14,4,56,3,17,30,11,4,2,4,0,0,0,5,8,11,0,19,2,12,1,1,1,17,46,11,1,2,5,3,0,0,9,15,10,0,16,5,20,14,1,56,3,22,10,0,15,5,21,11,0,15,6,11,1,56,5,1,2,6,3,0,0,42,28,11,1,46,17,54,6,1,0,0,0,0,0,0,0,22,12,3,10,0,17,7,10,0,17,8,10,0,15,7,10,3,10,0,16,5,20,10,0,16,8,20,18,1,56,6,11,0,11,3,12,2,46,11,2,17,32,2,7,0,0,0,9,29,10,0,16,5,20,10,0,16,1,20,23,10,0,15,5,21,10,0,16,8,20,10,0,16,2,20,23,10,0,15,8,21,6,0,0,0,0,0,0,0,0,10,0,15,1,21,6,0,0,0,0,0,0,0,0,11,0,15,2,21,2,8,3,0,0,23,31,10,0,16,5,20,10,0,16,8,20,18,1,12,1,10,0,16,5,20,10,0,16,0,20,22,10,0,15,5,21,14,1,10,0,16,5,20,17,30,10,0,15,8,21,6,0,0,0,0,0,0,0,0,11,0,15,0,21,2,9,0,0,0,44,33,10,0,11,3,12,4,46,11,4,17,22,12,6,14,6,11,2,17,29,12,8,10,8,10,1,38,4,20,11,8,11,1,23,12,5,5,22,6,0,0,0,0,0,0,0,0,12,5,11,5,10,0,16,6,56,3,17,45,12,7,11,0,15,6,11,7,56,7,2,10,3,0,0,9,29,10,0,15,7,10,1,17,31,56,6,10,0,46,17,16,4,10,5,14,11,0,1,7,15,39,10,0,46,17,17,32,4,20,5,24,11,0,1,7,17,39,11,0,15,9,11,1,56,8,2,11,3,0,0,9,16,10,0,46,17,17,32,4,6,5,10,11,0,1,7,12,39,11,1,56,9,11,0,15,10,21,2,12,1,0,0,9,4,11,0,16,5,20,2,13,1,0,0,9,4,11,0,16,3,20,2,14,1,0,0,9,4,11,0,16,11,56,3,2,15,1,0,0,9,4,11,0,16,4,20,2,16,1,0,0,9,4,11,0,16,9,56,10,2,17,1,0,0,9,4,11,0,16,10,56,11,2,18,1,0,0,15,53,10,0,16,11,56,3,12,3,10,1,10,3,37,4,9,5,15,11,0,1,11,2,1,7,4,39,11,3,10,1,23,7,0,38,4,22,5,28,11,0,1,11,2,1,7,19,39,10,1,7,0,38,4,33,5,39,11,0,1,11,2,1,7,19,39,11,2,17,48,10,0,16,3,20,10,0,16,4,20,11,0,15,11,11,1,56,7,18,2,2,19,1,4,0,9,9,11,0,11,1,10,2,17,18,11,2,46,17,55,56,12,2,20,1,4,0,51,24,10,0,14,1,12,2,46,11,2,17,21,4,8,5,12,11,0,1,7,13,39,11,1,19,2,12,3,1,1,17,46,11,0,15,11,11,3,56,5,1,2,21,1,0,0,18,25,10,0,16,3,20,10,1,16,3,20,33,4,17,11,0,16,4,20,11,1,16,4,20,33,12,2,5,23,11,0,1,11,1,1,9,12,2,11,2,2,22,1,0,0,42,45,10,0,10,1,17,28,4,8,11,0,1,17,31,2,10,0,16,10,10,1,56,13,11,1,17,45,12,3,10,0,16,9,56,14,20,12,2,10,3,10,2,38,4,41,5,25,10,0,16,7,10,3,56,15,4,36,11,0,16,7,11,3,56,16,20,2,11,3,6,1,0,0,0,0,0,0,0,23,12,3,5,20,11,0,1,17,31,2,23,1,0,0,9,4,11,0,16,0,20,2,24,1,0,0,9,4,11,0,16,1,20,2,25,3,0,0,9,3,11,0,16,7,2,26,1,0,0,9,4,11,0,16,12,20,2,27,1,0,0,9,4,11,0,16,13,20,2,28,0,0,0,18,17,10,0,17,16,4,8,11,0,1,8,12,2,5,15,11,0,16,9,56,14,20,11,1,36,12,2,11,2,2,29,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,12,20,53,11,1,53,24,11,0,16,13,20,53,26,52,2,30,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,13,20,53,11,1,53,24,11,0,16,12,20,53,26,52,2,31,0,0,0,9,4,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,18,1,2,32,0,0,0,55,22,10,0,11,1,17,22,12,3,14,3,10,0,16,5,20,17,30,12,4,11,0,16,8,20,12,2,11,4,11,2,33,4,19,5,21,7,10,39,2,0,7,0,8,0,9,2,1,2,2,0,3,0,4,0,6,0,5,0,1,0,2,2,3,1,0,1,1,0,76,0,77,0],"storage_fund":[161,28,235,11,6,0,0,0,11,1,0,6,2,6,14,3,20,44,4,64,8,5,72,73,7,145,1,178,1,8,195,2,64,10,131,3,15,12,146,3,107,13,253,3,4,15,129,4,2,0,9,1,4,1,10,0,2,4,0,1,0,4,1,0,1,2,1,2,0,0,6,0,1,0,0,3,2,0,0,0,13,3,4,0,0,12,3,4,0,1,5,8,4,1,0,1,8,9,7,1,0,1,14,10,4,1,0,1,15,5,7,1,0,7,6,4,6,5,6,6,6,1,11,1,1,8,2,1,8,0,6,7,8,0,11,1,1,8,2,11,1,1,8,2,11,1,1,8,2,3,3,1,6,8,0,1,3,0,1,8,2,1,11,1,1,9,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,6,11,1,1,9,0,7,66,97,108,97,110,99,101,3,83,85,73,11,83,116,111,114,97,103,101,70,117,110,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,4,106,111,105,110,3,110,101,119,22,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,98,97,108,97,110,99,101,5,115,112,108,105,116,12,115,116,111,114,97,103,101,95,102,117,110,100,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,13,116,111,116,97,108,95,98,97,108,97,110,99,101,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,11,1,1,8,2,7,11,1,1,8,2,0,3,0,0,5,4,56,0,11,0,18,0,2,1,3,0,0,0,30,10,0,15,0,11,2,56,1,1,10,0,15,0,11,3,56,1,1,10,0,15,1,11,1,56,1,1,10,0,15,1,11,5,56,2,12,6,10,0,15,0,11,6,56,1,1,11,0,15,1,11,4,56,2,2,2,1,0,0,5,4,11,0,16,1,56,3,2,3,1,0,0,5,8,10,0,16,1,56,3,11,0,16,0,56,3,22,2,0,1,0,0,0,11,0],"iota_system":[161,28,235,11,6,0,0,0,12,1,0,30,2,30,78,3,108,188,3,4,168,4,16,5,184,4,214,3,7,142,8,237,13,8,251,21,96,6,219,22,54,10,145,23,8,12,153,23,251,6,13,148,30,4,15,152,30,2,0,57,1,33,2,20,2,22,2,24,2,32,2,56,2,60,2,61,2,62,0,54,0,55,0,58,0,83,0,84,0,8,8,0,1,3,7,1,0,0,2,0,4,1,0,1,3,1,12,1,0,1,5,2,7,0,5,14,4,0,6,5,2,0,7,12,12,2,7,1,4,1,9,13,2,0,10,6,4,0,11,4,7,0,11,7,12,0,12,9,4,0,12,10,4,0,12,11,4,0,13,16,4,0,14,15,12,0,0,23,0,1,0,0,42,2,1,0,0,44,3,1,0,0,41,3,1,0,0,43,3,1,0,0,46,4,1,0,0,52,4,1,0,0,45,5,1,0,0,51,5,1,0,0,38,6,1,0,0,40,6,7,0,0,39,8,1,0,0,47,9,1,0,0,48,9,10,0,0,37,11,1,0,0,63,11,1,0,0,49,3,1,0,0,73,12,1,0,0,71,12,1,0,0,72,12,1,0,0,81,12,1,0,0,74,12,1,0,0,64,12,1,0,0,76,12,1,0,0,66,12,1,0,0,77,12,1,0,0,67,12,1,0,0,79,12,1,0,0,69,12,1,0,0,78,13,1,0,0,68,13,1,0,0,80,12,1,0,0,70,12,1,0,0,75,12,1,0,0,65,12,1,0,0,34,14,15,0,0,17,16,17,0,0,19,18,10,0,0,30,16,19,0,0,31,16,20,0,0,29,16,20,0,3,25,39,40,1,0,4,18,26,1,2,7,4,4,21,49,53,2,7,4,4,36,49,50,2,7,4,8,35,35,1,1,12,8,53,28,1,1,8,9,50,33,34,0,12,17,19,17,0,12,19,47,10,0,12,23,22,23,0,12,27,1,24,0,12,34,46,15,0,12,37,43,1,0,12,38,36,7,0,12,39,37,7,0,12,41,30,1,0,12,42,29,1,0,12,43,30,1,0,12,44,30,1,0,12,45,32,1,0,12,46,31,1,0,12,47,42,10,0,12,49,30,1,0,12,51,32,1,0,12,52,31,1,0,12,59,19,24,0,12,63,43,1,0,12,64,44,1,0,12,65,44,1,0,12,66,44,1,0,12,67,44,1,0,12,68,45,1,0,12,69,44,1,0,12,70,44,1,0,12,71,44,1,0,12,72,44,1,0,12,73,44,1,0,12,74,44,1,0,12,75,44,1,0,12,76,44,1,0,12,77,44,1,0,12,78,45,1,0,12,79,44,1,0,12,80,44,1,0,12,81,44,1,0,12,82,23,51,0,42,25,46,27,45,7,41,38,45,41,44,25,42,52,43,52,8,8,5,10,8,15,11,2,1,8,6,3,3,8,14,8,9,7,8,8,0,16,7,8,0,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,8,2,7,8,0,7,8,8,3,7,8,0,6,8,16,3,3,7,8,0,3,7,8,8,4,7,8,0,11,3,1,8,6,5,7,8,8,1,8,11,5,7,8,0,10,11,3,1,8,6,11,1,1,3,5,7,8,8,3,7,8,0,8,11,7,8,8,1,11,2,1,8,6,3,7,8,0,6,8,16,5,3,7,8,0,10,2,6,8,8,4,7,8,0,10,2,10,2,6,8,8,2,7,8,0,6,8,4,1,6,11,7,2,3,8,10,1,7,8,0,1,10,5,11,11,2,1,8,6,11,2,1,8,6,7,8,0,3,3,3,3,3,3,3,7,8,8,1,6,8,13,1,7,8,13,3,8,0,8,12,3,7,10,8,15,11,2,1,8,6,3,3,8,14,8,9,7,8,8,1,8,12,1,3,2,3,8,12,3,7,8,5,9,0,9,1,1,8,0,1,9,0,16,7,8,13,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,8,2,7,8,13,7,8,8,3,7,8,13,6,8,16,3,3,7,8,13,3,7,8,8,1,6,8,8,1,5,2,9,0,5,4,7,8,13,11,3,1,8,6,5,7,8,8,5,7,8,13,10,11,3,1,8,6,11,1,1,3,5,7,8,8,1,8,6,2,11,2,1,9,0,7,8,8,1,11,3,1,9,0,1,11,3,1,8,6,3,7,8,13,8,11,7,8,8,3,7,8,13,6,8,16,5,3,7,8,13,10,2,6,8,8,4,7,8,13,10,2,10,2,6,8,8,2,7,8,13,6,8,4,11,7,8,13,3,3,11,2,1,8,6,11,2,1,8,6,3,3,3,3,3,7,8,8,2,7,8,13,8,13,2,7,8,5,9,0,1,9,1,1,8,13,2,3,8,13,1,7,9,1,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,14,83,117,105,83,121,115,116,101,109,83,116,97,116,101,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,26,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,101,115,3,97,100,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,4,99,111,105,110,6,99,114,101,97,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,2,105,100,24,108,111,97,100,95,105,110,110,101,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,17,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,21,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,95,109,117,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,19,112,111,111,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,27,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,110,111,110,95,101,110,116,114,121,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,32,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,95,110,111,110,95,101,110,116,114,121,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,6,115,101,110,100,101,114,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,28,8,5,85,3,0,3,0,0,21,23,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,50,12,9,17,51,12,10,11,0,10,10,18,0,12,8,13,8,15,0,11,10,11,9,56,0,11,8,56,1,2,1,1,4,0,1,19,11,0,17,39,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,11,15,17,57,2,2,1,4,0,1,5,11,0,17,39,11,1,17,59,2,3,1,4,0,1,5,11,0,17,39,11,1,17,56,2,4,1,4,0,1,5,11,0,17,39,11,1,17,58,2,5,1,4,0,1,6,11,0,17,39,11,1,11,2,17,61,2,6,1,4,0,1,6,11,0,17,39,11,1,11,2,17,65,2,7,1,4,0,1,6,11,0,17,39,11,1,11,2,17,60,2,8,1,4,0,1,6,11,0,17,39,11,1,11,2,17,64,2,9,1,4,0,1,10,11,0,11,1,11,2,10,3,17,10,11,3,46,17,47,56,2,2,10,1,0,0,1,7,11,0,17,39,11,1,11,2,11,3,17,54,2,11,1,4,0,1,12,11,0,17,39,11,1,11,2,11,3,10,4,17,55,11,4,46,17,47,56,2,2,12,1,4,0,1,11,11,0,11,1,10,2,17,13,10,2,56,3,11,2,46,17,47,56,4,2,13,1,0,0,1,6,11,0,17,39,11,1,11,2,17,62,2,14,1,4,0,1,6,11,0,17,39,11,1,11,2,17,53,2,15,1,4,0,1,6,11,0,17,39,11,1,11,2,17,67,2,16,1,4,0,1,5,11,0,17,39,11,1,17,63,2,17,1,4,0,1,6,11,0,17,39,11,1,11,2,17,77,2,18,1,4,0,1,6,11,0,17,39,11,1,11,2,17,75,2,19,1,4,0,1,6,11,0,17,39,11,1,11,2,17,76,2,20,1,4,0,1,6,11,0,17,39,11,1,11,2,17,85,2,21,1,4,0,1,6,11,0,17,39,11,1,11,2,17,78,2,22,1,4,0,1,6,11,0,17,39,11,1,11,2,17,68,2,23,1,4,0,1,6,11,0,17,39,11,1,11,2,17,80,2,24,1,4,0,1,6,11,0,17,39,11,1,11,2,17,70,2,25,1,4,0,1,6,11,0,17,39,11,1,11,2,17,81,2,26,1,4,0,1,6,11,0,17,39,11,1,11,2,17,71,2,27,1,4,0,1,6,11,0,17,39,11,1,11,2,17,83,2,28,1,4,0,1,6,11,0,17,39,11,1,11,2,17,73,2,29,1,4,0,1,7,11,0,17,39,11,1,11,2,11,3,17,82,2,30,1,4,0,1,7,11,0,17,39,11,1,11,2,11,3,17,72,2,31,1,4,0,1,6,11,0,17,39,11,1,11,2,17,84,2,32,1,4,0,1,6,11,0,17,39,11,1,11,2,17,74,2,33,1,4,0,1,6,11,0,17,39,11,1,11,2,17,79,2,34,1,4,0,1,6,11,0,17,39,11,1,11,2,17,69,2,35,1,0,0,1,5,11,0,17,39,11,1,17,52,2,36,1,0,0,1,4,11,0,17,38,17,48,2,37,0,0,0,20,29,11,2,17,39,12,11,10,10,46,17,47,7,2,33,4,10,5,16,11,11,1,11,10,1,7,0,39,11,11,11,3,11,4,11,0,11,1,11,5,11,6,11,7,11,8,11,9,11,10,17,49,2,38,0,0,0,1,4,11,0,17,40,46,2,39,0,0,0,1,3,11,0,17,40,2,40,0,0,0,48,47,10,0,16,1,20,6,1,0,0,0,0,0,0,0,33,4,25,10,0,15,0,10,0,16,1,20,56,5,17,86,12,2,6,2,0,0,0,0,0,0,0,10,0,15,1,21,10,0,15,0,10,0,16,1,20,11,2,56,6,10,0,15,0,10,0,16,1,20,56,7,12,1,10,1,46,17,66,11,0,16,1,20,33,4,41,5,45,11,1,1,7,1,39,11,1,2,0,0,0,1,0,26,0],"iota_system_state_inner":[161,28,235,11,6,0,0,0,12,1,0,45,2,45,108,3,153,1,235,5,4,132,7,50,5,182,7,151,7,7,205,14,129,30,8,206,44,96,6,174,45,117,10,163,46,189,1,12,224,47,134,18,13,230,65,46,15,148,66,4,0,115,1,70,2,27,2,28,2,29,2,41,2,69,2,72,2,113,2,117,2,123,2,124,2,177,1,2,178,1,0,103,0,106,0,109,0,164,1,0,165,1,0,169,1,0,13,4,0,0,14,4,0,0,10,4,0,0,11,4,0,0,12,3,0,1,4,7,1,0,0,2,0,12,0,3,1,4,1,0,1,4,2,12,1,0,1,6,3,7,0,8,6,2,0,9,15,12,2,7,1,4,1,11,16,2,0,12,21,7,2,1,0,0,0,13,22,7,1,3,0,14,7,4,0,15,5,7,0,15,8,12,0,16,9,4,0,17,18,4,0,18,17,12,0,18,19,2,0,19,20,4,0,0,31,0,1,0,0,32,2,3,0,0,163,1,1,4,0,0,83,5,6,0,0,85,7,6,0,0,82,7,6,0,0,84,7,6,0,0,87,8,6,0,0,99,8,6,0,0,86,9,6,0,0,98,9,6,0,0,80,10,11,0,0,81,12,11,0,0,88,13,14,0,0,78,15,6,0,0,125,15,6,0,0,79,16,6,0,0,126,16,6,0,0,89,7,6,0,0,154,1,17,6,0,0,152,1,17,6,0,0,153,1,17,6,0,0,162,1,17,6,0,0,155,1,17,6,0,0,132,1,17,6,0,0,157,1,17,6,0,0,134,1,17,6,0,0,158,1,17,6,0,0,135,1,17,6,0,0,160,1,17,6,0,0,137,1,17,6,0,0,159,1,18,6,0,0,136,1,18,6,0,0,161,1,17,6,0,0,138,1,17,6,0,0,156,1,17,6,0,0,133,1,17,6,0,0,25,19,14,0,0,38,20,21,0,0,74,20,21,0,0,116,20,21,0,0,46,6,21,0,0,40,20,21,0,0,170,1,22,21,0,0,171,1,22,23,0,0,172,1,20,24,0,0,49,22,25,0,0,51,20,21,0,0,50,20,21,0,0,73,26,27,0,0,23,20,28,0,0,43,29,14,0,1,34,99,68,1,0,1,59,98,63,1,0,2,66,39,40,0,3,35,38,6,1,0,3,60,85,21,1,0,3,101,89,38,1,0,3,176,1,87,21,1,0,3,181,1,84,38,1,0,3,182,1,6,38,1,0,4,44,100,58,1,0,4,56,58,38,1,0,5,36,68,6,1,3,7,61,97,6,1,0,10,75,101,6,1,12,11,38,43,21,0,11,95,43,44,0,12,30,67,63,2,1,0,12,37,6,36,2,1,0,12,47,67,93,2,1,0,12,48,71,72,2,1,0,12,55,70,6,2,1,0,12,77,71,77,2,1,0,13,30,73,63,1,3,13,37,6,69,1,3,13,55,74,6,1,3,13,58,76,63,1,3,13,77,75,6,1,3,13,100,68,69,1,3,14,25,88,14,0,15,102,60,21,0,16,25,91,14,0,16,66,14,34,0,16,118,86,21,0,16,120,86,21,0,17,66,45,42,0,17,67,78,6,0,17,87,54,6,0,17,96,57,6,0,17,97,54,6,0,17,127,79,6,0,17,128,1,79,6,0,17,129,1,79,6,0,17,130,1,79,6,0,17,131,1,82,6,0,17,139,1,79,6,0,17,140,1,79,6,0,17,141,1,79,6,0,17,142,1,79,6,0,17,143,1,79,6,0,17,144,1,79,6,0,17,145,1,79,6,0,17,146,1,79,6,0,17,147,1,79,6,0,17,148,1,82,6,0,17,149,1,79,6,0,17,150,1,79,6,0,17,151,1,79,6,0,18,179,1,65,66,0,19,23,33,28,0,19,24,33,49,0,19,25,90,6,0,19,26,81,6,0,19,33,33,21,0,19,52,56,53,0,19,53,56,53,0,19,54,52,53,0,19,57,62,63,0,19,66,31,32,0,19,68,33,21,0,19,73,94,27,0,19,80,59,11,0,19,82,48,6,0,19,83,46,6,0,19,84,47,6,0,19,85,47,6,0,19,86,55,6,0,19,88,61,14,0,19,107,33,24,0,19,121,33,21,0,19,171,1,62,23,0,19,173,1,62,21,0,19,180,1,51,50,0,69,35,60,37,62,37,68,35,79,44,72,35,71,35,74,44,76,44,78,44,77,44,73,35,59,37,56,37,58,37,57,37,63,92,70,35,75,44,64,37,53,21,52,21,61,37,65,96,55,37,7,10,8,19,11,7,1,8,10,3,3,8,0,8,15,7,8,12,1,8,2,8,3,3,3,3,3,3,3,7,8,12,1,8,0,1,8,3,16,7,8,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,0,2,7,8,3,7,8,12,3,7,8,3,6,8,20,3,3,7,8,3,3,7,8,12,4,7,8,3,11,8,1,8,10,5,7,8,12,1,8,17,5,7,8,3,10,11,8,1,8,10,11,5,1,3,5,7,8,12,3,7,8,3,8,17,7,8,12,1,11,7,1,8,10,3,7,8,3,6,8,20,5,3,8,21,5,7,11,13,2,5,11,14,1,5,3,7,8,3,10,2,6,8,12,4,7,8,3,10,2,10,2,6,8,12,11,7,8,3,3,3,11,7,1,8,10,11,7,1,8,10,3,3,3,3,3,7,8,12,1,6,8,3,1,3,2,6,8,3,5,1,8,9,1,6,11,11,2,8,9,5,1,11,14,1,5,2,7,8,3,6,8,9,1,6,11,11,2,3,8,16,1,10,5,3,10,11,8,1,8,10,11,5,1,3,7,8,12,2,3,8,22,2,10,8,19,7,8,12,1,8,22,1,6,8,22,1,8,18,2,5,11,14,1,5,1,11,13,2,9,0,9,1,1,8,10,1,11,7,1,9,0,1,7,8,12,1,8,6,23,3,3,3,3,3,8,6,8,0,3,3,1,11,7,1,8,10,3,3,11,7,1,8,10,8,15,3,8,6,8,18,3,3,11,13,2,5,11,14,1,5,3,8,22,1,8,19,1,6,8,12,1,5,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,3,7,8,22,8,19,7,8,12,2,7,8,22,7,8,12,3,7,8,22,3,7,8,12,1,6,10,8,19,1,8,21,3,7,8,22,6,8,20,2,3,7,8,22,6,8,21,1,1,7,8,19,3,7,8,19,8,21,3,3,7,8,22,3,6,8,12,2,7,8,22,6,8,12,2,7,8,19,3,1,11,8,1,9,0,4,7,8,22,5,11,7,1,8,10,7,8,12,1,6,8,17,3,7,8,22,8,17,7,8,12,2,6,8,22,5,1,1,4,6,5,6,5,5,7,11,14,1,5,1,6,8,21,1,6,5,2,6,11,13,2,9,0,9,1,6,9,0,1,9,0,1,11,14,1,9,0,3,7,11,13,2,9,0,9,1,9,0,9,1,2,7,11,13,2,9,0,9,1,6,9,0,1,7,9,1,2,6,11,14,1,9,0,6,9,0,2,7,11,14,1,9,0,9,0,2,7,11,14,1,9,0,6,9,0,1,6,11,14,1,9,0,2,9,0,9,1,2,7,8,19,7,8,12,2,7,8,19,10,2,2,7,8,19,6,8,19,2,6,8,22,6,8,19,3,7,8,19,10,2,10,2,44,1,3,3,3,3,3,3,1,1,1,11,7,1,8,10,3,3,3,3,3,3,3,3,4,3,3,3,11,7,1,8,10,3,3,3,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,3,11,7,1,8,10,4,11,7,1,8,10,4,3,3,3,3,4,3,1,7,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,1,6,8,18,1,6,11,7,1,9,0,1,7,8,15,2,7,11,7,1,9,0,3,9,7,8,22,7,11,7,1,8,10,7,11,7,1,8,10,7,11,13,2,5,11,14,1,5,3,3,3,3,7,8,12,6,7,8,18,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,1,8,4,1,6,9,1,2,7,8,22,6,8,9,5,11,7,1,8,10,3,11,7,1,8,10,11,8,1,8,10,11,7,1,8,10,1,11,8,1,8,10,2,7,11,8,1,9,0,10,11,8,1,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,2,11,7,1,9,0,7,8,12,2,9,0,5,3,66,97,103,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,11,83,116,111,114,97,103,101,70,117,110,100,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,20,83,121,115,116,101,109,69,112,111,99,104,73,110,102,111,69,118,101,110,116,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,18,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,86,50,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,6,86,101,99,77,97,112,6,86,101,99,83,101,116,26,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,101,115,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,3,98,97,103,7,98,97,108,97,110,99,101,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,5,101,109,112,116,121,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,24,101,112,111,99,104,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,20,101,120,116,114,97,99,116,95,99,111,105,110,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,3,103,101,116,7,103,101,116,95,109,117,116,16,103,101,116,95,114,101,112,111,114,116,101,114,115,95,111,102,31,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,111,98,106,101,99,116,95,114,101,98,97,116,101,115,30,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,116,111,116,97,108,95,98,97,108,97,110,99,101,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,6,105,110,115,101,114,116,12,105,110,116,111,95,98,97,108,97,110,99,101,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,106,111,105,110,8,106,111,105,110,95,118,101,99,28,108,101,102,116,111,118,101,114,95,115,116,111,114,97,103,101,95,102,117,110,100,95,105,110,102,108,111,119,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,19,109,105,110,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,3,110,101,119,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,114,97,109,101,116,101,114,115,3,112,97,121,19,112,111,111,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,115,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,19,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,21,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,9,115,97,102,101,95,109,111,100,101,29,115,97,102,101,95,109,111,100,101,95,99,111,109,112,117,116,97,116,105,111,110,95,114,101,119,97,114,100,115,36,115,97,102,101,95,109,111,100,101,95,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,115,116,111,114,97,103,101,95,102,101,101,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,119,97,114,100,115,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,9,115,105,110,103,108,101,116,111,110,5,115,112,108,105,116,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,13,115,116,97,107,101,95,115,117,98,115,105,100,121,20,115,116,97,107,101,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,12,115,116,97,107,105,110,103,95,112,111,111,108,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,14,115,116,111,114,97,103,101,95,99,104,97,114,103,101,12,115,116,111,114,97,103,101,95,102,117,110,100,20,115,116,111,114,97,103,101,95,102,117,110,100,95,98,97,108,97,110,99,101,25,115,116,111,114,97,103,101,95,102,117,110,100,95,114,101,105,110,118,101,115,116,109,101,110,116,14,115,116,111,114,97,103,101,95,114,101,98,97,116,101,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,5,116,97,98,108,101,13,116,111,116,97,108,95,98,97,108,97,110,99,101,14,116,111,116,97,108,95,103,97,115,95,102,101,101,115,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,31,116,111,116,97,108,95,115,116,97,107,101,95,114,101,119,97,114,100,115,95,100,105,115,116,114,105,98,117,116,101,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,26,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,24,118,97,108,105,100,97,116,111,114,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,31,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,10,118,97,108,105,100,97,116,111,114,115,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,3,8,1,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,8,39,3,105,3,63,3,65,3,167,1,3,174,1,3,166,1,3,42,8,6,1,2,9,39,3,105,3,64,3,63,3,65,3,167,1,3,174,1,3,166,1,3,42,8,6,2,2,16,38,3,74,3,116,3,175,1,8,22,109,8,18,71,8,0,76,3,168,1,11,13,2,5,11,14,1,5,103,8,15,90,1,94,11,7,1,8,10,91,11,7,1,8,10,93,3,92,3,40,3,42,8,6,3,2,16,38,3,74,3,116,3,175,1,8,22,109,8,18,71,8,1,76,3,168,1,11,13,2,5,11,14,1,5,103,8,15,90,1,94,11,7,1,8,10,91,11,7,1,8,10,93,3,92,3,40,3,42,8,6,4,2,12,38,3,74,3,76,3,121,3,111,3,108,3,112,3,110,3,104,3,119,3,122,3,62,3,0,3,0,0,30,27,11,0,10,6,17,119,12,8,14,8,17,114,12,7,6,0,0,0,0,0,0,0,0,11,2,17,41,11,8,11,1,17,83,11,4,11,7,56,0,11,5,9,56,1,56,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,3,11,6,17,54,18,2,2,1,3,0,0,6,11,11,0,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,54,18,0,2,2,3,0,0,41,55,11,0,19,2,12,17,12,3,12,12,12,13,12,11,12,14,12,10,12,15,12,21,12,9,12,7,12,18,12,23,1,12,8,12,1,11,7,19,0,12,6,12,19,12,22,12,20,12,5,12,4,12,16,12,2,11,1,11,8,6,2,0,0,0,0,0,0,0,11,23,11,18,11,2,11,16,6,4,0,0,0,0,0,0,0,11,4,11,5,11,20,11,22,11,19,11,6,18,1,11,9,11,21,11,15,11,10,11,14,11,11,11,13,11,12,11,3,11,17,18,3,2,3,3,0,0,42,26,10,15,46,17,67,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,10,15,17,86,12,16,11,0,15,0,11,16,11,15,17,124,2,4,3,0,0,6,5,11,0,15,0,11,1,17,126,2,5,3,0,0,6,25,10,0,16,0,17,120,10,0,16,1,16,2,20,35,4,10,5,16,11,0,1,11,1,1,7,3,39,10,0,15,0,11,0,16,1,16,3,20,11,1,17,123,2,6,3,0,0,6,31,10,0,16,0,17,111,65,42,10,0,16,1,16,4,20,38,4,26,10,0,16,0,17,120,10,0,16,1,16,4,20,36,4,20,5,26,11,0,1,11,1,1,7,3,39,11,0,15,0,11,1,17,125,2,7,3,0,0,50,15,10,0,15,0,11,1,7,1,17,133,1,12,3,11,0,15,0,14,3,9,17,117,11,3,11,2,17,88,2,8,3,0,0,50,15,10,0,15,0,11,1,7,2,17,133,1,12,3,11,0,15,0,14,3,8,17,117,11,3,11,2,17,90,2,9,3,0,0,6,7,11,0,15,0,11,1,11,2,46,17,127,2,10,3,0,0,6,8,11,0,15,0,11,2,46,17,116,11,1,17,89,2,11,3,0,0,6,8,11,0,15,0,11,2,11,1,56,2,11,3,17,122,2,12,3,0,0,14,12,11,1,11,2,10,4,17,51,12,5,11,0,15,0,11,3,11,5,11,4,17,122,2,13,3,0,0,6,20,14,1,17,81,10,2,46,17,66,37,4,8,5,14,11,0,1,11,2,1,7,9,39,11,0,15,0,11,1,11,2,17,128,1,2,14,3,0,0,6,22,10,0,16,0,10,2,17,118,4,6,5,12,11,0,1,11,1,1,7,4,39,10,0,15,0,11,1,7,0,17,133,1,11,2,11,0,15,5,17,16,2,15,3,0,0,6,10,10,0,15,0,11,1,7,0,17,133,1,11,2,11,0,15,5,17,17,2,16,0,0,0,64,46,14,0,17,109,20,12,5,10,5,10,1,34,4,9,5,13,11,2,1,7,6,39,10,2,14,1,12,3,46,11,3,56,3,32,4,27,11,2,11,1,11,5,56,4,56,5,5,45,11,2,14,1,56,6,12,6,10,6,14,5,12,4,46,11,4,56,7,32,4,43,11,6,11,5,56,8,5,45,11,6,1,2,17,0,0,0,64,50,10,2,14,1,12,3,46,11,3,56,3,4,8,5,12,11,2,1,7,7,39,10,2,14,1,56,6,12,6,14,0,17,109,20,12,5,10,6,14,5,12,4,46,11,4,56,7,4,28,5,34,11,2,1,11,6,1,7,7,39,10,6,14,5,56,9,11,6,46,56,10,4,47,11,2,14,1,56,11,1,1,5,49,11,2,1,2,18,3,0,0,6,8,11,0,15,0,10,1,46,17,116,11,1,17,87,2,19,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,100,2,20,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,98,2,21,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,99,2,22,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,108,2,23,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,101,11,3,46,12,4,11,0,16,0,11,4,17,113,2,24,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,91,2,25,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,103,11,3,46,12,4,11,0,16,0,11,4,17,113,2,26,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,93,2,27,3,0,0,6,7,11,0,15,0,11,2,17,115,11,1,17,104,2,28,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,94,2,29,3,0,0,6,7,11,0,15,0,11,2,17,115,11,1,17,106,2,30,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,96,2,31,3,0,0,80,17,10,0,15,0,11,3,17,115,12,4,10,4,11,1,11,2,17,105,11,4,46,12,5,11,0,16,0,11,5,17,113,2,32,3,0,0,6,8,11,0,15,0,11,3,17,116,11,1,11,2,17,95,2,33,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,107,11,3,46,12,4,11,0,16,0,11,4,17,113,2,34,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,97,2,35,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,102,11,3,46,12,4,11,0,16,0,11,4,17,113,2,36,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,92,2,37,3,0,0,83,220,2,10,0,16,6,20,12,37,10,9,10,0,15,6,21,7,12,52,12,28,10,7,10,28,37,4,20,10,8,11,28,37,12,11,5,22,9,12,11,11,11,4,25,5,31,11,0,1,11,10,1,7,8,39,10,0,16,1,16,7,20,6,0,0,0,0,0,0,0,0,36,4,43,6,20,0,0,0,0,0,0,0,10,0,15,1,15,7,21,10,0,15,8,56,12,12,40,13,3,11,40,56,13,1,10,0,15,9,56,12,12,39,13,4,11,39,56,13,1,11,5,10,0,16,10,20,22,12,5,6,0,0,0,0,0,0,0,0,10,0,15,10,21,11,6,10,0,16,11,20,22,12,6,6,0,0,0,0,0,0,0,0,10,0,15,11,21,10,0,16,0,17,130,1,12,54,10,0,16,12,17,84,12,44,10,44,11,54,22,12,52,14,3,56,14,12,43,14,4,56,14,12,29,10,10,46,17,66,10,0,16,1,16,7,20,38,4,116,11,9,11,37,10,0,16,1,16,13,20,22,38,12,20,5,118,9,12,20,11,20,4,125,10,0,15,14,17,80,12,21,5,127,56,1,12,21,11,21,12,41,14,41,56,14,12,42,13,4,11,41,56,13,1,11,52,53,12,53,10,29,53,12,30,11,44,53,11,30,24,11,53,26,12,48,13,4,10,48,52,56,15,12,47,11,48,11,7,53,24,7,12,26,12,46,13,47,10,46,52,56,15,12,45,10,0,16,15,20,6,1,0,0,0,0,0,0,0,22,10,0,15,15,21,11,1,10,0,16,15,20,33,4,181,1,5,187,1,11,0,1,11,10,1,7,11,39,14,4,56,14,12,32,14,47,56,14,12,50,10,0,15,0,13,4,13,47,10,0,15,5,11,8,10,0,16,1,16,16,20,10,0,16,1,16,17,20,10,0,16,1,16,18,20,11,10,17,112,10,0,16,0,17,130,1,12,36,14,4,56,14,12,31,14,47,56,14,12,49,11,32,11,31,23,12,33,11,50,11,49,23,12,51,11,2,10,0,15,19,21,10,0,16,0,17,114,10,0,15,20,21,11,47,12,34,13,34,11,4,56,13,1,14,34,56,14,12,35,10,0,15,12,11,3,11,45,11,34,10,5,11,6,17,82,12,38,10,0,16,15,20,12,22,10,0,16,19,20,12,23,10,0,16,20,20,12,24,11,36,12,25,11,43,12,26,11,46,52,12,27,11,5,12,12,10,0,16,12,17,84,12,13,11,42,12,14,11,29,12,15,11,33,11,51,22,12,16,11,35,12,17,11,22,11,23,11,24,11,25,11,27,11,26,11,12,11,13,11,14,11,15,11,16,11,17,18,4,56,16,9,10,0,15,21,21,10,0,16,10,20,6,0,0,0,0,0,0,0,0,33,4,198,2,10,0,16,8,56,14,6,0,0,0,0,0,0,0,0,33,12,18,5,200,2,9,12,18,11,18,4,209,2,11,0,16,9,56,14,6,0,0,0,0,0,0,0,0,33,12,19,5,213,2,11,0,1,9,12,19,11,19,4,216,2,5,218,2,7,10,39,11,38,2,38,3,0,0,6,4,11,0,16,15,20,2,39,3,0,0,6,4,11,0,16,19,20,2,40,3,0,0,6,4,11,0,16,22,20,2,41,3,0,0,6,2,7,3,2,42,3,0,0,6,4,11,0,16,6,20,2,43,3,0,0,6,5,11,0,16,0,11,1,17,132,1,2,44,3,0,0,6,5,11,0,16,0,11,1,17,131,1,2,45,3,0,0,6,4,11,0,16,0,17,129,1,2,46,3,0,0,25,18,10,0,16,5,14,1,56,3,4,12,11,0,16,5,14,1,56,17,20,12,2,5,16,11,0,1,56,18,12,2,11,2,2,47,3,0,0,6,4,11,0,16,12,17,84,2,48,3,0,0,6,4,11,0,16,12,17,85,2,49,3,0,0,6,5,11,0,15,0,11,1,17,121,2,50,3,0,0,6,4,11,0,16,0,17,110,2,51,0,0,0,95,45,13,0,69,96,12,6,13,6,11,0,56,19,11,6,56,2,12,7,14,1,56,20,4,39,11,1,56,21,12,4,13,7,11,4,56,15,12,5,14,7,56,14,6,0,0,0,0,0,0,0,0,36,4,32,11,7,10,2,56,22,11,2,46,17,67,56,23,5,36,11,2,1,11,7,56,24,11,5,12,3,5,43,11,2,1,11,7,12,3,11,3,2,3,3,3,5,1,3,1,4,1,2,3,7,3,14,1,1,3,10,3,11,3,12,3,13,3,4,1,0,3,8,3,0,1,5,1,6,1,7,3,1,3,6,3,9,3,2,0,45,0,114,0],"validator":[161,28,235,11,6,0,0,0,12,1,0,33,2,33,72,3,105,197,4,4,174,5,40,5,214,5,131,4,7,217,9,247,19,8,208,29,96,6,176,30,190,1,10,238,31,156,1,12,138,33,237,27,13,247,60,60,15,179,61,13,0,137,1,1,20,1,23,1,74,1,105,2,21,2,22,2,34,2,72,2,106,2,113,2,114,2,134,1,0,103,0,139,1,0,14,4,0,0,13,4,0,0,8,3,0,0,11,3,0,1,9,7,0,3,3,7,1,0,0,4,9,7,0,5,0,12,0,6,1,4,1,0,1,8,2,7,0,9,5,2,0,11,10,2,0,12,12,7,0,13,4,7,0,13,6,12,0,13,7,12,0,14,15,2,0,0,56,0,1,0,0,54,2,3,0,0,26,4,5,0,0,16,4,5,0,0,18,6,5,0,0,88,7,8,0,0,89,7,5,0,0,92,9,10,0,0,91,11,5,0,0,96,11,5,0,0,90,4,5,0,0,95,4,5,0,0,29,12,5,0,0,83,13,5,0,0,47,14,15,0,0,49,14,16,0,0,107,14,17,0,0,50,14,18,0,0,30,14,18,0,0,42,14,19,0,0,84,14,19,0,0,52,14,18,0,0,75,14,18,0,0,80,14,18,0,0,145,1,14,18,0,0,86,14,20,0,0,85,14,20,0,0,53,14,20,0,0,146,1,14,20,0,0,62,14,21,0,0,64,14,21,0,0,65,14,21,0,0,69,14,21,0,0,67,14,22,0,0,66,14,22,0,0,63,14,22,0,0,70,14,22,0,0,73,14,23,0,0,60,14,24,0,0,112,14,24,0,0,100,14,24,0,0,111,14,24,0,0,144,1,14,24,0,0,97,4,5,0,0,76,14,24,0,0,77,14,24,0,0,38,14,24,0,0,25,14,24,0,0,79,25,26,0,0,104,14,27,0,0,43,28,15,0,0,45,29,15,1,0,0,44,30,15,1,0,0,58,13,5,0,0,125,31,5,0,0,123,31,5,0,0,124,31,5,0,0,133,1,31,5,0,0,126,31,5,0,0,116,31,5,0,0,128,1,31,5,0,0,118,31,5,0,0,129,1,31,5,0,0,119,31,5,0,0,131,1,31,5,0,0,121,31,5,0,0,130,1,32,5,0,0,120,32,5,0,0,127,31,5,0,0,117,31,5,0,0,132,1,31,5,0,0,122,31,5,0,0,31,6,5,0,0,135,1,16,5,0,0,136,1,33,5,0,0,40,14,34,0,0,55,35,3,0,1,105,33,41,0,2,110,65,33,1,0,3,24,67,65,1,0,3,36,70,53,1,0,3,46,67,15,1,0,3,48,67,15,1,0,3,71,5,37,1,0,3,98,53,37,1,0,4,37,41,38,0,5,54,43,44,0,6,142,1,48,24,1,0,7,32,53,5,1,3,8,41,65,27,1,8,10,87,54,5,1,12,11,33,49,24,0,11,94,49,17,0,12,57,33,42,0,13,17,45,5,0,13,27,45,5,0,13,28,61,5,0,13,47,34,15,0,13,54,43,64,0,13,76,34,24,0,13,77,34,24,0,13,79,63,26,0,13,82,51,5,0,13,83,62,5,0,13,88,50,8,0,13,92,57,10,0,13,99,56,24,0,13,101,56,24,0,13,108,34,24,0,14,58,69,27,0,14,143,1,59,60,0,83,33,83,38,87,47,88,52,90,8,88,58,89,64,52,38,52,33,51,38,51,33,81,53,79,53,84,38,84,33,82,38,80,38,82,33,80,33,78,1,14,5,10,2,10,2,10,2,10,2,8,6,8,6,8,12,8,12,8,6,8,6,8,6,8,6,8,7,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,11,1,8,1,2,7,8,1,3,0,1,7,8,1,4,7,8,1,11,8,1,8,10,5,7,8,11,1,8,14,3,7,8,1,8,14,7,8,11,1,11,8,1,8,10,3,7,8,1,8,16,3,2,7,8,1,11,8,1,8,10,2,7,8,1,7,8,11,1,6,8,1,1,1,1,6,8,0,1,5,1,6,8,6,1,6,8,12,1,6,10,2,1,6,11,5,1,8,6,1,6,11,5,1,10,2,1,6,8,9,1,3,2,6,8,1,3,1,8,13,1,8,9,2,6,8,1,6,8,1,2,6,11,5,1,9,0,6,9,0,2,6,11,5,1,9,0,6,11,5,1,9,0,2,7,8,1,10,2,3,7,8,1,10,2,10,2,1,10,2,1,6,8,15,4,8,0,3,3,7,8,11,22,5,8,6,8,6,8,6,8,6,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,8,6,11,5,1,8,6,10,2,11,5,1,8,6,11,5,1,8,6,8,7,10,2,10,2,10,2,8,6,8,6,8,12,8,12,1,11,5,1,9,0,1,8,6,8,1,1,1,1,1,1,1,8,0,1,2,1,8,4,1,8,12,1,7,8,11,1,8,7,2,7,8,15,3,3,3,3,8,14,1,8,10,1,6,11,8,1,9,0,1,6,8,11,4,7,8,15,11,8,1,8,10,3,7,8,11,1,7,8,15,1,8,2,1,9,0,2,9,0,5,5,3,3,3,3,11,8,1,8,10,1,6,8,14,3,7,8,15,8,14,7,8,11,1,8,3,1,6,8,16,1,6,5,2,7,8,15,11,8,1,8,10,2,7,8,15,7,8,11,2,6,8,15,3,1,8,15,1,6,9,0,29,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,6,11,5,1,9,0,2,1,1,2,5,7,8,11,1,7,11,5,1,9,0,3,8,9,8,15,5,3,66,97,103,7,66,97,108,97,110,99,101,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,19,83,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,21,85,110,115,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,3,85,114,108,9,86,97,108,105,100,97,116,111,114,17,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,8,97,99,116,105,118,97,116,101,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,6,97,109,111,117,110,116,5,97,115,99,105,105,3,98,97,103,7,98,97,108,97,110,99,101,3,98,99,115,6,98,111,114,114,111,119,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,10,100,101,97,99,116,105,118,97,116,101,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,11,100,101,115,99,114,105,112,116,105,111,110,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,5,101,112,111,99,104,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,10,102,114,111,109,95,97,115,99,105,105,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,20,103,101,116,95,115,116,97,107,105,110,103,95,112,111,111,108,95,114,101,102,2,105,100,9,105,109,97,103,101,95,117,114,108,12,105,115,95,100,117,112,108,105,99,97,116,101,13,105,115,95,101,113,117,97,108,95,115,111,109,101,23,105,115,95,101,113,117,97,108,95,115,111,109,101,95,97,110,100,95,118,97,108,117,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,8,109,101,116,97,100,97,116,97,4,110,97,109,101,11,110,101,116,95,97,100,100,114,101,115,115,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,20,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,102,114,111,109,95,109,101,116,97,100,97,116,97,12,110,101,119,95,109,101,116,97,100,97,116,97,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,20,110,101,120,116,95,101,112,111,99,104,95,103,97,115,95,112,114,105,99,101,22,110,101,120,116,95,101,112,111,99,104,95,110,101,116,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,22,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,32,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,16,110,101,120,116,95,101,112,111,99,104,95,115,116,97,107,101,25,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,7,112,111,111,108,95,105,100,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,16,112,114,105,110,99,105,112,97,108,95,97,109,111,117,110,116,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,21,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,13,114,101,119,97,114,100,95,97,109,111,117,110,116,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,111,109,101,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,12,115,116,97,107,101,95,97,109,111,117,110,116,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,14,115,116,97,107,101,114,95,97,100,100,114,101,115,115,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,6,115,116,114,105,110,103,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,11,115,117,105,95,98,97,108,97,110,99,101,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,111,95,98,121,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,15,117,110,115,116,97,107,105,110,103,95,101,112,111,99,104,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,3,117,114,108,17,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,21,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,95,98,99,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,12,118,111,116,105,110,103,95,112,111,119,101,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,19,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,100,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,3,8,102,0,0,0,0,0,0,0,3,8,208,7,0,0,0,0,0,0,3,8,0,1,0,0,0,0,0,0,3,8,160,134,1,0,0,0,0,0,0,2,22,107,5,86,10,2,53,10,2,146,1,10,2,85,10,2,50,8,6,30,8,6,42,8,12,84,8,12,51,8,6,75,8,6,80,8,6,145,1,8,6,67,11,5,1,10,2,66,11,5,1,10,2,63,11,5,1,10,2,70,11,5,1,10,2,61,11,5,1,8,6,64,11,5,1,8,6,65,11,5,1,8,6,69,11,5,1,8,6,35,8,7,1,2,10,49,8,0,144,1,3,73,8,9,38,3,103,8,15,25,3,68,3,60,3,59,3,35,8,7,2,2,5,78,8,9,138,1,5,102,5,33,3,19,3,3,2,7,78,8,9,138,1,5,102,5,99,3,115,3,81,3,93,3,0,3,0,0,36,68,11,0,12,14,11,1,12,25,11,2,12,29,11,3,12,30,11,4,12,31,11,5,12,32,11,6,12,33,11,7,12,34,11,8,12,35,11,9,12,15,11,10,12,16,11,11,12,17,11,12,12,18,56,0,12,19,56,0,12,20,56,0,12,21,56,0,12,22,56,1,12,23,56,1,12,24,56,1,12,26,56,1,12,27,11,13,12,28,11,14,11,25,11,29,11,30,11,31,11,32,11,33,11,34,11,35,11,15,11,16,11,17,11,18,11,19,11,22,11,20,11,21,11,23,11,24,11,26,11,27,11,28,18,0,2,1,3,0,0,39,137,1,14,9,65,40,7,17,37,4,11,14,10,65,40,7,17,37,12,16,5,13,9,12,16,11,16,4,21,14,11,65,40,7,17,37,12,17,5,23,9,12,17,11,17,4,31,14,12,65,40,7,17,37,12,18,5,33,9,12,18,11,18,4,41,14,5,65,40,7,17,37,12,19,5,43,9,12,19,11,19,4,51,14,6,65,40,7,17,37,12,20,5,53,9,12,20,11,20,4,61,14,7,65,40,7,17,37,12,21,5,63,9,12,21,11,21,4,71,14,8,65,40,7,17,37,12,22,5,73,9,12,22,11,22,4,76,5,80,11,15,1,7,9,39,10,14,7,16,37,4,85,5,89,11,15,1,7,8,39,10,13,7,18,35,4,94,5,98,11,15,1,7,15,39,11,0,11,1,11,2,11,3,11,4,11,5,17,77,17,85,11,6,17,77,17,85,11,7,17,93,11,8,17,93,11,9,17,77,17,85,11,10,17,77,17,85,11,11,17,77,17,85,11,12,17,77,17,85,10,15,17,86,17,0,12,23,14,23,17,73,11,23,11,13,11,14,11,15,17,76,2,2,3,0,0,5,5,11,0,15,0,11,1,17,95,2,3,3,0,0,5,5,11,0,15,0,11,1,17,94,2,4,3,0,0,5,13,10,0,16,1,20,10,0,15,2,21,10,0,16,3,20,11,0,15,4,21,2,5,3,0,0,46,58,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,8,5,14,11,0,1,11,3,1,7,11,39,10,3,46,17,91,6,1,0,0,0,0,0,0,0,22,12,5,10,0,15,0,11,1,11,5,10,3,17,104,12,6,10,0,16,0,17,97,4,34,10,0,15,0,17,102,10,0,16,5,20,10,4,22,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,11,2,11,3,46,17,91,11,4,18,2,56,3,11,6,2,6,3,0,0,24,47,10,3,46,17,91,6,0,0,0,0,0,0,0,0,33,4,7,5,13,11,0,1,11,3,1,7,12,39,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,21,5,27,11,0,1,11,3,1,7,11,39,10,0,15,0,11,1,6,0,0,0,0,0,0,0,0,11,3,17,104,11,2,56,4,10,0,15,0,17,102,10,0,16,5,20,11,4,22,11,0,15,5,21,2,7,3,0,0,55,47,14,1,17,107,12,3,14,1,17,106,12,5,10,0,15,0,11,1,10,2,17,105,12,7,14,7,56,2,12,6,10,6,10,3,23,12,4,10,0,16,5,20,11,6,23,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,10,2,46,17,92,11,5,11,2,46,17,91,11,3,11,4,18,3,56,5,11,7,2,8,3,0,0,5,28,10,2,7,18,35,4,5,5,9,11,0,1,7,15,39,14,1,17,110,20,10,0,16,6,16,7,20,33,4,19,5,23,11,0,1,7,14,39,11,2,11,0,15,1,21,2,9,3,0,0,5,41,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,2,7,18,35,4,14,5,18,11,0,1,7,15,39,14,1,17,110,20,10,0,16,6,16,7,20,33,4,28,5,32,11,0,1,7,14,39,10,2,10,0,15,1,21,11,2,11,0,15,2,21,2,10,3,0,0,5,14,10,1,7,16,37,4,5,5,9,11,0,1,7,8,39,11,1,11,0,15,3,21,2,11,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,1,7,16,37,4,14,5,18,11,0,1,7,8,39,11,1,11,0,15,4,21,2,12,3,0,0,5,14,10,0,16,5,20,14,1,56,2,22,10,0,15,5,21,11,0,15,0,11,1,17,96,2,13,3,0,0,5,16,10,0,15,0,11,1,17,103,10,0,46,17,40,11,0,16,5,20,33,4,13,5,15,7,11,39,2,14,1,0,0,5,4,11,0,16,0,17,97,2,15,1,0,0,5,3,11,0,16,6,2,16,1,0,0,5,5,11,0,16,6,16,7,20,2,17,1,0,0,5,4,11,0,16,6,16,8,2,18,1,0,0,5,4,11,0,16,6,16,9,2,19,1,0,0,5,4,11,0,16,6,16,10,2,20,1,0,0,5,4,11,0,16,6,16,11,2,21,1,0,0,5,4,11,0,16,6,16,12,2,22,1,0,0,5,4,11,0,16,6,16,13,2,23,1,0,0,5,4,11,0,16,6,16,14,2,24,1,0,0,5,4,11,0,16,6,16,15,2,25,1,0,0,5,4,11,0,16,6,16,16,2,26,1,0,0,5,4,11,0,16,6,16,17,2,27,1,0,0,5,4,11,0,16,6,16,18,2,28,1,0,0,5,4,11,0,16,6,16,19,2,29,1,0,0,5,4,11,0,16,6,16,20,2,30,1,0,0,5,4,11,0,16,6,16,21,2,31,1,0,0,5,4,11,0,16,6,16,22,2,32,1,0,0,5,4,11,0,16,6,16,23,2,33,1,0,0,5,4,11,0,16,6,16,24,2,34,1,0,0,5,4,11,0,16,6,16,25,2,35,1,0,0,5,4,11,0,16,6,16,26,2,36,1,0,0,5,4,11,0,16,6,16,27,2,37,1,0,0,5,3,11,0,16,28,2,38,1,0,0,5,4,11,0,16,1,20,2,39,1,0,0,5,5,40,11,0,16,0,17,108,2,40,1,0,0,5,4,11,0,16,0,17,108,2,41,1,0,0,5,3,11,0,17,40,2,42,1,0,0,5,4,11,0,16,29,20,2,43,3,0,0,5,5,11,1,11,0,15,29,21,2,44,1,0,0,5,4,11,0,16,0,17,99,2,45,1,0,0,5,4,11,0,16,0,17,100,2,46,1,0,0,5,4,11,0,16,2,20,2,47,1,0,0,5,4,11,0,16,4,20,2,48,1,0,0,5,5,11,0,16,0,11,1,17,101,2,49,1,0,0,5,4,11,0,16,0,56,6,2,50,1,0,0,66,151,3,10,0,16,6,16,7,20,10,1,16,6,16,7,20,33,4,13,8,12,2,5,23,10,0,16,6,16,8,20,10,1,16,6,16,8,20,33,12,2,11,2,4,28,8,12,13,5,38,10,0,16,6,16,12,20,10,1,16,6,16,12,20,33,12,13,11,13,4,43,8,12,24,5,53,10,0,16,6,16,13,20,10,1,16,6,16,13,20,33,12,24,11,24,4,58,8,12,25,5,68,10,0,16,6,16,16,20,10,1,16,6,16,16,20,33,12,25,11,25,4,73,8,12,26,5,83,10,0,16,6,16,18,20,10,1,16,6,16,18,20,33,12,26,11,26,4,88,8,12,27,5,98,10,0,16,6,16,18,20,10,1,16,6,16,19,20,33,12,27,11,27,4,103,8,12,28,5,113,10,0,16,6,16,19,20,10,1,16,6,16,19,20,33,12,28,11,28,4,118,8,12,29,5,128,1,10,0,16,6,16,19,20,10,1,16,6,16,18,20,33,12,29,11,29,4,133,1,8,12,30,5,141,1,10,0,16,6,16,20,10,1,16,6,16,20,56,7,12,30,11,30,4,146,1,8,12,3,5,154,1,10,0,16,6,16,21,10,1,16,6,16,21,56,7,12,3,11,3,4,159,1,8,12,4,5,167,1,10,0,16,6,16,24,10,1,16,6,16,24,56,8,12,4,11,4,4,172,1,8,12,5,5,180,1,10,0,16,6,16,26,10,1,16,6,16,26,56,8,12,5,11,5,4,185,1,8,12,6,5,193,1,10,0,16,6,16,26,10,1,16,6,16,27,56,8,12,6,11,6,4,198,1,8,12,7,5,206,1,10,0,16,6,16,27,10,1,16,6,16,27,56,8,12,7,11,7,4,211,1,8,12,8,5,219,1,10,0,16,6,16,27,10,1,16,6,16,26,56,8,12,8,11,8,4,224,1,8,12,9,5,232,1,10,0,16,6,16,20,10,1,16,6,16,12,56,9,12,9,11,9,4,237,1,8,12,10,5,245,1,10,0,16,6,16,21,10,1,16,6,16,13,56,9,12,10,11,10,4,250,1,8,12,11,5,130,2,10,0,16,6,16,24,10,1,16,6,16,16,56,10,12,11,11,11,4,135,2,8,12,12,5,143,2,10,0,16,6,16,26,10,1,16,6,16,18,56,10,12,12,11,12,4,148,2,8,12,14,5,156,2,10,0,16,6,16,26,10,1,16,6,16,19,56,10,12,14,11,14,4,161,2,8,12,15,5,169,2,10,0,16,6,16,27,10,1,16,6,16,19,56,10,12,15,11,15,4,174,2,8,12,16,5,182,2,10,0,16,6,16,27,10,1,16,6,16,18,56,10,12,16,11,16,4,187,2,8,12,17,5,195,2,10,1,16,6,16,20,10,0,16,6,16,12,56,9,12,17,11,17,4,200,2,8,12,18,5,208,2,10,1,16,6,16,21,10,0,16,6,16,13,56,9,12,18,11,18,4,213,2,8,12,19,5,221,2,10,1,16,6,16,24,10,0,16,6,16,16,56,10,12,19,11,19,4,226,2,8,12,20,5,234,2,10,1,16,6,16,26,10,0,16,6,16,18,56,10,12,20,11,20,4,239,2,8,12,21,5,247,2,10,1,16,6,16,26,10,0,16,6,16,19,56,10,12,21,11,21,4,252,2,8,12,22,5,132,3,10,1,16,6,16,27,10,0,16,6,16,19,56,10,12,22,11,22,4,141,3,11,0,1,11,1,1,8,12,23,5,149,3,11,1,16,6,16,27,11,0,16,6,16,18,56,10,12,23,11,23,2,51,0,0,0,15,17,10,0,56,11,4,10,11,1,1,11,0,1,9,12,2,5,15,11,0,56,12,11,1,33,12,2,11,2,2,52,0,0,0,68,26,10,0,56,11,4,6,8,12,2,5,9,10,1,56,11,12,2,11,2,4,18,11,1,1,11,0,1,9,12,3,5,24,11,0,56,12,11,1,56,12,33,12,3,11,3,2,53,3,0,0,17,25,10,1,46,17,92,12,2,10,2,10,0,16,6,16,7,20,33,4,12,5,18,11,0,1,11,1,1,7,13,39,11,2,11,1,17,109,11,0,15,28,21,2,54,3,0,0,5,18,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,11,0,15,6,15,8,21,2,55,3,0,0,5,18,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,11,0,15,6,15,9,21,2,56,3,0,0,5,17,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,93,11,0,15,6,15,10,21,2,57,3,0,0,5,17,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,93,11,0,15,6,15,11,21,2,58,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,20,21,11,0,16,6,17,73,2,59,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,12,21,11,0,16,6,17,73,2,60,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,21,21,11,0,16,6,17,73,2,61,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,13,21,11,0,16,6,17,73,2,62,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,22,21,11,0,16,6,17,73,2,63,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,14,21,11,0,16,6,17,73,2,64,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,23,21,11,0,16,6,17,73,2,65,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,15,21,11,0,16,6,17,73,2,66,3,0,0,5,16,11,1,56,14,10,0,15,6,15,24,21,11,2,56,14,10,0,15,6,15,25,21,11,0,16,6,17,73,2,67,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,16,21,11,2,10,0,15,6,15,17,21,11,0,16,6,17,73,2,68,3,0,0,5,10,11,1,56,14,10,0,15,6,15,26,21,11,0,16,6,17,73,2,69,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,18,21,11,0,16,6,17,73,2,70,3,0,0,5,10,11,1,56,14,10,0,15,6,15,27,21,11,0,16,6,17,73,2,71,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,19,21,11,0,16,6,17,73,2,72,3,0,0,5,143,1,10,0,46,17,29,56,15,4,18,10,0,15,6,15,20,56,16,10,0,15,6,15,12,21,56,1,10,0,15,6,15,20,21,10,0,46,17,30,56,15,4,36,10,0,15,6,15,21,56,16,10,0,15,6,15,13,21,56,1,10,0,15,6,15,21,21,10,0,46,17,31,56,15,4,54,10,0,15,6,15,22,56,16,10,0,15,6,15,14,21,56,1,10,0,15,6,15,22,21,10,0,46,17,32,56,15,4,72,10,0,15,6,15,23,56,16,10,0,15,6,15,15,21,56,1,10,0,15,6,15,23,21,10,0,46,17,33,56,17,4,103,10,0,15,6,15,24,56,18,10,0,15,6,15,16,21,56,0,10,0,15,6,15,24,21,10,0,15,6,15,25,56,18,10,0,15,6,15,17,21,56,0,10,0,15,6,15,25,21,10,0,46,17,35,56,17,4,121,10,0,15,6,15,26,56,18,10,0,15,6,15,18,21,56,0,10,0,15,6,15,26,21,10,0,46,17,36,56,17,4,140,1,10,0,15,6,15,27,56,18,10,0,15,6,15,19,21,56,0,11,0,15,6,15,27,21,5,142,1,11,0,1,2,73,1,0,0,5,4,11,0,56,19,17,74,2,74,1,2,0,75,3,0,0,5,3,11,0,16,0,2,76,0,0,0,71,24,14,0,16,7,20,12,6,10,3,17,98,12,5,11,6,10,3,17,109,12,4,11,0,6,0,0,0,0,0,0,0,0,11,4,10,1,11,5,10,2,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,17,86,18,1,2,1,4,1,7,1,3,1,8,1,5,1,6,1,0,0,0,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,1,0,4,0,2,0,3,0,17,0,18,0,19,0,20,0,13,0,14,0,15,0,16,1,2,1,1,0,39,0,109,0,140,1,0,141,1,0,144,1,0],"validator_cap":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,20,3,28,42,4,70,4,5,74,54,7,128,1,226,2,8,226,3,64,6,162,4,34,10,196,4,13,12,209,4,112,13,193,5,4,15,197,5,6,0,18,1,10,1,14,1,15,0,3,12,0,0,4,2,0,1,0,7,0,1,2,4,0,3,1,2,0,0,16,0,1,0,0,20,2,1,0,0,9,3,4,0,0,8,0,5,0,1,6,13,4,1,8,1,7,10,11,0,2,11,14,6,1,12,3,12,8,9,0,4,12,6,12,1,6,8,0,1,6,5,1,6,8,1,2,5,7,8,4,1,8,2,1,8,1,0,4,1,8,0,8,2,5,1,6,8,4,1,5,1,7,8,4,1,8,3,1,8,0,1,6,9,0,2,9,0,5,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,28,97,117,116,104,111,114,105,122,101,114,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,6,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,3,5,5,1,2,1,5,5,0,3,0,0,6,3,11,0,16,0,2,1,3,0,0,6,3,11,0,16,1,2,2,3,0,0,7,35,10,1,46,17,7,12,5,10,5,7,0,33,4,11,8,12,2,5,15,11,5,10,0,33,12,2,11,2,4,18,5,22,11,1,1,6,0,0,0,0,0,0,0,0,39,11,1,17,5,10,0,18,0,12,3,14,3,56,0,12,4,11,3,11,0,56,1,11,4,2,3,3,0,0,6,5,11,0,16,0,20,18,1,2,0,1,1,0,0,13,0,17,0,19,0],"validator_set":[161,28,235,11,6,0,0,0,12,1,0,54,2,54,116,3,170,1,173,6,4,215,7,137,1,5,224,8,136,10,7,232,18,175,24,8,151,43,96,6,247,43,195,1,10,186,45,141,1,12,199,46,159,36,13,230,82,16,15,246,82,5,0,166,1,1,107,1,174,1,2,32,2,33,2,59,2,105,2,118,2,147,1,2,151,1,2,152,1,2,158,1,2,159,1,2,172,1,2,173,1,0,143,1,0,162,1,0,165,1,0,170,1,0,177,1,0,20,4,0,0,15,3,0,0,16,3,0,0,17,3,0,0,18,3,0,1,4,7,1,0,0,3,0,12,0,4,1,4,1,0,1,6,3,7,0,7,2,6,1,2,0,7,6,6,1,2,0,8,7,2,0,9,10,12,2,7,1,4,1,10,11,4,1,4,1,12,12,2,0,13,22,7,2,1,0,0,0,14,23,7,1,3,0,15,5,7,0,15,8,12,0,15,9,12,0,16,14,4,0,17,13,12,0,17,19,2,0,18,21,4,0,0,100,0,1,0,0,130,1,2,3,0,0,132,1,4,3,0,0,129,1,5,3,0,0,30,6,3,0,0,131,1,4,3,0,0,128,1,7,8,0,0,134,1,9,10,0,0,133,1,11,3,0,0,29,12,3,0,0,161,1,13,3,0,0,54,14,3,0,0,49,15,16,0,0,155,1,15,16,0,0,169,1,17,16,0,0,167,1,17,16,0,0,168,1,17,18,0,0,145,1,15,19,0,0,110,20,21,0,0,103,15,16,0,0,85,17,22,0,0,88,6,22,0,0,87,23,22,0,0,45,23,16,0,0,89,6,22,0,0,44,24,16,0,0,71,25,26,0,0,63,27,28,0,0,64,29,28,0,0,75,30,31,0,0,76,32,26,0,0,68,33,26,0,0,79,34,26,0,0,77,35,26,0,0,78,35,26,0,0,80,27,36,0,0,69,37,36,0,0,70,17,36,0,0,73,17,36,0,0,176,1,38,39,0,0,119,40,3,0,0,122,41,3,0,0,37,42,3,0,0,121,43,3,0,0,139,1,44,3,0,0,120,45,3,0,0,36,46,16,0,0,28,47,3,0,0,40,48,49,0,0,41,50,51,0,0,42,52,53,0,0,39,54,53,0,0,53,55,3,0,0,56,56,3,0,0,150,1,30,16,0,0,26,15,46,0,0,94,17,22,0,0,91,57,22,0,0,25,15,51,0,1,51,118,85,1,0,1,62,84,85,1,0,1,93,83,22,1,0,1,104,3,118,1,0,1,138,1,85,118,1,0,2,43,86,22,1,0,2,90,132,1,22,1,0,2,127,102,85,1,0,3,100,60,70,0,4,52,155,1,3,1,0,4,96,156,1,16,1,0,4,140,1,154,1,155,1,1,0,4,171,1,88,16,1,0,5,55,85,3,1,3,6,81,117,18,1,8,7,100,108,109,1,2,7,101,106,107,1,2,7,117,110,106,1,2,9,27,64,3,2,7,4,9,34,72,92,2,7,4,9,35,77,93,2,7,4,9,43,72,22,2,7,4,9,100,60,61,2,7,4,9,127,77,78,2,7,4,10,34,116,117,1,4,10,35,121,122,1,4,10,57,60,65,1,4,10,90,113,22,1,4,10,98,113,16,1,4,10,116,142,1,85,1,4,10,124,81,3,1,4,11,123,157,1,3,1,12,12,58,76,16,0,12,135,1,76,63,0,13,43,98,22,2,1,0,13,57,3,69,2,1,0,13,67,98,92,2,1,0,13,72,99,93,2,1,0,13,83,101,3,2,1,0,13,90,137,1,22,2,1,0,13,97,137,1,138,1,2,1,0,13,115,149,1,100,2,1,0,13,127,99,100,2,1,0,13,137,1,137,1,16,2,1,0,14,43,139,1,22,1,3,14,84,150,1,138,1,1,3,14,90,141,1,22,1,3,14,127,140,1,3,1,3,15,60,112,21,0,15,111,91,18,0,16,24,79,3,0,16,28,26,3,0,16,38,36,16,0,16,47,79,3,0,16,48,158,1,3,0,16,54,26,3,0,16,65,36,16,0,16,74,36,112,0,16,86,115,22,0,16,92,36,22,0,16,106,36,130,1,0,16,114,160,1,161,1,0,16,120,145,1,3,0,16,128,1,89,8,0,16,133,1,79,3,0,16,134,1,95,10,0,16,142,1,36,16,0,16,144,1,36,18,0,16,148,1,36,63,0,16,156,1,36,16,0,16,177,1,36,16,0,17,102,128,1,39,0,17,160,1,128,1,124,0,17,175,1,123,124,0,18,46,73,74,0,18,50,74,62,0,18,99,94,26,0,19,125,3,16,0,19,136,1,47,3,0,19,157,1,3,16,0,81,59,77,59,85,62,81,66,81,67,94,68,80,67,77,67,82,67,82,59,77,66,89,62,61,16,60,16,64,16,71,87,80,59,78,59,80,66,79,66,93,68,101,68,96,68,97,68,66,62,75,16,74,16,76,16,87,62,83,62,79,67,63,16,62,16,59,16,84,62,73,129,1,65,16,72,134,1,93,136,1,101,136,1,99,136,1,96,136,1,103,63,106,63,105,63,86,62,88,62,72,143,1,94,103,97,103,98,136,1,100,136,1,104,63,102,103,93,103,95,103,70,87,69,87,90,8,68,87,95,136,1,64,63,72,162,1,2,10,8,20,7,8,14,1,8,0,3,7,8,0,8,20,7,8,14,0,2,7,8,0,7,8,14,3,7,8,0,3,7,8,14,2,6,8,0,6,8,20,4,7,8,0,5,11,7,1,8,11,7,8,14,1,8,18,3,7,8,0,8,18,7,8,14,1,11,7,1,8,11,3,7,8,0,3,6,8,14,9,7,8,0,7,11,7,1,8,11,7,11,7,1,8,11,7,11,15,2,5,11,16,1,5,3,3,3,3,7,8,14,6,7,8,0,3,3,3,7,11,15,2,5,11,16,1,5,7,8,14,1,7,8,0,1,6,8,0,1,3,2,6,8,0,5,1,8,8,1,6,11,12,2,8,8,5,2,7,8,0,6,8,8,1,6,11,12,2,3,8,17,1,1,2,6,10,8,20,6,8,20,2,6,11,13,1,8,20,6,8,20,2,7,8,0,5,1,7,8,20,2,6,10,8,20,5,1,11,5,1,3,2,6,11,13,1,8,20,5,2,6,10,8,20,6,10,5,1,10,3,2,7,10,8,20,5,3,7,8,0,5,1,3,7,8,0,6,8,22,1,2,7,8,0,6,8,14,1,6,8,20,3,7,8,0,5,2,3,7,8,0,6,8,21,2,1,8,22,3,7,8,0,7,11,15,2,5,11,16,1,5,7,8,14,5,7,8,0,8,20,7,11,15,2,5,11,16,1,5,1,7,8,14,2,7,11,15,2,5,11,16,1,5,5,2,7,8,0,3,1,7,10,3,2,7,10,8,20,7,8,14,1,6,10,8,20,1,7,10,8,20,4,10,3,3,6,10,3,6,10,3,4,3,11,15,2,3,3,3,11,15,2,3,3,2,6,8,0,11,15,2,5,11,16,1,5,1,10,5,4,6,10,8,20,3,3,3,2,10,3,10,3,9,6,10,8,20,3,3,10,3,10,3,3,11,15,2,3,3,3,11,15,2,3,3,6,7,10,8,20,6,10,3,6,10,3,7,11,7,1,8,11,7,11,7,1,8,11,7,8,14,6,3,6,10,8,20,6,10,3,6,10,3,6,11,15,2,5,11,16,1,5,6,10,5,2,6,8,0,8,8,6,3,3,11,12,2,8,8,5,3,6,8,20,8,0,2,8,8,5,1,7,8,14,1,11,12,2,9,0,9,1,1,8,20,1,5,3,7,11,12,2,9,0,9,1,9,0,9,1,1,11,13,1,9,0,2,8,8,8,23,2,5,8,23,2,5,3,1,11,15,2,9,0,9,1,1,8,6,4,6,8,20,6,8,20,1,5,2,6,11,12,2,9,0,9,1,9,0,2,8,20,7,8,14,1,8,23,3,8,8,8,20,5,1,6,8,14,2,7,11,12,2,9,0,9,1,9,0,1,9,1,2,7,8,20,3,5,6,8,20,6,8,20,1,8,20,5,2,7,11,13,1,9,0,9,0,3,5,3,11,5,1,3,1,6,11,5,1,9,0,1,7,11,5,1,9,0,1,9,0,2,6,10,9,0,6,9,0,1,8,11,1,6,11,7,1,9,0,4,7,8,20,11,7,1,8,11,5,7,8,14,3,7,8,20,8,8,5,1,6,8,18,1,6,9,1,1,7,9,1,1,7,8,23,3,7,8,20,8,18,7,8,14,14,11,15,2,5,11,16,1,5,6,10,5,10,3,10,3,11,15,2,3,3,11,15,2,3,3,3,10,5,3,3,3,3,10,3,10,3,8,3,3,7,3,3,8,20,8,20,5,6,8,20,2,6,11,15,2,9,0,9,1,6,9,0,2,7,11,15,2,9,0,9,1,6,9,0,2,9,0,9,1,3,7,11,15,2,9,0,9,1,9,0,9,1,2,7,10,9,0,3,2,3,3,10,10,11,9,1,3,3,3,11,10,1,3,3,3,3,6,8,20,3,6,10,8,20,1,11,9,1,3,2,3,9,0,1,11,9,1,9,0,1,10,11,9,1,9,0,1,11,10,1,9,0,1,7,11,10,1,9,0,2,6,8,20,5,1,6,8,19,1,6,11,13,1,9,0,3,3,3,3,2,6,8,20,6,8,20,2,6,11,13,1,9,0,3,1,6,9,0,1,11,5,1,9,0,5,5,3,11,5,1,3,3,10,3,4,3,3,11,5,1,3,11,5,1,3,2,7,11,13,1,9,0,3,1,7,9,0,1,6,8,22,1,6,5,2,3,11,5,1,3,6,1,1,3,3,11,5,1,3,11,5,1,3,5,5,6,8,20,8,8,5,6,8,20,1,6,8,21,1,8,21,1,6,8,8,2,3,8,20,1,6,10,9,0,3,3,5,8,8,1,8,4,7,6,5,6,5,3,3,6,5,10,5,7,11,16,1,5,2,5,11,16,1,5,1,6,11,15,2,9,0,9,1,1,10,9,0,2,6,11,16,1,9,0,6,9,0,2,7,11,16,1,9,0,6,9,0,1,6,11,16,1,9,0,1,7,11,13,1,9,0,1,8,3,6,3,3,3,3,3,3,2,7,8,20,7,8,14,4,3,3,3,6,8,20,7,11,15,2,3,3,11,15,2,3,3,4,4,3,3,3,5,10,5,6,10,8,20,11,16,1,5,10,5,5,1,7,11,15,2,9,0,9,1,1,11,16,1,9,0,6,3,3,4,10,3,10,3,3,17,3,3,3,10,3,3,10,3,3,4,3,3,3,3,3,3,3,3,4,8,3,3,11,7,1,8,11,3,7,8,20,5,4,11,7,1,8,11,2,7,11,7,1,9,0,3,1,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,2,9,0,5,2,7,8,20,11,7,1,8,11,8,10,5,3,3,3,3,10,5,6,8,20,5,2,6,8,20,3,1,8,17,1,8,2,5,3,3,10,5,5,6,10,8,20,3,66,97,103,7,66,97,108,97,110,99,101,5,69,110,116,114,121,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,13,80,114,105,111,114,105,116,121,81,117,101,117,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,23,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,25,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,86,50,18,86,97,108,105,100,97,116,111,114,74,111,105,110,69,118,101,110,116,19,86,97,108,105,100,97,116,111,114,76,101,97,118,101,69,118,101,110,116,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,6,86,101,99,77,97,112,6,86,101,99,83,101,116,8,97,99,116,105,118,97,116,101,26,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,101,115,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,3,97,100,100,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,18,97,116,95,114,105,115,107,95,118,97,108,105,100,97,116,111,114,115,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,22,99,97,108,99,117,108,97,116,101,95,116,111,116,97,108,95,115,116,97,107,101,115,38,99,108,101,97,110,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,95,108,101,97,118,105,110,103,95,118,97,108,105,100,97,116,111,114,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,36,99,111,109,112,117,116,101,95,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,26,99,111,109,112,117,116,101,95,114,101,119,97,114,100,95,97,100,106,117,115,116,109,101,110,116,115,26,99,111,109,112,117,116,101,95,115,108,97,115,104,101,100,95,118,97,108,105,100,97,116,111,114,115,38,99,111,109,112,117,116,101,95,117,110,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,8,99,111,110,116,97,105,110,115,25,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,116,97,98,108,101,118,101,99,20,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,118,101,99,9,99,114,101,97,116,101,95,118,49,10,100,101,97,99,116,105,118,97,116,101,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,17,100,105,115,116,114,105,98,117,116,101,95,114,101,119,97,114,100,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,27,101,109,105,116,95,118,97,108,105,100,97,116,111,114,95,101,112,111,99,104,95,101,118,101,110,116,115,5,101,109,112,116,121,5,101,112,111,99,104,5,101,118,101,110,116,14,101,120,99,104,97,110,103,101,95,114,97,116,101,115,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,14,102,105,110,100,95,118,97,108,105,100,97,116,111,114,29,102,105,110,100,95,118,97,108,105,100,97,116,111,114,95,102,114,111,109,95,116,97,98,108,101,95,118,101,99,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,3,103,101,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,24,103,101,116,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,37,103,101,116,95,99,97,110,100,105,100,97,116,101,95,111,114,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,7,103,101,116,95,109,117,116,25,103,101,116,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,95,114,101,102,20,103,101,116,95,115,116,97,107,105,110,103,95,112,111,111,108,95,114,101,102,21,103,101,116,95,118,97,108,105,100,97,116,111,114,95,105,110,100,105,99,101,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,114,101,102,2,105,100,19,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,12,105,115,95,100,117,112,108,105,99,97,116,101,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,34,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,35,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,21,105,115,95,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,22,105,115,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,12,105,115,95,118,111,108,117,110,116,97,114,121,4,106,111,105,110,4,107,101,121,115,6,108,101,110,103,116,104,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,25,112,101,110,100,105,110,103,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,16,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,19,112,111,111,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,115,7,112,111,111,108,95,105,100,19,112,111,111,108,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,24,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,3,112,111,112,8,112,111,112,95,98,97,99,107,7,112,111,112,95,109,97,120,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,24,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,26,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,115,27,112,114,111,99,101,115,115,95,118,97,108,105,100,97,116,111,114,95,100,101,112,97,114,116,117,114,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,9,112,117,115,104,95,98,97,99,107,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,26,114,101,102,101,114,101,110,99,101,95,103,97,115,95,115,117,114,118,101,121,95,113,117,111,116,101,6,114,101,109,111,118,101,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,6,115,101,110,100,101,114,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,105,122,101,4,115,111,109,101,17,115,111,114,116,95,114,101,109,111,118,97,108,95,108,105,115,116,5,115,112,108,105,116,5,115,116,97,107,101,12,115,116,97,107,101,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,27,115,116,111,114,97,103,101,95,102,117,110,100,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,29,115,117,109,95,118,111,116,105,110,103,95,112,111,119,101,114,95,98,121,95,97,100,100,114,101,115,115,101,115,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,26,116,97,108,108,121,105,110,103,95,114,117,108,101,95,103,108,111,98,97,108,95,115,99,111,114,101,23,116,97,108,108,121,105,110,103,95,114,117,108,101,95,114,101,112,111,114,116,101,114,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,39,117,112,100,97,116,101,95,97,110,100,95,112,114,111,99,101,115,115,95,108,111,119,95,115,116,97,107,101,95,100,101,112,97,114,116,117,114,101,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,20,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,10,3,1,0,10,5,1,0,0,2,9,155,1,3,26,10,8,20,108,11,13,1,8,20,109,10,3,145,1,11,12,2,8,8,5,82,11,12,2,8,8,8,23,164,1,11,12,2,5,8,23,31,11,15,2,5,3,61,8,6,1,2,10,58,3,163,1,5,126,3,141,1,3,38,3,112,3,146,1,3,113,8,17,154,1,10,5,153,1,3,2,2,11,58,3,163,1,5,126,3,141,1,3,177,1,3,38,3,112,3,146,1,3,113,8,17,154,1,10,5,153,1,3,3,2,3,58,3,163,1,5,144,1,8,8,4,2,4,58,3,163,1,5,144,1,8,8,95,1,0,3,0,0,58,51,14,0,17,46,12,5,10,1,56,0,12,4,14,0,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,16,14,0,10,2,66,62,12,6,13,4,10,6,17,126,11,6,17,127,56,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,11,5,11,0,10,1,56,2,64,16,0,0,0,0,0,0,0,0,11,4,10,1,56,3,10,1,56,4,56,5,11,1,17,67,18,0,12,7,13,7,15,0,17,137,1,11,7,2,1,3,0,0,71,69,10,0,14,1,12,3,46,11,3,17,21,32,4,17,10,0,14,1,12,4,46,11,4,17,24,32,12,5,5,19,9,12,5,11,5,4,22,5,28,11,0,1,11,2,1,7,7,39,14,1,17,127,12,6,10,0,16,1,10,6,56,6,32,4,38,5,44,11,0,1,11,2,1,7,11,39,14,1,17,118,4,48,5,54,11,0,1,11,2,1,7,12,39,10,0,15,2,14,1,17,126,11,6,56,1,11,0,15,1,14,1,17,127,11,1,11,2,17,133,1,56,7,2,2,3,0,0,75,53,10,1,46,17,92,12,4,10,0,16,1,10,4,56,6,4,10,5,16,11,0,1,11,1,1,7,13,39,10,0,15,1,11,4,56,8,17,134,1,12,3,14,3,17,118,4,26,5,32,11,0,1,11,1,1,7,12,39,14,3,17,126,12,2,10,0,15,2,10,2,56,9,1,13,3,10,1,46,17,91,17,112,11,0,15,3,11,2,11,3,11,1,17,133,1,56,10,2,3,3,0,0,80,69,11,2,46,17,92,12,7,10,0,16,1,10,7,56,6,4,10,5,14,11,0,1,7,13,39,10,0,15,1,11,7,56,8,17,134,1,12,6,10,0,14,6,12,3,46,11,3,17,21,32,4,37,10,0,14,6,12,4,46,11,4,17,24,32,12,5,5,39,9,12,5,11,5,4,42,5,46,11,0,1,7,7,39,14,6,17,118,4,50,5,54,11,0,1,7,12,39,14,6,17,128,1,11,1,38,4,60,5,64,11,0,1,7,10,39,11,0,15,4,11,6,56,11,2,4,3,0,0,3,16,10,0,16,0,10,1,17,23,11,0,16,4,11,1,17,25,22,6,1,0,0,0,0,0,0,0,33,4,13,5,15,7,7,39,2,5,3,0,0,82,36,11,1,46,17,92,12,2,10,0,16,0,11,2,17,27,12,4,14,4,56,12,4,13,5,17,11,0,1,7,9,39,13,4,56,13,12,3,10,0,16,5,14,3,56,14,32,4,27,5,31,11,0,1,7,16,39,11,0,15,5,11,3,68,16,2,6,3,0,0,3,22,14,2,56,15,7,4,38,4,6,5,12,11,0,1,11,3,1,7,15,39,11,0,11,1,17,26,11,2,10,3,46,17,92,11,3,17,122,2,7,3,0,0,90,43,14,1,17,108,12,4,10,0,16,2,10,4,56,16,4,20,10,0,16,2,14,1,17,108,56,17,20,12,5,11,0,11,5,17,26,12,3,5,38,10,0,16,3,10,4,56,18,4,26,5,32,11,0,1,11,2,1,7,8,39,11,0,15,3,11,4,56,19,17,135,1,12,3,11,3,11,1,11,2,17,124,2,8,3,0,0,63,10,11,2,17,92,12,3,11,0,15,0,11,3,17,30,11,1,17,123,2,9,3,0,0,96,110,10,8,46,17,91,6,1,0,0,0,0,0,0,0,22,12,15,17,138,1,12,20,10,0,16,0,10,20,10,1,46,56,15,10,2,46,56,15,17,50,12,22,12,21,10,0,10,3,20,12,9,46,11,9,17,49,12,16,10,0,16,0,14,16,17,54,12,17,10,0,16,0,14,16,17,29,11,4,14,21,14,22,17,48,12,14,12,19,12,13,12,18,10,0,16,0,11,20,11,17,11,21,11,22,11,18,11,13,11,19,11,14,17,51,12,12,12,11,10,0,15,0,14,11,14,12,11,1,11,2,10,8,17,52,10,0,15,0,17,47,10,0,15,0,10,8,17,45,10,15,10,0,16,0,14,11,14,12,10,3,14,16,12,10,46,11,10,17,53,10,0,11,15,17,43,10,0,10,3,10,8,17,40,10,0,11,5,11,6,11,7,11,3,11,8,17,10,10,0,16,0,17,46,10,0,15,6,21,10,0,15,0,17,137,1,11,0,17,11,2,10,0,0,0,97,106,10,0,16,0,65,62,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,99,5,9,11,7,6,1,0,0,0,0,0,0,0,23,12,7,10,0,16,0,10,7,66,62,12,13,10,13,17,127,12,12,11,13,17,128,1,12,9,10,9,10,1,38,4,40,10,0,16,7,14,12,56,20,4,39,10,0,15,7,14,12,56,21,1,1,5,98,11,9,10,2,38,4,87,10,0,16,7,14,12,56,20,4,64,10,0,15,7,14,12,56,22,12,8,10,8,20,6,1,0,0,0,0,0,0,0,22,10,8,21,11,8,20,12,6,5,71,10,0,15,7,11,12,6,1,0,0,0,0,0,0,0,56,23,6,1,0,0,0,0,0,0,0,12,6,11,6,10,3,36,4,86,10,0,15,0,10,7,56,24,12,10,10,0,11,10,10,4,9,10,5,17,41,5,98,10,0,15,0,10,7,56,24,12,11,10,0,11,11,10,4,9,10,5,17,41,5,4,11,4,1,11,0,1,11,5,1,2,11,0,0,0,103,24,10,0,16,0,65,62,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,21,5,11,10,0,15,0,10,1,67,62,17,114,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,12,1,0,0,104,60,11,0,16,0,12,10,10,10,65,62,12,3,64,105,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,15,10,10,10,2,66,62,12,8,13,1,10,8,17,115,11,8,17,129,1,56,25,68,105,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,10,11,10,1,11,1,56,26,12,4,6,0,0,0,0,0,0,0,0,12,6,17,138,1,17,136,1,23,12,7,6,0,0,0,0,0,0,0,0,12,5,10,6,10,7,35,4,58,5,49,13,4,56,27,12,9,12,5,11,6,11,9,22,12,6,5,44,11,5,2,13,1,0,0,3,4,11,0,16,6,20,2,14,1,0,0,3,6,11,0,16,0,11,1,17,35,17,128,1,2,15,1,0,0,3,6,11,0,16,0,11,1,17,35,17,125,2,16,1,0,0,3,6,11,0,16,0,11,1,17,35,17,126,2,17,1,0,0,3,3,11,0,16,2,2,18,3,0,0,111,31,10,0,16,2,10,1,20,56,16,4,19,10,0,16,2,11,1,20,56,17,20,12,3,11,0,11,3,7,2,17,36,12,2,5,27,11,0,15,3,11,1,20,56,19,17,135,1,46,12,2,11,2,17,116,17,107,2,19,3,0,0,3,12,10,0,16,0,65,62,10,0,16,5,65,16,23,11,0,16,4,56,28,22,2,20,3,0,0,28,8,11,0,16,0,11,1,17,27,12,2,14,2,56,12,2,21,0,0,0,3,5,11,0,16,0,11,1,17,22,2,22,3,0,0,3,6,11,0,11,1,17,23,6,0,0,0,0,0,0,0,0,36,2,23,0,0,0,114,33,10,0,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,66,62,10,1,17,117,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,24,0,0,0,3,7,11,0,16,4,11,1,17,25,6,0,0,0,0,0,0,0,0,36,2,25,0,0,0,114,33,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,56,29,10,1,17,117,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,26,0,0,0,3,16,10,0,16,1,10,1,56,6,4,11,11,0,15,1,11,1,56,30,17,135,1,2,11,0,15,0,11,1,17,30,2,27,0,0,0,103,31,10,0,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,66,62,17,127,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,28,0,0,0,103,31,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,56,29,17,127,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,29,0,0,0,119,46,10,1,65,63,12,5,6,0,0,0,0,0,0,0,0,12,3,7,20,12,6,10,3,10,5,35,4,40,5,12,10,1,10,3,66,63,20,12,2,10,0,11,2,17,27,12,4,14,4,56,12,4,25,5,31,11,0,1,11,1,1,7,9,39,13,6,11,4,56,33,68,16,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,0,1,11,1,1,11,6,2,30,3,0,0,82,22,10,0,11,1,12,2,46,11,2,17,27,12,4,14,4,56,12,4,11,5,15,11,0,1,7,9,39,13,4,56,13,12,3,11,0,11,3,67,62,2,31,0,0,0,120,45,10,0,16,0,10,1,17,27,12,5,14,5,56,12,4,16,13,5,56,13,12,3,11,0,15,0,11,3,67,62,2,10,0,16,4,10,1,17,28,12,6,14,6,56,12,4,32,13,6,56,13,12,4,11,0,15,4,11,4,56,34,2,11,2,4,35,5,39,11,0,1,7,14,39,11,0,15,1,11,1,56,30,17,135,1,2,32,3,0,0,3,7,11,0,11,1,17,132,1,20,11,2,17,31,2,33,3,0,0,63,8,11,1,17,92,12,2,11,0,11,2,9,17,31,2,34,3,0,0,63,8,11,1,17,92,12,2,11,0,11,2,8,17,31,2,35,0,0,0,125,19,10,0,11,1,17,27,12,3,14,3,56,12,4,8,5,12,11,0,1,7,9,39,13,3,56,13,12,2,11,0,11,2,66,62,2,36,3,0,0,126,57,10,0,16,0,10,1,17,27,12,7,14,7,56,12,4,11,8,12,3,5,15,10,2,7,0,33,12,3,11,3,4,25,13,7,56,13,12,5,11,0,16,0,11,5,66,62,2,10,0,16,4,10,1,17,28,12,8,14,8,56,12,4,36,8,12,4,5,40,11,2,7,1,33,12,4,11,4,4,50,13,8,56,13,12,6,11,0,16,4,11,6,56,29,2,11,0,15,1,11,1,56,30,17,135,1,46,2,37,1,0,0,125,21,10,0,16,0,11,1,17,27,12,3,14,3,56,12,4,9,5,13,11,0,1,7,9,39,13,3,56,13,12,2,11,0,16,0,11,2,66,62,2,38,1,0,0,125,21,10,0,16,4,11,1,17,28,12,3,14,3,56,12,4,9,5,13,11,0,1,7,17,39,13,3,56,13,12,2,11,0,16,4,11,2,56,29,2,39,3,0,0,127,39,10,1,17,131,1,20,12,6,10,2,7,0,33,4,16,11,0,11,6,12,3,46,11,3,17,37,12,4,5,21,11,0,11,6,11,2,17,36,12,4,11,4,12,7,10,1,56,35,12,5,11,7,17,119,14,5,33,4,32,5,36,11,1,1,7,19,39,11,1,17,130,1,2,40,0,0,0,131,1,32,10,0,15,5,17,44,10,0,16,5,56,36,32,4,25,5,9,10,0,15,5,69,16,12,3,10,0,15,0,11,3,56,24,12,4,10,0,11,4,10,1,8,10,2,17,41,5,3,11,1,1,11,0,1,11,2,1,2,41,0,0,0,133,1,58,10,4,46,17,91,6,1,0,0,0,0,0,0,0,22,12,5,14,1,17,127,12,6,14,1,17,126,12,7,10,0,15,2,10,7,56,9,1,10,0,16,7,14,6,56,20,4,28,10,0,15,7,14,6,56,21,1,1,10,0,16,6,20,14,1,17,128,1,23,10,0,15,6,21,11,2,10,6,17,42,10,5,11,6,14,1,17,126,11,3,18,4,56,37,13,1,11,5,17,112,11,0,15,3,11,7,11,1,11,4,17,133,1,56,10,2,42,0,0,0,135,1,69,10,0,14,1,12,2,46,11,2,56,38,4,12,10,0,14,1,56,39,1,1,10,0,46,56,40,12,7,14,7,65,63,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,66,5,26,14,7,10,4,66,63,12,6,10,0,10,6,56,41,12,8,10,8,14,1,12,3,46,11,3,56,42,4,57,10,8,14,1,56,43,11,8,46,56,44,4,54,10,0,11,6,56,39,1,1,5,56,11,6,1,5,61,11,8,1,11,6,1,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,21,11,0,1,2,43,0,0,0,62,28,10,0,16,4,56,45,32,4,25,5,6,10,0,15,4,56,46,12,2,13,2,10,1,17,109,10,1,14,2,17,127,14,2,17,126,18,3,56,47,10,0,15,0,11,2,68,62,5,0,11,0,1,2,44,0,0,0,144,1,57,10,0,46,65,16,12,6,6,1,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,54,5,11,10,0,10,4,12,1,46,11,1,66,16,20,12,3,10,4,12,5,10,5,6,0,0,0,0,0,0,0,0,36,4,49,5,26,11,5,6,1,0,0,0,0,0,0,0,23,12,5,10,0,10,5,12,2,46,11,2,66,16,20,10,3,36,4,41,5,42,5,49,10,0,10,5,10,5,6,1,0,0,0,0,0,0,0,22,71,16,5,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,1,2,45,0,0,0,103,26,10,0,46,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,21,5,11,10,0,10,2,67,62,10,1,17,121,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,11,1,1,2,46,0,0,0,146,1,30,6,0,0,0,0,0,0,0,0,12,3,10,0,65,62,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,26,5,12,10,0,10,1,66,62,12,4,11,3,11,4,17,128,1,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,47,0,0,0,103,23,10,0,46,65,62,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,20,5,11,10,0,10,1,67,62,17,110,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,48,0,0,0,147,1,69,6,0,0,0,0,0,0,0,0,12,8,56,48,12,4,6,0,0,0,0,0,0,0,0,12,9,56,48,12,5,13,0,46,56,36,32,4,60,5,14,13,0,69,16,12,10,10,2,10,10,66,16,20,53,10,1,53,24,7,3,26,12,6,13,4,10,10,10,6,52,56,49,11,8,11,6,52,22,12,8,10,3,10,10,66,16,20,53,10,1,53,24,7,3,26,12,7,13,5,11,10,10,7,52,56,49,11,9,11,7,52,22,12,9,5,8,11,3,1,11,2,1,11,8,11,4,11,9,11,5,2,49,0,0,0,148,1,40,7,21,12,5,14,1,56,50,32,4,36,5,7,13,1,56,51,12,4,12,6,10,0,10,6,17,20,4,16,5,20,11,0,1,7,5,39,10,0,16,0,12,3,11,4,56,52,12,2,11,3,14,2,17,54,17,136,1,38,4,35,13,5,11,6,68,63,5,2,11,0,1,11,5,2,50,0,0,0,151,1,47,64,16,0,0,0,0,0,0,0,0,12,7,64,16,0,0,0,0,0,0,0,0,12,8,10,0,65,62,12,5,11,3,10,5,26,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,42,5,18,10,0,10,4,66,62,17,129,1,53,10,2,53,24,10,1,53,26,12,6,13,7,11,6,52,68,16,13,8,10,9,68,16,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,13,11,0,1,11,7,11,8,2,51,0,0,0,152,1,108,11,1,11,2,23,12,22,64,16,0,0,0,0,0,0,0,0,12,12,64,16,0,0,0,0,0,0,0,0,12,14,10,0,65,62,12,20,10,20,14,6,56,53,23,12,21,6,0,0,0,0,0,0,0,0,12,19,10,19,10,20,35,4,103,5,23,10,0,10,19,66,62,17,129,1,53,12,25,14,3,10,19,66,16,20,12,23,14,6,14,19,56,54,4,48,14,6,14,19,56,55,20,12,15,11,23,11,15,23,12,9,5,61,10,5,53,11,25,24,10,22,53,26,12,16,11,23,11,16,52,22,12,9,11,9,12,11,13,12,11,11,68,16,14,4,10,19,66,16,20,12,24,14,8,14,19,56,54,4,85,14,8,14,19,56,55,20,12,17,11,24,11,17,23,12,10,5,93,10,7,10,21,26,12,18,11,24,11,18,22,12,10,11,10,12,13,13,14,11,13,68,16,11,19,6,1,0,0,0,0,0,0,0,22,12,19,5,18,11,0,1,11,12,11,14,2,52,0,0,0,153,1,107,10,0,46,65,62,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,9,5,23,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,7,18,39,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,94,5,30,10,0,10,6,67,62,12,10,10,1,10,6,66,16,20,12,9,10,3,10,9,56,56,12,8,11,9,53,10,10,46,17,111,53,24,7,3,26,12,12,13,8,11,12,52,56,56,12,13,13,13,10,4,10,2,10,6,66,16,20,56,56,56,57,1,14,13,56,15,6,0,0,0,0,0,0,0,0,36,4,84,10,10,46,17,127,12,11,10,10,11,13,10,11,10,5,17,122,11,11,56,58,5,86,11,13,56,59,11,10,11,8,17,113,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,25,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,2,53,0,0,0,159,1,84,10,1,65,62,12,9,6,0,0,0,0,0,0,0,0,12,8,10,8,10,9,35,4,73,5,10,10,1,10,8,66,62,12,12,10,12,17,127,12,13,10,4,14,13,56,38,4,28,10,4,14,13,56,60,20,56,52,12,6,5,30,7,21,12,6,11,6,12,11,10,5,14,13,56,61,4,39,6,0,0,0,0,0,0,0,0,12,7,5,41,6,1,0,0,0,0,0,0,0,12,7,11,7,12,10,10,0,11,13,10,12,17,115,10,12,17,128,1,10,12,17,129,1,10,12,17,111,10,2,10,8,66,16,20,10,3,10,8,66,16,20,11,12,10,0,17,120,11,11,11,10,18,2,56,62,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,5,11,1,1,11,3,1,11,5,1,11,4,1,11,2,1,2,54,1,0,0,146,1,35,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,1,65,63,12,3,10,2,10,3,35,4,29,5,12,10,0,10,1,10,2,66,63,20,17,35,12,5,11,4,11,5,17,129,1,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,55,1,0,0,3,3,11,0,16,0,2,56,1,0,0,3,5,11,0,16,1,11,1,56,6,2,57,1,0,0,3,5,11,0,16,3,11,1,56,18,2,58,3,0,0,163,1,32,11,0,16,0,12,5,7,21,12,3,6,0,0,0,0,0,0,0,0,12,1,10,5,65,62,12,2,10,1,10,2,35,4,28,5,15,10,5,10,1,66,62,17,127,12,4,13,3,11,4,68,63,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,10,11,5,1,11,3,2,0,1,0,6,0,4,0,5,0,2,0,3,0,0,0,7,0,66,0,149,1,0],"validator_wrapper":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,16,3,24,48,4,72,6,5,78,52,7,130,1,211,1,8,213,2,64,6,149,3,10,10,159,3,6,12,165,3,100,13,137,4,2,15,139,4,2,0,14,1,10,1,16,0,12,0,2,4,0,1,0,2,0,2,3,12,0,3,1,4,0,0,5,0,1,0,0,8,2,3,0,0,6,1,4,0,0,11,2,5,0,0,15,6,7,0,2,4,8,9,1,4,2,6,9,12,1,4,2,9,10,11,1,4,2,15,13,7,0,5,4,7,4,6,4,2,8,3,7,8,1,1,8,0,1,7,8,0,1,7,8,3,1,8,3,0,1,6,8,0,1,3,3,3,9,0,7,8,1,1,8,2,1,7,8,2,1,7,9,0,1,9,0,1,6,8,2,9,84,120,67,111,110,116,101,120,116,9,86,97,108,105,100,97,116,111,114,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,9,86,101,114,115,105,111,110,101,100,6,99,114,101,97,116,101,9,99,114,101,97,116,101,95,118,49,7,100,101,115,116,114,111,121,5,105,110,110,101,114,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,10,116,120,95,99,111,110,116,101,120,116,17,117,112,103,114,97,100,101,95,116,111,95,108,97,116,101,115,116,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,1,7,8,2,0,3,0,0,5,6,6,1,0,0,0,0,0,0,0,11,0,11,1,56,0,18,0,2,1,3,0,0,5,6,10,0,17,3,11,0,15,0,56,1,2,2,3,0,0,5,6,13,0,17,3,11,0,19,0,56,2,2,3,0,0,0,5,10,11,0,46,17,4,6,1,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,2,4,0,0,0,5,4,11,0,16,0,17,8,2,0,0,0,13,0],"voting_power":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,87,4,107,4,5,111,134,1,7,245,1,176,2,8,165,4,96,6,133,5,70,10,203,5,16,12,219,5,254,6,13,217,12,4,15,221,12,2,0,22,1,21,2,9,0,18,0,1,2,0,0,2,2,0,3,0,4,0,0,13,0,1,0,0,6,2,3,0,0,15,4,5,0,0,7,6,1,0,0,3,7,1,0,0,17,8,1,0,0,4,4,1,0,0,16,1,5,0,0,12,1,5,0,1,7,17,1,1,0,1,8,19,20,1,0,2,5,11,5,0,2,10,11,5,0,2,11,11,5,0,3,13,21,1,0,3,15,14,5,0,3,22,14,5,0,9,13,10,13,1,7,10,8,2,0,2,6,10,8,2,3,2,10,8,1,3,1,6,10,8,2,1,3,2,7,10,8,1,8,1,3,7,10,8,1,3,3,2,7,10,8,2,10,8,1,4,3,10,8,1,3,3,1,8,2,2,3,3,8,3,8,1,3,10,8,1,3,3,3,3,1,8,1,1,6,8,2,3,3,3,3,4,3,1,3,3,3,7,10,9,0,9,0,3,7,1,3,3,3,3,3,7,8,1,1,6,10,9,0,1,1,2,7,8,2,3,12,3,3,3,3,3,3,3,3,3,6,8,2,6,8,2,3,9,86,97,108,105,100,97,116,111,114,15,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,17,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,86,50,19,97,100,106,117,115,116,95,118,111,116,105,110,103,95,112,111,119,101,114,16,99,104,101,99,107,95,105,110,118,97,114,105,97,110,116,115,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,22,105,110,105,116,95,118,111,116,105,110,103,95,112,111,119,101,114,95,105,110,102,111,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,4,109,97,116,104,3,109,97,120,3,109,105,110,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,5,115,116,97,107,101,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,19,117,112,100,97,116,101,95,118,111,116,105,110,103,95,112,111,119,101,114,9,118,97,108,105,100,97,116,111,114,15,118,97,108,105,100,97,116,111,114,95,105,110,100,101,120,13,118,97,108,105,100,97,116,111,114,95,115,101,116,6,118,101,99,116,111,114,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,16,39,0,0,0,0,0,0,3,8,11,26,0,0,0,0,0,0,3,8,232,3,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,2,19,3,22,3,1,2,3,19,3,22,3,14,3,0,3,0,0,9,29,7,0,7,2,7,0,10,0,46,65,10,17,11,17,12,17,13,12,4,10,0,10,4,12,1,46,11,1,17,1,12,3,12,2,13,2,11,4,11,3,17,4,10,0,11,2,17,5,11,0,46,17,6,2,1,0,0,0,12,58,10,0,17,2,12,8,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,7,64,13,0,0,0,0,0,0,0,0,12,5,10,2,10,4,35,4,51,5,17,10,0,10,2,66,10,17,15,12,6,10,6,53,7,0,53,24,10,8,53,26,52,10,1,17,13,12,9,10,2,10,9,11,6,18,1,12,3,13,5,11,3,17,3,11,7,11,9,22,12,7,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,0,1,11,5,7,0,11,7,23,2,2,0,0,0,15,28,6,0,0,0,0,0,0,0,0,12,1,10,0,65,10,12,2,6,0,0,0,0,0,0,0,0,12,3,10,1,10,2,35,4,24,5,12,11,3,10,0,10,1,66,10,17,15,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,3,0,0,0,16,39,6,0,0,0,0,0,0,0,0,12,4,10,0,46,65,13,12,5,10,4,10,5,35,4,25,5,11,10,0,10,4,12,2,46,11,2,66,13,16,0,20,14,1,16,0,20,36,12,3,5,27,9,12,3,11,3,4,34,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,11,1,11,4,56,0,2,4,0,0,0,18,84,6,0,0,0,0,0,0,0,0,12,5,10,0,46,65,13,12,6,10,5,10,6,35,4,16,5,11,10,2,6,0,0,0,0,0,0,0,0,36,12,3,5,18,9,12,3,11,3,4,74,10,0,10,5,67,13,12,9,10,2,10,6,10,5,23,17,11,12,7,10,1,10,9,16,1,20,11,7,22,17,13,12,8,10,2,11,8,10,9,16,1,20,23,17,13,12,4,10,9,16,1,20,10,4,22,10,9,15,1,21,11,9,16,1,20,10,1,37,4,61,5,65,11,0,1,7,5,39,11,2,11,4,23,12,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,6,11,0,1,11,2,6,0,0,0,0,0,0,0,0,33,4,81,5,83,7,3,39,2,5,0,0,0,11,22,14,1,56,1,32,4,17,5,5,13,1,69,13,19,1,1,12,3,12,2,10,0,11,2,67,10,11,3,17,14,5,0,11,0,1,11,1,70,13,0,0,0,0,0,0,0,0,2,6,0,0,0,22,119,6,0,0,0,0,0,0,0,0,12,3,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,9,10,3,10,4,35,4,35,5,12,10,0,10,3,66,10,17,16,12,12,10,12,6,0,0,0,0,0,0,0,0,36,4,22,5,26,11,0,1,7,6,39,11,9,11,12,22,12,9,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,9,7,0,33,4,40,5,44,11,0,1,7,3,39,6,0,0,0,0,0,0,0,0,12,1,10,1,10,4,35,4,116,5,51,10,1,6,1,0,0,0,0,0,0,0,22,12,2,10,2,10,4,35,4,111,5,60,10,0,10,1,66,10,12,10,10,0,10,2,66,10,12,11,10,10,17,15,12,7,10,11,17,15,12,8,11,10,17,16,12,5,11,11,17,16,12,6,10,7,10,8,36,4,93,10,5,10,6,38,4,89,5,93,11,0,1,7,4,39,11,7,11,8,35,4,106,11,5,11,6,37,4,102,5,106,11,0,1,7,4,39,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,55,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,46,11,0,1,2,7,1,0,0,1,2,7,0,2,8,1,0,0,1,2,7,1,2,1,2,1,1,0,20,0]},"type_origin_table":[{"module_name":"validator_cap","struct_name":"UnverifiedValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_cap","struct_name":"ValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakingPool","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"PoolTokenExchangeRate","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakedIota","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"ValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"Validator","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"StakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"UnstakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfo","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfoV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_wrapper","struct_name":"ValidatorWrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorSet","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEventV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorJoinEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorLeaveEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"storage_fund","struct_name":"StorageFund","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"stake_subsidy","struct_name":"StakeSubsidy","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"SystemParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"SystemParametersV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"IotaSystemStateInner","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"IotaSystemStateInnerV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"SystemEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system","struct_name":"IotaSystemState","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisChainParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenDistributionSchedule","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenAllocation","package":"0x0000000000000000000000000000000000000000000000000000000000000003"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"F8GGcAVhtPumDoXzc6z9N8Hf9zoTNFx1BPiCy7FJNZsQ","storage_rebate":0},{"data":{"Package":{"id":"0x000000000000000000000000000000000000000000000000000000000000dee9","version":10,"module_map":{"clob":[161,28,235,11,6,0,0,0,13,1,0,35,2,35,134,1,3,169,1,195,4,4,236,5,178,1,5,158,7,249,9,7,151,17,237,14,8,132,32,96,6,228,32,147,2,10,247,34,226,1,11,217,36,8,12,225,36,179,39,13,148,76,40,14,188,76,26,0,45,0,53,0,54,0,94,1,105,1,135,1,2,28,2,46,2,47,2,64,2,85,2,103,2,124,2,127,2,133,1,2,134,1,0,16,7,0,0,14,7,2,0,1,0,1,0,10,7,2,0,1,0,1,0,12,7,2,0,1,0,1,0,9,6,0,0,19,4,0,0,15,8,2,0,1,0,1,0,13,7,2,0,1,0,1,0,11,7,2,0,1,0,1,1,4,4,1,4,0,2,0,12,0,2,5,12,1,0,1,4,8,7,1,0,0,5,21,7,0,6,1,4,1,0,1,7,2,8,0,8,3,12,1,0,1,10,7,12,2,7,0,4,1,11,6,7,0,11,22,4,0,12,17,2,0,13,18,12,2,7,1,4,1,15,20,2,0,0,60,0,1,0,0,49,2,3,0,0,51,4,1,2,0,0,0,50,5,1,2,0,0,0,57,6,1,2,0,0,0,58,7,1,2,0,0,0,144,1,8,9,2,0,0,0,145,1,8,10,2,0,0,0,125,11,12,2,0,0,0,126,13,12,2,0,0,0,93,14,15,2,0,0,0,92,14,15,2,0,0,0,91,16,15,2,0,0,0,110,17,18,2,0,0,0,78,19,20,2,0,0,0,109,21,22,2,0,0,0,107,20,23,0,0,62,24,1,2,0,0,0,63,25,1,2,0,0,0,44,26,1,2,0,0,0,121,27,28,2,0,0,0,43,29,1,2,0,0,0,36,30,1,2,0,0,0,86,31,32,2,0,0,0,24,31,33,2,0,0,0,74,34,35,2,0,0,0,73,36,37,2,0,0,0,72,36,37,2,0,0,0,71,38,20,2,0,0,0,75,39,40,2,0,0,1,39,84,60,1,4,1,40,84,60,1,4,1,42,71,72,1,4,1,66,84,20,1,4,1,67,84,78,1,4,1,79,91,20,1,4,1,82,70,23,1,4,1,95,70,35,1,4,1,96,70,35,1,4,1,98,2,51,1,4,1,102,84,35,1,4,1,112,84,35,1,4,1,120,71,45,1,4,2,23,97,20,1,0,2,24,97,35,1,0,2,55,90,55,1,0,2,56,77,55,1,0,2,77,62,1,1,0,2,87,90,1,1,0,2,98,2,54,1,0,2,137,1,77,1,1,0,2,143,1,63,9,1,0,3,97,35,20,0,3,138,1,35,20,0,3,139,1,35,20,0,3,140,1,35,78,0,4,38,74,60,1,0,4,83,74,23,1,0,5,70,1,46,1,0,6,84,80,20,1,0,6,123,79,55,1,0,6,142,1,67,20,1,0,6,146,1,1,55,1,0,7,131,1,66,20,0,8,68,68,9,1,0,8,80,9,55,1,0,8,84,88,1,1,0,8,142,1,59,20,1,0,9,61,45,1,1,3,10,27,73,74,2,7,4,10,38,75,76,2,7,4,10,41,83,82,2,7,4,10,48,75,23,2,7,4,10,59,43,1,2,7,4,10,69,73,74,2,7,4,10,82,73,23,2,7,4,10,98,2,43,2,7,4,10,99,75,74,2,7,4,10,114,92,1,2,7,4,10,119,83,47,2,7,4,11,76,60,61,1,8,11,98,2,48,0,11,136,1,49,50,0,13,25,95,1,2,7,4,13,38,94,76,2,7,4,13,41,81,82,2,7,4,13,48,94,23,2,7,4,13,98,2,53,2,7,4,14,122,45,1,1,8,73,42,58,45,58,47,39,0,87,52,49,45,49,47,62,45,62,47,88,57,68,58,67,45,80,3,65,45,47,45,67,47,65,47,47,47,51,45,51,47,13,56,10,56,61,45,64,45,64,47,36,0,38,0,32,0,74,42,56,20,75,42,70,42,50,45,17,56,46,45,60,47,59,47,59,45,18,56,77,42,57,20,85,52,79,35,79,42,71,42,40,0,42,0,34,0,37,0,50,47,46,47,60,45,41,0,11,56,66,45,12,56,66,47,48,47,48,45,76,42,35,0,78,42,68,93,86,52,76,35,83,52,78,35,43,47,45,47,61,47,45,45,14,56,68,98,68,99,72,35,70,35,20,56,30,0,72,42,75,35,69,35,84,52,74,35,31,0,77,35,44,45,44,47,33,0,28,56,1,8,5,0,1,7,8,22,1,8,10,6,3,3,3,3,11,14,1,8,20,7,8,22,4,3,3,11,16,1,8,20,7,8,22,3,7,11,6,2,9,0,9,1,11,16,1,9,0,6,8,10,3,7,11,6,2,9,0,9,1,11,16,1,9,1,6,8,10,4,7,11,6,2,9,0,9,1,3,6,8,10,7,8,22,1,11,16,1,9,0,1,11,16,1,9,1,6,7,11,6,2,9,0,9,1,3,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,3,11,16,1,9,0,11,16,1,9,1,3,5,7,11,6,2,9,0,9,1,3,6,8,15,11,16,1,9,1,7,8,22,5,7,11,6,2,9,0,9,1,3,3,3,11,14,1,9,1,2,11,14,1,9,0,11,14,1,9,1,4,7,11,6,2,9,0,9,1,3,3,11,14,1,9,0,7,7,11,6,2,9,0,9,1,3,1,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,2,11,16,1,9,0,11,16,1,9,1,7,7,11,6,2,9,0,9,1,3,3,1,3,6,8,10,7,8,22,1,3,9,7,11,6,2,9,0,9,1,3,3,1,3,2,6,8,15,6,8,10,7,8,22,4,3,3,1,3,1,1,2,8,18,6,8,4,5,8,18,6,8,4,3,3,3,3,7,11,6,2,9,0,9,1,3,6,8,10,5,7,11,9,1,8,5,7,11,17,2,3,3,3,3,8,18,1,8,4,2,7,11,6,2,9,0,9,1,6,8,10,3,7,11,6,2,9,0,9,1,10,3,6,8,10,2,6,11,6,2,9,0,9,1,6,8,10,1,10,8,4,4,3,3,3,3,1,6,11,6,2,9,0,9,1,2,3,3,4,6,11,6,2,9,0,9,1,3,3,6,8,15,2,10,3,10,3,3,6,11,9,1,8,5,3,3,3,6,11,6,2,9,0,9,1,3,6,8,10,1,6,8,4,1,11,17,2,3,8,4,2,3,8,4,1,11,17,2,9,0,9,1,4,8,13,8,18,8,19,8,13,1,9,0,1,8,13,1,9,1,1,8,19,1,6,8,19,1,6,8,18,1,11,9,1,9,0,2,8,18,11,17,2,3,3,1,11,21,2,9,0,9,1,1,11,11,1,9,0,1,11,14,1,9,0,2,9,0,9,1,1,11,6,2,9,0,9,1,1,8,0,1,6,11,16,1,9,0,1,6,9,0,1,8,18,3,7,11,11,1,9,0,8,18,11,14,1,9,0,4,7,11,11,1,9,0,3,6,8,10,7,8,22,4,3,11,16,1,9,0,11,16,1,9,1,3,3,11,14,1,9,0,11,14,1,9,1,3,1,6,8,15,1,6,11,14,1,9,0,2,11,14,1,9,0,7,8,22,30,1,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,11,14,1,9,1,1,3,3,3,1,3,7,8,5,3,1,6,11,9,1,9,0,2,7,11,9,1,9,0,3,1,7,9,0,1,6,11,17,2,9,0,9,1,1,6,11,12,1,9,0,2,6,11,17,2,9,0,9,1,9,0,1,6,9,1,3,7,11,11,1,9,0,8,18,3,2,1,3,2,7,11,14,1,9,0,3,2,7,11,14,1,9,0,11,14,1,9,0,2,7,11,21,2,9,0,9,1,9,0,1,7,9,1,2,7,11,17,2,9,0,9,1,9,0,2,6,11,9,1,9,0,3,26,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,27,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,1,3,6,8,4,7,8,4,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,3,11,14,1,9,0,11,14,1,9,1,11,14,1,9,1,2,7,11,16,1,9,0,11,16,1,9,0,7,3,7,11,9,1,8,5,8,4,3,3,3,8,18,3,7,11,11,1,9,0,6,8,10,3,3,7,11,9,1,9,0,3,9,0,3,7,11,17,2,9,0,9,1,9,0,9,1,1,11,1,2,9,0,9,1,2,6,11,21,2,9,0,9,1,9,0,3,7,11,21,2,9,0,9,1,9,0,9,1,11,11,14,1,9,0,11,14,1,9,0,11,14,1,9,0,3,3,11,14,1,9,1,11,14,1,9,1,11,14,1,9,1,3,3,8,18,2,6,11,11,1,9,0,8,18,1,11,2,2,9,0,9,1,1,11,3,2,9,0,9,1,11,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,1,8,4,3,3,8,18,7,11,17,2,3,3,3,3,7,8,5,8,4,13,3,7,11,9,1,8,5,3,3,1,7,11,9,1,8,5,8,4,3,3,8,18,3,8,18,7,11,17,2,3,3,17,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,3,1,3,3,3,8,4,3,8,18,3,3,8,18,7,11,17,2,3,3,7,6,8,5,10,8,4,6,8,4,6,11,12,1,3,3,8,18,6,11,17,2,3,3,5,3,3,3,3,8,18,6,3,10,3,3,3,3,10,3,4,3,6,8,4,6,11,12,1,3,6,11,17,2,3,8,4,4,6,11,9,1,8,5,3,8,18,6,11,17,2,3,3,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,11,67,114,105,116,98,105,116,84,114,101,101,9,67,117,115,116,111,100,105,97,110,2,73,68,11,76,105,110,107,101,100,84,97,98,108,101,6,79,112,116,105,111,110,5,79,114,100,101,114,13,79,114,100,101,114,67,97,110,99,101,108,101,100,11,79,114,100,101,114,70,105,108,108,101,100,13,79,114,100,101,114,70,105,108,108,101,100,86,50,11,79,114,100,101,114,80,108,97,99,101,100,13,79,114,100,101,114,80,108,97,99,101,100,86,50,4,80,111,111,108,11,80,111,111,108,67,114,101,97,116,101,100,3,83,85,73,5,84,97,98,108,101,9,84,105,99,107,76,101,118,101,108,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,3,97,100,100,4,97,115,107,115,4,98,97,99,107,7,98,97,108,97,110,99,101,10,98,97,115,101,95,97,115,115,101,116,28,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,99,97,110,99,101,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,102,105,108,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,112,108,97,99,101,100,29,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,114,101,109,97,105,110,105,110,103,23,98,97,115,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,14,98,97,115,101,95,99,117,115,116,111,100,105,97,110,18,98,97,116,99,104,95,99,97,110,99,101,108,95,111,114,100,101,114,4,98,105,100,115,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,17,99,97,110,99,101,108,95,97,108,108,95,111,114,100,101,114,115,12,99,97,110,99,101,108,95,111,114,100,101,114,4,99,108,111,98,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,14,99,114,101,97,116,101,95,97,99,99,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,12,99,114,101,97,116,101,95,112,111,111,108,95,12,99,114,101,97,116,105,111,110,95,102,101,101,7,99,114,105,116,98,105,116,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,100,101,112,111,115,105,116,95,98,97,115,101,13,100,101,112,111,115,105,116,95,113,117,111,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,19,100,101,115,116,114,111,121,95,101,109,112,116,121,95,108,101,118,101,108,4,101,109,105,116,19,101,109,105,116,95,111,114,100,101,114,95,99,97,110,99,101,108,101,100,17,101,109,105,116,95,111,114,100,101,114,95,102,105,108,108,101,100,5,101,118,101,110,116,16,101,120,112,105,114,101,95,116,105,109,101,115,116,97,109,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,12,102,114,111,109,95,98,97,108,97,110,99,101,5,102,114,111,110,116,3,103,101,116,22,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,97,115,107,95,115,105,100,101,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,98,105,100,95,115,105,100,101,16,103,101,116,95,109,97,114,107,101,116,95,112,114,105,99,101,16,103,101,116,95,111,114,100,101,114,95,115,116,97,116,117,115,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,18,105,110,106,101,99,116,95,108,105,109,105,116,95,111,114,100,101,114,11,105,110,115,101,114,116,95,108,101,97,102,12,105,110,116,111,95,98,97,108,97,110,99,101,6,105,115,95,98,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,4,106,111,105,110,12,108,105,110,107,101,100,95,116,97,98,108,101,16,108,105,115,116,95,111,112,101,110,95,111,114,100,101,114,115,12,108,111,99,107,95,98,97,108,97,110,99,101,8,108,111,116,95,115,105,122,101,17,109,97,107,101,114,95,114,101,98,97,116,101,95,114,97,116,101,13,109,97,107,101,114,95,114,101,98,97,116,101,115,9,109,97,116,99,104,95,97,115,107,9,109,97,116,99,104,95,98,105,100,29,109,97,116,99,104,95,98,105,100,95,119,105,116,104,95,113,117,111,116,101,95,113,117,97,110,116,105,116,121,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,3,109,117,108,3,110,101,119,4,110,101,120,116,17,110,101,120,116,95,97,115,107,95,111,114,100,101,114,95,105,100,17,110,101,120,116,95,98,105,100,95,111,114,100,101,114,95,105,100,9,110,101,120,116,95,108,101,97,102,6,111,98,106,101,99,116,11,111,112,101,110,95,111,114,100,101,114,115,6,111,112,116,105,111,110,8,111,114,100,101,114,95,105,100,12,111,114,100,101,114,95,105,115,95,98,105,100,5,111,119,110,101,114,17,112,108,97,99,101,95,108,105,109,105,116,95,111,114,100,101,114,18,112,108,97,99,101,95,109,97,114,107,101,116,95,111,114,100,101,114,7,112,111,111,108,95,105,100,13,112,114,101,118,105,111,117,115,95,108,101,97,102,5,112,114,105,99,101,9,112,117,115,104,95,98,97,99,107,8,113,117,97,110,116,105,116,121,11,113,117,111,116,101,95,97,115,115,101,116,24,113,117,111,116,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,15,113,117,111,116,101,95,99,117,115,116,111,100,105,97,110,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,12,114,101,109,111,118,101,95,111,114,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,3,115,117,105,25,115,119,97,112,95,101,120,97,99,116,95,98,97,115,101,95,102,111,114,95,113,117,111,116,101,25,115,119,97,112,95,101,120,97,99,116,95,113,117,111,116,101,95,102,111,114,95,98,97,115,101,5,116,97,98,108,101,16,116,97,107,101,114,95,99,111,109,109,105,115,115,105,111,110,14,116,97,107,101,114,95,102,101,101,95,114,97,116,101,9,116,105,99,107,95,115,105,122,101,12,116,105,109,101,115,116,97,109,112,95,109,115,14,116,111,116,97,108,95,113,117,97,110,116,105,116,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,10,117,110,115,97,102,101,95,100,105,118,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,15,117,115,114,95,111,112,101,110,95,111,114,100,101,114,115,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,13,119,105,116,104,100,114,97,119,95,98,97,115,101,14,119,105,116,104,100,114,97,119,95,113,117,111,116,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,3,8,19,0,0,0,0,0,0,0,3,8,20,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,2,1,4,2,1,0,2,1,1,2,1,2,2,1,3,3,8,0,0,0,0,0,0,0,128,3,8,64,75,76,0,0,0,0,0,3,8,160,37,38,0,0,0,0,0,3,8,0,232,118,72,23,0,0,0,0,2,7,111,8,18,29,8,13,116,8,13,129,1,3,89,3,130,1,3,88,3,1,2,7,111,8,18,106,3,81,1,108,8,18,32,3,113,3,65,3,2,2,6,111,8,18,106,3,81,1,108,8,18,30,3,113,3,3,2,10,111,8,18,106,3,81,1,108,8,18,132,1,3,31,3,33,3,113,3,128,1,3,90,3,4,2,6,106,3,113,3,115,3,81,1,108,8,18,65,3,5,2,2,113,3,104,11,17,2,3,8,4,6,2,15,76,8,19,37,11,9,1,8,5,26,11,9,1,8,5,101,3,100,3,141,1,11,21,2,8,18,11,17,2,3,3,129,1,3,89,3,130,1,3,88,3,35,11,11,1,9,0,118,11,11,1,9,1,52,11,14,1,8,20,34,11,14,1,9,0,117,11,14,1,9,1,7,2,6,111,8,18,106,3,81,1,108,8,18,32,3,113,3,8,2,8,111,8,18,106,3,81,1,108,8,18,132,1,3,31,3,33,3,113,3,6,56,1,56,2,56,3,56,0,0,0,0,41,7,11,0,19,5,12,1,1,11,1,56,0,2,1,1,0,0,1,2,7,0,39,2,0,0,0,44,72,56,1,12,6,56,2,12,9,10,3,10,2,17,54,6,0,0,0,0,0,0,0,0,36,4,11,5,15,11,5,1,7,20,39,10,6,10,9,34,4,20,5,24,11,5,1,7,16,39,10,0,10,1,38,4,29,5,33,11,5,1,7,2,39,10,5,17,81,12,8,14,8,17,82,20,12,7,11,8,10,5,56,3,10,5,56,3,7,1,7,27,10,5,56,4,10,0,10,1,10,2,10,3,10,5,56,5,11,5,56,6,11,4,56,7,56,8,57,0,56,9,11,7,11,6,11,9,11,0,11,1,11,2,11,3,18,0,56,10,2,3,1,0,0,1,2,7,0,39,4,1,0,0,1,20,14,1,56,11,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,7,39,11,0,54,0,11,2,56,12,11,1,56,13,56,14,2,5,1,0,0,1,20,14,1,56,15,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,8,39,11,0,54,1,11,2,56,12,11,1,56,16,56,17,2,6,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,6,39,11,0,54,0,11,1,11,2,11,3,56,18,2,7,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,6,39,11,0,54,1,11,1,11,2,11,3,56,19,2,8,1,0,0,64,49,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,5,1,11,4,1,7,6,39,14,2,56,11,10,1,38,4,19,5,27,11,0,1,11,5,1,11,4,1,7,7,39,14,3,56,15,12,6,11,0,11,1,9,11,2,11,3,11,4,11,5,56,20,12,8,12,7,14,8,56,15,12,9,11,7,11,8,11,9,11,6,23,2,9,1,0,0,65,48,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,4,1,11,2,1,7,6,39,14,3,56,15,10,1,38,4,19,5,27,11,0,1,11,4,1,11,2,1,7,8,39,11,0,11,1,7,27,11,2,17,63,11,3,56,16,56,21,12,6,12,5,14,5,56,22,12,7,11,5,10,4,56,23,11,6,11,4,56,24,11,7,2,10,0,0,0,69,193,2,10,0,55,2,17,82,20,12,24,11,1,12,30,56,7,12,10,11,4,12,26,10,0,54,3,12,9,10,9,46,56,25,4,25,11,0,1,11,9,1,11,10,11,26,2,10,9,46,56,26,12,32,12,34,9,12,31,10,9,46,56,25,32,4,43,5,38,10,34,10,2,37,12,5,5,45,9,12,5,11,5,4,190,2,10,9,10,32,56,27,12,33,10,33,16,4,56,28,56,29,20,12,23,10,33,16,4,56,30,32,4,158,2,5,63,10,33,16,4,10,23,56,31,12,16,10,16,16,5,20,12,15,9,12,27,10,16,16,6,20,10,3,37,4,95,8,12,27,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,32,10,24,10,16,56,33,5,227,1,10,15,10,16,16,8,20,17,52,12,19,10,19,10,0,55,4,20,17,55,12,28,4,112,11,28,6,1,0,0,0,0,0,0,0,22,12,28,10,19,11,28,22,12,18,10,30,10,18,36,4,127,11,18,12,12,11,19,12,13,10,15,12,11,5,170,1,8,12,31,10,30,7,21,10,0,55,4,20,22,17,53,10,16,16,8,20,17,53,10,0,55,5,20,26,10,0,55,5,20,24,12,11,10,11,10,16,16,8,20,17,54,12,13,10,13,10,0,55,4,20,17,55,12,29,4,166,1,11,29,6,1,0,0,0,0,0,0,0,22,12,29,10,13,11,29,22,12,12,10,13,10,0,55,6,20,17,54,12,20,11,15,10,11,23,12,15,11,30,10,12,23,12,30,10,0,54,0,10,16,16,7,20,10,11,56,34,12,14,13,26,10,12,56,35,12,25,10,0,54,1,10,16,16,7,20,13,25,10,20,10,13,22,56,35,56,17,10,0,54,7,11,25,56,36,1,13,10,11,14,56,37,1,10,0,55,2,17,82,20,10,16,11,11,11,12,11,13,23,11,20,56,38,11,27,4,232,1,8,12,6,5,236,1,10,15,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,143,2,10,23,12,22,10,33,16,4,10,23,56,39,12,21,10,21,56,40,32,4,254,1,11,21,56,29,20,12,23,5,128,2,11,21,1,10,0,54,8,11,16,16,7,20,56,41,10,22,56,42,1,10,33,15,4,11,22,56,43,1,5,154,2,11,16,1,10,33,15,4,10,23,56,44,12,17,11,15,11,17,15,5,21,10,31,4,157,2,5,158,2,5,57,11,33,16,4,56,30,4,182,2,10,9,11,34,12,7,46,11,7,56,45,1,12,34,10,9,11,32,56,46,17,0,10,9,10,34,12,8,46,11,8,56,47,12,32,1,10,31,4,189,2,11,0,1,11,9,1,5,190,2,5,32,11,10,11,26,2,11,0,0,0,85,153,2,10,0,55,2,17,82,20,12,22,11,1,12,25,56,7,12,11,11,4,12,23,10,0,54,3,12,10,10,10,46,56,25,4,25,11,0,1,11,10,1,11,11,11,23,2,10,10,46,56,26,12,28,12,30,10,10,46,56,25,32,4,41,5,36,10,30,10,2,37,12,5,5,43,9,12,5,11,5,4,150,2,10,10,10,28,56,27,12,29,10,29,16,4,56,28,56,29,20,12,21,10,29,16,4,56,30,32,4,244,1,5,61,10,29,16,4,10,21,56,31,12,16,10,16,16,5,20,12,15,9,12,24,10,16,16,6,20,10,3,37,4,93,8,12,24,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,32,10,22,10,16,56,33,5,183,1,10,25,10,15,36,4,100,10,15,12,6,5,102,10,25,12,6,11,6,12,12,10,12,10,16,16,8,20,17,52,12,13,10,13,10,0,55,6,20,17,54,12,18,10,13,10,0,55,4,20,17,55,12,26,4,127,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,15,10,12,23,12,15,11,25,10,12,23,12,25,10,0,54,0,10,16,16,7,20,10,12,56,34,12,14,13,23,10,26,56,35,12,27,10,0,54,1,10,16,16,7,20,13,27,10,18,56,35,56,17,10,0,54,7,11,27,56,36,1,13,11,11,14,56,37,1,10,0,54,1,10,16,16,7,20,13,23,11,13,56,35,56,17,10,0,55,2,17,82,20,10,16,11,12,11,26,11,18,56,38,11,24,4,188,1,8,12,7,5,192,1,10,15,6,0,0,0,0,0,0,0,0,33,12,7,11,7,4,227,1,10,21,12,20,10,29,16,4,10,21,56,39,12,19,10,19,56,40,32,4,210,1,11,19,56,29,20,12,21,5,212,1,11,19,1,10,0,54,8,11,16,16,7,20,56,41,10,20,56,42,1,10,29,15,4,11,20,56,43,1,5,238,1,11,16,1,10,29,15,4,10,21,56,44,12,17,11,15,11,17,15,5,21,10,25,6,0,0,0,0,0,0,0,0,33,4,243,1,5,244,1,5,55,11,29,16,4,56,30,4,140,2,10,10,11,30,12,8,46,11,8,56,45,1,12,30,10,10,11,28,56,46,17,0,10,10,10,30,12,9,46,11,9,56,47,12,28,1,10,25,6,0,0,0,0,0,0,0,0,33,4,149,2,11,0,1,11,10,1,5,150,2,5,30,11,11,11,23,2,12,0,0,0,86,158,2,10,0,55,2,17,82,20,12,22,11,3,12,10,56,8,12,23,10,0,54,9,12,9,10,9,46,56,25,4,23,11,0,1,11,9,1,11,10,11,23,2,10,9,46,56,48,12,28,12,30,10,9,46,56,25,32,4,39,5,34,10,30,10,1,38,12,4,5,41,9,12,4,11,4,4,155,2,10,9,10,28,56,27,12,29,10,29,16,4,56,28,56,29,20,12,21,10,29,16,4,56,30,32,4,248,1,5,59,10,29,16,4,10,21,56,31,12,15,10,15,16,5,20,12,14,9,12,24,10,15,16,6,20,10,2,37,4,97,8,12,24,10,15,16,5,20,10,15,16,8,20,17,52,12,17,10,0,54,1,10,15,16,7,20,11,17,56,49,10,22,10,15,56,33,5,186,1,14,10,56,22,12,25,10,25,10,14,38,4,107,10,14,12,5,5,109,11,25,12,5,11,5,12,11,10,11,10,15,16,8,20,17,52,12,12,10,12,10,0,55,6,20,17,54,12,18,10,12,10,0,55,4,20,17,55,12,26,4,134,1,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,14,10,11,23,12,14,10,0,54,1,10,15,16,7,20,11,12,56,50,12,13,13,13,10,26,56,35,12,27,10,0,54,1,10,15,16,7,20,13,27,10,18,56,35,56,17,10,0,54,7,11,27,56,36,1,13,23,11,13,56,36,1,10,0,54,0,10,15,16,7,20,13,10,10,11,56,51,56,14,10,0,55,2,17,82,20,10,15,11,11,11,26,11,18,56,38,11,24,4,191,1,8,12,6,5,195,1,10,14,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,230,1,10,21,12,20,10,29,16,4,10,21,56,39,12,19,10,19,56,40,32,4,213,1,11,19,56,29,20,12,21,5,215,1,11,19,1,10,0,54,8,11,15,16,7,20,56,41,10,20,56,42,1,10,29,15,4,11,20,56,43,1,5,241,1,11,15,1,10,29,15,4,10,21,56,44,12,16,11,14,11,16,15,5,21,14,10,56,22,6,0,0,0,0,0,0,0,0,33,4,247,1,5,248,1,5,53,11,29,16,4,56,30,4,144,2,10,9,11,30,12,7,46,11,7,56,52,1,12,30,10,9,11,28,56,46,17,0,10,9,10,30,12,8,46,11,8,56,47,12,28,1,14,10,56,22,6,0,0,0,0,0,0,0,0,33,4,154,2,11,0,1,11,9,1,5,155,2,5,28,11,10,11,23,2,13,1,0,0,87,85,10,1,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,9,5,17,11,0,1,11,6,1,11,5,1,7,6,39,10,1,6,0,0,0,0,0,0,0,0,34,4,22,5,30,11,0,1,11,6,1,11,5,1,7,6,39,11,2,4,52,11,0,11,1,7,27,11,5,17,63,11,4,56,16,56,53,12,9,12,7,13,3,11,7,10,6,56,23,56,54,11,9,11,6,56,24,12,4,5,82,11,1,14,3,56,11,37,4,58,5,66,11,0,1,11,6,1,11,5,1,7,7,39,11,0,7,0,11,5,17,63,11,3,56,13,56,55,12,8,10,6,56,23,12,3,13,4,11,8,11,6,56,24,56,56,11,3,11,4,2,14,0,0,0,89,118,10,5,56,12,12,13,10,3,4,30,10,2,10,1,17,52,12,11,10,0,54,1,11,5,11,11,56,57,10,0,55,10,20,12,10,10,0,55,10,20,6,1,0,0,0,0,0,0,0,22,10,0,54,10,21,10,0,54,9,12,8,5,50,10,0,54,0,11,5,10,2,56,58,10,0,55,11,20,12,10,10,0,55,11,20,6,1,0,0,0,0,0,0,0,22,10,0,54,11,21,10,0,54,3,12,8,10,10,10,1,10,2,10,3,10,13,10,4,18,4,12,9,10,8,10,1,12,7,46,11,7,56,47,12,12,32,4,75,10,8,10,1,10,1,10,6,56,59,18,5,56,60,12,12,11,8,11,12,56,27,15,4,10,10,11,9,56,61,10,0,55,2,17,82,20,10,10,11,3,10,13,11,2,10,1,11,4,57,1,56,62,10,0,55,8,10,13,56,63,32,4,107,10,0,54,8,10,13,11,6,56,64,56,65,5,109,11,6,1,11,0,54,8,11,13,56,41,10,10,11,1,56,66,11,10,2,15,1,0,0,96,144,2,10,2,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,8,1,11,6,1,11,7,1,7,6,39,10,1,6,0,0,0,0,0,0,0,0,36,4,20,5,30,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,1,10,0,55,12,20,25,6,0,0,0,0,0,0,0,0,33,4,39,5,49,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,2,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,58,5,68,11,0,1,11,8,1,11,6,1,11,7,1,7,6,39,10,4,10,6,17,63,36,4,74,5,84,11,0,1,11,8,1,11,6,1,11,7,1,7,19,39,10,7,56,12,12,19,10,3,4,128,1,10,0,55,1,10,19,56,67,12,18,10,0,54,1,10,7,10,18,56,68,12,14,10,0,10,2,10,1,11,6,17,63,11,14,56,53,12,16,12,10,14,10,56,22,12,12,11,18,14,16,56,69,23,12,17,10,0,54,0,10,19,11,10,56,14,10,0,54,1,11,19,11,16,56,17,5,160,1,10,0,54,0,10,7,10,2,56,70,12,9,10,0,10,1,11,6,17,63,11,9,56,55,12,15,12,11,10,2,14,11,56,22,23,12,12,14,15,56,69,12,17,10,0,54,0,10,19,11,11,56,14,10,0,54,1,11,19,11,15,56,17,10,5,7,24,33,4,175,1,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,25,33,4,197,1,11,0,1,11,8,1,11,7,1,10,12,11,2,33,4,190,1,5,192,1,7,9,39,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,26,33,4,228,1,10,12,6,0,0,0,0,0,0,0,0,33,4,206,1,5,214,1,11,0,1,11,8,1,11,7,1,7,10,39,11,0,11,1,11,2,11,3,11,4,11,7,11,8,56,71,12,13,11,12,11,17,8,11,13,2,11,5,7,23,33,4,233,1,5,241,1,11,0,1,11,8,1,11,7,1,7,14,39,10,2,10,12,36,4,133,2,11,0,11,1,11,2,10,12,23,11,3,11,4,11,7,11,8,56,71,12,13,11,12,11,17,8,11,13,2,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,16,0,0,0,1,4,11,0,7,27,35,2,17,0,0,0,1,19,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,11,1,16,8,20,57,2,56,72,2,18,0,0,0,1,27,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,10,2,10,1,16,5,20,11,2,23,11,1,16,8,20,11,3,11,4,57,3,56,73,2,19,1,0,0,100,110,11,2,56,12,12,12,10,0,55,8,10,12,56,63,4,9,5,13,11,0,1,7,12,39,10,0,54,8,10,12,56,41,12,13,10,13,10,1,12,3,46,11,3,56,74,4,26,5,32,11,13,1,11,0,1,7,3,39,10,13,10,1,12,4,46,11,4,56,75,20,12,11,10,1,17,16,12,8,10,8,4,49,10,0,55,9,12,5,5,52,10,0,55,3,12,5,11,5,11,11,56,47,12,10,4,58,5,64,11,13,1,11,0,1,7,3,39,10,8,4,70,10,0,54,9,12,6,5,73,10,0,54,3,12,6,11,6,11,13,11,10,11,1,10,12,56,76,12,9,11,8,4,96,14,9,16,5,20,14,9,16,8,20,17,52,12,7,10,0,54,1,11,12,11,7,56,49,5,103,10,0,54,0,11,12,14,9,16,5,20,56,32,11,0,55,2,17,82,20,14,9,56,33,2,20,0,0,0,101,54,11,1,10,3,56,42,1,10,0,10,2,12,5,46,11,5,56,77,16,4,10,3,56,78,4,15,5,19,11,0,1,7,3,39,10,0,10,2,56,27,12,6,10,6,15,4,11,3,56,43,12,7,14,7,16,7,20,11,4,33,4,35,5,41,11,0,1,11,6,1,7,4,39,11,6,16,4,56,30,4,50,11,0,11,2,56,46,17,0,5,52,11,0,1,11,7,2,21,1,0,0,102,104,10,0,55,2,17,82,20,12,11,11,1,56,12,12,13,10,0,55,8,10,13,56,63,4,14,5,18,11,0,1,7,12,39,10,0,54,8,10,13,56,41,12,14,10,14,46,56,79,32,4,99,5,29,10,14,46,56,80,56,29,20,12,9,10,14,10,9,12,2,46,11,2,56,75,20,12,10,10,9,17,16,12,6,10,6,4,52,10,0,54,9,12,3,5,55,10,0,54,3,12,3,11,3,12,7,10,7,11,10,12,4,46,11,4,56,47,12,12,1,11,7,10,14,11,12,11,9,10,13,56,76,12,8,11,6,4,88,14,8,16,5,20,14,8,16,8,20,17,52,12,5,10,0,54,1,10,13,11,5,56,49,5,95,10,0,54,0,10,13,14,8,16,5,20,56,32,10,11,14,8,56,33,5,23,11,14,1,11,0,1,2,22,1,0,0,103,148,1,10,0,55,2,17,82,20,12,15,11,2,56,12,12,18,10,0,55,8,10,18,56,63,4,14,5,18,11,0,1,6,0,0,0,0,0,0,0,0,39,6,0,0,0,0,0,0,0,0,12,16,6,0,0,0,0,0,0,0,0,12,17,14,1,65,20,12,10,6,0,0,0,0,0,0,0,0,12,8,10,0,54,8,10,18,56,41,12,19,10,8,10,10,35,4,143,1,5,37,14,1,10,8,66,20,20,12,14,10,19,10,14,12,3,46,11,3,56,74,4,50,5,56,11,19,1,11,0,1,7,3,39,10,19,10,14,12,4,46,11,4,56,75,20,12,12,10,14,17,16,12,9,10,12,10,17,34,4,96,11,12,12,17,10,9,4,79,10,0,55,9,12,5,5,82,10,0,55,3,12,5,11,5,10,17,56,47,12,11,4,88,5,94,11,19,1,11,0,1,7,11,39,11,11,12,16,10,9,4,102,10,0,54,9,12,6,5,105,10,0,54,3,12,6,11,6,10,19,10,16,11,14,10,18,56,76,12,13,11,9,4,128,1,14,13,16,5,20,14,13,16,8,20,17,52,12,7,10,0,54,1,10,18,11,7,56,49,5,135,1,10,0,54,0,10,18,14,13,16,5,20,56,32,10,15,14,13,56,33,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,32,11,19,1,11,0,1,2,23,1,0,0,104,84,11,1,56,12,12,7,10,0,55,8,11,7,56,81,12,8,64,28,0,0,0,0,0,0,0,0,12,3,10,8,56,82,12,5,10,5,56,40,32,4,76,5,18,10,8,10,5,56,29,20,56,75,20,12,6,10,5,56,29,20,17,16,4,36,10,0,55,9,11,6,56,83,12,2,5,41,10,0,55,3,11,6,56,83,12,2,11,2,16,4,10,5,56,29,20,56,31,12,4,13,3,10,4,16,18,20,10,4,16,8,20,10,4,16,5,20,10,4,16,19,20,10,4,16,7,20,11,4,16,6,20,18,4,68,28,10,8,11,5,56,29,20,56,84,12,5,5,13,11,8,1,11,0,1,11,5,1,11,3,2,24,1,0,0,105,20,11,1,56,12,12,6,10,0,55,0,10,6,56,85,12,3,12,2,11,0,55,1,11,6,56,86,12,5,12,4,11,2,11,3,11,4,11,5,2,25,1,0,0,35,13,10,0,55,9,56,48,1,12,2,11,0,55,3,56,26,1,12,1,11,2,11,1,2,26,1,0,0,106,86,10,0,55,9,56,26,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,9,56,48,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,9,11,1,56,87,12,1,10,0,55,9,11,2,56,87,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,9,10,1,10,3,17,63,56,88,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,9,11,1,56,45,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,27,1,0,0,106,86,10,0,55,3,56,26,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,3,56,48,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,3,11,1,56,87,12,1,10,0,55,3,11,2,56,87,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,3,10,1,10,3,17,63,56,88,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,3,11,1,56,45,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,28,0,0,0,107,49,11,0,11,1,56,83,16,4,12,6,6,0,0,0,0,0,0,0,0,12,3,10,6,56,28,12,5,10,5,56,40,32,4,43,5,15,10,6,10,5,56,29,20,56,31,12,4,10,4,16,6,20,10,2,36,4,34,11,3,11,4,16,5,20,22,12,3,5,36,11,4,1,10,6,11,5,56,29,20,56,39,12,5,5,10,11,6,1,11,5,1,11,3,2,29,1,0,0,108,52,11,2,56,12,12,5,10,0,55,8,10,5,56,63,4,9,5,13,11,0,1,7,12,39,10,0,55,8,11,5,56,81,12,6,10,6,10,1,56,74,4,23,5,29,11,6,1,11,0,1,7,3,39,11,6,10,1,56,75,20,12,4,10,1,7,27,35,4,42,11,0,55,9,12,3,5,45,11,0,55,3,12,3,11,3,11,4,56,83,16,4,11,1,56,31,2,6,10,6,11,6,0,6,2,5,1,4,2,4,5,4,4,4,1,6,6,6,9,6,7,6,14,6,5,6,1,6,3,6,4,6,8,4,0,4,3,0,56,1,56,2,56,3,56,9,56,10,56,11,56,12,56,13,56,14,56,15,56,16,56,17,56,0],"clob_v2":[161,28,235,11,6,0,0,0,13,1,0,40,2,40,146,1,3,186,1,246,4,4,176,6,202,1,5,250,7,210,12,7,204,20,130,17,8,206,37,96,6,174,38,157,2,10,203,40,131,2,11,206,42,20,12,226,42,169,51,13,139,94,46,14,185,94,26,0,50,0,59,0,60,0,102,1,115,1,150,1,1,158,1,2,31,2,51,2,52,2,70,2,91,2,113,2,138,1,2,141,1,2,148,1,2,149,1,0,17,7,0,0,15,7,2,0,1,0,1,0,13,7,2,0,1,0,1,0,2,7,2,0,1,0,1,0,1,7,2,0,1,0,1,0,14,7,2,0,1,0,1,0,8,7,1,0,1,0,24,7,1,0,1,0,12,6,0,0,20,4,0,0,16,8,2,0,1,0,1,1,6,4,1,4,0,2,0,12,0,2,7,12,1,0,1,4,11,7,1,0,0,5,22,7,0,7,3,4,1,0,1,8,4,8,0,9,5,12,1,0,1,11,10,12,2,7,0,4,1,12,9,7,0,12,23,4,0,13,18,2,0,14,19,12,2,7,1,4,1,16,21,2,0,0,66,0,1,0,0,54,2,3,0,0,57,4,1,2,0,0,0,56,5,1,2,0,0,0,55,6,1,2,0,0,0,63,7,1,2,0,0,0,64,8,1,2,0,0,0,160,1,9,10,2,0,0,0,161,1,9,11,2,0,0,0,139,1,12,13,2,0,0,0,140,1,14,13,2,0,0,0,101,15,16,2,0,0,0,100,15,16,2,0,0,0,99,17,16,2,0,0,0,122,18,19,2,0,0,0,84,20,21,2,0,0,0,121,22,23,2,0,0,0,117,21,24,0,0,68,25,1,2,0,0,0,69,26,1,2,0,0,0,47,27,1,2,0,0,0,133,1,28,29,2,0,0,0,46,30,1,2,0,0,0,39,31,1,2,0,0,0,48,32,1,2,0,0,0,92,33,34,2,0,0,0,26,33,35,2,0,0,0,80,36,37,2,0,0,0,79,38,39,2,0,0,0,78,38,39,2,0,0,0,77,40,21,2,0,0,0,81,41,42,2,0,0,1,42,94,84,1,4,1,43,94,84,1,4,1,45,80,81,1,4,1,72,94,21,1,4,1,73,94,88,1,4,1,85,104,21,1,4,1,88,78,24,1,4,1,103,78,50,1,4,1,104,78,50,1,4,1,107,2,54,1,4,1,111,94,50,1,4,1,124,94,50,1,4,1,132,1,80,47,1,4,2,25,110,21,1,0,2,26,110,50,1,0,2,27,64,65,0,2,61,103,58,1,0,2,62,87,58,1,0,2,83,66,1,1,0,2,93,103,1,1,0,2,105,2,3,0,2,107,2,57,1,0,2,152,1,87,1,1,0,2,159,1,70,10,1,0,3,106,50,21,0,3,153,1,50,21,0,3,154,1,50,21,0,3,155,1,50,88,0,4,41,83,84,1,0,4,89,83,24,1,0,4,112,1,123,1,0,4,136,1,47,123,1,0,5,76,1,48,1,0,6,88,95,24,1,0,7,90,90,21,1,0,7,137,1,89,58,1,0,7,157,1,75,21,1,0,7,162,1,1,58,1,0,8,147,1,74,21,0,9,74,76,10,1,0,9,86,10,58,1,0,9,90,100,1,1,0,9,137,1,101,10,1,0,9,157,1,63,21,1,0,10,67,47,1,1,3,11,30,82,83,2,7,4,11,41,85,86,2,7,4,11,44,93,92,2,7,4,11,53,85,24,2,7,4,11,65,45,1,2,7,4,11,75,82,83,2,7,4,11,88,82,24,2,7,4,11,107,2,45,2,7,4,11,108,85,83,2,7,4,11,126,105,1,2,7,4,11,131,1,93,49,2,7,4,12,107,2,51,0,12,151,1,52,53,0,14,28,108,1,2,7,4,14,41,107,86,2,7,4,14,44,91,92,2,7,4,14,53,107,24,2,7,4,14,107,2,56,2,7,4,15,135,1,47,1,1,8,81,44,64,47,64,49,41,0,94,55,53,47,53,49,69,47,69,49,95,60,76,61,75,62,4,59,72,62,2,59,75,47,72,47,50,47,76,67,75,49,72,49,50,49,76,68,76,69,55,47,76,71,55,49,14,59,11,59,68,47,71,47,71,49,38,0,40,0,34,0,82,44,60,21,83,44,78,44,54,47,18,59,49,47,67,49,66,49,66,47,19,59,85,44,61,21,92,55,87,50,87,44,79,44,42,0,44,0,36,0,65,79,76,96,39,0,54,49,49,49,67,47,43,0,12,59,73,47,74,47,13,59,73,49,51,49,51,47,84,44,37,0,86,44,76,106,93,55,84,50,90,55,86,50,45,49,48,49,68,49,48,47,15,59,76,112,76,114,80,50,78,50,21,59,32,0,80,44,83,50,77,50,91,55,82,50,33,0,85,50,46,47,46,49,63,21,62,21,35,0,30,59,1,8,9,0,1,7,8,24,1,8,12,6,3,3,3,3,11,16,1,8,22,7,8,24,4,3,3,11,18,1,8,22,7,8,24,6,3,3,3,3,11,18,1,8,22,7,8,24,3,7,11,10,2,9,0,9,1,11,18,1,9,0,6,8,12,3,7,11,10,2,9,0,9,1,11,18,1,9,1,6,8,12,4,7,11,10,2,9,0,9,1,3,6,8,12,7,8,24,1,11,18,1,9,0,1,11,18,1,9,1,8,7,11,10,2,9,0,9,1,3,6,8,12,3,11,18,1,9,0,11,18,1,9,1,6,8,17,7,8,24,3,11,18,1,9,0,11,18,1,9,1,3,7,7,11,10,2,9,0,9,1,3,6,8,12,3,6,8,17,11,18,1,9,1,7,8,24,7,7,11,10,2,9,0,9,1,6,8,12,3,3,3,3,11,16,1,9,1,2,11,16,1,9,0,11,16,1,9,1,6,7,11,10,2,9,0,9,1,6,8,12,3,3,3,11,16,1,9,0,9,7,11,10,2,9,0,9,1,6,8,12,3,3,1,11,18,1,9,0,11,18,1,9,1,6,8,17,7,8,24,2,11,18,1,9,0,11,18,1,9,1,10,7,11,10,2,9,0,9,1,3,3,3,3,1,2,3,6,8,12,7,8,24,1,3,11,7,11,10,2,9,0,9,1,3,3,3,2,1,3,2,6,8,17,6,8,12,7,8,24,4,3,3,1,3,1,1,2,8,20,6,8,8,7,8,20,3,5,6,8,8,3,3,3,3,7,11,10,2,9,0,9,1,3,6,8,12,5,7,11,11,1,8,9,7,11,19,2,3,3,3,3,5,1,8,8,2,7,11,10,2,9,0,9,1,6,8,12,3,7,11,10,2,9,0,9,1,10,3,6,8,12,4,7,11,10,2,9,0,9,1,6,8,17,10,3,10,5,2,6,11,10,2,9,0,9,1,6,8,12,1,10,8,8,4,3,3,3,3,1,6,11,10,2,9,0,9,1,2,11,14,1,3,11,14,1,3,4,6,11,10,2,9,0,9,1,3,3,6,8,17,2,10,3,10,3,3,6,11,11,1,8,9,3,3,3,6,11,10,2,9,0,9,1,3,6,8,12,1,6,8,8,1,11,19,2,3,8,8,2,3,8,8,1,11,19,2,9,0,9,1,4,8,15,8,20,8,21,8,15,1,9,0,1,8,15,1,9,1,2,3,3,1,8,21,1,6,8,21,1,6,8,20,1,11,11,1,9,0,2,5,11,19,2,3,3,1,11,23,2,9,0,9,1,1,11,13,1,9,0,1,11,16,1,9,0,2,9,0,9,1,1,11,10,2,9,0,9,1,1,8,0,1,8,22,1,6,11,18,1,9,0,1,6,8,12,1,5,3,7,11,13,1,9,0,5,11,16,1,9,0,1,11,6,1,9,0,1,11,6,1,9,1,1,11,7,1,9,0,4,7,11,13,1,9,0,3,6,8,12,7,8,24,1,11,7,1,9,1,4,3,11,18,1,9,0,11,18,1,9,1,3,3,11,16,1,9,0,11,16,1,9,1,3,1,6,8,17,1,6,11,16,1,9,0,2,11,16,1,9,0,7,8,24,40,1,1,3,3,1,3,3,1,5,3,3,3,7,11,11,1,8,9,11,16,1,9,0,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,3,3,11,16,1,9,0,3,6,8,8,7,8,8,3,3,3,6,11,14,1,3,3,3,8,20,11,16,1,9,1,11,16,1,9,1,1,3,3,3,1,3,7,8,9,3,1,6,11,11,1,9,0,1,11,3,2,9,0,9,1,2,7,11,11,1,9,0,3,1,7,9,0,1,6,11,19,2,9,0,9,1,1,6,11,14,1,9,0,1,6,9,0,2,6,11,19,2,9,0,9,1,9,0,1,6,9,1,3,7,11,13,1,9,0,5,3,2,1,3,2,7,11,16,1,9,0,3,2,7,11,16,1,9,0,11,16,1,9,0,2,7,11,23,2,9,0,9,1,9,0,1,7,9,1,2,7,11,19,2,9,0,9,1,9,0,2,6,11,11,1,9,0,3,1,6,10,9,0,1,11,4,2,9,0,9,1,36,1,3,1,3,3,1,3,3,1,5,3,3,3,7,11,11,1,8,9,11,16,1,9,0,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,3,11,16,1,9,0,3,6,8,8,7,8,8,3,6,11,14,1,3,3,3,8,20,11,16,1,9,1,1,3,3,11,16,1,9,1,3,7,8,9,3,37,1,3,1,3,3,1,3,3,1,5,3,3,3,7,11,11,1,8,9,11,16,1,9,0,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,3,11,16,1,9,1,3,6,8,8,7,8,8,3,3,6,11,14,1,3,3,3,8,20,11,16,1,9,1,1,3,3,11,16,1,9,1,3,7,8,9,3,5,11,16,1,9,0,11,16,1,9,0,11,18,1,9,0,11,16,1,9,1,11,16,1,9,1,2,7,11,18,1,9,0,11,18,1,9,0,3,7,11,18,1,9,0,3,7,8,24,7,3,7,11,11,1,8,9,8,8,3,5,3,3,3,7,11,13,1,9,0,6,8,12,3,3,7,11,11,1,9,0,3,9,0,3,7,11,19,2,9,0,9,1,9,0,9,1,1,11,1,2,9,0,9,1,2,6,11,23,2,9,0,9,1,9,0,3,7,11,23,2,9,0,9,1,9,0,9,1,12,11,16,1,9,0,11,16,1,9,0,11,16,1,9,0,3,3,3,5,11,16,1,9,1,11,16,1,9,1,11,16,1,9,1,3,3,2,6,11,13,1,9,0,5,8,8,20,3,3,1,5,3,3,3,1,11,2,2,9,0,9,1,13,8,20,3,3,3,3,3,3,5,3,1,5,3,3,1,11,5,2,9,0,9,1,11,3,3,6,11,11,1,8,9,7,11,11,1,8,9,3,1,8,8,5,3,3,7,11,19,2,3,3,3,3,7,8,9,8,8,22,3,3,3,3,7,11,11,1,8,9,3,3,3,1,5,3,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,1,7,11,11,1,8,9,8,8,3,3,5,8,20,3,7,11,19,2,3,3,26,5,3,3,3,3,3,6,11,11,1,8,9,7,11,11,1,8,9,3,3,1,3,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,1,3,3,3,8,8,3,5,8,20,3,3,7,11,19,2,3,3,28,1,5,3,3,3,3,3,7,11,11,1,8,9,3,3,3,3,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,1,3,3,3,3,7,11,11,1,8,9,8,8,3,5,8,20,3,3,7,11,19,2,3,3,7,6,8,9,10,8,8,6,8,8,6,11,14,1,3,3,5,6,11,19,2,3,3,5,3,3,5,3,3,4,11,14,1,3,11,14,1,3,11,14,1,3,11,14,1,3,1,11,14,1,9,0,6,3,10,3,3,3,3,10,3,4,3,6,8,8,6,11,14,1,3,6,11,19,2,3,8,8,4,6,11,11,1,8,9,3,5,6,11,19,2,3,3,10,65,99,99,111,117,110,116,67,97,112,17,65,108,108,79,114,100,101,114,115,67,97,110,99,101,108,101,100,26,65,108,108,79,114,100,101,114,115,67,97,110,99,101,108,101,100,67,111,109,112,111,110,101,110,116,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,11,67,114,105,116,98,105,116,84,114,101,101,9,67,117,115,116,111,100,105,97,110,12,68,101,112,111,115,105,116,65,115,115,101,116,2,73,68,11,76,105,110,107,101,100,84,97,98,108,101,6,79,112,116,105,111,110,5,79,114,100,101,114,13,79,114,100,101,114,67,97,110,99,101,108,101,100,11,79,114,100,101,114,70,105,108,108,101,100,11,79,114,100,101,114,80,108,97,99,101,100,4,80,111,111,108,11,80,111,111,108,67,114,101,97,116,101,100,3,83,85,73,5,84,97,98,108,101,9,84,105,99,107,76,101,118,101,108,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,13,87,105,116,104,100,114,97,119,65,115,115,101,116,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,13,97,99,99,111,117,110,116,95,111,119,110,101,114,3,97,100,100,4,97,115,107,115,4,98,97,99,107,7,98,97,108,97,110,99,101,10,98,97,115,101,95,97,115,115,101,116,28,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,99,97,110,99,101,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,102,105,108,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,112,108,97,99,101,100,29,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,114,101,109,97,105,110,105,110,103,23,98,97,115,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,14,98,97,115,101,95,99,117,115,116,111,100,105,97,110,18,98,97,116,99,104,95,99,97,110,99,101,108,95,111,114,100,101,114,4,98,105,100,115,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,17,99,97,110,99,101,108,95,97,108,108,95,111,114,100,101,114,115,12,99,97,110,99,101,108,95,111,114,100,101,114,23,99,108,101,97,110,95,117,112,95,101,120,112,105,114,101,100,95,111,114,100,101,114,115,15,99,108,105,101,110,116,95,111,114,100,101,114,95,105,100,7,99,108,111,98,95,118,50,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,14,99,114,101,97,116,101,95,97,99,99,111,117,110,116,22,99,114,101,97,116,101,95,99,117,115,116,111,109,105,122,101,100,95,112,111,111,108,11,99,114,101,97,116,101,95,112,111,111,108,12,99,114,101,97,116,101,95,112,111,111,108,95,12,99,114,101,97,116,105,111,110,95,102,101,101,7,99,114,105,116,98,105,116,12,99,117,115,116,111,100,105,97,110,95,118,50,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,100,101,112,111,115,105,116,95,98,97,115,101,13,100,101,112,111,115,105,116,95,113,117,111,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,19,100,101,115,116,114,111,121,95,101,109,112,116,121,95,108,101,118,101,108,4,101,109,105,116,19,101,109,105,116,95,111,114,100,101,114,95,99,97,110,99,101,108,101,100,17,101,109,105,116,95,111,114,100,101,114,95,102,105,108,108,101,100,5,101,118,101,110,116,16,101,120,112,105,114,101,95,116,105,109,101,115,116,97,109,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,12,102,114,111,109,95,98,97,108,97,110,99,101,5,102,114,111,110,116,3,103,101,116,22,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,97,115,107,95,115,105,100,101,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,98,105,100,95,115,105,100,101,16,103,101,116,95,109,97,114,107,101,116,95,112,114,105,99,101,16,103,101,116,95,111,114,100,101,114,95,115,116,97,116,117,115,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,18,105,110,106,101,99,116,95,108,105,109,105,116,95,111,114,100,101,114,11,105,110,115,101,114,116,95,108,101,97,102,12,105,110,116,111,95,98,97,108,97,110,99,101,6,105,115,95,98,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,4,106,111,105,110,12,108,105,110,107,101,100,95,116,97,98,108,101,16,108,105,115,116,95,111,112,101,110,95,111,114,100,101,114,115,12,108,111,99,107,95,98,97,108,97,110,99,101,8,108,111,116,95,115,105,122,101,13,109,97,107,101,114,95,97,100,100,114,101,115,115,21,109,97,107,101,114,95,99,108,105,101,110,116,95,111,114,100,101,114,95,105,100,17,109,97,107,101,114,95,114,101,98,97,116,101,95,114,97,116,101,13,109,97,107,101,114,95,114,101,98,97,116,101,115,9,109,97,116,99,104,95,97,115,107,9,109,97,116,99,104,95,98,105,100,29,109,97,116,99,104,95,98,105,100,95,119,105,116,104,95,113,117,111,116,101,95,113,117,97,110,116,105,116,121,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,109,117,108,3,110,101,119,4,110,101,120,116,17,110,101,120,116,95,97,115,107,95,111,114,100,101,114,95,105,100,17,110,101,120,116,95,98,105,100,95,111,114,100,101,114,95,105,100,9,110,101,120,116,95,108,101,97,102,4,110,111,110,101,6,111,98,106,101,99,116,11,111,112,101,110,95,111,114,100,101,114,115,6,111,112,116,105,111,110,8,111,114,100,101,114,95,105,100,12,111,114,100,101,114,95,105,115,95,98,105,100,15,111,114,100,101,114,115,95,99,97,110,99,101,108,101,100,17,111,114,105,103,105,110,97,108,95,113,117,97,110,116,105,116,121,5,111,119,110,101,114,17,112,108,97,99,101,95,108,105,109,105,116,95,111,114,100,101,114,18,112,108,97,99,101,95,109,97,114,107,101,116,95,111,114,100,101,114,7,112,111,111,108,95,105,100,13,112,114,101,118,105,111,117,115,95,108,101,97,102,5,112,114,105,99,101,9,112,117,115,104,95,98,97,99,107,8,113,117,97,110,116,105,116,121,11,113,117,111,116,101,95,97,115,115,101,116,24,113,117,111,116,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,15,113,117,111,116,101,95,99,117,115,116,111,100,105,97,110,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,12,114,101,109,111,118,101,95,111,114,100,101,114,24,115,101,108,102,95,109,97,116,99,104,105,110,103,95,112,114,101,118,101,110,116,105,111,110,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,115,112,108,105,116,3,115,117,105,25,115,119,97,112,95,101,120,97,99,116,95,98,97,115,101,95,102,111,114,95,113,117,111,116,101,25,115,119,97,112,95,101,120,97,99,116,95,113,117,111,116,101,95,102,111,114,95,98,97,115,101,5,116,97,98,108,101,13,116,97,107,101,114,95,97,100,100,114,101,115,115,21,116,97,107,101,114,95,99,108,105,101,110,116,95,111,114,100,101,114,95,105,100,16,116,97,107,101,114,95,99,111,109,109,105,115,115,105,111,110,14,116,97,107,101,114,95,102,101,101,95,114,97,116,101,9,116,105,99,107,95,115,105,122,101,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,10,117,110,115,97,102,101,95,100,105,118,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,15,117,115,114,95,111,112,101,110,95,111,114,100,101,114,115,5,118,97,108,117,101,6,118,101,99,116,111,114,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,13,119,105,116,104,100,114,97,119,95,98,97,115,101,14,119,105,116,104,100,114,97,119,95,113,117,111,116,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,3,8,19,0,0,0,0,0,0,0,3,8,20,0,0,0,0,0,0,0,3,8,21,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,2,1,0,2,1,4,2,1,1,2,1,2,2,1,3,3,8,0,0,0,0,0,0,0,128,3,8,0,0,0,0,0,0,0,0,3,8,160,37,38,0,0,0,0,0,3,8,96,227,22,0,0,0,0,0,3,8,0,232,118,72,23,0,0,0,0,2,7,123,8,20,32,8,15,128,1,8,15,145,1,3,97,3,146,1,3,94,3,1,2,9,123,8,20,116,3,49,3,87,1,120,5,119,3,35,3,125,3,71,3,2,2,8,123,8,20,116,3,49,3,87,1,120,5,119,3,33,3,125,3,3,2,7,116,3,49,3,87,1,120,5,119,3,33,3,125,3,4,2,2,123,8,20,118,10,11,3,2,9,0,9,1,5,2,13,123,8,20,116,3,143,1,3,96,3,87,1,142,1,5,95,5,119,3,34,3,36,3,125,3,144,1,3,98,3,6,2,3,123,8,20,127,3,120,5,7,2,3,123,8,20,127,3,120,5,8,2,9,116,3,49,3,125,3,119,3,127,3,87,1,120,5,71,3,134,1,2,9,2,2,125,3,114,11,19,2,3,8,8,10,2,15,82,8,21,40,11,11,1,8,9,29,11,11,1,8,9,110,3,109,3,156,1,11,23,2,5,11,19,2,3,3,145,1,3,97,3,146,1,3,94,3,38,11,13,1,9,0,130,1,11,13,1,9,1,58,11,16,1,8,22,37,11,16,1,9,0,129,1,11,16,1,9,1,10,59,6,47,6,49,7,47,7,49,3,59,4,59,1,59,2,59,5,59,0,0,0,0,43,7,11,0,19,9,12,1,1,11,1,56,0,2,1,1,0,0,1,3,11,0,17,52,2,2,0,0,0,46,72,56,1,12,6,56,2,12,9,10,3,10,2,17,58,6,0,0,0,0,0,0,0,0,36,4,11,5,15,11,5,1,7,19,39,10,6,10,9,34,4,20,5,24,11,5,1,7,15,39,10,0,10,1,38,4,29,5,33,11,5,1,7,1,39,10,5,17,88,12,8,14,8,17,89,20,12,7,11,8,10,5,56,3,10,5,56,3,7,0,7,27,10,5,56,4,10,0,10,1,10,2,10,3,10,5,56,5,11,5,56,6,11,4,56,7,56,8,57,0,56,9,11,7,11,6,11,9,11,0,11,1,11,2,11,3,18,0,56,10,2,3,1,0,0,1,18,14,2,56,11,7,31,33,4,6,5,10,11,3,1,7,17,39,11,0,11,1,7,29,7,30,11,2,11,3,56,12,2,4,1,0,0,1,19,14,4,56,11,7,31,33,4,6,5,10,11,5,1,7,17,39,11,2,11,3,11,0,11,1,11,4,56,13,11,5,56,14,2,5,1,0,0,21,31,14,1,56,15,12,3,10,3,6,0,0,0,0,0,0,0,0,34,4,8,5,14,11,0,1,11,2,1,7,6,39,10,0,54,0,10,2,17,47,11,1,56,16,56,17,11,0,55,1,17,89,20,11,3,11,2,17,47,57,1,56,18,2,6,1,0,0,21,31,14,1,56,19,12,3,10,3,6,0,0,0,0,0,0,0,0,34,4,8,5,14,11,0,1,11,2,1,7,7,39,10,0,54,2,10,2,17,47,11,1,56,20,56,21,11,0,55,1,17,89,20,11,3,11,2,17,47,57,2,56,22,2,7,1,0,0,1,29,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,10,0,55,1,17,89,20,10,1,10,2,17,47,57,3,56,23,11,0,54,0,11,1,11,2,11,3,56,24,2,8,1,0,0,1,29,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,10,0,55,1,17,89,20,10,1,10,2,17,47,57,4,56,25,11,0,54,2,11,1,11,2,11,3,56,26,2,9,1,0,0,72,55,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,7,1,11,6,1,11,2,1,7,5,39,14,4,56,15,10,3,38,4,21,5,31,11,0,1,11,7,1,11,6,1,11,2,1,7,6,39,14,5,56,19,12,8,11,0,11,2,11,1,11,3,9,11,4,11,5,11,6,11,7,56,27,12,10,12,9,14,10,56,19,12,11,11,9,11,10,11,11,11,8,23,2,10,1,0,0,73,54,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,6,1,11,4,1,11,2,1,7,5,39,14,5,56,19,10,3,38,4,21,5,31,11,0,1,11,6,1,11,4,1,11,2,1,7,7,39,11,0,11,2,11,1,11,3,7,27,11,4,17,70,11,5,56,20,56,28,12,8,12,7,14,7,56,29,12,9,11,7,10,6,56,30,11,8,11,6,56,31,11,9,2,11,0,0,0,77,134,3,10,0,55,1,17,89,20,12,36,11,3,12,42,56,7,12,20,11,6,12,38,10,0,54,3,12,19,10,19,46,56,32,4,27,11,0,1,11,19,1,11,1,1,11,20,11,38,2,10,19,46,56,33,12,44,12,46,9,12,43,64,79,0,0,0,0,0,0,0,0,12,22,10,19,46,56,32,32,4,47,5,42,10,46,10,4,37,12,7,5,49,9,12,7,11,7,4,251,2,10,19,10,44,56,34,12,45,10,45,16,4,56,35,56,36,20,12,35,10,45,16,4,56,37,32,4,217,2,5,67,10,45,16,4,10,35,56,38,12,28,10,28,16,5,20,12,27,9,12,39,10,28,16,6,20,10,5,37,4,87,8,12,11,5,94,10,1,17,47,10,28,16,7,20,33,12,11,11,11,4,151,1,8,12,39,10,0,54,0,10,28,16,7,20,10,28,16,5,20,56,39,10,36,10,28,56,40,10,28,16,8,20,12,12,10,28,16,9,20,12,13,10,28,16,10,20,12,14,10,28,16,7,20,12,15,10,28,16,11,20,12,16,10,28,16,5,20,12,17,10,28,16,12,20,12,18,11,13,11,12,11,14,11,15,11,16,11,17,11,18,57,5,12,21,13,22,11,21,68,79,5,158,2,10,27,10,28,16,12,20,17,56,12,31,10,31,10,0,55,4,20,17,59,12,40,4,168,1,11,40,6,1,0,0,0,0,0,0,0,22,12,40,10,31,11,40,22,12,30,10,42,10,30,36,4,183,1,11,30,12,24,11,31,12,25,10,27,12,23,5,226,1,8,12,43,10,42,7,21,10,0,55,4,20,22,17,57,10,28,16,12,20,17,57,10,0,55,5,20,26,10,0,55,5,20,24,12,23,10,23,10,28,16,12,20,17,58,12,25,10,25,10,0,55,4,20,17,59,12,41,4,222,1,11,41,6,1,0,0,0,0,0,0,0,22,12,41,10,25,11,41,22,12,24,10,25,10,0,55,6,20,17,58,12,32,11,27,10,23,23,12,27,11,42,10,24,23,12,42,10,0,54,0,10,28,16,7,20,10,23,56,41,12,26,13,38,10,24,56,42,12,37,10,0,54,2,10,28,16,7,20,13,37,10,32,10,25,22,56,42,56,21,10,0,54,7,11,37,56,43,1,13,20,11,26,56,44,1,10,0,55,1,17,89,20,10,2,10,1,17,47,10,28,11,23,11,24,11,25,23,11,32,56,45,11,39,4,163,2,8,12,8,5,167,2,10,27,6,0,0,0,0,0,0,0,0,33,12,8,11,8,4,202,2,10,35,12,34,10,45,16,4,10,35,56,46,12,33,10,33,56,47,32,4,185,2,11,33,56,36,20,12,35,5,187,2,11,33,1,10,0,54,8,11,28,16,7,20,56,48,10,34,56,49,1,10,45,15,4,11,34,56,50,1,5,213,2,11,28,1,10,45,15,4,10,35,56,51,12,29,11,27,11,29,15,5,21,10,43,4,216,2,5,217,2,5,61,11,45,16,4,56,37,4,241,2,10,19,11,46,12,9,46,11,9,56,52,1,12,46,10,19,11,44,56,53,17,0,10,19,10,46,12,10,46,11,10,56,54,12,44,1,10,43,4,250,2,11,0,1,11,19,1,11,1,1,5,251,2,5,36,14,22,56,55,32,4,131,3,11,36,11,22,57,6,56,56,11,20,11,38,2,12,0,0,0,97,222,2,10,0,55,1,17,89,20,12,34,11,3,12,37,56,7,12,21,11,6,12,35,10,0,54,3,12,20,10,20,46,56,32,4,27,11,0,1,11,20,1,11,1,1,11,21,11,35,2,10,20,46,56,33,12,40,12,42,64,79,0,0,0,0,0,0,0,0,12,23,10,20,46,56,32,32,4,45,5,40,10,42,10,4,37,12,7,5,47,9,12,7,11,7,4,211,2,10,20,10,40,56,34,12,41,10,41,16,4,56,35,56,36,20,12,33,10,41,16,4,56,37,32,4,175,2,5,65,10,41,16,4,10,33,56,38,12,28,10,28,16,5,20,12,27,9,12,36,10,28,16,6,20,10,5,37,4,85,8,12,12,5,92,10,1,17,47,10,28,16,7,20,33,12,12,11,12,4,149,1,8,12,36,10,0,54,0,10,28,16,7,20,10,28,16,5,20,56,39,10,34,10,28,56,40,10,28,16,8,20,12,13,10,28,16,9,20,12,14,10,28,16,10,20,12,15,10,28,16,7,20,12,16,10,28,16,11,20,12,17,10,28,16,5,20,12,18,10,28,16,12,20,12,19,11,14,11,13,11,15,11,16,11,17,11,18,11,19,57,5,12,22,13,23,11,22,68,79,5,242,1,10,37,10,27,36,4,156,1,10,27,12,8,5,158,1,10,37,12,8,11,8,12,24,10,24,10,28,16,12,20,17,56,12,25,10,25,10,0,55,6,20,17,58,12,30,10,25,10,0,55,4,20,17,59,12,38,4,183,1,11,38,6,1,0,0,0,0,0,0,0,22,12,38,11,27,10,24,23,12,27,11,37,10,24,23,12,37,10,0,54,0,10,28,16,7,20,10,24,56,41,12,26,13,35,10,38,56,42,12,39,10,0,54,2,10,28,16,7,20,13,39,10,30,56,42,56,21,10,0,54,7,11,39,56,43,1,13,21,11,26,56,44,1,10,0,54,2,10,28,16,7,20,13,35,11,25,56,42,56,21,10,0,55,1,17,89,20,10,2,10,1,17,47,10,28,11,24,11,38,11,30,56,45,11,36,4,247,1,8,12,9,5,251,1,10,27,6,0,0,0,0,0,0,0,0,33,12,9,11,9,4,158,2,10,33,12,32,10,41,16,4,10,33,56,46,12,31,10,31,56,47,32,4,141,2,11,31,56,36,20,12,33,5,143,2,11,31,1,10,0,54,8,11,28,16,7,20,56,48,10,32,56,49,1,10,41,15,4,11,32,56,50,1,5,169,2,11,28,1,10,41,15,4,10,33,56,51,12,29,11,27,11,29,15,5,21,10,37,6,0,0,0,0,0,0,0,0,33,4,174,2,5,175,2,5,59,11,41,16,4,56,37,4,199,2,10,20,11,42,12,10,46,11,10,56,52,1,12,42,10,20,11,40,56,53,17,0,10,20,10,42,12,11,46,11,11,56,54,12,40,1,10,37,6,0,0,0,0,0,0,0,0,33,4,210,2,11,0,1,11,20,1,11,1,1,5,211,2,5,34,14,23,56,55,32,4,219,2,11,34,11,23,57,6,56,56,11,21,11,35,2,13,0,0,0,98,227,2,10,0,55,1,17,89,20,12,34,11,5,12,20,56,8,12,35,10,0,54,9,12,19,10,19,46,56,32,4,25,11,0,1,11,19,1,11,1,1,11,20,11,35,2,10,19,46,56,57,12,40,12,42,64,79,0,0,0,0,0,0,0,0,12,22,10,19,46,56,32,32,4,43,5,38,10,42,10,3,38,12,6,5,45,9,12,6,11,6,4,216,2,10,19,10,40,56,34,12,41,10,41,16,4,56,35,56,36,20,12,33,10,41,16,4,56,37,32,4,179,2,5,63,10,41,16,4,10,33,56,38,12,27,10,27,16,5,20,12,26,9,12,36,10,27,16,6,20,10,4,37,4,83,8,12,11,5,90,10,1,17,47,10,27,16,7,20,33,12,11,11,11,4,153,1,8,12,36,10,27,16,5,20,10,27,16,12,20,17,56,12,29,10,0,54,2,10,27,16,7,20,11,29,56,58,10,34,10,27,56,40,10,27,16,8,20,12,12,10,27,16,9,20,12,13,10,27,16,10,20,12,14,10,27,16,7,20,12,15,10,27,16,11,20,12,16,10,27,16,5,20,12,17,10,27,16,12,20,12,18,11,13,11,12,11,14,11,15,11,16,11,17,11,18,57,5,12,21,13,22,11,21,68,79,5,245,1,14,20,56,29,12,37,10,37,10,26,38,4,163,1,10,26,12,7,5,165,1,11,37,12,7,11,7,12,23,10,23,10,27,16,12,20,17,56,12,24,10,24,10,0,55,6,20,17,58,12,30,10,24,10,0,55,4,20,17,59,12,38,4,190,1,11,38,6,1,0,0,0,0,0,0,0,22,12,38,11,26,10,23,23,12,26,10,0,54,2,10,27,16,7,20,11,24,56,59,12,25,13,25,10,38,56,42,12,39,10,0,54,2,10,27,16,7,20,13,39,10,30,56,42,56,21,10,0,54,7,11,39,56,43,1,13,35,11,25,56,43,1,10,0,54,0,10,27,16,7,20,13,20,10,23,56,60,56,17,10,0,55,1,17,89,20,10,2,10,1,17,47,10,27,11,23,11,38,11,30,56,45,11,36,4,250,1,8,12,8,5,254,1,10,26,6,0,0,0,0,0,0,0,0,33,12,8,11,8,4,161,2,10,33,12,32,10,41,16,4,10,33,56,46,12,31,10,31,56,47,32,4,144,2,11,31,56,36,20,12,33,5,146,2,11,31,1,10,0,54,8,11,27,16,7,20,56,48,10,32,56,49,1,10,41,15,4,11,32,56,50,1,5,172,2,11,27,1,10,41,15,4,10,33,56,51,12,28,11,26,11,28,15,5,21,14,20,56,29,6,0,0,0,0,0,0,0,0,33,4,178,2,5,179,2,5,57,11,41,16,4,56,37,4,203,2,10,19,11,42,12,9,46,11,9,56,61,1,12,42,10,19,11,40,56,53,17,0,10,19,10,42,12,10,46,11,10,56,54,12,40,1,14,20,56,29,6,0,0,0,0,0,0,0,0,33,4,215,2,11,0,1,11,19,1,11,1,1,5,216,2,5,32,14,22,56,55,32,4,224,2,11,34,11,22,57,6,56,56,11,20,11,35,2,14,1,0,0,99,103,10,3,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,9,5,19,11,0,1,11,8,1,11,7,1,11,1,1,7,5,39,10,3,6,0,0,0,0,0,0,0,0,34,4,24,5,34,11,0,1,11,8,1,11,7,1,11,1,1,7,5,39,11,4,4,58,11,0,11,1,11,2,11,3,7,27,11,7,17,70,11,6,56,20,56,62,12,13,12,9,13,5,11,9,10,8,56,30,56,63,11,13,11,8,56,31,12,6,5,100,10,3,14,5,56,15,37,4,64,5,74,11,0,1,11,8,1,11,7,1,11,1,1,7,6,39,13,5,11,3,10,8,56,64,12,11,11,0,11,1,11,2,7,28,11,7,17,70,11,11,56,16,56,65,12,12,12,10,13,5,11,10,10,8,56,30,56,63,13,6,11,12,11,8,56,31,56,66,11,5,11,6,2,15,0,0,0,102,123,10,8,17,47,12,14,10,5,4,30,10,4,10,2,17,56,12,15,10,0,54,2,11,8,11,15,56,67,10,0,55,10,20,12,13,10,0,55,10,20,6,1,0,0,0,0,0,0,0,22,10,0,54,10,21,10,0,54,9,12,11,5,50,10,0,54,0,11,8,10,4,56,68,10,0,55,11,20,12,13,10,0,55,11,20,6,1,0,0,0,0,0,0,0,22,10,0,54,11,21,10,0,54,3,12,11,10,13,10,1,10,2,10,3,10,4,10,5,10,14,10,7,11,6,18,8,12,12,10,11,10,2,12,10,46,11,10,56,54,12,16,32,4,78,10,11,10,2,10,2,10,9,56,69,18,9,56,70,12,16,11,11,11,16,56,34,15,4,10,13,11,12,56,71,10,0,55,1,17,89,20,10,13,11,1,11,5,10,14,11,3,11,4,10,2,11,7,57,7,56,72,10,0,55,8,10,14,56,73,32,4,112,10,0,54,8,10,14,11,9,56,74,56,75,5,114,11,9,1,11,0,54,8,11,14,56,48,10,13,11,2,56,76,11,13,2,16,1,0,0,109,171,2,10,4,7,22,33,4,5,5,15,11,0,1,11,10,1,11,8,1,11,9,1,7,20,39,10,3,6,0,0,0,0,0,0,0,0,36,4,20,5,30,11,0,1,11,10,1,11,8,1,11,9,1,7,5,39,10,2,6,0,0,0,0,0,0,0,0,36,4,35,5,45,11,0,1,11,10,1,11,8,1,11,9,1,7,4,39,10,2,10,0,55,12,20,25,6,0,0,0,0,0,0,0,0,33,4,54,5,64,11,0,1,11,10,1,11,8,1,11,9,1,7,4,39,10,3,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,73,5,83,11,0,1,11,10,1,11,8,1,11,9,1,7,5,39,10,6,10,8,17,70,36,4,89,5,99,11,0,1,11,10,1,11,8,1,11,9,1,7,18,39,10,9,17,47,12,17,10,3,12,16,10,5,4,147,1,10,0,55,2,10,17,56,77,12,22,10,0,54,2,10,9,10,22,56,78,12,18,10,0,10,9,10,1,10,3,10,2,11,8,17,70,11,18,56,62,12,20,12,12,14,12,56,29,12,14,11,22,14,20,56,79,23,12,21,10,0,54,0,10,17,11,12,56,17,10,0,54,2,11,17,11,20,56,21,5,181,1,10,0,54,0,10,9,10,3,56,80,12,11,10,0,10,9,10,1,10,2,11,8,17,70,11,11,56,65,12,19,12,13,10,3,14,13,56,29,23,12,14,14,19,56,79,12,21,10,0,54,0,10,17,11,13,56,17,10,0,54,2,11,17,11,19,56,21,10,7,7,24,33,4,196,1,11,0,1,11,10,1,11,9,1,11,14,11,21,9,6,0,0,0,0,0,0,0,0,2,10,7,7,25,33,4,218,1,11,0,1,11,10,1,11,9,1,10,14,11,3,33,4,211,1,5,213,1,7,8,39,11,14,11,21,9,6,0,0,0,0,0,0,0,0,2,10,7,7,26,33,4,252,1,10,14,6,0,0,0,0,0,0,0,0,33,4,227,1,5,235,1,11,0,1,11,10,1,11,9,1,7,9,39,11,0,11,1,11,2,11,16,11,3,11,5,11,4,11,6,11,9,11,10,56,81,12,15,11,14,11,21,8,11,15,2,11,7,7,22,33,4,129,2,5,137,2,11,0,1,11,10,1,11,9,1,7,13,39,10,3,10,14,36,4,160,2,11,0,11,1,11,2,11,16,11,3,10,14,23,11,5,11,4,11,6,11,9,11,10,56,81,12,15,11,14,11,21,8,11,15,2,11,0,1,11,10,1,11,9,1,11,14,11,21,9,6,0,0,0,0,0,0,0,0,2,17,0,0,0,1,4,11,0,7,27,35,2,18,0,0,0,111,41,11,0,12,2,10,1,16,8,20,12,3,10,1,16,9,20,12,4,10,1,16,10,20,12,5,10,1,16,7,20,12,6,10,1,16,11,20,12,7,10,1,16,5,20,12,8,11,1,16,12,20,12,9,11,2,11,4,11,3,11,5,11,6,11,7,11,8,11,9,57,8,56,82,2,19,0,0,0,113,58,11,0,12,7,10,3,16,9,20,12,12,11,1,12,13,11,2,12,14,10,3,16,8,20,12,15,10,3,16,10,20,12,16,10,3,16,7,20,12,17,10,3,16,11,20,12,18,10,4,12,19,10,3,16,5,20,11,4,23,12,8,11,3,16,12,20,12,9,11,5,12,10,11,6,12,11,11,7,11,12,11,13,11,15,11,16,11,14,11,17,11,18,11,19,11,8,11,9,11,10,11,11,57,9,56,83,2,20,1,0,0,115,115,11,2,17,47,12,10,10,0,55,8,10,10,56,73,4,9,5,13,11,0,1,7,11,39,10,0,54,8,10,10,56,48,12,13,10,13,10,1,12,3,46,11,3,56,84,4,26,5,32,11,13,1,11,0,1,7,2,39,10,13,10,1,12,4,46,11,4,56,85,20,12,12,10,1,17,17,12,8,10,8,4,49,10,0,55,9,12,5,5,52,10,0,55,3,12,5,11,5,11,12,56,54,12,11,4,58,5,64,11,13,1,11,0,1,7,2,39,10,8,4,70,10,0,54,9,12,6,5,73,10,0,54,3,12,6,11,6,11,13,11,11,11,1,10,10,56,86,12,9,11,8,4,101,14,9,16,5,20,14,9,16,12,20,17,59,12,7,4,95,11,7,6,1,0,0,0,0,0,0,0,22,12,7,10,0,54,2,11,10,11,7,56,58,5,108,10,0,54,0,11,10,14,9,16,5,20,56,39,11,0,55,1,17,89,20,14,9,56,40,2,21,0,0,0,116,54,11,1,10,3,56,49,1,10,0,10,2,12,5,46,11,5,56,87,16,4,10,3,56,88,4,15,5,19,11,0,1,7,2,39,10,0,10,2,56,34,12,6,10,6,15,4,11,3,56,50,12,7,14,7,16,7,20,11,4,33,4,35,5,41,11,0,1,11,6,1,7,3,39,11,6,16,4,56,37,4,50,11,0,11,2,56,53,17,0,5,52,11,0,1,11,7,2,22,1,0,0,117,154,1,10,0,55,1,17,89,20,12,21,11,1,17,47,12,20,10,0,55,8,10,20,56,73,4,14,5,18,11,0,1,7,11,39,10,0,54,8,10,20,56,48,12,23,64,79,0,0,0,0,0,0,0,0,12,14,10,23,46,56,89,32,4,141,1,5,31,10,23,46,56,90,56,36,20,12,18,10,23,10,18,12,5,46,11,5,56,85,20,12,19,10,18,17,17,12,15,10,15,4,54,10,0,54,9,12,6,5,57,10,0,54,3,12,6,11,6,12,16,10,16,11,19,12,7,46,11,7,56,54,12,22,1,11,16,10,23,11,22,11,18,10,20,56,86,12,17,11,15,4,90,14,17,16,5,20,14,17,16,12,20,17,56,12,12,10,0,54,2,10,20,11,12,56,58,5,97,10,0,54,0,10,20,14,17,16,5,20,56,39,10,21,14,17,56,40,14,17,16,8,20,12,8,14,17,16,9,20,12,9,14,17,16,10,20,12,10,14,17,16,7,20,12,11,14,17,16,11,20,12,2,14,17,16,5,20,12,3,14,17,16,12,20,12,4,11,9,11,8,11,10,11,11,11,2,11,3,11,4,57,5,12,13,13,14,11,13,68,79,5,25,11,23,1,11,0,1,14,14,56,55,32,4,153,1,11,21,11,14,57,6,56,56,2,23,1,0,0,118,203,1,10,0,55,1,17,89,20,12,25,11,2,17,47,12,24,10,0,55,8,10,24,56,73,4,14,5,18,11,0,1,6,0,0,0,0,0,0,0,0,39,6,0,0,0,0,0,0,0,0,12,26,6,0,0,0,0,0,0,0,0,12,27,14,1,65,21,12,19,6,0,0,0,0,0,0,0,0,12,17,10,0,54,8,10,24,56,48,12,28,64,79,0,0,0,0,0,0,0,0,12,16,10,17,10,19,35,4,190,1,5,39,14,1,10,17,66,21,20,12,23,10,28,10,23,12,7,46,11,7,56,84,4,52,5,58,11,28,1,11,0,1,7,2,39,10,28,10,23,12,8,46,11,8,56,85,20,12,21,10,23,17,17,12,18,10,21,10,27,34,4,98,11,21,12,27,10,18,4,81,10,0,55,9,12,9,5,84,10,0,55,3,12,9,11,9,10,27,56,54,12,20,4,90,5,96,11,28,1,11,0,1,7,10,39,11,20,12,26,10,18,4,104,10,0,54,9,12,10,5,107,10,0,54,3,12,10,11,10,10,28,10,26,11,23,10,24,56,86,12,22,11,18,4,135,1,14,22,16,5,20,14,22,16,12,20,17,59,12,14,4,129,1,11,14,6,1,0,0,0,0,0,0,0,22,12,14,10,0,54,2,10,24,11,14,56,58,5,142,1,10,0,54,0,10,24,14,22,16,5,20,56,39,10,25,14,22,56,40,14,22,16,8,20,12,11,14,22,16,9,20,12,12,14,22,16,10,20,12,13,14,22,16,7,20,12,3,14,22,16,11,20,12,4,14,22,16,5,20,12,5,14,22,16,12,20,12,6,11,12,11,11,11,13,11,3,11,4,11,5,11,6,57,5,12,15,13,16,11,15,68,79,11,17,6,1,0,0,0,0,0,0,0,22,12,17,5,34,11,28,1,11,0,1,14,16,56,55,32,4,202,1,11,25,11,16,57,6,56,56,2,24,1,0,0,119,214,1,10,0,55,1,17,89,20,12,28,11,1,17,70,12,23,14,2,65,21,12,20,10,20,14,3,65,65,33,4,17,5,21,11,0,1,7,12,39,6,0,0,0,0,0,0,0,0,12,18,6,0,0,0,0,0,0,0,0,12,29,6,0,0,0,0,0,0,0,0,12,30,64,79,0,0,0,0,0,0,0,0,12,17,10,18,10,20,35,4,203,1,5,34,14,2,10,18,66,21,20,12,26,14,3,10,18,66,65,20,12,27,10,0,55,8,10,27,56,73,32,4,51,5,29,10,0,54,8,10,27,56,48,12,31,10,31,10,26,12,9,46,11,9,56,84,32,4,67,11,31,1,5,29,10,31,10,26,12,10,46,11,10,56,85,20,12,22,10,26,17,17,12,19,10,19,4,84,10,0,54,9,12,11,5,87,10,0,54,3,12,11,11,11,12,24,10,22,10,30,34,4,114,11,22,12,30,10,24,10,30,12,12,46,11,12,56,54,12,21,4,104,5,112,11,31,1,11,0,1,11,24,1,7,10,39,11,21,12,29,11,24,11,31,10,29,11,26,10,27,56,86,12,25,14,25,16,6,20,10,23,35,4,128,1,5,132,1,11,0,1,7,18,39,11,19,4,148,1,14,25,16,5,20,14,25,16,12,20,17,56,12,15,10,0,54,2,11,27,11,15,56,58,5,155,1,10,0,54,0,11,27,14,25,16,5,20,56,39,10,28,14,25,56,40,14,25,16,8,20,12,13,14,25,16,9,20,12,14,14,25,16,10,20,12,4,14,25,16,7,20,12,5,14,25,16,11,20,12,6,14,25,16,5,20,12,7,14,25,16,12,20,12,8,11,14,11,13,11,4,11,5,11,6,11,7,11,8,57,5,12,16,13,17,11,16,68,79,11,18,6,1,0,0,0,0,0,0,0,22,12,18,5,29,11,0,1,14,17,56,55,32,4,213,1,11,28,11,17,57,6,56,56,2,25,1,0,0,120,93,11,1,17,47,12,7,10,0,55,8,11,7,56,91,12,8,64,29,0,0,0,0,0,0,0,0,12,3,10,8,56,92,12,5,10,5,56,47,32,4,85,5,18,10,8,10,5,56,36,20,56,85,20,12,6,10,5,56,36,20,17,17,4,36,10,0,55,9,11,6,56,93,12,2,5,41,10,0,55,3,11,6,56,93,12,2,11,2,16,4,10,5,56,36,20,56,38,12,4,13,3,10,4,16,9,20,10,4,16,8,20,10,4,16,12,20,10,4,16,11,20,10,4,16,5,20,10,4,16,10,20,10,4,16,7,20,10,4,16,6,20,11,4,16,22,20,18,8,68,29,10,8,11,5,56,36,20,56,94,12,5,5,13,11,8,1,11,0,1,11,5,1,11,3,2,26,1,0,0,121,20,11,1,17,47,12,4,10,0,55,0,10,4,56,95,12,3,12,2,11,0,55,2,11,4,56,96,12,6,12,5,11,2,11,3,11,5,11,6,2,27,1,0,0,122,37,10,0,55,9,56,32,32,4,12,10,0,55,9,56,57,1,56,97,12,1,5,14,56,98,12,1,11,1,12,4,10,0,55,3,56,32,32,4,28,11,0,55,3,56,33,1,56,97,12,2,5,32,11,0,1,56,98,12,2,11,2,12,3,11,4,11,3,2,28,1,0,0,124,90,64,21,0,0,0,0,0,0,0,0,12,9,64,21,0,0,0,0,0,0,0,0,12,5,10,0,55,9,56,32,4,15,11,0,1,11,3,1,11,9,11,5,2,10,0,55,9,56,33,1,12,8,10,1,10,8,35,4,26,11,8,12,1,10,0,55,9,56,57,1,12,7,10,2,10,7,36,4,37,11,7,12,2,10,0,55,9,11,1,56,99,12,1,10,0,55,9,11,2,56,99,12,2,10,1,10,2,37,4,87,5,52,10,0,55,9,10,1,10,3,17,70,56,100,12,4,10,4,6,0,0,0,0,0,0,0,0,34,4,69,13,9,10,1,68,21,13,5,11,4,68,21,10,0,55,9,11,1,56,52,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,84,11,0,1,11,3,1,5,87,11,6,12,1,5,47,11,9,11,5,2,29,1,0,0,124,90,64,21,0,0,0,0,0,0,0,0,12,9,64,21,0,0,0,0,0,0,0,0,12,5,10,0,55,3,56,32,4,15,11,0,1,11,3,1,11,9,11,5,2,10,0,55,3,56,33,1,12,8,10,1,10,8,35,4,26,11,8,12,1,10,0,55,3,56,57,1,12,7,10,2,10,7,36,4,37,11,7,12,2,10,0,55,3,11,1,56,99,12,1,10,0,55,3,11,2,56,99,12,2,10,1,10,2,37,4,87,5,52,10,0,55,3,10,1,10,3,17,70,56,100,12,4,10,4,6,0,0,0,0,0,0,0,0,34,4,69,13,9,10,1,68,21,13,5,11,4,68,21,10,0,55,3,11,1,56,52,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,84,11,0,1,11,3,1,5,87,11,6,12,1,5,47,11,9,11,5,2,30,0,0,0,125,49,11,0,11,1,56,93,16,4,12,6,6,0,0,0,0,0,0,0,0,12,3,10,6,56,35,12,5,10,5,56,47,32,4,43,5,15,10,6,10,5,56,36,20,56,38,12,4,10,4,16,6,20,10,2,36,4,34,11,3,11,4,16,5,20,22,12,3,5,36,11,4,1,10,6,11,5,56,36,20,56,46,12,5,5,10,11,6,1,11,5,1,11,3,2,31,1,0,0,126,52,11,2,17,47,12,5,10,0,55,8,10,5,56,73,4,9,5,13,11,0,1,7,11,39,10,0,55,8,11,5,56,91,12,6,10,6,10,1,56,84,4,23,5,29,11,6,1,11,0,1,7,2,39,11,6,10,1,56,85,20,12,4,10,1,7,27,35,4,42,11,0,55,9,12,3,5,45,11,0,55,3,12,3,11,3,11,4,56,93,16,4,11,1,56,38,2,10,10,10,0,10,11,10,2,9,1,8,4,8,7,8,6,8,1,8,0,8,5,8,3,8,2,10,6,10,9,10,7,10,14,10,5,10,1,10,3,10,4,10,8,8,8,0,59,1,59,2,59,3,59,13,59,14,59,15,59,16,59,17,59,18,59,19,59,20,59,21,59,0],"critbit":[161,28,235,11,6,0,0,0,14,1,0,8,2,8,28,3,36,194,1,4,230,1,54,5,156,2,232,1,7,132,4,166,4,8,170,8,64,6,234,8,120,10,226,9,51,11,149,10,4,12,153,10,173,14,13,198,24,28,14,226,24,20,15,246,24,4,0,14,0,30,1,45,1,46,0,2,6,1,0,0,0,1,6,0,0,0,4,1,4,0,2,3,12,2,7,1,4,1,3,4,2,0,0,33,0,1,1,4,0,44,2,3,1,4,0,22,2,4,1,4,0,32,2,5,1,4,0,31,2,5,1,4,0,38,6,5,1,4,0,35,6,5,1,4,0,27,6,3,1,4,0,42,6,3,1,4,0,20,7,3,1,4,0,18,6,8,1,4,0,17,6,3,1,4,0,40,9,10,1,4,0,10,9,11,1,4,0,7,6,12,1,4,0,8,6,12,1,4,0,16,1,13,1,6,0,15,1,13,1,4,0,19,6,3,1,4,0,47,14,13,1,4,0,23,15,4,1,4,1,13,25,26,0,2,5,24,13,2,7,4,2,6,20,21,2,7,4,2,9,28,30,2,7,4,2,15,17,13,2,7,4,2,16,17,13,2,7,6,2,22,19,4,2,7,4,2,28,19,3,2,7,4,2,33,0,17,2,7,4,2,39,28,29,2,7,4,29,16,29,18,28,18,27,18,2,10,23,18,10,10,20,10,23,16,8,10,7,10,22,18,18,10,22,16,19,10,6,10,5,10,30,18,1,10,24,16,24,18,30,16,14,10,26,16,26,18,25,18,25,16,1,7,8,4,1,11,2,1,9,0,1,6,11,2,1,9,0,1,3,1,1,2,3,3,2,6,11,2,1,9,0,3,3,7,11,2,1,9,0,3,9,0,2,1,3,2,7,11,2,1,9,0,3,1,9,0,1,7,9,0,1,6,9,0,0,4,7,11,2,1,9,0,3,3,1,3,6,11,2,1,9,0,3,3,2,3,8,1,1,11,3,2,9,0,9,1,2,3,11,0,1,9,0,1,6,11,3,2,9,0,9,1,2,6,11,3,2,9,0,9,1,9,0,1,6,9,1,4,1,3,3,3,16,3,3,3,3,3,2,6,8,1,1,1,8,1,3,3,11,0,1,9,0,3,3,3,3,7,11,3,2,9,0,9,1,9,0,9,1,1,4,1,2,16,3,3,3,3,3,3,3,3,3,1,3,3,6,8,1,3,3,9,0,2,7,11,3,2,9,0,9,1,9,0,1,9,1,1,7,9,1,2,11,3,2,3,8,1,11,3,2,3,11,0,1,9,0,2,6,8,1,3,11,67,114,105,116,98,105,116,84,114,101,101,12,73,110,116,101,114,110,97,108,78,111,100,101,4,76,101,97,102,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,4,99,108,111,98,7,99,108,111,98,95,118,50,19,99,111,117,110,116,95,108,101,97,100,105,110,103,95,122,101,114,111,115,7,99,114,105,116,98,105,116,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,29,103,101,116,95,99,108,111,115,101,115,116,95,108,101,97,102,95,105,110,100,101,120,95,98,121,95,107,101,121,11,105,110,115,101,114,116,95,108,101,97,102,14,105,110,116,101,114,110,97,108,95,110,111,100,101,115,8,105,115,95,101,109,112,116,121,13,105,115,95,108,101,102,116,95,99,104,105,108,100,3,107,101,121,6,108,101,97,118,101,115,10,108,101,102,116,95,99,104,105,108,100,14,108,101,102,116,95,109,111,115,116,95,108,101,97,102,6,108,101,110,103,116,104,4,109,97,115,107,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,3,110,101,119,24,110,101,120,116,95,105,110,116,101,114,110,97,108,95,110,111,100,101,95,105,110,100,101,120,9,110,101,120,116,95,108,101,97,102,15,110,101,120,116,95,108,101,97,102,95,105,110,100,101,120,6,112,97,114,101,110,116,13,112,114,101,118,105,111,117,115,95,108,101,97,102,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,11,114,105,103,104,116,95,99,104,105,108,100,15,114,105,103,104,116,95,109,111,115,116,95,108,101,97,102,4,114,111,111,116,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,112,100,97,116,101,95,99,104,105,108,100,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,128,3,8,255,255,255,255,255,255,255,255,3,8,255,255,255,255,255,255,255,127,0,2,3,24,3,48,9,0,37,3,1,2,4,29,3,26,3,41,3,37,3,2,2,7,43,3,21,11,3,2,3,8,1,25,11,3,2,3,11,0,1,9,0,32,3,31,3,34,3,36,3,2,10,0,10,0,3,0,0,13,11,7,9,10,0,56,0,11,0,56,1,7,9,7,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,57,0,2,1,3,0,0,13,4,11,0,55,0,56,2,2,2,3,0,0,13,4,11,0,55,0,56,3,2,3,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,1,20,56,5,55,2,20,11,0,55,1,20,2,4,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,0,55,3,20,2,5,1,0,0,22,78,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,36,5,30,10,0,10,4,11,5,56,7,12,2,5,38,9,12,2,11,2,4,50,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,59,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,7,20,56,9,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,6,3,0,0,22,79,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,37,5,30,10,0,10,4,11,5,56,7,32,12,2,5,39,9,12,2,11,2,4,51,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,60,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,8,20,56,10,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,7,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,7,20,12,2,5,2,11,0,1,11,2,2,8,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,8,20,12,2,5,2,11,0,1,11,2,2,9,3,0,0,23,247,1,10,1,11,2,7,9,57,1,12,15,10,0,55,6,20,12,16,10,0,55,6,20,6,1,0,0,0,0,0,0,0,22,10,0,54,6,21,10,16,7,11,6,1,0,0,0,0,0,0,0,23,35,4,24,5,28,11,0,1,7,1,39,10,0,54,0,10,16,11,15,56,11,10,0,10,1,12,3,46,11,3,56,12,12,7,10,7,7,9,33,4,69,10,16,6,0,0,0,0,0,0,0,0,33,4,49,5,53,11,0,1,7,2,39,7,10,10,16,23,10,0,54,7,21,10,16,10,0,54,1,21,11,16,11,0,54,3,21,6,0,0,0,0,0,0,0,0,2,10,0,55,0,11,7,56,5,55,2,20,12,6,10,6,10,1,34,4,81,5,85,11,0,1,7,3,39,49,64,11,6,10,1,29,53,17,21,49,64,23,23,12,8,6,1,0,0,0,0,0,0,0,11,8,49,1,23,47,12,17,10,17,7,9,7,9,7,9,18,1,12,12,10,0,55,8,20,12,13,10,0,55,8,20,6,1,0,0,0,0,0,0,0,22,10,0,54,8,21,10,0,54,5,10,13,11,12,56,13,10,0,55,7,20,12,18,7,9,12,14,10,18,7,9,35,4,169,1,5,135,1,10,0,55,5,10,18,56,8,12,9,10,17,10,9,16,12,20,36,4,149,1,11,9,1,5,169,1,11,18,12,14,10,1,10,9,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,164,1,11,9,16,7,20,12,18,5,168,1,11,9,16,8,20,12,18,5,130,1,10,14,7,9,33,4,178,1,10,13,10,0,54,7,21,5,193,1,10,0,10,14,10,18,12,5,12,4,46,11,4,11,5,56,7,12,10,10,0,11,14,10,13,11,10,56,14,11,17,10,1,28,6,0,0,0,0,0,0,0,0,33,12,11,10,0,10,13,7,10,10,16,23,10,11,56,14,10,0,11,13,11,18,11,11,32,56,14,10,0,55,0,10,0,55,1,20,56,5,55,2,20,10,1,36,4,227,1,10,16,10,0,54,1,21,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,1,35,4,243,1,10,16,11,0,54,3,21,5,245,1,11,0,1,11,16,2,10,3,0,0,3,27,10,0,56,4,4,8,11,0,1,9,7,9,2,10,0,10,1,56,12,12,2,11,0,55,0,10,2,56,5,55,2,20,11,1,34,4,24,9,7,9,2,8,11,2,2,11,3,0,0,3,18,10,0,56,4,4,7,11,0,1,6,0,0,0,0,0,0,0,0,2,10,0,11,1,56,12,12,2,11,0,55,0,11,2,56,5,55,2,20,2,12,3,0,0,27,171,1,10,0,55,0,10,1,56,5,55,2,20,12,12,10,0,55,1,20,10,1,33,4,25,10,0,10,12,12,4,46,11,4,56,15,12,9,1,11,9,10,0,54,1,21,10,0,55,3,20,10,1,33,4,43,10,0,11,12,12,5,46,11,5,56,16,12,10,1,11,10,10,0,54,3,21,10,0,54,0,10,1,56,17,58,1,12,15,12,17,1,10,0,46,56,18,6,0,0,0,0,0,0,0,0,33,4,78,7,9,10,0,54,7,21,7,9,10,0,54,1,21,7,9,10,0,54,3,21,6,0,0,0,0,0,0,0,0,10,0,54,8,21,6,0,0,0,0,0,0,0,0,11,0,54,6,21,5,169,1,10,15,7,9,34,4,83,5,87,11,0,1,7,6,39,10,0,55,5,10,15,56,8,12,14,10,14,16,6,20,12,13,10,0,10,15,7,10,11,1,23,12,7,12,6,46,11,6,11,7,56,7,4,113,11,14,16,8,20,12,8,5,117,11,14,16,7,20,12,8,11,8,12,16,10,13,7,9,33,4,149,1,10,16,7,9,35,4,135,1,7,9,10,0,54,5,10,16,56,19,15,6,21,5,144,1,7,9,10,0,54,0,7,10,10,16,23,56,20,54,4,21,11,16,10,0,54,7,21,5,164,1,10,0,10,13,10,15,12,3,12,2,46,11,2,11,3,56,7,12,11,10,0,11,13,11,16,11,11,56,14,11,0,54,5,11,15,56,21,1,11,17,2,13,3,0,0,13,6,11,0,54,0,11,1,56,20,54,9,2,14,3,0,0,13,6,11,0,55,0,11,1,56,5,55,9,2,15,3,0,0,3,14,10,0,11,1,56,6,12,2,4,6,5,10,11,0,1,7,4,39,11,0,11,2,56,22,2,16,3,0,0,31,14,11,0,58,0,1,1,1,1,12,2,12,1,1,11,1,56,23,11,2,56,24,2,17,3,0,0,31,23,14,0,55,0,56,2,6,0,0,0,0,0,0,0,0,33,4,7,5,9,6,0,0,0,0,0,0,0,0,39,11,0,58,0,1,1,1,1,12,2,12,1,1,11,2,56,25,11,1,56,26,2,18,0,0,0,32,46,10,0,55,7,20,12,3,10,3,7,9,33,4,12,11,0,1,7,9,2,10,3,7,9,35,4,40,5,17,10,0,55,5,11,3,56,8,12,2,10,1,10,2,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,35,11,2,16,7,20,12,3,5,39,11,2,16,8,20,12,3,5,12,11,0,1,7,10,11,3,23,2,19,0,0,0,13,48,10,1,7,9,34,4,5,5,9,11,0,1,7,7,39,11,3,4,19,10,2,10,0,54,5,10,1,56,19,15,7,21,5,26,10,2,10,0,54,5,10,1,56,19,15,8,21,10,2,7,9,36,4,40,11,1,11,0,54,0,7,10,11,2,23,56,20,54,4,21,5,47,11,1,11,0,54,5,11,2,56,19,15,6,21,2,20,0,0,0,13,9,11,0,55,5,11,1,56,8,16,7,20,11,2,33,2,2,2,2,3,0,0,2,4,0,2,2,1,1,3,1,1,1,2,2,6,2,0,2,5,1,0,0,1,0,10,1,10,2,10,3,10,4,10,5,10,9,10,10,10,11,10,13,10,0,11,0,12,0],"custodian":[161,28,235,11,6,0,0,0,14,1,0,12,2,12,48,3,60,158,1,4,218,1,30,5,248,1,246,1,7,238,3,166,4,8,148,8,64,6,212,8,10,10,222,8,38,11,132,9,4,12,136,9,238,2,13,246,11,8,14,254,11,6,15,132,12,2,0,23,1,15,1,21,1,35,1,37,1,38,0,0,4,1,0,1,0,1,12,0,0,4,12,1,0,1,1,2,4,1,0,1,2,3,12,1,0,1,3,5,7,0,3,8,4,0,4,6,12,2,7,1,4,1,5,7,2,0,0,33,0,1,0,0,10,2,3,1,0,0,34,0,4,1,0,0,42,5,6,1,0,0,28,7,8,1,0,0,24,9,10,1,0,0,29,11,8,1,0,0,25,12,10,1,0,0,31,9,8,1,0,0,40,12,8,1,0,0,9,2,13,1,0,0,12,2,13,1,0,0,19,14,15,1,0,0,17,2,16,1,0,1,30,27,13,1,0,1,36,30,10,1,0,1,41,24,13,1,0,1,43,8,10,1,0,2,26,26,6,1,0,3,34,0,17,0,3,39,28,29,0,4,13,31,8,2,7,4,4,16,21,23,2,7,4,4,18,32,33,2,7,4,4,22,21,22,2,7,4,4,34,0,25,2,7,4,24,20,22,20,16,19,25,20,5,19,18,19,12,19,14,19,15,19,6,19,7,19,4,19,17,19,21,20,23,20,1,7,8,8,1,8,1,2,6,11,2,1,9,0,8,5,2,3,3,1,11,2,1,9,0,4,7,11,2,1,9,0,3,6,8,1,7,8,8,1,11,4,1,9,0,3,7,11,2,1,9,0,8,5,11,3,1,9,0,0,3,7,11,2,1,9,0,6,8,1,3,1,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,11,3,1,9,0,3,7,11,2,1,9,0,8,5,3,1,3,2,7,11,2,1,9,0,8,5,1,7,11,0,1,9,0,1,6,11,0,1,9,0,1,8,6,3,6,11,0,1,9,0,3,3,1,9,0,2,8,5,11,0,1,9,0,2,6,11,7,2,9,0,9,1,9,0,1,1,1,6,9,1,1,6,11,3,1,9,0,1,11,7,2,9,0,9,1,2,11,3,1,9,0,7,8,8,2,7,11,3,1,9,0,11,3,1,9,0,1,6,8,6,1,8,5,2,7,11,3,1,9,0,3,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,7,9,1,7,65,99,99,111,117,110,116,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,4,67,111,105,110,9,67,117,115,116,111,100,105,97,110,2,73,68,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,16,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,115,22,97,99,99,111,117,110,116,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,3,97,100,100,17,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,22,98,111,114,114,111,119,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,26,98,111,114,114,111,119,95,109,117,116,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,4,99,108,111,98,4,99,111,105,110,8,99,111,110,116,97,105,110,115,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,105,110,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,4,106,111,105,110,12,108,111,99,107,95,98,97,108,97,110,99,101,14,108,111,99,107,101,100,95,98,97,108,97,110,99,101,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,110,101,119,6,111,98,106,101,99,116,5,115,112,108,105,116,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,0,2,2,14,11,3,1,9,0,32,11,3,1,9,0,1,2,1,27,8,6,2,2,2,27,8,6,11,11,7,2,8,5,11,0,1,9,0,2,19,0,19,0,1,0,0,8,4,11,0,17,19,18,1,2,1,3,0,0,18,27,10,0,55,0,10,1,56,0,32,4,11,11,0,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,2,11,0,55,0,11,1,56,1,12,2,10,2,55,1,56,2,12,3,11,2,55,2,56,2,12,4,11,3,11,4,2,2,3,0,0,8,6,10,0,17,19,11,0,56,3,57,0,2,3,3,0,0,8,7,11,0,11,2,11,1,56,4,11,3,56,5,2,4,3,0,0,8,8,11,0,11,1,56,6,54,1,11,2,56,7,1,2,5,3,0,0,8,9,11,0,11,1,16,3,17,20,56,6,54,1,11,2,56,8,2,6,3,0,0,8,10,11,0,11,1,16,3,17,20,56,6,54,2,11,2,56,7,1,2,7,3,0,0,8,7,11,0,11,1,56,6,54,2,11,2,56,8,2,8,3,0,0,10,10,10,0,10,1,11,2,56,4,12,3,11,0,11,1,11,3,56,9,2,9,3,0,0,10,10,10,0,10,1,11,2,56,10,12,3,11,0,11,1,11,3,56,11,2,10,3,0,0,8,7,11,0,55,0,11,1,56,1,55,1,56,2,2,11,3,0,0,8,7,11,0,55,0,11,1,56,1,55,2,56,2,2,12,0,0,0,8,18,10,0,55,0,10,1,56,0,32,4,13,10,0,54,0,10,1,56,12,56,12,57,1,56,13,11,0,54,0,11,1,56,14,2,13,0,0,0,8,15,10,0,55,0,10,1,56,0,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,1,2,2,1,0,0,0,1,1,0,0,19,1,19,2,19,0,20,0],"custodian_v2":[161,28,235,11,6,0,0,0,14,1,0,12,2,12,44,3,56,178,1,4,234,1,30,5,136,2,255,1,7,135,4,242,4,8,249,8,64,6,185,9,20,10,205,9,39,11,244,9,4,12,248,9,189,3,13,181,13,10,14,191,13,6,15,197,13,2,0,24,1,15,1,21,1,38,1,41,1,42,0,0,4,1,0,1,0,1,12,0,0,4,12,1,0,1,1,2,4,1,0,1,2,3,12,1,0,1,3,7,4,0,4,5,12,2,7,1,4,1,5,6,2,0,0,36,0,1,0,0,23,2,1,0,0,28,1,3,0,0,12,4,5,0,0,9,6,7,1,0,0,37,0,8,1,0,0,46,9,10,1,0,0,31,11,3,1,0,0,25,12,13,1,0,0,32,14,3,1,0,0,26,15,13,1,0,0,34,12,3,1,0,0,44,15,3,1,0,0,8,6,16,1,0,0,11,6,16,1,0,0,19,17,18,1,0,0,17,6,19,1,0,1,33,32,16,1,0,1,40,33,13,1,0,1,45,29,16,1,0,1,47,3,13,1,0,2,29,31,10,1,0,3,27,21,3,0,3,37,0,21,0,3,43,22,5,0,4,13,34,3,2,7,4,4,16,26,28,2,7,4,4,18,35,36,2,7,4,4,22,26,27,2,7,4,4,37,0,30,2,7,4,28,25,26,25,19,24,29,25,8,24,21,24,15,24,17,24,18,24,9,24,10,24,7,24,20,24,25,25,27,25,1,7,8,7,1,8,1,2,6,8,1,7,8,7,0,1,6,8,1,1,5,2,6,11,2,1,9,0,5,2,3,3,1,11,2,1,9,0,4,7,11,2,1,9,0,3,6,8,1,7,8,7,1,11,4,1,9,0,3,7,11,2,1,9,0,5,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,3,1,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,11,3,1,9,0,3,7,11,2,1,9,0,5,3,1,3,2,7,11,2,1,9,0,5,1,7,11,0,1,9,0,1,6,11,0,1,9,0,2,8,5,5,1,8,5,1,6,8,5,3,6,11,0,1,9,0,3,3,1,9,0,2,5,11,0,1,9,0,2,6,11,6,2,9,0,9,1,9,0,1,1,1,6,9,1,1,6,11,3,1,9,0,1,11,6,2,9,0,9,1,2,11,3,1,9,0,7,8,7,2,7,11,3,1,9,0,11,3,1,9,0,2,7,11,3,1,9,0,3,3,7,11,6,2,9,0,9,1,9,0,9,1,2,7,11,6,2,9,0,9,1,9,0,1,7,9,1,7,65,99,99,111,117,110,116,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,4,67,111,105,110,9,67,117,115,116,111,100,105,97,110,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,16,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,115,22,97,99,99,111,117,110,116,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,13,97,99,99,111,117,110,116,95,111,119,110,101,114,3,97,100,100,17,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,22,98,111,114,114,111,119,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,26,98,111,114,114,111,119,95,109,117,116,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,7,99,108,111,98,95,118,50,4,99,111,105,110,8,99,111,110,116,97,105,110,115,24,99,114,101,97,116,101,95,99,104,105,108,100,95,97,99,99,111,117,110,116,95,99,97,112,12,99,117,115,116,111,100,105,97,110,95,118,50,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,6,100,101,108,101,116,101,18,100,101,108,101,116,101,95,97,99,99,111,117,110,116,95,99,97,112,12,102,114,111,109,95,98,97,108,97,110,99,101,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,105,110,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,4,106,111,105,110,12,108,111,99,107,95,98,97,108,97,110,99,101,14,108,111,99,107,101,100,95,98,97,108,97,110,99,101,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,110,101,119,6,111,98,106,101,99,116,5,111,119,110,101,114,5,115,112,108,105,116,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,2,14,11,3,1,9,0,35,11,3,1,9,0,1,2,2,30,8,5,39,5,2,2,2,30,8,5,10,11,6,2,5,11,0,1,9,0,2,24,0,24,0,3,0,0,20,10,11,0,17,23,12,1,14,1,17,24,12,2,11,1,11,2,18,1,2,1,1,0,0,3,22,10,0,16,0,17,24,10,0,16,1,20,33,4,9,5,15,11,1,1,11,0,1,7,1,39,11,1,17,23,11,0,16,1,20,18,1,2,2,1,0,0,3,5,11,0,19,1,1,17,22,2,3,1,0,0,3,4,11,0,16,1,20,2,4,3,0,0,23,27,10,0,55,0,10,1,56,0,32,4,11,11,0,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,2,11,0,55,0,11,1,56,1,12,2,10,2,55,1,56,2,12,3,11,2,55,2,56,2,12,4,11,3,11,4,2,5,3,0,0,3,6,10,0,17,23,11,0,56,3,57,0,2,6,3,0,0,3,7,11,0,11,2,11,1,56,4,11,3,56,5,2,7,3,0,0,3,8,11,0,11,1,56,6,54,1,11,2,56,7,1,2,8,3,0,0,3,9,11,0,11,1,16,1,20,56,6,54,1,11,2,56,8,2,9,3,0,0,3,10,11,0,11,1,16,1,20,56,6,54,2,11,2,56,7,1,2,10,3,0,0,3,7,11,0,11,1,56,6,54,2,11,2,56,8,2,11,3,0,0,13,10,10,0,10,1,11,2,56,4,12,3,11,0,11,1,11,3,56,9,2,12,3,0,0,13,10,10,0,10,1,11,2,56,10,12,3,11,0,11,1,11,3,56,11,2,13,3,0,0,3,7,11,0,55,0,11,1,56,1,55,1,56,2,2,14,3,0,0,3,7,11,0,55,0,11,1,56,1,55,2,56,2,2,15,0,0,0,3,18,10,0,55,0,10,1,56,0,32,4,13,10,0,54,0,10,1,56,12,56,12,57,1,56,13,11,0,54,0,11,1,56,14,2,16,0,0,0,3,15,10,0,55,0,10,1,56,0,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,1,2,1,0,1,1,2,1,0,0,0,1,2,24,3,24,4,24,0,20,0],"math":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,40,5,42,20,7,62,126,8,188,1,32,6,220,1,38,12,130,2,183,5,15,185,7,6,0,5,0,10,0,1,0,0,11,0,2,0,0,6,0,1,0,0,7,0,2,0,0,8,0,1,0,0,9,0,2,0,0,4,0,2,0,0,2,3,4,0,2,3,3,1,3,2,1,3,1,4,1,2,0,3,1,4,4,2,2,2,4,99,108,111,98,7,99,108,111,98,95,118,50,19,99,111,117,110,116,95,108,101,97,100,105,110,103,95,122,101,114,111,115,7,99,114,105,116,98,105,116,9,100,105,118,95,114,111,117,110,100,4,109,97,116,104,3,109,117,108,9,109,117,108,95,114,111,117,110,100,10,117,110,115,97,102,101,95,100,105,118,16,117,110,115,97,102,101,95,100,105,118,95,114,111,117,110,100,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,3,8,0,202,154,59,0,0,0,0,4,16,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,3,0,0,1,7,11,0,11,1,17,1,12,2,1,11,2,2,1,3,0,0,6,26,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,10,4,24,7,1,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,18,9,12,2,11,2,11,3,11,4,24,7,1,26,52,2,2,1,0,0,1,14,11,0,11,1,17,1,12,2,1,10,2,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,2,3,1,0,0,2,15,11,0,11,1,17,1,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,4,3,0,0,1,7,11,0,11,1,17,5,12,2,1,11,2,2,5,3,0,0,6,28,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,7,0,53,24,10,4,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,9,12,2,11,2,11,3,7,0,53,24,11,4,26,52,2,6,1,0,0,2,15,11,0,11,1,17,5,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,7,3,0,0,7,107,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,49,128,12,1,5,105,49,0,12,2,10,0,50,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,23,11,0,49,64,47,12,0,11,2,49,64,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,37,11,0,49,32,47,12,0,11,2,49,32,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,51,11,0,49,16,47,12,0,11,2,49,16,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,65,11,0,49,8,47,12,0,11,2,49,8,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,79,11,0,49,4,47,12,0,11,2,49,4,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,93,11,0,49,2,47,12,0,11,2,49,2,22,12,2,11,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,103,11,2,49,1,22,12,2,11,2,12,1,11,1,2,0,0,0,1,0,3,0]},"type_origin_table":[{"module_name":"custodian","struct_name":"Account","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"AccountCap","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"Custodian","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"Leaf","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"InternalNode","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"CritbitTree","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"PoolCreated","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlacedV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilledV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Order","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"TickLevel","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Pool","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlaced","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian_v2","struct_name":"Account","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian_v2","struct_name":"AccountCap","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian_v2","struct_name":"Custodian","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"PoolCreated","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"OrderPlaced","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"OrderCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"AllOrdersCanceledComponent","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"AllOrdersCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"OrderFilled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"DepositAsset","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"WithdrawAsset","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"Order","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"TickLevel","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"Pool","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"ACKQVv64dXCmpxE1QPU2QMLxVpmtbzrFGMtWYY6szJrQ","storage_rebate":0},{"data":{"Package":{"id":"0xb2345915de1f9bd661e9ab27eb27e376cdf6391359ea64fbfdb4550b092c1aa0","version":4,"module_map":{"calculator":[161,28,235,11,6,0,0,0,8,1,0,12,2,12,12,3,24,75,5,99,67,7,166,1,189,2,8,227,3,96,6,195,4,44,12,239,4,164,5,0,10,0,23,0,21,2,17,1,11,1,16,1,2,12,0,3,1,8,0,4,0,8,0,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,6,3,1,0,0,7,3,1,0,0,9,4,1,0,0,4,4,1,0,1,12,0,8,0,1,13,0,3,0,1,15,0,3,0,2,19,6,1,0,2,20,3,1,0,2,22,3,1,0,3,14,10,11,0,5,18,12,13,0,2,7,8,0,2,1,15,3,7,8,0,2,15,2,15,15,4,6,8,2,6,8,1,15,2,7,15,15,15,15,15,15,15,0,6,15,15,15,15,15,15,5,15,15,15,15,15,2,2,15,3,6,8,2,6,8,1,2,3,1,15,2,2,3,2,1,3,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,20,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,9,103,101,116,95,105,110,100,101,120,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,4,109,97,116,104,6,111,114,97,99,108,101,3,112,111,119,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,153,183,0,0,0,0,0,0,0,1,0,0,5,31,10,0,10,1,17,9,12,7,12,8,11,0,11,1,17,8,12,3,12,4,11,7,11,3,17,12,12,5,11,8,11,4,17,12,12,6,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,29,11,5,11,6,17,11,12,2,11,2,2,1,1,0,0,7,37,10,0,10,1,17,7,12,6,1,12,4,12,5,12,3,11,0,11,1,17,0,12,7,10,7,10,6,35,4,23,11,3,11,7,11,5,17,12,22,12,2,5,35,11,3,10,6,11,5,17,12,22,11,7,11,6,23,11,4,17,12,22,12,2,11,2,2,2,1,0,0,3,20,10,0,10,1,17,7,1,12,3,1,1,1,11,0,11,1,17,0,12,4,11,2,11,4,17,12,17,10,11,3,23,17,12,2,3,1,0,0,5,60,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,17,10,2,10,0,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,5,11,1,7,0,26,12,6,10,6,10,6,17,12,12,3,10,3,10,6,17,12,12,2,10,0,10,4,24,11,3,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,7,10,0,11,4,24,11,5,24,11,2,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,17,10,11,6,11,0,24,22,11,7,22,11,8,22,2,4,1,0,0,6,8,17,10,11,1,11,0,24,7,0,26,22,2,5,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,11,5,24,6,10,0,0,0,0,0,0,0,11,4,17,14,77,26,2,6,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,6,10,0,0,0,0,0,0,0,11,4,17,14,77,24,11,5,26,2,0],"dynamic_calculator":[161,28,235,11,6,0,0,0,9,1,0,18,2,18,18,3,36,169,1,4,205,1,4,5,209,1,165,2,7,246,3,149,6,8,139,10,128,1,6,139,11,10,12,149,11,225,14,0,16,0,9,0,38,0,43,0,41,3,37,1,45,2,4,2,10,2,1,12,1,0,1,3,3,12,0,5,2,8,0,8,0,8,0,0,17,0,1,1,0,0,21,2,1,0,0,22,2,1,0,0,20,3,1,0,0,24,3,1,0,0,19,4,1,0,0,23,4,1,0,0,18,5,1,0,0,6,6,7,0,0,13,8,7,1,0,0,14,9,1,0,0,15,10,1,0,0,12,9,1,0,1,5,7,1,0,1,7,7,1,0,1,8,25,1,0,2,36,13,14,1,0,3,25,22,1,0,3,26,28,34,0,3,27,28,7,0,3,28,28,7,0,3,29,22,14,0,3,30,28,29,0,3,31,22,19,0,3,32,28,7,0,3,33,17,18,0,3,34,26,7,0,4,39,15,1,0,4,40,7,1,0,4,42,7,1,0,6,11,20,21,1,0,7,35,15,1,0,8,44,31,14,0,16,12,30,19,9,6,8,3,7,8,1,6,8,2,7,11,0,1,9,0,5,2,3,3,1,1,15,7,6,8,3,6,8,2,7,8,1,5,2,15,1,7,6,8,3,6,8,2,7,8,1,2,5,15,1,6,6,8,3,7,8,1,2,5,15,1,7,6,8,3,7,8,1,6,8,2,5,2,15,1,3,6,8,3,7,8,1,2,2,15,15,7,6,8,3,7,8,1,7,11,0,1,9,0,2,3,3,1,6,6,8,3,7,8,1,2,15,15,1,7,6,8,3,7,8,1,2,15,15,15,1,9,1,3,3,15,15,15,15,3,3,1,9,0,2,6,11,0,1,9,0,3,1,3,0,11,5,2,6,2,10,2,15,10,2,15,3,3,15,15,2,6,8,1,5,2,10,2,10,2,1,2,2,6,10,9,0,6,9,0,1,1,2,6,8,1,2,9,5,6,2,15,3,10,2,3,15,10,2,15,3,2,15,2,4,6,8,3,6,8,2,15,2,3,7,8,1,2,5,11,5,6,2,10,2,15,15,10,2,15,3,3,15,15,2,7,8,1,2,3,15,15,15,10,2,15,15,15,15,3,3,15,15,15,1,6,8,3,7,1,3,3,15,3,3,15,6,15,15,15,15,15,15,5,15,15,15,15,15,7,15,15,15,15,15,15,15,5,67,108,111,99,107,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,23,99,97,108,99,117,108,97,116,101,95,99,117,114,114,101,110,116,95,105,110,100,101,120,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,28,100,121,110,97,109,105,99,95,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,21,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,97,112,121,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,18,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,111,114,21,100,121,110,97,109,105,99,95,104,101,97,108,116,104,95,102,97,99,116,111,114,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,31,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,36,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,30,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,25,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,23,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,3,109,97,120,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,4,112,111,111,108,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,6,118,101,99,116,111,114,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,201,175,0,0,0,0,0,0,0,1,0,0,11,99,10,6,6,0,0,0,0,0,0,0,0,36,4,9,10,7,6,0,0,0,0,0,0,0,0,36,12,9,5,11,9,12,9,11,9,32,4,15,5,25,11,1,1,11,3,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,17,10,6,6,0,0,0,0,0,0,0,0,36,4,38,10,3,11,6,12,10,46,11,10,56,0,12,17,6,0,0,0,0,0,0,0,0,12,16,10,7,6,0,0,0,0,0,0,0,0,36,4,52,11,3,11,7,12,11,46,11,11,56,0,12,16,5,54,11,3,1,10,0,10,2,10,1,10,4,10,5,10,17,77,10,8,17,1,12,13,10,0,10,2,10,1,10,4,10,5,11,16,77,10,8,17,2,12,14,11,0,11,1,11,2,11,4,11,5,11,17,77,11,8,17,7,12,15,10,14,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,95,11,13,11,14,17,28,11,15,17,29,12,12,5,97,17,31,12,12,11,12,2,1,1,0,0,16,86,10,2,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,17,6,0,0,0,0,0,0,0,0,12,14,10,12,12,10,14,12,14,4,56,1,32,4,31,10,6,4,31,13,10,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,10,14,10,15,35,4,78,5,36,14,10,10,14,66,19,12,9,10,2,10,9,20,12,8,46,11,8,17,17,12,16,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,9,20,33,4,57,10,5,12,13,10,0,10,1,10,2,11,9,20,10,3,11,13,10,6,17,3,12,11,11,17,11,11,11,16,17,29,22,12,17,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,2,1,11,1,1,11,0,1,11,17,2,2,1,0,0,23,76,10,2,10,3,12,7,46,11,7,17,25,12,14,1,14,14,65,19,12,12,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,6,0,0,0,0,0,0,0,0,12,10,10,14,12,11,14,14,14,4,56,1,32,4,31,10,6,4,31,13,11,10,4,68,19,11,12,6,1,0,0,0,0,0,0,0,22,12,12,10,10,10,12,35,4,68,5,36,14,11,10,10,66,19,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,10,4,10,8,20,33,4,49,10,5,12,9,10,0,10,1,10,2,11,8,20,10,3,11,9,10,6,17,4,12,13,11,15,11,13,22,12,15,11,10,6,1,0,0,0,0,0,0,0,22,12,10,5,31,11,2,1,11,1,1,11,0,1,11,15,2,3,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,5,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,4,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,6,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,5,1,0,0,7,27,10,1,10,2,11,3,17,26,1,12,7,11,5,4,13,11,7,11,4,22,12,7,5,17,11,7,11,4,23,12,7,11,0,11,1,11,2,17,8,1,12,6,11,7,11,6,17,29,2,6,1,0,0,7,27,10,1,10,2,11,3,17,26,12,6,1,11,5,4,13,11,6,11,4,22,12,6,5,17,11,6,11,4,23,12,6,11,0,11,1,11,2,17,8,12,7,1,11,6,11,7,17,29,2,7,1,0,0,27,91,10,1,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,6,0,0,0,0,0,0,0,0,12,14,10,12,12,9,14,12,14,4,56,1,32,4,27,13,9,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,10,14,10,15,35,4,81,5,36,14,9,10,14,66,19,12,8,10,1,10,8,20,17,22,12,16,1,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,8,20,33,4,56,10,5,12,13,10,0,10,2,10,1,11,8,20,10,3,11,13,10,6,17,3,12,17,11,10,10,17,11,16,17,29,22,12,10,11,11,11,17,22,12,11,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,1,1,11,2,1,11,0,1,11,10,11,11,17,28,2,8,1,0,0,30,42,11,0,17,32,12,8,10,1,10,2,12,3,46,11,3,17,21,12,9,10,1,10,2,17,20,12,4,12,6,11,1,11,2,17,19,12,5,12,7,11,8,11,9,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,12,10,12,11,5,17,13,11,4,17,29,12,10,11,12,11,7,17,14,11,6,17,29,12,11,11,10,11,11,2,9,1,0,0,32,76,10,4,6,0,0,0,0,0,0,0,0,36,4,9,10,5,6,0,0,0,0,0,0,0,0,36,12,7,5,11,9,12,7,11,7,32,4,15,5,23,11,1,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,12,10,4,6,0,0,0,0,0,0,0,0,36,4,36,10,2,11,4,12,8,46,11,8,56,0,12,12,6,0,0,0,0,0,0,0,0,12,11,10,5,6,0,0,0,0,0,0,0,0,36,4,50,11,2,11,5,12,9,46,11,9,56,0,12,11,5,52,11,2,1,10,0,10,1,10,3,10,12,77,10,11,77,10,6,17,10,12,10,11,0,11,1,11,3,10,10,11,12,77,11,11,77,11,6,17,11,12,13,11,10,11,13,2,10,1,0,0,33,41,10,1,10,2,17,18,12,10,1,12,8,12,9,12,7,11,0,11,1,11,2,11,3,11,4,11,5,17,12,12,11,10,11,10,10,35,4,27,11,7,11,11,11,9,17,29,22,12,6,5,39,11,7,10,11,11,9,17,29,22,11,11,11,10,23,11,8,17,29,22,12,6,11,6,2,11,1,0,0,7,24,10,1,10,2,17,18,1,12,7,1,1,1,11,0,11,1,11,2,11,4,11,5,11,6,17,12,12,8,11,3,11,8,17,29,17,27,11,7,23,17,29,2,12,1,0,0,35,62,10,1,10,2,17,24,12,11,12,12,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,5,4,16,11,12,11,3,22,12,12,5,20,11,12,11,3,23,12,12,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,35,11,5,4,31,11,11,11,4,22,12,11,5,35,11,11,11,4,23,12,11,11,0,11,1,11,2,17,8,12,7,12,8,11,12,11,8,17,29,12,10,11,11,11,7,17,29,12,9,10,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,56,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,5,60,11,9,11,10,17,28,12,6,11,6,2,0],"incentive":[161,28,235,11,6,0,0,0,14,1,0,30,2,30,66,3,96,181,1,4,149,2,46,5,195,2,164,3,7,231,5,187,6,8,162,12,96,6,130,13,94,10,224,13,116,11,212,14,2,12,214,14,189,15,13,147,30,40,14,187,30,8,15,195,30,2,0,44,0,72,0,62,0,64,1,18,1,78,2,21,2,26,2,27,2,36,2,53,2,73,2,76,2,77,0,82,0,4,12,1,0,1,0,6,4,0,0,3,12,0,0,7,3,0,0,5,3,0,1,8,12,0,4,9,7,0,5,12,7,0,6,0,4,1,0,1,7,1,8,0,8,2,12,1,0,1,10,13,4,0,11,10,12,2,7,1,4,1,13,11,2,0,0,47,0,1,0,0,67,2,1,0,0,66,2,1,0,0,15,3,1,1,0,0,79,4,1,0,0,24,5,6,0,0,25,7,1,1,0,0,39,8,9,0,0,40,10,11,0,0,33,12,13,0,1,41,46,37,0,1,42,47,37,0,2,60,1,34,0,2,61,37,34,0,3,51,37,34,0,5,38,1,36,1,0,5,48,36,33,0,6,69,49,40,1,0,7,74,32,9,0,8,37,50,51,1,0,9,34,22,1,1,3,10,52,0,14,0,11,14,26,1,2,7,4,11,22,24,45,2,7,4,11,23,27,28,2,7,4,11,29,24,25,2,7,4,11,52,0,18,2,7,4,11,63,27,43,2,7,4,12,58,52,1,1,12,12,68,22,1,1,8,13,65,15,16,0,14,70,39,40,1,0,26,17,26,19,29,21,25,17,22,17,24,17,20,29,20,30,25,19,22,19,24,19,15,22,26,38,31,22,29,41,25,38,27,38,22,38,23,19,23,38,17,22,19,22,28,51,1,7,8,13,0,4,7,8,2,15,1,7,8,13,9,7,8,2,6,8,9,2,3,3,11,10,1,9,0,3,2,7,8,13,5,7,8,2,6,8,9,7,8,5,2,5,5,6,8,2,7,8,5,3,2,5,2,10,15,10,15,6,7,8,2,7,11,0,1,9,0,6,8,9,7,8,5,5,7,8,13,2,6,8,2,2,1,3,3,6,8,2,2,3,4,3,3,15,2,5,6,8,2,7,8,5,6,8,9,2,5,3,10,8,6,10,15,10,2,1,8,11,1,6,8,13,1,5,2,15,1,1,11,12,2,9,0,9,1,2,2,8,1,1,2,1,8,2,1,9,0,1,7,1,2,6,11,12,2,9,0,9,1,9,0,1,1,3,7,11,12,2,9,0,9,1,9,0,9,1,2,7,11,12,2,9,0,9,1,9,0,1,7,9,1,1,8,3,1,8,4,4,1,11,8,1,9,0,3,7,8,1,1,6,8,9,1,8,6,1,15,1,11,12,2,5,15,1,8,7,2,15,15,2,5,15,3,11,10,1,9,0,3,7,8,13,1,11,8,1,9,0,1,11,0,1,9,0,17,7,8,5,3,2,5,5,5,3,3,7,15,15,10,15,7,11,12,2,5,15,3,7,8,1,15,10,15,7,11,12,2,5,15,1,9,1,18,6,11,12,2,5,15,3,3,15,15,10,15,15,6,11,12,2,5,15,3,6,8,1,15,15,3,15,15,15,15,10,15,1,6,9,1,2,7,8,5,2,3,7,8,5,2,5,9,5,15,3,7,8,1,15,15,6,11,12,2,5,15,15,7,11,12,2,5,15,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,13,1,11,10,1,9,0,2,9,0,5,1,6,8,1,10,10,8,6,3,3,3,10,2,6,8,1,10,15,15,6,11,12,2,5,15,10,15,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,9,73,110,99,101,110,116,105,118,101,12,73,110,99,101,110,116,105,118,101,66,97,108,16,80,111,111,108,65,100,109,105,110,83,101,116,116,105,110,103,8,80,111,111,108,73,110,102,111,16,80,111,111,108,79,119,110,101,114,83,101,116,116,105,110,103,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,3,97,100,100,8,97,100,100,95,112,111,111,108,5,97,100,109,105,110,6,97,100,109,105,110,115,5,97,115,99,105,105,5,97,115,115,101,116,6,97,115,115,101,116,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,24,99,97,108,99,95,112,111,111,108,95,117,112,100,97,116,101,95,114,101,119,97,114,100,115,12,99,108,97,105,109,95,114,101,119,97,114,100,5,99,108,111,99,107,4,99,111,105,110,10,99,111,105,110,95,116,121,112,101,115,8,99,111,110,116,97,105,110,115,7,99,114,101,97,116,111,114,11,99,117,114,114,101,110,116,95,105,100,120,18,100,105,115,116,114,105,98,117,116,101,100,95,97,109,111,117,110,116,6,101,97,114,110,101,100,4,101,109,105,116,9,101,110,100,95,116,105,109,101,115,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,14,103,101,116,95,112,111,111,108,95,99,111,117,110,116,13,103,101,116,95,112,111,111,108,95,105,110,102,111,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,9,105,110,99,101,110,116,105,118,101,13,105,110,100,101,120,95,114,101,119,97,114,100,115,19,105,110,100,101,120,95,114,101,119,97,114,100,115,95,112,97,105,100,115,4,105,110,105,116,11,105,110,116,111,95,115,116,114,105,110,103,16,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,7,108,101,110,100,105,110,103,3,109,117,108,3,110,101,119,6,111,98,106,101,99,116,10,111,114,97,99,108,101,95,105,100,115,5,111,119,110,101,114,6,111,119,110,101,114,115,5,112,111,111,108,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,9,115,97,102,101,95,109,97,116,104,6,115,101,110,100,101,114,9,115,101,116,95,97,100,109,105,110,9,115,101,116,95,111,119,110,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,11,115,116,97,114,116,95,116,105,109,101,115,7,115,116,111,114,97,103,101,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,13,116,111,116,97,108,95,115,117,112,112,108,121,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,13,117,112,100,97,116,101,95,114,101,119,97,114,100,16,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,22,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,95,112,97,105,100,115,5,117,116,105,108,115,5,118,97,108,117,101,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,153,183,0,0,0,0,0,0,3,8,154,183,0,0,0,0,0,0,3,8,155,183,0,0,0,0,0,0,3,8,156,183,0,0,0,0,0,0,3,8,157,183,0,0,0,0,0,0,3,8,158,183,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,43,8,11,19,2,31,3,32,15,21,11,8,1,9,0,1,2,12,43,2,49,3,28,10,8,6,71,10,3,35,10,3,75,10,15,59,10,15,45,10,15,46,10,11,12,2,5,15,80,10,11,12,2,5,15,81,10,11,12,2,5,15,54,10,2,2,2,6,43,8,11,30,5,56,11,12,2,15,1,17,11,12,2,15,1,57,11,12,2,2,8,1,20,10,2,3,2,3,65,5,55,15,83,1,4,2,3,65,5,16,15,83,1,0,22,0,0,0,0,1,15,10,0,17,21,10,0,46,17,30,10,0,56,0,10,0,56,0,11,0,56,1,64,20,0,0,0,0,0,0,0,0,18,2,56,2,2,1,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,1,10,1,56,3,32,4,27,11,0,15,1,10,1,10,2,56,4,5,35,11,0,15,1,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,3,56,6,2,2,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,2,10,1,56,3,32,4,27,11,0,15,2,10,1,10,2,56,4,5,35,11,0,15,2,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,4,56,7,2,3,1,4,0,31,139,1,10,0,16,0,20,10,8,46,17,30,33,4,9,5,17,11,0,1,11,8,1,11,1,1,7,0,39,10,3,11,1,17,18,36,4,27,10,4,10,3,36,12,9,5,29,9,12,9,11,9,4,32,5,38,11,0,1,11,8,1,7,1,39,10,0,16,3,10,2,56,8,32,4,65,10,0,15,3,10,2,10,2,6,0,0,0,0,0,0,0,0,64,33,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,20,0,0,0,0,0,0,0,0,18,1,56,9,10,0,15,4,10,2,68,20,11,0,15,3,10,2,56,10,12,12,10,12,16,5,65,33,12,11,10,12,15,5,56,11,17,16,68,33,10,12,15,6,10,3,68,9,10,12,15,7,10,4,68,9,10,12,15,8,10,6,77,68,34,10,12,15,9,10,6,77,11,4,11,3,23,77,17,13,68,34,10,12,15,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,34,10,12,15,11,10,8,56,12,68,35,10,12,15,12,10,8,56,12,68,35,10,12,15,13,10,8,56,12,68,35,11,12,15,14,11,7,68,20,11,5,11,6,10,8,56,13,12,10,11,8,17,21,11,2,11,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,10,57,0,56,14,2,4,3,0,0,42,118,10,0,16,3,10,3,56,8,4,111,11,1,17,18,12,11,10,0,11,2,10,11,10,3,10,4,12,8,12,7,12,6,12,5,46,11,5,11,6,11,7,11,8,17,5,12,20,12,15,11,0,15,3,11,3,56,10,12,18,11,11,10,18,15,15,21,10,18,16,5,65,33,12,17,6,0,0,0,0,0,0,0,0,12,12,10,12,10,17,35,4,108,5,45,14,15,10,12,66,34,20,12,14,14,20,10,12,66,34,20,12,19,10,18,15,10,10,12,67,34,12,13,10,14,11,13,21,10,18,15,11,10,12,67,35,12,16,10,16,10,4,12,9,46,11,9,56,15,4,79,10,16,10,4,56,16,1,11,16,10,4,11,14,56,17,10,18,15,12,10,12,67,35,12,21,10,21,10,4,12,10,46,11,10,56,15,4,99,10,21,10,4,56,16,1,11,21,10,4,11,19,56,17,11,12,6,1,0,0,0,0,0,0,0,22,12,12,5,40,11,18,1,5,117,11,2,1,11,0,1,11,1,1,2,5,0,0,0,44,166,1,11,0,16,3,10,3,56,18,12,14,10,14,16,5,65,33,12,13,6,0,0,0,0,0,0,0,0,12,7,64,34,0,0,0,0,0,0,0,0,12,10,64,34,0,0,0,0,0,0,0,0,12,22,10,7,10,13,35,4,159,1,5,20,10,14,16,6,10,7,66,9,20,12,17,10,17,10,14,16,15,20,35,4,36,10,14,16,15,20,12,17,10,14,16,7,10,7,66,9,20,12,6,10,2,10,6,35,4,48,10,2,12,6,10,14,16,9,10,7,66,34,20,12,15,10,14,16,10,10,7,66,34,20,12,9,10,17,10,6,35,4,90,11,6,11,17,23,77,12,19,10,1,10,3,17,10,1,12,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,10,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,15,11,19,17,14,11,20,26,12,8,11,9,11,8,22,12,9,13,10,10,9,68,34,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,21,10,4,7,6,34,4,151,1,10,14,16,12,10,7,66,35,12,5,10,5,10,4,56,15,4,114,11,5,10,4,56,19,20,12,21,5,116,11,5,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,14,16,11,10,7,66,35,12,12,10,12,10,4,56,15,4,133,1,11,12,10,4,56,19,20,12,11,5,135,1,11,12,1,10,1,10,3,10,4,17,11,1,12,18,11,9,11,11,23,11,18,24,12,16,11,21,11,16,22,12,21,13,22,11,21,68,34,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,15,11,1,1,11,14,1,11,10,11,22,2,6,1,4,0,48,105,10,0,11,2,11,3,10,1,55,0,20,10,4,17,4,11,0,15,3,10,1,55,0,20,56,10,12,9,10,1,55,1,20,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,9,16,12,10,8,66,35,12,12,10,12,10,4,56,15,4,36,11,12,10,4,56,19,20,12,11,5,38,11,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,9,15,13,10,8,67,35,12,14,10,14,10,4,12,6,46,11,6,56,15,4,56,10,14,10,4,56,16,12,13,11,14,10,4,10,11,56,17,11,11,11,13,23,17,12,26,12,7,11,9,16,8,11,8,66,34,20,12,10,10,1,55,2,20,10,7,22,11,10,37,4,81,5,87,11,5,1,11,1,1,7,4,39,10,1,55,2,20,10,7,22,10,1,54,2,21,11,1,54,3,11,7,52,56,20,11,5,56,21,11,4,56,22,2,7,1,0,0,9,19,6,0,0,0,0,0,0,0,0,12,2,10,0,16,3,10,1,56,8,4,15,11,0,16,3,11,1,56,18,16,5,65,33,12,2,5,17,11,0,1,11,2,2,8,1,0,0,53,47,10,0,16,3,10,1,56,8,4,6,5,10,11,0,1,7,2,39,11,0,16,3,11,1,56,18,12,3,10,3,16,5,65,33,10,2,36,4,22,5,26,11,3,1,7,2,39,10,3,16,6,10,2,66,9,20,10,3,16,7,10,2,66,9,20,10,3,16,9,10,2,66,34,20,11,3,16,14,11,2,66,20,20,2,9,1,0,0,54,97,64,33,0,0,0,0,0,0,0,0,12,5,64,34,0,0,0,0,0,0,0,0,12,14,64,20,0,0,0,0,0,0,0,0,12,9,10,0,16,3,10,3,56,8,4,87,11,2,17,18,12,6,10,0,11,1,11,6,10,3,10,4,17,5,12,11,1,11,0,16,3,11,3,56,18,12,10,10,10,16,5,65,33,12,8,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,84,5,38,10,10,16,13,10,7,66,35,12,13,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,10,13,10,4,56,15,4,55,11,13,10,4,56,19,20,12,12,5,57,11,13,1,13,5,10,10,16,5,10,7,66,33,20,68,33,13,14,14,11,10,7,66,34,20,11,12,23,68,34,13,9,10,10,16,14,10,7,66,20,20,68,20,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,33,11,10,1,5,93,11,1,1,11,0,1,11,2,1,11,5,11,14,11,9,2,2,1,2,2,2,3,2,4,2,5,1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,1,11,1,1,0,1,0,2,0,3,0,4,16,22,17,22,18,22,19,22,0,50,0],"lending":[161,28,235,11,6,0,0,0,10,1,0,22,2,22,52,3,74,130,1,4,204,1,38,5,242,1,222,2,7,208,4,238,3,8,190,8,96,6,158,9,10,10,168,9,49,12,217,9,201,4,0,26,0,25,0,30,0,34,0,39,2,32,1,14,1,15,1,19,1,41,0,44,0,3,3,0,0,11,3,0,0,0,3,0,0,8,3,0,0,5,3,0,1,4,12,0,3,6,12,1,0,1,4,9,12,0,5,7,8,0,6,1,8,0,7,2,12,1,0,1,9,10,2,0,0,46,0,1,0,0,16,2,1,1,0,0,47,3,1,1,0,0,13,4,1,1,0,0,35,5,1,1,0,0,29,6,1,2,0,0,1,43,11,1,0,2,20,22,1,1,0,2,21,19,1,1,0,2,22,32,33,2,0,0,2,23,22,28,1,0,2,24,22,16,1,0,3,16,17,1,1,0,3,17,35,1,1,0,3,31,18,16,1,0,3,42,18,16,1,0,3,47,23,1,1,0,4,33,0,7,0,7,45,15,16,1,0,8,18,12,1,1,3,9,37,9,10,0,10,38,13,14,1,0,21,12,18,12,12,12,14,12,8,12,19,20,11,12,15,12,16,12,19,24,7,12,19,26,10,12,19,29,9,31,15,34,16,34,13,34,19,36,1,6,8,7,0,8,6,8,9,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,5,7,8,11,9,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,5,7,8,5,7,8,11,7,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,7,8,11,8,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,11,12,6,8,9,6,8,8,7,8,7,2,7,11,6,1,9,0,2,7,11,6,1,9,1,11,10,1,9,0,5,3,7,8,5,7,8,11,1,1,5,3,3,3,5,11,10,1,9,0,1,6,8,11,1,5,5,7,8,5,6,8,9,7,8,7,2,5,1,9,0,3,11,10,1,9,0,3,7,8,11,1,11,10,1,9,0,1,6,11,10,1,9,0,1,3,3,7,11,6,1,9,0,11,10,1,9,0,7,8,11,2,6,11,6,1,9,0,3,5,6,8,9,7,8,7,2,5,15,1,8,0,6,3,3,3,3,3,5,6,6,8,9,6,8,8,7,8,7,2,5,15,4,7,11,6,1,9,0,3,5,7,8,11,1,8,1,3,3,3,5,1,8,2,8,3,3,15,3,3,3,5,11,10,1,9,0,1,15,1,8,3,14,3,3,3,3,15,15,3,3,3,3,3,5,11,10,1,9,0,15,2,9,0,9,1,7,6,8,9,6,8,8,7,8,7,5,2,2,15,3,15,15,15,1,9,1,2,7,11,6,1,9,0,3,1,8,4,11,66,111,114,114,111,119,69,118,101,110,116,5,67,108,111,99,107,4,67,111,105,110,12,68,101,112,111,115,105,116,69,118,101,110,116,9,73,110,99,101,110,116,105,118,101,20,76,105,113,117,105,100,97,116,105,111,110,67,97,108,108,69,118,101,110,116,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,112,97,121,69,118,101,110,116,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,13,87,105,116,104,100,114,97,119,69,118,101,110,116,6,97,109,111,117,110,116,6,98,111,114,114,111,119,5,99,108,111,99,107,4,99,111,105,110,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,9,105,110,99,101,110,116,105,118,101,7,108,101,110,100,105,110,103,16,108,105,113,117,105,100,97,116,101,95,97,109,111,117,110,116,14,108,105,113,117,105,100,97,116,101,95,117,115,101,114,16,108,105,113,117,105,100,97,116,105,111,110,95,99,97,108,108,5,108,111,103,105,99,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,5,112,97,117,115,101,4,112,111,111,108,5,114,101,112,97,121,7,114,101,115,101,114,118,101,6,115,101,110,100,101,114,10,115,112,108,105,116,95,99,111,105,110,7,115,116,111,114,97,103,101,2,116,111,10,116,120,95,99,111,110,116,101,120,116,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,13,117,112,100,97,116,101,95,114,101,119,97,114,100,5,117,116,105,108,115,5,118,97,108,117,101,15,119,104,101,110,95,110,111,116,95,112,97,117,115,101,100,8,119,105,116,104,100,114,97,119,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,41,160,0,0,0,0,0,0,0,2,3,36,2,37,5,12,3,1,2,4,36,2,37,5,40,5,12,3,2,2,3,36,2,37,5,12,3,3,2,3,36,2,37,5,12,3,4,2,4,36,2,37,5,28,5,27,3,0,0,0,0,1,8,11,0,17,17,32,4,5,5,7,7,0,39,2,1,1,4,0,8,45,10,1,46,17,0,10,7,46,17,20,12,11,11,6,10,0,10,1,10,3,10,11,17,6,11,4,11,5,10,7,56,0,12,12,14,12,56,1,12,9,10,2,11,12,11,7,56,2,11,2,10,9,12,8,46,11,8,56,3,12,10,11,0,11,1,10,3,10,11,11,10,77,56,4,11,3,11,11,11,9,18,0,56,5,2,2,1,4,0,21,50,10,2,46,17,0,10,8,46,17,20,12,14,11,7,10,0,10,2,10,4,10,14,17,6,10,3,11,5,12,9,46,11,9,56,3,12,13,11,0,11,1,11,2,10,4,11,14,11,13,77,56,6,12,11,10,3,11,11,12,10,46,11,10,56,7,12,12,11,3,10,12,10,6,10,8,56,8,11,4,11,8,46,17,20,11,6,11,12,18,1,56,9,2,3,1,4,0,25,35,10,2,46,17,0,10,6,46,17,20,12,9,10,3,10,5,12,7,46,11,7,56,3,12,8,11,0,11,1,11,2,10,4,10,9,11,8,77,56,10,11,3,10,5,11,9,10,6,56,8,11,4,11,6,46,17,20,11,5,18,2,56,11,2,4,1,4,0,27,65,10,2,46,17,0,10,7,46,17,20,12,14,11,5,11,6,10,7,56,0,12,15,14,15,56,1,12,13,10,3,11,15,10,7,56,2,10,3,10,13,12,8,46,11,8,56,3,12,12,11,0,11,1,11,2,10,4,10,14,11,12,77,56,12,12,10,10,3,11,10,52,12,9,46,11,9,56,7,12,11,10,11,6,0,0,0,0,0,0,0,0,36,4,53,11,3,10,11,11,14,10,7,56,8,5,55,11,3,1,11,4,11,7,46,17,20,11,13,11,11,23,18,3,56,13,2,5,1,4,0,30,90,10,2,46,17,0,10,11,46,17,20,12,23,11,10,10,0,10,2,10,5,10,8,17,6,11,7,11,9,10,11,56,0,12,24,14,24,56,1,12,18,10,4,11,24,10,11,56,2,10,4,11,18,12,12,46,11,12,56,3,12,21,11,0,11,1,11,2,10,8,10,5,11,3,11,21,77,56,14,12,25,12,17,12,16,10,4,11,17,52,12,13,46,11,13,56,7,12,20,11,4,11,20,10,23,10,11,56,8,10,6,11,16,52,12,14,46,11,14,56,15,12,19,10,6,10,19,10,23,11,11,56,16,10,6,11,25,52,12,15,46,11,15,56,15,12,22,11,6,10,22,56,17,11,5,11,23,11,8,11,19,11,22,22,18,4,56,18,2,0],"logic":[161,28,235,11,6,0,0,0,10,1,0,20,2,20,12,3,32,220,2,4,252,2,12,5,136,3,214,2,7,222,5,205,9,8,171,15,128,1,6,171,16,60,12,231,16,222,18,15,197,35,2,0,42,0,11,0,53,0,73,0,48,0,52,3,45,1,74,2,3,2,12,2,2,12,0,6,1,8,0,9,0,8,0,0,18,0,1,1,0,0,21,2,3,1,0,0,17,2,1,1,0,0,20,2,4,1,0,0,19,5,6,2,0,0,0,57,7,1,0,0,56,8,1,0,0,55,9,1,0,0,36,10,1,0,0,15,10,1,0,0,35,10,1,0,0,14,10,1,0,0,39,11,12,0,0,64,13,14,0,0,63,15,4,0,0,16,15,4,0,0,62,11,4,0,0,65,11,4,0,0,67,16,4,0,0,61,16,4,0,0,60,17,4,0,0,66,17,4,0,0,38,17,12,0,0,40,17,12,0,0,8,18,19,0,1,4,44,4,0,1,5,9,4,0,1,6,22,4,0,1,7,22,4,0,1,9,21,4,0,1,10,44,4,0,2,14,10,1,0,2,15,10,1,0,2,22,31,4,0,2,23,9,32,0,2,24,9,22,0,2,25,9,22,0,2,26,31,3,0,2,27,9,6,0,2,28,31,28,0,2,29,27,28,0,2,30,9,22,0,2,31,9,4,0,2,32,39,40,0,2,33,17,22,0,2,34,34,1,0,2,35,10,1,0,2,36,10,1,0,2,37,21,1,0,2,50,17,1,0,2,51,17,1,0,2,55,34,1,0,2,56,33,1,0,2,58,17,1,0,2,59,17,1,0,3,68,21,1,1,0,3,69,21,1,1,0,3,70,25,1,2,0,0,3,71,21,1,1,0,3,72,21,1,1,0,4,46,1,4,0,4,47,22,4,0,4,49,22,4,0,5,44,22,4,0,7,13,46,12,1,0,8,43,1,4,0,9,54,30,3,0,56,20,59,20,55,20,58,20,57,24,64,28,5,6,8,2,7,8,0,2,5,15,0,6,6,8,2,6,8,1,7,8,0,2,5,15,1,3,1,15,7,6,8,2,6,8,1,7,8,0,5,2,2,15,3,15,15,15,2,6,8,2,7,8,0,3,6,8,2,7,8,0,2,2,7,8,0,2,4,7,8,0,2,5,15,4,6,8,2,6,8,1,7,8,0,5,1,1,4,6,8,2,6,8,1,7,8,0,10,5,1,10,15,4,6,8,2,7,8,0,6,8,1,5,5,6,8,2,6,8,1,7,8,0,2,5,3,7,8,0,2,5,7,6,8,2,7,8,0,6,8,1,5,2,2,15,6,15,15,15,15,15,1,1,9,0,3,7,8,0,2,15,2,15,15,6,15,15,1,15,15,15,2,9,0,9,1,4,7,8,0,2,2,15,2,2,2,1,6,8,0,1,2,18,2,15,15,15,15,3,15,15,3,15,15,15,15,15,15,15,15,15,1,6,8,2,2,6,8,0,2,5,15,15,15,15,15,6,7,8,0,2,15,15,3,15,4,7,8,0,2,15,15,4,15,3,3,10,15,1,5,4,15,15,15,15,9,5,6,2,15,15,10,2,3,3,15,15,2,6,8,0,5,2,10,2,10,2,9,5,2,6,2,15,10,2,3,3,15,15,7,5,6,2,3,3,15,10,2,15,3,2,15,2,4,6,8,2,6,8,1,15,2,2,5,10,2,2,6,10,9,0,6,9,0,18,2,15,15,15,15,1,15,15,15,15,15,2,15,15,15,15,15,15,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,7,105,115,95,108,111,97,110,7,108,101,110,100,105,110,103,5,108,111,103,105,99,3,109,97,120,3,109,105,110,6,111,114,97,99,108,101,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,9,115,97,102,101,95,109,97,116,104,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,19,117,112,100,97,116,101,95,115,116,97,116,101,95,111,102,95,97,108,108,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,24,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,95,98,97,116,99,104,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,6,118,101,99,116,111,114,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,33,78,0,0,0,0,0,0,3,8,34,78,0,0,0,0,0,0,3,8,35,78,0,0,0,0,0,0,3,8,36,78,0,0,0,0,0,0,3,8,37,78,0,0,0,0,0,0,3,8,38,78,0,0,0,0,0,0,0,3,0,0,1,26,11,0,10,1,17,5,10,1,10,2,10,4,56,0,10,1,10,2,10,3,11,4,17,8,10,1,10,2,10,3,17,22,32,4,22,10,1,10,2,11,3,17,53,11,1,11,2,17,7,2,1,3,0,0,22,92,10,2,10,3,10,4,17,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,16,11,2,1,11,1,1,11,0,1,7,4,39,10,0,10,2,17,5,10,2,10,3,10,5,56,1,10,2,10,3,10,4,17,20,12,7,11,5,10,7,17,63,12,6,10,2,10,3,10,4,10,6,17,9,11,0,11,1,10,2,10,4,17,12,4,44,5,48,11,2,1,7,0,39,10,6,10,7,33,4,61,10,2,10,3,10,4,17,22,4,61,10,2,10,3,10,4,17,49,10,7,10,6,36,4,86,10,7,10,6,23,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,4,86,10,2,10,3,11,7,10,6,23,17,48,10,2,10,3,10,4,17,22,4,86,10,2,10,3,11,4,17,49,11,2,11,3,17,7,11,6,52,2,2,3,0,0,1,37,10,0,10,2,17,5,10,2,10,3,10,5,56,2,10,2,10,3,10,4,11,5,17,10,10,2,10,3,10,4,17,23,32,4,22,10,2,10,3,10,4,17,54,11,0,11,1,10,2,11,4,17,12,4,29,5,33,11,2,1,7,0,39,11,2,11,3,17,7,2,3,3,0,0,6,58,10,2,10,3,10,4,17,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,14,11,2,1,11,0,1,7,5,39,11,0,10,2,17,5,10,2,10,3,10,5,56,3,10,2,10,3,10,4,17,21,12,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,5,12,8,10,6,10,5,35,4,40,10,6,12,8,11,5,10,6,23,12,7,10,2,10,3,10,4,10,8,17,11,11,8,11,6,33,4,53,10,2,10,3,11,4,17,50,11,2,11,3,17,7,11,7,2,4,3,0,0,23,92,10,2,10,5,10,3,17,23,4,6,5,14,11,2,1,11,1,1,11,0,1,7,3,39,10,2,10,4,10,3,17,22,4,20,5,28,11,2,1,11,1,1,11,0,1,7,2,39,10,0,10,2,17,5,10,2,10,5,10,4,10,6,56,4,10,0,10,1,10,2,10,3,17,12,32,4,44,5,52,11,2,1,11,1,1,11,0,1,7,1,39,11,0,10,2,11,1,10,3,10,4,10,5,11,6,17,24,12,9,12,8,12,12,12,7,12,11,12,10,10,2,10,5,10,3,11,11,17,11,10,2,10,4,10,3,11,10,17,9,11,9,4,82,10,2,10,5,11,3,17,50,10,2,11,4,17,7,11,2,11,5,17,7,11,7,11,8,11,12,2,5,0,0,0,26,25,10,1,46,17,40,12,2,49,0,12,3,10,3,10,2,35,4,20,5,11,10,0,10,1,10,3,17,6,11,3,49,1,22,12,3,5,6,11,1,1,11,0,1,2,6,0,0,0,29,97,11,0,17,66,12,8,10,1,10,2,12,3,46,11,3,17,37,12,11,10,8,11,11,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,18,10,1,10,2,17,36,12,4,12,6,10,1,10,2,17,35,12,5,12,7,10,18,11,7,17,28,10,6,17,62,12,13,11,18,11,5,17,27,10,4,17,62,12,12,10,1,10,2,17,34,1,12,14,1,1,1,10,1,10,2,17,41,12,19,12,20,10,19,10,12,10,4,23,17,62,12,9,11,20,10,13,11,6,23,17,62,12,10,11,9,10,12,17,61,12,15,11,10,10,13,17,61,12,17,11,19,10,12,11,4,23,17,62,11,14,17,62,10,12,17,61,12,16,10,1,10,2,11,12,11,13,11,8,10,16,17,52,11,1,11,2,11,17,11,15,11,16,22,17,45,2,7,0,0,0,22,15,10,0,10,1,17,26,12,2,10,0,10,1,10,2,17,29,12,3,11,0,11,1,11,2,11,3,17,51,2,8,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,47,2,9,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,32,2,10,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,46,2,11,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,31,2,12,1,0,0,1,8,11,0,11,2,11,1,11,3,17,14,17,60,38,2,13,1,0,0,35,37,14,3,65,36,12,6,6,0,0,0,0,0,0,0,0,12,5,64,4,0,0,0,0,0,0,0,0,12,7,10,5,10,6,35,4,29,5,12,10,0,10,2,10,1,14,3,10,5,66,36,20,17,14,12,4,13,7,11,4,68,4,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,7,11,2,1,11,1,1,11,0,1,11,7,2,14,1,0,0,37,33,10,0,10,2,10,1,10,3,17,16,12,6,10,0,10,1,10,2,10,3,17,15,12,5,11,0,11,2,11,1,11,3,17,17,12,7,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,29,11,6,11,7,17,61,11,5,17,62,12,4,5,31,17,65,12,4,11,4,2,15,1,0,0,38,72,10,1,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,6,0,0,0,0,0,0,0,0,12,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,10,9,10,10,35,4,56,5,22,14,8,10,9,66,28,12,5,10,1,10,5,20,17,38,12,11,1,1,10,0,10,2,10,1,11,5,20,10,3,17,19,12,12,11,6,10,12,11,11,17,62,22,12,6,11,7,11,12,22,12,7,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,17,11,1,1,11,2,1,11,0,1,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,11,6,11,7,17,61,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,16,1,0,0,41,59,10,2,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,6,0,0,0,0,0,0,0,0,12,9,10,9,10,10,35,4,51,5,20,14,8,10,9,66,28,12,6,10,2,10,6,20,12,5,46,11,5,17,33,12,11,10,0,10,1,10,2,11,6,20,10,3,17,19,12,7,11,12,11,7,11,11,17,62,22,12,12,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,15,11,2,1,11,1,1,11,0,1,11,12,2,17,1,0,0,42,49,10,2,10,3,12,4,46,11,4,17,43,12,9,1,14,9,65,28,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,41,5,20,14,9,10,6,66,28,12,5,10,0,10,1,10,2,11,5,20,10,3,17,18,12,8,11,10,11,8,22,12,10,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,15,11,2,1,11,1,1,11,0,1,11,10,2,18,1,0,0,43,18,10,2,10,3,11,4,17,21,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,19,1,0,0,43,18,10,2,10,3,11,4,17,20,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,20,1,0,0,22,15,10,0,10,1,11,2,17,44,1,12,3,11,0,11,1,17,36,1,12,4,11,3,11,4,17,62,2,21,1,0,0,22,15,10,0,10,1,11,2,17,44,12,3,1,11,0,11,1,17,36,12,4,1,11,3,11,4,17,62,2,22,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,1,12,4,14,4,14,1,56,5,2,23,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,12,4,1,14,4,14,1,56,5,2,24,0,0,0,47,113,10,1,10,4,17,38,1,12,15,12,16,10,0,10,2,10,1,10,4,10,3,17,19,11,16,17,62,12,20,10,0,10,2,10,1,10,5,11,3,17,18,12,19,9,12,12,10,19,10,20,35,4,32,11,19,12,20,8,12,12,10,1,10,5,12,7,46,11,7,17,39,12,18,10,0,10,2,11,6,11,18,17,30,12,21,10,21,10,20,36,4,54,11,21,10,20,23,12,11,5,58,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,11,21,12,20,10,20,11,15,17,62,12,8,11,1,10,4,17,42,12,22,10,8,11,22,17,62,12,23,10,20,10,23,23,12,17,10,0,10,2,10,20,10,4,17,25,12,13,10,0,10,2,11,20,10,5,17,25,12,14,10,0,10,2,11,17,10,4,17,25,12,9,10,0,10,2,11,23,11,4,17,25,12,24,11,0,11,2,11,11,11,8,22,11,5,17,25,12,10,11,13,11,14,11,9,11,24,11,10,11,12,2,0,41,0],"pool":[161,28,235,11,6,0,0,0,14,1,0,18,2,18,54,3,72,145,1,4,217,1,30,5,247,1,203,1,7,194,3,145,4,8,211,7,96,6,179,8,20,10,199,8,67,11,138,9,2,12,140,9,146,3,13,158,12,6,14,164,12,6,15,170,12,4,0,37,1,13,1,47,2,14,2,15,2,23,2,36,2,44,2,46,0,2,12,1,0,1,0,3,12,0,0,5,3,0,0,4,3,0,0,6,3,0,0,7,3,0,1,8,7,0,2,10,7,0,3,0,4,1,0,1,4,1,12,1,0,1,6,11,4,0,8,9,2,0,0,28,0,1,0,0,17,2,1,1,0,0,20,3,1,1,0,0,50,4,1,1,0,0,21,5,1,1,0,0,52,6,1,1,0,0,51,7,1,1,0,0,26,8,9,1,0,0,16,10,11,0,0,35,12,11,1,0,0,48,12,11,1,0,2,25,1,26,1,0,2,30,26,27,0,3,31,25,11,1,0,3,42,29,19,1,0,3,49,32,11,1,0,3,53,1,19,1,0,4,24,30,24,1,0,4,29,24,19,1,0,4,49,23,11,1,0,5,22,18,1,1,3,6,33,0,13,0,7,38,17,1,1,12,7,41,18,1,1,8,8,40,14,15,0,22,16,16,18,23,20,20,21,19,18,18,18,13,18,11,18,20,28,14,18,17,18,20,31,22,24,15,18,7,18,1,7,8,11,0,3,6,8,1,2,7,8,11,3,7,11,0,1,9,0,11,9,1,9,0,7,8,11,4,7,11,0,1,9,0,3,5,7,8,11,2,7,11,0,1,9,0,3,5,7,8,1,7,11,0,1,9,0,3,5,7,8,11,5,6,8,1,7,11,0,1,9,0,3,5,7,8,11,1,6,11,0,1,9,0,1,2,3,3,2,2,1,3,2,6,11,0,1,9,0,3,1,8,10,1,6,8,11,1,5,1,8,1,2,9,0,5,1,9,0,1,11,8,1,9,0,1,11,0,1,9,0,1,8,2,2,11,8,1,9,0,3,1,6,11,9,1,9,0,1,11,9,1,9,0,2,7,11,8,1,9,0,11,8,1,9,0,1,8,7,1,8,6,1,8,4,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,11,1,8,5,1,6,11,8,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,19,80,111,111,108,66,97,108,97,110,99,101,82,101,103,105,115,116,101,114,10,80,111,111,108,67,114,101,97,116,101,11,80,111,111,108,68,101,112,111,115,105,116,12,80,111,111,108,87,105,116,104,100,114,97,119,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,7,99,114,101,97,116,111,114,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,2,105,100,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,7,108,101,110,100,105,110,103,3,110,101,119,10,110,101,119,95,97,109,111,117,110,116,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,9,114,101,99,105,112,105,101,110,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,7,115,116,111,114,97,103,101,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,4,122,101,114,111,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,17,164,0,0,0,0,0,0,3,8,18,164,0,0,0,0,0,0,0,2,4,27,8,10,14,11,8,1,9,0,45,11,8,1,9,0,19,2,1,2,2,27,8,10,18,5,2,2,1,18,5,3,2,4,40,5,12,3,34,3,37,8,6,4,2,3,40,5,12,3,37,8,6,5,2,4,40,5,39,5,12,3,37,8,6,0,18,0,0,0,0,1,11,10,0,17,21,10,0,46,17,24,18,1,11,0,46,17,24,56,0,2,1,3,0,0,1,13,10,2,17,21,56,1,56,1,11,1,57,0,56,2,11,2,46,17,24,18,2,56,3,2,2,3,0,0,22,20,14,1,56,4,12,4,11,1,56,5,12,3,11,0,54,0,11,3,56,6,1,11,2,46,17,24,11,4,56,7,17,12,18,4,56,8,2,3,3,0,0,24,20,11,0,54,0,10,1,56,9,10,3,56,10,12,4,11,3,46,17,24,10,2,11,1,56,7,17,12,18,5,56,11,11,4,11,2,56,12,2,4,3,0,0,19,22,10,0,55,0,56,13,10,1,38,4,7,5,11,11,0,1,7,1,39,10,0,54,0,11,1,56,9,12,2,11,0,54,1,11,2,56,6,1,2,5,1,0,0,1,22,10,1,55,1,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,1,11,2,56,9,11,4,56,10,11,3,56,12,2,6,3,0,0,1,22,10,1,55,0,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,0,11,2,56,9,11,4,56,10,11,3,56,12,2,7,1,0,0,1,4,11,0,55,2,20,2,8,1,0,0,1,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,9,1,0,0,9,8,11,0,56,14,12,2,11,1,11,2,49,9,17,8,2,10,1,0,0,9,8,11,0,56,14,12,2,11,1,49,9,11,2,17,8,2,0,1,0,2,0,3,0,18,1,18,2,18,0,32,0,43,0],"ray_math":[161,28,235,11,6,0,0,0,7,1,0,4,3,4,55,5,59,8,7,67,101,8,168,1,64,6,232,1,200,1,12,176,3,168,5,0,6,1,0,0,4,0,1,0,0,9,0,1,0,0,1,0,1,0,0,2,0,1,0,0,11,2,1,0,0,10,2,1,0,0,7,2,1,0,0,5,2,1,0,0,8,1,1,0,0,12,1,1,0,1,3,0,1,0,0,1,15,2,15,15,1,1,7,97,100,100,114,101,115,115,8,104,97,108,102,95,114,97,121,8,104,97,108,102,95,119,97,100,3,109,97,120,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,10,114,97,121,95,116,111,95,119,97,100,3,119,97,100,7,119,97,100,95,100,105,118,7,119,97,100,95,109,117,108,10,119,97,100,95,116,111,95,114,97,121,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,100,167,179,182,224,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,178,211,89,91,240,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,77,4,0,0,0,0,0,0,3,8,78,4,0,0,0,0,0,0,3,8,79,4,0,0,0,0,0,0,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,0,2,2,1,0,0,0,2,7,3,2,3,1,0,0,0,2,7,1,2,4,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,1,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,1,22,7,0,26,2,5,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,0,26,37,4,20,5,22,7,5,39,11,0,7,0,24,11,2,22,11,1,26,2,6,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,3,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,3,22,7,2,26,2,7,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,2,26,37,4,20,5,22,7,5,39,11,0,7,2,24,11,2,22,11,1,26,2,8,1,0,0,2,19,7,4,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,1,10,1,11,0,22,12,2,10,2,11,1,38,4,13,5,15,7,6,39,11,2,7,4,26,2,9,1,0,0,1,15,10,0,7,4,24,12,1,10,1,7,4,26,11,0,33,4,11,5,13,7,5,39,11,1,2,0],"safe_math":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,30,5,32,6,7,38,34,8,72,32,6,104,50,12,154,1,163,2,0,5,0,0,0,1,0,0,6,0,1,0,0,4,0,1,0,0,1,0,1,0,0,3,0,1,0,0,2,0,1,0,2,15,15,1,15,0,3,97,100,100,3,100,105,118,3,109,105,110,3,109,111,100,3,109,117,108,9,115,97,102,101,95,109,97,116,104,3,115,117,98,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,3,8,233,3,0,0,0,0,0,0,3,8,234,3,0,0,0,0,0,0,3,8,235,3,0,0,0,0,0,0,3,8,236,3,0,0,0,0,0,0,3,8,237,3,0,0,0,0,0,0,0,1,0,0,1,13,10,0,11,1,22,12,2,10,2,11,0,38,4,9,5,11,7,0,39,11,2,2,1,1,0,0,2,11,10,1,10,0,37,4,5,5,7,7,1,39,11,0,11,1,23,2,2,1,0,0,1,21,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,10,1,24,12,2,10,2,11,0,26,11,1,33,4,17,5,19,7,2,39,11,2,2,3,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,5,5,7,7,3,39,11,0,11,1,26,2,4,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,4,39,11,0,11,1,25,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,0],"storage":[161,28,235,11,6,0,0,0,12,1,0,29,2,29,92,3,121,144,3,4,137,4,54,5,191,4,153,3,7,216,7,131,16,8,219,23,96,6,187,24,93,10,152,25,164,1,12,188,26,186,19,13,246,45,66,15,184,46,2,0,120,0,90,0,94,1,22,1,131,1,1,141,1,2,30,2,31,2,47,2,85,2,123,2,127,2,130,1,0,4,12,0,0,11,12,0,0,10,12,0,0,9,4,0,0,20,4,0,0,8,5,0,0,19,5,0,0,15,4,0,0,0,4,0,0,3,4,0,0,12,3,0,0,5,3,0,1,6,12,1,0,1,1,7,12,0,3,13,7,0,4,17,7,0,6,1,8,0,7,2,12,1,0,1,9,18,4,0,10,14,12,2,7,1,4,1,12,16,2,0,0,73,0,1,0,0,144,1,2,1,0,0,143,1,3,1,0,0,74,4,1,1,0,0,115,5,1,0,0,117,6,1,0,0,107,6,1,0,0,112,6,1,0,0,118,6,1,0,0,106,6,1,0,0,113,6,1,0,0,108,6,1,0,0,116,6,1,0,0,114,6,1,0,0,110,6,1,0,0,109,6,1,0,0,111,6,1,0,0,102,2,1,1,0,0,88,2,7,0,0,59,2,8,0,0,64,9,10,0,0,58,11,8,0,0,52,11,12,0,0,60,13,14,0,0,50,13,14,0,0,53,13,15,0,0,55,13,15,0,0,61,13,15,0,0,65,16,15,0,0,56,11,17,0,0,49,11,14,0,0,63,13,14,0,0,62,11,14,0,0,51,13,18,0,0,57,13,19,0,0,133,1,20,1,0,0,134,1,21,1,0,0,68,20,1,0,0,70,22,1,0,0,44,22,1,0,0,69,22,1,0,0,43,22,1,0,0,67,23,1,0,0,42,23,1,0,0,71,24,1,0,0,136,1,16,1,0,0,97,16,1,0,0,135,1,16,1,0,0,96,16,1,0,0,146,1,25,1,1,0,0,45,3,1,0,1,36,43,1,1,0,1,132,1,62,17,1,0,1,145,1,63,1,1,0,2,93,1,14,0,4,48,1,38,1,0,4,75,38,12,0,5,35,57,7,1,0,5,72,57,59,1,0,5,95,60,36,1,0,6,125,40,17,0,7,54,42,8,1,0,8,46,36,1,1,3,9,84,0,26,0,10,21,41,1,2,7,4,10,25,49,50,2,7,4,10,28,46,47,2,7,4,10,35,49,7,2,7,4,10,84,0,33,2,7,4,10,95,46,55,2,7,4,11,91,30,1,1,12,11,119,36,1,1,8,12,105,27,28,0,70,29,70,31,68,32,68,34,71,35,17,36,55,36,68,39,64,32,61,36,51,36,62,44,66,32,65,32,67,34,65,34,67,39,65,39,69,39,64,39,64,34,66,34,57,8,58,8,59,8,52,36,53,36,1,7,8,20,0,1,6,8,2,2,6,8,1,7,8,2,20,6,8,1,6,8,13,6,8,16,7,8,2,2,1,15,15,15,15,15,15,15,15,15,15,15,15,6,11,17,1,9,0,7,8,20,3,6,8,0,7,8,2,1,4,6,8,0,7,8,2,2,15,1,1,1,2,2,6,8,2,5,2,10,2,10,2,2,6,8,2,2,1,8,14,2,7,8,2,2,1,15,2,15,15,3,7,8,2,2,5,1,3,5,15,15,15,15,15,3,15,15,15,4,7,8,2,2,15,15,6,7,8,2,2,15,15,3,15,4,7,8,2,2,5,15,3,7,8,7,5,15,3,7,8,2,2,15,8,6,8,1,6,8,13,7,8,2,2,7,11,12,1,9,0,3,5,7,8,20,1,8,18,1,6,8,20,1,5,1,8,1,2,9,0,5,1,8,0,2,2,8,3,1,11,19,2,9,0,9,1,2,5,8,4,1,8,2,1,9,0,18,2,15,15,15,8,7,8,7,3,8,8,8,9,2,8,14,1,15,15,15,2,2,8,3,1,8,15,2,5,15,1,6,8,16,3,7,11,19,2,9,0,9,1,9,0,9,1,1,6,11,17,1,9,0,3,6,8,13,2,7,8,20,1,8,11,1,7,8,3,2,7,11,19,2,9,0,9,1,9,0,1,7,9,1,3,2,2,8,14,2,6,11,19,2,9,0,9,1,9,0,1,6,9,1,1,6,8,4,1,6,8,3,3,15,6,8,3,15,3,7,8,7,7,8,3,7,8,7,1,9,1,3,10,2,8,4,7,8,4,2,6,10,9,0,6,9,0,2,3,7,8,4,2,1,3,2,7,10,9,0,3,5,2,3,7,15,3,3,2,6,11,12,1,9,0,3,5,6,8,13,7,11,12,1,9,0,3,5,7,8,20,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,12,67,111,105,110,77,101,116,97,100,97,116,97,18,76,105,113,117,105,100,97,116,105,111,110,70,97,99,116,111,114,115,8,79,119,110,101,114,67,97,112,6,80,97,117,115,101,100,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,23,82,101,115,101,114,118,101,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,11,82,101,115,101,114,118,101,68,97,116,97,7,83,116,111,114,97,103,101,15,83,116,111,114,97,103,101,65,100,109,105,110,67,97,112,26,83,116,111,114,97,103,101,67,111,110,102,105,103,117,114,97,116,111,114,83,101,116,116,105,110,103,6,83,116,114,105,110,103,5,84,97,98,108,101,12,84,111,107,101,110,66,97,108,97,110,99,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,20,85,115,101,114,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,8,85,115,101,114,73,110,102,111,3,97,100,100,5,97,115,99,105,105,9,98,97,115,101,95,114,97,116,101,5,98,111,110,117,115,6,98,111,114,114,111,119,14,98,111,114,114,111,119,95,98,97,108,97,110,99,101,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,5,99,108,111,99,107,4,99,111,105,110,9,99,111,105,110,95,116,121,112,101,11,99,111,108,108,97,116,101,114,97,108,115,12,99,111,110,102,105,103,117,114,97,116,111,114,8,99,111,110,116,97,105,110,115,11,99,114,101,97,116,101,95,112,111,111,108,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,20,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,114,97,116,101,4,100,97,116,97,16,100,101,99,114,101,97,115,101,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,12,100,101,115,116,111,114,121,95,117,115,101,114,4,101,109,105,116,5,101,118,101,110,116,3,103,101,116,13,103,101,116,95,97,115,115,101,116,95,108,116,118,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,13,103,101,116,95,99,111,105,110,95,116,121,112,101,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,12,103,101,116,95,100,101,99,105,109,97,108,115,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,20,103,101,116,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,16,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,114,101,115,101,114,118,101,11,105,110,116,111,95,115,116,114,105,110,103,11,105,115,95,105,115,111,108,97,116,101,100,20,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,5,108,111,97,110,115,5,108,111,103,105,99,3,108,116,118,10,109,117,108,116,105,112,108,105,101,114,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,111,114,97,99,108,101,95,105,100,5,112,97,117,115,101,6,112,97,117,115,101,100,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,105,111,3,114,97,121,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,14,114,101,115,101,114,118,101,95,102,97,99,116,111,114,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,97,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,98,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,99,18,114,101,115,101,114,118,101,95,118,97,108,105,100,97,116,105,111,110,8,114,101,115,101,114,118,101,115,14,114,101,115,101,114,118,101,115,95,99,111,117,110,116,6,115,101,110,100,101,114,13,115,101,116,95,98,97,115,101,95,114,97,116,101,14,115,101,116,95,98,111,114,114,111,119,95,99,97,112,24,115,101,116,95,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,98,111,110,117,115,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,114,97,116,105,111,25,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,7,115,101,116,95,108,116,118,14,115,101,116,95,109,117,108,116,105,112,108,105,101,114,23,115,101,116,95,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,115,101,116,95,112,97,117,115,101,18,115,101,116,95,114,101,115,101,114,118,101,95,102,97,99,116,111,114,14,115,101,116,95,115,117,112,112,108,121,95,99,97,112,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,7,115,116,111,114,97,103,101,14,115,117,112,112,108,121,95,98,97,108,97,110,99,101,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,9,116,104,114,101,115,104,111,108,100,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,9,117,115,101,114,95,105,110,102,111,10,117,115,101,114,95,115,116,97,116,101,5,117,115,101,114,115,5,118,97,108,117,101,6,118,101,99,116,111,114,7,118,101,114,115,105,111,110,15,118,101,114,115,105,111,110,95,109,105,103,114,97,116,101,20,118,101,114,115,105,111,110,95,118,101,114,105,102,105,99,97,116,105,111,110,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,3,0,0,0,0,0,0,0,3,8,248,167,0,0,0,0,0,0,3,8,249,167,0,0,0,0,0,0,3,8,250,167,0,0,0,0,0,0,3,8,251,167,0,0,0,0,0,0,3,8,252,167,0,0,0,0,0,0,3,8,253,167,0,0,0,0,0,0,3,8,254,167,0,0,0,0,0,0,3,8,255,167,0,0,0,0,0,0,2,1,255,0,2,1,66,8,18,1,2,1,66,8,18,2,2,7,66,8,18,142,1,3,89,1,103,11,19,2,2,8,3,104,2,139,1,10,5,137,1,11,19,2,5,8,4,3,2,21,66,2,87,2,32,8,14,76,1,122,15,27,15,40,15,38,15,39,15,37,15,121,8,7,26,8,7,78,3,82,15,129,1,15,128,1,15,29,8,8,79,8,9,99,15,100,15,101,15,4,2,2,33,10,2,80,10,2,5,2,1,41,15,6,2,1,41,15,7,2,2,138,1,11,19,2,5,15,126,15,8,2,5,23,15,83,15,77,15,98,15,86,15,9,2,3,92,15,24,15,124,15,10,2,3,105,5,34,5,140,1,1,11,2,1,89,1,0,0,0,0,1,27,10,0,17,63,18,1,10,0,46,17,72,56,0,10,0,17,63,18,0,10,0,46,17,72,56,1,10,0,17,63,7,0,9,10,0,56,2,49,0,64,28,0,0,0,0,0,0,0,0,11,0,56,3,18,2,56,4,2,1,0,0,0,1,10,11,0,16,0,20,7,0,33,4,7,5,9,7,1,39,2,2,1,4,0,1,16,10,1,16,0,20,7,0,35,4,7,5,11,11,1,1,7,2,39,7,0,11,1,15,0,21,2,3,1,4,0,37,117,10,3,46,17,1,10,3,16,1,20,12,35,10,35,7,9,35,4,12,5,24,11,3,1,11,1,1,11,19,1,11,18,1,11,2,1,7,5,39,10,3,46,56,5,10,3,16,1,20,12,20,11,4,12,29,56,6,17,56,12,30,11,5,12,31,11,6,12,32,11,7,12,33,17,54,12,34,17,54,12,21,11,13,12,22,11,14,12,23,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,24,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,25,11,2,17,60,12,26,11,8,11,10,11,11,11,12,11,9,18,8,12,27,11,15,11,16,11,17,18,9,12,28,11,20,11,29,11,30,11,31,11,32,11,33,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,34,11,21,11,24,11,25,11,26,11,22,11,23,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,27,11,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,12,37,10,3,15,2,10,35,11,37,56,8,11,35,49,1,22,11,3,15,1,21,11,18,56,9,12,36,11,1,11,36,11,19,56,10,2,4,1,4,0,1,11,10,1,46,17,1,10,2,11,1,15,3,21,11,2,18,11,56,11,2,5,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,4,21,2,6,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,5,21,2,7,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,6,21,2,8,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,7,21,2,9,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,9,21,2,10,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,10,21,2,11,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,11,21,2,12,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,12,21,2,13,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,13,21,2,14,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,15,21,2,15,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,16,21,2,16,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,17,21,2,17,1,0,0,48,36,56,6,17,56,12,3,10,0,16,1,20,12,1,49,0,12,2,10,2,10,1,35,4,33,5,14,10,0,16,2,10,2,56,13,16,18,20,10,3,34,4,24,5,28,11,0,1,7,7,39,11,2,49,1,22,12,2,5,9,11,0,1,2,18,1,0,0,1,4,11,0,16,3,20,2,19,1,0,0,1,4,11,0,16,1,20,2,20,1,0,0,51,23,10,0,16,19,10,1,56,14,32,4,11,11,0,1,64,8,0,0,0,0,0,0,0,0,64,8,0,0,0,0,0,0,0,0,2,11,0,16,19,11,1,56,15,12,2,10,2,16,20,20,11,2,16,21,20,2,21,1,0,0,1,7,11,0,16,2,11,1,56,13,16,22,20,2,22,1,0,0,1,7,11,0,16,2,11,1,56,13,16,18,20,2,23,1,0,0,1,7,11,0,16,2,11,1,56,13,16,4,20,2,24,1,0,0,1,7,11,0,16,2,11,1,56,13,16,5,20,2,25,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,23,20,11,2,16,24,20,2,26,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,25,20,11,2,16,26,20,2,27,1,0,0,52,14,11,0,16,2,11,1,56,13,12,2,10,2,16,27,16,28,20,11,2,16,29,16,28,20,2,28,1,0,0,53,41,11,0,16,2,11,1,56,13,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,4,16,27,16,30,10,2,56,16,4,22,10,4,16,27,16,30,10,2,56,17,20,12,5,10,4,16,29,16,30,10,2,56,16,4,36,11,4,16,29,16,30,11,2,56,17,20,12,3,5,38,11,4,1,11,5,11,3,2,29,1,0,0,1,7,11,0,16,2,11,1,56,13,16,31,20,2,30,1,0,0,1,7,11,0,16,2,11,1,56,13,16,6,20,2,31,1,0,0,1,7,11,0,16,2,11,1,56,13,16,7,20,2,32,1,0,0,1,7,11,0,16,2,11,1,56,13,16,32,20,2,33,1,0,0,52,26,11,0,16,2,11,1,56,13,12,2,10,2,16,8,16,9,20,10,2,16,8,16,10,20,10,2,16,8,16,11,20,10,2,16,8,16,12,20,11,2,16,8,16,13,20,2,34,1,0,0,52,18,11,0,16,2,11,1,56,13,12,2,10,2,16,14,16,15,20,10,2,16,14,16,16,20,11,2,16,14,16,17,20,2,35,3,0,0,45,17,10,0,46,17,1,11,0,15,2,11,1,56,12,12,4,11,3,10,4,15,23,21,11,2,11,4,15,24,21,2,36,3,0,0,45,29,10,0,46,17,1,11,0,15,2,11,1,56,12,12,6,11,2,10,6,15,26,21,11,3,10,6,15,25,21,11,4,10,6,15,31,21,10,6,16,32,20,11,5,22,11,6,15,32,21,2,37,3,0,0,54,31,10,0,46,17,1,11,0,15,2,11,1,56,12,12,5,10,5,15,27,12,6,11,5,15,29,12,4,10,6,16,28,20,11,2,22,11,6,15,28,21,10,4,16,28,20,11,3,22,11,4,15,28,21,2,38,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,42,2,39,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,43,2,40,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,42,2,41,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,43,2,42,0,0,0,14,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,0,15,30,11,1,11,3,10,2,22,56,19,10,0,16,28,20,11,2,22,11,0,15,28,21,2,43,0,0,0,14,37,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,3,10,2,38,4,17,5,21,11,0,1,7,6,39,10,0,15,30,11,1,11,3,10,2,23,56,19,10,0,16,28,20,11,2,23,11,0,15,28,21,2,44,3,0,0,45,14,11,0,15,2,11,1,56,12,12,3,10,3,16,32,20,11,2,22,11,3,15,32,21,2,45,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,64,8,0,0,0,0,0,0,0,0,11,3,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,21,14,1,56,22,32,4,37,11,5,15,21,11,1,68,8,5,39,11,5,1,2,46,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,21,14,1,56,23,12,3,4,17,11,4,15,21,11,3,56,24,1,5,19,11,4,1,2,47,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,11,3,64,8,0,0,0,0,0,0,0,0,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,20,14,1,56,22,32,4,37,11,5,15,20,11,1,68,8,5,39,11,5,1,2,48,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,20,14,1,56,23,12,3,4,17,11,4,15,20,11,3,56,24,1,5,19,11,4,1,2,49,1,0,0,61,58,10,2,10,3,12,8,46,11,8,17,22,56,6,17,56,33,4,11,5,21,11,2,1,11,1,1,11,4,1,11,7,1,7,8,39,11,2,15,2,11,3,56,12,15,32,12,10,10,4,10,10,20,52,12,9,46,11,9,56,25,12,11,10,5,12,12,11,5,10,11,35,4,44,11,11,12,12,10,10,20,10,12,77,23,11,10,21,11,1,11,4,11,12,11,6,11,7,56,26,2,50,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,2,1,2,4,2,3,2,2,3,4,3,5,3,13,3,14,3,16,8,0,8,1,8,2,8,3,8,4,3,17,9,0,9,1,9,2,3,2,2,6,4,0,4,1,3,1,3,6,3,7,3,8,3,9,3,10,7,1,3,11,7,0,3,12,3,15,0,81,0],"utils":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,16,3,26,47,4,73,12,5,85,63,7,148,1,156,1,8,176,2,64,6,240,2,20,12,132,3,114,0,14,1,3,1,4,1,12,1,13,1,0,4,1,0,1,2,1,12,1,0,1,4,2,2,0,0,10,0,1,1,0,0,11,0,2,1,0,2,5,1,8,1,0,2,6,1,2,1,0,2,9,7,1,1,0,2,15,5,6,1,0,3,7,11,8,1,12,4,8,9,10,0,5,4,4,4,2,4,6,1,0,4,3,4,3,11,1,1,9,0,3,7,8,2,1,11,1,1,9,0,1,11,0,1,9,0,2,3,11,1,1,9,0,1,9,0,1,6,11,1,1,9,0,1,3,3,7,11,1,1,9,0,3,7,8,2,0,1,6,8,2,1,5,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,4,99,111,105,110,12,100,101,115,116,114,111,121,95,122,101,114,111,12,105,110,116,111,95,98,97,108,97,110,99,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,10,115,112,108,105,116,95,99,111,105,110,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,117,116,105,108,115,5,118,97,108,117,101,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,176,179,0,0,0,0,0,0,3,8,177,179,0,0,0,0,0,0,0,1,0,0,3,44,14,0,56,0,12,3,10,1,6,0,0,0,0,0,0,0,0,36,4,8,5,12,11,2,1,7,0,39,11,3,10,1,38,4,17,5,21,11,2,1,7,1,39,13,0,11,1,10,2,56,1,12,4,14,0,56,0,6,0,0,0,0,0,0,0,0,33,4,37,11,2,1,11,0,56,2,11,4,2,11,0,11,2,46,17,7,56,3,11,4,2,1,1,0,0,8,6,11,0,11,1,11,2,56,4,56,5,2,0],"validation":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,12,3,22,82,4,104,4,5,108,83,7,191,1,154,2,8,217,3,64,6,153,4,70,12,223,4,237,4,0,22,0,15,0,13,1,3,1,16,1,0,12,0,3,1,7,0,4,2,7,0,0,18,0,1,1,0,0,21,0,1,1,0,0,17,0,1,1,0,0,20,0,1,1,0,0,19,2,1,2,0,0,1,5,8,10,0,1,6,7,6,0,1,7,8,9,0,1,8,8,10,0,1,9,8,9,0,2,11,1,10,0,2,12,9,10,0,2,14,9,10,0,4,4,1,5,1,0,4,10,5,6,0,13,4,13,14,3,7,8,0,2,15,0,4,7,8,0,2,2,15,7,7,8,0,2,15,15,15,15,15,1,9,0,1,8,2,1,8,1,2,6,8,0,2,2,7,8,0,2,2,15,15,1,15,8,7,8,0,2,15,15,15,15,15,15,9,7,8,0,2,15,15,15,15,15,15,15,4,7,8,0,2,7,8,0,2,1,9,1,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,5,97,115,99,105,105,3,103,101,116,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,13,103,101,116,95,99,111,105,110,95,116,121,112,101,9,103,101,116,95,105,110,100,101,120,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,11,105,110,116,111,95,115,116,114,105,110,103,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,9,116,121,112,101,95,110,97,109,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,225,171,0,0,0,0,0,0,3,8,226,171,0,0,0,0,0,0,3,8,227,171,0,0,0,0,0,0,3,8,228,171,0,0,0,0,0,0,3,8,229,171,0,0,0,0,0,0,3,8,230,171,0,0,0,0,0,0,3,8,231,171,0,0,0,0,0,0,0,1,0,0,3,58,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,1,12,8,10,0,10,1,17,7,1,12,5,11,8,11,5,17,12,12,7,11,0,11,1,17,8,12,9,11,7,11,2,22,17,10,24,12,6,11,9,11,6,38,4,55,5,57,7,1,39,2,1,1,0,0,11,54,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,10,11,0,11,1,17,7,12,6,12,7,11,10,11,7,17,12,12,9,11,5,11,6,17,12,12,8,11,9,11,8,11,2,22,38,4,51,5,53,7,3,39,2,2,1,0,0,12,71,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,11,10,0,10,1,17,7,12,6,12,8,11,11,11,8,17,12,12,10,11,5,11,6,17,12,12,9,10,9,10,2,22,10,10,35,4,51,5,55,11,0,1,7,3,39,11,9,11,2,22,11,10,17,11,12,7,11,0,11,1,17,5,11,7,38,4,68,5,70,7,2,39,2,3,1,0,0,8,23,11,0,11,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,15,7,4,39,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,20,5,22,7,0,39,2,4,1,0,0,13,40,10,0,11,1,12,5,12,4,56,0,17,14,11,4,46,11,5,17,6,33,4,13,5,17,11,0,1,7,4,39,11,0,11,2,12,7,12,6,56,1,17,14,11,6,46,11,7,17,6,33,4,30,5,32,7,4,39,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,37,5,39,7,0,39,2,0]},"type_origin_table":[{"module_name":"pool","struct_name":"Pool","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolAdminCap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolCreate","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolBalanceRegister","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolDeposit","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolWithdraw","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"OwnerCap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"StorageAdminCap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"Storage","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"ReserveData","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"UserInfo","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"ReserveConfigurationMap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"UserConfigurationMap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"TokenBalance","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"BorrowRateFactors","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"LiquidationFactors","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"StorageConfiguratorSetting","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"Paused","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"IncentiveBal","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"PoolInfo","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"Incentive","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"PoolOwnerSetting","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"PoolAdminSetting","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"DepositEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"WithdrawEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"BorrowEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"RepayEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"LiquidationCallEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":9},"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f":{"upgraded_id":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f","upgraded_version":1}}}},"owner":"Immutable","previous_transaction":"3fqrGiknVvk82qum6zLYR749UTTyavaoH8TLU6bym8di","storage_rebate":213582800},{"data":{"Move":{"type_":"GasCoin","has_public_transfer":true,"version":26932892,"contents":[179,30,221,225,60,75,107,81,44,23,235,191,230,227,135,11,211,138,190,145,151,205,207,128,30,246,4,231,19,97,15,161,200,98,235,223,0,0,0,0]}},"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"previous_transaction":"7SuYS2Zphhb7KFnoanQBArUmXUQjKhehZ5fQkET4wNcN","storage_rebate":988000},{"data":{"Package":{"id":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f","version":1,"module_map":{"oracle":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,36,3,48,102,4,150,1,16,5,166,1,216,1,7,254,2,157,3,8,155,6,64,6,219,6,70,10,161,7,38,12,199,7,251,3,13,194,11,12,0,19,1,11,1,18,1,26,1,29,1,30,0,1,12,0,0,2,12,0,0,4,8,0,0,3,4,0,1,0,8,0,2,7,4,0,3,5,12,2,7,1,4,1,5,6,2,0,0,16,0,1,0,0,37,2,1,0,0,36,3,1,0,0,24,4,1,0,0,22,5,1,0,0,32,6,1,0,0,33,7,1,0,0,14,8,9,0,1,28,24,25,0,2,17,0,11,0,3,8,26,1,2,7,4,3,9,22,34,2,7,4,3,10,28,29,2,7,4,3,12,22,23,2,7,4,3,17,0,18,2,7,4,4,21,15,1,1,12,4,25,20,1,1,8,5,23,12,13,0,15,14,15,16,14,17,16,19,13,17,10,17,12,17,11,17,1,7,8,7,0,1,6,8,2,2,6,8,0,7,8,2,3,6,8,0,7,8,2,3,6,6,8,0,6,8,4,7,8,2,2,15,2,5,6,8,1,6,8,4,7,8,2,2,15,5,6,8,1,6,8,4,7,8,2,10,2,10,15,3,6,8,4,6,8,2,2,3,1,15,2,2,8,5,11,6,2,2,8,3,1,8,5,1,6,8,7,1,5,1,8,0,2,9,0,5,1,8,1,2,2,8,3,1,11,6,2,9,0,9,1,1,8,2,1,9,0,2,2,7,11,6,2,2,8,3,2,6,11,6,2,9,0,9,1,9,0,1,1,1,6,8,4,1,3,3,7,11,6,2,9,0,9,1,9,0,9,1,3,2,7,8,3,7,11,6,2,2,8,3,2,7,11,6,2,9,0,9,1,9,0,1,7,9,1,3,3,3,6,2,1,2,1,15,5,1,3,6,11,6,2,2,8,3,6,8,3,1,1,6,9,1,5,67,108,111,99,107,14,79,114,97,99,108,101,65,100,109,105,110,67,97,112,15,79,114,97,99,108,101,70,101,101,100,101,114,67,97,112,5,80,114,105,99,101,11,80,114,105,99,101,79,114,97,99,108,101,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,7,100,101,99,105,109,97,108,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,2,105,100,4,105,110,105,116,3,110,101,119,6,111,98,106,101,99,116,6,111,114,97,99,108,101,13,112,114,105,99,101,95,111,114,97,99,108,101,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,20,114,101,103,105,115,116,101,114,95,116,111,107,101,110,95,112,114,105,99,101,6,115,101,110,100,101,114,19,115,101,116,95,117,112,100,97,116,101,95,105,110,116,101,114,118,97,108,12,115,104,97,114,101,95,111,98,106,101,99,116,5,116,97,98,108,101,9,116,105,109,101,115,116,97,109,112,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,15,117,112,100,97,116,101,95,105,110,116,101,114,118,97,108,18,117,112,100,97,116,101,95,116,111,107,101,110,95,112,114,105,99,101,24,117,112,100,97,116,101,95,116,111,107,101,110,95,112,114,105,99,101,95,98,97,116,99,104,5,118,97,108,117,101,7,118,101,114,115,105,111,110,15,118,101,114,115,105,111,110,95,109,105,103,114,97,116,101,20,118,101,114,115,105,111,110,95,118,101,114,105,102,105,99,97,116,105,111,110,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,48,117,0,0,0,0,0,0,3,8,80,195,0,0,0,0,0,0,3,8,81,195,0,0,0,0,0,0,3,8,82,195,0,0,0,0,0,0,3,8,83,195,0,0,0,0,0,0,3,8,84,195,0,0,0,0,0,0,0,2,1,15,8,5,1,2,1,15,8,5,2,2,4,15,8,5,35,3,31,3,20,11,6,2,2,8,3,3,2,3,34,15,13,2,27,3,0,0,0,0,10,27,10,0,17,9,18,0,10,0,46,17,17,56,0,10,0,17,9,18,1,10,0,46,17,17,56,1,10,0,17,9,12,1,11,0,56,2,12,2,11,1,7,0,7,1,11,2,18,2,56,3,2,1,0,0,0,1,10,11,0,16,0,20,7,0,33,4,7,5,9,7,2,39,2,2,0,4,0,1,16,10,1,16,0,20,7,0,35,4,7,5,11,11,1,1,7,3,39,7,0,11,1,15,0,21,2,3,1,4,0,1,8,10,1,46,17,1,11,2,11,1,15,1,21,2,4,1,4,0,21,30,10,2,46,17,1,11,2,15,2,12,7,10,7,10,3,12,6,46,11,6,56,4,32,4,15,5,21,11,7,1,11,1,1,7,6,39,11,7,11,3,11,4,11,5,11,1,17,8,18,3,56,5,2,5,1,4,0,27,34,10,2,46,17,1,11,2,15,2,12,7,10,7,10,3,12,5,46,11,5,56,4,4,14,5,20,11,7,1,11,1,1,7,5,39,11,7,11,3,56,6,12,6,11,4,10,6,15,3,21,11,1,17,8,11,6,15,4,21,2,6,1,4,0,30,53,10,2,46,17,1,14,3,65,31,12,6,10,6,14,4,65,32,33,4,12,5,20,11,2,1,11,1,1,11,0,1,7,4,39,6,0,0,0,0,0,0,0,0,12,5,10,5,10,6,35,4,46,5,27,14,3,10,5,66,31,12,7,10,0,10,1,10,2,11,7,20,14,4,10,5,66,32,20,17,5,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,22,11,2,1,11,1,1,11,0,1,2,7,1,0,0,33,60,10,1,17,1,10,1,16,2,12,5,10,5,10,2,56,4,4,10,5,18,11,5,1,11,1,1,11,0,1,7,5,39,11,5,11,2,56,7,12,6,11,0,17,8,12,4,9,12,7,10,6,16,3,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,44,11,4,10,6,16,4,20,23,11,1,16,1,20,37,12,3,5,48,11,1,1,9,12,3,11,3,4,52,8,12,7,11,7,10,6,16,3,20,11,6,16,5,20,2,2,1,2,2,2,3,3,0,3,2,3,1,0]},"type_origin_table":[{"module_name":"oracle","struct_name":"OracleAdminCap","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"},{"module_name":"oracle","struct_name":"OracleFeederCap","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"},{"module_name":"oracle","struct_name":"PriceOracle","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"},{"module_name":"oracle","struct_name":"Price","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":8}}}},"owner":"Immutable","previous_transaction":"5rr1KbGr5ht2kWrPwgArYuaYsauoDG8CpuJLnaKnkgL6","storage_rebate":15010000},{"data":{"Move":{"type_":{"Other":{"address":"0000000000000000000000000000000000000000000000000000000000000002","module":"package","name":"UpgradeCap","type_args":[]}},"has_public_transfer":true,"version":10941462,"contents":[219,161,180,15,53,55,68,27,81,210,132,143,192,161,73,97,14,72,230,124,28,196,140,106,214,65,118,118,34,0,6,35,178,52,89,21,222,31,155,214,97,233,171,39,235,39,227,118,205,246,57,19,89,234,100,251,253,180,85,11,9,44,26,160,4,0,0,0,0,0,0,0,0]}},"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"previous_transaction":"3fqrGiknVvk82qum6zLYR749UTTyavaoH8TLU6bym8di","storage_rebate":1634000}],"local_exec_effects":{"messageVersion":"v1","status":{"status":"success"},"executedEpoch":"158","gasUsed":{"computationCost":"750000","storageCost":"216204800","storageRebate":"2595780","nonRefundableStorageFee":"26220"},"modifiedAtVersions":[{"objectId":"0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1","sequenceNumber":"26932892"},{"objectId":"0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623","sequenceNumber":"10941462"}],"transactionDigest":"4fxF3X4N8D6JGByWdbJvCCv1iuoT8GSEhXgPHJnzNHWP","created":[{"owner":"Immutable","reference":{"objectId":"0x0440aedc27c9a57ea357bd8fe1525a00d60d7f442a380924a7e7c1d79853bb8b","version":5,"digest":"Gm4LuFuwBvgmBuLSMAxEp2zkp1RLsfgwzv8xdscmzowH"}}],"mutated":[{"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"reference":{"objectId":"0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1","version":26932893,"digest":"J4QwR5VqcZDAekVtbABBjvZ6n1sCi4nDS7hBiaDkex37"}},{"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"reference":{"objectId":"0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623","version":26932893,"digest":"Bt3M5wQ3RStRoKWwioJ8vJUQvxL453r9HWBH2MpBzQaA"}}],"gasObject":{"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"reference":{"objectId":"0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1","version":26932893,"digest":"J4QwR5VqcZDAekVtbABBjvZ6n1sCi4nDS7hBiaDkex37"}},"dependencies":["3fqrGiknVvk82qum6zLYR749UTTyavaoH8TLU6bym8di","5rr1KbGr5ht2kWrPwgArYuaYsauoDG8CpuJLnaKnkgL6","7SuYS2Zphhb7KFnoanQBArUmXUQjKhehZ5fQkET4wNcN","ACKQVv64dXCmpxE1QPU2QMLxVpmtbzrFGMtWYY6szJrQ","BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn"]},"pre_exec_diag":{"loaded_child_objects":[]}} \ No newline at end of file diff --git a/crates/iota-replay/tests/sandbox_snapshots/ozN2rhczEUC39poaeVYxMN6b6TEAjiFX7jFSQFhbKmL.json b/crates/iota-replay/tests/sandbox_snapshots/ozN2rhczEUC39poaeVYxMN6b6TEAjiFX7jFSQFhbKmL.json new file mode 100644 index 00000000000..48357cb166c --- /dev/null +++ b/crates/iota-replay/tests/sandbox_snapshots/ozN2rhczEUC39poaeVYxMN6b6TEAjiFX7jFSQFhbKmL.json @@ -0,0 +1 @@ +{"transaction_info":{"tx_digest":"ozN2rhczEUC39poaeVYxMN6b6TEAjiFX7jFSQFhbKmL","sender_signed_data":[{"intent_message":{"intent":{"scope":0,"version":0,"app_id":0},"value":{"V1":{"kind":{"ProgrammableTransaction":{"inputs":[{"Object":{"SharedObject":{"id":"0x79d7106ea18373fc7542b0849d5ebefc3a9daf8b664a4f82d9b35bbd0c22042d","initial_shared_version":3195547,"mutable":false}}},{"Object":{"SharedObject":{"id":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","initial_shared_version":4346051,"mutable":true}}},{"Object":{"SharedObject":{"id":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","initial_shared_version":3478819,"mutable":true}}}],"commands":[{"MoveCall":{"package":"0x7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d","module":"migrate_proposal","function":"migrate_version","type_arguments":[],"arguments":[{"Input":0},{"Input":1},{"Input":2}]}}]}},"sender":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497","gas_data":{"payment":[["0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004",4346051,"2JXT4194QZ7FC7UEs8Hyh9zRpuCBY7PMZXKEXcvRXfu8"]],"owner":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497","price":820,"budget":500000000},"expiration":"None"}}},"tx_signatures":["AOd+1UjKqv2kF/b4EHVzWhv6U5qPXHWYTFiGjCWOFWdHCxDLrQfA79H9TLHDXHnCdKZCp5srbZA83/tBZ1g72gWOFOU0HVyF2bseRzKe9FsEoneTl3bxmBQ7Hi6cHBw6dg=="]}],"sender":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497","input_objects":[{"SharedMoveObject":{"id":"0x79d7106ea18373fc7542b0849d5ebefc3a9daf8b664a4f82d9b35bbd0c22042d","initial_shared_version":3195547,"mutable":false}},{"SharedMoveObject":{"id":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","initial_shared_version":4346051,"mutable":true}},{"SharedMoveObject":{"id":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","initial_shared_version":3478819,"mutable":true}},{"MovePackage":"0x7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d"},{"ImmOrOwnedMoveObject":["0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004",4346051,"2JXT4194QZ7FC7UEs8Hyh9zRpuCBY7PMZXKEXcvRXfu8"]}],"kind":{"ProgrammableTransaction":{"inputs":[{"Object":{"SharedObject":{"id":"0x79d7106ea18373fc7542b0849d5ebefc3a9daf8b664a4f82d9b35bbd0c22042d","initial_shared_version":3195547,"mutable":false}}},{"Object":{"SharedObject":{"id":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","initial_shared_version":4346051,"mutable":true}}},{"Object":{"SharedObject":{"id":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","initial_shared_version":3478819,"mutable":true}}}],"commands":[{"MoveCall":{"package":"0x7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d","module":"migrate_proposal","function":"migrate_version","type_arguments":[],"arguments":[{"Input":0},{"Input":1},{"Input":2}]}}]}},"modified_at_versions":[["0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004",4346051],["0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934",4346051],["0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621",4346049],["0x898dd24cc48476a7a2ff36372a443fefa53545b016feb317bb091e60e06b2e4c",3478819]],"shared_object_refs":[["0x79d7106ea18373fc7542b0849d5ebefc3a9daf8b664a4f82d9b35bbd0c22042d",4346051,"4KddCShzYaYA2QcVbNphjberckmHf3BQQ13QxTqWzqkh"],["0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934",4346051,"4BbiRiXkVTtkgnXwJJM1Px9u9Pw8XcTYeoi8xCAe5AiH"],["0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621",4346049,"Hbp9rYyMyeFxfGkw6EEUfFpmVrc85NfAyTs2mE6EcxHj"]],"gas":[["0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004",4346051,"2JXT4194QZ7FC7UEs8Hyh9zRpuCBY7PMZXKEXcvRXfu8"]],"gas_budget":500000000,"gas_price":820,"executed_epoch":55,"dependencies":["GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","5kWByxejQ95cxQ5zUCba3WyivedWBmtisRa4ZaWJuWpm","6B3tXa5PpoaRUQiYcytsC1M9fkfzXUc49NsWgC335qC1"],"effects":{"messageVersion":"v1","status":{"status":"success"},"executedEpoch":"55","gasUsed":{"computationCost":"820000","storageCost":"8291600","storageRebate":"7967916","nonRefundableStorageFee":"80484"},"modifiedAtVersions":[{"objectId":"0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004","sequenceNumber":"4346051"},{"objectId":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","sequenceNumber":"4346051"},{"objectId":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","sequenceNumber":"4346049"},{"objectId":"0x898dd24cc48476a7a2ff36372a443fefa53545b016feb317bb091e60e06b2e4c","sequenceNumber":"3478819"}],"sharedObjects":[{"objectId":"0x79d7106ea18373fc7542b0849d5ebefc3a9daf8b664a4f82d9b35bbd0c22042d","version":4346051,"digest":"4KddCShzYaYA2QcVbNphjberckmHf3BQQ13QxTqWzqkh"},{"objectId":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","version":4346051,"digest":"4BbiRiXkVTtkgnXwJJM1Px9u9Pw8XcTYeoi8xCAe5AiH"},{"objectId":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","version":4346049,"digest":"Hbp9rYyMyeFxfGkw6EEUfFpmVrc85NfAyTs2mE6EcxHj"}],"transactionDigest":"ozN2rhczEUC39poaeVYxMN6b6TEAjiFX7jFSQFhbKmL","mutated":[{"owner":{"AddressOwner":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497"},"reference":{"objectId":"0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004","version":4346052,"digest":"3DSxmS55mjcxjp4zni3HqxtpNBchuuEz1HkdY2cSGvx4"}},{"owner":{"Shared":{"initial_shared_version":4346051}},"reference":{"objectId":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","version":4346052,"digest":"EWBifxLP1W6RnLYEFEbsq5SrqCT28VBseSN6JDeBVB4g"}},{"owner":{"Shared":{"initial_shared_version":3478819}},"reference":{"objectId":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","version":4346052,"digest":"97QWr9zmCmV9L7WJHmG6ynSLbwtXtqaxEvJPzCw5r7ZK"}},{"owner":{"ObjectOwner":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621"},"reference":{"objectId":"0x898dd24cc48476a7a2ff36372a443fefa53545b016feb317bb091e60e06b2e4c","version":4346052,"digest":"39Twrdee3mTpzMUiccQdE2c5qYizZGmbGHsqycnCTA2j"}}],"gasObject":{"owner":{"AddressOwner":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497"},"reference":{"objectId":"0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004","version":4346052,"digest":"3DSxmS55mjcxjp4zni3HqxtpNBchuuEz1HkdY2cSGvx4"}},"eventsDigest":"J8u3bJn6FAMiadwesmkYjvm5kvNMKTNJecRQ9H5cndop","dependencies":["GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","5kWByxejQ95cxQ5zUCba3WyivedWBmtisRa4ZaWJuWpm","6B3tXa5PpoaRUQiYcytsC1M9fkfzXUc49NsWgC335qC1"]},"protocol_version":11,"epoch_start_timestamp":1686071016387,"reference_gas_price":820},"required_objects":[{"data":{"Move":{"type_":"GasCoin","has_public_transfer":true,"version":4346051,"contents":[21,32,188,177,31,211,164,184,188,23,93,46,13,51,223,242,149,206,222,73,87,55,189,56,32,255,148,164,64,84,144,4,144,115,177,150,11,0,0,0]}},"owner":{"AddressOwner":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497"},"previous_transaction":"GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","storage_rebate":988000},{"data":{"Move":{"type_":{"Other":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"governance_v1","name":"Proposal","type_args":[{"struct":{"address":"7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d","module":"migrate_proposal","name":"Certificate","type_args":[]}}]}},"has_public_transfer":false,"version":4346051,"contents":[57,252,244,217,254,131,156,97,185,211,22,22,230,144,104,131,113,142,173,223,177,229,32,89,200,170,223,35,213,70,217,52,101,133,153,88,189,98,227,10,160,87,31,151,18,150,47,89,9,141,30,178,159,115,176,145,217,215,19,23,216,230,116,151,55,0,0,0,0,0,0,0,0,85,0,0,0,0,0,0,0,64,55,102,54,98,51,56,48,100,98,102,51,54,50,51,54,50,48,53,54,49,53,99,54,52,102,99,98,98,54,99,52,101,57,52,53,52,98,55,54,101,102,102,48,57,55,100,100,54,99,54,53,51,52,102,54,100,53,48,55,48,100,49,55,100,0,0,0,1]}},"owner":{"Shared":{"initial_shared_version":4346051}},"previous_transaction":"GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","storage_rebate":2728400},{"data":{"Move":{"type_":{"Other":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"genesis","name":"GovernanceGenesis","type_args":[]}},"has_public_transfer":false,"version":4346049,"contents":[66,239,144,6,110,100,146,21,230,171,145,57,154,131,225,165,70,127,215,204,67,110,139,131,173,184,116,58,14,251,166,33,4,81,180,29,10,30,207,114,139,134,133,233,172,144,221,93,63,141,97,190,62,113,16,212,34,139,152,136,114,24,131,222,197,178,165,4,156,215,21,134,54,45,12,106,56,227,76,250,174,126,169,206,109,84,1,163,80,80,106,21,248,23,191,114,2,0,0,0,0,0,0,0,0,1,254,147,243,188,197,217,213,55,232,158,184,214,115,240,234,207,29,60,135,22,250,128,58,250,46,171,68,79,42,167,134,211]}},"owner":{"Shared":{"initial_shared_version":3478819}},"previous_transaction":"6B3tXa5PpoaRUQiYcytsC1M9fkfzXUc49NsWgC335qC1","storage_rebate":2181200},{"data":{"Move":{"type_":{"Other":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"governance_v1","name":"GovernanceInfo","type_args":[]}},"has_public_transfer":false,"version":4346051,"contents":[121,215,16,110,161,131,115,252,117,66,176,132,157,94,190,252,58,157,175,139,102,74,79,130,217,179,91,189,12,34,4,45,1,254,147,243,188,197,217,213,55,232,158,184,214,115,240,234,207,29,60,135,22,250,128,58,250,46,171,68,79,42,167,134,211,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,0,0,0,0,0,0,0,1,101,133,153,88,189,98,227,10,160,87,31,151,18,150,47,89,9,141,30,178,159,115,176,145,217,215,19,23,216,230,116,151,0]}},"owner":{"Shared":{"initial_shared_version":3195547}},"previous_transaction":"GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","storage_rebate":2097600},{"data":{"Move":{"type_":{"Other":{"address":"0000000000000000000000000000000000000000000000000000000000000002","module":"dynamic_field","name":"Field","type_args":[{"struct":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"genesis","name":"Version","type_args":[]}},{"struct":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"genesis","name":"Version_1_0_0","type_args":[]}}]}},"has_public_transfer":false,"version":3478819,"contents":[137,141,210,76,196,132,118,167,162,255,54,55,42,68,63,239,165,53,69,176,22,254,179,23,187,9,30,96,224,107,46,76,0,0]}},"owner":{"ObjectOwner":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621"},"previous_transaction":"McsTGPLu3V5rpv6CyPNv6rG5f4NAZMuVbWfadUqPjR2","storage_rebate":2150800},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000001","version":2,"module_map":{"address":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,3,7,10,15,8,25,32,12,57,16,0,0,0,1,0,1,0,0,1,3,7,97,100,100,114,101,115,115,6,108,101,110,103,116,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,6,32,0,0,0,0,0,0,0,2,0],"ascii":[161,28,235,11,6,0,0,0,11,1,0,4,2,4,14,3,18,84,4,102,8,5,110,59,7,169,1,200,1,8,241,2,32,6,145,3,10,10,155,3,11,12,166,3,186,2,13,224,5,4,0,5,0,16,0,2,7,0,0,0,7,0,1,1,7,1,0,0,0,8,0,1,0,0,20,2,3,0,0,21,2,4,0,0,3,5,6,0,0,18,7,8,0,0,17,9,1,0,0,14,5,10,0,0,4,5,11,0,0,10,3,2,0,0,6,1,0,0,0,13,0,6,0,0,11,0,6,0,1,9,13,14,1,0,1,12,12,6,1,0,1,15,8,13,1,0,1,19,14,13,1,0,13,3,12,3,14,3,15,3,1,2,1,8,1,1,10,2,1,8,0,1,11,2,1,8,0,1,6,8,0,1,1,2,7,8,0,8,1,0,1,7,8,0,1,3,1,6,10,2,1,6,11,2,1,9,0,1,11,2,1,9,0,1,9,0,2,3,3,4,67,104,97,114,6,79,112,116,105,111,110,6,83,116,114,105,110,103,24,97,108,108,95,99,104,97,114,97,99,116,101,114,115,95,112,114,105,110,116,97,98,108,101,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,4,98,121,116,101,5,98,121,116,101,115,4,99,104,97,114,12,100,101,115,116,114,111,121,95,115,111,109,101,10,105,110,116,111,95,98,121,116,101,115,17,105,115,95,112,114,105,110,116,97,98,108,101,95,99,104,97,114,7,105,115,95,115,111,109,101,13,105,115,95,118,97,108,105,100,95,99,104,97,114,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,8,112,111,112,95,99,104,97,114,9,112,117,115,104,95,99,104,97,114,4,115,111,109,101,6,115,116,114,105,110,103,10,116,114,121,95,115,116,114,105,110,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,1,0,0,0,0,0,0,2,1,7,10,2,1,2,1,6,2,0,1,0,0,8,9,10,0,17,10,4,4,5,6,7,0,39,11,0,18,1,2,1,1,0,0,4,12,11,0,17,2,12,1,14,1,56,0,4,7,5,9,7,0,39,11,1,56,1,2,2,1,0,0,15,30,14,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,25,5,11,14,0,10,1,66,0,20,17,10,32,4,20,56,2,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,5,40,11,0,18,0,56,3,2,3,1,0,0,15,32,10,0,16,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,29,5,12,10,0,16,0,10,1,66,0,20,17,11,32,4,24,11,0,1,9,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,40,8,2,4,1,0,0,8,7,11,0,15,0,14,1,16,1,20,68,0,2,5,1,0,0,8,5,11,0,15,0,69,0,18,1,2,6,1,0,0,8,4,11,0,17,7,65,0,2,7,1,0,0,8,3,11,0,16,0,2,8,1,0,0,8,3,11,0,19,0,2,9,1,0,0,8,3,11,0,19,1,2,10,1,0,0,8,4,11,0,49,127,37,2,11,1,0,0,6,13,10,0,49,32,38,4,9,11,0,49,126,37,12,1,5,11,9,12,1,11,1,2,0,0,1,0,0],"bcs":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,7,7,15,13,8,28,32,12,60,4,0,0,0,1,0,1,1,0,1,6,9,0,1,10,2,3,98,99,115,8,116,111,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,0],"bit_vector":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,36,7,77,109,8,186,1,32,6,218,1,40,10,130,2,8,12,138,2,239,3,13,249,5,4,0,2,0,0,7,0,0,6,0,1,0,0,7,2,3,0,0,9,2,3,0,0,8,2,3,0,0,3,4,5,0,0,4,6,0,0,0,5,4,0,0,1,3,1,8,0,2,7,8,0,3,0,2,6,8,0,3,1,1,1,6,8,0,2,10,1,3,1,7,1,5,3,7,1,3,3,3,9,66,105,116,86,101,99,116,111,114,9,98,105,116,95,102,105,101,108,100,10,98,105,116,95,118,101,99,116,111,114,12,105,115,95,105,110,100,101,120,95,115,101,116,6,108,101,110,103,116,104,32,108,111,110,103,101,115,116,95,115,101,116,95,115,101,113,117,101,110,99,101,95,115,116,97,114,116,105,110,103,95,97,116,3,110,101,119,3,115,101,116,10,115,104,105,102,116,95,108,101,102,116,5,117,110,115,101,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,3,8,1,0,2,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,4,0,0,0,0,0,0,0,2,2,4,3,1,10,1,0,1,0,0,7,37,10,0,6,0,0,0,0,0,0,0,0,36,4,5,5,7,7,1,39,10,0,7,3,35,4,12,5,14,7,1,39,6,0,0,0,0,0,0,0,0,12,2,64,5,0,0,0,0,0,0,0,0,12,1,40,10,2,10,0,35,4,32,5,24,13,1,9,68,5,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,18,40,11,0,11,1,18,0,2,1,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,8,11,2,21,2,2,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,9,11,2,21,2,3,1,0,0,9,89,10,1,10,0,16,1,20,38,4,33,10,0,16,0,65,5,12,6,6,0,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,30,5,17,10,0,15,0,10,4,67,5,12,3,9,11,3,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,12,11,0,1,5,88,10,1,12,5,10,5,10,0,16,1,20,35,4,65,5,42,10,0,10,5,12,2,46,11,2,17,4,4,55,10,0,10,5,10,1,23,17,1,5,60,10,0,10,5,10,1,23,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,35,10,0,16,1,20,11,1,23,12,5,10,5,10,0,16,1,20,35,4,86,5,78,10,0,10,5,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,71,11,0,1,2,4,1,0,0,3,17,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,16,0,11,1,66,5,20,2,5,1,0,0,3,4,11,0,16,0,65,5,2,6,1,0,0,0,37,10,1,10,0,16,1,20,35,4,7,5,11,11,0,1,7,0,39,10,1,12,2,10,2,10,0,16,1,20,35,4,33,5,20,10,0,10,2,17,4,32,4,28,11,0,1,5,33,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,13,11,2,11,1,23,2,0,1,0,0,0],"debug":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,11,5,13,5,7,18,30,8,48,32,12,80,8,0,0,0,1,0,1,1,0,0,2,1,1,0,1,6,9,0,0,5,100,101,98,117,103,5,112,114,105,110,116,17,112,114,105,110,116,95,115,116,97,99,107,95,116,114,97,99,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"fixed_point32":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,30,5,36,22,7,58,122,8,180,1,32,6,212,1,68,10,152,2,5,12,157,2,137,2,13,166,4,2,0,4,0,0,7,0,0,7,0,1,0,0,3,0,1,0,0,1,2,3,0,0,2,1,3,0,0,5,3,1,0,0,6,3,4,0,2,3,8,0,1,3,2,3,3,1,8,0,1,1,1,4,4,1,4,4,4,0,12,70,105,120,101,100,80,111,105,110,116,51,50,20,99,114,101,97,116,101,95,102,114,111,109,95,114,97,116,105,111,110,97,108,21,99,114,101,97,116,101,95,102,114,111,109,95,114,97,119,95,118,97,108,117,101,10,100,105,118,105,100,101,95,117,54,52,13,102,105,120,101,100,95,112,111,105,110,116,51,50,13,103,101,116,95,114,97,119,95,118,97,108,117,101,7,105,115,95,122,101,114,111,12,109,117,108,116,105,112,108,121,95,117,54,52,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,16,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,3,8,1,0,1,0,0,0,0,0,3,8,2,0,2,0,0,0,0,0,3,8,3,0,2,0,0,0,0,0,3,8,4,0,1,0,0,0,0,0,3,8,5,0,2,0,0,0,0,0,0,2,1,8,3,0,1,0,0,5,20,11,0,53,14,1,16,0,20,53,24,49,32,48,12,2,10,2,7,0,37,4,15,5,17,7,3,39,11,2,52,2,1,1,0,0,5,29,14,1,16,0,20,6,0,0,0,0,0,0,0,0,34,4,7,5,9,7,4,39,11,0,53,49,32,47,14,1,16,0,20,53,26,12,2,10,2,7,0,37,4,24,5,26,7,2,39,11,2,52,2,2,1,0,0,6,48,10,0,53,49,64,47,12,5,11,1,53,49,32,47,12,4,10,4,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,15,5,17,7,1,39,11,5,11,4,26,12,3,10,3,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,8,12,2,5,32,11,0,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,35,5,37,7,5,39,10,3,7,0,37,4,42,5,44,7,5,39,11,3,52,18,0,2,3,1,0,0,7,3,11,0,18,0,2,4,1,0,0,7,4,14,0,16,0,20,2,5,1,0,0,7,6,14,0,16,0,20,6,0,0,0,0,0,0,0,0,33,2,0,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,3,7,15,23,8,38,32,12,70,8,0,0,0,1,0,0,0,0,2,0,0,0,1,10,2,4,104,97,115,104,8,115,104,97,50,95,50,53,54,8,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"option":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,6,3,10,120,4,130,1,14,5,144,1,135,1,7,151,2,219,1,8,242,3,32,6,146,4,20,10,166,4,7,11,173,4,2,12,175,4,128,4,13,175,8,2,14,177,8,2,0,15,0,22,0,0,7,1,0,0,0,14,0,1,1,0,0,17,2,1,1,0,0,12,3,4,1,0,0,13,3,4,1,0,0,4,5,4,1,0,0,1,3,6,1,0,0,3,5,6,1,0,0,10,7,2,1,3,0,9,8,0,1,0,0,8,9,2,1,0,0,2,9,10,1,0,0,18,8,2,1,0,0,19,8,1,1,0,0,7,11,2,1,2,0,6,1,2,1,0,0,5,1,0,1,0,0,20,1,12,1,0,1,4,14,4,1,0,1,11,13,4,1,0,1,16,2,12,1,0,19,2,18,2,17,2,3,2,0,2,1,2,2,2,0,1,11,0,1,9,0,1,9,0,1,6,11,0,1,9,0,1,1,2,6,11,0,1,9,0,6,9,0,1,6,9,0,2,6,11,0,1,9,0,9,0,2,7,11,0,1,9,0,9,0,1,7,11,0,1,9,0,1,7,9,0,2,11,0,1,9,0,9,0,1,10,9,0,1,6,10,9,0,2,6,10,9,0,6,9,0,2,6,9,0,6,10,9,0,2,9,0,6,10,9,0,1,7,10,9,0,2,9,0,7,10,9,0,3,11,0,1,9,0,11,0,1,9,0,7,10,9,0,2,9,0,10,9,0,6,79,112,116,105,111,110,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,119,105,116,104,95,100,101,102,97,117,108,116,8,99,111,110,116,97,105,110,115,12,100,101,115,116,114,111,121,95,110,111,110,101,12,100,101,115,116,114,111,121,95,115,111,109,101,20,100,101,115,116,114,111,121,95,119,105,116,104,95,100,101,102,97,117,108,116,7,101,120,116,114,97,99,116,4,102,105,108,108,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,4,110,111,110,101,6,111,112,116,105,111,110,9,115,105,110,103,108,101,116,111,110,4,115,111,109,101,4,115,119,97,112,12,115,119,97,112,95,111,114,95,102,105,108,108,6,116,111,95,118,101,99,3,118,101,99,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,4,0,0,0,0,0,3,8,1,0,4,0,0,0,0,0,0,2,1,21,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,0,4,11,0,55,0,56,1,2,3,1,0,0,0,5,11,0,55,0,56,1,32,2,4,1,0,0,0,5,11,0,55,0,11,1,56,2,2,5,1,0,0,0,13,10,0,56,3,4,4,5,8,11,0,1,7,1,39,11,0,55,0,6,0,0,0,0,0,0,0,0,66,2,2,6,1,0,0,15,19,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,17,11,1,1,11,3,6,0,0,0,0,0,0,0,0,66,2,12,2,11,2,2,7,1,0,0,16,18,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,16,11,3,6,0,0,0,0,0,0,0,0,66,2,20,12,2,11,2,2,8,1,0,0,17,16,11,0,54,0,12,2,10,2,46,56,1,4,8,5,12,11,2,1,7,0,39,11,2,11,1,68,2,2,9,1,0,0,0,13,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,69,2,2,10,1,0,0,0,14,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,6,0,0,0,0,0,0,0,0,67,2,2,11,1,0,0,18,20,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,12,3,10,3,69,2,12,2,11,3,11,1,68,2,11,2,2,12,1,0,0,19,21,11,0,54,0,12,4,10,4,46,56,1,4,10,56,4,12,2,5,14,10,4,69,2,56,5,12,2,11,2,12,3,11,4,11,1,68,2,11,3,2,13,1,0,0,20,15,11,0,58,0,12,3,13,3,46,56,1,4,10,11,1,12,2,5,13,13,3,69,2,12,2,11,2,2,14,1,0,0,20,16,14,0,56,3,4,4,5,6,7,1,39,11,0,58,0,12,2,13,2,69,2,12,1,11,2,70,2,0,0,0,0,0,0,0,0,11,1,2,15,1,0,0,0,10,14,0,56,6,4,4,5,6,7,0,39,11,0,58,0,70,2,0,0,0,0,0,0,0,0,2,16,1,0,0,0,3,11,0,58,0,2,0,0,0,2,0],"string":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,14,3,22,114,4,136,1,8,5,144,1,123,7,139,2,248,1,8,131,4,32,6,163,4,20,10,183,4,6,12,189,4,133,3,13,194,7,2,0,19,0,4,0,17,0,24,0,1,7,0,1,1,7,0,2,0,7,1,0,0,0,23,0,1,0,0,6,2,1,0,0,21,1,2,0,0,22,0,3,0,0,5,4,5,0,0,14,4,6,0,0,15,4,7,0,0,2,8,9,0,0,3,10,9,0,0,8,11,9,0,0,20,12,1,0,0,7,13,7,0,0,9,5,6,0,0,11,14,6,0,0,12,15,0,0,0,10,16,7,0,1,13,2,0,0,1,19,0,2,0,2,16,9,18,1,0,2,18,17,18,1,0,3,2,21,9,1,0,3,14,20,6,1,0,19,1,18,1,21,19,20,19,1,10,2,1,8,0,1,8,1,1,11,2,1,8,0,1,6,8,0,1,6,10,2,1,1,1,3,2,7,8,0,8,0,0,2,7,8,0,10,2,3,7,8,0,3,8,0,3,6,8,0,3,3,2,6,8,0,6,8,0,2,6,10,2,3,3,6,10,2,3,3,2,6,10,2,6,10,2,1,9,0,1,11,2,1,9,0,1,2,1,6,10,9,0,2,7,10,9,0,10,9,0,8,1,3,3,3,6,10,2,8,0,8,0,3,5,1,1,1,6,10,2,3,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,97,112,112,101,110,100,11,97,112,112,101,110,100,95,117,116,102,56,5,97,115,99,105,105,5,98,121,116,101,115,10,102,114,111,109,95,97,115,99,105,105,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,19,105,110,116,101,114,110,97,108,95,99,104,101,99,107,95,117,116,102,56,17,105,110,116,101,114,110,97,108,95,105,110,100,101,120,95,111,102,25,105,110,116,101,114,110,97,108,95,105,115,95,99,104,97,114,95,98,111,117,110,100,97,114,121,19,105,110,116,101,114,110,97,108,95,115,117,98,95,115,116,114,105,110,103,10,105,110,116,111,95,98,121,116,101,115,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,4,115,111,109,101,6,115,116,114,105,110,103,10,115,117,98,95,115,116,114,105,110,103,8,116,111,95,97,115,99,105,105,8,116,114,121,95,117,116,102,56,4,117,116,102,56,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,5,10,2,0,1,0,0,9,9,14,0,17,12,4,4,5,6,7,0,39,11,0,18,0,2,1,1,0,0,9,4,11,0,17,16,18,0,2,2,1,0,0,9,4,11,0,19,0,17,17,2,3,1,0,0,3,12,14,0,17,12,4,8,11,0,18,0,56,0,12,1,5,10,56,1,12,1,11,1,2,4,1,0,0,9,3,11,0,16,0,2,5,1,0,0,9,4,11,0,16,0,56,2,2,6,1,0,0,9,4,11,0,16,0,65,19,2,7,1,0,0,9,7,11,0,15,0,14,1,16,0,20,56,3,2,8,1,0,0,9,5,11,0,11,1,17,0,17,7,2,9,1,0,0,22,56,10,0,16,0,12,7,10,1,10,7,65,19,37,4,13,11,7,10,1,17,13,12,3,5,17,11,7,1,9,12,3,11,3,4,20,5,24,11,0,1,7,1,39,10,0,46,17,6,12,10,10,0,10,1,12,4,46,6,0,0,0,0,0,0,0,0,11,4,17,10,12,9,10,0,11,1,11,10,12,6,12,5,46,11,5,11,6,17,10,12,8,13,9,11,2,17,7,13,9,11,8,17,7,11,9,11,0,21,2,10,1,0,0,23,48,11,0,16,0,12,6,10,6,65,19,12,7,10,2,11,7,37,4,15,10,1,10,2,37,12,3,5,17,9,12,3,11,3,4,24,10,6,10,1,17,13,12,4,5,26,9,12,4,11,4,4,33,10,6,10,2,17,13,12,5,5,35,9,12,5,11,5,4,38,5,42,11,6,1,7,1,39,11,6,11,1,11,2,17,14,18,0,2,11,1,0,0,9,6,11,0,16,0,11,1,16,0,17,15,2,12,0,2,0,13,0,2,0,14,0,2,0,15,0,2,0,0,0,0],"type_name":[161,28,235,11,6,0,0,0,10,1,0,6,2,6,8,3,14,47,5,61,44,7,105,143,1,8,248,1,32,6,152,2,7,10,159,2,6,12,165,2,215,1,13,252,3,2,0,14,0,2,0,4,0,1,7,0,2,0,7,0,0,6,0,1,1,0,0,9,0,1,1,0,0,5,2,3,0,0,7,2,4,0,0,8,2,4,0,0,10,1,4,0,1,11,0,6,0,2,3,3,7,0,2,13,9,4,0,0,1,8,0,1,6,8,0,1,6,8,1,1,8,1,4,10,2,3,3,6,10,2,1,3,1,6,10,2,1,2,1,10,2,5,2,6,2,3,10,2,6,10,2,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,13,98,111,114,114,111,119,95,115,116,114,105,110,103,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,11,105,110,116,111,95,115,116,114,105,110,103,6,108,101,110,103,116,104,4,110,97,109,101,6,115,116,114,105,110,103,9,116,121,112,101,95,110,97,109,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,58,10,2,1,0,0,2,1,12,8,1,0,1,2,0,1,1,2,0,2,1,0,0,0,3,11,0,16,0,2,3,1,0,0,5,33,17,6,6,2,0,0,0,0,0,0,0,24,12,3,11,0,16,0,17,7,12,4,7,1,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,28,5,17,13,1,10,4,10,2,66,8,20,68,8,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,4,1,11,1,17,8,2,4,1,0,0,10,39,17,6,6,2,0,0,0,0,0,0,0,24,6,2,0,0,0,0,0,0,0,22,12,3,11,0,16,0,17,7,12,5,7,1,12,4,10,5,10,3,66,8,12,2,7,0,12,1,10,2,14,1,34,4,32,5,23,13,4,11,2,20,68,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,12,11,5,1,11,2,1,11,4,17,8,2,5,1,0,0,0,4,14,0,16,0,20,2,0,0,0],"vector":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,102,4,104,4,5,108,97,7,205,1,154,1,8,231,2,32,6,135,3,10,12,145,3,216,4,0,17,0,5,0,1,1,0,0,9,2,3,1,0,0,1,4,5,1,0,0,11,6,0,1,0,0,2,7,8,1,0,0,10,9,10,1,0,0,4,1,0,1,0,0,15,11,0,1,0,0,14,10,1,1,0,0,13,9,0,1,0,0,0,12,0,1,0,0,8,2,13,1,0,0,3,14,13,1,0,0,6,14,15,1,0,0,12,7,10,1,0,0,7,16,0,1,0,0,16,7,10,1,0,9,10,11,10,0,1,10,9,0,1,6,10,9,0,1,3,2,6,10,9,0,3,1,6,9,0,2,7,10,9,0,9,0,2,7,10,9,0,3,1,7,9,0,1,7,10,9,0,1,9,0,3,7,10,9,0,3,3,2,7,10,9,0,10,9,0,1,1,2,6,10,9,0,6,9,0,2,1,3,3,7,10,9,0,9,0,3,3,3,3,3,2,3,3,3,3,7,10,9,0,3,6,97,112,112,101,110,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,5,101,109,112,116,121,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,7,114,101,118,101,114,115,101,9,115,105,110,103,108,101,116,111,110,4,115,119,97,112,11,115,119,97,112,95,114,101,109,111,118,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,2,0,4,1,2,0,5,1,2,0,6,1,2,0,7,1,2,0,8,1,0,0,1,7,64,10,0,0,0,0,0,0,0,0,12,1,13,1,11,0,68,10,11,1,2,9,1,0,0,17,38,10,0,46,65,10,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,2,6,0,0,0,0,0,0,0,0,12,2,11,3,6,1,0,0,0,0,0,0,0,23,12,1,10,2,10,1,35,4,35,5,22,10,0,10,2,10,1,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,1,6,1,0,0,0,0,0,0,0,23,12,1,5,17,11,0,1,2,10,1,0,0,0,17,13,1,56,0,14,1,56,1,32,4,12,5,7,10,0,13,1,69,10,68,10,5,2,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,11,1,0,0,0,5,11,0,65,10,6,0,0,0,0,0,0,0,0,33,2,12,1,0,0,18,33,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,27,5,10,10,0,10,2,66,10,10,1,33,4,22,11,0,1,11,1,1,8,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,2,13,1,0,0,18,35,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,28,5,10,10,0,10,2,66,10,10,1,33,4,23,11,0,1,11,1,1,8,11,2,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,6,0,0,0,0,0,0,0,0,2,14,1,0,0,19,37,10,0,46,65,10,12,4,10,1,10,4,38,4,12,11,0,1,7,0,39,11,4,6,1,0,0,0,0,0,0,0,23,12,4,10,1,10,4,35,4,34,5,21,10,0,12,3,10,1,12,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,11,3,11,2,10,1,71,10,5,16,11,0,69,10,2,15,1,0,0,3,32,10,0,46,65,10,12,3,10,2,10,3,36,4,12,11,0,1,7,0,39,10,0,11,1,68,10,10,2,10,3,35,4,29,5,20,10,0,10,2,10,3,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,2,16,1,0,0,3,23,10,0,46,56,1,32,4,6,5,10,11,0,1,7,0,39,10,0,46,65,10,6,1,0,0,0,0,0,0,0,23,12,2,10,0,11,1,11,2,71,10,11,0,69,10,2,0]},"type_origin_table":[{"module_name":"fixed_point32","struct_name":"FixedPoint32","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"option","struct_name":"Option","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"Char","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"bit_vector","struct_name":"BitVector","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"string","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"type_name","struct_name":"TypeName","package":"0x0000000000000000000000000000000000000000000000000000000000000001"}],"linkage_table":{}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000002","version":6,"module_map":{"address":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,8,3,18,61,4,79,2,5,81,20,7,101,129,1,8,230,1,64,6,166,2,54,12,220,2,69,0,1,1,2,1,3,1,11,0,8,1,0,7,0,3,0,7,0,0,15,0,1,0,0,7,1,0,0,0,6,2,0,0,0,13,0,2,0,0,12,0,3,0,0,14,0,4,0,0,9,5,6,0,0,10,5,1,0,1,11,2,3,0,2,13,7,2,1,0,3,5,3,4,0,4,4,2,2,0,9,0,1,5,1,15,1,10,2,1,8,0,1,8,1,0,1,3,1,6,9,0,6,83,116,114,105,110,103,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,6,101,110,99,111,100,101,10,102,114,111,109,95,97,115,99,105,105,10,102,114,111,109,95,98,121,116,101,115,9,102,114,111,109,95,117,50,53,54,3,104,101,120,6,108,101,110,103,116,104,3,109,97,120,6,115,116,114,105,110,103,15,116,111,95,97,115,99,105,105,95,115,116,114,105,110,103,8,116,111,95,98,121,116,101,115,9,116,111,95,115,116,114,105,110,103,7,116,111,95,117,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,32,0,0,0,0,0,0,0,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,3,8,0,0,0,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,0,0,5,3,14,0,56,0,2,4,1,0,0,5,5,11,0,17,3,17,11,17,8,2,5,1,0,0,5,4,11,0,17,4,17,10,2,6,1,0,0,5,2,7,0,2,7,1,0,0,5,2,7,1,2,0],"bag":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,112,4,132,1,12,5,144,1,82,7,226,1,185,1,8,155,3,32,6,187,3,10,10,197,3,8,12,205,3,230,1,13,179,5,4,0,4,0,11,0,18,0,21,0,0,12,0,2,2,4,0,3,1,2,0,0,17,0,1,0,0,3,2,3,2,7,4,0,5,4,5,2,7,4,0,6,6,7,2,7,4,0,19,6,8,2,7,4,0,7,4,9,1,7,0,8,4,9,2,7,4,0,16,10,11,0,0,15,10,9,0,0,10,1,3,0,1,3,14,3,2,7,4,1,5,15,5,2,7,4,1,6,16,7,2,7,4,1,12,15,9,1,7,1,13,15,9,2,7,4,1,19,16,8,2,7,4,2,9,12,3,0,2,17,0,12,0,10,13,11,13,12,13,15,13,13,17,14,13,1,7,8,2,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,1,9,0,2,8,1,3,3,66,97,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,3,98,97,103,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,14,8,1,20,3,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,18,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,0,0,0,1,0],"balance":[161,28,235,11,6,0,0,0,14,1,0,4,2,4,16,3,20,83,4,103,2,5,105,99,7,204,1,224,1,8,172,3,32,6,204,3,74,10,150,4,10,11,160,4,4,12,164,4,219,2,13,255,6,4,14,131,7,4,15,135,7,2,0,3,0,16,0,1,4,1,0,1,0,0,4,1,0,1,1,2,2,0,0,17,0,1,1,0,0,15,2,1,1,0,0,5,3,4,1,2,0,10,5,6,1,0,0,6,7,1,1,0,0,19,8,6,1,0,0,11,9,1,1,0,0,13,10,6,1,0,0,18,11,6,1,0,0,9,6,8,1,0,0,4,12,6,1,0,0,7,13,8,1,0,0,8,4,1,1,0,1,12,14,15,0,7,3,1,6,11,1,1,9,0,1,3,1,6,11,0,1,9,0,1,9,0,1,11,0,1,9,0,2,7,11,0,1,9,0,3,1,11,1,1,9,0,2,7,11,0,1,9,0,11,1,1,9,0,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,7,11,1,1,9,0,2,3,6,8,2,2,11,1,1,9,0,6,8,2,1,6,8,2,1,5,7,66,97,108,97,110,99,101,6,83,117,112,112,108,121,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,22,99,114,101,97,116,101,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,115,13,99,114,101,97,116,101,95,115,117,112,112,108,121,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,23,100,101,115,116,114,111,121,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,12,100,101,115,116,114,111,121,95,122,101,114,111,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,4,106,111,105,110,6,115,101,110,100,101,114,5,115,112,108,105,116,3,115,117,105,12,115,117,112,112,108,121,95,118,97,108,117,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,17,3,1,2,1,17,3,0,3,1,3,0,1,0,0,8,4,11,0,55,0,20,2,1,1,0,0,8,4,11,0,55,1,20,2,2,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,0,2,3,1,0,0,8,24,10,1,6,255,255,255,255,255,255,255,255,10,0,55,1,20,23,35,4,9,5,13,11,0,1,7,1,39,10,0,55,1,20,10,1,22,11,0,54,1,21,11,1,57,1,2,4,1,0,0,1,24,11,1,58,1,12,2,10,0,55,1,20,10,2,38,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,10,2,23,11,0,54,1,21,11,2,2,5,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,1,2,6,1,0,0,1,15,11,1,58,1,12,2,10,0,55,0,20,11,2,22,10,0,54,0,21,11,0,55,0,20,2,7,1,0,0,8,22,10,0,55,0,20,10,1,38,4,7,5,11,11,0,1,7,2,39,10,0,55,0,20,10,1,23,11,0,54,0,21,11,1,57,1,2,8,1,0,0,1,8,10,0,55,0,20,12,1,11,0,11,1,56,0,2,9,1,0,0,8,13,14,0,55,0,20,6,0,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,11,0,58,1,1,2,10,0,0,0,8,11,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,57,1,2,11,0,0,0,8,12,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,58,1,1,2,12,3,0,0,8,3,11,0,58,0,2,1,0,0,0,0,3,1,3,0,14,0],"bcs":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,10,3,20,135,1,4,155,1,24,5,179,1,131,1,7,182,2,222,2,8,148,5,64,6,212,5,55,10,139,6,6,12,145,6,203,8,13,220,14,2,0,3,1,3,1,10,1,31,0,2,0,0,7,0,2,1,7,1,0,0,0,30,0,1,1,0,0,8,1,2,0,0,6,2,1,0,0,11,3,4,0,0,12,3,5,0,0,20,3,6,0,0,19,3,7,0,0,18,3,8,0,0,23,3,7,0,0,21,3,9,0,0,22,3,10,0,0,26,3,1,0,0,27,3,11,0,0,25,3,12,0,0,24,3,13,0,0,13,3,14,0,0,14,3,15,0,0,17,3,16,0,0,16,3,17,0,0,15,3,18,0,1,30,0,1,1,0,2,9,19,33,1,0,2,29,20,33,1,0,3,28,21,19,1,0,4,5,1,4,0,4,7,19,7,0,20,20,23,6,22,4,21,4,22,5,21,5,22,6,21,6,22,7,21,7,22,8,21,8,1,6,9,0,1,10,2,1,8,0,1,7,8,0,1,5,1,1,1,2,1,3,1,4,1,10,5,1,10,1,1,10,10,2,1,10,3,1,10,4,1,11,1,1,5,1,11,1,1,1,1,11,1,1,2,1,11,1,1,3,1,11,1,1,4,0,1,9,0,1,7,10,9,0,2,10,2,3,2,1,2,3,3,2,3,3,4,2,4,4,3,3,2,3,3,3,3,10,5,3,3,3,10,1,3,3,3,10,2,3,3,3,10,10,2,3,3,3,10,3,3,3,3,10,4,1,11,1,1,9,0,3,66,67,83,6,79,112,116,105,111,110,7,97,100,100,114,101,115,115,3,98,99,115,5,98,121,116,101,115,10,102,114,111,109,95,98,121,116,101,115,20,105,110,116,111,95,114,101,109,97,105,110,100,101,114,95,98,121,116,101,115,6,108,101,110,103,116,104,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,12,112,101,101,108,95,97,100,100,114,101,115,115,9,112,101,101,108,95,98,111,111,108,19,112,101,101,108,95,111,112,116,105,111,110,95,97,100,100,114,101,115,115,16,112,101,101,108,95,111,112,116,105,111,110,95,98,111,111,108,16,112,101,101,108,95,111,112,116,105,111,110,95,117,49,50,56,15,112,101,101,108,95,111,112,116,105,111,110,95,117,54,52,14,112,101,101,108,95,111,112,116,105,111,110,95,117,56,9,112,101,101,108,95,117,49,50,56,8,112,101,101,108,95,117,54,52,7,112,101,101,108,95,117,56,16,112,101,101,108,95,118,101,99,95,97,100,100,114,101,115,115,13,112,101,101,108,95,118,101,99,95,98,111,111,108,15,112,101,101,108,95,118,101,99,95,108,101,110,103,116,104,13,112,101,101,108,95,118,101,99,95,117,49,50,56,12,112,101,101,108,95,118,101,99,95,117,54,52,11,112,101,101,108,95,118,101,99,95,117,56,15,112,101,101,108,95,118,101,99,95,118,101,99,95,117,56,7,114,101,118,101,114,115,101,4,115,111,109,101,8,116,111,95,98,121,116,101,115,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,10,5,1,0,10,1,1,0,10,2,1,0,10,10,2,1,0,10,3,1,0,10,4,1,0,0,2,1,4,10,2,0,1,0,0,19,3,11,0,56,0,2,1,1,0,0,19,5,13,0,56,1,11,0,18,0,2,2,1,0,0,1,7,11,0,19,0,12,1,13,1,56,1,11,1,2,3,1,0,0,22,35,10,0,16,0,65,6,17,25,38,4,7,5,11,11,0,1,7,0,39,64,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,12,2,12,1,10,2,17,25,35,4,30,5,20,13,1,10,0,15,0,69,6,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,11,1,17,24,2,4,1,0,0,23,21,11,0,17,5,12,2,10,2,49,0,33,4,10,9,12,1,5,19,11,2,49,1,33,4,15,5,17,7,1,39,8,12,1,11,1,2,5,1,0,0,19,15,10,0,16,0,65,6,6,1,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,11,0,15,0,69,6,2,6,1,0,0,24,40,10,0,16,0,65,6,6,8,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,64,35,4,36,5,20,10,0,15,0,69,6,52,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,7,1,0,0,25,40,10,0,16,0,65,6,6,16,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,128,35,4,36,5,20,10,0,15,0,69,6,53,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,8,1,0,0,26,48,6,0,0,0,0,0,0,0,0,49,0,6,0,0,0,0,0,0,0,0,12,2,12,3,12,4,10,2,6,4,0,0,0,0,0,0,0,37,4,11,5,15,11,0,1,7,2,39,10,0,15,0,69,6,52,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,4,10,1,6,127,0,0,0,0,0,0,0,28,10,3,47,27,12,4,11,1,6,128,0,0,0,0,0,0,0,28,6,0,0,0,0,0,0,0,0,33,4,39,5,44,11,3,49,7,22,12,3,5,6,11,0,1,11,4,2,9,1,0,0,27,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,3,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,3,68,4,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,10,1,0,0,28,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,4,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,4,68,5,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,11,1,0,0,29,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,5,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,5,68,6,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,12,1,0,0,30,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,6,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,11,68,1,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,13,1,0,0,31,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,7,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,6,68,7,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,14,1,0,0,32,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,8,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,7,68,8,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,15,1,0,0,14,14,10,0,17,4,4,8,11,0,17,3,56,2,12,1,5,12,11,0,1,56,3,12,1,11,1,2,16,1,0,0,15,14,10,0,17,4,4,8,11,0,17,4,56,4,12,1,5,12,11,0,1,56,5,12,1,11,1,2,17,1,0,0,16,14,10,0,17,4,4,8,11,0,17,5,56,6,12,1,5,12,11,0,1,56,7,12,1,11,1,2,18,1,0,0,17,14,10,0,17,4,4,8,11,0,17,6,56,8,12,1,5,12,11,0,1,56,9,12,1,11,1,2,19,1,0,0,18,14,10,0,17,4,4,8,11,0,17,7,56,10,12,1,5,12,11,0,1,56,11,12,1,11,1,2,0,0,0],"bls12381":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,12,7,24,56,8,80,32,12,112,8,0,0,0,2,0,1,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,8,98,108,115,49,50,51,56,49,22,98,108,115,49,50,51,56,49,95,109,105,110,95,112,107,95,118,101,114,105,102,121,23,98,108,115,49,50,51,56,49,95,109,105,110,95,115,105,103,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"borrow":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,24,3,32,59,4,91,10,5,101,83,7,184,1,158,1,8,214,2,64,6,150,3,20,10,170,3,19,11,189,3,2,12,191,3,125,13,188,4,4,14,192,4,4,0,5,1,15,0,14,0,19,0,3,4,1,12,0,0,0,0,0,1,2,7,1,0,0,2,1,7,0,3,4,2,0,0,12,0,1,1,12,0,5,2,3,1,12,0,16,4,5,1,12,0,6,1,6,1,12,1,7,9,6,1,0,1,8,11,6,1,0,1,9,15,5,1,0,1,18,6,9,1,0,2,11,12,13,1,8,3,10,7,8,0,7,6,5,6,8,6,6,6,4,6,2,9,0,7,8,4,1,11,0,1,9,0,1,7,11,0,1,9,0,2,9,0,8,1,3,7,11,0,1,9,0,9,0,8,1,0,1,9,0,1,7,8,4,1,5,1,11,2,1,9,0,2,8,3,9,0,1,7,11,2,1,9,0,1,6,9,0,1,8,3,2,8,3,5,2,7,11,2,1,9,0,9,0,6,66,111,114,114,111,119,2,73,68,6,79,112,116,105,111,110,8,82,101,102,101,114,101,110,116,9,84,120,67,111,110,116,101,120,116,6,98,111,114,114,111,119,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,7,101,120,116,114,97,99,116,4,102,105,108,108,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,3,111,98,106,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,117,116,95,98,97,99,107,3,114,101,102,4,115,111,109,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,2,11,5,20,11,2,1,9,0,1,2,2,17,5,13,8,3,0,6,0,1,0,0,5,6,11,1,17,9,11,0,56,0,57,0,2,1,1,0,0,10,14,10,0,54,0,56,1,12,2,14,2,56,2,12,1,11,2,11,0,55,1,20,11,1,18,1,2,2,1,0,0,14,30,11,2,19,1,12,3,12,4,14,1,56,2,11,3,33,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,11,4,33,4,21,5,25,11,0,1,7,0,39,11,0,54,0,11,1,56,3,2,3,1,0,0,9,7,11,0,58,0,12,1,1,11,1,56,4,2,0,1,0,0,0,6,1,6,0],"clock":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,31,4,51,2,5,53,30,7,83,122,8,205,1,32,6,237,1,44,10,153,2,8,12,161,2,79,13,240,2,2,0,3,0,7,0,11,0,12,0,0,8,0,1,2,4,0,3,1,2,0,0,10,0,1,0,0,5,2,3,0,0,4,4,3,0,1,3,3,6,0,2,9,8,3,1,8,3,8,2,5,0,4,7,1,6,8,0,1,3,1,6,8,2,0,3,7,8,0,3,6,8,2,1,5,1,8,1,1,8,0,1,9,0,5,67,108,111,99,107,9,84,120,67,111,110,116,101,120,116,3,85,73,68,5,99,108,111,99,107,25,99,111,110,115,101,110,115,117,115,95,99,111,109,109,105,116,95,112,114,111,108,111,103,117,101,6,99,114,101,97,116,101,2,105,100,6,111,98,106,101,99,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,1,10,3,0,1,0,0,3,4,11,0,16,0,20,2,1,0,0,0,3,13,11,0,17,5,7,1,33,4,6,5,8,7,0,39,17,3,6,0,0,0,0,0,0,0,0,18,0,56,0,2,2,0,0,0,3,15,11,2,17,5,7,1,33,4,6,5,10,11,0,1,7,0,39,11,1,11,0,15,0,21,2,0,1,0],"coin":[161,28,235,11,6,0,0,0,13,1,0,20,2,20,62,3,82,155,2,4,237,2,34,5,143,3,221,2,7,236,5,164,5,8,144,11,64,6,208,11,30,10,238,11,52,11,162,12,6,12,168,12,249,4,13,161,17,14,14,175,17,14,0,15,1,11,1,43,1,48,0,12,0,42,0,56,0,58,0,59,0,64,0,1,12,1,0,1,0,2,12,1,0,1,0,7,12,1,0,1,0,3,3,1,0,1,1,5,7,0,2,4,7,1,0,0,3,5,7,0,4,0,4,1,0,1,4,6,4,1,0,1,5,9,4,0,7,8,2,0,9,10,7,0,0,55,0,1,1,0,0,57,2,3,1,0,0,50,0,4,1,0,0,51,5,6,1,0,0,66,7,1,1,0,0,12,7,8,1,0,0,13,9,10,1,0,0,24,11,12,1,0,0,33,12,13,1,0,0,54,14,12,1,0,0,45,15,16,1,0,0,35,17,16,1,0,0,47,18,12,1,0,0,23,18,19,1,0,0,67,20,12,1,0,0,22,12,16,1,0,0,16,21,22,1,2,0,36,23,12,1,0,0,38,24,13,1,0,0,14,25,1,1,0,0,37,26,16,1,0,0,62,27,16,1,0,0,63,28,16,1,0,0,60,27,16,1,0,0,61,28,16,1,0,0,25,29,30,1,0,0,28,29,31,1,0,0,29,29,32,1,0,0,26,29,31,1,0,0,27,29,33,1,0,0,49,5,4,1,0,1,48,41,32,0,2,46,34,46,1,0,3,65,41,31,0,4,17,34,3,1,2,4,19,43,1,1,0,4,22,13,16,1,0,4,32,42,13,1,0,4,35,37,1,1,0,4,47,36,13,1,0,4,52,4,1,1,0,4,66,8,1,1,0,4,67,16,13,1,0,5,20,35,16,0,5,40,20,35,0,6,44,44,16,1,12,8,34,39,40,1,2,9,41,32,45,0,40,34,41,34,39,34,8,34,38,34,9,34,4,34,12,34,42,34,36,34,46,34,34,34,37,34,35,34,17,34,45,12,32,45,1,6,11,2,1,9,0,1,3,1,11,2,1,9,0,1,11,8,1,9,0,1,6,11,8,1,9,0,1,7,11,2,1,9,0,1,7,11,8,1,9,0,1,6,11,0,1,9,0,1,6,11,7,1,9,0,1,7,11,0,1,9,0,1,7,11,7,1,9,0,2,11,7,1,9,0,7,8,10,1,11,0,1,9,0,1,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,10,2,7,11,7,1,9,0,11,0,1,9,0,0,2,7,11,0,1,9,0,11,0,1,9,0,3,7,11,0,1,9,0,3,7,8,10,1,10,11,0,1,9,0,1,7,8,10,7,9,0,2,10,2,10,2,10,2,11,5,1,8,11,7,8,10,2,11,2,1,9,0,11,1,1,9,0,3,7,11,2,1,9,0,3,7,8,10,2,7,11,2,1,9,0,3,2,7,11,2,1,9,0,11,0,1,9,0,4,7,11,2,1,9,0,3,5,7,8,10,3,6,11,2,1,9,0,7,11,1,1,9,0,8,6,3,6,11,2,1,9,0,7,11,1,1,9,0,8,4,1,6,11,1,1,9,0,1,2,1,8,6,1,8,4,1,11,5,1,8,11,1,9,0,1,8,9,2,7,11,7,1,9,0,3,2,7,11,7,1,9,0,11,7,1,9,0,3,3,3,10,11,0,1,9,0,1,6,9,0,1,1,1,10,2,2,7,11,8,1,9,0,3,2,7,11,8,1,9,0,11,7,1,9,0,2,9,0,5,1,8,11,1,11,5,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,15,67,117,114,114,101,110,99,121,67,114,101,97,116,101,100,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,85,114,108,5,97,115,99,105,105,7,98,97,108,97,110,99,101,11,98,97,108,97,110,99,101,95,109,117,116,4,98,117,114,110,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,13,99,114,101,97,116,101,95,115,117,112,112,108,121,8,100,101,99,105,109,97,108,115,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,6,100,101,108,101,116,101,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,122,101,114,111,13,100,105,118,105,100,101,95,105,110,116,111,95,110,12,102,114,111,109,95,98,97,108,97,110,99,101,12,103,101,116,95,100,101,99,105,109,97,108,115,15,103,101,116,95,100,101,115,99,114,105,112,116,105,111,110,12,103,101,116,95,105,99,111,110,95,117,114,108,8,103,101,116,95,110,97,109,101,10,103,101,116,95,115,121,109,98,111,108,8,105,99,111,110,95,117,114,108,2,105,100,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,12,105,110,116,111,95,98,97,108,97,110,99,101,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,4,106,111,105,110,4,109,105,110,116,17,109,105,110,116,95,97,110,100,95,116,114,97,110,115,102,101,114,12,109,105,110,116,95,98,97,108,97,110,99,101,4,110,97,109,101,3,110,101,119,10,110,101,119,95,117,110,115,97,102,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,3,112,117,116,4,115,111,109,101,5,115,112,108,105,116,6,115,116,114,105,110,103,6,115,117,112,112,108,121,12,115,117,112,112,108,121,95,105,109,109,117,116,10,115,117,112,112,108,121,95,109,117,116,12,115,117,112,112,108,121,95,118,97,108,117,101,6,115,121,109,98,111,108,4,116,97,107,101,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,5,116,121,112,101,115,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,15,117,112,100,97,116,101,95,105,99,111,110,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,13,117,112,100,97,116,101,95,115,121,109,98,111,108,3,117,114,108,4,117,116,102,56,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,2,31,8,9,12,11,7,1,9,0,1,2,6,31,8,9,18,2,39,8,6,53,8,4,21,8,6,30,11,5,1,8,11,2,2,2,31,8,9,55,11,8,1,9,0,3,2,1,18,2,2,34,0,34,1,34,0,1,0,0,16,4,11,0,55,0,56,0,2,1,1,0,0,3,6,11,0,58,0,12,1,17,43,11,1,2,2,1,0,0,16,3,11,0,55,0,2,3,1,0,0,16,3,11,0,54,0,2,4,1,0,0,16,4,11,0,55,1,56,1,2,5,1,0,0,16,3,11,0,55,1,2,6,1,0,0,16,3,11,0,54,1,2,7,1,0,0,16,5,11,1,17,44,11,0,57,1,2,8,1,0,0,13,6,11,0,58,1,12,1,17,43,11,1,2,9,1,0,0,16,7,11,2,17,44,11,0,11,1,56,2,57,1,2,10,1,0,0,16,6,11,0,11,1,56,3,56,4,1,2,11,1,4,0,13,10,11,1,58,1,12,2,17,43,11,0,54,1,11,2,56,4,1,2,12,1,0,0,16,6,11,0,54,1,11,1,11,2,56,5,2,13,1,0,0,38,59,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,11,11,0,1,11,2,1,7,1,39,10,1,10,0,46,56,6,37,4,18,5,24,11,0,1,11,2,1,7,2,39,64,12,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,3,10,0,46,56,6,10,1,26,12,4,40,10,3,10,1,6,1,0,0,0,0,0,0,0,23,35,4,53,5,42,13,5,10,0,10,4,10,2,56,7,68,12,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,34,11,0,1,11,2,1,11,5,2,14,1,0,0,16,5,11,0,17,44,56,8,57,1,2,15,1,0,0,13,7,11,0,58,1,12,1,17,43,11,1,56,9,2,16,1,0,0,16,25,14,0,56,10,4,4,5,8,11,6,1,7,0,39,10,6,17,44,11,0,56,11,57,0,11,6,17,44,11,1,11,3,17,33,11,2,17,31,11,4,17,33,11,5,57,2,2,17,1,0,0,16,8,11,2,17,44,11,0,54,0,11,1,56,12,57,1,2,18,1,0,0,16,5,11,0,54,0,11,1,56,12,2,19,1,4,0,13,9,11,1,58,1,12,2,17,43,11,0,54,0,11,2,56,13,2,20,1,4,0,16,7,11,0,11,1,11,3,56,14,11,2,56,15,2,21,1,4,0,16,5,11,2,11,1,54,2,21,2,22,1,4,0,16,5,11,2,11,1,54,3,21,2,23,1,4,0,16,5,11,2,11,1,54,4,21,2,24,1,4,0,16,7,11,2,17,47,56,16,11,1,54,5,21,2,25,1,0,0,16,4,11,0,55,6,20,2,26,1,0,0,16,4,11,0,55,2,20,2,27,1,0,0,16,4,11,0,55,3,20,2,28,1,0,0,16,4,11,0,55,4,20,2,29,1,0,0,16,4,11,0,55,5,20,2,30,1,0,0,16,3,11,0,55,0,2,2,1,0,1,1,2,1,3,1,4,1,5,1,1,0,34,1,34,2,34,3,34,4,34,5,34,6,34,0],"display":[161,28,235,11,6,0,0,0,13,1,0,16,2,16,46,3,62,132,1,4,194,1,22,5,216,1,196,1,7,156,3,223,2,8,251,5,64,6,187,6,20,10,207,6,38,11,245,6,6,12,251,6,160,3,13,155,10,6,14,161,10,6,0,14,1,31,0,18,0,26,0,27,0,32,0,33,0,36,0,0,12,1,8,1,0,1,3,1,8,1,0,8,3,1,8,1,1,4,7,0,3,2,7,0,3,6,4,0,4,3,12,0,6,5,2,0,7,7,7,2,1,0,0,0,0,24,0,1,1,8,0,25,2,1,1,8,0,12,0,3,1,8,0,35,4,3,1,8,0,9,5,3,1,8,0,11,6,3,1,8,0,15,5,3,1,8,0,29,7,3,1,8,0,23,8,9,1,8,0,37,10,11,1,8,0,19,10,12,1,8,0,13,13,1,1,8,0,10,5,3,1,8,2,16,14,3,1,3,3,24,13,28,0,3,34,21,22,0,4,20,8,9,1,0,5,28,19,3,1,12,6,30,17,18,0,7,17,3,30,2,1,0,7,22,31,3,2,1,0,7,29,26,27,2,1,0,8,14,11,14,0,14,12,14,17,1,13,23,21,25,16,14,13,29,19,25,20,25,2,6,8,6,7,8,7,1,11,0,1,9,0,4,6,8,6,10,8,3,10,8,3,7,8,7,0,1,7,11,0,1,9,0,3,7,11,0,1,9,0,8,3,8,3,3,7,11,0,1,9,0,10,8,3,10,8,3,2,7,11,0,1,9,0,8,3,1,6,8,6,1,1,1,6,11,0,1,9,0,1,13,1,6,11,8,2,8,3,8,3,1,7,8,7,1,9,0,3,11,0,1,9,0,3,3,1,8,3,1,6,8,7,1,5,2,9,0,5,2,13,11,8,2,8,3,8,3,1,6,8,5,1,8,4,1,11,2,1,9,0,2,3,3,2,8,3,8,3,2,7,11,8,2,9,0,9,1,6,9,0,2,9,0,9,1,1,8,5,1,11,1,1,9,0,1,11,8,2,9,0,9,1,3,7,11,8,2,9,0,9,1,9,0,9,1,7,68,105,115,112,108,97,121,14,68,105,115,112,108,97,121,67,114,101,97,116,101,100,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,6,86,101,99,77,97,112,14,86,101,114,115,105,111,110,85,112,100,97,116,101,100,3,97,100,100,12,97,100,100,95,105,110,116,101,114,110,97,108,12,97,100,100,95,109,117,108,116,105,112,108,101,15,99,114,101,97,116,101,95,97,110,100,95,107,101,101,112,15,99,114,101,97,116,101,95,105,110,116,101,114,110,97,108,7,100,105,115,112,108,97,121,4,101,100,105,116,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,6,102,105,101,108,100,115,12,102,114,111,109,95,112,97,99,107,97,103,101,2,105,100,6,105,110,115,101,114,116,13,105,115,95,97,117,116,104,111,114,105,122,101,100,3,110,101,119,15,110,101,119,95,119,105,116,104,95,102,105,101,108,100,115,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,6,115,101,110,100,101,114,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,112,100,97,116,101,95,118,101,114,115,105,111,110,7,118,101,99,95,109,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,3,21,8,5,19,11,8,2,8,3,8,3,37,13,1,2,1,21,8,4,2,2,3,21,8,4,37,13,19,11,8,2,8,3,8,3,2,14,1,14,0,14,0,1,0,0,3,11,11,0,56,0,4,4,5,8,11,1,1,7,0,39,11,1,56,1,2,1,1,0,0,15,43,14,1,65,16,12,6,10,6,14,2,65,16,33,4,9,5,15,11,0,1,11,3,1,7,1,39,6,0,0,0,0,0,0,0,0,12,5,11,0,11,3,56,2,12,4,10,5,10,6,35,4,41,5,26,13,4,14,1,10,5,66,16,20,14,2,10,5,66,16,20,56,3,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,21,11,4,2,2,1,4,0,3,8,11,0,10,1,56,2,11,1,46,17,18,56,4,2,3,1,4,0,20,24,10,0,55,0,20,72,1,0,22,10,0,54,0,21,10,0,55,0,20,12,1,10,0,55,1,20,12,2,11,0,55,2,17,15,11,1,11,2,57,0,56,5,2,4,1,4,0,3,5,11,0,11,1,11,2,56,3,2,5,1,4,0,24,38,14,1,65,16,12,4,10,4,14,2,65,16,33,4,9,5,13,11,0,1,7,1,39,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,35,5,20,10,0,14,1,10,3,66,16,20,14,2,10,3,66,16,20,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,15,11,0,1,2,6,1,4,0,3,11,10,0,54,1,14,1,56,6,1,1,11,0,11,1,11,2,56,3,2,7,1,4,0,3,7,11,0,54,1,14,1,56,6,1,1,2,8,1,0,0,3,3,11,0,56,7,2,9,1,0,0,3,4,11,0,55,0,20,2,10,1,0,0,3,3,11,0,55,1,2,11,0,0,0,28,12,11,0,17,14,12,1,14,1,17,15,57,1,56,8,11,1,56,9,72,0,0,57,2,2,12,0,0,0,3,6,11,0,54,1,11,1,11,2,56,10,2,0,2,0,1,0,0,0,14,1,14,2,14,0],"dynamic_field":[161,28,235,11,6,0,0,0,14,1,0,6,2,6,22,3,28,133,1,4,161,1,24,5,185,1,168,1,7,225,2,129,3,8,226,5,64,6,162,6,40,10,202,6,12,11,214,6,2,12,216,6,235,2,13,195,9,6,14,201,9,8,15,209,9,2,0,11,1,26,0,25,0,0,8,2,7,0,4,0,1,2,7,1,0,0,2,1,7,0,2,3,4,0,0,4,0,1,2,7,4,0,6,2,3,2,7,4,0,9,4,5,2,7,4,0,27,4,6,2,7,4,0,13,2,7,1,7,0,29,4,8,2,7,4,0,14,2,7,2,7,4,0,15,2,9,1,7,0,16,4,10,1,7,0,19,11,12,1,7,0,5,11,1,1,8,0,7,9,13,1,8,0,8,10,14,1,8,0,28,15,16,1,8,0,17,15,7,0,0,18,15,7,1,8,1,24,1,24,1,0,1,30,16,24,1,0,2,10,19,1,0,2,21,28,12,0,2,23,12,19,0,2,31,18,12,0,9,16,10,21,11,21,12,21,13,21,4,16,3,20,17,6,16,6,15,21,11,26,12,26,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,9,1,2,6,8,3,5,2,7,8,3,5,2,5,9,0,1,5,1,6,9,0,1,7,9,0,2,5,5,1,9,0,3,11,0,2,9,0,9,1,5,5,1,6,8,3,1,8,3,2,9,0,9,1,1,11,0,2,9,0,9,1,3,5,5,9,1,2,9,0,11,1,1,9,1,1,11,1,1,9,0,4,6,11,0,2,9,0,8,2,5,6,8,3,6,8,2,1,11,0,2,9,0,8,2,2,9,0,8,2,1,6,8,2,4,7,11,0,2,9,0,8,2,5,7,8,3,7,8,2,5,70,105,101,108,100,2,73,68,6,79,112,116,105,111,110,3,85,73,68,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,6,100,101,108,101,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,16,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,17,104,97,115,104,95,116,121,112,101,95,97,110,100,95,107,101,121,2,105,100,13,105,100,95,116,111,95,97,100,100,114,101,115,115,4,110,97,109,101,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,3,20,8,3,22,9,0,32,9,1,0,20,0,1,0,0,17,26,11,0,46,17,21,12,5,10,5,10,1,56,0,12,4,10,5,10,4,17,14,32,4,14,5,16,7,0,39,11,4,17,20,11,1,11,2,57,0,12,3,11,5,11,3,56,1,2,1,1,0,0,12,10,10,0,17,21,11,1,56,0,12,2,11,0,11,2,56,2,55,0,2,2,1,0,0,12,11,10,0,46,17,21,11,1,56,0,12,2,11,0,11,2,56,3,54,0,2,3,1,0,0,22,17,11,0,46,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,4,58,0,12,4,1,17,18,11,4,2,4,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,17,14,2,5,1,0,0,23,19,10,0,10,1,12,2,46,11,2,56,5,4,13,11,0,11,1,56,6,56,7,12,3,5,17,11,0,1,56,8,12,3,11,3,2,6,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,9,2,7,3,0,0,25,22,10,0,17,21,11,1,56,0,12,3,11,0,11,3,56,10,12,2,10,2,55,1,12,4,10,2,55,2,1,11,2,55,3,12,5,11,4,11,5,17,19,2,8,3,0,0,29,24,10,0,46,17,21,11,1,56,0,12,3,11,0,11,3,56,11,12,2,10,2,54,1,12,4,10,2,54,2,1,11,2,54,3,12,5,11,4,11,5,46,17,19,2,9,3,2,0,10,3,2,0,11,3,2,0,12,3,2,0,13,3,2,0,14,3,2,0,15,3,2,0,0,2,0,0,0,1,0,20,1,27,2,27,0,27,0,12,0],"dynamic_object_field":[161,28,235,11,6,0,0,0,10,1,0,8,2,8,20,3,28,138,1,4,166,1,26,5,192,1,131,1,7,195,2,178,2,8,245,4,64,10,181,5,6,11,187,5,2,12,189,5,233,1,0,11,1,22,0,10,0,21,0,3,7,1,0,0,1,1,7,1,0,0,3,0,7,0,3,2,4,0,0,4,0,1,2,7,12,0,6,2,3,2,7,12,0,9,4,5,2,7,12,0,23,4,6,2,7,12,0,12,2,7,1,7,0,13,2,7,2,7,12,0,17,2,8,1,7,1,20,1,24,1,0,1,25,10,24,1,0,2,4,0,1,2,7,4,2,5,18,1,1,8,2,7,15,11,1,8,2,8,19,20,1,8,2,13,2,7,2,7,4,2,14,2,15,1,7,2,15,4,19,1,7,2,16,22,7,1,8,2,23,4,6,2,7,4,2,24,22,10,1,8,3,17,11,12,1,8,3,18,17,12,0,3,26,16,17,0,19,6,9,13,14,14,10,6,11,6,15,14,12,6,18,6,17,13,13,13,16,6,7,12,8,12,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,8,2,3,11,0,1,9,0,8,2,11,0,1,9,0,1,9,0,1,6,9,0,1,8,2,2,11,0,1,9,0,8,2,1,11,0,1,9,0,2,6,8,3,5,1,6,8,3,1,5,2,5,9,0,2,7,8,3,5,1,7,9,0,4,11,0,1,9,0,11,0,1,9,0,9,1,5,2,5,5,2,11,0,1,9,0,5,1,11,1,1,9,0,2,73,68,6,79,112,116,105,111,110,3,85,73,68,7,87,114,97,112,112,101,114,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,4,110,97,109,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,19,9,0,0,10,0,1,0,0,9,21,11,1,57,0,12,5,14,2,56,0,12,4,10,0,10,5,11,4,56,1,11,0,11,5,12,3,46,11,3,56,2,1,17,21,11,2,56,3,2,1,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,2,56,4,2,2,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,5,56,6,2,3,1,0,0,21,20,11,1,57,0,12,3,10,0,10,3,12,2,46,11,2,56,2,12,5,17,21,11,5,56,7,12,4,11,0,11,3,56,8,1,11,4,2,4,1,0,0,14,7,11,1,57,0,12,2,11,0,11,2,56,9,2,5,1,0,0,23,20,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,9,2,11,0,11,2,56,2,12,3,17,21,11,3,56,10,2,6,1,0,0,23,21,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,56,11,2,11,0,11,2,56,2,12,3,1,11,3,17,20,56,12,2,0],"ecdsa_k1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,15,5,17,28,7,45,64,8,109,32,6,141,1,26,12,167,1,12,0,1,0,2,0,1,0,0,0,2,1,0,0,3,3,4,0,3,6,10,2,6,10,2,2,1,10,2,1,6,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,17,100,101,99,111,109,112,114,101,115,115,95,112,117,98,107,101,121,8,101,99,100,115,97,95,107,49,19,115,101,99,112,50,53,54,107,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,107,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,2,1,2,0,0],"ecdsa_r1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,10,5,12,24,7,36,46,8,82,32,6,114,26,12,140,1,8,0,0,0,1,0,1,0,0,2,2,3,0,3,6,10,2,6,10,2,2,1,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,8,101,99,100,115,97,95,114,49,19,115,101,99,112,50,53,54,114,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,114,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,0],"ecvrf":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,5,5,7,15,7,22,19,8,41,32,6,73,30,12,103,4,0,0,0,1,0,1,0,4,6,10,2,6,10,2,6,10,2,6,10,2,1,1,5,101,99,118,114,102,12,101,99,118,114,102,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,1,2,0,0],"ed25519":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,12,7,19,23,8,42,32,12,74,4,0,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,7,101,100,50,53,53,49,57,14,101,100,50,53,53,49,57,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"event":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,4,7,12,11,8,23,32,12,55,4,0,1,0,0,0,1,1,3,1,9,0,0,4,101,109,105,116,5,101,118,101,110,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"groth16":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,16,3,18,50,5,68,76,7,144,1,237,2,8,253,3,32,6,157,4,30,10,187,4,32,12,219,4,180,1,13,143,6,14,0,10,0,0,7,0,0,1,7,0,0,3,7,0,0,2,7,0,0,5,0,1,0,0,6,0,1,0,0,16,2,3,0,0,17,3,4,0,0,15,5,6,0,0,14,5,7,0,0,12,8,3,0,0,13,9,3,0,0,18,10,11,0,0,19,12,11,0,0,1,8,0,4,10,2,10,2,10,2,10,2,1,8,1,1,10,10,2,1,10,2,1,8,2,1,8,3,2,6,8,0,6,10,2,2,2,6,10,2,4,6,8,0,6,8,1,6,8,2,6,8,3,1,1,7,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,5,67,117,114,118,101,20,80,114,101,112,97,114,101,100,86,101,114,105,102,121,105,110,103,75,101,121,11,80,114,111,111,102,80,111,105,110,116,115,17,80,117,98,108,105,99,80,114,111,111,102,73,110,112,117,116,115,22,97,108,112,104,97,95,103,49,95,98,101,116,97,95,103,50,95,98,121,116,101,115,8,98,108,115,49,50,51,56,49,5,98,110,50,53,52,5,98,121,116,101,115,21,100,101,108,116,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,21,103,97,109,109,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,7,103,114,111,116,104,49,54,2,105,100,21,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,30,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,95,105,110,116,101,114,110,97,108,23,112,114,111,111,102,95,112,111,105,110,116,115,95,102,114,111,109,95,98,121,116,101,115,30,112,117,98,108,105,99,95,112,114,111,111,102,95,105,110,112,117,116,115,95,102,114,111,109,95,98,121,116,101,115,14,112,118,107,95,102,114,111,109,95,98,121,116,101,115,12,112,118,107,95,116,111,95,98,121,116,101,115,20,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,29,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,95,105,110,116,101,114,110,97,108,21,118,107,95,103,97,109,109,97,95,97,98,99,95,103,49,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,11,2,1,2,4,20,10,2,4,10,2,9,10,2,8,10,2,2,2,1,7,10,2,3,2,1,7,10,2,0,1,0,0,0,3,49,0,18,0,2,1,1,0,0,0,3,49,1,18,0,2,2,1,0,0,0,6,11,0,11,1,11,2,11,3,18,1,2,3,1,0,0,4,24,64,5,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,68,5,13,1,14,0,16,1,20,68,5,13,1,14,0,16,2,20,68,5,13,1,14,0,16,3,20,68,5,11,1,2,4,1,0,0,0,3,11,0,18,2,2,5,1,0,0,0,3,11,0,18,3,2,6,1,0,0,0,6,11,0,16,4,20,11,1,17,7,2,7,0,2,0,8,1,0,0,0,17,11,0,16,4,20,10,1,16,0,10,1,16,1,10,1,16,2,11,1,16,3,11,2,16,5,11,3,16,6,17,9,2,9,0,2,0,1,0,1,1,1,2,1,3,0,0,2,0,3,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,7,7,19,26,8,45,32,12,77,8,0,1,0,0,0,1,0,0,2,0,1,0,1,6,10,2,1,10,2,10,98,108,97,107,101,50,98,50,53,54,4,104,97,115,104,9,107,101,99,99,97,107,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"hex":[161,28,235,11,6,0,0,0,8,1,0,4,3,4,21,4,25,2,5,27,37,7,64,44,8,108,64,6,172,1,159,6,12,203,7,194,2,0,4,1,5,0,3,0,0,0,0,1,0,0,0,0,2,1,1,0,1,0,3,4,1,0,3,1,1,10,2,1,2,5,10,10,2,7,10,2,3,3,10,2,2,7,10,9,0,10,9,0,0,4,2,3,3,10,2,5,1,1,1,2,2,6,97,112,112,101,110,100,6,100,101,99,111,100,101,11,100,101,99,111,100,101,95,98,121,116,101,6,101,110,99,111,100,101,3,104,101,120,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,10,10,2,130,6,128,2,2,48,48,2,48,49,2,48,50,2,48,51,2,48,52,2,48,53,2,48,54,2,48,55,2,48,56,2,48,57,2,48,97,2,48,98,2,48,99,2,48,100,2,48,101,2,48,102,2,49,48,2,49,49,2,49,50,2,49,51,2,49,52,2,49,53,2,49,54,2,49,55,2,49,56,2,49,57,2,49,97,2,49,98,2,49,99,2,49,100,2,49,101,2,49,102,2,50,48,2,50,49,2,50,50,2,50,51,2,50,52,2,50,53,2,50,54,2,50,55,2,50,56,2,50,57,2,50,97,2,50,98,2,50,99,2,50,100,2,50,101,2,50,102,2,51,48,2,51,49,2,51,50,2,51,51,2,51,52,2,51,53,2,51,54,2,51,55,2,51,56,2,51,57,2,51,97,2,51,98,2,51,99,2,51,100,2,51,101,2,51,102,2,52,48,2,52,49,2,52,50,2,52,51,2,52,52,2,52,53,2,52,54,2,52,55,2,52,56,2,52,57,2,52,97,2,52,98,2,52,99,2,52,100,2,52,101,2,52,102,2,53,48,2,53,49,2,53,50,2,53,51,2,53,52,2,53,53,2,53,54,2,53,55,2,53,56,2,53,57,2,53,97,2,53,98,2,53,99,2,53,100,2,53,101,2,53,102,2,54,48,2,54,49,2,54,50,2,54,51,2,54,52,2,54,53,2,54,54,2,54,55,2,54,56,2,54,57,2,54,97,2,54,98,2,54,99,2,54,100,2,54,101,2,54,102,2,55,48,2,55,49,2,55,50,2,55,51,2,55,52,2,55,53,2,55,54,2,55,55,2,55,56,2,55,57,2,55,97,2,55,98,2,55,99,2,55,100,2,55,101,2,55,102,2,56,48,2,56,49,2,56,50,2,56,51,2,56,52,2,56,53,2,56,54,2,56,55,2,56,56,2,56,57,2,56,97,2,56,98,2,56,99,2,56,100,2,56,101,2,56,102,2,57,48,2,57,49,2,57,50,2,57,51,2,57,52,2,57,53,2,57,54,2,57,55,2,57,56,2,57,57,2,57,97,2,57,98,2,57,99,2,57,100,2,57,101,2,57,102,2,97,48,2,97,49,2,97,50,2,97,51,2,97,52,2,97,53,2,97,54,2,97,55,2,97,56,2,97,57,2,97,97,2,97,98,2,97,99,2,97,100,2,97,101,2,97,102,2,98,48,2,98,49,2,98,50,2,98,51,2,98,52,2,98,53,2,98,54,2,98,55,2,98,56,2,98,57,2,98,97,2,98,98,2,98,99,2,98,100,2,98,101,2,98,102,2,99,48,2,99,49,2,99,50,2,99,51,2,99,52,2,99,53,2,99,54,2,99,55,2,99,56,2,99,57,2,99,97,2,99,98,2,99,99,2,99,100,2,99,101,2,99,102,2,100,48,2,100,49,2,100,50,2,100,51,2,100,52,2,100,53,2,100,54,2,100,55,2,100,56,2,100,57,2,100,97,2,100,98,2,100,99,2,100,100,2,100,101,2,100,102,2,101,48,2,101,49,2,101,50,2,101,51,2,101,52,2,101,53,2,101,54,2,101,55,2,101,56,2,101,57,2,101,97,2,101,98,2,101,99,2,101,100,2,101,101,2,101,102,2,102,48,2,102,49,2,102,50,2,102,51,2,102,52,2,102,53,2,102,54,2,102,55,2,102,56,2,102,57,2,102,97,2,102,98,2,102,99,2,102,100,2,102,101,2,102,102,10,2,1,0,0,1,0,0,2,33,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,4,12,5,12,3,10,3,10,4,35,4,31,5,12,13,5,12,2,7,2,12,1,11,2,14,1,14,0,10,3,66,1,20,52,66,0,20,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,5,2,1,1,0,0,5,47,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,3,12,4,12,2,10,3,6,2,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,14,5,16,7,0,39,10,2,10,3,35,4,45,5,21,14,0,10,2,66,1,20,17,2,49,16,24,14,0,10,2,6,1,0,0,0,0,0,0,0,22,66,1,20,17,2,22,12,1,13,4,11,1,68,1,11,2,6,2,0,0,0,0,0,0,0,22,12,2,5,16,11,4,2,2,0,0,0,6,64,49,48,10,0,37,4,9,10,0,49,58,35,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,5,5,62,49,65,10,0,37,4,27,10,0,49,71,35,12,2,5,29,9,12,2,11,2,4,38,49,10,11,0,22,49,65,23,12,4,5,60,49,97,10,0,37,4,47,10,0,49,103,35,12,3,5,49,9,12,3,11,3,4,52,5,54,7,1,39,49,10,11,0,22,49,97,23,12,4,11,4,12,5,11,5,2,0],"hmac":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,10,7,17,19,8,36,32,12,68,4,0,0,0,1,0,1,0,2,6,10,2,6,10,2,1,10,2,4,104,109,97,99,13,104,109,97,99,95,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"kiosk":[161,28,235,11,6,0,0,0,13,1,0,22,2,22,94,3,116,230,2,4,218,3,64,5,154,4,250,3,7,148,8,189,7,8,209,15,64,6,145,16,130,1,10,147,17,101,11,248,17,8,12,128,18,244,13,13,244,31,18,14,134,32,6,0,51,1,60,0,21,0,26,0,30,0,31,0,33,0,59,0,81,0,83,0,84,0,8,12,0,0,9,12,0,0,13,12,1,12,1,0,1,0,0,0,4,7,0,0,10,7,0,0,11,7,0,0,6,3,1,12,1,0,7,3,1,12,1,0,5,3,1,12,1,1,12,7,1,0,0,2,0,4,1,0,1,3,2,12,1,0,1,7,3,7,0,7,18,4,0,8,14,2,0,9,15,12,1,0,1,9,16,0,1,0,1,10,17,2,0,0,57,0,1,0,0,25,2,3,0,0,79,4,5,0,0,80,6,5,0,0,62,7,5,1,12,0,55,8,5,1,12,0,82,9,10,1,12,0,53,11,5,1,12,0,63,12,5,1,12,0,28,9,5,1,12,0,68,13,14,1,12,0,54,15,16,1,12,0,72,17,14,1,12,0,75,18,5,1,12,0,90,19,3,0,0,39,20,21,0,0,40,20,21,1,12,0,46,20,21,0,0,44,20,21,0,0,45,20,21,0,0,38,22,21,0,0,87,22,23,0,0,78,24,5,0,0,85,25,26,0,0,86,27,23,0,0,61,25,28,0,0,48,25,29,0,0,66,25,30,0,0,67,22,31,0,0,22,32,33,1,12,0,23,9,34,1,12,0,24,9,35,1,12,0,76,36,5,1,12,0,70,37,38,1,12,0,69,37,38,1,12,0,71,37,30,1,12,1,29,70,10,1,0,1,47,69,21,1,0,2,50,61,30,1,0,2,89,71,30,1,0,2,91,5,42,1,0,3,37,46,47,1,0,3,42,47,42,1,0,3,82,72,47,1,0,3,89,60,30,1,0,4,19,49,5,2,7,4,4,34,74,21,1,7,4,73,53,55,2,7,4,4,74,53,54,2,7,4,5,19,49,5,2,7,12,5,22,74,77,2,7,12,5,23,53,78,2,7,12,5,34,74,21,1,7,5,35,74,21,2,7,12,5,73,53,55,2,7,12,6,32,10,5,1,3,7,27,40,5,0,7,41,33,38,1,8,7,57,0,40,0,7,88,26,38,0,9,58,63,64,1,0,10,77,43,28,0,40,41,57,44,41,41,57,10,49,48,45,50,4,10,48,52,54,48,16,10,45,52,55,57,7,10,47,52,55,58,44,41,42,41,38,41,48,50,55,62,60,10,10,10,37,30,36,30,39,41,43,41,52,73,53,48,46,75,46,76,50,48,51,48,1,7,8,18,2,8,0,8,1,3,8,0,8,1,7,8,18,1,11,12,1,8,15,3,7,8,0,6,8,1,6,8,18,0,3,7,8,0,6,8,1,5,3,7,8,0,6,8,1,9,0,4,7,8,0,6,8,1,6,11,16,1,9,0,9,0,3,7,8,0,6,8,1,8,13,1,9,0,4,7,8,0,6,8,1,8,13,3,4,7,8,0,6,8,1,9,0,3,3,7,8,0,8,13,11,12,1,8,15,2,9,0,11,17,1,9,0,5,7,8,0,6,8,1,8,13,3,7,8,18,1,11,2,1,9,0,3,7,8,0,11,2,1,9,0,11,12,1,8,15,2,7,8,0,11,2,1,9,0,4,7,8,0,6,8,1,11,10,1,3,7,8,18,2,6,8,0,8,13,1,1,2,7,8,0,6,8,1,1,7,8,14,3,7,8,0,6,8,1,1,1,6,8,0,1,6,8,14,1,7,8,0,1,5,1,14,1,3,1,7,11,11,1,8,15,3,6,8,0,6,8,1,8,13,1,6,9,0,1,7,9,0,2,9,0,8,3,3,7,8,0,9,0,8,3,1,6,11,2,1,9,0,1,8,13,2,8,1,8,0,1,8,14,1,8,15,1,11,11,1,9,0,1,6,8,18,1,8,0,5,8,14,8,13,8,14,14,11,11,1,8,15,2,11,11,1,9,0,7,8,18,1,11,12,1,9,0,2,8,4,9,0,3,7,8,14,9,0,9,1,2,8,6,1,3,8,13,8,13,8,13,2,8,5,3,2,7,8,14,9,0,1,11,10,1,9,1,1,9,1,2,8,13,8,13,1,11,7,1,9,0,1,11,9,1,9,0,2,9,0,3,1,6,11,12,1,9,0,2,7,11,11,1,9,0,11,11,1,9,0,1,11,8,1,9,0,3,8,13,3,8,13,1,11,17,1,9,0,7,8,13,8,13,8,14,8,13,8,13,3,8,14,5,8,14,8,13,8,13,3,3,3,8,14,8,13,8,13,3,3,3,3,1,6,11,10,1,9,0,1,11,10,1,9,0,1,6,11,11,1,9,0,3,7,11,11,1,9,0,3,7,8,18,1,8,4,2,6,8,14,9,0,1,8,6,1,8,5,1,6,9,1,1,7,9,1,7,66,97,108,97,110,99,101,6,66,111,114,114,111,119,4,67,111,105,110,2,73,68,4,73,116,101,109,12,73,116,101,109,68,101,108,105,115,116,101,100,10,73,116,101,109,76,105,115,116,101,100,13,73,116,101,109,80,117,114,99,104,97,115,101,100,5,75,105,111,115,107,13,75,105,111,115,107,79,119,110,101,114,67,97,112,7,76,105,115,116,105,110,103,4,76,111,99,107,6,79,112,116,105,111,110,11,80,117,114,99,104,97,115,101,67,97,112,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,16,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,10,98,111,114,114,111,119,95,118,97,108,18,99,108,111,115,101,95,97,110,100,95,119,105,116,104,100,114,97,119,4,99,111,105,110,6,100,101,108,101,116,101,6,100,101,108,105,115,116,12,100,101,115,116,114,111,121,95,115,111,109,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,4,101,109,105,116,5,101,118,101,110,116,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,3,102,111,114,12,102,114,111,109,95,98,97,108,97,110,99,101,10,104,97,115,95,97,99,99,101,115,115,8,104,97,115,95,105,116,101,109,18,104,97,115,95,105,116,101,109,95,119,105,116,104,95,116,121,112,101,2,105,100,12,105,110,116,111,95,98,97,108,97,110,99,101,12,105,115,95,101,120,99,108,117,115,105,118,101,9,105,115,95,108,105,115,116,101,100,21,105,115,95,108,105,115,116,101,100,95,101,120,99,108,117,115,105,118,101,108,121,9,105,115,95,108,111,99,107,101,100,7,105,115,95,115,111,109,101,10,105,116,101,109,95,99,111,117,110,116,7,105,116,101,109,95,105,100,4,106,111,105,110,5,107,105,111,115,107,8,107,105,111,115,107,95,105,100,4,108,105,115,116,22,108,105,115,116,95,119,105,116,104,95,112,117,114,99,104,97,115,101,95,99,97,112,4,108,111,99,107,9,109,105,110,95,112,114,105,99,101,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,5,111,119,110,101,114,5,112,108,97,99,101,14,112,108,97,99,101,95,97,110,100,95,108,105,115,116,5,112,114,105,99,101,7,112,114,111,102,105,116,115,14,112,114,111,102,105,116,115,95,97,109,111,117,110,116,11,112,114,111,102,105,116,115,95,109,117,116,8,112,117,114,99,104,97,115,101,17,112,117,114,99,104,97,115,101,95,99,97,112,95,105,116,101,109,18,112,117,114,99,104,97,115,101,95,99,97,112,95,107,105,111,115,107,22,112,117,114,99,104,97,115,101,95,99,97,112,95,109,105,110,95,112,114,105,99,101,17,112,117,114,99,104,97,115,101,95,119,105,116,104,95,99,97,112,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,19,114,101,116,117,114,110,95,112,117,114,99,104,97,115,101,95,99,97,112,10,114,101,116,117,114,110,95,118,97,108,6,115,101,110,100,101,114,20,115,101,116,95,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,9,115,101,116,95,111,119,110,101,114,16,115,101,116,95,111,119,110,101,114,95,99,117,115,116,111,109,3,115,117,105,4,116,97,107,101,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,3,117,105,100,7,117,105,100,95,109,117,116,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,0,2,5,41,8,14,65,11,11,1,8,15,61,5,48,14,20,1,1,2,2,41,8,14,36,8,13,2,2,4,41,8,14,52,8,13,49,8,13,56,3,3,2,2,52,8,13,49,8,13,4,2,1,41,8,13,5,2,2,41,8,13,43,1,6,2,1,41,8,13,7,2,3,51,8,13,41,8,13,64,3,8,2,3,51,8,13,41,8,13,64,3,9,2,2,51,8,13,41,8,13,7,10,9,10,8,10,2,10,0,1,0,0,39,19,10,0,17,58,56,0,10,0,46,17,61,73,0,0,0,0,8,18,0,12,2,11,0,17,58,14,2,56,1,18,1,12,1,11,2,11,1,2,1,1,0,0,45,38,11,0,19,0,1,12,6,1,12,7,12,5,11,1,19,1,12,4,12,3,14,5,17,59,11,4,33,4,17,5,21,11,2,1,7,0,39,11,6,73,0,0,0,0,33,4,26,5,30,11,2,1,7,3,39,11,3,17,56,11,5,17,56,11,7,11,2,56,2,2,2,1,0,0,5,21,10,0,46,56,1,11,1,16,0,20,33,4,9,5,15,11,0,1,11,2,1,7,0,39,11,2,17,61,11,0,15,1,21,2,3,1,0,0,5,18,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,2,11,0,15,1,21,2,4,1,0,0,5,29,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,16,2,20,73,1,0,0,0,22,10,0,15,2,21,11,0,15,3,14,2,56,3,18,4,11,2,56,4,2,5,1,0,0,5,12,10,0,15,3,14,3,56,3,18,6,8,56,5,11,0,11,1,11,3,56,6,2,6,1,0,0,51,72,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,17,32,4,22,5,26,11,0,1,7,8,39,10,0,10,2,12,4,46,11,4,17,19,32,4,35,5,39,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,15,4,47,5,51,11,0,1,7,11,39,10,0,16,2,20,73,1,0,0,0,23,10,0,15,2,21,10,0,15,3,10,2,9,18,5,56,7,1,11,0,15,3,11,2,18,4,56,8,2,7,1,0,0,56,53,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,4,46,11,4,56,9,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,5,46,11,5,17,19,32,4,34,5,38,11,0,1,7,4,39,10,0,15,3,10,2,9,18,5,10,3,56,10,11,0,46,56,1,11,2,11,3,57,0,56,11,2,8,1,0,0,38,13,14,2,56,3,12,4,10,0,10,1,11,2,56,6,11,0,11,1,11,4,11,3,56,12,2,9,1,0,0,51,64,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,56,9,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,19,32,4,34,5,38,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,18,4,46,5,50,11,0,1,7,12,39,10,0,15,3,10,2,9,18,5,56,13,1,11,0,46,56,1,11,2,57,1,56,14,2,10,1,0,0,59,58,10,0,15,3,10,1,9,18,5,56,13,12,4,10,0,15,3,10,1,18,4,56,8,12,3,10,0,16,2,20,73,1,0,0,0,23,10,0,15,2,21,10,4,14,2,56,15,33,4,27,5,31,11,0,1,7,1,39,10,0,15,4,11,2,56,16,56,17,1,10,0,15,3,10,1,18,6,56,18,1,10,0,46,56,1,10,1,10,4,57,2,56,19,11,3,11,1,11,4,11,0,46,56,1,56,20,2,11,1,0,0,65,76,10,0,46,56,1,10,1,16,0,20,33,4,9,5,17,11,0,1,11,4,1,11,1,1,7,0,39,10,0,10,2,12,5,46,11,5,56,9,4,25,5,33,11,0,1,11,4,1,11,1,1,7,11,39,10,0,10,2,12,6,46,11,6,17,18,32,4,42,5,50,11,0,1,11,4,1,11,1,1,7,6,39,11,4,17,58,12,11,11,0,15,3,10,2,8,18,5,10,3,56,10,11,11,12,7,11,2,12,8,11,1,16,0,20,12,9,11,3,12,10,11,7,11,9,11,8,11,10,57,3,2,12,1,0,0,66,50,11,1,58,3,12,6,12,4,12,5,12,3,14,2,56,15,12,7,10,7,11,6,38,4,14,5,18,11,0,1,7,1,39,10,0,46,56,1,11,5,33,4,25,5,29,11,0,1,7,5,39,10,0,15,3,10,4,8,18,5,56,13,1,10,0,15,3,10,4,9,18,5,11,7,56,10,11,3,17,56,11,0,11,4,11,2,56,21,2,13,1,0,0,67,27,11,1,58,3,1,12,3,12,4,12,2,10,0,46,56,1,11,4,33,4,13,5,17,11,0,1,7,5,39,11,0,15,3,11,3,8,18,5,56,13,1,11,2,17,56,2,14,1,0,0,68,49,10,0,46,56,1,11,1,16,0,20,33,4,9,5,15,11,0,1,11,3,1,7,0,39,14,2,56,22,4,37,11,2,56,23,12,6,10,6,10,0,16,4,56,24,37,4,28,5,34,11,0,1,11,3,1,7,2,39,11,6,12,4,5,41,10,0,16,4,56,24,12,4,11,4,12,5,11,0,15,4,11,5,11,3,56,25,2,15,1,0,0,5,6,11,0,16,3,11,1,18,4,56,26,2,16,1,0,0,5,6,11,0,16,3,11,1,18,4,56,27,2,17,1,0,0,5,6,11,0,16,3,11,1,18,6,56,28,2,18,1,0,0,21,18,10,0,16,3,10,1,9,18,5,56,29,4,12,11,0,1,8,12,2,5,16,11,0,11,1,17,19,12,2,11,2,2,19,1,0,0,5,7,11,0,16,3,11,1,8,18,5,56,29,2,20,1,0,0,5,8,11,0,46,56,1,11,1,16,0,20,33,2,21,1,0,0,5,16,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,0,15,3,2,22,1,0,0,5,18,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,2,11,0,15,5,21,2,23,1,0,0,5,12,10,0,16,5,20,4,5,5,9,11,0,1,7,7,39,11,0,16,3,2,24,1,0,0,5,12,10,0,16,5,20,4,5,5,9,11,0,1,7,7,39,11,0,15,3,2,25,1,0,0,5,4,11,0,16,1,20,2,26,1,0,0,5,4,11,0,16,2,20,2,27,1,0,0,5,4,11,0,16,4,56,24,2,28,1,0,0,5,16,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,0,15,4,2,29,1,0,0,5,27,10,0,56,1,11,1,16,0,20,33,4,8,5,12,11,0,1,7,0,39,10,0,10,2,17,15,4,17,5,21,11,0,1,7,11,39,11,0,16,3,11,2,18,4,56,30,2,30,1,0,0,56,44,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,15,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,18,32,4,34,5,38,11,0,1,7,9,39,11,0,15,3,11,2,18,4,56,31,2,31,1,0,0,56,49,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,15,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,18,32,4,34,5,38,11,0,1,7,9,39,10,0,15,3,10,2,18,4,56,8,11,0,46,56,1,11,2,18,3,2,32,1,0,0,56,32,11,2,19,3,12,3,12,4,10,0,46,56,1,11,4,33,4,11,5,15,11,0,1,7,5,39,14,1,56,3,10,3,33,4,21,5,25,11,0,1,7,10,39,11,0,15,3,11,3,18,4,11,1,56,4,2,33,1,0,0,5,4,11,0,55,0,20,2,34,1,0,0,5,4,11,0,55,1,20,2,35,1,0,0,5,4,11,0,55,2,20,2,1,1,0,2,0,3,0,0,0,1,0,4,2,1,2,2,2,3,6,10,7,10,8,10,0],"linked_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,30,3,40,212,1,4,252,1,28,5,152,2,188,1,7,212,3,205,2,8,161,6,64,6,225,6,20,10,245,6,38,11,155,7,4,12,159,7,151,5,13,182,12,14,14,196,12,14,0,24,1,29,0,14,0,28,0,40,0,0,12,2,7,0,4,1,0,1,4,2,7,0,4,0,1,2,7,1,0,0,3,4,4,0,4,3,2,0,0,25,0,1,2,7,4,0,17,2,3,2,7,4,0,6,2,3,2,7,4,0,34,4,5,2,7,4,0,33,4,5,2,7,4,0,7,6,7,2,7,4,0,8,8,9,2,7,4,0,32,6,3,2,7,4,0,26,6,3,2,7,4,0,35,8,10,2,7,4,0,31,11,12,2,7,4,0,30,11,12,2,7,4,0,9,6,13,2,7,4,0,23,2,14,2,7,4,0,20,2,13,2,7,4,0,11,1,5,2,7,4,0,13,1,5,2,7,6,1,7,3,25,1,0,1,12,17,16,1,0,1,16,19,5,1,0,1,21,3,13,1,0,1,22,3,13,1,0,1,27,5,17,1,0,1,37,16,17,1,0,1,38,19,17,1,0,2,5,22,5,2,7,4,2,7,23,7,2,7,4,2,8,21,9,2,7,4,2,15,23,13,2,7,4,2,35,21,10,2,7,4,3,10,15,5,0,3,25,0,15,0,22,16,24,16,20,16,19,16,21,16,18,16,23,16,27,20,25,20,26,20,29,20,17,16,9,12,28,20,1,7,8,4,1,11,0,2,9,0,9,1,1,6,11,0,2,9,0,9,1,1,6,11,2,1,9,0,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,7,11,0,2,9,0,9,1,2,9,0,9,1,1,1,1,3,1,8,3,1,9,0,1,11,2,1,9,0,5,11,2,1,9,0,11,2,1,9,0,11,2,1,9,0,9,0,11,2,1,9,0,2,7,11,2,1,9,0,9,0,2,9,0,11,1,2,9,0,9,1,2,7,8,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,3,11,2,1,9,0,11,2,1,9,0,9,1,1,6,9,0,2,8,3,3,11,76,105,110,107,101,100,84,97,98,108,101,4,78,111,100,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,4,98,97,99,107,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,4,102,105,108,108,5,102,114,111,110,116,4,104,101,97,100,2,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,6,108,101,110,103,116,104,12,108,105,110,107,101,100,95,116,97,98,108,101,3,110,101,119,4,110,101,120,116,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,111,112,95,98,97,99,107,9,112,111,112,95,102,114,111,110,116,4,112,114,101,118,9,112,117,115,104,95,98,97,99,107,10,112,117,115,104,95,102,114,111,110,116,6,114,101,109,111,118,101,4,115,105,122,101,4,115,111,109,101,12,115,119,97,112,95,111,114,95,102,105,108,108,4,116,97,105,108,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,19,8,3,36,3,18,11,2,1,9,0,39,11,2,1,9,0,1,2,3,32,11,2,1,9,0,26,11,2,1,9,0,41,9,1,0,12,1,12,0,1,0,0,5,7,11,0,17,31,6,0,0,0,0,0,0,0,0,56,0,56,0,57,0,2,1,1,0,0,5,3,11,0,55,0,2,2,1,0,0,5,3,11,0,55,1,2,3,1,0,0,18,54,10,0,54,0,10,1,56,1,12,5,10,0,55,1,56,2,4,13,10,0,54,1,10,1,56,3,56,0,12,7,14,5,56,4,4,33,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,3,21,11,6,56,6,12,3,5,35,56,0,12,3,11,3,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,4,1,0,0,18,54,10,0,55,0,56,2,4,8,10,0,54,0,10,1,56,3,10,0,54,1,10,1,56,1,12,5,14,5,56,4,4,31,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,5,21,11,6,56,6,12,3,5,33,56,0,12,3,11,3,12,7,56,0,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,5,1,0,0,5,6,11,0,55,2,11,1,56,9,55,6,2,6,1,0,0,5,6,11,0,54,2,11,1,56,7,54,6,2,7,1,0,0,5,6,11,0,55,2,11,1,56,9,55,3,2,8,1,0,0,5,6,11,0,55,2,11,1,56,9,55,5,2,9,1,0,0,24,65,10,0,54,2,10,1,56,10,58,1,12,4,12,2,12,3,10,0,55,4,20,6,1,0,0,0,0,0,0,0,23,10,0,54,4,21,14,3,56,4,4,28,10,2,10,0,54,2,14,3,56,11,20,56,7,54,5,21,14,2,56,4,4,40,10,3,10,0,54,2,14,2,56,11,20,56,7,54,3,21,10,0,55,0,56,11,14,1,33,4,50,11,2,10,0,54,0,21,10,0,55,1,56,11,14,1,33,4,61,11,3,11,0,54,1,21,5,63,11,0,1,11,4,2,10,1,0,0,16,19,10,0,55,0,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,0,56,11,20,12,1,10,1,11,0,11,1,56,12,2,11,1,0,0,16,19,10,0,55,1,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,1,56,11,20,12,1,10,1,11,0,11,1,56,12,2,12,1,0,0,5,5,11,0,55,2,11,1,56,13,2,13,1,0,0,5,4,11,0,55,4,20,2,14,1,0,0,5,6,11,0,55,4,20,6,0,0,0,0,0,0,0,0,33,2,15,1,0,0,26,16,11,0,58,0,1,1,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,11,5,13,7,0,39,11,1,17,30,2,16,1,0,0,5,7,11,0,58,0,1,1,1,17,30,2,0,2,0,3,0,0,1,0,0,1,1,1,1,2,0,12,1,12,2,12,3,12,4,12,5,12,6,12,0],"math":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,35,5,37,18,7,55,57,8,112,32,12,144,1,249,3,0,2,0,3,0,1,0,0,4,0,1,0,0,0,0,1,0,0,5,2,1,0,0,6,1,1,0,0,7,3,3,0,0,1,0,1,0,2,3,3,1,3,2,3,2,1,4,3,4,4,4,3,15,15,15,4,100,105,102,102,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,4,109,97,116,104,3,109,97,120,3,109,105,110,3,112,111,119,4,115,113,114,116,9,115,113,114,116,95,117,49,50,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,1,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,2,1,0,0,1,15,10,0,10,1,36,4,9,11,0,11,1,23,12,2,5,13,11,1,11,0,23,12,2,11,2,2,3,1,0,0,1,33,6,1,0,0,0,0,0,0,0,12,2,10,1,49,1,38,4,31,5,7,10,1,49,2,25,49,0,33,4,22,10,0,11,0,24,12,0,11,1,49,2,26,12,1,5,30,11,2,10,0,24,12,2,11,1,49,1,23,12,1,5,2,11,2,2,4,1,0,0,4,43,50,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,12,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,53,12,3,10,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,52,2,5,1,0,0,5,43,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,77,12,3,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,53,2,6,1,0,0,1,19,10,0,10,1,25,6,0,0,0,0,0,0,0,0,33,4,11,11,0,11,1,26,12,2,5,17,11,0,11,1,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,2,0],"object":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,126,4,146,1,6,5,152,1,35,7,187,1,250,2,8,181,4,64,6,245,4,112,10,229,5,11,12,240,5,130,2,13,242,7,4,15,246,7,8,0,24,1,4,0,3,0,30,0,0,7,0,0,2,4,0,3,1,2,0,0,21,0,1,0,0,20,0,2,0,0,19,1,3,0,0,18,2,3,0,0,27,4,5,0,0,8,6,5,0,0,31,7,0,0,0,34,7,3,0,0,33,7,1,0,0,32,7,2,0,0,22,8,5,0,0,9,5,6,0,0,15,9,3,1,8,0,5,9,0,1,8,0,17,9,1,1,8,0,16,9,2,1,8,0,6,9,7,1,8,0,23,2,5,0,0,10,2,6,0,0,25,2,6,0,1,28,9,1,1,0,2,14,1,2,0,3,13,8,2,0,3,26,4,2,0,20,2,16,10,20,3,1,6,8,0,1,10,2,1,5,1,8,0,1,6,8,2,1,8,1,0,1,6,8,1,1,7,8,2,1,6,9,0,1,9,0,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,100,100,114,101,115,115,3,98,99,115,9,98,111,114,114,111,119,95,105,100,10,98,111,114,114,111,119,95,117,105,100,5,98,121,116,101,115,5,99,108,111,99,107,6,100,101,108,101,116,101,11,100,101,108,101,116,101,95,105,109,112,108,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,2,105,100,10,105,100,95,97,100,100,114,101,115,115,8,105,100,95,98,121,116,101,115,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,102,114,111,109,95,98,121,116,101,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,11,105,100,95,116,111,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,6,111,98,106,101,99,116,14,114,101,99,111,114,100,95,110,101,119,95,117,105,100,6,115,101,110,100,101,114,16,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,12,117,105,100,95,116,111,95,98,121,116,101,115,12,117,105,100,95,116,111,95,105,110,110,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,7,5,1,2,1,15,8,0,0,1,0,0,6,4,11,0,16,0,56,0,2,1,1,0,0,6,4,11,0,16,0,20,2,2,1,0,0,6,4,11,0,17,21,17,3,2,3,1,0,0,6,3,11,0,18,0,2,4,0,0,0,6,12,11,0,17,23,7,3,33,4,6,5,8,7,2,39,7,0,18,0,18,1,2,5,3,0,0,6,4,7,1,18,0,18,1,2,6,1,0,0,6,3,11,0,16,1,2,7,1,0,0,6,4,11,0,16,1,20,2,8,1,0,0,6,5,11,0,16,1,16,0,56,0,2,9,1,0,0,6,5,11,0,16,1,16,0,20,2,10,1,0,0,6,5,11,0,17,22,18,0,18,1,2,11,1,0,0,6,5,11,0,19,1,19,0,17,18,2,12,1,0,0,6,5,11,0,56,1,16,1,20,2,13,1,0,0,6,4,11,0,56,1,16,1,2,14,1,0,0,6,5,11,0,56,1,16,1,56,2,2,15,1,0,0,6,6,11,0,56,1,16,1,16,0,20,2,16,0,2,0,17,3,0,0,6,6,10,0,17,19,11,0,18,0,18,1,2,18,0,2,0,19,0,2,0,0,0,1,0,0,8,0,11,0,12,0,29,0],"object_bag":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,22,3,32,124,4,156,1,14,5,170,1,88,7,130,2,231,1,8,233,3,64,6,169,4,10,10,179,4,8,12,187,4,245,1,13,176,6,4,0,20,1,21,0,12,0,19,0,24,0,1,12,0,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,18,0,1,0,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,22,6,8,2,7,12,0,8,4,9,1,7,0,9,4,9,2,7,12,0,17,10,11,0,0,16,10,9,0,0,11,1,3,0,0,25,4,12,1,7,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,13,16,9,1,7,2,14,16,9,2,7,12,2,15,16,12,1,7,2,22,17,8,2,7,12,3,10,13,3,0,3,18,0,13,0,11,14,12,14,13,14,17,14,14,18,15,14,16,18,1,7,8,4,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,9,79,98,106,101,99,116,66,97,103,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,10,111,98,106,101,99,116,95,98,97,103,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,15,8,3,23,3,0,1,0,0,3,5,11,0,17,19,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,19,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,18,2,10,1,0,0,3,5,11,0,16,0,11,1,56,6,2,0,0,0,1,0],"object_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,26,3,36,120,4,156,1,12,5,168,1,113,7,153,2,199,1,8,224,3,64,6,160,4,10,10,170,4,8,11,178,4,2,12,180,4,230,1,13,154,6,4,14,158,6,4,0,18,1,19,0,11,0,17,0,22,0,1,12,2,7,1,12,1,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,16,0,1,2,7,12,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,20,6,8,2,7,12,0,8,4,9,2,7,12,0,15,10,11,2,7,12,0,14,10,9,2,7,12,0,10,1,3,2,7,12,0,23,4,12,2,7,12,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,12,16,9,1,7,2,13,16,12,1,7,2,20,17,8,2,7,12,3,9,13,3,0,3,16,0,13,0,10,14,11,14,12,14,15,14,13,18,14,18,1,7,8,4,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,13,8,3,21,3,0,14,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,19,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,9,1,0,0,3,5,11,0,55,0,11,1,56,5,2,0,0,0,1,0,14,1,14,0],"package":[161,28,235,11,6,0,0,0,11,1,0,14,2,14,36,3,50,183,1,4,233,1,10,5,243,1,118,7,233,2,144,5,8,249,7,64,6,185,8,93,10,150,9,48,12,198,9,129,4,13,199,13,20,0,36,1,10,1,50,0,33,0,48,0,49,0,51,0,1,12,0,0,6,12,0,0,8,0,0,0,7,0,0,1,2,7,0,2,4,7,0,3,0,7,0,3,5,4,0,5,3,2,0,0,14,0,1,1,2,0,15,0,2,1,2,0,12,1,2,0,0,22,3,4,1,0,0,21,3,4,1,0,0,39,3,5,0,0,40,3,5,0,0,52,6,7,0,0,54,6,8,0,0,53,6,9,0,0,46,10,7,0,0,47,10,9,0,0,41,11,7,0,0,42,11,7,0,0,45,10,12,0,0,17,2,9,0,0,9,2,9,0,0,19,2,9,0,0,34,13,2,0,0,35,13,2,0,0,30,14,2,0,0,11,15,16,0,0,16,17,2,0,0,43,18,2,0,2,23,24,25,0,2,24,24,25,0,2,25,2,19,1,0,3,18,23,2,0,3,26,21,7,1,8,3,27,27,7,0,3,28,31,27,0,3,32,22,23,0,4,38,28,2,1,12,5,44,26,27,0,6,29,21,4,1,2,34,20,26,20,0,20,32,1,28,14,2,9,0,7,8,8,1,8,0,0,1,6,8,0,1,1,1,6,8,4,1,6,8,1,1,8,6,1,3,1,2,1,6,8,2,1,6,8,3,1,6,10,2,1,7,8,1,1,8,1,3,7,8,1,2,10,2,1,8,2,2,7,8,1,8,3,2,7,8,1,2,1,8,5,1,9,0,1,6,9,0,1,7,8,8,1,8,7,1,6,8,5,1,8,4,1,6,8,8,1,5,2,9,0,5,2,1,8,5,2,8,6,8,6,1,6,8,6,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,15,97,100,100,105,116,105,118,101,95,112,111,108,105,99,121,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,14,98,117,114,110,95,112,117,98,108,105,115,104,101,114,3,99,97,112,5,99,108,97,105,109,14,99,108,97,105,109,95,97,110,100,95,107,101,101,112,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,17,99,111,109,112,97,116,105,98,108,101,95,112,111,108,105,99,121,6,100,101,108,101,116,101,15,100,101,112,95,111,110,108,121,95,112,111,108,105,99,121,6,100,105,103,101,115,116,11,102,114,111,109,95,109,111,100,117,108,101,12,102,114,111,109,95,112,97,99,107,97,103,101,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,14,109,97,107,101,95,105,109,109,117,116,97,98,108,101,11,109,111,100,117,108,101,95,110,97,109,101,3,110,101,119,6,111,98,106,101,99,116,22,111,110,108,121,95,97,100,100,105,116,105,118,101,95,117,112,103,114,97,100,101,115,17,111,110,108,121,95,100,101,112,95,117,112,103,114,97,100,101,115,7,112,97,99,107,97,103,101,6,112,111,108,105,99,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,16,112,117,98,108,105,115,104,101,100,95,109,111,100,117,108,101,17,112,117,98,108,105,115,104,101,100,95,112,97,99,107,97,103,101,11,114,101,99,101,105,112,116,95,99,97,112,15,114,101,99,101,105,112,116,95,112,97,99,107,97,103,101,8,114,101,115,116,114,105,99,116,6,115,101,110,100,101,114,13,116,105,99,107,101,116,95,100,105,103,101,115,116,14,116,105,99,107,101,116,95,112,97,99,107,97,103,101,13,116,105,99,107,101,116,95,112,111,108,105,99,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,5,116,121,112,101,115,15,117,112,103,114,97,100,101,95,112,97,99,107,97,103,101,14,117,112,103,114,97,100,101,95,112,111,108,105,99,121,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,2,1,0,2,1,128,2,1,192,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,26,8,7,36,8,4,31,8,4,1,2,4,26,8,7,36,8,6,54,3,37,2,2,2,4,13,8,6,36,8,6,37,2,20,10,2,3,2,2,13,8,6,36,8,6,0,1,0,0,19,18,14,0,56,0,4,4,5,8,11,1,1,7,0,39,56,1,12,2,11,1,17,31,14,2,17,24,14,2,17,25,18,0,2,1,1,0,0,2,8,11,0,10,1,56,2,11,1,46,17,33,56,3,2,2,1,0,0,2,6,11,0,19,0,1,1,17,27,2,3,1,0,0,19,9,56,1,12,1,14,1,17,24,11,0,16,0,20,33,2,4,1,0,0,29,23,56,1,12,2,14,2,17,24,10,0,16,0,20,33,4,17,14,2,17,25,11,0,16,1,20,33,12,1,5,21,11,0,1,9,12,1,11,1,2,5,1,0,0,2,3,11,0,16,1,2,6,1,0,0,2,3,11,0,16,0,2,7,1,0,0,2,4,11,0,16,2,20,2,8,1,0,0,2,4,11,0,16,3,20,2,9,1,0,0,2,4,11,0,16,4,20,2,10,1,0,0,2,4,11,0,16,5,20,2,11,1,0,0,2,4,11,0,16,6,20,2,12,1,0,0,2,4,11,0,16,7,20,2,13,1,0,0,2,4,11,0,16,8,20,2,14,1,0,0,2,3,11,0,16,9,2,15,1,0,0,2,2,7,5,2,16,1,0,0,2,2,7,6,2,17,1,0,0,2,2,7,7,2,18,1,4,0,2,4,11,0,7,6,17,23,2,19,1,4,0,2,4,11,0,7,7,17,23,2,20,1,4,0,2,7,11,0,19,1,1,1,1,17,27,2,21,1,0,0,30,41,7,8,17,29,12,3,10,0,16,2,20,10,3,34,4,10,5,14,11,0,1,7,2,39,10,1,10,0,16,4,20,38,4,21,5,25,11,0,1,7,1,39,10,0,16,2,20,12,4,11,3,10,0,15,2,21,11,0,46,56,4,11,4,11,1,11,2,18,2,2,22,1,0,0,30,39,11,1,19,3,12,3,12,2,10,0,46,56,4,11,2,33,4,11,5,15,11,0,1,7,4,39,10,0,16,2,17,30,7,8,33,4,22,5,26,11,0,1,7,3,39,11,3,10,0,15,2,21,10,0,16,3,20,6,1,0,0,0,0,0,0,0,22,11,0,15,3,21,2,23,0,0,0,2,16,10,0,16,4,20,10,1,37,4,7,5,11,11,0,1,7,1,39,11,1,11,0,15,4,21,2,0,1,0,2,1,1,1,2,1,3,2,1,2,2,3,0,3,1,2,3,0],"pay":[161,28,235,11,6,0,0,0,9,1,0,8,2,8,10,3,18,77,4,95,14,5,109,126,7,235,1,173,1,8,152,3,32,6,184,3,10,12,194,3,214,2,0,9,0,2,0,15,0,16,1,0,12,1,0,1,3,1,2,0,0,8,0,1,1,0,0,12,2,1,1,0,0,14,3,1,1,0,0,13,4,1,1,0,0,3,2,1,1,0,0,5,5,1,1,0,0,6,6,1,1,0,0,7,7,1,1,0,1,4,2,16,1,0,1,5,5,1,1,0,1,12,2,10,1,0,2,10,11,1,1,12,3,11,8,9,0,11,10,10,12,0,12,1,12,8,12,9,12,6,12,2,11,0,1,9,0,6,8,1,0,3,7,11,0,1,9,0,3,7,8,1,3,7,11,0,1,9,0,10,3,7,8,1,4,7,11,0,1,9,0,3,5,7,8,1,2,7,11,0,1,9,0,11,0,1,9,0,2,7,11,0,1,9,0,10,11,0,1,9,0,2,10,11,0,1,9,0,5,1,6,8,1,1,5,1,11,0,1,9,0,2,9,0,5,1,9,0,2,3,3,1,3,3,3,3,10,11,0,1,9,0,1,10,11,0,1,9,0,3,11,0,1,9,0,3,3,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,15,100,105,118,105,100,101,95,97,110,100,95,107,101,101,112,13,100,105,118,105,100,101,95,105,110,116,111,95,110,4,106,111,105,110,8,106,111,105,110,95,118,101,99,21,106,111,105,110,95,118,101,99,95,97,110,100,95,116,114,97,110,115,102,101,114,4,107,101,101,112,3,112,97,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,18,115,112,108,105,116,95,97,110,100,95,116,114,97,110,115,102,101,114,9,115,112,108,105,116,95,118,101,99,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,5,11,0,11,1,17,12,56,0,2,1,1,4,0,1,8,11,0,11,1,10,2,56,1,11,2,46,56,2,2,2,1,4,0,13,27,6,0,0,0,0,0,0,0,0,14,1,65,14,12,4,12,3,10,3,10,4,35,4,22,5,10,10,0,14,1,10,3,66,14,20,10,2,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,2,1,2,3,1,4,0,1,7,11,0,11,1,11,3,56,1,11,2,56,0,2,4,1,4,0,15,31,11,0,11,1,10,2,56,4,12,5,6,0,0,0,0,0,0,0,0,14,5,65,10,12,4,12,3,10,3,10,4,35,4,26,5,15,13,5,69,10,10,2,46,17,12,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,10,11,2,1,11,5,70,10,0,0,0,0,0,0,0,0,2,5,1,4,0,1,4,11,0,11,1,56,5,2,6,1,4,0,17,26,6,0,0,0,0,0,0,0,0,14,1,65,10,12,4,12,3,10,3,10,4,35,4,21,5,10,13,1,69,10,12,2,10,0,11,2,56,5,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,7,1,4,0,10,18,14,0,65,10,6,0,0,0,0,0,0,0,0,36,4,6,5,8,7,0,39,13,0,69,10,12,2,13,2,11,0,56,6,11,2,11,1,56,0,2,0],"priority_queue":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,12,3,16,60,4,76,10,5,86,167,1,7,253,1,184,1,8,181,3,64,6,245,3,14,10,131,4,18,11,149,4,4,12,153,4,243,5,13,140,10,4,14,144,10,4,0,11,1,16,0,1,6,1,2,0,0,0,6,1,2,0,0,6,0,1,1,2,0,8,2,3,1,2,0,4,4,5,1,2,0,7,3,6,1,2,0,2,7,0,1,2,0,13,8,5,1,2,0,5,9,5,1,2,0,9,10,11,1,2,1,12,15,13,1,0,1,14,15,13,1,0,6,13,9,6,5,13,8,16,8,13,1,10,11,1,1,9,0,1,11,0,1,9,0,1,7,11,0,1,9,0,2,3,9,0,3,7,11,0,1,9,0,3,9,0,0,1,11,1,1,9,0,2,10,3,10,9,0,2,7,10,11,1,1,9,0,3,3,7,10,11,1,1,9,0,3,3,1,6,11,0,1,9,0,1,10,3,2,3,3,1,9,0,3,3,3,9,0,2,7,10,9,0,3,1,3,5,3,3,3,10,11,1,1,9,0,9,0,5,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,13,7,10,11,1,1,9,0,1,3,7,10,11,1,1,9,0,3,1,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,3,3,2,3,10,3,5,69,110,116,114,121,13,80,114,105,111,114,105,116,121,81,117,101,117,101,14,99,114,101,97,116,101,95,101,110,116,114,105,101,115,7,101,110,116,114,105,101,115,6,105,110,115,101,114,116,21,109,97,120,95,104,101,97,112,105,102,121,95,114,101,99,117,114,115,105,118,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,7,112,111,112,95,109,97,120,10,112,114,105,111,114,105,116,105,101,115,8,112,114,105,111,114,105,116,121,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,6,114,101,109,111,118,101,22,114,101,115,116,111,114,101,95,104,101,97,112,95,114,101,99,117,114,115,105,118,101,11,115,119,97,112,95,114,101,109,111,118,101,5,118,97,108,117,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,10,3,1,0,0,2,1,3,10,11,1,1,9,0,1,2,2,10,3,15,9,0,0,13,1,13,0,1,0,0,12,24,14,0,65,6,12,2,10,2,6,2,0,0,0,0,0,0,0,26,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,21,5,12,11,1,6,1,0,0,0,0,0,0,0,23,12,1,13,0,10,2,10,1,56,0,5,7,11,0,57,0,2,1,1,0,0,14,30,10,0,55,0,65,6,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,10,0,54,0,6,0,0,0,0,0,0,0,0,56,1,58,1,12,3,12,2,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,6,0,0,0,0,0,0,0,0,56,0,11,2,11,3,2,2,1,0,0,16,17,10,0,54,0,11,1,11,2,57,1,68,6,10,0,55,0,65,6,6,1,0,0,0,0,0,0,0,23,12,3,11,0,54,0,11,3,56,2,2,3,1,0,0,5,4,11,0,11,1,57,1,2,4,1,0,0,17,40,14,0,65,16,12,3,14,1,65,13,10,3,33,4,9,5,11,6,0,0,0,0,0,0,0,0,39,64,6,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,38,5,20,13,0,6,0,0,0,0,0,0,0,0,56,3,12,4,13,1,6,0,0,0,0,0,0,0,0,56,4,12,6,13,5,11,4,11,6,57,1,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,5,2,5,0,0,0,18,46,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,1,6,1,0,0,0,0,0,0,0,23,6,2,0,0,0,0,0,0,0,26,12,6,10,0,10,1,12,3,12,2,10,0,10,6,12,5,12,4,11,2,46,11,3,66,6,55,1,20,11,4,46,11,5,66,6,55,1,20,36,4,43,10,0,11,1,10,6,71,6,11,0,11,6,56,2,5,45,11,0,1,2,6,0,0,0,19,110,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,2,10,1,35,4,12,5,16,11,0,1,6,1,0,0,0,0,0,0,0,39,10,2,6,2,0,0,0,0,0,0,0,24,6,1,0,0,0,0,0,0,0,22,12,13,10,13,6,1,0,0,0,0,0,0,0,22,12,15,10,2,12,14,10,13,10,1,35,4,55,10,0,10,13,12,5,12,3,10,0,10,14,12,7,12,6,11,3,46,11,5,66,6,55,1,20,11,6,46,11,7,66,6,55,1,20,36,12,8,5,57,9,12,8,11,8,4,61,11,13,12,14,10,15,10,1,35,4,88,10,0,10,15,12,10,12,9,10,0,10,14,12,12,12,11,11,9,46,11,10,66,6,55,1,20,11,11,46,11,12,66,6,55,1,20,36,12,4,5,90,9,12,4,11,4,4,94,11,15,12,14,10,14,10,2,34,4,107,10,0,10,14,11,2,71,6,11,0,11,1,11,14,56,0,5,109,11,0,1,2,7,1,0,0,20,28,7,1,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,0,55,0,65,6,35,4,24,5,11,13,2,10,0,55,0,10,1,66,6,55,1,20,68,16,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,4,11,0,1,11,2,2,0,0,1,0,0,13,1,13,0],"prover":[161,28,235,11,6,0,0,0,4,1,0,2,7,2,7,8,9,32,6,41,30,0,0,6,112,114,111,118,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0],"iota":[161,28,235,11,6,0,0,0,10,1,0,14,2,14,48,3,62,62,4,124,14,5,138,1,133,1,7,143,2,129,2,8,144,4,64,6,208,4,102,10,182,5,5,12,187,5,109,0,22,1,18,0,9,0,10,0,23,0,25,0,26,0,4,2,0,1,3,7,1,0,0,2,0,4,1,0,1,2,5,4,1,0,1,3,1,12,1,0,1,3,2,12,1,0,1,3,6,12,1,0,1,5,7,2,0,6,8,7,0,0,16,0,1,0,0,23,2,3,0,1,17,3,9,1,0,2,12,16,7,1,0,2,15,17,18,1,0,3,11,11,12,1,2,3,24,15,16,1,0,4,19,14,3,1,12,4,20,20,3,1,12,5,14,5,7,0,5,21,5,6,0,2,8,5,10,7,13,6,10,4,10,3,10,8,19,1,7,8,7,1,11,2,1,8,0,2,11,4,1,8,0,5,0,4,11,5,1,8,0,11,3,1,8,0,11,2,1,8,0,11,6,1,8,0,1,6,8,7,1,5,1,3,1,8,8,1,11,1,1,9,0,1,8,0,7,9,0,2,10,2,10,2,10,2,11,1,1,8,8,7,8,7,2,11,6,1,9,0,11,5,1,9,0,1,11,5,1,8,0,1,9,0,1,11,6,1,9,0,1,11,3,1,9,0,2,7,11,3,1,9,0,3,1,11,2,1,9,0,1,11,4,1,8,0,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,114,108,7,98,97,108,97,110,99,101,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,11,100,117,109,109,121,95,102,105,101,108,100,5,101,112,111,99,104,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,3,115,117,105,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,228,11,84,2,0,0,0,3,8,0,0,232,137,4,35,199,138,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,2,4,3,83,85,73,10,2,4,3,83,117,105,10,2,1,0,0,2,1,13,1,0,0,0,0,4,47,10,0,46,17,10,7,5,33,4,7,5,11,11,0,1,7,1,39,10,0,46,17,9,6,0,0,0,0,0,0,0,0,33,4,18,5,22,11,0,1,7,0,39,9,18,0,49,9,7,6,7,7,7,8,56,0,11,0,56,1,12,1,12,4,11,1,56,2,11,4,56,3,12,2,13,2,7,4,56,4,12,3,11,2,56,5,1,11,3,2,1,1,4,0,3,4,11,0,11,1,56,6,2,0],"table":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,16,3,24,115,4,139,1,10,5,149,1,104,7,253,1,167,1,8,164,3,32,6,196,3,10,10,206,3,8,11,214,3,2,12,216,3,229,1,13,189,5,4,14,193,5,4,0,19,0,10,0,16,0,20,0,0,12,2,7,1,4,1,2,2,4,0,3,1,2,0,0,15,0,1,2,7,4,0,3,2,3,2,7,4,0,4,4,5,2,7,4,0,5,6,7,2,7,4,0,17,6,8,2,7,4,0,6,4,9,2,7,4,0,14,10,11,2,7,4,0,13,10,9,2,7,4,0,8,1,3,2,7,4,0,9,1,3,2,7,6,1,3,14,3,2,7,4,1,4,15,5,2,7,4,1,5,16,7,2,7,4,1,11,15,9,2,7,4,1,17,16,8,2,7,4,2,7,12,3,0,2,15,0,12,0,10,13,11,13,12,13,14,13,13,13,1,7,8,2,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,2,8,1,3,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,1,18,3,0,13,0,1,0,0,3,5,11,0,17,16,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,17,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,15,2,9,1,0,0,3,5,11,0,58,0,1,17,15,2,0,0,0,1,0,13,1,13,0],"table_vec":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,18,3,24,103,4,127,20,5,147,1,138,1,7,157,2,159,1,8,188,3,32,6,220,3,20,10,240,3,10,11,250,3,2,12,252,3,245,1,13,241,5,2,14,243,5,2,0,17,0,16,0,18,0,1,4,1,4,1,1,0,12,2,7,1,4,1,2,2,2,0,0,8,0,1,1,4,0,15,2,1,1,4,0,10,3,4,1,4,0,9,3,5,1,4,0,4,6,7,1,4,0,13,8,9,1,4,0,5,10,11,1,4,0,12,12,13,1,4,0,7,1,9,1,4,1,3,19,9,2,7,4,1,4,17,18,2,7,4,1,5,20,21,2,7,4,1,7,15,9,2,7,4,1,10,16,4,2,7,4,1,11,0,15,2,7,4,1,14,20,22,2,7,4,14,14,0,13,5,13,13,14,2,13,10,14,9,14,11,14,15,14,12,14,1,7,8,2,1,11,0,1,9,0,2,9,0,7,8,2,1,6,11,0,1,9,0,1,3,1,1,2,6,11,0,1,9,0,3,1,6,9,0,2,7,11,0,1,9,0,9,0,0,2,7,11,0,1,9,0,3,1,7,9,0,1,7,11,0,1,9,0,1,9,0,2,3,9,0,1,11,1,2,9,0,9,1,1,6,11,1,2,9,0,9,1,2,6,11,1,2,9,0,9,1,9,0,1,6,9,1,3,7,11,1,2,9,0,9,1,9,0,9,1,2,7,11,1,2,9,0,9,1,9,0,1,7,9,1,1,9,1,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,5,101,109,112,116,121,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,6,11,1,2,3,9,0,0,13,0,1,0,0,9,4,11,0,56,0,57,0,2,1,1,0,0,1,8,11,1,56,1,12,2,13,2,11,0,56,2,11,2,2,2,1,0,0,9,4,11,0,55,0,56,3,2,3,1,0,0,9,5,11,0,56,4,6,0,0,0,0,0,0,0,0,33,2,4,1,0,0,9,15,10,0,56,4,10,1,36,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,5,2,5,1,0,0,4,10,10,0,46,56,4,12,2,11,0,54,0,11,2,11,1,56,6,2,6,1,0,0,9,16,10,0,46,56,4,10,1,36,4,7,5,11,11,0,1,7,0,39,11,0,54,0,11,1,56,7,2,7,1,0,0,4,20,10,0,46,56,4,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,56,8,2,8,1,0,0,9,12,14,0,56,4,6,0,0,0,0,0,0,0,0,33,4,6,5,8,7,1,39,11,0,58,0,56,9,2,0,0,0,13,0],"transfer":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,54,4,56,6,5,62,8,7,70,144,1,8,214,1,32,6,246,1,10,12,128,2,82,0,7,0,7,0,1,1,8,0,4,0,1,1,12,0,0,2,1,1,8,0,2,2,1,1,12,0,5,2,1,1,8,0,3,2,1,1,12,0,1,2,1,1,8,0,6,2,1,1,8,0,8,0,1,1,8,8,2,6,2,7,2,2,9,0,5,0,1,9,0,13,102,114,101,101,122,101,95,111,98,106,101,99,116,18,102,114,101,101,122,101,95,111,98,106,101,99,116,95,105,109,112,108,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,17,115,104,97,114,101,95,111,98,106,101,99,116,95,105,109,112,108,8,116,114,97,110,115,102,101,114,13,116,114,97,110,115,102,101,114,95,105,109,112,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,56,0,2,1,1,0,0,1,4,11,0,11,1,56,0,2,2,1,0,0,1,3,11,0,56,1,2,3,1,0,0,1,3,11,0,56,1,2,4,1,0,0,1,3,11,0,56,2,2,5,1,0,0,1,3,11,0,56,2,2,6,3,2,0,7,3,2,0,8,3,2,0,0],"transfer_policy":[161,28,235,11,6,0,0,0,13,1,0,24,2,24,78,3,102,255,1,4,229,2,44,5,145,3,176,3,7,193,6,229,4,8,166,11,64,6,230,11,60,10,162,12,55,11,217,12,10,12,227,12,252,4,13,223,17,16,14,239,17,16,0,59,1,47,1,61,0,19,0,21,0,28,0,31,0,46,0,48,0,57,0,60,0,66,0,10,0,1,0,1,0,7,12,1,0,1,0,8,12,1,0,1,0,9,3,1,0,1,0,5,7,1,2,1,1,3,7,1,0,0,2,12,7,0,3,0,4,1,0,1,4,1,12,1,0,1,7,2,7,0,7,13,4,0,8,4,12,0,9,6,2,0,10,11,2,0,11,14,7,1,3,0,0,45,0,1,1,0,0,44,2,3,1,0,0,67,4,5,1,0,0,25,6,5,1,0,0,22,7,0,1,0,0,17,8,9,3,0,2,6,0,37,10,11,3,0,2,6,0,18,12,9,2,0,2,0,16,13,9,2,0,2,0,38,14,15,2,0,2,0,54,16,9,3,0,2,6,0,62,14,17,1,0,0,63,16,18,1,0,0,55,14,19,1,0,0,43,20,21,1,0,0,49,20,22,1,0,0,33,20,21,1,0,1,26,37,25,1,0,1,42,36,15,1,0,2,36,9,23,1,0,3,65,38,22,1,0,3,68,9,32,1,0,4,34,42,40,1,0,4,51,54,9,1,0,4,58,39,40,1,0,5,15,50,9,2,7,4,5,20,52,53,2,7,4,5,32,52,15,1,7,5,53,57,48,2,7,4,6,29,25,9,1,3,7,24,29,9,0,7,39,35,21,1,8,7,44,28,29,0,7,64,17,21,0,8,35,27,15,1,0,11,23,46,15,1,3,11,30,9,24,1,3,11,40,51,9,1,3,11,41,24,44,1,3,11,53,58,9,1,3,11,56,45,22,1,3,36,23,34,25,29,30,21,31,31,34,18,22,17,22,20,31,24,31,22,31,38,23,40,23,35,23,9,47,25,49,19,48,37,23,26,49,23,31,27,55,28,49,39,23,3,8,9,3,8,9,1,11,0,1,9,0,2,6,8,11,7,8,13,2,11,1,1,9,0,11,2,1,9,0,4,7,11,1,1,9,0,6,11,2,1,9,0,11,5,1,3,7,8,13,1,11,8,1,8,12,3,11,1,1,9,0,11,2,1,9,0,7,8,13,2,6,11,1,1,9,0,11,0,1,9,0,4,9,1,7,11,1,1,9,0,6,11,2,1,9,0,9,2,0,2,9,1,6,11,1,1,9,0,1,6,9,2,3,9,1,7,11,1,1,9,0,11,8,1,8,12,2,9,1,7,11,0,1,9,0,1,6,11,1,1,9,0,1,1,2,7,11,1,1,9,0,6,11,2,1,9,0,1,6,8,10,1,7,8,10,1,6,11,14,1,8,6,1,6,11,0,1,9,0,1,8,9,1,3,1,8,6,1,11,14,1,9,0,1,9,0,5,8,10,11,14,1,8,6,11,7,1,8,12,8,10,8,9,1,6,8,11,1,7,8,13,1,8,10,1,11,3,1,9,0,1,8,12,1,11,7,1,9,0,3,3,3,3,1,11,1,1,9,0,1,6,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,1,6,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,13,1,11,8,1,9,0,2,11,7,1,8,12,8,10,2,11,7,1,9,0,7,8,13,7,10,8,6,8,9,8,9,3,11,14,1,8,6,8,6,3,1,10,9,0,1,6,11,14,1,9,0,2,6,11,14,1,9,0,6,9,0,2,9,0,9,1,1,9,1,2,11,4,1,9,1,9,2,3,7,8,10,9,0,9,1,2,7,11,14,1,9,0,9,0,2,6,8,10,9,0,1,6,9,1,2,7,11,7,1,9,0,11,8,1,9,0,1,11,4,1,9,1,2,8,6,7,11,14,1,8,6,2,7,8,10,9,0,2,7,11,14,1,9,0,6,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,9,80,117,98,108,105,115,104,101,114,7,82,117,108,101,75,101,121,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,17,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,97,112,21,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,114,101,97,116,101,100,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,86,101,99,83,101,116,3,97,100,100,11,97,100,100,95,114,101,99,101,105,112,116,8,97,100,100,95,114,117,108,101,14,97,100,100,95,116,111,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,4,99,111,105,110,15,99,111,110,102,105,114,109,95,114,101,113,117,101,115,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,20,100,101,115,116,114,111,121,95,97,110,100,95,119,105,116,104,100,114,97,119,12,100,101,115,116,114,111,121,95,115,111,109,101,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,7,101,120,105,115,116,115,95,4,102,114,111,109,12,102,114,111,109,95,98,97,108,97,110,99,101,12,102,114,111,109,95,112,97,99,107,97,103,101,3,103,101,116,8,103,101,116,95,114,117,108,101,8,104,97,115,95,114,117,108,101,2,105,100,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,7,105,115,95,115,111,109,101,4,105,116,101,109,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,4,112,97,105,100,9,112,111,108,105,99,121,95,105,100,3,112,117,116,8,114,101,99,101,105,112,116,115,6,114,101,109,111,118,101,11,114,101,109,111,118,101,95,114,117,108,101,5,114,117,108,101,115,4,115,105,122,101,3,115,117,105,4,116,97,107,101,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,3,117,105,100,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,7,118,101,99,95,115,101,116,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,4,43,8,9,49,3,33,8,9,52,11,14,1,8,6,1,2,3,39,8,10,19,11,7,1,8,12,55,11,14,1,8,6,2,2,2,39,8,10,50,8,9,3,2,1,39,8,9,4,2,1,27,1,0,25,3,25,1,25,2,25,4,48,0,1,0,0,9,6,11,0,11,1,11,2,56,0,57,0,2,1,1,0,0,26,32,11,0,56,1,4,4,5,8,11,1,1,6,0,0,0,0,0,0,0,0,39,10,1,17,32,12,5,14,5,17,33,12,6,10,6,57,1,56,2,11,5,12,2,56,0,12,3,56,3,12,4,11,2,11,4,11,3,57,2,11,1,17,32,11,6,57,3,2,2,1,0,0,33,49,10,0,46,56,4,11,1,55,0,20,33,4,9,5,15,11,0,1,11,3,1,7,4,39,14,2,56,5,4,37,11,2,56,6,12,6,10,6,10,0,55,1,56,7,37,4,28,5,34,11,0,1,11,3,1,7,5,39,11,6,12,4,5,41,10,0,55,1,56,7,12,4,11,4,12,5,11,0,54,1,11,5,11,3,56,8,2,3,1,0,0,41,27,14,0,56,4,14,1,55,0,20,33,4,8,5,12,11,2,1,7,4,39,11,1,58,3,1,12,4,11,0,58,2,1,12,3,17,30,11,4,17,30,11,3,11,2,56,9,2,4,1,0,0,43,52,11,1,58,0,12,6,12,3,12,5,12,4,11,6,56,10,12,2,14,2,65,23,12,8,10,8,10,0,55,2,56,11,33,4,19,5,23,11,0,1,7,0,39,10,8,6,0,0,0,0,0,0,0,0,36,4,46,5,28,13,2,69,23,12,7,10,0,55,2,14,7,56,12,4,37,5,41,11,0,1,7,1,39,11,8,6,1,0,0,0,0,0,0,0,23,12,8,5,23,11,0,1,11,4,11,5,11,3,2,5,1,0,0,9,34,10,1,46,56,4,11,2,55,0,20,33,4,9,5,13,11,1,1,7,4,39,10,1,46,56,13,32,4,19,5,23,11,1,1,7,3,39,10,1,54,3,9,57,4,11,3,56,14,11,1,54,2,56,15,56,16,2,6,1,0,0,9,6,11,1,55,3,9,57,4,56,17,2,7,1,0,0,9,14,10,1,46,56,13,4,5,5,9,11,1,1,7,2,39,11,1,54,1,11,2,56,18,2,8,1,0,0,9,5,11,1,54,4,56,15,56,16,2,9,1,0,0,9,6,11,0,55,3,9,57,4,56,19,2,10,1,0,0,56,28,10,0,46,56,4,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,10,0,54,3,9,57,4,56,20,1,11,0,54,2,12,3,56,15,12,2,11,3,14,2,56,21,2,11,1,0,0,9,3,11,0,55,3,2,12,1,0,0,9,16,10,0,46,56,4,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,11,0,54,3,2,13,1,0,0,9,3,11,0,55,2,2,14,1,0,0,9,4,11,0,55,5,20,2,15,1,0,0,9,4,11,0,55,6,20,2,16,1,0,0,9,4,11,0,55,7,20,2,2,1,1,1,1,2,1,0,0,3,0,0,0,1,0,2,0,25,1,25,2,25,3,25,4,25,5,25,6,25,7,25,0],"tx_context":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,24,7,65,111,8,176,1,32,6,208,1,20,10,228,1,14,12,242,1,107,13,221,2,10,0,8,0,0,2,0,0,7,0,1,0,0,2,0,2,0,0,3,0,3,0,0,4,0,3,0,0,5,4,1,0,0,6,0,3,0,0,1,5,1,0,1,6,8,0,1,5,1,6,10,2,1,3,1,7,8,0,2,10,2,3,0,2,5,3,9,84,120,67,111,110,116,101,120,116,9,100,101,114,105,118,101,95,105,100,6,100,105,103,101,115,116,5,101,112,111,99,104,18,101,112,111,99,104,95,116,105,109,101,115,116,97,109,112,95,109,115,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,11,105,100,115,95,99,114,101,97,116,101,100,6,115,101,110,100,101,114,10,116,120,95,99,111,110,116,101,120,116,7,116,120,95,104,97,115,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,32,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,5,7,5,9,10,2,3,3,4,3,6,3,0,1,0,0,6,4,11,0,16,0,20,2,1,1,0,0,6,3,11,0,16,1,2,2,1,0,0,6,4,11,0,16,2,20,2,3,1,0,0,6,4,11,0,16,3,20,2,4,1,0,0,7,18,10,0,16,4,20,12,2,10,0,16,1,20,10,2,17,6,12,1,11,2,6,1,0,0,0,0,0,0,0,22,11,0,15,4,21,11,1,2,5,0,0,0,6,4,11,0,16,4,20,2,6,0,2,0,0,0,0,1,0,2,0,3,0,4,0],"types":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,6,7,14,26,8,40,32,12,72,4,0,1,0,0,0,1,1,2,1,6,9,0,1,1,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,5,116,121,112,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"url":[161,28,235,11,6,0,0,0,9,1,0,4,2,4,8,3,12,25,5,37,20,7,57,78,8,135,1,64,10,199,1,6,12,205,1,50,13,255,1,2,0,8,1,2,0,1,7,0,1,0,7,0,0,4,0,1,0,0,5,2,1,0,0,3,3,0,0,0,7,4,5,0,1,6,2,0,0,1,8,1,1,8,0,1,10,2,1,6,8,0,2,7,8,0,8,1,0,6,83,116,114,105,110,103,3,85,114,108,5,97,115,99,105,105,9,105,110,110,101,114,95,117,114,108,10,110,101,119,95,117,110,115,97,102,101,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,6,115,116,114,105,110,103,6,117,112,100,97,116,101,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,8,8,1,0,1,0,0,5,3,11,0,18,0,2,1,1,0,0,5,4,11,0,17,4,18,0,2,2,1,0,0,5,4,11,0,16,0,20,2,3,1,0,0,5,5,11,1,11,0,15,0,21,2,0,0,0],"vec_map":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,22,3,28,168,1,4,196,1,28,5,224,1,254,1,7,222,3,153,2,8,247,5,64,6,183,6,50,10,233,6,21,11,254,6,4,12,130,7,235,5,13,237,12,6,14,243,12,6,0,30,1,21,1,31,0,2,7,2,1,0,0,0,0,0,7,2,1,0,0,0,1,1,7,1,0,0,0,7,0,1,2,1,0,0,14,2,0,2,1,0,0,23,3,4,2,1,0,0,22,5,4,2,1,0,0,13,3,6,2,1,0,0,8,7,8,2,1,0,0,28,7,9,2,1,1,0,3,7,10,2,1,0,0,26,11,12,2,1,0,0,16,11,10,2,1,0,0,5,1,0,2,1,0,0,15,1,13,2,1,0,0,19,11,14,2,1,0,0,12,7,15,2,1,0,0,11,7,12,2,1,0,0,9,16,17,2,1,0,0,10,18,19,2,1,0,0,24,18,4,2,1,0,1,6,27,24,1,0,1,17,28,10,1,0,1,20,0,27,1,0,1,27,24,27,1,0,2,16,25,10,1,0,2,23,23,24,1,0,2,25,31,0,1,0,7,4,14,4,23,20,22,20,5,4,21,26,20,26,13,4,19,12,8,4,24,20,21,12,20,12,18,12,0,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,2,7,11,0,2,9,0,9,1,6,9,0,2,9,0,9,1,1,7,11,0,2,9,0,9,1,1,7,9,1,2,6,11,0,2,9,0,9,1,6,9,0,1,6,9,1,1,11,2,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,2,10,9,0,10,9,1,1,10,9,0,1,11,2,1,3,2,6,11,0,2,9,0,9,1,3,2,6,9,0,6,9,1,2,7,11,0,2,9,0,9,1,3,2,6,9,0,7,9,1,1,11,1,2,9,0,9,1,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,9,0,1,6,10,9,0,1,9,1,1,11,2,1,9,0,1,6,11,2,1,9,0,1,10,11,1,2,9,0,9,1,7,10,11,1,2,9,0,9,1,3,9,0,10,9,0,3,9,1,10,9,1,1,7,10,9,0,4,6,11,1,2,9,0,9,1,3,10,9,0,3,2,3,3,1,6,11,1,2,9,0,9,1,1,7,11,1,2,9,0,9,1,5,69,110,116,114,121,6,79,112,116,105,111,110,6,86,101,99,77,97,112,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,3,103,101,116,16,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,20,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,95,109,117,116,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,7,103,101,116,95,109,117,116,6,105,110,115,101,114,116,16,105,110,116,111,95,107,101,121,115,95,118,97,108,117,101,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,3,107,101,121,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,3,112,111,112,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,101,110,116,114,121,95,98,121,95,105,100,120,7,114,101,118,101,114,115,101,4,115,105,122,101,4,115,111,109,101,7,116,114,121,95,103,101,116,5,118,97,108,117,101,7,118,101,99,95,109,97,112,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,1,4,10,11,1,2,9,0,9,1,1,2,2,18,9,0,29,9,1,0,4,1,4,0,1,0,0,0,3,64,20,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,21,20,10,0,14,1,12,3,46,11,3,56,0,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,11,2,57,1,68,20,2,2,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,56,2,58,1,2,3,1,0,0,0,15,10,0,55,0,56,3,32,4,6,5,10,11,0,1,7,4,39,11,0,54,0,69,20,58,1,2,4,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,67,20,54,1,2,5,1,0,0,12,10,10,0,11,1,56,1,12,2,11,0,55,0,11,2,66,20,55,1,2,6,1,0,0,9,19,10,0,10,1,56,0,4,11,11,0,11,1,56,4,20,56,5,12,2,5,17,11,0,1,11,1,1,56,6,12,2,11,2,2,7,1,0,0,15,7,11,0,11,1,56,7,12,2,14,2,56,8,2,8,1,0,0,0,4,11,0,55,0,65,20,2,9,1,0,0,0,5,11,0,56,9,6,0,0,0,0,0,0,0,0,33,2,10,1,0,0,29,12,11,0,58,0,12,1,14,1,56,3,4,7,5,9,7,2,39,11,1,70,20,0,0,0,0,0,0,0,0,2,11,1,0,0,30,40,11,0,58,0,12,1,13,1,56,10,6,0,0,0,0,0,0,0,0,12,2,14,1,65,20,12,5,64,24,0,0,0,0,0,0,0,0,12,4,64,26,0,0,0,0,0,0,0,0,12,7,10,2,10,5,35,4,35,5,19,13,1,69,20,58,1,12,6,12,3,13,4,11,3,68,24,13,7,11,6,68,26,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,14,11,1,70,20,0,0,0,0,0,0,0,0,11,4,11,7,2,12,1,0,0,32,32,6,0,0,0,0,0,0,0,0,12,2,10,0,55,0,65,20,12,4,64,24,0,0,0,0,0,0,0,0,12,3,10,2,10,4,35,4,28,5,13,10,0,55,0,10,2,66,20,12,1,13,3,11,1,55,2,20,68,24,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,8,11,0,1,11,3,2,13,1,0,0,33,36,6,0,0,0,0,0,0,0,0,12,2,10,0,56,9,12,3,10,2,10,3,35,4,30,5,10,10,0,55,0,10,2,66,20,55,2,10,1,33,4,25,11,0,1,11,1,1,11,2,56,11,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,12,2,14,1,0,0,15,13,11,0,11,1,56,7,12,2,14,2,56,8,4,8,5,10,7,1,39,11,2,56,13,2,15,1,0,0,34,20,10,1,10,0,56,9,35,4,6,5,10,11,0,1,7,3,39,11,0,55,0,11,1,66,20,12,2,10,2,55,2,11,2,55,1,2,16,1,0,0,35,21,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,67,20,12,2,10,2,55,2,11,2,54,1,2,17,1,0,0,0,17,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,56,2,58,1,2,0,0,1,1,1,0,0,4,1,4,2,4,0],"vec_set":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,12,3,18,102,4,120,20,5,140,1,95,7,235,1,164,1,8,143,3,64,6,207,3,20,10,227,3,7,11,234,3,2,12,236,3,156,2,13,136,6,2,14,138,6,2,0,19,1,14,1,20,0,1,7,1,3,0,1,0,7,1,0,0,0,5,0,1,1,3,0,16,2,1,1,3,0,8,3,0,1,3,0,15,4,0,1,3,0,2,5,6,1,3,0,17,7,8,1,3,0,10,7,6,1,3,0,9,1,9,1,3,0,12,7,10,1,3,0,7,5,11,1,3,0,6,5,8,1,3,1,4,17,2,1,0,1,11,15,6,1,0,1,13,0,17,1,0,1,18,2,17,1,0,2,15,14,2,1,0,2,16,2,9,1,0,16,2,4,2,10,2,15,2,9,2,12,8,5,2,14,8,13,8,11,8,0,1,11,0,1,9,0,1,9,0,2,7,11,0,1,9,0,9,0,2,7,11,0,1,9,0,6,9,0,2,6,11,0,1,9,0,6,9,0,1,1,1,6,11,0,1,9,0,1,3,1,10,9,0,1,6,10,9,0,1,11,1,1,3,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,6,11,1,1,9,0,2,3,3,1,11,1,1,9,0,6,79,112,116,105,111,110,6,86,101,99,83,101,116,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,4,115,105,122,101,4,115,111,109,101,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,3,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,12,18,10,0,14,1,12,2,46,11,2,56,1,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,68,2,2,3,1,0,0,13,13,10,0,11,1,12,2,46,11,2,56,2,12,3,11,0,54,0,11,3,56,3,1,2,4,1,0,0,11,7,11,0,11,1,56,4,12,2,14,2,56,5,2,5,1,0,0,0,4,11,0,55,0,65,2,2,6,1,0,0,0,5,11,0,56,6,6,0,0,0,0,0,0,0,0,33,2,7,1,0,0,0,3,11,0,58,0,2,8,1,0,0,0,3,11,0,55,0,2,9,0,0,0,16,35,6,0,0,0,0,0,0,0,0,12,2,10,0,56,6,12,3,10,2,10,3,35,4,29,5,10,10,0,55,0,10,2,66,2,10,1,33,4,24,11,0,1,11,1,1,11,2,56,7,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,8,2,10,0,0,0,11,13,11,0,11,1,56,4,12,2,14,2,56,5,4,8,5,10,7,1,39,11,2,56,9,2,0,0,0,2,0],"versioned":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,20,3,28,85,4,113,10,5,123,97,7,220,1,236,1,8,200,3,32,6,232,3,10,10,242,3,16,12,130,4,197,1,13,199,5,4,0,23,0,11,0,16,0,20,0,4,12,0,0,3,0,0,2,0,7,0,2,2,4,0,3,1,2,0,0,8,0,1,1,4,0,22,2,3,0,0,13,2,4,1,4,0,14,5,6,1,4,0,19,5,7,1,4,0,21,8,9,1,4,0,10,1,10,1,4,1,5,14,9,2,7,4,1,6,15,16,2,7,4,1,7,17,18,2,7,4,1,18,17,19,2,7,4,2,9,12,9,0,2,12,4,20,1,8,2,15,11,12,0,7,13,8,13,9,13,10,13,12,1,3,3,9,0,7,8,4,1,8,0,1,6,8,0,1,3,1,6,9,0,1,7,8,0,1,7,9,0,2,9,0,8,1,4,7,8,0,3,9,0,8,1,0,1,9,0,1,7,8,4,1,8,3,2,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,8,2,3,8,3,9,0,3,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,16,86,101,114,115,105,111,110,67,104,97,110,103,101,67,97,112,9,86,101,114,115,105,111,110,101,100,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,2,105,100,10,108,111,97,100,95,118,97,108,117,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,3,110,101,119,6,111,98,106,101,99,116,11,111,108,100,95,118,101,114,115,105,111,110,6,114,101,109,111,118,101,24,114,101,109,111,118,101,95,118,97,108,117,101,95,102,111,114,95,117,112,103,114,97,100,101,10,116,120,95,99,111,110,116,101,120,116,7,117,112,103,114,97,100,101,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,12,118,101,114,115,105,111,110,101,100,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,3,22,3,1,2,2,24,8,2,17,3,0,1,0,0,1,12,11,2,17,13,10,0,18,0,12,3,13,3,15,0,11,0,11,1,56,0,11,3,2,1,1,0,0,9,4,11,0,16,1,20,2,2,1,0,0,9,7,10,0,16,0,11,0,16,1,20,56,1,2,3,1,0,0,9,7,10,0,15,0,11,0,16,1,20,56,2,2,4,1,0,0,9,14,10,0,15,0,10,0,16,1,20,56,3,10,0,46,56,4,11,0,16,1,20,18,1,2,5,1,0,0,3,32,11,3,19,1,12,4,10,0,46,56,4,33,4,9,5,13,11,0,1,7,0,39,11,4,10,1,35,4,18,5,22,11,0,1,7,0,39,10,0,15,0,10,1,11,2,56,0,11,1,11,0,15,1,21,2,6,1,0,0,21,12,11,0,19,0,12,3,12,1,13,1,11,3,56,3,12,2,11,1,17,11,11,2,2,0,0,0,1,0]},"type_origin_table":[{"module_name":"tx_context","struct_name":"TxContext","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"ID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"UID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_field","struct_name":"Field","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bag","struct_name":"Bag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Supply","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Balance","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bcs","struct_name":"BCS","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Referent","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"clock","struct_name":"Clock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"url","struct_name":"Url","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"Coin","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CoinMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"TreasuryCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CurrencyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"VecMap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"Publisher","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeTicket","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeReceipt","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"Display","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"DisplayCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"VersionUpdated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_object_field","struct_name":"Wrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"Curve","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PreparedVerifyingKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PublicProofInputs","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"ProofPoints","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_set","struct_name":"VecSet","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"iota","struct_name":"IOTA","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferRequest","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicy","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"RuleKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Kiosk","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"KioskOwnerCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"PurchaseCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Item","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Listing","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Lock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemListed","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemPurchased","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemDelisted","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"LinkedTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"Node","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_bag","struct_name":"ObjectBag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_table","struct_name":"ObjectTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"PriorityQueue","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table","struct_name":"Table","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table_vec","struct_name":"TableVec","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"Versioned","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"VersionChangeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000003","version":5,"module_map":{"genesis":[161,28,235,11,6,0,0,0,11,1,0,26,2,26,58,3,84,107,4,191,1,14,5,205,1,176,2,7,253,3,137,9,8,134,13,96,6,230,13,20,10,250,13,93,12,215,14,219,3,13,178,18,24,0,31,1,44,1,72,2,18,2,20,2,43,2,61,2,66,0,54,0,63,0,64,0,67,0,70,0,3,3,0,0,2,3,0,0,9,0,0,0,8,0,0,1,4,7,1,0,0,3,0,4,1,0,1,4,1,12,1,0,1,5,11,4,0,6,5,2,0,7,10,2,0,8,6,4,0,10,7,4,0,11,12,4,0,0,22,0,1,0,0,15,2,1,0,0,14,3,1,0,1,25,25,26,1,0,1,36,24,14,1,0,2,35,22,14,1,0,3,26,9,1,1,0,3,53,8,9,1,0,3,75,1,9,1,0,4,29,30,31,1,0,6,65,32,1,0,7,27,5,6,0,8,22,17,18,0,9,22,19,1,0,10,23,15,16,0,11,13,34,1,0,11,42,12,10,0,11,52,29,1,0,12,32,27,28,0,12,34,13,14,0,7,7,8,7,5,21,4,23,3,23,9,7,6,7,6,8,7,11,5,1,8,8,8,1,10,8,0,8,2,7,8,9,0,4,11,5,1,8,8,10,8,3,7,10,8,12,7,8,9,1,7,10,8,12,25,10,8,3,3,3,10,2,3,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,8,10,3,11,5,1,8,8,11,5,1,8,8,5,8,11,8,12,10,8,12,10,2,10,2,1,6,8,9,1,3,1,8,8,2,7,11,5,1,9,0,3,1,11,5,1,9,0,1,8,12,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,9,2,6,10,8,12,6,8,12,1,1,8,3,3,3,3,3,3,3,7,8,9,1,8,11,5,11,5,1,8,8,3,3,13,7,8,9,1,8,10,8,8,7,10,8,12,11,5,1,8,8,3,3,8,11,8,10,7,8,9,5,11,5,1,8,8,3,5,11,4,1,5,5,1,8,3,1,6,10,9,0,1,5,1,6,11,4,1,9,0,1,11,4,1,9,0,1,9,0,2,7,10,8,12,5,1,7,8,12,4,7,8,12,11,5,1,8,8,5,7,8,9,2,11,5,1,9,0,7,8,9,1,11,6,1,9,0,2,11,6,1,8,8,5,2,3,3,2,7,8,12,3,7,66,97,108,97,110,99,101,4,67,111,105,110,22,71,101,110,101,115,105,115,67,104,97,105,110,80,97,114,97,109,101,116,101,114,115,24,71,101,110,101,115,105,115,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,15,84,111,107,101,110,65,108,108,111,99,97,116,105,111,110,25,84,111,107,101,110,68,105,115,116,114,105,98,117,116,105,111,110,83,99,104,101,100,117,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,9,86,97,108,105,100,97,116,111,114,8,97,99,116,105,118,97,116,101,19,97,99,116,105,118,97,116,101,95,118,97,108,105,100,97,116,111,114,115,15,97,108,108,111,99,97,116,101,95,116,111,107,101,110,115,11,97,108,108,111,99,97,116,105,111,110,115,11,97,109,111,117,110,116,95,109,105,115,116,7,98,97,108,97,110,99,101,24,99,104,97,105,110,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,4,99,111,105,110,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,12,102,114,111,109,95,98,97,108,97,110,99,101,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,9,105,109,97,103,101,95,117,114,108,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,4,110,97,109,101,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,18,110,101,116,119,111,114,107,95,112,117,98,108,105,99,95,107,101,121,3,110,101,119,6,111,98,106,101,99,116,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,19,112,114,111,116,111,99,111,108,95,112,117,98,108,105,99,95,107,101,121,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,17,114,101,99,105,112,105,101,110,116,95,97,100,100,114,101,115,115,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,23,115,116,97,107,101,95,115,117,98,115,105,100,121,95,102,117,110,100,95,109,105,115,116,41,115,116,97,107,101,95,115,117,98,115,105,100,121,95,105,110,105,116,105,97,108,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,21,115,116,97,107,101,100,95,119,105,116,104,95,118,97,108,105,100,97,116,111,114,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,118,97,108,105,100,97,116,111,114,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,13,118,97,108,105,100,97,116,111,114,95,115,101,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,6,118,101,99,116,111,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,17,119,111,114,107,101,114,95,112,117,98,108,105,99,95,107,101,121,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,15,39,10,2,24,10,2,33,10,2,47,10,2,62,5,30,3,21,3,49,10,2,48,10,2,41,10,2,74,10,2,40,10,2,45,10,2,46,10,2,73,10,2,1,2,12,50,3,19,3,28,3,59,3,57,3,58,3,55,13,37,3,38,3,69,3,71,3,68,3,2,2,2,56,3,16,10,8,3,3,2,3,51,5,17,3,60,11,4,1,5,0,0,0,0,4,147,1,10,5,46,17,11,6,0,0,0,0,0,0,0,0,33,4,7,5,11,11,5,1,7,0,39,11,4,19,2,12,6,12,22,13,1,11,22,56,0,12,24,56,1,12,23,64,10,0,0,0,0,0,0,0,0,12,28,14,3,65,11,12,8,6,0,0,0,0,0,0,0,0,12,11,10,11,10,8,35,4,89,5,33,14,3,10,11,66,11,20,19,0,12,29,12,17,12,16,12,14,12,30,12,15,12,19,12,20,12,7,12,10,12,25,12,18,12,12,12,9,12,13,11,25,11,20,11,15,11,30,11,19,11,13,11,9,11,12,11,18,11,14,11,16,11,17,11,29,11,10,11,7,10,5,17,16,12,27,14,28,14,27,17,19,32,4,77,5,81,11,5,1,7,1,39,13,28,11,27,68,10,11,11,6,1,0,0,0,0,0,0,0,22,12,11,5,28,11,1,11,6,13,28,10,5,17,1,13,28,17,2,14,2,16,0,20,14,2,16,1,20,14,2,16,2,20,14,2,16,3,20,14,2,16,4,20,14,2,16,5,20,14,2,16,6,20,10,5,17,14,12,26,11,24,14,2,16,7,20,14,2,16,8,20,14,2,16,9,20,10,5,17,12,12,21,11,0,11,28,11,23,14,2,16,10,20,14,2,16,11,20,11,26,11,21,11,5,17,13,2,1,0,0,0,20,44,14,1,56,2,32,4,35,5,5,13,1,69,21,19,3,12,7,12,5,12,6,13,0,11,5,56,0,12,4,14,7,56,3,4,29,11,7,56,4,12,8,10,2,11,8,17,18,11,4,11,6,10,3,17,17,5,34,11,4,10,3,56,5,11,6,17,10,5,0,11,2,1,11,3,1,11,1,70,21,0,0,0,0,0,0,0,0,11,0,56,6,2,2,0,0,0,33,24,10,0,46,65,10,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,1,35,4,21,5,11,10,0,10,2,67,10,6,0,0,0,0,0,0,0,0,17,15,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,2,1,2,1,3,1,7,1,8,1,9,1,10,1,11,1,4,1,5,1,6,1,0,1,1,0],"stake_subsidy":[161,28,235,11,6,0,0,0,12,1,0,12,2,12,22,3,34,37,4,71,4,5,75,74,7,149,1,176,2,8,197,3,64,6,133,4,28,10,161,4,20,12,181,4,180,1,13,233,5,10,15,243,5,4,0,18,1,6,1,7,1,14,1,21,1,23,0,3,4,0,1,0,12,0,2,1,4,1,0,1,4,2,2,0,5,4,2,0,0,8,0,1,0,0,5,2,3,0,0,10,4,5,0,1,16,7,8,0,2,17,13,14,1,0,2,24,11,5,1,0,3,15,12,5,0,5,10,4,10,5,11,2,1,8,3,3,3,13,7,8,4,1,8,0,1,7,8,0,1,11,2,1,8,3,1,6,8,0,1,3,0,1,7,8,4,1,8,1,3,4,11,2,1,8,3,3,1,8,3,1,6,11,2,1,9,0,2,3,3,2,7,11,2,1,9,0,3,1,11,2,1,9,0,3,66,97,103,7,66,97,108,97,110,99,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,84,120,67,111,110,116,101,120,116,13,97,100,118,97,110,99,101,95,101,112,111,99,104,3,98,97,103,7,98,97,108,97,110,99,101,6,99,114,101,97,116,101,27,99,117,114,114,101,110,116,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,28,99,117,114,114,101,110,116,95,101,112,111,99,104,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,20,100,105,115,116,114,105,98,117,116,105,111,110,95,99,111,117,110,116,101,114,12,101,120,116,114,97,95,102,105,101,108,100,115,7,103,101,110,101,115,105,115,4,109,97,116,104,3,109,105,110,3,110,101,119,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,6,7,11,2,1,8,3,11,3,9,3,20,3,19,13,12,8,1,0,3,0,0,6,19,10,3,7,0,75,37,4,6,5,10,11,4,1,7,1,39,11,0,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,11,4,17,3,18,0,2,1,3,0,0,9,57,10,0,16,0,20,10,0,16,1,56,0,17,6,12,3,10,0,15,1,11,3,56,1,12,2,10,0,16,2,20,6,1,0,0,0,0,0,0,0,22,10,0,15,2,21,10,0,16,2,20,10,0,16,3,20,25,6,0,0,0,0,0,0,0,0,33,4,53,10,0,16,0,20,53,10,0,16,4,20,53,24,7,0,26,12,1,10,0,16,0,20,11,1,52,23,11,0,15,0,21,5,55,11,0,1,11,2,2,2,1,0,0,6,8,10,0,16,0,20,11,0,16,1,56,0,17,6,2,0,2,0,0,0,1,0,3,0,4,0,13,0,22,0],"staking_pool":[161,28,235,11,6,0,0,0,12,1,0,22,2,22,58,3,80,175,2,4,255,2,38,5,165,3,224,2,7,133,6,144,9,8,149,15,96,6,245,15,200,1,10,189,17,66,12,255,17,237,11,13,236,29,28,15,136,30,4,0,73,1,48,2,15,2,16,2,19,2,43,2,47,2,74,2,77,2,78,2,79,0,8,12,0,0,5,7,0,0,7,8,0,1,4,7,1,0,0,2,0,12,0,3,1,4,1,0,1,4,2,12,1,0,1,6,3,7,0,6,11,4,0,7,6,2,0,8,9,12,2,7,1,4,1,10,10,2,0,0,45,0,1,0,0,63,2,3,0,0,64,4,5,0,0,84,6,7,0,0,80,8,9,0,0,24,10,3,0,0,61,11,3,0,0,60,12,3,0,0,59,12,3,0,0,85,13,9,0,0,12,14,3,0,0,65,4,5,0,0,21,14,3,0,0,76,15,5,0,0,54,16,17,0,0,72,16,5,0,0,71,16,5,0,0,38,15,18,0,0,36,15,18,0,0,69,19,8,0,0,70,19,3,0,0,42,20,3,0,0,35,21,18,0,0,57,22,23,0,0,51,15,5,0,0,52,15,5,0,0,39,22,18,0,0,30,24,5,0,0,31,24,5,0,0,34,3,23,0,0,18,22,3,0,1,17,52,35,1,0,1,28,49,3,1,0,1,32,54,51,1,3,1,37,52,18,1,0,1,40,52,18,1,0,1,46,3,29,1,0,1,68,51,29,1,0,2,45,0,32,0,3,41,40,5,1,0,3,69,48,31,1,0,3,83,34,5,1,0,3,86,3,31,1,0,4,29,41,42,1,0,5,44,45,5,0,6,23,28,3,0,6,33,35,17,1,8,6,45,0,28,0,8,14,46,3,2,7,4,8,17,55,56,2,7,4,8,20,55,18,2,7,4,8,45,0,27,2,7,4,9,62,36,3,1,12,9,78,36,3,1,8,10,25,38,5,0,10,67,38,39,0,51,26,36,5,42,30,41,30,46,1,53,8,39,30,43,30,52,43,48,26,40,30,32,5,37,5,34,5,35,5,33,5,31,5,50,26,49,26,1,7,8,11,1,8,0,5,7,8,0,11,5,1,8,9,5,3,7,8,11,0,3,7,8,0,8,2,7,8,11,1,3,2,7,8,0,8,2,2,3,11,5,1,8,9,1,8,2,1,11,5,1,8,9,2,7,8,0,11,5,1,8,9,2,7,8,0,7,8,11,1,7,8,0,4,7,8,0,3,3,3,2,7,8,0,3,1,6,8,0,1,6,8,2,1,8,7,1,1,3,7,8,2,3,7,8,11,2,7,8,2,8,2,2,6,8,2,6,8,2,2,6,8,0,3,1,8,1,2,6,8,1,3,1,11,10,2,3,8,1,2,3,8,1,1,11,10,2,9,0,9,1,1,8,8,1,11,3,1,9,0,1,8,9,1,11,5,1,9,0,1,8,4,2,8,2,3,1,6,11,5,1,9,0,1,6,9,0,2,9,0,5,6,3,11,5,1,8,9,3,11,5,1,8,9,5,3,1,6,8,11,1,5,2,7,11,5,1,9,0,11,5,1,9,0,2,11,5,1,9,0,7,8,11,1,11,6,1,9,0,1,11,6,1,8,9,3,3,8,1,11,5,1,8,9,2,3,3,3,7,11,10,2,9,0,9,1,9,0,9,1,5,3,3,8,1,3,3,2,7,11,5,1,9,0,3,2,7,11,3,1,9,0,9,0,3,11,5,1,8,9,5,3,1,9,0,1,6,11,3,1,9,0,2,6,8,2,11,5,1,8,9,2,6,11,3,1,9,0,9,0,2,6,11,10,2,9,0,9,1,9,0,1,6,9,1,3,3,8,1,3,3,66,97,103,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,16,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,3,97,100,100,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,24,99,104,101,99,107,95,98,97,108,97,110,99,101,95,105,110,118,97,114,105,97,110,116,115,4,99,111,105,110,8,99,111,110,116,97,105,110,115,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,18,100,101,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,6,100,101,108,101,116,101,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,5,101,112,111,99,104,14,101,120,99,104,97,110,103,101,95,114,97,116,101,115,12,101,120,116,114,97,95,102,105,101,108,100,115,4,102,105,108,108,12,102,114,111,109,95,98,97,108,97,110,99,101,14,103,101,116,95,115,117,105,95,97,109,111,117,110,116,16,103,101,116,95,116,111,107,101,110,95,97,109,111,117,110,116,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,2,105,100,21,105,110,105,116,105,97,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,25,105,115,95,101,113,117,97,108,95,115,116,97,107,105,110,103,95,109,101,116,97,100,97,116,97,11,105,115,95,105,110,97,99,116,105,118,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,21,105,115,95,112,114,101,97,99,116,105,118,101,95,97,116,95,101,112,111,99,104,7,105,115,95,115,111,109,101,4,106,111,105,110,15,106,111,105,110,95,115,116,97,107,101,100,95,115,117,105,4,109,97,116,104,3,109,105,110,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,27,112,101,110,100,105,110,103,95,112,111,111,108,95,116,111,107,101,110,95,119,105,116,104,100,114,97,119,13,112,101,110,100,105,110,103,95,115,116,97,107,101,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,26,112,101,110,100,105,110,103,95,116,111,116,97,108,95,115,117,105,95,119,105,116,104,100,114,97,119,7,112,111,111,108,95,105,100,17,112,111,111,108,95,116,111,107,101,110,95,97,109,111,117,110,116,18,112,111,111,108,95,116,111,107,101,110,95,98,97,108,97,110,99,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,9,112,114,105,110,99,105,112,97,108,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,30,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,32,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,95,112,114,101,97,99,116,105,118,101,12,114,101,119,97,114,100,115,95,112,111,111,108,6,115,101,110,100,101,114,4,115,111,109,101,5,115,112,108,105,116,16,115,112,108,105,116,95,115,116,97,107,101,100,95,115,117,105,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,97,109,111,117,110,116,11,115,117,105,95,98,97,108,97,110,99,101,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,17,117,110,119,114,97,112,95,115,116,97,107,101,100,95,115,117,105,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,5,118,97,108,117,101,23,119,105,116,104,100,114,97,119,95,102,114,111,109,95,112,114,105,110,99,105,112,97,108,16,119,105,116,104,100,114,97,119,95,114,101,119,97,114,100,115,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,0,2,11,33,8,8,13,11,3,1,3,22,11,3,1,3,76,3,66,11,5,1,8,9,56,3,26,11,10,2,3,8,1,50,3,53,3,49,3,27,8,4,1,2,2,75,3,55,3,2,2,4,33,8,8,54,8,7,71,3,58,11,5,1,8,9,0,3,0,0,25,18,10,0,56,0,12,1,10,0,17,47,56,1,56,1,6,0,0,0,0,0,0,0,0,56,2,6,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,0,17,38,18,0,2,1,3,0,0,33,47,14,1,56,3,12,6,10,0,46,17,18,32,4,9,5,15,11,0,1,11,4,1,7,11,39,10,6,6,0,0,0,0,0,0,0,0,36,4,20,5,26,11,0,1,11,4,1,7,18,39,11,4,17,47,10,0,46,56,4,11,3,11,1,18,2,12,5,10,0,16,0,20,11,6,22,11,0,15,0,21,11,5,11,2,56,5,2,2,3,0,0,37,61,10,0,11,1,17,3,12,4,12,3,10,2,46,17,55,12,7,14,4,56,3,12,5,10,0,10,5,10,3,10,2,46,17,54,17,9,12,6,11,5,14,6,56,3,22,12,8,10,0,16,1,20,10,8,22,10,0,15,1,21,10,0,16,2,20,11,3,22,10,0,15,2,21,10,0,46,17,18,4,48,11,0,17,7,5,50,11,0,1,13,4,11,6,56,6,1,11,4,11,2,56,7,11,7,56,8,11,8,2,3,3,0,0,44,31,14,1,16,3,20,10,0,46,56,4,33,4,9,5,13,11,0,1,7,2,39,11,0,14,1,16,4,20,12,2,46,11,2,17,23,12,3,11,1,17,4,12,4,14,3,14,4,56,3,17,28,11,4,2,4,0,0,0,9,8,11,0,19,2,12,1,1,1,17,45,11,1,2,5,3,0,0,3,15,10,0,16,5,20,14,1,56,3,22,10,0,15,5,21,11,0,15,6,11,1,56,6,1,2,6,3,0,0,45,28,11,1,46,17,54,6,1,0,0,0,0,0,0,0,22,12,3,10,0,17,7,10,0,17,8,10,0,15,7,10,3,10,0,16,5,20,10,0,16,8,20,18,1,56,9,11,0,11,3,12,2,46,11,2,17,30,2,7,0,0,0,3,29,10,0,16,5,20,10,0,16,1,20,23,10,0,15,5,21,10,0,16,8,20,10,0,16,2,20,23,10,0,15,8,21,6,0,0,0,0,0,0,0,0,10,0,15,1,21,6,0,0,0,0,0,0,0,0,11,0,15,2,21,2,8,3,0,0,23,31,10,0,16,5,20,10,0,16,8,20,18,1,12,1,10,0,16,5,20,10,0,16,0,20,22,10,0,15,5,21,14,1,10,0,16,5,20,17,28,10,0,15,8,21,6,0,0,0,0,0,0,0,0,11,0,15,0,21,2,9,0,0,0,47,33,10,0,11,3,12,4,46,11,4,17,23,12,6,14,6,11,2,17,27,12,8,10,8,10,1,38,4,20,11,8,11,1,23,12,5,5,22,6,0,0,0,0,0,0,0,0,12,5,11,5,10,0,16,6,56,3,17,44,12,7,11,0,15,6,11,7,56,10,2,10,3,0,0,3,29,10,0,15,7,10,1,17,29,56,9,10,0,46,17,17,4,10,5,14,11,0,1,7,15,39,10,0,46,17,18,32,4,20,5,24,11,0,1,7,17,39,11,0,15,9,11,1,56,11,2,11,3,0,0,50,59,14,1,16,3,20,10,0,46,56,4,33,4,9,5,15,11,0,1,11,2,1,7,2,39,10,0,46,17,17,4,20,5,26,11,0,1,11,2,1,7,16,39,10,2,46,17,55,12,4,11,1,17,4,12,3,14,3,56,3,12,5,10,0,16,5,20,10,5,23,10,0,15,5,21,10,0,16,8,20,10,5,23,11,0,15,8,21,11,3,11,2,56,7,11,4,56,8,11,5,2,12,3,0,0,3,16,10,0,46,17,18,32,4,6,5,10,11,0,1,7,12,39,11,1,56,12,11,0,15,10,21,2,13,1,0,0,3,4,11,0,16,5,20,2,14,1,0,0,3,4,11,0,16,3,20,2,15,1,0,0,3,4,11,0,16,11,56,3,2,16,1,0,0,3,4,11,0,16,4,20,2,17,1,0,0,3,4,11,0,16,9,56,13,2,18,1,0,0,3,4,11,0,16,10,56,14,2,19,1,0,0,5,53,10,0,16,11,56,3,12,3,10,1,10,3,37,4,9,5,15,11,0,1,11,2,1,7,4,39,11,3,10,1,23,7,0,38,4,22,5,28,11,0,1,11,2,1,7,19,39,10,1,7,0,38,4,33,5,39,11,0,1,11,2,1,7,19,39,11,2,17,47,10,0,16,3,20,10,0,16,4,20,11,0,15,11,11,1,56,10,18,2,2,20,1,4,0,3,9,11,0,11,1,10,2,17,19,11,2,46,17,55,56,5,2,21,1,4,0,53,24,10,0,14,1,12,2,46,11,2,17,22,4,8,5,12,11,0,1,7,13,39,11,1,19,2,12,3,1,1,17,45,11,0,15,11,11,3,56,6,1,2,22,1,0,0,18,25,10,0,16,3,20,10,1,16,3,20,33,4,17,11,0,16,4,20,11,1,16,4,20,33,12,2,5,23,11,0,1,11,1,1,9,12,2,11,2,2,23,1,0,0,45,45,10,0,10,1,17,26,4,8,11,0,1,17,29,2,10,0,16,10,10,1,56,15,11,1,17,44,12,3,10,0,16,9,56,16,20,12,2,10,3,10,2,38,4,41,5,25,10,0,16,7,10,3,56,17,4,36,11,0,16,7,11,3,56,18,20,2,11,3,6,1,0,0,0,0,0,0,0,23,12,3,5,20,11,0,1,17,29,2,24,1,0,0,3,4,11,0,16,0,20,2,25,1,0,0,3,4,11,0,16,1,20,2,26,0,0,0,18,17,10,0,17,17,4,8,11,0,1,8,12,2,5,15,11,0,16,9,56,16,20,11,1,36,12,2,11,2,2,27,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,12,20,53,11,1,53,24,11,0,16,13,20,53,26,52,2,28,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,13,20,53,11,1,53,24,11,0,16,12,20,53,26,52,2,29,0,0,0,3,4,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,18,1,2,30,0,0,0,57,22,10,0,11,1,17,23,12,3,14,3,10,0,16,5,20,17,28,12,4,11,0,16,8,20,12,2,11,4,11,2,33,4,19,5,21,7,10,39,2,0,7,0,8,0,9,2,1,2,2,0,3,0,4,0,6,0,5,0,1,0,2,2,3,1,0,1,1,0,81,0,82,0],"storage_fund":[161,28,235,11,6,0,0,0,11,1,0,6,2,6,14,3,20,44,4,64,8,5,72,73,7,145,1,178,1,8,195,2,64,10,131,3,15,12,146,3,107,13,253,3,4,15,129,4,2,0,9,1,4,1,10,0,2,4,0,1,0,4,1,0,1,2,1,2,0,0,6,0,1,0,0,3,2,0,0,0,13,3,4,0,0,12,3,4,0,1,5,8,4,1,0,1,8,9,7,1,0,1,14,10,4,1,0,1,15,5,7,1,0,7,6,4,6,5,6,6,6,1,11,1,1,8,2,1,8,0,6,7,8,0,11,1,1,8,2,11,1,1,8,2,11,1,1,8,2,3,3,1,6,8,0,1,3,0,1,8,2,1,11,1,1,9,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,6,11,1,1,9,0,7,66,97,108,97,110,99,101,3,83,85,73,11,83,116,111,114,97,103,101,70,117,110,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,4,106,111,105,110,3,110,101,119,22,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,98,97,108,97,110,99,101,5,115,112,108,105,116,12,115,116,111,114,97,103,101,95,102,117,110,100,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,13,116,111,116,97,108,95,98,97,108,97,110,99,101,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,11,1,1,8,2,7,11,1,1,8,2,0,3,0,0,5,4,56,0,11,0,18,0,2,1,3,0,0,0,30,10,0,15,0,11,2,56,1,1,10,0,15,0,11,3,56,1,1,10,0,15,1,11,1,56,1,1,10,0,15,1,11,5,56,2,12,6,10,0,15,0,11,6,56,1,1,11,0,15,1,11,4,56,2,2,2,1,0,0,5,4,11,0,16,1,56,3,2,3,1,0,0,5,8,10,0,16,1,56,3,11,0,16,0,56,3,22,2,0,1,0,0,0,11,0],"iota_system":[161,28,235,11,6,0,0,0,12,1,0,28,2,28,62,3,90,146,3,4,236,3,10,5,246,3,158,3,7,148,7,191,12,8,211,19,96,6,179,20,54,10,233,20,8,12,241,20,166,6,13,151,27,4,15,155,27,2,0,48,1,28,2,16,2,18,2,20,2,27,2,47,2,51,2,52,0,45,0,46,0,49,0,73,0,74,0,6,8,0,1,2,7,1,0,0,2,0,4,1,0,1,3,1,12,1,0,1,5,11,4,0,6,3,2,0,8,10,2,0,9,4,4,0,10,5,8,0,11,7,4,0,11,8,4,0,11,9,4,0,12,13,4,0,13,12,12,0,0,19,0,1,0,0,34,2,1,0,0,36,3,1,0,0,33,3,1,0,0,35,3,1,0,0,38,4,1,0,0,43,4,1,0,0,37,5,1,0,0,42,5,1,0,0,31,6,1,0,0,32,7,1,0,0,39,8,1,0,0,30,9,1,0,0,53,9,1,0,0,40,3,1,0,0,63,10,1,0,0,61,10,1,0,0,62,10,1,0,0,71,10,1,0,0,64,10,1,0,0,54,10,1,0,0,66,10,1,0,0,56,10,1,0,0,67,10,1,0,0,57,10,1,0,0,69,10,1,0,0,59,10,1,0,0,68,11,1,0,0,58,11,1,0,0,70,10,1,0,0,60,10,1,0,0,65,10,1,0,0,55,10,1,0,0,15,12,13,0,0,25,14,15,0,0,26,14,16,0,0,24,14,16,0,4,14,22,1,2,7,4,4,17,39,43,2,7,4,4,29,39,40,2,7,4,7,44,24,1,1,8,8,41,35,36,0,11,15,37,13,0,11,19,18,19,0,11,22,1,20,0,11,30,32,1,0,11,31,29,1,0,11,32,30,1,0,11,33,26,1,0,11,34,25,1,0,11,35,26,1,0,11,36,26,1,0,11,37,28,1,0,11,38,27,1,0,11,39,31,1,0,11,40,26,1,0,11,42,28,1,0,11,43,27,1,0,11,50,15,20,0,11,53,32,1,0,11,54,33,1,0,11,55,33,1,0,11,56,33,1,0,11,57,33,1,0,11,58,34,1,0,11,59,33,1,0,11,60,33,1,0,11,61,33,1,0,11,62,33,1,0,11,63,33,1,0,11,64,33,1,0,11,65,33,1,0,11,66,33,1,0,11,67,33,1,0,11,68,34,1,0,11,69,33,1,0,11,70,33,1,0,11,71,33,1,0,11,72,19,41,0,37,21,40,23,39,21,37,42,38,42,8,8,4,10,8,12,11,2,1,8,5,3,3,8,11,8,7,7,8,6,0,16,7,8,0,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,6,2,7,8,0,7,8,6,3,7,8,0,6,8,13,3,3,7,8,0,3,7,8,6,4,7,8,0,11,3,1,8,5,5,7,8,6,5,7,8,0,10,11,3,1,8,5,11,1,1,3,5,7,8,6,3,7,8,0,8,8,7,8,6,3,7,8,0,6,8,13,5,3,7,8,0,10,2,6,8,6,4,7,8,0,10,2,10,2,6,8,6,11,11,2,1,8,5,11,2,1,8,5,7,8,0,3,3,3,3,3,3,3,7,8,6,1,11,2,1,8,5,1,7,8,0,1,6,8,10,1,7,8,10,3,8,0,8,9,3,7,10,8,12,11,2,1,8,5,3,3,8,11,8,7,7,8,6,1,8,9,1,3,2,3,8,9,3,7,8,4,9,0,9,1,1,8,0,1,9,0,16,7,8,10,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,6,2,7,8,10,7,8,6,3,7,8,10,6,8,13,3,3,7,8,10,3,7,8,6,4,7,8,10,11,3,1,8,5,5,7,8,6,5,7,8,10,10,11,3,1,8,5,11,1,1,3,5,7,8,6,3,7,8,10,8,8,7,8,6,3,7,8,10,6,8,13,5,3,7,8,10,10,2,6,8,6,4,7,8,10,10,2,10,2,6,8,6,1,6,8,6,1,5,11,7,8,10,3,3,11,2,1,8,5,11,2,1,8,5,3,3,3,3,3,7,8,6,2,7,8,10,8,10,2,7,8,4,9,0,1,9,1,1,8,10,2,3,8,10,1,7,9,1,7,66,97,108,97,110,99,101,4,67,111,105,110,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,14,83,117,105,83,121,115,116,101,109,83,116,97,116,101,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,3,97,100,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,4,99,111,105,110,6,99,114,101,97,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,2,105,100,24,108,111,97,100,95,105,110,110,101,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,17,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,21,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,95,109,117,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,6,115,101,110,100,101,114,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,23,8,4,75,3,0,3,0,0,17,23,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,43,12,9,17,44,12,10,11,0,10,10,18,0,12,8,13,8,15,0,11,10,11,9,56,0,11,8,56,1,2,1,1,4,0,1,19,11,0,17,35,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,11,15,17,49,2,2,1,4,0,1,5,11,0,17,35,11,1,17,51,2,3,1,4,0,1,5,11,0,17,35,11,1,17,48,2,4,1,4,0,1,5,11,0,17,35,11,1,17,50,2,5,1,4,0,1,6,11,0,17,35,11,1,11,2,17,53,2,6,1,4,0,1,6,11,0,17,35,11,1,11,2,17,57,2,7,1,4,0,1,6,11,0,17,35,11,1,11,2,17,52,2,8,1,4,0,1,6,11,0,17,35,11,1,11,2,17,56,2,9,1,4,0,1,7,11,0,17,35,11,1,11,2,11,3,17,46,2,10,1,4,0,1,8,11,0,17,35,11,1,11,2,11,3,11,4,17,47,2,11,1,4,0,1,6,11,0,17,35,11,1,11,2,17,54,2,12,1,4,0,1,6,11,0,17,35,11,1,11,2,17,45,2,13,1,4,0,1,6,11,0,17,35,11,1,11,2,17,59,2,14,1,4,0,1,5,11,0,17,35,11,1,17,55,2,15,1,4,0,1,6,11,0,17,35,11,1,11,2,17,69,2,16,1,4,0,1,6,11,0,17,35,11,1,11,2,17,67,2,17,1,4,0,1,6,11,0,17,35,11,1,11,2,17,68,2,18,1,4,0,1,6,11,0,17,35,11,1,11,2,17,77,2,19,1,4,0,1,6,11,0,17,35,11,1,11,2,17,70,2,20,1,4,0,1,6,11,0,17,35,11,1,11,2,17,60,2,21,1,4,0,1,6,11,0,17,35,11,1,11,2,17,72,2,22,1,4,0,1,6,11,0,17,35,11,1,11,2,17,62,2,23,1,4,0,1,6,11,0,17,35,11,1,11,2,17,73,2,24,1,4,0,1,6,11,0,17,35,11,1,11,2,17,63,2,25,1,4,0,1,6,11,0,17,35,11,1,11,2,17,75,2,26,1,4,0,1,6,11,0,17,35,11,1,11,2,17,65,2,27,1,4,0,1,7,11,0,17,35,11,1,11,2,11,3,17,74,2,28,1,4,0,1,7,11,0,17,35,11,1,11,2,11,3,17,64,2,29,1,4,0,1,6,11,0,17,35,11,1,11,2,17,76,2,30,1,4,0,1,6,11,0,17,35,11,1,11,2,17,66,2,31,1,4,0,1,6,11,0,17,35,11,1,11,2,17,71,2,32,1,4,0,1,6,11,0,17,35,11,1,11,2,17,61,2,33,0,0,0,16,29,11,2,17,35,12,11,10,10,46,17,41,7,2,33,4,10,5,16,11,11,1,11,10,1,7,0,39,11,11,11,3,11,4,11,0,11,1,11,5,11,6,11,7,11,8,11,9,11,10,17,42,2,34,0,0,0,1,4,11,0,17,36,46,2,35,0,0,0,1,3,11,0,17,36,2,36,0,0,0,38,47,10,0,16,1,20,6,1,0,0,0,0,0,0,0,33,4,25,10,0,15,0,10,0,16,1,20,56,2,17,78,12,2,6,2,0,0,0,0,0,0,0,10,0,15,1,21,10,0,15,0,10,0,16,1,20,11,2,56,3,10,0,15,0,10,0,16,1,20,56,4,12,1,10,1,46,17,58,11,0,16,1,20,33,4,41,5,45,11,1,1,7,1,39,11,1,2,0,0,0,1,0,21,0],"iota_system_state_inner":[161,28,235,11,6,0,0,0,12,1,0,45,2,45,104,3,149,1,212,5,4,233,6,50,5,155,7,251,6,7,150,14,188,29,8,210,43,96,6,178,44,117,10,167,45,189,1,12,228,46,229,17,13,201,64,46,15,247,64,4,0,112,1,68,2,25,2,26,2,27,2,39,2,67,2,70,2,110,2,114,2,120,2,121,2,174,1,2,175,1,0,100,0,103,0,106,0,161,1,0,162,1,0,166,1,0,12,4,0,0,13,4,0,0,9,4,0,0,10,4,0,0,11,3,0,1,4,7,1,0,0,2,0,12,0,3,1,4,1,0,1,4,2,12,1,0,1,6,3,7,0,8,5,2,0,9,14,12,2,7,1,4,1,11,15,2,0,12,20,7,2,1,0,0,0,13,21,7,1,3,0,14,6,4,0,15,7,8,0,16,8,4,0,17,17,4,0,18,16,12,0,18,18,2,0,19,19,4,0,0,29,0,1,0,0,30,2,3,0,0,160,1,1,4,0,0,80,5,6,0,0,82,7,6,0,0,79,7,6,0,0,81,7,6,0,0,84,8,6,0,0,96,8,6,0,0,83,9,6,0,0,95,9,6,0,0,77,10,6,0,0,78,11,6,0,0,85,12,6,0,0,75,13,6,0,0,122,13,6,0,0,76,14,6,0,0,123,14,6,0,0,86,7,6,0,0,151,1,15,6,0,0,149,1,15,6,0,0,150,1,15,6,0,0,159,1,15,6,0,0,152,1,15,6,0,0,129,1,15,6,0,0,154,1,15,6,0,0,131,1,15,6,0,0,155,1,15,6,0,0,132,1,15,6,0,0,157,1,15,6,0,0,134,1,15,6,0,0,156,1,16,6,0,0,133,1,16,6,0,0,158,1,15,6,0,0,135,1,15,6,0,0,153,1,15,6,0,0,130,1,15,6,0,0,23,17,18,0,0,36,19,20,0,0,71,19,20,0,0,113,19,20,0,0,44,6,20,0,0,38,19,20,0,0,167,1,21,20,0,0,168,1,21,22,0,0,169,1,19,23,0,0,47,21,24,0,0,49,19,20,0,0,48,19,20,0,0,41,25,18,0,1,32,94,64,1,0,1,57,93,59,1,0,2,64,35,36,0,3,33,34,6,1,0,3,58,81,20,1,0,3,98,85,34,1,0,3,173,1,83,20,1,0,3,178,1,80,34,1,0,3,179,1,6,34,1,0,4,42,95,54,1,0,4,54,54,34,1,0,5,34,64,6,1,3,7,59,92,6,1,0,10,72,96,6,1,12,11,36,39,20,0,11,92,39,40,0,12,28,63,59,2,1,0,12,35,6,32,2,1,0,12,45,63,89,2,1,0,12,46,67,68,2,1,0,12,53,66,6,2,1,0,12,74,67,73,2,1,0,13,28,69,59,1,3,13,35,6,65,1,3,13,53,70,6,1,3,13,56,72,59,1,3,13,74,71,6,1,3,13,97,64,65,1,3,14,23,84,18,0,15,99,56,20,0,16,23,87,18,0,16,64,18,30,0,16,115,82,20,0,16,117,82,20,0,17,64,41,38,0,17,65,74,6,0,17,84,50,6,0,17,93,53,6,0,17,94,50,6,0,17,124,75,6,0,17,125,75,6,0,17,126,75,6,0,17,127,75,6,0,17,128,1,78,6,0,17,136,1,75,6,0,17,137,1,75,6,0,17,138,1,75,6,0,17,139,1,75,6,0,17,140,1,75,6,0,17,141,1,75,6,0,17,142,1,75,6,0,17,143,1,75,6,0,17,144,1,75,6,0,17,145,1,78,6,0,17,146,1,75,6,0,17,147,1,75,6,0,17,148,1,75,6,0,18,176,1,61,62,0,19,22,29,45,0,19,23,86,6,0,19,24,77,6,0,19,31,29,20,0,19,50,52,49,0,19,51,52,49,0,19,52,48,49,0,19,55,58,59,0,19,64,27,28,0,19,66,29,20,0,19,77,55,6,0,19,79,44,6,0,19,80,42,6,0,19,81,43,6,0,19,82,43,6,0,19,83,51,6,0,19,85,57,6,0,19,104,29,23,0,19,118,29,20,0,19,168,1,58,22,0,19,170,1,58,20,0,19,177,1,47,46,0,67,31,58,33,60,33,66,31,77,40,70,31,69,31,72,40,74,40,76,40,75,40,71,31,57,33,54,33,56,33,55,33,61,88,68,31,73,40,62,33,51,20,50,20,59,33,63,91,53,33,7,10,8,18,11,7,1,8,10,3,3,8,0,8,15,7,8,12,1,8,2,8,3,3,3,3,3,3,3,7,8,12,1,8,0,1,8,3,16,7,8,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,0,2,7,8,3,7,8,12,3,7,8,3,6,8,19,3,3,7,8,3,3,7,8,12,4,7,8,3,11,8,1,8,10,5,7,8,12,5,7,8,3,10,11,8,1,8,10,11,5,1,3,5,7,8,12,3,7,8,3,8,16,7,8,12,3,7,8,3,6,8,19,5,3,8,20,5,7,11,13,2,5,11,14,1,5,3,7,8,3,10,2,6,8,12,4,7,8,3,10,2,10,2,6,8,12,11,7,8,3,3,3,11,7,1,8,10,11,7,1,8,10,3,3,3,3,3,7,8,12,1,11,7,1,8,10,1,6,8,3,1,3,2,6,8,3,5,1,8,9,1,6,11,11,2,8,9,5,1,11,14,1,5,3,10,11,8,1,8,10,11,5,1,3,7,8,12,2,3,8,21,2,10,8,18,7,8,12,1,8,21,1,6,8,21,1,8,17,2,5,11,14,1,5,1,11,13,2,9,0,9,1,1,8,10,1,11,7,1,9,0,1,7,8,12,1,8,6,23,3,3,3,3,3,8,6,8,0,3,3,1,11,7,1,8,10,3,3,11,7,1,8,10,8,15,3,8,6,8,17,3,3,11,13,2,5,11,14,1,5,3,8,21,1,8,18,1,6,8,12,1,5,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,3,7,8,21,8,18,7,8,12,2,7,8,21,7,8,12,3,7,8,21,3,7,8,12,1,6,10,8,18,1,8,20,3,7,8,21,6,8,19,2,3,7,8,21,6,8,20,1,1,7,8,18,3,7,8,18,8,20,3,3,7,8,21,3,6,8,12,2,7,8,21,6,8,12,2,7,8,18,3,1,11,8,1,9,0,4,7,8,21,5,11,7,1,8,10,7,8,12,1,6,8,16,3,7,8,21,8,16,7,8,12,2,6,8,21,5,1,1,4,6,5,6,5,5,7,11,14,1,5,1,6,8,20,1,6,5,2,6,11,13,2,9,0,9,1,6,9,0,1,9,0,1,11,14,1,9,0,3,7,11,13,2,9,0,9,1,9,0,9,1,2,7,11,13,2,9,0,9,1,6,9,0,1,7,9,1,2,6,11,14,1,9,0,6,9,0,2,7,11,14,1,9,0,9,0,2,7,11,14,1,9,0,6,9,0,1,6,11,14,1,9,0,2,9,0,9,1,2,7,8,18,7,8,12,2,7,8,18,10,2,2,7,8,18,6,8,18,2,6,8,21,6,8,18,3,7,8,18,10,2,10,2,44,1,3,3,3,3,3,3,1,1,1,11,7,1,8,10,3,3,3,3,3,3,3,3,4,3,3,3,11,7,1,8,10,3,3,3,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,3,11,7,1,8,10,4,11,7,1,8,10,4,3,3,3,3,4,3,1,7,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,1,6,8,17,1,6,11,7,1,9,0,1,7,8,15,2,7,11,7,1,9,0,3,9,7,8,21,7,11,7,1,8,10,7,11,7,1,8,10,7,11,13,2,5,11,14,1,5,3,3,3,3,7,8,12,6,7,8,17,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,1,8,4,1,6,9,1,5,11,7,1,8,10,3,11,7,1,8,10,11,8,1,8,10,11,7,1,8,10,1,11,8,1,8,10,2,7,11,8,1,9,0,10,11,8,1,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,2,11,7,1,9,0,7,8,12,2,9,0,5,3,66,97,103,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,11,83,116,111,114,97,103,101,70,117,110,100,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,20,83,121,115,116,101,109,69,112,111,99,104,73,110,102,111,69,118,101,110,116,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,18,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,86,50,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,6,86,101,99,77,97,112,6,86,101,99,83,101,116,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,3,98,97,103,7,98,97,108,97,110,99,101,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,5,101,109,112,116,121,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,24,101,112,111,99,104,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,20,101,120,116,114,97,99,116,95,99,111,105,110,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,3,103,101,116,7,103,101,116,95,109,117,116,16,103,101,116,95,114,101,112,111,114,116,101,114,115,95,111,102,31,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,111,98,106,101,99,116,95,114,101,98,97,116,101,115,30,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,116,111,116,97,108,95,98,97,108,97,110,99,101,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,6,105,110,115,101,114,116,12,105,110,116,111,95,98,97,108,97,110,99,101,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,106,111,105,110,8,106,111,105,110,95,118,101,99,28,108,101,102,116,111,118,101,114,95,115,116,111,114,97,103,101,95,102,117,110,100,95,105,110,102,108,111,119,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,19,109,105,110,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,3,110,101,119,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,114,97,109,101,116,101,114,115,3,112,97,121,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,19,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,21,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,9,115,97,102,101,95,109,111,100,101,29,115,97,102,101,95,109,111,100,101,95,99,111,109,112,117,116,97,116,105,111,110,95,114,101,119,97,114,100,115,36,115,97,102,101,95,109,111,100,101,95,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,115,116,111,114,97,103,101,95,102,101,101,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,119,97,114,100,115,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,9,115,105,110,103,108,101,116,111,110,5,115,112,108,105,116,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,13,115,116,97,107,101,95,115,117,98,115,105,100,121,20,115,116,97,107,101,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,12,115,116,97,107,105,110,103,95,112,111,111,108,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,14,115,116,111,114,97,103,101,95,99,104,97,114,103,101,12,115,116,111,114,97,103,101,95,102,117,110,100,20,115,116,111,114,97,103,101,95,102,117,110,100,95,98,97,108,97,110,99,101,25,115,116,111,114,97,103,101,95,102,117,110,100,95,114,101,105,110,118,101,115,116,109,101,110,116,14,115,116,111,114,97,103,101,95,114,101,98,97,116,101,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,5,116,97,98,108,101,13,116,111,116,97,108,95,98,97,108,97,110,99,101,14,116,111,116,97,108,95,103,97,115,95,102,101,101,115,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,31,116,111,116,97,108,95,115,116,97,107,101,95,114,101,119,97,114,100,115,95,100,105,115,116,114,105,98,117,116,101,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,26,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,24,118,97,108,105,100,97,116,111,114,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,31,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,10,118,97,108,105,100,97,116,111,114,115,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,3,8,1,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,8,37,3,102,3,61,3,63,3,164,1,3,171,1,3,163,1,3,40,8,6,1,2,9,37,3,102,3,62,3,61,3,63,3,164,1,3,171,1,3,163,1,3,40,8,6,2,2,16,36,3,71,3,113,3,172,1,8,21,106,8,17,69,8,0,73,3,165,1,11,13,2,5,11,14,1,5,100,8,15,87,1,91,11,7,1,8,10,88,11,7,1,8,10,90,3,89,3,38,3,40,8,6,3,2,16,36,3,71,3,113,3,172,1,8,21,106,8,17,69,8,1,73,3,165,1,11,13,2,5,11,14,1,5,100,8,15,87,1,91,11,7,1,8,10,88,11,7,1,8,10,90,3,89,3,38,3,40,8,6,4,2,12,36,3,71,3,73,3,118,3,108,3,105,3,109,3,107,3,101,3,116,3,119,3,60,3,0,3,0,0,26,27,11,0,10,6,17,116,12,8,14,8,17,111,12,7,6,0,0,0,0,0,0,0,0,11,2,17,41,11,8,11,1,17,81,11,4,11,7,56,0,11,5,9,56,1,56,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,3,11,6,17,52,18,2,2,1,3,0,0,6,11,11,0,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,52,18,0,2,2,3,0,0,37,55,11,0,19,2,12,17,12,3,12,12,12,13,12,11,12,14,12,10,12,15,12,21,12,9,12,7,12,18,12,23,1,12,8,12,1,11,7,19,0,12,6,12,19,12,22,12,20,12,5,12,4,12,16,12,2,11,1,11,8,6,2,0,0,0,0,0,0,0,11,23,11,18,11,2,11,16,6,4,0,0,0,0,0,0,0,11,4,11,5,11,20,11,22,11,19,11,6,18,1,11,9,11,21,11,15,11,10,11,14,11,11,11,13,11,12,11,3,11,17,18,3,2,3,3,0,0,38,26,10,15,46,17,65,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,10,15,17,84,12,16,11,0,15,0,11,16,11,15,17,120,2,4,3,0,0,6,5,11,0,15,0,11,1,17,122,2,5,3,0,0,6,25,10,0,16,0,17,117,10,0,16,1,16,2,20,35,4,10,5,16,11,0,1,11,1,1,7,3,39,10,0,15,0,11,0,16,1,16,3,20,11,1,17,119,2,6,3,0,0,6,31,10,0,16,0,17,108,65,38,10,0,16,1,16,4,20,38,4,26,10,0,16,0,17,117,10,0,16,1,16,4,20,36,4,20,5,26,11,0,1,11,1,1,7,3,39,11,0,15,0,11,1,17,121,2,7,3,0,0,46,15,10,0,15,0,11,1,7,1,17,129,1,12,3,11,0,15,0,14,3,9,17,114,11,3,11,2,17,86,2,8,3,0,0,46,15,10,0,15,0,11,1,7,2,17,129,1,12,3,11,0,15,0,14,3,8,17,114,11,3,11,2,17,88,2,9,3,0,0,6,7,11,0,15,0,11,1,11,2,46,17,123,2,10,3,0,0,6,8,11,0,15,0,11,2,46,17,113,11,1,17,87,2,11,3,0,0,6,8,11,0,15,0,11,2,11,1,56,2,11,3,17,118,2,12,3,0,0,18,12,11,1,11,2,10,4,17,49,12,5,11,0,15,0,11,3,11,5,11,4,17,118,2,13,3,0,0,6,20,14,1,17,79,10,2,46,17,64,37,4,8,5,14,11,0,1,11,2,1,7,9,39,11,0,15,0,11,1,11,2,17,124,2,14,3,0,0,6,22,10,0,16,0,10,2,17,115,4,6,5,12,11,0,1,11,1,1,7,4,39,10,0,15,0,11,1,7,0,17,129,1,11,2,11,0,15,5,17,16,2,15,3,0,0,6,10,10,0,15,0,11,1,7,0,17,129,1,11,2,11,0,15,5,17,17,2,16,0,0,0,60,46,14,0,17,107,20,12,5,10,5,10,1,34,4,9,5,13,11,2,1,7,6,39,10,2,14,1,12,3,46,11,3,56,3,32,4,27,11,2,11,1,11,5,56,4,56,5,5,45,11,2,14,1,56,6,12,6,10,6,14,5,12,4,46,11,4,56,7,32,4,43,11,6,11,5,56,8,5,45,11,6,1,2,17,0,0,0,60,50,10,2,14,1,12,3,46,11,3,56,3,4,8,5,12,11,2,1,7,7,39,10,2,14,1,56,6,12,6,14,0,17,107,20,12,5,10,6,14,5,12,4,46,11,4,56,7,4,28,5,34,11,2,1,11,6,1,7,7,39,10,6,14,5,56,9,11,6,46,56,10,4,47,11,2,14,1,56,11,1,1,5,49,11,2,1,2,18,3,0,0,6,8,11,0,15,0,10,1,46,17,113,11,1,17,85,2,19,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,98,2,20,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,96,2,21,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,97,2,22,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,106,2,23,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,99,11,3,46,12,4,11,0,16,0,11,4,17,110,2,24,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,89,2,25,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,101,11,3,46,12,4,11,0,16,0,11,4,17,110,2,26,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,91,2,27,3,0,0,6,7,11,0,15,0,11,2,17,112,11,1,17,102,2,28,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,92,2,29,3,0,0,6,7,11,0,15,0,11,2,17,112,11,1,17,104,2,30,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,94,2,31,3,0,0,76,17,10,0,15,0,11,3,17,112,12,4,10,4,11,1,11,2,17,103,11,4,46,12,5,11,0,16,0,11,5,17,110,2,32,3,0,0,6,8,11,0,15,0,11,3,17,113,11,1,11,2,17,93,2,33,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,105,11,3,46,12,4,11,0,16,0,11,4,17,110,2,34,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,95,2,35,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,100,11,3,46,12,4,11,0,16,0,11,4,17,110,2,36,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,90,2,37,3,0,0,79,220,2,10,0,16,6,20,12,37,10,9,10,0,15,6,21,7,12,52,12,28,10,7,10,28,37,4,20,10,8,11,28,37,12,11,5,22,9,12,11,11,11,4,25,5,31,11,0,1,11,10,1,7,8,39,10,0,16,1,16,7,20,6,0,0,0,0,0,0,0,0,36,4,43,6,20,0,0,0,0,0,0,0,10,0,15,1,15,7,21,10,0,15,8,56,12,12,40,13,3,11,40,56,13,1,10,0,15,9,56,12,12,39,13,4,11,39,56,13,1,11,5,10,0,16,10,20,22,12,5,6,0,0,0,0,0,0,0,0,10,0,15,10,21,11,6,10,0,16,11,20,22,12,6,6,0,0,0,0,0,0,0,0,10,0,15,11,21,10,0,16,0,17,126,12,54,10,0,16,12,17,82,12,44,10,44,11,54,22,12,52,14,3,56,14,12,43,14,4,56,14,12,29,10,10,46,17,64,10,0,16,1,16,7,20,38,4,116,11,9,11,37,10,0,16,1,16,13,20,22,38,12,20,5,118,9,12,20,11,20,4,125,10,0,15,14,17,78,12,21,5,127,56,1,12,21,11,21,12,41,14,41,56,14,12,42,13,4,11,41,56,13,1,11,52,53,12,53,10,29,53,12,30,11,44,53,11,30,24,11,53,26,12,48,13,4,10,48,52,56,15,12,47,11,48,11,7,53,24,7,12,26,12,46,13,47,10,46,52,56,15,12,45,10,0,16,15,20,6,1,0,0,0,0,0,0,0,22,10,0,15,15,21,11,1,10,0,16,15,20,33,4,181,1,5,187,1,11,0,1,11,10,1,7,11,39,14,4,56,14,12,32,14,47,56,14,12,50,10,0,15,0,13,4,13,47,10,0,15,5,11,8,10,0,16,1,16,16,20,10,0,16,1,16,17,20,10,0,16,1,16,18,20,11,10,17,109,10,0,16,0,17,126,12,36,14,4,56,14,12,31,14,47,56,14,12,49,11,32,11,31,23,12,33,11,50,11,49,23,12,51,11,2,10,0,15,19,21,10,0,16,0,17,111,10,0,15,20,21,11,47,12,34,13,34,11,4,56,13,1,14,34,56,14,12,35,10,0,15,12,11,3,11,45,11,34,10,5,11,6,17,80,12,38,10,0,16,15,20,12,22,10,0,16,19,20,12,23,10,0,16,20,20,12,24,11,36,12,25,11,43,12,26,11,46,52,12,27,11,5,12,12,10,0,16,12,17,82,12,13,11,42,12,14,11,29,12,15,11,33,11,51,22,12,16,11,35,12,17,11,22,11,23,11,24,11,25,11,27,11,26,11,12,11,13,11,14,11,15,11,16,11,17,18,4,56,16,9,10,0,15,21,21,10,0,16,10,20,6,0,0,0,0,0,0,0,0,33,4,198,2,10,0,16,8,56,14,6,0,0,0,0,0,0,0,0,33,12,18,5,200,2,9,12,18,11,18,4,209,2,11,0,16,9,56,14,6,0,0,0,0,0,0,0,0,33,12,19,5,213,2,11,0,1,9,12,19,11,19,4,216,2,5,218,2,7,10,39,11,38,2,38,3,0,0,6,4,11,0,16,15,20,2,39,3,0,0,6,4,11,0,16,19,20,2,40,3,0,0,6,4,11,0,16,22,20,2,41,3,0,0,6,2,7,3,2,42,3,0,0,6,4,11,0,16,6,20,2,43,3,0,0,6,5,11,0,16,0,11,1,17,128,1,2,44,3,0,0,6,5,11,0,16,0,11,1,17,127,2,45,3,0,0,6,4,11,0,16,0,17,125,2,46,3,0,0,24,18,10,0,16,5,14,1,56,3,4,12,11,0,16,5,14,1,56,17,20,12,2,5,16,11,0,1,56,18,12,2,11,2,2,47,3,0,0,6,4,11,0,16,12,17,82,2,48,3,0,0,6,4,11,0,16,12,17,83,2,49,0,0,0,90,45,13,0,69,91,12,6,13,6,11,0,56,19,11,6,56,2,12,7,14,1,56,20,4,39,11,1,56,21,12,4,13,7,11,4,56,15,12,5,14,7,56,14,6,0,0,0,0,0,0,0,0,36,4,32,11,7,10,2,56,22,11,2,46,17,65,56,23,5,36,11,2,1,11,7,56,24,11,5,12,3,5,43,11,2,1,11,7,12,3,11,3,2,3,3,3,5,1,3,1,4,1,2,3,7,3,14,1,1,3,10,3,11,3,12,3,13,3,4,1,0,3,8,3,0,1,5,1,6,1,7,3,1,3,6,3,9,3,2,0,43,0,111,0],"validator":[161,28,235,11,6,0,0,0,12,1,0,31,2,31,72,3,103,183,4,4,158,5,38,5,196,5,240,3,7,180,9,201,19,8,253,28,96,6,221,29,190,1,10,155,31,156,1,12,183,32,214,27,13,141,60,60,15,201,60,13,0,134,1,1,20,1,23,1,73,1,103,2,21,2,22,2,34,2,71,2,104,2,111,2,131,1,0,101,0,136,1,0,14,4,0,0,13,4,0,0,8,3,0,0,11,3,0,1,9,7,0,3,3,7,1,0,0,4,9,7,0,5,0,12,0,6,1,4,1,0,1,8,2,7,0,9,5,2,0,10,10,2,0,11,12,7,0,12,4,7,0,12,6,8,0,12,7,12,0,13,15,2,0,0,55,0,1,0,0,53,2,3,0,0,26,4,5,0,0,16,4,5,0,0,18,6,5,0,0,86,7,5,0,0,87,7,5,0,0,90,8,5,0,0,89,9,5,0,0,94,9,5,0,0,88,4,5,0,0,93,4,5,0,0,29,10,5,0,0,82,11,5,0,0,46,12,13,0,0,48,12,14,0,0,105,12,15,0,0,49,12,16,0,0,30,12,16,0,0,41,12,17,0,0,83,12,17,0,0,51,12,16,0,0,74,12,16,0,0,79,12,16,0,0,142,1,12,16,0,0,85,12,18,0,0,84,12,18,0,0,52,12,18,0,0,143,1,12,18,0,0,61,12,19,0,0,63,12,19,0,0,64,12,19,0,0,68,12,19,0,0,66,12,20,0,0,65,12,20,0,0,62,12,20,0,0,69,12,20,0,0,72,12,21,0,0,59,12,22,0,0,110,12,22,0,0,98,12,22,0,0,109,12,22,0,0,141,1,12,22,0,0,95,4,5,0,0,75,12,22,0,0,76,12,22,0,0,38,12,22,0,0,25,12,22,0,0,78,23,24,0,0,102,12,25,0,0,42,26,13,0,0,44,27,13,1,0,0,43,28,13,1,0,0,57,11,5,0,0,122,29,5,0,0,120,29,5,0,0,121,29,5,0,0,130,1,29,5,0,0,123,29,5,0,0,113,29,5,0,0,125,29,5,0,0,115,29,5,0,0,126,29,5,0,0,116,29,5,0,0,128,1,29,5,0,0,118,29,5,0,0,127,30,5,0,0,117,30,5,0,0,124,29,5,0,0,114,29,5,0,0,129,1,29,5,0,0,119,29,5,0,0,31,6,5,0,0,132,1,14,5,0,0,133,1,31,5,0,0,54,32,3,0,1,103,31,38,0,2,108,62,31,1,0,3,24,64,62,1,0,3,36,67,51,1,0,3,45,64,13,1,0,3,47,64,13,1,0,3,70,5,34,1,0,3,96,51,34,1,0,4,37,38,35,0,5,53,40,41,0,6,139,1,45,22,1,0,7,32,51,5,1,3,8,40,62,25,1,8,10,33,46,22,0,10,92,46,15,0,11,56,31,39,0,12,17,42,5,0,12,27,42,5,0,12,28,58,5,0,12,46,48,13,0,12,53,40,61,0,12,75,48,22,0,12,76,48,22,0,12,78,60,24,0,12,81,49,5,0,12,82,59,5,0,12,86,47,5,0,12,90,54,22,0,12,97,53,22,0,12,99,53,22,0,12,106,48,22,0,13,57,66,25,0,13,140,1,56,57,0,82,31,82,35,86,44,87,50,87,55,88,61,52,35,52,31,51,35,51,31,80,51,78,51,83,35,83,31,81,35,79,35,81,31,79,31,77,1,14,5,10,2,10,2,10,2,10,2,8,6,8,6,8,12,8,12,8,6,8,6,8,6,8,6,8,7,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,11,1,8,1,2,7,8,1,3,0,1,7,8,1,4,7,8,1,11,8,1,8,10,5,7,8,11,3,7,8,1,8,14,7,8,11,3,7,8,1,8,16,3,2,7,8,1,11,8,1,8,10,2,7,8,1,7,8,11,1,6,8,1,1,1,1,6,8,0,1,5,1,6,8,6,1,6,8,12,1,6,10,2,1,6,11,5,1,8,6,1,6,11,5,1,10,2,1,6,8,9,1,3,2,6,8,1,3,1,8,13,1,8,9,2,6,8,1,6,8,1,2,6,11,5,1,9,0,6,9,0,2,6,11,5,1,9,0,6,11,5,1,9,0,2,7,8,1,10,2,3,7,8,1,10,2,10,2,1,10,2,4,8,0,3,3,7,8,11,22,5,8,6,8,6,8,6,8,6,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,8,6,11,5,1,8,6,10,2,11,5,1,8,6,11,5,1,8,6,8,7,10,2,10,2,10,2,8,6,8,6,8,12,8,12,1,11,5,1,9,0,1,8,6,8,1,1,1,1,1,1,1,8,0,1,2,1,8,4,1,8,12,1,7,8,11,1,8,7,2,7,8,15,3,2,3,3,1,8,10,1,6,11,8,1,9,0,1,6,8,11,5,7,8,15,11,8,1,8,10,5,3,7,8,11,1,6,8,15,1,7,8,15,1,8,2,1,9,0,4,3,3,3,3,1,6,8,14,3,7,8,15,8,14,7,8,11,1,8,3,1,6,8,16,1,6,5,2,7,8,15,11,8,1,8,10,2,7,8,15,7,8,11,2,6,8,15,3,1,8,15,1,6,9,0,29,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,6,11,5,1,9,0,2,1,1,2,5,7,8,11,1,7,11,5,1,9,0,3,8,9,8,15,5,3,66,97,103,7,66,97,108,97,110,99,101,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,19,83,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,21,85,110,115,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,3,85,114,108,9,86,97,108,105,100,97,116,111,114,17,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,8,97,99,116,105,118,97,116,101,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,6,97,109,111,117,110,116,5,97,115,99,105,105,3,98,97,103,7,98,97,108,97,110,99,101,3,98,99,115,6,98,111,114,114,111,119,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,10,100,101,97,99,116,105,118,97,116,101,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,11,100,101,115,99,114,105,112,116,105,111,110,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,5,101,112,111,99,104,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,10,102,114,111,109,95,97,115,99,105,105,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,2,105,100,9,105,109,97,103,101,95,117,114,108,12,105,115,95,100,117,112,108,105,99,97,116,101,13,105,115,95,101,113,117,97,108,95,115,111,109,101,23,105,115,95,101,113,117,97,108,95,115,111,109,101,95,97,110,100,95,118,97,108,117,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,8,109,101,116,97,100,97,116,97,4,110,97,109,101,11,110,101,116,95,97,100,100,114,101,115,115,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,20,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,102,114,111,109,95,109,101,116,97,100,97,116,97,12,110,101,119,95,109,101,116,97,100,97,116,97,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,20,110,101,120,116,95,101,112,111,99,104,95,103,97,115,95,112,114,105,99,101,22,110,101,120,116,95,101,112,111,99,104,95,110,101,116,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,22,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,32,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,16,110,101,120,116,95,101,112,111,99,104,95,115,116,97,107,101,25,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,7,112,111,111,108,95,105,100,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,16,112,114,105,110,99,105,112,97,108,95,97,109,111,117,110,116,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,21,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,13,114,101,119,97,114,100,95,97,109,111,117,110,116,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,111,109,101,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,12,115,116,97,107,101,95,97,109,111,117,110,116,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,14,115,116,97,107,101,114,95,97,100,100,114,101,115,115,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,6,115,116,114,105,110,103,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,11,115,117,105,95,98,97,108,97,110,99,101,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,111,95,98,121,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,10,116,120,95,99,111,110,116,101,120,116,15,117,110,115,116,97,107,105,110,103,95,101,112,111,99,104,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,3,117,114,108,17,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,21,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,95,98,99,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,12,118,111,116,105,110,103,95,112,111,119,101,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,19,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,100,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,3,8,102,0,0,0,0,0,0,0,3,8,208,7,0,0,0,0,0,0,3,8,0,1,0,0,0,0,0,0,3,8,160,134,1,0,0,0,0,0,0,2,22,105,5,85,10,2,52,10,2,143,1,10,2,84,10,2,49,8,6,30,8,6,41,8,12,83,8,12,50,8,6,74,8,6,79,8,6,142,1,8,6,66,11,5,1,10,2,65,11,5,1,10,2,62,11,5,1,10,2,69,11,5,1,10,2,60,11,5,1,8,6,63,11,5,1,8,6,64,11,5,1,8,6,68,11,5,1,8,6,35,8,7,1,2,10,48,8,0,141,1,3,72,8,9,38,3,101,8,15,25,3,67,3,59,3,58,3,35,8,7,2,2,5,77,8,9,135,1,5,100,5,33,3,19,3,3,2,7,77,8,9,135,1,5,100,5,97,3,112,3,80,3,91,3,0,3,0,0,33,68,11,0,12,14,11,1,12,25,11,2,12,29,11,3,12,30,11,4,12,31,11,5,12,32,11,6,12,33,11,7,12,34,11,8,12,35,11,9,12,15,11,10,12,16,11,11,12,17,11,12,12,18,56,0,12,19,56,0,12,20,56,0,12,21,56,0,12,22,56,1,12,23,56,1,12,24,56,1,12,26,56,1,12,27,11,13,12,28,11,14,11,25,11,29,11,30,11,31,11,32,11,33,11,34,11,35,11,15,11,16,11,17,11,18,11,19,11,22,11,20,11,21,11,23,11,24,11,26,11,27,11,28,18,0,2,1,3,0,0,36,137,1,14,9,65,37,7,17,37,4,11,14,10,65,37,7,17,37,12,16,5,13,9,12,16,11,16,4,21,14,11,65,37,7,17,37,12,17,5,23,9,12,17,11,17,4,31,14,12,65,37,7,17,37,12,18,5,33,9,12,18,11,18,4,41,14,5,65,37,7,17,37,12,19,5,43,9,12,19,11,19,4,51,14,6,65,37,7,17,37,12,20,5,53,9,12,20,11,20,4,61,14,7,65,37,7,17,37,12,21,5,63,9,12,21,11,21,4,71,14,8,65,37,7,17,37,12,22,5,73,9,12,22,11,22,4,76,5,80,11,15,1,7,9,39,10,14,7,16,37,4,85,5,89,11,15,1,7,8,39,10,13,7,18,35,4,94,5,98,11,15,1,7,15,39,11,0,11,1,11,2,11,3,11,4,11,5,17,76,17,84,11,6,17,76,17,84,11,7,17,91,11,8,17,91,11,9,17,76,17,84,11,10,17,76,17,84,11,11,17,76,17,84,11,12,17,76,17,84,10,15,17,85,17,0,12,23,14,23,17,73,11,23,11,13,11,14,11,15,17,75,2,2,3,0,0,5,5,11,0,15,0,11,1,17,93,2,3,3,0,0,5,5,11,0,15,0,11,1,17,92,2,4,3,0,0,5,13,10,0,16,1,20,10,0,15,2,21,10,0,16,3,20,11,0,15,4,21,2,5,3,0,0,43,57,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,8,5,14,11,0,1,11,3,1,7,11,39,10,3,46,17,89,6,1,0,0,0,0,0,0,0,22,12,5,10,0,15,0,11,1,10,2,11,5,10,3,17,102,10,0,16,0,17,95,4,34,10,0,15,0,17,100,10,0,16,5,20,10,4,22,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,11,2,11,3,46,17,89,11,4,18,2,56,3,2,6,3,0,0,22,46,10,3,46,17,89,6,0,0,0,0,0,0,0,0,33,4,7,5,13,11,0,1,11,3,1,7,12,39,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,21,5,27,11,0,1,11,3,1,7,11,39,10,0,15,0,11,1,11,2,6,0,0,0,0,0,0,0,0,11,3,17,102,10,0,15,0,17,100,10,0,16,5,20,11,4,22,11,0,15,5,21,2,7,3,0,0,52,43,14,1,17,105,12,3,14,1,17,104,12,5,10,0,15,0,11,1,10,2,17,103,12,6,10,6,10,3,23,12,4,10,0,16,5,20,11,6,23,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,10,2,46,17,90,11,5,11,2,46,17,89,11,3,11,4,18,3,56,4,2,8,3,0,0,5,28,10,2,7,18,35,4,5,5,9,11,0,1,7,15,39,14,1,17,108,20,10,0,16,6,16,7,20,33,4,19,5,23,11,0,1,7,14,39,11,2,11,0,15,1,21,2,9,3,0,0,5,41,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,2,7,18,35,4,14,5,18,11,0,1,7,15,39,14,1,17,108,20,10,0,16,6,16,7,20,33,4,28,5,32,11,0,1,7,14,39,10,2,10,0,15,1,21,11,2,11,0,15,2,21,2,10,3,0,0,5,14,10,1,7,16,37,4,5,5,9,11,0,1,7,8,39,11,1,11,0,15,3,21,2,11,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,1,7,16,37,4,14,5,18,11,0,1,7,8,39,11,1,11,0,15,4,21,2,12,3,0,0,5,14,10,0,16,5,20,14,1,56,2,22,10,0,15,5,21,11,0,15,0,11,1,17,94,2,13,3,0,0,5,16,10,0,15,0,11,1,17,101,10,0,46,17,40,11,0,16,5,20,33,4,13,5,15,7,11,39,2,14,1,0,0,5,4,11,0,16,0,17,95,2,15,1,0,0,5,3,11,0,16,6,2,16,1,0,0,5,5,11,0,16,6,16,7,20,2,17,1,0,0,5,4,11,0,16,6,16,8,2,18,1,0,0,5,4,11,0,16,6,16,9,2,19,1,0,0,5,4,11,0,16,6,16,10,2,20,1,0,0,5,4,11,0,16,6,16,11,2,21,1,0,0,5,4,11,0,16,6,16,12,2,22,1,0,0,5,4,11,0,16,6,16,13,2,23,1,0,0,5,4,11,0,16,6,16,14,2,24,1,0,0,5,4,11,0,16,6,16,15,2,25,1,0,0,5,4,11,0,16,6,16,16,2,26,1,0,0,5,4,11,0,16,6,16,17,2,27,1,0,0,5,4,11,0,16,6,16,18,2,28,1,0,0,5,4,11,0,16,6,16,19,2,29,1,0,0,5,4,11,0,16,6,16,20,2,30,1,0,0,5,4,11,0,16,6,16,21,2,31,1,0,0,5,4,11,0,16,6,16,22,2,32,1,0,0,5,4,11,0,16,6,16,23,2,33,1,0,0,5,4,11,0,16,6,16,24,2,34,1,0,0,5,4,11,0,16,6,16,25,2,35,1,0,0,5,4,11,0,16,6,16,26,2,36,1,0,0,5,4,11,0,16,6,16,27,2,37,1,0,0,5,3,11,0,16,28,2,38,1,0,0,5,4,11,0,16,1,20,2,39,1,0,0,5,5,40,11,0,16,0,17,106,2,40,1,0,0,5,4,11,0,16,0,17,106,2,41,1,0,0,5,3,11,0,17,40,2,42,1,0,0,5,4,11,0,16,29,20,2,43,3,0,0,5,5,11,1,11,0,15,29,21,2,44,1,0,0,5,4,11,0,16,0,17,97,2,45,1,0,0,5,4,11,0,16,0,17,98,2,46,1,0,0,5,4,11,0,16,2,20,2,47,1,0,0,5,4,11,0,16,4,20,2,48,1,0,0,5,5,11,0,16,0,11,1,17,99,2,49,1,0,0,5,4,11,0,16,0,56,5,2,50,1,0,0,63,151,3,10,0,16,6,16,7,20,10,1,16,6,16,7,20,33,4,13,8,12,2,5,23,10,0,16,6,16,8,20,10,1,16,6,16,8,20,33,12,2,11,2,4,28,8,12,13,5,38,10,0,16,6,16,12,20,10,1,16,6,16,12,20,33,12,13,11,13,4,43,8,12,24,5,53,10,0,16,6,16,13,20,10,1,16,6,16,13,20,33,12,24,11,24,4,58,8,12,25,5,68,10,0,16,6,16,16,20,10,1,16,6,16,16,20,33,12,25,11,25,4,73,8,12,26,5,83,10,0,16,6,16,18,20,10,1,16,6,16,18,20,33,12,26,11,26,4,88,8,12,27,5,98,10,0,16,6,16,18,20,10,1,16,6,16,19,20,33,12,27,11,27,4,103,8,12,28,5,113,10,0,16,6,16,19,20,10,1,16,6,16,19,20,33,12,28,11,28,4,118,8,12,29,5,128,1,10,0,16,6,16,19,20,10,1,16,6,16,18,20,33,12,29,11,29,4,133,1,8,12,30,5,141,1,10,0,16,6,16,20,10,1,16,6,16,20,56,6,12,30,11,30,4,146,1,8,12,3,5,154,1,10,0,16,6,16,21,10,1,16,6,16,21,56,6,12,3,11,3,4,159,1,8,12,4,5,167,1,10,0,16,6,16,24,10,1,16,6,16,24,56,7,12,4,11,4,4,172,1,8,12,5,5,180,1,10,0,16,6,16,26,10,1,16,6,16,26,56,7,12,5,11,5,4,185,1,8,12,6,5,193,1,10,0,16,6,16,26,10,1,16,6,16,27,56,7,12,6,11,6,4,198,1,8,12,7,5,206,1,10,0,16,6,16,27,10,1,16,6,16,27,56,7,12,7,11,7,4,211,1,8,12,8,5,219,1,10,0,16,6,16,27,10,1,16,6,16,26,56,7,12,8,11,8,4,224,1,8,12,9,5,232,1,10,0,16,6,16,20,10,1,16,6,16,12,56,8,12,9,11,9,4,237,1,8,12,10,5,245,1,10,0,16,6,16,21,10,1,16,6,16,13,56,8,12,10,11,10,4,250,1,8,12,11,5,130,2,10,0,16,6,16,24,10,1,16,6,16,16,56,9,12,11,11,11,4,135,2,8,12,12,5,143,2,10,0,16,6,16,26,10,1,16,6,16,18,56,9,12,12,11,12,4,148,2,8,12,14,5,156,2,10,0,16,6,16,26,10,1,16,6,16,19,56,9,12,14,11,14,4,161,2,8,12,15,5,169,2,10,0,16,6,16,27,10,1,16,6,16,19,56,9,12,15,11,15,4,174,2,8,12,16,5,182,2,10,0,16,6,16,27,10,1,16,6,16,18,56,9,12,16,11,16,4,187,2,8,12,17,5,195,2,10,1,16,6,16,20,10,0,16,6,16,12,56,8,12,17,11,17,4,200,2,8,12,18,5,208,2,10,1,16,6,16,21,10,0,16,6,16,13,56,8,12,18,11,18,4,213,2,8,12,19,5,221,2,10,1,16,6,16,24,10,0,16,6,16,16,56,9,12,19,11,19,4,226,2,8,12,20,5,234,2,10,1,16,6,16,26,10,0,16,6,16,18,56,9,12,20,11,20,4,239,2,8,12,21,5,247,2,10,1,16,6,16,26,10,0,16,6,16,19,56,9,12,21,11,21,4,252,2,8,12,22,5,132,3,10,1,16,6,16,27,10,0,16,6,16,19,56,9,12,22,11,22,4,141,3,11,0,1,11,1,1,8,12,23,5,149,3,11,1,16,6,16,27,11,0,16,6,16,18,56,9,12,23,11,23,2,51,0,0,0,13,17,10,0,56,10,4,10,11,1,1,11,0,1,9,12,2,5,15,11,0,56,11,11,1,33,12,2,11,2,2,52,0,0,0,65,26,10,0,56,10,4,6,8,12,2,5,9,10,1,56,10,12,2,11,2,4,18,11,1,1,11,0,1,9,12,3,5,24,11,0,56,11,11,1,56,11,33,12,3,11,3,2,53,3,0,0,15,25,10,1,46,17,90,12,2,10,2,10,0,16,6,16,7,20,33,4,12,5,18,11,0,1,11,1,1,7,13,39,11,2,11,1,17,107,11,0,15,28,21,2,54,3,0,0,5,18,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,11,0,15,6,15,8,21,2,55,3,0,0,5,18,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,11,0,15,6,15,9,21,2,56,3,0,0,5,17,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,91,11,0,15,6,15,10,21,2,57,3,0,0,5,17,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,91,11,0,15,6,15,11,21,2,58,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,20,21,11,0,16,6,17,73,2,59,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,12,21,11,0,16,6,17,73,2,60,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,21,21,11,0,16,6,17,73,2,61,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,13,21,11,0,16,6,17,73,2,62,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,22,21,11,0,16,6,17,73,2,63,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,14,21,11,0,16,6,17,73,2,64,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,23,21,11,0,16,6,17,73,2,65,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,15,21,11,0,16,6,17,73,2,66,3,0,0,5,16,11,1,56,13,10,0,15,6,15,24,21,11,2,56,13,10,0,15,6,15,25,21,11,0,16,6,17,73,2,67,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,16,21,11,2,10,0,15,6,15,17,21,11,0,16,6,17,73,2,68,3,0,0,5,10,11,1,56,13,10,0,15,6,15,26,21,11,0,16,6,17,73,2,69,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,18,21,11,0,16,6,17,73,2,70,3,0,0,5,10,11,1,56,13,10,0,15,6,15,27,21,11,0,16,6,17,73,2,71,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,19,21,11,0,16,6,17,73,2,72,3,0,0,5,143,1,10,0,46,17,29,56,14,4,18,10,0,15,6,15,20,56,15,10,0,15,6,15,12,21,56,1,10,0,15,6,15,20,21,10,0,46,17,30,56,14,4,36,10,0,15,6,15,21,56,15,10,0,15,6,15,13,21,56,1,10,0,15,6,15,21,21,10,0,46,17,31,56,14,4,54,10,0,15,6,15,22,56,15,10,0,15,6,15,14,21,56,1,10,0,15,6,15,22,21,10,0,46,17,32,56,14,4,72,10,0,15,6,15,23,56,15,10,0,15,6,15,15,21,56,1,10,0,15,6,15,23,21,10,0,46,17,33,56,16,4,103,10,0,15,6,15,24,56,17,10,0,15,6,15,16,21,56,0,10,0,15,6,15,24,21,10,0,15,6,15,25,56,17,10,0,15,6,15,17,21,56,0,10,0,15,6,15,25,21,10,0,46,17,35,56,16,4,121,10,0,15,6,15,26,56,17,10,0,15,6,15,18,21,56,0,10,0,15,6,15,26,21,10,0,46,17,36,56,16,4,140,1,10,0,15,6,15,27,56,17,10,0,15,6,15,19,21,56,0,11,0,15,6,15,27,21,5,142,1,11,0,1,2,73,1,0,0,5,4,11,0,56,18,17,74,2,74,1,2,0,75,0,0,0,68,24,14,0,16,7,20,12,6,10,3,17,96,12,5,11,6,10,3,17,107,12,4,11,0,6,0,0,0,0,0,0,0,0,11,4,10,1,11,5,10,2,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,17,85,18,1,2,1,4,1,7,1,3,1,8,1,5,1,6,1,0,0,0,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,1,0,4,0,2,0,3,0,17,0,18,0,19,0,20,0,13,0,14,0,15,0,16,1,2,1,1,0,39,0,107,0,137,1,0,138,1,0,141,1,0],"validator_cap":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,20,3,28,42,4,70,4,5,74,54,7,128,1,226,2,8,226,3,64,6,162,4,34,10,196,4,13,12,209,4,112,13,193,5,4,15,197,5,6,0,18,1,10,1,14,1,15,0,3,12,0,0,4,2,0,1,0,7,0,1,2,4,0,3,1,2,0,0,16,0,1,0,0,20,2,1,0,0,9,3,4,0,0,8,0,5,0,1,6,13,4,1,8,1,7,10,11,0,2,11,14,6,1,12,3,12,8,9,0,4,12,6,12,1,6,8,0,1,6,5,1,6,8,1,2,5,7,8,4,1,8,2,1,8,1,0,4,1,8,0,8,2,5,1,6,8,4,1,5,1,7,8,4,1,8,3,1,8,0,1,6,9,0,2,9,0,5,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,28,97,117,116,104,111,114,105,122,101,114,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,6,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,3,5,5,1,2,1,5,5,0,3,0,0,6,3,11,0,16,0,2,1,3,0,0,6,3,11,0,16,1,2,2,3,0,0,7,35,10,1,46,17,7,12,5,10,5,7,0,33,4,11,8,12,2,5,15,11,5,10,0,33,12,2,11,2,4,18,5,22,11,1,1,6,0,0,0,0,0,0,0,0,39,11,1,17,5,10,0,18,0,12,3,14,3,56,0,12,4,11,3,11,0,56,1,11,4,2,3,3,0,0,6,5,11,0,16,0,20,18,1,2,0,1,1,0,0,13,0,17,0,19,0],"validator_set":[161,28,235,11,6,0,0,0,12,1,0,51,2,51,112,3,163,1,134,6,4,169,7,133,1,5,174,8,210,9,7,128,18,183,23,8,183,41,96,6,151,42,195,1,10,218,43,141,1,12,231,44,251,34,13,226,79,16,15,242,79,5,0,159,1,1,103,1,167,1,2,30,2,31,2,57,2,101,2,113,2,141,1,2,145,1,2,146,1,2,152,1,2,165,1,2,166,1,0,137,1,0,155,1,0,158,1,0,163,1,0,170,1,0,19,4,0,0,14,3,0,0,15,3,0,0,16,3,0,0,17,3,0,1,4,7,1,0,0,3,0,12,0,4,1,4,1,0,1,6,3,7,0,7,2,6,1,2,0,7,6,6,1,2,0,8,7,2,0,9,9,12,2,7,1,4,1,10,10,4,1,4,1,11,11,2,0,12,21,7,2,1,0,0,0,13,22,7,1,3,0,14,5,7,0,14,8,8,0,15,13,4,0,16,12,12,0,16,18,2,0,17,20,4,0,0,96,0,1,0,0,124,2,3,0,0,126,4,3,0,0,123,5,3,0,0,28,6,3,0,0,125,4,3,0,0,122,7,3,0,0,128,1,8,3,0,0,127,9,3,0,0,27,10,3,0,0,154,1,11,3,0,0,52,12,3,0,0,47,13,14,0,0,149,1,13,14,0,0,162,1,15,14,0,0,160,1,15,14,0,0,161,1,15,16,0,0,139,1,13,17,0,0,99,13,14,0,0,81,15,18,0,0,84,6,18,0,0,83,19,18,0,0,43,19,14,0,0,85,6,18,0,0,42,20,14,0,0,68,21,22,0,0,60,23,24,0,0,61,25,24,0,0,71,26,27,0,0,72,28,22,0,0,65,29,22,0,0,75,30,22,0,0,73,31,22,0,0,74,31,22,0,0,76,23,32,0,0,66,33,32,0,0,67,15,32,0,0,70,15,32,0,0,169,1,34,35,0,0,114,36,3,0,0,117,37,3,0,0,35,38,3,0,0,116,39,3,0,0,133,1,40,3,0,0,115,41,3,0,0,34,42,14,0,0,26,43,3,0,0,38,44,45,0,0,39,46,47,0,0,40,48,49,0,0,37,50,49,0,0,51,51,3,0,0,54,52,3,0,0,144,1,26,14,0,0,24,13,42,0,0,90,15,18,0,0,87,53,18,0,1,49,111,81,1,0,1,59,80,81,1,0,1,89,79,18,1,0,1,100,3,111,1,0,1,132,1,81,111,1,0,2,41,82,18,1,0,2,86,125,18,1,0,2,121,97,81,1,0,3,96,56,66,0,4,50,148,1,3,1,0,4,92,149,1,14,1,0,4,134,1,147,1,148,1,1,0,4,164,1,84,14,1,0,5,53,81,3,1,3,6,77,110,16,1,8,7,96,103,104,1,2,7,97,101,102,1,2,7,112,105,101,1,2,9,25,60,3,2,7,4,9,32,68,87,2,7,4,9,33,73,89,2,7,4,9,41,68,18,2,7,4,9,96,56,57,2,7,4,9,121,73,74,2,7,4,10,32,109,110,1,4,10,33,114,115,1,4,10,55,56,61,1,4,10,86,106,18,1,4,10,94,106,14,1,4,10,111,135,1,81,1,4,10,118,77,3,1,4,11,56,72,14,0,11,129,1,72,59,0,12,41,93,18,2,1,0,12,55,3,65,2,1,0,12,64,93,87,2,1,0,12,69,94,89,2,1,0,12,79,96,3,2,1,0,12,86,130,1,18,2,1,0,12,93,130,1,131,1,2,1,0,12,110,142,1,95,2,1,0,12,121,94,95,2,1,0,12,131,1,130,1,14,2,1,0,13,41,132,1,18,1,3,13,80,143,1,131,1,1,3,13,86,134,1,18,1,3,13,121,133,1,3,1,3,14,106,86,16,0,15,23,75,3,0,15,26,22,3,0,15,36,32,14,0,15,45,75,3,0,15,46,150,1,3,0,15,52,22,3,0,15,62,32,14,0,15,82,108,18,0,15,88,32,18,0,15,102,32,123,0,15,109,152,1,153,1,0,15,115,138,1,3,0,15,122,85,3,0,15,127,75,3,0,15,128,1,88,3,0,15,136,1,32,14,0,15,138,1,32,16,0,15,142,1,32,59,0,15,150,1,32,14,0,15,170,1,32,14,0,16,98,121,35,0,16,153,1,121,117,0,16,168,1,116,117,0,17,44,69,70,0,17,48,70,58,0,17,95,90,22,0,18,119,3,14,0,18,130,1,43,3,0,18,151,1,3,14,0,79,55,75,55,83,58,79,62,79,63,91,64,78,63,75,63,80,63,80,55,75,62,87,58,59,14,58,14,62,14,69,83,78,55,76,55,78,62,77,62,90,64,98,64,93,64,94,64,64,58,73,14,72,14,74,14,85,58,81,58,77,63,61,14,60,14,57,14,82,58,71,122,63,14,70,127,90,129,1,98,129,1,96,129,1,93,129,1,100,59,103,59,102,59,84,58,86,58,70,136,1,91,98,94,98,95,129,1,97,129,1,101,59,99,98,90,98,92,98,68,83,67,83,66,83,92,129,1,62,59,70,154,1,2,10,8,19,7,8,14,1,8,0,3,7,8,0,8,19,7,8,14,0,2,7,8,0,7,8,14,3,7,8,0,3,7,8,14,2,6,8,0,6,8,19,4,7,8,0,5,11,7,1,8,11,7,8,14,3,7,8,0,8,18,7,8,14,3,7,8,0,3,6,8,14,9,7,8,0,7,11,7,1,8,11,7,11,7,1,8,11,7,11,15,2,5,11,16,1,5,3,3,3,3,7,8,14,6,7,8,0,3,3,3,7,11,15,2,5,11,16,1,5,7,8,14,1,7,8,0,1,6,8,0,1,3,2,6,8,0,5,1,8,8,1,6,11,12,2,8,8,5,1,1,2,6,10,8,19,6,8,19,2,6,11,13,1,8,19,6,8,19,2,7,8,0,5,1,7,8,19,2,6,10,8,19,5,1,11,5,1,3,2,6,11,13,1,8,19,5,2,6,10,8,19,6,10,5,1,10,3,2,7,10,8,19,5,3,7,8,0,5,1,3,7,8,0,6,8,21,1,2,7,8,0,6,8,14,1,6,8,19,3,7,8,0,5,2,3,7,8,0,6,8,20,2,1,8,21,3,7,8,0,7,11,15,2,5,11,16,1,5,7,8,14,5,7,8,0,8,19,7,11,15,2,5,11,16,1,5,1,7,8,14,2,7,11,15,2,5,11,16,1,5,5,2,7,8,0,3,1,7,10,3,2,7,10,8,19,7,8,14,1,6,10,8,19,1,7,10,8,19,4,10,3,3,6,10,3,6,10,3,4,3,11,15,2,3,3,3,11,15,2,3,3,2,6,8,0,11,15,2,5,11,16,1,5,1,10,5,4,6,10,8,19,3,3,3,2,10,3,10,3,9,6,10,8,19,3,3,10,3,10,3,3,11,15,2,3,3,3,11,15,2,3,3,6,7,10,8,19,6,10,3,6,10,3,7,11,7,1,8,11,7,11,7,1,8,11,7,8,14,6,3,6,10,8,19,6,10,3,6,10,3,6,11,15,2,5,11,16,1,5,6,10,5,2,6,8,0,8,8,6,3,3,11,12,2,8,8,5,3,6,8,19,8,0,2,8,8,5,1,7,8,14,1,11,12,2,9,0,9,1,1,8,19,1,5,3,7,11,12,2,9,0,9,1,9,0,9,1,1,11,13,1,9,0,2,8,8,8,22,2,5,8,22,2,5,3,1,11,15,2,9,0,9,1,1,8,6,4,6,8,19,6,8,19,1,5,2,6,11,12,2,9,0,9,1,9,0,2,8,19,7,8,14,1,8,22,3,8,8,8,19,5,1,6,8,14,2,7,11,12,2,9,0,9,1,9,0,1,9,1,2,7,8,19,3,5,6,8,19,6,8,19,1,8,19,5,2,7,11,13,1,9,0,9,0,3,5,3,11,5,1,3,1,6,11,5,1,9,0,1,7,11,5,1,9,0,1,9,0,2,6,10,9,0,6,9,0,1,8,11,1,6,11,7,1,9,0,4,7,8,19,11,7,1,8,11,5,7,8,14,1,6,8,18,1,6,9,1,3,7,8,19,8,18,7,8,14,1,7,9,1,1,7,8,22,14,11,15,2,5,11,16,1,5,6,10,5,10,3,10,3,11,15,2,3,3,11,15,2,3,3,3,10,5,3,3,3,3,10,3,10,3,8,3,3,7,3,3,8,19,8,19,5,6,8,19,2,6,11,15,2,9,0,9,1,6,9,0,2,7,11,15,2,9,0,9,1,6,9,0,2,9,0,9,1,3,7,11,15,2,9,0,9,1,9,0,9,1,2,7,10,9,0,3,2,3,3,10,10,11,9,1,3,3,3,11,10,1,3,3,3,3,3,6,8,19,6,10,8,19,1,11,9,1,3,2,3,9,0,1,11,9,1,9,0,1,10,11,9,1,9,0,1,11,10,1,9,0,1,7,11,10,1,9,0,1,6,11,13,1,9,0,3,3,3,3,2,6,8,19,6,8,19,2,6,11,13,1,9,0,3,1,6,9,0,1,11,5,1,9,0,5,5,3,11,5,1,3,3,10,3,4,3,3,11,5,1,3,11,5,1,3,2,7,11,13,1,9,0,3,1,7,9,0,1,6,8,21,1,6,5,2,3,11,5,1,3,6,1,1,3,3,11,5,1,3,11,5,1,3,5,5,6,8,19,8,8,5,6,8,19,1,6,8,20,1,8,20,1,6,8,8,2,3,8,19,1,6,10,9,0,3,3,5,8,8,1,8,4,7,6,5,6,5,3,3,6,5,10,5,7,11,16,1,5,2,5,11,16,1,5,1,6,11,15,2,9,0,9,1,1,10,9,0,2,6,11,16,1,9,0,6,9,0,2,7,11,16,1,9,0,6,9,0,1,6,11,16,1,9,0,1,7,11,13,1,9,0,1,8,3,6,3,3,3,3,3,3,2,7,8,19,7,8,14,4,3,3,3,6,8,19,7,11,15,2,3,3,11,15,2,3,3,4,4,3,3,3,5,10,5,6,10,8,19,11,16,1,5,10,5,5,1,7,11,15,2,9,0,9,1,1,11,16,1,9,0,6,3,3,4,10,3,10,3,3,17,3,3,3,10,3,3,10,3,3,4,3,3,3,3,3,3,3,3,4,8,3,3,11,7,1,8,11,3,7,8,19,5,4,11,7,1,8,11,2,7,11,7,1,9,0,3,1,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,2,7,8,19,11,7,1,8,11,8,10,5,3,3,3,3,10,5,6,8,19,5,2,6,8,19,3,1,8,17,1,8,2,3,66,97,103,7,66,97,108,97,110,99,101,5,69,110,116,114,121,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,13,80,114,105,111,114,105,116,121,81,117,101,117,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,23,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,25,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,86,50,18,86,97,108,105,100,97,116,111,114,74,111,105,110,69,118,101,110,116,19,86,97,108,105,100,97,116,111,114,76,101,97,118,101,69,118,101,110,116,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,6,86,101,99,77,97,112,6,86,101,99,83,101,116,8,97,99,116,105,118,97,116,101,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,3,97,100,100,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,18,97,116,95,114,105,115,107,95,118,97,108,105,100,97,116,111,114,115,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,22,99,97,108,99,117,108,97,116,101,95,116,111,116,97,108,95,115,116,97,107,101,115,38,99,108,101,97,110,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,95,108,101,97,118,105,110,103,95,118,97,108,105,100,97,116,111,114,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,36,99,111,109,112,117,116,101,95,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,26,99,111,109,112,117,116,101,95,114,101,119,97,114,100,95,97,100,106,117,115,116,109,101,110,116,115,26,99,111,109,112,117,116,101,95,115,108,97,115,104,101,100,95,118,97,108,105,100,97,116,111,114,115,38,99,111,109,112,117,116,101,95,117,110,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,8,99,111,110,116,97,105,110,115,25,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,116,97,98,108,101,118,101,99,20,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,118,101,99,9,99,114,101,97,116,101,95,118,49,10,100,101,97,99,116,105,118,97,116,101,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,17,100,105,115,116,114,105,98,117,116,101,95,114,101,119,97,114,100,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,27,101,109,105,116,95,118,97,108,105,100,97,116,111,114,95,101,112,111,99,104,95,101,118,101,110,116,115,5,101,109,112,116,121,5,101,112,111,99,104,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,14,102,105,110,100,95,118,97,108,105,100,97,116,111,114,29,102,105,110,100,95,118,97,108,105,100,97,116,111,114,95,102,114,111,109,95,116,97,98,108,101,95,118,101,99,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,3,103,101,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,24,103,101,116,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,37,103,101,116,95,99,97,110,100,105,100,97,116,101,95,111,114,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,7,103,101,116,95,109,117,116,25,103,101,116,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,95,114,101,102,21,103,101,116,95,118,97,108,105,100,97,116,111,114,95,105,110,100,105,99,101,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,114,101,102,2,105,100,19,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,12,105,115,95,100,117,112,108,105,99,97,116,101,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,34,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,35,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,21,105,115,95,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,22,105,115,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,12,105,115,95,118,111,108,117,110,116,97,114,121,4,106,111,105,110,4,107,101,121,115,6,108,101,110,103,116,104,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,25,112,101,110,100,105,110,103,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,16,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,7,112,111,111,108,95,105,100,19,112,111,111,108,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,24,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,3,112,111,112,8,112,111,112,95,98,97,99,107,7,112,111,112,95,109,97,120,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,24,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,26,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,115,27,112,114,111,99,101,115,115,95,118,97,108,105,100,97,116,111,114,95,100,101,112,97,114,116,117,114,101,9,112,117,115,104,95,98,97,99,107,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,26,114,101,102,101,114,101,110,99,101,95,103,97,115,95,115,117,114,118,101,121,95,113,117,111,116,101,6,114,101,109,111,118,101,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,6,115,101,110,100,101,114,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,105,122,101,4,115,111,109,101,17,115,111,114,116,95,114,101,109,111,118,97,108,95,108,105,115,116,5,115,112,108,105,116,5,115,116,97,107,101,12,115,116,97,107,101,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,27,115,116,111,114,97,103,101,95,102,117,110,100,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,29,115,117,109,95,118,111,116,105,110,103,95,112,111,119,101,114,95,98,121,95,97,100,100,114,101,115,115,101,115,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,26,116,97,108,108,121,105,110,103,95,114,117,108,101,95,103,108,111,98,97,108,95,115,99,111,114,101,23,116,97,108,108,121,105,110,103,95,114,117,108,101,95,114,101,112,111,114,116,101,114,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,39,117,112,100,97,116,101,95,97,110,100,95,112,114,111,99,101,115,115,95,108,111,119,95,115,116,97,107,101,95,100,101,112,97,114,116,117,114,101,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,20,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,10,3,1,0,10,5,1,0,0,2,9,149,1,3,24,10,8,19,104,11,13,1,8,19,105,10,3,139,1,11,12,2,8,8,5,78,11,12,2,8,8,8,22,157,1,11,12,2,5,8,22,29,11,15,2,5,3,58,8,6,1,2,10,56,3,156,1,5,120,3,135,1,3,36,3,107,3,140,1,3,108,8,17,148,1,10,5,147,1,3,2,2,11,56,3,156,1,5,120,3,135,1,3,170,1,3,36,3,107,3,140,1,3,108,8,17,148,1,10,5,147,1,3,3,2,3,56,3,156,1,5,138,1,8,8,4,2,4,56,3,156,1,5,138,1,8,8,91,1,0,3,0,0,54,51,14,0,17,45,12,5,10,1,56,0,12,4,14,0,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,16,14,0,10,2,66,58,12,6,13,4,10,6,17,121,11,6,17,122,56,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,11,5,11,0,10,1,56,2,64,14,0,0,0,0,0,0,0,0,11,4,10,1,56,3,10,1,56,4,56,5,11,1,17,65,18,0,12,7,13,7,15,0,17,132,1,11,7,2,1,3,0,0,67,69,10,0,14,1,12,3,46,11,3,17,20,32,4,17,10,0,14,1,12,4,46,11,4,17,23,32,12,5,5,19,9,12,5,11,5,4,22,5,28,11,0,1,11,2,1,7,7,39,14,1,17,122,12,6,10,0,16,1,10,6,56,6,32,4,38,5,44,11,0,1,11,2,1,7,11,39,14,1,17,113,4,48,5,54,11,0,1,11,2,1,7,12,39,10,0,15,2,14,1,17,121,11,6,56,1,11,0,15,1,14,1,17,122,11,1,11,2,17,128,1,56,7,2,2,3,0,0,71,53,10,1,46,17,89,12,4,10,0,16,1,10,4,56,6,4,10,5,16,11,0,1,11,1,1,7,13,39,10,0,15,1,11,4,56,8,17,129,1,12,3,14,3,17,113,4,26,5,32,11,0,1,11,1,1,7,12,39,14,3,17,121,12,2,10,0,15,2,10,2,56,9,1,13,3,10,1,46,17,88,17,108,11,0,15,3,11,2,11,3,11,1,17,128,1,56,10,2,3,3,0,0,76,69,11,2,46,17,89,12,7,10,0,16,1,10,7,56,6,4,10,5,14,11,0,1,7,13,39,10,0,15,1,11,7,56,8,17,129,1,12,6,10,0,14,6,12,3,46,11,3,17,20,32,4,37,10,0,14,6,12,4,46,11,4,17,23,32,12,5,5,39,9,12,5,11,5,4,42,5,46,11,0,1,7,7,39,14,6,17,113,4,50,5,54,11,0,1,7,12,39,14,6,17,123,11,1,38,4,60,5,64,11,0,1,7,10,39,11,0,15,4,11,6,56,11,2,4,3,0,0,3,16,10,0,16,0,10,1,17,22,11,0,16,4,11,1,17,24,22,6,1,0,0,0,0,0,0,0,33,4,13,5,15,7,7,39,2,5,3,0,0,78,36,11,1,46,17,89,12,2,10,0,16,0,11,2,17,26,12,4,14,4,56,12,4,13,5,17,11,0,1,7,9,39,13,4,56,13,12,3,10,0,16,5,14,3,56,14,32,4,27,5,31,11,0,1,7,16,39,11,0,15,5,11,3,68,14,2,6,3,0,0,3,22,14,2,56,15,7,4,38,4,6,5,12,11,0,1,11,3,1,7,15,39,11,0,11,1,17,25,11,2,10,3,46,17,89,11,3,17,117,2,7,3,0,0,55,43,14,1,17,104,12,3,10,0,16,2,10,3,56,16,4,22,10,0,16,2,14,1,17,104,56,17,20,12,4,11,0,11,4,17,25,11,1,11,2,17,119,5,42,10,0,16,3,10,3,56,18,4,28,5,34,11,0,1,11,2,1,7,8,39,11,0,15,3,11,3,56,19,17,130,1,11,1,11,2,17,119,2,8,3,0,0,59,10,11,2,17,89,12,3,11,0,15,0,11,3,17,29,11,1,17,118,2,9,3,0,0,91,110,10,8,46,17,88,6,1,0,0,0,0,0,0,0,22,12,15,17,133,1,12,20,10,0,16,0,10,20,10,1,46,56,15,10,2,46,56,15,17,49,12,22,12,21,10,0,10,3,20,12,9,46,11,9,17,48,12,16,10,0,16,0,14,16,17,53,12,17,10,0,16,0,14,16,17,28,11,4,14,21,14,22,17,47,12,14,12,19,12,13,12,18,10,0,16,0,11,20,11,17,11,21,11,22,11,18,11,13,11,19,11,14,17,50,12,12,12,11,10,0,15,0,14,11,14,12,11,1,11,2,10,8,17,51,10,0,15,0,17,46,10,0,15,0,10,8,17,44,10,15,10,0,16,0,14,11,14,12,10,3,14,16,12,10,46,11,10,17,52,10,0,11,15,17,42,10,0,10,3,10,8,17,39,10,0,11,5,11,6,11,7,11,3,11,8,17,10,10,0,16,0,17,45,10,0,15,6,21,10,0,15,0,17,132,1,11,0,17,11,2,10,0,0,0,92,106,10,0,16,0,65,58,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,99,5,9,11,7,6,1,0,0,0,0,0,0,0,23,12,7,10,0,16,0,10,7,66,58,12,13,10,13,17,122,12,12,11,13,17,123,12,9,10,9,10,1,38,4,40,10,0,16,7,14,12,56,20,4,39,10,0,15,7,14,12,56,21,1,1,5,98,11,9,10,2,38,4,87,10,0,16,7,14,12,56,20,4,64,10,0,15,7,14,12,56,22,12,8,10,8,20,6,1,0,0,0,0,0,0,0,22,10,8,21,11,8,20,12,6,5,71,10,0,15,7,11,12,6,1,0,0,0,0,0,0,0,56,23,6,1,0,0,0,0,0,0,0,12,6,11,6,10,3,36,4,86,10,0,15,0,10,7,56,24,12,10,10,0,11,10,10,4,9,10,5,17,40,5,98,10,0,15,0,10,7,56,24,12,11,10,0,11,11,10,4,9,10,5,17,40,5,4,11,4,1,11,0,1,11,5,1,2,11,0,0,0,98,24,10,0,16,0,65,58,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,21,5,11,10,0,15,0,10,1,67,58,17,110,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,12,1,0,0,99,60,11,0,16,0,12,10,10,10,65,58,12,3,64,100,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,15,10,10,10,2,66,58,12,9,13,1,10,9,17,111,11,9,17,124,56,25,68,100,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,10,11,10,1,11,1,56,26,12,4,6,0,0,0,0,0,0,0,0,12,7,17,133,1,17,131,1,23,12,8,6,0,0,0,0,0,0,0,0,12,5,10,7,10,8,35,4,58,5,49,13,4,56,27,12,6,12,5,11,7,11,6,22,12,7,5,44,11,5,2,13,1,0,0,3,4,11,0,16,6,20,2,14,1,0,0,3,6,11,0,16,0,11,1,17,34,17,123,2,15,1,0,0,3,6,11,0,16,0,11,1,17,34,17,120,2,16,1,0,0,3,6,11,0,16,0,11,1,17,34,17,121,2,17,1,0,0,3,3,11,0,16,2,2,18,3,0,0,3,12,10,0,16,0,65,58,10,0,16,5,65,14,23,11,0,16,4,56,28,22,2,19,3,0,0,24,8,11,0,16,0,11,1,17,26,12,2,14,2,56,12,2,20,0,0,0,3,5,11,0,16,0,11,1,17,21,2,21,3,0,0,3,6,11,0,11,1,17,22,6,0,0,0,0,0,0,0,0,36,2,22,0,0,0,107,33,10,0,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,66,58,10,1,17,112,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,23,0,0,0,3,7,11,0,16,4,11,1,17,24,6,0,0,0,0,0,0,0,0,36,2,24,0,0,0,107,33,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,56,29,10,1,17,112,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,25,0,0,0,3,16,10,0,16,1,10,1,56,6,4,11,11,0,15,1,11,1,56,30,17,130,1,2,11,0,15,0,11,1,17,29,2,26,0,0,0,98,31,10,0,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,66,58,17,122,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,27,0,0,0,98,31,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,56,29,17,122,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,28,0,0,0,112,46,10,1,65,59,12,5,6,0,0,0,0,0,0,0,0,12,3,7,20,12,6,10,3,10,5,35,4,40,5,12,10,1,10,3,66,59,20,12,2,10,0,11,2,17,26,12,4,14,4,56,12,4,25,5,31,11,0,1,11,1,1,7,9,39,13,6,11,4,56,33,68,14,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,0,1,11,1,1,11,6,2,29,3,0,0,78,22,10,0,11,1,12,2,46,11,2,17,26,12,4,14,4,56,12,4,11,5,15,11,0,1,7,9,39,13,4,56,13,12,3,11,0,11,3,67,58,2,30,0,0,0,113,45,10,0,16,0,10,1,17,26,12,5,14,5,56,12,4,16,13,5,56,13,12,3,11,0,15,0,11,3,67,58,2,10,0,16,4,10,1,17,27,12,6,14,6,56,12,4,32,13,6,56,13,12,4,11,0,15,4,11,4,56,34,2,11,2,4,35,5,39,11,0,1,7,14,39,11,0,15,1,11,1,56,30,17,130,1,2,31,3,0,0,3,7,11,0,11,1,17,127,20,11,2,17,30,2,32,3,0,0,59,8,11,1,17,89,12,2,11,0,11,2,9,17,30,2,33,3,0,0,59,8,11,1,17,89,12,2,11,0,11,2,8,17,30,2,34,0,0,0,118,19,10,0,11,1,17,26,12,3,14,3,56,12,4,8,5,12,11,0,1,7,9,39,13,3,56,13,12,2,11,0,11,2,66,58,2,35,3,0,0,119,57,10,0,16,0,10,1,17,26,12,7,14,7,56,12,4,11,8,12,3,5,15,10,2,7,0,33,12,3,11,3,4,25,13,7,56,13,12,5,11,0,16,0,11,5,66,58,2,10,0,16,4,10,1,17,27,12,8,14,8,56,12,4,36,8,12,4,5,40,11,2,7,1,33,12,4,11,4,4,50,13,8,56,13,12,6,11,0,16,4,11,6,56,29,2,11,0,15,1,11,1,56,30,17,130,1,46,2,36,1,0,0,118,21,10,0,16,0,11,1,17,26,12,3,14,3,56,12,4,9,5,13,11,0,1,7,9,39,13,3,56,13,12,2,11,0,16,0,11,2,66,58,2,37,1,0,0,118,21,10,0,16,4,11,1,17,27,12,3,14,3,56,12,4,9,5,13,11,0,1,7,17,39,13,3,56,13,12,2,11,0,16,4,11,2,56,29,2,38,3,0,0,120,39,10,1,17,126,20,12,6,10,2,7,0,33,4,16,11,0,11,6,12,3,46,11,3,17,36,12,4,5,21,11,0,11,6,11,2,17,35,12,4,11,4,12,7,10,1,56,35,12,5,11,7,17,114,14,5,33,4,32,5,36,11,1,1,7,19,39,11,1,17,125,2,39,0,0,0,124,32,10,0,15,5,17,43,10,0,16,5,56,36,32,4,25,5,9,10,0,15,5,69,14,12,3,10,0,15,0,11,3,56,24,12,4,10,0,11,4,10,1,8,10,2,17,40,5,3,11,1,1,11,0,1,11,2,1,2,40,0,0,0,126,58,10,4,46,17,88,6,1,0,0,0,0,0,0,0,22,12,5,14,1,17,122,12,6,14,1,17,121,12,7,10,0,15,2,10,7,56,9,1,10,0,16,7,14,6,56,20,4,28,10,0,15,7,14,6,56,21,1,1,10,0,16,6,20,14,1,17,123,23,10,0,15,6,21,11,2,10,6,17,41,10,5,11,6,14,1,17,121,11,3,18,4,56,37,13,1,11,5,17,108,11,0,15,3,11,7,11,1,11,4,17,128,1,56,10,2,41,0,0,0,128,1,69,10,0,14,1,12,2,46,11,2,56,38,4,12,10,0,14,1,56,39,1,1,10,0,46,56,40,12,7,14,7,65,59,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,66,5,26,14,7,10,4,66,59,12,6,10,0,10,6,56,41,12,8,10,8,14,1,12,3,46,11,3,56,42,4,57,10,8,14,1,56,43,11,8,46,56,44,4,54,10,0,11,6,56,39,1,1,5,56,11,6,1,5,61,11,8,1,11,6,1,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,21,11,0,1,2,42,0,0,0,58,28,10,0,16,4,56,45,32,4,25,5,6,10,0,15,4,56,46,12,2,13,2,10,1,17,105,10,1,14,2,17,122,14,2,17,121,18,3,56,47,10,0,15,0,11,2,68,58,5,0,11,0,1,2,43,0,0,0,137,1,57,10,0,46,65,14,12,6,6,1,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,54,5,11,10,0,10,4,12,1,46,11,1,66,14,20,12,3,10,4,12,5,10,5,6,0,0,0,0,0,0,0,0,36,4,49,5,26,11,5,6,1,0,0,0,0,0,0,0,23,12,5,10,0,10,5,12,2,46,11,2,66,14,20,10,3,36,4,41,5,42,5,49,10,0,10,5,10,5,6,1,0,0,0,0,0,0,0,22,71,14,5,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,1,2,44,0,0,0,98,26,10,0,46,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,21,5,11,10,0,10,2,67,58,10,1,17,116,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,11,1,1,2,45,0,0,0,139,1,30,6,0,0,0,0,0,0,0,0,12,3,10,0,65,58,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,26,5,12,10,0,10,1,66,58,12,4,11,3,11,4,17,123,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,46,0,0,0,98,23,10,0,46,65,58,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,20,5,11,10,0,10,1,67,58,17,106,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,47,0,0,0,140,1,69,6,0,0,0,0,0,0,0,0,12,8,56,48,12,4,6,0,0,0,0,0,0,0,0,12,9,56,48,12,5,13,0,46,56,36,32,4,60,5,14,13,0,69,14,12,10,10,2,10,10,66,14,20,53,10,1,53,24,7,3,26,12,6,13,4,10,10,10,6,52,56,49,11,8,11,6,52,22,12,8,10,3,10,10,66,14,20,53,10,1,53,24,7,3,26,12,7,13,5,11,10,10,7,52,56,49,11,9,11,7,52,22,12,9,5,8,11,3,1,11,2,1,11,8,11,4,11,9,11,5,2,48,0,0,0,141,1,40,7,21,12,5,14,1,56,50,32,4,36,5,7,13,1,56,51,12,4,12,6,10,0,10,6,17,19,4,16,5,20,11,0,1,7,5,39,10,0,16,0,12,3,11,4,56,52,12,2,11,3,14,2,17,53,17,131,1,38,4,35,13,5,11,6,68,59,5,2,11,0,1,11,5,2,49,0,0,0,144,1,47,64,14,0,0,0,0,0,0,0,0,12,7,64,14,0,0,0,0,0,0,0,0,12,8,10,0,65,58,12,5,11,3,10,5,26,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,42,5,18,10,0,10,4,66,58,17,124,53,10,2,53,24,10,1,53,26,12,6,13,7,11,6,52,68,14,13,8,10,9,68,14,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,13,11,0,1,11,7,11,8,2,50,0,0,0,145,1,108,11,1,11,2,23,12,22,64,14,0,0,0,0,0,0,0,0,12,12,64,14,0,0,0,0,0,0,0,0,12,14,10,0,65,58,12,20,10,20,14,6,56,53,23,12,21,6,0,0,0,0,0,0,0,0,12,19,10,19,10,20,35,4,103,5,23,10,0,10,19,66,58,17,124,53,12,25,14,3,10,19,66,14,20,12,23,14,6,14,19,56,54,4,48,14,6,14,19,56,55,20,12,15,11,23,11,15,23,12,9,5,61,10,5,53,11,25,24,10,22,53,26,12,16,11,23,11,16,52,22,12,9,11,9,12,11,13,12,11,11,68,14,14,4,10,19,66,14,20,12,24,14,8,14,19,56,54,4,85,14,8,14,19,56,55,20,12,17,11,24,11,17,23,12,10,5,93,10,7,10,21,26,12,18,11,24,11,18,22,12,10,11,10,12,13,13,14,11,13,68,14,11,19,6,1,0,0,0,0,0,0,0,22,12,19,5,18,11,0,1,11,12,11,14,2,51,0,0,0,146,1,105,10,0,46,65,58,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,9,5,23,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,7,18,39,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,92,5,30,10,0,10,6,67,58,12,10,10,1,10,6,66,14,20,12,9,10,3,10,9,56,56,12,8,11,9,53,10,10,46,17,107,53,24,7,3,26,12,12,13,8,11,12,52,56,56,12,13,13,13,10,4,10,2,10,6,66,14,20,56,56,56,57,1,14,13,56,15,6,0,0,0,0,0,0,0,0,36,4,82,10,10,46,17,122,12,11,10,10,11,13,11,11,10,5,17,117,5,84,11,13,56,58,11,10,11,8,17,109,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,25,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,2,52,0,0,0,151,1,84,10,1,65,58,12,9,6,0,0,0,0,0,0,0,0,12,8,10,8,10,9,35,4,73,5,10,10,1,10,8,66,58,12,12,10,12,17,122,12,13,10,4,14,13,56,38,4,28,10,4,14,13,56,59,20,56,52,12,6,5,30,7,21,12,6,11,6,12,11,10,5,14,13,56,60,4,39,6,0,0,0,0,0,0,0,0,12,7,5,41,6,1,0,0,0,0,0,0,0,12,7,11,7,12,10,10,0,11,13,10,12,17,111,10,12,17,123,10,12,17,124,10,12,17,107,10,2,10,8,66,14,20,10,3,10,8,66,14,20,11,12,10,0,17,115,11,11,11,10,18,2,56,61,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,5,11,1,1,11,3,1,11,5,1,11,4,1,11,2,1,2,53,1,0,0,139,1,35,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,1,65,59,12,3,10,2,10,3,35,4,29,5,12,10,0,10,1,10,2,66,59,20,17,34,12,5,11,4,11,5,17,124,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,54,1,0,0,3,3,11,0,16,0,2,55,1,0,0,3,5,11,0,16,1,11,1,56,6,2,56,1,0,0,3,5,11,0,16,3,11,1,56,18,2,0,1,0,6,0,4,0,5,0,2,0,3,0,0,0,7,0,63,0,143,1,0],"validator_wrapper":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,16,3,24,48,4,72,6,5,78,52,7,130,1,211,1,8,213,2,64,6,149,3,10,10,159,3,6,12,165,3,100,13,137,4,2,15,139,4,2,0,14,1,10,1,16,0,12,0,2,4,0,1,0,2,0,2,3,12,0,3,1,4,0,0,5,0,1,0,0,8,2,3,0,0,6,1,4,0,0,11,2,5,0,0,15,6,7,0,2,4,8,9,1,4,2,6,9,12,1,4,2,9,10,11,1,4,2,15,13,7,0,5,4,7,4,6,4,2,8,3,7,8,1,1,8,0,1,7,8,0,1,7,8,3,1,8,3,0,1,6,8,0,1,3,3,3,9,0,7,8,1,1,8,2,1,7,8,2,1,7,9,0,1,9,0,1,6,8,2,9,84,120,67,111,110,116,101,120,116,9,86,97,108,105,100,97,116,111,114,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,9,86,101,114,115,105,111,110,101,100,6,99,114,101,97,116,101,9,99,114,101,97,116,101,95,118,49,7,100,101,115,116,114,111,121,5,105,110,110,101,114,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,10,116,120,95,99,111,110,116,101,120,116,17,117,112,103,114,97,100,101,95,116,111,95,108,97,116,101,115,116,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,1,7,8,2,0,3,0,0,5,6,6,1,0,0,0,0,0,0,0,11,0,11,1,56,0,18,0,2,1,3,0,0,5,6,10,0,17,3,11,0,15,0,56,1,2,2,3,0,0,5,6,13,0,17,3,11,0,19,0,56,2,2,3,0,0,0,5,10,11,0,46,17,4,6,1,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,2,4,0,0,0,5,4,11,0,16,0,17,8,2,0,0,0,13,0],"voting_power":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,87,4,107,4,5,111,134,1,7,245,1,176,2,8,165,4,96,6,133,5,70,10,203,5,16,12,219,5,254,6,13,217,12,4,15,221,12,2,0,22,1,21,2,9,0,18,0,1,2,0,0,2,2,0,3,0,4,0,0,13,0,1,0,0,6,2,3,0,0,15,4,5,0,0,7,6,1,0,0,3,7,1,0,0,17,8,1,0,0,4,4,1,0,0,16,1,5,0,0,12,1,5,0,1,7,17,1,1,0,1,8,19,20,1,0,2,5,11,5,0,2,10,11,5,0,2,11,11,5,0,3,13,21,1,0,3,15,14,5,0,3,22,14,5,0,9,13,10,13,1,7,10,8,2,0,2,6,10,8,2,3,2,10,8,1,3,1,6,10,8,2,1,3,2,7,10,8,1,8,1,3,7,10,8,1,3,3,2,7,10,8,2,10,8,1,4,3,10,8,1,3,3,1,8,2,2,3,3,8,3,8,1,3,10,8,1,3,3,3,3,1,8,1,1,6,8,2,3,3,3,3,4,3,1,3,3,3,7,10,9,0,9,0,3,7,1,3,3,3,3,3,7,8,1,1,6,10,9,0,1,1,2,7,8,2,3,12,3,3,3,3,3,3,3,3,3,6,8,2,6,8,2,3,9,86,97,108,105,100,97,116,111,114,15,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,17,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,86,50,19,97,100,106,117,115,116,95,118,111,116,105,110,103,95,112,111,119,101,114,16,99,104,101,99,107,95,105,110,118,97,114,105,97,110,116,115,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,22,105,110,105,116,95,118,111,116,105,110,103,95,112,111,119,101,114,95,105,110,102,111,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,4,109,97,116,104,3,109,97,120,3,109,105,110,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,5,115,116,97,107,101,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,19,117,112,100,97,116,101,95,118,111,116,105,110,103,95,112,111,119,101,114,9,118,97,108,105,100,97,116,111,114,15,118,97,108,105,100,97,116,111,114,95,105,110,100,101,120,13,118,97,108,105,100,97,116,111,114,95,115,101,116,6,118,101,99,116,111,114,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,16,39,0,0,0,0,0,0,3,8,11,26,0,0,0,0,0,0,3,8,232,3,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,2,19,3,22,3,1,2,3,19,3,22,3,14,3,0,3,0,0,9,29,7,0,7,2,7,0,10,0,46,65,10,17,11,17,12,17,13,12,4,10,0,10,4,12,1,46,11,1,17,1,12,3,12,2,13,2,11,4,11,3,17,4,10,0,11,2,17,5,11,0,46,17,6,2,1,0,0,0,12,58,10,0,17,2,12,8,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,7,64,13,0,0,0,0,0,0,0,0,12,5,10,2,10,4,35,4,51,5,17,10,0,10,2,66,10,17,15,12,6,10,6,53,7,0,53,24,10,8,53,26,52,10,1,17,13,12,9,10,2,10,9,11,6,18,1,12,3,13,5,11,3,17,3,11,7,11,9,22,12,7,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,0,1,11,5,7,0,11,7,23,2,2,0,0,0,15,28,6,0,0,0,0,0,0,0,0,12,1,10,0,65,10,12,2,6,0,0,0,0,0,0,0,0,12,3,10,1,10,2,35,4,24,5,12,11,3,10,0,10,1,66,10,17,15,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,3,0,0,0,16,39,6,0,0,0,0,0,0,0,0,12,4,10,0,46,65,13,12,5,10,4,10,5,35,4,25,5,11,10,0,10,4,12,2,46,11,2,66,13,16,0,20,14,1,16,0,20,36,12,3,5,27,9,12,3,11,3,4,34,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,11,1,11,4,56,0,2,4,0,0,0,18,84,6,0,0,0,0,0,0,0,0,12,5,10,0,46,65,13,12,6,10,5,10,6,35,4,16,5,11,10,2,6,0,0,0,0,0,0,0,0,36,12,3,5,18,9,12,3,11,3,4,74,10,0,10,5,67,13,12,9,10,2,10,6,10,5,23,17,11,12,7,10,1,10,9,16,1,20,11,7,22,17,13,12,8,10,2,11,8,10,9,16,1,20,23,17,13,12,4,10,9,16,1,20,10,4,22,10,9,15,1,21,11,9,16,1,20,10,1,37,4,61,5,65,11,0,1,7,5,39,11,2,11,4,23,12,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,6,11,0,1,11,2,6,0,0,0,0,0,0,0,0,33,4,81,5,83,7,3,39,2,5,0,0,0,11,22,14,1,56,1,32,4,17,5,5,13,1,69,13,19,1,1,12,3,12,2,10,0,11,2,67,10,11,3,17,14,5,0,11,0,1,11,1,70,13,0,0,0,0,0,0,0,0,2,6,0,0,0,22,119,6,0,0,0,0,0,0,0,0,12,3,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,9,10,3,10,4,35,4,35,5,12,10,0,10,3,66,10,17,16,12,12,10,12,6,0,0,0,0,0,0,0,0,36,4,22,5,26,11,0,1,7,6,39,11,9,11,12,22,12,9,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,9,7,0,33,4,40,5,44,11,0,1,7,3,39,6,0,0,0,0,0,0,0,0,12,1,10,1,10,4,35,4,116,5,51,10,1,6,1,0,0,0,0,0,0,0,22,12,2,10,2,10,4,35,4,111,5,60,10,0,10,1,66,10,12,10,10,0,10,2,66,10,12,11,10,10,17,15,12,7,10,11,17,15,12,8,11,10,17,16,12,5,11,11,17,16,12,6,10,7,10,8,36,4,93,10,5,10,6,38,4,89,5,93,11,0,1,7,4,39,11,7,11,8,35,4,106,11,5,11,6,37,4,102,5,106,11,0,1,7,4,39,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,55,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,46,11,0,1,2,7,1,0,0,1,2,7,0,2,8,1,0,0,1,2,7,1,2,1,2,1,1,0,20,0]},"type_origin_table":[{"module_name":"validator_cap","struct_name":"UnverifiedValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_cap","struct_name":"ValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakingPool","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"PoolTokenExchangeRate","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakedIota","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"ValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"Validator","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"StakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"UnstakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfo","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfoV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_wrapper","struct_name":"ValidatorWrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorSet","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEventV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorJoinEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorLeaveEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"storage_fund","struct_name":"StorageFund","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"stake_subsidy","struct_name":"StakeSubsidy","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"SystemParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"SystemParametersV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"IotaSystemStateInner","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"IotaSystemStateInnerV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"SystemEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system","struct_name":"IotaSystemState","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisChainParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenDistributionSchedule","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenAllocation","package":"0x0000000000000000000000000000000000000000000000000000000000000003"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"DdYtSHED8qYakCvtPiThXfbiSHFJpFGJkYpbYfohRxxh","storage_rebate":0},{"data":{"Package":{"id":"0x000000000000000000000000000000000000000000000000000000000000dee9","version":5,"module_map":{"clob":[161,28,235,11,6,0,0,0,13,1,0,36,2,36,134,1,3,170,1,204,4,4,246,5,184,1,5,174,7,241,9,7,159,17,135,15,8,166,32,96,6,134,33,147,2,10,153,35,226,1,11,251,36,8,12,131,37,235,39,13,238,76,40,14,150,77,26,0,45,0,53,0,54,0,94,1,107,1,137,1,2,28,2,46,2,47,2,65,2,85,2,105,2,126,2,129,1,2,135,1,2,136,1,0,16,7,0,0,14,7,2,0,1,0,1,0,10,7,2,0,1,0,1,0,12,7,2,0,1,0,1,0,9,6,0,0,19,4,0,0,15,8,2,0,1,0,1,0,13,7,2,0,1,0,1,0,11,7,2,0,1,0,1,1,4,4,1,4,0,2,0,12,0,2,5,12,1,0,1,4,8,7,1,0,0,5,21,7,0,6,1,4,1,0,1,7,2,8,0,8,3,12,1,0,1,10,7,12,2,7,0,4,1,11,6,7,0,11,22,4,0,12,17,2,0,13,18,12,2,7,1,4,1,15,20,2,0,0,60,0,1,0,0,49,2,3,0,0,51,4,1,2,0,0,0,50,5,1,2,0,0,0,57,6,1,2,0,0,0,58,7,1,2,0,0,0,146,1,8,9,2,0,0,0,147,1,8,10,2,0,0,0,127,11,12,2,0,0,0,128,1,13,12,2,0,0,0,93,14,15,2,0,0,0,92,14,15,2,0,0,0,91,16,15,2,0,0,0,112,17,18,2,0,0,0,78,19,20,2,0,0,0,111,21,22,2,0,0,0,109,20,23,0,0,63,24,1,2,0,0,0,64,25,1,2,0,0,0,44,26,1,2,0,0,0,123,27,28,2,0,0,0,43,29,1,2,0,0,0,36,30,1,2,0,0,0,86,31,32,2,0,0,0,24,31,33,2,0,0,0,74,34,35,2,0,0,0,73,34,35,2,0,0,0,72,36,20,2,0,0,0,75,37,38,2,0,0,1,39,84,60,1,4,1,40,84,60,1,4,1,42,71,72,1,4,1,67,84,20,1,4,1,68,84,78,1,4,1,79,91,20,1,4,1,82,70,23,1,4,1,95,70,46,1,4,1,96,70,46,1,4,1,100,2,50,1,4,1,104,84,46,1,4,1,114,84,46,1,4,1,122,71,43,1,4,2,23,97,20,1,0,2,24,97,46,1,0,2,55,90,54,1,0,2,56,77,54,1,0,2,77,62,1,1,0,2,87,90,1,1,0,2,97,2,3,0,2,100,2,53,1,0,2,139,1,77,1,1,0,2,145,1,63,9,1,0,3,61,46,78,0,3,98,46,20,0,3,99,46,78,0,3,140,1,46,78,0,3,141,1,46,20,0,3,142,1,46,78,0,4,38,74,60,1,0,4,83,74,23,1,0,5,71,1,44,1,0,6,84,80,20,1,0,6,125,79,54,1,0,6,144,1,67,20,1,0,6,148,1,1,54,1,0,7,133,1,66,20,0,8,69,68,9,1,0,8,80,9,54,1,0,8,84,88,1,1,0,8,144,1,59,20,1,0,9,62,43,1,1,3,10,27,73,74,2,7,4,10,38,75,76,2,7,4,10,41,83,82,2,7,4,10,48,75,23,2,7,4,10,59,41,1,2,7,4,10,70,73,74,2,7,4,10,82,73,23,2,7,4,10,100,2,41,2,7,4,10,101,75,74,2,7,4,10,116,92,1,2,7,4,10,121,83,45,2,7,4,11,76,60,61,1,8,11,100,2,47,0,11,138,1,48,49,0,13,25,95,1,2,7,4,13,38,94,76,2,7,4,13,41,81,82,2,7,4,13,48,94,23,2,7,4,13,100,2,52,2,7,4,14,124,43,1,1,8,75,40,60,43,60,45,38,0,89,51,49,43,49,45,64,43,64,45,90,56,70,57,69,58,67,58,2,55,69,43,82,3,67,43,46,43,69,45,67,45,46,45,51,43,51,45,13,55,10,55,63,43,66,43,66,45,35,0,37,0,31,0,76,40,58,20,77,40,72,40,50,43,17,55,45,43,62,45,61,45,61,43,18,55,79,40,59,20,87,51,81,46,81,40,73,40,39,0,41,0,33,0,36,0,50,45,45,45,62,43,40,0,11,55,68,43,12,55,68,45,47,45,47,43,78,40,34,0,80,40,70,93,88,51,78,46,85,51,80,46,42,45,44,45,63,45,44,43,14,55,70,98,70,99,74,46,72,46,20,55,29,0,74,40,77,46,71,46,86,51,76,46,30,0,79,46,43,43,43,45,32,0,27,55,1,8,5,0,1,7,8,22,1,8,10,6,3,3,3,3,11,14,1,8,20,7,8,22,4,3,3,11,16,1,8,20,7,8,22,3,7,11,6,2,9,0,9,1,11,16,1,9,0,6,8,10,3,7,11,6,2,9,0,9,1,11,16,1,9,1,6,8,10,4,7,11,6,2,9,0,9,1,3,6,8,10,7,8,22,1,11,16,1,9,0,1,11,16,1,9,1,6,7,11,6,2,9,0,9,1,3,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,3,11,16,1,9,0,11,16,1,9,1,3,5,7,11,6,2,9,0,9,1,3,6,8,15,11,16,1,9,1,7,8,22,5,7,11,6,2,9,0,9,1,3,3,3,11,14,1,9,1,2,11,14,1,9,0,11,14,1,9,1,4,7,11,6,2,9,0,9,1,3,3,11,14,1,9,0,7,7,11,6,2,9,0,9,1,3,1,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,2,11,16,1,9,0,11,16,1,9,1,7,7,11,6,2,9,0,9,1,3,3,1,3,6,8,10,7,8,22,1,3,9,7,11,6,2,9,0,9,1,3,3,1,3,2,6,8,15,6,8,10,7,8,22,4,3,3,1,3,1,1,2,8,18,6,8,4,5,8,18,6,8,4,3,3,3,3,7,11,6,2,9,0,9,1,3,6,8,10,5,7,11,9,1,8,5,7,11,17,2,3,3,3,3,8,18,1,8,4,2,7,11,6,2,9,0,9,1,6,8,10,3,7,11,6,2,9,0,9,1,10,3,6,8,10,2,6,11,6,2,9,0,9,1,6,8,10,1,10,8,4,4,3,3,3,3,4,6,11,6,2,9,0,9,1,3,3,6,8,15,2,10,3,10,3,3,6,11,9,1,8,5,3,3,3,6,11,6,2,9,0,9,1,3,6,8,10,1,6,8,4,1,11,17,2,3,8,4,2,3,8,4,1,11,17,2,9,0,9,1,4,8,13,8,18,8,19,8,13,1,9,0,1,8,13,1,9,1,2,3,3,1,8,19,1,6,8,19,1,6,8,18,1,11,9,1,9,0,2,8,18,11,17,2,3,3,1,11,21,2,9,0,9,1,1,11,11,1,9,0,1,11,14,1,9,0,2,9,0,9,1,1,11,6,2,9,0,9,1,1,8,0,1,8,20,1,6,11,16,1,9,0,1,6,9,0,1,8,18,3,7,11,11,1,9,0,8,18,11,14,1,9,0,4,7,11,11,1,9,0,3,6,8,10,7,8,22,4,3,11,16,1,9,0,11,16,1,9,1,3,3,11,14,1,9,0,11,14,1,9,1,3,1,6,8,15,1,6,11,14,1,9,0,2,11,14,1,9,0,7,8,22,28,1,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,11,14,1,9,1,1,3,3,1,3,7,8,5,3,1,6,11,9,1,9,0,2,7,11,9,1,9,0,3,1,7,9,0,1,6,11,17,2,9,0,9,1,1,6,11,12,1,9,0,2,6,11,17,2,9,0,9,1,9,0,1,6,9,1,3,7,11,11,1,9,0,8,18,3,2,1,3,2,7,11,14,1,9,0,3,2,7,11,14,1,9,0,11,14,1,9,0,2,7,11,21,2,9,0,9,1,9,0,1,7,9,1,2,7,11,17,2,9,0,9,1,9,0,2,6,11,9,1,9,0,3,26,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,27,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,1,3,6,8,4,7,8,4,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,3,11,14,1,9,0,11,14,1,9,1,11,14,1,9,1,2,7,11,16,1,9,0,11,16,1,9,0,7,3,7,11,9,1,8,5,8,4,3,3,3,8,18,3,7,11,11,1,9,0,6,8,10,3,3,7,11,9,1,9,0,3,9,0,3,7,11,17,2,9,0,9,1,9,0,9,1,1,11,1,2,9,0,9,1,2,6,11,21,2,9,0,9,1,9,0,3,7,11,21,2,9,0,9,1,9,0,9,1,11,11,14,1,9,0,11,14,1,9,0,11,14,1,9,0,3,3,11,14,1,9,1,11,14,1,9,1,11,14,1,9,1,3,3,8,18,2,6,11,11,1,9,0,8,18,1,11,2,2,9,0,9,1,1,11,3,2,9,0,9,1,11,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,1,8,4,3,3,8,18,7,11,17,2,3,3,3,3,7,8,5,8,4,13,3,7,11,9,1,8,5,3,3,1,7,11,9,1,8,5,8,4,3,3,8,18,3,8,18,7,11,17,2,3,3,17,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,3,1,3,3,3,8,4,3,8,18,3,3,8,18,7,11,17,2,3,3,7,6,8,5,10,8,4,6,8,4,6,11,12,1,3,3,8,18,6,11,17,2,3,3,5,3,3,3,3,8,18,6,3,10,3,3,3,3,10,3,4,3,6,8,4,6,11,12,1,3,6,11,17,2,3,8,4,4,6,11,9,1,8,5,3,8,18,6,11,17,2,3,3,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,11,67,114,105,116,98,105,116,84,114,101,101,9,67,117,115,116,111,100,105,97,110,2,73,68,11,76,105,110,107,101,100,84,97,98,108,101,6,79,112,116,105,111,110,5,79,114,100,101,114,13,79,114,100,101,114,67,97,110,99,101,108,101,100,11,79,114,100,101,114,70,105,108,108,101,100,13,79,114,100,101,114,70,105,108,108,101,100,86,50,11,79,114,100,101,114,80,108,97,99,101,100,13,79,114,100,101,114,80,108,97,99,101,100,86,50,4,80,111,111,108,11,80,111,111,108,67,114,101,97,116,101,100,3,83,85,73,5,84,97,98,108,101,9,84,105,99,107,76,101,118,101,108,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,3,97,100,100,4,97,115,107,115,4,98,97,99,107,7,98,97,108,97,110,99,101,10,98,97,115,101,95,97,115,115,101,116,28,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,99,97,110,99,101,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,102,105,108,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,112,108,97,99,101,100,29,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,114,101,109,97,105,110,105,110,103,23,98,97,115,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,14,98,97,115,101,95,99,117,115,116,111,100,105,97,110,18,98,97,116,99,104,95,99,97,110,99,101,108,95,111,114,100,101,114,4,98,105,100,115,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,17,99,97,110,99,101,108,95,97,108,108,95,111,114,100,101,114,115,12,99,97,110,99,101,108,95,111,114,100,101,114,4,99,108,111,98,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,14,99,114,101,97,116,101,95,97,99,99,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,12,99,114,101,97,116,101,95,112,111,111,108,95,12,99,114,101,97,116,105,111,110,95,102,101,101,7,99,114,105,116,98,105,116,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,100,101,112,111,115,105,116,95,98,97,115,101,13,100,101,112,111,115,105,116,95,113,117,111,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,19,100,101,115,116,114,111,121,95,101,109,112,116,121,95,108,101,118,101,108,9,100,105,118,95,114,111,117,110,100,4,101,109,105,116,19,101,109,105,116,95,111,114,100,101,114,95,99,97,110,99,101,108,101,100,17,101,109,105,116,95,111,114,100,101,114,95,102,105,108,108,101,100,5,101,118,101,110,116,16,101,120,112,105,114,101,95,116,105,109,101,115,116,97,109,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,12,102,114,111,109,95,98,97,108,97,110,99,101,5,102,114,111,110,116,3,103,101,116,22,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,97,115,107,95,115,105,100,101,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,98,105,100,95,115,105,100,101,16,103,101,116,95,111,114,100,101,114,95,115,116,97,116,117,115,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,18,105,110,106,101,99,116,95,108,105,109,105,116,95,111,114,100,101,114,11,105,110,115,101,114,116,95,108,101,97,102,12,105,110,116,111,95,98,97,108,97,110,99,101,6,105,115,95,98,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,4,106,111,105,110,12,108,105,110,107,101,100,95,116,97,98,108,101,16,108,105,115,116,95,111,112,101,110,95,111,114,100,101,114,115,12,108,111,99,107,95,98,97,108,97,110,99,101,8,108,111,116,95,115,105,122,101,17,109,97,107,101,114,95,114,101,98,97,116,101,95,114,97,116,101,13,109,97,107,101,114,95,114,101,98,97,116,101,115,9,109,97,116,99,104,95,97,115,107,9,109,97,116,99,104,95,98,105,100,29,109,97,116,99,104,95,98,105,100,95,119,105,116,104,95,113,117,111,116,101,95,113,117,97,110,116,105,116,121,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,109,117,108,9,109,117,108,95,114,111,117,110,100,3,110,101,119,4,110,101,120,116,17,110,101,120,116,95,97,115,107,95,111,114,100,101,114,95,105,100,17,110,101,120,116,95,98,105,100,95,111,114,100,101,114,95,105,100,9,110,101,120,116,95,108,101,97,102,6,111,98,106,101,99,116,11,111,112,101,110,95,111,114,100,101,114,115,6,111,112,116,105,111,110,8,111,114,100,101,114,95,105,100,12,111,114,100,101,114,95,105,115,95,98,105,100,5,111,119,110,101,114,17,112,108,97,99,101,95,108,105,109,105,116,95,111,114,100,101,114,18,112,108,97,99,101,95,109,97,114,107,101,116,95,111,114,100,101,114,7,112,111,111,108,95,105,100,13,112,114,101,118,105,111,117,115,95,108,101,97,102,5,112,114,105,99,101,9,112,117,115,104,95,98,97,99,107,8,113,117,97,110,116,105,116,121,11,113,117,111,116,101,95,97,115,115,101,116,24,113,117,111,116,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,15,113,117,111,116,101,95,99,117,115,116,111,100,105,97,110,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,12,114,101,109,111,118,101,95,111,114,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,3,115,117,105,25,115,119,97,112,95,101,120,97,99,116,95,98,97,115,101,95,102,111,114,95,113,117,111,116,101,25,115,119,97,112,95,101,120,97,99,116,95,113,117,111,116,101,95,102,111,114,95,98,97,115,101,5,116,97,98,108,101,16,116,97,107,101,114,95,99,111,109,109,105,115,115,105,111,110,14,116,97,107,101,114,95,102,101,101,95,114,97,116,101,9,116,105,99,107,95,115,105,122,101,12,116,105,109,101,115,116,97,109,112,95,109,115,14,116,111,116,97,108,95,113,117,97,110,116,105,116,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,16,117,110,115,97,102,101,95,100,105,118,95,114,111,117,110,100,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,15,117,115,114,95,111,112,101,110,95,111,114,100,101,114,115,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,13,119,105,116,104,100,114,97,119,95,98,97,115,101,14,119,105,116,104,100,114,97,119,95,113,117,111,116,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,3,8,19,0,0,0,0,0,0,0,3,8,20,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,2,1,4,2,1,0,2,1,1,2,1,2,2,1,3,3,8,0,0,0,0,0,0,0,128,3,8,0,0,0,0,0,0,0,0,3,8,64,75,76,0,0,0,0,0,3,8,160,37,38,0,0,0,0,0,3,8,0,232,118,72,23,0,0,0,0,2,7,113,8,18,29,8,13,118,8,13,131,1,3,89,3,132,1,3,88,3,1,2,7,113,8,18,108,3,81,1,110,8,18,32,3,115,3,66,3,2,2,6,113,8,18,108,3,81,1,110,8,18,30,3,115,3,3,2,10,113,8,18,108,3,81,1,110,8,18,134,1,3,31,3,33,3,115,3,130,1,3,90,3,4,2,6,108,3,115,3,117,3,81,1,110,8,18,66,3,5,2,2,115,3,106,11,17,2,3,8,4,6,2,15,76,8,19,37,11,9,1,8,5,26,11,9,1,8,5,103,3,102,3,143,1,11,21,2,8,18,11,17,2,3,3,131,1,3,89,3,132,1,3,88,3,35,11,11,1,9,0,120,11,11,1,9,1,52,11,14,1,8,20,34,11,14,1,9,0,119,11,14,1,9,1,7,2,6,113,8,18,108,3,81,1,110,8,18,32,3,115,3,8,2,8,113,8,18,108,3,81,1,110,8,18,134,1,3,31,3,33,3,115,3,6,55,1,55,2,55,3,55,0,0,0,0,39,7,11,0,19,5,12,1,1,11,1,56,0,2,1,1,0,0,1,3,11,0,17,48,2,2,0,0,0,42,72,56,1,12,6,56,2,12,9,10,3,10,2,17,56,6,0,0,0,0,0,0,0,0,36,4,11,5,15,11,5,1,7,19,39,10,6,10,9,34,4,20,5,24,11,5,1,7,15,39,10,0,10,1,38,4,29,5,33,11,5,1,7,1,39,10,5,17,83,12,8,14,8,17,84,20,12,7,11,8,10,5,56,3,10,5,56,3,7,0,7,26,10,5,56,4,10,0,10,1,10,2,10,3,10,5,56,5,11,5,56,6,11,4,56,7,56,8,57,0,56,9,11,7,11,6,11,9,11,0,11,1,11,2,11,3,18,0,56,10,2,3,1,0,0,1,19,14,2,56,11,7,30,33,4,6,5,10,11,3,1,7,17,39,7,28,7,29,11,0,11,1,11,2,56,12,11,3,56,13,2,4,1,0,0,1,20,14,1,56,14,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,6,39,11,0,54,0,11,2,56,15,11,1,56,16,56,17,2,5,1,0,0,1,20,14,1,56,18,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,7,39,11,0,54,1,11,2,56,15,11,1,56,19,56,20,2,6,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,11,0,54,0,11,1,11,2,11,3,56,21,2,7,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,11,0,54,1,11,1,11,2,11,3,56,22,2,8,1,0,0,64,49,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,5,1,11,4,1,7,5,39,14,2,56,14,10,1,38,4,19,5,27,11,0,1,11,5,1,11,4,1,7,6,39,14,3,56,18,12,6,11,0,11,1,9,11,2,11,3,11,4,11,5,56,23,12,8,12,7,14,8,56,18,12,9,11,7,11,8,11,9,11,6,23,2,9,1,0,0,65,48,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,4,1,11,2,1,7,5,39,14,3,56,18,10,1,38,4,19,5,27,11,0,1,11,4,1,11,2,1,7,7,39,11,0,11,1,7,26,11,2,17,65,11,3,56,19,56,24,12,6,12,5,14,5,56,25,12,7,11,5,10,4,56,26,11,6,11,4,56,27,11,7,2,10,0,0,0,69,215,2,10,0,55,2,17,84,20,12,23,11,1,12,28,56,7,12,10,11,4,12,25,10,0,54,3,12,9,10,9,46,56,28,4,25,11,0,1,11,9,1,11,10,11,25,2,10,9,46,56,29,12,30,12,32,9,12,29,10,9,46,56,28,32,4,43,5,38,10,32,10,2,37,12,5,5,45,9,12,5,11,5,4,212,2,10,9,10,30,56,30,12,31,10,31,16,4,56,31,56,32,20,12,22,10,31,16,4,56,33,32,4,180,2,5,63,10,31,16,4,10,22,56,34,12,16,10,16,16,5,20,12,15,9,12,26,10,16,16,6,20,10,3,37,4,95,8,12,26,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,35,10,23,10,16,56,36,5,249,1,10,15,10,16,16,8,20,17,54,12,18,4,106,11,18,6,1,0,0,0,0,0,0,0,22,12,18,11,18,7,20,10,0,55,4,20,22,17,54,12,18,4,119,11,18,6,1,0,0,0,0,0,0,0,22,12,18,10,28,10,18,38,4,137,1,11,18,12,12,10,12,7,20,10,0,55,4,20,22,17,52,12,13,1,10,15,12,11,5,186,1,8,12,29,10,28,7,20,10,0,55,4,20,22,17,55,12,13,1,11,13,10,16,16,8,20,17,55,12,11,1,11,11,10,0,55,5,20,26,10,0,55,5,20,24,12,11,10,11,10,16,16,8,20,17,56,12,13,10,13,10,0,55,4,20,17,57,12,27,4,182,1,11,27,6,1,0,0,0,0,0,0,0,22,12,27,10,13,11,27,22,12,12,10,13,10,0,55,6,20,17,56,12,19,11,15,10,11,23,12,15,11,28,10,12,23,12,28,10,28,6,0,0,0,0,0,0,0,0,33,4,206,1,8,12,29,10,0,54,0,10,16,16,7,20,10,11,56,37,12,14,13,25,10,12,56,38,12,24,10,0,54,1,10,16,16,7,20,13,24,10,19,10,13,22,56,38,56,20,10,0,54,7,11,24,56,39,1,13,10,11,14,56,40,1,10,0,55,2,17,84,20,10,16,11,11,11,12,11,13,23,11,19,56,41,11,26,4,254,1,8,12,6,5,130,2,10,15,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,165,2,10,22,12,21,10,31,16,4,10,22,56,42,12,20,10,20,56,43,32,4,148,2,11,20,56,32,20,12,22,5,150,2,11,20,1,10,0,54,8,11,16,16,7,20,56,44,10,21,56,45,1,10,31,15,4,11,21,56,46,1,5,176,2,11,16,1,10,31,15,4,10,22,56,47,12,17,11,15,11,17,15,5,21,10,29,4,179,2,5,180,2,5,57,11,31,16,4,56,33,4,204,2,10,9,11,32,12,7,46,11,7,56,48,1,12,32,10,9,11,30,56,49,17,0,10,9,10,32,12,8,46,11,8,56,50,12,30,1,10,29,4,211,2,11,0,1,11,9,1,5,212,2,5,32,11,10,11,25,2,11,0,0,0,85,153,2,10,0,55,2,17,84,20,12,22,11,1,12,25,56,7,12,11,11,4,12,23,10,0,54,3,12,10,10,10,46,56,28,4,25,11,0,1,11,10,1,11,11,11,23,2,10,10,46,56,29,12,28,12,30,10,10,46,56,28,32,4,41,5,36,10,30,10,2,37,12,5,5,43,9,12,5,11,5,4,150,2,10,10,10,28,56,30,12,29,10,29,16,4,56,31,56,32,20,12,21,10,29,16,4,56,33,32,4,244,1,5,61,10,29,16,4,10,21,56,34,12,16,10,16,16,5,20,12,15,9,12,24,10,16,16,6,20,10,3,37,4,93,8,12,24,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,35,10,22,10,16,56,36,5,183,1,10,25,10,15,36,4,100,10,15,12,6,5,102,10,25,12,6,11,6,12,12,10,12,10,16,16,8,20,17,53,12,13,10,13,10,0,55,6,20,17,56,12,18,10,13,10,0,55,4,20,17,57,12,26,4,127,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,15,10,12,23,12,15,11,25,10,12,23,12,25,10,0,54,0,10,16,16,7,20,10,12,56,37,12,14,13,23,10,26,56,38,12,27,10,0,54,1,10,16,16,7,20,13,27,10,18,56,38,56,20,10,0,54,7,11,27,56,39,1,13,11,11,14,56,40,1,10,0,54,1,10,16,16,7,20,13,23,11,13,56,38,56,20,10,0,55,2,17,84,20,10,16,11,12,11,26,11,18,56,41,11,24,4,188,1,8,12,7,5,192,1,10,15,6,0,0,0,0,0,0,0,0,33,12,7,11,7,4,227,1,10,21,12,20,10,29,16,4,10,21,56,42,12,19,10,19,56,43,32,4,210,1,11,19,56,32,20,12,21,5,212,1,11,19,1,10,0,54,8,11,16,16,7,20,56,44,10,20,56,45,1,10,29,15,4,11,20,56,46,1,5,238,1,11,16,1,10,29,15,4,10,21,56,47,12,17,11,15,11,17,15,5,21,10,25,6,0,0,0,0,0,0,0,0,33,4,243,1,5,244,1,5,55,11,29,16,4,56,33,4,140,2,10,10,11,30,12,8,46,11,8,56,48,1,12,30,10,10,11,28,56,49,17,0,10,10,10,30,12,9,46,11,9,56,50,12,28,1,10,25,6,0,0,0,0,0,0,0,0,33,4,149,2,11,0,1,11,10,1,5,150,2,5,30,11,11,11,23,2,12,0,0,0,86,158,2,10,0,55,2,17,84,20,12,22,11,3,12,10,56,8,12,23,10,0,54,9,12,9,10,9,46,56,28,4,23,11,0,1,11,9,1,11,10,11,23,2,10,9,46,56,51,12,28,12,30,10,9,46,56,28,32,4,39,5,34,10,30,10,1,38,12,4,5,41,9,12,4,11,4,4,155,2,10,9,10,28,56,30,12,29,10,29,16,4,56,31,56,32,20,12,21,10,29,16,4,56,33,32,4,248,1,5,59,10,29,16,4,10,21,56,34,12,15,10,15,16,5,20,12,14,9,12,24,10,15,16,6,20,10,2,37,4,97,8,12,24,10,15,16,5,20,10,15,16,8,20,17,53,12,17,10,0,54,1,10,15,16,7,20,11,17,56,52,10,22,10,15,56,36,5,186,1,14,10,56,25,12,25,10,25,10,14,38,4,107,10,14,12,5,5,109,11,25,12,5,11,5,12,11,10,11,10,15,16,8,20,17,53,12,12,10,12,10,0,55,6,20,17,56,12,18,10,12,10,0,55,4,20,17,57,12,26,4,134,1,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,14,10,11,23,12,14,10,0,54,1,10,15,16,7,20,11,12,56,53,12,13,13,13,10,26,56,38,12,27,10,0,54,1,10,15,16,7,20,13,27,10,18,56,38,56,20,10,0,54,7,11,27,56,39,1,13,23,11,13,56,39,1,10,0,54,0,10,15,16,7,20,13,10,10,11,56,54,56,17,10,0,55,2,17,84,20,10,15,11,11,11,26,11,18,56,41,11,24,4,191,1,8,12,6,5,195,1,10,14,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,230,1,10,21,12,20,10,29,16,4,10,21,56,42,12,19,10,19,56,43,32,4,213,1,11,19,56,32,20,12,21,5,215,1,11,19,1,10,0,54,8,11,15,16,7,20,56,44,10,20,56,45,1,10,29,15,4,11,20,56,46,1,5,241,1,11,15,1,10,29,15,4,10,21,56,47,12,16,11,14,11,16,15,5,21,14,10,56,25,6,0,0,0,0,0,0,0,0,33,4,247,1,5,248,1,5,53,11,29,16,4,56,33,4,144,2,10,9,11,30,12,7,46,11,7,56,55,1,12,30,10,9,11,28,56,49,17,0,10,9,10,30,12,8,46,11,8,56,50,12,28,1,14,10,56,25,6,0,0,0,0,0,0,0,0,33,4,154,2,11,0,1,11,9,1,5,155,2,5,28,11,10,11,23,2,13,1,0,0,87,85,10,1,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,9,5,17,11,0,1,11,6,1,11,5,1,7,5,39,10,1,6,0,0,0,0,0,0,0,0,34,4,22,5,30,11,0,1,11,6,1,11,5,1,7,5,39,11,2,4,52,11,0,11,1,7,26,11,5,17,65,11,4,56,19,56,56,12,9,12,7,13,3,11,7,10,6,56,26,56,57,11,9,11,6,56,27,12,4,5,82,11,1,14,3,56,14,37,4,58,5,66,11,0,1,11,6,1,11,5,1,7,6,39,11,0,7,27,11,5,17,65,11,3,56,16,56,58,12,8,10,6,56,26,12,3,13,4,11,8,11,6,56,27,56,59,11,3,11,4,2,14,0,0,0,89,118,10,5,56,15,12,13,10,3,4,30,10,2,10,1,17,53,12,11,10,0,54,1,11,5,11,11,56,60,10,0,55,10,20,12,10,10,0,55,10,20,6,1,0,0,0,0,0,0,0,22,10,0,54,10,21,10,0,54,9,12,8,5,50,10,0,54,0,11,5,10,2,56,61,10,0,55,11,20,12,10,10,0,55,11,20,6,1,0,0,0,0,0,0,0,22,10,0,54,11,21,10,0,54,3,12,8,10,10,10,1,10,2,10,3,10,13,10,4,18,4,12,9,10,8,10,1,12,7,46,11,7,56,50,12,12,32,4,75,10,8,10,1,10,1,10,6,56,62,18,5,56,63,12,12,11,8,11,12,56,30,15,4,10,10,11,9,56,64,10,0,55,2,17,84,20,10,10,11,3,10,13,11,2,10,1,11,4,57,1,56,65,10,0,55,8,10,13,56,66,32,4,107,10,0,54,8,10,13,11,6,56,67,56,68,5,109,11,6,1,11,0,54,8,11,13,56,44,10,10,11,1,56,69,11,10,2,15,1,0,0,96,144,2,10,2,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,1,6,0,0,0,0,0,0,0,0,36,4,20,5,30,11,0,1,11,8,1,11,6,1,11,7,1,7,4,39,10,1,10,0,55,12,20,25,6,0,0,0,0,0,0,0,0,33,4,39,5,49,11,0,1,11,8,1,11,6,1,11,7,1,7,4,39,10,2,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,58,5,68,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,4,10,6,17,65,36,4,74,5,84,11,0,1,11,8,1,11,6,1,11,7,1,7,18,39,10,7,56,15,12,19,10,3,4,128,1,10,0,55,1,10,19,56,70,12,18,10,0,54,1,10,7,10,18,56,71,12,14,10,0,10,2,10,1,11,6,17,65,11,14,56,56,12,16,12,10,14,10,56,25,12,12,11,18,14,16,56,72,23,12,17,10,0,54,0,10,19,11,10,56,17,10,0,54,1,11,19,11,16,56,20,5,160,1,10,0,54,0,10,7,10,2,56,73,12,9,10,0,10,1,11,6,17,65,11,9,56,58,12,15,12,11,10,2,14,11,56,25,23,12,12,14,15,56,72,12,17,10,0,54,0,10,19,11,11,56,17,10,0,54,1,11,19,11,15,56,20,10,5,7,23,33,4,175,1,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,24,33,4,197,1,11,0,1,11,8,1,11,7,1,10,12,11,2,33,4,190,1,5,192,1,7,8,39,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,25,33,4,228,1,10,12,6,0,0,0,0,0,0,0,0,33,4,206,1,5,214,1,11,0,1,11,8,1,11,7,1,7,9,39,11,0,11,1,11,2,11,3,11,4,11,7,11,8,56,74,12,13,11,12,11,17,8,11,13,2,11,5,7,22,33,4,233,1,5,241,1,11,0,1,11,8,1,11,7,1,7,13,39,10,2,10,12,36,4,133,2,11,0,11,1,11,2,10,12,23,11,3,11,4,11,7,11,8,56,74,12,13,11,12,11,17,8,11,13,2,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,16,0,0,0,1,4,11,0,7,26,35,2,17,0,0,0,1,19,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,11,1,16,8,20,57,2,56,75,2,18,0,0,0,1,27,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,10,2,10,1,16,5,20,11,2,23,11,1,16,8,20,11,3,11,4,57,3,56,76,2,19,1,0,0,100,110,11,2,56,15,12,12,10,0,55,8,10,12,56,66,4,9,5,13,11,0,1,7,11,39,10,0,54,8,10,12,56,44,12,13,10,13,10,1,12,3,46,11,3,56,77,4,26,5,32,11,13,1,11,0,1,7,2,39,10,13,10,1,12,4,46,11,4,56,78,20,12,11,10,1,17,16,12,8,10,8,4,49,10,0,55,9,12,5,5,52,10,0,55,3,12,5,11,5,11,11,56,50,12,10,4,58,5,64,11,13,1,11,0,1,7,2,39,10,8,4,70,10,0,54,9,12,6,5,73,10,0,54,3,12,6,11,6,11,13,11,10,11,1,10,12,56,79,12,9,11,8,4,96,14,9,16,5,20,14,9,16,8,20,17,53,12,7,10,0,54,1,11,12,11,7,56,52,5,103,10,0,54,0,11,12,14,9,16,5,20,56,35,11,0,55,2,17,84,20,14,9,56,36,2,20,0,0,0,101,54,11,1,10,3,56,45,1,10,0,10,2,12,5,46,11,5,56,80,16,4,10,3,56,81,4,15,5,19,11,0,1,7,2,39,10,0,10,2,56,30,12,6,10,6,15,4,11,3,56,46,12,7,14,7,16,7,20,11,4,33,4,35,5,41,11,0,1,11,6,1,7,3,39,11,6,16,4,56,33,4,50,11,0,11,2,56,49,17,0,5,52,11,0,1,11,7,2,21,1,0,0,102,104,10,0,55,2,17,84,20,12,11,11,1,56,15,12,13,10,0,55,8,10,13,56,66,4,14,5,18,11,0,1,7,11,39,10,0,54,8,10,13,56,44,12,14,10,14,46,56,82,32,4,99,5,29,10,14,46,56,83,56,32,20,12,9,10,14,10,9,12,2,46,11,2,56,78,20,12,10,10,9,17,16,12,6,10,6,4,52,10,0,54,9,12,3,5,55,10,0,54,3,12,3,11,3,12,7,10,7,11,10,12,4,46,11,4,56,50,12,12,1,11,7,10,14,11,12,11,9,10,13,56,79,12,8,11,6,4,88,14,8,16,5,20,14,8,16,8,20,17,53,12,5,10,0,54,1,10,13,11,5,56,52,5,95,10,0,54,0,10,13,14,8,16,5,20,56,35,10,11,14,8,56,36,5,23,11,14,1,11,0,1,2,22,1,0,0,103,148,1,10,0,55,2,17,84,20,12,15,11,2,56,15,12,18,10,0,55,8,10,18,56,66,4,14,5,18,11,0,1,6,0,0,0,0,0,0,0,0,39,6,0,0,0,0,0,0,0,0,12,16,6,0,0,0,0,0,0,0,0,12,17,14,1,65,20,12,10,6,0,0,0,0,0,0,0,0,12,8,10,0,54,8,10,18,56,44,12,19,10,8,10,10,35,4,143,1,5,37,14,1,10,8,66,20,20,12,14,10,19,10,14,12,3,46,11,3,56,77,4,50,5,56,11,19,1,11,0,1,7,2,39,10,19,10,14,12,4,46,11,4,56,78,20,12,12,10,14,17,16,12,9,10,12,10,17,34,4,96,11,12,12,17,10,9,4,79,10,0,55,9,12,5,5,82,10,0,55,3,12,5,11,5,10,17,56,50,12,11,4,88,5,94,11,19,1,11,0,1,7,10,39,11,11,12,16,10,9,4,102,10,0,54,9,12,6,5,105,10,0,54,3,12,6,11,6,10,19,10,16,11,14,10,18,56,79,12,13,11,9,4,128,1,14,13,16,5,20,14,13,16,8,20,17,53,12,7,10,0,54,1,10,18,11,7,56,52,5,135,1,10,0,54,0,10,18,14,13,16,5,20,56,35,10,15,14,13,56,36,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,32,11,19,1,11,0,1,2,23,1,0,0,104,84,11,1,56,15,12,7,10,0,55,8,11,7,56,84,12,8,64,28,0,0,0,0,0,0,0,0,12,3,10,8,56,85,12,5,10,5,56,43,32,4,76,5,18,10,8,10,5,56,32,20,56,78,20,12,6,10,5,56,32,20,17,16,4,36,10,0,55,9,11,6,56,86,12,2,5,41,10,0,55,3,11,6,56,86,12,2,11,2,16,4,10,5,56,32,20,56,34,12,4,13,3,10,4,16,18,20,10,4,16,8,20,10,4,16,5,20,10,4,16,19,20,10,4,16,7,20,11,4,16,6,20,18,4,68,28,10,8,11,5,56,32,20,56,87,12,5,5,13,11,8,1,11,0,1,11,5,1,11,3,2,24,1,0,0,105,20,11,1,56,15,12,6,10,0,55,0,10,6,56,88,12,3,12,2,11,0,55,1,11,6,56,89,12,5,12,4,11,2,11,3,11,4,11,5,2,25,1,0,0,106,86,10,0,55,9,56,29,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,9,56,51,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,9,11,1,56,90,12,1,10,0,55,9,11,2,56,90,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,9,10,1,10,3,17,65,56,91,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,9,11,1,56,48,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,26,1,0,0,106,86,10,0,55,3,56,29,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,3,56,51,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,3,11,1,56,90,12,1,10,0,55,3,11,2,56,90,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,3,10,1,10,3,17,65,56,91,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,3,11,1,56,48,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,27,0,0,0,107,49,11,0,11,1,56,86,16,4,12,6,6,0,0,0,0,0,0,0,0,12,3,10,6,56,31,12,5,10,5,56,43,32,4,43,5,15,10,6,10,5,56,32,20,56,34,12,4,10,4,16,6,20,10,2,36,4,34,11,3,11,4,16,5,20,22,12,3,5,36,11,4,1,10,6,11,5,56,32,20,56,42,12,5,5,10,11,6,1,11,5,1,11,3,2,28,1,0,0,108,52,11,2,56,15,12,5,10,0,55,8,10,5,56,66,4,9,5,13,11,0,1,7,11,39,10,0,55,8,11,5,56,84,12,6,10,6,10,1,56,77,4,23,5,29,11,6,1,11,0,1,7,2,39,11,6,10,1,56,78,20,12,4,10,1,7,26,35,4,42,11,0,55,9,12,3,5,45,11,0,55,3,12,3,11,3,11,4,56,86,16,4,11,1,56,34,2,6,10,6,11,6,0,6,2,5,1,4,2,4,5,4,4,4,1,6,6,6,9,6,7,6,14,6,5,6,1,6,3,6,4,6,8,4,0,4,3,0,55,1,55,2,55,3,55,9,55,10,55,11,55,12,55,13,55,14,55,15,55,16,55,17,55,0],"critbit":[161,28,235,11,6,0,0,0,14,1,0,6,2,6,28,3,34,194,1,4,228,1,54,5,154,2,235,1,7,133,4,153,4,8,158,8,64,6,222,8,120,10,214,9,51,11,137,10,4,12,141,10,217,17,13,230,27,28,14,130,28,20,15,150,28,2,0,13,1,43,1,44,0,2,6,1,0,0,0,1,6,0,0,0,4,1,4,0,1,3,12,2,7,1,4,1,2,4,2,0,0,31,0,1,1,4,0,42,2,3,1,4,0,21,2,4,1,4,0,30,2,5,1,4,0,29,2,5,1,4,0,36,6,5,1,4,0,33,6,5,1,4,0,26,6,3,1,4,0,40,6,3,1,4,0,19,7,3,1,4,0,17,6,8,1,4,0,16,6,3,1,4,0,38,9,10,1,4,0,10,9,11,1,4,0,7,6,12,1,4,0,8,6,12,1,4,0,15,1,13,1,6,0,14,1,13,1,4,0,18,6,3,1,4,0,45,14,13,1,4,0,22,15,4,1,4,0,12,16,17,0,1,5,26,13,2,7,4,1,6,22,23,2,7,4,1,9,28,30,2,7,4,1,14,19,13,2,7,4,1,15,19,13,2,7,6,1,21,21,4,2,7,4,1,27,21,3,2,7,4,1,31,0,19,2,7,4,1,37,28,29,2,7,4,29,18,29,20,28,20,27,20,2,10,23,20,10,10,20,10,23,18,8,10,7,10,22,20,18,10,22,18,19,10,6,10,5,10,30,20,1,10,24,18,24,20,30,18,14,10,26,18,26,20,25,20,25,18,1,7,8,4,1,11,2,1,9,0,1,6,11,2,1,9,0,1,3,1,1,2,3,3,2,6,11,2,1,9,0,3,3,7,11,2,1,9,0,3,9,0,2,1,3,2,7,11,2,1,9,0,3,1,9,0,1,7,9,0,1,6,9,0,0,4,7,11,2,1,9,0,3,3,1,3,6,11,2,1,9,0,3,3,1,4,1,2,2,3,8,1,1,11,3,2,9,0,9,1,2,3,11,0,1,9,0,1,6,11,3,2,9,0,9,1,2,6,11,3,2,9,0,9,1,9,0,1,6,9,1,4,1,3,3,3,16,3,3,3,3,3,2,6,8,1,1,1,8,1,3,3,11,0,1,9,0,3,3,3,3,7,11,3,2,9,0,9,1,9,0,9,1,16,3,3,3,3,3,3,3,3,3,1,3,3,6,8,1,3,3,9,0,2,7,11,3,2,9,0,9,1,9,0,1,9,1,1,7,9,1,2,11,3,2,3,8,1,11,3,2,3,11,0,1,9,0,2,6,8,1,3,2,2,2,11,67,114,105,116,98,105,116,84,114,101,101,12,73,110,116,101,114,110,97,108,78,111,100,101,4,76,101,97,102,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,4,99,108,111,98,19,99,111,117,110,116,95,108,101,97,100,105,110,103,95,122,101,114,111,115,7,99,114,105,116,98,105,116,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,29,103,101,116,95,99,108,111,115,101,115,116,95,108,101,97,102,95,105,110,100,101,120,95,98,121,95,107,101,121,11,105,110,115,101,114,116,95,108,101,97,102,14,105,110,116,101,114,110,97,108,95,110,111,100,101,115,8,105,115,95,101,109,112,116,121,13,105,115,95,108,101,102,116,95,99,104,105,108,100,3,107,101,121,6,108,101,97,118,101,115,10,108,101,102,116,95,99,104,105,108,100,14,108,101,102,116,95,109,111,115,116,95,108,101,97,102,6,108,101,110,103,116,104,4,109,97,115,107,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,3,110,101,119,24,110,101,120,116,95,105,110,116,101,114,110,97,108,95,110,111,100,101,95,105,110,100,101,120,9,110,101,120,116,95,108,101,97,102,15,110,101,120,116,95,108,101,97,102,95,105,110,100,101,120,6,112,97,114,101,110,116,13,112,114,101,118,105,111,117,115,95,108,101,97,102,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,11,114,105,103,104,116,95,99,104,105,108,100,15,114,105,103,104,116,95,109,111,115,116,95,108,101,97,102,4,114,111,111,116,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,112,100,97,116,101,95,99,104,105,108,100,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,128,3,8,255,255,255,255,255,255,255,255,3,8,255,255,255,255,255,255,255,127,0,2,3,23,3,46,9,0,35,3,1,2,4,28,3,25,3,39,3,35,3,2,2,7,41,3,20,11,3,2,3,8,1,24,11,3,2,3,11,0,1,9,0,30,3,29,3,32,3,34,3,2,10,0,10,0,3,0,0,13,11,7,9,10,0,56,0,11,0,56,1,7,9,7,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,57,0,2,1,3,0,0,13,4,11,0,55,0,56,2,2,2,3,0,0,13,4,11,0,55,0,56,3,2,3,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,1,20,56,5,55,2,20,11,0,55,1,20,2,4,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,0,55,3,20,2,5,1,0,0,24,78,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,36,5,30,10,0,10,4,11,5,56,7,12,2,5,38,9,12,2,11,2,4,50,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,59,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,7,20,56,9,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,6,3,0,0,24,79,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,37,5,30,10,0,10,4,11,5,56,7,32,12,2,5,39,9,12,2,11,2,4,51,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,60,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,8,20,56,10,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,7,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,7,20,12,2,5,2,11,0,1,11,2,2,8,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,8,20,12,2,5,2,11,0,1,11,2,2,9,3,0,0,25,247,1,10,1,11,2,7,9,57,1,12,15,10,0,55,6,20,12,16,10,0,55,6,20,6,1,0,0,0,0,0,0,0,22,10,0,54,6,21,10,16,7,11,6,1,0,0,0,0,0,0,0,23,35,4,24,5,28,11,0,1,7,1,39,10,0,54,0,10,16,11,15,56,11,10,0,10,1,12,3,46,11,3,56,12,12,7,10,7,7,9,33,4,69,10,16,6,0,0,0,0,0,0,0,0,33,4,49,5,53,11,0,1,7,2,39,7,10,10,16,23,10,0,54,7,21,10,16,10,0,54,1,21,11,16,11,0,54,3,21,6,0,0,0,0,0,0,0,0,2,10,0,55,0,11,7,56,5,55,2,20,12,6,10,6,10,1,34,4,81,5,85,11,0,1,7,3,39,49,64,11,6,10,1,29,53,17,21,49,64,23,23,12,8,6,1,0,0,0,0,0,0,0,11,8,49,1,23,47,12,17,10,17,7,9,7,9,7,9,18,1,12,12,10,0,55,8,20,12,13,10,0,55,8,20,6,1,0,0,0,0,0,0,0,22,10,0,54,8,21,10,0,54,5,10,13,11,12,56,13,10,0,55,7,20,12,18,7,9,12,14,10,18,7,9,35,4,169,1,5,135,1,10,0,55,5,10,18,56,8,12,9,10,17,10,9,16,12,20,36,4,149,1,11,9,1,5,169,1,11,18,12,14,10,1,10,9,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,164,1,11,9,16,7,20,12,18,5,168,1,11,9,16,8,20,12,18,5,130,1,10,14,7,9,33,4,178,1,10,13,10,0,54,7,21,5,193,1,10,0,10,14,10,18,12,5,12,4,46,11,4,11,5,56,7,12,10,10,0,11,14,10,13,11,10,56,14,11,17,10,1,28,6,0,0,0,0,0,0,0,0,33,12,11,10,0,10,13,7,10,10,16,23,10,11,56,14,10,0,11,13,11,18,11,11,32,56,14,10,0,55,0,10,0,55,1,20,56,5,55,2,20,10,1,36,4,227,1,10,16,10,0,54,1,21,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,1,35,4,243,1,10,16,11,0,54,3,21,5,245,1,11,0,1,11,16,2,10,3,0,0,3,27,10,0,56,4,4,8,11,0,1,9,7,9,2,10,0,10,1,56,12,12,2,11,0,55,0,10,2,56,5,55,2,20,11,1,34,4,24,9,7,9,2,8,11,2,2,11,3,0,0,3,18,10,0,56,4,4,7,11,0,1,6,0,0,0,0,0,0,0,0,2,10,0,11,1,56,12,12,2,11,0,55,0,11,2,56,5,55,2,20,2,12,3,0,0,27,171,1,10,0,55,0,10,1,56,5,55,2,20,12,12,10,0,55,1,20,10,1,33,4,25,10,0,10,12,12,4,46,11,4,56,15,12,9,1,11,9,10,0,54,1,21,10,0,55,3,20,10,1,33,4,43,10,0,11,12,12,5,46,11,5,56,16,12,10,1,11,10,10,0,54,3,21,10,0,54,0,10,1,56,17,58,1,12,15,12,17,1,10,0,46,56,18,6,0,0,0,0,0,0,0,0,33,4,78,7,9,10,0,54,7,21,7,9,10,0,54,1,21,7,9,10,0,54,3,21,6,0,0,0,0,0,0,0,0,10,0,54,8,21,6,0,0,0,0,0,0,0,0,11,0,54,6,21,5,169,1,10,15,7,9,34,4,83,5,87,11,0,1,7,6,39,10,0,55,5,10,15,56,8,12,14,10,14,16,6,20,12,13,10,0,10,15,7,10,11,1,23,12,7,12,6,46,11,6,11,7,56,7,4,113,11,14,16,8,20,12,8,5,117,11,14,16,7,20,12,8,11,8,12,16,10,13,7,9,33,4,149,1,10,16,7,9,35,4,135,1,7,9,10,0,54,5,10,16,56,19,15,6,21,5,144,1,7,9,10,0,54,0,7,10,10,16,23,56,20,54,4,21,11,16,10,0,54,7,21,5,164,1,10,0,10,13,10,15,12,3,12,2,46,11,2,11,3,56,7,12,11,10,0,11,13,11,16,11,11,56,14,11,0,54,5,11,15,56,21,1,11,17,2,13,3,0,0,13,6,11,0,54,0,11,1,56,20,54,9,2,14,3,0,0,13,6,11,0,55,0,11,1,56,5,55,9,2,15,3,0,0,3,14,10,0,11,1,56,6,12,2,4,6,5,10,11,0,1,7,4,39,11,0,11,2,56,22,2,16,3,0,0,31,14,11,0,58,0,1,1,1,1,12,2,12,1,1,11,1,56,23,11,2,56,24,2,17,3,0,0,31,23,14,0,55,0,56,2,6,0,0,0,0,0,0,0,0,33,4,7,5,9,6,0,0,0,0,0,0,0,0,39,11,0,58,0,1,1,1,1,12,2,12,1,1,11,2,56,25,11,1,56,26,2,18,0,0,0,32,46,10,0,55,7,20,12,3,10,3,7,9,33,4,12,11,0,1,7,9,2,10,3,7,9,35,4,40,5,17,10,0,55,5,11,3,56,8,12,2,10,1,10,2,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,35,11,2,16,7,20,12,3,5,39,11,2,16,8,20,12,3,5,12,11,0,1,7,10,11,3,23,2,19,0,0,0,13,55,10,1,7,9,34,4,5,5,9,11,0,1,7,7,39,11,3,4,19,10,2,10,0,54,5,10,1,56,19,15,7,21,5,26,10,2,10,0,54,5,10,1,56,19,15,8,21,10,2,7,9,34,4,52,10,2,7,9,36,4,44,11,1,11,0,54,0,7,10,11,2,23,56,20,54,4,21,5,51,11,1,11,0,54,5,11,2,56,19,15,6,21,5,54,11,0,1,2,20,0,0,0,13,9,11,0,55,5,11,1,56,8,16,7,20,11,2,33,2,21,0,0,0,33,107,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,49,128,12,1,5,105,49,0,12,2,10,0,50,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,23,11,0,49,64,47,12,0,11,2,49,64,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,37,11,0,49,32,47,12,0,11,2,49,32,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,51,11,0,49,16,47,12,0,11,2,49,16,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,65,11,0,49,8,47,12,0,11,2,49,8,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,79,11,0,49,4,47,12,0,11,2,49,4,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,93,11,0,49,2,47,12,0,11,2,49,2,22,12,2,11,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,103,11,2,49,1,22,12,2,11,2,12,1,11,1,2,2,2,2,3,0,0,2,4,0,2,2,1,1,3,1,1,1,2,2,6,2,0,2,5,1,0,0,1,0,10,1,10,2,10,3,10,4,10,5,10,9,10,10,10,11,10,13,10,0,11,0],"custodian":[161,28,235,11,6,0,0,0,14,1,0,12,2,12,48,3,60,158,1,4,218,1,30,5,248,1,246,1,7,238,3,166,4,8,148,8,64,6,212,8,10,10,222,8,38,11,132,9,4,12,136,9,238,2,13,246,11,8,14,254,11,6,15,132,12,2,0,23,1,15,1,21,1,35,1,37,1,38,0,0,4,1,0,1,0,1,12,0,0,4,12,1,0,1,1,2,4,1,0,1,2,3,12,1,0,1,3,5,7,0,3,8,4,0,4,6,12,2,7,1,4,1,5,7,2,0,0,33,0,1,0,0,10,2,3,1,0,0,34,0,4,1,0,0,42,5,6,1,0,0,28,7,8,1,0,0,24,9,10,1,0,0,29,11,8,1,0,0,25,12,10,1,0,0,31,9,8,1,0,0,40,12,8,1,0,0,9,2,13,1,0,0,12,2,13,1,0,0,19,14,15,1,0,0,17,2,16,1,0,1,30,27,13,1,0,1,36,30,10,1,0,1,41,24,13,1,0,1,43,8,10,1,0,2,26,26,6,1,0,3,34,0,17,0,3,39,28,29,0,4,13,31,8,2,7,4,4,16,21,23,2,7,4,4,18,32,33,2,7,4,4,22,21,22,2,7,4,4,34,0,25,2,7,4,24,20,22,20,16,19,25,20,5,19,18,19,12,19,14,19,15,19,6,19,7,19,4,19,17,19,21,20,23,20,1,7,8,8,1,8,1,2,6,11,2,1,9,0,8,5,2,3,3,1,11,2,1,9,0,4,7,11,2,1,9,0,3,6,8,1,7,8,8,1,11,4,1,9,0,3,7,11,2,1,9,0,8,5,11,3,1,9,0,0,3,7,11,2,1,9,0,6,8,1,3,1,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,11,3,1,9,0,3,7,11,2,1,9,0,8,5,3,1,3,2,7,11,2,1,9,0,8,5,1,7,11,0,1,9,0,1,6,11,0,1,9,0,1,8,6,3,6,11,0,1,9,0,3,3,1,9,0,2,8,5,11,0,1,9,0,2,6,11,7,2,9,0,9,1,9,0,1,1,1,6,9,1,1,6,11,3,1,9,0,1,11,7,2,9,0,9,1,2,11,3,1,9,0,7,8,8,2,7,11,3,1,9,0,11,3,1,9,0,1,6,8,6,1,8,5,2,7,11,3,1,9,0,3,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,7,9,1,7,65,99,99,111,117,110,116,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,4,67,111,105,110,9,67,117,115,116,111,100,105,97,110,2,73,68,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,16,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,115,22,97,99,99,111,117,110,116,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,3,97,100,100,17,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,22,98,111,114,114,111,119,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,26,98,111,114,114,111,119,95,109,117,116,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,4,99,108,111,98,4,99,111,105,110,8,99,111,110,116,97,105,110,115,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,105,110,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,4,106,111,105,110,12,108,111,99,107,95,98,97,108,97,110,99,101,14,108,111,99,107,101,100,95,98,97,108,97,110,99,101,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,110,101,119,6,111,98,106,101,99,116,5,115,112,108,105,116,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,0,2,2,14,11,3,1,9,0,32,11,3,1,9,0,1,2,1,27,8,6,2,2,2,27,8,6,11,11,7,2,8,5,11,0,1,9,0,2,19,0,19,0,1,0,0,8,4,11,0,17,19,18,1,2,1,3,0,0,18,27,10,0,55,0,10,1,56,0,32,4,11,11,0,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,2,11,0,55,0,11,1,56,1,12,2,10,2,55,1,56,2,12,3,11,2,55,2,56,2,12,4,11,3,11,4,2,2,3,0,0,8,6,10,0,17,19,11,0,56,3,57,0,2,3,3,0,0,8,7,11,0,11,2,11,1,56,4,11,3,56,5,2,4,3,0,0,8,8,11,0,11,1,56,6,54,1,11,2,56,7,1,2,5,3,0,0,8,9,11,0,11,1,16,3,17,20,56,6,54,1,11,2,56,8,2,6,3,0,0,8,10,11,0,11,1,16,3,17,20,56,6,54,2,11,2,56,7,1,2,7,3,0,0,8,7,11,0,11,1,56,6,54,2,11,2,56,8,2,8,3,0,0,10,10,10,0,10,1,11,2,56,4,12,3,11,0,11,1,11,3,56,9,2,9,3,0,0,10,10,10,0,10,1,11,2,56,10,12,3,11,0,11,1,11,3,56,11,2,10,3,0,0,8,7,11,0,55,0,11,1,56,1,55,1,56,2,2,11,3,0,0,8,7,11,0,55,0,11,1,56,1,55,2,56,2,2,12,0,0,0,8,18,10,0,55,0,10,1,56,0,32,4,13,10,0,54,0,10,1,56,12,56,12,57,1,56,13,11,0,54,0,11,1,56,14,2,13,0,0,0,8,15,10,0,55,0,10,1,56,0,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,1,2,2,1,0,0,0,1,1,0,0,19,1,19,2,19,0,20,0],"math":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,30,5,32,13,7,45,79,8,124,32,6,156,1,38,12,194,1,133,2,15,199,3,2,0,2,0,6,0,1,0,0,7,0,2,0,0,3,0,1,0,0,4,0,2,0,0,5,0,2,0,0,1,0,2,0,2,3,3,1,3,2,1,3,0,3,1,4,4,4,99,108,111,98,9,100,105,118,95,114,111,117,110,100,4,109,97,116,104,3,109,117,108,9,109,117,108,95,114,111,117,110,100,16,117,110,115,97,102,101,95,100,105,118,95,114,111,117,110,100,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,3,8,0,202,154,59,0,0,0,0,4,16,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,3,0,0,1,7,11,0,11,1,17,1,12,2,1,11,2,2,1,3,0,0,4,26,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,10,4,24,7,1,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,18,9,12,2,11,2,11,3,11,4,24,7,1,26,52,2,2,1,0,0,1,14,11,0,11,1,17,1,12,2,1,10,2,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,2,3,1,0,0,2,15,11,0,11,1,17,1,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,4,3,0,0,4,28,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,7,0,53,24,10,4,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,9,12,2,11,2,11,3,7,0,53,24,11,4,26,52,2,5,1,0,0,2,15,11,0,11,1,17,4,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,0,0,0]},"type_origin_table":[{"module_name":"custodian","struct_name":"Account","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"AccountCap","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"Custodian","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"Leaf","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"InternalNode","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"CritbitTree","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"PoolCreated","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlacedV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilledV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Order","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"TickLevel","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Pool","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlaced","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Package":{"id":"0x7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d","version":1,"module_map":{"migrate_proposal":[161,28,235,11,6,0,0,0,10,1,0,10,2,10,40,3,50,68,4,118,14,5,132,1,130,1,7,134,2,192,2,8,198,4,128,1,6,198,5,20,10,218,5,5,12,223,5,118,0,19,3,14,3,16,1,21,2,22,0,0,6,0,1,1,0,0,1,2,8,0,1,7,7,0,1,8,7,0,2,3,8,0,2,5,8,1,6,0,3,4,7,1,0,0,4,6,2,0,0,9,0,1,0,0,23,2,1,0,0,20,3,1,0,1,15,1,16,0,1,20,18,1,2,6,6,2,9,6,1,1,6,2,10,9,1,0,2,24,8,7,1,6,3,11,12,1,1,0,3,13,14,15,1,0,3,17,10,11,1,0,3,18,10,11,1,0,5,5,7,5,10,9,8,9,11,9,9,9,4,17,2,7,8,5,7,8,8,0,3,6,8,5,7,11,6,1,8,0,7,8,8,4,6,8,5,7,11,6,1,8,0,7,8,2,7,8,8,1,7,8,8,1,8,0,3,6,8,5,9,0,7,8,8,1,11,7,1,8,1,5,6,8,5,9,0,7,11,6,1,9,0,1,7,8,8,1,8,1,1,6,11,7,1,9,0,1,1,1,11,7,1,9,0,3,8,1,11,7,1,8,1,8,4,1,7,11,7,1,9,0,1,9,0,1,8,4,2,8,3,8,4,3,6,8,1,7,8,2,9,1,11,67,101,114,116,105,102,105,99,97,116,101,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,9,84,120,67,111,110,116,101,120,116,13,86,101,114,115,105,111,110,95,49,95,48,95,48,13,86,101,114,115,105,111,110,95,49,95,48,95,49,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,12,100,101,115,116,114,111,121,95,110,111,110,101,11,100,117,109,109,121,95,102,105,101,108,100,7,101,120,116,114,97,99,116,7,103,101,110,101,115,105,115,17,103,101,116,95,118,101,114,115,105,111,110,95,49,95,48,95,49,13,103,111,118,101,114,110,97,110,99,101,95,118,49,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,16,109,105,103,114,97,116,101,95,112,114,111,112,111,115,97,108,15,109,105,103,114,97,116,101,95,118,101,114,115,105,111,110,6,111,112,116,105,111,110,10,116,120,95,99,111,110,116,101,120,116,13,118,111,116,101,95,112,111,114,112,111,115,97,108,13,118,111,116,101,95,112,114,111,112,111,115,97,108,127,107,56,13,191,54,35,98,5,97,92,100,252,187,108,78,148,84,183,110,255,9,125,214,198,83,79,109,80,112,209,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,12,1,0,1,4,0,4,9,11,0,11,1,12,2,46,9,18,0,11,2,56,0,2,1,1,4,0,7,17,11,0,9,18,0,11,1,8,11,2,56,1,12,3,14,3,56,2,4,12,5,14,7,1,39,11,3,56,3,2,2,1,0,0,13,30,11,0,9,18,0,11,1,8,11,3,56,1,12,5,14,5,56,4,4,12,5,16,11,2,1,7,0,39,13,5,56,5,12,4,17,3,12,6,14,4,11,2,11,6,56,6,11,4,17,6,11,5,56,3,2,0]},"type_origin_table":[{"module_name":"migrate_proposal","struct_name":"Certificate","package":"0x7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":6},"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302":{"upgraded_id":"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302","upgraded_version":1},"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a":{"upgraded_id":"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a","upgraded_version":1},"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e":{"upgraded_id":"0xc5b2a5049cd71586362d0c6a38e34cfaae7ea9ce6d5401a350506a15f817bf72","upgraded_version":2}}}},"owner":"Immutable","previous_transaction":"5kWByxejQ95cxQ5zUCba3WyivedWBmtisRa4ZaWJuWpm","storage_rebate":10830000},{"data":{"Package":{"id":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","version":1,"module_map":{"app_manager":[161,28,235,11,6,0,0,0,10,1,0,10,2,10,24,3,34,46,4,80,2,5,82,54,7,136,1,228,1,8,236,2,64,10,172,3,18,12,190,3,106,13,168,4,4,0,8,0,11,1,16,1,20,1,21,0,3,12,0,0,0,12,0,1,1,0,0,2,2,7,0,2,5,4,0,4,4,2,0,0,14,0,1,0,0,17,2,3,0,0,18,4,3,0,0,12,5,6,0,0,10,3,1,0,2,9,7,1,0,2,15,0,7,0,2,22,12,8,0,3,19,10,1,1,8,8,9,1,7,8,5,0,2,7,8,0,7,8,5,1,8,1,3,6,8,2,7,8,0,7,8,5,1,6,8,1,1,13,1,8,4,1,8,3,1,8,0,1,9,0,3,8,1,8,3,8,4,1,6,8,4,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,2,73,68,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,97,112,112,95,99,97,112,115,6,97,112,112,95,105,100,11,97,112,112,95,109,97,110,97,103,101,114,6,100,101,108,101,116,101,15,100,101,115,116,114,111,121,95,97,112,112,95,99,97,112,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,2,105,100,4,105,110,105,116,3,110,101,119,6,111,98,106,101,99,116,12,114,101,103,105,115,116,101,114,95,97,112,112,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,8,4,6,10,8,3,1,2,2,13,8,4,7,13,0,0,0,0,1,6,11,0,17,6,64,8,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,11,19,11,1,17,6,12,4,14,4,17,7,12,3,11,4,10,0,16,0,65,8,75,18,1,12,2,11,0,15,0,11,3,68,8,11,2,2,2,1,0,0,1,4,11,1,11,2,17,1,2,3,1,0,0,1,4,11,0,16,1,20,2,4,1,0,0,1,5,11,0,19,1,1,17,5,2,0,1,1,1,0],"dola_address":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,12,3,24,109,4,133,1,6,5,139,1,78,7,217,1,191,3,8,152,5,96,6,248,5,14,10,134,6,8,12,142,6,151,2,13,165,8,4,0,13,0,23,1,4,1,27,2,3,2,5,0,0,7,0,2,1,7,0,3,2,7,0,0,20,0,1,0,0,19,2,1,0,0,18,2,3,0,0,29,4,5,0,0,28,6,5,0,0,10,7,5,0,0,6,8,5,0,0,7,5,8,0,0,9,0,5,1,0,0,8,5,3,0,0,15,5,3,0,0,11,3,5,0,1,12,19,1,0,1,24,14,0,0,1,25,15,0,0,1,30,17,18,1,1,2,21,13,3,0,3,17,0,12,1,0,3,22,12,13,0,4,16,3,8,0,5,26,9,3,1,0,20,8,17,11,15,10,0,1,13,1,6,8,0,1,10,2,2,8,0,13,1,8,0,2,8,0,10,2,2,13,10,2,1,5,1,6,9,0,1,2,1,9,0,1,8,2,1,8,1,2,7,10,2,13,2,7,10,2,10,2,6,10,2,3,10,2,13,3,3,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,11,68,111,108,97,65,100,100,114,101,115,115,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,112,111,111,108,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,19,117,112,100,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,13,2,0,0,0,2,2,14,13,13,10,2,0,1,0,0,0,2,7,1,2,1,1,0,0,0,4,11,0,16,0,20,2,2,1,0,0,0,4,11,0,16,1,20,2,3,1,0,0,0,6,11,1,13,0,15,0,21,11,0,2,4,1,0,0,0,6,11,1,13,0,15,1,21,11,0,2,5,1,0,0,0,4,11,0,11,1,18,0,2,6,1,0,0,0,5,7,1,14,0,56,0,18,0,2,7,1,0,0,0,14,14,0,16,1,65,10,6,32,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,14,0,16,1,20,17,19,2,8,1,0,0,3,8,56,1,17,18,17,16,12,0,7,1,11,0,18,0,2,9,1,0,0,0,4,14,0,16,1,20,2,10,1,0,0,3,14,64,10,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,17,13,13,1,14,0,16,1,20,17,14,11,1,2,11,1,0,0,16,30,14,0,65,10,12,6,6,0,0,0,0,0,0,0,0,12,5,6,2,0,0,0,0,0,0,0,12,2,14,0,10,5,10,5,10,2,22,56,2,12,1,14,1,17,12,12,4,11,5,11,2,22,12,5,14,0,11,5,11,6,56,2,12,3,11,4,11,3,18,0,2,0,0,0,1,0],"dola_pool":[161,28,235,11,6,0,0,0,14,1,0,22,2,22,52,3,74,173,1,4,247,1,32,5,151,2,211,1,7,234,3,168,5,8,146,9,96,6,242,9,50,10,164,10,34,11,198,10,2,12,200,10,222,2,13,166,13,4,14,170,13,4,15,174,13,4,0,23,0,22,0,45,1,12,1,54,2,13,2,14,2,27,2,43,2,52,2,53,0,5,12,1,0,1,0,3,3,0,0,10,3,0,1,4,7,0,3,6,7,0,4,8,7,0,5,0,4,1,0,1,6,1,12,1,0,1,6,2,12,1,0,1,8,9,4,0,10,7,2,0,0,30,0,1,1,0,0,19,2,3,1,0,0,16,4,5,0,0,42,6,5,1,0,0,55,6,5,1,0,0,21,7,8,1,0,0,57,9,3,1,0,0,48,10,8,0,1,15,19,21,0,1,17,21,19,0,1,18,3,21,1,0,1,32,30,8,0,1,33,30,29,0,1,34,3,29,0,2,25,22,8,0,2,26,35,8,0,3,37,26,8,0,4,29,3,25,1,0,4,38,25,26,0,5,39,24,5,1,0,5,51,31,15,1,0,5,59,3,15,1,0,6,28,32,23,1,0,6,31,12,1,1,0,6,36,23,15,1,0,6,56,20,5,1,0,7,24,11,3,1,3,8,41,13,14,0,9,46,34,3,1,12,9,50,11,3,1,8,10,49,18,19,0,23,11,21,11,29,16,0,11,25,11,3,11,10,11,24,11,19,11,17,11,26,27,4,11,20,11,22,11,26,33,28,23,1,6,11,0,1,9,0,1,2,2,6,11,8,1,9,0,7,8,10,0,3,3,2,2,1,3,2,6,11,0,1,9,0,3,5,7,11,0,1,9,0,11,7,1,9,0,13,10,2,7,8,10,1,10,2,5,7,11,0,1,9,0,8,3,3,8,3,7,8,10,3,13,10,2,7,8,10,1,9,0,1,6,11,8,1,9,0,1,7,8,10,1,8,9,1,11,6,1,9,0,1,11,0,1,9,0,6,3,3,3,10,2,5,8,3,1,6,8,10,1,5,1,6,11,7,1,9,0,1,8,3,5,8,3,8,3,3,13,10,2,1,11,7,1,9,0,2,7,11,6,1,9,0,11,6,1,9,0,1,8,5,1,8,4,1,8,1,3,3,11,7,1,9,0,5,1,13,1,6,8,3,2,7,11,6,1,9,0,3,2,11,6,1,9,0,7,8,10,1,8,2,2,9,0,5,3,8,3,13,10,2,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,11,68,101,112,111,115,105,116,80,111,111,108,11,68,111,108,97,65,100,100,114,101,115,115,4,80,111,111,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,12,87,105,116,104,100,114,97,119,80,111,111,108,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,11,99,114,101,97,116,101,95,112,111,111,108,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,4,101,109,105,116,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,12,103,101,116,95,100,101,99,105,109,97,108,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,12,105,110,116,111,95,98,97,108,97,110,99,101,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,10,112,111,111,108,95,99,111,100,101,99,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,35,8,9,13,11,6,1,9,0,20,2,1,2,3,44,8,4,49,5,11,3,2,2,3,44,8,4,47,5,11,3,0,11,0,1,0,0,3,4,11,0,55,0,20,2,1,1,0,0,1,10,11,0,56,0,12,2,11,1,17,27,56,1,11,2,57,0,56,2,2,2,1,0,0,3,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,3,1,0,0,1,8,11,0,56,3,12,2,11,1,11,2,49,8,17,2,2,4,1,0,0,1,8,11,0,56,3,12,2,11,1,49,8,11,2,17,2,2,5,3,0,0,17,38,11,4,46,17,30,12,9,14,1,56,4,12,7,10,0,10,7,12,5,46,11,5,56,5,12,6,10,9,17,8,12,10,56,6,11,10,11,6,11,2,11,3,17,14,12,8,11,0,54,1,11,1,56,7,56,8,1,56,9,17,18,11,9,11,7,18,1,56,10,11,8,2,6,3,0,0,28,53,17,13,14,3,17,12,33,4,6,5,12,11,0,1,11,4,1,7,4,39,14,3,17,11,56,9,17,18,17,16,33,4,20,5,26,11,0,1,11,4,1,7,0,39,11,1,17,9,12,7,10,0,11,2,12,5,46,11,5,56,11,12,2,11,0,54,1,10,2,56,12,11,4,56,13,12,6,56,9,17,18,10,7,11,2,18,2,56,14,11,6,11,7,56,15,2,7,3,0,0,3,8,11,2,46,17,30,17,8,11,0,11,1,17,15,2,0,2,0,1,0,11,1,11,0,40,0,58,0],"equilibrium_fee":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,50,5,54,29,7,83,174,1,8,129,2,32,12,161,2,197,5,0,4,0,10,0,2,0,1,0,0,3,2,1,0,0,0,3,1,0,0,1,3,1,0,1,5,0,1,0,1,6,4,1,0,1,7,0,1,0,1,8,4,1,0,1,9,1,1,0,1,11,0,1,0,2,15,15,1,15,3,15,15,15,6,15,15,15,15,15,15,0,4,1,15,15,15,6,1,15,15,15,15,15,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,27,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,112,101,114,99,101,110,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,1,13,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,11,11,1,11,0,17,6,12,2,11,2,2,1,1,0,0,1,17,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,15,11,0,11,1,17,6,11,2,17,6,17,5,17,4,12,3,11,3,2,2,1,0,0,5,93,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,1,10,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,2,23,10,0,10,2,23,10,3,17,1,10,4,36,4,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,10,4,36,4,50,10,1,10,0,10,4,17,9,10,3,17,9,23,17,5,10,4,10,3,17,9,23,17,6,12,7,5,52,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,12,9,10,2,10,9,23,10,5,17,5,10,4,10,3,17,9,23,17,9,24,10,4,10,3,17,9,26,12,8,10,0,11,1,23,11,5,17,7,17,9,24,10,0,11,9,23,11,0,11,2,23,17,6,17,8,17,9,11,4,11,3,17,9,26,11,8,23,2,3,1,0,0,6,51,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,12,7,11,1,10,2,22,11,0,10,2,22,11,3,17,1,11,7,23,12,9,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,4,11,5,17,6,24,12,11,11,2,11,11,17,6,17,5,17,4,12,10,11,9,11,10,17,4,12,8,11,4,11,8,17,9,2,0],"genesis":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,52,3,70,123,4,193,1,22,5,215,1,167,1,7,254,2,226,3,8,224,6,96,6,192,7,61,10,253,7,34,12,159,8,137,2,13,168,10,6,15,174,10,2,0,25,1,14,1,42,1,44,2,23,2,36,2,37,2,40,2,41,0,0,0,0,0,2,12,0,0,1,8,0,0,11,7,0,0,12,7,0,1,4,7,0,2,6,7,0,5,3,7,0,5,7,4,0,6,8,12,0,6,9,0,0,6,10,0,0,8,5,2,0,0,31,0,1,0,0,15,2,3,0,0,17,4,5,0,0,34,6,5,2,6,6,0,18,7,8,0,0,20,8,5,0,0,21,9,5,0,0,16,10,5,0,1,32,29,30,0,2,26,5,22,1,0,2,27,28,29,0,3,30,33,34,1,0,3,38,35,19,1,0,4,13,16,5,2,7,4,4,24,24,25,2,7,4,4,38,26,27,2,7,4,5,19,13,5,0,5,29,17,14,1,8,5,35,12,13,0,6,15,20,3,0,6,17,21,5,0,7,39,19,5,1,8,13,15,17,1,21,18,14,23,15,23,9,27,9,19,13,31,11,14,12,14,14,15,2,8,9,7,8,12,1,8,1,4,6,8,0,7,8,2,2,10,2,1,8,11,2,7,8,2,8,10,0,3,6,8,0,7,8,2,9,1,1,6,8,1,1,8,0,2,7,8,2,8,1,1,6,8,2,2,8,2,8,1,1,7,8,12,1,8,8,1,8,7,2,8,3,8,4,3,7,8,8,9,0,9,1,1,6,9,0,1,8,2,1,9,0,3,7,8,9,2,10,2,2,7,8,9,8,10,1,8,6,2,8,3,9,0,2,6,8,8,9,0,1,1,2,7,8,8,9,0,1,9,1,1,6,8,6,1,8,5,1,10,2,2,8,3,9,1,2,3,8,7,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,7,86,101,114,115,105,111,110,13,86,101,114,115,105,111,110,95,49,95,48,95,48,3,97,100,100,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,15,100,101,115,116,114,111,121,95,109,97,110,97,103,101,114,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,7,103,101,110,101,115,105,115,3,103,101,116,10,103,101,116,95,109,111,100,117,108,101,13,103,111,118,101,114,110,97,110,99,101,95,118,49,2,105,100,8,105,110,100,101,120,95,111,102,12,105,110,105,116,95,103,101,110,101,115,105,115,10,105,110,116,111,95,98,121,116,101,115,11,109,97,110,97,103,101,114,95,105,100,115,15,109,105,103,114,97,116,101,95,118,101,114,115,105,111,110,3,110,101,119,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,11,117,112,103,114,97,100,101,95,99,97,112,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,10,2,8,7,103,101,110,101,115,105,115,0,2,1,22,1,1,2,1,29,8,8,2,2,3,29,8,8,43,8,9,33,10,8,7,3,2,1,22,1,4,2,1,22,1,0,3,0,0,11,26,10,1,17,18,11,0,64,14,0,0,0,0,0,0,0,0,18,2,12,2,11,1,17,18,18,1,12,3,13,2,15,0,9,18,3,9,18,4,56,0,13,2,15,1,14,3,56,1,68,14,11,2,56,2,11,3,2,1,1,0,0,5,6,11,1,15,2,11,2,11,3,17,19,2,2,1,0,0,5,5,11,0,15,2,11,1,17,20,2,3,1,0,0,22,47,10,1,15,0,46,9,18,3,56,3,4,8,5,12,11,1,1,7,1,39,10,1,15,0,9,18,3,56,4,1,56,5,12,3,10,3,56,6,34,4,25,5,29,11,1,1,7,2,39,14,3,17,10,17,8,7,5,33,4,36,5,40,11,1,1,7,3,39,11,1,15,0,9,18,3,11,2,56,7,2,4,1,0,0,5,3,9,18,0,2,5,1,0,0,5,4,11,0,19,0,1,2,6,1,0,0,32,18,14,1,56,1,12,3,10,0,16,1,14,3,56,8,12,2,1,11,0,15,1,11,2,56,9,1,11,1,19,1,17,16,2,7,1,0,0,5,10,11,0,16,0,9,18,3,56,10,4,7,5,9,7,4,39,2,2,0,2,2,2,1,0,28,0],"governance_v1":[161,28,235,11,6,0,0,0,13,1,0,22,2,22,56,3,78,198,1,4,148,2,40,5,188,2,148,2,7,208,4,155,6,8,235,10,96,6,203,11,207,1,10,154,13,72,11,226,13,2,12,228,13,215,9,13,187,23,28,14,215,23,14,0,43,0,38,1,18,1,57,1,71,1,75,2,33,2,56,2,58,2,69,2,70,0,3,8,0,0,7,8,1,6,0,0,1,3,0,0,0,3,0,1,2,0,0,1,4,12,0,2,8,7,0,3,6,7,1,0,0,4,10,7,0,7,5,7,0,7,11,4,0,8,12,12,0,10,9,2,0,0,47,0,1,0,0,13,2,1,0,0,74,3,4,0,0,15,5,1,0,0,62,5,1,0,0,73,6,1,0,0,22,7,1,0,0,31,8,9,0,0,41,10,11,1,6,0,28,12,1,0,0,25,13,1,1,6,0,76,14,15,1,6,0,20,10,1,1,6,1,24,47,12,0,1,27,12,1,0,1,48,25,4,0,2,68,35,11,0,3,19,46,44,1,0,3,35,27,23,1,0,3,37,26,1,1,0,3,49,46,9,1,0,3,50,46,9,1,0,3,55,1,20,1,0,3,65,23,20,1,0,4,39,1,39,1,0,4,40,40,11,0,5,23,29,9,1,0,5,46,29,31,1,0,5,61,32,23,1,0,6,29,23,1,1,3,7,45,44,21,1,8,7,53,0,19,0,7,72,37,38,0,9,64,23,1,1,8,10,32,18,34,0,10,63,18,17,0,22,4,33,22,19,4,18,4,26,17,27,17,28,17,22,34,23,34,24,23,33,41,29,42,30,41,29,45,20,34,17,34,17,4,23,12,21,34,22,12,1,7,8,12,0,3,8,11,7,8,0,7,8,12,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,1,9,0,7,8,12,1,8,6,1,8,4,3,6,8,0,9,0,7,8,12,5,6,8,0,9,0,7,11,1,1,9,0,1,7,8,12,1,11,7,1,8,4,1,10,5,1,5,1,6,8,12,1,8,10,1,11,7,1,9,0,1,8,9,1,8,0,1,9,0,2,5,1,2,8,11,7,8,12,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,1,10,2,12,8,8,3,11,7,1,3,3,5,8,10,5,11,7,1,3,3,8,10,8,9,3,1,6,8,10,1,6,8,9,1,8,8,1,6,8,8,1,11,1,1,9,0,1,8,2,11,1,6,5,6,5,1,1,7,10,5,3,7,10,5,3,3,5,1,6,9,0,1,8,3,1,6,11,7,1,9,0,1,6,8,5,11,67,104,97,110,103,101,83,116,97,116,101,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,10,97,100,100,95,109,101,109,98,101,114,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,12,99,104,101,99,107,95,109,101,109,98,101,114,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,49,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,103,101,110,101,115,105,115,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,9,109,97,120,95,100,101,108,97,121,7,109,101,109,98,101,114,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,6,114,101,109,111,118,101,13,114,101,109,111,118,101,95,109,101,109,98,101,114,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,7,117,112,103,114,97,100,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,8,45,8,10,42,11,7,1,8,5,14,1,17,3,77,3,51,3,52,10,5,44,10,8,9,1,2,10,45,8,10,26,5,66,3,30,11,7,1,3,34,3,59,8,6,21,9,0,36,10,5,16,10,5,67,2,2,2,1,60,8,9,3,2,2,60,8,9,54,2,1,23,0,0,0,0,16,19,64,17,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,35,68,17,11,0,17,31,56,0,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,11,1,64,21,0,0,0,0,0,0,0,0,18,0,56,1,2,1,1,4,0,24,42,10,1,10,2,46,17,35,12,3,46,11,3,17,6,10,1,16,0,20,32,4,20,10,1,16,1,65,21,6,0,0,0,0,0,0,0,0,33,12,4,5,22,9,12,4,11,4,4,25,5,31,11,1,1,11,2,1,7,5,39,10,1,15,2,11,0,11,2,17,15,56,2,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,2,56,3,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,28,19,10,1,15,3,14,2,12,3,46,11,3,56,4,32,4,10,5,14,11,1,1,7,9,39,11,1,15,3,11,2,68,17,2,4,1,0,0,30,21,10,1,10,2,12,3,46,11,3,17,6,10,1,15,3,14,2,12,4,46,11,4,56,5,12,5,1,11,1,15,3,11,5,56,6,1,2,5,1,0,0,1,24,10,4,10,3,10,2,22,36,4,7,5,11,11,1,1,7,7,39,11,2,10,1,15,4,21,11,3,10,1,15,5,21,11,4,11,1,15,6,21,2,6,1,0,0,1,9,11,0,16,3,14,1,56,4,4,6,5,8,7,8,39,2,7,1,0,0,8,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,8,1,0,0,33,75,11,1,46,17,34,12,7,10,0,55,0,20,7,2,33,4,16,11,0,1,7,16,17,16,12,6,5,73,10,0,55,0,20,7,3,33,4,28,11,0,1,7,17,17,16,12,5,5,71,10,0,55,0,20,7,4,33,4,40,11,0,1,7,18,17,16,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,19,17,16,12,3,5,67,11,0,55,0,20,7,0,33,4,62,7,20,17,16,12,2,5,65,7,21,17,16,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,9,1,0,0,1,3,11,0,17,14,2,10,1,0,0,36,86,10,0,16,0,20,4,5,5,11,11,0,1,11,2,1,7,6,39,10,2,46,17,35,12,9,10,0,10,9,17,6,10,2,46,17,34,10,0,16,4,20,22,12,14,10,0,16,5,20,6,0,0,0,0,0,0,0,0,33,4,35,56,7,12,10,5,42,10,14,10,0,16,5,20,22,56,8,12,10,10,2,46,17,34,11,0,16,6,20,22,12,11,11,2,17,31,12,12,14,12,17,32,20,12,13,11,12,12,8,11,9,12,7,11,14,12,6,11,10,12,5,11,11,12,4,56,9,12,3,11,8,11,7,11,6,11,5,11,4,14,3,17,25,11,1,64,17,0,0,0,0,0,0,0,0,64,17,0,0,0,0,0,0,0,0,7,0,57,0,56,10,11,13,18,2,56,11,2,11,1,0,0,43,213,1,10,4,46,17,34,12,11,10,11,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,4,1,7,11,39,10,11,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,4,1,7,14,39,10,2,55,0,20,7,0,33,4,50,7,1,10,2,54,0,21,10,2,46,56,12,7,1,18,3,56,13,10,2,55,0,20,7,1,33,4,57,5,65,11,2,1,11,0,1,11,4,1,7,13,39,11,4,46,17,35,12,15,10,0,10,15,17,6,10,2,54,3,12,12,10,2,54,4,12,10,10,2,55,5,56,14,4,85,8,12,5,5,92,10,11,10,2,55,5,56,15,20,35,12,5,11,5,4,138,1,10,12,14,15,12,6,46,11,6,56,4,32,4,111,10,10,14,15,12,7,46,11,7,56,4,32,12,8,5,113,9,12,8,11,8,4,116,5,126,11,2,1,11,0,1,11,12,1,11,10,1,7,10,39,11,3,4,134,1,11,10,1,10,12,11,15,68,17,5,137,1,11,10,11,15,68,17,5,140,1,11,10,1,10,2,55,5,56,14,4,147,1,8,12,9,5,154,1,11,11,10,2,55,5,56,15,20,38,12,9,11,9,4,205,1,10,0,16,3,65,17,12,14,11,12,46,65,17,12,13,11,14,11,13,17,7,4,184,1,7,2,10,2,54,0,21,11,2,46,56,12,7,2,18,3,56,13,11,0,16,2,56,16,17,13,56,17,2,11,0,1,10,2,55,5,56,18,4,201,1,7,3,10,2,54,0,21,11,2,46,56,12,7,3,18,3,56,13,5,203,1,11,2,1,56,19,2,11,2,1,11,0,1,11,12,1,56,19,2,12,1,4,0,1,45,10,1,46,17,34,10,0,55,1,20,35,4,21,10,0,55,0,20,7,0,33,4,15,5,21,11,0,1,11,1,1,7,12,39,11,1,46,17,35,10,0,55,6,20,33,4,30,5,34,11,0,1,7,15,39,7,4,10,0,54,0,21,11,0,46,56,12,7,4,18,3,56,13,2,0,2,0,7,0,1,0,6,0,3,0,4,0,5,1,9,1,4,1,2,1,7,1,8,1,3,1,1,7,23,8,23,9,23,10,23,11,23,12,23,13,23,0],"governance_v2":[161,28,235,11,6,0,0,0,13,1,0,28,2,28,74,3,102,145,2,4,247,2,58,5,177,3,229,3,7,150,7,131,8,8,153,15,96,6,249,15,129,2,10,250,17,95,11,217,18,2,12,219,18,171,13,13,134,32,38,14,172,32,18,0,54,0,48,0,64,1,22,1,69,1,87,1,93,2,23,2,29,2,41,2,68,2,84,2,85,2,86,0,5,8,0,0,9,8,2,6,0,0,1,0,3,3,0,0,1,3,0,1,4,0,0,1,6,12,0,3,10,7,0,4,8,7,1,0,0,5,13,7,0,7,0,4,1,0,1,8,2,12,1,0,1,10,7,7,0,10,14,4,0,11,11,12,2,7,1,4,1,13,12,2,0,0,59,0,1,0,0,15,2,1,0,0,91,3,4,0,0,18,5,1,0,0,75,5,1,0,0,90,6,1,0,0,89,7,1,0,0,27,8,1,0,0,39,9,10,0,0,51,11,12,2,6,0,0,35,13,1,0,0,32,14,1,2,6,0,0,94,15,16,2,6,0,0,25,17,1,2,6,0,0,28,11,1,2,6,0,1,31,59,13,0,1,34,13,1,0,2,63,40,41,1,0,3,83,37,12,0,4,24,58,52,1,0,4,43,28,26,1,0,4,46,27,1,1,0,4,67,1,22,1,0,4,78,26,22,1,0,5,49,1,23,1,0,5,50,47,12,0,6,30,30,10,1,0,6,58,30,32,1,0,6,74,33,26,1,0,7,61,54,35,1,0,7,79,61,48,1,0,7,92,57,35,1,0,8,36,41,1,1,0,8,47,62,41,1,0,8,60,41,48,1,0,9,37,26,1,1,3,10,57,52,24,1,8,10,65,0,21,0,10,88,45,46,0,11,17,44,1,2,7,4,11,30,55,10,2,7,4,11,65,0,43,2,7,4,11,74,56,39,2,7,4,12,73,64,1,1,12,12,77,26,1,1,8,13,40,20,35,0,13,76,20,19,0,22,4,22,23,44,25,21,23,21,4,20,4,26,19,27,19,28,19,17,39,41,42,39,42,24,26,34,39,44,49,35,50,36,49,35,53,29,39,40,42,42,42,31,39,22,13,32,39,19,4,23,13,30,39,33,39,43,63,1,7,8,14,0,4,6,8,4,7,8,0,8,8,8,5,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,4,6,8,4,7,8,0,3,3,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,2,9,0,9,1,7,8,14,1,8,6,1,8,4,5,6,8,0,9,0,10,11,10,1,9,1,3,7,8,14,7,6,8,0,9,0,7,11,1,2,9,0,9,1,10,11,10,1,9,1,3,1,7,8,14,1,11,7,1,8,4,3,6,8,0,7,11,1,2,9,0,9,1,7,8,14,1,10,5,1,5,1,6,8,14,1,8,12,1,11,7,1,9,0,1,8,8,1,8,11,1,8,0,1,9,0,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,2,9,0,9,1,1,10,2,15,8,8,3,3,3,5,8,12,5,3,3,3,11,13,2,5,3,8,12,8,11,11,10,1,9,1,3,1,9,1,3,10,11,10,1,9,0,3,7,8,14,1,11,10,1,9,0,2,5,3,1,11,13,2,9,0,9,1,3,7,11,13,2,9,0,9,1,9,0,9,1,1,6,8,12,1,6,8,11,1,6,8,8,1,11,9,1,9,0,1,11,1,2,9,0,9,1,1,8,2,17,11,7,1,8,4,11,7,1,8,4,5,5,5,5,1,3,3,7,11,13,2,5,3,3,3,3,7,11,13,2,5,3,11,10,1,9,1,5,3,1,6,9,0,1,8,3,2,7,11,9,1,9,0,11,9,1,9,0,2,6,11,13,2,9,0,9,1,9,0,2,7,11,13,2,9,0,9,1,9,0,1,6,11,9,1,9,0,1,6,11,7,1,9,0,1,6,8,5,11,1,1,1,5,5,7,11,13,2,5,3,3,7,11,13,2,5,3,5,3,3,2,7,11,9,1,9,0,3,2,11,9,1,9,0,7,8,14,1,11,10,1,9,1,2,9,0,5,7,66,97,108,97,110,99,101,11,67,104,97,110,103,101,83,116,97,116,101,4,67,111,105,110,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,3,97,100,100,13,97,100,100,95,103,117,97,114,100,105,97,110,115,11,97,103,97,105,110,115,116,95,110,117,109,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,15,99,104,101,99,107,95,103,117,97,114,100,105,97,110,115,5,99,108,97,105,109,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,9,102,97,118,111,114,95,110,117,109,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,20,103,111,118,101,114,110,97,110,99,101,95,99,111,105,110,95,116,121,112,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,50,9,103,117,97,114,100,105,97,110,115,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,4,106,111,105,110,9,109,97,120,95,100,101,108,97,121,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,24,112,114,111,112,111,115,97,108,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,103,117,97,114,100,105,97,110,115,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,115,112,108,105,116,11,115,116,97,107,101,100,95,99,111,105,110,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,22,117,112,100,97,116,101,95,109,105,110,117,109,117,109,95,115,116,97,107,105,110,103,7,117,112,103,114,97,100,101,5,118,97,108,117,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,22,118,111,116,105,110,103,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,255,255,255,255,255,255,255,255,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,11,57,8,12,53,11,7,1,8,5,52,11,7,1,8,8,55,10,5,16,1,21,3,95,3,62,3,72,3,96,3,56,10,8,11,1,2,13,57,8,12,33,5,81,3,38,3,42,3,70,8,6,26,9,0,80,11,9,1,9,1,44,3,45,11,13,2,5,3,19,3,20,11,13,2,5,3,82,2,2,2,1,71,8,11,3,2,2,71,8,11,66,2,1,36,0,0,0,0,18,22,64,19,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,46,68,19,11,0,17,37,56,0,56,1,64,19,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,6,1,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,64,24,0,0,0,0,0,0,0,0,18,0,56,2,2,1,1,0,0,10,34,10,1,16,0,20,32,4,12,10,1,16,1,65,24,6,0,0,0,0,0,0,0,0,33,12,4,5,14,9,12,4,11,4,4,17,5,21,11,1,1,7,6,39,10,1,15,2,11,2,56,3,10,1,15,3,11,3,56,4,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,3,56,5,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,29,19,10,1,15,4,14,2,12,3,46,11,3,56,6,32,4,10,5,14,11,1,1,7,10,39,11,1,15,4,11,2,68,19,2,4,1,0,0,31,21,10,1,10,2,12,3,46,11,3,17,7,10,1,15,4,14,2,12,4,46,11,4,56,7,12,5,1,11,1,15,4,11,5,56,8,1,2,5,1,0,0,1,9,11,2,10,1,15,5,21,11,3,11,1,15,6,21,2,6,1,0,0,1,33,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,9,11,1,1,7,8,39,10,4,10,3,10,2,22,36,4,16,5,20,11,1,1,7,8,39,11,2,10,1,15,7,21,11,3,10,1,15,8,21,11,4,11,1,15,9,21,2,7,1,0,0,1,9,11,0,16,4,14,1,56,6,4,6,5,8,7,9,39,2,8,1,0,0,9,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,9,1,0,0,34,75,11,1,46,17,45,12,7,10,0,55,0,20,7,3,33,4,16,11,0,1,7,21,17,18,12,6,5,73,10,0,55,0,20,7,4,33,4,28,11,0,1,7,22,17,18,12,5,5,71,10,0,55,0,20,7,5,33,4,40,11,0,1,7,23,17,18,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,24,17,18,12,3,5,67,11,0,55,0,20,7,1,33,4,62,7,25,17,18,12,2,5,65,7,26,17,18,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,10,1,0,0,1,3,11,0,17,16,2,11,1,0,0,38,103,10,0,16,0,20,4,5,5,11,11,0,1,11,4,1,7,7,39,11,2,10,3,10,4,56,9,12,18,10,3,10,0,16,5,20,38,4,23,5,29,11,0,1,11,4,1,7,16,39,10,4,46,17,46,12,11,10,4,46,17,45,12,12,10,12,10,0,16,7,20,22,12,19,10,19,10,0,16,8,20,22,12,13,11,12,11,0,16,9,20,22,12,14,10,4,56,10,12,15,13,15,10,11,10,3,56,11,10,4,17,37,12,16,14,16,17,38,20,12,17,11,16,12,10,11,11,12,9,11,19,12,8,11,13,12,7,11,14,12,6,56,12,12,5,11,10,11,9,11,8,11,7,11,6,14,5,17,25,11,1,11,18,56,13,11,3,11,15,6,0,0,0,0,0,0,0,0,11,4,56,10,7,1,57,0,56,14,11,17,18,2,56,15,2,12,1,0,0,51,175,2,10,6,46,17,45,12,17,10,17,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,6,1,7,12,39,10,17,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,6,1,7,15,39,10,2,55,0,20,7,1,33,4,50,7,2,10,2,54,0,21,10,2,46,56,16,7,2,18,3,56,17,10,2,55,0,20,7,2,33,4,57,5,65,11,2,1,11,0,1,11,6,1,7,14,39,10,6,46,17,46,12,22,10,2,54,3,12,20,10,2,54,4,12,16,11,3,10,4,11,6,56,9,12,21,11,17,10,2,55,5,20,35,4,237,1,11,0,1,10,2,54,6,11,21,56,13,56,18,1,11,5,4,158,1,10,2,55,7,20,10,4,22,10,2,54,7,21,11,4,12,18,10,20,10,22,12,9,46,11,9,56,19,4,119,11,18,10,20,10,22,56,20,22,12,18,10,16,10,22,12,10,46,11,10,56,19,4,151,1,11,16,10,22,56,20,12,14,10,2,55,7,20,10,14,22,10,2,54,7,21,10,2,55,8,20,10,14,23,10,2,54,8,21,11,18,11,14,22,12,18,5,153,1,11,16,1,11,20,11,22,11,18,56,11,5,219,1,10,2,55,8,20,10,4,22,10,2,54,8,21,11,4,12,15,10,16,10,22,12,11,46,11,11,56,19,4,181,1,11,15,10,16,10,22,56,20,22,12,15,10,20,10,22,12,12,46,11,12,56,19,4,213,1,11,20,10,22,56,20,12,19,10,2,55,8,20,10,19,22,10,2,54,8,21,10,2,55,7,20,10,19,23,10,2,54,7,21,11,15,11,19,22,12,15,5,215,1,11,20,1,11,16,11,22,11,15,56,11,10,2,55,7,20,10,2,55,8,20,22,11,2,55,6,56,21,33,4,232,1,5,234,1,7,19,39,56,22,12,8,5,173,2,11,20,1,11,16,1,11,21,56,23,10,2,55,7,20,10,2,55,8,20,22,12,23,10,23,10,2,55,7,20,17,8,4,136,2,11,23,10,0,16,6,20,38,12,13,5,138,2,9,12,13,11,13,4,157,2,7,3,10,2,54,0,21,11,2,46,56,16,7,3,18,3,56,17,11,0,16,3,56,24,17,15,56,25,12,7,5,171,2,11,0,1,7,4,10,2,54,0,21,11,2,46,56,16,7,4,18,3,56,17,56,22,12,7,11,7,12,8,11,8,2,13,1,4,0,19,41,10,2,46,17,45,10,1,55,1,20,35,4,23,10,1,55,0,20,7,1,33,4,15,5,23,11,1,1,11,0,1,11,2,1,7,13,39,11,2,46,17,46,12,3,11,0,11,3,17,7,7,5,10,1,54,0,21,11,1,46,56,16,7,5,18,3,56,17,2,14,1,4,0,60,129,1,10,1,46,17,45,12,8,10,0,55,0,20,7,3,33,4,13,8,12,2,5,19,10,0,55,0,20,7,4,33,12,2,11,2,4,24,8,12,3,5,30,10,0,55,0,20,7,5,33,12,3,11,3,4,35,8,12,4,5,41,11,8,10,0,55,1,20,38,12,4,11,4,4,44,5,50,11,0,1,11,1,1,7,20,39,10,1,46,17,46,12,10,10,0,54,3,12,9,10,0,54,4,12,7,10,9,10,10,12,5,46,11,5,56,19,4,90,11,7,1,11,9,10,10,56,20,12,12,10,0,54,6,10,12,56,26,11,1,56,27,11,10,56,28,10,0,55,7,20,11,12,23,11,0,54,7,21,5,128,1,11,9,1,10,7,10,10,12,6,46,11,6,56,19,4,100,5,108,11,0,1,11,1,1,11,7,1,7,11,39,11,7,10,10,56,20,12,11,10,0,54,6,10,11,56,26,11,1,56,27,11,10,56,28,10,0,55,8,20,11,11,23,11,0,54,8,21,2,0,4,0,10,0,2,0,1,0,3,0,8,0,9,0,5,0,6,0,7,1,12,1,4,1,2,1,9,1,11,1,3,1,7,1,8,1,10,10,36,11,36,12,36,13,36,14,36,15,36,16,36,17,36,18,36,0],"lending_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,126,4,136,1,2,5,138,1,175,1,7,185,2,166,4,8,223,6,32,6,255,6,41,12,168,7,192,10,0,22,0,9,0,23,1,0,7,0,0,20,0,1,0,0,21,0,1,0,0,16,0,1,0,0,19,0,1,0,0,18,0,1,0,0,15,0,1,0,0,17,0,1,0,0,10,2,3,0,0,1,3,2,0,0,14,4,3,0,0,5,3,4,0,0,12,5,3,0,0,3,3,6,0,0,13,7,3,0,0,4,3,7,0,1,2,3,11,0,1,11,11,3,0,2,6,17,18,0,2,7,17,19,0,2,8,17,1,0,2,24,9,0,0,2,25,10,0,0,2,26,13,0,0,2,27,12,0,0,2,28,15,16,1,1,24,1,0,1,2,4,13,3,8,0,2,1,10,2,6,13,3,3,8,0,8,0,2,4,13,3,8,0,3,5,13,3,8,0,3,2,2,10,13,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,11,10,2,10,2,10,2,10,2,3,3,2,3,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,3,10,2,10,2,10,2,16,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,2,3,8,0,13,13,8,0,13,13,10,2,10,2,10,2,10,2,10,2,3,3,2,3,3,13,8,0,13,3,3,10,2,3,10,10,2,10,2,10,2,3,13,10,13,13,3,2,13,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,101,110,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,101,110,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,8,24,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,22,11,4,2,8,1,0,0,14,92,6,0,0,0,0,0,0,0,0,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,1,14,1,17,17,12,11,11,6,11,5,22,12,6,6,8,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,2,14,2,17,18,12,8,11,6,11,5,22,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,3,14,3,17,17,12,9,11,6,11,5,22,12,6,11,9,52,12,5,14,0,10,6,10,6,10,5,22,56,0,17,15,12,10,11,6,11,5,22,12,6,6,1,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,4,14,4,17,19,12,7,11,6,11,5,22,14,0,65,1,33,4,85,5,87,7,0,39,11,11,11,8,11,10,11,7,2,9,1,0,0,20,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,20,13,6,11,1,17,21,13,6,11,2,17,21,11,3,17,16,12,7,13,6,14,7,65,1,75,17,20,13,6,11,7,17,23,11,4,17,16,12,8,13,6,14,8,65,1,75,17,20,13,6,11,8,17,23,13,6,11,5,17,22,11,6,2,10,1,0,0,21,141,1,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,18,12,11,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,18,12,7,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,15,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,19,12,10,11,9,11,8,22,14,0,65,1,33,4,132,1,5,134,1,7,0,39,11,16,11,11,11,7,11,12,11,15,11,10,2,11,1,0,0,8,27,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,21,13,4,7,6,17,22,11,4,2,12,1,0,0,22,118,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,1,14,1,17,17,12,11,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,2,14,2,17,18,12,10,11,7,11,6,22,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,3,14,3,17,17,12,13,11,7,11,6,22,12,7,11,13,52,12,6,14,0,10,7,10,7,10,6,22,56,0,17,15,12,12,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,4,14,4,17,18,12,9,11,7,11,6,22,12,7,6,1,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,5,14,5,17,19,12,8,11,7,11,6,22,12,7,10,8,7,6,33,4,102,5,104,7,1,39,11,7,14,0,65,1,33,4,110,5,112,7,0,39,11,11,11,10,11,12,11,9,11,8,2,13,1,0,0,23,32,64,1,0,0,0,0,0,0,0,0,12,3,14,0,65,18,12,4,13,3,10,4,75,17,20,6,0,0,0,0,0,0,0,0,12,2,10,2,10,4,35,4,27,5,16,13,3,14,0,10,2,66,18,20,17,20,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,13,3,11,1,17,22,11,3,2,14,1,0,0,24,76,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,1,14,1,17,17,12,10,11,8,11,4,22,12,8,72,0,0,12,7,64,18,0,0,0,0,0,0,0,0,12,6,10,7,10,10,35,4,51,5,27,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,2,14,2,17,17,12,5,13,6,11,5,68,18,11,8,11,4,22,12,8,11,7,72,1,0,22,12,7,5,22,6,1,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,3,14,3,17,19,12,9,11,8,11,4,22,14,0,65,1,33,4,71,5,73,7,0,39,11,6,11,9,2,0],"lending_core_storage":[161,28,235,11,6,0,0,0,12,1,0,20,2,20,52,3,72,245,2,4,189,3,40,5,229,3,172,2,7,145,6,149,16,8,166,22,96,6,134,23,20,10,154,23,101,12,255,23,239,16,13,238,40,62,15,172,41,6,0,77,0,17,0,43,0,91,1,122,2,31,2,87,2,109,2,112,2,115,0,6,8,0,0,11,4,0,0,4,4,0,0,5,4,0,0,1,4,0,1,0,12,0,1,8,12,0,2,3,0,0,5,2,8,0,6,10,4,0,7,7,12,2,7,1,4,1,9,9,2,0,0,72,0,1,0,0,93,2,1,0,0,104,3,1,0,0,102,3,1,0,0,106,4,1,0,0,105,4,1,0,0,99,4,1,0,0,103,4,1,0,0,100,4,1,0,0,101,5,1,0,0,45,6,7,0,0,61,8,9,0,0,73,10,11,0,0,30,10,11,0,0,58,6,12,0,0,42,13,11,0,0,41,10,11,0,0,65,13,9,0,0,63,13,9,0,0,66,13,14,0,0,64,13,14,0,0,67,13,14,0,0,69,15,9,0,0,68,15,9,0,0,60,10,12,0,0,52,10,9,0,0,62,10,9,0,0,59,10,9,0,0,57,10,9,0,0,46,10,9,0,0,50,10,9,0,0,53,10,9,0,0,56,10,9,0,0,51,10,9,0,0,55,10,9,0,0,54,10,9,0,0,48,10,9,0,0,47,10,9,0,0,49,10,16,0,0,44,6,17,0,0,85,18,1,0,0,29,18,1,0,0,84,18,1,0,0,28,18,1,0,0,14,15,1,0,0,96,15,1,0,0,13,15,1,0,0,95,15,1,0,0,15,15,1,0,0,97,15,1,0,0,119,19,1,0,0,117,20,1,0,0,118,21,1,0,0,116,22,1,0,0,40,23,1,0,1,45,17,7,0,1,92,0,26,0,3,90,1,9,0,4,34,46,11,1,0,4,71,46,48,1,0,4,94,49,31,1,0,5,110,8,12,0,6,86,24,25,0,7,12,34,1,2,7,4,7,20,32,39,2,7,4,7,23,36,37,2,7,4,7,34,32,11,2,7,4,7,81,40,12,2,7,4,7,86,24,28,2,7,4,7,94,36,44,2,7,4,8,107,31,1,1,8,68,27,68,29,70,30,66,27,68,33,63,27,65,27,64,27,67,27,66,29,64,29,66,33,64,33,69,33,63,33,65,29,58,7,59,7,60,7,63,29,3,6,8,7,7,8,6,7,8,11,0,17,6,8,7,7,8,0,6,8,8,13,1,1,3,15,15,15,15,15,15,15,15,15,7,8,11,4,6,8,7,7,8,0,13,1,4,6,8,7,7,8,0,13,15,7,6,8,7,7,8,0,13,15,15,15,15,1,7,8,0,1,13,1,6,8,8,1,15,2,7,8,0,13,1,1,1,3,2,7,8,0,3,1,10,13,3,7,8,0,3,13,4,15,15,15,15,1,6,8,5,4,7,8,0,13,3,15,4,7,8,0,6,8,8,3,15,3,7,8,0,13,15,6,7,8,0,13,15,15,15,15,4,7,8,0,13,15,15,3,7,8,0,6,8,8,3,1,7,8,11,1,8,9,1,8,5,2,13,8,2,1,11,10,2,9,0,9,1,2,3,8,1,1,8,0,1,9,0,2,6,11,10,2,9,0,9,1,9,0,2,3,15,3,7,11,10,2,9,0,9,1,9,0,9,1,1,7,8,2,2,7,11,10,2,9,0,9,1,9,0,1,7,9,1,1,7,8,4,1,6,9,1,1,6,11,10,2,9,0,9,1,2,15,6,8,2,1,6,8,4,2,15,7,8,3,1,9,1,1,7,8,1,2,6,10,9,0,6,9,0,2,3,7,8,1,2,1,3,2,7,10,9,0,3,2,3,7,8,2,6,65,112,112,67,97,112,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,11,82,101,115,101,114,118,101,68,97,116,97,13,83,99,97,108,101,100,66,97,108,97,110,99,101,7,83,116,111,114,97,103,101,5,84,97,98,108,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,85,115,101,114,73,110,102,111,3,97,100,100,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,17,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,16,98,97,115,101,95,98,111,114,114,111,119,95,114,97,116,101,6,98,111,114,114,111,119,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,18,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,49,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,50,23,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,5,99,108,111,99,107,22,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,11,99,111,108,108,97,116,101,114,97,108,115,8,99,111,110,116,97,105,110,115,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,23,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,22,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,13,100,116,111,107,101,110,95,115,99,97,108,101,100,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,10,103,101,116,95,97,112,112,95,105,100,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,18,103,101,116,95,114,101,115,101,114,118,101,95,108,101,110,103,116,104,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,13,103,101,116,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,2,105,100,8,105,110,100,101,120,95,111,102,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,12,105,115,111,108,97,116,101,95,100,101,98,116,19,108,97,115,116,95,97,118,101,114,97,103,101,95,117,112,100,97,116,101,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,13,108,105,113,117,105,100,95,97,115,115,101,116,115,5,108,111,97,110,115,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,13,111,116,111,107,101,110,95,115,99,97,108,101,100,3,114,97,121,8,114,97,121,95,109,97,116,104,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,20,114,101,103,105,115,116,101,114,95,110,101,119,95,114,101,115,101,114,118,101,6,114,101,109,111,118,101,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,8,114,101,115,101,114,118,101,115,22,115,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,22,115,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,23,115,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,27,115,101,116,95,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,26,115,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,21,115,101,116,95,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,22,115,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,8,116,114,101,97,115,117,114,121,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,10,117,115,101,114,95,105,110,102,111,115,10,117,115,101,114,95,115,116,97,116,101,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,70,8,9,16,8,5,98,11,10,2,13,8,2,120,11,10,2,3,8,1,1,2,5,18,15,75,15,82,10,13,33,10,13,83,10,13,2,2,17,73,1,27,1,74,15,76,15,113,3,114,15,108,15,21,15,36,15,38,15,35,15,37,15,32,15,22,15,24,8,4,89,8,3,39,8,3,3,2,2,121,11,10,2,3,15,111,15,4,2,4,19,15,25,15,26,15,88,15,0,1,0,0,1,13,10,2,17,62,11,0,11,1,10,2,17,56,10,2,56,0,11,2,56,1,18,0,56,2,2,1,1,0,0,1,49,10,1,16,0,10,3,56,3,32,4,7,5,15,11,1,1,11,16,1,11,2,1,7,0,39,11,1,15,0,11,3,11,4,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,2,17,11,11,6,11,7,11,8,11,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,57,17,57,11,10,11,11,11,12,11,13,11,14,11,15,18,4,10,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,11,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,18,2,56,5,2,2,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,1,21,2,3,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,2,21,2,4,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,3,21,2,5,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,4,21,2,6,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,5,21,2,7,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,6,21,2,8,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,7,21,2,9,1,0,0,38,23,11,1,15,0,11,2,56,6,15,8,12,7,11,3,10,7,15,9,21,11,4,10,7,15,10,21,11,5,10,7,15,11,21,11,6,11,7,15,12,21,2,10,1,0,0,1,4,11,0,16,13,17,55,2,11,1,0,0,1,6,11,0,17,61,6,232,3,0,0,0,0,0,0,26,77,2,12,1,0,0,1,7,11,0,16,0,11,1,56,7,16,1,20,2,13,1,0,0,1,7,11,0,16,0,11,1,56,7,16,2,20,2,14,1,0,0,1,4,11,0,16,0,56,8,2,15,1,0,0,12,8,11,0,15,14,11,1,12,2,46,11,2,56,9,2,16,1,0,0,7,8,11,0,15,0,11,1,12,2,46,11,2,56,3,2,17,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,15,20,2,18,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,16,20,2,19,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,17,20,2,20,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,18,20,2,21,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,19,20,2,22,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,20,16,21,10,1,56,11,4,19,11,4,16,20,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,23,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,22,16,21,10,1,56,11,4,19,11,4,16,22,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,24,1,0,0,1,7,11,0,16,0,11,1,56,7,16,23,20,2,25,1,0,0,1,7,11,0,16,0,11,1,56,7,16,24,20,2,26,1,0,0,1,7,11,0,16,0,11,1,56,7,16,3,20,2,27,1,0,0,1,7,11,0,16,0,11,1,56,7,16,4,20,2,28,1,0,0,1,7,11,0,16,0,11,1,56,7,16,5,20,2,29,1,0,0,1,7,11,0,16,0,11,1,56,7,16,7,20,2,30,1,0,0,1,7,11,0,16,0,11,1,56,7,16,6,20,2,31,1,0,0,1,7,11,0,16,0,11,1,56,7,16,25,20,2,32,1,0,0,1,8,11,0,16,0,11,1,56,7,16,20,16,26,20,2,33,1,0,0,1,8,11,0,16,0,11,1,56,7,16,22,16,26,20,2,34,1,0,0,1,7,11,0,16,0,11,1,56,7,16,27,20,2,35,1,0,0,1,7,11,0,16,0,11,1,56,7,16,28,20,2,36,1,0,0,1,7,11,0,16,0,11,1,56,7,16,29,20,2,37,1,0,0,1,7,11,0,16,0,11,1,56,7,16,30,20,2,38,1,0,0,42,19,11,0,16,0,11,1,56,7,16,8,12,2,10,2,16,9,20,10,2,16,10,20,10,2,16,11,20,11,2,16,12,20,2,39,3,0,0,1,3,11,0,16,13,2,40,3,0,0,43,35,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,41,3,0,0,43,44,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,42,3,0,0,43,35,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,43,3,0,0,43,44,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,44,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,17,14,2,56,16,32,4,16,11,3,15,17,11,2,68,7,5,18,11,3,1,2,45,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,17,14,2,56,17,12,3,4,17,11,4,15,17,11,3,56,18,1,5,19,11,4,1,2,46,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,18,14,2,56,16,32,4,16,11,3,15,18,11,2,68,7,5,18,11,3,1,2,47,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,18,14,2,56,17,12,3,4,17,11,4,15,18,11,3,56,18,1,5,19,11,4,1,2,48,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,19,14,2,56,16,32,4,16,11,3,15,19,11,2,68,7,5,18,11,3,1,2,49,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,19,14,2,56,17,12,3,4,17,11,4,15,19,11,3,56,18,1,5,19,11,4,1,2,50,3,0,0,45,15,11,0,15,14,11,2,56,15,12,4,11,1,17,11,10,4,15,15,21,11,3,11,4,15,16,21,2,51,3,0,0,35,10,11,0,15,0,11,1,56,6,12,3,11,2,11,3,15,24,21,2,52,3,0,0,50,30,10,0,15,0,10,1,56,6,12,7,11,2,10,7,15,30,21,11,3,10,7,15,28,21,11,4,11,7,15,25,21,10,0,16,0,10,1,56,7,16,23,20,12,6,11,0,11,1,11,6,11,5,17,40,2,53,3,0,0,35,14,11,0,15,0,11,1,56,6,12,4,11,2,10,4,15,29,21,11,3,11,4,15,27,21,2,54,1,0,0,12,26,10,0,15,14,10,2,12,3,46,11,3,56,9,32,4,21,11,0,15,14,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,1,17,11,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,18,1,56,19,5,25,11,0,1,11,1,1,2,0,2,2,0,2,1,2,5,2,6,2,7,2,12,2,13,2,14,4,0,4,1,4,2,4,3,0,1,0,3,1,1,1,0,1,2,1,3,1,4,2,15,3,0,2,16,2,4,2,2,2,3,3,1,2,9,2,11,2,8,2,10,0,78,0,79,0,80,0],"lending_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,36,2,36,68,3,104,198,1,4,174,2,8,5,182,2,233,3,7,159,6,228,8,8,131,15,128,1,6,131,16,30,10,161,16,36,12,197,16,230,11,0,58,0,17,0,30,0,42,0,56,0,57,0,59,0,64,0,65,0,80,0,82,1,63,2,23,2,24,2,35,2,77,2,79,3,76,0,6,3,0,0,10,3,0,1,0,12,0,2,4,7,0,3,5,8,0,5,13,8,0,7,9,8,0,8,8,12,0,9,15,12,0,10,3,12,0,11,7,7,1,0,0,12,1,8,0,13,2,12,1,0,1,15,11,2,0,16,14,2,0,17,12,12,0,0,78,0,1,0,0,81,2,1,0,0,19,2,1,0,0,70,0,1,0,0,60,0,1,0,0,18,0,1,0,0,21,0,1,0,2,47,17,14,0,2,48,17,10,0,3,22,4,1,0,4,25,14,15,0,4,26,14,35,0,4,27,14,38,0,4,28,14,23,0,4,44,1,16,0,4,45,1,16,0,4,46,1,16,0,4,52,1,16,0,4,53,1,16,0,4,54,1,16,0,5,43,5,6,0,6,18,39,1,0,6,21,39,1,0,6,36,13,1,0,6,37,36,1,0,6,38,13,1,0,6,39,13,1,0,6,40,13,30,0,8,41,24,25,0,8,50,9,10,0,8,51,9,30,0,9,49,11,12,0,10,66,7,8,0,10,67,21,22,0,10,68,21,22,0,10,71,31,12,0,11,29,29,19,1,0,11,55,27,28,1,0,14,34,19,1,1,3,38,18,37,26,36,26,38,32,10,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,10,2,6,8,11,7,8,14,0,11,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,11,12,1,8,13,10,2,6,8,11,7,8,14,17,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,10,2,2,13,3,3,8,3,8,3,13,8,3,1,6,8,4,1,7,8,5,1,6,8,2,8,7,8,15,7,8,9,6,8,2,10,2,7,8,7,7,8,8,6,8,11,7,8,14,4,8,3,8,3,15,10,2,2,7,8,7,8,3,1,13,2,6,8,8,8,3,1,3,7,6,8,7,7,8,5,7,8,6,6,8,11,3,13,15,1,10,2,4,13,3,8,3,2,1,2,1,6,8,3,1,8,0,1,9,0,27,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,6,7,8,15,7,8,9,6,8,2,10,2,6,8,11,7,8,14,2,8,3,10,2,6,13,3,3,8,3,8,3,2,3,7,8,7,13,13,1,11,10,1,8,3,1,8,3,1,6,11,10,1,9,0,1,1,1,11,10,1,9,0,1,15,11,7,8,15,7,8,9,6,8,2,7,8,7,8,3,8,3,13,3,15,11,12,1,8,13,6,8,11,1,8,1,26,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,26,7,8,5,7,8,6,6,8,11,3,3,13,13,8,3,7,8,5,7,8,6,6,8,11,3,13,15,10,2,2,15,13,8,3,8,3,3,3,3,13,13,8,3,5,13,3,8,3,3,2,8,6,8,7,7,8,5,7,8,6,6,8,11,3,3,13,13,14,8,3,7,8,5,7,8,6,6,8,11,3,13,10,2,2,6,13,10,13,3,3,3,8,3,2,10,13,2,6,6,8,7,7,8,5,7,8,6,6,8,11,3,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,76,101,110,100,105,110,103,67,111,114,101,69,118,101,110,116,6,79,112,116,105,111,110,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,6,98,111,114,114,111,119,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,112,111,111,108,95,105,100,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,9,108,105,113,117,105,100,97,116,101,17,108,105,113,117,105,100,97,116,101,95,117,115,101,114,95,105,100,5,110,111,110,99,101,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,5,114,101,112,97,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,14,115,101,110,100,101,114,95,117,115,101,114,95,105,100,8,115,101,113,117,101,110,99,101,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,18,115,111,117,114,99,101,95,99,104,97,105,110,95,110,111,110,99,101,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,9,62,3,72,3,74,13,32,13,31,13,69,10,2,16,15,61,3,20,2,1,2,5,73,3,74,13,75,3,33,8,3,20,2,0,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,26,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,18,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,1,1,4,0,20,168,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,26,12,37,11,26,17,13,12,27,12,35,12,34,12,24,12,33,12,36,10,27,17,19,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,24,77,12,25,10,1,11,34,17,29,12,28,11,2,11,37,12,16,46,11,16,17,31,12,29,14,35,17,8,12,30,10,1,10,28,11,30,17,28,12,31,14,31,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,31,56,2,12,32,10,1,10,6,11,5,10,9,10,29,10,28,11,25,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,27,12,23,10,1,10,32,17,30,10,23,38,4,113,5,125,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,32,10,35,10,36,10,33,10,23,11,7,11,9,17,35,12,11,11,32,12,12,10,36,12,13,10,33,12,14,10,27,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,33,11,29,11,36,14,35,17,8,11,28,14,35,17,7,11,23,6,0,0,0,0,0,0,0,0,11,27,18,0,56,0,2,2,1,4,0,33,167,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,25,12,36,11,25,17,13,12,26,12,34,12,33,12,23,12,32,12,35,10,26,17,15,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,23,77,12,24,10,1,11,33,17,29,12,27,11,2,11,36,12,16,46,11,16,17,31,12,28,14,34,17,8,12,29,10,1,10,27,11,29,17,28,12,30,14,30,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,30,56,2,12,31,10,1,10,6,11,5,10,9,10,28,10,27,10,24,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,23,10,1,10,31,17,30,10,24,38,4,112,5,124,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,31,10,34,10,35,10,32,10,24,11,7,11,9,17,35,12,11,11,31,12,12,10,35,12,13,10,32,12,14,10,26,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,32,11,28,11,35,14,34,17,8,11,27,14,34,17,7,11,24,6,0,0,0,0,0,0,0,0,11,26,18,0,56,0,2,3,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,25,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,17,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,4,1,4,0,34,97,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,24,12,26,12,29,12,28,11,24,17,11,12,25,12,30,12,35,12,32,12,33,11,2,10,29,12,17,46,11,17,17,31,12,31,10,1,11,28,17,29,12,27,10,1,11,35,17,29,12,34,10,1,10,6,10,5,10,8,10,31,10,27,10,26,12,23,12,22,12,21,12,20,12,19,12,18,46,11,18,11,19,11,20,11,21,11,22,11,23,17,26,11,1,11,6,11,5,11,8,10,31,10,30,10,34,11,27,12,16,12,15,12,14,12,13,12,12,12,11,12,10,46,11,10,11,11,11,12,11,13,11,14,11,15,11,16,17,24,11,32,11,31,11,33,14,29,17,8,11,34,14,29,17,7,11,26,11,30,11,25,18,0,56,0,2,5,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,14,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,21,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,6,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,16,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,22,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,0],"lending_logic":[161,28,235,11,6,0,0,0,11,1,0,27,2,27,24,3,51,189,4,4,240,4,4,5,244,4,199,3,7,187,8,241,18,8,172,27,96,6,140,28,144,2,10,156,30,15,12,171,30,253,36,15,168,67,4,0,93,0,48,0,90,0,91,0,104,0,106,0,108,0,111,0,117,1,135,1,2,35,2,40,2,95,0,2,3,0,1,1,0,0,3,5,8,0,4,4,8,0,5,3,12,0,10,0,8,0,0,42,0,1,0,0,44,2,1,0,0,45,2,3,0,0,41,2,1,0,0,43,2,1,0,0,11,4,1,0,0,31,4,1,0,0,34,5,1,0,0,103,6,7,0,0,102,8,7,0,0,83,9,7,0,0,85,10,7,0,0,88,11,7,0,0,84,11,7,0,0,89,11,7,0,0,87,12,7,0,0,33,13,1,0,0,81,12,7,0,0,82,10,7,0,0,128,1,10,3,0,0,126,14,3,0,0,125,11,3,0,0,132,1,14,3,0,0,131,1,11,3,0,0,127,10,3,0,0,129,1,10,3,0,0,133,1,10,3,0,0,134,1,10,3,0,0,28,15,3,0,0,19,15,3,0,0,24,10,3,0,0,25,16,3,0,0,27,17,18,0,0,18,19,20,0,0,119,9,3,0,0,118,9,3,0,0,37,12,1,0,0,99,21,1,0,0,15,21,1,0,0,97,21,1,0,0,13,21,1,0,0,6,8,1,0,0,113,8,1,0,0,120,22,1,0,0,123,23,1,0,0,121,24,1,0,2,51,1,27,0,2,55,1,27,0,2,56,1,27,0,2,61,1,27,0,2,65,1,27,0,2,69,1,27,0,2,80,1,27,0,3,7,11,1,0,3,8,11,1,0,3,9,11,1,0,3,14,53,1,0,3,16,53,1,0,3,30,9,7,0,3,39,30,1,0,3,46,9,7,0,3,47,12,7,0,3,49,61,31,0,3,52,9,3,0,3,53,9,3,0,3,54,9,3,0,3,57,9,3,0,3,58,9,3,0,3,59,9,3,0,3,60,9,3,0,3,62,9,3,0,3,63,9,3,0,3,64,9,3,0,3,66,9,3,0,3,67,9,3,0,3,68,9,26,0,3,70,57,3,0,3,72,9,3,0,3,73,12,3,0,3,74,12,37,0,3,75,12,3,0,3,76,12,37,0,3,77,12,37,0,3,78,11,3,0,3,79,11,3,0,3,86,9,7,0,3,98,53,1,0,3,100,53,1,0,3,114,11,1,0,3,115,11,1,0,3,116,11,1,0,3,121,63,1,0,3,122,6,1,0,3,123,60,1,0,3,124,58,1,0,4,32,32,1,0,4,71,47,48,0,5,50,62,3,0,6,20,20,3,0,6,21,6,3,0,6,22,33,3,0,6,23,33,3,0,6,26,63,3,0,7,96,18,3,0,7,109,1,3,0,7,110,18,3,0,7,112,18,3,0,8,12,18,3,0,8,17,18,3,0,8,101,18,3,0,9,36,39,7,1,0,11,38,29,1,1,3,12,107,49,26,0,111,28,110,31,8,6,8,4,7,8,2,7,8,3,6,8,5,3,3,13,13,0,7,6,8,4,7,8,2,7,8,3,6,8,5,3,13,15,1,15,6,6,8,4,7,8,2,7,8,3,6,8,5,3,13,7,6,8,1,6,8,4,7,8,2,6,8,5,13,3,15,3,7,8,2,13,15,1,1,3,7,8,2,3,15,2,7,8,2,13,3,7,8,2,7,8,3,3,3,7,8,2,3,13,2,7,8,2,3,4,7,8,3,7,8,2,3,6,8,5,4,7,8,2,7,8,3,3,13,3,7,8,3,13,15,4,7,8,2,7,8,3,3,3,6,7,8,2,7,8,3,3,3,13,13,2,15,15,7,7,8,3,13,15,13,15,15,15,4,15,15,15,15,4,7,8,2,3,13,15,4,7,8,2,7,8,3,6,8,5,3,3,7,8,2,6,8,5,13,4,6,8,4,7,8,2,13,15,12,1,15,15,15,15,15,15,15,15,3,15,15,1,3,1,2,1,8,0,1,9,0,3,7,8,2,6,8,5,3,1,13,3,7,8,3,10,13,6,8,5,3,15,15,15,5,15,15,15,15,3,3,1,15,15,5,1,15,6,13,15,10,13,1,10,13,2,1,10,13,2,6,10,9,0,6,9,0,3,1,13,10,13,2,10,13,10,13,7,6,13,15,15,10,13,3,3,15,7,15,3,3,6,13,15,10,13,15,6,6,13,15,10,13,3,3,15,6,3,3,6,13,15,10,13,15,2,2,15,2,7,8,3,13,3,15,2,3,2,3,2,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,6,15,15,15,15,15,15,6,15,3,3,6,13,10,13,3,4,7,8,2,13,3,15,3,6,13,15,10,13,5,15,6,13,15,15,10,13,7,15,15,15,15,15,15,15,1,6,8,5,4,7,8,2,6,8,5,3,15,9,15,15,15,15,15,15,15,15,15,6,7,8,2,13,15,15,15,15,1,7,8,2,3,6,8,4,13,13,4,7,8,2,13,15,15,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,23,76,101,110,100,105,110,103,67,111,114,101,69,120,101,99,117,116,101,69,118,101,110,116,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,16,97,100,100,95,105,115,111,108,97,116,101,95,100,101,98,116,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,6,97,109,111,117,110,116,13,97,115,95,99,111,108,108,97,116,101,114,97,108,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,100,116,111,107,101,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,111,116,111,107,101,110,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,115,99,97,108,101,100,28,99,97,108,99,117,108,97,116,101,95,97,99,116,117,97,108,95,108,105,113,117,105,100,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,35,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,98,97,115,101,95,100,105,115,99,111,117,110,116,30,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,100,105,115,99,111,117,110,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,25,99,97,108,99,117,108,97,116,101,95,109,97,120,95,108,105,113,117,105,100,97,116,105,111,110,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,9,99,97,108,108,95,116,121,112,101,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,22,99,104,101,99,107,95,117,115,101,114,95,102,114,101,115,104,95,112,114,105,99,101,19,99,108,97,105,109,95,102,114,111,109,95,116,114,101,97,115,117,114,121,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,13,99,111,118,101,114,95,100,101,102,105,99,105,116,4,101,109,105,116,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,13,103,101,116,95,116,105,109,101,115,116,97,109,112,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,14,104,97,115,95,99,111,108,108,97,116,101,114,97,108,11,104,97,115,95,100,101,102,105,99,105,116,19,105,115,95,98,111,114,114,111,119,97,98,108,101,95,97,115,115,101,116,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,17,105,115,95,105,115,111,108,97,116,105,111,110,95,109,111,100,101,15,105,115,95,108,105,113,117,105,100,95,97,115,115,101,116,7,105,115,95,108,111,97,110,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,109,97,116,104,3,109,105,110,11,109,105,110,116,95,100,116,111,107,101,110,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,111,116,111,107,101,110,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,24,110,111,116,95,114,101,97,99,104,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,24,110,111,116,95,114,101,97,99,104,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,6,111,114,97,99,108,101,7,112,111,111,108,95,105,100,12,112,111,111,108,95,109,97,110,97,103,101,114,3,112,111,119,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,19,114,101,100,117,99,101,95,105,115,111,108,97,116,101,95,100,101,98,116,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,19,116,111,116,97,108,95,100,116,111,107,101,110,95,115,117,112,112,108,121,19,116,111,116,97,108,95,111,116,111,107,101,110,95,115,117,112,112,108,121,24,117,112,100,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,7,117,115,101,114,95,105,100,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,27,117,115,101,114,95,116,111,116,97,108,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,21,117,115,101,114,95,116,111,116,97,108,95,108,111,97,110,95,118,97,108,117,101,6,118,101,99,116,111,114,11,118,105,111,108,97,116,111,114,95,105,100,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,15,32,0,0,0,200,165,25,144,185,165,111,165,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,34,76,160,196,199,203,249,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,0,2,5,130,1,3,10,15,105,13,136,1,3,29,2,0,3,0,0,25,233,1,10,1,10,5,10,6,17,13,4,6,5,16,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,5,10,7,17,14,4,22,5,32,11,1,1,11,0,1,11,2,1,11,3,1,7,8,39,10,1,10,4,10,7,17,13,4,38,5,48,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,3,10,7,17,44,10,1,10,3,10,6,17,44,10,1,10,2,10,3,10,4,17,43,10,2,10,1,10,5,10,3,17,16,10,1,10,2,10,5,17,11,32,4,73,5,83,11,1,1,11,0,1,11,2,1,11,3,1,7,6,39,10,1,10,2,10,4,10,5,10,6,10,7,17,32,12,15,12,14,10,1,10,6,17,77,12,18,10,1,10,4,10,7,17,21,12,16,10,2,10,6,11,14,10,7,11,15,11,16,11,18,17,33,12,19,12,11,12,10,12,9,10,1,10,6,17,75,12,17,10,1,10,5,10,7,10,10,17,40,10,1,10,5,10,6,10,9,17,38,10,1,10,4,10,7,11,10,17,38,10,1,11,17,10,6,11,19,17,37,10,1,10,2,10,5,17,18,4,145,1,10,1,10,5,17,36,10,1,10,4,10,6,17,14,4,184,1,10,1,10,4,10,6,17,23,12,13,10,13,10,11,17,103,12,12,10,1,10,4,10,6,11,12,17,40,10,11,10,13,36,4,183,1,10,1,10,4,10,6,17,90,10,1,10,4,10,6,11,11,11,13,23,17,37,10,1,10,4,10,6,17,54,5,210,1,10,1,10,4,10,6,11,11,17,37,10,1,10,4,10,6,17,13,32,4,202,1,10,1,10,4,10,6,17,12,32,12,8,5,204,1,9,12,8,11,8,4,210,1,10,1,10,4,10,6,17,54,10,0,10,1,10,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,0,10,1,11,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,5,17,43,11,4,11,9,11,6,11,5,17,49,18,0,56,0,2,1,3,0,0,7,128,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,4,10,5,17,14,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,18,39,10,1,10,5,10,6,17,8,4,42,5,52,11,1,1,11,0,1,11,2,1,11,3,1,7,19,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,10,6,17,37,10,1,10,4,10,5,17,13,32,4,74,10,1,10,4,10,5,17,12,32,12,7,5,76,9,12,7,11,7,4,110,10,1,10,4,17,15,4,87,10,1,10,4,10,5,17,54,5,110,10,1,10,4,17,17,32,4,97,10,1,10,4,10,5,17,53,5,110,10,1,10,5,17,85,4,106,10,1,10,4,10,5,17,54,5,110,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,51,18,0,56,0,2,2,3,0,0,18,95,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,21,12,8,11,6,10,8,17,103,12,7,10,1,10,4,10,5,10,7,17,38,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,48,5,58,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,10,7,11,8,33,4,76,10,1,10,4,10,5,17,13,4,72,10,1,10,4,10,5,17,88,5,76,10,1,10,4,10,5,17,89,11,0,10,1,10,5,10,7,17,45,11,1,11,2,11,3,10,4,17,43,11,4,10,7,11,5,6,0,0,0,0,0,0,0,0,17,52,18,0,56,0,11,7,2,3,3,0,0,1,170,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,13,32,4,30,5,40,11,1,1,11,0,1,11,2,1,11,3,1,7,3,39,10,1,10,4,10,5,17,12,32,4,47,5,57,11,1,1,11,0,1,11,2,1,11,3,1,7,4,39,10,1,10,5,17,10,4,62,5,72,11,1,1,11,0,1,11,2,1,11,3,1,7,13,39,10,1,10,4,17,15,4,111,10,1,10,5,17,58,4,81,5,91,11,1,1,11,0,1,11,2,1,11,3,1,7,12,39,10,1,10,4,10,6,17,9,4,97,5,107,11,1,1,11,0,1,11,2,1,11,3,1,7,11,39,10,1,10,4,10,6,17,41,10,1,10,4,10,5,17,14,32,4,121,10,1,10,4,10,5,17,55,10,1,10,4,10,5,10,6,17,39,10,2,10,1,10,4,10,3,17,16,10,2,10,5,64,31,1,0,0,0,0,0,0,0,10,3,17,95,10,1,10,2,10,4,17,11,4,142,1,5,152,1,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,10,6,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,47,18,0,56,0,2,4,3,0,0,33,88,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,23,12,7,10,6,10,7,17,103,12,9,10,1,10,4,10,5,10,9,17,40,10,1,10,4,17,15,4,45,10,1,10,4,10,9,17,42,10,6,10,7,38,4,70,10,1,10,4,10,5,17,90,11,6,11,7,23,12,8,10,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,10,1,10,4,10,5,11,8,17,37,10,1,10,4,10,5,17,54,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,9,11,5,6,0,0,0,0,0,0,0,0,17,50,18,0,56,0,2,5,3,0,0,1,82,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,12,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,14,39,10,1,10,4,17,15,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,15,39,10,1,10,4,17,17,4,56,10,1,10,5,17,85,32,4,46,5,56,11,1,1,11,0,1,11,2,1,11,3,1,7,17,39,10,1,10,4,10,5,17,89,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,46,18,0,56,0,2,6,3,0,0,1,67,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,13,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,4,10,5,17,88,10,1,10,4,10,5,17,54,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,39,5,49,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,48,18,0,56,0,2,7,1,0,0,34,49,10,2,11,3,10,4,17,44,10,2,10,4,17,75,12,11,10,2,10,11,10,4,17,21,12,10,10,2,10,11,10,4,17,23,12,9,10,10,10,9,36,4,27,11,10,11,9,23,12,7,5,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,11,6,17,103,12,8,10,2,11,11,10,4,10,8,17,38,10,2,11,5,10,4,11,8,17,37,11,1,11,2,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,2,8,1,0,0,35,23,10,0,10,1,17,74,12,4,11,0,11,1,17,34,12,5,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,15,8,12,3,5,21,11,5,11,2,22,11,4,35,12,3,11,3,2,9,1,0,0,36,33,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,5,10,0,10,5,20,17,73,12,4,11,0,11,5,20,17,68,12,6,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,8,12,3,5,31,11,6,11,2,22,11,4,35,12,3,11,3,2,10,1,0,0,1,6,11,0,11,1,17,63,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,2,11,1,0,0,1,7,11,0,11,1,11,2,17,19,17,104,36,2,12,1,0,0,38,19,10,0,10,1,17,61,4,13,11,0,11,1,17,81,12,4,14,4,14,2,56,1,12,3,5,17,11,0,1,9,12,3,11,3,2,13,1,0,0,37,8,11,0,11,1,17,79,12,3,14,3,14,2,56,1,2,14,1,0,0,37,8,11,0,11,1,17,82,12,3,14,3,14,2,56,1,2,15,1,0,0,40,25,10,0,11,1,17,79,12,4,14,4,65,31,6,1,0,0,0,0,0,0,0,33,4,19,14,4,6,0,0,0,0,0,0,0,0,66,31,20,12,3,11,0,11,3,17,85,12,2,5,23,11,0,1,9,12,2,11,2,2,16,1,0,0,41,17,10,1,10,2,17,79,12,4,11,1,11,2,17,82,12,5,10,0,11,4,10,3,17,95,11,0,11,5,11,3,17,95,2,17,1,0,0,37,9,11,0,11,1,17,79,12,2,14,2,65,31,6,0,0,0,0,0,0,0,0,36,2,18,1,0,0,35,23,10,0,10,1,10,2,17,26,12,4,11,0,11,1,11,2,17,27,12,5,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,12,3,5,21,9,12,3,11,3,2,19,1,0,0,33,23,10,0,10,1,10,2,17,24,12,4,11,0,11,1,11,2,17,25,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,19,11,4,11,5,17,105,12,3,5,21,7,0,12,3,11,3,2,20,1,0,0,3,10,11,0,11,2,10,3,17,21,12,4,11,1,11,3,11,4,17,28,2,21,1,0,0,18,13,10,0,11,1,10,2,17,84,12,4,11,0,11,2,17,70,12,3,11,4,11,3,17,107,2,22,1,0,0,3,10,11,0,11,2,10,3,17,23,12,4,11,1,11,3,11,4,17,28,2,23,1,0,0,18,13,10,0,11,1,10,2,17,83,12,4,11,0,11,2,17,64,12,3,11,4,11,3,17,107,2,24,1,0,0,42,49,10,0,10,2,17,79,12,6,14,6,65,31,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,43,5,16,14,6,10,7,66,31,12,3,10,0,10,3,20,17,66,12,4,10,0,10,1,10,2,11,3,20,17,20,12,5,11,9,11,5,11,4,17,106,22,12,9,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,11,11,0,1,11,1,1,11,9,2,25,1,0,0,43,49,10,0,10,2,17,82,12,8,14,8,65,31,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,43,5,16,14,8,10,4,66,31,12,6,10,0,10,6,20,17,63,12,3,10,0,10,1,10,2,11,6,20,17,22,12,7,11,9,11,7,11,3,17,106,22,12,9,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,11,11,0,1,11,1,1,11,9,2,26,1,0,0,44,42,10,0,10,2,17,79,12,5,14,5,65,31,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,36,5,16,14,5,10,6,66,31,12,3,10,0,10,1,10,2,11,3,20,17,20,12,4,11,8,11,4,22,12,8,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,11,11,0,1,11,1,1,11,8,2,27,1,0,0,45,42,10,0,10,2,17,82,12,7,14,7,65,31,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,36,5,16,14,7,10,3,66,31,12,5,10,0,10,1,10,2,11,5,20,17,22,12,6,11,8,11,6,22,12,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,11,11,0,1,11,1,1,11,8,2,28,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,11,4,24,6,10,0,0,0,0,0,0,0,11,3,17,112,77,26,2,29,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,6,10,0,0,0,0,0,0,0,11,3,17,112,77,24,11,4,26,2,30,1,0,0,18,16,10,0,10,1,10,2,17,24,12,3,11,0,11,1,11,2,17,25,12,4,17,104,11,3,11,4,17,105,23,2,31,1,0,0,20,52,10,0,10,3,17,61,4,5,5,11,11,0,1,11,1,1,7,16,39,10,0,10,2,17,61,4,16,5,22,11,0,1,11,1,1,7,16,39,10,0,10,1,10,3,17,30,12,5,10,0,11,2,17,78,12,4,11,0,11,1,11,3,17,25,12,7,11,4,74,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,24,17,105,17,104,17,103,17,104,22,12,6,11,5,11,6,17,106,7,1,17,103,2,32,1,0,0,50,89,10,0,10,1,11,2,10,3,17,31,12,12,10,0,10,1,10,3,17,24,12,10,10,0,10,1,10,3,17,25,12,11,10,0,10,5,17,63,12,6,10,0,10,4,17,66,12,7,11,11,7,2,17,106,11,10,23,12,19,7,2,17,104,10,12,23,17,106,11,6,17,106,11,7,23,12,18,11,19,11,18,17,105,12,14,10,0,10,1,10,3,10,4,17,20,10,14,17,105,12,8,10,14,17,104,11,12,23,17,106,12,16,11,0,10,1,11,3,10,5,17,22,10,16,17,105,12,9,11,8,11,9,17,103,17,104,17,103,12,17,10,1,11,4,11,14,10,17,17,106,17,29,12,13,11,1,11,5,11,16,11,17,17,106,17,29,12,15,11,13,11,15,2,33,1,0,0,51,45,10,5,10,4,38,4,9,11,4,12,8,11,2,12,7,5,17,11,5,12,8,11,2,10,8,11,4,17,105,17,106,12,7,10,0,10,1,10,7,17,28,12,9,10,0,11,3,10,8,17,28,12,11,11,0,11,1,11,9,11,11,23,17,29,11,6,17,106,12,12,10,7,10,12,23,12,10,11,7,11,8,11,10,11,12,2,34,1,0,0,18,12,10,0,10,1,17,72,12,3,11,0,11,1,17,70,12,2,11,3,11,2,17,106,2,35,1,0,0,18,12,10,0,10,1,17,67,12,3,11,0,11,1,17,64,12,2,11,3,11,2,17,106,2,36,0,0,0,52,49,10,0,10,1,17,82,12,6,14,6,65,31,12,4,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,46,5,14,14,6,10,3,66,31,12,5,10,0,10,5,20,17,75,12,7,10,0,10,1,10,5,20,17,23,12,2,10,0,10,1,10,5,20,10,2,17,40,10,0,11,7,11,5,20,11,2,17,39,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,9,11,0,1,2,37,0,0,0,3,12,11,3,10,0,10,2,17,70,17,109,12,4,11,0,11,2,11,1,11,4,17,87,2,38,0,0,0,3,12,11,3,10,0,10,2,17,70,17,108,12,4,11,0,11,2,11,1,11,4,17,57,2,39,0,0,0,3,12,11,3,10,0,10,2,17,64,17,109,12,4,11,0,11,2,11,1,11,4,17,86,2,40,0,0,0,3,12,11,3,10,0,10,2,17,64,17,108,12,4,11,0,11,2,11,1,11,4,17,56,2,41,0,0,0,54,21,10,0,11,1,17,79,12,5,14,5,6,0,0,0,0,0,0,0,0,66,31,12,3,10,0,10,3,20,17,68,11,2,22,12,4,11,0,11,3,20,11,4,17,92,2,42,0,0,0,55,32,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,4,10,0,10,4,20,17,68,12,5,10,5,10,2,38,4,22,11,5,11,2,23,12,3,5,24,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,12,6,11,0,11,4,20,11,6,17,92,2,43,0,0,0,56,58,10,0,10,3,17,61,4,51,10,2,17,76,12,5,10,0,10,3,17,80,12,9,10,0,10,1,10,3,17,24,12,6,10,0,11,1,10,3,17,25,12,7,10,6,10,7,36,4,45,11,6,11,7,23,12,8,10,0,10,3,17,78,12,4,11,5,11,9,11,4,11,8,17,98,12,10,11,0,11,2,11,3,11,10,17,94,5,50,11,0,11,2,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,94,5,57,11,0,1,11,1,1,11,2,1,2,44,0,0,0,59,59,11,1,17,76,12,5,10,0,10,2,17,69,12,7,10,0,10,2,17,67,12,6,10,0,10,2,17,64,12,3,10,0,10,2,17,70,12,4,10,0,10,2,17,77,12,11,10,5,10,7,10,0,10,2,17,65,17,100,10,3,17,106,12,9,10,5,11,7,10,0,10,2,17,71,17,101,11,4,17,106,12,10,11,6,10,9,11,3,23,17,106,11,11,17,106,10,10,17,109,12,8,11,0,11,2,11,9,11,10,11,5,11,8,17,93,2,45,0,0,0,20,36,11,0,10,2,10,1,17,62,17,97,12,5,10,5,10,3,38,4,11,5,15,11,1,1,7,10,39,11,5,11,3,23,12,6,10,1,10,2,10,6,17,99,12,4,10,1,10,2,10,4,11,6,17,102,12,7,11,1,11,2,11,4,11,7,17,91,2,0,92,0,94,0],"lending_portal":[161,28,235,11,6,0,0,0,11,1,0,44,2,44,90,3,134,1,165,2,4,171,3,36,5,207,3,230,5,7,181,9,176,10,8,229,19,128,1,6,229,20,54,10,155,21,59,12,214,21,204,16,13,162,38,4,0,72,0,23,0,38,0,39,0,52,0,69,0,70,0,71,0,75,0,83,0,84,0,103,0,108,1,82,2,30,2,31,2,44,2,81,2,99,2,101,2,102,3,98,0,8,8,0,0,14,3,0,0,9,3,0,0,7,3,0,1,0,12,0,2,4,7,0,3,11,12,1,0,1,4,5,0,0,4,6,8,0,6,17,8,0,9,13,8,0,10,12,12,0,11,20,12,0,12,3,12,0,13,10,7,1,0,0,14,1,8,0,15,2,12,1,0,1,17,19,4,0,18,15,2,0,20,18,2,0,21,16,12,0,0,66,0,1,0,0,60,2,3,0,0,94,4,1,0,0,24,5,1,0,0,28,5,1,0,0,100,6,1,1,0,0,106,7,1,1,0,0,107,8,1,0,0,25,7,1,1,0,0,26,8,1,0,0,90,6,1,1,0,0,73,9,1,1,0,2,32,12,17,0,2,33,1,17,1,0,2,34,45,17,0,2,55,35,28,0,2,59,1,19,0,3,35,27,28,1,0,3,80,25,3,1,0,3,105,43,1,1,0,4,29,16,1,0,5,54,1,26,0,5,58,1,26,0,5,62,1,26,0,5,63,1,26,0,5,64,1,26,0,6,53,49,50,0,7,24,20,1,0,7,28,20,1,0,7,45,34,1,0,7,46,60,1,0,7,47,34,1,0,7,48,34,1,0,7,49,34,42,0,8,74,22,23,1,0,10,21,29,30,0,10,51,38,39,0,10,57,33,19,0,10,61,33,42,0,10,89,29,30,0,11,56,18,3,0,11,67,18,31,0,11,87,32,1,0,12,91,51,3,0,13,36,41,14,1,0,13,68,40,31,1,0,15,37,23,1,1,0,15,97,48,23,1,0,15,104,24,3,1,0,16,43,14,1,1,3,17,77,0,10,0,19,85,53,1,1,12,19,95,14,1,1,8,20,92,11,12,0,21,76,47,3,0,52,13,13,14,34,14,48,14,18,14,17,14,49,36,45,17,44,17,19,14,34,46,47,46,48,46,51,52,49,54,49,55,5,14,46,14,1,7,8,19,0,1,7,8,0,1,3,3,6,8,7,7,8,0,5,8,6,8,8,7,8,9,7,8,10,6,8,15,7,8,11,7,8,12,10,13,7,8,19,11,6,8,8,7,8,9,7,8,10,6,8,15,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,16,1,9,0,3,7,8,19,10,6,8,8,7,8,9,7,8,10,6,8,15,7,8,0,7,8,11,7,8,12,7,11,6,1,9,0,3,7,8,19,16,6,8,8,7,8,9,7,8,10,6,8,15,7,8,13,7,8,0,7,8,20,7,8,11,7,8,12,10,2,10,2,13,3,10,11,16,1,8,18,3,7,8,19,14,6,8,8,7,8,9,7,8,10,6,8,15,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,16,1,9,0,3,13,10,2,3,7,8,19,1,8,17,1,6,8,19,1,5,1,8,0,1,9,0,11,8,5,7,8,9,7,8,10,6,8,15,3,13,6,13,3,3,3,8,5,1,6,8,8,1,8,5,2,6,8,12,8,5,1,13,6,6,8,11,7,8,9,7,8,10,6,8,15,3,13,17,6,8,15,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,3,11,16,1,9,0,13,3,3,8,5,8,5,3,10,11,16,1,9,0,3,7,8,19,1,11,16,1,9,0,1,6,11,16,1,9,0,2,6,11,6,1,9,0,3,1,2,5,7,11,6,1,9,0,11,16,1,9,0,13,10,2,7,8,19,1,10,2,4,7,8,11,8,5,13,15,2,15,15,1,1,2,7,8,12,8,5,2,7,8,11,8,5,7,6,8,11,7,8,9,7,8,10,6,8,15,3,13,15,1,6,8,5,1,8,3,16,8,5,7,8,9,7,8,10,6,8,15,3,13,15,15,13,3,13,11,14,1,8,5,8,5,8,5,8,5,15,3,7,8,11,13,13,1,11,14,1,8,5,1,6,11,14,1,9,0,1,11,14,1,9,0,1,15,5,7,11,6,1,9,0,8,5,3,8,5,7,8,19,21,8,5,7,8,9,7,8,10,6,8,15,3,13,15,15,11,16,1,8,18,13,3,11,14,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,16,1,8,18,3,2,13,10,2,1,8,18,1,6,8,20,3,7,11,16,1,9,0,3,7,8,19,1,7,8,9,1,6,8,4,11,7,8,20,7,8,13,6,8,4,7,8,11,8,5,8,5,13,3,15,11,16,1,8,18,6,8,15,1,11,16,1,8,18,2,9,0,5,1,8,1,1,8,2,15,8,5,7,8,9,7,8,10,6,8,15,3,13,15,13,3,13,11,14,1,8,5,8,5,8,5,8,5,15,20,8,5,7,8,9,7,8,10,6,8,15,3,13,15,11,16,1,8,18,13,3,11,14,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,16,1,8,18,3,17,6,8,15,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,13,3,3,8,5,3,11,16,1,9,0,8,5,16,13,8,5,7,8,9,7,8,10,6,8,15,3,3,13,13,8,5,3,8,5,3,5,13,8,5,8,6,8,11,7,8,9,7,8,10,6,8,15,3,3,13,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,17,76,101,110,100,105,110,103,76,111,99,97,108,69,118,101,110,116,13,76,101,110,100,105,110,103,80,111,114,116,97,108,18,76,101,110,100,105,110,103,80,111,114,116,97,108,69,118,101,110,116,6,79,112,116,105,111,110,4,80,111,111,108,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,13,97,100,100,95,108,105,113,117,105,100,105,116,121,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,12,98,111,114,114,111,119,95,108,111,99,97,108,13,98,111,114,114,111,119,95,114,101,109,111,116,101,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,7,100,101,112,111,115,105,116,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,17,100,111,108,97,95,112,111,111,108,95,97,100,100,114,101,115,115,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,10,102,101,101,95,97,109,111,117,110,116,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,2,105,100,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,9,108,105,113,117,105,100,97,116,101,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,11,109,101,115,115,97,103,101,95,102,101,101,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,7,114,101,108,97,121,101,114,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,5,114,101,112,97,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,6,115,101,110,100,101,114,8,115,101,113,117,101,110,99,101,11,115,101,116,95,114,101,108,97,121,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,112,108,105,116,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,14,119,105,116,104,100,114,97,119,95,108,111,99,97,108,15,119,105,116,104,100,114,97,119,95,114,101,109,111,116,101,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,13,2,1,0,0,2,3,65,8,17,88,5,78,3,1,2,5,93,3,79,3,42,8,5,50,3,27,2,2,2,8,79,3,92,5,40,10,2,96,13,41,13,86,10,2,22,3,27,2,3,2,5,79,3,92,5,40,10,2,22,3,27,2,0,0,0,0,1,9,10,0,17,50,11,0,46,17,53,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,0,0,1,5,11,2,11,1,15,1,21,2,3,1,4,0,15,61,11,0,17,20,11,7,46,17,53,17,12,12,18,11,5,11,18,12,8,46,11,8,17,40,12,15,14,6,65,19,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,19,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,27,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,4,1,4,0,15,61,11,0,17,20,11,7,46,17,53,17,12,12,18,11,5,11,18,12,8,46,11,8,17,40,12,15,14,6,65,19,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,19,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,28,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,5,1,4,0,21,117,11,0,17,20,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,53,17,12,12,27,56,1,12,26,11,8,11,9,10,10,56,2,12,22,10,7,14,22,56,3,12,15,46,11,15,56,4,12,21,11,4,17,1,12,25,11,7,11,22,7,5,64,26,0,0,0,0,0,0,0,0,10,10,56,5,1,10,6,10,26,7,5,10,21,77,17,35,1,12,20,10,5,10,27,12,16,46,11,16,17,41,32,4,74,10,5,10,27,17,42,10,6,10,26,17,37,12,23,11,5,11,27,12,17,46,11,17,17,40,12,24,11,6,11,1,11,2,11,3,11,24,11,23,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,32,11,25,11,10,46,17,53,14,26,17,15,11,21,17,24,18,3,56,6,2,6,1,4,0,37,117,11,0,17,20,17,16,12,20,10,9,46,17,53,17,12,12,24,56,1,12,23,10,5,10,23,17,37,12,18,11,6,10,24,12,10,46,11,10,17,40,12,19,10,5,10,18,11,20,17,36,12,21,14,21,56,7,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,21,56,8,12,22,10,5,11,1,11,2,11,3,11,19,11,18,11,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,33,12,17,10,5,10,22,17,38,10,17,38,4,80,5,90,11,5,1,11,7,1,11,4,1,11,9,1,7,1,39,11,5,11,22,7,5,10,17,17,39,1,12,25,11,7,11,24,11,25,52,10,23,10,9,56,9,11,4,17,1,11,9,46,17,53,14,23,17,15,11,17,52,17,25,18,3,56,6,2,7,1,4,0,44,184,1,11,0,17,20,10,11,10,10,17,14,12,31,10,11,11,9,17,14,12,30,10,15,46,17,53,17,12,12,34,10,7,10,30,17,37,12,25,11,8,11,34,12,16,46,11,16,17,40,12,26,10,7,10,25,10,11,17,36,12,27,14,27,56,7,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,27,56,8,12,28,10,7,10,1,11,2,10,3,11,26,11,25,11,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,33,12,23,10,7,10,28,17,38,10,23,38,4,86,5,102,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,11,13,10,14,10,15,56,10,12,24,10,6,46,17,54,12,36,11,14,10,36,38,4,116,5,132,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,24,11,36,10,15,56,11,12,35,14,24,56,12,12,32,10,5,17,1,12,29,11,6,11,4,11,1,17,26,11,7,10,28,11,31,17,16,10,29,10,23,11,35,11,3,17,43,12,33,11,24,11,5,16,1,20,56,13,11,33,10,29,11,28,11,32,17,25,18,1,56,14,11,29,11,15,46,17,53,14,30,17,15,17,16,11,11,11,10,11,23,52,17,25,18,2,56,15,2,8,1,4,0,56,123,11,0,17,20,17,16,12,19,56,1,12,22,10,9,46,17,53,17,12,12,23,10,5,10,22,17,37,12,17,11,6,10,23,12,10,46,11,10,17,40,12,18,10,5,10,17,11,19,17,36,12,20,14,20,56,7,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,20,56,8,12,21,10,5,10,21,17,38,10,8,77,38,4,58,5,74,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,1,39,10,5,11,1,11,2,11,3,11,18,11,17,10,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,29,11,5,11,21,7,5,10,8,77,17,39,1,12,24,11,7,11,23,11,24,52,10,22,10,9,56,9,11,4,17,1,11,9,46,17,53,14,22,17,15,11,8,17,21,18,3,56,6,2,9,1,4,0,57,186,1,11,0,17,20,10,11,10,10,17,14,12,30,10,11,11,9,17,14,12,29,10,15,46,17,53,17,12,12,33,10,7,10,29,17,37,12,24,11,8,11,33,12,16,46,11,16,17,40,12,25,10,7,10,24,10,11,17,36,12,26,14,26,56,7,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,26,56,8,12,27,10,7,10,27,17,38,10,12,77,38,4,64,5,82,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,10,7,10,1,11,2,10,3,11,25,11,24,10,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,29,11,13,10,14,10,15,56,10,12,23,10,6,46,17,54,12,35,11,14,10,35,38,4,118,5,134,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,23,11,35,10,15,56,11,12,34,14,23,56,12,12,31,10,5,17,1,12,28,11,6,11,4,11,1,17,26,11,7,10,27,11,30,17,16,10,28,10,12,77,11,34,11,3,17,43,12,32,11,23,11,5,16,1,20,56,13,11,32,10,28,11,27,11,31,17,25,18,1,56,14,11,28,11,15,46,17,53,14,29,17,15,17,16,11,11,11,10,11,12,17,21,18,2,56,15,2,10,1,4,0,58,117,11,0,17,20,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,53,17,12,12,27,56,1,12,24,11,8,11,9,10,10,56,2,12,26,10,7,14,26,56,3,12,15,46,11,15,56,4,12,25,11,4,17,1,12,23,11,7,11,26,7,5,64,26,0,0,0,0,0,0,0,0,10,10,56,5,1,10,6,10,24,7,5,10,25,77,17,35,1,12,20,10,5,10,27,12,16,46,11,16,17,41,32,4,74,10,5,10,27,17,42,10,6,10,24,17,37,12,21,11,5,11,27,12,17,46,11,17,17,40,12,22,11,6,11,1,11,2,11,3,11,22,11,21,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,31,11,23,11,10,46,17,53,14,24,17,15,11,25,17,23,18,3,56,6,2,11,1,4,0,59,93,10,0,17,20,10,13,46,17,53,12,27,10,27,17,12,12,25,56,1,12,23,11,10,10,11,17,14,12,29,10,6,11,23,17,37,12,22,10,6,11,29,17,37,12,28,10,4,17,1,12,26,10,9,6,0,0,0,0,0,0,0,0,36,4,43,11,0,10,1,10,2,10,3,11,4,10,5,10,6,11,7,11,8,10,9,11,13,56,16,5,54,11,4,1,11,0,1,11,7,1,11,8,10,9,11,13,56,2,56,17,11,5,11,25,12,15,46,11,15,17,40,12,24,11,6,11,1,11,2,11,3,11,24,11,12,11,28,11,22,12,14,12,21,12,20,12,19,12,18,12,17,12,16,46,11,16,11,17,11,18,11,19,11,20,11,21,11,14,17,30,11,26,11,27,11,11,11,9,17,22,18,3,56,6,2,0,2,0,1,0],"merge_coins":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,10,3,20,53,4,73,14,5,87,102,7,189,1,132,1,8,193,2,96,6,161,3,30,12,191,3,189,1,0,6,1,14,2,2,2,11,2,12,2,0,12,1,0,1,4,1,2,0,0,5,0,1,1,0,1,3,5,6,1,0,1,8,3,4,1,0,2,4,8,4,1,0,2,10,11,1,1,0,2,13,9,10,1,0,2,15,15,1,1,0,3,7,14,4,1,12,4,9,12,13,0,2,1,1,1,3,7,5,7,4,7,7,1,6,7,3,10,11,0,1,9,0,3,7,8,1,1,11,0,1,9,0,6,11,0,1,9,0,11,0,1,9,0,11,0,1,9,0,3,11,0,1,9,0,3,1,7,10,9,0,0,1,6,10,9,0,1,1,1,9,0,2,7,11,0,1,9,0,11,0,1,9,0,1,6,11,0,1,9,0,1,3,3,7,11,0,1,9,0,3,7,8,1,1,6,8,1,1,5,2,9,0,5,1,7,8,1,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,8,105,115,95,101,109,112,116,121,4,106,111,105,110,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,7,114,101,118,101,114,115,101,6,115,101,110,100,101,114,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,118,101,99,116,111,114,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,255,255,255,255,255,255,255,255,0,1,0,0,2,83,14,0,65,1,6,0,0,0,0,0,0,0,0,36,4,67,13,0,56,0,13,0,69,1,12,5,14,0,56,1,32,4,20,5,15,13,5,13,0,69,1,56,2,5,10,11,0,70,1,0,0,0,0,0,0,0,0,14,5,56,3,12,8,10,1,12,6,11,1,7,2,33,4,33,10,8,12,6,11,8,10,6,38,4,38,5,42,11,2,1,7,0,39,14,5,56,3,10,6,36,4,60,13,5,11,6,10,2,56,4,12,7,11,5,11,2,46,17,8,56,5,11,7,12,3,5,64,11,2,1,11,5,12,3,11,3,12,4,5,81,11,0,70,1,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,33,4,74,5,78,11,2,1,7,1,39,11,2,56,6,12,4,11,4,2,0],"oracle":[161,28,235,11,6,0,0,0,11,1,0,36,2,36,84,3,120,157,1,4,149,2,22,5,171,2,231,2,7,146,5,231,6,8,249,11,128,1,6,249,12,70,10,191,13,33,12,224,13,232,5,13,200,19,14,0,47,0,31,2,40,2,41,2,49,2,52,2,54,2,56,2,61,1,23,1,24,1,46,1,62,1,63,1,65,1,66,3,61,3,68,0,10,8,0,0,6,4,0,1,2,0,0,1,3,8,0,2,4,0,1,3,0,3,5,7,0,4,6,7,0,5,7,7,0,6,8,7,0,6,9,12,0,8,12,12,0,9,0,8,0,10,1,12,1,0,1,11,15,4,0,12,11,2,0,13,13,12,2,7,1,4,1,15,14,2,0,16,12,12,0,17,16,0,0,0,43,0,1,0,0,39,2,3,0,0,59,4,1,0,0,58,4,1,0,0,57,5,1,0,0,20,6,1,0,0,21,6,1,0,0,29,7,1,0,1,22,27,1,0,2,28,40,1,1,3,3,33,43,23,0,3,34,43,23,0,4,32,41,42,0,4,35,41,42,0,5,30,19,20,0,6,36,30,20,0,6,37,28,29,0,7,26,33,34,0,7,38,38,39,0,7,67,35,34,0,9,64,22,23,0,11,45,0,8,0,13,17,21,1,2,7,4,13,18,15,17,2,7,4,13,19,36,37,2,7,4,13,25,15,16,2,7,4,13,45,0,10,2,7,4,14,60,13,1,1,8,17,48,31,32,0,26,9,26,11,27,12,25,11,23,11,25,9,22,9,22,11,23,9,24,11,9,29,1,7,8,16,0,2,7,8,0,13,3,15,2,3,3,6,8,2,7,8,0,3,7,6,8,2,7,8,0,10,2,13,15,2,6,8,11,3,7,8,0,10,13,6,8,11,9,6,8,3,7,8,17,7,8,10,7,8,9,7,8,0,13,10,2,6,8,11,11,12,1,8,14,1,8,13,2,13,8,7,1,11,15,2,9,0,9,1,2,13,8,1,1,8,0,1,9,0,4,13,13,6,8,1,7,11,15,2,13,8,1,2,6,11,15,2,9,0,9,1,9,0,1,1,1,6,9,1,5,13,13,8,7,7,11,15,2,13,8,7,7,11,15,2,13,8,1,1,10,2,1,8,7,3,7,11,15,2,9,0,9,1,9,0,9,1,1,6,8,11,1,3,6,13,3,6,13,3,6,8,1,7,11,15,2,13,8,1,1,13,23,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,6,8,11,13,10,2,6,8,11,10,8,18,6,8,11,3,8,5,3,11,4,1,8,8,7,8,1,6,8,7,8,8,11,4,1,8,8,8,5,3,8,6,8,7,8,18,1,6,8,3,1,6,8,9,1,8,8,1,6,8,8,3,6,8,17,10,2,6,8,11,1,8,18,3,6,8,10,10,8,18,6,8,11,1,11,4,1,8,8,5,6,8,10,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,2,7,11,15,2,9,0,9,1,9,0,1,7,9,1,3,6,8,9,6,8,11,3,1,8,6,1,11,4,1,9,0,1,6,8,6,1,8,5,1,6,8,5,5,67,108,111,99,107,4,67,111,105,110,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,15,72,111,116,80,111,116,97,116,111,86,101,99,116,111,114,3,73,54,52,5,80,114,105,99,101,15,80,114,105,99,101,73,100,101,110,116,105,102,105,101,114,9,80,114,105,99,101,73,110,102,111,15,80,114,105,99,101,73,110,102,111,79,98,106,101,99,116,11,80,114,105,99,101,79,114,97,99,108,101,3,83,85,73,5,83,116,97,116,101,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,86,65,65,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,17,99,104,101,99,107,95,103,117,97,114,100,95,112,114,105,99,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,29,99,114,101,97,116,101,95,112,114,105,99,101,95,105,110,102,111,115,95,104,111,116,95,112,111,116,97,116,111,7,100,101,99,105,109,97,108,7,100,101,115,116,114,111,121,24,102,101,101,100,95,116,111,107,101,110,95,112,114,105,99,101,95,98,121,95,112,121,116,104,13,102,114,111,109,95,98,121,116,101,95,118,101,99,7,103,101,110,101,115,105,115,8,103,101,116,95,101,120,112,111,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,110,101,103,97,116,105,118,101,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,112,111,115,105,116,105,118,101,9,103,101,116,95,112,114,105,99,101,20,103,101,116,95,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,37,103,101,116,95,112,114,105,99,101,95,105,110,102,111,95,102,114,111,109,95,112,114,105,99,101,95,105,110,102,111,95,111,98,106,101,99,116,23,103,101,116,95,112,114,105,99,101,95,110,111,95,111,108,100,101,114,95,116,104,97,110,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,17,104,111,116,95,112,111,116,97,116,111,95,118,101,99,116,111,114,3,105,54,52,2,105,100,4,105,110,105,116,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,3,110,101,119,6,111,98,106,101,99,116,6,111,114,97,99,108,101,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,5,112,114,105,99,101,16,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,16,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,16,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,17,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,115,10,112,114,105,99,101,95,105,110,102,111,13,112,114,105,99,101,95,111,114,97,99,108,101,115,4,112,121,116,104,20,114,101,103,105,115,116,101,114,95,116,111,107,101,110,95,112,114,105,99,101,20,115,101,116,95,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,20,115,101,116,95,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,116,97,116,101,3,115,117,105,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,24,117,112,100,97,116,101,95,115,105,110,103,108,101,95,112,114,105,99,101,95,102,101,101,100,3,118,97,97,5,118,97,108,117,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,181,59,15,65,116,16,134,39,251,238,114,226,73,139,88,214,162,113,76,222,213,63,172,83,112,52,194,32,210,99,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,60,0,0,0,0,0,0,0,3,8,16,14,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,5,42,8,13,51,3,50,3,53,11,15,2,13,8,7,55,11,15,2,13,8,1,1,2,3,69,15,27,2,44,3,0,0,0,0,1,11,10,0,17,21,7,1,7,0,10,0,56,0,11,0,56,1,18,0,56,2,2,1,1,0,0,14,32,11,0,15,0,12,5,10,5,10,1,12,2,46,11,2,56,3,4,11,5,15,11,5,1,7,2,39,11,5,11,1,12,3,46,11,3,56,4,12,4,10,4,16,1,20,10,4,16,2,20,11,4,16,3,20,2,2,1,0,0,1,5,11,2,11,1,15,4,21,2,3,1,0,0,1,5,11,2,11,1,15,5,21,2,4,1,0,0,18,58,10,1,15,0,12,11,10,11,10,3,12,7,46,11,7,56,3,32,4,12,5,20,11,11,1,11,1,1,11,6,1,7,3,39,11,2,17,14,12,9,11,1,15,6,12,10,10,10,10,3,12,8,46,11,8,56,5,32,4,35,5,43,11,11,1,11,10,1,11,6,1,7,3,39,11,10,10,3,11,9,56,6,11,11,11,3,11,4,11,5,11,6,17,20,6,232,3,0,0,0,0,0,0,26,18,1,56,7,2,5,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,5,20,35,4,39,5,45,11,8,1,11,0,1,7,4,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,6,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,4,20,35,4,39,5,45,11,8,1,11,0,1,7,5,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,7,1,0,0,26,136,1,11,0,17,8,10,4,16,6,10,5,56,5,4,8,5,20,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,2,39,10,4,15,6,10,5,12,14,46,11,14,56,8,12,24,10,3,46,17,16,12,25,14,25,17,15,12,30,11,24,14,30,33,4,40,5,52,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,6,39,11,1,11,6,10,7,12,16,12,15,46,11,15,11,16,17,28,12,31,10,2,11,31,64,32,1,0,0,0,0,0,0,0,10,7,12,18,12,17,46,11,17,11,18,17,17,12,26,11,2,11,26,10,3,11,8,10,7,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,17,19,12,22,10,7,17,20,6,232,3,0,0,0,0,0,0,26,12,19,11,4,15,0,11,5,56,9,12,23,11,3,11,7,12,13,46,11,13,7,0,17,18,12,29,11,22,56,10,14,29,17,13,12,27,14,27,17,11,12,28,14,29,17,12,12,20,14,20,17,10,12,21,11,28,77,10,23,15,1,21,11,21,51,10,23,15,2,21,11,19,11,23,15,3,21,2,0,4,1,0,1,1,1,2,0,1,0,2,0,3,0],"pool_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,136,1,4,146,1,2,5,148,1,208,1,7,228,2,205,4,8,177,7,32,6,209,7,41,12,250,7,133,12,0,23,0,10,0,24,1,0,7,0,0,18,0,1,0,0,22,0,1,0,0,21,0,1,0,0,19,0,1,0,0,20,0,1,0,0,16,0,1,0,0,17,0,1,0,0,11,2,3,0,0,1,3,4,0,0,15,5,3,0,0,5,3,6,0,0,14,7,3,0,0,4,3,8,0,0,13,9,3,0,0,3,3,9,0,1,2,3,12,0,1,12,12,3,0,2,6,19,20,0,2,7,19,27,0,2,8,19,21,0,2,9,19,1,0,2,25,11,0,0,2,26,25,0,0,2,27,14,0,0,2,28,15,0,0,2,29,13,0,0,2,30,17,18,1,1,26,1,0,1,2,5,8,0,8,0,3,13,10,2,1,10,2,6,8,0,8,0,3,13,2,10,2,5,13,3,8,0,8,0,3,6,13,3,8,0,8,0,3,2,3,8,0,13,10,2,4,8,0,13,2,10,2,3,13,15,2,3,10,2,10,2,10,2,2,7,10,2,13,1,8,0,2,7,10,2,10,2,2,7,10,2,3,2,7,10,2,2,18,10,2,10,2,10,2,10,2,10,2,10,2,3,13,10,2,13,3,3,3,8,0,2,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,17,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,3,3,8,0,2,13,13,8,0,13,2,10,2,10,2,13,10,2,10,2,10,2,10,2,13,10,2,13,3,3,3,2,8,0,13,2,7,10,2,15,9,10,2,10,2,10,2,3,13,15,3,3,2,1,15,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,100,101,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,21,103,101,116,95,100,101,108,101,116,101,95,111,119,110,101,114,95,116,121,112,101,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,16,103,101,116,95,100,101,112,111,115,105,116,95,116,121,112,101,23,103,101,116,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,21,103,101,116,95,115,101,110,100,95,109,101,115,115,97,103,101,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,10,112,111,111,108,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,10,48,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,3,17,21,11,0,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,1,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,2,17,23,13,6,7,2,17,24,14,4,65,1,6,0,0,0,0,0,0,0,0,36,4,46,13,6,14,4,65,1,75,17,21,13,6,11,4,17,25,11,6,2,8,1,0,0,16,172,1,14,0,65,1,12,13,6,0,0,0,0,0,0,0,0,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,1,14,1,17,17,12,8,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,2,14,2,17,17,12,16,11,12,11,11,22,12,12,11,16,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,14,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,3,14,3,17,17,12,18,11,12,11,11,22,12,12,11,18,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,17,11,12,11,11,22,12,12,6,8,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,4,14,4,17,19,12,7,11,12,11,11,22,12,12,6,1,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,5,14,5,17,20,12,15,11,12,11,11,22,12,12,64,1,0,0,0,0,0,0,0,0,12,9,10,13,10,12,36,4,151,1,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,6,14,6,17,17,12,10,11,12,11,11,22,12,12,11,10,52,12,11,14,0,10,12,10,12,10,11,22,56,0,12,9,11,12,11,11,22,12,12,10,15,7,2,33,4,156,1,5,158,1,7,1,39,11,13,11,12,33,4,163,1,5,165,1,7,0,39,11,14,11,17,11,7,11,8,11,15,11,9,2,9,1,0,0,10,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,21,13,6,11,1,17,23,11,2,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,3,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,4,17,23,13,6,7,3,17,24,11,6,2,10,1,0,0,22,152,1,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,15,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,19,12,11,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,17,11,9,11,8,22,12,9,11,17,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,19,12,7,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,20,12,13,11,9,11,8,22,12,9,10,13,7,3,33,4,136,1,5,138,1,7,1,39,11,10,11,9,33,4,143,1,5,145,1,7,0,39,11,15,11,11,11,12,11,16,11,7,11,13,2,11,1,0,0,23,34,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,1,17,21,11,0,17,16,12,4,13,3,14,4,65,1,75,17,21,13,3,11,4,17,25,13,3,7,4,17,24,14,2,65,1,6,0,0,0,0,0,0,0,0,36,4,32,13,3,14,2,65,1,75,17,21,13,3,11,2,17,25,11,3,2,12,1,0,0,24,123,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,5,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,20,12,11,11,9,11,8,22,12,9,64,1,0,0,0,0,0,0,0,0,12,6,10,10,10,9,36,4,104,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,7,11,9,11,8,22,12,9,11,7,52,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,11,9,11,8,22,12,9,10,11,7,4,33,4,109,5,111,7,1,39,11,10,11,9,33,4,116,5,118,7,0,39,11,12,11,5,11,11,11,6,2,13,1,0,0,3,13,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,0,17,21,13,3,11,1,17,22,13,3,11,2,17,24,11,3,2,14,1,0,0,26,64,14,0,65,1,12,8,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,1,14,1,17,17,12,5,11,7,11,4,22,12,7,6,32,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,2,14,2,17,18,12,6,11,7,11,4,22,12,7,6,1,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,3,14,3,17,20,12,9,11,7,11,4,22,12,7,11,8,11,7,33,4,58,5,60,7,0,39,11,5,11,6,11,9,2,0],"pool_manager":[161,28,235,11,6,0,0,0,12,1,0,22,2,22,66,3,88,199,1,4,159,2,62,5,221,2,206,2,7,171,5,144,8,8,187,13,96,6,155,14,138,1,10,165,15,108,12,145,16,154,13,13,171,29,32,15,203,29,4,0,62,0,28,0,30,0,36,1,21,1,58,2,32,2,57,2,74,2,76,2,77,0,9,12,0,0,1,4,0,0,7,4,0,0,4,4,0,0,8,4,0,0,6,4,0,0,0,3,0,0,10,3,0,1,2,7,0,3,3,0,0,4,11,7,0,5,5,7,1,0,0,7,14,4,0,8,12,12,2,7,1,4,1,10,13,2,0,0,51,0,1,0,0,66,2,1,0,0,65,3,1,0,0,71,4,1,0,0,69,5,1,0,0,70,4,1,0,0,47,6,7,0,0,41,8,9,0,0,44,6,10,0,0,37,11,12,0,0,48,6,12,0,0,43,8,12,0,0,42,8,12,0,0,45,6,12,0,0,46,8,12,0,0,38,1,12,0,0,39,1,12,0,0,35,13,14,0,0,34,15,16,0,0,33,17,16,0,0,81,1,18,0,0,16,19,20,0,0,67,19,20,0,1,40,46,9,0,2,24,49,12,0,2,25,49,12,0,2,26,20,12,0,5,56,1,47,1,0,5,73,28,47,1,0,6,29,28,1,1,3,7,55,0,21,0,8,15,31,1,2,7,4,8,22,41,42,2,7,4,8,23,35,36,2,7,4,8,27,41,16,2,7,4,8,55,0,23,2,7,4,9,72,28,1,1,8,35,22,35,24,35,25,35,26,36,27,35,30,31,24,31,26,35,33,31,22,31,25,33,26,33,24,31,30,33,30,32,26,32,25,32,24,32,22,34,33,32,33,32,30,28,32,27,32,34,24,34,25,33,22,31,33,33,33,29,50,29,51,1,7,8,14,0,5,6,8,9,7,8,0,8,10,13,7,8,14,4,6,8,9,7,8,0,8,8,13,4,6,8,9,7,8,0,8,8,15,4,6,8,9,7,8,0,13,15,2,7,8,0,13,1,10,8,8,2,7,8,0,8,8,1,13,1,8,10,3,6,8,0,13,13,1,15,3,7,8,0,13,13,1,11,11,1,8,8,2,6,8,0,13,1,1,2,6,8,0,8,8,1,8,3,4,7,8,0,8,8,13,15,2,15,15,1,8,12,2,13,8,1,1,11,13,2,9,0,9,1,2,13,8,2,2,8,8,13,2,13,10,8,8,1,8,0,1,9,0,8,13,8,10,8,3,11,13,2,8,8,8,4,8,1,7,11,13,2,13,8,1,8,2,7,11,13,2,13,8,2,2,8,8,8,4,3,7,11,13,2,9,0,9,1,9,0,9,1,1,8,8,2,13,8,3,3,13,8,8,7,8,5,2,7,11,13,2,9,0,9,1,9,0,1,7,9,1,4,8,8,13,7,8,2,7,8,4,2,13,7,8,2,3,8,8,13,7,8,4,2,13,13,2,6,11,13,2,9,0,9,1,9,0,1,6,9,1,2,8,8,8,8,2,15,6,11,13,2,13,8,3,4,8,8,3,3,10,8,8,1,6,8,8,1,11,11,1,9,0,9,8,8,13,15,7,11,13,2,13,8,3,7,8,3,13,15,7,8,2,7,8,4,6,15,15,15,15,15,15,1,8,6,1,8,7,12,65,100,100,76,105,113,117,105,100,105,116,121,7,65,112,112,73,110,102,111,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,9,76,105,113,117,105,100,105,116,121,6,79,112,116,105,111,110,11,80,111,111,108,67,97,116,97,108,111,103,8,80,111,111,108,73,110,102,111,13,80,111,111,108,76,105,113,117,105,100,105,116,121,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,15,82,101,109,111,118,101,76,105,113,117,105,100,105,116,121,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,13,97,100,100,95,108,105,113,117,105,100,105,116,121,7,97,108,112,104,97,95,49,6,97,109,111,117,110,116,9,97,112,112,95,105,110,102,111,115,13,97,112,112,95,108,105,113,117,105,100,105,116,121,5,97,115,99,105,105,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,5,101,118,101,110,116,18,101,120,105,115,116,95,99,101,114,116,97,105,110,95,112,111,111,108,13,101,120,105,115,116,95,112,111,111,108,95,105,100,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,100,101,102,97,117,108,116,95,97,108,112,104,97,95,49,20,103,101,116,95,100,101,102,97,117,108,116,95,108,97,109,98,100,97,95,49,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,24,103,101,116,95,112,111,111,108,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,112,111,111,108,95,110,97,109,101,95,98,121,95,105,100,21,103,101,116,95,112,111,111,108,95,116,111,116,97,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,115,95,98,121,95,105,100,19,103,101,116,95,116,111,107,101,110,95,108,105,113,117,105,100,105,116,121,2,105,100,11,105,100,95,116,111,95,112,111,111,108,115,4,105,110,105,116,8,108,97,109,98,100,97,95,49,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,110,97,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,12,112,111,111,108,95,97,100,100,114,101,115,115,12,112,111,111,108,95,99,97,116,97,108,111,103,10,112,111,111,108,95,105,110,102,111,115,12,112,111,111,108,95,109,97,110,97,103,101,114,10,112,111,111,108,95,116,111,95,105,100,5,112,111,111,108,115,13,114,101,103,105,115,116,101,114,95,112,111,111,108,16,114,101,103,105,115,116,101,114,95,112,111,111,108,95,105,100,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,7,114,101,115,101,114,118,101,21,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,97,108,112,104,97,22,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,108,97,109,98,100,97,15,115,101,116,95,112,111,111,108,95,119,101,105,103,104,116,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,116,97,98,108,101,12,116,111,116,97,108,95,119,101,105,103,104,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,119,101,105,103,104,116,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,14,122,101,114,111,95,108,105,113,117,105,100,105,116,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,0,88,241,76,176,44,241,78,240,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,37,164,0,10,139,202,34,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,0,2,4,49,8,12,19,11,13,2,13,8,1,61,11,13,2,13,8,2,60,8,5,1,2,1,20,11,13,2,13,8,3,2,2,5,54,8,10,68,8,3,17,15,75,15,64,11,13,2,8,8,8,4,3,2,1,78,15,4,2,4,78,15,52,15,30,15,79,15,5,2,2,63,11,13,2,8,8,13,50,11,13,2,13,10,8,8,6,2,3,59,8,8,18,15,31,15,7,2,3,59,8,8,18,15,30,15,0,0,0,0,1,14,10,0,17,30,10,0,56,0,10,0,56,1,10,0,56,2,11,0,56,3,18,5,18,0,56,4,2,1,1,0,0,29,54,10,1,10,3,12,5,46,11,5,17,18,32,4,9,5,15,11,1,1,11,4,1,7,2,39,10,1,15,0,12,12,11,2,12,6,17,20,12,7,10,4,56,5,12,8,11,6,11,7,7,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,8,18,2,12,11,11,12,10,3,11,11,56,6,10,1,15,1,15,2,10,3,64,32,0,0,0,0,0,0,0,0,56,7,11,1,15,3,12,10,11,4,56,8,18,1,12,9,11,10,11,3,11,9,56,9,2,2,1,0,0,34,52,10,1,10,3,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,10,1,10,2,12,5,46,11,5,17,19,32,4,21,5,25,11,1,1,7,4,39,10,1,15,1,12,6,10,6,15,4,10,2,10,3,56,10,11,6,15,2,10,3,56,11,10,2,68,32,11,1,15,0,11,3,56,12,15,5,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,4,56,13,2,3,1,0,0,37,43,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,12,6,10,6,15,5,11,2,56,14,12,7,10,6,16,6,20,10,7,16,7,20,23,10,3,22,11,6,15,6,21,11,3,11,7,15,7,21,2,4,1,0,0,38,22,10,1,10,2,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,11,1,15,0,11,2,56,12,12,5,11,3,11,5,15,8,21,2,5,1,0,0,39,29,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,15,5,11,2,56,14,12,6,11,3,11,6,15,9,21,2,6,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,1,15,2,11,1,12,3,46,11,3,56,15,20,2,7,1,0,0,43,22,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,11,0,15,1,15,4,11,1,12,3,46,11,3,56,16,20,2,8,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,0,11,1,12,3,46,11,3,56,17,16,10,20,2,9,1,0,0,44,32,10,0,10,1,17,18,4,5,5,9,11,0,1,7,3,39,11,0,16,3,11,1,56,18,16,11,12,4,10,4,10,2,56,19,4,26,11,4,11,2,56,20,16,12,20,12,3,5,30,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,10,1,0,0,9,20,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,13,16,12,20,2,11,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,14,20,2,12,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,15,20,2,13,1,0,0,9,19,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,6,20,2,14,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,7,20,2,15,1,0,0,1,2,7,0,2,16,1,0,0,1,2,7,1,2,17,1,0,0,45,34,11,0,11,1,17,6,12,6,14,6,65,32,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,32,5,14,14,6,10,4,66,32,20,12,3,14,3,17,23,10,2,33,4,27,11,3,56,22,2,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,9,56,23,2,18,1,0,0,1,5,11,0,16,0,11,1,56,24,2,19,1,0,0,1,6,11,0,16,1,16,4,11,1,56,25,2,20,1,0,0,1,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,2,21,3,0,0,48,119,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,12,16,15,20,10,12,16,9,20,17,25,12,10,10,3,10,10,22,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,32,4,73,11,7,11,2,10,6,18,3,56,27,5,85,11,7,11,2,56,28,12,8,10,8,16,12,20,10,6,22,11,8,15,12,21,10,11,16,13,16,12,20,10,3,22,11,11,15,13,15,12,21,10,12,16,14,20,10,3,22,10,12,15,14,21,10,12,16,15,20,10,10,23,11,12,15,15,21,11,1,11,3,10,10,18,6,56,29,11,6,11,10,2,22,3,0,0,48,151,1,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,12,16,14,20,10,3,38,4,33,5,41,11,0,1,11,12,1,11,11,1,7,8,39,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,11,16,8,20,10,12,16,9,20,17,24,12,10,10,3,10,10,23,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,4,82,5,90,11,12,1,11,11,1,11,7,1,7,6,39,11,7,11,2,56,28,12,8,10,8,16,12,20,10,3,38,4,101,5,109,11,12,1,11,11,1,11,8,1,7,7,39,10,8,16,12,20,10,3,23,11,8,15,12,21,10,11,16,13,16,12,20,10,6,23,11,11,15,13,15,12,21,10,12,16,14,20,10,6,23,10,12,15,14,21,10,12,16,15,20,10,10,22,11,12,15,15,21,11,1,11,3,10,10,18,7,56,30,11,6,11,10,2,0,2,0,3,5,1,0,1,5,0,2,4,2,3,4,3,2,2,4,1,2,0,1,0,3,0,2,1,4,0,4,2,0,53,0,80,0],"rates":[161,28,235,11,6,0,0,0,8,1,0,6,2,6,4,3,10,70,5,80,48,7,128,1,185,2,8,185,3,32,6,217,3,68,12,157,4,128,5,0,13,0,11,0,16,1,0,8,0,0,6,0,1,0,0,2,0,1,0,0,5,2,1,0,0,1,3,1,0,0,3,4,1,0,0,4,4,1,0,1,7,6,1,0,1,8,6,3,0,1,9,6,1,0,1,10,6,1,0,2,12,7,1,0,2,14,5,1,0,2,15,7,1,0,2,17,7,1,0,3,7,8,0,13,15,1,15,4,7,8,0,13,15,15,4,15,15,15,15,3,15,15,15,0,2,7,8,0,13,2,15,15,6,15,15,15,15,15,15,7,15,15,15,15,15,15,15,7,83,116,111,114,97,103,101,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,21,99,97,108,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,3,109,105,110,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,128,81,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,3,29,10,0,10,1,17,8,12,6,11,0,11,1,17,6,12,4,11,6,11,4,17,13,12,5,10,5,10,2,22,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,27,10,5,11,5,11,2,22,17,12,12,3,11,3,2,1,1,0,0,8,39,10,0,10,1,11,2,17,0,12,8,11,0,11,1,17,7,12,7,12,6,12,5,12,4,10,8,10,7,35,4,23,11,4,11,8,11,5,17,13,22,12,3,5,37,11,4,11,5,22,11,6,11,8,10,7,23,17,11,11,7,23,17,12,17,13,22,12,3,11,3,2,2,1,0,0,7,17,10,0,10,1,11,3,17,0,12,5,11,0,11,1,17,9,12,4,11,2,11,5,17,11,11,4,23,17,13,17,13,2,3,1,0,0,7,20,11,0,11,1,23,7,1,17,10,12,4,7,1,10,4,23,12,5,11,2,11,5,24,11,3,11,4,24,22,7,1,26,2,4,1,0,0,9,69,11,0,11,1,23,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,10,17,11,2,10,5,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,6,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,23,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,7,5,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,2,10,2,17,13,7,0,7,0,24,26,12,4,10,4,10,2,17,13,7,0,26,12,3,10,5,10,6,24,11,4,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,10,5,11,6,24,11,7,24,11,3,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,9,17,11,11,2,11,5,24,7,0,26,22,11,8,22,11,9,22,2,5,1,0,0,1,12,11,2,11,0,11,1,23,24,7,0,26,12,3,17,11,11,3,22,2,0],"ray_math":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,40,5,42,13,7,55,59,8,114,32,6,146,1,146,1,12,164,2,247,5,0,7,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,4,2,1,0,0,1,2,1,0,0,2,2,1,0,0,6,1,1,0,0,0,1,3,0,0,1,15,2,15,15,1,2,4,15,2,15,15,4,108,111,103,50,3,109,97,120,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,208,121,0,161,63,121,92,118,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,249,214,165,42,128,81,101,243,159,91,61,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,1,0,0,0,2,7,0,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,10,11,0,11,1,24,7,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,7,0,26,2,3,1,0,0,0,10,11,0,7,0,24,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,11,1,26,2,4,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,6,1,0,0,4,59,10,0,7,0,38,4,5,5,7,7,4,39,10,0,7,0,26,17,7,12,2,10,2,77,7,0,24,12,3,11,0,11,2,48,12,4,10,4,7,0,33,4,27,11,3,2,7,1,12,1,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,57,5,34,10,4,11,4,24,7,0,26,12,4,10,4,7,2,38,4,52,11,3,10,1,22,12,3,11,4,49,1,48,12,4,11,1,49,1,48,12,1,5,29,11,3,2,7,1,0,0,3,112,49,0,12,1,10,0,49,128,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,16,11,0,49,128,48,12,0,11,1,49,128,22,12,1,10,0,49,64,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,30,11,0,49,64,48,12,0,11,1,49,64,22,12,1,10,0,49,32,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,44,11,0,49,32,48,12,0,11,1,49,32,22,12,1,10,0,49,16,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,58,11,0,49,16,48,12,0,11,1,49,16,22,12,1,10,0,49,8,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,72,11,0,49,8,48,12,0,11,1,49,8,22,12,1,10,0,49,4,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,0,49,4,48,12,0,11,1,49,4,22,12,1,10,0,49,2,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,100,11,0,49,2,48,12,0,11,1,49,2,22,12,1,11,0,49,1,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,110,11,1,49,1,22,12,1,11,1,2,0],"scaled_balance":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,25,5,29,6,7,35,75,8,110,32,12,142,1,39,0,6,0,4,0,0,0,1,0,0,2,0,1,0,0,1,0,1,0,1,3,0,1,0,1,5,0,1,0,2,15,15,1,15,0,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,2,4,11,0,11,1,17,4,2,1,1,0,0,2,4,11,0,11,1,17,3,2,2,1,0,0,2,4,11,0,11,1,17,3,2,0],"serde":[161,28,235,11,6,0,0,0,9,1,0,12,2,12,8,3,20,167,1,4,187,1,12,5,199,1,148,1,7,219,2,211,4,8,174,7,96,6,142,8,20,12,162,8,157,35,0,23,1,4,1,6,1,36,1,37,2,2,1,0,7,0,3,1,7,0,0,32,0,1,0,0,28,2,1,0,0,31,3,1,0,0,26,4,1,0,0,29,5,1,0,0,19,6,6,0,0,5,6,6,0,0,27,4,1,0,0,30,5,1,0,0,33,7,1,0,0,24,8,1,0,0,25,9,1,1,0,0,34,7,1,0,0,14,10,6,0,0,10,10,11,0,0,13,10,12,0,0,8,10,13,0,0,11,10,14,0,0,9,10,13,0,0,12,10,14,0,0,7,10,15,0,0,18,10,12,0,0,15,10,16,0,0,38,17,18,1,1,0,39,19,20,1,3,1,20,28,16,0,2,35,27,16,1,0,3,17,1,30,1,0,3,21,30,28,0,4,3,25,1,1,0,4,22,24,1,1,0,5,16,16,15,0,30,6,29,6,26,15,27,29,23,6,23,29,2,7,10,2,2,0,2,7,10,2,13,2,7,10,2,3,2,7,10,2,4,2,7,10,2,15,1,2,2,7,10,2,10,2,2,7,10,2,5,1,7,10,2,1,6,10,2,1,13,1,3,1,4,1,15,1,5,1,10,2,3,6,10,9,0,3,3,1,10,9,0,2,6,10,9,0,9,0,1,10,10,9,0,2,1,2,3,1,1,2,2,4,10,2,1,7,10,9,0,2,7,10,9,0,10,9,0,2,15,10,2,1,6,9,0,1,8,0,1,9,0,1,8,1,2,4,3,2,15,3,3,10,2,3,3,3,1,3,10,9,0,3,3,10,10,9,0,3,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,6,97,112,112,101,110,100,5,97,115,99,105,105,16,97,115,99,105,105,95,116,111,95,104,101,120,95,115,116,114,3,98,99,115,19,100,101,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,16,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,29,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,29,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,30,100,101,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,17,103,101,116,95,118,101,99,116,111,114,95,108,101,110,103,116,104,16,104,101,120,95,115,116,114,95,116,111,95,97,115,99,105,105,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,7,114,101,118,101,114,115,101,5,115,101,114,100,101,17,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,14,115,101,114,105,97,108,105,122,101,95,116,121,112,101,14,115,101,114,105,97,108,105,122,101,95,117,49,50,56,27,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,27,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,28,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,6,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,12,118,101,99,116,111,114,95,115,112,108,105,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,68,6,2,1,1,0,0,1,15,10,0,10,1,49,8,48,72,255,0,28,51,17,0,11,0,11,1,72,255,0,28,51,17,0,2,2,1,0,0,1,63,10,0,10,1,49,56,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,6,255,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,6,255,0,0,0,0,0,0,0,28,51,17,0,2,3,1,0,0,1,127,10,0,10,1,49,120,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,4,1,0,0,1,255,1,10,0,10,1,49,248,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,240,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,232,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,224,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,216,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,208,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,200,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,192,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,184,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,176,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,168,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,160,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,152,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,144,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,136,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,128,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,120,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,5,1,0,0,21,31,10,0,49,0,38,4,9,10,0,49,9,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,22,12,2,5,29,10,0,49,15,37,4,23,5,25,7,1,39,11,0,49,87,22,12,2,11,2,2,6,1,0,0,22,40,10,0,49,48,38,4,9,10,0,49,57,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,3,5,38,10,0,49,97,38,4,27,10,0,49,102,37,12,2,5,29,9,12,2,11,2,4,32,5,34,7,1,39,11,0,49,87,23,12,3,11,3,2,7,1,0,0,23,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,8,1,0,0,26,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,9,1,0,0,1,4,11,0,11,1,56,1,2,10,1,0,0,16,17,14,1,56,2,12,2,14,2,65,6,6,32,0,0,0,0,0,0,0,33,4,9,5,13,11,0,1,7,0,39,11,0,11,2,56,1,2,11,1,0,0,28,8,56,3,17,28,12,1,11,0,11,1,17,25,17,9,2,12,1,0,0,12,17,14,1,65,6,12,2,10,2,6,0,0,0,0,0,0,0,0,33,4,10,11,0,1,2,10,0,11,2,17,2,11,0,11,1,17,9,2,13,1,0,0,1,15,10,0,65,6,6,1,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,6,0,0,0,0,0,0,0,0,66,6,20,2,14,1,0,0,1,24,10,0,65,6,6,2,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,75,49,8,47,11,0,6,1,0,0,0,0,0,0,0,66,6,20,75,22,2,15,1,0,0,1,72,10,0,65,6,6,8,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,52,49,56,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,52,49,48,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,52,49,40,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,52,49,32,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,52,49,24,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,52,49,16,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,52,49,8,47,22,11,0,6,7,0,0,0,0,0,0,0,66,6,20,52,22,2,16,1,0,0,1,136,1,10,0,65,6,6,16,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,53,49,120,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,53,49,112,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,53,49,104,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,53,49,96,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,53,49,88,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,53,49,80,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,53,49,72,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,53,49,64,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,53,49,56,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,53,49,48,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,53,49,40,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,53,49,32,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,53,49,24,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,53,49,16,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,53,49,8,47,22,11,0,6,15,0,0,0,0,0,0,0,66,6,20,53,22,2,17,1,0,0,1,136,2,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,77,49,248,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,77,49,240,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,77,49,232,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,77,49,224,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,77,49,216,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,77,49,208,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,77,49,200,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,77,49,192,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,77,49,184,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,77,49,176,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,77,49,168,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,77,49,160,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,77,49,152,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,77,49,144,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,77,49,136,47,22,10,0,6,15,0,0,0,0,0,0,0,66,6,20,77,49,128,47,22,10,0,6,16,0,0,0,0,0,0,0,66,6,20,77,49,120,47,22,10,0,6,17,0,0,0,0,0,0,0,66,6,20,77,49,112,47,22,10,0,6,18,0,0,0,0,0,0,0,66,6,20,77,49,104,47,22,10,0,6,19,0,0,0,0,0,0,0,66,6,20,77,49,96,47,22,10,0,6,20,0,0,0,0,0,0,0,66,6,20,77,49,88,47,22,10,0,6,21,0,0,0,0,0,0,0,66,6,20,77,49,80,47,22,10,0,6,22,0,0,0,0,0,0,0,66,6,20,77,49,72,47,22,10,0,6,23,0,0,0,0,0,0,0,66,6,20,77,49,64,47,22,10,0,6,24,0,0,0,0,0,0,0,66,6,20,77,49,56,47,22,10,0,6,25,0,0,0,0,0,0,0,66,6,20,77,49,48,47,22,10,0,6,26,0,0,0,0,0,0,0,66,6,20,77,49,40,47,22,10,0,6,27,0,0,0,0,0,0,0,66,6,20,77,49,32,47,22,10,0,6,28,0,0,0,0,0,0,0,66,6,20,77,49,24,47,22,10,0,6,29,0,0,0,0,0,0,0,66,6,20,77,49,16,47,22,10,0,6,30,0,0,0,0,0,0,0,66,6,20,77,49,8,47,22,11,0,6,31,0,0,0,0,0,0,0,66,6,20,77,22,2,18,1,0,0,31,29,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,53,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,19,1,0,0,32,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,77,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,20,1,0,0,1,14,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,20,17,31,2,21,1,0,0,16,8,11,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,2,22,1,0,0,33,46,10,0,65,6,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,64,6,0,0,0,0,0,0,0,0,2,10,3,6,8,0,0,0,0,0,0,0,36,4,16,5,20,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,12,2,11,3,10,2,6,8,0,0,0,0,0,0,0,22,33,4,35,5,39,11,0,1,7,0,39,11,0,6,8,0,0,0,0,0,0,0,11,2,6,8,0,0,0,0,0,0,0,22,56,4,2,23,1,0,0,34,43,10,1,10,2,35,4,10,10,2,10,0,65,29,37,12,3,5,12,9,12,3,11,3,4,15,5,19,11,0,1,7,0,39,64,29,0,0,0,0,0,0,0,0,12,5,11,1,12,4,10,4,10,2,35,4,39,5,28,13,5,10,0,10,4,66,29,20,68,29,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,23,11,0,1,11,5,2,24,1,0,0,35,53,64,18,0,0,0,0,0,0,0,0,12,3,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,29,35,4,38,5,12,10,0,10,2,66,29,20,10,1,33,4,33,10,4,10,2,35,4,29,13,3,10,0,11,4,10,2,56,5,68,18,10,2,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,10,4,10,2,35,4,49,13,3,11,0,11,4,11,2,56,5,68,18,5,51,11,0,1,11,3,2,0],"system_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,71,4,81,2,5,83,78,7,161,1,150,2,8,183,3,32,6,215,3,26,12,241,3,169,2,0,16,0,6,0,11,1,0,7,0,0,9,0,1,0,0,10,0,1,0,0,7,2,3,0,0,1,3,2,0,1,2,3,7,0,1,8,7,3,0,2,3,13,14,0,2,4,13,15,0,2,5,13,1,0,2,12,5,0,0,2,13,6,0,0,2,14,9,0,0,2,15,8,0,0,2,17,11,12,1,1,13,1,0,1,2,4,13,3,8,0,2,1,10,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,12,10,2,10,2,10,2,10,2,8,0,13,3,3,3,3,13,2,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,11,68,111,108,97,65,100,100,114,101,115,115,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,19,101,110,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,115,121,115,116,101,109,95,99,111,100,101,99,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,4,24,64,1,0,0,0,0,0,0,0,0,12,5,13,5,11,0,17,9,13,5,11,1,17,10,11,2,17,5,12,4,13,5,14,4,65,1,75,17,9,13,5,11,4,17,12,13,5,11,3,17,11,11,5,2,3,1,0,0,10,96,14,0,65,1,12,9,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,1,14,1,17,6,12,11,11,8,11,7,22,12,8,6,8,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,2,14,2,17,7,12,10,11,8,11,7,22,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,3,14,3,17,6,12,6,11,8,11,7,22,12,8,11,6,52,12,7,14,0,10,8,10,8,10,7,22,56,0,17,4,12,5,11,8,11,7,22,12,8,6,1,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,4,14,4,17,8,12,12,11,8,11,7,22,12,8,11,9,11,8,33,4,89,5,91,7,0,39,11,11,11,10,11,5,11,12,2,0],"system_core_storage":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,24,3,36,26,4,62,2,5,64,35,7,99,252,1,8,223,2,64,10,159,3,9,12,168,3,34,13,202,3,2,15,204,3,2,0,16,0,7,0,8,1,13,1,18,1,19,0,2,8,0,1,0,12,0,1,3,12,0,2,1,0,0,3,5,4,0,5,4,2,0,0,11,0,1,0,0,9,2,3,0,1,14,0,6,0,3,12,4,5,0,4,15,8,1,1,8,4,7,3,6,8,3,7,8,2,7,8,5,0,1,6,8,0,1,6,8,1,1,7,8,5,1,8,4,1,8,1,1,8,0,1,9,0,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,7,83,116,111,114,97,103,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,3,110,101,119,6,111,98,106,101,99,116,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,10,8,4,6,8,1,0,1,0,0,1,9,10,2,17,3,11,0,11,1,11,2,17,2,18,0,56,0,2,1,3,0,0,1,3,11,0,16,0,2,0,1,0,17,0],"system_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,24,2,24,40,3,64,71,4,135,1,2,5,137,1,117,7,254,1,155,4,8,153,6,96,6,249,6,10,10,131,7,17,12,148,7,191,1,0,33,0,10,0,16,0,19,0,31,0,32,0,38,0,39,1,14,1,18,1,34,2,30,0,7,3,0,1,0,12,0,2,3,7,0,3,4,8,0,5,6,8,0,6,9,12,0,7,2,12,0,8,1,8,0,10,8,2,0,11,5,12,0,0,11,0,1,0,0,35,0,1,0,2,22,13,8,0,2,23,13,14,0,3,13,3,1,0,4,15,8,9,0,4,21,1,10,0,4,24,1,10,0,5,20,4,5,0,6,11,12,1,0,6,27,11,1,0,6,35,12,1,0,7,26,6,7,0,9,17,16,1,1,3,13,15,8,6,8,3,7,8,5,7,8,9,7,8,6,6,8,4,10,2,6,8,7,7,8,8,0,6,10,2,8,2,2,3,8,2,13,1,6,8,3,1,6,8,4,1,6,8,1,6,7,8,9,7,8,6,6,8,1,10,2,6,8,7,7,8,8,2,8,2,10,2,1,10,2,4,13,3,8,2,2,1,2,2,7,8,5,8,2,3,7,8,5,8,2,8,2,1,6,8,2,1,13,1,8,0,1,9,0,6,10,2,2,3,8,2,13,8,2,6,65,112,112,67,97,112,5,67,108,111,99,107,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,5,83,116,97,116,101,7,83,116,111,114,97,103,101,15,83,121,115,116,101,109,67,111,114,101,69,118,101,110,116,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,11,97,112,112,95,109,97,110,97,103,101,114,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,110,111,110,99,101,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,12,115,121,115,116,101,109,95,99,111,100,101,99,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,0,2,6,25,3,28,10,2,29,13,37,13,36,10,2,12,2,0,1,4,0,2,51,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,12,11,8,17,5,12,10,12,9,12,11,12,13,10,10,17,6,33,4,23,5,27,11,1,1,7,0,39,10,12,10,9,33,4,35,11,1,10,12,17,10,5,39,11,1,10,12,10,9,17,9,11,11,14,12,17,2,11,13,14,9,17,3,14,9,17,2,11,10,18,0,56,0,2,1,1,4,0,17,43,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,11,11,8,17,5,12,9,12,13,12,10,12,12,10,9,17,7,33,4,23,5,27,11,1,1,7,0,39,11,1,10,11,10,13,17,11,11,10,14,11,17,2,11,12,14,13,17,3,14,13,17,2,11,9,18,0,56,0,2,0],"system_portal":[161,28,235,11,6,0,0,0,10,1,0,18,2,18,28,3,46,82,4,128,1,4,5,132,1,84,7,216,1,208,3,8,168,5,64,10,232,5,22,12,254,5,187,1,13,185,7,2,0,30,0,13,0,16,0,29,0,37,1,15,1,25,1,31,1,32,0,3,8,0,0,2,3,0,1,0,7,0,2,1,8,0,4,6,12,0,6,5,4,0,8,4,2,0,0,21,0,1,0,0,18,2,3,0,0,8,4,1,0,0,34,4,1,0,1,11,11,12,0,1,12,13,12,0,2,10,9,1,0,3,17,1,16,0,3,19,1,16,0,4,7,15,1,0,4,26,14,1,0,4,33,15,1,0,5,14,7,1,1,3,6,22,0,5,0,7,28,7,1,1,8,8,27,10,11,0,14,6,12,17,1,7,8,6,0,1,7,8,0,1,3,6,6,8,3,7,8,0,7,8,4,13,10,2,7,8,6,1,8,5,1,8,0,1,9,0,3,8,2,5,8,2,1,6,8,3,1,6,8,6,1,5,1,8,2,2,13,10,2,2,7,8,4,8,2,3,7,8,4,8,2,8,2,1,2,1,8,1,3,5,8,2,8,2,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,83,121,115,116,101,109,76,111,99,97,108,69,118,101,110,116,12,83,121,115,116,101,109,80,111,114,116,97,108,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,7,98,105,110,100,105,110,103,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,2,105,100,4,105,110,105,116,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,6,111,98,106,101,99,116,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,115,121,115,116,101,109,95,99,111,100,101,99,13,115,121,115,116,101,109,95,112,111,114,116,97,108,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,117,110,98,105,110,100,105,110,103,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,20,8,5,23,3,1,2,5,24,3,27,5,36,13,35,10,2,9,2,0,0,0,0,1,6,11,0,17,13,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,4,0,8,34,11,0,17,6,11,5,46,17,15,12,7,10,7,17,4,12,8,10,3,10,4,17,5,12,6,10,8,10,6,33,4,21,11,2,11,8,17,10,5,25,11,2,11,8,11,6,17,9,11,1,17,1,11,7,11,3,11,4,17,7,18,1,56,1,2,3,1,4,0,18,26,11,0,17,6,11,5,46,17,15,12,6,10,6,17,4,12,8,10,3,10,4,17,5,12,7,11,2,11,8,11,7,17,11,11,1,17,1,11,6,11,3,11,4,17,8,18,1,56,1,2,0,1,0],"user_manager":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,40,3,58,138,1,4,196,1,42,5,238,1,128,2,7,238,3,161,5,8,143,9,96,6,239,9,60,10,171,10,49,12,220,10,247,4,13,211,15,8,15,219,15,8,0,48,0,15,0,20,1,49,2,19,2,31,2,39,2,40,2,41,0,8,12,0,0,7,4,0,0,0,3,0,0,6,3,0,1,1,7,0,2,2,0,0,5,5,4,0,6,3,12,2,7,1,4,1,8,4,2,0,0,26,0,1,0,0,33,2,1,0,0,43,3,1,0,0,22,4,5,0,0,23,6,7,0,0,32,4,8,0,0,27,4,9,0,0,34,10,1,0,0,10,11,1,0,0,42,11,1,0,1,21,28,29,0,1,44,30,8,0,3,25,37,38,1,0,3,35,39,18,1,0,4,18,18,1,1,3,5,30,0,12,0,6,9,21,1,2,7,4,6,11,20,25,2,7,4,6,12,22,35,2,7,4,6,14,20,9,2,7,4,6,29,32,5,2,7,4,6,30,0,14,2,7,4,6,35,22,23,2,7,4,7,36,18,1,1,8,21,13,21,15,21,16,23,17,19,16,16,16,22,16,19,13,17,13,19,15,17,15,17,16,20,15,16,13,16,15,14,33,18,15,12,8,22,13,13,8,14,40,1,7,8,8,0,4,6,8,5,7,8,0,13,13,3,6,8,5,7,8,0,13,2,6,8,0,8,4,1,3,2,6,8,0,3,1,10,8,4,1,8,4,1,1,2,7,8,0,8,4,3,7,8,0,8,4,8,4,1,8,6,2,8,4,3,1,11,7,2,9,0,9,1,2,3,10,8,4,2,13,13,1,8,0,1,9,0,2,13,7,11,7,2,13,13,2,6,11,7,2,9,0,9,1,9,0,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,9,1,2,8,4,6,8,1,1,6,9,1,1,6,8,1,3,8,4,6,11,7,2,13,13,13,1,6,8,4,1,13,2,8,4,13,6,8,4,8,4,3,8,4,10,8,4,7,8,1,1,6,11,7,2,9,0,9,1,1,8,2,7,8,4,8,4,8,4,8,4,3,7,10,8,4,7,8,1,1,7,9,1,10,8,4,8,4,8,4,6,8,4,3,3,3,8,4,7,10,8,4,7,8,1,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,1,8,3,8,66,105,110,100,85,115,101,114,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,10,85,110,98,105,110,100,85,115,101,114,18,85,115,101,114,65,100,100,114,101,115,115,67,97,116,97,108,111,103,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,97,100,100,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,97,105,110,95,105,100,95,116,111,95,103,114,111,117,112,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,17,100,111,108,97,95,117,115,101,114,95,97,100,100,114,101,115,115,12,100,111,108,97,95,117,115,101,114,95,105,100,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,18,103,101,116,95,117,115,101,114,95,97,100,100,114,101,115,115,101,115,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,16,112,114,111,99,101,115,115,95,103,114,111,117,112,95,105,100,22,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,115,121,115,116,101,109,95,112,111,114,116,97,108,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,24,117,110,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,115,101,114,95,97,100,100,114,101,115,115,95,99,97,116,97,108,111,103,23,117,115,101,114,95,97,100,100,114,101,115,115,95,116,111,95,117,115,101,114,95,105,100,20,117,115,101,114,95,105,100,95,116,111,95,97,100,100,114,101,115,115,101,115,12,117,115,101,114,95,109,97,110,97,103,101,114,6,118,101,99,116,111,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,3,24,8,6,45,8,1,13,11,7,2,13,13,1,2,2,46,11,7,2,8,4,3,47,11,7,2,3,10,8,4,2,2,2,16,8,4,17,3,3,2,2,16,8,4,17,3,0,0,0,0,1,12,10,0,17,15,10,0,56,0,10,0,56,1,18,1,11,0,56,2,18,0,56,3,2,1,1,0,0,19,21,11,1,15,0,12,5,10,5,10,2,12,4,46,11,4,56,4,32,4,12,5,16,11,5,1,7,3,39,11,5,11,2,11,3,56,5,2,2,1,0,0,19,20,11,1,15,0,12,4,10,4,10,2,12,3,46,11,3,56,4,4,11,5,15,11,4,1,7,4,39,11,4,11,2,56,6,1,2,3,1,0,0,24,23,10,0,11,1,17,5,12,2,11,0,16,1,12,3,10,3,16,2,10,2,56,7,4,13,5,17,11,3,1,7,1,39,11,3,16,2,11,2,56,8,20,2,4,1,0,0,26,19,11,0,16,1,12,2,10,2,16,3,10,1,56,9,4,9,5,13,11,2,1,7,1,39,11,2,16,3,11,1,56,10,20,2,5,1,0,0,27,24,14,1,17,10,12,4,11,0,16,0,12,3,10,3,10,4,56,4,4,18,11,1,11,3,11,4,56,11,20,17,11,12,2,5,22,11,3,1,11,1,12,2,11,2,2,6,1,0,0,8,10,10,0,11,1,17,5,12,2,11,0,16,1,16,2,11,2,56,7,2,7,3,0,0,31,50,10,0,11,1,12,2,46,11,2,17,5,12,5,11,0,15,1,12,7,10,7,15,2,10,5,12,3,46,11,3,56,7,32,4,20,5,24,11,7,1,7,0,39,10,7,16,3,56,12,6,1,0,0,0,0,0,0,0,22,12,4,64,8,0,0,0,0,0,0,0,0,12,6,10,7,15,2,10,5,10,4,56,13,13,6,10,5,68,8,11,7,15,3,10,4,11,6,56,14,11,5,11,4,18,2,56,15,2,8,3,0,0,34,49,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,11,2,12,4,46,11,4,17,5,12,6,11,0,15,1,12,9,10,9,15,2,10,6,12,5,46,11,5,56,7,32,4,27,5,31,11,9,1,7,0,39,10,9,15,3,10,7,56,16,12,8,11,9,15,2,10,6,10,7,56,13,11,8,10,6,68,8,11,6,11,7,18,2,56,15,2,9,3,0,0,36,73,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,10,2,12,4,46,11,4,17,3,12,9,10,7,10,9,33,4,19,5,23,11,0,1,7,5,39,10,0,11,2,12,5,46,11,5,17,5,12,10,11,0,15,1,12,12,10,12,15,3,11,9,56,16,12,11,10,11,46,65,8,6,2,0,0,0,0,0,0,0,38,4,45,5,51,11,12,1,11,11,1,7,2,39,10,11,14,10,12,6,46,11,6,56,17,12,8,1,11,12,15,2,10,10,56,18,1,11,11,11,8,56,19,1,11,10,11,7,18,3,56,20,2,0,2,0,1,1,0,1,1,0,28,0,37,0,38,0,50,0],"wormhole_adapter_core":[161,28,235,11,6,0,0,0,12,1,0,46,2,46,114,3,160,1,212,1,4,244,2,22,5,138,3,146,3,7,156,6,196,10,8,224,16,96,6,192,17,30,10,222,17,68,12,162,18,236,4,13,142,23,6,15,148,23,6,0,90,0,27,0,36,0,46,0,62,0,63,0,87,0,91,1,29,1,30,1,44,1,59,1,60,1,81,1,85,1,86,1,89,2,28,2,40,2,45,2,66,2,80,2,88,0,4,12,0,0,15,3,0,0,5,3,0,0,16,3,0,0,6,3,0,0,17,3,0,0,7,3,0,1,0,12,0,2,8,7,0,3,11,0,0,5,14,12,0,6,23,12,0,7,22,12,0,8,2,8,0,9,3,12,1,0,1,11,21,4,0,12,13,12,2,7,1,12,1,13,18,2,0,15,20,2,0,16,25,7,2,1,0,0,0,17,1,7,0,18,9,12,0,19,10,7,0,20,12,0,0,21,19,12,0,22,24,0,0,0,53,0,1,0,0,71,2,1,0,0,35,3,1,0,0,75,4,1,0,0,76,4,1,0,0,73,4,1,0,0,74,4,1,0,0,68,5,6,0,0,67,7,8,0,0,69,5,6,0,0,79,9,10,0,1,47,45,46,0,4,33,24,48,0,4,34,24,44,0,4,42,33,24,0,4,43,54,24,0,4,48,1,32,0,4,49,1,32,0,4,50,1,32,0,4,51,1,32,0,5,26,49,50,0,5,78,49,50,0,6,55,51,23,0,6,70,52,1,0,7,61,42,43,0,10,39,21,1,1,3,11,58,12,13,0,12,58,12,17,2,7,12,14,65,21,1,1,12,16,32,22,23,2,1,0,16,41,1,19,2,1,0,16,54,27,1,2,1,0,16,77,29,30,2,1,0,17,58,24,25,0,18,58,14,15,0,19,58,25,26,0,19,84,26,24,0,20,64,34,35,0,20,66,36,10,0,22,83,43,24,0,27,16,30,18,28,20,29,18,31,18,25,28,32,18,25,37,25,38,25,39,25,40,3,6,8,9,7,8,24,7,8,18,0,4,6,8,9,7,8,0,13,10,2,3,6,8,9,7,8,0,13,7,6,8,9,7,8,24,7,8,0,13,15,11,14,1,8,17,6,8,13,6,7,8,24,7,8,0,6,8,7,10,2,6,8,13,7,8,18,2,8,8,10,2,8,7,8,24,7,8,0,6,8,7,10,2,7,8,10,7,8,11,6,8,13,7,8,18,4,8,8,8,8,15,10,2,11,7,8,24,7,8,0,6,8,7,7,8,10,8,8,8,8,13,3,15,11,14,1,8,17,6,8,13,1,3,3,7,8,24,7,8,18,8,15,1,7,8,18,1,8,15,2,6,8,24,7,8,18,1,8,21,2,8,20,8,12,1,11,16,2,9,0,9,1,2,13,8,22,1,11,19,2,9,0,9,1,1,8,0,1,9,0,2,6,11,19,2,9,0,9,1,6,9,0,1,1,1,10,2,1,8,20,1,8,22,3,7,11,19,2,9,0,9,1,9,0,9,1,1,8,1,2,7,11,19,2,9,0,9,1,6,9,0,2,9,0,9,1,2,8,23,10,2,1,2,3,13,15,2,3,7,8,21,14,10,2,1,8,23,4,7,8,24,11,14,1,8,17,8,23,6,8,13,1,8,3,1,8,5,1,8,4,1,8,6,3,13,10,2,8,8,6,7,8,24,6,11,19,2,13,8,22,7,11,16,2,8,20,8,12,10,2,6,8,13,7,8,18,1,8,25,4,8,8,13,2,10,2,1,6,8,7,1,13,7,8,8,15,3,13,10,2,8,8,8,8,6,8,8,8,8,3,13,2,10,2,4,7,8,10,8,8,13,15,2,15,15,2,6,8,11,8,8,2,7,8,11,8,8,3,15,8,23,10,2,5,13,3,8,8,8,8,3,6,65,112,112,67,97,112,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,12,68,101,108,101,116,101,66,114,105,100,103,101,11,68,101,108,101,116,101,79,119,110,101,114,13,68,101,108,101,116,101,83,112,101,110,100,101,114,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,14,82,101,103,105,115,116,101,114,66,114,105,100,103,101,13,82,101,103,105,115,116,101,114,79,119,110,101,114,15,82,101,103,105,115,116,101,114,83,112,101,110,100,101,114,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,86,65,65,6,86,101,99,77,97,112,13,97,100,100,95,108,105,113,117,105,100,105,116,121,11,97,112,112,95,109,97,110,97,103,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,8,99,111,110,116,97,105,110,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,20,100,101,108,101,116,101,95,114,101,109,111,116,101,95,98,114,105,100,103,101,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,13,100,111,108,97,95,99,111,110,116,114,97,99,116,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,21,103,101,116,95,100,101,108,101,116,101,95,111,119,110,101,114,95,116,121,112,101,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,23,103,101,116,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,6,105,110,115,101,114,116,12,105,115,95,100,111,108,97,95,117,115,101,114,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,10,112,111,111,108,95,99,111,100,101,99,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,22,114,101,103,105,115,116,101,114,95,114,101,109,111,116,101,95,98,114,105,100,103,101,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,19,114,101,109,111,116,101,95,100,101,108,101,116,101,95,111,119,110,101,114,21,114,101,109,111,116,101,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,21,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,23,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,5,115,116,97,116,101,3,115,117,105,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,3,118,97,97,7,118,101,99,95,109,97,112,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,24,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,22,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,99,104,97,105,110,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,4,52,8,15,92,8,21,31,11,16,2,8,20,8,12,72,11,19,2,13,8,22,1,2,2,94,13,93,10,2,2,2,2,94,13,93,10,2,3,2,2,37,13,38,15,4,2,2,37,13,38,15,5,2,2,37,13,38,15,6,2,2,37,13,38,15,0,1,0,0,11,18,10,2,17,26,12,5,11,1,10,2,12,4,12,3,11,5,11,3,46,11,4,17,34,11,2,56,0,56,1,18,0,56,2,2,1,1,0,0,1,23,10,1,16,0,14,2,56,3,32,4,7,5,11,11,1,1,7,1,39,11,1,15,0,10,2,10,3,17,33,17,35,56,4,11,2,11,3,18,1,56,5,2,2,1,0,0,26,22,10,1,16,0,14,2,56,3,4,6,5,10,11,1,1,7,0,39,11,1,15,0,14,2,56,6,12,3,1,11,2,11,3,17,36,18,1,56,5,2,3,1,0,0,31,22,10,3,10,4,17,18,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,3,56,7,2,4,1,0,0,31,22,10,3,10,4,17,19,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,5,56,8,2,5,1,0,0,31,22,10,3,10,4,17,16,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,4,56,9,2,6,1,0,0,31,22,10,3,10,4,17,17,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,6,56,10,2,7,3,0,0,41,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,24,17,39,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,8,3,0,0,47,59,11,0,10,1,16,0,11,1,15,2,11,3,11,6,11,7,17,24,17,39,17,12,12,12,1,12,11,12,10,12,14,12,13,10,2,17,11,11,11,33,4,23,5,31,11,5,1,11,4,1,11,2,1,7,2,39,11,4,10,13,11,2,17,11,11,10,77,17,20,1,12,9,10,5,10,14,12,8,46,11,8,17,22,32,4,52,11,5,10,14,17,23,5,54,11,5,1,11,13,11,14,11,9,11,12,2,9,3,0,0,41,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,24,17,39,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,10,3,0,0,53,28,11,3,10,4,11,2,17,11,11,8,17,21,1,12,11,11,6,11,7,11,4,11,5,11,11,52,17,15,12,13,11,1,15,1,73,0,0,0,0,11,13,17,37,12,12,11,0,11,9,11,12,11,10,17,38,2,0,3,0,1,0,2,0,56,0,57,0,82,0],"wormhole_adapter_pool":[161,28,235,11,6,0,0,0,11,1,0,42,2,42,92,3,134,1,142,1,4,148,2,16,5,164,2,185,2,7,221,4,156,6,8,249,10,96,6,217,11,50,10,139,12,51,12,190,12,168,2,13,230,14,10,0,70,0,29,0,30,0,37,0,51,0,71,1,23,1,24,1,35,1,47,1,48,1,63,1,65,1,66,1,68,2,21,2,33,2,36,2,53,2,62,2,67,0,10,8,0,0,11,8,0,0,12,3,0,1,3,7,0,2,9,12,1,0,1,3,6,8,0,5,17,12,0,6,1,8,0,7,2,12,1,0,1,9,16,4,0,10,8,12,2,7,1,12,1,11,13,2,0,13,15,2,0,14,19,7,2,1,0,0,0,15,0,7,0,16,4,12,0,17,5,7,0,18,7,0,0,19,14,12,0,20,18,0,0,0,41,0,1,0,0,42,2,1,0,0,57,3,1,1,0,0,58,4,1,0,0,54,5,1,1,0,1,38,36,16,0,1,39,36,37,0,2,28,24,16,1,0,2,58,29,16,0,2,69,35,1,1,0,3,22,31,1,0,4,27,16,34,0,5,49,32,33,0,8,32,10,1,1,3,9,45,0,6,0,10,45,0,21,2,7,12,12,60,10,1,1,8,13,59,7,8,0,14,34,1,15,2,1,0,14,43,19,1,2,1,0,15,45,16,17,0,16,45,12,13,0,17,45,17,18,0,18,52,25,26,0,18,53,27,28,0,20,64,33,16,0,16,9,18,14,19,14,15,20,16,22,7,10,9,10,13,38,1,7,8,12,0,5,7,8,0,13,10,2,7,8,18,7,8,12,9,7,8,1,7,8,18,11,8,1,8,11,7,11,4,1,9,0,11,8,1,9,0,13,10,2,6,8,7,7,8,12,7,7,8,1,7,8,18,11,8,1,8,11,13,10,2,6,8,7,7,8,12,7,6,8,5,7,8,18,7,8,1,7,11,4,1,9,0,10,2,6,8,7,7,8,12,1,8,9,1,6,8,12,1,5,1,8,0,1,9,0,3,7,8,12,11,13,2,13,8,16,8,15,2,6,8,18,7,8,12,1,8,15,2,13,8,16,1,11,13,2,9,0,9,1,1,10,2,1,8,14,1,8,16,3,7,11,13,2,9,0,9,1,9,0,9,1,2,8,14,8,6,1,11,10,2,9,0,9,1,1,8,1,2,8,17,10,2,5,7,11,4,1,9,0,11,8,1,9,0,13,10,2,7,8,12,3,7,8,15,14,10,2,1,8,17,4,7,8,18,11,8,1,8,11,8,17,6,8,7,1,3,3,13,10,2,7,8,12,5,3,3,8,3,8,3,13,1,6,8,5,6,7,8,18,6,11,13,2,13,8,16,7,11,10,2,8,14,8,6,10,2,6,8,7,7,8,12,1,8,19,6,13,3,8,3,8,3,3,2,5,7,11,4,1,9,0,8,3,3,8,3,7,8,12,1,6,8,3,1,13,1,8,2,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,4,80,111,111,108,11,80,111,111,108,71,101,110,101,115,105,115,9,80,111,111,108,83,116,97,116,101,17,80,111,111,108,87,105,116,104,100,114,97,119,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,6,97,109,111,117,110,116,7,98,121,116,101,115,51,50,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,7,99,114,101,97,116,111,114,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,12,100,115,116,95,99,104,97,105,110,95,105,100,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,4,105,110,105,116,10,105,110,105,116,105,97,108,105,122,101,6,105,110,115,101,114,116,7,105,115,95,105,110,105,116,3,110,101,119,5,110,111,110,99,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,12,112,111,111,108,95,97,100,100,114,101,115,115,10,112,111,111,108,95,99,111,100,101,99,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,12,115,101,110,100,95,100,101,112,111,115,105,116,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,3,115,117,105,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,40,8,9,26,5,44,1,1,2,4,40,8,9,72,8,15,25,11,10,2,8,14,8,6,56,11,13,2,13,8,16,2,2,6,46,3,61,13,31,13,50,10,2,55,10,2,20,3,0,0,0,0,1,9,10,0,17,14,11,0,46,17,17,9,18,0,56,0,2,1,1,4,0,11,59,10,0,16,0,20,10,4,46,17,17,33,4,9,5,17,11,3,1,11,0,1,11,4,1,7,2,39,10,0,16,1,20,32,4,23,5,31,11,3,1,11,0,1,11,4,1,7,3,39,11,3,10,4,12,5,46,11,5,17,21,12,7,56,1,12,6,13,6,11,1,11,2,17,20,17,22,56,2,10,4,17,14,11,7,11,4,56,3,11,6,18,1,56,4,8,11,0,15,1,21,2,2,3,0,0,23,20,11,3,11,4,11,5,11,6,11,8,56,5,12,10,11,0,15,2,73,0,0,0,0,11,10,17,23,12,9,11,1,11,2,11,9,11,7,17,24,1,2,3,3,0,0,23,18,11,3,11,4,11,6,17,8,12,8,11,0,15,2,73,0,0,0,0,11,8,17,23,12,7,11,1,11,2,11,7,11,5,17,24,1,2,4,1,4,0,30,37,11,0,17,10,11,1,10,2,16,3,11,2,15,4,11,4,11,5,10,6,17,12,17,25,17,11,1,12,7,12,10,12,9,12,8,12,11,11,3,10,10,10,7,10,9,11,6,56,6,11,8,11,11,14,9,17,6,14,9,17,5,14,10,17,5,11,7,18,2,56,7,2,0,1,0,2,1,1,1,3,1,2,0],"wormhole_adapter_verify":[161,28,235,11,6,0,0,0,10,1,0,22,2,22,54,3,76,102,4,178,1,16,5,194,1,206,1,7,144,3,135,3,8,151,6,128,1,6,151,7,30,10,181,7,6,12,187,7,205,1,0,38,1,29,2,14,2,27,2,28,2,35,2,37,3,13,3,19,3,34,3,36,0,8,12,0,1,4,7,1,0,0,2,1,8,0,3,7,4,0,4,3,12,2,7,1,12,1,5,6,2,0,6,10,7,2,1,0,0,0,7,0,7,0,8,2,7,0,9,5,12,0,10,9,0,0,0,22,0,1,0,0,12,2,3,0,0,30,4,5,0,0,32,6,3,0,0,31,7,5,0,1,20,19,13,1,0,1,24,18,10,1,0,1,26,3,14,1,0,1,33,13,14,1,0,3,25,25,26,0,4,11,27,3,2,7,12,4,15,24,10,2,7,12,6,15,9,10,2,1,0,6,21,9,11,2,1,0,10,16,16,22,0,10,17,16,12,0,10,18,16,17,0,10,30,21,5,0,12,8,13,8,8,12,7,12,6,12,5,12,11,23,10,23,2,6,11,6,2,13,8,8,6,13,1,11,1,1,8,8,2,6,11,6,2,13,8,8,6,8,10,0,4,7,8,9,6,11,6,2,13,8,8,10,2,6,8,2,1,8,10,3,7,11,4,2,8,7,8,0,6,8,10,7,8,5,6,7,8,9,6,11,6,2,13,8,8,7,11,4,2,8,7,8,0,10,2,6,8,2,7,8,5,2,13,8,8,2,6,11,6,2,9,0,9,1,6,9,0,1,1,1,6,9,1,1,8,8,1,9,0,1,11,1,1,9,0,2,11,1,1,8,8,13,1,6,8,10,1,13,1,6,11,1,1,9,0,1,7,11,1,1,9,0,3,10,2,6,8,2,8,10,3,6,8,9,10,2,6,8,2,1,8,7,2,8,7,8,0,2,6,11,4,2,9,0,9,1,9,0,1,7,8,5,1,8,3,3,7,11,4,2,9,0,9,1,9,0,9,1,7,66,121,116,101,115,51,50,5,67,108,111,99,107,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,3,97,100,100,20,97,115,115,101,114,116,95,107,110,111,119,110,95,101,109,105,116,116,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,6,100,105,103,101,115,116,15,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,13,101,109,105,116,116,101,114,95,99,104,97,105,110,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,101,120,116,114,97,99,116,3,103,101,116,22,103,101,116,95,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,2,105,100,7,105,115,95,115,111,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,14,114,101,112,108,97,121,95,112,114,111,116,101,99,116,4,115,111,109,101,5,115,116,97,116,101,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,1,23,8,3,0,1,0,0,1,19,10,0,10,1,56,0,4,11,11,0,11,1,56,1,20,56,2,12,2,5,17,11,1,1,11,0,1,56,3,12,2,11,2,2,1,1,0,0,15,25,10,1,17,16,12,3,11,0,14,3,17,0,12,2,14,2,56,4,4,11,5,15,11,1,1,7,0,39,13,2,56,5,11,1,17,15,33,4,22,5,24,7,1,39,2,2,1,0,0,20,15,11,0,11,2,11,3,12,5,12,4,46,11,4,11,5,17,17,12,6,11,1,14,6,17,1,11,6,2,3,1,0,0,22,26,10,0,10,1,17,14,12,3,46,11,3,56,6,32,4,10,5,18,11,1,1,11,2,1,11,0,1,7,2,39,11,0,11,1,17,14,11,2,17,9,18,0,56,7,2,4,1,0,0,5,12,11,0,11,1,11,3,11,4,17,2,12,6,11,2,14,6,11,5,17,3,11,6,2,0]},"type_origin_table":[{"module_name":"dola_address","struct_name":"DolaAddress","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"Pool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"DepositPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"WithdrawPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_verify","struct_name":"Unit","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceManagerCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version_1_0_0","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"app_manager","struct_name":"TotalAppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"app_manager","struct_name":"AppCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"UserInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ReserveData","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ScaledBalance","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"BorrowRateFactors","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"PriceOracle","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"Price","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"Liquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AddLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"RemoveLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_logic","struct_name":"LendingCoreExecuteEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserAddressCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"BindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UnbindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"CoreState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"LendingCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_wormhole_adapter","struct_name":"SystemCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolWithdrawEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":1},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":5},"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302":{"upgraded_id":"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302","upgraded_version":1},"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a":{"upgraded_id":"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a","upgraded_version":1}}}},"owner":"Immutable","previous_transaction":"BPLPMMmGBp3vAM6v31MEKfQLcUzKmgin9gBefQsnbg4m","storage_rebate":548454000},{"data":{"Package":{"id":"0xc5b2a5049cd71586362d0c6a38e34cfaae7ea9ce6d5401a350506a15f817bf72","version":2,"module_map":{"app_manager":[161,28,235,11,6,0,0,0,10,1,0,10,2,10,24,3,34,46,4,80,2,5,82,54,7,136,1,228,1,8,236,2,64,10,172,3,18,12,190,3,106,13,168,4,4,0,8,0,11,1,16,1,20,1,21,0,3,12,0,0,0,12,0,1,1,0,0,2,2,7,0,2,5,4,0,4,4,2,0,0,14,0,1,0,0,17,2,3,0,0,18,4,3,0,0,12,5,6,0,0,10,3,1,0,2,9,7,1,0,2,15,0,7,0,2,22,12,8,0,3,19,10,1,1,8,8,9,1,7,8,5,0,2,7,8,0,7,8,5,1,8,1,3,6,8,2,7,8,0,7,8,5,1,6,8,1,1,13,1,8,4,1,8,3,1,8,0,1,9,0,3,8,1,8,3,8,4,1,6,8,4,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,2,73,68,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,97,112,112,95,99,97,112,115,6,97,112,112,95,105,100,11,97,112,112,95,109,97,110,97,103,101,114,6,100,101,108,101,116,101,15,100,101,115,116,114,111,121,95,97,112,112,95,99,97,112,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,2,105,100,4,105,110,105,116,3,110,101,119,6,111,98,106,101,99,116,12,114,101,103,105,115,116,101,114,95,97,112,112,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,8,4,6,10,8,3,1,2,2,13,8,4,7,13,0,0,0,0,1,6,11,0,17,6,64,8,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,11,19,11,1,17,6,12,4,14,4,17,7,12,3,11,4,10,0,16,0,65,8,75,18,1,12,2,11,0,15,0,11,3,68,8,11,2,2,2,1,0,0,1,4,11,1,11,2,17,1,2,3,1,0,0,1,4,11,0,16,1,20,2,4,1,0,0,1,5,11,0,19,1,1,17,5,2,0,1,1,1,0],"dola_address":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,12,3,24,109,4,133,1,6,5,139,1,78,7,217,1,191,3,8,152,5,96,6,248,5,14,10,134,6,8,12,142,6,151,2,13,165,8,4,0,13,0,23,1,4,1,27,2,3,2,5,0,0,7,0,2,1,7,0,3,2,7,0,0,20,0,1,0,0,19,2,1,0,0,18,2,3,0,0,29,4,5,0,0,28,6,5,0,0,10,7,5,0,0,6,8,5,0,0,7,5,8,0,0,9,0,5,1,0,0,8,5,3,0,0,15,5,3,0,0,11,3,5,0,1,12,19,1,0,1,24,14,0,0,1,25,15,0,0,1,30,17,18,1,1,2,21,13,3,0,3,17,0,12,1,0,3,22,12,13,0,4,16,3,8,0,5,26,9,3,1,0,20,8,17,11,15,10,0,1,13,1,6,8,0,1,10,2,2,8,0,13,1,8,0,2,8,0,10,2,2,13,10,2,1,5,1,6,9,0,1,2,1,9,0,1,8,2,1,8,1,2,7,10,2,13,2,7,10,2,10,2,6,10,2,3,10,2,13,3,3,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,11,68,111,108,97,65,100,100,114,101,115,115,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,112,111,111,108,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,19,117,112,100,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,13,2,0,0,0,2,2,14,13,13,10,2,0,1,0,0,0,2,7,1,2,1,1,0,0,0,4,11,0,16,0,20,2,2,1,0,0,0,4,11,0,16,1,20,2,3,1,0,0,0,6,11,1,13,0,15,0,21,11,0,2,4,1,0,0,0,6,11,1,13,0,15,1,21,11,0,2,5,1,0,0,0,4,11,0,11,1,18,0,2,6,1,0,0,0,5,7,1,14,0,56,0,18,0,2,7,1,0,0,0,14,14,0,16,1,65,10,6,32,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,14,0,16,1,20,17,19,2,8,1,0,0,3,8,56,1,17,18,17,16,12,0,7,1,11,0,18,0,2,9,1,0,0,0,4,14,0,16,1,20,2,10,1,0,0,3,14,64,10,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,17,13,13,1,14,0,16,1,20,17,14,11,1,2,11,1,0,0,16,30,14,0,65,10,12,6,6,0,0,0,0,0,0,0,0,12,5,6,2,0,0,0,0,0,0,0,12,2,14,0,10,5,10,5,10,2,22,56,2,12,1,14,1,17,12,12,4,11,5,11,2,22,12,5,14,0,11,5,11,6,56,2,12,3,11,4,11,3,18,0,2,0,0,0,1,0],"dola_pool":[161,28,235,11,6,0,0,0,14,1,0,22,2,22,52,3,74,173,1,4,247,1,32,5,151,2,211,1,7,234,3,168,5,8,146,9,96,6,242,9,50,10,164,10,34,11,198,10,2,12,200,10,222,2,13,166,13,4,14,170,13,4,15,174,13,4,0,23,0,22,0,45,1,12,1,54,2,13,2,14,2,27,2,43,2,52,2,53,0,5,12,1,0,1,0,3,3,0,0,10,3,0,1,4,7,0,3,6,7,0,4,8,7,0,5,0,4,1,0,1,6,1,12,1,0,1,6,2,12,1,0,1,8,9,4,0,10,7,2,0,0,30,0,1,1,0,0,19,2,3,1,0,0,16,4,5,0,0,42,6,5,1,0,0,55,6,5,1,0,0,21,7,8,1,0,0,57,9,3,1,0,0,48,10,8,0,1,15,19,21,0,1,17,21,19,0,1,18,3,21,1,0,1,32,30,8,0,1,33,30,29,0,1,34,3,29,0,2,25,22,8,0,2,26,35,8,0,3,37,26,8,0,4,29,3,25,1,0,4,38,25,26,0,5,39,24,5,1,0,5,51,31,15,1,0,5,59,3,15,1,0,6,28,32,23,1,0,6,31,12,1,1,0,6,36,23,15,1,0,6,56,20,5,1,0,7,24,11,3,1,3,8,41,13,14,0,9,46,34,3,1,12,9,50,11,3,1,8,10,49,18,19,0,23,11,21,11,29,16,0,11,25,11,3,11,10,11,24,11,19,11,17,11,26,27,4,11,20,11,22,11,26,33,28,23,1,6,11,0,1,9,0,1,2,2,6,11,8,1,9,0,7,8,10,0,3,3,2,2,1,3,2,6,11,0,1,9,0,3,5,7,11,0,1,9,0,11,7,1,9,0,13,10,2,7,8,10,1,10,2,5,7,11,0,1,9,0,8,3,3,8,3,7,8,10,3,13,10,2,7,8,10,1,9,0,1,6,11,8,1,9,0,1,7,8,10,1,8,9,1,11,6,1,9,0,1,11,0,1,9,0,6,3,3,3,10,2,5,8,3,1,6,8,10,1,5,1,6,11,7,1,9,0,1,8,3,5,8,3,8,3,3,13,10,2,1,11,7,1,9,0,2,7,11,6,1,9,0,11,6,1,9,0,1,8,5,1,8,4,1,8,1,3,3,11,7,1,9,0,5,1,13,1,6,8,3,2,7,11,6,1,9,0,3,2,11,6,1,9,0,7,8,10,1,8,2,2,9,0,5,3,8,3,13,10,2,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,11,68,101,112,111,115,105,116,80,111,111,108,11,68,111,108,97,65,100,100,114,101,115,115,4,80,111,111,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,12,87,105,116,104,100,114,97,119,80,111,111,108,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,11,99,114,101,97,116,101,95,112,111,111,108,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,4,101,109,105,116,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,12,103,101,116,95,100,101,99,105,109,97,108,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,12,105,110,116,111,95,98,97,108,97,110,99,101,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,10,112,111,111,108,95,99,111,100,101,99,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,35,8,9,13,11,6,1,9,0,20,2,1,2,3,44,8,4,49,5,11,3,2,2,3,44,8,4,47,5,11,3,0,11,0,1,0,0,3,4,11,0,55,0,20,2,1,1,0,0,1,10,11,0,56,0,12,2,11,1,17,27,56,1,11,2,57,0,56,2,2,2,1,0,0,3,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,3,1,0,0,1,8,11,0,56,3,12,2,11,1,11,2,49,8,17,2,2,4,1,0,0,1,8,11,0,56,3,12,2,11,1,49,8,11,2,17,2,2,5,3,0,0,17,38,11,4,46,17,30,12,9,14,1,56,4,12,7,10,0,10,7,12,5,46,11,5,56,5,12,6,10,9,17,8,12,10,56,6,11,10,11,6,11,2,11,3,17,14,12,8,11,0,54,1,11,1,56,7,56,8,1,56,9,17,18,11,9,11,7,18,1,56,10,11,8,2,6,3,0,0,28,53,17,13,14,3,17,12,33,4,6,5,12,11,0,1,11,4,1,7,4,39,14,3,17,11,56,9,17,18,17,16,33,4,20,5,26,11,0,1,11,4,1,7,0,39,11,1,17,9,12,7,10,0,11,2,12,5,46,11,5,56,11,12,2,11,0,54,1,10,2,56,12,11,4,56,13,12,6,56,9,17,18,10,7,11,2,18,2,56,14,11,6,11,7,56,15,2,7,3,0,0,3,8,11,2,46,17,30,17,8,11,0,11,1,17,15,2,0,2,0,1,0,11,1,11,0,40,0,58,0],"equilibrium_fee":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,50,5,54,29,7,83,174,1,8,129,2,32,12,161,2,197,5,0,4,0,10,0,2,0,1,0,0,3,2,1,0,0,0,3,1,0,0,1,3,1,0,1,5,0,1,0,1,6,4,1,0,1,7,0,1,0,1,8,4,1,0,1,9,1,1,0,1,11,0,1,0,2,15,15,1,15,3,15,15,15,6,15,15,15,15,15,15,0,4,1,15,15,15,6,1,15,15,15,15,15,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,27,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,112,101,114,99,101,110,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,1,13,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,11,11,1,11,0,17,6,12,2,11,2,2,1,1,0,0,1,17,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,15,11,0,11,1,17,6,11,2,17,6,17,5,17,4,12,3,11,3,2,2,1,0,0,5,93,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,1,10,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,2,23,10,0,10,2,23,10,3,17,1,10,4,36,4,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,10,4,36,4,50,10,1,10,0,10,4,17,9,10,3,17,9,23,17,5,10,4,10,3,17,9,23,17,6,12,7,5,52,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,12,9,10,2,10,9,23,10,5,17,5,10,4,10,3,17,9,23,17,9,24,10,4,10,3,17,9,26,12,8,10,0,11,1,23,11,5,17,7,17,9,24,10,0,11,9,23,11,0,11,2,23,17,6,17,8,17,9,11,4,11,3,17,9,26,11,8,23,2,3,1,0,0,6,51,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,12,7,11,1,10,2,22,11,0,10,2,22,11,3,17,1,11,7,23,12,9,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,4,11,5,17,6,24,12,11,11,2,11,11,17,6,17,5,17,4,12,10,11,9,11,10,17,4,12,8,11,4,11,8,17,9,2,0],"genesis":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,56,3,74,128,1,4,202,1,22,5,224,1,175,1,7,143,3,130,4,8,145,7,96,6,241,7,61,10,174,8,39,12,213,8,147,2,13,232,10,6,15,238,10,2,0,26,1,15,1,44,1,46,2,24,2,38,2,39,2,42,2,43,0,0,0,0,0,2,12,0,0,1,8,0,0,11,7,0,0,12,7,0,0,13,7,0,1,4,7,0,2,6,7,0,5,3,7,0,5,7,4,0,6,8,12,0,6,9,0,0,6,10,0,0,8,5,2,0,0,29,0,1,0,0,17,2,0,0,0,33,3,4,0,0,16,5,6,0,0,18,7,0,0,0,36,8,0,2,6,6,0,19,9,10,0,0,21,10,0,0,0,22,11,0,0,1,34,31,32,0,2,27,0,26,1,0,2,28,30,31,0,3,32,35,36,1,0,3,40,37,23,1,0,4,14,20,0,2,7,4,4,25,13,14,2,7,4,4,40,28,29,2,7,4,5,20,17,0,0,5,31,21,18,1,8,5,37,16,17,0,6,16,24,6,0,6,18,25,0,0,7,41,23,0,1,8,15,12,14,19,18,4,22,22,15,27,16,27,10,29,10,23,14,33,12,18,13,18,0,1,8,5,1,6,8,2,2,8,10,7,8,13,1,8,1,4,6,8,0,7,8,2,2,10,2,1,8,12,2,7,8,2,8,11,3,6,8,0,7,8,2,9,1,1,6,8,1,1,8,0,2,7,8,2,8,1,2,8,3,8,5,2,6,8,9,9,0,1,1,2,8,2,8,1,1,7,8,13,1,8,9,1,8,8,2,8,3,8,4,3,7,8,9,9,0,9,1,1,6,9,0,1,8,2,1,9,0,3,7,8,10,2,10,2,2,7,8,10,8,11,1,8,7,2,8,3,9,0,2,7,8,9,9,0,1,9,1,1,6,8,7,1,8,6,1,10,2,2,8,3,9,1,2,3,8,8,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,7,86,101,114,115,105,111,110,13,86,101,114,115,105,111,110,95,49,95,48,95,48,13,86,101,114,115,105,111,110,95,49,95,48,95,49,3,97,100,100,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,15,100,101,115,116,114,111,121,95,109,97,110,97,103,101,114,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,7,103,101,110,101,115,105,115,3,103,101,116,10,103,101,116,95,109,111,100,117,108,101,17,103,101,116,95,118,101,114,115,105,111,110,95,49,95,48,95,49,13,103,111,118,101,114,110,97,110,99,101,95,118,49,2,105,100,8,105,110,100,101,120,95,111,102,12,105,110,105,116,95,103,101,110,101,115,105,115,10,105,110,116,111,95,98,121,116,101,115,11,109,97,110,97,103,101,114,95,105,100,115,15,109,105,103,114,97,116,101,95,118,101,114,115,105,111,110,3,110,101,119,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,11,117,112,103,114,97,100,101,95,99,97,112,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,10,2,8,7,103,101,110,101,115,105,115,0,2,1,23,1,1,2,1,31,8,9,2,2,3,31,8,9,45,8,10,35,10,8,8,3,2,1,23,1,4,2,1,23,1,5,2,1,23,1,0,1,0,0,0,3,9,18,5,2,1,1,0,0,0,10,11,0,16,0,9,18,3,56,0,4,7,5,9,7,4,39,2,2,3,0,0,15,26,10,1,17,19,11,0,64,18,0,0,0,0,0,0,0,0,18,2,12,2,11,1,17,19,18,1,12,3,13,2,15,0,9,18,3,9,18,4,56,1,13,2,15,1,14,3,56,2,68,18,11,2,56,3,11,3,2,3,1,0,0,0,6,11,1,15,2,11,2,11,3,17,20,2,4,1,0,0,0,5,11,0,15,2,11,1,17,21,2,5,1,0,0,26,47,10,1,15,0,46,9,18,3,56,4,4,8,5,12,11,1,1,7,1,39,10,1,15,0,9,18,3,56,5,1,56,6,12,3,10,3,56,7,34,4,25,5,29,11,1,1,7,2,39,14,3,17,11,17,9,7,5,33,4,36,5,40,11,1,1,7,3,39,11,1,15,0,9,18,3,11,2,56,8,2,6,1,0,0,0,3,9,18,0,2,7,1,0,0,0,4,11,0,19,0,1,2,8,1,0,0,34,18,14,1,56,2,12,3,10,0,16,1,14,3,56,9,12,2,1,11,0,15,1,11,2,56,10,1,11,1,19,1,17,17,2,2,0,2,2,2,1,0,30,0],"governance_v1":[161,28,235,11,6,0,0,0,13,1,0,22,2,22,56,3,78,198,1,4,148,2,40,5,188,2,148,2,7,208,4,155,6,8,235,10,96,6,203,11,207,1,10,154,13,72,11,226,13,2,12,228,13,215,9,13,187,23,28,14,215,23,14,0,43,0,38,1,18,1,57,1,71,1,75,2,33,2,56,2,58,2,69,2,70,0,3,8,0,0,7,8,1,6,0,0,1,3,0,0,0,3,0,1,2,0,0,1,4,12,0,2,8,7,0,3,6,7,1,0,0,4,10,7,0,7,5,7,0,7,11,4,0,8,12,12,0,10,9,2,0,0,47,0,1,0,0,13,2,1,0,0,74,3,4,0,0,15,5,1,0,0,62,5,1,0,0,73,6,1,0,0,22,7,1,0,0,31,8,9,0,0,41,10,11,1,6,0,28,12,1,0,0,25,13,1,1,6,0,76,14,15,1,6,0,20,10,1,1,6,1,24,47,12,0,1,27,12,1,0,1,48,25,4,0,2,68,35,11,0,3,19,46,44,1,0,3,35,27,23,1,0,3,37,26,1,1,0,3,49,46,9,1,0,3,50,46,9,1,0,3,55,1,20,1,0,3,65,23,20,1,0,4,39,1,39,1,0,4,40,40,11,0,5,23,29,9,1,0,5,46,29,31,1,0,5,61,32,23,1,0,6,29,23,1,1,3,7,45,44,21,1,8,7,53,0,19,0,7,72,37,38,0,9,64,23,1,1,8,10,32,18,34,0,10,63,18,17,0,22,4,33,22,19,4,18,4,26,17,27,17,28,17,22,34,23,34,24,23,33,41,29,42,30,41,29,45,20,34,17,34,17,4,23,12,21,34,22,12,1,7,8,12,0,3,8,11,7,8,0,7,8,12,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,1,9,0,7,8,12,1,8,6,1,8,4,3,6,8,0,9,0,7,8,12,5,6,8,0,9,0,7,11,1,1,9,0,1,7,8,12,1,11,7,1,8,4,1,10,5,1,5,1,6,8,12,1,8,10,1,11,7,1,9,0,1,8,9,1,8,0,1,9,0,2,5,1,2,8,11,7,8,12,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,1,10,2,12,8,8,3,11,7,1,3,3,5,8,10,5,11,7,1,3,3,8,10,8,9,3,1,6,8,10,1,6,8,9,1,8,8,1,6,8,8,1,11,1,1,9,0,1,8,2,11,1,6,5,6,5,1,1,7,10,5,3,7,10,5,3,3,5,1,6,9,0,1,8,3,1,6,11,7,1,9,0,1,6,8,5,11,67,104,97,110,103,101,83,116,97,116,101,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,10,97,100,100,95,109,101,109,98,101,114,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,12,99,104,101,99,107,95,109,101,109,98,101,114,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,49,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,103,101,110,101,115,105,115,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,9,109,97,120,95,100,101,108,97,121,7,109,101,109,98,101,114,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,6,114,101,109,111,118,101,13,114,101,109,111,118,101,95,109,101,109,98,101,114,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,7,117,112,103,114,97,100,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,8,45,8,10,42,11,7,1,8,5,14,1,17,3,77,3,51,3,52,10,5,44,10,8,9,1,2,10,45,8,10,26,5,66,3,30,11,7,1,3,34,3,59,8,6,21,9,0,36,10,5,16,10,5,67,2,2,2,1,60,8,9,3,2,2,60,8,9,54,2,1,23,0,0,0,0,16,19,64,17,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,35,68,17,11,0,17,31,56,0,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,11,1,64,21,0,0,0,0,0,0,0,0,18,0,56,1,2,1,1,4,0,24,42,10,1,10,2,46,17,35,12,3,46,11,3,17,6,10,1,16,0,20,32,4,20,10,1,16,1,65,21,6,0,0,0,0,0,0,0,0,33,12,4,5,22,9,12,4,11,4,4,25,5,31,11,1,1,11,2,1,7,5,39,10,1,15,2,11,0,11,2,17,15,56,2,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,2,56,3,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,28,19,10,1,15,3,14,2,12,3,46,11,3,56,4,32,4,10,5,14,11,1,1,7,9,39,11,1,15,3,11,2,68,17,2,4,1,0,0,30,21,10,1,10,2,12,3,46,11,3,17,6,10,1,15,3,14,2,12,4,46,11,4,56,5,12,5,1,11,1,15,3,11,5,56,6,1,2,5,1,0,0,1,24,10,4,10,3,10,2,22,36,4,7,5,11,11,1,1,7,7,39,11,2,10,1,15,4,21,11,3,10,1,15,5,21,11,4,11,1,15,6,21,2,6,1,0,0,1,9,11,0,16,3,14,1,56,4,4,6,5,8,7,8,39,2,7,1,0,0,8,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,8,1,0,0,33,75,11,1,46,17,34,12,7,10,0,55,0,20,7,2,33,4,16,11,0,1,7,16,17,16,12,6,5,73,10,0,55,0,20,7,3,33,4,28,11,0,1,7,17,17,16,12,5,5,71,10,0,55,0,20,7,4,33,4,40,11,0,1,7,18,17,16,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,19,17,16,12,3,5,67,11,0,55,0,20,7,0,33,4,62,7,20,17,16,12,2,5,65,7,21,17,16,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,9,1,0,0,1,3,11,0,17,14,2,10,1,0,0,36,86,10,0,16,0,20,4,5,5,11,11,0,1,11,2,1,7,6,39,10,2,46,17,35,12,9,10,0,10,9,17,6,10,2,46,17,34,10,0,16,4,20,22,12,14,10,0,16,5,20,6,0,0,0,0,0,0,0,0,33,4,35,56,7,12,10,5,42,10,14,10,0,16,5,20,22,56,8,12,10,10,2,46,17,34,11,0,16,6,20,22,12,11,11,2,17,31,12,12,14,12,17,32,20,12,13,11,12,12,8,11,9,12,7,11,14,12,6,11,10,12,5,11,11,12,4,56,9,12,3,11,8,11,7,11,6,11,5,11,4,14,3,17,25,11,1,64,17,0,0,0,0,0,0,0,0,64,17,0,0,0,0,0,0,0,0,7,0,57,0,56,10,11,13,18,2,56,11,2,11,1,0,0,43,213,1,10,4,46,17,34,12,11,10,11,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,4,1,7,11,39,10,11,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,4,1,7,14,39,10,2,55,0,20,7,0,33,4,50,7,1,10,2,54,0,21,10,2,46,56,12,7,1,18,3,56,13,10,2,55,0,20,7,1,33,4,57,5,65,11,2,1,11,0,1,11,4,1,7,13,39,11,4,46,17,35,12,15,10,0,10,15,17,6,10,2,54,3,12,12,10,2,54,4,12,10,10,2,55,5,56,14,4,85,8,12,5,5,92,10,11,10,2,55,5,56,15,20,35,12,5,11,5,4,138,1,10,12,14,15,12,6,46,11,6,56,4,32,4,111,10,10,14,15,12,7,46,11,7,56,4,32,12,8,5,113,9,12,8,11,8,4,116,5,126,11,2,1,11,0,1,11,12,1,11,10,1,7,10,39,11,3,4,134,1,11,10,1,10,12,11,15,68,17,5,137,1,11,10,11,15,68,17,5,140,1,11,10,1,10,2,55,5,56,14,4,147,1,8,12,9,5,154,1,11,11,10,2,55,5,56,15,20,38,12,9,11,9,4,205,1,10,0,16,3,65,17,12,14,11,12,46,65,17,12,13,11,14,11,13,17,7,4,184,1,7,2,10,2,54,0,21,11,2,46,56,12,7,2,18,3,56,13,11,0,16,2,56,16,17,13,56,17,2,11,0,1,10,2,55,5,56,18,4,201,1,7,3,10,2,54,0,21,11,2,46,56,12,7,3,18,3,56,13,5,203,1,11,2,1,56,19,2,11,2,1,11,0,1,11,12,1,56,19,2,12,1,4,0,1,45,10,1,46,17,34,10,0,55,1,20,35,4,21,10,0,55,0,20,7,0,33,4,15,5,21,11,0,1,11,1,1,7,12,39,11,1,46,17,35,10,0,55,6,20,33,4,30,5,34,11,0,1,7,15,39,7,4,10,0,54,0,21,11,0,46,56,12,7,4,18,3,56,13,2,0,2,0,7,0,1,0,6,0,3,0,4,0,5,1,9,1,4,1,2,1,7,1,8,1,3,1,1,7,23,8,23,9,23,10,23,11,23,12,23,13,23,0],"governance_v2":[161,28,235,11,6,0,0,0,13,1,0,28,2,28,74,3,102,145,2,4,247,2,58,5,177,3,229,3,7,150,7,131,8,8,153,15,96,6,249,15,129,2,10,250,17,95,11,217,18,2,12,219,18,171,13,13,134,32,38,14,172,32,18,0,54,0,48,0,64,1,22,1,69,1,87,1,93,2,23,2,29,2,41,2,68,2,84,2,85,2,86,0,5,8,0,0,9,8,2,6,0,0,1,0,3,3,0,0,1,3,0,1,4,0,0,1,6,12,0,3,10,7,0,4,8,7,1,0,0,5,13,7,0,7,0,4,1,0,1,8,2,12,1,0,1,10,7,7,0,10,14,4,0,11,11,12,2,7,1,4,1,13,12,2,0,0,59,0,1,0,0,15,2,1,0,0,91,3,4,0,0,18,5,1,0,0,75,5,1,0,0,90,6,1,0,0,89,7,1,0,0,27,8,1,0,0,39,9,10,0,0,51,11,12,2,6,0,0,35,13,1,0,0,32,14,1,2,6,0,0,94,15,16,2,6,0,0,25,17,1,2,6,0,0,28,11,1,2,6,0,1,31,59,13,0,1,34,13,1,0,2,63,40,41,1,0,3,83,37,12,0,4,24,58,52,1,0,4,43,28,26,1,0,4,46,27,1,1,0,4,67,1,22,1,0,4,78,26,22,1,0,5,49,1,23,1,0,5,50,47,12,0,6,30,30,10,1,0,6,58,30,32,1,0,6,74,33,26,1,0,7,61,54,35,1,0,7,79,61,48,1,0,7,92,57,35,1,0,8,36,41,1,1,0,8,47,62,41,1,0,8,60,41,48,1,0,9,37,26,1,1,3,10,57,52,24,1,8,10,65,0,21,0,10,88,45,46,0,11,17,44,1,2,7,4,11,30,55,10,2,7,4,11,65,0,43,2,7,4,11,74,56,39,2,7,4,12,73,64,1,1,12,12,77,26,1,1,8,13,40,20,35,0,13,76,20,19,0,22,4,22,23,44,25,21,23,21,4,20,4,26,19,27,19,28,19,17,39,41,42,39,42,24,26,34,39,44,49,35,50,36,49,35,53,29,39,40,42,42,42,31,39,22,13,32,39,19,4,23,13,30,39,33,39,43,63,1,7,8,14,0,4,6,8,4,7,8,0,8,8,8,5,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,4,6,8,4,7,8,0,3,3,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,2,9,0,9,1,7,8,14,1,8,6,1,8,4,5,6,8,0,9,0,10,11,10,1,9,1,3,7,8,14,7,6,8,0,9,0,7,11,1,2,9,0,9,1,10,11,10,1,9,1,3,1,7,8,14,1,11,7,1,8,4,3,6,8,0,7,11,1,2,9,0,9,1,7,8,14,1,10,5,1,5,1,6,8,14,1,8,12,1,11,7,1,9,0,1,8,8,1,8,11,1,8,0,1,9,0,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,2,9,0,9,1,1,10,2,15,8,8,3,3,3,5,8,12,5,3,3,3,11,13,2,5,3,8,12,8,11,11,10,1,9,1,3,1,9,1,3,10,11,10,1,9,0,3,7,8,14,1,11,10,1,9,0,2,5,3,1,11,13,2,9,0,9,1,3,7,11,13,2,9,0,9,1,9,0,9,1,1,6,8,12,1,6,8,11,1,6,8,8,1,11,9,1,9,0,1,11,1,2,9,0,9,1,1,8,2,17,11,7,1,8,4,11,7,1,8,4,5,5,5,5,1,3,3,7,11,13,2,5,3,3,3,3,7,11,13,2,5,3,11,10,1,9,1,5,3,1,6,9,0,1,8,3,2,7,11,9,1,9,0,11,9,1,9,0,2,6,11,13,2,9,0,9,1,9,0,2,7,11,13,2,9,0,9,1,9,0,1,6,11,9,1,9,0,1,6,11,7,1,9,0,1,6,8,5,11,1,1,1,5,5,7,11,13,2,5,3,3,7,11,13,2,5,3,5,3,3,2,7,11,9,1,9,0,3,2,11,9,1,9,0,7,8,14,1,11,10,1,9,1,2,9,0,5,7,66,97,108,97,110,99,101,11,67,104,97,110,103,101,83,116,97,116,101,4,67,111,105,110,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,3,97,100,100,13,97,100,100,95,103,117,97,114,100,105,97,110,115,11,97,103,97,105,110,115,116,95,110,117,109,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,15,99,104,101,99,107,95,103,117,97,114,100,105,97,110,115,5,99,108,97,105,109,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,9,102,97,118,111,114,95,110,117,109,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,20,103,111,118,101,114,110,97,110,99,101,95,99,111,105,110,95,116,121,112,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,50,9,103,117,97,114,100,105,97,110,115,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,4,106,111,105,110,9,109,97,120,95,100,101,108,97,121,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,24,112,114,111,112,111,115,97,108,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,103,117,97,114,100,105,97,110,115,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,115,112,108,105,116,11,115,116,97,107,101,100,95,99,111,105,110,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,22,117,112,100,97,116,101,95,109,105,110,117,109,117,109,95,115,116,97,107,105,110,103,7,117,112,103,114,97,100,101,5,118,97,108,117,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,22,118,111,116,105,110,103,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,255,255,255,255,255,255,255,255,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,11,57,8,12,53,11,7,1,8,5,52,11,7,1,8,8,55,10,5,16,1,21,3,95,3,62,3,72,3,96,3,56,10,8,11,1,2,13,57,8,12,33,5,81,3,38,3,42,3,70,8,6,26,9,0,80,11,9,1,9,1,44,3,45,11,13,2,5,3,19,3,20,11,13,2,5,3,82,2,2,2,1,71,8,11,3,2,2,71,8,11,66,2,1,36,0,0,0,0,18,22,64,19,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,46,68,19,11,0,17,37,56,0,56,1,64,19,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,6,1,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,64,24,0,0,0,0,0,0,0,0,18,0,56,2,2,1,1,0,0,10,34,10,1,16,0,20,32,4,12,10,1,16,1,65,24,6,0,0,0,0,0,0,0,0,33,12,4,5,14,9,12,4,11,4,4,17,5,21,11,1,1,7,6,39,10,1,15,2,11,2,56,3,10,1,15,3,11,3,56,4,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,3,56,5,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,29,19,10,1,15,4,14,2,12,3,46,11,3,56,6,32,4,10,5,14,11,1,1,7,10,39,11,1,15,4,11,2,68,19,2,4,1,0,0,31,21,10,1,10,2,12,3,46,11,3,17,7,10,1,15,4,14,2,12,4,46,11,4,56,7,12,5,1,11,1,15,4,11,5,56,8,1,2,5,1,0,0,1,9,11,2,10,1,15,5,21,11,3,11,1,15,6,21,2,6,1,0,0,1,33,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,9,11,1,1,7,8,39,10,4,10,3,10,2,22,36,4,16,5,20,11,1,1,7,8,39,11,2,10,1,15,7,21,11,3,10,1,15,8,21,11,4,11,1,15,9,21,2,7,1,0,0,1,9,11,0,16,4,14,1,56,6,4,6,5,8,7,9,39,2,8,1,0,0,9,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,9,1,0,0,34,75,11,1,46,17,45,12,7,10,0,55,0,20,7,3,33,4,16,11,0,1,7,21,17,18,12,6,5,73,10,0,55,0,20,7,4,33,4,28,11,0,1,7,22,17,18,12,5,5,71,10,0,55,0,20,7,5,33,4,40,11,0,1,7,23,17,18,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,24,17,18,12,3,5,67,11,0,55,0,20,7,1,33,4,62,7,25,17,18,12,2,5,65,7,26,17,18,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,10,1,0,0,1,3,11,0,17,16,2,11,1,0,0,38,103,10,0,16,0,20,4,5,5,11,11,0,1,11,4,1,7,7,39,11,2,10,3,10,4,56,9,12,18,10,3,10,0,16,5,20,38,4,23,5,29,11,0,1,11,4,1,7,16,39,10,4,46,17,46,12,11,10,4,46,17,45,12,12,10,12,10,0,16,7,20,22,12,19,10,19,10,0,16,8,20,22,12,13,11,12,11,0,16,9,20,22,12,14,10,4,56,10,12,15,13,15,10,11,10,3,56,11,10,4,17,37,12,16,14,16,17,38,20,12,17,11,16,12,10,11,11,12,9,11,19,12,8,11,13,12,7,11,14,12,6,56,12,12,5,11,10,11,9,11,8,11,7,11,6,14,5,17,25,11,1,11,18,56,13,11,3,11,15,6,0,0,0,0,0,0,0,0,11,4,56,10,7,1,57,0,56,14,11,17,18,2,56,15,2,12,1,0,0,51,175,2,10,6,46,17,45,12,17,10,17,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,6,1,7,12,39,10,17,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,6,1,7,15,39,10,2,55,0,20,7,1,33,4,50,7,2,10,2,54,0,21,10,2,46,56,16,7,2,18,3,56,17,10,2,55,0,20,7,2,33,4,57,5,65,11,2,1,11,0,1,11,6,1,7,14,39,10,6,46,17,46,12,22,10,2,54,3,12,20,10,2,54,4,12,16,11,3,10,4,11,6,56,9,12,21,11,17,10,2,55,5,20,35,4,237,1,11,0,1,10,2,54,6,11,21,56,13,56,18,1,11,5,4,158,1,10,2,55,7,20,10,4,22,10,2,54,7,21,11,4,12,18,10,20,10,22,12,9,46,11,9,56,19,4,119,11,18,10,20,10,22,56,20,22,12,18,10,16,10,22,12,10,46,11,10,56,19,4,151,1,11,16,10,22,56,20,12,14,10,2,55,7,20,10,14,22,10,2,54,7,21,10,2,55,8,20,10,14,23,10,2,54,8,21,11,18,11,14,22,12,18,5,153,1,11,16,1,11,20,11,22,11,18,56,11,5,219,1,10,2,55,8,20,10,4,22,10,2,54,8,21,11,4,12,15,10,16,10,22,12,11,46,11,11,56,19,4,181,1,11,15,10,16,10,22,56,20,22,12,15,10,20,10,22,12,12,46,11,12,56,19,4,213,1,11,20,10,22,56,20,12,19,10,2,55,8,20,10,19,22,10,2,54,8,21,10,2,55,7,20,10,19,23,10,2,54,7,21,11,15,11,19,22,12,15,5,215,1,11,20,1,11,16,11,22,11,15,56,11,10,2,55,7,20,10,2,55,8,20,22,11,2,55,6,56,21,33,4,232,1,5,234,1,7,19,39,56,22,12,8,5,173,2,11,20,1,11,16,1,11,21,56,23,10,2,55,7,20,10,2,55,8,20,22,12,23,10,23,10,2,55,7,20,17,8,4,136,2,11,23,10,0,16,6,20,38,12,13,5,138,2,9,12,13,11,13,4,157,2,7,3,10,2,54,0,21,11,2,46,56,16,7,3,18,3,56,17,11,0,16,3,56,24,17,15,56,25,12,7,5,171,2,11,0,1,7,4,10,2,54,0,21,11,2,46,56,16,7,4,18,3,56,17,56,22,12,7,11,7,12,8,11,8,2,13,1,4,0,19,41,10,2,46,17,45,10,1,55,1,20,35,4,23,10,1,55,0,20,7,1,33,4,15,5,23,11,1,1,11,0,1,11,2,1,7,13,39,11,2,46,17,46,12,3,11,0,11,3,17,7,7,5,10,1,54,0,21,11,1,46,56,16,7,5,18,3,56,17,2,14,1,4,0,60,129,1,10,1,46,17,45,12,8,10,0,55,0,20,7,3,33,4,13,8,12,2,5,19,10,0,55,0,20,7,4,33,12,2,11,2,4,24,8,12,3,5,30,10,0,55,0,20,7,5,33,12,3,11,3,4,35,8,12,4,5,41,11,8,10,0,55,1,20,38,12,4,11,4,4,44,5,50,11,0,1,11,1,1,7,20,39,10,1,46,17,46,12,10,10,0,54,3,12,9,10,0,54,4,12,7,10,9,10,10,12,5,46,11,5,56,19,4,90,11,7,1,11,9,10,10,56,20,12,12,10,0,54,6,10,12,56,26,11,1,56,27,11,10,56,28,10,0,55,7,20,11,12,23,11,0,54,7,21,5,128,1,11,9,1,10,7,10,10,12,6,46,11,6,56,19,4,100,5,108,11,0,1,11,1,1,11,7,1,7,11,39,11,7,10,10,56,20,12,11,10,0,54,6,10,11,56,26,11,1,56,27,11,10,56,28,10,0,55,8,20,11,11,23,11,0,54,8,21,2,0,4,0,10,0,2,0,1,0,3,0,8,0,9,0,5,0,6,0,7,1,12,1,4,1,2,1,9,1,11,1,3,1,7,1,8,1,10,10,36,11,36,12,36,13,36,14,36,15,36,16,36,17,36,18,36,0],"lending_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,126,4,136,1,2,5,138,1,175,1,7,185,2,166,4,8,223,6,32,6,255,6,41,12,168,7,192,10,0,22,0,9,0,23,1,0,7,0,0,20,0,1,0,0,21,0,1,0,0,16,0,1,0,0,19,0,1,0,0,18,0,1,0,0,15,0,1,0,0,17,0,1,0,0,10,2,3,0,0,1,3,2,0,0,14,4,3,0,0,5,3,4,0,0,12,5,3,0,0,3,3,6,0,0,13,7,3,0,0,4,3,7,0,1,2,3,11,0,1,11,11,3,0,2,6,17,18,0,2,7,17,19,0,2,8,17,1,0,2,24,9,0,0,2,25,10,0,0,2,26,13,0,0,2,27,12,0,0,2,28,15,16,1,1,24,1,0,1,2,4,13,3,8,0,2,1,10,2,6,13,3,3,8,0,8,0,2,4,13,3,8,0,3,5,13,3,8,0,3,2,2,10,13,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,11,10,2,10,2,10,2,10,2,3,3,2,3,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,3,10,2,10,2,10,2,16,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,2,3,8,0,13,13,8,0,13,13,10,2,10,2,10,2,10,2,10,2,3,3,2,3,3,13,8,0,13,3,3,10,2,3,10,10,2,10,2,10,2,3,13,10,13,13,3,2,13,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,101,110,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,101,110,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,8,24,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,22,11,4,2,8,1,0,0,14,92,6,0,0,0,0,0,0,0,0,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,1,14,1,17,17,12,11,11,6,11,5,22,12,6,6,8,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,2,14,2,17,18,12,8,11,6,11,5,22,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,3,14,3,17,17,12,9,11,6,11,5,22,12,6,11,9,52,12,5,14,0,10,6,10,6,10,5,22,56,0,17,15,12,10,11,6,11,5,22,12,6,6,1,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,4,14,4,17,19,12,7,11,6,11,5,22,14,0,65,1,33,4,85,5,87,7,0,39,11,11,11,8,11,10,11,7,2,9,1,0,0,20,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,20,13,6,11,1,17,21,13,6,11,2,17,21,11,3,17,16,12,7,13,6,14,7,65,1,75,17,20,13,6,11,7,17,23,11,4,17,16,12,8,13,6,14,8,65,1,75,17,20,13,6,11,8,17,23,13,6,11,5,17,22,11,6,2,10,1,0,0,21,141,1,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,18,12,11,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,18,12,7,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,15,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,19,12,10,11,9,11,8,22,14,0,65,1,33,4,132,1,5,134,1,7,0,39,11,16,11,11,11,7,11,12,11,15,11,10,2,11,1,0,0,8,27,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,21,13,4,7,6,17,22,11,4,2,12,1,0,0,22,118,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,1,14,1,17,17,12,11,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,2,14,2,17,18,12,10,11,7,11,6,22,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,3,14,3,17,17,12,13,11,7,11,6,22,12,7,11,13,52,12,6,14,0,10,7,10,7,10,6,22,56,0,17,15,12,12,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,4,14,4,17,18,12,9,11,7,11,6,22,12,7,6,1,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,5,14,5,17,19,12,8,11,7,11,6,22,12,7,10,8,7,6,33,4,102,5,104,7,1,39,11,7,14,0,65,1,33,4,110,5,112,7,0,39,11,11,11,10,11,12,11,9,11,8,2,13,1,0,0,23,32,64,1,0,0,0,0,0,0,0,0,12,3,14,0,65,18,12,4,13,3,10,4,75,17,20,6,0,0,0,0,0,0,0,0,12,2,10,2,10,4,35,4,27,5,16,13,3,14,0,10,2,66,18,20,17,20,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,13,3,11,1,17,22,11,3,2,14,1,0,0,24,76,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,1,14,1,17,17,12,10,11,8,11,4,22,12,8,72,0,0,12,7,64,18,0,0,0,0,0,0,0,0,12,6,10,7,10,10,35,4,51,5,27,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,2,14,2,17,17,12,5,13,6,11,5,68,18,11,8,11,4,22,12,8,11,7,72,1,0,22,12,7,5,22,6,1,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,3,14,3,17,19,12,9,11,8,11,4,22,14,0,65,1,33,4,71,5,73,7,0,39,11,6,11,9,2,0],"lending_core_storage":[161,28,235,11,6,0,0,0,12,1,0,20,2,20,52,3,72,245,2,4,189,3,40,5,229,3,172,2,7,145,6,149,16,8,166,22,96,6,134,23,20,10,154,23,101,12,255,23,239,16,13,238,40,62,15,172,41,6,0,77,0,17,0,43,0,91,1,122,2,31,2,87,2,109,2,112,2,115,0,6,8,0,0,11,4,0,0,4,4,0,0,5,4,0,0,1,4,0,1,0,12,0,1,8,12,0,2,3,0,0,5,2,8,0,6,10,4,0,7,7,12,2,7,1,4,1,9,9,2,0,0,72,0,1,0,0,93,2,1,0,0,104,3,1,0,0,102,3,1,0,0,106,4,1,0,0,105,4,1,0,0,99,4,1,0,0,103,4,1,0,0,100,4,1,0,0,101,5,1,0,0,45,6,7,0,0,61,8,9,0,0,73,10,11,0,0,30,10,11,0,0,58,6,12,0,0,42,13,11,0,0,41,10,11,0,0,65,13,9,0,0,63,13,9,0,0,66,13,14,0,0,64,13,14,0,0,67,13,14,0,0,69,15,9,0,0,68,15,9,0,0,60,10,12,0,0,52,10,9,0,0,62,10,9,0,0,59,10,9,0,0,57,10,9,0,0,46,10,9,0,0,50,10,9,0,0,53,10,9,0,0,56,10,9,0,0,51,10,9,0,0,55,10,9,0,0,54,10,9,0,0,48,10,9,0,0,47,10,9,0,0,49,10,16,0,0,44,6,17,0,0,85,18,1,0,0,29,18,1,0,0,84,18,1,0,0,28,18,1,0,0,14,15,1,0,0,96,15,1,0,0,13,15,1,0,0,95,15,1,0,0,15,15,1,0,0,97,15,1,0,0,119,19,1,0,0,117,20,1,0,0,118,21,1,0,0,116,22,1,0,0,40,23,1,0,1,45,17,7,0,1,92,0,26,0,3,90,1,9,0,4,34,46,11,1,0,4,71,46,48,1,0,4,94,49,31,1,0,5,110,8,12,0,6,86,24,25,0,7,12,34,1,2,7,4,7,20,32,39,2,7,4,7,23,36,37,2,7,4,7,34,32,11,2,7,4,7,81,40,12,2,7,4,7,86,24,28,2,7,4,7,94,36,44,2,7,4,8,107,31,1,1,8,68,27,68,29,70,30,66,27,68,33,63,27,65,27,64,27,67,27,66,29,64,29,66,33,64,33,69,33,63,33,65,29,58,7,59,7,60,7,63,29,3,6,8,7,7,8,6,7,8,11,0,17,6,8,7,7,8,0,6,8,8,13,1,1,3,15,15,15,15,15,15,15,15,15,7,8,11,4,6,8,7,7,8,0,13,1,4,6,8,7,7,8,0,13,15,7,6,8,7,7,8,0,13,15,15,15,15,1,7,8,0,1,13,1,6,8,8,1,15,2,7,8,0,13,1,1,1,3,2,7,8,0,3,1,10,13,3,7,8,0,3,13,4,15,15,15,15,1,6,8,5,4,7,8,0,13,3,15,4,7,8,0,6,8,8,3,15,3,7,8,0,13,15,6,7,8,0,13,15,15,15,15,4,7,8,0,13,15,15,3,7,8,0,6,8,8,3,1,7,8,11,1,8,9,1,8,5,2,13,8,2,1,11,10,2,9,0,9,1,2,3,8,1,1,8,0,1,9,0,2,6,11,10,2,9,0,9,1,9,0,2,3,15,3,7,11,10,2,9,0,9,1,9,0,9,1,1,7,8,2,2,7,11,10,2,9,0,9,1,9,0,1,7,9,1,1,7,8,4,1,6,9,1,1,6,11,10,2,9,0,9,1,2,15,6,8,2,1,6,8,4,2,15,7,8,3,1,9,1,1,7,8,1,2,6,10,9,0,6,9,0,2,3,7,8,1,2,1,3,2,7,10,9,0,3,2,3,7,8,2,6,65,112,112,67,97,112,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,11,82,101,115,101,114,118,101,68,97,116,97,13,83,99,97,108,101,100,66,97,108,97,110,99,101,7,83,116,111,114,97,103,101,5,84,97,98,108,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,85,115,101,114,73,110,102,111,3,97,100,100,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,17,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,16,98,97,115,101,95,98,111,114,114,111,119,95,114,97,116,101,6,98,111,114,114,111,119,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,18,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,49,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,50,23,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,5,99,108,111,99,107,22,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,11,99,111,108,108,97,116,101,114,97,108,115,8,99,111,110,116,97,105,110,115,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,23,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,22,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,13,100,116,111,107,101,110,95,115,99,97,108,101,100,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,10,103,101,116,95,97,112,112,95,105,100,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,18,103,101,116,95,114,101,115,101,114,118,101,95,108,101,110,103,116,104,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,13,103,101,116,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,2,105,100,8,105,110,100,101,120,95,111,102,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,12,105,115,111,108,97,116,101,95,100,101,98,116,19,108,97,115,116,95,97,118,101,114,97,103,101,95,117,112,100,97,116,101,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,13,108,105,113,117,105,100,95,97,115,115,101,116,115,5,108,111,97,110,115,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,13,111,116,111,107,101,110,95,115,99,97,108,101,100,3,114,97,121,8,114,97,121,95,109,97,116,104,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,20,114,101,103,105,115,116,101,114,95,110,101,119,95,114,101,115,101,114,118,101,6,114,101,109,111,118,101,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,8,114,101,115,101,114,118,101,115,22,115,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,22,115,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,23,115,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,27,115,101,116,95,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,26,115,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,21,115,101,116,95,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,22,115,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,8,116,114,101,97,115,117,114,121,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,10,117,115,101,114,95,105,110,102,111,115,10,117,115,101,114,95,115,116,97,116,101,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,70,8,9,16,8,5,98,11,10,2,13,8,2,120,11,10,2,3,8,1,1,2,5,18,15,75,15,82,10,13,33,10,13,83,10,13,2,2,17,73,1,27,1,74,15,76,15,113,3,114,15,108,15,21,15,36,15,38,15,35,15,37,15,32,15,22,15,24,8,4,89,8,3,39,8,3,3,2,2,121,11,10,2,3,15,111,15,4,2,4,19,15,25,15,26,15,88,15,0,1,0,0,1,13,10,2,17,62,11,0,11,1,10,2,17,56,10,2,56,0,11,2,56,1,18,0,56,2,2,1,1,0,0,1,49,10,1,16,0,10,3,56,3,32,4,7,5,15,11,1,1,11,16,1,11,2,1,7,0,39,11,1,15,0,11,3,11,4,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,2,17,11,11,6,11,7,11,8,11,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,57,17,57,11,10,11,11,11,12,11,13,11,14,11,15,18,4,10,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,11,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,18,2,56,5,2,2,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,1,21,2,3,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,2,21,2,4,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,3,21,2,5,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,4,21,2,6,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,5,21,2,7,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,6,21,2,8,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,7,21,2,9,1,0,0,38,23,11,1,15,0,11,2,56,6,15,8,12,7,11,3,10,7,15,9,21,11,4,10,7,15,10,21,11,5,10,7,15,11,21,11,6,11,7,15,12,21,2,10,1,0,0,1,4,11,0,16,13,17,55,2,11,1,0,0,1,6,11,0,17,61,6,232,3,0,0,0,0,0,0,26,77,2,12,1,0,0,1,7,11,0,16,0,11,1,56,7,16,1,20,2,13,1,0,0,1,7,11,0,16,0,11,1,56,7,16,2,20,2,14,1,0,0,1,4,11,0,16,0,56,8,2,15,1,0,0,12,8,11,0,15,14,11,1,12,2,46,11,2,56,9,2,16,1,0,0,7,8,11,0,15,0,11,1,12,2,46,11,2,56,3,2,17,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,15,20,2,18,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,16,20,2,19,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,17,20,2,20,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,18,20,2,21,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,19,20,2,22,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,20,16,21,10,1,56,11,4,19,11,4,16,20,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,23,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,22,16,21,10,1,56,11,4,19,11,4,16,22,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,24,1,0,0,1,7,11,0,16,0,11,1,56,7,16,23,20,2,25,1,0,0,1,7,11,0,16,0,11,1,56,7,16,24,20,2,26,1,0,0,1,7,11,0,16,0,11,1,56,7,16,3,20,2,27,1,0,0,1,7,11,0,16,0,11,1,56,7,16,4,20,2,28,1,0,0,1,7,11,0,16,0,11,1,56,7,16,5,20,2,29,1,0,0,1,7,11,0,16,0,11,1,56,7,16,7,20,2,30,1,0,0,1,7,11,0,16,0,11,1,56,7,16,6,20,2,31,1,0,0,1,7,11,0,16,0,11,1,56,7,16,25,20,2,32,1,0,0,1,8,11,0,16,0,11,1,56,7,16,20,16,26,20,2,33,1,0,0,1,8,11,0,16,0,11,1,56,7,16,22,16,26,20,2,34,1,0,0,1,7,11,0,16,0,11,1,56,7,16,27,20,2,35,1,0,0,1,7,11,0,16,0,11,1,56,7,16,28,20,2,36,1,0,0,1,7,11,0,16,0,11,1,56,7,16,29,20,2,37,1,0,0,1,7,11,0,16,0,11,1,56,7,16,30,20,2,38,1,0,0,42,19,11,0,16,0,11,1,56,7,16,8,12,2,10,2,16,9,20,10,2,16,10,20,10,2,16,11,20,11,2,16,12,20,2,39,3,0,0,1,3,11,0,16,13,2,40,3,0,0,43,35,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,41,3,0,0,43,44,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,42,3,0,0,43,35,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,43,3,0,0,43,44,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,44,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,17,14,2,56,16,32,4,16,11,3,15,17,11,2,68,7,5,18,11,3,1,2,45,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,17,14,2,56,17,12,3,4,17,11,4,15,17,11,3,56,18,1,5,19,11,4,1,2,46,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,18,14,2,56,16,32,4,16,11,3,15,18,11,2,68,7,5,18,11,3,1,2,47,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,18,14,2,56,17,12,3,4,17,11,4,15,18,11,3,56,18,1,5,19,11,4,1,2,48,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,19,14,2,56,16,32,4,16,11,3,15,19,11,2,68,7,5,18,11,3,1,2,49,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,19,14,2,56,17,12,3,4,17,11,4,15,19,11,3,56,18,1,5,19,11,4,1,2,50,3,0,0,45,15,11,0,15,14,11,2,56,15,12,4,11,1,17,11,10,4,15,15,21,11,3,11,4,15,16,21,2,51,3,0,0,35,10,11,0,15,0,11,1,56,6,12,3,11,2,11,3,15,24,21,2,52,3,0,0,50,30,10,0,15,0,10,1,56,6,12,7,11,2,10,7,15,30,21,11,3,10,7,15,28,21,11,4,11,7,15,25,21,10,0,16,0,10,1,56,7,16,23,20,12,6,11,0,11,1,11,6,11,5,17,40,2,53,3,0,0,35,14,11,0,15,0,11,1,56,6,12,4,11,2,10,4,15,29,21,11,3,11,4,15,27,21,2,54,1,0,0,12,26,10,0,15,14,10,2,12,3,46,11,3,56,9,32,4,21,11,0,15,14,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,1,17,11,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,18,1,56,19,5,25,11,0,1,11,1,1,2,0,2,2,0,2,1,2,5,2,6,2,7,2,12,2,13,2,14,4,0,4,1,4,2,4,3,0,1,0,3,1,1,1,0,1,2,1,3,1,4,2,15,3,0,2,16,2,4,2,2,2,3,3,1,2,9,2,11,2,8,2,10,0,78,0,79,0,80,0],"lending_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,36,2,36,68,3,104,198,1,4,174,2,8,5,182,2,233,3,7,159,6,228,8,8,131,15,128,1,6,131,16,30,10,161,16,36,12,197,16,230,11,0,58,0,17,0,30,0,42,0,56,0,57,0,59,0,64,0,65,0,80,0,82,1,63,2,23,2,24,2,35,2,77,2,79,3,76,0,6,3,0,0,10,3,0,1,0,12,0,2,4,7,0,3,5,8,0,5,13,8,0,7,9,8,0,8,8,12,0,9,15,12,0,10,3,12,0,11,7,7,1,0,0,12,1,8,0,13,2,12,1,0,1,15,11,2,0,16,14,2,0,17,12,12,0,0,78,0,1,0,0,81,2,1,0,0,19,2,1,0,0,70,0,1,0,0,60,0,1,0,0,18,0,1,0,0,21,0,1,0,2,47,17,14,0,2,48,17,10,0,3,22,4,1,0,4,25,14,15,0,4,26,14,35,0,4,27,14,38,0,4,28,14,23,0,4,44,1,16,0,4,45,1,16,0,4,46,1,16,0,4,52,1,16,0,4,53,1,16,0,4,54,1,16,0,5,43,5,6,0,6,18,39,1,0,6,21,39,1,0,6,36,13,1,0,6,37,36,1,0,6,38,13,1,0,6,39,13,1,0,6,40,13,30,0,8,41,24,25,0,8,50,9,10,0,8,51,9,30,0,9,49,11,12,0,10,66,7,8,0,10,67,21,22,0,10,68,21,22,0,10,71,31,12,0,11,29,29,19,1,0,11,55,27,28,1,0,14,34,19,1,1,3,38,18,37,26,36,26,38,32,10,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,10,2,6,8,11,7,8,14,0,11,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,11,12,1,8,13,10,2,6,8,11,7,8,14,17,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,10,2,2,13,3,3,8,3,8,3,13,8,3,1,6,8,4,1,7,8,5,1,6,8,2,8,7,8,15,7,8,9,6,8,2,10,2,7,8,7,7,8,8,6,8,11,7,8,14,4,8,3,8,3,15,10,2,2,7,8,7,8,3,1,13,2,6,8,8,8,3,1,3,7,6,8,7,7,8,5,7,8,6,6,8,11,3,13,15,1,10,2,4,13,3,8,3,2,1,2,1,6,8,3,1,8,0,1,9,0,27,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,6,7,8,15,7,8,9,6,8,2,10,2,6,8,11,7,8,14,2,8,3,10,2,6,13,3,3,8,3,8,3,2,3,7,8,7,13,13,1,11,10,1,8,3,1,8,3,1,6,11,10,1,9,0,1,1,1,11,10,1,9,0,1,15,11,7,8,15,7,8,9,6,8,2,7,8,7,8,3,8,3,13,3,15,11,12,1,8,13,6,8,11,1,8,1,26,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,26,7,8,5,7,8,6,6,8,11,3,3,13,13,8,3,7,8,5,7,8,6,6,8,11,3,13,15,10,2,2,15,13,8,3,8,3,3,3,3,13,13,8,3,5,13,3,8,3,3,2,8,6,8,7,7,8,5,7,8,6,6,8,11,3,3,13,13,14,8,3,7,8,5,7,8,6,6,8,11,3,13,10,2,2,6,13,10,13,3,3,3,8,3,2,10,13,2,6,6,8,7,7,8,5,7,8,6,6,8,11,3,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,76,101,110,100,105,110,103,67,111,114,101,69,118,101,110,116,6,79,112,116,105,111,110,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,6,98,111,114,114,111,119,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,112,111,111,108,95,105,100,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,9,108,105,113,117,105,100,97,116,101,17,108,105,113,117,105,100,97,116,101,95,117,115,101,114,95,105,100,5,110,111,110,99,101,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,5,114,101,112,97,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,14,115,101,110,100,101,114,95,117,115,101,114,95,105,100,8,115,101,113,117,101,110,99,101,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,18,115,111,117,114,99,101,95,99,104,97,105,110,95,110,111,110,99,101,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,9,62,3,72,3,74,13,32,13,31,13,69,10,2,16,15,61,3,20,2,1,2,5,73,3,74,13,75,3,33,8,3,20,2,0,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,26,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,18,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,1,1,4,0,20,168,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,26,12,37,11,26,17,13,12,27,12,35,12,34,12,24,12,33,12,36,10,27,17,19,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,24,77,12,25,10,1,11,34,17,29,12,28,11,2,11,37,12,16,46,11,16,17,31,12,29,14,35,17,8,12,30,10,1,10,28,11,30,17,28,12,31,14,31,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,31,56,2,12,32,10,1,10,6,11,5,10,9,10,29,10,28,11,25,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,27,12,23,10,1,10,32,17,30,10,23,38,4,113,5,125,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,32,10,35,10,36,10,33,10,23,11,7,11,9,17,35,12,11,11,32,12,12,10,36,12,13,10,33,12,14,10,27,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,33,11,29,11,36,14,35,17,8,11,28,14,35,17,7,11,23,6,0,0,0,0,0,0,0,0,11,27,18,0,56,0,2,2,1,4,0,33,167,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,25,12,36,11,25,17,13,12,26,12,34,12,33,12,23,12,32,12,35,10,26,17,15,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,23,77,12,24,10,1,11,33,17,29,12,27,11,2,11,36,12,16,46,11,16,17,31,12,28,14,34,17,8,12,29,10,1,10,27,11,29,17,28,12,30,14,30,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,30,56,2,12,31,10,1,10,6,11,5,10,9,10,28,10,27,10,24,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,23,10,1,10,31,17,30,10,24,38,4,112,5,124,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,31,10,34,10,35,10,32,10,24,11,7,11,9,17,35,12,11,11,31,12,12,10,35,12,13,10,32,12,14,10,26,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,32,11,28,11,35,14,34,17,8,11,27,14,34,17,7,11,24,6,0,0,0,0,0,0,0,0,11,26,18,0,56,0,2,3,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,25,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,17,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,4,1,4,0,34,97,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,24,12,26,12,29,12,28,11,24,17,11,12,25,12,30,12,35,12,32,12,33,11,2,10,29,12,17,46,11,17,17,31,12,31,10,1,11,28,17,29,12,27,10,1,11,35,17,29,12,34,10,1,10,6,10,5,10,8,10,31,10,27,10,26,12,23,12,22,12,21,12,20,12,19,12,18,46,11,18,11,19,11,20,11,21,11,22,11,23,17,26,11,1,11,6,11,5,11,8,10,31,10,30,10,34,11,27,12,16,12,15,12,14,12,13,12,12,12,11,12,10,46,11,10,11,11,11,12,11,13,11,14,11,15,11,16,17,24,11,32,11,31,11,33,14,29,17,8,11,34,14,29,17,7,11,26,11,30,11,25,18,0,56,0,2,5,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,14,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,21,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,6,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,16,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,22,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,0],"lending_logic":[161,28,235,11,6,0,0,0,11,1,0,27,2,27,24,3,51,189,4,4,240,4,4,5,244,4,199,3,7,187,8,241,18,8,172,27,96,6,140,28,144,2,10,156,30,15,12,171,30,196,36,15,239,66,4,0,93,0,48,0,90,0,91,0,104,0,106,0,108,0,111,0,117,1,135,1,2,35,2,40,2,95,0,2,3,0,1,1,0,0,3,5,8,0,4,4,8,0,5,3,12,0,10,0,8,0,0,42,0,1,0,0,44,2,1,0,0,45,2,3,0,0,41,2,1,0,0,43,2,1,0,0,11,4,1,0,0,31,4,1,0,0,34,5,1,0,0,103,6,7,0,0,102,8,7,0,0,83,9,7,0,0,85,10,7,0,0,88,11,7,0,0,84,11,7,0,0,89,11,7,0,0,87,12,7,0,0,33,13,1,0,0,81,12,7,0,0,82,10,7,0,0,128,1,10,3,0,0,126,14,3,0,0,125,11,3,0,0,132,1,14,3,0,0,131,1,11,3,0,0,127,10,3,0,0,129,1,10,3,0,0,133,1,10,3,0,0,134,1,10,3,0,0,28,15,3,0,0,19,15,3,0,0,24,10,3,0,0,25,16,3,0,0,27,17,18,0,0,18,19,20,0,0,119,9,3,0,0,118,9,3,0,0,37,12,1,0,0,99,21,1,0,0,15,21,1,0,0,97,21,1,0,0,13,21,1,0,0,6,8,1,0,0,113,8,1,0,0,120,22,1,0,0,123,23,1,0,0,121,24,1,0,2,51,1,27,0,2,55,1,27,0,2,56,1,27,0,2,61,1,27,0,2,65,1,27,0,2,69,1,27,0,2,80,1,27,0,3,7,11,1,0,3,8,11,1,0,3,9,11,1,0,3,14,53,1,0,3,16,53,1,0,3,30,9,7,0,3,39,30,1,0,3,46,9,7,0,3,47,12,7,0,3,49,61,31,0,3,52,9,3,0,3,53,9,3,0,3,54,9,3,0,3,57,9,3,0,3,58,9,3,0,3,59,9,3,0,3,60,9,3,0,3,62,9,3,0,3,63,9,3,0,3,64,9,3,0,3,66,9,3,0,3,67,9,3,0,3,68,9,26,0,3,70,57,3,0,3,72,9,3,0,3,73,12,3,0,3,74,12,37,0,3,75,12,3,0,3,76,12,37,0,3,77,12,37,0,3,78,11,3,0,3,79,11,3,0,3,86,9,7,0,3,98,53,1,0,3,100,53,1,0,3,114,11,1,0,3,115,11,1,0,3,116,11,1,0,3,121,63,1,0,3,122,6,1,0,3,123,60,1,0,3,124,58,1,0,4,32,32,1,0,4,71,47,48,0,5,50,62,3,0,6,20,20,3,0,6,21,6,3,0,6,22,33,3,0,6,23,33,3,0,6,26,63,3,0,7,96,18,3,0,7,109,1,3,0,7,110,18,3,0,7,112,18,3,0,8,12,18,3,0,8,17,18,3,0,8,101,18,3,0,9,36,39,7,1,0,11,38,29,1,1,3,12,107,49,26,0,111,28,110,31,8,6,8,4,7,8,2,7,8,3,6,8,5,3,3,13,13,0,7,6,8,4,7,8,2,7,8,3,6,8,5,3,13,15,1,15,6,6,8,4,7,8,2,7,8,3,6,8,5,3,13,7,6,8,1,6,8,4,7,8,2,6,8,5,13,3,15,3,7,8,2,13,15,1,1,3,7,8,2,3,15,2,7,8,2,13,3,7,8,2,7,8,3,3,3,7,8,2,3,13,2,7,8,2,3,4,7,8,3,7,8,2,3,6,8,5,4,7,8,2,7,8,3,3,13,3,7,8,3,13,15,4,7,8,2,7,8,3,3,3,6,7,8,2,7,8,3,3,3,13,13,2,15,15,7,7,8,3,13,15,13,15,15,15,4,15,15,15,15,4,7,8,2,3,13,15,4,7,8,2,7,8,3,6,8,5,3,3,7,8,2,6,8,5,13,4,6,8,4,7,8,2,13,15,12,1,15,15,15,15,15,15,15,15,3,15,15,1,3,1,2,1,8,0,1,9,0,3,7,8,2,6,8,5,3,1,13,3,7,8,3,10,13,6,8,5,3,15,15,15,5,15,15,15,15,3,3,1,15,15,5,1,15,6,13,15,10,13,1,10,13,2,1,10,13,2,6,10,9,0,6,9,0,3,1,13,10,13,2,10,13,10,13,7,6,13,15,15,10,13,3,3,15,7,15,3,3,6,13,15,10,13,15,6,6,13,15,10,13,3,3,15,6,3,3,6,13,15,10,13,15,2,2,15,2,7,8,3,13,3,15,2,3,2,3,2,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,6,15,15,15,15,15,15,6,15,3,3,6,13,10,13,3,4,7,8,2,13,3,15,3,6,13,15,10,13,5,15,6,13,15,15,10,13,7,15,15,15,15,15,15,15,1,6,8,5,4,7,8,2,6,8,5,3,15,9,15,15,15,15,15,15,15,15,15,6,7,8,2,13,15,15,15,15,1,7,8,2,3,6,8,4,13,13,4,7,8,2,13,15,15,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,23,76,101,110,100,105,110,103,67,111,114,101,69,120,101,99,117,116,101,69,118,101,110,116,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,16,97,100,100,95,105,115,111,108,97,116,101,95,100,101,98,116,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,6,97,109,111,117,110,116,13,97,115,95,99,111,108,108,97,116,101,114,97,108,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,100,116,111,107,101,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,111,116,111,107,101,110,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,115,99,97,108,101,100,28,99,97,108,99,117,108,97,116,101,95,97,99,116,117,97,108,95,108,105,113,117,105,100,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,35,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,98,97,115,101,95,100,105,115,99,111,117,110,116,30,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,100,105,115,99,111,117,110,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,25,99,97,108,99,117,108,97,116,101,95,109,97,120,95,108,105,113,117,105,100,97,116,105,111,110,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,9,99,97,108,108,95,116,121,112,101,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,22,99,104,101,99,107,95,117,115,101,114,95,102,114,101,115,104,95,112,114,105,99,101,19,99,108,97,105,109,95,102,114,111,109,95,116,114,101,97,115,117,114,121,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,13,99,111,118,101,114,95,100,101,102,105,99,105,116,4,101,109,105,116,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,13,103,101,116,95,116,105,109,101,115,116,97,109,112,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,14,104,97,115,95,99,111,108,108,97,116,101,114,97,108,11,104,97,115,95,100,101,102,105,99,105,116,19,105,115,95,98,111,114,114,111,119,97,98,108,101,95,97,115,115,101,116,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,17,105,115,95,105,115,111,108,97,116,105,111,110,95,109,111,100,101,15,105,115,95,108,105,113,117,105,100,95,97,115,115,101,116,7,105,115,95,108,111,97,110,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,109,97,116,104,3,109,105,110,11,109,105,110,116,95,100,116,111,107,101,110,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,111,116,111,107,101,110,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,24,110,111,116,95,114,101,97,99,104,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,24,110,111,116,95,114,101,97,99,104,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,6,111,114,97,99,108,101,7,112,111,111,108,95,105,100,12,112,111,111,108,95,109,97,110,97,103,101,114,3,112,111,119,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,19,114,101,100,117,99,101,95,105,115,111,108,97,116,101,95,100,101,98,116,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,19,116,111,116,97,108,95,100,116,111,107,101,110,95,115,117,112,112,108,121,19,116,111,116,97,108,95,111,116,111,107,101,110,95,115,117,112,112,108,121,24,117,112,100,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,7,117,115,101,114,95,105,100,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,27,117,115,101,114,95,116,111,116,97,108,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,21,117,115,101,114,95,116,111,116,97,108,95,108,111,97,110,95,118,97,108,117,101,6,118,101,99,116,111,114,11,118,105,111,108,97,116,111,114,95,105,100,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,15,32,0,0,0,200,165,25,144,185,165,111,165,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,34,76,160,196,199,203,249,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,0,2,5,130,1,3,10,15,105,13,136,1,3,29,2,0,3,0,0,25,233,1,10,1,10,5,10,6,17,13,4,6,5,16,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,5,10,7,17,14,4,22,5,32,11,1,1,11,0,1,11,2,1,11,3,1,7,8,39,10,1,10,4,10,7,17,13,4,38,5,48,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,3,10,7,17,44,10,1,10,3,10,6,17,44,10,1,10,2,10,3,10,4,17,43,10,2,10,1,10,5,10,3,17,16,10,1,10,2,10,5,17,11,32,4,73,5,83,11,1,1,11,0,1,11,2,1,11,3,1,7,6,39,10,1,10,2,10,4,10,5,10,6,10,7,17,32,12,15,12,14,10,1,10,6,17,77,12,18,10,1,10,4,10,7,17,21,12,16,10,2,10,6,11,14,10,7,11,15,11,16,11,18,17,33,12,19,12,11,12,10,12,9,10,1,10,6,17,75,12,17,10,1,10,5,10,7,10,10,17,40,10,1,10,5,10,6,10,9,17,38,10,1,10,4,10,7,11,10,17,38,10,1,11,17,10,6,11,19,17,37,10,1,10,2,10,5,17,18,4,145,1,10,1,10,5,17,36,10,1,10,4,10,6,17,14,4,184,1,10,1,10,4,10,6,17,23,12,13,10,13,10,11,17,103,12,12,10,1,10,4,10,6,11,12,17,40,10,11,10,13,36,4,183,1,10,1,10,4,10,6,17,90,10,1,10,4,10,6,11,11,11,13,23,17,37,10,1,10,4,10,6,17,54,5,210,1,10,1,10,4,10,6,11,11,17,37,10,1,10,4,10,6,17,13,32,4,202,1,10,1,10,4,10,6,17,12,32,12,8,5,204,1,9,12,8,11,8,4,210,1,10,1,10,4,10,6,17,54,10,0,10,1,10,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,0,10,1,11,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,5,17,43,11,4,11,9,11,6,11,5,17,49,18,0,56,0,2,1,3,0,0,7,128,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,4,10,5,17,14,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,18,39,10,1,10,5,10,6,17,8,4,42,5,52,11,1,1,11,0,1,11,2,1,11,3,1,7,19,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,10,6,17,37,10,1,10,4,10,5,17,13,32,4,74,10,1,10,4,10,5,17,12,32,12,7,5,76,9,12,7,11,7,4,110,10,1,10,4,17,15,4,87,10,1,10,4,10,5,17,54,5,110,10,1,10,4,17,17,32,4,97,10,1,10,4,10,5,17,53,5,110,10,1,10,5,17,85,4,106,10,1,10,4,10,5,17,54,5,110,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,51,18,0,56,0,2,2,3,0,0,18,95,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,21,12,8,11,6,10,8,17,103,12,7,10,1,10,4,10,5,10,7,17,38,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,48,5,58,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,10,7,11,8,33,4,76,10,1,10,4,10,5,17,13,4,72,10,1,10,4,10,5,17,88,5,76,10,1,10,4,10,5,17,89,11,0,10,1,10,5,10,7,17,45,11,1,11,2,11,3,10,4,17,43,11,4,10,7,11,5,6,0,0,0,0,0,0,0,0,17,52,18,0,56,0,11,7,2,3,3,0,0,1,137,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,5,17,85,32,4,29,5,39,11,1,1,11,0,1,11,2,1,11,3,1,7,13,39,10,1,10,4,17,15,4,78,10,1,10,5,17,58,4,48,5,58,11,1,1,11,0,1,11,2,1,11,3,1,7,12,39,10,1,10,4,10,6,17,9,4,64,5,74,11,1,1,11,0,1,11,2,1,11,3,1,7,11,39,10,1,10,4,10,6,17,41,10,1,10,4,10,5,17,14,32,4,88,10,1,10,4,10,5,17,55,10,1,10,4,10,5,10,6,17,39,10,2,10,1,10,4,10,3,17,16,10,2,10,5,64,31,1,0,0,0,0,0,0,0,10,3,17,95,10,1,10,2,10,4,17,11,4,109,5,119,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,10,6,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,47,18,0,56,0,2,4,3,0,0,33,88,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,23,12,7,10,6,10,7,17,103,12,9,10,1,10,4,10,5,10,9,17,40,10,1,10,4,17,15,4,45,10,1,10,4,10,9,17,42,10,6,10,7,38,4,70,10,1,10,4,10,5,17,90,11,6,11,7,23,12,8,10,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,10,1,10,4,10,5,11,8,17,37,10,1,10,4,10,5,17,54,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,9,11,5,6,0,0,0,0,0,0,0,0,17,50,18,0,56,0,2,5,3,0,0,1,82,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,12,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,14,39,10,1,10,4,17,15,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,15,39,10,1,10,4,17,17,4,56,10,1,10,5,17,85,32,4,46,5,56,11,1,1,11,0,1,11,2,1,11,3,1,7,17,39,10,1,10,4,10,5,17,89,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,46,18,0,56,0,2,6,3,0,0,1,67,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,13,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,4,10,5,17,88,10,1,10,4,10,5,17,54,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,39,5,49,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,48,18,0,56,0,2,7,1,0,0,34,49,10,2,11,3,10,4,17,44,10,2,10,4,17,75,12,11,10,2,10,11,10,4,17,21,12,10,10,2,10,11,10,4,17,23,12,9,10,10,10,9,36,4,27,11,10,11,9,23,12,7,5,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,11,6,17,103,12,8,10,2,11,11,10,4,10,8,17,38,10,2,11,5,10,4,11,8,17,37,11,1,11,2,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,2,8,1,0,0,35,23,10,0,10,1,17,74,12,4,11,0,11,1,17,34,12,5,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,15,8,12,3,5,21,11,5,11,2,22,11,4,35,12,3,11,3,2,9,1,0,0,36,33,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,5,10,0,10,5,20,17,73,12,4,11,0,11,5,20,17,68,12,6,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,8,12,3,5,31,11,6,11,2,22,11,4,35,12,3,11,3,2,10,1,0,0,1,6,11,0,11,1,17,63,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,2,11,1,0,0,1,7,11,0,11,1,11,2,17,19,17,104,36,2,12,1,0,0,38,19,10,0,10,1,17,61,4,13,11,0,11,1,17,81,12,4,14,4,14,2,56,1,12,3,5,17,11,0,1,9,12,3,11,3,2,13,1,0,0,37,8,11,0,11,1,17,79,12,3,14,3,14,2,56,1,2,14,1,0,0,37,8,11,0,11,1,17,82,12,3,14,3,14,2,56,1,2,15,1,0,0,40,25,10,0,11,1,17,79,12,4,14,4,65,31,6,1,0,0,0,0,0,0,0,33,4,19,14,4,6,0,0,0,0,0,0,0,0,66,31,20,12,3,11,0,11,3,17,85,12,2,5,23,11,0,1,9,12,2,11,2,2,16,1,0,0,41,17,10,1,10,2,17,79,12,4,11,1,11,2,17,82,12,5,10,0,11,4,10,3,17,95,11,0,11,5,11,3,17,95,2,17,1,0,0,37,9,11,0,11,1,17,79,12,2,14,2,65,31,6,0,0,0,0,0,0,0,0,36,2,18,1,0,0,35,23,10,0,10,1,10,2,17,26,12,4,11,0,11,1,11,2,17,27,12,5,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,12,3,5,21,9,12,3,11,3,2,19,1,0,0,33,23,10,0,10,1,10,2,17,24,12,4,11,0,11,1,11,2,17,25,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,19,11,4,11,5,17,105,12,3,5,21,7,0,12,3,11,3,2,20,1,0,0,3,10,11,0,11,2,10,3,17,21,12,4,11,1,11,3,11,4,17,28,2,21,1,0,0,18,13,10,0,11,1,10,2,17,84,12,4,11,0,11,2,17,70,12,3,11,4,11,3,17,107,2,22,1,0,0,3,10,11,0,11,2,10,3,17,23,12,4,11,1,11,3,11,4,17,28,2,23,1,0,0,18,13,10,0,11,1,10,2,17,83,12,4,11,0,11,2,17,64,12,3,11,4,11,3,17,107,2,24,1,0,0,42,49,10,0,10,2,17,79,12,6,14,6,65,31,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,43,5,16,14,6,10,7,66,31,12,3,10,0,10,3,20,17,66,12,4,10,0,10,1,10,2,11,3,20,17,20,12,5,11,9,11,5,11,4,17,106,22,12,9,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,11,11,0,1,11,1,1,11,9,2,25,1,0,0,43,49,10,0,10,2,17,82,12,8,14,8,65,31,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,43,5,16,14,8,10,4,66,31,12,6,10,0,10,6,20,17,63,12,3,10,0,10,1,10,2,11,6,20,17,22,12,7,11,9,11,7,11,3,17,106,22,12,9,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,11,11,0,1,11,1,1,11,9,2,26,1,0,0,44,42,10,0,10,2,17,79,12,5,14,5,65,31,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,36,5,16,14,5,10,6,66,31,12,3,10,0,10,1,10,2,11,3,20,17,20,12,4,11,8,11,4,22,12,8,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,11,11,0,1,11,1,1,11,8,2,27,1,0,0,45,42,10,0,10,2,17,82,12,7,14,7,65,31,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,36,5,16,14,7,10,3,66,31,12,5,10,0,10,1,10,2,11,5,20,17,22,12,6,11,8,11,6,22,12,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,11,11,0,1,11,1,1,11,8,2,28,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,11,4,24,6,10,0,0,0,0,0,0,0,11,3,17,112,77,26,2,29,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,6,10,0,0,0,0,0,0,0,11,3,17,112,77,24,11,4,26,2,30,1,0,0,18,16,10,0,10,1,10,2,17,24,12,3,11,0,11,1,11,2,17,25,12,4,17,104,11,3,11,4,17,105,23,2,31,1,0,0,20,52,10,0,10,3,17,61,4,5,5,11,11,0,1,11,1,1,7,16,39,10,0,10,2,17,61,4,16,5,22,11,0,1,11,1,1,7,16,39,10,0,10,1,10,3,17,30,12,5,10,0,11,2,17,78,12,4,11,0,11,1,11,3,17,25,12,7,11,4,74,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,24,17,105,17,104,17,103,17,104,22,12,6,11,5,11,6,17,106,7,1,17,103,2,32,1,0,0,50,89,10,0,10,1,11,2,10,3,17,31,12,12,10,0,10,1,10,3,17,24,12,10,10,0,10,1,10,3,17,25,12,11,10,0,10,5,17,63,12,6,10,0,10,4,17,66,12,7,11,11,7,2,17,106,11,10,23,12,19,7,2,17,104,10,12,23,17,106,11,6,17,106,11,7,23,12,18,11,19,11,18,17,105,12,14,10,0,10,1,10,3,10,4,17,20,10,14,17,105,12,8,10,14,17,104,11,12,23,17,106,12,16,11,0,10,1,11,3,10,5,17,22,10,16,17,105,12,9,11,8,11,9,17,103,17,104,17,103,12,17,10,1,11,4,11,14,10,17,17,106,17,29,12,13,11,1,11,5,11,16,11,17,17,106,17,29,12,15,11,13,11,15,2,33,1,0,0,51,45,10,5,10,4,38,4,9,11,4,12,8,11,2,12,7,5,17,11,5,12,8,11,2,10,8,11,4,17,105,17,106,12,7,10,0,10,1,10,7,17,28,12,9,10,0,11,3,10,8,17,28,12,11,11,0,11,1,11,9,11,11,23,17,29,11,6,17,106,12,12,10,7,10,12,23,12,10,11,7,11,8,11,10,11,12,2,34,1,0,0,18,12,10,0,10,1,17,72,12,3,11,0,11,1,17,70,12,2,11,3,11,2,17,106,2,35,1,0,0,18,12,10,0,10,1,17,67,12,3,11,0,11,1,17,64,12,2,11,3,11,2,17,106,2,36,0,0,0,52,49,10,0,10,1,17,82,12,6,14,6,65,31,12,4,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,46,5,14,14,6,10,3,66,31,12,5,10,0,10,5,20,17,75,12,7,10,0,10,1,10,5,20,17,23,12,2,10,0,10,1,10,5,20,10,2,17,40,10,0,11,7,11,5,20,11,2,17,39,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,9,11,0,1,2,37,0,0,0,3,12,11,3,10,0,10,2,17,70,17,109,12,4,11,0,11,2,11,1,11,4,17,87,2,38,0,0,0,3,12,11,3,10,0,10,2,17,70,17,108,12,4,11,0,11,2,11,1,11,4,17,57,2,39,0,0,0,3,12,11,3,10,0,10,2,17,64,17,109,12,4,11,0,11,2,11,1,11,4,17,86,2,40,0,0,0,3,12,11,3,10,0,10,2,17,64,17,108,12,4,11,0,11,2,11,1,11,4,17,56,2,41,0,0,0,54,21,10,0,11,1,17,79,12,5,14,5,6,0,0,0,0,0,0,0,0,66,31,12,3,10,0,10,3,20,17,68,11,2,22,12,4,11,0,11,3,20,11,4,17,92,2,42,0,0,0,55,32,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,4,10,0,10,4,20,17,68,12,5,10,5,10,2,38,4,22,11,5,11,2,23,12,3,5,24,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,12,6,11,0,11,4,20,11,6,17,92,2,43,0,0,0,56,58,10,0,10,3,17,61,4,51,10,2,17,76,12,5,10,0,10,3,17,80,12,9,10,0,10,1,10,3,17,24,12,6,10,0,11,1,10,3,17,25,12,7,10,6,10,7,36,4,45,11,6,11,7,23,12,8,10,0,10,3,17,78,12,4,11,5,11,9,11,4,11,8,17,98,12,10,11,0,11,2,11,3,11,10,17,94,5,50,11,0,11,2,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,94,5,57,11,0,1,11,1,1,11,2,1,2,44,0,0,0,59,59,11,1,17,76,12,5,10,0,10,2,17,69,12,7,10,0,10,2,17,67,12,6,10,0,10,2,17,64,12,3,10,0,10,2,17,70,12,4,10,0,10,2,17,77,12,11,10,5,10,7,10,0,10,2,17,65,17,100,10,3,17,106,12,9,10,5,11,7,10,0,10,2,17,71,17,101,11,4,17,106,12,10,11,6,10,9,11,3,23,17,106,11,11,17,106,10,10,17,109,12,8,11,0,11,2,11,9,11,10,11,5,11,8,17,93,2,45,0,0,0,20,36,11,0,10,2,10,1,17,62,17,97,12,5,10,5,10,3,38,4,11,5,15,11,1,1,7,10,39,11,5,11,3,23,12,6,10,1,10,2,10,6,17,99,12,4,10,1,10,2,10,4,11,6,17,102,12,7,11,1,11,2,11,4,11,7,17,91,2,0,92,0,94,0],"lending_portal":[161,28,235,11,6,0,0,0,11,1,0,46,2,46,94,3,140,1,185,2,4,197,3,36,5,233,3,172,6,7,149,10,184,11,8,205,21,128,1,6,205,22,88,10,165,23,59,12,224,23,204,17,13,172,41,4,0,76,0,24,0,40,0,41,0,55,0,73,0,74,0,75,0,79,0,87,0,88,0,108,0,113,0,114,1,86,2,32,2,33,2,47,2,85,2,104,2,106,2,107,3,103,0,8,8,0,0,15,3,0,0,9,3,0,0,7,3,0,1,0,12,0,2,4,7,0,3,11,12,1,0,1,4,5,0,0,4,6,8,0,6,18,8,0,9,14,8,0,10,12,12,0,11,21,12,0,12,3,12,0,13,13,8,0,14,10,7,1,0,0,15,1,8,0,16,2,12,1,0,1,18,20,4,0,19,16,2,0,21,19,2,0,22,17,12,0,0,70,0,1,0,0,64,2,3,0,0,99,4,1,0,0,25,5,1,0,0,29,5,1,0,0,30,6,1,0,0,105,7,1,1,0,0,111,8,1,1,0,0,112,9,1,0,0,26,8,1,1,0,0,27,9,1,0,0,94,7,1,1,0,0,77,10,1,1,0,2,34,13,18,0,2,35,1,18,1,0,2,36,55,18,0,2,59,45,31,0,2,63,1,20,0,3,37,38,31,1,0,3,84,37,3,1,0,3,110,53,1,1,0,4,31,17,1,0,5,46,30,31,0,5,57,1,29,0,5,58,1,29,0,5,62,1,29,0,5,66,1,29,0,5,67,1,29,0,5,68,1,29,0,6,56,56,57,0,7,25,21,1,0,7,29,21,1,0,7,48,44,1,0,7,49,64,1,0,7,50,44,1,0,7,51,44,1,0,7,52,44,52,0,8,78,24,25,1,0,10,22,39,40,0,10,54,48,49,0,10,61,43,20,0,10,65,43,52,0,10,93,39,40,0,11,60,19,3,0,11,71,19,41,0,11,91,42,1,0,12,96,58,3,0,13,95,32,3,0,14,38,51,15,1,0,14,72,50,41,1,0,16,39,25,1,1,0,16,102,27,25,1,0,16,109,28,3,1,0,17,45,15,1,1,3,18,81,0,11,0,20,89,34,1,1,12,20,100,15,1,1,8,21,97,12,13,0,22,80,26,3,0,56,14,37,23,51,23,52,23,55,33,53,35,14,15,37,15,52,15,19,15,18,15,53,46,49,18,48,18,20,15,53,59,6,15,50,15,1,7,8,20,0,1,7,8,0,1,3,3,6,8,7,7,8,0,5,8,6,8,8,7,8,9,7,8,10,6,8,16,7,8,11,7,8,12,10,13,7,8,20,9,6,8,8,6,8,16,7,8,14,7,8,0,7,8,21,10,13,10,11,17,1,8,19,3,7,8,20,11,6,8,8,7,8,9,7,8,10,6,8,16,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,17,1,9,0,3,7,8,20,10,6,8,8,7,8,9,7,8,10,6,8,16,7,8,0,7,8,11,7,8,12,7,11,6,1,9,0,3,7,8,20,16,6,8,8,7,8,9,7,8,10,6,8,16,7,8,13,7,8,0,7,8,21,7,8,11,7,8,12,10,2,10,2,13,3,10,11,17,1,8,19,3,7,8,20,14,6,8,8,7,8,9,7,8,10,6,8,16,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,17,1,9,0,3,13,10,2,3,7,8,20,1,8,18,1,6,8,20,1,5,1,8,0,1,9,0,11,8,5,7,8,9,7,8,10,6,8,16,3,13,6,13,3,3,3,8,5,1,6,8,8,1,8,5,2,6,8,12,8,5,1,13,6,6,8,11,7,8,9,7,8,10,6,8,16,3,13,7,11,17,1,8,19,3,10,2,3,3,11,17,1,8,19,3,1,8,19,3,10,11,17,1,9,0,3,7,8,20,1,11,17,1,9,0,1,6,8,21,3,7,11,17,1,9,0,3,7,8,20,1,6,11,17,1,9,0,1,2,2,10,13,2,1,10,2,7,7,8,14,7,8,21,11,17,1,8,19,13,10,2,6,8,16,7,8,20,1,11,17,1,8,19,2,9,0,5,1,8,1,17,6,8,16,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,3,11,17,1,9,0,13,3,3,8,5,8,5,2,6,11,6,1,9,0,3,5,7,11,6,1,9,0,11,17,1,9,0,13,10,2,7,8,20,4,7,8,11,8,5,13,15,2,15,15,1,1,2,7,8,12,8,5,2,7,8,11,8,5,7,6,8,11,7,8,9,7,8,10,6,8,16,3,13,15,1,6,8,5,1,8,3,16,8,5,7,8,9,7,8,10,6,8,16,3,13,15,15,13,3,13,11,15,1,8,5,8,5,8,5,8,5,15,3,7,8,11,13,13,1,11,15,1,8,5,1,6,11,15,1,9,0,1,11,15,1,9,0,1,15,5,7,11,6,1,9,0,8,5,3,8,5,7,8,20,21,8,5,7,8,9,7,8,10,6,8,16,3,13,15,15,11,17,1,8,19,13,3,11,15,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,17,1,8,19,3,2,13,10,2,1,7,8,9,1,6,8,4,11,7,8,21,7,8,13,6,8,4,7,8,11,8,5,8,5,13,3,15,11,17,1,8,19,6,8,16,1,8,2,15,8,5,7,8,9,7,8,10,6,8,16,3,13,15,13,3,13,11,15,1,8,5,8,5,8,5,8,5,15,20,8,5,7,8,9,7,8,10,6,8,16,3,13,15,11,17,1,8,19,13,3,11,15,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,17,1,8,19,3,17,6,8,16,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,13,3,3,8,5,3,11,17,1,9,0,8,5,16,13,8,5,7,8,9,7,8,10,6,8,16,3,3,13,13,8,5,3,8,5,3,5,13,8,5,8,6,8,11,7,8,9,7,8,10,6,8,16,3,3,13,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,17,76,101,110,100,105,110,103,76,111,99,97,108,69,118,101,110,116,13,76,101,110,100,105,110,103,80,111,114,116,97,108,18,76,101,110,100,105,110,103,80,111,114,116,97,108,69,118,101,110,116,6,79,112,116,105,111,110,4,80,111,111,108,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,9,80,111,111,108,83,116,97,116,101,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,13,97,100,100,95,108,105,113,117,105,100,105,116,121,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,12,98,111,114,114,111,119,95,108,111,99,97,108,13,98,111,114,114,111,119,95,114,101,109,111,116,101,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,27,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,95,114,101,109,111,116,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,7,100,101,112,111,115,105,116,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,17,100,111,108,97,95,112,111,111,108,95,97,100,100,114,101,115,115,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,32,101,110,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,10,102,101,101,95,97,109,111,117,110,116,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,2,105,100,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,9,108,105,113,117,105,100,97,116,101,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,11,109,101,115,115,97,103,101,95,102,101,101,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,7,114,101,108,97,121,101,114,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,5,114,101,112,97,121,12,115,101,110,100,95,109,101,115,115,97,103,101,13,115,101,110,100,95,119,105,116,104,100,114,97,119,6,115,101,110,100,101,114,8,115,101,113,117,101,110,99,101,11,115,101,116,95,114,101,108,97,121,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,112,108,105,116,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,14,119,105,116,104,100,114,97,119,95,108,111,99,97,108,15,119,105,116,104,100,114,97,119,95,114,101,109,111,116,101,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,13,2,1,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,69,8,18,92,5,82,3,1,2,5,98,3,83,3,44,8,5,53,3,28,2,2,2,8,83,3,97,5,42,10,2,101,13,43,13,90,10,2,23,3,28,2,3,2,5,83,3,97,5,42,10,2,23,3,28,2,0,0,0,0,1,9,10,0,17,54,11,0,46,17,57,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,0,0,1,5,11,2,11,1,15,1,21,2,3,1,4,0,16,61,11,0,17,21,11,7,46,17,57,17,13,12,18,11,5,11,18,12,8,46,11,8,17,43,12,15,14,6,65,20,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,20,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,30,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,4,1,4,0,16,61,11,0,17,21,11,7,46,17,57,17,13,12,18,11,5,11,18,12,8,46,11,8,17,43,12,15,14,6,65,20,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,20,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,31,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,5,0,4,0,22,66,11,0,17,21,11,6,10,7,10,8,56,1,12,9,10,4,46,17,58,12,15,11,7,10,15,38,4,16,5,28,11,4,1,11,2,1,11,3,1,11,8,1,11,1,1,7,3,39,13,9,11,15,10,8,56,2,12,14,14,9,56,3,12,12,11,5,17,24,17,22,12,11,10,3,17,1,12,10,11,2,11,4,11,14,7,5,11,11,11,1,11,8,17,47,12,13,11,9,11,3,16,1,20,56,4,11,13,11,10,7,6,17,13,11,12,17,24,18,1,56,5,2,6,1,4,0,36,117,11,0,17,21,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,57,17,13,12,27,56,6,12,26,11,8,11,9,10,10,56,7,12,22,10,7,14,22,56,8,12,15,46,11,15,56,9,12,21,11,4,17,1,12,25,11,7,11,22,7,5,64,29,0,0,0,0,0,0,0,0,10,10,56,10,1,10,6,10,26,7,5,10,21,77,17,38,1,12,20,10,5,10,27,12,16,46,11,16,17,44,32,4,74,10,5,10,27,17,45,10,6,10,26,17,40,12,23,11,5,11,27,12,17,46,11,17,17,43,12,24,11,6,11,1,11,2,11,3,11,24,11,23,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,35,11,25,11,10,46,17,57,14,26,17,16,11,21,17,27,18,3,56,11,2,7,1,4,0,47,117,11,0,17,21,17,17,12,20,10,9,46,17,57,17,13,12,24,56,6,12,23,10,5,10,23,17,40,12,18,11,6,10,24,12,10,46,11,10,17,43,12,19,10,5,10,18,11,20,17,39,12,21,14,21,56,12,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,21,56,13,12,22,10,5,11,1,11,2,11,3,11,19,11,18,11,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,36,12,17,10,5,10,22,17,41,10,17,38,4,80,5,90,11,5,1,11,7,1,11,4,1,11,9,1,7,1,39,11,5,11,22,7,5,10,17,17,42,1,12,25,11,7,11,24,11,25,52,10,23,10,9,56,14,11,4,17,1,11,9,46,17,57,14,23,17,16,11,17,52,17,28,18,3,56,11,2,8,1,4,0,54,184,1,11,0,17,21,10,11,10,10,17,15,12,31,10,11,11,9,17,15,12,30,10,15,46,17,57,17,13,12,34,10,7,10,30,17,40,12,25,11,8,11,34,12,16,46,11,16,17,43,12,26,10,7,10,25,10,11,17,39,12,27,14,27,56,12,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,27,56,13,12,28,10,7,10,1,11,2,10,3,11,26,11,25,11,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,36,12,23,10,7,10,28,17,41,10,23,38,4,86,5,102,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,11,13,10,14,10,15,56,1,12,24,10,6,46,17,58,12,36,11,14,10,36,38,4,116,5,132,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,24,11,36,10,15,56,2,12,35,14,24,56,3,12,32,10,5,17,1,12,29,11,6,11,4,11,1,17,29,11,7,10,28,11,31,17,17,10,29,10,23,11,35,11,3,17,46,12,33,11,24,11,5,16,1,20,56,4,11,33,10,29,11,28,11,32,17,28,18,1,56,5,11,29,11,15,46,17,57,14,30,17,16,17,17,11,11,11,10,11,23,52,17,28,18,2,56,15,2,9,1,4,0,60,123,11,0,17,21,17,17,12,19,56,6,12,22,10,9,46,17,57,17,13,12,23,10,5,10,22,17,40,12,17,11,6,10,23,12,10,46,11,10,17,43,12,18,10,5,10,17,11,19,17,39,12,20,14,20,56,12,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,20,56,13,12,21,10,5,10,21,17,41,10,8,77,38,4,58,5,74,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,1,39,10,5,11,1,11,2,11,3,11,18,11,17,10,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,32,11,5,11,21,7,5,10,8,77,17,42,1,12,24,11,7,11,23,11,24,52,10,22,10,9,56,14,11,4,17,1,11,9,46,17,57,14,22,17,16,11,8,17,23,18,3,56,11,2,10,1,4,0,61,186,1,11,0,17,21,10,11,10,10,17,15,12,30,10,11,11,9,17,15,12,29,10,15,46,17,57,17,13,12,33,10,7,10,29,17,40,12,24,11,8,11,33,12,16,46,11,16,17,43,12,25,10,7,10,24,10,11,17,39,12,26,14,26,56,12,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,26,56,13,12,27,10,7,10,27,17,41,10,12,77,38,4,64,5,82,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,10,7,10,1,11,2,10,3,11,25,11,24,10,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,32,11,13,10,14,10,15,56,1,12,23,10,6,46,17,58,12,35,11,14,10,35,38,4,118,5,134,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,23,11,35,10,15,56,2,12,34,14,23,56,3,12,31,10,5,17,1,12,28,11,6,11,4,11,1,17,29,11,7,10,27,11,30,17,17,10,28,10,12,77,11,34,11,3,17,46,12,32,11,23,11,5,16,1,20,56,4,11,32,10,28,11,27,11,31,17,28,18,1,56,5,11,28,11,15,46,17,57,14,29,17,16,17,17,11,11,11,10,11,12,17,23,18,2,56,15,2,11,1,4,0,62,117,11,0,17,21,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,57,17,13,12,27,56,6,12,24,11,8,11,9,10,10,56,7,12,26,10,7,14,26,56,8,12,15,46,11,15,56,9,12,25,11,4,17,1,12,23,11,7,11,26,7,5,64,29,0,0,0,0,0,0,0,0,10,10,56,10,1,10,6,10,24,7,5,10,25,77,17,38,1,12,20,10,5,10,27,12,16,46,11,16,17,44,32,4,74,10,5,10,27,17,45,10,6,10,24,17,40,12,21,11,5,11,27,12,17,46,11,17,17,43,12,22,11,6,11,1,11,2,11,3,11,22,11,21,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,34,11,23,11,10,46,17,57,14,24,17,16,11,25,17,26,18,3,56,11,2,12,1,4,0,63,93,10,0,17,21,10,13,46,17,57,12,27,10,27,17,13,12,25,56,6,12,23,11,10,10,11,17,15,12,29,10,6,11,23,17,40,12,22,10,6,11,29,17,40,12,28,10,4,17,1,12,26,10,9,6,0,0,0,0,0,0,0,0,36,4,43,11,0,10,1,10,2,10,3,11,4,10,5,10,6,11,7,11,8,10,9,11,13,56,16,5,54,11,4,1,11,0,1,11,7,1,11,8,10,9,11,13,56,7,56,17,11,5,11,25,12,15,46,11,15,17,43,12,24,11,6,11,1,11,2,11,3,11,24,11,12,11,28,11,22,12,14,12,21,12,20,12,19,12,18,12,17,12,16,46,11,16,11,17,11,18,11,19,11,20,11,21,11,14,17,33,11,26,11,27,11,11,11,9,17,25,18,3,56,11,2,0,2,0,1,0],"merge_coins":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,10,3,20,53,4,73,14,5,87,102,7,189,1,132,1,8,193,2,96,6,161,3,30,12,191,3,189,1,0,6,1,14,2,2,2,11,2,12,2,0,12,1,0,1,4,1,2,0,0,5,0,1,1,0,1,3,5,6,1,0,1,8,3,4,1,0,2,4,8,4,1,0,2,10,11,1,1,0,2,13,9,10,1,0,2,15,15,1,1,0,3,7,14,4,1,12,4,9,12,13,0,2,1,1,1,3,7,5,7,4,7,7,1,6,7,3,10,11,0,1,9,0,3,7,8,1,1,11,0,1,9,0,6,11,0,1,9,0,11,0,1,9,0,11,0,1,9,0,3,11,0,1,9,0,3,1,7,10,9,0,0,1,6,10,9,0,1,1,1,9,0,2,7,11,0,1,9,0,11,0,1,9,0,1,6,11,0,1,9,0,1,3,3,7,11,0,1,9,0,3,7,8,1,1,6,8,1,1,5,2,9,0,5,1,7,8,1,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,8,105,115,95,101,109,112,116,121,4,106,111,105,110,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,7,114,101,118,101,114,115,101,6,115,101,110,100,101,114,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,118,101,99,116,111,114,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,255,255,255,255,255,255,255,255,0,1,0,0,2,83,14,0,65,1,6,0,0,0,0,0,0,0,0,36,4,67,13,0,56,0,13,0,69,1,12,5,14,0,56,1,32,4,20,5,15,13,5,13,0,69,1,56,2,5,10,11,0,70,1,0,0,0,0,0,0,0,0,14,5,56,3,12,8,10,1,12,6,11,1,7,2,33,4,33,10,8,12,6,11,8,10,6,38,4,38,5,42,11,2,1,7,0,39,14,5,56,3,10,6,36,4,60,13,5,11,6,10,2,56,4,12,7,11,5,11,2,46,17,8,56,5,11,7,12,3,5,64,11,2,1,11,5,12,3,11,3,12,4,5,81,11,0,70,1,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,33,4,74,5,78,11,2,1,7,1,39,11,2,56,6,12,4,11,4,2,0],"oracle":[161,28,235,11,6,0,0,0,11,1,0,36,2,36,84,3,120,157,1,4,149,2,22,5,171,2,231,2,7,146,5,231,6,8,249,11,128,1,6,249,12,70,10,191,13,33,12,224,13,232,5,13,200,19,14,0,47,0,31,2,40,2,41,2,49,2,52,2,54,2,56,2,61,1,23,1,24,1,46,1,62,1,63,1,65,1,66,3,61,3,68,0,10,8,0,0,6,4,0,1,2,0,0,1,3,8,0,2,4,0,1,3,0,3,5,7,0,4,6,7,0,5,7,7,0,6,8,7,0,6,9,12,0,8,12,12,0,9,0,8,0,10,1,12,1,0,1,11,15,4,0,12,11,2,0,13,13,12,2,7,1,4,1,15,14,2,0,16,12,12,0,17,16,0,0,0,43,0,1,0,0,39,2,3,0,0,59,4,1,0,0,58,4,1,0,0,57,5,1,0,0,20,6,1,0,0,21,6,1,0,0,29,7,1,0,1,22,27,1,0,2,28,40,1,1,3,3,33,43,23,0,3,34,43,23,0,4,32,41,42,0,4,35,41,42,0,5,30,19,20,0,6,36,30,20,0,6,37,28,29,0,7,26,33,34,0,7,38,38,39,0,7,67,35,34,0,9,64,22,23,0,11,45,0,8,0,13,17,21,1,2,7,4,13,18,15,17,2,7,4,13,19,36,37,2,7,4,13,25,15,16,2,7,4,13,45,0,10,2,7,4,14,60,13,1,1,8,17,48,31,32,0,26,9,26,11,27,12,25,11,23,11,25,9,22,9,22,11,23,9,24,11,9,29,1,7,8,16,0,2,7,8,0,13,3,15,2,3,3,6,8,2,7,8,0,3,7,6,8,2,7,8,0,10,2,13,15,2,6,8,11,3,7,8,0,10,13,6,8,11,9,6,8,3,7,8,17,7,8,10,7,8,9,7,8,0,13,10,2,6,8,11,11,12,1,8,14,1,8,13,2,13,8,7,1,11,15,2,9,0,9,1,2,13,8,1,1,8,0,1,9,0,4,13,13,6,8,1,7,11,15,2,13,8,1,2,6,11,15,2,9,0,9,1,9,0,1,1,1,6,9,1,5,13,13,8,7,7,11,15,2,13,8,7,7,11,15,2,13,8,1,1,10,2,1,8,7,3,7,11,15,2,9,0,9,1,9,0,9,1,1,6,8,11,1,3,6,13,3,6,13,3,6,8,1,7,11,15,2,13,8,1,1,13,23,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,6,8,11,13,10,2,6,8,11,10,8,18,6,8,11,3,8,5,3,11,4,1,8,8,7,8,1,6,8,7,8,8,11,4,1,8,8,8,5,3,8,6,8,7,8,18,1,6,8,3,1,6,8,9,1,8,8,1,6,8,8,3,6,8,17,10,2,6,8,11,1,8,18,3,6,8,10,10,8,18,6,8,11,1,11,4,1,8,8,5,6,8,10,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,2,7,11,15,2,9,0,9,1,9,0,1,7,9,1,3,6,8,9,6,8,11,3,1,8,6,1,11,4,1,9,0,1,6,8,6,1,8,5,1,6,8,5,5,67,108,111,99,107,4,67,111,105,110,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,15,72,111,116,80,111,116,97,116,111,86,101,99,116,111,114,3,73,54,52,5,80,114,105,99,101,15,80,114,105,99,101,73,100,101,110,116,105,102,105,101,114,9,80,114,105,99,101,73,110,102,111,15,80,114,105,99,101,73,110,102,111,79,98,106,101,99,116,11,80,114,105,99,101,79,114,97,99,108,101,3,83,85,73,5,83,116,97,116,101,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,86,65,65,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,17,99,104,101,99,107,95,103,117,97,114,100,95,112,114,105,99,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,29,99,114,101,97,116,101,95,112,114,105,99,101,95,105,110,102,111,115,95,104,111,116,95,112,111,116,97,116,111,7,100,101,99,105,109,97,108,7,100,101,115,116,114,111,121,24,102,101,101,100,95,116,111,107,101,110,95,112,114,105,99,101,95,98,121,95,112,121,116,104,13,102,114,111,109,95,98,121,116,101,95,118,101,99,7,103,101,110,101,115,105,115,8,103,101,116,95,101,120,112,111,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,110,101,103,97,116,105,118,101,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,112,111,115,105,116,105,118,101,9,103,101,116,95,112,114,105,99,101,20,103,101,116,95,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,37,103,101,116,95,112,114,105,99,101,95,105,110,102,111,95,102,114,111,109,95,112,114,105,99,101,95,105,110,102,111,95,111,98,106,101,99,116,23,103,101,116,95,112,114,105,99,101,95,110,111,95,111,108,100,101,114,95,116,104,97,110,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,17,104,111,116,95,112,111,116,97,116,111,95,118,101,99,116,111,114,3,105,54,52,2,105,100,4,105,110,105,116,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,3,110,101,119,6,111,98,106,101,99,116,6,111,114,97,99,108,101,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,5,112,114,105,99,101,16,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,16,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,16,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,17,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,115,10,112,114,105,99,101,95,105,110,102,111,13,112,114,105,99,101,95,111,114,97,99,108,101,115,4,112,121,116,104,20,114,101,103,105,115,116,101,114,95,116,111,107,101,110,95,112,114,105,99,101,20,115,101,116,95,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,20,115,101,116,95,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,116,97,116,101,3,115,117,105,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,24,117,112,100,97,116,101,95,115,105,110,103,108,101,95,112,114,105,99,101,95,102,101,101,100,3,118,97,97,5,118,97,108,117,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,181,59,15,65,116,16,134,39,251,238,114,226,73,139,88,214,162,113,76,222,213,63,172,83,112,52,194,32,210,99,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,60,0,0,0,0,0,0,0,3,8,16,14,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,5,42,8,13,51,3,50,3,53,11,15,2,13,8,7,55,11,15,2,13,8,1,1,2,3,69,15,27,2,44,3,0,0,0,0,1,11,10,0,17,21,7,1,7,0,10,0,56,0,11,0,56,1,18,0,56,2,2,1,1,0,0,14,32,11,0,15,0,12,5,10,5,10,1,12,2,46,11,2,56,3,4,11,5,15,11,5,1,7,2,39,11,5,11,1,12,3,46,11,3,56,4,12,4,10,4,16,1,20,10,4,16,2,20,11,4,16,3,20,2,2,1,0,0,1,5,11,2,11,1,15,4,21,2,3,1,0,0,1,5,11,2,11,1,15,5,21,2,4,1,0,0,18,58,10,1,15,0,12,11,10,11,10,3,12,7,46,11,7,56,3,32,4,12,5,20,11,11,1,11,1,1,11,6,1,7,3,39,11,2,17,14,12,9,11,1,15,6,12,10,10,10,10,3,12,8,46,11,8,56,5,32,4,35,5,43,11,11,1,11,10,1,11,6,1,7,3,39,11,10,10,3,11,9,56,6,11,11,11,3,11,4,11,5,11,6,17,20,6,232,3,0,0,0,0,0,0,26,18,1,56,7,2,5,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,5,20,35,4,39,5,45,11,8,1,11,0,1,7,4,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,6,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,4,20,35,4,39,5,45,11,8,1,11,0,1,7,5,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,7,1,0,0,26,136,1,11,0,17,8,10,4,16,6,10,5,56,5,4,8,5,20,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,2,39,10,4,15,6,10,5,12,14,46,11,14,56,8,12,24,10,3,46,17,16,12,25,14,25,17,15,12,30,11,24,14,30,33,4,40,5,52,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,6,39,11,1,11,6,10,7,12,16,12,15,46,11,15,11,16,17,28,12,31,10,2,11,31,64,32,1,0,0,0,0,0,0,0,10,7,12,18,12,17,46,11,17,11,18,17,17,12,26,11,2,11,26,10,3,11,8,10,7,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,17,19,12,22,10,7,17,20,6,232,3,0,0,0,0,0,0,26,12,19,11,4,15,0,11,5,56,9,12,23,11,3,11,7,12,13,46,11,13,7,0,17,18,12,29,11,22,56,10,14,29,17,13,12,27,14,27,17,11,12,28,14,29,17,12,12,20,14,20,17,10,12,21,11,28,77,10,23,15,1,21,11,21,51,10,23,15,2,21,11,19,11,23,15,3,21,2,0,4,1,0,1,1,1,2,0,1,0,2,0,3,0],"pool_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,136,1,4,146,1,2,5,148,1,208,1,7,228,2,205,4,8,177,7,32,6,209,7,41,12,250,7,133,12,0,23,0,10,0,24,1,0,7,0,0,18,0,1,0,0,22,0,1,0,0,21,0,1,0,0,19,0,1,0,0,20,0,1,0,0,16,0,1,0,0,17,0,1,0,0,11,2,3,0,0,1,3,4,0,0,15,5,3,0,0,5,3,6,0,0,14,7,3,0,0,4,3,8,0,0,13,9,3,0,0,3,3,9,0,1,2,3,12,0,1,12,12,3,0,2,6,19,20,0,2,7,19,27,0,2,8,19,21,0,2,9,19,1,0,2,25,11,0,0,2,26,25,0,0,2,27,14,0,0,2,28,15,0,0,2,29,13,0,0,2,30,17,18,1,1,26,1,0,1,2,5,8,0,8,0,3,13,10,2,1,10,2,6,8,0,8,0,3,13,2,10,2,5,13,3,8,0,8,0,3,6,13,3,8,0,8,0,3,2,3,8,0,13,10,2,4,8,0,13,2,10,2,3,13,15,2,3,10,2,10,2,10,2,2,7,10,2,13,1,8,0,2,7,10,2,10,2,2,7,10,2,3,2,7,10,2,2,18,10,2,10,2,10,2,10,2,10,2,10,2,3,13,10,2,13,3,3,3,8,0,2,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,17,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,3,3,8,0,2,13,13,8,0,13,2,10,2,10,2,13,10,2,10,2,10,2,10,2,13,10,2,13,3,3,3,2,8,0,13,2,7,10,2,15,9,10,2,10,2,10,2,3,13,15,3,3,2,1,15,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,100,101,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,21,103,101,116,95,100,101,108,101,116,101,95,111,119,110,101,114,95,116,121,112,101,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,16,103,101,116,95,100,101,112,111,115,105,116,95,116,121,112,101,23,103,101,116,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,21,103,101,116,95,115,101,110,100,95,109,101,115,115,97,103,101,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,10,112,111,111,108,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,10,48,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,3,17,21,11,0,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,1,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,2,17,23,13,6,7,2,17,24,14,4,65,1,6,0,0,0,0,0,0,0,0,36,4,46,13,6,14,4,65,1,75,17,21,13,6,11,4,17,25,11,6,2,8,1,0,0,16,172,1,14,0,65,1,12,13,6,0,0,0,0,0,0,0,0,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,1,14,1,17,17,12,8,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,2,14,2,17,17,12,16,11,12,11,11,22,12,12,11,16,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,14,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,3,14,3,17,17,12,18,11,12,11,11,22,12,12,11,18,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,17,11,12,11,11,22,12,12,6,8,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,4,14,4,17,19,12,7,11,12,11,11,22,12,12,6,1,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,5,14,5,17,20,12,15,11,12,11,11,22,12,12,64,1,0,0,0,0,0,0,0,0,12,9,10,13,10,12,36,4,151,1,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,6,14,6,17,17,12,10,11,12,11,11,22,12,12,11,10,52,12,11,14,0,10,12,10,12,10,11,22,56,0,12,9,11,12,11,11,22,12,12,10,15,7,2,33,4,156,1,5,158,1,7,1,39,11,13,11,12,33,4,163,1,5,165,1,7,0,39,11,14,11,17,11,7,11,8,11,15,11,9,2,9,1,0,0,10,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,21,13,6,11,1,17,23,11,2,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,3,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,4,17,23,13,6,7,3,17,24,11,6,2,10,1,0,0,22,152,1,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,15,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,19,12,11,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,17,11,9,11,8,22,12,9,11,17,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,19,12,7,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,20,12,13,11,9,11,8,22,12,9,10,13,7,3,33,4,136,1,5,138,1,7,1,39,11,10,11,9,33,4,143,1,5,145,1,7,0,39,11,15,11,11,11,12,11,16,11,7,11,13,2,11,1,0,0,23,34,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,1,17,21,11,0,17,16,12,4,13,3,14,4,65,1,75,17,21,13,3,11,4,17,25,13,3,7,4,17,24,14,2,65,1,6,0,0,0,0,0,0,0,0,36,4,32,13,3,14,2,65,1,75,17,21,13,3,11,2,17,25,11,3,2,12,1,0,0,24,123,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,5,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,20,12,11,11,9,11,8,22,12,9,64,1,0,0,0,0,0,0,0,0,12,6,10,10,10,9,36,4,104,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,7,11,9,11,8,22,12,9,11,7,52,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,11,9,11,8,22,12,9,10,11,7,4,33,4,109,5,111,7,1,39,11,10,11,9,33,4,116,5,118,7,0,39,11,12,11,5,11,11,11,6,2,13,1,0,0,3,13,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,0,17,21,13,3,11,1,17,22,13,3,11,2,17,24,11,3,2,14,1,0,0,26,64,14,0,65,1,12,8,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,1,14,1,17,17,12,5,11,7,11,4,22,12,7,6,32,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,2,14,2,17,18,12,6,11,7,11,4,22,12,7,6,1,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,3,14,3,17,20,12,9,11,7,11,4,22,12,7,11,8,11,7,33,4,58,5,60,7,0,39,11,5,11,6,11,9,2,0],"pool_manager":[161,28,235,11,6,0,0,0,12,1,0,22,2,22,66,3,88,199,1,4,159,2,62,5,221,2,206,2,7,171,5,144,8,8,187,13,96,6,155,14,138,1,10,165,15,108,12,145,16,154,13,13,171,29,32,15,203,29,4,0,62,0,28,0,30,0,36,1,21,1,58,2,32,2,57,2,74,2,76,2,77,0,9,12,0,0,1,4,0,0,7,4,0,0,4,4,0,0,8,4,0,0,6,4,0,0,0,3,0,0,10,3,0,1,2,7,0,3,3,0,0,4,11,7,0,5,5,7,1,0,0,7,14,4,0,8,12,12,2,7,1,4,1,10,13,2,0,0,51,0,1,0,0,66,2,1,0,0,65,3,1,0,0,71,4,1,0,0,69,5,1,0,0,70,4,1,0,0,47,6,7,0,0,41,8,9,0,0,44,6,10,0,0,37,11,12,0,0,48,6,12,0,0,43,8,12,0,0,42,8,12,0,0,45,6,12,0,0,46,8,12,0,0,38,1,12,0,0,39,1,12,0,0,35,13,14,0,0,34,15,16,0,0,33,17,16,0,0,81,1,18,0,0,16,19,20,0,0,67,19,20,0,1,40,46,9,0,2,24,49,12,0,2,25,49,12,0,2,26,20,12,0,5,56,1,47,1,0,5,73,28,47,1,0,6,29,28,1,1,3,7,55,0,21,0,8,15,31,1,2,7,4,8,22,41,42,2,7,4,8,23,35,36,2,7,4,8,27,41,16,2,7,4,8,55,0,23,2,7,4,9,72,28,1,1,8,35,22,35,24,35,25,35,26,36,27,35,30,31,24,31,26,35,33,31,22,31,25,33,26,33,24,31,30,33,30,32,26,32,25,32,24,32,22,34,33,32,33,32,30,28,32,27,32,34,24,34,25,33,22,31,33,33,33,29,50,29,51,1,7,8,14,0,5,6,8,9,7,8,0,8,10,13,7,8,14,4,6,8,9,7,8,0,8,8,13,4,6,8,9,7,8,0,8,8,15,4,6,8,9,7,8,0,13,15,2,7,8,0,13,1,10,8,8,2,7,8,0,8,8,1,13,1,8,10,3,6,8,0,13,13,1,15,3,7,8,0,13,13,1,11,11,1,8,8,2,6,8,0,13,1,1,2,6,8,0,8,8,1,8,3,4,7,8,0,8,8,13,15,2,15,15,1,8,12,2,13,8,1,1,11,13,2,9,0,9,1,2,13,8,2,2,8,8,13,2,13,10,8,8,1,8,0,1,9,0,8,13,8,10,8,3,11,13,2,8,8,8,4,8,1,7,11,13,2,13,8,1,8,2,7,11,13,2,13,8,2,2,8,8,8,4,3,7,11,13,2,9,0,9,1,9,0,9,1,1,8,8,2,13,8,3,3,13,8,8,7,8,5,2,7,11,13,2,9,0,9,1,9,0,1,7,9,1,4,8,8,13,7,8,2,7,8,4,2,13,7,8,2,3,8,8,13,7,8,4,2,13,13,2,6,11,13,2,9,0,9,1,9,0,1,6,9,1,2,8,8,8,8,2,15,6,11,13,2,13,8,3,4,8,8,3,3,10,8,8,1,6,8,8,1,11,11,1,9,0,9,8,8,13,15,7,11,13,2,13,8,3,7,8,3,13,15,7,8,2,7,8,4,6,15,15,15,15,15,15,1,8,6,1,8,7,12,65,100,100,76,105,113,117,105,100,105,116,121,7,65,112,112,73,110,102,111,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,9,76,105,113,117,105,100,105,116,121,6,79,112,116,105,111,110,11,80,111,111,108,67,97,116,97,108,111,103,8,80,111,111,108,73,110,102,111,13,80,111,111,108,76,105,113,117,105,100,105,116,121,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,15,82,101,109,111,118,101,76,105,113,117,105,100,105,116,121,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,13,97,100,100,95,108,105,113,117,105,100,105,116,121,7,97,108,112,104,97,95,49,6,97,109,111,117,110,116,9,97,112,112,95,105,110,102,111,115,13,97,112,112,95,108,105,113,117,105,100,105,116,121,5,97,115,99,105,105,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,5,101,118,101,110,116,18,101,120,105,115,116,95,99,101,114,116,97,105,110,95,112,111,111,108,13,101,120,105,115,116,95,112,111,111,108,95,105,100,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,100,101,102,97,117,108,116,95,97,108,112,104,97,95,49,20,103,101,116,95,100,101,102,97,117,108,116,95,108,97,109,98,100,97,95,49,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,24,103,101,116,95,112,111,111,108,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,112,111,111,108,95,110,97,109,101,95,98,121,95,105,100,21,103,101,116,95,112,111,111,108,95,116,111,116,97,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,115,95,98,121,95,105,100,19,103,101,116,95,116,111,107,101,110,95,108,105,113,117,105,100,105,116,121,2,105,100,11,105,100,95,116,111,95,112,111,111,108,115,4,105,110,105,116,8,108,97,109,98,100,97,95,49,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,110,97,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,12,112,111,111,108,95,97,100,100,114,101,115,115,12,112,111,111,108,95,99,97,116,97,108,111,103,10,112,111,111,108,95,105,110,102,111,115,12,112,111,111,108,95,109,97,110,97,103,101,114,10,112,111,111,108,95,116,111,95,105,100,5,112,111,111,108,115,13,114,101,103,105,115,116,101,114,95,112,111,111,108,16,114,101,103,105,115,116,101,114,95,112,111,111,108,95,105,100,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,7,114,101,115,101,114,118,101,21,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,97,108,112,104,97,22,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,108,97,109,98,100,97,15,115,101,116,95,112,111,111,108,95,119,101,105,103,104,116,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,116,97,98,108,101,12,116,111,116,97,108,95,119,101,105,103,104,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,119,101,105,103,104,116,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,14,122,101,114,111,95,108,105,113,117,105,100,105,116,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,0,88,241,76,176,44,241,78,240,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,37,164,0,10,139,202,34,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,0,2,4,49,8,12,19,11,13,2,13,8,1,61,11,13,2,13,8,2,60,8,5,1,2,1,20,11,13,2,13,8,3,2,2,5,54,8,10,68,8,3,17,15,75,15,64,11,13,2,8,8,8,4,3,2,1,78,15,4,2,4,78,15,52,15,30,15,79,15,5,2,2,63,11,13,2,8,8,13,50,11,13,2,13,10,8,8,6,2,3,59,8,8,18,15,31,15,7,2,3,59,8,8,18,15,30,15,0,0,0,0,1,14,10,0,17,30,10,0,56,0,10,0,56,1,10,0,56,2,11,0,56,3,18,5,18,0,56,4,2,1,1,0,0,29,54,10,1,10,3,12,5,46,11,5,17,18,32,4,9,5,15,11,1,1,11,4,1,7,2,39,10,1,15,0,12,12,11,2,12,6,17,20,12,7,10,4,56,5,12,8,11,6,11,7,7,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,8,18,2,12,11,11,12,10,3,11,11,56,6,10,1,15,1,15,2,10,3,64,32,0,0,0,0,0,0,0,0,56,7,11,1,15,3,12,10,11,4,56,8,18,1,12,9,11,10,11,3,11,9,56,9,2,2,1,0,0,34,52,10,1,10,3,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,10,1,10,2,12,5,46,11,5,17,19,32,4,21,5,25,11,1,1,7,4,39,10,1,15,1,12,6,10,6,15,4,10,2,10,3,56,10,11,6,15,2,10,3,56,11,10,2,68,32,11,1,15,0,11,3,56,12,15,5,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,4,56,13,2,3,1,0,0,37,43,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,12,6,10,6,15,5,11,2,56,14,12,7,10,6,16,6,20,10,7,16,7,20,23,10,3,22,11,6,15,6,21,11,3,11,7,15,7,21,2,4,1,0,0,38,22,10,1,10,2,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,11,1,15,0,11,2,56,12,12,5,11,3,11,5,15,8,21,2,5,1,0,0,39,29,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,15,5,11,2,56,14,12,6,11,3,11,6,15,9,21,2,6,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,1,15,2,11,1,12,3,46,11,3,56,15,20,2,7,1,0,0,43,22,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,11,0,15,1,15,4,11,1,12,3,46,11,3,56,16,20,2,8,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,0,11,1,12,3,46,11,3,56,17,16,10,20,2,9,1,0,0,44,32,10,0,10,1,17,18,4,5,5,9,11,0,1,7,3,39,11,0,16,3,11,1,56,18,16,11,12,4,10,4,10,2,56,19,4,26,11,4,11,2,56,20,16,12,20,12,3,5,30,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,10,1,0,0,9,20,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,13,16,12,20,2,11,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,14,20,2,12,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,15,20,2,13,1,0,0,9,19,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,6,20,2,14,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,7,20,2,15,1,0,0,1,2,7,0,2,16,1,0,0,1,2,7,1,2,17,1,0,0,45,34,11,0,11,1,17,6,12,6,14,6,65,32,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,32,5,14,14,6,10,4,66,32,20,12,3,14,3,17,23,10,2,33,4,27,11,3,56,22,2,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,9,56,23,2,18,1,0,0,1,5,11,0,16,0,11,1,56,24,2,19,1,0,0,1,6,11,0,16,1,16,4,11,1,56,25,2,20,1,0,0,1,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,2,21,3,0,0,48,119,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,12,16,15,20,10,12,16,9,20,17,25,12,10,10,3,10,10,22,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,32,4,73,11,7,11,2,10,6,18,3,56,27,5,85,11,7,11,2,56,28,12,8,10,8,16,12,20,10,6,22,11,8,15,12,21,10,11,16,13,16,12,20,10,3,22,11,11,15,13,15,12,21,10,12,16,14,20,10,3,22,10,12,15,14,21,10,12,16,15,20,10,10,23,11,12,15,15,21,11,1,11,3,10,10,18,6,56,29,11,6,11,10,2,22,3,0,0,48,151,1,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,12,16,14,20,10,3,38,4,33,5,41,11,0,1,11,12,1,11,11,1,7,8,39,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,11,16,8,20,10,12,16,9,20,17,24,12,10,10,3,10,10,23,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,4,82,5,90,11,12,1,11,11,1,11,7,1,7,6,39,11,7,11,2,56,28,12,8,10,8,16,12,20,10,3,38,4,101,5,109,11,12,1,11,11,1,11,8,1,7,7,39,10,8,16,12,20,10,3,23,11,8,15,12,21,10,11,16,13,16,12,20,10,6,23,11,11,15,13,15,12,21,10,12,16,14,20,10,6,23,10,12,15,14,21,10,12,16,15,20,10,10,22,11,12,15,15,21,11,1,11,3,10,10,18,7,56,30,11,6,11,10,2,0,2,0,3,5,1,0,1,5,0,2,4,2,3,4,3,2,2,4,1,2,0,1,0,3,0,2,1,4,0,4,2,0,53,0,80,0],"rates":[161,28,235,11,6,0,0,0,8,1,0,6,2,6,4,3,10,70,5,80,48,7,128,1,185,2,8,185,3,32,6,217,3,68,12,157,4,128,5,0,13,0,11,0,16,1,0,8,0,0,6,0,1,0,0,2,0,1,0,0,5,2,1,0,0,1,3,1,0,0,3,4,1,0,0,4,4,1,0,1,7,6,1,0,1,8,6,3,0,1,9,6,1,0,1,10,6,1,0,2,12,7,1,0,2,14,5,1,0,2,15,7,1,0,2,17,7,1,0,3,7,8,0,13,15,1,15,4,7,8,0,13,15,15,4,15,15,15,15,3,15,15,15,0,2,7,8,0,13,2,15,15,6,15,15,15,15,15,15,7,15,15,15,15,15,15,15,7,83,116,111,114,97,103,101,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,21,99,97,108,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,3,109,105,110,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,128,81,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,3,29,10,0,10,1,17,8,12,6,11,0,11,1,17,6,12,4,11,6,11,4,17,13,12,5,10,5,10,2,22,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,27,10,5,11,5,11,2,22,17,12,12,3,11,3,2,1,1,0,0,8,39,10,0,10,1,11,2,17,0,12,8,11,0,11,1,17,7,12,7,12,6,12,5,12,4,10,8,10,7,35,4,23,11,4,11,8,11,5,17,13,22,12,3,5,37,11,4,11,5,22,11,6,11,8,10,7,23,17,11,11,7,23,17,12,17,13,22,12,3,11,3,2,2,1,0,0,7,17,10,0,10,1,11,3,17,0,12,5,11,0,11,1,17,9,12,4,11,2,11,5,17,11,11,4,23,17,13,17,13,2,3,1,0,0,7,20,11,0,11,1,23,7,1,17,10,12,4,7,1,10,4,23,12,5,11,2,11,5,24,11,3,11,4,24,22,7,1,26,2,4,1,0,0,9,69,11,0,11,1,23,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,10,17,11,2,10,5,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,6,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,23,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,7,5,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,2,10,2,17,13,7,0,7,0,24,26,12,4,10,4,10,2,17,13,7,0,26,12,3,10,5,10,6,24,11,4,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,10,5,11,6,24,11,7,24,11,3,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,9,17,11,11,2,11,5,24,7,0,26,22,11,8,22,11,9,22,2,5,1,0,0,1,12,11,2,11,0,11,1,23,24,7,0,26,12,3,17,11,11,3,22,2,0],"ray_math":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,40,5,42,13,7,55,59,8,114,32,6,146,1,146,1,12,164,2,247,5,0,7,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,4,2,1,0,0,1,2,1,0,0,2,2,1,0,0,6,1,1,0,0,0,1,3,0,0,1,15,2,15,15,1,2,4,15,2,15,15,4,108,111,103,50,3,109,97,120,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,208,121,0,161,63,121,92,118,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,249,214,165,42,128,81,101,243,159,91,61,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,1,0,0,0,2,7,0,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,10,11,0,11,1,24,7,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,7,0,26,2,3,1,0,0,0,10,11,0,7,0,24,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,11,1,26,2,4,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,6,1,0,0,4,59,10,0,7,0,38,4,5,5,7,7,4,39,10,0,7,0,26,17,7,12,2,10,2,77,7,0,24,12,3,11,0,11,2,48,12,4,10,4,7,0,33,4,27,11,3,2,7,1,12,1,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,57,5,34,10,4,11,4,24,7,0,26,12,4,10,4,7,2,38,4,52,11,3,10,1,22,12,3,11,4,49,1,48,12,4,11,1,49,1,48,12,1,5,29,11,3,2,7,1,0,0,3,112,49,0,12,1,10,0,49,128,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,16,11,0,49,128,48,12,0,11,1,49,128,22,12,1,10,0,49,64,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,30,11,0,49,64,48,12,0,11,1,49,64,22,12,1,10,0,49,32,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,44,11,0,49,32,48,12,0,11,1,49,32,22,12,1,10,0,49,16,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,58,11,0,49,16,48,12,0,11,1,49,16,22,12,1,10,0,49,8,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,72,11,0,49,8,48,12,0,11,1,49,8,22,12,1,10,0,49,4,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,0,49,4,48,12,0,11,1,49,4,22,12,1,10,0,49,2,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,100,11,0,49,2,48,12,0,11,1,49,2,22,12,1,11,0,49,1,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,110,11,1,49,1,22,12,1,11,1,2,0],"scaled_balance":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,25,5,29,6,7,35,75,8,110,32,12,142,1,39,0,6,0,4,0,0,0,1,0,0,2,0,1,0,0,1,0,1,0,1,3,0,1,0,1,5,0,1,0,2,15,15,1,15,0,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,2,4,11,0,11,1,17,4,2,1,1,0,0,2,4,11,0,11,1,17,3,2,2,1,0,0,2,4,11,0,11,1,17,3,2,0],"serde":[161,28,235,11,6,0,0,0,9,1,0,12,2,12,8,3,20,167,1,4,187,1,12,5,199,1,148,1,7,219,2,211,4,8,174,7,96,6,142,8,20,12,162,8,157,35,0,23,1,4,1,6,1,36,1,37,2,2,1,0,7,0,3,1,7,0,0,32,0,1,0,0,28,2,1,0,0,31,3,1,0,0,26,4,1,0,0,29,5,1,0,0,19,6,6,0,0,5,6,6,0,0,27,4,1,0,0,30,5,1,0,0,33,7,1,0,0,24,8,1,0,0,25,9,1,1,0,0,34,7,1,0,0,14,10,6,0,0,10,10,11,0,0,13,10,12,0,0,8,10,13,0,0,11,10,14,0,0,9,10,13,0,0,12,10,14,0,0,7,10,15,0,0,18,10,12,0,0,15,10,16,0,0,38,17,18,1,1,0,39,19,20,1,3,1,20,28,16,0,2,35,27,16,1,0,3,17,1,30,1,0,3,21,30,28,0,4,3,25,1,1,0,4,22,24,1,1,0,5,16,16,15,0,30,6,29,6,26,15,27,29,23,6,23,29,2,7,10,2,2,0,2,7,10,2,13,2,7,10,2,3,2,7,10,2,4,2,7,10,2,15,1,2,2,7,10,2,10,2,2,7,10,2,5,1,7,10,2,1,6,10,2,1,13,1,3,1,4,1,15,1,5,1,10,2,3,6,10,9,0,3,3,1,10,9,0,2,6,10,9,0,9,0,1,10,10,9,0,2,1,2,3,1,1,2,2,4,10,2,1,7,10,9,0,2,7,10,9,0,10,9,0,2,15,10,2,1,6,9,0,1,8,0,1,9,0,1,8,1,2,4,3,2,15,3,3,10,2,3,3,3,1,3,10,9,0,3,3,10,10,9,0,3,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,6,97,112,112,101,110,100,5,97,115,99,105,105,16,97,115,99,105,105,95,116,111,95,104,101,120,95,115,116,114,3,98,99,115,19,100,101,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,16,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,29,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,29,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,30,100,101,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,17,103,101,116,95,118,101,99,116,111,114,95,108,101,110,103,116,104,16,104,101,120,95,115,116,114,95,116,111,95,97,115,99,105,105,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,7,114,101,118,101,114,115,101,5,115,101,114,100,101,17,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,14,115,101,114,105,97,108,105,122,101,95,116,121,112,101,14,115,101,114,105,97,108,105,122,101,95,117,49,50,56,27,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,27,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,28,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,6,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,12,118,101,99,116,111,114,95,115,112,108,105,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,68,6,2,1,1,0,0,1,15,10,0,10,1,49,8,48,72,255,0,28,51,17,0,11,0,11,1,72,255,0,28,51,17,0,2,2,1,0,0,1,63,10,0,10,1,49,56,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,6,255,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,6,255,0,0,0,0,0,0,0,28,51,17,0,2,3,1,0,0,1,127,10,0,10,1,49,120,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,4,1,0,0,1,255,1,10,0,10,1,49,248,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,240,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,232,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,224,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,216,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,208,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,200,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,192,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,184,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,176,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,168,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,160,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,152,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,144,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,136,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,128,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,120,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,5,1,0,0,21,31,10,0,49,0,38,4,9,10,0,49,9,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,22,12,2,5,29,10,0,49,15,37,4,23,5,25,7,1,39,11,0,49,87,22,12,2,11,2,2,6,1,0,0,22,40,10,0,49,48,38,4,9,10,0,49,57,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,3,5,38,10,0,49,97,38,4,27,10,0,49,102,37,12,2,5,29,9,12,2,11,2,4,32,5,34,7,1,39,11,0,49,87,23,12,3,11,3,2,7,1,0,0,23,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,8,1,0,0,26,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,9,1,0,0,1,4,11,0,11,1,56,1,2,10,1,0,0,16,17,14,1,56,2,12,2,14,2,65,6,6,32,0,0,0,0,0,0,0,33,4,9,5,13,11,0,1,7,0,39,11,0,11,2,56,1,2,11,1,0,0,28,8,56,3,17,28,12,1,11,0,11,1,17,25,17,9,2,12,1,0,0,12,17,14,1,65,6,12,2,10,2,6,0,0,0,0,0,0,0,0,33,4,10,11,0,1,2,10,0,11,2,17,2,11,0,11,1,17,9,2,13,1,0,0,1,15,10,0,65,6,6,1,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,6,0,0,0,0,0,0,0,0,66,6,20,2,14,1,0,0,1,24,10,0,65,6,6,2,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,75,49,8,47,11,0,6,1,0,0,0,0,0,0,0,66,6,20,75,22,2,15,1,0,0,1,72,10,0,65,6,6,8,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,52,49,56,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,52,49,48,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,52,49,40,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,52,49,32,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,52,49,24,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,52,49,16,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,52,49,8,47,22,11,0,6,7,0,0,0,0,0,0,0,66,6,20,52,22,2,16,1,0,0,1,136,1,10,0,65,6,6,16,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,53,49,120,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,53,49,112,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,53,49,104,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,53,49,96,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,53,49,88,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,53,49,80,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,53,49,72,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,53,49,64,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,53,49,56,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,53,49,48,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,53,49,40,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,53,49,32,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,53,49,24,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,53,49,16,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,53,49,8,47,22,11,0,6,15,0,0,0,0,0,0,0,66,6,20,53,22,2,17,1,0,0,1,136,2,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,77,49,248,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,77,49,240,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,77,49,232,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,77,49,224,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,77,49,216,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,77,49,208,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,77,49,200,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,77,49,192,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,77,49,184,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,77,49,176,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,77,49,168,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,77,49,160,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,77,49,152,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,77,49,144,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,77,49,136,47,22,10,0,6,15,0,0,0,0,0,0,0,66,6,20,77,49,128,47,22,10,0,6,16,0,0,0,0,0,0,0,66,6,20,77,49,120,47,22,10,0,6,17,0,0,0,0,0,0,0,66,6,20,77,49,112,47,22,10,0,6,18,0,0,0,0,0,0,0,66,6,20,77,49,104,47,22,10,0,6,19,0,0,0,0,0,0,0,66,6,20,77,49,96,47,22,10,0,6,20,0,0,0,0,0,0,0,66,6,20,77,49,88,47,22,10,0,6,21,0,0,0,0,0,0,0,66,6,20,77,49,80,47,22,10,0,6,22,0,0,0,0,0,0,0,66,6,20,77,49,72,47,22,10,0,6,23,0,0,0,0,0,0,0,66,6,20,77,49,64,47,22,10,0,6,24,0,0,0,0,0,0,0,66,6,20,77,49,56,47,22,10,0,6,25,0,0,0,0,0,0,0,66,6,20,77,49,48,47,22,10,0,6,26,0,0,0,0,0,0,0,66,6,20,77,49,40,47,22,10,0,6,27,0,0,0,0,0,0,0,66,6,20,77,49,32,47,22,10,0,6,28,0,0,0,0,0,0,0,66,6,20,77,49,24,47,22,10,0,6,29,0,0,0,0,0,0,0,66,6,20,77,49,16,47,22,10,0,6,30,0,0,0,0,0,0,0,66,6,20,77,49,8,47,22,11,0,6,31,0,0,0,0,0,0,0,66,6,20,77,22,2,18,1,0,0,31,29,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,53,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,19,1,0,0,32,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,77,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,20,1,0,0,1,14,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,20,17,31,2,21,1,0,0,16,8,11,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,2,22,1,0,0,33,46,10,0,65,6,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,64,6,0,0,0,0,0,0,0,0,2,10,3,6,8,0,0,0,0,0,0,0,36,4,16,5,20,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,12,2,11,3,10,2,6,8,0,0,0,0,0,0,0,22,33,4,35,5,39,11,0,1,7,0,39,11,0,6,8,0,0,0,0,0,0,0,11,2,6,8,0,0,0,0,0,0,0,22,56,4,2,23,1,0,0,34,43,10,1,10,2,35,4,10,10,2,10,0,65,29,37,12,3,5,12,9,12,3,11,3,4,15,5,19,11,0,1,7,0,39,64,29,0,0,0,0,0,0,0,0,12,5,11,1,12,4,10,4,10,2,35,4,39,5,28,13,5,10,0,10,4,66,29,20,68,29,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,23,11,0,1,11,5,2,24,1,0,0,35,53,64,18,0,0,0,0,0,0,0,0,12,3,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,29,35,4,38,5,12,10,0,10,2,66,29,20,10,1,33,4,33,10,4,10,2,35,4,29,13,3,10,0,11,4,10,2,56,5,68,18,10,2,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,10,4,10,2,35,4,49,13,3,11,0,11,4,11,2,56,5,68,18,5,51,11,0,1,11,3,2,0],"system_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,71,4,81,2,5,83,78,7,161,1,150,2,8,183,3,32,6,215,3,26,12,241,3,169,2,0,16,0,6,0,11,1,0,7,0,0,9,0,1,0,0,10,0,1,0,0,7,2,3,0,0,1,3,2,0,1,2,3,7,0,1,8,7,3,0,2,3,13,14,0,2,4,13,15,0,2,5,13,1,0,2,12,5,0,0,2,13,6,0,0,2,14,9,0,0,2,15,8,0,0,2,17,11,12,1,1,13,1,0,1,2,4,13,3,8,0,2,1,10,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,12,10,2,10,2,10,2,10,2,8,0,13,3,3,3,3,13,2,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,11,68,111,108,97,65,100,100,114,101,115,115,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,19,101,110,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,115,121,115,116,101,109,95,99,111,100,101,99,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,4,24,64,1,0,0,0,0,0,0,0,0,12,5,13,5,11,0,17,9,13,5,11,1,17,10,11,2,17,5,12,4,13,5,14,4,65,1,75,17,9,13,5,11,4,17,12,13,5,11,3,17,11,11,5,2,3,1,0,0,10,96,14,0,65,1,12,9,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,1,14,1,17,6,12,11,11,8,11,7,22,12,8,6,8,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,2,14,2,17,7,12,10,11,8,11,7,22,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,3,14,3,17,6,12,6,11,8,11,7,22,12,8,11,6,52,12,7,14,0,10,8,10,8,10,7,22,56,0,17,4,12,5,11,8,11,7,22,12,8,6,1,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,4,14,4,17,8,12,12,11,8,11,7,22,12,8,11,9,11,8,33,4,89,5,91,7,0,39,11,11,11,10,11,5,11,12,2,0],"system_core_storage":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,24,3,36,26,4,62,2,5,64,35,7,99,252,1,8,223,2,64,10,159,3,9,12,168,3,34,13,202,3,2,15,204,3,2,0,16,0,7,0,8,1,13,1,18,1,19,0,2,8,0,1,0,12,0,1,3,12,0,2,1,0,0,3,5,4,0,5,4,2,0,0,11,0,1,0,0,9,2,3,0,1,14,0,6,0,3,12,4,5,0,4,15,8,1,1,8,4,7,3,6,8,3,7,8,2,7,8,5,0,1,6,8,0,1,6,8,1,1,7,8,5,1,8,4,1,8,1,1,8,0,1,9,0,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,7,83,116,111,114,97,103,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,3,110,101,119,6,111,98,106,101,99,116,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,10,8,4,6,8,1,0,1,0,0,1,9,10,2,17,3,11,0,11,1,11,2,17,2,18,0,56,0,2,1,3,0,0,1,3,11,0,16,0,2,0,1,0,17,0],"system_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,24,2,24,40,3,64,71,4,135,1,2,5,137,1,117,7,254,1,155,4,8,153,6,96,6,249,6,10,10,131,7,17,12,148,7,191,1,0,33,0,10,0,16,0,19,0,31,0,32,0,38,0,39,1,14,1,18,1,34,2,30,0,7,3,0,1,0,12,0,2,3,7,0,3,4,8,0,5,6,8,0,6,9,12,0,7,2,12,0,8,1,8,0,10,8,2,0,11,5,12,0,0,11,0,1,0,0,35,0,1,0,2,22,13,8,0,2,23,13,14,0,3,13,3,1,0,4,15,8,9,0,4,21,1,10,0,4,24,1,10,0,5,20,4,5,0,6,11,12,1,0,6,27,11,1,0,6,35,12,1,0,7,26,6,7,0,9,17,16,1,1,3,13,15,8,6,8,3,7,8,5,7,8,9,7,8,6,6,8,4,10,2,6,8,7,7,8,8,0,6,10,2,8,2,2,3,8,2,13,1,6,8,3,1,6,8,4,1,6,8,1,6,7,8,9,7,8,6,6,8,1,10,2,6,8,7,7,8,8,2,8,2,10,2,1,10,2,4,13,3,8,2,2,1,2,2,7,8,5,8,2,3,7,8,5,8,2,8,2,1,6,8,2,1,13,1,8,0,1,9,0,6,10,2,2,3,8,2,13,8,2,6,65,112,112,67,97,112,5,67,108,111,99,107,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,5,83,116,97,116,101,7,83,116,111,114,97,103,101,15,83,121,115,116,101,109,67,111,114,101,69,118,101,110,116,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,11,97,112,112,95,109,97,110,97,103,101,114,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,110,111,110,99,101,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,12,115,121,115,116,101,109,95,99,111,100,101,99,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,0,2,6,25,3,28,10,2,29,13,37,13,36,10,2,12,2,0,1,4,0,2,51,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,12,11,8,17,5,12,10,12,9,12,11,12,13,10,10,17,6,33,4,23,5,27,11,1,1,7,0,39,10,12,10,9,33,4,35,11,1,10,12,17,10,5,39,11,1,10,12,10,9,17,9,11,11,14,12,17,2,11,13,14,9,17,3,14,9,17,2,11,10,18,0,56,0,2,1,1,4,0,17,43,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,11,11,8,17,5,12,9,12,13,12,10,12,12,10,9,17,7,33,4,23,5,27,11,1,1,7,0,39,11,1,10,11,10,13,17,11,11,10,14,11,17,2,11,12,14,13,17,3,14,13,17,2,11,9,18,0,56,0,2,0],"system_portal":[161,28,235,11,6,0,0,0,10,1,0,18,2,18,28,3,46,82,4,128,1,4,5,132,1,84,7,216,1,208,3,8,168,5,64,10,232,5,22,12,254,5,187,1,13,185,7,2,0,30,0,13,0,16,0,29,0,37,1,15,1,25,1,31,1,32,0,3,8,0,0,2,3,0,1,0,7,0,2,1,8,0,4,6,12,0,6,5,4,0,8,4,2,0,0,21,0,1,0,0,18,2,3,0,0,8,4,1,0,0,34,4,1,0,1,11,11,12,0,1,12,13,12,0,2,10,9,1,0,3,17,1,16,0,3,19,1,16,0,4,7,15,1,0,4,26,14,1,0,4,33,15,1,0,5,14,7,1,1,3,6,22,0,5,0,7,28,7,1,1,8,8,27,10,11,0,14,6,12,17,1,7,8,6,0,1,7,8,0,1,3,6,6,8,3,7,8,0,7,8,4,13,10,2,7,8,6,1,8,5,1,8,0,1,9,0,3,8,2,5,8,2,1,6,8,3,1,6,8,6,1,5,1,8,2,2,13,10,2,2,7,8,4,8,2,3,7,8,4,8,2,8,2,1,2,1,8,1,3,5,8,2,8,2,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,83,121,115,116,101,109,76,111,99,97,108,69,118,101,110,116,12,83,121,115,116,101,109,80,111,114,116,97,108,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,7,98,105,110,100,105,110,103,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,2,105,100,4,105,110,105,116,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,6,111,98,106,101,99,116,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,115,121,115,116,101,109,95,99,111,100,101,99,13,115,121,115,116,101,109,95,112,111,114,116,97,108,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,117,110,98,105,110,100,105,110,103,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,20,8,5,23,3,1,2,5,24,3,27,5,36,13,35,10,2,9,2,0,0,0,0,1,6,11,0,17,13,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,4,0,8,34,11,0,17,6,11,5,46,17,15,12,7,10,7,17,4,12,8,10,3,10,4,17,5,12,6,10,8,10,6,33,4,21,11,2,11,8,17,10,5,25,11,2,11,8,11,6,17,9,11,1,17,1,11,7,11,3,11,4,17,7,18,1,56,1,2,3,1,4,0,18,26,11,0,17,6,11,5,46,17,15,12,6,10,6,17,4,12,8,10,3,10,4,17,5,12,7,11,2,11,8,11,7,17,11,11,1,17,1,11,6,11,3,11,4,17,8,18,1,56,1,2,0,1,0],"user_manager":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,40,3,58,138,1,4,196,1,42,5,238,1,128,2,7,238,3,161,5,8,143,9,96,6,239,9,60,10,171,10,49,12,220,10,247,4,13,211,15,8,15,219,15,8,0,48,0,15,0,20,1,49,2,19,2,31,2,39,2,40,2,41,0,8,12,0,0,7,4,0,0,0,3,0,0,6,3,0,1,1,7,0,2,2,0,0,5,5,4,0,6,3,12,2,7,1,4,1,8,4,2,0,0,26,0,1,0,0,33,2,1,0,0,43,3,1,0,0,22,4,5,0,0,23,6,7,0,0,32,4,8,0,0,27,4,9,0,0,34,10,1,0,0,10,11,1,0,0,42,11,1,0,1,21,28,29,0,1,44,30,8,0,3,25,37,38,1,0,3,35,39,18,1,0,4,18,18,1,1,3,5,30,0,12,0,6,9,21,1,2,7,4,6,11,20,25,2,7,4,6,12,22,35,2,7,4,6,14,20,9,2,7,4,6,29,32,5,2,7,4,6,30,0,14,2,7,4,6,35,22,23,2,7,4,7,36,18,1,1,8,21,13,21,15,21,16,23,17,19,16,16,16,22,16,19,13,17,13,19,15,17,15,17,16,20,15,16,13,16,15,14,33,18,15,12,8,22,13,13,8,14,40,1,7,8,8,0,4,6,8,5,7,8,0,13,13,3,6,8,5,7,8,0,13,2,6,8,0,8,4,1,3,2,6,8,0,3,1,10,8,4,1,8,4,1,1,2,7,8,0,8,4,3,7,8,0,8,4,8,4,1,8,6,2,8,4,3,1,11,7,2,9,0,9,1,2,3,10,8,4,2,13,13,1,8,0,1,9,0,2,13,7,11,7,2,13,13,2,6,11,7,2,9,0,9,1,9,0,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,9,1,2,8,4,6,8,1,1,6,9,1,1,6,8,1,3,8,4,6,11,7,2,13,13,13,1,6,8,4,1,13,2,8,4,13,6,8,4,8,4,3,8,4,10,8,4,7,8,1,1,6,11,7,2,9,0,9,1,1,8,2,7,8,4,8,4,8,4,8,4,3,7,10,8,4,7,8,1,1,7,9,1,10,8,4,8,4,8,4,6,8,4,3,3,3,8,4,7,10,8,4,7,8,1,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,1,8,3,8,66,105,110,100,85,115,101,114,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,10,85,110,98,105,110,100,85,115,101,114,18,85,115,101,114,65,100,100,114,101,115,115,67,97,116,97,108,111,103,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,97,100,100,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,97,105,110,95,105,100,95,116,111,95,103,114,111,117,112,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,17,100,111,108,97,95,117,115,101,114,95,97,100,100,114,101,115,115,12,100,111,108,97,95,117,115,101,114,95,105,100,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,18,103,101,116,95,117,115,101,114,95,97,100,100,114,101,115,115,101,115,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,16,112,114,111,99,101,115,115,95,103,114,111,117,112,95,105,100,22,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,115,121,115,116,101,109,95,112,111,114,116,97,108,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,24,117,110,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,115,101,114,95,97,100,100,114,101,115,115,95,99,97,116,97,108,111,103,23,117,115,101,114,95,97,100,100,114,101,115,115,95,116,111,95,117,115,101,114,95,105,100,20,117,115,101,114,95,105,100,95,116,111,95,97,100,100,114,101,115,115,101,115,12,117,115,101,114,95,109,97,110,97,103,101,114,6,118,101,99,116,111,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,3,24,8,6,45,8,1,13,11,7,2,13,13,1,2,2,46,11,7,2,8,4,3,47,11,7,2,3,10,8,4,2,2,2,16,8,4,17,3,3,2,2,16,8,4,17,3,0,0,0,0,1,12,10,0,17,15,10,0,56,0,10,0,56,1,18,1,11,0,56,2,18,0,56,3,2,1,1,0,0,19,21,11,1,15,0,12,5,10,5,10,2,12,4,46,11,4,56,4,32,4,12,5,16,11,5,1,7,3,39,11,5,11,2,11,3,56,5,2,2,1,0,0,19,20,11,1,15,0,12,4,10,4,10,2,12,3,46,11,3,56,4,4,11,5,15,11,4,1,7,4,39,11,4,11,2,56,6,1,2,3,1,0,0,24,23,10,0,11,1,17,5,12,2,11,0,16,1,12,3,10,3,16,2,10,2,56,7,4,13,5,17,11,3,1,7,1,39,11,3,16,2,11,2,56,8,20,2,4,1,0,0,26,19,11,0,16,1,12,2,10,2,16,3,10,1,56,9,4,9,5,13,11,2,1,7,1,39,11,2,16,3,11,1,56,10,20,2,5,1,0,0,27,24,14,1,17,10,12,4,11,0,16,0,12,3,10,3,10,4,56,4,4,18,11,1,11,3,11,4,56,11,20,17,11,12,2,5,22,11,3,1,11,1,12,2,11,2,2,6,1,0,0,8,10,10,0,11,1,17,5,12,2,11,0,16,1,16,2,11,2,56,7,2,7,3,0,0,31,50,10,0,11,1,12,2,46,11,2,17,5,12,5,11,0,15,1,12,7,10,7,15,2,10,5,12,3,46,11,3,56,7,32,4,20,5,24,11,7,1,7,0,39,10,7,16,3,56,12,6,1,0,0,0,0,0,0,0,22,12,4,64,8,0,0,0,0,0,0,0,0,12,6,10,7,15,2,10,5,10,4,56,13,13,6,10,5,68,8,11,7,15,3,10,4,11,6,56,14,11,5,11,4,18,2,56,15,2,8,3,0,0,34,49,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,11,2,12,4,46,11,4,17,5,12,6,11,0,15,1,12,9,10,9,15,2,10,6,12,5,46,11,5,56,7,32,4,27,5,31,11,9,1,7,0,39,10,9,15,3,10,7,56,16,12,8,11,9,15,2,10,6,10,7,56,13,11,8,10,6,68,8,11,6,11,7,18,2,56,15,2,9,3,0,0,36,73,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,10,2,12,4,46,11,4,17,3,12,9,10,7,10,9,33,4,19,5,23,11,0,1,7,5,39,10,0,11,2,12,5,46,11,5,17,5,12,10,11,0,15,1,12,12,10,12,15,3,11,9,56,16,12,11,10,11,46,65,8,6,2,0,0,0,0,0,0,0,38,4,45,5,51,11,12,1,11,11,1,7,2,39,10,11,14,10,12,6,46,11,6,56,17,12,8,1,11,12,15,2,10,10,56,18,1,11,11,11,8,56,19,1,11,10,11,7,18,3,56,20,2,0,2,0,1,1,0,1,1,0,28,0,37,0,38,0,50,0],"wormhole_adapter_core":[161,28,235,11,6,0,0,0,12,1,0,46,2,46,114,3,160,1,202,1,4,234,2,18,5,252,2,140,3,7,136,6,150,10,8,158,16,96,6,254,16,30,10,156,17,68,12,224,17,166,4,13,134,22,6,15,140,22,6,0,88,0,27,0,36,0,46,0,60,0,61,0,85,0,89,1,29,1,30,1,44,1,57,1,58,1,79,1,83,1,84,1,87,2,28,2,40,2,45,2,64,2,78,2,86,0,4,12,0,0,15,3,0,0,5,3,0,0,16,3,0,0,6,3,0,0,17,3,0,0,7,3,0,1,0,12,0,2,8,7,0,3,11,0,0,5,14,12,0,6,23,12,0,7,22,12,0,8,2,8,0,9,3,12,1,0,1,11,21,4,0,12,13,12,2,7,1,12,1,13,18,2,0,15,20,2,0,16,25,7,2,1,0,0,0,17,1,7,0,18,9,12,0,19,10,7,0,20,12,0,0,21,19,12,0,22,24,0,0,0,51,0,1,0,0,69,2,1,0,0,35,3,1,0,0,73,4,1,0,0,71,4,1,0,0,74,4,1,0,0,72,4,1,0,0,66,5,6,0,0,65,7,8,0,0,67,5,6,0,0,77,9,10,0,1,47,43,44,0,4,33,24,46,0,4,34,24,42,0,4,42,33,24,0,4,43,52,24,0,4,48,1,32,0,4,49,1,32,0,5,26,47,48,0,5,76,47,48,0,6,53,49,23,0,6,68,50,1,0,7,59,40,41,0,10,39,21,1,1,3,11,56,12,13,0,12,56,12,17,2,7,12,14,63,21,1,1,12,16,32,22,23,2,1,0,16,41,1,19,2,1,0,16,52,27,1,2,1,0,16,75,29,30,2,1,0,17,56,24,25,0,18,56,14,15,0,19,56,25,26,0,19,82,26,24,0,20,62,34,35,0,20,64,36,10,0,22,81,41,24,0,25,16,28,18,26,20,27,18,29,18,23,28,30,18,23,37,23,38,3,6,8,9,7,8,24,7,8,18,0,4,6,8,9,7,8,0,13,10,2,3,6,8,9,7,8,0,13,7,6,8,9,7,8,24,7,8,0,13,15,11,14,1,8,17,6,8,13,6,7,8,24,7,8,0,6,8,7,10,2,6,8,13,7,8,18,2,8,8,10,2,8,7,8,24,7,8,0,6,8,7,10,2,7,8,10,7,8,11,6,8,13,7,8,18,4,8,8,8,8,15,10,2,11,7,8,24,7,8,0,6,8,7,7,8,10,8,8,8,8,13,3,15,11,14,1,8,17,6,8,13,1,3,3,7,8,24,7,8,18,8,15,1,7,8,18,1,8,15,2,6,8,24,7,8,18,1,8,21,2,8,20,8,12,1,11,16,2,9,0,9,1,2,13,8,22,1,11,19,2,9,0,9,1,1,8,0,1,9,0,2,6,11,19,2,9,0,9,1,6,9,0,1,1,1,10,2,1,8,20,1,8,22,3,7,11,19,2,9,0,9,1,9,0,9,1,1,8,1,2,7,11,19,2,9,0,9,1,6,9,0,2,9,0,9,1,2,8,23,10,2,1,2,3,13,15,2,3,7,8,21,14,10,2,1,8,23,4,7,8,24,11,14,1,8,17,8,23,6,8,13,1,8,5,1,8,6,3,13,10,2,8,8,6,7,8,24,6,11,19,2,13,8,22,7,11,16,2,8,20,8,12,10,2,6,8,13,7,8,18,1,8,25,4,8,8,13,2,10,2,1,6,8,7,1,13,7,8,8,15,3,13,10,2,8,8,8,8,6,8,8,8,8,3,13,2,10,2,4,7,8,10,8,8,13,15,2,15,15,2,6,8,11,8,8,2,7,8,11,8,8,3,15,8,23,10,2,5,13,3,8,8,8,8,3,6,65,112,112,67,97,112,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,12,68,101,108,101,116,101,66,114,105,100,103,101,11,68,101,108,101,116,101,79,119,110,101,114,13,68,101,108,101,116,101,83,112,101,110,100,101,114,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,14,82,101,103,105,115,116,101,114,66,114,105,100,103,101,13,82,101,103,105,115,116,101,114,79,119,110,101,114,15,82,101,103,105,115,116,101,114,83,112,101,110,100,101,114,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,86,65,65,6,86,101,99,77,97,112,13,97,100,100,95,108,105,113,117,105,100,105,116,121,11,97,112,112,95,109,97,110,97,103,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,8,99,111,110,116,97,105,110,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,20,100,101,108,101,116,101,95,114,101,109,111,116,101,95,98,114,105,100,103,101,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,13,100,111,108,97,95,99,111,110,116,114,97,99,116,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,6,105,110,115,101,114,116,12,105,115,95,100,111,108,97,95,117,115,101,114,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,10,112,111,111,108,95,99,111,100,101,99,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,22,114,101,103,105,115,116,101,114,95,114,101,109,111,116,101,95,98,114,105,100,103,101,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,19,114,101,109,111,116,101,95,100,101,108,101,116,101,95,111,119,110,101,114,21,114,101,109,111,116,101,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,21,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,23,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,5,115,116,97,116,101,3,115,117,105,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,3,118,97,97,7,118,101,99,95,109,97,112,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,24,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,22,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,99,104,97,105,110,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,4,50,8,15,90,8,21,31,11,16,2,8,20,8,12,70,11,19,2,13,8,22,1,2,2,92,13,91,10,2,2,2,2,92,13,91,10,2,3,2,2,37,13,38,15,4,2,2,37,13,38,15,5,2,2,37,13,38,15,6,2,2,37,13,38,15,0,1,0,0,11,18,10,2,17,24,12,5,11,1,10,2,12,4,12,3,11,5,11,3,46,11,4,17,32,11,2,56,0,56,1,18,0,56,2,2,1,1,0,0,1,23,10,1,16,0,14,2,56,3,32,4,7,5,11,11,1,1,7,1,39,11,1,15,0,10,2,10,3,17,31,17,33,56,4,11,2,11,3,18,1,56,5,2,2,1,0,0,26,22,10,1,16,0,14,2,56,3,4,6,5,10,11,1,1,7,0,39,11,1,15,0,14,2,56,6,12,3,1,11,2,11,3,17,34,18,1,56,5,2,3,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,4,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,5,1,0,0,31,22,10,3,10,4,17,17,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,35,12,7,11,1,11,5,11,7,11,6,17,36,1,11,3,11,4,18,5,56,7,2,6,1,0,0,31,22,10,3,10,4,17,16,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,35,12,7,11,1,11,5,11,7,11,6,17,36,1,11,3,11,4,18,6,56,8,2,7,3,0,0,39,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,22,17,37,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,8,3,0,0,45,59,11,0,10,1,16,0,11,1,15,2,11,3,11,6,11,7,17,22,17,37,17,12,12,12,1,12,11,12,10,12,14,12,13,10,2,17,11,11,11,33,4,23,5,31,11,5,1,11,4,1,11,2,1,7,2,39,11,4,10,13,11,2,17,11,11,10,77,17,18,1,12,9,10,5,10,14,12,8,46,11,8,17,20,32,4,52,11,5,10,14,17,21,5,54,11,5,1,11,13,11,14,11,9,11,12,2,9,3,0,0,39,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,22,17,37,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,10,3,0,0,51,28,11,3,10,4,11,2,17,11,11,8,17,19,1,12,11,11,6,11,7,11,4,11,5,11,11,52,17,15,12,13,11,1,15,1,73,0,0,0,0,11,13,17,35,12,12,11,0,11,9,11,12,11,10,17,36,2,0,3,0,1,0,2,0,54,0,55,0,80,0],"wormhole_adapter_pool":[161,28,235,11,6,0,0,0,12,1,0,42,2,42,92,3,134,1,142,1,4,148,2,16,5,164,2,185,2,7,221,4,171,6,8,136,11,96,6,232,11,50,10,154,12,51,12,205,12,167,2,13,244,14,10,15,254,14,2,0,71,0,29,0,30,0,37,0,52,0,72,1,23,1,24,1,35,1,48,1,49,1,64,1,66,1,67,1,69,2,21,2,33,2,36,2,54,2,63,2,68,0,10,8,0,0,11,8,0,0,12,3,0,1,3,7,0,2,9,12,1,0,1,3,6,8,0,5,17,12,0,6,1,8,0,7,2,12,1,0,1,9,16,4,0,10,8,12,2,7,1,12,1,11,13,2,0,13,15,2,0,14,19,7,2,1,0,0,0,15,0,7,0,16,4,12,0,17,5,7,0,18,7,0,0,19,14,12,0,20,18,0,0,0,41,0,1,0,0,42,2,1,0,0,58,3,1,1,0,0,59,4,5,0,0,55,6,1,1,0,1,38,36,17,0,1,39,36,37,0,2,28,25,17,1,0,2,59,29,17,0,2,70,35,1,1,0,3,22,31,1,0,4,27,17,34,0,5,50,32,33,0,8,32,11,1,1,3,9,46,0,7,0,10,46,0,22,2,7,12,12,61,11,1,1,8,13,60,8,9,0,14,34,1,16,2,1,0,14,43,20,1,2,1,0,15,46,17,18,0,16,46,13,14,0,17,46,18,19,0,18,53,26,27,0,18,54,28,5,0,20,65,33,17,0,16,10,18,15,19,15,15,21,16,23,7,11,9,11,13,38,1,7,8,12,0,5,7,8,0,13,10,2,7,8,18,7,8,12,9,7,8,1,7,8,18,11,8,1,8,11,7,11,4,1,9,0,11,8,1,9,0,13,10,2,6,8,7,7,8,12,7,7,8,1,7,8,18,11,8,1,8,11,13,10,2,6,8,7,7,8,12,1,3,7,6,8,5,7,8,18,7,8,1,7,11,4,1,9,0,10,2,6,8,7,7,8,12,1,8,9,1,6,8,12,1,5,1,8,0,1,9,0,3,7,8,12,11,13,2,13,8,16,8,15,2,6,8,18,7,8,12,1,8,15,2,13,8,16,1,11,13,2,9,0,9,1,1,10,2,1,8,14,1,8,16,3,7,11,13,2,9,0,9,1,9,0,9,1,2,8,14,8,6,1,11,10,2,9,0,9,1,1,8,1,2,8,17,10,2,5,7,11,4,1,9,0,11,8,1,9,0,13,10,2,7,8,12,3,7,8,15,14,10,2,1,8,17,4,7,8,18,11,8,1,8,11,8,17,6,8,7,3,13,10,2,7,8,12,5,3,3,8,3,8,3,13,1,6,8,5,6,7,8,18,6,11,13,2,13,8,16,7,11,10,2,8,14,8,6,10,2,6,8,7,7,8,12,1,8,19,6,13,3,8,3,8,3,3,2,5,7,11,4,1,9,0,8,3,3,8,3,7,8,12,1,6,8,3,1,13,1,8,2,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,4,80,111,111,108,11,80,111,111,108,71,101,110,101,115,105,115,9,80,111,111,108,83,116,97,116,101,17,80,111,111,108,87,105,116,104,100,114,97,119,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,6,97,109,111,117,110,116,7,98,121,116,101,115,51,50,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,7,99,114,101,97,116,111,114,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,12,100,115,116,95,99,104,97,105,110,95,105,100,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,4,105,110,105,116,10,105,110,105,116,105,97,108,105,122,101,6,105,110,115,101,114,116,7,105,115,95,105,110,105,116,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,5,110,111,110,99,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,12,112,111,111,108,95,97,100,100,114,101,115,115,10,112,111,111,108,95,99,111,100,101,99,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,12,115,101,110,100,95,100,101,112,111,115,105,116,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,3,115,117,105,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,40,8,9,26,5,44,1,1,2,4,40,8,9,73,8,15,25,11,10,2,8,14,8,6,57,11,13,2,13,8,16,2,2,6,47,3,62,13,31,13,51,10,2,56,10,2,20,3,0,0,0,0,1,9,10,0,17,14,11,0,46,17,17,9,18,0,56,0,2,1,1,4,0,12,59,10,0,16,0,20,10,4,46,17,17,33,4,9,5,17,11,3,1,11,0,1,11,4,1,7,2,39,10,0,16,1,20,32,4,23,5,31,11,3,1,11,0,1,11,4,1,7,3,39,11,3,10,4,12,5,46,11,5,17,21,12,7,56,1,12,6,13,6,11,1,11,2,17,20,17,22,56,2,10,4,17,14,11,7,11,4,56,3,11,6,18,1,56,4,8,11,0,15,1,21,2,2,3,0,0,24,20,11,3,11,4,11,5,11,6,11,8,56,5,12,10,11,0,15,2,73,0,0,0,0,11,10,17,23,12,9,11,1,11,2,11,9,11,7,17,24,1,2,3,3,0,0,24,17,11,3,11,4,11,6,17,8,12,8,11,0,15,2,73,0,0,0,0,11,8,17,23,12,7,11,1,11,2,11,7,11,5,17,24,2,4,1,4,0,30,37,11,0,17,10,11,1,10,2,16,3,11,2,15,4,11,4,11,5,10,6,17,12,17,25,17,11,1,12,7,12,10,12,9,12,8,12,11,11,3,10,10,10,7,10,9,11,6,56,6,11,8,11,11,14,9,17,6,14,9,17,5,14,10,17,5,11,7,18,2,56,7,2,0,1,0,2,1,1,1,3,1,2,0,45,0],"wormhole_adapter_verify":[161,28,235,11,6,0,0,0,10,1,0,22,2,22,54,3,76,102,4,178,1,16,5,194,1,206,1,7,144,3,135,3,8,151,6,128,1,6,151,7,30,10,181,7,6,12,187,7,205,1,0,38,1,29,2,14,2,27,2,28,2,35,2,37,3,13,3,19,3,34,3,36,0,8,12,0,1,4,7,1,0,0,2,1,8,0,3,7,4,0,4,3,12,2,7,1,12,1,5,6,2,0,6,10,7,2,1,0,0,0,7,0,7,0,8,2,7,0,9,5,12,0,10,9,0,0,0,22,0,1,0,0,12,2,3,0,0,30,4,5,0,0,32,6,3,0,0,31,7,5,0,1,20,19,13,1,0,1,24,18,10,1,0,1,26,3,14,1,0,1,33,13,14,1,0,3,25,25,26,0,4,11,27,3,2,7,12,4,15,24,10,2,7,12,6,15,9,10,2,1,0,6,21,9,11,2,1,0,10,16,16,22,0,10,17,16,12,0,10,18,16,17,0,10,30,21,5,0,12,8,13,8,8,12,7,12,6,12,5,12,11,23,10,23,2,6,11,6,2,13,8,8,6,13,1,11,1,1,8,8,2,6,11,6,2,13,8,8,6,8,10,0,4,7,8,9,6,11,6,2,13,8,8,10,2,6,8,2,1,8,10,3,7,11,4,2,8,7,8,0,6,8,10,7,8,5,6,7,8,9,6,11,6,2,13,8,8,7,11,4,2,8,7,8,0,10,2,6,8,2,7,8,5,2,13,8,8,2,6,11,6,2,9,0,9,1,6,9,0,1,1,1,6,9,1,1,8,8,1,9,0,1,11,1,1,9,0,2,11,1,1,8,8,13,1,6,8,10,1,13,1,6,11,1,1,9,0,1,7,11,1,1,9,0,3,10,2,6,8,2,8,10,3,6,8,9,10,2,6,8,2,1,8,7,2,8,7,8,0,2,6,11,4,2,9,0,9,1,9,0,1,7,8,5,1,8,3,3,7,11,4,2,9,0,9,1,9,0,9,1,7,66,121,116,101,115,51,50,5,67,108,111,99,107,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,3,97,100,100,20,97,115,115,101,114,116,95,107,110,111,119,110,95,101,109,105,116,116,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,6,100,105,103,101,115,116,15,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,13,101,109,105,116,116,101,114,95,99,104,97,105,110,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,101,120,116,114,97,99,116,3,103,101,116,22,103,101,116,95,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,2,105,100,7,105,115,95,115,111,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,14,114,101,112,108,97,121,95,112,114,111,116,101,99,116,4,115,111,109,101,5,115,116,97,116,101,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,1,23,8,3,0,1,0,0,1,19,10,0,10,1,56,0,4,11,11,0,11,1,56,1,20,56,2,12,2,5,17,11,1,1,11,0,1,56,3,12,2,11,2,2,1,1,0,0,15,25,10,1,17,16,12,3,11,0,14,3,17,0,12,2,14,2,56,4,4,11,5,15,11,1,1,7,0,39,13,2,56,5,11,1,17,15,33,4,22,5,24,7,1,39,2,2,1,0,0,20,15,11,0,11,2,11,3,12,5,12,4,46,11,4,11,5,17,17,12,6,11,1,14,6,17,1,11,6,2,3,1,0,0,22,26,10,0,10,1,17,14,12,3,46,11,3,56,6,32,4,10,5,18,11,1,1,11,2,1,11,0,1,7,2,39,11,0,11,1,17,14,11,2,17,9,18,0,56,7,2,4,1,0,0,5,12,11,0,11,1,11,3,11,4,17,2,12,6,11,2,14,6,11,5,17,3,11,6,2,0]},"type_origin_table":[{"module_name":"dola_address","struct_name":"DolaAddress","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"Pool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"DepositPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"WithdrawPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_verify","struct_name":"Unit","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceManagerCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version_1_0_0","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version_1_0_1","package":"0xc5b2a5049cd71586362d0c6a38e34cfaae7ea9ce6d5401a350506a15f817bf72"},{"module_name":"app_manager","struct_name":"TotalAppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"app_manager","struct_name":"AppCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"UserInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ReserveData","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ScaledBalance","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"BorrowRateFactors","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"PriceOracle","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"Price","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"Liquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AddLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"RemoveLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_logic","struct_name":"LendingCoreExecuteEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserAddressCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"BindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UnbindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"CoreState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"LendingCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_wormhole_adapter","struct_name":"SystemCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolWithdrawEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":6},"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302":{"upgraded_id":"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302","upgraded_version":1},"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a":{"upgraded_id":"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a","upgraded_version":1}}}},"owner":"Immutable","previous_transaction":"6B3tXa5PpoaRUQiYcytsC1M9fkfzXUc49NsWgC335qC1","storage_rebate":551022800},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000001","version":2,"module_map":{"address":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,3,7,10,15,8,25,32,12,57,16,0,0,0,1,0,1,0,0,1,3,7,97,100,100,114,101,115,115,6,108,101,110,103,116,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,6,32,0,0,0,0,0,0,0,2,0],"ascii":[161,28,235,11,6,0,0,0,11,1,0,4,2,4,14,3,18,84,4,102,8,5,110,59,7,169,1,200,1,8,241,2,32,6,145,3,10,10,155,3,11,12,166,3,186,2,13,224,5,4,0,5,0,16,0,2,7,0,0,0,7,0,1,1,7,1,0,0,0,8,0,1,0,0,20,2,3,0,0,21,2,4,0,0,3,5,6,0,0,18,7,8,0,0,17,9,1,0,0,14,5,10,0,0,4,5,11,0,0,10,3,2,0,0,6,1,0,0,0,13,0,6,0,0,11,0,6,0,1,9,13,14,1,0,1,12,12,6,1,0,1,15,8,13,1,0,1,19,14,13,1,0,13,3,12,3,14,3,15,3,1,2,1,8,1,1,10,2,1,8,0,1,11,2,1,8,0,1,6,8,0,1,1,2,7,8,0,8,1,0,1,7,8,0,1,3,1,6,10,2,1,6,11,2,1,9,0,1,11,2,1,9,0,1,9,0,2,3,3,4,67,104,97,114,6,79,112,116,105,111,110,6,83,116,114,105,110,103,24,97,108,108,95,99,104,97,114,97,99,116,101,114,115,95,112,114,105,110,116,97,98,108,101,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,4,98,121,116,101,5,98,121,116,101,115,4,99,104,97,114,12,100,101,115,116,114,111,121,95,115,111,109,101,10,105,110,116,111,95,98,121,116,101,115,17,105,115,95,112,114,105,110,116,97,98,108,101,95,99,104,97,114,7,105,115,95,115,111,109,101,13,105,115,95,118,97,108,105,100,95,99,104,97,114,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,8,112,111,112,95,99,104,97,114,9,112,117,115,104,95,99,104,97,114,4,115,111,109,101,6,115,116,114,105,110,103,10,116,114,121,95,115,116,114,105,110,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,1,0,0,0,0,0,0,2,1,7,10,2,1,2,1,6,2,0,1,0,0,8,9,10,0,17,10,4,4,5,6,7,0,39,11,0,18,1,2,1,1,0,0,4,12,11,0,17,2,12,1,14,1,56,0,4,7,5,9,7,0,39,11,1,56,1,2,2,1,0,0,15,30,14,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,25,5,11,14,0,10,1,66,0,20,17,10,32,4,20,56,2,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,5,40,11,0,18,0,56,3,2,3,1,0,0,15,32,10,0,16,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,29,5,12,10,0,16,0,10,1,66,0,20,17,11,32,4,24,11,0,1,9,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,40,8,2,4,1,0,0,8,7,11,0,15,0,14,1,16,1,20,68,0,2,5,1,0,0,8,5,11,0,15,0,69,0,18,1,2,6,1,0,0,8,4,11,0,17,7,65,0,2,7,1,0,0,8,3,11,0,16,0,2,8,1,0,0,8,3,11,0,19,0,2,9,1,0,0,8,3,11,0,19,1,2,10,1,0,0,8,4,11,0,49,127,37,2,11,1,0,0,6,13,10,0,49,32,38,4,9,11,0,49,126,37,12,1,5,11,9,12,1,11,1,2,0,0,1,0,0],"bcs":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,7,7,15,13,8,28,32,12,60,4,0,0,0,1,0,1,1,0,1,6,9,0,1,10,2,3,98,99,115,8,116,111,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,0],"bit_vector":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,36,7,77,109,8,186,1,32,6,218,1,40,10,130,2,8,12,138,2,239,3,13,249,5,4,0,2,0,0,7,0,0,6,0,1,0,0,7,2,3,0,0,9,2,3,0,0,8,2,3,0,0,3,4,5,0,0,4,6,0,0,0,5,4,0,0,1,3,1,8,0,2,7,8,0,3,0,2,6,8,0,3,1,1,1,6,8,0,2,10,1,3,1,7,1,5,3,7,1,3,3,3,9,66,105,116,86,101,99,116,111,114,9,98,105,116,95,102,105,101,108,100,10,98,105,116,95,118,101,99,116,111,114,12,105,115,95,105,110,100,101,120,95,115,101,116,6,108,101,110,103,116,104,32,108,111,110,103,101,115,116,95,115,101,116,95,115,101,113,117,101,110,99,101,95,115,116,97,114,116,105,110,103,95,97,116,3,110,101,119,3,115,101,116,10,115,104,105,102,116,95,108,101,102,116,5,117,110,115,101,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,3,8,1,0,2,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,4,0,0,0,0,0,0,0,2,2,4,3,1,10,1,0,1,0,0,7,37,10,0,6,0,0,0,0,0,0,0,0,36,4,5,5,7,7,1,39,10,0,7,3,35,4,12,5,14,7,1,39,6,0,0,0,0,0,0,0,0,12,2,64,5,0,0,0,0,0,0,0,0,12,1,40,10,2,10,0,35,4,32,5,24,13,1,9,68,5,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,18,40,11,0,11,1,18,0,2,1,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,8,11,2,21,2,2,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,9,11,2,21,2,3,1,0,0,9,89,10,1,10,0,16,1,20,38,4,33,10,0,16,0,65,5,12,6,6,0,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,30,5,17,10,0,15,0,10,4,67,5,12,3,9,11,3,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,12,11,0,1,5,88,10,1,12,5,10,5,10,0,16,1,20,35,4,65,5,42,10,0,10,5,12,2,46,11,2,17,4,4,55,10,0,10,5,10,1,23,17,1,5,60,10,0,10,5,10,1,23,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,35,10,0,16,1,20,11,1,23,12,5,10,5,10,0,16,1,20,35,4,86,5,78,10,0,10,5,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,71,11,0,1,2,4,1,0,0,3,17,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,16,0,11,1,66,5,20,2,5,1,0,0,3,4,11,0,16,0,65,5,2,6,1,0,0,0,37,10,1,10,0,16,1,20,35,4,7,5,11,11,0,1,7,0,39,10,1,12,2,10,2,10,0,16,1,20,35,4,33,5,20,10,0,10,2,17,4,32,4,28,11,0,1,5,33,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,13,11,2,11,1,23,2,0,1,0,0,0],"debug":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,11,5,13,5,7,18,30,8,48,32,12,80,8,0,0,0,1,0,1,1,0,0,2,1,1,0,1,6,9,0,0,5,100,101,98,117,103,5,112,114,105,110,116,17,112,114,105,110,116,95,115,116,97,99,107,95,116,114,97,99,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"fixed_point32":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,30,5,36,22,7,58,122,8,180,1,32,6,212,1,68,10,152,2,5,12,157,2,137,2,13,166,4,2,0,4,0,0,7,0,0,7,0,1,0,0,3,0,1,0,0,1,2,3,0,0,2,1,3,0,0,5,3,1,0,0,6,3,4,0,2,3,8,0,1,3,2,3,3,1,8,0,1,1,1,4,4,1,4,4,4,0,12,70,105,120,101,100,80,111,105,110,116,51,50,20,99,114,101,97,116,101,95,102,114,111,109,95,114,97,116,105,111,110,97,108,21,99,114,101,97,116,101,95,102,114,111,109,95,114,97,119,95,118,97,108,117,101,10,100,105,118,105,100,101,95,117,54,52,13,102,105,120,101,100,95,112,111,105,110,116,51,50,13,103,101,116,95,114,97,119,95,118,97,108,117,101,7,105,115,95,122,101,114,111,12,109,117,108,116,105,112,108,121,95,117,54,52,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,16,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,3,8,1,0,1,0,0,0,0,0,3,8,2,0,2,0,0,0,0,0,3,8,3,0,2,0,0,0,0,0,3,8,4,0,1,0,0,0,0,0,3,8,5,0,2,0,0,0,0,0,0,2,1,8,3,0,1,0,0,5,20,11,0,53,14,1,16,0,20,53,24,49,32,48,12,2,10,2,7,0,37,4,15,5,17,7,3,39,11,2,52,2,1,1,0,0,5,29,14,1,16,0,20,6,0,0,0,0,0,0,0,0,34,4,7,5,9,7,4,39,11,0,53,49,32,47,14,1,16,0,20,53,26,12,2,10,2,7,0,37,4,24,5,26,7,2,39,11,2,52,2,2,1,0,0,6,48,10,0,53,49,64,47,12,5,11,1,53,49,32,47,12,4,10,4,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,15,5,17,7,1,39,11,5,11,4,26,12,3,10,3,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,8,12,2,5,32,11,0,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,35,5,37,7,5,39,10,3,7,0,37,4,42,5,44,7,5,39,11,3,52,18,0,2,3,1,0,0,7,3,11,0,18,0,2,4,1,0,0,7,4,14,0,16,0,20,2,5,1,0,0,7,6,14,0,16,0,20,6,0,0,0,0,0,0,0,0,33,2,0,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,3,7,15,23,8,38,32,12,70,8,0,0,0,1,0,0,0,0,2,0,0,0,1,10,2,4,104,97,115,104,8,115,104,97,50,95,50,53,54,8,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"option":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,6,3,10,120,4,130,1,14,5,144,1,135,1,7,151,2,219,1,8,242,3,32,6,146,4,20,10,166,4,7,11,173,4,2,12,175,4,128,4,13,175,8,2,14,177,8,2,0,15,0,22,0,0,7,1,0,0,0,14,0,1,1,0,0,17,2,1,1,0,0,12,3,4,1,0,0,13,3,4,1,0,0,4,5,4,1,0,0,1,3,6,1,0,0,3,5,6,1,0,0,10,7,2,1,3,0,9,8,0,1,0,0,8,9,2,1,0,0,2,9,10,1,0,0,18,8,2,1,0,0,19,8,1,1,0,0,7,11,2,1,2,0,6,1,2,1,0,0,5,1,0,1,0,0,20,1,12,1,0,1,4,14,4,1,0,1,11,13,4,1,0,1,16,2,12,1,0,19,2,18,2,17,2,3,2,0,2,1,2,2,2,0,1,11,0,1,9,0,1,9,0,1,6,11,0,1,9,0,1,1,2,6,11,0,1,9,0,6,9,0,1,6,9,0,2,6,11,0,1,9,0,9,0,2,7,11,0,1,9,0,9,0,1,7,11,0,1,9,0,1,7,9,0,2,11,0,1,9,0,9,0,1,10,9,0,1,6,10,9,0,2,6,10,9,0,6,9,0,2,6,9,0,6,10,9,0,2,9,0,6,10,9,0,1,7,10,9,0,2,9,0,7,10,9,0,3,11,0,1,9,0,11,0,1,9,0,7,10,9,0,2,9,0,10,9,0,6,79,112,116,105,111,110,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,119,105,116,104,95,100,101,102,97,117,108,116,8,99,111,110,116,97,105,110,115,12,100,101,115,116,114,111,121,95,110,111,110,101,12,100,101,115,116,114,111,121,95,115,111,109,101,20,100,101,115,116,114,111,121,95,119,105,116,104,95,100,101,102,97,117,108,116,7,101,120,116,114,97,99,116,4,102,105,108,108,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,4,110,111,110,101,6,111,112,116,105,111,110,9,115,105,110,103,108,101,116,111,110,4,115,111,109,101,4,115,119,97,112,12,115,119,97,112,95,111,114,95,102,105,108,108,6,116,111,95,118,101,99,3,118,101,99,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,4,0,0,0,0,0,3,8,1,0,4,0,0,0,0,0,0,2,1,21,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,0,4,11,0,55,0,56,1,2,3,1,0,0,0,5,11,0,55,0,56,1,32,2,4,1,0,0,0,5,11,0,55,0,11,1,56,2,2,5,1,0,0,0,13,10,0,56,3,4,4,5,8,11,0,1,7,1,39,11,0,55,0,6,0,0,0,0,0,0,0,0,66,2,2,6,1,0,0,15,19,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,17,11,1,1,11,3,6,0,0,0,0,0,0,0,0,66,2,12,2,11,2,2,7,1,0,0,16,18,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,16,11,3,6,0,0,0,0,0,0,0,0,66,2,20,12,2,11,2,2,8,1,0,0,17,16,11,0,54,0,12,2,10,2,46,56,1,4,8,5,12,11,2,1,7,0,39,11,2,11,1,68,2,2,9,1,0,0,0,13,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,69,2,2,10,1,0,0,0,14,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,6,0,0,0,0,0,0,0,0,67,2,2,11,1,0,0,18,20,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,12,3,10,3,69,2,12,2,11,3,11,1,68,2,11,2,2,12,1,0,0,19,21,11,0,54,0,12,4,10,4,46,56,1,4,10,56,4,12,2,5,14,10,4,69,2,56,5,12,2,11,2,12,3,11,4,11,1,68,2,11,3,2,13,1,0,0,20,15,11,0,58,0,12,3,13,3,46,56,1,4,10,11,1,12,2,5,13,13,3,69,2,12,2,11,2,2,14,1,0,0,20,16,14,0,56,3,4,4,5,6,7,1,39,11,0,58,0,12,2,13,2,69,2,12,1,11,2,70,2,0,0,0,0,0,0,0,0,11,1,2,15,1,0,0,0,10,14,0,56,6,4,4,5,6,7,0,39,11,0,58,0,70,2,0,0,0,0,0,0,0,0,2,16,1,0,0,0,3,11,0,58,0,2,0,0,0,2,0],"string":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,14,3,22,114,4,136,1,8,5,144,1,123,7,139,2,248,1,8,131,4,32,6,163,4,20,10,183,4,6,12,189,4,133,3,13,194,7,2,0,19,0,4,0,17,0,24,0,1,7,0,1,1,7,0,2,0,7,1,0,0,0,23,0,1,0,0,6,2,1,0,0,21,1,2,0,0,22,0,3,0,0,5,4,5,0,0,14,4,6,0,0,15,4,7,0,0,2,8,9,0,0,3,10,9,0,0,8,11,9,0,0,20,12,1,0,0,7,13,7,0,0,9,5,6,0,0,11,14,6,0,0,12,15,0,0,0,10,16,7,0,1,13,2,0,0,1,19,0,2,0,2,16,9,18,1,0,2,18,17,18,1,0,3,2,21,9,1,0,3,14,20,6,1,0,19,1,18,1,21,19,20,19,1,10,2,1,8,0,1,8,1,1,11,2,1,8,0,1,6,8,0,1,6,10,2,1,1,1,3,2,7,8,0,8,0,0,2,7,8,0,10,2,3,7,8,0,3,8,0,3,6,8,0,3,3,2,6,8,0,6,8,0,2,6,10,2,3,3,6,10,2,3,3,2,6,10,2,6,10,2,1,9,0,1,11,2,1,9,0,1,2,1,6,10,9,0,2,7,10,9,0,10,9,0,8,1,3,3,3,6,10,2,8,0,8,0,3,5,1,1,1,6,10,2,3,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,97,112,112,101,110,100,11,97,112,112,101,110,100,95,117,116,102,56,5,97,115,99,105,105,5,98,121,116,101,115,10,102,114,111,109,95,97,115,99,105,105,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,19,105,110,116,101,114,110,97,108,95,99,104,101,99,107,95,117,116,102,56,17,105,110,116,101,114,110,97,108,95,105,110,100,101,120,95,111,102,25,105,110,116,101,114,110,97,108,95,105,115,95,99,104,97,114,95,98,111,117,110,100,97,114,121,19,105,110,116,101,114,110,97,108,95,115,117,98,95,115,116,114,105,110,103,10,105,110,116,111,95,98,121,116,101,115,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,4,115,111,109,101,6,115,116,114,105,110,103,10,115,117,98,95,115,116,114,105,110,103,8,116,111,95,97,115,99,105,105,8,116,114,121,95,117,116,102,56,4,117,116,102,56,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,5,10,2,0,1,0,0,9,9,14,0,17,12,4,4,5,6,7,0,39,11,0,18,0,2,1,1,0,0,9,4,11,0,17,16,18,0,2,2,1,0,0,9,4,11,0,19,0,17,17,2,3,1,0,0,3,12,14,0,17,12,4,8,11,0,18,0,56,0,12,1,5,10,56,1,12,1,11,1,2,4,1,0,0,9,3,11,0,16,0,2,5,1,0,0,9,4,11,0,16,0,56,2,2,6,1,0,0,9,4,11,0,16,0,65,19,2,7,1,0,0,9,7,11,0,15,0,14,1,16,0,20,56,3,2,8,1,0,0,9,5,11,0,11,1,17,0,17,7,2,9,1,0,0,22,56,10,0,16,0,12,7,10,1,10,7,65,19,37,4,13,11,7,10,1,17,13,12,3,5,17,11,7,1,9,12,3,11,3,4,20,5,24,11,0,1,7,1,39,10,0,46,17,6,12,10,10,0,10,1,12,4,46,6,0,0,0,0,0,0,0,0,11,4,17,10,12,9,10,0,11,1,11,10,12,6,12,5,46,11,5,11,6,17,10,12,8,13,9,11,2,17,7,13,9,11,8,17,7,11,9,11,0,21,2,10,1,0,0,23,48,11,0,16,0,12,6,10,6,65,19,12,7,10,2,11,7,37,4,15,10,1,10,2,37,12,3,5,17,9,12,3,11,3,4,24,10,6,10,1,17,13,12,4,5,26,9,12,4,11,4,4,33,10,6,10,2,17,13,12,5,5,35,9,12,5,11,5,4,38,5,42,11,6,1,7,1,39,11,6,11,1,11,2,17,14,18,0,2,11,1,0,0,9,6,11,0,16,0,11,1,16,0,17,15,2,12,0,2,0,13,0,2,0,14,0,2,0,15,0,2,0,0,0,0],"type_name":[161,28,235,11,6,0,0,0,10,1,0,6,2,6,8,3,14,47,5,61,44,7,105,143,1,8,248,1,32,6,152,2,7,10,159,2,6,12,165,2,215,1,13,252,3,2,0,14,0,2,0,4,0,1,7,0,2,0,7,0,0,6,0,1,1,0,0,9,0,1,1,0,0,5,2,3,0,0,7,2,4,0,0,8,2,4,0,0,10,1,4,0,1,11,0,6,0,2,3,3,7,0,2,13,9,4,0,0,1,8,0,1,6,8,0,1,6,8,1,1,8,1,4,10,2,3,3,6,10,2,1,3,1,6,10,2,1,2,1,10,2,5,2,6,2,3,10,2,6,10,2,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,13,98,111,114,114,111,119,95,115,116,114,105,110,103,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,11,105,110,116,111,95,115,116,114,105,110,103,6,108,101,110,103,116,104,4,110,97,109,101,6,115,116,114,105,110,103,9,116,121,112,101,95,110,97,109,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,58,10,2,1,0,0,2,1,12,8,1,0,1,2,0,1,1,2,0,2,1,0,0,0,3,11,0,16,0,2,3,1,0,0,5,33,17,6,6,2,0,0,0,0,0,0,0,24,12,3,11,0,16,0,17,7,12,4,7,1,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,28,5,17,13,1,10,4,10,2,66,8,20,68,8,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,4,1,11,1,17,8,2,4,1,0,0,10,39,17,6,6,2,0,0,0,0,0,0,0,24,6,2,0,0,0,0,0,0,0,22,12,3,11,0,16,0,17,7,12,5,7,1,12,4,10,5,10,3,66,8,12,2,7,0,12,1,10,2,14,1,34,4,32,5,23,13,4,11,2,20,68,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,12,11,5,1,11,2,1,11,4,17,8,2,5,1,0,0,0,4,14,0,16,0,20,2,0,0,0],"vector":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,102,4,104,4,5,108,97,7,205,1,154,1,8,231,2,32,6,135,3,10,12,145,3,216,4,0,17,0,5,0,1,1,0,0,9,2,3,1,0,0,1,4,5,1,0,0,11,6,0,1,0,0,2,7,8,1,0,0,10,9,10,1,0,0,4,1,0,1,0,0,15,11,0,1,0,0,14,10,1,1,0,0,13,9,0,1,0,0,0,12,0,1,0,0,8,2,13,1,0,0,3,14,13,1,0,0,6,14,15,1,0,0,12,7,10,1,0,0,7,16,0,1,0,0,16,7,10,1,0,9,10,11,10,0,1,10,9,0,1,6,10,9,0,1,3,2,6,10,9,0,3,1,6,9,0,2,7,10,9,0,9,0,2,7,10,9,0,3,1,7,9,0,1,7,10,9,0,1,9,0,3,7,10,9,0,3,3,2,7,10,9,0,10,9,0,1,1,2,6,10,9,0,6,9,0,2,1,3,3,7,10,9,0,9,0,3,3,3,3,3,2,3,3,3,3,7,10,9,0,3,6,97,112,112,101,110,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,5,101,109,112,116,121,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,7,114,101,118,101,114,115,101,9,115,105,110,103,108,101,116,111,110,4,115,119,97,112,11,115,119,97,112,95,114,101,109,111,118,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,2,0,4,1,2,0,5,1,2,0,6,1,2,0,7,1,2,0,8,1,0,0,1,7,64,10,0,0,0,0,0,0,0,0,12,1,13,1,11,0,68,10,11,1,2,9,1,0,0,17,38,10,0,46,65,10,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,2,6,0,0,0,0,0,0,0,0,12,2,11,3,6,1,0,0,0,0,0,0,0,23,12,1,10,2,10,1,35,4,35,5,22,10,0,10,2,10,1,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,1,6,1,0,0,0,0,0,0,0,23,12,1,5,17,11,0,1,2,10,1,0,0,0,17,13,1,56,0,14,1,56,1,32,4,12,5,7,10,0,13,1,69,10,68,10,5,2,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,11,1,0,0,0,5,11,0,65,10,6,0,0,0,0,0,0,0,0,33,2,12,1,0,0,18,33,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,27,5,10,10,0,10,2,66,10,10,1,33,4,22,11,0,1,11,1,1,8,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,2,13,1,0,0,18,35,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,28,5,10,10,0,10,2,66,10,10,1,33,4,23,11,0,1,11,1,1,8,11,2,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,6,0,0,0,0,0,0,0,0,2,14,1,0,0,19,37,10,0,46,65,10,12,4,10,1,10,4,38,4,12,11,0,1,7,0,39,11,4,6,1,0,0,0,0,0,0,0,23,12,4,10,1,10,4,35,4,34,5,21,10,0,12,3,10,1,12,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,11,3,11,2,10,1,71,10,5,16,11,0,69,10,2,15,1,0,0,3,32,10,0,46,65,10,12,3,10,2,10,3,36,4,12,11,0,1,7,0,39,10,0,11,1,68,10,10,2,10,3,35,4,29,5,20,10,0,10,2,10,3,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,2,16,1,0,0,3,23,10,0,46,56,1,32,4,6,5,10,11,0,1,7,0,39,10,0,46,65,10,6,1,0,0,0,0,0,0,0,23,12,2,10,0,11,1,11,2,71,10,11,0,69,10,2,0]},"type_origin_table":[{"module_name":"fixed_point32","struct_name":"FixedPoint32","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"option","struct_name":"Option","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"Char","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"bit_vector","struct_name":"BitVector","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"string","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"type_name","struct_name":"TypeName","package":"0x0000000000000000000000000000000000000000000000000000000000000001"}],"linkage_table":{}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000002","version":6,"module_map":{"address":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,8,3,18,61,4,79,2,5,81,20,7,101,129,1,8,230,1,64,6,166,2,54,12,220,2,69,0,1,1,2,1,3,1,11,0,8,1,0,7,0,3,0,7,0,0,15,0,1,0,0,7,1,0,0,0,6,2,0,0,0,13,0,2,0,0,12,0,3,0,0,14,0,4,0,0,9,5,6,0,0,10,5,1,0,1,11,2,3,0,2,13,7,2,1,0,3,5,3,4,0,4,4,2,2,0,9,0,1,5,1,15,1,10,2,1,8,0,1,8,1,0,1,3,1,6,9,0,6,83,116,114,105,110,103,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,6,101,110,99,111,100,101,10,102,114,111,109,95,97,115,99,105,105,10,102,114,111,109,95,98,121,116,101,115,9,102,114,111,109,95,117,50,53,54,3,104,101,120,6,108,101,110,103,116,104,3,109,97,120,6,115,116,114,105,110,103,15,116,111,95,97,115,99,105,105,95,115,116,114,105,110,103,8,116,111,95,98,121,116,101,115,9,116,111,95,115,116,114,105,110,103,7,116,111,95,117,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,32,0,0,0,0,0,0,0,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,3,8,0,0,0,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,0,0,5,3,14,0,56,0,2,4,1,0,0,5,5,11,0,17,3,17,11,17,8,2,5,1,0,0,5,4,11,0,17,4,17,10,2,6,1,0,0,5,2,7,0,2,7,1,0,0,5,2,7,1,2,0],"bag":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,112,4,132,1,12,5,144,1,82,7,226,1,185,1,8,155,3,32,6,187,3,10,10,197,3,8,12,205,3,230,1,13,179,5,4,0,4,0,11,0,18,0,21,0,0,12,0,2,2,4,0,3,1,2,0,0,17,0,1,0,0,3,2,3,2,7,4,0,5,4,5,2,7,4,0,6,6,7,2,7,4,0,19,6,8,2,7,4,0,7,4,9,1,7,0,8,4,9,2,7,4,0,16,10,11,0,0,15,10,9,0,0,10,1,3,0,1,3,14,3,2,7,4,1,5,15,5,2,7,4,1,6,16,7,2,7,4,1,12,15,9,1,7,1,13,15,9,2,7,4,1,19,16,8,2,7,4,2,9,12,3,0,2,17,0,12,0,10,13,11,13,12,13,15,13,13,17,14,13,1,7,8,2,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,1,9,0,2,8,1,3,3,66,97,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,3,98,97,103,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,14,8,1,20,3,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,18,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,0,0,0,1,0],"balance":[161,28,235,11,6,0,0,0,14,1,0,4,2,4,16,3,20,83,4,103,2,5,105,99,7,204,1,224,1,8,172,3,32,6,204,3,74,10,150,4,10,11,160,4,4,12,164,4,219,2,13,255,6,4,14,131,7,4,15,135,7,2,0,3,0,16,0,1,4,1,0,1,0,0,4,1,0,1,1,2,2,0,0,17,0,1,1,0,0,15,2,1,1,0,0,5,3,4,1,2,0,10,5,6,1,0,0,6,7,1,1,0,0,19,8,6,1,0,0,11,9,1,1,0,0,13,10,6,1,0,0,18,11,6,1,0,0,9,6,8,1,0,0,4,12,6,1,0,0,7,13,8,1,0,0,8,4,1,1,0,1,12,14,15,0,7,3,1,6,11,1,1,9,0,1,3,1,6,11,0,1,9,0,1,9,0,1,11,0,1,9,0,2,7,11,0,1,9,0,3,1,11,1,1,9,0,2,7,11,0,1,9,0,11,1,1,9,0,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,7,11,1,1,9,0,2,3,6,8,2,2,11,1,1,9,0,6,8,2,1,6,8,2,1,5,7,66,97,108,97,110,99,101,6,83,117,112,112,108,121,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,22,99,114,101,97,116,101,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,115,13,99,114,101,97,116,101,95,115,117,112,112,108,121,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,23,100,101,115,116,114,111,121,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,12,100,101,115,116,114,111,121,95,122,101,114,111,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,4,106,111,105,110,6,115,101,110,100,101,114,5,115,112,108,105,116,3,115,117,105,12,115,117,112,112,108,121,95,118,97,108,117,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,17,3,1,2,1,17,3,0,3,1,3,0,1,0,0,8,4,11,0,55,0,20,2,1,1,0,0,8,4,11,0,55,1,20,2,2,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,0,2,3,1,0,0,8,24,10,1,6,255,255,255,255,255,255,255,255,10,0,55,1,20,23,35,4,9,5,13,11,0,1,7,1,39,10,0,55,1,20,10,1,22,11,0,54,1,21,11,1,57,1,2,4,1,0,0,1,24,11,1,58,1,12,2,10,0,55,1,20,10,2,38,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,10,2,23,11,0,54,1,21,11,2,2,5,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,1,2,6,1,0,0,1,15,11,1,58,1,12,2,10,0,55,0,20,11,2,22,10,0,54,0,21,11,0,55,0,20,2,7,1,0,0,8,22,10,0,55,0,20,10,1,38,4,7,5,11,11,0,1,7,2,39,10,0,55,0,20,10,1,23,11,0,54,0,21,11,1,57,1,2,8,1,0,0,1,8,10,0,55,0,20,12,1,11,0,11,1,56,0,2,9,1,0,0,8,13,14,0,55,0,20,6,0,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,11,0,58,1,1,2,10,0,0,0,8,11,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,57,1,2,11,0,0,0,8,12,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,58,1,1,2,12,3,0,0,8,3,11,0,58,0,2,1,0,0,0,0,3,1,3,0,14,0],"bcs":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,10,3,20,135,1,4,155,1,24,5,179,1,131,1,7,182,2,222,2,8,148,5,64,6,212,5,55,10,139,6,6,12,145,6,203,8,13,220,14,2,0,3,1,3,1,10,1,31,0,2,0,0,7,0,2,1,7,1,0,0,0,30,0,1,1,0,0,8,1,2,0,0,6,2,1,0,0,11,3,4,0,0,12,3,5,0,0,20,3,6,0,0,19,3,7,0,0,18,3,8,0,0,23,3,7,0,0,21,3,9,0,0,22,3,10,0,0,26,3,1,0,0,27,3,11,0,0,25,3,12,0,0,24,3,13,0,0,13,3,14,0,0,14,3,15,0,0,17,3,16,0,0,16,3,17,0,0,15,3,18,0,1,30,0,1,1,0,2,9,19,33,1,0,2,29,20,33,1,0,3,28,21,19,1,0,4,5,1,4,0,4,7,19,7,0,20,20,23,6,22,4,21,4,22,5,21,5,22,6,21,6,22,7,21,7,22,8,21,8,1,6,9,0,1,10,2,1,8,0,1,7,8,0,1,5,1,1,1,2,1,3,1,4,1,10,5,1,10,1,1,10,10,2,1,10,3,1,10,4,1,11,1,1,5,1,11,1,1,1,1,11,1,1,2,1,11,1,1,3,1,11,1,1,4,0,1,9,0,1,7,10,9,0,2,10,2,3,2,1,2,3,3,2,3,3,4,2,4,4,3,3,2,3,3,3,3,10,5,3,3,3,10,1,3,3,3,10,2,3,3,3,10,10,2,3,3,3,10,3,3,3,3,10,4,1,11,1,1,9,0,3,66,67,83,6,79,112,116,105,111,110,7,97,100,100,114,101,115,115,3,98,99,115,5,98,121,116,101,115,10,102,114,111,109,95,98,121,116,101,115,20,105,110,116,111,95,114,101,109,97,105,110,100,101,114,95,98,121,116,101,115,6,108,101,110,103,116,104,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,12,112,101,101,108,95,97,100,100,114,101,115,115,9,112,101,101,108,95,98,111,111,108,19,112,101,101,108,95,111,112,116,105,111,110,95,97,100,100,114,101,115,115,16,112,101,101,108,95,111,112,116,105,111,110,95,98,111,111,108,16,112,101,101,108,95,111,112,116,105,111,110,95,117,49,50,56,15,112,101,101,108,95,111,112,116,105,111,110,95,117,54,52,14,112,101,101,108,95,111,112,116,105,111,110,95,117,56,9,112,101,101,108,95,117,49,50,56,8,112,101,101,108,95,117,54,52,7,112,101,101,108,95,117,56,16,112,101,101,108,95,118,101,99,95,97,100,100,114,101,115,115,13,112,101,101,108,95,118,101,99,95,98,111,111,108,15,112,101,101,108,95,118,101,99,95,108,101,110,103,116,104,13,112,101,101,108,95,118,101,99,95,117,49,50,56,12,112,101,101,108,95,118,101,99,95,117,54,52,11,112,101,101,108,95,118,101,99,95,117,56,15,112,101,101,108,95,118,101,99,95,118,101,99,95,117,56,7,114,101,118,101,114,115,101,4,115,111,109,101,8,116,111,95,98,121,116,101,115,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,10,5,1,0,10,1,1,0,10,2,1,0,10,10,2,1,0,10,3,1,0,10,4,1,0,0,2,1,4,10,2,0,1,0,0,19,3,11,0,56,0,2,1,1,0,0,19,5,13,0,56,1,11,0,18,0,2,2,1,0,0,1,7,11,0,19,0,12,1,13,1,56,1,11,1,2,3,1,0,0,22,35,10,0,16,0,65,6,17,25,38,4,7,5,11,11,0,1,7,0,39,64,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,12,2,12,1,10,2,17,25,35,4,30,5,20,13,1,10,0,15,0,69,6,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,11,1,17,24,2,4,1,0,0,23,21,11,0,17,5,12,2,10,2,49,0,33,4,10,9,12,1,5,19,11,2,49,1,33,4,15,5,17,7,1,39,8,12,1,11,1,2,5,1,0,0,19,15,10,0,16,0,65,6,6,1,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,11,0,15,0,69,6,2,6,1,0,0,24,40,10,0,16,0,65,6,6,8,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,64,35,4,36,5,20,10,0,15,0,69,6,52,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,7,1,0,0,25,40,10,0,16,0,65,6,6,16,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,128,35,4,36,5,20,10,0,15,0,69,6,53,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,8,1,0,0,26,48,6,0,0,0,0,0,0,0,0,49,0,6,0,0,0,0,0,0,0,0,12,2,12,3,12,4,10,2,6,4,0,0,0,0,0,0,0,37,4,11,5,15,11,0,1,7,2,39,10,0,15,0,69,6,52,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,4,10,1,6,127,0,0,0,0,0,0,0,28,10,3,47,27,12,4,11,1,6,128,0,0,0,0,0,0,0,28,6,0,0,0,0,0,0,0,0,33,4,39,5,44,11,3,49,7,22,12,3,5,6,11,0,1,11,4,2,9,1,0,0,27,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,3,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,3,68,4,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,10,1,0,0,28,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,4,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,4,68,5,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,11,1,0,0,29,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,5,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,5,68,6,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,12,1,0,0,30,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,6,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,11,68,1,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,13,1,0,0,31,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,7,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,6,68,7,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,14,1,0,0,32,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,8,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,7,68,8,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,15,1,0,0,14,14,10,0,17,4,4,8,11,0,17,3,56,2,12,1,5,12,11,0,1,56,3,12,1,11,1,2,16,1,0,0,15,14,10,0,17,4,4,8,11,0,17,4,56,4,12,1,5,12,11,0,1,56,5,12,1,11,1,2,17,1,0,0,16,14,10,0,17,4,4,8,11,0,17,5,56,6,12,1,5,12,11,0,1,56,7,12,1,11,1,2,18,1,0,0,17,14,10,0,17,4,4,8,11,0,17,6,56,8,12,1,5,12,11,0,1,56,9,12,1,11,1,2,19,1,0,0,18,14,10,0,17,4,4,8,11,0,17,7,56,10,12,1,5,12,11,0,1,56,11,12,1,11,1,2,0,0,0],"bls12381":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,12,7,24,56,8,80,32,12,112,8,0,0,0,2,0,1,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,8,98,108,115,49,50,51,56,49,22,98,108,115,49,50,51,56,49,95,109,105,110,95,112,107,95,118,101,114,105,102,121,23,98,108,115,49,50,51,56,49,95,109,105,110,95,115,105,103,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"borrow":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,24,3,32,59,4,91,10,5,101,83,7,184,1,158,1,8,214,2,64,6,150,3,20,10,170,3,19,11,189,3,2,12,191,3,125,13,188,4,4,14,192,4,4,0,5,1,15,0,14,0,19,0,3,4,1,12,0,0,0,0,0,1,2,7,1,0,0,2,1,7,0,3,4,2,0,0,12,0,1,1,12,0,5,2,3,1,12,0,16,4,5,1,12,0,6,1,6,1,12,1,7,9,6,1,0,1,8,11,6,1,0,1,9,15,5,1,0,1,18,6,9,1,0,2,11,12,13,1,8,3,10,7,8,0,7,6,5,6,8,6,6,6,4,6,2,9,0,7,8,4,1,11,0,1,9,0,1,7,11,0,1,9,0,2,9,0,8,1,3,7,11,0,1,9,0,9,0,8,1,0,1,9,0,1,7,8,4,1,5,1,11,2,1,9,0,2,8,3,9,0,1,7,11,2,1,9,0,1,6,9,0,1,8,3,2,8,3,5,2,7,11,2,1,9,0,9,0,6,66,111,114,114,111,119,2,73,68,6,79,112,116,105,111,110,8,82,101,102,101,114,101,110,116,9,84,120,67,111,110,116,101,120,116,6,98,111,114,114,111,119,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,7,101,120,116,114,97,99,116,4,102,105,108,108,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,3,111,98,106,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,117,116,95,98,97,99,107,3,114,101,102,4,115,111,109,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,2,11,5,20,11,2,1,9,0,1,2,2,17,5,13,8,3,0,6,0,1,0,0,5,6,11,1,17,9,11,0,56,0,57,0,2,1,1,0,0,10,14,10,0,54,0,56,1,12,2,14,2,56,2,12,1,11,2,11,0,55,1,20,11,1,18,1,2,2,1,0,0,14,30,11,2,19,1,12,3,12,4,14,1,56,2,11,3,33,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,11,4,33,4,21,5,25,11,0,1,7,0,39,11,0,54,0,11,1,56,3,2,3,1,0,0,9,7,11,0,58,0,12,1,1,11,1,56,4,2,0,1,0,0,0,6,1,6,0],"clock":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,31,4,51,2,5,53,30,7,83,122,8,205,1,32,6,237,1,44,10,153,2,8,12,161,2,79,13,240,2,2,0,3,0,7,0,11,0,12,0,0,8,0,1,2,4,0,3,1,2,0,0,10,0,1,0,0,5,2,3,0,0,4,4,3,0,1,3,3,6,0,2,9,8,3,1,8,3,8,2,5,0,4,7,1,6,8,0,1,3,1,6,8,2,0,3,7,8,0,3,6,8,2,1,5,1,8,1,1,8,0,1,9,0,5,67,108,111,99,107,9,84,120,67,111,110,116,101,120,116,3,85,73,68,5,99,108,111,99,107,25,99,111,110,115,101,110,115,117,115,95,99,111,109,109,105,116,95,112,114,111,108,111,103,117,101,6,99,114,101,97,116,101,2,105,100,6,111,98,106,101,99,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,1,10,3,0,1,0,0,3,4,11,0,16,0,20,2,1,0,0,0,3,13,11,0,17,5,7,1,33,4,6,5,8,7,0,39,17,3,6,0,0,0,0,0,0,0,0,18,0,56,0,2,2,0,0,0,3,15,11,2,17,5,7,1,33,4,6,5,10,11,0,1,7,0,39,11,1,11,0,15,0,21,2,0,1,0],"coin":[161,28,235,11,6,0,0,0,13,1,0,20,2,20,62,3,82,155,2,4,237,2,34,5,143,3,221,2,7,236,5,164,5,8,144,11,64,6,208,11,30,10,238,11,52,11,162,12,6,12,168,12,249,4,13,161,17,14,14,175,17,14,0,15,1,11,1,43,1,48,0,12,0,42,0,56,0,58,0,59,0,64,0,1,12,1,0,1,0,2,12,1,0,1,0,7,12,1,0,1,0,3,3,1,0,1,1,5,7,0,2,4,7,1,0,0,3,5,7,0,4,0,4,1,0,1,4,6,4,1,0,1,5,9,4,0,7,8,2,0,9,10,7,0,0,55,0,1,1,0,0,57,2,3,1,0,0,50,0,4,1,0,0,51,5,6,1,0,0,66,7,1,1,0,0,12,7,8,1,0,0,13,9,10,1,0,0,24,11,12,1,0,0,33,12,13,1,0,0,54,14,12,1,0,0,45,15,16,1,0,0,35,17,16,1,0,0,47,18,12,1,0,0,23,18,19,1,0,0,67,20,12,1,0,0,22,12,16,1,0,0,16,21,22,1,2,0,36,23,12,1,0,0,38,24,13,1,0,0,14,25,1,1,0,0,37,26,16,1,0,0,62,27,16,1,0,0,63,28,16,1,0,0,60,27,16,1,0,0,61,28,16,1,0,0,25,29,30,1,0,0,28,29,31,1,0,0,29,29,32,1,0,0,26,29,31,1,0,0,27,29,33,1,0,0,49,5,4,1,0,1,48,41,32,0,2,46,34,46,1,0,3,65,41,31,0,4,17,34,3,1,2,4,19,43,1,1,0,4,22,13,16,1,0,4,32,42,13,1,0,4,35,37,1,1,0,4,47,36,13,1,0,4,52,4,1,1,0,4,66,8,1,1,0,4,67,16,13,1,0,5,20,35,16,0,5,40,20,35,0,6,44,44,16,1,12,8,34,39,40,1,2,9,41,32,45,0,40,34,41,34,39,34,8,34,38,34,9,34,4,34,12,34,42,34,36,34,46,34,34,34,37,34,35,34,17,34,45,12,32,45,1,6,11,2,1,9,0,1,3,1,11,2,1,9,0,1,11,8,1,9,0,1,6,11,8,1,9,0,1,7,11,2,1,9,0,1,7,11,8,1,9,0,1,6,11,0,1,9,0,1,6,11,7,1,9,0,1,7,11,0,1,9,0,1,7,11,7,1,9,0,2,11,7,1,9,0,7,8,10,1,11,0,1,9,0,1,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,10,2,7,11,7,1,9,0,11,0,1,9,0,0,2,7,11,0,1,9,0,11,0,1,9,0,3,7,11,0,1,9,0,3,7,8,10,1,10,11,0,1,9,0,1,7,8,10,7,9,0,2,10,2,10,2,10,2,11,5,1,8,11,7,8,10,2,11,2,1,9,0,11,1,1,9,0,3,7,11,2,1,9,0,3,7,8,10,2,7,11,2,1,9,0,3,2,7,11,2,1,9,0,11,0,1,9,0,4,7,11,2,1,9,0,3,5,7,8,10,3,6,11,2,1,9,0,7,11,1,1,9,0,8,6,3,6,11,2,1,9,0,7,11,1,1,9,0,8,4,1,6,11,1,1,9,0,1,2,1,8,6,1,8,4,1,11,5,1,8,11,1,9,0,1,8,9,2,7,11,7,1,9,0,3,2,7,11,7,1,9,0,11,7,1,9,0,3,3,3,10,11,0,1,9,0,1,6,9,0,1,1,1,10,2,2,7,11,8,1,9,0,3,2,7,11,8,1,9,0,11,7,1,9,0,2,9,0,5,1,8,11,1,11,5,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,15,67,117,114,114,101,110,99,121,67,114,101,97,116,101,100,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,85,114,108,5,97,115,99,105,105,7,98,97,108,97,110,99,101,11,98,97,108,97,110,99,101,95,109,117,116,4,98,117,114,110,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,13,99,114,101,97,116,101,95,115,117,112,112,108,121,8,100,101,99,105,109,97,108,115,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,6,100,101,108,101,116,101,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,122,101,114,111,13,100,105,118,105,100,101,95,105,110,116,111,95,110,12,102,114,111,109,95,98,97,108,97,110,99,101,12,103,101,116,95,100,101,99,105,109,97,108,115,15,103,101,116,95,100,101,115,99,114,105,112,116,105,111,110,12,103,101,116,95,105,99,111,110,95,117,114,108,8,103,101,116,95,110,97,109,101,10,103,101,116,95,115,121,109,98,111,108,8,105,99,111,110,95,117,114,108,2,105,100,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,12,105,110,116,111,95,98,97,108,97,110,99,101,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,4,106,111,105,110,4,109,105,110,116,17,109,105,110,116,95,97,110,100,95,116,114,97,110,115,102,101,114,12,109,105,110,116,95,98,97,108,97,110,99,101,4,110,97,109,101,3,110,101,119,10,110,101,119,95,117,110,115,97,102,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,3,112,117,116,4,115,111,109,101,5,115,112,108,105,116,6,115,116,114,105,110,103,6,115,117,112,112,108,121,12,115,117,112,112,108,121,95,105,109,109,117,116,10,115,117,112,112,108,121,95,109,117,116,12,115,117,112,112,108,121,95,118,97,108,117,101,6,115,121,109,98,111,108,4,116,97,107,101,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,5,116,121,112,101,115,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,15,117,112,100,97,116,101,95,105,99,111,110,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,13,117,112,100,97,116,101,95,115,121,109,98,111,108,3,117,114,108,4,117,116,102,56,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,2,31,8,9,12,11,7,1,9,0,1,2,6,31,8,9,18,2,39,8,6,53,8,4,21,8,6,30,11,5,1,8,11,2,2,2,31,8,9,55,11,8,1,9,0,3,2,1,18,2,2,34,0,34,1,34,0,1,0,0,16,4,11,0,55,0,56,0,2,1,1,0,0,3,6,11,0,58,0,12,1,17,43,11,1,2,2,1,0,0,16,3,11,0,55,0,2,3,1,0,0,16,3,11,0,54,0,2,4,1,0,0,16,4,11,0,55,1,56,1,2,5,1,0,0,16,3,11,0,55,1,2,6,1,0,0,16,3,11,0,54,1,2,7,1,0,0,16,5,11,1,17,44,11,0,57,1,2,8,1,0,0,13,6,11,0,58,1,12,1,17,43,11,1,2,9,1,0,0,16,7,11,2,17,44,11,0,11,1,56,2,57,1,2,10,1,0,0,16,6,11,0,11,1,56,3,56,4,1,2,11,1,4,0,13,10,11,1,58,1,12,2,17,43,11,0,54,1,11,2,56,4,1,2,12,1,0,0,16,6,11,0,54,1,11,1,11,2,56,5,2,13,1,0,0,38,59,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,11,11,0,1,11,2,1,7,1,39,10,1,10,0,46,56,6,37,4,18,5,24,11,0,1,11,2,1,7,2,39,64,12,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,3,10,0,46,56,6,10,1,26,12,4,40,10,3,10,1,6,1,0,0,0,0,0,0,0,23,35,4,53,5,42,13,5,10,0,10,4,10,2,56,7,68,12,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,34,11,0,1,11,2,1,11,5,2,14,1,0,0,16,5,11,0,17,44,56,8,57,1,2,15,1,0,0,13,7,11,0,58,1,12,1,17,43,11,1,56,9,2,16,1,0,0,16,25,14,0,56,10,4,4,5,8,11,6,1,7,0,39,10,6,17,44,11,0,56,11,57,0,11,6,17,44,11,1,11,3,17,33,11,2,17,31,11,4,17,33,11,5,57,2,2,17,1,0,0,16,8,11,2,17,44,11,0,54,0,11,1,56,12,57,1,2,18,1,0,0,16,5,11,0,54,0,11,1,56,12,2,19,1,4,0,13,9,11,1,58,1,12,2,17,43,11,0,54,0,11,2,56,13,2,20,1,4,0,16,7,11,0,11,1,11,3,56,14,11,2,56,15,2,21,1,4,0,16,5,11,2,11,1,54,2,21,2,22,1,4,0,16,5,11,2,11,1,54,3,21,2,23,1,4,0,16,5,11,2,11,1,54,4,21,2,24,1,4,0,16,7,11,2,17,47,56,16,11,1,54,5,21,2,25,1,0,0,16,4,11,0,55,6,20,2,26,1,0,0,16,4,11,0,55,2,20,2,27,1,0,0,16,4,11,0,55,3,20,2,28,1,0,0,16,4,11,0,55,4,20,2,29,1,0,0,16,4,11,0,55,5,20,2,30,1,0,0,16,3,11,0,55,0,2,2,1,0,1,1,2,1,3,1,4,1,5,1,1,0,34,1,34,2,34,3,34,4,34,5,34,6,34,0],"display":[161,28,235,11,6,0,0,0,13,1,0,16,2,16,46,3,62,132,1,4,194,1,22,5,216,1,196,1,7,156,3,223,2,8,251,5,64,6,187,6,20,10,207,6,38,11,245,6,6,12,251,6,160,3,13,155,10,6,14,161,10,6,0,14,1,31,0,18,0,26,0,27,0,32,0,33,0,36,0,0,12,1,8,1,0,1,3,1,8,1,0,8,3,1,8,1,1,4,7,0,3,2,7,0,3,6,4,0,4,3,12,0,6,5,2,0,7,7,7,2,1,0,0,0,0,24,0,1,1,8,0,25,2,1,1,8,0,12,0,3,1,8,0,35,4,3,1,8,0,9,5,3,1,8,0,11,6,3,1,8,0,15,5,3,1,8,0,29,7,3,1,8,0,23,8,9,1,8,0,37,10,11,1,8,0,19,10,12,1,8,0,13,13,1,1,8,0,10,5,3,1,8,2,16,14,3,1,3,3,24,13,28,0,3,34,21,22,0,4,20,8,9,1,0,5,28,19,3,1,12,6,30,17,18,0,7,17,3,30,2,1,0,7,22,31,3,2,1,0,7,29,26,27,2,1,0,8,14,11,14,0,14,12,14,17,1,13,23,21,25,16,14,13,29,19,25,20,25,2,6,8,6,7,8,7,1,11,0,1,9,0,4,6,8,6,10,8,3,10,8,3,7,8,7,0,1,7,11,0,1,9,0,3,7,11,0,1,9,0,8,3,8,3,3,7,11,0,1,9,0,10,8,3,10,8,3,2,7,11,0,1,9,0,8,3,1,6,8,6,1,1,1,6,11,0,1,9,0,1,13,1,6,11,8,2,8,3,8,3,1,7,8,7,1,9,0,3,11,0,1,9,0,3,3,1,8,3,1,6,8,7,1,5,2,9,0,5,2,13,11,8,2,8,3,8,3,1,6,8,5,1,8,4,1,11,2,1,9,0,2,3,3,2,8,3,8,3,2,7,11,8,2,9,0,9,1,6,9,0,2,9,0,9,1,1,8,5,1,11,1,1,9,0,1,11,8,2,9,0,9,1,3,7,11,8,2,9,0,9,1,9,0,9,1,7,68,105,115,112,108,97,121,14,68,105,115,112,108,97,121,67,114,101,97,116,101,100,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,6,86,101,99,77,97,112,14,86,101,114,115,105,111,110,85,112,100,97,116,101,100,3,97,100,100,12,97,100,100,95,105,110,116,101,114,110,97,108,12,97,100,100,95,109,117,108,116,105,112,108,101,15,99,114,101,97,116,101,95,97,110,100,95,107,101,101,112,15,99,114,101,97,116,101,95,105,110,116,101,114,110,97,108,7,100,105,115,112,108,97,121,4,101,100,105,116,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,6,102,105,101,108,100,115,12,102,114,111,109,95,112,97,99,107,97,103,101,2,105,100,6,105,110,115,101,114,116,13,105,115,95,97,117,116,104,111,114,105,122,101,100,3,110,101,119,15,110,101,119,95,119,105,116,104,95,102,105,101,108,100,115,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,6,115,101,110,100,101,114,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,112,100,97,116,101,95,118,101,114,115,105,111,110,7,118,101,99,95,109,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,3,21,8,5,19,11,8,2,8,3,8,3,37,13,1,2,1,21,8,4,2,2,3,21,8,4,37,13,19,11,8,2,8,3,8,3,2,14,1,14,0,14,0,1,0,0,3,11,11,0,56,0,4,4,5,8,11,1,1,7,0,39,11,1,56,1,2,1,1,0,0,15,43,14,1,65,16,12,6,10,6,14,2,65,16,33,4,9,5,15,11,0,1,11,3,1,7,1,39,6,0,0,0,0,0,0,0,0,12,5,11,0,11,3,56,2,12,4,10,5,10,6,35,4,41,5,26,13,4,14,1,10,5,66,16,20,14,2,10,5,66,16,20,56,3,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,21,11,4,2,2,1,4,0,3,8,11,0,10,1,56,2,11,1,46,17,18,56,4,2,3,1,4,0,20,24,10,0,55,0,20,72,1,0,22,10,0,54,0,21,10,0,55,0,20,12,1,10,0,55,1,20,12,2,11,0,55,2,17,15,11,1,11,2,57,0,56,5,2,4,1,4,0,3,5,11,0,11,1,11,2,56,3,2,5,1,4,0,24,38,14,1,65,16,12,4,10,4,14,2,65,16,33,4,9,5,13,11,0,1,7,1,39,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,35,5,20,10,0,14,1,10,3,66,16,20,14,2,10,3,66,16,20,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,15,11,0,1,2,6,1,4,0,3,11,10,0,54,1,14,1,56,6,1,1,11,0,11,1,11,2,56,3,2,7,1,4,0,3,7,11,0,54,1,14,1,56,6,1,1,2,8,1,0,0,3,3,11,0,56,7,2,9,1,0,0,3,4,11,0,55,0,20,2,10,1,0,0,3,3,11,0,55,1,2,11,0,0,0,28,12,11,0,17,14,12,1,14,1,17,15,57,1,56,8,11,1,56,9,72,0,0,57,2,2,12,0,0,0,3,6,11,0,54,1,11,1,11,2,56,10,2,0,2,0,1,0,0,0,14,1,14,2,14,0],"dynamic_field":[161,28,235,11,6,0,0,0,14,1,0,6,2,6,22,3,28,133,1,4,161,1,24,5,185,1,168,1,7,225,2,129,3,8,226,5,64,6,162,6,40,10,202,6,12,11,214,6,2,12,216,6,235,2,13,195,9,6,14,201,9,8,15,209,9,2,0,11,1,26,0,25,0,0,8,2,7,0,4,0,1,2,7,1,0,0,2,1,7,0,2,3,4,0,0,4,0,1,2,7,4,0,6,2,3,2,7,4,0,9,4,5,2,7,4,0,27,4,6,2,7,4,0,13,2,7,1,7,0,29,4,8,2,7,4,0,14,2,7,2,7,4,0,15,2,9,1,7,0,16,4,10,1,7,0,19,11,12,1,7,0,5,11,1,1,8,0,7,9,13,1,8,0,8,10,14,1,8,0,28,15,16,1,8,0,17,15,7,0,0,18,15,7,1,8,1,24,1,24,1,0,1,30,16,24,1,0,2,10,19,1,0,2,21,28,12,0,2,23,12,19,0,2,31,18,12,0,9,16,10,21,11,21,12,21,13,21,4,16,3,20,17,6,16,6,15,21,11,26,12,26,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,9,1,2,6,8,3,5,2,7,8,3,5,2,5,9,0,1,5,1,6,9,0,1,7,9,0,2,5,5,1,9,0,3,11,0,2,9,0,9,1,5,5,1,6,8,3,1,8,3,2,9,0,9,1,1,11,0,2,9,0,9,1,3,5,5,9,1,2,9,0,11,1,1,9,1,1,11,1,1,9,0,4,6,11,0,2,9,0,8,2,5,6,8,3,6,8,2,1,11,0,2,9,0,8,2,2,9,0,8,2,1,6,8,2,4,7,11,0,2,9,0,8,2,5,7,8,3,7,8,2,5,70,105,101,108,100,2,73,68,6,79,112,116,105,111,110,3,85,73,68,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,6,100,101,108,101,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,16,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,17,104,97,115,104,95,116,121,112,101,95,97,110,100,95,107,101,121,2,105,100,13,105,100,95,116,111,95,97,100,100,114,101,115,115,4,110,97,109,101,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,3,20,8,3,22,9,0,32,9,1,0,20,0,1,0,0,17,26,11,0,46,17,21,12,5,10,5,10,1,56,0,12,4,10,5,10,4,17,14,32,4,14,5,16,7,0,39,11,4,17,20,11,1,11,2,57,0,12,3,11,5,11,3,56,1,2,1,1,0,0,12,10,10,0,17,21,11,1,56,0,12,2,11,0,11,2,56,2,55,0,2,2,1,0,0,12,11,10,0,46,17,21,11,1,56,0,12,2,11,0,11,2,56,3,54,0,2,3,1,0,0,22,17,11,0,46,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,4,58,0,12,4,1,17,18,11,4,2,4,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,17,14,2,5,1,0,0,23,19,10,0,10,1,12,2,46,11,2,56,5,4,13,11,0,11,1,56,6,56,7,12,3,5,17,11,0,1,56,8,12,3,11,3,2,6,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,9,2,7,3,0,0,25,22,10,0,17,21,11,1,56,0,12,3,11,0,11,3,56,10,12,2,10,2,55,1,12,4,10,2,55,2,1,11,2,55,3,12,5,11,4,11,5,17,19,2,8,3,0,0,29,24,10,0,46,17,21,11,1,56,0,12,3,11,0,11,3,56,11,12,2,10,2,54,1,12,4,10,2,54,2,1,11,2,54,3,12,5,11,4,11,5,46,17,19,2,9,3,2,0,10,3,2,0,11,3,2,0,12,3,2,0,13,3,2,0,14,3,2,0,15,3,2,0,0,2,0,0,0,1,0,20,1,27,2,27,0,27,0,12,0],"dynamic_object_field":[161,28,235,11,6,0,0,0,10,1,0,8,2,8,20,3,28,138,1,4,166,1,26,5,192,1,131,1,7,195,2,178,2,8,245,4,64,10,181,5,6,11,187,5,2,12,189,5,233,1,0,11,1,22,0,10,0,21,0,3,7,1,0,0,1,1,7,1,0,0,3,0,7,0,3,2,4,0,0,4,0,1,2,7,12,0,6,2,3,2,7,12,0,9,4,5,2,7,12,0,23,4,6,2,7,12,0,12,2,7,1,7,0,13,2,7,2,7,12,0,17,2,8,1,7,1,20,1,24,1,0,1,25,10,24,1,0,2,4,0,1,2,7,4,2,5,18,1,1,8,2,7,15,11,1,8,2,8,19,20,1,8,2,13,2,7,2,7,4,2,14,2,15,1,7,2,15,4,19,1,7,2,16,22,7,1,8,2,23,4,6,2,7,4,2,24,22,10,1,8,3,17,11,12,1,8,3,18,17,12,0,3,26,16,17,0,19,6,9,13,14,14,10,6,11,6,15,14,12,6,18,6,17,13,13,13,16,6,7,12,8,12,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,8,2,3,11,0,1,9,0,8,2,11,0,1,9,0,1,9,0,1,6,9,0,1,8,2,2,11,0,1,9,0,8,2,1,11,0,1,9,0,2,6,8,3,5,1,6,8,3,1,5,2,5,9,0,2,7,8,3,5,1,7,9,0,4,11,0,1,9,0,11,0,1,9,0,9,1,5,2,5,5,2,11,0,1,9,0,5,1,11,1,1,9,0,2,73,68,6,79,112,116,105,111,110,3,85,73,68,7,87,114,97,112,112,101,114,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,4,110,97,109,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,19,9,0,0,10,0,1,0,0,9,21,11,1,57,0,12,5,14,2,56,0,12,4,10,0,10,5,11,4,56,1,11,0,11,5,12,3,46,11,3,56,2,1,17,21,11,2,56,3,2,1,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,2,56,4,2,2,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,5,56,6,2,3,1,0,0,21,20,11,1,57,0,12,3,10,0,10,3,12,2,46,11,2,56,2,12,5,17,21,11,5,56,7,12,4,11,0,11,3,56,8,1,11,4,2,4,1,0,0,14,7,11,1,57,0,12,2,11,0,11,2,56,9,2,5,1,0,0,23,20,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,9,2,11,0,11,2,56,2,12,3,17,21,11,3,56,10,2,6,1,0,0,23,21,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,56,11,2,11,0,11,2,56,2,12,3,1,11,3,17,20,56,12,2,0],"ecdsa_k1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,15,5,17,28,7,45,64,8,109,32,6,141,1,26,12,167,1,12,0,1,0,2,0,1,0,0,0,2,1,0,0,3,3,4,0,3,6,10,2,6,10,2,2,1,10,2,1,6,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,17,100,101,99,111,109,112,114,101,115,115,95,112,117,98,107,101,121,8,101,99,100,115,97,95,107,49,19,115,101,99,112,50,53,54,107,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,107,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,2,1,2,0,0],"ecdsa_r1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,10,5,12,24,7,36,46,8,82,32,6,114,26,12,140,1,8,0,0,0,1,0,1,0,0,2,2,3,0,3,6,10,2,6,10,2,2,1,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,8,101,99,100,115,97,95,114,49,19,115,101,99,112,50,53,54,114,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,114,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,0],"ecvrf":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,5,5,7,15,7,22,19,8,41,32,6,73,30,12,103,4,0,0,0,1,0,1,0,4,6,10,2,6,10,2,6,10,2,6,10,2,1,1,5,101,99,118,114,102,12,101,99,118,114,102,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,1,2,0,0],"ed25519":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,12,7,19,23,8,42,32,12,74,4,0,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,7,101,100,50,53,53,49,57,14,101,100,50,53,53,49,57,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"event":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,4,7,12,11,8,23,32,12,55,4,0,1,0,0,0,1,1,3,1,9,0,0,4,101,109,105,116,5,101,118,101,110,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"groth16":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,16,3,18,50,5,68,76,7,144,1,237,2,8,253,3,32,6,157,4,30,10,187,4,32,12,219,4,180,1,13,143,6,14,0,10,0,0,7,0,0,1,7,0,0,3,7,0,0,2,7,0,0,5,0,1,0,0,6,0,1,0,0,16,2,3,0,0,17,3,4,0,0,15,5,6,0,0,14,5,7,0,0,12,8,3,0,0,13,9,3,0,0,18,10,11,0,0,19,12,11,0,0,1,8,0,4,10,2,10,2,10,2,10,2,1,8,1,1,10,10,2,1,10,2,1,8,2,1,8,3,2,6,8,0,6,10,2,2,2,6,10,2,4,6,8,0,6,8,1,6,8,2,6,8,3,1,1,7,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,5,67,117,114,118,101,20,80,114,101,112,97,114,101,100,86,101,114,105,102,121,105,110,103,75,101,121,11,80,114,111,111,102,80,111,105,110,116,115,17,80,117,98,108,105,99,80,114,111,111,102,73,110,112,117,116,115,22,97,108,112,104,97,95,103,49,95,98,101,116,97,95,103,50,95,98,121,116,101,115,8,98,108,115,49,50,51,56,49,5,98,110,50,53,52,5,98,121,116,101,115,21,100,101,108,116,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,21,103,97,109,109,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,7,103,114,111,116,104,49,54,2,105,100,21,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,30,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,95,105,110,116,101,114,110,97,108,23,112,114,111,111,102,95,112,111,105,110,116,115,95,102,114,111,109,95,98,121,116,101,115,30,112,117,98,108,105,99,95,112,114,111,111,102,95,105,110,112,117,116,115,95,102,114,111,109,95,98,121,116,101,115,14,112,118,107,95,102,114,111,109,95,98,121,116,101,115,12,112,118,107,95,116,111,95,98,121,116,101,115,20,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,29,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,95,105,110,116,101,114,110,97,108,21,118,107,95,103,97,109,109,97,95,97,98,99,95,103,49,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,11,2,1,2,4,20,10,2,4,10,2,9,10,2,8,10,2,2,2,1,7,10,2,3,2,1,7,10,2,0,1,0,0,0,3,49,0,18,0,2,1,1,0,0,0,3,49,1,18,0,2,2,1,0,0,0,6,11,0,11,1,11,2,11,3,18,1,2,3,1,0,0,4,24,64,5,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,68,5,13,1,14,0,16,1,20,68,5,13,1,14,0,16,2,20,68,5,13,1,14,0,16,3,20,68,5,11,1,2,4,1,0,0,0,3,11,0,18,2,2,5,1,0,0,0,3,11,0,18,3,2,6,1,0,0,0,6,11,0,16,4,20,11,1,17,7,2,7,0,2,0,8,1,0,0,0,17,11,0,16,4,20,10,1,16,0,10,1,16,1,10,1,16,2,11,1,16,3,11,2,16,5,11,3,16,6,17,9,2,9,0,2,0,1,0,1,1,1,2,1,3,0,0,2,0,3,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,7,7,19,26,8,45,32,12,77,8,0,1,0,0,0,1,0,0,2,0,1,0,1,6,10,2,1,10,2,10,98,108,97,107,101,50,98,50,53,54,4,104,97,115,104,9,107,101,99,99,97,107,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"hex":[161,28,235,11,6,0,0,0,8,1,0,4,3,4,21,4,25,2,5,27,37,7,64,44,8,108,64,6,172,1,159,6,12,203,7,194,2,0,4,1,5,0,3,0,0,0,0,1,0,0,0,0,2,1,1,0,1,0,3,4,1,0,3,1,1,10,2,1,2,5,10,10,2,7,10,2,3,3,10,2,2,7,10,9,0,10,9,0,0,4,2,3,3,10,2,5,1,1,1,2,2,6,97,112,112,101,110,100,6,100,101,99,111,100,101,11,100,101,99,111,100,101,95,98,121,116,101,6,101,110,99,111,100,101,3,104,101,120,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,10,10,2,130,6,128,2,2,48,48,2,48,49,2,48,50,2,48,51,2,48,52,2,48,53,2,48,54,2,48,55,2,48,56,2,48,57,2,48,97,2,48,98,2,48,99,2,48,100,2,48,101,2,48,102,2,49,48,2,49,49,2,49,50,2,49,51,2,49,52,2,49,53,2,49,54,2,49,55,2,49,56,2,49,57,2,49,97,2,49,98,2,49,99,2,49,100,2,49,101,2,49,102,2,50,48,2,50,49,2,50,50,2,50,51,2,50,52,2,50,53,2,50,54,2,50,55,2,50,56,2,50,57,2,50,97,2,50,98,2,50,99,2,50,100,2,50,101,2,50,102,2,51,48,2,51,49,2,51,50,2,51,51,2,51,52,2,51,53,2,51,54,2,51,55,2,51,56,2,51,57,2,51,97,2,51,98,2,51,99,2,51,100,2,51,101,2,51,102,2,52,48,2,52,49,2,52,50,2,52,51,2,52,52,2,52,53,2,52,54,2,52,55,2,52,56,2,52,57,2,52,97,2,52,98,2,52,99,2,52,100,2,52,101,2,52,102,2,53,48,2,53,49,2,53,50,2,53,51,2,53,52,2,53,53,2,53,54,2,53,55,2,53,56,2,53,57,2,53,97,2,53,98,2,53,99,2,53,100,2,53,101,2,53,102,2,54,48,2,54,49,2,54,50,2,54,51,2,54,52,2,54,53,2,54,54,2,54,55,2,54,56,2,54,57,2,54,97,2,54,98,2,54,99,2,54,100,2,54,101,2,54,102,2,55,48,2,55,49,2,55,50,2,55,51,2,55,52,2,55,53,2,55,54,2,55,55,2,55,56,2,55,57,2,55,97,2,55,98,2,55,99,2,55,100,2,55,101,2,55,102,2,56,48,2,56,49,2,56,50,2,56,51,2,56,52,2,56,53,2,56,54,2,56,55,2,56,56,2,56,57,2,56,97,2,56,98,2,56,99,2,56,100,2,56,101,2,56,102,2,57,48,2,57,49,2,57,50,2,57,51,2,57,52,2,57,53,2,57,54,2,57,55,2,57,56,2,57,57,2,57,97,2,57,98,2,57,99,2,57,100,2,57,101,2,57,102,2,97,48,2,97,49,2,97,50,2,97,51,2,97,52,2,97,53,2,97,54,2,97,55,2,97,56,2,97,57,2,97,97,2,97,98,2,97,99,2,97,100,2,97,101,2,97,102,2,98,48,2,98,49,2,98,50,2,98,51,2,98,52,2,98,53,2,98,54,2,98,55,2,98,56,2,98,57,2,98,97,2,98,98,2,98,99,2,98,100,2,98,101,2,98,102,2,99,48,2,99,49,2,99,50,2,99,51,2,99,52,2,99,53,2,99,54,2,99,55,2,99,56,2,99,57,2,99,97,2,99,98,2,99,99,2,99,100,2,99,101,2,99,102,2,100,48,2,100,49,2,100,50,2,100,51,2,100,52,2,100,53,2,100,54,2,100,55,2,100,56,2,100,57,2,100,97,2,100,98,2,100,99,2,100,100,2,100,101,2,100,102,2,101,48,2,101,49,2,101,50,2,101,51,2,101,52,2,101,53,2,101,54,2,101,55,2,101,56,2,101,57,2,101,97,2,101,98,2,101,99,2,101,100,2,101,101,2,101,102,2,102,48,2,102,49,2,102,50,2,102,51,2,102,52,2,102,53,2,102,54,2,102,55,2,102,56,2,102,57,2,102,97,2,102,98,2,102,99,2,102,100,2,102,101,2,102,102,10,2,1,0,0,1,0,0,2,33,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,4,12,5,12,3,10,3,10,4,35,4,31,5,12,13,5,12,2,7,2,12,1,11,2,14,1,14,0,10,3,66,1,20,52,66,0,20,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,5,2,1,1,0,0,5,47,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,3,12,4,12,2,10,3,6,2,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,14,5,16,7,0,39,10,2,10,3,35,4,45,5,21,14,0,10,2,66,1,20,17,2,49,16,24,14,0,10,2,6,1,0,0,0,0,0,0,0,22,66,1,20,17,2,22,12,1,13,4,11,1,68,1,11,2,6,2,0,0,0,0,0,0,0,22,12,2,5,16,11,4,2,2,0,0,0,6,64,49,48,10,0,37,4,9,10,0,49,58,35,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,5,5,62,49,65,10,0,37,4,27,10,0,49,71,35,12,2,5,29,9,12,2,11,2,4,38,49,10,11,0,22,49,65,23,12,4,5,60,49,97,10,0,37,4,47,10,0,49,103,35,12,3,5,49,9,12,3,11,3,4,52,5,54,7,1,39,49,10,11,0,22,49,97,23,12,4,11,4,12,5,11,5,2,0],"hmac":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,10,7,17,19,8,36,32,12,68,4,0,0,0,1,0,1,0,2,6,10,2,6,10,2,1,10,2,4,104,109,97,99,13,104,109,97,99,95,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"kiosk":[161,28,235,11,6,0,0,0,13,1,0,22,2,22,94,3,116,230,2,4,218,3,64,5,154,4,250,3,7,148,8,189,7,8,209,15,64,6,145,16,130,1,10,147,17,101,11,248,17,8,12,128,18,244,13,13,244,31,18,14,134,32,6,0,51,1,60,0,21,0,26,0,30,0,31,0,33,0,59,0,81,0,83,0,84,0,8,12,0,0,9,12,0,0,13,12,1,12,1,0,1,0,0,0,4,7,0,0,10,7,0,0,11,7,0,0,6,3,1,12,1,0,7,3,1,12,1,0,5,3,1,12,1,1,12,7,1,0,0,2,0,4,1,0,1,3,2,12,1,0,1,7,3,7,0,7,18,4,0,8,14,2,0,9,15,12,1,0,1,9,16,0,1,0,1,10,17,2,0,0,57,0,1,0,0,25,2,3,0,0,79,4,5,0,0,80,6,5,0,0,62,7,5,1,12,0,55,8,5,1,12,0,82,9,10,1,12,0,53,11,5,1,12,0,63,12,5,1,12,0,28,9,5,1,12,0,68,13,14,1,12,0,54,15,16,1,12,0,72,17,14,1,12,0,75,18,5,1,12,0,90,19,3,0,0,39,20,21,0,0,40,20,21,1,12,0,46,20,21,0,0,44,20,21,0,0,45,20,21,0,0,38,22,21,0,0,87,22,23,0,0,78,24,5,0,0,85,25,26,0,0,86,27,23,0,0,61,25,28,0,0,48,25,29,0,0,66,25,30,0,0,67,22,31,0,0,22,32,33,1,12,0,23,9,34,1,12,0,24,9,35,1,12,0,76,36,5,1,12,0,70,37,38,1,12,0,69,37,38,1,12,0,71,37,30,1,12,1,29,70,10,1,0,1,47,69,21,1,0,2,50,61,30,1,0,2,89,71,30,1,0,2,91,5,42,1,0,3,37,46,47,1,0,3,42,47,42,1,0,3,82,72,47,1,0,3,89,60,30,1,0,4,19,49,5,2,7,4,4,34,74,21,1,7,4,73,53,55,2,7,4,4,74,53,54,2,7,4,5,19,49,5,2,7,12,5,22,74,77,2,7,12,5,23,53,78,2,7,12,5,34,74,21,1,7,5,35,74,21,2,7,12,5,73,53,55,2,7,12,6,32,10,5,1,3,7,27,40,5,0,7,41,33,38,1,8,7,57,0,40,0,7,88,26,38,0,9,58,63,64,1,0,10,77,43,28,0,40,41,57,44,41,41,57,10,49,48,45,50,4,10,48,52,54,48,16,10,45,52,55,57,7,10,47,52,55,58,44,41,42,41,38,41,48,50,55,62,60,10,10,10,37,30,36,30,39,41,43,41,52,73,53,48,46,75,46,76,50,48,51,48,1,7,8,18,2,8,0,8,1,3,8,0,8,1,7,8,18,1,11,12,1,8,15,3,7,8,0,6,8,1,6,8,18,0,3,7,8,0,6,8,1,5,3,7,8,0,6,8,1,9,0,4,7,8,0,6,8,1,6,11,16,1,9,0,9,0,3,7,8,0,6,8,1,8,13,1,9,0,4,7,8,0,6,8,1,8,13,3,4,7,8,0,6,8,1,9,0,3,3,7,8,0,8,13,11,12,1,8,15,2,9,0,11,17,1,9,0,5,7,8,0,6,8,1,8,13,3,7,8,18,1,11,2,1,9,0,3,7,8,0,11,2,1,9,0,11,12,1,8,15,2,7,8,0,11,2,1,9,0,4,7,8,0,6,8,1,11,10,1,3,7,8,18,2,6,8,0,8,13,1,1,2,7,8,0,6,8,1,1,7,8,14,3,7,8,0,6,8,1,1,1,6,8,0,1,6,8,14,1,7,8,0,1,5,1,14,1,3,1,7,11,11,1,8,15,3,6,8,0,6,8,1,8,13,1,6,9,0,1,7,9,0,2,9,0,8,3,3,7,8,0,9,0,8,3,1,6,11,2,1,9,0,1,8,13,2,8,1,8,0,1,8,14,1,8,15,1,11,11,1,9,0,1,6,8,18,1,8,0,5,8,14,8,13,8,14,14,11,11,1,8,15,2,11,11,1,9,0,7,8,18,1,11,12,1,9,0,2,8,4,9,0,3,7,8,14,9,0,9,1,2,8,6,1,3,8,13,8,13,8,13,2,8,5,3,2,7,8,14,9,0,1,11,10,1,9,1,1,9,1,2,8,13,8,13,1,11,7,1,9,0,1,11,9,1,9,0,2,9,0,3,1,6,11,12,1,9,0,2,7,11,11,1,9,0,11,11,1,9,0,1,11,8,1,9,0,3,8,13,3,8,13,1,11,17,1,9,0,7,8,13,8,13,8,14,8,13,8,13,3,8,14,5,8,14,8,13,8,13,3,3,3,8,14,8,13,8,13,3,3,3,3,1,6,11,10,1,9,0,1,11,10,1,9,0,1,6,11,11,1,9,0,3,7,11,11,1,9,0,3,7,8,18,1,8,4,2,6,8,14,9,0,1,8,6,1,8,5,1,6,9,1,1,7,9,1,7,66,97,108,97,110,99,101,6,66,111,114,114,111,119,4,67,111,105,110,2,73,68,4,73,116,101,109,12,73,116,101,109,68,101,108,105,115,116,101,100,10,73,116,101,109,76,105,115,116,101,100,13,73,116,101,109,80,117,114,99,104,97,115,101,100,5,75,105,111,115,107,13,75,105,111,115,107,79,119,110,101,114,67,97,112,7,76,105,115,116,105,110,103,4,76,111,99,107,6,79,112,116,105,111,110,11,80,117,114,99,104,97,115,101,67,97,112,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,16,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,10,98,111,114,114,111,119,95,118,97,108,18,99,108,111,115,101,95,97,110,100,95,119,105,116,104,100,114,97,119,4,99,111,105,110,6,100,101,108,101,116,101,6,100,101,108,105,115,116,12,100,101,115,116,114,111,121,95,115,111,109,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,4,101,109,105,116,5,101,118,101,110,116,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,3,102,111,114,12,102,114,111,109,95,98,97,108,97,110,99,101,10,104,97,115,95,97,99,99,101,115,115,8,104,97,115,95,105,116,101,109,18,104,97,115,95,105,116,101,109,95,119,105,116,104,95,116,121,112,101,2,105,100,12,105,110,116,111,95,98,97,108,97,110,99,101,12,105,115,95,101,120,99,108,117,115,105,118,101,9,105,115,95,108,105,115,116,101,100,21,105,115,95,108,105,115,116,101,100,95,101,120,99,108,117,115,105,118,101,108,121,9,105,115,95,108,111,99,107,101,100,7,105,115,95,115,111,109,101,10,105,116,101,109,95,99,111,117,110,116,7,105,116,101,109,95,105,100,4,106,111,105,110,5,107,105,111,115,107,8,107,105,111,115,107,95,105,100,4,108,105,115,116,22,108,105,115,116,95,119,105,116,104,95,112,117,114,99,104,97,115,101,95,99,97,112,4,108,111,99,107,9,109,105,110,95,112,114,105,99,101,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,5,111,119,110,101,114,5,112,108,97,99,101,14,112,108,97,99,101,95,97,110,100,95,108,105,115,116,5,112,114,105,99,101,7,112,114,111,102,105,116,115,14,112,114,111,102,105,116,115,95,97,109,111,117,110,116,11,112,114,111,102,105,116,115,95,109,117,116,8,112,117,114,99,104,97,115,101,17,112,117,114,99,104,97,115,101,95,99,97,112,95,105,116,101,109,18,112,117,114,99,104,97,115,101,95,99,97,112,95,107,105,111,115,107,22,112,117,114,99,104,97,115,101,95,99,97,112,95,109,105,110,95,112,114,105,99,101,17,112,117,114,99,104,97,115,101,95,119,105,116,104,95,99,97,112,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,19,114,101,116,117,114,110,95,112,117,114,99,104,97,115,101,95,99,97,112,10,114,101,116,117,114,110,95,118,97,108,6,115,101,110,100,101,114,20,115,101,116,95,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,9,115,101,116,95,111,119,110,101,114,16,115,101,116,95,111,119,110,101,114,95,99,117,115,116,111,109,3,115,117,105,4,116,97,107,101,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,3,117,105,100,7,117,105,100,95,109,117,116,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,0,2,5,41,8,14,65,11,11,1,8,15,61,5,48,14,20,1,1,2,2,41,8,14,36,8,13,2,2,4,41,8,14,52,8,13,49,8,13,56,3,3,2,2,52,8,13,49,8,13,4,2,1,41,8,13,5,2,2,41,8,13,43,1,6,2,1,41,8,13,7,2,3,51,8,13,41,8,13,64,3,8,2,3,51,8,13,41,8,13,64,3,9,2,2,51,8,13,41,8,13,7,10,9,10,8,10,2,10,0,1,0,0,39,19,10,0,17,58,56,0,10,0,46,17,61,73,0,0,0,0,8,18,0,12,2,11,0,17,58,14,2,56,1,18,1,12,1,11,2,11,1,2,1,1,0,0,45,38,11,0,19,0,1,12,6,1,12,7,12,5,11,1,19,1,12,4,12,3,14,5,17,59,11,4,33,4,17,5,21,11,2,1,7,0,39,11,6,73,0,0,0,0,33,4,26,5,30,11,2,1,7,3,39,11,3,17,56,11,5,17,56,11,7,11,2,56,2,2,2,1,0,0,5,21,10,0,46,56,1,11,1,16,0,20,33,4,9,5,15,11,0,1,11,2,1,7,0,39,11,2,17,61,11,0,15,1,21,2,3,1,0,0,5,18,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,2,11,0,15,1,21,2,4,1,0,0,5,29,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,16,2,20,73,1,0,0,0,22,10,0,15,2,21,11,0,15,3,14,2,56,3,18,4,11,2,56,4,2,5,1,0,0,5,12,10,0,15,3,14,3,56,3,18,6,8,56,5,11,0,11,1,11,3,56,6,2,6,1,0,0,51,72,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,17,32,4,22,5,26,11,0,1,7,8,39,10,0,10,2,12,4,46,11,4,17,19,32,4,35,5,39,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,15,4,47,5,51,11,0,1,7,11,39,10,0,16,2,20,73,1,0,0,0,23,10,0,15,2,21,10,0,15,3,10,2,9,18,5,56,7,1,11,0,15,3,11,2,18,4,56,8,2,7,1,0,0,56,53,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,4,46,11,4,56,9,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,5,46,11,5,17,19,32,4,34,5,38,11,0,1,7,4,39,10,0,15,3,10,2,9,18,5,10,3,56,10,11,0,46,56,1,11,2,11,3,57,0,56,11,2,8,1,0,0,38,13,14,2,56,3,12,4,10,0,10,1,11,2,56,6,11,0,11,1,11,4,11,3,56,12,2,9,1,0,0,51,64,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,56,9,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,19,32,4,34,5,38,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,18,4,46,5,50,11,0,1,7,12,39,10,0,15,3,10,2,9,18,5,56,13,1,11,0,46,56,1,11,2,57,1,56,14,2,10,1,0,0,59,58,10,0,15,3,10,1,9,18,5,56,13,12,4,10,0,15,3,10,1,18,4,56,8,12,3,10,0,16,2,20,73,1,0,0,0,23,10,0,15,2,21,10,4,14,2,56,15,33,4,27,5,31,11,0,1,7,1,39,10,0,15,4,11,2,56,16,56,17,1,10,0,15,3,10,1,18,6,56,18,1,10,0,46,56,1,10,1,10,4,57,2,56,19,11,3,11,1,11,4,11,0,46,56,1,56,20,2,11,1,0,0,65,76,10,0,46,56,1,10,1,16,0,20,33,4,9,5,17,11,0,1,11,4,1,11,1,1,7,0,39,10,0,10,2,12,5,46,11,5,56,9,4,25,5,33,11,0,1,11,4,1,11,1,1,7,11,39,10,0,10,2,12,6,46,11,6,17,18,32,4,42,5,50,11,0,1,11,4,1,11,1,1,7,6,39,11,4,17,58,12,11,11,0,15,3,10,2,8,18,5,10,3,56,10,11,11,12,7,11,2,12,8,11,1,16,0,20,12,9,11,3,12,10,11,7,11,9,11,8,11,10,57,3,2,12,1,0,0,66,50,11,1,58,3,12,6,12,4,12,5,12,3,14,2,56,15,12,7,10,7,11,6,38,4,14,5,18,11,0,1,7,1,39,10,0,46,56,1,11,5,33,4,25,5,29,11,0,1,7,5,39,10,0,15,3,10,4,8,18,5,56,13,1,10,0,15,3,10,4,9,18,5,11,7,56,10,11,3,17,56,11,0,11,4,11,2,56,21,2,13,1,0,0,67,27,11,1,58,3,1,12,3,12,4,12,2,10,0,46,56,1,11,4,33,4,13,5,17,11,0,1,7,5,39,11,0,15,3,11,3,8,18,5,56,13,1,11,2,17,56,2,14,1,0,0,68,49,10,0,46,56,1,11,1,16,0,20,33,4,9,5,15,11,0,1,11,3,1,7,0,39,14,2,56,22,4,37,11,2,56,23,12,6,10,6,10,0,16,4,56,24,37,4,28,5,34,11,0,1,11,3,1,7,2,39,11,6,12,4,5,41,10,0,16,4,56,24,12,4,11,4,12,5,11,0,15,4,11,5,11,3,56,25,2,15,1,0,0,5,6,11,0,16,3,11,1,18,4,56,26,2,16,1,0,0,5,6,11,0,16,3,11,1,18,4,56,27,2,17,1,0,0,5,6,11,0,16,3,11,1,18,6,56,28,2,18,1,0,0,21,18,10,0,16,3,10,1,9,18,5,56,29,4,12,11,0,1,8,12,2,5,16,11,0,11,1,17,19,12,2,11,2,2,19,1,0,0,5,7,11,0,16,3,11,1,8,18,5,56,29,2,20,1,0,0,5,8,11,0,46,56,1,11,1,16,0,20,33,2,21,1,0,0,5,16,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,0,15,3,2,22,1,0,0,5,18,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,2,11,0,15,5,21,2,23,1,0,0,5,12,10,0,16,5,20,4,5,5,9,11,0,1,7,7,39,11,0,16,3,2,24,1,0,0,5,12,10,0,16,5,20,4,5,5,9,11,0,1,7,7,39,11,0,15,3,2,25,1,0,0,5,4,11,0,16,1,20,2,26,1,0,0,5,4,11,0,16,2,20,2,27,1,0,0,5,4,11,0,16,4,56,24,2,28,1,0,0,5,16,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,0,15,4,2,29,1,0,0,5,27,10,0,56,1,11,1,16,0,20,33,4,8,5,12,11,0,1,7,0,39,10,0,10,2,17,15,4,17,5,21,11,0,1,7,11,39,11,0,16,3,11,2,18,4,56,30,2,30,1,0,0,56,44,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,15,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,18,32,4,34,5,38,11,0,1,7,9,39,11,0,15,3,11,2,18,4,56,31,2,31,1,0,0,56,49,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,15,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,18,32,4,34,5,38,11,0,1,7,9,39,10,0,15,3,10,2,18,4,56,8,11,0,46,56,1,11,2,18,3,2,32,1,0,0,56,32,11,2,19,3,12,3,12,4,10,0,46,56,1,11,4,33,4,11,5,15,11,0,1,7,5,39,14,1,56,3,10,3,33,4,21,5,25,11,0,1,7,10,39,11,0,15,3,11,3,18,4,11,1,56,4,2,33,1,0,0,5,4,11,0,55,0,20,2,34,1,0,0,5,4,11,0,55,1,20,2,35,1,0,0,5,4,11,0,55,2,20,2,1,1,0,2,0,3,0,0,0,1,0,4,2,1,2,2,2,3,6,10,7,10,8,10,0],"linked_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,30,3,40,212,1,4,252,1,28,5,152,2,188,1,7,212,3,205,2,8,161,6,64,6,225,6,20,10,245,6,38,11,155,7,4,12,159,7,151,5,13,182,12,14,14,196,12,14,0,24,1,29,0,14,0,28,0,40,0,0,12,2,7,0,4,1,0,1,4,2,7,0,4,0,1,2,7,1,0,0,3,4,4,0,4,3,2,0,0,25,0,1,2,7,4,0,17,2,3,2,7,4,0,6,2,3,2,7,4,0,34,4,5,2,7,4,0,33,4,5,2,7,4,0,7,6,7,2,7,4,0,8,8,9,2,7,4,0,32,6,3,2,7,4,0,26,6,3,2,7,4,0,35,8,10,2,7,4,0,31,11,12,2,7,4,0,30,11,12,2,7,4,0,9,6,13,2,7,4,0,23,2,14,2,7,4,0,20,2,13,2,7,4,0,11,1,5,2,7,4,0,13,1,5,2,7,6,1,7,3,25,1,0,1,12,17,16,1,0,1,16,19,5,1,0,1,21,3,13,1,0,1,22,3,13,1,0,1,27,5,17,1,0,1,37,16,17,1,0,1,38,19,17,1,0,2,5,22,5,2,7,4,2,7,23,7,2,7,4,2,8,21,9,2,7,4,2,15,23,13,2,7,4,2,35,21,10,2,7,4,3,10,15,5,0,3,25,0,15,0,22,16,24,16,20,16,19,16,21,16,18,16,23,16,27,20,25,20,26,20,29,20,17,16,9,12,28,20,1,7,8,4,1,11,0,2,9,0,9,1,1,6,11,0,2,9,0,9,1,1,6,11,2,1,9,0,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,7,11,0,2,9,0,9,1,2,9,0,9,1,1,1,1,3,1,8,3,1,9,0,1,11,2,1,9,0,5,11,2,1,9,0,11,2,1,9,0,11,2,1,9,0,9,0,11,2,1,9,0,2,7,11,2,1,9,0,9,0,2,9,0,11,1,2,9,0,9,1,2,7,8,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,3,11,2,1,9,0,11,2,1,9,0,9,1,1,6,9,0,2,8,3,3,11,76,105,110,107,101,100,84,97,98,108,101,4,78,111,100,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,4,98,97,99,107,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,4,102,105,108,108,5,102,114,111,110,116,4,104,101,97,100,2,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,6,108,101,110,103,116,104,12,108,105,110,107,101,100,95,116,97,98,108,101,3,110,101,119,4,110,101,120,116,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,111,112,95,98,97,99,107,9,112,111,112,95,102,114,111,110,116,4,112,114,101,118,9,112,117,115,104,95,98,97,99,107,10,112,117,115,104,95,102,114,111,110,116,6,114,101,109,111,118,101,4,115,105,122,101,4,115,111,109,101,12,115,119,97,112,95,111,114,95,102,105,108,108,4,116,97,105,108,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,19,8,3,36,3,18,11,2,1,9,0,39,11,2,1,9,0,1,2,3,32,11,2,1,9,0,26,11,2,1,9,0,41,9,1,0,12,1,12,0,1,0,0,5,7,11,0,17,31,6,0,0,0,0,0,0,0,0,56,0,56,0,57,0,2,1,1,0,0,5,3,11,0,55,0,2,2,1,0,0,5,3,11,0,55,1,2,3,1,0,0,18,54,10,0,54,0,10,1,56,1,12,5,10,0,55,1,56,2,4,13,10,0,54,1,10,1,56,3,56,0,12,7,14,5,56,4,4,33,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,3,21,11,6,56,6,12,3,5,35,56,0,12,3,11,3,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,4,1,0,0,18,54,10,0,55,0,56,2,4,8,10,0,54,0,10,1,56,3,10,0,54,1,10,1,56,1,12,5,14,5,56,4,4,31,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,5,21,11,6,56,6,12,3,5,33,56,0,12,3,11,3,12,7,56,0,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,5,1,0,0,5,6,11,0,55,2,11,1,56,9,55,6,2,6,1,0,0,5,6,11,0,54,2,11,1,56,7,54,6,2,7,1,0,0,5,6,11,0,55,2,11,1,56,9,55,3,2,8,1,0,0,5,6,11,0,55,2,11,1,56,9,55,5,2,9,1,0,0,24,65,10,0,54,2,10,1,56,10,58,1,12,4,12,2,12,3,10,0,55,4,20,6,1,0,0,0,0,0,0,0,23,10,0,54,4,21,14,3,56,4,4,28,10,2,10,0,54,2,14,3,56,11,20,56,7,54,5,21,14,2,56,4,4,40,10,3,10,0,54,2,14,2,56,11,20,56,7,54,3,21,10,0,55,0,56,11,14,1,33,4,50,11,2,10,0,54,0,21,10,0,55,1,56,11,14,1,33,4,61,11,3,11,0,54,1,21,5,63,11,0,1,11,4,2,10,1,0,0,16,19,10,0,55,0,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,0,56,11,20,12,1,10,1,11,0,11,1,56,12,2,11,1,0,0,16,19,10,0,55,1,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,1,56,11,20,12,1,10,1,11,0,11,1,56,12,2,12,1,0,0,5,5,11,0,55,2,11,1,56,13,2,13,1,0,0,5,4,11,0,55,4,20,2,14,1,0,0,5,6,11,0,55,4,20,6,0,0,0,0,0,0,0,0,33,2,15,1,0,0,26,16,11,0,58,0,1,1,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,11,5,13,7,0,39,11,1,17,30,2,16,1,0,0,5,7,11,0,58,0,1,1,1,17,30,2,0,2,0,3,0,0,1,0,0,1,1,1,1,2,0,12,1,12,2,12,3,12,4,12,5,12,6,12,0],"math":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,35,5,37,18,7,55,57,8,112,32,12,144,1,249,3,0,2,0,3,0,1,0,0,4,0,1,0,0,0,0,1,0,0,5,2,1,0,0,6,1,1,0,0,7,3,3,0,0,1,0,1,0,2,3,3,1,3,2,3,2,1,4,3,4,4,4,3,15,15,15,4,100,105,102,102,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,4,109,97,116,104,3,109,97,120,3,109,105,110,3,112,111,119,4,115,113,114,116,9,115,113,114,116,95,117,49,50,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,1,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,2,1,0,0,1,15,10,0,10,1,36,4,9,11,0,11,1,23,12,2,5,13,11,1,11,0,23,12,2,11,2,2,3,1,0,0,1,33,6,1,0,0,0,0,0,0,0,12,2,10,1,49,1,38,4,31,5,7,10,1,49,2,25,49,0,33,4,22,10,0,11,0,24,12,0,11,1,49,2,26,12,1,5,30,11,2,10,0,24,12,2,11,1,49,1,23,12,1,5,2,11,2,2,4,1,0,0,4,43,50,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,12,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,53,12,3,10,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,52,2,5,1,0,0,5,43,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,77,12,3,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,53,2,6,1,0,0,1,19,10,0,10,1,25,6,0,0,0,0,0,0,0,0,33,4,11,11,0,11,1,26,12,2,5,17,11,0,11,1,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,2,0],"object":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,126,4,146,1,6,5,152,1,35,7,187,1,250,2,8,181,4,64,6,245,4,112,10,229,5,11,12,240,5,130,2,13,242,7,4,15,246,7,8,0,24,1,4,0,3,0,30,0,0,7,0,0,2,4,0,3,1,2,0,0,21,0,1,0,0,20,0,2,0,0,19,1,3,0,0,18,2,3,0,0,27,4,5,0,0,8,6,5,0,0,31,7,0,0,0,34,7,3,0,0,33,7,1,0,0,32,7,2,0,0,22,8,5,0,0,9,5,6,0,0,15,9,3,1,8,0,5,9,0,1,8,0,17,9,1,1,8,0,16,9,2,1,8,0,6,9,7,1,8,0,23,2,5,0,0,10,2,6,0,0,25,2,6,0,1,28,9,1,1,0,2,14,1,2,0,3,13,8,2,0,3,26,4,2,0,20,2,16,10,20,3,1,6,8,0,1,10,2,1,5,1,8,0,1,6,8,2,1,8,1,0,1,6,8,1,1,7,8,2,1,6,9,0,1,9,0,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,100,100,114,101,115,115,3,98,99,115,9,98,111,114,114,111,119,95,105,100,10,98,111,114,114,111,119,95,117,105,100,5,98,121,116,101,115,5,99,108,111,99,107,6,100,101,108,101,116,101,11,100,101,108,101,116,101,95,105,109,112,108,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,2,105,100,10,105,100,95,97,100,100,114,101,115,115,8,105,100,95,98,121,116,101,115,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,102,114,111,109,95,98,121,116,101,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,11,105,100,95,116,111,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,6,111,98,106,101,99,116,14,114,101,99,111,114,100,95,110,101,119,95,117,105,100,6,115,101,110,100,101,114,16,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,12,117,105,100,95,116,111,95,98,121,116,101,115,12,117,105,100,95,116,111,95,105,110,110,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,7,5,1,2,1,15,8,0,0,1,0,0,6,4,11,0,16,0,56,0,2,1,1,0,0,6,4,11,0,16,0,20,2,2,1,0,0,6,4,11,0,17,21,17,3,2,3,1,0,0,6,3,11,0,18,0,2,4,0,0,0,6,12,11,0,17,23,7,3,33,4,6,5,8,7,2,39,7,0,18,0,18,1,2,5,3,0,0,6,4,7,1,18,0,18,1,2,6,1,0,0,6,3,11,0,16,1,2,7,1,0,0,6,4,11,0,16,1,20,2,8,1,0,0,6,5,11,0,16,1,16,0,56,0,2,9,1,0,0,6,5,11,0,16,1,16,0,20,2,10,1,0,0,6,5,11,0,17,22,18,0,18,1,2,11,1,0,0,6,5,11,0,19,1,19,0,17,18,2,12,1,0,0,6,5,11,0,56,1,16,1,20,2,13,1,0,0,6,4,11,0,56,1,16,1,2,14,1,0,0,6,5,11,0,56,1,16,1,56,2,2,15,1,0,0,6,6,11,0,56,1,16,1,16,0,20,2,16,0,2,0,17,3,0,0,6,6,10,0,17,19,11,0,18,0,18,1,2,18,0,2,0,19,0,2,0,0,0,1,0,0,8,0,11,0,12,0,29,0],"object_bag":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,22,3,32,124,4,156,1,14,5,170,1,88,7,130,2,231,1,8,233,3,64,6,169,4,10,10,179,4,8,12,187,4,245,1,13,176,6,4,0,20,1,21,0,12,0,19,0,24,0,1,12,0,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,18,0,1,0,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,22,6,8,2,7,12,0,8,4,9,1,7,0,9,4,9,2,7,12,0,17,10,11,0,0,16,10,9,0,0,11,1,3,0,0,25,4,12,1,7,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,13,16,9,1,7,2,14,16,9,2,7,12,2,15,16,12,1,7,2,22,17,8,2,7,12,3,10,13,3,0,3,18,0,13,0,11,14,12,14,13,14,17,14,14,18,15,14,16,18,1,7,8,4,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,9,79,98,106,101,99,116,66,97,103,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,10,111,98,106,101,99,116,95,98,97,103,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,15,8,3,23,3,0,1,0,0,3,5,11,0,17,19,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,19,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,18,2,10,1,0,0,3,5,11,0,16,0,11,1,56,6,2,0,0,0,1,0],"object_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,26,3,36,120,4,156,1,12,5,168,1,113,7,153,2,199,1,8,224,3,64,6,160,4,10,10,170,4,8,11,178,4,2,12,180,4,230,1,13,154,6,4,14,158,6,4,0,18,1,19,0,11,0,17,0,22,0,1,12,2,7,1,12,1,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,16,0,1,2,7,12,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,20,6,8,2,7,12,0,8,4,9,2,7,12,0,15,10,11,2,7,12,0,14,10,9,2,7,12,0,10,1,3,2,7,12,0,23,4,12,2,7,12,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,12,16,9,1,7,2,13,16,12,1,7,2,20,17,8,2,7,12,3,9,13,3,0,3,16,0,13,0,10,14,11,14,12,14,15,14,13,18,14,18,1,7,8,4,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,13,8,3,21,3,0,14,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,19,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,9,1,0,0,3,5,11,0,55,0,11,1,56,5,2,0,0,0,1,0,14,1,14,0],"package":[161,28,235,11,6,0,0,0,11,1,0,14,2,14,36,3,50,183,1,4,233,1,10,5,243,1,118,7,233,2,144,5,8,249,7,64,6,185,8,93,10,150,9,48,12,198,9,129,4,13,199,13,20,0,36,1,10,1,50,0,33,0,48,0,49,0,51,0,1,12,0,0,6,12,0,0,8,0,0,0,7,0,0,1,2,7,0,2,4,7,0,3,0,7,0,3,5,4,0,5,3,2,0,0,14,0,1,1,2,0,15,0,2,1,2,0,12,1,2,0,0,22,3,4,1,0,0,21,3,4,1,0,0,39,3,5,0,0,40,3,5,0,0,52,6,7,0,0,54,6,8,0,0,53,6,9,0,0,46,10,7,0,0,47,10,9,0,0,41,11,7,0,0,42,11,7,0,0,45,10,12,0,0,17,2,9,0,0,9,2,9,0,0,19,2,9,0,0,34,13,2,0,0,35,13,2,0,0,30,14,2,0,0,11,15,16,0,0,16,17,2,0,0,43,18,2,0,2,23,24,25,0,2,24,24,25,0,2,25,2,19,1,0,3,18,23,2,0,3,26,21,7,1,8,3,27,27,7,0,3,28,31,27,0,3,32,22,23,0,4,38,28,2,1,12,5,44,26,27,0,6,29,21,4,1,2,34,20,26,20,0,20,32,1,28,14,2,9,0,7,8,8,1,8,0,0,1,6,8,0,1,1,1,6,8,4,1,6,8,1,1,8,6,1,3,1,2,1,6,8,2,1,6,8,3,1,6,10,2,1,7,8,1,1,8,1,3,7,8,1,2,10,2,1,8,2,2,7,8,1,8,3,2,7,8,1,2,1,8,5,1,9,0,1,6,9,0,1,7,8,8,1,8,7,1,6,8,5,1,8,4,1,6,8,8,1,5,2,9,0,5,2,1,8,5,2,8,6,8,6,1,6,8,6,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,15,97,100,100,105,116,105,118,101,95,112,111,108,105,99,121,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,14,98,117,114,110,95,112,117,98,108,105,115,104,101,114,3,99,97,112,5,99,108,97,105,109,14,99,108,97,105,109,95,97,110,100,95,107,101,101,112,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,17,99,111,109,112,97,116,105,98,108,101,95,112,111,108,105,99,121,6,100,101,108,101,116,101,15,100,101,112,95,111,110,108,121,95,112,111,108,105,99,121,6,100,105,103,101,115,116,11,102,114,111,109,95,109,111,100,117,108,101,12,102,114,111,109,95,112,97,99,107,97,103,101,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,14,109,97,107,101,95,105,109,109,117,116,97,98,108,101,11,109,111,100,117,108,101,95,110,97,109,101,3,110,101,119,6,111,98,106,101,99,116,22,111,110,108,121,95,97,100,100,105,116,105,118,101,95,117,112,103,114,97,100,101,115,17,111,110,108,121,95,100,101,112,95,117,112,103,114,97,100,101,115,7,112,97,99,107,97,103,101,6,112,111,108,105,99,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,16,112,117,98,108,105,115,104,101,100,95,109,111,100,117,108,101,17,112,117,98,108,105,115,104,101,100,95,112,97,99,107,97,103,101,11,114,101,99,101,105,112,116,95,99,97,112,15,114,101,99,101,105,112,116,95,112,97,99,107,97,103,101,8,114,101,115,116,114,105,99,116,6,115,101,110,100,101,114,13,116,105,99,107,101,116,95,100,105,103,101,115,116,14,116,105,99,107,101,116,95,112,97,99,107,97,103,101,13,116,105,99,107,101,116,95,112,111,108,105,99,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,5,116,121,112,101,115,15,117,112,103,114,97,100,101,95,112,97,99,107,97,103,101,14,117,112,103,114,97,100,101,95,112,111,108,105,99,121,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,2,1,0,2,1,128,2,1,192,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,26,8,7,36,8,4,31,8,4,1,2,4,26,8,7,36,8,6,54,3,37,2,2,2,4,13,8,6,36,8,6,37,2,20,10,2,3,2,2,13,8,6,36,8,6,0,1,0,0,19,18,14,0,56,0,4,4,5,8,11,1,1,7,0,39,56,1,12,2,11,1,17,31,14,2,17,24,14,2,17,25,18,0,2,1,1,0,0,2,8,11,0,10,1,56,2,11,1,46,17,33,56,3,2,2,1,0,0,2,6,11,0,19,0,1,1,17,27,2,3,1,0,0,19,9,56,1,12,1,14,1,17,24,11,0,16,0,20,33,2,4,1,0,0,29,23,56,1,12,2,14,2,17,24,10,0,16,0,20,33,4,17,14,2,17,25,11,0,16,1,20,33,12,1,5,21,11,0,1,9,12,1,11,1,2,5,1,0,0,2,3,11,0,16,1,2,6,1,0,0,2,3,11,0,16,0,2,7,1,0,0,2,4,11,0,16,2,20,2,8,1,0,0,2,4,11,0,16,3,20,2,9,1,0,0,2,4,11,0,16,4,20,2,10,1,0,0,2,4,11,0,16,5,20,2,11,1,0,0,2,4,11,0,16,6,20,2,12,1,0,0,2,4,11,0,16,7,20,2,13,1,0,0,2,4,11,0,16,8,20,2,14,1,0,0,2,3,11,0,16,9,2,15,1,0,0,2,2,7,5,2,16,1,0,0,2,2,7,6,2,17,1,0,0,2,2,7,7,2,18,1,4,0,2,4,11,0,7,6,17,23,2,19,1,4,0,2,4,11,0,7,7,17,23,2,20,1,4,0,2,7,11,0,19,1,1,1,1,17,27,2,21,1,0,0,30,41,7,8,17,29,12,3,10,0,16,2,20,10,3,34,4,10,5,14,11,0,1,7,2,39,10,1,10,0,16,4,20,38,4,21,5,25,11,0,1,7,1,39,10,0,16,2,20,12,4,11,3,10,0,15,2,21,11,0,46,56,4,11,4,11,1,11,2,18,2,2,22,1,0,0,30,39,11,1,19,3,12,3,12,2,10,0,46,56,4,11,2,33,4,11,5,15,11,0,1,7,4,39,10,0,16,2,17,30,7,8,33,4,22,5,26,11,0,1,7,3,39,11,3,10,0,15,2,21,10,0,16,3,20,6,1,0,0,0,0,0,0,0,22,11,0,15,3,21,2,23,0,0,0,2,16,10,0,16,4,20,10,1,37,4,7,5,11,11,0,1,7,1,39,11,1,11,0,15,4,21,2,0,1,0,2,1,1,1,2,1,3,2,1,2,2,3,0,3,1,2,3,0],"pay":[161,28,235,11,6,0,0,0,9,1,0,8,2,8,10,3,18,77,4,95,14,5,109,126,7,235,1,173,1,8,152,3,32,6,184,3,10,12,194,3,214,2,0,9,0,2,0,15,0,16,1,0,12,1,0,1,3,1,2,0,0,8,0,1,1,0,0,12,2,1,1,0,0,14,3,1,1,0,0,13,4,1,1,0,0,3,2,1,1,0,0,5,5,1,1,0,0,6,6,1,1,0,0,7,7,1,1,0,1,4,2,16,1,0,1,5,5,1,1,0,1,12,2,10,1,0,2,10,11,1,1,12,3,11,8,9,0,11,10,10,12,0,12,1,12,8,12,9,12,6,12,2,11,0,1,9,0,6,8,1,0,3,7,11,0,1,9,0,3,7,8,1,3,7,11,0,1,9,0,10,3,7,8,1,4,7,11,0,1,9,0,3,5,7,8,1,2,7,11,0,1,9,0,11,0,1,9,0,2,7,11,0,1,9,0,10,11,0,1,9,0,2,10,11,0,1,9,0,5,1,6,8,1,1,5,1,11,0,1,9,0,2,9,0,5,1,9,0,2,3,3,1,3,3,3,3,10,11,0,1,9,0,1,10,11,0,1,9,0,3,11,0,1,9,0,3,3,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,15,100,105,118,105,100,101,95,97,110,100,95,107,101,101,112,13,100,105,118,105,100,101,95,105,110,116,111,95,110,4,106,111,105,110,8,106,111,105,110,95,118,101,99,21,106,111,105,110,95,118,101,99,95,97,110,100,95,116,114,97,110,115,102,101,114,4,107,101,101,112,3,112,97,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,18,115,112,108,105,116,95,97,110,100,95,116,114,97,110,115,102,101,114,9,115,112,108,105,116,95,118,101,99,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,5,11,0,11,1,17,12,56,0,2,1,1,4,0,1,8,11,0,11,1,10,2,56,1,11,2,46,56,2,2,2,1,4,0,13,27,6,0,0,0,0,0,0,0,0,14,1,65,14,12,4,12,3,10,3,10,4,35,4,22,5,10,10,0,14,1,10,3,66,14,20,10,2,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,2,1,2,3,1,4,0,1,7,11,0,11,1,11,3,56,1,11,2,56,0,2,4,1,4,0,15,31,11,0,11,1,10,2,56,4,12,5,6,0,0,0,0,0,0,0,0,14,5,65,10,12,4,12,3,10,3,10,4,35,4,26,5,15,13,5,69,10,10,2,46,17,12,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,10,11,2,1,11,5,70,10,0,0,0,0,0,0,0,0,2,5,1,4,0,1,4,11,0,11,1,56,5,2,6,1,4,0,17,26,6,0,0,0,0,0,0,0,0,14,1,65,10,12,4,12,3,10,3,10,4,35,4,21,5,10,13,1,69,10,12,2,10,0,11,2,56,5,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,7,1,4,0,10,18,14,0,65,10,6,0,0,0,0,0,0,0,0,36,4,6,5,8,7,0,39,13,0,69,10,12,2,13,2,11,0,56,6,11,2,11,1,56,0,2,0],"priority_queue":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,12,3,16,60,4,76,10,5,86,167,1,7,253,1,184,1,8,181,3,64,6,245,3,14,10,131,4,18,11,149,4,4,12,153,4,243,5,13,140,10,4,14,144,10,4,0,11,1,16,0,1,6,1,2,0,0,0,6,1,2,0,0,6,0,1,1,2,0,8,2,3,1,2,0,4,4,5,1,2,0,7,3,6,1,2,0,2,7,0,1,2,0,13,8,5,1,2,0,5,9,5,1,2,0,9,10,11,1,2,1,12,15,13,1,0,1,14,15,13,1,0,6,13,9,6,5,13,8,16,8,13,1,10,11,1,1,9,0,1,11,0,1,9,0,1,7,11,0,1,9,0,2,3,9,0,3,7,11,0,1,9,0,3,9,0,0,1,11,1,1,9,0,2,10,3,10,9,0,2,7,10,11,1,1,9,0,3,3,7,10,11,1,1,9,0,3,3,1,6,11,0,1,9,0,1,10,3,2,3,3,1,9,0,3,3,3,9,0,2,7,10,9,0,3,1,3,5,3,3,3,10,11,1,1,9,0,9,0,5,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,13,7,10,11,1,1,9,0,1,3,7,10,11,1,1,9,0,3,1,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,3,3,2,3,10,3,5,69,110,116,114,121,13,80,114,105,111,114,105,116,121,81,117,101,117,101,14,99,114,101,97,116,101,95,101,110,116,114,105,101,115,7,101,110,116,114,105,101,115,6,105,110,115,101,114,116,21,109,97,120,95,104,101,97,112,105,102,121,95,114,101,99,117,114,115,105,118,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,7,112,111,112,95,109,97,120,10,112,114,105,111,114,105,116,105,101,115,8,112,114,105,111,114,105,116,121,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,6,114,101,109,111,118,101,22,114,101,115,116,111,114,101,95,104,101,97,112,95,114,101,99,117,114,115,105,118,101,11,115,119,97,112,95,114,101,109,111,118,101,5,118,97,108,117,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,10,3,1,0,0,2,1,3,10,11,1,1,9,0,1,2,2,10,3,15,9,0,0,13,1,13,0,1,0,0,12,24,14,0,65,6,12,2,10,2,6,2,0,0,0,0,0,0,0,26,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,21,5,12,11,1,6,1,0,0,0,0,0,0,0,23,12,1,13,0,10,2,10,1,56,0,5,7,11,0,57,0,2,1,1,0,0,14,30,10,0,55,0,65,6,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,10,0,54,0,6,0,0,0,0,0,0,0,0,56,1,58,1,12,3,12,2,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,6,0,0,0,0,0,0,0,0,56,0,11,2,11,3,2,2,1,0,0,16,17,10,0,54,0,11,1,11,2,57,1,68,6,10,0,55,0,65,6,6,1,0,0,0,0,0,0,0,23,12,3,11,0,54,0,11,3,56,2,2,3,1,0,0,5,4,11,0,11,1,57,1,2,4,1,0,0,17,40,14,0,65,16,12,3,14,1,65,13,10,3,33,4,9,5,11,6,0,0,0,0,0,0,0,0,39,64,6,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,38,5,20,13,0,6,0,0,0,0,0,0,0,0,56,3,12,4,13,1,6,0,0,0,0,0,0,0,0,56,4,12,6,13,5,11,4,11,6,57,1,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,5,2,5,0,0,0,18,46,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,1,6,1,0,0,0,0,0,0,0,23,6,2,0,0,0,0,0,0,0,26,12,6,10,0,10,1,12,3,12,2,10,0,10,6,12,5,12,4,11,2,46,11,3,66,6,55,1,20,11,4,46,11,5,66,6,55,1,20,36,4,43,10,0,11,1,10,6,71,6,11,0,11,6,56,2,5,45,11,0,1,2,6,0,0,0,19,110,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,2,10,1,35,4,12,5,16,11,0,1,6,1,0,0,0,0,0,0,0,39,10,2,6,2,0,0,0,0,0,0,0,24,6,1,0,0,0,0,0,0,0,22,12,13,10,13,6,1,0,0,0,0,0,0,0,22,12,15,10,2,12,14,10,13,10,1,35,4,55,10,0,10,13,12,5,12,3,10,0,10,14,12,7,12,6,11,3,46,11,5,66,6,55,1,20,11,6,46,11,7,66,6,55,1,20,36,12,8,5,57,9,12,8,11,8,4,61,11,13,12,14,10,15,10,1,35,4,88,10,0,10,15,12,10,12,9,10,0,10,14,12,12,12,11,11,9,46,11,10,66,6,55,1,20,11,11,46,11,12,66,6,55,1,20,36,12,4,5,90,9,12,4,11,4,4,94,11,15,12,14,10,14,10,2,34,4,107,10,0,10,14,11,2,71,6,11,0,11,1,11,14,56,0,5,109,11,0,1,2,7,1,0,0,20,28,7,1,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,0,55,0,65,6,35,4,24,5,11,13,2,10,0,55,0,10,1,66,6,55,1,20,68,16,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,4,11,0,1,11,2,2,0,0,1,0,0,13,1,13,0],"prover":[161,28,235,11,6,0,0,0,4,1,0,2,7,2,7,8,9,32,6,41,30,0,0,6,112,114,111,118,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0],"iota":[161,28,235,11,6,0,0,0,10,1,0,14,2,14,48,3,62,62,4,124,14,5,138,1,133,1,7,143,2,129,2,8,144,4,64,6,208,4,102,10,182,5,5,12,187,5,109,0,22,1,18,0,9,0,10,0,23,0,25,0,26,0,4,2,0,1,3,7,1,0,0,2,0,4,1,0,1,2,5,4,1,0,1,3,1,12,1,0,1,3,2,12,1,0,1,3,6,12,1,0,1,5,7,2,0,6,8,7,0,0,16,0,1,0,0,23,2,3,0,1,17,3,9,1,0,2,12,16,7,1,0,2,15,17,18,1,0,3,11,11,12,1,2,3,24,15,16,1,0,4,19,14,3,1,12,4,20,20,3,1,12,5,14,5,7,0,5,21,5,6,0,2,8,5,10,7,13,6,10,4,10,3,10,8,19,1,7,8,7,1,11,2,1,8,0,2,11,4,1,8,0,5,0,4,11,5,1,8,0,11,3,1,8,0,11,2,1,8,0,11,6,1,8,0,1,6,8,7,1,5,1,3,1,8,8,1,11,1,1,9,0,1,8,0,7,9,0,2,10,2,10,2,10,2,11,1,1,8,8,7,8,7,2,11,6,1,9,0,11,5,1,9,0,1,11,5,1,8,0,1,9,0,1,11,6,1,9,0,1,11,3,1,9,0,2,7,11,3,1,9,0,3,1,11,2,1,9,0,1,11,4,1,8,0,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,114,108,7,98,97,108,97,110,99,101,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,11,100,117,109,109,121,95,102,105,101,108,100,5,101,112,111,99,104,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,3,115,117,105,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,228,11,84,2,0,0,0,3,8,0,0,232,137,4,35,199,138,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,2,4,3,83,85,73,10,2,4,3,83,117,105,10,2,1,0,0,2,1,13,1,0,0,0,0,4,47,10,0,46,17,10,7,5,33,4,7,5,11,11,0,1,7,1,39,10,0,46,17,9,6,0,0,0,0,0,0,0,0,33,4,18,5,22,11,0,1,7,0,39,9,18,0,49,9,7,6,7,7,7,8,56,0,11,0,56,1,12,1,12,4,11,1,56,2,11,4,56,3,12,2,13,2,7,4,56,4,12,3,11,2,56,5,1,11,3,2,1,1,4,0,3,4,11,0,11,1,56,6,2,0],"table":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,16,3,24,115,4,139,1,10,5,149,1,104,7,253,1,167,1,8,164,3,32,6,196,3,10,10,206,3,8,11,214,3,2,12,216,3,229,1,13,189,5,4,14,193,5,4,0,19,0,10,0,16,0,20,0,0,12,2,7,1,4,1,2,2,4,0,3,1,2,0,0,15,0,1,2,7,4,0,3,2,3,2,7,4,0,4,4,5,2,7,4,0,5,6,7,2,7,4,0,17,6,8,2,7,4,0,6,4,9,2,7,4,0,14,10,11,2,7,4,0,13,10,9,2,7,4,0,8,1,3,2,7,4,0,9,1,3,2,7,6,1,3,14,3,2,7,4,1,4,15,5,2,7,4,1,5,16,7,2,7,4,1,11,15,9,2,7,4,1,17,16,8,2,7,4,2,7,12,3,0,2,15,0,12,0,10,13,11,13,12,13,14,13,13,13,1,7,8,2,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,2,8,1,3,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,1,18,3,0,13,0,1,0,0,3,5,11,0,17,16,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,17,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,15,2,9,1,0,0,3,5,11,0,58,0,1,17,15,2,0,0,0,1,0,13,1,13,0],"table_vec":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,18,3,24,103,4,127,20,5,147,1,138,1,7,157,2,159,1,8,188,3,32,6,220,3,20,10,240,3,10,11,250,3,2,12,252,3,245,1,13,241,5,2,14,243,5,2,0,17,0,16,0,18,0,1,4,1,4,1,1,0,12,2,7,1,4,1,2,2,2,0,0,8,0,1,1,4,0,15,2,1,1,4,0,10,3,4,1,4,0,9,3,5,1,4,0,4,6,7,1,4,0,13,8,9,1,4,0,5,10,11,1,4,0,12,12,13,1,4,0,7,1,9,1,4,1,3,19,9,2,7,4,1,4,17,18,2,7,4,1,5,20,21,2,7,4,1,7,15,9,2,7,4,1,10,16,4,2,7,4,1,11,0,15,2,7,4,1,14,20,22,2,7,4,14,14,0,13,5,13,13,14,2,13,10,14,9,14,11,14,15,14,12,14,1,7,8,2,1,11,0,1,9,0,2,9,0,7,8,2,1,6,11,0,1,9,0,1,3,1,1,2,6,11,0,1,9,0,3,1,6,9,0,2,7,11,0,1,9,0,9,0,0,2,7,11,0,1,9,0,3,1,7,9,0,1,7,11,0,1,9,0,1,9,0,2,3,9,0,1,11,1,2,9,0,9,1,1,6,11,1,2,9,0,9,1,2,6,11,1,2,9,0,9,1,9,0,1,6,9,1,3,7,11,1,2,9,0,9,1,9,0,9,1,2,7,11,1,2,9,0,9,1,9,0,1,7,9,1,1,9,1,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,5,101,109,112,116,121,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,6,11,1,2,3,9,0,0,13,0,1,0,0,9,4,11,0,56,0,57,0,2,1,1,0,0,1,8,11,1,56,1,12,2,13,2,11,0,56,2,11,2,2,2,1,0,0,9,4,11,0,55,0,56,3,2,3,1,0,0,9,5,11,0,56,4,6,0,0,0,0,0,0,0,0,33,2,4,1,0,0,9,15,10,0,56,4,10,1,36,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,5,2,5,1,0,0,4,10,10,0,46,56,4,12,2,11,0,54,0,11,2,11,1,56,6,2,6,1,0,0,9,16,10,0,46,56,4,10,1,36,4,7,5,11,11,0,1,7,0,39,11,0,54,0,11,1,56,7,2,7,1,0,0,4,20,10,0,46,56,4,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,56,8,2,8,1,0,0,9,12,14,0,56,4,6,0,0,0,0,0,0,0,0,33,4,6,5,8,7,1,39,11,0,58,0,56,9,2,0,0,0,13,0],"transfer":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,54,4,56,6,5,62,8,7,70,144,1,8,214,1,32,6,246,1,10,12,128,2,82,0,7,0,7,0,1,1,8,0,4,0,1,1,12,0,0,2,1,1,8,0,2,2,1,1,12,0,5,2,1,1,8,0,3,2,1,1,12,0,1,2,1,1,8,0,6,2,1,1,8,0,8,0,1,1,8,8,2,6,2,7,2,2,9,0,5,0,1,9,0,13,102,114,101,101,122,101,95,111,98,106,101,99,116,18,102,114,101,101,122,101,95,111,98,106,101,99,116,95,105,109,112,108,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,17,115,104,97,114,101,95,111,98,106,101,99,116,95,105,109,112,108,8,116,114,97,110,115,102,101,114,13,116,114,97,110,115,102,101,114,95,105,109,112,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,56,0,2,1,1,0,0,1,4,11,0,11,1,56,0,2,2,1,0,0,1,3,11,0,56,1,2,3,1,0,0,1,3,11,0,56,1,2,4,1,0,0,1,3,11,0,56,2,2,5,1,0,0,1,3,11,0,56,2,2,6,3,2,0,7,3,2,0,8,3,2,0,0],"transfer_policy":[161,28,235,11,6,0,0,0,13,1,0,24,2,24,78,3,102,255,1,4,229,2,44,5,145,3,176,3,7,193,6,229,4,8,166,11,64,6,230,11,60,10,162,12,55,11,217,12,10,12,227,12,252,4,13,223,17,16,14,239,17,16,0,59,1,47,1,61,0,19,0,21,0,28,0,31,0,46,0,48,0,57,0,60,0,66,0,10,0,1,0,1,0,7,12,1,0,1,0,8,12,1,0,1,0,9,3,1,0,1,0,5,7,1,2,1,1,3,7,1,0,0,2,12,7,0,3,0,4,1,0,1,4,1,12,1,0,1,7,2,7,0,7,13,4,0,8,4,12,0,9,6,2,0,10,11,2,0,11,14,7,1,3,0,0,45,0,1,1,0,0,44,2,3,1,0,0,67,4,5,1,0,0,25,6,5,1,0,0,22,7,0,1,0,0,17,8,9,3,0,2,6,0,37,10,11,3,0,2,6,0,18,12,9,2,0,2,0,16,13,9,2,0,2,0,38,14,15,2,0,2,0,54,16,9,3,0,2,6,0,62,14,17,1,0,0,63,16,18,1,0,0,55,14,19,1,0,0,43,20,21,1,0,0,49,20,22,1,0,0,33,20,21,1,0,1,26,37,25,1,0,1,42,36,15,1,0,2,36,9,23,1,0,3,65,38,22,1,0,3,68,9,32,1,0,4,34,42,40,1,0,4,51,54,9,1,0,4,58,39,40,1,0,5,15,50,9,2,7,4,5,20,52,53,2,7,4,5,32,52,15,1,7,5,53,57,48,2,7,4,6,29,25,9,1,3,7,24,29,9,0,7,39,35,21,1,8,7,44,28,29,0,7,64,17,21,0,8,35,27,15,1,0,11,23,46,15,1,3,11,30,9,24,1,3,11,40,51,9,1,3,11,41,24,44,1,3,11,53,58,9,1,3,11,56,45,22,1,3,36,23,34,25,29,30,21,31,31,34,18,22,17,22,20,31,24,31,22,31,38,23,40,23,35,23,9,47,25,49,19,48,37,23,26,49,23,31,27,55,28,49,39,23,3,8,9,3,8,9,1,11,0,1,9,0,2,6,8,11,7,8,13,2,11,1,1,9,0,11,2,1,9,0,4,7,11,1,1,9,0,6,11,2,1,9,0,11,5,1,3,7,8,13,1,11,8,1,8,12,3,11,1,1,9,0,11,2,1,9,0,7,8,13,2,6,11,1,1,9,0,11,0,1,9,0,4,9,1,7,11,1,1,9,0,6,11,2,1,9,0,9,2,0,2,9,1,6,11,1,1,9,0,1,6,9,2,3,9,1,7,11,1,1,9,0,11,8,1,8,12,2,9,1,7,11,0,1,9,0,1,6,11,1,1,9,0,1,1,2,7,11,1,1,9,0,6,11,2,1,9,0,1,6,8,10,1,7,8,10,1,6,11,14,1,8,6,1,6,11,0,1,9,0,1,8,9,1,3,1,8,6,1,11,14,1,9,0,1,9,0,5,8,10,11,14,1,8,6,11,7,1,8,12,8,10,8,9,1,6,8,11,1,7,8,13,1,8,10,1,11,3,1,9,0,1,8,12,1,11,7,1,9,0,3,3,3,3,1,11,1,1,9,0,1,6,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,1,6,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,13,1,11,8,1,9,0,2,11,7,1,8,12,8,10,2,11,7,1,9,0,7,8,13,7,10,8,6,8,9,8,9,3,11,14,1,8,6,8,6,3,1,10,9,0,1,6,11,14,1,9,0,2,6,11,14,1,9,0,6,9,0,2,9,0,9,1,1,9,1,2,11,4,1,9,1,9,2,3,7,8,10,9,0,9,1,2,7,11,14,1,9,0,9,0,2,6,8,10,9,0,1,6,9,1,2,7,11,7,1,9,0,11,8,1,9,0,1,11,4,1,9,1,2,8,6,7,11,14,1,8,6,2,7,8,10,9,0,2,7,11,14,1,9,0,6,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,9,80,117,98,108,105,115,104,101,114,7,82,117,108,101,75,101,121,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,17,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,97,112,21,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,114,101,97,116,101,100,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,86,101,99,83,101,116,3,97,100,100,11,97,100,100,95,114,101,99,101,105,112,116,8,97,100,100,95,114,117,108,101,14,97,100,100,95,116,111,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,4,99,111,105,110,15,99,111,110,102,105,114,109,95,114,101,113,117,101,115,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,20,100,101,115,116,114,111,121,95,97,110,100,95,119,105,116,104,100,114,97,119,12,100,101,115,116,114,111,121,95,115,111,109,101,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,7,101,120,105,115,116,115,95,4,102,114,111,109,12,102,114,111,109,95,98,97,108,97,110,99,101,12,102,114,111,109,95,112,97,99,107,97,103,101,3,103,101,116,8,103,101,116,95,114,117,108,101,8,104,97,115,95,114,117,108,101,2,105,100,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,7,105,115,95,115,111,109,101,4,105,116,101,109,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,4,112,97,105,100,9,112,111,108,105,99,121,95,105,100,3,112,117,116,8,114,101,99,101,105,112,116,115,6,114,101,109,111,118,101,11,114,101,109,111,118,101,95,114,117,108,101,5,114,117,108,101,115,4,115,105,122,101,3,115,117,105,4,116,97,107,101,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,3,117,105,100,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,7,118,101,99,95,115,101,116,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,4,43,8,9,49,3,33,8,9,52,11,14,1,8,6,1,2,3,39,8,10,19,11,7,1,8,12,55,11,14,1,8,6,2,2,2,39,8,10,50,8,9,3,2,1,39,8,9,4,2,1,27,1,0,25,3,25,1,25,2,25,4,48,0,1,0,0,9,6,11,0,11,1,11,2,56,0,57,0,2,1,1,0,0,26,32,11,0,56,1,4,4,5,8,11,1,1,6,0,0,0,0,0,0,0,0,39,10,1,17,32,12,5,14,5,17,33,12,6,10,6,57,1,56,2,11,5,12,2,56,0,12,3,56,3,12,4,11,2,11,4,11,3,57,2,11,1,17,32,11,6,57,3,2,2,1,0,0,33,49,10,0,46,56,4,11,1,55,0,20,33,4,9,5,15,11,0,1,11,3,1,7,4,39,14,2,56,5,4,37,11,2,56,6,12,6,10,6,10,0,55,1,56,7,37,4,28,5,34,11,0,1,11,3,1,7,5,39,11,6,12,4,5,41,10,0,55,1,56,7,12,4,11,4,12,5,11,0,54,1,11,5,11,3,56,8,2,3,1,0,0,41,27,14,0,56,4,14,1,55,0,20,33,4,8,5,12,11,2,1,7,4,39,11,1,58,3,1,12,4,11,0,58,2,1,12,3,17,30,11,4,17,30,11,3,11,2,56,9,2,4,1,0,0,43,52,11,1,58,0,12,6,12,3,12,5,12,4,11,6,56,10,12,2,14,2,65,23,12,8,10,8,10,0,55,2,56,11,33,4,19,5,23,11,0,1,7,0,39,10,8,6,0,0,0,0,0,0,0,0,36,4,46,5,28,13,2,69,23,12,7,10,0,55,2,14,7,56,12,4,37,5,41,11,0,1,7,1,39,11,8,6,1,0,0,0,0,0,0,0,23,12,8,5,23,11,0,1,11,4,11,5,11,3,2,5,1,0,0,9,34,10,1,46,56,4,11,2,55,0,20,33,4,9,5,13,11,1,1,7,4,39,10,1,46,56,13,32,4,19,5,23,11,1,1,7,3,39,10,1,54,3,9,57,4,11,3,56,14,11,1,54,2,56,15,56,16,2,6,1,0,0,9,6,11,1,55,3,9,57,4,56,17,2,7,1,0,0,9,14,10,1,46,56,13,4,5,5,9,11,1,1,7,2,39,11,1,54,1,11,2,56,18,2,8,1,0,0,9,5,11,1,54,4,56,15,56,16,2,9,1,0,0,9,6,11,0,55,3,9,57,4,56,19,2,10,1,0,0,56,28,10,0,46,56,4,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,10,0,54,3,9,57,4,56,20,1,11,0,54,2,12,3,56,15,12,2,11,3,14,2,56,21,2,11,1,0,0,9,3,11,0,55,3,2,12,1,0,0,9,16,10,0,46,56,4,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,11,0,54,3,2,13,1,0,0,9,3,11,0,55,2,2,14,1,0,0,9,4,11,0,55,5,20,2,15,1,0,0,9,4,11,0,55,6,20,2,16,1,0,0,9,4,11,0,55,7,20,2,2,1,1,1,1,2,1,0,0,3,0,0,0,1,0,2,0,25,1,25,2,25,3,25,4,25,5,25,6,25,7,25,0],"tx_context":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,24,7,65,111,8,176,1,32,6,208,1,20,10,228,1,14,12,242,1,107,13,221,2,10,0,8,0,0,2,0,0,7,0,1,0,0,2,0,2,0,0,3,0,3,0,0,4,0,3,0,0,5,4,1,0,0,6,0,3,0,0,1,5,1,0,1,6,8,0,1,5,1,6,10,2,1,3,1,7,8,0,2,10,2,3,0,2,5,3,9,84,120,67,111,110,116,101,120,116,9,100,101,114,105,118,101,95,105,100,6,100,105,103,101,115,116,5,101,112,111,99,104,18,101,112,111,99,104,95,116,105,109,101,115,116,97,109,112,95,109,115,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,11,105,100,115,95,99,114,101,97,116,101,100,6,115,101,110,100,101,114,10,116,120,95,99,111,110,116,101,120,116,7,116,120,95,104,97,115,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,32,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,5,7,5,9,10,2,3,3,4,3,6,3,0,1,0,0,6,4,11,0,16,0,20,2,1,1,0,0,6,3,11,0,16,1,2,2,1,0,0,6,4,11,0,16,2,20,2,3,1,0,0,6,4,11,0,16,3,20,2,4,1,0,0,7,18,10,0,16,4,20,12,2,10,0,16,1,20,10,2,17,6,12,1,11,2,6,1,0,0,0,0,0,0,0,22,11,0,15,4,21,11,1,2,5,0,0,0,6,4,11,0,16,4,20,2,6,0,2,0,0,0,0,1,0,2,0,3,0,4,0],"types":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,6,7,14,26,8,40,32,12,72,4,0,1,0,0,0,1,1,2,1,6,9,0,1,1,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,5,116,121,112,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"url":[161,28,235,11,6,0,0,0,9,1,0,4,2,4,8,3,12,25,5,37,20,7,57,78,8,135,1,64,10,199,1,6,12,205,1,50,13,255,1,2,0,8,1,2,0,1,7,0,1,0,7,0,0,4,0,1,0,0,5,2,1,0,0,3,3,0,0,0,7,4,5,0,1,6,2,0,0,1,8,1,1,8,0,1,10,2,1,6,8,0,2,7,8,0,8,1,0,6,83,116,114,105,110,103,3,85,114,108,5,97,115,99,105,105,9,105,110,110,101,114,95,117,114,108,10,110,101,119,95,117,110,115,97,102,101,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,6,115,116,114,105,110,103,6,117,112,100,97,116,101,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,8,8,1,0,1,0,0,5,3,11,0,18,0,2,1,1,0,0,5,4,11,0,17,4,18,0,2,2,1,0,0,5,4,11,0,16,0,20,2,3,1,0,0,5,5,11,1,11,0,15,0,21,2,0,0,0],"vec_map":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,22,3,28,168,1,4,196,1,28,5,224,1,254,1,7,222,3,153,2,8,247,5,64,6,183,6,50,10,233,6,21,11,254,6,4,12,130,7,235,5,13,237,12,6,14,243,12,6,0,30,1,21,1,31,0,2,7,2,1,0,0,0,0,0,7,2,1,0,0,0,1,1,7,1,0,0,0,7,0,1,2,1,0,0,14,2,0,2,1,0,0,23,3,4,2,1,0,0,22,5,4,2,1,0,0,13,3,6,2,1,0,0,8,7,8,2,1,0,0,28,7,9,2,1,1,0,3,7,10,2,1,0,0,26,11,12,2,1,0,0,16,11,10,2,1,0,0,5,1,0,2,1,0,0,15,1,13,2,1,0,0,19,11,14,2,1,0,0,12,7,15,2,1,0,0,11,7,12,2,1,0,0,9,16,17,2,1,0,0,10,18,19,2,1,0,0,24,18,4,2,1,0,1,6,27,24,1,0,1,17,28,10,1,0,1,20,0,27,1,0,1,27,24,27,1,0,2,16,25,10,1,0,2,23,23,24,1,0,2,25,31,0,1,0,7,4,14,4,23,20,22,20,5,4,21,26,20,26,13,4,19,12,8,4,24,20,21,12,20,12,18,12,0,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,2,7,11,0,2,9,0,9,1,6,9,0,2,9,0,9,1,1,7,11,0,2,9,0,9,1,1,7,9,1,2,6,11,0,2,9,0,9,1,6,9,0,1,6,9,1,1,11,2,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,2,10,9,0,10,9,1,1,10,9,0,1,11,2,1,3,2,6,11,0,2,9,0,9,1,3,2,6,9,0,6,9,1,2,7,11,0,2,9,0,9,1,3,2,6,9,0,7,9,1,1,11,1,2,9,0,9,1,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,9,0,1,6,10,9,0,1,9,1,1,11,2,1,9,0,1,6,11,2,1,9,0,1,10,11,1,2,9,0,9,1,7,10,11,1,2,9,0,9,1,3,9,0,10,9,0,3,9,1,10,9,1,1,7,10,9,0,4,6,11,1,2,9,0,9,1,3,10,9,0,3,2,3,3,1,6,11,1,2,9,0,9,1,1,7,11,1,2,9,0,9,1,5,69,110,116,114,121,6,79,112,116,105,111,110,6,86,101,99,77,97,112,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,3,103,101,116,16,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,20,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,95,109,117,116,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,7,103,101,116,95,109,117,116,6,105,110,115,101,114,116,16,105,110,116,111,95,107,101,121,115,95,118,97,108,117,101,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,3,107,101,121,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,3,112,111,112,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,101,110,116,114,121,95,98,121,95,105,100,120,7,114,101,118,101,114,115,101,4,115,105,122,101,4,115,111,109,101,7,116,114,121,95,103,101,116,5,118,97,108,117,101,7,118,101,99,95,109,97,112,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,1,4,10,11,1,2,9,0,9,1,1,2,2,18,9,0,29,9,1,0,4,1,4,0,1,0,0,0,3,64,20,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,21,20,10,0,14,1,12,3,46,11,3,56,0,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,11,2,57,1,68,20,2,2,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,56,2,58,1,2,3,1,0,0,0,15,10,0,55,0,56,3,32,4,6,5,10,11,0,1,7,4,39,11,0,54,0,69,20,58,1,2,4,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,67,20,54,1,2,5,1,0,0,12,10,10,0,11,1,56,1,12,2,11,0,55,0,11,2,66,20,55,1,2,6,1,0,0,9,19,10,0,10,1,56,0,4,11,11,0,11,1,56,4,20,56,5,12,2,5,17,11,0,1,11,1,1,56,6,12,2,11,2,2,7,1,0,0,15,7,11,0,11,1,56,7,12,2,14,2,56,8,2,8,1,0,0,0,4,11,0,55,0,65,20,2,9,1,0,0,0,5,11,0,56,9,6,0,0,0,0,0,0,0,0,33,2,10,1,0,0,29,12,11,0,58,0,12,1,14,1,56,3,4,7,5,9,7,2,39,11,1,70,20,0,0,0,0,0,0,0,0,2,11,1,0,0,30,40,11,0,58,0,12,1,13,1,56,10,6,0,0,0,0,0,0,0,0,12,2,14,1,65,20,12,5,64,24,0,0,0,0,0,0,0,0,12,4,64,26,0,0,0,0,0,0,0,0,12,7,10,2,10,5,35,4,35,5,19,13,1,69,20,58,1,12,6,12,3,13,4,11,3,68,24,13,7,11,6,68,26,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,14,11,1,70,20,0,0,0,0,0,0,0,0,11,4,11,7,2,12,1,0,0,32,32,6,0,0,0,0,0,0,0,0,12,2,10,0,55,0,65,20,12,4,64,24,0,0,0,0,0,0,0,0,12,3,10,2,10,4,35,4,28,5,13,10,0,55,0,10,2,66,20,12,1,13,3,11,1,55,2,20,68,24,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,8,11,0,1,11,3,2,13,1,0,0,33,36,6,0,0,0,0,0,0,0,0,12,2,10,0,56,9,12,3,10,2,10,3,35,4,30,5,10,10,0,55,0,10,2,66,20,55,2,10,1,33,4,25,11,0,1,11,1,1,11,2,56,11,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,12,2,14,1,0,0,15,13,11,0,11,1,56,7,12,2,14,2,56,8,4,8,5,10,7,1,39,11,2,56,13,2,15,1,0,0,34,20,10,1,10,0,56,9,35,4,6,5,10,11,0,1,7,3,39,11,0,55,0,11,1,66,20,12,2,10,2,55,2,11,2,55,1,2,16,1,0,0,35,21,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,67,20,12,2,10,2,55,2,11,2,54,1,2,17,1,0,0,0,17,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,56,2,58,1,2,0,0,1,1,1,0,0,4,1,4,2,4,0],"vec_set":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,12,3,18,102,4,120,20,5,140,1,95,7,235,1,164,1,8,143,3,64,6,207,3,20,10,227,3,7,11,234,3,2,12,236,3,156,2,13,136,6,2,14,138,6,2,0,19,1,14,1,20,0,1,7,1,3,0,1,0,7,1,0,0,0,5,0,1,1,3,0,16,2,1,1,3,0,8,3,0,1,3,0,15,4,0,1,3,0,2,5,6,1,3,0,17,7,8,1,3,0,10,7,6,1,3,0,9,1,9,1,3,0,12,7,10,1,3,0,7,5,11,1,3,0,6,5,8,1,3,1,4,17,2,1,0,1,11,15,6,1,0,1,13,0,17,1,0,1,18,2,17,1,0,2,15,14,2,1,0,2,16,2,9,1,0,16,2,4,2,10,2,15,2,9,2,12,8,5,2,14,8,13,8,11,8,0,1,11,0,1,9,0,1,9,0,2,7,11,0,1,9,0,9,0,2,7,11,0,1,9,0,6,9,0,2,6,11,0,1,9,0,6,9,0,1,1,1,6,11,0,1,9,0,1,3,1,10,9,0,1,6,10,9,0,1,11,1,1,3,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,6,11,1,1,9,0,2,3,3,1,11,1,1,9,0,6,79,112,116,105,111,110,6,86,101,99,83,101,116,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,4,115,105,122,101,4,115,111,109,101,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,3,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,12,18,10,0,14,1,12,2,46,11,2,56,1,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,68,2,2,3,1,0,0,13,13,10,0,11,1,12,2,46,11,2,56,2,12,3,11,0,54,0,11,3,56,3,1,2,4,1,0,0,11,7,11,0,11,1,56,4,12,2,14,2,56,5,2,5,1,0,0,0,4,11,0,55,0,65,2,2,6,1,0,0,0,5,11,0,56,6,6,0,0,0,0,0,0,0,0,33,2,7,1,0,0,0,3,11,0,58,0,2,8,1,0,0,0,3,11,0,55,0,2,9,0,0,0,16,35,6,0,0,0,0,0,0,0,0,12,2,10,0,56,6,12,3,10,2,10,3,35,4,29,5,10,10,0,55,0,10,2,66,2,10,1,33,4,24,11,0,1,11,1,1,11,2,56,7,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,8,2,10,0,0,0,11,13,11,0,11,1,56,4,12,2,14,2,56,5,4,8,5,10,7,1,39,11,2,56,9,2,0,0,0,2,0],"versioned":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,20,3,28,85,4,113,10,5,123,97,7,220,1,236,1,8,200,3,32,6,232,3,10,10,242,3,16,12,130,4,197,1,13,199,5,4,0,23,0,11,0,16,0,20,0,4,12,0,0,3,0,0,2,0,7,0,2,2,4,0,3,1,2,0,0,8,0,1,1,4,0,22,2,3,0,0,13,2,4,1,4,0,14,5,6,1,4,0,19,5,7,1,4,0,21,8,9,1,4,0,10,1,10,1,4,1,5,14,9,2,7,4,1,6,15,16,2,7,4,1,7,17,18,2,7,4,1,18,17,19,2,7,4,2,9,12,9,0,2,12,4,20,1,8,2,15,11,12,0,7,13,8,13,9,13,10,13,12,1,3,3,9,0,7,8,4,1,8,0,1,6,8,0,1,3,1,6,9,0,1,7,8,0,1,7,9,0,2,9,0,8,1,4,7,8,0,3,9,0,8,1,0,1,9,0,1,7,8,4,1,8,3,2,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,8,2,3,8,3,9,0,3,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,16,86,101,114,115,105,111,110,67,104,97,110,103,101,67,97,112,9,86,101,114,115,105,111,110,101,100,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,2,105,100,10,108,111,97,100,95,118,97,108,117,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,3,110,101,119,6,111,98,106,101,99,116,11,111,108,100,95,118,101,114,115,105,111,110,6,114,101,109,111,118,101,24,114,101,109,111,118,101,95,118,97,108,117,101,95,102,111,114,95,117,112,103,114,97,100,101,10,116,120,95,99,111,110,116,101,120,116,7,117,112,103,114,97,100,101,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,12,118,101,114,115,105,111,110,101,100,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,3,22,3,1,2,2,24,8,2,17,3,0,1,0,0,1,12,11,2,17,13,10,0,18,0,12,3,13,3,15,0,11,0,11,1,56,0,11,3,2,1,1,0,0,9,4,11,0,16,1,20,2,2,1,0,0,9,7,10,0,16,0,11,0,16,1,20,56,1,2,3,1,0,0,9,7,10,0,15,0,11,0,16,1,20,56,2,2,4,1,0,0,9,14,10,0,15,0,10,0,16,1,20,56,3,10,0,46,56,4,11,0,16,1,20,18,1,2,5,1,0,0,3,32,11,3,19,1,12,4,10,0,46,56,4,33,4,9,5,13,11,0,1,7,0,39,11,4,10,1,35,4,18,5,22,11,0,1,7,0,39,10,0,15,0,10,1,11,2,56,0,11,1,11,0,15,1,21,2,6,1,0,0,21,12,11,0,19,0,12,3,12,1,13,1,11,3,56,3,12,2,11,1,17,11,11,2,2,0,0,0,1,0]},"type_origin_table":[{"module_name":"tx_context","struct_name":"TxContext","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"ID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"UID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_field","struct_name":"Field","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bag","struct_name":"Bag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Supply","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Balance","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bcs","struct_name":"BCS","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Referent","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"clock","struct_name":"Clock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"url","struct_name":"Url","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"Coin","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CoinMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"TreasuryCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CurrencyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"VecMap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"Publisher","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeTicket","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeReceipt","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"Display","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"DisplayCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"VersionUpdated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_object_field","struct_name":"Wrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"Curve","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PreparedVerifyingKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PublicProofInputs","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"ProofPoints","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_set","struct_name":"VecSet","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"iota","struct_name":"IOTA","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferRequest","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicy","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"RuleKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Kiosk","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"KioskOwnerCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"PurchaseCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Item","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Listing","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Lock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemListed","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemPurchased","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemDelisted","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"LinkedTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"Node","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_bag","struct_name":"ObjectBag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_table","struct_name":"ObjectTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"PriorityQueue","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table","struct_name":"Table","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table_vec","struct_name":"TableVec","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"Versioned","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"VersionChangeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000003","version":5,"module_map":{"genesis":[161,28,235,11,6,0,0,0,11,1,0,26,2,26,58,3,84,107,4,191,1,14,5,205,1,176,2,7,253,3,137,9,8,134,13,96,6,230,13,20,10,250,13,93,12,215,14,219,3,13,178,18,24,0,31,1,44,1,72,2,18,2,20,2,43,2,61,2,66,0,54,0,63,0,64,0,67,0,70,0,3,3,0,0,2,3,0,0,9,0,0,0,8,0,0,1,4,7,1,0,0,3,0,4,1,0,1,4,1,12,1,0,1,5,11,4,0,6,5,2,0,7,10,2,0,8,6,4,0,10,7,4,0,11,12,4,0,0,22,0,1,0,0,15,2,1,0,0,14,3,1,0,1,25,25,26,1,0,1,36,24,14,1,0,2,35,22,14,1,0,3,26,9,1,1,0,3,53,8,9,1,0,3,75,1,9,1,0,4,29,30,31,1,0,6,65,32,1,0,7,27,5,6,0,8,22,17,18,0,9,22,19,1,0,10,23,15,16,0,11,13,34,1,0,11,42,12,10,0,11,52,29,1,0,12,32,27,28,0,12,34,13,14,0,7,7,8,7,5,21,4,23,3,23,9,7,6,7,6,8,7,11,5,1,8,8,8,1,10,8,0,8,2,7,8,9,0,4,11,5,1,8,8,10,8,3,7,10,8,12,7,8,9,1,7,10,8,12,25,10,8,3,3,3,10,2,3,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,8,10,3,11,5,1,8,8,11,5,1,8,8,5,8,11,8,12,10,8,12,10,2,10,2,1,6,8,9,1,3,1,8,8,2,7,11,5,1,9,0,3,1,11,5,1,9,0,1,8,12,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,9,2,6,10,8,12,6,8,12,1,1,8,3,3,3,3,3,3,3,7,8,9,1,8,11,5,11,5,1,8,8,3,3,13,7,8,9,1,8,10,8,8,7,10,8,12,11,5,1,8,8,3,3,8,11,8,10,7,8,9,5,11,5,1,8,8,3,5,11,4,1,5,5,1,8,3,1,6,10,9,0,1,5,1,6,11,4,1,9,0,1,11,4,1,9,0,1,9,0,2,7,10,8,12,5,1,7,8,12,4,7,8,12,11,5,1,8,8,5,7,8,9,2,11,5,1,9,0,7,8,9,1,11,6,1,9,0,2,11,6,1,8,8,5,2,3,3,2,7,8,12,3,7,66,97,108,97,110,99,101,4,67,111,105,110,22,71,101,110,101,115,105,115,67,104,97,105,110,80,97,114,97,109,101,116,101,114,115,24,71,101,110,101,115,105,115,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,15,84,111,107,101,110,65,108,108,111,99,97,116,105,111,110,25,84,111,107,101,110,68,105,115,116,114,105,98,117,116,105,111,110,83,99,104,101,100,117,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,9,86,97,108,105,100,97,116,111,114,8,97,99,116,105,118,97,116,101,19,97,99,116,105,118,97,116,101,95,118,97,108,105,100,97,116,111,114,115,15,97,108,108,111,99,97,116,101,95,116,111,107,101,110,115,11,97,108,108,111,99,97,116,105,111,110,115,11,97,109,111,117,110,116,95,109,105,115,116,7,98,97,108,97,110,99,101,24,99,104,97,105,110,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,4,99,111,105,110,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,12,102,114,111,109,95,98,97,108,97,110,99,101,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,9,105,109,97,103,101,95,117,114,108,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,4,110,97,109,101,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,18,110,101,116,119,111,114,107,95,112,117,98,108,105,99,95,107,101,121,3,110,101,119,6,111,98,106,101,99,116,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,19,112,114,111,116,111,99,111,108,95,112,117,98,108,105,99,95,107,101,121,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,17,114,101,99,105,112,105,101,110,116,95,97,100,100,114,101,115,115,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,23,115,116,97,107,101,95,115,117,98,115,105,100,121,95,102,117,110,100,95,109,105,115,116,41,115,116,97,107,101,95,115,117,98,115,105,100,121,95,105,110,105,116,105,97,108,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,21,115,116,97,107,101,100,95,119,105,116,104,95,118,97,108,105,100,97,116,111,114,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,118,97,108,105,100,97,116,111,114,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,13,118,97,108,105,100,97,116,111,114,95,115,101,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,6,118,101,99,116,111,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,17,119,111,114,107,101,114,95,112,117,98,108,105,99,95,107,101,121,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,15,39,10,2,24,10,2,33,10,2,47,10,2,62,5,30,3,21,3,49,10,2,48,10,2,41,10,2,74,10,2,40,10,2,45,10,2,46,10,2,73,10,2,1,2,12,50,3,19,3,28,3,59,3,57,3,58,3,55,13,37,3,38,3,69,3,71,3,68,3,2,2,2,56,3,16,10,8,3,3,2,3,51,5,17,3,60,11,4,1,5,0,0,0,0,4,147,1,10,5,46,17,11,6,0,0,0,0,0,0,0,0,33,4,7,5,11,11,5,1,7,0,39,11,4,19,2,12,6,12,22,13,1,11,22,56,0,12,24,56,1,12,23,64,10,0,0,0,0,0,0,0,0,12,28,14,3,65,11,12,8,6,0,0,0,0,0,0,0,0,12,11,10,11,10,8,35,4,89,5,33,14,3,10,11,66,11,20,19,0,12,29,12,17,12,16,12,14,12,30,12,15,12,19,12,20,12,7,12,10,12,25,12,18,12,12,12,9,12,13,11,25,11,20,11,15,11,30,11,19,11,13,11,9,11,12,11,18,11,14,11,16,11,17,11,29,11,10,11,7,10,5,17,16,12,27,14,28,14,27,17,19,32,4,77,5,81,11,5,1,7,1,39,13,28,11,27,68,10,11,11,6,1,0,0,0,0,0,0,0,22,12,11,5,28,11,1,11,6,13,28,10,5,17,1,13,28,17,2,14,2,16,0,20,14,2,16,1,20,14,2,16,2,20,14,2,16,3,20,14,2,16,4,20,14,2,16,5,20,14,2,16,6,20,10,5,17,14,12,26,11,24,14,2,16,7,20,14,2,16,8,20,14,2,16,9,20,10,5,17,12,12,21,11,0,11,28,11,23,14,2,16,10,20,14,2,16,11,20,11,26,11,21,11,5,17,13,2,1,0,0,0,20,44,14,1,56,2,32,4,35,5,5,13,1,69,21,19,3,12,7,12,5,12,6,13,0,11,5,56,0,12,4,14,7,56,3,4,29,11,7,56,4,12,8,10,2,11,8,17,18,11,4,11,6,10,3,17,17,5,34,11,4,10,3,56,5,11,6,17,10,5,0,11,2,1,11,3,1,11,1,70,21,0,0,0,0,0,0,0,0,11,0,56,6,2,2,0,0,0,33,24,10,0,46,65,10,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,1,35,4,21,5,11,10,0,10,2,67,10,6,0,0,0,0,0,0,0,0,17,15,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,2,1,2,1,3,1,7,1,8,1,9,1,10,1,11,1,4,1,5,1,6,1,0,1,1,0],"stake_subsidy":[161,28,235,11,6,0,0,0,12,1,0,12,2,12,22,3,34,37,4,71,4,5,75,74,7,149,1,176,2,8,197,3,64,6,133,4,28,10,161,4,20,12,181,4,180,1,13,233,5,10,15,243,5,4,0,18,1,6,1,7,1,14,1,21,1,23,0,3,4,0,1,0,12,0,2,1,4,1,0,1,4,2,2,0,5,4,2,0,0,8,0,1,0,0,5,2,3,0,0,10,4,5,0,1,16,7,8,0,2,17,13,14,1,0,2,24,11,5,1,0,3,15,12,5,0,5,10,4,10,5,11,2,1,8,3,3,3,13,7,8,4,1,8,0,1,7,8,0,1,11,2,1,8,3,1,6,8,0,1,3,0,1,7,8,4,1,8,1,3,4,11,2,1,8,3,3,1,8,3,1,6,11,2,1,9,0,2,3,3,2,7,11,2,1,9,0,3,1,11,2,1,9,0,3,66,97,103,7,66,97,108,97,110,99,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,84,120,67,111,110,116,101,120,116,13,97,100,118,97,110,99,101,95,101,112,111,99,104,3,98,97,103,7,98,97,108,97,110,99,101,6,99,114,101,97,116,101,27,99,117,114,114,101,110,116,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,28,99,117,114,114,101,110,116,95,101,112,111,99,104,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,20,100,105,115,116,114,105,98,117,116,105,111,110,95,99,111,117,110,116,101,114,12,101,120,116,114,97,95,102,105,101,108,100,115,7,103,101,110,101,115,105,115,4,109,97,116,104,3,109,105,110,3,110,101,119,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,6,7,11,2,1,8,3,11,3,9,3,20,3,19,13,12,8,1,0,3,0,0,6,19,10,3,7,0,75,37,4,6,5,10,11,4,1,7,1,39,11,0,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,11,4,17,3,18,0,2,1,3,0,0,9,57,10,0,16,0,20,10,0,16,1,56,0,17,6,12,3,10,0,15,1,11,3,56,1,12,2,10,0,16,2,20,6,1,0,0,0,0,0,0,0,22,10,0,15,2,21,10,0,16,2,20,10,0,16,3,20,25,6,0,0,0,0,0,0,0,0,33,4,53,10,0,16,0,20,53,10,0,16,4,20,53,24,7,0,26,12,1,10,0,16,0,20,11,1,52,23,11,0,15,0,21,5,55,11,0,1,11,2,2,2,1,0,0,6,8,10,0,16,0,20,11,0,16,1,56,0,17,6,2,0,2,0,0,0,1,0,3,0,4,0,13,0,22,0],"staking_pool":[161,28,235,11,6,0,0,0,12,1,0,22,2,22,58,3,80,175,2,4,255,2,38,5,165,3,224,2,7,133,6,144,9,8,149,15,96,6,245,15,200,1,10,189,17,66,12,255,17,237,11,13,236,29,28,15,136,30,4,0,73,1,48,2,15,2,16,2,19,2,43,2,47,2,74,2,77,2,78,2,79,0,8,12,0,0,5,7,0,0,7,8,0,1,4,7,1,0,0,2,0,12,0,3,1,4,1,0,1,4,2,12,1,0,1,6,3,7,0,6,11,4,0,7,6,2,0,8,9,12,2,7,1,4,1,10,10,2,0,0,45,0,1,0,0,63,2,3,0,0,64,4,5,0,0,84,6,7,0,0,80,8,9,0,0,24,10,3,0,0,61,11,3,0,0,60,12,3,0,0,59,12,3,0,0,85,13,9,0,0,12,14,3,0,0,65,4,5,0,0,21,14,3,0,0,76,15,5,0,0,54,16,17,0,0,72,16,5,0,0,71,16,5,0,0,38,15,18,0,0,36,15,18,0,0,69,19,8,0,0,70,19,3,0,0,42,20,3,0,0,35,21,18,0,0,57,22,23,0,0,51,15,5,0,0,52,15,5,0,0,39,22,18,0,0,30,24,5,0,0,31,24,5,0,0,34,3,23,0,0,18,22,3,0,1,17,52,35,1,0,1,28,49,3,1,0,1,32,54,51,1,3,1,37,52,18,1,0,1,40,52,18,1,0,1,46,3,29,1,0,1,68,51,29,1,0,2,45,0,32,0,3,41,40,5,1,0,3,69,48,31,1,0,3,83,34,5,1,0,3,86,3,31,1,0,4,29,41,42,1,0,5,44,45,5,0,6,23,28,3,0,6,33,35,17,1,8,6,45,0,28,0,8,14,46,3,2,7,4,8,17,55,56,2,7,4,8,20,55,18,2,7,4,8,45,0,27,2,7,4,9,62,36,3,1,12,9,78,36,3,1,8,10,25,38,5,0,10,67,38,39,0,51,26,36,5,42,30,41,30,46,1,53,8,39,30,43,30,52,43,48,26,40,30,32,5,37,5,34,5,35,5,33,5,31,5,50,26,49,26,1,7,8,11,1,8,0,5,7,8,0,11,5,1,8,9,5,3,7,8,11,0,3,7,8,0,8,2,7,8,11,1,3,2,7,8,0,8,2,2,3,11,5,1,8,9,1,8,2,1,11,5,1,8,9,2,7,8,0,11,5,1,8,9,2,7,8,0,7,8,11,1,7,8,0,4,7,8,0,3,3,3,2,7,8,0,3,1,6,8,0,1,6,8,2,1,8,7,1,1,3,7,8,2,3,7,8,11,2,7,8,2,8,2,2,6,8,2,6,8,2,2,6,8,0,3,1,8,1,2,6,8,1,3,1,11,10,2,3,8,1,2,3,8,1,1,11,10,2,9,0,9,1,1,8,8,1,11,3,1,9,0,1,8,9,1,11,5,1,9,0,1,8,4,2,8,2,3,1,6,11,5,1,9,0,1,6,9,0,2,9,0,5,6,3,11,5,1,8,9,3,11,5,1,8,9,5,3,1,6,8,11,1,5,2,7,11,5,1,9,0,11,5,1,9,0,2,11,5,1,9,0,7,8,11,1,11,6,1,9,0,1,11,6,1,8,9,3,3,8,1,11,5,1,8,9,2,3,3,3,7,11,10,2,9,0,9,1,9,0,9,1,5,3,3,8,1,3,3,2,7,11,5,1,9,0,3,2,7,11,3,1,9,0,9,0,3,11,5,1,8,9,5,3,1,9,0,1,6,11,3,1,9,0,2,6,8,2,11,5,1,8,9,2,6,11,3,1,9,0,9,0,2,6,11,10,2,9,0,9,1,9,0,1,6,9,1,3,3,8,1,3,3,66,97,103,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,16,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,3,97,100,100,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,24,99,104,101,99,107,95,98,97,108,97,110,99,101,95,105,110,118,97,114,105,97,110,116,115,4,99,111,105,110,8,99,111,110,116,97,105,110,115,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,18,100,101,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,6,100,101,108,101,116,101,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,5,101,112,111,99,104,14,101,120,99,104,97,110,103,101,95,114,97,116,101,115,12,101,120,116,114,97,95,102,105,101,108,100,115,4,102,105,108,108,12,102,114,111,109,95,98,97,108,97,110,99,101,14,103,101,116,95,115,117,105,95,97,109,111,117,110,116,16,103,101,116,95,116,111,107,101,110,95,97,109,111,117,110,116,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,2,105,100,21,105,110,105,116,105,97,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,25,105,115,95,101,113,117,97,108,95,115,116,97,107,105,110,103,95,109,101,116,97,100,97,116,97,11,105,115,95,105,110,97,99,116,105,118,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,21,105,115,95,112,114,101,97,99,116,105,118,101,95,97,116,95,101,112,111,99,104,7,105,115,95,115,111,109,101,4,106,111,105,110,15,106,111,105,110,95,115,116,97,107,101,100,95,115,117,105,4,109,97,116,104,3,109,105,110,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,27,112,101,110,100,105,110,103,95,112,111,111,108,95,116,111,107,101,110,95,119,105,116,104,100,114,97,119,13,112,101,110,100,105,110,103,95,115,116,97,107,101,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,26,112,101,110,100,105,110,103,95,116,111,116,97,108,95,115,117,105,95,119,105,116,104,100,114,97,119,7,112,111,111,108,95,105,100,17,112,111,111,108,95,116,111,107,101,110,95,97,109,111,117,110,116,18,112,111,111,108,95,116,111,107,101,110,95,98,97,108,97,110,99,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,9,112,114,105,110,99,105,112,97,108,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,30,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,32,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,95,112,114,101,97,99,116,105,118,101,12,114,101,119,97,114,100,115,95,112,111,111,108,6,115,101,110,100,101,114,4,115,111,109,101,5,115,112,108,105,116,16,115,112,108,105,116,95,115,116,97,107,101,100,95,115,117,105,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,97,109,111,117,110,116,11,115,117,105,95,98,97,108,97,110,99,101,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,17,117,110,119,114,97,112,95,115,116,97,107,101,100,95,115,117,105,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,5,118,97,108,117,101,23,119,105,116,104,100,114,97,119,95,102,114,111,109,95,112,114,105,110,99,105,112,97,108,16,119,105,116,104,100,114,97,119,95,114,101,119,97,114,100,115,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,0,2,11,33,8,8,13,11,3,1,3,22,11,3,1,3,76,3,66,11,5,1,8,9,56,3,26,11,10,2,3,8,1,50,3,53,3,49,3,27,8,4,1,2,2,75,3,55,3,2,2,4,33,8,8,54,8,7,71,3,58,11,5,1,8,9,0,3,0,0,25,18,10,0,56,0,12,1,10,0,17,47,56,1,56,1,6,0,0,0,0,0,0,0,0,56,2,6,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,0,17,38,18,0,2,1,3,0,0,33,47,14,1,56,3,12,6,10,0,46,17,18,32,4,9,5,15,11,0,1,11,4,1,7,11,39,10,6,6,0,0,0,0,0,0,0,0,36,4,20,5,26,11,0,1,11,4,1,7,18,39,11,4,17,47,10,0,46,56,4,11,3,11,1,18,2,12,5,10,0,16,0,20,11,6,22,11,0,15,0,21,11,5,11,2,56,5,2,2,3,0,0,37,61,10,0,11,1,17,3,12,4,12,3,10,2,46,17,55,12,7,14,4,56,3,12,5,10,0,10,5,10,3,10,2,46,17,54,17,9,12,6,11,5,14,6,56,3,22,12,8,10,0,16,1,20,10,8,22,10,0,15,1,21,10,0,16,2,20,11,3,22,10,0,15,2,21,10,0,46,17,18,4,48,11,0,17,7,5,50,11,0,1,13,4,11,6,56,6,1,11,4,11,2,56,7,11,7,56,8,11,8,2,3,3,0,0,44,31,14,1,16,3,20,10,0,46,56,4,33,4,9,5,13,11,0,1,7,2,39,11,0,14,1,16,4,20,12,2,46,11,2,17,23,12,3,11,1,17,4,12,4,14,3,14,4,56,3,17,28,11,4,2,4,0,0,0,9,8,11,0,19,2,12,1,1,1,17,45,11,1,2,5,3,0,0,3,15,10,0,16,5,20,14,1,56,3,22,10,0,15,5,21,11,0,15,6,11,1,56,6,1,2,6,3,0,0,45,28,11,1,46,17,54,6,1,0,0,0,0,0,0,0,22,12,3,10,0,17,7,10,0,17,8,10,0,15,7,10,3,10,0,16,5,20,10,0,16,8,20,18,1,56,9,11,0,11,3,12,2,46,11,2,17,30,2,7,0,0,0,3,29,10,0,16,5,20,10,0,16,1,20,23,10,0,15,5,21,10,0,16,8,20,10,0,16,2,20,23,10,0,15,8,21,6,0,0,0,0,0,0,0,0,10,0,15,1,21,6,0,0,0,0,0,0,0,0,11,0,15,2,21,2,8,3,0,0,23,31,10,0,16,5,20,10,0,16,8,20,18,1,12,1,10,0,16,5,20,10,0,16,0,20,22,10,0,15,5,21,14,1,10,0,16,5,20,17,28,10,0,15,8,21,6,0,0,0,0,0,0,0,0,11,0,15,0,21,2,9,0,0,0,47,33,10,0,11,3,12,4,46,11,4,17,23,12,6,14,6,11,2,17,27,12,8,10,8,10,1,38,4,20,11,8,11,1,23,12,5,5,22,6,0,0,0,0,0,0,0,0,12,5,11,5,10,0,16,6,56,3,17,44,12,7,11,0,15,6,11,7,56,10,2,10,3,0,0,3,29,10,0,15,7,10,1,17,29,56,9,10,0,46,17,17,4,10,5,14,11,0,1,7,15,39,10,0,46,17,18,32,4,20,5,24,11,0,1,7,17,39,11,0,15,9,11,1,56,11,2,11,3,0,0,50,59,14,1,16,3,20,10,0,46,56,4,33,4,9,5,15,11,0,1,11,2,1,7,2,39,10,0,46,17,17,4,20,5,26,11,0,1,11,2,1,7,16,39,10,2,46,17,55,12,4,11,1,17,4,12,3,14,3,56,3,12,5,10,0,16,5,20,10,5,23,10,0,15,5,21,10,0,16,8,20,10,5,23,11,0,15,8,21,11,3,11,2,56,7,11,4,56,8,11,5,2,12,3,0,0,3,16,10,0,46,17,18,32,4,6,5,10,11,0,1,7,12,39,11,1,56,12,11,0,15,10,21,2,13,1,0,0,3,4,11,0,16,5,20,2,14,1,0,0,3,4,11,0,16,3,20,2,15,1,0,0,3,4,11,0,16,11,56,3,2,16,1,0,0,3,4,11,0,16,4,20,2,17,1,0,0,3,4,11,0,16,9,56,13,2,18,1,0,0,3,4,11,0,16,10,56,14,2,19,1,0,0,5,53,10,0,16,11,56,3,12,3,10,1,10,3,37,4,9,5,15,11,0,1,11,2,1,7,4,39,11,3,10,1,23,7,0,38,4,22,5,28,11,0,1,11,2,1,7,19,39,10,1,7,0,38,4,33,5,39,11,0,1,11,2,1,7,19,39,11,2,17,47,10,0,16,3,20,10,0,16,4,20,11,0,15,11,11,1,56,10,18,2,2,20,1,4,0,3,9,11,0,11,1,10,2,17,19,11,2,46,17,55,56,5,2,21,1,4,0,53,24,10,0,14,1,12,2,46,11,2,17,22,4,8,5,12,11,0,1,7,13,39,11,1,19,2,12,3,1,1,17,45,11,0,15,11,11,3,56,6,1,2,22,1,0,0,18,25,10,0,16,3,20,10,1,16,3,20,33,4,17,11,0,16,4,20,11,1,16,4,20,33,12,2,5,23,11,0,1,11,1,1,9,12,2,11,2,2,23,1,0,0,45,45,10,0,10,1,17,26,4,8,11,0,1,17,29,2,10,0,16,10,10,1,56,15,11,1,17,44,12,3,10,0,16,9,56,16,20,12,2,10,3,10,2,38,4,41,5,25,10,0,16,7,10,3,56,17,4,36,11,0,16,7,11,3,56,18,20,2,11,3,6,1,0,0,0,0,0,0,0,23,12,3,5,20,11,0,1,17,29,2,24,1,0,0,3,4,11,0,16,0,20,2,25,1,0,0,3,4,11,0,16,1,20,2,26,0,0,0,18,17,10,0,17,17,4,8,11,0,1,8,12,2,5,15,11,0,16,9,56,16,20,11,1,36,12,2,11,2,2,27,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,12,20,53,11,1,53,24,11,0,16,13,20,53,26,52,2,28,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,13,20,53,11,1,53,24,11,0,16,12,20,53,26,52,2,29,0,0,0,3,4,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,18,1,2,30,0,0,0,57,22,10,0,11,1,17,23,12,3,14,3,10,0,16,5,20,17,28,12,4,11,0,16,8,20,12,2,11,4,11,2,33,4,19,5,21,7,10,39,2,0,7,0,8,0,9,2,1,2,2,0,3,0,4,0,6,0,5,0,1,0,2,2,3,1,0,1,1,0,81,0,82,0],"storage_fund":[161,28,235,11,6,0,0,0,11,1,0,6,2,6,14,3,20,44,4,64,8,5,72,73,7,145,1,178,1,8,195,2,64,10,131,3,15,12,146,3,107,13,253,3,4,15,129,4,2,0,9,1,4,1,10,0,2,4,0,1,0,4,1,0,1,2,1,2,0,0,6,0,1,0,0,3,2,0,0,0,13,3,4,0,0,12,3,4,0,1,5,8,4,1,0,1,8,9,7,1,0,1,14,10,4,1,0,1,15,5,7,1,0,7,6,4,6,5,6,6,6,1,11,1,1,8,2,1,8,0,6,7,8,0,11,1,1,8,2,11,1,1,8,2,11,1,1,8,2,3,3,1,6,8,0,1,3,0,1,8,2,1,11,1,1,9,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,6,11,1,1,9,0,7,66,97,108,97,110,99,101,3,83,85,73,11,83,116,111,114,97,103,101,70,117,110,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,4,106,111,105,110,3,110,101,119,22,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,98,97,108,97,110,99,101,5,115,112,108,105,116,12,115,116,111,114,97,103,101,95,102,117,110,100,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,13,116,111,116,97,108,95,98,97,108,97,110,99,101,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,11,1,1,8,2,7,11,1,1,8,2,0,3,0,0,5,4,56,0,11,0,18,0,2,1,3,0,0,0,30,10,0,15,0,11,2,56,1,1,10,0,15,0,11,3,56,1,1,10,0,15,1,11,1,56,1,1,10,0,15,1,11,5,56,2,12,6,10,0,15,0,11,6,56,1,1,11,0,15,1,11,4,56,2,2,2,1,0,0,5,4,11,0,16,1,56,3,2,3,1,0,0,5,8,10,0,16,1,56,3,11,0,16,0,56,3,22,2,0,1,0,0,0,11,0],"iota_system":[161,28,235,11,6,0,0,0,12,1,0,28,2,28,62,3,90,146,3,4,236,3,10,5,246,3,158,3,7,148,7,191,12,8,211,19,96,6,179,20,54,10,233,20,8,12,241,20,166,6,13,151,27,4,15,155,27,2,0,48,1,28,2,16,2,18,2,20,2,27,2,47,2,51,2,52,0,45,0,46,0,49,0,73,0,74,0,6,8,0,1,2,7,1,0,0,2,0,4,1,0,1,3,1,12,1,0,1,5,11,4,0,6,3,2,0,8,10,2,0,9,4,4,0,10,5,8,0,11,7,4,0,11,8,4,0,11,9,4,0,12,13,4,0,13,12,12,0,0,19,0,1,0,0,34,2,1,0,0,36,3,1,0,0,33,3,1,0,0,35,3,1,0,0,38,4,1,0,0,43,4,1,0,0,37,5,1,0,0,42,5,1,0,0,31,6,1,0,0,32,7,1,0,0,39,8,1,0,0,30,9,1,0,0,53,9,1,0,0,40,3,1,0,0,63,10,1,0,0,61,10,1,0,0,62,10,1,0,0,71,10,1,0,0,64,10,1,0,0,54,10,1,0,0,66,10,1,0,0,56,10,1,0,0,67,10,1,0,0,57,10,1,0,0,69,10,1,0,0,59,10,1,0,0,68,11,1,0,0,58,11,1,0,0,70,10,1,0,0,60,10,1,0,0,65,10,1,0,0,55,10,1,0,0,15,12,13,0,0,25,14,15,0,0,26,14,16,0,0,24,14,16,0,4,14,22,1,2,7,4,4,17,39,43,2,7,4,4,29,39,40,2,7,4,7,44,24,1,1,8,8,41,35,36,0,11,15,37,13,0,11,19,18,19,0,11,22,1,20,0,11,30,32,1,0,11,31,29,1,0,11,32,30,1,0,11,33,26,1,0,11,34,25,1,0,11,35,26,1,0,11,36,26,1,0,11,37,28,1,0,11,38,27,1,0,11,39,31,1,0,11,40,26,1,0,11,42,28,1,0,11,43,27,1,0,11,50,15,20,0,11,53,32,1,0,11,54,33,1,0,11,55,33,1,0,11,56,33,1,0,11,57,33,1,0,11,58,34,1,0,11,59,33,1,0,11,60,33,1,0,11,61,33,1,0,11,62,33,1,0,11,63,33,1,0,11,64,33,1,0,11,65,33,1,0,11,66,33,1,0,11,67,33,1,0,11,68,34,1,0,11,69,33,1,0,11,70,33,1,0,11,71,33,1,0,11,72,19,41,0,37,21,40,23,39,21,37,42,38,42,8,8,4,10,8,12,11,2,1,8,5,3,3,8,11,8,7,7,8,6,0,16,7,8,0,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,6,2,7,8,0,7,8,6,3,7,8,0,6,8,13,3,3,7,8,0,3,7,8,6,4,7,8,0,11,3,1,8,5,5,7,8,6,5,7,8,0,10,11,3,1,8,5,11,1,1,3,5,7,8,6,3,7,8,0,8,8,7,8,6,3,7,8,0,6,8,13,5,3,7,8,0,10,2,6,8,6,4,7,8,0,10,2,10,2,6,8,6,11,11,2,1,8,5,11,2,1,8,5,7,8,0,3,3,3,3,3,3,3,7,8,6,1,11,2,1,8,5,1,7,8,0,1,6,8,10,1,7,8,10,3,8,0,8,9,3,7,10,8,12,11,2,1,8,5,3,3,8,11,8,7,7,8,6,1,8,9,1,3,2,3,8,9,3,7,8,4,9,0,9,1,1,8,0,1,9,0,16,7,8,10,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,6,2,7,8,10,7,8,6,3,7,8,10,6,8,13,3,3,7,8,10,3,7,8,6,4,7,8,10,11,3,1,8,5,5,7,8,6,5,7,8,10,10,11,3,1,8,5,11,1,1,3,5,7,8,6,3,7,8,10,8,8,7,8,6,3,7,8,10,6,8,13,5,3,7,8,10,10,2,6,8,6,4,7,8,10,10,2,10,2,6,8,6,1,6,8,6,1,5,11,7,8,10,3,3,11,2,1,8,5,11,2,1,8,5,3,3,3,3,3,7,8,6,2,7,8,10,8,10,2,7,8,4,9,0,1,9,1,1,8,10,2,3,8,10,1,7,9,1,7,66,97,108,97,110,99,101,4,67,111,105,110,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,14,83,117,105,83,121,115,116,101,109,83,116,97,116,101,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,3,97,100,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,4,99,111,105,110,6,99,114,101,97,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,2,105,100,24,108,111,97,100,95,105,110,110,101,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,17,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,21,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,95,109,117,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,6,115,101,110,100,101,114,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,23,8,4,75,3,0,3,0,0,17,23,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,43,12,9,17,44,12,10,11,0,10,10,18,0,12,8,13,8,15,0,11,10,11,9,56,0,11,8,56,1,2,1,1,4,0,1,19,11,0,17,35,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,11,15,17,49,2,2,1,4,0,1,5,11,0,17,35,11,1,17,51,2,3,1,4,0,1,5,11,0,17,35,11,1,17,48,2,4,1,4,0,1,5,11,0,17,35,11,1,17,50,2,5,1,4,0,1,6,11,0,17,35,11,1,11,2,17,53,2,6,1,4,0,1,6,11,0,17,35,11,1,11,2,17,57,2,7,1,4,0,1,6,11,0,17,35,11,1,11,2,17,52,2,8,1,4,0,1,6,11,0,17,35,11,1,11,2,17,56,2,9,1,4,0,1,7,11,0,17,35,11,1,11,2,11,3,17,46,2,10,1,4,0,1,8,11,0,17,35,11,1,11,2,11,3,11,4,17,47,2,11,1,4,0,1,6,11,0,17,35,11,1,11,2,17,54,2,12,1,4,0,1,6,11,0,17,35,11,1,11,2,17,45,2,13,1,4,0,1,6,11,0,17,35,11,1,11,2,17,59,2,14,1,4,0,1,5,11,0,17,35,11,1,17,55,2,15,1,4,0,1,6,11,0,17,35,11,1,11,2,17,69,2,16,1,4,0,1,6,11,0,17,35,11,1,11,2,17,67,2,17,1,4,0,1,6,11,0,17,35,11,1,11,2,17,68,2,18,1,4,0,1,6,11,0,17,35,11,1,11,2,17,77,2,19,1,4,0,1,6,11,0,17,35,11,1,11,2,17,70,2,20,1,4,0,1,6,11,0,17,35,11,1,11,2,17,60,2,21,1,4,0,1,6,11,0,17,35,11,1,11,2,17,72,2,22,1,4,0,1,6,11,0,17,35,11,1,11,2,17,62,2,23,1,4,0,1,6,11,0,17,35,11,1,11,2,17,73,2,24,1,4,0,1,6,11,0,17,35,11,1,11,2,17,63,2,25,1,4,0,1,6,11,0,17,35,11,1,11,2,17,75,2,26,1,4,0,1,6,11,0,17,35,11,1,11,2,17,65,2,27,1,4,0,1,7,11,0,17,35,11,1,11,2,11,3,17,74,2,28,1,4,0,1,7,11,0,17,35,11,1,11,2,11,3,17,64,2,29,1,4,0,1,6,11,0,17,35,11,1,11,2,17,76,2,30,1,4,0,1,6,11,0,17,35,11,1,11,2,17,66,2,31,1,4,0,1,6,11,0,17,35,11,1,11,2,17,71,2,32,1,4,0,1,6,11,0,17,35,11,1,11,2,17,61,2,33,0,0,0,16,29,11,2,17,35,12,11,10,10,46,17,41,7,2,33,4,10,5,16,11,11,1,11,10,1,7,0,39,11,11,11,3,11,4,11,0,11,1,11,5,11,6,11,7,11,8,11,9,11,10,17,42,2,34,0,0,0,1,4,11,0,17,36,46,2,35,0,0,0,1,3,11,0,17,36,2,36,0,0,0,38,47,10,0,16,1,20,6,1,0,0,0,0,0,0,0,33,4,25,10,0,15,0,10,0,16,1,20,56,2,17,78,12,2,6,2,0,0,0,0,0,0,0,10,0,15,1,21,10,0,15,0,10,0,16,1,20,11,2,56,3,10,0,15,0,10,0,16,1,20,56,4,12,1,10,1,46,17,58,11,0,16,1,20,33,4,41,5,45,11,1,1,7,1,39,11,1,2,0,0,0,1,0,21,0],"iota_system_state_inner":[161,28,235,11,6,0,0,0,12,1,0,45,2,45,104,3,149,1,212,5,4,233,6,50,5,155,7,251,6,7,150,14,188,29,8,210,43,96,6,178,44,117,10,167,45,189,1,12,228,46,229,17,13,201,64,46,15,247,64,4,0,112,1,68,2,25,2,26,2,27,2,39,2,67,2,70,2,110,2,114,2,120,2,121,2,174,1,2,175,1,0,100,0,103,0,106,0,161,1,0,162,1,0,166,1,0,12,4,0,0,13,4,0,0,9,4,0,0,10,4,0,0,11,3,0,1,4,7,1,0,0,2,0,12,0,3,1,4,1,0,1,4,2,12,1,0,1,6,3,7,0,8,5,2,0,9,14,12,2,7,1,4,1,11,15,2,0,12,20,7,2,1,0,0,0,13,21,7,1,3,0,14,6,4,0,15,7,8,0,16,8,4,0,17,17,4,0,18,16,12,0,18,18,2,0,19,19,4,0,0,29,0,1,0,0,30,2,3,0,0,160,1,1,4,0,0,80,5,6,0,0,82,7,6,0,0,79,7,6,0,0,81,7,6,0,0,84,8,6,0,0,96,8,6,0,0,83,9,6,0,0,95,9,6,0,0,77,10,6,0,0,78,11,6,0,0,85,12,6,0,0,75,13,6,0,0,122,13,6,0,0,76,14,6,0,0,123,14,6,0,0,86,7,6,0,0,151,1,15,6,0,0,149,1,15,6,0,0,150,1,15,6,0,0,159,1,15,6,0,0,152,1,15,6,0,0,129,1,15,6,0,0,154,1,15,6,0,0,131,1,15,6,0,0,155,1,15,6,0,0,132,1,15,6,0,0,157,1,15,6,0,0,134,1,15,6,0,0,156,1,16,6,0,0,133,1,16,6,0,0,158,1,15,6,0,0,135,1,15,6,0,0,153,1,15,6,0,0,130,1,15,6,0,0,23,17,18,0,0,36,19,20,0,0,71,19,20,0,0,113,19,20,0,0,44,6,20,0,0,38,19,20,0,0,167,1,21,20,0,0,168,1,21,22,0,0,169,1,19,23,0,0,47,21,24,0,0,49,19,20,0,0,48,19,20,0,0,41,25,18,0,1,32,94,64,1,0,1,57,93,59,1,0,2,64,35,36,0,3,33,34,6,1,0,3,58,81,20,1,0,3,98,85,34,1,0,3,173,1,83,20,1,0,3,178,1,80,34,1,0,3,179,1,6,34,1,0,4,42,95,54,1,0,4,54,54,34,1,0,5,34,64,6,1,3,7,59,92,6,1,0,10,72,96,6,1,12,11,36,39,20,0,11,92,39,40,0,12,28,63,59,2,1,0,12,35,6,32,2,1,0,12,45,63,89,2,1,0,12,46,67,68,2,1,0,12,53,66,6,2,1,0,12,74,67,73,2,1,0,13,28,69,59,1,3,13,35,6,65,1,3,13,53,70,6,1,3,13,56,72,59,1,3,13,74,71,6,1,3,13,97,64,65,1,3,14,23,84,18,0,15,99,56,20,0,16,23,87,18,0,16,64,18,30,0,16,115,82,20,0,16,117,82,20,0,17,64,41,38,0,17,65,74,6,0,17,84,50,6,0,17,93,53,6,0,17,94,50,6,0,17,124,75,6,0,17,125,75,6,0,17,126,75,6,0,17,127,75,6,0,17,128,1,78,6,0,17,136,1,75,6,0,17,137,1,75,6,0,17,138,1,75,6,0,17,139,1,75,6,0,17,140,1,75,6,0,17,141,1,75,6,0,17,142,1,75,6,0,17,143,1,75,6,0,17,144,1,75,6,0,17,145,1,78,6,0,17,146,1,75,6,0,17,147,1,75,6,0,17,148,1,75,6,0,18,176,1,61,62,0,19,22,29,45,0,19,23,86,6,0,19,24,77,6,0,19,31,29,20,0,19,50,52,49,0,19,51,52,49,0,19,52,48,49,0,19,55,58,59,0,19,64,27,28,0,19,66,29,20,0,19,77,55,6,0,19,79,44,6,0,19,80,42,6,0,19,81,43,6,0,19,82,43,6,0,19,83,51,6,0,19,85,57,6,0,19,104,29,23,0,19,118,29,20,0,19,168,1,58,22,0,19,170,1,58,20,0,19,177,1,47,46,0,67,31,58,33,60,33,66,31,77,40,70,31,69,31,72,40,74,40,76,40,75,40,71,31,57,33,54,33,56,33,55,33,61,88,68,31,73,40,62,33,51,20,50,20,59,33,63,91,53,33,7,10,8,18,11,7,1,8,10,3,3,8,0,8,15,7,8,12,1,8,2,8,3,3,3,3,3,3,3,7,8,12,1,8,0,1,8,3,16,7,8,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,0,2,7,8,3,7,8,12,3,7,8,3,6,8,19,3,3,7,8,3,3,7,8,12,4,7,8,3,11,8,1,8,10,5,7,8,12,5,7,8,3,10,11,8,1,8,10,11,5,1,3,5,7,8,12,3,7,8,3,8,16,7,8,12,3,7,8,3,6,8,19,5,3,8,20,5,7,11,13,2,5,11,14,1,5,3,7,8,3,10,2,6,8,12,4,7,8,3,10,2,10,2,6,8,12,11,7,8,3,3,3,11,7,1,8,10,11,7,1,8,10,3,3,3,3,3,7,8,12,1,11,7,1,8,10,1,6,8,3,1,3,2,6,8,3,5,1,8,9,1,6,11,11,2,8,9,5,1,11,14,1,5,3,10,11,8,1,8,10,11,5,1,3,7,8,12,2,3,8,21,2,10,8,18,7,8,12,1,8,21,1,6,8,21,1,8,17,2,5,11,14,1,5,1,11,13,2,9,0,9,1,1,8,10,1,11,7,1,9,0,1,7,8,12,1,8,6,23,3,3,3,3,3,8,6,8,0,3,3,1,11,7,1,8,10,3,3,11,7,1,8,10,8,15,3,8,6,8,17,3,3,11,13,2,5,11,14,1,5,3,8,21,1,8,18,1,6,8,12,1,5,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,3,7,8,21,8,18,7,8,12,2,7,8,21,7,8,12,3,7,8,21,3,7,8,12,1,6,10,8,18,1,8,20,3,7,8,21,6,8,19,2,3,7,8,21,6,8,20,1,1,7,8,18,3,7,8,18,8,20,3,3,7,8,21,3,6,8,12,2,7,8,21,6,8,12,2,7,8,18,3,1,11,8,1,9,0,4,7,8,21,5,11,7,1,8,10,7,8,12,1,6,8,16,3,7,8,21,8,16,7,8,12,2,6,8,21,5,1,1,4,6,5,6,5,5,7,11,14,1,5,1,6,8,20,1,6,5,2,6,11,13,2,9,0,9,1,6,9,0,1,9,0,1,11,14,1,9,0,3,7,11,13,2,9,0,9,1,9,0,9,1,2,7,11,13,2,9,0,9,1,6,9,0,1,7,9,1,2,6,11,14,1,9,0,6,9,0,2,7,11,14,1,9,0,9,0,2,7,11,14,1,9,0,6,9,0,1,6,11,14,1,9,0,2,9,0,9,1,2,7,8,18,7,8,12,2,7,8,18,10,2,2,7,8,18,6,8,18,2,6,8,21,6,8,18,3,7,8,18,10,2,10,2,44,1,3,3,3,3,3,3,1,1,1,11,7,1,8,10,3,3,3,3,3,3,3,3,4,3,3,3,11,7,1,8,10,3,3,3,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,3,11,7,1,8,10,4,11,7,1,8,10,4,3,3,3,3,4,3,1,7,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,1,6,8,17,1,6,11,7,1,9,0,1,7,8,15,2,7,11,7,1,9,0,3,9,7,8,21,7,11,7,1,8,10,7,11,7,1,8,10,7,11,13,2,5,11,14,1,5,3,3,3,3,7,8,12,6,7,8,17,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,1,8,4,1,6,9,1,5,11,7,1,8,10,3,11,7,1,8,10,11,8,1,8,10,11,7,1,8,10,1,11,8,1,8,10,2,7,11,8,1,9,0,10,11,8,1,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,2,11,7,1,9,0,7,8,12,2,9,0,5,3,66,97,103,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,11,83,116,111,114,97,103,101,70,117,110,100,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,20,83,121,115,116,101,109,69,112,111,99,104,73,110,102,111,69,118,101,110,116,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,18,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,86,50,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,6,86,101,99,77,97,112,6,86,101,99,83,101,116,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,3,98,97,103,7,98,97,108,97,110,99,101,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,5,101,109,112,116,121,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,24,101,112,111,99,104,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,20,101,120,116,114,97,99,116,95,99,111,105,110,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,3,103,101,116,7,103,101,116,95,109,117,116,16,103,101,116,95,114,101,112,111,114,116,101,114,115,95,111,102,31,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,111,98,106,101,99,116,95,114,101,98,97,116,101,115,30,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,116,111,116,97,108,95,98,97,108,97,110,99,101,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,6,105,110,115,101,114,116,12,105,110,116,111,95,98,97,108,97,110,99,101,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,106,111,105,110,8,106,111,105,110,95,118,101,99,28,108,101,102,116,111,118,101,114,95,115,116,111,114,97,103,101,95,102,117,110,100,95,105,110,102,108,111,119,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,19,109,105,110,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,3,110,101,119,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,114,97,109,101,116,101,114,115,3,112,97,121,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,19,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,21,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,9,115,97,102,101,95,109,111,100,101,29,115,97,102,101,95,109,111,100,101,95,99,111,109,112,117,116,97,116,105,111,110,95,114,101,119,97,114,100,115,36,115,97,102,101,95,109,111,100,101,95,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,115,116,111,114,97,103,101,95,102,101,101,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,119,97,114,100,115,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,9,115,105,110,103,108,101,116,111,110,5,115,112,108,105,116,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,13,115,116,97,107,101,95,115,117,98,115,105,100,121,20,115,116,97,107,101,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,12,115,116,97,107,105,110,103,95,112,111,111,108,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,14,115,116,111,114,97,103,101,95,99,104,97,114,103,101,12,115,116,111,114,97,103,101,95,102,117,110,100,20,115,116,111,114,97,103,101,95,102,117,110,100,95,98,97,108,97,110,99,101,25,115,116,111,114,97,103,101,95,102,117,110,100,95,114,101,105,110,118,101,115,116,109,101,110,116,14,115,116,111,114,97,103,101,95,114,101,98,97,116,101,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,5,116,97,98,108,101,13,116,111,116,97,108,95,98,97,108,97,110,99,101,14,116,111,116,97,108,95,103,97,115,95,102,101,101,115,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,31,116,111,116,97,108,95,115,116,97,107,101,95,114,101,119,97,114,100,115,95,100,105,115,116,114,105,98,117,116,101,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,26,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,24,118,97,108,105,100,97,116,111,114,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,31,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,10,118,97,108,105,100,97,116,111,114,115,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,3,8,1,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,8,37,3,102,3,61,3,63,3,164,1,3,171,1,3,163,1,3,40,8,6,1,2,9,37,3,102,3,62,3,61,3,63,3,164,1,3,171,1,3,163,1,3,40,8,6,2,2,16,36,3,71,3,113,3,172,1,8,21,106,8,17,69,8,0,73,3,165,1,11,13,2,5,11,14,1,5,100,8,15,87,1,91,11,7,1,8,10,88,11,7,1,8,10,90,3,89,3,38,3,40,8,6,3,2,16,36,3,71,3,113,3,172,1,8,21,106,8,17,69,8,1,73,3,165,1,11,13,2,5,11,14,1,5,100,8,15,87,1,91,11,7,1,8,10,88,11,7,1,8,10,90,3,89,3,38,3,40,8,6,4,2,12,36,3,71,3,73,3,118,3,108,3,105,3,109,3,107,3,101,3,116,3,119,3,60,3,0,3,0,0,26,27,11,0,10,6,17,116,12,8,14,8,17,111,12,7,6,0,0,0,0,0,0,0,0,11,2,17,41,11,8,11,1,17,81,11,4,11,7,56,0,11,5,9,56,1,56,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,3,11,6,17,52,18,2,2,1,3,0,0,6,11,11,0,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,52,18,0,2,2,3,0,0,37,55,11,0,19,2,12,17,12,3,12,12,12,13,12,11,12,14,12,10,12,15,12,21,12,9,12,7,12,18,12,23,1,12,8,12,1,11,7,19,0,12,6,12,19,12,22,12,20,12,5,12,4,12,16,12,2,11,1,11,8,6,2,0,0,0,0,0,0,0,11,23,11,18,11,2,11,16,6,4,0,0,0,0,0,0,0,11,4,11,5,11,20,11,22,11,19,11,6,18,1,11,9,11,21,11,15,11,10,11,14,11,11,11,13,11,12,11,3,11,17,18,3,2,3,3,0,0,38,26,10,15,46,17,65,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,10,15,17,84,12,16,11,0,15,0,11,16,11,15,17,120,2,4,3,0,0,6,5,11,0,15,0,11,1,17,122,2,5,3,0,0,6,25,10,0,16,0,17,117,10,0,16,1,16,2,20,35,4,10,5,16,11,0,1,11,1,1,7,3,39,10,0,15,0,11,0,16,1,16,3,20,11,1,17,119,2,6,3,0,0,6,31,10,0,16,0,17,108,65,38,10,0,16,1,16,4,20,38,4,26,10,0,16,0,17,117,10,0,16,1,16,4,20,36,4,20,5,26,11,0,1,11,1,1,7,3,39,11,0,15,0,11,1,17,121,2,7,3,0,0,46,15,10,0,15,0,11,1,7,1,17,129,1,12,3,11,0,15,0,14,3,9,17,114,11,3,11,2,17,86,2,8,3,0,0,46,15,10,0,15,0,11,1,7,2,17,129,1,12,3,11,0,15,0,14,3,8,17,114,11,3,11,2,17,88,2,9,3,0,0,6,7,11,0,15,0,11,1,11,2,46,17,123,2,10,3,0,0,6,8,11,0,15,0,11,2,46,17,113,11,1,17,87,2,11,3,0,0,6,8,11,0,15,0,11,2,11,1,56,2,11,3,17,118,2,12,3,0,0,18,12,11,1,11,2,10,4,17,49,12,5,11,0,15,0,11,3,11,5,11,4,17,118,2,13,3,0,0,6,20,14,1,17,79,10,2,46,17,64,37,4,8,5,14,11,0,1,11,2,1,7,9,39,11,0,15,0,11,1,11,2,17,124,2,14,3,0,0,6,22,10,0,16,0,10,2,17,115,4,6,5,12,11,0,1,11,1,1,7,4,39,10,0,15,0,11,1,7,0,17,129,1,11,2,11,0,15,5,17,16,2,15,3,0,0,6,10,10,0,15,0,11,1,7,0,17,129,1,11,2,11,0,15,5,17,17,2,16,0,0,0,60,46,14,0,17,107,20,12,5,10,5,10,1,34,4,9,5,13,11,2,1,7,6,39,10,2,14,1,12,3,46,11,3,56,3,32,4,27,11,2,11,1,11,5,56,4,56,5,5,45,11,2,14,1,56,6,12,6,10,6,14,5,12,4,46,11,4,56,7,32,4,43,11,6,11,5,56,8,5,45,11,6,1,2,17,0,0,0,60,50,10,2,14,1,12,3,46,11,3,56,3,4,8,5,12,11,2,1,7,7,39,10,2,14,1,56,6,12,6,14,0,17,107,20,12,5,10,6,14,5,12,4,46,11,4,56,7,4,28,5,34,11,2,1,11,6,1,7,7,39,10,6,14,5,56,9,11,6,46,56,10,4,47,11,2,14,1,56,11,1,1,5,49,11,2,1,2,18,3,0,0,6,8,11,0,15,0,10,1,46,17,113,11,1,17,85,2,19,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,98,2,20,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,96,2,21,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,97,2,22,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,106,2,23,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,99,11,3,46,12,4,11,0,16,0,11,4,17,110,2,24,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,89,2,25,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,101,11,3,46,12,4,11,0,16,0,11,4,17,110,2,26,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,91,2,27,3,0,0,6,7,11,0,15,0,11,2,17,112,11,1,17,102,2,28,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,92,2,29,3,0,0,6,7,11,0,15,0,11,2,17,112,11,1,17,104,2,30,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,94,2,31,3,0,0,76,17,10,0,15,0,11,3,17,112,12,4,10,4,11,1,11,2,17,103,11,4,46,12,5,11,0,16,0,11,5,17,110,2,32,3,0,0,6,8,11,0,15,0,11,3,17,113,11,1,11,2,17,93,2,33,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,105,11,3,46,12,4,11,0,16,0,11,4,17,110,2,34,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,95,2,35,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,100,11,3,46,12,4,11,0,16,0,11,4,17,110,2,36,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,90,2,37,3,0,0,79,220,2,10,0,16,6,20,12,37,10,9,10,0,15,6,21,7,12,52,12,28,10,7,10,28,37,4,20,10,8,11,28,37,12,11,5,22,9,12,11,11,11,4,25,5,31,11,0,1,11,10,1,7,8,39,10,0,16,1,16,7,20,6,0,0,0,0,0,0,0,0,36,4,43,6,20,0,0,0,0,0,0,0,10,0,15,1,15,7,21,10,0,15,8,56,12,12,40,13,3,11,40,56,13,1,10,0,15,9,56,12,12,39,13,4,11,39,56,13,1,11,5,10,0,16,10,20,22,12,5,6,0,0,0,0,0,0,0,0,10,0,15,10,21,11,6,10,0,16,11,20,22,12,6,6,0,0,0,0,0,0,0,0,10,0,15,11,21,10,0,16,0,17,126,12,54,10,0,16,12,17,82,12,44,10,44,11,54,22,12,52,14,3,56,14,12,43,14,4,56,14,12,29,10,10,46,17,64,10,0,16,1,16,7,20,38,4,116,11,9,11,37,10,0,16,1,16,13,20,22,38,12,20,5,118,9,12,20,11,20,4,125,10,0,15,14,17,78,12,21,5,127,56,1,12,21,11,21,12,41,14,41,56,14,12,42,13,4,11,41,56,13,1,11,52,53,12,53,10,29,53,12,30,11,44,53,11,30,24,11,53,26,12,48,13,4,10,48,52,56,15,12,47,11,48,11,7,53,24,7,12,26,12,46,13,47,10,46,52,56,15,12,45,10,0,16,15,20,6,1,0,0,0,0,0,0,0,22,10,0,15,15,21,11,1,10,0,16,15,20,33,4,181,1,5,187,1,11,0,1,11,10,1,7,11,39,14,4,56,14,12,32,14,47,56,14,12,50,10,0,15,0,13,4,13,47,10,0,15,5,11,8,10,0,16,1,16,16,20,10,0,16,1,16,17,20,10,0,16,1,16,18,20,11,10,17,109,10,0,16,0,17,126,12,36,14,4,56,14,12,31,14,47,56,14,12,49,11,32,11,31,23,12,33,11,50,11,49,23,12,51,11,2,10,0,15,19,21,10,0,16,0,17,111,10,0,15,20,21,11,47,12,34,13,34,11,4,56,13,1,14,34,56,14,12,35,10,0,15,12,11,3,11,45,11,34,10,5,11,6,17,80,12,38,10,0,16,15,20,12,22,10,0,16,19,20,12,23,10,0,16,20,20,12,24,11,36,12,25,11,43,12,26,11,46,52,12,27,11,5,12,12,10,0,16,12,17,82,12,13,11,42,12,14,11,29,12,15,11,33,11,51,22,12,16,11,35,12,17,11,22,11,23,11,24,11,25,11,27,11,26,11,12,11,13,11,14,11,15,11,16,11,17,18,4,56,16,9,10,0,15,21,21,10,0,16,10,20,6,0,0,0,0,0,0,0,0,33,4,198,2,10,0,16,8,56,14,6,0,0,0,0,0,0,0,0,33,12,18,5,200,2,9,12,18,11,18,4,209,2,11,0,16,9,56,14,6,0,0,0,0,0,0,0,0,33,12,19,5,213,2,11,0,1,9,12,19,11,19,4,216,2,5,218,2,7,10,39,11,38,2,38,3,0,0,6,4,11,0,16,15,20,2,39,3,0,0,6,4,11,0,16,19,20,2,40,3,0,0,6,4,11,0,16,22,20,2,41,3,0,0,6,2,7,3,2,42,3,0,0,6,4,11,0,16,6,20,2,43,3,0,0,6,5,11,0,16,0,11,1,17,128,1,2,44,3,0,0,6,5,11,0,16,0,11,1,17,127,2,45,3,0,0,6,4,11,0,16,0,17,125,2,46,3,0,0,24,18,10,0,16,5,14,1,56,3,4,12,11,0,16,5,14,1,56,17,20,12,2,5,16,11,0,1,56,18,12,2,11,2,2,47,3,0,0,6,4,11,0,16,12,17,82,2,48,3,0,0,6,4,11,0,16,12,17,83,2,49,0,0,0,90,45,13,0,69,91,12,6,13,6,11,0,56,19,11,6,56,2,12,7,14,1,56,20,4,39,11,1,56,21,12,4,13,7,11,4,56,15,12,5,14,7,56,14,6,0,0,0,0,0,0,0,0,36,4,32,11,7,10,2,56,22,11,2,46,17,65,56,23,5,36,11,2,1,11,7,56,24,11,5,12,3,5,43,11,2,1,11,7,12,3,11,3,2,3,3,3,5,1,3,1,4,1,2,3,7,3,14,1,1,3,10,3,11,3,12,3,13,3,4,1,0,3,8,3,0,1,5,1,6,1,7,3,1,3,6,3,9,3,2,0,43,0,111,0],"validator":[161,28,235,11,6,0,0,0,12,1,0,31,2,31,72,3,103,183,4,4,158,5,38,5,196,5,240,3,7,180,9,201,19,8,253,28,96,6,221,29,190,1,10,155,31,156,1,12,183,32,214,27,13,141,60,60,15,201,60,13,0,134,1,1,20,1,23,1,73,1,103,2,21,2,22,2,34,2,71,2,104,2,111,2,131,1,0,101,0,136,1,0,14,4,0,0,13,4,0,0,8,3,0,0,11,3,0,1,9,7,0,3,3,7,1,0,0,4,9,7,0,5,0,12,0,6,1,4,1,0,1,8,2,7,0,9,5,2,0,10,10,2,0,11,12,7,0,12,4,7,0,12,6,8,0,12,7,12,0,13,15,2,0,0,55,0,1,0,0,53,2,3,0,0,26,4,5,0,0,16,4,5,0,0,18,6,5,0,0,86,7,5,0,0,87,7,5,0,0,90,8,5,0,0,89,9,5,0,0,94,9,5,0,0,88,4,5,0,0,93,4,5,0,0,29,10,5,0,0,82,11,5,0,0,46,12,13,0,0,48,12,14,0,0,105,12,15,0,0,49,12,16,0,0,30,12,16,0,0,41,12,17,0,0,83,12,17,0,0,51,12,16,0,0,74,12,16,0,0,79,12,16,0,0,142,1,12,16,0,0,85,12,18,0,0,84,12,18,0,0,52,12,18,0,0,143,1,12,18,0,0,61,12,19,0,0,63,12,19,0,0,64,12,19,0,0,68,12,19,0,0,66,12,20,0,0,65,12,20,0,0,62,12,20,0,0,69,12,20,0,0,72,12,21,0,0,59,12,22,0,0,110,12,22,0,0,98,12,22,0,0,109,12,22,0,0,141,1,12,22,0,0,95,4,5,0,0,75,12,22,0,0,76,12,22,0,0,38,12,22,0,0,25,12,22,0,0,78,23,24,0,0,102,12,25,0,0,42,26,13,0,0,44,27,13,1,0,0,43,28,13,1,0,0,57,11,5,0,0,122,29,5,0,0,120,29,5,0,0,121,29,5,0,0,130,1,29,5,0,0,123,29,5,0,0,113,29,5,0,0,125,29,5,0,0,115,29,5,0,0,126,29,5,0,0,116,29,5,0,0,128,1,29,5,0,0,118,29,5,0,0,127,30,5,0,0,117,30,5,0,0,124,29,5,0,0,114,29,5,0,0,129,1,29,5,0,0,119,29,5,0,0,31,6,5,0,0,132,1,14,5,0,0,133,1,31,5,0,0,54,32,3,0,1,103,31,38,0,2,108,62,31,1,0,3,24,64,62,1,0,3,36,67,51,1,0,3,45,64,13,1,0,3,47,64,13,1,0,3,70,5,34,1,0,3,96,51,34,1,0,4,37,38,35,0,5,53,40,41,0,6,139,1,45,22,1,0,7,32,51,5,1,3,8,40,62,25,1,8,10,33,46,22,0,10,92,46,15,0,11,56,31,39,0,12,17,42,5,0,12,27,42,5,0,12,28,58,5,0,12,46,48,13,0,12,53,40,61,0,12,75,48,22,0,12,76,48,22,0,12,78,60,24,0,12,81,49,5,0,12,82,59,5,0,12,86,47,5,0,12,90,54,22,0,12,97,53,22,0,12,99,53,22,0,12,106,48,22,0,13,57,66,25,0,13,140,1,56,57,0,82,31,82,35,86,44,87,50,87,55,88,61,52,35,52,31,51,35,51,31,80,51,78,51,83,35,83,31,81,35,79,35,81,31,79,31,77,1,14,5,10,2,10,2,10,2,10,2,8,6,8,6,8,12,8,12,8,6,8,6,8,6,8,6,8,7,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,11,1,8,1,2,7,8,1,3,0,1,7,8,1,4,7,8,1,11,8,1,8,10,5,7,8,11,3,7,8,1,8,14,7,8,11,3,7,8,1,8,16,3,2,7,8,1,11,8,1,8,10,2,7,8,1,7,8,11,1,6,8,1,1,1,1,6,8,0,1,5,1,6,8,6,1,6,8,12,1,6,10,2,1,6,11,5,1,8,6,1,6,11,5,1,10,2,1,6,8,9,1,3,2,6,8,1,3,1,8,13,1,8,9,2,6,8,1,6,8,1,2,6,11,5,1,9,0,6,9,0,2,6,11,5,1,9,0,6,11,5,1,9,0,2,7,8,1,10,2,3,7,8,1,10,2,10,2,1,10,2,4,8,0,3,3,7,8,11,22,5,8,6,8,6,8,6,8,6,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,8,6,11,5,1,8,6,10,2,11,5,1,8,6,11,5,1,8,6,8,7,10,2,10,2,10,2,8,6,8,6,8,12,8,12,1,11,5,1,9,0,1,8,6,8,1,1,1,1,1,1,1,8,0,1,2,1,8,4,1,8,12,1,7,8,11,1,8,7,2,7,8,15,3,2,3,3,1,8,10,1,6,11,8,1,9,0,1,6,8,11,5,7,8,15,11,8,1,8,10,5,3,7,8,11,1,6,8,15,1,7,8,15,1,8,2,1,9,0,4,3,3,3,3,1,6,8,14,3,7,8,15,8,14,7,8,11,1,8,3,1,6,8,16,1,6,5,2,7,8,15,11,8,1,8,10,2,7,8,15,7,8,11,2,6,8,15,3,1,8,15,1,6,9,0,29,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,6,11,5,1,9,0,2,1,1,2,5,7,8,11,1,7,11,5,1,9,0,3,8,9,8,15,5,3,66,97,103,7,66,97,108,97,110,99,101,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,19,83,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,21,85,110,115,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,3,85,114,108,9,86,97,108,105,100,97,116,111,114,17,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,8,97,99,116,105,118,97,116,101,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,6,97,109,111,117,110,116,5,97,115,99,105,105,3,98,97,103,7,98,97,108,97,110,99,101,3,98,99,115,6,98,111,114,114,111,119,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,10,100,101,97,99,116,105,118,97,116,101,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,11,100,101,115,99,114,105,112,116,105,111,110,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,5,101,112,111,99,104,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,10,102,114,111,109,95,97,115,99,105,105,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,2,105,100,9,105,109,97,103,101,95,117,114,108,12,105,115,95,100,117,112,108,105,99,97,116,101,13,105,115,95,101,113,117,97,108,95,115,111,109,101,23,105,115,95,101,113,117,97,108,95,115,111,109,101,95,97,110,100,95,118,97,108,117,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,8,109,101,116,97,100,97,116,97,4,110,97,109,101,11,110,101,116,95,97,100,100,114,101,115,115,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,20,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,102,114,111,109,95,109,101,116,97,100,97,116,97,12,110,101,119,95,109,101,116,97,100,97,116,97,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,20,110,101,120,116,95,101,112,111,99,104,95,103,97,115,95,112,114,105,99,101,22,110,101,120,116,95,101,112,111,99,104,95,110,101,116,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,22,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,32,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,16,110,101,120,116,95,101,112,111,99,104,95,115,116,97,107,101,25,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,7,112,111,111,108,95,105,100,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,16,112,114,105,110,99,105,112,97,108,95,97,109,111,117,110,116,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,21,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,13,114,101,119,97,114,100,95,97,109,111,117,110,116,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,111,109,101,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,12,115,116,97,107,101,95,97,109,111,117,110,116,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,14,115,116,97,107,101,114,95,97,100,100,114,101,115,115,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,6,115,116,114,105,110,103,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,11,115,117,105,95,98,97,108,97,110,99,101,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,111,95,98,121,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,10,116,120,95,99,111,110,116,101,120,116,15,117,110,115,116,97,107,105,110,103,95,101,112,111,99,104,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,3,117,114,108,17,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,21,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,95,98,99,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,12,118,111,116,105,110,103,95,112,111,119,101,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,19,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,100,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,3,8,102,0,0,0,0,0,0,0,3,8,208,7,0,0,0,0,0,0,3,8,0,1,0,0,0,0,0,0,3,8,160,134,1,0,0,0,0,0,0,2,22,105,5,85,10,2,52,10,2,143,1,10,2,84,10,2,49,8,6,30,8,6,41,8,12,83,8,12,50,8,6,74,8,6,79,8,6,142,1,8,6,66,11,5,1,10,2,65,11,5,1,10,2,62,11,5,1,10,2,69,11,5,1,10,2,60,11,5,1,8,6,63,11,5,1,8,6,64,11,5,1,8,6,68,11,5,1,8,6,35,8,7,1,2,10,48,8,0,141,1,3,72,8,9,38,3,101,8,15,25,3,67,3,59,3,58,3,35,8,7,2,2,5,77,8,9,135,1,5,100,5,33,3,19,3,3,2,7,77,8,9,135,1,5,100,5,97,3,112,3,80,3,91,3,0,3,0,0,33,68,11,0,12,14,11,1,12,25,11,2,12,29,11,3,12,30,11,4,12,31,11,5,12,32,11,6,12,33,11,7,12,34,11,8,12,35,11,9,12,15,11,10,12,16,11,11,12,17,11,12,12,18,56,0,12,19,56,0,12,20,56,0,12,21,56,0,12,22,56,1,12,23,56,1,12,24,56,1,12,26,56,1,12,27,11,13,12,28,11,14,11,25,11,29,11,30,11,31,11,32,11,33,11,34,11,35,11,15,11,16,11,17,11,18,11,19,11,22,11,20,11,21,11,23,11,24,11,26,11,27,11,28,18,0,2,1,3,0,0,36,137,1,14,9,65,37,7,17,37,4,11,14,10,65,37,7,17,37,12,16,5,13,9,12,16,11,16,4,21,14,11,65,37,7,17,37,12,17,5,23,9,12,17,11,17,4,31,14,12,65,37,7,17,37,12,18,5,33,9,12,18,11,18,4,41,14,5,65,37,7,17,37,12,19,5,43,9,12,19,11,19,4,51,14,6,65,37,7,17,37,12,20,5,53,9,12,20,11,20,4,61,14,7,65,37,7,17,37,12,21,5,63,9,12,21,11,21,4,71,14,8,65,37,7,17,37,12,22,5,73,9,12,22,11,22,4,76,5,80,11,15,1,7,9,39,10,14,7,16,37,4,85,5,89,11,15,1,7,8,39,10,13,7,18,35,4,94,5,98,11,15,1,7,15,39,11,0,11,1,11,2,11,3,11,4,11,5,17,76,17,84,11,6,17,76,17,84,11,7,17,91,11,8,17,91,11,9,17,76,17,84,11,10,17,76,17,84,11,11,17,76,17,84,11,12,17,76,17,84,10,15,17,85,17,0,12,23,14,23,17,73,11,23,11,13,11,14,11,15,17,75,2,2,3,0,0,5,5,11,0,15,0,11,1,17,93,2,3,3,0,0,5,5,11,0,15,0,11,1,17,92,2,4,3,0,0,5,13,10,0,16,1,20,10,0,15,2,21,10,0,16,3,20,11,0,15,4,21,2,5,3,0,0,43,57,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,8,5,14,11,0,1,11,3,1,7,11,39,10,3,46,17,89,6,1,0,0,0,0,0,0,0,22,12,5,10,0,15,0,11,1,10,2,11,5,10,3,17,102,10,0,16,0,17,95,4,34,10,0,15,0,17,100,10,0,16,5,20,10,4,22,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,11,2,11,3,46,17,89,11,4,18,2,56,3,2,6,3,0,0,22,46,10,3,46,17,89,6,0,0,0,0,0,0,0,0,33,4,7,5,13,11,0,1,11,3,1,7,12,39,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,21,5,27,11,0,1,11,3,1,7,11,39,10,0,15,0,11,1,11,2,6,0,0,0,0,0,0,0,0,11,3,17,102,10,0,15,0,17,100,10,0,16,5,20,11,4,22,11,0,15,5,21,2,7,3,0,0,52,43,14,1,17,105,12,3,14,1,17,104,12,5,10,0,15,0,11,1,10,2,17,103,12,6,10,6,10,3,23,12,4,10,0,16,5,20,11,6,23,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,10,2,46,17,90,11,5,11,2,46,17,89,11,3,11,4,18,3,56,4,2,8,3,0,0,5,28,10,2,7,18,35,4,5,5,9,11,0,1,7,15,39,14,1,17,108,20,10,0,16,6,16,7,20,33,4,19,5,23,11,0,1,7,14,39,11,2,11,0,15,1,21,2,9,3,0,0,5,41,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,2,7,18,35,4,14,5,18,11,0,1,7,15,39,14,1,17,108,20,10,0,16,6,16,7,20,33,4,28,5,32,11,0,1,7,14,39,10,2,10,0,15,1,21,11,2,11,0,15,2,21,2,10,3,0,0,5,14,10,1,7,16,37,4,5,5,9,11,0,1,7,8,39,11,1,11,0,15,3,21,2,11,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,1,7,16,37,4,14,5,18,11,0,1,7,8,39,11,1,11,0,15,4,21,2,12,3,0,0,5,14,10,0,16,5,20,14,1,56,2,22,10,0,15,5,21,11,0,15,0,11,1,17,94,2,13,3,0,0,5,16,10,0,15,0,11,1,17,101,10,0,46,17,40,11,0,16,5,20,33,4,13,5,15,7,11,39,2,14,1,0,0,5,4,11,0,16,0,17,95,2,15,1,0,0,5,3,11,0,16,6,2,16,1,0,0,5,5,11,0,16,6,16,7,20,2,17,1,0,0,5,4,11,0,16,6,16,8,2,18,1,0,0,5,4,11,0,16,6,16,9,2,19,1,0,0,5,4,11,0,16,6,16,10,2,20,1,0,0,5,4,11,0,16,6,16,11,2,21,1,0,0,5,4,11,0,16,6,16,12,2,22,1,0,0,5,4,11,0,16,6,16,13,2,23,1,0,0,5,4,11,0,16,6,16,14,2,24,1,0,0,5,4,11,0,16,6,16,15,2,25,1,0,0,5,4,11,0,16,6,16,16,2,26,1,0,0,5,4,11,0,16,6,16,17,2,27,1,0,0,5,4,11,0,16,6,16,18,2,28,1,0,0,5,4,11,0,16,6,16,19,2,29,1,0,0,5,4,11,0,16,6,16,20,2,30,1,0,0,5,4,11,0,16,6,16,21,2,31,1,0,0,5,4,11,0,16,6,16,22,2,32,1,0,0,5,4,11,0,16,6,16,23,2,33,1,0,0,5,4,11,0,16,6,16,24,2,34,1,0,0,5,4,11,0,16,6,16,25,2,35,1,0,0,5,4,11,0,16,6,16,26,2,36,1,0,0,5,4,11,0,16,6,16,27,2,37,1,0,0,5,3,11,0,16,28,2,38,1,0,0,5,4,11,0,16,1,20,2,39,1,0,0,5,5,40,11,0,16,0,17,106,2,40,1,0,0,5,4,11,0,16,0,17,106,2,41,1,0,0,5,3,11,0,17,40,2,42,1,0,0,5,4,11,0,16,29,20,2,43,3,0,0,5,5,11,1,11,0,15,29,21,2,44,1,0,0,5,4,11,0,16,0,17,97,2,45,1,0,0,5,4,11,0,16,0,17,98,2,46,1,0,0,5,4,11,0,16,2,20,2,47,1,0,0,5,4,11,0,16,4,20,2,48,1,0,0,5,5,11,0,16,0,11,1,17,99,2,49,1,0,0,5,4,11,0,16,0,56,5,2,50,1,0,0,63,151,3,10,0,16,6,16,7,20,10,1,16,6,16,7,20,33,4,13,8,12,2,5,23,10,0,16,6,16,8,20,10,1,16,6,16,8,20,33,12,2,11,2,4,28,8,12,13,5,38,10,0,16,6,16,12,20,10,1,16,6,16,12,20,33,12,13,11,13,4,43,8,12,24,5,53,10,0,16,6,16,13,20,10,1,16,6,16,13,20,33,12,24,11,24,4,58,8,12,25,5,68,10,0,16,6,16,16,20,10,1,16,6,16,16,20,33,12,25,11,25,4,73,8,12,26,5,83,10,0,16,6,16,18,20,10,1,16,6,16,18,20,33,12,26,11,26,4,88,8,12,27,5,98,10,0,16,6,16,18,20,10,1,16,6,16,19,20,33,12,27,11,27,4,103,8,12,28,5,113,10,0,16,6,16,19,20,10,1,16,6,16,19,20,33,12,28,11,28,4,118,8,12,29,5,128,1,10,0,16,6,16,19,20,10,1,16,6,16,18,20,33,12,29,11,29,4,133,1,8,12,30,5,141,1,10,0,16,6,16,20,10,1,16,6,16,20,56,6,12,30,11,30,4,146,1,8,12,3,5,154,1,10,0,16,6,16,21,10,1,16,6,16,21,56,6,12,3,11,3,4,159,1,8,12,4,5,167,1,10,0,16,6,16,24,10,1,16,6,16,24,56,7,12,4,11,4,4,172,1,8,12,5,5,180,1,10,0,16,6,16,26,10,1,16,6,16,26,56,7,12,5,11,5,4,185,1,8,12,6,5,193,1,10,0,16,6,16,26,10,1,16,6,16,27,56,7,12,6,11,6,4,198,1,8,12,7,5,206,1,10,0,16,6,16,27,10,1,16,6,16,27,56,7,12,7,11,7,4,211,1,8,12,8,5,219,1,10,0,16,6,16,27,10,1,16,6,16,26,56,7,12,8,11,8,4,224,1,8,12,9,5,232,1,10,0,16,6,16,20,10,1,16,6,16,12,56,8,12,9,11,9,4,237,1,8,12,10,5,245,1,10,0,16,6,16,21,10,1,16,6,16,13,56,8,12,10,11,10,4,250,1,8,12,11,5,130,2,10,0,16,6,16,24,10,1,16,6,16,16,56,9,12,11,11,11,4,135,2,8,12,12,5,143,2,10,0,16,6,16,26,10,1,16,6,16,18,56,9,12,12,11,12,4,148,2,8,12,14,5,156,2,10,0,16,6,16,26,10,1,16,6,16,19,56,9,12,14,11,14,4,161,2,8,12,15,5,169,2,10,0,16,6,16,27,10,1,16,6,16,19,56,9,12,15,11,15,4,174,2,8,12,16,5,182,2,10,0,16,6,16,27,10,1,16,6,16,18,56,9,12,16,11,16,4,187,2,8,12,17,5,195,2,10,1,16,6,16,20,10,0,16,6,16,12,56,8,12,17,11,17,4,200,2,8,12,18,5,208,2,10,1,16,6,16,21,10,0,16,6,16,13,56,8,12,18,11,18,4,213,2,8,12,19,5,221,2,10,1,16,6,16,24,10,0,16,6,16,16,56,9,12,19,11,19,4,226,2,8,12,20,5,234,2,10,1,16,6,16,26,10,0,16,6,16,18,56,9,12,20,11,20,4,239,2,8,12,21,5,247,2,10,1,16,6,16,26,10,0,16,6,16,19,56,9,12,21,11,21,4,252,2,8,12,22,5,132,3,10,1,16,6,16,27,10,0,16,6,16,19,56,9,12,22,11,22,4,141,3,11,0,1,11,1,1,8,12,23,5,149,3,11,1,16,6,16,27,11,0,16,6,16,18,56,9,12,23,11,23,2,51,0,0,0,13,17,10,0,56,10,4,10,11,1,1,11,0,1,9,12,2,5,15,11,0,56,11,11,1,33,12,2,11,2,2,52,0,0,0,65,26,10,0,56,10,4,6,8,12,2,5,9,10,1,56,10,12,2,11,2,4,18,11,1,1,11,0,1,9,12,3,5,24,11,0,56,11,11,1,56,11,33,12,3,11,3,2,53,3,0,0,15,25,10,1,46,17,90,12,2,10,2,10,0,16,6,16,7,20,33,4,12,5,18,11,0,1,11,1,1,7,13,39,11,2,11,1,17,107,11,0,15,28,21,2,54,3,0,0,5,18,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,11,0,15,6,15,8,21,2,55,3,0,0,5,18,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,11,0,15,6,15,9,21,2,56,3,0,0,5,17,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,91,11,0,15,6,15,10,21,2,57,3,0,0,5,17,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,91,11,0,15,6,15,11,21,2,58,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,20,21,11,0,16,6,17,73,2,59,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,12,21,11,0,16,6,17,73,2,60,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,21,21,11,0,16,6,17,73,2,61,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,13,21,11,0,16,6,17,73,2,62,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,22,21,11,0,16,6,17,73,2,63,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,14,21,11,0,16,6,17,73,2,64,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,23,21,11,0,16,6,17,73,2,65,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,15,21,11,0,16,6,17,73,2,66,3,0,0,5,16,11,1,56,13,10,0,15,6,15,24,21,11,2,56,13,10,0,15,6,15,25,21,11,0,16,6,17,73,2,67,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,16,21,11,2,10,0,15,6,15,17,21,11,0,16,6,17,73,2,68,3,0,0,5,10,11,1,56,13,10,0,15,6,15,26,21,11,0,16,6,17,73,2,69,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,18,21,11,0,16,6,17,73,2,70,3,0,0,5,10,11,1,56,13,10,0,15,6,15,27,21,11,0,16,6,17,73,2,71,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,19,21,11,0,16,6,17,73,2,72,3,0,0,5,143,1,10,0,46,17,29,56,14,4,18,10,0,15,6,15,20,56,15,10,0,15,6,15,12,21,56,1,10,0,15,6,15,20,21,10,0,46,17,30,56,14,4,36,10,0,15,6,15,21,56,15,10,0,15,6,15,13,21,56,1,10,0,15,6,15,21,21,10,0,46,17,31,56,14,4,54,10,0,15,6,15,22,56,15,10,0,15,6,15,14,21,56,1,10,0,15,6,15,22,21,10,0,46,17,32,56,14,4,72,10,0,15,6,15,23,56,15,10,0,15,6,15,15,21,56,1,10,0,15,6,15,23,21,10,0,46,17,33,56,16,4,103,10,0,15,6,15,24,56,17,10,0,15,6,15,16,21,56,0,10,0,15,6,15,24,21,10,0,15,6,15,25,56,17,10,0,15,6,15,17,21,56,0,10,0,15,6,15,25,21,10,0,46,17,35,56,16,4,121,10,0,15,6,15,26,56,17,10,0,15,6,15,18,21,56,0,10,0,15,6,15,26,21,10,0,46,17,36,56,16,4,140,1,10,0,15,6,15,27,56,17,10,0,15,6,15,19,21,56,0,11,0,15,6,15,27,21,5,142,1,11,0,1,2,73,1,0,0,5,4,11,0,56,18,17,74,2,74,1,2,0,75,0,0,0,68,24,14,0,16,7,20,12,6,10,3,17,96,12,5,11,6,10,3,17,107,12,4,11,0,6,0,0,0,0,0,0,0,0,11,4,10,1,11,5,10,2,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,17,85,18,1,2,1,4,1,7,1,3,1,8,1,5,1,6,1,0,0,0,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,1,0,4,0,2,0,3,0,17,0,18,0,19,0,20,0,13,0,14,0,15,0,16,1,2,1,1,0,39,0,107,0,137,1,0,138,1,0,141,1,0],"validator_cap":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,20,3,28,42,4,70,4,5,74,54,7,128,1,226,2,8,226,3,64,6,162,4,34,10,196,4,13,12,209,4,112,13,193,5,4,15,197,5,6,0,18,1,10,1,14,1,15,0,3,12,0,0,4,2,0,1,0,7,0,1,2,4,0,3,1,2,0,0,16,0,1,0,0,20,2,1,0,0,9,3,4,0,0,8,0,5,0,1,6,13,4,1,8,1,7,10,11,0,2,11,14,6,1,12,3,12,8,9,0,4,12,6,12,1,6,8,0,1,6,5,1,6,8,1,2,5,7,8,4,1,8,2,1,8,1,0,4,1,8,0,8,2,5,1,6,8,4,1,5,1,7,8,4,1,8,3,1,8,0,1,6,9,0,2,9,0,5,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,28,97,117,116,104,111,114,105,122,101,114,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,6,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,3,5,5,1,2,1,5,5,0,3,0,0,6,3,11,0,16,0,2,1,3,0,0,6,3,11,0,16,1,2,2,3,0,0,7,35,10,1,46,17,7,12,5,10,5,7,0,33,4,11,8,12,2,5,15,11,5,10,0,33,12,2,11,2,4,18,5,22,11,1,1,6,0,0,0,0,0,0,0,0,39,11,1,17,5,10,0,18,0,12,3,14,3,56,0,12,4,11,3,11,0,56,1,11,4,2,3,3,0,0,6,5,11,0,16,0,20,18,1,2,0,1,1,0,0,13,0,17,0,19,0],"validator_set":[161,28,235,11,6,0,0,0,12,1,0,51,2,51,112,3,163,1,134,6,4,169,7,133,1,5,174,8,210,9,7,128,18,183,23,8,183,41,96,6,151,42,195,1,10,218,43,141,1,12,231,44,251,34,13,226,79,16,15,242,79,5,0,159,1,1,103,1,167,1,2,30,2,31,2,57,2,101,2,113,2,141,1,2,145,1,2,146,1,2,152,1,2,165,1,2,166,1,0,137,1,0,155,1,0,158,1,0,163,1,0,170,1,0,19,4,0,0,14,3,0,0,15,3,0,0,16,3,0,0,17,3,0,1,4,7,1,0,0,3,0,12,0,4,1,4,1,0,1,6,3,7,0,7,2,6,1,2,0,7,6,6,1,2,0,8,7,2,0,9,9,12,2,7,1,4,1,10,10,4,1,4,1,11,11,2,0,12,21,7,2,1,0,0,0,13,22,7,1,3,0,14,5,7,0,14,8,8,0,15,13,4,0,16,12,12,0,16,18,2,0,17,20,4,0,0,96,0,1,0,0,124,2,3,0,0,126,4,3,0,0,123,5,3,0,0,28,6,3,0,0,125,4,3,0,0,122,7,3,0,0,128,1,8,3,0,0,127,9,3,0,0,27,10,3,0,0,154,1,11,3,0,0,52,12,3,0,0,47,13,14,0,0,149,1,13,14,0,0,162,1,15,14,0,0,160,1,15,14,0,0,161,1,15,16,0,0,139,1,13,17,0,0,99,13,14,0,0,81,15,18,0,0,84,6,18,0,0,83,19,18,0,0,43,19,14,0,0,85,6,18,0,0,42,20,14,0,0,68,21,22,0,0,60,23,24,0,0,61,25,24,0,0,71,26,27,0,0,72,28,22,0,0,65,29,22,0,0,75,30,22,0,0,73,31,22,0,0,74,31,22,0,0,76,23,32,0,0,66,33,32,0,0,67,15,32,0,0,70,15,32,0,0,169,1,34,35,0,0,114,36,3,0,0,117,37,3,0,0,35,38,3,0,0,116,39,3,0,0,133,1,40,3,0,0,115,41,3,0,0,34,42,14,0,0,26,43,3,0,0,38,44,45,0,0,39,46,47,0,0,40,48,49,0,0,37,50,49,0,0,51,51,3,0,0,54,52,3,0,0,144,1,26,14,0,0,24,13,42,0,0,90,15,18,0,0,87,53,18,0,1,49,111,81,1,0,1,59,80,81,1,0,1,89,79,18,1,0,1,100,3,111,1,0,1,132,1,81,111,1,0,2,41,82,18,1,0,2,86,125,18,1,0,2,121,97,81,1,0,3,96,56,66,0,4,50,148,1,3,1,0,4,92,149,1,14,1,0,4,134,1,147,1,148,1,1,0,4,164,1,84,14,1,0,5,53,81,3,1,3,6,77,110,16,1,8,7,96,103,104,1,2,7,97,101,102,1,2,7,112,105,101,1,2,9,25,60,3,2,7,4,9,32,68,87,2,7,4,9,33,73,89,2,7,4,9,41,68,18,2,7,4,9,96,56,57,2,7,4,9,121,73,74,2,7,4,10,32,109,110,1,4,10,33,114,115,1,4,10,55,56,61,1,4,10,86,106,18,1,4,10,94,106,14,1,4,10,111,135,1,81,1,4,10,118,77,3,1,4,11,56,72,14,0,11,129,1,72,59,0,12,41,93,18,2,1,0,12,55,3,65,2,1,0,12,64,93,87,2,1,0,12,69,94,89,2,1,0,12,79,96,3,2,1,0,12,86,130,1,18,2,1,0,12,93,130,1,131,1,2,1,0,12,110,142,1,95,2,1,0,12,121,94,95,2,1,0,12,131,1,130,1,14,2,1,0,13,41,132,1,18,1,3,13,80,143,1,131,1,1,3,13,86,134,1,18,1,3,13,121,133,1,3,1,3,14,106,86,16,0,15,23,75,3,0,15,26,22,3,0,15,36,32,14,0,15,45,75,3,0,15,46,150,1,3,0,15,52,22,3,0,15,62,32,14,0,15,82,108,18,0,15,88,32,18,0,15,102,32,123,0,15,109,152,1,153,1,0,15,115,138,1,3,0,15,122,85,3,0,15,127,75,3,0,15,128,1,88,3,0,15,136,1,32,14,0,15,138,1,32,16,0,15,142,1,32,59,0,15,150,1,32,14,0,15,170,1,32,14,0,16,98,121,35,0,16,153,1,121,117,0,16,168,1,116,117,0,17,44,69,70,0,17,48,70,58,0,17,95,90,22,0,18,119,3,14,0,18,130,1,43,3,0,18,151,1,3,14,0,79,55,75,55,83,58,79,62,79,63,91,64,78,63,75,63,80,63,80,55,75,62,87,58,59,14,58,14,62,14,69,83,78,55,76,55,78,62,77,62,90,64,98,64,93,64,94,64,64,58,73,14,72,14,74,14,85,58,81,58,77,63,61,14,60,14,57,14,82,58,71,122,63,14,70,127,90,129,1,98,129,1,96,129,1,93,129,1,100,59,103,59,102,59,84,58,86,58,70,136,1,91,98,94,98,95,129,1,97,129,1,101,59,99,98,90,98,92,98,68,83,67,83,66,83,92,129,1,62,59,70,154,1,2,10,8,19,7,8,14,1,8,0,3,7,8,0,8,19,7,8,14,0,2,7,8,0,7,8,14,3,7,8,0,3,7,8,14,2,6,8,0,6,8,19,4,7,8,0,5,11,7,1,8,11,7,8,14,3,7,8,0,8,18,7,8,14,3,7,8,0,3,6,8,14,9,7,8,0,7,11,7,1,8,11,7,11,7,1,8,11,7,11,15,2,5,11,16,1,5,3,3,3,3,7,8,14,6,7,8,0,3,3,3,7,11,15,2,5,11,16,1,5,7,8,14,1,7,8,0,1,6,8,0,1,3,2,6,8,0,5,1,8,8,1,6,11,12,2,8,8,5,1,1,2,6,10,8,19,6,8,19,2,6,11,13,1,8,19,6,8,19,2,7,8,0,5,1,7,8,19,2,6,10,8,19,5,1,11,5,1,3,2,6,11,13,1,8,19,5,2,6,10,8,19,6,10,5,1,10,3,2,7,10,8,19,5,3,7,8,0,5,1,3,7,8,0,6,8,21,1,2,7,8,0,6,8,14,1,6,8,19,3,7,8,0,5,2,3,7,8,0,6,8,20,2,1,8,21,3,7,8,0,7,11,15,2,5,11,16,1,5,7,8,14,5,7,8,0,8,19,7,11,15,2,5,11,16,1,5,1,7,8,14,2,7,11,15,2,5,11,16,1,5,5,2,7,8,0,3,1,7,10,3,2,7,10,8,19,7,8,14,1,6,10,8,19,1,7,10,8,19,4,10,3,3,6,10,3,6,10,3,4,3,11,15,2,3,3,3,11,15,2,3,3,2,6,8,0,11,15,2,5,11,16,1,5,1,10,5,4,6,10,8,19,3,3,3,2,10,3,10,3,9,6,10,8,19,3,3,10,3,10,3,3,11,15,2,3,3,3,11,15,2,3,3,6,7,10,8,19,6,10,3,6,10,3,7,11,7,1,8,11,7,11,7,1,8,11,7,8,14,6,3,6,10,8,19,6,10,3,6,10,3,6,11,15,2,5,11,16,1,5,6,10,5,2,6,8,0,8,8,6,3,3,11,12,2,8,8,5,3,6,8,19,8,0,2,8,8,5,1,7,8,14,1,11,12,2,9,0,9,1,1,8,19,1,5,3,7,11,12,2,9,0,9,1,9,0,9,1,1,11,13,1,9,0,2,8,8,8,22,2,5,8,22,2,5,3,1,11,15,2,9,0,9,1,1,8,6,4,6,8,19,6,8,19,1,5,2,6,11,12,2,9,0,9,1,9,0,2,8,19,7,8,14,1,8,22,3,8,8,8,19,5,1,6,8,14,2,7,11,12,2,9,0,9,1,9,0,1,9,1,2,7,8,19,3,5,6,8,19,6,8,19,1,8,19,5,2,7,11,13,1,9,0,9,0,3,5,3,11,5,1,3,1,6,11,5,1,9,0,1,7,11,5,1,9,0,1,9,0,2,6,10,9,0,6,9,0,1,8,11,1,6,11,7,1,9,0,4,7,8,19,11,7,1,8,11,5,7,8,14,1,6,8,18,1,6,9,1,3,7,8,19,8,18,7,8,14,1,7,9,1,1,7,8,22,14,11,15,2,5,11,16,1,5,6,10,5,10,3,10,3,11,15,2,3,3,11,15,2,3,3,3,10,5,3,3,3,3,10,3,10,3,8,3,3,7,3,3,8,19,8,19,5,6,8,19,2,6,11,15,2,9,0,9,1,6,9,0,2,7,11,15,2,9,0,9,1,6,9,0,2,9,0,9,1,3,7,11,15,2,9,0,9,1,9,0,9,1,2,7,10,9,0,3,2,3,3,10,10,11,9,1,3,3,3,11,10,1,3,3,3,3,3,6,8,19,6,10,8,19,1,11,9,1,3,2,3,9,0,1,11,9,1,9,0,1,10,11,9,1,9,0,1,11,10,1,9,0,1,7,11,10,1,9,0,1,6,11,13,1,9,0,3,3,3,3,2,6,8,19,6,8,19,2,6,11,13,1,9,0,3,1,6,9,0,1,11,5,1,9,0,5,5,3,11,5,1,3,3,10,3,4,3,3,11,5,1,3,11,5,1,3,2,7,11,13,1,9,0,3,1,7,9,0,1,6,8,21,1,6,5,2,3,11,5,1,3,6,1,1,3,3,11,5,1,3,11,5,1,3,5,5,6,8,19,8,8,5,6,8,19,1,6,8,20,1,8,20,1,6,8,8,2,3,8,19,1,6,10,9,0,3,3,5,8,8,1,8,4,7,6,5,6,5,3,3,6,5,10,5,7,11,16,1,5,2,5,11,16,1,5,1,6,11,15,2,9,0,9,1,1,10,9,0,2,6,11,16,1,9,0,6,9,0,2,7,11,16,1,9,0,6,9,0,1,6,11,16,1,9,0,1,7,11,13,1,9,0,1,8,3,6,3,3,3,3,3,3,2,7,8,19,7,8,14,4,3,3,3,6,8,19,7,11,15,2,3,3,11,15,2,3,3,4,4,3,3,3,5,10,5,6,10,8,19,11,16,1,5,10,5,5,1,7,11,15,2,9,0,9,1,1,11,16,1,9,0,6,3,3,4,10,3,10,3,3,17,3,3,3,10,3,3,10,3,3,4,3,3,3,3,3,3,3,3,4,8,3,3,11,7,1,8,11,3,7,8,19,5,4,11,7,1,8,11,2,7,11,7,1,9,0,3,1,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,2,7,8,19,11,7,1,8,11,8,10,5,3,3,3,3,10,5,6,8,19,5,2,6,8,19,3,1,8,17,1,8,2,3,66,97,103,7,66,97,108,97,110,99,101,5,69,110,116,114,121,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,13,80,114,105,111,114,105,116,121,81,117,101,117,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,23,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,25,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,86,50,18,86,97,108,105,100,97,116,111,114,74,111,105,110,69,118,101,110,116,19,86,97,108,105,100,97,116,111,114,76,101,97,118,101,69,118,101,110,116,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,6,86,101,99,77,97,112,6,86,101,99,83,101,116,8,97,99,116,105,118,97,116,101,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,3,97,100,100,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,18,97,116,95,114,105,115,107,95,118,97,108,105,100,97,116,111,114,115,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,22,99,97,108,99,117,108,97,116,101,95,116,111,116,97,108,95,115,116,97,107,101,115,38,99,108,101,97,110,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,95,108,101,97,118,105,110,103,95,118,97,108,105,100,97,116,111,114,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,36,99,111,109,112,117,116,101,95,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,26,99,111,109,112,117,116,101,95,114,101,119,97,114,100,95,97,100,106,117,115,116,109,101,110,116,115,26,99,111,109,112,117,116,101,95,115,108,97,115,104,101,100,95,118,97,108,105,100,97,116,111,114,115,38,99,111,109,112,117,116,101,95,117,110,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,8,99,111,110,116,97,105,110,115,25,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,116,97,98,108,101,118,101,99,20,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,118,101,99,9,99,114,101,97,116,101,95,118,49,10,100,101,97,99,116,105,118,97,116,101,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,17,100,105,115,116,114,105,98,117,116,101,95,114,101,119,97,114,100,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,27,101,109,105,116,95,118,97,108,105,100,97,116,111,114,95,101,112,111,99,104,95,101,118,101,110,116,115,5,101,109,112,116,121,5,101,112,111,99,104,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,14,102,105,110,100,95,118,97,108,105,100,97,116,111,114,29,102,105,110,100,95,118,97,108,105,100,97,116,111,114,95,102,114,111,109,95,116,97,98,108,101,95,118,101,99,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,3,103,101,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,24,103,101,116,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,37,103,101,116,95,99,97,110,100,105,100,97,116,101,95,111,114,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,7,103,101,116,95,109,117,116,25,103,101,116,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,95,114,101,102,21,103,101,116,95,118,97,108,105,100,97,116,111,114,95,105,110,100,105,99,101,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,114,101,102,2,105,100,19,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,12,105,115,95,100,117,112,108,105,99,97,116,101,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,34,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,35,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,21,105,115,95,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,22,105,115,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,12,105,115,95,118,111,108,117,110,116,97,114,121,4,106,111,105,110,4,107,101,121,115,6,108,101,110,103,116,104,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,25,112,101,110,100,105,110,103,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,16,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,7,112,111,111,108,95,105,100,19,112,111,111,108,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,24,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,3,112,111,112,8,112,111,112,95,98,97,99,107,7,112,111,112,95,109,97,120,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,24,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,26,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,115,27,112,114,111,99,101,115,115,95,118,97,108,105,100,97,116,111,114,95,100,101,112,97,114,116,117,114,101,9,112,117,115,104,95,98,97,99,107,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,26,114,101,102,101,114,101,110,99,101,95,103,97,115,95,115,117,114,118,101,121,95,113,117,111,116,101,6,114,101,109,111,118,101,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,6,115,101,110,100,101,114,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,105,122,101,4,115,111,109,101,17,115,111,114,116,95,114,101,109,111,118,97,108,95,108,105,115,116,5,115,112,108,105,116,5,115,116,97,107,101,12,115,116,97,107,101,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,27,115,116,111,114,97,103,101,95,102,117,110,100,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,29,115,117,109,95,118,111,116,105,110,103,95,112,111,119,101,114,95,98,121,95,97,100,100,114,101,115,115,101,115,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,26,116,97,108,108,121,105,110,103,95,114,117,108,101,95,103,108,111,98,97,108,95,115,99,111,114,101,23,116,97,108,108,121,105,110,103,95,114,117,108,101,95,114,101,112,111,114,116,101,114,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,39,117,112,100,97,116,101,95,97,110,100,95,112,114,111,99,101,115,115,95,108,111,119,95,115,116,97,107,101,95,100,101,112,97,114,116,117,114,101,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,20,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,10,3,1,0,10,5,1,0,0,2,9,149,1,3,24,10,8,19,104,11,13,1,8,19,105,10,3,139,1,11,12,2,8,8,5,78,11,12,2,8,8,8,22,157,1,11,12,2,5,8,22,29,11,15,2,5,3,58,8,6,1,2,10,56,3,156,1,5,120,3,135,1,3,36,3,107,3,140,1,3,108,8,17,148,1,10,5,147,1,3,2,2,11,56,3,156,1,5,120,3,135,1,3,170,1,3,36,3,107,3,140,1,3,108,8,17,148,1,10,5,147,1,3,3,2,3,56,3,156,1,5,138,1,8,8,4,2,4,56,3,156,1,5,138,1,8,8,91,1,0,3,0,0,54,51,14,0,17,45,12,5,10,1,56,0,12,4,14,0,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,16,14,0,10,2,66,58,12,6,13,4,10,6,17,121,11,6,17,122,56,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,11,5,11,0,10,1,56,2,64,14,0,0,0,0,0,0,0,0,11,4,10,1,56,3,10,1,56,4,56,5,11,1,17,65,18,0,12,7,13,7,15,0,17,132,1,11,7,2,1,3,0,0,67,69,10,0,14,1,12,3,46,11,3,17,20,32,4,17,10,0,14,1,12,4,46,11,4,17,23,32,12,5,5,19,9,12,5,11,5,4,22,5,28,11,0,1,11,2,1,7,7,39,14,1,17,122,12,6,10,0,16,1,10,6,56,6,32,4,38,5,44,11,0,1,11,2,1,7,11,39,14,1,17,113,4,48,5,54,11,0,1,11,2,1,7,12,39,10,0,15,2,14,1,17,121,11,6,56,1,11,0,15,1,14,1,17,122,11,1,11,2,17,128,1,56,7,2,2,3,0,0,71,53,10,1,46,17,89,12,4,10,0,16,1,10,4,56,6,4,10,5,16,11,0,1,11,1,1,7,13,39,10,0,15,1,11,4,56,8,17,129,1,12,3,14,3,17,113,4,26,5,32,11,0,1,11,1,1,7,12,39,14,3,17,121,12,2,10,0,15,2,10,2,56,9,1,13,3,10,1,46,17,88,17,108,11,0,15,3,11,2,11,3,11,1,17,128,1,56,10,2,3,3,0,0,76,69,11,2,46,17,89,12,7,10,0,16,1,10,7,56,6,4,10,5,14,11,0,1,7,13,39,10,0,15,1,11,7,56,8,17,129,1,12,6,10,0,14,6,12,3,46,11,3,17,20,32,4,37,10,0,14,6,12,4,46,11,4,17,23,32,12,5,5,39,9,12,5,11,5,4,42,5,46,11,0,1,7,7,39,14,6,17,113,4,50,5,54,11,0,1,7,12,39,14,6,17,123,11,1,38,4,60,5,64,11,0,1,7,10,39,11,0,15,4,11,6,56,11,2,4,3,0,0,3,16,10,0,16,0,10,1,17,22,11,0,16,4,11,1,17,24,22,6,1,0,0,0,0,0,0,0,33,4,13,5,15,7,7,39,2,5,3,0,0,78,36,11,1,46,17,89,12,2,10,0,16,0,11,2,17,26,12,4,14,4,56,12,4,13,5,17,11,0,1,7,9,39,13,4,56,13,12,3,10,0,16,5,14,3,56,14,32,4,27,5,31,11,0,1,7,16,39,11,0,15,5,11,3,68,14,2,6,3,0,0,3,22,14,2,56,15,7,4,38,4,6,5,12,11,0,1,11,3,1,7,15,39,11,0,11,1,17,25,11,2,10,3,46,17,89,11,3,17,117,2,7,3,0,0,55,43,14,1,17,104,12,3,10,0,16,2,10,3,56,16,4,22,10,0,16,2,14,1,17,104,56,17,20,12,4,11,0,11,4,17,25,11,1,11,2,17,119,5,42,10,0,16,3,10,3,56,18,4,28,5,34,11,0,1,11,2,1,7,8,39,11,0,15,3,11,3,56,19,17,130,1,11,1,11,2,17,119,2,8,3,0,0,59,10,11,2,17,89,12,3,11,0,15,0,11,3,17,29,11,1,17,118,2,9,3,0,0,91,110,10,8,46,17,88,6,1,0,0,0,0,0,0,0,22,12,15,17,133,1,12,20,10,0,16,0,10,20,10,1,46,56,15,10,2,46,56,15,17,49,12,22,12,21,10,0,10,3,20,12,9,46,11,9,17,48,12,16,10,0,16,0,14,16,17,53,12,17,10,0,16,0,14,16,17,28,11,4,14,21,14,22,17,47,12,14,12,19,12,13,12,18,10,0,16,0,11,20,11,17,11,21,11,22,11,18,11,13,11,19,11,14,17,50,12,12,12,11,10,0,15,0,14,11,14,12,11,1,11,2,10,8,17,51,10,0,15,0,17,46,10,0,15,0,10,8,17,44,10,15,10,0,16,0,14,11,14,12,10,3,14,16,12,10,46,11,10,17,52,10,0,11,15,17,42,10,0,10,3,10,8,17,39,10,0,11,5,11,6,11,7,11,3,11,8,17,10,10,0,16,0,17,45,10,0,15,6,21,10,0,15,0,17,132,1,11,0,17,11,2,10,0,0,0,92,106,10,0,16,0,65,58,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,99,5,9,11,7,6,1,0,0,0,0,0,0,0,23,12,7,10,0,16,0,10,7,66,58,12,13,10,13,17,122,12,12,11,13,17,123,12,9,10,9,10,1,38,4,40,10,0,16,7,14,12,56,20,4,39,10,0,15,7,14,12,56,21,1,1,5,98,11,9,10,2,38,4,87,10,0,16,7,14,12,56,20,4,64,10,0,15,7,14,12,56,22,12,8,10,8,20,6,1,0,0,0,0,0,0,0,22,10,8,21,11,8,20,12,6,5,71,10,0,15,7,11,12,6,1,0,0,0,0,0,0,0,56,23,6,1,0,0,0,0,0,0,0,12,6,11,6,10,3,36,4,86,10,0,15,0,10,7,56,24,12,10,10,0,11,10,10,4,9,10,5,17,40,5,98,10,0,15,0,10,7,56,24,12,11,10,0,11,11,10,4,9,10,5,17,40,5,4,11,4,1,11,0,1,11,5,1,2,11,0,0,0,98,24,10,0,16,0,65,58,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,21,5,11,10,0,15,0,10,1,67,58,17,110,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,12,1,0,0,99,60,11,0,16,0,12,10,10,10,65,58,12,3,64,100,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,15,10,10,10,2,66,58,12,9,13,1,10,9,17,111,11,9,17,124,56,25,68,100,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,10,11,10,1,11,1,56,26,12,4,6,0,0,0,0,0,0,0,0,12,7,17,133,1,17,131,1,23,12,8,6,0,0,0,0,0,0,0,0,12,5,10,7,10,8,35,4,58,5,49,13,4,56,27,12,6,12,5,11,7,11,6,22,12,7,5,44,11,5,2,13,1,0,0,3,4,11,0,16,6,20,2,14,1,0,0,3,6,11,0,16,0,11,1,17,34,17,123,2,15,1,0,0,3,6,11,0,16,0,11,1,17,34,17,120,2,16,1,0,0,3,6,11,0,16,0,11,1,17,34,17,121,2,17,1,0,0,3,3,11,0,16,2,2,18,3,0,0,3,12,10,0,16,0,65,58,10,0,16,5,65,14,23,11,0,16,4,56,28,22,2,19,3,0,0,24,8,11,0,16,0,11,1,17,26,12,2,14,2,56,12,2,20,0,0,0,3,5,11,0,16,0,11,1,17,21,2,21,3,0,0,3,6,11,0,11,1,17,22,6,0,0,0,0,0,0,0,0,36,2,22,0,0,0,107,33,10,0,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,66,58,10,1,17,112,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,23,0,0,0,3,7,11,0,16,4,11,1,17,24,6,0,0,0,0,0,0,0,0,36,2,24,0,0,0,107,33,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,56,29,10,1,17,112,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,25,0,0,0,3,16,10,0,16,1,10,1,56,6,4,11,11,0,15,1,11,1,56,30,17,130,1,2,11,0,15,0,11,1,17,29,2,26,0,0,0,98,31,10,0,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,66,58,17,122,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,27,0,0,0,98,31,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,56,29,17,122,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,28,0,0,0,112,46,10,1,65,59,12,5,6,0,0,0,0,0,0,0,0,12,3,7,20,12,6,10,3,10,5,35,4,40,5,12,10,1,10,3,66,59,20,12,2,10,0,11,2,17,26,12,4,14,4,56,12,4,25,5,31,11,0,1,11,1,1,7,9,39,13,6,11,4,56,33,68,14,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,0,1,11,1,1,11,6,2,29,3,0,0,78,22,10,0,11,1,12,2,46,11,2,17,26,12,4,14,4,56,12,4,11,5,15,11,0,1,7,9,39,13,4,56,13,12,3,11,0,11,3,67,58,2,30,0,0,0,113,45,10,0,16,0,10,1,17,26,12,5,14,5,56,12,4,16,13,5,56,13,12,3,11,0,15,0,11,3,67,58,2,10,0,16,4,10,1,17,27,12,6,14,6,56,12,4,32,13,6,56,13,12,4,11,0,15,4,11,4,56,34,2,11,2,4,35,5,39,11,0,1,7,14,39,11,0,15,1,11,1,56,30,17,130,1,2,31,3,0,0,3,7,11,0,11,1,17,127,20,11,2,17,30,2,32,3,0,0,59,8,11,1,17,89,12,2,11,0,11,2,9,17,30,2,33,3,0,0,59,8,11,1,17,89,12,2,11,0,11,2,8,17,30,2,34,0,0,0,118,19,10,0,11,1,17,26,12,3,14,3,56,12,4,8,5,12,11,0,1,7,9,39,13,3,56,13,12,2,11,0,11,2,66,58,2,35,3,0,0,119,57,10,0,16,0,10,1,17,26,12,7,14,7,56,12,4,11,8,12,3,5,15,10,2,7,0,33,12,3,11,3,4,25,13,7,56,13,12,5,11,0,16,0,11,5,66,58,2,10,0,16,4,10,1,17,27,12,8,14,8,56,12,4,36,8,12,4,5,40,11,2,7,1,33,12,4,11,4,4,50,13,8,56,13,12,6,11,0,16,4,11,6,56,29,2,11,0,15,1,11,1,56,30,17,130,1,46,2,36,1,0,0,118,21,10,0,16,0,11,1,17,26,12,3,14,3,56,12,4,9,5,13,11,0,1,7,9,39,13,3,56,13,12,2,11,0,16,0,11,2,66,58,2,37,1,0,0,118,21,10,0,16,4,11,1,17,27,12,3,14,3,56,12,4,9,5,13,11,0,1,7,17,39,13,3,56,13,12,2,11,0,16,4,11,2,56,29,2,38,3,0,0,120,39,10,1,17,126,20,12,6,10,2,7,0,33,4,16,11,0,11,6,12,3,46,11,3,17,36,12,4,5,21,11,0,11,6,11,2,17,35,12,4,11,4,12,7,10,1,56,35,12,5,11,7,17,114,14,5,33,4,32,5,36,11,1,1,7,19,39,11,1,17,125,2,39,0,0,0,124,32,10,0,15,5,17,43,10,0,16,5,56,36,32,4,25,5,9,10,0,15,5,69,14,12,3,10,0,15,0,11,3,56,24,12,4,10,0,11,4,10,1,8,10,2,17,40,5,3,11,1,1,11,0,1,11,2,1,2,40,0,0,0,126,58,10,4,46,17,88,6,1,0,0,0,0,0,0,0,22,12,5,14,1,17,122,12,6,14,1,17,121,12,7,10,0,15,2,10,7,56,9,1,10,0,16,7,14,6,56,20,4,28,10,0,15,7,14,6,56,21,1,1,10,0,16,6,20,14,1,17,123,23,10,0,15,6,21,11,2,10,6,17,41,10,5,11,6,14,1,17,121,11,3,18,4,56,37,13,1,11,5,17,108,11,0,15,3,11,7,11,1,11,4,17,128,1,56,10,2,41,0,0,0,128,1,69,10,0,14,1,12,2,46,11,2,56,38,4,12,10,0,14,1,56,39,1,1,10,0,46,56,40,12,7,14,7,65,59,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,66,5,26,14,7,10,4,66,59,12,6,10,0,10,6,56,41,12,8,10,8,14,1,12,3,46,11,3,56,42,4,57,10,8,14,1,56,43,11,8,46,56,44,4,54,10,0,11,6,56,39,1,1,5,56,11,6,1,5,61,11,8,1,11,6,1,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,21,11,0,1,2,42,0,0,0,58,28,10,0,16,4,56,45,32,4,25,5,6,10,0,15,4,56,46,12,2,13,2,10,1,17,105,10,1,14,2,17,122,14,2,17,121,18,3,56,47,10,0,15,0,11,2,68,58,5,0,11,0,1,2,43,0,0,0,137,1,57,10,0,46,65,14,12,6,6,1,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,54,5,11,10,0,10,4,12,1,46,11,1,66,14,20,12,3,10,4,12,5,10,5,6,0,0,0,0,0,0,0,0,36,4,49,5,26,11,5,6,1,0,0,0,0,0,0,0,23,12,5,10,0,10,5,12,2,46,11,2,66,14,20,10,3,36,4,41,5,42,5,49,10,0,10,5,10,5,6,1,0,0,0,0,0,0,0,22,71,14,5,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,1,2,44,0,0,0,98,26,10,0,46,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,21,5,11,10,0,10,2,67,58,10,1,17,116,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,11,1,1,2,45,0,0,0,139,1,30,6,0,0,0,0,0,0,0,0,12,3,10,0,65,58,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,26,5,12,10,0,10,1,66,58,12,4,11,3,11,4,17,123,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,46,0,0,0,98,23,10,0,46,65,58,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,20,5,11,10,0,10,1,67,58,17,106,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,47,0,0,0,140,1,69,6,0,0,0,0,0,0,0,0,12,8,56,48,12,4,6,0,0,0,0,0,0,0,0,12,9,56,48,12,5,13,0,46,56,36,32,4,60,5,14,13,0,69,14,12,10,10,2,10,10,66,14,20,53,10,1,53,24,7,3,26,12,6,13,4,10,10,10,6,52,56,49,11,8,11,6,52,22,12,8,10,3,10,10,66,14,20,53,10,1,53,24,7,3,26,12,7,13,5,11,10,10,7,52,56,49,11,9,11,7,52,22,12,9,5,8,11,3,1,11,2,1,11,8,11,4,11,9,11,5,2,48,0,0,0,141,1,40,7,21,12,5,14,1,56,50,32,4,36,5,7,13,1,56,51,12,4,12,6,10,0,10,6,17,19,4,16,5,20,11,0,1,7,5,39,10,0,16,0,12,3,11,4,56,52,12,2,11,3,14,2,17,53,17,131,1,38,4,35,13,5,11,6,68,59,5,2,11,0,1,11,5,2,49,0,0,0,144,1,47,64,14,0,0,0,0,0,0,0,0,12,7,64,14,0,0,0,0,0,0,0,0,12,8,10,0,65,58,12,5,11,3,10,5,26,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,42,5,18,10,0,10,4,66,58,17,124,53,10,2,53,24,10,1,53,26,12,6,13,7,11,6,52,68,14,13,8,10,9,68,14,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,13,11,0,1,11,7,11,8,2,50,0,0,0,145,1,108,11,1,11,2,23,12,22,64,14,0,0,0,0,0,0,0,0,12,12,64,14,0,0,0,0,0,0,0,0,12,14,10,0,65,58,12,20,10,20,14,6,56,53,23,12,21,6,0,0,0,0,0,0,0,0,12,19,10,19,10,20,35,4,103,5,23,10,0,10,19,66,58,17,124,53,12,25,14,3,10,19,66,14,20,12,23,14,6,14,19,56,54,4,48,14,6,14,19,56,55,20,12,15,11,23,11,15,23,12,9,5,61,10,5,53,11,25,24,10,22,53,26,12,16,11,23,11,16,52,22,12,9,11,9,12,11,13,12,11,11,68,14,14,4,10,19,66,14,20,12,24,14,8,14,19,56,54,4,85,14,8,14,19,56,55,20,12,17,11,24,11,17,23,12,10,5,93,10,7,10,21,26,12,18,11,24,11,18,22,12,10,11,10,12,13,13,14,11,13,68,14,11,19,6,1,0,0,0,0,0,0,0,22,12,19,5,18,11,0,1,11,12,11,14,2,51,0,0,0,146,1,105,10,0,46,65,58,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,9,5,23,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,7,18,39,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,92,5,30,10,0,10,6,67,58,12,10,10,1,10,6,66,14,20,12,9,10,3,10,9,56,56,12,8,11,9,53,10,10,46,17,107,53,24,7,3,26,12,12,13,8,11,12,52,56,56,12,13,13,13,10,4,10,2,10,6,66,14,20,56,56,56,57,1,14,13,56,15,6,0,0,0,0,0,0,0,0,36,4,82,10,10,46,17,122,12,11,10,10,11,13,11,11,10,5,17,117,5,84,11,13,56,58,11,10,11,8,17,109,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,25,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,2,52,0,0,0,151,1,84,10,1,65,58,12,9,6,0,0,0,0,0,0,0,0,12,8,10,8,10,9,35,4,73,5,10,10,1,10,8,66,58,12,12,10,12,17,122,12,13,10,4,14,13,56,38,4,28,10,4,14,13,56,59,20,56,52,12,6,5,30,7,21,12,6,11,6,12,11,10,5,14,13,56,60,4,39,6,0,0,0,0,0,0,0,0,12,7,5,41,6,1,0,0,0,0,0,0,0,12,7,11,7,12,10,10,0,11,13,10,12,17,111,10,12,17,123,10,12,17,124,10,12,17,107,10,2,10,8,66,14,20,10,3,10,8,66,14,20,11,12,10,0,17,115,11,11,11,10,18,2,56,61,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,5,11,1,1,11,3,1,11,5,1,11,4,1,11,2,1,2,53,1,0,0,139,1,35,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,1,65,59,12,3,10,2,10,3,35,4,29,5,12,10,0,10,1,10,2,66,59,20,17,34,12,5,11,4,11,5,17,124,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,54,1,0,0,3,3,11,0,16,0,2,55,1,0,0,3,5,11,0,16,1,11,1,56,6,2,56,1,0,0,3,5,11,0,16,3,11,1,56,18,2,0,1,0,6,0,4,0,5,0,2,0,3,0,0,0,7,0,63,0,143,1,0],"validator_wrapper":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,16,3,24,48,4,72,6,5,78,52,7,130,1,211,1,8,213,2,64,6,149,3,10,10,159,3,6,12,165,3,100,13,137,4,2,15,139,4,2,0,14,1,10,1,16,0,12,0,2,4,0,1,0,2,0,2,3,12,0,3,1,4,0,0,5,0,1,0,0,8,2,3,0,0,6,1,4,0,0,11,2,5,0,0,15,6,7,0,2,4,8,9,1,4,2,6,9,12,1,4,2,9,10,11,1,4,2,15,13,7,0,5,4,7,4,6,4,2,8,3,7,8,1,1,8,0,1,7,8,0,1,7,8,3,1,8,3,0,1,6,8,0,1,3,3,3,9,0,7,8,1,1,8,2,1,7,8,2,1,7,9,0,1,9,0,1,6,8,2,9,84,120,67,111,110,116,101,120,116,9,86,97,108,105,100,97,116,111,114,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,9,86,101,114,115,105,111,110,101,100,6,99,114,101,97,116,101,9,99,114,101,97,116,101,95,118,49,7,100,101,115,116,114,111,121,5,105,110,110,101,114,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,10,116,120,95,99,111,110,116,101,120,116,17,117,112,103,114,97,100,101,95,116,111,95,108,97,116,101,115,116,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,1,7,8,2,0,3,0,0,5,6,6,1,0,0,0,0,0,0,0,11,0,11,1,56,0,18,0,2,1,3,0,0,5,6,10,0,17,3,11,0,15,0,56,1,2,2,3,0,0,5,6,13,0,17,3,11,0,19,0,56,2,2,3,0,0,0,5,10,11,0,46,17,4,6,1,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,2,4,0,0,0,5,4,11,0,16,0,17,8,2,0,0,0,13,0],"voting_power":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,87,4,107,4,5,111,134,1,7,245,1,176,2,8,165,4,96,6,133,5,70,10,203,5,16,12,219,5,254,6,13,217,12,4,15,221,12,2,0,22,1,21,2,9,0,18,0,1,2,0,0,2,2,0,3,0,4,0,0,13,0,1,0,0,6,2,3,0,0,15,4,5,0,0,7,6,1,0,0,3,7,1,0,0,17,8,1,0,0,4,4,1,0,0,16,1,5,0,0,12,1,5,0,1,7,17,1,1,0,1,8,19,20,1,0,2,5,11,5,0,2,10,11,5,0,2,11,11,5,0,3,13,21,1,0,3,15,14,5,0,3,22,14,5,0,9,13,10,13,1,7,10,8,2,0,2,6,10,8,2,3,2,10,8,1,3,1,6,10,8,2,1,3,2,7,10,8,1,8,1,3,7,10,8,1,3,3,2,7,10,8,2,10,8,1,4,3,10,8,1,3,3,1,8,2,2,3,3,8,3,8,1,3,10,8,1,3,3,3,3,1,8,1,1,6,8,2,3,3,3,3,4,3,1,3,3,3,7,10,9,0,9,0,3,7,1,3,3,3,3,3,7,8,1,1,6,10,9,0,1,1,2,7,8,2,3,12,3,3,3,3,3,3,3,3,3,6,8,2,6,8,2,3,9,86,97,108,105,100,97,116,111,114,15,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,17,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,86,50,19,97,100,106,117,115,116,95,118,111,116,105,110,103,95,112,111,119,101,114,16,99,104,101,99,107,95,105,110,118,97,114,105,97,110,116,115,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,22,105,110,105,116,95,118,111,116,105,110,103,95,112,111,119,101,114,95,105,110,102,111,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,4,109,97,116,104,3,109,97,120,3,109,105,110,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,5,115,116,97,107,101,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,19,117,112,100,97,116,101,95,118,111,116,105,110,103,95,112,111,119,101,114,9,118,97,108,105,100,97,116,111,114,15,118,97,108,105,100,97,116,111,114,95,105,110,100,101,120,13,118,97,108,105,100,97,116,111,114,95,115,101,116,6,118,101,99,116,111,114,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,16,39,0,0,0,0,0,0,3,8,11,26,0,0,0,0,0,0,3,8,232,3,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,2,19,3,22,3,1,2,3,19,3,22,3,14,3,0,3,0,0,9,29,7,0,7,2,7,0,10,0,46,65,10,17,11,17,12,17,13,12,4,10,0,10,4,12,1,46,11,1,17,1,12,3,12,2,13,2,11,4,11,3,17,4,10,0,11,2,17,5,11,0,46,17,6,2,1,0,0,0,12,58,10,0,17,2,12,8,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,7,64,13,0,0,0,0,0,0,0,0,12,5,10,2,10,4,35,4,51,5,17,10,0,10,2,66,10,17,15,12,6,10,6,53,7,0,53,24,10,8,53,26,52,10,1,17,13,12,9,10,2,10,9,11,6,18,1,12,3,13,5,11,3,17,3,11,7,11,9,22,12,7,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,0,1,11,5,7,0,11,7,23,2,2,0,0,0,15,28,6,0,0,0,0,0,0,0,0,12,1,10,0,65,10,12,2,6,0,0,0,0,0,0,0,0,12,3,10,1,10,2,35,4,24,5,12,11,3,10,0,10,1,66,10,17,15,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,3,0,0,0,16,39,6,0,0,0,0,0,0,0,0,12,4,10,0,46,65,13,12,5,10,4,10,5,35,4,25,5,11,10,0,10,4,12,2,46,11,2,66,13,16,0,20,14,1,16,0,20,36,12,3,5,27,9,12,3,11,3,4,34,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,11,1,11,4,56,0,2,4,0,0,0,18,84,6,0,0,0,0,0,0,0,0,12,5,10,0,46,65,13,12,6,10,5,10,6,35,4,16,5,11,10,2,6,0,0,0,0,0,0,0,0,36,12,3,5,18,9,12,3,11,3,4,74,10,0,10,5,67,13,12,9,10,2,10,6,10,5,23,17,11,12,7,10,1,10,9,16,1,20,11,7,22,17,13,12,8,10,2,11,8,10,9,16,1,20,23,17,13,12,4,10,9,16,1,20,10,4,22,10,9,15,1,21,11,9,16,1,20,10,1,37,4,61,5,65,11,0,1,7,5,39,11,2,11,4,23,12,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,6,11,0,1,11,2,6,0,0,0,0,0,0,0,0,33,4,81,5,83,7,3,39,2,5,0,0,0,11,22,14,1,56,1,32,4,17,5,5,13,1,69,13,19,1,1,12,3,12,2,10,0,11,2,67,10,11,3,17,14,5,0,11,0,1,11,1,70,13,0,0,0,0,0,0,0,0,2,6,0,0,0,22,119,6,0,0,0,0,0,0,0,0,12,3,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,9,10,3,10,4,35,4,35,5,12,10,0,10,3,66,10,17,16,12,12,10,12,6,0,0,0,0,0,0,0,0,36,4,22,5,26,11,0,1,7,6,39,11,9,11,12,22,12,9,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,9,7,0,33,4,40,5,44,11,0,1,7,3,39,6,0,0,0,0,0,0,0,0,12,1,10,1,10,4,35,4,116,5,51,10,1,6,1,0,0,0,0,0,0,0,22,12,2,10,2,10,4,35,4,111,5,60,10,0,10,1,66,10,12,10,10,0,10,2,66,10,12,11,10,10,17,15,12,7,10,11,17,15,12,8,11,10,17,16,12,5,11,11,17,16,12,6,10,7,10,8,36,4,93,10,5,10,6,38,4,89,5,93,11,0,1,7,4,39,11,7,11,8,35,4,106,11,5,11,6,37,4,102,5,106,11,0,1,7,4,39,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,55,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,46,11,0,1,2,7,1,0,0,1,2,7,0,2,8,1,0,0,1,2,7,1,2,1,2,1,1,0,20,0]},"type_origin_table":[{"module_name":"validator_cap","struct_name":"UnverifiedValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_cap","struct_name":"ValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakingPool","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"PoolTokenExchangeRate","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakedIota","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"ValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"Validator","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"StakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"UnstakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfo","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfoV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_wrapper","struct_name":"ValidatorWrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorSet","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEventV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorJoinEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorLeaveEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"storage_fund","struct_name":"StorageFund","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"stake_subsidy","struct_name":"StakeSubsidy","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"SystemParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"SystemParametersV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"IotaSystemStateInner","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"IotaSystemStateInnerV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system_state_inner","struct_name":"SystemEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"iota_system","struct_name":"IotaSystemState","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisChainParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenDistributionSchedule","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenAllocation","package":"0x0000000000000000000000000000000000000000000000000000000000000003"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"DdYtSHED8qYakCvtPiThXfbiSHFJpFGJkYpbYfohRxxh","storage_rebate":0},{"data":{"Package":{"id":"0x000000000000000000000000000000000000000000000000000000000000dee9","version":5,"module_map":{"clob":[161,28,235,11,6,0,0,0,13,1,0,36,2,36,134,1,3,170,1,204,4,4,246,5,184,1,5,174,7,241,9,7,159,17,135,15,8,166,32,96,6,134,33,147,2,10,153,35,226,1,11,251,36,8,12,131,37,235,39,13,238,76,40,14,150,77,26,0,45,0,53,0,54,0,94,1,107,1,137,1,2,28,2,46,2,47,2,65,2,85,2,105,2,126,2,129,1,2,135,1,2,136,1,0,16,7,0,0,14,7,2,0,1,0,1,0,10,7,2,0,1,0,1,0,12,7,2,0,1,0,1,0,9,6,0,0,19,4,0,0,15,8,2,0,1,0,1,0,13,7,2,0,1,0,1,0,11,7,2,0,1,0,1,1,4,4,1,4,0,2,0,12,0,2,5,12,1,0,1,4,8,7,1,0,0,5,21,7,0,6,1,4,1,0,1,7,2,8,0,8,3,12,1,0,1,10,7,12,2,7,0,4,1,11,6,7,0,11,22,4,0,12,17,2,0,13,18,12,2,7,1,4,1,15,20,2,0,0,60,0,1,0,0,49,2,3,0,0,51,4,1,2,0,0,0,50,5,1,2,0,0,0,57,6,1,2,0,0,0,58,7,1,2,0,0,0,146,1,8,9,2,0,0,0,147,1,8,10,2,0,0,0,127,11,12,2,0,0,0,128,1,13,12,2,0,0,0,93,14,15,2,0,0,0,92,14,15,2,0,0,0,91,16,15,2,0,0,0,112,17,18,2,0,0,0,78,19,20,2,0,0,0,111,21,22,2,0,0,0,109,20,23,0,0,63,24,1,2,0,0,0,64,25,1,2,0,0,0,44,26,1,2,0,0,0,123,27,28,2,0,0,0,43,29,1,2,0,0,0,36,30,1,2,0,0,0,86,31,32,2,0,0,0,24,31,33,2,0,0,0,74,34,35,2,0,0,0,73,34,35,2,0,0,0,72,36,20,2,0,0,0,75,37,38,2,0,0,1,39,84,60,1,4,1,40,84,60,1,4,1,42,71,72,1,4,1,67,84,20,1,4,1,68,84,78,1,4,1,79,91,20,1,4,1,82,70,23,1,4,1,95,70,46,1,4,1,96,70,46,1,4,1,100,2,50,1,4,1,104,84,46,1,4,1,114,84,46,1,4,1,122,71,43,1,4,2,23,97,20,1,0,2,24,97,46,1,0,2,55,90,54,1,0,2,56,77,54,1,0,2,77,62,1,1,0,2,87,90,1,1,0,2,97,2,3,0,2,100,2,53,1,0,2,139,1,77,1,1,0,2,145,1,63,9,1,0,3,61,46,78,0,3,98,46,20,0,3,99,46,78,0,3,140,1,46,78,0,3,141,1,46,20,0,3,142,1,46,78,0,4,38,74,60,1,0,4,83,74,23,1,0,5,71,1,44,1,0,6,84,80,20,1,0,6,125,79,54,1,0,6,144,1,67,20,1,0,6,148,1,1,54,1,0,7,133,1,66,20,0,8,69,68,9,1,0,8,80,9,54,1,0,8,84,88,1,1,0,8,144,1,59,20,1,0,9,62,43,1,1,3,10,27,73,74,2,7,4,10,38,75,76,2,7,4,10,41,83,82,2,7,4,10,48,75,23,2,7,4,10,59,41,1,2,7,4,10,70,73,74,2,7,4,10,82,73,23,2,7,4,10,100,2,41,2,7,4,10,101,75,74,2,7,4,10,116,92,1,2,7,4,10,121,83,45,2,7,4,11,76,60,61,1,8,11,100,2,47,0,11,138,1,48,49,0,13,25,95,1,2,7,4,13,38,94,76,2,7,4,13,41,81,82,2,7,4,13,48,94,23,2,7,4,13,100,2,52,2,7,4,14,124,43,1,1,8,75,40,60,43,60,45,38,0,89,51,49,43,49,45,64,43,64,45,90,56,70,57,69,58,67,58,2,55,69,43,82,3,67,43,46,43,69,45,67,45,46,45,51,43,51,45,13,55,10,55,63,43,66,43,66,45,35,0,37,0,31,0,76,40,58,20,77,40,72,40,50,43,17,55,45,43,62,45,61,45,61,43,18,55,79,40,59,20,87,51,81,46,81,40,73,40,39,0,41,0,33,0,36,0,50,45,45,45,62,43,40,0,11,55,68,43,12,55,68,45,47,45,47,43,78,40,34,0,80,40,70,93,88,51,78,46,85,51,80,46,42,45,44,45,63,45,44,43,14,55,70,98,70,99,74,46,72,46,20,55,29,0,74,40,77,46,71,46,86,51,76,46,30,0,79,46,43,43,43,45,32,0,27,55,1,8,5,0,1,7,8,22,1,8,10,6,3,3,3,3,11,14,1,8,20,7,8,22,4,3,3,11,16,1,8,20,7,8,22,3,7,11,6,2,9,0,9,1,11,16,1,9,0,6,8,10,3,7,11,6,2,9,0,9,1,11,16,1,9,1,6,8,10,4,7,11,6,2,9,0,9,1,3,6,8,10,7,8,22,1,11,16,1,9,0,1,11,16,1,9,1,6,7,11,6,2,9,0,9,1,3,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,3,11,16,1,9,0,11,16,1,9,1,3,5,7,11,6,2,9,0,9,1,3,6,8,15,11,16,1,9,1,7,8,22,5,7,11,6,2,9,0,9,1,3,3,3,11,14,1,9,1,2,11,14,1,9,0,11,14,1,9,1,4,7,11,6,2,9,0,9,1,3,3,11,14,1,9,0,7,7,11,6,2,9,0,9,1,3,1,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,2,11,16,1,9,0,11,16,1,9,1,7,7,11,6,2,9,0,9,1,3,3,1,3,6,8,10,7,8,22,1,3,9,7,11,6,2,9,0,9,1,3,3,1,3,2,6,8,15,6,8,10,7,8,22,4,3,3,1,3,1,1,2,8,18,6,8,4,5,8,18,6,8,4,3,3,3,3,7,11,6,2,9,0,9,1,3,6,8,10,5,7,11,9,1,8,5,7,11,17,2,3,3,3,3,8,18,1,8,4,2,7,11,6,2,9,0,9,1,6,8,10,3,7,11,6,2,9,0,9,1,10,3,6,8,10,2,6,11,6,2,9,0,9,1,6,8,10,1,10,8,4,4,3,3,3,3,4,6,11,6,2,9,0,9,1,3,3,6,8,15,2,10,3,10,3,3,6,11,9,1,8,5,3,3,3,6,11,6,2,9,0,9,1,3,6,8,10,1,6,8,4,1,11,17,2,3,8,4,2,3,8,4,1,11,17,2,9,0,9,1,4,8,13,8,18,8,19,8,13,1,9,0,1,8,13,1,9,1,2,3,3,1,8,19,1,6,8,19,1,6,8,18,1,11,9,1,9,0,2,8,18,11,17,2,3,3,1,11,21,2,9,0,9,1,1,11,11,1,9,0,1,11,14,1,9,0,2,9,0,9,1,1,11,6,2,9,0,9,1,1,8,0,1,8,20,1,6,11,16,1,9,0,1,6,9,0,1,8,18,3,7,11,11,1,9,0,8,18,11,14,1,9,0,4,7,11,11,1,9,0,3,6,8,10,7,8,22,4,3,11,16,1,9,0,11,16,1,9,1,3,3,11,14,1,9,0,11,14,1,9,1,3,1,6,8,15,1,6,11,14,1,9,0,2,11,14,1,9,0,7,8,22,28,1,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,11,14,1,9,1,1,3,3,1,3,7,8,5,3,1,6,11,9,1,9,0,2,7,11,9,1,9,0,3,1,7,9,0,1,6,11,17,2,9,0,9,1,1,6,11,12,1,9,0,2,6,11,17,2,9,0,9,1,9,0,1,6,9,1,3,7,11,11,1,9,0,8,18,3,2,1,3,2,7,11,14,1,9,0,3,2,7,11,14,1,9,0,11,14,1,9,0,2,7,11,21,2,9,0,9,1,9,0,1,7,9,1,2,7,11,17,2,9,0,9,1,9,0,2,6,11,9,1,9,0,3,26,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,27,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,1,3,6,8,4,7,8,4,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,3,11,14,1,9,0,11,14,1,9,1,11,14,1,9,1,2,7,11,16,1,9,0,11,16,1,9,0,7,3,7,11,9,1,8,5,8,4,3,3,3,8,18,3,7,11,11,1,9,0,6,8,10,3,3,7,11,9,1,9,0,3,9,0,3,7,11,17,2,9,0,9,1,9,0,9,1,1,11,1,2,9,0,9,1,2,6,11,21,2,9,0,9,1,9,0,3,7,11,21,2,9,0,9,1,9,0,9,1,11,11,14,1,9,0,11,14,1,9,0,11,14,1,9,0,3,3,11,14,1,9,1,11,14,1,9,1,11,14,1,9,1,3,3,8,18,2,6,11,11,1,9,0,8,18,1,11,2,2,9,0,9,1,1,11,3,2,9,0,9,1,11,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,1,8,4,3,3,8,18,7,11,17,2,3,3,3,3,7,8,5,8,4,13,3,7,11,9,1,8,5,3,3,1,7,11,9,1,8,5,8,4,3,3,8,18,3,8,18,7,11,17,2,3,3,17,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,3,1,3,3,3,8,4,3,8,18,3,3,8,18,7,11,17,2,3,3,7,6,8,5,10,8,4,6,8,4,6,11,12,1,3,3,8,18,6,11,17,2,3,3,5,3,3,3,3,8,18,6,3,10,3,3,3,3,10,3,4,3,6,8,4,6,11,12,1,3,6,11,17,2,3,8,4,4,6,11,9,1,8,5,3,8,18,6,11,17,2,3,3,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,11,67,114,105,116,98,105,116,84,114,101,101,9,67,117,115,116,111,100,105,97,110,2,73,68,11,76,105,110,107,101,100,84,97,98,108,101,6,79,112,116,105,111,110,5,79,114,100,101,114,13,79,114,100,101,114,67,97,110,99,101,108,101,100,11,79,114,100,101,114,70,105,108,108,101,100,13,79,114,100,101,114,70,105,108,108,101,100,86,50,11,79,114,100,101,114,80,108,97,99,101,100,13,79,114,100,101,114,80,108,97,99,101,100,86,50,4,80,111,111,108,11,80,111,111,108,67,114,101,97,116,101,100,3,83,85,73,5,84,97,98,108,101,9,84,105,99,107,76,101,118,101,108,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,3,97,100,100,4,97,115,107,115,4,98,97,99,107,7,98,97,108,97,110,99,101,10,98,97,115,101,95,97,115,115,101,116,28,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,99,97,110,99,101,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,102,105,108,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,112,108,97,99,101,100,29,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,114,101,109,97,105,110,105,110,103,23,98,97,115,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,14,98,97,115,101,95,99,117,115,116,111,100,105,97,110,18,98,97,116,99,104,95,99,97,110,99,101,108,95,111,114,100,101,114,4,98,105,100,115,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,17,99,97,110,99,101,108,95,97,108,108,95,111,114,100,101,114,115,12,99,97,110,99,101,108,95,111,114,100,101,114,4,99,108,111,98,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,14,99,114,101,97,116,101,95,97,99,99,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,12,99,114,101,97,116,101,95,112,111,111,108,95,12,99,114,101,97,116,105,111,110,95,102,101,101,7,99,114,105,116,98,105,116,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,100,101,112,111,115,105,116,95,98,97,115,101,13,100,101,112,111,115,105,116,95,113,117,111,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,19,100,101,115,116,114,111,121,95,101,109,112,116,121,95,108,101,118,101,108,9,100,105,118,95,114,111,117,110,100,4,101,109,105,116,19,101,109,105,116,95,111,114,100,101,114,95,99,97,110,99,101,108,101,100,17,101,109,105,116,95,111,114,100,101,114,95,102,105,108,108,101,100,5,101,118,101,110,116,16,101,120,112,105,114,101,95,116,105,109,101,115,116,97,109,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,12,102,114,111,109,95,98,97,108,97,110,99,101,5,102,114,111,110,116,3,103,101,116,22,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,97,115,107,95,115,105,100,101,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,98,105,100,95,115,105,100,101,16,103,101,116,95,111,114,100,101,114,95,115,116,97,116,117,115,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,18,105,110,106,101,99,116,95,108,105,109,105,116,95,111,114,100,101,114,11,105,110,115,101,114,116,95,108,101,97,102,12,105,110,116,111,95,98,97,108,97,110,99,101,6,105,115,95,98,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,4,106,111,105,110,12,108,105,110,107,101,100,95,116,97,98,108,101,16,108,105,115,116,95,111,112,101,110,95,111,114,100,101,114,115,12,108,111,99,107,95,98,97,108,97,110,99,101,8,108,111,116,95,115,105,122,101,17,109,97,107,101,114,95,114,101,98,97,116,101,95,114,97,116,101,13,109,97,107,101,114,95,114,101,98,97,116,101,115,9,109,97,116,99,104,95,97,115,107,9,109,97,116,99,104,95,98,105,100,29,109,97,116,99,104,95,98,105,100,95,119,105,116,104,95,113,117,111,116,101,95,113,117,97,110,116,105,116,121,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,109,117,108,9,109,117,108,95,114,111,117,110,100,3,110,101,119,4,110,101,120,116,17,110,101,120,116,95,97,115,107,95,111,114,100,101,114,95,105,100,17,110,101,120,116,95,98,105,100,95,111,114,100,101,114,95,105,100,9,110,101,120,116,95,108,101,97,102,6,111,98,106,101,99,116,11,111,112,101,110,95,111,114,100,101,114,115,6,111,112,116,105,111,110,8,111,114,100,101,114,95,105,100,12,111,114,100,101,114,95,105,115,95,98,105,100,5,111,119,110,101,114,17,112,108,97,99,101,95,108,105,109,105,116,95,111,114,100,101,114,18,112,108,97,99,101,95,109,97,114,107,101,116,95,111,114,100,101,114,7,112,111,111,108,95,105,100,13,112,114,101,118,105,111,117,115,95,108,101,97,102,5,112,114,105,99,101,9,112,117,115,104,95,98,97,99,107,8,113,117,97,110,116,105,116,121,11,113,117,111,116,101,95,97,115,115,101,116,24,113,117,111,116,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,15,113,117,111,116,101,95,99,117,115,116,111,100,105,97,110,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,12,114,101,109,111,118,101,95,111,114,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,3,115,117,105,25,115,119,97,112,95,101,120,97,99,116,95,98,97,115,101,95,102,111,114,95,113,117,111,116,101,25,115,119,97,112,95,101,120,97,99,116,95,113,117,111,116,101,95,102,111,114,95,98,97,115,101,5,116,97,98,108,101,16,116,97,107,101,114,95,99,111,109,109,105,115,115,105,111,110,14,116,97,107,101,114,95,102,101,101,95,114,97,116,101,9,116,105,99,107,95,115,105,122,101,12,116,105,109,101,115,116,97,109,112,95,109,115,14,116,111,116,97,108,95,113,117,97,110,116,105,116,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,16,117,110,115,97,102,101,95,100,105,118,95,114,111,117,110,100,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,15,117,115,114,95,111,112,101,110,95,111,114,100,101,114,115,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,13,119,105,116,104,100,114,97,119,95,98,97,115,101,14,119,105,116,104,100,114,97,119,95,113,117,111,116,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,3,8,19,0,0,0,0,0,0,0,3,8,20,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,2,1,4,2,1,0,2,1,1,2,1,2,2,1,3,3,8,0,0,0,0,0,0,0,128,3,8,0,0,0,0,0,0,0,0,3,8,64,75,76,0,0,0,0,0,3,8,160,37,38,0,0,0,0,0,3,8,0,232,118,72,23,0,0,0,0,2,7,113,8,18,29,8,13,118,8,13,131,1,3,89,3,132,1,3,88,3,1,2,7,113,8,18,108,3,81,1,110,8,18,32,3,115,3,66,3,2,2,6,113,8,18,108,3,81,1,110,8,18,30,3,115,3,3,2,10,113,8,18,108,3,81,1,110,8,18,134,1,3,31,3,33,3,115,3,130,1,3,90,3,4,2,6,108,3,115,3,117,3,81,1,110,8,18,66,3,5,2,2,115,3,106,11,17,2,3,8,4,6,2,15,76,8,19,37,11,9,1,8,5,26,11,9,1,8,5,103,3,102,3,143,1,11,21,2,8,18,11,17,2,3,3,131,1,3,89,3,132,1,3,88,3,35,11,11,1,9,0,120,11,11,1,9,1,52,11,14,1,8,20,34,11,14,1,9,0,119,11,14,1,9,1,7,2,6,113,8,18,108,3,81,1,110,8,18,32,3,115,3,8,2,8,113,8,18,108,3,81,1,110,8,18,134,1,3,31,3,33,3,115,3,6,55,1,55,2,55,3,55,0,0,0,0,39,7,11,0,19,5,12,1,1,11,1,56,0,2,1,1,0,0,1,3,11,0,17,48,2,2,0,0,0,42,72,56,1,12,6,56,2,12,9,10,3,10,2,17,56,6,0,0,0,0,0,0,0,0,36,4,11,5,15,11,5,1,7,19,39,10,6,10,9,34,4,20,5,24,11,5,1,7,15,39,10,0,10,1,38,4,29,5,33,11,5,1,7,1,39,10,5,17,83,12,8,14,8,17,84,20,12,7,11,8,10,5,56,3,10,5,56,3,7,0,7,26,10,5,56,4,10,0,10,1,10,2,10,3,10,5,56,5,11,5,56,6,11,4,56,7,56,8,57,0,56,9,11,7,11,6,11,9,11,0,11,1,11,2,11,3,18,0,56,10,2,3,1,0,0,1,19,14,2,56,11,7,30,33,4,6,5,10,11,3,1,7,17,39,7,28,7,29,11,0,11,1,11,2,56,12,11,3,56,13,2,4,1,0,0,1,20,14,1,56,14,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,6,39,11,0,54,0,11,2,56,15,11,1,56,16,56,17,2,5,1,0,0,1,20,14,1,56,18,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,7,39,11,0,54,1,11,2,56,15,11,1,56,19,56,20,2,6,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,11,0,54,0,11,1,11,2,11,3,56,21,2,7,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,11,0,54,1,11,1,11,2,11,3,56,22,2,8,1,0,0,64,49,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,5,1,11,4,1,7,5,39,14,2,56,14,10,1,38,4,19,5,27,11,0,1,11,5,1,11,4,1,7,6,39,14,3,56,18,12,6,11,0,11,1,9,11,2,11,3,11,4,11,5,56,23,12,8,12,7,14,8,56,18,12,9,11,7,11,8,11,9,11,6,23,2,9,1,0,0,65,48,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,4,1,11,2,1,7,5,39,14,3,56,18,10,1,38,4,19,5,27,11,0,1,11,4,1,11,2,1,7,7,39,11,0,11,1,7,26,11,2,17,65,11,3,56,19,56,24,12,6,12,5,14,5,56,25,12,7,11,5,10,4,56,26,11,6,11,4,56,27,11,7,2,10,0,0,0,69,215,2,10,0,55,2,17,84,20,12,23,11,1,12,28,56,7,12,10,11,4,12,25,10,0,54,3,12,9,10,9,46,56,28,4,25,11,0,1,11,9,1,11,10,11,25,2,10,9,46,56,29,12,30,12,32,9,12,29,10,9,46,56,28,32,4,43,5,38,10,32,10,2,37,12,5,5,45,9,12,5,11,5,4,212,2,10,9,10,30,56,30,12,31,10,31,16,4,56,31,56,32,20,12,22,10,31,16,4,56,33,32,4,180,2,5,63,10,31,16,4,10,22,56,34,12,16,10,16,16,5,20,12,15,9,12,26,10,16,16,6,20,10,3,37,4,95,8,12,26,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,35,10,23,10,16,56,36,5,249,1,10,15,10,16,16,8,20,17,54,12,18,4,106,11,18,6,1,0,0,0,0,0,0,0,22,12,18,11,18,7,20,10,0,55,4,20,22,17,54,12,18,4,119,11,18,6,1,0,0,0,0,0,0,0,22,12,18,10,28,10,18,38,4,137,1,11,18,12,12,10,12,7,20,10,0,55,4,20,22,17,52,12,13,1,10,15,12,11,5,186,1,8,12,29,10,28,7,20,10,0,55,4,20,22,17,55,12,13,1,11,13,10,16,16,8,20,17,55,12,11,1,11,11,10,0,55,5,20,26,10,0,55,5,20,24,12,11,10,11,10,16,16,8,20,17,56,12,13,10,13,10,0,55,4,20,17,57,12,27,4,182,1,11,27,6,1,0,0,0,0,0,0,0,22,12,27,10,13,11,27,22,12,12,10,13,10,0,55,6,20,17,56,12,19,11,15,10,11,23,12,15,11,28,10,12,23,12,28,10,28,6,0,0,0,0,0,0,0,0,33,4,206,1,8,12,29,10,0,54,0,10,16,16,7,20,10,11,56,37,12,14,13,25,10,12,56,38,12,24,10,0,54,1,10,16,16,7,20,13,24,10,19,10,13,22,56,38,56,20,10,0,54,7,11,24,56,39,1,13,10,11,14,56,40,1,10,0,55,2,17,84,20,10,16,11,11,11,12,11,13,23,11,19,56,41,11,26,4,254,1,8,12,6,5,130,2,10,15,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,165,2,10,22,12,21,10,31,16,4,10,22,56,42,12,20,10,20,56,43,32,4,148,2,11,20,56,32,20,12,22,5,150,2,11,20,1,10,0,54,8,11,16,16,7,20,56,44,10,21,56,45,1,10,31,15,4,11,21,56,46,1,5,176,2,11,16,1,10,31,15,4,10,22,56,47,12,17,11,15,11,17,15,5,21,10,29,4,179,2,5,180,2,5,57,11,31,16,4,56,33,4,204,2,10,9,11,32,12,7,46,11,7,56,48,1,12,32,10,9,11,30,56,49,17,0,10,9,10,32,12,8,46,11,8,56,50,12,30,1,10,29,4,211,2,11,0,1,11,9,1,5,212,2,5,32,11,10,11,25,2,11,0,0,0,85,153,2,10,0,55,2,17,84,20,12,22,11,1,12,25,56,7,12,11,11,4,12,23,10,0,54,3,12,10,10,10,46,56,28,4,25,11,0,1,11,10,1,11,11,11,23,2,10,10,46,56,29,12,28,12,30,10,10,46,56,28,32,4,41,5,36,10,30,10,2,37,12,5,5,43,9,12,5,11,5,4,150,2,10,10,10,28,56,30,12,29,10,29,16,4,56,31,56,32,20,12,21,10,29,16,4,56,33,32,4,244,1,5,61,10,29,16,4,10,21,56,34,12,16,10,16,16,5,20,12,15,9,12,24,10,16,16,6,20,10,3,37,4,93,8,12,24,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,35,10,22,10,16,56,36,5,183,1,10,25,10,15,36,4,100,10,15,12,6,5,102,10,25,12,6,11,6,12,12,10,12,10,16,16,8,20,17,53,12,13,10,13,10,0,55,6,20,17,56,12,18,10,13,10,0,55,4,20,17,57,12,26,4,127,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,15,10,12,23,12,15,11,25,10,12,23,12,25,10,0,54,0,10,16,16,7,20,10,12,56,37,12,14,13,23,10,26,56,38,12,27,10,0,54,1,10,16,16,7,20,13,27,10,18,56,38,56,20,10,0,54,7,11,27,56,39,1,13,11,11,14,56,40,1,10,0,54,1,10,16,16,7,20,13,23,11,13,56,38,56,20,10,0,55,2,17,84,20,10,16,11,12,11,26,11,18,56,41,11,24,4,188,1,8,12,7,5,192,1,10,15,6,0,0,0,0,0,0,0,0,33,12,7,11,7,4,227,1,10,21,12,20,10,29,16,4,10,21,56,42,12,19,10,19,56,43,32,4,210,1,11,19,56,32,20,12,21,5,212,1,11,19,1,10,0,54,8,11,16,16,7,20,56,44,10,20,56,45,1,10,29,15,4,11,20,56,46,1,5,238,1,11,16,1,10,29,15,4,10,21,56,47,12,17,11,15,11,17,15,5,21,10,25,6,0,0,0,0,0,0,0,0,33,4,243,1,5,244,1,5,55,11,29,16,4,56,33,4,140,2,10,10,11,30,12,8,46,11,8,56,48,1,12,30,10,10,11,28,56,49,17,0,10,10,10,30,12,9,46,11,9,56,50,12,28,1,10,25,6,0,0,0,0,0,0,0,0,33,4,149,2,11,0,1,11,10,1,5,150,2,5,30,11,11,11,23,2,12,0,0,0,86,158,2,10,0,55,2,17,84,20,12,22,11,3,12,10,56,8,12,23,10,0,54,9,12,9,10,9,46,56,28,4,23,11,0,1,11,9,1,11,10,11,23,2,10,9,46,56,51,12,28,12,30,10,9,46,56,28,32,4,39,5,34,10,30,10,1,38,12,4,5,41,9,12,4,11,4,4,155,2,10,9,10,28,56,30,12,29,10,29,16,4,56,31,56,32,20,12,21,10,29,16,4,56,33,32,4,248,1,5,59,10,29,16,4,10,21,56,34,12,15,10,15,16,5,20,12,14,9,12,24,10,15,16,6,20,10,2,37,4,97,8,12,24,10,15,16,5,20,10,15,16,8,20,17,53,12,17,10,0,54,1,10,15,16,7,20,11,17,56,52,10,22,10,15,56,36,5,186,1,14,10,56,25,12,25,10,25,10,14,38,4,107,10,14,12,5,5,109,11,25,12,5,11,5,12,11,10,11,10,15,16,8,20,17,53,12,12,10,12,10,0,55,6,20,17,56,12,18,10,12,10,0,55,4,20,17,57,12,26,4,134,1,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,14,10,11,23,12,14,10,0,54,1,10,15,16,7,20,11,12,56,53,12,13,13,13,10,26,56,38,12,27,10,0,54,1,10,15,16,7,20,13,27,10,18,56,38,56,20,10,0,54,7,11,27,56,39,1,13,23,11,13,56,39,1,10,0,54,0,10,15,16,7,20,13,10,10,11,56,54,56,17,10,0,55,2,17,84,20,10,15,11,11,11,26,11,18,56,41,11,24,4,191,1,8,12,6,5,195,1,10,14,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,230,1,10,21,12,20,10,29,16,4,10,21,56,42,12,19,10,19,56,43,32,4,213,1,11,19,56,32,20,12,21,5,215,1,11,19,1,10,0,54,8,11,15,16,7,20,56,44,10,20,56,45,1,10,29,15,4,11,20,56,46,1,5,241,1,11,15,1,10,29,15,4,10,21,56,47,12,16,11,14,11,16,15,5,21,14,10,56,25,6,0,0,0,0,0,0,0,0,33,4,247,1,5,248,1,5,53,11,29,16,4,56,33,4,144,2,10,9,11,30,12,7,46,11,7,56,55,1,12,30,10,9,11,28,56,49,17,0,10,9,10,30,12,8,46,11,8,56,50,12,28,1,14,10,56,25,6,0,0,0,0,0,0,0,0,33,4,154,2,11,0,1,11,9,1,5,155,2,5,28,11,10,11,23,2,13,1,0,0,87,85,10,1,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,9,5,17,11,0,1,11,6,1,11,5,1,7,5,39,10,1,6,0,0,0,0,0,0,0,0,34,4,22,5,30,11,0,1,11,6,1,11,5,1,7,5,39,11,2,4,52,11,0,11,1,7,26,11,5,17,65,11,4,56,19,56,56,12,9,12,7,13,3,11,7,10,6,56,26,56,57,11,9,11,6,56,27,12,4,5,82,11,1,14,3,56,14,37,4,58,5,66,11,0,1,11,6,1,11,5,1,7,6,39,11,0,7,27,11,5,17,65,11,3,56,16,56,58,12,8,10,6,56,26,12,3,13,4,11,8,11,6,56,27,56,59,11,3,11,4,2,14,0,0,0,89,118,10,5,56,15,12,13,10,3,4,30,10,2,10,1,17,53,12,11,10,0,54,1,11,5,11,11,56,60,10,0,55,10,20,12,10,10,0,55,10,20,6,1,0,0,0,0,0,0,0,22,10,0,54,10,21,10,0,54,9,12,8,5,50,10,0,54,0,11,5,10,2,56,61,10,0,55,11,20,12,10,10,0,55,11,20,6,1,0,0,0,0,0,0,0,22,10,0,54,11,21,10,0,54,3,12,8,10,10,10,1,10,2,10,3,10,13,10,4,18,4,12,9,10,8,10,1,12,7,46,11,7,56,50,12,12,32,4,75,10,8,10,1,10,1,10,6,56,62,18,5,56,63,12,12,11,8,11,12,56,30,15,4,10,10,11,9,56,64,10,0,55,2,17,84,20,10,10,11,3,10,13,11,2,10,1,11,4,57,1,56,65,10,0,55,8,10,13,56,66,32,4,107,10,0,54,8,10,13,11,6,56,67,56,68,5,109,11,6,1,11,0,54,8,11,13,56,44,10,10,11,1,56,69,11,10,2,15,1,0,0,96,144,2,10,2,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,1,6,0,0,0,0,0,0,0,0,36,4,20,5,30,11,0,1,11,8,1,11,6,1,11,7,1,7,4,39,10,1,10,0,55,12,20,25,6,0,0,0,0,0,0,0,0,33,4,39,5,49,11,0,1,11,8,1,11,6,1,11,7,1,7,4,39,10,2,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,58,5,68,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,4,10,6,17,65,36,4,74,5,84,11,0,1,11,8,1,11,6,1,11,7,1,7,18,39,10,7,56,15,12,19,10,3,4,128,1,10,0,55,1,10,19,56,70,12,18,10,0,54,1,10,7,10,18,56,71,12,14,10,0,10,2,10,1,11,6,17,65,11,14,56,56,12,16,12,10,14,10,56,25,12,12,11,18,14,16,56,72,23,12,17,10,0,54,0,10,19,11,10,56,17,10,0,54,1,11,19,11,16,56,20,5,160,1,10,0,54,0,10,7,10,2,56,73,12,9,10,0,10,1,11,6,17,65,11,9,56,58,12,15,12,11,10,2,14,11,56,25,23,12,12,14,15,56,72,12,17,10,0,54,0,10,19,11,11,56,17,10,0,54,1,11,19,11,15,56,20,10,5,7,23,33,4,175,1,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,24,33,4,197,1,11,0,1,11,8,1,11,7,1,10,12,11,2,33,4,190,1,5,192,1,7,8,39,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,25,33,4,228,1,10,12,6,0,0,0,0,0,0,0,0,33,4,206,1,5,214,1,11,0,1,11,8,1,11,7,1,7,9,39,11,0,11,1,11,2,11,3,11,4,11,7,11,8,56,74,12,13,11,12,11,17,8,11,13,2,11,5,7,22,33,4,233,1,5,241,1,11,0,1,11,8,1,11,7,1,7,13,39,10,2,10,12,36,4,133,2,11,0,11,1,11,2,10,12,23,11,3,11,4,11,7,11,8,56,74,12,13,11,12,11,17,8,11,13,2,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,16,0,0,0,1,4,11,0,7,26,35,2,17,0,0,0,1,19,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,11,1,16,8,20,57,2,56,75,2,18,0,0,0,1,27,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,10,2,10,1,16,5,20,11,2,23,11,1,16,8,20,11,3,11,4,57,3,56,76,2,19,1,0,0,100,110,11,2,56,15,12,12,10,0,55,8,10,12,56,66,4,9,5,13,11,0,1,7,11,39,10,0,54,8,10,12,56,44,12,13,10,13,10,1,12,3,46,11,3,56,77,4,26,5,32,11,13,1,11,0,1,7,2,39,10,13,10,1,12,4,46,11,4,56,78,20,12,11,10,1,17,16,12,8,10,8,4,49,10,0,55,9,12,5,5,52,10,0,55,3,12,5,11,5,11,11,56,50,12,10,4,58,5,64,11,13,1,11,0,1,7,2,39,10,8,4,70,10,0,54,9,12,6,5,73,10,0,54,3,12,6,11,6,11,13,11,10,11,1,10,12,56,79,12,9,11,8,4,96,14,9,16,5,20,14,9,16,8,20,17,53,12,7,10,0,54,1,11,12,11,7,56,52,5,103,10,0,54,0,11,12,14,9,16,5,20,56,35,11,0,55,2,17,84,20,14,9,56,36,2,20,0,0,0,101,54,11,1,10,3,56,45,1,10,0,10,2,12,5,46,11,5,56,80,16,4,10,3,56,81,4,15,5,19,11,0,1,7,2,39,10,0,10,2,56,30,12,6,10,6,15,4,11,3,56,46,12,7,14,7,16,7,20,11,4,33,4,35,5,41,11,0,1,11,6,1,7,3,39,11,6,16,4,56,33,4,50,11,0,11,2,56,49,17,0,5,52,11,0,1,11,7,2,21,1,0,0,102,104,10,0,55,2,17,84,20,12,11,11,1,56,15,12,13,10,0,55,8,10,13,56,66,4,14,5,18,11,0,1,7,11,39,10,0,54,8,10,13,56,44,12,14,10,14,46,56,82,32,4,99,5,29,10,14,46,56,83,56,32,20,12,9,10,14,10,9,12,2,46,11,2,56,78,20,12,10,10,9,17,16,12,6,10,6,4,52,10,0,54,9,12,3,5,55,10,0,54,3,12,3,11,3,12,7,10,7,11,10,12,4,46,11,4,56,50,12,12,1,11,7,10,14,11,12,11,9,10,13,56,79,12,8,11,6,4,88,14,8,16,5,20,14,8,16,8,20,17,53,12,5,10,0,54,1,10,13,11,5,56,52,5,95,10,0,54,0,10,13,14,8,16,5,20,56,35,10,11,14,8,56,36,5,23,11,14,1,11,0,1,2,22,1,0,0,103,148,1,10,0,55,2,17,84,20,12,15,11,2,56,15,12,18,10,0,55,8,10,18,56,66,4,14,5,18,11,0,1,6,0,0,0,0,0,0,0,0,39,6,0,0,0,0,0,0,0,0,12,16,6,0,0,0,0,0,0,0,0,12,17,14,1,65,20,12,10,6,0,0,0,0,0,0,0,0,12,8,10,0,54,8,10,18,56,44,12,19,10,8,10,10,35,4,143,1,5,37,14,1,10,8,66,20,20,12,14,10,19,10,14,12,3,46,11,3,56,77,4,50,5,56,11,19,1,11,0,1,7,2,39,10,19,10,14,12,4,46,11,4,56,78,20,12,12,10,14,17,16,12,9,10,12,10,17,34,4,96,11,12,12,17,10,9,4,79,10,0,55,9,12,5,5,82,10,0,55,3,12,5,11,5,10,17,56,50,12,11,4,88,5,94,11,19,1,11,0,1,7,10,39,11,11,12,16,10,9,4,102,10,0,54,9,12,6,5,105,10,0,54,3,12,6,11,6,10,19,10,16,11,14,10,18,56,79,12,13,11,9,4,128,1,14,13,16,5,20,14,13,16,8,20,17,53,12,7,10,0,54,1,10,18,11,7,56,52,5,135,1,10,0,54,0,10,18,14,13,16,5,20,56,35,10,15,14,13,56,36,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,32,11,19,1,11,0,1,2,23,1,0,0,104,84,11,1,56,15,12,7,10,0,55,8,11,7,56,84,12,8,64,28,0,0,0,0,0,0,0,0,12,3,10,8,56,85,12,5,10,5,56,43,32,4,76,5,18,10,8,10,5,56,32,20,56,78,20,12,6,10,5,56,32,20,17,16,4,36,10,0,55,9,11,6,56,86,12,2,5,41,10,0,55,3,11,6,56,86,12,2,11,2,16,4,10,5,56,32,20,56,34,12,4,13,3,10,4,16,18,20,10,4,16,8,20,10,4,16,5,20,10,4,16,19,20,10,4,16,7,20,11,4,16,6,20,18,4,68,28,10,8,11,5,56,32,20,56,87,12,5,5,13,11,8,1,11,0,1,11,5,1,11,3,2,24,1,0,0,105,20,11,1,56,15,12,6,10,0,55,0,10,6,56,88,12,3,12,2,11,0,55,1,11,6,56,89,12,5,12,4,11,2,11,3,11,4,11,5,2,25,1,0,0,106,86,10,0,55,9,56,29,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,9,56,51,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,9,11,1,56,90,12,1,10,0,55,9,11,2,56,90,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,9,10,1,10,3,17,65,56,91,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,9,11,1,56,48,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,26,1,0,0,106,86,10,0,55,3,56,29,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,3,56,51,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,3,11,1,56,90,12,1,10,0,55,3,11,2,56,90,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,3,10,1,10,3,17,65,56,91,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,3,11,1,56,48,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,27,0,0,0,107,49,11,0,11,1,56,86,16,4,12,6,6,0,0,0,0,0,0,0,0,12,3,10,6,56,31,12,5,10,5,56,43,32,4,43,5,15,10,6,10,5,56,32,20,56,34,12,4,10,4,16,6,20,10,2,36,4,34,11,3,11,4,16,5,20,22,12,3,5,36,11,4,1,10,6,11,5,56,32,20,56,42,12,5,5,10,11,6,1,11,5,1,11,3,2,28,1,0,0,108,52,11,2,56,15,12,5,10,0,55,8,10,5,56,66,4,9,5,13,11,0,1,7,11,39,10,0,55,8,11,5,56,84,12,6,10,6,10,1,56,77,4,23,5,29,11,6,1,11,0,1,7,2,39,11,6,10,1,56,78,20,12,4,10,1,7,26,35,4,42,11,0,55,9,12,3,5,45,11,0,55,3,12,3,11,3,11,4,56,86,16,4,11,1,56,34,2,6,10,6,11,6,0,6,2,5,1,4,2,4,5,4,4,4,1,6,6,6,9,6,7,6,14,6,5,6,1,6,3,6,4,6,8,4,0,4,3,0,55,1,55,2,55,3,55,9,55,10,55,11,55,12,55,13,55,14,55,15,55,16,55,17,55,0],"critbit":[161,28,235,11,6,0,0,0,14,1,0,6,2,6,28,3,34,194,1,4,228,1,54,5,154,2,235,1,7,133,4,153,4,8,158,8,64,6,222,8,120,10,214,9,51,11,137,10,4,12,141,10,217,17,13,230,27,28,14,130,28,20,15,150,28,2,0,13,1,43,1,44,0,2,6,1,0,0,0,1,6,0,0,0,4,1,4,0,1,3,12,2,7,1,4,1,2,4,2,0,0,31,0,1,1,4,0,42,2,3,1,4,0,21,2,4,1,4,0,30,2,5,1,4,0,29,2,5,1,4,0,36,6,5,1,4,0,33,6,5,1,4,0,26,6,3,1,4,0,40,6,3,1,4,0,19,7,3,1,4,0,17,6,8,1,4,0,16,6,3,1,4,0,38,9,10,1,4,0,10,9,11,1,4,0,7,6,12,1,4,0,8,6,12,1,4,0,15,1,13,1,6,0,14,1,13,1,4,0,18,6,3,1,4,0,45,14,13,1,4,0,22,15,4,1,4,0,12,16,17,0,1,5,26,13,2,7,4,1,6,22,23,2,7,4,1,9,28,30,2,7,4,1,14,19,13,2,7,4,1,15,19,13,2,7,6,1,21,21,4,2,7,4,1,27,21,3,2,7,4,1,31,0,19,2,7,4,1,37,28,29,2,7,4,29,18,29,20,28,20,27,20,2,10,23,20,10,10,20,10,23,18,8,10,7,10,22,20,18,10,22,18,19,10,6,10,5,10,30,20,1,10,24,18,24,20,30,18,14,10,26,18,26,20,25,20,25,18,1,7,8,4,1,11,2,1,9,0,1,6,11,2,1,9,0,1,3,1,1,2,3,3,2,6,11,2,1,9,0,3,3,7,11,2,1,9,0,3,9,0,2,1,3,2,7,11,2,1,9,0,3,1,9,0,1,7,9,0,1,6,9,0,0,4,7,11,2,1,9,0,3,3,1,3,6,11,2,1,9,0,3,3,1,4,1,2,2,3,8,1,1,11,3,2,9,0,9,1,2,3,11,0,1,9,0,1,6,11,3,2,9,0,9,1,2,6,11,3,2,9,0,9,1,9,0,1,6,9,1,4,1,3,3,3,16,3,3,3,3,3,2,6,8,1,1,1,8,1,3,3,11,0,1,9,0,3,3,3,3,7,11,3,2,9,0,9,1,9,0,9,1,16,3,3,3,3,3,3,3,3,3,1,3,3,6,8,1,3,3,9,0,2,7,11,3,2,9,0,9,1,9,0,1,9,1,1,7,9,1,2,11,3,2,3,8,1,11,3,2,3,11,0,1,9,0,2,6,8,1,3,2,2,2,11,67,114,105,116,98,105,116,84,114,101,101,12,73,110,116,101,114,110,97,108,78,111,100,101,4,76,101,97,102,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,4,99,108,111,98,19,99,111,117,110,116,95,108,101,97,100,105,110,103,95,122,101,114,111,115,7,99,114,105,116,98,105,116,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,29,103,101,116,95,99,108,111,115,101,115,116,95,108,101,97,102,95,105,110,100,101,120,95,98,121,95,107,101,121,11,105,110,115,101,114,116,95,108,101,97,102,14,105,110,116,101,114,110,97,108,95,110,111,100,101,115,8,105,115,95,101,109,112,116,121,13,105,115,95,108,101,102,116,95,99,104,105,108,100,3,107,101,121,6,108,101,97,118,101,115,10,108,101,102,116,95,99,104,105,108,100,14,108,101,102,116,95,109,111,115,116,95,108,101,97,102,6,108,101,110,103,116,104,4,109,97,115,107,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,3,110,101,119,24,110,101,120,116,95,105,110,116,101,114,110,97,108,95,110,111,100,101,95,105,110,100,101,120,9,110,101,120,116,95,108,101,97,102,15,110,101,120,116,95,108,101,97,102,95,105,110,100,101,120,6,112,97,114,101,110,116,13,112,114,101,118,105,111,117,115,95,108,101,97,102,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,11,114,105,103,104,116,95,99,104,105,108,100,15,114,105,103,104,116,95,109,111,115,116,95,108,101,97,102,4,114,111,111,116,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,112,100,97,116,101,95,99,104,105,108,100,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,128,3,8,255,255,255,255,255,255,255,255,3,8,255,255,255,255,255,255,255,127,0,2,3,23,3,46,9,0,35,3,1,2,4,28,3,25,3,39,3,35,3,2,2,7,41,3,20,11,3,2,3,8,1,24,11,3,2,3,11,0,1,9,0,30,3,29,3,32,3,34,3,2,10,0,10,0,3,0,0,13,11,7,9,10,0,56,0,11,0,56,1,7,9,7,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,57,0,2,1,3,0,0,13,4,11,0,55,0,56,2,2,2,3,0,0,13,4,11,0,55,0,56,3,2,3,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,1,20,56,5,55,2,20,11,0,55,1,20,2,4,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,0,55,3,20,2,5,1,0,0,24,78,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,36,5,30,10,0,10,4,11,5,56,7,12,2,5,38,9,12,2,11,2,4,50,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,59,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,7,20,56,9,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,6,3,0,0,24,79,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,37,5,30,10,0,10,4,11,5,56,7,32,12,2,5,39,9,12,2,11,2,4,51,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,60,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,8,20,56,10,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,7,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,7,20,12,2,5,2,11,0,1,11,2,2,8,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,8,20,12,2,5,2,11,0,1,11,2,2,9,3,0,0,25,247,1,10,1,11,2,7,9,57,1,12,15,10,0,55,6,20,12,16,10,0,55,6,20,6,1,0,0,0,0,0,0,0,22,10,0,54,6,21,10,16,7,11,6,1,0,0,0,0,0,0,0,23,35,4,24,5,28,11,0,1,7,1,39,10,0,54,0,10,16,11,15,56,11,10,0,10,1,12,3,46,11,3,56,12,12,7,10,7,7,9,33,4,69,10,16,6,0,0,0,0,0,0,0,0,33,4,49,5,53,11,0,1,7,2,39,7,10,10,16,23,10,0,54,7,21,10,16,10,0,54,1,21,11,16,11,0,54,3,21,6,0,0,0,0,0,0,0,0,2,10,0,55,0,11,7,56,5,55,2,20,12,6,10,6,10,1,34,4,81,5,85,11,0,1,7,3,39,49,64,11,6,10,1,29,53,17,21,49,64,23,23,12,8,6,1,0,0,0,0,0,0,0,11,8,49,1,23,47,12,17,10,17,7,9,7,9,7,9,18,1,12,12,10,0,55,8,20,12,13,10,0,55,8,20,6,1,0,0,0,0,0,0,0,22,10,0,54,8,21,10,0,54,5,10,13,11,12,56,13,10,0,55,7,20,12,18,7,9,12,14,10,18,7,9,35,4,169,1,5,135,1,10,0,55,5,10,18,56,8,12,9,10,17,10,9,16,12,20,36,4,149,1,11,9,1,5,169,1,11,18,12,14,10,1,10,9,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,164,1,11,9,16,7,20,12,18,5,168,1,11,9,16,8,20,12,18,5,130,1,10,14,7,9,33,4,178,1,10,13,10,0,54,7,21,5,193,1,10,0,10,14,10,18,12,5,12,4,46,11,4,11,5,56,7,12,10,10,0,11,14,10,13,11,10,56,14,11,17,10,1,28,6,0,0,0,0,0,0,0,0,33,12,11,10,0,10,13,7,10,10,16,23,10,11,56,14,10,0,11,13,11,18,11,11,32,56,14,10,0,55,0,10,0,55,1,20,56,5,55,2,20,10,1,36,4,227,1,10,16,10,0,54,1,21,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,1,35,4,243,1,10,16,11,0,54,3,21,5,245,1,11,0,1,11,16,2,10,3,0,0,3,27,10,0,56,4,4,8,11,0,1,9,7,9,2,10,0,10,1,56,12,12,2,11,0,55,0,10,2,56,5,55,2,20,11,1,34,4,24,9,7,9,2,8,11,2,2,11,3,0,0,3,18,10,0,56,4,4,7,11,0,1,6,0,0,0,0,0,0,0,0,2,10,0,11,1,56,12,12,2,11,0,55,0,11,2,56,5,55,2,20,2,12,3,0,0,27,171,1,10,0,55,0,10,1,56,5,55,2,20,12,12,10,0,55,1,20,10,1,33,4,25,10,0,10,12,12,4,46,11,4,56,15,12,9,1,11,9,10,0,54,1,21,10,0,55,3,20,10,1,33,4,43,10,0,11,12,12,5,46,11,5,56,16,12,10,1,11,10,10,0,54,3,21,10,0,54,0,10,1,56,17,58,1,12,15,12,17,1,10,0,46,56,18,6,0,0,0,0,0,0,0,0,33,4,78,7,9,10,0,54,7,21,7,9,10,0,54,1,21,7,9,10,0,54,3,21,6,0,0,0,0,0,0,0,0,10,0,54,8,21,6,0,0,0,0,0,0,0,0,11,0,54,6,21,5,169,1,10,15,7,9,34,4,83,5,87,11,0,1,7,6,39,10,0,55,5,10,15,56,8,12,14,10,14,16,6,20,12,13,10,0,10,15,7,10,11,1,23,12,7,12,6,46,11,6,11,7,56,7,4,113,11,14,16,8,20,12,8,5,117,11,14,16,7,20,12,8,11,8,12,16,10,13,7,9,33,4,149,1,10,16,7,9,35,4,135,1,7,9,10,0,54,5,10,16,56,19,15,6,21,5,144,1,7,9,10,0,54,0,7,10,10,16,23,56,20,54,4,21,11,16,10,0,54,7,21,5,164,1,10,0,10,13,10,15,12,3,12,2,46,11,2,11,3,56,7,12,11,10,0,11,13,11,16,11,11,56,14,11,0,54,5,11,15,56,21,1,11,17,2,13,3,0,0,13,6,11,0,54,0,11,1,56,20,54,9,2,14,3,0,0,13,6,11,0,55,0,11,1,56,5,55,9,2,15,3,0,0,3,14,10,0,11,1,56,6,12,2,4,6,5,10,11,0,1,7,4,39,11,0,11,2,56,22,2,16,3,0,0,31,14,11,0,58,0,1,1,1,1,12,2,12,1,1,11,1,56,23,11,2,56,24,2,17,3,0,0,31,23,14,0,55,0,56,2,6,0,0,0,0,0,0,0,0,33,4,7,5,9,6,0,0,0,0,0,0,0,0,39,11,0,58,0,1,1,1,1,12,2,12,1,1,11,2,56,25,11,1,56,26,2,18,0,0,0,32,46,10,0,55,7,20,12,3,10,3,7,9,33,4,12,11,0,1,7,9,2,10,3,7,9,35,4,40,5,17,10,0,55,5,11,3,56,8,12,2,10,1,10,2,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,35,11,2,16,7,20,12,3,5,39,11,2,16,8,20,12,3,5,12,11,0,1,7,10,11,3,23,2,19,0,0,0,13,55,10,1,7,9,34,4,5,5,9,11,0,1,7,7,39,11,3,4,19,10,2,10,0,54,5,10,1,56,19,15,7,21,5,26,10,2,10,0,54,5,10,1,56,19,15,8,21,10,2,7,9,34,4,52,10,2,7,9,36,4,44,11,1,11,0,54,0,7,10,11,2,23,56,20,54,4,21,5,51,11,1,11,0,54,5,11,2,56,19,15,6,21,5,54,11,0,1,2,20,0,0,0,13,9,11,0,55,5,11,1,56,8,16,7,20,11,2,33,2,21,0,0,0,33,107,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,49,128,12,1,5,105,49,0,12,2,10,0,50,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,23,11,0,49,64,47,12,0,11,2,49,64,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,37,11,0,49,32,47,12,0,11,2,49,32,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,51,11,0,49,16,47,12,0,11,2,49,16,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,65,11,0,49,8,47,12,0,11,2,49,8,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,79,11,0,49,4,47,12,0,11,2,49,4,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,93,11,0,49,2,47,12,0,11,2,49,2,22,12,2,11,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,103,11,2,49,1,22,12,2,11,2,12,1,11,1,2,2,2,2,3,0,0,2,4,0,2,2,1,1,3,1,1,1,2,2,6,2,0,2,5,1,0,0,1,0,10,1,10,2,10,3,10,4,10,5,10,9,10,10,10,11,10,13,10,0,11,0],"custodian":[161,28,235,11,6,0,0,0,14,1,0,12,2,12,48,3,60,158,1,4,218,1,30,5,248,1,246,1,7,238,3,166,4,8,148,8,64,6,212,8,10,10,222,8,38,11,132,9,4,12,136,9,238,2,13,246,11,8,14,254,11,6,15,132,12,2,0,23,1,15,1,21,1,35,1,37,1,38,0,0,4,1,0,1,0,1,12,0,0,4,12,1,0,1,1,2,4,1,0,1,2,3,12,1,0,1,3,5,7,0,3,8,4,0,4,6,12,2,7,1,4,1,5,7,2,0,0,33,0,1,0,0,10,2,3,1,0,0,34,0,4,1,0,0,42,5,6,1,0,0,28,7,8,1,0,0,24,9,10,1,0,0,29,11,8,1,0,0,25,12,10,1,0,0,31,9,8,1,0,0,40,12,8,1,0,0,9,2,13,1,0,0,12,2,13,1,0,0,19,14,15,1,0,0,17,2,16,1,0,1,30,27,13,1,0,1,36,30,10,1,0,1,41,24,13,1,0,1,43,8,10,1,0,2,26,26,6,1,0,3,34,0,17,0,3,39,28,29,0,4,13,31,8,2,7,4,4,16,21,23,2,7,4,4,18,32,33,2,7,4,4,22,21,22,2,7,4,4,34,0,25,2,7,4,24,20,22,20,16,19,25,20,5,19,18,19,12,19,14,19,15,19,6,19,7,19,4,19,17,19,21,20,23,20,1,7,8,8,1,8,1,2,6,11,2,1,9,0,8,5,2,3,3,1,11,2,1,9,0,4,7,11,2,1,9,0,3,6,8,1,7,8,8,1,11,4,1,9,0,3,7,11,2,1,9,0,8,5,11,3,1,9,0,0,3,7,11,2,1,9,0,6,8,1,3,1,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,11,3,1,9,0,3,7,11,2,1,9,0,8,5,3,1,3,2,7,11,2,1,9,0,8,5,1,7,11,0,1,9,0,1,6,11,0,1,9,0,1,8,6,3,6,11,0,1,9,0,3,3,1,9,0,2,8,5,11,0,1,9,0,2,6,11,7,2,9,0,9,1,9,0,1,1,1,6,9,1,1,6,11,3,1,9,0,1,11,7,2,9,0,9,1,2,11,3,1,9,0,7,8,8,2,7,11,3,1,9,0,11,3,1,9,0,1,6,8,6,1,8,5,2,7,11,3,1,9,0,3,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,7,9,1,7,65,99,99,111,117,110,116,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,4,67,111,105,110,9,67,117,115,116,111,100,105,97,110,2,73,68,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,16,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,115,22,97,99,99,111,117,110,116,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,3,97,100,100,17,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,22,98,111,114,114,111,119,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,26,98,111,114,114,111,119,95,109,117,116,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,4,99,108,111,98,4,99,111,105,110,8,99,111,110,116,97,105,110,115,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,105,110,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,4,106,111,105,110,12,108,111,99,107,95,98,97,108,97,110,99,101,14,108,111,99,107,101,100,95,98,97,108,97,110,99,101,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,110,101,119,6,111,98,106,101,99,116,5,115,112,108,105,116,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,0,2,2,14,11,3,1,9,0,32,11,3,1,9,0,1,2,1,27,8,6,2,2,2,27,8,6,11,11,7,2,8,5,11,0,1,9,0,2,19,0,19,0,1,0,0,8,4,11,0,17,19,18,1,2,1,3,0,0,18,27,10,0,55,0,10,1,56,0,32,4,11,11,0,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,2,11,0,55,0,11,1,56,1,12,2,10,2,55,1,56,2,12,3,11,2,55,2,56,2,12,4,11,3,11,4,2,2,3,0,0,8,6,10,0,17,19,11,0,56,3,57,0,2,3,3,0,0,8,7,11,0,11,2,11,1,56,4,11,3,56,5,2,4,3,0,0,8,8,11,0,11,1,56,6,54,1,11,2,56,7,1,2,5,3,0,0,8,9,11,0,11,1,16,3,17,20,56,6,54,1,11,2,56,8,2,6,3,0,0,8,10,11,0,11,1,16,3,17,20,56,6,54,2,11,2,56,7,1,2,7,3,0,0,8,7,11,0,11,1,56,6,54,2,11,2,56,8,2,8,3,0,0,10,10,10,0,10,1,11,2,56,4,12,3,11,0,11,1,11,3,56,9,2,9,3,0,0,10,10,10,0,10,1,11,2,56,10,12,3,11,0,11,1,11,3,56,11,2,10,3,0,0,8,7,11,0,55,0,11,1,56,1,55,1,56,2,2,11,3,0,0,8,7,11,0,55,0,11,1,56,1,55,2,56,2,2,12,0,0,0,8,18,10,0,55,0,10,1,56,0,32,4,13,10,0,54,0,10,1,56,12,56,12,57,1,56,13,11,0,54,0,11,1,56,14,2,13,0,0,0,8,15,10,0,55,0,10,1,56,0,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,1,2,2,1,0,0,0,1,1,0,0,19,1,19,2,19,0,20,0],"math":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,30,5,32,13,7,45,79,8,124,32,6,156,1,38,12,194,1,133,2,15,199,3,2,0,2,0,6,0,1,0,0,7,0,2,0,0,3,0,1,0,0,4,0,2,0,0,5,0,2,0,0,1,0,2,0,2,3,3,1,3,2,1,3,0,3,1,4,4,4,99,108,111,98,9,100,105,118,95,114,111,117,110,100,4,109,97,116,104,3,109,117,108,9,109,117,108,95,114,111,117,110,100,16,117,110,115,97,102,101,95,100,105,118,95,114,111,117,110,100,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,3,8,0,202,154,59,0,0,0,0,4,16,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,3,0,0,1,7,11,0,11,1,17,1,12,2,1,11,2,2,1,3,0,0,4,26,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,10,4,24,7,1,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,18,9,12,2,11,2,11,3,11,4,24,7,1,26,52,2,2,1,0,0,1,14,11,0,11,1,17,1,12,2,1,10,2,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,2,3,1,0,0,2,15,11,0,11,1,17,1,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,4,3,0,0,4,28,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,7,0,53,24,10,4,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,9,12,2,11,2,11,3,7,0,53,24,11,4,26,52,2,5,1,0,0,2,15,11,0,11,1,17,4,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,0,0,0]},"type_origin_table":[{"module_name":"custodian","struct_name":"Account","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"AccountCap","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"Custodian","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"Leaf","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"InternalNode","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"CritbitTree","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"PoolCreated","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlacedV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilledV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Order","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"TickLevel","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Pool","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlaced","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Move":{"type_":"GasCoin","has_public_transfer":true,"version":4346051,"contents":[21,32,188,177,31,211,164,184,188,23,93,46,13,51,223,242,149,206,222,73,87,55,189,56,32,255,148,164,64,84,144,4,144,115,177,150,11,0,0,0]}},"owner":{"AddressOwner":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497"},"previous_transaction":"GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","storage_rebate":988000},{"data":{"Move":{"type_":{"Other":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"governance_v1","name":"Proposal","type_args":[{"struct":{"address":"7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d","module":"migrate_proposal","name":"Certificate","type_args":[]}}]}},"has_public_transfer":false,"version":4346051,"contents":[57,252,244,217,254,131,156,97,185,211,22,22,230,144,104,131,113,142,173,223,177,229,32,89,200,170,223,35,213,70,217,52,101,133,153,88,189,98,227,10,160,87,31,151,18,150,47,89,9,141,30,178,159,115,176,145,217,215,19,23,216,230,116,151,55,0,0,0,0,0,0,0,0,85,0,0,0,0,0,0,0,64,55,102,54,98,51,56,48,100,98,102,51,54,50,51,54,50,48,53,54,49,53,99,54,52,102,99,98,98,54,99,52,101,57,52,53,52,98,55,54,101,102,102,48,57,55,100,100,54,99,54,53,51,52,102,54,100,53,48,55,48,100,49,55,100,0,0,0,1]}},"owner":{"Shared":{"initial_shared_version":4346051}},"previous_transaction":"GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","storage_rebate":2728400},{"data":{"Move":{"type_":{"Other":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"genesis","name":"GovernanceGenesis","type_args":[]}},"has_public_transfer":false,"version":4346049,"contents":[66,239,144,6,110,100,146,21,230,171,145,57,154,131,225,165,70,127,215,204,67,110,139,131,173,184,116,58,14,251,166,33,4,81,180,29,10,30,207,114,139,134,133,233,172,144,221,93,63,141,97,190,62,113,16,212,34,139,152,136,114,24,131,222,197,178,165,4,156,215,21,134,54,45,12,106,56,227,76,250,174,126,169,206,109,84,1,163,80,80,106,21,248,23,191,114,2,0,0,0,0,0,0,0,0,1,254,147,243,188,197,217,213,55,232,158,184,214,115,240,234,207,29,60,135,22,250,128,58,250,46,171,68,79,42,167,134,211]}},"owner":{"Shared":{"initial_shared_version":3478819}},"previous_transaction":"6B3tXa5PpoaRUQiYcytsC1M9fkfzXUc49NsWgC335qC1","storage_rebate":2181200},{"data":{"Move":{"type_":{"Other":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"governance_v1","name":"GovernanceInfo","type_args":[]}},"has_public_transfer":false,"version":4346051,"contents":[121,215,16,110,161,131,115,252,117,66,176,132,157,94,190,252,58,157,175,139,102,74,79,130,217,179,91,189,12,34,4,45,1,254,147,243,188,197,217,213,55,232,158,184,214,115,240,234,207,29,60,135,22,250,128,58,250,46,171,68,79,42,167,134,211,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,0,0,0,0,0,0,0,1,101,133,153,88,189,98,227,10,160,87,31,151,18,150,47,89,9,141,30,178,159,115,176,145,217,215,19,23,216,230,116,151,0]}},"owner":{"Shared":{"initial_shared_version":3195547}},"previous_transaction":"GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","storage_rebate":2097600},{"data":{"Package":{"id":"0x7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d","version":1,"module_map":{"migrate_proposal":[161,28,235,11,6,0,0,0,10,1,0,10,2,10,40,3,50,68,4,118,14,5,132,1,130,1,7,134,2,192,2,8,198,4,128,1,6,198,5,20,10,218,5,5,12,223,5,118,0,19,3,14,3,16,1,21,2,22,0,0,6,0,1,1,0,0,1,2,8,0,1,7,7,0,1,8,7,0,2,3,8,0,2,5,8,1,6,0,3,4,7,1,0,0,4,6,2,0,0,9,0,1,0,0,23,2,1,0,0,20,3,1,0,1,15,1,16,0,1,20,18,1,2,6,6,2,9,6,1,1,6,2,10,9,1,0,2,24,8,7,1,6,3,11,12,1,1,0,3,13,14,15,1,0,3,17,10,11,1,0,3,18,10,11,1,0,5,5,7,5,10,9,8,9,11,9,9,9,4,17,2,7,8,5,7,8,8,0,3,6,8,5,7,11,6,1,8,0,7,8,8,4,6,8,5,7,11,6,1,8,0,7,8,2,7,8,8,1,7,8,8,1,8,0,3,6,8,5,9,0,7,8,8,1,11,7,1,8,1,5,6,8,5,9,0,7,11,6,1,9,0,1,7,8,8,1,8,1,1,6,11,7,1,9,0,1,1,1,11,7,1,9,0,3,8,1,11,7,1,8,1,8,4,1,7,11,7,1,9,0,1,9,0,1,8,4,2,8,3,8,4,3,6,8,1,7,8,2,9,1,11,67,101,114,116,105,102,105,99,97,116,101,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,9,84,120,67,111,110,116,101,120,116,13,86,101,114,115,105,111,110,95,49,95,48,95,48,13,86,101,114,115,105,111,110,95,49,95,48,95,49,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,12,100,101,115,116,114,111,121,95,110,111,110,101,11,100,117,109,109,121,95,102,105,101,108,100,7,101,120,116,114,97,99,116,7,103,101,110,101,115,105,115,17,103,101,116,95,118,101,114,115,105,111,110,95,49,95,48,95,49,13,103,111,118,101,114,110,97,110,99,101,95,118,49,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,16,109,105,103,114,97,116,101,95,112,114,111,112,111,115,97,108,15,109,105,103,114,97,116,101,95,118,101,114,115,105,111,110,6,111,112,116,105,111,110,10,116,120,95,99,111,110,116,101,120,116,13,118,111,116,101,95,112,111,114,112,111,115,97,108,13,118,111,116,101,95,112,114,111,112,111,115,97,108,127,107,56,13,191,54,35,98,5,97,92,100,252,187,108,78,148,84,183,110,255,9,125,214,198,83,79,109,80,112,209,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,12,1,0,1,4,0,4,9,11,0,11,1,12,2,46,9,18,0,11,2,56,0,2,1,1,4,0,7,17,11,0,9,18,0,11,1,8,11,2,56,1,12,3,14,3,56,2,4,12,5,14,7,1,39,11,3,56,3,2,2,1,0,0,13,30,11,0,9,18,0,11,1,8,11,3,56,1,12,5,14,5,56,4,4,12,5,16,11,2,1,7,0,39,13,5,56,5,12,4,17,3,12,6,14,4,11,2,11,6,56,6,11,4,17,6,11,5,56,3,2,0]},"type_origin_table":[{"module_name":"migrate_proposal","struct_name":"Certificate","package":"0x7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":6},"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302":{"upgraded_id":"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302","upgraded_version":1},"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a":{"upgraded_id":"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a","upgraded_version":1},"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e":{"upgraded_id":"0xc5b2a5049cd71586362d0c6a38e34cfaae7ea9ce6d5401a350506a15f817bf72","upgraded_version":2}}}},"owner":"Immutable","previous_transaction":"5kWByxejQ95cxQ5zUCba3WyivedWBmtisRa4ZaWJuWpm","storage_rebate":10830000},{"data":{"Package":{"id":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","version":1,"module_map":{"app_manager":[161,28,235,11,6,0,0,0,10,1,0,10,2,10,24,3,34,46,4,80,2,5,82,54,7,136,1,228,1,8,236,2,64,10,172,3,18,12,190,3,106,13,168,4,4,0,8,0,11,1,16,1,20,1,21,0,3,12,0,0,0,12,0,1,1,0,0,2,2,7,0,2,5,4,0,4,4,2,0,0,14,0,1,0,0,17,2,3,0,0,18,4,3,0,0,12,5,6,0,0,10,3,1,0,2,9,7,1,0,2,15,0,7,0,2,22,12,8,0,3,19,10,1,1,8,8,9,1,7,8,5,0,2,7,8,0,7,8,5,1,8,1,3,6,8,2,7,8,0,7,8,5,1,6,8,1,1,13,1,8,4,1,8,3,1,8,0,1,9,0,3,8,1,8,3,8,4,1,6,8,4,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,2,73,68,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,97,112,112,95,99,97,112,115,6,97,112,112,95,105,100,11,97,112,112,95,109,97,110,97,103,101,114,6,100,101,108,101,116,101,15,100,101,115,116,114,111,121,95,97,112,112,95,99,97,112,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,2,105,100,4,105,110,105,116,3,110,101,119,6,111,98,106,101,99,116,12,114,101,103,105,115,116,101,114,95,97,112,112,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,8,4,6,10,8,3,1,2,2,13,8,4,7,13,0,0,0,0,1,6,11,0,17,6,64,8,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,11,19,11,1,17,6,12,4,14,4,17,7,12,3,11,4,10,0,16,0,65,8,75,18,1,12,2,11,0,15,0,11,3,68,8,11,2,2,2,1,0,0,1,4,11,1,11,2,17,1,2,3,1,0,0,1,4,11,0,16,1,20,2,4,1,0,0,1,5,11,0,19,1,1,17,5,2,0,1,1,1,0],"dola_address":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,12,3,24,109,4,133,1,6,5,139,1,78,7,217,1,191,3,8,152,5,96,6,248,5,14,10,134,6,8,12,142,6,151,2,13,165,8,4,0,13,0,23,1,4,1,27,2,3,2,5,0,0,7,0,2,1,7,0,3,2,7,0,0,20,0,1,0,0,19,2,1,0,0,18,2,3,0,0,29,4,5,0,0,28,6,5,0,0,10,7,5,0,0,6,8,5,0,0,7,5,8,0,0,9,0,5,1,0,0,8,5,3,0,0,15,5,3,0,0,11,3,5,0,1,12,19,1,0,1,24,14,0,0,1,25,15,0,0,1,30,17,18,1,1,2,21,13,3,0,3,17,0,12,1,0,3,22,12,13,0,4,16,3,8,0,5,26,9,3,1,0,20,8,17,11,15,10,0,1,13,1,6,8,0,1,10,2,2,8,0,13,1,8,0,2,8,0,10,2,2,13,10,2,1,5,1,6,9,0,1,2,1,9,0,1,8,2,1,8,1,2,7,10,2,13,2,7,10,2,10,2,6,10,2,3,10,2,13,3,3,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,11,68,111,108,97,65,100,100,114,101,115,115,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,112,111,111,108,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,19,117,112,100,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,13,2,0,0,0,2,2,14,13,13,10,2,0,1,0,0,0,2,7,1,2,1,1,0,0,0,4,11,0,16,0,20,2,2,1,0,0,0,4,11,0,16,1,20,2,3,1,0,0,0,6,11,1,13,0,15,0,21,11,0,2,4,1,0,0,0,6,11,1,13,0,15,1,21,11,0,2,5,1,0,0,0,4,11,0,11,1,18,0,2,6,1,0,0,0,5,7,1,14,0,56,0,18,0,2,7,1,0,0,0,14,14,0,16,1,65,10,6,32,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,14,0,16,1,20,17,19,2,8,1,0,0,3,8,56,1,17,18,17,16,12,0,7,1,11,0,18,0,2,9,1,0,0,0,4,14,0,16,1,20,2,10,1,0,0,3,14,64,10,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,17,13,13,1,14,0,16,1,20,17,14,11,1,2,11,1,0,0,16,30,14,0,65,10,12,6,6,0,0,0,0,0,0,0,0,12,5,6,2,0,0,0,0,0,0,0,12,2,14,0,10,5,10,5,10,2,22,56,2,12,1,14,1,17,12,12,4,11,5,11,2,22,12,5,14,0,11,5,11,6,56,2,12,3,11,4,11,3,18,0,2,0,0,0,1,0],"dola_pool":[161,28,235,11,6,0,0,0,14,1,0,22,2,22,52,3,74,173,1,4,247,1,32,5,151,2,211,1,7,234,3,168,5,8,146,9,96,6,242,9,50,10,164,10,34,11,198,10,2,12,200,10,222,2,13,166,13,4,14,170,13,4,15,174,13,4,0,23,0,22,0,45,1,12,1,54,2,13,2,14,2,27,2,43,2,52,2,53,0,5,12,1,0,1,0,3,3,0,0,10,3,0,1,4,7,0,3,6,7,0,4,8,7,0,5,0,4,1,0,1,6,1,12,1,0,1,6,2,12,1,0,1,8,9,4,0,10,7,2,0,0,30,0,1,1,0,0,19,2,3,1,0,0,16,4,5,0,0,42,6,5,1,0,0,55,6,5,1,0,0,21,7,8,1,0,0,57,9,3,1,0,0,48,10,8,0,1,15,19,21,0,1,17,21,19,0,1,18,3,21,1,0,1,32,30,8,0,1,33,30,29,0,1,34,3,29,0,2,25,22,8,0,2,26,35,8,0,3,37,26,8,0,4,29,3,25,1,0,4,38,25,26,0,5,39,24,5,1,0,5,51,31,15,1,0,5,59,3,15,1,0,6,28,32,23,1,0,6,31,12,1,1,0,6,36,23,15,1,0,6,56,20,5,1,0,7,24,11,3,1,3,8,41,13,14,0,9,46,34,3,1,12,9,50,11,3,1,8,10,49,18,19,0,23,11,21,11,29,16,0,11,25,11,3,11,10,11,24,11,19,11,17,11,26,27,4,11,20,11,22,11,26,33,28,23,1,6,11,0,1,9,0,1,2,2,6,11,8,1,9,0,7,8,10,0,3,3,2,2,1,3,2,6,11,0,1,9,0,3,5,7,11,0,1,9,0,11,7,1,9,0,13,10,2,7,8,10,1,10,2,5,7,11,0,1,9,0,8,3,3,8,3,7,8,10,3,13,10,2,7,8,10,1,9,0,1,6,11,8,1,9,0,1,7,8,10,1,8,9,1,11,6,1,9,0,1,11,0,1,9,0,6,3,3,3,10,2,5,8,3,1,6,8,10,1,5,1,6,11,7,1,9,0,1,8,3,5,8,3,8,3,3,13,10,2,1,11,7,1,9,0,2,7,11,6,1,9,0,11,6,1,9,0,1,8,5,1,8,4,1,8,1,3,3,11,7,1,9,0,5,1,13,1,6,8,3,2,7,11,6,1,9,0,3,2,11,6,1,9,0,7,8,10,1,8,2,2,9,0,5,3,8,3,13,10,2,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,11,68,101,112,111,115,105,116,80,111,111,108,11,68,111,108,97,65,100,100,114,101,115,115,4,80,111,111,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,12,87,105,116,104,100,114,97,119,80,111,111,108,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,11,99,114,101,97,116,101,95,112,111,111,108,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,4,101,109,105,116,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,12,103,101,116,95,100,101,99,105,109,97,108,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,12,105,110,116,111,95,98,97,108,97,110,99,101,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,10,112,111,111,108,95,99,111,100,101,99,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,35,8,9,13,11,6,1,9,0,20,2,1,2,3,44,8,4,49,5,11,3,2,2,3,44,8,4,47,5,11,3,0,11,0,1,0,0,3,4,11,0,55,0,20,2,1,1,0,0,1,10,11,0,56,0,12,2,11,1,17,27,56,1,11,2,57,0,56,2,2,2,1,0,0,3,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,3,1,0,0,1,8,11,0,56,3,12,2,11,1,11,2,49,8,17,2,2,4,1,0,0,1,8,11,0,56,3,12,2,11,1,49,8,11,2,17,2,2,5,3,0,0,17,38,11,4,46,17,30,12,9,14,1,56,4,12,7,10,0,10,7,12,5,46,11,5,56,5,12,6,10,9,17,8,12,10,56,6,11,10,11,6,11,2,11,3,17,14,12,8,11,0,54,1,11,1,56,7,56,8,1,56,9,17,18,11,9,11,7,18,1,56,10,11,8,2,6,3,0,0,28,53,17,13,14,3,17,12,33,4,6,5,12,11,0,1,11,4,1,7,4,39,14,3,17,11,56,9,17,18,17,16,33,4,20,5,26,11,0,1,11,4,1,7,0,39,11,1,17,9,12,7,10,0,11,2,12,5,46,11,5,56,11,12,2,11,0,54,1,10,2,56,12,11,4,56,13,12,6,56,9,17,18,10,7,11,2,18,2,56,14,11,6,11,7,56,15,2,7,3,0,0,3,8,11,2,46,17,30,17,8,11,0,11,1,17,15,2,0,2,0,1,0,11,1,11,0,40,0,58,0],"equilibrium_fee":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,50,5,54,29,7,83,174,1,8,129,2,32,12,161,2,197,5,0,4,0,10,0,2,0,1,0,0,3,2,1,0,0,0,3,1,0,0,1,3,1,0,1,5,0,1,0,1,6,4,1,0,1,7,0,1,0,1,8,4,1,0,1,9,1,1,0,1,11,0,1,0,2,15,15,1,15,3,15,15,15,6,15,15,15,15,15,15,0,4,1,15,15,15,6,1,15,15,15,15,15,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,27,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,112,101,114,99,101,110,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,1,13,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,11,11,1,11,0,17,6,12,2,11,2,2,1,1,0,0,1,17,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,15,11,0,11,1,17,6,11,2,17,6,17,5,17,4,12,3,11,3,2,2,1,0,0,5,93,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,1,10,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,2,23,10,0,10,2,23,10,3,17,1,10,4,36,4,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,10,4,36,4,50,10,1,10,0,10,4,17,9,10,3,17,9,23,17,5,10,4,10,3,17,9,23,17,6,12,7,5,52,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,12,9,10,2,10,9,23,10,5,17,5,10,4,10,3,17,9,23,17,9,24,10,4,10,3,17,9,26,12,8,10,0,11,1,23,11,5,17,7,17,9,24,10,0,11,9,23,11,0,11,2,23,17,6,17,8,17,9,11,4,11,3,17,9,26,11,8,23,2,3,1,0,0,6,51,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,12,7,11,1,10,2,22,11,0,10,2,22,11,3,17,1,11,7,23,12,9,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,4,11,5,17,6,24,12,11,11,2,11,11,17,6,17,5,17,4,12,10,11,9,11,10,17,4,12,8,11,4,11,8,17,9,2,0],"genesis":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,52,3,70,123,4,193,1,22,5,215,1,167,1,7,254,2,226,3,8,224,6,96,6,192,7,61,10,253,7,34,12,159,8,137,2,13,168,10,6,15,174,10,2,0,25,1,14,1,42,1,44,2,23,2,36,2,37,2,40,2,41,0,0,0,0,0,2,12,0,0,1,8,0,0,11,7,0,0,12,7,0,1,4,7,0,2,6,7,0,5,3,7,0,5,7,4,0,6,8,12,0,6,9,0,0,6,10,0,0,8,5,2,0,0,31,0,1,0,0,15,2,3,0,0,17,4,5,0,0,34,6,5,2,6,6,0,18,7,8,0,0,20,8,5,0,0,21,9,5,0,0,16,10,5,0,1,32,29,30,0,2,26,5,22,1,0,2,27,28,29,0,3,30,33,34,1,0,3,38,35,19,1,0,4,13,16,5,2,7,4,4,24,24,25,2,7,4,4,38,26,27,2,7,4,5,19,13,5,0,5,29,17,14,1,8,5,35,12,13,0,6,15,20,3,0,6,17,21,5,0,7,39,19,5,1,8,13,15,17,1,21,18,14,23,15,23,9,27,9,19,13,31,11,14,12,14,14,15,2,8,9,7,8,12,1,8,1,4,6,8,0,7,8,2,2,10,2,1,8,11,2,7,8,2,8,10,0,3,6,8,0,7,8,2,9,1,1,6,8,1,1,8,0,2,7,8,2,8,1,1,6,8,2,2,8,2,8,1,1,7,8,12,1,8,8,1,8,7,2,8,3,8,4,3,7,8,8,9,0,9,1,1,6,9,0,1,8,2,1,9,0,3,7,8,9,2,10,2,2,7,8,9,8,10,1,8,6,2,8,3,9,0,2,6,8,8,9,0,1,1,2,7,8,8,9,0,1,9,1,1,6,8,6,1,8,5,1,10,2,2,8,3,9,1,2,3,8,7,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,7,86,101,114,115,105,111,110,13,86,101,114,115,105,111,110,95,49,95,48,95,48,3,97,100,100,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,15,100,101,115,116,114,111,121,95,109,97,110,97,103,101,114,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,7,103,101,110,101,115,105,115,3,103,101,116,10,103,101,116,95,109,111,100,117,108,101,13,103,111,118,101,114,110,97,110,99,101,95,118,49,2,105,100,8,105,110,100,101,120,95,111,102,12,105,110,105,116,95,103,101,110,101,115,105,115,10,105,110,116,111,95,98,121,116,101,115,11,109,97,110,97,103,101,114,95,105,100,115,15,109,105,103,114,97,116,101,95,118,101,114,115,105,111,110,3,110,101,119,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,11,117,112,103,114,97,100,101,95,99,97,112,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,10,2,8,7,103,101,110,101,115,105,115,0,2,1,22,1,1,2,1,29,8,8,2,2,3,29,8,8,43,8,9,33,10,8,7,3,2,1,22,1,4,2,1,22,1,0,3,0,0,11,26,10,1,17,18,11,0,64,14,0,0,0,0,0,0,0,0,18,2,12,2,11,1,17,18,18,1,12,3,13,2,15,0,9,18,3,9,18,4,56,0,13,2,15,1,14,3,56,1,68,14,11,2,56,2,11,3,2,1,1,0,0,5,6,11,1,15,2,11,2,11,3,17,19,2,2,1,0,0,5,5,11,0,15,2,11,1,17,20,2,3,1,0,0,22,47,10,1,15,0,46,9,18,3,56,3,4,8,5,12,11,1,1,7,1,39,10,1,15,0,9,18,3,56,4,1,56,5,12,3,10,3,56,6,34,4,25,5,29,11,1,1,7,2,39,14,3,17,10,17,8,7,5,33,4,36,5,40,11,1,1,7,3,39,11,1,15,0,9,18,3,11,2,56,7,2,4,1,0,0,5,3,9,18,0,2,5,1,0,0,5,4,11,0,19,0,1,2,6,1,0,0,32,18,14,1,56,1,12,3,10,0,16,1,14,3,56,8,12,2,1,11,0,15,1,11,2,56,9,1,11,1,19,1,17,16,2,7,1,0,0,5,10,11,0,16,0,9,18,3,56,10,4,7,5,9,7,4,39,2,2,0,2,2,2,1,0,28,0],"governance_v1":[161,28,235,11,6,0,0,0,13,1,0,22,2,22,56,3,78,198,1,4,148,2,40,5,188,2,148,2,7,208,4,155,6,8,235,10,96,6,203,11,207,1,10,154,13,72,11,226,13,2,12,228,13,215,9,13,187,23,28,14,215,23,14,0,43,0,38,1,18,1,57,1,71,1,75,2,33,2,56,2,58,2,69,2,70,0,3,8,0,0,7,8,1,6,0,0,1,3,0,0,0,3,0,1,2,0,0,1,4,12,0,2,8,7,0,3,6,7,1,0,0,4,10,7,0,7,5,7,0,7,11,4,0,8,12,12,0,10,9,2,0,0,47,0,1,0,0,13,2,1,0,0,74,3,4,0,0,15,5,1,0,0,62,5,1,0,0,73,6,1,0,0,22,7,1,0,0,31,8,9,0,0,41,10,11,1,6,0,28,12,1,0,0,25,13,1,1,6,0,76,14,15,1,6,0,20,10,1,1,6,1,24,47,12,0,1,27,12,1,0,1,48,25,4,0,2,68,35,11,0,3,19,46,44,1,0,3,35,27,23,1,0,3,37,26,1,1,0,3,49,46,9,1,0,3,50,46,9,1,0,3,55,1,20,1,0,3,65,23,20,1,0,4,39,1,39,1,0,4,40,40,11,0,5,23,29,9,1,0,5,46,29,31,1,0,5,61,32,23,1,0,6,29,23,1,1,3,7,45,44,21,1,8,7,53,0,19,0,7,72,37,38,0,9,64,23,1,1,8,10,32,18,34,0,10,63,18,17,0,22,4,33,22,19,4,18,4,26,17,27,17,28,17,22,34,23,34,24,23,33,41,29,42,30,41,29,45,20,34,17,34,17,4,23,12,21,34,22,12,1,7,8,12,0,3,8,11,7,8,0,7,8,12,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,1,9,0,7,8,12,1,8,6,1,8,4,3,6,8,0,9,0,7,8,12,5,6,8,0,9,0,7,11,1,1,9,0,1,7,8,12,1,11,7,1,8,4,1,10,5,1,5,1,6,8,12,1,8,10,1,11,7,1,9,0,1,8,9,1,8,0,1,9,0,2,5,1,2,8,11,7,8,12,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,1,10,2,12,8,8,3,11,7,1,3,3,5,8,10,5,11,7,1,3,3,8,10,8,9,3,1,6,8,10,1,6,8,9,1,8,8,1,6,8,8,1,11,1,1,9,0,1,8,2,11,1,6,5,6,5,1,1,7,10,5,3,7,10,5,3,3,5,1,6,9,0,1,8,3,1,6,11,7,1,9,0,1,6,8,5,11,67,104,97,110,103,101,83,116,97,116,101,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,10,97,100,100,95,109,101,109,98,101,114,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,12,99,104,101,99,107,95,109,101,109,98,101,114,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,49,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,103,101,110,101,115,105,115,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,9,109,97,120,95,100,101,108,97,121,7,109,101,109,98,101,114,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,6,114,101,109,111,118,101,13,114,101,109,111,118,101,95,109,101,109,98,101,114,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,7,117,112,103,114,97,100,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,8,45,8,10,42,11,7,1,8,5,14,1,17,3,77,3,51,3,52,10,5,44,10,8,9,1,2,10,45,8,10,26,5,66,3,30,11,7,1,3,34,3,59,8,6,21,9,0,36,10,5,16,10,5,67,2,2,2,1,60,8,9,3,2,2,60,8,9,54,2,1,23,0,0,0,0,16,19,64,17,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,35,68,17,11,0,17,31,56,0,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,11,1,64,21,0,0,0,0,0,0,0,0,18,0,56,1,2,1,1,4,0,24,42,10,1,10,2,46,17,35,12,3,46,11,3,17,6,10,1,16,0,20,32,4,20,10,1,16,1,65,21,6,0,0,0,0,0,0,0,0,33,12,4,5,22,9,12,4,11,4,4,25,5,31,11,1,1,11,2,1,7,5,39,10,1,15,2,11,0,11,2,17,15,56,2,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,2,56,3,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,28,19,10,1,15,3,14,2,12,3,46,11,3,56,4,32,4,10,5,14,11,1,1,7,9,39,11,1,15,3,11,2,68,17,2,4,1,0,0,30,21,10,1,10,2,12,3,46,11,3,17,6,10,1,15,3,14,2,12,4,46,11,4,56,5,12,5,1,11,1,15,3,11,5,56,6,1,2,5,1,0,0,1,24,10,4,10,3,10,2,22,36,4,7,5,11,11,1,1,7,7,39,11,2,10,1,15,4,21,11,3,10,1,15,5,21,11,4,11,1,15,6,21,2,6,1,0,0,1,9,11,0,16,3,14,1,56,4,4,6,5,8,7,8,39,2,7,1,0,0,8,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,8,1,0,0,33,75,11,1,46,17,34,12,7,10,0,55,0,20,7,2,33,4,16,11,0,1,7,16,17,16,12,6,5,73,10,0,55,0,20,7,3,33,4,28,11,0,1,7,17,17,16,12,5,5,71,10,0,55,0,20,7,4,33,4,40,11,0,1,7,18,17,16,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,19,17,16,12,3,5,67,11,0,55,0,20,7,0,33,4,62,7,20,17,16,12,2,5,65,7,21,17,16,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,9,1,0,0,1,3,11,0,17,14,2,10,1,0,0,36,86,10,0,16,0,20,4,5,5,11,11,0,1,11,2,1,7,6,39,10,2,46,17,35,12,9,10,0,10,9,17,6,10,2,46,17,34,10,0,16,4,20,22,12,14,10,0,16,5,20,6,0,0,0,0,0,0,0,0,33,4,35,56,7,12,10,5,42,10,14,10,0,16,5,20,22,56,8,12,10,10,2,46,17,34,11,0,16,6,20,22,12,11,11,2,17,31,12,12,14,12,17,32,20,12,13,11,12,12,8,11,9,12,7,11,14,12,6,11,10,12,5,11,11,12,4,56,9,12,3,11,8,11,7,11,6,11,5,11,4,14,3,17,25,11,1,64,17,0,0,0,0,0,0,0,0,64,17,0,0,0,0,0,0,0,0,7,0,57,0,56,10,11,13,18,2,56,11,2,11,1,0,0,43,213,1,10,4,46,17,34,12,11,10,11,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,4,1,7,11,39,10,11,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,4,1,7,14,39,10,2,55,0,20,7,0,33,4,50,7,1,10,2,54,0,21,10,2,46,56,12,7,1,18,3,56,13,10,2,55,0,20,7,1,33,4,57,5,65,11,2,1,11,0,1,11,4,1,7,13,39,11,4,46,17,35,12,15,10,0,10,15,17,6,10,2,54,3,12,12,10,2,54,4,12,10,10,2,55,5,56,14,4,85,8,12,5,5,92,10,11,10,2,55,5,56,15,20,35,12,5,11,5,4,138,1,10,12,14,15,12,6,46,11,6,56,4,32,4,111,10,10,14,15,12,7,46,11,7,56,4,32,12,8,5,113,9,12,8,11,8,4,116,5,126,11,2,1,11,0,1,11,12,1,11,10,1,7,10,39,11,3,4,134,1,11,10,1,10,12,11,15,68,17,5,137,1,11,10,11,15,68,17,5,140,1,11,10,1,10,2,55,5,56,14,4,147,1,8,12,9,5,154,1,11,11,10,2,55,5,56,15,20,38,12,9,11,9,4,205,1,10,0,16,3,65,17,12,14,11,12,46,65,17,12,13,11,14,11,13,17,7,4,184,1,7,2,10,2,54,0,21,11,2,46,56,12,7,2,18,3,56,13,11,0,16,2,56,16,17,13,56,17,2,11,0,1,10,2,55,5,56,18,4,201,1,7,3,10,2,54,0,21,11,2,46,56,12,7,3,18,3,56,13,5,203,1,11,2,1,56,19,2,11,2,1,11,0,1,11,12,1,56,19,2,12,1,4,0,1,45,10,1,46,17,34,10,0,55,1,20,35,4,21,10,0,55,0,20,7,0,33,4,15,5,21,11,0,1,11,1,1,7,12,39,11,1,46,17,35,10,0,55,6,20,33,4,30,5,34,11,0,1,7,15,39,7,4,10,0,54,0,21,11,0,46,56,12,7,4,18,3,56,13,2,0,2,0,7,0,1,0,6,0,3,0,4,0,5,1,9,1,4,1,2,1,7,1,8,1,3,1,1,7,23,8,23,9,23,10,23,11,23,12,23,13,23,0],"governance_v2":[161,28,235,11,6,0,0,0,13,1,0,28,2,28,74,3,102,145,2,4,247,2,58,5,177,3,229,3,7,150,7,131,8,8,153,15,96,6,249,15,129,2,10,250,17,95,11,217,18,2,12,219,18,171,13,13,134,32,38,14,172,32,18,0,54,0,48,0,64,1,22,1,69,1,87,1,93,2,23,2,29,2,41,2,68,2,84,2,85,2,86,0,5,8,0,0,9,8,2,6,0,0,1,0,3,3,0,0,1,3,0,1,4,0,0,1,6,12,0,3,10,7,0,4,8,7,1,0,0,5,13,7,0,7,0,4,1,0,1,8,2,12,1,0,1,10,7,7,0,10,14,4,0,11,11,12,2,7,1,4,1,13,12,2,0,0,59,0,1,0,0,15,2,1,0,0,91,3,4,0,0,18,5,1,0,0,75,5,1,0,0,90,6,1,0,0,89,7,1,0,0,27,8,1,0,0,39,9,10,0,0,51,11,12,2,6,0,0,35,13,1,0,0,32,14,1,2,6,0,0,94,15,16,2,6,0,0,25,17,1,2,6,0,0,28,11,1,2,6,0,1,31,59,13,0,1,34,13,1,0,2,63,40,41,1,0,3,83,37,12,0,4,24,58,52,1,0,4,43,28,26,1,0,4,46,27,1,1,0,4,67,1,22,1,0,4,78,26,22,1,0,5,49,1,23,1,0,5,50,47,12,0,6,30,30,10,1,0,6,58,30,32,1,0,6,74,33,26,1,0,7,61,54,35,1,0,7,79,61,48,1,0,7,92,57,35,1,0,8,36,41,1,1,0,8,47,62,41,1,0,8,60,41,48,1,0,9,37,26,1,1,3,10,57,52,24,1,8,10,65,0,21,0,10,88,45,46,0,11,17,44,1,2,7,4,11,30,55,10,2,7,4,11,65,0,43,2,7,4,11,74,56,39,2,7,4,12,73,64,1,1,12,12,77,26,1,1,8,13,40,20,35,0,13,76,20,19,0,22,4,22,23,44,25,21,23,21,4,20,4,26,19,27,19,28,19,17,39,41,42,39,42,24,26,34,39,44,49,35,50,36,49,35,53,29,39,40,42,42,42,31,39,22,13,32,39,19,4,23,13,30,39,33,39,43,63,1,7,8,14,0,4,6,8,4,7,8,0,8,8,8,5,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,4,6,8,4,7,8,0,3,3,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,2,9,0,9,1,7,8,14,1,8,6,1,8,4,5,6,8,0,9,0,10,11,10,1,9,1,3,7,8,14,7,6,8,0,9,0,7,11,1,2,9,0,9,1,10,11,10,1,9,1,3,1,7,8,14,1,11,7,1,8,4,3,6,8,0,7,11,1,2,9,0,9,1,7,8,14,1,10,5,1,5,1,6,8,14,1,8,12,1,11,7,1,9,0,1,8,8,1,8,11,1,8,0,1,9,0,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,2,9,0,9,1,1,10,2,15,8,8,3,3,3,5,8,12,5,3,3,3,11,13,2,5,3,8,12,8,11,11,10,1,9,1,3,1,9,1,3,10,11,10,1,9,0,3,7,8,14,1,11,10,1,9,0,2,5,3,1,11,13,2,9,0,9,1,3,7,11,13,2,9,0,9,1,9,0,9,1,1,6,8,12,1,6,8,11,1,6,8,8,1,11,9,1,9,0,1,11,1,2,9,0,9,1,1,8,2,17,11,7,1,8,4,11,7,1,8,4,5,5,5,5,1,3,3,7,11,13,2,5,3,3,3,3,7,11,13,2,5,3,11,10,1,9,1,5,3,1,6,9,0,1,8,3,2,7,11,9,1,9,0,11,9,1,9,0,2,6,11,13,2,9,0,9,1,9,0,2,7,11,13,2,9,0,9,1,9,0,1,6,11,9,1,9,0,1,6,11,7,1,9,0,1,6,8,5,11,1,1,1,5,5,7,11,13,2,5,3,3,7,11,13,2,5,3,5,3,3,2,7,11,9,1,9,0,3,2,11,9,1,9,0,7,8,14,1,11,10,1,9,1,2,9,0,5,7,66,97,108,97,110,99,101,11,67,104,97,110,103,101,83,116,97,116,101,4,67,111,105,110,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,3,97,100,100,13,97,100,100,95,103,117,97,114,100,105,97,110,115,11,97,103,97,105,110,115,116,95,110,117,109,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,15,99,104,101,99,107,95,103,117,97,114,100,105,97,110,115,5,99,108,97,105,109,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,9,102,97,118,111,114,95,110,117,109,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,20,103,111,118,101,114,110,97,110,99,101,95,99,111,105,110,95,116,121,112,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,50,9,103,117,97,114,100,105,97,110,115,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,4,106,111,105,110,9,109,97,120,95,100,101,108,97,121,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,24,112,114,111,112,111,115,97,108,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,103,117,97,114,100,105,97,110,115,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,115,112,108,105,116,11,115,116,97,107,101,100,95,99,111,105,110,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,22,117,112,100,97,116,101,95,109,105,110,117,109,117,109,95,115,116,97,107,105,110,103,7,117,112,103,114,97,100,101,5,118,97,108,117,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,22,118,111,116,105,110,103,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,255,255,255,255,255,255,255,255,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,11,57,8,12,53,11,7,1,8,5,52,11,7,1,8,8,55,10,5,16,1,21,3,95,3,62,3,72,3,96,3,56,10,8,11,1,2,13,57,8,12,33,5,81,3,38,3,42,3,70,8,6,26,9,0,80,11,9,1,9,1,44,3,45,11,13,2,5,3,19,3,20,11,13,2,5,3,82,2,2,2,1,71,8,11,3,2,2,71,8,11,66,2,1,36,0,0,0,0,18,22,64,19,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,46,68,19,11,0,17,37,56,0,56,1,64,19,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,6,1,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,64,24,0,0,0,0,0,0,0,0,18,0,56,2,2,1,1,0,0,10,34,10,1,16,0,20,32,4,12,10,1,16,1,65,24,6,0,0,0,0,0,0,0,0,33,12,4,5,14,9,12,4,11,4,4,17,5,21,11,1,1,7,6,39,10,1,15,2,11,2,56,3,10,1,15,3,11,3,56,4,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,3,56,5,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,29,19,10,1,15,4,14,2,12,3,46,11,3,56,6,32,4,10,5,14,11,1,1,7,10,39,11,1,15,4,11,2,68,19,2,4,1,0,0,31,21,10,1,10,2,12,3,46,11,3,17,7,10,1,15,4,14,2,12,4,46,11,4,56,7,12,5,1,11,1,15,4,11,5,56,8,1,2,5,1,0,0,1,9,11,2,10,1,15,5,21,11,3,11,1,15,6,21,2,6,1,0,0,1,33,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,9,11,1,1,7,8,39,10,4,10,3,10,2,22,36,4,16,5,20,11,1,1,7,8,39,11,2,10,1,15,7,21,11,3,10,1,15,8,21,11,4,11,1,15,9,21,2,7,1,0,0,1,9,11,0,16,4,14,1,56,6,4,6,5,8,7,9,39,2,8,1,0,0,9,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,9,1,0,0,34,75,11,1,46,17,45,12,7,10,0,55,0,20,7,3,33,4,16,11,0,1,7,21,17,18,12,6,5,73,10,0,55,0,20,7,4,33,4,28,11,0,1,7,22,17,18,12,5,5,71,10,0,55,0,20,7,5,33,4,40,11,0,1,7,23,17,18,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,24,17,18,12,3,5,67,11,0,55,0,20,7,1,33,4,62,7,25,17,18,12,2,5,65,7,26,17,18,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,10,1,0,0,1,3,11,0,17,16,2,11,1,0,0,38,103,10,0,16,0,20,4,5,5,11,11,0,1,11,4,1,7,7,39,11,2,10,3,10,4,56,9,12,18,10,3,10,0,16,5,20,38,4,23,5,29,11,0,1,11,4,1,7,16,39,10,4,46,17,46,12,11,10,4,46,17,45,12,12,10,12,10,0,16,7,20,22,12,19,10,19,10,0,16,8,20,22,12,13,11,12,11,0,16,9,20,22,12,14,10,4,56,10,12,15,13,15,10,11,10,3,56,11,10,4,17,37,12,16,14,16,17,38,20,12,17,11,16,12,10,11,11,12,9,11,19,12,8,11,13,12,7,11,14,12,6,56,12,12,5,11,10,11,9,11,8,11,7,11,6,14,5,17,25,11,1,11,18,56,13,11,3,11,15,6,0,0,0,0,0,0,0,0,11,4,56,10,7,1,57,0,56,14,11,17,18,2,56,15,2,12,1,0,0,51,175,2,10,6,46,17,45,12,17,10,17,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,6,1,7,12,39,10,17,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,6,1,7,15,39,10,2,55,0,20,7,1,33,4,50,7,2,10,2,54,0,21,10,2,46,56,16,7,2,18,3,56,17,10,2,55,0,20,7,2,33,4,57,5,65,11,2,1,11,0,1,11,6,1,7,14,39,10,6,46,17,46,12,22,10,2,54,3,12,20,10,2,54,4,12,16,11,3,10,4,11,6,56,9,12,21,11,17,10,2,55,5,20,35,4,237,1,11,0,1,10,2,54,6,11,21,56,13,56,18,1,11,5,4,158,1,10,2,55,7,20,10,4,22,10,2,54,7,21,11,4,12,18,10,20,10,22,12,9,46,11,9,56,19,4,119,11,18,10,20,10,22,56,20,22,12,18,10,16,10,22,12,10,46,11,10,56,19,4,151,1,11,16,10,22,56,20,12,14,10,2,55,7,20,10,14,22,10,2,54,7,21,10,2,55,8,20,10,14,23,10,2,54,8,21,11,18,11,14,22,12,18,5,153,1,11,16,1,11,20,11,22,11,18,56,11,5,219,1,10,2,55,8,20,10,4,22,10,2,54,8,21,11,4,12,15,10,16,10,22,12,11,46,11,11,56,19,4,181,1,11,15,10,16,10,22,56,20,22,12,15,10,20,10,22,12,12,46,11,12,56,19,4,213,1,11,20,10,22,56,20,12,19,10,2,55,8,20,10,19,22,10,2,54,8,21,10,2,55,7,20,10,19,23,10,2,54,7,21,11,15,11,19,22,12,15,5,215,1,11,20,1,11,16,11,22,11,15,56,11,10,2,55,7,20,10,2,55,8,20,22,11,2,55,6,56,21,33,4,232,1,5,234,1,7,19,39,56,22,12,8,5,173,2,11,20,1,11,16,1,11,21,56,23,10,2,55,7,20,10,2,55,8,20,22,12,23,10,23,10,2,55,7,20,17,8,4,136,2,11,23,10,0,16,6,20,38,12,13,5,138,2,9,12,13,11,13,4,157,2,7,3,10,2,54,0,21,11,2,46,56,16,7,3,18,3,56,17,11,0,16,3,56,24,17,15,56,25,12,7,5,171,2,11,0,1,7,4,10,2,54,0,21,11,2,46,56,16,7,4,18,3,56,17,56,22,12,7,11,7,12,8,11,8,2,13,1,4,0,19,41,10,2,46,17,45,10,1,55,1,20,35,4,23,10,1,55,0,20,7,1,33,4,15,5,23,11,1,1,11,0,1,11,2,1,7,13,39,11,2,46,17,46,12,3,11,0,11,3,17,7,7,5,10,1,54,0,21,11,1,46,56,16,7,5,18,3,56,17,2,14,1,4,0,60,129,1,10,1,46,17,45,12,8,10,0,55,0,20,7,3,33,4,13,8,12,2,5,19,10,0,55,0,20,7,4,33,12,2,11,2,4,24,8,12,3,5,30,10,0,55,0,20,7,5,33,12,3,11,3,4,35,8,12,4,5,41,11,8,10,0,55,1,20,38,12,4,11,4,4,44,5,50,11,0,1,11,1,1,7,20,39,10,1,46,17,46,12,10,10,0,54,3,12,9,10,0,54,4,12,7,10,9,10,10,12,5,46,11,5,56,19,4,90,11,7,1,11,9,10,10,56,20,12,12,10,0,54,6,10,12,56,26,11,1,56,27,11,10,56,28,10,0,55,7,20,11,12,23,11,0,54,7,21,5,128,1,11,9,1,10,7,10,10,12,6,46,11,6,56,19,4,100,5,108,11,0,1,11,1,1,11,7,1,7,11,39,11,7,10,10,56,20,12,11,10,0,54,6,10,11,56,26,11,1,56,27,11,10,56,28,10,0,55,8,20,11,11,23,11,0,54,8,21,2,0,4,0,10,0,2,0,1,0,3,0,8,0,9,0,5,0,6,0,7,1,12,1,4,1,2,1,9,1,11,1,3,1,7,1,8,1,10,10,36,11,36,12,36,13,36,14,36,15,36,16,36,17,36,18,36,0],"lending_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,126,4,136,1,2,5,138,1,175,1,7,185,2,166,4,8,223,6,32,6,255,6,41,12,168,7,192,10,0,22,0,9,0,23,1,0,7,0,0,20,0,1,0,0,21,0,1,0,0,16,0,1,0,0,19,0,1,0,0,18,0,1,0,0,15,0,1,0,0,17,0,1,0,0,10,2,3,0,0,1,3,2,0,0,14,4,3,0,0,5,3,4,0,0,12,5,3,0,0,3,3,6,0,0,13,7,3,0,0,4,3,7,0,1,2,3,11,0,1,11,11,3,0,2,6,17,18,0,2,7,17,19,0,2,8,17,1,0,2,24,9,0,0,2,25,10,0,0,2,26,13,0,0,2,27,12,0,0,2,28,15,16,1,1,24,1,0,1,2,4,13,3,8,0,2,1,10,2,6,13,3,3,8,0,8,0,2,4,13,3,8,0,3,5,13,3,8,0,3,2,2,10,13,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,11,10,2,10,2,10,2,10,2,3,3,2,3,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,3,10,2,10,2,10,2,16,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,2,3,8,0,13,13,8,0,13,13,10,2,10,2,10,2,10,2,10,2,3,3,2,3,3,13,8,0,13,3,3,10,2,3,10,10,2,10,2,10,2,3,13,10,13,13,3,2,13,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,101,110,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,101,110,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,8,24,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,22,11,4,2,8,1,0,0,14,92,6,0,0,0,0,0,0,0,0,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,1,14,1,17,17,12,11,11,6,11,5,22,12,6,6,8,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,2,14,2,17,18,12,8,11,6,11,5,22,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,3,14,3,17,17,12,9,11,6,11,5,22,12,6,11,9,52,12,5,14,0,10,6,10,6,10,5,22,56,0,17,15,12,10,11,6,11,5,22,12,6,6,1,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,4,14,4,17,19,12,7,11,6,11,5,22,14,0,65,1,33,4,85,5,87,7,0,39,11,11,11,8,11,10,11,7,2,9,1,0,0,20,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,20,13,6,11,1,17,21,13,6,11,2,17,21,11,3,17,16,12,7,13,6,14,7,65,1,75,17,20,13,6,11,7,17,23,11,4,17,16,12,8,13,6,14,8,65,1,75,17,20,13,6,11,8,17,23,13,6,11,5,17,22,11,6,2,10,1,0,0,21,141,1,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,18,12,11,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,18,12,7,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,15,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,19,12,10,11,9,11,8,22,14,0,65,1,33,4,132,1,5,134,1,7,0,39,11,16,11,11,11,7,11,12,11,15,11,10,2,11,1,0,0,8,27,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,21,13,4,7,6,17,22,11,4,2,12,1,0,0,22,118,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,1,14,1,17,17,12,11,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,2,14,2,17,18,12,10,11,7,11,6,22,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,3,14,3,17,17,12,13,11,7,11,6,22,12,7,11,13,52,12,6,14,0,10,7,10,7,10,6,22,56,0,17,15,12,12,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,4,14,4,17,18,12,9,11,7,11,6,22,12,7,6,1,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,5,14,5,17,19,12,8,11,7,11,6,22,12,7,10,8,7,6,33,4,102,5,104,7,1,39,11,7,14,0,65,1,33,4,110,5,112,7,0,39,11,11,11,10,11,12,11,9,11,8,2,13,1,0,0,23,32,64,1,0,0,0,0,0,0,0,0,12,3,14,0,65,18,12,4,13,3,10,4,75,17,20,6,0,0,0,0,0,0,0,0,12,2,10,2,10,4,35,4,27,5,16,13,3,14,0,10,2,66,18,20,17,20,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,13,3,11,1,17,22,11,3,2,14,1,0,0,24,76,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,1,14,1,17,17,12,10,11,8,11,4,22,12,8,72,0,0,12,7,64,18,0,0,0,0,0,0,0,0,12,6,10,7,10,10,35,4,51,5,27,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,2,14,2,17,17,12,5,13,6,11,5,68,18,11,8,11,4,22,12,8,11,7,72,1,0,22,12,7,5,22,6,1,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,3,14,3,17,19,12,9,11,8,11,4,22,14,0,65,1,33,4,71,5,73,7,0,39,11,6,11,9,2,0],"lending_core_storage":[161,28,235,11,6,0,0,0,12,1,0,20,2,20,52,3,72,245,2,4,189,3,40,5,229,3,172,2,7,145,6,149,16,8,166,22,96,6,134,23,20,10,154,23,101,12,255,23,239,16,13,238,40,62,15,172,41,6,0,77,0,17,0,43,0,91,1,122,2,31,2,87,2,109,2,112,2,115,0,6,8,0,0,11,4,0,0,4,4,0,0,5,4,0,0,1,4,0,1,0,12,0,1,8,12,0,2,3,0,0,5,2,8,0,6,10,4,0,7,7,12,2,7,1,4,1,9,9,2,0,0,72,0,1,0,0,93,2,1,0,0,104,3,1,0,0,102,3,1,0,0,106,4,1,0,0,105,4,1,0,0,99,4,1,0,0,103,4,1,0,0,100,4,1,0,0,101,5,1,0,0,45,6,7,0,0,61,8,9,0,0,73,10,11,0,0,30,10,11,0,0,58,6,12,0,0,42,13,11,0,0,41,10,11,0,0,65,13,9,0,0,63,13,9,0,0,66,13,14,0,0,64,13,14,0,0,67,13,14,0,0,69,15,9,0,0,68,15,9,0,0,60,10,12,0,0,52,10,9,0,0,62,10,9,0,0,59,10,9,0,0,57,10,9,0,0,46,10,9,0,0,50,10,9,0,0,53,10,9,0,0,56,10,9,0,0,51,10,9,0,0,55,10,9,0,0,54,10,9,0,0,48,10,9,0,0,47,10,9,0,0,49,10,16,0,0,44,6,17,0,0,85,18,1,0,0,29,18,1,0,0,84,18,1,0,0,28,18,1,0,0,14,15,1,0,0,96,15,1,0,0,13,15,1,0,0,95,15,1,0,0,15,15,1,0,0,97,15,1,0,0,119,19,1,0,0,117,20,1,0,0,118,21,1,0,0,116,22,1,0,0,40,23,1,0,1,45,17,7,0,1,92,0,26,0,3,90,1,9,0,4,34,46,11,1,0,4,71,46,48,1,0,4,94,49,31,1,0,5,110,8,12,0,6,86,24,25,0,7,12,34,1,2,7,4,7,20,32,39,2,7,4,7,23,36,37,2,7,4,7,34,32,11,2,7,4,7,81,40,12,2,7,4,7,86,24,28,2,7,4,7,94,36,44,2,7,4,8,107,31,1,1,8,68,27,68,29,70,30,66,27,68,33,63,27,65,27,64,27,67,27,66,29,64,29,66,33,64,33,69,33,63,33,65,29,58,7,59,7,60,7,63,29,3,6,8,7,7,8,6,7,8,11,0,17,6,8,7,7,8,0,6,8,8,13,1,1,3,15,15,15,15,15,15,15,15,15,7,8,11,4,6,8,7,7,8,0,13,1,4,6,8,7,7,8,0,13,15,7,6,8,7,7,8,0,13,15,15,15,15,1,7,8,0,1,13,1,6,8,8,1,15,2,7,8,0,13,1,1,1,3,2,7,8,0,3,1,10,13,3,7,8,0,3,13,4,15,15,15,15,1,6,8,5,4,7,8,0,13,3,15,4,7,8,0,6,8,8,3,15,3,7,8,0,13,15,6,7,8,0,13,15,15,15,15,4,7,8,0,13,15,15,3,7,8,0,6,8,8,3,1,7,8,11,1,8,9,1,8,5,2,13,8,2,1,11,10,2,9,0,9,1,2,3,8,1,1,8,0,1,9,0,2,6,11,10,2,9,0,9,1,9,0,2,3,15,3,7,11,10,2,9,0,9,1,9,0,9,1,1,7,8,2,2,7,11,10,2,9,0,9,1,9,0,1,7,9,1,1,7,8,4,1,6,9,1,1,6,11,10,2,9,0,9,1,2,15,6,8,2,1,6,8,4,2,15,7,8,3,1,9,1,1,7,8,1,2,6,10,9,0,6,9,0,2,3,7,8,1,2,1,3,2,7,10,9,0,3,2,3,7,8,2,6,65,112,112,67,97,112,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,11,82,101,115,101,114,118,101,68,97,116,97,13,83,99,97,108,101,100,66,97,108,97,110,99,101,7,83,116,111,114,97,103,101,5,84,97,98,108,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,85,115,101,114,73,110,102,111,3,97,100,100,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,17,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,16,98,97,115,101,95,98,111,114,114,111,119,95,114,97,116,101,6,98,111,114,114,111,119,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,18,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,49,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,50,23,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,5,99,108,111,99,107,22,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,11,99,111,108,108,97,116,101,114,97,108,115,8,99,111,110,116,97,105,110,115,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,23,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,22,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,13,100,116,111,107,101,110,95,115,99,97,108,101,100,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,10,103,101,116,95,97,112,112,95,105,100,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,18,103,101,116,95,114,101,115,101,114,118,101,95,108,101,110,103,116,104,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,13,103,101,116,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,2,105,100,8,105,110,100,101,120,95,111,102,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,12,105,115,111,108,97,116,101,95,100,101,98,116,19,108,97,115,116,95,97,118,101,114,97,103,101,95,117,112,100,97,116,101,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,13,108,105,113,117,105,100,95,97,115,115,101,116,115,5,108,111,97,110,115,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,13,111,116,111,107,101,110,95,115,99,97,108,101,100,3,114,97,121,8,114,97,121,95,109,97,116,104,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,20,114,101,103,105,115,116,101,114,95,110,101,119,95,114,101,115,101,114,118,101,6,114,101,109,111,118,101,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,8,114,101,115,101,114,118,101,115,22,115,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,22,115,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,23,115,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,27,115,101,116,95,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,26,115,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,21,115,101,116,95,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,22,115,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,8,116,114,101,97,115,117,114,121,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,10,117,115,101,114,95,105,110,102,111,115,10,117,115,101,114,95,115,116,97,116,101,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,70,8,9,16,8,5,98,11,10,2,13,8,2,120,11,10,2,3,8,1,1,2,5,18,15,75,15,82,10,13,33,10,13,83,10,13,2,2,17,73,1,27,1,74,15,76,15,113,3,114,15,108,15,21,15,36,15,38,15,35,15,37,15,32,15,22,15,24,8,4,89,8,3,39,8,3,3,2,2,121,11,10,2,3,15,111,15,4,2,4,19,15,25,15,26,15,88,15,0,1,0,0,1,13,10,2,17,62,11,0,11,1,10,2,17,56,10,2,56,0,11,2,56,1,18,0,56,2,2,1,1,0,0,1,49,10,1,16,0,10,3,56,3,32,4,7,5,15,11,1,1,11,16,1,11,2,1,7,0,39,11,1,15,0,11,3,11,4,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,2,17,11,11,6,11,7,11,8,11,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,57,17,57,11,10,11,11,11,12,11,13,11,14,11,15,18,4,10,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,11,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,18,2,56,5,2,2,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,1,21,2,3,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,2,21,2,4,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,3,21,2,5,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,4,21,2,6,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,5,21,2,7,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,6,21,2,8,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,7,21,2,9,1,0,0,38,23,11,1,15,0,11,2,56,6,15,8,12,7,11,3,10,7,15,9,21,11,4,10,7,15,10,21,11,5,10,7,15,11,21,11,6,11,7,15,12,21,2,10,1,0,0,1,4,11,0,16,13,17,55,2,11,1,0,0,1,6,11,0,17,61,6,232,3,0,0,0,0,0,0,26,77,2,12,1,0,0,1,7,11,0,16,0,11,1,56,7,16,1,20,2,13,1,0,0,1,7,11,0,16,0,11,1,56,7,16,2,20,2,14,1,0,0,1,4,11,0,16,0,56,8,2,15,1,0,0,12,8,11,0,15,14,11,1,12,2,46,11,2,56,9,2,16,1,0,0,7,8,11,0,15,0,11,1,12,2,46,11,2,56,3,2,17,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,15,20,2,18,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,16,20,2,19,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,17,20,2,20,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,18,20,2,21,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,19,20,2,22,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,20,16,21,10,1,56,11,4,19,11,4,16,20,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,23,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,22,16,21,10,1,56,11,4,19,11,4,16,22,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,24,1,0,0,1,7,11,0,16,0,11,1,56,7,16,23,20,2,25,1,0,0,1,7,11,0,16,0,11,1,56,7,16,24,20,2,26,1,0,0,1,7,11,0,16,0,11,1,56,7,16,3,20,2,27,1,0,0,1,7,11,0,16,0,11,1,56,7,16,4,20,2,28,1,0,0,1,7,11,0,16,0,11,1,56,7,16,5,20,2,29,1,0,0,1,7,11,0,16,0,11,1,56,7,16,7,20,2,30,1,0,0,1,7,11,0,16,0,11,1,56,7,16,6,20,2,31,1,0,0,1,7,11,0,16,0,11,1,56,7,16,25,20,2,32,1,0,0,1,8,11,0,16,0,11,1,56,7,16,20,16,26,20,2,33,1,0,0,1,8,11,0,16,0,11,1,56,7,16,22,16,26,20,2,34,1,0,0,1,7,11,0,16,0,11,1,56,7,16,27,20,2,35,1,0,0,1,7,11,0,16,0,11,1,56,7,16,28,20,2,36,1,0,0,1,7,11,0,16,0,11,1,56,7,16,29,20,2,37,1,0,0,1,7,11,0,16,0,11,1,56,7,16,30,20,2,38,1,0,0,42,19,11,0,16,0,11,1,56,7,16,8,12,2,10,2,16,9,20,10,2,16,10,20,10,2,16,11,20,11,2,16,12,20,2,39,3,0,0,1,3,11,0,16,13,2,40,3,0,0,43,35,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,41,3,0,0,43,44,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,42,3,0,0,43,35,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,43,3,0,0,43,44,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,44,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,17,14,2,56,16,32,4,16,11,3,15,17,11,2,68,7,5,18,11,3,1,2,45,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,17,14,2,56,17,12,3,4,17,11,4,15,17,11,3,56,18,1,5,19,11,4,1,2,46,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,18,14,2,56,16,32,4,16,11,3,15,18,11,2,68,7,5,18,11,3,1,2,47,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,18,14,2,56,17,12,3,4,17,11,4,15,18,11,3,56,18,1,5,19,11,4,1,2,48,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,19,14,2,56,16,32,4,16,11,3,15,19,11,2,68,7,5,18,11,3,1,2,49,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,19,14,2,56,17,12,3,4,17,11,4,15,19,11,3,56,18,1,5,19,11,4,1,2,50,3,0,0,45,15,11,0,15,14,11,2,56,15,12,4,11,1,17,11,10,4,15,15,21,11,3,11,4,15,16,21,2,51,3,0,0,35,10,11,0,15,0,11,1,56,6,12,3,11,2,11,3,15,24,21,2,52,3,0,0,50,30,10,0,15,0,10,1,56,6,12,7,11,2,10,7,15,30,21,11,3,10,7,15,28,21,11,4,11,7,15,25,21,10,0,16,0,10,1,56,7,16,23,20,12,6,11,0,11,1,11,6,11,5,17,40,2,53,3,0,0,35,14,11,0,15,0,11,1,56,6,12,4,11,2,10,4,15,29,21,11,3,11,4,15,27,21,2,54,1,0,0,12,26,10,0,15,14,10,2,12,3,46,11,3,56,9,32,4,21,11,0,15,14,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,1,17,11,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,18,1,56,19,5,25,11,0,1,11,1,1,2,0,2,2,0,2,1,2,5,2,6,2,7,2,12,2,13,2,14,4,0,4,1,4,2,4,3,0,1,0,3,1,1,1,0,1,2,1,3,1,4,2,15,3,0,2,16,2,4,2,2,2,3,3,1,2,9,2,11,2,8,2,10,0,78,0,79,0,80,0],"lending_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,36,2,36,68,3,104,198,1,4,174,2,8,5,182,2,233,3,7,159,6,228,8,8,131,15,128,1,6,131,16,30,10,161,16,36,12,197,16,230,11,0,58,0,17,0,30,0,42,0,56,0,57,0,59,0,64,0,65,0,80,0,82,1,63,2,23,2,24,2,35,2,77,2,79,3,76,0,6,3,0,0,10,3,0,1,0,12,0,2,4,7,0,3,5,8,0,5,13,8,0,7,9,8,0,8,8,12,0,9,15,12,0,10,3,12,0,11,7,7,1,0,0,12,1,8,0,13,2,12,1,0,1,15,11,2,0,16,14,2,0,17,12,12,0,0,78,0,1,0,0,81,2,1,0,0,19,2,1,0,0,70,0,1,0,0,60,0,1,0,0,18,0,1,0,0,21,0,1,0,2,47,17,14,0,2,48,17,10,0,3,22,4,1,0,4,25,14,15,0,4,26,14,35,0,4,27,14,38,0,4,28,14,23,0,4,44,1,16,0,4,45,1,16,0,4,46,1,16,0,4,52,1,16,0,4,53,1,16,0,4,54,1,16,0,5,43,5,6,0,6,18,39,1,0,6,21,39,1,0,6,36,13,1,0,6,37,36,1,0,6,38,13,1,0,6,39,13,1,0,6,40,13,30,0,8,41,24,25,0,8,50,9,10,0,8,51,9,30,0,9,49,11,12,0,10,66,7,8,0,10,67,21,22,0,10,68,21,22,0,10,71,31,12,0,11,29,29,19,1,0,11,55,27,28,1,0,14,34,19,1,1,3,38,18,37,26,36,26,38,32,10,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,10,2,6,8,11,7,8,14,0,11,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,11,12,1,8,13,10,2,6,8,11,7,8,14,17,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,10,2,2,13,3,3,8,3,8,3,13,8,3,1,6,8,4,1,7,8,5,1,6,8,2,8,7,8,15,7,8,9,6,8,2,10,2,7,8,7,7,8,8,6,8,11,7,8,14,4,8,3,8,3,15,10,2,2,7,8,7,8,3,1,13,2,6,8,8,8,3,1,3,7,6,8,7,7,8,5,7,8,6,6,8,11,3,13,15,1,10,2,4,13,3,8,3,2,1,2,1,6,8,3,1,8,0,1,9,0,27,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,6,7,8,15,7,8,9,6,8,2,10,2,6,8,11,7,8,14,2,8,3,10,2,6,13,3,3,8,3,8,3,2,3,7,8,7,13,13,1,11,10,1,8,3,1,8,3,1,6,11,10,1,9,0,1,1,1,11,10,1,9,0,1,15,11,7,8,15,7,8,9,6,8,2,7,8,7,8,3,8,3,13,3,15,11,12,1,8,13,6,8,11,1,8,1,26,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,26,7,8,5,7,8,6,6,8,11,3,3,13,13,8,3,7,8,5,7,8,6,6,8,11,3,13,15,10,2,2,15,13,8,3,8,3,3,3,3,13,13,8,3,5,13,3,8,3,3,2,8,6,8,7,7,8,5,7,8,6,6,8,11,3,3,13,13,14,8,3,7,8,5,7,8,6,6,8,11,3,13,10,2,2,6,13,10,13,3,3,3,8,3,2,10,13,2,6,6,8,7,7,8,5,7,8,6,6,8,11,3,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,76,101,110,100,105,110,103,67,111,114,101,69,118,101,110,116,6,79,112,116,105,111,110,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,6,98,111,114,114,111,119,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,112,111,111,108,95,105,100,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,9,108,105,113,117,105,100,97,116,101,17,108,105,113,117,105,100,97,116,101,95,117,115,101,114,95,105,100,5,110,111,110,99,101,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,5,114,101,112,97,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,14,115,101,110,100,101,114,95,117,115,101,114,95,105,100,8,115,101,113,117,101,110,99,101,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,18,115,111,117,114,99,101,95,99,104,97,105,110,95,110,111,110,99,101,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,9,62,3,72,3,74,13,32,13,31,13,69,10,2,16,15,61,3,20,2,1,2,5,73,3,74,13,75,3,33,8,3,20,2,0,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,26,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,18,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,1,1,4,0,20,168,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,26,12,37,11,26,17,13,12,27,12,35,12,34,12,24,12,33,12,36,10,27,17,19,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,24,77,12,25,10,1,11,34,17,29,12,28,11,2,11,37,12,16,46,11,16,17,31,12,29,14,35,17,8,12,30,10,1,10,28,11,30,17,28,12,31,14,31,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,31,56,2,12,32,10,1,10,6,11,5,10,9,10,29,10,28,11,25,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,27,12,23,10,1,10,32,17,30,10,23,38,4,113,5,125,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,32,10,35,10,36,10,33,10,23,11,7,11,9,17,35,12,11,11,32,12,12,10,36,12,13,10,33,12,14,10,27,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,33,11,29,11,36,14,35,17,8,11,28,14,35,17,7,11,23,6,0,0,0,0,0,0,0,0,11,27,18,0,56,0,2,2,1,4,0,33,167,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,25,12,36,11,25,17,13,12,26,12,34,12,33,12,23,12,32,12,35,10,26,17,15,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,23,77,12,24,10,1,11,33,17,29,12,27,11,2,11,36,12,16,46,11,16,17,31,12,28,14,34,17,8,12,29,10,1,10,27,11,29,17,28,12,30,14,30,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,30,56,2,12,31,10,1,10,6,11,5,10,9,10,28,10,27,10,24,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,23,10,1,10,31,17,30,10,24,38,4,112,5,124,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,31,10,34,10,35,10,32,10,24,11,7,11,9,17,35,12,11,11,31,12,12,10,35,12,13,10,32,12,14,10,26,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,32,11,28,11,35,14,34,17,8,11,27,14,34,17,7,11,24,6,0,0,0,0,0,0,0,0,11,26,18,0,56,0,2,3,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,25,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,17,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,4,1,4,0,34,97,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,24,12,26,12,29,12,28,11,24,17,11,12,25,12,30,12,35,12,32,12,33,11,2,10,29,12,17,46,11,17,17,31,12,31,10,1,11,28,17,29,12,27,10,1,11,35,17,29,12,34,10,1,10,6,10,5,10,8,10,31,10,27,10,26,12,23,12,22,12,21,12,20,12,19,12,18,46,11,18,11,19,11,20,11,21,11,22,11,23,17,26,11,1,11,6,11,5,11,8,10,31,10,30,10,34,11,27,12,16,12,15,12,14,12,13,12,12,12,11,12,10,46,11,10,11,11,11,12,11,13,11,14,11,15,11,16,17,24,11,32,11,31,11,33,14,29,17,8,11,34,14,29,17,7,11,26,11,30,11,25,18,0,56,0,2,5,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,14,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,21,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,6,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,16,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,22,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,0],"lending_logic":[161,28,235,11,6,0,0,0,11,1,0,27,2,27,24,3,51,189,4,4,240,4,4,5,244,4,199,3,7,187,8,241,18,8,172,27,96,6,140,28,144,2,10,156,30,15,12,171,30,253,36,15,168,67,4,0,93,0,48,0,90,0,91,0,104,0,106,0,108,0,111,0,117,1,135,1,2,35,2,40,2,95,0,2,3,0,1,1,0,0,3,5,8,0,4,4,8,0,5,3,12,0,10,0,8,0,0,42,0,1,0,0,44,2,1,0,0,45,2,3,0,0,41,2,1,0,0,43,2,1,0,0,11,4,1,0,0,31,4,1,0,0,34,5,1,0,0,103,6,7,0,0,102,8,7,0,0,83,9,7,0,0,85,10,7,0,0,88,11,7,0,0,84,11,7,0,0,89,11,7,0,0,87,12,7,0,0,33,13,1,0,0,81,12,7,0,0,82,10,7,0,0,128,1,10,3,0,0,126,14,3,0,0,125,11,3,0,0,132,1,14,3,0,0,131,1,11,3,0,0,127,10,3,0,0,129,1,10,3,0,0,133,1,10,3,0,0,134,1,10,3,0,0,28,15,3,0,0,19,15,3,0,0,24,10,3,0,0,25,16,3,0,0,27,17,18,0,0,18,19,20,0,0,119,9,3,0,0,118,9,3,0,0,37,12,1,0,0,99,21,1,0,0,15,21,1,0,0,97,21,1,0,0,13,21,1,0,0,6,8,1,0,0,113,8,1,0,0,120,22,1,0,0,123,23,1,0,0,121,24,1,0,2,51,1,27,0,2,55,1,27,0,2,56,1,27,0,2,61,1,27,0,2,65,1,27,0,2,69,1,27,0,2,80,1,27,0,3,7,11,1,0,3,8,11,1,0,3,9,11,1,0,3,14,53,1,0,3,16,53,1,0,3,30,9,7,0,3,39,30,1,0,3,46,9,7,0,3,47,12,7,0,3,49,61,31,0,3,52,9,3,0,3,53,9,3,0,3,54,9,3,0,3,57,9,3,0,3,58,9,3,0,3,59,9,3,0,3,60,9,3,0,3,62,9,3,0,3,63,9,3,0,3,64,9,3,0,3,66,9,3,0,3,67,9,3,0,3,68,9,26,0,3,70,57,3,0,3,72,9,3,0,3,73,12,3,0,3,74,12,37,0,3,75,12,3,0,3,76,12,37,0,3,77,12,37,0,3,78,11,3,0,3,79,11,3,0,3,86,9,7,0,3,98,53,1,0,3,100,53,1,0,3,114,11,1,0,3,115,11,1,0,3,116,11,1,0,3,121,63,1,0,3,122,6,1,0,3,123,60,1,0,3,124,58,1,0,4,32,32,1,0,4,71,47,48,0,5,50,62,3,0,6,20,20,3,0,6,21,6,3,0,6,22,33,3,0,6,23,33,3,0,6,26,63,3,0,7,96,18,3,0,7,109,1,3,0,7,110,18,3,0,7,112,18,3,0,8,12,18,3,0,8,17,18,3,0,8,101,18,3,0,9,36,39,7,1,0,11,38,29,1,1,3,12,107,49,26,0,111,28,110,31,8,6,8,4,7,8,2,7,8,3,6,8,5,3,3,13,13,0,7,6,8,4,7,8,2,7,8,3,6,8,5,3,13,15,1,15,6,6,8,4,7,8,2,7,8,3,6,8,5,3,13,7,6,8,1,6,8,4,7,8,2,6,8,5,13,3,15,3,7,8,2,13,15,1,1,3,7,8,2,3,15,2,7,8,2,13,3,7,8,2,7,8,3,3,3,7,8,2,3,13,2,7,8,2,3,4,7,8,3,7,8,2,3,6,8,5,4,7,8,2,7,8,3,3,13,3,7,8,3,13,15,4,7,8,2,7,8,3,3,3,6,7,8,2,7,8,3,3,3,13,13,2,15,15,7,7,8,3,13,15,13,15,15,15,4,15,15,15,15,4,7,8,2,3,13,15,4,7,8,2,7,8,3,6,8,5,3,3,7,8,2,6,8,5,13,4,6,8,4,7,8,2,13,15,12,1,15,15,15,15,15,15,15,15,3,15,15,1,3,1,2,1,8,0,1,9,0,3,7,8,2,6,8,5,3,1,13,3,7,8,3,10,13,6,8,5,3,15,15,15,5,15,15,15,15,3,3,1,15,15,5,1,15,6,13,15,10,13,1,10,13,2,1,10,13,2,6,10,9,0,6,9,0,3,1,13,10,13,2,10,13,10,13,7,6,13,15,15,10,13,3,3,15,7,15,3,3,6,13,15,10,13,15,6,6,13,15,10,13,3,3,15,6,3,3,6,13,15,10,13,15,2,2,15,2,7,8,3,13,3,15,2,3,2,3,2,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,6,15,15,15,15,15,15,6,15,3,3,6,13,10,13,3,4,7,8,2,13,3,15,3,6,13,15,10,13,5,15,6,13,15,15,10,13,7,15,15,15,15,15,15,15,1,6,8,5,4,7,8,2,6,8,5,3,15,9,15,15,15,15,15,15,15,15,15,6,7,8,2,13,15,15,15,15,1,7,8,2,3,6,8,4,13,13,4,7,8,2,13,15,15,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,23,76,101,110,100,105,110,103,67,111,114,101,69,120,101,99,117,116,101,69,118,101,110,116,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,16,97,100,100,95,105,115,111,108,97,116,101,95,100,101,98,116,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,6,97,109,111,117,110,116,13,97,115,95,99,111,108,108,97,116,101,114,97,108,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,100,116,111,107,101,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,111,116,111,107,101,110,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,115,99,97,108,101,100,28,99,97,108,99,117,108,97,116,101,95,97,99,116,117,97,108,95,108,105,113,117,105,100,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,35,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,98,97,115,101,95,100,105,115,99,111,117,110,116,30,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,100,105,115,99,111,117,110,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,25,99,97,108,99,117,108,97,116,101,95,109,97,120,95,108,105,113,117,105,100,97,116,105,111,110,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,9,99,97,108,108,95,116,121,112,101,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,22,99,104,101,99,107,95,117,115,101,114,95,102,114,101,115,104,95,112,114,105,99,101,19,99,108,97,105,109,95,102,114,111,109,95,116,114,101,97,115,117,114,121,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,13,99,111,118,101,114,95,100,101,102,105,99,105,116,4,101,109,105,116,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,13,103,101,116,95,116,105,109,101,115,116,97,109,112,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,14,104,97,115,95,99,111,108,108,97,116,101,114,97,108,11,104,97,115,95,100,101,102,105,99,105,116,19,105,115,95,98,111,114,114,111,119,97,98,108,101,95,97,115,115,101,116,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,17,105,115,95,105,115,111,108,97,116,105,111,110,95,109,111,100,101,15,105,115,95,108,105,113,117,105,100,95,97,115,115,101,116,7,105,115,95,108,111,97,110,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,109,97,116,104,3,109,105,110,11,109,105,110,116,95,100,116,111,107,101,110,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,111,116,111,107,101,110,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,24,110,111,116,95,114,101,97,99,104,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,24,110,111,116,95,114,101,97,99,104,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,6,111,114,97,99,108,101,7,112,111,111,108,95,105,100,12,112,111,111,108,95,109,97,110,97,103,101,114,3,112,111,119,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,19,114,101,100,117,99,101,95,105,115,111,108,97,116,101,95,100,101,98,116,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,19,116,111,116,97,108,95,100,116,111,107,101,110,95,115,117,112,112,108,121,19,116,111,116,97,108,95,111,116,111,107,101,110,95,115,117,112,112,108,121,24,117,112,100,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,7,117,115,101,114,95,105,100,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,27,117,115,101,114,95,116,111,116,97,108,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,21,117,115,101,114,95,116,111,116,97,108,95,108,111,97,110,95,118,97,108,117,101,6,118,101,99,116,111,114,11,118,105,111,108,97,116,111,114,95,105,100,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,15,32,0,0,0,200,165,25,144,185,165,111,165,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,34,76,160,196,199,203,249,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,0,2,5,130,1,3,10,15,105,13,136,1,3,29,2,0,3,0,0,25,233,1,10,1,10,5,10,6,17,13,4,6,5,16,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,5,10,7,17,14,4,22,5,32,11,1,1,11,0,1,11,2,1,11,3,1,7,8,39,10,1,10,4,10,7,17,13,4,38,5,48,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,3,10,7,17,44,10,1,10,3,10,6,17,44,10,1,10,2,10,3,10,4,17,43,10,2,10,1,10,5,10,3,17,16,10,1,10,2,10,5,17,11,32,4,73,5,83,11,1,1,11,0,1,11,2,1,11,3,1,7,6,39,10,1,10,2,10,4,10,5,10,6,10,7,17,32,12,15,12,14,10,1,10,6,17,77,12,18,10,1,10,4,10,7,17,21,12,16,10,2,10,6,11,14,10,7,11,15,11,16,11,18,17,33,12,19,12,11,12,10,12,9,10,1,10,6,17,75,12,17,10,1,10,5,10,7,10,10,17,40,10,1,10,5,10,6,10,9,17,38,10,1,10,4,10,7,11,10,17,38,10,1,11,17,10,6,11,19,17,37,10,1,10,2,10,5,17,18,4,145,1,10,1,10,5,17,36,10,1,10,4,10,6,17,14,4,184,1,10,1,10,4,10,6,17,23,12,13,10,13,10,11,17,103,12,12,10,1,10,4,10,6,11,12,17,40,10,11,10,13,36,4,183,1,10,1,10,4,10,6,17,90,10,1,10,4,10,6,11,11,11,13,23,17,37,10,1,10,4,10,6,17,54,5,210,1,10,1,10,4,10,6,11,11,17,37,10,1,10,4,10,6,17,13,32,4,202,1,10,1,10,4,10,6,17,12,32,12,8,5,204,1,9,12,8,11,8,4,210,1,10,1,10,4,10,6,17,54,10,0,10,1,10,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,0,10,1,11,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,5,17,43,11,4,11,9,11,6,11,5,17,49,18,0,56,0,2,1,3,0,0,7,128,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,4,10,5,17,14,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,18,39,10,1,10,5,10,6,17,8,4,42,5,52,11,1,1,11,0,1,11,2,1,11,3,1,7,19,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,10,6,17,37,10,1,10,4,10,5,17,13,32,4,74,10,1,10,4,10,5,17,12,32,12,7,5,76,9,12,7,11,7,4,110,10,1,10,4,17,15,4,87,10,1,10,4,10,5,17,54,5,110,10,1,10,4,17,17,32,4,97,10,1,10,4,10,5,17,53,5,110,10,1,10,5,17,85,4,106,10,1,10,4,10,5,17,54,5,110,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,51,18,0,56,0,2,2,3,0,0,18,95,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,21,12,8,11,6,10,8,17,103,12,7,10,1,10,4,10,5,10,7,17,38,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,48,5,58,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,10,7,11,8,33,4,76,10,1,10,4,10,5,17,13,4,72,10,1,10,4,10,5,17,88,5,76,10,1,10,4,10,5,17,89,11,0,10,1,10,5,10,7,17,45,11,1,11,2,11,3,10,4,17,43,11,4,10,7,11,5,6,0,0,0,0,0,0,0,0,17,52,18,0,56,0,11,7,2,3,3,0,0,1,170,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,13,32,4,30,5,40,11,1,1,11,0,1,11,2,1,11,3,1,7,3,39,10,1,10,4,10,5,17,12,32,4,47,5,57,11,1,1,11,0,1,11,2,1,11,3,1,7,4,39,10,1,10,5,17,10,4,62,5,72,11,1,1,11,0,1,11,2,1,11,3,1,7,13,39,10,1,10,4,17,15,4,111,10,1,10,5,17,58,4,81,5,91,11,1,1,11,0,1,11,2,1,11,3,1,7,12,39,10,1,10,4,10,6,17,9,4,97,5,107,11,1,1,11,0,1,11,2,1,11,3,1,7,11,39,10,1,10,4,10,6,17,41,10,1,10,4,10,5,17,14,32,4,121,10,1,10,4,10,5,17,55,10,1,10,4,10,5,10,6,17,39,10,2,10,1,10,4,10,3,17,16,10,2,10,5,64,31,1,0,0,0,0,0,0,0,10,3,17,95,10,1,10,2,10,4,17,11,4,142,1,5,152,1,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,10,6,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,47,18,0,56,0,2,4,3,0,0,33,88,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,23,12,7,10,6,10,7,17,103,12,9,10,1,10,4,10,5,10,9,17,40,10,1,10,4,17,15,4,45,10,1,10,4,10,9,17,42,10,6,10,7,38,4,70,10,1,10,4,10,5,17,90,11,6,11,7,23,12,8,10,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,10,1,10,4,10,5,11,8,17,37,10,1,10,4,10,5,17,54,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,9,11,5,6,0,0,0,0,0,0,0,0,17,50,18,0,56,0,2,5,3,0,0,1,82,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,12,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,14,39,10,1,10,4,17,15,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,15,39,10,1,10,4,17,17,4,56,10,1,10,5,17,85,32,4,46,5,56,11,1,1,11,0,1,11,2,1,11,3,1,7,17,39,10,1,10,4,10,5,17,89,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,46,18,0,56,0,2,6,3,0,0,1,67,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,13,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,4,10,5,17,88,10,1,10,4,10,5,17,54,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,39,5,49,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,48,18,0,56,0,2,7,1,0,0,34,49,10,2,11,3,10,4,17,44,10,2,10,4,17,75,12,11,10,2,10,11,10,4,17,21,12,10,10,2,10,11,10,4,17,23,12,9,10,10,10,9,36,4,27,11,10,11,9,23,12,7,5,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,11,6,17,103,12,8,10,2,11,11,10,4,10,8,17,38,10,2,11,5,10,4,11,8,17,37,11,1,11,2,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,2,8,1,0,0,35,23,10,0,10,1,17,74,12,4,11,0,11,1,17,34,12,5,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,15,8,12,3,5,21,11,5,11,2,22,11,4,35,12,3,11,3,2,9,1,0,0,36,33,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,5,10,0,10,5,20,17,73,12,4,11,0,11,5,20,17,68,12,6,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,8,12,3,5,31,11,6,11,2,22,11,4,35,12,3,11,3,2,10,1,0,0,1,6,11,0,11,1,17,63,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,2,11,1,0,0,1,7,11,0,11,1,11,2,17,19,17,104,36,2,12,1,0,0,38,19,10,0,10,1,17,61,4,13,11,0,11,1,17,81,12,4,14,4,14,2,56,1,12,3,5,17,11,0,1,9,12,3,11,3,2,13,1,0,0,37,8,11,0,11,1,17,79,12,3,14,3,14,2,56,1,2,14,1,0,0,37,8,11,0,11,1,17,82,12,3,14,3,14,2,56,1,2,15,1,0,0,40,25,10,0,11,1,17,79,12,4,14,4,65,31,6,1,0,0,0,0,0,0,0,33,4,19,14,4,6,0,0,0,0,0,0,0,0,66,31,20,12,3,11,0,11,3,17,85,12,2,5,23,11,0,1,9,12,2,11,2,2,16,1,0,0,41,17,10,1,10,2,17,79,12,4,11,1,11,2,17,82,12,5,10,0,11,4,10,3,17,95,11,0,11,5,11,3,17,95,2,17,1,0,0,37,9,11,0,11,1,17,79,12,2,14,2,65,31,6,0,0,0,0,0,0,0,0,36,2,18,1,0,0,35,23,10,0,10,1,10,2,17,26,12,4,11,0,11,1,11,2,17,27,12,5,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,12,3,5,21,9,12,3,11,3,2,19,1,0,0,33,23,10,0,10,1,10,2,17,24,12,4,11,0,11,1,11,2,17,25,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,19,11,4,11,5,17,105,12,3,5,21,7,0,12,3,11,3,2,20,1,0,0,3,10,11,0,11,2,10,3,17,21,12,4,11,1,11,3,11,4,17,28,2,21,1,0,0,18,13,10,0,11,1,10,2,17,84,12,4,11,0,11,2,17,70,12,3,11,4,11,3,17,107,2,22,1,0,0,3,10,11,0,11,2,10,3,17,23,12,4,11,1,11,3,11,4,17,28,2,23,1,0,0,18,13,10,0,11,1,10,2,17,83,12,4,11,0,11,2,17,64,12,3,11,4,11,3,17,107,2,24,1,0,0,42,49,10,0,10,2,17,79,12,6,14,6,65,31,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,43,5,16,14,6,10,7,66,31,12,3,10,0,10,3,20,17,66,12,4,10,0,10,1,10,2,11,3,20,17,20,12,5,11,9,11,5,11,4,17,106,22,12,9,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,11,11,0,1,11,1,1,11,9,2,25,1,0,0,43,49,10,0,10,2,17,82,12,8,14,8,65,31,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,43,5,16,14,8,10,4,66,31,12,6,10,0,10,6,20,17,63,12,3,10,0,10,1,10,2,11,6,20,17,22,12,7,11,9,11,7,11,3,17,106,22,12,9,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,11,11,0,1,11,1,1,11,9,2,26,1,0,0,44,42,10,0,10,2,17,79,12,5,14,5,65,31,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,36,5,16,14,5,10,6,66,31,12,3,10,0,10,1,10,2,11,3,20,17,20,12,4,11,8,11,4,22,12,8,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,11,11,0,1,11,1,1,11,8,2,27,1,0,0,45,42,10,0,10,2,17,82,12,7,14,7,65,31,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,36,5,16,14,7,10,3,66,31,12,5,10,0,10,1,10,2,11,5,20,17,22,12,6,11,8,11,6,22,12,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,11,11,0,1,11,1,1,11,8,2,28,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,11,4,24,6,10,0,0,0,0,0,0,0,11,3,17,112,77,26,2,29,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,6,10,0,0,0,0,0,0,0,11,3,17,112,77,24,11,4,26,2,30,1,0,0,18,16,10,0,10,1,10,2,17,24,12,3,11,0,11,1,11,2,17,25,12,4,17,104,11,3,11,4,17,105,23,2,31,1,0,0,20,52,10,0,10,3,17,61,4,5,5,11,11,0,1,11,1,1,7,16,39,10,0,10,2,17,61,4,16,5,22,11,0,1,11,1,1,7,16,39,10,0,10,1,10,3,17,30,12,5,10,0,11,2,17,78,12,4,11,0,11,1,11,3,17,25,12,7,11,4,74,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,24,17,105,17,104,17,103,17,104,22,12,6,11,5,11,6,17,106,7,1,17,103,2,32,1,0,0,50,89,10,0,10,1,11,2,10,3,17,31,12,12,10,0,10,1,10,3,17,24,12,10,10,0,10,1,10,3,17,25,12,11,10,0,10,5,17,63,12,6,10,0,10,4,17,66,12,7,11,11,7,2,17,106,11,10,23,12,19,7,2,17,104,10,12,23,17,106,11,6,17,106,11,7,23,12,18,11,19,11,18,17,105,12,14,10,0,10,1,10,3,10,4,17,20,10,14,17,105,12,8,10,14,17,104,11,12,23,17,106,12,16,11,0,10,1,11,3,10,5,17,22,10,16,17,105,12,9,11,8,11,9,17,103,17,104,17,103,12,17,10,1,11,4,11,14,10,17,17,106,17,29,12,13,11,1,11,5,11,16,11,17,17,106,17,29,12,15,11,13,11,15,2,33,1,0,0,51,45,10,5,10,4,38,4,9,11,4,12,8,11,2,12,7,5,17,11,5,12,8,11,2,10,8,11,4,17,105,17,106,12,7,10,0,10,1,10,7,17,28,12,9,10,0,11,3,10,8,17,28,12,11,11,0,11,1,11,9,11,11,23,17,29,11,6,17,106,12,12,10,7,10,12,23,12,10,11,7,11,8,11,10,11,12,2,34,1,0,0,18,12,10,0,10,1,17,72,12,3,11,0,11,1,17,70,12,2,11,3,11,2,17,106,2,35,1,0,0,18,12,10,0,10,1,17,67,12,3,11,0,11,1,17,64,12,2,11,3,11,2,17,106,2,36,0,0,0,52,49,10,0,10,1,17,82,12,6,14,6,65,31,12,4,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,46,5,14,14,6,10,3,66,31,12,5,10,0,10,5,20,17,75,12,7,10,0,10,1,10,5,20,17,23,12,2,10,0,10,1,10,5,20,10,2,17,40,10,0,11,7,11,5,20,11,2,17,39,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,9,11,0,1,2,37,0,0,0,3,12,11,3,10,0,10,2,17,70,17,109,12,4,11,0,11,2,11,1,11,4,17,87,2,38,0,0,0,3,12,11,3,10,0,10,2,17,70,17,108,12,4,11,0,11,2,11,1,11,4,17,57,2,39,0,0,0,3,12,11,3,10,0,10,2,17,64,17,109,12,4,11,0,11,2,11,1,11,4,17,86,2,40,0,0,0,3,12,11,3,10,0,10,2,17,64,17,108,12,4,11,0,11,2,11,1,11,4,17,56,2,41,0,0,0,54,21,10,0,11,1,17,79,12,5,14,5,6,0,0,0,0,0,0,0,0,66,31,12,3,10,0,10,3,20,17,68,11,2,22,12,4,11,0,11,3,20,11,4,17,92,2,42,0,0,0,55,32,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,4,10,0,10,4,20,17,68,12,5,10,5,10,2,38,4,22,11,5,11,2,23,12,3,5,24,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,12,6,11,0,11,4,20,11,6,17,92,2,43,0,0,0,56,58,10,0,10,3,17,61,4,51,10,2,17,76,12,5,10,0,10,3,17,80,12,9,10,0,10,1,10,3,17,24,12,6,10,0,11,1,10,3,17,25,12,7,10,6,10,7,36,4,45,11,6,11,7,23,12,8,10,0,10,3,17,78,12,4,11,5,11,9,11,4,11,8,17,98,12,10,11,0,11,2,11,3,11,10,17,94,5,50,11,0,11,2,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,94,5,57,11,0,1,11,1,1,11,2,1,2,44,0,0,0,59,59,11,1,17,76,12,5,10,0,10,2,17,69,12,7,10,0,10,2,17,67,12,6,10,0,10,2,17,64,12,3,10,0,10,2,17,70,12,4,10,0,10,2,17,77,12,11,10,5,10,7,10,0,10,2,17,65,17,100,10,3,17,106,12,9,10,5,11,7,10,0,10,2,17,71,17,101,11,4,17,106,12,10,11,6,10,9,11,3,23,17,106,11,11,17,106,10,10,17,109,12,8,11,0,11,2,11,9,11,10,11,5,11,8,17,93,2,45,0,0,0,20,36,11,0,10,2,10,1,17,62,17,97,12,5,10,5,10,3,38,4,11,5,15,11,1,1,7,10,39,11,5,11,3,23,12,6,10,1,10,2,10,6,17,99,12,4,10,1,10,2,10,4,11,6,17,102,12,7,11,1,11,2,11,4,11,7,17,91,2,0,92,0,94,0],"lending_portal":[161,28,235,11,6,0,0,0,11,1,0,44,2,44,90,3,134,1,165,2,4,171,3,36,5,207,3,230,5,7,181,9,176,10,8,229,19,128,1,6,229,20,54,10,155,21,59,12,214,21,204,16,13,162,38,4,0,72,0,23,0,38,0,39,0,52,0,69,0,70,0,71,0,75,0,83,0,84,0,103,0,108,1,82,2,30,2,31,2,44,2,81,2,99,2,101,2,102,3,98,0,8,8,0,0,14,3,0,0,9,3,0,0,7,3,0,1,0,12,0,2,4,7,0,3,11,12,1,0,1,4,5,0,0,4,6,8,0,6,17,8,0,9,13,8,0,10,12,12,0,11,20,12,0,12,3,12,0,13,10,7,1,0,0,14,1,8,0,15,2,12,1,0,1,17,19,4,0,18,15,2,0,20,18,2,0,21,16,12,0,0,66,0,1,0,0,60,2,3,0,0,94,4,1,0,0,24,5,1,0,0,28,5,1,0,0,100,6,1,1,0,0,106,7,1,1,0,0,107,8,1,0,0,25,7,1,1,0,0,26,8,1,0,0,90,6,1,1,0,0,73,9,1,1,0,2,32,12,17,0,2,33,1,17,1,0,2,34,45,17,0,2,55,35,28,0,2,59,1,19,0,3,35,27,28,1,0,3,80,25,3,1,0,3,105,43,1,1,0,4,29,16,1,0,5,54,1,26,0,5,58,1,26,0,5,62,1,26,0,5,63,1,26,0,5,64,1,26,0,6,53,49,50,0,7,24,20,1,0,7,28,20,1,0,7,45,34,1,0,7,46,60,1,0,7,47,34,1,0,7,48,34,1,0,7,49,34,42,0,8,74,22,23,1,0,10,21,29,30,0,10,51,38,39,0,10,57,33,19,0,10,61,33,42,0,10,89,29,30,0,11,56,18,3,0,11,67,18,31,0,11,87,32,1,0,12,91,51,3,0,13,36,41,14,1,0,13,68,40,31,1,0,15,37,23,1,1,0,15,97,48,23,1,0,15,104,24,3,1,0,16,43,14,1,1,3,17,77,0,10,0,19,85,53,1,1,12,19,95,14,1,1,8,20,92,11,12,0,21,76,47,3,0,52,13,13,14,34,14,48,14,18,14,17,14,49,36,45,17,44,17,19,14,34,46,47,46,48,46,51,52,49,54,49,55,5,14,46,14,1,7,8,19,0,1,7,8,0,1,3,3,6,8,7,7,8,0,5,8,6,8,8,7,8,9,7,8,10,6,8,15,7,8,11,7,8,12,10,13,7,8,19,11,6,8,8,7,8,9,7,8,10,6,8,15,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,16,1,9,0,3,7,8,19,10,6,8,8,7,8,9,7,8,10,6,8,15,7,8,0,7,8,11,7,8,12,7,11,6,1,9,0,3,7,8,19,16,6,8,8,7,8,9,7,8,10,6,8,15,7,8,13,7,8,0,7,8,20,7,8,11,7,8,12,10,2,10,2,13,3,10,11,16,1,8,18,3,7,8,19,14,6,8,8,7,8,9,7,8,10,6,8,15,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,16,1,9,0,3,13,10,2,3,7,8,19,1,8,17,1,6,8,19,1,5,1,8,0,1,9,0,11,8,5,7,8,9,7,8,10,6,8,15,3,13,6,13,3,3,3,8,5,1,6,8,8,1,8,5,2,6,8,12,8,5,1,13,6,6,8,11,7,8,9,7,8,10,6,8,15,3,13,17,6,8,15,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,3,11,16,1,9,0,13,3,3,8,5,8,5,3,10,11,16,1,9,0,3,7,8,19,1,11,16,1,9,0,1,6,11,16,1,9,0,2,6,11,6,1,9,0,3,1,2,5,7,11,6,1,9,0,11,16,1,9,0,13,10,2,7,8,19,1,10,2,4,7,8,11,8,5,13,15,2,15,15,1,1,2,7,8,12,8,5,2,7,8,11,8,5,7,6,8,11,7,8,9,7,8,10,6,8,15,3,13,15,1,6,8,5,1,8,3,16,8,5,7,8,9,7,8,10,6,8,15,3,13,15,15,13,3,13,11,14,1,8,5,8,5,8,5,8,5,15,3,7,8,11,13,13,1,11,14,1,8,5,1,6,11,14,1,9,0,1,11,14,1,9,0,1,15,5,7,11,6,1,9,0,8,5,3,8,5,7,8,19,21,8,5,7,8,9,7,8,10,6,8,15,3,13,15,15,11,16,1,8,18,13,3,11,14,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,16,1,8,18,3,2,13,10,2,1,8,18,1,6,8,20,3,7,11,16,1,9,0,3,7,8,19,1,7,8,9,1,6,8,4,11,7,8,20,7,8,13,6,8,4,7,8,11,8,5,8,5,13,3,15,11,16,1,8,18,6,8,15,1,11,16,1,8,18,2,9,0,5,1,8,1,1,8,2,15,8,5,7,8,9,7,8,10,6,8,15,3,13,15,13,3,13,11,14,1,8,5,8,5,8,5,8,5,15,20,8,5,7,8,9,7,8,10,6,8,15,3,13,15,11,16,1,8,18,13,3,11,14,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,16,1,8,18,3,17,6,8,15,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,13,3,3,8,5,3,11,16,1,9,0,8,5,16,13,8,5,7,8,9,7,8,10,6,8,15,3,3,13,13,8,5,3,8,5,3,5,13,8,5,8,6,8,11,7,8,9,7,8,10,6,8,15,3,3,13,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,17,76,101,110,100,105,110,103,76,111,99,97,108,69,118,101,110,116,13,76,101,110,100,105,110,103,80,111,114,116,97,108,18,76,101,110,100,105,110,103,80,111,114,116,97,108,69,118,101,110,116,6,79,112,116,105,111,110,4,80,111,111,108,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,13,97,100,100,95,108,105,113,117,105,100,105,116,121,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,12,98,111,114,114,111,119,95,108,111,99,97,108,13,98,111,114,114,111,119,95,114,101,109,111,116,101,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,7,100,101,112,111,115,105,116,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,17,100,111,108,97,95,112,111,111,108,95,97,100,100,114,101,115,115,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,10,102,101,101,95,97,109,111,117,110,116,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,2,105,100,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,9,108,105,113,117,105,100,97,116,101,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,11,109,101,115,115,97,103,101,95,102,101,101,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,7,114,101,108,97,121,101,114,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,5,114,101,112,97,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,6,115,101,110,100,101,114,8,115,101,113,117,101,110,99,101,11,115,101,116,95,114,101,108,97,121,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,112,108,105,116,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,14,119,105,116,104,100,114,97,119,95,108,111,99,97,108,15,119,105,116,104,100,114,97,119,95,114,101,109,111,116,101,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,13,2,1,0,0,2,3,65,8,17,88,5,78,3,1,2,5,93,3,79,3,42,8,5,50,3,27,2,2,2,8,79,3,92,5,40,10,2,96,13,41,13,86,10,2,22,3,27,2,3,2,5,79,3,92,5,40,10,2,22,3,27,2,0,0,0,0,1,9,10,0,17,50,11,0,46,17,53,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,0,0,1,5,11,2,11,1,15,1,21,2,3,1,4,0,15,61,11,0,17,20,11,7,46,17,53,17,12,12,18,11,5,11,18,12,8,46,11,8,17,40,12,15,14,6,65,19,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,19,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,27,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,4,1,4,0,15,61,11,0,17,20,11,7,46,17,53,17,12,12,18,11,5,11,18,12,8,46,11,8,17,40,12,15,14,6,65,19,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,19,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,28,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,5,1,4,0,21,117,11,0,17,20,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,53,17,12,12,27,56,1,12,26,11,8,11,9,10,10,56,2,12,22,10,7,14,22,56,3,12,15,46,11,15,56,4,12,21,11,4,17,1,12,25,11,7,11,22,7,5,64,26,0,0,0,0,0,0,0,0,10,10,56,5,1,10,6,10,26,7,5,10,21,77,17,35,1,12,20,10,5,10,27,12,16,46,11,16,17,41,32,4,74,10,5,10,27,17,42,10,6,10,26,17,37,12,23,11,5,11,27,12,17,46,11,17,17,40,12,24,11,6,11,1,11,2,11,3,11,24,11,23,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,32,11,25,11,10,46,17,53,14,26,17,15,11,21,17,24,18,3,56,6,2,6,1,4,0,37,117,11,0,17,20,17,16,12,20,10,9,46,17,53,17,12,12,24,56,1,12,23,10,5,10,23,17,37,12,18,11,6,10,24,12,10,46,11,10,17,40,12,19,10,5,10,18,11,20,17,36,12,21,14,21,56,7,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,21,56,8,12,22,10,5,11,1,11,2,11,3,11,19,11,18,11,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,33,12,17,10,5,10,22,17,38,10,17,38,4,80,5,90,11,5,1,11,7,1,11,4,1,11,9,1,7,1,39,11,5,11,22,7,5,10,17,17,39,1,12,25,11,7,11,24,11,25,52,10,23,10,9,56,9,11,4,17,1,11,9,46,17,53,14,23,17,15,11,17,52,17,25,18,3,56,6,2,7,1,4,0,44,184,1,11,0,17,20,10,11,10,10,17,14,12,31,10,11,11,9,17,14,12,30,10,15,46,17,53,17,12,12,34,10,7,10,30,17,37,12,25,11,8,11,34,12,16,46,11,16,17,40,12,26,10,7,10,25,10,11,17,36,12,27,14,27,56,7,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,27,56,8,12,28,10,7,10,1,11,2,10,3,11,26,11,25,11,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,33,12,23,10,7,10,28,17,38,10,23,38,4,86,5,102,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,11,13,10,14,10,15,56,10,12,24,10,6,46,17,54,12,36,11,14,10,36,38,4,116,5,132,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,24,11,36,10,15,56,11,12,35,14,24,56,12,12,32,10,5,17,1,12,29,11,6,11,4,11,1,17,26,11,7,10,28,11,31,17,16,10,29,10,23,11,35,11,3,17,43,12,33,11,24,11,5,16,1,20,56,13,11,33,10,29,11,28,11,32,17,25,18,1,56,14,11,29,11,15,46,17,53,14,30,17,15,17,16,11,11,11,10,11,23,52,17,25,18,2,56,15,2,8,1,4,0,56,123,11,0,17,20,17,16,12,19,56,1,12,22,10,9,46,17,53,17,12,12,23,10,5,10,22,17,37,12,17,11,6,10,23,12,10,46,11,10,17,40,12,18,10,5,10,17,11,19,17,36,12,20,14,20,56,7,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,20,56,8,12,21,10,5,10,21,17,38,10,8,77,38,4,58,5,74,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,1,39,10,5,11,1,11,2,11,3,11,18,11,17,10,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,29,11,5,11,21,7,5,10,8,77,17,39,1,12,24,11,7,11,23,11,24,52,10,22,10,9,56,9,11,4,17,1,11,9,46,17,53,14,22,17,15,11,8,17,21,18,3,56,6,2,9,1,4,0,57,186,1,11,0,17,20,10,11,10,10,17,14,12,30,10,11,11,9,17,14,12,29,10,15,46,17,53,17,12,12,33,10,7,10,29,17,37,12,24,11,8,11,33,12,16,46,11,16,17,40,12,25,10,7,10,24,10,11,17,36,12,26,14,26,56,7,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,26,56,8,12,27,10,7,10,27,17,38,10,12,77,38,4,64,5,82,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,10,7,10,1,11,2,10,3,11,25,11,24,10,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,29,11,13,10,14,10,15,56,10,12,23,10,6,46,17,54,12,35,11,14,10,35,38,4,118,5,134,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,23,11,35,10,15,56,11,12,34,14,23,56,12,12,31,10,5,17,1,12,28,11,6,11,4,11,1,17,26,11,7,10,27,11,30,17,16,10,28,10,12,77,11,34,11,3,17,43,12,32,11,23,11,5,16,1,20,56,13,11,32,10,28,11,27,11,31,17,25,18,1,56,14,11,28,11,15,46,17,53,14,29,17,15,17,16,11,11,11,10,11,12,17,21,18,2,56,15,2,10,1,4,0,58,117,11,0,17,20,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,53,17,12,12,27,56,1,12,24,11,8,11,9,10,10,56,2,12,26,10,7,14,26,56,3,12,15,46,11,15,56,4,12,25,11,4,17,1,12,23,11,7,11,26,7,5,64,26,0,0,0,0,0,0,0,0,10,10,56,5,1,10,6,10,24,7,5,10,25,77,17,35,1,12,20,10,5,10,27,12,16,46,11,16,17,41,32,4,74,10,5,10,27,17,42,10,6,10,24,17,37,12,21,11,5,11,27,12,17,46,11,17,17,40,12,22,11,6,11,1,11,2,11,3,11,22,11,21,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,31,11,23,11,10,46,17,53,14,24,17,15,11,25,17,23,18,3,56,6,2,11,1,4,0,59,93,10,0,17,20,10,13,46,17,53,12,27,10,27,17,12,12,25,56,1,12,23,11,10,10,11,17,14,12,29,10,6,11,23,17,37,12,22,10,6,11,29,17,37,12,28,10,4,17,1,12,26,10,9,6,0,0,0,0,0,0,0,0,36,4,43,11,0,10,1,10,2,10,3,11,4,10,5,10,6,11,7,11,8,10,9,11,13,56,16,5,54,11,4,1,11,0,1,11,7,1,11,8,10,9,11,13,56,2,56,17,11,5,11,25,12,15,46,11,15,17,40,12,24,11,6,11,1,11,2,11,3,11,24,11,12,11,28,11,22,12,14,12,21,12,20,12,19,12,18,12,17,12,16,46,11,16,11,17,11,18,11,19,11,20,11,21,11,14,17,30,11,26,11,27,11,11,11,9,17,22,18,3,56,6,2,0,2,0,1,0],"merge_coins":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,10,3,20,53,4,73,14,5,87,102,7,189,1,132,1,8,193,2,96,6,161,3,30,12,191,3,189,1,0,6,1,14,2,2,2,11,2,12,2,0,12,1,0,1,4,1,2,0,0,5,0,1,1,0,1,3,5,6,1,0,1,8,3,4,1,0,2,4,8,4,1,0,2,10,11,1,1,0,2,13,9,10,1,0,2,15,15,1,1,0,3,7,14,4,1,12,4,9,12,13,0,2,1,1,1,3,7,5,7,4,7,7,1,6,7,3,10,11,0,1,9,0,3,7,8,1,1,11,0,1,9,0,6,11,0,1,9,0,11,0,1,9,0,11,0,1,9,0,3,11,0,1,9,0,3,1,7,10,9,0,0,1,6,10,9,0,1,1,1,9,0,2,7,11,0,1,9,0,11,0,1,9,0,1,6,11,0,1,9,0,1,3,3,7,11,0,1,9,0,3,7,8,1,1,6,8,1,1,5,2,9,0,5,1,7,8,1,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,8,105,115,95,101,109,112,116,121,4,106,111,105,110,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,7,114,101,118,101,114,115,101,6,115,101,110,100,101,114,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,118,101,99,116,111,114,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,255,255,255,255,255,255,255,255,0,1,0,0,2,83,14,0,65,1,6,0,0,0,0,0,0,0,0,36,4,67,13,0,56,0,13,0,69,1,12,5,14,0,56,1,32,4,20,5,15,13,5,13,0,69,1,56,2,5,10,11,0,70,1,0,0,0,0,0,0,0,0,14,5,56,3,12,8,10,1,12,6,11,1,7,2,33,4,33,10,8,12,6,11,8,10,6,38,4,38,5,42,11,2,1,7,0,39,14,5,56,3,10,6,36,4,60,13,5,11,6,10,2,56,4,12,7,11,5,11,2,46,17,8,56,5,11,7,12,3,5,64,11,2,1,11,5,12,3,11,3,12,4,5,81,11,0,70,1,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,33,4,74,5,78,11,2,1,7,1,39,11,2,56,6,12,4,11,4,2,0],"oracle":[161,28,235,11,6,0,0,0,11,1,0,36,2,36,84,3,120,157,1,4,149,2,22,5,171,2,231,2,7,146,5,231,6,8,249,11,128,1,6,249,12,70,10,191,13,33,12,224,13,232,5,13,200,19,14,0,47,0,31,2,40,2,41,2,49,2,52,2,54,2,56,2,61,1,23,1,24,1,46,1,62,1,63,1,65,1,66,3,61,3,68,0,10,8,0,0,6,4,0,1,2,0,0,1,3,8,0,2,4,0,1,3,0,3,5,7,0,4,6,7,0,5,7,7,0,6,8,7,0,6,9,12,0,8,12,12,0,9,0,8,0,10,1,12,1,0,1,11,15,4,0,12,11,2,0,13,13,12,2,7,1,4,1,15,14,2,0,16,12,12,0,17,16,0,0,0,43,0,1,0,0,39,2,3,0,0,59,4,1,0,0,58,4,1,0,0,57,5,1,0,0,20,6,1,0,0,21,6,1,0,0,29,7,1,0,1,22,27,1,0,2,28,40,1,1,3,3,33,43,23,0,3,34,43,23,0,4,32,41,42,0,4,35,41,42,0,5,30,19,20,0,6,36,30,20,0,6,37,28,29,0,7,26,33,34,0,7,38,38,39,0,7,67,35,34,0,9,64,22,23,0,11,45,0,8,0,13,17,21,1,2,7,4,13,18,15,17,2,7,4,13,19,36,37,2,7,4,13,25,15,16,2,7,4,13,45,0,10,2,7,4,14,60,13,1,1,8,17,48,31,32,0,26,9,26,11,27,12,25,11,23,11,25,9,22,9,22,11,23,9,24,11,9,29,1,7,8,16,0,2,7,8,0,13,3,15,2,3,3,6,8,2,7,8,0,3,7,6,8,2,7,8,0,10,2,13,15,2,6,8,11,3,7,8,0,10,13,6,8,11,9,6,8,3,7,8,17,7,8,10,7,8,9,7,8,0,13,10,2,6,8,11,11,12,1,8,14,1,8,13,2,13,8,7,1,11,15,2,9,0,9,1,2,13,8,1,1,8,0,1,9,0,4,13,13,6,8,1,7,11,15,2,13,8,1,2,6,11,15,2,9,0,9,1,9,0,1,1,1,6,9,1,5,13,13,8,7,7,11,15,2,13,8,7,7,11,15,2,13,8,1,1,10,2,1,8,7,3,7,11,15,2,9,0,9,1,9,0,9,1,1,6,8,11,1,3,6,13,3,6,13,3,6,8,1,7,11,15,2,13,8,1,1,13,23,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,6,8,11,13,10,2,6,8,11,10,8,18,6,8,11,3,8,5,3,11,4,1,8,8,7,8,1,6,8,7,8,8,11,4,1,8,8,8,5,3,8,6,8,7,8,18,1,6,8,3,1,6,8,9,1,8,8,1,6,8,8,3,6,8,17,10,2,6,8,11,1,8,18,3,6,8,10,10,8,18,6,8,11,1,11,4,1,8,8,5,6,8,10,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,2,7,11,15,2,9,0,9,1,9,0,1,7,9,1,3,6,8,9,6,8,11,3,1,8,6,1,11,4,1,9,0,1,6,8,6,1,8,5,1,6,8,5,5,67,108,111,99,107,4,67,111,105,110,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,15,72,111,116,80,111,116,97,116,111,86,101,99,116,111,114,3,73,54,52,5,80,114,105,99,101,15,80,114,105,99,101,73,100,101,110,116,105,102,105,101,114,9,80,114,105,99,101,73,110,102,111,15,80,114,105,99,101,73,110,102,111,79,98,106,101,99,116,11,80,114,105,99,101,79,114,97,99,108,101,3,83,85,73,5,83,116,97,116,101,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,86,65,65,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,17,99,104,101,99,107,95,103,117,97,114,100,95,112,114,105,99,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,29,99,114,101,97,116,101,95,112,114,105,99,101,95,105,110,102,111,115,95,104,111,116,95,112,111,116,97,116,111,7,100,101,99,105,109,97,108,7,100,101,115,116,114,111,121,24,102,101,101,100,95,116,111,107,101,110,95,112,114,105,99,101,95,98,121,95,112,121,116,104,13,102,114,111,109,95,98,121,116,101,95,118,101,99,7,103,101,110,101,115,105,115,8,103,101,116,95,101,120,112,111,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,110,101,103,97,116,105,118,101,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,112,111,115,105,116,105,118,101,9,103,101,116,95,112,114,105,99,101,20,103,101,116,95,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,37,103,101,116,95,112,114,105,99,101,95,105,110,102,111,95,102,114,111,109,95,112,114,105,99,101,95,105,110,102,111,95,111,98,106,101,99,116,23,103,101,116,95,112,114,105,99,101,95,110,111,95,111,108,100,101,114,95,116,104,97,110,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,17,104,111,116,95,112,111,116,97,116,111,95,118,101,99,116,111,114,3,105,54,52,2,105,100,4,105,110,105,116,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,3,110,101,119,6,111,98,106,101,99,116,6,111,114,97,99,108,101,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,5,112,114,105,99,101,16,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,16,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,16,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,17,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,115,10,112,114,105,99,101,95,105,110,102,111,13,112,114,105,99,101,95,111,114,97,99,108,101,115,4,112,121,116,104,20,114,101,103,105,115,116,101,114,95,116,111,107,101,110,95,112,114,105,99,101,20,115,101,116,95,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,20,115,101,116,95,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,116,97,116,101,3,115,117,105,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,24,117,112,100,97,116,101,95,115,105,110,103,108,101,95,112,114,105,99,101,95,102,101,101,100,3,118,97,97,5,118,97,108,117,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,181,59,15,65,116,16,134,39,251,238,114,226,73,139,88,214,162,113,76,222,213,63,172,83,112,52,194,32,210,99,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,60,0,0,0,0,0,0,0,3,8,16,14,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,5,42,8,13,51,3,50,3,53,11,15,2,13,8,7,55,11,15,2,13,8,1,1,2,3,69,15,27,2,44,3,0,0,0,0,1,11,10,0,17,21,7,1,7,0,10,0,56,0,11,0,56,1,18,0,56,2,2,1,1,0,0,14,32,11,0,15,0,12,5,10,5,10,1,12,2,46,11,2,56,3,4,11,5,15,11,5,1,7,2,39,11,5,11,1,12,3,46,11,3,56,4,12,4,10,4,16,1,20,10,4,16,2,20,11,4,16,3,20,2,2,1,0,0,1,5,11,2,11,1,15,4,21,2,3,1,0,0,1,5,11,2,11,1,15,5,21,2,4,1,0,0,18,58,10,1,15,0,12,11,10,11,10,3,12,7,46,11,7,56,3,32,4,12,5,20,11,11,1,11,1,1,11,6,1,7,3,39,11,2,17,14,12,9,11,1,15,6,12,10,10,10,10,3,12,8,46,11,8,56,5,32,4,35,5,43,11,11,1,11,10,1,11,6,1,7,3,39,11,10,10,3,11,9,56,6,11,11,11,3,11,4,11,5,11,6,17,20,6,232,3,0,0,0,0,0,0,26,18,1,56,7,2,5,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,5,20,35,4,39,5,45,11,8,1,11,0,1,7,4,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,6,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,4,20,35,4,39,5,45,11,8,1,11,0,1,7,5,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,7,1,0,0,26,136,1,11,0,17,8,10,4,16,6,10,5,56,5,4,8,5,20,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,2,39,10,4,15,6,10,5,12,14,46,11,14,56,8,12,24,10,3,46,17,16,12,25,14,25,17,15,12,30,11,24,14,30,33,4,40,5,52,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,6,39,11,1,11,6,10,7,12,16,12,15,46,11,15,11,16,17,28,12,31,10,2,11,31,64,32,1,0,0,0,0,0,0,0,10,7,12,18,12,17,46,11,17,11,18,17,17,12,26,11,2,11,26,10,3,11,8,10,7,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,17,19,12,22,10,7,17,20,6,232,3,0,0,0,0,0,0,26,12,19,11,4,15,0,11,5,56,9,12,23,11,3,11,7,12,13,46,11,13,7,0,17,18,12,29,11,22,56,10,14,29,17,13,12,27,14,27,17,11,12,28,14,29,17,12,12,20,14,20,17,10,12,21,11,28,77,10,23,15,1,21,11,21,51,10,23,15,2,21,11,19,11,23,15,3,21,2,0,4,1,0,1,1,1,2,0,1,0,2,0,3,0],"pool_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,136,1,4,146,1,2,5,148,1,208,1,7,228,2,205,4,8,177,7,32,6,209,7,41,12,250,7,133,12,0,23,0,10,0,24,1,0,7,0,0,18,0,1,0,0,22,0,1,0,0,21,0,1,0,0,19,0,1,0,0,20,0,1,0,0,16,0,1,0,0,17,0,1,0,0,11,2,3,0,0,1,3,4,0,0,15,5,3,0,0,5,3,6,0,0,14,7,3,0,0,4,3,8,0,0,13,9,3,0,0,3,3,9,0,1,2,3,12,0,1,12,12,3,0,2,6,19,20,0,2,7,19,27,0,2,8,19,21,0,2,9,19,1,0,2,25,11,0,0,2,26,25,0,0,2,27,14,0,0,2,28,15,0,0,2,29,13,0,0,2,30,17,18,1,1,26,1,0,1,2,5,8,0,8,0,3,13,10,2,1,10,2,6,8,0,8,0,3,13,2,10,2,5,13,3,8,0,8,0,3,6,13,3,8,0,8,0,3,2,3,8,0,13,10,2,4,8,0,13,2,10,2,3,13,15,2,3,10,2,10,2,10,2,2,7,10,2,13,1,8,0,2,7,10,2,10,2,2,7,10,2,3,2,7,10,2,2,18,10,2,10,2,10,2,10,2,10,2,10,2,3,13,10,2,13,3,3,3,8,0,2,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,17,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,3,3,8,0,2,13,13,8,0,13,2,10,2,10,2,13,10,2,10,2,10,2,10,2,13,10,2,13,3,3,3,2,8,0,13,2,7,10,2,15,9,10,2,10,2,10,2,3,13,15,3,3,2,1,15,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,100,101,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,21,103,101,116,95,100,101,108,101,116,101,95,111,119,110,101,114,95,116,121,112,101,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,16,103,101,116,95,100,101,112,111,115,105,116,95,116,121,112,101,23,103,101,116,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,21,103,101,116,95,115,101,110,100,95,109,101,115,115,97,103,101,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,10,112,111,111,108,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,10,48,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,3,17,21,11,0,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,1,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,2,17,23,13,6,7,2,17,24,14,4,65,1,6,0,0,0,0,0,0,0,0,36,4,46,13,6,14,4,65,1,75,17,21,13,6,11,4,17,25,11,6,2,8,1,0,0,16,172,1,14,0,65,1,12,13,6,0,0,0,0,0,0,0,0,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,1,14,1,17,17,12,8,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,2,14,2,17,17,12,16,11,12,11,11,22,12,12,11,16,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,14,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,3,14,3,17,17,12,18,11,12,11,11,22,12,12,11,18,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,17,11,12,11,11,22,12,12,6,8,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,4,14,4,17,19,12,7,11,12,11,11,22,12,12,6,1,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,5,14,5,17,20,12,15,11,12,11,11,22,12,12,64,1,0,0,0,0,0,0,0,0,12,9,10,13,10,12,36,4,151,1,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,6,14,6,17,17,12,10,11,12,11,11,22,12,12,11,10,52,12,11,14,0,10,12,10,12,10,11,22,56,0,12,9,11,12,11,11,22,12,12,10,15,7,2,33,4,156,1,5,158,1,7,1,39,11,13,11,12,33,4,163,1,5,165,1,7,0,39,11,14,11,17,11,7,11,8,11,15,11,9,2,9,1,0,0,10,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,21,13,6,11,1,17,23,11,2,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,3,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,4,17,23,13,6,7,3,17,24,11,6,2,10,1,0,0,22,152,1,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,15,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,19,12,11,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,17,11,9,11,8,22,12,9,11,17,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,19,12,7,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,20,12,13,11,9,11,8,22,12,9,10,13,7,3,33,4,136,1,5,138,1,7,1,39,11,10,11,9,33,4,143,1,5,145,1,7,0,39,11,15,11,11,11,12,11,16,11,7,11,13,2,11,1,0,0,23,34,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,1,17,21,11,0,17,16,12,4,13,3,14,4,65,1,75,17,21,13,3,11,4,17,25,13,3,7,4,17,24,14,2,65,1,6,0,0,0,0,0,0,0,0,36,4,32,13,3,14,2,65,1,75,17,21,13,3,11,2,17,25,11,3,2,12,1,0,0,24,123,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,5,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,20,12,11,11,9,11,8,22,12,9,64,1,0,0,0,0,0,0,0,0,12,6,10,10,10,9,36,4,104,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,7,11,9,11,8,22,12,9,11,7,52,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,11,9,11,8,22,12,9,10,11,7,4,33,4,109,5,111,7,1,39,11,10,11,9,33,4,116,5,118,7,0,39,11,12,11,5,11,11,11,6,2,13,1,0,0,3,13,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,0,17,21,13,3,11,1,17,22,13,3,11,2,17,24,11,3,2,14,1,0,0,26,64,14,0,65,1,12,8,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,1,14,1,17,17,12,5,11,7,11,4,22,12,7,6,32,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,2,14,2,17,18,12,6,11,7,11,4,22,12,7,6,1,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,3,14,3,17,20,12,9,11,7,11,4,22,12,7,11,8,11,7,33,4,58,5,60,7,0,39,11,5,11,6,11,9,2,0],"pool_manager":[161,28,235,11,6,0,0,0,12,1,0,22,2,22,66,3,88,199,1,4,159,2,62,5,221,2,206,2,7,171,5,144,8,8,187,13,96,6,155,14,138,1,10,165,15,108,12,145,16,154,13,13,171,29,32,15,203,29,4,0,62,0,28,0,30,0,36,1,21,1,58,2,32,2,57,2,74,2,76,2,77,0,9,12,0,0,1,4,0,0,7,4,0,0,4,4,0,0,8,4,0,0,6,4,0,0,0,3,0,0,10,3,0,1,2,7,0,3,3,0,0,4,11,7,0,5,5,7,1,0,0,7,14,4,0,8,12,12,2,7,1,4,1,10,13,2,0,0,51,0,1,0,0,66,2,1,0,0,65,3,1,0,0,71,4,1,0,0,69,5,1,0,0,70,4,1,0,0,47,6,7,0,0,41,8,9,0,0,44,6,10,0,0,37,11,12,0,0,48,6,12,0,0,43,8,12,0,0,42,8,12,0,0,45,6,12,0,0,46,8,12,0,0,38,1,12,0,0,39,1,12,0,0,35,13,14,0,0,34,15,16,0,0,33,17,16,0,0,81,1,18,0,0,16,19,20,0,0,67,19,20,0,1,40,46,9,0,2,24,49,12,0,2,25,49,12,0,2,26,20,12,0,5,56,1,47,1,0,5,73,28,47,1,0,6,29,28,1,1,3,7,55,0,21,0,8,15,31,1,2,7,4,8,22,41,42,2,7,4,8,23,35,36,2,7,4,8,27,41,16,2,7,4,8,55,0,23,2,7,4,9,72,28,1,1,8,35,22,35,24,35,25,35,26,36,27,35,30,31,24,31,26,35,33,31,22,31,25,33,26,33,24,31,30,33,30,32,26,32,25,32,24,32,22,34,33,32,33,32,30,28,32,27,32,34,24,34,25,33,22,31,33,33,33,29,50,29,51,1,7,8,14,0,5,6,8,9,7,8,0,8,10,13,7,8,14,4,6,8,9,7,8,0,8,8,13,4,6,8,9,7,8,0,8,8,15,4,6,8,9,7,8,0,13,15,2,7,8,0,13,1,10,8,8,2,7,8,0,8,8,1,13,1,8,10,3,6,8,0,13,13,1,15,3,7,8,0,13,13,1,11,11,1,8,8,2,6,8,0,13,1,1,2,6,8,0,8,8,1,8,3,4,7,8,0,8,8,13,15,2,15,15,1,8,12,2,13,8,1,1,11,13,2,9,0,9,1,2,13,8,2,2,8,8,13,2,13,10,8,8,1,8,0,1,9,0,8,13,8,10,8,3,11,13,2,8,8,8,4,8,1,7,11,13,2,13,8,1,8,2,7,11,13,2,13,8,2,2,8,8,8,4,3,7,11,13,2,9,0,9,1,9,0,9,1,1,8,8,2,13,8,3,3,13,8,8,7,8,5,2,7,11,13,2,9,0,9,1,9,0,1,7,9,1,4,8,8,13,7,8,2,7,8,4,2,13,7,8,2,3,8,8,13,7,8,4,2,13,13,2,6,11,13,2,9,0,9,1,9,0,1,6,9,1,2,8,8,8,8,2,15,6,11,13,2,13,8,3,4,8,8,3,3,10,8,8,1,6,8,8,1,11,11,1,9,0,9,8,8,13,15,7,11,13,2,13,8,3,7,8,3,13,15,7,8,2,7,8,4,6,15,15,15,15,15,15,1,8,6,1,8,7,12,65,100,100,76,105,113,117,105,100,105,116,121,7,65,112,112,73,110,102,111,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,9,76,105,113,117,105,100,105,116,121,6,79,112,116,105,111,110,11,80,111,111,108,67,97,116,97,108,111,103,8,80,111,111,108,73,110,102,111,13,80,111,111,108,76,105,113,117,105,100,105,116,121,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,15,82,101,109,111,118,101,76,105,113,117,105,100,105,116,121,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,13,97,100,100,95,108,105,113,117,105,100,105,116,121,7,97,108,112,104,97,95,49,6,97,109,111,117,110,116,9,97,112,112,95,105,110,102,111,115,13,97,112,112,95,108,105,113,117,105,100,105,116,121,5,97,115,99,105,105,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,5,101,118,101,110,116,18,101,120,105,115,116,95,99,101,114,116,97,105,110,95,112,111,111,108,13,101,120,105,115,116,95,112,111,111,108,95,105,100,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,100,101,102,97,117,108,116,95,97,108,112,104,97,95,49,20,103,101,116,95,100,101,102,97,117,108,116,95,108,97,109,98,100,97,95,49,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,24,103,101,116,95,112,111,111,108,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,112,111,111,108,95,110,97,109,101,95,98,121,95,105,100,21,103,101,116,95,112,111,111,108,95,116,111,116,97,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,115,95,98,121,95,105,100,19,103,101,116,95,116,111,107,101,110,95,108,105,113,117,105,100,105,116,121,2,105,100,11,105,100,95,116,111,95,112,111,111,108,115,4,105,110,105,116,8,108,97,109,98,100,97,95,49,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,110,97,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,12,112,111,111,108,95,97,100,100,114,101,115,115,12,112,111,111,108,95,99,97,116,97,108,111,103,10,112,111,111,108,95,105,110,102,111,115,12,112,111,111,108,95,109,97,110,97,103,101,114,10,112,111,111,108,95,116,111,95,105,100,5,112,111,111,108,115,13,114,101,103,105,115,116,101,114,95,112,111,111,108,16,114,101,103,105,115,116,101,114,95,112,111,111,108,95,105,100,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,7,114,101,115,101,114,118,101,21,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,97,108,112,104,97,22,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,108,97,109,98,100,97,15,115,101,116,95,112,111,111,108,95,119,101,105,103,104,116,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,116,97,98,108,101,12,116,111,116,97,108,95,119,101,105,103,104,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,119,101,105,103,104,116,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,14,122,101,114,111,95,108,105,113,117,105,100,105,116,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,0,88,241,76,176,44,241,78,240,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,37,164,0,10,139,202,34,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,0,2,4,49,8,12,19,11,13,2,13,8,1,61,11,13,2,13,8,2,60,8,5,1,2,1,20,11,13,2,13,8,3,2,2,5,54,8,10,68,8,3,17,15,75,15,64,11,13,2,8,8,8,4,3,2,1,78,15,4,2,4,78,15,52,15,30,15,79,15,5,2,2,63,11,13,2,8,8,13,50,11,13,2,13,10,8,8,6,2,3,59,8,8,18,15,31,15,7,2,3,59,8,8,18,15,30,15,0,0,0,0,1,14,10,0,17,30,10,0,56,0,10,0,56,1,10,0,56,2,11,0,56,3,18,5,18,0,56,4,2,1,1,0,0,29,54,10,1,10,3,12,5,46,11,5,17,18,32,4,9,5,15,11,1,1,11,4,1,7,2,39,10,1,15,0,12,12,11,2,12,6,17,20,12,7,10,4,56,5,12,8,11,6,11,7,7,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,8,18,2,12,11,11,12,10,3,11,11,56,6,10,1,15,1,15,2,10,3,64,32,0,0,0,0,0,0,0,0,56,7,11,1,15,3,12,10,11,4,56,8,18,1,12,9,11,10,11,3,11,9,56,9,2,2,1,0,0,34,52,10,1,10,3,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,10,1,10,2,12,5,46,11,5,17,19,32,4,21,5,25,11,1,1,7,4,39,10,1,15,1,12,6,10,6,15,4,10,2,10,3,56,10,11,6,15,2,10,3,56,11,10,2,68,32,11,1,15,0,11,3,56,12,15,5,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,4,56,13,2,3,1,0,0,37,43,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,12,6,10,6,15,5,11,2,56,14,12,7,10,6,16,6,20,10,7,16,7,20,23,10,3,22,11,6,15,6,21,11,3,11,7,15,7,21,2,4,1,0,0,38,22,10,1,10,2,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,11,1,15,0,11,2,56,12,12,5,11,3,11,5,15,8,21,2,5,1,0,0,39,29,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,15,5,11,2,56,14,12,6,11,3,11,6,15,9,21,2,6,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,1,15,2,11,1,12,3,46,11,3,56,15,20,2,7,1,0,0,43,22,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,11,0,15,1,15,4,11,1,12,3,46,11,3,56,16,20,2,8,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,0,11,1,12,3,46,11,3,56,17,16,10,20,2,9,1,0,0,44,32,10,0,10,1,17,18,4,5,5,9,11,0,1,7,3,39,11,0,16,3,11,1,56,18,16,11,12,4,10,4,10,2,56,19,4,26,11,4,11,2,56,20,16,12,20,12,3,5,30,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,10,1,0,0,9,20,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,13,16,12,20,2,11,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,14,20,2,12,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,15,20,2,13,1,0,0,9,19,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,6,20,2,14,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,7,20,2,15,1,0,0,1,2,7,0,2,16,1,0,0,1,2,7,1,2,17,1,0,0,45,34,11,0,11,1,17,6,12,6,14,6,65,32,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,32,5,14,14,6,10,4,66,32,20,12,3,14,3,17,23,10,2,33,4,27,11,3,56,22,2,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,9,56,23,2,18,1,0,0,1,5,11,0,16,0,11,1,56,24,2,19,1,0,0,1,6,11,0,16,1,16,4,11,1,56,25,2,20,1,0,0,1,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,2,21,3,0,0,48,119,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,12,16,15,20,10,12,16,9,20,17,25,12,10,10,3,10,10,22,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,32,4,73,11,7,11,2,10,6,18,3,56,27,5,85,11,7,11,2,56,28,12,8,10,8,16,12,20,10,6,22,11,8,15,12,21,10,11,16,13,16,12,20,10,3,22,11,11,15,13,15,12,21,10,12,16,14,20,10,3,22,10,12,15,14,21,10,12,16,15,20,10,10,23,11,12,15,15,21,11,1,11,3,10,10,18,6,56,29,11,6,11,10,2,22,3,0,0,48,151,1,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,12,16,14,20,10,3,38,4,33,5,41,11,0,1,11,12,1,11,11,1,7,8,39,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,11,16,8,20,10,12,16,9,20,17,24,12,10,10,3,10,10,23,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,4,82,5,90,11,12,1,11,11,1,11,7,1,7,6,39,11,7,11,2,56,28,12,8,10,8,16,12,20,10,3,38,4,101,5,109,11,12,1,11,11,1,11,8,1,7,7,39,10,8,16,12,20,10,3,23,11,8,15,12,21,10,11,16,13,16,12,20,10,6,23,11,11,15,13,15,12,21,10,12,16,14,20,10,6,23,10,12,15,14,21,10,12,16,15,20,10,10,22,11,12,15,15,21,11,1,11,3,10,10,18,7,56,30,11,6,11,10,2,0,2,0,3,5,1,0,1,5,0,2,4,2,3,4,3,2,2,4,1,2,0,1,0,3,0,2,1,4,0,4,2,0,53,0,80,0],"rates":[161,28,235,11,6,0,0,0,8,1,0,6,2,6,4,3,10,70,5,80,48,7,128,1,185,2,8,185,3,32,6,217,3,68,12,157,4,128,5,0,13,0,11,0,16,1,0,8,0,0,6,0,1,0,0,2,0,1,0,0,5,2,1,0,0,1,3,1,0,0,3,4,1,0,0,4,4,1,0,1,7,6,1,0,1,8,6,3,0,1,9,6,1,0,1,10,6,1,0,2,12,7,1,0,2,14,5,1,0,2,15,7,1,0,2,17,7,1,0,3,7,8,0,13,15,1,15,4,7,8,0,13,15,15,4,15,15,15,15,3,15,15,15,0,2,7,8,0,13,2,15,15,6,15,15,15,15,15,15,7,15,15,15,15,15,15,15,7,83,116,111,114,97,103,101,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,21,99,97,108,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,3,109,105,110,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,128,81,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,3,29,10,0,10,1,17,8,12,6,11,0,11,1,17,6,12,4,11,6,11,4,17,13,12,5,10,5,10,2,22,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,27,10,5,11,5,11,2,22,17,12,12,3,11,3,2,1,1,0,0,8,39,10,0,10,1,11,2,17,0,12,8,11,0,11,1,17,7,12,7,12,6,12,5,12,4,10,8,10,7,35,4,23,11,4,11,8,11,5,17,13,22,12,3,5,37,11,4,11,5,22,11,6,11,8,10,7,23,17,11,11,7,23,17,12,17,13,22,12,3,11,3,2,2,1,0,0,7,17,10,0,10,1,11,3,17,0,12,5,11,0,11,1,17,9,12,4,11,2,11,5,17,11,11,4,23,17,13,17,13,2,3,1,0,0,7,20,11,0,11,1,23,7,1,17,10,12,4,7,1,10,4,23,12,5,11,2,11,5,24,11,3,11,4,24,22,7,1,26,2,4,1,0,0,9,69,11,0,11,1,23,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,10,17,11,2,10,5,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,6,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,23,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,7,5,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,2,10,2,17,13,7,0,7,0,24,26,12,4,10,4,10,2,17,13,7,0,26,12,3,10,5,10,6,24,11,4,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,10,5,11,6,24,11,7,24,11,3,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,9,17,11,11,2,11,5,24,7,0,26,22,11,8,22,11,9,22,2,5,1,0,0,1,12,11,2,11,0,11,1,23,24,7,0,26,12,3,17,11,11,3,22,2,0],"ray_math":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,40,5,42,13,7,55,59,8,114,32,6,146,1,146,1,12,164,2,247,5,0,7,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,4,2,1,0,0,1,2,1,0,0,2,2,1,0,0,6,1,1,0,0,0,1,3,0,0,1,15,2,15,15,1,2,4,15,2,15,15,4,108,111,103,50,3,109,97,120,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,208,121,0,161,63,121,92,118,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,249,214,165,42,128,81,101,243,159,91,61,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,1,0,0,0,2,7,0,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,10,11,0,11,1,24,7,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,7,0,26,2,3,1,0,0,0,10,11,0,7,0,24,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,11,1,26,2,4,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,6,1,0,0,4,59,10,0,7,0,38,4,5,5,7,7,4,39,10,0,7,0,26,17,7,12,2,10,2,77,7,0,24,12,3,11,0,11,2,48,12,4,10,4,7,0,33,4,27,11,3,2,7,1,12,1,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,57,5,34,10,4,11,4,24,7,0,26,12,4,10,4,7,2,38,4,52,11,3,10,1,22,12,3,11,4,49,1,48,12,4,11,1,49,1,48,12,1,5,29,11,3,2,7,1,0,0,3,112,49,0,12,1,10,0,49,128,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,16,11,0,49,128,48,12,0,11,1,49,128,22,12,1,10,0,49,64,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,30,11,0,49,64,48,12,0,11,1,49,64,22,12,1,10,0,49,32,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,44,11,0,49,32,48,12,0,11,1,49,32,22,12,1,10,0,49,16,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,58,11,0,49,16,48,12,0,11,1,49,16,22,12,1,10,0,49,8,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,72,11,0,49,8,48,12,0,11,1,49,8,22,12,1,10,0,49,4,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,0,49,4,48,12,0,11,1,49,4,22,12,1,10,0,49,2,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,100,11,0,49,2,48,12,0,11,1,49,2,22,12,1,11,0,49,1,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,110,11,1,49,1,22,12,1,11,1,2,0],"scaled_balance":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,25,5,29,6,7,35,75,8,110,32,12,142,1,39,0,6,0,4,0,0,0,1,0,0,2,0,1,0,0,1,0,1,0,1,3,0,1,0,1,5,0,1,0,2,15,15,1,15,0,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,2,4,11,0,11,1,17,4,2,1,1,0,0,2,4,11,0,11,1,17,3,2,2,1,0,0,2,4,11,0,11,1,17,3,2,0],"serde":[161,28,235,11,6,0,0,0,9,1,0,12,2,12,8,3,20,167,1,4,187,1,12,5,199,1,148,1,7,219,2,211,4,8,174,7,96,6,142,8,20,12,162,8,157,35,0,23,1,4,1,6,1,36,1,37,2,2,1,0,7,0,3,1,7,0,0,32,0,1,0,0,28,2,1,0,0,31,3,1,0,0,26,4,1,0,0,29,5,1,0,0,19,6,6,0,0,5,6,6,0,0,27,4,1,0,0,30,5,1,0,0,33,7,1,0,0,24,8,1,0,0,25,9,1,1,0,0,34,7,1,0,0,14,10,6,0,0,10,10,11,0,0,13,10,12,0,0,8,10,13,0,0,11,10,14,0,0,9,10,13,0,0,12,10,14,0,0,7,10,15,0,0,18,10,12,0,0,15,10,16,0,0,38,17,18,1,1,0,39,19,20,1,3,1,20,28,16,0,2,35,27,16,1,0,3,17,1,30,1,0,3,21,30,28,0,4,3,25,1,1,0,4,22,24,1,1,0,5,16,16,15,0,30,6,29,6,26,15,27,29,23,6,23,29,2,7,10,2,2,0,2,7,10,2,13,2,7,10,2,3,2,7,10,2,4,2,7,10,2,15,1,2,2,7,10,2,10,2,2,7,10,2,5,1,7,10,2,1,6,10,2,1,13,1,3,1,4,1,15,1,5,1,10,2,3,6,10,9,0,3,3,1,10,9,0,2,6,10,9,0,9,0,1,10,10,9,0,2,1,2,3,1,1,2,2,4,10,2,1,7,10,9,0,2,7,10,9,0,10,9,0,2,15,10,2,1,6,9,0,1,8,0,1,9,0,1,8,1,2,4,3,2,15,3,3,10,2,3,3,3,1,3,10,9,0,3,3,10,10,9,0,3,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,6,97,112,112,101,110,100,5,97,115,99,105,105,16,97,115,99,105,105,95,116,111,95,104,101,120,95,115,116,114,3,98,99,115,19,100,101,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,16,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,29,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,29,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,30,100,101,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,17,103,101,116,95,118,101,99,116,111,114,95,108,101,110,103,116,104,16,104,101,120,95,115,116,114,95,116,111,95,97,115,99,105,105,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,7,114,101,118,101,114,115,101,5,115,101,114,100,101,17,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,14,115,101,114,105,97,108,105,122,101,95,116,121,112,101,14,115,101,114,105,97,108,105,122,101,95,117,49,50,56,27,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,27,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,28,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,6,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,12,118,101,99,116,111,114,95,115,112,108,105,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,68,6,2,1,1,0,0,1,15,10,0,10,1,49,8,48,72,255,0,28,51,17,0,11,0,11,1,72,255,0,28,51,17,0,2,2,1,0,0,1,63,10,0,10,1,49,56,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,6,255,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,6,255,0,0,0,0,0,0,0,28,51,17,0,2,3,1,0,0,1,127,10,0,10,1,49,120,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,4,1,0,0,1,255,1,10,0,10,1,49,248,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,240,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,232,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,224,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,216,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,208,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,200,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,192,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,184,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,176,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,168,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,160,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,152,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,144,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,136,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,128,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,120,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,5,1,0,0,21,31,10,0,49,0,38,4,9,10,0,49,9,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,22,12,2,5,29,10,0,49,15,37,4,23,5,25,7,1,39,11,0,49,87,22,12,2,11,2,2,6,1,0,0,22,40,10,0,49,48,38,4,9,10,0,49,57,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,3,5,38,10,0,49,97,38,4,27,10,0,49,102,37,12,2,5,29,9,12,2,11,2,4,32,5,34,7,1,39,11,0,49,87,23,12,3,11,3,2,7,1,0,0,23,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,8,1,0,0,26,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,9,1,0,0,1,4,11,0,11,1,56,1,2,10,1,0,0,16,17,14,1,56,2,12,2,14,2,65,6,6,32,0,0,0,0,0,0,0,33,4,9,5,13,11,0,1,7,0,39,11,0,11,2,56,1,2,11,1,0,0,28,8,56,3,17,28,12,1,11,0,11,1,17,25,17,9,2,12,1,0,0,12,17,14,1,65,6,12,2,10,2,6,0,0,0,0,0,0,0,0,33,4,10,11,0,1,2,10,0,11,2,17,2,11,0,11,1,17,9,2,13,1,0,0,1,15,10,0,65,6,6,1,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,6,0,0,0,0,0,0,0,0,66,6,20,2,14,1,0,0,1,24,10,0,65,6,6,2,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,75,49,8,47,11,0,6,1,0,0,0,0,0,0,0,66,6,20,75,22,2,15,1,0,0,1,72,10,0,65,6,6,8,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,52,49,56,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,52,49,48,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,52,49,40,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,52,49,32,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,52,49,24,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,52,49,16,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,52,49,8,47,22,11,0,6,7,0,0,0,0,0,0,0,66,6,20,52,22,2,16,1,0,0,1,136,1,10,0,65,6,6,16,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,53,49,120,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,53,49,112,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,53,49,104,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,53,49,96,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,53,49,88,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,53,49,80,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,53,49,72,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,53,49,64,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,53,49,56,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,53,49,48,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,53,49,40,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,53,49,32,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,53,49,24,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,53,49,16,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,53,49,8,47,22,11,0,6,15,0,0,0,0,0,0,0,66,6,20,53,22,2,17,1,0,0,1,136,2,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,77,49,248,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,77,49,240,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,77,49,232,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,77,49,224,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,77,49,216,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,77,49,208,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,77,49,200,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,77,49,192,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,77,49,184,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,77,49,176,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,77,49,168,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,77,49,160,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,77,49,152,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,77,49,144,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,77,49,136,47,22,10,0,6,15,0,0,0,0,0,0,0,66,6,20,77,49,128,47,22,10,0,6,16,0,0,0,0,0,0,0,66,6,20,77,49,120,47,22,10,0,6,17,0,0,0,0,0,0,0,66,6,20,77,49,112,47,22,10,0,6,18,0,0,0,0,0,0,0,66,6,20,77,49,104,47,22,10,0,6,19,0,0,0,0,0,0,0,66,6,20,77,49,96,47,22,10,0,6,20,0,0,0,0,0,0,0,66,6,20,77,49,88,47,22,10,0,6,21,0,0,0,0,0,0,0,66,6,20,77,49,80,47,22,10,0,6,22,0,0,0,0,0,0,0,66,6,20,77,49,72,47,22,10,0,6,23,0,0,0,0,0,0,0,66,6,20,77,49,64,47,22,10,0,6,24,0,0,0,0,0,0,0,66,6,20,77,49,56,47,22,10,0,6,25,0,0,0,0,0,0,0,66,6,20,77,49,48,47,22,10,0,6,26,0,0,0,0,0,0,0,66,6,20,77,49,40,47,22,10,0,6,27,0,0,0,0,0,0,0,66,6,20,77,49,32,47,22,10,0,6,28,0,0,0,0,0,0,0,66,6,20,77,49,24,47,22,10,0,6,29,0,0,0,0,0,0,0,66,6,20,77,49,16,47,22,10,0,6,30,0,0,0,0,0,0,0,66,6,20,77,49,8,47,22,11,0,6,31,0,0,0,0,0,0,0,66,6,20,77,22,2,18,1,0,0,31,29,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,53,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,19,1,0,0,32,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,77,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,20,1,0,0,1,14,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,20,17,31,2,21,1,0,0,16,8,11,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,2,22,1,0,0,33,46,10,0,65,6,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,64,6,0,0,0,0,0,0,0,0,2,10,3,6,8,0,0,0,0,0,0,0,36,4,16,5,20,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,12,2,11,3,10,2,6,8,0,0,0,0,0,0,0,22,33,4,35,5,39,11,0,1,7,0,39,11,0,6,8,0,0,0,0,0,0,0,11,2,6,8,0,0,0,0,0,0,0,22,56,4,2,23,1,0,0,34,43,10,1,10,2,35,4,10,10,2,10,0,65,29,37,12,3,5,12,9,12,3,11,3,4,15,5,19,11,0,1,7,0,39,64,29,0,0,0,0,0,0,0,0,12,5,11,1,12,4,10,4,10,2,35,4,39,5,28,13,5,10,0,10,4,66,29,20,68,29,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,23,11,0,1,11,5,2,24,1,0,0,35,53,64,18,0,0,0,0,0,0,0,0,12,3,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,29,35,4,38,5,12,10,0,10,2,66,29,20,10,1,33,4,33,10,4,10,2,35,4,29,13,3,10,0,11,4,10,2,56,5,68,18,10,2,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,10,4,10,2,35,4,49,13,3,11,0,11,4,11,2,56,5,68,18,5,51,11,0,1,11,3,2,0],"system_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,71,4,81,2,5,83,78,7,161,1,150,2,8,183,3,32,6,215,3,26,12,241,3,169,2,0,16,0,6,0,11,1,0,7,0,0,9,0,1,0,0,10,0,1,0,0,7,2,3,0,0,1,3,2,0,1,2,3,7,0,1,8,7,3,0,2,3,13,14,0,2,4,13,15,0,2,5,13,1,0,2,12,5,0,0,2,13,6,0,0,2,14,9,0,0,2,15,8,0,0,2,17,11,12,1,1,13,1,0,1,2,4,13,3,8,0,2,1,10,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,12,10,2,10,2,10,2,10,2,8,0,13,3,3,3,3,13,2,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,11,68,111,108,97,65,100,100,114,101,115,115,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,19,101,110,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,115,121,115,116,101,109,95,99,111,100,101,99,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,4,24,64,1,0,0,0,0,0,0,0,0,12,5,13,5,11,0,17,9,13,5,11,1,17,10,11,2,17,5,12,4,13,5,14,4,65,1,75,17,9,13,5,11,4,17,12,13,5,11,3,17,11,11,5,2,3,1,0,0,10,96,14,0,65,1,12,9,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,1,14,1,17,6,12,11,11,8,11,7,22,12,8,6,8,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,2,14,2,17,7,12,10,11,8,11,7,22,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,3,14,3,17,6,12,6,11,8,11,7,22,12,8,11,6,52,12,7,14,0,10,8,10,8,10,7,22,56,0,17,4,12,5,11,8,11,7,22,12,8,6,1,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,4,14,4,17,8,12,12,11,8,11,7,22,12,8,11,9,11,8,33,4,89,5,91,7,0,39,11,11,11,10,11,5,11,12,2,0],"system_core_storage":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,24,3,36,26,4,62,2,5,64,35,7,99,252,1,8,223,2,64,10,159,3,9,12,168,3,34,13,202,3,2,15,204,3,2,0,16,0,7,0,8,1,13,1,18,1,19,0,2,8,0,1,0,12,0,1,3,12,0,2,1,0,0,3,5,4,0,5,4,2,0,0,11,0,1,0,0,9,2,3,0,1,14,0,6,0,3,12,4,5,0,4,15,8,1,1,8,4,7,3,6,8,3,7,8,2,7,8,5,0,1,6,8,0,1,6,8,1,1,7,8,5,1,8,4,1,8,1,1,8,0,1,9,0,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,7,83,116,111,114,97,103,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,3,110,101,119,6,111,98,106,101,99,116,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,10,8,4,6,8,1,0,1,0,0,1,9,10,2,17,3,11,0,11,1,11,2,17,2,18,0,56,0,2,1,3,0,0,1,3,11,0,16,0,2,0,1,0,17,0],"system_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,24,2,24,40,3,64,71,4,135,1,2,5,137,1,117,7,254,1,155,4,8,153,6,96,6,249,6,10,10,131,7,17,12,148,7,191,1,0,33,0,10,0,16,0,19,0,31,0,32,0,38,0,39,1,14,1,18,1,34,2,30,0,7,3,0,1,0,12,0,2,3,7,0,3,4,8,0,5,6,8,0,6,9,12,0,7,2,12,0,8,1,8,0,10,8,2,0,11,5,12,0,0,11,0,1,0,0,35,0,1,0,2,22,13,8,0,2,23,13,14,0,3,13,3,1,0,4,15,8,9,0,4,21,1,10,0,4,24,1,10,0,5,20,4,5,0,6,11,12,1,0,6,27,11,1,0,6,35,12,1,0,7,26,6,7,0,9,17,16,1,1,3,13,15,8,6,8,3,7,8,5,7,8,9,7,8,6,6,8,4,10,2,6,8,7,7,8,8,0,6,10,2,8,2,2,3,8,2,13,1,6,8,3,1,6,8,4,1,6,8,1,6,7,8,9,7,8,6,6,8,1,10,2,6,8,7,7,8,8,2,8,2,10,2,1,10,2,4,13,3,8,2,2,1,2,2,7,8,5,8,2,3,7,8,5,8,2,8,2,1,6,8,2,1,13,1,8,0,1,9,0,6,10,2,2,3,8,2,13,8,2,6,65,112,112,67,97,112,5,67,108,111,99,107,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,5,83,116,97,116,101,7,83,116,111,114,97,103,101,15,83,121,115,116,101,109,67,111,114,101,69,118,101,110,116,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,11,97,112,112,95,109,97,110,97,103,101,114,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,110,111,110,99,101,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,12,115,121,115,116,101,109,95,99,111,100,101,99,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,0,2,6,25,3,28,10,2,29,13,37,13,36,10,2,12,2,0,1,4,0,2,51,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,12,11,8,17,5,12,10,12,9,12,11,12,13,10,10,17,6,33,4,23,5,27,11,1,1,7,0,39,10,12,10,9,33,4,35,11,1,10,12,17,10,5,39,11,1,10,12,10,9,17,9,11,11,14,12,17,2,11,13,14,9,17,3,14,9,17,2,11,10,18,0,56,0,2,1,1,4,0,17,43,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,11,11,8,17,5,12,9,12,13,12,10,12,12,10,9,17,7,33,4,23,5,27,11,1,1,7,0,39,11,1,10,11,10,13,17,11,11,10,14,11,17,2,11,12,14,13,17,3,14,13,17,2,11,9,18,0,56,0,2,0],"system_portal":[161,28,235,11,6,0,0,0,10,1,0,18,2,18,28,3,46,82,4,128,1,4,5,132,1,84,7,216,1,208,3,8,168,5,64,10,232,5,22,12,254,5,187,1,13,185,7,2,0,30,0,13,0,16,0,29,0,37,1,15,1,25,1,31,1,32,0,3,8,0,0,2,3,0,1,0,7,0,2,1,8,0,4,6,12,0,6,5,4,0,8,4,2,0,0,21,0,1,0,0,18,2,3,0,0,8,4,1,0,0,34,4,1,0,1,11,11,12,0,1,12,13,12,0,2,10,9,1,0,3,17,1,16,0,3,19,1,16,0,4,7,15,1,0,4,26,14,1,0,4,33,15,1,0,5,14,7,1,1,3,6,22,0,5,0,7,28,7,1,1,8,8,27,10,11,0,14,6,12,17,1,7,8,6,0,1,7,8,0,1,3,6,6,8,3,7,8,0,7,8,4,13,10,2,7,8,6,1,8,5,1,8,0,1,9,0,3,8,2,5,8,2,1,6,8,3,1,6,8,6,1,5,1,8,2,2,13,10,2,2,7,8,4,8,2,3,7,8,4,8,2,8,2,1,2,1,8,1,3,5,8,2,8,2,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,83,121,115,116,101,109,76,111,99,97,108,69,118,101,110,116,12,83,121,115,116,101,109,80,111,114,116,97,108,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,7,98,105,110,100,105,110,103,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,2,105,100,4,105,110,105,116,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,6,111,98,106,101,99,116,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,115,121,115,116,101,109,95,99,111,100,101,99,13,115,121,115,116,101,109,95,112,111,114,116,97,108,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,117,110,98,105,110,100,105,110,103,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,20,8,5,23,3,1,2,5,24,3,27,5,36,13,35,10,2,9,2,0,0,0,0,1,6,11,0,17,13,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,4,0,8,34,11,0,17,6,11,5,46,17,15,12,7,10,7,17,4,12,8,10,3,10,4,17,5,12,6,10,8,10,6,33,4,21,11,2,11,8,17,10,5,25,11,2,11,8,11,6,17,9,11,1,17,1,11,7,11,3,11,4,17,7,18,1,56,1,2,3,1,4,0,18,26,11,0,17,6,11,5,46,17,15,12,6,10,6,17,4,12,8,10,3,10,4,17,5,12,7,11,2,11,8,11,7,17,11,11,1,17,1,11,6,11,3,11,4,17,8,18,1,56,1,2,0,1,0],"user_manager":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,40,3,58,138,1,4,196,1,42,5,238,1,128,2,7,238,3,161,5,8,143,9,96,6,239,9,60,10,171,10,49,12,220,10,247,4,13,211,15,8,15,219,15,8,0,48,0,15,0,20,1,49,2,19,2,31,2,39,2,40,2,41,0,8,12,0,0,7,4,0,0,0,3,0,0,6,3,0,1,1,7,0,2,2,0,0,5,5,4,0,6,3,12,2,7,1,4,1,8,4,2,0,0,26,0,1,0,0,33,2,1,0,0,43,3,1,0,0,22,4,5,0,0,23,6,7,0,0,32,4,8,0,0,27,4,9,0,0,34,10,1,0,0,10,11,1,0,0,42,11,1,0,1,21,28,29,0,1,44,30,8,0,3,25,37,38,1,0,3,35,39,18,1,0,4,18,18,1,1,3,5,30,0,12,0,6,9,21,1,2,7,4,6,11,20,25,2,7,4,6,12,22,35,2,7,4,6,14,20,9,2,7,4,6,29,32,5,2,7,4,6,30,0,14,2,7,4,6,35,22,23,2,7,4,7,36,18,1,1,8,21,13,21,15,21,16,23,17,19,16,16,16,22,16,19,13,17,13,19,15,17,15,17,16,20,15,16,13,16,15,14,33,18,15,12,8,22,13,13,8,14,40,1,7,8,8,0,4,6,8,5,7,8,0,13,13,3,6,8,5,7,8,0,13,2,6,8,0,8,4,1,3,2,6,8,0,3,1,10,8,4,1,8,4,1,1,2,7,8,0,8,4,3,7,8,0,8,4,8,4,1,8,6,2,8,4,3,1,11,7,2,9,0,9,1,2,3,10,8,4,2,13,13,1,8,0,1,9,0,2,13,7,11,7,2,13,13,2,6,11,7,2,9,0,9,1,9,0,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,9,1,2,8,4,6,8,1,1,6,9,1,1,6,8,1,3,8,4,6,11,7,2,13,13,13,1,6,8,4,1,13,2,8,4,13,6,8,4,8,4,3,8,4,10,8,4,7,8,1,1,6,11,7,2,9,0,9,1,1,8,2,7,8,4,8,4,8,4,8,4,3,7,10,8,4,7,8,1,1,7,9,1,10,8,4,8,4,8,4,6,8,4,3,3,3,8,4,7,10,8,4,7,8,1,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,1,8,3,8,66,105,110,100,85,115,101,114,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,10,85,110,98,105,110,100,85,115,101,114,18,85,115,101,114,65,100,100,114,101,115,115,67,97,116,97,108,111,103,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,97,100,100,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,97,105,110,95,105,100,95,116,111,95,103,114,111,117,112,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,17,100,111,108,97,95,117,115,101,114,95,97,100,100,114,101,115,115,12,100,111,108,97,95,117,115,101,114,95,105,100,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,18,103,101,116,95,117,115,101,114,95,97,100,100,114,101,115,115,101,115,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,16,112,114,111,99,101,115,115,95,103,114,111,117,112,95,105,100,22,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,115,121,115,116,101,109,95,112,111,114,116,97,108,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,24,117,110,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,115,101,114,95,97,100,100,114,101,115,115,95,99,97,116,97,108,111,103,23,117,115,101,114,95,97,100,100,114,101,115,115,95,116,111,95,117,115,101,114,95,105,100,20,117,115,101,114,95,105,100,95,116,111,95,97,100,100,114,101,115,115,101,115,12,117,115,101,114,95,109,97,110,97,103,101,114,6,118,101,99,116,111,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,3,24,8,6,45,8,1,13,11,7,2,13,13,1,2,2,46,11,7,2,8,4,3,47,11,7,2,3,10,8,4,2,2,2,16,8,4,17,3,3,2,2,16,8,4,17,3,0,0,0,0,1,12,10,0,17,15,10,0,56,0,10,0,56,1,18,1,11,0,56,2,18,0,56,3,2,1,1,0,0,19,21,11,1,15,0,12,5,10,5,10,2,12,4,46,11,4,56,4,32,4,12,5,16,11,5,1,7,3,39,11,5,11,2,11,3,56,5,2,2,1,0,0,19,20,11,1,15,0,12,4,10,4,10,2,12,3,46,11,3,56,4,4,11,5,15,11,4,1,7,4,39,11,4,11,2,56,6,1,2,3,1,0,0,24,23,10,0,11,1,17,5,12,2,11,0,16,1,12,3,10,3,16,2,10,2,56,7,4,13,5,17,11,3,1,7,1,39,11,3,16,2,11,2,56,8,20,2,4,1,0,0,26,19,11,0,16,1,12,2,10,2,16,3,10,1,56,9,4,9,5,13,11,2,1,7,1,39,11,2,16,3,11,1,56,10,20,2,5,1,0,0,27,24,14,1,17,10,12,4,11,0,16,0,12,3,10,3,10,4,56,4,4,18,11,1,11,3,11,4,56,11,20,17,11,12,2,5,22,11,3,1,11,1,12,2,11,2,2,6,1,0,0,8,10,10,0,11,1,17,5,12,2,11,0,16,1,16,2,11,2,56,7,2,7,3,0,0,31,50,10,0,11,1,12,2,46,11,2,17,5,12,5,11,0,15,1,12,7,10,7,15,2,10,5,12,3,46,11,3,56,7,32,4,20,5,24,11,7,1,7,0,39,10,7,16,3,56,12,6,1,0,0,0,0,0,0,0,22,12,4,64,8,0,0,0,0,0,0,0,0,12,6,10,7,15,2,10,5,10,4,56,13,13,6,10,5,68,8,11,7,15,3,10,4,11,6,56,14,11,5,11,4,18,2,56,15,2,8,3,0,0,34,49,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,11,2,12,4,46,11,4,17,5,12,6,11,0,15,1,12,9,10,9,15,2,10,6,12,5,46,11,5,56,7,32,4,27,5,31,11,9,1,7,0,39,10,9,15,3,10,7,56,16,12,8,11,9,15,2,10,6,10,7,56,13,11,8,10,6,68,8,11,6,11,7,18,2,56,15,2,9,3,0,0,36,73,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,10,2,12,4,46,11,4,17,3,12,9,10,7,10,9,33,4,19,5,23,11,0,1,7,5,39,10,0,11,2,12,5,46,11,5,17,5,12,10,11,0,15,1,12,12,10,12,15,3,11,9,56,16,12,11,10,11,46,65,8,6,2,0,0,0,0,0,0,0,38,4,45,5,51,11,12,1,11,11,1,7,2,39,10,11,14,10,12,6,46,11,6,56,17,12,8,1,11,12,15,2,10,10,56,18,1,11,11,11,8,56,19,1,11,10,11,7,18,3,56,20,2,0,2,0,1,1,0,1,1,0,28,0,37,0,38,0,50,0],"wormhole_adapter_core":[161,28,235,11,6,0,0,0,12,1,0,46,2,46,114,3,160,1,212,1,4,244,2,22,5,138,3,146,3,7,156,6,196,10,8,224,16,96,6,192,17,30,10,222,17,68,12,162,18,236,4,13,142,23,6,15,148,23,6,0,90,0,27,0,36,0,46,0,62,0,63,0,87,0,91,1,29,1,30,1,44,1,59,1,60,1,81,1,85,1,86,1,89,2,28,2,40,2,45,2,66,2,80,2,88,0,4,12,0,0,15,3,0,0,5,3,0,0,16,3,0,0,6,3,0,0,17,3,0,0,7,3,0,1,0,12,0,2,8,7,0,3,11,0,0,5,14,12,0,6,23,12,0,7,22,12,0,8,2,8,0,9,3,12,1,0,1,11,21,4,0,12,13,12,2,7,1,12,1,13,18,2,0,15,20,2,0,16,25,7,2,1,0,0,0,17,1,7,0,18,9,12,0,19,10,7,0,20,12,0,0,21,19,12,0,22,24,0,0,0,53,0,1,0,0,71,2,1,0,0,35,3,1,0,0,75,4,1,0,0,76,4,1,0,0,73,4,1,0,0,74,4,1,0,0,68,5,6,0,0,67,7,8,0,0,69,5,6,0,0,79,9,10,0,1,47,45,46,0,4,33,24,48,0,4,34,24,44,0,4,42,33,24,0,4,43,54,24,0,4,48,1,32,0,4,49,1,32,0,4,50,1,32,0,4,51,1,32,0,5,26,49,50,0,5,78,49,50,0,6,55,51,23,0,6,70,52,1,0,7,61,42,43,0,10,39,21,1,1,3,11,58,12,13,0,12,58,12,17,2,7,12,14,65,21,1,1,12,16,32,22,23,2,1,0,16,41,1,19,2,1,0,16,54,27,1,2,1,0,16,77,29,30,2,1,0,17,58,24,25,0,18,58,14,15,0,19,58,25,26,0,19,84,26,24,0,20,64,34,35,0,20,66,36,10,0,22,83,43,24,0,27,16,30,18,28,20,29,18,31,18,25,28,32,18,25,37,25,38,25,39,25,40,3,6,8,9,7,8,24,7,8,18,0,4,6,8,9,7,8,0,13,10,2,3,6,8,9,7,8,0,13,7,6,8,9,7,8,24,7,8,0,13,15,11,14,1,8,17,6,8,13,6,7,8,24,7,8,0,6,8,7,10,2,6,8,13,7,8,18,2,8,8,10,2,8,7,8,24,7,8,0,6,8,7,10,2,7,8,10,7,8,11,6,8,13,7,8,18,4,8,8,8,8,15,10,2,11,7,8,24,7,8,0,6,8,7,7,8,10,8,8,8,8,13,3,15,11,14,1,8,17,6,8,13,1,3,3,7,8,24,7,8,18,8,15,1,7,8,18,1,8,15,2,6,8,24,7,8,18,1,8,21,2,8,20,8,12,1,11,16,2,9,0,9,1,2,13,8,22,1,11,19,2,9,0,9,1,1,8,0,1,9,0,2,6,11,19,2,9,0,9,1,6,9,0,1,1,1,10,2,1,8,20,1,8,22,3,7,11,19,2,9,0,9,1,9,0,9,1,1,8,1,2,7,11,19,2,9,0,9,1,6,9,0,2,9,0,9,1,2,8,23,10,2,1,2,3,13,15,2,3,7,8,21,14,10,2,1,8,23,4,7,8,24,11,14,1,8,17,8,23,6,8,13,1,8,3,1,8,5,1,8,4,1,8,6,3,13,10,2,8,8,6,7,8,24,6,11,19,2,13,8,22,7,11,16,2,8,20,8,12,10,2,6,8,13,7,8,18,1,8,25,4,8,8,13,2,10,2,1,6,8,7,1,13,7,8,8,15,3,13,10,2,8,8,8,8,6,8,8,8,8,3,13,2,10,2,4,7,8,10,8,8,13,15,2,15,15,2,6,8,11,8,8,2,7,8,11,8,8,3,15,8,23,10,2,5,13,3,8,8,8,8,3,6,65,112,112,67,97,112,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,12,68,101,108,101,116,101,66,114,105,100,103,101,11,68,101,108,101,116,101,79,119,110,101,114,13,68,101,108,101,116,101,83,112,101,110,100,101,114,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,14,82,101,103,105,115,116,101,114,66,114,105,100,103,101,13,82,101,103,105,115,116,101,114,79,119,110,101,114,15,82,101,103,105,115,116,101,114,83,112,101,110,100,101,114,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,86,65,65,6,86,101,99,77,97,112,13,97,100,100,95,108,105,113,117,105,100,105,116,121,11,97,112,112,95,109,97,110,97,103,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,8,99,111,110,116,97,105,110,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,20,100,101,108,101,116,101,95,114,101,109,111,116,101,95,98,114,105,100,103,101,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,13,100,111,108,97,95,99,111,110,116,114,97,99,116,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,21,103,101,116,95,100,101,108,101,116,101,95,111,119,110,101,114,95,116,121,112,101,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,23,103,101,116,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,6,105,110,115,101,114,116,12,105,115,95,100,111,108,97,95,117,115,101,114,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,10,112,111,111,108,95,99,111,100,101,99,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,22,114,101,103,105,115,116,101,114,95,114,101,109,111,116,101,95,98,114,105,100,103,101,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,19,114,101,109,111,116,101,95,100,101,108,101,116,101,95,111,119,110,101,114,21,114,101,109,111,116,101,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,21,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,23,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,5,115,116,97,116,101,3,115,117,105,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,3,118,97,97,7,118,101,99,95,109,97,112,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,24,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,22,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,99,104,97,105,110,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,4,52,8,15,92,8,21,31,11,16,2,8,20,8,12,72,11,19,2,13,8,22,1,2,2,94,13,93,10,2,2,2,2,94,13,93,10,2,3,2,2,37,13,38,15,4,2,2,37,13,38,15,5,2,2,37,13,38,15,6,2,2,37,13,38,15,0,1,0,0,11,18,10,2,17,26,12,5,11,1,10,2,12,4,12,3,11,5,11,3,46,11,4,17,34,11,2,56,0,56,1,18,0,56,2,2,1,1,0,0,1,23,10,1,16,0,14,2,56,3,32,4,7,5,11,11,1,1,7,1,39,11,1,15,0,10,2,10,3,17,33,17,35,56,4,11,2,11,3,18,1,56,5,2,2,1,0,0,26,22,10,1,16,0,14,2,56,3,4,6,5,10,11,1,1,7,0,39,11,1,15,0,14,2,56,6,12,3,1,11,2,11,3,17,36,18,1,56,5,2,3,1,0,0,31,22,10,3,10,4,17,18,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,3,56,7,2,4,1,0,0,31,22,10,3,10,4,17,19,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,5,56,8,2,5,1,0,0,31,22,10,3,10,4,17,16,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,4,56,9,2,6,1,0,0,31,22,10,3,10,4,17,17,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,6,56,10,2,7,3,0,0,41,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,24,17,39,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,8,3,0,0,47,59,11,0,10,1,16,0,11,1,15,2,11,3,11,6,11,7,17,24,17,39,17,12,12,12,1,12,11,12,10,12,14,12,13,10,2,17,11,11,11,33,4,23,5,31,11,5,1,11,4,1,11,2,1,7,2,39,11,4,10,13,11,2,17,11,11,10,77,17,20,1,12,9,10,5,10,14,12,8,46,11,8,17,22,32,4,52,11,5,10,14,17,23,5,54,11,5,1,11,13,11,14,11,9,11,12,2,9,3,0,0,41,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,24,17,39,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,10,3,0,0,53,28,11,3,10,4,11,2,17,11,11,8,17,21,1,12,11,11,6,11,7,11,4,11,5,11,11,52,17,15,12,13,11,1,15,1,73,0,0,0,0,11,13,17,37,12,12,11,0,11,9,11,12,11,10,17,38,2,0,3,0,1,0,2,0,56,0,57,0,82,0],"wormhole_adapter_pool":[161,28,235,11,6,0,0,0,11,1,0,42,2,42,92,3,134,1,142,1,4,148,2,16,5,164,2,185,2,7,221,4,156,6,8,249,10,96,6,217,11,50,10,139,12,51,12,190,12,168,2,13,230,14,10,0,70,0,29,0,30,0,37,0,51,0,71,1,23,1,24,1,35,1,47,1,48,1,63,1,65,1,66,1,68,2,21,2,33,2,36,2,53,2,62,2,67,0,10,8,0,0,11,8,0,0,12,3,0,1,3,7,0,2,9,12,1,0,1,3,6,8,0,5,17,12,0,6,1,8,0,7,2,12,1,0,1,9,16,4,0,10,8,12,2,7,1,12,1,11,13,2,0,13,15,2,0,14,19,7,2,1,0,0,0,15,0,7,0,16,4,12,0,17,5,7,0,18,7,0,0,19,14,12,0,20,18,0,0,0,41,0,1,0,0,42,2,1,0,0,57,3,1,1,0,0,58,4,1,0,0,54,5,1,1,0,1,38,36,16,0,1,39,36,37,0,2,28,24,16,1,0,2,58,29,16,0,2,69,35,1,1,0,3,22,31,1,0,4,27,16,34,0,5,49,32,33,0,8,32,10,1,1,3,9,45,0,6,0,10,45,0,21,2,7,12,12,60,10,1,1,8,13,59,7,8,0,14,34,1,15,2,1,0,14,43,19,1,2,1,0,15,45,16,17,0,16,45,12,13,0,17,45,17,18,0,18,52,25,26,0,18,53,27,28,0,20,64,33,16,0,16,9,18,14,19,14,15,20,16,22,7,10,9,10,13,38,1,7,8,12,0,5,7,8,0,13,10,2,7,8,18,7,8,12,9,7,8,1,7,8,18,11,8,1,8,11,7,11,4,1,9,0,11,8,1,9,0,13,10,2,6,8,7,7,8,12,7,7,8,1,7,8,18,11,8,1,8,11,13,10,2,6,8,7,7,8,12,7,6,8,5,7,8,18,7,8,1,7,11,4,1,9,0,10,2,6,8,7,7,8,12,1,8,9,1,6,8,12,1,5,1,8,0,1,9,0,3,7,8,12,11,13,2,13,8,16,8,15,2,6,8,18,7,8,12,1,8,15,2,13,8,16,1,11,13,2,9,0,9,1,1,10,2,1,8,14,1,8,16,3,7,11,13,2,9,0,9,1,9,0,9,1,2,8,14,8,6,1,11,10,2,9,0,9,1,1,8,1,2,8,17,10,2,5,7,11,4,1,9,0,11,8,1,9,0,13,10,2,7,8,12,3,7,8,15,14,10,2,1,8,17,4,7,8,18,11,8,1,8,11,8,17,6,8,7,1,3,3,13,10,2,7,8,12,5,3,3,8,3,8,3,13,1,6,8,5,6,7,8,18,6,11,13,2,13,8,16,7,11,10,2,8,14,8,6,10,2,6,8,7,7,8,12,1,8,19,6,13,3,8,3,8,3,3,2,5,7,11,4,1,9,0,8,3,3,8,3,7,8,12,1,6,8,3,1,13,1,8,2,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,4,80,111,111,108,11,80,111,111,108,71,101,110,101,115,105,115,9,80,111,111,108,83,116,97,116,101,17,80,111,111,108,87,105,116,104,100,114,97,119,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,6,97,109,111,117,110,116,7,98,121,116,101,115,51,50,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,7,99,114,101,97,116,111,114,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,12,100,115,116,95,99,104,97,105,110,95,105,100,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,4,105,110,105,116,10,105,110,105,116,105,97,108,105,122,101,6,105,110,115,101,114,116,7,105,115,95,105,110,105,116,3,110,101,119,5,110,111,110,99,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,12,112,111,111,108,95,97,100,100,114,101,115,115,10,112,111,111,108,95,99,111,100,101,99,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,12,115,101,110,100,95,100,101,112,111,115,105,116,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,3,115,117,105,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,40,8,9,26,5,44,1,1,2,4,40,8,9,72,8,15,25,11,10,2,8,14,8,6,56,11,13,2,13,8,16,2,2,6,46,3,61,13,31,13,50,10,2,55,10,2,20,3,0,0,0,0,1,9,10,0,17,14,11,0,46,17,17,9,18,0,56,0,2,1,1,4,0,11,59,10,0,16,0,20,10,4,46,17,17,33,4,9,5,17,11,3,1,11,0,1,11,4,1,7,2,39,10,0,16,1,20,32,4,23,5,31,11,3,1,11,0,1,11,4,1,7,3,39,11,3,10,4,12,5,46,11,5,17,21,12,7,56,1,12,6,13,6,11,1,11,2,17,20,17,22,56,2,10,4,17,14,11,7,11,4,56,3,11,6,18,1,56,4,8,11,0,15,1,21,2,2,3,0,0,23,20,11,3,11,4,11,5,11,6,11,8,56,5,12,10,11,0,15,2,73,0,0,0,0,11,10,17,23,12,9,11,1,11,2,11,9,11,7,17,24,1,2,3,3,0,0,23,18,11,3,11,4,11,6,17,8,12,8,11,0,15,2,73,0,0,0,0,11,8,17,23,12,7,11,1,11,2,11,7,11,5,17,24,1,2,4,1,4,0,30,37,11,0,17,10,11,1,10,2,16,3,11,2,15,4,11,4,11,5,10,6,17,12,17,25,17,11,1,12,7,12,10,12,9,12,8,12,11,11,3,10,10,10,7,10,9,11,6,56,6,11,8,11,11,14,9,17,6,14,9,17,5,14,10,17,5,11,7,18,2,56,7,2,0,1,0,2,1,1,1,3,1,2,0],"wormhole_adapter_verify":[161,28,235,11,6,0,0,0,10,1,0,22,2,22,54,3,76,102,4,178,1,16,5,194,1,206,1,7,144,3,135,3,8,151,6,128,1,6,151,7,30,10,181,7,6,12,187,7,205,1,0,38,1,29,2,14,2,27,2,28,2,35,2,37,3,13,3,19,3,34,3,36,0,8,12,0,1,4,7,1,0,0,2,1,8,0,3,7,4,0,4,3,12,2,7,1,12,1,5,6,2,0,6,10,7,2,1,0,0,0,7,0,7,0,8,2,7,0,9,5,12,0,10,9,0,0,0,22,0,1,0,0,12,2,3,0,0,30,4,5,0,0,32,6,3,0,0,31,7,5,0,1,20,19,13,1,0,1,24,18,10,1,0,1,26,3,14,1,0,1,33,13,14,1,0,3,25,25,26,0,4,11,27,3,2,7,12,4,15,24,10,2,7,12,6,15,9,10,2,1,0,6,21,9,11,2,1,0,10,16,16,22,0,10,17,16,12,0,10,18,16,17,0,10,30,21,5,0,12,8,13,8,8,12,7,12,6,12,5,12,11,23,10,23,2,6,11,6,2,13,8,8,6,13,1,11,1,1,8,8,2,6,11,6,2,13,8,8,6,8,10,0,4,7,8,9,6,11,6,2,13,8,8,10,2,6,8,2,1,8,10,3,7,11,4,2,8,7,8,0,6,8,10,7,8,5,6,7,8,9,6,11,6,2,13,8,8,7,11,4,2,8,7,8,0,10,2,6,8,2,7,8,5,2,13,8,8,2,6,11,6,2,9,0,9,1,6,9,0,1,1,1,6,9,1,1,8,8,1,9,0,1,11,1,1,9,0,2,11,1,1,8,8,13,1,6,8,10,1,13,1,6,11,1,1,9,0,1,7,11,1,1,9,0,3,10,2,6,8,2,8,10,3,6,8,9,10,2,6,8,2,1,8,7,2,8,7,8,0,2,6,11,4,2,9,0,9,1,9,0,1,7,8,5,1,8,3,3,7,11,4,2,9,0,9,1,9,0,9,1,7,66,121,116,101,115,51,50,5,67,108,111,99,107,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,3,97,100,100,20,97,115,115,101,114,116,95,107,110,111,119,110,95,101,109,105,116,116,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,6,100,105,103,101,115,116,15,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,13,101,109,105,116,116,101,114,95,99,104,97,105,110,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,101,120,116,114,97,99,116,3,103,101,116,22,103,101,116,95,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,2,105,100,7,105,115,95,115,111,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,14,114,101,112,108,97,121,95,112,114,111,116,101,99,116,4,115,111,109,101,5,115,116,97,116,101,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,1,23,8,3,0,1,0,0,1,19,10,0,10,1,56,0,4,11,11,0,11,1,56,1,20,56,2,12,2,5,17,11,1,1,11,0,1,56,3,12,2,11,2,2,1,1,0,0,15,25,10,1,17,16,12,3,11,0,14,3,17,0,12,2,14,2,56,4,4,11,5,15,11,1,1,7,0,39,13,2,56,5,11,1,17,15,33,4,22,5,24,7,1,39,2,2,1,0,0,20,15,11,0,11,2,11,3,12,5,12,4,46,11,4,11,5,17,17,12,6,11,1,14,6,17,1,11,6,2,3,1,0,0,22,26,10,0,10,1,17,14,12,3,46,11,3,56,6,32,4,10,5,18,11,1,1,11,2,1,11,0,1,7,2,39,11,0,11,1,17,14,11,2,17,9,18,0,56,7,2,4,1,0,0,5,12,11,0,11,1,11,3,11,4,17,2,12,6,11,2,14,6,11,5,17,3,11,6,2,0]},"type_origin_table":[{"module_name":"dola_address","struct_name":"DolaAddress","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"Pool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"DepositPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"WithdrawPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_verify","struct_name":"Unit","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceManagerCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version_1_0_0","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"app_manager","struct_name":"TotalAppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"app_manager","struct_name":"AppCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"UserInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ReserveData","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ScaledBalance","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"BorrowRateFactors","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"PriceOracle","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"Price","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"Liquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AddLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"RemoveLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_logic","struct_name":"LendingCoreExecuteEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserAddressCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"BindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UnbindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"CoreState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"LendingCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_wormhole_adapter","struct_name":"SystemCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolWithdrawEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":1},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":5},"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302":{"upgraded_id":"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302","upgraded_version":1},"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a":{"upgraded_id":"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a","upgraded_version":1}}}},"owner":"Immutable","previous_transaction":"BPLPMMmGBp3vAM6v31MEKfQLcUzKmgin9gBefQsnbg4m","storage_rebate":548454000},{"data":{"Move":{"type_":{"Other":{"address":"0000000000000000000000000000000000000000000000000000000000000002","module":"dynamic_field","name":"Field","type_args":[{"struct":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"genesis","name":"Version","type_args":[]}},{"struct":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"genesis","name":"Version_1_0_0","type_args":[]}}]}},"has_public_transfer":false,"version":3478819,"contents":[137,141,210,76,196,132,118,167,162,255,54,55,42,68,63,239,165,53,69,176,22,254,179,23,187,9,30,96,224,107,46,76,0,0]}},"owner":{"ObjectOwner":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621"},"previous_transaction":"McsTGPLu3V5rpv6CyPNv6rG5f4NAZMuVbWfadUqPjR2","storage_rebate":2150800},{"data":{"Package":{"id":"0xc5b2a5049cd71586362d0c6a38e34cfaae7ea9ce6d5401a350506a15f817bf72","version":2,"module_map":{"app_manager":[161,28,235,11,6,0,0,0,10,1,0,10,2,10,24,3,34,46,4,80,2,5,82,54,7,136,1,228,1,8,236,2,64,10,172,3,18,12,190,3,106,13,168,4,4,0,8,0,11,1,16,1,20,1,21,0,3,12,0,0,0,12,0,1,1,0,0,2,2,7,0,2,5,4,0,4,4,2,0,0,14,0,1,0,0,17,2,3,0,0,18,4,3,0,0,12,5,6,0,0,10,3,1,0,2,9,7,1,0,2,15,0,7,0,2,22,12,8,0,3,19,10,1,1,8,8,9,1,7,8,5,0,2,7,8,0,7,8,5,1,8,1,3,6,8,2,7,8,0,7,8,5,1,6,8,1,1,13,1,8,4,1,8,3,1,8,0,1,9,0,3,8,1,8,3,8,4,1,6,8,4,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,2,73,68,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,97,112,112,95,99,97,112,115,6,97,112,112,95,105,100,11,97,112,112,95,109,97,110,97,103,101,114,6,100,101,108,101,116,101,15,100,101,115,116,114,111,121,95,97,112,112,95,99,97,112,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,2,105,100,4,105,110,105,116,3,110,101,119,6,111,98,106,101,99,116,12,114,101,103,105,115,116,101,114,95,97,112,112,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,8,4,6,10,8,3,1,2,2,13,8,4,7,13,0,0,0,0,1,6,11,0,17,6,64,8,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,11,19,11,1,17,6,12,4,14,4,17,7,12,3,11,4,10,0,16,0,65,8,75,18,1,12,2,11,0,15,0,11,3,68,8,11,2,2,2,1,0,0,1,4,11,1,11,2,17,1,2,3,1,0,0,1,4,11,0,16,1,20,2,4,1,0,0,1,5,11,0,19,1,1,17,5,2,0,1,1,1,0],"dola_address":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,12,3,24,109,4,133,1,6,5,139,1,78,7,217,1,191,3,8,152,5,96,6,248,5,14,10,134,6,8,12,142,6,151,2,13,165,8,4,0,13,0,23,1,4,1,27,2,3,2,5,0,0,7,0,2,1,7,0,3,2,7,0,0,20,0,1,0,0,19,2,1,0,0,18,2,3,0,0,29,4,5,0,0,28,6,5,0,0,10,7,5,0,0,6,8,5,0,0,7,5,8,0,0,9,0,5,1,0,0,8,5,3,0,0,15,5,3,0,0,11,3,5,0,1,12,19,1,0,1,24,14,0,0,1,25,15,0,0,1,30,17,18,1,1,2,21,13,3,0,3,17,0,12,1,0,3,22,12,13,0,4,16,3,8,0,5,26,9,3,1,0,20,8,17,11,15,10,0,1,13,1,6,8,0,1,10,2,2,8,0,13,1,8,0,2,8,0,10,2,2,13,10,2,1,5,1,6,9,0,1,2,1,9,0,1,8,2,1,8,1,2,7,10,2,13,2,7,10,2,10,2,6,10,2,3,10,2,13,3,3,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,11,68,111,108,97,65,100,100,114,101,115,115,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,112,111,111,108,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,19,117,112,100,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,13,2,0,0,0,2,2,14,13,13,10,2,0,1,0,0,0,2,7,1,2,1,1,0,0,0,4,11,0,16,0,20,2,2,1,0,0,0,4,11,0,16,1,20,2,3,1,0,0,0,6,11,1,13,0,15,0,21,11,0,2,4,1,0,0,0,6,11,1,13,0,15,1,21,11,0,2,5,1,0,0,0,4,11,0,11,1,18,0,2,6,1,0,0,0,5,7,1,14,0,56,0,18,0,2,7,1,0,0,0,14,14,0,16,1,65,10,6,32,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,14,0,16,1,20,17,19,2,8,1,0,0,3,8,56,1,17,18,17,16,12,0,7,1,11,0,18,0,2,9,1,0,0,0,4,14,0,16,1,20,2,10,1,0,0,3,14,64,10,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,17,13,13,1,14,0,16,1,20,17,14,11,1,2,11,1,0,0,16,30,14,0,65,10,12,6,6,0,0,0,0,0,0,0,0,12,5,6,2,0,0,0,0,0,0,0,12,2,14,0,10,5,10,5,10,2,22,56,2,12,1,14,1,17,12,12,4,11,5,11,2,22,12,5,14,0,11,5,11,6,56,2,12,3,11,4,11,3,18,0,2,0,0,0,1,0],"dola_pool":[161,28,235,11,6,0,0,0,14,1,0,22,2,22,52,3,74,173,1,4,247,1,32,5,151,2,211,1,7,234,3,168,5,8,146,9,96,6,242,9,50,10,164,10,34,11,198,10,2,12,200,10,222,2,13,166,13,4,14,170,13,4,15,174,13,4,0,23,0,22,0,45,1,12,1,54,2,13,2,14,2,27,2,43,2,52,2,53,0,5,12,1,0,1,0,3,3,0,0,10,3,0,1,4,7,0,3,6,7,0,4,8,7,0,5,0,4,1,0,1,6,1,12,1,0,1,6,2,12,1,0,1,8,9,4,0,10,7,2,0,0,30,0,1,1,0,0,19,2,3,1,0,0,16,4,5,0,0,42,6,5,1,0,0,55,6,5,1,0,0,21,7,8,1,0,0,57,9,3,1,0,0,48,10,8,0,1,15,19,21,0,1,17,21,19,0,1,18,3,21,1,0,1,32,30,8,0,1,33,30,29,0,1,34,3,29,0,2,25,22,8,0,2,26,35,8,0,3,37,26,8,0,4,29,3,25,1,0,4,38,25,26,0,5,39,24,5,1,0,5,51,31,15,1,0,5,59,3,15,1,0,6,28,32,23,1,0,6,31,12,1,1,0,6,36,23,15,1,0,6,56,20,5,1,0,7,24,11,3,1,3,8,41,13,14,0,9,46,34,3,1,12,9,50,11,3,1,8,10,49,18,19,0,23,11,21,11,29,16,0,11,25,11,3,11,10,11,24,11,19,11,17,11,26,27,4,11,20,11,22,11,26,33,28,23,1,6,11,0,1,9,0,1,2,2,6,11,8,1,9,0,7,8,10,0,3,3,2,2,1,3,2,6,11,0,1,9,0,3,5,7,11,0,1,9,0,11,7,1,9,0,13,10,2,7,8,10,1,10,2,5,7,11,0,1,9,0,8,3,3,8,3,7,8,10,3,13,10,2,7,8,10,1,9,0,1,6,11,8,1,9,0,1,7,8,10,1,8,9,1,11,6,1,9,0,1,11,0,1,9,0,6,3,3,3,10,2,5,8,3,1,6,8,10,1,5,1,6,11,7,1,9,0,1,8,3,5,8,3,8,3,3,13,10,2,1,11,7,1,9,0,2,7,11,6,1,9,0,11,6,1,9,0,1,8,5,1,8,4,1,8,1,3,3,11,7,1,9,0,5,1,13,1,6,8,3,2,7,11,6,1,9,0,3,2,11,6,1,9,0,7,8,10,1,8,2,2,9,0,5,3,8,3,13,10,2,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,11,68,101,112,111,115,105,116,80,111,111,108,11,68,111,108,97,65,100,100,114,101,115,115,4,80,111,111,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,12,87,105,116,104,100,114,97,119,80,111,111,108,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,11,99,114,101,97,116,101,95,112,111,111,108,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,4,101,109,105,116,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,12,103,101,116,95,100,101,99,105,109,97,108,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,12,105,110,116,111,95,98,97,108,97,110,99,101,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,10,112,111,111,108,95,99,111,100,101,99,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,35,8,9,13,11,6,1,9,0,20,2,1,2,3,44,8,4,49,5,11,3,2,2,3,44,8,4,47,5,11,3,0,11,0,1,0,0,3,4,11,0,55,0,20,2,1,1,0,0,1,10,11,0,56,0,12,2,11,1,17,27,56,1,11,2,57,0,56,2,2,2,1,0,0,3,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,3,1,0,0,1,8,11,0,56,3,12,2,11,1,11,2,49,8,17,2,2,4,1,0,0,1,8,11,0,56,3,12,2,11,1,49,8,11,2,17,2,2,5,3,0,0,17,38,11,4,46,17,30,12,9,14,1,56,4,12,7,10,0,10,7,12,5,46,11,5,56,5,12,6,10,9,17,8,12,10,56,6,11,10,11,6,11,2,11,3,17,14,12,8,11,0,54,1,11,1,56,7,56,8,1,56,9,17,18,11,9,11,7,18,1,56,10,11,8,2,6,3,0,0,28,53,17,13,14,3,17,12,33,4,6,5,12,11,0,1,11,4,1,7,4,39,14,3,17,11,56,9,17,18,17,16,33,4,20,5,26,11,0,1,11,4,1,7,0,39,11,1,17,9,12,7,10,0,11,2,12,5,46,11,5,56,11,12,2,11,0,54,1,10,2,56,12,11,4,56,13,12,6,56,9,17,18,10,7,11,2,18,2,56,14,11,6,11,7,56,15,2,7,3,0,0,3,8,11,2,46,17,30,17,8,11,0,11,1,17,15,2,0,2,0,1,0,11,1,11,0,40,0,58,0],"equilibrium_fee":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,50,5,54,29,7,83,174,1,8,129,2,32,12,161,2,197,5,0,4,0,10,0,2,0,1,0,0,3,2,1,0,0,0,3,1,0,0,1,3,1,0,1,5,0,1,0,1,6,4,1,0,1,7,0,1,0,1,8,4,1,0,1,9,1,1,0,1,11,0,1,0,2,15,15,1,15,3,15,15,15,6,15,15,15,15,15,15,0,4,1,15,15,15,6,1,15,15,15,15,15,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,27,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,112,101,114,99,101,110,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,1,13,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,11,11,1,11,0,17,6,12,2,11,2,2,1,1,0,0,1,17,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,15,11,0,11,1,17,6,11,2,17,6,17,5,17,4,12,3,11,3,2,2,1,0,0,5,93,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,1,10,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,2,23,10,0,10,2,23,10,3,17,1,10,4,36,4,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,10,4,36,4,50,10,1,10,0,10,4,17,9,10,3,17,9,23,17,5,10,4,10,3,17,9,23,17,6,12,7,5,52,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,12,9,10,2,10,9,23,10,5,17,5,10,4,10,3,17,9,23,17,9,24,10,4,10,3,17,9,26,12,8,10,0,11,1,23,11,5,17,7,17,9,24,10,0,11,9,23,11,0,11,2,23,17,6,17,8,17,9,11,4,11,3,17,9,26,11,8,23,2,3,1,0,0,6,51,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,12,7,11,1,10,2,22,11,0,10,2,22,11,3,17,1,11,7,23,12,9,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,4,11,5,17,6,24,12,11,11,2,11,11,17,6,17,5,17,4,12,10,11,9,11,10,17,4,12,8,11,4,11,8,17,9,2,0],"genesis":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,56,3,74,128,1,4,202,1,22,5,224,1,175,1,7,143,3,130,4,8,145,7,96,6,241,7,61,10,174,8,39,12,213,8,147,2,13,232,10,6,15,238,10,2,0,26,1,15,1,44,1,46,2,24,2,38,2,39,2,42,2,43,0,0,0,0,0,2,12,0,0,1,8,0,0,11,7,0,0,12,7,0,0,13,7,0,1,4,7,0,2,6,7,0,5,3,7,0,5,7,4,0,6,8,12,0,6,9,0,0,6,10,0,0,8,5,2,0,0,29,0,1,0,0,17,2,0,0,0,33,3,4,0,0,16,5,6,0,0,18,7,0,0,0,36,8,0,2,6,6,0,19,9,10,0,0,21,10,0,0,0,22,11,0,0,1,34,31,32,0,2,27,0,26,1,0,2,28,30,31,0,3,32,35,36,1,0,3,40,37,23,1,0,4,14,20,0,2,7,4,4,25,13,14,2,7,4,4,40,28,29,2,7,4,5,20,17,0,0,5,31,21,18,1,8,5,37,16,17,0,6,16,24,6,0,6,18,25,0,0,7,41,23,0,1,8,15,12,14,19,18,4,22,22,15,27,16,27,10,29,10,23,14,33,12,18,13,18,0,1,8,5,1,6,8,2,2,8,10,7,8,13,1,8,1,4,6,8,0,7,8,2,2,10,2,1,8,12,2,7,8,2,8,11,3,6,8,0,7,8,2,9,1,1,6,8,1,1,8,0,2,7,8,2,8,1,2,8,3,8,5,2,6,8,9,9,0,1,1,2,8,2,8,1,1,7,8,13,1,8,9,1,8,8,2,8,3,8,4,3,7,8,9,9,0,9,1,1,6,9,0,1,8,2,1,9,0,3,7,8,10,2,10,2,2,7,8,10,8,11,1,8,7,2,8,3,9,0,2,7,8,9,9,0,1,9,1,1,6,8,7,1,8,6,1,10,2,2,8,3,9,1,2,3,8,8,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,7,86,101,114,115,105,111,110,13,86,101,114,115,105,111,110,95,49,95,48,95,48,13,86,101,114,115,105,111,110,95,49,95,48,95,49,3,97,100,100,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,15,100,101,115,116,114,111,121,95,109,97,110,97,103,101,114,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,7,103,101,110,101,115,105,115,3,103,101,116,10,103,101,116,95,109,111,100,117,108,101,17,103,101,116,95,118,101,114,115,105,111,110,95,49,95,48,95,49,13,103,111,118,101,114,110,97,110,99,101,95,118,49,2,105,100,8,105,110,100,101,120,95,111,102,12,105,110,105,116,95,103,101,110,101,115,105,115,10,105,110,116,111,95,98,121,116,101,115,11,109,97,110,97,103,101,114,95,105,100,115,15,109,105,103,114,97,116,101,95,118,101,114,115,105,111,110,3,110,101,119,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,11,117,112,103,114,97,100,101,95,99,97,112,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,10,2,8,7,103,101,110,101,115,105,115,0,2,1,23,1,1,2,1,31,8,9,2,2,3,31,8,9,45,8,10,35,10,8,8,3,2,1,23,1,4,2,1,23,1,5,2,1,23,1,0,1,0,0,0,3,9,18,5,2,1,1,0,0,0,10,11,0,16,0,9,18,3,56,0,4,7,5,9,7,4,39,2,2,3,0,0,15,26,10,1,17,19,11,0,64,18,0,0,0,0,0,0,0,0,18,2,12,2,11,1,17,19,18,1,12,3,13,2,15,0,9,18,3,9,18,4,56,1,13,2,15,1,14,3,56,2,68,18,11,2,56,3,11,3,2,3,1,0,0,0,6,11,1,15,2,11,2,11,3,17,20,2,4,1,0,0,0,5,11,0,15,2,11,1,17,21,2,5,1,0,0,26,47,10,1,15,0,46,9,18,3,56,4,4,8,5,12,11,1,1,7,1,39,10,1,15,0,9,18,3,56,5,1,56,6,12,3,10,3,56,7,34,4,25,5,29,11,1,1,7,2,39,14,3,17,11,17,9,7,5,33,4,36,5,40,11,1,1,7,3,39,11,1,15,0,9,18,3,11,2,56,8,2,6,1,0,0,0,3,9,18,0,2,7,1,0,0,0,4,11,0,19,0,1,2,8,1,0,0,34,18,14,1,56,2,12,3,10,0,16,1,14,3,56,9,12,2,1,11,0,15,1,11,2,56,10,1,11,1,19,1,17,17,2,2,0,2,2,2,1,0,30,0],"governance_v1":[161,28,235,11,6,0,0,0,13,1,0,22,2,22,56,3,78,198,1,4,148,2,40,5,188,2,148,2,7,208,4,155,6,8,235,10,96,6,203,11,207,1,10,154,13,72,11,226,13,2,12,228,13,215,9,13,187,23,28,14,215,23,14,0,43,0,38,1,18,1,57,1,71,1,75,2,33,2,56,2,58,2,69,2,70,0,3,8,0,0,7,8,1,6,0,0,1,3,0,0,0,3,0,1,2,0,0,1,4,12,0,2,8,7,0,3,6,7,1,0,0,4,10,7,0,7,5,7,0,7,11,4,0,8,12,12,0,10,9,2,0,0,47,0,1,0,0,13,2,1,0,0,74,3,4,0,0,15,5,1,0,0,62,5,1,0,0,73,6,1,0,0,22,7,1,0,0,31,8,9,0,0,41,10,11,1,6,0,28,12,1,0,0,25,13,1,1,6,0,76,14,15,1,6,0,20,10,1,1,6,1,24,47,12,0,1,27,12,1,0,1,48,25,4,0,2,68,35,11,0,3,19,46,44,1,0,3,35,27,23,1,0,3,37,26,1,1,0,3,49,46,9,1,0,3,50,46,9,1,0,3,55,1,20,1,0,3,65,23,20,1,0,4,39,1,39,1,0,4,40,40,11,0,5,23,29,9,1,0,5,46,29,31,1,0,5,61,32,23,1,0,6,29,23,1,1,3,7,45,44,21,1,8,7,53,0,19,0,7,72,37,38,0,9,64,23,1,1,8,10,32,18,34,0,10,63,18,17,0,22,4,33,22,19,4,18,4,26,17,27,17,28,17,22,34,23,34,24,23,33,41,29,42,30,41,29,45,20,34,17,34,17,4,23,12,21,34,22,12,1,7,8,12,0,3,8,11,7,8,0,7,8,12,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,1,9,0,7,8,12,1,8,6,1,8,4,3,6,8,0,9,0,7,8,12,5,6,8,0,9,0,7,11,1,1,9,0,1,7,8,12,1,11,7,1,8,4,1,10,5,1,5,1,6,8,12,1,8,10,1,11,7,1,9,0,1,8,9,1,8,0,1,9,0,2,5,1,2,8,11,7,8,12,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,1,10,2,12,8,8,3,11,7,1,3,3,5,8,10,5,11,7,1,3,3,8,10,8,9,3,1,6,8,10,1,6,8,9,1,8,8,1,6,8,8,1,11,1,1,9,0,1,8,2,11,1,6,5,6,5,1,1,7,10,5,3,7,10,5,3,3,5,1,6,9,0,1,8,3,1,6,11,7,1,9,0,1,6,8,5,11,67,104,97,110,103,101,83,116,97,116,101,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,10,97,100,100,95,109,101,109,98,101,114,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,12,99,104,101,99,107,95,109,101,109,98,101,114,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,49,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,103,101,110,101,115,105,115,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,9,109,97,120,95,100,101,108,97,121,7,109,101,109,98,101,114,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,6,114,101,109,111,118,101,13,114,101,109,111,118,101,95,109,101,109,98,101,114,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,7,117,112,103,114,97,100,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,8,45,8,10,42,11,7,1,8,5,14,1,17,3,77,3,51,3,52,10,5,44,10,8,9,1,2,10,45,8,10,26,5,66,3,30,11,7,1,3,34,3,59,8,6,21,9,0,36,10,5,16,10,5,67,2,2,2,1,60,8,9,3,2,2,60,8,9,54,2,1,23,0,0,0,0,16,19,64,17,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,35,68,17,11,0,17,31,56,0,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,11,1,64,21,0,0,0,0,0,0,0,0,18,0,56,1,2,1,1,4,0,24,42,10,1,10,2,46,17,35,12,3,46,11,3,17,6,10,1,16,0,20,32,4,20,10,1,16,1,65,21,6,0,0,0,0,0,0,0,0,33,12,4,5,22,9,12,4,11,4,4,25,5,31,11,1,1,11,2,1,7,5,39,10,1,15,2,11,0,11,2,17,15,56,2,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,2,56,3,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,28,19,10,1,15,3,14,2,12,3,46,11,3,56,4,32,4,10,5,14,11,1,1,7,9,39,11,1,15,3,11,2,68,17,2,4,1,0,0,30,21,10,1,10,2,12,3,46,11,3,17,6,10,1,15,3,14,2,12,4,46,11,4,56,5,12,5,1,11,1,15,3,11,5,56,6,1,2,5,1,0,0,1,24,10,4,10,3,10,2,22,36,4,7,5,11,11,1,1,7,7,39,11,2,10,1,15,4,21,11,3,10,1,15,5,21,11,4,11,1,15,6,21,2,6,1,0,0,1,9,11,0,16,3,14,1,56,4,4,6,5,8,7,8,39,2,7,1,0,0,8,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,8,1,0,0,33,75,11,1,46,17,34,12,7,10,0,55,0,20,7,2,33,4,16,11,0,1,7,16,17,16,12,6,5,73,10,0,55,0,20,7,3,33,4,28,11,0,1,7,17,17,16,12,5,5,71,10,0,55,0,20,7,4,33,4,40,11,0,1,7,18,17,16,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,19,17,16,12,3,5,67,11,0,55,0,20,7,0,33,4,62,7,20,17,16,12,2,5,65,7,21,17,16,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,9,1,0,0,1,3,11,0,17,14,2,10,1,0,0,36,86,10,0,16,0,20,4,5,5,11,11,0,1,11,2,1,7,6,39,10,2,46,17,35,12,9,10,0,10,9,17,6,10,2,46,17,34,10,0,16,4,20,22,12,14,10,0,16,5,20,6,0,0,0,0,0,0,0,0,33,4,35,56,7,12,10,5,42,10,14,10,0,16,5,20,22,56,8,12,10,10,2,46,17,34,11,0,16,6,20,22,12,11,11,2,17,31,12,12,14,12,17,32,20,12,13,11,12,12,8,11,9,12,7,11,14,12,6,11,10,12,5,11,11,12,4,56,9,12,3,11,8,11,7,11,6,11,5,11,4,14,3,17,25,11,1,64,17,0,0,0,0,0,0,0,0,64,17,0,0,0,0,0,0,0,0,7,0,57,0,56,10,11,13,18,2,56,11,2,11,1,0,0,43,213,1,10,4,46,17,34,12,11,10,11,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,4,1,7,11,39,10,11,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,4,1,7,14,39,10,2,55,0,20,7,0,33,4,50,7,1,10,2,54,0,21,10,2,46,56,12,7,1,18,3,56,13,10,2,55,0,20,7,1,33,4,57,5,65,11,2,1,11,0,1,11,4,1,7,13,39,11,4,46,17,35,12,15,10,0,10,15,17,6,10,2,54,3,12,12,10,2,54,4,12,10,10,2,55,5,56,14,4,85,8,12,5,5,92,10,11,10,2,55,5,56,15,20,35,12,5,11,5,4,138,1,10,12,14,15,12,6,46,11,6,56,4,32,4,111,10,10,14,15,12,7,46,11,7,56,4,32,12,8,5,113,9,12,8,11,8,4,116,5,126,11,2,1,11,0,1,11,12,1,11,10,1,7,10,39,11,3,4,134,1,11,10,1,10,12,11,15,68,17,5,137,1,11,10,11,15,68,17,5,140,1,11,10,1,10,2,55,5,56,14,4,147,1,8,12,9,5,154,1,11,11,10,2,55,5,56,15,20,38,12,9,11,9,4,205,1,10,0,16,3,65,17,12,14,11,12,46,65,17,12,13,11,14,11,13,17,7,4,184,1,7,2,10,2,54,0,21,11,2,46,56,12,7,2,18,3,56,13,11,0,16,2,56,16,17,13,56,17,2,11,0,1,10,2,55,5,56,18,4,201,1,7,3,10,2,54,0,21,11,2,46,56,12,7,3,18,3,56,13,5,203,1,11,2,1,56,19,2,11,2,1,11,0,1,11,12,1,56,19,2,12,1,4,0,1,45,10,1,46,17,34,10,0,55,1,20,35,4,21,10,0,55,0,20,7,0,33,4,15,5,21,11,0,1,11,1,1,7,12,39,11,1,46,17,35,10,0,55,6,20,33,4,30,5,34,11,0,1,7,15,39,7,4,10,0,54,0,21,11,0,46,56,12,7,4,18,3,56,13,2,0,2,0,7,0,1,0,6,0,3,0,4,0,5,1,9,1,4,1,2,1,7,1,8,1,3,1,1,7,23,8,23,9,23,10,23,11,23,12,23,13,23,0],"governance_v2":[161,28,235,11,6,0,0,0,13,1,0,28,2,28,74,3,102,145,2,4,247,2,58,5,177,3,229,3,7,150,7,131,8,8,153,15,96,6,249,15,129,2,10,250,17,95,11,217,18,2,12,219,18,171,13,13,134,32,38,14,172,32,18,0,54,0,48,0,64,1,22,1,69,1,87,1,93,2,23,2,29,2,41,2,68,2,84,2,85,2,86,0,5,8,0,0,9,8,2,6,0,0,1,0,3,3,0,0,1,3,0,1,4,0,0,1,6,12,0,3,10,7,0,4,8,7,1,0,0,5,13,7,0,7,0,4,1,0,1,8,2,12,1,0,1,10,7,7,0,10,14,4,0,11,11,12,2,7,1,4,1,13,12,2,0,0,59,0,1,0,0,15,2,1,0,0,91,3,4,0,0,18,5,1,0,0,75,5,1,0,0,90,6,1,0,0,89,7,1,0,0,27,8,1,0,0,39,9,10,0,0,51,11,12,2,6,0,0,35,13,1,0,0,32,14,1,2,6,0,0,94,15,16,2,6,0,0,25,17,1,2,6,0,0,28,11,1,2,6,0,1,31,59,13,0,1,34,13,1,0,2,63,40,41,1,0,3,83,37,12,0,4,24,58,52,1,0,4,43,28,26,1,0,4,46,27,1,1,0,4,67,1,22,1,0,4,78,26,22,1,0,5,49,1,23,1,0,5,50,47,12,0,6,30,30,10,1,0,6,58,30,32,1,0,6,74,33,26,1,0,7,61,54,35,1,0,7,79,61,48,1,0,7,92,57,35,1,0,8,36,41,1,1,0,8,47,62,41,1,0,8,60,41,48,1,0,9,37,26,1,1,3,10,57,52,24,1,8,10,65,0,21,0,10,88,45,46,0,11,17,44,1,2,7,4,11,30,55,10,2,7,4,11,65,0,43,2,7,4,11,74,56,39,2,7,4,12,73,64,1,1,12,12,77,26,1,1,8,13,40,20,35,0,13,76,20,19,0,22,4,22,23,44,25,21,23,21,4,20,4,26,19,27,19,28,19,17,39,41,42,39,42,24,26,34,39,44,49,35,50,36,49,35,53,29,39,40,42,42,42,31,39,22,13,32,39,19,4,23,13,30,39,33,39,43,63,1,7,8,14,0,4,6,8,4,7,8,0,8,8,8,5,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,4,6,8,4,7,8,0,3,3,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,2,9,0,9,1,7,8,14,1,8,6,1,8,4,5,6,8,0,9,0,10,11,10,1,9,1,3,7,8,14,7,6,8,0,9,0,7,11,1,2,9,0,9,1,10,11,10,1,9,1,3,1,7,8,14,1,11,7,1,8,4,3,6,8,0,7,11,1,2,9,0,9,1,7,8,14,1,10,5,1,5,1,6,8,14,1,8,12,1,11,7,1,9,0,1,8,8,1,8,11,1,8,0,1,9,0,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,2,9,0,9,1,1,10,2,15,8,8,3,3,3,5,8,12,5,3,3,3,11,13,2,5,3,8,12,8,11,11,10,1,9,1,3,1,9,1,3,10,11,10,1,9,0,3,7,8,14,1,11,10,1,9,0,2,5,3,1,11,13,2,9,0,9,1,3,7,11,13,2,9,0,9,1,9,0,9,1,1,6,8,12,1,6,8,11,1,6,8,8,1,11,9,1,9,0,1,11,1,2,9,0,9,1,1,8,2,17,11,7,1,8,4,11,7,1,8,4,5,5,5,5,1,3,3,7,11,13,2,5,3,3,3,3,7,11,13,2,5,3,11,10,1,9,1,5,3,1,6,9,0,1,8,3,2,7,11,9,1,9,0,11,9,1,9,0,2,6,11,13,2,9,0,9,1,9,0,2,7,11,13,2,9,0,9,1,9,0,1,6,11,9,1,9,0,1,6,11,7,1,9,0,1,6,8,5,11,1,1,1,5,5,7,11,13,2,5,3,3,7,11,13,2,5,3,5,3,3,2,7,11,9,1,9,0,3,2,11,9,1,9,0,7,8,14,1,11,10,1,9,1,2,9,0,5,7,66,97,108,97,110,99,101,11,67,104,97,110,103,101,83,116,97,116,101,4,67,111,105,110,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,3,97,100,100,13,97,100,100,95,103,117,97,114,100,105,97,110,115,11,97,103,97,105,110,115,116,95,110,117,109,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,15,99,104,101,99,107,95,103,117,97,114,100,105,97,110,115,5,99,108,97,105,109,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,9,102,97,118,111,114,95,110,117,109,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,20,103,111,118,101,114,110,97,110,99,101,95,99,111,105,110,95,116,121,112,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,50,9,103,117,97,114,100,105,97,110,115,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,4,106,111,105,110,9,109,97,120,95,100,101,108,97,121,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,24,112,114,111,112,111,115,97,108,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,103,117,97,114,100,105,97,110,115,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,115,112,108,105,116,11,115,116,97,107,101,100,95,99,111,105,110,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,22,117,112,100,97,116,101,95,109,105,110,117,109,117,109,95,115,116,97,107,105,110,103,7,117,112,103,114,97,100,101,5,118,97,108,117,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,22,118,111,116,105,110,103,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,255,255,255,255,255,255,255,255,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,11,57,8,12,53,11,7,1,8,5,52,11,7,1,8,8,55,10,5,16,1,21,3,95,3,62,3,72,3,96,3,56,10,8,11,1,2,13,57,8,12,33,5,81,3,38,3,42,3,70,8,6,26,9,0,80,11,9,1,9,1,44,3,45,11,13,2,5,3,19,3,20,11,13,2,5,3,82,2,2,2,1,71,8,11,3,2,2,71,8,11,66,2,1,36,0,0,0,0,18,22,64,19,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,46,68,19,11,0,17,37,56,0,56,1,64,19,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,6,1,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,64,24,0,0,0,0,0,0,0,0,18,0,56,2,2,1,1,0,0,10,34,10,1,16,0,20,32,4,12,10,1,16,1,65,24,6,0,0,0,0,0,0,0,0,33,12,4,5,14,9,12,4,11,4,4,17,5,21,11,1,1,7,6,39,10,1,15,2,11,2,56,3,10,1,15,3,11,3,56,4,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,3,56,5,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,29,19,10,1,15,4,14,2,12,3,46,11,3,56,6,32,4,10,5,14,11,1,1,7,10,39,11,1,15,4,11,2,68,19,2,4,1,0,0,31,21,10,1,10,2,12,3,46,11,3,17,7,10,1,15,4,14,2,12,4,46,11,4,56,7,12,5,1,11,1,15,4,11,5,56,8,1,2,5,1,0,0,1,9,11,2,10,1,15,5,21,11,3,11,1,15,6,21,2,6,1,0,0,1,33,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,9,11,1,1,7,8,39,10,4,10,3,10,2,22,36,4,16,5,20,11,1,1,7,8,39,11,2,10,1,15,7,21,11,3,10,1,15,8,21,11,4,11,1,15,9,21,2,7,1,0,0,1,9,11,0,16,4,14,1,56,6,4,6,5,8,7,9,39,2,8,1,0,0,9,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,9,1,0,0,34,75,11,1,46,17,45,12,7,10,0,55,0,20,7,3,33,4,16,11,0,1,7,21,17,18,12,6,5,73,10,0,55,0,20,7,4,33,4,28,11,0,1,7,22,17,18,12,5,5,71,10,0,55,0,20,7,5,33,4,40,11,0,1,7,23,17,18,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,24,17,18,12,3,5,67,11,0,55,0,20,7,1,33,4,62,7,25,17,18,12,2,5,65,7,26,17,18,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,10,1,0,0,1,3,11,0,17,16,2,11,1,0,0,38,103,10,0,16,0,20,4,5,5,11,11,0,1,11,4,1,7,7,39,11,2,10,3,10,4,56,9,12,18,10,3,10,0,16,5,20,38,4,23,5,29,11,0,1,11,4,1,7,16,39,10,4,46,17,46,12,11,10,4,46,17,45,12,12,10,12,10,0,16,7,20,22,12,19,10,19,10,0,16,8,20,22,12,13,11,12,11,0,16,9,20,22,12,14,10,4,56,10,12,15,13,15,10,11,10,3,56,11,10,4,17,37,12,16,14,16,17,38,20,12,17,11,16,12,10,11,11,12,9,11,19,12,8,11,13,12,7,11,14,12,6,56,12,12,5,11,10,11,9,11,8,11,7,11,6,14,5,17,25,11,1,11,18,56,13,11,3,11,15,6,0,0,0,0,0,0,0,0,11,4,56,10,7,1,57,0,56,14,11,17,18,2,56,15,2,12,1,0,0,51,175,2,10,6,46,17,45,12,17,10,17,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,6,1,7,12,39,10,17,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,6,1,7,15,39,10,2,55,0,20,7,1,33,4,50,7,2,10,2,54,0,21,10,2,46,56,16,7,2,18,3,56,17,10,2,55,0,20,7,2,33,4,57,5,65,11,2,1,11,0,1,11,6,1,7,14,39,10,6,46,17,46,12,22,10,2,54,3,12,20,10,2,54,4,12,16,11,3,10,4,11,6,56,9,12,21,11,17,10,2,55,5,20,35,4,237,1,11,0,1,10,2,54,6,11,21,56,13,56,18,1,11,5,4,158,1,10,2,55,7,20,10,4,22,10,2,54,7,21,11,4,12,18,10,20,10,22,12,9,46,11,9,56,19,4,119,11,18,10,20,10,22,56,20,22,12,18,10,16,10,22,12,10,46,11,10,56,19,4,151,1,11,16,10,22,56,20,12,14,10,2,55,7,20,10,14,22,10,2,54,7,21,10,2,55,8,20,10,14,23,10,2,54,8,21,11,18,11,14,22,12,18,5,153,1,11,16,1,11,20,11,22,11,18,56,11,5,219,1,10,2,55,8,20,10,4,22,10,2,54,8,21,11,4,12,15,10,16,10,22,12,11,46,11,11,56,19,4,181,1,11,15,10,16,10,22,56,20,22,12,15,10,20,10,22,12,12,46,11,12,56,19,4,213,1,11,20,10,22,56,20,12,19,10,2,55,8,20,10,19,22,10,2,54,8,21,10,2,55,7,20,10,19,23,10,2,54,7,21,11,15,11,19,22,12,15,5,215,1,11,20,1,11,16,11,22,11,15,56,11,10,2,55,7,20,10,2,55,8,20,22,11,2,55,6,56,21,33,4,232,1,5,234,1,7,19,39,56,22,12,8,5,173,2,11,20,1,11,16,1,11,21,56,23,10,2,55,7,20,10,2,55,8,20,22,12,23,10,23,10,2,55,7,20,17,8,4,136,2,11,23,10,0,16,6,20,38,12,13,5,138,2,9,12,13,11,13,4,157,2,7,3,10,2,54,0,21,11,2,46,56,16,7,3,18,3,56,17,11,0,16,3,56,24,17,15,56,25,12,7,5,171,2,11,0,1,7,4,10,2,54,0,21,11,2,46,56,16,7,4,18,3,56,17,56,22,12,7,11,7,12,8,11,8,2,13,1,4,0,19,41,10,2,46,17,45,10,1,55,1,20,35,4,23,10,1,55,0,20,7,1,33,4,15,5,23,11,1,1,11,0,1,11,2,1,7,13,39,11,2,46,17,46,12,3,11,0,11,3,17,7,7,5,10,1,54,0,21,11,1,46,56,16,7,5,18,3,56,17,2,14,1,4,0,60,129,1,10,1,46,17,45,12,8,10,0,55,0,20,7,3,33,4,13,8,12,2,5,19,10,0,55,0,20,7,4,33,12,2,11,2,4,24,8,12,3,5,30,10,0,55,0,20,7,5,33,12,3,11,3,4,35,8,12,4,5,41,11,8,10,0,55,1,20,38,12,4,11,4,4,44,5,50,11,0,1,11,1,1,7,20,39,10,1,46,17,46,12,10,10,0,54,3,12,9,10,0,54,4,12,7,10,9,10,10,12,5,46,11,5,56,19,4,90,11,7,1,11,9,10,10,56,20,12,12,10,0,54,6,10,12,56,26,11,1,56,27,11,10,56,28,10,0,55,7,20,11,12,23,11,0,54,7,21,5,128,1,11,9,1,10,7,10,10,12,6,46,11,6,56,19,4,100,5,108,11,0,1,11,1,1,11,7,1,7,11,39,11,7,10,10,56,20,12,11,10,0,54,6,10,11,56,26,11,1,56,27,11,10,56,28,10,0,55,8,20,11,11,23,11,0,54,8,21,2,0,4,0,10,0,2,0,1,0,3,0,8,0,9,0,5,0,6,0,7,1,12,1,4,1,2,1,9,1,11,1,3,1,7,1,8,1,10,10,36,11,36,12,36,13,36,14,36,15,36,16,36,17,36,18,36,0],"lending_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,126,4,136,1,2,5,138,1,175,1,7,185,2,166,4,8,223,6,32,6,255,6,41,12,168,7,192,10,0,22,0,9,0,23,1,0,7,0,0,20,0,1,0,0,21,0,1,0,0,16,0,1,0,0,19,0,1,0,0,18,0,1,0,0,15,0,1,0,0,17,0,1,0,0,10,2,3,0,0,1,3,2,0,0,14,4,3,0,0,5,3,4,0,0,12,5,3,0,0,3,3,6,0,0,13,7,3,0,0,4,3,7,0,1,2,3,11,0,1,11,11,3,0,2,6,17,18,0,2,7,17,19,0,2,8,17,1,0,2,24,9,0,0,2,25,10,0,0,2,26,13,0,0,2,27,12,0,0,2,28,15,16,1,1,24,1,0,1,2,4,13,3,8,0,2,1,10,2,6,13,3,3,8,0,8,0,2,4,13,3,8,0,3,5,13,3,8,0,3,2,2,10,13,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,11,10,2,10,2,10,2,10,2,3,3,2,3,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,3,10,2,10,2,10,2,16,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,2,3,8,0,13,13,8,0,13,13,10,2,10,2,10,2,10,2,10,2,3,3,2,3,3,13,8,0,13,3,3,10,2,3,10,10,2,10,2,10,2,3,13,10,13,13,3,2,13,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,101,110,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,101,110,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,8,24,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,22,11,4,2,8,1,0,0,14,92,6,0,0,0,0,0,0,0,0,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,1,14,1,17,17,12,11,11,6,11,5,22,12,6,6,8,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,2,14,2,17,18,12,8,11,6,11,5,22,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,3,14,3,17,17,12,9,11,6,11,5,22,12,6,11,9,52,12,5,14,0,10,6,10,6,10,5,22,56,0,17,15,12,10,11,6,11,5,22,12,6,6,1,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,4,14,4,17,19,12,7,11,6,11,5,22,14,0,65,1,33,4,85,5,87,7,0,39,11,11,11,8,11,10,11,7,2,9,1,0,0,20,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,20,13,6,11,1,17,21,13,6,11,2,17,21,11,3,17,16,12,7,13,6,14,7,65,1,75,17,20,13,6,11,7,17,23,11,4,17,16,12,8,13,6,14,8,65,1,75,17,20,13,6,11,8,17,23,13,6,11,5,17,22,11,6,2,10,1,0,0,21,141,1,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,18,12,11,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,18,12,7,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,15,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,19,12,10,11,9,11,8,22,14,0,65,1,33,4,132,1,5,134,1,7,0,39,11,16,11,11,11,7,11,12,11,15,11,10,2,11,1,0,0,8,27,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,21,13,4,7,6,17,22,11,4,2,12,1,0,0,22,118,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,1,14,1,17,17,12,11,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,2,14,2,17,18,12,10,11,7,11,6,22,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,3,14,3,17,17,12,13,11,7,11,6,22,12,7,11,13,52,12,6,14,0,10,7,10,7,10,6,22,56,0,17,15,12,12,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,4,14,4,17,18,12,9,11,7,11,6,22,12,7,6,1,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,5,14,5,17,19,12,8,11,7,11,6,22,12,7,10,8,7,6,33,4,102,5,104,7,1,39,11,7,14,0,65,1,33,4,110,5,112,7,0,39,11,11,11,10,11,12,11,9,11,8,2,13,1,0,0,23,32,64,1,0,0,0,0,0,0,0,0,12,3,14,0,65,18,12,4,13,3,10,4,75,17,20,6,0,0,0,0,0,0,0,0,12,2,10,2,10,4,35,4,27,5,16,13,3,14,0,10,2,66,18,20,17,20,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,13,3,11,1,17,22,11,3,2,14,1,0,0,24,76,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,1,14,1,17,17,12,10,11,8,11,4,22,12,8,72,0,0,12,7,64,18,0,0,0,0,0,0,0,0,12,6,10,7,10,10,35,4,51,5,27,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,2,14,2,17,17,12,5,13,6,11,5,68,18,11,8,11,4,22,12,8,11,7,72,1,0,22,12,7,5,22,6,1,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,3,14,3,17,19,12,9,11,8,11,4,22,14,0,65,1,33,4,71,5,73,7,0,39,11,6,11,9,2,0],"lending_core_storage":[161,28,235,11,6,0,0,0,12,1,0,20,2,20,52,3,72,245,2,4,189,3,40,5,229,3,172,2,7,145,6,149,16,8,166,22,96,6,134,23,20,10,154,23,101,12,255,23,239,16,13,238,40,62,15,172,41,6,0,77,0,17,0,43,0,91,1,122,2,31,2,87,2,109,2,112,2,115,0,6,8,0,0,11,4,0,0,4,4,0,0,5,4,0,0,1,4,0,1,0,12,0,1,8,12,0,2,3,0,0,5,2,8,0,6,10,4,0,7,7,12,2,7,1,4,1,9,9,2,0,0,72,0,1,0,0,93,2,1,0,0,104,3,1,0,0,102,3,1,0,0,106,4,1,0,0,105,4,1,0,0,99,4,1,0,0,103,4,1,0,0,100,4,1,0,0,101,5,1,0,0,45,6,7,0,0,61,8,9,0,0,73,10,11,0,0,30,10,11,0,0,58,6,12,0,0,42,13,11,0,0,41,10,11,0,0,65,13,9,0,0,63,13,9,0,0,66,13,14,0,0,64,13,14,0,0,67,13,14,0,0,69,15,9,0,0,68,15,9,0,0,60,10,12,0,0,52,10,9,0,0,62,10,9,0,0,59,10,9,0,0,57,10,9,0,0,46,10,9,0,0,50,10,9,0,0,53,10,9,0,0,56,10,9,0,0,51,10,9,0,0,55,10,9,0,0,54,10,9,0,0,48,10,9,0,0,47,10,9,0,0,49,10,16,0,0,44,6,17,0,0,85,18,1,0,0,29,18,1,0,0,84,18,1,0,0,28,18,1,0,0,14,15,1,0,0,96,15,1,0,0,13,15,1,0,0,95,15,1,0,0,15,15,1,0,0,97,15,1,0,0,119,19,1,0,0,117,20,1,0,0,118,21,1,0,0,116,22,1,0,0,40,23,1,0,1,45,17,7,0,1,92,0,26,0,3,90,1,9,0,4,34,46,11,1,0,4,71,46,48,1,0,4,94,49,31,1,0,5,110,8,12,0,6,86,24,25,0,7,12,34,1,2,7,4,7,20,32,39,2,7,4,7,23,36,37,2,7,4,7,34,32,11,2,7,4,7,81,40,12,2,7,4,7,86,24,28,2,7,4,7,94,36,44,2,7,4,8,107,31,1,1,8,68,27,68,29,70,30,66,27,68,33,63,27,65,27,64,27,67,27,66,29,64,29,66,33,64,33,69,33,63,33,65,29,58,7,59,7,60,7,63,29,3,6,8,7,7,8,6,7,8,11,0,17,6,8,7,7,8,0,6,8,8,13,1,1,3,15,15,15,15,15,15,15,15,15,7,8,11,4,6,8,7,7,8,0,13,1,4,6,8,7,7,8,0,13,15,7,6,8,7,7,8,0,13,15,15,15,15,1,7,8,0,1,13,1,6,8,8,1,15,2,7,8,0,13,1,1,1,3,2,7,8,0,3,1,10,13,3,7,8,0,3,13,4,15,15,15,15,1,6,8,5,4,7,8,0,13,3,15,4,7,8,0,6,8,8,3,15,3,7,8,0,13,15,6,7,8,0,13,15,15,15,15,4,7,8,0,13,15,15,3,7,8,0,6,8,8,3,1,7,8,11,1,8,9,1,8,5,2,13,8,2,1,11,10,2,9,0,9,1,2,3,8,1,1,8,0,1,9,0,2,6,11,10,2,9,0,9,1,9,0,2,3,15,3,7,11,10,2,9,0,9,1,9,0,9,1,1,7,8,2,2,7,11,10,2,9,0,9,1,9,0,1,7,9,1,1,7,8,4,1,6,9,1,1,6,11,10,2,9,0,9,1,2,15,6,8,2,1,6,8,4,2,15,7,8,3,1,9,1,1,7,8,1,2,6,10,9,0,6,9,0,2,3,7,8,1,2,1,3,2,7,10,9,0,3,2,3,7,8,2,6,65,112,112,67,97,112,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,11,82,101,115,101,114,118,101,68,97,116,97,13,83,99,97,108,101,100,66,97,108,97,110,99,101,7,83,116,111,114,97,103,101,5,84,97,98,108,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,85,115,101,114,73,110,102,111,3,97,100,100,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,17,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,16,98,97,115,101,95,98,111,114,114,111,119,95,114,97,116,101,6,98,111,114,114,111,119,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,18,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,49,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,50,23,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,5,99,108,111,99,107,22,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,11,99,111,108,108,97,116,101,114,97,108,115,8,99,111,110,116,97,105,110,115,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,23,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,22,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,13,100,116,111,107,101,110,95,115,99,97,108,101,100,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,10,103,101,116,95,97,112,112,95,105,100,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,18,103,101,116,95,114,101,115,101,114,118,101,95,108,101,110,103,116,104,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,13,103,101,116,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,2,105,100,8,105,110,100,101,120,95,111,102,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,12,105,115,111,108,97,116,101,95,100,101,98,116,19,108,97,115,116,95,97,118,101,114,97,103,101,95,117,112,100,97,116,101,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,13,108,105,113,117,105,100,95,97,115,115,101,116,115,5,108,111,97,110,115,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,13,111,116,111,107,101,110,95,115,99,97,108,101,100,3,114,97,121,8,114,97,121,95,109,97,116,104,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,20,114,101,103,105,115,116,101,114,95,110,101,119,95,114,101,115,101,114,118,101,6,114,101,109,111,118,101,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,8,114,101,115,101,114,118,101,115,22,115,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,22,115,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,23,115,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,27,115,101,116,95,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,26,115,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,21,115,101,116,95,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,22,115,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,8,116,114,101,97,115,117,114,121,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,10,117,115,101,114,95,105,110,102,111,115,10,117,115,101,114,95,115,116,97,116,101,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,70,8,9,16,8,5,98,11,10,2,13,8,2,120,11,10,2,3,8,1,1,2,5,18,15,75,15,82,10,13,33,10,13,83,10,13,2,2,17,73,1,27,1,74,15,76,15,113,3,114,15,108,15,21,15,36,15,38,15,35,15,37,15,32,15,22,15,24,8,4,89,8,3,39,8,3,3,2,2,121,11,10,2,3,15,111,15,4,2,4,19,15,25,15,26,15,88,15,0,1,0,0,1,13,10,2,17,62,11,0,11,1,10,2,17,56,10,2,56,0,11,2,56,1,18,0,56,2,2,1,1,0,0,1,49,10,1,16,0,10,3,56,3,32,4,7,5,15,11,1,1,11,16,1,11,2,1,7,0,39,11,1,15,0,11,3,11,4,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,2,17,11,11,6,11,7,11,8,11,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,57,17,57,11,10,11,11,11,12,11,13,11,14,11,15,18,4,10,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,11,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,18,2,56,5,2,2,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,1,21,2,3,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,2,21,2,4,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,3,21,2,5,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,4,21,2,6,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,5,21,2,7,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,6,21,2,8,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,7,21,2,9,1,0,0,38,23,11,1,15,0,11,2,56,6,15,8,12,7,11,3,10,7,15,9,21,11,4,10,7,15,10,21,11,5,10,7,15,11,21,11,6,11,7,15,12,21,2,10,1,0,0,1,4,11,0,16,13,17,55,2,11,1,0,0,1,6,11,0,17,61,6,232,3,0,0,0,0,0,0,26,77,2,12,1,0,0,1,7,11,0,16,0,11,1,56,7,16,1,20,2,13,1,0,0,1,7,11,0,16,0,11,1,56,7,16,2,20,2,14,1,0,0,1,4,11,0,16,0,56,8,2,15,1,0,0,12,8,11,0,15,14,11,1,12,2,46,11,2,56,9,2,16,1,0,0,7,8,11,0,15,0,11,1,12,2,46,11,2,56,3,2,17,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,15,20,2,18,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,16,20,2,19,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,17,20,2,20,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,18,20,2,21,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,19,20,2,22,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,20,16,21,10,1,56,11,4,19,11,4,16,20,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,23,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,22,16,21,10,1,56,11,4,19,11,4,16,22,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,24,1,0,0,1,7,11,0,16,0,11,1,56,7,16,23,20,2,25,1,0,0,1,7,11,0,16,0,11,1,56,7,16,24,20,2,26,1,0,0,1,7,11,0,16,0,11,1,56,7,16,3,20,2,27,1,0,0,1,7,11,0,16,0,11,1,56,7,16,4,20,2,28,1,0,0,1,7,11,0,16,0,11,1,56,7,16,5,20,2,29,1,0,0,1,7,11,0,16,0,11,1,56,7,16,7,20,2,30,1,0,0,1,7,11,0,16,0,11,1,56,7,16,6,20,2,31,1,0,0,1,7,11,0,16,0,11,1,56,7,16,25,20,2,32,1,0,0,1,8,11,0,16,0,11,1,56,7,16,20,16,26,20,2,33,1,0,0,1,8,11,0,16,0,11,1,56,7,16,22,16,26,20,2,34,1,0,0,1,7,11,0,16,0,11,1,56,7,16,27,20,2,35,1,0,0,1,7,11,0,16,0,11,1,56,7,16,28,20,2,36,1,0,0,1,7,11,0,16,0,11,1,56,7,16,29,20,2,37,1,0,0,1,7,11,0,16,0,11,1,56,7,16,30,20,2,38,1,0,0,42,19,11,0,16,0,11,1,56,7,16,8,12,2,10,2,16,9,20,10,2,16,10,20,10,2,16,11,20,11,2,16,12,20,2,39,3,0,0,1,3,11,0,16,13,2,40,3,0,0,43,35,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,41,3,0,0,43,44,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,42,3,0,0,43,35,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,43,3,0,0,43,44,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,44,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,17,14,2,56,16,32,4,16,11,3,15,17,11,2,68,7,5,18,11,3,1,2,45,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,17,14,2,56,17,12,3,4,17,11,4,15,17,11,3,56,18,1,5,19,11,4,1,2,46,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,18,14,2,56,16,32,4,16,11,3,15,18,11,2,68,7,5,18,11,3,1,2,47,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,18,14,2,56,17,12,3,4,17,11,4,15,18,11,3,56,18,1,5,19,11,4,1,2,48,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,19,14,2,56,16,32,4,16,11,3,15,19,11,2,68,7,5,18,11,3,1,2,49,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,19,14,2,56,17,12,3,4,17,11,4,15,19,11,3,56,18,1,5,19,11,4,1,2,50,3,0,0,45,15,11,0,15,14,11,2,56,15,12,4,11,1,17,11,10,4,15,15,21,11,3,11,4,15,16,21,2,51,3,0,0,35,10,11,0,15,0,11,1,56,6,12,3,11,2,11,3,15,24,21,2,52,3,0,0,50,30,10,0,15,0,10,1,56,6,12,7,11,2,10,7,15,30,21,11,3,10,7,15,28,21,11,4,11,7,15,25,21,10,0,16,0,10,1,56,7,16,23,20,12,6,11,0,11,1,11,6,11,5,17,40,2,53,3,0,0,35,14,11,0,15,0,11,1,56,6,12,4,11,2,10,4,15,29,21,11,3,11,4,15,27,21,2,54,1,0,0,12,26,10,0,15,14,10,2,12,3,46,11,3,56,9,32,4,21,11,0,15,14,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,1,17,11,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,18,1,56,19,5,25,11,0,1,11,1,1,2,0,2,2,0,2,1,2,5,2,6,2,7,2,12,2,13,2,14,4,0,4,1,4,2,4,3,0,1,0,3,1,1,1,0,1,2,1,3,1,4,2,15,3,0,2,16,2,4,2,2,2,3,3,1,2,9,2,11,2,8,2,10,0,78,0,79,0,80,0],"lending_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,36,2,36,68,3,104,198,1,4,174,2,8,5,182,2,233,3,7,159,6,228,8,8,131,15,128,1,6,131,16,30,10,161,16,36,12,197,16,230,11,0,58,0,17,0,30,0,42,0,56,0,57,0,59,0,64,0,65,0,80,0,82,1,63,2,23,2,24,2,35,2,77,2,79,3,76,0,6,3,0,0,10,3,0,1,0,12,0,2,4,7,0,3,5,8,0,5,13,8,0,7,9,8,0,8,8,12,0,9,15,12,0,10,3,12,0,11,7,7,1,0,0,12,1,8,0,13,2,12,1,0,1,15,11,2,0,16,14,2,0,17,12,12,0,0,78,0,1,0,0,81,2,1,0,0,19,2,1,0,0,70,0,1,0,0,60,0,1,0,0,18,0,1,0,0,21,0,1,0,2,47,17,14,0,2,48,17,10,0,3,22,4,1,0,4,25,14,15,0,4,26,14,35,0,4,27,14,38,0,4,28,14,23,0,4,44,1,16,0,4,45,1,16,0,4,46,1,16,0,4,52,1,16,0,4,53,1,16,0,4,54,1,16,0,5,43,5,6,0,6,18,39,1,0,6,21,39,1,0,6,36,13,1,0,6,37,36,1,0,6,38,13,1,0,6,39,13,1,0,6,40,13,30,0,8,41,24,25,0,8,50,9,10,0,8,51,9,30,0,9,49,11,12,0,10,66,7,8,0,10,67,21,22,0,10,68,21,22,0,10,71,31,12,0,11,29,29,19,1,0,11,55,27,28,1,0,14,34,19,1,1,3,38,18,37,26,36,26,38,32,10,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,10,2,6,8,11,7,8,14,0,11,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,11,12,1,8,13,10,2,6,8,11,7,8,14,17,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,10,2,2,13,3,3,8,3,8,3,13,8,3,1,6,8,4,1,7,8,5,1,6,8,2,8,7,8,15,7,8,9,6,8,2,10,2,7,8,7,7,8,8,6,8,11,7,8,14,4,8,3,8,3,15,10,2,2,7,8,7,8,3,1,13,2,6,8,8,8,3,1,3,7,6,8,7,7,8,5,7,8,6,6,8,11,3,13,15,1,10,2,4,13,3,8,3,2,1,2,1,6,8,3,1,8,0,1,9,0,27,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,6,7,8,15,7,8,9,6,8,2,10,2,6,8,11,7,8,14,2,8,3,10,2,6,13,3,3,8,3,8,3,2,3,7,8,7,13,13,1,11,10,1,8,3,1,8,3,1,6,11,10,1,9,0,1,1,1,11,10,1,9,0,1,15,11,7,8,15,7,8,9,6,8,2,7,8,7,8,3,8,3,13,3,15,11,12,1,8,13,6,8,11,1,8,1,26,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,26,7,8,5,7,8,6,6,8,11,3,3,13,13,8,3,7,8,5,7,8,6,6,8,11,3,13,15,10,2,2,15,13,8,3,8,3,3,3,3,13,13,8,3,5,13,3,8,3,3,2,8,6,8,7,7,8,5,7,8,6,6,8,11,3,3,13,13,14,8,3,7,8,5,7,8,6,6,8,11,3,13,10,2,2,6,13,10,13,3,3,3,8,3,2,10,13,2,6,6,8,7,7,8,5,7,8,6,6,8,11,3,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,76,101,110,100,105,110,103,67,111,114,101,69,118,101,110,116,6,79,112,116,105,111,110,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,6,98,111,114,114,111,119,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,112,111,111,108,95,105,100,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,9,108,105,113,117,105,100,97,116,101,17,108,105,113,117,105,100,97,116,101,95,117,115,101,114,95,105,100,5,110,111,110,99,101,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,5,114,101,112,97,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,14,115,101,110,100,101,114,95,117,115,101,114,95,105,100,8,115,101,113,117,101,110,99,101,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,18,115,111,117,114,99,101,95,99,104,97,105,110,95,110,111,110,99,101,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,9,62,3,72,3,74,13,32,13,31,13,69,10,2,16,15,61,3,20,2,1,2,5,73,3,74,13,75,3,33,8,3,20,2,0,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,26,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,18,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,1,1,4,0,20,168,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,26,12,37,11,26,17,13,12,27,12,35,12,34,12,24,12,33,12,36,10,27,17,19,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,24,77,12,25,10,1,11,34,17,29,12,28,11,2,11,37,12,16,46,11,16,17,31,12,29,14,35,17,8,12,30,10,1,10,28,11,30,17,28,12,31,14,31,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,31,56,2,12,32,10,1,10,6,11,5,10,9,10,29,10,28,11,25,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,27,12,23,10,1,10,32,17,30,10,23,38,4,113,5,125,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,32,10,35,10,36,10,33,10,23,11,7,11,9,17,35,12,11,11,32,12,12,10,36,12,13,10,33,12,14,10,27,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,33,11,29,11,36,14,35,17,8,11,28,14,35,17,7,11,23,6,0,0,0,0,0,0,0,0,11,27,18,0,56,0,2,2,1,4,0,33,167,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,25,12,36,11,25,17,13,12,26,12,34,12,33,12,23,12,32,12,35,10,26,17,15,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,23,77,12,24,10,1,11,33,17,29,12,27,11,2,11,36,12,16,46,11,16,17,31,12,28,14,34,17,8,12,29,10,1,10,27,11,29,17,28,12,30,14,30,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,30,56,2,12,31,10,1,10,6,11,5,10,9,10,28,10,27,10,24,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,23,10,1,10,31,17,30,10,24,38,4,112,5,124,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,31,10,34,10,35,10,32,10,24,11,7,11,9,17,35,12,11,11,31,12,12,10,35,12,13,10,32,12,14,10,26,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,32,11,28,11,35,14,34,17,8,11,27,14,34,17,7,11,24,6,0,0,0,0,0,0,0,0,11,26,18,0,56,0,2,3,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,25,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,17,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,4,1,4,0,34,97,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,24,12,26,12,29,12,28,11,24,17,11,12,25,12,30,12,35,12,32,12,33,11,2,10,29,12,17,46,11,17,17,31,12,31,10,1,11,28,17,29,12,27,10,1,11,35,17,29,12,34,10,1,10,6,10,5,10,8,10,31,10,27,10,26,12,23,12,22,12,21,12,20,12,19,12,18,46,11,18,11,19,11,20,11,21,11,22,11,23,17,26,11,1,11,6,11,5,11,8,10,31,10,30,10,34,11,27,12,16,12,15,12,14,12,13,12,12,12,11,12,10,46,11,10,11,11,11,12,11,13,11,14,11,15,11,16,17,24,11,32,11,31,11,33,14,29,17,8,11,34,14,29,17,7,11,26,11,30,11,25,18,0,56,0,2,5,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,14,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,21,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,6,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,16,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,22,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,0],"lending_logic":[161,28,235,11,6,0,0,0,11,1,0,27,2,27,24,3,51,189,4,4,240,4,4,5,244,4,199,3,7,187,8,241,18,8,172,27,96,6,140,28,144,2,10,156,30,15,12,171,30,196,36,15,239,66,4,0,93,0,48,0,90,0,91,0,104,0,106,0,108,0,111,0,117,1,135,1,2,35,2,40,2,95,0,2,3,0,1,1,0,0,3,5,8,0,4,4,8,0,5,3,12,0,10,0,8,0,0,42,0,1,0,0,44,2,1,0,0,45,2,3,0,0,41,2,1,0,0,43,2,1,0,0,11,4,1,0,0,31,4,1,0,0,34,5,1,0,0,103,6,7,0,0,102,8,7,0,0,83,9,7,0,0,85,10,7,0,0,88,11,7,0,0,84,11,7,0,0,89,11,7,0,0,87,12,7,0,0,33,13,1,0,0,81,12,7,0,0,82,10,7,0,0,128,1,10,3,0,0,126,14,3,0,0,125,11,3,0,0,132,1,14,3,0,0,131,1,11,3,0,0,127,10,3,0,0,129,1,10,3,0,0,133,1,10,3,0,0,134,1,10,3,0,0,28,15,3,0,0,19,15,3,0,0,24,10,3,0,0,25,16,3,0,0,27,17,18,0,0,18,19,20,0,0,119,9,3,0,0,118,9,3,0,0,37,12,1,0,0,99,21,1,0,0,15,21,1,0,0,97,21,1,0,0,13,21,1,0,0,6,8,1,0,0,113,8,1,0,0,120,22,1,0,0,123,23,1,0,0,121,24,1,0,2,51,1,27,0,2,55,1,27,0,2,56,1,27,0,2,61,1,27,0,2,65,1,27,0,2,69,1,27,0,2,80,1,27,0,3,7,11,1,0,3,8,11,1,0,3,9,11,1,0,3,14,53,1,0,3,16,53,1,0,3,30,9,7,0,3,39,30,1,0,3,46,9,7,0,3,47,12,7,0,3,49,61,31,0,3,52,9,3,0,3,53,9,3,0,3,54,9,3,0,3,57,9,3,0,3,58,9,3,0,3,59,9,3,0,3,60,9,3,0,3,62,9,3,0,3,63,9,3,0,3,64,9,3,0,3,66,9,3,0,3,67,9,3,0,3,68,9,26,0,3,70,57,3,0,3,72,9,3,0,3,73,12,3,0,3,74,12,37,0,3,75,12,3,0,3,76,12,37,0,3,77,12,37,0,3,78,11,3,0,3,79,11,3,0,3,86,9,7,0,3,98,53,1,0,3,100,53,1,0,3,114,11,1,0,3,115,11,1,0,3,116,11,1,0,3,121,63,1,0,3,122,6,1,0,3,123,60,1,0,3,124,58,1,0,4,32,32,1,0,4,71,47,48,0,5,50,62,3,0,6,20,20,3,0,6,21,6,3,0,6,22,33,3,0,6,23,33,3,0,6,26,63,3,0,7,96,18,3,0,7,109,1,3,0,7,110,18,3,0,7,112,18,3,0,8,12,18,3,0,8,17,18,3,0,8,101,18,3,0,9,36,39,7,1,0,11,38,29,1,1,3,12,107,49,26,0,111,28,110,31,8,6,8,4,7,8,2,7,8,3,6,8,5,3,3,13,13,0,7,6,8,4,7,8,2,7,8,3,6,8,5,3,13,15,1,15,6,6,8,4,7,8,2,7,8,3,6,8,5,3,13,7,6,8,1,6,8,4,7,8,2,6,8,5,13,3,15,3,7,8,2,13,15,1,1,3,7,8,2,3,15,2,7,8,2,13,3,7,8,2,7,8,3,3,3,7,8,2,3,13,2,7,8,2,3,4,7,8,3,7,8,2,3,6,8,5,4,7,8,2,7,8,3,3,13,3,7,8,3,13,15,4,7,8,2,7,8,3,3,3,6,7,8,2,7,8,3,3,3,13,13,2,15,15,7,7,8,3,13,15,13,15,15,15,4,15,15,15,15,4,7,8,2,3,13,15,4,7,8,2,7,8,3,6,8,5,3,3,7,8,2,6,8,5,13,4,6,8,4,7,8,2,13,15,12,1,15,15,15,15,15,15,15,15,3,15,15,1,3,1,2,1,8,0,1,9,0,3,7,8,2,6,8,5,3,1,13,3,7,8,3,10,13,6,8,5,3,15,15,15,5,15,15,15,15,3,3,1,15,15,5,1,15,6,13,15,10,13,1,10,13,2,1,10,13,2,6,10,9,0,6,9,0,3,1,13,10,13,2,10,13,10,13,7,6,13,15,15,10,13,3,3,15,7,15,3,3,6,13,15,10,13,15,6,6,13,15,10,13,3,3,15,6,3,3,6,13,15,10,13,15,2,2,15,2,7,8,3,13,3,15,2,3,2,3,2,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,6,15,15,15,15,15,15,6,15,3,3,6,13,10,13,3,4,7,8,2,13,3,15,3,6,13,15,10,13,5,15,6,13,15,15,10,13,7,15,15,15,15,15,15,15,1,6,8,5,4,7,8,2,6,8,5,3,15,9,15,15,15,15,15,15,15,15,15,6,7,8,2,13,15,15,15,15,1,7,8,2,3,6,8,4,13,13,4,7,8,2,13,15,15,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,23,76,101,110,100,105,110,103,67,111,114,101,69,120,101,99,117,116,101,69,118,101,110,116,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,16,97,100,100,95,105,115,111,108,97,116,101,95,100,101,98,116,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,6,97,109,111,117,110,116,13,97,115,95,99,111,108,108,97,116,101,114,97,108,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,100,116,111,107,101,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,111,116,111,107,101,110,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,115,99,97,108,101,100,28,99,97,108,99,117,108,97,116,101,95,97,99,116,117,97,108,95,108,105,113,117,105,100,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,35,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,98,97,115,101,95,100,105,115,99,111,117,110,116,30,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,100,105,115,99,111,117,110,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,25,99,97,108,99,117,108,97,116,101,95,109,97,120,95,108,105,113,117,105,100,97,116,105,111,110,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,9,99,97,108,108,95,116,121,112,101,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,22,99,104,101,99,107,95,117,115,101,114,95,102,114,101,115,104,95,112,114,105,99,101,19,99,108,97,105,109,95,102,114,111,109,95,116,114,101,97,115,117,114,121,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,13,99,111,118,101,114,95,100,101,102,105,99,105,116,4,101,109,105,116,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,13,103,101,116,95,116,105,109,101,115,116,97,109,112,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,14,104,97,115,95,99,111,108,108,97,116,101,114,97,108,11,104,97,115,95,100,101,102,105,99,105,116,19,105,115,95,98,111,114,114,111,119,97,98,108,101,95,97,115,115,101,116,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,17,105,115,95,105,115,111,108,97,116,105,111,110,95,109,111,100,101,15,105,115,95,108,105,113,117,105,100,95,97,115,115,101,116,7,105,115,95,108,111,97,110,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,109,97,116,104,3,109,105,110,11,109,105,110,116,95,100,116,111,107,101,110,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,111,116,111,107,101,110,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,24,110,111,116,95,114,101,97,99,104,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,24,110,111,116,95,114,101,97,99,104,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,6,111,114,97,99,108,101,7,112,111,111,108,95,105,100,12,112,111,111,108,95,109,97,110,97,103,101,114,3,112,111,119,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,19,114,101,100,117,99,101,95,105,115,111,108,97,116,101,95,100,101,98,116,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,19,116,111,116,97,108,95,100,116,111,107,101,110,95,115,117,112,112,108,121,19,116,111,116,97,108,95,111,116,111,107,101,110,95,115,117,112,112,108,121,24,117,112,100,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,7,117,115,101,114,95,105,100,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,27,117,115,101,114,95,116,111,116,97,108,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,21,117,115,101,114,95,116,111,116,97,108,95,108,111,97,110,95,118,97,108,117,101,6,118,101,99,116,111,114,11,118,105,111,108,97,116,111,114,95,105,100,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,15,32,0,0,0,200,165,25,144,185,165,111,165,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,34,76,160,196,199,203,249,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,0,2,5,130,1,3,10,15,105,13,136,1,3,29,2,0,3,0,0,25,233,1,10,1,10,5,10,6,17,13,4,6,5,16,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,5,10,7,17,14,4,22,5,32,11,1,1,11,0,1,11,2,1,11,3,1,7,8,39,10,1,10,4,10,7,17,13,4,38,5,48,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,3,10,7,17,44,10,1,10,3,10,6,17,44,10,1,10,2,10,3,10,4,17,43,10,2,10,1,10,5,10,3,17,16,10,1,10,2,10,5,17,11,32,4,73,5,83,11,1,1,11,0,1,11,2,1,11,3,1,7,6,39,10,1,10,2,10,4,10,5,10,6,10,7,17,32,12,15,12,14,10,1,10,6,17,77,12,18,10,1,10,4,10,7,17,21,12,16,10,2,10,6,11,14,10,7,11,15,11,16,11,18,17,33,12,19,12,11,12,10,12,9,10,1,10,6,17,75,12,17,10,1,10,5,10,7,10,10,17,40,10,1,10,5,10,6,10,9,17,38,10,1,10,4,10,7,11,10,17,38,10,1,11,17,10,6,11,19,17,37,10,1,10,2,10,5,17,18,4,145,1,10,1,10,5,17,36,10,1,10,4,10,6,17,14,4,184,1,10,1,10,4,10,6,17,23,12,13,10,13,10,11,17,103,12,12,10,1,10,4,10,6,11,12,17,40,10,11,10,13,36,4,183,1,10,1,10,4,10,6,17,90,10,1,10,4,10,6,11,11,11,13,23,17,37,10,1,10,4,10,6,17,54,5,210,1,10,1,10,4,10,6,11,11,17,37,10,1,10,4,10,6,17,13,32,4,202,1,10,1,10,4,10,6,17,12,32,12,8,5,204,1,9,12,8,11,8,4,210,1,10,1,10,4,10,6,17,54,10,0,10,1,10,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,0,10,1,11,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,5,17,43,11,4,11,9,11,6,11,5,17,49,18,0,56,0,2,1,3,0,0,7,128,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,4,10,5,17,14,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,18,39,10,1,10,5,10,6,17,8,4,42,5,52,11,1,1,11,0,1,11,2,1,11,3,1,7,19,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,10,6,17,37,10,1,10,4,10,5,17,13,32,4,74,10,1,10,4,10,5,17,12,32,12,7,5,76,9,12,7,11,7,4,110,10,1,10,4,17,15,4,87,10,1,10,4,10,5,17,54,5,110,10,1,10,4,17,17,32,4,97,10,1,10,4,10,5,17,53,5,110,10,1,10,5,17,85,4,106,10,1,10,4,10,5,17,54,5,110,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,51,18,0,56,0,2,2,3,0,0,18,95,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,21,12,8,11,6,10,8,17,103,12,7,10,1,10,4,10,5,10,7,17,38,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,48,5,58,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,10,7,11,8,33,4,76,10,1,10,4,10,5,17,13,4,72,10,1,10,4,10,5,17,88,5,76,10,1,10,4,10,5,17,89,11,0,10,1,10,5,10,7,17,45,11,1,11,2,11,3,10,4,17,43,11,4,10,7,11,5,6,0,0,0,0,0,0,0,0,17,52,18,0,56,0,11,7,2,3,3,0,0,1,137,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,5,17,85,32,4,29,5,39,11,1,1,11,0,1,11,2,1,11,3,1,7,13,39,10,1,10,4,17,15,4,78,10,1,10,5,17,58,4,48,5,58,11,1,1,11,0,1,11,2,1,11,3,1,7,12,39,10,1,10,4,10,6,17,9,4,64,5,74,11,1,1,11,0,1,11,2,1,11,3,1,7,11,39,10,1,10,4,10,6,17,41,10,1,10,4,10,5,17,14,32,4,88,10,1,10,4,10,5,17,55,10,1,10,4,10,5,10,6,17,39,10,2,10,1,10,4,10,3,17,16,10,2,10,5,64,31,1,0,0,0,0,0,0,0,10,3,17,95,10,1,10,2,10,4,17,11,4,109,5,119,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,10,6,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,47,18,0,56,0,2,4,3,0,0,33,88,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,23,12,7,10,6,10,7,17,103,12,9,10,1,10,4,10,5,10,9,17,40,10,1,10,4,17,15,4,45,10,1,10,4,10,9,17,42,10,6,10,7,38,4,70,10,1,10,4,10,5,17,90,11,6,11,7,23,12,8,10,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,10,1,10,4,10,5,11,8,17,37,10,1,10,4,10,5,17,54,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,9,11,5,6,0,0,0,0,0,0,0,0,17,50,18,0,56,0,2,5,3,0,0,1,82,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,12,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,14,39,10,1,10,4,17,15,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,15,39,10,1,10,4,17,17,4,56,10,1,10,5,17,85,32,4,46,5,56,11,1,1,11,0,1,11,2,1,11,3,1,7,17,39,10,1,10,4,10,5,17,89,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,46,18,0,56,0,2,6,3,0,0,1,67,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,13,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,4,10,5,17,88,10,1,10,4,10,5,17,54,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,39,5,49,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,48,18,0,56,0,2,7,1,0,0,34,49,10,2,11,3,10,4,17,44,10,2,10,4,17,75,12,11,10,2,10,11,10,4,17,21,12,10,10,2,10,11,10,4,17,23,12,9,10,10,10,9,36,4,27,11,10,11,9,23,12,7,5,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,11,6,17,103,12,8,10,2,11,11,10,4,10,8,17,38,10,2,11,5,10,4,11,8,17,37,11,1,11,2,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,2,8,1,0,0,35,23,10,0,10,1,17,74,12,4,11,0,11,1,17,34,12,5,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,15,8,12,3,5,21,11,5,11,2,22,11,4,35,12,3,11,3,2,9,1,0,0,36,33,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,5,10,0,10,5,20,17,73,12,4,11,0,11,5,20,17,68,12,6,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,8,12,3,5,31,11,6,11,2,22,11,4,35,12,3,11,3,2,10,1,0,0,1,6,11,0,11,1,17,63,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,2,11,1,0,0,1,7,11,0,11,1,11,2,17,19,17,104,36,2,12,1,0,0,38,19,10,0,10,1,17,61,4,13,11,0,11,1,17,81,12,4,14,4,14,2,56,1,12,3,5,17,11,0,1,9,12,3,11,3,2,13,1,0,0,37,8,11,0,11,1,17,79,12,3,14,3,14,2,56,1,2,14,1,0,0,37,8,11,0,11,1,17,82,12,3,14,3,14,2,56,1,2,15,1,0,0,40,25,10,0,11,1,17,79,12,4,14,4,65,31,6,1,0,0,0,0,0,0,0,33,4,19,14,4,6,0,0,0,0,0,0,0,0,66,31,20,12,3,11,0,11,3,17,85,12,2,5,23,11,0,1,9,12,2,11,2,2,16,1,0,0,41,17,10,1,10,2,17,79,12,4,11,1,11,2,17,82,12,5,10,0,11,4,10,3,17,95,11,0,11,5,11,3,17,95,2,17,1,0,0,37,9,11,0,11,1,17,79,12,2,14,2,65,31,6,0,0,0,0,0,0,0,0,36,2,18,1,0,0,35,23,10,0,10,1,10,2,17,26,12,4,11,0,11,1,11,2,17,27,12,5,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,12,3,5,21,9,12,3,11,3,2,19,1,0,0,33,23,10,0,10,1,10,2,17,24,12,4,11,0,11,1,11,2,17,25,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,19,11,4,11,5,17,105,12,3,5,21,7,0,12,3,11,3,2,20,1,0,0,3,10,11,0,11,2,10,3,17,21,12,4,11,1,11,3,11,4,17,28,2,21,1,0,0,18,13,10,0,11,1,10,2,17,84,12,4,11,0,11,2,17,70,12,3,11,4,11,3,17,107,2,22,1,0,0,3,10,11,0,11,2,10,3,17,23,12,4,11,1,11,3,11,4,17,28,2,23,1,0,0,18,13,10,0,11,1,10,2,17,83,12,4,11,0,11,2,17,64,12,3,11,4,11,3,17,107,2,24,1,0,0,42,49,10,0,10,2,17,79,12,6,14,6,65,31,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,43,5,16,14,6,10,7,66,31,12,3,10,0,10,3,20,17,66,12,4,10,0,10,1,10,2,11,3,20,17,20,12,5,11,9,11,5,11,4,17,106,22,12,9,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,11,11,0,1,11,1,1,11,9,2,25,1,0,0,43,49,10,0,10,2,17,82,12,8,14,8,65,31,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,43,5,16,14,8,10,4,66,31,12,6,10,0,10,6,20,17,63,12,3,10,0,10,1,10,2,11,6,20,17,22,12,7,11,9,11,7,11,3,17,106,22,12,9,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,11,11,0,1,11,1,1,11,9,2,26,1,0,0,44,42,10,0,10,2,17,79,12,5,14,5,65,31,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,36,5,16,14,5,10,6,66,31,12,3,10,0,10,1,10,2,11,3,20,17,20,12,4,11,8,11,4,22,12,8,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,11,11,0,1,11,1,1,11,8,2,27,1,0,0,45,42,10,0,10,2,17,82,12,7,14,7,65,31,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,36,5,16,14,7,10,3,66,31,12,5,10,0,10,1,10,2,11,5,20,17,22,12,6,11,8,11,6,22,12,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,11,11,0,1,11,1,1,11,8,2,28,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,11,4,24,6,10,0,0,0,0,0,0,0,11,3,17,112,77,26,2,29,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,6,10,0,0,0,0,0,0,0,11,3,17,112,77,24,11,4,26,2,30,1,0,0,18,16,10,0,10,1,10,2,17,24,12,3,11,0,11,1,11,2,17,25,12,4,17,104,11,3,11,4,17,105,23,2,31,1,0,0,20,52,10,0,10,3,17,61,4,5,5,11,11,0,1,11,1,1,7,16,39,10,0,10,2,17,61,4,16,5,22,11,0,1,11,1,1,7,16,39,10,0,10,1,10,3,17,30,12,5,10,0,11,2,17,78,12,4,11,0,11,1,11,3,17,25,12,7,11,4,74,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,24,17,105,17,104,17,103,17,104,22,12,6,11,5,11,6,17,106,7,1,17,103,2,32,1,0,0,50,89,10,0,10,1,11,2,10,3,17,31,12,12,10,0,10,1,10,3,17,24,12,10,10,0,10,1,10,3,17,25,12,11,10,0,10,5,17,63,12,6,10,0,10,4,17,66,12,7,11,11,7,2,17,106,11,10,23,12,19,7,2,17,104,10,12,23,17,106,11,6,17,106,11,7,23,12,18,11,19,11,18,17,105,12,14,10,0,10,1,10,3,10,4,17,20,10,14,17,105,12,8,10,14,17,104,11,12,23,17,106,12,16,11,0,10,1,11,3,10,5,17,22,10,16,17,105,12,9,11,8,11,9,17,103,17,104,17,103,12,17,10,1,11,4,11,14,10,17,17,106,17,29,12,13,11,1,11,5,11,16,11,17,17,106,17,29,12,15,11,13,11,15,2,33,1,0,0,51,45,10,5,10,4,38,4,9,11,4,12,8,11,2,12,7,5,17,11,5,12,8,11,2,10,8,11,4,17,105,17,106,12,7,10,0,10,1,10,7,17,28,12,9,10,0,11,3,10,8,17,28,12,11,11,0,11,1,11,9,11,11,23,17,29,11,6,17,106,12,12,10,7,10,12,23,12,10,11,7,11,8,11,10,11,12,2,34,1,0,0,18,12,10,0,10,1,17,72,12,3,11,0,11,1,17,70,12,2,11,3,11,2,17,106,2,35,1,0,0,18,12,10,0,10,1,17,67,12,3,11,0,11,1,17,64,12,2,11,3,11,2,17,106,2,36,0,0,0,52,49,10,0,10,1,17,82,12,6,14,6,65,31,12,4,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,46,5,14,14,6,10,3,66,31,12,5,10,0,10,5,20,17,75,12,7,10,0,10,1,10,5,20,17,23,12,2,10,0,10,1,10,5,20,10,2,17,40,10,0,11,7,11,5,20,11,2,17,39,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,9,11,0,1,2,37,0,0,0,3,12,11,3,10,0,10,2,17,70,17,109,12,4,11,0,11,2,11,1,11,4,17,87,2,38,0,0,0,3,12,11,3,10,0,10,2,17,70,17,108,12,4,11,0,11,2,11,1,11,4,17,57,2,39,0,0,0,3,12,11,3,10,0,10,2,17,64,17,109,12,4,11,0,11,2,11,1,11,4,17,86,2,40,0,0,0,3,12,11,3,10,0,10,2,17,64,17,108,12,4,11,0,11,2,11,1,11,4,17,56,2,41,0,0,0,54,21,10,0,11,1,17,79,12,5,14,5,6,0,0,0,0,0,0,0,0,66,31,12,3,10,0,10,3,20,17,68,11,2,22,12,4,11,0,11,3,20,11,4,17,92,2,42,0,0,0,55,32,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,4,10,0,10,4,20,17,68,12,5,10,5,10,2,38,4,22,11,5,11,2,23,12,3,5,24,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,12,6,11,0,11,4,20,11,6,17,92,2,43,0,0,0,56,58,10,0,10,3,17,61,4,51,10,2,17,76,12,5,10,0,10,3,17,80,12,9,10,0,10,1,10,3,17,24,12,6,10,0,11,1,10,3,17,25,12,7,10,6,10,7,36,4,45,11,6,11,7,23,12,8,10,0,10,3,17,78,12,4,11,5,11,9,11,4,11,8,17,98,12,10,11,0,11,2,11,3,11,10,17,94,5,50,11,0,11,2,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,94,5,57,11,0,1,11,1,1,11,2,1,2,44,0,0,0,59,59,11,1,17,76,12,5,10,0,10,2,17,69,12,7,10,0,10,2,17,67,12,6,10,0,10,2,17,64,12,3,10,0,10,2,17,70,12,4,10,0,10,2,17,77,12,11,10,5,10,7,10,0,10,2,17,65,17,100,10,3,17,106,12,9,10,5,11,7,10,0,10,2,17,71,17,101,11,4,17,106,12,10,11,6,10,9,11,3,23,17,106,11,11,17,106,10,10,17,109,12,8,11,0,11,2,11,9,11,10,11,5,11,8,17,93,2,45,0,0,0,20,36,11,0,10,2,10,1,17,62,17,97,12,5,10,5,10,3,38,4,11,5,15,11,1,1,7,10,39,11,5,11,3,23,12,6,10,1,10,2,10,6,17,99,12,4,10,1,10,2,10,4,11,6,17,102,12,7,11,1,11,2,11,4,11,7,17,91,2,0,92,0,94,0],"lending_portal":[161,28,235,11,6,0,0,0,11,1,0,46,2,46,94,3,140,1,185,2,4,197,3,36,5,233,3,172,6,7,149,10,184,11,8,205,21,128,1,6,205,22,88,10,165,23,59,12,224,23,204,17,13,172,41,4,0,76,0,24,0,40,0,41,0,55,0,73,0,74,0,75,0,79,0,87,0,88,0,108,0,113,0,114,1,86,2,32,2,33,2,47,2,85,2,104,2,106,2,107,3,103,0,8,8,0,0,15,3,0,0,9,3,0,0,7,3,0,1,0,12,0,2,4,7,0,3,11,12,1,0,1,4,5,0,0,4,6,8,0,6,18,8,0,9,14,8,0,10,12,12,0,11,21,12,0,12,3,12,0,13,13,8,0,14,10,7,1,0,0,15,1,8,0,16,2,12,1,0,1,18,20,4,0,19,16,2,0,21,19,2,0,22,17,12,0,0,70,0,1,0,0,64,2,3,0,0,99,4,1,0,0,25,5,1,0,0,29,5,1,0,0,30,6,1,0,0,105,7,1,1,0,0,111,8,1,1,0,0,112,9,1,0,0,26,8,1,1,0,0,27,9,1,0,0,94,7,1,1,0,0,77,10,1,1,0,2,34,13,18,0,2,35,1,18,1,0,2,36,55,18,0,2,59,45,31,0,2,63,1,20,0,3,37,38,31,1,0,3,84,37,3,1,0,3,110,53,1,1,0,4,31,17,1,0,5,46,30,31,0,5,57,1,29,0,5,58,1,29,0,5,62,1,29,0,5,66,1,29,0,5,67,1,29,0,5,68,1,29,0,6,56,56,57,0,7,25,21,1,0,7,29,21,1,0,7,48,44,1,0,7,49,64,1,0,7,50,44,1,0,7,51,44,1,0,7,52,44,52,0,8,78,24,25,1,0,10,22,39,40,0,10,54,48,49,0,10,61,43,20,0,10,65,43,52,0,10,93,39,40,0,11,60,19,3,0,11,71,19,41,0,11,91,42,1,0,12,96,58,3,0,13,95,32,3,0,14,38,51,15,1,0,14,72,50,41,1,0,16,39,25,1,1,0,16,102,27,25,1,0,16,109,28,3,1,0,17,45,15,1,1,3,18,81,0,11,0,20,89,34,1,1,12,20,100,15,1,1,8,21,97,12,13,0,22,80,26,3,0,56,14,37,23,51,23,52,23,55,33,53,35,14,15,37,15,52,15,19,15,18,15,53,46,49,18,48,18,20,15,53,59,6,15,50,15,1,7,8,20,0,1,7,8,0,1,3,3,6,8,7,7,8,0,5,8,6,8,8,7,8,9,7,8,10,6,8,16,7,8,11,7,8,12,10,13,7,8,20,9,6,8,8,6,8,16,7,8,14,7,8,0,7,8,21,10,13,10,11,17,1,8,19,3,7,8,20,11,6,8,8,7,8,9,7,8,10,6,8,16,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,17,1,9,0,3,7,8,20,10,6,8,8,7,8,9,7,8,10,6,8,16,7,8,0,7,8,11,7,8,12,7,11,6,1,9,0,3,7,8,20,16,6,8,8,7,8,9,7,8,10,6,8,16,7,8,13,7,8,0,7,8,21,7,8,11,7,8,12,10,2,10,2,13,3,10,11,17,1,8,19,3,7,8,20,14,6,8,8,7,8,9,7,8,10,6,8,16,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,17,1,9,0,3,13,10,2,3,7,8,20,1,8,18,1,6,8,20,1,5,1,8,0,1,9,0,11,8,5,7,8,9,7,8,10,6,8,16,3,13,6,13,3,3,3,8,5,1,6,8,8,1,8,5,2,6,8,12,8,5,1,13,6,6,8,11,7,8,9,7,8,10,6,8,16,3,13,7,11,17,1,8,19,3,10,2,3,3,11,17,1,8,19,3,1,8,19,3,10,11,17,1,9,0,3,7,8,20,1,11,17,1,9,0,1,6,8,21,3,7,11,17,1,9,0,3,7,8,20,1,6,11,17,1,9,0,1,2,2,10,13,2,1,10,2,7,7,8,14,7,8,21,11,17,1,8,19,13,10,2,6,8,16,7,8,20,1,11,17,1,8,19,2,9,0,5,1,8,1,17,6,8,16,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,3,11,17,1,9,0,13,3,3,8,5,8,5,2,6,11,6,1,9,0,3,5,7,11,6,1,9,0,11,17,1,9,0,13,10,2,7,8,20,4,7,8,11,8,5,13,15,2,15,15,1,1,2,7,8,12,8,5,2,7,8,11,8,5,7,6,8,11,7,8,9,7,8,10,6,8,16,3,13,15,1,6,8,5,1,8,3,16,8,5,7,8,9,7,8,10,6,8,16,3,13,15,15,13,3,13,11,15,1,8,5,8,5,8,5,8,5,15,3,7,8,11,13,13,1,11,15,1,8,5,1,6,11,15,1,9,0,1,11,15,1,9,0,1,15,5,7,11,6,1,9,0,8,5,3,8,5,7,8,20,21,8,5,7,8,9,7,8,10,6,8,16,3,13,15,15,11,17,1,8,19,13,3,11,15,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,17,1,8,19,3,2,13,10,2,1,7,8,9,1,6,8,4,11,7,8,21,7,8,13,6,8,4,7,8,11,8,5,8,5,13,3,15,11,17,1,8,19,6,8,16,1,8,2,15,8,5,7,8,9,7,8,10,6,8,16,3,13,15,13,3,13,11,15,1,8,5,8,5,8,5,8,5,15,20,8,5,7,8,9,7,8,10,6,8,16,3,13,15,11,17,1,8,19,13,3,11,15,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,17,1,8,19,3,17,6,8,16,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,13,3,3,8,5,3,11,17,1,9,0,8,5,16,13,8,5,7,8,9,7,8,10,6,8,16,3,3,13,13,8,5,3,8,5,3,5,13,8,5,8,6,8,11,7,8,9,7,8,10,6,8,16,3,3,13,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,17,76,101,110,100,105,110,103,76,111,99,97,108,69,118,101,110,116,13,76,101,110,100,105,110,103,80,111,114,116,97,108,18,76,101,110,100,105,110,103,80,111,114,116,97,108,69,118,101,110,116,6,79,112,116,105,111,110,4,80,111,111,108,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,9,80,111,111,108,83,116,97,116,101,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,13,97,100,100,95,108,105,113,117,105,100,105,116,121,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,12,98,111,114,114,111,119,95,108,111,99,97,108,13,98,111,114,114,111,119,95,114,101,109,111,116,101,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,27,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,95,114,101,109,111,116,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,7,100,101,112,111,115,105,116,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,17,100,111,108,97,95,112,111,111,108,95,97,100,100,114,101,115,115,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,32,101,110,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,10,102,101,101,95,97,109,111,117,110,116,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,2,105,100,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,9,108,105,113,117,105,100,97,116,101,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,11,109,101,115,115,97,103,101,95,102,101,101,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,7,114,101,108,97,121,101,114,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,5,114,101,112,97,121,12,115,101,110,100,95,109,101,115,115,97,103,101,13,115,101,110,100,95,119,105,116,104,100,114,97,119,6,115,101,110,100,101,114,8,115,101,113,117,101,110,99,101,11,115,101,116,95,114,101,108,97,121,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,112,108,105,116,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,14,119,105,116,104,100,114,97,119,95,108,111,99,97,108,15,119,105,116,104,100,114,97,119,95,114,101,109,111,116,101,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,13,2,1,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,69,8,18,92,5,82,3,1,2,5,98,3,83,3,44,8,5,53,3,28,2,2,2,8,83,3,97,5,42,10,2,101,13,43,13,90,10,2,23,3,28,2,3,2,5,83,3,97,5,42,10,2,23,3,28,2,0,0,0,0,1,9,10,0,17,54,11,0,46,17,57,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,0,0,1,5,11,2,11,1,15,1,21,2,3,1,4,0,16,61,11,0,17,21,11,7,46,17,57,17,13,12,18,11,5,11,18,12,8,46,11,8,17,43,12,15,14,6,65,20,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,20,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,30,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,4,1,4,0,16,61,11,0,17,21,11,7,46,17,57,17,13,12,18,11,5,11,18,12,8,46,11,8,17,43,12,15,14,6,65,20,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,20,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,31,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,5,0,4,0,22,66,11,0,17,21,11,6,10,7,10,8,56,1,12,9,10,4,46,17,58,12,15,11,7,10,15,38,4,16,5,28,11,4,1,11,2,1,11,3,1,11,8,1,11,1,1,7,3,39,13,9,11,15,10,8,56,2,12,14,14,9,56,3,12,12,11,5,17,24,17,22,12,11,10,3,17,1,12,10,11,2,11,4,11,14,7,5,11,11,11,1,11,8,17,47,12,13,11,9,11,3,16,1,20,56,4,11,13,11,10,7,6,17,13,11,12,17,24,18,1,56,5,2,6,1,4,0,36,117,11,0,17,21,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,57,17,13,12,27,56,6,12,26,11,8,11,9,10,10,56,7,12,22,10,7,14,22,56,8,12,15,46,11,15,56,9,12,21,11,4,17,1,12,25,11,7,11,22,7,5,64,29,0,0,0,0,0,0,0,0,10,10,56,10,1,10,6,10,26,7,5,10,21,77,17,38,1,12,20,10,5,10,27,12,16,46,11,16,17,44,32,4,74,10,5,10,27,17,45,10,6,10,26,17,40,12,23,11,5,11,27,12,17,46,11,17,17,43,12,24,11,6,11,1,11,2,11,3,11,24,11,23,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,35,11,25,11,10,46,17,57,14,26,17,16,11,21,17,27,18,3,56,11,2,7,1,4,0,47,117,11,0,17,21,17,17,12,20,10,9,46,17,57,17,13,12,24,56,6,12,23,10,5,10,23,17,40,12,18,11,6,10,24,12,10,46,11,10,17,43,12,19,10,5,10,18,11,20,17,39,12,21,14,21,56,12,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,21,56,13,12,22,10,5,11,1,11,2,11,3,11,19,11,18,11,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,36,12,17,10,5,10,22,17,41,10,17,38,4,80,5,90,11,5,1,11,7,1,11,4,1,11,9,1,7,1,39,11,5,11,22,7,5,10,17,17,42,1,12,25,11,7,11,24,11,25,52,10,23,10,9,56,14,11,4,17,1,11,9,46,17,57,14,23,17,16,11,17,52,17,28,18,3,56,11,2,8,1,4,0,54,184,1,11,0,17,21,10,11,10,10,17,15,12,31,10,11,11,9,17,15,12,30,10,15,46,17,57,17,13,12,34,10,7,10,30,17,40,12,25,11,8,11,34,12,16,46,11,16,17,43,12,26,10,7,10,25,10,11,17,39,12,27,14,27,56,12,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,27,56,13,12,28,10,7,10,1,11,2,10,3,11,26,11,25,11,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,36,12,23,10,7,10,28,17,41,10,23,38,4,86,5,102,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,11,13,10,14,10,15,56,1,12,24,10,6,46,17,58,12,36,11,14,10,36,38,4,116,5,132,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,24,11,36,10,15,56,2,12,35,14,24,56,3,12,32,10,5,17,1,12,29,11,6,11,4,11,1,17,29,11,7,10,28,11,31,17,17,10,29,10,23,11,35,11,3,17,46,12,33,11,24,11,5,16,1,20,56,4,11,33,10,29,11,28,11,32,17,28,18,1,56,5,11,29,11,15,46,17,57,14,30,17,16,17,17,11,11,11,10,11,23,52,17,28,18,2,56,15,2,9,1,4,0,60,123,11,0,17,21,17,17,12,19,56,6,12,22,10,9,46,17,57,17,13,12,23,10,5,10,22,17,40,12,17,11,6,10,23,12,10,46,11,10,17,43,12,18,10,5,10,17,11,19,17,39,12,20,14,20,56,12,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,20,56,13,12,21,10,5,10,21,17,41,10,8,77,38,4,58,5,74,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,1,39,10,5,11,1,11,2,11,3,11,18,11,17,10,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,32,11,5,11,21,7,5,10,8,77,17,42,1,12,24,11,7,11,23,11,24,52,10,22,10,9,56,14,11,4,17,1,11,9,46,17,57,14,22,17,16,11,8,17,23,18,3,56,11,2,10,1,4,0,61,186,1,11,0,17,21,10,11,10,10,17,15,12,30,10,11,11,9,17,15,12,29,10,15,46,17,57,17,13,12,33,10,7,10,29,17,40,12,24,11,8,11,33,12,16,46,11,16,17,43,12,25,10,7,10,24,10,11,17,39,12,26,14,26,56,12,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,26,56,13,12,27,10,7,10,27,17,41,10,12,77,38,4,64,5,82,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,10,7,10,1,11,2,10,3,11,25,11,24,10,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,32,11,13,10,14,10,15,56,1,12,23,10,6,46,17,58,12,35,11,14,10,35,38,4,118,5,134,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,23,11,35,10,15,56,2,12,34,14,23,56,3,12,31,10,5,17,1,12,28,11,6,11,4,11,1,17,29,11,7,10,27,11,30,17,17,10,28,10,12,77,11,34,11,3,17,46,12,32,11,23,11,5,16,1,20,56,4,11,32,10,28,11,27,11,31,17,28,18,1,56,5,11,28,11,15,46,17,57,14,29,17,16,17,17,11,11,11,10,11,12,17,23,18,2,56,15,2,11,1,4,0,62,117,11,0,17,21,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,57,17,13,12,27,56,6,12,24,11,8,11,9,10,10,56,7,12,26,10,7,14,26,56,8,12,15,46,11,15,56,9,12,25,11,4,17,1,12,23,11,7,11,26,7,5,64,29,0,0,0,0,0,0,0,0,10,10,56,10,1,10,6,10,24,7,5,10,25,77,17,38,1,12,20,10,5,10,27,12,16,46,11,16,17,44,32,4,74,10,5,10,27,17,45,10,6,10,24,17,40,12,21,11,5,11,27,12,17,46,11,17,17,43,12,22,11,6,11,1,11,2,11,3,11,22,11,21,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,34,11,23,11,10,46,17,57,14,24,17,16,11,25,17,26,18,3,56,11,2,12,1,4,0,63,93,10,0,17,21,10,13,46,17,57,12,27,10,27,17,13,12,25,56,6,12,23,11,10,10,11,17,15,12,29,10,6,11,23,17,40,12,22,10,6,11,29,17,40,12,28,10,4,17,1,12,26,10,9,6,0,0,0,0,0,0,0,0,36,4,43,11,0,10,1,10,2,10,3,11,4,10,5,10,6,11,7,11,8,10,9,11,13,56,16,5,54,11,4,1,11,0,1,11,7,1,11,8,10,9,11,13,56,7,56,17,11,5,11,25,12,15,46,11,15,17,43,12,24,11,6,11,1,11,2,11,3,11,24,11,12,11,28,11,22,12,14,12,21,12,20,12,19,12,18,12,17,12,16,46,11,16,11,17,11,18,11,19,11,20,11,21,11,14,17,33,11,26,11,27,11,11,11,9,17,25,18,3,56,11,2,0,2,0,1,0],"merge_coins":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,10,3,20,53,4,73,14,5,87,102,7,189,1,132,1,8,193,2,96,6,161,3,30,12,191,3,189,1,0,6,1,14,2,2,2,11,2,12,2,0,12,1,0,1,4,1,2,0,0,5,0,1,1,0,1,3,5,6,1,0,1,8,3,4,1,0,2,4,8,4,1,0,2,10,11,1,1,0,2,13,9,10,1,0,2,15,15,1,1,0,3,7,14,4,1,12,4,9,12,13,0,2,1,1,1,3,7,5,7,4,7,7,1,6,7,3,10,11,0,1,9,0,3,7,8,1,1,11,0,1,9,0,6,11,0,1,9,0,11,0,1,9,0,11,0,1,9,0,3,11,0,1,9,0,3,1,7,10,9,0,0,1,6,10,9,0,1,1,1,9,0,2,7,11,0,1,9,0,11,0,1,9,0,1,6,11,0,1,9,0,1,3,3,7,11,0,1,9,0,3,7,8,1,1,6,8,1,1,5,2,9,0,5,1,7,8,1,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,8,105,115,95,101,109,112,116,121,4,106,111,105,110,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,7,114,101,118,101,114,115,101,6,115,101,110,100,101,114,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,118,101,99,116,111,114,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,255,255,255,255,255,255,255,255,0,1,0,0,2,83,14,0,65,1,6,0,0,0,0,0,0,0,0,36,4,67,13,0,56,0,13,0,69,1,12,5,14,0,56,1,32,4,20,5,15,13,5,13,0,69,1,56,2,5,10,11,0,70,1,0,0,0,0,0,0,0,0,14,5,56,3,12,8,10,1,12,6,11,1,7,2,33,4,33,10,8,12,6,11,8,10,6,38,4,38,5,42,11,2,1,7,0,39,14,5,56,3,10,6,36,4,60,13,5,11,6,10,2,56,4,12,7,11,5,11,2,46,17,8,56,5,11,7,12,3,5,64,11,2,1,11,5,12,3,11,3,12,4,5,81,11,0,70,1,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,33,4,74,5,78,11,2,1,7,1,39,11,2,56,6,12,4,11,4,2,0],"oracle":[161,28,235,11,6,0,0,0,11,1,0,36,2,36,84,3,120,157,1,4,149,2,22,5,171,2,231,2,7,146,5,231,6,8,249,11,128,1,6,249,12,70,10,191,13,33,12,224,13,232,5,13,200,19,14,0,47,0,31,2,40,2,41,2,49,2,52,2,54,2,56,2,61,1,23,1,24,1,46,1,62,1,63,1,65,1,66,3,61,3,68,0,10,8,0,0,6,4,0,1,2,0,0,1,3,8,0,2,4,0,1,3,0,3,5,7,0,4,6,7,0,5,7,7,0,6,8,7,0,6,9,12,0,8,12,12,0,9,0,8,0,10,1,12,1,0,1,11,15,4,0,12,11,2,0,13,13,12,2,7,1,4,1,15,14,2,0,16,12,12,0,17,16,0,0,0,43,0,1,0,0,39,2,3,0,0,59,4,1,0,0,58,4,1,0,0,57,5,1,0,0,20,6,1,0,0,21,6,1,0,0,29,7,1,0,1,22,27,1,0,2,28,40,1,1,3,3,33,43,23,0,3,34,43,23,0,4,32,41,42,0,4,35,41,42,0,5,30,19,20,0,6,36,30,20,0,6,37,28,29,0,7,26,33,34,0,7,38,38,39,0,7,67,35,34,0,9,64,22,23,0,11,45,0,8,0,13,17,21,1,2,7,4,13,18,15,17,2,7,4,13,19,36,37,2,7,4,13,25,15,16,2,7,4,13,45,0,10,2,7,4,14,60,13,1,1,8,17,48,31,32,0,26,9,26,11,27,12,25,11,23,11,25,9,22,9,22,11,23,9,24,11,9,29,1,7,8,16,0,2,7,8,0,13,3,15,2,3,3,6,8,2,7,8,0,3,7,6,8,2,7,8,0,10,2,13,15,2,6,8,11,3,7,8,0,10,13,6,8,11,9,6,8,3,7,8,17,7,8,10,7,8,9,7,8,0,13,10,2,6,8,11,11,12,1,8,14,1,8,13,2,13,8,7,1,11,15,2,9,0,9,1,2,13,8,1,1,8,0,1,9,0,4,13,13,6,8,1,7,11,15,2,13,8,1,2,6,11,15,2,9,0,9,1,9,0,1,1,1,6,9,1,5,13,13,8,7,7,11,15,2,13,8,7,7,11,15,2,13,8,1,1,10,2,1,8,7,3,7,11,15,2,9,0,9,1,9,0,9,1,1,6,8,11,1,3,6,13,3,6,13,3,6,8,1,7,11,15,2,13,8,1,1,13,23,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,6,8,11,13,10,2,6,8,11,10,8,18,6,8,11,3,8,5,3,11,4,1,8,8,7,8,1,6,8,7,8,8,11,4,1,8,8,8,5,3,8,6,8,7,8,18,1,6,8,3,1,6,8,9,1,8,8,1,6,8,8,3,6,8,17,10,2,6,8,11,1,8,18,3,6,8,10,10,8,18,6,8,11,1,11,4,1,8,8,5,6,8,10,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,2,7,11,15,2,9,0,9,1,9,0,1,7,9,1,3,6,8,9,6,8,11,3,1,8,6,1,11,4,1,9,0,1,6,8,6,1,8,5,1,6,8,5,5,67,108,111,99,107,4,67,111,105,110,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,15,72,111,116,80,111,116,97,116,111,86,101,99,116,111,114,3,73,54,52,5,80,114,105,99,101,15,80,114,105,99,101,73,100,101,110,116,105,102,105,101,114,9,80,114,105,99,101,73,110,102,111,15,80,114,105,99,101,73,110,102,111,79,98,106,101,99,116,11,80,114,105,99,101,79,114,97,99,108,101,3,83,85,73,5,83,116,97,116,101,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,86,65,65,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,17,99,104,101,99,107,95,103,117,97,114,100,95,112,114,105,99,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,29,99,114,101,97,116,101,95,112,114,105,99,101,95,105,110,102,111,115,95,104,111,116,95,112,111,116,97,116,111,7,100,101,99,105,109,97,108,7,100,101,115,116,114,111,121,24,102,101,101,100,95,116,111,107,101,110,95,112,114,105,99,101,95,98,121,95,112,121,116,104,13,102,114,111,109,95,98,121,116,101,95,118,101,99,7,103,101,110,101,115,105,115,8,103,101,116,95,101,120,112,111,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,110,101,103,97,116,105,118,101,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,112,111,115,105,116,105,118,101,9,103,101,116,95,112,114,105,99,101,20,103,101,116,95,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,37,103,101,116,95,112,114,105,99,101,95,105,110,102,111,95,102,114,111,109,95,112,114,105,99,101,95,105,110,102,111,95,111,98,106,101,99,116,23,103,101,116,95,112,114,105,99,101,95,110,111,95,111,108,100,101,114,95,116,104,97,110,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,17,104,111,116,95,112,111,116,97,116,111,95,118,101,99,116,111,114,3,105,54,52,2,105,100,4,105,110,105,116,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,3,110,101,119,6,111,98,106,101,99,116,6,111,114,97,99,108,101,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,5,112,114,105,99,101,16,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,16,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,16,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,17,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,115,10,112,114,105,99,101,95,105,110,102,111,13,112,114,105,99,101,95,111,114,97,99,108,101,115,4,112,121,116,104,20,114,101,103,105,115,116,101,114,95,116,111,107,101,110,95,112,114,105,99,101,20,115,101,116,95,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,20,115,101,116,95,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,116,97,116,101,3,115,117,105,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,24,117,112,100,97,116,101,95,115,105,110,103,108,101,95,112,114,105,99,101,95,102,101,101,100,3,118,97,97,5,118,97,108,117,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,181,59,15,65,116,16,134,39,251,238,114,226,73,139,88,214,162,113,76,222,213,63,172,83,112,52,194,32,210,99,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,60,0,0,0,0,0,0,0,3,8,16,14,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,5,42,8,13,51,3,50,3,53,11,15,2,13,8,7,55,11,15,2,13,8,1,1,2,3,69,15,27,2,44,3,0,0,0,0,1,11,10,0,17,21,7,1,7,0,10,0,56,0,11,0,56,1,18,0,56,2,2,1,1,0,0,14,32,11,0,15,0,12,5,10,5,10,1,12,2,46,11,2,56,3,4,11,5,15,11,5,1,7,2,39,11,5,11,1,12,3,46,11,3,56,4,12,4,10,4,16,1,20,10,4,16,2,20,11,4,16,3,20,2,2,1,0,0,1,5,11,2,11,1,15,4,21,2,3,1,0,0,1,5,11,2,11,1,15,5,21,2,4,1,0,0,18,58,10,1,15,0,12,11,10,11,10,3,12,7,46,11,7,56,3,32,4,12,5,20,11,11,1,11,1,1,11,6,1,7,3,39,11,2,17,14,12,9,11,1,15,6,12,10,10,10,10,3,12,8,46,11,8,56,5,32,4,35,5,43,11,11,1,11,10,1,11,6,1,7,3,39,11,10,10,3,11,9,56,6,11,11,11,3,11,4,11,5,11,6,17,20,6,232,3,0,0,0,0,0,0,26,18,1,56,7,2,5,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,5,20,35,4,39,5,45,11,8,1,11,0,1,7,4,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,6,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,4,20,35,4,39,5,45,11,8,1,11,0,1,7,5,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,7,1,0,0,26,136,1,11,0,17,8,10,4,16,6,10,5,56,5,4,8,5,20,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,2,39,10,4,15,6,10,5,12,14,46,11,14,56,8,12,24,10,3,46,17,16,12,25,14,25,17,15,12,30,11,24,14,30,33,4,40,5,52,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,6,39,11,1,11,6,10,7,12,16,12,15,46,11,15,11,16,17,28,12,31,10,2,11,31,64,32,1,0,0,0,0,0,0,0,10,7,12,18,12,17,46,11,17,11,18,17,17,12,26,11,2,11,26,10,3,11,8,10,7,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,17,19,12,22,10,7,17,20,6,232,3,0,0,0,0,0,0,26,12,19,11,4,15,0,11,5,56,9,12,23,11,3,11,7,12,13,46,11,13,7,0,17,18,12,29,11,22,56,10,14,29,17,13,12,27,14,27,17,11,12,28,14,29,17,12,12,20,14,20,17,10,12,21,11,28,77,10,23,15,1,21,11,21,51,10,23,15,2,21,11,19,11,23,15,3,21,2,0,4,1,0,1,1,1,2,0,1,0,2,0,3,0],"pool_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,136,1,4,146,1,2,5,148,1,208,1,7,228,2,205,4,8,177,7,32,6,209,7,41,12,250,7,133,12,0,23,0,10,0,24,1,0,7,0,0,18,0,1,0,0,22,0,1,0,0,21,0,1,0,0,19,0,1,0,0,20,0,1,0,0,16,0,1,0,0,17,0,1,0,0,11,2,3,0,0,1,3,4,0,0,15,5,3,0,0,5,3,6,0,0,14,7,3,0,0,4,3,8,0,0,13,9,3,0,0,3,3,9,0,1,2,3,12,0,1,12,12,3,0,2,6,19,20,0,2,7,19,27,0,2,8,19,21,0,2,9,19,1,0,2,25,11,0,0,2,26,25,0,0,2,27,14,0,0,2,28,15,0,0,2,29,13,0,0,2,30,17,18,1,1,26,1,0,1,2,5,8,0,8,0,3,13,10,2,1,10,2,6,8,0,8,0,3,13,2,10,2,5,13,3,8,0,8,0,3,6,13,3,8,0,8,0,3,2,3,8,0,13,10,2,4,8,0,13,2,10,2,3,13,15,2,3,10,2,10,2,10,2,2,7,10,2,13,1,8,0,2,7,10,2,10,2,2,7,10,2,3,2,7,10,2,2,18,10,2,10,2,10,2,10,2,10,2,10,2,3,13,10,2,13,3,3,3,8,0,2,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,17,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,3,3,8,0,2,13,13,8,0,13,2,10,2,10,2,13,10,2,10,2,10,2,10,2,13,10,2,13,3,3,3,2,8,0,13,2,7,10,2,15,9,10,2,10,2,10,2,3,13,15,3,3,2,1,15,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,100,101,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,21,103,101,116,95,100,101,108,101,116,101,95,111,119,110,101,114,95,116,121,112,101,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,16,103,101,116,95,100,101,112,111,115,105,116,95,116,121,112,101,23,103,101,116,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,21,103,101,116,95,115,101,110,100,95,109,101,115,115,97,103,101,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,10,112,111,111,108,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,10,48,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,3,17,21,11,0,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,1,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,2,17,23,13,6,7,2,17,24,14,4,65,1,6,0,0,0,0,0,0,0,0,36,4,46,13,6,14,4,65,1,75,17,21,13,6,11,4,17,25,11,6,2,8,1,0,0,16,172,1,14,0,65,1,12,13,6,0,0,0,0,0,0,0,0,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,1,14,1,17,17,12,8,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,2,14,2,17,17,12,16,11,12,11,11,22,12,12,11,16,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,14,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,3,14,3,17,17,12,18,11,12,11,11,22,12,12,11,18,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,17,11,12,11,11,22,12,12,6,8,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,4,14,4,17,19,12,7,11,12,11,11,22,12,12,6,1,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,5,14,5,17,20,12,15,11,12,11,11,22,12,12,64,1,0,0,0,0,0,0,0,0,12,9,10,13,10,12,36,4,151,1,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,6,14,6,17,17,12,10,11,12,11,11,22,12,12,11,10,52,12,11,14,0,10,12,10,12,10,11,22,56,0,12,9,11,12,11,11,22,12,12,10,15,7,2,33,4,156,1,5,158,1,7,1,39,11,13,11,12,33,4,163,1,5,165,1,7,0,39,11,14,11,17,11,7,11,8,11,15,11,9,2,9,1,0,0,10,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,21,13,6,11,1,17,23,11,2,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,3,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,4,17,23,13,6,7,3,17,24,11,6,2,10,1,0,0,22,152,1,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,15,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,19,12,11,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,17,11,9,11,8,22,12,9,11,17,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,19,12,7,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,20,12,13,11,9,11,8,22,12,9,10,13,7,3,33,4,136,1,5,138,1,7,1,39,11,10,11,9,33,4,143,1,5,145,1,7,0,39,11,15,11,11,11,12,11,16,11,7,11,13,2,11,1,0,0,23,34,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,1,17,21,11,0,17,16,12,4,13,3,14,4,65,1,75,17,21,13,3,11,4,17,25,13,3,7,4,17,24,14,2,65,1,6,0,0,0,0,0,0,0,0,36,4,32,13,3,14,2,65,1,75,17,21,13,3,11,2,17,25,11,3,2,12,1,0,0,24,123,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,5,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,20,12,11,11,9,11,8,22,12,9,64,1,0,0,0,0,0,0,0,0,12,6,10,10,10,9,36,4,104,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,7,11,9,11,8,22,12,9,11,7,52,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,11,9,11,8,22,12,9,10,11,7,4,33,4,109,5,111,7,1,39,11,10,11,9,33,4,116,5,118,7,0,39,11,12,11,5,11,11,11,6,2,13,1,0,0,3,13,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,0,17,21,13,3,11,1,17,22,13,3,11,2,17,24,11,3,2,14,1,0,0,26,64,14,0,65,1,12,8,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,1,14,1,17,17,12,5,11,7,11,4,22,12,7,6,32,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,2,14,2,17,18,12,6,11,7,11,4,22,12,7,6,1,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,3,14,3,17,20,12,9,11,7,11,4,22,12,7,11,8,11,7,33,4,58,5,60,7,0,39,11,5,11,6,11,9,2,0],"pool_manager":[161,28,235,11,6,0,0,0,12,1,0,22,2,22,66,3,88,199,1,4,159,2,62,5,221,2,206,2,7,171,5,144,8,8,187,13,96,6,155,14,138,1,10,165,15,108,12,145,16,154,13,13,171,29,32,15,203,29,4,0,62,0,28,0,30,0,36,1,21,1,58,2,32,2,57,2,74,2,76,2,77,0,9,12,0,0,1,4,0,0,7,4,0,0,4,4,0,0,8,4,0,0,6,4,0,0,0,3,0,0,10,3,0,1,2,7,0,3,3,0,0,4,11,7,0,5,5,7,1,0,0,7,14,4,0,8,12,12,2,7,1,4,1,10,13,2,0,0,51,0,1,0,0,66,2,1,0,0,65,3,1,0,0,71,4,1,0,0,69,5,1,0,0,70,4,1,0,0,47,6,7,0,0,41,8,9,0,0,44,6,10,0,0,37,11,12,0,0,48,6,12,0,0,43,8,12,0,0,42,8,12,0,0,45,6,12,0,0,46,8,12,0,0,38,1,12,0,0,39,1,12,0,0,35,13,14,0,0,34,15,16,0,0,33,17,16,0,0,81,1,18,0,0,16,19,20,0,0,67,19,20,0,1,40,46,9,0,2,24,49,12,0,2,25,49,12,0,2,26,20,12,0,5,56,1,47,1,0,5,73,28,47,1,0,6,29,28,1,1,3,7,55,0,21,0,8,15,31,1,2,7,4,8,22,41,42,2,7,4,8,23,35,36,2,7,4,8,27,41,16,2,7,4,8,55,0,23,2,7,4,9,72,28,1,1,8,35,22,35,24,35,25,35,26,36,27,35,30,31,24,31,26,35,33,31,22,31,25,33,26,33,24,31,30,33,30,32,26,32,25,32,24,32,22,34,33,32,33,32,30,28,32,27,32,34,24,34,25,33,22,31,33,33,33,29,50,29,51,1,7,8,14,0,5,6,8,9,7,8,0,8,10,13,7,8,14,4,6,8,9,7,8,0,8,8,13,4,6,8,9,7,8,0,8,8,15,4,6,8,9,7,8,0,13,15,2,7,8,0,13,1,10,8,8,2,7,8,0,8,8,1,13,1,8,10,3,6,8,0,13,13,1,15,3,7,8,0,13,13,1,11,11,1,8,8,2,6,8,0,13,1,1,2,6,8,0,8,8,1,8,3,4,7,8,0,8,8,13,15,2,15,15,1,8,12,2,13,8,1,1,11,13,2,9,0,9,1,2,13,8,2,2,8,8,13,2,13,10,8,8,1,8,0,1,9,0,8,13,8,10,8,3,11,13,2,8,8,8,4,8,1,7,11,13,2,13,8,1,8,2,7,11,13,2,13,8,2,2,8,8,8,4,3,7,11,13,2,9,0,9,1,9,0,9,1,1,8,8,2,13,8,3,3,13,8,8,7,8,5,2,7,11,13,2,9,0,9,1,9,0,1,7,9,1,4,8,8,13,7,8,2,7,8,4,2,13,7,8,2,3,8,8,13,7,8,4,2,13,13,2,6,11,13,2,9,0,9,1,9,0,1,6,9,1,2,8,8,8,8,2,15,6,11,13,2,13,8,3,4,8,8,3,3,10,8,8,1,6,8,8,1,11,11,1,9,0,9,8,8,13,15,7,11,13,2,13,8,3,7,8,3,13,15,7,8,2,7,8,4,6,15,15,15,15,15,15,1,8,6,1,8,7,12,65,100,100,76,105,113,117,105,100,105,116,121,7,65,112,112,73,110,102,111,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,9,76,105,113,117,105,100,105,116,121,6,79,112,116,105,111,110,11,80,111,111,108,67,97,116,97,108,111,103,8,80,111,111,108,73,110,102,111,13,80,111,111,108,76,105,113,117,105,100,105,116,121,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,15,82,101,109,111,118,101,76,105,113,117,105,100,105,116,121,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,13,97,100,100,95,108,105,113,117,105,100,105,116,121,7,97,108,112,104,97,95,49,6,97,109,111,117,110,116,9,97,112,112,95,105,110,102,111,115,13,97,112,112,95,108,105,113,117,105,100,105,116,121,5,97,115,99,105,105,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,5,101,118,101,110,116,18,101,120,105,115,116,95,99,101,114,116,97,105,110,95,112,111,111,108,13,101,120,105,115,116,95,112,111,111,108,95,105,100,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,100,101,102,97,117,108,116,95,97,108,112,104,97,95,49,20,103,101,116,95,100,101,102,97,117,108,116,95,108,97,109,98,100,97,95,49,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,24,103,101,116,95,112,111,111,108,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,112,111,111,108,95,110,97,109,101,95,98,121,95,105,100,21,103,101,116,95,112,111,111,108,95,116,111,116,97,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,115,95,98,121,95,105,100,19,103,101,116,95,116,111,107,101,110,95,108,105,113,117,105,100,105,116,121,2,105,100,11,105,100,95,116,111,95,112,111,111,108,115,4,105,110,105,116,8,108,97,109,98,100,97,95,49,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,110,97,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,12,112,111,111,108,95,97,100,100,114,101,115,115,12,112,111,111,108,95,99,97,116,97,108,111,103,10,112,111,111,108,95,105,110,102,111,115,12,112,111,111,108,95,109,97,110,97,103,101,114,10,112,111,111,108,95,116,111,95,105,100,5,112,111,111,108,115,13,114,101,103,105,115,116,101,114,95,112,111,111,108,16,114,101,103,105,115,116,101,114,95,112,111,111,108,95,105,100,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,7,114,101,115,101,114,118,101,21,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,97,108,112,104,97,22,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,108,97,109,98,100,97,15,115,101,116,95,112,111,111,108,95,119,101,105,103,104,116,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,116,97,98,108,101,12,116,111,116,97,108,95,119,101,105,103,104,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,119,101,105,103,104,116,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,14,122,101,114,111,95,108,105,113,117,105,100,105,116,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,0,88,241,76,176,44,241,78,240,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,37,164,0,10,139,202,34,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,0,2,4,49,8,12,19,11,13,2,13,8,1,61,11,13,2,13,8,2,60,8,5,1,2,1,20,11,13,2,13,8,3,2,2,5,54,8,10,68,8,3,17,15,75,15,64,11,13,2,8,8,8,4,3,2,1,78,15,4,2,4,78,15,52,15,30,15,79,15,5,2,2,63,11,13,2,8,8,13,50,11,13,2,13,10,8,8,6,2,3,59,8,8,18,15,31,15,7,2,3,59,8,8,18,15,30,15,0,0,0,0,1,14,10,0,17,30,10,0,56,0,10,0,56,1,10,0,56,2,11,0,56,3,18,5,18,0,56,4,2,1,1,0,0,29,54,10,1,10,3,12,5,46,11,5,17,18,32,4,9,5,15,11,1,1,11,4,1,7,2,39,10,1,15,0,12,12,11,2,12,6,17,20,12,7,10,4,56,5,12,8,11,6,11,7,7,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,8,18,2,12,11,11,12,10,3,11,11,56,6,10,1,15,1,15,2,10,3,64,32,0,0,0,0,0,0,0,0,56,7,11,1,15,3,12,10,11,4,56,8,18,1,12,9,11,10,11,3,11,9,56,9,2,2,1,0,0,34,52,10,1,10,3,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,10,1,10,2,12,5,46,11,5,17,19,32,4,21,5,25,11,1,1,7,4,39,10,1,15,1,12,6,10,6,15,4,10,2,10,3,56,10,11,6,15,2,10,3,56,11,10,2,68,32,11,1,15,0,11,3,56,12,15,5,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,4,56,13,2,3,1,0,0,37,43,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,12,6,10,6,15,5,11,2,56,14,12,7,10,6,16,6,20,10,7,16,7,20,23,10,3,22,11,6,15,6,21,11,3,11,7,15,7,21,2,4,1,0,0,38,22,10,1,10,2,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,11,1,15,0,11,2,56,12,12,5,11,3,11,5,15,8,21,2,5,1,0,0,39,29,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,15,5,11,2,56,14,12,6,11,3,11,6,15,9,21,2,6,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,1,15,2,11,1,12,3,46,11,3,56,15,20,2,7,1,0,0,43,22,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,11,0,15,1,15,4,11,1,12,3,46,11,3,56,16,20,2,8,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,0,11,1,12,3,46,11,3,56,17,16,10,20,2,9,1,0,0,44,32,10,0,10,1,17,18,4,5,5,9,11,0,1,7,3,39,11,0,16,3,11,1,56,18,16,11,12,4,10,4,10,2,56,19,4,26,11,4,11,2,56,20,16,12,20,12,3,5,30,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,10,1,0,0,9,20,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,13,16,12,20,2,11,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,14,20,2,12,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,15,20,2,13,1,0,0,9,19,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,6,20,2,14,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,7,20,2,15,1,0,0,1,2,7,0,2,16,1,0,0,1,2,7,1,2,17,1,0,0,45,34,11,0,11,1,17,6,12,6,14,6,65,32,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,32,5,14,14,6,10,4,66,32,20,12,3,14,3,17,23,10,2,33,4,27,11,3,56,22,2,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,9,56,23,2,18,1,0,0,1,5,11,0,16,0,11,1,56,24,2,19,1,0,0,1,6,11,0,16,1,16,4,11,1,56,25,2,20,1,0,0,1,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,2,21,3,0,0,48,119,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,12,16,15,20,10,12,16,9,20,17,25,12,10,10,3,10,10,22,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,32,4,73,11,7,11,2,10,6,18,3,56,27,5,85,11,7,11,2,56,28,12,8,10,8,16,12,20,10,6,22,11,8,15,12,21,10,11,16,13,16,12,20,10,3,22,11,11,15,13,15,12,21,10,12,16,14,20,10,3,22,10,12,15,14,21,10,12,16,15,20,10,10,23,11,12,15,15,21,11,1,11,3,10,10,18,6,56,29,11,6,11,10,2,22,3,0,0,48,151,1,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,12,16,14,20,10,3,38,4,33,5,41,11,0,1,11,12,1,11,11,1,7,8,39,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,11,16,8,20,10,12,16,9,20,17,24,12,10,10,3,10,10,23,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,4,82,5,90,11,12,1,11,11,1,11,7,1,7,6,39,11,7,11,2,56,28,12,8,10,8,16,12,20,10,3,38,4,101,5,109,11,12,1,11,11,1,11,8,1,7,7,39,10,8,16,12,20,10,3,23,11,8,15,12,21,10,11,16,13,16,12,20,10,6,23,11,11,15,13,15,12,21,10,12,16,14,20,10,6,23,10,12,15,14,21,10,12,16,15,20,10,10,22,11,12,15,15,21,11,1,11,3,10,10,18,7,56,30,11,6,11,10,2,0,2,0,3,5,1,0,1,5,0,2,4,2,3,4,3,2,2,4,1,2,0,1,0,3,0,2,1,4,0,4,2,0,53,0,80,0],"rates":[161,28,235,11,6,0,0,0,8,1,0,6,2,6,4,3,10,70,5,80,48,7,128,1,185,2,8,185,3,32,6,217,3,68,12,157,4,128,5,0,13,0,11,0,16,1,0,8,0,0,6,0,1,0,0,2,0,1,0,0,5,2,1,0,0,1,3,1,0,0,3,4,1,0,0,4,4,1,0,1,7,6,1,0,1,8,6,3,0,1,9,6,1,0,1,10,6,1,0,2,12,7,1,0,2,14,5,1,0,2,15,7,1,0,2,17,7,1,0,3,7,8,0,13,15,1,15,4,7,8,0,13,15,15,4,15,15,15,15,3,15,15,15,0,2,7,8,0,13,2,15,15,6,15,15,15,15,15,15,7,15,15,15,15,15,15,15,7,83,116,111,114,97,103,101,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,21,99,97,108,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,3,109,105,110,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,128,81,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,3,29,10,0,10,1,17,8,12,6,11,0,11,1,17,6,12,4,11,6,11,4,17,13,12,5,10,5,10,2,22,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,27,10,5,11,5,11,2,22,17,12,12,3,11,3,2,1,1,0,0,8,39,10,0,10,1,11,2,17,0,12,8,11,0,11,1,17,7,12,7,12,6,12,5,12,4,10,8,10,7,35,4,23,11,4,11,8,11,5,17,13,22,12,3,5,37,11,4,11,5,22,11,6,11,8,10,7,23,17,11,11,7,23,17,12,17,13,22,12,3,11,3,2,2,1,0,0,7,17,10,0,10,1,11,3,17,0,12,5,11,0,11,1,17,9,12,4,11,2,11,5,17,11,11,4,23,17,13,17,13,2,3,1,0,0,7,20,11,0,11,1,23,7,1,17,10,12,4,7,1,10,4,23,12,5,11,2,11,5,24,11,3,11,4,24,22,7,1,26,2,4,1,0,0,9,69,11,0,11,1,23,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,10,17,11,2,10,5,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,6,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,23,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,7,5,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,2,10,2,17,13,7,0,7,0,24,26,12,4,10,4,10,2,17,13,7,0,26,12,3,10,5,10,6,24,11,4,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,10,5,11,6,24,11,7,24,11,3,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,9,17,11,11,2,11,5,24,7,0,26,22,11,8,22,11,9,22,2,5,1,0,0,1,12,11,2,11,0,11,1,23,24,7,0,26,12,3,17,11,11,3,22,2,0],"ray_math":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,40,5,42,13,7,55,59,8,114,32,6,146,1,146,1,12,164,2,247,5,0,7,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,4,2,1,0,0,1,2,1,0,0,2,2,1,0,0,6,1,1,0,0,0,1,3,0,0,1,15,2,15,15,1,2,4,15,2,15,15,4,108,111,103,50,3,109,97,120,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,208,121,0,161,63,121,92,118,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,249,214,165,42,128,81,101,243,159,91,61,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,1,0,0,0,2,7,0,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,10,11,0,11,1,24,7,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,7,0,26,2,3,1,0,0,0,10,11,0,7,0,24,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,11,1,26,2,4,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,6,1,0,0,4,59,10,0,7,0,38,4,5,5,7,7,4,39,10,0,7,0,26,17,7,12,2,10,2,77,7,0,24,12,3,11,0,11,2,48,12,4,10,4,7,0,33,4,27,11,3,2,7,1,12,1,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,57,5,34,10,4,11,4,24,7,0,26,12,4,10,4,7,2,38,4,52,11,3,10,1,22,12,3,11,4,49,1,48,12,4,11,1,49,1,48,12,1,5,29,11,3,2,7,1,0,0,3,112,49,0,12,1,10,0,49,128,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,16,11,0,49,128,48,12,0,11,1,49,128,22,12,1,10,0,49,64,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,30,11,0,49,64,48,12,0,11,1,49,64,22,12,1,10,0,49,32,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,44,11,0,49,32,48,12,0,11,1,49,32,22,12,1,10,0,49,16,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,58,11,0,49,16,48,12,0,11,1,49,16,22,12,1,10,0,49,8,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,72,11,0,49,8,48,12,0,11,1,49,8,22,12,1,10,0,49,4,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,0,49,4,48,12,0,11,1,49,4,22,12,1,10,0,49,2,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,100,11,0,49,2,48,12,0,11,1,49,2,22,12,1,11,0,49,1,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,110,11,1,49,1,22,12,1,11,1,2,0],"scaled_balance":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,25,5,29,6,7,35,75,8,110,32,12,142,1,39,0,6,0,4,0,0,0,1,0,0,2,0,1,0,0,1,0,1,0,1,3,0,1,0,1,5,0,1,0,2,15,15,1,15,0,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,2,4,11,0,11,1,17,4,2,1,1,0,0,2,4,11,0,11,1,17,3,2,2,1,0,0,2,4,11,0,11,1,17,3,2,0],"serde":[161,28,235,11,6,0,0,0,9,1,0,12,2,12,8,3,20,167,1,4,187,1,12,5,199,1,148,1,7,219,2,211,4,8,174,7,96,6,142,8,20,12,162,8,157,35,0,23,1,4,1,6,1,36,1,37,2,2,1,0,7,0,3,1,7,0,0,32,0,1,0,0,28,2,1,0,0,31,3,1,0,0,26,4,1,0,0,29,5,1,0,0,19,6,6,0,0,5,6,6,0,0,27,4,1,0,0,30,5,1,0,0,33,7,1,0,0,24,8,1,0,0,25,9,1,1,0,0,34,7,1,0,0,14,10,6,0,0,10,10,11,0,0,13,10,12,0,0,8,10,13,0,0,11,10,14,0,0,9,10,13,0,0,12,10,14,0,0,7,10,15,0,0,18,10,12,0,0,15,10,16,0,0,38,17,18,1,1,0,39,19,20,1,3,1,20,28,16,0,2,35,27,16,1,0,3,17,1,30,1,0,3,21,30,28,0,4,3,25,1,1,0,4,22,24,1,1,0,5,16,16,15,0,30,6,29,6,26,15,27,29,23,6,23,29,2,7,10,2,2,0,2,7,10,2,13,2,7,10,2,3,2,7,10,2,4,2,7,10,2,15,1,2,2,7,10,2,10,2,2,7,10,2,5,1,7,10,2,1,6,10,2,1,13,1,3,1,4,1,15,1,5,1,10,2,3,6,10,9,0,3,3,1,10,9,0,2,6,10,9,0,9,0,1,10,10,9,0,2,1,2,3,1,1,2,2,4,10,2,1,7,10,9,0,2,7,10,9,0,10,9,0,2,15,10,2,1,6,9,0,1,8,0,1,9,0,1,8,1,2,4,3,2,15,3,3,10,2,3,3,3,1,3,10,9,0,3,3,10,10,9,0,3,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,6,97,112,112,101,110,100,5,97,115,99,105,105,16,97,115,99,105,105,95,116,111,95,104,101,120,95,115,116,114,3,98,99,115,19,100,101,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,16,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,29,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,29,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,30,100,101,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,17,103,101,116,95,118,101,99,116,111,114,95,108,101,110,103,116,104,16,104,101,120,95,115,116,114,95,116,111,95,97,115,99,105,105,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,7,114,101,118,101,114,115,101,5,115,101,114,100,101,17,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,14,115,101,114,105,97,108,105,122,101,95,116,121,112,101,14,115,101,114,105,97,108,105,122,101,95,117,49,50,56,27,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,27,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,28,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,6,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,12,118,101,99,116,111,114,95,115,112,108,105,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,68,6,2,1,1,0,0,1,15,10,0,10,1,49,8,48,72,255,0,28,51,17,0,11,0,11,1,72,255,0,28,51,17,0,2,2,1,0,0,1,63,10,0,10,1,49,56,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,6,255,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,6,255,0,0,0,0,0,0,0,28,51,17,0,2,3,1,0,0,1,127,10,0,10,1,49,120,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,4,1,0,0,1,255,1,10,0,10,1,49,248,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,240,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,232,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,224,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,216,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,208,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,200,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,192,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,184,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,176,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,168,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,160,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,152,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,144,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,136,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,128,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,120,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,5,1,0,0,21,31,10,0,49,0,38,4,9,10,0,49,9,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,22,12,2,5,29,10,0,49,15,37,4,23,5,25,7,1,39,11,0,49,87,22,12,2,11,2,2,6,1,0,0,22,40,10,0,49,48,38,4,9,10,0,49,57,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,3,5,38,10,0,49,97,38,4,27,10,0,49,102,37,12,2,5,29,9,12,2,11,2,4,32,5,34,7,1,39,11,0,49,87,23,12,3,11,3,2,7,1,0,0,23,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,8,1,0,0,26,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,9,1,0,0,1,4,11,0,11,1,56,1,2,10,1,0,0,16,17,14,1,56,2,12,2,14,2,65,6,6,32,0,0,0,0,0,0,0,33,4,9,5,13,11,0,1,7,0,39,11,0,11,2,56,1,2,11,1,0,0,28,8,56,3,17,28,12,1,11,0,11,1,17,25,17,9,2,12,1,0,0,12,17,14,1,65,6,12,2,10,2,6,0,0,0,0,0,0,0,0,33,4,10,11,0,1,2,10,0,11,2,17,2,11,0,11,1,17,9,2,13,1,0,0,1,15,10,0,65,6,6,1,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,6,0,0,0,0,0,0,0,0,66,6,20,2,14,1,0,0,1,24,10,0,65,6,6,2,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,75,49,8,47,11,0,6,1,0,0,0,0,0,0,0,66,6,20,75,22,2,15,1,0,0,1,72,10,0,65,6,6,8,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,52,49,56,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,52,49,48,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,52,49,40,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,52,49,32,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,52,49,24,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,52,49,16,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,52,49,8,47,22,11,0,6,7,0,0,0,0,0,0,0,66,6,20,52,22,2,16,1,0,0,1,136,1,10,0,65,6,6,16,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,53,49,120,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,53,49,112,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,53,49,104,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,53,49,96,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,53,49,88,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,53,49,80,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,53,49,72,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,53,49,64,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,53,49,56,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,53,49,48,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,53,49,40,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,53,49,32,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,53,49,24,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,53,49,16,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,53,49,8,47,22,11,0,6,15,0,0,0,0,0,0,0,66,6,20,53,22,2,17,1,0,0,1,136,2,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,77,49,248,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,77,49,240,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,77,49,232,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,77,49,224,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,77,49,216,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,77,49,208,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,77,49,200,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,77,49,192,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,77,49,184,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,77,49,176,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,77,49,168,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,77,49,160,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,77,49,152,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,77,49,144,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,77,49,136,47,22,10,0,6,15,0,0,0,0,0,0,0,66,6,20,77,49,128,47,22,10,0,6,16,0,0,0,0,0,0,0,66,6,20,77,49,120,47,22,10,0,6,17,0,0,0,0,0,0,0,66,6,20,77,49,112,47,22,10,0,6,18,0,0,0,0,0,0,0,66,6,20,77,49,104,47,22,10,0,6,19,0,0,0,0,0,0,0,66,6,20,77,49,96,47,22,10,0,6,20,0,0,0,0,0,0,0,66,6,20,77,49,88,47,22,10,0,6,21,0,0,0,0,0,0,0,66,6,20,77,49,80,47,22,10,0,6,22,0,0,0,0,0,0,0,66,6,20,77,49,72,47,22,10,0,6,23,0,0,0,0,0,0,0,66,6,20,77,49,64,47,22,10,0,6,24,0,0,0,0,0,0,0,66,6,20,77,49,56,47,22,10,0,6,25,0,0,0,0,0,0,0,66,6,20,77,49,48,47,22,10,0,6,26,0,0,0,0,0,0,0,66,6,20,77,49,40,47,22,10,0,6,27,0,0,0,0,0,0,0,66,6,20,77,49,32,47,22,10,0,6,28,0,0,0,0,0,0,0,66,6,20,77,49,24,47,22,10,0,6,29,0,0,0,0,0,0,0,66,6,20,77,49,16,47,22,10,0,6,30,0,0,0,0,0,0,0,66,6,20,77,49,8,47,22,11,0,6,31,0,0,0,0,0,0,0,66,6,20,77,22,2,18,1,0,0,31,29,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,53,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,19,1,0,0,32,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,77,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,20,1,0,0,1,14,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,20,17,31,2,21,1,0,0,16,8,11,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,2,22,1,0,0,33,46,10,0,65,6,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,64,6,0,0,0,0,0,0,0,0,2,10,3,6,8,0,0,0,0,0,0,0,36,4,16,5,20,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,12,2,11,3,10,2,6,8,0,0,0,0,0,0,0,22,33,4,35,5,39,11,0,1,7,0,39,11,0,6,8,0,0,0,0,0,0,0,11,2,6,8,0,0,0,0,0,0,0,22,56,4,2,23,1,0,0,34,43,10,1,10,2,35,4,10,10,2,10,0,65,29,37,12,3,5,12,9,12,3,11,3,4,15,5,19,11,0,1,7,0,39,64,29,0,0,0,0,0,0,0,0,12,5,11,1,12,4,10,4,10,2,35,4,39,5,28,13,5,10,0,10,4,66,29,20,68,29,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,23,11,0,1,11,5,2,24,1,0,0,35,53,64,18,0,0,0,0,0,0,0,0,12,3,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,29,35,4,38,5,12,10,0,10,2,66,29,20,10,1,33,4,33,10,4,10,2,35,4,29,13,3,10,0,11,4,10,2,56,5,68,18,10,2,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,10,4,10,2,35,4,49,13,3,11,0,11,4,11,2,56,5,68,18,5,51,11,0,1,11,3,2,0],"system_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,71,4,81,2,5,83,78,7,161,1,150,2,8,183,3,32,6,215,3,26,12,241,3,169,2,0,16,0,6,0,11,1,0,7,0,0,9,0,1,0,0,10,0,1,0,0,7,2,3,0,0,1,3,2,0,1,2,3,7,0,1,8,7,3,0,2,3,13,14,0,2,4,13,15,0,2,5,13,1,0,2,12,5,0,0,2,13,6,0,0,2,14,9,0,0,2,15,8,0,0,2,17,11,12,1,1,13,1,0,1,2,4,13,3,8,0,2,1,10,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,12,10,2,10,2,10,2,10,2,8,0,13,3,3,3,3,13,2,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,11,68,111,108,97,65,100,100,114,101,115,115,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,19,101,110,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,115,121,115,116,101,109,95,99,111,100,101,99,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,4,24,64,1,0,0,0,0,0,0,0,0,12,5,13,5,11,0,17,9,13,5,11,1,17,10,11,2,17,5,12,4,13,5,14,4,65,1,75,17,9,13,5,11,4,17,12,13,5,11,3,17,11,11,5,2,3,1,0,0,10,96,14,0,65,1,12,9,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,1,14,1,17,6,12,11,11,8,11,7,22,12,8,6,8,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,2,14,2,17,7,12,10,11,8,11,7,22,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,3,14,3,17,6,12,6,11,8,11,7,22,12,8,11,6,52,12,7,14,0,10,8,10,8,10,7,22,56,0,17,4,12,5,11,8,11,7,22,12,8,6,1,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,4,14,4,17,8,12,12,11,8,11,7,22,12,8,11,9,11,8,33,4,89,5,91,7,0,39,11,11,11,10,11,5,11,12,2,0],"system_core_storage":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,24,3,36,26,4,62,2,5,64,35,7,99,252,1,8,223,2,64,10,159,3,9,12,168,3,34,13,202,3,2,15,204,3,2,0,16,0,7,0,8,1,13,1,18,1,19,0,2,8,0,1,0,12,0,1,3,12,0,2,1,0,0,3,5,4,0,5,4,2,0,0,11,0,1,0,0,9,2,3,0,1,14,0,6,0,3,12,4,5,0,4,15,8,1,1,8,4,7,3,6,8,3,7,8,2,7,8,5,0,1,6,8,0,1,6,8,1,1,7,8,5,1,8,4,1,8,1,1,8,0,1,9,0,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,7,83,116,111,114,97,103,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,3,110,101,119,6,111,98,106,101,99,116,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,10,8,4,6,8,1,0,1,0,0,1,9,10,2,17,3,11,0,11,1,11,2,17,2,18,0,56,0,2,1,3,0,0,1,3,11,0,16,0,2,0,1,0,17,0],"system_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,24,2,24,40,3,64,71,4,135,1,2,5,137,1,117,7,254,1,155,4,8,153,6,96,6,249,6,10,10,131,7,17,12,148,7,191,1,0,33,0,10,0,16,0,19,0,31,0,32,0,38,0,39,1,14,1,18,1,34,2,30,0,7,3,0,1,0,12,0,2,3,7,0,3,4,8,0,5,6,8,0,6,9,12,0,7,2,12,0,8,1,8,0,10,8,2,0,11,5,12,0,0,11,0,1,0,0,35,0,1,0,2,22,13,8,0,2,23,13,14,0,3,13,3,1,0,4,15,8,9,0,4,21,1,10,0,4,24,1,10,0,5,20,4,5,0,6,11,12,1,0,6,27,11,1,0,6,35,12,1,0,7,26,6,7,0,9,17,16,1,1,3,13,15,8,6,8,3,7,8,5,7,8,9,7,8,6,6,8,4,10,2,6,8,7,7,8,8,0,6,10,2,8,2,2,3,8,2,13,1,6,8,3,1,6,8,4,1,6,8,1,6,7,8,9,7,8,6,6,8,1,10,2,6,8,7,7,8,8,2,8,2,10,2,1,10,2,4,13,3,8,2,2,1,2,2,7,8,5,8,2,3,7,8,5,8,2,8,2,1,6,8,2,1,13,1,8,0,1,9,0,6,10,2,2,3,8,2,13,8,2,6,65,112,112,67,97,112,5,67,108,111,99,107,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,5,83,116,97,116,101,7,83,116,111,114,97,103,101,15,83,121,115,116,101,109,67,111,114,101,69,118,101,110,116,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,11,97,112,112,95,109,97,110,97,103,101,114,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,110,111,110,99,101,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,12,115,121,115,116,101,109,95,99,111,100,101,99,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,0,2,6,25,3,28,10,2,29,13,37,13,36,10,2,12,2,0,1,4,0,2,51,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,12,11,8,17,5,12,10,12,9,12,11,12,13,10,10,17,6,33,4,23,5,27,11,1,1,7,0,39,10,12,10,9,33,4,35,11,1,10,12,17,10,5,39,11,1,10,12,10,9,17,9,11,11,14,12,17,2,11,13,14,9,17,3,14,9,17,2,11,10,18,0,56,0,2,1,1,4,0,17,43,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,11,11,8,17,5,12,9,12,13,12,10,12,12,10,9,17,7,33,4,23,5,27,11,1,1,7,0,39,11,1,10,11,10,13,17,11,11,10,14,11,17,2,11,12,14,13,17,3,14,13,17,2,11,9,18,0,56,0,2,0],"system_portal":[161,28,235,11,6,0,0,0,10,1,0,18,2,18,28,3,46,82,4,128,1,4,5,132,1,84,7,216,1,208,3,8,168,5,64,10,232,5,22,12,254,5,187,1,13,185,7,2,0,30,0,13,0,16,0,29,0,37,1,15,1,25,1,31,1,32,0,3,8,0,0,2,3,0,1,0,7,0,2,1,8,0,4,6,12,0,6,5,4,0,8,4,2,0,0,21,0,1,0,0,18,2,3,0,0,8,4,1,0,0,34,4,1,0,1,11,11,12,0,1,12,13,12,0,2,10,9,1,0,3,17,1,16,0,3,19,1,16,0,4,7,15,1,0,4,26,14,1,0,4,33,15,1,0,5,14,7,1,1,3,6,22,0,5,0,7,28,7,1,1,8,8,27,10,11,0,14,6,12,17,1,7,8,6,0,1,7,8,0,1,3,6,6,8,3,7,8,0,7,8,4,13,10,2,7,8,6,1,8,5,1,8,0,1,9,0,3,8,2,5,8,2,1,6,8,3,1,6,8,6,1,5,1,8,2,2,13,10,2,2,7,8,4,8,2,3,7,8,4,8,2,8,2,1,2,1,8,1,3,5,8,2,8,2,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,83,121,115,116,101,109,76,111,99,97,108,69,118,101,110,116,12,83,121,115,116,101,109,80,111,114,116,97,108,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,7,98,105,110,100,105,110,103,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,2,105,100,4,105,110,105,116,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,6,111,98,106,101,99,116,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,115,121,115,116,101,109,95,99,111,100,101,99,13,115,121,115,116,101,109,95,112,111,114,116,97,108,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,117,110,98,105,110,100,105,110,103,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,20,8,5,23,3,1,2,5,24,3,27,5,36,13,35,10,2,9,2,0,0,0,0,1,6,11,0,17,13,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,4,0,8,34,11,0,17,6,11,5,46,17,15,12,7,10,7,17,4,12,8,10,3,10,4,17,5,12,6,10,8,10,6,33,4,21,11,2,11,8,17,10,5,25,11,2,11,8,11,6,17,9,11,1,17,1,11,7,11,3,11,4,17,7,18,1,56,1,2,3,1,4,0,18,26,11,0,17,6,11,5,46,17,15,12,6,10,6,17,4,12,8,10,3,10,4,17,5,12,7,11,2,11,8,11,7,17,11,11,1,17,1,11,6,11,3,11,4,17,8,18,1,56,1,2,0,1,0],"user_manager":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,40,3,58,138,1,4,196,1,42,5,238,1,128,2,7,238,3,161,5,8,143,9,96,6,239,9,60,10,171,10,49,12,220,10,247,4,13,211,15,8,15,219,15,8,0,48,0,15,0,20,1,49,2,19,2,31,2,39,2,40,2,41,0,8,12,0,0,7,4,0,0,0,3,0,0,6,3,0,1,1,7,0,2,2,0,0,5,5,4,0,6,3,12,2,7,1,4,1,8,4,2,0,0,26,0,1,0,0,33,2,1,0,0,43,3,1,0,0,22,4,5,0,0,23,6,7,0,0,32,4,8,0,0,27,4,9,0,0,34,10,1,0,0,10,11,1,0,0,42,11,1,0,1,21,28,29,0,1,44,30,8,0,3,25,37,38,1,0,3,35,39,18,1,0,4,18,18,1,1,3,5,30,0,12,0,6,9,21,1,2,7,4,6,11,20,25,2,7,4,6,12,22,35,2,7,4,6,14,20,9,2,7,4,6,29,32,5,2,7,4,6,30,0,14,2,7,4,6,35,22,23,2,7,4,7,36,18,1,1,8,21,13,21,15,21,16,23,17,19,16,16,16,22,16,19,13,17,13,19,15,17,15,17,16,20,15,16,13,16,15,14,33,18,15,12,8,22,13,13,8,14,40,1,7,8,8,0,4,6,8,5,7,8,0,13,13,3,6,8,5,7,8,0,13,2,6,8,0,8,4,1,3,2,6,8,0,3,1,10,8,4,1,8,4,1,1,2,7,8,0,8,4,3,7,8,0,8,4,8,4,1,8,6,2,8,4,3,1,11,7,2,9,0,9,1,2,3,10,8,4,2,13,13,1,8,0,1,9,0,2,13,7,11,7,2,13,13,2,6,11,7,2,9,0,9,1,9,0,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,9,1,2,8,4,6,8,1,1,6,9,1,1,6,8,1,3,8,4,6,11,7,2,13,13,13,1,6,8,4,1,13,2,8,4,13,6,8,4,8,4,3,8,4,10,8,4,7,8,1,1,6,11,7,2,9,0,9,1,1,8,2,7,8,4,8,4,8,4,8,4,3,7,10,8,4,7,8,1,1,7,9,1,10,8,4,8,4,8,4,6,8,4,3,3,3,8,4,7,10,8,4,7,8,1,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,1,8,3,8,66,105,110,100,85,115,101,114,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,10,85,110,98,105,110,100,85,115,101,114,18,85,115,101,114,65,100,100,114,101,115,115,67,97,116,97,108,111,103,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,97,100,100,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,97,105,110,95,105,100,95,116,111,95,103,114,111,117,112,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,17,100,111,108,97,95,117,115,101,114,95,97,100,100,114,101,115,115,12,100,111,108,97,95,117,115,101,114,95,105,100,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,18,103,101,116,95,117,115,101,114,95,97,100,100,114,101,115,115,101,115,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,16,112,114,111,99,101,115,115,95,103,114,111,117,112,95,105,100,22,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,115,121,115,116,101,109,95,112,111,114,116,97,108,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,24,117,110,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,115,101,114,95,97,100,100,114,101,115,115,95,99,97,116,97,108,111,103,23,117,115,101,114,95,97,100,100,114,101,115,115,95,116,111,95,117,115,101,114,95,105,100,20,117,115,101,114,95,105,100,95,116,111,95,97,100,100,114,101,115,115,101,115,12,117,115,101,114,95,109,97,110,97,103,101,114,6,118,101,99,116,111,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,3,24,8,6,45,8,1,13,11,7,2,13,13,1,2,2,46,11,7,2,8,4,3,47,11,7,2,3,10,8,4,2,2,2,16,8,4,17,3,3,2,2,16,8,4,17,3,0,0,0,0,1,12,10,0,17,15,10,0,56,0,10,0,56,1,18,1,11,0,56,2,18,0,56,3,2,1,1,0,0,19,21,11,1,15,0,12,5,10,5,10,2,12,4,46,11,4,56,4,32,4,12,5,16,11,5,1,7,3,39,11,5,11,2,11,3,56,5,2,2,1,0,0,19,20,11,1,15,0,12,4,10,4,10,2,12,3,46,11,3,56,4,4,11,5,15,11,4,1,7,4,39,11,4,11,2,56,6,1,2,3,1,0,0,24,23,10,0,11,1,17,5,12,2,11,0,16,1,12,3,10,3,16,2,10,2,56,7,4,13,5,17,11,3,1,7,1,39,11,3,16,2,11,2,56,8,20,2,4,1,0,0,26,19,11,0,16,1,12,2,10,2,16,3,10,1,56,9,4,9,5,13,11,2,1,7,1,39,11,2,16,3,11,1,56,10,20,2,5,1,0,0,27,24,14,1,17,10,12,4,11,0,16,0,12,3,10,3,10,4,56,4,4,18,11,1,11,3,11,4,56,11,20,17,11,12,2,5,22,11,3,1,11,1,12,2,11,2,2,6,1,0,0,8,10,10,0,11,1,17,5,12,2,11,0,16,1,16,2,11,2,56,7,2,7,3,0,0,31,50,10,0,11,1,12,2,46,11,2,17,5,12,5,11,0,15,1,12,7,10,7,15,2,10,5,12,3,46,11,3,56,7,32,4,20,5,24,11,7,1,7,0,39,10,7,16,3,56,12,6,1,0,0,0,0,0,0,0,22,12,4,64,8,0,0,0,0,0,0,0,0,12,6,10,7,15,2,10,5,10,4,56,13,13,6,10,5,68,8,11,7,15,3,10,4,11,6,56,14,11,5,11,4,18,2,56,15,2,8,3,0,0,34,49,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,11,2,12,4,46,11,4,17,5,12,6,11,0,15,1,12,9,10,9,15,2,10,6,12,5,46,11,5,56,7,32,4,27,5,31,11,9,1,7,0,39,10,9,15,3,10,7,56,16,12,8,11,9,15,2,10,6,10,7,56,13,11,8,10,6,68,8,11,6,11,7,18,2,56,15,2,9,3,0,0,36,73,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,10,2,12,4,46,11,4,17,3,12,9,10,7,10,9,33,4,19,5,23,11,0,1,7,5,39,10,0,11,2,12,5,46,11,5,17,5,12,10,11,0,15,1,12,12,10,12,15,3,11,9,56,16,12,11,10,11,46,65,8,6,2,0,0,0,0,0,0,0,38,4,45,5,51,11,12,1,11,11,1,7,2,39,10,11,14,10,12,6,46,11,6,56,17,12,8,1,11,12,15,2,10,10,56,18,1,11,11,11,8,56,19,1,11,10,11,7,18,3,56,20,2,0,2,0,1,1,0,1,1,0,28,0,37,0,38,0,50,0],"wormhole_adapter_core":[161,28,235,11,6,0,0,0,12,1,0,46,2,46,114,3,160,1,202,1,4,234,2,18,5,252,2,140,3,7,136,6,150,10,8,158,16,96,6,254,16,30,10,156,17,68,12,224,17,166,4,13,134,22,6,15,140,22,6,0,88,0,27,0,36,0,46,0,60,0,61,0,85,0,89,1,29,1,30,1,44,1,57,1,58,1,79,1,83,1,84,1,87,2,28,2,40,2,45,2,64,2,78,2,86,0,4,12,0,0,15,3,0,0,5,3,0,0,16,3,0,0,6,3,0,0,17,3,0,0,7,3,0,1,0,12,0,2,8,7,0,3,11,0,0,5,14,12,0,6,23,12,0,7,22,12,0,8,2,8,0,9,3,12,1,0,1,11,21,4,0,12,13,12,2,7,1,12,1,13,18,2,0,15,20,2,0,16,25,7,2,1,0,0,0,17,1,7,0,18,9,12,0,19,10,7,0,20,12,0,0,21,19,12,0,22,24,0,0,0,51,0,1,0,0,69,2,1,0,0,35,3,1,0,0,73,4,1,0,0,71,4,1,0,0,74,4,1,0,0,72,4,1,0,0,66,5,6,0,0,65,7,8,0,0,67,5,6,0,0,77,9,10,0,1,47,43,44,0,4,33,24,46,0,4,34,24,42,0,4,42,33,24,0,4,43,52,24,0,4,48,1,32,0,4,49,1,32,0,5,26,47,48,0,5,76,47,48,0,6,53,49,23,0,6,68,50,1,0,7,59,40,41,0,10,39,21,1,1,3,11,56,12,13,0,12,56,12,17,2,7,12,14,63,21,1,1,12,16,32,22,23,2,1,0,16,41,1,19,2,1,0,16,52,27,1,2,1,0,16,75,29,30,2,1,0,17,56,24,25,0,18,56,14,15,0,19,56,25,26,0,19,82,26,24,0,20,62,34,35,0,20,64,36,10,0,22,81,41,24,0,25,16,28,18,26,20,27,18,29,18,23,28,30,18,23,37,23,38,3,6,8,9,7,8,24,7,8,18,0,4,6,8,9,7,8,0,13,10,2,3,6,8,9,7,8,0,13,7,6,8,9,7,8,24,7,8,0,13,15,11,14,1,8,17,6,8,13,6,7,8,24,7,8,0,6,8,7,10,2,6,8,13,7,8,18,2,8,8,10,2,8,7,8,24,7,8,0,6,8,7,10,2,7,8,10,7,8,11,6,8,13,7,8,18,4,8,8,8,8,15,10,2,11,7,8,24,7,8,0,6,8,7,7,8,10,8,8,8,8,13,3,15,11,14,1,8,17,6,8,13,1,3,3,7,8,24,7,8,18,8,15,1,7,8,18,1,8,15,2,6,8,24,7,8,18,1,8,21,2,8,20,8,12,1,11,16,2,9,0,9,1,2,13,8,22,1,11,19,2,9,0,9,1,1,8,0,1,9,0,2,6,11,19,2,9,0,9,1,6,9,0,1,1,1,10,2,1,8,20,1,8,22,3,7,11,19,2,9,0,9,1,9,0,9,1,1,8,1,2,7,11,19,2,9,0,9,1,6,9,0,2,9,0,9,1,2,8,23,10,2,1,2,3,13,15,2,3,7,8,21,14,10,2,1,8,23,4,7,8,24,11,14,1,8,17,8,23,6,8,13,1,8,5,1,8,6,3,13,10,2,8,8,6,7,8,24,6,11,19,2,13,8,22,7,11,16,2,8,20,8,12,10,2,6,8,13,7,8,18,1,8,25,4,8,8,13,2,10,2,1,6,8,7,1,13,7,8,8,15,3,13,10,2,8,8,8,8,6,8,8,8,8,3,13,2,10,2,4,7,8,10,8,8,13,15,2,15,15,2,6,8,11,8,8,2,7,8,11,8,8,3,15,8,23,10,2,5,13,3,8,8,8,8,3,6,65,112,112,67,97,112,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,12,68,101,108,101,116,101,66,114,105,100,103,101,11,68,101,108,101,116,101,79,119,110,101,114,13,68,101,108,101,116,101,83,112,101,110,100,101,114,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,14,82,101,103,105,115,116,101,114,66,114,105,100,103,101,13,82,101,103,105,115,116,101,114,79,119,110,101,114,15,82,101,103,105,115,116,101,114,83,112,101,110,100,101,114,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,86,65,65,6,86,101,99,77,97,112,13,97,100,100,95,108,105,113,117,105,100,105,116,121,11,97,112,112,95,109,97,110,97,103,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,8,99,111,110,116,97,105,110,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,20,100,101,108,101,116,101,95,114,101,109,111,116,101,95,98,114,105,100,103,101,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,13,100,111,108,97,95,99,111,110,116,114,97,99,116,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,6,105,110,115,101,114,116,12,105,115,95,100,111,108,97,95,117,115,101,114,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,10,112,111,111,108,95,99,111,100,101,99,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,22,114,101,103,105,115,116,101,114,95,114,101,109,111,116,101,95,98,114,105,100,103,101,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,19,114,101,109,111,116,101,95,100,101,108,101,116,101,95,111,119,110,101,114,21,114,101,109,111,116,101,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,21,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,23,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,5,115,116,97,116,101,3,115,117,105,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,3,118,97,97,7,118,101,99,95,109,97,112,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,24,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,22,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,99,104,97,105,110,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,4,50,8,15,90,8,21,31,11,16,2,8,20,8,12,70,11,19,2,13,8,22,1,2,2,92,13,91,10,2,2,2,2,92,13,91,10,2,3,2,2,37,13,38,15,4,2,2,37,13,38,15,5,2,2,37,13,38,15,6,2,2,37,13,38,15,0,1,0,0,11,18,10,2,17,24,12,5,11,1,10,2,12,4,12,3,11,5,11,3,46,11,4,17,32,11,2,56,0,56,1,18,0,56,2,2,1,1,0,0,1,23,10,1,16,0,14,2,56,3,32,4,7,5,11,11,1,1,7,1,39,11,1,15,0,10,2,10,3,17,31,17,33,56,4,11,2,11,3,18,1,56,5,2,2,1,0,0,26,22,10,1,16,0,14,2,56,3,4,6,5,10,11,1,1,7,0,39,11,1,15,0,14,2,56,6,12,3,1,11,2,11,3,17,34,18,1,56,5,2,3,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,4,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,5,1,0,0,31,22,10,3,10,4,17,17,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,35,12,7,11,1,11,5,11,7,11,6,17,36,1,11,3,11,4,18,5,56,7,2,6,1,0,0,31,22,10,3,10,4,17,16,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,35,12,7,11,1,11,5,11,7,11,6,17,36,1,11,3,11,4,18,6,56,8,2,7,3,0,0,39,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,22,17,37,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,8,3,0,0,45,59,11,0,10,1,16,0,11,1,15,2,11,3,11,6,11,7,17,22,17,37,17,12,12,12,1,12,11,12,10,12,14,12,13,10,2,17,11,11,11,33,4,23,5,31,11,5,1,11,4,1,11,2,1,7,2,39,11,4,10,13,11,2,17,11,11,10,77,17,18,1,12,9,10,5,10,14,12,8,46,11,8,17,20,32,4,52,11,5,10,14,17,21,5,54,11,5,1,11,13,11,14,11,9,11,12,2,9,3,0,0,39,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,22,17,37,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,10,3,0,0,51,28,11,3,10,4,11,2,17,11,11,8,17,19,1,12,11,11,6,11,7,11,4,11,5,11,11,52,17,15,12,13,11,1,15,1,73,0,0,0,0,11,13,17,35,12,12,11,0,11,9,11,12,11,10,17,36,2,0,3,0,1,0,2,0,54,0,55,0,80,0],"wormhole_adapter_pool":[161,28,235,11,6,0,0,0,12,1,0,42,2,42,92,3,134,1,142,1,4,148,2,16,5,164,2,185,2,7,221,4,171,6,8,136,11,96,6,232,11,50,10,154,12,51,12,205,12,167,2,13,244,14,10,15,254,14,2,0,71,0,29,0,30,0,37,0,52,0,72,1,23,1,24,1,35,1,48,1,49,1,64,1,66,1,67,1,69,2,21,2,33,2,36,2,54,2,63,2,68,0,10,8,0,0,11,8,0,0,12,3,0,1,3,7,0,2,9,12,1,0,1,3,6,8,0,5,17,12,0,6,1,8,0,7,2,12,1,0,1,9,16,4,0,10,8,12,2,7,1,12,1,11,13,2,0,13,15,2,0,14,19,7,2,1,0,0,0,15,0,7,0,16,4,12,0,17,5,7,0,18,7,0,0,19,14,12,0,20,18,0,0,0,41,0,1,0,0,42,2,1,0,0,58,3,1,1,0,0,59,4,5,0,0,55,6,1,1,0,1,38,36,17,0,1,39,36,37,0,2,28,25,17,1,0,2,59,29,17,0,2,70,35,1,1,0,3,22,31,1,0,4,27,17,34,0,5,50,32,33,0,8,32,11,1,1,3,9,46,0,7,0,10,46,0,22,2,7,12,12,61,11,1,1,8,13,60,8,9,0,14,34,1,16,2,1,0,14,43,20,1,2,1,0,15,46,17,18,0,16,46,13,14,0,17,46,18,19,0,18,53,26,27,0,18,54,28,5,0,20,65,33,17,0,16,10,18,15,19,15,15,21,16,23,7,11,9,11,13,38,1,7,8,12,0,5,7,8,0,13,10,2,7,8,18,7,8,12,9,7,8,1,7,8,18,11,8,1,8,11,7,11,4,1,9,0,11,8,1,9,0,13,10,2,6,8,7,7,8,12,7,7,8,1,7,8,18,11,8,1,8,11,13,10,2,6,8,7,7,8,12,1,3,7,6,8,5,7,8,18,7,8,1,7,11,4,1,9,0,10,2,6,8,7,7,8,12,1,8,9,1,6,8,12,1,5,1,8,0,1,9,0,3,7,8,12,11,13,2,13,8,16,8,15,2,6,8,18,7,8,12,1,8,15,2,13,8,16,1,11,13,2,9,0,9,1,1,10,2,1,8,14,1,8,16,3,7,11,13,2,9,0,9,1,9,0,9,1,2,8,14,8,6,1,11,10,2,9,0,9,1,1,8,1,2,8,17,10,2,5,7,11,4,1,9,0,11,8,1,9,0,13,10,2,7,8,12,3,7,8,15,14,10,2,1,8,17,4,7,8,18,11,8,1,8,11,8,17,6,8,7,3,13,10,2,7,8,12,5,3,3,8,3,8,3,13,1,6,8,5,6,7,8,18,6,11,13,2,13,8,16,7,11,10,2,8,14,8,6,10,2,6,8,7,7,8,12,1,8,19,6,13,3,8,3,8,3,3,2,5,7,11,4,1,9,0,8,3,3,8,3,7,8,12,1,6,8,3,1,13,1,8,2,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,4,80,111,111,108,11,80,111,111,108,71,101,110,101,115,105,115,9,80,111,111,108,83,116,97,116,101,17,80,111,111,108,87,105,116,104,100,114,97,119,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,6,97,109,111,117,110,116,7,98,121,116,101,115,51,50,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,7,99,114,101,97,116,111,114,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,12,100,115,116,95,99,104,97,105,110,95,105,100,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,4,105,110,105,116,10,105,110,105,116,105,97,108,105,122,101,6,105,110,115,101,114,116,7,105,115,95,105,110,105,116,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,5,110,111,110,99,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,12,112,111,111,108,95,97,100,100,114,101,115,115,10,112,111,111,108,95,99,111,100,101,99,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,12,115,101,110,100,95,100,101,112,111,115,105,116,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,3,115,117,105,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,40,8,9,26,5,44,1,1,2,4,40,8,9,73,8,15,25,11,10,2,8,14,8,6,57,11,13,2,13,8,16,2,2,6,47,3,62,13,31,13,51,10,2,56,10,2,20,3,0,0,0,0,1,9,10,0,17,14,11,0,46,17,17,9,18,0,56,0,2,1,1,4,0,12,59,10,0,16,0,20,10,4,46,17,17,33,4,9,5,17,11,3,1,11,0,1,11,4,1,7,2,39,10,0,16,1,20,32,4,23,5,31,11,3,1,11,0,1,11,4,1,7,3,39,11,3,10,4,12,5,46,11,5,17,21,12,7,56,1,12,6,13,6,11,1,11,2,17,20,17,22,56,2,10,4,17,14,11,7,11,4,56,3,11,6,18,1,56,4,8,11,0,15,1,21,2,2,3,0,0,24,20,11,3,11,4,11,5,11,6,11,8,56,5,12,10,11,0,15,2,73,0,0,0,0,11,10,17,23,12,9,11,1,11,2,11,9,11,7,17,24,1,2,3,3,0,0,24,17,11,3,11,4,11,6,17,8,12,8,11,0,15,2,73,0,0,0,0,11,8,17,23,12,7,11,1,11,2,11,7,11,5,17,24,2,4,1,4,0,30,37,11,0,17,10,11,1,10,2,16,3,11,2,15,4,11,4,11,5,10,6,17,12,17,25,17,11,1,12,7,12,10,12,9,12,8,12,11,11,3,10,10,10,7,10,9,11,6,56,6,11,8,11,11,14,9,17,6,14,9,17,5,14,10,17,5,11,7,18,2,56,7,2,0,1,0,2,1,1,1,3,1,2,0,45,0],"wormhole_adapter_verify":[161,28,235,11,6,0,0,0,10,1,0,22,2,22,54,3,76,102,4,178,1,16,5,194,1,206,1,7,144,3,135,3,8,151,6,128,1,6,151,7,30,10,181,7,6,12,187,7,205,1,0,38,1,29,2,14,2,27,2,28,2,35,2,37,3,13,3,19,3,34,3,36,0,8,12,0,1,4,7,1,0,0,2,1,8,0,3,7,4,0,4,3,12,2,7,1,12,1,5,6,2,0,6,10,7,2,1,0,0,0,7,0,7,0,8,2,7,0,9,5,12,0,10,9,0,0,0,22,0,1,0,0,12,2,3,0,0,30,4,5,0,0,32,6,3,0,0,31,7,5,0,1,20,19,13,1,0,1,24,18,10,1,0,1,26,3,14,1,0,1,33,13,14,1,0,3,25,25,26,0,4,11,27,3,2,7,12,4,15,24,10,2,7,12,6,15,9,10,2,1,0,6,21,9,11,2,1,0,10,16,16,22,0,10,17,16,12,0,10,18,16,17,0,10,30,21,5,0,12,8,13,8,8,12,7,12,6,12,5,12,11,23,10,23,2,6,11,6,2,13,8,8,6,13,1,11,1,1,8,8,2,6,11,6,2,13,8,8,6,8,10,0,4,7,8,9,6,11,6,2,13,8,8,10,2,6,8,2,1,8,10,3,7,11,4,2,8,7,8,0,6,8,10,7,8,5,6,7,8,9,6,11,6,2,13,8,8,7,11,4,2,8,7,8,0,10,2,6,8,2,7,8,5,2,13,8,8,2,6,11,6,2,9,0,9,1,6,9,0,1,1,1,6,9,1,1,8,8,1,9,0,1,11,1,1,9,0,2,11,1,1,8,8,13,1,6,8,10,1,13,1,6,11,1,1,9,0,1,7,11,1,1,9,0,3,10,2,6,8,2,8,10,3,6,8,9,10,2,6,8,2,1,8,7,2,8,7,8,0,2,6,11,4,2,9,0,9,1,9,0,1,7,8,5,1,8,3,3,7,11,4,2,9,0,9,1,9,0,9,1,7,66,121,116,101,115,51,50,5,67,108,111,99,107,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,3,97,100,100,20,97,115,115,101,114,116,95,107,110,111,119,110,95,101,109,105,116,116,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,6,100,105,103,101,115,116,15,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,13,101,109,105,116,116,101,114,95,99,104,97,105,110,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,101,120,116,114,97,99,116,3,103,101,116,22,103,101,116,95,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,2,105,100,7,105,115,95,115,111,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,14,114,101,112,108,97,121,95,112,114,111,116,101,99,116,4,115,111,109,101,5,115,116,97,116,101,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,1,23,8,3,0,1,0,0,1,19,10,0,10,1,56,0,4,11,11,0,11,1,56,1,20,56,2,12,2,5,17,11,1,1,11,0,1,56,3,12,2,11,2,2,1,1,0,0,15,25,10,1,17,16,12,3,11,0,14,3,17,0,12,2,14,2,56,4,4,11,5,15,11,1,1,7,0,39,13,2,56,5,11,1,17,15,33,4,22,5,24,7,1,39,2,2,1,0,0,20,15,11,0,11,2,11,3,12,5,12,4,46,11,4,11,5,17,17,12,6,11,1,14,6,17,1,11,6,2,3,1,0,0,22,26,10,0,10,1,17,14,12,3,46,11,3,56,6,32,4,10,5,18,11,1,1,11,2,1,11,0,1,7,2,39,11,0,11,1,17,14,11,2,17,9,18,0,56,7,2,4,1,0,0,5,12,11,0,11,1,11,3,11,4,17,2,12,6,11,2,14,6,11,5,17,3,11,6,2,0]},"type_origin_table":[{"module_name":"dola_address","struct_name":"DolaAddress","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"Pool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"DepositPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"WithdrawPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_verify","struct_name":"Unit","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceManagerCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version_1_0_0","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version_1_0_1","package":"0xc5b2a5049cd71586362d0c6a38e34cfaae7ea9ce6d5401a350506a15f817bf72"},{"module_name":"app_manager","struct_name":"TotalAppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"app_manager","struct_name":"AppCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"UserInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ReserveData","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ScaledBalance","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"BorrowRateFactors","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"PriceOracle","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"Price","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"Liquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AddLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"RemoveLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_logic","struct_name":"LendingCoreExecuteEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserAddressCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"BindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UnbindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"CoreState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"LendingCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_wormhole_adapter","struct_name":"SystemCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolWithdrawEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":6},"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302":{"upgraded_id":"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302","upgraded_version":1},"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a":{"upgraded_id":"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a","upgraded_version":1}}}},"owner":"Immutable","previous_transaction":"6B3tXa5PpoaRUQiYcytsC1M9fkfzXUc49NsWgC335qC1","storage_rebate":551022800}],"local_exec_effects":{"messageVersion":"v1","status":{"status":"success"},"executedEpoch":"55","gasUsed":{"computationCost":"820000","storageCost":"8291600","storageRebate":"7967916","nonRefundableStorageFee":"80484"},"modifiedAtVersions":[{"objectId":"0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004","sequenceNumber":"4346051"},{"objectId":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","sequenceNumber":"4346051"},{"objectId":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","sequenceNumber":"4346049"},{"objectId":"0x898dd24cc48476a7a2ff36372a443fefa53545b016feb317bb091e60e06b2e4c","sequenceNumber":"3478819"}],"sharedObjects":[{"objectId":"0x79d7106ea18373fc7542b0849d5ebefc3a9daf8b664a4f82d9b35bbd0c22042d","version":4346051,"digest":"4KddCShzYaYA2QcVbNphjberckmHf3BQQ13QxTqWzqkh"},{"objectId":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","version":4346051,"digest":"4BbiRiXkVTtkgnXwJJM1Px9u9Pw8XcTYeoi8xCAe5AiH"},{"objectId":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","version":4346049,"digest":"Hbp9rYyMyeFxfGkw6EEUfFpmVrc85NfAyTs2mE6EcxHj"}],"transactionDigest":"ozN2rhczEUC39poaeVYxMN6b6TEAjiFX7jFSQFhbKmL","mutated":[{"owner":{"AddressOwner":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497"},"reference":{"objectId":"0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004","version":4346052,"digest":"3DSxmS55mjcxjp4zni3HqxtpNBchuuEz1HkdY2cSGvx4"}},{"owner":{"Shared":{"initial_shared_version":4346051}},"reference":{"objectId":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","version":4346052,"digest":"EWBifxLP1W6RnLYEFEbsq5SrqCT28VBseSN6JDeBVB4g"}},{"owner":{"Shared":{"initial_shared_version":3478819}},"reference":{"objectId":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","version":4346052,"digest":"97QWr9zmCmV9L7WJHmG6ynSLbwtXtqaxEvJPzCw5r7ZK"}},{"owner":{"ObjectOwner":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621"},"reference":{"objectId":"0x898dd24cc48476a7a2ff36372a443fefa53545b016feb317bb091e60e06b2e4c","version":4346052,"digest":"39Twrdee3mTpzMUiccQdE2c5qYizZGmbGHsqycnCTA2j"}}],"gasObject":{"owner":{"AddressOwner":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497"},"reference":{"objectId":"0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004","version":4346052,"digest":"3DSxmS55mjcxjp4zni3HqxtpNBchuuEz1HkdY2cSGvx4"}},"eventsDigest":"J8u3bJn6FAMiadwesmkYjvm5kvNMKTNJecRQ9H5cndop","dependencies":["GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","5kWByxejQ95cxQ5zUCba3WyivedWBmtisRa4ZaWJuWpm","6B3tXa5PpoaRUQiYcytsC1M9fkfzXUc49NsWgC335qC1"]},"pre_exec_diag":{"loaded_child_objects":[["0x898dd24cc48476a7a2ff36372a443fefa53545b016feb317bb091e60e06b2e4c",3478819]]}} \ No newline at end of file diff --git a/crates/iota-rest-api/Cargo.toml b/crates/iota-rest-api/Cargo.toml new file mode 100644 index 00000000000..e893ef96bf5 --- /dev/null +++ b/crates/iota-rest-api/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "iota-rest-api" +version = "0.1.0" +edition = "2021" +license = "Apache-2.0" +publish = false + +[dependencies] +mime = "0.3.17" +anyhow.workspace = true +axum.workspace = true +bcs.workspace = true +rand.workspace = true +reqwest.workspace = true +serde.workspace = true +serde_json.workspace = true +serde_with.workspace = true +tap.workspace = true +thiserror.workspace = true + +fastcrypto.workspace = true +iota-types.workspace = true + +[dev-dependencies] +tokio.workspace = true diff --git a/crates/sui-rest-api/src/accept.rs b/crates/iota-rest-api/src/accept.rs similarity index 98% rename from crates/sui-rest-api/src/accept.rs rename to crates/iota-rest-api/src/accept.rs index 13e53f829b8..b535a09ee65 100644 --- a/crates/sui-rest-api/src/accept.rs +++ b/crates/iota-rest-api/src/accept.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use axum::http::{self, header, HeaderMap}; diff --git a/crates/iota-rest-api/src/checkpoints.rs b/crates/iota-rest-api/src/checkpoints.rs new file mode 100644 index 00000000000..15a9ba4882c --- /dev/null +++ b/crates/iota-rest-api/src/checkpoints.rs @@ -0,0 +1,139 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use axum::extract::{Path, State}; +use iota_types::{ + full_checkpoint_content::CheckpointData, + messages_checkpoint::{CertifiedCheckpointSummary, CheckpointDigest, CheckpointSequenceNumber}, + storage::ReadStore, +}; +use tap::Pipe; + +use crate::{ + accept::AcceptFormat, + response::{Bcs, ResponseContent}, + Result, +}; + +pub const GET_LATEST_CHECKPOINT_PATH: &str = "/checkpoints"; +pub const GET_CHECKPOINT_PATH: &str = "/checkpoints/:checkpoint"; +pub const GET_FULL_CHECKPOINT_PATH: &str = "/checkpoints/:checkpoint/full"; + +pub async fn get_full_checkpoint( + Path(checkpoint_id): Path, + accept: AcceptFormat, + State(state): State, +) -> Result> { + match accept { + AcceptFormat::Bcs => {} + _ => return Err(anyhow::anyhow!("invalid accept type").into()), + } + + let verified_summary = match checkpoint_id { + CheckpointId::SequenceNumber(s) => state.get_checkpoint_by_sequence_number(s), + CheckpointId::Digest(d) => state.get_checkpoint_by_digest(&d), + }? + .ok_or(CheckpointNotFoundError(checkpoint_id))?; + + let checkpoint_contents = state + .get_checkpoint_contents_by_digest(&verified_summary.content_digest)? + .ok_or(CheckpointNotFoundError(checkpoint_id))?; + + let checkpoint_data = state.get_checkpoint_data(verified_summary, checkpoint_contents)?; + + Ok(Bcs(checkpoint_data)) +} + +pub async fn get_latest_checkpoint( + accept: AcceptFormat, + State(state): State, +) -> Result> { + let summary = state.get_latest_checkpoint()?.into(); + + match accept { + AcceptFormat::Json => ResponseContent::Json(summary), + AcceptFormat::Bcs => ResponseContent::Bcs(summary), + } + .pipe(Ok) +} + +pub async fn get_checkpoint( + Path(checkpoint_id): Path, + accept: AcceptFormat, + State(state): State, +) -> Result> { + let summary = match checkpoint_id { + CheckpointId::SequenceNumber(s) => state.get_checkpoint_by_sequence_number(s), + CheckpointId::Digest(d) => state.get_checkpoint_by_digest(&d), + }? + .ok_or(CheckpointNotFoundError(checkpoint_id))? + .into(); + + match accept { + AcceptFormat::Json => ResponseContent::Json(summary), + AcceptFormat::Bcs => ResponseContent::Bcs(summary), + } + .pipe(Ok) +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum CheckpointId { + SequenceNumber(CheckpointSequenceNumber), + Digest(CheckpointDigest), +} + +impl<'de> serde::Deserialize<'de> for CheckpointId { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + let raw = String::deserialize(deserializer)?; + + if let Ok(s) = raw.parse::() { + Ok(Self::SequenceNumber(s)) + } else if let Ok(d) = raw.parse::() { + Ok(Self::Digest(d)) + } else { + Err(serde::de::Error::custom(format!( + "unrecognized checkpoint-id {raw}" + ))) + } + } +} + +impl serde::Serialize for CheckpointId { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + match self { + CheckpointId::SequenceNumber(s) => serializer.serialize_str(&s.to_string()), + CheckpointId::Digest(d) => serializer.serialize_str(&d.to_string()), + } + } +} + +#[derive(Debug)] +pub struct CheckpointNotFoundError(CheckpointId); + +impl std::fmt::Display for CheckpointNotFoundError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Checkpoint ")?; + + match self.0 { + CheckpointId::SequenceNumber(n) => write!(f, "{n}")?, + CheckpointId::Digest(d) => write!(f, "{d}")?, + } + + write!(f, " not found") + } +} + +impl std::error::Error for CheckpointNotFoundError {} + +impl From for crate::RestError { + fn from(value: CheckpointNotFoundError) -> Self { + Self::new(axum::http::StatusCode::NOT_FOUND, value.to_string()) + } +} diff --git a/crates/sui-rest-api/src/client.rs b/crates/iota-rest-api/src/client.rs similarity index 98% rename from crates/sui-rest-api/src/client.rs rename to crates/iota-rest-api/src/client.rs index 831bb5ee278..319defcff91 100644 --- a/crates/sui-rest-api/src/client.rs +++ b/crates/iota-rest-api/src/client.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; -use sui_types::{ +use iota_types::{ base_types::{ObjectID, SequenceNumber}, full_checkpoint_content::CheckpointData, messages_checkpoint::{CertifiedCheckpointSummary, CheckpointSequenceNumber}, diff --git a/crates/iota-rest-api/src/error.rs b/crates/iota-rest-api/src/error.rs new file mode 100644 index 00000000000..f4b4e8fb43c --- /dev/null +++ b/crates/iota-rest-api/src/error.rs @@ -0,0 +1,49 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use axum::http::StatusCode; + +pub type Result = std::result::Result; + +pub struct RestError { + status: StatusCode, + message: Option, +} + +impl RestError { + pub fn new(status: StatusCode, message: String) -> Self { + Self { + status, + message: Some(message), + } + } +} + +// Tell axum how to convert `AppError` into a response. +impl axum::response::IntoResponse for RestError { + fn into_response(self) -> axum::response::Response { + match self.message { + Some(message) => (self.status, message).into_response(), + None => self.status.into_response(), + } + } +} + +impl From for RestError { + fn from(value: iota_types::storage::error::Error) -> Self { + Self { + status: StatusCode::INTERNAL_SERVER_ERROR, + message: Some(value.to_string()), + } + } +} + +impl From for RestError { + fn from(value: anyhow::Error) -> Self { + Self { + status: StatusCode::INTERNAL_SERVER_ERROR, + message: Some(value.to_string()), + } + } +} diff --git a/crates/sui-rest-api/src/health.rs b/crates/iota-rest-api/src/health.rs similarity index 92% rename from crates/sui-rest-api/src/health.rs rename to crates/iota-rest-api/src/health.rs index d1e09b9008d..6c46eb423f2 100644 --- a/crates/sui-rest-api/src/health.rs +++ b/crates/iota-rest-api/src/health.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::time::{Duration, SystemTime}; @@ -8,7 +9,7 @@ use axum::{ http::StatusCode, response::IntoResponse, }; -use sui_types::storage::ReadStore; +use iota_types::storage::ReadStore; use tap::Pipe; use crate::Result; diff --git a/crates/sui-rest-api/src/info.rs b/crates/iota-rest-api/src/info.rs similarity index 93% rename from crates/sui-rest-api/src/info.rs rename to crates/iota-rest-api/src/info.rs index c8c4a27b139..cfb4c933e7f 100644 --- a/crates/sui-rest-api/src/info.rs +++ b/crates/iota-rest-api/src/info.rs @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::borrow::Cow; use axum::extract::State; -use sui_types::digests::ChainIdentifier; +use iota_types::digests::ChainIdentifier; use tap::Pipe; use crate::{accept::AcceptFormat, response::ResponseContent, RestService, Result}; diff --git a/crates/iota-rest-api/src/lib.rs b/crates/iota-rest-api/src/lib.rs new file mode 100644 index 00000000000..4dca060ff62 --- /dev/null +++ b/crates/iota-rest-api/src/lib.rs @@ -0,0 +1,112 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use axum::{routing::get, Router}; + +pub mod accept; +mod checkpoints; +mod client; +mod error; +mod health; +mod info; +mod objects; +mod response; +pub mod types; + +pub use client::Client; +pub use error::{RestError, Result}; +pub use iota_types::full_checkpoint_content::{CheckpointData, CheckpointTransaction}; +use iota_types::storage::ReadStore; + +pub const TEXT_PLAIN_UTF_8: &str = "text/plain; charset=utf-8"; +pub const APPLICATION_BCS: &str = "application/bcs"; +pub const APPLICATION_JSON: &str = "application/json"; + +#[derive(Clone)] +pub struct RestService { + store: std::sync::Arc, + chain_id: iota_types::digests::ChainIdentifier, + software_version: &'static str, +} + +impl RestService { + pub fn new( + store: std::sync::Arc, + chain_id: iota_types::digests::ChainIdentifier, + software_version: &'static str, + ) -> Self { + Self { + store, + chain_id, + software_version, + } + } + + pub fn new_without_version( + store: std::sync::Arc, + chain_id: iota_types::digests::ChainIdentifier, + ) -> Self { + Self::new(store, chain_id, "unknown") + } + + pub fn chain_id(&self) -> iota_types::digests::ChainIdentifier { + self.chain_id + } + + pub fn software_version(&self) -> &'static str { + self.software_version + } + + pub fn into_router(self) -> Router { + rest_router(self.store.clone()) + .merge( + Router::new() + .route("/", get(info::node_info)) + .with_state(self.clone()), + ) + .layer(axum::middleware::map_response_with_state( + self, + response::append_info_headers, + )) + } + + pub async fn start_service(self, socket_address: std::net::SocketAddr, base: Option) { + let mut app = self.into_router(); + + if let Some(base) = base { + app = Router::new().nest(&base, app); + } + + axum::Server::bind(&socket_address) + .serve(app.into_make_service()) + .await + .unwrap(); + } +} + +fn rest_router(state: S) -> Router +where + S: ReadStore + Clone + Send + Sync + 'static, +{ + Router::new() + .route(health::HEALTH_PATH, get(health::health::)) + .route( + checkpoints::GET_FULL_CHECKPOINT_PATH, + get(checkpoints::get_full_checkpoint::), + ) + .route( + checkpoints::GET_CHECKPOINT_PATH, + get(checkpoints::get_checkpoint::), + ) + .route( + checkpoints::GET_LATEST_CHECKPOINT_PATH, + get(checkpoints::get_latest_checkpoint::), + ) + .route(objects::GET_OBJECT_PATH, get(objects::get_object::)) + .route( + objects::GET_OBJECT_WITH_VERSION_PATH, + get(objects::get_object_with_version::), + ) + .with_state(state) +} diff --git a/crates/iota-rest-api/src/objects.rs b/crates/iota-rest-api/src/objects.rs new file mode 100644 index 00000000000..1189b0a36ae --- /dev/null +++ b/crates/iota-rest-api/src/objects.rs @@ -0,0 +1,91 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use axum::extract::{Path, State}; +use iota_types::{ + base_types::{ObjectID, SequenceNumber}, + object::Object, + storage::ReadStore, +}; +use tap::Pipe; + +use crate::{accept::AcceptFormat, response::ResponseContent, types::JsonObject, Result}; + +pub const GET_OBJECT_PATH: &str = "/objects/:object_id"; + +pub async fn get_object( + Path(object_id): Path, + accept: AcceptFormat, + State(state): State, +) -> Result> { + let object = state + .get_object(&object_id)? + .ok_or_else(|| ObjectNotFoundError::new(object_id))?; + + match accept { + AcceptFormat::Json => ResponseContent::Json(JsonObject::from_object(&object)), + AcceptFormat::Bcs => ResponseContent::Bcs(object), + } + .pipe(Ok) +} + +pub const GET_OBJECT_WITH_VERSION_PATH: &str = "/objects/:object_id/version/:version"; + +pub async fn get_object_with_version( + Path((object_id, version)): Path<(ObjectID, SequenceNumber)>, + accept: AcceptFormat, + State(state): State, +) -> Result> { + let object = state + .get_object_by_key(&object_id, version)? + .ok_or_else(|| ObjectNotFoundError::new_with_version(object_id, version))?; + + match accept { + AcceptFormat::Json => ResponseContent::Json(JsonObject::from_object(&object)), + AcceptFormat::Bcs => ResponseContent::Bcs(object), + } + .pipe(Ok) +} + +#[derive(Debug)] +pub struct ObjectNotFoundError { + object_id: ObjectID, + version: Option, +} + +impl ObjectNotFoundError { + pub fn new(object_id: ObjectID) -> Self { + Self { + object_id, + version: None, + } + } + + pub fn new_with_version(object_id: ObjectID, version: SequenceNumber) -> Self { + Self { + object_id, + version: Some(version), + } + } +} + +impl std::fmt::Display for ObjectNotFoundError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Object {}", self.object_id)?; + + if let Some(version) = self.version { + write!(f, " with version {version}")?; + } + + write!(f, " not found") + } +} + +impl std::error::Error for ObjectNotFoundError {} + +impl From for crate::RestError { + fn from(value: ObjectNotFoundError) -> Self { + Self::new(axum::http::StatusCode::NOT_FOUND, value.to_string()) + } +} diff --git a/crates/iota-rest-api/src/response.rs b/crates/iota-rest-api/src/response.rs new file mode 100644 index 00000000000..5cd65735a2c --- /dev/null +++ b/crates/iota-rest-api/src/response.rs @@ -0,0 +1,106 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use axum::{ + extract::State, + http::HeaderMap, + response::{IntoResponse, Response}, +}; +use reqwest::StatusCode; + +use crate::{ + types::{ + X_IOTA_CHAIN_ID, X_IOTA_CHECKPOINT_HEIGHT, X_IOTA_EPOCH, X_IOTA_OLDEST_CHECKPOINT_HEIGHT, + X_IOTA_TIMESTAMP_MS, + }, + RestService, APPLICATION_BCS, TEXT_PLAIN_UTF_8, +}; + +pub struct Bcs(pub T); + +pub enum ResponseContent { + Bcs(T), + Json(J), +} + +impl axum::response::IntoResponse for Bcs +where + T: serde::Serialize, +{ + fn into_response(self) -> axum::response::Response { + match bcs::to_bytes(&self.0) { + Ok(buf) => ( + [( + axum::http::header::CONTENT_TYPE, + axum::http::HeaderValue::from_static(APPLICATION_BCS), + )], + buf, + ) + .into_response(), + Err(err) => ( + StatusCode::INTERNAL_SERVER_ERROR, + [( + axum::http::header::CONTENT_TYPE, + axum::http::HeaderValue::from_static(TEXT_PLAIN_UTF_8), + )], + err.to_string(), + ) + .into_response(), + } + } +} + +impl axum::response::IntoResponse for ResponseContent +where + T: serde::Serialize, + J: serde::Serialize, +{ + fn into_response(self) -> axum::response::Response { + match self { + ResponseContent::Bcs(inner) => Bcs(inner).into_response(), + ResponseContent::Json(inner) => axum::Json(inner).into_response(), + } + } +} + +pub async fn append_info_headers( + State(state): State, + response: Response, +) -> impl IntoResponse { + let latest_checkpoint = state.store.get_latest_checkpoint().unwrap(); + let oldest_checkpoint = state.store.get_lowest_available_checkpoint().unwrap(); + + let mut headers = HeaderMap::new(); + + headers.insert( + X_IOTA_CHAIN_ID, + state.chain_id().to_string().try_into().unwrap(), + ); + headers.insert( + X_IOTA_EPOCH, + latest_checkpoint.epoch().to_string().try_into().unwrap(), + ); + headers.insert( + X_IOTA_CHECKPOINT_HEIGHT, + latest_checkpoint + .sequence_number() + .to_string() + .try_into() + .unwrap(), + ); + headers.insert( + X_IOTA_TIMESTAMP_MS, + latest_checkpoint + .timestamp_ms + .to_string() + .try_into() + .unwrap(), + ); + headers.insert( + X_IOTA_OLDEST_CHECKPOINT_HEIGHT, + oldest_checkpoint.to_string().try_into().unwrap(), + ); + + (headers, response) +} diff --git a/crates/iota-rest-api/src/types.rs b/crates/iota-rest-api/src/types.rs new file mode 100644 index 00000000000..5f939b8033f --- /dev/null +++ b/crates/iota-rest-api/src/types.rs @@ -0,0 +1,148 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use fastcrypto::encoding::Base64; +pub use fastcrypto::traits::KeyPair as KeypairTraits; +use iota_types::{ + base_types::{ObjectID, ObjectType}, + digests::{ObjectDigest, TransactionDigest}, + iota_serde::BigInt, + move_package::{TypeOrigin, UpgradeInfo}, + object::{Object, Owner}, +}; +use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, DisplayFromStr}; + +#[serde_as] +#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] +pub struct JsonObject { + pub object_id: ObjectID, + /// Object version. + #[serde_as(as = "BigInt")] + pub version: u64, + /// Base64 string representing the object digest + pub digest: ObjectDigest, + // Default to be None because otherwise it will be repeated for the getOwnedObjects endpoint + /// The owner of this object. + pub owner: Owner, + /// The digest of the transaction that created or last mutated this object. + /// Default to be None unless IotaObjectDataOptions. + /// showPreviousTransaction is set to true + pub previous_transaction: TransactionDigest, + /// The amount of IOTA we would rebate if this object gets deleted. + /// This number is re-calculated each time the object is mutated based on + /// the present storage gas price. + #[serde_as(as = "BigInt")] + pub storage_rebate: u64, + + /// The type of the object + #[serde_as(as = "DisplayFromStr")] + #[serde(rename = "type")] + pub type_: ObjectType, + /// Move object content or package content + pub data: JsonObjectData, +} + +#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] +#[serde(untagged)] +pub enum JsonObjectData { + Move(JsonMoveObject), + Package(JsonPackage), +} + +#[serde_as] +#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] +pub struct JsonPackage { + // TODO do we want to dissasemble this? + #[serde_as(as = "BTreeMap<_, Base64>")] + module_map: BTreeMap>, + + /// Maps struct/module to a package version where it was first defined, + /// stored as a vector for simple serialization and deserialization. + type_origin_table: Vec, + + // For each dependency, maps original package ID to the info about the (upgraded) dependency + // version that this package is using + linkage_table: BTreeMap, +} + +#[serde_as] +#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] +#[serde(rename_all = "kebab-case")] +pub struct JsonMoveObject { + /// DEPRECATED this field is no longer used to determine whether a tx can + /// transfer this object. Instead, it is always calculated from the + /// objects type when loaded in execution + has_public_transfer: bool, + + // TODO Do we want to spend the effort to render this? + // Move Struct rendered with type info + // fields: BTreeMap, + #[serde_as(as = "Base64")] + pub content: Vec, +} + +impl JsonObject { + pub fn from_object(object: &Object) -> Self { + let (type_, object_data) = match &object.data { + iota_types::object::Data::Move(struct_) => { + let s = JsonMoveObject { + has_public_transfer: struct_.has_public_transfer(), + content: struct_.contents().to_vec(), + }; + + ( + ObjectType::Struct(struct_.type_().clone()), + JsonObjectData::Move(s), + ) + } + iota_types::object::Data::Package(package) => { + let pkg = JsonPackage { + module_map: package.serialized_module_map().clone(), + type_origin_table: package.type_origin_table().clone(), + linkage_table: package.linkage_table().clone(), + }; + + (ObjectType::Package, JsonObjectData::Package(pkg)) + } + }; + + let version = object.version().value(); + let object_id = object.id(); + + Self { + object_id, + version, + digest: object.digest(), + owner: object.owner, + previous_transaction: object.previous_transaction, + storage_rebate: object.storage_rebate, + type_, + data: object_data, + } + } +} + +/// Chain ID of the current chain +pub const X_IOTA_CHAIN_ID: &str = "x-iota-chain-id"; + +/// Current checkpoint height +pub const X_IOTA_CHECKPOINT_HEIGHT: &str = "x-iota-checkpoint-height"; + +/// Oldest non-pruned checkpoint height +pub const X_IOTA_OLDEST_CHECKPOINT_HEIGHT: &str = "x-iota-oldest-checkpoint-height"; + +/// Current epoch of the chain +pub const X_IOTA_EPOCH: &str = "x-iota-epoch"; + +/// Cursor to be used for endpoints that support cursor-based pagination. Pass +/// this to the start field of the endpoint on the next call to get the next +/// page of results. +pub const X_IOTA_CURSOR: &str = "x-iota-cursor"; + +/// Current timestamp of the chain - represented as number of milliseconds from +/// the Unix epoch +pub const X_IOTA_TIMESTAMP_MS: &str = "x-iota-timestamp-ms"; diff --git a/crates/iota-rosetta/Cargo.toml b/crates/iota-rosetta/Cargo.toml new file mode 100644 index 00000000000..58e0373c382 --- /dev/null +++ b/crates/iota-rosetta/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "iota-rosetta" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +axum.workspace = true +axum-extra.workspace = true +anyhow.workspace = true +tracing.workspace = true +serde.workspace = true +serde_json.workspace = true +tokio.workspace = true +futures.workspace = true +once_cell.workspace = true +signature.workspace = true +bcs.workspace = true +hyper.workspace = true +strum.workspace = true +strum_macros.workspace = true +async-trait.workspace = true +clap.workspace = true +thiserror.workspace = true +eyre.workspace = true +typed-store.workspace = true +tempfile.workspace = true +fastcrypto.workspace = true +iota-swarm-config.workspace = true +iota-types.workspace = true +iota-sdk.workspace = true +iota-node.workspace = true +iota-config.workspace = true +iota-keys.workspace = true +iota-json-rpc-types.workspace = true +mysten-metrics.workspace = true +shared-crypto.workspace = true + +move-core-types.workspace = true + +telemetry-subscribers.workspace = true + +[dev-dependencies] +iota-sdk.workspace = true +iota-move-build.workspace = true +test-cluster.workspace = true +tempfile.workspace = true +rand.workspace = true +reqwest.workspace = true diff --git a/crates/iota-rosetta/README.md b/crates/iota-rosetta/README.md new file mode 100644 index 00000000000..a3aeed49e50 --- /dev/null +++ b/crates/iota-rosetta/README.md @@ -0,0 +1,213 @@ +# Rosetta API for Iota + +[Rosetta](https://www.rosetta-api.org/docs/welcome.html) is an open-source specification and set of tools for blockchain +integration. Rosetta’s goal is to make blockchain integration simpler, faster, and more reliable than using a native +integration. + +## Overview + +Iota-Rosetta is an implementation of the Rosetta API for the Iota network, the Iota-Rosetta server uses the Iota fullnode to +read and write transactions to the Iota network. + +## Local network quick start + +### Build from source +#### 0. Checkout and build Iota +Checkout the [Iota source code](https://github.com/iotaledger/iota) and compile using `cargo build --release`, the binaries will be located in `target/release` directory. + +#### 1. Genesis + +`./iota genesis -f` +The Iota genesis process will create configs and coins for testing, the config files are stored in `~/.iota/iota_config` by +default. + +#### 2. Start local network + +`./iota start` + +#### 3. Start Rosetta Online server + +`./iota-rosetta start-online-server` + +#### 4. Start Rosetta Offline server + +`./iota-rosetta start-offline-server` + +#### 5. Generate configuration with prefunded accounts for rosetta-cli + +`./iota-rosetta generate-rosetta-cli-config` +This will generate the `rosetta-cli.json` and `iota.ros` file to be used by the [Rosetta-CLI](https://github.com/coinbase/rosetta-cli) + +### Build local test network using Docker Compose + +#### 1. CD into the Dockerfile directory + +```shell +cd /crate/iota-rosetta/docker/iota-rosetta-local +``` +#### 2. Build the image +```shell +./build.sh +``` +#### 3. Start the container + +```shell +docker-compose up -d +``` +Docker compose will start the rosetta-online and rosetta-offline containers, the ports for both rosetta server (9002, 9003 respectively) will be exposed to the host. + +#### 4. Enter the rosetta service shell + +```shell +docker-compose exec rosetta-online bash +``` + +#### 5. use the rosetta-cli to test the api +```shell +rosetta-cli --configuration-file rosetta-cli.json check:data +rosetta-cli --configuration-file rosetta-cli.json check:construction +``` + +### Start Rosetta servers using docker run +you can also start the individual server using docker run. +To start the rosetta-online server, run +```shell +docker run mysten/iota-rosetta-devnet iota-rosetta start-online-server +``` +Alternatively, to start the rosetta-offline server, run +```shell +docker run mysten/iota-rosetta-devnet iota-rosetta start-offline-server +``` + +## Supported APIs + +### Account + +| Method | Endpoint | Description | Iota Supported? | Server Type | +|--------|------------------|--------------------------------|:--------------:|:-------------:| +| POST | /account/balance | Get an Account's Balance | Yes | Online | +| POST | /account/coins | Get an Account's Unspent Coins | Yes | Online | + +### Block + +| Method | Endpoint | Description | Iota Supported? | Server Type | +|--------|--------------------|-------------------------|:-----------------------------------------------------------------------------------------:|:-------------:| +| POST | /block | Get a Block | Yes (One transaction per block in phase 1, will be replaced by Iota checkpoint in phase 2) | Online | +| POST | /block/transaction | Get a Block Transaction | Yes | Online | + +### Call + +| Method | Endpoint | Description | Iota Supported? | Server Type | +|--------|----------|----------------------------------------|:--------------:|:-----------:| +| POST | /call | Make a Network-Specific Procedure Call | No | -- | + +### Construction + +| Method | Endpoint | Description | Iota Supported? | Server Type | +|--------|--------------------------|-------------------------------------------------------|:--------------:|:-----------:| +| POST | /construction/combine | Create Network Transaction from Signatures | Yes | Offline | +| POST | /construction/derive | Derive an AccountIdentifier from a PublicKey | Yes | Offline | +| POST | /construction/hash | Get the Hash of a Signed Transaction | Yes | Offline | +| POST | /construction/metadata | Get Metadata for Transaction Construction | Yes | Online | +| POST | /construction/parse | Parse a Transaction | Yes | Offline | +| POST | /construction/payloads | Generate an Unsigned Transaction and Signing Payloads | Yes | Offline | +| POST | /construction/preprocess | Create a Request to Fetch Metadata | Yes | Offline | +| POST | /construction/submit | Submit a Signed Transaction | Yes | Online | + +### Events + +| Method | Endpoint | Description | Iota Supported? | Server Type | +|--------|----------------|--------------------------------------|:--------------:|:-----------:| +| POST | /events/blocks | [INDEXER] Get a range of BlockEvents | No | -- | + +### Mempool + +| Method | Endpoint | Description | Iota Supported? | Server Type | +|--------|----------------------|------------------------------|:--------------:|:-----------:| +| POST | /mempool | Get All Mempool Transactions | No | -- | +| POST | /mempool/transaction | Get a Mempool Transaction | No | -- | + +### Network + +| Method | Endpoint | Description | Iota Supported? | Server Type | +|--------|------------------|--------------------------------|:--------------:|:--------------:| +| POST | /network/list | Get List of Available Networks | Yes | Online/Offline | +| POST | /network/options | Get Network Options | Yes | Online/Offline | +| POST | /network/status | Get Network Status | Yes | Online | + +### Search + +| Method | Endpoint | Description | Iota Supported? | Server Type | +|--------|----------------------|-----------------------------------|:--------------:|:-----------:| +| POST | /search/transactions | [INDEXER] Search for Transactions | No | -- | + + +## Iota transaction <> Rosetta Operation conversion explained +There are 2 places we convert Iota's transaction to Rosetta's operations, +one is in the `/construction/parse` endpoint and another one in `/block/transaction endpoint`. +`/operation/parse` uses `Operation::from_data` to create the "intent" operations and `/block/transaction` uses `Operation::from_data_and_effect` to create the "confirmed" operations. +the `/construction/parse` endpoint is used for checking transaction correctness during transaction construction, in our case we only support `TransferIota` for now, the operations created looks like this (negative amount indicate sender): +```json +{ + "operation_identifier": { + "index": 0 + }, + "type": "TransferIOTA", + "account": { + "address": "0xc4173a804406a365e69dfb297d4eaaf002546ebd" + }, + "amount": { + "value": "-100000", + "currency": { + "symbol": "IOTA", + "decimals": 9 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "0x0dce9190d54cde842d39537bf94efe128181b8a6:5549" + }, + "coin_action": "coin_spent" + } +}, +{ + "operation_identifier": { + "index": 1 + }, + "type": "TransferIOTA", + "account": { + "address": "0x96bc0b37b67103651d1f98c67b34df9558ea527a" + }, + "amount": { + "value": "100000", + "currency": { + "symbol": "IOTA", + "decimals": 9 + } + } +}, +{ + "operation_identifier": { + "index": 2 + }, + "type": "GasBudget", + "account": { + "address": "0xc4173a804406a365e69dfb297d4eaaf002546ebd" + }, + "coin_change": { + "coin_identifier": { + "identifier": "0x0dce9190d54cde842d39537bf94efe128181b8a6:5549" + }, + "coin_action": "coin_spent" + }, + "metadata": { + "budget": 1000 + } +} +``` +The sender, recipients and transfer amounts are specified in the intent operations, +these data are being used to create TransactionData for signature. +After the tx is executed, the rosetta-cli compare the intent operations with the confirmed operations , +the confirmed operations must contain the intent operations (the confirmed operations can have more operations than the intent). +Since the intent operations of TransferIota contains all the balance change information(amount field) already, +we don't need to use the event to create the operations, also operation created by `get_coin_operation_from_event` will contain recipient's coin id, which will cause a mismatch. \ No newline at end of file diff --git a/crates/iota-rosetta/docker/iota-rosetta-devnet/Dockerfile b/crates/iota-rosetta/docker/iota-rosetta-devnet/Dockerfile new file mode 100644 index 00000000000..4ddaf2d25c5 --- /dev/null +++ b/crates/iota-rosetta/docker/iota-rosetta-devnet/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:latest AS chef +WORKDIR iota +ARG GIT_REVISION +ENV GIT_REVISION=$GIT_REVISION +RUN apt-get update && apt-get install -y build-essential libssl-dev pkg-config curl cmake clang git ca-certificates +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" + +FROM chef AS builder +RUN git clone https://github.com/iotaledger/iota . +RUN git checkout devnet + +RUN curl -sSfL https://raw.githubusercontent.com/coinbase/rosetta-cli/master/scripts/install.sh | sh -s +RUN curl -fLJO https://github.com/iotaledger/iota-genesis/raw/main/devnet/genesis.blob +RUN cargo build --release --bin iota --bin iota-rosetta --bin iota-node + +# Production Image +FROM ubuntu:latest AS runtime +WORKDIR iota +RUN apt-get update && apt-get install -y ca-certificates +COPY --from=builder /iota/target/release/iota /usr/local/bin +COPY --from=builder /iota/target/release/iota-node /usr/local/bin +COPY --from=builder /iota/target/release/iota-rosetta /usr/local/bin +COPY --from=builder /iota/bin/rosetta-cli /usr/local/bin +COPY --from=builder /iota/crates/iota-config/data/fullnode-template.yaml /iota/devnet/fullnode.yaml +COPY --from=builder /iota/genesis.blob /iota/devnet/genesis.blob +RUN /usr/local/bin/iota genesis + +ARG BUILD_DATE +LABEL build-date=$BUILD_DATE +LABEL git-revision=$GIT_REVISION diff --git a/crates/iota-rosetta/docker/iota-rosetta-devnet/build.sh b/crates/iota-rosetta/docker/iota-rosetta-devnet/build.sh new file mode 100755 index 00000000000..c3f09ad931a --- /dev/null +++ b/crates/iota-rosetta/docker/iota-rosetta-devnet/build.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# Copyright (c) Mysten Labs, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Modifications Copyright (c) 2024 IOTA Stiftung +# SPDX-License-Identifier: Apache-2.0 + +# fast fail. +set -e + +DIR="$( cd "$( dirname "$0" )" && pwd )" +REPO_ROOT="$(git rev-parse --show-toplevel)" +DOCKERFILE="$DIR/Dockerfile" +GIT_REVISION="$(git describe --always --dirty --exclude '*')" +BUILD_DATE="$(date -u +'%Y-%m-%d')" + +echo +echo "Building iota-rosetta docker image" +echo "Dockerfile: \t$DOCKERFILE" +echo "docker context: $REPO_ROOT" +echo "build date: \t$BUILD_DATE" +echo "git revision: \t$GIT_REVISION" +echo + +docker build -f "$DOCKERFILE" "$REPO_ROOT" \ + -t mysten/iota-rosetta-devnet \ + --build-arg GIT_REVISION="$GIT_REVISION" \ + --build-arg BUILD_DATE="$BUILD_DATE" \ + "$@" diff --git a/crates/iota-rosetta/docker/iota-rosetta-devnet/docker-compose.yaml b/crates/iota-rosetta/docker/iota-rosetta-devnet/docker-compose.yaml new file mode 100644 index 00000000000..0d6f93d8137 --- /dev/null +++ b/crates/iota-rosetta/docker/iota-rosetta-devnet/docker-compose.yaml @@ -0,0 +1,36 @@ +--- +version: "3.9" +services: + rosetta-online: + image: mysten/iota-rosetta-devnet + ports: + - "9002:9002" + expose: + - "9002" + volumes: + - data:/data:rw + working_dir: /iota/devnet + command: + - /bin/bash + - -c + - | + /usr/local/bin/iota-rosetta generate-rosetta-cli-config --env devnet & + /usr/local/bin/iota-rosetta start-online-server --env devnet --node-config fullnode.yaml + stdin_open: true + tty: true + rosetta-offline: + image: mysten/iota-rosetta-devnet + ports: + - "9003:9003" + expose: + - "9003" + working_dir: /iota/devnet + command: + - /bin/bash + - -c + - | + /usr/local/bin/iota-rosetta start-offline-server --env devnet + stdin_open: true + tty: true +volumes: + data: diff --git a/crates/iota-rosetta/docker/iota-rosetta-devnet/remote/docker-compose.yaml b/crates/iota-rosetta/docker/iota-rosetta-devnet/remote/docker-compose.yaml new file mode 100644 index 00000000000..28df2511e94 --- /dev/null +++ b/crates/iota-rosetta/docker/iota-rosetta-devnet/remote/docker-compose.yaml @@ -0,0 +1,33 @@ +--- +version: "3.9" +services: + rosetta-online: + image: mysten/iota-rosetta-devnet + ports: + - "9002:9002" + expose: + - "9002" + working_dir: /iota/devnet + command: + - /bin/bash + - -c + - | + /usr/local/bin/iota-rosetta generate-rosetta-cli-config --env devnet & + /usr/local/bin/iota-rosetta start-online-remote-server --env devnet --genesis-path genesis.blob --full-node-url https://fullnode.devnet.iota.io:443 + stdin_open: true + tty: true + rosetta-offline: + image: mysten/iota-rosetta-devnet + ports: + - "9003:9003" + expose: + - "9003" + working_dir: /iota/devnet + command: + - /bin/bash + - -c + - | + /usr/local/bin/iota-rosetta start-offline-server --env devnet + stdin_open: true + tty: true + diff --git a/crates/iota-rosetta/docker/iota-rosetta-local/Dockerfile b/crates/iota-rosetta/docker/iota-rosetta-local/Dockerfile new file mode 100644 index 00000000000..a49e77c00d3 --- /dev/null +++ b/crates/iota-rosetta/docker/iota-rosetta-local/Dockerfile @@ -0,0 +1,34 @@ +FROM ubuntu:latest AS chef +WORKDIR iota +ARG GIT_REVISION +ENV GIT_REVISION=$GIT_REVISION +RUN apt-get update && apt-get install -y build-essential libssl-dev pkg-config curl cmake clang ca-certificates +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" + +# Build application +FROM chef AS builder + +RUN curl -sSfL https://raw.githubusercontent.com/coinbase/rosetta-cli/master/scripts/install.sh | sh -s + +COPY Cargo.toml Cargo.lock ./ +COPY consensus consensus +COPY crates crates +COPY iota-execution iota-execution +COPY narwhal narwhal +COPY external-crates external-crates +RUN cargo build --release --bin iota --bin iota-rosetta + +# Production Image +FROM ubuntu:latest AS runtime +WORKDIR iota +RUN apt-get update && apt-get install -y ca-certificates +COPY --from=builder /iota/target/release/iota /usr/local/bin +COPY --from=builder /iota/target/release/iota-rosetta /usr/local/bin +COPY --from=builder /iota/bin/rosetta-cli /usr/local/bin +COPY --from=builder /iota/crates/iota-config/data/fullnode-template.yaml /iota/devnet/fullnode.yaml +RUN /usr/local/bin/iota genesis + +ARG BUILD_DATE +LABEL build-date=$BUILD_DATE +LABEL git-revision=$GIT_REVISION diff --git a/crates/iota-rosetta/docker/iota-rosetta-local/build.sh b/crates/iota-rosetta/docker/iota-rosetta-local/build.sh new file mode 100755 index 00000000000..df199df7d10 --- /dev/null +++ b/crates/iota-rosetta/docker/iota-rosetta-local/build.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# Copyright (c) Mysten Labs, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Modifications Copyright (c) 2024 IOTA Stiftung +# SPDX-License-Identifier: Apache-2.0 + +# fast fail. +set -e + +DIR="$( cd "$( dirname "$0" )" && pwd )" +REPO_ROOT="$(git rev-parse --show-toplevel)" +DOCKERFILE="$DIR/Dockerfile" +GIT_REVISION="$(git describe --always --dirty)" +BUILD_DATE="$(date -u +'%Y-%m-%d')" + +echo +echo "Building iota-rosetta docker image" +echo "Dockerfile: \t$DOCKERFILE" +echo "docker context: $REPO_ROOT" +echo "build date: \t$BUILD_DATE" +echo "git revision: \t$GIT_REVISION" +echo + +docker build -f "$DOCKERFILE" "$REPO_ROOT" \ + -t mysten/iota-rosetta-local \ + --build-arg GIT_REVISION="$GIT_REVISION" \ + --build-arg BUILD_DATE="$BUILD_DATE" \ + "$@" diff --git a/crates/iota-rosetta/docker/iota-rosetta-local/docker-compose.yaml b/crates/iota-rosetta/docker/iota-rosetta-local/docker-compose.yaml new file mode 100644 index 00000000000..4ab7519f366 --- /dev/null +++ b/crates/iota-rosetta/docker/iota-rosetta-local/docker-compose.yaml @@ -0,0 +1,40 @@ +--- +version: "3.9" +services: + iota-network: + image: mysten/iota-rosetta-local + ports: + - "9000:9000" + expose: + - "9000" + command: + - /bin/bash + - -c + - | + /usr/local/bin/iota start + rosetta-online: + image: mysten/iota-rosetta-local + ports: + - "9002:9002" + expose: + - "9002" + working_dir: /iota/localnet + command: + - /bin/bash + - -c + - | + /usr/local/bin/iota-rosetta generate-rosetta-cli-config & + /usr/local/bin/iota-rosetta start-online-remote-server --full-node-url http://iota-network:9000 + stdin_open: true + tty: true + rosetta-offline: + image: mysten/iota-rosetta-local + ports: + - "9003:9003" + expose: + - "9003" + command: + - /bin/bash + - -c + - | + /usr/local/bin/iota-rosetta start-offline-server \ No newline at end of file diff --git a/crates/iota-rosetta/resources/iota.ros b/crates/iota-rosetta/resources/iota.ros new file mode 100644 index 00000000000..d19518e6742 --- /dev/null +++ b/crates/iota-rosetta/resources/iota.ros @@ -0,0 +1,44 @@ +transfer(10){ + transfer{ + transfer.network = {"network":"{{iota.env}}", "blockchain":"iota"}; + currency = {"symbol":"IOTA", "decimals":9}; + sender = find_balance({ + "minimum_balance":{ + "value": "100000", + "currency": {{currency}} + } + }); + recipient_amount = random_number({"minimum": "1", "maximum": "100000"}); + sender_amount = 0 - {{recipient_amount}}; + print_message({"recipient_amount":{{recipient_amount}}}); + + // Find recipient and construct operations + recipient = find_balance({ + "not_account_identifier":[{{sender.account_identifier}}], + "minimum_balance":{ + "value": "0", + "currency": {{currency}} + } + }); + transfer.confirmation_depth = "1"; + transfer.operations = [ + { + "operation_identifier":{"index":0}, + "type":"PayIota", + "account":{{recipient.account_identifier}}, + "amount":{ + "value":{{recipient_amount}}, + "currency":{{currency}} + } + }, + { + "operation_identifier":{"index":1}, + "type":"PayIota", + "account":{{sender.account_identifier}}, + "amount":{ + "value":{{sender_amount}}, + "currency":{{currency}} + } + }]; + } +} \ No newline at end of file diff --git a/crates/sui-rosetta/resources/rosetta_cli.json b/crates/iota-rosetta/resources/rosetta_cli.json similarity index 95% rename from crates/sui-rosetta/resources/rosetta_cli.json rename to crates/iota-rosetta/resources/rosetta_cli.json index 63bd2d57855..142f39a68e9 100644 --- a/crates/sui-rosetta/resources/rosetta_cli.json +++ b/crates/iota-rosetta/resources/rosetta_cli.json @@ -1,6 +1,6 @@ { "network": { - "blockchain": "sui", + "blockchain": "iota", "network": "localnet" }, "online_url": "http://rosetta-online:9002", @@ -19,7 +19,7 @@ "coin_supported": false, "construction": { "offline_url": "http://rosetta-offline:9003", - "constructor_dsl_file": "sui.ros", + "constructor_dsl_file": "iota.ros", "end_conditions": { "transfer": 20 }, diff --git a/crates/sui-rosetta/src/account.rs b/crates/iota-rosetta/src/account.rs similarity index 91% rename from crates/sui-rosetta/src/account.rs rename to crates/iota-rosetta/src/account.rs index 9667f459972..e7248bc4374 100644 --- a/crates/sui-rosetta/src/account.rs +++ b/crates/iota-rosetta/src/account.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! This module implements the [Rosetta Account API](https://www.rosetta-api.org/docs/AccountApi.html) use std::time::Duration; @@ -6,8 +7,8 @@ use std::time::Duration; use axum::{extract::State, Extension, Json}; use axum_extra::extract::WithRejection; use futures::StreamExt; -use sui_sdk::{rpc_types::StakeStatus, SuiClient, SUI_COIN_TYPE}; -use sui_types::base_types::SuiAddress; +use iota_sdk::{rpc_types::StakeStatus, IotaClient, IOTA_COIN_TYPE}; +use iota_types::base_types::IotaAddress; use tracing::info; use crate::{ @@ -16,7 +17,7 @@ use crate::{ AccountBalanceRequest, AccountBalanceResponse, AccountCoinsRequest, AccountCoinsResponse, Amount, Coin, SubAccount, SubAccountType, SubBalance, }, - OnlineServerContext, SuiEnv, + IotaEnv, OnlineServerContext, }; /// Get an array of all AccountBalances for an AccountIdentifier and the @@ -24,7 +25,7 @@ use crate::{ /// [Rosetta API Spec](https://www.rosetta-api.org/docs/AccountApi.html#accountbalance) pub async fn balance( State(ctx): State, - Extension(env): Extension, + Extension(env): Extension, WithRejection(Json(request), _): WithRejection, Error>, ) -> Result { env.check_network_identifier(&request.network_identifier)?; @@ -73,7 +74,7 @@ pub async fn balance( let balances_first = ctx .client .coin_read_api() - .get_balance(address, Some(SUI_COIN_TYPE.to_string())) + .get_balance(address, Some(IOTA_COIN_TYPE.to_string())) .await? .total_balance as i128; @@ -104,7 +105,7 @@ pub async fn balance( let balances_second = ctx .client .coin_read_api() - .get_balance(address, Some(SUI_COIN_TYPE.to_string())) + .get_balance(address, Some(IOTA_COIN_TYPE.to_string())) .await? .total_balance as i128; @@ -134,8 +135,8 @@ pub async fn balance( async fn get_sub_account_balances( account_type: SubAccountType, - client: &SuiClient, - address: SuiAddress, + client: &IotaClient, + address: IotaAddress, ) -> Result, Error> { let amounts = match account_type { SubAccountType::Stake => { @@ -144,7 +145,7 @@ async fn get_sub_account_balances( for stake in &stakes.stakes { if let StakeStatus::Active { .. } = stake.status { amounts.push(SubBalance { - stake_id: stake.staked_sui_id, + stake_id: stake.staked_iota_id, validator: stakes.validator_address, value: stake.principal as i128, }); @@ -159,7 +160,7 @@ async fn get_sub_account_balances( for stake in &stakes.stakes { if let StakeStatus::Pending = stake.status { amounts.push(SubBalance { - stake_id: stake.staked_sui_id, + stake_id: stake.staked_iota_id, validator: stakes.validator_address, value: stake.principal as i128, }); @@ -175,7 +176,7 @@ async fn get_sub_account_balances( for stake in &stakes.stakes { if let StakeStatus::Active { estimated_reward } = stake.status { amounts.push(SubBalance { - stake_id: stake.staked_sui_id, + stake_id: stake.staked_iota_id, validator: stakes.validator_address, value: estimated_reward as i128, }); @@ -198,7 +199,7 @@ async fn get_sub_account_balances( /// BlockIdentifier at which the lookup was performed. . [Rosetta API Spec](https://www.rosetta-api.org/docs/AccountApi.html#accountcoins) pub async fn coins( State(context): State, - Extension(env): Extension, + Extension(env): Extension, WithRejection(Json(request), _): WithRejection, Error>, ) -> Result { env.check_network_identifier(&request.network_identifier)?; @@ -207,7 +208,7 @@ pub async fn coins( .coin_read_api() .get_coins_stream( request.account_identifier.address, - Some(SUI_COIN_TYPE.to_string()), + Some(IOTA_COIN_TYPE.to_string()), ) .map(Coin::from) .collect() diff --git a/crates/sui-rosetta/src/block.rs b/crates/iota-rosetta/src/block.rs similarity index 88% rename from crates/sui-rosetta/src/block.rs rename to crates/iota-rosetta/src/block.rs index 18cf0bf1a9a..795ad800f58 100644 --- a/crates/sui-rosetta/src/block.rs +++ b/crates/iota-rosetta/src/block.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use axum::{extract::State, Extension, Json}; use axum_extra::extract::WithRejection; -use sui_json_rpc_types::SuiTransactionBlockResponseOptions; +use iota_json_rpc_types::IotaTransactionBlockResponseOptions; use tracing::debug; use crate::{ @@ -11,7 +12,7 @@ use crate::{ BlockRequest, BlockResponse, BlockTransactionRequest, BlockTransactionResponse, Transaction, TransactionIdentifier, }, - Error, OnlineServerContext, SuiEnv, + Error, IotaEnv, OnlineServerContext, }; /// This module implements the [Rosetta Block API](https://www.rosetta-api.org/docs/BlockApi.html) @@ -20,7 +21,7 @@ use crate::{ /// [Rosetta API Spec](https://www.rosetta-api.org/docs/BlockApi.html#block) pub async fn block( State(state): State, - Extension(env): Extension, + Extension(env): Extension, WithRejection(Json(request), _): WithRejection, Error>, ) -> Result { debug!("Called /block endpoint: {:?}", request.block_identifier); @@ -39,7 +40,7 @@ pub async fn block( /// [Rosetta API Spec](https://www.rosetta-api.org/docs/BlockApi.html#blocktransaction) pub async fn transaction( State(context): State, - Extension(env): Extension, + Extension(env): Extension, WithRejection(Json(request), _): WithRejection, Error>, ) -> Result { env.check_network_identifier(&request.network_identifier)?; @@ -49,7 +50,7 @@ pub async fn transaction( .read_api() .get_transaction_with_options( digest, - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_input() .with_events() .with_effects() diff --git a/crates/sui-rosetta/src/construction.rs b/crates/iota-rosetta/src/construction.rs similarity index 89% rename from crates/sui-rosetta/src/construction.rs rename to crates/iota-rosetta/src/construction.rs index 75ec304536a..b652295c8ef 100644 --- a/crates/sui-rosetta/src/construction.rs +++ b/crates/iota-rosetta/src/construction.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use axum::{extract::State, Extension, Json}; @@ -8,19 +9,19 @@ use fastcrypto::{ hash::HashFunction, }; use futures::StreamExt; -use shared_crypto::intent::{Intent, IntentMessage}; -use sui_json_rpc_types::{ - StakeStatus, SuiObjectDataOptions, SuiTransactionBlockEffectsAPI, - SuiTransactionBlockResponseOptions, +use iota_json_rpc_types::{ + IotaObjectDataOptions, IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponseOptions, + StakeStatus, }; -use sui_sdk::rpc_types::SuiExecutionStatus; -use sui_types::{ - base_types::SuiAddress, +use iota_sdk::rpc_types::IotaExecutionStatus; +use iota_types::{ + base_types::IotaAddress, crypto::{DefaultHash, SignatureScheme, ToFromBytes}, - error::SuiError, + error::IotaError, signature::{GenericSignature, VerifyParams}, transaction::{Transaction, TransactionData, TransactionDataAPI}, }; +use shared_crypto::intent::{Intent, IntentMessage}; use crate::{ errors::Error, @@ -33,7 +34,7 @@ use crate::{ InternalOperation, MetadataOptions, SignatureType, SigningPayload, TransactionIdentifier, TransactionIdentifierResponse, }, - OnlineServerContext, SuiEnv, + IotaEnv, OnlineServerContext, }; /// This module implements the [Rosetta Construction API](https://www.rosetta-api.org/docs/ConstructionApi.html) @@ -42,11 +43,11 @@ use crate::{ /// /// [Rosetta API Spec](https://www.rosetta-api.org/docs/ConstructionApi.html#constructionderive) pub async fn derive( - Extension(env): Extension, + Extension(env): Extension, WithRejection(Json(request), _): WithRejection, Error>, ) -> Result { env.check_network_identifier(&request.network_identifier)?; - let address: SuiAddress = request.public_key.try_into()?; + let address: IotaAddress = request.public_key.try_into()?; Ok(ConstructionDeriveResponse { account_identifier: address.into(), }) @@ -59,7 +60,7 @@ pub async fn derive( /// /// [Rosetta API Spec](https://www.rosetta-api.org/docs/ConstructionApi.html#constructionpayloads) pub async fn payloads( - Extension(env): Extension, + Extension(env): Extension, WithRejection(Json(request), _): WithRejection, Error>, ) -> Result { env.check_network_identifier(&request.network_identifier)?; @@ -70,7 +71,7 @@ pub async fn payloads( .operations .into_internal()? .try_into_data(metadata)?; - let intent_msg = IntentMessage::new(Intent::sui_transaction(), data); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), data); let intent_msg_bytes = bcs::to_bytes(&intent_msg)?; let mut hasher = DefaultHash::default(); @@ -92,7 +93,7 @@ pub async fn payloads( /// /// [Rosetta API Spec](https://www.rosetta-api.org/docs/ConstructionApi.html#constructioncombine) pub async fn combine( - Extension(env): Extension, + Extension(env): Extension, WithRejection(Json(request), _): WithRejection, Error>, ) -> Result { env.check_network_identifier(&request.network_identifier)?; @@ -131,7 +132,7 @@ pub async fn combine( /// [Rosetta API Spec](https://www.rosetta-api.org/docs/ConstructionApi.html#constructionsubmit) pub async fn submit( State(context): State, - Extension(env): Extension, + Extension(env): Extension, WithRejection(Json(request), _): WithRejection, Error>, ) -> Result { env.check_network_identifier(&request.network_identifier)?; @@ -147,7 +148,7 @@ pub async fn submit( .read_api() .dry_run_transaction_block(tx_data) .await?; - if let SuiExecutionStatus::Failure { error } = dry_run.effects.status() { + if let IotaExecutionStatus::Failure { error } = dry_run.effects.status() { return Err(Error::TransactionDryRunError(error.clone())); }; @@ -156,7 +157,7 @@ pub async fn submit( .quorum_driver_api() .execute_transaction_block( signed_tx, - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_input() .with_effects() .with_balance_changes(), @@ -164,7 +165,7 @@ pub async fn submit( ) .await?; - if let SuiExecutionStatus::Failure { error } = response + if let IotaExecutionStatus::Failure { error } = response .effects .expect("Execute transaction should return effects") .status() @@ -186,7 +187,7 @@ pub async fn submit( /// /// [Rosetta API Spec](https://www.rosetta-api.org/docs/ConstructionApi.html#constructionpreprocess) pub async fn preprocess( - Extension(env): Extension, + Extension(env): Extension, WithRejection(Json(request), _): WithRejection, Error>, ) -> Result { env.check_network_identifier(&request.network_identifier)?; @@ -209,7 +210,7 @@ pub async fn preprocess( /// /// [Rosetta API Spec](https://www.rosetta-api.org/docs/ConstructionApi.html#constructionhash) pub async fn hash( - Extension(env): Extension, + Extension(env): Extension, WithRejection(Json(request), _): WithRejection, Error>, ) -> Result { env.check_network_identifier(&request.network_identifier)?; @@ -223,13 +224,13 @@ pub async fn hash( } /// Get any information required to construct a transaction for a specific -/// network. For Sui, we are returning the latest object refs for all the input +/// network. For Iota, we are returning the latest object refs for all the input /// objects, which will be used in transaction construction. /// /// [Rosetta API Spec](https://www.rosetta-api.org/docs/ConstructionApi.html#constructionmetadata) pub async fn metadata( State(context): State, - Extension(env): Extension, + Extension(env): Extension, WithRejection(Json(request), _): WithRejection, Error>, ) -> Result { env.check_network_identifier(&request.network_identifier)?; @@ -246,7 +247,7 @@ pub async fn metadata( // Get amount, objects, for the operation let (total_required_amount, objects) = match &option.internal_operation { - InternalOperation::PaySui { amounts, .. } => { + InternalOperation::PayIota { amounts, .. } => { let amount = amounts.iter().sum::(); (Some(amount), vec![]) } @@ -263,7 +264,7 @@ pub async fn metadata( .flat_map(|s| { s.stakes.into_iter().filter_map(|s| { if let StakeStatus::Active { .. } = s.status { - Some(s.staked_sui_id) + Some(s.staked_iota_id) } else { None } @@ -281,13 +282,13 @@ pub async fn metadata( let responses = context .client .read_api() - .multi_get_object_with_options(stake_ids, SuiObjectDataOptions::default()) + .multi_get_object_with_options(stake_ids, IotaObjectDataOptions::default()) .await?; let stake_refs = responses .into_iter() .map(|stake| stake.into_object().map(|o| o.object_ref())) .collect::, _>>() - .map_err(SuiError::from)?; + .map_err(IotaError::from)?; (Some(0), stake_refs) } @@ -306,7 +307,7 @@ pub async fn metadata( sender, coins: vec![], objects: objects.clone(), - // Mock coin have 1B SUI + // Mock coin have 1B IOTA total_coin_value: 1_000_000_000 * 1_000_000_000, gas_price, // MAX BUDGET @@ -320,7 +321,7 @@ pub async fn metadata( .await?; let effects = dry_run.effects; - if let SuiExecutionStatus::Failure { error } = effects.status() { + if let IotaExecutionStatus::Failure { error } = effects.status() { return Err(Error::TransactionDryRunError(error.to_string())); } effects.gas_cost_summary().computation_cost + effects.gas_cost_summary().storage_cost @@ -340,8 +341,8 @@ pub async fn metadata( None }; - // If required amount is None (all SUI) or failed to select coin (might not have - // enough SUI), select all coins. + // If required amount is None (all IOTA) or failed to select coin (might not + // have enough IOTA), select all coins. let coins = if let Some(coins) = coins { coins } else { @@ -378,7 +379,7 @@ pub async fn metadata( /// /// [Rosetta API Spec](https://www.rosetta-api.org/docs/ConstructionApi.html#constructionparse) pub async fn parse( - Extension(env): Extension, + Extension(env): Extension, WithRejection(Json(request), _): WithRejection, Error>, ) -> Result { env.check_network_identifier(&request.network_identifier)?; diff --git a/crates/iota-rosetta/src/errors.rs b/crates/iota-rosetta/src/errors.rs new file mode 100644 index 00000000000..373662a1de2 --- /dev/null +++ b/crates/iota-rosetta/src/errors.rs @@ -0,0 +1,140 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt::Debug; + +use axum::{ + extract::rejection::JsonRejection, + http::StatusCode, + response::{IntoResponse, Response}, + Json, +}; +use fastcrypto::error::FastCryptoError; +use iota_types::error::IotaError; +use serde::{Serialize, Serializer}; +use serde_json::{json, Value}; +use strum::{EnumProperty, IntoEnumIterator}; +use strum_macros::{Display, EnumDiscriminants, EnumIter}; +use thiserror::Error; +use typed_store::TypedStoreError; + +use crate::types::{BlockHash, IotaEnv, OperationType, PublicKey}; + +/// Iota-Rosetta specific error types. +/// This contains all the errors returns by the iota-rosetta server. +#[derive(Debug, Error, EnumDiscriminants, EnumProperty)] +#[strum_discriminants( + name(ErrorType), + derive(Display, EnumIter), + strum(serialize_all = "kebab-case") +)] +#[allow(clippy::enum_variant_names)] +pub enum Error { + #[error("Unsupported blockchain: {0}")] + UnsupportedBlockchain(String), + #[error("Unsupported network: {0:?}")] + UnsupportedNetwork(IotaEnv), + #[error("Invalid input: {0}")] + InvalidInput(String), + #[error("Missing input: {0}")] + MissingInput(String), + #[error("Missing metadata")] + MissingMetadata, + #[error("{0}")] + MalformedOperationError(String), + #[error("Unsupported operation: {0:?}")] + UnsupportedOperation(OperationType), + #[error("Data error: {0}")] + DataError(String), + #[error("Block not found, index: {index:?}, hash: {hash:?}")] + BlockNotFound { + index: Option, + hash: Option, + }, + #[error("Public key deserialization error: {0:?}")] + PublicKeyDeserializationError(PublicKey), + + #[error("Error executing transaction: {0}")] + TransactionExecutionError(String), + + #[error("{0}")] + TransactionDryRunError(String), + + #[error(transparent)] + InternalError(#[from] anyhow::Error), + #[error(transparent)] + BCSSerializationError(#[from] bcs::Error), + #[error(transparent)] + CryptoError(#[from] FastCryptoError), + #[error(transparent)] + IotaError(#[from] IotaError), + #[error(transparent)] + IotaRpcError(#[from] iota_sdk::error::Error), + #[error(transparent)] + EncodingError(#[from] eyre::Report), + #[error(transparent)] + DBError(#[from] TypedStoreError), + #[error(transparent)] + JsonExtractorRejection(#[from] JsonRejection), + + #[error("Retries exhausted while getting balance. try again.")] + #[strum(props(retriable = "true"))] + RetryExhausted(String), +} + +impl Serialize for ErrorType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.json().serialize(serializer) + } +} + +trait CustomProperties { + fn retriable(&self) -> bool; +} + +impl CustomProperties for Error { + fn retriable(&self) -> bool { + matches!(self.get_str("retriable"), Some("true")) + } +} + +impl ErrorType { + fn json(&self) -> Value { + let retriable = false; + // Safe to unwrap + let error_code = ErrorType::iter().position(|e| &e == self).unwrap(); + let message = format!("{self}").replace('-', " "); + let message = message[0..1].to_uppercase() + &message[1..]; + + json![{ + "code": error_code, + "message": message, + "retriable": retriable, + }] + } +} + +impl Serialize for Error { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let type_: ErrorType = self.into(); + let mut json = type_.json(); + // Safe to unwrap, we know ErrorType must be an object. + let error = json.as_object_mut().unwrap(); + error.insert("details".into(), json!({ "error": format!("{self}") })); + error.insert("retriable".into(), json!(self.retriable())); + error.serialize(serializer) + } +} + +impl IntoResponse for Error { + fn into_response(self) -> Response { + (StatusCode::INTERNAL_SERVER_ERROR, Json(self)).into_response() + } +} diff --git a/crates/iota-rosetta/src/lib.rs b/crates/iota-rosetta/src/lib.rs new file mode 100644 index 00000000000..6d42c649e7e --- /dev/null +++ b/crates/iota-rosetta/src/lib.rs @@ -0,0 +1,100 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{net::SocketAddr, sync::Arc}; + +use axum::{routing::post, Extension, Router}; +use iota_sdk::IotaClient; +use mysten_metrics::spawn_monitored_task; +use once_cell::sync::Lazy; +use tokio::task::JoinHandle; +use tracing::info; + +use crate::{ + errors::Error, + state::{CheckpointBlockProvider, OnlineServerContext}, + types::{Currency, IotaEnv}, +}; + +/// This lib implements the Rosetta online and offline server defined by the [Rosetta API Spec](https://www.rosetta-api.org/docs/Reference.html) +mod account; +mod block; +mod construction; +mod errors; +mod network; +pub mod operations; +mod state; +pub mod types; + +pub static IOTA: Lazy = Lazy::new(|| Currency { + symbol: "IOTA".to_string(), + decimals: 9, +}); + +pub struct RosettaOnlineServer { + env: IotaEnv, + context: OnlineServerContext, +} + +impl RosettaOnlineServer { + pub fn new(env: IotaEnv, client: IotaClient) -> Self { + let blocks = Arc::new(CheckpointBlockProvider::new(client.clone())); + Self { + env, + context: OnlineServerContext::new(client, blocks), + } + } + + pub fn serve(self, addr: SocketAddr) -> JoinHandle> { + // Online endpoints + let app = Router::new() + .route("/account/balance", post(account::balance)) + .route("/account/coins", post(account::coins)) + .route("/block", post(block::block)) + .route("/block/transaction", post(block::transaction)) + .route("/construction/submit", post(construction::submit)) + .route("/construction/metadata", post(construction::metadata)) + .route("/network/status", post(network::status)) + .route("/network/list", post(network::list)) + .route("/network/options", post(network::options)) + .layer(Extension(self.env)) + .with_state(self.context); + let server = axum::Server::bind(&addr).serve(app.into_make_service()); + info!( + "Iota Rosetta online server listening on {}", + server.local_addr() + ); + spawn_monitored_task!(server) + } +} + +pub struct RosettaOfflineServer { + env: IotaEnv, +} + +impl RosettaOfflineServer { + pub fn new(env: IotaEnv) -> Self { + Self { env } + } + + pub fn serve(self, addr: SocketAddr) -> JoinHandle> { + // Online endpoints + let app = Router::new() + .route("/construction/derive", post(construction::derive)) + .route("/construction/payloads", post(construction::payloads)) + .route("/construction/combine", post(construction::combine)) + .route("/construction/preprocess", post(construction::preprocess)) + .route("/construction/hash", post(construction::hash)) + .route("/construction/parse", post(construction::parse)) + .route("/network/list", post(network::list)) + .route("/network/options", post(network::options)) + .layer(Extension(self.env)); + let server = axum::Server::bind(&addr).serve(app.into_make_service()); + info!( + "Iota Rosetta offline server listening on {}", + server.local_addr() + ); + spawn_monitored_task!(server) + } +} diff --git a/crates/iota-rosetta/src/main.rs b/crates/iota-rosetta/src/main.rs new file mode 100644 index 00000000000..250e6564240 --- /dev/null +++ b/crates/iota-rosetta/src/main.rs @@ -0,0 +1,297 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::BTreeMap, + fs, + fs::File, + io::BufReader, + net::SocketAddr, + path::{Path, PathBuf}, + time::Duration, +}; + +use anyhow::anyhow; +use clap::Parser; +use fastcrypto::{ + encoding::{Encoding, Hex}, + traits::EncodeDecodeBase64, +}; +use iota_config::{ + iota_config_dir, Config, NodeConfig, IOTA_FULLNODE_CONFIG, IOTA_KEYSTORE_FILENAME, +}; +use iota_node::IotaNode; +use iota_rosetta::{ + types::{CurveType, IotaEnv, PrefundedAccount}, + RosettaOfflineServer, RosettaOnlineServer, IOTA, +}; +use iota_sdk::{IotaClient, IotaClientBuilder}; +use iota_types::{ + base_types::IotaAddress, + crypto::{IotaKeyPair, KeypairTraits, ToFromBytes}, +}; +use serde_json::{json, Value}; +use tracing::{info, log::warn}; + +#[derive(Parser)] +#[clap(name = "iota-rosetta", rename_all = "kebab-case", author, version)] +pub enum RosettaServerCommand { + GenerateRosettaCLIConfig { + #[clap(long)] + keystore_path: Option, + #[clap(long, default_value = "localnet")] + env: IotaEnv, + #[clap(long, default_value = "http://rosetta-online:9002")] + online_url: String, + #[clap(long, default_value = "http://rosetta-offline:9003")] + offline_url: String, + }, + StartOnlineRemoteServer { + #[clap(long, default_value = "localnet")] + env: IotaEnv, + #[clap(long, default_value = "0.0.0.0:9002")] + addr: SocketAddr, + #[clap(long)] + full_node_url: String, + #[clap(long, default_value = "/data")] + data_path: PathBuf, + }, + StartOnlineServer { + #[clap(long, default_value = "localnet")] + env: IotaEnv, + #[clap(long, default_value = "0.0.0.0:9002")] + addr: SocketAddr, + #[clap(long)] + node_config: Option, + #[clap(long, default_value = "/data")] + data_path: PathBuf, + }, + StartOfflineServer { + #[clap(long, default_value = "localnet")] + env: IotaEnv, + #[clap(long, default_value = "0.0.0.0:9003")] + addr: SocketAddr, + }, +} + +impl RosettaServerCommand { + async fn execute(self) -> Result<(), anyhow::Error> { + match self { + RosettaServerCommand::GenerateRosettaCLIConfig { + keystore_path, + env, + online_url, + offline_url, + } => { + let path = keystore_path + .unwrap_or_else(|| iota_config_dir().unwrap().join(IOTA_KEYSTORE_FILENAME)); + + let prefunded_accounts = read_prefunded_account(&path)?; + + info!( + "Retrieved {} Iota address from keystore file {:?}", + prefunded_accounts.len(), + &path + ); + + let mut config: Value = + serde_json::from_str(include_str!("../resources/rosetta_cli.json"))?; + + config + .as_object_mut() + .unwrap() + .insert("online_url".into(), json!(online_url)); + + // Set network. + let network = config.pointer_mut("/network").ok_or_else(|| { + anyhow!("Cannot find construction config in default config file.") + })?; + network + .as_object_mut() + .unwrap() + .insert("network".into(), json!(env)); + + // Add prefunded accounts. + let construction = config.pointer_mut("/construction").ok_or_else(|| { + anyhow!("Cannot find construction config in default config file.") + })?; + + let construction = construction.as_object_mut().unwrap(); + construction.insert("prefunded_accounts".into(), json!(prefunded_accounts)); + construction.insert("offline_url".into(), json!(offline_url)); + + let config_path = PathBuf::from(".").join("rosetta_cli.json"); + fs::write(&config_path, serde_json::to_string_pretty(&config)?)?; + info!( + "Rosetta CLI configuration file is stored in {:?}", + config_path + ); + + let dsl_path = PathBuf::from(".").join("iota.ros"); + let dsl = include_str!("../resources/iota.ros"); + fs::write( + &dsl_path, + dsl.replace("{{iota.env}}", json!(env).as_str().unwrap()), + )?; + info!("Rosetta DSL file is stored in {:?}", dsl_path); + } + RosettaServerCommand::StartOfflineServer { env, addr } => { + info!("Starting Rosetta Offline Server."); + let server = RosettaOfflineServer::new(env); + server.serve(addr).await??; + } + RosettaServerCommand::StartOnlineRemoteServer { + env, + addr, + full_node_url, + data_path, + } => { + info!( + "Starting Rosetta Online Server with remove Iota full node [{full_node_url}]." + ); + let iota_client = wait_for_iota_client(full_node_url).await; + let rosetta_path = data_path.join("rosetta_db"); + info!("Rosetta db path : {rosetta_path:?}"); + let rosetta = RosettaOnlineServer::new(env, iota_client); + rosetta.serve(addr).await??; + } + + RosettaServerCommand::StartOnlineServer { + env, + addr, + node_config, + data_path, + } => { + info!("Starting Rosetta Online Server with embedded Iota full node."); + info!("Data directory path: {data_path:?}"); + + let node_config = node_config.unwrap_or_else(|| { + let path = iota_config_dir().unwrap().join(IOTA_FULLNODE_CONFIG); + info!("Using default node config from {path:?}"); + path + }); + + let mut config = NodeConfig::load(&node_config)?; + config.db_path = data_path.join("iota_db"); + info!("Overriding Iota db path to : {:?}", config.db_path); + + let registry_service = + mysten_metrics::start_prometheus_server(config.metrics_address); + // Staring a full node for the rosetta server. + let rpc_address = format!("http://127.0.0.1:{}", config.json_rpc_address.port()); + let _node = IotaNode::start(config, registry_service, None).await?; + + let iota_client = wait_for_iota_client(rpc_address).await; + + let rosetta_path = data_path.join("rosetta_db"); + info!("Rosetta db path : {rosetta_path:?}"); + let rosetta = RosettaOnlineServer::new(env, iota_client); + rosetta.serve(addr).await??; + } + }; + Ok(()) + } +} + +async fn wait_for_iota_client(rpc_address: String) -> IotaClient { + loop { + match IotaClientBuilder::default() + .max_concurrent_requests(usize::MAX) + .build(&rpc_address) + .await + { + Ok(client) => return client, + Err(e) => { + warn!( + "Error connecting to Iota RPC server [{rpc_address}]: {e}, retrying in 5 seconds." + ); + tokio::time::sleep(Duration::from_millis(5000)).await; + } + } + } +} + +/// This method reads the keypairs from the Iota keystore to create the +/// PrefundedAccount objects, PrefundedAccount will be written to the +/// rosetta-cli config file for testing. +fn read_prefunded_account(path: &Path) -> Result, anyhow::Error> { + let reader = BufReader::new(File::open(path).unwrap()); + let kp_strings: Vec = serde_json::from_reader(reader).unwrap(); + let keys = kp_strings + .iter() + .map(|kpstr| { + let key = IotaKeyPair::decode_base64(kpstr); + key.map(|k| (IotaAddress::from(&k.public()), k)) + }) + .collect::, _>>() + .unwrap(); + + Ok(keys + .into_iter() + .map(|(address, key)| { + let (privkey, curve_type) = match key { + IotaKeyPair::Ed25519(k) => { + (Hex::encode(k.private().as_bytes()), CurveType::Edwards25519) + } + IotaKeyPair::Secp256k1(k) => { + (Hex::encode(k.private().as_bytes()), CurveType::Secp256k1) + } + IotaKeyPair::Secp256r1(k) => { + (Hex::encode(k.private().as_bytes()), CurveType::Secp256r1) + } + }; + PrefundedAccount { + privkey, + account_identifier: address.into(), + curve_type, + currency: IOTA.clone(), + } + }) + .collect()) +} + +#[test] +fn test_read_keystore() { + use iota_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; + use iota_types::crypto::SignatureScheme; + + let temp_dir = tempfile::tempdir().unwrap(); + let path = temp_dir.path().join("iota.keystore"); + let mut ks = Keystore::from(FileBasedKeystore::new(&path).unwrap()); + let key1 = ks + .generate_and_add_new_key(SignatureScheme::ED25519, None, None, None) + .unwrap(); + let key2 = ks + .generate_and_add_new_key(SignatureScheme::Secp256k1, None, None, None) + .unwrap(); + + let accounts = read_prefunded_account(&path).unwrap(); + let acc_map = accounts + .into_iter() + .map(|acc| (acc.account_identifier.address, acc)) + .collect::>(); + + assert_eq!(2, acc_map.len()); + assert!(acc_map.contains_key(&key1.0)); + assert!(acc_map.contains_key(&key2.0)); + + let acc1 = acc_map[&key1.0].clone(); + let acc2 = acc_map[&key2.0].clone(); + + let schema1: SignatureScheme = acc1.curve_type.into(); + let schema2: SignatureScheme = acc2.curve_type.into(); + assert!(matches!(schema1, SignatureScheme::ED25519)); + assert!(matches!(schema2, SignatureScheme::Secp256k1)); +} + +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + let cmd: RosettaServerCommand = RosettaServerCommand::parse(); + + let (_guard, _) = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .init(); + + cmd.execute().await +} diff --git a/crates/sui-rosetta/src/network.rs b/crates/iota-rosetta/src/network.rs similarity index 88% rename from crates/sui-rosetta/src/network.rs rename to crates/iota-rosetta/src/network.rs index 5720e9b1187..bf24a84535c 100644 --- a/crates/sui-rosetta/src/network.rs +++ b/crates/iota-rosetta/src/network.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use axum::{extract::State, Extension, Json}; use axum_extra::extract::WithRejection; use fastcrypto::encoding::Hex; +use iota_types::base_types::ObjectID; use serde_json::json; use strum::IntoEnumIterator; -use sui_types::base_types::ObjectID; use crate::{ errors::{Error, ErrorType}, @@ -15,7 +16,7 @@ use crate::{ NetworkRequest, NetworkStatusResponse, OperationStatus, OperationType, Peer, SyncStatus, Version, }, - OnlineServerContext, SuiEnv, + IotaEnv, OnlineServerContext, }; /// This module implements the [Rosetta Network API](https://www.rosetta-api.org/docs/NetworkApi.html) @@ -24,10 +25,10 @@ use crate::{ /// supports. /// /// [Rosetta API Spec](https://www.rosetta-api.org/docs/NetworkApi.html#networklist) -pub async fn list(Extension(env): Extension) -> Result { +pub async fn list(Extension(env): Extension) -> Result { Ok(NetworkListResponse { network_identifiers: vec![NetworkIdentifier { - blockchain: "sui".to_string(), + blockchain: "iota".to_string(), network: env, }], }) @@ -38,7 +39,7 @@ pub async fn list(Extension(env): Extension) -> Result, - Extension(env): Extension, + Extension(env): Extension, WithRejection(Json(request), _): WithRejection, Error>, ) -> Result { env.check_network_identifier(&request.network_identifier)?; @@ -46,17 +47,17 @@ pub async fn status( let system_state = context .client .governance_api() - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await?; let peers = system_state .active_validators .iter() .map(|validator| Peer { - peer_id: ObjectID::from(validator.sui_address).into(), + peer_id: ObjectID::from(validator.iota_address).into(), metadata: Some(json!({ "public_key": Hex::from_bytes(&validator.protocol_pubkey_bytes), - "stake_amount": validator.staking_pool_sui_balance, + "stake_amount": validator.staking_pool_iota_balance, })), }) .collect(); @@ -89,7 +90,7 @@ pub async fn status( /// /// [Rosetta API Spec](https://www.rosetta-api.org/docs/NetworkApi.html#networkoptions) pub async fn options( - Extension(env): Extension, + Extension(env): Extension, WithRejection(Json(request), _): WithRejection, Error>, ) -> Result { env.check_network_identifier(&request.network_identifier)?; diff --git a/crates/sui-rosetta/src/operations.rs b/crates/iota-rosetta/src/operations.rs similarity index 82% rename from crates/sui-rosetta/src/operations.rs rename to crates/iota-rosetta/src/operations.rs index 2ee763a5928..d30ff143783 100644 --- a/crates/sui-rosetta/src/operations.rs +++ b/crates/iota-rosetta/src/operations.rs @@ -1,32 +1,33 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, ops::Not, str::FromStr, vec}; use anyhow::anyhow; -use move_core_types::{ - ident_str, - language_storage::{ModuleId, StructTag}, - resolver::ModuleResolver, -}; -use serde::{Deserialize, Serialize}; -use sui_json_rpc_types::{ - BalanceChange, SuiArgument, SuiCallArg, SuiCommand, SuiProgrammableMoveCall, - SuiProgrammableTransactionBlock, +use iota_json_rpc_types::{ + BalanceChange, IotaArgument, IotaCallArg, IotaCommand, IotaProgrammableMoveCall, + IotaProgrammableTransactionBlock, }; -use sui_sdk::rpc_types::{ - SuiTransactionBlockData, SuiTransactionBlockDataAPI, SuiTransactionBlockEffectsAPI, - SuiTransactionBlockKind, SuiTransactionBlockResponse, +use iota_sdk::rpc_types::{ + IotaTransactionBlockData, IotaTransactionBlockDataAPI, IotaTransactionBlockEffectsAPI, + IotaTransactionBlockKind, IotaTransactionBlockResponse, }; -use sui_types::{ - base_types::{ObjectID, SequenceNumber, SuiAddress}, +use iota_types::{ + base_types::{IotaAddress, ObjectID, SequenceNumber}, gas_coin::{GasCoin, GAS}, governance::{ADD_STAKE_FUN_NAME, WITHDRAW_STAKE_FUN_NAME}, + iota_system_state::IOTA_SYSTEM_MODULE_NAME, object::Owner, - sui_system_state::SUI_SYSTEM_MODULE_NAME, transaction::TransactionData, - SUI_SYSTEM_ADDRESS, SUI_SYSTEM_PACKAGE_ID, + IOTA_SYSTEM_ADDRESS, IOTA_SYSTEM_PACKAGE_ID, }; +use move_core_types::{ + ident_str, + language_storage::{ModuleId, StructTag}, + resolver::ModuleResolver, +}; +use serde::{Deserialize, Serialize}; use crate::{ types::{ @@ -102,14 +103,14 @@ impl Operations { .type_() .ok_or_else(|| Error::MissingInput("Operation type".into()))?; match type_ { - OperationType::PaySui => self.pay_sui_ops_to_internal(), + OperationType::PayIota => self.pay_iota_ops_to_internal(), OperationType::Stake => self.stake_ops_to_internal(), OperationType::WithdrawStake => self.withdraw_stake_ops_to_internal(), op => Err(Error::UnsupportedOperation(op)), } } - fn pay_sui_ops_to_internal(self) -> Result { + fn pay_iota_ops_to_internal(self) -> Result { let mut recipients = vec![]; let mut amounts = vec![]; let mut sender = None; @@ -130,7 +131,7 @@ impl Operations { } } let sender = sender.ok_or_else(|| Error::MissingInput("Sender address".to_string()))?; - Ok(InternalOperation::PaySui { + Ok(InternalOperation::PayIota { sender, recipients, amounts, @@ -216,12 +217,12 @@ impl Operations { } fn from_transaction( - tx: SuiTransactionBlockKind, - sender: SuiAddress, + tx: IotaTransactionBlockKind, + sender: IotaAddress, status: Option, ) -> Result, Error> { Ok(match tx { - SuiTransactionBlockKind::ProgrammableTransaction(pt) => { + IotaTransactionBlockKind::ProgrammableTransaction(pt) => { Self::parse_programmable_transaction(sender, status, pt)? } _ => vec![Operation::generic_op(status, sender, tx)], @@ -229,9 +230,9 @@ impl Operations { } fn parse_programmable_transaction( - sender: SuiAddress, + sender: IotaAddress, status: Option, - pt: SuiProgrammableTransactionBlock, + pt: IotaProgrammableTransactionBlock, ) -> Result, Error> { #[derive(Debug)] enum KnownValue { @@ -247,33 +248,33 @@ impl Operations { .and_then(|inner| inner.get(j as usize)) } fn split_coins( - inputs: &[SuiCallArg], + inputs: &[IotaCallArg], known_results: &[Vec], - coin: SuiArgument, - amounts: &[SuiArgument], + coin: IotaArgument, + amounts: &[IotaArgument], ) -> Option> { match coin { - SuiArgument::Result(i) => { + IotaArgument::Result(i) => { let KnownValue::GasCoin(_) = resolve_result(known_results, i, 0)?; } - SuiArgument::NestedResult(i, j) => { + IotaArgument::NestedResult(i, j) => { let KnownValue::GasCoin(_) = resolve_result(known_results, i, j)?; } - SuiArgument::GasCoin => (), - // Might not be a SUI coin - SuiArgument::Input(_) => return None, + IotaArgument::GasCoin => (), + // Might not be a IOTA coin + IotaArgument::Input(_) => return None, }; let amounts = amounts .iter() .map(|amount| { let value: u64 = match *amount { - SuiArgument::Input(i) => { + IotaArgument::Input(i) => { u64::from_str(inputs[i as usize].pure()?.to_json_value().as_str()?) .ok()? } - SuiArgument::GasCoin - | SuiArgument::Result(_) - | SuiArgument::NestedResult(_, _) => return None, + IotaArgument::GasCoin + | IotaArgument::Result(_) + | IotaArgument::NestedResult(_, _) => return None, }; Some(KnownValue::GasCoin(value)) }) @@ -281,29 +282,31 @@ impl Operations { Some(amounts) } fn transfer_object( - aggregated_recipients: &mut HashMap, - inputs: &[SuiCallArg], + aggregated_recipients: &mut HashMap, + inputs: &[IotaCallArg], known_results: &[Vec], - objs: &[SuiArgument], - recipient: SuiArgument, + objs: &[IotaArgument], + recipient: IotaArgument, ) -> Option> { let addr = match recipient { - SuiArgument::Input(i) => inputs[i as usize].pure()?.to_sui_address().ok()?, - SuiArgument::GasCoin | SuiArgument::Result(_) | SuiArgument::NestedResult(_, _) => { + IotaArgument::Input(i) => inputs[i as usize].pure()?.to_iota_address().ok()?, + IotaArgument::GasCoin + | IotaArgument::Result(_) + | IotaArgument::NestedResult(_, _) => { return None; } }; for obj in objs { let value = match *obj { - SuiArgument::Result(i) => { + IotaArgument::Result(i) => { let KnownValue::GasCoin(value) = resolve_result(known_results, i, 0)?; value } - SuiArgument::NestedResult(i, j) => { + IotaArgument::NestedResult(i, j) => { let KnownValue::GasCoin(value) = resolve_result(known_results, i, j)?; value } - SuiArgument::GasCoin | SuiArgument::Input(_) => return None, + IotaArgument::GasCoin | IotaArgument::Input(_) => return None, }; let aggregate = aggregated_recipients.entry(addr).or_default(); *aggregate += value; @@ -311,15 +314,15 @@ impl Operations { Some(vec![]) } fn stake_call( - inputs: &[SuiCallArg], + inputs: &[IotaCallArg], known_results: &[Vec], - call: &SuiProgrammableMoveCall, - ) -> Result, SuiAddress)>, Error> { - let SuiProgrammableMoveCall { arguments, .. } = call; + call: &IotaProgrammableMoveCall, + ) -> Result, IotaAddress)>, Error> { + let IotaProgrammableMoveCall { arguments, .. } = call; let (amount, validator) = match &arguments[..] { [_, coin, validator] => { let amount = match coin { - SuiArgument::Result(i) => { + IotaArgument::Result(i) => { let KnownValue::GasCoin(value) = resolve_result(known_results, *i, 0) .ok_or_else(|| { anyhow!("Cannot resolve Gas coin value at Result({i})") @@ -335,11 +338,11 @@ impl Operations { // stake transaction is staking the whole wallet or // not, if staking whole wallet, we have to omit the // amount value in the final operation output. - SuiArgument::Input(i) => ( + IotaArgument::Input(i) => ( *i == 1, inputs[*i as usize] .pure() - .map(|v| v.to_sui_address()) + .map(|v| v.to_iota_address()) .transpose(), ), _ => return Ok(None), @@ -355,14 +358,14 @@ impl Operations { } fn unstake_call( - inputs: &[SuiCallArg], - call: &SuiProgrammableMoveCall, + inputs: &[IotaCallArg], + call: &IotaProgrammableMoveCall, ) -> Result, Error> { - let SuiProgrammableMoveCall { arguments, .. } = call; + let IotaProgrammableMoveCall { arguments, .. } = call; let id = match &arguments[..] { [_, stake_id] => { match stake_id { - SuiArgument::Input(i) => { + IotaArgument::Input(i) => { let id = inputs[*i as usize] .object() .ok_or_else(|| anyhow!("Cannot find stake id from input args."))?; @@ -382,25 +385,25 @@ impl Operations { }; Ok(id.cloned()) } - let SuiProgrammableTransactionBlock { inputs, commands } = &pt; + let IotaProgrammableTransactionBlock { inputs, commands } = &pt; let mut known_results: Vec> = vec![]; - let mut aggregated_recipients: HashMap = HashMap::new(); + let mut aggregated_recipients: HashMap = HashMap::new(); let mut needs_generic = false; let mut operations = vec![]; let mut stake_ids = vec![]; for command in commands { let result = match command { - SuiCommand::SplitCoins(coin, amounts) => { + IotaCommand::SplitCoins(coin, amounts) => { split_coins(inputs, &known_results, *coin, amounts) } - SuiCommand::TransferObjects(objs, addr) => transfer_object( + IotaCommand::TransferObjects(objs, addr) => transfer_object( &mut aggregated_recipients, inputs, &known_results, objs, *addr, ), - SuiCommand::MoveCall(m) if Self::is_stake_call(m) => { + IotaCommand::MoveCall(m) if Self::is_stake_call(m) => { stake_call(inputs, &known_results, m)?.map(|(amount, validator)| { let amount = amount.map(|amount| Amount::new(-(amount as i128))); operations.push(Operation { @@ -415,7 +418,7 @@ impl Operations { vec![] }) } - SuiCommand::MoveCall(m) if Self::is_unstake_call(m) => { + IotaCommand::MoveCall(m) if Self::is_unstake_call(m) => { let stake_id = unstake_call(inputs, m)?; stake_ids.push(stake_id); Some(vec![]) @@ -436,10 +439,10 @@ impl Operations { aggregated_recipients .into_iter() .map(|(recipient, amount)| { - Operation::pay_sui(status, recipient, amount.into()) + Operation::pay_iota(status, recipient, amount.into()) }), ); - operations.push(Operation::pay_sui(status, sender, -(total_paid as i128))); + operations.push(Operation::pay_iota(status, sender, -(total_paid as i128))); } else if !stake_ids.is_empty() { let stake_ids = stake_ids.into_iter().flatten().collect::>(); let metadata = stake_ids @@ -459,30 +462,30 @@ impl Operations { operations.push(Operation::generic_op( status, sender, - SuiTransactionBlockKind::ProgrammableTransaction(pt), + IotaTransactionBlockKind::ProgrammableTransaction(pt), )) } Ok(operations) } - fn is_stake_call(tx: &SuiProgrammableMoveCall) -> bool { - tx.package == SUI_SYSTEM_PACKAGE_ID - && tx.module == SUI_SYSTEM_MODULE_NAME.as_str() + fn is_stake_call(tx: &IotaProgrammableMoveCall) -> bool { + tx.package == IOTA_SYSTEM_PACKAGE_ID + && tx.module == IOTA_SYSTEM_MODULE_NAME.as_str() && tx.function == ADD_STAKE_FUN_NAME.as_str() } - fn is_unstake_call(tx: &SuiProgrammableMoveCall) -> bool { - tx.package == SUI_SYSTEM_PACKAGE_ID - && tx.module == SUI_SYSTEM_MODULE_NAME.as_str() + fn is_unstake_call(tx: &IotaProgrammableMoveCall) -> bool { + tx.package == IOTA_SYSTEM_PACKAGE_ID + && tx.module == IOTA_SYSTEM_MODULE_NAME.as_str() && tx.function == WITHDRAW_STAKE_FUN_NAME.as_str() } fn process_balance_change( - gas_owner: SuiAddress, + gas_owner: IotaAddress, gas_used: i128, balance_changes: &[BalanceChange], status: Option, - balances: HashMap, + balances: HashMap, ) -> impl Iterator { let mut balances = balance_changes .iter() @@ -513,9 +516,9 @@ impl Operations { } } -impl TryFrom for Operations { +impl TryFrom for Operations { type Error = Error; - fn try_from(data: SuiTransactionBlockData) -> Result { + fn try_from(data: IotaTransactionBlockData) -> Result { let sender = *data.sender(); Ok(Self::new(Self::from_transaction( data.transaction().clone(), @@ -525,9 +528,9 @@ impl TryFrom for Operations { } } -impl TryFrom for Operations { +impl TryFrom for Operations { type Error = Error; - fn try_from(response: SuiTransactionBlockResponse) -> Result { + fn try_from(response: IotaTransactionBlockResponse) -> Result { let tx = response .transaction .ok_or_else(|| anyhow!("Response input should not be empty"))?; @@ -616,7 +619,7 @@ impl TryFrom for Operations { } fn is_unstake_event(tag: &StructTag) -> bool { - tag.address == SUI_SYSTEM_ADDRESS + tag.address == IOTA_SYSTEM_ADDRESS && tag.module.as_ident_str() == ident_str!("validator") && tag.name.as_ident_str() == ident_str!("UnstakingRequestEvent") } @@ -632,7 +635,7 @@ impl TryFrom for Operations { } } // Rosetta don't need the call args to be parsed into readable format - SuiTransactionBlockData::try_from(data, &&mut NoOpsModuleResolver)?.try_into() + IotaTransactionBlockData::try_from(data, &&mut NoOpsModuleResolver)?.try_into() } } @@ -666,16 +669,16 @@ impl PartialEq for Operation { #[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)] pub enum OperationMetadata { - GenericTransaction(SuiTransactionBlockKind), - Stake { validator: SuiAddress }, + GenericTransaction(IotaTransactionBlockKind), + Stake { validator: IotaAddress }, WithdrawStake { stake_ids: Vec }, } impl Operation { fn generic_op( status: Option, - sender: SuiAddress, - tx: SuiTransactionBlockKind, + sender: IotaAddress, + tx: IotaTransactionBlockKind, ) -> Self { Operation { operation_identifier: Default::default(), @@ -688,7 +691,7 @@ impl Operation { } } - pub fn genesis(index: u64, sender: SuiAddress, coin: GasCoin) -> Self { + pub fn genesis(index: u64, sender: IotaAddress, coin: GasCoin) -> Self { Operation { operation_identifier: index.into(), type_: OperationType::Genesis, @@ -708,10 +711,10 @@ impl Operation { } } - fn pay_sui(status: Option, address: SuiAddress, amount: i128) -> Self { + fn pay_iota(status: Option, address: IotaAddress, amount: i128) -> Self { Operation { operation_identifier: Default::default(), - type_: OperationType::PaySui, + type_: OperationType::PayIota, status, account: Some(address.into()), amount: Some(Amount::new(amount)), @@ -720,10 +723,10 @@ impl Operation { } } - fn balance_change(status: Option, addr: SuiAddress, amount: i128) -> Self { + fn balance_change(status: Option, addr: IotaAddress, amount: i128) -> Self { Self { operation_identifier: Default::default(), - type_: OperationType::SuiBalanceChange, + type_: OperationType::IotaBalanceChange, status, account: Some(addr.into()), amount: Some(Amount::new(amount)), @@ -731,7 +734,7 @@ impl Operation { metadata: None, } } - fn gas(addr: SuiAddress, amount: i128) -> Self { + fn gas(addr: IotaAddress, amount: i128) -> Self { Self { operation_identifier: Default::default(), type_: OperationType::Gas, @@ -742,7 +745,7 @@ impl Operation { metadata: None, } } - fn stake_reward(status: Option, addr: SuiAddress, amount: i128) -> Self { + fn stake_reward(status: Option, addr: IotaAddress, amount: i128) -> Self { Self { operation_identifier: Default::default(), type_: OperationType::StakeReward, @@ -753,7 +756,7 @@ impl Operation { metadata: None, } } - fn stake_principle(status: Option, addr: SuiAddress, amount: i128) -> Self { + fn stake_principle(status: Option, addr: IotaAddress, amount: i128) -> Self { Self { operation_identifier: Default::default(), type_: OperationType::StakePrinciple, diff --git a/crates/sui-rosetta/src/state.rs b/crates/iota-rosetta/src/state.rs similarity index 91% rename from crates/sui-rosetta/src/state.rs rename to crates/iota-rosetta/src/state.rs index 569f084f623..fafa1950abe 100644 --- a/crates/sui-rosetta/src/state.rs +++ b/crates/iota-rosetta/src/state.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; use async_trait::async_trait; -use sui_json_rpc_types::SuiTransactionBlockResponseOptions; -use sui_sdk::{rpc_types::Checkpoint, SuiClient}; -use sui_types::messages_checkpoint::CheckpointSequenceNumber; +use iota_json_rpc_types::IotaTransactionBlockResponseOptions; +use iota_sdk::{rpc_types::Checkpoint, IotaClient}; +use iota_types::messages_checkpoint::CheckpointSequenceNumber; use crate::{ operations::Operations, @@ -20,12 +21,12 @@ mod balance_changing_tx_tests; #[derive(Clone)] pub struct OnlineServerContext { - pub client: SuiClient, + pub client: IotaClient, block_provider: Arc, } impl OnlineServerContext { - pub fn new(client: SuiClient, block_provider: Arc) -> Self { + pub fn new(client: IotaClient, block_provider: Arc) -> Self { Self { client, block_provider, @@ -53,7 +54,7 @@ pub trait BlockProvider { #[derive(Clone)] pub struct CheckpointBlockProvider { - client: SuiClient, + client: IotaClient, } #[async_trait] @@ -104,7 +105,7 @@ impl BlockProvider for CheckpointBlockProvider { } impl CheckpointBlockProvider { - pub fn new(client: SuiClient) -> Self { + pub fn new(client: IotaClient) -> Self { Self { client } } @@ -118,7 +119,7 @@ impl CheckpointBlockProvider { .read_api() .multi_get_transactions_with_options( batch.to_vec(), - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_input() .with_effects() .with_balance_changes() diff --git a/crates/iota-rosetta/src/types.rs b/crates/iota-rosetta/src/types.rs new file mode 100644 index 00000000000..96afb99a4ff --- /dev/null +++ b/crates/iota-rosetta/src/types.rs @@ -0,0 +1,968 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{fmt::Debug, str::FromStr}; + +use axum::{ + response::{IntoResponse, Response}, + Json, +}; +use fastcrypto::encoding::Hex; +use iota_sdk::rpc_types::{IotaExecutionStatus, IotaTransactionBlockKind}; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber, TransactionDigest}, + crypto::{PublicKey as IotaPublicKey, SignatureScheme}, + governance::{ADD_STAKE_FUN_NAME, WITHDRAW_STAKE_FUN_NAME}, + iota_system_state::IOTA_SYSTEM_MODULE_NAME, + messages_checkpoint::CheckpointDigest, + programmable_transaction_builder::ProgrammableTransactionBuilder, + transaction::{Argument, CallArg, Command, ObjectArg, TransactionData}, + IOTA_SYSTEM_PACKAGE_ID, +}; +use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer}; +use serde_json::Value; +use strum_macros::{EnumIter, EnumString}; + +use crate::{ + errors::{Error, ErrorType}, + operations::Operations, + IOTA, +}; + +pub type BlockHeight = u64; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct NetworkIdentifier { + pub blockchain: String, + pub network: IotaEnv, +} + +#[derive( + Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Debug, Clone, Copy, EnumString, +)] +#[strum(serialize_all = "lowercase")] +#[serde(rename_all = "lowercase")] +pub enum IotaEnv { + MainNet, + DevNet, + TestNet, + LocalNet, +} + +impl IotaEnv { + pub fn check_network_identifier( + &self, + network_identifier: &NetworkIdentifier, + ) -> Result<(), Error> { + if &network_identifier.blockchain != "iota" { + return Err(Error::UnsupportedBlockchain( + network_identifier.blockchain.clone(), + )); + } + if &network_identifier.network != self { + return Err(Error::UnsupportedNetwork(network_identifier.network)); + } + Ok(()) + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] +pub struct AccountIdentifier { + pub address: IotaAddress, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub sub_account: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] +pub struct SubAccount { + #[serde(rename = "address")] + pub account_type: SubAccountType, +} + +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] +pub enum SubAccountType { + Stake, + PendingStake, + EstimatedReward, +} + +impl From for AccountIdentifier { + fn from(address: IotaAddress) -> Self { + AccountIdentifier { + address, + sub_account: None, + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] +pub struct Currency { + pub symbol: String, + pub decimals: u64, +} +#[derive(Serialize, Deserialize)] +pub struct AccountBalanceRequest { + pub network_identifier: NetworkIdentifier, + pub account_identifier: AccountIdentifier, + #[serde(default)] + pub block_identifier: PartialBlockIdentifier, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub currencies: Vec, +} +#[derive(Serialize, Deserialize, Debug)] +pub struct AccountBalanceResponse { + pub block_identifier: BlockIdentifier, + pub balances: Vec, +} + +impl IntoResponse for AccountBalanceResponse { + fn into_response(self) -> Response { + Json(self).into_response() + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, Copy)] +pub struct BlockIdentifier { + pub index: BlockHeight, + pub hash: BlockHash, +} + +pub type BlockHash = CheckpointDigest; + +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] +pub struct Amount { + #[serde(with = "str_format")] + pub value: i128, + pub currency: Currency, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub metadata: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] +pub struct AmountMetadata { + pub sub_balances: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] +pub struct SubBalance { + pub stake_id: ObjectID, + pub validator: IotaAddress, + #[serde(with = "str_format")] + pub value: i128, +} + +impl Amount { + pub fn new(value: i128) -> Self { + Self { + value, + currency: IOTA.clone(), + metadata: None, + } + } + pub fn new_from_sub_balances(sub_balances: Vec) -> Self { + let value = sub_balances.iter().map(|b| b.value).sum(); + + Self { + value, + currency: IOTA.clone(), + metadata: Some(AmountMetadata { sub_balances }), + } + } +} + +mod str_format { + use std::str::FromStr; + + use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; + + pub fn serialize(value: &i128, serializer: S) -> Result + where + S: Serializer, + { + value.to_string().serialize(serializer) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + i128::from_str(&s).map_err(Error::custom) + } +} + +#[derive(Deserialize)] +pub struct AccountCoinsRequest { + pub network_identifier: NetworkIdentifier, + pub account_identifier: AccountIdentifier, + pub include_mempool: bool, +} +#[derive(Serialize)] +pub struct AccountCoinsResponse { + pub block_identifier: BlockIdentifier, + pub coins: Vec, +} +impl IntoResponse for AccountCoinsResponse { + fn into_response(self) -> Response { + Json(self).into_response() + } +} +#[derive(Serialize)] +pub struct Coin { + pub coin_identifier: CoinIdentifier, + pub amount: Amount, +} + +impl From for Coin { + fn from(coin: iota_sdk::rpc_types::Coin) -> Self { + Self { + coin_identifier: CoinIdentifier { + identifier: CoinID { + id: coin.coin_object_id, + version: coin.version, + }, + }, + amount: Amount { + value: coin.balance as i128, + currency: IOTA.clone(), + metadata: None, + }, + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] +pub struct CoinIdentifier { + pub identifier: CoinID, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CoinID { + pub id: ObjectID, + pub version: SequenceNumber, +} + +impl Serialize for CoinID { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + format!("{}:{}", self.id, self.version.value()).serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for CoinID { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + + let (id, version) = s.split_at( + s.find(':') + .ok_or_else(|| D::Error::custom(format!("Malformed Coin id [{s}].")))?, + ); + let version = version.trim_start_matches(':'); + let id = ObjectID::from_hex_literal(id).map_err(D::Error::custom)?; + let version = SequenceNumber::from_u64(u64::from_str(version).map_err(D::Error::custom)?); + + Ok(Self { id, version }) + } +} + +#[test] +fn test_coin_id_serde() { + let id = ObjectID::random(); + let coin_id = CoinID { + id, + version: SequenceNumber::from_u64(10), + }; + let s = serde_json::to_string(&coin_id).unwrap(); + assert_eq!(format!("\"{}:{}\"", id, 10), s); + + let deserialized: CoinID = serde_json::from_str(&s).unwrap(); + + assert_eq!(id, deserialized.id); + assert_eq!(SequenceNumber::from_u64(10), deserialized.version) +} + +impl From for CoinID { + fn from((id, version, _): ObjectRef) -> Self { + Self { id, version } + } +} + +#[derive(Deserialize)] +pub struct MetadataRequest { + #[serde(default)] + pub metadata: Option, +} + +#[derive(Serialize)] +pub struct NetworkListResponse { + pub network_identifiers: Vec, +} + +impl IntoResponse for NetworkListResponse { + fn into_response(self) -> Response { + Json(self).into_response() + } +} + +#[derive(Deserialize)] +pub struct ConstructionDeriveRequest { + pub network_identifier: NetworkIdentifier, + pub public_key: PublicKey, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct PublicKey { + pub hex_bytes: Hex, + pub curve_type: CurveType, +} + +impl From for PublicKey { + fn from(pk: IotaPublicKey) -> Self { + match pk { + IotaPublicKey::Ed25519(k) => PublicKey { + hex_bytes: Hex::from_bytes(&k.0), + curve_type: CurveType::Edwards25519, + }, + IotaPublicKey::Secp256k1(k) => PublicKey { + hex_bytes: Hex::from_bytes(&k.0), + curve_type: CurveType::Secp256k1, + }, + IotaPublicKey::Secp256r1(k) => PublicKey { + hex_bytes: Hex::from_bytes(&k.0), + curve_type: CurveType::Secp256r1, + }, + IotaPublicKey::ZkLogin(k) => PublicKey { + hex_bytes: Hex::from_bytes(&k.0), + curve_type: CurveType::ZkLogin, // inaccurate but added for completeness. + }, + } + } +} + +impl TryInto for PublicKey { + type Error = Error; + + fn try_into(self) -> Result { + let key_bytes = self.hex_bytes.to_vec()?; + let pub_key = IotaPublicKey::try_from_bytes(self.curve_type.into(), &key_bytes)?; + Ok((&pub_key).into()) + } +} + +#[derive(Deserialize, Serialize, Copy, Clone, Debug)] +#[serde(rename_all = "lowercase")] +pub enum CurveType { + Secp256k1, + Edwards25519, + Secp256r1, + ZkLogin, +} + +impl From for SignatureScheme { + fn from(type_: CurveType) -> Self { + match type_ { + CurveType::Secp256k1 => SignatureScheme::Secp256k1, + CurveType::Edwards25519 => SignatureScheme::ED25519, + CurveType::Secp256r1 => SignatureScheme::Secp256r1, + CurveType::ZkLogin => SignatureScheme::ZkLoginAuthenticator, + } + } +} + +#[derive(Serialize)] +pub struct ConstructionDeriveResponse { + pub account_identifier: AccountIdentifier, +} + +impl IntoResponse for ConstructionDeriveResponse { + fn into_response(self) -> Response { + Json(self).into_response() + } +} + +#[derive(Serialize, Deserialize)] +pub struct ConstructionPayloadsRequest { + pub network_identifier: NetworkIdentifier, + pub operations: Operations, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub metadata: Option, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub public_keys: Vec, +} + +#[derive(Deserialize, Serialize, Copy, Clone, Debug, EnumIter, Eq, PartialEq)] +pub enum OperationType { + // Balance changing operations from TransactionEffect + Gas, + IotaBalanceChange, + StakeReward, + StakePrinciple, + // iota-rosetta supported operation type + PayIota, + Stake, + WithdrawStake, + // All other Iota transaction types, readonly + EpochChange, + Genesis, + ConsensusCommitPrologue, + ProgrammableTransaction, + AuthenticatorStateUpdate, + RandomnessStateUpdate, + EndOfEpochTransaction, +} + +impl From<&IotaTransactionBlockKind> for OperationType { + fn from(tx: &IotaTransactionBlockKind) -> Self { + match tx { + IotaTransactionBlockKind::ChangeEpoch(_) => OperationType::EpochChange, + IotaTransactionBlockKind::Genesis(_) => OperationType::Genesis, + IotaTransactionBlockKind::ConsensusCommitPrologue(_) + | IotaTransactionBlockKind::ConsensusCommitPrologueV2(_) => { + OperationType::ConsensusCommitPrologue + } + IotaTransactionBlockKind::ProgrammableTransaction(_) => { + OperationType::ProgrammableTransaction + } + IotaTransactionBlockKind::AuthenticatorStateUpdate(_) => { + OperationType::AuthenticatorStateUpdate + } + IotaTransactionBlockKind::RandomnessStateUpdate(_) => { + OperationType::RandomnessStateUpdate + } + IotaTransactionBlockKind::EndOfEpochTransaction(_) => { + OperationType::EndOfEpochTransaction + } + } + } +} + +#[derive(Deserialize, Serialize, Clone, Debug, Default, Eq, PartialEq)] +pub struct OperationIdentifier { + index: u64, + #[serde(default, skip_serializing_if = "Option::is_none")] + network_index: Option, +} + +impl From for OperationIdentifier { + fn from(index: u64) -> Self { + OperationIdentifier { + index, + network_index: None, + } + } +} + +#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)] +pub struct CoinChange { + pub coin_identifier: CoinIdentifier, + pub coin_action: CoinAction, +} + +#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum CoinAction { + CoinCreated, + CoinSpent, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ConstructionPayloadsResponse { + pub unsigned_transaction: Hex, + pub payloads: Vec, +} + +impl IntoResponse for ConstructionPayloadsResponse { + fn into_response(self) -> Response { + Json(self).into_response() + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SigningPayload { + pub account_identifier: AccountIdentifier, + // Rosetta need the hex string without `0x`, cannot use fastcrypto's Hex + pub hex_bytes: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub signature_type: Option, +} + +#[derive(Deserialize, Serialize, Debug, Clone)] +#[serde(rename_all = "lowercase")] +pub enum SignatureType { + Ed25519, + Ecdsa, +} + +#[derive(Deserialize, Serialize)] +pub struct ConstructionCombineRequest { + pub network_identifier: NetworkIdentifier, + pub unsigned_transaction: Hex, + pub signatures: Vec, +} + +#[derive(Deserialize, Serialize)] +pub struct Signature { + pub signing_payload: SigningPayload, + pub public_key: PublicKey, + pub signature_type: SignatureType, + pub hex_bytes: Hex, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ConstructionCombineResponse { + pub signed_transaction: Hex, +} + +impl IntoResponse for ConstructionCombineResponse { + fn into_response(self) -> Response { + Json(self).into_response() + } +} + +#[derive(Serialize, Deserialize)] +pub struct ConstructionSubmitRequest { + pub network_identifier: NetworkIdentifier, + pub signed_transaction: Hex, +} +#[derive(Serialize, Deserialize, Debug)] +pub struct TransactionIdentifierResponse { + pub transaction_identifier: TransactionIdentifier, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub metadata: Option, +} + +impl IntoResponse for TransactionIdentifierResponse { + fn into_response(self) -> Response { + Json(self).into_response() + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct TransactionIdentifier { + pub hash: TransactionDigest, +} + +#[derive(Serialize, Deserialize)] +pub struct ConstructionPreprocessRequest { + pub network_identifier: NetworkIdentifier, + pub operations: Operations, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub metadata: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct PreprocessMetadata { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub budget: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ConstructionPreprocessResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub options: Option, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub required_public_keys: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct MetadataOptions { + pub internal_operation: InternalOperation, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub budget: Option, +} + +impl IntoResponse for ConstructionPreprocessResponse { + fn into_response(self) -> Response { + Json(self).into_response() + } +} +#[derive(Deserialize)] +pub struct ConstructionHashRequest { + pub network_identifier: NetworkIdentifier, + pub signed_transaction: Hex, +} + +#[derive(Serialize, Deserialize)] +pub struct ConstructionMetadataRequest { + pub network_identifier: NetworkIdentifier, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub options: Option, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub public_keys: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ConstructionMetadataResponse { + pub metadata: ConstructionMetadata, + #[serde(default)] + pub suggested_fee: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ConstructionMetadata { + pub sender: IotaAddress, + pub coins: Vec, + pub objects: Vec, + pub total_coin_value: u64, + pub gas_price: u64, + pub budget: u64, +} + +impl IntoResponse for ConstructionMetadataResponse { + fn into_response(self) -> Response { + Json(self).into_response() + } +} + +#[derive(Deserialize)] +pub struct ConstructionParseRequest { + pub network_identifier: NetworkIdentifier, + pub signed: bool, + pub transaction: Hex, +} + +#[derive(Serialize)] +pub struct ConstructionParseResponse { + pub operations: Operations, + pub account_identifier_signers: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub metadata: Option, +} + +impl IntoResponse for ConstructionParseResponse { + fn into_response(self) -> Response { + Json(self).into_response() + } +} + +#[derive(Deserialize)] +pub struct NetworkRequest { + pub network_identifier: NetworkIdentifier, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub metadata: Option, +} + +#[derive(Serialize)] +pub struct NetworkStatusResponse { + pub current_block_identifier: BlockIdentifier, + pub current_block_timestamp: u64, + pub genesis_block_identifier: BlockIdentifier, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub oldest_block_identifier: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub sync_status: Option, + pub peers: Vec, +} + +impl IntoResponse for NetworkStatusResponse { + fn into_response(self) -> Response { + Json(self).into_response() + } +} + +#[derive(Serialize)] +pub struct SyncStatus { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub current_index: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub target_index: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub stage: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub synced: Option, +} +#[derive(Serialize)] +pub struct Peer { + pub peer_id: IotaAddress, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub metadata: Option, +} + +#[derive(Serialize)] +pub struct NetworkOptionsResponse { + pub version: Version, + pub allow: Allow, +} + +impl IntoResponse for NetworkOptionsResponse { + fn into_response(self) -> Response { + Json(self).into_response() + } +} + +#[derive(Serialize)] +pub struct Version { + pub rosetta_version: String, + pub node_version: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub middleware_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub metadata: Option, +} + +#[derive(Serialize)] +pub struct Allow { + pub operation_statuses: Vec, + pub operation_types: Vec, + pub errors: Vec, + pub historical_balance_lookup: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub timestamp_start_index: Option, + pub call_methods: Vec, + pub balance_exemptions: Vec, + pub mempool_coins: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub block_hash_case: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub transaction_hash_case: Option, +} + +#[derive(Copy, Clone, Deserialize, Serialize, Debug, Eq, PartialEq)] +#[serde(rename_all = "UPPERCASE")] +pub enum OperationStatus { + Success, + Failure, +} + +impl From for OperationStatus { + fn from(es: IotaExecutionStatus) -> Self { + match es { + IotaExecutionStatus::Success => OperationStatus::Success, + IotaExecutionStatus::Failure { .. } => OperationStatus::Failure, + } + } +} + +#[derive(Serialize)] +pub struct BalanceExemption { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub sub_account_address: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub currency: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub exemption_type: Option, +} + +#[derive(Serialize)] +#[serde(rename_all = "snake_case")] +#[allow(dead_code)] +pub enum ExemptionType { + GreaterOrEqual, + LessOrEqual, + Dynamic, +} + +#[derive(Serialize)] +#[serde(rename_all = "snake_case")] +#[allow(clippy::enum_variant_names, dead_code)] +pub enum Case { + UpperCase, + LowerCase, + CaseSensitive, + Null, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Block { + pub block_identifier: BlockIdentifier, + pub parent_block_identifier: BlockIdentifier, + pub timestamp: u64, + pub transactions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub metadata: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Transaction { + pub transaction_identifier: TransactionIdentifier, + pub operations: Operations, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub related_transactions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub metadata: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct RelatedTransaction { + network_identifier: NetworkIdentifier, + transaction_identifier: TransactionIdentifier, + direction: Direction, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "lowercase")] +#[allow(dead_code)] +pub enum Direction { + Forward, + Backward, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct BlockResponse { + pub block: Block, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub other_transactions: Vec, +} + +impl IntoResponse for BlockResponse { + fn into_response(self) -> Response { + Json(self).into_response() + } +} +#[derive(Serialize, Deserialize, Default, Debug)] +pub struct PartialBlockIdentifier { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub index: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub hash: Option, +} +#[derive(Deserialize)] +pub struct BlockRequest { + pub network_identifier: NetworkIdentifier, + #[serde(default)] + pub block_identifier: PartialBlockIdentifier, +} + +#[derive(Deserialize)] +pub struct BlockTransactionRequest { + pub network_identifier: NetworkIdentifier, + pub block_identifier: BlockIdentifier, + pub transaction_identifier: TransactionIdentifier, +} + +#[derive(Serialize)] +pub struct BlockTransactionResponse { + pub transaction: Transaction, +} + +impl IntoResponse for BlockTransactionResponse { + fn into_response(self) -> Response { + Json(self).into_response() + } +} + +#[derive(Serialize, Clone)] +pub struct PrefundedAccount { + pub privkey: String, + pub account_identifier: AccountIdentifier, + pub curve_type: CurveType, + pub currency: Currency, +} + +#[derive(Serialize, Deserialize, Debug)] +pub enum InternalOperation { + PayIota { + sender: IotaAddress, + recipients: Vec, + amounts: Vec, + }, + Stake { + sender: IotaAddress, + validator: IotaAddress, + amount: Option, + }, + WithdrawStake { + sender: IotaAddress, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + stake_ids: Vec, + }, +} + +impl InternalOperation { + pub fn sender(&self) -> IotaAddress { + match self { + InternalOperation::PayIota { sender, .. } + | InternalOperation::Stake { sender, .. } + | InternalOperation::WithdrawStake { sender, .. } => *sender, + } + } + /// Combine with ConstructionMetadata to form the TransactionData + pub fn try_into_data(self, metadata: ConstructionMetadata) -> Result { + let pt = match self { + Self::PayIota { + recipients, + amounts, + .. + } => { + let mut builder = ProgrammableTransactionBuilder::new(); + builder.pay_iota(recipients, amounts)?; + builder.finish() + } + InternalOperation::Stake { + validator, amount, .. + } => { + let mut builder = ProgrammableTransactionBuilder::new(); + + // [WORKAROUND] - this is a hack to work out if the staking ops is for a + // selected amount or None amount (whole wallet). if amount is + // none, validator input will be created after the system object input + let (validator, system_state, amount) = if let Some(amount) = amount { + let amount = builder.pure(amount)?; + let validator = builder.input(CallArg::Pure(bcs::to_bytes(&validator)?))?; + let state = builder.input(CallArg::IOTA_SYSTEM_MUT)?; + (validator, state, amount) + } else { + let amount = builder.pure(metadata.total_coin_value - metadata.budget)?; + let state = builder.input(CallArg::IOTA_SYSTEM_MUT)?; + let validator = builder.input(CallArg::Pure(bcs::to_bytes(&validator)?))?; + (validator, state, amount) + }; + let coin = builder.command(Command::SplitCoins(Argument::GasCoin, vec![amount])); + + let arguments = vec![system_state, coin, validator]; + + builder.command(Command::move_call( + IOTA_SYSTEM_PACKAGE_ID, + IOTA_SYSTEM_MODULE_NAME.to_owned(), + ADD_STAKE_FUN_NAME.to_owned(), + vec![], + arguments, + )); + builder.finish() + } + InternalOperation::WithdrawStake { stake_ids, .. } => { + let mut builder = ProgrammableTransactionBuilder::new(); + + for stake_id in metadata.objects { + // [WORKAROUND] - this is a hack to work out if the withdraw stake ops is for + // selected stake_ids or None (all stakes) using the index of the call args. + // if stake_ids is not empty, id input will be created after the system object + // input + let (system_state, id) = if !stake_ids.is_empty() { + let system_state = builder.input(CallArg::IOTA_SYSTEM_MUT)?; + let id = builder.obj(ObjectArg::ImmOrOwnedObject(stake_id))?; + (system_state, id) + } else { + let id = builder.obj(ObjectArg::ImmOrOwnedObject(stake_id))?; + let system_state = builder.input(CallArg::IOTA_SYSTEM_MUT)?; + (system_state, id) + }; + + let arguments = vec![system_state, id]; + builder.command(Command::move_call( + IOTA_SYSTEM_PACKAGE_ID, + IOTA_SYSTEM_MODULE_NAME.to_owned(), + WITHDRAW_STAKE_FUN_NAME.to_owned(), + vec![], + arguments, + )); + } + builder.finish() + } + }; + + Ok(TransactionData::new_programmable( + metadata.sender, + metadata.coins, + pt, + metadata.budget, + metadata.gas_price, + )) + } +} diff --git a/crates/sui-rosetta/src/unit_tests/balance_changing_tx_tests.rs b/crates/iota-rosetta/src/unit_tests/balance_changing_tx_tests.rs similarity index 84% rename from crates/sui-rosetta/src/unit_tests/balance_changing_tx_tests.rs rename to crates/iota-rosetta/src/unit_tests/balance_changing_tx_tests.rs index d4c6b4d0cf9..452676fa60f 100644 --- a/crates/sui-rosetta/src/unit_tests/balance_changing_tx_tests.rs +++ b/crates/iota-rosetta/src/unit_tests/balance_changing_tx_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -8,26 +9,21 @@ use std::{ }; use anyhow::anyhow; -use move_core_types::identifier::Identifier; -use rand::seq::{IteratorRandom, SliceRandom}; -use serde_json::json; -use shared_crypto::intent::Intent; -use signature::rand_core::OsRng; -use sui_json_rpc_types::{ - ObjectChange, SuiObjectDataOptions, SuiObjectRef, SuiObjectResponseQuery, - SuiTransactionBlockResponseOptions, +use iota_json_rpc_types::{ + IotaObjectDataOptions, IotaObjectRef, IotaObjectResponseQuery, + IotaTransactionBlockResponseOptions, ObjectChange, }; -use sui_keys::keystore::{AccountKeystore, Keystore}; -use sui_move_build::BuildConfig; -use sui_sdk::{ +use iota_keys::keystore::{AccountKeystore, Keystore}; +use iota_move_build::BuildConfig; +use iota_sdk::{ rpc_types::{ - OwnedObjectRef, SuiData, SuiExecutionStatus, SuiTransactionBlockEffectsAPI, - SuiTransactionBlockResponse, + IotaData, IotaExecutionStatus, IotaTransactionBlockEffectsAPI, + IotaTransactionBlockResponse, OwnedObjectRef, }, - SuiClient, + IotaClient, }; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef}, gas_coin::GasCoin, programmable_transaction_builder::ProgrammableTransactionBuilder, quorum_driver_types::ExecuteTransactionRequestType, @@ -38,6 +34,11 @@ use sui_types::{ TEST_ONLY_GAS_UNIT_FOR_STAKING, TEST_ONLY_GAS_UNIT_FOR_TRANSFER, }, }; +use move_core_types::identifier::Identifier; +use rand::seq::{IteratorRandom, SliceRandom}; +use serde_json::json; +use shared_crypto::intent::Intent; +use signature::rand_core::OsRng; use test_cluster::TestClusterBuilder; use crate::{ @@ -46,19 +47,19 @@ use crate::{ }; #[tokio::test] -async fn test_transfer_sui() { +async fn test_transfer_iota() { let network = TestClusterBuilder::new().build().await; let client = network.wallet.get_client().await.unwrap(); let keystore = &network.wallet.config.keystore; let rgp = network.get_reference_gas_price().await; - // Test Transfer Sui + // Test Transfer Iota let addresses = network.get_addresses(); let sender = get_random_address(&addresses, vec![]); let recipient = get_random_address(&addresses, vec![sender]); let pt = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.transfer_sui(recipient, Some(50000)); + builder.transfer_iota(recipient, Some(50000)); builder.finish() }; test_transaction( @@ -76,19 +77,19 @@ async fn test_transfer_sui() { } #[tokio::test] -async fn test_transfer_sui_whole_coin() { +async fn test_transfer_iota_whole_coin() { let network = TestClusterBuilder::new().build().await; let client = network.wallet.get_client().await.unwrap(); let keystore = &network.wallet.config.keystore; let rgp = network.get_reference_gas_price().await; - // Test transfer sui whole coin + // Test transfer iota whole coin let addresses = network.get_addresses(); let sender = get_random_address(&addresses, vec![]); let recipient = get_random_address(&addresses, vec![sender]); let pt = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.transfer_sui(recipient, None); + builder.transfer_iota(recipient, None); builder.finish() }; test_transaction( @@ -116,7 +117,7 @@ async fn test_transfer_object() { let addresses = network.get_addresses(); let sender = get_random_address(&addresses, vec![]); let recipient = get_random_address(&addresses, vec![sender]); - let object_ref = get_random_sui(&client, sender, vec![]).await; + let object_ref = get_random_iota(&client, sender, vec![]).await; let pt = { let mut builder = ProgrammableTransactionBuilder::new(); builder.transfer_object(recipient, object_ref).unwrap(); @@ -150,7 +151,7 @@ async fn test_publish_and_move_call() { path.extend([ "..", "..", - "sui_programmability", + "iota_programmability", "examples", "fungible_tokens", ]); @@ -235,7 +236,7 @@ async fn test_split_coin() { // Test spilt coin let sender = get_random_address(&network.get_addresses(), vec![]); - let coin = get_random_sui(&client, sender, vec![]).await; + let coin = get_random_iota(&client, sender, vec![]).await; let tx = client .transaction_builder() .split_coin(sender, coin.0, vec![100000], None, 10000) @@ -268,8 +269,8 @@ async fn test_merge_coin() { // Test merge coin let sender = get_random_address(&network.get_addresses(), vec![]); - let coin = get_random_sui(&client, sender, vec![]).await; - let coin2 = get_random_sui(&client, sender, vec![coin.0]).await; + let coin = get_random_iota(&client, sender, vec![]).await; + let coin2 = get_random_iota(&client, sender, vec![coin.0]).await; let tx = client .transaction_builder() .merge_coins(sender, coin.0, coin2.0, None, 10000) @@ -304,7 +305,7 @@ async fn test_pay() { let addresses = network.get_addresses(); let sender = get_random_address(&addresses, vec![]); let recipient = get_random_address(&addresses, vec![sender]); - let coin = get_random_sui(&client, sender, vec![]).await; + let coin = get_random_iota(&client, sender, vec![]).await; let pt = { let mut builder = ProgrammableTransactionBuilder::new(); builder @@ -338,8 +339,8 @@ async fn test_pay_multiple_coin_multiple_recipient() { let sender = get_random_address(&addresses, vec![]); let recipient1 = get_random_address(&addresses, vec![sender]); let recipient2 = get_random_address(&addresses, vec![sender, recipient1]); - let coin1 = get_random_sui(&client, sender, vec![]).await; - let coin2 = get_random_sui(&client, sender, vec![coin1.0]).await; + let coin1 = get_random_iota(&client, sender, vec![]).await; + let coin2 = get_random_iota(&client, sender, vec![coin1.0]).await; let pt = { let mut builder = ProgrammableTransactionBuilder::new(); builder @@ -366,7 +367,7 @@ async fn test_pay_multiple_coin_multiple_recipient() { } #[tokio::test] -async fn test_pay_sui_multiple_coin_same_recipient() { +async fn test_pay_iota_multiple_coin_same_recipient() { let network = TestClusterBuilder::new().build().await; let client = network.wallet.get_client().await.unwrap(); let keystore = &network.wallet.config.keystore; @@ -376,12 +377,12 @@ async fn test_pay_sui_multiple_coin_same_recipient() { let addresses = network.get_addresses(); let sender = get_random_address(&addresses, vec![]); let recipient1 = get_random_address(&addresses, vec![sender]); - let coin1 = get_random_sui(&client, sender, vec![]).await; - let coin2 = get_random_sui(&client, sender, vec![coin1.0]).await; + let coin1 = get_random_iota(&client, sender, vec![]).await; + let coin2 = get_random_iota(&client, sender, vec![coin1.0]).await; let pt = { let mut builder = ProgrammableTransactionBuilder::new(); builder - .pay_sui( + .pay_iota( vec![recipient1, recipient1, recipient1], vec![100000, 100000, 100000], ) @@ -403,23 +404,23 @@ async fn test_pay_sui_multiple_coin_same_recipient() { } #[tokio::test] -async fn test_pay_sui() { +async fn test_pay_iota() { let network = TestClusterBuilder::new().build().await; let client = network.wallet.get_client().await.unwrap(); let keystore = &network.wallet.config.keystore; let rgp = network.get_reference_gas_price().await; - // Test Pay Sui + // Test Pay Iota let addresses = network.get_addresses(); let sender = get_random_address(&addresses, vec![]); let recipient1 = get_random_address(&addresses, vec![sender]); let recipient2 = get_random_address(&addresses, vec![sender, recipient1]); - let coin1 = get_random_sui(&client, sender, vec![]).await; - let coin2 = get_random_sui(&client, sender, vec![coin1.0]).await; + let coin1 = get_random_iota(&client, sender, vec![]).await; + let coin2 = get_random_iota(&client, sender, vec![coin1.0]).await; let pt = { let mut builder = ProgrammableTransactionBuilder::new(); builder - .pay_sui(vec![recipient1, recipient2], vec![1000000, 2000000]) + .pay_iota(vec![recipient1, recipient2], vec![1000000, 2000000]) .unwrap(); builder.finish() }; @@ -438,23 +439,23 @@ async fn test_pay_sui() { } #[tokio::test] -async fn test_failed_pay_sui() { +async fn test_failed_pay_iota() { let network = TestClusterBuilder::new().build().await; let client = network.wallet.get_client().await.unwrap(); let keystore = &network.wallet.config.keystore; let rgp = network.get_reference_gas_price().await; - // Test failed Pay Sui + // Test failed Pay Iota let addresses = network.get_addresses(); let sender = get_random_address(&addresses, vec![]); let recipient1 = get_random_address(&addresses, vec![sender]); let recipient2 = get_random_address(&addresses, vec![sender, recipient1]); - let coin1 = get_random_sui(&client, sender, vec![]).await; - let coin2 = get_random_sui(&client, sender, vec![coin1.0]).await; + let coin1 = get_random_iota(&client, sender, vec![]).await; + let coin2 = get_random_iota(&client, sender, vec![coin1.0]).await; let pt = { let mut builder = ProgrammableTransactionBuilder::new(); builder - .pay_sui(vec![recipient1, recipient2], vec![1000000, 2000000]) + .pay_iota(vec![recipient1, recipient2], vec![1000000, 2000000]) .unwrap(); builder.finish() }; @@ -473,23 +474,23 @@ async fn test_failed_pay_sui() { } #[tokio::test] -async fn test_stake_sui() { +async fn test_stake_iota() { let network = TestClusterBuilder::new().build().await; let client = network.wallet.get_client().await.unwrap(); let keystore = &network.wallet.config.keystore; let rgp = network.get_reference_gas_price().await; - // Test Delegate Sui + // Test Delegate Iota let sender = get_random_address(&network.get_addresses(), vec![]); - let coin1 = get_random_sui(&client, sender, vec![]).await; - let coin2 = get_random_sui(&client, sender, vec![coin1.0]).await; + let coin1 = get_random_iota(&client, sender, vec![]).await; + let coin2 = get_random_iota(&client, sender, vec![coin1.0]).await; let validator = client .governance_api() - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await .unwrap() .active_validators[0] - .sui_address; + .iota_address; let tx = client .transaction_builder() .request_add_stake( @@ -521,23 +522,23 @@ async fn test_stake_sui() { } #[tokio::test] -async fn test_stake_sui_with_none_amount() { +async fn test_stake_iota_with_none_amount() { let network = TestClusterBuilder::new().build().await; let client = network.wallet.get_client().await.unwrap(); let keystore = &network.wallet.config.keystore; let rgp = network.get_reference_gas_price().await; - // Test Staking Sui + // Test Staking Iota let sender = get_random_address(&network.get_addresses(), vec![]); - let coin1 = get_random_sui(&client, sender, vec![]).await; - let coin2 = get_random_sui(&client, sender, vec![coin1.0]).await; + let coin1 = get_random_iota(&client, sender, vec![]).await; + let coin2 = get_random_iota(&client, sender, vec![coin1.0]).await; let validator = client .governance_api() - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await .unwrap() .active_validators[0] - .sui_address; + .iota_address; let tx = client .transaction_builder() .request_add_stake( @@ -569,21 +570,21 @@ async fn test_stake_sui_with_none_amount() { } #[tokio::test] -async fn test_pay_all_sui() { +async fn test_pay_all_iota() { let network = TestClusterBuilder::new().build().await; let client = network.wallet.get_client().await.unwrap(); let keystore = &network.wallet.config.keystore; let rgp = network.get_reference_gas_price().await; - // Test Pay All Sui + // Test Pay All Iota let addresses = network.get_addresses(); let sender = get_random_address(&addresses, vec![]); let recipient = get_random_address(&addresses, vec![sender]); - let coin1 = get_random_sui(&client, sender, vec![]).await; - let coin2 = get_random_sui(&client, sender, vec![coin1.0]).await; + let coin1 = get_random_iota(&client, sender, vec![]).await; + let coin2 = get_random_iota(&client, sender, vec![coin1.0]).await; let pt = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.pay_all_sui(recipient); + builder.pay_all_iota(recipient); builder.finish() }; test_transaction( @@ -606,21 +607,21 @@ async fn test_delegation_parsing() -> Result<(), anyhow::Error> { let rgp = network.get_reference_gas_price().await; let client = network.wallet.get_client().await.unwrap(); let sender = get_random_address(&network.get_addresses(), vec![]); - let gas = get_random_sui(&client, sender, vec![]).await; + let gas = get_random_iota(&client, sender, vec![]).await; let validator = client .governance_api() - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await .unwrap() .active_validators[0] - .sui_address; + .iota_address; let ops: Operations = serde_json::from_value(json!( [{ "operation_identifier":{"index":0}, "type":"Stake", "account": { "address" : sender.to_string() }, - "amount" : { "value": "-100000" , "currency": { "symbol": "SUI", "decimals": 9}}, + "amount" : { "value": "-100000" , "currency": { "symbol": "IOTA", "decimals": 9}}, "metadata": { "Stake" : {"validator": validator.to_string()} } }] )) @@ -655,7 +656,7 @@ fn find_module_object(changes: &[ObjectChange], object_type_name: &str) -> Owned if object_type.to_string().contains(object_type_name) { return Some(OwnedObjectRef { owner: *owner, - reference: SuiObjectRef { + reference: IotaObjectRef { object_id: *object_id, version: *version, digest: *digest, @@ -671,20 +672,20 @@ fn find_module_object(changes: &[ObjectChange], object_type_name: &str) -> Owned results.pop().unwrap() } -// Record current Sui balance of an address then execute the transaction, +// Record current Iota balance of an address then execute the transaction, // and compare the balance change reported by the event against the actual // balance change. async fn test_transaction( - client: &SuiClient, + client: &IotaClient, keystore: &Keystore, - addr_to_check: Vec, - sender: SuiAddress, + addr_to_check: Vec, + sender: IotaAddress, tx: ProgrammableTransaction, gas: Vec, gas_budget: u64, gas_price: u64, expect_fail: bool, -) -> SuiTransactionBlockResponse { +) -> IotaTransactionBlockResponse { let gas = if !gas.is_empty() { gas } else { @@ -700,7 +701,7 @@ async fn test_transaction( } }) .collect::>(); - vec![get_random_sui(client, sender, input_objects).await] + vec![get_random_iota(client, sender, input_objects).await] }; let data = TransactionData::new_with_gas_coins( @@ -712,7 +713,7 @@ async fn test_transaction( ); let signature = keystore - .sign_secure(&data.sender(), &data, Intent::sui_transaction()) + .sign_secure(&data.sender(), &data, Intent::iota_transaction()) .unwrap(); // Balance before execution @@ -727,7 +728,7 @@ async fn test_transaction( .quorum_driver_api() .execute_transaction_block( Transaction::from_data(data.clone(), vec![signature]), - SuiTransactionBlockResponseOptions::full_content(), + IotaTransactionBlockResponseOptions::full_content(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await @@ -738,7 +739,7 @@ async fn test_transaction( if !expect_fail { assert_eq!( - SuiExecutionStatus::Success, + IotaExecutionStatus::Success, *effects.status(), "TX execution failed for {:#?}", data @@ -746,7 +747,7 @@ async fn test_transaction( } else { assert!(matches!( effects.status(), - SuiExecutionStatus::Failure { .. } + IotaExecutionStatus::Failure { .. } )); } @@ -768,14 +769,14 @@ async fn test_transaction( response } -fn extract_balance_changes_from_ops(ops: Operations) -> HashMap { +fn extract_balance_changes_from_ops(ops: Operations) -> HashMap { ops.into_iter() - .fold(HashMap::::new(), |mut changes, op| { + .fold(HashMap::::new(), |mut changes, op| { if let Some(OperationStatus::Success) = op.status { match op.type_ { - OperationType::SuiBalanceChange + OperationType::IotaBalanceChange | OperationType::Gas - | OperationType::PaySui + | OperationType::PayIota | OperationType::StakeReward | OperationType::StakePrinciple | OperationType::Stake => { @@ -790,17 +791,17 @@ fn extract_balance_changes_from_ops(ops: Operations) -> HashMap, ) -> ObjectRef { let coins = client .read_api() .get_owned_objects( sender, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -827,7 +828,7 @@ async fn get_random_sui( (coin.object_id, coin.version, coin.digest) } -fn get_random_address(addresses: &[SuiAddress], except: Vec) -> SuiAddress { +fn get_random_address(addresses: &[IotaAddress], except: Vec) -> IotaAddress { *addresses .iter() .filter(|addr| !except.contains(*addr)) @@ -835,13 +836,13 @@ fn get_random_address(addresses: &[SuiAddress], except: Vec) -> SuiA .unwrap() } -async fn get_balance(client: &SuiClient, address: SuiAddress) -> u64 { +async fn get_balance(client: &IotaClient, address: IotaAddress) -> u64 { let coins = client .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -861,7 +862,7 @@ async fn get_balance(client: &SuiClient, address: SuiAddress) -> u64 { if obj.is_gas_coin() { let object = client .read_api() - .get_object_with_options(obj.object_id, SuiObjectDataOptions::new().with_bcs()) + .get_object_with_options(obj.object_id, IotaObjectDataOptions::new().with_bcs()) .await .unwrap(); let coin: GasCoin = object diff --git a/crates/iota-rosetta/src/unit_tests/operations_tests.rs b/crates/iota-rosetta/src/unit_tests/operations_tests.rs new file mode 100644 index 00000000000..a4170c5b5d4 --- /dev/null +++ b/crates/iota-rosetta/src/unit_tests/operations_tests.rs @@ -0,0 +1,62 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_json_rpc_types::IotaCallArg; +use iota_types::{ + base_types::{IotaAddress, ObjectDigest, ObjectID, SequenceNumber}, + programmable_transaction_builder::ProgrammableTransactionBuilder, + transaction::{CallArg, TransactionData, TEST_ONLY_GAS_UNIT_FOR_TRANSFER}, +}; +use move_core_types::annotated_value::MoveTypeLayout; + +use crate::{operations::Operations, types::ConstructionMetadata}; + +#[tokio::test] +async fn test_operation_data_parsing() -> Result<(), anyhow::Error> { + let gas = ( + ObjectID::random(), + SequenceNumber::new(), + ObjectDigest::random(), + ); + + let sender = IotaAddress::random_for_testing_only(); + + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + builder + .pay_iota(vec![IotaAddress::random_for_testing_only()], vec![10000]) + .unwrap(); + builder.finish() + }; + let gas_price = 10; + let data = TransactionData::new_programmable( + sender, + vec![gas], + pt, + TEST_ONLY_GAS_UNIT_FOR_TRANSFER * gas_price, + gas_price, + ); + + let ops: Operations = data.clone().try_into()?; + let metadata = ConstructionMetadata { + sender, + coins: vec![gas], + objects: vec![], + total_coin_value: 0, + gas_price, + budget: TEST_ONLY_GAS_UNIT_FOR_TRANSFER * gas_price, + }; + let parsed_data = ops.into_internal()?.try_into_data(metadata)?; + assert_eq!(data, parsed_data); + + Ok(()) +} +#[tokio::test] +async fn test_iota_json() { + let arg1 = CallArg::Pure(bcs::to_bytes(&1000000u64).unwrap()); + let arg2 = CallArg::Pure(bcs::to_bytes(&30215u64).unwrap()); + let json1 = IotaCallArg::try_from(arg1, Some(&MoveTypeLayout::U64)).unwrap(); + let json2 = IotaCallArg::try_from(arg2, Some(&MoveTypeLayout::U64)).unwrap(); + println!("{:?}, {:?}", json1, json2); +} diff --git a/crates/sui-rosetta/tests/end_to_end_tests.rs b/crates/iota-rosetta/tests/end_to_end_tests.rs similarity index 85% rename from crates/sui-rosetta/tests/end_to_end_tests.rs rename to crates/iota-rosetta/tests/end_to_end_tests.rs index a6c6f76ef28..fad92873d3b 100644 --- a/crates/sui-rosetta/tests/end_to_end_tests.rs +++ b/crates/iota-rosetta/tests/end_to_end_tests.rs @@ -1,24 +1,25 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::time::Duration; -use rosetta_client::start_rosetta_test_server; -use serde_json::json; -use sui_json_rpc_types::SuiTransactionBlockResponseOptions; -use sui_keys::keystore::AccountKeystore; -use sui_rosetta::{ +use iota_json_rpc_types::IotaTransactionBlockResponseOptions; +use iota_keys::keystore::AccountKeystore; +use iota_rosetta::{ operations::Operations, types::{ - AccountBalanceRequest, AccountBalanceResponse, AccountIdentifier, NetworkIdentifier, - SubAccount, SubAccountType, SuiEnv, + AccountBalanceRequest, AccountBalanceResponse, AccountIdentifier, IotaEnv, + NetworkIdentifier, SubAccount, SubAccountType, }, }; -use sui_sdk::rpc_types::{SuiExecutionStatus, SuiTransactionBlockEffectsAPI}; -use sui_swarm_config::genesis_config::{DEFAULT_GAS_AMOUNT, DEFAULT_NUMBER_OF_OBJECT_PER_ACCOUNT}; -use sui_types::{ +use iota_sdk::rpc_types::{IotaExecutionStatus, IotaTransactionBlockEffectsAPI}; +use iota_swarm_config::genesis_config::{DEFAULT_GAS_AMOUNT, DEFAULT_NUMBER_OF_OBJECT_PER_ACCOUNT}; +use iota_types::{ quorum_driver_types::ExecuteTransactionRequestType, utils::to_sender_signed_transaction, }; +use rosetta_client::start_rosetta_test_server; +use serde_json::json; use test_cluster::TestClusterBuilder; use crate::rosetta_client::RosettaEndpoint; @@ -26,7 +27,7 @@ use crate::rosetta_client::RosettaEndpoint; mod rosetta_client; #[tokio::test] -async fn test_get_staked_sui() { +async fn test_get_staked_iota() { let test_cluster = TestClusterBuilder::new().build().await; let address = test_cluster.get_address_0(); let client = test_cluster.wallet.get_client().await.unwrap(); @@ -37,8 +38,8 @@ async fn test_get_staked_sui() { tokio::time::sleep(Duration::from_secs(1)).await; let network_identifier = NetworkIdentifier { - blockchain: "sui".to_string(), - network: SuiEnv::LocalNet, + blockchain: "iota".to_string(), + network: IotaEnv::LocalNet, }; // Verify initial balance and stake let request = AccountBalanceRequest { @@ -76,14 +77,14 @@ async fn test_get_staked_sui() { .await; assert_eq!(response.balances[0].value, 0); - // Stake some sui + // Stake some iota let validator = client .governance_api() - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await .unwrap() .active_validators[0] - .sui_address; + .iota_address; let coins = client .coin_read_api() .get_coins(address, None, None, None) @@ -107,7 +108,7 @@ async fn test_get_staked_sui() { .quorum_driver_api() .execute_transaction_block( tx, - SuiTransactionBlockResponseOptions::new(), + IotaTransactionBlockResponseOptions::new(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await @@ -137,18 +138,18 @@ async fn test_stake() { let validator = client .governance_api() - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await .unwrap() .active_validators[0] - .sui_address; + .iota_address; let ops = serde_json::from_value(json!( [{ "operation_identifier":{"index":0}, "type":"Stake", "account": { "address" : sender.to_string() }, - "amount" : { "value": "-1000000000" , "currency": { "symbol": "SUI", "decimals": 9}}, + "amount" : { "value": "-1000000000" , "currency": { "symbol": "IOTA", "decimals": 9}}, "metadata": { "Stake" : {"validator": validator.to_string()} } }] )) @@ -160,7 +161,7 @@ async fn test_stake() { .read_api() .get_transaction_with_options( response.transaction_identifier.hash, - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_input() .with_effects() .with_balance_changes() @@ -169,10 +170,10 @@ async fn test_stake() { .await .unwrap(); - println!("Sui TX: {tx:?}"); + println!("Iota TX: {tx:?}"); assert_eq!( - &SuiExecutionStatus::Success, + &IotaExecutionStatus::Success, tx.effects.as_ref().unwrap().status() ); @@ -198,11 +199,11 @@ async fn test_stake_all() { let validator = client .governance_api() - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await .unwrap() .active_validators[0] - .sui_address; + .iota_address; let ops = serde_json::from_value(json!( [{ @@ -220,7 +221,7 @@ async fn test_stake_all() { .read_api() .get_transaction_with_options( response.transaction_identifier.hash, - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_input() .with_effects() .with_balance_changes() @@ -229,10 +230,10 @@ async fn test_stake_all() { .await .unwrap(); - println!("Sui TX: {tx:?}"); + println!("Iota TX: {tx:?}"); assert_eq!( - &SuiExecutionStatus::Success, + &IotaExecutionStatus::Success, tx.effects.as_ref().unwrap().status() ); @@ -264,18 +265,18 @@ async fn test_withdraw_stake() { // First add some stakes let validator = client .governance_api() - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await .unwrap() .active_validators[0] - .sui_address; + .iota_address; let ops = serde_json::from_value(json!( [{ "operation_identifier":{"index":0}, "type":"Stake", "account": { "address" : sender.to_string() }, - "amount" : { "value": "-1000000000" , "currency": { "symbol": "SUI", "decimals": 9}}, + "amount" : { "value": "-1000000000" , "currency": { "symbol": "IOTA", "decimals": 9}}, "metadata": { "Stake" : {"validator": validator.to_string()} } }] )) @@ -287,7 +288,7 @@ async fn test_withdraw_stake() { .read_api() .get_transaction_with_options( response.transaction_identifier.hash, - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_input() .with_effects() .with_balance_changes() @@ -296,16 +297,16 @@ async fn test_withdraw_stake() { .await .unwrap(); - println!("Sui TX: {tx:?}"); + println!("Iota TX: {tx:?}"); assert_eq!( - &SuiExecutionStatus::Success, + &IotaExecutionStatus::Success, tx.effects.as_ref().unwrap().status() ); // verify balance let network_identifier = NetworkIdentifier { - blockchain: "sui".to_string(), - network: SuiEnv::LocalNet, + blockchain: "iota".to_string(), + network: IotaEnv::LocalNet, }; let response = rosetta_client .get_balance( @@ -337,7 +338,7 @@ async fn test_withdraw_stake() { .read_api() .get_transaction_with_options( response.transaction_identifier.hash, - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_input() .with_effects() .with_balance_changes() @@ -347,10 +348,10 @@ async fn test_withdraw_stake() { .unwrap(); assert_eq!( - &SuiExecutionStatus::Success, + &IotaExecutionStatus::Success, tx.effects.as_ref().unwrap().status() ); - println!("Sui TX: {tx:?}"); + println!("Iota TX: {tx:?}"); let ops2 = Operations::try_from(tx).unwrap(); assert!( @@ -376,7 +377,7 @@ async fn test_withdraw_stake() { } #[tokio::test] -async fn test_pay_sui() { +async fn test_pay_iota() { let test_cluster = TestClusterBuilder::new().build().await; let sender = test_cluster.get_address_0(); let recipient = test_cluster.get_address_1(); @@ -388,14 +389,14 @@ async fn test_pay_sui() { let ops = serde_json::from_value(json!( [{ "operation_identifier":{"index":0}, - "type":"PaySui", + "type":"PayIota", "account": { "address" : recipient.to_string() }, - "amount" : { "value": "1000000000" , "currency": { "symbol": "SUI", "decimals": 9}} + "amount" : { "value": "1000000000" , "currency": { "symbol": "IOTA", "decimals": 9}} },{ "operation_identifier":{"index":1}, - "type":"PaySui", + "type":"PayIota", "account": { "address" : sender.to_string() }, - "amount" : { "value": "-1000000000" , "currency": { "symbol": "SUI", "decimals": 9}} + "amount" : { "value": "-1000000000" , "currency": { "symbol": "IOTA", "decimals": 9}} }] )) .unwrap(); @@ -406,7 +407,7 @@ async fn test_pay_sui() { .read_api() .get_transaction_with_options( response.transaction_identifier.hash, - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_input() .with_effects() .with_balance_changes() @@ -416,10 +417,10 @@ async fn test_pay_sui() { .unwrap(); assert_eq!( - &SuiExecutionStatus::Success, + &IotaExecutionStatus::Success, tx.effects.as_ref().unwrap().status() ); - println!("Sui TX: {tx:?}"); + println!("Iota TX: {tx:?}"); let ops2 = Operations::try_from(tx).unwrap(); assert!( @@ -431,7 +432,7 @@ async fn test_pay_sui() { } #[tokio::test] -async fn test_pay_sui_multiple_times() { +async fn test_pay_iota_multiple_times() { let test_cluster = TestClusterBuilder::new() .with_epoch_duration_ms(36000000) .build() @@ -448,14 +449,14 @@ async fn test_pay_sui_multiple_times() { let ops = serde_json::from_value(json!( [{ "operation_identifier":{"index":0}, - "type":"PaySui", + "type":"PayIota", "account": { "address" : recipient.to_string() }, - "amount" : { "value": "1000000000" , "currency": { "symbol": "SUI", "decimals": 9}} + "amount" : { "value": "1000000000" , "currency": { "symbol": "IOTA", "decimals": 9}} },{ "operation_identifier":{"index":1}, - "type":"PaySui", + "type":"PayIota", "account": { "address" : sender.to_string() }, - "amount" : { "value": "-1000000000" , "currency": { "symbol": "SUI", "decimals": 9}} + "amount" : { "value": "-1000000000" , "currency": { "symbol": "IOTA", "decimals": 9}} }] )) .unwrap(); @@ -466,7 +467,7 @@ async fn test_pay_sui_multiple_times() { .read_api() .get_transaction_with_options( response.transaction_identifier.hash, - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_input() .with_effects() .with_balance_changes() @@ -474,9 +475,9 @@ async fn test_pay_sui_multiple_times() { ) .await .unwrap(); - println!("Sui TX: {tx:?}"); + println!("Iota TX: {tx:?}"); assert_eq!( - &SuiExecutionStatus::Success, + &IotaExecutionStatus::Success, tx.effects.as_ref().unwrap().status() ); diff --git a/crates/sui-rosetta/tests/gas_budget_tests.rs b/crates/iota-rosetta/tests/gas_budget_tests.rs similarity index 92% rename from crates/sui-rosetta/tests/gas_budget_tests.rs rename to crates/iota-rosetta/tests/gas_budget_tests.rs index 8c160379180..0ac786e2082 100644 --- a/crates/sui-rosetta/tests/gas_budget_tests.rs +++ b/crates/iota-rosetta/tests/gas_budget_tests.rs @@ -1,24 +1,25 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::time::Duration; use fastcrypto::encoding::{Encoding, Hex}; -use rosetta_client::start_rosetta_test_server; -use serde::Deserialize; -use serde_json::json; -use sui_keys::keystore::AccountKeystore; -use sui_rosetta::{ +use iota_keys::keystore::AccountKeystore; +use iota_rosetta::{ operations::Operations, types::{ ConstructionCombineRequest, ConstructionCombineResponse, ConstructionMetadataRequest, ConstructionMetadataResponse, ConstructionPayloadsRequest, ConstructionPayloadsResponse, ConstructionPreprocessRequest, ConstructionPreprocessResponse, ConstructionSubmitRequest, - NetworkIdentifier, PreprocessMetadata, Signature, SignatureType, SuiEnv, + IotaEnv, NetworkIdentifier, PreprocessMetadata, Signature, SignatureType, TransactionIdentifierResponse, }, }; -use sui_types::crypto::SuiSignature; +use iota_types::crypto::IotaSignature; +use rosetta_client::start_rosetta_test_server; +use serde::Deserialize; +use serde_json::json; use test_cluster::TestClusterBuilder; use crate::rosetta_client::RosettaEndpoint; @@ -59,21 +60,21 @@ async fn pay_with_gas_budget(budget: u64) -> TransactionIdentifierResponseResult tokio::time::sleep(Duration::from_secs(1)).await; let network_identifier = NetworkIdentifier { - blockchain: "sui".to_string(), - network: SuiEnv::LocalNet, + blockchain: "iota".to_string(), + network: IotaEnv::LocalNet, }; let ops: Operations = serde_json::from_value(json!( [{ "operation_identifier":{"index":0}, - "type":"PaySui", + "type":"PayIota", "account": { "address" : recipient.to_string() }, - "amount" : { "value": "1000000000" , "currency": { "symbol": "SUI", "decimals": 9}} + "amount" : { "value": "1000000000" , "currency": { "symbol": "IOTA", "decimals": 9}} },{ "operation_identifier":{"index":1}, - "type":"PaySui", + "type":"PayIota", "account": { "address" : sender.to_string() }, - "amount" : { "value": "-1000000000" , "currency": { "symbol": "SUI", "decimals": 9}} + "amount" : { "value": "-1000000000" , "currency": { "symbol": "IOTA", "decimals": 9}} }] )) .unwrap(); @@ -138,7 +139,7 @@ async fn pay_with_gas_budget(budget: u64) -> TransactionIdentifierResponseResult signing_payload: signing_payload.clone(), public_key: public_key.into(), signature_type: SignatureType::Ed25519, - hex_bytes: Hex::from_bytes(SuiSignature::signature_bytes(&signature)), + hex_bytes: Hex::from_bytes(IotaSignature::signature_bytes(&signature)), }], }, ) diff --git a/crates/sui-rosetta/tests/rosetta_client.rs b/crates/iota-rosetta/tests/rosetta_client.rs similarity index 92% rename from crates/sui-rosetta/tests/rosetta_client.rs rename to crates/iota-rosetta/tests/rosetta_client.rs index db1db9d5f91..b9aa14b4c60 100644 --- a/crates/sui-rosetta/tests/rosetta_client.rs +++ b/crates/iota-rosetta/tests/rosetta_client.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -8,32 +9,32 @@ use std::{ }; use fastcrypto::encoding::{Encoding, Hex}; -use reqwest::Client; -use serde::{de::DeserializeOwned, Serialize}; -use serde_json::Value; -use sui_config::local_ip_utils; -use sui_keys::keystore::{AccountKeystore, Keystore}; -use sui_rosetta::{ +use iota_config::local_ip_utils; +use iota_keys::keystore::{AccountKeystore, Keystore}; +use iota_rosetta::{ operations::Operations, types::{ AccountBalanceRequest, AccountBalanceResponse, AccountIdentifier, ConstructionCombineRequest, ConstructionCombineResponse, ConstructionMetadataRequest, ConstructionMetadataResponse, ConstructionPayloadsRequest, ConstructionPayloadsResponse, ConstructionPreprocessRequest, ConstructionPreprocessResponse, ConstructionSubmitRequest, - NetworkIdentifier, Signature, SignatureType, SubAccount, SubAccountType, SuiEnv, + IotaEnv, NetworkIdentifier, Signature, SignatureType, SubAccount, SubAccountType, TransactionIdentifierResponse, }, RosettaOfflineServer, RosettaOnlineServer, }; -use sui_sdk::SuiClient; -use sui_types::{base_types::SuiAddress, crypto::SuiSignature}; +use iota_sdk::IotaClient; +use iota_types::{base_types::IotaAddress, crypto::IotaSignature}; +use reqwest::Client; +use serde::{de::DeserializeOwned, Serialize}; +use serde_json::Value; use tokio::task::JoinHandle; pub async fn start_rosetta_test_server( - client: SuiClient, + client: IotaClient, ) -> (RosettaClient, Vec>>) { - let online_server = RosettaOnlineServer::new(SuiEnv::LocalNet, client); - let offline_server = RosettaOfflineServer::new(SuiEnv::LocalNet); + let online_server = RosettaOnlineServer::new(IotaEnv::LocalNet, client); + let offline_server = RosettaOfflineServer::new(IotaEnv::LocalNet); let local_ip = local_ip_utils::localhost_for_testing(); let port = local_ip_utils::get_available_port(&local_ip); let rosetta_address = format!("{}:{}", local_ip, port); @@ -97,8 +98,8 @@ impl RosettaClient { keystore: &Keystore, ) -> TransactionIdentifierResponse { let network_identifier = NetworkIdentifier { - blockchain: "sui".to_string(), - network: SuiEnv::LocalNet, + blockchain: "iota".to_string(), + network: IotaEnv::LocalNet, }; // Preprocess let preprocess: ConstructionPreprocessResponse = self @@ -153,7 +154,7 @@ impl RosettaClient { signing_payload: signing_payload.clone(), public_key: public_key.into(), signature_type: SignatureType::Ed25519, - hex_bytes: Hex::from_bytes(SuiSignature::signature_bytes(&signature)), + hex_bytes: Hex::from_bytes(IotaSignature::signature_bytes(&signature)), }], }, ) @@ -176,7 +177,7 @@ impl RosettaClient { pub async fn get_balance( &self, network_identifier: NetworkIdentifier, - address: SuiAddress, + address: IotaAddress, sub_account: Option, ) -> AccountBalanceResponse { let sub_account = sub_account.map(|account_type| SubAccount { account_type }); diff --git a/crates/iota-rpc-loadgen/Cargo.toml b/crates/iota-rpc-loadgen/Cargo.toml new file mode 100644 index 00000000000..6a127d2c219 --- /dev/null +++ b/crates/iota-rpc-loadgen/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "iota-rpc-loadgen" +version.workspace = true +edition = "2021" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false + +[dependencies] +anyhow.workspace = true +async-trait.workspace = true +clap.workspace = true +tokio = { workspace = true, features = ["full"] } +tracing.workspace = true +serde.workspace = true +tonic.workspace = true +futures.workspace = true +dirs.workspace = true +dashmap.workspace = true +itertools.workspace = true + +shellexpand.workspace = true + +iota-types = { workspace = true, features = ["test-utils"]} +iota-keys.workspace = true +iota-sdk.workspace = true +telemetry-subscribers.workspace = true +iota-json-rpc.workspace = true +iota-json-rpc-types.workspace = true +strum.workspace = true +shared-crypto.workspace = true +serde_json.workspace = true +strum_macros.workspace = true + +[dev-dependencies] +test-cluster.workspace = true + + +[[bin]] +name = "iota-rpc-loadgen" +path = "src/main.rs" diff --git a/crates/iota-rpc-loadgen/README.md b/crates/iota-rpc-loadgen/README.md new file mode 100644 index 00000000000..b3d9ccc436f --- /dev/null +++ b/crates/iota-rpc-loadgen/README.md @@ -0,0 +1,91 @@ +# iota-rpc-loadgen: Load Generator for IOTA RPC Servers + +`iota-rpc-loadgen` is a utility that facilitates the generation of read and write loads on single or multiple Iota RPC servers. Its primary functions include performance testing and data correctness verification. + +## Features + +- **Easily extendable** to support any read/write endpoint +- **Concurrent load generation** with multiple threads, making it suitable for load testing high-traffic RPC servers. +- **Cross-verifying** results across multiple RPC Servers, ensuring data consistency and accuracy. +- **Performance comparison** between vanilla Full node RPC and Enhanced Full node RPC + +## Getting Started + +Run the following command to see available commands: + +```bash +cargo run --bin iota-rpc-loadgen -- -h +``` + +To try this locally, refer to [sef](../iota-test-validator/README.md). Recommend setting `database-url` to an env variable. Note: run `RUST_LOG="consensus=off" cargo run iota-test-validator -- --with-indexer` to rebuild. + +### Example 1: Get All Checkpoints + +The following command initiates a single thread (num-threads == 1) to retrieve all checkpoints from the beginning (sequence 0) to the latest, executing the operation exactly once (repeat == 0): + +```bash +cargo run --bin iota-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9124" --num-threads 1 get-checkpoints --start 0 --repeat 0 --interval-in-ms 0 +``` + +This command is equivalent to the simplified version below: + +```bash +cargo run --bin iota-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9124" --num-threads 1 get-checkpoints +``` + +Both commands achieve the same outcome: fetching all checkpoints using one thread, without repeating the operation. + +By default, this command also verify all the transactions in the checkpoint, specify `--skip-verify-transactions` to disable fetching transactions. Note that this must used with `--skip-verify-objects` as we do need to fetch transactions to get objects for the checkpoint. + +**Note** you must put `--num-threads ` after the urls, otherwise the command will not be parsed correctly + +### Example 2: (WIP) Execute PayIota Transaction + +```bash +cargo run --bin iota-rpc-loadgen -- --urls "http://127.0.0.1:9000" --num-threads 1 pay-iota --repeat 100 +``` + +**NOTE**: right now `pay-iota` only supports 1 thread but multi-threading support can be added pretty easily by assigning different gas coins to different threads + +### Example 3: Query Transaction Blocks + +```bash +cargo run --bin iota-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9000" --num-threads 4 query-transaction-blocks --address-type from +``` + +### Multi Get Transaction Blocks +```bash +cargo run --bin iota-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9000" --num-threads 4 multi-get-transaction-blocks +``` + +### Multi Get Objects + +```bash +cargo run --bin iota-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9000" --num-threads 4 multi-get-objects +``` + +### Get Object +```bash +cargo run --bin iota-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9000" --num-threads 2 get-object --chunk-size 20 +``` + +### Get All Balances +```bash +cargo run --bin iota-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9000" --num-threads 2 get-all-balances --chunk-size 20 +``` + + +### Get Reference Gas Price +```bash +cargo run --bin iota-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9000" --num-threads 2 get-reference-gas-price --num-chunks-per-thread 10 +``` + +# Useful commands + +```bash +cat iota-rpc-loadgen.b844f547-d354-4871-b958-1ea3fe23a0a8.log.2023-03-23 | awk '/Finished processing/{print $7}' | sort -n | uniq | awk 'BEGIN{last=0}{for(i=last+1;i<$1;i++) print i; last=$1} END{print last}' | tee missing_numbers.txt && wc -l missing_numbers.txt +``` + +Checks which checkpoints among threads have not been processed yet. The last one should be the largest checkpoint being processed. + +`wc -l missing_numbers.txt` - counts how many checkpoints to go diff --git a/crates/sui-rpc-loadgen/src/load_test.rs b/crates/iota-rpc-loadgen/src/load_test.rs similarity index 98% rename from crates/sui-rpc-loadgen/src/load_test.rs rename to crates/iota-rpc-loadgen/src/load_test.rs index 87befb902c8..9788c9c69b2 100644 --- a/crates/sui-rpc-loadgen/src/load_test.rs +++ b/crates/iota-rpc-loadgen/src/load_test.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/iota-rpc-loadgen/src/main.rs b/crates/iota-rpc-loadgen/src/main.rs new file mode 100644 index 00000000000..fcfa36221a7 --- /dev/null +++ b/crates/iota-rpc-loadgen/src/main.rs @@ -0,0 +1,287 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod load_test; +mod payload; + +use std::{ + error::Error, + path::PathBuf, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; + +use anyhow::Result; +use clap::Parser; +use iota_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; +use iota_types::crypto::{EncodeDecodeBase64, IotaKeyPair}; +use payload::AddressQueryType; +use tracing::info; + +use crate::{ + load_test::{LoadTest, LoadTestConfig}, + payload::{ + load_addresses_from_file, load_digests_from_file, load_objects_from_file, Command, + RpcCommandProcessor, SignerInfo, + }, +}; + +#[derive(Parser)] +#[clap( + name = "Iota RPC Load Generator", + version = "0.1", + about = "A load test application for Iota RPC" +)] +struct Opts { + // TODO(chris): support running multiple commands at once + #[clap(subcommand)] + pub command: ClapCommand, + #[clap(long, default_value_t = 1)] + pub num_threads: usize, + #[clap(long, default_value_t = true)] + pub cross_validate: bool, + #[clap(long, num_args(1..), default_value = "http://127.0.0.1:9000")] + pub urls: Vec, + /// the path to log file directory + #[clap(long, default_value = "~/.iota/iota_config/logs")] + logs_directory: String, + + #[clap(long, default_value = "~/.iota/loadgen/data")] + data_directory: String, +} + +#[derive(Parser)] +pub struct CommonOptions { + #[clap(short, long, default_value_t = 0)] + pub repeat: usize, + + #[clap(short, long, default_value_t = 0)] + pub interval_in_ms: u64, + + /// different chunks will be executed concurrently on the same thread + #[clap(long, default_value_t = 1)] + num_chunks_per_thread: usize, +} + +#[derive(Parser)] +pub enum ClapCommand { + #[clap(name = "dry-run")] + DryRun { + #[clap(flatten)] + common: CommonOptions, + }, + #[clap(name = "get-checkpoints")] + GetCheckpoints { + /// Default to start from checkpoint 0 + #[clap(short, long, default_value_t = 0)] + start: u64, + + /// inclusive, uses `getLatestCheckpointSequenceNumber` if `None` + #[clap(short, long)] + end: Option, + + #[clap(long)] + skip_verify_transactions: bool, + + #[clap(long)] + skip_verify_objects: bool, + + // Whether to record data from checkpoint + #[clap(long)] + skip_record: bool, + + #[clap(flatten)] + common: CommonOptions, + }, + #[clap(name = "pay-iota")] + PayIota { + // TODO(chris) customize recipients and amounts + #[clap(flatten)] + common: CommonOptions, + }, + #[clap(name = "query-transaction-blocks")] + QueryTransactionBlocks { + #[clap(long, ignore_case = true)] + address_type: AddressQueryType, + + #[clap(flatten)] + common: CommonOptions, + }, + #[clap(name = "multi-get-transaction-blocks")] + MultiGetTransactionBlocks { + #[clap(flatten)] + common: CommonOptions, + }, + #[clap(name = "multi-get-objects")] + MultiGetObjects { + #[clap(flatten)] + common: CommonOptions, + }, + #[clap(name = "get-object")] + GetObject { + #[clap(long)] + chunk_size: usize, + + #[clap(flatten)] + common: CommonOptions, + }, + #[clap(name = "get-all-balances")] + GetAllBalances { + #[clap(long)] + chunk_size: usize, + + #[clap(flatten)] + common: CommonOptions, + }, + #[clap(name = "get-reference-gas-price")] + GetReferenceGasPrice { + #[clap(flatten)] + common: CommonOptions, + }, +} + +fn get_keypair() -> Result { + // TODO(chris) allow pass in custom path for keystore + // Load keystore from ~/.iota/iota_config/iota.keystore + let keystore_path = get_iota_config_directory().join("iota.keystore"); + let keystore = Keystore::from(FileBasedKeystore::new(&keystore_path)?); + let active_address = keystore.addresses().pop().unwrap(); + let keypair: &IotaKeyPair = keystore.get_key(&active_address)?; + println!("using address {active_address} for signing"); + Ok(SignerInfo::new(keypair.encode_base64())) +} + +fn get_iota_config_directory() -> PathBuf { + match dirs::home_dir() { + Some(v) => v.join(".iota").join("iota_config"), + None => panic!("Cannot obtain home directory path"), + } +} + +pub fn expand_path(dir_path: &str) -> String { + shellexpand::full(&dir_path) + .map(|v| v.into_owned()) + .unwrap_or_else(|e| panic!("Failed to expand directory '{:?}': {}", dir_path, e)) +} + +fn get_log_file_path(dir_path: String) -> String { + let current_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + let timestamp = current_time.as_secs(); + // use timestamp to signify which file is newer + let log_filename = format!("iota-rpc-loadgen.{}.log", timestamp); + + let dir_path = expand_path(&dir_path); + format!("{dir_path}/{log_filename}") +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let tracing_level = "debug"; + let network_tracing_level = "info"; + let log_filter = format!( + "{tracing_level},h2={network_tracing_level},tower={network_tracing_level},hyper={network_tracing_level},tonic::transport={network_tracing_level}" + ); + let opts = Opts::parse(); + + let log_filename = get_log_file_path(opts.logs_directory); + + // Initialize logger + let (_guard, _filter_handle) = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .with_log_level(&log_filter) + .with_log_file(&log_filename) + .init(); + + println!("Logging to {}", &log_filename); + info!("Running Load Gen with following urls {:?}", opts.urls); + + let (command, common, need_keystore) = match opts.command { + ClapCommand::DryRun { common } => (Command::new_dry_run(), common, false), + ClapCommand::PayIota { common } => (Command::new_pay_iota(), common, true), + ClapCommand::GetCheckpoints { + common, + start, + end, + skip_verify_transactions, + skip_verify_objects, + skip_record, + } => ( + Command::new_get_checkpoints( + start, + end, + !skip_verify_transactions, + !skip_verify_objects, + !skip_record, + ), + common, + false, + ), + ClapCommand::QueryTransactionBlocks { + common, + address_type, + } => { + let addresses = load_addresses_from_file(expand_path(&opts.data_directory)); + ( + Command::new_query_transaction_blocks(address_type, addresses), + common, + false, + ) + } + ClapCommand::MultiGetTransactionBlocks { common } => { + let digests = load_digests_from_file(expand_path(&opts.data_directory)); + ( + Command::new_multi_get_transaction_blocks(digests), + common, + false, + ) + } + ClapCommand::GetAllBalances { common, chunk_size } => { + let addresses = load_addresses_from_file(expand_path(&opts.data_directory)); + ( + Command::new_get_all_balances(addresses, chunk_size), + common, + false, + ) + } + ClapCommand::MultiGetObjects { common } => { + let objects = load_objects_from_file(expand_path(&opts.data_directory)); + (Command::new_multi_get_objects(objects), common, false) + } + ClapCommand::GetReferenceGasPrice { common } => { + let num_repeats = common.num_chunks_per_thread; + ( + Command::new_get_reference_gas_price(num_repeats), + common, + false, + ) + } + ClapCommand::GetObject { common, chunk_size } => { + let objects = load_objects_from_file(expand_path(&opts.data_directory)); + (Command::new_get_object(objects, chunk_size), common, false) + } + }; + + let signer_info = need_keystore.then_some(get_keypair()?); + + let command = command + .with_repeat_interval(Duration::from_millis(common.interval_in_ms)) + .with_repeat_n_times(common.repeat); + + let processor = RpcCommandProcessor::new(&opts.urls, expand_path(&opts.data_directory)).await; + + let load_test = LoadTest { + processor, + config: LoadTestConfig { + command, + num_threads: opts.num_threads, + // TODO: pass in from config + divide_tasks: true, + signer_info, + num_chunks_per_thread: common.num_chunks_per_thread, + max_repeat: common.repeat, + }, + }; + load_test.run().await?; + + Ok(()) +} diff --git a/crates/sui-rpc-loadgen/src/payload/checkpoint_utils.rs b/crates/iota-rpc-loadgen/src/payload/checkpoint_utils.rs similarity index 91% rename from crates/sui-rpc-loadgen/src/payload/checkpoint_utils.rs rename to crates/iota-rpc-loadgen/src/payload/checkpoint_utils.rs index 5b0531935ec..709e74b1298 100644 --- a/crates/sui-rpc-loadgen/src/payload/checkpoint_utils.rs +++ b/crates/iota-rpc-loadgen/src/payload/checkpoint_utils.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fmt, fmt::Display}; use futures::future::join_all; -use sui_sdk::SuiClient; -use sui_types::messages_checkpoint::CheckpointSequenceNumber; +use iota_sdk::IotaClient; +use iota_types::messages_checkpoint::CheckpointSequenceNumber; pub(crate) struct CheckpointStats { pub latest_checkpoints: Vec, @@ -47,7 +48,7 @@ impl Display for CheckpointStats { } pub(crate) async fn get_latest_checkpoint_stats( - clients: &[SuiClient], + clients: &[IotaClient], end_checkpoint: Option, ) -> CheckpointStats { let latest_checkpoints: Vec = diff --git a/crates/sui-rpc-loadgen/src/payload/get_all_balances.rs b/crates/iota-rpc-loadgen/src/payload/get_all_balances.rs similarity index 84% rename from crates/sui-rpc-loadgen/src/payload/get_all_balances.rs rename to crates/iota-rpc-loadgen/src/payload/get_all_balances.rs index 1c65166fff4..2cfb4b65059 100644 --- a/crates/sui-rpc-loadgen/src/payload/get_all_balances.rs +++ b/crates/iota-rpc-loadgen/src/payload/get_all_balances.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; use async_trait::async_trait; use futures::future::join_all; -use sui_json_rpc_types::Balance; -use sui_sdk::SuiClient; -use sui_types::base_types::SuiAddress; +use iota_json_rpc_types::Balance; +use iota_sdk::IotaClient; +use iota_types::base_types::IotaAddress; use super::validation::chunk_entities; use crate::payload::{GetAllBalances, ProcessPayload, RpcCommandProcessor, SignerInfo}; @@ -40,7 +41,7 @@ impl<'a> ProcessPayload<'a, &'a GetAllBalances> for RpcCommandProcessor { } } -async fn get_all_balances(client: &SuiClient, owner_address: SuiAddress) -> Result> { +async fn get_all_balances(client: &IotaClient, owner_address: IotaAddress) -> Result> { let balances = client .coin_read_api() .get_all_balances(owner_address) diff --git a/crates/sui-rpc-loadgen/src/payload/get_checkpoints.rs b/crates/iota-rpc-loadgen/src/payload/get_checkpoints.rs similarity index 97% rename from crates/sui-rpc-loadgen/src/payload/get_checkpoints.rs rename to crates/iota-rpc-loadgen/src/payload/get_checkpoints.rs index 2640bd3c3a6..62778b6353e 100644 --- a/crates/sui-rpc-loadgen/src/payload/get_checkpoints.rs +++ b/crates/iota-rpc-loadgen/src/payload/get_checkpoints.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; @@ -7,9 +8,9 @@ use anyhow::Result; use async_trait::async_trait; use dashmap::DashSet; use futures::future::join_all; +use iota_json_rpc_types::CheckpointId; +use iota_types::base_types::TransactionDigest; use itertools::Itertools; -use sui_json_rpc_types::CheckpointId; -use sui_types::base_types::TransactionDigest; use tokio::sync::Mutex; use tracing::{debug, error, info, log::warn}; diff --git a/crates/sui-rpc-loadgen/src/payload/get_object.rs b/crates/iota-rpc-loadgen/src/payload/get_object.rs similarity index 80% rename from crates/sui-rpc-loadgen/src/payload/get_object.rs rename to crates/iota-rpc-loadgen/src/payload/get_object.rs index 8bdf1f0b042..16a48ab78e9 100644 --- a/crates/sui-rpc-loadgen/src/payload/get_object.rs +++ b/crates/iota-rpc-loadgen/src/payload/get_object.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; use async_trait::async_trait; use futures::future::join_all; -use sui_json_rpc_types::{SuiObjectDataOptions, SuiObjectResponse}; -use sui_sdk::SuiClient; -use sui_types::base_types::ObjectID; +use iota_json_rpc_types::{IotaObjectDataOptions, IotaObjectResponse}; +use iota_sdk::IotaClient; +use iota_types::base_types::ObjectID; use super::validation::chunk_entities; use crate::payload::{GetObject, ProcessPayload, RpcCommandProcessor, SignerInfo}; @@ -38,12 +39,12 @@ impl<'a> ProcessPayload<'a, &'a GetObject> for RpcCommandProcessor { // TODO: should organize these into an api_calls.rs pub(crate) async fn get_object( - client: &SuiClient, + client: &IotaClient, object_id: ObjectID, -) -> Result { +) -> Result { let result = client .read_api() - .get_object_with_options(object_id, SuiObjectDataOptions::full_content()) + .get_object_with_options(object_id, IotaObjectDataOptions::full_content()) .await .unwrap(); Ok(result) diff --git a/crates/sui-rpc-loadgen/src/payload/get_reference_gas_price.rs b/crates/iota-rpc-loadgen/src/payload/get_reference_gas_price.rs similarity index 87% rename from crates/sui-rpc-loadgen/src/payload/get_reference_gas_price.rs rename to crates/iota-rpc-loadgen/src/payload/get_reference_gas_price.rs index a89e7a34237..0558ab377fe 100644 --- a/crates/sui-rpc-loadgen/src/payload/get_reference_gas_price.rs +++ b/crates/iota-rpc-loadgen/src/payload/get_reference_gas_price.rs @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; use async_trait::async_trait; use futures::future::try_join_all; -use sui_sdk::SuiClient; +use iota_sdk::IotaClient; use crate::payload::{GetReferenceGasPrice, ProcessPayload, RpcCommandProcessor, SignerInfo}; @@ -30,7 +31,7 @@ impl<'a> ProcessPayload<'a, &'a GetReferenceGasPrice> for RpcCommandProcessor { } } -async fn get_reference_gas_price(client: &SuiClient) -> Result { +async fn get_reference_gas_price(client: &IotaClient) -> Result { let results = client .governance_api() .get_reference_gas_price() diff --git a/crates/iota-rpc-loadgen/src/payload/mod.rs b/crates/iota-rpc-loadgen/src/payload/mod.rs new file mode 100644 index 00000000000..984db2417c7 --- /dev/null +++ b/crates/iota-rpc-loadgen/src/payload/mod.rs @@ -0,0 +1,269 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod checkpoint_utils; +mod get_all_balances; +mod get_checkpoints; +mod get_object; +mod get_reference_gas_price; +mod multi_get_objects; +mod multi_get_transaction_blocks; +mod pay_iota; +mod query_transactions; +mod rpc_command_processor; +mod validation; +use core::default::Default; +use std::time::Duration; + +use anyhow::Result; +use async_trait::async_trait; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + digests::TransactionDigest, + messages_checkpoint::CheckpointSequenceNumber, +}; +pub use rpc_command_processor::{ + load_addresses_from_file, load_digests_from_file, load_objects_from_file, RpcCommandProcessor, +}; +use strum_macros::EnumString; + +use crate::load_test::LoadTestConfig; + +#[derive(Default, Clone)] +pub struct SignerInfo { + pub encoded_keypair: String, + /// Different thread should use different gas_payment to avoid equivocation + pub gas_payment: Option>, + pub gas_budget: Option, +} + +impl SignerInfo { + pub fn new(encoded_keypair: String) -> Self { + Self { + encoded_keypair, + gas_payment: None, + gas_budget: None, + } + } +} + +#[derive(Clone, Default)] +pub struct Payload { + pub commands: Vec, + pub signer_info: Option, +} + +#[derive(Default, Clone)] +pub struct Command { + pub data: CommandData, + /// 0 means the command will be run once. Default to be 0 + pub repeat_n_times: usize, + /// how long to wait between the start of two subsequent repeats + /// If the previous command takes longer than `repeat_interval` to finish, + /// the next command will run as soon as the previous command finishes + /// Default to be 0 + pub repeat_interval: Duration, +} + +impl Command { + pub fn new_dry_run() -> Self { + Self { + data: CommandData::DryRun(DryRun {}), + ..Default::default() + } + } + + pub fn new_pay_iota() -> Self { + Self { + data: CommandData::PayIota(PayIota {}), + ..Default::default() + } + } + + pub fn new_get_checkpoints( + start: CheckpointSequenceNumber, + end: Option, + verify_transactions: bool, + verify_objects: bool, + record: bool, + ) -> Self { + Self { + data: CommandData::GetCheckpoints(GetCheckpoints { + start, + end, + verify_transactions, + verify_objects, + record, + }), + ..Default::default() + } + } + + pub fn new_query_transaction_blocks( + address_type: AddressQueryType, + addresses: Vec, + ) -> Self { + let query_transactions = QueryTransactionBlocks { + address_type, + addresses, + }; + Self { + data: CommandData::QueryTransactionBlocks(query_transactions), + ..Default::default() + } + } + + pub fn new_multi_get_transaction_blocks(digests: Vec) -> Self { + let multi_get_transaction_blocks = MultiGetTransactionBlocks { digests }; + Self { + data: CommandData::MultiGetTransactionBlocks(multi_get_transaction_blocks), + ..Default::default() + } + } + + pub fn new_multi_get_objects(object_ids: Vec) -> Self { + let multi_get_objects = MultiGetObjects { object_ids }; + Self { + data: CommandData::MultiGetObjects(multi_get_objects), + ..Default::default() + } + } + + pub fn new_get_object(object_ids: Vec, chunk_size: usize) -> Self { + let get_object = GetObject { + object_ids, + chunk_size, + }; + Self { + data: CommandData::GetObject(get_object), + ..Default::default() + } + } + + pub fn new_get_all_balances(addresses: Vec, chunk_size: usize) -> Self { + let get_all_balances = GetAllBalances { + addresses, + chunk_size, + }; + Self { + data: CommandData::GetAllBalances(get_all_balances), + ..Default::default() + } + } + + pub fn new_get_reference_gas_price(num_repeats: usize) -> Self { + let get_reference_gas_price = GetReferenceGasPrice { num_repeats }; + Self { + data: CommandData::GetReferenceGasPrice(get_reference_gas_price), + ..Default::default() + } + } + + pub fn with_repeat_n_times(mut self, num: usize) -> Self { + self.repeat_n_times = num; + self + } + + pub fn with_repeat_interval(mut self, duration: Duration) -> Self { + self.repeat_interval = duration; + self + } +} + +#[derive(Clone)] +#[allow(dead_code)] +pub enum CommandData { + DryRun(DryRun), + GetCheckpoints(GetCheckpoints), + PayIota(PayIota), + QueryTransactionBlocks(QueryTransactionBlocks), + MultiGetTransactionBlocks(MultiGetTransactionBlocks), + MultiGetObjects(MultiGetObjects), + GetObject(GetObject), + GetAllBalances(GetAllBalances), + GetReferenceGasPrice(GetReferenceGasPrice), +} + +impl Default for CommandData { + fn default() -> Self { + CommandData::DryRun(DryRun {}) + } +} + +#[derive(Clone)] +pub struct DryRun {} + +#[derive(Clone, Default)] +pub struct GetCheckpoints { + /// Default to start from 0 + pub start: CheckpointSequenceNumber, + /// If None, use `getLatestCheckpointSequenceNumber` + pub end: Option, + pub verify_transactions: bool, + pub verify_objects: bool, + pub record: bool, +} + +#[derive(Clone)] +pub struct PayIota {} + +#[derive(Clone, Default)] +pub struct QueryTransactionBlocks { + pub address_type: AddressQueryType, + pub addresses: Vec, +} + +#[derive(Clone)] +pub struct MultiGetTransactionBlocks { + pub digests: Vec, +} + +#[derive(Clone, EnumString, Default)] +#[strum(serialize_all = "lowercase")] +pub enum AddressQueryType { + #[default] + From, + To, + Both, +} + +#[derive(Clone)] +pub struct MultiGetObjects { + pub object_ids: Vec, +} + +#[derive(Clone)] +pub struct GetObject { + pub object_ids: Vec, + pub chunk_size: usize, +} + +#[derive(Clone)] +pub struct GetAllBalances { + pub addresses: Vec, + pub chunk_size: usize, +} + +#[derive(Clone)] +pub struct GetReferenceGasPrice { + num_repeats: usize, +} + +#[async_trait] +pub trait Processor { + /// process commands in order + async fn apply(&self, payload: &Payload) -> Result<()>; + + /// prepare payload for each thread according to LoadTestConfig + async fn prepare(&self, config: &LoadTestConfig) -> Result>; + + /// write results to file based on LoadTestConfig + fn dump_cache_to_file(&self, config: &LoadTestConfig); +} + +/// all payload should implement this trait +#[async_trait] +pub trait ProcessPayload<'a, T> { + async fn process(&'a self, op: T, signer_info: &Option) -> Result<()>; +} diff --git a/crates/sui-rpc-loadgen/src/payload/multi_get_objects.rs b/crates/iota-rpc-loadgen/src/payload/multi_get_objects.rs similarity index 92% rename from crates/sui-rpc-loadgen/src/payload/multi_get_objects.rs rename to crates/iota-rpc-loadgen/src/payload/multi_get_objects.rs index 6f97d7e8c59..7b318794482 100644 --- a/crates/sui-rpc-loadgen/src/payload/multi_get_objects.rs +++ b/crates/iota-rpc-loadgen/src/payload/multi_get_objects.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; diff --git a/crates/sui-rpc-loadgen/src/payload/multi_get_transaction_blocks.rs b/crates/iota-rpc-loadgen/src/payload/multi_get_transaction_blocks.rs similarity index 95% rename from crates/sui-rpc-loadgen/src/payload/multi_get_transaction_blocks.rs rename to crates/iota-rpc-loadgen/src/payload/multi_get_transaction_blocks.rs index b0efda36f96..dfe92f973f6 100644 --- a/crates/sui-rpc-loadgen/src/payload/multi_get_transaction_blocks.rs +++ b/crates/iota-rpc-loadgen/src/payload/multi_get_transaction_blocks.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; diff --git a/crates/iota-rpc-loadgen/src/payload/pay_iota.rs b/crates/iota-rpc-loadgen/src/payload/pay_iota.rs new file mode 100644 index 00000000000..432b8aea1a9 --- /dev/null +++ b/crates/iota-rpc-loadgen/src/payload/pay_iota.rs @@ -0,0 +1,77 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use futures::future::join_all; +use iota_types::{ + base_types::IotaAddress, + crypto::{EncodeDecodeBase64, IotaKeyPair}, + quorum_driver_types::ExecuteTransactionRequestType, + transaction::TransactionData, +}; +use tracing::debug; + +use crate::payload::{ + rpc_command_processor::DEFAULT_GAS_BUDGET, PayIota, ProcessPayload, RpcCommandProcessor, + SignerInfo, +}; + +#[async_trait] +impl<'a> ProcessPayload<'a, &'a PayIota> for RpcCommandProcessor { + async fn process( + &'a self, + _op: &'a PayIota, + signer_info: &Option, + ) -> anyhow::Result<()> { + let clients = self.get_clients().await?; + let SignerInfo { + encoded_keypair, + gas_budget, + gas_payment, + } = signer_info.clone().unwrap(); + let recipient = IotaAddress::random_for_testing_only(); + let amount = 1; + let gas_budget = gas_budget.unwrap_or(DEFAULT_GAS_BUDGET); + let gas_payments = gas_payment.unwrap(); + + let keypair = + IotaKeyPair::decode_base64(&encoded_keypair).expect("Decoding keypair should not fail"); + + debug!( + "Transfer Iota {} time to {recipient} with {amount} MICROS with {gas_payments:?}", + gas_payments.len() + ); + + let sender = IotaAddress::from(&keypair.public()); + // TODO: For write operations, we usually just want to submit the transaction to + // fullnode Let's figure out what's the best way to support other mode + // later + let client = clients.first().unwrap(); + let gas_price = client + .governance_api() + .get_reference_gas_price() + .await + .expect("Unable to fetch gas price"); + join_all(gas_payments.iter().map(|gas| async { + let tx = TransactionData::new_transfer_iota( + recipient, + sender, + Some(amount), + self.get_object_ref(client, gas).await, + gas_budget, + gas_price, + ); + self.sign_and_execute( + client, + &keypair, + tx, + ExecuteTransactionRequestType::WaitForEffectsCert, + ) + .await + })) + .await; + + Ok(()) + } +} diff --git a/crates/sui-rpc-loadgen/src/payload/query_transactions.rs b/crates/iota-rpc-loadgen/src/payload/query_transactions.rs similarity index 83% rename from crates/sui-rpc-loadgen/src/payload/query_transactions.rs rename to crates/iota-rpc-loadgen/src/payload/query_transactions.rs index 7109116c9d9..0715c75bd2f 100644 --- a/crates/sui-rpc-loadgen/src/payload/query_transactions.rs +++ b/crates/iota-rpc-loadgen/src/payload/query_transactions.rs @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; use async_trait::async_trait; use futures::future::join_all; -use sui_json_rpc_types::{ - Page, SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, - SuiTransactionBlockResponseQuery, TransactionBlocksPage, TransactionFilter, +use iota_json_rpc_types::{ + IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, + IotaTransactionBlockResponseQuery, Page, TransactionBlocksPage, TransactionFilter, }; -use sui_sdk::SuiClient; -use sui_types::base_types::TransactionDigest; +use iota_sdk::IotaClient; +use iota_types::base_types::TransactionDigest; use tracing::log::warn; use crate::payload::{ @@ -50,11 +51,11 @@ impl<'a> ProcessPayload<'a, &'a QueryTransactionBlocks> for RpcCommandProcessor } }; - let queries: Vec = filters + let queries: Vec = filters .into_iter() - .map(|filter| SuiTransactionBlockResponseQuery { + .map(|filter| IotaTransactionBlockResponseQuery { filter, - options: Some(SuiTransactionBlockResponseOptions::full_content()), + options: Some(IotaTransactionBlockResponseOptions::full_content()), }) .collect(); @@ -95,7 +96,7 @@ impl<'a> ProcessPayload<'a, &'a QueryTransactionBlocks> for RpcCommandProcessor })) .await; - let transactions: Vec> = + let transactions: Vec> = results.iter().map(|page| page.data.clone()).collect(); cross_validate_entities(&transactions, "Transactions"); } @@ -105,11 +106,11 @@ impl<'a> ProcessPayload<'a, &'a QueryTransactionBlocks> for RpcCommandProcessor } async fn query_transaction_blocks( - client: &SuiClient, - query: SuiTransactionBlockResponseQuery, + client: &IotaClient, + query: IotaTransactionBlockResponseQuery, cursor: Option, limit: Option, // TODO: we should probably set a limit and paginate -) -> Result> { +) -> Result> { let transactions = client .read_api() .query_transaction_blocks(query, cursor, limit, true) diff --git a/crates/sui-rpc-loadgen/src/payload/rpc_command_processor.rs b/crates/iota-rpc-loadgen/src/payload/rpc_command_processor.rs similarity index 90% rename from crates/sui-rpc-loadgen/src/payload/rpc_command_processor.rs rename to crates/iota-rpc-loadgen/src/payload/rpc_command_processor.rs index db759891601..9abc6ad86e4 100644 --- a/crates/sui-rpc-loadgen/src/payload/rpc_command_processor.rs +++ b/crates/iota-rpc-loadgen/src/payload/rpc_command_processor.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -13,20 +14,21 @@ use anyhow::{anyhow, Result}; use async_trait::async_trait; use dashmap::{DashMap, DashSet}; use futures::future::join_all; -use serde::{de::DeserializeOwned, Serialize}; -use shared_crypto::intent::{Intent, IntentMessage}; -use sui_json_rpc_types::{ - SuiExecutionStatus, SuiObjectDataOptions, SuiTransactionBlockDataAPI, - SuiTransactionBlockEffectsAPI, SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, +use iota_json_rpc_types::{ + IotaExecutionStatus, IotaObjectDataOptions, IotaTransactionBlockDataAPI, + IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponse, + IotaTransactionBlockResponseOptions, }; -use sui_sdk::{SuiClient, SuiClientBuilder}; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, - crypto::{get_key_pair, AccountKeyPair, EncodeDecodeBase64, Signature, SuiKeyPair}, +use iota_sdk::{IotaClient, IotaClientBuilder}; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef}, + crypto::{get_key_pair, AccountKeyPair, EncodeDecodeBase64, IotaKeyPair, Signature}, digests::TransactionDigest, quorum_driver_types::ExecuteTransactionRequestType, transaction::{Transaction, TransactionData}, }; +use serde::{de::DeserializeOwned, Serialize}; +use shared_crypto::intent::{Intent, IntentMessage}; use tokio::{sync::RwLock, time::sleep}; use tracing::{debug, info}; @@ -46,18 +48,18 @@ pub(crate) const MAX_NUM_NEW_OBJECTS_IN_SINGLE_TRANSACTION: usize = 120; #[derive(Clone)] pub struct RpcCommandProcessor { - clients: Arc>>, + clients: Arc>>, // for equivocation prevention in `WaitForEffectsCert` mode object_ref_cache: Arc>, transaction_digests: Arc>, - addresses: Arc>, + addresses: Arc>, data_dir: String, } impl RpcCommandProcessor { pub async fn new(urls: &[String], data_dir: String) -> Self { let clients = join_all(urls.iter().map(|url| async { - SuiClientBuilder::default() + IotaClientBuilder::default() .max_concurrent_requests(usize::MAX) .request_timeout(Duration::from_secs(60)) .build(url.clone()) @@ -83,7 +85,7 @@ impl RpcCommandProcessor { match command { CommandData::DryRun(ref v) => self.process(v, signer_info).await, CommandData::GetCheckpoints(ref v) => self.process(v, signer_info).await, - CommandData::PaySui(ref v) => self.process(v, signer_info).await, + CommandData::PayIota(ref v) => self.process(v, signer_info).await, CommandData::QueryTransactionBlocks(ref v) => self.process(v, signer_info).await, CommandData::MultiGetTransactionBlocks(ref v) => self.process(v, signer_info).await, CommandData::MultiGetObjects(ref v) => self.process(v, signer_info).await, @@ -93,7 +95,7 @@ impl RpcCommandProcessor { } } - pub(crate) async fn get_clients(&self) -> Result> { + pub(crate) async fn get_clients(&self) -> Result> { let read = self.clients.read().await; Ok(read.clone()) } @@ -101,11 +103,11 @@ impl RpcCommandProcessor { /// sign_and_execute transaction and update `object_ref_cache` pub(crate) async fn sign_and_execute( &self, - client: &SuiClient, - keypair: &SuiKeyPair, + client: &IotaClient, + keypair: &IotaKeyPair, txn_data: TransactionData, request_type: ExecuteTransactionRequestType, - ) -> SuiTransactionBlockResponse { + ) -> IotaTransactionBlockResponse { let resp = sign_and_execute(client, keypair, txn_data, request_type).await; let effects = resp.effects.as_ref().unwrap(); let object_ref_cache = self.object_ref_cache.clone(); @@ -131,7 +133,7 @@ impl RpcCommandProcessor { /// fullnode pub(crate) async fn get_object_ref( &self, - client: &SuiClient, + client: &IotaClient, object_id: &ObjectID, ) -> ObjectRef { let object_ref_cache = self.object_ref_cache.clone(); @@ -141,7 +143,7 @@ impl RpcCommandProcessor { None => { let resp = client .read_api() - .get_object_with_options(*object_id, SuiObjectDataOptions::new()) + .get_object_with_options(*object_id, IotaObjectDataOptions::new()) .await .unwrap_or_else(|_| panic!("Unable to fetch object reference {object_id}")); let object_ref = resp.object_ref_if_exists().unwrap_or_else(|| { @@ -161,7 +163,7 @@ impl RpcCommandProcessor { } } - pub(crate) fn add_addresses_from_response(&self, responses: &[SuiTransactionBlockResponse]) { + pub(crate) fn add_addresses_from_response(&self, responses: &[IotaTransactionBlockResponse]) { for response in responses { let transaction = &response.transaction; if let Some(transaction) = transaction { @@ -171,7 +173,7 @@ impl RpcCommandProcessor { } } - pub(crate) fn add_object_ids_from_response(&self, responses: &[SuiTransactionBlockResponse]) { + pub(crate) fn add_object_ids_from_response(&self, responses: &[IotaTransactionBlockResponse]) { for response in responses { let effects = &response.effects; if let Some(effects) = effects { @@ -196,12 +198,12 @@ impl RpcCommandProcessor { .unwrap(); } - let addresses: Vec = self.addresses.iter().map(|x| *x).collect(); + let addresses: Vec = self.addresses.iter().map(|x| *x).collect(); if !addresses.is_empty() { debug!("dumping addresses to file {:?}", addresses.len()); write_data_to_file( &addresses, - &format!("{}/{}", &self.data_dir, CacheType::SuiAddress), + &format!("{}/{}", &self.data_dir, CacheType::IotaAddress), ) .unwrap(); } @@ -374,7 +376,7 @@ fn write_data_to_file(data: &T, file_path: &str) -> Result<(), any } pub enum CacheType { - SuiAddress, + IotaAddress, TransactionDigest, ObjectID, } @@ -382,7 +384,7 @@ pub enum CacheType { impl fmt::Display for CacheType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - CacheType::SuiAddress => write!(f, "SuiAddress"), + CacheType::IotaAddress => write!(f, "IotaAddress"), CacheType::TransactionDigest => write!(f, "TransactionDigest"), CacheType::ObjectID => write!(f, "ObjectID"), } @@ -391,9 +393,9 @@ impl fmt::Display for CacheType { // TODO(Will): Consider using enums for input and output? Would mean we need to // do checks any time we use generic load_cache_from_file -pub fn load_addresses_from_file(filepath: String) -> Vec { - let path = format!("{}/{}", filepath, CacheType::SuiAddress); - let addresses: Vec = read_data_from_file(&path).expect("Failed to read addresses"); +pub fn load_addresses_from_file(filepath: String) -> Vec { + let path = format!("{}/{}", filepath, CacheType::IotaAddress); + let addresses: Vec = read_data_from_file(&path).expect("Failed to read addresses"); addresses } @@ -432,7 +434,7 @@ fn read_data_from_file(file_path: &str) -> Result Vec { @@ -546,7 +548,7 @@ async fn divide_get_object_tasks(data: &GetObject, num_threads: usize) -> Vec balance { panic!( - "Current balance {balance} is smaller than require amount of MIST to fund the operation {required_balance}" + "Current balance {balance} is smaller than require amount of MICROS to fund the operation {required_balance}" ); } @@ -590,7 +592,7 @@ async fn prepare_new_signer_and_coins( // from the faucet, but in some environment that might not be possible when // faucet resource is scarce let (burner_address, burner_keypair): (_, AccountKeyPair) = get_key_pair(); - let burner_keypair = SuiKeyPair::Ed25519(burner_keypair); + let burner_keypair = IotaKeyPair::Ed25519(burner_keypair); let pay_amounts = split_amounts .iter() .map(|(amount, _)| *amount) @@ -599,7 +601,7 @@ async fn prepare_new_signer_and_coins( debug!("pay_amounts {pay_amounts:?}"); - pay_sui( + pay_iota( client, &primary_keypair, vec![coin], @@ -609,7 +611,7 @@ async fn prepare_new_signer_and_coins( ) .await; - let coins = get_sui_coin_ids(client, burner_address).await; + let coins = get_iota_coin_ids(client, burner_address).await; let gas_coin_id = get_coin_with_balance(&coins, gas_fee_for_split); let primary_coin = get_coin_with_balance(&coins, split_amounts[0].0); assert!(!coins.is_empty()); @@ -689,8 +691,8 @@ fn calculate_split_amounts( split_amounts } -async fn get_coin_with_max_balance(client: &SuiClient, address: SuiAddress) -> (ObjectID, u64) { - let coins = get_sui_coin_ids(client, address).await; +async fn get_coin_with_max_balance(client: &IotaClient, address: IotaAddress) -> (ObjectID, u64) { + let coins = get_iota_coin_ids(client, address).await; assert!(!coins.is_empty()); coins.into_iter().max_by(|a, b| a.1.cmp(&b.1)).unwrap() } @@ -700,7 +702,7 @@ fn get_coin_with_balance(coins: &[(ObjectID, u64)], target: u64) -> ObjectID { } // TODO: move this to the Rust SDK -async fn get_sui_coin_ids(client: &SuiClient, address: SuiAddress) -> Vec<(ObjectID, u64)> { +async fn get_iota_coin_ids(client: &IotaClient, address: IotaAddress) -> Vec<(ObjectID, u64)> { match client .coin_read_api() .get_coins(address, None, None, None) @@ -712,26 +714,26 @@ async fn get_sui_coin_ids(client: &SuiClient, address: SuiAddress) -> Vec<(Objec .map(|c| (c.coin_object_id, c.balance)) .collect::>(), Err(e) => { - panic!("get_sui_coin_ids error for address {address} {e}") + panic!("get_iota_coin_ids error for address {address} {e}") } } // TODO: implement iteration over next page } -async fn pay_sui( - client: &SuiClient, - keypair: &SuiKeyPair, +async fn pay_iota( + client: &IotaClient, + keypair: &IotaKeyPair, input_coins: Vec, gas_budget: u64, - recipients: Vec, + recipients: Vec, amounts: Vec, -) -> SuiTransactionBlockResponse { - let sender = SuiAddress::from(&keypair.public()); +) -> IotaTransactionBlockResponse { + let sender = IotaAddress::from(&keypair.public()); let tx = client .transaction_builder() .pay(sender, input_coins, recipients, amounts, None, gas_budget) .await - .expect("Failed to construct pay sui transaction"); + .expect("Failed to construct pay iota transaction"); sign_and_execute( client, keypair, @@ -742,13 +744,13 @@ async fn pay_sui( } async fn split_coins( - client: &SuiClient, - keypair: &SuiKeyPair, + client: &IotaClient, + keypair: &IotaKeyPair, coin_to_split: ObjectID, gas_payment: ObjectID, num_coins: u64, ) -> Vec { - let sender = SuiAddress::from(&keypair.public()); + let sender = IotaAddress::from(&keypair.public()); let split_coin_tx = client .transaction_builder() .split_coin_equal( @@ -777,13 +779,13 @@ async fn split_coins( } pub(crate) async fn sign_and_execute( - client: &SuiClient, - keypair: &SuiKeyPair, + client: &IotaClient, + keypair: &IotaKeyPair, txn_data: TransactionData, request_type: ExecuteTransactionRequestType, -) -> SuiTransactionBlockResponse { +) -> IotaTransactionBlockResponse { let signature = Signature::new_secure( - &IntentMessage::new(Intent::sui_transaction(), &txn_data), + &IntentMessage::new(Intent::iota_transaction(), &txn_data), keypair, ); @@ -791,7 +793,7 @@ pub(crate) async fn sign_and_execute( .quorum_driver_api() .execute_transaction_block( Transaction::from_data(txn_data, vec![signature]), - SuiTransactionBlockResponseOptions::new().with_effects(), + IotaTransactionBlockResponseOptions::new().with_effects(), Some(request_type), ) .await @@ -804,7 +806,7 @@ pub(crate) async fn sign_and_execute( match &transaction_response.effects { Some(effects) => { - if let SuiExecutionStatus::Failure { error } = effects.status() { + if let IotaExecutionStatus::Failure { error } = effects.status() { panic!( "Transaction {} failed with error: {}. Transaction Response: {:?}", transaction_response.digest, error, &transaction_response diff --git a/crates/sui-rpc-loadgen/src/payload/validation.rs b/crates/iota-rpc-loadgen/src/payload/validation.rs similarity index 84% rename from crates/sui-rpc-loadgen/src/payload/validation.rs rename to crates/iota-rpc-loadgen/src/payload/validation.rs index 26a041a5ab6..d09df2fb21f 100644 --- a/crates/sui-rpc-loadgen/src/payload/validation.rs +++ b/crates/iota-rpc-loadgen/src/payload/validation.rs @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashSet, fmt::Debug}; use futures::future::join_all; -use itertools::Itertools; -use sui_json_rpc_types::{ - SuiObjectDataOptions, SuiObjectResponse, SuiTransactionBlockEffectsAPI, - SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, +use iota_json_rpc_types::{ + IotaObjectDataOptions, IotaObjectResponse, IotaTransactionBlockEffectsAPI, + IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, }; -use sui_sdk::SuiClient; -use sui_types::base_types::{ObjectID, TransactionDigest}; +use iota_sdk::IotaClient; +use iota_types::base_types::{ObjectID, TransactionDigest}; +use itertools::Itertools; use tracing::{error, log::warn}; const LOADGEN_QUERY_MAX_RESULT_LIMIT: usize = 25; @@ -63,19 +64,19 @@ where } pub(crate) async fn check_transactions( - clients: &[SuiClient], + clients: &[IotaClient], digests: &[TransactionDigest], cross_validate: bool, verify_objects: bool, -) -> Vec> { - let transactions: Vec> = +) -> Vec> { + let transactions: Vec> = join_all(clients.iter().map(|client| async move { client .read_api() .multi_get_transactions_with_options( digests.to_vec(), - SuiTransactionBlockResponseOptions::full_content(), /* todo(Will) support - * options for this */ + IotaTransactionBlockResponseOptions::full_content(), /* todo(Will) support + * options for this */ ) .await })) @@ -112,7 +113,7 @@ pub(crate) async fn check_transactions( transactions } -pub(crate) fn get_all_object_ids(response: &SuiTransactionBlockResponse) -> Vec { +pub(crate) fn get_all_object_ids(response: &IotaTransactionBlockResponse) -> Vec { let objects = match response.effects.as_ref() { // TODO: handle deleted and wrapped objects Some(effects) => effects.all_changed_objects(), @@ -145,7 +146,7 @@ where } pub(crate) async fn check_objects( - clients: &[SuiClient], + clients: &[IotaClient], object_ids: &[ObjectID], cross_validate: bool, ) { @@ -160,10 +161,10 @@ pub(crate) async fn check_objects( } pub(crate) async fn multi_get_object( - clients: &[SuiClient], + clients: &[IotaClient], object_ids: &[ObjectID], -) -> Vec> { - let objects: Vec> = join_all(clients.iter().map(|client| async move { +) -> Vec> { + let objects: Vec> = join_all(clients.iter().map(|client| async move { let object_ids = if object_ids.len() > LOADGEN_QUERY_MAX_RESULT_LIMIT { warn!( "The input size for multi_get_object_with_options has exceed the query limit\ @@ -179,7 +180,7 @@ pub(crate) async fn multi_get_object( .read_api() .multi_get_object_with_options( object_ids.to_vec(), - SuiObjectDataOptions::full_content(), // todo(Will) support options for this + IotaObjectDataOptions::full_content(), // todo(Will) support options for this ) .await })) diff --git a/crates/iota-sdk/Cargo.toml b/crates/iota-sdk/Cargo.toml new file mode 100644 index 00000000000..b52193a89af --- /dev/null +++ b/crates/iota-sdk/Cargo.toml @@ -0,0 +1,86 @@ +[package] +name = "iota-sdk" +version.workspace = true +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +async-trait.workspace = true +clap.workspace = true +colored.workspace = true +jsonrpsee.workspace = true +serde.workspace = true +serde_with.workspace = true +serde_json.workspace = true +futures-core.workspace = true +futures.workspace = true +tokio.workspace = true +bcs.workspace = true +thiserror.workspace = true +reqwest.workspace = true + +iota-json-rpc-api.workspace = true +iota-transaction-builder.workspace = true +iota-json-rpc-types.workspace = true +iota-types.workspace = true +iota-json.workspace = true +iota-keys.workspace = true +iota-config.workspace = true +shared-crypto.workspace = true +tracing.workspace = true +move-core-types.workspace = true +fastcrypto.workspace = true + +# NOTE: It's important to keep the above dependency list short. +# This and the iota-json-rpc-api crate are widely used to develop on Iota and it's valuable +# to not have to pull in the entire iota repo for it. + +[dev-dependencies] +clap.workspace = true +dirs.workspace = true +async-recursion.workspace = true +tempfile.workspace = true +futures-core.workspace = true +futures.workspace = true +rand.workspace = true + +[[example]] +name = "tic_tac_toe" +path = "examples/tic_tac_toe.rs" +test = false + +[[example]] +name = "coin_read_api" +path = "examples/coin_read_api.rs" + +[[example]] +name = "read_api" +path = "examples/read_api.rs" + +[[example]] +name = "event_api" +path = "examples/event_api.rs" + +[[example]] +name = "governance_api" +path = "examples/governance_api.rs" + +[[example]] +name = "programmable_transactions_api" +path = "examples/programmable_transactions_api.rs" + +[[example]] +name = "iota_client" +path = "examples/iota_client.rs" + +[[example]] +name = "sign_tx_guide" +path = "examples/sign_tx_guide.rs" + +[[example]] +name = "utils" +path = "examples/utils.rs" +crate-type = ["staticlib"] diff --git a/crates/iota-sdk/README.md b/crates/iota-sdk/README.md new file mode 100644 index 00000000000..25a67615c88 --- /dev/null +++ b/crates/iota-sdk/README.md @@ -0,0 +1,183 @@ +This crate provides the Iota Rust SDK, containing APIs to interact with the Iota network. + +## Getting started + +Add the `iota-sdk` dependency as following: + +```toml +iota-sdk = { git = "https://github.com/iotaledger/iota", package = "iota-sdk"} +tokio = { version = "1.2", features = ["full"] } +anyhow = "1.0" +``` + +The main building block for the Iota Rust SDK is the `IotaClientBuilder`, which provides a simple and straightforward way of connecting to a Iota network and having access to the different available APIs. + +In the following example, the application connects to the Iota `testnet` and `devnet` networks and prints out their respective RPC API versions. + +```rust +use iota_sdk::IotaClientBuilder; + +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + // Iota testnet -- https://fullnode.testnet.iota.io:443 + let iota_testnet = IotaClientBuilder::default().build_testnet().await?; + println!("Iota testnet version: {}", iota_testnet.api_version()); + + // Iota devnet -- https://fullnode.devnet.iota.io:443 + let iota_devnet = IotaClientBuilder::default().build_devnet().await?; + println!("Iota devnet version: {}", iota_devnet.api_version()); + + Ok(()) +} + +``` + +## Documentation for iota-sdk crate + +[GitHub Pages](https://mystenlabs.github.io/iota/iota_sdk/index.html) hosts the generated documentation for all Rust crates in the Iota repository. + +### Building documentation locally + +You can also build the documentation locally. To do so, + +1. Clone the `iota` repo locally. Open a Terminal or Console and go to the `iota/crates/iota-sdk` directory. + +1. Run `cargo doc` to build the documentation into the `iota/target` directory. Take note of location of the generated file from the last line of the output, for example `Generated /Users/foo/iota/target/doc/iota_sdk/index.html`. + +1. Use a web browser, like Chrome, to open the `.../target/doc/iota_sdk/index.html` file at the location your console reported in the previous step. + +## Rust SDK examples + +The [examples](https://github.com/iotaledger/iota/tree/main/crates/iota-sdk/examples) folder provides both basic and advanced examples. + +There are serveral files ending in `_api.rs` which provide code examples of the corresponding APIs and their methods. These showcase how to use the Iota Rust SDK, and can be run against the Iota testnet. Below are instructions on the prerequisites and how to run these examples. + +### Prerequisites + +Unless otherwise specified, most of these examples assume `Rust` and `cargo` are installed, and that there is an available internet connection. The examples connect to the Iota testnet (`https://fullnode.testnet.iota.io:443`) and execute different APIs using the active address from the local wallet. If there is no local wallet, it will create one, generate two addresses, set one of them to be active, and it will request 1 IOTA from the testnet faucet for the active address. + +### Running the existing examples + +In the root folder of the `iota` repository (or in the `iota-sdk` crate folder), you can individually run examples using the command `cargo run --example filename` (without `.rs` extension). For example: +* `cargo run --example iota_client` -- this one requires a local Iota network running (see [here](#Connecting to Iota Network +)). If you do not have a local Iota network running, please skip this example. +* `cargo run --example coin_read_api` +* `cargo run --example event_api` -- note that this will subscribe to a stream and thus the program will not terminate unless forced (Ctrl+C) +* `cargo run --example governance_api` +* `cargo run --example read_api` +* `cargo run --example programmable_transactions_api` +* `cargo run --example sign_tx_guide` + +### Basic Examples + +#### Connecting to Iota Network +The `IotaClientBuilder` struct provides a connection to the JSON-RPC server that you use for all read-only operations. The default URLs to connect to the Iota network are: + +- Local: http://127.0.0.1:9000 +- Devnet: https://fullnode.devnet.iota.io:443 +- Testnet: https://fullnode.testnet.iota.io:443 +- Mainnet: https://fullnode.mainnet.iota.io:443 + +For all available servers, see [here](https://iota.io/networkinfo). + +For running a local Iota network, please follow [this guide](https://docs.iota.io/build/iota-local-network) for installing Iota and [this guide](https://docs.iota.io/build/iota-local-network#start-the-local-network) for starting the local Iota network. + + +```rust +use iota_sdk::IotaClientBuilder; + +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + let iota = IotaClientBuilder::default() + .build("http://127.0.0.1:9000") // local network address + .await?; + println!("Iota local network version: {}", iota.api_version()); + + // local Iota network, like the above one but using the dedicated function + let iota_local = IotaClientBuilder::default().build_localnet().await?; + println!("Iota local network version: {}", iota_local.api_version()); + + // Iota devnet -- https://fullnode.devnet.iota.io:443 + let iota_devnet = IotaClientBuilder::default().build_devnet().await?; + println!("Iota devnet version: {}", iota_devnet.api_version()); + + // Iota testnet -- https://fullnode.testnet.iota.io:443 + let iota_testnet = IotaClientBuilder::default().build_testnet().await?; + println!("Iota testnet version: {}", iota_testnet.api_version()); + + Ok(()) +} +``` + +#### Read the total coin balance for each coin type owned by this address +```rust +use std::str::FromStr; +use iota_sdk::types::base_types::IotaAddress; +use iota_sdk::{ IotaClientBuilder}; +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + + let iota_local = IotaClientBuilder::default().build_localnet().await?; + println!("Iota local network version: {}", iota_local.api_version()); + + let active_address = IotaAddress::from_str("")?; // change to your Iota address + + let total_balance = iota_local + .coin_read_api() + .get_all_balances(active_address) + .await?; + println!("The balances for all coins owned by address: {active_address} are {}", total_balance); + Ok(()) +} +``` + +## Advanced examples + +See the programmable transactions [example](https://github.com/iotaledger/iota/blob/main/crates/iota-sdk/examples/programmable_transactions_api.rs). + +## Games examples + +### Tic Tac Toe quick start + +1. Prepare the environment + 1. Install `iota` binary following the [Iota installation](https://github.com/iotaledger/iota/blob/main/docs/content/guides/developer/getting-started/iota-install.mdx) docs. + 1. [Connect to Iota Devnet](https://github.com/iotaledger/iota/blob/main/docs/content/guides/developer/getting-started/connect.mdx). + 1. [Make sure you have two addresses with gas](https://github.com/iotaledger/iota/blob/main/docs/content/guides/developer/getting-started/get-address.mdx) by using the `new-address` command to create new addresses: + ```shell + iota client new-address ed25519 + ``` + You must specify the key scheme, one of `ed25519` or `secp256k1` or `secp256r1`. + You can skip this step if you are going to play with a friend. :) + 1. [Request Iota tokens](https://github.com/iotaledger/iota/blob/main/docs/content/guides/developer/getting-started/get-coins.mdx) for all addresses that will be used to join the game. + +2. Publish the move contract + 1. [Download the Iota source code](https://github.com/iotaledger/iota/blob/main/docs/content/guides/developer/getting-started/iota-install.mdx). + 1. Publish the [`games` package](https://github.com/iotaledger/iota/tree/main/iota_programmability/examples/games) + using the Iota client: + ```shell + iota client publish --path /path-to-iota-source-code/iota_programmability/examples/games --gas-budget 10000 + ``` + 1. Record the package object ID. + +3. Create a new tic-tac-toe game + 1. Run the following command in the Iota source code directory to start a new game, replacing the game package objects ID with the one you recorded: + ```shell + cargo run --example tic-tac-toe -- --game-package-id <> new-game + ``` + This will create a game for the first two addresses in your keystore by default. If you want to specify the identity of each player, + use the following command and replace the variables with the actual player's addresses: + ```shell + cargo run --example tic-tac-toe -- --game-package-id <> new-game --player-x <> --player-o <> + ``` + 1. Copy the game ID and pass it to your friend to join the game. + +4. Joining the game + + Run the following command in the Iota source code directory to join the game, replacing the game ID and address accordingly: + ```shell + cargo run --example tic-tac-toe -- --game-package-id <> join-game --my-identity <
    > --game-id <> + ``` + +## License + +[SPDX-License-Identifier: Apache-2.0](https://github.com/iotaledger/iota/blob/main/LICENSE) diff --git a/crates/iota-sdk/examples/coin_read_api.rs b/crates/iota-sdk/examples/coin_read_api.rs new file mode 100644 index 00000000000..1e0e930fc92 --- /dev/null +++ b/crates/iota-sdk/examples/coin_read_api.rs @@ -0,0 +1,113 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod utils; +use futures::{future, stream::StreamExt}; +use utils::setup_for_read; + +// This example uses the coin read api to showcase the available +// functions to retrieve coin related information for a specific address. +// The example will use the active address in the wallet (if it exists or create +// one if it doesn't) check if it has coins and request coins from the faucet if +// there aren't any. If there is no wallet, it will create a wallet and two +// addresses, set one address as active, and add 1 IOTA to the active address. +// By default, the example will use the Iota testnet network +// (fullnode.testnet.iota.io:443). + +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + let (iota, active_address) = setup_for_read().await?; + + // ************ COIN READ API ************ // + + // Get coins for this address. Coins can be filtered by `coin_type` + // (e.g., 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC) or + // use `None` for the default `Coin` which is represented as + // "0x2::iota::IOTA" + let coin_type = Some("0x2::iota::IOTA".to_string()); + let coins = iota + .coin_read_api() + .get_coins(active_address, coin_type.clone(), None, Some(5)) // get the first five coins + .await?; + println!(" *** Coins ***"); + println!("{:?}", coins); + println!(" *** Coins ***\n"); + + // Get all coins + // This function works very similar to the get_coins function, except it does + // not take a coin_type filter argument and it returns all coin types + // associated with this address + let all_coins = iota + .coin_read_api() + .get_all_coins(active_address, None, Some(5)) // get the first five coins + .await?; + println!(" *** All coins ***"); + println!("{:?}", all_coins); + println!(" *** All coins ***\n"); + + // Get coins as a stream + // Similar to the previous functions, except it returns the coins as a stream. + let coins_stream = iota.coin_read_api().get_coins_stream(active_address, None); + + println!(" *** Coins Stream ***"); + coins_stream + .for_each(|coin| { + println!("{:?}", coin); + future::ready(()) + }) + .await; + println!(" *** Coins Stream ***\n"); + + // Select coins based on the provided coin type (IOTA in this example). Use + // `None` for the default Iota coin + let select_coins = iota + .coin_read_api() + .select_coins(active_address, coin_type, 1, vec![]) + .await?; + + println!(" *** Select Coins ***"); + println!("{:?}", select_coins); + println!(" *** Select Coins ***\n"); + + // Balance + // Returns the balance for the specified coin type for this address, + // or if None is passed, it will use Coin as the coin type + let balance = iota + .coin_read_api() + .get_balance(active_address, None) + .await?; + + // Total balance + // Returns the balance for each coin owned by this address + let total_balance = iota + .coin_read_api() + .get_all_balances(active_address) + .await?; + println!(" *** Balance + Total Balance *** "); + println!("Balance: {:?}", balance); + println!("Total Balance: {:?}", total_balance); + println!(" *** Balance + Total Balance ***\n "); + + // Return the coin metadata for the Coin + let coin_metadata = iota + .coin_read_api() + .get_coin_metadata("0x2::iota::IOTA".to_string()) + .await?; + + println!(" *** Coin Metadata *** "); + println!("{:?}", coin_metadata); + println!(" *** Coin Metadata ***\n "); + + // Total Supply + let total_supply = iota + .coin_read_api() + .get_total_supply("0x2::iota::IOTA".to_string()) + .await?; + println!(" *** Total Supply *** "); + println!("{:?}", total_supply); + println!(" *** Total Supply ***\n "); + + // ************ END OF COIN READ API ************ // + Ok(()) +} diff --git a/crates/iota-sdk/examples/event_api.rs b/crates/iota-sdk/examples/event_api.rs new file mode 100644 index 00000000000..e3ba7aeed5f --- /dev/null +++ b/crates/iota-sdk/examples/event_api.rs @@ -0,0 +1,50 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod utils; +use futures::stream::StreamExt; +use iota_sdk::{rpc_types::EventFilter, IotaClientBuilder}; +use utils::{setup_for_write, split_coin_digest}; + +// This example showcases how to use the Event API. +// At the end of the program it subscribes to the events +// on the Iota testnet and prints every incoming event to +// the console. The program will loop until it is force +// stopped. + +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + let (iota, active_address, _second_address) = setup_for_write().await?; + + println!(" *** Get events *** "); + // for demonstration purposes, we set to make a transaction + let digest = split_coin_digest(&iota, &active_address).await?; + let events = iota.event_api().get_events(digest).await?; + println!("{:?}", events); + println!(" *** Get events ***\n "); + + let descending = true; + let query_events = iota + .event_api() + .query_events(EventFilter::All(vec![]), None, Some(5), descending) // query first 5 events in descending order + .await?; + println!(" *** Query events *** "); + println!("{:?}", query_events); + println!(" *** Query events ***\n "); + + let ws = IotaClientBuilder::default() + .ws_url("wss://rpc.testnet.iota.io:443") + .build("https://fullnode.testnet.iota.io:443") + .await?; + println!("WS version {:?}", ws.api_version()); + + let mut subscribe = ws + .event_api() + .subscribe_event(EventFilter::All(vec![])) + .await?; + + loop { + println!("{:?}", subscribe.next().await); + } +} diff --git a/crates/iota-sdk/examples/governance_api.rs b/crates/iota-sdk/examples/governance_api.rs new file mode 100644 index 00000000000..15e7f06ac11 --- /dev/null +++ b/crates/iota-sdk/examples/governance_api.rs @@ -0,0 +1,64 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod utils; +use utils::setup_for_read; + +// This example connects to the Iota testnet +// and collects information about the stakes in the network, +// the committee information, +// lists all the validators' name, description, and iota address, +// and prints the reference gas price. + +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + let (iota, active_address) = setup_for_read().await?; + + // ************ GOVERNANCE API ************ // + + // Stakes + let stakes = iota.governance_api().get_stakes(active_address).await?; + + println!(" *** Stakes ***"); + println!("{:?}", stakes); + println!(" *** Stakes ***\n"); + + // Committee Info + let committee = iota.governance_api().get_committee_info(None).await?; // None defaults to the latest epoch + + println!(" *** Committee Info ***"); + println!("{:?}", committee); + println!(" *** Committee Info ***\n"); + + // Latest Iota System State + let iota_system_state = iota.governance_api().get_latest_iota_system_state().await?; + + println!(" *** Iota System State ***"); + println!("{:?}", iota_system_state); + println!(" *** Iota System State ***\n"); + + // List all active validators + + println!(" *** List active validators *** "); + iota_system_state + .active_validators + .into_iter() + .for_each(|validator| { + println!( + "Name: {}, Description: {}, IotaAddress: {:?}", + validator.name, validator.description, validator.iota_address + ) + }); + + println!(" *** List active validators ***\n"); + // Reference Gas Price + let reference_gas_price = iota.governance_api().get_reference_gas_price().await?; + + println!(" *** Reference Gas Price ***"); + println!("{:?}", reference_gas_price); + println!(" *** Reference Gas Price ***\n"); + + // ************ END OF GOVERNANCE API ************ // + Ok(()) +} diff --git a/crates/iota-sdk/examples/iota_client.rs b/crates/iota-sdk/examples/iota_client.rs new file mode 100644 index 00000000000..9a63f0de232 --- /dev/null +++ b/crates/iota-sdk/examples/iota_client.rs @@ -0,0 +1,40 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_sdk::IotaClientBuilder; + +// This example shows the few basic ways to connect to a Iota network. +// There are several in-built methods for connecting to the +// Iota devnet, tesnet, and localnet (running locally), +// as well as a custom way for connecting to custom URLs. +// The example prints out the API versions of the different networks, +// and finally, it prints the list of available RPC methods +// and the list of subscriptions. +// Note that running this code will fail if there is no Iota network +// running locally on the default address: 127.0.0.1:9000 + +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + let iota = IotaClientBuilder::default() + .build("http://127.0.0.1:9000") // local network address + .await?; + println!("Iota local network version: {}", iota.api_version()); + + // local Iota network, like the above one but using the dedicated function + let iota_local = IotaClientBuilder::default().build_localnet().await?; + println!("Iota local network version: {}", iota_local.api_version()); + + // Iota devnet -- https://fullnode.devnet.iota.io:443 + let iota_devnet = IotaClientBuilder::default().build_devnet().await?; + println!("Iota devnet version: {}", iota_devnet.api_version()); + + // Iota testnet -- https://fullnode.testnet.iota.io:443 + let iota_testnet = IotaClientBuilder::default().build_testnet().await?; + println!("Iota testnet version: {}", iota_testnet.api_version()); + + println!("{:?}", iota_local.available_rpc_methods()); + println!("{:?}", iota_local.available_subscriptions()); + + Ok(()) +} diff --git a/crates/sui-sdk/examples/json_rpc_errors.rs b/crates/iota-sdk/examples/json_rpc_errors.rs similarity index 80% rename from crates/sui-sdk/examples/json_rpc_errors.rs rename to crates/iota-sdk/examples/json_rpc_errors.rs index f0ce37ddbcb..314db0362bd 100644 --- a/crates/sui-sdk/examples/json_rpc_errors.rs +++ b/crates/iota-sdk/examples/json_rpc_errors.rs @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 mod utils; use anyhow::bail; -use sui_sdk::error::{Error, JsonRpcError}; +use iota_sdk::error::{Error, JsonRpcError}; use utils::setup_for_read; #[tokio::main] async fn main() -> Result<(), anyhow::Error> { - let (sui, active_address) = setup_for_read().await?; + let (iota, active_address) = setup_for_read().await?; let coin_type = Some("0x42".to_string()); - let coins = sui + let coins = iota .coin_read_api() .get_coins(active_address, coin_type.clone(), None, Some(5)) .await; diff --git a/crates/iota-sdk/examples/programmable_transactions_api.rs b/crates/iota-sdk/examples/programmable_transactions_api.rs new file mode 100644 index 00000000000..38eb6225a43 --- /dev/null +++ b/crates/iota-sdk/examples/programmable_transactions_api.rs @@ -0,0 +1,106 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod utils; +use iota_config::{iota_config_dir, IOTA_KEYSTORE_FILENAME}; +use iota_keys::keystore::{AccountKeystore, FileBasedKeystore}; +use iota_sdk::{ + rpc_types::IotaTransactionBlockResponseOptions, + types::{ + programmable_transaction_builder::ProgrammableTransactionBuilder, + quorum_driver_types::ExecuteTransactionRequestType, + transaction::{Argument, Command, Transaction, TransactionData}, + }, +}; +use shared_crypto::intent::Intent; +use utils::setup_for_write; + +// This example shows how to use programmable transactions to chain multiple +// actions into one transaction. Specifically, the example retrieves two +// addresses from the local wallet, and then +// 1) finds a coin from the active address that has Iota, +// 2) splits the coin into one coin of 1000 MICROS and the rest, +// 3 transfers the split coin to second Iota address, +// 4) signs the transaction, +// 5) executes it. +// For some of these actions it prints some output. +// Finally, at the end of the program it prints the number of coins for the +// Iota address that received the coin. +// If you run this program several times, you should see the number of coins +// for the recipient address increases. + +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + // 1) get the Iota client, the sender and recipient that we will use + // for the transaction, and find the coin we use as gas + let (iota, sender, recipient) = setup_for_write().await?; + + // we need to find the coin we will use as gas + let coins = iota + .coin_read_api() + .get_coins(sender, None, None, None) + .await?; + let coin = coins.data.into_iter().next().unwrap(); + + // programmable transactions allows the user to bundle a number of actions into + // one transaction + let mut ptb = ProgrammableTransactionBuilder::new(); + + // 2) split coin + // the amount we want in the new coin, 1000 MICROS + let split_coint_amount = ptb.pure(1000u64)?; // note that we need to specify the u64 type + ptb.command(Command::SplitCoins( + Argument::GasCoin, + vec![split_coint_amount], + )); + + // 3) transfer the new coin to a different address + let argument_address = ptb.pure(recipient)?; + ptb.command(Command::TransferObjects( + vec![Argument::Result(0)], + argument_address, + )); + + // finish building the transaction block by calling finish on the ptb + let builder = ptb.finish(); + + let gas_budget = 5_000_000; + let gas_price = iota.read_api().get_reference_gas_price().await?; + // create the transaction data that will be sent to the network + let tx_data = TransactionData::new_programmable( + sender, + vec![coin.object_ref()], + builder, + gas_budget, + gas_price, + ); + + // 4) sign transaction + let keystore = FileBasedKeystore::new(&iota_config_dir()?.join(IOTA_KEYSTORE_FILENAME))?; + let signature = keystore.sign_secure(&sender, &tx_data, Intent::iota_transaction())?; + + // 5) execute the transaction + print!("Executing the transaction..."); + let transaction_response = iota + .quorum_driver_api() + .execute_transaction_block( + Transaction::from_data(tx_data, vec![signature]), + IotaTransactionBlockResponseOptions::full_content(), + Some(ExecuteTransactionRequestType::WaitForLocalExecution), + ) + .await?; + print!("done\n Transaction information: "); + println!("{:?}", transaction_response); + + let coins = iota + .coin_read_api() + .get_coins(recipient, None, None, None) + .await?; + + println!( + "After the transfer, the recipient address {recipient} has {} coins", + coins.data.len() + ); + Ok(()) +} diff --git a/crates/iota-sdk/examples/read_api.rs b/crates/iota-sdk/examples/read_api.rs new file mode 100644 index 00000000000..3e4ed80199e --- /dev/null +++ b/crates/iota-sdk/examples/read_api.rs @@ -0,0 +1,144 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod utils; +use iota_sdk::{ + rpc_types::{ + IotaGetPastObjectRequest, IotaObjectDataOptions, IotaTransactionBlockResponseOptions, + }, + types::base_types::ObjectID, +}; +use utils::{setup_for_write, split_coin_digest}; + +// This example uses the Read API to get owned objects of an address, +// the dynamic fields of an object, +// past objects, information about the chain +// and the protocol configuration, +// the transaction data after executing a transaction, +// and finally, the number of transaction blocks known to the server. + +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + let (iota, active_address, _) = setup_for_write().await?; + + // ************ READ API ************ // + println!("// ************ READ API ************ //\n"); + // Owned Objects + let owned_objects = iota + .read_api() + .get_owned_objects(active_address, None, None, Some(5)) + .await?; + println!(" *** Owned Objects ***"); + println!("{:?}", owned_objects); + println!(" *** Owned Objects ***\n"); + + // Dynamic Fields + let parent_object_id = ObjectID::from_address(active_address.into()); + let dynamic_fields = iota + .read_api() + .get_dynamic_fields(parent_object_id, None, None) + .await?; + println!(" *** Dynamic Fields ***"); + println!("{:?}", dynamic_fields); + println!(" *** Dynamic Fields ***\n"); + if let Some(dynamic_field_info) = dynamic_fields.data.into_iter().next() { + println!(" *** First Dynamic Field ***"); + let dynamic_field = iota + .read_api() + .get_dynamic_field_object(parent_object_id, dynamic_field_info.name) + .await?; + println!("{dynamic_field:?}"); + println!(" *** First Dynamic Field ***\n"); + } + + let object = owned_objects + .data + .first() + .unwrap_or_else(|| panic!("No object data for this address {}", active_address)); + let object_data = object + .data + .as_ref() + .unwrap_or_else(|| panic!("No object data for this IotaObjectResponse {:?}", object)); + let object_id = object_data.object_id; + let version = object_data.version; + + let iota_data_options = IotaObjectDataOptions { + show_type: true, + show_owner: true, + show_previous_transaction: true, + show_display: true, + show_content: true, + show_bcs: true, + show_storage_rebate: true, + }; + + let past_object = iota + .read_api() + .try_get_parsed_past_object(object_id, version, iota_data_options.clone()) + .await?; + println!(" *** Past Object *** "); + println!("{:?}", past_object); + println!(" *** Past Object ***\n"); + + let iota_get_past_object_request = past_object.clone().into_object()?; + let multi_past_object = iota + .read_api() + .try_multi_get_parsed_past_object( + vec![IotaGetPastObjectRequest { + object_id: iota_get_past_object_request.object_id, + version: iota_get_past_object_request.version, + }], + iota_data_options.clone(), + ) + .await?; + println!(" *** Multi Past Object *** "); + println!("{:?}", multi_past_object); + println!(" *** Multi Past Object ***\n"); + + // Object with options + let object_with_options = iota + .read_api() + .get_object_with_options(iota_get_past_object_request.object_id, iota_data_options) + .await?; + + println!(" *** Object with Options *** "); + println!("{:?}", object_with_options); + println!(" *** Object with Options ***\n"); + + println!(" *** Chain identifier *** "); + println!("{:?}", iota.read_api().get_chain_identifier().await?); + println!(" *** Chain identifier ***\n "); + + println!(" *** Protocol Config *** "); + println!("{:?}", iota.read_api().get_protocol_config(None).await?); + println!(" *** Protocol Config ***\n "); + + // we make a dummy transaction which returns a transaction digest + let tx_digest = split_coin_digest(&iota, &active_address).await?; + println!(" *** Transaction data *** "); + let tx_response = iota + .read_api() + .get_transaction_with_options( + tx_digest, + IotaTransactionBlockResponseOptions { + show_input: true, + show_raw_input: true, + show_effects: true, + show_events: true, + show_object_changes: true, + show_balance_changes: true, + show_raw_effects: true, + }, + ) + .await?; + println!("Transaction succeeded: {:?}\n\n", tx_response.status_ok()); + + println!("Transaction data: {:?}", tx_response); + + let tx_blocks = iota.read_api().get_total_transaction_blocks().await?; + println!("Total transaction blocks {tx_blocks}"); + // ************ END OF READ API ************ // + + Ok(()) +} diff --git a/crates/iota-sdk/examples/sign_tx_guide.rs b/crates/iota-sdk/examples/sign_tx_guide.rs new file mode 100644 index 00000000000..c37dc7362cf --- /dev/null +++ b/crates/iota-sdk/examples/sign_tx_guide.rs @@ -0,0 +1,172 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod utils; +use anyhow::anyhow; +use fastcrypto::{ + ed25519::Ed25519KeyPair, + encoding::{Base64, Encoding}, + hash::HashFunction, + secp256k1::Secp256k1KeyPair, + secp256r1::Secp256r1KeyPair, + traits::{EncodeDecodeBase64, KeyPair}, +}; +use iota_sdk::{ + rpc_types::IotaTransactionBlockResponseOptions, + types::{ + programmable_transaction_builder::ProgrammableTransactionBuilder, + transaction::TransactionData, + }, + IotaClientBuilder, +}; +use iota_types::{ + base_types::IotaAddress, + crypto::{get_key_pair_from_rng, IotaKeyPair, IotaSignature, Signer, ToFromBytes}, + signature::GenericSignature, +}; +use rand::{rngs::StdRng, SeedableRng}; +use shared_crypto::intent::{Intent, IntentMessage}; + +use crate::utils::request_tokens_from_faucet; + +/// This example walks through the Rust SDK use case described in +/// https://github.com/iotaledger/iota/blob/main/docs/content/guides/developer/iota-101/sign-and-send-txn.mdx +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + // set up iota client for the desired network. + let iota_client = IotaClientBuilder::default().build_testnet().await?; + + // deterministically generate a keypair, testing only, do not use for mainnet, + // use the next section to randomly generate a keypair instead. + let skp_determ_0 = + IotaKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))); + let _skp_determ_1 = + IotaKeyPair::Secp256k1(Secp256k1KeyPair::generate(&mut StdRng::from_seed([0; 32]))); + let _skp_determ_2 = + IotaKeyPair::Secp256r1(Secp256r1KeyPair::generate(&mut StdRng::from_seed([0; 32]))); + + // randomly generate a keypair. + let _skp_rand_0 = IotaKeyPair::Ed25519(get_key_pair_from_rng(&mut rand::rngs::OsRng).1); + let _skp_rand_1 = IotaKeyPair::Secp256k1(get_key_pair_from_rng(&mut rand::rngs::OsRng).1); + let _skp_rand_2 = IotaKeyPair::Secp256r1(get_key_pair_from_rng(&mut rand::rngs::OsRng).1); + + // import a keypair from a base64 encoded 32-byte `private key` assuming scheme + // is Ed25519. + let _skp_import_no_flag_0 = IotaKeyPair::Ed25519(Ed25519KeyPair::from_bytes( + &Base64::decode("1GPhHHkVlF6GrCty2IuBkM+tj/e0jn64ksJ1pc8KPoI=") + .map_err(|_| anyhow!("Invalid base64"))?, + )?); + let _skp_import_no_flag_1 = IotaKeyPair::Ed25519(Ed25519KeyPair::from_bytes( + &Base64::decode("1GPhHHkVlF6GrCty2IuBkM+tj/e0jn64ksJ1pc8KPoI=") + .map_err(|_| anyhow!("Invalid base64"))?, + )?); + let _skp_import_no_flag_2 = IotaKeyPair::Ed25519(Ed25519KeyPair::from_bytes( + &Base64::decode("1GPhHHkVlF6GrCty2IuBkM+tj/e0jn64ksJ1pc8KPoI=") + .map_err(|_| anyhow!("Invalid base64"))?, + )?); + + // import a keypair from a base64 encoded 33-byte `flag || private key`. + // The signature scheme is determined by the flag. + let _skp_import_with_flag_0 = + IotaKeyPair::decode_base64("ANRj4Rx5FZRehqwrctiLgZDPrY/3tI5+uJLCdaXPCj6C") + .map_err(|_| anyhow!("Invalid base64"))?; + let _skp_import_with_flag_1 = + IotaKeyPair::decode_base64("AdRj4Rx5FZRehqwrctiLgZDPrY/3tI5+uJLCdaXPCj6C") + .map_err(|_| anyhow!("Invalid base64"))?; + let _skp_import_with_flag_2 = + IotaKeyPair::decode_base64("AtRj4Rx5FZRehqwrctiLgZDPrY/3tI5+uJLCdaXPCj6C") + .map_err(|_| anyhow!("Invalid base64"))?; + + // import a keypair from a Bech32 encoded 33-byte `flag || private key`. + // this is the format of a private key exported from Iota Wallet or + // iota.keystore. + let _skp_import_with_flag_0 = IotaKeyPair::decode( + "iotaprivkey1qzdlfxn2qa2lj5uprl8pyhexs02sg2wrhdy7qaq50cqgnffw4c2477kg9h3", + ) + .map_err(|_| anyhow!("Invalid Bech32"))?; + let _skp_import_with_flag_1 = IotaKeyPair::decode( + "iotaprivkey1qqesr6xhua2dkt840v9yefely578q5ad90znnpmhhgpekfvwtxke6ef2xyg", + ) + .map_err(|_| anyhow!("Invalid Bech32"))?; + let _skp_import_with_flag_2 = IotaKeyPair::decode( + "iotaprivkey1qprzkcs823gcrk7n4hy8pzhntdxakpqk32qwjg9f2wyc3myj78egvtw3ecr", + ) + .map_err(|_| anyhow!("Invalid Bech32"))?; + + // replace `skp_determ_0` with the variable names above + let pk = skp_determ_0.public(); + let sender = IotaAddress::from(&pk); + println!("Sender: {:?}", sender); + + // make sure the sender has a gas coin as an example. + request_tokens_from_faucet(sender, &iota_client).await?; + let gas_coin = iota_client + .coin_read_api() + .get_coins(sender, None, None, None) + .await? + .data + .into_iter() + .next() + .ok_or(anyhow!("No coins found for sender"))?; + + // construct an example programmable transaction. + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + builder.pay_iota(vec![sender], vec![1])?; + builder.finish() + }; + + let gas_budget = 5_000_000; + let gas_price = iota_client.read_api().get_reference_gas_price().await?; + + // create the transaction data that will be sent to the network. + let tx_data = TransactionData::new_programmable( + sender, + vec![gas_coin.object_ref()], + pt, + gas_budget, + gas_price, + ); + + // derive the digest that the keypair should sign on, + // i.e. the blake2b hash of `intent || tx_data`. + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data); + let raw_tx = bcs::to_bytes(&intent_msg).expect("bcs should not fail"); + let mut hasher = iota_types::crypto::DefaultHash::default(); + hasher.update(raw_tx.clone()); + let digest = hasher.finalize().digest; + + // use IotaKeyPair to sign the digest. + let iota_sig = skp_determ_0.sign(&digest); + + // if you would like to verify the signature locally before submission, use this + // function. if it fails to verify locally, the transaction will fail to + // execute in Iota. + let res = iota_sig.verify_secure( + &intent_msg, + sender, + iota_types::crypto::SignatureScheme::ED25519, + ); + assert!(res.is_ok()); + + // execute the transaction. + let transaction_response = iota_client + .quorum_driver_api() + .execute_transaction_block( + iota_types::transaction::Transaction::from_generic_sig_data( + intent_msg.value, + vec![GenericSignature::Signature(iota_sig)], + ), + IotaTransactionBlockResponseOptions::default(), + None, + ) + .await?; + + println!( + "Transaction executed. Transaction digest: {}", + transaction_response.digest.base58_encode() + ); + println!("{transaction_response}"); + Ok(()) +} diff --git a/crates/sui-sdk/examples/tic_tac_toe.rs b/crates/iota-sdk/examples/tic_tac_toe.rs similarity index 84% rename from crates/sui-sdk/examples/tic_tac_toe.rs rename to crates/iota-sdk/examples/tic_tac_toe.rs index 156d55f787a..32aedd979ef 100644 --- a/crates/sui-sdk/examples/tic_tac_toe.rs +++ b/crates/iota-sdk/examples/tic_tac_toe.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -12,21 +13,21 @@ use std::{ use anyhow::anyhow; use async_recursion::async_recursion; use clap::{Parser, Subcommand}; -use serde::Deserialize; -use shared_crypto::intent::Intent; -use sui_json_rpc_types::{SuiObjectDataOptions, SuiTransactionBlockResponseOptions}; -use sui_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; -use sui_sdk::{ - json::SuiJsonValue, - rpc_types::{SuiData, SuiTransactionBlockEffectsAPI}, +use iota_json_rpc_types::{IotaObjectDataOptions, IotaTransactionBlockResponseOptions}; +use iota_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; +use iota_sdk::{ + json::IotaJsonValue, + rpc_types::{IotaData, IotaTransactionBlockEffectsAPI}, types::{ - base_types::{ObjectID, SuiAddress}, + base_types::{IotaAddress, ObjectID}, id::UID, transaction::Transaction, }, - SuiClient, SuiClientBuilder, + IotaClient, IotaClientBuilder, }; -use sui_types::quorum_driver_types::ExecuteTransactionRequestType; +use iota_types::quorum_driver_types::ExecuteTransactionRequestType; +use serde::Deserialize; +use shared_crypto::intent::Intent; #[tokio::main] async fn main() -> Result<(), anyhow::Error> { @@ -36,7 +37,7 @@ async fn main() -> Result<(), anyhow::Error> { let game = TicTacToe { game_package_id: opts.game_package_id, - client: SuiClientBuilder::default() + client: IotaClientBuilder::default() .build(opts.rpc_server_url) .await?, keystore, @@ -59,15 +60,15 @@ async fn main() -> Result<(), anyhow::Error> { struct TicTacToe { game_package_id: ObjectID, - client: SuiClient, + client: IotaClient, keystore: Keystore, } impl TicTacToe { async fn create_game( &self, - player_x: Option, - player_o: Option, + player_x: Option, + player_o: Option, ) -> Result<(), anyhow::Error> { // Default player identity to first and second keys in the keystore if not // provided. @@ -85,8 +86,8 @@ impl TicTacToe { "create_game", vec![], vec![ - SuiJsonValue::from_str(&player_x.to_string())?, - SuiJsonValue::from_str(&player_o.to_string())?, + IotaJsonValue::from_str(&player_x.to_string())?, + IotaJsonValue::from_str(&player_o.to_string())?, ], None, // The node will pick a gas object belong to the signer if not provided. 1000, @@ -97,7 +98,7 @@ impl TicTacToe { // Sign transaction. let signature = self.keystore - .sign_secure(&player_x, &create_game_call, Intent::sui_transaction())?; + .sign_secure(&player_x, &create_game_call, Intent::iota_transaction())?; // Execute the transaction. @@ -106,7 +107,7 @@ impl TicTacToe { .quorum_driver_api() .execute_transaction_block( Transaction::from_data(create_game_call, vec![signature]), - SuiTransactionBlockResponseOptions::full_content(), + IotaTransactionBlockResponseOptions::full_content(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; @@ -135,7 +136,7 @@ impl TicTacToe { async fn join_game( &self, game_id: ObjectID, - my_identity: SuiAddress, + my_identity: IotaAddress, ) -> Result<(), anyhow::Error> { let game_state = self.fetch_game_state(game_id).await?; if game_state.o_address == my_identity { @@ -151,7 +152,7 @@ impl TicTacToe { #[async_recursion] async fn next_turn( &self, - my_identity: SuiAddress, + my_identity: IotaAddress, game_state: TicTacToeState, ) -> Result<(), anyhow::Error> { game_state.print_game_board(); @@ -184,9 +185,9 @@ impl TicTacToe { "place_mark", vec![], vec![ - SuiJsonValue::from_str(&game_state.info.object_id().to_hex_literal())?, - SuiJsonValue::from_str(&row.to_string())?, - SuiJsonValue::from_str(&col.to_string())?, + IotaJsonValue::from_str(&game_state.info.object_id().to_hex_literal())?, + IotaJsonValue::from_str(&row.to_string())?, + IotaJsonValue::from_str(&col.to_string())?, ], None, 1000, @@ -198,7 +199,7 @@ impl TicTacToe { let signature = self.keystore.sign_secure( &my_identity, &place_mark_call, - Intent::sui_transaction(), + Intent::iota_transaction(), )?; // Execute the transaction. @@ -207,7 +208,7 @@ impl TicTacToe { .quorum_driver_api() .execute_transaction_block( Transaction::from_data(place_mark_call, vec![signature]), - SuiTransactionBlockResponseOptions::new().with_effects(), + IotaTransactionBlockResponseOptions::new().with_effects(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; @@ -250,7 +251,7 @@ impl TicTacToe { let current_game = self .client .read_api() - .get_object_with_options(game_id, SuiObjectDataOptions::new().with_bcs()) + .get_object_with_options(game_id, IotaObjectDataOptions::new().with_bcs()) .await?; current_game .object()? @@ -293,7 +294,7 @@ struct TicTacToeOpts { game_package_id: ObjectID, #[clap(long)] keystore_path: Option, - #[clap(long, default_value = "https://fullnode.devnet.sui.io:443")] + #[clap(long, default_value = "https://fullnode.devnet.iota.io:443")] rpc_server_url: String, #[clap(subcommand)] subcommand: TicTacToeCommand, @@ -301,7 +302,7 @@ struct TicTacToeOpts { fn default_keystore_path() -> PathBuf { match dirs::home_dir() { - Some(v) => v.join(".sui").join("sui_config").join("sui.keystore"), + Some(v) => v.join(".iota").join("iota_config").join("iota.keystore"), None => panic!("Cannot obtain home directory path"), } } @@ -311,13 +312,13 @@ fn default_keystore_path() -> PathBuf { enum TicTacToeCommand { NewGame { #[clap(long)] - player_x: Option, + player_x: Option, #[clap(long)] - player_o: Option, + player_o: Option, }, JoinGame { #[clap(long)] - my_identity: SuiAddress, + my_identity: IotaAddress, #[clap(long)] game_id: ObjectID, }, @@ -331,8 +332,8 @@ struct TicTacToeState { gameboard: Vec>, cur_turn: u8, game_status: u8, - x_address: SuiAddress, - o_address: SuiAddress, + x_address: IotaAddress, + o_address: IotaAddress, } impl TicTacToeState { @@ -359,7 +360,7 @@ impl TicTacToeState { println!(" └-----┴-----┴-----┘"); } - fn is_my_turn(&self, my_identity: SuiAddress) -> bool { + fn is_my_turn(&self, my_identity: IotaAddress) -> bool { let current_player = if self.cur_turn % 2 == 0 { self.x_address } else { diff --git a/crates/iota-sdk/examples/transaction_subscription.rs b/crates/iota-sdk/examples/transaction_subscription.rs new file mode 100644 index 00000000000..05233211b8b --- /dev/null +++ b/crates/iota-sdk/examples/transaction_subscription.rs @@ -0,0 +1,35 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use futures::stream::StreamExt; +use iota_json_rpc_types::TransactionFilter; +use iota_sdk::IotaClientBuilder; + +// This example showcases how to use the Read API to listen +// for transactions. It subscribes to the transactions that +// transfer IOTA on the Iota testnet and prints every incoming +// transaction to the console. The program will loop until it +// is force stopped. + +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + let ws = IotaClientBuilder::default() + .ws_url("wss://rpc.testnet.iota.io:443") + .build("https://fullnode.testnet.iota.io:443") + .await?; + println!("WS version {:?}", ws.api_version()); + + let mut subscribe = ws + .read_api() + .subscribe_transaction(TransactionFilter::MoveFunction { + package: "0x2".parse()?, + module: Some("iota".to_owned()), + function: Some("transfer".to_owned()), + }) + .await?; + + loop { + println!("{:?}", subscribe.next().await); + } +} diff --git a/crates/iota-sdk/examples/utils.rs b/crates/iota-sdk/examples/utils.rs new file mode 100644 index 00000000000..36e287789c3 --- /dev/null +++ b/crates/iota-sdk/examples/utils.rs @@ -0,0 +1,331 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{str::FromStr, time::Duration}; + +use anyhow::bail; +use futures::{future, stream::StreamExt}; +use iota_config::{ + iota_config_dir, Config, PersistedConfig, IOTA_CLIENT_CONFIG, IOTA_KEYSTORE_FILENAME, +}; +use iota_json_rpc_types::{Coin, IotaObjectDataOptions}; +use iota_keys::keystore::{AccountKeystore, FileBasedKeystore}; +use iota_sdk::{ + iota_client_config::{IotaClientConfig, IotaEnv}, + rpc_types::IotaTransactionBlockResponseOptions, + types::{ + base_types::{IotaAddress, ObjectID}, + crypto::SignatureScheme::ED25519, + digests::TransactionDigest, + programmable_transaction_builder::ProgrammableTransactionBuilder, + quorum_driver_types::ExecuteTransactionRequestType, + transaction::{Argument, Command, Transaction, TransactionData}, + }, + wallet_context::WalletContext, + IotaClient, IotaClientBuilder, +}; +use reqwest::Client; +use serde_json::json; +use shared_crypto::intent::Intent; +use tracing::info; + +#[derive(serde::Deserialize)] +struct FaucetResponse { + task: String, + error: Option, +} + +// const IOTA_FAUCET: &str = "https://faucet.devnet.iota.io/gas"; // devnet faucet + +pub const IOTA_FAUCET: &str = "https://faucet.testnet.iota.io/v1/gas"; // testnet faucet + +// if you use the iota-test-validator and use the local network; if it does not +// work, try with port 5003. const IOTA_FAUCET: &str = "http://127.0.0.1:9123/gas"; + +/// Return a iota client to interact with the APIs, +/// the active address of the local wallet, and another address that can be used +/// as a recipient. +/// +/// By default, this function will set up a wallet locally if there isn't any, +/// or reuse the existing one and its active address. This function should be +/// used when two addresses are needed, e.g., transferring objects from one +/// address to another. +pub async fn setup_for_write() -> Result<(IotaClient, IotaAddress, IotaAddress), anyhow::Error> { + let (client, active_address) = setup_for_read().await?; + // make sure we have some IOTA (5_000_000 MICROS) on this address + let coin = fetch_coin(&client, &active_address).await?; + if coin.is_none() { + request_tokens_from_faucet(active_address, &client).await?; + } + let wallet = retrieve_wallet()?; + let addresses = wallet.get_addresses(); + let addresses = addresses + .into_iter() + .filter(|address| address != &active_address) + .collect::>(); + let recipient = addresses + .first() + .expect("Cannot get the recipient address needed for writing operations. Aborting"); + + Ok((client, active_address, *recipient)) +} + +/// Return a iota client to interact with the APIs and an active address from +/// the local wallet. +/// +/// This function sets up a wallet in case there is no wallet locally, +/// and ensures that the active address of the wallet has IOTA on it. +/// If there is no IOTA owned by the active address, then it will request +/// IOTA from the faucet. +pub async fn setup_for_read() -> Result<(IotaClient, IotaAddress), anyhow::Error> { + let client = IotaClientBuilder::default().build_testnet().await?; + println!("Iota testnet version is: {}", client.api_version()); + let mut wallet = retrieve_wallet()?; + assert!(wallet.get_addresses().len() >= 2); + let active_address = wallet.active_address()?; + + println!("Wallet active address is: {active_address}"); + Ok((client, active_address)) +} + +/// Request tokens from the Faucet for the given address +#[allow(unused_assignments)] +pub async fn request_tokens_from_faucet( + address: IotaAddress, + iota_client: &IotaClient, +) -> Result<(), anyhow::Error> { + let address_str = address.to_string(); + let json_body = json![{ + "FixedAmountRequest": { + "recipient": &address_str + } + }]; + + // make the request to the faucet JSON RPC API for coin + let client = Client::new(); + let resp = client + .post(IOTA_FAUCET) + .header("Content-Type", "application/json") + .json(&json_body) + .send() + .await?; + println!( + "Faucet request for address {address_str} has status: {}", + resp.status() + ); + println!("Waiting for the faucet to complete the gas request..."); + let faucet_resp: FaucetResponse = resp.json().await?; + + let task_id = if let Some(err) = faucet_resp.error { + bail!("Faucet request was unsuccessful. Error is {err:?}") + } else { + faucet_resp.task + }; + + println!("Faucet request task id: {task_id}"); + + let json_body = json![{ + "GetBatchSendStatusRequest": { + "task_id": &task_id + } + }]; + + let mut coin_id = "".to_string(); + + // wait for the faucet to finish the batch of token requests + loop { + let resp = client + .get("https://faucet.testnet.iota.io/v1/status") + .header("Content-Type", "application/json") + .json(&json_body) + .send() + .await?; + let text = resp.text().await?; + if text.contains("SUCCEEDED") { + let resp_json: serde_json::Value = serde_json::from_str(&text).unwrap(); + + coin_id = <&str>::clone( + &resp_json + .pointer("/status/transferred_gas_objects/sent/0/id") + .unwrap() + .as_str() + .unwrap(), + ) + .to_string(); + + break; + } else { + tokio::time::sleep(Duration::from_secs(1)).await; + } + } + + // wait until the fullnode has the coin object, and check if it has the same + // owner + loop { + let owner = iota_client + .read_api() + .get_object_with_options( + ObjectID::from_str(&coin_id)?, + IotaObjectDataOptions::new().with_owner(), + ) + .await?; + + if owner.owner().is_some() { + let owner_address = owner.owner().unwrap().get_owner_address()?; + if owner_address == address { + break; + } + } else { + tokio::time::sleep(Duration::from_secs(1)).await; + } + } + Ok(()) +} + +/// Return the coin owned by the address that has at least 5_000_000 MICROS, +/// otherwise returns None +pub async fn fetch_coin( + iota: &IotaClient, + sender: &IotaAddress, +) -> Result, anyhow::Error> { + let coin_type = "0x2::iota::IOTA".to_string(); + let coins_stream = iota + .coin_read_api() + .get_coins_stream(*sender, Some(coin_type)); + + let mut coins = coins_stream + .skip_while(|c| future::ready(c.balance < 5_000_000)) + .boxed(); + let coin = coins.next().await; + Ok(coin) +} + +/// Return a transaction digest from a split coin + merge coins transaction +pub async fn split_coin_digest( + iota: &IotaClient, + sender: &IotaAddress, +) -> Result { + let coin = match fetch_coin(iota, sender).await? { + None => { + request_tokens_from_faucet(*sender, iota).await?; + fetch_coin(iota, sender) + .await? + .expect("Supposed to get a coin with IOTA, but didn't. Aborting") + } + Some(c) => c, + }; + + println!( + "Address: {sender}. The selected coin for split is {} and has a balance of {}\n", + coin.coin_object_id, coin.balance + ); + + // set the maximum gas budget + let max_gas_budget = 5_000_000; + + // get the reference gas price from the network + let gas_price = iota.read_api().get_reference_gas_price().await?; + + // now we programmatically build the transaction through several commands + let mut ptb = ProgrammableTransactionBuilder::new(); + // first, we want to split the coin, and we specify how much IOTA (in MICROS) we + // want for the new coin + let split_coin_amount = ptb.pure(1000u64)?; // note that we need to specify the u64 type here + ptb.command(Command::SplitCoins( + Argument::GasCoin, + vec![split_coin_amount], + )); + // now we want to merge the coins (so that we don't have many coins with very + // small values) observe here that we pass Argument::Result(0), which + // instructs the PTB to get the result from the previous command + ptb.command(Command::MergeCoins( + Argument::GasCoin, + vec![Argument::Result(0)], + )); + + // we finished constructing our PTB and we need to call finish + let builder = ptb.finish(); + + // using the PTB that we just constructed, create the transaction data + // that we will submit to the network + let tx_data = TransactionData::new_programmable( + *sender, + vec![coin.object_ref()], + builder, + max_gas_budget, + gas_price, + ); + + // sign & execute the transaction + let keystore = FileBasedKeystore::new(&iota_config_dir()?.join(IOTA_KEYSTORE_FILENAME))?; + let signature = keystore.sign_secure(sender, &tx_data, Intent::iota_transaction())?; + + let transaction_response = iota + .quorum_driver_api() + .execute_transaction_block( + Transaction::from_data(tx_data, vec![signature]), + IotaTransactionBlockResponseOptions::new(), + Some(ExecuteTransactionRequestType::WaitForLocalExecution), + ) + .await?; + Ok(transaction_response.digest) +} + +pub fn retrieve_wallet() -> Result { + let wallet_conf = iota_config_dir()?.join(IOTA_CLIENT_CONFIG); + let keystore_path = iota_config_dir()?.join(IOTA_KEYSTORE_FILENAME); + + // check if a wallet exists and if not, create a wallet and a iota client config + if !keystore_path.exists() { + let keystore = FileBasedKeystore::new(&keystore_path)?; + keystore.save()?; + } + + if !wallet_conf.exists() { + let keystore = FileBasedKeystore::new(&keystore_path)?; + let mut client_config = IotaClientConfig::new(keystore.into()); + + client_config.add_env(IotaEnv::testnet()); + client_config.add_env(IotaEnv::devnet()); + client_config.add_env(IotaEnv::localnet()); + + if client_config.active_env.is_none() { + client_config.active_env = client_config.envs.first().map(|env| env.alias.clone()); + } + + client_config.save(&wallet_conf)?; + info!("Client config file is stored in {:?}.", &wallet_conf); + } + + let mut keystore = FileBasedKeystore::new(&keystore_path)?; + let mut client_config: IotaClientConfig = PersistedConfig::read(&wallet_conf)?; + + let default_active_address = if let Some(address) = keystore.addresses().first() { + *address + } else { + keystore + .generate_and_add_new_key(ED25519, None, None, None)? + .0 + }; + + if keystore.addresses().len() < 2 { + keystore.generate_and_add_new_key(ED25519, None, None, None)?; + } + + client_config.active_address = Some(default_active_address); + client_config.save(&wallet_conf)?; + + let wallet = WalletContext::new(&wallet_conf, Some(std::time::Duration::from_secs(60)), None)?; + + Ok(wallet) +} + +// this function should not be used. It is only used to make clippy happy, +// and to reduce the number of allow(dead_code) annotations to just this one +#[allow(dead_code)] +async fn just_for_clippy() -> Result<(), anyhow::Error> { + let (iota, sender, _recipient) = setup_for_write().await?; + let _digest = split_coin_digest(&iota, &sender).await?; + Ok(()) +} diff --git a/crates/iota-sdk/src/apis.rs b/crates/iota-sdk/src/apis.rs new file mode 100644 index 00000000000..0eb21059537 --- /dev/null +++ b/crates/iota-sdk/src/apis.rs @@ -0,0 +1,1290 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::BTreeMap, future, sync::Arc, time::Instant}; + +use fastcrypto::encoding::Base64; +use futures::{stream, StreamExt}; +use futures_core::Stream; +use iota_json_rpc_api::{ + CoinReadApiClient, GovernanceReadApiClient, IndexerApiClient, MoveUtilsClient, ReadApiClient, + WriteApiClient, +}; +use iota_json_rpc_types::{ + Balance, Checkpoint, CheckpointId, CheckpointPage, Coin, CoinPage, DelegatedStake, + DevInspectArgs, DevInspectResults, DryRunTransactionBlockResponse, DynamicFieldPage, + EventFilter, EventPage, IotaCoinMetadata, IotaCommittee, IotaData, IotaEvent, + IotaGetPastObjectRequest, IotaLoadedChildObjectsResponse, IotaMoveNormalizedModule, + IotaObjectDataOptions, IotaObjectResponse, IotaObjectResponseQuery, IotaPastObjectResponse, + IotaTransactionBlockEffects, IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, + IotaTransactionBlockResponseQuery, ObjectsPage, ProtocolConfigResponse, TransactionBlocksPage, + TransactionFilter, +}; +use iota_types::{ + balance::Supply, + base_types::{IotaAddress, ObjectID, SequenceNumber, TransactionDigest}, + dynamic_field::DynamicFieldName, + event::EventID, + iota_serde::BigInt, + iota_system_state::iota_system_state_summary::IotaSystemStateSummary, + messages_checkpoint::CheckpointSequenceNumber, + quorum_driver_types::ExecuteTransactionRequestType, + transaction::{Transaction, TransactionData, TransactionKind}, +}; +use jsonrpsee::core::client::Subscription; + +use crate::{ + error::{Error, IotaRpcResult}, + RpcClient, +}; + +const WAIT_FOR_LOCAL_EXECUTION_RETRY_COUNT: u8 = 3; + +/// The main read API structure with functions for retrieving data about +/// different objects and transactions +#[derive(Debug)] +pub struct ReadApi { + api: Arc, +} + +impl ReadApi { + pub(crate) fn new(api: Arc) -> Self { + Self { api } + } + /// Return a paginated response with the objects owned by the given address, + /// or an error upon failure. + /// + /// Note that if the address owns more than `QUERY_MAX_RESULT_LIMIT` objects + /// (default is 50), the pagination is not accurate, because previous + /// page may have been updated when the next page is fetched. + /// + /// # Examples + /// + /// ```rust,no_run + /// use std::str::FromStr; + /// + /// use iota_sdk::IotaClientBuilder; + /// use iota_types::base_types::IotaAddress; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let address = IotaAddress::from_str("0x0000....0000")?; + /// let owned_objects = iota + /// .read_api() + /// .get_owned_objects(address, None, None, None) + /// .await?; + /// Ok(()) + /// } + /// ``` + pub async fn get_owned_objects( + &self, + address: IotaAddress, + query: Option, + cursor: Option, + limit: Option, + ) -> IotaRpcResult { + Ok(self + .api + .http + .get_owned_objects(address, query, cursor, limit) + .await?) + } + + /// Return a paginated response with the dynamic fields owned by the given + /// [ObjectID], or an error upon failure. + /// + /// The return type is a list of `DynamicFieldInfo` objects, where the field + /// name is always present, represented as a Move `Value`. + /// + /// If the field is a dynamic field, returns the ID of the Field object + /// (which contains both the name and the value). If the field is a + /// dynamic object field, it returns the ID of the Object (the value of the + /// field). + /// + /// # Examples + /// + /// ```rust,no_run + /// use std::str::FromStr; + /// + /// use iota_sdk::IotaClientBuilder; + /// use iota_types::base_types::{IotaAddress, ObjectID}; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let address = IotaAddress::from_str("0x0000....0000")?; + /// let owned_objects = iota + /// .read_api() + /// .get_owned_objects(address, None, None, None) + /// .await?; + /// // this code example assumes that there are previous owned objects + /// let object = owned_objects + /// .data + /// .get(0) + /// .expect(&format!("No owned objects for this address {}", address)); + /// let object_data = object.data.as_ref().expect(&format!( + /// "No object data for this IotaObjectResponse {:?}", + /// object + /// )); + /// let object_id = object_data.object_id; + /// let dynamic_fields = iota + /// .read_api() + /// .get_dynamic_fields(object_id, None, None) + /// .await?; + /// Ok(()) + /// } + /// ``` + pub async fn get_dynamic_fields( + &self, + object_id: ObjectID, + cursor: Option, + limit: Option, + ) -> IotaRpcResult { + Ok(self + .api + .http + .get_dynamic_fields(object_id, cursor, limit) + .await?) + } + + /// Return the dynamic field object information for a specified object. + pub async fn get_dynamic_field_object( + &self, + parent_object_id: ObjectID, + name: DynamicFieldName, + ) -> IotaRpcResult { + Ok(self + .api + .http + .get_dynamic_field_object(parent_object_id, name) + .await?) + } + + /// Return a parsed past object for the provided [ObjectID] and version, or + /// an error upon failure. + /// + /// An object's version increases (though it is not guaranteed that it + /// increases always by 1) when the object is mutated. A past object can + /// be used to understand how the object changed over time, + /// i.e. what was the total balance at a specific version. + /// + /// # Examples + /// + /// ```rust,no_run + /// use std::str::FromStr; + /// + /// use iota_json_rpc_types::IotaObjectDataOptions; + /// use iota_sdk::IotaClientBuilder; + /// use iota_types::base_types::{IotaAddress, ObjectID}; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let address = IotaAddress::from_str("0x0000....0000")?; + /// let owned_objects = iota + /// .read_api() + /// .get_owned_objects(address, None, None, None) + /// .await?; + /// // this code example assumes that there are previous owned objects + /// let object = owned_objects + /// .data + /// .get(0) + /// .expect(&format!("No owned objects for this address {}", address)); + /// let object_data = object.data.as_ref().expect(&format!( + /// "No object data for this IotaObjectResponse {:?}", + /// object + /// )); + /// let object_id = object_data.object_id; + /// let version = object_data.version; + /// let past_object = iota + /// .read_api() + /// .try_get_parsed_past_object( + /// object_id, + /// version, + /// IotaObjectDataOptions { + /// show_type: true, + /// show_owner: true, + /// show_previous_transaction: true, + /// show_display: true, + /// show_content: true, + /// show_bcs: true, + /// show_storage_rebate: true, + /// }, + /// ) + /// .await?; + /// Ok(()) + /// } + /// ``` + pub async fn try_get_parsed_past_object( + &self, + object_id: ObjectID, + version: SequenceNumber, + options: IotaObjectDataOptions, + ) -> IotaRpcResult { + Ok(self + .api + .http + .try_get_past_object(object_id, version, Some(options)) + .await?) + } + + /// Return a list of [IotaPastObjectResponse] objects, or an error upon + /// failure. + /// + /// See [this function](ReadApi::try_get_parsed_past_object) for more + /// details about past objects. + /// + /// # Examples + /// + /// ```rust,no_run + /// use std::str::FromStr; + /// + /// use iota_json_rpc_types::{IotaGetPastObjectRequest, IotaObjectDataOptions}; + /// use iota_sdk::IotaClientBuilder; + /// use iota_types::base_types::{IotaAddress, ObjectID}; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let address = IotaAddress::from_str("0x0000....0000")?; + /// let owned_objects = iota + /// .read_api() + /// .get_owned_objects(address, None, None, None) + /// .await?; + /// // this code example assumes that there are previous owned objects + /// let object = owned_objects + /// .data + /// .get(0) + /// .expect(&format!("No owned objects for this address {}", address)); + /// let object_data = object.data.as_ref().expect(&format!( + /// "No object data for this IotaObjectResponse {:?}", + /// object + /// )); + /// let object_id = object_data.object_id; + /// let version = object_data.version; + /// let past_object = iota + /// .read_api() + /// .try_get_parsed_past_object( + /// object_id, + /// version, + /// IotaObjectDataOptions { + /// show_type: true, + /// show_owner: true, + /// show_previous_transaction: true, + /// show_display: true, + /// show_content: true, + /// show_bcs: true, + /// show_storage_rebate: true, + /// }, + /// ) + /// .await?; + /// let past_object = past_object.into_object()?; + /// let multi_past_object = iota + /// .read_api() + /// .try_multi_get_parsed_past_object( + /// vec![IotaGetPastObjectRequest { + /// object_id: past_object.object_id, + /// version: past_object.version, + /// }], + /// IotaObjectDataOptions { + /// show_type: true, + /// show_owner: true, + /// show_previous_transaction: true, + /// show_display: true, + /// show_content: true, + /// show_bcs: true, + /// show_storage_rebate: true, + /// }, + /// ) + /// .await?; + /// Ok(()) + /// } + /// ``` + pub async fn try_multi_get_parsed_past_object( + &self, + past_objects: Vec, + options: IotaObjectDataOptions, + ) -> IotaRpcResult> { + Ok(self + .api + .http + .try_multi_get_past_objects(past_objects, Some(options)) + .await?) + } + + /// Return a [IotaObjectResponse] based on the provided [ObjectID] and + /// [IotaObjectDataOptions], or an error upon failure. + /// + /// The [IotaObjectResponse] contains two fields: + /// 1) `data` for the object's data (see + /// [IotaObjectData](iota_json_rpc_types::IotaObjectData)), + /// 2) `error` for the error (if any) (see + /// [IotaObjectResponseError](iota_types::error::IotaObjectResponseError)). + /// + /// # Examples + /// + /// ```rust,no_run + /// use std::str::FromStr; + /// + /// use iota_json_rpc_types::IotaObjectDataOptions; + /// use iota_sdk::IotaClientBuilder; + /// use iota_types::base_types::IotaAddress; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let address = IotaAddress::from_str("0x0000....0000")?; + /// let owned_objects = iota + /// .read_api() + /// .get_owned_objects(address, None, None, None) + /// .await?; + /// // this code example assumes that there are previous owned objects + /// let object = owned_objects + /// .data + /// .get(0) + /// .expect(&format!("No owned objects for this address {}", address)); + /// let object_data = object.data.as_ref().expect(&format!( + /// "No object data for this IotaObjectResponse {:?}", + /// object + /// )); + /// let object_id = object_data.object_id; + /// let object = iota + /// .read_api() + /// .get_object_with_options( + /// object_id, + /// IotaObjectDataOptions { + /// show_type: true, + /// show_owner: true, + /// show_previous_transaction: true, + /// show_display: true, + /// show_content: true, + /// show_bcs: true, + /// show_storage_rebate: true, + /// }, + /// ) + /// .await?; + /// Ok(()) + /// } + /// ``` + pub async fn get_object_with_options( + &self, + object_id: ObjectID, + options: IotaObjectDataOptions, + ) -> IotaRpcResult { + Ok(self.api.http.get_object(object_id, Some(options)).await?) + } + + /// Return a list of [IotaObjectResponse] from the given vector of + /// [ObjectID]s and [IotaObjectDataOptions], or an error upon failure. + /// + /// If only one object is needed, use the + /// [get_object_with_options](ReadApi::get_object_with_options) function + /// instead. + /// + /// # Examples + /// + /// ```rust,no_run + /// use std::str::FromStr; + /// + /// use iota_json_rpc_types::IotaObjectDataOptions; + /// use iota_sdk::IotaClientBuilder; + /// use iota_types::base_types::IotaAddress; + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let address = IotaAddress::from_str("0x0000....0000")?; + /// let owned_objects = iota + /// .read_api() + /// .get_owned_objects(address, None, None, None) + /// .await?; + /// // this code example assumes that there are previous owned objects + /// let object = owned_objects + /// .data + /// .get(0) + /// .expect(&format!("No owned objects for this address {}", address)); + /// let object_data = object.data.as_ref().expect(&format!( + /// "No object data for this IotaObjectResponse {:?}", + /// object + /// )); + /// let object_id = object_data.object_id; + /// let object_ids = vec![object_id]; // and other object ids + /// let object = iota + /// .read_api() + /// .multi_get_object_with_options( + /// object_ids, + /// IotaObjectDataOptions { + /// show_type: true, + /// show_owner: true, + /// show_previous_transaction: true, + /// show_display: true, + /// show_content: true, + /// show_bcs: true, + /// show_storage_rebate: true, + /// }, + /// ) + /// .await?; + /// Ok(()) + /// } + /// ``` + pub async fn multi_get_object_with_options( + &self, + object_ids: Vec, + options: IotaObjectDataOptions, + ) -> IotaRpcResult> { + Ok(self + .api + .http + .multi_get_objects(object_ids, Some(options)) + .await?) + } + + /// Return An object's bcs content [`Vec`] based on the provided + /// [ObjectID], or an error upon failure. + pub async fn get_move_object_bcs(&self, object_id: ObjectID) -> IotaRpcResult> { + let resp = self + .get_object_with_options(object_id, IotaObjectDataOptions::default().with_bcs()) + .await? + .into_object() + .map_err(|e| { + Error::DataError(format!("Can't get bcs of object {:?}: {:?}", object_id, e)) + })?; + // unwrap: requested bcs data + let move_object = resp.bcs.unwrap(); + let raw_move_obj = move_object.try_into_move().ok_or(Error::DataError(format!( + "Object {:?} is not a MoveObject", + object_id + )))?; + Ok(raw_move_obj.bcs_bytes) + } + + /// Return the total number of transaction blocks known to server, or an + /// error upon failure. + /// + /// # Examples + /// + /// ```rust,no_run + /// use iota_sdk::IotaClientBuilder; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let total_transaction_blocks = iota.read_api().get_total_transaction_blocks().await?; + /// Ok(()) + /// } + /// ``` + pub async fn get_total_transaction_blocks(&self) -> IotaRpcResult { + Ok(*self.api.http.get_total_transaction_blocks().await?) + } + + /// Return a transaction and its effects in a [IotaTransactionBlockResponse] + /// based on its [TransactionDigest], or an error upon failure. + pub async fn get_transaction_with_options( + &self, + digest: TransactionDigest, + options: IotaTransactionBlockResponseOptions, + ) -> IotaRpcResult { + Ok(self + .api + .http + .get_transaction_block(digest, Some(options)) + .await?) + } + /// Return a list of [IotaTransactionBlockResponse] based on the given + /// vector of [TransactionDigest], or an error upon failure. + /// + /// If only one transaction data is needed, use the + /// [get_transaction_with_options](ReadApi::get_transaction_with_options) + /// function instead. + pub async fn multi_get_transactions_with_options( + &self, + digests: Vec, + options: IotaTransactionBlockResponseOptions, + ) -> IotaRpcResult> { + Ok(self + .api + .http + .multi_get_transaction_blocks(digests, Some(options)) + .await?) + } + + /// Return the [IotaCommittee] information for the provided `epoch`, or an + /// error upon failure. + /// + /// The [IotaCommittee] contains the validators list and their information + /// (name and stakes). + /// + /// The argument `epoch` is either a known epoch id or `None` for the + /// current epoch. + /// + /// # Examples + /// + /// ```rust,no_run + /// use iota_sdk::IotaClientBuilder; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let committee_info = iota.read_api().get_committee_info(None).await?; + /// Ok(()) + /// } + /// ``` + pub async fn get_committee_info( + &self, + epoch: Option>, + ) -> IotaRpcResult { + Ok(self.api.http.get_committee_info(epoch).await?) + } + + /// Return a paginated response with all transaction blocks information, or + /// an error upon failure. + pub async fn query_transaction_blocks( + &self, + query: IotaTransactionBlockResponseQuery, + cursor: Option, + limit: Option, + descending_order: bool, + ) -> IotaRpcResult { + Ok(self + .api + .http + .query_transaction_blocks(query, cursor, limit, Some(descending_order)) + .await?) + } + + /// Return the first four bytes of the chain's genesis checkpoint digest, or + /// an error upon failure. + pub async fn get_chain_identifier(&self) -> IotaRpcResult { + Ok(self.api.http.get_chain_identifier().await?) + } + + /// Return a checkpoint, or an error upon failure. + /// + /// A Iota checkpoint is a sequence of transaction sets that a quorum of + /// validators agree upon as having been executed within the Iota system. + pub async fn get_checkpoint(&self, id: CheckpointId) -> IotaRpcResult { + Ok(self.api.http.get_checkpoint(id).await?) + } + + /// Return a paginated list of checkpoints, or an error upon failure. + pub async fn get_checkpoints( + &self, + cursor: Option>, + limit: Option, + descending_order: bool, + ) -> IotaRpcResult { + Ok(self + .api + .http + .get_checkpoints(cursor, limit, descending_order) + .await?) + } + + /// Return the sequence number of the latest checkpoint that has been + /// executed, or an error upon failure. + pub async fn get_latest_checkpoint_sequence_number( + &self, + ) -> IotaRpcResult { + Ok(*self + .api + .http + .get_latest_checkpoint_sequence_number() + .await?) + } + + /// Return a stream of [IotaTransactionBlockResponse], or an error upon + /// failure. + pub fn get_transactions_stream( + &self, + query: IotaTransactionBlockResponseQuery, + cursor: Option, + descending_order: bool, + ) -> impl Stream + '_ { + stream::unfold( + (vec![], cursor, true, query), + move |(mut data, cursor, first, query)| async move { + if let Some(item) = data.pop() { + Some((item, (data, cursor, false, query))) + } else if (cursor.is_none() && first) || cursor.is_some() { + let page = self + .query_transaction_blocks( + query.clone(), + cursor, + Some(100), + descending_order, + ) + .await + .ok()?; + let mut data = page.data; + data.reverse(); + data.pop() + .map(|item| (item, (data, page.next_cursor, false, query))) + } else { + None + } + }, + ) + } + + /// Subscribe to a stream of transactions. + /// + /// This is only available through WebSockets. + pub async fn subscribe_transaction( + &self, + filter: TransactionFilter, + ) -> IotaRpcResult>> { + let Some(c) = &self.api.ws else { + return Err(Error::Subscription( + "Subscription only supported by WebSocket client.".to_string(), + )); + }; + let subscription: Subscription = + c.subscribe_transaction(filter).await?; + Ok(subscription.map(|item| Ok(item?))) + } + + /// Return a map consisting of the move package name and the normalized + /// module, or an error upon failure. + pub async fn get_normalized_move_modules_by_package( + &self, + package: ObjectID, + ) -> IotaRpcResult> { + Ok(self + .api + .http + .get_normalized_move_modules_by_package(package) + .await?) + } + + // TODO(devx): we can probably cache this given an epoch + /// Return the reference gas price, or an error upon failure. + pub async fn get_reference_gas_price(&self) -> IotaRpcResult { + Ok(*self.api.http.get_reference_gas_price().await?) + } + + /// Dry run a transaction block given the provided transaction data. Returns + /// an error upon failure. + /// + /// Simulate running the transaction, including all standard checks, without + /// actually running it. This is useful for estimating the gas fees of a + /// transaction before executing it. You can also use it to identify any + /// side-effects of a transaction before you execute it on the network. + pub async fn dry_run_transaction_block( + &self, + tx: TransactionData, + ) -> IotaRpcResult { + Ok(self + .api + .http + .dry_run_transaction_block(Base64::from_bytes(&bcs::to_bytes(&tx)?)) + .await?) + } + + /// Return the inspection of the transaction block, or an error upon + /// failure. + /// + /// Use this function to inspect the current state of the network by running + /// a programmable transaction block without committing its effects on + /// chain. Unlike + /// [dry_run_transaction_block](ReadApi::dry_run_transaction_block), + /// dev inspect will not validate whether the transaction block + /// would succeed or fail under normal circumstances, e.g.: + /// + /// - Transaction inputs are not checked for ownership (i.e. you can + /// construct calls involving objects you do not own). + /// - Calls are not checked for visibility (you can call private functions + /// on modules) + /// - Inputs of any type can be constructed and passed in, (including Coins + /// and other objects that would usually need to be constructed with a + /// move call). + /// - Function returns do not need to be used, even if they do not have + /// `drop`. + /// + /// Dev inspect's output includes a breakdown of results returned by every + /// transaction in the block, as well as the transaction's effects. + /// + /// To run an accurate simulation of a transaction and understand whether + /// it will successfully validate and run, + /// use the [dry_run_transaction_block](ReadApi::dry_run_transaction_block) + /// function instead. + pub async fn dev_inspect_transaction_block( + &self, + sender_address: IotaAddress, + tx: TransactionKind, + gas_price: Option>, + epoch: Option>, + additional_args: Option, + ) -> IotaRpcResult { + Ok(self + .api + .http + .dev_inspect_transaction_block( + sender_address, + Base64::from_bytes(&bcs::to_bytes(&tx)?), + gas_price, + epoch, + additional_args, + ) + .await?) + } + + /// Return the loaded child objects response for the provided digest, or an + /// error upon failure. + /// + /// Loaded child objects + /// ([IotaLoadedChildObject](iota_json_rpc_types::IotaLoadedChildObject)) + /// are the non-input objects that the transaction at the digest loaded + /// in response to dynamic field accesses. + pub async fn get_loaded_child_objects( + &self, + digest: TransactionDigest, + ) -> IotaRpcResult { + Ok(self.api.http.get_loaded_child_objects(digest).await?) + } + + /// Return the protocol config, or an error upon failure. + pub async fn get_protocol_config( + &self, + version: Option>, + ) -> IotaRpcResult { + Ok(self.api.http.get_protocol_config(version).await?) + } +} + +/// Coin Read API provides the functionality needed to get information from the +/// Iota network regarding the coins owned by an address. +#[derive(Debug, Clone)] +pub struct CoinReadApi { + api: Arc, +} + +impl CoinReadApi { + pub(crate) fn new(api: Arc) -> Self { + Self { api } + } + + /// Return a paginated response with the coins for the given address, or an + /// error upon failure. + /// + /// The coins can be filtered by `coin_type` (e.g., + /// 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC) + /// or use `None` for the default `Coin`. + /// + /// # Examples + /// + /// ```rust,no_run + /// use std::str::FromStr; + /// + /// use iota_sdk::IotaClientBuilder; + /// use iota_types::base_types::IotaAddress; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let address = IotaAddress::from_str("0x0000....0000")?; + /// let coins = iota + /// .coin_read_api() + /// .get_coins(address, None, None, None) + /// .await?; + /// Ok(()) + /// } + /// ``` + pub async fn get_coins( + &self, + owner: IotaAddress, + coin_type: Option, + cursor: Option, + limit: Option, + ) -> IotaRpcResult { + Ok(self + .api + .http + .get_coins(owner, coin_type, cursor, limit) + .await?) + } + /// Return a paginated response with all the coins for the given address, or + /// an error upon failure. + /// + /// This function includes all coins. If needed to filter by coin type, use + /// the `get_coins` method instead. + /// + /// # Examples + /// + /// ```rust,no_run + /// use std::str::FromStr; + /// + /// use iota_sdk::IotaClientBuilder; + /// use iota_types::base_types::IotaAddress; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let address = IotaAddress::from_str("0x0000....0000")?; + /// let coins = iota + /// .coin_read_api() + /// .get_all_coins(address, None, None) + /// .await?; + /// Ok(()) + /// } + /// ``` + pub async fn get_all_coins( + &self, + owner: IotaAddress, + cursor: Option, + limit: Option, + ) -> IotaRpcResult { + Ok(self.api.http.get_all_coins(owner, cursor, limit).await?) + } + + /// Return the coins for the given address as a stream. + /// + /// The coins can be filtered by `coin_type` (e.g., + /// 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC) + /// or use `None` for the default `Coin`. + /// + /// # Examples + /// + /// ```rust,no_run + /// use std::str::FromStr; + /// + /// use iota_sdk::IotaClientBuilder; + /// use iota_types::base_types::IotaAddress; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let address = IotaAddress::from_str("0x0000....0000")?; + /// let coins = iota.coin_read_api().get_coins_stream(address, None); + /// Ok(()) + /// } + /// ``` + pub fn get_coins_stream( + &self, + owner: IotaAddress, + coin_type: Option, + ) -> impl Stream + '_ { + stream::unfold( + ( + vec![], + // cursor + None, + // has_next_page + true, + coin_type, + ), + move |(mut data, cursor, has_next_page, coin_type)| async move { + if let Some(item) = data.pop() { + Some((item, (data, cursor, /* has_next_page */ true, coin_type))) + } else if has_next_page { + let page = self + .get_coins(owner, coin_type.clone(), cursor, Some(100)) + .await + .ok()?; + let mut data = page.data; + data.reverse(); + data.pop().map(|item| { + ( + item, + (data, page.next_cursor, page.has_next_page, coin_type), + ) + }) + } else { + None + } + }, + ) + } + + /// Return a list of coins for the given address, or an error upon failure. + /// + /// Note that the function selects coins to meet or exceed the requested + /// `amount`. If that it is not possible, it will fail with an + /// insufficient fund error. + /// + /// The coins can be filtered by `coin_type` (e.g., + /// 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC) + /// or use `None` to use the default `Coin`. + /// + /// # Examples + /// + /// ```rust,no_run + /// use std::str::FromStr; + /// + /// use iota_sdk::IotaClientBuilder; + /// use iota_types::base_types::IotaAddress; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let address = IotaAddress::from_str("0x0000....0000")?; + /// let coins = iota + /// .coin_read_api() + /// .select_coins(address, None, 5, vec![]) + /// .await?; + /// Ok(()) + /// } + /// ``` + pub async fn select_coins( + &self, + address: IotaAddress, + coin_type: Option, + amount: u128, + exclude: Vec, + ) -> IotaRpcResult> { + let mut total = 0u128; + let coins = self + .get_coins_stream(address, coin_type) + .filter(|coin: &Coin| future::ready(!exclude.contains(&coin.coin_object_id))) + .take_while(|coin: &Coin| { + let ready = future::ready(total < amount); + total += coin.balance as u128; + ready + }) + .collect::>() + .await; + + if total < amount { + return Err(Error::InsufficientFund { address, amount }); + } + Ok(coins) + } + + /// Return the balance for the given coin type owned by address, or an error + /// upon failure. + /// + /// Note that this function sums up all the balances of all the coins + /// matching the given coin type. By default, if `coin_type` is set to + /// `None`, it will use the default `Coin`. + /// + /// # Examples + /// + /// ```rust,no_run + /// use std::str::FromStr; + /// + /// use iota_sdk::IotaClientBuilder; + /// use iota_types::base_types::IotaAddress; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let address = IotaAddress::from_str("0x0000....0000")?; + /// let balance = iota.coin_read_api().get_balance(address, None).await?; + /// Ok(()) + /// } + /// ``` + pub async fn get_balance( + &self, + owner: IotaAddress, + coin_type: Option, + ) -> IotaRpcResult { + Ok(self.api.http.get_balance(owner, coin_type).await?) + } + + /// Return a list of balances for each coin type owned by the given address, + /// or an error upon failure. + /// + /// Note that this function groups the coins by coin type, and sums up all + /// their balances. + /// + /// # Examples + /// + /// ```rust,no_run + /// use std::str::FromStr; + /// + /// use iota_sdk::IotaClientBuilder; + /// use iota_types::base_types::IotaAddress; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let address = IotaAddress::from_str("0x0000....0000")?; + /// let all_balances = iota.coin_read_api().get_all_balances(address).await?; + /// Ok(()) + /// } + /// ``` + pub async fn get_all_balances(&self, owner: IotaAddress) -> IotaRpcResult> { + Ok(self.api.http.get_all_balances(owner).await?) + } + + /// Return the coin metadata (name, symbol, description, decimals, etc.) for + /// a given coin type, or an error upon failure. + /// + /// # Examples + /// + /// ```rust,no_run + /// use iota_sdk::IotaClientBuilder; + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let coin_metadata = iota + /// .coin_read_api() + /// .get_coin_metadata("0x2::iota::IOTA".to_string()) + /// .await?; + /// Ok(()) + /// } + /// ``` + pub async fn get_coin_metadata( + &self, + coin_type: String, + ) -> IotaRpcResult> { + Ok(self.api.http.get_coin_metadata(coin_type).await?) + } + + /// Return the total supply for a given coin type, or an error upon failure. + /// + /// # Examples + /// + /// ```rust,no_run + /// use iota_sdk::IotaClientBuilder; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let total_supply = iota + /// .coin_read_api() + /// .get_total_supply("0x2::iota::IOTA".to_string()) + /// .await?; + /// Ok(()) + /// } + /// ``` + pub async fn get_total_supply(&self, coin_type: String) -> IotaRpcResult { + Ok(self.api.http.get_total_supply(coin_type).await?) + } +} + +/// Event API provides the functionality to fetch, query, or subscribe to events +/// on the Iota network. +#[derive(Clone)] +pub struct EventApi { + api: Arc, +} + +impl EventApi { + pub(crate) fn new(api: Arc) -> Self { + Self { api } + } + + /// Return a stream of events, or an error upon failure. + /// + /// Subscription is only possible via WebSockets. + /// For a list of possible event filters, see [EventFilter]. + /// + /// # Examples + /// + /// ```rust, no_run + /// use std::str::FromStr; + /// + /// use futures::StreamExt; + /// use iota_json_rpc_types::EventFilter; + /// use iota_sdk::IotaClientBuilder; + /// use iota_types::base_types::IotaAddress; + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default() + /// .ws_url("wss://rpc.mainnet.iota.io:443") + /// .build("https://fullnode.mainnet.iota.io:443") + /// .await?; + /// let mut subscribe_all = iota + /// .event_api() + /// .subscribe_event(EventFilter::All(vec![])) + /// .await?; + /// loop { + /// println!("{:?}", subscribe_all.next().await); + /// } + /// Ok(()) + /// } + /// ``` + pub async fn subscribe_event( + &self, + filter: EventFilter, + ) -> IotaRpcResult>> { + match &self.api.ws { + Some(c) => { + let subscription: Subscription = c.subscribe_event(filter).await?; + Ok(subscription.map(|item| Ok(item?))) + } + _ => Err(Error::Subscription( + "Subscription only supported by WebSocket client.".to_string(), + )), + } + } + + /// Return a list of events for the given transaction digest, or an error + /// upon failure. + pub async fn get_events(&self, digest: TransactionDigest) -> IotaRpcResult> { + Ok(self.api.http.get_events(digest).await?) + } + + /// Return a paginated response with events for the given event filter, or + /// an error upon failure. + /// + /// The ordering of the events can be set with the `descending_order` + /// argument. For a list of possible event filters, see [EventFilter]. + pub async fn query_events( + &self, + query: EventFilter, + cursor: Option, + limit: Option, + descending_order: bool, + ) -> IotaRpcResult { + Ok(self + .api + .http + .query_events(query, cursor, limit, Some(descending_order)) + .await?) + } + + /// Return a stream of events for the given event filter. + /// + /// The ordering of the events can be set with the `descending_order` + /// argument. For a list of possible event filters, see [EventFilter]. + pub fn get_events_stream( + &self, + query: EventFilter, + cursor: Option, + descending_order: bool, + ) -> impl Stream + '_ { + stream::unfold( + (vec![], cursor, true, query), + move |(mut data, cursor, first, query)| async move { + if let Some(item) = data.pop() { + Some((item, (data, cursor, false, query))) + } else if (cursor.is_none() && first) || cursor.is_some() { + let page = self + .query_events(query.clone(), cursor, Some(100), descending_order) + .await + .ok()?; + let mut data = page.data; + data.reverse(); + data.pop() + .map(|item| (item, (data, page.next_cursor, false, query))) + } else { + None + } + }, + ) + } +} + +/// Quorum API that provides functionality to execute a transaction block and +/// submit it to the fullnode(s). +#[derive(Clone)] +pub struct QuorumDriverApi { + api: Arc, +} + +impl QuorumDriverApi { + pub(crate) fn new(api: Arc) -> Self { + Self { api } + } + + /// Execute a transaction with a FullNode client. `request_type` + /// defaults to `ExecuteTransactionRequestType::WaitForLocalExecution`. + /// When `ExecuteTransactionRequestType::WaitForLocalExecution` is used, + /// but returned `confirmed_local_execution` is false, the client will + /// keep retry for WAIT_FOR_LOCAL_EXECUTION_RETRY_COUNT times. If it + /// still fails, it will return an error. + pub async fn execute_transaction_block( + &self, + tx: Transaction, + options: IotaTransactionBlockResponseOptions, + request_type: Option, + ) -> IotaRpcResult { + let (tx_bytes, signatures) = tx.to_tx_bytes_and_signatures(); + let request_type = request_type.unwrap_or_else(|| options.default_execution_request_type()); + let mut retry_count = 0; + let start = Instant::now(); + while retry_count < WAIT_FOR_LOCAL_EXECUTION_RETRY_COUNT { + let response: IotaTransactionBlockResponse = self + .api + .http + .execute_transaction_block( + tx_bytes.clone(), + signatures.clone(), + Some(options.clone()), + Some(request_type.clone()), + ) + .await?; + + match request_type { + ExecuteTransactionRequestType::WaitForEffectsCert => { + return Ok(response); + } + ExecuteTransactionRequestType::WaitForLocalExecution => { + if let Some(true) = response.confirmed_local_execution { + return Ok(response); + } else { + // If fullnode executed the cert in the network but did not confirm local + // execution, it must have timed out and hence we could retry. + retry_count += 1; + } + } + } + } + Err(Error::FailToConfirmTransactionStatus( + *tx.digest(), + start.elapsed().as_secs(), + )) + } +} + +/// Governance API provides the staking functionality. +#[derive(Debug, Clone)] +pub struct GovernanceApi { + api: Arc, +} + +impl GovernanceApi { + pub(crate) fn new(api: Arc) -> Self { + Self { api } + } + + /// Return a list of [DelegatedStake] objects for the given address, or an + /// error upon failure. + pub async fn get_stakes(&self, owner: IotaAddress) -> IotaRpcResult> { + Ok(self.api.http.get_stakes(owner).await?) + } + + /// Return the [IotaCommittee] information for the given `epoch`, or an + /// error upon failure. + /// + /// The argument `epoch` is the known epoch id or `None` for the current + /// epoch. + /// + /// # Examples + /// + /// ```rust,no_run + /// use iota_sdk::IotaClientBuilder; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// let committee_info = iota.governance_api().get_committee_info(None).await?; + /// Ok(()) + /// } + /// ``` + pub async fn get_committee_info( + &self, + epoch: Option>, + ) -> IotaRpcResult { + Ok(self.api.http.get_committee_info(epoch).await?) + } + + /// Return the latest IOTA system state object on-chain, or an error upon + /// failure. + /// + /// Use this method to access system's information, such as the current + /// epoch, the protocol version, the reference gas price, the total + /// stake, active validators, and much more. See the + /// [IotaSystemStateSummary] for all the available fields. + pub async fn get_latest_iota_system_state(&self) -> IotaRpcResult { + Ok(self.api.http.get_latest_iota_system_state().await?) + } + + /// Return the reference gas price for the network, or an error upon + /// failure. + pub async fn get_reference_gas_price(&self) -> IotaRpcResult { + Ok(*self.api.http.get_reference_gas_price().await?) + } +} diff --git a/crates/iota-sdk/src/error.rs b/crates/iota-sdk/src/error.rs new file mode 100644 index 00000000000..a2f2ca3ed47 --- /dev/null +++ b/crates/iota-sdk/src/error.rs @@ -0,0 +1,40 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_types::{ + base_types::{IotaAddress, TransactionDigest}, + error::UserInputError, +}; +use thiserror::Error; + +pub use crate::json_rpc_error::Error as JsonRpcError; + +pub type IotaRpcResult = Result; + +#[derive(Error, Debug)] +pub enum Error { + #[error(transparent)] + RpcError(#[from] jsonrpsee::core::Error), + #[error(transparent)] + JsonRpcError(JsonRpcError), + #[error(transparent)] + BcsSerialisationError(#[from] bcs::Error), + #[error(transparent)] + UserInputError(#[from] UserInputError), + #[error("Subscription error : {0}")] + Subscription(String), + #[error("Failed to confirm tx status for {0:?} within {1} seconds.")] + FailToConfirmTransactionStatus(TransactionDigest, u64), + #[error("Data error: {0}")] + DataError(String), + #[error( + "Client/Server api version mismatch, client api version : {client_version}, server api version : {server_version}" + )] + ServerVersionMismatch { + client_version: String, + server_version: String, + }, + #[error("Insufficient fund for address [{address}], requested amount: {amount}")] + InsufficientFund { address: IotaAddress, amount: u128 }, +} diff --git a/crates/iota-sdk/src/iota_client_config.rs b/crates/iota-sdk/src/iota_client_config.rs new file mode 100644 index 00000000000..b3d491f170c --- /dev/null +++ b/crates/iota-sdk/src/iota_client_config.rs @@ -0,0 +1,151 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt::{Display, Formatter, Write}; + +use anyhow::anyhow; +use iota_config::Config; +use iota_keys::keystore::{AccountKeystore, Keystore}; +use iota_types::base_types::*; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +use crate::{ + IotaClient, IotaClientBuilder, IOTA_DEVNET_URL, IOTA_LOCAL_NETWORK_URL, IOTA_TESTNET_URL, +}; + +#[serde_as] +#[derive(Serialize, Deserialize)] +pub struct IotaClientConfig { + pub keystore: Keystore, + pub envs: Vec, + pub active_env: Option, + pub active_address: Option, +} + +impl IotaClientConfig { + pub fn new(keystore: Keystore) -> Self { + IotaClientConfig { + keystore, + envs: vec![], + active_env: None, + active_address: None, + } + } + + pub fn get_env(&self, alias: &Option) -> Option<&IotaEnv> { + if let Some(alias) = alias { + self.envs.iter().find(|env| &env.alias == alias) + } else { + self.envs.first() + } + } + + pub fn get_active_env(&self) -> Result<&IotaEnv, anyhow::Error> { + self.get_env(&self.active_env).ok_or_else(|| { + anyhow!( + "Environment configuration not found for env [{}]", + self.active_env.as_deref().unwrap_or("None") + ) + }) + } + + pub fn add_env(&mut self, env: IotaEnv) { + if !self + .envs + .iter() + .any(|other_env| other_env.alias == env.alias) + { + self.envs.push(env) + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct IotaEnv { + pub alias: String, + pub rpc: String, + pub ws: Option, +} + +impl IotaEnv { + pub async fn create_rpc_client( + &self, + request_timeout: Option, + max_concurrent_requests: Option, + ) -> Result { + let mut builder = IotaClientBuilder::default(); + if let Some(request_timeout) = request_timeout { + builder = builder.request_timeout(request_timeout); + } + if let Some(ws_url) = &self.ws { + builder = builder.ws_url(ws_url); + } + + if let Some(max_concurrent_requests) = max_concurrent_requests { + builder = builder.max_concurrent_requests(max_concurrent_requests as usize); + } + Ok(builder.build(&self.rpc).await?) + } + + pub fn devnet() -> Self { + Self { + alias: "devnet".to_string(), + rpc: IOTA_DEVNET_URL.into(), + ws: None, + } + } + pub fn testnet() -> Self { + Self { + alias: "testnet".to_string(), + rpc: IOTA_TESTNET_URL.into(), + ws: None, + } + } + + pub fn localnet() -> Self { + Self { + alias: "local".to_string(), + rpc: IOTA_LOCAL_NETWORK_URL.into(), + ws: None, + } + } +} + +impl Display for IotaEnv { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let mut writer = String::new(); + writeln!(writer, "Active environment : {}", self.alias)?; + write!(writer, "RPC URL: {}", self.rpc)?; + if let Some(ws) = &self.ws { + writeln!(writer)?; + write!(writer, "Websocket URL: {ws}")?; + } + write!(f, "{}", writer) + } +} + +impl Config for IotaClientConfig {} + +impl Display for IotaClientConfig { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let mut writer = String::new(); + + writeln!( + writer, + "Managed addresses : {}", + self.keystore.addresses().len() + )?; + write!(writer, "Active address: ")?; + match self.active_address { + Some(r) => writeln!(writer, "{}", r)?, + None => writeln!(writer, "None")?, + }; + writeln!(writer, "{}", self.keystore)?; + if let Ok(env) = self.get_active_env() { + write!(writer, "{}", env)?; + } + write!(f, "{}", writer) + } +} diff --git a/crates/sui-sdk/src/json_rpc_error.rs b/crates/iota-sdk/src/json_rpc_error.rs similarity index 89% rename from crates/sui-sdk/src/json_rpc_error.rs rename to crates/iota-sdk/src/json_rpc_error.rs index 2861747440b..e6bdf3b549e 100644 --- a/crates/sui-sdk/src/json_rpc_error.rs +++ b/crates/iota-sdk/src/json_rpc_error.rs @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +pub use iota_json_rpc_api::{TRANSACTION_EXECUTION_CLIENT_ERROR_CODE, TRANSIENT_ERROR_CODE}; use jsonrpsee::types::{error::UNKNOWN_ERROR_CODE, ErrorObjectOwned}; -pub use sui_json_rpc_api::{TRANSACTION_EXECUTION_CLIENT_ERROR_CODE, TRANSIENT_ERROR_CODE}; use thiserror::Error; #[derive(Error, Debug, Clone)] pub struct Error { pub code: i32, pub message: String, - // TODO: as this SDK is specialized for the Sui JSON RPC implementation, we should define + // TODO: as this SDK is specialized for the Iota JSON RPC implementation, we should define // structured representation for the data field if applicable pub data: Option, } diff --git a/crates/iota-sdk/src/lib.rs b/crates/iota-sdk/src/lib.rs new file mode 100644 index 00000000000..61e7570fa13 --- /dev/null +++ b/crates/iota-sdk/src/lib.rs @@ -0,0 +1,577 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! The Iota Rust SDK +//! +//! It aims at providing a similar SDK functionality like the one existing for +//! [TypeScript](https://github.com/iotaledger/iota/tree/main/sdk/typescript/). +//! Iota Rust SDK builds on top of the [JSON RPC API](https://docs.iota.io/iota-jsonrpc) +//! and therefore many of the return types are the ones specified in +//! [iota_types]. +//! +//! The API is split in several parts corresponding to different functionalities +//! as following: +//! * [CoinReadApi] - provides read-only functions to work with the coins +//! * [EventApi] - provides event related functions functions to +//! * [GovernanceApi] - provides functionality related to staking +//! * [QuorumDriverApi] - provides functionality to execute a transaction +//! block and submit it to the fullnode(s) +//! * [ReadApi] - provides functions for retrieving data about different +//! objects and transactions +//! * TransactionBuilder - +//! provides functions for building transactions +//! +//! # Usage +//! The main way to interact with the API is through the [IotaClientBuilder], +//! which returns a [IotaClient] object from which the user can access the +//! various APIs. +//! +//! ## Getting Started +//! Add the Rust SDK to the project by running `cargo add iota-sdk` in the root +//! folder of your Rust project. +//! +//! The main building block for the Iota Rust SDK is the [IotaClientBuilder], +//! which provides a simple and straightforward way of connecting to a Iota +//! network and having access to the different available APIs. +//! +//! A simple example that connects to a running Iota local network, +//! the Iota devnet, and the Iota testnet is shown below. +//! To successfully run this program, make sure to spin up a local +//! network with a local validator, a fullnode, and a faucet server +//! (see [here](https://github.com/stefan-mysten/iota/tree/rust_sdk_api_examples/crates/iota-sdk/examples#preqrequisites) for more information). +//! +//! ```rust,no_run +//! use iota_sdk::IotaClientBuilder; +//! +//! #[tokio::main] +//! async fn main() -> Result<(), anyhow::Error> { +//! let iota = IotaClientBuilder::default() +//! .build("http://127.0.0.1:9000") // provide the Iota network URL +//! .await?; +//! println!("Iota local network version: {:?}", iota.api_version()); +//! +//! // local Iota network, same result as above except using the dedicated function +//! let iota_local = IotaClientBuilder::default().build_localnet().await?; +//! println!("Iota local network version: {:?}", iota_local.api_version()); +//! +//! // Iota devnet running at `https://fullnode.devnet.io:443` +//! let iota_devnet = IotaClientBuilder::default().build_devnet().await?; +//! println!("Iota devnet version: {:?}", iota_devnet.api_version()); +//! +//! // Iota testnet running at `https://testnet.devnet.io:443` +//! let iota_testnet = IotaClientBuilder::default().build_testnet().await?; +//! println!("Iota testnet version: {:?}", iota_testnet.api_version()); +//! Ok(()) +//! } +//! ``` +//! +//! ## Examples +//! +//! For detailed examples, please check the APIs docs and the examples folder +//! in the [main repository](https://github.com/iotaledger/iota/tree/main/crates/iota-sdk/examples). + +use std::{ + fmt::{Debug, Formatter}, + sync::Arc, + time::Duration, +}; + +use async_trait::async_trait; +pub use iota_json as json; +use iota_json_rpc_api::{ + CLIENT_SDK_TYPE_HEADER, CLIENT_SDK_VERSION_HEADER, CLIENT_TARGET_API_VERSION_HEADER, +}; +pub use iota_json_rpc_types as rpc_types; +use iota_json_rpc_types::{ + IotaObjectDataFilter, IotaObjectDataOptions, IotaObjectResponse, IotaObjectResponseQuery, + ObjectsPage, +}; +use iota_transaction_builder::{DataReader, TransactionBuilder}; +pub use iota_types as types; +use iota_types::base_types::{IotaAddress, ObjectID, ObjectInfo}; +use jsonrpsee::{ + core::client::ClientT, + http_client::{HeaderMap, HeaderValue, HttpClient, HttpClientBuilder}, + rpc_params, + ws_client::{WsClient, WsClientBuilder}, +}; +use move_core_types::language_storage::StructTag; +use serde_json::Value; + +use crate::{ + apis::{CoinReadApi, EventApi, GovernanceApi, QuorumDriverApi, ReadApi}, + error::{Error, IotaRpcResult}, +}; + +pub mod apis; +pub mod error; +pub mod iota_client_config; +pub mod json_rpc_error; +pub mod wallet_context; + +pub const IOTA_COIN_TYPE: &str = "0x2::iota::IOTA"; +pub const IOTA_LOCAL_NETWORK_URL: &str = "http://127.0.0.1:9000"; +pub const IOTA_LOCAL_NETWORK_GAS_URL: &str = "http://127.0.0.1:5003/gas"; +pub const IOTA_DEVNET_URL: &str = "https://fullnode.devnet.iota.io:443"; +pub const IOTA_TESTNET_URL: &str = "https://fullnode.testnet.iota.io:443"; + +/// A Iota client builder for connecting to the Iota network +/// +/// By default the `maximum concurrent requests` is set to 256 and +/// the `request timeout` is set to 60 seconds. These can be adjusted using the +/// `max_concurrent_requests` function, and the `request_timeout` function. +/// If you use the WebSocket, consider setting the `ws_ping_interval` field to a +/// value of your choice to prevent the inactive WS subscription being +/// disconnected due to proxy timeout. +/// +/// # Examples +/// +/// ```rust,no_run +/// use iota_sdk::IotaClientBuilder; +/// #[tokio::main] +/// async fn main() -> Result<(), anyhow::Error> { +/// let iota = IotaClientBuilder::default() +/// .build("http://127.0.0.1:9000") +/// .await?; +/// +/// println!("Iota local network version: {:?}", iota.api_version()); +/// Ok(()) +/// } +/// ``` +pub struct IotaClientBuilder { + request_timeout: Duration, + max_concurrent_requests: usize, + ws_url: Option, + ws_ping_interval: Option, +} + +impl Default for IotaClientBuilder { + fn default() -> Self { + Self { + request_timeout: Duration::from_secs(60), + max_concurrent_requests: 256, + ws_url: None, + ws_ping_interval: None, + } + } +} + +impl IotaClientBuilder { + /// Set the request timeout to the specified duration + pub fn request_timeout(mut self, request_timeout: Duration) -> Self { + self.request_timeout = request_timeout; + self + } + + /// Set the max concurrent requests allowed + pub fn max_concurrent_requests(mut self, max_concurrent_requests: usize) -> Self { + self.max_concurrent_requests = max_concurrent_requests; + self + } + + /// Set the WebSocket URL for the Iota network + pub fn ws_url(mut self, url: impl AsRef) -> Self { + self.ws_url = Some(url.as_ref().to_string()); + self + } + + /// Set the WebSocket ping interval + pub fn ws_ping_interval(mut self, duration: Duration) -> Self { + self.ws_ping_interval = Some(duration); + self + } + + /// Returns a [IotaClient] object connected to the Iota network running at + /// the URI provided. + /// + /// # Examples + /// + /// ```rust,no_run + /// use iota_sdk::IotaClientBuilder; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default() + /// .build("http://127.0.0.1:9000") + /// .await?; + /// + /// println!("Iota local version: {:?}", iota.api_version()); + /// Ok(()) + /// } + /// ``` + pub async fn build(self, http: impl AsRef) -> IotaRpcResult { + let client_version = env!("CARGO_PKG_VERSION"); + let mut headers = HeaderMap::new(); + headers.insert( + CLIENT_TARGET_API_VERSION_HEADER, + // in rust, the client version is the same as the target api version + HeaderValue::from_static(client_version), + ); + headers.insert( + CLIENT_SDK_VERSION_HEADER, + HeaderValue::from_static(client_version), + ); + headers.insert(CLIENT_SDK_TYPE_HEADER, HeaderValue::from_static("rust")); + + let ws = if let Some(url) = self.ws_url { + let mut builder = WsClientBuilder::default() + .max_request_body_size(2 << 30) + .max_concurrent_requests(self.max_concurrent_requests) + .set_headers(headers.clone()) + .request_timeout(self.request_timeout); + + if let Some(duration) = self.ws_ping_interval { + builder = builder.ping_interval(duration) + } + + Some(builder.build(url).await?) + } else { + None + }; + + let http = HttpClientBuilder::default() + .max_request_body_size(2 << 30) + .max_concurrent_requests(self.max_concurrent_requests) + .set_headers(headers.clone()) + .request_timeout(self.request_timeout) + .build(http)?; + + let info = Self::get_server_info(&http, &ws).await?; + + let rpc = RpcClient { http, ws, info }; + let api = Arc::new(rpc); + let read_api = Arc::new(ReadApi::new(api.clone())); + let quorum_driver_api = QuorumDriverApi::new(api.clone()); + let event_api = EventApi::new(api.clone()); + let transaction_builder = TransactionBuilder::new(read_api.clone()); + let coin_read_api = CoinReadApi::new(api.clone()); + let governance_api = GovernanceApi::new(api.clone()); + + Ok(IotaClient { + api, + transaction_builder, + read_api, + coin_read_api, + event_api, + quorum_driver_api, + governance_api, + }) + } + + /// Returns a [IotaClient] object that is ready to interact with the local + /// development network (by default it expects the Iota network to be + /// up and running at `127.0.0.1:9000`). + /// + /// For connecting to a custom URI, use the `build` function instead. + /// + /// # Examples + /// + /// ```rust,no_run + /// use iota_sdk::IotaClientBuilder; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_localnet().await?; + /// + /// println!("Iota local version: {:?}", iota.api_version()); + /// Ok(()) + /// } + /// ``` + pub async fn build_localnet(self) -> IotaRpcResult { + self.build(IOTA_LOCAL_NETWORK_URL).await + } + + /// Returns a [IotaClient] object that is ready to interact with the Iota + /// devnet. + /// + /// For connecting to a custom URI, use the `build` function instead.. + /// + /// # Examples + /// + /// ```rust,no_run + /// use iota_sdk::IotaClientBuilder; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_devnet().await?; + /// + /// println!("{:?}", iota.api_version()); + /// Ok(()) + /// } + /// ``` + pub async fn build_devnet(self) -> IotaRpcResult { + self.build(IOTA_DEVNET_URL).await + } + + /// Returns a [IotaClient] object that is ready to interact with the Iota + /// testnet. + /// + /// For connecting to a custom URI, use the `build` function instead. + /// + /// # Examples + /// + /// ```rust,no_run + /// use iota_sdk::IotaClientBuilder; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), anyhow::Error> { + /// let iota = IotaClientBuilder::default().build_testnet().await?; + /// + /// println!("{:?}", iota.api_version()); + /// Ok(()) + /// } + /// ``` + pub async fn build_testnet(self) -> IotaRpcResult { + self.build(IOTA_TESTNET_URL).await + } + + /// Return the server information as a `ServerInfo` structure. + /// + /// Fails with an error if it cannot call the RPC discover. + async fn get_server_info( + http: &HttpClient, + ws: &Option, + ) -> Result { + let rpc_spec: Value = http.request("rpc.discover", rpc_params![]).await?; + let version = rpc_spec + .pointer("/info/version") + .and_then(|v| v.as_str()) + .ok_or_else(|| { + Error::DataError("Fail parsing server version from rpc.discover endpoint.".into()) + })?; + let rpc_methods = Self::parse_methods(&rpc_spec)?; + + let subscriptions = if let Some(ws) = ws { + let rpc_spec: Value = ws.request("rpc.discover", rpc_params![]).await?; + Self::parse_methods(&rpc_spec)? + } else { + Vec::new() + }; + Ok(ServerInfo { + rpc_methods, + subscriptions, + version: version.to_string(), + }) + } + + fn parse_methods(server_spec: &Value) -> Result, Error> { + let methods = server_spec + .pointer("/methods") + .and_then(|methods| methods.as_array()) + .ok_or_else(|| { + Error::DataError( + "Fail parsing server information from rpc.discover endpoint.".into(), + ) + })?; + + Ok(methods + .iter() + .flat_map(|method| method["name"].as_str()) + .map(|s| s.into()) + .collect()) + } +} + +/// IotaClient is the basic type that provides all the necessary abstractions +/// for interacting with the Iota network. +/// +/// # Usage +/// +/// Use [IotaClientBuilder] to build a [IotaClient]. +/// +/// # Examples +/// +/// ```rust,no_run +/// use std::str::FromStr; +/// +/// use iota_sdk::{types::base_types::IotaAddress, IotaClientBuilder}; +/// +/// #[tokio::main] +/// async fn main() -> Result<(), anyhow::Error> { +/// let iota = IotaClientBuilder::default() +/// .build("http://127.0.0.1:9000") +/// .await?; +/// +/// println!("{:?}", iota.available_rpc_methods()); +/// println!("{:?}", iota.available_subscriptions()); +/// println!("{:?}", iota.api_version()); +/// +/// let address = IotaAddress::from_str("0x0000....0000")?; +/// let owned_objects = iota +/// .read_api() +/// .get_owned_objects(address, None, None, None) +/// .await?; +/// +/// println!("{:?}", owned_objects); +/// +/// Ok(()) +/// } +/// ``` +#[derive(Clone)] +pub struct IotaClient { + api: Arc, + transaction_builder: TransactionBuilder, + read_api: Arc, + coin_read_api: CoinReadApi, + event_api: EventApi, + quorum_driver_api: QuorumDriverApi, + governance_api: GovernanceApi, +} + +pub(crate) struct RpcClient { + http: HttpClient, + ws: Option, + info: ServerInfo, +} + +impl Debug for RpcClient { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "RPC client. Http: {:?}, Websocket: {:?}", + self.http, self.ws + ) + } +} + +/// ServerInfo contains all the useful information regarding the API version, +/// the available RPC calls, and subscriptions. +struct ServerInfo { + rpc_methods: Vec, + subscriptions: Vec, + version: String, +} + +impl IotaClient { + /// Returns a list of RPC methods supported by the node the client is + /// connected to. + pub fn available_rpc_methods(&self) -> &Vec { + &self.api.info.rpc_methods + } + + /// Returns a list of streaming/subscription APIs supported by the node the + /// client is connected to. + pub fn available_subscriptions(&self) -> &Vec { + &self.api.info.subscriptions + } + + /// Returns the API version information as a string. + /// + /// The format of this string is `..`, e.g., `1.6.0`, + /// and it is retrieved from the OpenRPC specification via the discover + /// service method. + pub fn api_version(&self) -> &str { + &self.api.info.version + } + + /// Verifies if the API version matches the server version and returns an + /// error if they do not match. + pub fn check_api_version(&self) -> IotaRpcResult<()> { + let server_version = self.api_version(); + let client_version = env!("CARGO_PKG_VERSION"); + if server_version != client_version { + return Err(Error::ServerVersionMismatch { + client_version: client_version.to_string(), + server_version: server_version.to_string(), + }); + }; + Ok(()) + } + + /// Returns a reference to the coin read API. + pub fn coin_read_api(&self) -> &CoinReadApi { + &self.coin_read_api + } + + /// Returns a reference to the event API. + pub fn event_api(&self) -> &EventApi { + &self.event_api + } + + /// Returns a reference to the governance API. + pub fn governance_api(&self) -> &GovernanceApi { + &self.governance_api + } + + /// Returns a reference to the quorum driver API. + pub fn quorum_driver_api(&self) -> &QuorumDriverApi { + &self.quorum_driver_api + } + + /// Returns a reference to the read API. + pub fn read_api(&self) -> &ReadApi { + &self.read_api + } + + /// Returns a reference to the transaction builder API. + pub fn transaction_builder(&self) -> &TransactionBuilder { + &self.transaction_builder + } + + /// Returns a reference to the underlying http client. + pub fn http(&self) -> &HttpClient { + &self.api.http + } + + /// Returns a reference to the underlying WebSocket client, if any. + pub fn ws(&self) -> Option<&WsClient> { + self.api.ws.as_ref() + } +} + +#[async_trait] +impl DataReader for ReadApi { + async fn get_owned_objects( + &self, + address: IotaAddress, + object_type: StructTag, + ) -> Result, anyhow::Error> { + let mut result = vec![]; + let query = Some(IotaObjectResponseQuery { + filter: Some(IotaObjectDataFilter::StructType(object_type)), + options: Some( + IotaObjectDataOptions::new() + .with_previous_transaction() + .with_type() + .with_owner(), + ), + }); + + let mut has_next = true; + let mut cursor = None; + + while has_next { + let ObjectsPage { + data, + next_cursor, + has_next_page, + } = self + .get_owned_objects(address, query.clone(), cursor, None) + .await?; + result.extend( + data.iter() + .map(|r| r.clone().try_into()) + .collect::, _>>()?, + ); + cursor = next_cursor; + has_next = has_next_page; + } + Ok(result) + } + + async fn get_object_with_options( + &self, + object_id: ObjectID, + options: IotaObjectDataOptions, + ) -> Result { + Ok(self.get_object_with_options(object_id, options).await?) + } + + /// Returns the reference gas price as a u64 or an error otherwise + async fn get_reference_gas_price(&self) -> Result { + Ok(self.get_reference_gas_price().await?) + } +} diff --git a/crates/sui-sdk/src/wallet_context.rs b/crates/iota-sdk/src/wallet_context.rs similarity index 78% rename from crates/sui-sdk/src/wallet_context.rs rename to crates/iota-sdk/src/wallet_context.rs index 26c028f8f04..35eb62ed9f9 100644 --- a/crates/sui-sdk/src/wallet_context.rs +++ b/crates/iota-sdk/src/wallet_context.rs @@ -1,31 +1,32 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeSet, path::Path, sync::Arc}; use anyhow::anyhow; use colored::Colorize; -use shared_crypto::intent::Intent; -use sui_config::{Config, PersistedConfig}; -use sui_json_rpc_types::{ - SuiObjectData, SuiObjectDataFilter, SuiObjectDataOptions, SuiObjectResponse, - SuiObjectResponseQuery, SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, +use iota_config::{Config, PersistedConfig}; +use iota_json_rpc_types::{ + IotaObjectData, IotaObjectDataFilter, IotaObjectDataOptions, IotaObjectResponse, + IotaObjectResponseQuery, IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, }; -use sui_keys::keystore::AccountKeystore; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, +use iota_keys::keystore::AccountKeystore; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef}, gas_coin::GasCoin, transaction::{Transaction, TransactionData, TransactionDataAPI}, }; +use shared_crypto::intent::Intent; use tokio::sync::RwLock; use tracing::warn; -use crate::{sui_client_config::SuiClientConfig, SuiClient}; +use crate::{iota_client_config::IotaClientConfig, IotaClient}; pub struct WalletContext { - pub config: PersistedConfig, + pub config: PersistedConfig, request_timeout: Option, - client: Arc>>, + client: Arc>>, max_concurrent_requests: Option, } @@ -35,7 +36,7 @@ impl WalletContext { request_timeout: Option, max_concurrent_requests: Option, ) -> Result { - let config: SuiClientConfig = PersistedConfig::read(config_path).map_err(|err| { + let config: IotaClientConfig = PersistedConfig::read(config_path).map_err(|err| { anyhow!( "Cannot open wallet config file at {:?}. Err: {err}", config_path @@ -52,11 +53,11 @@ impl WalletContext { Ok(context) } - pub fn get_addresses(&self) -> Vec { + pub fn get_addresses(&self) -> Vec { self.config.keystore.addresses() } - pub async fn get_client(&self) -> Result { + pub async fn get_client(&self) -> Result { let read = self.client.read().await; Ok(if let Some(client) = read.as_ref() { @@ -77,7 +78,7 @@ impl WalletContext { } // TODO: Ger rid of mut - pub fn active_address(&mut self) -> Result { + pub fn active_address(&mut self) -> Result { if self.config.keystore.addresses().is_empty() { return Err(anyhow!( "No managed addresses. Create new address with `new-address` command." @@ -100,7 +101,7 @@ impl WalletContext { let client = self.get_client().await?; Ok(client .read_api() - .get_object_with_options(object_id, SuiObjectDataOptions::new()) + .get_object_with_options(object_id, IotaObjectDataOptions::new()) .await? .into_object()? .object_ref()) @@ -109,20 +110,20 @@ impl WalletContext { /// Get all the gas objects (and conveniently, gas amounts) for the address pub async fn gas_objects( &self, - address: SuiAddress, - ) -> Result, anyhow::Error> { + address: IotaAddress, + ) -> Result, anyhow::Error> { let client = self.get_client().await?; - let mut objects: Vec = Vec::new(); + let mut objects: Vec = Vec::new(); let mut cursor = None; loop { let response = client .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new( - Some(SuiObjectDataFilter::StructType(GasCoin::type_())), - Some(SuiObjectDataOptions::full_content()), + Some(IotaObjectResponseQuery::new( + Some(IotaObjectDataFilter::StructType(GasCoin::type_())), + Some(IotaObjectDataOptions::full_content()), )), cursor, None, @@ -152,11 +153,11 @@ impl WalletContext { Ok(values_objects) } - pub async fn get_object_owner(&self, id: &ObjectID) -> Result { + pub async fn get_object_owner(&self, id: &ObjectID) -> Result { let client = self.get_client().await?; let object = client .read_api() - .get_object_with_options(*id, SuiObjectDataOptions::new().with_owner()) + .get_object_with_options(*id, IotaObjectDataOptions::new().with_owner()) .await? .into_object()?; Ok(object @@ -168,7 +169,7 @@ impl WalletContext { pub async fn try_get_object_owner( &self, id: &Option, - ) -> Result, anyhow::Error> { + ) -> Result, anyhow::Error> { if let Some(id) = id { Ok(Some(self.get_object_owner(id).await?)) } else { @@ -179,30 +180,30 @@ impl WalletContext { /// Find a gas object which fits the budget pub async fn gas_for_owner_budget( &self, - address: SuiAddress, + address: IotaAddress, budget: u64, forbidden_gas_objects: BTreeSet, - ) -> Result<(u64, SuiObjectData), anyhow::Error> { + ) -> Result<(u64, IotaObjectData), anyhow::Error> { for o in self.gas_objects(address).await.unwrap() { if o.0 >= budget && !forbidden_gas_objects.contains(&o.1.object_id) { return Ok((o.0, o.1)); } } Err(anyhow!( - "No non-argument gas objects found for this address with value >= budget {budget}. Run sui client gas to check for gas objects." + "No non-argument gas objects found for this address with value >= budget {budget}. Run iota client gas to check for gas objects." )) } pub async fn get_all_gas_objects_owned_by_address( &self, - address: SuiAddress, + address: IotaAddress, ) -> anyhow::Result> { self.get_gas_objects_owned_by_address(address, None).await } pub async fn get_gas_objects_owned_by_address( &self, - address: SuiAddress, + address: IotaAddress, limit: Option, ) -> anyhow::Result> { let client = self.get_client().await?; @@ -210,9 +211,9 @@ impl WalletContext { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new( - Some(SuiObjectDataFilter::StructType(GasCoin::type_())), - Some(SuiObjectDataOptions::full_content()), + Some(IotaObjectResponseQuery::new( + Some(IotaObjectDataFilter::StructType(GasCoin::type_())), + Some(IotaObjectDataOptions::full_content()), )), None, limit, @@ -230,7 +231,7 @@ impl WalletContext { /// read api. pub async fn get_one_gas_object_owned_by_address( &self, - address: SuiAddress, + address: IotaAddress, ) -> anyhow::Result> { Ok(self .get_gas_objects_owned_by_address(address, Some(1)) @@ -239,7 +240,7 @@ impl WalletContext { } /// Returns one address and all gas objects owned by that address. - pub async fn get_one_account(&self) -> anyhow::Result<(SuiAddress, Vec)> { + pub async fn get_one_account(&self) -> anyhow::Result<(IotaAddress, Vec)> { let address = self.get_addresses().pop().unwrap(); Ok(( address, @@ -248,7 +249,7 @@ impl WalletContext { } /// Return a gas object owned by an arbitrary address managed by the wallet. - pub async fn get_one_gas_object(&self) -> anyhow::Result> { + pub async fn get_one_gas_object(&self) -> anyhow::Result> { for address in self.get_addresses() { if let Some(gas_object) = self.get_one_gas_object_owned_by_address(address).await? { return Ok(Some((address, gas_object))); @@ -261,7 +262,7 @@ impl WalletContext { /// gas objects. pub async fn get_all_accounts_and_gas_objects( &self, - ) -> anyhow::Result)>> { + ) -> anyhow::Result)>> { let mut result = vec![]; for address in self.get_addresses() { let objects = self @@ -286,7 +287,7 @@ impl WalletContext { let sig = self .config .keystore - .sign_secure(&data.sender(), data, Intent::sui_transaction()) + .sign_secure(&data.sender(), data, Intent::iota_transaction()) .unwrap(); // TODO: To support sponsored transaction, we should also look at the gas owner. Transaction::from_data(data.clone(), vec![sig]) @@ -298,7 +299,7 @@ impl WalletContext { pub async fn execute_transaction_must_succeed( &self, tx: Transaction, - ) -> SuiTransactionBlockResponse { + ) -> IotaTransactionBlockResponse { tracing::debug!("Executing transaction: {:?}", tx); let response = self.execute_transaction_may_fail(tx).await.unwrap(); assert!( @@ -316,19 +317,19 @@ impl WalletContext { pub async fn execute_transaction_may_fail( &self, tx: Transaction, - ) -> anyhow::Result { + ) -> anyhow::Result { let client = self.get_client().await?; Ok(client .quorum_driver_api() .execute_transaction_block( tx, - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_effects() .with_input() .with_events() .with_object_changes() .with_balance_changes(), - Some(sui_types::quorum_driver_types::ExecuteTransactionRequestType::WaitForLocalExecution), + Some(iota_types::quorum_driver_types::ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?) } diff --git a/crates/iota-sdk/tests/tests.rs b/crates/iota-sdk/tests/tests.rs new file mode 100644 index 00000000000..4d6b8ddd9da --- /dev/null +++ b/crates/iota-sdk/tests/tests.rs @@ -0,0 +1,33 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use iota_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; +use iota_types::crypto::{Ed25519IotaSignature, IotaSignatureInner, SignatureScheme}; +use tempfile::TempDir; +#[test] +fn mnemonic_test() { + let temp_dir = TempDir::new().unwrap(); + let keystore_path = temp_dir.path().join("iota.keystore"); + let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + let (address, phrase, scheme) = keystore + .generate_and_add_new_key(SignatureScheme::ED25519, None, None, None) + .unwrap(); + + let keystore_path_2 = temp_dir.path().join("iota2.keystore"); + let mut keystore2 = Keystore::from(FileBasedKeystore::new(&keystore_path_2).unwrap()); + let imported_address = keystore2 + .import_from_mnemonic(&phrase, SignatureScheme::ED25519, None) + .unwrap(); + assert_eq!(scheme.flag(), Ed25519IotaSignature::SCHEME.flag()); + assert_eq!(address, imported_address); +} + +#[test] +fn keystore_display_test() -> Result<(), anyhow::Error> { + let temp_dir = TempDir::new().unwrap(); + let keystore_path = temp_dir.path().join("iota.keystore"); + let keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); + assert!(keystore.to_string().contains("iota.keystore")); + assert!(!keystore.to_string().contains("keys:")); + Ok(()) +} diff --git a/crates/iota-simulator/Cargo.toml b/crates/iota-simulator/Cargo.toml new file mode 100644 index 00000000000..398c894965e --- /dev/null +++ b/crates/iota-simulator/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "iota-simulator" +version = "0.7.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +move-package.workspace = true + +iota-framework.workspace = true +iota-move-build.workspace = true +iota-types.workspace = true +tempfile.workspace = true +tracing.workspace = true +anemo.workspace = true +anemo-tower.workspace = true +narwhal-network.workspace = true +fastcrypto = { workspace = true, features = ["copy_key"] } +telemetry-subscribers.workspace = true +tower.workspace = true +lru.workspace = true +rand.workspace = true +serde.workspace = true +bcs.workspace = true + +[target.'cfg(msim)'.dependencies] +msim.workspace = true diff --git a/crates/iota-simulator/README.md b/crates/iota-simulator/README.md new file mode 100644 index 00000000000..457784b3a50 --- /dev/null +++ b/crates/iota-simulator/README.md @@ -0,0 +1,277 @@ + +# Iota Simulation Testing + +This document outlines what the simulator used by `cargo simtest` enables, how it works, how to write sim tests, +and outlines some future work. + +## What its for: + +Currently, the simulator: + +- Provides deterministic, randomized execution of an entire Iota network in a single process. +- Simulates network latency and packet loss as desired. + +This allows us to: + +- Run tests under adverse network conditions, including high latency, packet loss, and total partitions. +- Run many iterations of tests with different starting seeds, to attempt to expose rare bugs. +- Reproduce bugs easily, once found, by re-running the test with a given seed. + +## How it works: + +The code for the simulator itself lives in the https://github.com/MystenLabs/mysten-sim repository. +It has the following main components: + +1. A [runtime](https://github.com/MystenLabs/mysten-sim/blob/main/msim/src/sim/runtime/mod.rs) which provides: + - A "node" context for all running tasks. The node is a simulated machine, which can be killed, restarted, or paused. + - A randomized but deterministic executor. + - Simulated clock facilities, including timers, sleep(), etc. + - A global, seeded PRNG used to provide all random behavior throughout the simulator. + +1. A network simulator, which delivers network messages between nodes, and can inject latency and packet loss. + +1. An API-compatible replacement for tokio. + - Most facilities from `tokio::runtime` and `tokio::time` are delegated back to the simulator runtime. + - Custom implementations of the `tokio::net::Tcp*` structs are provided to interface with the network simulator. + - Most other pieces of tokio (e.g. `sync`) did not need to be re-implemented because they don't interface with the runtime or the network. These are simply re-exported as is. + - A minimal [fork of tokio](https://github.com/mystenmark/tokio-madsim-fork) is required in order to expose certain internals to the simulator. This fork has very few modifications, which were written to be easily rebaseable when new tokio releases come out. + +1. A library of interceptor functions which intercept various posix API calls in order to enforce determinism throughout the test. These include: + - `getrandom()`, `getentropy()` - intercepted and delegated to the simulator PRNG. + - Various [socket api calls](https://github.com/MystenLabs/mysten-sim/blob/main/msim/src/sim/net/mod.rs#L195), which intercept networking operations and route them through the network simulator. It was necessary to do this at a very low level because [Quinn](https://github.com/quinn-rs/quinn) does its UDP I/O via direct `libc::` calls rather than using `tokio::net::UdpSocket`. + - `mach_absolute_time()`, `clock_gettime()`: Intercepted to provide deterministic high-resolution timing behavior. + - TODO: `gettimeofday()`: We would like to intercept this to provide deterministic wall-clock operations (e.g. on dates, etc). However, intercepting this currently breaks RocksDB. + + This interception behavior is in effect only in threads that have explicitly enabled it, which generally includes the main test thread only. In other threads, the interceptors delegate the call to the system library implementation via `dlsym()`. See implementation [here](https://github.com/MystenLabs/mysten-sim/blob/main/msim/src/sim/intercept.rs#L34-L48). + +1. Procedural macros that replace `#[tokio::test]` and run test code inside a testing environment. These are `#[iota_test]` and `#[sim_test]` and are documented below. The test harness created by these macros initializes the simulator runtime with a starting seed, generates the simulator configuration, and runs the test inside a newly created thread. The test must be run in its own thread in order to provide each test case with fresh thread local storage. + + +## How to run sim tests + +First, you'll have to install the `simtest` sub-command by running: + + $ ./scripts/simtest/install.sh + +You can then run tests by doing: + + $ cargo simtest + +The simtest command calls `cargo nextest`, so you can add any valid `nextest` option to the command line. + +`cargo simtest` also reads the following environment variables: + +- `MSIM_TEST_SEED` - the random seed for the global PRNG. Must be a positive decimal integer that fits into a `u64`. The default value is `1`. + +- `MSIM_TEST_NUM` - the number of times to repeat each test. Each repetition of a test is done with a different random seed, starting from the value of `MSIM_TEST_SEED` for the first repetition. The next seed is computed using the following function: + + fn next_seed(seed: u64) -> u64 { + use rand::Rng; + rand::GlobalRng::new_with_seed(seed).gen::() + } + + This means that if you run these two commands: + + $ MSIM_TEST_SEED=1 MSIM_TEST_NUM=10 cargo simtest + $ MSIM_TEST_SEED=2 MSIM_TEST_NUM=10 cargo simtest + + No two iterations will have the same seed (with very high probability). + +- `MSIM_TEST_CHECK_DETERMINISM` - if set, the specified tests will be run twice, and the framework will verify that the test executes identically in both runs. (This check can also be done by defining a test case with: `#[sim_test(check_determinism)]`.). *Note: Many existing tests in iota do not pass this check, which runs the test case twice in the same process, although those same tests do execute identically if run twice in separate processes. This is a bug, is most likely due to tests sharing static storage or on-disk state, and will hopefully be fixed shortly.* + + +## How to write simulation tests: + +Simulation tests are declared in one of the following two ways: + + using iota_macros::*; + + #[iota_test] + async fn test1() { + // A test that will run using `#[tokio::test]` when run via `cargo nextest`, or + // else a simulator test when run via `cargo simtest`. + } + + #[sim_test] + async fn test2() { + // A test that will be ignored when run via `cargo nextest`, and only run + // via `cargo simtest`. + } + +The `#[sim_test]` proc macro also takes a number of arguments, described below. + +The easiest way to write tests that run in the simulation testing framework is to use [SwarmBuilder](https://github.com/iotaledger/iota/blob/main/crates/iota-swarm/src/memory/swarm.rs#L47) to start your validators. +This is most often called indirectly via `start_test_network` in the test-utils crate. +Swarm will create one simulator node (i.e. a simulated machine) per validator, and each validator will have its own unique IP address. + +If you use Swarm, you usually will not have to write any code that is aware of the fact that it is running in the simulator. +However, the fact that the validators are running on unique simulator nodes means you will be able to add network latency, packet loss, and partitions to your test later on. + +### `IotaNodeHandle` + +Swarm assumes a level of encapsulation that reflects what client code would actually experience in production. +In other words, the only way to communicate with the validators when using Swarm is via the network. +However, we have many tests that create validators and manipulate them more directly. +https://github.com/iotaledger/iota/blob/main/crates/iota/tests/checkpoints_tests.rs is a good example of this. + +In these tests, the test code is able to break the simulator abstraction and directly manipulate the state of remote validators. +Yet, the validators are still running on simulated nodes. +This can cause problems if the test code spawns a task on behalf of a remote validator. +The spawned task will appear to the simulator to be executing inside the client node rather than the validator node. +If that spawned task initiates a network connection, it will appear to originate from the client node rather than the validator node. + +To address this, most such test code launches validators via the `spawn_test_authorities` function in the `test-utils` carate, which returns `Vec` rather than `Vec`. +`IotaNodeHandle` hides the `IotaNode` from the test code. +It can only be accessed as follows: + + handle.with(|node| { + let state = node.state(); + do_stuff_to_state(state); + }); + +Or in the case of async code: + + handle.with_async(|node| async move { + let state = node.state(); + do_async_stuff_to_state(state).await; + }).await; + +(`with_mut` and `with_mut_async` are also available). + +`IotaNodeHandle` runs the provided callbacks/futures inside the context of the appropriate simulator node, so that network requests, spawned tasks, etc continue running in the correct context. + +Note that it is trivial to exfiltrate state from the remote node, e.g.: + + let node_state = handle.with(|node| { + node.state() + }); + + // Never do this! + spawn_task_on_state_in_client_node(node_state); + +It's not feasible to completely prevent this from happening - the API is just designed to make the correct thing as easy as possible. + +Also, the world will not end if you break this rule. You just might see confusing behavior in your tests. + +### The #[sim_test] macro + +`#[sim_test]` currently accepts two arguments: + +- `config = "config_expr"` - This argument accepts a string which will be evaluated as an expression that returns the configuration for the test. Generally, you should make this a function call, and then define the function to return the config. The function must return a type that can implements `Into` - the most common choice is `SimConfig`, but `Vec` and `Vec<(usize /* repeat count */, SimConfig)>` are also supported by default. See https://github.com/MystenLabs/mysten-sim/blob/main/msim/src/sim/config.rs for the `TestConfig` implementation. + +- `check_determinism` - If set, the framework will run the test twice, and verify that it executes identically each time. (It does this by keeping a log which contains an entry for every call to the PRNG. Each entry contains a hash of the value yielded by the PRNG at that point + the current time.). Tests with `check_determinism` are usually for testing the framework itself, so you probably won't need to use this. + +### Configuring the network: + +Network latency and packet loss can be configured using [SimConfig](https://github.com/MystenLabs/mysten-sim/blob/main/msim/src/sim/config.rs#L8), which is re-exported from this crate as `iota_simulator::config::SimConfig`. + +To configure a test, you write: + + fn my_config() -> SimConfig { + ... + } + + #[sim_test(config = "my_config()")] + async fn test_case() { + ... + } + +A vector a SimConfigs can also be returned, in order to run the same test under multiple configurations. +For instance, you might do: + + fn test_scenarios -> Vec { + vec![ + fast_network_config(), // low latency + slow_network_config(), // high latency + lossy_network_config(), // packet loss + ] + } + + #[sim_test(config = "test_scenarios()")] + async fn test_case() { + ... + } + +Documentation of network configuration is not finished yet, but reading the code for the [NetworkConfig](https://github.com/MystenLabs/mysten-sim/blob/main/msim/src/sim/net/config.rs#L221) should be very instructive. + +There is a small but growing library of functions for building network configs in [iota_simulator::configs](https://github.com/iotaledger/iota/blob/main/crates/iota-simulator/src/lib.rs). + +There are also some examples of network configuration at https://github.com/iotaledger/iota/blob/main/crates/iota-benchmark/tests/simtest.rs#L52. + +### The `nondeterministic!` macro + +Occasionally a test needs an escape hatch from its deterministic environment. +The most common such case is when creating a temporary directory. +For these situations, the `nondeterministic!` macro is provided. +It can be used to evaluate any expression in another thread, in which the system interceptor functions (e.g. `getrandom()`) are disabled. +For example: + + let path = dir.join(format!("DB_{:?}", nondeterministic!(ObjectID::random()))); + +Without the `nondeterministic!` macro, this code could generate the same path in two different tests (each test is started with the same seed). + +## Flaky tests + +One of the benefits of deterministic simulation is that it eliminates flaky tests. +However, that is a half truth: The simulator framework tries to guarantee that a given test binary will produce the exact same behavior when run twice with the same seed. +This means that in general, tests shouldn't be flaky in the usual sense. +If they fail once, retrying them won't help. +Similarly, if they pass once (at a given commit), they should never fail at that commit. + +However, tests may be "intrinsically flaky" - for instance they may be dependent on precise timing. +As a reductio, you could imagine a test that simply samples a random number at some point, and fails if is greater than a threshold. +This test will either fail or pass repeatably when run with the same seed at the same commit. +However, that test is obviously flaky by its nature. + +Further, the simulator framework is unavoidably very susceptible to butterfly effects - almost any event (e.g. spawning a new task, sending data over the network, sampling a random number) will cause every event that comes later to play out differently. +Network messages will have different delays, tasks will execute in a different order, random samples will change. + +This means that almost any code change could cause a totally unrelated flaky test to suddenly start failing due to butterfly effects. +In such cases, the blame goes to the test that started failing - it was clearly passing by chance only. +The good news is that because the system is deterministic, the flaky test can usually be debugged quickly. + +### How to fix a flaky test + +If you find a flaky test, here are some tips on how to start. +First, ascertain that the test fails repeatedly when run in isolation, e.g.: + + $ cargo simtest my_flaky_test + +If it fails when run *en masse*, but passes when run individually (or vice versa) then there may be a test isolation failure. +Test isolation failures are often due to filesystem or static memory access, or may be simulator bugs. + +Assuming that the test does fail repeatably in isolation, you can try the test with several different seeds: + + + $ MSIM_TEST_SEED=XXX cargo simtest my_flaky_test + +And see how often if passes/fails. +Note which seeds cause the test to pass, and which cause it to fail - it may be helpful to compare log output from passing and failing runs to see how they differ, and between pairs of passing or failing runs to see how they are alike. + +**Do not forget that the test may not be to blame!** +Your code may be just be buggy! +In other words, flaky code may also cause flaky tests. + +It's impossible to list every possible cause of flakiness in a document, but the best place to start looking is at anything timing related, especially hard-coded delays in the test. +n t +Once you have found the bug or the source of the flakiness, you can validator your fix by running: + + $ MSIM_TEST_NUM=20 cargo simtest my_flaky_test + +This will run your test 20 times with different seeds. +Feel free to increase this number - theoretically working code should work no matter how many times you repeat the test, but you probably don't have time for more than a few dozen iterations. + +(Soon, we will add a nightly workflow that runs all tests with a high iteration count in order to pro-actively find bugs and flaky tests.) + +## Reproducing failures + +The point of having a deterministic execution environment for tests is that failures can be reproduced easily once found. + +When tests fail, they print out a random seed that you can use to reproduce the failure. +In normal CI runs, this seed should always be `1` (the default value). +However, when a test is run with a higher iteration count, the reported seed will be some large random number. +Ideally you should be able to immediately reproduce the failure by running a single iteration of the test with the given seed. + +*Currently, this feature is in progress due to some isolation failures in the simulator framework that I am trying to track down.* + +**Linux vs Mac**: There is one big caveat here, which is that we don't have identical execution across different platforms. This may be impossible to achieve due to `#[cfg(target_os = xxx)]` attributes in our dependencies. Therefore, even once test re-execution is fully supported, it may be necessary to use linux (perhaps via a local docker container) to reproduce failures found on our CI machines. diff --git a/crates/iota-simulator/src/lib.rs b/crates/iota-simulator/src/lib.rs new file mode 100644 index 00000000000..b1f6eb60862 --- /dev/null +++ b/crates/iota-simulator/src/lib.rs @@ -0,0 +1,201 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(msim)] +use std::hash::Hasher; +use std::sync::atomic::{AtomicUsize, Ordering}; + +// Re-export things used by iota-macros +pub use ::rand as rand_crate; +pub use anemo; +pub use anemo_tower; +pub use fastcrypto; +pub use iota_framework; +pub use iota_move_build; +pub use iota_types; +pub use lru; +pub use move_package; +#[cfg(msim)] +pub use msim::*; +pub use narwhal_network; +pub use telemetry_subscribers; +pub use tempfile; +pub use tower; + +#[cfg(msim)] +pub mod configs { + use std::{collections::HashMap, ops::Range, time::Duration}; + + use msim::*; + use tracing::info; + + fn ms_to_dur(range: Range) -> Range { + Duration::from_millis(range.start)..Duration::from_millis(range.end) + } + + /// A network with constant uniform latency. + pub fn constant_latency_ms(latency: u64) -> SimConfig { + uniform_latency_ms(latency..(latency + 1)) + } + + /// A network with latency sampled uniformly from a range. + pub fn uniform_latency_ms(range: Range) -> SimConfig { + let range = ms_to_dur(range); + SimConfig { + net: NetworkConfig { + latency: LatencyConfig { + default_latency: LatencyDistribution::uniform(range), + ..Default::default() + }, + ..Default::default() + }, + } + } + + /// A network with bimodal latency. + pub fn bimodal_latency_ms( + // The typical latency. + baseline: Range, + // The exceptional latency. + degraded: Range, + // The frequency (from 0.0 to 1.0) with which the exceptional distribution is sampled. + degraded_freq: f64, + ) -> SimConfig { + let baseline = ms_to_dur(baseline); + let degraded = ms_to_dur(degraded); + SimConfig { + net: NetworkConfig { + latency: LatencyConfig { + default_latency: LatencyDistribution::bimodal( + baseline, + degraded, + degraded_freq, + ), + ..Default::default() + }, + ..Default::default() + }, + } + } + + /// Select from among a number of configs using the IOTA_SIM_CONFIG env var. + pub fn env_config( + // Config to use when IOTA_SIM_CONFIG is not set. + default: SimConfig, + // List of (&str, SimConfig) pairs - the SimConfig associated with the value + // of the IOTA_SIM_CONFIG var is chosen. + env_configs: impl IntoIterator, + ) -> SimConfig { + let mut env_configs = HashMap::<&'static str, SimConfig>::from_iter(env_configs); + if let Some(env) = std::env::var("IOTA_SIM_CONFIG").ok() { + if let Some(cfg) = env_configs.remove(env.as_str()) { + info!("Using test config for IOTA_SIM_CONFIG={}", env); + cfg + } else { + panic!( + "No config found for IOTA_SIM_CONFIG={}. Available configs are: {:?}", + env, + env_configs.keys() + ); + } + } else { + info!("Using default test config"); + default + } + } +} + +thread_local! { + static NODE_COUNT: AtomicUsize = AtomicUsize::new(0); +} + +pub struct NodeLeakDetector(()); + +impl NodeLeakDetector { + pub fn new() -> Self { + NODE_COUNT.with(|c| c.fetch_add(1, Ordering::SeqCst)); + Self(()) + } + + pub fn get_current_node_count() -> usize { + NODE_COUNT.with(|c| c.load(Ordering::SeqCst)) + } +} + +impl Default for NodeLeakDetector { + fn default() -> Self { + Self::new() + } +} + +impl Drop for NodeLeakDetector { + fn drop(&mut self) { + NODE_COUNT.with(|c| c.fetch_sub(1, Ordering::SeqCst)); + } +} + +#[cfg(not(msim))] +#[macro_export] +macro_rules! return_if_killed { + () => {}; +} + +#[cfg(msim)] +pub fn current_simnode_id() -> msim::task::NodeId { + msim::runtime::NodeHandle::current().id() +} + +#[cfg(msim)] +pub mod random { + use std::{cell::RefCell, collections::HashSet, hash::Hash}; + + use rand_crate::{rngs::SmallRng, thread_rng, Rng, SeedableRng}; + use serde::Serialize; + + use super::*; + + /// Given a value, produce a random probability using the value as a seed, + /// with an additional seed that is constant only for the current test + /// thread. + pub fn deterministic_probability(value: T, chance: f32) -> bool { + thread_local! { + // a random seed that is shared by the whole test process, so that equal `value` + // inputs produce different outputs when the test seed changes + static SEED: u64 = thread_rng().gen(); + } + + chance + > SEED.with(|seed| { + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + seed.hash(&mut hasher); + value.hash(&mut hasher); + let mut rng = SmallRng::seed_from_u64(hasher.finish()); + rng.gen_range(0.0..1.0) + }) + } + + /// Like deterministic_probability, but only returns true once for each + /// unique value. May eventually consume all memory if there are a large + /// number of unique, failing values. + pub fn deterministic_probability_once(value: T, chance: f32) -> bool { + thread_local! { + static FAILING_VALUES: RefCell)>> = RefCell::new(HashSet::new()); + } + + let bytes = bcs::to_bytes(&value).unwrap(); + let key = (current_simnode_id(), bytes); + + FAILING_VALUES.with(|failing_values| { + let mut failing_values = failing_values.borrow_mut(); + if failing_values.contains(&key) { + false + } else if deterministic_probability(value, chance) { + failing_values.insert(key); + true + } else { + false + } + }) + } +} diff --git a/crates/iota-single-node-benchmark/Cargo.toml b/crates/iota-single-node-benchmark/Cargo.toml new file mode 100644 index 00000000000..7732b3534de --- /dev/null +++ b/crates/iota-single-node-benchmark/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "iota-single-node-benchmark" +version = "0.1.0" +edition = "2021" +publish = false +license = "Apache-2.0" + +[dependencies] +move-binary-format.workspace = true +move-bytecode-utils.workspace = true +move-core-types.workspace = true +move-package.workspace = true +iota-config.workspace = true +iota-core = { workspace = true, features = ["test-utils"] } +iota-move-build.workspace = true +iota-test-transaction-builder.workspace = true +iota-transaction-checks.workspace = true +iota-types = { workspace = true, features = ["test-utils"] } +iota-storage.workspace = true + +async-trait.workspace = true +bcs.workspace = true +clap.workspace = true +fs_extra.workspace = true +futures.workspace = true +prometheus.workspace = true +once_cell.workspace = true +serde = { version = "1.0.190", features = ["derive"] } +serde_json.workspace = true +strum.workspace = true +strum_macros.workspace = true +telemetry-subscribers.workspace = true +tokio = { workspace = true, features = ["full", "tracing", "test-util"] } +tracing.workspace = true + +[dev-dependencies] +iota-macros.workspace = true +iota-protocol-config.workspace = true +iota-simulator.workspace = true diff --git a/crates/iota-single-node-benchmark/README.md b/crates/iota-single-node-benchmark/README.md new file mode 100644 index 00000000000..007bb4111a8 --- /dev/null +++ b/crates/iota-single-node-benchmark/README.md @@ -0,0 +1,43 @@ +# Iota Single Node Benchmark + +This crate contains a binary for performance benchmarking a single Iota node. +Upon running the binary, the node will instantiate a standalone `AuthorityState`, and submit +executable transactions to it in parallel. We then measure the time it takes for it to finish +executing all the transactions. + +## Usage +To run the benchmark, you can simply run the following command: +``` +cargo run --release --bin iota-single-node-benchmark -- ptb +``` +By default, it generates 50,0000 transactions, which can be changed using `--tx-count`. Each transaction will contain an empty PTB without any command (i.e. essentially a nop transaction). + +### PTB benchmark workloads +When running the PTB benchmark, one can adjust the workload to stress test different parts +of the execution engine: +- `--num-transfers`: this specifies number of transfers made per transaction. Default to 0. +- `--use-native-transfer`: this is false by default, which means we use Move call to transfer objects. When specified, we will use the native TransferObject command without invoking Move to transfer objects. +- `--num-dynamic-fields`: this specifies number of dynamic fields read by each transaction. Default to 0. +- `--computation`: this specifies computation intensity. An increase by 1 means 100 more loop iterations in Fibonacci computation. Default to 0. + +### Publish benchmark workloads +WIP (please refer to smoke_tests to see how its setup) + +### Components +By default, the benchmark will use the `AuthorityState::try_execute_immediately` entry function, +which includes the execution layer as well as the interaction with the DB. This is equivalent to running: +``` +cargo run --release --bin iota-single-node-benchmark -- --component baseline ptb +``` +The benchmark supports various component: +- `baseline`: this is the default component, which includes the execution layer as well as the interaction with the DB. +- `execution-only`: compared to baseline, this doesn't interact with RocksDB at all, and only does execution. +- `with-tx-manager`: on top of baseline, it schedules transactions into the transaction manager, instead of executing them immediately. It also goes through the execution driver. +- `validator-without-consensus`: in this mode, transactions are sent to the `handle_certificate` GRPC entry point of the validator service. On top of `with-tx-manager`, it also includes the verification of the certificate. +- `validator-with-fake-consensus`: in this mode, on top of `validator-without-consensus`, it also submits the transactions to a simple consensus layer, which sequences transactions in the order as it receives it directly back to the store. It covers part of the cost in consensus handler. The commit size can be controlled with `--checkpoint-size`. +- `txn-signing`: in this mode, instead of executing transactions, we only benchmark transactions signing. +- `checkpoint-executor`: in this mode, we benchmark how long it takes for the checkpoint executor to execute all checkpoints (i.e. all transactions in them) for the entire epoch. We first construct transactions and effects by actually executing them, and revert them as if they were never executed, construct checkpoints using the results, and then start the checkpoint executor. The size of checkpoints can be controlled with `--checkpoint-size`. + + +### Profiling +If you are interested in profiling Iota, you can start the benchmark, wait for it to print out "Started execution...", and then attach a profiler to the process. diff --git a/crates/iota-single-node-benchmark/move_package/Move.toml b/crates/iota-single-node-benchmark/move_package/Move.toml new file mode 100644 index 00000000000..ecb05d11dc4 --- /dev/null +++ b/crates/iota-single-node-benchmark/move_package/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "MoveBenchmark" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../iota-framework/packages/iota-framework" } + +[addresses] +move_benchmark = "0x0" \ No newline at end of file diff --git a/crates/sui-single-node-benchmark/move_package/sources/benchmark.move b/crates/iota-single-node-benchmark/move_package/sources/benchmark.move similarity index 85% rename from crates/sui-single-node-benchmark/move_package/sources/benchmark.move rename to crates/iota-single-node-benchmark/move_package/sources/benchmark.move index e038ee44941..5693eaa6df6 100644 --- a/crates/sui-single-node-benchmark/move_package/sources/benchmark.move +++ b/crates/iota-single-node-benchmark/move_package/sources/benchmark.move @@ -1,20 +1,21 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module move_benchmark::benchmark { use std::ascii; use std::ascii::String; use std::vector; - use sui::coin::Coin; - use sui::dynamic_field; - use sui::object; - use sui::object::UID; - use sui::sui::SUI; - use sui::transfer; - use sui::tx_context; - use sui::tx_context::TxContext; + use iota::coin::Coin; + use iota::dynamic_field; + use iota::object; + use iota::object::UID; + use iota::iota::IOTA; + use iota::transfer; + use iota::tx_context; + use iota::tx_context::TxContext; - public fun transfer_coin(coin: Coin, ctx: &TxContext) { + public fun transfer_coin(coin: Coin, ctx: &TxContext) { transfer::public_transfer(coin, tx_context::sender(ctx)); } diff --git a/crates/sui-single-node-benchmark/src/benchmark_context.rs b/crates/iota-single-node-benchmark/src/benchmark_context.rs similarity index 98% rename from crates/sui-single-node-benchmark/src/benchmark_context.rs rename to crates/iota-single-node-benchmark/src/benchmark_context.rs index d62f78e68ce..319d157a73a 100644 --- a/crates/sui-single-node-benchmark/src/benchmark_context.rs +++ b/crates/iota-single-node-benchmark/src/benchmark_context.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -8,10 +9,10 @@ use std::{ }; use futures::{stream::FuturesUnordered, StreamExt}; -use sui_config::node::RunWithRange; -use sui_test_transaction_builder::PublishData; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, +use iota_config::node::RunWithRange; +use iota_test_transaction_builder::PublishData; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef}, effects::{TransactionEffects, TransactionEffectsAPI}, messages_grpc::HandleTransactionResponse, mock_checkpoint_builder::ValidatorKeypairProvider, @@ -30,7 +31,7 @@ use crate::{ pub struct BenchmarkContext { validator: SingleValidator, - user_accounts: BTreeMap, + user_accounts: BTreeMap, admin_account: Account, benchmark_component: Component, } @@ -99,7 +100,7 @@ impl BenchmarkContext { &mut self, move_package: ObjectID, num_dynamic_fields: u64, - ) -> HashMap { + ) -> HashMap { let mut root_objects = HashMap::new(); if num_dynamic_fields == 0 { diff --git a/crates/iota-single-node-benchmark/src/command.rs b/crates/iota-single-node-benchmark/src/command.rs new file mode 100644 index 00000000000..fb2e31f4524 --- /dev/null +++ b/crates/iota-single-node-benchmark/src/command.rs @@ -0,0 +1,135 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::path::PathBuf; + +use clap::{Parser, Subcommand, ValueEnum}; +use strum_macros::EnumIter; + +#[derive(Parser)] +#[clap( + name = "iota-single-node-benchmark", + about = "Benchmark a single validator node", + rename_all = "kebab-case", + author, + version +)] +pub struct Command { + #[arg( + long, + default_value_t = 500000, + help = "Number of transactions to submit" + )] + pub tx_count: u64, + #[arg( + long, + default_value_t = 100, + help = "Number of transactions in a consensus commit/checkpoint" + )] + pub checkpoint_size: usize, + #[arg( + long, + help = "Whether to print out a sample transaction and effects that is going to be benchmarked on" + )] + pub print_sample_tx: bool, + #[arg( + long, + default_value_t = false, + help = "If true, skip signing on the validators, instead, creating certificates directly using validator secrets" + )] + pub skip_signing: bool, + #[arg( + long, + default_value = "baseline", + ignore_case = true, + help = "Which component to benchmark" + )] + pub component: Component, + #[clap(subcommand)] + pub workload: WorkloadKind, +} + +#[derive(Copy, Clone, EnumIter, ValueEnum)] +pub enum Component { + ExecutionOnly, + /// Baseline includes the execution and storage layer only. + Baseline, + /// On top of Baseline, this schedules transactions through the transaction + /// manager. + WithTxManager, + /// This goes through the `handle_certificate` entry point on + /// authority_server, which includes certificate verification, + /// transaction manager, as well as a noop consensus layer. The noop + /// consensus layer does absolutely nothing when receiving a transaction in + /// consensus. + ValidatorWithoutConsensus, + /// Similar to ValidatorWithNoopConsensus, but the consensus layer contains + /// a fake consensus protocol that basically sequences transactions in + /// order. It then verify the transaction and store the sequenced + /// transactions into the store. It covers the consensus-independent + /// portion of the code in consensus handler. + ValidatorWithFakeConsensus, + /// Benchmark only validator signing component: `handle_transaction`. + TxnSigning, + /// Benchmark the checkpoint executor by constructing a full epoch of + /// checkpoints, execute all transactions in them and measure time. + CheckpointExecutor, +} + +#[derive(Subcommand, Clone)] +pub enum WorkloadKind { + PTB { + #[arg( + long, + default_value_t = 0, + help = "Number of address owned input objects per transaction.\ + This represents the amount of DB reads per transaction prior to execution." + )] + num_transfers: u64, + #[arg( + long, + default_value_t = false, + help = "When transferring an object, whether to use native TransferObjecet command, or to use Move code for the transfer" + )] + use_native_transfer: bool, + #[arg( + long, + default_value_t = 0, + help = "Number of dynamic fields read per transaction.\ + This represents the amount of runtime DB reads per transaction during execution." + )] + num_dynamic_fields: u64, + #[arg( + long, + default_value_t = 0, + help = "Computation intensity per transaction.\ + The transaction computes the n-th Fibonacci number \ + specified by this parameter * 100." + )] + computation: u8, + }, + Publish { + #[arg( + long, + help = "Path to the manifest file that describe the package dependencies.\ + Follow examples in the tests directory to see how to set up the manifest file.\ + The manifest file is a json file that contains a list of dependent packages that need to\ + be published first, as well as the root package that will be benchmarked on. Each package\ + can be either in source code or bytecode form. If it is in source code form, the benchmark\ + will compile the package first before publishing it." + )] + manifest_file: PathBuf, + }, +} + +impl WorkloadKind { + pub(crate) fn gas_object_num_per_account(&self) -> u64 { + match self { + // Each transaction will always have 1 gas object, plus the number of owned objects that + // will be transferred. + WorkloadKind::PTB { num_transfers, .. } => *num_transfers + 1, + WorkloadKind::Publish { .. } => 1, + } + } +} diff --git a/crates/iota-single-node-benchmark/src/lib.rs b/crates/iota-single-node-benchmark/src/lib.rs new file mode 100644 index 00000000000..15e15a0f067 --- /dev/null +++ b/crates/iota-single-node-benchmark/src/lib.rs @@ -0,0 +1,54 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use crate::{benchmark_context::BenchmarkContext, command::Component, workload::Workload}; + +pub(crate) mod benchmark_context; +pub mod command; +pub(crate) mod mock_account; +pub(crate) mod mock_consensus; +pub(crate) mod mock_storage; +pub(crate) mod single_node; +pub(crate) mod tx_generator; +pub mod workload; + +/// Benchmark a given workload on a specified component. +/// The different kinds of workloads and components can be found in command.rs. +/// \checkpoint_size represents both the size of a consensus commit, and size of +/// a checkpoint if we are benchmarking the checkpoint. +pub async fn run_benchmark( + workload: Workload, + component: Component, + checkpoint_size: usize, + print_sample_tx: bool, + skip_signing: bool, +) { + let mut ctx = BenchmarkContext::new( + workload.clone(), + component, + checkpoint_size, + print_sample_tx, + ) + .await; + let tx_generator = workload.create_tx_generator(&mut ctx).await; + let transactions = ctx.generate_transactions(tx_generator).await; + match component { + Component::TxnSigning => { + ctx.benchmark_transaction_signing(transactions, print_sample_tx) + .await; + } + Component::CheckpointExecutor => { + ctx.benchmark_checkpoint_executor(transactions, checkpoint_size) + .await; + } + Component::ExecutionOnly => { + ctx.benchmark_transaction_execution_in_memory(transactions, print_sample_tx) + .await; + } + _ => { + ctx.benchmark_transaction_execution(transactions, print_sample_tx, skip_signing) + .await; + } + } +} diff --git a/crates/iota-single-node-benchmark/src/main.rs b/crates/iota-single-node-benchmark/src/main.rs new file mode 100644 index 00000000000..d45f71d4a8d --- /dev/null +++ b/crates/iota-single-node-benchmark/src/main.rs @@ -0,0 +1,30 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use clap::Parser; +use iota_single_node_benchmark::{command::Command, run_benchmark, workload::Workload}; + +#[tokio::main] +async fn main() { + let _guard = telemetry_subscribers::TelemetryConfig::new() + .with_log_level("off,iota_single_node_benchmark=info") + .with_env() + .init(); + + let args = Command::parse(); + run_benchmark( + Workload::new(args.tx_count, args.workload), + args.component, + args.checkpoint_size, + args.print_sample_tx, + args.skip_signing, + ) + .await; + + if std::env::var("TRACE_FILTER").is_ok() { + println!("Sleeping for 60 seconds to allow tracing to flush."); + println!("You can ctrl-c to exit once you see trace data appearing in grafana"); + tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; + } +} diff --git a/crates/sui-single-node-benchmark/src/mock_account.rs b/crates/iota-single-node-benchmark/src/mock_account.rs similarity index 86% rename from crates/sui-single-node-benchmark/src/mock_account.rs rename to crates/iota-single-node-benchmark/src/mock_account.rs index 160488ba125..baa536a6fcc 100644 --- a/crates/sui-single-node-benchmark/src/mock_account.rs +++ b/crates/iota-single-node-benchmark/src/mock_account.rs @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, sync::Arc}; use futures::stream::FuturesUnordered; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress, SUI_ADDRESS_LENGTH}, +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, IOTA_ADDRESS_LENGTH}, crypto::{get_account_key_pair, AccountKeyPair}, object::Object, }; #[derive(Clone)] pub struct Account { - pub sender: SuiAddress, + pub sender: IotaAddress, pub keypair: Arc, pub gas_objects: Arc>, } @@ -23,7 +24,7 @@ pub struct Account { pub async fn batch_create_account_and_gas( num_accounts: u64, gas_object_num_per_account: u64, -) -> (BTreeMap, Vec) { +) -> (BTreeMap, Vec) { let tasks: FuturesUnordered<_> = (0..num_accounts) .map(|idx| { let starting_id = idx * gas_object_num_per_account; @@ -57,9 +58,9 @@ pub async fn batch_create_account_and_gas( (accounts, genesis_gas_objects) } -fn new_gas_object(idx: u64, owner: SuiAddress) -> Object { +fn new_gas_object(idx: u64, owner: IotaAddress) -> Object { // Predictable and cheaper way of generating object IDs for benchmarking. - let mut id_bytes = [0u8; SUI_ADDRESS_LENGTH]; + let mut id_bytes = [0u8; IOTA_ADDRESS_LENGTH]; let idx_bytes = idx.to_le_bytes(); id_bytes[0] = 255; id_bytes[1..idx_bytes.len() + 1].copy_from_slice(&idx_bytes); diff --git a/crates/sui-single-node-benchmark/src/mock_consensus.rs b/crates/iota-single-node-benchmark/src/mock_consensus.rs similarity index 95% rename from crates/sui-single-node-benchmark/src/mock_consensus.rs rename to crates/iota-single-node-benchmark/src/mock_consensus.rs index 44dc63236e8..2e2a7f37194 100644 --- a/crates/sui-single-node-benchmark/src/mock_consensus.rs +++ b/crates/iota-single-node-benchmark/src/mock_consensus.rs @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{mem, sync::Arc}; -use prometheus::IntCounter; -use sui_core::{ +use iota_core::{ authority::{authority_per_epoch_store::AuthorityPerEpochStore, AuthorityState}, checkpoints::CheckpointServiceNoop, consensus_adapter::SubmitToConsensus, consensus_handler::SequencedConsensusTransaction, }; -use sui_types::{error::SuiResult, messages_consensus::ConsensusTransaction}; +use iota_types::{error::IotaResult, messages_consensus::ConsensusTransaction}; +use prometheus::IntCounter; use tokio::{sync::mpsc, task::JoinHandle}; pub(crate) struct MockConsensusClient { @@ -86,7 +87,7 @@ impl SubmitToConsensus for MockConsensusClient { &self, transaction: &ConsensusTransaction, _epoch_store: &Arc, - ) -> SuiResult { + ) -> IotaResult { self.tx_sender.send(transaction.clone()).await.unwrap(); Ok(()) } diff --git a/crates/sui-single-node-benchmark/src/mock_storage.rs b/crates/iota-single-node-benchmark/src/mock_storage.rs similarity index 88% rename from crates/sui-single-node-benchmark/src/mock_storage.rs rename to crates/iota-single-node-benchmark/src/mock_storage.rs index 16ec445453e..ecc6be56d7e 100644 --- a/crates/sui-single-node-benchmark/src/mock_storage.rs +++ b/crates/iota-single-node-benchmark/src/mock_storage.rs @@ -1,17 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, sync::Arc}; -use move_binary_format::CompiledModule; -use move_bytecode_utils::module_cache::GetModule; -use move_core_types::language_storage::ModuleId; -use once_cell::unsync::OnceCell; -use prometheus::core::{Atomic, AtomicU64}; -use sui_storage::package_object_cache::PackageObjectCache; -use sui_types::{ +use iota_storage::package_object_cache::PackageObjectCache; +use iota_types::{ base_types::{EpochId, ObjectID, ObjectRef, SequenceNumber, VersionNumber}, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, object::{Object, Owner}, storage::{ get_module_by_id, BackingPackageStore, ChildObjectResolver, GetSharedLocks, ObjectStore, @@ -19,6 +15,11 @@ use sui_types::{ }, transaction::{InputObjectKind, InputObjects, ObjectReadResult, TransactionKey}, }; +use move_binary_format::CompiledModule; +use move_bytecode_utils::module_cache::GetModule; +use move_core_types::language_storage::ModuleId; +use once_cell::unsync::OnceCell; +use prometheus::core::{Atomic, AtomicU64}; // TODO: We won't need a special purpose InMemoryObjectStore once the // InMemoryCache is ready. @@ -49,7 +50,7 @@ impl InMemoryObjectStore { shared_locks: &dyn GetSharedLocks, tx_key: &TransactionKey, input_object_kinds: &[InputObjectKind], - ) -> SuiResult { + ) -> IotaResult { let shared_locks_cell: OnceCell> = OnceCell::new(); let mut input_objects = Vec::new(); for kind in input_object_kinds { @@ -61,7 +62,7 @@ impl InMemoryObjectStore { InputObjectKind::SharedMoveObject { id, .. } => { let shared_locks = shared_locks_cell.get_or_try_init(|| { - Ok::, SuiError>( + Ok::, IotaError>( shared_locks.get_shared_locks(tx_key)?.into_iter().collect(), ) })?; @@ -87,7 +88,7 @@ impl ObjectStore for InMemoryObjectStore { fn get_object( &self, object_id: &ObjectID, - ) -> Result, sui_types::storage::error::Error> { + ) -> Result, iota_types::storage::error::Error> { self.num_object_reads.inc_by(1); Ok(self.objects.get(object_id).cloned()) } @@ -96,7 +97,7 @@ impl ObjectStore for InMemoryObjectStore { &self, object_id: &ObjectID, version: VersionNumber, - ) -> Result, sui_types::storage::error::Error> { + ) -> Result, iota_types::storage::error::Error> { Ok(self.get_object(object_id).unwrap().and_then(|o| { if o.version() == version { Some(o.clone()) @@ -108,7 +109,7 @@ impl ObjectStore for InMemoryObjectStore { } impl BackingPackageStore for InMemoryObjectStore { - fn get_package_object(&self, package_id: &ObjectID) -> SuiResult> { + fn get_package_object(&self, package_id: &ObjectID) -> IotaResult> { self.package_cache.get_package_object(package_id, self) } } @@ -119,7 +120,7 @@ impl ChildObjectResolver for InMemoryObjectStore { parent: &ObjectID, child: &ObjectID, child_version_upper_bound: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self.get_object(child).unwrap().and_then(|o| { if o.version() <= child_version_upper_bound && o.owner == Owner::ObjectOwner((*parent).into()) @@ -137,13 +138,13 @@ impl ChildObjectResolver for InMemoryObjectStore { _receiving_object_id: &ObjectID, _receive_object_at_version: SequenceNumber, _epoch_id: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { unimplemented!() } } impl GetModule for InMemoryObjectStore { - type Error = SuiError; + type Error = IotaError; type Item = CompiledModule; fn get_module_by_id(&self, id: &ModuleId) -> Result, Self::Error> { @@ -155,7 +156,7 @@ impl ParentSync for InMemoryObjectStore { fn get_latest_parent_entry_ref_deprecated( &self, _object_id: ObjectID, - ) -> SuiResult> { + ) -> IotaResult> { unreachable!() } } @@ -164,7 +165,7 @@ impl GetSharedLocks for InMemoryObjectStore { fn get_shared_locks( &self, _key: &TransactionKey, - ) -> Result, SuiError> { + ) -> Result, IotaError> { unreachable!() } } diff --git a/crates/sui-single-node-benchmark/src/single_node.rs b/crates/iota-single-node-benchmark/src/single_node.rs similarity index 96% rename from crates/sui-single-node-benchmark/src/single_node.rs rename to crates/iota-single-node-benchmark/src/single_node.rs index e75c7e72513..eba9eb480ae 100644 --- a/crates/sui-single-node-benchmark/src/single_node.rs +++ b/crates/iota-single-node-benchmark/src/single_node.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -6,7 +7,7 @@ use std::{ sync::Arc, }; -use sui_core::{ +use iota_core::{ authority::{ authority_per_epoch_store::AuthorityPerEpochStore, authority_store_tables::LiveObject, test_authority_builder::TestAuthorityBuilder, AuthorityState, @@ -18,9 +19,9 @@ use sui_core::{ }, state_accumulator::{AccumulatorStore, StateAccumulator}, }; -use sui_test_transaction_builder::{PublishData, TestTransactionBuilder}; -use sui_types::{ - base_types::{AuthorityName, ObjectRef, SuiAddress, TransactionDigest}, +use iota_test_transaction_builder::{PublishData, TestTransactionBuilder}; +use iota_types::{ + base_types::{AuthorityName, IotaAddress, ObjectRef, TransactionDigest}, committee::Committee, crypto::{AccountKeyPair, AuthoritySignature, Signer}, effects::{TransactionEffects, TransactionEffectsAPI}, @@ -103,7 +104,7 @@ impl SingleValidator { pub async fn publish_package( &self, publish_data: PublishData, - sender: SuiAddress, + sender: IotaAddress, keypair: &AccountKeyPair, gas: ObjectRef, ) -> (ObjectRef, ObjectRef) { @@ -192,7 +193,7 @@ impl SingleValidator { VerifiedTransaction::new_unchecked(transaction), 0, ); - let (gas_status, input_objects) = sui_transaction_checks::check_certificate_input( + let (gas_status, input_objects) = iota_transaction_checks::check_certificate_input( &executable, objects, self.epoch_store.protocol_config(), diff --git a/crates/sui-single-node-benchmark/src/tx_generator.rs b/crates/iota-single-node-benchmark/src/tx_generator.rs similarity index 88% rename from crates/sui-single-node-benchmark/src/tx_generator.rs rename to crates/iota-single-node-benchmark/src/tx_generator.rs index 9204a76f46a..d556d02ed36 100644 --- a/crates/sui-single-node-benchmark/src/tx_generator.rs +++ b/crates/iota-single-node-benchmark/src/tx_generator.rs @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_types::transaction::Transaction; pub use move_tx_generator::MoveTxGenerator; pub use package_publish_tx_generator::PackagePublishTxGenerator; pub use root_object_create_tx_generator::RootObjectCreateTxGenerator; -use sui_types::transaction::Transaction; use crate::mock_account::Account; diff --git a/crates/sui-single-node-benchmark/src/tx_generator/move_tx_generator.rs b/crates/iota-single-node-benchmark/src/tx_generator/move_tx_generator.rs similarity index 92% rename from crates/sui-single-node-benchmark/src/tx_generator/move_tx_generator.rs rename to crates/iota-single-node-benchmark/src/tx_generator/move_tx_generator.rs index adb735a50c8..73c9fd3b4ff 100644 --- a/crates/sui-single-node-benchmark/src/tx_generator/move_tx_generator.rs +++ b/crates/iota-single-node-benchmark/src/tx_generator/move_tx_generator.rs @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::HashMap; -use move_core_types::identifier::Identifier; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef}, programmable_transaction_builder::ProgrammableTransactionBuilder, transaction::{CallArg, ObjectArg, Transaction, DEFAULT_VALIDATOR_GAS_PRICE}, }; +use move_core_types::identifier::Identifier; use crate::{mock_account::Account, tx_generator::TxGenerator}; @@ -18,7 +19,7 @@ pub struct MoveTxGenerator { num_transfers: u64, use_native_transfer: bool, computation: u8, - root_objects: HashMap, + root_objects: HashMap, } impl MoveTxGenerator { @@ -27,7 +28,7 @@ impl MoveTxGenerator { num_transfers: u64, use_native_transfer: bool, computation: u8, - root_objects: HashMap, + root_objects: HashMap, ) -> Self { Self { move_package, diff --git a/crates/sui-single-node-benchmark/src/tx_generator/package_publish_tx_generator.rs b/crates/iota-single-node-benchmark/src/tx_generator/package_publish_tx_generator.rs similarity index 95% rename from crates/sui-single-node-benchmark/src/tx_generator/package_publish_tx_generator.rs rename to crates/iota-single-node-benchmark/src/tx_generator/package_publish_tx_generator.rs index e9dd5007fdc..c735c3726be 100644 --- a/crates/sui-single-node-benchmark/src/tx_generator/package_publish_tx_generator.rs +++ b/crates/iota-single-node-benchmark/src/tx_generator/package_publish_tx_generator.rs @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, fs, path::PathBuf}; -use move_package::source_package::manifest_parser::parse_move_manifest_from_file; -use serde::{Deserialize, Serialize}; -use sui_move_build::{BuildConfig, CompiledPackage}; -use sui_test_transaction_builder::{PublishData, TestTransactionBuilder}; -use sui_types::{ +use iota_move_build::{BuildConfig, CompiledPackage}; +use iota_test_transaction_builder::{PublishData, TestTransactionBuilder}; +use iota_types::{ base_types::ObjectID, transaction::{Transaction, DEFAULT_VALIDATOR_GAS_PRICE}, }; +use move_package::source_package::manifest_parser::parse_move_manifest_from_file; +use serde::{Deserialize, Serialize}; use tracing::info; use crate::{ diff --git a/crates/sui-single-node-benchmark/src/tx_generator/root_object_create_tx_generator.rs b/crates/iota-single-node-benchmark/src/tx_generator/root_object_create_tx_generator.rs similarity index 90% rename from crates/sui-single-node-benchmark/src/tx_generator/root_object_create_tx_generator.rs rename to crates/iota-single-node-benchmark/src/tx_generator/root_object_create_tx_generator.rs index e4052ef5760..0d1db38c290 100644 --- a/crates/sui-single-node-benchmark/src/tx_generator/root_object_create_tx_generator.rs +++ b/crates/iota-single-node-benchmark/src/tx_generator/root_object_create_tx_generator.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ base_types::ObjectID, transaction::{CallArg, Transaction, DEFAULT_VALIDATOR_GAS_PRICE}, }; diff --git a/crates/iota-single-node-benchmark/src/workload.rs b/crates/iota-single-node-benchmark/src/workload.rs new file mode 100644 index 00000000000..e4b0e324a14 --- /dev/null +++ b/crates/iota-single-node-benchmark/src/workload.rs @@ -0,0 +1,67 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{path::PathBuf, sync::Arc}; + +use iota_test_transaction_builder::PublishData; + +use crate::{ + benchmark_context::BenchmarkContext, + command::WorkloadKind, + tx_generator::{MoveTxGenerator, PackagePublishTxGenerator, TxGenerator}, +}; + +#[derive(Clone)] +pub struct Workload { + pub tx_count: u64, + pub workload_kind: WorkloadKind, +} + +impl Workload { + pub fn new(tx_count: u64, workload_kind: WorkloadKind) -> Self { + Self { + tx_count, + workload_kind, + } + } + + pub(crate) fn num_accounts(&self) -> u64 { + self.tx_count + } + + pub(crate) fn gas_object_num_per_account(&self) -> u64 { + self.workload_kind.gas_object_num_per_account() + } + + pub(crate) async fn create_tx_generator( + &self, + ctx: &mut BenchmarkContext, + ) -> Arc { + match &self.workload_kind { + WorkloadKind::PTB { + num_transfers, + use_native_transfer, + num_dynamic_fields, + computation, + } => { + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.extend(["move_package"]); + let move_package = ctx.publish_package(PublishData::Source(path, false)).await; + let root_objects = ctx + .preparing_dynamic_fields(move_package.0, *num_dynamic_fields) + .await; + Arc::new(MoveTxGenerator::new( + move_package.0, + *num_transfers, + *use_native_transfer, + *computation, + root_objects, + )) + } + WorkloadKind::Publish { + manifest_file: manifest_path, + } => Arc::new(PackagePublishTxGenerator::new(ctx, manifest_path.clone()).await), + } + } +} diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/manifest.json b/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/manifest.json similarity index 100% rename from crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/manifest.json rename to crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/manifest.json diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_a/Move.toml b/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_a/Move.toml similarity index 100% rename from crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_a/Move.toml rename to crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_a/Move.toml diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_a/build/A/bytecode_modules/a.mv b/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_a/build/A/bytecode_modules/a.mv similarity index 100% rename from crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_a/build/A/bytecode_modules/a.mv rename to crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_a/build/A/bytecode_modules/a.mv diff --git a/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_a/sources/a.move b/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_a/sources/a.move new file mode 100644 index 00000000000..7049f775678 --- /dev/null +++ b/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_a/sources/a.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module a::a { + public fun a() {} +} \ No newline at end of file diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_b/Move.toml b/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_b/Move.toml similarity index 100% rename from crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_b/Move.toml rename to crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_b/Move.toml diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_b/build/B/bytecode_modules/b.mv b/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_b/build/B/bytecode_modules/b.mv similarity index 100% rename from crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_b/build/B/bytecode_modules/b.mv rename to crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_b/build/B/bytecode_modules/b.mv diff --git a/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_b/sources/b.move b/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_b/sources/b.move new file mode 100644 index 00000000000..3dba020e08e --- /dev/null +++ b/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_b/sources/b.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::b { + public fun b() {} +} \ No newline at end of file diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_c/Move.toml b/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_c/Move.toml similarity index 100% rename from crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_c/Move.toml rename to crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_c/Move.toml diff --git a/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_c/sources/c.move b/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_c/sources/c.move new file mode 100644 index 00000000000..310e1dfd672 --- /dev/null +++ b/crates/iota-single-node-benchmark/tests/data/package_publish_from_bytecode/package_c/sources/c.move @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module c::c { + use a::a; + use b::b; + + public fun c() { + a::a(); + b::b(); + } +} \ No newline at end of file diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_source/manifest.json b/crates/iota-single-node-benchmark/tests/data/package_publish_from_source/manifest.json similarity index 100% rename from crates/sui-single-node-benchmark/tests/data/package_publish_from_source/manifest.json rename to crates/iota-single-node-benchmark/tests/data/package_publish_from_source/manifest.json diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_a/Move.toml b/crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_a/Move.toml similarity index 100% rename from crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_a/Move.toml rename to crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_a/Move.toml diff --git a/crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_a/sources/a.move b/crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_a/sources/a.move new file mode 100644 index 00000000000..7049f775678 --- /dev/null +++ b/crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_a/sources/a.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module a::a { + public fun a() {} +} \ No newline at end of file diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_b/Move.toml b/crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_b/Move.toml similarity index 100% rename from crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_b/Move.toml rename to crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_b/Move.toml diff --git a/crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_b/sources/b.move b/crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_b/sources/b.move new file mode 100644 index 00000000000..3dba020e08e --- /dev/null +++ b/crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_b/sources/b.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::b { + public fun b() {} +} \ No newline at end of file diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_c/Move.toml b/crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_c/Move.toml similarity index 100% rename from crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_c/Move.toml rename to crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_c/Move.toml diff --git a/crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_c/sources/c.move b/crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_c/sources/c.move new file mode 100644 index 00000000000..310e1dfd672 --- /dev/null +++ b/crates/iota-single-node-benchmark/tests/data/package_publish_from_source/package_c/sources/c.move @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module c::c { + use a::a; + use b::b; + + public fun c() { + a::a(); + b::b(); + } +} \ No newline at end of file diff --git a/crates/iota-single-node-benchmark/tests/smoke_tests.rs b/crates/iota-single-node-benchmark/tests/smoke_tests.rs new file mode 100644 index 00000000000..10d906e68c1 --- /dev/null +++ b/crates/iota-single-node-benchmark/tests/smoke_tests.rs @@ -0,0 +1,115 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::path::PathBuf; + +use iota_macros::sim_test; +use iota_single_node_benchmark::{ + command::{Component, WorkloadKind}, + run_benchmark, + workload::Workload, +}; +use strum::IntoEnumIterator; + +#[sim_test] +async fn benchmark_non_move_transactions_smoke_test() { + for skip_signing in [true, false] { + for component in Component::iter() { + run_benchmark( + Workload::new( + 10, + WorkloadKind::PTB { + num_transfers: 2, + use_native_transfer: true, + num_dynamic_fields: 0, + computation: 0, + }, + ), + component, + 1000, + false, + skip_signing, + ) + .await; + } + } +} + +#[sim_test] +async fn benchmark_move_transactions_smoke_test() { + for skip_signing in [true, false] { + for component in Component::iter() { + run_benchmark( + Workload::new( + 10, + WorkloadKind::PTB { + num_transfers: 2, + use_native_transfer: false, + num_dynamic_fields: 1, + computation: 1, + }, + ), + component, + 1000, + false, + skip_signing, + ) + .await; + } + } +} + +#[sim_test] +async fn benchmark_publish_from_source() { + // This test makes sure that the benchmark runs. + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.extend([ + "tests", + "data", + "package_publish_from_source", + "manifest.json", + ]); + for component in Component::iter() { + run_benchmark( + Workload::new( + 10, + WorkloadKind::Publish { + manifest_file: path.clone(), + }, + ), + component, + 1000, + false, + false, + ) + .await; + } +} + +#[sim_test] +async fn benchmark_publish_from_bytecode() { + // This test makes sure that the benchmark runs. + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.extend([ + "tests", + "data", + "package_publish_from_bytecode", + "manifest.json", + ]); + for component in Component::iter() { + run_benchmark( + Workload::new( + 10, + WorkloadKind::Publish { + manifest_file: path.clone(), + }, + ), + component, + 1000, + false, + false, + ) + .await; + } +} diff --git a/crates/iota-snapshot/Cargo.toml b/crates/iota-snapshot/Cargo.toml new file mode 100644 index 00000000000..3c58dae6a2c --- /dev/null +++ b/crates/iota-snapshot/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "iota-snapshot" +version = "0.1.0" +edition = "2021" +publish = false +license = "Apache-2.0" +authors = ["Mysten Labs "] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +integer-encoding.workspace = true +indicatif.workspace = true +anyhow.workspace = true +serde.workspace = true +bcs.workspace = true +byteorder.workspace = true +tracing.workspace = true +bytes.workspace = true +tokio-stream.workspace = true +num_enum.workspace = true +futures.workspace = true +object_store.workspace = true +prometheus.workspace = true +iota-types.workspace = true +iota-config.workspace = true +iota-core.workspace = true +iota-storage.workspace = true +iota-protocol-config.workspace = true +fastcrypto = { workspace = true, features = ["copy_key"] } +tokio = { workspace = true, features = ["full"] } +serde_json.workspace = true + +[dev-dependencies] +tempfile.workspace = true diff --git a/crates/iota-snapshot/src/lib.rs b/crates/iota-snapshot/src/lib.rs new file mode 100644 index 00000000000..3f11a4195d5 --- /dev/null +++ b/crates/iota-snapshot/src/lib.rs @@ -0,0 +1,256 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +#![allow(dead_code)] + +#[cfg(test)] +mod tests; + +pub mod reader; +pub mod uploader; +mod writer; + +use std::{path::PathBuf, sync::Arc}; + +use anyhow::Result; +use iota_core::{ + authority::{ + authority_store_tables::AuthorityPerpetualTables, + epoch_start_configuration::EpochStartConfiguration, + }, + checkpoints::CheckpointStore, + epoch::committee_store::CommitteeStore, +}; +use iota_storage::{ + compute_sha3_checksum, object_store::util::path_to_filesystem, FileCompression, SHA3_BYTES, +}; +use iota_types::{ + accumulator::Accumulator, + base_types::ObjectID, + iota_system_state::{ + epoch_start_iota_system_state::EpochStartSystemStateTrait, get_iota_system_state, + IotaSystemStateTrait, + }, +}; +use num_enum::{IntoPrimitive, TryFromPrimitive}; +use object_store::path::Path; +use serde::{Deserialize, Serialize}; + +/// The following describes the format of an object file (*.obj) used for +/// persisting live iota objects. The maximum size per .obj file is 128MB. State +/// snapshot will be taken at the end of every epoch. Live object set is split +/// into and stored across multiple hash buckets. The hashing function used +/// for bucketing objects is the same as the one used to build the accumulator +/// tree for computing state root hash. Buckets are further subdivided into +/// partitions. A partition is a smallest storage unit which holds a subset of +/// objects in one bucket. Each partition is a single *.obj file where +/// objects are appended to in an append-only fashion. A new partition is +/// created once the size of current one reaches the max size i.e. 128MB. +/// Partitions allow a single hash bucket to be consumed in parallel. Partition +/// files are optionally compressed with the zstd compression format. Partition +/// filenames follows the format _.obj. Object +/// references for hash There is one single ref file per hash bucket. Object +/// references are written in an append-only manner as well. Finally, the +/// MANIFEST file contains per file metadata of every file in the snapshot +/// directory. current one reaches the max size i.e. 64MB. Partitions allow a +/// single hash bucket to be consumed in parallel. Partition files are +/// compressed with the zstd compression format. State Snapshot Directory Layout +/// - snapshot/ +/// - epoch_0/ +/// - 1_1.obj +/// - 1_2.obj +/// - 1_3.obj +/// - 2_1.obj +/// - ... +/// - 1000_1.obj +/// - REFERENCE-1 +/// - REFERENCE-2 +/// - ... +/// - REFERENCE-1000 +/// - MANIFEST +/// - epoch_1/ +/// - 1_1.obj +/// - ... +/// Object File Disk Format +/// ┌──────────────────────────────┐ +/// │ magic(0x00B7EC75) <4 byte> │ +/// ├──────────────────────────────┤ +/// │ ┌──────────────────────────┐ │ +/// │ │ Object 1 │ │ +/// │ ├──────────────────────────┤ │ +/// │ │ ... │ │ +/// │ ├──────────────────────────┤ │ +/// │ │ Object N │ │ +/// │ └──────────────────────────┘ │ +/// └──────────────────────────────┘ +/// Object +/// ┌───────────────┬───────────────────┬──────────────┐ +/// │ len │ encoding <1 byte> │ data │ +/// └───────────────┴───────────────────┴──────────────┘ +/// +/// REFERENCE File Disk Format +/// ┌──────────────────────────────┐ +/// │ magic(0x5EFE5E11) <4 byte> │ +/// ├──────────────────────────────┤ +/// │ ┌──────────────────────────┐ │ +/// │ │ ObjectRef 1 │ │ +/// │ ├──────────────────────────┤ │ +/// │ │ ... │ │ +/// │ ├──────────────────────────┤ │ +/// │ │ ObjectRef N │ │ +/// │ └──────────────────────────┘ │ +/// └──────────────────────────────┘ +/// ObjectRef (ObjectID, SequenceNumber, ObjectDigest) +/// ┌───────────────┬───────────────────┬──────────────┐ +/// │ data (<(address_len + 8 + 32) bytes>) │ +/// └───────────────┴───────────────────┴──────────────┘ +/// +/// MANIFEST File Disk Format +/// ┌──────────────────────────────┐ +/// │ magic(0x00C0FFEE) <4 byte> │ +/// ├──────────────────────────────┤ +/// │ serialized manifest │ +/// ├──────────────────────────────┤ +/// │ sha3 <32 bytes> │ +/// └──────────────────────────────┘ +const OBJECT_FILE_MAGIC: u32 = 0x00B7EC75; +const REFERENCE_FILE_MAGIC: u32 = 0xDEADBEEF; +const MANIFEST_FILE_MAGIC: u32 = 0x00C0FFEE; +const MAGIC_BYTES: usize = 4; +const SNAPSHOT_VERSION_BYTES: usize = 1; +const ADDRESS_LENGTH_BYTES: usize = 8; +const PADDING_BYTES: usize = 3; +const MANIFEST_FILE_HEADER_BYTES: usize = + MAGIC_BYTES + SNAPSHOT_VERSION_BYTES + ADDRESS_LENGTH_BYTES + PADDING_BYTES; +const FILE_MAX_BYTES: usize = 128 * 1024 * 1024; +const OBJECT_ID_BYTES: usize = ObjectID::LENGTH; +const SEQUENCE_NUM_BYTES: usize = 8; +const OBJECT_DIGEST_BYTES: usize = 32; +const OBJECT_REF_BYTES: usize = OBJECT_ID_BYTES + SEQUENCE_NUM_BYTES + OBJECT_DIGEST_BYTES; +const FILE_TYPE_BYTES: usize = 1; +const BUCKET_BYTES: usize = 4; +const BUCKET_PARTITION_BYTES: usize = 4; +const COMPRESSION_TYPE_BYTES: usize = 1; +const FILE_METADATA_BYTES: usize = + FILE_TYPE_BYTES + BUCKET_BYTES + BUCKET_PARTITION_BYTES + COMPRESSION_TYPE_BYTES + SHA3_BYTES; + +#[derive( + Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, TryFromPrimitive, IntoPrimitive, +)] +#[repr(u8)] +pub enum FileType { + Object = 0, + Reference, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +pub struct FileMetadata { + pub file_type: FileType, + pub bucket_num: u32, + pub part_num: u32, + pub file_compression: FileCompression, + pub sha3_digest: [u8; 32], +} + +impl FileMetadata { + pub fn file_path(&self, dir_path: &Path) -> Path { + match self.file_type { + FileType::Object => { + dir_path.child(&*format!("{}_{}.obj", self.bucket_num, self.part_num)) + } + FileType::Reference => { + dir_path.child(&*format!("{}_{}.ref", self.bucket_num, self.part_num)) + } + } + } + pub fn local_file_path(&self, root_path: &std::path::Path, dir_path: &Path) -> Result { + path_to_filesystem(root_path.to_path_buf(), &self.file_path(dir_path)) + } +} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] +pub struct ManifestV1 { + pub snapshot_version: u8, + pub address_length: u64, + pub file_metadata: Vec, + pub epoch: u64, +} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] +pub enum Manifest { + V1(ManifestV1), +} + +impl Manifest { + pub fn snapshot_version(&self) -> u8 { + match self { + Self::V1(manifest) => manifest.snapshot_version, + } + } + pub fn address_length(&self) -> u64 { + match self { + Self::V1(manifest) => manifest.address_length, + } + } + pub fn file_metadata(&self) -> &Vec { + match self { + Self::V1(manifest) => &manifest.file_metadata, + } + } + pub fn epoch(&self) -> u64 { + match self { + Self::V1(manifest) => manifest.epoch, + } + } +} + +pub fn create_file_metadata( + file_path: &std::path::Path, + file_compression: FileCompression, + file_type: FileType, + bucket_num: u32, + part_num: u32, +) -> Result { + file_compression.compress(file_path)?; + let sha3_digest = compute_sha3_checksum(file_path)?; + let file_metadata = FileMetadata { + file_type, + bucket_num, + part_num, + file_compression, + sha3_digest, + }; + Ok(file_metadata) +} + +pub async fn setup_db_state( + epoch: u64, + accumulator: Accumulator, + perpetual_db: Arc, + checkpoint_store: Arc, + committee_store: Arc, +) -> Result<()> { + // This function should be called once state accumulator based hash verification + // is complete and live object set state is downloaded to local store + let system_state_object = get_iota_system_state(&perpetual_db)?; + let new_epoch_start_state = system_state_object.into_epoch_start_state(); + let next_epoch_committee = new_epoch_start_state.get_iota_committee(); + let last_checkpoint = checkpoint_store + .get_epoch_last_checkpoint(epoch) + .expect("Error loading last checkpoint for current epoch") + .expect("Could not load last checkpoint for current epoch"); + let epoch_start_configuration = EpochStartConfiguration::new( + new_epoch_start_state, + *last_checkpoint.digest(), + &perpetual_db, + None, + ) + .unwrap(); + perpetual_db.set_epoch_start_configuration(&epoch_start_configuration)?; + perpetual_db.insert_root_state_hash(epoch, last_checkpoint.sequence_number, accumulator)?; + perpetual_db.set_highest_pruned_checkpoint_without_wb(last_checkpoint.sequence_number)?; + committee_store.insert_new_committee(&next_epoch_committee)?; + checkpoint_store.update_highest_executed_checkpoint(&last_checkpoint)?; + + Ok(()) +} diff --git a/crates/iota-snapshot/src/reader.rs b/crates/iota-snapshot/src/reader.rs new file mode 100644 index 00000000000..6bffcee30c9 --- /dev/null +++ b/crates/iota-snapshot/src/reader.rs @@ -0,0 +1,611 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::BTreeMap, + fs, + fs::File, + io::{BufReader, Read, Seek, SeekFrom}, + num::NonZeroUsize, + path::PathBuf, + sync::{ + atomic::{AtomicU64, AtomicUsize, Ordering}, + Arc, + }, +}; + +use anyhow::{anyhow, Context, Result}; +use byteorder::{BigEndian, ReadBytesExt}; +use bytes::{Buf, Bytes}; +use fastcrypto::hash::{HashFunction, MultisetHash, Sha3_256}; +use futures::{ + future::{AbortRegistration, Abortable}, + StreamExt, TryStreamExt, +}; +use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; +use integer_encoding::VarIntReader; +use iota_config::object_storage_config::ObjectStoreConfig; +use iota_core::authority::{ + authority_store_tables::{AuthorityPerpetualTables, LiveObject}, + AuthorityStore, +}; +use iota_storage::{ + blob::{Blob, BlobEncoding}, + object_store::{ + http::HttpDownloaderBuilder, + util::{copy_file, copy_files, path_to_filesystem}, + ObjectStoreGetExt, ObjectStorePutExt, + }, +}; +use iota_types::{ + accumulator::Accumulator, + base_types::{ObjectDigest, ObjectID, ObjectRef, SequenceNumber}, +}; +use object_store::path::Path; +use tokio::{ + sync::Mutex, + task::JoinHandle, + time::{Duration, Instant}, +}; +use tracing::{error, info}; + +use crate::{ + FileMetadata, FileType, Manifest, MAGIC_BYTES, MANIFEST_FILE_MAGIC, OBJECT_FILE_MAGIC, + OBJECT_ID_BYTES, OBJECT_REF_BYTES, REFERENCE_FILE_MAGIC, SEQUENCE_NUM_BYTES, SHA3_BYTES, +}; + +pub type SnapshotChecksums = (DigestByBucketAndPartition, Accumulator); +pub type DigestByBucketAndPartition = BTreeMap>; +pub struct StateSnapshotReaderV1 { + epoch: u64, + local_staging_dir_root: PathBuf, + remote_object_store: Arc, + local_object_store: Arc, + ref_files: BTreeMap>, + object_files: BTreeMap>, + indirect_objects_threshold: usize, + m: MultiProgress, + concurrency: usize, +} + +impl StateSnapshotReaderV1 { + pub async fn new( + epoch: u64, + remote_store_config: &ObjectStoreConfig, + local_store_config: &ObjectStoreConfig, + indirect_objects_threshold: usize, + download_concurrency: NonZeroUsize, + m: MultiProgress, + ) -> Result { + let epoch_dir = format!("epoch_{}", epoch); + let remote_object_store = if remote_store_config.no_sign_request { + remote_store_config.make_http()? + } else { + remote_store_config.make().map(Arc::new)? + }; + let local_object_store: Arc = + local_store_config.make().map(Arc::new)?; + let local_staging_dir_root = local_store_config + .directory + .as_ref() + .context("No directory specified")? + .clone(); + let local_epoch_dir_path = local_staging_dir_root.join(&epoch_dir); + if local_epoch_dir_path.exists() { + fs::remove_dir_all(&local_epoch_dir_path)?; + } + fs::create_dir_all(&local_epoch_dir_path)?; + // Download MANIFEST first + let manifest_file_path = Path::from(epoch_dir.clone()).child("MANIFEST"); + copy_file( + &manifest_file_path, + &manifest_file_path, + &remote_object_store, + &local_object_store, + ) + .await?; + let manifest = Self::read_manifest(path_to_filesystem( + local_staging_dir_root.clone(), + &manifest_file_path, + )?)?; + let snapshot_version = manifest.snapshot_version(); + if snapshot_version != 1u8 { + return Err(anyhow!("Unexpected snapshot version: {}", snapshot_version)); + } + if manifest.address_length() as usize > ObjectID::LENGTH { + return Err(anyhow!( + "Max possible address length is: {}", + ObjectID::LENGTH + )); + } + if manifest.epoch() != epoch { + return Err(anyhow!("Download manifest is not for epoch: {}", epoch,)); + } + let mut object_files = BTreeMap::new(); + let mut ref_files = BTreeMap::new(); + for file_metadata in manifest.file_metadata() { + match file_metadata.file_type { + FileType::Object => { + let entry = object_files + .entry(file_metadata.bucket_num) + .or_insert_with(BTreeMap::new); + entry.insert(file_metadata.part_num, file_metadata.clone()); + } + FileType::Reference => { + let entry = ref_files + .entry(file_metadata.bucket_num) + .or_insert_with(BTreeMap::new); + entry.insert(file_metadata.part_num, file_metadata.clone()); + } + } + } + let epoch_dir_path = Path::from(epoch_dir); + let files: Vec = ref_files + .values() + .flat_map(|entry| { + let files: Vec<_> = entry + .values() + .map(|file_metadata| file_metadata.file_path(&epoch_dir_path)) + .collect(); + files + }) + .collect(); + + let progress_bar = m.add( + ProgressBar::new(files.len() as u64).with_style( + ProgressStyle::with_template( + "[{elapsed_precise}] {wide_bar} {pos} out of {len} .ref files done\n({msg})", + ) + .unwrap(), + ), + ); + copy_files( + &files, + &files, + &remote_object_store, + &local_object_store, + download_concurrency, + Some(progress_bar.clone()), + ) + .await?; + progress_bar.finish_with_message("ref files download complete"); + Ok(StateSnapshotReaderV1 { + epoch, + local_staging_dir_root, + remote_object_store, + local_object_store, + ref_files, + object_files, + indirect_objects_threshold, + m, + concurrency: download_concurrency.get(), + }) + } + + pub async fn read( + &mut self, + perpetual_db: &AuthorityPerpetualTables, + abort_registration: AbortRegistration, + sender: Option>, + ) -> Result<()> { + // This computes and stores the sha3 digest of object references in REFERENCE + // file for each bucket partition. When downloading objects, we will + // match sha3 digest of object references per *.obj file against this. + // We do this so during restore we can pre fetch object references and + // start building state accumulator and fail early if the state root hash + // doesn't match but we still need to ensure that objects match references + // exactly. + let sha3_digests: Arc> = + Arc::new(Mutex::new(BTreeMap::new())); + + let num_part_files = self + .ref_files + .values() + .map(|part_files| part_files.len()) + .sum::(); + + // Generate checksums + info!("Computing checksums"); + let checksum_progress_bar = self.m.add( + ProgressBar::new(num_part_files as u64).with_style( + ProgressStyle::with_template( + "[{elapsed_precise}] {wide_bar} {pos} out of {len} ref files checksummed ({msg})", + ) + .unwrap(), + ), + ); + + for (bucket, part_files) in self.ref_files.clone().iter() { + for (part, _part_file) in part_files.iter() { + let mut sha3_digests = sha3_digests.lock().await; + let ref_iter = self.ref_iter(*bucket, *part)?; + let mut hasher = Sha3_256::default(); + let mut empty = true; + self.object_files + .get(bucket) + .context(format!("No bucket exists for: {bucket}"))? + .get(part) + .context(format!("No part exists for bucket: {bucket}, part: {part}"))?; + for object_ref in ref_iter { + hasher.update(object_ref.2.inner()); + empty = false; + } + if !empty { + sha3_digests + .entry(*bucket) + .or_insert(BTreeMap::new()) + .entry(*part) + .or_insert(hasher.finalize().digest); + } + checksum_progress_bar.inc(1); + checksum_progress_bar.set_message(format!("Bucket: {}, Part: {}", bucket, part)); + } + } + checksum_progress_bar.finish_with_message("Checksumming complete"); + + let accum_handle = + sender.map(|sender| self.spawn_accumulation_tasks(sender, num_part_files)); + + self.sync_live_objects(perpetual_db, abort_registration, sha3_digests) + .await?; + + if let Some(handle) = accum_handle { + handle.await?; + } + Ok(()) + } + + fn spawn_accumulation_tasks( + &self, + sender: tokio::sync::mpsc::Sender, + num_part_files: usize, + ) -> JoinHandle<()> { + // Spawn accumulation progress bar + let concurrency = self.concurrency; + let accum_counter = Arc::new(AtomicU64::new(0)); + let cloned_accum_counter = accum_counter.clone(); + let accum_progress_bar = self.m.add( + ProgressBar::new(num_part_files as u64).with_style( + ProgressStyle::with_template( + "[{elapsed_precise}] {wide_bar} {pos} out of {len} ref files accumulated ({msg})", + ) + .unwrap(), + ), + ); + let cloned_accum_progress_bar = accum_progress_bar.clone(); + tokio::spawn(async move { + let a_instant = Instant::now(); + loop { + if cloned_accum_progress_bar.is_finished() { + break; + } + let num_partitions = cloned_accum_counter.load(Ordering::Relaxed); + let total_partitions_per_sec = + num_partitions as f64 / a_instant.elapsed().as_secs_f64(); + cloned_accum_progress_bar.set_position(num_partitions); + cloned_accum_progress_bar.set_message(format!( + "file partitions per sec: {}", + total_partitions_per_sec + )); + tokio::time::sleep(Duration::from_secs(1)).await; + } + }); + + // spawn accumualation task + let ref_files = self.ref_files.clone(); + let epoch_dir = self.epoch_dir(); + let local_staging_dir_root = self.local_staging_dir_root.clone(); + tokio::task::spawn(async move { + let local_staging_dir_root_clone = local_staging_dir_root.clone(); + let epoch_dir_clone = epoch_dir.clone(); + for (bucket, part_files) in ref_files.clone().iter() { + futures::stream::iter(part_files.iter()) + .map(|(part, _part_files)| { + // TODO depending on concurrency limit here, we may be + // materializing too many refs into memory at once. + // This is only done because ObjectRefIter is not Send + let obj_digests = { + let file_metadata = ref_files + .get(bucket) + .expect("No ref files found for bucket: {bucket_num}") + .get(part) + .expect( + "No ref files found for bucket: {bucket_num}, part: {part_num}", + ); + ObjectRefIter::new( + file_metadata, + local_staging_dir_root_clone.clone(), + epoch_dir_clone.clone(), + ) + .expect("Failed to create object ref iter") + } + .map(|obj_ref| obj_ref.2) + .collect::>(); + let sender_clone = sender.clone(); + tokio::spawn(async move { + let mut partial_acc = Accumulator::default(); + partial_acc.insert_all(obj_digests); + sender_clone + .send(partial_acc) + .await + .expect("Unable to send accumulator from snapshot reader"); + }) + }) + .boxed() + .buffer_unordered(concurrency) + .for_each(|result| { + result.expect("Failed to generate partial accumulator"); + accum_counter.fetch_add(1, Ordering::Relaxed); + futures::future::ready(()) + }) + .await; + } + accum_progress_bar.finish_with_message("Accumulation complete"); + }) + } + + async fn sync_live_objects( + &self, + perpetual_db: &AuthorityPerpetualTables, + abort_registration: AbortRegistration, + sha3_digests: Arc>, + ) -> Result<(), anyhow::Error> { + let epoch_dir = self.epoch_dir(); + let concurrency = self.concurrency; + let threshold = self.indirect_objects_threshold; + let remote_object_store = self.remote_object_store.clone(); + let input_files: Vec<_> = self + .object_files + .iter() + .flat_map(|(bucket, parts)| { + parts + .clone() + .into_iter() + .map(|entry| (bucket, entry)) + .collect::>() + }) + .collect(); + let obj_progress_bar = self.m.add( + ProgressBar::new(input_files.len() as u64).with_style( + ProgressStyle::with_template( + "[{elapsed_precise}] {wide_bar} {pos} out of {len} .obj files done\n({msg})", + ) + .unwrap(), + ), + ); + let obj_progress_bar_clone = obj_progress_bar.clone(); + let instant = Instant::now(); + let downloaded_bytes = AtomicUsize::new(0); + + let ret = Abortable::new( + async move { + futures::stream::iter(input_files.iter()) + .map(|(bucket, (part_num, file_metadata))| { + let epoch_dir = epoch_dir.clone(); + let file_path = file_metadata.file_path(&epoch_dir); + let remote_object_store = remote_object_store.clone(); + let sha3_digests_cloned = sha3_digests.clone(); + async move { + // Download object file with retries + let max_timeout = Duration::from_secs(30); + let mut timeout = Duration::from_secs(2); + timeout += timeout / 2; + timeout = std::cmp::min(max_timeout, timeout); + let mut attempts = 0usize; + let bytes = loop { + match remote_object_store.get_bytes(&file_path).await { + Ok(bytes) => { + break bytes; + } + Err(err) => { + error!( + "Obj {} .get failed (attempt {}): {}", + file_metadata.file_path(&epoch_dir), + attempts, + err, + ); + if timeout > max_timeout { + panic!( + "Failed to get obj file after {} attempts", + attempts + ); + } else { + attempts += 1; + tokio::time::sleep(timeout).await; + timeout += timeout / 2; + continue; + } + } + } + }; + + let sha3_digest = sha3_digests_cloned.lock().await; + let bucket_map = sha3_digest + .get(bucket) + .expect("Bucket not in digest map") + .clone(); + let sha3_digest = *bucket_map + .get(part_num) + .expect("sha3 digest not in bucket map"); + Ok::<(Bytes, FileMetadata, [u8; 32]), anyhow::Error>(( + bytes, + (*file_metadata).clone(), + sha3_digest, + )) + } + }) + .boxed() + .buffer_unordered(concurrency) + .try_for_each(|(bytes, file_metadata, sha3_digest)| { + let bytes_len = bytes.len(); + let result: Result<(), anyhow::Error> = + LiveObjectIter::new(&file_metadata, bytes).map(|obj_iter| { + AuthorityStore::bulk_insert_live_objects( + perpetual_db, + obj_iter, + threshold, + &sha3_digest, + ) + .expect("Failed to insert live objects"); + }); + downloaded_bytes.fetch_add(bytes_len, Ordering::Relaxed); + obj_progress_bar_clone.inc(1); + obj_progress_bar_clone.set_message(format!( + "Download speed: {} MiB/s", + downloaded_bytes.load(Ordering::Relaxed) as f64 + / (1024 * 1024) as f64 + / instant.elapsed().as_secs_f64(), + )); + futures::future::ready(result) + }) + .await + }, + abort_registration, + ) + .await?; + obj_progress_bar.finish_with_message("Objects download complete"); + ret + } + + pub fn ref_iter(&self, bucket_num: u32, part_num: u32) -> Result { + let file_metadata = self + .ref_files + .get(&bucket_num) + .context(format!("No ref files found for bucket: {bucket_num}"))? + .get(&part_num) + .context(format!( + "No ref files found for bucket: {bucket_num}, part: {part_num}" + ))?; + ObjectRefIter::new( + file_metadata, + self.local_staging_dir_root.clone(), + self.epoch_dir(), + ) + } + + fn buckets(&self) -> Result> { + Ok(self.ref_files.keys().copied().collect()) + } + + fn epoch_dir(&self) -> Path { + Path::from(format!("epoch_{}", self.epoch)) + } + + fn read_manifest(path: PathBuf) -> anyhow::Result { + let manifest_file = File::open(path)?; + let manifest_file_size = manifest_file.metadata()?.len() as usize; + let mut manifest_reader = BufReader::new(manifest_file); + manifest_reader.rewind()?; + let magic = manifest_reader.read_u32::()?; + if magic != MANIFEST_FILE_MAGIC { + return Err(anyhow!("Unexpected magic byte: {}", magic)); + } + manifest_reader.seek(SeekFrom::End(-(SHA3_BYTES as i64)))?; + let mut sha3_digest = [0u8; SHA3_BYTES]; + manifest_reader.read_exact(&mut sha3_digest)?; + manifest_reader.rewind()?; + let mut content_buf = vec![0u8; manifest_file_size - SHA3_BYTES]; + manifest_reader.read_exact(&mut content_buf)?; + let mut hasher = Sha3_256::default(); + hasher.update(&content_buf); + let computed_digest = hasher.finalize().digest; + if computed_digest != sha3_digest { + return Err(anyhow!( + "Checksum: {:?} don't match: {:?}", + computed_digest, + sha3_digest + )); + } + manifest_reader.rewind()?; + manifest_reader.seek(SeekFrom::Start(MAGIC_BYTES as u64))?; + let manifest = bcs::from_bytes(&content_buf[MAGIC_BYTES..])?; + Ok(manifest) + } +} + +/// An iterator over all object refs in a .ref file. +pub struct ObjectRefIter { + reader: Box, +} + +impl ObjectRefIter { + pub fn new(file_metadata: &FileMetadata, root_path: PathBuf, dir_path: Path) -> Result { + let file_path = file_metadata.local_file_path(&root_path, &dir_path)?; + let mut reader = file_metadata.file_compression.decompress(&file_path)?; + let magic = reader.read_u32::()?; + if magic != REFERENCE_FILE_MAGIC { + Err(anyhow!( + "Unexpected magic string in REFERENCE file: {:?}", + magic + )) + } else { + Ok(ObjectRefIter { reader }) + } + } + + fn next_ref(&mut self) -> Result { + let mut buf = [0u8; OBJECT_REF_BYTES]; + self.reader.read_exact(&mut buf)?; + let object_id = &buf[0..OBJECT_ID_BYTES]; + let sequence_number = &buf[OBJECT_ID_BYTES..OBJECT_ID_BYTES + SEQUENCE_NUM_BYTES] + .reader() + .read_u64::()?; + let sha3_digest = &buf[OBJECT_ID_BYTES + SEQUENCE_NUM_BYTES..OBJECT_REF_BYTES]; + let object_ref: ObjectRef = ( + ObjectID::from_bytes(object_id)?, + SequenceNumber::from_u64(*sequence_number), + ObjectDigest::try_from(sha3_digest)?, + ); + Ok(object_ref) + } +} + +impl Iterator for ObjectRefIter { + type Item = ObjectRef; + fn next(&mut self) -> Option { + self.next_ref().ok() + } +} + +/// An iterator over all objects in a *.obj file. +pub struct LiveObjectIter { + reader: Box, +} + +impl LiveObjectIter { + pub fn new(file_metadata: &FileMetadata, bytes: Bytes) -> Result { + let mut reader = file_metadata.file_compression.bytes_decompress(bytes)?; + let magic = reader.read_u32::()?; + if magic != OBJECT_FILE_MAGIC { + Err(anyhow!( + "Unexpected magic string in object file: {:?}", + magic + )) + } else { + Ok(LiveObjectIter { reader }) + } + } + + fn next_object(&mut self) -> Result { + let len = self.reader.read_varint::()? as usize; + if len == 0 { + return Err(anyhow!("Invalid object length of 0 in file")); + } + let encoding = self.reader.read_u8()?; + let mut data = vec![0u8; len]; + self.reader.read_exact(&mut data)?; + let blob = Blob { + data, + encoding: BlobEncoding::try_from(encoding)?, + }; + blob.decode() + } +} + +impl Iterator for LiveObjectIter { + type Item = LiveObject; + fn next(&mut self) -> Option { + self.next_object().ok() + } +} diff --git a/crates/iota-snapshot/src/tests.rs b/crates/iota-snapshot/src/tests.rs new file mode 100644 index 00000000000..c3a708ae08d --- /dev/null +++ b/crates/iota-snapshot/src/tests.rs @@ -0,0 +1,160 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::HashSet, num::NonZeroUsize, sync::Arc}; + +use futures::future::AbortHandle; +use indicatif::MultiProgress; +use iota_config::object_storage_config::{ObjectStoreConfig, ObjectStoreType}; +use iota_core::authority::authority_store_tables::AuthorityPerpetualTables; +use iota_protocol_config::ProtocolConfig; +use iota_types::{base_types::ObjectID, object::Object}; +use tempfile::tempdir; + +use crate::{reader::StateSnapshotReaderV1, writer::StateSnapshotWriterV1, FileCompression}; + +fn temp_dir() -> std::path::PathBuf { + tempdir() + .expect("Failed to open temporary directory") + .into_path() +} + +pub fn insert_keys( + db: &AuthorityPerpetualTables, + total_unique_object_ids: u64, +) -> Result<(), anyhow::Error> { + let ids = ObjectID::in_range(ObjectID::ZERO, total_unique_object_ids)?; + for id in ids { + let object = Object::immutable_with_id_for_testing(id); + db.insert_object_test_only(object)?; + } + Ok(()) +} + +fn compare_live_objects( + db1: &AuthorityPerpetualTables, + db2: &AuthorityPerpetualTables, + include_wrapped_tombstone: bool, +) -> Result<(), anyhow::Error> { + let mut object_set_1 = HashSet::new(); + let mut object_set_2 = HashSet::new(); + for live_object in db1.iter_live_object_set(include_wrapped_tombstone) { + object_set_1.insert(live_object.object_reference()); + } + for live_object in db2.iter_live_object_set(include_wrapped_tombstone) { + object_set_2.insert(live_object.object_reference()); + } + assert_eq!(object_set_1, object_set_2); + Ok(()) +} + +#[tokio::test] +async fn test_snapshot_basic() -> Result<(), anyhow::Error> { + let db_path = temp_dir(); + let restored_db_path = temp_dir(); + let local = temp_dir().join("local_dir"); + let remote = temp_dir().join("remote_dir"); + let restored_local = temp_dir().join("local_dir_restore"); + let local_store_config = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(local), + ..Default::default() + }; + let remote_store_config = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(remote), + ..Default::default() + }; + + let snapshot_writer = StateSnapshotWriterV1::new( + &local_store_config, + &remote_store_config, + FileCompression::Zstd, + NonZeroUsize::new(1).unwrap(), + ) + .await?; + let perpetual_db = Arc::new(AuthorityPerpetualTables::open(&db_path, None)); + insert_keys(&perpetual_db, 1000)?; + snapshot_writer + .write_internal(0, true, perpetual_db.clone()) + .await?; + let local_store_restore_config = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(restored_local), + ..Default::default() + }; + let mut snapshot_reader = StateSnapshotReaderV1::new( + 0, + &remote_store_config, + &local_store_restore_config, + usize::MAX, + NonZeroUsize::new(1).unwrap(), + MultiProgress::new(), + ) + .await?; + let restored_perpetual_db = AuthorityPerpetualTables::open(&restored_db_path, None); + let (_abort_handle, abort_registration) = AbortHandle::new_pair(); + snapshot_reader + .read(&restored_perpetual_db, abort_registration, None) + .await?; + compare_live_objects(&perpetual_db, &restored_perpetual_db, true)?; + Ok(()) +} + +#[tokio::test] +async fn test_snapshot_empty_db() -> Result<(), anyhow::Error> { + let db_path = temp_dir(); + let restored_db_path = temp_dir(); + let local = temp_dir().join("local_dir"); + let remote = temp_dir().join("remote_dir"); + let restored_local = temp_dir().join("local_dir_restore"); + let local_store_config = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(local), + ..Default::default() + }; + let remote_store_config = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(remote), + ..Default::default() + }; + let include_wrapped_tombstone = + !ProtocolConfig::get_for_max_version_UNSAFE().simplified_unwrap_then_delete(); + let snapshot_writer = StateSnapshotWriterV1::new( + &local_store_config, + &remote_store_config, + FileCompression::Zstd, + NonZeroUsize::new(1).unwrap(), + ) + .await?; + let perpetual_db = Arc::new(AuthorityPerpetualTables::open(&db_path, None)); + snapshot_writer + .write_internal(0, true, perpetual_db.clone()) + .await?; + let local_store_restore_config = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(restored_local), + ..Default::default() + }; + let mut snapshot_reader = StateSnapshotReaderV1::new( + 0, + &remote_store_config, + &local_store_restore_config, + usize::MAX, + NonZeroUsize::new(1).unwrap(), + MultiProgress::new(), + ) + .await?; + let restored_perpetual_db = AuthorityPerpetualTables::open(&restored_db_path, None); + let (_abort_handle, abort_registration) = AbortHandle::new_pair(); + snapshot_reader + .read(&restored_perpetual_db, abort_registration, None) + .await?; + compare_live_objects( + &perpetual_db, + &restored_perpetual_db, + include_wrapped_tombstone, + )?; + Ok(()) +} diff --git a/crates/sui-snapshot/src/uploader.rs b/crates/iota-snapshot/src/uploader.rs similarity index 97% rename from crates/sui-snapshot/src/uploader.rs rename to crates/iota-snapshot/src/uploader.rs index a7935369370..517bffbece9 100644 --- a/crates/sui-snapshot/src/uploader.rs +++ b/crates/iota-snapshot/src/uploader.rs @@ -1,24 +1,25 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{num::NonZeroUsize, path::PathBuf, sync::Arc, time::Duration}; use anyhow::Result; use bytes::Bytes; -use object_store::DynObjectStore; -use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; -use sui_config::object_storage_config::{ObjectStoreConfig, ObjectStoreType}; -use sui_core::{ +use iota_config::object_storage_config::{ObjectStoreConfig, ObjectStoreType}; +use iota_core::{ authority::authority_store_tables::AuthorityPerpetualTables, db_checkpoint_handler::{STATE_SNAPSHOT_COMPLETED_MARKER, SUCCESS_MARKER}, }; -use sui_storage::{ +use iota_storage::{ object_store::util::{ find_all_dirs_with_epoch_prefix, find_missing_epochs_dirs, path_to_filesystem, put, run_manifest_update_loop, }, FileCompression, }; +use object_store::DynObjectStore; +use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; use tracing::{debug, error, info}; use crate::writer::StateSnapshotWriterV1; diff --git a/crates/iota-snapshot/src/writer.rs b/crates/iota-snapshot/src/writer.rs new file mode 100644 index 00000000000..039864f7b78 --- /dev/null +++ b/crates/iota-snapshot/src/writer.rs @@ -0,0 +1,491 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +#![allow(dead_code)] + +use std::{ + collections::{hash_map::Entry::Vacant, HashMap}, + fs, + fs::{File, OpenOptions}, + io::{BufWriter, Seek, SeekFrom, Write}, + num::NonZeroUsize, + path::PathBuf, + sync::Arc, +}; + +use anyhow::{anyhow, Context, Result}; +use byteorder::{BigEndian, ByteOrder}; +use futures::StreamExt; +use integer_encoding::VarInt; +use iota_config::object_storage_config::ObjectStoreConfig; +use iota_core::authority::{ + authority_store_tables::{AuthorityPerpetualTables, LiveObject}, + CHAIN_IDENTIFIER, +}; +use iota_protocol_config::{ProtocolConfig, ProtocolVersion}; +use iota_storage::{ + blob::{Blob, BlobEncoding, BLOB_ENCODING_BYTES}, + object_store::util::{copy_file, delete_recursively, path_to_filesystem}, +}; +use iota_types::{ + base_types::{ObjectID, ObjectRef}, + iota_system_state::{get_iota_system_state, IotaSystemStateTrait}, +}; +use object_store::{path::Path, DynObjectStore}; +use tokio::{ + sync::{ + mpsc, + mpsc::{Receiver, Sender}, + }, + task::JoinHandle, +}; +use tokio_stream::wrappers::ReceiverStream; +use tracing::debug; + +use crate::{ + compute_sha3_checksum, create_file_metadata, FileCompression, FileMetadata, FileType, Manifest, + ManifestV1, FILE_MAX_BYTES, MAGIC_BYTES, MANIFEST_FILE_MAGIC, OBJECT_FILE_MAGIC, + OBJECT_REF_BYTES, REFERENCE_FILE_MAGIC, SEQUENCE_NUM_BYTES, +}; + +/// LiveObjectSetWriterV1 writes live object set. It creates multiple *.obj +/// files and *.ref file +struct LiveObjectSetWriterV1 { + dir_path: PathBuf, + bucket_num: u32, + current_part_num: u32, + wbuf: BufWriter, + ref_wbuf: BufWriter, + n: usize, + files: Vec, + sender: Option>, + file_compression: FileCompression, +} + +impl LiveObjectSetWriterV1 { + fn new( + dir_path: PathBuf, + bucket_num: u32, + file_compression: FileCompression, + sender: Sender, + ) -> Result { + let part_num = 1; + let (n, obj_file) = Self::object_file(dir_path.clone(), bucket_num, part_num)?; + let ref_file = Self::ref_file(dir_path.clone(), bucket_num, part_num)?; + Ok(LiveObjectSetWriterV1 { + dir_path, + bucket_num, + current_part_num: part_num, + wbuf: BufWriter::new(obj_file), + ref_wbuf: BufWriter::new(ref_file), + n, + files: vec![], + sender: Some(sender), + file_compression, + }) + } + pub fn write(&mut self, object: &LiveObject) -> Result<()> { + let object_reference = object.object_reference(); + self.write_object(object)?; + self.write_object_ref(&object_reference)?; + Ok(()) + } + pub fn done(mut self) -> Result> { + self.finalize()?; + self.finalize_ref()?; + self.sender = None; + Ok(self.files.clone()) + } + fn object_file(dir_path: PathBuf, bucket_num: u32, part_num: u32) -> Result<(usize, File)> { + let next_part_file_path = dir_path.join(format!("{bucket_num}_{part_num}.obj")); + let next_part_file_tmp_path = dir_path.join(format!("{bucket_num}_{part_num}.obj.tmp")); + let mut f = File::create(next_part_file_tmp_path.clone())?; + let mut metab = [0u8; MAGIC_BYTES]; + BigEndian::write_u32(&mut metab, OBJECT_FILE_MAGIC); + f.rewind()?; + let n = f.write(&metab)?; + drop(f); + fs::rename(next_part_file_tmp_path, next_part_file_path.clone())?; + let mut f = OpenOptions::new().append(true).open(next_part_file_path)?; + f.seek(SeekFrom::Start(n as u64))?; + Ok((n, f)) + } + fn ref_file(dir_path: PathBuf, bucket_num: u32, part_num: u32) -> Result { + let ref_path = dir_path.join(format!("{bucket_num}_{part_num}.ref")); + let ref_tmp_path = dir_path.join(format!("{bucket_num}_{part_num}.ref.tmp")); + let mut f = File::create(ref_tmp_path.clone())?; + f.rewind()?; + let mut metab = [0u8; MAGIC_BYTES]; + BigEndian::write_u32(&mut metab, REFERENCE_FILE_MAGIC); + let n = f.write(&metab)?; + drop(f); + fs::rename(ref_tmp_path, ref_path.clone())?; + let mut f = OpenOptions::new().append(true).open(ref_path)?; + f.seek(SeekFrom::Start(n as u64))?; + Ok(f) + } + fn finalize(&mut self) -> Result<()> { + self.wbuf.flush()?; + self.wbuf.get_ref().sync_data()?; + let off = self.wbuf.get_ref().stream_position()?; + self.wbuf.get_ref().set_len(off)?; + let file_path = self + .dir_path + .join(format!("{}_{}.obj", self.bucket_num, self.current_part_num)); + let file_metadata = create_file_metadata( + &file_path, + self.file_compression, + FileType::Object, + self.bucket_num, + self.current_part_num, + )?; + self.files.push(file_metadata.clone()); + if let Some(sender) = &self.sender { + sender.blocking_send(file_metadata)?; + } + Ok(()) + } + fn finalize_ref(&mut self) -> Result<()> { + self.ref_wbuf.flush()?; + self.ref_wbuf.get_ref().sync_data()?; + let off = self.ref_wbuf.get_ref().stream_position()?; + self.ref_wbuf.get_ref().set_len(off)?; + let file_path = self + .dir_path + .join(format!("{}_{}.ref", self.bucket_num, self.current_part_num)); + let file_metadata = create_file_metadata( + &file_path, + self.file_compression, + FileType::Reference, + self.bucket_num, + self.current_part_num, + )?; + self.files.push(file_metadata.clone()); + if let Some(sender) = &self.sender { + sender.blocking_send(file_metadata)?; + } + Ok(()) + } + fn cut(&mut self) -> Result<()> { + self.finalize()?; + let (n, f) = Self::object_file( + self.dir_path.clone(), + self.bucket_num, + self.current_part_num + 1, + )?; + self.n = n; + self.wbuf = BufWriter::new(f); + Ok(()) + } + fn cut_reference_file(&mut self) -> Result<()> { + self.finalize_ref()?; + let f = Self::ref_file( + self.dir_path.clone(), + self.bucket_num, + self.current_part_num + 1, + )?; + self.ref_wbuf = BufWriter::new(f); + Ok(()) + } + fn write_object(&mut self, object: &LiveObject) -> Result<()> { + let blob = Blob::encode(object, BlobEncoding::Bcs)?; + let mut blob_size = blob.data.len().required_space(); + blob_size += BLOB_ENCODING_BYTES; + blob_size += blob.data.len(); + let cut_new_part_file = (self.n + blob_size) > FILE_MAX_BYTES; + if cut_new_part_file { + self.cut()?; + self.cut_reference_file()?; + self.current_part_num += 1; + } + self.n += blob.write(&mut self.wbuf)?; + Ok(()) + } + fn write_object_ref(&mut self, object_ref: &ObjectRef) -> Result<()> { + let mut buf = [0u8; OBJECT_REF_BYTES]; + buf[0..ObjectID::LENGTH].copy_from_slice(object_ref.0.as_ref()); + BigEndian::write_u64( + &mut buf[ObjectID::LENGTH..OBJECT_REF_BYTES], + object_ref.1.value(), + ); + buf[ObjectID::LENGTH + SEQUENCE_NUM_BYTES..OBJECT_REF_BYTES] + .copy_from_slice(object_ref.2.as_ref()); + self.ref_wbuf.write_all(&buf)?; + Ok(()) + } +} + +/// StateSnapshotWriterV1 writes snapshot files to a local staging dir and +/// simultaneously uploads them to a remote object store +pub struct StateSnapshotWriterV1 { + local_staging_dir: PathBuf, + file_compression: FileCompression, + remote_object_store: Arc, + local_staging_store: Arc, + concurrency: usize, +} + +impl StateSnapshotWriterV1 { + pub async fn new_from_store( + local_staging_path: &std::path::Path, + local_staging_store: &Arc, + remote_object_store: &Arc, + file_compression: FileCompression, + concurrency: NonZeroUsize, + ) -> Result { + Ok(StateSnapshotWriterV1 { + file_compression, + local_staging_dir: local_staging_path.to_path_buf(), + remote_object_store: remote_object_store.clone(), + local_staging_store: local_staging_store.clone(), + concurrency: concurrency.get(), + }) + } + + pub async fn new( + local_store_config: &ObjectStoreConfig, + remote_store_config: &ObjectStoreConfig, + file_compression: FileCompression, + concurrency: NonZeroUsize, + ) -> Result { + let remote_object_store = remote_store_config.make()?; + let local_staging_store = local_store_config.make()?; + let local_staging_dir = local_store_config + .directory + .as_ref() + .context("No local directory specified")? + .clone(); + Ok(StateSnapshotWriterV1 { + local_staging_dir, + file_compression, + remote_object_store, + local_staging_store, + concurrency: concurrency.get(), + }) + } + + pub async fn write( + self, + epoch: u64, + perpetual_db: Arc, + ) -> Result<()> { + let system_state_object = get_iota_system_state(&perpetual_db)?; + + let protocol_version = system_state_object.protocol_version(); + let chain_identifier = CHAIN_IDENTIFIER + .get() + .ok_or(anyhow!("No chain identifier found"))?; + let protocol_config = ProtocolConfig::get_for_version( + ProtocolVersion::new(protocol_version), + chain_identifier.chain(), + ); + let include_wrapped_tombstone = !protocol_config.simplified_unwrap_then_delete(); + self.write_internal(epoch, include_wrapped_tombstone, perpetual_db) + .await + } + + pub(crate) async fn write_internal( + mut self, + epoch: u64, + include_wrapped_tombstone: bool, + perpetual_db: Arc, + ) -> Result<()> { + self.setup_epoch_dir(epoch).await?; + + let manifest_file_path = self.epoch_dir(epoch).child("MANIFEST"); + let local_staging_dir = self.local_staging_dir.clone(); + let local_object_store = self.local_staging_store.clone(); + let remote_object_store = self.remote_object_store.clone(); + + let (sender, receiver) = mpsc::channel::(1000); + let upload_handle = self.start_upload(epoch, receiver)?; + let write_handler = tokio::task::spawn_blocking(move || { + self.write_live_object_set( + epoch, + perpetual_db, + sender, + Self::bucket_func, + include_wrapped_tombstone, + ) + }); + write_handler.await?.context(format!( + "Failed to write state snapshot for epoch: {}", + &epoch + ))?; + + upload_handle.await?.context(format!( + "Failed to upload state snapshot for epoch: {}", + &epoch + ))?; + + Self::sync_file_to_remote( + local_staging_dir, + manifest_file_path, + local_object_store, + remote_object_store, + ) + .await?; + Ok(()) + } + + fn start_upload( + &self, + epoch: u64, + receiver: Receiver, + ) -> Result, anyhow::Error>>> { + let remote_object_store = self.remote_object_store.clone(); + let local_staging_store = self.local_staging_store.clone(); + let local_dir_path = self.local_staging_dir.clone(); + let epoch_dir = self.epoch_dir(epoch); + let upload_concurrency = self.concurrency; + let join_handle = tokio::spawn(async move { + let results: Vec> = ReceiverStream::new(receiver) + .map(|file_metadata| { + let file_path = file_metadata.file_path(&epoch_dir); + let remote_object_store = remote_object_store.clone(); + let local_object_store = local_staging_store.clone(); + let local_dir_path = local_dir_path.clone(); + async move { + Self::sync_file_to_remote( + local_dir_path.clone(), + file_path.clone(), + local_object_store.clone(), + remote_object_store.clone(), + ) + .await?; + Ok(()) + } + }) + .boxed() + .buffer_unordered(upload_concurrency) + .collect() + .await; + results + .into_iter() + .collect::, anyhow::Error>>() + }); + Ok(join_handle) + } + + fn write_live_object_set( + &mut self, + epoch: u64, + perpetual_db: Arc, + sender: Sender, + bucket_func: F, + include_wrapped_tombstone: bool, + ) -> Result<()> + where + F: Fn(&LiveObject) -> u32, + { + let mut object_writers: HashMap = HashMap::new(); + let local_staging_dir_path = + path_to_filesystem(self.local_staging_dir.clone(), &self.epoch_dir(epoch))?; + for object in perpetual_db.iter_live_object_set(include_wrapped_tombstone) { + let bucket_num = bucket_func(&object); + if let Vacant(entry) = object_writers.entry(bucket_num) { + entry.insert(LiveObjectSetWriterV1::new( + local_staging_dir_path.clone(), + bucket_num, + self.file_compression, + sender.clone(), + )?); + } + let writer = object_writers + .get_mut(&bucket_num) + .context("Unexpected missing bucket writer")?; + writer.write(&object)?; + } + let mut files = vec![]; + for (_, writer) in object_writers.into_iter() { + files.extend(writer.done()?); + } + self.write_manifest(epoch, files)?; + Ok(()) + } + + fn write_manifest(&mut self, epoch: u64, file_metadata: Vec) -> Result<()> { + let (f, manifest_file_path) = self.manifest_file(epoch)?; + let mut wbuf = BufWriter::new(f); + let manifest: Manifest = Manifest::V1(ManifestV1 { + snapshot_version: 1, + address_length: ObjectID::LENGTH as u64, + file_metadata, + epoch, + }); + let serialized_manifest = bcs::to_bytes(&manifest)?; + wbuf.write_all(&serialized_manifest)?; + wbuf.flush()?; + wbuf.get_ref().sync_data()?; + let sha3_digest = compute_sha3_checksum(&manifest_file_path)?; + wbuf.write_all(&sha3_digest)?; + wbuf.flush()?; + wbuf.get_ref().sync_data()?; + let off = wbuf.get_ref().stream_position()?; + wbuf.get_ref().set_len(off)?; + Ok(()) + } + + fn manifest_file(&mut self, epoch: u64) -> Result<(File, PathBuf)> { + let manifest_file_path = path_to_filesystem( + self.local_staging_dir.clone(), + &self.epoch_dir(epoch).child("MANIFEST"), + )?; + let manifest_file_tmp_path = path_to_filesystem( + self.local_staging_dir.clone(), + &self.epoch_dir(epoch).child("MANIFEST.tmp"), + )?; + let mut f = File::create(manifest_file_tmp_path.clone())?; + let mut metab = vec![0u8; MAGIC_BYTES]; + BigEndian::write_u32(&mut metab, MANIFEST_FILE_MAGIC); + f.rewind()?; + f.write_all(&metab)?; + drop(f); + fs::rename(manifest_file_tmp_path, manifest_file_path.clone())?; + let mut f = OpenOptions::new() + .append(true) + .open(manifest_file_path.clone())?; + f.seek(SeekFrom::Start(MAGIC_BYTES as u64))?; + Ok((f, manifest_file_path)) + } + + fn bucket_func(_object: &LiveObject) -> u32 { + // TODO: Use the hash bucketing function used for accumulator tree if there is + // one + 1u32 + } + + fn epoch_dir(&self, epoch: u64) -> Path { + Path::from(format!("epoch_{}", epoch)) + } + + async fn setup_epoch_dir(&self, epoch: u64) -> Result<()> { + let epoch_dir = self.epoch_dir(epoch); + // Delete remote epoch dir if it exists + delete_recursively( + &epoch_dir, + &self.remote_object_store, + NonZeroUsize::new(self.concurrency).unwrap(), + ) + .await?; + // Delete local staging epoch dir if it exists + let local_epoch_dir_path = self.local_staging_dir.join(format!("epoch_{}", epoch)); + if local_epoch_dir_path.exists() { + fs::remove_dir_all(&local_epoch_dir_path)?; + } + fs::create_dir_all(&local_epoch_dir_path)?; + Ok(()) + } + + async fn sync_file_to_remote( + local_path: PathBuf, + path: Path, + from: Arc, + to: Arc, + ) -> Result<()> { + debug!("Syncing snapshot file to remote: {:?}", path); + copy_file(&path, &path, &from, &to).await?; + fs::remove_file(path_to_filesystem(local_path, &path)?)?; + Ok(()) + } +} diff --git a/crates/iota-source-validation-service/Cargo.toml b/crates/iota-source-validation-service/Cargo.toml new file mode 100644 index 00000000000..7df52430324 --- /dev/null +++ b/crates/iota-source-validation-service/Cargo.toml @@ -0,0 +1,54 @@ +[package] +name = "iota-source-validation-service" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[lib] +path = "src/lib.rs" + +[[bin]] +path = "src/main.rs" +name = "iota-source-validation-service" + +[dependencies] +anyhow = { version = "1.0.64", features = ["backtrace"] } +clap.workspace = true +hyper = "0.14" +jsonrpsee.workspace = true +tempfile = "3.3.0" +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } +toml = { version = "0.7.4", features = ["preserve_order"] } +tracing = "0.1.36" +serde = { version = "1.0.144", features = ["derive"] } +url = "2.3.1" + +iota-move.workspace = true +iota-move-build.workspace = true +iota-sdk.workspace = true +iota-source-validation.workspace = true + +axum.workspace = true +const-str.workspace = true +git-version.workspace = true +move-package.workspace = true +move-compiler.workspace = true +move-core-types.workspace = true +move-symbol-pool.workspace = true +mysten-metrics.workspace = true +prometheus.workspace = true +telemetry-subscribers.workspace = true +tower.workspace = true +tower-http.workspace = true + +[dev-dependencies] +expect-test = "1.4.0" +fs_extra = "1.3.0" +reqwest = { version = "0.11", default-features = false, features = ["rustls-tls"] } + +iota.workspace = true +iota-move = { workspace = true, features = ["all"] } +iota-json-rpc-types.workspace = true +test-cluster.workspace = true diff --git a/crates/iota-source-validation-service/README.md b/crates/iota-source-validation-service/README.md new file mode 100644 index 00000000000..4b51a0f743d --- /dev/null +++ b/crates/iota-source-validation-service/README.md @@ -0,0 +1,67 @@ +# Iota Source Validation Service + +This document describes the Iota Source Validation Service. It is engineering documentation primarily for engineers who may want to build, extend, configure, or understand the service. + +The Source Validation Service is a server that returns Move source code associated with on-chain Move bytecode. It fetches and builds Move source code for a repository, and then verifies that the built artifact matches the on-chain bytecode. + +The default configuration limits scope to Iota framework packages in `crates/iota-framework/packages`: + +- `move-stdlib` — [address `0x1`](https://iotaexplorer.com/object/0x1) +- `iota-framework` — [address `0x2`](https://iotaexplorer.com/object/0x2) +- `iota-system` — [address `0x3`](https://iotaexplorer.com/object/0x2) +- `deepbook` — [address `0xdee9`](https://iotaexplorer.com/object/0xdee9) + +See examples below for requesting source from the server. + +## Build and Run + +``` +cargo run --release --bin iota-source-validation-service crates/iota-source-validation-service/config.toml +``` + +See [`config.toml` in this directory](config.toml). + +## Configuring + +A sample configuration entry is as follows: + +```toml +[[packages]] +source = "Repository" +[packages.values] +repository = "https://github.com/iotaledger/iota" +branch = "framework/mainnet" +network = "mainnet" +packages = [ + { path = "crates/iota-framework/packages/deepbook", watch = "0xdee9" }, + { path = "crates/iota-framework/packages/move-stdlib", watch = "0x1" }, + { path = "crates/iota-framework/packages/iota-framework", watch = "0x2" }, + { path = "crates/iota-framework/packages/iota-system", watch = "0x3" }, +] +``` + +It specifies the `repository` and `branch` for one or more move `packages`. `network` specifies the on-chain network to verify the source against. It can be one of `mainnet`, `testnet`, `devnet`, or `localnet`. + +A package `path` specifies the path of the package in the repository (where the `Move.toml` is). +The `watch` field is optional, and specifies the address of an object that the server should monitor for on-chain changes if a package is upgraded. For example, Iota framework packages mutate their on-chain address when upgraded. +Non-framework packages may mutate an `UpgradeCap` or an object wrapping the `UpgradeCap` (in which case, `watch` should be set to the `UpgradeCap` object ID or wrapped object ID respectively). + +Currently the `watch` field intends only to invalidate and evict the source code if on-chain code changes via upgrades. Due to current limitations, it does not automatically attempt to find and reprocess the latest source code. To reprocess the latest source code, restart the server, which will download and verify the source code afresh. + +The `HOST_PORT` environment variable sets the server host and port. The default is `0.0.0.0:8000`. + +## Usage + +After running `cargo run --bin iota-source-validation-service crates/iota-source-validation-service/config.toml` locally, try: + +``` +curl 'http://0.0.0.0:8000/api?address=0x2&module=coin&network=mainnet' --header 'X-Iota-Source-Validation-Version: 0.1' +``` + +This returns the source code for module `coin` on `mainnet` where the package `address` is `0x2` in JSON, e.g., `{"source":"..."}`. + +For errors, or if the source code does not exist, an error encoded in JSON returns, e.g., `{"error":"..."}`. + +The URL parameters `address`, `module`, and `network` are required. + +Although not required, it is good practice to set the `X-Iota-Source-Validation-Version` header. diff --git a/crates/iota-source-validation-service/config.toml b/crates/iota-source-validation-service/config.toml new file mode 100644 index 00000000000..0557d450c37 --- /dev/null +++ b/crates/iota-source-validation-service/config.toml @@ -0,0 +1,73 @@ +[[packages]] +source = "Repository" +[packages.values] +repository = "https://github.com/iotaledger/iota" +network = "mainnet" +[[packages.values.branches]] +branch = "framework/mainnet" +paths = [ + { path = "crates/iota-framework/packages/deepbook", watch = "0xdee9" }, + { path = "crates/iota-framework/packages/move-stdlib", watch = "0x1" }, + { path = "crates/iota-framework/packages/iota-framework", watch = "0x2" }, + { path = "crates/iota-framework/packages/iota-system", watch = "0x3" } +] + +[[packages]] +source = "Repository" +[packages.values] +repository = "https://github.com/iotaledger/iota" +network = "testnet" +[[packages.values.branches]] +branch = "framework/testnet" +paths = [ + { path = "crates/iota-framework/packages/deepbook", watch = "0xdee9" }, + { path = "crates/iota-framework/packages/move-stdlib", watch = "0x1" }, + { path = "crates/iota-framework/packages/iota-framework", watch = "0x2" }, + { path = "crates/iota-framework/packages/iota-system", watch = "0x3" } +] + +[[packages]] +source = "Repository" +[packages.values] +repository = "https://github.com/iotaledger/iota" +network = "devnet" +[[packages.values.branches]] +branch = "framework/devnet" +paths = [ + { path = "crates/iota-framework/packages/deepbook", watch = "0xdee9" }, + { path = "crates/iota-framework/packages/move-stdlib", watch = "0x1" }, + { path = "crates/iota-framework/packages/iota-framework", watch = "0x2" }, + { path = "crates/iota-framework/packages/iota-system", watch = "0x3" } +] + +[[packages]] +source = "Repository" +[packages.values] +repository = "https://github.com/mystenlabs/apps" +network = "mainnet" +[[packages.values.branches]] +branch = "main" +paths = [ + { path = "kiosk" }, +] + +[[packages]] +source = "Repository" +[packages.values] +repository = "https://github.com/mystenlabs/apps" +network = "testnet" +[[packages.values.branches]] +branch = "testnet" +paths = [ + { path = "kiosk" }, +] + +# [[packages]] +# source = "Repository" +# [packages.values] +# repository = "https://github.com/kunalabs-io/iota-smart-contracts" +# [[packages.values.branches]] +# branch = "master" +# paths = [ +# { path = "kai-finance" } +# ] \ No newline at end of file diff --git a/crates/iota-source-validation-service/src/lib.rs b/crates/iota-source-validation-service/src/lib.rs new file mode 100644 index 00000000000..5845379cade --- /dev/null +++ b/crates/iota-source-validation-service/src/lib.rs @@ -0,0 +1,716 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::BTreeMap, + ffi::OsString, + fmt, fs, + net::TcpListener, + path::{Path, PathBuf}, + process::Command, + sync::{Arc, RwLock}, + time::Duration, +}; + +use anyhow::{anyhow, bail}; +use axum::{ + extract::{Query, State}, + middleware::{self, Next}, + response::{IntoResponse, Response}, + routing::{get, IntoMakeService}, + Extension, Json, Router, Server, +}; +use hyper::{ + http::{HeaderName, HeaderValue, Method}, + server::conn::AddrIncoming, + HeaderMap, StatusCode, +}; +use iota_move::build::resolve_lock_file_path; +use iota_move_build::{BuildConfig, IotaPackageHooks}; +use iota_sdk::{ + rpc_types::{IotaTransactionBlockEffects, TransactionFilter}, + types::base_types::ObjectID, + IotaClientBuilder, +}; +use iota_source_validation::{BytecodeSourceVerifier, SourceMode}; +use jsonrpsee::{ + core::{ + client::{Subscription, SubscriptionClientT}, + params::ArrayParams, + }, + ws_client::{WsClient, WsClientBuilder}, +}; +use move_core_types::account_address::AccountAddress; +use move_package::{BuildConfig as MoveBuildConfig, LintFlag}; +use move_symbol_pool::Symbol; +use mysten_metrics::RegistryService; +use prometheus::{register_int_counter_with_registry, IntCounter, Registry}; +use serde::{Deserialize, Serialize}; +use tokio::sync::oneshot::Sender; +use tower::ServiceBuilder; +use tracing::{debug, error, info}; +use url::Url; + +pub const HOST_PORT_ENV: &str = "HOST_PORT"; +pub const IOTA_SOURCE_VALIDATION_VERSION_HEADER: &str = "x-iota-source-validation-version"; +pub const IOTA_SOURCE_VALIDATION_VERSION: &str = "0.1"; + +pub const MAINNET_URL: &str = "https://fullnode.mainnet.iota.io:443"; +pub const TESTNET_URL: &str = "https://fullnode.testnet.iota.io:443"; +pub const DEVNET_URL: &str = "https://fullnode.devnet.iota.io:443"; +pub const LOCALNET_URL: &str = "http://127.0.0.1:9000"; + +pub const MAINNET_WS_URL: &str = "wss://rpc.mainnet.iota.io:443"; +pub const TESTNET_WS_URL: &str = "wss://rpc.testnet.iota.io:443"; +pub const DEVNET_WS_URL: &str = "wss://rpc.devnet.iota.io:443"; +pub const LOCALNET_WS_URL: &str = "ws://127.0.0.1:9000"; + +pub const WS_PING_INTERVAL: Duration = Duration::from_millis(20_000); + +pub const METRICS_ROUTE: &str = "/metrics"; +pub const METRICS_HOST_PORT: &str = "0.0.0.0:9184"; + +pub fn host_port() -> String { + match option_env!("HOST_PORT") { + Some(v) => v.to_string(), + None => String::from("0.0.0.0:8000"), + } +} + +#[derive(Clone, Deserialize, Debug)] +pub struct Config { + pub packages: Vec, +} + +#[derive(Clone, Deserialize, Debug)] +#[serde(tag = "source", content = "values")] +pub enum PackageSource { + Repository(RepositorySource), + Directory(DirectorySource), +} + +#[derive(Clone, Deserialize, Debug)] +pub struct RepositorySource { + pub repository: String, + pub network: Option, + pub branches: Vec, +} + +#[derive(Clone, Deserialize, Debug)] +pub struct Branch { + pub branch: String, + pub paths: Vec, +} + +#[derive(Clone, Deserialize, Debug)] +pub struct DirectorySource { + pub paths: Vec, + pub network: Option, +} + +#[derive(Clone, Deserialize, Debug)] +pub struct Package { + pub path: String, + /// Optional object ID to watch for upgrades. For framework packages, this + /// is an address like 0x2. For non-framework packages this is an + /// upgrade cap (possibly wrapped). + pub watch: Option, +} + +#[derive(Clone, Serialize, Debug)] +pub struct SourceInfo { + pub path: PathBuf, + #[serde(skip_serializing_if = "Option::is_none")] + // Is Some when content is hydrated from disk. + pub source: Option, +} + +#[derive(Eq, PartialEq, Clone, Default, Serialize, Deserialize, Debug, Ord, PartialOrd)] +#[serde(rename_all = "lowercase")] +pub enum Network { + #[default] + #[serde(alias = "Mainnet")] + Mainnet, + #[serde(alias = "Testnet")] + Testnet, + #[serde(alias = "Devnet")] + Devnet, + #[serde(alias = "Localnet")] + Localnet, +} + +impl fmt::Display for Network { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Network::Mainnet => "mainnet", + Network::Testnet => "testnet", + Network::Devnet => "devnet", + Network::Localnet => "localnet", + } + ) + } +} + +/// Map module name to verified source info. +pub type SourceLookup = BTreeMap; +/// Map addresses to module names and sources. +pub type AddressLookup = BTreeMap; +/// Top-level lookup that maps network to sources for corresponding on-chain +/// networks. +pub type NetworkLookup = BTreeMap; + +pub async fn verify_package( + network: &Network, + package_path: impl AsRef, +) -> anyhow::Result<(Network, AddressLookup)> { + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); + let mut config = resolve_lock_file_path( + MoveBuildConfig::default(), + Some(package_path.as_ref().to_path_buf()), + )?; + config.lint_flag = LintFlag::LEVEL_NONE; + config.silence_warnings = true; + let build_config = BuildConfig { + config, + run_bytecode_verifier: false, // no need to run verifier if code is on-chain + print_diags_to_stderr: false, + }; + let compiled_package = build_config.build(package_path.as_ref().to_path_buf())?; + + let network_url = match network { + Network::Mainnet => MAINNET_URL, + Network::Testnet => TESTNET_URL, + Network::Devnet => DEVNET_URL, + Network::Localnet => LOCALNET_URL, + }; + let client = IotaClientBuilder::default().build(network_url).await?; + BytecodeSourceVerifier::new(client.read_api()) + .verify_package( + &compiled_package, + // verify_deps + false, + SourceMode::Verify, + ) + .await + .map_err(|e| anyhow!("Network {network}: {e}"))?; + + let mut address_map = AddressLookup::new(); + let address = compiled_package + .published_at + .as_ref() + .map(|id| **id) + .map_err(|_| anyhow!("could not resolve published-at field in package manifest"))?; + info!("verifying {} at {address}", package_path.as_ref().display()); + for v in &compiled_package.package.root_compiled_units { + let path = v.source_path.to_path_buf(); + let source = Some(fs::read_to_string(path.as_path())?); + let name = v.unit.name; + if let Some(existing) = address_map.get_mut(&address) { + existing.insert(name, SourceInfo { path, source }); + } else { + let mut source_map = SourceLookup::new(); + source_map.insert(name, SourceInfo { path, source }); + address_map.insert(address, source_map); + } + } + Ok((network.clone(), address_map)) +} + +pub fn parse_config(config_path: impl AsRef) -> anyhow::Result { + let contents = fs::read_to_string(config_path)?; + Ok(toml::from_str(&contents)?) +} + +pub fn repo_name_from_url(url: &str) -> anyhow::Result { + let repo_url = Url::parse(url)?; + let mut components = repo_url + .path_segments() + .ok_or_else(|| anyhow!("Could not discover repository path in url {url}"))?; + let repo_name = components + .next_back() + .ok_or_else(|| anyhow!("Could not discover repository name in url {url}"))?; + Ok(repo_name.to_string()) +} + +#[derive(Debug)] +/// Represents a sequence of git commands to clone a repository and sparsely +/// checkout Move packages within. +pub struct CloneCommand { + /// git args + args: Vec>, + /// report repository url in error messages + repo_url: String, +} + +impl CloneCommand { + pub fn new(p: &RepositorySource, b: &Branch, dest: &Path) -> anyhow::Result { + let repo_name = repo_name_from_url(&p.repository)?; + let network = p.network.clone().unwrap_or_default().to_string(); + let sanitized_branch = b.branch.replace('/', "__"); + let dest = dest + .join(network) + .join(format!("{repo_name}__{sanitized_branch}")) + .into_os_string(); + + macro_rules! ostr { + ($arg:expr) => { + OsString::from($arg) + }; + } + + let mut args = vec![]; + // Args to clone empty repository + let cmd_args: Vec = vec![ + ostr!("clone"), + ostr!("--no-checkout"), + ostr!("--depth=1"), // implies --single-branch + ostr!("--filter=tree:0"), + ostr!(format!("--branch={}", b.branch)), + ostr!(&p.repository), + ostr!(dest.clone()), + ]; + args.push(cmd_args); + + // Args to sparse checkout the package set + let mut cmd_args: Vec = vec![ + ostr!("-C"), + dest.clone(), + ostr!("sparse-checkout"), + ostr!("set"), + ostr!("--no-cone"), + ]; + let path_args: Vec = b + .paths + .iter() + .map(|p| OsString::from(p.path.clone())) + .collect(); + cmd_args.extend_from_slice(&path_args); + args.push(cmd_args); + + // Args to checkout the default branch. + let cmd_args: Vec = vec![ostr!("-C"), dest, ostr!("checkout")]; + args.push(cmd_args); + + Ok(Self { + args, + repo_url: p.repository.clone(), + }) + } + + pub async fn run(&self) -> anyhow::Result<()> { + for args in &self.args { + let result = Command::new("git").args(args).output().map_err(|_| { + anyhow!( + "Error cloning {} with command `git {:#?}`", + self.repo_url, + args + ) + })?; + if !result.status.success() { + bail!( + "Nonzero exit status when cloning {} with command `git {:#?}`. \ + Stderr: {}", + self.repo_url, + args, + String::from_utf8_lossy(&result.stderr) + ) + } + } + Ok(()) + } +} + +/// Clones repositories and checks out packages as per `config` at the directory +/// `dir`. +pub async fn clone_repositories(repos: Vec<&RepositorySource>, dir: &Path) -> anyhow::Result<()> { + let mut tasks = vec![]; + for p in &repos { + for b in &p.branches { + let command = CloneCommand::new(p, b, dir)?; + info!( + "cloning {}:{} to {}", + &p.repository, + &b.branch, + dir.display() + ); + let t = tokio::spawn(async move { command.run().await }); + tasks.push(t); + } + } + + for t in tasks { + t.await.unwrap()?; + } + Ok(()) +} + +pub async fn initialize( + config: &Config, + dir: &Path, +) -> anyhow::Result<(NetworkLookup, NetworkLookup)> { + let mut repos = vec![]; + for s in &config.packages { + match s { + PackageSource::Repository(r) => repos.push(r), + PackageSource::Directory(_) => (), // skip cloning + } + } + clone_repositories(repos, dir).await?; + let sources = verify_packages(config, dir).await?; + let sources_list = sources_list(&sources).await; + Ok((sources, sources_list)) +} + +pub async fn sources_list(sources: &NetworkLookup) -> NetworkLookup { + let mut sources_list = NetworkLookup::new(); + for (network, addresses) in sources { + let mut address_map = AddressLookup::new(); + for (address, symbols) in addresses { + let mut symbol_map = SourceLookup::new(); + for (symbol, source_info) in symbols { + symbol_map.insert( + *symbol, + SourceInfo { + path: source_info.path.file_name().unwrap().into(), + source: None, + }, + ); + } + address_map.insert(*address, symbol_map); + } + sources_list.insert(network.clone(), address_map); + } + sources_list +} + +pub async fn verify_packages(config: &Config, dir: &Path) -> anyhow::Result { + let mut tasks = vec![]; + for p in &config.packages { + match p { + PackageSource::Repository(r) => { + let repo_name = repo_name_from_url(&r.repository)?; + let network_name = r.network.clone().unwrap_or_default().to_string(); + for b in &r.branches { + for p in &b.paths { + let sanitized_branch = b.branch.replace('/', "__"); + let package_path = dir + .join(network_name.clone()) + .join(format!("{repo_name}__{sanitized_branch}")) + .join(p.path.clone()) + .clone(); + let network = r.network.clone().unwrap_or_default(); + let t = + tokio::spawn( + async move { verify_package(&network, package_path).await }, + ); + tasks.push(t) + } + } + } + PackageSource::Directory(packages_dir) => { + for p in &packages_dir.paths { + let package_path = PathBuf::from(p.path.clone()); + let network = packages_dir.network.clone().unwrap_or_default(); + let t = + tokio::spawn(async move { verify_package(&network, package_path).await }); + tasks.push(t) + } + } + } + } + + let mut mainnet_lookup = AddressLookup::new(); + let mut testnet_lookup = AddressLookup::new(); + let mut devnet_lookup = AddressLookup::new(); + let mut localnet_lookup = AddressLookup::new(); + for t in tasks { + let (network, new_lookup) = t.await.unwrap()?; + match network { + Network::Mainnet => mainnet_lookup.extend(new_lookup), + Network::Testnet => testnet_lookup.extend(new_lookup), + Network::Devnet => devnet_lookup.extend(new_lookup), + Network::Localnet => localnet_lookup.extend(new_lookup), + } + } + let mut lookup = NetworkLookup::new(); + lookup.insert(Network::Mainnet, mainnet_lookup); + lookup.insert(Network::Testnet, testnet_lookup); + lookup.insert(Network::Devnet, devnet_lookup); + lookup.insert(Network::Localnet, localnet_lookup); + Ok(lookup) +} + +// A thread that monitors on-chain transactions for package upgrades. `config` +// specifies which packages to watch. `app_state` contains the map of sources +// returned by the server. In particular, `watch_for_upgrades` invalidates +// (i.e., clears) the sources returned by the serve when we observe a package +// upgrade, so that we do not falsely report outdated sources for a package. +// Pass an optional `channel` to observe the upgrade transaction(s). +// The `channel` parameter exists for testing. +pub async fn watch_for_upgrades( + packages: Vec, + app_state: Arc>, + network: Network, + channel: Option>, +) -> anyhow::Result<()> { + let mut watch_ids = ArrayParams::new(); + let mut num_packages = 0; + for s in packages { + let branches = match s { + PackageSource::Repository(RepositorySource { branches, .. }) => branches, + PackageSource::Directory(DirectorySource { paths, .. }) => vec![Branch { + branch: "".into(), // Unused. + paths, + }], + }; + for b in branches { + for p in b.paths { + if let Some(id) = p.watch { + num_packages += 1; + watch_ids.insert(TransactionFilter::ChangedObject(id))? + } + } + } + } + + let websocket_url = match network { + Network::Mainnet => MAINNET_WS_URL, + Network::Testnet => TESTNET_WS_URL, + Network::Devnet => DEVNET_WS_URL, + Network::Localnet => LOCALNET_WS_URL, + }; + + let client: WsClient = WsClientBuilder::default() + .ping_interval(WS_PING_INTERVAL) + .build(websocket_url) + .await?; + let mut subscription: Subscription = client + .subscribe( + "iotax_subscribeTransaction", + watch_ids, + "iotax_unsubscribeTransaction", + ) + .await + .map_err(|e| anyhow!("Failed to open websocket connection for {}: {}", network, e))?; + + info!("Listening for upgrades on {num_packages} package(s) on {websocket_url}..."); + loop { + let result: Option> = subscription.next().await; + match result { + Some(Ok(result)) => { + // We see an upgrade transaction. Clear all sources since all of part of these + // may now be invalid. Currently we need to restart the server + // within some time delta of this observation to resume + // returning source. Restarting revalidates the latest release sources per + // repositories in the config file. Restarting is a manual + // side-effect outside of this server because we need to ensure that sources in + // the repositories _actually contain_ the latest source + // corresponding to on-chain data (which is subject to + // manual syncing itself currently). + info!("Saw upgrade txn: {:?}", result); + let mut app_state = app_state.write().unwrap(); + app_state.sources = NetworkLookup::new(); // Clear all sources. + app_state.sources_list = NetworkLookup::new(); // Clear all listed sources. + if let Some(channel) = channel { + channel.send(result).unwrap(); + break Ok(()); + } + info!("Shutting down server (resync performed on restart)"); + std::process::exit(1) + } + Some(_) => { + info!("Saw failed transaction when listening to upgrades.") + } + None => { + error!( + "Fatal: WebSocket connection lost while listening for upgrades. Shutting down server." + ); + std::process::exit(1) + } + } + } +} + +pub struct AppState { + pub sources: NetworkLookup, + pub metrics: Option, + pub sources_list: NetworkLookup, +} + +pub fn serve( + app_state: Arc>, +) -> anyhow::Result>> { + let app = Router::new() + .route("/api", get(api_route)) + .route("/api/list", get(list_route)) + .layer( + ServiceBuilder::new() + .layer( + tower_http::cors::CorsLayer::new() + .allow_methods([Method::GET]) + .allow_origin(tower_http::cors::Any), + ) + .layer(middleware::from_fn(check_version_header)), + ) + .with_state(app_state); + let listener = TcpListener::bind(host_port())?; + Ok(Server::from_tcp(listener)?.serve(app.into_make_service())) +} + +#[derive(Deserialize)] +pub struct Request { + #[serde(default)] + network: Network, + address: String, + module: String, +} + +#[derive(Serialize, Deserialize)] +pub struct SourceResponse { + pub source: String, +} + +#[derive(Serialize, Deserialize)] +pub struct ErrorResponse { + pub error: String, +} + +async fn api_route( + State(app_state): State>>, + Query(Request { + network, + address, + module, + }): Query, +) -> impl IntoResponse { + debug!("request network={network}&address={address}&module={module}"); + let symbol = Symbol::from(module); + let Ok(address) = AccountAddress::from_hex_literal(&address) else { + let error = format!("Invalid hex address {address}"); + return ( + StatusCode::BAD_REQUEST, + Json(ErrorResponse { error }).into_response(), + ); + }; + + let app_state = app_state.read().unwrap(); + if let Some(metrics) = &app_state.metrics { + metrics.total_requests_received.inc(); + } + let source_result = app_state + .sources + .get(&network) + .and_then(|n| n.get(&address)) + .and_then(|a| a.get(&symbol)); + if let Some(SourceInfo { + source: Some(source), + .. + }) = source_result + { + ( + StatusCode::OK, + Json(SourceResponse { + source: source.to_owned(), + }) + .into_response(), + ) + } else { + ( + StatusCode::NOT_FOUND, + Json(ErrorResponse { + error: format!( + "No source found for {symbol} at address {address} on network {network}" + ), + }) + .into_response(), + ) + } +} + +async fn check_version_header( + headers: HeaderMap, + req: hyper::Request, + next: Next, +) -> Response { + let version = headers + .get(IOTA_SOURCE_VALIDATION_VERSION_HEADER) + .as_ref() + .and_then(|h| h.to_str().ok()) + .map(|s| s.to_string()); + + match version { + Some(v) if v != IOTA_SOURCE_VALIDATION_VERSION => { + let error = format!( + "Unsupported version '{v}' specified in header \ + {IOTA_SOURCE_VALIDATION_VERSION_HEADER}" + ); + let mut headers = HeaderMap::new(); + headers.insert( + HeaderName::from_static(IOTA_SOURCE_VALIDATION_VERSION_HEADER), + HeaderValue::from_static(IOTA_SOURCE_VALIDATION_VERSION), + ); + return ( + StatusCode::BAD_REQUEST, + headers, + Json(ErrorResponse { error }).into_response(), + ) + .into_response(); + } + _ => (), + } + let mut response = next.run(req).await; + response.headers_mut().insert( + HeaderName::from_static(IOTA_SOURCE_VALIDATION_VERSION_HEADER), + HeaderValue::from_static(IOTA_SOURCE_VALIDATION_VERSION), + ); + response +} + +async fn list_route(State(app_state): State>>) -> impl IntoResponse { + let app_state = app_state.read().unwrap(); + ( + StatusCode::OK, + Json(app_state.sources_list.clone()).into_response(), + ) +} + +pub struct SourceServiceMetrics { + pub total_requests_received: IntCounter, +} + +impl SourceServiceMetrics { + pub fn new(registry: &Registry) -> Self { + Self { + total_requests_received: register_int_counter_with_registry!( + "total_requests", + "Total number of requests received by Source Service", + registry + ) + .unwrap(), + } + } +} + +pub fn start_prometheus_server(addr: TcpListener) -> RegistryService { + let registry = Registry::new(); + + let registry_service = RegistryService::new(registry); + + let app = Router::new() + .route(METRICS_ROUTE, get(mysten_metrics::metrics)) + .layer(Extension(registry_service.clone())); + + tokio::spawn(async move { + axum::Server::from_tcp(addr) + .unwrap() + .serve(app.into_make_service()) + .await + .unwrap(); + }); + + registry_service +} diff --git a/crates/iota-source-validation-service/src/main.rs b/crates/iota-source-validation-service/src/main.rs new file mode 100644 index 00000000000..fd6899bfc2f --- /dev/null +++ b/crates/iota-source-validation-service/src/main.rs @@ -0,0 +1,101 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + path::PathBuf, + sync::{Arc, RwLock}, +}; + +use clap::Parser; +use iota_source_validation_service::{ + host_port, initialize, parse_config, serve, start_prometheus_server, watch_for_upgrades, + AppState, DirectorySource, Network, PackageSource, RepositorySource, SourceServiceMetrics, + METRICS_HOST_PORT, +}; +use telemetry_subscribers::TelemetryConfig; +use tracing::info; + +#[derive(Parser, Debug)] +struct Args { + config_path: PathBuf, +} + +const GIT_REVISION: &str = { + if let Some(revision) = option_env!("GIT_REVISION") { + revision + } else { + git_version::git_version!( + args = ["--always", "--dirty", "--exclude", "*"], + fallback = "DIRTY" + ) + } +}; + +pub const VERSION: &str = const_str::concat!(env!("CARGO_PKG_VERSION"), "-", GIT_REVISION); + +#[tokio::main] +pub async fn main() -> anyhow::Result<()> { + let args = Args::parse(); + let _logging_guard = TelemetryConfig::new().with_env().init(); + let package_config = parse_config(args.config_path)?; + let tmp_dir = tempfile::tempdir()?; + let start = tokio::time::Instant::now(); + let (sources, sources_list) = initialize(&package_config, tmp_dir.path()).await?; + info!("verification complete in {:?}", start.elapsed()); + + let metrics_listener = std::net::TcpListener::bind(METRICS_HOST_PORT)?; + let registry_service = start_prometheus_server(metrics_listener); + let prometheus_registry = registry_service.default_registry(); + let metrics = SourceServiceMetrics::new(&prometheus_registry); + + let app_state = Arc::new(RwLock::new(AppState { + sources, + metrics: Some(metrics), + sources_list, + })); + let mut threads = vec![]; + let networks_to_watch = vec![ + Network::Mainnet, + Network::Testnet, + Network::Devnet, + Network::Localnet, + ]; + // spawn a watcher thread for upgrades for each network + for network in networks_to_watch { + let app_state_copy = app_state.clone(); + let packages: Vec<_> = package_config + .clone() + .packages + .into_iter() + .filter(|p| { + matches!( + p, + PackageSource::Repository(RepositorySource { + network: Some(n), + .. + }) | PackageSource::Directory(DirectorySource { + network: Some(n), + .. + }) if *n == network, + ) + }) + .collect(); + if packages.is_empty() { + continue; + } + let watcher = tokio::spawn(async move { + watch_for_upgrades(packages, app_state_copy, network, None).await + }); + threads.push(watcher); + } + + let app_state_copy = app_state.clone(); + let server = tokio::spawn(async { serve(app_state_copy)?.await.map_err(anyhow::Error::from) }); + threads.push(server); + info!("serving on {}", host_port()); + for t in threads { + t.await.unwrap()?; + } + Ok(()) +} diff --git a/crates/sui-source-validation-service/tests/fixture/custom/Move.toml b/crates/iota-source-validation-service/tests/fixture/custom/Move.toml similarity index 100% rename from crates/sui-source-validation-service/tests/fixture/custom/Move.toml rename to crates/iota-source-validation-service/tests/fixture/custom/Move.toml diff --git a/crates/iota-source-validation-service/tests/fixture/custom/sources/custom.move b/crates/iota-source-validation-service/tests/fixture/custom/sources/custom.move new file mode 100644 index 00000000000..fa929949819 --- /dev/null +++ b/crates/iota-source-validation-service/tests/fixture/custom/sources/custom.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module custom::foo { + public fun id(): u64 { + 0 + } +} diff --git a/crates/sui-source-validation-service/tests/fixture/sui__main/move-stdlib/Move.toml b/crates/iota-source-validation-service/tests/fixture/iota__main/move-stdlib/Move.toml similarity index 100% rename from crates/sui-source-validation-service/tests/fixture/sui__main/move-stdlib/Move.toml rename to crates/iota-source-validation-service/tests/fixture/iota__main/move-stdlib/Move.toml diff --git a/crates/iota-source-validation-service/tests/fixture/iota__main/move-stdlib/sources/address.move b/crates/iota-source-validation-service/tests/fixture/iota__main/move-stdlib/sources/address.move new file mode 100644 index 00000000000..d75d9c21b6b --- /dev/null +++ b/crates/iota-source-validation-service/tests/fixture/iota__main/move-stdlib/sources/address.move @@ -0,0 +1,6 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Dummy module for testing +module std::address {} diff --git a/crates/iota-source-validation-service/tests/tests.rs b/crates/iota-source-validation-service/tests/tests.rs new file mode 100644 index 00000000000..fe8a987bbc8 --- /dev/null +++ b/crates/iota-source-validation-service/tests/tests.rs @@ -0,0 +1,545 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(not(target_os = "windows"))] +use std::os::unix::fs::FileExt; +#[cfg(target_os = "windows")] +use std::os::windows::fs::FileExt; +use std::{ + fs, + io::Read, + path::PathBuf, + sync::{Arc, RwLock}, +}; + +use expect_test::expect; +use iota::client_commands::{IotaClientCommandResult, IotaClientCommands}; +use iota_json_rpc_types::{IotaTransactionBlockEffects, IotaTransactionBlockEffectsAPI}; +use iota_move_build::{BuildConfig, IotaPackageHooks}; +use iota_sdk::{ + rpc_types::{ + IotaObjectDataOptions, IotaObjectResponseQuery, IotaTransactionBlockEffectsV1, + OwnedObjectRef, + }, + types::{base_types::ObjectID, object::Owner, transaction::TEST_ONLY_GAS_UNIT_FOR_PUBLISH}, + wallet_context::WalletContext, +}; +use iota_source_validation_service::{ + host_port, initialize, serve, start_prometheus_server, verify_packages, watch_for_upgrades, + AddressLookup, AppState, Branch, CloneCommand, Config, DirectorySource, ErrorResponse, Network, + NetworkLookup, Package, PackageSource, RepositorySource, SourceInfo, SourceLookup, + SourceResponse, SourceServiceMetrics, IOTA_SOURCE_VALIDATION_VERSION_HEADER, METRICS_HOST_PORT, +}; +use move_core_types::account_address::AccountAddress; +use move_symbol_pool::Symbol; +use reqwest::Client; +use test_cluster::TestClusterBuilder; +use tokio::sync::oneshot; + +const LOCALNET_PORT: u16 = 9000; +const TEST_FIXTURES_DIR: &str = "tests/fixture"; + +#[allow(clippy::await_holding_lock)] +#[tokio::test] +async fn test_end_to_end() -> anyhow::Result<()> { + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); + let mut test_cluster = TestClusterBuilder::new() + .with_fullnode_rpc_port(LOCALNET_PORT) + .build() + .await; + + /////////////////////////// + // Test watch_for_upgrades + ////////////////////////// + let rgp = test_cluster.get_reference_gas_price().await; + let address = test_cluster.get_address_0(); + let context = &mut test_cluster.wallet; + let client = context.get_client().await?; + let object_refs = client + .read_api() + .get_owned_objects( + address, + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() + .with_type() + .with_owner() + .with_previous_transaction(), + )), + None, + None, + ) + .await? + .data; + + let gas_obj_id = object_refs.first().unwrap().object().unwrap().object_id; + let mut package_path = PathBuf::from(TEST_FIXTURES_DIR); + package_path.push("custom"); + + // Publish and get upgrade capability to monitor. + let effects = run_publish(package_path.clone(), context, gas_obj_id, rgp).await?; + let cap = effects + .created() + .iter() + .find(|refe| matches!(refe.owner, Owner::AddressOwner(_))) + .unwrap(); + + // Set up source service config to watch the upgrade cap. + let config = Config { + packages: vec![PackageSource::Directory(DirectorySource { + paths: vec![Package { + path: "unused".into(), + watch: Some(cap.reference.object_id), // watch the upgrade cap + }], + network: Some(Network::Localnet), + })], + }; + // Start watching for upgrades. + let mut sources = NetworkLookup::new(); + sources.insert(Network::Localnet, AddressLookup::new()); + + let mut sources_list = NetworkLookup::new(); + sources_list.insert(Network::Localnet, AddressLookup::new()); + let app_state = Arc::new(RwLock::new(AppState { + sources, + metrics: None, + sources_list, + })); + let app_state_ref = app_state.clone(); + let (tx, rx) = oneshot::channel(); + tokio::spawn(async move { + watch_for_upgrades(config.packages, app_state, Network::Localnet, Some(tx)).await + }); + + // Set up to upgrade package. + let package = effects + .created() + .iter() + .find(|refe| matches!(refe.owner, Owner::Immutable)) + .unwrap(); + let package_id = package.reference.object_id; + let tmp_dir = tempfile::tempdir().unwrap(); + let upgrade_pkg_path = + copy_with_published_at_manifest(&package_path, &tmp_dir.path().to_path_buf(), package_id); + // Run the upgrade. + run_upgrade(upgrade_pkg_path, cap, context, gas_obj_id, rgp).await?; + + // Test expects to observe an upgrade transaction. + let Ok(IotaTransactionBlockEffects::V1(effects)) = rx.await else { + panic!("No upgrade transaction observed") + }; + assert!(effects.status.is_ok()); + // Test expects `sources` of server state to be empty / cleared on upgrade. + let app_state_ref = app_state_ref.read().unwrap(); + assert!(app_state_ref.sources.is_empty()); + + /////////////////////////// + // Test verify_packages + ////////////////////////// + let config = Config { + packages: vec![PackageSource::Repository(RepositorySource { + repository: "https://github.com/iotaledger/iota".into(), + branches: vec![Branch { + branch: "main".into(), + paths: vec![Package { + path: "move-stdlib".into(), + watch: None, + }], + }], + network: Some(Network::Localnet), + })], + }; + + let fixtures = tempfile::tempdir()?; + fs::create_dir(fixtures.path().join("localnet"))?; + fs_extra::dir::copy( + PathBuf::from(TEST_FIXTURES_DIR).join("iota__main"), + fixtures.path().join("localnet"), + &fs_extra::dir::CopyOptions::default(), + )?; + let result = verify_packages(&config, fixtures.path()).await; + let truncated_error_message = &result + .unwrap_err() + .to_string() + .lines() + .take(3) + .map(|s| s.into()) + .collect::>() + .join("\n"); + let expected = expect![ + r#" +Network localnet: Multiple source verification errors found: + +- Local dependency did not match its on-chain version at 0000000000000000000000000000000000000000000000000000000000000001::MoveStdlib::address"# + ]; + expected.assert_eq(truncated_error_message); + Ok(()) +} + +async fn run_publish( + package_path: PathBuf, + context: &mut WalletContext, + gas_obj_id: ObjectID, + rgp: u64, +) -> anyhow::Result { + let build_config = BuildConfig::new_for_testing().config; + let resp = IotaClientCommands::Publish { + package_path: package_path.clone(), + build_config, + gas: Some(gas_obj_id), + gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, + skip_dependency_verification: false, + with_unpublished_dependencies: false, + serialize_unsigned_transaction: false, + serialize_signed_transaction: false, + } + .execute(context) + .await?; + + let IotaClientCommandResult::Publish(response) = resp else { + unreachable!("Invalid response"); + }; + let IotaTransactionBlockEffects::V1(effects) = response.effects.unwrap(); + assert!(effects.status.is_ok()); + Ok(effects) +} + +async fn run_upgrade( + upgrade_pkg_path: PathBuf, + cap: &OwnedObjectRef, + context: &mut WalletContext, + gas_obj_id: ObjectID, + rgp: u64, +) -> anyhow::Result<()> { + let build_config = BuildConfig::new_for_testing().config; + let resp = IotaClientCommands::Upgrade { + package_path: upgrade_pkg_path, + upgrade_capability: cap.reference.object_id, + build_config, + gas: Some(gas_obj_id), + gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, + skip_dependency_verification: false, + with_unpublished_dependencies: false, + serialize_unsigned_transaction: false, + serialize_signed_transaction: false, + } + .execute(context) + .await?; + + let IotaClientCommandResult::Upgrade(response) = resp else { + unreachable!("Invalid upgrade response"); + }; + let IotaTransactionBlockEffects::V1(effects) = response.effects.unwrap(); + assert!(effects.status.is_ok()); + Ok(()) +} + +/// Copy the package and set `published-at` in the Move toml file. The need for +/// this will be subsumed by automated address management. +fn copy_with_published_at_manifest( + source_path: &PathBuf, + dest_path: &PathBuf, + package_id: ObjectID, +) -> PathBuf { + fs_extra::dir::copy( + source_path, + dest_path, + &fs_extra::dir::CopyOptions::default(), + ) + .unwrap(); + let mut upgrade_pkg_path = dest_path.clone(); + upgrade_pkg_path.extend(["custom", "Move.toml"]); + let mut move_toml = std::fs::File::options() + .read(true) + .write(true) + .open(&upgrade_pkg_path) + .unwrap(); + upgrade_pkg_path.pop(); + + let mut buf = String::new(); + move_toml.read_to_string(&mut buf).unwrap(); + + // Add a `published-at = "0x"` to the Move manifest. + let mut lines: Vec = buf.split('\n').map(|x| x.to_string()).collect(); + let idx = lines.iter().position(|s| s == "[package]").unwrap(); + lines.insert( + idx + 1, + format!("published-at = \"{}\"", package_id.to_hex_uncompressed()), + ); + let new = lines.join("\n"); + + #[cfg(target_os = "windows")] + move_toml.seek_write(new.as_bytes(), 0).unwrap(); + + #[cfg(not(target_os = "windows"))] + move_toml.write_at(new.as_bytes(), 0).unwrap(); + + upgrade_pkg_path +} + +#[tokio::test] +async fn test_api_route() -> anyhow::Result<()> { + let config = Config { packages: vec![] }; + let tmp_dir = tempfile::tempdir()?; + initialize(&config, tmp_dir.path()).await?; + + // set up sample lookup to serve + let fixtures = tempfile::tempdir()?; + fs_extra::dir::copy( + PathBuf::from(TEST_FIXTURES_DIR).join("iota__main"), + fixtures.path(), + &fs_extra::dir::CopyOptions::default(), + )?; + + let address = "0x2"; + let module = "address"; + let source_path = fixtures + .into_path() + .join("iota/move-stdlib/sources/address.move"); + + let mut source_lookup = SourceLookup::new(); + source_lookup.insert( + Symbol::from(module), + SourceInfo { + path: source_path, + source: Some("module address {...}".to_owned()), + }, + ); + let mut address_lookup = AddressLookup::new(); + let account_address = AccountAddress::from_hex_literal(address).unwrap(); + address_lookup.insert(account_address, source_lookup); + let mut sources = NetworkLookup::new(); + sources.insert(Network::Localnet, address_lookup); + let mut sources_list = NetworkLookup::new(); + sources_list.insert(Network::Localnet, AddressLookup::new()); + let app_state = Arc::new(RwLock::new(AppState { + sources, + metrics: None, + sources_list, + })); + tokio::spawn(serve(app_state).expect("Cannot start service.")); + + let client = Client::new(); + + // check that serve returns expected sample code + let json = client + .get(format!( + "http://{}/api?address={address}&module={module}&network=localnet", + host_port() + )) + .send() + .await + .expect("Request failed.") + .json::() + .await?; + + let expected = expect!["module address {...}"]; + expected.assert_eq(&json.source); + + // check /list route + let response = client + .get(format!("http://{}/api/list", host_port())) + .send() + .await? + .text() + .await?; + + let expected = expect![[r#"{"localnet":{}}"#]]; + expected.assert_eq(response.as_str()); + + // check server rejects bad version header + let json = client + .get(format!( + "http://{}/api?address={address}&module={module}&network=localnet", + host_port() + )) + .header(IOTA_SOURCE_VALIDATION_VERSION_HEADER, "bogus") + .send() + .await + .expect("Request failed.") + .json::() + .await?; + + let expected = + expect!["Unsupported version 'bogus' specified in header x-iota-source-validation-version"]; + expected.assert_eq(&json.error); + + Ok(()) +} + +#[tokio::test] +async fn test_metrics_route() -> anyhow::Result<()> { + // Start metrics server + let metrics_listener = std::net::TcpListener::bind(METRICS_HOST_PORT)?; + let registry_service = start_prometheus_server(metrics_listener); + let prometheus_registry = registry_service.default_registry(); + SourceServiceMetrics::new(&prometheus_registry); + + let client = Client::new(); + let response = client + .get(format!("http://{METRICS_HOST_PORT}/metrics")) + .send() + .await + .expect("Request failed.") + .text() + .await?; + + let expected = expect![[r#" + # HELP total_requests Total number of requests received by Source Service + # TYPE total_requests counter + total_requests 0 + "#]]; + expected.assert_eq(response.as_str()); + Ok(()) +} + +#[test] +fn test_parse_package_config() -> anyhow::Result<()> { + let config = r#" +[[packages]] +source = "Repository" +[packages.values] +repository = "https://github.com/iotaledger/iota" +network = "mainnet" +[[packages.values.branches]] +branch = "framework/mainnet" +paths = [ + { path = "crates/iota-framework/packages/deepbook", watch = "0xdee9" }, + { path = "crates/iota-framework/packages/move-stdlib", watch = "0x1" }, + { path = "crates/iota-framework/packages/iota-framework", watch = "0x2" }, + { path = "crates/iota-framework/packages/iota-system", watch = "0x3" } +] + + [[packages]] + source = "Directory" + [packages.values] + paths = [ + { path = "home/user/some/upgradeable-package", watch = "0x1234" }, + { path = "home/user/some/immutable-package" }, + ] +"#; + + let config: Config = toml::from_str(config).unwrap(); + let expect = expect![[r#" + Config { + packages: [ + Repository( + RepositorySource { + repository: "https://github.com/iotaledger/iota", + network: Some( + Mainnet, + ), + branches: [ + Branch { + branch: "framework/mainnet", + paths: [ + Package { + path: "crates/iota-framework/packages/deepbook", + watch: Some( + 0x000000000000000000000000000000000000000000000000000000000000dee9, + ), + }, + Package { + path: "crates/iota-framework/packages/move-stdlib", + watch: Some( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + }, + Package { + path: "crates/iota-framework/packages/iota-framework", + watch: Some( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + }, + Package { + path: "crates/iota-framework/packages/iota-system", + watch: Some( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + }, + ], + }, + ], + }, + ), + Directory( + DirectorySource { + paths: [ + Package { + path: "home/user/some/upgradeable-package", + watch: Some( + 0x0000000000000000000000000000000000000000000000000000000000001234, + ), + }, + Package { + path: "home/user/some/immutable-package", + watch: None, + }, + ], + network: None, + }, + ), + ], + }"#]]; + expect.assert_eq(&format!("{:#?}", config)); + Ok(()) +} + +#[test] +fn test_clone_command() -> anyhow::Result<()> { + let source = RepositorySource { + repository: "https://github.com/user/repo".into(), + branches: vec![Branch { + branch: "main".into(), + paths: vec![ + Package { + path: "a".into(), + watch: None, + }, + Package { + path: "b".into(), + watch: None, + }, + ], + }], + network: Some(Network::Localnet), + }; + + let command = CloneCommand::new( + &source, + &source.branches[0], + PathBuf::from("/foo").as_path(), + )?; + let expect = expect![ + r#"CloneCommand { + args: [ + [ + "clone", + "--no-checkout", + "--depth=1", + "--filter=tree:0", + "--branch=main", + "https://github.com/user/repo", + "/foo/localnet/repo__main", + ], + [ + "-C", + "/foo/localnet/repo__main", + "sparse-checkout", + "set", + "--no-cone", + "a", + "b", + ], + [ + "-C", + "/foo/localnet/repo__main", + "checkout", + ], + ], + repo_url: "https://github.com/user/repo", +}"# + ]; + expect.assert_eq(&format!("{:#?}", command)); + Ok(()) +} diff --git a/crates/iota-source-validation/Cargo.toml b/crates/iota-source-validation/Cargo.toml new file mode 100644 index 00000000000..069f6e960fa --- /dev/null +++ b/crates/iota-source-validation/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "iota-source-validation" +version.workspace = true +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[lib] +path = "src/lib.rs" + +[dependencies] +anyhow.workspace = true +colored.workspace = true +thiserror.workspace = true +tracing.workspace = true +futures.workspace = true + +iota-json-rpc-types.workspace = true +iota-types.workspace = true +iota-sdk.workspace = true +iota-move-build.workspace = true + +move-binary-format.workspace = true +move-bytecode-source-map.workspace = true +move-command-line-common.workspace = true +move-compiler.workspace = true +move-core-types.workspace = true +move-package.workspace = true +move-symbol-pool.workspace = true + +tar.workspace = true +tempfile.workspace = true +flate2.workspace = true +ureq.workspace = true + + +[dev-dependencies] + +expect-test.workspace = true +rand.workspace = true +tempfile.workspace = true +tokio = { workspace = true, features = ["macros", "test-util"] } +tracing.workspace = true + +iota-test-transaction-builder.workspace = true +test-cluster.workspace = true diff --git a/crates/sui-source-validation/fixture/a/Move.toml b/crates/iota-source-validation/fixture/a/Move.toml similarity index 100% rename from crates/sui-source-validation/fixture/a/Move.toml rename to crates/iota-source-validation/fixture/a/Move.toml diff --git a/crates/iota-source-validation/fixture/a/sources/a.move b/crates/iota-source-validation/fixture/a/sources/a.move new file mode 100644 index 00000000000..41a2e0cfd79 --- /dev/null +++ b/crates/iota-source-validation/fixture/a/sources/a.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module a::a { + use b::b::b; + use b::c::c; + + public fun a(): u64 { + let var = 123; + let _ = var + 4; + b() + c() + } +} diff --git a/crates/sui-source-validation/fixture/b-v2/Move.toml b/crates/iota-source-validation/fixture/b-v2/Move.toml similarity index 100% rename from crates/sui-source-validation/fixture/b-v2/Move.toml rename to crates/iota-source-validation/fixture/b-v2/Move.toml diff --git a/crates/iota-source-validation/fixture/b-v2/sources/b.move b/crates/iota-source-validation/fixture/b-v2/sources/b.move new file mode 100644 index 00000000000..fe16510d276 --- /dev/null +++ b/crates/iota-source-validation/fixture/b-v2/sources/b.move @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::b { + public fun b(): u64 { + 42 + } + + public fun c(): u64 { + b() + 1 + } +} diff --git a/crates/iota-source-validation/fixture/b-v2/sources/c.move b/crates/iota-source-validation/fixture/b-v2/sources/c.move new file mode 100644 index 00000000000..5dee6024a2f --- /dev/null +++ b/crates/iota-source-validation/fixture/b-v2/sources/c.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::c { + public fun c(): u64 { + 43 + } +} diff --git a/crates/iota-source-validation/fixture/b-v2/sources/d.move b/crates/iota-source-validation/fixture/b-v2/sources/d.move new file mode 100644 index 00000000000..6eed2cc6bf2 --- /dev/null +++ b/crates/iota-source-validation/fixture/b-v2/sources/d.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::d { + public fun d(): u64 { + 44 + } +} diff --git a/crates/sui-source-validation/fixture/b/Move.toml b/crates/iota-source-validation/fixture/b/Move.toml similarity index 100% rename from crates/sui-source-validation/fixture/b/Move.toml rename to crates/iota-source-validation/fixture/b/Move.toml diff --git a/crates/iota-source-validation/fixture/b/sources/b.move b/crates/iota-source-validation/fixture/b/sources/b.move new file mode 100644 index 00000000000..bde4dfc7771 --- /dev/null +++ b/crates/iota-source-validation/fixture/b/sources/b.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::b { + public fun b(): u64 { + 42 + } +} diff --git a/crates/iota-source-validation/fixture/b/sources/c.move b/crates/iota-source-validation/fixture/b/sources/c.move new file mode 100644 index 00000000000..5dee6024a2f --- /dev/null +++ b/crates/iota-source-validation/fixture/b/sources/c.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::c { + public fun c(): u64 { + 43 + } +} diff --git a/crates/iota-source-validation/fixture/b/sources/d.move b/crates/iota-source-validation/fixture/b/sources/d.move new file mode 100644 index 00000000000..6eed2cc6bf2 --- /dev/null +++ b/crates/iota-source-validation/fixture/b/sources/d.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::d { + public fun d(): u64 { + 44 + } +} diff --git a/crates/sui-source-validation/fixture/c/Move.toml b/crates/iota-source-validation/fixture/c/Move.toml similarity index 100% rename from crates/sui-source-validation/fixture/c/Move.toml rename to crates/iota-source-validation/fixture/c/Move.toml diff --git a/crates/iota-source-validation/fixture/c/sources/b.move b/crates/iota-source-validation/fixture/c/sources/b.move new file mode 100644 index 00000000000..4bf58a4ab69 --- /dev/null +++ b/crates/iota-source-validation/fixture/c/sources/b.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module c::b { + public fun b(): u64 { + 42 + } +} diff --git a/crates/iota-source-validation/fixture/c/sources/c.move b/crates/iota-source-validation/fixture/c/sources/c.move new file mode 100644 index 00000000000..17b048e9d3e --- /dev/null +++ b/crates/iota-source-validation/fixture/c/sources/c.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module c::c { + public fun c(): u64 { + 43 + } +} diff --git a/crates/iota-source-validation/fixture/c/sources/d.move b/crates/iota-source-validation/fixture/c/sources/d.move new file mode 100644 index 00000000000..28a8eadb015 --- /dev/null +++ b/crates/iota-source-validation/fixture/c/sources/d.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module c::d { + public fun d(): u64 { + 44 + } +} diff --git a/crates/sui-source-validation/fixture/d/Move.toml b/crates/iota-source-validation/fixture/d/Move.toml similarity index 100% rename from crates/sui-source-validation/fixture/d/Move.toml rename to crates/iota-source-validation/fixture/d/Move.toml diff --git a/crates/iota-source-validation/fixture/d/sources/a.move b/crates/iota-source-validation/fixture/d/sources/a.move new file mode 100644 index 00000000000..4a74fdfdbbe --- /dev/null +++ b/crates/iota-source-validation/fixture/d/sources/a.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module d::d { + use b::b::b; + use c::c::c; + + public fun d(): u64 { + let var = 123; + let _ = var + 4; + b() + c() + } +} diff --git a/crates/sui-source-validation/fixture/e/Move.toml b/crates/iota-source-validation/fixture/e/Move.toml similarity index 100% rename from crates/sui-source-validation/fixture/e/Move.toml rename to crates/iota-source-validation/fixture/e/Move.toml diff --git a/crates/sui-source-validation/fixture/e/sources/e.move b/crates/iota-source-validation/fixture/e/sources/e.move similarity index 78% rename from crates/sui-source-validation/fixture/e/sources/e.move rename to crates/iota-source-validation/fixture/e/sources/e.move index a3419f3d87a..db8272ff810 100644 --- a/crates/sui-source-validation/fixture/e/sources/e.move +++ b/crates/iota-source-validation/fixture/e/sources/e.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module e::e { diff --git a/crates/sui-source-validation/fixture/versioned-a-depends-on-b/Move.toml b/crates/iota-source-validation/fixture/versioned-a-depends-on-b/Move.toml similarity index 100% rename from crates/sui-source-validation/fixture/versioned-a-depends-on-b/Move.toml rename to crates/iota-source-validation/fixture/versioned-a-depends-on-b/Move.toml diff --git a/crates/iota-source-validation/fixture/versioned-a-depends-on-b/sources/a.move b/crates/iota-source-validation/fixture/versioned-a-depends-on-b/sources/a.move new file mode 100644 index 00000000000..8bafb743427 --- /dev/null +++ b/crates/iota-source-validation/fixture/versioned-a-depends-on-b/sources/a.move @@ -0,0 +1,12 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module a::a { + use b::b::b; + use b::b::c; + + public fun a() : u64 { + b() + c() + } +} diff --git a/crates/iota-source-validation/fixture/versioned-b/Move.lock b/crates/iota-source-validation/fixture/versioned-b/Move.lock new file mode 100644 index 00000000000..f5057a832a4 --- /dev/null +++ b/crates/iota-source-validation/fixture/versioned-b/Move.lock @@ -0,0 +1,11 @@ +# @generated by Move, please check-in and do not edit manually. + +[move] +version = 0 +manifest_digest = "C70E0438875A0C3B10FA5995F317F701134E629D1B2E5F3DCA3621E50034F809" +deps_digest = "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855" + +[move.toolchain-version] +compiler-version = "$COMPILER_VERSION" +edition = "legacy" +flavor = "iota" diff --git a/crates/sui-source-validation/fixture/versioned-b/Move.toml b/crates/iota-source-validation/fixture/versioned-b/Move.toml similarity index 100% rename from crates/sui-source-validation/fixture/versioned-b/Move.toml rename to crates/iota-source-validation/fixture/versioned-b/Move.toml diff --git a/crates/iota-source-validation/fixture/versioned-b/sources/b.move b/crates/iota-source-validation/fixture/versioned-b/sources/b.move new file mode 100644 index 00000000000..fe16510d276 --- /dev/null +++ b/crates/iota-source-validation/fixture/versioned-b/sources/b.move @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::b { + public fun b(): u64 { + 42 + } + + public fun c(): u64 { + b() + 1 + } +} diff --git a/crates/iota-source-validation/fixture/versioned-b/sources/c.move b/crates/iota-source-validation/fixture/versioned-b/sources/c.move new file mode 100644 index 00000000000..5dee6024a2f --- /dev/null +++ b/crates/iota-source-validation/fixture/versioned-b/sources/c.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::c { + public fun c(): u64 { + 43 + } +} diff --git a/crates/iota-source-validation/fixture/versioned-b/sources/d.move b/crates/iota-source-validation/fixture/versioned-b/sources/d.move new file mode 100644 index 00000000000..6eed2cc6bf2 --- /dev/null +++ b/crates/iota-source-validation/fixture/versioned-b/sources/d.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module b::d { + public fun d(): u64 { + 44 + } +} diff --git a/crates/iota-source-validation/fixture/z/Move.toml b/crates/iota-source-validation/fixture/z/Move.toml new file mode 100644 index 00000000000..9326d194b32 --- /dev/null +++ b/crates/iota-source-validation/fixture/z/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "z" +version = "0.0.1" +published-at = "$STORAGE_ID" + +[dependencies] +Iota = { local = "$REPO_ROOT/crates/iota-framework/packages/iota-framework" } + +[addresses] +z = "$RUNTIME_ID" diff --git a/crates/iota-source-validation/fixture/z/sources/a.move b/crates/iota-source-validation/fixture/z/sources/a.move new file mode 100644 index 00000000000..e3a47049afd --- /dev/null +++ b/crates/iota-source-validation/fixture/z/sources/a.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module z::a { + public fun bar(x: u64): u64 { + z::b::foo(iota::math::max(x, 42)) + } +} diff --git a/crates/iota-source-validation/fixture/z/sources/b.move b/crates/iota-source-validation/fixture/z/sources/b.move new file mode 100644 index 00000000000..c3dabc28906 --- /dev/null +++ b/crates/iota-source-validation/fixture/z/sources/b.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module z::b { + public fun foo(x: u64): u64 { + x + } +} diff --git a/crates/iota-source-validation/src/lib.rs b/crates/iota-source-validation/src/lib.rs new file mode 100644 index 00000000000..f94e8f8c8f1 --- /dev/null +++ b/crates/iota-source-validation/src/lib.rs @@ -0,0 +1,835 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use core::fmt; +use std::{ + collections::HashMap, + ffi::OsStr, + fmt::Debug, + fs::File, + io::{self, Seek}, + path::{Path, PathBuf}, + process::Command, +}; + +use anyhow::{anyhow, bail, ensure}; +use colored::Colorize; +use futures::future; +use iota_move_build::CompiledPackage; +use iota_sdk::{ + apis::ReadApi, + error::Error, + rpc_types::{IotaObjectDataOptions, IotaRawData, IotaRawMoveObject, IotaRawMovePackage}, +}; +use iota_types::{base_types::ObjectID, error::IotaObjectResponseError}; +use move_binary_format::{access::ModuleAccess, CompiledModule}; +use move_bytecode_source_map::utils::source_map_from_file; +use move_command_line_common::{ + env::MOVE_HOME, + files::{ + extension_equals, find_filenames, MOVE_COMPILED_EXTENSION, MOVE_EXTENSION, + SOURCE_MAP_EXTENSION, + }, +}; +use move_compiler::{ + compiled_unit::NamedCompiledModule, + editions::{Edition, Flavor}, + shared::NumericalAddress, +}; +use move_core_types::account_address::AccountAddress; +use move_package::{ + compilation::{ + compiled_package::{CompiledPackage as MoveCompiledPackage, CompiledUnitWithSource}, + package_layout::CompiledPackageLayout, + }, + lock_file::schema::{Header, ToolchainVersion}, + source_package::{ + layout::SourcePackageLayout, + parsed_manifest::{FileName, PackageName}, + }, +}; +use move_symbol_pool::Symbol; +use tar::Archive; +use tempfile::TempDir; +use thiserror::Error; +use tracing::{debug, info}; + +#[cfg(test)] +mod tests; + +const CURRENT_COMPILER_VERSION: &str = env!("CARGO_PKG_VERSION"); +const LEGACY_COMPILER_VERSION: &str = CURRENT_COMPILER_VERSION; // TODO: update this when Move 2024 is released +const PRE_TOOLCHAIN_MOVE_LOCK_VERSION: u64 = 0; // Used to detect lockfiles pre-toolchain versioning support +const CANONICAL_UNIX_BINARY_NAME: &str = "iota"; +const CANONICAL_WIN_BINARY_NAME: &str = "iota.exe"; + +#[derive(Debug, Error)] +pub enum SourceVerificationError { + #[error("Could not read a dependency's on-chain object: {0:?}")] + DependencyObjectReadFailure(Error), + + #[error("Dependency object does not exist or was deleted: {0:?}")] + IotaObjectRefFailure(IotaObjectResponseError), + + #[error("Dependency ID contains a Iota object, not a Move package: {0}")] + ObjectFoundWhenPackageExpected(ObjectID, IotaRawMoveObject), + + #[error("On-chain version of dependency {package}::{module} was not found.")] + OnChainDependencyNotFound { package: Symbol, module: Symbol }, + + #[error("Could not deserialize on-chain dependency {address}::{module}.")] + OnChainDependencyDeserializationError { + address: AccountAddress, + module: Symbol, + }, + + #[error("Local version of dependency {address}::{module} was not found.")] + LocalDependencyNotFound { + address: AccountAddress, + module: Symbol, + }, + + #[error( + "Local dependency did not match its on-chain version at {address}::{package}::{module}" + )] + ModuleBytecodeMismatch { + address: AccountAddress, + package: Symbol, + module: Symbol, + }, + + #[error("Cannot check local module for {package}: {message}")] + CannotCheckLocalModules { package: Symbol, message: String }, + + #[error("On-chain address cannot be zero")] + ZeroOnChainAddresSpecifiedFailure, + + #[error("Invalid module {name} with error: {message}")] + InvalidModuleFailure { name: String, message: String }, +} + +#[derive(Debug, Error)] +pub struct AggregateSourceVerificationError(Vec); + +impl From for AggregateSourceVerificationError { + fn from(error: SourceVerificationError) -> Self { + AggregateSourceVerificationError(vec![error]) + } +} + +impl fmt::Display for AggregateSourceVerificationError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let AggregateSourceVerificationError(errors) = self; + match &errors[..] { + [] => unreachable!("Aggregate error with no errors"), + [error] => write!(f, "{}", error)?, + errors => { + writeln!(f, "Multiple source verification errors found:")?; + for error in errors { + write!(f, "\n- {}", error)?; + } + return Ok(()); + } + }; + Ok(()) + } +} + +/// How to handle package source during bytecode verification. +#[derive(PartialEq, Eq)] +pub enum SourceMode { + /// Don't verify source. + Skip, + + /// Verify source at the address specified in its manifest. + Verify, + + /// Verify source at an overridden address (only works if the package is not + /// published) + VerifyAt(AccountAddress), +} + +pub struct BytecodeSourceVerifier<'a> { + rpc_client: &'a ReadApi, +} + +/// Map package addresses and module names to package names and bytecode. +type LocalModules = HashMap<(AccountAddress, Symbol), (Symbol, CompiledModule)>; +/// Map package addresses and modules names to bytecode (package names are gone +/// in the on-chain representation). +type OnChainModules = HashMap<(AccountAddress, Symbol), CompiledModule>; + +impl<'a> BytecodeSourceVerifier<'a> { + pub fn new(rpc_client: &'a ReadApi) -> Self { + BytecodeSourceVerifier { rpc_client } + } + + /// Helper wrapper to verify that all local Move package dependencies' and + /// root bytecode matches the bytecode at the address specified on the + /// Iota network we are publishing to. + pub async fn verify_package_root_and_deps( + &self, + compiled_package: &CompiledPackage, + root_on_chain_address: AccountAddress, + ) -> Result<(), AggregateSourceVerificationError> { + self.verify_package( + compiled_package, + // verify_deps + true, + SourceMode::VerifyAt(root_on_chain_address), + ) + .await + } + + /// Helper wrapper to verify that all local Move package root bytecode + /// matches the bytecode at the address specified on the Iota network we + /// are publishing to. + pub async fn verify_package_root( + &self, + compiled_package: &CompiledPackage, + root_on_chain_address: AccountAddress, + ) -> Result<(), AggregateSourceVerificationError> { + self.verify_package( + compiled_package, + // verify_deps + false, + SourceMode::VerifyAt(root_on_chain_address), + ) + .await + } + + /// Helper wrapper to verify that all local Move package dependencies' + /// matches the bytecode at the address specified on the Iota network we + /// are publishing to. + pub async fn verify_package_deps( + &self, + compiled_package: &CompiledPackage, + ) -> Result<(), AggregateSourceVerificationError> { + self.verify_package( + compiled_package, + // verify_deps + true, + SourceMode::Skip, + ) + .await + } + + /// Verify that all local Move package dependencies' and/or root bytecode + /// matches the bytecode at the address specified on the Iota network we + /// are publishing to. If `verify_deps` is true, the dependencies are + /// verified. If `root_on_chain_address` is specified, the root is + /// verified against a package at `root_on_chain_address`. + pub async fn verify_package( + &self, + compiled_package: &CompiledPackage, + verify_deps: bool, + source_mode: SourceMode, + ) -> Result<(), AggregateSourceVerificationError> { + let mut on_chain_pkgs = vec![]; + match &source_mode { + SourceMode::Skip => (), + // On-chain address for matching root package cannot be zero + SourceMode::VerifyAt(AccountAddress::ZERO) => { + return Err(SourceVerificationError::ZeroOnChainAddresSpecifiedFailure.into()); + } + SourceMode::VerifyAt(root_address) => on_chain_pkgs.push(*root_address), + SourceMode::Verify => { + on_chain_pkgs.extend(compiled_package.published_at.as_ref().map(|id| **id)) + } + }; + + if verify_deps { + on_chain_pkgs.extend( + compiled_package + .dependency_ids + .published + .values() + .map(|id| **id), + ); + } + + let local_modules = local_modules(&compiled_package.package, verify_deps, source_mode)?; + let mut on_chain_modules = self.on_chain_modules(on_chain_pkgs.into_iter()).await?; + + let mut errors = Vec::new(); + for ((address, module), (package, local_module)) in local_modules { + let Some(on_chain_module) = on_chain_modules.remove(&(address, module)) else { + errors.push(SourceVerificationError::OnChainDependencyNotFound { package, module }); + continue; + }; + + // compare local bytecode to on-chain bytecode to ensure integrity of our + // dependencies + if local_module != on_chain_module { + errors.push(SourceVerificationError::ModuleBytecodeMismatch { + address, + package, + module, + }); + } + } + + if let Some(((address, module), _)) = on_chain_modules.into_iter().next() { + errors.push(SourceVerificationError::LocalDependencyNotFound { address, module }); + } + + if !errors.is_empty() { + return Err(AggregateSourceVerificationError(errors)); + } + + Ok(()) + } + + async fn pkg_for_address( + &self, + addr: AccountAddress, + ) -> Result { + // Move packages are specified with an AccountAddress, but are + // fetched from a iota network via iota_getObject, which takes an object ID + let obj_id = ObjectID::from(addr); + + // fetch the Iota object at the address specified for the package in the local + // resolution table if future packages with a large set of dependency + // packages prove too slow to verify, batched object fetching should be + // added to the ReadApi & used here + let obj_read = self + .rpc_client + .get_object_with_options(obj_id, IotaObjectDataOptions::new().with_bcs()) + .await + .map_err(SourceVerificationError::DependencyObjectReadFailure)?; + + let obj = obj_read + .into_object() + .map_err(SourceVerificationError::IotaObjectRefFailure)? + .bcs + .ok_or_else(|| { + SourceVerificationError::DependencyObjectReadFailure(Error::DataError( + "Bcs field is not found".to_string(), + )) + })?; + + match obj { + IotaRawData::Package(pkg) => Ok(pkg), + IotaRawData::MoveObject(move_obj) => Err( + SourceVerificationError::ObjectFoundWhenPackageExpected(obj_id, move_obj), + ), + } + } + + async fn on_chain_modules( + &self, + addresses: impl Iterator + Clone, + ) -> Result { + let resp = future::join_all(addresses.clone().map(|addr| self.pkg_for_address(addr))).await; + let mut map = OnChainModules::new(); + let mut err = vec![]; + + for (storage_id, pkg) in addresses.zip(resp) { + let IotaRawMovePackage { module_map, .. } = pkg?; + for (name, bytes) in module_map { + let Ok(module) = CompiledModule::deserialize_with_defaults(&bytes) else { + err.push( + SourceVerificationError::OnChainDependencyDeserializationError { + address: storage_id, + module: name.into(), + }, + ); + continue; + }; + + let runtime_id = *module.self_id().address(); + map.insert((runtime_id, Symbol::from(name)), module); + } + } + + if !err.is_empty() { + return Err(AggregateSourceVerificationError(err)); + } + + Ok(map) + } +} + +fn substitute_root_address( + named_module: &NamedCompiledModule, + root: AccountAddress, +) -> Result { + let mut module = named_module.module.clone(); + let address_idx = module.self_handle().address; + + let Some(addr) = module.address_identifiers.get_mut(address_idx.0 as usize) else { + return Err(SourceVerificationError::InvalidModuleFailure { + name: named_module.name.to_string(), + message: "Self address field missing".into(), + }); + }; + + if *addr != AccountAddress::ZERO { + return Err(SourceVerificationError::InvalidModuleFailure { + name: named_module.name.to_string(), + message: "Self address already populated".to_string(), + }); + } + + *addr = root; + Ok(module) +} + +fn local_modules( + compiled_package: &MoveCompiledPackage, + include_deps: bool, + source_mode: SourceMode, +) -> Result { + let mut map = LocalModules::new(); + + if include_deps { + // Compile dependencies with prior compilers if needed. + let deps_compiled_units = units_for_toolchain(&compiled_package.deps_compiled_units) + .map_err(|e| SourceVerificationError::CannotCheckLocalModules { + package: compiled_package.compiled_package_info.package_name, + message: e.to_string(), + })?; + + for (package, local_unit) in deps_compiled_units { + let m = &local_unit.unit; + let module = m.name; + let address = m.address.into_inner(); + if address == AccountAddress::ZERO { + continue; + } + + map.insert((address, module), (package, m.module.clone())); + } + } + + let root_package = compiled_package.compiled_package_info.package_name; + match source_mode { + SourceMode::Skip => { /* nop */ } + + // Include the root compiled units, at their current addresses. + SourceMode::Verify => { + // Compile root modules with prior compiler if needed. + let root_compiled_units = { + let root_compiled_units = compiled_package + .root_compiled_units + .iter() + .map(|u| ("root".into(), u.clone())) + .collect::>(); + + units_for_toolchain(&root_compiled_units).map_err(|e| { + SourceVerificationError::CannotCheckLocalModules { + package: compiled_package.compiled_package_info.package_name, + message: e.to_string(), + } + })? + }; + + for (_, local_unit) in root_compiled_units { + let m = &local_unit.unit; + + let module = m.name; + let address = m.address.into_inner(); + if address == AccountAddress::ZERO { + return Err(SourceVerificationError::InvalidModuleFailure { + name: module.to_string(), + message: "Can't verify unpublished source".to_string(), + }); + } + + map.insert((address, module), (root_package, m.module.clone())); + } + } + + // Include the root compiled units, and any unpublished dependencies with their + // addresses substituted + SourceMode::VerifyAt(root_address) => { + // Compile root modules with prior compiler if needed. + let root_compiled_units = { + let root_compiled_units = compiled_package + .root_compiled_units + .iter() + .map(|u| ("root".into(), u.clone())) + .collect::>(); + + units_for_toolchain(&root_compiled_units).map_err(|e| { + SourceVerificationError::CannotCheckLocalModules { + package: compiled_package.compiled_package_info.package_name, + message: e.to_string(), + } + })? + }; + + for (_, local_unit) in root_compiled_units { + let m = &local_unit.unit; + + let module = m.name; + map.insert( + (root_address, module), + (root_package, substitute_root_address(m, root_address)?), + ); + } + + for (package, local_unit) in &compiled_package.deps_compiled_units { + let m = &local_unit.unit; + let module = m.name; + let address = m.address.into_inner(); + if address != AccountAddress::ZERO { + continue; + } + + map.insert( + (root_address, module), + (*package, substitute_root_address(m, root_address)?), + ); + } + } + } + + Ok(map) +} + +fn current_toolchain() -> ToolchainVersion { + ToolchainVersion { + compiler_version: CURRENT_COMPILER_VERSION.into(), + edition: Edition::LEGACY, // does not matter, unused for current_toolchain + flavor: Flavor::Iota, // does not matter, unused for current_toolchain + } +} + +fn legacy_toolchain() -> ToolchainVersion { + ToolchainVersion { + compiler_version: LEGACY_COMPILER_VERSION.into(), + edition: Edition::LEGACY, + flavor: Flavor::Iota, + } +} + +/// Ensures `compiled_units` are compiled with the right compiler version, based +/// on Move.lock contents. This works by detecting if a compiled unit requires a +/// prior compiler version: +/// - If so, download the compiler, recompile the unit, and return that unit in +/// the result. +/// - If not, simply keep the current compiled unit. +fn units_for_toolchain( + compiled_units: &Vec<(PackageName, CompiledUnitWithSource)>, +) -> anyhow::Result> { + if std::env::var("IOTA_RUN_TOOLCHAIN_BUILD").is_err() { + return Ok(compiled_units.clone()); + } + let mut package_version_map: HashMap)> = + HashMap::new(); + // First iterate over packages, mapping the required version for each package in + // `package_version_map`. + for (package, local_unit) in compiled_units { + if let Some((_, units)) = package_version_map.get_mut(package) { + // We've processed this package's required version. + units.push(local_unit.clone()); + continue; + } + + if iota_types::is_system_package(local_unit.unit.address.into_inner()) { + // System packages are always compiled with the current compiler. + package_version_map.insert(*package, (current_toolchain(), vec![local_unit.clone()])); + continue; + } + + let package_root = SourcePackageLayout::try_find_root(&local_unit.source_path)?; + let lock_file = package_root.join(SourcePackageLayout::Lock.path()); + if !lock_file.exists() { + // No lock file implies current compiler for this package. + package_version_map.insert(*package, (current_toolchain(), vec![local_unit.clone()])); + continue; + } + + let mut lock_file = File::open(lock_file)?; + let lock_version = Header::read(&mut lock_file)?.version; + if lock_version == PRE_TOOLCHAIN_MOVE_LOCK_VERSION { + // No need to attempt reading lock file toolchain + debug!("{package} on legacy compiler",); + package_version_map.insert(*package, (legacy_toolchain(), vec![local_unit.clone()])); + continue; + } + + // Read lock file toolchain info + lock_file.rewind()?; + let toolchain_version = ToolchainVersion::read(&mut lock_file)?; + match toolchain_version { + // No ToolchainVersion and new Move.lock version implies current compiler. + None => { + debug!("{package} on current compiler @ {CURRENT_COMPILER_VERSION}",); + package_version_map + .insert(*package, (current_toolchain(), vec![local_unit.clone()])); + } + // This dependency uses the current compiler. + Some(ToolchainVersion { + compiler_version, .. + }) if compiler_version == CURRENT_COMPILER_VERSION => { + debug!("{package} on current compiler @ {CURRENT_COMPILER_VERSION}",); + package_version_map + .insert(*package, (current_toolchain(), vec![local_unit.clone()])); + } + // This dependency needs a prior compiler. Mark it and compile. + Some(toolchain_version) => { + println!( + "{} {package} compiler @ {}", + "REQUIRE".bold().green(), + toolchain_version.compiler_version.yellow(), + ); + package_version_map.insert(*package, (toolchain_version, vec![local_unit.clone()])); + } + } + } + + let mut units = vec![]; + // Iterate over compiled units, and check if they need to be recompiled and + // replaced by a prior compiler's output. + for (package, (toolchain_version, local_units)) in package_version_map { + if toolchain_version.compiler_version == CURRENT_COMPILER_VERSION { + let local_units: Vec<_> = local_units.iter().map(|u| (package, u.clone())).collect(); + units.extend(local_units); + continue; + } + + if local_units.is_empty() { + bail!("Expected one or more modules, but none found"); + } + let package_root = SourcePackageLayout::try_find_root(&local_units[0].source_path)?; + let install_dir = tempfile::tempdir()?; // place compiled packages in this temp dir, don't pollute this packages build dir + download_and_compile( + package_root.clone(), + &install_dir, + &toolchain_version, + &package, + )?; + + let compiled_unit_paths = vec![package_root.clone()]; + let compiled_units = find_filenames(&compiled_unit_paths, |path| { + extension_equals(path, MOVE_COMPILED_EXTENSION) + })?; + let build_path = install_dir + .path() + .join(CompiledPackageLayout::path(&CompiledPackageLayout::Root)) + .join(package.as_str()); + debug!("build path is {}", build_path.display()); + + // Add all units compiled with the previous compiler. + for bytecode_path in compiled_units { + info!("bytecode path {bytecode_path}, {package}"); + let local_unit = decode_bytecode_file(build_path.clone(), &package, &bytecode_path)?; + units.push((package, local_unit)) + } + } + Ok(units) +} + +fn download_and_compile( + root: PathBuf, + install_dir: &TempDir, + ToolchainVersion { + compiler_version, + edition, + flavor, + }: &ToolchainVersion, + dep_name: &Symbol, +) -> anyhow::Result<()> { + let dest_dir = PathBuf::from_iter([&*MOVE_HOME, "binaries"]); // E.g., ~/.move/binaries + let dest_version = dest_dir.join(compiler_version); + let mut dest_canonical_path = dest_version.clone(); + dest_canonical_path.extend(["target", "release"]); + let mut dest_canonical_binary = dest_canonical_path.clone(); + + let platform = detect_platform(&root, compiler_version, &dest_canonical_path)?; + if platform == "windows-x86_64" { + dest_canonical_binary.push(CANONICAL_WIN_BINARY_NAME); + } else { + dest_canonical_binary.push(CANONICAL_UNIX_BINARY_NAME); + } + + if !dest_canonical_binary.exists() { + // Check the platform and proceed if we can download a binary. If not, the user + // should follow error instructions to sideload the binary. Download if + // binary does not exist. + let mainnet_url = format!( + "https://github.com/iotaledger/iota/releases/download/mainnet-v{compiler_version}/iota-mainnet-v{compiler_version}-{platform}.tgz", + ); + + println!( + "{} mainnet compiler @ {} (this may take a while)", + "DOWNLOADING".bold().green(), + compiler_version.yellow() + ); + + let mut response = match ureq::get(&mainnet_url).call() { + Ok(response) => response, + Err(ureq::Error::Status(404, _)) => { + println!( + "{} iota mainnet compiler {} not available, attempting to download testnet compiler release...", + "WARNING".bold().yellow(), + compiler_version.yellow() + ); + println!( + "{} testnet compiler @ {} (this may take a while)", + "DOWNLOADING".bold().green(), + compiler_version.yellow() + ); + let testnet_url = format!("https://github.com/iotaledger/iota/releases/download/testnet-v{compiler_version}/iota-testnet-v{compiler_version}-{platform}.tgz"); + ureq::get(&testnet_url).call()? + } + Err(e) => return Err(e.into()), + }.into_reader(); + + let dest_tarball = dest_version.join(format!("{}.tgz", compiler_version)); + debug!("tarball destination: {} ", dest_tarball.display()); + if let Some(parent) = dest_tarball.parent() { + std::fs::create_dir_all(parent) + .map_err(|e| anyhow!("failed to create directory for tarball: {e}"))?; + } + let mut dest_file = File::create(&dest_tarball)?; + io::copy(&mut response, &mut dest_file)?; + + // Extract the tarball using the tar crate + let tar_gz = File::open(&dest_tarball)?; + let tar = flate2::read::GzDecoder::new(tar_gz); + let mut archive = Archive::new(tar); + archive + .unpack(&dest_version) + .map_err(|e| anyhow!("failed to untar compiler binary: {e}"))?; + + let mut dest_binary = dest_version.clone(); + dest_binary.extend(["target", "release"]); + if platform == "windows-x86_64" { + dest_binary.push(&format!("iota-{platform}.exe")); + } else { + dest_binary.push(&format!("iota-{platform}")); + } + let dest_binary_os = OsStr::new(dest_binary.as_path()); + set_executable_permission(dest_binary_os)?; + std::fs::rename(dest_binary_os, dest_canonical_binary.clone())?; + } + + debug!( + "{} move build --default-move-edition {} --default-move-flavor {} -p {} --install-dir {}", + dest_canonical_binary.display(), + edition.to_string().as_str(), + flavor.to_string().as_str(), + root.display(), + install_dir.path().display(), + ); + info!( + "{} {} (compiler @ {})", + "BUILDING".bold().green(), + dep_name.as_str(), + compiler_version.yellow() + ); + Command::new(dest_canonical_binary) + .args([ + OsStr::new("move"), + OsStr::new("build"), + OsStr::new("--default-move-edition"), + OsStr::new(edition.to_string().as_str()), + OsStr::new("--default-move-flavor"), + OsStr::new(flavor.to_string().as_str()), + OsStr::new("-p"), + OsStr::new(root.as_path()), + OsStr::new("--install-dir"), + OsStr::new(install_dir.path()), + ]) + .output() + .map_err(|e| { + anyhow!("failed to build package from compiler binary {compiler_version}: {e}",) + })?; + Ok(()) +} + +fn detect_platform( + package_path: &Path, + compiler_version: &String, + dest_dir: &Path, +) -> anyhow::Result { + let s = match (std::env::consts::OS, std::env::consts::ARCH) { + ("macos", "aarch64") => "macos-arm64", + ("macos", "x86_64") => "macos-x86_64", + ("linux", "x86_64") => "ubuntu-x86_64", + ("windows", "x86_64") => "windows-x86_64", + (os, arch) => { + let mut binary_name = CANONICAL_UNIX_BINARY_NAME; + if os == "windows" { + binary_name = CANONICAL_WIN_BINARY_NAME; + }; + bail!( + "The package {} needs to be built with iota compiler version {compiler_version} but there \ + is no binary release available to download for your platform:\n\ + Operating System: {os}\n\ + Architecture: {arch}\n\ + You can manually put a {binary_name} binary for your platform in {} and rerun your command to continue.", + package_path.display(), + dest_dir.display(), + ) + } + }; + Ok(s.into()) +} + +#[cfg(unix)] +fn set_executable_permission(path: &OsStr) -> anyhow::Result<()> { + use std::{fs, os::unix::prelude::PermissionsExt}; + let mut perms = fs::metadata(path)?.permissions(); + perms.set_mode(0o755); + fs::set_permissions(path, perms)?; + Ok(()) +} + +#[cfg(not(unix))] +fn set_executable_permission(path: &OsStr) -> anyhow::Result<()> { + Command::new("icacls") + .args([path, OsStr::new("/grant"), OsStr::new("Everyone:(RX)")]) + .status()?; + Ok(()) +} + +fn decode_bytecode_file( + root_path: PathBuf, + package_name: &Symbol, + bytecode_path_str: &str, +) -> anyhow::Result { + let package_name_opt = Some(*package_name); + let bytecode_path = Path::new(bytecode_path_str); + let path_to_file = CompiledPackageLayout::path_to_file_after_category(bytecode_path); + let bytecode_bytes = std::fs::read(bytecode_path)?; + let source_map = source_map_from_file( + &root_path + .join(CompiledPackageLayout::SourceMaps.path()) + .join(&path_to_file) + .with_extension(SOURCE_MAP_EXTENSION), + )?; + let source_path = &root_path + .join(CompiledPackageLayout::Sources.path()) + .join(path_to_file) + .with_extension(MOVE_EXTENSION); + ensure!( + source_path.is_file(), + "Error decoding package: Unable to find corresponding source file for '{bytecode_path_str}' in package {package_name}" + ); + let module = CompiledModule::deserialize_with_defaults(&bytecode_bytes)?; + let (address_bytes, module_name) = { + let id = module.self_id(); + let parsed_addr = NumericalAddress::new( + id.address().into_bytes(), + move_compiler::shared::NumberFormat::Hex, + ); + let module_name = FileName::from(id.name().as_str()); + (parsed_addr, module_name) + }; + let unit = NamedCompiledModule { + package_name: package_name_opt, + address: address_bytes, + name: module_name, + module, + source_map, + }; + Ok(CompiledUnitWithSource { + unit, + source_path: source_path.clone(), + }) +} diff --git a/crates/iota-source-validation/src/tests.rs b/crates/iota-source-validation/src/tests.rs new file mode 100644 index 00000000000..fbabc0ac1f9 --- /dev/null +++ b/crates/iota-source-validation/src/tests.rs @@ -0,0 +1,763 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::HashMap, + fs, io, + path::{Path, PathBuf}, + str, +}; + +use expect_test::expect; +use iota_json_rpc_types::{ + get_new_package_obj_from_response, get_new_package_upgrade_cap_from_response, +}; +use iota_move_build::{BuildConfig, CompiledPackage, IotaPackageHooks}; +use iota_sdk::wallet_context::WalletContext; +use iota_test_transaction_builder::{make_publish_transaction, make_publish_transaction_with_deps}; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, TransactionDigest}, + move_package::UpgradePolicy, + transaction::TEST_ONLY_GAS_UNIT_FOR_PUBLISH, + IOTA_SYSTEM_STATE_OBJECT_ID, +}; +use move_core_types::account_address::AccountAddress; +use test_cluster::TestClusterBuilder; + +use crate::{BytecodeSourceVerifier, SourceMode, CURRENT_COMPILER_VERSION}; + +#[tokio::test] +async fn successful_verification() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + + let b_ref_fixtures = tempfile::tempdir()?; + let b_ref = { + let b_src = copy_published_package(&b_ref_fixtures, "b", IotaAddress::ZERO).await?; + publish_package(context, b_src).await.0 + }; + + let b_pkg_fixtures = tempfile::tempdir()?; + let b_pkg = { + let b_src = copy_published_package(&b_pkg_fixtures, "b", b_ref.0.into()).await?; + compile_package(b_src) + }; + + let a_fixtures = tempfile::tempdir()?; + let (a_pkg, a_ref) = { + copy_published_package(&a_fixtures, "b", b_ref.0.into()).await?; + let a_src = copy_published_package(&a_fixtures, "a", IotaAddress::ZERO).await?; + ( + compile_package(a_src.clone()), + publish_package(context, a_src).await.0, + ) + }; + + let client = context.get_client().await?; + let verifier = BytecodeSourceVerifier::new(client.read_api()); + + // Skip deps and root + verifier + .verify_package(&a_pkg, /* verify_deps */ false, SourceMode::Skip) + .await + .unwrap(); + + // Verify root without updating the address + verifier + .verify_package(&b_pkg, /* verify_deps */ false, SourceMode::Verify) + .await + .unwrap(); + + // Verify deps but skip root + verifier.verify_package_deps(&a_pkg).await.unwrap(); + + // Skip deps but verify root + verifier + .verify_package_root(&a_pkg, a_ref.0.into()) + .await + .unwrap(); + + // Verify both deps and root + verifier + .verify_package_root_and_deps(&a_pkg, a_ref.0.into()) + .await + .unwrap(); + + Ok(()) +} + +#[tokio::test] +async fn successful_verification_unpublished_deps() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + let fixtures = tempfile::tempdir()?; + + let a_src = { + copy_published_package(&fixtures, "b", IotaAddress::ZERO).await?; + copy_published_package(&fixtures, "a", IotaAddress::ZERO).await? + }; + + let a_pkg = compile_package(a_src.clone()); + let a_ref = publish_package_and_deps(context, a_src).await; + + let client = context.get_client().await?; + let verifier = BytecodeSourceVerifier::new(client.read_api()); + + // Verify the root package which now includes dependency modules + verifier + .verify_package_root(&a_pkg, a_ref.0.into()) + .await + .unwrap(); + + Ok(()) +} + +#[tokio::test] +async fn successful_verification_module_ordering() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + + // This package contains a module that refers to itself, and also to the iota + // framework. Its self-address is `0x0` (i.e. compares lower than the + // framework's `0x2`) before publishing, and will be greater after + // publishing. + // + // This is a regression test for a source validation bug related to module order + // instability where the on-chain package (which is compiled with + // self-address = 0x0, and later substituted) orders module handles + // (references to other modules) differently to the package compiled as a + // dependency with its self-address already set as its published address. + let z_ref_fixtures = tempfile::tempdir()?; + let z_ref = { + let z_src = copy_published_package(&z_ref_fixtures, "z", IotaAddress::ZERO).await?; + publish_package(context, z_src).await.0 + }; + + let z_pkg_fixtures = tempfile::tempdir()?; + let z_pkg = { + let z_src = copy_published_package(&z_pkg_fixtures, "z", z_ref.0.into()).await?; + compile_package(z_src) + }; + + let client = context.get_client().await?; + let verifier = BytecodeSourceVerifier::new(client.read_api()); + + let verify_deps = false; + verifier + .verify_package(&z_pkg, verify_deps, SourceMode::Verify) + .await + .unwrap(); + + Ok(()) +} + +#[tokio::test] +async fn successful_verification_upgrades() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + + let b_v1_fixtures = tempfile::tempdir()?; + let (b_v1, b_cap) = { + let b_src = copy_published_package(&b_v1_fixtures, "b", IotaAddress::ZERO).await?; + publish_package(context, b_src).await + }; + + let b_v2_fixtures = tempfile::tempdir()?; + let b_v2 = { + let b_src = copy_published_package(&b_v2_fixtures, "b-v2", IotaAddress::ZERO).await?; + upgrade_package(context, b_v1.0, b_cap.0, b_src).await + }; + + let b_fixtures = tempfile::tempdir()?; + let (b_pkg, e_pkg) = { + let b_src = + copy_upgraded_package(&b_fixtures, "b-v2", b_v2.0.into(), b_v1.0.into()).await?; + let e_src = copy_published_package(&b_fixtures, "e", IotaAddress::ZERO).await?; + (compile_package(b_src), compile_package(e_src)) + }; + + let client = context.get_client().await?; + let verifier = BytecodeSourceVerifier::new(client.read_api()); + + // Verify the upgraded package b-v2 as the root. + let verify_deps = false; + verifier + .verify_package(&b_pkg, verify_deps, SourceMode::Verify) + .await + .unwrap(); + + // Verify the upgraded package b-v2 as a dep of e. + verifier.verify_package_deps(&e_pkg).await.unwrap(); + + Ok(()) +} + +#[tokio::test] +async fn fail_verification_bad_address() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + + let b_ref_fixtures = tempfile::tempdir()?; + let b_ref = { + let b_src = copy_published_package(&b_ref_fixtures, "b", IotaAddress::ZERO).await?; + publish_package(context, b_src).await.0 + }; + + let a_pkg_fixtures = tempfile::tempdir()?; + let a_pkg = { + copy_published_package(&a_pkg_fixtures, "b", b_ref.0.into()).await?; + let a_src = copy_published_package(&a_pkg_fixtures, "a", IotaAddress::ZERO).await?; + publish_package(context, a_src.clone()).await; + compile_package(a_src) + }; + + let client = context.get_client().await?; + let verifier = BytecodeSourceVerifier::new(client.read_api()); + + let expected = expect!["On-chain address cannot be zero"]; + expected.assert_eq( + &verifier + .verify_package_root_and_deps(&a_pkg, AccountAddress::ZERO) + .await + .unwrap_err() + .to_string(), + ); + + Ok(()) +} + +#[tokio::test] +async fn fail_to_verify_unpublished_root() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + + let b_pkg_fixtures = tempfile::tempdir()?; + let b_pkg = { + let b_src = copy_published_package(&b_pkg_fixtures, "b", IotaAddress::ZERO).await?; + compile_package(b_src) + }; + + let client = context.get_client().await?; + let verifier = BytecodeSourceVerifier::new(client.read_api()); + + // Trying to verify the root package, which hasn't been published -- this is + // going to fail because there is no on-chain package to verify against. + let expected = expect!["Invalid module b with error: Can't verify unpublished source"]; + expected.assert_eq( + &verifier + .verify_package(&b_pkg, /* verify_deps */ false, SourceMode::Verify) + .await + .unwrap_err() + .to_string(), + ); + + Ok(()) +} + +#[tokio::test] +async fn rpc_call_failed_during_verify() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + + let b_ref_fixtures = tempfile::tempdir()?; + let b_ref = { + let b_src = copy_published_package(&b_ref_fixtures, "b", IotaAddress::ZERO).await?; + publish_package(context, b_src).await.0 + }; + + let a_ref_fixtures = tempfile::tempdir()?; + let a_ref = { + copy_published_package(&a_ref_fixtures, "b", b_ref.0.into()).await?; + let a_src = copy_published_package(&a_ref_fixtures, "a", IotaAddress::ZERO).await?; + publish_package(context, a_src).await.0 + }; + let _a_addr: IotaAddress = a_ref.0.into(); + + let client = context.get_client().await?; + let _verifier = BytecodeSourceVerifier::new(client.read_api()); + + // TODO: Dropping cluster no longer stops the network. Need to look into this + // and see what we want to do with it. + // Stop the network, so future RPC requests fail. + // drop(cluster); + // + // assert!(matches!( + // verifier.verify_package_deps(&a_pkg).await, + // Err(SourceVerificationError::DependencyObjectReadFailure(_)), + // ),); + // + // assert!(matches!( + // verifier + // .verify_package_root_and_deps(&a_pkg, a_addr.into()) + // .await, + // Err(SourceVerificationError::DependencyObjectReadFailure(_)), + // ),); + // + // assert!(matches!( + // verifier + // .verify_package_root(&a_pkg, a_addr.into()) + // .await, + // Err(SourceVerificationError::DependencyObjectReadFailure(_)), + // ),); + // + + Ok(()) +} + +#[tokio::test] +async fn package_not_found() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + let mut stable_addrs = HashMap::new(); + + let a_pkg_fixtures = tempfile::tempdir()?; + let a_pkg = { + let b_id = IotaAddress::random_for_testing_only(); + stable_addrs.insert(b_id, ""); + copy_published_package(&a_pkg_fixtures, "b", b_id).await?; + let a_src = copy_published_package(&a_pkg_fixtures, "a", IotaAddress::ZERO).await?; + compile_package(a_src) + }; + + let client = context.get_client().await?; + let verifier = BytecodeSourceVerifier::new(client.read_api()); + + let Err(err) = verifier.verify_package_deps(&a_pkg).await else { + panic!("Expected verification to fail"); + }; + + let expected = + expect!["Dependency object does not exist or was deleted: NotExists { object_id: 0x }"]; + expected.assert_eq(&sanitize_id(err.to_string(), &stable_addrs)); + + let package_root = AccountAddress::random(); + stable_addrs.insert(IotaAddress::from(package_root), ""); + let Err(err) = verifier + .verify_package_root_and_deps(&a_pkg, package_root) + .await + else { + panic!("Expected verification to fail"); + }; + + // below may refer to either the package_root or dependent package `b` + // (the check reports the first missing object nondeterministically) + let expected = + expect!["Dependency object does not exist or was deleted: NotExists { object_id: 0x }"]; + expected.assert_eq(&sanitize_id(err.to_string(), &stable_addrs)); + + let package_root = AccountAddress::random(); + stable_addrs.insert(IotaAddress::from(package_root), ""); + let Err(err) = verifier.verify_package_root(&a_pkg, package_root).await else { + panic!("Expected verification to fail"); + }; + + let expected = + expect!["Dependency object does not exist or was deleted: NotExists { object_id: 0x }"]; + expected.assert_eq(&sanitize_id(err.to_string(), &stable_addrs)); + + Ok(()) +} + +#[tokio::test] +async fn dependency_is_an_object() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + + let a_pkg_fixtures = tempfile::tempdir()?; + let a_pkg = { + let b_id = IOTA_SYSTEM_STATE_OBJECT_ID.into(); + copy_published_package(&a_pkg_fixtures, "b", b_id).await?; + let a_src = copy_published_package(&a_pkg_fixtures, "a", IotaAddress::ZERO).await?; + compile_package(a_src) + }; + let client = context.get_client().await?; + let verifier = BytecodeSourceVerifier::new(client.read_api()); + + let expected = expect![ + "Dependency ID contains a Iota object, not a Move package: 0x0000000000000000000000000000000000000000000000000000000000000005" + ]; + expected.assert_eq( + &verifier + .verify_package_deps(&a_pkg) + .await + .unwrap_err() + .to_string(), + ); + + Ok(()) +} + +#[tokio::test] +async fn module_not_found_on_chain() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + + let b_ref_fixtures = tempfile::tempdir()?; + let b_ref = { + let b_src = copy_published_package(&b_ref_fixtures, "b", IotaAddress::ZERO).await?; + tokio::fs::remove_file(b_src.join("sources").join("c.move")).await?; + publish_package(context, b_src).await.0 + }; + + let a_pkg_fixtures = tempfile::tempdir()?; + let a_pkg = { + copy_published_package(&a_pkg_fixtures, "b", b_ref.0.into()).await?; + let a_src = copy_published_package(&a_pkg_fixtures, "a", IotaAddress::ZERO).await?; + compile_package(a_src) + }; + let client = context.get_client().await?; + let verifier = BytecodeSourceVerifier::new(client.read_api()); + + let Err(err) = verifier.verify_package_deps(&a_pkg).await else { + panic!("Expected verification to fail"); + }; + + let expected = expect!["On-chain version of dependency b::c was not found."]; + expected.assert_eq(&err.to_string()); + + Ok(()) +} + +#[tokio::test] +async fn module_not_found_locally() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + let mut stable_addrs = HashMap::new(); + + let b_ref_fixtures = tempfile::tempdir()?; + let b_ref = { + let b_src = copy_published_package(&b_ref_fixtures, "b", IotaAddress::ZERO).await?; + publish_package(context, b_src).await.0 + }; + + let a_pkg_fixtures = tempfile::tempdir()?; + let a_pkg = { + let b_id = b_ref.0.into(); + stable_addrs.insert(b_id, "b_id"); + let b_src = copy_published_package(&a_pkg_fixtures, "b", b_id).await?; + let a_src = copy_published_package(&a_pkg_fixtures, "a", IotaAddress::ZERO).await?; + tokio::fs::remove_file(b_src.join("sources").join("d.move")).await?; + compile_package(a_src) + }; + + let client = context.get_client().await?; + let verifier = BytecodeSourceVerifier::new(client.read_api()); + + let Err(err) = verifier.verify_package_deps(&a_pkg).await else { + panic!("Expected verification to fail"); + }; + + let expected = expect!["Local version of dependency b_id::d was not found."]; + expected.assert_eq(&sanitize_id(err.to_string(), &stable_addrs)); + + Ok(()) +} + +#[tokio::test] +async fn module_bytecode_mismatch() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + let mut stable_addrs = HashMap::new(); + + let b_ref_fixtures = tempfile::tempdir()?; + let b_ref = { + let b_src = copy_published_package(&b_ref_fixtures, "b", IotaAddress::ZERO).await?; + + // Modify a module before publishing + let c_path = b_src.join("sources").join("c.move"); + let c_file = tokio::fs::read_to_string(&c_path) + .await? + .replace("43", "44"); + tokio::fs::write(&c_path, c_file).await?; + + publish_package(context, b_src).await.0 + }; + + let a_fixtures = tempfile::tempdir()?; + let (a_pkg, a_ref) = { + let b_id = b_ref.0.into(); + stable_addrs.insert(b_id, ""); + copy_published_package(&a_fixtures, "b", b_id).await?; + let a_src = copy_published_package(&a_fixtures, "a", IotaAddress::ZERO).await?; + + let compiled = compile_package(a_src.clone()); + // Modify a module before publishing + let c_path = a_src.join("sources").join("a.move"); + let c_file = tokio::fs::read_to_string(&c_path) + .await? + .replace("123", "1234"); + tokio::fs::write(&c_path, c_file).await?; + + (compiled, publish_package(context, a_src).await.0) + }; + let a_addr: IotaAddress = a_ref.0.into(); + stable_addrs.insert(a_addr, ""); + + let client = context.get_client().await?; + let verifier = BytecodeSourceVerifier::new(client.read_api()); + + let Err(err) = verifier.verify_package_deps(&a_pkg).await else { + panic!("Expected verification to fail"); + }; + + let expected = expect!["Local dependency did not match its on-chain version at ::b::c"]; + expected.assert_eq(&sanitize_id(err.to_string(), &stable_addrs)); + + let Err(err) = verifier.verify_package_root(&a_pkg, a_addr.into()).await else { + panic!("Expected verification to fail"); + }; + + let expected = expect!["Local dependency did not match its on-chain version at ::a::a"]; + expected.assert_eq(&sanitize_id(err.to_string(), &stable_addrs)); + + Ok(()) +} + +#[tokio::test] +async fn multiple_failures() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + let mut stable_addrs = HashMap::new(); + + // Publish package `b::b` on-chain without c.move. + let b_ref_fixtures = tempfile::tempdir()?; + let b_ref = { + let b_src = copy_published_package(&b_ref_fixtures, "b", IotaAddress::ZERO).await?; + tokio::fs::remove_file(b_src.join("sources").join("c.move")).await?; + publish_package(context, b_src).await.0 + }; + + // Publish package `c::c` on-chain, unmodified. + let c_ref_fixtures = tempfile::tempdir()?; + let c_ref = { + let c_src = copy_published_package(&c_ref_fixtures, "c", IotaAddress::ZERO).await?; + publish_package(context, c_src).await.0 + }; + + // Compile local package `d` that references: + // - `b::b` (c.move exists locally but not on chain => error) + // - `c::c` (d.move exists on-chain but we delete it locally before compiling => + // error) + let d_pkg_fixtures = tempfile::tempdir()?; + let d_pkg = { + let b_id = b_ref.0.into(); + let c_id = c_ref.0.into(); + stable_addrs.insert(b_id, ""); + stable_addrs.insert(c_id, ""); + copy_published_package(&d_pkg_fixtures, "b", b_id).await?; + let c_src = copy_published_package(&d_pkg_fixtures, "c", c_id).await?; + let d_src = copy_published_package(&d_pkg_fixtures, "d", IotaAddress::ZERO).await?; + tokio::fs::remove_file(c_src.join("sources").join("d.move")).await?; // delete local module in `c` + compile_package(d_src) + }; + + let client = context.get_client().await?; + let verifier = BytecodeSourceVerifier::new(client.read_api()); + + let Err(err) = verifier.verify_package_deps(&d_pkg).await else { + panic!("Expected verification to fail"); + }; + + let expected = expect![[r#" + Multiple source verification errors found: + + - On-chain version of dependency b::c was not found. + - Local version of dependency ::d was not found."#]]; + expected.assert_eq(&sanitize_id(err.to_string(), &stable_addrs)); + + Ok(()) +} + +#[tokio::test] +async fn successful_versioned_dependency_verification() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + + let b_ref_fixtures = tempfile::tempdir()?; + let b_ref = { + let b_src = + copy_published_package(&b_ref_fixtures, "versioned-b", IotaAddress::ZERO).await?; + publish_package(context, b_src).await.0 + }; + + let a_fixtures = tempfile::tempdir()?; + let a_pkg = { + copy_published_package(&a_fixtures, "versioned-b", b_ref.0.into()).await?; + let a_src = + copy_published_package(&a_fixtures, "versioned-a-depends-on-b", IotaAddress::ZERO) + .await?; + compile_package(a_src.clone()) + }; + + let client = context.get_client().await?; + let verifier = BytecodeSourceVerifier::new(client.read_api()); + + // Verify versioned dependency + verifier.verify_package_deps(&a_pkg).await.unwrap(); + + Ok(()) +} + +/// Compile the package at absolute path `package`. +fn compile_package(package: impl AsRef) -> CompiledPackage { + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); + BuildConfig::new_for_testing() + .build(package.as_ref().to_path_buf()) + .unwrap() +} + +fn sanitize_id(mut message: String, m: &HashMap) -> String { + for (addr, label) in m { + message = message.replace(format!("{addr}").strip_prefix("0x").unwrap(), label); + } + message +} + +/// Compile and publish package at absolute path `package` to chain. +async fn publish_package(context: &WalletContext, package: PathBuf) -> (ObjectRef, ObjectRef) { + let txn = make_publish_transaction(context, package).await; + let response = context.execute_transaction_must_succeed(txn).await; + let package = get_new_package_obj_from_response(&response).unwrap(); + let cap = get_new_package_upgrade_cap_from_response(&response).unwrap(); + (package, cap) +} + +async fn upgrade_package( + context: &WalletContext, + package_id: ObjectID, + upgrade_cap: ObjectID, + package: impl AsRef, +) -> ObjectRef { + let package = compile_package(package); + let with_unpublished_deps = false; + let package_bytes = package.get_package_bytes(with_unpublished_deps); + let package_digest = package.get_package_digest(with_unpublished_deps).to_vec(); + let package_deps = package.dependency_ids.published.into_values().collect(); + + upgrade_package_with_wallet( + context, + package_id, + upgrade_cap, + package_bytes, + package_deps, + package_digest, + ) + .await + .0 +} + +/// Compile and publish package at absolute path `package` to chain, along with +/// its unpublished dependencies. +async fn publish_package_and_deps(context: &WalletContext, package: PathBuf) -> ObjectRef { + let txn = make_publish_transaction_with_deps(context, package).await; + let response = context.execute_transaction_must_succeed(txn).await; + get_new_package_obj_from_response(&response).unwrap() +} + +/// Copy `package` from fixtures into `directory`, setting its named address in +/// the copied package's `Move.toml` to `address`. (A fixture's self-address is +/// assumed to match its package name). +async fn copy_published_package<'s>( + directory: impl AsRef, + package: &str, + address: IotaAddress, +) -> io::Result { + copy_upgraded_package(directory, package, address, address).await +} + +async fn copy_upgraded_package<'s>( + directory: impl AsRef, + package: &str, + storage_id: IotaAddress, + runtime_id: IotaAddress, +) -> io::Result { + let cargo_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let repo_root = { + let mut path = cargo_root.clone(); + path.pop(); // iota-source-validation + path.pop(); // crates + path + }; + + let dst = directory.as_ref().join(package); + let src = { + let mut buf = cargo_root.clone(); + buf.push("fixture"); + buf.push(package); + buf + }; + + // Create destination directory + tokio::fs::create_dir(&dst).await?; + + // Copy TOML, performing replacements + let mut toml = tokio::fs::read_to_string(src.join("Move.toml")).await?; + toml = toml.replace("$REPO_ROOT", &repo_root.to_string_lossy()); + toml = toml.replace("$STORAGE_ID", &storage_id.to_string()); + toml = toml.replace("$RUNTIME_ID", &runtime_id.to_string()); + tokio::fs::write(dst.join("Move.toml"), toml).await?; + + // Copy Move.lock file if it exists, performing replacements + let lock_file = src.join("Move.lock"); + if lock_file.exists() { + let mut toml = tokio::fs::read_to_string(lock_file).await?; + toml = toml.replace("$COMPILER_VERSION", CURRENT_COMPILER_VERSION); + tokio::fs::write(dst.join("Move.lock"), toml).await?; + } + + // Make destination source directory + tokio::fs::create_dir(dst.join("sources")).await?; + + // Copy source files + for entry in fs::read_dir(src.join("sources"))? { + let entry = entry?; + assert!(entry.file_type()?.is_file()); + + let src_abs = entry.path(); + let src_rel = src_abs.strip_prefix(&src).unwrap(); + let dst_abs = dst.join(src_rel); + tokio::fs::copy(src_abs, dst_abs).await?; + } + + Ok(dst) +} + +pub async fn upgrade_package_with_wallet( + context: &WalletContext, + package_id: ObjectID, + upgrade_cap: ObjectID, + all_module_bytes: Vec>, + dep_ids: Vec, + digest: Vec, +) -> (ObjectRef, TransactionDigest) { + let sender = context.get_addresses()[0]; + let client = context.get_client().await.unwrap(); + let gas_price = context.get_reference_gas_price().await.unwrap(); + let transaction = { + let data = client + .transaction_builder() + .upgrade( + sender, + package_id, + all_module_bytes, + dep_ids, + upgrade_cap, + UpgradePolicy::COMPATIBLE, + digest, + None, + TEST_ONLY_GAS_UNIT_FOR_PUBLISH * 2 * gas_price, + ) + .await + .unwrap(); + + context.sign_transaction(&data) + }; + + let resp = context.execute_transaction_must_succeed(transaction).await; + + ( + get_new_package_obj_from_response(&resp).unwrap(), + resp.digest, + ) +} diff --git a/crates/iota-storage/Cargo.toml b/crates/iota-storage/Cargo.toml new file mode 100644 index 00000000000..8228eecf38d --- /dev/null +++ b/crates/iota-storage/Cargo.toml @@ -0,0 +1,67 @@ +[package] +name = "iota-storage" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +integer-encoding.workspace = true +async-trait.workspace = true +futures.workspace = true +num_enum.workspace = true +serde.workspace = true +serde_json.workspace = true +tokio = { workspace = true, features = ["full", "tracing"] } +rocksdb.workspace = true +tracing.workspace = true +byteorder.workspace = true +anyhow.workspace = true +tempfile.workspace = true +tap.workspace = true +reqwest.workspace = true +percent-encoding = "2.2.0" +chrono.workspace = true +object_store.workspace = true +backoff.workspace = true +bytes.workspace = true +parking_lot.workspace = true +bcs.workspace = true +prometheus.workspace = true +itertools.workspace = true +zstd.workspace = true +url.workspace = true +fastcrypto.workspace = true +clap = "4.3.2" +hyper.workspace = true +hyper-rustls.workspace = true +base64-url.workspace = true +telemetry-subscribers.workspace = true +indicatif.workspace = true + +iota-types.workspace = true +mysten-metrics.workspace = true +move-core-types.workspace = true +iota-json-rpc-types.workspace = true +iota-protocol-config.workspace = true +iota-config.workspace = true +typed-store.workspace = true +typed-store-derive.workspace = true +eyre.workspace = true +lru.workspace = true + +move-binary-format.workspace = true +move-bytecode-utils.workspace = true + +[dev-dependencies] +anyhow.workspace = true +criterion.workspace = true +tempfile.workspace = true +num_cpus.workspace = true +pretty_assertions.workspace = true +once_cell.workspace = true +iota-test-transaction-builder.workspace = true +iota-types = { workspace = true, features = ["test-utils"] } +iota-macros = { workspace = true } +iota-simulator = { workspace = true } diff --git a/crates/sui-storage/src/bin/http_kv_tool.rs b/crates/iota-storage/src/bin/http_kv_tool.rs similarity index 95% rename from crates/sui-storage/src/bin/http_kv_tool.rs rename to crates/iota-storage/src/bin/http_kv_tool.rs index 1659cbefa2a..10f3cf35330 100644 --- a/crates/sui-storage/src/bin/http_kv_tool.rs +++ b/crates/iota-storage/src/bin/http_kv_tool.rs @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{str::FromStr, sync::Arc}; use clap::*; -use sui_storage::{ +use iota_storage::{ http_key_value_store::*, key_value_store::TransactionKeyValueStore, key_value_store_metrics::KeyValueStoreMetrics, }; -use sui_types::{ +use iota_types::{ base_types::ObjectID, digests::{ CheckpointContentsDigest, CheckpointDigest, TransactionDigest, TransactionEventsDigest, @@ -23,8 +24,8 @@ use sui_types::{ #[derive(Parser)] #[command(rename_all = "kebab-case")] struct Options { - // default value of 'https://transactions.sui.io/' - #[arg(short, long, default_value = "https://transactions.sui.io/mainnet")] + // default value of 'https://transactions.iota.io/' + #[arg(short, long, default_value = "https://transactions.iota.io/mainnet")] base_url: String, #[arg(short, long)] diff --git a/crates/iota-storage/src/blob.rs b/crates/iota-storage/src/blob.rs new file mode 100644 index 00000000000..e902e02c117 --- /dev/null +++ b/crates/iota-storage/src/blob.rs @@ -0,0 +1,115 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + io::{Read, Write}, + marker::PhantomData, +}; + +use anyhow::{anyhow, Result}; +use byteorder::ReadBytesExt; +use integer_encoding::{VarInt, VarIntReader}; +use num_enum::{IntoPrimitive, TryFromPrimitive}; +use serde::{de::DeserializeOwned, Serialize}; + +pub const MAX_VARINT_LENGTH: usize = 10; +pub const BLOB_ENCODING_BYTES: usize = 1; + +#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(u8)] +pub enum BlobEncoding { + Bcs = 1, +} + +pub struct Blob { + pub data: Vec, + pub encoding: BlobEncoding, +} + +impl Blob { + pub fn encode(value: &T, encoding: BlobEncoding) -> Result { + let value_buf = bcs::to_bytes(value)?; + let (data, encoding) = match encoding { + BlobEncoding::Bcs => (value_buf, encoding), + }; + Ok(Blob { data, encoding }) + } + pub fn decode(self) -> Result { + let data = match &self.encoding { + BlobEncoding::Bcs => self.data, + }; + let res = bcs::from_bytes(&data)?; + Ok(res) + } + pub fn read(rbuf: &mut R) -> Result { + let len = rbuf.read_varint::()? as usize; + if len == 0 { + return Err(anyhow!("Invalid object length of 0 in file")); + } + let encoding = rbuf.read_u8()?; + let mut data = vec![0u8; len]; + rbuf.read_exact(&mut data)?; + let blob = Blob { + data, + encoding: BlobEncoding::try_from(encoding)?, + }; + Ok(blob) + } + pub fn write(&self, wbuf: &mut W) -> Result { + let mut buf = [0u8; MAX_VARINT_LENGTH]; + let mut counter = 0; + let n = (self.data.len() as u64).encode_var(&mut buf); + wbuf.write_all(&buf[0..n])?; + counter += n; + buf[0] = self.encoding.into(); + wbuf.write_all(&buf[0..BLOB_ENCODING_BYTES])?; + counter += 1; + wbuf.write_all(&self.data)?; + counter += self.data.len(); + Ok(counter) + } + pub fn size(&self) -> usize { + let mut blob_size = self.data.len().required_space(); + blob_size += BLOB_ENCODING_BYTES; + blob_size += self.data.len(); + blob_size + } + pub fn to_bytes(&self) -> Vec { + [vec![self.encoding.into()], self.data.clone()].concat() + } + pub fn from_bytes(bytes: &[u8]) -> Result { + let (encoding, data) = bytes.split_first().ok_or(anyhow!("empty bytes"))?; + Blob { + data: data.to_vec(), + encoding: BlobEncoding::try_from(*encoding)?, + } + .decode() + } +} + +/// An iterator over blobs in a blob file. +pub struct BlobIter { + reader: Box, + _phantom: PhantomData, +} + +impl BlobIter { + pub fn new(reader: Box) -> Self { + Self { + reader, + _phantom: PhantomData, + } + } + fn next_blob(&mut self) -> Result { + let blob = Blob::read(&mut self.reader)?; + blob.decode() + } +} + +impl Iterator for BlobIter { + type Item = T; + fn next(&mut self) -> Option { + self.next_blob().ok() + } +} diff --git a/crates/sui-storage/src/http_key_value_store.rs b/crates/iota-storage/src/http_key_value_store.rs similarity index 91% rename from crates/sui-storage/src/http_key_value_store.rs rename to crates/iota-storage/src/http_key_value_store.rs index d973ba66908..b0c15c08151 100644 --- a/crates/sui-storage/src/http_key_value_store.rs +++ b/crates/iota-storage/src/http_key_value_store.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{str::FromStr, sync::Arc}; @@ -12,14 +13,13 @@ use hyper::{ Client, Uri, }; use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder}; -use serde::{Deserialize, Serialize}; -use sui_types::{ +use iota_types::{ base_types::{ObjectID, SequenceNumber, VersionNumber}, digests::{ CheckpointContentsDigest, CheckpointDigest, TransactionDigest, TransactionEventsDigest, }, effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, messages_checkpoint::{ CertifiedCheckpointSummary, CheckpointContents, CheckpointSequenceNumber, }, @@ -27,6 +27,7 @@ use sui_types::{ storage::ObjectKey, transaction::Transaction, }; +use serde::{Deserialize, Serialize}; use tap::TapFallible; use tracing::{error, info, instrument, trace, warn}; use url::Url; @@ -62,16 +63,16 @@ pub fn encode_object_key(object_id: &ObjectID, version: &VersionNumber) -> Strin base64_url::encode(&bytes) } -trait IntoSuiResult { - fn into_sui_result(self) -> SuiResult; +trait IntoIotaResult { + fn into_iota_result(self) -> IotaResult; } -impl IntoSuiResult for Result +impl IntoIotaResult for Result where E: std::error::Error, { - fn into_sui_result(self) -> SuiResult { - self.map_err(|e| SuiError::Storage(e.to_string())) + fn into_iota_result(self) -> IotaResult { + self.map_err(|e| IotaError::Storage(e.to_string())) } } @@ -98,7 +99,7 @@ enum Value { TxToCheckpoint(CheckpointSequenceNumber), } -fn key_to_path_elements(key: &Key) -> SuiResult<(String, &'static str)> { +fn key_to_path_elements(key: &Key) -> IotaResult<(String, &'static str)> { match key { Key::Tx(digest) => Ok((encode_digest(digest), "tx")), Key::Fx(digest) => Ok((encode_digest(digest), "fx")), @@ -122,12 +123,12 @@ impl HttpKVStore { pub fn new_kv( base_url: &str, metrics: Arc, - ) -> SuiResult { + ) -> IotaResult { let inner = Arc::new(Self::new(base_url)?); Ok(TransactionKeyValueStore::new("http", metrics, inner)) } - pub fn new(base_url: &str) -> SuiResult { + pub fn new(base_url: &str) -> IotaResult { info!("creating HttpKVStore with base_url: {}", base_url); let http = HttpsConnectorBuilder::new() .with_webpki_roots() @@ -145,7 +146,7 @@ impl HttpKVStore { format!("{}/", base_url) }; - let base_url = Url::parse(&base_url).into_sui_result()?; + let base_url = Url::parse(&base_url).into_iota_result()?; Ok(Self { base_url, @@ -153,16 +154,16 @@ impl HttpKVStore { }) } - fn get_url(&self, key: &Key) -> SuiResult { + fn get_url(&self, key: &Key) -> IotaResult { let (digest, item_type) = key_to_path_elements(key)?; let joined = self .base_url .join(&format!("{}/{}", digest, item_type)) - .into_sui_result()?; - Uri::from_str(joined.as_str()).into_sui_result() + .into_iota_result()?; + Uri::from_str(joined.as_str()).into_iota_result() } - async fn multi_fetch(&self, uris: Vec) -> Vec>> { + async fn multi_fetch(&self, uris: Vec) -> Vec>> { let uris_vec = uris.to_vec(); let fetches = stream::iter( uris_vec @@ -173,10 +174,10 @@ impl HttpKVStore { fetches.buffered(uris.len()).collect::>().await } - async fn fetch(&self, key: Key) -> SuiResult> { + async fn fetch(&self, key: Key) -> IotaResult> { let uri = self.get_url(&key)?; trace!("fetching uri: {}", uri); - let resp = self.client.get(uri.clone()).await.into_sui_result()?; + let resp = self.client.get(uri.clone()).await.into_iota_result()?; trace!( "got response {} for uri: {}, len: {:?}", uri, @@ -190,7 +191,7 @@ impl HttpKVStore { hyper::body::to_bytes(resp.into_body()) .await .map(Some) - .into_sui_result() + .into_iota_result() } else { Ok(None) } @@ -207,7 +208,7 @@ where .ok() } -fn map_fetch<'a, K>(fetch: (&'a SuiResult>, &'a K)) -> Option<(&'a Bytes, &'a K)> +fn map_fetch<'a, K>(fetch: (&'a IotaResult>, &'a K)) -> Option<(&'a Bytes, &'a K)> where K: std::fmt::Debug, { @@ -266,7 +267,7 @@ impl TransactionKeyValueStoreTrait for HttpKVStore { transactions: &[TransactionDigest], effects: &[TransactionDigest], events: &[TransactionEventsDigest], - ) -> SuiResult<( + ) -> IotaResult<( Vec>, Vec>, Vec>, @@ -335,7 +336,7 @@ impl TransactionKeyValueStoreTrait for HttpKVStore { checkpoint_contents: &[CheckpointSequenceNumber], checkpoint_summaries_by_digest: &[CheckpointDigest], checkpoint_contents_by_digest: &[CheckpointContentsDigest], - ) -> SuiResult<( + ) -> IotaResult<( Vec>, Vec>, Vec>, @@ -430,7 +431,7 @@ impl TransactionKeyValueStoreTrait for HttpKVStore { async fn deprecated_get_transaction_checkpoint( &self, digest: TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { let key = Key::TxToCheckpoint(digest); self.fetch(key).await.map(|maybe| { maybe.and_then(|bytes| deser::<_, CheckpointSequenceNumber>(&key, bytes.as_ref())) @@ -442,7 +443,7 @@ impl TransactionKeyValueStoreTrait for HttpKVStore { &self, object_id: ObjectID, version: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { let key = Key::ObjectKey(object_id, version); self.fetch(key) .await @@ -453,7 +454,7 @@ impl TransactionKeyValueStoreTrait for HttpKVStore { async fn multi_get_transaction_checkpoint( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { let keys = digests .iter() .map(|digest| Key::TxToCheckpoint(*digest)) diff --git a/crates/sui-storage/src/indexes.rs b/crates/iota-storage/src/indexes.rs similarity index 90% rename from crates/sui-storage/src/indexes.rs rename to crates/iota-storage/src/indexes.rs index d99b5d9566a..cf35f38ac29 100644 --- a/crates/sui-storage/src/indexes.rs +++ b/crates/iota-storage/src/indexes.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! IndexStore supports creation of various ancillary indexes of state in -//! SuiDataStore. The main user of this data is the explorer. +//! IotaDataStore. The main user of this data is the explorer. use std::{ cmp::{max, min}, @@ -14,28 +15,28 @@ use std::{ }, }; -use itertools::Itertools; -use move_core_types::{ - identifier::Identifier, - language_storage::{ModuleId, StructTag, TypeTag}, -}; -use prometheus::{register_int_counter_with_registry, IntCounter, Registry}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use sui_json_rpc_types::{SuiObjectDataFilter, TransactionFilter}; -use sui_types::{ +use iota_json_rpc_types::{IotaObjectDataFilter, TransactionFilter}; +use iota_types::{ base_types::{ - ObjectDigest, ObjectID, ObjectInfo, ObjectRef, SequenceNumber, SuiAddress, + IotaAddress, ObjectDigest, ObjectID, ObjectInfo, ObjectRef, SequenceNumber, TransactionDigest, TxSequenceNumber, }, digests::TransactionEventsDigest, dynamic_field::{self, DynamicFieldInfo}, effects::TransactionEvents, - error::{SuiError, SuiResult, UserInputError}, + error::{IotaError, IotaResult, UserInputError}, execution::DynamicallyLoadedObjectMetadata, inner_temporary_store::TxCoins, object::{Object, Owner}, - parse_sui_struct_tag, + parse_iota_struct_tag, +}; +use itertools::Itertools; +use move_core_types::{ + identifier::Identifier, + language_storage::{ModuleId, StructTag, TypeTag}, }; +use prometheus::{register_int_counter_with_registry, IntCounter, Registry}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use tokio::{sync::OwnedMutexGuard, task::spawn_blocking}; use tracing::{debug, trace}; use typed_store::{ @@ -47,8 +48,8 @@ use typed_store_derive::DBMapUtils; use crate::{mutex_table::MutexTable, sharded_lru::ShardedLruCache}; -type OwnerIndexKey = (SuiAddress, ObjectID); -type CoinIndexKey = (SuiAddress, String, ObjectID); +type OwnerIndexKey = (IotaAddress, ObjectID); +type CoinIndexKey = (IotaAddress, String, ObjectID); type DynamicFieldKey = (ObjectID, ObjectID); type EventId = (TxSequenceNumber, usize); type EventIndex = (TransactionEventsDigest, TransactionDigest, u64); @@ -133,27 +134,27 @@ impl IndexStoreMetrics { } pub struct IndexStoreCaches { - per_coin_type_balance: ShardedLruCache<(SuiAddress, TypeTag), SuiResult>, - all_balances: ShardedLruCache>>>, - locks: MutexTable, + per_coin_type_balance: ShardedLruCache<(IotaAddress, TypeTag), IotaResult>, + all_balances: ShardedLruCache>>>, + locks: MutexTable, } #[derive(Default)] pub struct IndexStoreCacheUpdates { _locks: Vec>, - per_coin_type_balance_changes: Vec<((SuiAddress, TypeTag), SuiResult)>, - all_balance_changes: Vec<(SuiAddress, SuiResult>)>, + per_coin_type_balance_changes: Vec<((IotaAddress, TypeTag), IotaResult)>, + all_balance_changes: Vec<(IotaAddress, IotaResult>)>, } #[derive(DBMapUtils)] pub struct IndexStoreTables { - /// Index from sui address to transactions initiated by that address. + /// Index from iota address to transactions initiated by that address. #[default_options_override_fn = "transactions_from_addr_table_default_config"] - transactions_from_addr: DBMap<(SuiAddress, TxSequenceNumber), TransactionDigest>, + transactions_from_addr: DBMap<(IotaAddress, TxSequenceNumber), TransactionDigest>, - /// Index from sui address to transactions that were sent to that address. + /// Index from iota address to transactions that were sent to that address. #[default_options_override_fn = "transactions_to_addr_table_default_config"] - transactions_to_addr: DBMap<(SuiAddress, TxSequenceNumber), TransactionDigest>, + transactions_to_addr: DBMap<(IotaAddress, TxSequenceNumber), TransactionDigest>, /// Index from object id to transactions that used that object id as input. #[default_options_override_fn = "transactions_by_input_object_id_table_default_config"] @@ -190,7 +191,7 @@ pub struct IndexStoreTables { transactions_seq: DBMap, /// This is an index of object references to currently existing objects, - /// indexed by the composite key of the SuiAddress of their owner and + /// indexed by the composite key of the IotaAddress of their owner and /// the object ID of the object. This composite index allows an /// efficient iterator to list all objected currently owned /// by a specific user, and their object reference. @@ -220,7 +221,7 @@ pub struct IndexStoreTables { #[default_options_override_fn = "index_table_default_config"] event_by_event_module: DBMap<(ModuleId, EventId), EventIndex>, #[default_options_override_fn = "index_table_default_config"] - event_by_sender: DBMap<(SuiAddress, EventId), EventIndex>, + event_by_sender: DBMap<(IotaAddress, EventId), EventIndex>, #[default_options_override_fn = "index_table_default_config"] event_by_time: DBMap<(u64, EventId), EventIndex>, } @@ -323,7 +324,7 @@ impl IndexStore { batch: &mut DBBatch, object_index_changes: &ObjectIndexChanges, tx_coins: Option, - ) -> SuiResult { + ) -> IotaResult { // In production if this code path is hit, we should expect `tx_coins` to not be // None. However, in many tests today we do not distinguish validator // and/or fullnode, so we gracefully exist here. @@ -331,7 +332,7 @@ impl IndexStore { return Ok(IndexStoreCacheUpdates::default()); } // Acquire locks on changed coin owners - let mut addresses: HashSet = HashSet::new(); + let mut addresses: HashSet = HashSet::new(); addresses.extend( object_index_changes .deleted_owners @@ -345,7 +346,7 @@ impl IndexStore { .map(|((owner, _), _)| *owner), ); let _locks = self.caches.locks.acquire_locks(addresses.into_iter()).await; - let mut balance_changes: HashMap> = + let mut balance_changes: HashMap> = HashMap::new(); // Index coin info let (input_coins, written_coins) = tx_coins.unwrap(); @@ -439,7 +440,7 @@ impl IndexStore { balance_map.iter().map(|(type_tag, balance)| { ( (*address, type_tag.clone()), - Ok::(*balance), + Ok::(*balance), ) }) }) @@ -449,7 +450,7 @@ impl IndexStore { .map(|(address, balance_map)| { ( address, - Ok::>, SuiError>(Arc::new(balance_map)), + Ok::>, IotaError>(Arc::new(balance_map)), ) }) .collect(); @@ -463,7 +464,7 @@ impl IndexStore { pub async fn index_tx( &self, - sender: SuiAddress, + sender: IotaAddress, active_inputs: impl Iterator, mutated_objects: impl Iterator + Clone, move_functions: impl Iterator + Clone, @@ -473,7 +474,7 @@ impl IndexStore { timestamp_ms: u64, tx_coins: Option, loaded_child_objects: &BTreeMap, - ) -> SuiResult { + ) -> IotaResult { let sequence = self.next_sequence_number.fetch_add(1, Ordering::SeqCst); let mut batch = self.tables.transactions_from_addr.batch(); @@ -669,12 +670,12 @@ impl IndexStore { cursor: Option, limit: Option, reverse: bool, - ) -> SuiResult> { + ) -> IotaResult> { // Lookup TransactionDigest sequence number, let cursor = if let Some(cursor) = cursor { Some( self.get_transaction_seq(&cursor)? - .ok_or(SuiError::TransactionNotFound { digest: cursor })?, + .ok_or(IotaError::TransactionNotFound { digest: cursor })?, ) } else { None @@ -701,7 +702,7 @@ impl IndexStore { } // NOTE: filter via checkpoint sequence number is implemented in // `get_transactions` of authority.rs. - Some(_) => Err(SuiError::UserInputError { + Some(_) => Err(IotaError::UserInputError { error: UserInputError::Unsupported(format!("{:?}", filter)), }), None => { @@ -737,7 +738,7 @@ impl IndexStore { pub fn loaded_child_object_versions( &self, transaction_digest: &TransactionDigest, - ) -> SuiResult>> { + ) -> IotaResult>> { self.tables .loaded_child_object_versions .get(transaction_digest) @@ -750,7 +751,7 @@ impl IndexStore { cursor: Option, limit: Option, reverse: bool, - ) -> SuiResult> { + ) -> IotaResult> { Ok(if reverse { let iter = index .unbounded_iter() @@ -787,7 +788,7 @@ impl IndexStore { cursor: Option, limit: Option, reverse: bool, - ) -> SuiResult> { + ) -> IotaResult> { Self::get_transactions_from_index( &self.tables.transactions_by_input_object_id, input_object, @@ -803,7 +804,7 @@ impl IndexStore { cursor: Option, limit: Option, reverse: bool, - ) -> SuiResult> { + ) -> IotaResult> { Self::get_transactions_from_index( &self.tables.transactions_by_mutated_object_id, mutated_object, @@ -815,11 +816,11 @@ impl IndexStore { pub fn get_transactions_from_addr( &self, - addr: SuiAddress, + addr: IotaAddress, cursor: Option, limit: Option, reverse: bool, - ) -> SuiResult> { + ) -> IotaResult> { Self::get_transactions_from_index( &self.tables.transactions_from_addr, addr, @@ -837,10 +838,10 @@ impl IndexStore { cursor: Option, limit: Option, reverse: bool, - ) -> SuiResult> { + ) -> IotaResult> { // If we are passed a function with no module return a UserInputError if function.is_some() && module.is_none() { - return Err(SuiError::UserInputError { + return Err(IotaError::UserInputError { error: UserInputError::MoveFunctionInputError( "Cannot supply function without supplying module".to_string(), ), @@ -849,7 +850,7 @@ impl IndexStore { // We cannot have a cursor without filling out the other keys. if cursor.is_some() && (module.is_none() || function.is_none()) { - return Err(SuiError::UserInputError { + return Err(IotaError::UserInputError { error: UserInputError::MoveFunctionInputError( "Cannot supply cursor without supplying module and function".to_string(), ), @@ -914,11 +915,11 @@ impl IndexStore { pub fn get_transactions_to_addr( &self, - addr: SuiAddress, + addr: IotaAddress, cursor: Option, limit: Option, reverse: bool, - ) -> SuiResult> { + ) -> IotaResult> { Self::get_transactions_from_index( &self.tables.transactions_to_addr, addr, @@ -931,7 +932,7 @@ impl IndexStore { pub fn get_transaction_seq( &self, digest: &TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self.tables.transactions_seq.get(digest)?) } @@ -941,7 +942,7 @@ impl IndexStore { event_seq: usize, limit: usize, descending: bool, - ) -> SuiResult> { + ) -> IotaResult> { Ok(if descending { self.tables .event_order @@ -973,10 +974,10 @@ impl IndexStore { event_seq: usize, limit: usize, descending: bool, - ) -> SuiResult> { + ) -> IotaResult> { let seq = self .get_transaction_seq(digest)? - .ok_or(SuiError::TransactionNotFound { digest: *digest })?; + .ok_or(IotaError::TransactionNotFound { digest: *digest })?; Ok(if descending { self.tables .event_order @@ -1010,7 +1011,7 @@ impl IndexStore { event_seq: usize, limit: usize, descending: bool, - ) -> SuiResult> { + ) -> IotaResult> { Ok(if descending { index .unbounded_iter() @@ -1042,7 +1043,7 @@ impl IndexStore { event_seq: usize, limit: usize, descending: bool, - ) -> SuiResult> { + ) -> IotaResult> { Self::get_event_from_index( &self.tables.event_by_move_module, module, @@ -1060,7 +1061,7 @@ impl IndexStore { event_seq: usize, limit: usize, descending: bool, - ) -> SuiResult> { + ) -> IotaResult> { Self::get_event_from_index( &self.tables.event_by_move_event, struct_name, @@ -1078,7 +1079,7 @@ impl IndexStore { event_seq: usize, limit: usize, descending: bool, - ) -> SuiResult> { + ) -> IotaResult> { Self::get_event_from_index( &self.tables.event_by_event_module, module_id, @@ -1091,12 +1092,12 @@ impl IndexStore { pub fn events_by_sender( &self, - sender: &SuiAddress, + sender: &IotaAddress, tx_seq: TxSequenceNumber, event_seq: usize, limit: usize, descending: bool, - ) -> SuiResult> { + ) -> IotaResult> { Self::get_event_from_index( &self.tables.event_by_sender, sender, @@ -1115,7 +1116,7 @@ impl IndexStore { event_seq: usize, limit: usize, descending: bool, - ) -> SuiResult> { + ) -> IotaResult> { Ok(if descending { self.tables .event_by_time @@ -1146,7 +1147,7 @@ impl IndexStore { &self, object: ObjectID, cursor: Option, - ) -> SuiResult> + '_> + ) -> IotaResult> + '_> { debug!(?object, "get_dynamic_fields"); let iter_lower_bound = (object, ObjectID::ZERO); @@ -1168,12 +1169,12 @@ impl IndexStore { object: ObjectID, name_type: TypeTag, name_bcs_bytes: &[u8], - ) -> SuiResult> { + ) -> IotaResult> { debug!(?object, "get_dynamic_field_object_id"); let dynamic_field_id = dynamic_field::derive_dynamic_field_id(object, &name_type, name_bcs_bytes).map_err( |e| { - SuiError::Unknown(format!( + IotaError::Unknown(format!( "Unable to generate dynamic field id. Got error: {e:?}" )) }, @@ -1200,7 +1201,7 @@ impl IndexStore { name_bcs_bytes, ) .map_err(|e| { - SuiError::Unknown(format!( + IotaError::Unknown(format!( "Unable to generate dynamic field id. Got error: {e:?}" )) })?; @@ -1217,11 +1218,11 @@ impl IndexStore { pub fn get_owner_objects( &self, - owner: SuiAddress, + owner: IotaAddress, cursor: Option, limit: usize, - filter: Option, - ) -> SuiResult> { + filter: Option, + ) -> IotaResult> { let cursor = match cursor { Some(cursor) => cursor, None => ObjectID::ZERO, @@ -1234,9 +1235,9 @@ impl IndexStore { pub fn get_owned_coins_iterator( coin_index: &DBMap, - owner: SuiAddress, + owner: IotaAddress, coin_type_tag: Option, - ) -> SuiResult + '_> { + ) -> IotaResult + '_> { let all_coins = coin_type_tag.is_none(); let starting_coin_type = coin_type_tag.unwrap_or_else(|| String::from_utf8([0u8].to_vec()).unwrap()); @@ -1257,11 +1258,11 @@ impl IndexStore { pub fn get_owned_coins_iterator_with_cursor( &self, - owner: SuiAddress, + owner: IotaAddress, cursor: (String, ObjectID), limit: usize, one_coin_type_only: bool, - ) -> SuiResult + '_> { + ) -> IotaResult + '_> { let (starting_coin_type, starting_object_id) = cursor; Ok(self .tables @@ -1290,10 +1291,10 @@ impl IndexStore { /// next page. pub fn get_owner_objects_iterator( &self, - owner: SuiAddress, + owner: IotaAddress, starting_object_id: ObjectID, - filter: Option, - ) -> SuiResult + '_> { + filter: Option, + ) -> IotaResult + '_> { Ok(self .tables .owner_index @@ -1312,7 +1313,7 @@ impl IndexStore { .map(|(_, object_info)| object_info)) } - pub fn insert_genesis_objects(&self, object_index_changes: ObjectIndexChanges) -> SuiResult { + pub fn insert_genesis_objects(&self, object_index_changes: ObjectIndexChanges) -> IotaResult { let mut batch = self.tables.owner_index.batch(); batch.insert_batch( &self.tables.owner_index, @@ -1330,7 +1331,7 @@ impl IndexStore { self.tables.owner_index.is_empty() } - pub fn checkpoint_db(&self, path: &Path) -> SuiResult { + pub fn checkpoint_db(&self, path: &Path) -> IotaResult { // We are checkpointing the whole db self.tables .transactions_from_addr @@ -1345,9 +1346,9 @@ impl IndexStore { /// done with `spawn_blocking` as that is expected to block pub async fn get_balance( &self, - owner: SuiAddress, + owner: IotaAddress, coin_type: TypeTag, - ) -> SuiResult { + ) -> IotaResult { let force_disable_cache = read_size_from_env(ENV_VAR_DISABLE_INDEX_CACHE).unwrap_or(0) > 0; let cloned_coin_type = coin_type.clone(); let metrics_cloned = self.metrics.clone(); @@ -1364,7 +1365,7 @@ impl IndexStore { .await .unwrap() .map_err(|e| { - SuiError::ExecutionError(format!("Failed to read balance frm DB: {:?}", e)) + IotaError::ExecutionError(format!("Failed to read balance frm DB: {:?}", e)) }); } @@ -1402,7 +1403,7 @@ impl IndexStore { .await .unwrap() .map_err(|e| { - SuiError::ExecutionError(format!("Failed to read balance frm DB: {:?}", e)) + IotaError::ExecutionError(format!("Failed to read balance frm DB: {:?}", e)) }) }) .await @@ -1416,8 +1417,8 @@ impl IndexStore { /// `spawn_blocking` as that is expected to block pub async fn get_all_balance( &self, - owner: SuiAddress, - ) -> SuiResult>> { + owner: IotaAddress, + ) -> IotaResult>> { let force_disable_cache = read_size_from_env(ENV_VAR_DISABLE_INDEX_CACHE).unwrap_or(0) > 0; let metrics_cloned = self.metrics.clone(); let coin_index_cloned = self.tables.coin_index.clone(); @@ -1428,7 +1429,7 @@ impl IndexStore { .await .unwrap() .map_err(|e| { - SuiError::ExecutionError(format!("Failed to read all balance from DB: {:?}", e)) + IotaError::ExecutionError(format!("Failed to read all balance from DB: {:?}", e)) }); } @@ -1444,19 +1445,23 @@ impl IndexStore { .await .unwrap() .map_err(|e| { - SuiError::ExecutionError(format!("Failed to read all balance from DB: {:?}", e)) + IotaError::ExecutionError(format!( + "Failed to read all balance from DB: {:?}", + e + )) }) }) .await } - /// Read balance for a `SuiAddress` and `CoinType` from the backend database + /// Read balance for a `IotaAddress` and `CoinType` from the backend + /// database pub fn get_balance_from_db( metrics: Arc, coin_index: DBMap, - owner: SuiAddress, + owner: IotaAddress, coin_type: TypeTag, - ) -> SuiResult { + ) -> IotaResult { metrics.balance_lookup_from_db.inc(); let coin_type_str = coin_type.to_string(); let coins = @@ -1472,12 +1477,12 @@ impl IndexStore { Ok(TotalBalance { balance, num_coins }) } - /// Read all balances for a `SuiAddress` from the backend database + /// Read all balances for a `IotaAddress` from the backend database pub fn get_all_balances_from_db( metrics: Arc, coin_index: DBMap, - owner: SuiAddress, - ) -> SuiResult>> { + owner: IotaAddress, + ) -> IotaResult>> { metrics.all_balance_lookup_from_db.inc(); let mut balances: HashMap = HashMap::new(); let coins = Self::get_owned_coins_iterator(&coin_index, owner, None)? @@ -1489,13 +1494,14 @@ impl IndexStore { total_balance += coin_info.balance as i128; coin_object_count += 1; } - let coin_type = - TypeTag::Struct(Box::new(parse_sui_struct_tag(&coin_type).map_err(|e| { - SuiError::ExecutionError(format!( + let coin_type = TypeTag::Struct(Box::new(parse_iota_struct_tag(&coin_type).map_err( + |e| { + IotaError::ExecutionError(format!( "Failed to parse event sender address: {:?}", e )) - })?)); + }, + )?)); balances.insert( coin_type, TotalBalance { @@ -1509,8 +1515,8 @@ impl IndexStore { async fn invalidate_per_coin_type_cache( &self, - keys: impl IntoIterator, - ) -> SuiResult { + keys: impl IntoIterator, + ) -> IotaResult { self.caches .per_coin_type_balance .batch_invalidate(keys) @@ -1520,16 +1526,16 @@ impl IndexStore { async fn invalidate_all_balance_cache( &self, - addresses: impl IntoIterator, - ) -> SuiResult { + addresses: impl IntoIterator, + ) -> IotaResult { self.caches.all_balances.batch_invalidate(addresses).await; Ok(()) } async fn update_per_coin_type_cache( &self, - keys: impl IntoIterator)>, - ) -> SuiResult { + keys: impl IntoIterator)>, + ) -> IotaResult { self.caches .per_coin_type_balance .batch_merge(keys, Self::merge_balance) @@ -1538,9 +1544,9 @@ impl IndexStore { } fn merge_balance( - old_balance: &SuiResult, - balance_delta: &SuiResult, - ) -> SuiResult { + old_balance: &IotaResult, + balance_delta: &IotaResult, + ) -> IotaResult { if let Ok(old_balance) = old_balance { if let Ok(balance_delta) = balance_delta { Ok(TotalBalance { @@ -1557,8 +1563,8 @@ impl IndexStore { async fn update_all_balance_cache( &self, - keys: impl IntoIterator>>)>, - ) -> SuiResult { + keys: impl IntoIterator>>)>, + ) -> IotaResult { self.caches .all_balances .batch_merge(keys, Self::merge_all_balance) @@ -1567,9 +1573,9 @@ impl IndexStore { } fn merge_all_balance( - old_balance: &SuiResult>>, - balance_delta: &SuiResult>>, - ) -> SuiResult>> { + old_balance: &IotaResult>>, + balance_delta: &IotaResult>>, + ) -> IotaResult>> { if let Ok(old_balance) = old_balance { if let Ok(balance_delta) = balance_delta { let mut new_balance = HashMap::new(); @@ -1601,16 +1607,16 @@ impl IndexStore { mod tests { use std::{collections::BTreeMap, env::temp_dir}; - use move_core_types::account_address::AccountAddress; - use prometheus::Registry; - use sui_types::{ - base_types::{ObjectInfo, ObjectType, SuiAddress}, + use iota_types::{ + base_types::{IotaAddress, ObjectInfo, ObjectType}, digests::TransactionDigest, effects::TransactionEvents, gas_coin::GAS, object, object::Owner, }; + use move_core_types::account_address::AccountAddress; + use prometheus::Registry; use crate::{indexes::ObjectIndexChanges, IndexStore}; @@ -1624,7 +1630,7 @@ mod tests { // both db and cache. This tests make sure we are invalidating entries // in the cache and always reading latest balance. let index_store = IndexStore::new(temp_dir(), &Registry::default(), Some(128)); - let address: SuiAddress = AccountAddress::random().into(); + let address: IotaAddress = AccountAddress::random().into(); let mut written_objects = BTreeMap::new(); let mut object_map = BTreeMap::new(); diff --git a/crates/sui-storage/src/key_value_store.rs b/crates/iota-storage/src/key_value_store.rs similarity index 91% rename from crates/sui-storage/src/key_value_store.rs rename to crates/iota-storage/src/key_value_store.rs index 84bcea234c4..243af36ac50 100644 --- a/crates/sui-storage/src/key_value_store.rs +++ b/crates/iota-storage/src/key_value_store.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! Immutable key/value store trait for storing/retrieving transactions, @@ -7,13 +8,13 @@ use std::{sync::Arc, time::Instant}; use async_trait::async_trait; -use sui_types::{ +use iota_types::{ base_types::{ObjectID, SequenceNumber, VersionNumber}, digests::{ CheckpointContentsDigest, CheckpointDigest, TransactionDigest, TransactionEventsDigest, }, effects::{TransactionEffects, TransactionEvents}, - error::{SuiError, SuiResult, UserInputError}, + error::{IotaError, IotaResult, UserInputError}, messages_checkpoint::{ CertifiedCheckpointSummary, CheckpointContents, CheckpointSequenceNumber, }, @@ -63,7 +64,7 @@ impl TransactionKeyValueStore { transactions: &[TransactionDigest], effects: &[TransactionDigest], events: &[TransactionEventsDigest], - ) -> SuiResult<( + ) -> IotaResult<( Vec>, Vec>, Vec>, @@ -152,7 +153,7 @@ impl TransactionKeyValueStore { checkpoint_contents: &[CheckpointSequenceNumber], checkpoint_summaries_by_digest: &[CheckpointDigest], checkpoint_contents_by_digest: &[CheckpointContentsDigest], - ) -> SuiResult<( + ) -> IotaResult<( Vec>, Vec>, Vec>, @@ -236,7 +237,7 @@ impl TransactionKeyValueStore { pub async fn multi_get_checkpoints_summaries( &self, keys: &[CheckpointSequenceNumber], - ) -> SuiResult>> { + ) -> IotaResult>> { self.multi_get_checkpoints(keys, &[], &[], &[]) .await .map(|(summaries, _, _, _)| summaries) @@ -245,7 +246,7 @@ impl TransactionKeyValueStore { pub async fn multi_get_checkpoints_contents( &self, keys: &[CheckpointSequenceNumber], - ) -> SuiResult>> { + ) -> IotaResult>> { self.multi_get_checkpoints(&[], keys, &[], &[]) .await .map(|(_, contents, _, _)| contents) @@ -254,7 +255,7 @@ impl TransactionKeyValueStore { pub async fn multi_get_checkpoints_summaries_by_digest( &self, keys: &[CheckpointDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { self.multi_get_checkpoints(&[], &[], keys, &[]) .await .map(|(_, _, summaries, _)| summaries) @@ -263,7 +264,7 @@ impl TransactionKeyValueStore { pub async fn multi_get_checkpoints_contents_by_digest( &self, keys: &[CheckpointContentsDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { self.multi_get_checkpoints(&[], &[], &[], keys) .await .map(|(_, _, _, contents)| contents) @@ -272,7 +273,7 @@ impl TransactionKeyValueStore { pub async fn multi_get_tx( &self, keys: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { self.multi_get(keys, &[], &[]) .await .map(|(txns, _, _)| txns) @@ -281,14 +282,14 @@ impl TransactionKeyValueStore { pub async fn multi_get_fx_by_tx_digest( &self, keys: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { self.multi_get(&[], keys, &[]).await.map(|(_, fx, _)| fx) } pub async fn multi_get_events( &self, keys: &[TransactionEventsDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { self.multi_get(&[], &[], keys) .await .map(|(_, _, events)| events) @@ -296,13 +297,13 @@ impl TransactionKeyValueStore { /// Convenience method for fetching single digest, and returning an error if /// it's not found. Prefer using multi_get_tx whenever possible. - pub async fn get_tx(&self, digest: TransactionDigest) -> SuiResult { + pub async fn get_tx(&self, digest: TransactionDigest) -> IotaResult { self.multi_get_tx(&[digest]) .await? .into_iter() .next() .flatten() - .ok_or(SuiError::TransactionNotFound { digest }) + .ok_or(IotaError::TransactionNotFound { digest }) } /// Convenience method for fetching single digest, and returning an error if @@ -311,13 +312,13 @@ impl TransactionKeyValueStore { pub async fn get_fx_by_tx_digest( &self, digest: TransactionDigest, - ) -> SuiResult { + ) -> IotaResult { self.multi_get_fx_by_tx_digest(&[digest]) .await? .into_iter() .next() .flatten() - .ok_or(SuiError::TransactionNotFound { digest }) + .ok_or(IotaError::TransactionNotFound { digest }) } /// Convenience method for fetching single digest, and returning an error if @@ -325,13 +326,13 @@ impl TransactionKeyValueStore { pub async fn get_events( &self, digest: TransactionEventsDigest, - ) -> SuiResult { + ) -> IotaResult { self.multi_get_events(&[digest]) .await? .into_iter() .next() .flatten() - .ok_or(SuiError::TransactionEventsNotFound { digest }) + .ok_or(IotaError::TransactionEventsNotFound { digest }) } /// Convenience method for fetching single checkpoint, and returning an @@ -340,13 +341,13 @@ impl TransactionKeyValueStore { pub async fn get_checkpoint_summary( &self, checkpoint: CheckpointSequenceNumber, - ) -> SuiResult { + ) -> IotaResult { self.multi_get_checkpoints_summaries(&[checkpoint]) .await? .into_iter() .next() .flatten() - .ok_or(SuiError::UserInputError { + .ok_or(IotaError::UserInputError { error: UserInputError::VerifiedCheckpointNotFound(checkpoint), }) } @@ -357,13 +358,13 @@ impl TransactionKeyValueStore { pub async fn get_checkpoint_contents( &self, checkpoint: CheckpointSequenceNumber, - ) -> SuiResult { + ) -> IotaResult { self.multi_get_checkpoints_contents(&[checkpoint]) .await? .into_iter() .next() .flatten() - .ok_or(SuiError::UserInputError { + .ok_or(IotaError::UserInputError { error: UserInputError::VerifiedCheckpointNotFound(checkpoint), }) } @@ -374,13 +375,13 @@ impl TransactionKeyValueStore { pub async fn get_checkpoint_summary_by_digest( &self, digest: CheckpointDigest, - ) -> SuiResult { + ) -> IotaResult { self.multi_get_checkpoints_summaries_by_digest(&[digest]) .await? .into_iter() .next() .flatten() - .ok_or(SuiError::UserInputError { + .ok_or(IotaError::UserInputError { error: UserInputError::VerifiedCheckpointDigestNotFound(format!("{:?}", digest)), }) } @@ -391,13 +392,13 @@ impl TransactionKeyValueStore { pub async fn get_checkpoint_contents_by_digest( &self, digest: CheckpointContentsDigest, - ) -> SuiResult { + ) -> IotaResult { self.multi_get_checkpoints_contents_by_digest(&[digest]) .await? .into_iter() .next() .flatten() - .ok_or(SuiError::UserInputError { + .ok_or(IotaError::UserInputError { error: UserInputError::VerifiedCheckpointDigestNotFound(format!("{:?}", digest)), }) } @@ -405,7 +406,7 @@ impl TransactionKeyValueStore { pub async fn deprecated_get_transaction_checkpoint( &self, digest: TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { self.inner .deprecated_get_transaction_checkpoint(digest) .await @@ -415,14 +416,14 @@ impl TransactionKeyValueStore { &self, object_id: ObjectID, version: VersionNumber, - ) -> SuiResult> { + ) -> IotaResult> { self.inner.get_object(object_id, version).await } pub async fn multi_get_transaction_checkpoint( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { self.inner.multi_get_transaction_checkpoint(digests).await } } @@ -439,7 +440,7 @@ pub trait TransactionKeyValueStoreTrait { transactions: &[TransactionDigest], effects: &[TransactionDigest], events: &[TransactionEventsDigest], - ) -> SuiResult; + ) -> IotaResult; /// Generic multi_get to allow implementors to get heterogenous values with /// a single round trip. @@ -449,23 +450,23 @@ pub trait TransactionKeyValueStoreTrait { checkpoint_contents: &[CheckpointSequenceNumber], checkpoint_summaries_by_digest: &[CheckpointDigest], checkpoint_contents_by_digest: &[CheckpointContentsDigest], - ) -> SuiResult; + ) -> IotaResult; async fn deprecated_get_transaction_checkpoint( &self, digest: TransactionDigest, - ) -> SuiResult>; + ) -> IotaResult>; async fn get_object( &self, object_id: ObjectID, version: SequenceNumber, - ) -> SuiResult>; + ) -> IotaResult>; async fn multi_get_transaction_checkpoint( &self, digests: &[TransactionDigest], - ) -> SuiResult>>; + ) -> IotaResult>>; } /// A TransactionKeyValueStoreTrait that falls back to a secondary store for any @@ -498,7 +499,7 @@ impl TransactionKeyValueStoreTrait for FallbackTransactionKVStore { transactions: &[TransactionDigest], effects: &[TransactionDigest], events: &[TransactionEventsDigest], - ) -> SuiResult<( + ) -> IotaResult<( Vec>, Vec>, Vec>, @@ -538,7 +539,7 @@ impl TransactionKeyValueStoreTrait for FallbackTransactionKVStore { checkpoint_contents: &[CheckpointSequenceNumber], checkpoint_summaries_by_digest: &[CheckpointDigest], checkpoint_contents_by_digest: &[CheckpointContentsDigest], - ) -> SuiResult<( + ) -> IotaResult<( Vec>, Vec>, Vec>, @@ -591,7 +592,7 @@ impl TransactionKeyValueStoreTrait for FallbackTransactionKVStore { async fn deprecated_get_transaction_checkpoint( &self, digest: TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { let mut res = self .primary .deprecated_get_transaction_checkpoint(digest) @@ -610,7 +611,7 @@ impl TransactionKeyValueStoreTrait for FallbackTransactionKVStore { &self, object_id: ObjectID, version: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { let mut res = self.primary.get_object(object_id, version).await?; if res.is_none() { res = self.fallback.get_object(object_id, version).await?; @@ -622,7 +623,7 @@ impl TransactionKeyValueStoreTrait for FallbackTransactionKVStore { async fn multi_get_transaction_checkpoint( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { let mut res = self .primary .multi_get_transaction_checkpoint(digests) diff --git a/crates/sui-storage/src/key_value_store_metrics.rs b/crates/iota-storage/src/key_value_store_metrics.rs similarity index 98% rename from crates/sui-storage/src/key_value_store_metrics.rs rename to crates/iota-storage/src/key_value_store_metrics.rs index 8b08d6b86a8..dc3d53c2b08 100644 --- a/crates/sui-storage/src/key_value_store_metrics.rs +++ b/crates/iota-storage/src/key_value_store_metrics.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; diff --git a/crates/iota-storage/src/lib.rs b/crates/iota-storage/src/lib.rs new file mode 100644 index 00000000000..63736dc8615 --- /dev/null +++ b/crates/iota-storage/src/lib.rs @@ -0,0 +1,395 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +#![allow(dead_code)] + +pub mod indexes; + +use std::{ + fs, + fs::File, + io, + io::{BufReader, Read, Write}, + ops::Range, + path::{Path, PathBuf}, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, + }, +}; + +use anyhow::{anyhow, Result}; +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use bytes::{Buf, Bytes}; +use fastcrypto::hash::{HashFunction, Sha3_256}; +use futures::StreamExt; +pub use indexes::{IndexStore, IndexStoreTables}; +use iota_types::{ + committee::Committee, + messages_checkpoint::{ + CertifiedCheckpointSummary, CheckpointSequenceNumber, VerifiedCheckpoint, + }, + storage::WriteStore, +}; +use itertools::Itertools; +use num_enum::{IntoPrimitive, TryFromPrimitive}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use tracing::debug; + +use crate::blob::BlobIter; + +pub mod blob; +pub mod http_key_value_store; +pub mod key_value_store; +pub mod key_value_store_metrics; +pub mod mutex_table; +pub mod object_store; +pub mod package_object_cache; +pub mod sharded_lru; +pub mod write_path_pending_tx_log; + +pub const SHA3_BYTES: usize = 32; + +#[derive( + Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, TryFromPrimitive, IntoPrimitive, +)] +#[repr(u8)] +pub enum StorageFormat { + Blob = 0, +} + +#[derive( + Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, TryFromPrimitive, IntoPrimitive, +)] +#[repr(u8)] +pub enum FileCompression { + None = 0, + Zstd, +} + +impl FileCompression { + pub fn zstd_compress(reader: &mut R, writer: &mut W) -> io::Result<()> { + // TODO: Add zstd compression level as function argument + let mut encoder = zstd::Encoder::new(writer, 1)?; + io::copy(reader, &mut encoder)?; + encoder.finish()?; + Ok(()) + } + pub fn compress(&self, source: &std::path::Path) -> io::Result<()> { + match self { + FileCompression::Zstd => { + let mut input = File::open(source)?; + let tmp_file_name = source.with_extension("tmp"); + let mut output = File::create(&tmp_file_name)?; + Self::zstd_compress(&mut input, &mut output)?; + fs::rename(tmp_file_name, source)?; + } + FileCompression::None => {} + } + Ok(()) + } + pub fn decompress(&self, source: &PathBuf) -> Result> { + let file = File::open(source)?; + let res: Box = match self { + FileCompression::Zstd => Box::new(zstd::stream::Decoder::new(file)?), + FileCompression::None => Box::new(BufReader::new(file)), + }; + Ok(res) + } + pub fn bytes_decompress(&self, bytes: Bytes) -> Result> { + let res: Box = match self { + FileCompression::Zstd => Box::new(zstd::stream::Decoder::new(bytes.reader())?), + FileCompression::None => Box::new(BufReader::new(bytes.reader())), + }; + Ok(res) + } +} + +pub fn compute_sha3_checksum_for_bytes(bytes: Bytes) -> Result<[u8; 32]> { + let mut hasher = Sha3_256::default(); + io::copy(&mut bytes.reader(), &mut hasher)?; + Ok(hasher.finalize().digest) +} + +pub fn compute_sha3_checksum_for_file(file: &mut File) -> Result<[u8; 32]> { + let mut hasher = Sha3_256::default(); + io::copy(file, &mut hasher)?; + Ok(hasher.finalize().digest) +} + +pub fn compute_sha3_checksum(source: &std::path::Path) -> Result<[u8; 32]> { + let mut file = fs::File::open(source)?; + compute_sha3_checksum_for_file(&mut file) +} + +pub fn compress(reader: &mut R, writer: &mut W) -> Result<()> { + let magic = reader.read_u32::()?; + writer.write_u32::(magic)?; + let storage_format = reader.read_u8()?; + writer.write_u8(storage_format)?; + let file_compression = FileCompression::try_from(reader.read_u8()?)?; + writer.write_u8(file_compression.into())?; + match file_compression { + FileCompression::Zstd => { + FileCompression::zstd_compress(reader, writer)?; + } + FileCompression::None => {} + } + Ok(()) +} + +pub fn read( + expected_magic: u32, + mut reader: R, +) -> Result<(Box, StorageFormat)> { + let magic = reader.read_u32::()?; + if magic != expected_magic { + Err(anyhow!( + "Unexpected magic string in file: {:?}, expected: {:?}", + magic, + expected_magic + )) + } else { + let storage_format = StorageFormat::try_from(reader.read_u8()?)?; + let file_compression = FileCompression::try_from(reader.read_u8()?)?; + let reader: Box = match file_compression { + FileCompression::Zstd => Box::new(zstd::stream::Decoder::new(reader)?), + FileCompression::None => Box::new(BufReader::new(reader)), + }; + Ok((reader, storage_format)) + } +} + +pub fn make_iterator( + expected_magic: u32, + reader: R, +) -> Result> { + let (reader, storage_format) = read(expected_magic, reader)?; + match storage_format { + StorageFormat::Blob => Ok(BlobIter::new(reader)), + } +} + +pub fn verify_checkpoint_with_committee( + committee: Arc, + current: &VerifiedCheckpoint, + checkpoint: CertifiedCheckpointSummary, +) -> Result { + assert_eq!( + *checkpoint.sequence_number(), + current.sequence_number().checked_add(1).unwrap() + ); + + if Some(*current.digest()) != checkpoint.previous_digest { + debug!( + current_checkpoint_seq = current.sequence_number(), + current_digest =% current.digest(), + checkpoint_seq = checkpoint.sequence_number(), + checkpoint_digest =% checkpoint.digest(), + checkpoint_previous_digest =? checkpoint.previous_digest, + "checkpoint not on same chain" + ); + return Err(checkpoint); + } + + let current_epoch = current.epoch(); + if checkpoint.epoch() != current_epoch + && checkpoint.epoch() != current_epoch.checked_add(1).unwrap() + { + debug!( + checkpoint_seq = checkpoint.sequence_number(), + checkpoint_epoch = checkpoint.epoch(), + current_checkpoint_seq = current.sequence_number(), + current_epoch = current_epoch, + "cannot verify checkpoint with too high of an epoch", + ); + return Err(checkpoint); + } + + if checkpoint.epoch() == current_epoch.checked_add(1).unwrap() + && current.next_epoch_committee().is_none() + { + debug!( + checkpoint_seq = checkpoint.sequence_number(), + checkpoint_epoch = checkpoint.epoch(), + current_checkpoint_seq = current.sequence_number(), + current_epoch = current_epoch, + "next checkpoint claims to be from the next epoch but the latest verified \ + checkpoint does not indicate that it is the last checkpoint of an epoch" + ); + return Err(checkpoint); + } + + checkpoint + .verify_authority_signatures(&committee) + .map_err(|e| { + debug!("error verifying checkpoint: {e}"); + checkpoint.clone() + })?; + Ok(VerifiedCheckpoint::new_unchecked(checkpoint)) +} + +pub fn verify_checkpoint( + current: &VerifiedCheckpoint, + store: S, + checkpoint: CertifiedCheckpointSummary, +) -> Result +where + S: WriteStore, +{ + let committee = store + .get_committee(checkpoint.epoch()) + .expect("store operation should not fail") + .unwrap_or_else(|| { + panic!( + "BUG: should have committee for epoch {} before we try to verify checkpoint {}", + checkpoint.epoch(), + checkpoint.sequence_number() + ) + }); + + verify_checkpoint_with_committee(committee, current, checkpoint) +} + +pub async fn verify_checkpoint_range( + checkpoint_range: Range, + store: S, + checkpoint_counter: Arc, + max_concurrency: usize, +) where + S: WriteStore + Clone, +{ + let range_clone = checkpoint_range.clone(); + futures::stream::iter(range_clone.into_iter().tuple_windows()) + .map(|(a, b)| { + let current = store + .get_checkpoint_by_sequence_number(a) + .expect("store operation should not fail") + .unwrap_or_else(|| { + panic!( + "Checkpoint {} should exist in store after summary sync but does not", + a + ); + }); + let next = store + .get_checkpoint_by_sequence_number(b) + .expect("store operation should not fail") + .unwrap_or_else(|| { + panic!( + "Checkpoint {} should exist in store after summary sync but does not", + a + ); + }); + let committee = store + .get_committee(next.epoch()) + .expect("store operation should not fail") + .unwrap_or_else(|| { + panic!( + "BUG: should have committee for epoch {} before we try to verify checkpoint {}", + next.epoch(), + next.sequence_number() + ) + }); + tokio::spawn(async move { + verify_checkpoint_with_committee(committee, ¤t, next.clone().into()) + .expect("Checkpoint verification failed"); + }) + }) + .buffer_unordered(max_concurrency) + .for_each(|result| { + result.expect("Checkpoint verification task failed"); + checkpoint_counter.fetch_add(1, Ordering::Relaxed); + futures::future::ready(()) + }) + .await; + let last = checkpoint_range + .last() + .expect("Received empty checkpoint range"); + let final_checkpoint = store + .get_checkpoint_by_sequence_number(last) + .expect("Failed to fetch checkpoint") + .expect("Expected end of checkpoint range to exist in store"); + store + .update_highest_verified_checkpoint(&final_checkpoint) + .expect("Failed to update highest verified checkpoint"); +} + +fn hard_link(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { + fs::create_dir_all(&dst)?; + for entry in fs::read_dir(src)? { + let entry = entry?; + let ty = entry.file_type()?; + if ty.is_dir() { + hard_link(entry.path(), dst.as_ref().join(entry.file_name()))?; + } else { + fs::hard_link(entry.path(), dst.as_ref().join(entry.file_name()))?; + } + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use tempfile::TempDir; + use typed_store::{ + reopen, + rocks::{open_cf, DBMap, MetricConf, ReadWriteOptions}, + Map, + }; + + use crate::hard_link; + + #[tokio::test] + pub async fn test_db_hard_link() -> anyhow::Result<()> { + let input = TempDir::new()?; + let input_path = input.path(); + + let output = TempDir::new()?; + let output_path = output.path(); + + const FIRST_CF: &str = "First_CF"; + const SECOND_CF: &str = "Second_CF"; + + let db_a = open_cf( + input_path, + None, + MetricConf::new("test_db_hard_link_1"), + &[FIRST_CF, SECOND_CF], + ) + .unwrap(); + + let (db_map_1, db_map_2) = reopen!(&db_a, FIRST_CF;, SECOND_CF;); + + let keys_vals_cf1 = (1..100).map(|i| (i, i.to_string())); + let keys_vals_cf2 = (1..100).map(|i| (i, i.to_string())); + + assert!(db_map_1.multi_insert(keys_vals_cf1).is_ok()); + assert!(db_map_2.multi_insert(keys_vals_cf2).is_ok()); + + // set up db hard link + hard_link(input_path, output_path)?; + let db_b = open_cf( + output_path, + None, + MetricConf::new("test_db_hard_link_2"), + &[FIRST_CF, SECOND_CF], + ) + .unwrap(); + + let (db_map_1, db_map_2) = reopen!(&db_b, FIRST_CF;, SECOND_CF;); + for i in 1..100 { + assert!( + db_map_1 + .contains_key(&i) + .expect("Failed to call contains key") + ); + assert!( + db_map_2 + .contains_key(&i) + .expect("Failed to call contains key") + ); + } + + Ok(()) + } +} diff --git a/crates/sui-storage/src/mutex_table.rs b/crates/iota-storage/src/mutex_table.rs similarity index 99% rename from crates/sui-storage/src/mutex_table.rs rename to crates/iota-storage/src/mutex_table.rs index 4785fd176af..c371174ae0b 100644 --- a/crates/sui-storage/src/mutex_table.rs +++ b/crates/iota-storage/src/mutex_table.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/sui-storage/src/object_store/http/gcs.rs b/crates/iota-storage/src/object_store/http/gcs.rs similarity index 97% rename from crates/sui-storage/src/object_store/http/gcs.rs rename to crates/iota-storage/src/object_store/http/gcs.rs index ce56c6616ab..9853ecac6b0 100644 --- a/crates/sui-storage/src/object_store/http/gcs.rs +++ b/crates/iota-storage/src/object_store/http/gcs.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fmt, sync::Arc}; diff --git a/crates/sui-storage/src/object_store/http/local.rs b/crates/iota-storage/src/object_store/http/local.rs similarity index 96% rename from crates/sui-storage/src/object_store/http/local.rs rename to crates/iota-storage/src/object_store/http/local.rs index d9ddf687dbc..e77cc457f50 100644 --- a/crates/sui-storage/src/object_store/http/local.rs +++ b/crates/iota-storage/src/object_store/http/local.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fmt, fs, fs::File, io::Read, path::PathBuf}; diff --git a/crates/iota-storage/src/object_store/http/mod.rs b/crates/iota-storage/src/object_store/http/mod.rs new file mode 100644 index 00000000000..5bad654fe19 --- /dev/null +++ b/crates/iota-storage/src/object_store/http/mod.rs @@ -0,0 +1,160 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod gcs; +mod local; +mod s3; + +use std::sync::Arc; + +use anyhow::{anyhow, Context, Result}; +use chrono::{DateTime, Utc}; +use futures::{StreamExt, TryStreamExt}; +use iota_config::object_storage_config::{ObjectStoreConfig, ObjectStoreType}; +use object_store::{path::Path, Error, GetResult, GetResultPayload, ObjectMeta}; +use reqwest::{ + header::{HeaderMap, CONTENT_LENGTH, ETAG, LAST_MODIFIED}, + Client, Method, +}; + +use crate::object_store::{ + http::{gcs::GoogleCloudStorage, local::LocalStorage, s3::AmazonS3}, + ObjectStoreGetExt, +}; + +// http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html +// +// Do not URI-encode any of the unreserved characters that RFC 3986 defines: +// A-Z, a-z, 0-9, hyphen ( - ), underscore ( _ ), period ( . ), and tilde ( ~ ). +pub(crate) const STRICT_ENCODE_SET: percent_encoding::AsciiSet = percent_encoding::NON_ALPHANUMERIC + .remove(b'-') + .remove(b'.') + .remove(b'_') + .remove(b'~'); +const STRICT_PATH_ENCODE_SET: percent_encoding::AsciiSet = STRICT_ENCODE_SET.remove(b'/'); +static DEFAULT_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),); + +pub trait HttpDownloaderBuilder { + fn make_http(&self) -> Result>; +} + +impl HttpDownloaderBuilder for ObjectStoreConfig { + fn make_http(&self) -> Result> { + match self.object_store { + Some(ObjectStoreType::File) => { + Ok(LocalStorage::new(self.directory.as_ref().unwrap()).map(Arc::new)?) + } + Some(ObjectStoreType::S3) => { + let bucket_endpoint = if let Some(endpoint) = &self.aws_endpoint { + if self.aws_virtual_hosted_style_request { + endpoint.clone() + } else { + let bucket = self.bucket.as_ref().unwrap(); + format!("{endpoint}/{bucket}") + } + } else { + let bucket = self.bucket.as_ref().unwrap(); + let region = self.aws_region.as_ref().unwrap(); + if self.aws_virtual_hosted_style_request { + format!("https://{bucket}.s3.{region}.amazonaws.com") + } else { + format!("https://s3.{region}.amazonaws.com/{bucket}") + } + }; + Ok(AmazonS3::new(&bucket_endpoint).map(Arc::new)?) + } + Some(ObjectStoreType::GCS) => { + Ok(GoogleCloudStorage::new(self.bucket.as_ref().unwrap()).map(Arc::new)?) + } + _ => Err(anyhow!("At least one storage backend should be provided")), + } + } +} + +async fn get( + url: &str, + store: &'static str, + location: &Path, + client: &Client, +) -> Result { + let request = client.request(Method::GET, url); + let response = request.send().await.context("failed to get")?; + let meta = header_meta(location, response.headers()).context("Failed to get header")?; + let stream = response + .bytes_stream() + .map_err(|source| Error::Generic { + store, + source: Box::new(source), + }) + .boxed(); + Ok(GetResult { + range: 0..meta.size, + payload: GetResultPayload::Stream(stream), + meta, + }) +} + +fn header_meta(location: &Path, headers: &HeaderMap) -> Result { + let last_modified = headers + .get(LAST_MODIFIED) + .context("Missing last modified")?; + + let content_length = headers + .get(CONTENT_LENGTH) + .context("Missing content length")?; + + let last_modified = last_modified.to_str().context("bad header")?; + let last_modified = DateTime::parse_from_rfc2822(last_modified) + .context("invalid last modified")? + .with_timezone(&Utc); + + let content_length = content_length.to_str().context("bad header")?; + let content_length = content_length.parse().context("invalid content length")?; + + let e_tag = headers.get(ETAG).context("missing etag")?; + let e_tag = e_tag.to_str().context("bad header")?; + + Ok(ObjectMeta { + location: location.clone(), + last_modified, + size: content_length, + e_tag: Some(e_tag.to_string()), + }) +} + +#[cfg(test)] +mod tests { + use std::fs; + + use iota_config::object_storage_config::{ObjectStoreConfig, ObjectStoreType}; + use object_store::path::Path; + use tempfile::TempDir; + + use crate::object_store::http::HttpDownloaderBuilder; + + #[tokio::test] + pub async fn test_local_download() -> anyhow::Result<()> { + let input = TempDir::new()?; + let input_path = input.path(); + let child = input_path.join("child"); + fs::create_dir(&child)?; + let file1 = child.join("file1"); + fs::write(file1, b"Lorem ipsum")?; + let grandchild = child.join("grand_child"); + fs::create_dir(&grandchild)?; + let file2 = grandchild.join("file2"); + fs::write(file2, b"Lorem ipsum")?; + + let input_store = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(input_path.to_path_buf()), + ..Default::default() + } + .make_http()?; + + let downloaded = input_store.get_bytes(&Path::from("child/file1")).await?; + assert_eq!(downloaded.to_vec(), b"Lorem ipsum"); + Ok(()) + } +} diff --git a/crates/sui-storage/src/object_store/http/s3.rs b/crates/iota-storage/src/object_store/http/s3.rs similarity index 97% rename from crates/sui-storage/src/object_store/http/s3.rs rename to crates/iota-storage/src/object_store/http/s3.rs index 7593610b0c2..3a30a9a5eed 100644 --- a/crates/sui-storage/src/object_store/http/s3.rs +++ b/crates/iota-storage/src/object_store/http/s3.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fmt, sync::Arc}; diff --git a/crates/iota-storage/src/object_store/mod.rs b/crates/iota-storage/src/object_store/mod.rs new file mode 100644 index 00000000000..317ba0637f1 --- /dev/null +++ b/crates/iota-storage/src/object_store/mod.rs @@ -0,0 +1,138 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::Arc; + +use anyhow::{anyhow, Result}; +use async_trait::async_trait; +use bytes::Bytes; +use futures::stream::BoxStream; +use object_store::{path::Path, DynObjectStore, ObjectMeta}; + +pub mod http; +pub mod util; + +#[async_trait] +pub trait ObjectStoreGetExt: std::fmt::Display + Send + Sync + 'static { + /// Return the bytes at given path in object store + async fn get_bytes(&self, src: &Path) -> Result; +} + +macro_rules! as_ref_get_ext_impl { + ($type:ty) => { + #[async_trait] + impl ObjectStoreGetExt for $type { + async fn get_bytes(&self, src: &Path) -> Result { + self.as_ref().get_bytes(src).await + } + } + }; +} + +as_ref_get_ext_impl!(Arc); +as_ref_get_ext_impl!(Box); + +#[async_trait] +impl ObjectStoreGetExt for Arc { + async fn get_bytes(&self, src: &Path) -> Result { + self.get(src) + .await? + .bytes() + .await + .map_err(|e| anyhow!("Failed to get file: {} with error: {}", src, e.to_string())) + } +} + +#[async_trait] +pub trait ObjectStoreListExt: Send + Sync + 'static { + /// List the objects at the given path in object store + async fn list_objects( + &self, + src: Option<&Path>, + ) -> object_store::Result>>; +} + +macro_rules! as_ref_list_ext_impl { + ($type:ty) => { + #[async_trait] + impl ObjectStoreListExt for $type { + async fn list_objects( + &self, + src: Option<&Path>, + ) -> object_store::Result>> { + self.as_ref().list_objects(src).await + } + } + }; +} + +as_ref_list_ext_impl!(Arc); +as_ref_list_ext_impl!(Box); + +#[async_trait] +impl ObjectStoreListExt for Arc { + async fn list_objects( + &self, + src: Option<&Path>, + ) -> object_store::Result>> { + self.list(src).await + } +} + +#[async_trait] +pub trait ObjectStorePutExt: Send + Sync + 'static { + /// Write the bytes at the given location in object store + async fn put_bytes(&self, src: &Path, bytes: Bytes) -> Result<()>; +} + +macro_rules! as_ref_put_ext_impl { + ($type:ty) => { + #[async_trait] + impl ObjectStorePutExt for $type { + async fn put_bytes(&self, src: &Path, bytes: Bytes) -> Result<()> { + self.as_ref().put_bytes(src, bytes).await + } + } + }; +} + +as_ref_put_ext_impl!(Arc); +as_ref_put_ext_impl!(Box); + +#[async_trait] +impl ObjectStorePutExt for Arc { + async fn put_bytes(&self, src: &Path, bytes: Bytes) -> Result<()> { + self.put(src, bytes).await?; + Ok(()) + } +} + +#[async_trait] +pub trait ObjectStoreDeleteExt: Send + Sync + 'static { + /// Delete the object at the given location in object store + async fn delete_object(&self, src: &Path) -> Result<()>; +} + +macro_rules! as_ref_delete_ext_impl { + ($type:ty) => { + #[async_trait] + impl ObjectStoreDeleteExt for $type { + async fn delete_object(&self, src: &Path) -> Result<()> { + self.as_ref().delete_object(src).await + } + } + }; +} + +as_ref_delete_ext_impl!(Arc); +as_ref_delete_ext_impl!(Box); + +#[async_trait] + +impl ObjectStoreDeleteExt for Arc { + async fn delete_object(&self, src: &Path) -> Result<()> { + self.delete(src).await?; + Ok(()) + } +} diff --git a/crates/iota-storage/src/object_store/util.rs b/crates/iota-storage/src/object_store/util.rs new file mode 100644 index 00000000000..e68c8dca3d7 --- /dev/null +++ b/crates/iota-storage/src/object_store/util.rs @@ -0,0 +1,558 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::BTreeMap, num::NonZeroUsize, ops::Range, path::PathBuf, sync::Arc, time::Duration, +}; + +use anyhow::{anyhow, Context, Result}; +use backoff::future::retry; +use bytes::Bytes; +use futures::{StreamExt, TryStreamExt}; +use indicatif::ProgressBar; +use itertools::Itertools; +use object_store::{path::Path, DynObjectStore, Error, ObjectStore}; +use serde::{Deserialize, Serialize}; +use tokio::time::Instant; +use tracing::{error, warn}; +use url::Url; + +use crate::object_store::{ + ObjectStoreDeleteExt, ObjectStoreGetExt, ObjectStoreListExt, ObjectStorePutExt, +}; + +pub const MANIFEST_FILENAME: &str = "MANIFEST"; + +#[derive(Serialize, Deserialize)] + +pub struct Manifest { + pub available_epochs: Vec, +} + +impl Manifest { + pub fn new(available_epochs: Vec) -> Self { + Manifest { available_epochs } + } + + pub fn epoch_exists(&self, epoch: u64) -> bool { + self.available_epochs.contains(&epoch) + } +} + +#[derive(Debug, Clone)] +pub struct PerEpochManifest { + pub lines: Vec, +} + +impl PerEpochManifest { + pub fn new(lines: Vec) -> Self { + PerEpochManifest { lines } + } + + pub fn serialize_as_newline_delimited(&self) -> String { + self.lines.join("\n") + } + + pub fn deserialize_from_newline_delimited(s: &str) -> PerEpochManifest { + PerEpochManifest { + lines: s.lines().map(String::from).collect(), + } + } + + // Method to filter lines by a given prefix + pub fn filter_by_prefix(&self, prefix: &str) -> PerEpochManifest { + let filtered_lines = self + .lines + .iter() + .filter(|line| line.starts_with(prefix)) + .cloned() + .collect(); + + PerEpochManifest { + lines: filtered_lines, + } + } +} + +pub async fn get(store: &S, src: &Path) -> Result { + let bytes = retry(backoff::ExponentialBackoff::default(), || async { + store.get_bytes(src).await.map_err(|e| { + error!("Failed to read file from object store with error: {:?}", &e); + backoff::Error::transient(e) + }) + }) + .await?; + Ok(bytes) +} + +pub async fn exists(store: &S, src: &Path) -> bool { + store.get_bytes(src).await.is_ok() +} + +pub async fn put(store: &S, src: &Path, bytes: Bytes) -> Result<()> { + retry(backoff::ExponentialBackoff::default(), || async { + if !bytes.is_empty() { + store.put_bytes(src, bytes.clone()).await.map_err(|e| { + error!("Failed to write file to object store with error: {:?}", &e); + backoff::Error::transient(e) + }) + } else { + warn!("Not copying empty file: {:?}", src); + Ok(()) + } + }) + .await?; + Ok(()) +} + +pub async fn copy_file( + src: &Path, + dest: &Path, + src_store: &S, + dest_store: &D, +) -> Result<()> { + let bytes = get(src_store, src).await?; + if !bytes.is_empty() { + put(dest_store, dest, bytes).await + } else { + warn!("Not copying empty file: {:?}", src); + Ok(()) + } +} + +pub async fn copy_files( + src: &[Path], + dest: &[Path], + src_store: &S, + dest_store: &D, + concurrency: NonZeroUsize, + progress_bar: Option, +) -> Result> { + let mut instant = Instant::now(); + let progress_bar_clone = progress_bar.clone(); + let results = futures::stream::iter(src.iter().zip(dest.iter())) + .map(|(path_in, path_out)| async move { + let ret = copy_file(path_in, path_out, src_store, dest_store).await; + Ok((path_out.clone(), ret)) + }) + .boxed() + .buffer_unordered(concurrency.get()) + .try_for_each(|(path, ret)| { + if let Some(progress_bar_clone) = &progress_bar_clone { + progress_bar_clone.inc(1); + progress_bar_clone.set_message(format!("file: {}", path)); + instant = Instant::now(); + } + futures::future::ready(ret) + }) + .await; + Ok(results.into_iter().collect()) +} + +pub async fn copy_recursively( + dir: &Path, + src_store: &S, + dest_store: &D, + concurrency: NonZeroUsize, +) -> Result> { + let mut input_paths = vec![]; + let mut output_paths = vec![]; + let mut paths = src_store.list_objects(Some(dir)).await?; + while let Some(res) = paths.next().await { + if let Ok(object_metadata) = res { + input_paths.push(object_metadata.location.clone()); + output_paths.push(object_metadata.location); + } else { + return Err(res.err().unwrap().into()); + } + } + copy_files( + &input_paths, + &output_paths, + src_store, + dest_store, + concurrency, + None, + ) + .await +} + +pub async fn delete_files( + files: &[Path], + store: &S, + concurrency: NonZeroUsize, +) -> Result> { + let results: Vec> = futures::stream::iter(files) + .map(|f| { + retry(backoff::ExponentialBackoff::default(), || async { + store.delete_object(f).await.map_err(|e| { + error!("Failed to delete file on object store with error: {:?}", &e); + backoff::Error::transient(e) + }) + }) + }) + .boxed() + .buffer_unordered(concurrency.get()) + .collect() + .await; + results.into_iter().collect() +} + +pub async fn delete_recursively( + path: &Path, + store: &S, + concurrency: NonZeroUsize, +) -> Result> { + let mut paths_to_delete = vec![]; + let mut paths = store.list_objects(Some(path)).await?; + while let Some(res) = paths.next().await { + if let Ok(object_metadata) = res { + paths_to_delete.push(object_metadata.location); + } else { + return Err(res.err().unwrap().into()); + } + } + delete_files(&paths_to_delete, store, concurrency).await +} + +pub fn path_to_filesystem(local_dir_path: PathBuf, location: &Path) -> anyhow::Result { + // Convert an `object_store::path::Path` to `std::path::PathBuf` + let path = std::fs::canonicalize(local_dir_path)?; + let mut url = Url::from_file_path(&path) + .map_err(|_| anyhow!("Failed to parse input path: {}", path.display()))?; + url.path_segments_mut() + .map_err(|_| anyhow!("Failed to get path segments: {}", path.display()))? + .pop_if_empty() + .extend(location.parts()); + let new_path = url + .to_file_path() + .map_err(|_| anyhow!("Failed to convert url to path: {}", url.as_str()))?; + Ok(new_path) +} + +/// This function will find all child directories in the input store which are +/// of the form "epoch_num" and return a map of epoch number to the directory +/// path +pub async fn find_all_dirs_with_epoch_prefix( + store: &Arc, + prefix: Option<&Path>, +) -> anyhow::Result> { + let mut dirs = BTreeMap::new(); + let entries = store.list_with_delimiter(prefix).await?; + for entry in entries.common_prefixes { + if let Some(filename) = entry.filename() { + if !filename.starts_with("epoch_") { + continue; + } + let epoch = filename + .split_once('_') + .context("Failed to split dir name") + .map(|(_, epoch)| epoch.parse::())??; + dirs.insert(epoch, entry); + } + } + Ok(dirs) +} + +pub async fn list_all_epochs(object_store: Arc) -> Result> { + let remote_epoch_dirs = find_all_dirs_with_epoch_prefix(&object_store, None).await?; + let mut out = vec![]; + let mut success_marker_found = false; + for (epoch, path) in remote_epoch_dirs.iter().sorted() { + let success_marker = path.child("_SUCCESS"); + let get_result = object_store.get(&success_marker).await; + match get_result { + Err(_) => { + if !success_marker_found { + error!("No success marker found for epoch: {epoch}"); + } + } + Ok(_) => { + out.push(*epoch); + success_marker_found = true; + } + } + } + Ok(out) +} + +pub async fn run_manifest_update_loop( + store: Arc, + mut recv: tokio::sync::broadcast::Receiver<()>, +) -> Result<()> { + let mut update_interval = tokio::time::interval(Duration::from_secs(300)); + loop { + tokio::select! { + _now = update_interval.tick() => { + if let Ok(epochs) = list_all_epochs(store.clone()).await { + let manifest_path = Path::from(MANIFEST_FILENAME); + let manifest = Manifest::new(epochs); + let bytes = serde_json::to_string(&manifest)?; + put(&store, &manifest_path, Bytes::from(bytes)).await?; + } + }, + _ = recv.recv() => break, + } + } + Ok(()) +} + +/// This function will find all child directories in the input store which are +/// of the form "epoch_num" and return a map of epoch number to the directory +/// path +pub async fn find_all_files_with_epoch_prefix( + store: &Arc, + prefix: Option<&Path>, +) -> anyhow::Result>> { + let mut ranges = Vec::new(); + let entries = store.list_with_delimiter(prefix).await?; + for entry in entries.objects { + let checkpoint_seq_range = entry + .location + .filename() + .ok_or(anyhow!("Illegal file name"))? + .split_once('.') + .context("Failed to split dir name")? + .0 + .split_once('_') + .context("Failed to split dir name") + .map(|(start, end)| Range { + start: start.parse::().unwrap(), + end: end.parse::().unwrap(), + })?; + + ranges.push(checkpoint_seq_range); + } + Ok(ranges) +} + +/// This function will find missing epoch directories in the input store and +/// return a list of such epoch numbers. If the highest epoch directory in the +/// store is `epoch_N` then it is expected that the store will have all epoch +/// directories from `epoch_0` to `epoch_N`. Additionally, any epoch directory +/// should have the passed in marker file present or else that epoch number is +/// already considered as missing +pub async fn find_missing_epochs_dirs( + store: &Arc, + success_marker: &str, +) -> anyhow::Result> { + let remote_checkpoints_by_epoch = find_all_dirs_with_epoch_prefix(store, None).await?; + let mut dirs: Vec<_> = remote_checkpoints_by_epoch.iter().collect(); + dirs.sort_by_key(|(epoch_num, _path)| *epoch_num); + let mut candidate_epoch: u64 = 0; + let mut missing_epochs = Vec::new(); + for (epoch_num, path) in dirs { + while candidate_epoch < *epoch_num { + // The whole epoch directory is missing + missing_epochs.push(candidate_epoch); + candidate_epoch += 1; + continue; + } + let success_marker = path.child(success_marker); + let get_result = store.get(&success_marker).await; + match get_result { + Err(Error::NotFound { .. }) => { + error!("No success marker found in db checkpoint for epoch: {epoch_num}"); + missing_epochs.push(*epoch_num); + } + Err(_) => { + // Probably a transient error + warn!( + "Failed while trying to read success marker in db checkpoint for epoch: {epoch_num}" + ); + } + Ok(_) => { + // Nothing to do + } + } + candidate_epoch += 1 + } + missing_epochs.push(candidate_epoch); + Ok(missing_epochs) +} + +pub fn get_path(prefix: &str) -> Path { + Path::from(prefix) +} + +// Snapshot MANIFEST file is very simple. Just a newline delimited list of all +// paths in the snapshot directory this simplicty enables easy parsing for +// scripts to download snapshots +pub async fn write_snapshot_manifest( + dir: &Path, + store: &S, + epoch_prefix: String, +) -> Result<()> { + let mut file_names = vec![]; + let mut paths = store.list_objects(Some(dir)).await?; + while let Some(res) = paths.next().await { + if let Ok(object_metadata) = res { + // trim the "epoch_XX/" dir prefix here + let mut path_str = object_metadata.location.to_string(); + if path_str.starts_with(&epoch_prefix) { + path_str = String::from(&path_str[epoch_prefix.len()..]); + file_names.push(path_str); + } else { + warn!("{path_str}, should be coming from the files in the {epoch_prefix} dir",) + } + } else { + return Err(res.err().unwrap().into()); + } + } + + let epoch_manifest = PerEpochManifest::new(file_names); + let bytes = Bytes::from(epoch_manifest.serialize_as_newline_delimited()); + put( + store, + &Path::from(format!("{}/{}", dir, MANIFEST_FILENAME)), + bytes, + ) + .await?; + + Ok(()) +} + +#[cfg(test)] +mod tests { + use std::{fs, num::NonZeroUsize}; + + use iota_config::object_storage_config::{ObjectStoreConfig, ObjectStoreType}; + use object_store::path::Path; + use tempfile::TempDir; + + use crate::object_store::util::{ + copy_recursively, delete_recursively, write_snapshot_manifest, MANIFEST_FILENAME, + }; + + #[tokio::test] + pub async fn test_copy_recursively() -> anyhow::Result<()> { + let input = TempDir::new()?; + let input_path = input.path(); + let child = input_path.join("child"); + fs::create_dir(&child)?; + let file1 = child.join("file1"); + fs::write(file1, b"Lorem ipsum")?; + let grandchild = child.join("grand_child"); + fs::create_dir(&grandchild)?; + let file2 = grandchild.join("file2"); + fs::write(file2, b"Lorem ipsum")?; + + let output = TempDir::new()?; + let output_path = output.path(); + + let input_store = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(input_path.to_path_buf()), + ..Default::default() + } + .make()?; + + let output_store = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(output_path.to_path_buf()), + ..Default::default() + } + .make()?; + + copy_recursively( + &Path::from("child"), + &input_store, + &output_store, + NonZeroUsize::new(1).unwrap(), + ) + .await?; + + assert!(output_path.join("child").exists()); + assert!(output_path.join("child").join("file1").exists()); + assert!(output_path.join("child").join("grand_child").exists()); + assert!( + output_path + .join("child") + .join("grand_child") + .join("file2") + .exists() + ); + let content = fs::read_to_string(output_path.join("child").join("file1"))?; + assert_eq!(content, "Lorem ipsum"); + let content = + fs::read_to_string(output_path.join("child").join("grand_child").join("file2"))?; + assert_eq!(content, "Lorem ipsum"); + Ok(()) + } + + #[tokio::test] + pub async fn test_write_snapshot_manifest() -> anyhow::Result<()> { + let input = TempDir::new()?; + let input_path = input.path(); + let epoch_0 = input_path.join("epoch_0"); + fs::create_dir(&epoch_0)?; + let file1 = epoch_0.join("file1"); + fs::write(file1, b"Lorem ipsum")?; + let file2 = epoch_0.join("file2"); + fs::write(file2, b"Lorem ipsum")?; + let grandchild = epoch_0.join("grand_child"); + fs::create_dir(&grandchild)?; + let file3 = grandchild.join("file2.tar.gz"); + fs::write(file3, b"Lorem ipsum")?; + + let input_store = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(input_path.to_path_buf()), + ..Default::default() + } + .make()?; + + write_snapshot_manifest( + &Path::from("epoch_0"), + &input_store, + String::from("epoch_0/"), + ) + .await?; + + assert!(input_path.join("epoch_0").join(MANIFEST_FILENAME).exists()); + let content = fs::read_to_string(input_path.join("epoch_0").join(MANIFEST_FILENAME))?; + assert!(content.contains("file2")); + assert!(content.contains("file1")); + assert!(content.contains("grand_child/file2.tar.gz")); + Ok(()) + } + + #[tokio::test] + pub async fn test_delete_recursively() -> anyhow::Result<()> { + let input = TempDir::new()?; + let input_path = input.path(); + let child = input_path.join("child"); + fs::create_dir(&child)?; + let file1 = child.join("file1"); + fs::write(file1, b"Lorem ipsum")?; + let grandchild = child.join("grand_child"); + fs::create_dir(&grandchild)?; + let file2 = grandchild.join("file2"); + fs::write(file2, b"Lorem ipsum")?; + + let input_store = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(input_path.to_path_buf()), + ..Default::default() + } + .make()?; + + delete_recursively( + &Path::from("child"), + &input_store, + NonZeroUsize::new(1).unwrap(), + ) + .await?; + + assert!(!input_path.join("child").join("file1").exists()); + assert!( + !input_path + .join("child") + .join("grand_child") + .join("file2") + .exists() + ); + Ok(()) + } +} diff --git a/crates/sui-storage/src/package_object_cache.rs b/crates/iota-storage/src/package_object_cache.rs similarity index 92% rename from crates/sui-storage/src/package_object_cache.rs rename to crates/iota-storage/src/package_object_cache.rs index 4113d027fe0..3e854be014a 100644 --- a/crates/sui-storage/src/package_object_cache.rs +++ b/crates/iota-storage/src/package_object_cache.rs @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{num::NonZeroUsize, sync::Arc}; -use lru::LruCache; -use parking_lot::RwLock; -use sui_types::{ +use iota_types::{ base_types::ObjectID, - error::{SuiError, SuiResult, UserInputError}, + error::{IotaError, IotaResult, UserInputError}, storage::{ObjectStore, PackageObject}, }; +use lru::LruCache; +use parking_lot::RwLock; pub struct PackageObjectCache { cache: RwLock>, @@ -28,7 +29,7 @@ impl PackageObjectCache { &self, package_id: &ObjectID, store: &impl ObjectStore, - ) -> SuiResult> { + ) -> IotaResult> { // TODO: Here the use of `peek` doesn't update the internal use record, // and hence the LRU is really used as a capped map here. // This is OK because we won't typically have too many entries. @@ -52,7 +53,7 @@ impl PackageObjectCache { self.cache.write().push(*package_id, p.clone()); Ok(Some(p)) } else { - Err(SuiError::UserInputError { + Err(IotaError::UserInputError { error: UserInputError::MoveObjectAsPackage { object_id: *package_id, }, diff --git a/crates/sui-storage/src/sharded_lru.rs b/crates/iota-storage/src/sharded_lru.rs similarity index 98% rename from crates/sui-storage/src/sharded_lru.rs rename to crates/iota-storage/src/sharded_lru.rs index b105e7525ed..678e313d01e 100644 --- a/crates/sui-storage/src/sharded_lru.rs +++ b/crates/iota-storage/src/sharded_lru.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/sui-storage/src/write_path_pending_tx_log.rs b/crates/iota-storage/src/write_path_pending_tx_log.rs similarity index 95% rename from crates/sui-storage/src/write_path_pending_tx_log.rs rename to crates/iota-storage/src/write_path_pending_tx_log.rs index 6b09d0c8393..529c1ebf341 100644 --- a/crates/sui-storage/src/write_path_pending_tx_log.rs +++ b/crates/iota-storage/src/write_path_pending_tx_log.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! WritePathPendingTransactionLog is used in the transaction write path (e.g. @@ -10,10 +11,10 @@ use std::path::PathBuf; -use sui_types::{ +use iota_types::{ base_types::TransactionDigest, crypto::EmptySignInfo, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, message_envelope::TrustedEnvelope, transaction::{SenderSignedData, VerifiedTransaction}, }; @@ -55,7 +56,7 @@ impl WritePathPendingTransactionLog { pub async fn write_pending_transaction_maybe( &self, tx: &VerifiedTransaction, - ) -> SuiResult { + ) -> IotaResult { let tx_digest = tx.digest(); let mut transaction = self.pending_transactions.logs.transaction()?; if transaction @@ -81,10 +82,10 @@ impl WritePathPendingTransactionLog { // making the second request thinks it is the first record. It's preventable // by checking this transaction again after the call of // `write_pending_transaction_maybe`. - pub fn finish_transaction(&self, tx: &TransactionDigest) -> SuiResult { + pub fn finish_transaction(&self, tx: &TransactionDigest) -> IotaResult { let mut write_batch = self.pending_transactions.logs.batch(); write_batch.delete_batch(&self.pending_transactions.logs, std::iter::once(tx))?; - write_batch.write().map_err(SuiError::from) + write_batch.write().map_err(IotaError::from) } pub fn load_all_pending_transactions(&self) -> Vec { @@ -101,7 +102,7 @@ mod tests { use std::collections::HashSet; use anyhow; - use sui_types::utils::create_fake_transaction; + use iota_types::utils::create_fake_transaction; use super::*; diff --git a/crates/sui-storage/tests/key_value_tests.rs b/crates/iota-storage/tests/key_value_tests.rs similarity index 96% rename from crates/sui-storage/tests/key_value_tests.rs rename to crates/iota-storage/tests/key_value_tests.rs index 455de83ba50..1eaa467da4e 100644 --- a/crates/sui-storage/tests/key_value_tests.rs +++ b/crates/iota-storage/tests/key_value_tests.rs @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, sync::Arc}; use async_trait::async_trait; use futures::FutureExt; -use sui_storage::{key_value_store::*, key_value_store_metrics::KeyValueStoreMetrics}; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ +use iota_storage::{key_value_store::*, key_value_store_metrics::KeyValueStoreMetrics}; +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ base_types::{random_object_ref, ExecutionDigests, ObjectID, VersionNumber}, committee::Committee, crypto::{get_key_pair, AccountKeyPair, KeypairTraits}, @@ -15,7 +16,7 @@ use sui_types::{ CheckpointContentsDigest, CheckpointDigest, TransactionDigest, TransactionEventsDigest, }, effects::{TestEffectsBuilder, TransactionEffects, TransactionEffectsAPI, TransactionEvents}, - error::SuiResult, + error::IotaResult, event::Event, messages_checkpoint::{ CertifiedCheckpointSummary, CheckpointContents, CheckpointSequenceNumber, @@ -153,7 +154,7 @@ impl TransactionKeyValueStoreTrait for MockTxStore { transactions: &[TransactionDigest], effects: &[TransactionDigest], events: &[TransactionEventsDigest], - ) -> SuiResult<( + ) -> IotaResult<( Vec>, Vec>, Vec>, @@ -182,7 +183,7 @@ impl TransactionKeyValueStoreTrait for MockTxStore { checkpoint_contents: &[CheckpointSequenceNumber], checkpoint_summaries_by_digest: &[CheckpointDigest], checkpoint_contents_by_digest: &[CheckpointContentsDigest], - ) -> SuiResult<( + ) -> IotaResult<( Vec>, Vec>, Vec>, @@ -214,7 +215,7 @@ impl TransactionKeyValueStoreTrait for MockTxStore { async fn deprecated_get_transaction_checkpoint( &self, digest: TransactionDigest, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self.tx_to_checkpoint.get(&digest).cloned()) } @@ -222,14 +223,14 @@ impl TransactionKeyValueStoreTrait for MockTxStore { &self, object_id: ObjectID, version: VersionNumber, - ) -> SuiResult> { + ) -> IotaResult> { Ok(self.objects.get(&ObjectKey(object_id, version)).cloned()) } async fn multi_get_transaction_checkpoint( &self, digests: &[TransactionDigest], - ) -> SuiResult>> { + ) -> IotaResult>> { Ok(digests .iter() .map(|digest| self.tx_to_checkpoint.get(digest).cloned()) @@ -434,15 +435,15 @@ mod simtests { service::{make_service_fn, service_fn}, Body, Request, Response, Server, }; - use sui_macros::sim_test; - use sui_simulator::configs::constant_latency_ms; - use sui_storage::http_key_value_store::*; + use iota_macros::sim_test; + use iota_simulator::configs::constant_latency_ms; + use iota_storage::http_key_value_store::*; use tracing::info; use super::*; async fn test_server(data: Arc>>>) { - let handle = sui_simulator::runtime::Handle::current(); + let handle = iota_simulator::runtime::Handle::current(); let builder = handle.create_node(); let (startup_sender, mut startup_receiver) = tokio::sync::watch::channel(false); let startup_sender = Arc::new(startup_sender); diff --git a/crates/iota-surfer/Cargo.toml b/crates/iota-surfer/Cargo.toml new file mode 100644 index 00000000000..a4b35440c88 --- /dev/null +++ b/crates/iota-surfer/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "iota-surfer" +version.workspace = true +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +iota-core.workspace = true +iota-swarm-config.workspace = true +iota-json-rpc-types.workspace = true +iota-move-build.workspace = true +iota-protocol-config.workspace = true +iota-types.workspace = true +test-cluster.workspace = true + +async-trait.workspace = true +bcs.workspace = true +clap.workspace = true +futures.workspace = true +indexmap.workspace = true +rand.workspace = true +tokio = { workspace = true, features = ["full", "tracing", "test-util"] } +tracing.workspace = true + +move-binary-format.workspace = true +move-core-types.workspace = true +telemetry-subscribers.workspace = true + +[dev-dependencies] +prometheus.workspace = true +iota-macros.workspace = true +iota-simulator.workspace = true + +move-package.workspace = true diff --git a/crates/sui-surfer/src/default_surf_strategy.rs b/crates/iota-surfer/src/default_surf_strategy.rs similarity index 99% rename from crates/sui-surfer/src/default_surf_strategy.rs rename to crates/iota-surfer/src/default_surf_strategy.rs index 5672ab7868b..4d0fdddf692 100644 --- a/crates/sui-surfer/src/default_surf_strategy.rs +++ b/crates/iota-surfer/src/default_surf_strategy.rs @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_trait::async_trait; -use move_binary_format::normalized::Type; -use move_core_types::language_storage::StructTag; -use rand::{seq::SliceRandom, Rng}; -use sui_types::{ +use iota_types::{ base_types::ObjectRef, transaction::{CallArg, ObjectArg}, }; +use move_binary_format::normalized::Type; +use move_core_types::language_storage::StructTag; +use rand::{seq::SliceRandom, Rng}; use tokio::sync::watch; use tracing::debug; diff --git a/crates/iota-surfer/src/lib.rs b/crates/iota-surfer/src/lib.rs new file mode 100644 index 00000000000..b25f0c3a384 --- /dev/null +++ b/crates/iota-surfer/src/lib.rs @@ -0,0 +1,81 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{path::PathBuf, sync::Arc, time::Duration}; + +use futures::future::join_all; +use iota_swarm_config::genesis_config::{AccountConfig, DEFAULT_GAS_AMOUNT}; +use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng}; +use surf_strategy::SurfStrategy; +use test_cluster::TestClusterBuilder; +use tokio::sync::watch; +use tracing::info; + +use crate::{surfer_state::SurfStatistics, surfer_task::SurferTask}; + +pub mod default_surf_strategy; +mod surf_strategy; +mod surfer_state; +mod surfer_task; + +const VALIDATOR_COUNT: usize = 7; + +const ACCOUNT_NUM: usize = 20; +const GAS_OBJECT_COUNT: usize = 3; + +pub async fn run( + run_duration: Duration, + epoch_duration: Duration, + package_paths: Vec, +) -> SurfStatistics { + let cluster = Arc::new( + TestClusterBuilder::new() + .with_num_validators(VALIDATOR_COUNT) + .with_epoch_duration_ms(epoch_duration.as_millis() as u64) + .with_accounts(vec![ + AccountConfig { + address: None, + gas_amounts: vec![DEFAULT_GAS_AMOUNT; GAS_OBJECT_COUNT], + }; + ACCOUNT_NUM + ]) + .build() + .await, + ); + info!( + "Started cluster with {} validators and epoch duration of {:?}ms", + VALIDATOR_COUNT, + epoch_duration.as_millis() + ); + + let seed = rand::thread_rng().gen::(); + info!("Initial Seed: {:?}", seed); + let mut rng = StdRng::seed_from_u64(seed); + let (exit_sender, exit_rcv) = watch::channel(()); + + let mut tasks = + SurferTask::create_surfer_tasks::(cluster.clone(), rng.gen::(), exit_rcv).await; + info!("Created {} surfer tasks", tasks.len()); + + for path in package_paths { + tasks + .choose_mut(&mut rng) + .unwrap() + .state + .publish_package(path) + .await; + } + + let mut handles = vec![]; + for task in tasks { + handles.push(tokio::task::spawn(task.surf())); + } + tokio::time::sleep(run_duration).await; + exit_sender.send(()).unwrap(); + let all_stats: Result, _> = join_all(handles).await.into_iter().collect(); + SurfStatistics::aggregate(all_stats.unwrap()) + + // TODO: Right now it will panic here complaining about dropping a tokio + // runtime inside of another tokio runtime. Reason unclear. +} diff --git a/crates/iota-surfer/src/main.rs b/crates/iota-surfer/src/main.rs new file mode 100644 index 00000000000..142ccef02bc --- /dev/null +++ b/crates/iota-surfer/src/main.rs @@ -0,0 +1,48 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{path::PathBuf, time::Duration}; + +use clap::Parser; +use iota_surfer::default_surf_strategy::DefaultSurfStrategy; +use tracing::info; + +#[derive(Parser)] +#[clap(rename_all = "kebab-case")] +struct Args { + #[clap(long, help = "Number of seconds to surf, default to 30")] + pub run_duration: Option, + + #[clap(long, help = "Number of seconds per epoch, default to 15")] + pub epoch_duration: Option, + + #[clap(long, help = "List of package paths to surf")] + packages: Vec, +} + +const DEFAULT_RUN_DURATION: u64 = 30; +const DEFAULT_EPOCH_DURATION: u64 = 15; + +#[tokio::main] +async fn main() { + let args = Args::parse(); + if args.packages.is_empty() { + eprintln!("At least one package is required"); + return; + } + + let _guard = telemetry_subscribers::TelemetryConfig::new() + .with_log_level("off,iota_surfer=info") + .with_env() + .init(); + + let results = iota_surfer::run::( + Duration::from_secs(args.run_duration.unwrap_or(DEFAULT_RUN_DURATION)), + Duration::from_secs(args.run_duration.unwrap_or(DEFAULT_EPOCH_DURATION)), + args.packages, + ) + .await; + results.print_stats(); + info!("Finished surfing"); +} diff --git a/crates/sui-surfer/src/surf_strategy.rs b/crates/iota-surfer/src/surf_strategy.rs similarity index 93% rename from crates/sui-surfer/src/surf_strategy.rs rename to crates/iota-surfer/src/surf_strategy.rs index 29433f67264..59106c256cb 100644 --- a/crates/sui-surfer/src/surf_strategy.rs +++ b/crates/iota-surfer/src/surf_strategy.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use async_trait::async_trait; diff --git a/crates/sui-surfer/src/surfer_state.rs b/crates/iota-surfer/src/surfer_state.rs similarity index 96% rename from crates/sui-surfer/src/surfer_state.rs rename to crates/iota-surfer/src/surfer_state.rs index 02684fbfb9c..f41ebb6aec7 100644 --- a/crates/sui-surfer/src/surfer_state.rs +++ b/crates/iota-surfer/src/surfer_state.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -9,20 +10,20 @@ use std::{ }; use indexmap::IndexSet; -use move_binary_format::{file_format::Visibility, normalized::Type}; -use move_core_types::language_storage::StructTag; -use rand::rngs::StdRng; -use sui_json_rpc_types::{SuiTransactionBlockEffects, SuiTransactionBlockEffectsAPI}; -use sui_move_build::BuildConfig; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress}, +use iota_json_rpc_types::{IotaTransactionBlockEffects, IotaTransactionBlockEffectsAPI}; +use iota_move_build::BuildConfig; +use iota_protocol_config::ProtocolConfig; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber}, execution_config_utils::to_binary_config, object::{Object, Owner}, storage::WriteKind, transaction::{CallArg, ObjectArg, TransactionData, TEST_ONLY_GAS_UNIT_FOR_PUBLISH}, - Identifier, SUI_FRAMEWORK_ADDRESS, + Identifier, IOTA_FRAMEWORK_ADDRESS, }; +use move_binary_format::{file_format::Visibility, normalized::Type}; +use move_core_types::language_storage::StructTag; +use rand::rngs::StdRng; use test_cluster::TestCluster; use tokio::sync::RwLock; use tracing::{debug, error, info}; @@ -111,7 +112,7 @@ pub struct SurferState { pub cluster: Arc, pub rng: StdRng, - pub address: SuiAddress, + pub address: IotaAddress, pub gas_object: ObjectRef, pub owned_objects: OwnedObjects, pub immutable_objects: ImmObjects, @@ -125,7 +126,7 @@ impl SurferState { pub fn new( cluster: Arc, rng: StdRng, - address: SuiAddress, + address: IotaAddress, gas_object: ObjectRef, owned_objects: OwnedObjects, immutable_objects: ImmObjects, @@ -205,7 +206,7 @@ impl SurferState { self.process_tx_effects(&effects).await; } - async fn process_tx_effects(&mut self, effects: &SuiTransactionBlockEffects) { + async fn process_tx_effects(&mut self, effects: &IotaTransactionBlockEffects) { for (owned_ref, write_kind) in effects.all_changed_objects() { if matches!(owned_ref.owner, Owner::ObjectOwner(_)) { // For object owned objects, we don't need to do anything. @@ -403,7 +404,7 @@ fn is_type_tx_context(ty: &Type) -> bool { name, type_arguments, } => { - address == &SUI_FRAMEWORK_ADDRESS + address == &IOTA_FRAMEWORK_ADDRESS && module == &Identifier::new("tx_context").unwrap() && name == &Identifier::new("TxContext").unwrap() && type_arguments.is_empty() diff --git a/crates/sui-surfer/src/surfer_task.rs b/crates/iota-surfer/src/surfer_task.rs similarity index 95% rename from crates/sui-surfer/src/surfer_task.rs rename to crates/iota-surfer/src/surfer_task.rs index a8f6899706d..cc8694fa833 100644 --- a/crates/sui-surfer/src/surfer_task.rs +++ b/crates/iota-surfer/src/surfer_task.rs @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashMap, sync::Arc}; -use rand::{rngs::StdRng, Rng, SeedableRng}; -use sui_core::{ +use iota_core::{ authority::authority_store_tables::LiveObject, state_accumulator::AccumulatorStore, }; -use sui_types::{ - base_types::{ObjectRef, SuiAddress}, +use iota_types::{ + base_types::{IotaAddress, ObjectRef}, object::Owner, }; +use rand::{rngs::StdRng, Rng, SeedableRng}; use test_cluster::TestCluster; use tokio::sync::{watch, RwLock}; @@ -35,7 +36,7 @@ impl SurferTask { let immutable_objects: ImmObjects = Arc::new(RwLock::new(HashMap::new())); let shared_objects: SharedObjects = Arc::new(RwLock::new(HashMap::new())); - let mut accounts: HashMap, OwnedObjects)> = cluster + let mut accounts: HashMap, OwnedObjects)> = cluster .get_addresses() .iter() .map(|address| (*address, (None, HashMap::new()))) diff --git a/crates/iota-surfer/tests/move_building_blocks/Move.toml b/crates/iota-surfer/tests/move_building_blocks/Move.toml new file mode 100644 index 00000000000..8aae2dfcd9d --- /dev/null +++ b/crates/iota-surfer/tests/move_building_blocks/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "MoveBuildingBlocks" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../iota-framework/packages/iota-framework" } + +[addresses] +move_building_blocks = "0x0" \ No newline at end of file diff --git a/crates/sui-surfer/tests/move_building_blocks/sources/limits.move b/crates/iota-surfer/tests/move_building_blocks/sources/limits.move similarity index 85% rename from crates/sui-surfer/tests/move_building_blocks/sources/limits.move rename to crates/iota-surfer/tests/move_building_blocks/sources/limits.move index f1bb1464042..df3547cdc95 100644 --- a/crates/sui-surfer/tests/move_building_blocks/sources/limits.move +++ b/crates/iota-surfer/tests/move_building_blocks/sources/limits.move @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module move_building_blocks::limits { - use sui::object::UID; - use sui::object; - use sui::tx_context::TxContext; + use iota::object::UID; + use iota::object; + use iota::tx_context::TxContext; use std::vector; - use sui::transfer; - use sui::tx_context; - use sui::dynamic_field; + use iota::transfer; + use iota::tx_context; + use iota::dynamic_field; struct ObjectWithVector has key, store { id: UID, diff --git a/crates/sui-surfer/tests/move_building_blocks/sources/objects.move b/crates/iota-surfer/tests/move_building_blocks/sources/objects.move similarity index 94% rename from crates/sui-surfer/tests/move_building_blocks/sources/objects.move rename to crates/iota-surfer/tests/move_building_blocks/sources/objects.move index 0f93190d227..08cd803788d 100644 --- a/crates/sui-surfer/tests/move_building_blocks/sources/objects.move +++ b/crates/iota-surfer/tests/move_building_blocks/sources/objects.move @@ -1,16 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module move_building_blocks::objects { - use sui::object::UID; + use iota::object::UID; use std::option::Option; - use sui::table::Table; - use sui::tx_context::TxContext; - use sui::object; + use iota::table::Table; + use iota::tx_context::TxContext; + use iota::object; use std::option; - use sui::table; - use sui::transfer; - use sui::tx_context; + use iota::table; + use iota::transfer; + use iota::tx_context; struct Object has key, store { id: UID, diff --git a/crates/iota-surfer/tests/random/Move.toml b/crates/iota-surfer/tests/random/Move.toml new file mode 100644 index 00000000000..8299ae0edcb --- /dev/null +++ b/crates/iota-surfer/tests/random/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "Random" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../iota-framework/packages/iota-framework" } + +[addresses] +random = "0x0" diff --git a/crates/iota-surfer/tests/random/sources/random.move b/crates/iota-surfer/tests/random/sources/random.move new file mode 100644 index 00000000000..2cb89cbae44 --- /dev/null +++ b/crates/iota-surfer/tests/random/sources/random.move @@ -0,0 +1,49 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module random::random_test { + use iota::object::UID; + use iota::object; + use iota::tx_context::TxContext; + use iota::transfer; + use iota::random; + + + // Test transactions that use the same shared object, sometimes with Random and sometimes without. + + struct SharedObject has key, store { + id: UID, + value: u256, + } + + fun init(ctx: &mut TxContext) { + let object = SharedObject { + id: object::new(ctx), + value: 123, + }; + transfer::share_object(object); + } + + // Update the shared object using Random. + entry fun mutate_with_random(obj: &mut SharedObject, r: &random::Random, n: u8, ctx: &mut TxContext) { + let gen = random::new_generator(r, ctx); + let _b = random::generate_bytes(&mut gen, (n as u16)); + obj.value = random::generate_u256(&mut gen); + assert!(obj.value > 0, 0); // very low probability + } + + // Update the shared object without using Random. + entry fun mutate_without(obj: &mut SharedObject) { + obj.value = obj.value % 27; + } + + + // Test transactions that use Random without a shared object. + entry fun generate(r: &random::Random, ctx: &mut TxContext): u64 { + let _gen1 = random::new_generator(r, ctx); + let _gen2 = random::new_generator(r, ctx); + let gen3 = random::new_generator(r, ctx); + random::generate_u64(&mut gen3) + } +} diff --git a/crates/iota-surfer/tests/smoke_tests.rs b/crates/iota-surfer/tests/smoke_tests.rs new file mode 100644 index 00000000000..7657a34d55d --- /dev/null +++ b/crates/iota-surfer/tests/smoke_tests.rs @@ -0,0 +1,23 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{path::PathBuf, time::Duration}; + +use iota_macros::sim_test; +use iota_surfer::default_surf_strategy::DefaultSurfStrategy; + +#[sim_test] +async fn smoke_test() { + // This test makes sure that the iota surfer runs. + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.extend(["tests", "move_building_blocks"]); + let results = iota_surfer::run::( + Duration::from_secs(30), + Duration::from_secs(15), + vec![path], + ) + .await; + assert!(results.num_successful_transactions > 0); + assert!(!results.unique_move_functions_called.is_empty()); +} diff --git a/crates/iota-swarm-config/Cargo.toml b/crates/iota-swarm-config/Cargo.toml new file mode 100644 index 00000000000..a9254bc14d7 --- /dev/null +++ b/crates/iota-swarm-config/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "iota-swarm-config" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anemo.workspace = true +anyhow.workspace = true +fastcrypto.workspace = true +rand.workspace = true +serde.workspace = true +serde_with.workspace = true +serde_yaml.workspace = true +tempfile.workspace = true +tracing.workspace = true +prometheus.workspace = true + +move-bytecode-utils.workspace = true +narwhal-config.workspace = true +shared-crypto.workspace = true +iota-config.workspace = true +iota-macros.workspace = true +iota-protocol-config.workspace = true +iota-types.workspace = true +iota-genesis-builder.workspace = true + +[target.'cfg(msim)'.dependencies] +iota-simulator.workspace = true + +[dev-dependencies] +insta.workspace = true +tempfile.workspace = true + +iota-execution.workspace = true diff --git a/crates/sui-swarm-config/src/genesis_config.rs b/crates/iota-swarm-config/src/genesis_config.rs similarity index 93% rename from crates/sui-swarm-config/src/genesis_config.rs rename to crates/iota-swarm-config/src/genesis_config.rs index f08c8caabb4..5a1750452cc 100644 --- a/crates/sui-swarm-config/src/genesis_config.rs +++ b/crates/iota-swarm-config/src/genesis_config.rs @@ -1,27 +1,28 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::net::{IpAddr, SocketAddr}; use anyhow::Result; use fastcrypto::traits::KeyPair; -use rand::{rngs::StdRng, SeedableRng}; -use serde::{Deserialize, Serialize}; -use sui_config::{ +use iota_config::{ genesis::{GenesisCeremonyParameters, TokenAllocation}, local_ip_utils, node::{DEFAULT_COMMISSION_RATE, DEFAULT_VALIDATOR_GAS_PRICE}, Config, }; -use sui_genesis_builder::validator_info::{GenesisValidatorInfo, ValidatorInfo}; -use sui_types::{ - base_types::SuiAddress, +use iota_genesis_builder::validator_info::{GenesisValidatorInfo, ValidatorInfo}; +use iota_types::{ + base_types::IotaAddress, crypto::{ generate_proof_of_possession, get_key_pair_from_rng, AccountKeyPair, AuthorityKeyPair, - AuthorityPublicKeyBytes, NetworkKeyPair, NetworkPublicKey, PublicKey, SuiKeyPair, + AuthorityPublicKeyBytes, IotaKeyPair, NetworkKeyPair, NetworkPublicKey, PublicKey, }, multiaddr::Multiaddr, }; +use rand::{rngs::StdRng, SeedableRng}; +use serde::{Deserialize, Serialize}; use tracing::info; // All information needed to build a NodeConfig for a state sync fullnode. @@ -38,8 +39,8 @@ pub struct ValidatorGenesisConfig { pub key_pair: AuthorityKeyPair, #[serde(default = "default_ed25519_key_pair")] pub worker_key_pair: NetworkKeyPair, - #[serde(default = "default_sui_key_pair")] - pub account_key_pair: SuiKeyPair, + #[serde(default = "default_iota_key_pair")] + pub account_key_pair: IotaKeyPair, #[serde(default = "default_ed25519_key_pair")] pub network_key_pair: NetworkKeyPair, pub network_address: Multiaddr, @@ -73,7 +74,7 @@ impl ValidatorGenesisConfig { protocol_key, worker_key, network_key, - account_address: SuiAddress::from(&account_key), + account_address: IotaAddress::from(&account_key), gas_price: self.gas_price, commission_rate: self.commission_rate, network_address, @@ -214,7 +215,7 @@ impl ValidatorGenesisConfigBuilder { narwhal_worker_address, consensus_address, consensus_internal_worker_address: None, - stake: sui_types::governance::VALIDATOR_LOW_STAKE_THRESHOLD_MIST, + stake: iota_types::governance::VALIDATOR_LOW_STAKE_THRESHOLD_MICROS, name: None, } } @@ -256,7 +257,7 @@ impl GenesisConfig { account.gas_amounts.iter().for_each(|a| { allocations.push(TokenAllocation { recipient_address: address, - amount_mist: *a, + amount_micros: *a, staked_with_validator: None, }); }); @@ -275,7 +276,7 @@ fn default_multiaddr_address() -> Multiaddr { } fn default_stake() -> u64 { - sui_types::governance::VALIDATOR_LOW_STAKE_THRESHOLD_MIST + iota_types::governance::VALIDATOR_LOW_STAKE_THRESHOLD_MICROS } fn default_bls12381_key_pair() -> AuthorityKeyPair { @@ -286,14 +287,14 @@ fn default_ed25519_key_pair() -> NetworkKeyPair { get_key_pair_from_rng(&mut rand::rngs::OsRng).1 } -fn default_sui_key_pair() -> SuiKeyPair { - SuiKeyPair::Ed25519(get_key_pair_from_rng(&mut rand::rngs::OsRng).1) +fn default_iota_key_pair() -> IotaKeyPair { + IotaKeyPair::Ed25519(get_key_pair_from_rng(&mut rand::rngs::OsRng).1) } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct AccountConfig { #[serde(skip_serializing_if = "Option::is_none")] - pub address: Option, + pub address: Option, pub gas_amounts: Vec, } @@ -320,7 +321,7 @@ impl GenesisConfig { ) } - pub fn for_local_testing_with_addresses(addresses: Vec) -> Self { + pub fn for_local_testing_with_addresses(addresses: Vec) -> Self { Self::custom_genesis_with_addresses(addresses, DEFAULT_NUMBER_OF_OBJECT_PER_ACCOUNT) } @@ -340,7 +341,7 @@ impl GenesisConfig { } pub fn custom_genesis_with_addresses( - addresses: Vec, + addresses: Vec, num_objects_per_account: usize, ) -> Self { let mut accounts = Vec::new(); @@ -383,7 +384,7 @@ impl GenesisConfig { let account_configs = Self::benchmark_gas_keys(validator_config_info.len()) .iter() .map(|gas_key| { - let gas_address = SuiAddress::from(&gas_key.public()); + let gas_address = IotaAddress::from(&gas_key.public()); AccountConfig { address: Some(gas_address), @@ -416,10 +417,10 @@ impl GenesisConfig { /// for benchmarks. This function may be called by other parts of the /// codebase (e.g. load generators) to get the same keypair used for /// genesis (hence the importance of the seedable rng). - pub fn benchmark_gas_keys(n: usize) -> Vec { + pub fn benchmark_gas_keys(n: usize) -> Vec { let mut rng = StdRng::seed_from_u64(Self::BENCHMARKS_RNG_SEED); (0..n) - .map(|_| SuiKeyPair::Ed25519(NetworkKeyPair::generate(&mut rng))) + .map(|_| IotaKeyPair::Ed25519(NetworkKeyPair::generate(&mut rng))) .collect() } diff --git a/crates/iota-swarm-config/src/lib.rs b/crates/iota-swarm-config/src/lib.rs new file mode 100644 index 00000000000..d5af1e8a8bd --- /dev/null +++ b/crates/iota-swarm-config/src/lib.rs @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod genesis_config; +pub mod network_config; +pub mod network_config_builder; +pub mod node_config_builder; +pub mod test_utils; diff --git a/crates/sui-swarm-config/src/network_config.rs b/crates/iota-swarm-config/src/network_config.rs similarity index 90% rename from crates/sui-swarm-config/src/network_config.rs rename to crates/iota-swarm-config/src/network_config.rs index d3d2e3b9f5d..63600bba708 100644 --- a/crates/sui-swarm-config/src/network_config.rs +++ b/crates/iota-swarm-config/src/network_config.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use sui_config::{genesis, Config, NodeConfig}; -use sui_types::{ +use iota_config::{genesis, Config, NodeConfig}; +use iota_types::{ committee::CommitteeWithNetworkMetadata, crypto::AccountKeyPair, multiaddr::Multiaddr, }; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; /// This is a config that is used for testing or local use as it contains the /// config and keys for all validators diff --git a/crates/sui-swarm-config/src/network_config_builder.rs b/crates/iota-swarm-config/src/network_config_builder.rs similarity index 94% rename from crates/sui-swarm-config/src/network_config_builder.rs rename to crates/iota-swarm-config/src/network_config_builder.rs index b2661d15fdf..45055f080af 100644 --- a/crates/sui-swarm-config/src/network_config_builder.rs +++ b/crates/iota-swarm-config/src/network_config_builder.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -8,19 +9,19 @@ use std::{ time::Duration, }; -use rand::rngs::OsRng; -use sui_config::{ +use iota_config::{ genesis::{TokenAllocation, TokenDistributionScheduleBuilder}, node::AuthorityOverloadConfig, }; -use sui_macros::nondeterministic; -use sui_protocol_config::SupportedProtocolVersions; -use sui_types::{ - base_types::{AuthorityName, SuiAddress}, +use iota_macros::nondeterministic; +use iota_protocol_config::SupportedProtocolVersions; +use iota_types::{ + base_types::{AuthorityName, IotaAddress}, committee::{Committee, ProtocolVersion}, crypto::{get_key_pair_from_rng, AccountKeyPair, KeypairTraits, PublicKey}, object::Object, }; +use rand::rngs::OsRng; use crate::{ genesis_config::{ @@ -319,16 +320,16 @@ impl ConfigBuilder { // Add allocations for each validator for validator in &validators { let account_key: PublicKey = validator.account_key_pair.public(); - let address = SuiAddress::from(&account_key); + let address = IotaAddress::from(&account_key); // Give each validator some gas so they can pay for their transactions. let gas_coin = TokenAllocation { recipient_address: address, - amount_mist: DEFAULT_GAS_AMOUNT, + amount_micros: DEFAULT_GAS_AMOUNT, staked_with_validator: None, }; let stake = TokenAllocation { recipient_address: address, - amount_mist: validator.stake, + amount_micros: validator.stake, staked_with_validator: Some(address), }; builder.add_allocation(gas_coin); @@ -338,7 +339,7 @@ impl ConfigBuilder { }; let genesis = { - let mut builder = sui_genesis_builder::Builder::new() + let mut builder = iota_genesis_builder::Builder::new() .with_parameters(genesis_config.parameters) .add_objects(self.additional_objects); @@ -411,7 +412,7 @@ impl ConfigBuilder { #[cfg(test)] mod tests { - use sui_config::node::Genesis; + use iota_config::node::Genesis; #[test] fn serialize_genesis_config_in_place() { @@ -461,11 +462,11 @@ mod tests { mod test { use std::{collections::HashSet, sync::Arc}; - use sui_config::genesis::Genesis; - use sui_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; - use sui_types::{ - epoch_data::EpochData, gas::SuiGasStatus, in_memory_storage::InMemoryStorage, - metrics::LimitsMetrics, sui_system_state::SuiSystemStateTrait, + use iota_config::genesis::Genesis; + use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; + use iota_types::{ + epoch_data::EpochData, gas::IotaGasStatus, in_memory_storage::InMemoryStorage, + iota_system_state::IotaSystemStateTrait, metrics::LimitsMetrics, transaction::CheckedInputObjects, }; @@ -487,7 +488,8 @@ mod test { let builder = crate::network_config_builder::ConfigBuilder::new_with_temp_dir(); let network_config = builder.build(); let genesis = network_config.genesis; - let protocol_version = ProtocolVersion::new(genesis.sui_system_object().protocol_version()); + let protocol_version = + ProtocolVersion::new(genesis.iota_system_object().protocol_version()); let protocol_config = ProtocolConfig::get_for_version(protocol_version, Chain::Unknown); let genesis_transaction = genesis.transaction().clone(); @@ -495,7 +497,7 @@ mod test { let genesis_digest = *genesis_transaction.digest(); let silent = true; - let executor = sui_execution::executor(&protocol_config, silent, None) + let executor = iota_execution::executor(&protocol_config, silent, None) .expect("Creating an executor should not fail here"); // Use a throwaway metrics registry for genesis transaction execution. @@ -519,7 +521,7 @@ mod test { epoch.epoch_start_timestamp(), input_objects, vec![], - SuiGasStatus::new_unmetered(), + IotaGasStatus::new_unmetered(), kind, signer, genesis_digest, diff --git a/crates/sui-swarm-config/src/node_config_builder.rs b/crates/iota-swarm-config/src/node_config_builder.rs similarity index 95% rename from crates/sui-swarm-config/src/node_config_builder.rs rename to crates/iota-swarm-config/src/node_config_builder.rs index 6a50eb9632d..f7387de47eb 100644 --- a/crates/sui-swarm-config/src/node_config_builder.rs +++ b/crates/iota-swarm-config/src/node_config_builder.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{net::SocketAddr, path::PathBuf, time::Duration}; @@ -7,8 +8,7 @@ use fastcrypto::{ encoding::{Encoding, Hex}, traits::KeyPair, }; -use narwhal_config::{NetworkAdminServerParameters, PrometheusMetricsParameters}; -use sui_config::{ +use iota_config::{ local_ip_utils, node::{ default_enable_index_processing, default_end_of_epoch_broadcast_channel_capacity, @@ -20,11 +20,12 @@ use sui_config::{ p2p::{P2pConfig, SeedPeer, StateSyncConfig}, ConsensusConfig, NodeConfig, AUTHORITIES_DB_NAME, CONSENSUS_DB_NAME, FULL_NODE_DB_PATH, }; -use sui_protocol_config::SupportedProtocolVersions; -use sui_types::{ - crypto::{AuthorityKeyPair, AuthorityPublicKeyBytes, NetworkKeyPair, SuiKeyPair}, +use iota_protocol_config::SupportedProtocolVersions; +use iota_types::{ + crypto::{AuthorityKeyPair, AuthorityPublicKeyBytes, IotaKeyPair, NetworkKeyPair}, multiaddr::Multiaddr, }; +use narwhal_config::{NetworkAdminServerParameters, PrometheusMetricsParameters}; use crate::{ genesis_config::{ValidatorGenesisConfig, ValidatorGenesisConfigBuilder}, @@ -87,7 +88,7 @@ impl ValidatorConfigBuilder { pub fn build( self, validator: ValidatorGenesisConfig, - genesis: sui_config::genesis::Genesis, + genesis: iota_config::genesis::Genesis, ) -> NodeConfig { let key_path = get_key_path(&validator.key_pair); let config_directory = self @@ -155,9 +156,11 @@ impl ValidatorConfigBuilder { NodeConfig { protocol_key_pair: AuthorityKeyPairWithPath::new(validator.key_pair), - network_key_pair: KeyPairWithPath::new(SuiKeyPair::Ed25519(validator.network_key_pair)), + network_key_pair: KeyPairWithPath::new(IotaKeyPair::Ed25519( + validator.network_key_pair, + )), account_key_pair: KeyPairWithPath::new(validator.account_key_pair), - worker_key_pair: KeyPairWithPath::new(SuiKeyPair::Ed25519(validator.worker_key_pair)), + worker_key_pair: KeyPairWithPath::new(IotaKeyPair::Ed25519(validator.worker_key_pair)), db_path, network_address, metrics_address: validator.metrics_address, @@ -168,7 +171,7 @@ impl ValidatorConfigBuilder { consensus_config: Some(consensus_config), enable_event_processing: false, enable_index_processing: default_enable_index_processing(), - genesis: sui_config::node::Genesis::new(genesis), + genesis: iota_config::node::Genesis::new(genesis), grpc_load_shed: None, grpc_concurrency_limit: Some(DEFAULT_GRPC_CONCURRENCY_LIMIT), p2p_config, @@ -321,7 +324,7 @@ impl FullnodeConfigBuilder { pub fn with_network_key_pair(mut self, network_key_pair: Option) -> Self { if let Some(network_key_pair) = network_key_pair { self.network_key_pair = - Some(KeyPairWithPath::new(SuiKeyPair::Ed25519(network_key_pair))); + Some(KeyPairWithPath::new(IotaKeyPair::Ed25519(network_key_pair))); } self } @@ -399,11 +402,11 @@ impl FullnodeConfigBuilder { NodeConfig { protocol_key_pair: AuthorityKeyPairWithPath::new(validator_config.key_pair), account_key_pair: KeyPairWithPath::new(validator_config.account_key_pair), - worker_key_pair: KeyPairWithPath::new(SuiKeyPair::Ed25519( + worker_key_pair: KeyPairWithPath::new(IotaKeyPair::Ed25519( validator_config.worker_key_pair, )), network_key_pair: self.network_key_pair.unwrap_or(KeyPairWithPath::new( - SuiKeyPair::Ed25519(validator_config.network_key_pair), + IotaKeyPair::Ed25519(validator_config.network_key_pair), )), db_path: self .db_path @@ -421,7 +424,7 @@ impl FullnodeConfigBuilder { consensus_config: None, enable_event_processing: true, // This is unused. enable_index_processing: default_enable_index_processing(), - genesis: self.genesis.unwrap_or(sui_config::node::Genesis::new( + genesis: self.genesis.unwrap_or(iota_config::node::Genesis::new( network_config.genesis.clone(), )), grpc_load_shed: None, diff --git a/crates/iota-swarm-config/src/test_utils.rs b/crates/iota-swarm-config/src/test_utils.rs new file mode 100644 index 00000000000..2a2f4cbfdcf --- /dev/null +++ b/crates/iota-swarm-config/src/test_utils.rs @@ -0,0 +1,256 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashMap; + +use iota_types::{ + base_types::AuthorityName, + committee::{Committee, EpochId, StakeUnit}, + crypto::{ + AuthorityKeyPair, AuthoritySignInfo, AuthoritySignature, IotaAuthoritySignature, + KeypairTraits, + }, + messages_checkpoint::{ + CertifiedCheckpointSummary, CheckpointDigest, CheckpointSequenceNumber, CheckpointSummary, + EndOfEpochData, FullCheckpointContents, VerifiedCheckpoint, VerifiedCheckpointContents, + }, +}; +use shared_crypto::intent::{Intent, IntentMessage, IntentScope}; + +use crate::network_config::NetworkConfig; + +pub struct CommitteeFixture { + epoch: EpochId, + validators: HashMap, + committee: Committee, +} + +type MakeCheckpointResults = ( + Vec, + Vec, + HashMap, + HashMap, +); + +impl CommitteeFixture { + pub fn generate( + mut rng: R, + epoch: EpochId, + committee_size: usize, + ) -> Self { + let validators = (0..committee_size) + .map(|_| iota_types::crypto::get_key_pair_from_rng::(&mut rng).1) + .map(|keypair| (keypair.public().into(), (keypair, 1))) + .collect::>(); + + let committee = Committee::new_for_testing_with_normalized_voting_power( + epoch, + validators + .iter() + .map(|(name, (_, stake))| (*name, *stake)) + .collect(), + ); + + Self { + epoch, + validators, + committee, + } + } + + pub fn from_network_config(network_config: &NetworkConfig) -> Self { + let committee = network_config.genesis.committee().unwrap(); + Self { + epoch: committee.epoch, + validators: committee + .members() + .map(|(name, stake)| { + ( + *name, + ( + network_config + .validator_configs() + .iter() + .find(|config| config.protocol_public_key() == *name) + .unwrap() + .protocol_key_pair() + .copy(), + *stake, + ), + ) + }) + .collect(), + committee, + } + } + + pub fn committee(&self) -> &Committee { + &self.committee + } + + fn create_root_checkpoint(&self) -> (VerifiedCheckpoint, VerifiedCheckpointContents) { + assert_eq!(self.epoch, 0, "root checkpoint must be epoch 0"); + let checkpoint = CheckpointSummary { + epoch: 0, + sequence_number: 0, + network_total_transactions: 0, + content_digest: *empty_contents() + .into_inner() + .into_checkpoint_contents() + .digest(), + previous_digest: None, + epoch_rolling_gas_cost_summary: Default::default(), + end_of_epoch_data: None, + timestamp_ms: 0, + version_specific_data: Vec::new(), + checkpoint_commitments: Default::default(), + }; + + ( + self.create_certified_checkpoint(checkpoint), + empty_contents(), + ) + } + + fn create_certified_checkpoint(&self, checkpoint: CheckpointSummary) -> VerifiedCheckpoint { + let signatures = self + .validators + .iter() + .map(|(name, (key, _))| { + let intent_msg = IntentMessage::new( + Intent::iota_app(IntentScope::CheckpointSummary), + checkpoint.clone(), + ); + let signature = AuthoritySignature::new_secure(&intent_msg, &checkpoint.epoch, key); + AuthoritySignInfo { + epoch: checkpoint.epoch, + authority: *name, + signature, + } + }) + .collect(); + + let checkpoint = CertifiedCheckpointSummary::new(checkpoint, signatures, self.committee()) + .unwrap() + .verify(self.committee()) + .unwrap(); + + checkpoint + } + + pub fn make_random_checkpoints( + &self, + number_of_checkpoints: usize, + previous_checkpoint: Option, + ) -> MakeCheckpointResults { + self.make_checkpoints(number_of_checkpoints, previous_checkpoint, random_contents) + } + + pub fn make_empty_checkpoints( + &self, + number_of_checkpoints: usize, + previous_checkpoint: Option, + ) -> MakeCheckpointResults { + self.make_checkpoints(number_of_checkpoints, previous_checkpoint, empty_contents) + } + + fn make_checkpoints VerifiedCheckpointContents>( + &self, + number_of_checkpoints: usize, + previous_checkpoint: Option, + content_generator: F, + ) -> MakeCheckpointResults { + // Only skip the first one if it was supplied + let skip = previous_checkpoint.is_some() as usize; + let first = previous_checkpoint + .map(|c| (c, empty_contents())) + .unwrap_or_else(|| self.create_root_checkpoint()); + + let (ordered_checkpoints, contents): (Vec<_>, Vec<_>) = + std::iter::successors(Some(first), |prev| { + let contents = content_generator(); + let contents_digest = *contents + .clone() + .into_inner() + .into_checkpoint_contents() + .digest(); + let summary = CheckpointSummary { + epoch: self.epoch, + sequence_number: prev.0.sequence_number + 1, + network_total_transactions: prev.0.network_total_transactions + + contents.num_of_transactions() as u64, + content_digest: contents_digest, + previous_digest: Some(*prev.0.digest()), + epoch_rolling_gas_cost_summary: Default::default(), + end_of_epoch_data: None, + timestamp_ms: 0, + version_specific_data: Vec::new(), + checkpoint_commitments: Default::default(), + }; + + let checkpoint = self.create_certified_checkpoint(summary); + + Some((checkpoint, contents)) + }) + .skip(skip) + .take(number_of_checkpoints) + .unzip(); + + let (sequence_number_to_digest, checkpoints) = ordered_checkpoints + .iter() + .cloned() + .map(|checkpoint| { + let digest = *checkpoint.digest(); + ((checkpoint.sequence_number, digest), (digest, checkpoint)) + }) + .unzip(); + + ( + ordered_checkpoints, + contents, + sequence_number_to_digest, + checkpoints, + ) + } + + pub fn make_end_of_epoch_checkpoint( + &self, + previous_checkpoint: VerifiedCheckpoint, + end_of_epoch_data: Option, + ) -> ( + CheckpointSequenceNumber, + CheckpointDigest, + VerifiedCheckpoint, + ) { + let summary = CheckpointSummary { + epoch: self.epoch, + sequence_number: previous_checkpoint.sequence_number + 1, + network_total_transactions: 0, + content_digest: *empty_contents() + .into_inner() + .into_checkpoint_contents() + .digest(), + previous_digest: Some(*previous_checkpoint.digest()), + epoch_rolling_gas_cost_summary: Default::default(), + end_of_epoch_data, + timestamp_ms: 0, + version_specific_data: Vec::new(), + checkpoint_commitments: Default::default(), + }; + + let checkpoint = self.create_certified_checkpoint(summary); + + (checkpoint.sequence_number, *checkpoint.digest(), checkpoint) + } +} + +pub fn empty_contents() -> VerifiedCheckpointContents { + VerifiedCheckpointContents::new_unchecked( + FullCheckpointContents::new_with_causally_ordered_transactions(std::iter::empty()), + ) +} + +pub fn random_contents() -> VerifiedCheckpointContents { + VerifiedCheckpointContents::new_unchecked(FullCheckpointContents::random_for_testing()) +} diff --git a/crates/iota-swarm-config/tests/snapshot_tests.rs b/crates/iota-swarm-config/tests/snapshot_tests.rs new file mode 100644 index 00000000000..5f6d7312c30 --- /dev/null +++ b/crates/iota-swarm-config/tests/snapshot_tests.rs @@ -0,0 +1,164 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// This file contains tests that detect changes in Iota configs. +// If a PR breaks one or more tests here, the PR probably has a real impact +// on a production configuration file. When test failure happens, the PR should +// be marked as a breaking change and reviewers should be aware of this. +// +// Owners and operators of production configuration files can add themselves to +// .github/CODEOWNERS for the corresponding snapshot tests, so they can get +// notified of changes. PRs that modifies snapshot files should wait for reviews +// from code owners (if any) before merging. +// +// To review snapshot changes, and fix snapshot differences, +// 0. Install cargo-insta +// 1. Run `cargo insta test --review` under `./iota-config`. +// 2. Review, accept or reject changes. + +use std::num::NonZeroUsize; + +use fastcrypto::traits::KeyPair; +use insta::assert_yaml_snapshot; +use iota_config::{ + genesis::{GenesisCeremonyParameters, TokenDistributionScheduleBuilder}, + node::{DEFAULT_COMMISSION_RATE, DEFAULT_VALIDATOR_GAS_PRICE}, +}; +use iota_genesis_builder::{validator_info::ValidatorInfo, Builder}; +use iota_swarm_config::genesis_config::GenesisConfig; +use iota_types::{ + base_types::IotaAddress, + crypto::{ + generate_proof_of_possession, get_key_pair_from_rng, AccountKeyPair, AuthorityKeyPair, + IotaKeyPair, NetworkKeyPair, + }, + multiaddr::Multiaddr, +}; +use rand::{rngs::StdRng, SeedableRng}; + +#[test] +#[cfg_attr(msim, ignore)] +fn genesis_config_snapshot_matches() { + let ed_kp1: IotaKeyPair = + IotaKeyPair::Ed25519(get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1); + let fake_addr: IotaAddress = (&ed_kp1.public()).into(); + + let mut genesis_config = GenesisConfig::for_local_testing(); + genesis_config.parameters.chain_start_timestamp_ms = 0; + for account in &mut genesis_config.accounts { + account.address = Some(fake_addr); + } + assert_yaml_snapshot!(genesis_config); +} + +#[test] +fn populated_genesis_snapshot_matches() { + let genesis_config = GenesisConfig::for_local_testing(); + let (_account_keys, allocations) = genesis_config + .generate_accounts(StdRng::from_seed([0; 32])) + .unwrap(); + let mut rng = StdRng::from_seed([0; 32]); + let key: AuthorityKeyPair = get_key_pair_from_rng(&mut rng).1; + let worker_key: NetworkKeyPair = get_key_pair_from_rng(&mut rng).1; + let network_key: NetworkKeyPair = get_key_pair_from_rng(&mut rng).1; + let account_key: AccountKeyPair = get_key_pair_from_rng(&mut rng).1; + let validator = ValidatorInfo { + name: "0".into(), + protocol_key: key.public().into(), + worker_key: worker_key.public().clone(), + account_address: IotaAddress::from(account_key.public()), + network_key: network_key.public().clone(), + gas_price: DEFAULT_VALIDATOR_GAS_PRICE, + commission_rate: DEFAULT_COMMISSION_RATE, + network_address: "/ip4/127.0.0.1/tcp/80".parse().unwrap(), + p2p_address: "/ip4/127.0.0.1/udp/80".parse().unwrap(), + narwhal_primary_address: "/ip4/127.0.0.1/udp/80".parse().unwrap(), + narwhal_worker_address: "/ip4/127.0.0.1/udp/80".parse().unwrap(), + description: String::new(), + image_url: String::new(), + project_url: String::new(), + }; + let pop = generate_proof_of_possession(&key, account_key.public().into()); + + let token_distribution_schedule = { + let mut builder = TokenDistributionScheduleBuilder::new(); + for allocation in allocations { + builder.add_allocation(allocation); + } + builder.default_allocation_for_validators(Some(validator.account_address)); + builder.build() + }; + + let genesis = Builder::new() + .with_token_distribution_schedule(token_distribution_schedule) + .add_validator(validator, pop) + .with_parameters(GenesisCeremonyParameters { + chain_start_timestamp_ms: 10, + ..GenesisCeremonyParameters::new() + }) + .add_validator_signature(&key) + .build(); + assert_yaml_snapshot!(genesis.iota_system_wrapper_object()); + assert_yaml_snapshot!( + genesis + .iota_system_object() + .into_genesis_version_for_tooling() + ); + assert_yaml_snapshot!(genesis.clock()); + // Serialized `genesis` is not static and cannot be snapshot tested. +} + +#[test] +#[cfg_attr(msim, ignore)] +fn network_config_snapshot_matches() { + use std::{ + net::{IpAddr, Ipv4Addr, SocketAddr}, + path::PathBuf, + }; + + use iota_swarm_config::network_config_builder::ConfigBuilder; + + let temp_dir = tempfile::tempdir().unwrap(); + let committee_size = 7; + let rng = StdRng::from_seed([0; 32]); + let mut network_config = ConfigBuilder::new(temp_dir) + .committee_size(NonZeroUsize::new(committee_size).unwrap()) + .rng(rng) + .build(); + // TODO: Inject static temp path and port numbers, instead of clearing them. + for validator_config in &mut network_config.validator_configs { + validator_config.db_path = PathBuf::from("/tmp/foo/"); + validator_config.network_address = Multiaddr::empty(); + let fake_socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 1); + validator_config.json_rpc_address = fake_socket; + validator_config.metrics_address = fake_socket; + validator_config.p2p_config.listen_address = fake_socket; + validator_config.p2p_config.external_address = None; + validator_config.admin_interface_port = 8888; + let metrics_addr: Multiaddr = "/ip4/127.0.0.1/tcp/1234".parse().unwrap(); + let primary_network_admin_server_port = 5678; + let worker_network_admin_server_base_port = 8765; + if let Some(consensus_config) = validator_config.consensus_config.as_mut() { + consensus_config.address = Multiaddr::empty(); + consensus_config.db_path = PathBuf::from("/tmp/foo/"); + consensus_config.internal_worker_address = Some(Multiaddr::empty()); + consensus_config + .narwhal_config + .prometheus_metrics + .socket_addr = metrics_addr; + consensus_config + .narwhal_config + .network_admin_server + .primary_network_admin_server_port = primary_network_admin_server_port; + consensus_config + .narwhal_config + .network_admin_server + .worker_network_admin_server_base_port = worker_network_admin_server_base_port; + } + } + assert_yaml_snapshot!(network_config, { + ".genesis" => "[fake genesis]", + ".validator_configs[].genesis.genesis" => "[fake genesis]", + }); +} diff --git a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__genesis_config_snapshot_matches.snap b/crates/iota-swarm-config/tests/snapshots/snapshot_tests__genesis_config_snapshot_matches.snap similarity index 96% rename from crates/sui-swarm-config/tests/snapshots/snapshot_tests__genesis_config_snapshot_matches.snap rename to crates/iota-swarm-config/tests/snapshots/snapshot_tests__genesis_config_snapshot_matches.snap index 87dc6b2796a..c04a7a8e9a8 100644 --- a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__genesis_config_snapshot_matches.snap +++ b/crates/iota-swarm-config/tests/snapshots/snapshot_tests__genesis_config_snapshot_matches.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-swarm-config/tests/snapshot_tests.rs +source: crates/iota-swarm-config/tests/snapshot_tests.rs expression: genesis_config --- ssfn_config_info: ~ diff --git a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__network_config_snapshot_matches.snap b/crates/iota-swarm-config/tests/snapshots/snapshot_tests__network_config_snapshot_matches.snap similarity index 95% rename from crates/sui-swarm-config/tests/snapshots/snapshot_tests__network_config_snapshot_matches.snap rename to crates/iota-swarm-config/tests/snapshots/snapshot_tests__network_config_snapshot_matches.snap index e92843235c9..2634da7b23d 100644 --- a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__network_config_snapshot_matches.snap +++ b/crates/iota-swarm-config/tests/snapshots/snapshot_tests__network_config_snapshot_matches.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-swarm-config/tests/snapshot_tests.rs +source: crates/iota-swarm-config/tests/snapshot_tests.rs expression: network_config --- validator_configs: @@ -69,9 +69,9 @@ validator_configs: perform-db-checkpoints-at-epoch-end: false indirect-objects-threshold: 18446744073709551615 expensive-safety-check-config: - enable-epoch-sui-conservation-check: false - enable-deep-per-tx-sui-conservation-check: false - force-disable-epoch-sui-conservation-check: false + enable-epoch-iota-conservation-check: false + enable-deep-per-tx-iota-conservation-check: false + force-disable-epoch-iota-conservation-check: false enable-state-consistency-check: false force-disable-state-consistency-check: false enable-secondary-index-checks: false @@ -196,9 +196,9 @@ validator_configs: perform-db-checkpoints-at-epoch-end: false indirect-objects-threshold: 18446744073709551615 expensive-safety-check-config: - enable-epoch-sui-conservation-check: false - enable-deep-per-tx-sui-conservation-check: false - force-disable-epoch-sui-conservation-check: false + enable-epoch-iota-conservation-check: false + enable-deep-per-tx-iota-conservation-check: false + force-disable-epoch-iota-conservation-check: false enable-state-consistency-check: false force-disable-state-consistency-check: false enable-secondary-index-checks: false @@ -323,9 +323,9 @@ validator_configs: perform-db-checkpoints-at-epoch-end: false indirect-objects-threshold: 18446744073709551615 expensive-safety-check-config: - enable-epoch-sui-conservation-check: false - enable-deep-per-tx-sui-conservation-check: false - force-disable-epoch-sui-conservation-check: false + enable-epoch-iota-conservation-check: false + enable-deep-per-tx-iota-conservation-check: false + force-disable-epoch-iota-conservation-check: false enable-state-consistency-check: false force-disable-state-consistency-check: false enable-secondary-index-checks: false @@ -450,9 +450,9 @@ validator_configs: perform-db-checkpoints-at-epoch-end: false indirect-objects-threshold: 18446744073709551615 expensive-safety-check-config: - enable-epoch-sui-conservation-check: false - enable-deep-per-tx-sui-conservation-check: false - force-disable-epoch-sui-conservation-check: false + enable-epoch-iota-conservation-check: false + enable-deep-per-tx-iota-conservation-check: false + force-disable-epoch-iota-conservation-check: false enable-state-consistency-check: false force-disable-state-consistency-check: false enable-secondary-index-checks: false @@ -577,9 +577,9 @@ validator_configs: perform-db-checkpoints-at-epoch-end: false indirect-objects-threshold: 18446744073709551615 expensive-safety-check-config: - enable-epoch-sui-conservation-check: false - enable-deep-per-tx-sui-conservation-check: false - force-disable-epoch-sui-conservation-check: false + enable-epoch-iota-conservation-check: false + enable-deep-per-tx-iota-conservation-check: false + force-disable-epoch-iota-conservation-check: false enable-state-consistency-check: false force-disable-state-consistency-check: false enable-secondary-index-checks: false @@ -704,9 +704,9 @@ validator_configs: perform-db-checkpoints-at-epoch-end: false indirect-objects-threshold: 18446744073709551615 expensive-safety-check-config: - enable-epoch-sui-conservation-check: false - enable-deep-per-tx-sui-conservation-check: false - force-disable-epoch-sui-conservation-check: false + enable-epoch-iota-conservation-check: false + enable-deep-per-tx-iota-conservation-check: false + force-disable-epoch-iota-conservation-check: false enable-state-consistency-check: false force-disable-state-consistency-check: false enable-secondary-index-checks: false @@ -831,9 +831,9 @@ validator_configs: perform-db-checkpoints-at-epoch-end: false indirect-objects-threshold: 18446744073709551615 expensive-safety-check-config: - enable-epoch-sui-conservation-check: false - enable-deep-per-tx-sui-conservation-check: false - force-disable-epoch-sui-conservation-check: false + enable-epoch-iota-conservation-check: false + enable-deep-per-tx-iota-conservation-check: false + force-disable-epoch-iota-conservation-check: false enable-state-consistency-check: false force-disable-state-consistency-check: false enable-secondary-index-checks: false diff --git a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap b/crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap similarity index 95% rename from crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap rename to crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap index 79e7b40dbd5..9a3a459ed2f 100644 --- a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap +++ b/crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap @@ -1,6 +1,6 @@ --- -source: crates/sui-swarm-config/tests/snapshot_tests.rs -expression: genesis.sui_system_object().into_genesis_version_for_tooling() +source: crates/iota-swarm-config/tests/snapshot_tests.rs +expression: genesis.iota_system_object().into_genesis_version_for_tooling() --- epoch: 0 protocol_version: 42 @@ -9,7 +9,7 @@ validators: total_stake: 20000000000000000 active_validators: - metadata: - sui_address: "0x60307f36c284875bf298d4d85a673046648b1ac4b47e712e42ab10d57dd77a26" + iota_address: "0x60307f36c284875bf298d4d85a673046648b1ac4b47e712e42ab10d57dd77a26" protocol_pubkey_bytes: - 153 - 242 @@ -249,7 +249,7 @@ validators: id: "0x36a34b5a3e61721e569b93c83376471739d996323bac81bb62cf692b6d356340" activation_epoch: 0 deactivation_epoch: ~ - sui_balance: 20000000000000000 + iota_balance: 20000000000000000 rewards_pool: value: 0 pool_token_balance: 20000000000000000 @@ -257,7 +257,7 @@ validators: id: "0x3b70ffe10f9a22714e5ec0567fe1dad8e0467aefc280dcb9398991a8a1f6ec9a" size: 1 pending_stake: 0 - pending_total_sui_withdraw: 0 + pending_total_iota_withdraw: 0 pending_pool_token_withdraw: 0 extra_fields: id: diff --git a/crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-3.snap b/crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-3.snap new file mode 100644 index 00000000000..074a7422b31 --- /dev/null +++ b/crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-3.snap @@ -0,0 +1,8 @@ +--- +source: crates/iota-swarm-config/tests/snapshot_tests.rs +expression: genesis.clock() +--- +id: + id: "0x0000000000000000000000000000000000000000000000000000000000000006" +timestamp_ms: 10 + diff --git a/crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-4.snap b/crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-4.snap new file mode 100644 index 00000000000..f1540c076eb --- /dev/null +++ b/crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-4.snap @@ -0,0 +1,8 @@ +--- +source: crates/iota-config/tests/snapshot_tests.rs +expression: genesis.clock() +--- +id: + id: "0x0000000000000000000000000000000000000000000000000000000000000006" +timestamp_ms: 0 + diff --git a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-5.snap b/crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-5.snap similarity index 96% rename from crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-5.snap rename to crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-5.snap index ba21eade5c7..ce70edd3c0f 100644 --- a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-5.snap +++ b/crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-5.snap @@ -1,6 +1,6 @@ --- -source: crates/sui-config/tests/snapshot_tests.rs -expression: genesis.sui_system_object() +source: crates/iota-config/tests/snapshot_tests.rs +expression: genesis.iota_system_object() --- info: id: "0x0000000000000000000000000000000000000005" @@ -11,7 +11,7 @@ validators: quorum_stake_threshold: 1 active_validators: - metadata: - sui_address: "0x21b60aa9a8cb189ccbe20461dbfad2202fdef55b" + iota_address: "0x21b60aa9a8cb189ccbe20461dbfad2202fdef55b" pubkey_bytes: - 153 - 242 @@ -217,7 +217,7 @@ validators: delegation_staking_pool: validator_address: "0x21b60aa9a8cb189ccbe20461dbfad2202fdef55b" starting_epoch: 1 - sui_balance: 0 + iota_balance: 0 rewards_pool: value: 0 delegation_token_supply: @@ -228,7 +228,7 @@ validators: pending_validators: [] pending_removals: [] next_epoch_validators: - - sui_address: "0x21b60aa9a8cb189ccbe20461dbfad2202fdef55b" + - iota_address: "0x21b60aa9a8cb189ccbe20461dbfad2202fdef55b" pubkey_bytes: - 153 - 242 diff --git a/crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches.snap b/crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches.snap new file mode 100644 index 00000000000..fda6fe7731d --- /dev/null +++ b/crates/iota-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches.snap @@ -0,0 +1,8 @@ +--- +source: crates/iota-config/tests/snapshot_tests.rs +expression: genesis.iota_system_wrapper_object() +--- +id: + id: "0x0000000000000000000000000000000000000000000000000000000000000005" +version: 1 + diff --git a/crates/iota-swarm/Cargo.toml b/crates/iota-swarm/Cargo.toml new file mode 100644 index 00000000000..8cba6c3cba4 --- /dev/null +++ b/crates/iota-swarm/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "iota-swarm" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +rand.workspace = true +tracing.workspace = true +tokio = { workspace = true, features = ["full"] } +futures.workspace = true +tempfile.workspace = true +tonic-health.workspace = true +tap.workspace = true +prometheus.workspace = true + +iota-config.workspace = true +iota-swarm-config.workspace = true +iota-macros.workspace = true +iota-node.workspace = true +iota-protocol-config.workspace = true +iota-types.workspace = true +mysten-metrics.workspace = true +mysten-network.workspace = true +telemetry-subscribers.workspace = true + +[target.'cfg(msim)'.dependencies] +iota-simulator.workspace = true + diff --git a/crates/iota-swarm/README.md b/crates/iota-swarm/README.md new file mode 100644 index 00000000000..7e3464b1d5d --- /dev/null +++ b/crates/iota-swarm/README.md @@ -0,0 +1,20 @@ +# iota-swarm + +This crate contains a collection of utilities for managing complete Iota +networks. The intended use for these utilities is for performing end-to-end +testing and benchmarking. In the future, the expectation is that we'll have +support for a number of different "backends" for how the network is operated. +Today the only supplied backend is the `memory` backend, although in the future +we should be able to support a multi-process and even a Kubernetes (k8s) backend. + +## Backends + +### memory + +An `in-memory`, or rather `in-process`, backend for building and managing Iota +networks that all run inside the same process. Nodes are isolated from one +another by each being run on their own separate thread within their own `tokio` +runtime. This enables the ability to properly shut down a single node and +ensure that all of its running tasks are also shut down, something that is +extremely difficult or down right impossible to do if all the nodes are running +on the same runtime. diff --git a/crates/iota-swarm/src/lib.rs b/crates/iota-swarm/src/lib.rs new file mode 100644 index 00000000000..989a5bcae10 --- /dev/null +++ b/crates/iota-swarm/src/lib.rs @@ -0,0 +1,5 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod memory; diff --git a/crates/sui-swarm/src/memory/container-sim.rs b/crates/iota-swarm/src/memory/container-sim.rs similarity index 82% rename from crates/sui-swarm/src/memory/container-sim.rs rename to crates/iota-swarm/src/memory/container-sim.rs index 73df7c6f5f6..05efeb3216d 100644 --- a/crates/sui-swarm/src/memory/container-sim.rs +++ b/crates/iota-swarm/src/memory/container-sim.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -6,10 +7,10 @@ use std::{ sync::{Arc, Weak}, }; +use iota_config::NodeConfig; +use iota_node::{IotaNode, IotaNodeHandle}; +use iota_types::base_types::ConciseableName; use prometheus::Registry; -use sui_config::NodeConfig; -use sui_node::{SuiNode, SuiNodeHandle}; -use sui_types::base_types::ConciseableName; use tokio::sync::watch; use tracing::{info, trace}; @@ -19,12 +20,12 @@ use super::node::RuntimeType; pub(crate) struct Container { handle: Option, cancel_sender: Option>, - node_watch: watch::Receiver>, + node_watch: watch::Receiver>, } #[derive(Debug)] struct ContainerHandle { - node_id: sui_simulator::task::NodeId, + node_id: iota_simulator::task::NodeId, } /// When dropped, stop and wait for the node running in this Container to @@ -33,7 +34,7 @@ impl Drop for Container { fn drop(&mut self) { if let Some(handle) = self.handle.take() { tracing::info!("shutting down {}", handle.node_id); - sui_simulator::runtime::Handle::try_current().map(|h| h.delete_node(handle.node_id)); + iota_simulator::runtime::Handle::try_current().map(|h| h.delete_node(handle.node_id)); } } } @@ -44,7 +45,7 @@ impl Container { let (startup_sender, mut startup_receiver) = tokio::sync::watch::channel(Weak::new()); let (cancel_sender, cancel_receiver) = tokio::sync::watch::channel(false); - let handle = sui_simulator::runtime::Handle::current(); + let handle = iota_simulator::runtime::Handle::current(); let builder = handle.create_node(); let socket_addr = config.network_address.to_socket_addr().unwrap(); @@ -64,7 +65,7 @@ impl Container { let startup_sender = startup_sender.clone(); async move { let registry_service = mysten_metrics::RegistryService::new(Registry::new()); - let server = SuiNode::start(config, registry_service, None) + let server = IotaNode::start(config, registry_service, None) .await .unwrap(); @@ -90,9 +91,9 @@ impl Container { } } - /// Get a SuiNodeHandle to the node owned by the container. - pub fn get_node_handle(&self) -> Option { - Some(SuiNodeHandle::new(self.node_watch.borrow().upgrade()?)) + /// Get a IotaNodeHandle to the node owned by the container. + pub fn get_node_handle(&self) -> Option { + Some(IotaNodeHandle::new(self.node_watch.borrow().upgrade()?)) } /// Check to see that the Node is still alive by checking if the receiving diff --git a/crates/sui-swarm/src/memory/container.rs b/crates/iota-swarm/src/memory/container.rs similarity index 91% rename from crates/sui-swarm/src/memory/container.rs rename to crates/iota-swarm/src/memory/container.rs index 912dcf56c30..a774ffe5b47 100644 --- a/crates/sui-swarm/src/memory/container.rs +++ b/crates/iota-swarm/src/memory/container.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -7,9 +8,9 @@ use std::{ }; use futures::FutureExt; -use sui_config::NodeConfig; -use sui_node::{SuiNode, SuiNodeHandle}; -use sui_types::{ +use iota_config::NodeConfig; +use iota_node::{IotaNode, IotaNodeHandle}; +use iota_types::{ base_types::ConciseableName, crypto::{AuthorityPublicKeyBytes, KeypairTraits}, }; @@ -22,7 +23,7 @@ use super::node::RuntimeType; pub(crate) struct Container { join_handle: Option>, cancel_sender: Option>, - node: Weak, + node: Weak, } /// When dropped, stop and wait for the node running in this Container to @@ -102,7 +103,7 @@ impl Container { "Started Prometheus HTTP endpoint. To query metrics use\n\tcurl -s http://{}/metrics", config.metrics_address ); - let server = SuiNode::start(config, registry_service, None).await.unwrap(); + let server = IotaNode::start(config, registry_service, None).await.unwrap(); // Notify that we've successfully started the node let _ = startup_sender.send(Arc::downgrade(&server)); // run until canceled @@ -121,9 +122,9 @@ impl Container { } } - /// Get a SuiNodeHandle to the node owned by the container. - pub fn get_node_handle(&self) -> Option { - Some(SuiNodeHandle::new(self.node.upgrade()?)) + /// Get a IotaNodeHandle to the node owned by the container. + pub fn get_node_handle(&self) -> Option { + Some(IotaNodeHandle::new(self.node.upgrade()?)) } /// Check to see that the Node is still alive by checking if the receiving diff --git a/crates/iota-swarm/src/memory/mod.rs b/crates/iota-swarm/src/memory/mod.rs new file mode 100644 index 00000000000..9ae6f422811 --- /dev/null +++ b/crates/iota-swarm/src/memory/mod.rs @@ -0,0 +1,25 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! An `in-memory`, or rather `in-process`, backend for building and managing +//! Iota Networks that all run inside the same process. Nodes are isolated from +//! one another by each being run on their own separate thread within their own +//! `tokio` runtime. This enables the ability to properly shut down a single +//! node and ensure that all of its running tasks are also shut down, something +//! that is extremely difficult or down right impossible to do if all the nodes +//! are running on the same runtime. + +mod node; +pub use node::{Node, RuntimeType}; + +mod swarm; +pub use swarm::{Swarm, SwarmBuilder}; + +#[cfg(msim)] +#[path = "./container-sim.rs"] +mod container; + +#[cfg(not(msim))] +#[path = "./container.rs"] +mod container; diff --git a/crates/iota-swarm/src/memory/node.rs b/crates/iota-swarm/src/memory/node.rs new file mode 100644 index 00000000000..f63c2c541b7 --- /dev/null +++ b/crates/iota-swarm/src/memory/node.rs @@ -0,0 +1,167 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::Mutex; + +use anyhow::{anyhow, Result}; +use iota_config::NodeConfig; +use iota_node::IotaNodeHandle; +use iota_types::base_types::{AuthorityName, ConciseableName}; +use tap::TapFallible; +use tracing::{error, info}; + +use super::container::Container; + +/// A handle to an in-memory Iota Node. +/// +/// Each Node is attempted to run in isolation from each other by running them +/// in their own tokio runtime in a separate thread. By doing this we can ensure +/// that all asynchronous tasks associated with a Node are able to be stopped +/// when desired (either when a Node is dropped or explicitly stopped by calling +/// [`Node::stop`]) by simply dropping that Node's runtime. +#[derive(Debug)] +pub struct Node { + container: Mutex>, + pub config: NodeConfig, + runtime_type: RuntimeType, +} + +impl Node { + /// Create a new Node from the provided `NodeConfig`. + /// + /// The Node is returned without being started. See [`Node::spawn`] or + /// [`Node::start`] for how to start the node. + /// + /// [`NodeConfig`]: iota_config::NodeConfig + pub fn new(config: NodeConfig) -> Self { + Self { + container: Default::default(), + config, + runtime_type: RuntimeType::SingleThreaded, + } + } + + /// Return the `name` of this Node + pub fn name(&self) -> AuthorityName { + self.config.protocol_public_key() + } + + pub fn json_rpc_address(&self) -> std::net::SocketAddr { + self.config.json_rpc_address + } + + /// Start this Node + pub async fn spawn(&self) -> Result<()> { + info!(name =% self.name().concise(), "starting in-memory node"); + *self.container.lock().unwrap() = + Some(Container::spawn(self.config.clone(), self.runtime_type).await); + Ok(()) + } + + /// Start this Node, waiting until its completely started up. + pub async fn start(&self) -> Result<()> { + self.spawn().await + } + + /// Stop this Node + pub fn stop(&self) { + info!(name =% self.name().concise(), "stopping in-memory node"); + *self.container.lock().unwrap() = None; + } + + /// If this Node is currently running + pub fn is_running(&self) -> bool { + self.container + .lock() + .unwrap() + .as_ref() + .map_or(false, |c| c.is_alive()) + } + + pub fn get_node_handle(&self) -> Option { + self.container + .lock() + .unwrap() + .as_ref() + .and_then(|c| c.get_node_handle()) + } + + /// Perform a health check on this Node by: + /// * Checking that the node is running + /// * Calling the Node's gRPC Health service if it's a validator. + pub async fn health_check(&self, is_validator: bool) -> Result<(), HealthCheckError> { + { + let lock = self.container.lock().unwrap(); + let container = lock.as_ref().ok_or(HealthCheckError::NotRunning)?; + if !container.is_alive() { + return Err(HealthCheckError::NotRunning); + } + } + + if is_validator { + let channel = mysten_network::client::connect(self.config.network_address()) + .await + .map_err(|err| anyhow!(err.to_string())) + .map_err(HealthCheckError::Failure) + .tap_err(|e| error!("error connecting to {}: {e}", self.name().concise()))?; + + let mut client = tonic_health::pb::health_client::HealthClient::new(channel); + client + .check(tonic_health::pb::HealthCheckRequest::default()) + .await + .map_err(|e| HealthCheckError::Failure(e.into())) + .tap_err(|e| { + error!( + "error performing health check on {}: {e}", + self.name().concise() + ) + })?; + } + + Ok(()) + } +} + +#[derive(Debug)] +pub enum HealthCheckError { + NotRunning, + Failure(anyhow::Error), + Unknown(anyhow::Error), +} + +impl std::fmt::Display for HealthCheckError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl std::error::Error for HealthCheckError {} + +/// The type of tokio runtime that should be used for a particular Node +#[derive(Clone, Copy, Debug)] +pub enum RuntimeType { + SingleThreaded, + MultiThreaded, +} + +#[cfg(test)] +mod test { + use crate::memory::Swarm; + + #[tokio::test] + async fn start_and_stop() { + telemetry_subscribers::init_for_testing(); + let swarm = Swarm::builder().build(); + + let validator = swarm.validator_nodes().next().unwrap(); + + validator.start().await.unwrap(); + validator.health_check(true).await.unwrap(); + validator.stop(); + validator.health_check(true).await.unwrap_err(); + + validator.start().await.unwrap(); + validator.health_check(true).await.unwrap(); + } +} diff --git a/crates/sui-swarm/src/memory/swarm.rs b/crates/iota-swarm/src/memory/swarm.rs similarity index 97% rename from crates/sui-swarm/src/memory/swarm.rs rename to crates/iota-swarm/src/memory/swarm.rs index fba9eec5c5a..6016aeb8e4c 100644 --- a/crates/sui-swarm/src/memory/swarm.rs +++ b/crates/iota-swarm/src/memory/swarm.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -12,15 +13,14 @@ use std::{ use anyhow::Result; use futures::future::try_join_all; -use rand::rngs::OsRng; -use sui_config::{ +use iota_config::{ node::{AuthorityOverloadConfig, DBCheckpointConfig, RunWithRange}, NodeConfig, }; -use sui_macros::nondeterministic; -use sui_node::SuiNodeHandle; -use sui_protocol_config::{ProtocolVersion, SupportedProtocolVersions}; -use sui_swarm_config::{ +use iota_macros::nondeterministic; +use iota_node::IotaNodeHandle; +use iota_protocol_config::{ProtocolVersion, SupportedProtocolVersions}; +use iota_swarm_config::{ genesis_config::{AccountConfig, GenesisConfig, ValidatorGenesisConfig}, network_config::NetworkConfig, network_config_builder::{ @@ -28,7 +28,8 @@ use sui_swarm_config::{ }, node_config_builder::FullnodeConfigBuilder, }; -use sui_types::{base_types::AuthorityName, object::Object}; +use iota_types::{base_types::AuthorityName, object::Object}; +use rand::rngs::OsRng; use tempfile::TempDir; use tracing::info; @@ -355,7 +356,7 @@ impl SwarmBuilder { } } -/// A handle to an in-memory Sui Network. +/// A handle to an in-memory Iota Network. #[derive(Debug)] pub struct Swarm { dir: SwarmDirectory, @@ -428,7 +429,7 @@ impl Swarm { .filter(|node| node.config.consensus_config.is_some()) } - pub fn validator_node_handles(&self) -> Vec { + pub fn validator_node_handles(&self) -> Vec { self.validator_nodes() .map(|node| node.get_node_handle().unwrap()) .collect() @@ -451,7 +452,7 @@ impl Swarm { .filter(|node| node.config.consensus_config.is_none()) } - pub async fn spawn_new_node(&mut self, config: NodeConfig) -> SuiNodeHandle { + pub async fn spawn_new_node(&mut self, config: NodeConfig) -> IotaNodeHandle { let name = config.protocol_public_key(); let node = Node::new(config); node.start().await.unwrap(); diff --git a/crates/iota-telemetry/Cargo.toml b/crates/iota-telemetry/Cargo.toml new file mode 100644 index 00000000000..fe9cf361c49 --- /dev/null +++ b/crates/iota-telemetry/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "iota-telemetry" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +serde.workspace = true +reqwest.workspace = true +tracing.workspace = true + +iota-core.workspace = true + diff --git a/crates/iota-telemetry/src/lib.rs b/crates/iota-telemetry/src/lib.rs new file mode 100644 index 00000000000..12ee0ee1979 --- /dev/null +++ b/crates/iota-telemetry/src/lib.rs @@ -0,0 +1,126 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::BTreeMap, + sync::Arc, + time::{SystemTime, UNIX_EPOCH}, +}; + +use iota_core::authority::AuthorityState; +use serde::{Deserialize, Serialize}; +use tracing::trace; + +pub(crate) const GA_API_SECRET: &str = "zeq-aYEzS0aGdRJ8kNZTEg"; +pub(crate) const GA_EVENT_NAME: &str = "node_telemetry_event"; +pub(crate) const GA_MEASUREMENT_ID: &str = "G-96DM59YK2F"; +pub(crate) const GA_URL: &str = "https://www.google-analytics.com/mp/collect"; +// need this hardcoded client ID as only existing client is valid. +// see below for details: +// https://developers.google.com/analytics/devguides/collection/protocol/ga4/verify-implementation?client_type=gtag +pub(crate) const HARDCODED_CLIENT_ID: &str = "1871165366.1648333069"; +pub(crate) const IPLOOKUP_URL: &str = "https://api.ipify.org?format=json"; +pub(crate) const UNKNOWN_STRING: &str = "UNKNOWN"; + +#[derive(Debug, Serialize, Deserialize)] +struct TelemetryEvent { + name: String, + params: BTreeMap, +} + +// The payload needs to meet this requirement in +// https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference?client_type=gtag#payload_post_body +#[derive(Debug, Serialize, Deserialize)] +struct TelemetryPayload { + client_id: String, + events: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +struct IpResponse { + ip: String, +} + +pub async fn send_telemetry_event(state: Arc, is_validator: bool) { + let git_rev = env!("CARGO_PKG_VERSION").to_string(); + let ip_address = get_ip().await; + let chain_identifier = match state.get_chain_identifier() { + Some(chain_identifier) => chain_identifier.to_string(), + None => "Unknown".to_string(), + }; + let since_the_epoch = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Now should be later than epoch!"); + let telemetry_event = TelemetryEvent { + name: GA_EVENT_NAME.into(), + params: BTreeMap::from([ + ("chain_identifier".into(), chain_identifier), + ("node_address".into(), ip_address), + ( + "node_type".into(), + if is_validator { + "validator".into() + } else { + "full_node".into() + }, + ), + ("git_rev".into(), git_rev), + ( + "seconds_since_epoch".into(), + since_the_epoch.as_secs().to_string(), + ), + ]), + }; + + let telemetry_payload = TelemetryPayload { + client_id: HARDCODED_CLIENT_ID.into(), + events: vec![telemetry_event], + }; + + send_telemetry_event_impl(telemetry_payload).await +} + +async fn get_ip() -> String { + let resp = reqwest::get(IPLOOKUP_URL).await; + match resp { + Ok(json) => match json.json::().await { + Ok(ip_json) => ip_json.ip, + Err(_) => UNKNOWN_STRING.into(), + }, + Err(_) => UNKNOWN_STRING.into(), + } +} + +async fn send_telemetry_event_impl(telemetry_payload: TelemetryPayload) { + let client = reqwest::Client::new(); + let response_result = client + .post(format!( + "{}?&measurement_id={}&api_secret={}", + GA_URL, GA_MEASUREMENT_ID, GA_API_SECRET + )) + .json::(&telemetry_payload) + .send() + .await; + + match response_result { + Ok(response) => { + let status = response.status().as_u16(); + if (200..299).contains(&status) { + trace!("SUCCESS: Sent telemetry event: {:?}", &telemetry_payload,); + } else { + trace!( + "FAIL: Sending telemetry event failed with status: {} and response {:?}.", + response.status(), + response + ); + } + } + Err(error) => { + trace!( + "FAIL: Sending telemetry event failed with error: {:?}", + error + ); + } + } +} diff --git a/crates/iota-test-transaction-builder/Cargo.toml b/crates/iota-test-transaction-builder/Cargo.toml new file mode 100644 index 00000000000..d10835de998 --- /dev/null +++ b/crates/iota-test-transaction-builder/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "iota-test-transaction-builder" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +bcs.workspace = true + +shared-crypto.workspace = true +iota-genesis-builder.workspace = true +iota-move-build.workspace = true +iota-sdk.workspace = true +iota-types.workspace = true + +move-core-types.workspace = true diff --git a/crates/iota-test-transaction-builder/src/lib.rs b/crates/iota-test-transaction-builder/src/lib.rs new file mode 100644 index 00000000000..45efb327b8a --- /dev/null +++ b/crates/iota-test-transaction-builder/src/lib.rs @@ -0,0 +1,672 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::path::PathBuf; + +use iota_genesis_builder::validator_info::GenesisValidatorMetadata; +use iota_move_build::{BuildConfig, CompiledPackage}; +use iota_sdk::{ + rpc_types::{ + get_new_package_obj_from_response, IotaTransactionBlockEffectsAPI, + IotaTransactionBlockResponse, + }, + wallet_context::WalletContext, +}; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber}, + crypto::{get_key_pair, AccountKeyPair, Signature, Signer}, + digests::TransactionDigest, + iota_system_state::IOTA_SYSTEM_MODULE_NAME, + multisig::{BitmapUnit, MultiSig, MultiSigPublicKey}, + multisig_legacy::{MultiSigLegacy, MultiSigPublicKeyLegacy}, + object::Owner, + signature::GenericSignature, + transaction::{ + CallArg, ObjectArg, ProgrammableTransaction, Transaction, TransactionData, + DEFAULT_VALIDATOR_GAS_PRICE, TEST_ONLY_GAS_UNIT_FOR_HEAVY_COMPUTATION_STORAGE, + TEST_ONLY_GAS_UNIT_FOR_TRANSFER, + }, + TypeTag, IOTA_SYSTEM_PACKAGE_ID, +}; +use move_core_types::ident_str; +use shared_crypto::intent::{Intent, IntentMessage}; + +pub struct TestTransactionBuilder { + test_data: TestTransactionData, + sender: IotaAddress, + gas_object: ObjectRef, + gas_price: u64, +} + +impl TestTransactionBuilder { + pub fn new(sender: IotaAddress, gas_object: ObjectRef, gas_price: u64) -> Self { + Self { + test_data: TestTransactionData::Empty, + sender, + gas_object, + gas_price, + } + } + + pub fn sender(&self) -> IotaAddress { + self.sender + } + + pub fn gas_object(&self) -> ObjectRef { + self.gas_object + } + + // Use `with_type_args` below to provide type args if any + pub fn move_call( + mut self, + package_id: ObjectID, + module: &'static str, + function: &'static str, + args: Vec, + ) -> Self { + assert!(matches!(self.test_data, TestTransactionData::Empty)); + self.test_data = TestTransactionData::Move(MoveData { + package_id, + module, + function, + args, + type_args: vec![], + }); + self + } + + pub fn with_type_args(mut self, type_args: Vec) -> Self { + if let TestTransactionData::Move(data) = &mut self.test_data { + assert!(data.type_args.is_empty()); + data.type_args = type_args; + } else { + panic!("Cannot set type args for non-move call"); + } + self + } + + pub fn call_counter_create(self, package_id: ObjectID) -> Self { + self.move_call(package_id, "counter", "create", vec![]) + } + + pub fn call_counter_increment( + self, + package_id: ObjectID, + counter_id: ObjectID, + counter_initial_shared_version: SequenceNumber, + ) -> Self { + self.move_call( + package_id, + "counter", + "increment", + vec![CallArg::Object(ObjectArg::SharedObject { + id: counter_id, + initial_shared_version: counter_initial_shared_version, + mutable: true, + })], + ) + } + + pub fn call_counter_read( + self, + package_id: ObjectID, + counter_id: ObjectID, + counter_initial_shared_version: SequenceNumber, + ) -> Self { + self.move_call( + package_id, + "counter", + "value", + vec![CallArg::Object(ObjectArg::SharedObject { + id: counter_id, + initial_shared_version: counter_initial_shared_version, + mutable: false, + })], + ) + } + + pub fn call_counter_delete( + self, + package_id: ObjectID, + counter_id: ObjectID, + counter_initial_shared_version: SequenceNumber, + ) -> Self { + self.move_call( + package_id, + "counter", + "delete", + vec![CallArg::Object(ObjectArg::SharedObject { + id: counter_id, + initial_shared_version: counter_initial_shared_version, + mutable: true, + })], + ) + } + + pub fn call_nft_create(self, package_id: ObjectID) -> Self { + self.move_call( + package_id, + "devnet_nft", + "mint", + vec![ + CallArg::Pure(bcs::to_bytes("example_nft_name").unwrap()), + CallArg::Pure(bcs::to_bytes("example_nft_description").unwrap()), + CallArg::Pure( + bcs::to_bytes("https://iota.io/_nuxt/img/iota-logo.8d3c44e.svg").unwrap(), + ), + ], + ) + } + + pub fn call_nft_delete(self, package_id: ObjectID, nft_to_delete: ObjectRef) -> Self { + self.move_call( + package_id, + "devnet_nft", + "burn", + vec![CallArg::Object(ObjectArg::ImmOrOwnedObject(nft_to_delete))], + ) + } + + pub fn call_staking(self, stake_coin: ObjectRef, validator: IotaAddress) -> Self { + self.move_call( + IOTA_SYSTEM_PACKAGE_ID, + IOTA_SYSTEM_MODULE_NAME.as_str(), + "request_add_stake", + vec![ + CallArg::IOTA_SYSTEM_MUT, + CallArg::Object(ObjectArg::ImmOrOwnedObject(stake_coin)), + CallArg::Pure(bcs::to_bytes(&validator).unwrap()), + ], + ) + } + + pub fn call_request_add_validator(self) -> Self { + self.move_call( + IOTA_SYSTEM_PACKAGE_ID, + IOTA_SYSTEM_MODULE_NAME.as_str(), + "request_add_validator", + vec![CallArg::IOTA_SYSTEM_MUT], + ) + } + + pub fn call_request_add_validator_candidate( + self, + validator: &GenesisValidatorMetadata, + ) -> Self { + self.move_call( + IOTA_SYSTEM_PACKAGE_ID, + IOTA_SYSTEM_MODULE_NAME.as_str(), + "request_add_validator_candidate", + vec![ + CallArg::IOTA_SYSTEM_MUT, + CallArg::Pure(bcs::to_bytes(&validator.protocol_public_key).unwrap()), + CallArg::Pure(bcs::to_bytes(&validator.network_public_key).unwrap()), + CallArg::Pure(bcs::to_bytes(&validator.worker_public_key).unwrap()), + CallArg::Pure(bcs::to_bytes(&validator.proof_of_possession).unwrap()), + CallArg::Pure(bcs::to_bytes(validator.name.as_bytes()).unwrap()), + CallArg::Pure(bcs::to_bytes(validator.description.as_bytes()).unwrap()), + CallArg::Pure(bcs::to_bytes(validator.image_url.as_bytes()).unwrap()), + CallArg::Pure(bcs::to_bytes(validator.project_url.as_bytes()).unwrap()), + CallArg::Pure(bcs::to_bytes(&validator.network_address).unwrap()), + CallArg::Pure(bcs::to_bytes(&validator.p2p_address).unwrap()), + CallArg::Pure(bcs::to_bytes(&validator.primary_address).unwrap()), + CallArg::Pure(bcs::to_bytes(&validator.worker_address).unwrap()), + CallArg::Pure(bcs::to_bytes(&DEFAULT_VALIDATOR_GAS_PRICE).unwrap()), // gas_price + CallArg::Pure(bcs::to_bytes(&0u64).unwrap()), // commission_rate + ], + ) + } + + pub fn call_request_remove_validator(self) -> Self { + self.move_call( + IOTA_SYSTEM_PACKAGE_ID, + IOTA_SYSTEM_MODULE_NAME.as_str(), + "request_remove_validator", + vec![CallArg::IOTA_SYSTEM_MUT], + ) + } + + pub fn transfer(mut self, object: ObjectRef, recipient: IotaAddress) -> Self { + self.test_data = TestTransactionData::Transfer(TransferData { object, recipient }); + self + } + + pub fn transfer_iota(mut self, amount: Option, recipient: IotaAddress) -> Self { + self.test_data = TestTransactionData::TransferIota(TransferIotaData { amount, recipient }); + self + } + + pub fn publish(mut self, path: PathBuf) -> Self { + assert!(matches!(self.test_data, TestTransactionData::Empty)); + self.test_data = TestTransactionData::Publish(PublishData::Source(path, false)); + self + } + + pub fn publish_with_deps(mut self, path: PathBuf) -> Self { + assert!(matches!(self.test_data, TestTransactionData::Empty)); + self.test_data = TestTransactionData::Publish(PublishData::Source(path, true)); + self + } + + pub fn publish_with_data(mut self, data: PublishData) -> Self { + assert!(matches!(self.test_data, TestTransactionData::Empty)); + self.test_data = TestTransactionData::Publish(data); + self + } + + pub fn publish_examples(self, subpath: &'static str) -> Self { + let path = if let Ok(p) = std::env::var("MOVE_EXAMPLES_DIR") { + let mut path = PathBuf::from(p); + path.extend([subpath]); + path + } else { + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.extend(["..", "..", "iota_programmability", "examples", subpath]); + path + }; + self.publish(path) + } + + pub fn programmable(mut self, programmable: ProgrammableTransaction) -> Self { + self.test_data = TestTransactionData::Programmable(programmable); + self + } + + pub fn build(self) -> TransactionData { + match self.test_data { + TestTransactionData::Move(data) => TransactionData::new_move_call( + self.sender, + data.package_id, + ident_str!(data.module).to_owned(), + ident_str!(data.function).to_owned(), + data.type_args, + self.gas_object, + data.args, + self.gas_price * TEST_ONLY_GAS_UNIT_FOR_HEAVY_COMPUTATION_STORAGE, + self.gas_price, + ) + .unwrap(), + TestTransactionData::Transfer(data) => TransactionData::new_transfer( + data.recipient, + data.object, + self.sender, + self.gas_object, + self.gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, + self.gas_price, + ), + TestTransactionData::TransferIota(data) => TransactionData::new_transfer_iota( + data.recipient, + self.sender, + data.amount, + self.gas_object, + self.gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, + self.gas_price, + ), + TestTransactionData::Publish(data) => { + let (all_module_bytes, dependencies) = match data { + PublishData::Source(path, with_unpublished_deps) => { + let compiled_package = BuildConfig::new_for_testing().build(path).unwrap(); + let all_module_bytes = + compiled_package.get_package_bytes(with_unpublished_deps); + let dependencies = compiled_package.get_dependency_original_package_ids(); + (all_module_bytes, dependencies) + } + PublishData::ModuleBytes(bytecode) => (bytecode, vec![]), + PublishData::CompiledPackage(compiled_package) => { + let all_module_bytes = compiled_package.get_package_bytes(false); + let dependencies = compiled_package.get_dependency_original_package_ids(); + (all_module_bytes, dependencies) + } + }; + + TransactionData::new_module( + self.sender, + self.gas_object, + all_module_bytes, + dependencies, + self.gas_price * TEST_ONLY_GAS_UNIT_FOR_HEAVY_COMPUTATION_STORAGE, + self.gas_price, + ) + } + TestTransactionData::Programmable(pt) => TransactionData::new_programmable( + self.sender, + vec![self.gas_object], + pt, + self.gas_price * TEST_ONLY_GAS_UNIT_FOR_HEAVY_COMPUTATION_STORAGE, + self.gas_price, + ), + TestTransactionData::Empty => { + panic!("Cannot build empty transaction"); + } + } + } + + pub fn build_and_sign(self, signer: &dyn Signer) -> Transaction { + Transaction::from_data_and_signer(self.build(), vec![signer]) + } + + pub fn build_and_sign_multisig( + self, + multisig_pk: MultiSigPublicKey, + signers: &[&dyn Signer], + bitmap: BitmapUnit, + ) -> Transaction { + let data = self.build(); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), data.clone()); + + let mut signatures = Vec::with_capacity(signers.len()); + for signer in signers { + signatures.push( + GenericSignature::from(Signature::new_secure(&intent_msg, *signer)) + .to_compressed() + .unwrap(), + ); + } + + let multisig = + GenericSignature::MultiSig(MultiSig::insecure_new(signatures, bitmap, multisig_pk)); + + Transaction::from_generic_sig_data(data, vec![multisig]) + } + + pub fn build_and_sign_multisig_legacy( + self, + multisig_pk: MultiSigPublicKeyLegacy, + signers: &[&dyn Signer], + ) -> Transaction { + let data = self.build(); + let intent = Intent::iota_transaction(); + let intent_msg = IntentMessage::new(intent.clone(), data.clone()); + + let mut signatures = Vec::with_capacity(signers.len()); + for signer in signers { + signatures.push(Signature::new_secure(&intent_msg, *signer).into()); + } + + let multisig = GenericSignature::MultiSigLegacy( + MultiSigLegacy::combine(signatures, multisig_pk).unwrap(), + ); + + Transaction::from_generic_sig_data(data, vec![multisig]) + } +} + +enum TestTransactionData { + Move(MoveData), + Transfer(TransferData), + TransferIota(TransferIotaData), + Publish(PublishData), + Programmable(ProgrammableTransaction), + Empty, +} + +struct MoveData { + package_id: ObjectID, + module: &'static str, + function: &'static str, + args: Vec, + type_args: Vec, +} + +pub enum PublishData { + /// Path to source code directory and with_unpublished_deps. + /// with_unpublished_deps indicates whether to publish unpublished + /// dependencies in the same transaction or not. + Source(PathBuf, bool), + ModuleBytes(Vec>), + CompiledPackage(CompiledPackage), +} + +struct TransferData { + object: ObjectRef, + recipient: IotaAddress, +} + +struct TransferIotaData { + amount: Option, + recipient: IotaAddress, +} + +/// A helper function to make Transactions with controlled accounts in +/// WalletContext. Particularly, the wallet needs to own gas objects for +/// transactions. However, if this function is called multiple times without any +/// "sync" actions on gas object management, txns may fail and objects may be +/// locked. +/// +/// The param is called `max_txn_num` because it does not always return the +/// exact same amount of Transactions, for example when there are not enough gas +/// objects controlled by the WalletContext. Caller should rely on the return +/// value to check the count. +pub async fn batch_make_transfer_transactions( + context: &WalletContext, + max_txn_num: usize, +) -> Vec { + let recipient = get_key_pair::().0; + let accounts_and_objs = context.get_all_accounts_and_gas_objects().await.unwrap(); + let mut res = Vec::with_capacity(max_txn_num); + + let gas_price = context.get_reference_gas_price().await.unwrap(); + for (address, objs) in accounts_and_objs { + for obj in objs { + if res.len() >= max_txn_num { + return res; + } + let data = TransactionData::new_transfer_iota( + recipient, + address, + Some(2), + obj, + gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, + gas_price, + ); + let tx = context.sign_transaction(&data); + res.push(tx); + } + } + res +} + +pub async fn make_transfer_iota_transaction( + context: &WalletContext, + recipient: Option, + amount: Option, +) -> Transaction { + let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); + let gas_price = context.get_reference_gas_price().await.unwrap(); + context.sign_transaction( + &TestTransactionBuilder::new(sender, gas_object, gas_price) + .transfer_iota(amount, recipient.unwrap_or(sender)) + .build(), + ) +} + +pub async fn make_staking_transaction( + context: &WalletContext, + validator_address: IotaAddress, +) -> Transaction { + let accounts_and_objs = context.get_all_accounts_and_gas_objects().await.unwrap(); + let sender = accounts_and_objs[0].0; + let gas_object = accounts_and_objs[0].1[0]; + let stake_object = accounts_and_objs[0].1[1]; + let gas_price = context.get_reference_gas_price().await.unwrap(); + context.sign_transaction( + &TestTransactionBuilder::new(sender, gas_object, gas_price) + .call_staking(stake_object, validator_address) + .build(), + ) +} + +pub async fn make_publish_transaction(context: &WalletContext, path: PathBuf) -> Transaction { + let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); + let gas_price = context.get_reference_gas_price().await.unwrap(); + context.sign_transaction( + &TestTransactionBuilder::new(sender, gas_object, gas_price) + .publish(path) + .build(), + ) +} + +pub async fn make_publish_transaction_with_deps( + context: &WalletContext, + path: PathBuf, +) -> Transaction { + let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); + let gas_price = context.get_reference_gas_price().await.unwrap(); + context.sign_transaction( + &TestTransactionBuilder::new(sender, gas_object, gas_price) + .publish_with_deps(path) + .build(), + ) +} + +pub async fn publish_package(context: &WalletContext, path: PathBuf) -> ObjectRef { + let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); + let gas_price = context.get_reference_gas_price().await.unwrap(); + let txn = context.sign_transaction( + &TestTransactionBuilder::new(sender, gas_object, gas_price) + .publish(path) + .build(), + ); + let resp = context.execute_transaction_must_succeed(txn).await; + get_new_package_obj_from_response(&resp).unwrap() +} + +/// Executes a transaction to publish the `basics` package and returns the +/// package object ref. +pub async fn publish_basics_package(context: &WalletContext) -> ObjectRef { + let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); + let gas_price = context.get_reference_gas_price().await.unwrap(); + let txn = context.sign_transaction( + &TestTransactionBuilder::new(sender, gas_object, gas_price) + .publish_examples("basics") + .build(), + ); + let resp = context.execute_transaction_must_succeed(txn).await; + get_new_package_obj_from_response(&resp).unwrap() +} + +/// Executes a transaction to publish the `basics` package and another one to +/// create a counter. Returns the package object ref and the counter object ref. +pub async fn publish_basics_package_and_make_counter( + context: &WalletContext, +) -> (ObjectRef, ObjectRef) { + let package_ref = publish_basics_package(context).await; + let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); + let gas_price = context.get_reference_gas_price().await.unwrap(); + let counter_creation_txn = context.sign_transaction( + &TestTransactionBuilder::new(sender, gas_object, gas_price) + .call_counter_create(package_ref.0) + .build(), + ); + let resp = context + .execute_transaction_must_succeed(counter_creation_txn) + .await; + let counter_ref = resp + .effects + .unwrap() + .created() + .iter() + .find(|obj_ref| matches!(obj_ref.owner, Owner::Shared { .. })) + .unwrap() + .reference + .to_object_ref(); + (package_ref, counter_ref) +} + +/// Executes a transaction to increment a counter object. +/// Must be called after calling `publish_basics_package_and_make_counter`. +pub async fn increment_counter( + context: &WalletContext, + sender: IotaAddress, + gas_object_id: Option, + package_id: ObjectID, + counter_id: ObjectID, + initial_shared_version: SequenceNumber, +) -> IotaTransactionBlockResponse { + let gas_object = if let Some(gas_object_id) = gas_object_id { + context.get_object_ref(gas_object_id).await.unwrap() + } else { + context + .get_one_gas_object_owned_by_address(sender) + .await + .unwrap() + .unwrap() + }; + let rgp = context.get_reference_gas_price().await.unwrap(); + let txn = context.sign_transaction( + &TestTransactionBuilder::new(sender, gas_object, rgp) + .call_counter_increment(package_id, counter_id, initial_shared_version) + .build(), + ); + context.execute_transaction_must_succeed(txn).await +} + +/// Executes a transaction to publish the `nfts` package and returns the package +/// id, id of the gas object used, and the digest of the transaction. +pub async fn publish_nfts_package( + context: &WalletContext, +) -> (ObjectID, ObjectID, TransactionDigest) { + let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); + let gas_id = gas_object.0; + let gas_price = context.get_reference_gas_price().await.unwrap(); + let txn = context.sign_transaction( + &TestTransactionBuilder::new(sender, gas_object, gas_price) + .publish_examples("nfts") + .build(), + ); + let resp = context.execute_transaction_must_succeed(txn).await; + let package_id = get_new_package_obj_from_response(&resp).unwrap().0; + (package_id, gas_id, resp.digest) +} + +/// Pre-requisite: `publish_nfts_package` must be called before this function. +/// Executes a transaction to create an NFT and returns the sender address, the +/// object id of the NFT, and the digest of the transaction. +pub async fn create_devnet_nft( + context: &WalletContext, + package_id: ObjectID, +) -> (IotaAddress, ObjectID, TransactionDigest) { + let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); + let rgp = context.get_reference_gas_price().await.unwrap(); + + let txn = context.sign_transaction( + &TestTransactionBuilder::new(sender, gas_object, rgp) + .call_nft_create(package_id) + .build(), + ); + let resp = context.execute_transaction_must_succeed(txn).await; + + let object_id = resp + .effects + .as_ref() + .unwrap() + .created() + .first() + .unwrap() + .reference + .object_id; + + (sender, object_id, resp.digest) +} + +/// Executes a transaction to delete the given NFT. +pub async fn delete_devnet_nft( + context: &WalletContext, + sender: IotaAddress, + package_id: ObjectID, + nft_to_delete: ObjectRef, +) -> IotaTransactionBlockResponse { + let gas = context + .get_one_gas_object_owned_by_address(sender) + .await + .unwrap() + .unwrap_or_else(|| panic!("Expect {sender} to have at least one gas object")); + let rgp = context.get_reference_gas_price().await.unwrap(); + let txn = context.sign_transaction( + &TestTransactionBuilder::new(sender, gas, rgp) + .call_nft_delete(package_id, nft_to_delete) + .build(), + ); + context.execute_transaction_must_succeed(txn).await +} diff --git a/crates/iota-test-validator/Cargo.toml b/crates/iota-test-validator/Cargo.toml new file mode 100644 index 00000000000..d6c5d9941e6 --- /dev/null +++ b/crates/iota-test-validator/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "iota-test-validator" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +clap.workspace = true +tokio = { workspace = true, features = ["full"] } +axum.workspace = true +tower.workspace = true +tower-http.workspace = true +http.workspace = true +uuid.workspace = true + +iota-faucet.workspace = true +iota-cluster-test.workspace = true +telemetry-subscribers.workspace = true diff --git a/crates/iota-test-validator/README.md b/crates/iota-test-validator/README.md new file mode 100644 index 00000000000..8cd528eddd4 --- /dev/null +++ b/crates/iota-test-validator/README.md @@ -0,0 +1,21 @@ +The iota-test-validator starts a local network that includes a Iota Full node, a Iota validator, a Iota faucet and (optionally) +an indexer. + +## Guide + +Refer to [iota-local-network.md](../../docs/content/guides/developer/getting-started/local-network.mdx) + +## Experimental Feature - Running with Indexer + +**Note** Similar to the fullnode db, all state will be wiped upon restart + +1. Follow the [Prerequisites section](../../crates/iota-indexer/README.md#prerequisites) in the `iota-indexer` README to set up the postgresdb on your local machine +2. Make sure the `Posgresdb` starts on your local machine +3. run `RUST_LOG="consensus=off" ./target/debug/iota-test-validator --with-indexer` +4. To check your local db, if you use the default db url `postgres://postgres:postgres@localhost:5432/iota_indexer`, you can login to the `postgres` database and run `\dt` to show all tables. + +## Run with a persisted state +You can combine this with indexer runs as well to save a persisted state on local development. + +1. Generate a config to store db and genesis configs `iota genesis -f --with-faucet --working-dir=[some-directory]` +2. `iota-test-validator --config-dir [some-directory]` diff --git a/crates/iota-test-validator/src/main.rs b/crates/iota-test-validator/src/main.rs new file mode 100644 index 00000000000..48b86e86425 --- /dev/null +++ b/crates/iota-test-validator/src/main.rs @@ -0,0 +1,266 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{net::SocketAddr, sync::Arc}; + +use anyhow::Result; +use axum::{ + extract::Path, + response::IntoResponse, + routing::{get, post}, + Extension, Json, Router, +}; +use clap::Parser; +use http::{Method, StatusCode}; +use iota_cluster_test::{ + cluster::{Cluster, LocalNewCluster}, + config::{ClusterTestOpt, Env}, + faucet::{FaucetClient, FaucetClientFactory}, +}; +use iota_faucet::{ + BatchFaucetResponse, BatchStatusFaucetResponse, FaucetError, FaucetRequest, FaucetResponse, + FixedAmountRequest, +}; +use tower::ServiceBuilder; +use tower_http::cors::{Any, CorsLayer}; +use uuid::Uuid; + +/// Start a Iota validator and fullnode for easy testing. +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +struct Args { + /// Config directory that will be used to store network config, node db, + /// keystore iota genesis -f --with-faucet generates a genesis config + /// that can be used to start this process. Example: iota-test-validator + /// --config-dir ~/.iota/iota_config We can use any config dir that is + /// generated by the iota genesis. + #[clap(short, long)] + config_dir: Option, + /// Port to start the Fullnode RPC server on + #[clap(long, default_value = "9000")] + fullnode_rpc_port: u16, + + /// Port to start the Iota faucet on + #[clap(long, default_value = "9123")] + faucet_port: u16, + + /// Host to start the GraphQl server on + #[clap(long, default_value = "127.0.0.1")] + graphql_host: String, + + /// Port to start the GraphQl server on + /// Explicitly setting this enables the server + #[clap(long)] + graphql_port: Option, + + /// Port to start the Indexer RPC server on + #[clap(long, default_value = "9124")] + indexer_rpc_port: u16, + + /// Port for the Indexer Postgres DB + /// 5432 is the default port for postgres on Mac + #[clap(long, default_value = "5432")] + pg_port: u16, + + /// Hostname for the Indexer Postgres DB + #[clap(long, default_value = "localhost")] + pg_host: String, + + /// DB name for the Indexer Postgres DB + #[clap(long, default_value = "iota_indexer")] + pg_db_name: String, + + /// DB username for the Indexer Postgres DB + #[clap(long, default_value = "postgres")] + pg_user: String, + + /// DB password for the Indexer Postgres DB + #[clap(long, default_value = "postgrespw")] + pg_password: String, + + /// The duration for epochs (defaults to one minute) + #[clap(long, default_value = "60000")] + epoch_duration_ms: u64, + + /// if we should run indexer + #[clap(long)] + pub with_indexer: bool, +} + +#[tokio::main] +async fn main() -> Result<()> { + let (_guard, _filter_handle) = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .init(); + + let args = Args::parse(); + let Args { + config_dir, + fullnode_rpc_port, + graphql_host, + graphql_port, + indexer_rpc_port, + pg_port, + pg_host, + pg_db_name, + pg_user, + pg_password, + epoch_duration_ms, + faucet_port, + with_indexer, + } = args; + + // We don't pass epoch duration if we have a genesis config. + let epoch_duration_ms = if config_dir.is_some() { + None + } else { + Some(epoch_duration_ms) + }; + + if graphql_port.is_none() { + println!("Graphql port not provided. Graphql service will not run.") + } + if !with_indexer { + println!("`with_indexer` flag unset. Indexer service will not run.") + } + + let cluster_config = ClusterTestOpt { + env: Env::NewLocal, + + fullnode_address: Some(format!("0.0.0.0:{}", fullnode_rpc_port)), + indexer_address: with_indexer.then_some(format!("0.0.0.0:{}", indexer_rpc_port)), + pg_address: Some(format!( + "postgres://{pg_user}:{pg_password}@{pg_host}:{pg_port}/{pg_db_name}" + )), + faucet_address: Some(format!("127.0.0.1:{}", faucet_port)), + epoch_duration_ms, + config_dir, + graphql_address: graphql_port.map(|p| format!("{}:{}", graphql_host, p)), + }; + + println!("Starting Iota validator with config: {:#?}", cluster_config); + let cluster = LocalNewCluster::start(&cluster_config).await?; + + println!("Fullnode RPC URL: {}", cluster.fullnode_url()); + + if with_indexer { + println!( + "Indexer RPC URL: {}", + cluster.indexer_url().clone().unwrap_or_default() + ); + } + + start_faucet(&cluster, faucet_port).await?; + + Ok(()) +} + +struct AppState { + faucet: Arc, +} + +async fn start_faucet(cluster: &LocalNewCluster, port: u16) -> Result<()> { + let faucet = FaucetClientFactory::new_from_cluster(cluster).await; + + let app_state = Arc::new(AppState { faucet }); + + let cors = CorsLayer::new() + .allow_methods(vec![Method::GET, Method::POST]) + .allow_headers(Any) + .allow_origin(Any); + + let app = Router::new() + .route("/", get(health)) + .route("/gas", post(faucet_request)) + .route("/v1/gas", post(faucet_batch_request)) + .route("/v1/status/:task_id", get(request_status)) + .layer( + ServiceBuilder::new() + .layer(cors) + .layer(Extension(app_state)) + .into_inner(), + ); + + let addr = SocketAddr::from(([0, 0, 0, 0], port)); + + println!("Faucet URL: http://{}", addr); + + axum::Server::bind(&addr) + .serve(app.into_make_service()) + .await?; + + Ok(()) +} + +/// basic handler that responds with a static string +async fn health() -> &'static str { + "OK" +} + +async fn faucet_request( + Extension(state): Extension>, + Json(payload): Json, +) -> impl IntoResponse { + let result = match payload { + FaucetRequest::FixedAmountRequest(FixedAmountRequest { recipient }) => { + state.faucet.request_iota_coins(recipient).await + } + _ => { + return ( + StatusCode::BAD_REQUEST, + Json(FaucetResponse::from(FaucetError::Internal( + "Input Error.".to_string(), + ))), + ); + } + }; + + if !result.transferred_gas_objects.is_empty() { + (StatusCode::CREATED, Json(result)) + } else { + (StatusCode::INTERNAL_SERVER_ERROR, Json(result)) + } +} + +async fn faucet_batch_request( + Extension(state): Extension>, + Json(payload): Json, +) -> impl IntoResponse { + let result = match payload { + FaucetRequest::FixedAmountRequest(FixedAmountRequest { recipient }) => { + state.faucet.batch_request_iota_coins(recipient).await + } + _ => { + return ( + StatusCode::BAD_REQUEST, + Json(BatchFaucetResponse::from(FaucetError::Internal( + "Input Error.".to_string(), + ))), + ); + } + }; + if result.task.is_some() { + (StatusCode::CREATED, Json(result)) + } else { + (StatusCode::INTERNAL_SERVER_ERROR, Json(result)) + } +} + +async fn request_status( + Extension(state): Extension>, + Path(id): Path, +) -> impl IntoResponse { + match Uuid::parse_str(&id) { + Ok(task_id) => { + let status = state.faucet.get_batch_send_status(task_id).await; + (StatusCode::CREATED, Json(status)) + } + Err(e) => ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(BatchStatusFaucetResponse::from(FaucetError::Internal( + e.to_string(), + ))), + ), + } +} diff --git a/crates/iota-tls/Cargo.toml b/crates/iota-tls/Cargo.toml new file mode 100644 index 00000000000..d0c8a53f371 --- /dev/null +++ b/crates/iota-tls/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "iota-tls" +version = "0.0.0" +license = "Apache-2.0" +authors = ["Brandon Williams "] +description = "tools for rustls-based certificate generation and verification" +edition = "2021" +publish = false + +[dependencies] +anyhow.workspace = true +ed25519.workspace = true +pkcs8.workspace = true +rcgen.workspace = true +rustls.workspace = true +webpki.workspace = true +x509-parser.workspace = true + +fastcrypto.workspace = true + +# reqwest support +reqwest.workspace = true + +# Axum support +axum.workspace = true +axum-server.workspace = true +tokio-rustls.workspace = true +tower-layer.workspace = true +tokio.workspace = true + +[dev-dependencies] +rand.workspace = true diff --git a/crates/sui-tls/src/acceptor.rs b/crates/iota-tls/src/acceptor.rs similarity index 98% rename from crates/sui-tls/src/acceptor.rs rename to crates/iota-tls/src/acceptor.rs index 41f0cfd930b..c6d3971cf41 100644 --- a/crates/sui-tls/src/acceptor.rs +++ b/crates/iota-tls/src/acceptor.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{io, sync::Arc}; diff --git a/crates/sui-tls/src/certgen.rs b/crates/iota-tls/src/certgen.rs similarity index 98% rename from crates/sui-tls/src/certgen.rs rename to crates/iota-tls/src/certgen.rs index 80f8c8d4944..06485d04566 100644 --- a/crates/sui-tls/src/certgen.rs +++ b/crates/iota-tls/src/certgen.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use fastcrypto::ed25519::{Ed25519PrivateKey, Ed25519PublicKey}; diff --git a/crates/iota-tls/src/lib.rs b/crates/iota-tls/src/lib.rs new file mode 100644 index 00000000000..d7e66f80261 --- /dev/null +++ b/crates/iota-tls/src/lib.rs @@ -0,0 +1,188 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod acceptor; +mod certgen; +mod verifier; + +pub const IOTA_VALIDATOR_SERVER_NAME: &str = "iota"; + +pub use acceptor::{TlsAcceptor, TlsConnectionInfo}; +pub use certgen::SelfSignedCertificate; +pub use rustls; +pub use verifier::{AllowAll, Allower, CertVerifier, HashSetAllow, ValidatorAllowlist}; + +#[cfg(test)] +mod tests { + use fastcrypto::{ed25519::Ed25519KeyPair, traits::KeyPair}; + use rustls::server::ClientCertVerifier; + + use super::*; + + #[test] + fn verify_allowall() { + let mut rng = rand::thread_rng(); + let allowed = Ed25519KeyPair::generate(&mut rng); + let disallowed = Ed25519KeyPair::generate(&mut rng); + let random_cert_bob = + SelfSignedCertificate::new(allowed.private(), IOTA_VALIDATOR_SERVER_NAME); + let random_cert_alice = + SelfSignedCertificate::new(disallowed.private(), IOTA_VALIDATOR_SERVER_NAME); + + let verifier = CertVerifier::new(AllowAll); + + // The bob passes validation + verifier + .verify_client_cert( + &random_cert_bob.rustls_certificate(), + &[], + std::time::SystemTime::now(), + ) + .unwrap(); + + // The alice passes validation + verifier + .verify_client_cert( + &random_cert_alice.rustls_certificate(), + &[], + std::time::SystemTime::now(), + ) + .unwrap(); + } + + #[test] + fn verify_hashset() { + let mut rng = rand::thread_rng(); + let allowed = Ed25519KeyPair::generate(&mut rng); + let disallowed = Ed25519KeyPair::generate(&mut rng); + + let allowed_public_key = allowed.public().to_owned(); + let allowed_cert = + SelfSignedCertificate::new(allowed.private(), IOTA_VALIDATOR_SERVER_NAME); + + let disallowed_cert = + SelfSignedCertificate::new(disallowed.private(), IOTA_VALIDATOR_SERVER_NAME); + + let mut allowlist = HashSetAllow::new(); + let verifier = CertVerifier::new(allowlist.clone()); + + // Add our public key to the allower + allowlist + .inner_mut() + .write() + .unwrap() + .insert(allowed_public_key); + + // The allowed cert passes validation + verifier + .verify_client_cert( + &allowed_cert.rustls_certificate(), + &[], + std::time::SystemTime::now(), + ) + .unwrap(); + + // The disallowed cert fails validation + verifier + .verify_client_cert( + &disallowed_cert.rustls_certificate(), + &[], + std::time::SystemTime::now(), + ) + .unwrap_err(); + + // After removing the allowed public key from the set it now fails validation + allowlist.inner_mut().write().unwrap().clear(); + verifier + .verify_client_cert( + &allowed_cert.rustls_certificate(), + &[], + std::time::SystemTime::now(), + ) + .unwrap_err(); + } + + #[test] + fn invalid_server_name() { + let mut rng = rand::thread_rng(); + let keypair = Ed25519KeyPair::generate(&mut rng); + let public_key = keypair.public().to_owned(); + let cert = SelfSignedCertificate::new(keypair.private(), "not-iota"); + + let mut allowlist = HashSetAllow::new(); + let verifier = CertVerifier::new(allowlist.clone()); + + // Add our public key to the allower + allowlist.inner_mut().write().unwrap().insert(public_key); + + // Allowed public key but the server-name in the cert is not the required "iota" + verifier + .verify_client_cert( + &cert.rustls_certificate(), + &[], + std::time::SystemTime::now(), + ) + .unwrap_err(); + } + + #[tokio::test] + async fn axum_acceptor() { + use fastcrypto::{ed25519::Ed25519KeyPair, traits::KeyPair}; + + let mut rng = rand::thread_rng(); + let client_keypair = Ed25519KeyPair::generate(&mut rng); + let client_public_key = client_keypair.public().to_owned(); + let client_certificate = + SelfSignedCertificate::new(client_keypair.private(), IOTA_VALIDATOR_SERVER_NAME); + let server_keypair = Ed25519KeyPair::generate(&mut rng); + let server_certificate = SelfSignedCertificate::new(server_keypair.private(), "localhost"); + + let client = reqwest::Client::builder() + .add_root_certificate(server_certificate.reqwest_certificate()) + .identity(client_certificate.reqwest_identity()) + .https_only(true) + .build() + .unwrap(); + + let mut allowlist = HashSetAllow::new(); + let tls_config = CertVerifier::new(allowlist.clone()) + .rustls_server_config( + vec![server_certificate.rustls_certificate()], + server_certificate.rustls_private_key(), + ) + .unwrap(); + + async fn handler(tls_info: axum::Extension) -> String { + tls_info.public_key().unwrap().to_string() + } + + let app = axum::Router::new().route("/", axum::routing::get(handler)); + let listener = std::net::TcpListener::bind("localhost:0").unwrap(); + let server_address = listener.local_addr().unwrap(); + let acceptor = TlsAcceptor::new(tls_config); + let _server = tokio::spawn(async move { + axum_server::Server::from_tcp(listener) + .acceptor(acceptor) + .serve(app.into_make_service()) + .await + .unwrap() + }); + + let server_url = format!("https://localhost:{}", server_address.port()); + // Client request is rejected because it isn't in the allowlist + client.get(&server_url).send().await.unwrap_err(); + + // Insert the client's public key into the allowlist and verify the request is + // successful + allowlist + .inner_mut() + .write() + .unwrap() + .insert(client_public_key.clone()); + + let res = client.get(&server_url).send().await.unwrap(); + let body = res.text().await.unwrap(); + assert_eq!(client_public_key.to_string(), body); + } +} diff --git a/crates/iota-tls/src/verifier.rs b/crates/iota-tls/src/verifier.rs new file mode 100644 index 00000000000..075c7bb80f1 --- /dev/null +++ b/crates/iota-tls/src/verifier.rs @@ -0,0 +1,212 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::HashSet, + sync::{Arc, RwLock}, +}; + +use fastcrypto::{ed25519::Ed25519PublicKey, traits::ToFromBytes}; + +static SUPPORTED_SIG_ALGS: &[&webpki::SignatureAlgorithm] = &[&webpki::ED25519]; + +pub type ValidatorAllowlist = Arc>>; + +/// The Allower trait provides an interface for callers to inject decsions +/// whether to allow a cert to be verified or not. This does not prform actual +/// cert validation it only acts as a gatekeeper to decide if we should even +/// try. For example, we may want to filter our actions to well known public +/// keys. +pub trait Allower: Send + Sync { + fn allowed(&self, key: &Ed25519PublicKey) -> bool; +} + +/// AllowAll will allow all public certificates to be validated, it fails open +#[derive(Clone, Default)] +pub struct AllowAll; + +impl Allower for AllowAll { + fn allowed(&self, _: &Ed25519PublicKey) -> bool { + true + } +} + +/// HashSetAllow restricts keys to those that are found in the member set. +/// non-members will not be allowed. +#[derive(Clone, Default)] +pub struct HashSetAllow { + inner: ValidatorAllowlist, +} + +impl HashSetAllow { + pub fn new() -> Self { + let inner = Arc::new(RwLock::new(HashSet::new())); + Self { inner } + } + /// Get a reference to the inner service + pub fn inner(&self) -> &ValidatorAllowlist { + &self.inner + } + + /// Get a mutable reference to the inner service + pub fn inner_mut(&mut self) -> &mut ValidatorAllowlist { + &mut self.inner + } +} + +impl Allower for HashSetAllow { + fn allowed(&self, key: &Ed25519PublicKey) -> bool { + self.inner.read().unwrap().contains(key) + } +} + +/// A `rustls::server::ClientCertVerifier` that will ensure that every client +/// provides a valid, expected certificate and that the client's public key is +/// in the validator set. +#[derive(Clone, Debug)] +pub struct CertVerifier { + allower: A, +} + +impl CertVerifier { + pub fn new(allower: A) -> Self { + Self { allower } + } +} + +impl CertVerifier { + pub fn rustls_server_config( + self, + certificates: Vec, + private_key: rustls::PrivateKey, + ) -> Result { + let mut config = rustls::ServerConfig::builder() + .with_safe_defaults() + .with_client_cert_verifier(std::sync::Arc::new(self)) + .with_single_cert(certificates, private_key)?; + config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; + + Ok(config) + } +} + +impl rustls::server::ClientCertVerifier for CertVerifier { + fn offer_client_auth(&self) -> bool { + true + } + + fn client_auth_mandatory(&self) -> bool { + true + } + + fn client_auth_root_subjects(&self) -> &[rustls::DistinguishedName] { + // Since we're relying on self-signed certificates and not on CAs, continue the + // handshake without passing a list of CA DNs + &[] + } + + // Verifies this is a valid ed25519 self-signed certificate + // 1. we prepare arguments for webpki's certificate verification (following the + // rustls implementation) placing the public key at the root of the + // certificate chain (as it should be for a self-signed certificate) + // 2. we call webpki's certificate verification + fn verify_client_cert( + &self, + end_entity: &rustls::Certificate, + intermediates: &[rustls::Certificate], + now: std::time::SystemTime, + ) -> Result { + // Step 1: Check this matches the key we expect + let public_key = public_key_from_certificate(end_entity)?; + + if !self.allower.allowed(&public_key) { + return Err(rustls::Error::General(format!( + "invalid certificate: {:?} is not in the validator set", + public_key, + ))); + } + + // We now check we're receiving correctly signed data with the expected key + // Step 1: prepare arguments + let (cert, chain, trustroots) = prepare_for_self_signed(end_entity, intermediates)?; + let now = webpki::Time::try_from(now).map_err(|_| rustls::Error::FailedToGetCurrentTime)?; + + // Step 2: call verification from webpki + let cert = cert + .verify_for_usage( + SUPPORTED_SIG_ALGS, + &trustroots, + &chain, + now, + webpki::KeyUsage::client_auth(), + &[], + ) + .map_err(pki_error) + .map(|_| cert)?; + + // Ensure the cert is valid for the network name + let dns_nameref = + webpki::SubjectNameRef::try_from_ascii_str(crate::IOTA_VALIDATOR_SERVER_NAME) + .map_err(|_| rustls::Error::UnsupportedNameType)?; + cert.verify_is_valid_for_subject_name(dns_nameref) + .map_err(pki_error) + .map(|_| rustls::server::ClientCertVerified::assertion()) + } +} + +type CertChainAndRoots<'a> = ( + webpki::EndEntityCert<'a>, + Vec<&'a [u8]>, + Vec>, +); + +// This prepares arguments for webpki, including a trust anchor which is the end +// entity of the certificate (which embodies a self-signed certificate by +// definition) +fn prepare_for_self_signed<'a>( + end_entity: &'a rustls::Certificate, + intermediates: &'a [rustls::Certificate], +) -> Result, rustls::Error> { + // EE cert must appear first. + let cert = webpki::EndEntityCert::try_from(end_entity.0.as_ref()).map_err(pki_error)?; + + let intermediates: Vec<&'a [u8]> = intermediates.iter().map(|cert| cert.0.as_ref()).collect(); + + // reinterpret the certificate as a root, materializing the self-signed policy + let root = webpki::TrustAnchor::try_from_cert_der(end_entity.0.as_ref()).map_err(pki_error)?; + + Ok((cert, intermediates, vec![root])) +} + +fn pki_error(error: webpki::Error) -> rustls::Error { + use webpki::Error::*; + match error { + BadDer | BadDerTime => { + rustls::Error::InvalidCertificate(rustls::CertificateError::BadEncoding) + } + InvalidSignatureForPublicKey + | UnsupportedSignatureAlgorithm + | UnsupportedSignatureAlgorithmForPublicKey => { + rustls::Error::InvalidCertificate(rustls::CertificateError::BadSignature) + } + e => rustls::Error::General(format!("invalid peer certificate: {e}")), + } +} + +pub(crate) fn public_key_from_certificate( + certificate: &rustls::Certificate, +) -> Result { + use x509_parser::{certificate::X509Certificate, prelude::FromDer}; + + let cert = X509Certificate::from_der(certificate.0.as_ref()) + .map_err(|e| rustls::Error::General(e.to_string()))?; + let spki = cert.1.public_key(); + let public_key_bytes = + ::from_public_key_der(spki.raw) + .map_err(|e| rustls::Error::General(format!("invalid ed25519 public key: {e}")))?; + + let public_key = Ed25519PublicKey::from_bytes(public_key_bytes.as_ref()) + .map_err(|e| rustls::Error::General(format!("invalid ed25519 public key: {e}")))?; + Ok(public_key) +} diff --git a/crates/iota-tool/Cargo.toml b/crates/iota-tool/Cargo.toml new file mode 100644 index 00000000000..83efdaf80b9 --- /dev/null +++ b/crates/iota-tool/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "iota-tool" +version.workspace = true +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +num_cpus.workspace = true +bcs.workspace = true +clap = { version = "4.1.4", features = ["derive"] } +colored.workspace = true +comfy-table.workspace = true +diesel.workspace = true +eyre.workspace = true +futures.workspace = true +hex.workspace = true +move-core-types.workspace = true +itertools.workspace = true +rocksdb.workspace = true +ron.workspace = true +serde.workspace = true +serde_json.workspace = true +strum.workspace = true +strum_macros.workspace = true +tempfile.workspace = true +tracing.workspace = true +prometheus.workspace = true +object_store.workspace = true +indicatif.workspace = true + +anemo-cli.workspace = true +anemo.workspace = true +telemetry-subscribers.workspace = true +tokio = { workspace = true, features = ["full"] } +typed-store.workspace = true +fastcrypto.workspace = true + +narwhal-storage.workspace = true +narwhal-types.workspace = true +iota-config.workspace = true +iota-core.workspace = true +iota-indexer.workspace = true +iota-network.workspace = true +iota-snapshot.workspace = true +iota-protocol-config.workspace = true +iota-replay.workspace = true +iota-sdk.workspace = true +iota-storage.workspace = true +iota-types.workspace = true +iota-archival.workspace = true +git-version.workspace = true +const-str = "0.5.6" diff --git a/crates/iota-tool/README.md b/crates/iota-tool/README.md new file mode 100644 index 00000000000..50614c2f405 --- /dev/null +++ b/crates/iota-tool/README.md @@ -0,0 +1,44 @@ +# iota-tool + +`iota-tool` contains assorted debugging utilities for Iota. + +You can build and run `iota-tool` from source with: +```sh +cargo run --bin iota-tool -- +``` + +## `anemo` tools + +You can use the anemo CLI tools to ping or call an RPC on an Anemo server. Note that (for now) this uses randomly generated keys, so a server or method that restricts access to allowlisted peers will reject connections from this tool. + +Anemo networks are identified by a "server name" that the client must match. Server names you may want to use: +- Narwhal primary and worker: `narwhal` +- Iota discovery and state sync: `iota` + +### ping + +Example command to ping an anemo server: + +```sh +SERVER_NAME="iota"; \ +ADDRESS="1.2.3.4:5678"; \ +cargo run --bin iota-tool -- anemo ping --server-name "$SERVER_NAME" "$ADDRESS" +``` + +### call + +`iota-tool` has been preconfigured to support RPC calls using [RON (Rusty Object Notation)](https://crates.io/crates/ron) for the following servivces: +- Narwhal: `PrimaryToPrimary` and `WorkerToWorker` +- Iota: `Discovery` and `StateSync` + +Example command to send an RPC: + +```sh +SERVER_NAME="iota"; \ +ADDRESS="1.2.3.4:5678"; \ +SERVICE_NAME="StateSync"; \ +METHOD_NAME="GetCheckpointSummary"; \ +REQUEST="BySequenceNumber(123)"; \ +cargo run --bin iota-tool -- \ + anemo call --server-name "$SERVER_NAME" "$ADDRESS" "$SERVICE_NAME" "$METHOD_NAME" "$REQUEST" +``` diff --git a/crates/iota-tool/src/commands.rs b/crates/iota-tool/src/commands.rs new file mode 100644 index 00000000000..6511fa4f384 --- /dev/null +++ b/crates/iota-tool/src/commands.rs @@ -0,0 +1,991 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{env, path::PathBuf}; + +use anyhow::Result; +use clap::*; +use fastcrypto::encoding::Encoding; +use iota_archival::{read_manifest_as_json, write_manifest_from_json}; +use iota_config::{ + genesis::Genesis, + object_storage_config::{ObjectStoreConfig, ObjectStoreType}, + Config, +}; +use iota_core::{authority_aggregator::AuthorityAggregatorBuilder, authority_client::AuthorityAPI}; +use iota_protocol_config::Chain; +use iota_replay::{execute_replay_command, ReplayToolCommand}; +use iota_types::{ + base_types::*, + messages_checkpoint::{CheckpointRequest, CheckpointResponse, CheckpointSequenceNumber}, + object::Owner, + transaction::{SenderSignedData, Transaction}, +}; +use telemetry_subscribers::TracingHandle; + +use crate::{ + check_completed_snapshot, + db_tool::{execute_db_tool_command, print_db_all_tables, DbToolCommand}, + download_db_snapshot, download_formal_snapshot, dump_checkpoints_from_archive, + get_latest_available_epoch, get_object, get_transaction_block, make_clients, pkg_dump, + restore_from_db_checkpoint, verify_archive, verify_archive_by_checksum, ConciseObjectOutput, + GroupedObjectOutput, VerboseObjectOutput, +}; + +#[derive(Parser, Clone, ValueEnum)] +pub enum Verbosity { + Grouped, + Concise, + Verbose, +} +const GIT_REVISION: &str = { + if let Some(revision) = option_env!("GIT_REVISION") { + revision + } else { + let version = git_version::git_version!( + args = ["--always", "--abbrev=12", "--dirty", "--exclude", "*"], + fallback = "" + ); + + if version.is_empty() { + panic!("unable to query git revision"); + } + version + } +}; +const VERSION: &str = const_str::concat!(env!("CARGO_PKG_VERSION"), "-", GIT_REVISION); + +#[derive(Parser)] +#[command( + name = "iota-tool", + about = "Debugging utilities for iota", + rename_all = "kebab-case", + author, + version = VERSION, +)] +pub enum ToolCommand { + /// Fetch the same object from all validators + #[command(name = "fetch-object")] + FetchObject { + #[arg(long, help = "The object ID to fetch")] + id: ObjectID, + + #[arg(long, help = "Fetch object at a specific sequence")] + version: Option, + + #[arg( + long, + help = "Validator to fetch from - if not specified, all validators are queried" + )] + validator: Option, + + // At least one of genesis or fullnode_rpc_url must be provided + #[arg(long = "genesis")] + genesis: Option, + + // At least one of genesis or fullnode_rpc_url must be provided + // RPC address to provide the up-to-date committee info + #[arg(long = "fullnode-rpc-url")] + fullnode_rpc_url: Option, + + /// Concise mode groups responses by results. + /// prints tabular output suitable for processing with unix tools. For + /// instance, to quickly check that all validators agree on the history + /// of an object: ```text + /// $ iota-tool fetch-object --id + /// 0x260efde76ebccf57f4c5e951157f5c361cde822c \ --genesis + /// $HOME/.iota/iota_config/genesis.blob \ --verbosity + /// concise --concise-no-header ``` + #[arg( + value_enum, + long = "verbosity", + default_value = "grouped", + ignore_case = true + )] + verbosity: Verbosity, + + #[arg( + long = "concise-no-header", + help = "don't show header in concise output" + )] + concise_no_header: bool, + }, + + /// Fetch the effects association with transaction `digest` + #[command(name = "fetch-transaction")] + FetchTransaction { + // At least one of genesis or fullnode_rpc_url must be provided + #[arg(long = "genesis")] + genesis: Option, + + // At least one of genesis or fullnode_rpc_url must be provided + // RPC address to provide the up-to-date committee info + #[arg(long = "fullnode-rpc-url")] + fullnode_rpc_url: Option, + + #[arg(long, help = "The transaction ID to fetch")] + digest: TransactionDigest, + + /// If true, show the input transaction as well as the effects + #[arg(long = "show-tx")] + show_input_tx: bool, + }, + + /// Tool to read validator & node db. + #[command(name = "db-tool")] + DbTool { + /// Path of the DB to read + #[arg(long = "db-path")] + db_path: String, + #[command(subcommand)] + cmd: Option, + }, + + /// Tool to verify the archive store + #[command(name = "verify-archive")] + VerifyArchive { + #[arg(long = "genesis")] + genesis: PathBuf, + #[command(flatten)] + object_store_config: ObjectStoreConfig, + #[arg(default_value_t = 5)] + download_concurrency: usize, + }, + + /// Tool to print the archive manifest + #[command(name = "print-archive-manifest")] + PrintArchiveManifest { + #[command(flatten)] + object_store_config: ObjectStoreConfig, + }, + /// Tool to update the archive manifest + #[command(name = "update-archive-manifest")] + UpdateArchiveManifest { + #[command(flatten)] + object_store_config: ObjectStoreConfig, + #[arg(long = "archive-path")] + archive_json_path: PathBuf, + }, + /// Tool to verify the archive store by comparing file checksums + #[command(name = "verify-archive-from-checksums")] + VerifyArchiveByChecksum { + #[command(flatten)] + object_store_config: ObjectStoreConfig, + #[arg(default_value_t = 5)] + download_concurrency: usize, + }, + + /// Tool to print archive contents in checkpoint range + #[command(name = "dump-archive")] + DumpArchiveByChecksum { + #[command(flatten)] + object_store_config: ObjectStoreConfig, + #[arg(default_value_t = 0)] + start: u64, + end: u64, + #[arg(default_value_t = 80)] + max_content_length: usize, + }, + + /// Download all packages to the local filesystem from an indexer database. + /// Each package gets its own sub-directory, named for its ID on-chain, + /// containing two metadata files (linkage.json and origins.json) as + /// well as a file for every module it contains. Each module + /// file is named for its module name, with a .mv suffix, and contains Move + /// bytecode (suitable for passing into a disassembler). + #[command(name = "dump-packages")] + DumpPackages { + /// Connection information for the Indexer's Postgres DB. + #[clap(long, short)] + db_url: String, + + /// Path to a non-existent directory that can be created and filled with + /// package information. + #[clap(long, short)] + output_dir: PathBuf, + + /// If false (default), log level will be overridden to "off", and + /// output will be reduced to necessary status information. + #[clap(short, long = "verbose")] + verbose: bool, + }, + + #[command(name = "dump-validators")] + DumpValidators { + #[arg(long = "genesis")] + genesis: PathBuf, + + #[arg( + long = "concise", + help = "show concise output - name, protocol key and network address" + )] + concise: bool, + }, + + #[command(name = "dump-genesis")] + DumpGenesis { + #[arg(long = "genesis")] + genesis: PathBuf, + }, + + /// Fetch authenticated checkpoint information at a specific sequence + /// number. If sequence number is not specified, get the latest + /// authenticated checkpoint. + #[command(name = "fetch-checkpoint")] + FetchCheckpoint { + // At least one of genesis or fullnode_rpc_url must be provided + #[arg(long = "genesis")] + genesis: Option, + + // At least one of genesis or fullnode_rpc_url must be provided + // RPC address to provide the up-to-date committee info + #[arg(long = "fullnode-rpc-url")] + fullnode_rpc_url: Option, + + #[arg(long, help = "Fetch checkpoint at a specific sequence number")] + sequence_number: Option, + }, + + #[command(name = "anemo")] + Anemo { + #[command(next_help_heading = "foo", flatten)] + args: anemo_cli::Args, + }, + + #[command(name = "restore-db")] + RestoreFromDBCheckpoint { + #[arg(long = "config-path")] + config_path: PathBuf, + #[arg(long = "db-checkpoint-path")] + db_checkpoint_path: PathBuf, + }, + + #[clap( + name = "download-db-snapshot", + about = "Downloads the legacy database snapshot via cloud object store, outputs to local disk" + )] + DownloadDBSnapshot { + #[clap(long = "epoch")] + epoch: Option, + #[clap(long = "path", default_value = "/tmp")] + path: PathBuf, + /// skip downloading indexes dir + #[clap(long = "skip-indexes")] + skip_indexes: bool, + /// Number of parallel downloads to perform. Defaults to a reasonable + /// value based on number of available logical cores. + #[clap(long = "num-parallel-downloads")] + num_parallel_downloads: Option, + /// Network to download snapshot for. Defaults to "mainnet". + /// If `--snapshot-bucket` or `--archive-bucket` is not specified, + /// the value of this flag is used to construct default bucket names. + #[clap(long = "network", default_value = "mainnet")] + network: Chain, + /// Snapshot bucket name. If not specified, defaults are + /// based on value of `--network` flag. + #[clap(long = "snapshot-bucket")] + snapshot_bucket: Option, + /// Snapshot bucket type + #[clap( + long = "snapshot-bucket-type", + help = "Required if --no-sign-request is not set" + )] + snapshot_bucket_type: Option, + /// Path to snapshot directory on local filesystem. + /// Only applicable if `--snapshot-bucket-type` is "file". + #[clap( + long = "snapshot-path", + help = "only used for testing, when --snapshot-bucket-type=FILE" + )] + snapshot_path: Option, + /// If true, no authentication is needed for snapshot restores + #[clap( + long = "no-sign-request", + help = "if set, --snapshot-bucket and --snapshot-bucket-type are ignored" + )] + no_sign_request: bool, + /// Download snapshot of the latest available epoch. + /// If `--epoch` is specified, then this flag gets ignored. + #[clap(long = "latest")] + latest: bool, + /// If false (default), log level will be overridden to "off", + /// and output will be reduced to necessary status information. + #[clap(long = "verbose")] + verbose: bool, + }, + + // Restore from formal (slim, DB agnostic) snapshot. Note that this is only supported + /// for protocol versions supporting `commit_root_state_digest`. For + /// mainnet, this is epoch 20+, and for testnet this is epoch 12+ + #[clap( + name = "download-formal-snapshot", + about = "Downloads formal database snapshot via cloud object store, outputs to local disk" + )] + DownloadFormalSnapshot { + #[clap(long = "epoch")] + epoch: Option, + #[clap(long = "genesis")] + genesis: PathBuf, + #[clap(long = "path", default_value = "/tmp")] + path: PathBuf, + /// Number of parallel downloads to perform. Defaults to a reasonable + /// value based on number of available logical cores. + #[clap(long = "num-parallel-downloads")] + num_parallel_downloads: Option, + /// If true, perform snapshot and checkpoint summary verification. + /// Defaults to true. + #[clap(long = "verify")] + verify: Option, + /// Network to download snapshot for. Defaults to "mainnet". + /// If `--snapshot-bucket` or `--archive-bucket` is not specified, + /// the value of this flag is used to construct default bucket names. + #[clap(long = "network", default_value = "mainnet")] + network: Chain, + /// Snapshot bucket name. If not specified, defaults are + /// based on value of `--network` flag. + #[clap(long = "snapshot-bucket")] + snapshot_bucket: Option, + /// Snapshot bucket type + #[clap( + long = "snapshot-bucket-type", + help = "Required if --no-sign-request is not set" + )] + snapshot_bucket_type: Option, + /// Path to snapshot directory on local filesystem. + /// Only applicable if `--snapshot-bucket-type` is "file". + #[clap(long = "snapshot-path")] + snapshot_path: Option, + /// Archival bucket name. If not specified, defaults are + /// based on value of `--network` flag. + #[clap(long = "archive-bucket")] + archive_bucket: Option, + #[clap(long = "archive-bucket-type", default_value = "s3")] + archive_bucket_type: ObjectStoreType, + /// If true, no authentication is needed for snapshot restores + #[clap( + long = "no-sign-request", + help = "if set, --snapshot-bucket and --snapshot-bucket-type are ignored" + )] + no_sign_request: bool, + /// Download snapshot of the latest available epoch. + /// If `--epoch` is specified, then this flag gets ignored. + #[clap(long = "latest")] + latest: bool, + /// If false (default), log level will be overridden to "off", + /// and output will be reduced to necessary status information. + #[clap(long = "verbose")] + verbose: bool, + }, + + #[clap(name = "replay")] + Replay { + #[arg(long = "rpc")] + rpc_url: Option, + #[arg(long = "safety-checks")] + safety_checks: bool, + #[arg(long = "authority")] + use_authority: bool, + #[arg(long = "cfg-path", short)] + cfg_path: Option, + #[command(subcommand)] + cmd: ReplayToolCommand, + }, + + /// Ask all validators to sign a transaction through AuthorityAggregator. + #[command(name = "sign-transaction")] + SignTransaction { + #[arg(long = "genesis")] + genesis: PathBuf, + + #[arg( + long, + help = "The Base64-encoding of the bcs bytes of SenderSignedData" + )] + sender_signed_data: String, + }, +} + +trait OptionDebug { + fn opt_debug(&self, def_str: &str) -> String; +} +trait OptionDisplay { + fn opt_display(&self, def_str: &str) -> String; +} + +impl OptionDebug for Option +where + T: std::fmt::Debug, +{ + fn opt_debug(&self, def_str: &str) -> String { + match self { + None => def_str.to_string(), + Some(t) => format!("{:?}", t), + } + } +} + +impl OptionDisplay for Option +where + T: std::fmt::Display, +{ + fn opt_display(&self, def_str: &str) -> String { + match self { + None => def_str.to_string(), + Some(t) => format!("{}", t), + } + } +} + +struct OwnerOutput(Owner); + +// grep/awk-friendly output for Owner +impl std::fmt::Display for OwnerOutput { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.0 { + Owner::AddressOwner(address) => { + write!(f, "address({})", address) + } + Owner::ObjectOwner(address) => { + write!(f, "object({})", address) + } + Owner::Immutable => { + write!(f, "immutable") + } + Owner::Shared { .. } => { + write!(f, "shared") + } + } + } +} + +impl ToolCommand { + #[allow(clippy::format_in_format_args)] + pub async fn execute(self, tracing_handle: TracingHandle) -> Result<(), anyhow::Error> { + match self { + ToolCommand::FetchObject { + id, + validator, + genesis, + version, + fullnode_rpc_url, + verbosity, + concise_no_header, + } => { + let output = get_object(id, version, validator, genesis, fullnode_rpc_url).await?; + + match verbosity { + Verbosity::Grouped => { + println!("{}", GroupedObjectOutput(output)); + } + Verbosity::Verbose => { + println!("{}", VerboseObjectOutput(output)); + } + Verbosity::Concise => { + if !concise_no_header { + println!("{}", ConciseObjectOutput::header()); + } + println!("{}", ConciseObjectOutput(output)); + } + } + } + ToolCommand::FetchTransaction { + genesis, + digest, + show_input_tx, + fullnode_rpc_url, + } => { + print!( + "{}", + get_transaction_block(digest, genesis, show_input_tx, fullnode_rpc_url).await? + ); + } + ToolCommand::DbTool { db_path, cmd } => { + let path = PathBuf::from(db_path); + match cmd { + Some(c) => execute_db_tool_command(path, c).await?, + None => print_db_all_tables(path)?, + } + } + ToolCommand::DumpPackages { + db_url, + output_dir, + verbose, + } => { + if !verbose { + tracing_handle + .update_log("off") + .expect("Failed to update log level"); + } + + pkg_dump::dump(db_url, output_dir).await?; + } + ToolCommand::DumpValidators { genesis, concise } => { + let genesis = Genesis::load(genesis).unwrap(); + if !concise { + println!("{:#?}", genesis.validator_set_for_tooling()); + } else { + for (i, val_info) in genesis.validator_set_for_tooling().iter().enumerate() { + let metadata = val_info.verified_metadata(); + println!( + "#{:<2} {:<20} {:?} {:?} {}", + i, + metadata.name, + metadata.iota_pubkey_bytes().concise(), + metadata.net_address, + anemo::PeerId(metadata.network_pubkey.0.to_bytes()), + ) + } + } + } + ToolCommand::DumpGenesis { genesis } => { + let genesis = Genesis::load(genesis)?; + println!("{:#?}", genesis); + } + ToolCommand::FetchCheckpoint { + genesis, + sequence_number, + fullnode_rpc_url, + } => { + let clients = make_clients(genesis, fullnode_rpc_url).await?; + + for (name, (_, client)) in clients { + let resp = client + .handle_checkpoint(CheckpointRequest { + sequence_number, + request_content: true, + }) + .await + .unwrap(); + let CheckpointResponse { + checkpoint, + contents, + } = resp; + println!("Validator: {:?}\n", name.concise()); + println!("Checkpoint: {:?}\n", checkpoint); + println!("Content: {:?}\n", contents); + } + } + ToolCommand::Anemo { args } => { + let config = crate::make_anemo_config(); + anemo_cli::run(config, args).await + } + ToolCommand::RestoreFromDBCheckpoint { + config_path, + db_checkpoint_path, + } => { + let config = iota_config::NodeConfig::load(config_path)?; + restore_from_db_checkpoint(&config, &db_checkpoint_path).await?; + } + ToolCommand::DownloadFormalSnapshot { + epoch, + genesis, + path, + num_parallel_downloads, + verify, + network, + snapshot_bucket, + snapshot_bucket_type, + snapshot_path, + archive_bucket, + archive_bucket_type, + no_sign_request, + latest, + verbose, + } => { + if !verbose { + tracing_handle + .update_log("off") + .expect("Failed to update log level"); + } + let num_parallel_downloads = num_parallel_downloads.unwrap_or_else(|| { + num_cpus::get() + .checked_sub(1) + .expect("Failed to get number of CPUs") + }); + let snapshot_bucket = + snapshot_bucket.or_else(|| match (network, no_sign_request) { + (Chain::Mainnet, false) => Some( + env::var("MAINNET_FORMAL_SIGNED_BUCKET") + .unwrap_or("mysten-mainnet-formal".to_string()), + ), + (Chain::Mainnet, true) => env::var("MAINNET_FORMAL_UNSIGNED_BUCKET").ok(), + (Chain::Testnet, true) => env::var("TESTNET_FORMAL_UNSIGNED_BUCKET").ok(), + (Chain::Testnet, _) => Some( + env::var("TESTNET_FORMAL_SIGNED_BUCKET") + .unwrap_or("mysten-testnet-formal".to_string()), + ), + (Chain::Unknown, _) => { + panic!("Cannot generate default snapshot bucket for unknown network"); + } + }); + + let aws_endpoint = env::var("AWS_SNAPSHOT_ENDPOINT").ok().or_else(|| { + if no_sign_request { + if network == Chain::Mainnet { + Some("https://formal-snapshot.mainnet.iota.io".to_string()) + } else if network == Chain::Testnet { + Some("https://formal-snapshot.testnet.iota.io".to_string()) + } else { + None + } + } else { + None + } + }); + + let snapshot_bucket_type = if no_sign_request { + ObjectStoreType::S3 + } else { + snapshot_bucket_type + .expect("--snapshot-bucket-type must be set if not using --no-sign-request") + }; + let snapshot_store_config = match snapshot_bucket_type { + ObjectStoreType::S3 => ObjectStoreConfig { + object_store: Some(ObjectStoreType::S3), + bucket: snapshot_bucket.filter(|s| !s.is_empty()), + aws_access_key_id: env::var("AWS_SNAPSHOT_ACCESS_KEY_ID").ok(), + aws_secret_access_key: env::var("AWS_SNAPSHOT_SECRET_ACCESS_KEY").ok(), + aws_region: env::var("AWS_SNAPSHOT_REGION").ok(), + aws_endpoint: aws_endpoint.filter(|s| !s.is_empty()), + aws_virtual_hosted_style_request: env::var( + "AWS_SNAPSHOT_VIRTUAL_HOSTED_REQUESTS", + ) + .ok() + .and_then(|b| b.parse().ok()) + .unwrap_or(no_sign_request), + object_store_connection_limit: 200, + no_sign_request, + ..Default::default() + }, + ObjectStoreType::GCS => ObjectStoreConfig { + object_store: Some(ObjectStoreType::GCS), + bucket: snapshot_bucket, + google_service_account: env::var("GCS_SNAPSHOT_SERVICE_ACCOUNT_FILE_PATH") + .ok(), + object_store_connection_limit: 200, + no_sign_request, + ..Default::default() + }, + ObjectStoreType::Azure => ObjectStoreConfig { + object_store: Some(ObjectStoreType::Azure), + bucket: snapshot_bucket, + azure_storage_account: env::var("AZURE_SNAPSHOT_STORAGE_ACCOUNT").ok(), + azure_storage_access_key: env::var("AZURE_SNAPSHOT_STORAGE_ACCESS_KEY") + .ok(), + object_store_connection_limit: 200, + no_sign_request, + ..Default::default() + }, + ObjectStoreType::File => { + if snapshot_path.is_some() { + ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: snapshot_path, + ..Default::default() + } + } else { + panic!( + "--snapshot-path must be specified for --snapshot-bucket-type=file" + ); + } + } + }; + + let archive_bucket = archive_bucket.or_else(|| match network { + Chain::Mainnet => Some( + env::var("MAINNET_ARCHIVE_BUCKET") + .unwrap_or("mysten-mainnet-archives".to_string()), + ), + Chain::Testnet => Some( + env::var("TESTNET_ARCHIVE_BUCKET") + .unwrap_or("mysten-testnet-archives".to_string()), + ), + Chain::Unknown => { + panic!("Cannot generate default archive bucket for unknown network"); + } + }); + let aws_region = + Some(env::var("AWS_ARCHIVE_REGION").unwrap_or("us-west-2".to_string())); + let archive_store_config = match archive_bucket_type { + ObjectStoreType::S3 => ObjectStoreConfig { + object_store: Some(ObjectStoreType::S3), + bucket: archive_bucket.filter(|s| !s.is_empty()), + aws_access_key_id: env::var("AWS_ARCHIVE_ACCESS_KEY_ID").ok(), + aws_secret_access_key: env::var("AWS_ARCHIVE_SECRET_ACCESS_KEY").ok(), + aws_region: aws_region.filter(|s| !s.is_empty()), + aws_endpoint: env::var("AWS_ARCHIVE_ENDPOINT").ok(), + aws_virtual_hosted_style_request: env::var( + "AWS_ARCHIVE_VIRTUAL_HOSTED_REQUESTS", + ) + .ok() + .and_then(|b| b.parse().ok()) + .unwrap_or(false), + object_store_connection_limit: 200, + no_sign_request, + ..Default::default() + }, + ObjectStoreType::GCS => ObjectStoreConfig { + object_store: Some(ObjectStoreType::GCS), + bucket: archive_bucket, + google_service_account: env::var("GCS_ARCHIVE_SERVICE_ACCOUNT_FILE_PATH") + .ok(), + object_store_connection_limit: 200, + no_sign_request, + ..Default::default() + }, + ObjectStoreType::Azure => ObjectStoreConfig { + object_store: Some(ObjectStoreType::Azure), + bucket: archive_bucket, + azure_storage_account: env::var("AZURE_ARCHIVE_STORAGE_ACCOUNT").ok(), + azure_storage_access_key: env::var("AZURE_ARCHIVE_STORAGE_ACCESS_KEY").ok(), + object_store_connection_limit: 200, + no_sign_request, + ..Default::default() + }, + ObjectStoreType::File => { + panic!("Download from local filesystem is not supported") + } + }; + let latest_available_epoch = + latest.then_some(get_latest_available_epoch(&snapshot_store_config).await?); + let epoch_to_download = epoch.or(latest_available_epoch).expect( + "Either pass epoch with --epoch or use latest with --latest", + ); + + if let Err(e) = + check_completed_snapshot(&snapshot_store_config, epoch_to_download).await + { + panic!( + "Aborting snapshot restore: {}, snapshot may not be uploaded yet", + e + ); + } + + let verify = verify.unwrap_or(true); + download_formal_snapshot( + &path, + epoch_to_download, + &genesis, + snapshot_store_config, + archive_store_config, + num_parallel_downloads, + network, + verify, + ) + .await?; + } + ToolCommand::DownloadDBSnapshot { + epoch, + path, + skip_indexes, + num_parallel_downloads, + network, + snapshot_bucket, + snapshot_bucket_type, + snapshot_path, + no_sign_request, + latest, + verbose, + } => { + if !verbose { + tracing_handle + .update_log("off") + .expect("Failed to update log level"); + } + let num_parallel_downloads = num_parallel_downloads.unwrap_or_else(|| { + num_cpus::get() + .checked_sub(1) + .expect("Failed to get number of CPUs") + }); + let snapshot_bucket = + snapshot_bucket.or_else(|| match (network, no_sign_request) { + (Chain::Mainnet, false) => Some( + env::var("MAINNET_DB_SIGNED_BUCKET") + .unwrap_or("mysten-mainnet-snapshots".to_string()), + ), + (Chain::Mainnet, true) => env::var("MAINNET_DB_UNSIGNED_BUCKET").ok(), + (Chain::Testnet, true) => env::var("TESTNET_DB_UNSIGNED_BUCKET").ok(), + (Chain::Testnet, _) => Some( + env::var("TESTNET_DB_SIGNED_BUCKET") + .unwrap_or("mysten-testnet-snapshots".to_string()), + ), + (Chain::Unknown, _) => { + panic!("Cannot generate default snapshot bucket for unknown network"); + } + }); + + let aws_endpoint = env::var("AWS_SNAPSHOT_ENDPOINT").ok(); + let snapshot_bucket_type = if no_sign_request { + ObjectStoreType::S3 + } else { + snapshot_bucket_type + .expect("--snapshot-bucket-type must be set if not using --no-sign-request") + }; + let snapshot_store_config = if no_sign_request { + let aws_endpoint = env::var("AWS_SNAPSHOT_ENDPOINT").ok().or_else(|| { + if network == Chain::Mainnet { + Some("https://db-snapshot.mainnet.iota.io".to_string()) + } else if network == Chain::Testnet { + Some("https://db-snapshot.testnet.iota.io".to_string()) + } else { + None + } + }); + ObjectStoreConfig { + object_store: Some(ObjectStoreType::S3), + aws_endpoint: aws_endpoint.filter(|s| !s.is_empty()), + aws_virtual_hosted_style_request: env::var( + "AWS_SNAPSHOT_VIRTUAL_HOSTED_REQUESTS", + ) + .ok() + .and_then(|b| b.parse().ok()) + .unwrap_or(no_sign_request), + object_store_connection_limit: 200, + no_sign_request, + ..Default::default() + } + } else { + match snapshot_bucket_type { + ObjectStoreType::S3 => ObjectStoreConfig { + object_store: Some(ObjectStoreType::S3), + bucket: snapshot_bucket.filter(|s| !s.is_empty()), + aws_access_key_id: env::var("AWS_SNAPSHOT_ACCESS_KEY_ID").ok(), + aws_secret_access_key: env::var("AWS_SNAPSHOT_SECRET_ACCESS_KEY").ok(), + aws_region: env::var("AWS_SNAPSHOT_REGION").ok(), + aws_endpoint: aws_endpoint.filter(|s| !s.is_empty()), + aws_virtual_hosted_style_request: env::var( + "AWS_SNAPSHOT_VIRTUAL_HOSTED_REQUESTS", + ) + .ok() + .and_then(|b| b.parse().ok()) + .unwrap_or(no_sign_request), + object_store_connection_limit: 200, + no_sign_request, + ..Default::default() + }, + ObjectStoreType::GCS => ObjectStoreConfig { + object_store: Some(ObjectStoreType::GCS), + bucket: snapshot_bucket, + google_service_account: env::var( + "GCS_SNAPSHOT_SERVICE_ACCOUNT_FILE_PATH", + ) + .ok(), + google_project_id: env::var("GCS_SNAPSHOT_SERVICE_ACCOUNT_PROJECT_ID") + .ok(), + object_store_connection_limit: 200, + no_sign_request, + ..Default::default() + }, + ObjectStoreType::Azure => ObjectStoreConfig { + object_store: Some(ObjectStoreType::Azure), + bucket: snapshot_bucket, + azure_storage_account: env::var("AZURE_SNAPSHOT_STORAGE_ACCOUNT").ok(), + azure_storage_access_key: env::var("AZURE_SNAPSHOT_STORAGE_ACCESS_KEY") + .ok(), + object_store_connection_limit: 200, + no_sign_request, + ..Default::default() + }, + ObjectStoreType::File => { + if snapshot_path.is_some() { + ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: snapshot_path, + ..Default::default() + } + } else { + panic!( + "--snapshot-path must be specified for --snapshot-bucket-type=file" + ); + } + } + } + }; + + let latest_available_epoch = + latest.then_some(get_latest_available_epoch(&snapshot_store_config).await?); + let epoch_to_download = epoch.or(latest_available_epoch).expect( + "Either pass epoch with --epoch or use latest with --latest", + ); + + if let Err(e) = + check_completed_snapshot(&snapshot_store_config, epoch_to_download).await + { + panic!( + "Aborting snapshot restore: {}, snapshot may not be uploaded yet", + e + ); + } + download_db_snapshot( + &path, + epoch_to_download, + snapshot_store_config, + skip_indexes, + num_parallel_downloads, + ) + .await?; + } + ToolCommand::Replay { + rpc_url, + safety_checks, + cmd, + use_authority, + cfg_path, + } => { + execute_replay_command(rpc_url, safety_checks, use_authority, cfg_path, cmd) + .await?; + } + ToolCommand::VerifyArchive { + genesis, + object_store_config, + download_concurrency, + } => { + verify_archive(&genesis, object_store_config, download_concurrency, true).await?; + } + ToolCommand::PrintArchiveManifest { + object_store_config, + } => { + println!("{}", read_manifest_as_json(object_store_config).await?); + } + ToolCommand::UpdateArchiveManifest { + object_store_config, + archive_json_path, + } => { + write_manifest_from_json(object_store_config, archive_json_path).await?; + } + ToolCommand::VerifyArchiveByChecksum { + object_store_config, + download_concurrency, + } => { + verify_archive_by_checksum(object_store_config, download_concurrency).await?; + } + ToolCommand::DumpArchiveByChecksum { + object_store_config, + start, + end, + max_content_length, + } => { + dump_checkpoints_from_archive(object_store_config, start, end, max_content_length) + .await?; + } + ToolCommand::SignTransaction { + genesis, + sender_signed_data, + } => { + let genesis = Genesis::load(genesis)?; + let sender_signed_data = bcs::from_bytes::( + &fastcrypto::encoding::Base64::decode(sender_signed_data.as_str()).unwrap(), + ) + .unwrap(); + let transaction = Transaction::new(sender_signed_data); + let (agg, _) = AuthorityAggregatorBuilder::from_genesis(&genesis) + .build() + .unwrap(); + let result = agg.process_transaction(transaction).await; + println!("{:?}", result); + } + }; + Ok(()) + } +} diff --git a/crates/sui-tool/src/db_tool/db_dump.rs b/crates/iota-tool/src/db_tool/db_dump.rs similarity index 97% rename from crates/sui-tool/src/db_tool/db_dump.rs rename to crates/iota-tool/src/db_tool/db_dump.rs index 8b9bf1047ac..95608625328 100644 --- a/crates/sui-tool/src/db_tool/db_dump.rs +++ b/crates/iota-tool/src/db_tool/db_dump.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -11,12 +12,9 @@ use std::{ use anyhow::{anyhow, Ok}; use clap::{Parser, ValueEnum}; use comfy_table::{Cell, ContentArrangement, Row, Table}; -use prometheus::Registry; -use rocksdb::MultiThreaded; -use strum_macros::EnumString; -use sui_archival::reader::ArchiveReaderBalancer; -use sui_config::node::AuthorityStorePruningConfig; -use sui_core::{ +use iota_archival::reader::ArchiveReaderBalancer; +use iota_config::node::AuthorityStorePruningConfig; +use iota_core::{ authority::{ authority_per_epoch_store::AuthorityEpochTables, authority_store_pruner::{ @@ -28,8 +26,11 @@ use sui_core::{ checkpoints::CheckpointStore, epoch::committee_store::CommitteeStoreTables, }; -use sui_storage::{mutex_table::RwLockTable, IndexStoreTables}; -use sui_types::base_types::{EpochId, ObjectID}; +use iota_storage::{mutex_table::RwLockTable, IndexStoreTables}; +use iota_types::base_types::{EpochId, ObjectID}; +use prometheus::Registry; +use rocksdb::MultiThreaded; +use strum_macros::EnumString; use tracing::info; use typed_store::{ rocks::{default_db_options, MetricConf}, @@ -311,7 +312,7 @@ pub fn dump_table( #[cfg(test)] mod test { - use sui_core::authority::{ + use iota_core::authority::{ authority_per_epoch_store::AuthorityEpochTables, authority_store_tables::AuthorityPerpetualTables, }; diff --git a/crates/sui-tool/src/db_tool/index_search.rs b/crates/iota-tool/src/db_tool/index_search.rs similarity index 94% rename from crates/sui-tool/src/db_tool/index_search.rs rename to crates/iota-tool/src/db_tool/index_search.rs index f1167dbe85b..da4dc01155f 100644 --- a/crates/sui-tool/src/db_tool/index_search.rs +++ b/crates/iota-tool/src/db_tool/index_search.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fmt::Debug, path::PathBuf, str::FromStr}; use anyhow::anyhow; -use move_core_types::language_storage::ModuleId; -use serde::{de::DeserializeOwned, Serialize}; -use sui_storage::IndexStoreTables; -use sui_types::{ - base_types::{ObjectID, SuiAddress, TxSequenceNumber}, +use iota_storage::IndexStoreTables; +use iota_types::{ + base_types::{IotaAddress, ObjectID, TxSequenceNumber}, digests::TransactionDigest, Identifier, TypeTag, }; +use move_core_types::language_storage::ModuleId; +use serde::{de::DeserializeOwned, Serialize}; use typed_store::{ rocks::{DBMap, MetricConf}, traits::Map, @@ -251,14 +252,14 @@ where Ok(entries) } -fn from_addr_seq(s: &str) -> Result<(SuiAddress, TxSequenceNumber), anyhow::Error> { +fn from_addr_seq(s: &str) -> Result<(IotaAddress, TxSequenceNumber), anyhow::Error> { // Remove whitespaces let s = s.trim(); let tokens = s.split(',').collect::>(); if tokens.len() != 2 { return Err(anyhow!("Invalid address, sequence number pair")); } - let address = SuiAddress::from_str(tokens[0].trim())?; + let address = IotaAddress::from_str(tokens[0].trim())?; let sequence_number = TxSequenceNumber::from_str(tokens[1].trim())?; Ok((address, sequence_number)) @@ -296,27 +297,27 @@ fn from_id_module_function_txseq( Ok((pid, module.to_string(), func.to_string(), seq)) } -fn from_addr_oid(s: &str) -> Result<(SuiAddress, ObjectID), anyhow::Error> { +fn from_addr_oid(s: &str) -> Result<(IotaAddress, ObjectID), anyhow::Error> { // Remove whitespaces let s = s.trim(); let tokens = s.split(',').collect::>(); if tokens.len() != 2 { return Err(anyhow!("Invalid address, object id pair")); } - let addr = SuiAddress::from_str(tokens[0].trim())?; + let addr = IotaAddress::from_str(tokens[0].trim())?; let oid = ObjectID::from_str(tokens[1].trim())?; Ok((addr, oid)) } -fn from_addr_str_oid(s: &str) -> Result<(SuiAddress, String, ObjectID), anyhow::Error> { +fn from_addr_str_oid(s: &str) -> Result<(IotaAddress, String, ObjectID), anyhow::Error> { // Remove whitespaces let s = s.trim(); let tokens = s.split(',').collect::>(); if tokens.len() != 3 { return Err(anyhow!("Invalid addr, type tag object id triplet")); } - let address = SuiAddress::from_str(tokens[0].trim())?; + let address = IotaAddress::from_str(tokens[0].trim())?; let tag: TypeTag = TypeTag::from_str(tokens[1].trim())?; let oid: ObjectID = ObjectID::from_str(tokens[2].trim())?; @@ -371,7 +372,7 @@ fn from_event_id(s: &str) -> Result<(TxSequenceNumber, usize), anyhow::Error> { fn from_address_and_event_id( s: &str, -) -> Result<(SuiAddress, (TxSequenceNumber, usize)), anyhow::Error> { +) -> Result<(IotaAddress, (TxSequenceNumber, usize)), anyhow::Error> { // Example: "0x1 1234 5" let tokens = s.split(' ').collect::>(); if tokens.len() != 3 { @@ -379,6 +380,6 @@ fn from_address_and_event_id( } let tx_seq = TxSequenceNumber::from_str(tokens[1])?; let event_seq = usize::from_str(tokens[2])?; - let address = SuiAddress::from_str(tokens[0].trim())?; + let address = IotaAddress::from_str(tokens[0].trim())?; Ok((address, (tx_seq, event_seq))) } diff --git a/crates/iota-tool/src/db_tool/mod.rs b/crates/iota-tool/src/db_tool/mod.rs new file mode 100644 index 00000000000..5a70e4c63bd --- /dev/null +++ b/crates/iota-tool/src/db_tool/mod.rs @@ -0,0 +1,542 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::path::{Path, PathBuf}; + +use anyhow::{anyhow, bail}; +use clap::Parser; +use iota_core::{ + authority::{ + authority_per_epoch_store::AuthorityEpochTables, + authority_store_tables::AuthorityPerpetualTables, + }, + checkpoints::CheckpointStore, +}; +use iota_types::{ + base_types::{EpochId, ObjectID}, + digests::{CheckpointContentsDigest, TransactionDigest}, + effects::TransactionEffectsAPI, + messages_checkpoint::{CheckpointDigest, CheckpointSequenceNumber}, + storage::ObjectStore, +}; +use narwhal_storage::NodeStorage; +use typed_store::rocks::MetricConf; + +use self::{ + db_dump::{dump_table, duplicate_objects_summary, list_tables, table_summary, StoreName}, + index_search::{search_index, SearchRange}, +}; +use crate::db_tool::db_dump::{compact, print_table_metadata, prune_checkpoints, prune_objects}; +pub mod db_dump; +mod index_search; + +#[derive(Parser)] +#[command(rename_all = "kebab-case")] +pub enum DbToolCommand { + ListTables, + Dump(Options), + IndexSearchKeyRange(IndexSearchKeyRangeOptions), + IndexSearchCount(IndexSearchCountOptions), + TableSummary(Options), + DuplicatesSummary, + ListDBMetadata(Options), + PrintLastConsensusIndex, + PrintConsensusCommit(PrintConsensusCommitOptions), + PrintTransaction(PrintTransactionOptions), + PrintObject(PrintObjectOptions), + PrintCheckpoint(PrintCheckpointOptions), + PrintCheckpointContent(PrintCheckpointContentOptions), + ResetDB, + RewindCheckpointExecution(RewindCheckpointExecutionOptions), + Compact, + PruneObjects, + PruneCheckpoints, + SetCheckpointWatermark(SetCheckpointWatermarkOptions), +} + +#[derive(Parser)] +#[command(rename_all = "kebab-case")] +pub struct IndexSearchKeyRangeOptions { + #[arg(long = "table-name", short = 't')] + table_name: String, + #[arg(long = "start", short = 's')] + start: String, + #[arg(long = "end", short = 'e')] + end_key: String, +} + +#[derive(Parser)] +#[command(rename_all = "kebab-case")] +pub struct IndexSearchCountOptions { + #[arg(long = "table-name", short = 't')] + table_name: String, + #[arg(long = "start", short = 's')] + start: String, + #[arg(long = "count", short = 'c')] + count: u64, +} + +#[derive(Parser)] +#[command(rename_all = "kebab-case")] +pub struct Options { + /// The type of store to dump + #[arg(long = "store", short = 's', value_enum)] + store_name: StoreName, + /// The name of the table to dump + #[arg(long = "table-name", short = 't')] + table_name: String, + /// The size of page to dump. This is a u16 + #[arg(long = "page-size", short = 'p')] + page_size: u16, + /// The page number to dump + #[arg(long = "page-num", short = 'n')] + page_number: usize, + + // TODO: We should load this automatically from the system object in AuthorityPerpetualTables. + // This is very difficult to do right now because you can't share code between + // AuthorityPerpetualTables and AuthorityEpochTablesReadonly. + /// The epoch to use when loading AuthorityEpochTables. + #[arg(long = "epoch", short = 'e')] + epoch: Option, +} + +#[derive(Parser)] +#[command(rename_all = "kebab-case")] +pub struct PrintConsensusCommitOptions { + #[arg(long, help = "Sequence number of the consensus commit")] + seqnum: u64, +} + +#[derive(Parser)] +#[command(rename_all = "kebab-case")] +pub struct PrintTransactionOptions { + #[arg(long, help = "The transaction digest to print")] + digest: TransactionDigest, +} + +#[derive(Parser)] +#[command(rename_all = "kebab-case")] +pub struct PrintObjectOptions { + #[arg(long, help = "The object id to print")] + id: ObjectID, + #[arg(long, help = "The object version to print")] + version: Option, +} + +#[derive(Parser)] +#[command(rename_all = "kebab-case")] +pub struct PrintCheckpointOptions { + #[arg(long, help = "The checkpoint digest to print")] + digest: CheckpointDigest, +} + +#[derive(Parser)] +#[command(rename_all = "kebab-case")] +pub struct PrintCheckpointContentOptions { + #[arg( + long, + help = "The checkpoint content digest (NOT the checkpoint digest)" + )] + digest: CheckpointContentsDigest, +} + +#[derive(Parser)] +#[command(rename_all = "kebab-case")] +pub struct RemoveTransactionOptions { + #[arg(long, help = "The transaction digest to remove")] + digest: TransactionDigest, + + #[arg(long)] + confirm: bool, + + /// The epoch to use when loading AuthorityEpochTables. + /// Defaults to the current epoch. + #[arg(long = "epoch", short = 'e')] + epoch: Option, +} + +#[derive(Parser)] +#[command(rename_all = "kebab-case")] +pub struct RemoveObjectLockOptions { + #[arg(long, help = "The object ID to remove")] + id: ObjectID, + + #[arg(long, help = "The object version to remove")] + version: u64, + + #[arg(long)] + confirm: bool, +} + +#[derive(Parser)] +#[command(rename_all = "kebab-case")] +pub struct RewindCheckpointExecutionOptions { + #[arg(long = "epoch")] + epoch: EpochId, + + #[arg(long = "checkpoint-sequence-number")] + checkpoint_sequence_number: u64, +} + +#[derive(Parser)] +#[command(rename_all = "kebab-case")] +pub struct SetCheckpointWatermarkOptions { + #[arg(long)] + highest_verified: Option, + + #[arg(long)] + highest_synced: Option, +} + +pub async fn execute_db_tool_command(db_path: PathBuf, cmd: DbToolCommand) -> anyhow::Result<()> { + match cmd { + DbToolCommand::ListTables => print_db_all_tables(db_path), + DbToolCommand::Dump(d) => print_all_entries( + d.store_name, + d.epoch, + db_path, + &d.table_name, + d.page_size, + d.page_number, + ), + DbToolCommand::TableSummary(d) => { + print_db_table_summary(d.store_name, d.epoch, db_path, &d.table_name) + } + DbToolCommand::DuplicatesSummary => print_db_duplicates_summary(db_path), + DbToolCommand::ListDBMetadata(d) => { + print_table_metadata(d.store_name, d.epoch, db_path, &d.table_name) + } + DbToolCommand::PrintLastConsensusIndex => print_last_consensus_index(&db_path), + DbToolCommand::PrintConsensusCommit(d) => print_consensus_commit(&db_path, d), + DbToolCommand::PrintTransaction(d) => print_transaction(&db_path, d), + DbToolCommand::PrintObject(o) => print_object(&db_path, o), + DbToolCommand::PrintCheckpoint(d) => print_checkpoint(&db_path, d), + DbToolCommand::PrintCheckpointContent(d) => print_checkpoint_content(&db_path, d), + DbToolCommand::ResetDB => reset_db_to_genesis(&db_path), + DbToolCommand::RewindCheckpointExecution(d) => { + rewind_checkpoint_execution(&db_path, d.epoch, d.checkpoint_sequence_number) + } + DbToolCommand::Compact => compact(db_path), + DbToolCommand::PruneObjects => prune_objects(db_path).await, + DbToolCommand::PruneCheckpoints => prune_checkpoints(db_path).await, + DbToolCommand::IndexSearchKeyRange(rg) => { + let res = search_index( + db_path, + rg.table_name, + rg.start, + SearchRange::ExclusiveLastKey(rg.end_key), + )?; + for (k, v) in res { + println!("{}: {}", k, v); + } + Ok(()) + } + DbToolCommand::IndexSearchCount(sc) => { + let res = search_index( + db_path, + sc.table_name, + sc.start, + SearchRange::Count(sc.count), + )?; + for (k, v) in res { + println!("{}: {}", k, v); + } + Ok(()) + } + DbToolCommand::SetCheckpointWatermark(d) => set_checkpoint_watermark(&db_path, d), + } +} + +pub fn print_db_all_tables(db_path: PathBuf) -> anyhow::Result<()> { + list_tables(db_path)?.iter().for_each(|t| println!("{}", t)); + Ok(()) +} + +pub fn print_db_duplicates_summary(db_path: PathBuf) -> anyhow::Result<()> { + let (total_count, duplicate_count, total_bytes, duplicated_bytes) = + duplicate_objects_summary(db_path); + println!( + "Total objects = {}, duplicated objects = {}, total bytes = {}, duplicated bytes = {}", + total_count, duplicate_count, total_bytes, duplicated_bytes + ); + Ok(()) +} + +pub fn print_last_consensus_index(path: &Path) -> anyhow::Result<()> { + let epoch_tables = AuthorityEpochTables::open_tables_read_write( + path.to_path_buf(), + MetricConf::default(), + None, + None, + ); + let last_index = epoch_tables.get_last_consensus_index()?; + println!("Last consensus index is {:?}", last_index); + Ok(()) +} + +pub fn print_consensus_commit(path: &Path, opt: PrintConsensusCommitOptions) -> anyhow::Result<()> { + let consensus_db = NodeStorage::reopen(path, None); + let consensus_commit = consensus_db + .consensus_store + .read_consensus_commit(&opt.seqnum)?; + match consensus_commit { + Some(commit) => println!("Consensus commit at {} is {:?}", opt.seqnum, commit), + None => println!("Consensus commit at {} is not found!", opt.seqnum), + } + Ok(()) +} + +pub fn print_transaction(path: &Path, opt: PrintTransactionOptions) -> anyhow::Result<()> { + let perpetual_db = AuthorityPerpetualTables::open(&path.join("store"), None); + if let Some((epoch, checkpoint_seq_num)) = + perpetual_db.get_checkpoint_sequence_number(&opt.digest)? + { + println!( + "Transaction {:?} executed in epoch {} checkpoint {}", + opt.digest, epoch, checkpoint_seq_num + ); + }; + if let Some(effects) = perpetual_db.get_effects(&opt.digest)? { + println!( + "Transaction {:?} dependencies: {:#?}", + opt.digest, + effects.dependencies(), + ); + }; + Ok(()) +} + +pub fn print_object(path: &Path, opt: PrintObjectOptions) -> anyhow::Result<()> { + let perpetual_db = AuthorityPerpetualTables::open(&path.join("store"), None); + + let obj = if let Some(version) = opt.version { + perpetual_db.get_object_by_key(&opt.id, version.into())? + } else { + perpetual_db.get_object(&opt.id)? + }; + + if let Some(obj) = obj { + println!("Object {:?}:\n{:#?}", opt.id, obj); + } else { + println!("Object {:?} not found", opt.id); + } + + Ok(()) +} + +pub fn print_checkpoint(path: &Path, opt: PrintCheckpointOptions) -> anyhow::Result<()> { + let checkpoint_store = CheckpointStore::new(&path.join("checkpoints")); + let checkpoint = checkpoint_store + .get_checkpoint_by_digest(&opt.digest)? + .ok_or(anyhow!( + "Checkpoint digest {:?} not found in checkpoint store", + opt.digest + ))?; + println!("Checkpoint: {:?}", checkpoint); + drop(checkpoint_store); + print_checkpoint_content( + path, + PrintCheckpointContentOptions { + digest: checkpoint.content_digest, + }, + ) +} + +pub fn print_checkpoint_content( + path: &Path, + opt: PrintCheckpointContentOptions, +) -> anyhow::Result<()> { + let checkpoint_store = CheckpointStore::new(&path.join("checkpoints")); + let contents = checkpoint_store + .get_checkpoint_contents(&opt.digest)? + .ok_or(anyhow!( + "Checkpoint content digest {:?} not found in checkpoint store", + opt.digest + ))?; + println!("Checkpoint content: {:?}", contents); + Ok(()) +} + +pub fn reset_db_to_genesis(path: &Path) -> anyhow::Result<()> { + // Follow the below steps to test: + // + // Get a db snapshot. Either generate one by running stress locally and enabling + // db checkpoints or download one from S3 bucket (pretty big in size though). + // Download the snapshot for the epoch you want to restore to the local disk. + // You will find one snapshot per epoch in the S3 bucket. We need to place the + // snapshot in the dir where config is pointing to. If db-config in + // fullnode.yaml is /opt/iota/db/authorities_db and we want to restore from + // epoch 10, we want to copy the snapshot to /opt/iota/db/authorities_dblike + // this: aws s3 cp s3://myBucket/dir /opt/iota/db/authorities_db/ + // --recursive —exclude “*” —include “epoch_10*” Mark downloaded snapshot as + // live: mv /opt/iota/db/authorities_db/epoch_10 + // /opt/iota/db/authorities_db/live Reset the downloaded db to execute from + // genesis with: cargo run --package iota-tool -- db-tool --db-path + // /opt/iota/db/authorities_db/live reset-db Start the iota full node: cargo + // run --release --bin iota-node -- --config-path ~/db_checkpoints/fullnode. + // yaml A sample fullnode.yaml config would be: --- + // db-path: /opt/iota/db/authorities_db + // network-address: /ip4/0.0.0.0/tcp/8080/http + // json-rpc-address: "0.0.0.0:9000" + // websocket-address: "0.0.0.0:9001" + // metrics-address: "0.0.0.0:9184" + // admin-interface-port: 1337 + // enable-event-processing: true + // grpc-load-shed: ~ + // grpc-concurrency-limit: ~ + // p2p-config: + // listen-address: "0.0.0.0:8084" + // genesis: + // genesis-file-location: + // authority-store-pruning-config: + // num-latest-epoch-dbs-to-retain: 3 + // epoch-db-pruning-period-secs: 3600 + // num-epochs-to-retain: 18446744073709551615 + // max-checkpoints-in-batch: 10 + // max-transactions-in-batch: 1000 + let perpetual_db = AuthorityPerpetualTables::open_tables_read_write( + path.join("store").join("perpetual"), + MetricConf::default(), + None, + None, + ); + perpetual_db.reset_db_for_execution_since_genesis()?; + + let checkpoint_db = CheckpointStore::open_tables_read_write( + path.join("checkpoints"), + MetricConf::default(), + None, + None, + ); + checkpoint_db.reset_db_for_execution_since_genesis()?; + + let epoch_db = AuthorityEpochTables::open_tables_read_write( + path.join("store"), + MetricConf::default(), + None, + None, + ); + epoch_db.reset_db_for_execution_since_genesis()?; + + Ok(()) +} + +/// Force sets the highest executed checkpoint. +/// NOTE: Does not force re-execution of transactions. +/// Run with: cargo run --package iota-tool -- db-tool --db-path +/// /opt/iota/db/authorities_db/live rewind-checkpoint-execution --epoch 3 +/// --checkpoint-sequence-number 300000 +pub fn rewind_checkpoint_execution( + path: &Path, + epoch: EpochId, + checkpoint_sequence_number: u64, +) -> anyhow::Result<()> { + let checkpoint_db = CheckpointStore::open_tables_read_write( + path.join("checkpoints"), + MetricConf::default(), + None, + None, + ); + let Some(checkpoint) = + checkpoint_db.get_checkpoint_by_sequence_number(checkpoint_sequence_number)? + else { + bail!("Checkpoint {checkpoint_sequence_number} not found!"); + }; + if epoch != checkpoint.epoch() { + bail!( + "Checkpoint {checkpoint_sequence_number} is in epoch {} not {epoch}!", + checkpoint.epoch() + ); + } + let highest_executed_sequence_number = checkpoint_db + .get_highest_executed_checkpoint_seq_number()? + .unwrap_or_default(); + if checkpoint_sequence_number > highest_executed_sequence_number { + bail!( + "Must rewind checkpoint execution to be not later than highest executed ({} > {})!", + checkpoint_sequence_number, + highest_executed_sequence_number + ); + } + checkpoint_db.set_highest_executed_checkpoint_subtle(&checkpoint)?; + Ok(()) +} + +pub fn print_db_table_summary( + store: StoreName, + epoch: Option, + path: PathBuf, + table_name: &str, +) -> anyhow::Result<()> { + let summary = table_summary(store, epoch, path, table_name)?; + let quantiles = [25, 50, 75, 90, 99]; + println!( + "Total num keys = {}, total key bytes = {}, total value bytes = {}", + summary.num_keys, summary.key_bytes_total, summary.value_bytes_total + ); + println!("Key size distribution:\n"); + quantiles.iter().for_each(|q| { + println!( + "p{:?} -> {:?} bytes\n", + q, + summary.key_hist.value_at_quantile(*q as f64 / 100.0) + ); + }); + println!("Value size distribution:\n"); + quantiles.iter().for_each(|q| { + println!( + "p{:?} -> {:?} bytes\n", + q, + summary.value_hist.value_at_quantile(*q as f64 / 100.0) + ); + }); + Ok(()) +} + +pub fn print_all_entries( + store: StoreName, + epoch: Option, + path: PathBuf, + table_name: &str, + page_size: u16, + page_number: usize, +) -> anyhow::Result<()> { + for (k, v) in dump_table(store, epoch, path, table_name, page_size, page_number)? { + println!("{:>100?}: {:?}", k, v); + } + Ok(()) +} + +/// Force sets state sync checkpoint watermarks. +/// Run with (for example): +/// cargo run --package iota-tool -- db-tool --db-path +/// /opt/iota/db/authorities_db/live set_checkpoint_watermark --highest-synced +/// 300000 +pub fn set_checkpoint_watermark( + path: &Path, + options: SetCheckpointWatermarkOptions, +) -> anyhow::Result<()> { + let checkpoint_db = CheckpointStore::open_tables_read_write( + path.join("checkpoints"), + MetricConf::default(), + None, + None, + ); + + if let Some(highest_verified) = options.highest_verified { + let Some(checkpoint) = checkpoint_db.get_checkpoint_by_sequence_number(highest_verified)? + else { + bail!("Checkpoint {highest_verified} not found"); + }; + checkpoint_db.update_highest_verified_checkpoint(&checkpoint)?; + } + if let Some(highest_synced) = options.highest_synced { + let Some(checkpoint) = checkpoint_db.get_checkpoint_by_sequence_number(highest_synced)? + else { + bail!("Checkpoint {highest_synced} not found"); + }; + checkpoint_db.update_highest_synced_checkpoint(&checkpoint)?; + } + Ok(()) +} diff --git a/crates/iota-tool/src/lib.rs b/crates/iota-tool/src/lib.rs new file mode 100644 index 00000000000..0dec6d163e8 --- /dev/null +++ b/crates/iota-tool/src/lib.rs @@ -0,0 +1,1197 @@ +// Copyright (c) 2021, Facebook, Inc. and its affiliates +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::BTreeMap, + fmt::Write, + fs, io, + num::NonZeroUsize, + ops::Range, + path::{Path, PathBuf}, + sync::{ + atomic::{AtomicU64, AtomicUsize, Ordering}, + Arc, + }, + time::Duration, +}; + +use anyhow::{anyhow, Result}; +use eyre::ContextCompat; +use fastcrypto::{hash::MultisetHash, traits::ToFromBytes}; +use futures::{ + future::{join_all, AbortHandle}, + StreamExt, TryStreamExt, +}; +use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; +use iota_archival::{ + reader::{ArchiveReader, ArchiveReaderMetrics}, + verify_archive_with_checksums, verify_archive_with_genesis_config, +}; +use iota_config::{ + genesis::Genesis, + node::ArchiveReaderConfig, + object_storage_config::{ObjectStoreConfig, ObjectStoreType}, + NodeConfig, +}; +use iota_core::{ + authority::{authority_store_tables::AuthorityPerpetualTables, AuthorityStore}, + authority_client::{AuthorityAPI, NetworkAuthorityClient}, + checkpoints::CheckpointStore, + epoch::committee_store::CommitteeStore, + execution_cache::ExecutionCache, + storage::RocksDbStore, +}; +use iota_network::default_mysten_network_config; +use iota_protocol_config::Chain; +use iota_sdk::IotaClientBuilder; +use iota_snapshot::{reader::StateSnapshotReaderV1, setup_db_state}; +use iota_storage::{ + object_store::{ + http::HttpDownloaderBuilder, + util::{copy_file, exists, get_path, Manifest, PerEpochManifest, MANIFEST_FILENAME}, + ObjectStoreGetExt, + }, + verify_checkpoint_range, +}; +use iota_types::{ + accumulator::Accumulator, + base_types::*, + crypto::AuthorityPublicKeyBytes, + messages_checkpoint::{CheckpointCommitment, ECMHLiveObjectSetDigest}, + messages_grpc::{ + LayoutGenerationOption, ObjectInfoRequest, ObjectInfoRequestKind, ObjectInfoResponse, + TransactionInfoRequest, TransactionStatus, + }, + multiaddr::Multiaddr, + object::Owner, + storage::{ReadStore, SharedInMemoryStore}, +}; +use itertools::Itertools; +use prometheus::Registry; +use tokio::{sync::mpsc, task::JoinHandle, time::Instant}; +use tracing::info; +use typed_store::rocks::MetricConf; + +pub mod commands; +pub mod db_tool; +pub mod pkg_dump; + +// This functions requires at least one of genesis or fullnode_rpc to be `Some`. +async fn make_clients( + genesis: Option, + fullnode_rpc: Option, +) -> Result> { + let mut net_config = default_mysten_network_config(); + net_config.connect_timeout = Some(Duration::from_secs(5)); + let mut authority_clients = BTreeMap::new(); + + if let Some(fullnode_rpc) = fullnode_rpc { + let iota_client = IotaClientBuilder::default().build(fullnode_rpc).await?; + let active_validators = iota_client + .governance_api() + .get_latest_iota_system_state() + .await? + .active_validators; + + for validator in active_validators { + let net_addr = Multiaddr::try_from(validator.net_address).unwrap(); + let channel = net_config + .connect_lazy(&net_addr) + .map_err(|err| anyhow!(err.to_string()))?; + let client = NetworkAuthorityClient::new(channel); + let public_key_bytes = + AuthorityPublicKeyBytes::from_bytes(&validator.protocol_pubkey_bytes)?; + authority_clients.insert(public_key_bytes, (net_addr.clone(), client)); + } + } else { + if genesis.is_none() { + return Err(anyhow!("Either genesis or fullnode_rpc must be specified")); + } + let genesis = Genesis::load(genesis.unwrap())?; + for validator in genesis.validator_set_for_tooling() { + let metadata = validator.verified_metadata(); + let channel = net_config + .connect_lazy(&metadata.net_address) + .map_err(|err| anyhow!(err.to_string()))?; + let client = NetworkAuthorityClient::new(channel); + let public_key_bytes = metadata.iota_pubkey_bytes(); + authority_clients.insert(public_key_bytes, (metadata.net_address.clone(), client)); + } + } + + Ok(authority_clients) +} + +type ObjectVersionResponses = Vec<(Option, Result, f64)>; +pub struct ObjectData { + requested_id: ObjectID, + responses: Vec<(AuthorityName, Multiaddr, ObjectVersionResponses)>, +} + +trait OptionDebug { + fn opt_debug(&self, def_str: &str) -> String; +} +trait OptionDisplay { + fn opt_display(&self, def_str: &str) -> String; +} + +impl OptionDebug for Option +where + T: std::fmt::Debug, +{ + fn opt_debug(&self, def_str: &str) -> String { + match self { + None => def_str.to_string(), + Some(t) => format!("{:?}", t), + } + } +} + +impl OptionDisplay for Option +where + T: std::fmt::Display, +{ + fn opt_display(&self, def_str: &str) -> String { + match self { + None => def_str.to_string(), + Some(t) => format!("{}", t), + } + } +} + +struct OwnerOutput(Owner); + +// grep/awk-friendly output for Owner +impl std::fmt::Display for OwnerOutput { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.0 { + Owner::AddressOwner(address) => { + write!(f, "address({})", address) + } + Owner::ObjectOwner(address) => { + write!(f, "object({})", address) + } + Owner::Immutable => { + write!(f, "immutable") + } + Owner::Shared { .. } => { + write!(f, "shared") + } + } + } +} + +pub struct GroupedObjectOutput(pub ObjectData); + +#[allow(clippy::format_in_format_args)] +impl std::fmt::Display for GroupedObjectOutput { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let responses = self + .0 + .responses + .iter() + .flat_map(|(name, multiaddr, resp)| { + resp.iter().map(|(seq_num, r, timespent)| { + ( + *name, + multiaddr.clone(), + seq_num, + r, + timespent, + r.as_ref().err(), + ) + }) + }) + .sorted_by(|a, b| { + Ord::cmp(&b.2, &a.2) + .then_with(|| Ord::cmp(&format!("{:?}", &b.5), &format!("{:?}", &a.5))) + }) + .group_by(|(_, _, seq_num, _r, _ts, _)| **seq_num); + for (seq_num, group) in &responses { + writeln!(f, "seq num: {}", seq_num.opt_debug("latest-seq-num"))?; + let cur_version_resp = group.group_by(|(_, _, _, r, _, _)| match r { + Ok(result) => { + let parent_tx_digest = result.object.previous_transaction; + let obj_digest = result.object.compute_object_reference().2; + let lock = result + .lock_for_debugging + .as_ref() + .map(|lock| *lock.digest()); + let owner = result.object.owner; + Some((parent_tx_digest, obj_digest, lock, owner)) + } + Err(_) => None, + }); + for (result, group) in &cur_version_resp { + match result { + Some((parent_tx_digest, obj_digest, lock, owner)) => { + let lock = lock.opt_debug("no-known-lock"); + writeln!(f, "obj ref: {obj_digest}")?; + writeln!(f, "parent tx: {parent_tx_digest}")?; + writeln!(f, "owner: {owner}")?; + writeln!(f, "lock: {lock}")?; + for (i, (name, multiaddr, _, _, timespent, _)) in group.enumerate() { + writeln!( + f, + " {:<4} {:<20} {:<56} ({:.3}s)", + i, + name.concise(), + format!("{}", multiaddr), + timespent + )?; + } + } + None => { + writeln!(f, "ERROR")?; + for (i, (name, multiaddr, _, resp, timespent, _)) in group.enumerate() { + writeln!( + f, + " {:<4} {:<20} {:<56} ({:.3}s) {:?}", + i, + name.concise(), + format!("{}", multiaddr), + timespent, + resp + )?; + } + } + }; + writeln!(f, "{:<100}\n", "-".repeat(100))?; + } + } + Ok(()) + } +} + +struct ConciseObjectOutput(ObjectData); + +impl ConciseObjectOutput { + fn header() -> String { + format!( + "{:<20} {:<8} {:<66} {:<45} {}", + "validator", "version", "digest", "parent_cert", "owner" + ) + } +} + +impl std::fmt::Display for ConciseObjectOutput { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for (name, _multi_addr, versions) in &self.0.responses { + for (version, resp, _time_elapsed) in versions { + write!( + f, + "{:<20} {:<8}", + format!("{:?}", name.concise()), + version.map(|s| s.value()).opt_debug("-") + )?; + match resp { + Err(_) => writeln!( + f, + "{:<66} {:<45} {:<51}", + "object-fetch-failed", "no-cert-available", "no-owner-available" + )?, + Ok(resp) => { + let obj_digest = resp.object.compute_object_reference().2; + let parent = resp.object.previous_transaction; + let owner = resp.object.owner; + write!(f, " {:<66} {:<45} {:<51}", obj_digest, parent, owner)?; + } + } + writeln!(f)?; + } + } + Ok(()) + } +} + +struct VerboseObjectOutput(ObjectData); + +impl std::fmt::Display for VerboseObjectOutput { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "Object: {}", self.0.requested_id)?; + + for (name, multiaddr, versions) in &self.0.responses { + writeln!(f, "validator: {:?}, addr: {:?}", name.concise(), multiaddr)?; + + for (version, resp, timespent) in versions { + writeln!( + f, + "-- version: {} ({:.3}s)", + version.opt_debug(""), + timespent, + )?; + + match resp { + Err(e) => writeln!(f, "Error fetching object: {}", e)?, + Ok(resp) => { + writeln!( + f, + " -- object digest: {}", + resp.object.compute_object_reference().2 + )?; + if resp.object.is_package() { + writeln!(f, " -- object: ")?; + } else if let Some(layout) = &resp.layout { + writeln!( + f, + " -- object: Move Object: {}", + resp.object + .data + .try_as_move() + .unwrap() + .to_move_struct(layout) + .unwrap() + )?; + } + writeln!(f, " -- owner: {}", resp.object.owner)?; + writeln!( + f, + " -- locked by: {}", + resp.lock_for_debugging.opt_debug("") + )?; + } + } + } + } + Ok(()) + } +} + +pub async fn get_object( + obj_id: ObjectID, + version: Option, + validator: Option, + genesis: Option, + fullnode_rpc: Option, +) -> Result { + let clients = make_clients(genesis, fullnode_rpc).await?; + + let responses = join_all( + clients + .iter() + .filter(|(name, _)| { + if let Some(v) = validator { + v == **name + } else { + true + } + }) + .map(|(name, (address, client))| async { + let object_versions = get_object_impl(client, obj_id, version).await; + (*name, address.clone(), object_versions) + }), + ) + .await; + + Ok(ObjectData { + requested_id: obj_id, + responses, + }) +} + +pub async fn get_transaction_block( + tx_digest: TransactionDigest, + genesis: Option, + show_input_tx: bool, + fullnode_rpc: Option, +) -> Result { + let clients = make_clients(genesis, fullnode_rpc).await?; + let timer = Instant::now(); + let responses = join_all(clients.iter().map(|(name, (address, client))| async { + let result = client + .handle_transaction_info_request(TransactionInfoRequest { + transaction_digest: tx_digest, + }) + .await; + ( + *name, + address.clone(), + result, + timer.elapsed().as_secs_f64(), + ) + })) + .await; + + // Grab one validator that return Some(TransactionInfoResponse) + let validator_aware_of_tx = responses.iter().find(|r| r.2.is_ok()); + + let responses = responses + .iter() + .map(|r| { + let key = + r.2.as_ref() + .map(|ok_result| match &ok_result.status { + TransactionStatus::Signed(_) => None, + TransactionStatus::Executed(_, effects, _) => Some(effects.digest()), + }) + .ok(); + let err = r.2.as_ref().err(); + (key, err, r) + }) + .sorted_by(|(k1, err1, _), (k2, err2, _)| { + Ord::cmp(k1, k2).then_with(|| Ord::cmp(err1, err2)) + }) + .group_by(|(_, _err, r)| { + r.2.as_ref().map(|ok_result| match &ok_result.status { + TransactionStatus::Signed(_) => None, + TransactionStatus::Executed(_, effects, _) => Some(( + ok_result.transaction.transaction_data(), + effects.data(), + effects.digest(), + )), + }) + }); + let mut s = String::new(); + for (i, (key, group)) in responses.into_iter().enumerate() { + match key { + Ok(Some((tx, effects, effects_digest))) => { + writeln!( + &mut s, + "#{:<2} tx_digest: {:<68?} effects_digest: {:?}", + i, tx_digest, effects_digest, + )?; + writeln!(&mut s, "{:#?}", effects)?; + if show_input_tx { + writeln!(&mut s, "{:#?}", tx)?; + } + } + Ok(None) => { + writeln!( + &mut s, + "#{:<2} tx_digest: {:<68?} Signed but not executed", + i, tx_digest + )?; + if show_input_tx { + // In this case, we expect at least one validator knows about this tx + let validator_aware_of_tx = validator_aware_of_tx.unwrap(); + let client = &clients.get(&validator_aware_of_tx.0).unwrap().1; + let tx_info = client.handle_transaction_info_request(TransactionInfoRequest { + transaction_digest: tx_digest, + }).await.unwrap_or_else(|e| panic!("Validator {:?} should have known about tx_digest: {:?}, got error: {:?}", validator_aware_of_tx.0, tx_digest, e)); + writeln!(&mut s, "{:#?}", tx_info)?; + } + } + other => { + writeln!(&mut s, "#{:<2} {:#?}", i, other)?; + } + } + for (j, (_, _, res)) in group.enumerate() { + writeln!( + &mut s, + " {:<4} {:<20} {:<56} ({:.3}s)", + j, + res.0.concise(), + format!("{}", res.1), + res.3 + )?; + } + writeln!(&mut s, "{:<100}\n", "-".repeat(100))?; + } + Ok(s) +} + +// Keep the return type a vector in case we need support for lamport versions in +// the near future +async fn get_object_impl( + client: &NetworkAuthorityClient, + id: ObjectID, + version: Option, +) -> Vec<(Option, Result, f64)> { + let mut ret = Vec::new(); + + let start = Instant::now(); + let resp = client + .handle_object_info_request(ObjectInfoRequest { + object_id: id, + generate_layout: LayoutGenerationOption::Generate, + request_kind: match version { + None => ObjectInfoRequestKind::LatestObjectInfo, + Some(v) => ObjectInfoRequestKind::PastObjectInfoDebug(SequenceNumber::from_u64(v)), + }, + }) + .await + .map_err(anyhow::Error::from); + let elapsed = start.elapsed().as_secs_f64(); + + let resp_version = resp.as_ref().ok().map(|r| r.object.version().value()); + ret.push((resp_version.map(SequenceNumber::from), resp, elapsed)); + + ret +} + +pub(crate) fn make_anemo_config() -> anemo_cli::Config { + use iota_network::{discovery::*, state_sync::*}; + use narwhal_types::*; + + // TODO: implement `ServiceInfo` generation in anemo-build and use here. + anemo_cli::Config::new() + // Narwhal primary-to-primary + .add_service( + "PrimaryToPrimary", + anemo_cli::ServiceInfo::new() + .add_method( + "SendCertificate", + anemo_cli::ron_method!( + PrimaryToPrimaryClient, + send_certificate, + SendCertificateRequest + ), + ) + .add_method( + "RequestVote", + anemo_cli::ron_method!( + PrimaryToPrimaryClient, + request_vote, + RequestVoteRequest + ), + ) + .add_method( + "FetchCertificates", + anemo_cli::ron_method!( + PrimaryToPrimaryClient, + fetch_certificates, + FetchCertificatesRequest + ), + ), + ) + // Narwhal worker-to-worker + .add_service( + "WorkerToWorker", + anemo_cli::ServiceInfo::new() + .add_method( + "ReportBatch", + anemo_cli::ron_method!(WorkerToWorkerClient, report_batch, WorkerBatchMessage), + ) + .add_method( + "RequestBatches", + anemo_cli::ron_method!( + WorkerToWorkerClient, + request_batches, + RequestBatchesRequest + ), + ), + ) + // Iota discovery + .add_service( + "Discovery", + anemo_cli::ServiceInfo::new().add_method( + "GetKnownPeers", + anemo_cli::ron_method!(DiscoveryClient, get_known_peers, ()), + ), + ) + // Iota state sync + .add_service( + "StateSync", + anemo_cli::ServiceInfo::new() + .add_method( + "PushCheckpointSummary", + anemo_cli::ron_method!( + StateSyncClient, + push_checkpoint_summary, + iota_types::messages_checkpoint::CertifiedCheckpointSummary + ), + ) + .add_method( + "GetCheckpointSummary", + anemo_cli::ron_method!( + StateSyncClient, + get_checkpoint_summary, + GetCheckpointSummaryRequest + ), + ) + .add_method( + "GetCheckpointContents", + anemo_cli::ron_method!( + StateSyncClient, + get_checkpoint_contents, + iota_types::messages_checkpoint::CheckpointContentsDigest + ), + ) + .add_method( + "GetCheckpointAvailability", + anemo_cli::ron_method!(StateSyncClient, get_checkpoint_availability, ()), + ), + ) +} + +fn copy_dir_all( + src: impl AsRef, + dst: impl AsRef, + skip: Vec, +) -> io::Result<()> { + fs::create_dir_all(&dst)?; + for entry in fs::read_dir(src)? { + let entry = entry?; + let ty = entry.file_type()?; + if skip.contains(&entry.path()) { + continue; + } + if ty.is_dir() { + copy_dir_all( + entry.path(), + dst.as_ref().join(entry.file_name()), + skip.clone(), + )?; + } else { + fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; + } + } + Ok(()) +} + +pub async fn restore_from_db_checkpoint( + config: &NodeConfig, + db_checkpoint_path: &Path, +) -> Result<(), anyhow::Error> { + copy_dir_all(db_checkpoint_path, config.db_path(), vec![])?; + Ok(()) +} + +fn start_summary_sync( + perpetual_db: Arc, + committee_store: Arc, + checkpoint_store: Arc, + m: MultiProgress, + genesis: Genesis, + archive_store_config: ObjectStoreConfig, + epoch: u64, + num_parallel_downloads: usize, + verify: bool, +) -> JoinHandle> { + tokio::spawn(async move { + info!("Starting summary sync"); + let store = + AuthorityStore::open_no_genesis(perpetual_db, usize::MAX, false, &Registry::default())?; + let state_sync_store = RocksDbStore::new( + Arc::new(ExecutionCache::new_for_tests(store, &Registry::default())), + committee_store, + checkpoint_store.clone(), + ); + // Only insert the genesis checkpoint if the DB is empty and doesn't have it + // already + if checkpoint_store + .get_checkpoint_by_digest(genesis.checkpoint().digest()) + .unwrap() + .is_none() + { + checkpoint_store.insert_checkpoint_contents(genesis.checkpoint_contents().clone())?; + checkpoint_store.insert_verified_checkpoint(&genesis.checkpoint())?; + checkpoint_store.update_highest_synced_checkpoint(&genesis.checkpoint())?; + } + // set up download of checkpoint summaries + let config = ArchiveReaderConfig { + remote_store_config: archive_store_config, + download_concurrency: NonZeroUsize::new(num_parallel_downloads).unwrap(), + use_for_pruning_watermark: false, + }; + let metrics = ArchiveReaderMetrics::new(&Registry::default()); + let archive_reader = ArchiveReader::new(config, &metrics)?; + archive_reader.sync_manifest_once().await?; + let manifest = archive_reader.get_manifest().await?; + + let last_checkpoint = manifest.next_checkpoint_after_epoch(epoch) - 1; + let sync_progress_bar = m.add( + ProgressBar::new(last_checkpoint).with_style( + ProgressStyle::with_template("[{elapsed_precise}] {wide_bar} {pos}/{len}({msg})") + .unwrap(), + ), + ); + let cloned_progress_bar = sync_progress_bar.clone(); + let sync_checkpoint_counter = Arc::new(AtomicU64::new(0)); + let s_instant = Instant::now(); + + let cloned_counter = sync_checkpoint_counter.clone(); + let latest_synced = checkpoint_store + .get_highest_synced_checkpoint()? + .map(|c| c.sequence_number) + .unwrap_or(0); + let s_start = latest_synced + .checked_add(1) + .context("Checkpoint overflow") + .map_err(|_| anyhow!("Failed to increment checkpoint"))?; + tokio::spawn(async move { + loop { + if cloned_progress_bar.is_finished() { + break; + } + let num_summaries = cloned_counter.load(Ordering::Relaxed); + let total_checkpoints_per_sec = + num_summaries as f64 / s_instant.elapsed().as_secs_f64(); + cloned_progress_bar.set_position(s_start + num_summaries); + cloned_progress_bar.set_message(format!( + "checkpoints synced per sec: {}", + total_checkpoints_per_sec + )); + tokio::time::sleep(Duration::from_secs(1)).await; + } + }); + + let sync_range = s_start..last_checkpoint + 1; + archive_reader + .read_summaries( + state_sync_store.clone(), + sync_range.clone(), + sync_checkpoint_counter, + // rather than blocking on verify, sync all summaries first, then verify later + false, + ) + .await?; + sync_progress_bar.finish_with_message("Checkpoint summary sync is complete"); + + // verify checkpoint summaries + if verify { + let v_start = s_start; + // update highest verified to be highest synced. We will move back + // iff parallel verification succeeds + let latest_verified = checkpoint_store + .get_checkpoint_by_sequence_number(latest_synced) + .expect("Failed to get checkpoint") + .expect("Expected checkpoint to exist after summary sync"); + checkpoint_store + .update_highest_verified_checkpoint(&latest_verified) + .expect("Failed to update highest verified checkpoint"); + let verify_progress_bar = m.add( + ProgressBar::new(last_checkpoint).with_style( + ProgressStyle::with_template( + "[{elapsed_precise}] {wide_bar} {pos}/{len}({msg})", + ) + .unwrap(), + ), + ); + let cloned_verify_progress_bar = verify_progress_bar.clone(); + let verify_checkpoint_counter = Arc::new(AtomicU64::new(0)); + let cloned_verify_counter = verify_checkpoint_counter.clone(); + let v_instant = Instant::now(); + + tokio::spawn(async move { + loop { + if cloned_verify_progress_bar.is_finished() { + break; + } + let num_summaries = cloned_verify_counter.load(Ordering::Relaxed); + let total_checkpoints_per_sec = + num_summaries as f64 / v_instant.elapsed().as_secs_f64(); + cloned_verify_progress_bar.set_position(v_start + num_summaries); + cloned_verify_progress_bar.set_message(format!( + "checkpoints verified per sec: {}", + total_checkpoints_per_sec + )); + tokio::time::sleep(Duration::from_secs(1)).await; + } + }); + + let verify_range = v_start..last_checkpoint + 1; + verify_checkpoint_range( + verify_range, + state_sync_store, + verify_checkpoint_counter, + num_parallel_downloads, + ) + .await; + verify_progress_bar.finish_with_message("Checkpoint summary verification is complete"); + } + + let checkpoint = checkpoint_store + .get_checkpoint_by_sequence_number(last_checkpoint)? + .ok_or(anyhow!("Failed to read last checkpoint"))?; + + checkpoint_store.update_highest_verified_checkpoint(&checkpoint)?; + checkpoint_store.update_highest_synced_checkpoint(&checkpoint)?; + checkpoint_store.update_highest_executed_checkpoint(&checkpoint)?; + checkpoint_store.update_highest_pruned_checkpoint(&checkpoint)?; + Ok::<(), anyhow::Error>(()) + }) +} + +pub async fn get_latest_available_epoch( + snapshot_store_config: &ObjectStoreConfig, +) -> Result { + let remote_object_store = if snapshot_store_config.no_sign_request { + snapshot_store_config.make_http()? + } else { + snapshot_store_config.make().map(Arc::new)? + }; + let manifest_contents = remote_object_store + .get_bytes(&get_path(MANIFEST_FILENAME)) + .await?; + let root_manifest: Manifest = serde_json::from_slice(&manifest_contents) + .map_err(|err| anyhow!("Error parsing MANIFEST from bytes: {}", err))?; + let epoch = root_manifest + .available_epochs + .iter() + .max() + .ok_or(anyhow!("No snapshot found in manifest"))?; + Ok(*epoch) +} + +pub async fn check_completed_snapshot( + snapshot_store_config: &ObjectStoreConfig, + epoch: EpochId, +) -> Result<(), anyhow::Error> { + let success_marker = format!("epoch_{}/_SUCCESS", epoch); + let remote_object_store = if snapshot_store_config.no_sign_request { + snapshot_store_config.make_http()? + } else { + snapshot_store_config.make().map(Arc::new)? + }; + if exists(&remote_object_store, &get_path(success_marker.as_str())).await { + Ok(()) + } else { + Err(anyhow!( + "missing success marker at {}/{}", + snapshot_store_config.bucket.as_ref().unwrap_or( + &snapshot_store_config + .clone() + .aws_endpoint + .unwrap_or("unknown_bucket".to_string()) + ), + success_marker + )) + } +} + +pub async fn download_formal_snapshot( + path: &Path, + epoch: EpochId, + genesis: &Path, + snapshot_store_config: ObjectStoreConfig, + archive_store_config: ObjectStoreConfig, + num_parallel_downloads: usize, + network: Chain, + verify: bool, +) -> Result<(), anyhow::Error> { + eprintln!( + "Beginning formal snapshot restore to end of epoch {}, network: {:?}", + epoch, network, + ); + let path = path.join("staging").to_path_buf(); + if path.exists() { + fs::remove_dir_all(path.clone())?; + } + let perpetual_db = Arc::new(AuthorityPerpetualTables::open(&path.join("store"), None)); + let genesis = Genesis::load(genesis).unwrap(); + let genesis_committee = genesis.committee()?; + let committee_store = Arc::new(CommitteeStore::new( + path.join("epochs"), + &genesis_committee, + None, + )); + let checkpoint_store = Arc::new(CheckpointStore::open_tables_read_write( + path.join("checkpoints"), + MetricConf::default(), + None, + None, + )); + + let m = MultiProgress::new(); + let summaries_handle = start_summary_sync( + perpetual_db.clone(), + committee_store.clone(), + checkpoint_store.clone(), + m.clone(), + genesis.clone(), + archive_store_config.clone(), + epoch, + num_parallel_downloads, + verify, + ); + let (_abort_handle, abort_registration) = AbortHandle::new_pair(); + let perpetual_db_clone = perpetual_db.clone(); + let snapshot_dir = path.parent().unwrap().join("snapshot"); + if snapshot_dir.exists() { + fs::remove_dir_all(snapshot_dir.clone())?; + } + let snapshot_dir_clone = snapshot_dir.clone(); + + // TODO if verify is false, we should skip generating these and + // not pass in a channel to the reader + let (sender, mut receiver) = mpsc::channel(num_parallel_downloads); + + let snapshot_handle = tokio::spawn(async move { + let local_store_config = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(snapshot_dir_clone.to_path_buf()), + ..Default::default() + }; + let mut reader = StateSnapshotReaderV1::new( + epoch, + &snapshot_store_config, + &local_store_config, + usize::MAX, + NonZeroUsize::new(num_parallel_downloads).unwrap(), + m, + ) + .await + .unwrap_or_else(|err| panic!("Failed to create reader: {}", err)); + reader + .read(&perpetual_db_clone, abort_registration, Some(sender)) + .await + .unwrap_or_else(|err| panic!("Failed during read: {}", err)); + Ok::<(), anyhow::Error>(()) + }); + let mut root_accumulator = Accumulator::default(); + while let Some(partial_acc) = receiver.recv().await { + root_accumulator.union(&partial_acc); + } + summaries_handle + .await + .expect("Task join failed") + .expect("Summaries task failed"); + + let last_checkpoint = checkpoint_store + .get_highest_verified_checkpoint()? + .expect("Expected nonempty checkpoint store"); + + // Perform snapshot state verification + if verify { + assert_eq!( + last_checkpoint.epoch(), + epoch, + "Expected highest verified checkpoint ({}) to be for epoch {} but was for epoch {}", + last_checkpoint.sequence_number, + epoch, + last_checkpoint.epoch() + ); + let commitment = last_checkpoint + .end_of_epoch_data + .as_ref() + .expect("Expected highest verified checkpoint to have end of epoch data") + .epoch_commitments + .last() + .expect( + "End of epoch has no commitments. This likely means that the epoch \ + you are attempting to restore from does not support end of epoch state \ + digest commitment. If restoring from mainnet, `--epoch` must be > 20, \ + and for testnet, `--epoch` must be > 12.", + ); + match commitment { + CheckpointCommitment::ECMHLiveObjectSetDigest(consensus_digest) => { + let local_digest: ECMHLiveObjectSetDigest = root_accumulator.digest().into(); + assert_eq!( + *consensus_digest, local_digest, + "End of epoch {} root state digest {} does not match \ + local root state hash {} after restoring from formal snapshot", + epoch, consensus_digest.digest, local_digest.digest, + ); + eprintln!("Formal snapshot state verification completed successfully!"); + } + }; + } else { + eprintln!( + "WARNING: Skipping snapshot verification! \ + This is highly discouraged unless you fully trust the source of this snapshot and its contents. + If this was unintentional, rerun with `--verify` set to `true`" + ); + } + + snapshot_handle + .await + .expect("Task join failed") + .expect("Snapshot restore task failed"); + + // TODO we should ensure this map is being updated for all end of epoch + // checkpoints during summary sync. This happens in + // `insert_{verified|certified}_checkpoint` in checkpoint store, but not in + // the corresponding functions in ObjectStore trait + checkpoint_store.insert_epoch_last_checkpoint(epoch, &last_checkpoint)?; + + setup_db_state( + epoch, + root_accumulator, + perpetual_db, + checkpoint_store, + committee_store, + ) + .await?; + + let new_path = path.parent().unwrap().join("live"); + if new_path.exists() { + fs::remove_dir_all(new_path.clone())?; + } + fs::rename(&path, &new_path)?; + fs::remove_dir_all(snapshot_dir.clone())?; + info!( + "Successfully restored state from snapshot at end of epoch {}", + epoch + ); + + Ok(()) +} + +pub async fn download_db_snapshot( + path: &Path, + epoch: u64, + snapshot_store_config: ObjectStoreConfig, + skip_indexes: bool, + num_parallel_downloads: usize, +) -> Result<(), anyhow::Error> { + let remote_store = if snapshot_store_config.no_sign_request { + snapshot_store_config.make_http()? + } else { + snapshot_store_config.make().map(Arc::new)? + }; + + // We rely on the top level MANIFEST file which contains all valid epochs + let manifest_contents = remote_store.get_bytes(&get_path(MANIFEST_FILENAME)).await?; + let root_manifest: Manifest = serde_json::from_slice(&manifest_contents) + .map_err(|err| anyhow!("Error parsing MANIFEST from bytes: {}", err))?; + + if !root_manifest.epoch_exists(epoch) { + return Err(anyhow!( + "Epoch dir {} doesn't exist on the remote store", + epoch + )); + } + + let epoch_path = format!("epoch_{}", epoch); + let epoch_dir = get_path(&epoch_path); + + let manifest_file = epoch_dir.child(MANIFEST_FILENAME); + let epoch_manifest_contents = + String::from_utf8(remote_store.get_bytes(&manifest_file).await?.to_vec()) + .map_err(|err| anyhow!("Error parsing {}/MANIFEST from bytes: {}", epoch_path, err))?; + + let epoch_manifest = + PerEpochManifest::deserialize_from_newline_delimited(&epoch_manifest_contents); + + let mut files: Vec = vec![]; + files.extend(epoch_manifest.filter_by_prefix("store/perpetual").lines); + files.extend(epoch_manifest.filter_by_prefix("epochs").lines); + files.extend(epoch_manifest.filter_by_prefix("checkpoints").lines); + if !skip_indexes { + files.extend(epoch_manifest.filter_by_prefix("indexes").lines) + } + let local_store = ObjectStoreConfig { + object_store: Some(ObjectStoreType::File), + directory: Some(path.to_path_buf()), + ..Default::default() + } + .make()?; + let m = MultiProgress::new(); + let path = path.to_path_buf(); + let snapshot_handle = tokio::spawn(async move { + let progress_bar = m.add( + ProgressBar::new(files.len() as u64).with_style( + ProgressStyle::with_template( + "[{elapsed_precise}] {wide_bar} {pos} out of {len} files done\n({msg})", + ) + .unwrap(), + ), + ); + let cloned_progress_bar = progress_bar.clone(); + let file_counter = Arc::new(AtomicUsize::new(0)); + futures::stream::iter(files.iter()) + .map(|file| { + let local_store = local_store.clone(); + let remote_store = remote_store.clone(); + let counter_cloned = file_counter.clone(); + async move { + counter_cloned.fetch_add(1, Ordering::Relaxed); + let file_path = get_path(format!("epoch_{}/{}", epoch, file).as_str()); + copy_file(&file_path, &file_path, &remote_store, &local_store).await?; + Ok::<::object_store::path::Path, anyhow::Error>(file_path.clone()) + } + }) + .boxed() + .buffer_unordered(num_parallel_downloads) + .try_for_each(|path| { + file_counter.fetch_sub(1, Ordering::Relaxed); + cloned_progress_bar.inc(1); + cloned_progress_bar.set_message(format!( + "Downloading file: {}, #downloads_in_progress: {}", + path, + file_counter.load(Ordering::Relaxed) + )); + futures::future::ready(Ok(())) + }) + .await?; + progress_bar.finish_with_message("Snapshot file download is complete"); + Ok::<(), anyhow::Error>(()) + }); + + let tasks: Vec<_> = vec![Box::pin(snapshot_handle)]; + join_all(tasks) + .await + .into_iter() + .collect::, _>>()? + .into_iter() + .for_each(|result| result.expect("Task failed")); + + let store_dir = path.join("store"); + if store_dir.exists() { + fs::remove_dir_all(&store_dir)?; + } + let epochs_dir = path.join("epochs"); + if epochs_dir.exists() { + fs::remove_dir_all(&epochs_dir)?; + } + Ok(()) +} + +pub async fn verify_archive( + genesis: &Path, + remote_store_config: ObjectStoreConfig, + concurrency: usize, + interactive: bool, +) -> Result<()> { + verify_archive_with_genesis_config(genesis, remote_store_config, concurrency, interactive, 10) + .await +} + +pub async fn dump_checkpoints_from_archive( + remote_store_config: ObjectStoreConfig, + start_checkpoint: u64, + end_checkpoint: u64, + max_content_length: usize, +) -> Result<()> { + let metrics = ArchiveReaderMetrics::new(&Registry::default()); + let config = ArchiveReaderConfig { + remote_store_config, + download_concurrency: NonZeroUsize::new(1).unwrap(), + use_for_pruning_watermark: false, + }; + let store = SharedInMemoryStore::default(); + let archive_reader = ArchiveReader::new(config, &metrics)?; + archive_reader.sync_manifest_once().await?; + let checkpoint_counter = Arc::new(AtomicU64::new(0)); + let txn_counter = Arc::new(AtomicU64::new(0)); + archive_reader + .read( + store.clone(), + Range { + start: start_checkpoint, + end: end_checkpoint, + }, + txn_counter, + checkpoint_counter, + false, + ) + .await?; + for key in store + .inner() + .checkpoints() + .values() + .sorted_by(|a, b| a.sequence_number().cmp(&b.sequence_number)) + { + let mut content = serde_json::to_string( + &store + .get_full_checkpoint_contents_by_sequence_number(key.sequence_number)? + .unwrap(), + )?; + content.truncate(max_content_length); + info!( + "{}:{}:{:?}", + key.sequence_number, key.content_digest, content + ); + } + Ok(()) +} + +pub async fn verify_archive_by_checksum( + remote_store_config: ObjectStoreConfig, + concurrency: usize, +) -> Result<()> { + verify_archive_with_checksums(remote_store_config, concurrency).await +} diff --git a/crates/iota-tool/src/main.rs b/crates/iota-tool/src/main.rs new file mode 100644 index 00000000000..6fb03966494 --- /dev/null +++ b/crates/iota-tool/src/main.rs @@ -0,0 +1,22 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +extern crate core; + +use clap::*; +use colored::Colorize; +use iota_tool::commands::ToolCommand; +use iota_types::exit_main; + +#[tokio::main] +async fn main() { + #[cfg(windows)] + colored::control::set_virtual_terminal(true).unwrap(); + + let cmd: ToolCommand = ToolCommand::parse(); + let (_guards, handle) = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .init(); + + exit_main!(cmd.execute(handle).await); +} diff --git a/crates/sui-tool/src/pkg_dump.rs b/crates/iota-tool/src/pkg_dump.rs similarity index 91% rename from crates/sui-tool/src/pkg_dump.rs rename to crates/iota-tool/src/pkg_dump.rs index fce4bec9876..baf9cc5b990 100644 --- a/crates/sui-tool/src/pkg_dump.rs +++ b/crates/iota-tool/src/pkg_dump.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -13,8 +14,8 @@ use diesel::{ r2d2::{ConnectionManager, Pool}, PgConnection, RunQueryDsl, }; -use sui_indexer::{models::packages::StoredPackage, schema::packages}; -use sui_types::{base_types::SuiAddress, move_package::MovePackage}; +use iota_indexer::{models::packages::StoredPackage, schema::packages}; +use iota_types::{base_types::IotaAddress, move_package::MovePackage}; use tracing::info; type PgPool = Pool>; @@ -41,7 +42,7 @@ pub(crate) async fn dump(db_url: String, output_dir: PathBuf) -> Result<()> { progress = pct; } - let id = SuiAddress::from_bytes(&pkg.package_id).context("Parsing package ID")?; + let id = IotaAddress::from_bytes(&pkg.package_id).context("Parsing package ID")?; dump_package(&output_dir, id, &pkg.move_package) .with_context(|| format!("Dumping package: {id}"))?; } @@ -87,7 +88,7 @@ fn query_packages(pool: &PgPool) -> Result> { Ok(packages::dsl::packages.load::(&mut conn)?) } -fn dump_package(output_dir: &Path, id: SuiAddress, pkg: &[u8]) -> Result<()> { +fn dump_package(output_dir: &Path, id: IotaAddress, pkg: &[u8]) -> Result<()> { let package = bcs::from_bytes::(pkg).context("Deserializing")?; let origins: BTreeMap<_, _> = package .type_origin_table() diff --git a/crates/iota-transaction-builder/Cargo.toml b/crates/iota-transaction-builder/Cargo.toml new file mode 100644 index 00000000000..2a84516a92f --- /dev/null +++ b/crates/iota-transaction-builder/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "iota-transaction-builder" +version = "0.0.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anyhow.workspace = true +async-trait.workspace = true +futures.workspace = true +bcs.workspace = true + +move-binary-format.workspace = true +iota-json-rpc-types.workspace = true +iota-types.workspace = true +iota-json.workspace = true +iota-protocol-config.workspace = true + +move-core-types.workspace = true diff --git a/crates/iota-transaction-builder/src/lib.rs b/crates/iota-transaction-builder/src/lib.rs new file mode 100644 index 00000000000..43f21813e9b --- /dev/null +++ b/crates/iota-transaction-builder/src/lib.rs @@ -0,0 +1,894 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::BTreeMap, result::Result, str::FromStr, sync::Arc}; + +use anyhow::{anyhow, bail, ensure, Ok}; +use async_trait::async_trait; +use futures::future::join_all; +use iota_json::{ + is_receiving_argument, resolve_move_function_args, IotaJsonValue, ResolvedCallArg, +}; +use iota_json_rpc_types::{ + IotaData, IotaObjectDataOptions, IotaObjectResponse, IotaRawData, IotaTypeTag, + RPCTransactionRequestParams, +}; +use iota_protocol_config::ProtocolConfig; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectInfo, ObjectRef, ObjectType}, + coin, + error::UserInputError, + fp_ensure, + gas_coin::GasCoin, + governance::{ADD_STAKE_MUL_COIN_FUN_NAME, WITHDRAW_STAKE_FUN_NAME}, + iota_system_state::IOTA_SYSTEM_MODULE_NAME, + move_package::MovePackage, + object::{Object, Owner}, + programmable_transaction_builder::ProgrammableTransactionBuilder, + timelock::timelocked_staking::{ + ADD_TIMELOCKED_STAKE_FUN_NAME, TIMELOCKED_STAKING_MODULE_NAME, + WITHDRAW_TIMELOCKED_STAKE_FUN_NAME, + }, + transaction::{ + Argument, CallArg, Command, InputObjectKind, ObjectArg, TransactionData, TransactionKind, + }, + IOTA_FRAMEWORK_PACKAGE_ID, IOTA_SYSTEM_PACKAGE_ID, TIMELOCK_PACKAGE_ID, +}; +use move_binary_format::{ + binary_config::BinaryConfig, binary_views::BinaryIndexedView, file_format::SignatureToken, +}; +use move_core_types::{ + identifier::Identifier, + language_storage::{StructTag, TypeTag}, +}; + +#[async_trait] +pub trait DataReader { + async fn get_owned_objects( + &self, + address: IotaAddress, + object_type: StructTag, + ) -> Result, anyhow::Error>; + + async fn get_object_with_options( + &self, + object_id: ObjectID, + options: IotaObjectDataOptions, + ) -> Result; + + async fn get_reference_gas_price(&self) -> Result; +} + +#[derive(Clone)] +pub struct TransactionBuilder(Arc); + +impl TransactionBuilder { + pub fn new(data_reader: Arc) -> Self { + Self(data_reader) + } + + async fn select_gas( + &self, + signer: IotaAddress, + input_gas: Option, + budget: u64, + input_objects: Vec, + gas_price: u64, + ) -> Result { + if budget < gas_price { + bail!( + "Gas budget {budget} is less than the reference gas price {gas_price}. The gas budget must be at least the current reference gas price of {gas_price}." + ) + } + if let Some(gas) = input_gas { + self.get_object_ref(gas).await + } else { + let gas_objs = self.0.get_owned_objects(signer, GasCoin::type_()).await?; + + for obj in gas_objs { + let response = self + .0 + .get_object_with_options(obj.object_id, IotaObjectDataOptions::new().with_bcs()) + .await?; + let obj = response.object()?; + let gas: GasCoin = bcs::from_bytes( + &obj.bcs + .as_ref() + .ok_or_else(|| anyhow!("bcs field is unexpectedly empty"))? + .try_as_move() + .ok_or_else(|| anyhow!("Cannot parse move object to gas object"))? + .bcs_bytes, + )?; + if !input_objects.contains(&obj.object_id) && gas.value() >= budget { + return Ok(obj.object_ref()); + } + } + Err(anyhow!( + "Cannot find gas coin for signer address [{signer}] with amount sufficient for the required gas amount [{budget}]." + )) + } + } + + pub async fn transfer_object( + &self, + signer: IotaAddress, + object_id: ObjectID, + gas: Option, + gas_budget: u64, + recipient: IotaAddress, + ) -> anyhow::Result { + let mut builder = ProgrammableTransactionBuilder::new(); + self.single_transfer_object(&mut builder, object_id, recipient) + .await?; + let gas_price = self.0.get_reference_gas_price().await?; + let gas = self + .select_gas(signer, gas, gas_budget, vec![object_id], gas_price) + .await?; + + Ok(TransactionData::new( + TransactionKind::programmable(builder.finish()), + signer, + gas, + gas_budget, + gas_price, + )) + } + + async fn single_transfer_object( + &self, + builder: &mut ProgrammableTransactionBuilder, + object_id: ObjectID, + recipient: IotaAddress, + ) -> anyhow::Result<()> { + builder.transfer_object(recipient, self.get_object_ref(object_id).await?)?; + Ok(()) + } + + pub async fn transfer_iota( + &self, + signer: IotaAddress, + iota_object_id: ObjectID, + gas_budget: u64, + recipient: IotaAddress, + amount: Option, + ) -> anyhow::Result { + let object = self.get_object_ref(iota_object_id).await?; + let gas_price = self.0.get_reference_gas_price().await?; + Ok(TransactionData::new_transfer_iota( + recipient, signer, amount, object, gas_budget, gas_price, + )) + } + + pub async fn pay( + &self, + signer: IotaAddress, + input_coins: Vec, + recipients: Vec, + amounts: Vec, + gas: Option, + gas_budget: u64, + ) -> anyhow::Result { + if let Some(gas) = gas { + if input_coins.contains(&gas) { + return Err(anyhow!( + "Gas coin is in input coins of Pay transaction, use PayIota transaction instead!" + )); + } + } + + let handles: Vec<_> = input_coins + .iter() + .map(|id| self.get_object_ref(*id)) + .collect(); + let coin_refs = join_all(handles) + .await + .into_iter() + .collect::>>()?; + let gas_price = self.0.get_reference_gas_price().await?; + let gas = self + .select_gas(signer, gas, gas_budget, input_coins, gas_price) + .await?; + + TransactionData::new_pay( + signer, coin_refs, recipients, amounts, gas, gas_budget, gas_price, + ) + } + + pub async fn pay_iota( + &self, + signer: IotaAddress, + input_coins: Vec, + recipients: Vec, + amounts: Vec, + gas_budget: u64, + ) -> anyhow::Result { + fp_ensure!( + !input_coins.is_empty(), + UserInputError::EmptyInputCoins.into() + ); + + let handles: Vec<_> = input_coins + .into_iter() + .map(|id| self.get_object_ref(id)) + .collect(); + let mut coin_refs = join_all(handles) + .await + .into_iter() + .collect::>>()?; + // [0] is safe because input_coins is non-empty and coins are of same length as + // input_coins. + let gas_object_ref = coin_refs.remove(0); + let gas_price = self.0.get_reference_gas_price().await?; + TransactionData::new_pay_iota( + signer, + coin_refs, + recipients, + amounts, + gas_object_ref, + gas_budget, + gas_price, + ) + } + + pub async fn pay_all_iota( + &self, + signer: IotaAddress, + input_coins: Vec, + recipient: IotaAddress, + gas_budget: u64, + ) -> anyhow::Result { + fp_ensure!( + !input_coins.is_empty(), + UserInputError::EmptyInputCoins.into() + ); + + let handles: Vec<_> = input_coins + .into_iter() + .map(|id| self.get_object_ref(id)) + .collect(); + + let mut coin_refs = join_all(handles) + .await + .into_iter() + .collect::>>()?; + // [0] is safe because input_coins is non-empty and coins are of same length as + // input_coins. + let gas_object_ref = coin_refs.remove(0); + let gas_price = self.0.get_reference_gas_price().await?; + Ok(TransactionData::new_pay_all_iota( + signer, + coin_refs, + recipient, + gas_object_ref, + gas_budget, + gas_price, + )) + } + + pub async fn move_call( + &self, + signer: IotaAddress, + package_object_id: ObjectID, + module: &str, + function: &str, + type_args: Vec, + call_args: Vec, + gas: Option, + gas_budget: u64, + gas_price: Option, + ) -> anyhow::Result { + let mut builder = ProgrammableTransactionBuilder::new(); + self.single_move_call( + &mut builder, + package_object_id, + module, + function, + type_args, + call_args, + ) + .await?; + let pt = builder.finish(); + let input_objects = pt + .input_objects()? + .iter() + .flat_map(|obj| match obj { + InputObjectKind::ImmOrOwnedMoveObject((id, _, _)) => Some(*id), + _ => None, + }) + .collect(); + let gas_price = if let Some(gas_price) = gas_price { + gas_price + } else { + self.0.get_reference_gas_price().await? + }; + let gas = self + .select_gas(signer, gas, gas_budget, input_objects, gas_price) + .await?; + + Ok(TransactionData::new( + TransactionKind::programmable(pt), + signer, + gas, + gas_budget, + gas_price, + )) + } + + pub async fn single_move_call( + &self, + builder: &mut ProgrammableTransactionBuilder, + package: ObjectID, + module: &str, + function: &str, + type_args: Vec, + call_args: Vec, + ) -> anyhow::Result<()> { + let module = Identifier::from_str(module)?; + let function = Identifier::from_str(function)?; + + let type_args = type_args + .into_iter() + .map(|ty| ty.try_into()) + .collect::, _>>()?; + + let call_args = self + .resolve_and_checks_json_args( + builder, package, &module, &function, &type_args, call_args, + ) + .await?; + + builder.command(Command::move_call( + package, module, function, type_args, call_args, + )); + Ok(()) + } + + async fn get_object_arg( + &self, + id: ObjectID, + objects: &mut BTreeMap, + is_mutable_ref: bool, + view: &BinaryIndexedView<'_>, + arg_type: &SignatureToken, + ) -> Result { + let response = self + .0 + .get_object_with_options(id, IotaObjectDataOptions::bcs_lossless()) + .await?; + + let obj: Object = response.into_object()?.try_into()?; + let obj_ref = obj.compute_object_reference(); + let owner = obj.owner; + objects.insert(id, obj); + if is_receiving_argument(view, arg_type) { + return Ok(ObjectArg::Receiving(obj_ref)); + } + Ok(match owner { + Owner::Shared { + initial_shared_version, + } => ObjectArg::SharedObject { + id, + initial_shared_version, + mutable: is_mutable_ref, + }, + Owner::AddressOwner(_) | Owner::ObjectOwner(_) | Owner::Immutable => { + ObjectArg::ImmOrOwnedObject(obj_ref) + } + }) + } + + async fn resolve_and_checks_json_args( + &self, + builder: &mut ProgrammableTransactionBuilder, + package_id: ObjectID, + module: &Identifier, + function: &Identifier, + type_args: &[TypeTag], + json_args: Vec, + ) -> Result, anyhow::Error> { + let object = self + .0 + .get_object_with_options(package_id, IotaObjectDataOptions::bcs_lossless()) + .await? + .into_object()?; + let Some(IotaRawData::Package(package)) = object.bcs else { + bail!( + "Bcs field in object [{}] is missing or not a package.", + package_id + ); + }; + let package: MovePackage = MovePackage::new( + package.id, + object.version, + package.module_map, + ProtocolConfig::get_for_min_version().max_move_package_size(), + package.type_origin_table, + package.linkage_table, + )?; + + let json_args_and_tokens = resolve_move_function_args( + &package, + module.clone(), + function.clone(), + type_args, + json_args, + )?; + + let mut args = Vec::new(); + let mut objects = BTreeMap::new(); + let module = package.deserialize_module(module, &BinaryConfig::standard())?; + let view = BinaryIndexedView::Module(&module); + for (arg, expected_type) in json_args_and_tokens { + args.push(match arg { + ResolvedCallArg::Pure(p) => builder.input(CallArg::Pure(p)), + + ResolvedCallArg::Object(id) => builder.input(CallArg::Object( + self.get_object_arg( + id, + &mut objects, + // Is mutable if passed by mutable reference or by value + matches!(expected_type, SignatureToken::MutableReference(_)) + || !expected_type.is_reference(), + &view, + &expected_type, + ) + .await?, + )), + + ResolvedCallArg::ObjVec(v) => { + let mut object_ids = vec![]; + for id in v { + object_ids.push( + self.get_object_arg( + id, + &mut objects, + // is_mutable_ref + false, + &view, + &expected_type, + ) + .await?, + ) + } + builder.make_obj_vec(object_ids) + } + }?); + } + + Ok(args) + } + + pub async fn publish( + &self, + sender: IotaAddress, + compiled_modules: Vec>, + dep_ids: Vec, + gas: Option, + gas_budget: u64, + ) -> anyhow::Result { + let gas_price = self.0.get_reference_gas_price().await?; + let gas = self + .select_gas(sender, gas, gas_budget, vec![], gas_price) + .await?; + Ok(TransactionData::new_module( + sender, + gas, + compiled_modules, + dep_ids, + gas_budget, + gas_price, + )) + } + + pub async fn upgrade( + &self, + sender: IotaAddress, + package_id: ObjectID, + compiled_modules: Vec>, + dep_ids: Vec, + upgrade_capability: ObjectID, + upgrade_policy: u8, + digest: Vec, + gas: Option, + gas_budget: u64, + ) -> anyhow::Result { + let gas_price = self.0.get_reference_gas_price().await?; + let gas = self + .select_gas(sender, gas, gas_budget, vec![], gas_price) + .await?; + let upgrade_cap = self + .0 + .get_object_with_options( + upgrade_capability, + IotaObjectDataOptions::new().with_owner(), + ) + .await? + .into_object()?; + let cap_owner = upgrade_cap + .owner + .ok_or_else(|| anyhow!("Unable to determine ownership of upgrade capability"))?; + TransactionData::new_upgrade( + sender, + gas, + package_id, + compiled_modules, + dep_ids, + (upgrade_cap.object_ref(), cap_owner), + upgrade_policy, + digest, + gas_budget, + gas_price, + ) + } + + // TODO: consolidate this with Pay transactions + pub async fn split_coin( + &self, + signer: IotaAddress, + coin_object_id: ObjectID, + split_amounts: Vec, + gas: Option, + gas_budget: u64, + ) -> anyhow::Result { + let coin = self + .0 + .get_object_with_options(coin_object_id, IotaObjectDataOptions::bcs_lossless()) + .await? + .into_object()?; + let coin_object_ref = coin.object_ref(); + let coin: Object = coin.try_into()?; + let type_args = vec![coin.get_move_template_type()?]; + let gas_price = self.0.get_reference_gas_price().await?; + let gas = self + .select_gas(signer, gas, gas_budget, vec![coin_object_id], gas_price) + .await?; + + TransactionData::new_move_call( + signer, + IOTA_FRAMEWORK_PACKAGE_ID, + coin::PAY_MODULE_NAME.to_owned(), + coin::PAY_SPLIT_VEC_FUNC_NAME.to_owned(), + type_args, + gas, + vec![ + CallArg::Object(ObjectArg::ImmOrOwnedObject(coin_object_ref)), + CallArg::Pure(bcs::to_bytes(&split_amounts)?), + ], + gas_budget, + gas_price, + ) + } + + // TODO: consolidate this with Pay transactions + pub async fn split_coin_equal( + &self, + signer: IotaAddress, + coin_object_id: ObjectID, + split_count: u64, + gas: Option, + gas_budget: u64, + ) -> anyhow::Result { + let coin = self + .0 + .get_object_with_options(coin_object_id, IotaObjectDataOptions::bcs_lossless()) + .await? + .into_object()?; + let coin_object_ref = coin.object_ref(); + let coin: Object = coin.try_into()?; + let type_args = vec![coin.get_move_template_type()?]; + let gas_price = self.0.get_reference_gas_price().await?; + let gas = self + .select_gas(signer, gas, gas_budget, vec![coin_object_id], gas_price) + .await?; + + TransactionData::new_move_call( + signer, + IOTA_FRAMEWORK_PACKAGE_ID, + coin::PAY_MODULE_NAME.to_owned(), + coin::PAY_SPLIT_N_FUNC_NAME.to_owned(), + type_args, + gas, + vec![ + CallArg::Object(ObjectArg::ImmOrOwnedObject(coin_object_ref)), + CallArg::Pure(bcs::to_bytes(&split_count)?), + ], + gas_budget, + gas_price, + ) + } + + // TODO: consolidate this with Pay transactions + pub async fn merge_coins( + &self, + signer: IotaAddress, + primary_coin: ObjectID, + coin_to_merge: ObjectID, + gas: Option, + gas_budget: u64, + ) -> anyhow::Result { + let coin = self + .0 + .get_object_with_options(primary_coin, IotaObjectDataOptions::bcs_lossless()) + .await? + .into_object()?; + let primary_coin_ref = coin.object_ref(); + let coin_to_merge_ref = self.get_object_ref(coin_to_merge).await?; + let coin: Object = coin.try_into()?; + let type_args = vec![coin.get_move_template_type()?]; + let gas_price = self.0.get_reference_gas_price().await?; + let gas = self + .select_gas( + signer, + gas, + gas_budget, + vec![primary_coin, coin_to_merge], + gas_price, + ) + .await?; + + TransactionData::new_move_call( + signer, + IOTA_FRAMEWORK_PACKAGE_ID, + coin::PAY_MODULE_NAME.to_owned(), + coin::PAY_JOIN_FUNC_NAME.to_owned(), + type_args, + gas, + vec![ + CallArg::Object(ObjectArg::ImmOrOwnedObject(primary_coin_ref)), + CallArg::Object(ObjectArg::ImmOrOwnedObject(coin_to_merge_ref)), + ], + gas_budget, + gas_price, + ) + } + + pub async fn batch_transaction( + &self, + signer: IotaAddress, + single_transaction_params: Vec, + gas: Option, + gas_budget: u64, + ) -> anyhow::Result { + fp_ensure!( + !single_transaction_params.is_empty(), + UserInputError::InvalidBatchTransaction { + error: "Batch Transaction cannot be empty".to_owned(), + } + .into() + ); + let mut builder = ProgrammableTransactionBuilder::new(); + for param in single_transaction_params { + match param { + RPCTransactionRequestParams::TransferObjectRequestParams(param) => { + self.single_transfer_object(&mut builder, param.object_id, param.recipient) + .await? + } + RPCTransactionRequestParams::MoveCallRequestParams(param) => { + self.single_move_call( + &mut builder, + param.package_object_id, + ¶m.module, + ¶m.function, + param.type_arguments, + param.arguments, + ) + .await? + } + }; + } + let pt = builder.finish(); + let all_inputs = pt.input_objects()?; + let inputs = all_inputs + .iter() + .flat_map(|obj| match obj { + InputObjectKind::ImmOrOwnedMoveObject((id, _, _)) => Some(*id), + _ => None, + }) + .collect(); + let gas_price = self.0.get_reference_gas_price().await?; + let gas = self + .select_gas(signer, gas, gas_budget, inputs, gas_price) + .await?; + + Ok(TransactionData::new( + TransactionKind::programmable(pt), + signer, + gas, + gas_budget, + gas_price, + )) + } + + pub async fn request_add_stake( + &self, + signer: IotaAddress, + mut coins: Vec, + amount: Option, + validator: IotaAddress, + gas: Option, + gas_budget: u64, + ) -> anyhow::Result { + let gas_price = self.0.get_reference_gas_price().await?; + let gas = self + .select_gas(signer, gas, gas_budget, coins.clone(), gas_price) + .await?; + + let mut obj_vec = vec![]; + let coin = coins + .pop() + .ok_or_else(|| anyhow!("Coins input should contain at lease one coin object."))?; + let (oref, coin_type) = self.get_object_ref_and_type(coin).await?; + + let ObjectType::Struct(type_) = &coin_type else { + return Err(anyhow!("Provided object [{coin}] is not a move object.")); + }; + ensure!( + type_.is_coin(), + "Expecting either Coin input coin objects. Received [{type_}]" + ); + + for coin in coins { + let (oref, type_) = self.get_object_ref_and_type(coin).await?; + ensure!( + type_ == coin_type, + "All coins should be the same type, expecting {coin_type}, got {type_}." + ); + obj_vec.push(ObjectArg::ImmOrOwnedObject(oref)) + } + obj_vec.push(ObjectArg::ImmOrOwnedObject(oref)); + + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + let arguments = vec![ + builder.input(CallArg::IOTA_SYSTEM_MUT).unwrap(), + builder.make_obj_vec(obj_vec)?, + builder + .input(CallArg::Pure(bcs::to_bytes(&amount)?)) + .unwrap(), + builder + .input(CallArg::Pure(bcs::to_bytes(&validator)?)) + .unwrap(), + ]; + builder.command(Command::move_call( + IOTA_SYSTEM_PACKAGE_ID, + IOTA_SYSTEM_MODULE_NAME.to_owned(), + ADD_STAKE_MUL_COIN_FUN_NAME.to_owned(), + vec![], + arguments, + )); + builder.finish() + }; + Ok(TransactionData::new_programmable( + signer, + vec![gas], + pt, + gas_budget, + gas_price, + )) + } + + pub async fn request_withdraw_stake( + &self, + signer: IotaAddress, + staked_iota: ObjectID, + gas: Option, + gas_budget: u64, + ) -> anyhow::Result { + let staked_iota = self.get_object_ref(staked_iota).await?; + let gas_price = self.0.get_reference_gas_price().await?; + let gas = self + .select_gas(signer, gas, gas_budget, vec![], gas_price) + .await?; + TransactionData::new_move_call( + signer, + IOTA_SYSTEM_PACKAGE_ID, + IOTA_SYSTEM_MODULE_NAME.to_owned(), + WITHDRAW_STAKE_FUN_NAME.to_owned(), + vec![], + gas, + vec![ + CallArg::IOTA_SYSTEM_MUT, + CallArg::Object(ObjectArg::ImmOrOwnedObject(staked_iota)), + ], + gas_budget, + gas_price, + ) + } + + pub async fn request_add_timelocked_stake( + &self, + signer: IotaAddress, + locked_balance: ObjectID, + validator: IotaAddress, + gas: ObjectID, + gas_budget: u64, + ) -> anyhow::Result { + let gas_price = self.0.get_reference_gas_price().await?; + let gas = self + .select_gas(signer, Some(gas), gas_budget, vec![], gas_price) + .await?; + + let (oref, locked_balance_type) = self.get_object_ref_and_type(locked_balance).await?; + + let ObjectType::Struct(type_) = &locked_balance_type else { + anyhow::bail!("Provided object [{locked_balance}] is not a move object."); + }; + ensure!( + type_.is_timelocked_balance(), + "Expecting either TimeLock> input objects. Received [{type_}]" + ); + + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + let arguments = vec![ + builder.input(CallArg::IOTA_SYSTEM_MUT)?, + builder.input(CallArg::Object(ObjectArg::ImmOrOwnedObject(oref)))?, + builder.input(CallArg::Pure(bcs::to_bytes(&validator)?))?, + ]; + builder.command(Command::move_call( + TIMELOCK_PACKAGE_ID, + TIMELOCKED_STAKING_MODULE_NAME.to_owned(), + ADD_TIMELOCKED_STAKE_FUN_NAME.to_owned(), + vec![], + arguments, + )); + builder.finish() + }; + Ok(TransactionData::new_programmable( + signer, + vec![gas], + pt, + gas_budget, + gas_price, + )) + } + + pub async fn request_withdraw_timelocked_stake( + &self, + signer: IotaAddress, + timelocked_staked_iota: ObjectID, + gas: ObjectID, + gas_budget: u64, + ) -> anyhow::Result { + let timelocked_staked_iota = self.get_object_ref(timelocked_staked_iota).await?; + let gas_price = self.0.get_reference_gas_price().await?; + let gas = self + .select_gas(signer, Some(gas), gas_budget, vec![], gas_price) + .await?; + TransactionData::new_move_call( + signer, + TIMELOCK_PACKAGE_ID, + TIMELOCKED_STAKING_MODULE_NAME.to_owned(), + WITHDRAW_TIMELOCKED_STAKE_FUN_NAME.to_owned(), + vec![], + gas, + vec![ + CallArg::IOTA_SYSTEM_MUT, + CallArg::Object(ObjectArg::ImmOrOwnedObject(timelocked_staked_iota)), + ], + gas_budget, + gas_price, + ) + } + + // TODO: we should add retrial to reduce the transaction building error rate + pub async fn get_object_ref(&self, object_id: ObjectID) -> anyhow::Result { + self.get_object_ref_and_type(object_id) + .await + .map(|(oref, _)| oref) + } + + async fn get_object_ref_and_type( + &self, + object_id: ObjectID, + ) -> anyhow::Result<(ObjectRef, ObjectType)> { + let object = self + .0 + .get_object_with_options(object_id, IotaObjectDataOptions::new().with_type()) + .await? + .into_object()?; + + Ok((object.object_ref(), object.object_type()?)) + } +} diff --git a/crates/iota-transaction-checks/Cargo.toml b/crates/iota-transaction-checks/Cargo.toml new file mode 100644 index 00000000000..d3caa4f6caf --- /dev/null +++ b/crates/iota-transaction-checks/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "iota-transaction-checks" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +once_cell.workspace = true +iota-macros.workspace = true +iota-config.workspace = true +iota-protocol-config.workspace = true +iota-types.workspace = true +tracing.workspace = true +iota-execution.workspace = true +fastcrypto-zkp.workspace = true diff --git a/crates/sui-transaction-checks/src/deny.rs b/crates/iota-transaction-checks/src/deny.rs similarity index 93% rename from crates/sui-transaction-checks/src/deny.rs rename to crates/iota-transaction-checks/src/deny.rs index fd10c19489c..228486f4f05 100644 --- a/crates/sui-transaction-checks/src/deny.rs +++ b/crates/iota-transaction-checks/src/deny.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use fastcrypto_zkp::bn254::zk_login::OIDCProvider; -use sui_config::transaction_deny_config::TransactionDenyConfig; -use sui_types::{ +use iota_config::transaction_deny_config::TransactionDenyConfig; +use iota_types::{ base_types::ObjectRef, - error::{SuiError, SuiResult, UserInputError}, + error::{IotaError, IotaResult, UserInputError}, signature::GenericSignature, storage::BackingPackageStore, transaction::{Command, InputObjectKind, TransactionData, TransactionDataAPI}, @@ -13,7 +14,7 @@ use sui_types::{ macro_rules! deny_if_true { ($cond:expr, $msg:expr) => { if ($cond) { - return Err(SuiError::UserInputError { + return Err(IotaError::UserInputError { error: UserInputError::TransactionDenied { error: $msg.to_string(), }, @@ -31,7 +32,7 @@ pub fn check_transaction_for_signing( receiving_objects: &[ObjectRef], filter_config: &TransactionDenyConfig, package_store: &dyn BackingPackageStore, -) -> SuiResult { +) -> IotaResult { check_disabled_features(filter_config, tx_data, tx_signatures)?; check_signers(filter_config, tx_data)?; @@ -48,7 +49,7 @@ pub fn check_transaction_for_signing( fn check_receiving_objects( filter_config: &TransactionDenyConfig, receiving_objects: &[ObjectRef], -) -> SuiResult { +) -> IotaResult { deny_if_true!( filter_config.receiving_objects_disabled() && !receiving_objects.is_empty(), "Receiving objects is temporarily disabled".to_string() @@ -66,7 +67,7 @@ fn check_disabled_features( filter_config: &TransactionDenyConfig, tx_data: &TransactionData, tx_signatures: &[GenericSignature], -) -> SuiResult { +) -> IotaResult { deny_if_true!( filter_config.user_transaction_disabled(), "Transaction signing is temporarily disabled" @@ -81,7 +82,7 @@ fn check_disabled_features( deny_if_true!( filter_config.zklogin_disabled_providers().contains( &OIDCProvider::from_iss(z.get_iss()) - .map_err(|_| SuiError::UnexpectedMessage)? + .map_err(|_| IotaError::UnexpectedMessage)? .to_string() ), "zkLogin OAuth provider is temporarily disabled" @@ -107,7 +108,7 @@ fn check_disabled_features( Ok(()) } -fn check_signers(filter_config: &TransactionDenyConfig, tx_data: &TransactionData) -> SuiResult { +fn check_signers(filter_config: &TransactionDenyConfig, tx_data: &TransactionData) -> IotaResult { let deny_map = filter_config.get_address_deny_set(); if deny_map.is_empty() { return Ok(()); @@ -127,7 +128,7 @@ fn check_signers(filter_config: &TransactionDenyConfig, tx_data: &TransactionDat fn check_input_objects( filter_config: &TransactionDenyConfig, input_object_kinds: &[InputObjectKind], -) -> SuiResult { +) -> IotaResult { let deny_map = filter_config.get_object_deny_set(); let shared_object_disabled = filter_config.shared_object_disabled(); if deny_map.is_empty() && !shared_object_disabled { @@ -152,7 +153,7 @@ fn check_package_dependencies( filter_config: &TransactionDenyConfig, tx_data: &TransactionData, package_store: &dyn BackingPackageStore, -) -> SuiResult { +) -> IotaResult { let deny_map = filter_config.get_package_deny_set(); if deny_map.is_empty() { return Ok(()); @@ -174,7 +175,7 @@ fn check_package_dependencies( } Command::MoveCall(call) => { let package = package_store.get_package_object(&call.package)?.ok_or( - SuiError::UserInputError { + IotaError::UserInputError { error: UserInputError::ObjectNotFound { object_id: call.package, version: None, diff --git a/crates/iota-transaction-checks/src/lib.rs b/crates/iota-transaction-checks/src/lib.rs new file mode 100644 index 00000000000..e15dad5c23a --- /dev/null +++ b/crates/iota-transaction-checks/src/lib.rs @@ -0,0 +1,610 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod deny; + +pub use checked::*; + +#[iota_macros::with_checked_arithmetic] +mod checked { + use std::{ + collections::{BTreeMap, HashSet}, + sync::Arc, + }; + + use iota_protocol_config::ProtocolConfig; + use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber}, + error::{IotaError, IotaResult, UserInputError, UserInputResult}, + executable_transaction::VerifiedExecutableTransaction, + fp_bail, fp_ensure, + gas::IotaGasStatus, + metrics::BytecodeVerifierMetrics, + object::{Object, Owner}, + transaction::{ + CheckedInputObjects, InputObjectKind, InputObjects, ObjectReadResult, + ObjectReadResultKind, ReceivingObjectReadResult, ReceivingObjects, TransactionData, + TransactionDataAPI, TransactionKind, VersionedProtocolMessage as _, + }, + IOTA_AUTHENTICATOR_STATE_OBJECT_ID, IOTA_CLOCK_OBJECT_ID, IOTA_CLOCK_OBJECT_SHARED_VERSION, + IOTA_RANDOMNESS_STATE_OBJECT_ID, + }; + use tracing::{error, instrument}; + + trait IntoChecked { + fn into_checked(self) -> CheckedInputObjects; + } + + impl IntoChecked for InputObjects { + fn into_checked(self) -> CheckedInputObjects { + CheckedInputObjects::new_with_checked_transaction_inputs(self) + } + } + + // Entry point for all checks related to gas. + // Called on both signing and execution. + // On success the gas part of the transaction (gas data and gas coins) + // is verified and good to go + pub fn get_gas_status( + objects: &InputObjects, + gas: &[ObjectRef], + protocol_config: &ProtocolConfig, + reference_gas_price: u64, + transaction: &TransactionData, + ) -> IotaResult { + check_gas( + objects, + protocol_config, + reference_gas_price, + gas, + transaction.gas_budget(), + transaction.gas_price(), + transaction.kind(), + ) + } + + #[instrument(level = "trace", skip_all)] + pub fn check_transaction_input( + protocol_config: &ProtocolConfig, + reference_gas_price: u64, + transaction: &TransactionData, + input_objects: InputObjects, + receiving_objects: &ReceivingObjects, + metrics: &Arc, + ) -> IotaResult<(IotaGasStatus, CheckedInputObjects)> { + let gas_status = check_transaction_input_inner( + protocol_config, + reference_gas_price, + transaction, + &input_objects, + &[], + )?; + check_receiving_objects(&input_objects, receiving_objects)?; + // Runs verifier, which could be expensive. + check_non_system_packages_to_be_published(transaction, protocol_config, metrics)?; + + Ok((gas_status, input_objects.into_checked())) + } + + pub fn check_transaction_input_with_given_gas( + protocol_config: &ProtocolConfig, + reference_gas_price: u64, + transaction: &TransactionData, + mut input_objects: InputObjects, + receiving_objects: ReceivingObjects, + gas_object: Object, + metrics: &Arc, + ) -> IotaResult<(IotaGasStatus, CheckedInputObjects)> { + let gas_object_ref = gas_object.compute_object_reference(); + input_objects.push(ObjectReadResult::new_from_gas_object(&gas_object)); + + let gas_status = check_transaction_input_inner( + protocol_config, + reference_gas_price, + transaction, + &input_objects, + &[gas_object_ref], + )?; + check_receiving_objects(&input_objects, &receiving_objects)?; + // Runs verifier, which could be expensive. + check_non_system_packages_to_be_published(transaction, protocol_config, metrics)?; + + Ok((gas_status, input_objects.into_checked())) + } + + // Since the purpose of this function is to audit certified transactions, + // the checks here should be a strict subset of the checks in + // check_transaction_input(). For checks not performed in this function but + // in check_transaction_input(), we should add a comment calling out the + // difference. + #[instrument(level = "trace", skip_all)] + pub fn check_certificate_input( + cert: &VerifiedExecutableTransaction, + input_objects: InputObjects, + protocol_config: &ProtocolConfig, + reference_gas_price: u64, + ) -> IotaResult<(IotaGasStatus, CheckedInputObjects)> { + let transaction = cert.data().transaction_data(); + let gas_status = check_transaction_input_inner( + protocol_config, + reference_gas_price, + transaction, + &input_objects, + &[], + )?; + // NB: We do not check receiving objects when executing. Only at signing time do + // we check. NB: move verifier is only checked at signing time, not at + // execution. + + Ok((gas_status, input_objects.into_checked())) + } + + /// WARNING! This should only be used for the dev-inspect transaction. This + /// transaction type bypasses many of the normal object checks + pub fn check_dev_inspect_input( + config: &ProtocolConfig, + kind: &TransactionKind, + input_objects: InputObjects, + // TODO: check ReceivingObjects for dev inspect? + _receiving_objects: ReceivingObjects, + ) -> IotaResult { + kind.validity_check(config)?; + if kind.is_system_tx() { + return Err(UserInputError::Unsupported(format!( + "Transaction kind {} is not supported in dev-inspect", + kind + )) + .into()); + } + let mut used_objects: HashSet = HashSet::new(); + for input_object in input_objects.iter() { + let Some(object) = input_object.as_object() else { + // object was deleted + continue; + }; + + if !object.is_immutable() { + fp_ensure!( + used_objects.insert(object.id().into()), + UserInputError::MutableObjectUsedMoreThanOnce { + object_id: object.id() + } + .into() + ); + } + } + + Ok(input_objects.into_checked()) + } + + // Common checks performed for transactions and certificates. + fn check_transaction_input_inner( + protocol_config: &ProtocolConfig, + reference_gas_price: u64, + transaction: &TransactionData, + input_objects: &InputObjects, + // Overrides the gas objects in the transaction. + gas_override: &[ObjectRef], + ) -> IotaResult { + // Cheap validity checks that is ok to run multiple times during processing. + transaction.check_version_supported(protocol_config)?; + let gas = if gas_override.is_empty() { + transaction.validity_check(protocol_config)?; + transaction.gas() + } else { + transaction.validity_check_no_gas_check(protocol_config)?; + gas_override + }; + + let gas_status = get_gas_status( + input_objects, + gas, + protocol_config, + reference_gas_price, + transaction, + )?; + check_objects(transaction, input_objects)?; + + Ok(gas_status) + } + + fn check_receiving_objects( + input_objects: &InputObjects, + receiving_objects: &ReceivingObjects, + ) -> Result<(), IotaError> { + let mut objects_in_txn: HashSet<_> = input_objects + .object_kinds() + .map(|x| x.object_id()) + .collect(); + + // Since we're at signing we check that every object reference that we are + // receiving is the most recent version of that object. If it's been + // received at the version specified we let it through to allow the + // transaction to run and fail to unlock any other objects in + // the transaction. Otherwise, we return an error. + // + // If there are any object IDs in common (either between receiving objects and + // input objects) we return an error. + for ReceivingObjectReadResult { + object_ref: (object_id, version, object_digest), + object, + } in receiving_objects.iter() + { + fp_ensure!( + *version < SequenceNumber::MAX, + UserInputError::InvalidSequenceNumber.into() + ); + + let Some(object) = object.as_object() else { + // object was previously received + continue; + }; + + if !(object.owner.is_address_owned() + && object.version() == *version + && object.digest() == *object_digest) + { + // Version mismatch + fp_ensure!( + object.version() == *version, + UserInputError::ObjectVersionUnavailableForConsumption { + provided_obj_ref: (*object_id, *version, *object_digest), + current_version: object.version(), + } + .into() + ); + + // Tried to receive a package + fp_ensure!( + !object.is_package(), + UserInputError::MovePackageAsObject { + object_id: *object_id + } + .into() + ); + + // Digest mismatch + let expected_digest = object.digest(); + fp_ensure!( + expected_digest == *object_digest, + UserInputError::InvalidObjectDigest { + object_id: *object_id, + expected_digest + } + .into() + ); + + match object.owner { + Owner::AddressOwner(_) => { + debug_assert!( + false, + "Receiving object {:?} is invalid but we expect it should be valid. {:?}", + (*object_id, *version, *object_id), + object + ); + error!( + "Receiving object {:?} is invalid but we expect it should be valid. {:?}", + (*object_id, *version, *object_id), + object + ); + // We should never get here, but if for some reason we do just default to + // object not found and reject signing the transaction. + fp_bail!( + UserInputError::ObjectNotFound { + object_id: *object_id, + version: Some(*version), + } + .into() + ) + } + Owner::ObjectOwner(owner) => { + fp_bail!( + UserInputError::InvalidChildObjectArgument { + child_id: object.id(), + parent_id: owner.into(), + } + .into() + ) + } + Owner::Shared { .. } => fp_bail!(UserInputError::NotSharedObjectError.into()), + Owner::Immutable => fp_bail!( + UserInputError::MutableParameterExpected { + object_id: *object_id + } + .into() + ), + }; + } + + fp_ensure!( + !objects_in_txn.contains(object_id), + UserInputError::DuplicateObjectRefInput.into() + ); + + objects_in_txn.insert(*object_id); + } + Ok(()) + } + + /// Check transaction gas data/info and gas coins consistency. + /// Return the gas status to be used for the lifecycle of the transaction. + #[instrument(level = "trace", skip_all)] + fn check_gas( + objects: &InputObjects, + protocol_config: &ProtocolConfig, + reference_gas_price: u64, + gas: &[ObjectRef], + gas_budget: u64, + gas_price: u64, + tx_kind: &TransactionKind, + ) -> IotaResult { + if tx_kind.is_system_tx() { + Ok(IotaGasStatus::new_unmetered()) + } else { + let gas_status = + IotaGasStatus::new(gas_budget, gas_price, reference_gas_price, protocol_config)?; + + // check balance and coins consistency + // load all gas coins + let objects: BTreeMap<_, _> = objects.iter().map(|o| (o.id(), o)).collect(); + let mut gas_objects = vec![]; + for obj_ref in gas { + let obj = objects.get(&obj_ref.0); + let obj = *obj.ok_or(UserInputError::ObjectNotFound { + object_id: obj_ref.0, + version: Some(obj_ref.1), + })?; + gas_objects.push(obj); + } + gas_status.check_gas_balance(&gas_objects, gas_budget)?; + Ok(gas_status) + } + } + + /// Check all the objects used in the transaction against the database, and + /// ensure that they are all the correct version and number. + #[instrument(level = "trace", skip_all)] + fn check_objects(transaction: &TransactionData, objects: &InputObjects) -> UserInputResult<()> { + // We require that mutable objects cannot show up more than once. + let mut used_objects: HashSet = HashSet::new(); + for object in objects.iter() { + if object.is_mutable() { + fp_ensure!( + used_objects.insert(object.id().into()), + UserInputError::MutableObjectUsedMoreThanOnce { + object_id: object.id() + } + ); + } + } + + if !transaction.is_genesis_tx() && objects.is_empty() { + return Err(UserInputError::ObjectInputArityViolation); + } + + let gas_coins: HashSet = + HashSet::from_iter(transaction.gas().iter().map(|obj_ref| obj_ref.0)); + for object in objects.iter() { + let input_object_kind = object.input_object_kind; + + match &object.object { + ObjectReadResultKind::Object(object) => { + // For Gas Object, we check the object is owned by gas owner + let owner_address = if gas_coins.contains(&object.id()) { + transaction.gas_owner() + } else { + transaction.sender() + }; + // Check if the object contents match the type of lock we need for + // this object. + let system_transaction = transaction.is_system_tx(); + check_one_object( + &owner_address, + input_object_kind, + object, + system_transaction, + )?; + } + // We skip checking a deleted shared object because it no longer exists + ObjectReadResultKind::DeletedSharedObject(_, _) => (), + } + } + + Ok(()) + } + + /// Check one object against a reference + fn check_one_object( + owner: &IotaAddress, + object_kind: InputObjectKind, + object: &Object, + system_transaction: bool, + ) -> UserInputResult { + match object_kind { + InputObjectKind::MovePackage(package_id) => { + fp_ensure!( + object.data.try_as_package().is_some(), + UserInputError::MoveObjectAsPackage { + object_id: package_id + } + ); + } + InputObjectKind::ImmOrOwnedMoveObject((object_id, sequence_number, object_digest)) => { + fp_ensure!( + !object.is_package(), + UserInputError::MovePackageAsObject { object_id } + ); + fp_ensure!( + sequence_number < SequenceNumber::MAX, + UserInputError::InvalidSequenceNumber + ); + + // This is an invariant - we just load the object with the given ID and version. + assert_eq!( + object.version(), + sequence_number, + "The fetched object version {} does not match the requested version {}, object id: {}", + object.version(), + sequence_number, + object.id(), + ); + + // Check the digest matches - user could give a mismatched ObjectDigest + let expected_digest = object.digest(); + fp_ensure!( + expected_digest == object_digest, + UserInputError::InvalidObjectDigest { + object_id, + expected_digest + } + ); + + match object.owner { + Owner::Immutable => { + // Nothing else to check for Immutable. + } + Owner::AddressOwner(actual_owner) => { + // Check the owner is correct. + fp_ensure!( + owner == &actual_owner, + UserInputError::IncorrectUserSignature { + error: format!( + "Object {:?} is owned by account address {:?}, but given owner/signer address is {:?}", + object_id, actual_owner, owner + ), + } + ); + } + Owner::ObjectOwner(owner) => { + return Err(UserInputError::InvalidChildObjectArgument { + child_id: object.id(), + parent_id: owner.into(), + }); + } + Owner::Shared { .. } => { + // This object is a mutable shared object. However the transaction + // specifies it as an owned object. This is inconsistent. + return Err(UserInputError::NotSharedObjectError); + } + }; + } + InputObjectKind::SharedMoveObject { + id: IOTA_CLOCK_OBJECT_ID, + initial_shared_version: IOTA_CLOCK_OBJECT_SHARED_VERSION, + mutable: true, + } => { + // Only system transactions can accept the Clock + // object as a mutable parameter. + if system_transaction { + return Ok(()); + } else { + return Err(UserInputError::ImmutableParameterExpectedError { + object_id: IOTA_CLOCK_OBJECT_ID, + }); + } + } + InputObjectKind::SharedMoveObject { + id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID, + .. + } => { + if system_transaction { + return Ok(()); + } else { + return Err(UserInputError::InaccessibleSystemObject { + object_id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID, + }); + } + } + InputObjectKind::SharedMoveObject { + id: IOTA_RANDOMNESS_STATE_OBJECT_ID, + mutable: true, + .. + } => { + // Only system transactions can accept the Random + // object as a mutable parameter. + if system_transaction { + return Ok(()); + } else { + return Err(UserInputError::ImmutableParameterExpectedError { + object_id: IOTA_RANDOMNESS_STATE_OBJECT_ID, + }); + } + } + InputObjectKind::SharedMoveObject { + initial_shared_version: input_initial_shared_version, + .. + } => { + fp_ensure!( + object.version() < SequenceNumber::MAX, + UserInputError::InvalidSequenceNumber + ); + + match object.owner { + Owner::AddressOwner(_) | Owner::ObjectOwner(_) | Owner::Immutable => { + // When someone locks an object as shared it must be shared already. + return Err(UserInputError::NotSharedObjectError); + } + Owner::Shared { + initial_shared_version: actual_initial_shared_version, + } => { + fp_ensure!( + input_initial_shared_version == actual_initial_shared_version, + UserInputError::SharedObjectStartingVersionMismatch + ) + } + } + } + }; + Ok(()) + } + + /// Check package verification timeout + #[instrument(level = "trace", skip_all)] + pub fn check_non_system_packages_to_be_published( + transaction: &TransactionData, + protocol_config: &ProtocolConfig, + metrics: &Arc, + ) -> UserInputResult<()> { + // Only meter non-system programmable transaction blocks + if transaction.is_system_tx() { + return Ok(()); + } + + let TransactionKind::ProgrammableTransaction(pt) = transaction.kind() else { + return Ok(()); + }; + + // We use a custom config with metering enabled + let is_metered = true; + // Use the same verifier and meter for all packages + let mut verifier = iota_execution::verifier(protocol_config, is_metered, metrics); + + // Measure time for verifying all packages in the PTB + let shared_meter_verifier_timer = metrics + .verifier_runtime_per_ptb_success_latency + .start_timer(); + + let verifier_status = pt + .non_system_packages_to_be_published() + .try_for_each(|module_bytes| verifier.meter_module_bytes(protocol_config, module_bytes)) + .map_err(|e| UserInputError::PackageVerificationTimedout { err: e.to_string() }); + + match verifier_status { + Ok(_) => { + // Success: stop and record the success timer + shared_meter_verifier_timer.stop_and_record(); + } + Err(err) => { + // Failure: redirect the success timers output to the failure timer and + // discard the success timer + metrics + .verifier_runtime_per_ptb_timeout_latency + .observe(shared_meter_verifier_timer.stop_and_discard()); + return Err(err); + } + }; + + Ok(()) + } +} diff --git a/crates/iota-transactional-test-runner/Cargo.toml b/crates/iota-transactional-test-runner/Cargo.toml new file mode 100644 index 00000000000..4aa87b1e283 --- /dev/null +++ b/crates/iota-transactional-test-runner/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "iota-transactional-test-runner" +version = "0.1.0" +edition = "2021" +authors = ["Mysten Labs "] +description = "Move framework for Iota platform" +license = "Apache-2.0" +publish = false + +[dependencies] +anyhow.workspace = true +bcs.workspace = true +bimap.workspace = true +clap.workspace = true +eyre.workspace = true +once_cell.workspace = true +rand.workspace = true +regex.workspace = true +tempfile.workspace = true +async-trait.workspace = true +tokio.workspace = true +serde_json.workspace = true +futures.workspace = true +criterion.workspace = true + +fastcrypto.workspace = true +move-binary-format.workspace = true +move-bytecode-utils.workspace = true +move-command-line-common.workspace = true +move-compiler.workspace = true +move-core-types.workspace = true +move-symbol-pool.workspace = true +move-transactional-test-runner.workspace = true +telemetry-subscribers.workspace = true + +move-stdlib = { path = "../../external-crates/move/crates/move-stdlib" } +move-vm-runtime = { path = "../../external-crates/move/crates/move-vm-runtime" } + +rocksdb.workspace = true +simulacrum.workspace = true +iota-graphql-rpc.workspace = true +iota-rest-api.workspace = true +iota-swarm-config.workspace = true +iota-config.workspace = true +iota-core = { workspace = true, features = ["test-utils"] } +iota-framework.workspace = true +iota-protocol-config.workspace = true +iota-types = { workspace = true, features = ["test-utils"]} +iota-json-rpc-types.workspace = true +iota-json-rpc.workspace = true +iota-json-rpc-api.workspace = true +iota-framework-snapshot.workspace = true +iota-storage.workspace = true +typed-store.workspace = true +typed-store-derive.workspace = true + +[target.'cfg(msim)'.dependencies] +msim.workspace = true diff --git a/crates/iota-transactional-test-runner/src/args.rs b/crates/iota-transactional-test-runner/src/args.rs new file mode 100644 index 00000000000..cfcdd1a4d36 --- /dev/null +++ b/crates/iota-transactional-test-runner/src/args.rs @@ -0,0 +1,628 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::{bail, ensure}; +use clap::{self, Args, Parser}; +use iota_types::{ + base_types::{IotaAddress, SequenceNumber}, + move_package::UpgradePolicy, + object::{Object, Owner}, + programmable_transaction_builder::ProgrammableTransactionBuilder, + transaction::{Argument, CallArg, ObjectArg}, +}; +use move_command_line_common::{ + parser::{parse_u256, parse_u64, Parser as MoveCLParser}, + values::{ParsableValue, ParsedValue, ValueToken}, +}; +use move_compiler::editions::Flavor; +use move_core_types::{ + runtime_value::{MoveStruct, MoveValue}, + u256::U256, +}; +use move_symbol_pool::Symbol; +use move_transactional_test_runner::tasks::{RunCommand, SyntaxChoice}; + +use crate::test_adapter::{FakeID, IotaTestAdapter}; + +pub const IOTA_ARGS_LONG: &str = "iota-args"; + +#[derive(Clone, Debug, clap::Parser)] +pub struct IotaRunArgs { + #[clap(long = "sender")] + pub sender: Option, + #[clap(long = "gas-price")] + pub gas_price: Option, + #[clap(long = "summarize")] + pub summarize: bool, +} + +#[derive(Debug, clap::Parser, Default)] +pub struct IotaPublishArgs { + #[clap(long = "sender")] + pub sender: Option, + #[clap(long = "upgradeable", action = clap::ArgAction::SetTrue)] + pub upgradeable: bool, + #[clap(long = "dependencies", num_args(1..))] + pub dependencies: Vec, + #[clap(long = "gas-price")] + pub gas_price: Option, +} + +#[derive(Debug, clap::Parser)] +pub struct IotaInitArgs { + #[clap(long = "accounts", num_args(1..))] + pub accounts: Option>, + #[clap(long = "protocol-version")] + pub protocol_version: Option, + #[clap(long = "max-gas")] + pub max_gas: Option, + #[clap(long = "shared-object-deletion")] + pub shared_object_deletion: Option, + #[clap(long = "simulator")] + pub simulator: bool, + #[clap(long = "custom-validator-account")] + pub custom_validator_account: bool, + #[clap(long = "reference-gas-price")] + pub reference_gas_price: Option, + #[clap(long = "default-gas-price")] + pub default_gas_price: Option, + #[clap(long = "object-snapshot-min-checkpoint-lag")] + pub object_snapshot_min_checkpoint_lag: Option, + #[clap(long = "object-snapshot-max-checkpoint-lag")] + pub object_snapshot_max_checkpoint_lag: Option, + #[clap(long = "flavor")] + pub flavor: Option, +} + +#[derive(Debug, clap::Parser)] +pub struct ViewObjectCommand { + #[clap(value_parser = parse_fake_id)] + pub id: FakeID, +} + +#[derive(Debug, clap::Parser)] +pub struct TransferObjectCommand { + #[clap(value_parser = parse_fake_id)] + pub id: FakeID, + #[clap(long = "recipient")] + pub recipient: String, + #[clap(long = "sender")] + pub sender: Option, + #[clap(long = "gas-budget")] + pub gas_budget: Option, + #[clap(long = "gas-price")] + pub gas_price: Option, +} + +#[derive(Debug, clap::Parser)] +pub struct ConsensusCommitPrologueCommand { + #[clap(long = "timestamp-ms")] + pub timestamp_ms: u64, +} + +#[derive(Debug, clap::Parser)] +pub struct ProgrammableTransactionCommand { + #[clap(long = "sender")] + pub sender: Option, + #[clap(long = "gas-budget")] + pub gas_budget: Option, + #[clap(long = "gas-price")] + pub gas_price: Option, + #[clap(long = "dev-inspect")] + pub dev_inspect: bool, + #[clap( + long = "inputs", + value_parser = ParsedValue::::parse, + num_args(1..), + action = clap::ArgAction::Append, + )] + pub inputs: Vec>, +} + +#[derive(Debug, clap::Parser)] +pub struct UpgradePackageCommand { + #[clap(long = "package")] + pub package: String, + #[clap(long = "upgrade-capability", value_parser = parse_fake_id)] + pub upgrade_capability: FakeID, + #[clap(long = "dependencies", num_args(1..))] + pub dependencies: Vec, + #[clap(long = "sender")] + pub sender: String, + #[clap(long = "gas-budget")] + pub gas_budget: Option, + #[clap(long = "syntax")] + pub syntax: Option, + #[clap(long = "policy", default_value="compatible", value_parser = parse_policy)] + pub policy: u8, + #[clap(long = "gas-price")] + pub gas_price: Option, +} + +#[derive(Debug, clap::Parser)] +pub struct StagePackageCommand { + #[clap(long = "syntax")] + pub syntax: Option, + #[clap(long = "dependencies", num_args(1..))] + pub dependencies: Vec, +} + +#[derive(Debug, clap::Parser)] +pub struct SetAddressCommand { + pub address: String, + #[clap(value_parser = ParsedValue::::parse)] + pub input: ParsedValue, +} + +#[derive(Debug, clap::Parser)] +pub struct AdvanceClockCommand { + #[clap(long = "duration-ns")] + pub duration_ns: u64, +} + +#[derive(Debug, clap::Parser)] +pub struct RunGraphqlCommand { + #[clap(long = "show-usage")] + pub show_usage: bool, + #[clap(long = "show-headers")] + pub show_headers: bool, + #[clap(long = "show-service-version")] + pub show_service_version: bool, + #[clap(long, num_args(1..))] + pub cursors: Vec, +} + +#[derive(Debug, clap::Parser)] +pub struct ForceObjectSnapshotCatchup { + #[clap(long = "start-cp")] + pub start_cp: u64, + #[clap(long = "end-cp")] + pub end_cp: u64, +} + +#[derive(Debug, clap::Parser)] +pub struct CreateCheckpointCommand { + pub count: Option, +} + +#[derive(Debug, clap::Parser)] +pub struct AdvanceEpochCommand { + pub count: Option, + #[clap(long = "create-random-state")] + pub create_random_state: bool, +} + +#[derive(Debug, clap::Parser)] +pub struct SetRandomStateCommand { + #[clap(long = "randomness-round")] + pub randomness_round: u64, + #[clap(long = "random-bytes")] + pub random_bytes: String, + #[clap(long = "randomness-initial-version")] + pub randomness_initial_version: u64, +} + +#[derive(Debug)] +pub enum IotaSubcommand { + ViewObject(ViewObjectCommand), + TransferObject(TransferObjectCommand), + ConsensusCommitPrologue(ConsensusCommitPrologueCommand), + ProgrammableTransaction(ProgrammableTransactionCommand), + UpgradePackage(UpgradePackageCommand), + StagePackage(StagePackageCommand), + SetAddress(SetAddressCommand), + CreateCheckpoint(CreateCheckpointCommand), + AdvanceEpoch(AdvanceEpochCommand), + AdvanceClock(AdvanceClockCommand), + SetRandomState(SetRandomStateCommand), + ViewCheckpoint, + RunGraphql(RunGraphqlCommand), + ForceObjectSnapshotCatchup(ForceObjectSnapshotCatchup), + Bench(RunCommand, ExtraRunArgs), +} + +impl clap::FromArgMatches + for IotaSubcommand +{ + fn from_arg_matches(matches: &clap::ArgMatches) -> Result { + Ok(match matches.subcommand() { + Some(("view-object", matches)) => { + IotaSubcommand::ViewObject(ViewObjectCommand::from_arg_matches(matches)?) + } + Some(("transfer-object", matches)) => { + IotaSubcommand::TransferObject(TransferObjectCommand::from_arg_matches(matches)?) + } + Some(("consensus-commit-prologue", matches)) => { + IotaSubcommand::ConsensusCommitPrologue( + ConsensusCommitPrologueCommand::from_arg_matches(matches)?, + ) + } + Some(("programmable", matches)) => IotaSubcommand::ProgrammableTransaction( + ProgrammableTransactionCommand::from_arg_matches(matches)?, + ), + Some(("upgrade", matches)) => { + IotaSubcommand::UpgradePackage(UpgradePackageCommand::from_arg_matches(matches)?) + } + Some(("stage-package", matches)) => { + IotaSubcommand::StagePackage(StagePackageCommand::from_arg_matches(matches)?) + } + Some(("set-address", matches)) => { + IotaSubcommand::SetAddress(SetAddressCommand::from_arg_matches(matches)?) + } + Some(("create-checkpoint", matches)) => IotaSubcommand::CreateCheckpoint( + CreateCheckpointCommand::from_arg_matches(matches)?, + ), + Some(("advance-epoch", matches)) => { + IotaSubcommand::AdvanceEpoch(AdvanceEpochCommand::from_arg_matches(matches)?) + } + Some(("advance-clock", matches)) => { + IotaSubcommand::AdvanceClock(AdvanceClockCommand::from_arg_matches(matches)?) + } + Some(("set-random-state", matches)) => { + IotaSubcommand::SetRandomState(SetRandomStateCommand::from_arg_matches(matches)?) + } + Some(("view-checkpoint", _)) => IotaSubcommand::ViewCheckpoint, + Some(("run-graphql", matches)) => { + IotaSubcommand::RunGraphql(RunGraphqlCommand::from_arg_matches(matches)?) + } + Some(("force-object-snapshot-catchup", matches)) => { + IotaSubcommand::ForceObjectSnapshotCatchup( + ForceObjectSnapshotCatchup::from_arg_matches(matches)?, + ) + } + Some(("bench", matches)) => IotaSubcommand::Bench( + RunCommand::from_arg_matches(matches)?, + ExtraRunArgs::from_arg_matches(matches)?, + ), + _ => { + return Err(clap::Error::raw( + clap::error::ErrorKind::InvalidSubcommand, + "Invalid submcommand", + )); + } + }) + } + + fn update_from_arg_matches(&mut self, matches: &clap::ArgMatches) -> Result<(), clap::Error> { + *self = Self::from_arg_matches(matches)?; + Ok(()) + } +} + +impl clap::CommandFactory + for IotaSubcommand +{ + fn command() -> clap::Command { + clap::Command::new("iota_sub_command") + .subcommand(ViewObjectCommand::command().name("view-object")) + .subcommand(TransferObjectCommand::command().name("transfer-object")) + .subcommand(ConsensusCommitPrologueCommand::command().name("consensus-commit-prologue")) + .subcommand(ProgrammableTransactionCommand::command().name("programmable")) + .subcommand(UpgradePackageCommand::command().name("upgrade")) + .subcommand(StagePackageCommand::command().name("stage-package")) + .subcommand(SetAddressCommand::command().name("set-address")) + .subcommand(CreateCheckpointCommand::command().name("create-checkpoint")) + .subcommand(AdvanceEpochCommand::command().name("advance-epoch")) + .subcommand(AdvanceClockCommand::command().name("advance-clock")) + .subcommand(SetRandomStateCommand::command().name("set-random-state")) + .subcommand(clap::Command::new("view-checkpoint")) + .subcommand(RunGraphqlCommand::command().name("run-graphql")) + .subcommand(ForceObjectSnapshotCatchup::command().name("force-object-snapshot-catchup")) + .subcommand( + RunCommand::::augment_args(ExtraRunArgs::command()).name("bench"), + ) + } + + fn command_for_update() -> clap::Command { + todo!() + } +} + +impl clap::Parser + for IotaSubcommand +{ +} + +#[derive(Clone, Debug)] +pub enum IotaExtraValueArgs { + Object(FakeID, Option), + Digest(String), + Receiving(FakeID, Option), + ImmShared(FakeID, Option), +} + +#[derive(Clone)] +pub enum IotaValue { + MoveValue(MoveValue), + Object(FakeID, Option), + ObjVec(Vec<(FakeID, Option)>), + Digest(String), + Receiving(FakeID, Option), + ImmShared(FakeID, Option), +} + +impl IotaExtraValueArgs { + fn parse_object_value<'a, I: Iterator>( + parser: &mut MoveCLParser<'a, ValueToken, I>, + ) -> anyhow::Result { + let (fake_id, version) = Self::parse_receiving_or_object_value(parser, "object")?; + Ok(IotaExtraValueArgs::Object(fake_id, version)) + } + + fn parse_receiving_value<'a, I: Iterator>( + parser: &mut MoveCLParser<'a, ValueToken, I>, + ) -> anyhow::Result { + let (fake_id, version) = Self::parse_receiving_or_object_value(parser, "receiving")?; + Ok(IotaExtraValueArgs::Receiving(fake_id, version)) + } + + fn parse_read_shared_value<'a, I: Iterator>( + parser: &mut MoveCLParser<'a, ValueToken, I>, + ) -> anyhow::Result { + let (fake_id, version) = Self::parse_receiving_or_object_value(parser, "immshared")?; + Ok(IotaExtraValueArgs::ImmShared(fake_id, version)) + } + + fn parse_digest_value<'a, I: Iterator>( + parser: &mut MoveCLParser<'a, ValueToken, I>, + ) -> anyhow::Result { + let contents = parser.advance(ValueToken::Ident)?; + ensure!(contents == "digest"); + parser.advance(ValueToken::LParen)?; + let package = parser.advance(ValueToken::Ident)?; + parser.advance(ValueToken::RParen)?; + Ok(IotaExtraValueArgs::Digest(package.to_owned())) + } + + fn parse_receiving_or_object_value<'a, I: Iterator>( + parser: &mut MoveCLParser<'a, ValueToken, I>, + ident_name: &str, + ) -> anyhow::Result<(FakeID, Option)> { + let contents = parser.advance(ValueToken::Ident)?; + ensure!(contents == ident_name); + parser.advance(ValueToken::LParen)?; + let i_str = parser.advance(ValueToken::Number)?; + let (i, _) = parse_u256(i_str)?; + let fake_id = if let Some(ValueToken::Comma) = parser.peek_tok() { + parser.advance(ValueToken::Comma)?; + let j_str = parser.advance(ValueToken::Number)?; + let (j, _) = parse_u64(j_str)?; + if i > U256::from(u64::MAX) { + bail!("Object ID too large") + } + FakeID::Enumerated(i.unchecked_as_u64(), j) + } else { + let mut u256_bytes = i.to_le_bytes().to_vec(); + u256_bytes.reverse(); + let address: IotaAddress = IotaAddress::from_bytes(&u256_bytes).unwrap(); + FakeID::Known(address.into()) + }; + parser.advance(ValueToken::RParen)?; + let version = if let Some(ValueToken::AtSign) = parser.peek_tok() { + parser.advance(ValueToken::AtSign)?; + let v_str = parser.advance(ValueToken::Number)?; + let (v, _) = parse_u64(v_str)?; + Some(SequenceNumber::from_u64(v)) + } else { + None + }; + Ok((fake_id, version)) + } +} + +impl IotaValue { + fn assert_move_value(self) -> MoveValue { + match self { + IotaValue::MoveValue(v) => v, + IotaValue::Object(_, _) => panic!("unexpected nested Iota object in args"), + IotaValue::ObjVec(_) => panic!("unexpected nested Iota object vector in args"), + IotaValue::Digest(_) => panic!("unexpected nested Iota package digest in args"), + IotaValue::Receiving(_, _) => panic!("unexpected nested Iota receiving object in args"), + IotaValue::ImmShared(_, _) => panic!("unexpected nested Iota shared object in args"), + } + } + + fn assert_object(self) -> (FakeID, Option) { + match self { + IotaValue::MoveValue(_) => panic!("unexpected nested non-object value in args"), + IotaValue::Object(id, version) => (id, version), + IotaValue::ObjVec(_) => panic!("unexpected nested Iota object vector in args"), + IotaValue::Digest(_) => panic!("unexpected nested Iota package digest in args"), + IotaValue::Receiving(_, _) => panic!("unexpected nested Iota receiving object in args"), + IotaValue::ImmShared(_, _) => panic!("unexpected nested Iota shared object in args"), + } + } + + fn resolve_object( + fake_id: FakeID, + version: Option, + test_adapter: &IotaTestAdapter, + ) -> anyhow::Result { + let id = match test_adapter.fake_to_real_object_id(fake_id) { + Some(id) => id, + None => bail!("INVALID TEST. Unknown object, object({})", fake_id), + }; + let obj_res = if let Some(v) = version { + iota_types::storage::ObjectStore::get_object_by_key(&*test_adapter.executor, &id, v) + } else { + iota_types::storage::ObjectStore::get_object(&*test_adapter.executor, &id) + }; + let obj = match obj_res { + Ok(Some(obj)) => obj, + Err(_) | Ok(None) => bail!("INVALID TEST. Could not load object argument {}", id), + }; + Ok(obj) + } + + fn receiving_arg( + fake_id: FakeID, + version: Option, + test_adapter: &IotaTestAdapter, + ) -> anyhow::Result { + let obj = Self::resolve_object(fake_id, version, test_adapter)?; + Ok(ObjectArg::Receiving(obj.compute_object_reference())) + } + + fn read_shared_arg( + fake_id: FakeID, + version: Option, + test_adapter: &IotaTestAdapter, + ) -> anyhow::Result { + let obj = Self::resolve_object(fake_id, version, test_adapter)?; + let id = obj.id(); + if let Owner::Shared { + initial_shared_version, + } = obj.owner + { + Ok(ObjectArg::SharedObject { + id, + initial_shared_version, + mutable: false, + }) + } else { + bail!("{fake_id} is not a shared object.") + } + } + + fn object_arg( + fake_id: FakeID, + version: Option, + test_adapter: &IotaTestAdapter, + ) -> anyhow::Result { + let obj = Self::resolve_object(fake_id, version, test_adapter)?; + let id = obj.id(); + match obj.owner { + Owner::Shared { + initial_shared_version, + } => Ok(ObjectArg::SharedObject { + id, + initial_shared_version, + mutable: true, + }), + Owner::AddressOwner(_) | Owner::ObjectOwner(_) | Owner::Immutable => { + let obj_ref = obj.compute_object_reference(); + Ok(ObjectArg::ImmOrOwnedObject(obj_ref)) + } + } + } + + pub(crate) fn into_call_arg(self, test_adapter: &IotaTestAdapter) -> anyhow::Result { + Ok(match self { + IotaValue::Object(fake_id, version) => { + CallArg::Object(Self::object_arg(fake_id, version, test_adapter)?) + } + IotaValue::MoveValue(v) => CallArg::Pure(v.simple_serialize().unwrap()), + IotaValue::Receiving(fake_id, version) => { + CallArg::Object(Self::receiving_arg(fake_id, version, test_adapter)?) + } + IotaValue::ImmShared(fake_id, version) => { + CallArg::Object(Self::read_shared_arg(fake_id, version, test_adapter)?) + } + IotaValue::ObjVec(_) => bail!("obj vec is not supported as an input"), + IotaValue::Digest(pkg) => { + let pkg = Symbol::from(pkg); + let Some(staged) = test_adapter.staged_modules.get(&pkg) else { + bail!("Unbound staged package '{pkg}'") + }; + CallArg::Pure(bcs::to_bytes(&staged.digest).unwrap()) + } + }) + } + + pub(crate) fn into_argument( + self, + builder: &mut ProgrammableTransactionBuilder, + test_adapter: &IotaTestAdapter, + ) -> anyhow::Result { + match self { + IotaValue::ObjVec(vec) => builder.make_obj_vec( + vec.iter() + .map(|(fake_id, version)| Self::object_arg(*fake_id, *version, test_adapter)) + .collect::, _>>()?, + ), + value => { + let call_arg = value.into_call_arg(test_adapter)?; + builder.input(call_arg) + } + } + } +} + +impl ParsableValue for IotaExtraValueArgs { + type ConcreteValue = IotaValue; + + fn parse_value<'a, I: Iterator>( + parser: &mut MoveCLParser<'a, ValueToken, I>, + ) -> Option> { + match parser.peek()? { + (ValueToken::Ident, "object") => Some(Self::parse_object_value(parser)), + (ValueToken::Ident, "digest") => Some(Self::parse_digest_value(parser)), + (ValueToken::Ident, "receiving") => Some(Self::parse_receiving_value(parser)), + (ValueToken::Ident, "immshared") => Some(Self::parse_read_shared_value(parser)), + _ => None, + } + } + + fn move_value_into_concrete(v: MoveValue) -> anyhow::Result { + Ok(IotaValue::MoveValue(v)) + } + + fn concrete_vector(elems: Vec) -> anyhow::Result { + if !elems.is_empty() && matches!(elems[0], IotaValue::Object(_, _)) { + Ok(IotaValue::ObjVec( + elems.into_iter().map(IotaValue::assert_object).collect(), + )) + } else { + Ok(IotaValue::MoveValue(MoveValue::Vector( + elems + .into_iter() + .map(IotaValue::assert_move_value) + .collect(), + ))) + } + } + + fn concrete_struct(values: Vec) -> anyhow::Result { + Ok(IotaValue::MoveValue(MoveValue::Struct(MoveStruct( + values.into_iter().map(|v| v.assert_move_value()).collect(), + )))) + } + + fn into_concrete_value( + self, + _mapping: &impl Fn(&str) -> Option, + ) -> anyhow::Result { + match self { + IotaExtraValueArgs::Object(id, version) => Ok(IotaValue::Object(id, version)), + IotaExtraValueArgs::Digest(pkg) => Ok(IotaValue::Digest(pkg)), + IotaExtraValueArgs::Receiving(id, version) => Ok(IotaValue::Receiving(id, version)), + IotaExtraValueArgs::ImmShared(id, version) => Ok(IotaValue::ImmShared(id, version)), + } + } +} + +fn parse_fake_id(s: &str) -> anyhow::Result { + Ok(if let Some((s1, s2)) = s.split_once(',') { + let (i, _) = parse_u64(s1)?; + let (j, _) = parse_u64(s2)?; + FakeID::Enumerated(i, j) + } else { + let (i, _) = parse_u256(s)?; + let mut u256_bytes = i.to_le_bytes().to_vec(); + u256_bytes.reverse(); + let address: IotaAddress = IotaAddress::from_bytes(&u256_bytes).unwrap(); + FakeID::Known(address.into()) + }) +} + +fn parse_policy(x: &str) -> anyhow::Result { + Ok(match x { + "compatible" => UpgradePolicy::COMPATIBLE, + "additive" => UpgradePolicy::ADDITIVE, + "dep_only" => UpgradePolicy::DEP_ONLY, + _ => bail!( + "Invalid upgrade policy {x}. Policy must be one of 'compatible', 'additive', or 'dep_only'" + ), + }) +} diff --git a/crates/iota-transactional-test-runner/src/lib.rs b/crates/iota-transactional-test-runner/src/lib.rs new file mode 100644 index 00000000000..ece0c9b4303 --- /dev/null +++ b/crates/iota-transactional-test-runner/src/lib.rs @@ -0,0 +1,457 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! This module contains the transactional test runner instantiation for the +//! Iota adapter + +pub mod args; +pub mod programmable_transaction_test_parser; +mod simulator_persisted_store; +pub mod test_adapter; + +use std::{path::Path, sync::Arc}; + +use iota_core::authority::{ + authority_test_utils::send_and_confirm_transaction_with_execution_error, AuthorityState, +}; +use iota_json_rpc::authority_state::StateRead; +use iota_json_rpc_types::{DevInspectResults, EventFilter}; +use iota_storage::key_value_store::TransactionKeyValueStore; +use iota_types::{ + base_types::{IotaAddress, ObjectID, VersionNumber}, + digests::{TransactionDigest, TransactionEventsDigest}, + effects::{TransactionEffects, TransactionEvents}, + error::{ExecutionError, IotaError, IotaResult}, + event::Event, + executable_transaction::{ExecutableTransaction, VerifiedExecutableTransaction}, + iota_system_state::{ + epoch_start_iota_system_state::EpochStartSystemStateTrait, IotaSystemStateTrait, + }, + messages_checkpoint::{CheckpointContentsDigest, VerifiedCheckpoint}, + object::Object, + storage::{ObjectStore, ReadStore}, + transaction::{InputObjects, Transaction, TransactionDataAPI, TransactionKind}, +}; +pub use move_transactional_test_runner::framework::run_test_impl; +use rand::rngs::StdRng; +use simulacrum::{Simulacrum, SimulatorStore}; +use simulator_persisted_store::PersistedStore; +use test_adapter::{IotaTestAdapter, PRE_COMPILED}; + +#[cfg_attr(not(msim), tokio::main)] +#[cfg_attr(msim, msim::main)] +pub async fn run_test(path: &Path) -> Result<(), Box> { + let (_guard, _filter_handle) = telemetry_subscribers::TelemetryConfig::new() + .with_env() + .init(); + run_test_impl::(path, Some(std::sync::Arc::new(PRE_COMPILED.clone()))).await?; + Ok(()) +} + +pub struct ValidatorWithFullnode { + pub validator: Arc, + pub fullnode: Arc, + pub kv_store: Arc, +} + +#[allow(unused_variables)] +/// TODO: better name? +#[async_trait::async_trait] +pub trait TransactionalAdapter: Send + Sync + ReadStore { + async fn execute_txn( + &mut self, + transaction: Transaction, + ) -> anyhow::Result<(TransactionEffects, Option)>; + + async fn read_input_objects(&self, transaction: Transaction) -> IotaResult; + + fn prepare_txn( + &self, + transaction: Transaction, + input_objects: InputObjects, + ) -> anyhow::Result<(TransactionEffects, Option)>; + + async fn create_checkpoint(&mut self) -> anyhow::Result; + + async fn advance_clock( + &mut self, + duration: std::time::Duration, + ) -> anyhow::Result; + + async fn advance_epoch(&mut self, create_random_state: bool) -> anyhow::Result<()>; + + async fn request_gas( + &mut self, + address: IotaAddress, + amount: u64, + ) -> anyhow::Result; + + async fn dev_inspect_transaction_block( + &self, + sender: IotaAddress, + transaction_kind: TransactionKind, + gas_price: Option, + ) -> IotaResult; + + async fn query_tx_events_asc( + &self, + tx_digest: &TransactionDigest, + limit: usize, + ) -> IotaResult>; + + async fn get_active_validator_addresses(&self) -> IotaResult>; +} + +#[async_trait::async_trait] +impl TransactionalAdapter for ValidatorWithFullnode { + async fn execute_txn( + &mut self, + transaction: Transaction, + ) -> anyhow::Result<(TransactionEffects, Option)> { + let with_shared = transaction + .data() + .intent_message() + .value + .contains_shared_object(); + let (_, effects, execution_error) = send_and_confirm_transaction_with_execution_error( + &self.validator, + Some(&self.fullnode), + transaction, + with_shared, + ) + .await?; + Ok((effects.into_data(), execution_error)) + } + + async fn read_input_objects(&self, transaction: Transaction) -> IotaResult { + let tx = VerifiedExecutableTransaction::new_unchecked( + ExecutableTransaction::new_from_data_and_sig( + transaction.data().clone(), + iota_types::executable_transaction::CertificateProof::Checkpoint(0, 0), + ), + ); + + let epoch_store = self.validator.load_epoch_store_one_call_per_task().clone(); + self.validator + .read_objects_for_benchmarking(&tx, &epoch_store) + .await + } + + fn prepare_txn( + &self, + transaction: Transaction, + input_objects: InputObjects, + ) -> anyhow::Result<(TransactionEffects, Option)> { + let tx = VerifiedExecutableTransaction::new_unchecked( + ExecutableTransaction::new_from_data_and_sig( + transaction.data().clone(), + iota_types::executable_transaction::CertificateProof::Checkpoint(0, 0), + ), + ); + + let epoch_store = self.validator.load_epoch_store_one_call_per_task().clone(); + let (_, effects, error) = + self.validator + .prepare_certificate_for_benchmark(&tx, input_objects, &epoch_store)?; + Ok((effects, error)) + } + + async fn dev_inspect_transaction_block( + &self, + sender: IotaAddress, + transaction_kind: TransactionKind, + gas_price: Option, + ) -> IotaResult { + self.fullnode + .dev_inspect_transaction_block( + sender, + transaction_kind, + gas_price, + None, + None, + None, + None, + None, + ) + .await + } + + async fn query_tx_events_asc( + &self, + tx_digest: &TransactionDigest, + limit: usize, + ) -> IotaResult> { + Ok(self + .validator + .query_events( + &self.kv_store, + EventFilter::Transaction(*tx_digest), + None, + limit, + false, + ) + .await + .unwrap_or_default() + .into_iter() + .map(|iota_event| iota_event.into()) + .collect()) + } + + async fn create_checkpoint(&mut self) -> anyhow::Result { + unimplemented!("create_checkpoint not supported") + } + + async fn advance_clock( + &mut self, + _duration: std::time::Duration, + ) -> anyhow::Result { + unimplemented!("advance_clock not supported") + } + + async fn advance_epoch(&mut self, _create_random_state: bool) -> anyhow::Result<()> { + unimplemented!("advance_epoch not supported") + } + + async fn request_gas( + &mut self, + _address: IotaAddress, + _amount: u64, + ) -> anyhow::Result { + unimplemented!("request_gas not supported") + } + + async fn get_active_validator_addresses(&self) -> IotaResult> { + Ok(self + .fullnode + .get_system_state() + .map_err(|e| { + IotaError::IotaSystemStateReadError(format!( + "Failed to get system state from fullnode: {}", + e + )) + })? + .into_iota_system_state_summary() + .active_validators + .iter() + .map(|x| x.iota_address) + .collect::>()) + } +} + +impl ReadStore for ValidatorWithFullnode { + fn get_committee( + &self, + _epoch: iota_types::committee::EpochId, + ) -> iota_types::storage::error::Result>> { + todo!() + } + + fn get_latest_checkpoint(&self) -> iota_types::storage::error::Result { + let sequence_number = self + .validator + .get_latest_checkpoint_sequence_number() + .unwrap(); + self.get_checkpoint_by_sequence_number(sequence_number) + .map(|c| c.unwrap()) + } + + fn get_highest_verified_checkpoint( + &self, + ) -> iota_types::storage::error::Result { + todo!() + } + + fn get_highest_synced_checkpoint( + &self, + ) -> iota_types::storage::error::Result { + todo!() + } + + fn get_lowest_available_checkpoint( + &self, + ) -> iota_types::storage::error::Result + { + todo!() + } + + fn get_checkpoint_by_digest( + &self, + _digest: &iota_types::messages_checkpoint::CheckpointDigest, + ) -> iota_types::storage::error::Result> { + todo!() + } + + fn get_checkpoint_by_sequence_number( + &self, + sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber, + ) -> iota_types::storage::error::Result> { + self.validator + .get_checkpoint_store() + .get_checkpoint_by_sequence_number(sequence_number) + .map_err(iota_types::storage::error::Error::custom) + } + + fn get_checkpoint_contents_by_digest( + &self, + digest: &CheckpointContentsDigest, + ) -> iota_types::storage::error::Result< + Option, + > { + self.validator + .get_checkpoint_store() + .get_checkpoint_contents(digest) + .map_err(iota_types::storage::error::Error::custom) + } + + fn get_checkpoint_contents_by_sequence_number( + &self, + _sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber, + ) -> iota_types::storage::error::Result< + Option, + > { + todo!() + } + + fn get_transaction( + &self, + tx_digest: &TransactionDigest, + ) -> iota_types::storage::error::Result>> + { + self.validator + .get_cache_reader() + .get_transaction_block(tx_digest) + .map_err(iota_types::storage::error::Error::custom) + } + + fn get_transaction_effects( + &self, + tx_digest: &TransactionDigest, + ) -> iota_types::storage::error::Result> { + self.validator + .get_cache_reader() + .get_executed_effects(tx_digest) + .map_err(iota_types::storage::error::Error::custom) + } + + fn get_events( + &self, + event_digest: &TransactionEventsDigest, + ) -> iota_types::storage::error::Result> { + self.validator + .get_cache_reader() + .get_events(event_digest) + .map_err(iota_types::storage::error::Error::custom) + } + + fn get_full_checkpoint_contents_by_sequence_number( + &self, + _sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber, + ) -> iota_types::storage::error::Result< + Option, + > { + todo!() + } + + fn get_full_checkpoint_contents( + &self, + _digest: &CheckpointContentsDigest, + ) -> iota_types::storage::error::Result< + Option, + > { + todo!() + } +} + +impl ObjectStore for ValidatorWithFullnode { + fn get_object( + &self, + object_id: &ObjectID, + ) -> Result, iota_types::storage::error::Error> { + self.validator.get_object_store().get_object(object_id) + } + + fn get_object_by_key( + &self, + object_id: &ObjectID, + version: VersionNumber, + ) -> Result, iota_types::storage::error::Error> { + self.validator + .get_object_store() + .get_object_by_key(object_id, version) + } +} + +#[async_trait::async_trait] +impl TransactionalAdapter for Simulacrum { + async fn execute_txn( + &mut self, + transaction: Transaction, + ) -> anyhow::Result<(TransactionEffects, Option)> { + Ok(self.execute_transaction(transaction)?) + } + + async fn read_input_objects(&self, _transaction: Transaction) -> IotaResult { + unimplemented!("read_input_objects not supported in simulator mode") + } + + fn prepare_txn( + &self, + _transaction: Transaction, + _input_objects: InputObjects, + ) -> anyhow::Result<(TransactionEffects, Option)> { + unimplemented!("prepare_txn not supported in simulator mode") + } + + async fn dev_inspect_transaction_block( + &self, + _sender: IotaAddress, + _transaction_kind: TransactionKind, + _gas_price: Option, + ) -> IotaResult { + unimplemented!("dev_inspect_transaction_block not supported in simulator mode") + } + + async fn query_tx_events_asc( + &self, + tx_digest: &TransactionDigest, + _limit: usize, + ) -> IotaResult> { + Ok(self + .store() + .get_transaction_events_by_tx_digest(tx_digest) + .map(|x| x.data) + .unwrap_or_default()) + } + + async fn create_checkpoint(&mut self) -> anyhow::Result { + Ok(self.create_checkpoint()) + } + + async fn advance_clock( + &mut self, + duration: std::time::Duration, + ) -> anyhow::Result { + Ok(self.advance_clock(duration)) + } + + async fn advance_epoch(&mut self, create_random_state: bool) -> anyhow::Result<()> { + self.advance_epoch(create_random_state); + Ok(()) + } + + async fn request_gas( + &mut self, + address: IotaAddress, + amount: u64, + ) -> anyhow::Result { + self.request_gas(address, amount) + } + + async fn get_active_validator_addresses(&self) -> IotaResult> { + // TODO: this is a hack to get the validator addresses. Currently using start + // state but we should have a better way to get this information + // after reconfig + Ok(self.epoch_start_state().get_validator_addresses()) + } +} diff --git a/crates/iota-transactional-test-runner/src/programmable_transaction_test_parser/mod.rs b/crates/iota-transactional-test-runner/src/programmable_transaction_test_parser/mod.rs new file mode 100644 index 00000000000..42c0f1d4d4a --- /dev/null +++ b/crates/iota-transactional-test-runner/src/programmable_transaction_test_parser/mod.rs @@ -0,0 +1,6 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod parser; +pub mod token; diff --git a/crates/iota-transactional-test-runner/src/programmable_transaction_test_parser/parser.rs b/crates/iota-transactional-test-runner/src/programmable_transaction_test_parser/parser.rs new file mode 100644 index 00000000000..d1f708303de --- /dev/null +++ b/crates/iota-transactional-test-runner/src/programmable_transaction_test_parser/parser.rs @@ -0,0 +1,411 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{borrow::BorrowMut, marker::PhantomData, str::FromStr}; + +use anyhow::{bail, Context, Result}; +use iota_types::{ + base_types::ObjectID, + transaction::{Argument, Command, ProgrammableMoveCall}, +}; +use move_command_line_common::{ + parser::{Parser, Token}, + types::{ParsedType, TypeToken}, +}; +use move_core_types::{account_address::AccountAddress, identifier::Identifier}; + +use super::token::CommandToken; +use crate::programmable_transaction_test_parser::token::{ + GAS_COIN, INPUT, MAKE_MOVE_VEC, MERGE_COINS, NESTED_RESULT, PUBLISH, RESULT, SPLIT_COINS, + TRANSFER_OBJECTS, UPGRADE, +}; + +/// A small parser used for parsing programmable transaction commands for +/// transactional tests +pub struct CommandParser< + 'a, + I: Iterator, + P: BorrowMut>, +> { + inner: P, + _a: PhantomData<&'a ()>, + _i: PhantomData, +} + +#[derive(Debug, Clone)] +pub struct ParsedMoveCall { + pub package: Identifier, + pub module: Identifier, + pub function: Identifier, + pub type_arguments: Vec, + pub arguments: Vec, +} + +#[derive(Debug, Clone)] +pub enum ParsedCommand { + MoveCall(Box), + TransferObjects(Vec, Argument), + SplitCoins(Argument, Vec), + MergeCoins(Argument, Vec), + MakeMoveVec(Option, Vec), + Publish(String, Vec), + Upgrade(String, Vec, String, Argument), +} + +impl<'a, I: Iterator> + CommandParser<'a, I, Parser<'a, CommandToken, I>> +{ + pub fn new>(v: T) -> Self { + Self::from_parser(Parser::new(v)) + } +} + +impl<'a, I, P> CommandParser<'a, I, P> +where + I: Iterator, + P: BorrowMut>, +{ + pub fn from_parser(inner: P) -> Self { + Self { + inner, + _a: PhantomData, + _i: PhantomData, + } + } + + pub fn parse_commands(&mut self) -> Result> { + let commands = self.inner().parse_list( + |p| CommandParser::from_parser(p).parse_command_start(), + CommandToken::Semi, + // not checked + CommandToken::Void, + // allow_trailing_delim + true, + )?; + let commands = commands + .into_iter() + .enumerate() + .map(|(actual, (annotated, c))| { + if let Some(annotated) = annotated { + if actual != annotated { + anyhow::bail!( + "Actual command index of {actual} \ + does not match annotated index {annotated}", + ); + } + } + Ok(c) + }) + .collect::>()?; + Ok(commands) + } + + pub fn parse_command_start(&mut self) -> Result<(Option, ParsedCommand)> { + self.inner().advance(CommandToken::CommandStart)?; + let idx = if let Some(CommandToken::Number) = self.inner().peek_tok() { + let num = self.inner().advance(CommandToken::Number)?; + let idx = usize::from_str(num).context("Invalid command index annotation")?; + self.inner().advance(CommandToken::Colon)?; + Some(idx) + } else { + None + }; + let cmd = self.parse_command()?; + Ok((idx, cmd)) + } + + pub fn parse_command(&mut self) -> Result { + use super::token::CommandToken as Tok; + Ok(match self.inner().advance_any()? { + (Tok::Ident, TRANSFER_OBJECTS) => { + self.inner().advance(Tok::LParen)?; + let args = self.parse_command_args(Tok::LBracket, Tok::RBracket)?; + self.inner().advance(Tok::Comma)?; + let arg = self.parse_command_arg()?; + self.maybe_trailing_comma()?; + self.inner().advance(Tok::RParen)?; + ParsedCommand::TransferObjects(args, arg) + } + (Tok::Ident, SPLIT_COINS) => { + self.inner().advance(Tok::LParen)?; + let coin = self.parse_command_arg()?; + self.inner().advance(Tok::Comma)?; + let amts = self.parse_command_args(Tok::LBracket, Tok::RBracket)?; + self.maybe_trailing_comma()?; + self.inner().advance(Tok::RParen)?; + ParsedCommand::SplitCoins(coin, amts) + } + (Tok::Ident, MERGE_COINS) => { + self.inner().advance(Tok::LParen)?; + let target = self.parse_command_arg()?; + self.inner().advance(Tok::Comma)?; + let coins = self.parse_command_args(Tok::LBracket, Tok::RBracket)?; + self.maybe_trailing_comma()?; + self.inner().advance(Tok::RParen)?; + ParsedCommand::MergeCoins(target, coins) + } + (Tok::Ident, MAKE_MOVE_VEC) => { + let type_opt = self.parse_type_arg_opt()?; + self.inner().advance(Tok::LParen)?; + let args = self.parse_command_args(Tok::LBracket, Tok::RBracket)?; + self.maybe_trailing_comma()?; + self.inner().advance(Tok::RParen)?; + ParsedCommand::MakeMoveVec(type_opt, args) + } + (Tok::Ident, PUBLISH) => { + self.inner().advance(Tok::LParen)?; + let staged_package = self.inner().advance(Tok::Ident)?; + self.inner().advance(Tok::Comma)?; + self.inner().advance(Tok::LBracket)?; + let dependencies = self.inner().parse_list( + |p| Ok(p.advance(Tok::Ident)?.to_owned()), + CommandToken::Comma, + Tok::RBracket, + // allow_trailing_delim + true, + )?; + self.inner().advance(Tok::RBracket)?; + self.maybe_trailing_comma()?; + self.inner().advance(Tok::RParen)?; + ParsedCommand::Publish(staged_package.to_owned(), dependencies) + } + (Tok::Ident, UPGRADE) => { + self.inner().advance(Tok::LParen)?; + let staged_package = self.inner().advance(Tok::Ident)?; + self.inner().advance(Tok::Comma)?; + self.inner().advance(Tok::LBracket)?; + let dependencies = self.inner().parse_list( + |p| Ok(p.advance(Tok::Ident)?.to_owned()), + CommandToken::Comma, + Tok::RBracket, + // allow_trailing_delim + true, + )?; + self.inner().advance(Tok::RBracket)?; + self.inner().advance(Tok::Comma)?; + let upgraded_package = self.inner().advance(Tok::Ident)?; + self.inner().advance(Tok::Comma)?; + let upgrade_ticket = self.parse_command_arg()?; + self.maybe_trailing_comma()?; + self.inner().advance(Tok::RParen)?; + ParsedCommand::Upgrade( + staged_package.to_owned(), + dependencies, + upgraded_package.to_owned(), + upgrade_ticket, + ) + } + (Tok::Ident, contents) => { + let package = Identifier::new(contents)?; + self.inner().advance(Tok::ColonColon)?; + let module = Identifier::new(self.inner().advance(Tok::Ident)?)?; + self.inner().advance(Tok::ColonColon)?; + let function = Identifier::new(self.inner().advance(Tok::Ident)?)?; + let type_arguments = self.parse_type_args_opt()?.unwrap_or_default(); + let arguments = self.parse_command_args(Tok::LParen, Tok::RParen)?; + let call = ParsedMoveCall { + package, + module, + function, + type_arguments, + arguments, + }; + ParsedCommand::MoveCall(Box::new(call)) + } + + (tok, _) => bail!("unexpected token {}, expected command identifier", tok), + }) + } + + pub fn maybe_trailing_comma(&mut self) -> Result<()> { + if let Some(CommandToken::Comma) = self.inner().peek_tok() { + self.inner().advance(CommandToken::Comma)?; + } + Ok(()) + } + + pub fn parse_command_args( + &mut self, + start: CommandToken, + end: CommandToken, + ) -> Result> { + self.inner().advance(start)?; + let args = self.inner().parse_list( + |p| CommandParser::from_parser(p).parse_command_arg(), + CommandToken::Comma, + end, + // allow_trailing_delim + true, + )?; + self.inner().advance(end)?; + Ok(args) + } + + pub fn parse_command_arg(&mut self) -> Result { + use super::token::CommandToken as Tok; + Ok(match self.inner().advance_any()? { + (Tok::Ident, GAS_COIN) => Argument::GasCoin, + (Tok::Ident, INPUT) => { + self.inner().advance(Tok::LParen)?; + let num = self.parse_u16()?; + self.maybe_trailing_comma()?; + self.inner().advance(Tok::RParen)?; + Argument::Input(num) + } + (Tok::Ident, RESULT) => { + self.inner().advance(Tok::LParen)?; + let num = self.parse_u16()?; + self.maybe_trailing_comma()?; + self.inner().advance(Tok::RParen)?; + Argument::Result(num) + } + (Tok::Ident, NESTED_RESULT) => { + self.inner().advance(Tok::LParen)?; + let i = self.parse_u16()?; + self.inner().advance(Tok::Comma)?; + let j = self.parse_u16()?; + self.maybe_trailing_comma()?; + self.inner().advance(Tok::RParen)?; + Argument::NestedResult(i, j) + } + (tok, _) => bail!("unexpected token {}, expected argument identifier", tok), + }) + } + + pub fn parse_u16(&mut self) -> Result { + let contents = self.inner().advance(CommandToken::Number)?; + u16::from_str(contents).context("Expected u16 for Argument") + } + + pub fn parse_type_arg_opt(&mut self) -> Result> { + match self.parse_type_args_opt()? { + None => Ok(None), + Some(v) if v.len() != 1 => bail!( + "unexpected multiple type arguments. Expected 1 type argument but got {}", + v.len() + ), + Some(mut v) => Ok(Some(v.pop().unwrap())), + } + } + + pub fn parse_type_args_opt(&mut self) -> Result>> { + if !matches!(self.inner().peek_tok(), Some(CommandToken::TypeArgString)) { + return Ok(None); + } + let contents = self.inner().advance(CommandToken::TypeArgString)?; + let type_tokens: Vec<_> = TypeToken::tokenize(contents)? + .into_iter() + .filter(|(tok, _)| !tok.is_whitespace()) + .collect(); + let mut parser = Parser::new(type_tokens); + parser.advance(TypeToken::Lt)?; + let res = parser.parse_list(|p| p.parse_type(), TypeToken::Comma, TypeToken::Gt, true)?; + parser.advance(TypeToken::Gt)?; + if let Ok((_, contents)) = parser.advance_any() { + bail!("Expected end of token stream. Got: {}", contents) + } + Ok(Some(res)) + } + + pub fn inner(&mut self) -> &mut Parser<'a, CommandToken, I> { + self.inner.borrow_mut() + } +} + +impl ParsedCommand { + pub fn parse_vec(s: &str) -> Result> { + let tokens: Vec<_> = CommandToken::tokenize(s)? + .into_iter() + .filter(|(tok, _)| !tok.is_whitespace()) + .collect(); + let mut parser = CommandParser::new(tokens); + let res = parser.parse_commands()?; + if let Ok((_, contents)) = parser.inner().advance_any() { + bail!("Expected end of token stream. Got: {}", contents) + } + Ok(res) + } + + pub fn into_command( + self, + staged_packages: &impl Fn(&str) -> Option>>, + address_mapping: &impl Fn(&str) -> Option, + ) -> Result { + Ok(match self { + ParsedCommand::MoveCall(c) => { + Command::MoveCall(Box::new(c.into_move_call(address_mapping)?)) + } + ParsedCommand::TransferObjects(objs, recipient) => { + Command::TransferObjects(objs, recipient) + } + ParsedCommand::SplitCoins(coin, amts) => Command::SplitCoins(coin, amts), + ParsedCommand::MergeCoins(target, coins) => Command::MergeCoins(target, coins), + ParsedCommand::MakeMoveVec(ty_opt, args) => Command::MakeMoveVec( + ty_opt + .map(|t| t.into_type_tag(address_mapping)) + .transpose()?, + args, + ), + ParsedCommand::Publish(staged_package, dependencies) => { + let Some(package_contents) = staged_packages(&staged_package) else { + bail!("No staged package '{staged_package}'"); + }; + let dependencies = dependencies + .into_iter() + .map(|d| match address_mapping(&d) { + Some(a) => Ok(a.into()), + None => bail!("Unbound dependency '{d}"), + }) + .collect::>>()?; + Command::Publish(package_contents, dependencies) + } + ParsedCommand::Upgrade(staged_package, dependencies, upgraded_package, ticket) => { + let Some(package_contents) = staged_packages(&staged_package) else { + bail!("No staged package '{staged_package}'"); + }; + let dependencies = dependencies + .into_iter() + .map(|d| match address_mapping(&d) { + Some(a) => Ok(a.into()), + None => bail!("Unbound dependency '{d}"), + }) + .collect::>>()?; + let Some(upgraded_package) = address_mapping(&upgraded_package) else { + bail!("Unbound upgraded package '{upgraded_package}'"); + }; + let upgraded_package = upgraded_package.into(); + Command::Upgrade(package_contents, dependencies, upgraded_package, ticket) + } + }) + } +} + +impl ParsedMoveCall { + pub fn into_move_call( + self, + address_mapping: &impl Fn(&str) -> Option, + ) -> Result { + let Self { + package, + module, + function, + type_arguments, + arguments, + } = self; + let Some(package) = address_mapping(package.as_str()) else { + bail!("Unable to resolve package {}", package) + }; + let type_arguments = type_arguments + .into_iter() + .map(|t| t.into_type_tag(address_mapping)) + .collect::>()?; + Ok(ProgrammableMoveCall { + package: package.into(), + module, + function, + type_arguments, + arguments, + }) + } +} diff --git a/crates/iota-transactional-test-runner/src/programmable_transaction_test_parser/token.rs b/crates/iota-transactional-test-runner/src/programmable_transaction_test_parser/token.rs new file mode 100644 index 00000000000..cc02eee8a40 --- /dev/null +++ b/crates/iota-transactional-test-runner/src/programmable_transaction_test_parser/token.rs @@ -0,0 +1,190 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt::{self, Display}; + +use anyhow::bail; +use move_command_line_common::parser::Token; +use move_core_types::identifier; + +#[derive(Eq, PartialEq, Debug, Clone, Copy)] +pub enum CommandToken { + // any whitespace + Whitespace, + // // or /* */ + Comment, + // //> + CommandStart, + // alpha numeric + Ident, + // digits + Number, + // :: + ColonColon, + // : + Colon, + // , + Comma, + // ; + Semi, + // [ + LBracket, + // ] + RBracket, + // ( + LParen, + // ) + RParen, + // <...> + // eats the whole string, including the < and >, to pass to a different parser + TypeArgString, + // uninhabited token + Void, +} + +pub const TRANSFER_OBJECTS: &str = "TransferObjects"; +pub const SPLIT_COINS: &str = "SplitCoins"; +pub const MERGE_COINS: &str = "MergeCoins"; +pub const MAKE_MOVE_VEC: &str = "MakeMoveVec"; +pub const PUBLISH: &str = "Publish"; +pub const UPGRADE: &str = "Upgrade"; +pub const GAS_COIN: &str = "Gas"; +pub const INPUT: &str = "Input"; +pub const RESULT: &str = "Result"; +pub const NESTED_RESULT: &str = "NestedResult"; + +impl Display for CommandToken { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + let s = match *self { + CommandToken::Whitespace => "[whitespace]", + CommandToken::Comment => "[comment]", + CommandToken::Ident => "[identifier]", + CommandToken::Number => "[num]", + CommandToken::CommandStart => "//>", + CommandToken::ColonColon => "::", + CommandToken::Colon => ":", + CommandToken::Comma => ",", + CommandToken::Semi => ";", + CommandToken::LBracket => "[", + CommandToken::RBracket => "]", + CommandToken::LParen => "(", + CommandToken::RParen => ")", + CommandToken::TypeArgString => "<...>", + CommandToken::Void => "[void]", + }; + fmt::Display::fmt(s, formatter) + } +} + +impl Token for CommandToken { + fn is_whitespace(&self) -> bool { + matches!(self, Self::Whitespace | Self::Comment | Self::Void) + } + + fn next_token(s: &str) -> anyhow::Result> { + // parses a string where start matches end. + // performs simple matching for start/end pairs + + // type arguments get delegated to a different parser + if s.starts_with('<') { + let len = parse_sub_token_string(s, "<", ">")?; + return Ok(Some((Self::TypeArgString, len))); + } + // start of a command + if s.starts_with("//>") { + return Ok(Some((Self::CommandStart, 3))); + } + // comments + if let Some(after) = s.strip_prefix("//") { + let mut n = 2; + let mut in_whitespace_from_start = true; + for c in after.chars() { + n += 1; + if c == '\n' { + break; + } + if in_whitespace_from_start && c == '>' { + bail!("Remove whitespace between // and > to start a command"); + } + if !c.is_whitespace() { + in_whitespace_from_start = false; + } + } + return Ok(Some((Self::Comment, n))); + } + if s.starts_with("/*") { + let end = parse_sub_token_string(s, "/*", "*/")?; + return Ok(Some((Self::Comment, end))); + } + + // other tokens + let mut chars = s.chars().peekable(); + let c = match chars.next() { + None => return Ok(None), + Some(c) => c, + }; + Ok(Some(match c { + '(' => (Self::LParen, 1), + ')' => (Self::RParen, 1), + '[' => (Self::LBracket, 1), + ']' => (Self::RBracket, 1), + ',' => (Self::Comma, 1), + ';' => (Self::Semi, 1), + ':' if matches!(chars.peek(), Some(':')) => (Self::ColonColon, 2), + ':' => (Self::Colon, 1), + c if c.is_ascii_whitespace() => { + // c + remaining + let len = 1 + chars.take_while(char::is_ascii_whitespace).count(); + (Self::Whitespace, len) + } + c if c.is_ascii_digit() => { + // c + remaining + let len = 1 + chars + .take_while(|c| char::is_ascii_digit(c) || *c == '_') + .count(); + (CommandToken::Number, len) + } + c if c.is_ascii_alphabetic() || c == '_' => { + // c + remaining + let len = 1 + chars + .take_while(|c| identifier::is_valid_identifier_char(*c)) + .count(); + (Self::Ident, len) + } + _ => bail!("unrecognized token: {}", s), + })) + } +} + +fn parse_sub_token_string(mut s: &str, start: &str, end: &str) -> anyhow::Result { + // the length of the string until the matching end + let mut len = 0; + let start_len = start.len(); + let end_len = end.len(); + // the count of number of active start/end pairs + let mut count = 0i32; + loop { + s = if s.is_empty() { + bail!("Unexpected end of string after '{start}'. Expected matching '{end}'") + } else if let Some(next) = s.strip_prefix(start) { + len += start_len; + // new start + count += 1; + next + } else if let Some(next) = s.strip_prefix(end) { + len += end_len; + // an end + count -= 1; + if count == 0 { + // end found + break; + } + next + } else { + len += 1; + &s[1..] + } + } + Ok(len) +} diff --git a/crates/sui-transactional-test-runner/src/simulator_persisted_store.rs b/crates/iota-transactional-test-runner/src/simulator_persisted_store.rs similarity index 87% rename from crates/sui-transactional-test-runner/src/simulator_persisted_store.rs rename to crates/iota-transactional-test-runner/src/simulator_persisted_store.rs index fd2b09bcf04..1a1d47d4cde 100644 --- a/crates/sui-transactional-test-runner/src/simulator_persisted_store.rs +++ b/crates/iota-transactional-test-runner/src/simulator_persisted_store.rs @@ -1,22 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, num::NonZeroUsize, path::PathBuf, sync::Arc, time::Duration}; -use move_binary_format::CompiledModule; -use move_bytecode_utils::module_cache::GetModule; -use move_core_types::{language_storage::ModuleId, resolver::ModuleResolver}; -use simulacrum::Simulacrum; -use sui_config::genesis; -use sui_protocol_config::ProtocolVersion; -use sui_swarm_config::{genesis_config::AccountConfig, network_config_builder::ConfigBuilder}; -use sui_types::{ - base_types::{ObjectID, SequenceNumber, SuiAddress, VersionNumber}, +use iota_config::genesis; +use iota_protocol_config::ProtocolVersion; +use iota_swarm_config::{genesis_config::AccountConfig, network_config_builder::ConfigBuilder}; +use iota_types::{ + base_types::{IotaAddress, ObjectID, SequenceNumber, VersionNumber}, committee::{Committee, EpochId}, crypto::AccountKeyPair, digests::{ObjectDigest, TransactionDigest, TransactionEventsDigest}, effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, - error::{SuiError, UserInputError}, + error::{IotaError, UserInputError}, messages_checkpoint::{ CheckpointContents, CheckpointContentsDigest, CheckpointDigest, CheckpointSequenceNumber, VerifiedCheckpoint, @@ -28,6 +25,10 @@ use sui_types::{ }, transaction::VerifiedTransaction, }; +use move_binary_format::CompiledModule; +use move_bytecode_utils::module_cache::GetModule; +use move_core_types::{language_storage::ModuleId, resolver::ModuleResolver}; +use simulacrum::Simulacrum; use tempfile::tempdir; use typed_store::{ metrics::SamplingInterval, @@ -52,12 +53,13 @@ pub struct PersistedStoreInnerReadOnlyWrapper { #[derive(Debug, DBMapUtils)] pub struct PersistedStoreInner { // Checkpoint data - checkpoints: DBMap, + checkpoints: + DBMap, checkpoint_digest_to_sequence_number: DBMap, checkpoint_contents: DBMap, // Transaction data - transactions: DBMap, + transactions: DBMap, effects: DBMap, events: DBMap, events_tx_digest_index: DBMap, @@ -267,18 +269,18 @@ impl SimulatorStore for PersistedStore { .and_then(|versions| versions.get(&version).cloned()) } - fn get_system_state(&self) -> sui_types::sui_system_state::SuiSystemState { - sui_types::sui_system_state::get_sui_system_state(self).expect("system state must exist") + fn get_system_state(&self) -> iota_types::iota_system_state::IotaSystemState { + iota_types::iota_system_state::get_iota_system_state(self).expect("system state must exist") } - fn get_clock(&self) -> sui_types::clock::Clock { - SimulatorStore::get_object(self, &sui_types::SUI_CLOCK_OBJECT_ID) + fn get_clock(&self) -> iota_types::clock::Clock { + SimulatorStore::get_object(self, &iota_types::IOTA_CLOCK_OBJECT_ID) .expect("clock should exist") .to_rust() .expect("clock object should deserialize") } - fn owned_objects(&self, owner: SuiAddress) -> Box + '_> { + fn owned_objects(&self, owner: IotaAddress) -> Box + '_> { Box::new(self.read_write.live_objects .unbounded_iter() .flat_map(|(id, version)| self.get_object_at_version(&id, version)) @@ -410,7 +412,7 @@ impl SimulatorStore for PersistedStore { } } - fn backing_store(&self) -> &dyn sui_types::storage::BackingStore { + fn backing_store(&self) -> &dyn iota_types::storage::BackingStore { self } } @@ -419,7 +421,7 @@ impl BackingPackageStore for PersistedStore { fn get_package_object( &self, package_id: &ObjectID, - ) -> sui_types::error::SuiResult> { + ) -> iota_types::error::IotaResult> { load_package_object_from_object_store(self, package_id) } } @@ -430,7 +432,7 @@ impl ChildObjectResolver for PersistedStore { parent: &ObjectID, child: &ObjectID, child_version_upper_bound: SequenceNumber, - ) -> sui_types::error::SuiResult> { + ) -> iota_types::error::IotaResult> { let child_object = match SimulatorStore::get_object(self, child) { None => return Ok(None), Some(obj) => obj, @@ -438,7 +440,7 @@ impl ChildObjectResolver for PersistedStore { let parent = *parent; if child_object.owner != Owner::ObjectOwner(parent.into()) { - return Err(SuiError::InvalidChildObjectAccess { + return Err(IotaError::InvalidChildObjectAccess { object: *child, given_parent: parent, actual_owner: child_object.owner, @@ -446,7 +448,7 @@ impl ChildObjectResolver for PersistedStore { } if child_object.version() > child_version_upper_bound { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: "TODO InMemoryStorage::read_child_object does not yet support bounded reads" .to_owned(), }); @@ -461,7 +463,7 @@ impl ChildObjectResolver for PersistedStore { receiving_object_id: &ObjectID, receive_object_at_version: SequenceNumber, _epoch_id: EpochId, - ) -> sui_types::error::SuiResult> { + ) -> iota_types::error::IotaResult> { let recv_object = match SimulatorStore::get_object(self, receiving_object_id) { None => return Ok(None), Some(obj) => obj, @@ -478,7 +480,7 @@ impl ChildObjectResolver for PersistedStore { } impl GetModule for PersistedStore { - type Error = SuiError; + type Error = IotaError; type Item = CompiledModule; fn get_module_by_id(&self, id: &ModuleId) -> Result, Self::Error> { @@ -489,7 +491,7 @@ impl GetModule for PersistedStore { } impl ModuleResolver for PersistedStore { - type Error = SuiError; + type Error = IotaError; fn get_module(&self, module_id: &ModuleId) -> Result>, Self::Error> { Ok(self @@ -508,15 +510,15 @@ impl ObjectStore for PersistedStore { fn get_object( &self, object_id: &ObjectID, - ) -> Result, sui_types::storage::error::Error> { + ) -> Result, iota_types::storage::error::Error> { Ok(SimulatorStore::get_object(self, object_id)) } fn get_object_by_key( &self, object_id: &ObjectID, - version: sui_types::base_types::VersionNumber, - ) -> Result, sui_types::storage::error::Error> { + version: iota_types::base_types::VersionNumber, + ) -> Result, iota_types::storage::error::Error> { Ok(self.get_object_at_version(object_id, version)) } } @@ -525,7 +527,7 @@ impl ParentSync for PersistedStore { fn get_latest_parent_entry_ref_deprecated( &self, _object_id: ObjectID, - ) -> sui_types::error::SuiResult> { + ) -> iota_types::error::IotaResult> { panic!("Never called in newer protocol versions") } } @@ -534,7 +536,7 @@ impl ObjectStore for PersistedStoreInnerReadOnlyWrapper { fn get_object( &self, object_id: &ObjectID, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { self.sync(); self.inner @@ -550,7 +552,7 @@ impl ObjectStore for PersistedStoreInnerReadOnlyWrapper { &self, object_id: &ObjectID, version: VersionNumber, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { self.sync(); Ok(self @@ -566,11 +568,11 @@ impl ReadStore for PersistedStoreInnerReadOnlyWrapper { fn get_committee( &self, _epoch: EpochId, - ) -> sui_types::storage::error::Result>> { + ) -> iota_types::storage::error::Result>> { todo!() } - fn get_latest_checkpoint(&self) -> sui_types::storage::error::Result { + fn get_latest_checkpoint(&self) -> iota_types::storage::error::Result { self.sync(); self.inner .checkpoints @@ -578,41 +580,41 @@ impl ReadStore for PersistedStoreInnerReadOnlyWrapper { .skip_to_last() .next() .map(|(_, checkpoint)| checkpoint.into()) - .ok_or(SuiError::UserInputError { + .ok_or(IotaError::UserInputError { error: UserInputError::LatestCheckpointSequenceNumberNotFound, }) - .map_err(sui_types::storage::error::Error::custom) + .map_err(iota_types::storage::error::Error::custom) } fn get_highest_verified_checkpoint( &self, - ) -> sui_types::storage::error::Result { + ) -> iota_types::storage::error::Result { todo!() } fn get_highest_synced_checkpoint( &self, - ) -> sui_types::storage::error::Result { + ) -> iota_types::storage::error::Result { todo!() } fn get_lowest_available_checkpoint( &self, - ) -> sui_types::storage::error::Result { + ) -> iota_types::storage::error::Result { Ok(0) } fn get_checkpoint_by_digest( &self, _digest: &CheckpointDigest, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { todo!() } fn get_checkpoint_by_sequence_number( &self, sequence_number: CheckpointSequenceNumber, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { self.sync(); Ok(self .inner @@ -625,7 +627,7 @@ impl ReadStore for PersistedStoreInnerReadOnlyWrapper { fn get_checkpoint_contents_by_digest( &self, digest: &CheckpointContentsDigest, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { self.sync(); Ok(self @@ -638,14 +640,14 @@ impl ReadStore for PersistedStoreInnerReadOnlyWrapper { fn get_checkpoint_contents_by_sequence_number( &self, _sequence_number: CheckpointSequenceNumber, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { todo!() } fn get_transaction( &self, tx_digest: &TransactionDigest, - ) -> sui_types::storage::error::Result>> { + ) -> iota_types::storage::error::Result>> { self.sync(); Ok(self @@ -659,7 +661,7 @@ impl ReadStore for PersistedStoreInnerReadOnlyWrapper { fn get_transaction_effects( &self, tx_digest: &TransactionDigest, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { self.sync(); Ok(self @@ -672,7 +674,7 @@ impl ReadStore for PersistedStoreInnerReadOnlyWrapper { fn get_events( &self, event_digest: &TransactionEventsDigest, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { self.sync(); Ok(self @@ -685,8 +687,8 @@ impl ReadStore for PersistedStoreInnerReadOnlyWrapper { fn get_full_checkpoint_contents_by_sequence_number( &self, _sequence_number: CheckpointSequenceNumber, - ) -> sui_types::storage::error::Result< - Option, + ) -> iota_types::storage::error::Result< + Option, > { todo!() } @@ -694,8 +696,8 @@ impl ReadStore for PersistedStoreInnerReadOnlyWrapper { fn get_full_checkpoint_contents( &self, _digest: &CheckpointContentsDigest, - ) -> sui_types::storage::error::Result< - Option, + ) -> iota_types::storage::error::Result< + Option, > { todo!() } diff --git a/crates/sui-transactional-test-runner/src/test_adapter.rs b/crates/iota-transactional-test-runner/src/test_adapter.rs similarity index 91% rename from crates/sui-transactional-test-runner/src/test_adapter.rs rename to crates/iota-transactional-test-runner/src/test_adapter.rs index 250fd826885..66443200012 100644 --- a/crates/sui-transactional-test-runner/src/test_adapter.rs +++ b/crates/iota-transactional-test-runner/src/test_adapter.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -//! This module contains the transactional test runner instantiation for the Sui -//! adapter +//! This module contains the transactional test runner instantiation for the +//! Iota adapter use std::{ collections::{BTreeMap, BTreeSet}, @@ -22,48 +23,22 @@ use fastcrypto::{ encoding::{Base64, Encoding}, traits::ToFromBytes, }; -use move_binary_format::CompiledModule; -use move_bytecode_utils::module_cache::GetModule; -use move_command_line_common::{ - address::ParsedAddress, files::verify_and_create_named_address_mapping, -}; -use move_compiler::{ - editions::{Edition, Flavor}, - shared::{NumberFormat, NumericalAddress, PackageConfig, PackagePaths}, - Flags, FullyCompiledProgram, -}; -use move_core_types::{ - account_address::AccountAddress, - ident_str, - identifier::IdentStr, - language_storage::{ModuleId, TypeTag}, -}; -use move_symbol_pool::Symbol; -use move_transactional_test_runner::{ - framework::{ - compile_any, store_modules, CompiledState, MaybeNamedCompiledModule, MoveTestAdapter, - }, - tasks::{InitCommand, RunCommand, SyntaxChoice, TaskInput}, -}; -use move_vm_runtime::session::SerializedReturnValues; -use once_cell::sync::Lazy; -use rand::{rngs::StdRng, Rng, SeedableRng}; -use sui_core::authority::{test_authority_builder::TestAuthorityBuilder, AuthorityState}; -use sui_framework::DEFAULT_FRAMEWORK_PATH; -use sui_graphql_rpc::{ +use iota_core::authority::{test_authority_builder::TestAuthorityBuilder, AuthorityState}; +use iota_framework::DEFAULT_FRAMEWORK_PATH; +use iota_graphql_rpc::{ config::ConnectionConfig, test_infra::cluster::{serve_executor, ExecutorCluster, SnapshotLagConfig}, }; -use sui_json_rpc_api::QUERY_MAX_RESULT_LIMIT; -use sui_json_rpc_types::{DevInspectResults, SuiExecutionStatus, SuiTransactionBlockEffectsAPI}; -use sui_protocol_config::{Chain, ProtocolConfig}; -use sui_storage::{ +use iota_json_rpc_api::QUERY_MAX_RESULT_LIMIT; +use iota_json_rpc_types::{DevInspectResults, IotaExecutionStatus, IotaTransactionBlockEffectsAPI}; +use iota_protocol_config::{Chain, ProtocolConfig}; +use iota_storage::{ key_value_store::TransactionKeyValueStore, key_value_store_metrics::KeyValueStoreMetrics, }; -use sui_swarm_config::genesis_config::AccountConfig; -use sui_types::{ +use iota_swarm_config::genesis_config::AccountConfig; +use iota_types::{ base_types::{ - ObjectID, ObjectRef, SequenceNumber, SuiAddress, VersionNumber, SUI_ADDRESS_LENGTH, + IotaAddress, ObjectID, ObjectRef, SequenceNumber, VersionNumber, IOTA_ADDRESS_LENGTH, }, crypto::{get_authority_key_pair, get_key_pair_from_rng, AccountKeyPair, RandomnessRound}, digests::{ConsensusCommitDigest, TransactionDigest, TransactionEventsDigest}, @@ -83,11 +58,37 @@ use sui_types::{ TransactionDataAPI, TransactionKind, VerifiedTransaction, }, utils::to_sender_signed_transaction, - DEEPBOOK_ADDRESS, DEEPBOOK_PACKAGE_ID, MOVE_STDLIB_ADDRESS, MOVE_STDLIB_PACKAGE_ID, - SUI_CLOCK_OBJECT_ID, SUI_DENY_LIST_OBJECT_ID, SUI_FRAMEWORK_ADDRESS, SUI_FRAMEWORK_PACKAGE_ID, - SUI_RANDOMNESS_STATE_OBJECT_ID, SUI_SYSTEM_ADDRESS, SUI_SYSTEM_PACKAGE_ID, - SUI_SYSTEM_STATE_OBJECT_ID, + DEEPBOOK_ADDRESS, DEEPBOOK_PACKAGE_ID, IOTA_CLOCK_OBJECT_ID, IOTA_DENY_LIST_OBJECT_ID, + IOTA_FRAMEWORK_ADDRESS, IOTA_FRAMEWORK_PACKAGE_ID, IOTA_RANDOMNESS_STATE_OBJECT_ID, + IOTA_SYSTEM_ADDRESS, IOTA_SYSTEM_PACKAGE_ID, IOTA_SYSTEM_STATE_OBJECT_ID, MOVE_STDLIB_ADDRESS, + MOVE_STDLIB_PACKAGE_ID, }; +use move_binary_format::CompiledModule; +use move_bytecode_utils::module_cache::GetModule; +use move_command_line_common::{ + address::ParsedAddress, files::verify_and_create_named_address_mapping, +}; +use move_compiler::{ + editions::{Edition, Flavor}, + shared::{NumberFormat, NumericalAddress, PackageConfig, PackagePaths}, + Flags, FullyCompiledProgram, +}; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{ModuleId, TypeTag}, +}; +use move_symbol_pool::Symbol; +use move_transactional_test_runner::{ + framework::{ + compile_any, store_modules, CompiledState, MaybeNamedCompiledModule, MoveTestAdapter, + }, + tasks::{InitCommand, RunCommand, SyntaxChoice, TaskInput}, +}; +use move_vm_runtime::session::SerializedReturnValues; +use once_cell::sync::Lazy; +use rand::{rngs::StdRng, Rng, SeedableRng}; use tempfile::NamedTempFile; use crate::{ @@ -106,12 +107,12 @@ const DEFAULT_GAS_PRICE: u64 = 1_000; const WELL_KNOWN_OBJECTS: &[ObjectID] = &[ MOVE_STDLIB_PACKAGE_ID, DEEPBOOK_PACKAGE_ID, - SUI_FRAMEWORK_PACKAGE_ID, - SUI_SYSTEM_PACKAGE_ID, - SUI_SYSTEM_STATE_OBJECT_ID, - SUI_CLOCK_OBJECT_ID, - SUI_DENY_LIST_OBJECT_ID, - SUI_RANDOMNESS_STATE_OBJECT_ID, + IOTA_FRAMEWORK_PACKAGE_ID, + IOTA_SYSTEM_PACKAGE_ID, + IOTA_SYSTEM_STATE_OBJECT_ID, + IOTA_CLOCK_OBJECT_ID, + IOTA_DENY_LIST_OBJECT_ID, + IOTA_RANDOMNESS_STATE_OBJECT_ID, ]; // TODO use the file name as a seed const RNG_SEED: [u8; 32] = [ @@ -124,7 +125,7 @@ const GAS_FOR_TESTING: u64 = GAS_VALUE_FOR_TESTING; const DEFAULT_CHAIN_START_TIMESTAMP: u64 = 0; -pub struct SuiTestAdapter { +pub struct IotaTestAdapter { pub(crate) compiled_state: CompiledState, /// For upgrades: maps an upgraded package name to the original package /// name. @@ -150,7 +151,7 @@ pub(crate) struct StagedPackage { #[derive(Debug)] struct TestAccount { - address: SuiAddress, + address: IotaAddress, key_pair: AccountKeyPair, gas: ObjectID, } @@ -168,12 +169,12 @@ struct TxnSummary { } #[async_trait] -impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { - type ExtraPublishArgs = SuiPublishArgs; - type ExtraRunArgs = SuiRunArgs; - type ExtraInitArgs = SuiInitArgs; - type ExtraValueArgs = SuiExtraValueArgs; - type Subcommand = SuiSubcommand; +impl<'a> MoveTestAdapter<'a> for IotaTestAdapter { + type ExtraPublishArgs = IotaPublishArgs; + type ExtraRunArgs = IotaRunArgs; + type ExtraInitArgs = IotaInitArgs; + type ExtraValueArgs = IotaExtraValueArgs; + type Subcommand = IotaSubcommand; fn compiled_state(&mut self) -> &mut CompiledState { &mut self.compiled_state @@ -202,7 +203,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { let rng = StdRng::from_seed(RNG_SEED); assert!( pre_compiled_deps.is_some(), - "Must populate 'pre_compiled_deps' with Sui framework" + "Must populate 'pre_compiled_deps' with Iota framework" ); // Unpack the init arguments @@ -220,7 +221,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { ) = match task_opt.map(|t| t.command) { Some(( InitCommand { named_addresses }, - SuiInitArgs { + IotaInitArgs { accounts, protocol_version, max_gas, @@ -332,7 +333,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { NumberFormat::Hex, )), Some(Edition::E2024_ALPHA), - flavor.or(Some(Flavor::Sui)), + flavor.or(Some(Flavor::Iota)), ), package_upgrade_mapping: BTreeMap::new(), accounts, @@ -376,7 +377,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { extra: Self::ExtraPublishArgs, ) -> anyhow::Result<(Option, Vec)> { self.next_task(); - let SuiPublishArgs { + let IotaPublishArgs { sender, upgradeable, dependencies, @@ -405,9 +406,9 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { }) .collect::>()?; let gas_price = gas_price.unwrap_or(self.gas_price); - // we are assuming that all packages depend on Move Stdlib and Sui Framework, so - // these don't have to be provided explicitly as parameters - dependencies.extend([MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID]); + // we are assuming that all packages depend on Move Stdlib and Iota Framework, + // so these don't have to be provided explicitly as parameters + dependencies.extend([MOVE_STDLIB_PACKAGE_ID, IOTA_FRAMEWORK_PACKAGE_ID]); let data = |sender, gas| { let mut builder = ProgrammableTransactionBuilder::new(); if upgradeable { @@ -477,12 +478,12 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { function: &IdentStr, type_args: Vec, signers: Vec, - args: Vec, + args: Vec, gas_budget: Option, extra: Self::ExtraRunArgs, ) -> anyhow::Result<(Option, SerializedReturnValues)> { self.next_task(); - let SuiRunArgs { summarize, .. } = extra; + let IotaRunArgs { summarize, .. } = extra; let transaction = self.build_function_call_tx( module_id, function, type_args, signers, args, gas_budget, extra, )?; @@ -529,7 +530,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { ($fake_id:ident) => {{ get_obj!($fake_id, None) }}; } match command { - SuiSubcommand::ForceObjectSnapshotCatchup(ForceObjectSnapshotCatchup { + IotaSubcommand::ForceObjectSnapshotCatchup(ForceObjectSnapshotCatchup { start_cp, end_cp, }) => { @@ -553,7 +554,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { start_cp, end_cp ))) } - SuiSubcommand::RunGraphql(RunGraphqlCommand { + IotaSubcommand::RunGraphql(RunGraphqlCommand { show_usage, show_headers, show_service_version, @@ -589,7 +590,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { Ok(Some(output.join("\n"))) } - SuiSubcommand::ViewCheckpoint => { + IotaSubcommand::ViewCheckpoint => { let latest_chk = self.executor.get_latest_checkpoint_sequence_number()?; let chk = self .executor @@ -597,14 +598,14 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { .unwrap(); Ok(Some(format!("{}", chk.data()))) } - SuiSubcommand::CreateCheckpoint(CreateCheckpointCommand { count }) => { + IotaSubcommand::CreateCheckpoint(CreateCheckpointCommand { count }) => { for _ in 0..count.unwrap_or(1) { self.executor.create_checkpoint().await?; } let latest_chk = self.executor.get_latest_checkpoint_sequence_number()?; Ok(Some(format!("Checkpoint created: {}", latest_chk))) } - SuiSubcommand::AdvanceEpoch(AdvanceEpochCommand { + IotaSubcommand::AdvanceEpoch(AdvanceEpochCommand { count, create_random_state, }) => { @@ -614,13 +615,13 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { let epoch = self.get_latest_epoch_id()?; Ok(Some(format!("Epoch advanced: {epoch}"))) } - SuiSubcommand::AdvanceClock(AdvanceClockCommand { duration_ns }) => { + IotaSubcommand::AdvanceClock(AdvanceClockCommand { duration_ns }) => { self.executor .advance_clock(Duration::from_nanos(duration_ns)) .await?; Ok(None) } - SuiSubcommand::SetRandomState(SetRandomStateCommand { + IotaSubcommand::SetRandomState(SetRandomStateCommand { randomness_round, random_bytes, randomness_initial_version, @@ -639,7 +640,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { self.execute_txn(tx.into()).await?; Ok(None) } - SuiSubcommand::ViewObject(ViewObjectCommand { id: fake_id }) => { + IotaSubcommand::ViewObject(ViewObjectCommand { id: fake_id }) => { let obj = get_obj!(fake_id); Ok(Some(match &obj.data { object::Data::Move(move_obj) => { @@ -672,7 +673,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { } })) } - SuiSubcommand::TransferObject(TransferObjectCommand { + IotaSubcommand::TransferObject(TransferObjectCommand { id: fake_id, recipient, sender, @@ -680,7 +681,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { gas_price, }) => { let mut builder = ProgrammableTransactionBuilder::new(); - let obj_arg = SuiValue::Object(fake_id, None).into_argument(&mut builder, self)?; + let obj_arg = IotaValue::Object(fake_id, None).into_argument(&mut builder, self)?; let recipient = match self.accounts.get(&recipient) { Some(test_account) => test_account.address, None => panic!("Unbound account {}", recipient), @@ -689,7 +690,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { let gas_price: u64 = gas_price.unwrap_or(self.gas_price); let transaction = self.sign_txn(sender, |sender, gas| { let rec_arg = builder.pure(recipient).unwrap(); - builder.command(sui_types::transaction::Command::TransferObjects( + builder.command(iota_types::transaction::Command::TransferObjects( vec![obj_arg], rec_arg, )); @@ -700,7 +701,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { let output = self.object_summary_output(&summary, /* summarize */ false); Ok(output) } - SuiSubcommand::ConsensusCommitPrologue(ConsensusCommitPrologueCommand { + IotaSubcommand::ConsensusCommitPrologue(ConsensusCommitPrologueCommand { timestamp_ms, }) => { let transaction = VerifiedTransaction::new_consensus_commit_prologue_v2( @@ -713,7 +714,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { let output = self.object_summary_output(&summary, /* summarize */ false); Ok(output) } - SuiSubcommand::ProgrammableTransaction(ProgrammableTransactionCommand { + IotaSubcommand::ProgrammableTransaction(ProgrammableTransactionCommand { sender, gas_budget, gas_price, @@ -787,7 +788,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { let output = self.object_summary_output(&summary, /* summarize */ false); Ok(output) } - SuiSubcommand::UpgradePackage(UpgradePackageCommand { + IotaSubcommand::UpgradePackage(UpgradePackageCommand { package, upgrade_capability, dependencies, @@ -902,7 +903,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { store_modules(self, syntax, data, modules); Ok(merge_output(warnings_opt, output)) } - SuiSubcommand::StagePackage(StagePackageCommand { + IotaSubcommand::StagePackage(StagePackageCommand { syntax, dependencies, }) => { @@ -964,12 +965,12 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { } Ok(merge_output(warnings_opt, output)) } - SuiSubcommand::SetAddress(SetAddressCommand { address, input }) => { + IotaSubcommand::SetAddress(SetAddressCommand { address, input }) => { let address_sym = &Symbol::from(address.as_str()); let state = self.compiled_state(); let input = input.into_concrete_value(&|s| Some(state.resolve_named_address(s)))?; let (value, package) = match input { - SuiValue::Object(fake_id, version) => { + IotaValue::Object(fake_id, version) => { let id = match self.fake_to_real_object_id(fake_id) { Some(id) => id, None => bail!("INVALID TEST. Unknown object, object({})", fake_id), @@ -995,15 +996,15 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { let value: AccountAddress = id.into(); (value, package) } - SuiValue::MoveValue(v) => { + IotaValue::MoveValue(v) => { let bytes = v.simple_serialize().unwrap(); let value: AccountAddress = bcs::from_bytes(&bytes)?; (value, None) } - SuiValue::Digest(_) => bail!("digest is not supported as an input"), - SuiValue::ObjVec(_) => bail!("obj vec is not supported as an input"), - SuiValue::Receiving(_, _) => bail!("receiving is not supported as an input"), - SuiValue::ImmShared(_, _) => { + IotaValue::Digest(_) => bail!("digest is not supported as an input"), + IotaValue::ObjVec(_) => bail!("obj vec is not supported as an input"), + IotaValue::Receiving(_, _) => bail!("receiving is not supported as an input"), + IotaValue::ImmShared(_, _) => { bail!("read-only shared object is not supported as an input") } }; @@ -1025,7 +1026,7 @@ impl<'a> MoveTestAdapter<'a> for SuiTestAdapter { Ok(None) } - SuiSubcommand::Bench( + IotaSubcommand::Bench( RunCommand { signers, args, @@ -1131,7 +1132,7 @@ fn merge_output(left: Option, right: Option) -> Option { } } -impl<'a> SuiTestAdapter { +impl<'a> IotaTestAdapter { pub fn is_simulator(&self) -> bool { self.is_simulator } @@ -1270,7 +1271,7 @@ impl<'a> SuiTestAdapter { let mut builder = ProgrammableTransactionBuilder::new(); // Argument::Input(0) - SuiValue::Object(upgrade_capability, None).into_argument(&mut builder, self)?; + IotaValue::Object(upgrade_capability, None).into_argument(&mut builder, self)?; let upgrade_arg = builder.pure(policy).unwrap(); let digest: Vec = MovePackage::compute_digest_for_modules_and_deps( &modules_bytes, @@ -1282,7 +1283,7 @@ impl<'a> SuiTestAdapter { let digest_arg = builder.pure(digest).unwrap(); let upgrade_ticket = builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, ident_str!("package").to_owned(), ident_str!("authorize_upgrade").to_owned(), vec![], @@ -1294,7 +1295,7 @@ impl<'a> SuiTestAdapter { builder.upgrade(package_id, upgrade_ticket, dependencies, modules_bytes); builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, ident_str!("package").to_owned(), ident_str!("commit_upgrade").to_owned(), vec![], @@ -1340,7 +1341,12 @@ impl<'a> SuiTestAdapter { fn sign_txn( &self, sender: Option, - txn_data: impl FnOnce(/* sender */ SuiAddress, /* gas */ ObjectRef) -> TransactionData, + txn_data: impl FnOnce( + // sender + IotaAddress, + // gas + ObjectRef, + ) -> TransactionData, ) -> Transaction { let test_account = self.get_sender(sender); let gas_payment = self @@ -1367,12 +1373,12 @@ impl<'a> SuiTestAdapter { function: &IdentStr, type_args: Vec, signers: Vec, - args: Vec, + args: Vec, gas_budget: Option, - extra: SuiRunArgs, + extra: IotaRunArgs, ) -> anyhow::Result { assert!(signers.is_empty(), "signers are not used"); - let SuiRunArgs { + let IotaRunArgs { sender, gas_price, .. } = extra; let mut builder = ProgrammableTransactionBuilder::new(); @@ -1487,7 +1493,7 @@ impl<'a> SuiTestAdapter { async fn dev_inspect( &mut self, - sender: SuiAddress, + sender: IotaAddress, transaction_kind: TransactionKind, gas_price: Option, ) -> anyhow::Result { @@ -1536,11 +1542,11 @@ impl<'a> SuiTestAdapter { wrapped_ids.sort_by_key(|id| self.real_to_fake_object_id(id)); match effects.status() { - SuiExecutionStatus::Success { .. } => { + IotaExecutionStatus::Success { .. } => { let events = events .data .into_iter() - .map(|sui_event| sui_event.into()) + .map(|iota_event| iota_event.into()) .collect(); Ok(TxnSummary { events, @@ -1553,7 +1559,7 @@ impl<'a> SuiTestAdapter { wrapped: wrapped_ids, }) } - SuiExecutionStatus::Failure { error } => Err(anyhow::anyhow!(self.stabilize_str( + IotaExecutionStatus::Failure { error } => Err(anyhow::anyhow!(self.stabilize_str( format!("Transaction Effects Status: {error}\nExecution Error: {error}",) ))), } @@ -1700,7 +1706,7 @@ impl<'a> SuiTestAdapter { fn stabilize_str(&self, input: impl AsRef) -> String { fn candidate_is_hex(s: &str) -> bool { - const HEX_STR_LENGTH: usize = SUI_ADDRESS_LENGTH * 2; + const HEX_STR_LENGTH: usize = IOTA_ADDRESS_LENGTH * 2; let n = s.len(); (s.starts_with("0x") && n >= 3) || n == HEX_STR_LENGTH } @@ -1783,16 +1789,16 @@ impl<'a> SuiTestAdapter { Ok(id) }) .collect::>()?; - // we are assuming that all packages depend on Move Stdlib and Sui Framework, so - // these don't have to be provided explicitly as parameters + // we are assuming that all packages depend on Move Stdlib and Iota Framework, + // so these don't have to be provided explicitly as parameters if include_std { - dependencies.extend([MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID]); + dependencies.extend([MOVE_STDLIB_PACKAGE_ID, IOTA_FRAMEWORK_PACKAGE_ID]); } Ok(dependencies) } } -impl<'a> GetModule for &'a SuiTestAdapter { +impl<'a> GetModule for &'a IotaTestAdapter { type Error = anyhow::Error; type Item = &'a CompiledModule; @@ -1822,18 +1828,18 @@ impl fmt::Display for FakeID { static NAMED_ADDRESSES: Lazy> = Lazy::new(|| { let mut map = move_stdlib::move_stdlib_named_addresses(); assert!(map.get("std").unwrap().into_inner() == MOVE_STDLIB_ADDRESS); - // TODO fix Sui framework constants + // TODO fix Iota framework constants map.insert( - "sui".to_string(), + "iota".to_string(), NumericalAddress::new( - SUI_FRAMEWORK_ADDRESS.into_bytes(), + IOTA_FRAMEWORK_ADDRESS.into_bytes(), move_compiler::shared::NumberFormat::Hex, ), ); map.insert( - "sui_system".to_string(), + "iota_system".to_string(), NumericalAddress::new( - SUI_SYSTEM_ADDRESS.into_bytes(), + IOTA_SYSTEM_ADDRESS.into_bytes(), move_compiler::shared::NumberFormat::Hex, ), ); @@ -1851,36 +1857,41 @@ pub static PRE_COMPILED: Lazy = Lazy::new(|| { // TODO invoke package system? Or otherwise pull the versions for these packages // as per their actual Move.toml files. They way they are treated here is // odd, too, though. - let sui_files: &Path = Path::new(DEFAULT_FRAMEWORK_PATH); - let sui_system_sources = { - let mut buf = sui_files.to_path_buf(); - buf.extend(["packages", "sui-system", "sources"]); + let iota_files: &Path = Path::new(DEFAULT_FRAMEWORK_PATH); + let iota_system_sources = { + let mut buf = iota_files.to_path_buf(); + buf.extend(["packages", "iota-system", "sources"]); buf.to_string_lossy().to_string() }; - let sui_sources = { - let mut buf = sui_files.to_path_buf(); - buf.extend(["packages", "sui-framework", "sources"]); + let iota_sources = { + let mut buf = iota_files.to_path_buf(); + buf.extend(["packages", "iota-framework", "sources"]); buf.to_string_lossy().to_string() }; - let sui_deps = { - let mut buf = sui_files.to_path_buf(); + let iota_deps = { + let mut buf = iota_files.to_path_buf(); buf.extend(["packages", "move-stdlib", "sources"]); buf.to_string_lossy().to_string() }; let deepbook_sources = { - let mut buf = sui_files.to_path_buf(); + let mut buf = iota_files.to_path_buf(); buf.extend(["packages", "deepbook", "sources"]); buf.to_string_lossy().to_string() }; let config = PackageConfig { edition: Edition::E2024_BETA, - flavor: Flavor::Sui, + flavor: Flavor::Iota, ..Default::default() }; let fully_compiled_res = move_compiler::construct_pre_compiled_lib( vec![PackagePaths { - name: Some(("sui-framework".into(), config)), - paths: vec![sui_system_sources, sui_sources, sui_deps, deepbook_sources], + name: Some(("iota-framework".into(), config)), + paths: vec![ + iota_system_sources, + iota_sources, + iota_deps, + deepbook_sources, + ], named_address_map: NAMED_ADDRESSES.clone(), }], None, @@ -1889,7 +1900,7 @@ pub static PRE_COMPILED: Lazy = Lazy::new(|| { .unwrap(); match fully_compiled_res { Err((files, diags)) => { - eprintln!("!!!Sui framework failed to compile!!!"); + eprintln!("!!!Iota framework failed to compile!!!"); move_compiler::diagnostics::report_diagnostics(&files, diags) } Ok(res) => res, @@ -1972,7 +1983,7 @@ async fn init_val_fullnode_executor( test_account }; - // For each named Sui account without an address value, create an account with + // For each named Iota account without an address value, create an account with // an address and a gas object for n in account_names { let test_account = mk_account(); @@ -2028,7 +2039,7 @@ async fn init_sim_executor( let mut accounts = BTreeMap::new(); let mut objects = vec![]; - // For each named Sui account without an address value, create a key pair + // For each named Iota account without an address value, create a key pair for n in account_names { let test_account = get_key_pair_from_rng(&mut rng); account_kps.insert(n, test_account); @@ -2040,7 +2051,7 @@ async fn init_sim_executor( let (mut validator_addr, mut validator_key, mut key_copy) = (None, None, None); if custom_validator_account { // Make a validator account with a gas object - let (a, b): (SuiAddress, Ed25519KeyPair) = get_key_pair_from_rng(&mut rng); + let (a, b): (IotaAddress, Ed25519KeyPair) = get_key_pair_from_rng(&mut rng); key_copy = Some( Ed25519KeyPair::from_bytes(b.as_bytes()) @@ -2086,7 +2097,7 @@ async fn init_sim_executor( let mut hasher = std::collections::hash_map::DefaultHasher::new(); test_file_path.hash(&mut hasher); let hash = hasher.finish(); - let db_name = format!("sui_graphql_test_{}", hash); + let db_name = format!("iota_graphql_test_{}", hash); // Use the hash as a seed to generate a random port number let base_port = hash as u16 % 8192; @@ -2202,7 +2213,7 @@ async fn update_named_address_mapping( for (name, addr) in additional_mapping { if (named_address_mapping.contains_key(&name) && (named_address_mapping.get(&name) != Some(&addr))) - || name == "sui" + || name == "iota" { panic!( "Invalid init. The named address '{}' is reserved or duplicated", @@ -2213,11 +2224,11 @@ async fn update_named_address_mapping( } } -impl ObjectStore for SuiTestAdapter { +impl ObjectStore for IotaTestAdapter { fn get_object( &self, object_id: &ObjectID, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { ObjectStore::get_object(&*self.executor, object_id) } @@ -2225,52 +2236,52 @@ impl ObjectStore for SuiTestAdapter { &self, object_id: &ObjectID, version: VersionNumber, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { ObjectStore::get_object_by_key(&*self.executor, object_id, version) } } -impl ReadStore for SuiTestAdapter { +impl ReadStore for IotaTestAdapter { fn get_committee( &self, - epoch: sui_types::committee::EpochId, - ) -> sui_types::storage::error::Result>> { + epoch: iota_types::committee::EpochId, + ) -> iota_types::storage::error::Result>> { self.executor.get_committee(epoch) } - fn get_latest_checkpoint(&self) -> sui_types::storage::error::Result { + fn get_latest_checkpoint(&self) -> iota_types::storage::error::Result { ReadStore::get_latest_checkpoint(&self.executor) } fn get_highest_verified_checkpoint( &self, - ) -> sui_types::storage::error::Result { + ) -> iota_types::storage::error::Result { self.executor.get_highest_verified_checkpoint() } fn get_highest_synced_checkpoint( &self, - ) -> sui_types::storage::error::Result { + ) -> iota_types::storage::error::Result { self.executor.get_highest_synced_checkpoint() } fn get_lowest_available_checkpoint( &self, - ) -> sui_types::storage::error::Result { + ) -> iota_types::storage::error::Result { self.executor.get_lowest_available_checkpoint() } fn get_checkpoint_by_digest( &self, - digest: &sui_types::messages_checkpoint::CheckpointDigest, - ) -> sui_types::storage::error::Result> { + digest: &iota_types::messages_checkpoint::CheckpointDigest, + ) -> iota_types::storage::error::Result> { self.executor.get_checkpoint_by_digest(digest) } fn get_checkpoint_by_sequence_number( &self, sequence_number: CheckpointSequenceNumber, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { self.executor .get_checkpoint_by_sequence_number(sequence_number) } @@ -2278,14 +2289,14 @@ impl ReadStore for SuiTestAdapter { fn get_checkpoint_contents_by_digest( &self, digest: &CheckpointContentsDigest, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { self.executor.get_checkpoint_contents_by_digest(digest) } fn get_checkpoint_contents_by_sequence_number( &self, sequence_number: CheckpointSequenceNumber, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { self.executor .get_checkpoint_contents_by_sequence_number(sequence_number) } @@ -2293,29 +2304,29 @@ impl ReadStore for SuiTestAdapter { fn get_transaction( &self, tx_digest: &TransactionDigest, - ) -> sui_types::storage::error::Result>> { + ) -> iota_types::storage::error::Result>> { self.executor.get_transaction(tx_digest) } fn get_transaction_effects( &self, tx_digest: &TransactionDigest, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { self.executor.get_transaction_effects(tx_digest) } fn get_events( &self, event_digest: &TransactionEventsDigest, - ) -> sui_types::storage::error::Result> { + ) -> iota_types::storage::error::Result> { self.executor.get_events(event_digest) } fn get_full_checkpoint_contents_by_sequence_number( &self, sequence_number: CheckpointSequenceNumber, - ) -> sui_types::storage::error::Result< - Option, + ) -> iota_types::storage::error::Result< + Option, > { self.executor .get_full_checkpoint_contents_by_sequence_number(sequence_number) @@ -2324,8 +2335,8 @@ impl ReadStore for SuiTestAdapter { fn get_full_checkpoint_contents( &self, digest: &CheckpointContentsDigest, - ) -> sui_types::storage::error::Result< - Option, + ) -> iota_types::storage::error::Result< + Option, > { self.executor.get_full_checkpoint_contents(digest) } diff --git a/crates/iota-types/Cargo.toml b/crates/iota-types/Cargo.toml new file mode 100644 index 00000000000..6ca49ac12b7 --- /dev/null +++ b/crates/iota-types/Cargo.toml @@ -0,0 +1,90 @@ +[package] +name = "iota-types" +version = "0.1.0" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +anemo.workspace = true +anyhow.workspace = true +bincode.workspace = true +bcs.workspace = true +byteorder.workspace = true +consensus-config.workspace = true +im.workspace = true +itertools.workspace = true +nonempty.workspace = true +once_cell.workspace = true +prometheus.workspace = true +rand.workspace = true +serde.workspace = true +serde-name.workspace = true +thiserror.workspace = true +tracing.workspace = true +serde_json.workspace = true +serde_with.workspace = true +signature.workspace = true +static_assertions.workspace = true +schemars.workspace = true +tap.workspace = true +tonic.workspace = true +strum.workspace = true +strum_macros.workspace = true +roaring.workspace = true +enum_dispatch.workspace = true +eyre.workspace = true +indexmap.workspace = true +derivative.workspace = true +move-binary-format.workspace = true +move-bytecode-utils.workspace = true +move-command-line-common.workspace = true +move-core-types.workspace = true +move-disassembler.workspace = true +move-ir-types.workspace = true +move-vm-test-utils.workspace = true +move-vm-types.workspace = true +move-vm-profiler.workspace = true +num-traits = "0.2.18" +num-bigint = { version = "0.4", default-features = false, features = ["rand"] } + +narwhal-config.workspace = true +narwhal-crypto.workspace = true +iota-protocol-config.workspace = true +shared-crypto.workspace = true +mysten-network.workspace = true +mysten-metrics.workspace = true +iota-macros.workspace = true +iota-enum-compat-util.workspace = true + +fastcrypto = { workspace = true, features = ["copy_key"] } +fastcrypto-tbls.workspace = true +fastcrypto-zkp.workspace = true + +typed-store-error.workspace = true +derive_more.workspace = true +proptest.workspace = true +proptest-derive.workspace = true + +[dev-dependencies] +bincode.workspace = true +criterion.workspace = true +proptest.workspace = true +proptest-derive.workspace = true +serde_yaml.workspace = true +expect-test.workspace = true + +[[bench]] +name = "accumulator_bench" +harness = false + +[features] +default = [] +test-utils = [] +gas-profiler = [ + "move-vm-profiler/gas-profiler", + "move-vm-types/gas-profiler", + "move-vm-test-utils/gas-profiler", +] +fuzzing = ["move-core-types/fuzzing"] diff --git a/crates/sui-types/benches/accumulator_bench.rs b/crates/iota-types/benches/accumulator_bench.rs similarity index 90% rename from crates/sui-types/benches/accumulator_bench.rs rename to crates/iota-types/benches/accumulator_bench.rs index 9758e3f66ef..e17067a9d04 100644 --- a/crates/sui-types/benches/accumulator_bench.rs +++ b/crates/iota-types/benches/accumulator_bench.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use criterion::*; use fastcrypto::hash::MultisetHash; -use sui_types::{accumulator::Accumulator, base_types::ObjectDigest}; +use iota_types::{accumulator::Accumulator, base_types::ObjectDigest}; fn accumulator_benchmark(c: &mut Criterion) { { diff --git a/crates/iota-types/src/README.md b/crates/iota-types/src/README.md new file mode 100644 index 00000000000..9c999feada9 --- /dev/null +++ b/crates/iota-types/src/README.md @@ -0,0 +1,22 @@ +# iota-types README + +Note: this README file currently covers cryptography-related structs and methods. + +Currently, three files are equipped with signature and hashing functionality (`crypto.rs`, `signature_seed` and +`messages.rs`). See [Iota Signatures](https://github.com/iotaledger/iota/blob/main/docs/content/concepts/cryptography/transaction-auth/signatures.mdx) for supported signature schemes and its requirments for user and authority signatures. See [fastcrypto](https://github.com/MystenLabs/fastcrypto) for concrete implementation of various cryptography libraries. + +## Quick links + +- [crypto.rs](crypto.rs), the main library for cryptography (sign/verify/hash) structs and functions. +- [signature_seed.rs](signature_seed.rs), deterministic signer using a seed, domain and some key identifier. Potential + usage includes custodial services, in which user keys are not deterministically derived from BIP44/BIP32, but from their + username (i.e., email address). +- [messages.rs](messages.rs), functionality for adding/verifying signatures to transactions (for both account holders + and validators). + +## Tests + +Unit tests exist under the `unit_tests` folder, in particular + +- `messages_tests`: to handle signed values, aggregation and certificates. +- `signature_seed_tests`: for deterministic key derivation functionality. diff --git a/crates/sui-types/src/accumulator.rs b/crates/iota-types/src/accumulator.rs similarity index 98% rename from crates/sui-types/src/accumulator.rs rename to crates/iota-types/src/accumulator.rs index e04b22de22b..84737cd10c5 100644 --- a/crates/sui-types/src/accumulator.rs +++ b/crates/iota-types/src/accumulator.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 pub type Accumulator = fastcrypto::hash::EllipticCurveMultisetHash; diff --git a/crates/sui-types/src/authenticator_state.rs b/crates/iota-types/src/authenticator_state.rs similarity index 85% rename from crates/sui-types/src/authenticator_state.rs rename to crates/iota-types/src/authenticator_state.rs index 954228492a6..1b44683aeed 100644 --- a/crates/sui-types/src/authenticator_state.rs +++ b/crates/iota-types/src/authenticator_state.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use fastcrypto_zkp::bn254::zk_login::{JwkId, JWK}; @@ -8,11 +9,11 @@ use serde::{Deserialize, Serialize}; use crate::{ base_types::SequenceNumber, dynamic_field::get_dynamic_field_from_store, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, id::UID, object::Owner, storage::ObjectStore, - SUI_AUTHENTICATOR_STATE_OBJECT_ID, SUI_FRAMEWORK_ADDRESS, + IOTA_AUTHENTICATOR_STATE_OBJECT_ID, IOTA_FRAMEWORK_ADDRESS, }; pub const AUTHENTICATOR_STATE_MODULE_NAME: &IdentStr = ident_str!("authenticator_state"); @@ -21,8 +22,8 @@ pub const AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME: &IdentStr = ident_str!("update_authenticator_state"); pub const AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME: &IdentStr = ident_str!("create"); pub const AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME: &IdentStr = ident_str!("expire_jwks"); -pub const RESOLVED_SUI_AUTHENTICATOR_STATE: (&AccountAddress, &IdentStr, &IdentStr) = ( - &SUI_FRAMEWORK_ADDRESS, +pub const RESOLVED_IOTA_AUTHENTICATOR_STATE: (&AccountAddress, &IdentStr, &IdentStr) = ( + &IOTA_FRAMEWORK_ADDRESS, AUTHENTICATOR_STATE_MODULE_NAME, AUTHENTICATOR_STATE_STRUCT_NAME, ); @@ -110,18 +111,18 @@ impl std::cmp::Ord for ActiveJwk { pub fn get_authenticator_state( object_store: &dyn ObjectStore, -) -> SuiResult> { - let outer = object_store.get_object(&SUI_AUTHENTICATOR_STATE_OBJECT_ID)?; +) -> IotaResult> { + let outer = object_store.get_object(&IOTA_AUTHENTICATOR_STATE_OBJECT_ID)?; let Some(outer) = outer else { return Ok(None); }; let move_object = outer.data.try_as_move().ok_or_else(|| { - SuiError::SuiSystemStateReadError( + IotaError::IotaSystemStateReadError( "AuthenticatorState object must be a Move object".to_owned(), ) })?; let outer = bcs::from_bytes::(move_object.contents()) - .map_err(|err| SuiError::SuiSystemStateReadError(err.to_string()))?; + .map_err(|err| IotaError::IotaSystemStateReadError(err.to_string()))?; // No other versions exist yet. assert_eq!(outer.version, AUTHENTICATOR_STATE_VERSION); @@ -129,8 +130,8 @@ pub fn get_authenticator_state( let id = outer.id.id.bytes; let inner: AuthenticatorStateInner = get_dynamic_field_from_store(object_store, id, &outer.version).map_err(|err| { - SuiError::DynamicFieldReadError(format!( - "Failed to load sui system state inner object with ID {:?} and version {:?}: {:?}", + IotaError::DynamicFieldReadError(format!( + "Failed to load iota system state inner object with ID {:?} and version {:?}: {:?}", id, outer.version, err )) })?; @@ -140,9 +141,9 @@ pub fn get_authenticator_state( pub fn get_authenticator_state_obj_initial_shared_version( object_store: &dyn ObjectStore, -) -> SuiResult> { +) -> IotaResult> { Ok(object_store - .get_object(&SUI_AUTHENTICATOR_STATE_OBJECT_ID)? + .get_object(&IOTA_AUTHENTICATOR_STATE_OBJECT_ID)? .map(|obj| match obj.owner { Owner::Shared { initial_shared_version, diff --git a/crates/iota-types/src/balance.rs b/crates/iota-types/src/balance.rs new file mode 100644 index 00000000000..459fc3d2ebe --- /dev/null +++ b/crates/iota-types/src/balance.rs @@ -0,0 +1,91 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use move_core_types::{ + annotated_value::{MoveFieldLayout, MoveStructLayout, MoveTypeLayout}, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag}, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +use crate::{ + error::{ExecutionError, ExecutionErrorKind}, + iota_serde::{BigInt, Readable}, + IOTA_FRAMEWORK_ADDRESS, +}; +pub const BALANCE_MODULE_NAME: &IdentStr = ident_str!("balance"); +pub const BALANCE_STRUCT_NAME: &IdentStr = ident_str!("Balance"); +pub const BALANCE_CREATE_REWARDS_FUNCTION_NAME: &IdentStr = ident_str!("create_staking_rewards"); +pub const BALANCE_DESTROY_REBATES_FUNCTION_NAME: &IdentStr = ident_str!("destroy_storage_rebates"); + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, JsonSchema)] +pub struct Supply { + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub value: u64, +} + +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema, Eq, PartialEq)] +pub struct Balance { + value: u64, +} + +impl Balance { + pub fn new(value: u64) -> Self { + Self { value } + } + + pub fn type_(type_param: TypeTag) -> StructTag { + StructTag { + address: IOTA_FRAMEWORK_ADDRESS, + module: BALANCE_MODULE_NAME.to_owned(), + name: BALANCE_STRUCT_NAME.to_owned(), + type_params: vec![type_param], + } + } + + pub fn is_balance(s: &StructTag) -> bool { + s.address == IOTA_FRAMEWORK_ADDRESS + && s.module.as_ident_str() == BALANCE_MODULE_NAME + && s.name.as_ident_str() == BALANCE_STRUCT_NAME + } + + pub fn withdraw(&mut self, amount: u64) -> Result<(), ExecutionError> { + fp_ensure!( + self.value >= amount, + ExecutionError::new_with_source( + ExecutionErrorKind::InsufficientCoinBalance, + format!("balance: {} required: {}", self.value, amount) + ) + ); + self.value -= amount; + Ok(()) + } + + pub fn deposit_for_safe_mode(&mut self, amount: u64) { + self.value += amount; + } + + pub fn value(&self) -> u64 { + self.value + } + + pub fn to_bcs_bytes(&self) -> Vec { + bcs::to_bytes(&self).unwrap() + } + + pub fn layout(type_param: TypeTag) -> MoveStructLayout { + MoveStructLayout { + type_: Self::type_(type_param), + fields: vec![MoveFieldLayout::new( + ident_str!("value").to_owned(), + MoveTypeLayout::U64, + )], + } + } +} diff --git a/crates/sui-types/src/base_types.rs b/crates/iota-types/src/base_types.rs similarity index 83% rename from crates/sui-types/src/base_types.rs rename to crates/iota-types/src/base_types.rs index f50060f3a3f..b9f1f0d34cc 100644 --- a/crates/sui-types/src/base_types.rs +++ b/crates/iota-types/src/base_types.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -34,26 +35,26 @@ use crate::{ balance::Balance, coin::{Coin, CoinMetadata, TreasuryCap, COIN_MODULE_NAME, COIN_STRUCT_NAME}, crypto::{ - AuthorityPublicKeyBytes, DefaultHash, PublicKey, SignatureScheme, SuiPublicKey, - SuiSignature, + AuthorityPublicKeyBytes, DefaultHash, IotaPublicKey, IotaSignature, PublicKey, + SignatureScheme, }, dynamic_field::{DynamicFieldInfo, DynamicFieldType}, effects::{TransactionEffects, TransactionEffectsAPI}, epoch_data::EpochData, - error::{ExecutionError, ExecutionErrorKind, SuiError, SuiResult}, + error::{ExecutionError, ExecutionErrorKind, IotaError, IotaResult}, gas_coin::{GasCoin, GAS}, - governance::{StakedSui, STAKED_SUI_STRUCT_NAME, STAKING_POOL_MODULE_NAME}, - id::RESOLVED_SUI_ID, + governance::{StakedIota, STAKED_IOTA_STRUCT_NAME, STAKING_POOL_MODULE_NAME}, + id::RESOLVED_IOTA_ID, + iota_serde::{to_iota_struct_tag_string, HexAccountAddress, Readable}, messages_checkpoint::CheckpointTimestamp, multisig::MultiSigPublicKey, object::{Object, Owner}, - parse_sui_struct_tag, + parse_iota_struct_tag, signature::GenericSignature, - sui_serde::{to_sui_struct_tag_string, HexAccountAddress, Readable}, - timelock::{timelock, timelock::TimeLock, timelocked_staked_sui::TimelockedStakedSui}, + timelock::{timelock, timelock::TimeLock, timelocked_staked_iota::TimelockedStakedIota}, transaction::{Transaction, VerifiedTransaction}, zk_login_authenticator::ZkLoginAuthenticator, - MOVE_STDLIB_ADDRESS, SUI_CLOCK_OBJECT_ID, SUI_FRAMEWORK_ADDRESS, SUI_SYSTEM_ADDRESS, + IOTA_CLOCK_OBJECT_ID, IOTA_FRAMEWORK_ADDRESS, IOTA_SYSTEM_ADDRESS, MOVE_STDLIB_ADDRESS, }; pub use crate::{ committee::EpochId, @@ -162,12 +163,12 @@ pub struct MoveObjectType(MoveObjectType_); pub enum MoveObjectType_ { /// A type that is not `0x2::coin::Coin` Other(StructTag), - /// A SUI coin (i.e., `0x2::coin::Coin<0x2::sui::SUI>`) + /// A IOTA coin (i.e., `0x2::coin::Coin<0x2::iota::IOTA>`) GasCoin, - /// A record of a staked SUI coin (i.e., `0x3::staking_pool::StakedSui`) - StakedSui, - /// A non-SUI coin type (i.e., `0x2::coin::Coin where T != - /// 0x2::sui::SUI`) + /// A record of a staked IOTA coin (i.e., `0x3::staking_pool::StakedIota`) + StakedIota, + /// A non-IOTA coin type (i.e., `0x2::coin::Coin where T != + /// 0x2::iota::IOTA`) Coin(TypeTag), // NOTE: if adding a new type here, and there are existing on-chain objects of that // type with Other(_), that is ok, but you must hand-roll PartialEq/Eq/Ord/maybe Hash @@ -179,24 +180,24 @@ impl MoveObjectType { Self(MoveObjectType_::GasCoin) } - pub fn staked_sui() -> Self { - Self(MoveObjectType_::StakedSui) + pub fn staked_iota() -> Self { + Self(MoveObjectType_::StakedIota) } - pub fn timelocked_sui_balance() -> Self { + pub fn timelocked_iota_balance() -> Self { Self(MoveObjectType_::Other(TimeLock::::type_( Balance::type_(GAS::type_().into()).into(), ))) } - pub fn timelocked_staked_sui() -> Self { - Self(MoveObjectType_::Other(TimelockedStakedSui::type_())) + pub fn timelocked_staked_iota() -> Self { + Self(MoveObjectType_::Other(TimelockedStakedIota::type_())) } pub fn address(&self) -> AccountAddress { match &self.0 { - MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) => SUI_FRAMEWORK_ADDRESS, - MoveObjectType_::StakedSui => SUI_SYSTEM_ADDRESS, + MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) => IOTA_FRAMEWORK_ADDRESS, + MoveObjectType_::StakedIota => IOTA_SYSTEM_ADDRESS, MoveObjectType_::Other(s) => s.address, } } @@ -204,7 +205,7 @@ impl MoveObjectType { pub fn module(&self) -> &IdentStr { match &self.0 { MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) => COIN_MODULE_NAME, - MoveObjectType_::StakedSui => STAKING_POOL_MODULE_NAME, + MoveObjectType_::StakedIota => STAKING_POOL_MODULE_NAME, MoveObjectType_::Other(s) => &s.module, } } @@ -212,7 +213,7 @@ impl MoveObjectType { pub fn name(&self) -> &IdentStr { match &self.0 { MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) => COIN_STRUCT_NAME, - MoveObjectType_::StakedSui => STAKED_SUI_STRUCT_NAME, + MoveObjectType_::StakedIota => STAKED_IOTA_STRUCT_NAME, MoveObjectType_::Other(s) => &s.name, } } @@ -220,7 +221,7 @@ impl MoveObjectType { pub fn type_params(&self) -> Vec { match &self.0 { MoveObjectType_::GasCoin => vec![GAS::type_tag()], - MoveObjectType_::StakedSui => vec![], + MoveObjectType_::StakedIota => vec![], MoveObjectType_::Coin(inner) => vec![inner.clone()], MoveObjectType_::Other(s) => s.type_params.clone(), } @@ -229,7 +230,7 @@ impl MoveObjectType { pub fn into_type_params(self) -> Vec { match self.0 { MoveObjectType_::GasCoin => vec![GAS::type_tag()], - MoveObjectType_::StakedSui => vec![], + MoveObjectType_::StakedIota => vec![], MoveObjectType_::Coin(inner) => vec![inner], MoveObjectType_::Other(s) => s.type_params, } @@ -239,7 +240,7 @@ impl MoveObjectType { match &self.0 { MoveObjectType_::GasCoin => Some(GAS::type_tag()), MoveObjectType_::Coin(inner) => Some(inner.clone()), - MoveObjectType_::StakedSui => None, + MoveObjectType_::StakedIota => None, MoveObjectType_::Other(_) => None, } } @@ -252,26 +253,26 @@ impl MoveObjectType { // unwraps safe because a `StructTag` cannot fail to serialize match &self.0 { MoveObjectType_::GasCoin => 1, - MoveObjectType_::StakedSui => 1, + MoveObjectType_::StakedIota => 1, MoveObjectType_::Coin(inner) => bcs::serialized_size(inner).unwrap() + 1, MoveObjectType_::Other(s) => bcs::serialized_size(s).unwrap() + 1, } } /// Return true if `self` is `0x2::coin::Coin` for some T (note: T can be - /// SUI) + /// IOTA) pub fn is_coin(&self) -> bool { match &self.0 { MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) => true, - MoveObjectType_::StakedSui | MoveObjectType_::Other(_) => false, + MoveObjectType_::StakedIota | MoveObjectType_::Other(_) => false, } } - /// Return true if `self` is 0x2::coin::Coin<0x2::sui::SUI> + /// Return true if `self` is 0x2::coin::Coin<0x2::iota::IOTA> pub fn is_gas_coin(&self) -> bool { match &self.0 { MoveObjectType_::GasCoin => true, - MoveObjectType_::StakedSui | MoveObjectType_::Coin(_) | MoveObjectType_::Other(_) => { + MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) | MoveObjectType_::Other(_) => { false } } @@ -282,13 +283,13 @@ impl MoveObjectType { match &self.0 { MoveObjectType_::GasCoin => GAS::is_gas_type(t), MoveObjectType_::Coin(c) => t == c, - MoveObjectType_::StakedSui | MoveObjectType_::Other(_) => false, + MoveObjectType_::StakedIota | MoveObjectType_::Other(_) => false, } } - pub fn is_staked_sui(&self) -> bool { + pub fn is_staked_iota(&self) -> bool { match &self.0 { - MoveObjectType_::StakedSui => true, + MoveObjectType_::StakedIota => true, MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) | MoveObjectType_::Other(_) => { false } @@ -297,7 +298,7 @@ impl MoveObjectType { pub fn is_coin_metadata(&self) -> bool { match &self.0 { - MoveObjectType_::GasCoin | MoveObjectType_::StakedSui | MoveObjectType_::Coin(_) => { + MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => { false } MoveObjectType_::Other(s) => CoinMetadata::is_coin_metadata(s), @@ -306,7 +307,7 @@ impl MoveObjectType { pub fn is_treasury_cap(&self) -> bool { match &self.0 { - MoveObjectType_::GasCoin | MoveObjectType_::StakedSui | MoveObjectType_::Coin(_) => { + MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => { false } MoveObjectType_::Other(s) => TreasuryCap::is_treasury_type(s), @@ -314,26 +315,26 @@ impl MoveObjectType { } pub fn is_upgrade_cap(&self) -> bool { - self.address() == SUI_FRAMEWORK_ADDRESS + self.address() == IOTA_FRAMEWORK_ADDRESS && self.module().as_str() == "package" && self.name().as_str() == "UpgradeCap" } pub fn is_regulated_coin_metadata(&self) -> bool { - self.address() == SUI_FRAMEWORK_ADDRESS + self.address() == IOTA_FRAMEWORK_ADDRESS && self.module().as_str() == "coin" && self.name().as_str() == "RegulatedCoinMetadata" } pub fn is_coin_deny_cap(&self) -> bool { - self.address() == SUI_FRAMEWORK_ADDRESS + self.address() == IOTA_FRAMEWORK_ADDRESS && self.module().as_str() == "coin" && self.name().as_str() == "DenyCap" } pub fn is_dynamic_field(&self) -> bool { match &self.0 { - MoveObjectType_::GasCoin | MoveObjectType_::StakedSui | MoveObjectType_::Coin(_) => { + MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => { false } MoveObjectType_::Other(s) => DynamicFieldInfo::is_dynamic_field(s), @@ -342,7 +343,7 @@ impl MoveObjectType { pub fn is_timelock(&self) -> bool { match &self.0 { - MoveObjectType_::GasCoin | MoveObjectType_::StakedSui | MoveObjectType_::Coin(_) => { + MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => { false } MoveObjectType_::Other(s) => timelock::is_timelock(s), @@ -351,26 +352,26 @@ impl MoveObjectType { pub fn is_timelocked_balance(&self) -> bool { match &self.0 { - MoveObjectType_::GasCoin | MoveObjectType_::StakedSui | MoveObjectType_::Coin(_) => { + MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => { false } MoveObjectType_::Other(s) => timelock::is_timelocked_balance(s), } } - pub fn is_timelocked_staked_sui(&self) -> bool { + pub fn is_timelocked_staked_iota(&self) -> bool { match &self.0 { - MoveObjectType_::GasCoin | MoveObjectType_::StakedSui | MoveObjectType_::Coin(_) => { + MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => { false } - MoveObjectType_::Other(s) => TimelockedStakedSui::is_timelocked_staked_sui(s), + MoveObjectType_::Other(s) => TimelockedStakedIota::is_timelocked_staked_iota(s), } } - pub fn try_extract_field_name(&self, type_: &DynamicFieldType) -> SuiResult { + pub fn try_extract_field_name(&self, type_: &DynamicFieldType) -> IotaResult { match &self.0 { - MoveObjectType_::GasCoin | MoveObjectType_::StakedSui | MoveObjectType_::Coin(_) => { - Err(SuiError::ObjectDeserializationError { + MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => { + Err(IotaError::ObjectDeserializationError { error: "Error extracting dynamic object name from Coin object".to_string(), }) } @@ -378,10 +379,10 @@ impl MoveObjectType { } } - pub fn try_extract_field_value(&self) -> SuiResult { + pub fn try_extract_field_value(&self) -> IotaResult { match &self.0 { - MoveObjectType_::GasCoin | MoveObjectType_::StakedSui | MoveObjectType_::Coin(_) => { - Err(SuiError::ObjectDeserializationError { + MoveObjectType_::GasCoin | MoveObjectType_::StakedIota | MoveObjectType_::Coin(_) => { + Err(IotaError::ObjectDeserializationError { error: "Error extracting dynamic object value from Coin object".to_string(), }) } @@ -392,7 +393,7 @@ impl MoveObjectType { pub fn is(&self, s: &StructTag) -> bool { match &self.0 { MoveObjectType_::GasCoin => GasCoin::is_gas_coin(s), - MoveObjectType_::StakedSui => StakedSui::is_staked_sui(s), + MoveObjectType_::StakedIota => StakedIota::is_staked_iota(s), MoveObjectType_::Coin(inner) => { Coin::is_coin(s) && s.type_params.len() == 1 && inner == &s.type_params[0] } @@ -414,8 +415,8 @@ impl From for MoveObjectType { } else if Coin::is_coin(&s) { // unwrap safe because a coin has exactly one type parameter MoveObjectType_::Coin(s.type_params.pop().unwrap()) - } else if StakedSui::is_staked_sui(&s) { - MoveObjectType_::StakedSui + } else if StakedIota::is_staked_iota(&s) { + MoveObjectType_::StakedIota } else { MoveObjectType_::Other(s) }) @@ -426,7 +427,7 @@ impl From for StructTag { fn from(t: MoveObjectType) -> Self { match t.0 { MoveObjectType_::GasCoin => GasCoin::type_(), - MoveObjectType_::StakedSui => StakedSui::type_(), + MoveObjectType_::StakedIota => StakedIota::type_(), MoveObjectType_::Coin(inner) => Coin::type_(inner), MoveObjectType_::Other(s) => s, } @@ -456,7 +457,7 @@ pub fn is_primitive_type_tag(t: &TypeTag) -> bool { } = &**st; let resolved_struct = (address, module.as_ident_str(), name.as_ident_str()); // is id or.. - if resolved_struct == RESOLVED_SUI_ID { + if resolved_struct == RESOLVED_IOTA_ID { return true; } // is option of a primitive @@ -468,7 +469,7 @@ pub fn is_primitive_type_tag(t: &TypeTag) -> bool { } } -/// Type of a Sui object +/// Type of a Iota object #[derive(Clone, Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Debug)] pub enum ObjectType { /// Move package containing one or more bytecode modules @@ -504,7 +505,7 @@ impl FromStr for ObjectType { if s.to_lowercase() == PACKAGE { Ok(ObjectType::Package) } else { - let tag = parse_sui_struct_tag(s)?; + let tag = parse_iota_struct_tag(s)?; Ok(ObjectType::Struct(MoveObjectType::from(tag))) } } @@ -565,21 +566,21 @@ impl From<&ObjectInfo> for ObjectRef { } } -pub const SUI_ADDRESS_LENGTH: usize = ObjectID::LENGTH; +pub const IOTA_ADDRESS_LENGTH: usize = ObjectID::LENGTH; #[serde_as] #[derive( Eq, Default, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Serialize, Deserialize, JsonSchema, )] #[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))] -pub struct SuiAddress( +pub struct IotaAddress( #[schemars(with = "Hex")] #[serde_as(as = "Readable")] - [u8; SUI_ADDRESS_LENGTH], + [u8; IOTA_ADDRESS_LENGTH], ); -impl SuiAddress { - pub const ZERO: Self = Self([0u8; SUI_ADDRESS_LENGTH]); +impl IotaAddress { + pub const ZERO: Self = Self([0u8; IOTA_ADDRESS_LENGTH]); /// Convert the address to a byte buffer. pub fn to_vec(&self) -> Vec { @@ -587,19 +588,19 @@ impl SuiAddress { } #[cfg(any(feature = "test-utils", test))] - /// Return a random SuiAddress. + /// Return a random IotaAddress. pub fn random_for_testing_only() -> Self { AccountAddress::random().into() } pub fn generate(mut rng: R) -> Self { - let buf: [u8; SUI_ADDRESS_LENGTH] = rng.gen(); + let buf: [u8; IOTA_ADDRESS_LENGTH] = rng.gen(); Self(buf) } - /// Serialize an `Option` in Hex. + /// Serialize an `Option` in Hex. pub fn optional_address_as_hex( - key: &Option, + key: &Option, serializer: S, ) -> Result where @@ -608,10 +609,10 @@ impl SuiAddress { serializer.serialize_str(&key.map(Hex::encode).unwrap_or_default()) } - /// Deserialize into an `Option`. + /// Deserialize into an `Option`. pub fn optional_address_from_hex<'de, D>( deserializer: D, - ) -> Result, D::Error> + ) -> Result, D::Error> where D: serde::de::Deserializer<'de>, { @@ -620,103 +621,103 @@ impl SuiAddress { Ok(Some(value)) } - /// Return the underlying byte array of a SuiAddress. - pub fn to_inner(self) -> [u8; SUI_ADDRESS_LENGTH] { + /// Return the underlying byte array of a IotaAddress. + pub fn to_inner(self) -> [u8; IOTA_ADDRESS_LENGTH] { self.0 } - /// Parse a SuiAddress from a byte array or buffer. - pub fn from_bytes>(bytes: T) -> Result { - <[u8; SUI_ADDRESS_LENGTH]>::try_from(bytes.as_ref()) - .map_err(|_| SuiError::InvalidAddress) - .map(SuiAddress) + /// Parse a IotaAddress from a byte array or buffer. + pub fn from_bytes>(bytes: T) -> Result { + <[u8; IOTA_ADDRESS_LENGTH]>::try_from(bytes.as_ref()) + .map_err(|_| IotaError::InvalidAddress) + .map(IotaAddress) } /// This derives a zkLogin address by parsing the iss and address_seed from /// [struct ZkLoginAuthenticator]. Define as iss_bytes_len || iss_bytes /// || padded_32_byte_address_seed. This is to be differentiated with /// try_from_unpadded defined below. - pub fn try_from_padded(inputs: &ZkLoginInputs) -> SuiResult { + pub fn try_from_padded(inputs: &ZkLoginInputs) -> IotaResult { Ok((&PublicKey::from_zklogin_inputs(inputs)?).into()) } /// Define as iss_bytes_len || iss_bytes || unpadded_32_byte_address_seed. - pub fn try_from_unpadded(inputs: &ZkLoginInputs) -> SuiResult { + pub fn try_from_unpadded(inputs: &ZkLoginInputs) -> IotaResult { let mut hasher = DefaultHash::default(); hasher.update([SignatureScheme::ZkLoginAuthenticator.flag()]); let iss_bytes = inputs.get_iss().as_bytes(); hasher.update([iss_bytes.len() as u8]); hasher.update(iss_bytes); hasher.update(inputs.get_address_seed().unpadded()); - Ok(SuiAddress(hasher.finalize().digest)) + Ok(IotaAddress(hasher.finalize().digest)) } } -impl From for SuiAddress { - fn from(object_id: ObjectID) -> SuiAddress { +impl From for IotaAddress { + fn from(object_id: ObjectID) -> IotaAddress { Self(object_id.into_bytes()) } } -impl From for SuiAddress { - fn from(address: AccountAddress) -> SuiAddress { +impl From for IotaAddress { + fn from(address: AccountAddress) -> IotaAddress { Self(address.into_bytes()) } } -impl TryFrom<&[u8]> for SuiAddress { - type Error = SuiError; +impl TryFrom<&[u8]> for IotaAddress { + type Error = IotaError; - /// Tries to convert the provided byte array into a SuiAddress. - fn try_from(bytes: &[u8]) -> Result { + /// Tries to convert the provided byte array into a IotaAddress. + fn try_from(bytes: &[u8]) -> Result { Self::from_bytes(bytes) } } -impl TryFrom> for SuiAddress { - type Error = SuiError; +impl TryFrom> for IotaAddress { + type Error = IotaError; - /// Tries to convert the provided byte buffer into a SuiAddress. - fn try_from(bytes: Vec) -> Result { + /// Tries to convert the provided byte buffer into a IotaAddress. + fn try_from(bytes: Vec) -> Result { Self::from_bytes(bytes) } } -impl AsRef<[u8]> for SuiAddress { +impl AsRef<[u8]> for IotaAddress { fn as_ref(&self) -> &[u8] { &self.0[..] } } -impl FromStr for SuiAddress { +impl FromStr for IotaAddress { type Err = anyhow::Error; fn from_str(s: &str) -> Result { decode_bytes_hex(s).map_err(|e| anyhow!(e)) } } -impl From<&T> for SuiAddress { +impl From<&T> for IotaAddress { fn from(pk: &T) -> Self { let mut hasher = DefaultHash::default(); T::SIGNATURE_SCHEME.update_hasher_with_flag(&mut hasher); hasher.update(pk); let g_arr = hasher.finalize(); - SuiAddress(g_arr.digest) + IotaAddress(g_arr.digest) } } -impl From<&PublicKey> for SuiAddress { +impl From<&PublicKey> for IotaAddress { fn from(pk: &PublicKey) -> Self { let mut hasher = DefaultHash::default(); pk.scheme().update_hasher_with_flag(&mut hasher); hasher.update(pk); let g_arr = hasher.finalize(); - SuiAddress(g_arr.digest) + IotaAddress(g_arr.digest) } } -impl From<&MultiSigPublicKey> for SuiAddress { - /// Derive a SuiAddress from [struct MultiSigPublicKey]. A MultiSig address +impl From<&MultiSigPublicKey> for IotaAddress { + /// Derive a IotaAddress from [struct MultiSigPublicKey]. A MultiSig address /// is defined as the 32-byte Blake2b hash of serializing the flag, the /// threshold, concatenation of all n flag, public keys and /// its weight. `flag_MultiSig || threshold || flag_1 || pk_1 || weight_1 @@ -733,69 +734,69 @@ impl From<&MultiSigPublicKey> for SuiAddress { hasher.update(pk.as_ref()); hasher.update(w.to_le_bytes()); }); - SuiAddress(hasher.finalize().digest) + IotaAddress(hasher.finalize().digest) } } -/// Sui address for [struct ZkLoginAuthenticator] is defined as the black2b hash -/// of [zklogin_flag || iss_bytes_length || iss_bytes || +/// Iota address for [struct ZkLoginAuthenticator] is defined as the black2b +/// hash of [zklogin_flag || iss_bytes_length || iss_bytes || /// unpadded_address_seed_in_bytes]. -impl TryFrom<&ZkLoginAuthenticator> for SuiAddress { - type Error = SuiError; - fn try_from(authenticator: &ZkLoginAuthenticator) -> SuiResult { - SuiAddress::try_from_unpadded(&authenticator.inputs) +impl TryFrom<&ZkLoginAuthenticator> for IotaAddress { + type Error = IotaError; + fn try_from(authenticator: &ZkLoginAuthenticator) -> IotaResult { + IotaAddress::try_from_unpadded(&authenticator.inputs) } } -impl TryFrom<&GenericSignature> for SuiAddress { - type Error = SuiError; - /// Derive a SuiAddress from a serialized signature in Sui +impl TryFrom<&GenericSignature> for IotaAddress { + type Error = IotaError; + /// Derive a IotaAddress from a serialized signature in Iota /// [GenericSignature]. - fn try_from(sig: &GenericSignature) -> SuiResult { + fn try_from(sig: &GenericSignature) -> IotaResult { match sig { GenericSignature::Signature(sig) => { let scheme = sig.scheme(); let pub_key_bytes = sig.public_key_bytes(); let pub_key = PublicKey::try_from_bytes(scheme, pub_key_bytes).map_err(|_| { - SuiError::InvalidSignature { + IotaError::InvalidSignature { error: "Cannot parse pubkey".to_string(), } })?; - Ok(SuiAddress::from(&pub_key)) + Ok(IotaAddress::from(&pub_key)) } GenericSignature::MultiSig(ms) => Ok(ms.get_pk().into()), GenericSignature::MultiSigLegacy(ms) => { Ok(crate::multisig::MultiSig::try_from(ms.clone()) - .map_err(|_| SuiError::InvalidSignature { + .map_err(|_| IotaError::InvalidSignature { error: "Invalid legacy multisig".to_string(), })? .get_pk() .into()) } GenericSignature::ZkLoginAuthenticator(zklogin) => { - SuiAddress::try_from_unpadded(&zklogin.inputs) + IotaAddress::try_from_unpadded(&zklogin.inputs) } } } } -impl fmt::Display for SuiAddress { +impl fmt::Display for IotaAddress { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "0x{}", Hex::encode(self.0)) } } -impl fmt::Debug for SuiAddress { +impl fmt::Debug for IotaAddress { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "0x{}", Hex::encode(self.0)) } } #[cfg(any(test, feature = "test-utils"))] -/// Generate a fake SuiAddress with repeated one byte. -pub fn dbg_addr(name: u8) -> SuiAddress { - let addr = [name; SUI_ADDRESS_LENGTH]; - SuiAddress(addr) +/// Generate a fake IotaAddress with repeated one byte. +pub fn dbg_addr(name: u8) -> IotaAddress { + let addr = [name; IOTA_ADDRESS_LENGTH]; + IotaAddress(addr) } #[derive( @@ -929,7 +930,7 @@ pub enum TxContextKind { } impl TxContext { - pub fn new(sender: &SuiAddress, digest: &TransactionDigest, epoch_data: &EpochData) -> Self { + pub fn new(sender: &IotaAddress, digest: &TransactionDigest, epoch_data: &EpochData) -> Self { Self::new_from_components( sender, digest, @@ -939,7 +940,7 @@ impl TxContext { } pub fn new_from_components( - sender: &SuiAddress, + sender: &IotaAddress, digest: &TransactionDigest, epoch_id: &EpochId, epoch_timestamp_ms: u64, @@ -969,7 +970,7 @@ impl TxContext { let (module_addr, module_name, struct_name) = resolve_struct(view, *idx); let is_tx_context_type = module_name == TX_CONTEXT_MODULE_NAME - && module_addr == &SUI_FRAMEWORK_ADDRESS + && module_addr == &IOTA_FRAMEWORK_ADDRESS && struct_name == TX_CONTEXT_STRUCT_NAME; if is_tx_context_type { @@ -997,8 +998,8 @@ impl TxContext { TransactionDigest::new(self.digest.clone().try_into().unwrap()) } - pub fn sender(&self) -> SuiAddress { - SuiAddress::from(ObjectID(self.sender)) + pub fn sender(&self) -> IotaAddress { + IotaAddress::from(ObjectID(self.sender)) } pub fn to_vec(&self) -> Vec { @@ -1027,7 +1028,7 @@ impl TxContext { // Generate a random TxContext for testing. pub fn random_for_testing_only() -> Self { Self::new( - &SuiAddress::random_for_testing_only(), + &IotaAddress::random_for_testing_only(), &TransactionDigest::random(), &EpochData::new_test(), ) @@ -1035,7 +1036,7 @@ impl TxContext { #[cfg(feature = "test-utils")] /// Generate a TxContext for testing with a specific sender. - pub fn with_sender_for_testing_only(sender: &SuiAddress) -> Self { + pub fn with_sender_for_testing_only(sender: &IotaAddress) -> Self { Self::new(sender, &TransactionDigest::random(), &EpochData::new_test()) } } @@ -1272,12 +1273,12 @@ impl ObjectID { } pub fn is_clock(&self) -> bool { - *self == SUI_CLOCK_OBJECT_ID + *self == IOTA_CLOCK_OBJECT_ID } } -impl From for ObjectID { - fn from(address: SuiAddress) -> ObjectID { +impl From for ObjectID { + fn from(address: IotaAddress) -> ObjectID { let tmp: AccountAddress = address.into(); tmp.into() } @@ -1364,8 +1365,8 @@ impl From for AccountAddress { } } -impl From for AccountAddress { - fn from(address: SuiAddress) -> Self { +impl From for AccountAddress { + fn from(address: IotaAddress) -> Self { Self::new(address.0) } } @@ -1376,7 +1377,7 @@ impl fmt::Display for MoveObjectType { write!( f, "{}", - to_sui_struct_tag_string(&s).map_err(fmt::Error::custom)? + to_iota_struct_tag_string(&s).map_err(fmt::Error::custom)? ) } } diff --git a/crates/iota-types/src/bridge.rs b/crates/iota-types/src/bridge.rs new file mode 100644 index 00000000000..b4599263aa3 --- /dev/null +++ b/crates/iota-types/src/bridge.rs @@ -0,0 +1,28 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use move_core_types::{ident_str, identifier::IdentStr}; + +use crate::{ + base_types::SequenceNumber, error::IotaResult, object::Owner, storage::ObjectStore, + IOTA_BRIDGE_OBJECT_ID, +}; + +pub const BRIDGE_MODULE_NAME: &IdentStr = ident_str!("bridge"); +pub const BRIDGE_CREATE_FUNCTION_NAME: &IdentStr = ident_str!("create"); + +pub const BRIDGE_SUPPORTED_ASSET: &[&str] = &["btc", "eth", "usdc", "usdt"]; + +pub fn get_bridge_obj_initial_shared_version( + object_store: &dyn ObjectStore, +) -> IotaResult> { + Ok(object_store + .get_object(&IOTA_BRIDGE_OBJECT_ID)? + .map(|obj| match obj.owner { + Owner::Shared { + initial_shared_version, + } => initial_shared_version, + _ => unreachable!("Bridge object must be shared"), + })) +} diff --git a/crates/sui-types/src/clock.rs b/crates/iota-types/src/clock.rs similarity index 77% rename from crates/sui-types/src/clock.rs rename to crates/iota-types/src/clock.rs index 4dcd68ac8d0..3da010967b8 100644 --- a/crates/sui-types/src/clock.rs +++ b/crates/iota-types/src/clock.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use move_binary_format::{binary_views::BinaryIndexedView, file_format::SignatureToken}; @@ -8,12 +9,15 @@ use move_core_types::{ }; use serde::{Deserialize, Serialize}; -use crate::{id::UID, SUI_FRAMEWORK_ADDRESS}; +use crate::{id::UID, IOTA_FRAMEWORK_ADDRESS}; pub const CLOCK_MODULE_NAME: &IdentStr = ident_str!("clock"); pub const CLOCK_STRUCT_NAME: &IdentStr = ident_str!("Clock"); -pub const RESOLVED_SUI_CLOCK: (&AccountAddress, &IdentStr, &IdentStr) = - (&SUI_FRAMEWORK_ADDRESS, CLOCK_MODULE_NAME, CLOCK_STRUCT_NAME); +pub const RESOLVED_IOTA_CLOCK: (&AccountAddress, &IdentStr, &IdentStr) = ( + &IOTA_FRAMEWORK_ADDRESS, + CLOCK_MODULE_NAME, + CLOCK_STRUCT_NAME, +); pub const CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME: &IdentStr = ident_str!("consensus_commit_prologue"); @@ -30,20 +34,20 @@ impl Clock { pub fn type_() -> StructTag { StructTag { - address: SUI_FRAMEWORK_ADDRESS, + address: IOTA_FRAMEWORK_ADDRESS, module: CLOCK_MODULE_NAME.to_owned(), name: CLOCK_STRUCT_NAME.to_owned(), type_params: vec![], } } - /// Detects a `&mut sui::clock::Clock` or `sui::clock::Clock` in the + /// Detects a `&mut iota::clock::Clock` or `iota::clock::Clock` in the /// signature. pub fn is_mutable(view: &BinaryIndexedView<'_>, s: &SignatureToken) -> bool { use SignatureToken as S; match s { S::MutableReference(inner) => Self::is_mutable(view, inner), - S::Struct(idx) => resolve_struct(view, *idx) == RESOLVED_SUI_CLOCK, + S::Struct(idx) => resolve_struct(view, *idx) == RESOLVED_IOTA_CLOCK, _ => false, } } diff --git a/crates/iota-types/src/coin.rs b/crates/iota-types/src/coin.rs new file mode 100644 index 00000000000..04d4938dfe8 --- /dev/null +++ b/crates/iota-types/src/coin.rs @@ -0,0 +1,250 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use move_core_types::{ + annotated_value::{MoveFieldLayout, MoveStructLayout, MoveTypeLayout}, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag}, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use crate::{ + balance::{Balance, Supply}, + base_types::ObjectID, + error::{ExecutionError, ExecutionErrorKind, IotaError}, + id::UID, + object::{Data, Object}, + IOTA_FRAMEWORK_ADDRESS, +}; + +pub const COIN_MODULE_NAME: &IdentStr = ident_str!("coin"); +pub const COIN_STRUCT_NAME: &IdentStr = ident_str!("Coin"); +pub const COIN_METADATA_STRUCT_NAME: &IdentStr = ident_str!("CoinMetadata"); +pub const COIN_TREASURE_CAP_NAME: &IdentStr = ident_str!("TreasuryCap"); + +pub const PAY_MODULE_NAME: &IdentStr = ident_str!("pay"); +pub const PAY_JOIN_FUNC_NAME: &IdentStr = ident_str!("join"); +pub const PAY_SPLIT_N_FUNC_NAME: &IdentStr = ident_str!("divide_and_keep"); +pub const PAY_SPLIT_VEC_FUNC_NAME: &IdentStr = ident_str!("split_vec"); + +// Rust version of the Move iota::coin::Coin type +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema, Eq, PartialEq)] +pub struct Coin { + pub id: UID, + pub balance: Balance, +} + +impl Coin { + pub fn new(id: UID, value: u64) -> Self { + Self { + id, + balance: Balance::new(value), + } + } + + pub fn type_(type_param: TypeTag) -> StructTag { + StructTag { + address: IOTA_FRAMEWORK_ADDRESS, + name: COIN_STRUCT_NAME.to_owned(), + module: COIN_MODULE_NAME.to_owned(), + type_params: vec![type_param], + } + } + + /// Is this other StructTag representing a Coin? + pub fn is_coin(other: &StructTag) -> bool { + other.address == IOTA_FRAMEWORK_ADDRESS + && other.module.as_ident_str() == COIN_MODULE_NAME + && other.name.as_ident_str() == COIN_STRUCT_NAME + } + + /// Create a coin from BCS bytes + pub fn from_bcs_bytes(content: &[u8]) -> Result { + bcs::from_bytes(content) + } + + /// If the given object is a Coin, deserialize its contents and extract the + /// balance Ok(Some(u64)). If it's not a Coin, return Ok(None). + /// The cost is 2 comparisons if not a coin, and deserialization if its a + /// Coin. + pub fn extract_balance_if_coin(object: &Object) -> Result, bcs::Error> { + match &object.data { + Data::Move(move_obj) => { + if !move_obj.is_coin() { + return Ok(None); + } + + let coin = Self::from_bcs_bytes(move_obj.contents())?; + Ok(Some(coin.value())) + } + _ => Ok(None), // package + } + } + + pub fn id(&self) -> &ObjectID { + self.id.object_id() + } + + pub fn value(&self) -> u64 { + self.balance.value() + } + + pub fn to_bcs_bytes(&self) -> Vec { + bcs::to_bytes(&self).unwrap() + } + + pub fn layout(type_param: TypeTag) -> MoveStructLayout { + MoveStructLayout { + type_: Self::type_(type_param.clone()), + fields: vec![ + MoveFieldLayout::new( + ident_str!("id").to_owned(), + MoveTypeLayout::Struct(UID::layout()), + ), + MoveFieldLayout::new( + ident_str!("balance").to_owned(), + MoveTypeLayout::Struct(Balance::layout(type_param)), + ), + ], + } + } + + /// Add balance to this coin, erroring if the new total balance exceeds the + /// maximum + pub fn add(&mut self, balance: Balance) -> Result<(), ExecutionError> { + let Some(new_value) = self.value().checked_add(balance.value()) else { + return Err(ExecutionError::from_kind( + ExecutionErrorKind::CoinBalanceOverflow, + )); + }; + self.balance = Balance::new(new_value); + Ok(()) + } + + // Split amount out of this coin to a new coin. + // Related coin objects need to be updated in temporary_store to persist the + // changes, including creating the coin object related to the newly created + // coin. + pub fn split(&mut self, amount: u64, new_coin_id: UID) -> Result { + self.balance.withdraw(amount)?; + Ok(Coin::new(new_coin_id, amount)) + } +} + +// Rust version of the Move iota::coin::TreasuryCap type +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, JsonSchema)] +pub struct TreasuryCap { + pub id: UID, + pub total_supply: Supply, +} + +impl TreasuryCap { + pub fn is_treasury_type(other: &StructTag) -> bool { + other.address == IOTA_FRAMEWORK_ADDRESS + && other.module.as_ident_str() == COIN_MODULE_NAME + && other.name.as_ident_str() == COIN_TREASURE_CAP_NAME + } + + /// Create a TreasuryCap from BCS bytes + pub fn from_bcs_bytes(content: &[u8]) -> Result { + bcs::from_bytes(content).map_err(|err| IotaError::ObjectDeserializationError { + error: format!("Unable to deserialize TreasuryCap object: {}", err), + }) + } + + pub fn type_(type_param: StructTag) -> StructTag { + StructTag { + address: IOTA_FRAMEWORK_ADDRESS, + name: COIN_TREASURE_CAP_NAME.to_owned(), + module: COIN_MODULE_NAME.to_owned(), + type_params: vec![TypeTag::Struct(Box::new(type_param))], + } + } +} + +impl TryFrom for TreasuryCap { + type Error = IotaError; + fn try_from(object: Object) -> Result { + match &object.data { + Data::Move(o) => { + if o.type_().is_treasury_cap() { + return TreasuryCap::from_bcs_bytes(o.contents()); + } + } + Data::Package(_) => {} + } + + Err(IotaError::TypeError { + error: format!("Object type is not a TreasuryCap: {:?}", object), + }) + } +} + +// Rust version of the Move iota::coin::CoinMetadata type +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema, Eq, PartialEq)] +pub struct CoinMetadata { + pub id: UID, + /// Number of decimal places the coin uses. + pub decimals: u8, + /// Name for the token + pub name: String, + /// Symbol for the token + pub symbol: String, + /// Description of the token + pub description: String, + /// URL for the token logo + pub icon_url: Option, +} + +impl CoinMetadata { + /// Is this other StructTag representing a CoinMetadata? + pub fn is_coin_metadata(other: &StructTag) -> bool { + other.address == IOTA_FRAMEWORK_ADDRESS + && other.module.as_ident_str() == COIN_MODULE_NAME + && other.name.as_ident_str() == COIN_METADATA_STRUCT_NAME + } + + /// Create a coin from BCS bytes + pub fn from_bcs_bytes(content: &[u8]) -> Result { + bcs::from_bytes(content).map_err(|err| IotaError::ObjectDeserializationError { + error: format!("Unable to deserialize CoinMetadata object: {}", err), + }) + } + + pub fn type_(type_param: StructTag) -> StructTag { + StructTag { + address: IOTA_FRAMEWORK_ADDRESS, + name: COIN_METADATA_STRUCT_NAME.to_owned(), + module: COIN_MODULE_NAME.to_owned(), + type_params: vec![TypeTag::Struct(Box::new(type_param))], + } + } +} + +impl TryFrom for CoinMetadata { + type Error = IotaError; + fn try_from(object: Object) -> Result { + TryFrom::try_from(&object) + } +} + +impl TryFrom<&Object> for CoinMetadata { + type Error = IotaError; + fn try_from(object: &Object) -> Result { + match &object.data { + Data::Move(o) => { + if o.type_().is_coin_metadata() { + return CoinMetadata::from_bcs_bytes(o.contents()); + } + } + Data::Package(_) => {} + } + + Err(IotaError::TypeError { + error: format!("Object type is not a CoinMetadata: {:?}", object), + }) + } +} diff --git a/crates/sui-types/src/collection_types.rs b/crates/iota-types/src/collection_types.rs similarity index 79% rename from crates/sui-types/src/collection_types.rs rename to crates/iota-types/src/collection_types.rs index 09179e5e0c9..c285618fe14 100644 --- a/crates/sui-types/src/collection_types.rs +++ b/crates/iota-types/src/collection_types.rs @@ -1,30 +1,31 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use serde::{Deserialize, Serialize}; use crate::{base_types::ObjectID, id::UID}; -/// Rust version of the Move sui::vec_map::VecMap type +/// Rust version of the Move iota::vec_map::VecMap type #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct VecMap { pub contents: Vec>, } -/// Rust version of the Move sui::vec_map::Entry type +/// Rust version of the Move iota::vec_map::Entry type #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct Entry { pub key: K, pub value: V, } -/// Rust version of the Move sui::vec_set::VecSet type +/// Rust version of the Move iota::vec_set::VecSet type #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct VecSet { pub contents: Vec, } -/// Rust version of the Move sui::table::Table type. +/// Rust version of the Move iota::table::Table type. #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct TableVec { pub contents: Table, @@ -41,7 +42,7 @@ impl Default for TableVec { } } -/// Rust version of the Move sui::table::Table type. +/// Rust version of the Move iota::table::Table type. #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct Table { pub id: ObjectID, @@ -57,7 +58,7 @@ impl Default for Table { } } -/// Rust version of the Move sui::linked_table::LinkedTable type. +/// Rust version of the Move iota::linked_table::LinkedTable type. #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct LinkedTable { pub id: ObjectID, @@ -77,7 +78,7 @@ impl Default for LinkedTable { } } -/// Rust version of the Move sui::linked_table::Node type. +/// Rust version of the Move iota::linked_table::Node type. #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct LinkedTableNode { pub prev: Option, @@ -85,7 +86,7 @@ pub struct LinkedTableNode { pub value: V, } -/// Rust version of the Move sui::bag::Bag type. +/// Rust version of the Move iota::bag::Bag type. #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct Bag { pub id: UID, diff --git a/crates/sui-types/src/committee.rs b/crates/iota-types/src/committee.rs similarity index 97% rename from crates/sui-types/src/committee.rs rename to crates/iota-types/src/committee.rs index 2ef99564b3b..ad7198d6b6e 100644 --- a/crates/sui-types/src/committee.rs +++ b/crates/iota-types/src/committee.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -9,14 +10,14 @@ use std::{ }; use fastcrypto::traits::KeyPair; +pub use iota_protocol_config::ProtocolVersion; use rand::{rngs::ThreadRng, seq::SliceRandom, Rng}; use serde::{Deserialize, Serialize}; -pub use sui_protocol_config::ProtocolVersion; use super::base_types::*; use crate::{ crypto::{random_committee_key_pairs_of_size, AuthorityKeyPair, AuthorityPublicKey}, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, multiaddr::Multiaddr, }; @@ -79,7 +80,7 @@ impl Committee { /// Normalize the given weights to TOTAL_VOTING_POWER and create the /// committee. Used for testing only: a production system is using the - /// voting weights of the Sui System object. + /// voting weights of the Iota System object. pub fn new_for_testing_with_normalized_voting_power( epoch: EpochId, mut voting_weights: BTreeMap, @@ -141,11 +142,11 @@ impl Committee { self.epoch } - pub fn public_key(&self, authority: &AuthorityName) -> SuiResult<&AuthorityPublicKey> { + pub fn public_key(&self, authority: &AuthorityName) -> IotaResult<&AuthorityPublicKey> { debug_assert_eq!(self.expanded_keys.len(), self.voting_rights.len()); match self.expanded_keys.get(authority) { Some(v) => Ok(v), - None => Err(SuiError::InvalidCommittee(format!( + None => Err(IotaError::InvalidCommittee(format!( "Authority #{} not found, committee size {}", authority, self.expanded_keys.len() diff --git a/crates/iota-types/src/crypto.rs b/crates/iota-types/src/crypto.rs new file mode 100644 index 00000000000..2eeac54c787 --- /dev/null +++ b/crates/iota-types/src/crypto.rs @@ -0,0 +1,1771 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use std::{ + collections::BTreeMap, + fmt::{self, Debug, Display, Formatter}, + hash::{Hash, Hasher}, + str::FromStr, +}; + +use anyhow::{anyhow, Error}; +use derive_more::{AsMut, AsRef, From}; +pub use enum_dispatch::enum_dispatch; +use eyre::eyre; +pub use fastcrypto::traits::{ + AggregateAuthenticator, Authenticator, EncodeDecodeBase64, KeyPair as KeypairTraits, Signer, + SigningKey, ToFromBytes, VerifyingKey, +}; +use fastcrypto::{ + bls12381::min_sig::{ + BLS12381AggregateSignature, BLS12381AggregateSignatureAsBytes, BLS12381KeyPair, + BLS12381PrivateKey, BLS12381PublicKey, BLS12381Signature, + }, + ed25519::{ + Ed25519KeyPair, Ed25519PrivateKey, Ed25519PublicKey, Ed25519PublicKeyAsBytes, + Ed25519Signature, Ed25519SignatureAsBytes, + }, + encoding::{Base64, Bech32, Encoding, Hex}, + error::FastCryptoError, + hash::{Blake2b256, HashFunction}, + secp256k1::{ + Secp256k1KeyPair, Secp256k1PublicKey, Secp256k1PublicKeyAsBytes, Secp256k1Signature, + Secp256k1SignatureAsBytes, + }, + secp256r1::{ + Secp256r1KeyPair, Secp256r1PublicKey, Secp256r1PublicKeyAsBytes, Secp256r1Signature, + Secp256r1SignatureAsBytes, + }, +}; +use fastcrypto_zkp::{bn254::zk_login::ZkLoginInputs, zk_login_utils::Bn254FrElement}; +use rand::{ + rngs::{OsRng, StdRng}, + SeedableRng, +}; +use roaring::RoaringBitmap; +use schemars::JsonSchema; +use serde::{ser::Serializer, Deserialize, Deserializer, Serialize}; +use serde_with::{serde_as, Bytes}; +use shared_crypto::intent::{Intent, IntentMessage, IntentScope}; +use strum::EnumString; +use tracing::{instrument, warn}; + +use crate::{ + base_types::{AuthorityName, ConciseableName, IotaAddress}, + committee::{Committee, CommitteeTrait, EpochId, StakeUnit}, + error::{IotaError, IotaResult}, + iota_serde::{IotaBitmap, Readable}, + signature::GenericSignature, +}; + +#[cfg(test)] +#[path = "unit_tests/crypto_tests.rs"] +mod crypto_tests; + +#[cfg(test)] +#[cfg(feature = "test-utils")] +#[path = "unit_tests/intent_tests.rs"] +mod intent_tests; + +// Authority Objects +pub type AuthorityKeyPair = BLS12381KeyPair; +pub type AuthorityPublicKey = BLS12381PublicKey; +pub type AuthorityPrivateKey = BLS12381PrivateKey; +pub type AuthoritySignature = BLS12381Signature; +pub type AggregateAuthoritySignature = BLS12381AggregateSignature; +pub type AggregateAuthoritySignatureAsBytes = BLS12381AggregateSignatureAsBytes; + +// TODO(joyqvq): prefix these types with Default, DefaultAccountKeyPair etc +pub type AccountKeyPair = Ed25519KeyPair; +pub type AccountPublicKey = Ed25519PublicKey; +pub type AccountPrivateKey = Ed25519PrivateKey; + +pub type NetworkKeyPair = Ed25519KeyPair; +pub type NetworkPublicKey = Ed25519PublicKey; +pub type NetworkPrivateKey = Ed25519PrivateKey; + +pub type DefaultHash = Blake2b256; + +pub const DEFAULT_EPOCH_ID: EpochId = 0; +pub const IOTA_PRIV_KEY_PREFIX: &str = "iotaprivkey"; + +/// Creates a proof of that the authority account address is owned by the +/// holder of authority protocol key, and also ensures that the authority +/// protocol public key exists. A proof of possession is an authority +/// signature committed over the intent message `intent || message || epoch` +/// (See more at [struct IntentMessage] and [struct Intent]) where the message +/// is constructed as `authority_pubkey_bytes || authority_account_address`. +pub fn generate_proof_of_possession( + keypair: &AuthorityKeyPair, + address: IotaAddress, +) -> AuthoritySignature { + let mut msg: Vec = Vec::new(); + msg.extend_from_slice(keypair.public().as_bytes()); + msg.extend_from_slice(address.as_ref()); + AuthoritySignature::new_secure( + &IntentMessage::new(Intent::iota_app(IntentScope::ProofOfPossession), msg), + &DEFAULT_EPOCH_ID, + keypair, + ) +} + +/// Verify proof of possession against the expected intent message, +/// consisting of the protocol pubkey and the authority account address. +pub fn verify_proof_of_possession( + pop: &narwhal_crypto::Signature, + protocol_pubkey: &narwhal_crypto::PublicKey, + iota_address: IotaAddress, +) -> Result<(), IotaError> { + protocol_pubkey + .validate() + .map_err(|_| IotaError::InvalidSignature { + error: "Fail to validate pubkey".to_string(), + })?; + let mut msg = protocol_pubkey.as_bytes().to_vec(); + msg.extend_from_slice(iota_address.as_ref()); + pop.verify_secure( + &IntentMessage::new(Intent::iota_app(IntentScope::ProofOfPossession), msg), + DEFAULT_EPOCH_ID, + protocol_pubkey.into(), + ) +} +/////////////////////////////////////////////// +/// Account Keys +/// +/// * The following section defines the keypairs that are used by +/// * accounts to interact with Iota. +/// * Currently we support eddsa and ecdsa on Iota. + +#[allow(clippy::large_enum_variant)] +#[derive(Debug, From, PartialEq, Eq)] +pub enum IotaKeyPair { + Ed25519(Ed25519KeyPair), + Secp256k1(Secp256k1KeyPair), + Secp256r1(Secp256r1KeyPair), +} + +impl IotaKeyPair { + pub fn public(&self) -> PublicKey { + match self { + IotaKeyPair::Ed25519(kp) => PublicKey::Ed25519(kp.public().into()), + IotaKeyPair::Secp256k1(kp) => PublicKey::Secp256k1(kp.public().into()), + IotaKeyPair::Secp256r1(kp) => PublicKey::Secp256r1(kp.public().into()), + } + } +} + +impl Signer for IotaKeyPair { + fn sign(&self, msg: &[u8]) -> Signature { + match self { + IotaKeyPair::Ed25519(kp) => kp.sign(msg), + IotaKeyPair::Secp256k1(kp) => kp.sign(msg), + IotaKeyPair::Secp256r1(kp) => kp.sign(msg), + } + } +} + +impl EncodeDecodeBase64 for IotaKeyPair { + fn encode_base64(&self) -> String { + Base64::encode(self.to_bytes()) + } + + fn decode_base64(value: &str) -> Result { + let bytes = Base64::decode(value).map_err(|e| eyre!("{}", e.to_string()))?; + Self::from_bytes(&bytes) + } +} +impl IotaKeyPair { + pub fn to_bytes(&self) -> Vec { + let mut bytes: Vec = Vec::new(); + bytes.push(self.public().flag()); + + match self { + IotaKeyPair::Ed25519(kp) => { + bytes.extend_from_slice(kp.as_bytes()); + } + IotaKeyPair::Secp256k1(kp) => { + bytes.extend_from_slice(kp.as_bytes()); + } + IotaKeyPair::Secp256r1(kp) => { + bytes.extend_from_slice(kp.as_bytes()); + } + } + bytes + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + match SignatureScheme::from_flag_byte(bytes.first().ok_or_else(|| eyre!("Invalid length"))?) + { + Ok(x) => match x { + SignatureScheme::ED25519 => Ok(IotaKeyPair::Ed25519(Ed25519KeyPair::from_bytes( + bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?, + )?)), + SignatureScheme::Secp256k1 => { + Ok(IotaKeyPair::Secp256k1(Secp256k1KeyPair::from_bytes( + bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?, + )?)) + } + SignatureScheme::Secp256r1 => { + Ok(IotaKeyPair::Secp256r1(Secp256r1KeyPair::from_bytes( + bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?, + )?)) + } + _ => Err(eyre!("Invalid flag byte")), + }, + _ => Err(eyre!("Invalid bytes")), + } + } + /// Encode a IotaKeyPair as `flag || privkey` in Bech32 starting with + /// "iotaprivkey" to a string. Note that the pubkey is not encoded. + pub fn encode(&self) -> Result { + Bech32::encode(self.to_bytes(), IOTA_PRIV_KEY_PREFIX) + } + + /// Decode a IotaKeyPair from `flag || privkey` in Bech32 starting with + /// "iotaprivkey" to IotaKeyPair. The public key is computed directly from + /// the private key bytes. + pub fn decode(value: &str) -> Result { + let bytes = Bech32::decode(value, IOTA_PRIV_KEY_PREFIX)?; + Self::from_bytes(&bytes) + } +} + +impl Serialize for IotaKeyPair { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let s = self.encode_base64(); + serializer.serialize_str(&s) + } +} + +impl<'de> Deserialize<'de> for IotaKeyPair { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de::Error; + let s = String::deserialize(deserializer)?; + IotaKeyPair::decode_base64(&s).map_err(|e| Error::custom(e.to_string())) + } +} + +#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, Serialize, Deserialize)] +pub enum PublicKey { + Ed25519(Ed25519PublicKeyAsBytes), + Secp256k1(Secp256k1PublicKeyAsBytes), + Secp256r1(Secp256r1PublicKeyAsBytes), + ZkLogin(ZkLoginPublicIdentifier), +} + +/// A wrapper struct to retrofit in [enum PublicKey] for zkLogin. +/// Useful to construct [struct MultiSigPublicKey]. +#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, Serialize, Deserialize)] +pub struct ZkLoginPublicIdentifier(#[schemars(with = "Base64")] pub Vec); + +impl ZkLoginPublicIdentifier { + /// Consists of iss_bytes_len || iss_bytes || padded_32_byte_address_seed. + pub fn new(iss: &str, address_seed: &Bn254FrElement) -> IotaResult { + let mut bytes = Vec::new(); + let iss_bytes = iss.as_bytes(); + bytes.extend([iss_bytes.len() as u8]); + bytes.extend(iss_bytes); + bytes.extend(address_seed.padded()); + + Ok(Self(bytes)) + } +} +impl AsRef<[u8]> for PublicKey { + fn as_ref(&self) -> &[u8] { + match self { + PublicKey::Ed25519(pk) => &pk.0, + PublicKey::Secp256k1(pk) => &pk.0, + PublicKey::Secp256r1(pk) => &pk.0, + PublicKey::ZkLogin(z) => &z.0, + } + } +} + +impl EncodeDecodeBase64 for PublicKey { + fn encode_base64(&self) -> String { + let mut bytes: Vec = Vec::new(); + bytes.extend_from_slice(&[self.flag()]); + bytes.extend_from_slice(self.as_ref()); + Base64::encode(&bytes[..]) + } + + fn decode_base64(value: &str) -> Result { + let bytes = Base64::decode(value).map_err(|e| eyre!("{}", e.to_string()))?; + match bytes.first() { + Some(x) => { + if x == &SignatureScheme::ED25519.flag() { + let pk: Ed25519PublicKey = Ed25519PublicKey::from_bytes( + bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?, + )?; + Ok(PublicKey::Ed25519((&pk).into())) + } else if x == &SignatureScheme::Secp256k1.flag() { + let pk = Secp256k1PublicKey::from_bytes( + bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?, + )?; + Ok(PublicKey::Secp256k1((&pk).into())) + } else if x == &SignatureScheme::Secp256r1.flag() { + let pk = Secp256r1PublicKey::from_bytes( + bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?, + )?; + Ok(PublicKey::Secp256r1((&pk).into())) + } else { + Err(eyre!("Invalid flag byte")) + } + } + _ => Err(eyre!("Invalid bytes")), + } + } +} + +impl PublicKey { + pub fn flag(&self) -> u8 { + self.scheme().flag() + } + + pub fn try_from_bytes( + curve: SignatureScheme, + key_bytes: &[u8], + ) -> Result { + match curve { + SignatureScheme::ED25519 => Ok(PublicKey::Ed25519( + (&Ed25519PublicKey::from_bytes(key_bytes)?).into(), + )), + SignatureScheme::Secp256k1 => Ok(PublicKey::Secp256k1( + (&Secp256k1PublicKey::from_bytes(key_bytes)?).into(), + )), + SignatureScheme::Secp256r1 => Ok(PublicKey::Secp256r1( + (&Secp256r1PublicKey::from_bytes(key_bytes)?).into(), + )), + _ => Err(eyre!("Unsupported curve")), + } + } + + pub fn scheme(&self) -> SignatureScheme { + match self { + PublicKey::Ed25519(_) => Ed25519IotaSignature::SCHEME, + PublicKey::Secp256k1(_) => Secp256k1IotaSignature::SCHEME, + PublicKey::Secp256r1(_) => Secp256r1IotaSignature::SCHEME, + PublicKey::ZkLogin(_) => SignatureScheme::ZkLoginAuthenticator, + } + } + + pub fn from_zklogin_inputs(inputs: &ZkLoginInputs) -> IotaResult { + Ok(PublicKey::ZkLogin(ZkLoginPublicIdentifier::new( + inputs.get_iss(), + inputs.get_address_seed(), + )?)) + } +} + +/// Defines the compressed version of the public key that we pass around +/// in Iota +#[serde_as] +#[derive( + Copy, + Clone, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + Serialize, + Deserialize, + schemars::JsonSchema, + AsRef, +)] +#[as_ref(forward)] +pub struct AuthorityPublicKeyBytes( + #[schemars(with = "Base64")] + #[serde_as(as = "Readable")] + pub [u8; AuthorityPublicKey::LENGTH], +); + +impl AuthorityPublicKeyBytes { + fn fmt_impl(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + let s = Hex::encode(self.0); + write!(f, "k#{}", s)?; + Ok(()) + } +} + +impl<'a> ConciseableName<'a> for AuthorityPublicKeyBytes { + type ConciseTypeRef = ConciseAuthorityPublicKeyBytesRef<'a>; + type ConciseType = ConciseAuthorityPublicKeyBytes; + + /// Get a ConciseAuthorityPublicKeyBytesRef. Usage: + /// + /// debug!(name = ?authority.concise()); + /// format!("{:?}", authority.concise()); + fn concise(&'a self) -> ConciseAuthorityPublicKeyBytesRef<'a> { + ConciseAuthorityPublicKeyBytesRef(self) + } + + fn concise_owned(&self) -> ConciseAuthorityPublicKeyBytes { + ConciseAuthorityPublicKeyBytes(*self) + } +} + +/// A wrapper around AuthorityPublicKeyBytes that provides a concise Debug impl. +pub struct ConciseAuthorityPublicKeyBytesRef<'a>(&'a AuthorityPublicKeyBytes); + +impl Debug for ConciseAuthorityPublicKeyBytesRef<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + let s = Hex::encode(self.0.0.get(0..4).ok_or(std::fmt::Error)?); + write!(f, "k#{}..", s) + } +} + +impl Display for ConciseAuthorityPublicKeyBytesRef<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + Debug::fmt(self, f) + } +} + +/// A wrapper around AuthorityPublicKeyBytes but owns it. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, schemars::JsonSchema)] +pub struct ConciseAuthorityPublicKeyBytes(AuthorityPublicKeyBytes); + +impl Debug for ConciseAuthorityPublicKeyBytes { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + let s = Hex::encode(self.0.0.get(0..4).ok_or(std::fmt::Error)?); + write!(f, "k#{}..", s) + } +} + +impl Display for ConciseAuthorityPublicKeyBytes { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + Debug::fmt(self, f) + } +} + +impl TryFrom for AuthorityPublicKey { + type Error = FastCryptoError; + + fn try_from(bytes: AuthorityPublicKeyBytes) -> Result { + AuthorityPublicKey::from_bytes(bytes.as_ref()) + } +} + +impl From<&AuthorityPublicKey> for AuthorityPublicKeyBytes { + fn from(pk: &AuthorityPublicKey) -> AuthorityPublicKeyBytes { + AuthorityPublicKeyBytes::from_bytes(pk.as_ref()).unwrap() + } +} + +impl Debug for AuthorityPublicKeyBytes { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + self.fmt_impl(f) + } +} + +impl Display for AuthorityPublicKeyBytes { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + self.fmt_impl(f) + } +} + +impl ToFromBytes for AuthorityPublicKeyBytes { + fn from_bytes(bytes: &[u8]) -> Result { + let bytes: [u8; AuthorityPublicKey::LENGTH] = bytes + .try_into() + .map_err(|_| fastcrypto::error::FastCryptoError::InvalidInput)?; + Ok(AuthorityPublicKeyBytes(bytes)) + } +} + +impl AuthorityPublicKeyBytes { + pub const ZERO: Self = Self::new([0u8; AuthorityPublicKey::LENGTH]); + + /// This ensures it's impossible to construct an instance with other than + /// registered lengths + pub const fn new(bytes: [u8; AuthorityPublicKey::LENGTH]) -> AuthorityPublicKeyBytes +where { + AuthorityPublicKeyBytes(bytes) + } +} + +impl FromStr for AuthorityPublicKeyBytes { + type Err = Error; + + fn from_str(s: &str) -> Result { + let value = Hex::decode(s).map_err(|e| anyhow!(e))?; + Self::from_bytes(&value[..]).map_err(|e| anyhow!(e)) + } +} + +impl Default for AuthorityPublicKeyBytes { + fn default() -> Self { + Self::ZERO + } +} + +// Add helper calls for Authority Signature +// + +pub trait IotaAuthoritySignature { + fn verify_secure( + &self, + value: &IntentMessage, + epoch_id: EpochId, + author: AuthorityPublicKeyBytes, + ) -> Result<(), IotaError> + where + T: Serialize; + + fn new_secure( + value: &IntentMessage, + epoch_id: &EpochId, + secret: &dyn Signer, + ) -> Self + where + T: Serialize; +} + +impl IotaAuthoritySignature for AuthoritySignature { + #[instrument(level = "trace", skip_all)] + fn new_secure(value: &IntentMessage, epoch: &EpochId, secret: &dyn Signer) -> Self + where + T: Serialize, + { + let mut intent_msg_bytes = + bcs::to_bytes(&value).expect("Message serialization should not fail"); + epoch.write(&mut intent_msg_bytes); + secret.sign(&intent_msg_bytes) + } + + #[instrument(level = "trace", skip_all)] + fn verify_secure( + &self, + value: &IntentMessage, + epoch: EpochId, + author: AuthorityPublicKeyBytes, + ) -> Result<(), IotaError> + where + T: Serialize, + { + let mut message = bcs::to_bytes(&value).expect("Message serialization should not fail"); + epoch.write(&mut message); + + let public_key = AuthorityPublicKey::try_from(author).map_err(|_| { + IotaError::KeyConversionError( + "Failed to serialize public key bytes to valid public key".to_string(), + ) + })?; + public_key + .verify(&message[..], self) + .map_err(|e| IotaError::InvalidSignature { + error: format!( + "Fail to verify auth sig {} epoch: {} author: {}", + e, + epoch, + author.concise() + ), + }) + } +} + +// TODO: get_key_pair() and get_key_pair_from_bytes() should return KeyPair +// only. TODO: rename to random_key_pair +pub fn get_key_pair() -> (IotaAddress, KP) +where + ::PubKey: IotaPublicKey, +{ + get_key_pair_from_rng(&mut OsRng) +} + +/// Generate a random committee key pairs with a given committee size +pub fn random_committee_key_pairs_of_size(size: usize) -> Vec { + let mut rng = StdRng::from_seed([0; 32]); + (0..size) + .map(|_| { + // TODO: We are generating the keys 4 times to match exactly as how we generate + // keys in ConfigBuilder::build (iota-config/src/network_config_builder). This + // is because we are using these key generation functions as + // fixtures and we call them independently in different paths and + // exact the results to be the same. We should eliminate them. + let key_pair = get_key_pair_from_rng::(&mut rng); + get_key_pair_from_rng::(&mut rng); + get_key_pair_from_rng::(&mut rng); + get_key_pair_from_rng::(&mut rng); + key_pair.1 + }) + .collect() +} + +pub fn deterministic_random_account_key() -> (IotaAddress, AccountKeyPair) { + let mut rng = StdRng::from_seed([0; 32]); + get_key_pair_from_rng(&mut rng) +} + +pub fn get_account_key_pair() -> (IotaAddress, AccountKeyPair) { + get_key_pair() +} + +pub fn get_authority_key_pair() -> (IotaAddress, AuthorityKeyPair) { + get_key_pair() +} + +/// Generate a keypair from the specified RNG (useful for testing with seedable +/// rngs). +pub fn get_key_pair_from_rng(csprng: &mut R) -> (IotaAddress, KP) +where + R: rand::CryptoRng + rand::RngCore, + ::PubKey: IotaPublicKey, +{ + let kp = KP::generate(&mut StdRng::from_rng(csprng).unwrap()); + (kp.public().into(), kp) +} + +// TODO: C-GETTER +pub fn get_key_pair_from_bytes(bytes: &[u8]) -> IotaResult<(IotaAddress, KP)> +where + ::PubKey: IotaPublicKey, +{ + let priv_length = ::PrivKey::LENGTH; + let pub_key_length = ::PubKey::LENGTH; + if bytes.len() != priv_length + pub_key_length { + return Err(IotaError::KeyConversionError(format!( + "Invalid input byte length, expected {}: {}", + priv_length, + bytes.len() + ))); + } + let sk = ::PrivKey::from_bytes( + bytes + .get(..priv_length) + .ok_or(IotaError::InvalidPrivateKey)?, + ) + .map_err(|_| IotaError::InvalidPrivateKey)?; + let kp: KP = sk.into(); + Ok((kp.public().into(), kp)) +} + +// Account Signatures +// + +// Enums for signature scheme signatures +#[enum_dispatch] +#[derive(Clone, JsonSchema, Debug, PartialEq, Eq, Hash)] +pub enum Signature { + Ed25519IotaSignature, + Secp256k1IotaSignature, + Secp256r1IotaSignature, +} + +impl Serialize for Signature { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let bytes = self.as_ref(); + + if serializer.is_human_readable() { + let s = Base64::encode(bytes); + serializer.serialize_str(&s) + } else { + serializer.serialize_bytes(bytes) + } + } +} + +impl<'de> Deserialize<'de> for Signature { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de::Error; + + let bytes = if deserializer.is_human_readable() { + let s = String::deserialize(deserializer)?; + Base64::decode(&s).map_err(|e| Error::custom(e.to_string()))? + } else { + let data: Vec = Vec::deserialize(deserializer)?; + data + }; + + Self::from_bytes(&bytes).map_err(|e| Error::custom(e.to_string())) + } +} + +impl Signature { + /// The messaged passed in is already hashed form. + pub fn new_hashed(hashed_msg: &[u8], secret: &dyn Signer) -> Self { + Signer::sign(secret, hashed_msg) + } + + pub fn new_secure(value: &IntentMessage, secret: &dyn Signer) -> Self + where + T: Serialize, + { + let mut hasher = DefaultHash::default(); + hasher.update(&bcs::to_bytes(&value).expect("Message serialization should not fail")); + Signer::sign(secret, &hasher.finalize().digest) + } +} + +impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + match self { + Signature::Ed25519IotaSignature(sig) => sig.as_ref(), + Signature::Secp256k1IotaSignature(sig) => sig.as_ref(), + Signature::Secp256r1IotaSignature(sig) => sig.as_ref(), + } + } +} +impl AsMut<[u8]> for Signature { + fn as_mut(&mut self) -> &mut [u8] { + match self { + Signature::Ed25519IotaSignature(sig) => sig.as_mut(), + Signature::Secp256k1IotaSignature(sig) => sig.as_mut(), + Signature::Secp256r1IotaSignature(sig) => sig.as_mut(), + } + } +} + +impl ToFromBytes for Signature { + fn from_bytes(bytes: &[u8]) -> Result { + match bytes.first() { + Some(x) => { + if x == &Ed25519IotaSignature::SCHEME.flag() { + Ok(::from_bytes(bytes)?.into()) + } else if x == &Secp256k1IotaSignature::SCHEME.flag() { + Ok(::from_bytes(bytes)?.into()) + } else if x == &Secp256r1IotaSignature::SCHEME.flag() { + Ok(::from_bytes(bytes)?.into()) + } else { + Err(FastCryptoError::InvalidInput) + } + } + _ => Err(FastCryptoError::InvalidInput), + } + } +} + +// BLS Port +// + +impl IotaPublicKey for BLS12381PublicKey { + const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::BLS12381; +} + +// Ed25519 Iota Signature port +// + +#[serde_as] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)] +#[as_ref(forward)] +#[as_mut(forward)] +pub struct Ed25519IotaSignature( + #[schemars(with = "Base64")] + #[serde_as(as = "Readable")] + [u8; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1], +); + +// Implementation useful for simplify testing when mock signature is needed +impl Default for Ed25519IotaSignature { + fn default() -> Self { + Self([0; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1]) + } +} + +impl IotaSignatureInner for Ed25519IotaSignature { + type Sig = Ed25519Signature; + type PubKey = Ed25519PublicKey; + type KeyPair = Ed25519KeyPair; + const LENGTH: usize = Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1; +} + +impl IotaPublicKey for Ed25519PublicKey { + const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::ED25519; +} + +impl ToFromBytes for Ed25519IotaSignature { + fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != Self::LENGTH { + return Err(FastCryptoError::InputLengthWrong(Self::LENGTH)); + } + let mut sig_bytes = [0; Self::LENGTH]; + sig_bytes.copy_from_slice(bytes); + Ok(Self(sig_bytes)) + } +} + +impl Signer for Ed25519KeyPair { + fn sign(&self, msg: &[u8]) -> Signature { + Ed25519IotaSignature::new(self, msg).into() + } +} + +// Secp256k1 Iota Signature port +// +#[serde_as] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)] +#[as_ref(forward)] +#[as_mut(forward)] +pub struct Secp256k1IotaSignature( + #[schemars(with = "Base64")] + #[serde_as(as = "Readable")] + [u8; Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1], +); + +impl IotaSignatureInner for Secp256k1IotaSignature { + type Sig = Secp256k1Signature; + type PubKey = Secp256k1PublicKey; + type KeyPair = Secp256k1KeyPair; + const LENGTH: usize = Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1; +} + +impl IotaPublicKey for Secp256k1PublicKey { + const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256k1; +} + +impl ToFromBytes for Secp256k1IotaSignature { + fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != Self::LENGTH { + return Err(FastCryptoError::InputLengthWrong(Self::LENGTH)); + } + let mut sig_bytes = [0; Self::LENGTH]; + sig_bytes.copy_from_slice(bytes); + Ok(Self(sig_bytes)) + } +} + +impl Signer for Secp256k1KeyPair { + fn sign(&self, msg: &[u8]) -> Signature { + Secp256k1IotaSignature::new(self, msg).into() + } +} + +// Secp256r1 Iota Signature port +// +#[serde_as] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)] +#[as_ref(forward)] +#[as_mut(forward)] +pub struct Secp256r1IotaSignature( + #[schemars(with = "Base64")] + #[serde_as(as = "Readable")] + [u8; Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1], +); + +impl IotaSignatureInner for Secp256r1IotaSignature { + type Sig = Secp256r1Signature; + type PubKey = Secp256r1PublicKey; + type KeyPair = Secp256r1KeyPair; + const LENGTH: usize = Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1; +} + +impl IotaPublicKey for Secp256r1PublicKey { + const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256r1; +} + +impl ToFromBytes for Secp256r1IotaSignature { + fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != Self::LENGTH { + return Err(FastCryptoError::InputLengthWrong(Self::LENGTH)); + } + let mut sig_bytes = [0; Self::LENGTH]; + sig_bytes.copy_from_slice(bytes); + Ok(Self(sig_bytes)) + } +} + +impl Signer for Secp256r1KeyPair { + fn sign(&self, msg: &[u8]) -> Signature { + Secp256r1IotaSignature::new(self, msg).into() + } +} + +// This struct exists due to the limitations of the `enum_dispatch` library. +// +pub trait IotaSignatureInner: Sized + ToFromBytes + PartialEq + Eq + Hash { + type Sig: Authenticator; + type PubKey: VerifyingKey + IotaPublicKey; + type KeyPair: KeypairTraits; + + const LENGTH: usize = Self::Sig::LENGTH + Self::PubKey::LENGTH + 1; + const SCHEME: SignatureScheme = Self::PubKey::SIGNATURE_SCHEME; + + /// Returns the deserialized signature and deserialized pubkey. + fn get_verification_inputs(&self) -> IotaResult<(Self::Sig, Self::PubKey)> { + let pk = Self::PubKey::from_bytes(self.public_key_bytes()) + .map_err(|_| IotaError::KeyConversionError("Invalid public key".to_string()))?; + + // deserialize the signature + let signature = Self::Sig::from_bytes(self.signature_bytes()).map_err(|_| { + IotaError::InvalidSignature { + error: "Fail to get pubkey and sig".to_string(), + } + })?; + + Ok((signature, pk)) + } + + fn new(kp: &Self::KeyPair, message: &[u8]) -> Self { + let sig = Signer::sign(kp, message); + + let mut signature_bytes: Vec = Vec::new(); + signature_bytes + .extend_from_slice(&[::SIGNATURE_SCHEME.flag()]); + signature_bytes.extend_from_slice(sig.as_ref()); + signature_bytes.extend_from_slice(kp.public().as_ref()); + Self::from_bytes(&signature_bytes[..]) + .expect("Serialized signature did not have expected size") + } +} + +pub trait IotaPublicKey: VerifyingKey { + const SIGNATURE_SCHEME: SignatureScheme; +} + +#[enum_dispatch(Signature)] +pub trait IotaSignature: Sized + ToFromBytes { + fn signature_bytes(&self) -> &[u8]; + fn public_key_bytes(&self) -> &[u8]; + fn scheme(&self) -> SignatureScheme; + + fn verify_secure( + &self, + value: &IntentMessage, + author: IotaAddress, + scheme: SignatureScheme, + ) -> IotaResult<()> + where + T: Serialize; +} + +impl IotaSignature for S { + fn signature_bytes(&self) -> &[u8] { + // Access array slice is safe because the array bytes is initialized as + // flag || signature || pubkey with its defined length. + &self.as_ref()[1..1 + S::Sig::LENGTH] + } + + fn public_key_bytes(&self) -> &[u8] { + // Access array slice is safe because the array bytes is initialized as + // flag || signature || pubkey with its defined length. + &self.as_ref()[S::Sig::LENGTH + 1..] + } + + fn scheme(&self) -> SignatureScheme { + S::PubKey::SIGNATURE_SCHEME + } + + fn verify_secure( + &self, + value: &IntentMessage, + author: IotaAddress, + scheme: SignatureScheme, + ) -> Result<(), IotaError> + where + T: Serialize, + { + let mut hasher = DefaultHash::default(); + hasher.update(&bcs::to_bytes(&value).expect("Message serialization should not fail")); + let digest = hasher.finalize().digest; + + let (sig, pk) = &self.get_verification_inputs()?; + match scheme { + SignatureScheme::ZkLoginAuthenticator => {} // Pass this check because zk login does + // not derive address from pubkey. + _ => { + let address = IotaAddress::from(pk); + if author != address { + return Err(IotaError::IncorrectSigner { + error: format!( + "Incorrect signer, expected {:?}, got {:?}", + author, address + ), + }); + } + } + } + + pk.verify(&digest, sig) + .map_err(|e| IotaError::InvalidSignature { + error: format!("Fail to verify user sig {}", e), + }) + } +} + +/// AuthoritySignInfoTrait is a trait used specifically for a few structs in +/// messages.rs to template on whether the struct is signed by an authority. We +/// want to limit how those structs can be instantiated on, hence the sealed +/// trait. TODO: We could also add the aggregated signature as another impl of +/// the trait. This will make CertifiedTransaction also an instance of the +/// same struct. +pub trait AuthoritySignInfoTrait: private::SealedAuthoritySignInfoTrait { + fn verify_secure( + &self, + data: &T, + intent: Intent, + committee: &Committee, + ) -> IotaResult; + + fn add_to_verification_obligation<'a>( + &self, + committee: &'a Committee, + obligation: &mut VerificationObligation<'a>, + message_index: usize, + ) -> IotaResult<()>; +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct EmptySignInfo {} +impl AuthoritySignInfoTrait for EmptySignInfo { + fn verify_secure( + &self, + _data: &T, + _intent: Intent, + _committee: &Committee, + ) -> IotaResult { + Ok(()) + } + + fn add_to_verification_obligation<'a>( + &self, + _committee: &'a Committee, + _obligation: &mut VerificationObligation<'a>, + _message_index: usize, + ) -> IotaResult<()> { + Ok(()) + } +} + +#[derive(Clone, Debug, Eq, Serialize, Deserialize)] +pub struct AuthoritySignInfo { + pub epoch: EpochId, + pub authority: AuthorityName, + pub signature: AuthoritySignature, +} + +impl AuthoritySignInfoTrait for AuthoritySignInfo { + fn verify_secure( + &self, + data: &T, + intent: Intent, + committee: &Committee, + ) -> IotaResult<()> { + let mut obligation = VerificationObligation::default(); + let idx = obligation.add_message(data, self.epoch, intent); + self.add_to_verification_obligation(committee, &mut obligation, idx)?; + obligation.verify_all()?; + Ok(()) + } + + fn add_to_verification_obligation<'a>( + &self, + committee: &'a Committee, + obligation: &mut VerificationObligation<'a>, + message_index: usize, + ) -> IotaResult<()> { + fp_ensure!( + self.epoch == committee.epoch(), + IotaError::WrongEpoch { + expected_epoch: committee.epoch(), + actual_epoch: self.epoch, + } + ); + let weight = committee.weight(&self.authority); + fp_ensure!( + weight > 0, + IotaError::UnknownSigner { + signer: Some(self.authority.concise().to_string()), + index: None, + committee: Box::new(committee.clone()) + } + ); + + obligation + .public_keys + .get_mut(message_index) + .ok_or(IotaError::InvalidAddress)? + .push(committee.public_key(&self.authority)?); + obligation + .signatures + .get_mut(message_index) + .ok_or(IotaError::InvalidAddress)? + .add_signature(self.signature.clone()) + .map_err(|_| IotaError::InvalidSignature { + error: "Fail to aggregator auth sig".to_string(), + })?; + Ok(()) + } +} + +impl AuthoritySignInfo { + pub fn new( + epoch: EpochId, + value: &T, + intent: Intent, + name: AuthorityName, + secret: &dyn Signer, + ) -> Self + where + T: Serialize, + { + Self { + epoch, + authority: name, + signature: AuthoritySignature::new_secure( + &IntentMessage::new(intent, value), + &epoch, + secret, + ), + } + } +} + +impl Hash for AuthoritySignInfo { + fn hash(&self, state: &mut H) { + self.epoch.hash(state); + self.authority.hash(state); + } +} + +impl Display for AuthoritySignInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "AuthoritySignInfo {{ epoch: {:?}, authority: {} }}", + self.epoch, self.authority, + ) + } +} + +impl PartialEq for AuthoritySignInfo { + fn eq(&self, other: &Self) -> bool { + // We do not compare the signature, because there can be multiple + // valid signatures for the same epoch and authority. + self.epoch == other.epoch && self.authority == other.authority + } +} + +/// Represents at least a quorum (could be more) of authority signatures. +/// STRONG_THRESHOLD indicates whether to use the quorum threshold for quorum +/// check. When STRONG_THRESHOLD is true, the quorum is valid when the total +/// stake is at least the quorum threshold (2f+1) of the committee; when +/// STRONG_THRESHOLD is false, the quorum is valid when the total stake is at +/// least the validity threshold (f+1) of the committee. +#[serde_as] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct AuthorityQuorumSignInfo { + pub epoch: EpochId, + #[schemars(with = "Base64")] + pub signature: AggregateAuthoritySignature, + #[schemars(with = "Base64")] + #[serde_as(as = "IotaBitmap")] + pub signers_map: RoaringBitmap, +} + +pub type AuthorityStrongQuorumSignInfo = AuthorityQuorumSignInfo; + +// Variant of [AuthorityStrongQuorumSignInfo] but with a serialized signature, +// to be used in external APIs. +#[serde_as] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct IotaAuthorityStrongQuorumSignInfo { + pub epoch: EpochId, + pub signature: AggregateAuthoritySignatureAsBytes, + #[schemars(with = "Base64")] + #[serde_as(as = "IotaBitmap")] + pub signers_map: RoaringBitmap, +} + +impl From<&AuthorityStrongQuorumSignInfo> for IotaAuthorityStrongQuorumSignInfo { + fn from(info: &AuthorityStrongQuorumSignInfo) -> Self { + Self { + epoch: info.epoch, + signature: (&info.signature).into(), + signers_map: info.signers_map.clone(), + } + } +} + +impl TryFrom<&IotaAuthorityStrongQuorumSignInfo> for AuthorityStrongQuorumSignInfo { + type Error = FastCryptoError; + + fn try_from(info: &IotaAuthorityStrongQuorumSignInfo) -> Result { + Ok(Self { + epoch: info.epoch, + signature: (&info.signature).try_into()?, + signers_map: info.signers_map.clone(), + }) + } +} + +// Note: if you meet an error due to this line it may be because you need an Eq +// implementation for `CertifiedTransaction`, or one of the structs that include +// it, i.e. `ConfirmationTransaction`, `TransactionInfoResponse` or +// `ObjectInfoResponse`. +// +// Please note that any such implementation must be agnostic to the exact set of +// signatures in the certificate, as clients are allowed to equivocate on the +// exact nature of valid certificates they send to the system. This assertion is +// a simple tool to make sure certificates are accounted for correctly - should +// you remove it, you're on your own to maintain the invariant that valid +// certificates with distinct signatures are equivalent, but yet-unchecked +// certificates that differ on signers aren't. +// +// see also https://github.com/iotaledger/iota/issues/266 +static_assertions::assert_not_impl_any!(AuthorityStrongQuorumSignInfo: Hash, Eq, PartialEq); + +impl AuthoritySignInfoTrait + for AuthorityQuorumSignInfo +{ + fn verify_secure( + &self, + data: &T, + intent: Intent, + committee: &Committee, + ) -> IotaResult { + let mut obligation = VerificationObligation::default(); + let idx = obligation.add_message(data, self.epoch, intent); + self.add_to_verification_obligation(committee, &mut obligation, idx)?; + obligation.verify_all()?; + Ok(()) + } + + fn add_to_verification_obligation<'a>( + &self, + committee: &'a Committee, + obligation: &mut VerificationObligation<'a>, + message_index: usize, + ) -> IotaResult<()> { + // Check epoch + fp_ensure!( + self.epoch == committee.epoch(), + IotaError::WrongEpoch { + expected_epoch: committee.epoch(), + actual_epoch: self.epoch, + } + ); + + let mut weight = 0; + + // Create obligations for the committee signatures + obligation + .signatures + .get_mut(message_index) + .ok_or(IotaError::InvalidAuthenticator)? + .add_aggregate(self.signature.clone()) + .map_err(|_| IotaError::InvalidSignature { + error: "Signature Aggregation failed".to_string(), + })?; + + let selected_public_keys = obligation + .public_keys + .get_mut(message_index) + .ok_or(IotaError::InvalidAuthenticator)?; + + for authority_index in self.signers_map.iter() { + let authority = committee + .authority_by_index(authority_index) + .ok_or_else(|| IotaError::UnknownSigner { + signer: None, + index: Some(authority_index), + committee: Box::new(committee.clone()), + })?; + + // Update weight. + let voting_rights = committee.weight(authority); + fp_ensure!( + voting_rights > 0, + IotaError::UnknownSigner { + signer: Some(authority.concise().to_string()), + index: Some(authority_index), + committee: Box::new(committee.clone()), + } + ); + weight += voting_rights; + + selected_public_keys.push(committee.public_key(authority)?); + } + + fp_ensure!( + weight >= Self::quorum_threshold(committee), + IotaError::CertificateRequiresQuorum + ); + + Ok(()) + } +} + +impl AuthorityQuorumSignInfo { + pub fn new_from_auth_sign_infos( + auth_sign_infos: Vec, + committee: &Committee, + ) -> IotaResult { + fp_ensure!( + auth_sign_infos.iter().all(|a| a.epoch == committee.epoch), + IotaError::InvalidSignature { + error: "All signatures must be from the same epoch as the committee".to_string() + } + ); + let total_stake: StakeUnit = auth_sign_infos + .iter() + .map(|a| committee.weight(&a.authority)) + .sum(); + fp_ensure!( + total_stake >= Self::quorum_threshold(committee), + IotaError::InvalidSignature { + error: "Signatures don't have enough stake to form a quorum".to_string() + } + ); + + let signatures: BTreeMap<_, _> = auth_sign_infos + .into_iter() + .map(|a| (a.authority, a.signature)) + .collect(); + let mut map = RoaringBitmap::new(); + for pk in signatures.keys() { + map.insert( + committee + .authority_index(pk) + .ok_or_else(|| IotaError::UnknownSigner { + signer: Some(pk.concise().to_string()), + index: None, + committee: Box::new(committee.clone()), + })?, + ); + } + let sigs: Vec = signatures.into_values().collect(); + + Ok(AuthorityQuorumSignInfo { + epoch: committee.epoch, + signature: AggregateAuthoritySignature::aggregate(&sigs).map_err(|e| { + IotaError::InvalidSignature { + error: e.to_string(), + } + })?, + signers_map: map, + }) + } + + pub fn authorities<'a>( + &'a self, + committee: &'a Committee, + ) -> impl Iterator> { + self.signers_map.iter().map(|i| { + committee + .authority_by_index(i) + .ok_or(IotaError::InvalidAuthenticator) + }) + } + + pub fn quorum_threshold(committee: &Committee) -> StakeUnit { + committee.threshold::() + } + + pub fn len(&self) -> u64 { + self.signers_map.len() + } + + pub fn is_empty(&self) -> bool { + self.signers_map.is_empty() + } +} + +impl Display for AuthorityQuorumSignInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + writeln!( + f, + "{} {{ epoch: {:?}, signers_map: {:?} }}", + if S { + "AuthorityStrongQuorumSignInfo" + } else { + "AuthorityWeakQuorumSignInfo" + }, + self.epoch, + self.signers_map, + )?; + Ok(()) + } +} + +mod private { + pub trait SealedAuthoritySignInfoTrait {} + impl SealedAuthoritySignInfoTrait for super::EmptySignInfo {} + impl SealedAuthoritySignInfoTrait for super::AuthoritySignInfo {} + impl SealedAuthoritySignInfoTrait for super::AuthorityQuorumSignInfo {} +} + +/// Something that we know how to hash and sign. +pub trait Signable { + fn write(&self, writer: &mut W); +} + +pub trait SignableBytes +where + Self: Sized, +{ + fn from_signable_bytes(bytes: &[u8]) -> Result; +} + +/// Activate the blanket implementation of `Signable` based on serde and BCS. +/// * We use `serde_name` to extract a seed from the name of structs and enums. +/// * We use `BCS` to generate canonical bytes suitable for hashing and signing. +/// +/// # Safety +/// We protect the access to this marker trait through a "sealed trait" pattern: +/// impls must be add added here (nowehre else) which lets us note those impls +/// MUST be on types that comply with the `serde_name` machinery +/// for the below implementations not to panic. One way to check they work is to +/// write a unit test for serialization to / deserialization from signable +/// bytes. +mod bcs_signable { + + pub trait BcsSignable: serde::Serialize + serde::de::DeserializeOwned {} + impl BcsSignable for crate::committee::Committee {} + impl BcsSignable for crate::messages_checkpoint::CheckpointSummary {} + impl BcsSignable for crate::messages_checkpoint::CheckpointContents {} + + impl BcsSignable for crate::effects::TransactionEffects {} + impl BcsSignable for crate::effects::TransactionEvents {} + impl BcsSignable for crate::transaction::TransactionData {} + impl BcsSignable for crate::transaction::SenderSignedData {} + impl BcsSignable for crate::object::ObjectInner {} + + impl BcsSignable for crate::accumulator::Accumulator {} + + impl BcsSignable for super::bcs_signable_test::Foo {} + #[cfg(test)] + impl BcsSignable for super::bcs_signable_test::Bar {} +} + +impl Signable for T +where + T: bcs_signable::BcsSignable, + W: std::io::Write, +{ + fn write(&self, writer: &mut W) { + let name = serde_name::trace_name::().expect("Self must be a struct or an enum"); + // Note: This assumes that names never contain the separator `::`. + write!(writer, "{}::", name).expect("Hasher should not fail"); + bcs::serialize_into(writer, &self).expect("Message serialization should not fail"); + } +} + +impl Signable for EpochId +where + W: std::io::Write, +{ + fn write(&self, writer: &mut W) { + bcs::serialize_into(writer, &self).expect("Message serialization should not fail"); + } +} + +impl SignableBytes for T +where + T: bcs_signable::BcsSignable, +{ + fn from_signable_bytes(bytes: &[u8]) -> Result { + // Remove name tag before deserialization using BCS + let name = serde_name::trace_name::().expect("Self should be a struct or an enum"); + let name_byte_len = format!("{}::", name).bytes().len(); + Ok(bcs::from_bytes(bytes.get(name_byte_len..).ok_or_else( + || anyhow!("Failed to deserialize to {name}."), + )?)?) + } +} + +fn hash, H: HashFunction, const DIGEST_SIZE: usize>( + signable: &S, +) -> [u8; DIGEST_SIZE] { + let mut digest = H::default(); + signable.write(&mut digest); + let hash = digest.finalize(); + hash.into() +} + +pub fn default_hash>(signable: &S) -> [u8; 32] { + hash::(signable) +} + +#[derive(Default)] +pub struct VerificationObligation<'a> { + pub messages: Vec>, + pub signatures: Vec, + pub public_keys: Vec>, +} + +impl<'a> VerificationObligation<'a> { + pub fn new() -> VerificationObligation<'a> { + VerificationObligation::default() + } + + /// Add a new message to the list of messages to be verified. + /// Returns the index of the message. + pub fn add_message(&mut self, message_value: &T, epoch: EpochId, intent: Intent) -> usize + where + T: Serialize, + { + let intent_msg = IntentMessage::new(intent, message_value); + let mut intent_msg_bytes = + bcs::to_bytes(&intent_msg).expect("Message serialization should not fail"); + epoch.write(&mut intent_msg_bytes); + self.signatures.push(AggregateAuthoritySignature::default()); + self.public_keys.push(Vec::new()); + self.messages.push(intent_msg_bytes); + self.messages.len() - 1 + } + + // Attempts to add signature and public key to the obligation. If this fails, + // ensure to call `verify` manually. + pub fn add_signature_and_public_key( + &mut self, + signature: &AuthoritySignature, + public_key: &'a AuthorityPublicKey, + idx: usize, + ) -> IotaResult<()> { + self.public_keys + .get_mut(idx) + .ok_or(IotaError::InvalidAuthenticator)? + .push(public_key); + self.signatures + .get_mut(idx) + .ok_or(IotaError::InvalidAuthenticator)? + .add_signature(signature.clone()) + .map_err(|_| IotaError::InvalidSignature { + error: "Failed to add signature to obligation".to_string(), + })?; + Ok(()) + } + + pub fn verify_all(self) -> IotaResult<()> { + let mut pks = Vec::with_capacity(self.public_keys.len()); + for pk in self.public_keys.clone() { + pks.push(pk.into_iter()); + } + AggregateAuthoritySignature::batch_verify( + &self.signatures.iter().collect::>()[..], + pks, + &self.messages.iter().map(|x| &x[..]).collect::>()[..], + ) + .map_err(|e| { + let message = format!( + "pks: {:?}, messages: {:?}, sigs: {:?}", + &self.public_keys, + self.messages + .iter() + .map(Base64::encode) + .collect::>(), + &self + .signatures + .iter() + .map(|s| Base64::encode(s.as_ref())) + .collect::>() + ); + + let chunk_size = 2048; + + // This error message may be very long, so we print out the error in chunks of + // to avoid hitting a max log line length on the system. + for (i, chunk) in message + .as_bytes() + .chunks(chunk_size) + .map(std::str::from_utf8) + .enumerate() + { + warn!( + "Failed to batch verify aggregated auth sig: {} (chunk {}): {}", + e, + i, + chunk.unwrap() + ); + } + + IotaError::InvalidSignature { + error: format!("Failed to batch verify aggregated auth sig: {}", e), + } + })?; + Ok(()) + } +} + +pub mod bcs_signable_test { + use serde::{Deserialize, Serialize}; + + #[derive(Clone, Serialize, Deserialize)] + pub struct Foo(pub String); + + #[cfg(test)] + #[derive(Serialize, Deserialize)] + pub struct Bar(pub String); + + #[cfg(test)] + use super::VerificationObligation; + + #[cfg(test)] + pub fn get_obligation_input(value: &T) -> (VerificationObligation<'_>, usize) + where + T: super::bcs_signable::BcsSignable, + { + use shared_crypto::intent::{Intent, IntentScope}; + + let mut obligation = VerificationObligation::default(); + // Add the obligation of the authority signature verifications. + let idx = obligation.add_message( + value, + 0, + Intent::iota_app(IntentScope::SenderSignedTransaction), + ); + (obligation, idx) + } +} + +#[derive( + Clone, Copy, Deserialize, Serialize, JsonSchema, Debug, EnumString, strum_macros::Display, +)] +#[strum(serialize_all = "lowercase")] +pub enum SignatureScheme { + ED25519, + Secp256k1, + Secp256r1, + BLS12381, // This is currently not supported for user Iota Address. + MultiSig, + ZkLoginAuthenticator, +} + +impl SignatureScheme { + pub fn flag(&self) -> u8 { + match self { + SignatureScheme::ED25519 => 0x00, + SignatureScheme::Secp256k1 => 0x01, + SignatureScheme::Secp256r1 => 0x02, + SignatureScheme::MultiSig => 0x03, + SignatureScheme::BLS12381 => 0x04, // This is currently not supported for user Iota + // Address. + SignatureScheme::ZkLoginAuthenticator => 0x05, + } + } + + /// Takes as input an hasher and updates it with a flag byte if the input + /// scheme is not ED25519; it does nothing otherwise. + pub fn update_hasher_with_flag(&self, hasher: &mut DefaultHash) { + match self { + SignatureScheme::ED25519 => (), + _ => hasher.update([self.flag()]), + }; + } + + pub fn from_flag(flag: &str) -> Result { + let byte_int = flag + .parse::() + .map_err(|_| IotaError::KeyConversionError("Invalid key scheme".to_string()))?; + Self::from_flag_byte(&byte_int) + } + + pub fn from_flag_byte(byte_int: &u8) -> Result { + match byte_int { + 0x00 => Ok(SignatureScheme::ED25519), + 0x01 => Ok(SignatureScheme::Secp256k1), + 0x02 => Ok(SignatureScheme::Secp256r1), + 0x03 => Ok(SignatureScheme::MultiSig), + 0x04 => Ok(SignatureScheme::BLS12381), + 0x05 => Ok(SignatureScheme::ZkLoginAuthenticator), + _ => Err(IotaError::KeyConversionError( + "Invalid key scheme".to_string(), + )), + } + } +} +/// Unlike [enum Signature], [enum CompressedSignature] does not contain public +/// key. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] +pub enum CompressedSignature { + Ed25519(Ed25519SignatureAsBytes), + Secp256k1(Secp256k1SignatureAsBytes), + Secp256r1(Secp256r1SignatureAsBytes), + ZkLogin(ZkLoginAuthenticatorAsBytes), +} +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] +pub struct ZkLoginAuthenticatorAsBytes(#[schemars(with = "Base64")] pub Vec); + +impl AsRef<[u8]> for CompressedSignature { + fn as_ref(&self) -> &[u8] { + match self { + CompressedSignature::Ed25519(sig) => &sig.0, + CompressedSignature::Secp256k1(sig) => &sig.0, + CompressedSignature::Secp256r1(sig) => &sig.0, + CompressedSignature::ZkLogin(sig) => &sig.0, + } + } +} + +impl FromStr for Signature { + type Err = eyre::Report; + fn from_str(s: &str) -> Result { + Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string())) + } +} + +impl FromStr for PublicKey { + type Err = eyre::Report; + fn from_str(s: &str) -> Result { + Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string())) + } +} + +impl FromStr for GenericSignature { + type Err = eyre::Report; + fn from_str(s: &str) -> Result { + Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string())) + } +} + +// Types for randomness generation +// +pub type RandomnessSignature = fastcrypto_tbls::types::Signature; +pub type RandomnessPartialSignature = fastcrypto_tbls::tbls::PartialSignature; +pub type RandomnessPrivateKey = + fastcrypto_tbls::ecies::PrivateKey; + +/// Round number of generated randomness. +#[derive(Clone, Copy, Hash, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct RandomnessRound(pub u64); + +impl Display for RandomnessRound { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl std::ops::Add for RandomnessRound { + type Output = Self; + fn add(self, other: Self) -> Self { + Self(self.0 + other.0) + } +} + +impl std::ops::Add for RandomnessRound { + type Output = Self; + fn add(self, other: u64) -> Self { + Self(self.0 + other) + } +} + +impl RandomnessRound { + pub fn new(round: u64) -> Self { + Self(round) + } + + pub fn checked_add(self, rhs: u64) -> Option { + self.0.checked_add(rhs).map(Self) + } + + pub fn signature_message(&self) -> Vec { + "random_beacon round " + .as_bytes() + .iter() + .cloned() + .chain(bcs::to_bytes(&self.0).expect("serialization should not fail")) + .collect() + } +} diff --git a/crates/sui-types/src/deny_list.rs b/crates/iota-types/src/deny_list.rs similarity index 93% rename from crates/sui-types/src/deny_list.rs rename to crates/iota-types/src/deny_list.rs index d5eaad0dc8a..dd545fce7e6 100644 --- a/crates/sui-types/src/deny_list.rs +++ b/crates/iota-types/src/deny_list.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeSet; @@ -8,14 +9,14 @@ use serde::{Deserialize, Serialize}; use tracing::{debug, error}; use crate::{ - base_types::{SequenceNumber, SuiAddress}, + base_types::{IotaAddress, SequenceNumber}, collection_types::{Bag, Table, VecSet}, dynamic_field::get_dynamic_field_from_store, error::{UserInputError, UserInputResult}, id::{ID, UID}, object::{Object, Owner}, storage::ObjectStore, - SUI_DENY_LIST_OBJECT_ID, + IOTA_DENY_LIST_OBJECT_ID, }; pub const DENY_LIST_MODULE: &IdentStr = ident_str!("deny_list"); @@ -52,7 +53,7 @@ pub struct PerTypeDenyList { impl DenyList { pub fn check_coin_deny_list( - address: SuiAddress, + address: IotaAddress, coin_types: BTreeSet, object_store: &dyn ObjectStore, ) -> UserInputResult { @@ -69,12 +70,12 @@ impl DenyList { fn check_deny_list( deny_list: PerTypeDenyList, - address: SuiAddress, + address: IotaAddress, coin_types: BTreeSet, object_store: &dyn ObjectStore, ) -> UserInputResult { // TODO: Add caches to avoid repeated DF reads. - let Ok(count) = get_dynamic_field_from_store::( + let Ok(count) = get_dynamic_field_from_store::( object_store, deny_list.denied_count.id, &address, @@ -85,7 +86,7 @@ impl DenyList { return Ok(()); } for coin_type in coin_types { - let Ok(denied_addresses) = get_dynamic_field_from_store::, VecSet>( + let Ok(denied_addresses) = get_dynamic_field_from_store::, VecSet>( object_store, deny_list.denied_addresses.id, &coin_type.clone().into_bytes(), @@ -118,7 +119,7 @@ pub struct RegulatedCoinMetadata { } pub fn get_deny_list_root_object(object_store: &dyn ObjectStore) -> Option { - match object_store.get_object(&SUI_DENY_LIST_OBJECT_ID) { + match object_store.get_object(&IOTA_DENY_LIST_OBJECT_ID) { Ok(Some(obj)) => Some(obj), Ok(None) => { error!("Deny list object not found"); diff --git a/crates/sui-types/src/digests.rs b/crates/iota-types/src/digests.rs similarity index 94% rename from crates/sui-types/src/digests.rs rename to crates/iota-types/src/digests.rs index eab1f6bd9a5..aca3a320566 100644 --- a/crates/sui-types/src/digests.rs +++ b/crates/iota-types/src/digests.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{env, fmt}; use fastcrypto::encoding::{Base58, Encoding}; +use iota_protocol_config::Chain; use once_cell::sync::{Lazy, OnceCell}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, Bytes}; -use sui_protocol_config::Chain; use tracing::info; -use crate::{error::SuiError, sui_serde::Readable}; +use crate::{error::IotaError, iota_serde::Readable}; /// A representation of a 32 byte digest #[serde_as] @@ -87,11 +88,11 @@ impl From<[u8; 32]> for Digest { } impl TryFrom> for Digest { - type Error = SuiError; + type Error = IotaError; - fn try_from(bytes: Vec) -> Result { + fn try_from(bytes: Vec) -> Result { let bytes: [u8; 32] = - <[u8; 32]>::try_from(&bytes[..]).map_err(|_| SuiError::InvalidDigestLength { + <[u8; 32]>::try_from(&bytes[..]).map_err(|_| IotaError::InvalidDigestLength { expected: 32, actual: bytes.len(), })?; @@ -164,16 +165,17 @@ pub static TESTNET_CHAIN_IDENTIFIER: OnceCell = OnceCell::new() /// For testing purposes or bootstrapping regenesis chaing configuration, you /// can set this environment variable to force protocol config to use a specific /// Chain. -const SUI_PROTOCOL_CONFIG_CHAIN_OVERRIDE_ENV_VAR_NAME: &str = "SUI_PROTOCOL_CONFIG_CHAIN_OVERRIDE"; +const IOTA_PROTOCOL_CONFIG_CHAIN_OVERRIDE_ENV_VAR_NAME: &str = + "IOTA_PROTOCOL_CONFIG_CHAIN_OVERRIDE"; -static SUI_PROTOCOL_CONFIG_CHAIN_OVERRIDE: Lazy> = Lazy::new(|| { - if let Ok(s) = env::var(SUI_PROTOCOL_CONFIG_CHAIN_OVERRIDE_ENV_VAR_NAME) { - info!("SUI_PROTOCOL_CONFIG_CHAIN_OVERRIDE: {:?}", s); +static IOTA_PROTOCOL_CONFIG_CHAIN_OVERRIDE: Lazy> = Lazy::new(|| { + if let Ok(s) = env::var(IOTA_PROTOCOL_CONFIG_CHAIN_OVERRIDE_ENV_VAR_NAME) { + info!("IOTA_PROTOCOL_CONFIG_CHAIN_OVERRIDE: {:?}", s); match s.as_str() { "mainnet" => Some(Chain::Mainnet), "testnet" => Some(Chain::Testnet), "" => None, - _ => panic!("unrecognized SUI_PROTOCOL_CONFIG_CHAIN_OVERRIDE: {s:?}"), + _ => panic!("unrecognized IOTA_PROTOCOL_CONFIG_CHAIN_OVERRIDE: {s:?}"), } } else { None @@ -190,7 +192,7 @@ impl ChainIdentifier { id if *id == testnet_id => Chain::Testnet, _ => Chain::Unknown, }; - if let Some(override_chain) = *SUI_PROTOCOL_CONFIG_CHAIN_OVERRIDE { + if let Some(override_chain) = *IOTA_PROTOCOL_CONFIG_CHAIN_OVERRIDE { if chain != Chain::Unknown { panic!("not allowed to override real chain {chain:?}"); } @@ -308,9 +310,9 @@ impl From<[u8; 32]> for CheckpointDigest { } impl TryFrom> for CheckpointDigest { - type Error = SuiError; + type Error = IotaError; - fn try_from(bytes: Vec) -> Result { + fn try_from(bytes: Vec) -> Result { Digest::try_from(bytes).map(CheckpointDigest) } } @@ -503,7 +505,7 @@ impl TransactionDigest { /// ie. for an object there is no parent digest. /// Note that this is not the same as the digest of the genesis transaction, /// which cannot be known ahead of time. - // TODO(https://github.com/MystenLabs/sui/issues/65): we can pick anything here + // TODO(https://github.com/iotaledger/iota/issues/65): we can pick anything here pub const fn genesis_marker() -> Self { Self::ZERO } @@ -582,12 +584,12 @@ impl fmt::UpperHex for TransactionDigest { } impl TryFrom<&[u8]> for TransactionDigest { - type Error = crate::error::SuiError; + type Error = crate::error::IotaError; - fn try_from(bytes: &[u8]) -> Result { + fn try_from(bytes: &[u8]) -> Result { let arr: [u8; 32] = bytes .try_into() - .map_err(|_| crate::error::SuiError::InvalidTransactionDigest)?; + .map_err(|_| crate::error::IotaError::InvalidTransactionDigest)?; Ok(Self::new(arr)) } } @@ -899,12 +901,12 @@ impl fmt::UpperHex for ObjectDigest { } impl TryFrom<&[u8]> for ObjectDigest { - type Error = crate::error::SuiError; + type Error = crate::error::IotaError; - fn try_from(bytes: &[u8]) -> Result { + fn try_from(bytes: &[u8]) -> Result { let arr: [u8; 32] = bytes .try_into() - .map_err(|_| crate::error::SuiError::InvalidTransactionDigest)?; + .map_err(|_| crate::error::IotaError::InvalidTransactionDigest)?; Ok(Self::new(arr)) } } diff --git a/crates/iota-types/src/display.rs b/crates/iota-types/src/display.rs new file mode 100644 index 00000000000..3d8224fcab4 --- /dev/null +++ b/crates/iota-types/src/display.rs @@ -0,0 +1,93 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; +use serde::Deserialize; + +use crate::{ + collection_types::VecMap, + event::Event, + id::{ID, UID}, + IOTA_FRAMEWORK_ADDRESS, +}; + +pub const DISPLAY_MODULE_NAME: &IdentStr = ident_str!("display"); +pub const DISPLAY_CREATED_EVENT_NAME: &IdentStr = ident_str!("DisplayCreated"); +pub const DISPLAY_VERSION_UPDATED_EVENT_NAME: &IdentStr = ident_str!("VersionUpdated"); + +// TODO: add tests to keep in sync +/// Rust version of the Move iota::display::Display type +#[derive(Debug, Deserialize, Clone, Eq, PartialEq)] +pub struct DisplayObject { + pub id: UID, + pub fields: VecMap, + pub version: u16, +} + +#[derive(Deserialize, Debug)] +/// The event that is emitted when a `Display` version is "released". +/// Serves for Display versioning. +pub struct DisplayVersionUpdatedEvent { + pub id: ID, + pub version: u16, + pub fields: VecMap, +} + +impl DisplayVersionUpdatedEvent { + pub fn type_(inner: &StructTag) -> StructTag { + StructTag { + address: IOTA_FRAMEWORK_ADDRESS, + name: DISPLAY_VERSION_UPDATED_EVENT_NAME.to_owned(), + module: DISPLAY_MODULE_NAME.to_owned(), + type_params: vec![inner.clone().into()], + } + } + + // Checks if the provided `StructTag` is a DisplayVersionUpdatedEvent + pub fn is_display_updated_event(inner: &StructTag) -> bool { + inner.address == IOTA_FRAMEWORK_ADDRESS + && inner.module.as_ident_str() == DISPLAY_MODULE_NAME + && inner.name.as_ident_str() == DISPLAY_VERSION_UPDATED_EVENT_NAME + } + + // Checks if the provided `StructTag` is a DisplayVersionUpdatedEvent and + // returns a reference to the inner type T if so. + pub fn inner_type(inner: &StructTag) -> Option<&StructTag> { + use move_core_types::language_storage::TypeTag; + + if !Self::is_display_updated_event(inner) { + return None; + } + + match &inner.type_params[..] { + [TypeTag::Struct(struct_type)] => Some(struct_type), + _ => None, + } + } + + pub fn try_from_event(event: &Event) -> Option<(&StructTag, Self)> { + let inner_type = Self::inner_type(&event.type_)?; + + bcs::from_bytes(&event.contents) + .ok() + .map(|event| (inner_type, event)) + } +} + +#[derive(Deserialize, Debug)] +pub struct DisplayCreatedEvent { + // The Object ID of Display Object + pub id: ID, +} + +impl DisplayCreatedEvent { + pub fn type_(inner: &StructTag) -> StructTag { + StructTag { + address: IOTA_FRAMEWORK_ADDRESS, + name: DISPLAY_CREATED_EVENT_NAME.to_owned(), + module: DISPLAY_MODULE_NAME.to_owned(), + type_params: vec![inner.clone().into()], + } + } +} diff --git a/crates/iota-types/src/dynamic_field.rs b/crates/iota-types/src/dynamic_field.rs new file mode 100644 index 00000000000..ad48d80322a --- /dev/null +++ b/crates/iota-types/src/dynamic_field.rs @@ -0,0 +1,333 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + fmt, + fmt::{Display, Formatter}, +}; + +use fastcrypto::{encoding::Base58, hash::HashFunction}; +use move_core_types::{ + annotated_value::{MoveStruct, MoveValue}, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag}, +}; +use schemars::JsonSchema; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde_json::Value; +use serde_with::{serde_as, DisplayFromStr}; +use shared_crypto::intent::HashingIntentScope; + +use crate::{ + base_types::{IotaAddress, ObjectDigest}, + crypto::DefaultHash, + error::{IotaError, IotaResult}, + id::UID, + iota_serde::{IotaTypeTag, Readable}, + object::Object, + storage::ObjectStore, + MoveTypeTagTrait, ObjectID, SequenceNumber, IOTA_FRAMEWORK_ADDRESS, +}; + +const DYNAMIC_FIELD_MODULE_NAME: &IdentStr = ident_str!("dynamic_field"); +const DYNAMIC_FIELD_FIELD_STRUCT_NAME: &IdentStr = ident_str!("Field"); + +const DYNAMIC_OBJECT_FIELD_MODULE_NAME: &IdentStr = ident_str!("dynamic_object_field"); +const DYNAMIC_OBJECT_FIELD_WRAPPER_STRUCT_NAME: &IdentStr = ident_str!("Wrapper"); + +/// Rust version of the Move iota::dynamic_field::Field type +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct Field { + pub id: UID, + pub name: N, + pub value: V, +} + +#[serde_as] +#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)] +#[serde(rename_all = "camelCase")] +pub struct DynamicFieldInfo { + pub name: DynamicFieldName, + #[schemars(with = "Base58")] + #[serde_as(as = "Readable")] + pub bcs_name: Vec, + pub type_: DynamicFieldType, + pub object_type: String, + pub object_id: ObjectID, + pub version: SequenceNumber, + pub digest: ObjectDigest, +} + +#[serde_as] +#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)] +#[serde(rename_all = "camelCase")] +pub struct DynamicFieldName { + #[schemars(with = "String")] + #[serde_as(as = "Readable")] + pub type_: TypeTag, + // Bincode does not like serde_json::Value, rocksdb will not insert the value without + // serializing value as string. TODO: investigate if this can be removed after switch to + // BCS. + #[schemars(with = "Value")] + #[serde_as(as = "Readable<_, DisplayFromStr>")] + pub value: Value, +} + +impl Display for DynamicFieldName { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}: {}", self.type_, self.value) + } +} + +#[derive(Clone, Serialize, Deserialize, JsonSchema, Ord, PartialOrd, Eq, PartialEq, Debug)] +pub enum DynamicFieldType { + #[serde(rename_all = "camelCase")] + DynamicField, + DynamicObject, +} + +impl Display for DynamicFieldType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DynamicFieldType::DynamicField => write!(f, "DynamicField"), + DynamicFieldType::DynamicObject => write!(f, "DynamicObject"), + } + } +} + +impl DynamicFieldInfo { + pub fn is_dynamic_field(tag: &StructTag) -> bool { + tag.address == IOTA_FRAMEWORK_ADDRESS + && tag.module.as_ident_str() == DYNAMIC_FIELD_MODULE_NAME + && tag.name.as_ident_str() == DYNAMIC_FIELD_FIELD_STRUCT_NAME + } + + pub fn is_dynamic_object_field_wrapper(tag: &StructTag) -> bool { + tag.address == IOTA_FRAMEWORK_ADDRESS + && tag.module.as_ident_str() == DYNAMIC_OBJECT_FIELD_MODULE_NAME + && tag.name.as_ident_str() == DYNAMIC_OBJECT_FIELD_WRAPPER_STRUCT_NAME + } + + pub fn dynamic_field_type(key: TypeTag, value: TypeTag) -> StructTag { + StructTag { + address: IOTA_FRAMEWORK_ADDRESS, + name: DYNAMIC_FIELD_FIELD_STRUCT_NAME.to_owned(), + module: DYNAMIC_FIELD_MODULE_NAME.to_owned(), + type_params: vec![key, value], + } + } + + pub fn dynamic_object_field_wrapper(key: TypeTag) -> StructTag { + StructTag { + address: IOTA_FRAMEWORK_ADDRESS, + module: DYNAMIC_OBJECT_FIELD_MODULE_NAME.to_owned(), + name: DYNAMIC_OBJECT_FIELD_WRAPPER_STRUCT_NAME.to_owned(), + type_params: vec![key], + } + } + + pub fn try_extract_field_name( + tag: &StructTag, + type_: &DynamicFieldType, + ) -> IotaResult { + match (type_, tag.type_params.first()) { + (DynamicFieldType::DynamicField, Some(name_type)) => Ok(name_type.clone()), + (DynamicFieldType::DynamicObject, Some(TypeTag::Struct(s))) => Ok(s + .type_params + .first() + .ok_or_else(|| IotaError::ObjectDeserializationError { + error: format!("Error extracting dynamic object name from object: {tag}"), + })? + .clone()), + _ => Err(IotaError::ObjectDeserializationError { + error: format!("Error extracting dynamic object name from object: {tag}"), + }), + } + } + + pub fn try_extract_field_value(tag: &StructTag) -> IotaResult { + match tag.type_params.last() { + Some(value_type) => Ok(value_type.clone()), + None => Err(IotaError::ObjectDeserializationError { + error: format!("Error extracting dynamic object value from object: {tag}"), + }), + } + } + + pub fn parse_move_object( + move_struct: &MoveStruct, + ) -> IotaResult<(MoveValue, DynamicFieldType, ObjectID)> { + let name = extract_field_from_move_struct(move_struct, "name").ok_or_else(|| { + IotaError::ObjectDeserializationError { + error: "Cannot extract [name] field from iota::dynamic_field::Field".to_string(), + } + })?; + + let value = extract_field_from_move_struct(move_struct, "value").ok_or_else(|| { + IotaError::ObjectDeserializationError { + error: "Cannot extract [value] field from iota::dynamic_field::Field".to_string(), + } + })?; + + Ok(if is_dynamic_object(move_struct) { + let name = match name { + MoveValue::Struct(name_struct) => { + extract_field_from_move_struct(name_struct, "name") + } + _ => None, + } + .ok_or_else(|| IotaError::ObjectDeserializationError { + error: "Cannot extract [name] field from iota::dynamic_object_field::Wrapper." + .to_string(), + })?; + // ID extracted from the wrapper object + let object_id = + extract_id_value(value).ok_or_else(|| IotaError::ObjectDeserializationError { + error: format!( + "Cannot extract dynamic object's object id from \ + iota::dynamic_field::Field, {value:?}" + ), + })?; + (name.clone(), DynamicFieldType::DynamicObject, object_id) + } else { + // ID of the Field object + let object_id = extract_object_id(move_struct).ok_or_else(|| { + IotaError::ObjectDeserializationError { + error: format!( + "Cannot extract dynamic object's object id from \ + iota::dynamic_field::Field, {move_struct:?}", + ), + } + })?; + (name.clone(), DynamicFieldType::DynamicField, object_id) + }) + } +} + +pub fn extract_field_from_move_struct<'a>( + move_struct: &'a MoveStruct, + field_name: &str, +) -> Option<&'a MoveValue> { + move_struct.fields.iter().find_map(|(id, value)| { + if id.to_string() == field_name { + Some(value) + } else { + None + } + }) +} + +fn extract_object_id(value: &MoveStruct) -> Option { + // id:UID is the first value in an object + let uid_value = &value.fields.first()?.1; + + // id is the first value in UID + let id_value = match uid_value { + MoveValue::Struct(MoveStruct { fields, .. }) => &fields.first()?.1, + _ => return None, + }; + extract_id_value(id_value) +} + +fn extract_id_value(id_value: &MoveValue) -> Option { + // the id struct has a single bytes field + let id_bytes_value = match id_value { + MoveValue::Struct(MoveStruct { fields, .. }) => &fields.first()?.1, + _ => return None, + }; + // the bytes field should be an address + match id_bytes_value { + MoveValue::Address(addr) => Some(ObjectID::from(*addr)), + _ => None, + } +} + +pub fn is_dynamic_object(move_struct: &MoveStruct) -> bool { + matches!( + &move_struct.type_.type_params[0], + TypeTag::Struct(tag) if DynamicFieldInfo::is_dynamic_object_field_wrapper(tag) + ) +} + +pub fn derive_dynamic_field_id( + parent: T, + key_type_tag: &TypeTag, + key_bytes: &[u8], +) -> Result +where + T: Into, +{ + let parent: IotaAddress = parent.into(); + let k_tag_bytes = bcs::to_bytes(key_type_tag)?; + tracing::trace!( + "Deriving dynamic field ID for parent={:?}, key={:?}, key_type_tag={:?}", + parent, + key_bytes, + key_type_tag, + ); + + // hash(parent || len(key) || key || key_type_tag) + let mut hasher = DefaultHash::default(); + hasher.update([HashingIntentScope::ChildObjectId as u8]); + hasher.update(parent); + hasher.update(key_bytes.len().to_le_bytes()); + hasher.update(key_bytes); + hasher.update(k_tag_bytes); + let hash = hasher.finalize(); + + // truncate into an ObjectID and return + // OK to access slice because digest should never be shorter than + // ObjectID::LENGTH. + let id = ObjectID::try_from(&hash.as_ref()[0..ObjectID::LENGTH]).unwrap(); + tracing::trace!("derive_dynamic_field_id result: {:?}", id); + Ok(id) +} + +/// Given a parent object ID (e.g. a table), and a `key`, retrieve the +/// corresponding dynamic field object from the `object_store`. The key type `K` +/// must implement `MoveTypeTagTrait` which has an associated function that +/// returns the Move type tag. Note that this function returns the Field object +/// itself, not the value in the field. +pub fn get_dynamic_field_object_from_store( + object_store: &dyn ObjectStore, + parent_id: ObjectID, + key: &K, +) -> Result +where + K: MoveTypeTagTrait + Serialize + DeserializeOwned + fmt::Debug, +{ + let id = derive_dynamic_field_id(parent_id, &K::get_type_tag(), &bcs::to_bytes(key).unwrap()) + .map_err(|err| IotaError::DynamicFieldReadError(err.to_string()))?; + let object = object_store.get_object(&id)?.ok_or_else(|| { + IotaError::DynamicFieldReadError(format!( + "Dynamic field with key={:?} and ID={:?} not found on parent {:?}", + key, id, parent_id + )) + })?; + Ok(object) +} + +/// Similar to `get_dynamic_field_object_from_store`, but returns the value in +/// the field instead of the Field object itself. +pub fn get_dynamic_field_from_store( + object_store: &dyn ObjectStore, + parent_id: ObjectID, + key: &K, +) -> Result +where + K: MoveTypeTagTrait + Serialize + DeserializeOwned + fmt::Debug, + V: Serialize + DeserializeOwned, +{ + let object = get_dynamic_field_object_from_store(object_store, parent_id, key)?; + let move_object = object.data.try_as_move().ok_or_else(|| { + IotaError::DynamicFieldReadError(format!( + "Dynamic field {:?} is not a Move object", + object.id() + )) + })?; + Ok(bcs::from_bytes::>(move_object.contents()) + .map_err(|err| IotaError::DynamicFieldReadError(err.to_string()))? + .value) +} diff --git a/crates/sui-types/src/effects/effects_v1.rs b/crates/iota-types/src/effects/effects_v1.rs similarity index 98% rename from crates/sui-types/src/effects/effects_v1.rs rename to crates/iota-types/src/effects/effects_v1.rs index db1b6c28ab2..d78b8f3d7e9 100644 --- a/crates/sui-types/src/effects/effects_v1.rs +++ b/crates/iota-types/src/effects/effects_v1.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -11,7 +12,7 @@ use serde::{Deserialize, Serialize}; use super::{IDOperation, ObjectChange}; use crate::{ base_types::{ - random_object_ref, EpochId, ObjectID, ObjectRef, SequenceNumber, SuiAddress, + random_object_ref, EpochId, IotaAddress, ObjectID, ObjectRef, SequenceNumber, TransactionDigest, }, digests::{ObjectDigest, TransactionEventsDigest}, @@ -356,7 +357,7 @@ impl Default for TransactionEffectsV1 { wrapped: Vec::new(), gas_object: ( random_object_ref(), - Owner::AddressOwner(SuiAddress::default()), + Owner::AddressOwner(IotaAddress::default()), ), events_digest: None, dependencies: Vec::new(), diff --git a/crates/sui-types/src/effects/effects_v2.rs b/crates/iota-types/src/effects/effects_v2.rs similarity index 98% rename from crates/sui-types/src/effects/effects_v2.rs rename to crates/iota-types/src/effects/effects_v2.rs index 43b4e8eef4b..1963089fe2d 100644 --- a/crates/sui-types/src/effects/effects_v2.rs +++ b/crates/iota-types/src/effects/effects_v2.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeMap; @@ -15,7 +16,7 @@ use super::{ use crate::is_system_package; use crate::{ base_types::{ - EpochId, ObjectDigest, ObjectID, ObjectRef, SequenceNumber, SuiAddress, TransactionDigest, + EpochId, IotaAddress, ObjectDigest, ObjectID, ObjectRef, SequenceNumber, TransactionDigest, VersionDigest, }, digests::{EffectsAuxDataDigest, TransactionEventsDigest}, @@ -295,7 +296,7 @@ impl TransactionEffectsAPI for TransactionEffectsV2 { } else { ( (ObjectID::ZERO, SequenceNumber::default(), ObjectDigest::MIN), - Owner::AddressOwner(SuiAddress::default()), + Owner::AddressOwner(IotaAddress::default()), ) } } @@ -371,11 +372,11 @@ impl TransactionEffectsAPI for TransactionEffectsV2 { EffectsObjectChange { input_state: ObjectIn::Exist(( (obj_ref.1, obj_ref.2), - Owner::AddressOwner(SuiAddress::default()), + Owner::AddressOwner(IotaAddress::default()), )), output_state: ObjectOut::ObjectWrite(( obj_ref.2, - Owner::AddressOwner(SuiAddress::default()), + Owner::AddressOwner(IotaAddress::default()), )), id_operation: IDOperation::None, }, @@ -388,7 +389,7 @@ impl TransactionEffectsAPI for TransactionEffectsV2 { EffectsObjectChange { input_state: ObjectIn::Exist(( (obj_ref.1, obj_ref.2), - Owner::AddressOwner(SuiAddress::default()), + Owner::AddressOwner(IotaAddress::default()), )), output_state: ObjectOut::NotExist, id_operation: IDOperation::Deleted, diff --git a/crates/iota-types/src/effects/mod.rs b/crates/iota-types/src/effects/mod.rs new file mode 100644 index 00000000000..0f202702cdd --- /dev/null +++ b/crates/iota-types/src/effects/mod.rs @@ -0,0 +1,465 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use effects_v1::TransactionEffectsV1; +pub use effects_v2::UnchangedSharedKind; +use enum_dispatch::enum_dispatch; +use iota_protocol_config::ProtocolConfig; +pub use object_change::{EffectsObjectChange, ObjectIn, ObjectOut}; +use serde::{Deserialize, Serialize}; +use shared_crypto::intent::IntentScope; +pub use test_effects_builder::TestEffectsBuilder; + +use self::effects_v2::TransactionEffectsV2; +use crate::{ + base_types::{ExecutionDigests, ObjectID, ObjectRef, SequenceNumber}, + committee::EpochId, + crypto::{default_hash, AuthoritySignInfo, AuthorityStrongQuorumSignInfo, EmptySignInfo}, + digests::{ObjectDigest, TransactionDigest, TransactionEffectsDigest, TransactionEventsDigest}, + error::{IotaError, IotaResult}, + event::Event, + execution::SharedInput, + execution_status::ExecutionStatus, + gas::GasCostSummary, + message_envelope::{ + Envelope, Message, TrustedEnvelope, UnauthenticatedMessage, VerifiedEnvelope, + }, + object::Owner, + storage::WriteKind, + transaction::VersionedProtocolMessage, +}; + +mod effects_v1; +mod effects_v2; +mod object_change; +mod test_effects_builder; + +// Since `std::mem::size_of` may not be stable across platforms, we use rough +// constants We need these for estimating effects sizes +// Approximate size of `ObjectRef` type in bytes +pub const APPROX_SIZE_OF_OBJECT_REF: usize = 80; +// Approximate size of `ExecutionStatus` type in bytes +pub const APPROX_SIZE_OF_EXECUTION_STATUS: usize = 120; +// Approximate size of `EpochId` type in bytes +pub const APPROX_SIZE_OF_EPOCH_ID: usize = 10; +// Approximate size of `GasCostSummary` type in bytes +pub const APPROX_SIZE_OF_GAS_COST_SUMMARY: usize = 40; +// Approximate size of `Option` type in bytes +pub const APPROX_SIZE_OF_OPT_TX_EVENTS_DIGEST: usize = 40; +// Approximate size of `TransactionDigest` type in bytes +pub const APPROX_SIZE_OF_TX_DIGEST: usize = 40; +// Approximate size of `Owner` type in bytes +pub const APPROX_SIZE_OF_OWNER: usize = 48; + +/// The response from processing a transaction or a certified transaction +#[enum_dispatch(TransactionEffectsAPI)] +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] +#[allow(clippy::large_enum_variant)] +pub enum TransactionEffects { + V1(TransactionEffectsV1), + V2(TransactionEffectsV2), +} + +impl VersionedProtocolMessage for TransactionEffects { + fn message_version(&self) -> Option { + Some(match self { + Self::V1(_) => 1, + Self::V2(_) => 2, + }) + } + + fn check_version_supported(&self, protocol_config: &ProtocolConfig) -> IotaResult { + match self { + Self::V1(_) => Ok(()), + Self::V2(_) => { + if protocol_config.enable_effects_v2() { + Ok(()) + } else { + Err(IotaError::WrongMessageVersion { + error: format!( + "TransactionEffectsV2 is not supported at protocol {:?}.", + protocol_config.version + ), + }) + } + } + } + } +} + +impl Message for TransactionEffects { + type DigestType = TransactionEffectsDigest; + const SCOPE: IntentScope = IntentScope::TransactionEffects; + + fn digest(&self) -> Self::DigestType { + TransactionEffectsDigest::new(default_hash(self)) + } + + fn verify_user_input(&self) -> IotaResult { + Ok(()) + } + + fn verify_epoch(&self, _: EpochId) -> IotaResult { + // Authorities are allowed to re-sign effects from prior epochs, so we do not + // verify the epoch here. + Ok(()) + } +} + +impl UnauthenticatedMessage for TransactionEffects {} + +// TODO: Get rid of this and use TestEffectsBuilder instead. +impl Default for TransactionEffects { + fn default() -> Self { + TransactionEffects::V2(Default::default()) + } +} + +pub enum ObjectRemoveKind { + Delete, + Wrap, +} + +impl TransactionEffects { + /// Creates a TransactionEffects message from the results of execution, + /// choosing the correct format for the current protocol version. + pub fn new_from_execution_v1( + status: ExecutionStatus, + executed_epoch: EpochId, + gas_used: GasCostSummary, + modified_at_versions: Vec<(ObjectID, SequenceNumber)>, + shared_objects: Vec, + transaction_digest: TransactionDigest, + created: Vec<(ObjectRef, Owner)>, + mutated: Vec<(ObjectRef, Owner)>, + unwrapped: Vec<(ObjectRef, Owner)>, + deleted: Vec, + unwrapped_then_deleted: Vec, + wrapped: Vec, + gas_object: (ObjectRef, Owner), + events_digest: Option, + dependencies: Vec, + ) -> Self { + Self::V1(TransactionEffectsV1::new( + status, + executed_epoch, + gas_used, + modified_at_versions, + shared_objects, + transaction_digest, + created, + mutated, + unwrapped, + deleted, + unwrapped_then_deleted, + wrapped, + gas_object, + events_digest, + dependencies, + )) + } + + /// Creates a TransactionEffects message from the results of execution, + /// choosing the correct format for the current protocol version. + pub fn new_from_execution_v2( + status: ExecutionStatus, + executed_epoch: EpochId, + gas_used: GasCostSummary, + shared_objects: Vec, + transaction_digest: TransactionDigest, + lamport_version: SequenceNumber, + changed_objects: BTreeMap, + gas_object: Option, + events_digest: Option, + dependencies: Vec, + ) -> Self { + Self::V2(TransactionEffectsV2::new( + status, + executed_epoch, + gas_used, + shared_objects, + transaction_digest, + lamport_version, + changed_objects, + gas_object, + events_digest, + dependencies, + )) + } + + pub fn execution_digests(&self) -> ExecutionDigests { + ExecutionDigests { + transaction: *self.transaction_digest(), + effects: self.digest(), + } + } + + pub fn estimate_effects_size_upperbound_v1( + num_writes: usize, + num_mutables: usize, + num_deletes: usize, + num_deps: usize, + ) -> usize { + let fixed_sizes = APPROX_SIZE_OF_EXECUTION_STATUS + + APPROX_SIZE_OF_EPOCH_ID + + APPROX_SIZE_OF_GAS_COST_SUMMARY + + APPROX_SIZE_OF_OPT_TX_EVENTS_DIGEST; + + // Each write or delete contributes at roughly this amount because: + // Each write can be a mutation which can show up in `mutated` and + // `modified_at_versions` `num_delete` is added for padding + let approx_change_entry_size = 1_000 + + (APPROX_SIZE_OF_OWNER + APPROX_SIZE_OF_OBJECT_REF) * num_writes + + (APPROX_SIZE_OF_OBJECT_REF * num_mutables) + + (APPROX_SIZE_OF_OBJECT_REF * num_deletes); + + let deps_size = 1_000 + APPROX_SIZE_OF_TX_DIGEST * num_deps; + + fixed_sizes + approx_change_entry_size + deps_size + } + + pub fn estimate_effects_size_upperbound_v2( + num_writes: usize, + num_modifies: usize, + num_deps: usize, + ) -> usize { + let fixed_sizes = APPROX_SIZE_OF_EXECUTION_STATUS + + APPROX_SIZE_OF_EPOCH_ID + + APPROX_SIZE_OF_GAS_COST_SUMMARY + + APPROX_SIZE_OF_OPT_TX_EVENTS_DIGEST; + + // We store object ref and owner for both old objects and new objects. + let approx_change_entry_size = 1_000 + + (APPROX_SIZE_OF_OWNER + APPROX_SIZE_OF_OBJECT_REF) * num_writes + + (APPROX_SIZE_OF_OWNER + APPROX_SIZE_OF_OBJECT_REF) * num_modifies; + + let deps_size = 1_000 + APPROX_SIZE_OF_TX_DIGEST * num_deps; + + fixed_sizes + approx_change_entry_size + deps_size + } + + /// Return an iterator that iterates through all changed objects, including + /// mutated, created and unwrapped objects. In other words, all objects + /// that still exist in the object state after this transaction. + /// It doesn't include deleted/wrapped objects. + pub fn all_changed_objects(&self) -> Vec<(ObjectRef, Owner, WriteKind)> { + self.mutated() + .into_iter() + .map(|(r, o)| (r, o, WriteKind::Mutate)) + .chain( + self.created() + .into_iter() + .map(|(r, o)| (r, o, WriteKind::Create)), + ) + .chain( + self.unwrapped() + .into_iter() + .map(|(r, o)| (r, o, WriteKind::Unwrap)), + ) + .collect() + } + + /// Return all objects that existed in the state prior to the transaction + /// but no longer exist in the state after the transaction. + /// It includes deleted and wrapped objects, but does not include + /// unwrapped_then_deleted objects. + pub fn all_removed_objects(&self) -> Vec<(ObjectRef, ObjectRemoveKind)> { + self.deleted() + .iter() + .map(|obj_ref| (*obj_ref, ObjectRemoveKind::Delete)) + .chain( + self.wrapped() + .iter() + .map(|obj_ref| (*obj_ref, ObjectRemoveKind::Wrap)), + ) + .collect() + } + + /// Returns all objects that will become a tombstone after this transaction. + /// This includes deleted, unwrapped_then_deleted and wrapped objects. + pub fn all_tombstones(&self) -> Vec<(ObjectID, SequenceNumber)> { + self.deleted() + .into_iter() + .chain(self.unwrapped_then_deleted()) + .chain(self.wrapped()) + .map(|obj_ref| (obj_ref.0, obj_ref.1)) + .collect() + } + + /// Return an iterator of mutated objects, but excluding the gas object. + pub fn mutated_excluding_gas(&self) -> Vec<(ObjectRef, Owner)> { + self.mutated() + .into_iter() + .filter(|o| o != &self.gas_object()) + .collect() + } + + pub fn summary_for_debug(&self) -> TransactionEffectsDebugSummary { + TransactionEffectsDebugSummary { + bcs_size: bcs::serialized_size(self).unwrap(), + status: self.status().clone(), + gas_used: self.gas_cost_summary().clone(), + transaction_digest: *self.transaction_digest(), + created_object_count: self.created().len(), + mutated_object_count: self.mutated().len(), + unwrapped_object_count: self.unwrapped().len(), + deleted_object_count: self.deleted().len(), + wrapped_object_count: self.wrapped().len(), + dependency_count: self.dependencies().len(), + } + } +} + +#[derive(Eq, PartialEq, Clone, Debug)] +pub enum InputSharedObject { + Mutate(ObjectRef), + ReadOnly(ObjectRef), + ReadDeleted(ObjectID, SequenceNumber), + MutateDeleted(ObjectID, SequenceNumber), +} + +impl InputSharedObject { + pub fn id_and_version(&self) -> (ObjectID, SequenceNumber) { + let oref = self.object_ref(); + (oref.0, oref.1) + } + + pub fn object_ref(&self) -> ObjectRef { + match self { + InputSharedObject::Mutate(oref) | InputSharedObject::ReadOnly(oref) => *oref, + InputSharedObject::ReadDeleted(id, version) + | InputSharedObject::MutateDeleted(id, version) => { + (*id, *version, ObjectDigest::OBJECT_DIGEST_DELETED) + } + } + } +} + +#[enum_dispatch] +pub trait TransactionEffectsAPI { + fn status(&self) -> &ExecutionStatus; + fn into_status(self) -> ExecutionStatus; + fn executed_epoch(&self) -> EpochId; + fn modified_at_versions(&self) -> Vec<(ObjectID, SequenceNumber)>; + + /// The version assigned to all output objects (apart from packages). + fn lamport_version(&self) -> SequenceNumber; + + /// Metadata of objects prior to modification. This includes any object that + /// exists in the store prior to this transaction and is modified in + /// this transaction. It includes objects that are mutated, wrapped and + /// deleted. This API is only available on effects v2 and above. + fn old_object_metadata(&self) -> Vec<(ObjectRef, Owner)>; + /// Returns the list of shared objects used in the input, with full object + /// reference and use kind. This is needed in effects because in + /// transaction we only have object ID for shared objects. Their version + /// and digest can only be figured out after sequencing. Also provides + /// the use kind to indicate whether the object was mutated or read-only. + /// Down the road it could also indicate use-of-deleted. + fn input_shared_objects(&self) -> Vec; + fn created(&self) -> Vec<(ObjectRef, Owner)>; + fn mutated(&self) -> Vec<(ObjectRef, Owner)>; + fn unwrapped(&self) -> Vec<(ObjectRef, Owner)>; + fn deleted(&self) -> Vec; + fn unwrapped_then_deleted(&self) -> Vec; + fn wrapped(&self) -> Vec; + + fn object_changes(&self) -> Vec; + + // TODO: We should consider having this function to return Option. + // When the gas object is not available (i.e. system transaction), we currently + // return dummy object ref and owner. This is not ideal. + fn gas_object(&self) -> (ObjectRef, Owner); + + fn events_digest(&self) -> Option<&TransactionEventsDigest>; + fn dependencies(&self) -> &[TransactionDigest]; + + fn transaction_digest(&self) -> &TransactionDigest; + + fn gas_cost_summary(&self) -> &GasCostSummary; + + fn deleted_mutably_accessed_shared_objects(&self) -> Vec { + self.input_shared_objects() + .into_iter() + .filter_map(|kind| match kind { + InputSharedObject::MutateDeleted(id, _) => Some(id), + InputSharedObject::Mutate(..) + | InputSharedObject::ReadOnly(..) + | InputSharedObject::ReadDeleted(..) => None, + }) + .collect() + } + + // All of these should be #[cfg(test)], but they are used by tests in other + // crates, and dependencies don't get built with cfg(test) set as far as I + // can tell. + fn status_mut_for_testing(&mut self) -> &mut ExecutionStatus; + fn gas_cost_summary_mut_for_testing(&mut self) -> &mut GasCostSummary; + fn transaction_digest_mut_for_testing(&mut self) -> &mut TransactionDigest; + fn dependencies_mut_for_testing(&mut self) -> &mut Vec; + fn unsafe_add_input_shared_object_for_testing(&mut self, kind: InputSharedObject); + + // Adding an old version of a live object. + fn unsafe_add_deleted_live_object_for_testing(&mut self, obj_ref: ObjectRef); + + // Adding a tombstone for a deleted object. + fn unsafe_add_object_tombstone_for_testing(&mut self, obj_ref: ObjectRef); +} + +#[derive(Clone)] +pub struct ObjectChange { + pub id: ObjectID, + pub input_version: Option, + pub input_digest: Option, + pub output_version: Option, + pub output_digest: Option, + pub id_operation: IDOperation, +} + +#[derive(Eq, PartialEq, Copy, Clone, Debug, Serialize, Deserialize)] +pub enum IDOperation { + None, + Created, + Deleted, +} + +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Default)] +pub struct TransactionEvents { + pub data: Vec, +} + +impl TransactionEvents { + pub fn digest(&self) -> TransactionEventsDigest { + TransactionEventsDigest::new(default_hash(self)) + } +} + +#[derive(Debug)] +pub struct TransactionEffectsDebugSummary { + /// Size of bcs serialized byets of the effects. + pub bcs_size: usize, + pub status: ExecutionStatus, + pub gas_used: GasCostSummary, + pub transaction_digest: TransactionDigest, + pub created_object_count: usize, + pub mutated_object_count: usize, + pub unwrapped_object_count: usize, + pub deleted_object_count: usize, + pub wrapped_object_count: usize, + pub dependency_count: usize, + // TODO: Add deleted_and_unwrapped_object_count and event digest. +} + +pub type TransactionEffectsEnvelope = Envelope; +pub type UnsignedTransactionEffects = TransactionEffectsEnvelope; +pub type SignedTransactionEffects = TransactionEffectsEnvelope; +pub type CertifiedTransactionEffects = TransactionEffectsEnvelope; + +pub type TrustedSignedTransactionEffects = TrustedEnvelope; +pub type VerifiedTransactionEffectsEnvelope = VerifiedEnvelope; +pub type VerifiedSignedTransactionEffects = VerifiedTransactionEffectsEnvelope; +pub type VerifiedCertifiedTransactionEffects = + VerifiedTransactionEffectsEnvelope; diff --git a/crates/iota-types/src/effects/object_change.rs b/crates/iota-types/src/effects/object_change.rs new file mode 100644 index 00000000000..91de5063380 --- /dev/null +++ b/crates/iota-types/src/effects/object_change.rs @@ -0,0 +1,79 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use serde::{Deserialize, Serialize}; + +use super::IDOperation; +use crate::{ + base_types::VersionDigest, + digests::ObjectDigest, + object::{Object, Owner}, +}; + +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] +pub struct EffectsObjectChange { + // input_state and output_state are the core fields that's required by + // the protocol as it tells how an object changes on-chain. + /// State of the object in the store prior to this transaction. + pub(crate) input_state: ObjectIn, + /// State of the object in the store after this transaction. + pub(crate) output_state: ObjectOut, + + /// Whether this object ID is created or deleted in this transaction. + /// This information isn't required by the protocol but is useful for + /// providing more detailed semantics on object changes. + pub(crate) id_operation: IDOperation, +} + +impl EffectsObjectChange { + pub fn new( + modified_at: Option<(VersionDigest, Owner)>, + written: Option<&Object>, + id_created: bool, + id_deleted: bool, + ) -> Self { + debug_assert!( + !id_created || !id_deleted, + "Object ID can't be created and deleted at the same time." + ); + Self { + input_state: modified_at.map_or(ObjectIn::NotExist, ObjectIn::Exist), + output_state: written.map_or(ObjectOut::NotExist, |o| { + if o.is_package() { + ObjectOut::PackageWrite((o.version(), o.digest())) + } else { + ObjectOut::ObjectWrite((o.digest(), o.owner)) + } + }), + id_operation: if id_created { + IDOperation::Created + } else if id_deleted { + IDOperation::Deleted + } else { + IDOperation::None + }, + } + } +} + +/// If an object exists (at root-level) in the store prior to this transaction, +/// it should be Exist, otherwise it's NonExist, e.g. wrapped objects should be +/// NonExist. +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] +pub enum ObjectIn { + NotExist, + /// The old version, digest and owner. + Exist((VersionDigest, Owner)), +} + +#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] +pub enum ObjectOut { + /// Same definition as in ObjectIn. + NotExist, + /// Any written object, including all of mutated, created, unwrapped today. + ObjectWrite((ObjectDigest, Owner)), + /// Packages writes need to be tracked separately with version because + /// we don't use lamport version for package publish and upgrades. + PackageWrite(VersionDigest), +} diff --git a/crates/sui-types/src/effects/test_effects_builder.rs b/crates/iota-types/src/effects/test_effects_builder.rs similarity index 99% rename from crates/sui-types/src/effects/test_effects_builder.rs rename to crates/iota-types/src/effects/test_effects_builder.rs index 9b58948e9ad..3982a8ef2fd 100644 --- a/crates/sui-types/src/effects/test_effects_builder.rs +++ b/crates/iota-types/src/effects/test_effects_builder.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeMap; diff --git a/crates/sui-types/src/epoch_data.rs b/crates/iota-types/src/epoch_data.rs similarity index 96% rename from crates/sui-types/src/epoch_data.rs rename to crates/iota-types/src/epoch_data.rs index be0a8f0e28f..bf5f5a11c68 100644 --- a/crates/sui-types/src/epoch_data.rs +++ b/crates/iota-types/src/epoch_data.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use crate::{ diff --git a/crates/iota-types/src/error.rs b/crates/iota-types/src/error.rs new file mode 100644 index 00000000000..fb073704c06 --- /dev/null +++ b/crates/iota-types/src/error.rs @@ -0,0 +1,940 @@ +// Copyright (c) 2021, Facebook, Inc. and its affiliates +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::BTreeMap, fmt::Debug}; + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use strum_macros::{AsRefStr, IntoStaticStr}; +use thiserror::Error; +use tonic::Status; +use typed_store_error::TypedStoreError; + +use crate::{ + base_types::*, + committee::{Committee, EpochId, StakeUnit}, + digests::CheckpointContentsDigest, + execution_status::CommandArgumentError, + messages_checkpoint::CheckpointSequenceNumber, + object::Owner, +}; + +pub const TRANSACTION_NOT_FOUND_MSG_PREFIX: &str = "Could not find the referenced transaction"; +pub const TRANSACTIONS_NOT_FOUND_MSG_PREFIX: &str = "Could not find the referenced transactions"; + +#[macro_export] +macro_rules! fp_bail { + ($e:expr) => { + return Err($e) + }; +} + +#[macro_export(local_inner_macros)] +macro_rules! fp_ensure { + ($cond:expr, $e:expr) => { + if !($cond) { + fp_bail!($e); + } + }; +} +pub(crate) use fp_ensure; + +use crate::{ + digests::TransactionEventsDigest, + execution_status::{CommandIndex, ExecutionFailureStatus}, +}; + +#[macro_export] +macro_rules! exit_main { + ($result:expr) => { + match $result { + Ok(_) => (), + Err(err) => { + let err = format!("{:?}", err); + println!("{}", err.bold().red()); + std::process::exit(1); + } + } + }; +} + +#[macro_export] +macro_rules! make_invariant_violation { + ($($args:expr),* $(,)?) => {{ + if cfg!(debug_assertions) { + panic!($($args),*) + } + ExecutionError::invariant_violation(format!($($args),*)) + }} +} + +#[macro_export] +macro_rules! invariant_violation { + ($($args:expr),* $(,)?) => { + return Err(make_invariant_violation!($($args),*).into()) + }; +} + +#[macro_export] +macro_rules! assert_invariant { + ($cond:expr, $($args:expr),* $(,)?) => {{ + if !$cond { + invariant_violation!($($args),*) + } + }}; +} + +#[derive( + Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Error, Hash, AsRefStr, IntoStaticStr, +)] +pub enum UserInputError { + #[error("Mutable object {object_id} cannot appear more than one in one transaction.")] + MutableObjectUsedMoreThanOnce { object_id: ObjectID }, + #[error("Wrong number of parameters for the transaction.")] + ObjectInputArityViolation, + #[error( + "Could not find the referenced object {:?} at version {:?}.", + object_id, + version + )] + ObjectNotFound { + object_id: ObjectID, + version: Option, + }, + #[error( + "Object {provided_obj_ref:?} is not available for consumption, its current version: {current_version:?}." + )] + ObjectVersionUnavailableForConsumption { + provided_obj_ref: ObjectRef, + current_version: SequenceNumber, + }, + #[error("Package verification failed: {err:?}")] + PackageVerificationTimedout { err: String }, + #[error("Dependent package not found on-chain: {package_id:?}")] + DependentPackageNotFound { package_id: ObjectID }, + #[error("Mutable parameter provided, immutable parameter expected.")] + ImmutableParameterExpectedError { object_id: ObjectID }, + #[error("Size limit exceeded: {limit} is {value}")] + SizeLimitExceeded { limit: String, value: String }, + #[error( + "Object {child_id:?} is owned by object {parent_id:?}. \ + Objects owned by other objects cannot be used as input arguments." + )] + InvalidChildObjectArgument { + child_id: ObjectID, + parent_id: ObjectID, + }, + #[error( + "Invalid Object digest for object {object_id:?}. Expected digest : {expected_digest:?}." + )] + InvalidObjectDigest { + object_id: ObjectID, + expected_digest: ObjectDigest, + }, + #[error("Sequence numbers above the maximal value are not usable for transfers.")] + InvalidSequenceNumber, + #[error("A move object is expected, instead a move package is passed: {object_id}")] + MovePackageAsObject { object_id: ObjectID }, + #[error("A move package is expected, instead a move object is passed: {object_id}")] + MoveObjectAsPackage { object_id: ObjectID }, + #[error("Transaction was not signed by the correct sender: {}", error)] + IncorrectUserSignature { error: String }, + + #[error("Object used as shared is not shared.")] + NotSharedObjectError, + #[error("The transaction inputs contain duplicated ObjectRef's")] + DuplicateObjectRefInput, + + // Gas related errors + #[error("Transaction gas payment missing.")] + MissingGasPayment, + #[error("Gas object is not an owned object with owner: {:?}.", owner)] + GasObjectNotOwnedObject { owner: Owner }, + #[error("Gas budget: {:?} is higher than max: {:?}.", gas_budget, max_budget)] + GasBudgetTooHigh { gas_budget: u64, max_budget: u64 }, + #[error("Gas budget: {:?} is lower than min: {:?}.", gas_budget, min_budget)] + GasBudgetTooLow { gas_budget: u64, min_budget: u64 }, + #[error( + "Balance of gas object {:?} is lower than the needed amount: {:?}.", + gas_balance, + needed_gas_amount + )] + GasBalanceTooLow { + gas_balance: u128, + needed_gas_amount: u128, + }, + #[error("Transaction kind does not support Sponsored Transaction")] + UnsupportedSponsoredTransactionKind, + #[error( + "Gas price {:?} under reference gas price (RGP) {:?}", + gas_price, + reference_gas_price + )] + GasPriceUnderRGP { + gas_price: u64, + reference_gas_price: u64, + }, + #[error("Gas price cannot exceed {:?} micros", max_gas_price)] + GasPriceTooHigh { max_gas_price: u64 }, + #[error("Object {object_id} is not a gas object")] + InvalidGasObject { object_id: ObjectID }, + #[error("Gas object does not have enough balance to cover minimal gas spend")] + InsufficientBalanceToCoverMinimalGas, + + #[error( + "Could not find the referenced object {:?} as the asked version {:?} is higher than the latest {:?}", + object_id, + asked_version, + latest_version + )] + ObjectSequenceNumberTooHigh { + object_id: ObjectID, + asked_version: SequenceNumber, + latest_version: SequenceNumber, + }, + #[error("Object deleted at reference {:?}.", object_ref)] + ObjectDeleted { object_ref: ObjectRef }, + #[error("Invalid Batch Transaction: {}", error)] + InvalidBatchTransaction { error: String }, + #[error("This Move function is currently disabled and not available for call")] + BlockedMoveFunction, + #[error("Empty input coins for Pay related transaction")] + EmptyInputCoins, + + #[error( + "IOTA payment transactions use first input coin for gas payment, but found a different gas object." + )] + UnexpectedGasPaymentObject, + + #[error("Wrong initial version given for shared object")] + SharedObjectStartingVersionMismatch, + + #[error( + "Attempt to transfer object {object_id} that does not have public transfer. Object transfer must be done instead using a distinct Move function call." + )] + TransferObjectWithoutPublicTransferError { object_id: ObjectID }, + + #[error( + "TransferObjects, MergeCoin, and Publish cannot have empty arguments. \ + If MakeMoveVec has empty arguments, it must have a type specified" + )] + EmptyCommandInput, + + #[error("Transaction is denied: {}", error)] + TransactionDenied { error: String }, + + #[error("Feature is not supported: {0}")] + Unsupported(String), + + #[error("Query transactions with move function input error: {0}")] + MoveFunctionInputError(String), + + #[error("Verified checkpoint not found for sequence number: {0}")] + VerifiedCheckpointNotFound(CheckpointSequenceNumber), + + #[error("Verified checkpoint not found for digest: {0}")] + VerifiedCheckpointDigestNotFound(String), + + #[error("Latest checkpoint sequence number not found")] + LatestCheckpointSequenceNumberNotFound, + + #[error("Checkpoint contents not found for digest: {0}")] + CheckpointContentsNotFound(CheckpointContentsDigest), + + #[error("Genesis transaction not found")] + GenesisTransactionNotFound, + + #[error("Transaction {0} not found")] + TransactionCursorNotFound(u64), + + #[error( + "Object {:?} is a system object and cannot be accessed by user transactions.", + object_id + )] + InaccessibleSystemObject { object_id: ObjectID }, + #[error( + "{max_publish_commands} max publish/upgrade commands allowed, {publish_count} provided" + )] + MaxPublishCountExceeded { + max_publish_commands: u64, + publish_count: u64, + }, + + #[error("Immutable parameter provided, mutable parameter expected.")] + MutableParameterExpected { object_id: ObjectID }, + + #[error("Address {address:?} is denied for coin {coin_type}")] + AddressDeniedForCoin { + address: IotaAddress, + coin_type: String, + }, + + #[error("Commands following a command with Random can only be TransferObjects or MergeCoins")] + PostRandomCommandRestrictions, +} + +#[derive( + Eq, + PartialEq, + Clone, + Debug, + Serialize, + Deserialize, + Hash, + AsRefStr, + IntoStaticStr, + JsonSchema, + Error, +)] +#[serde(tag = "code", rename = "ObjectResponseError", rename_all = "camelCase")] +pub enum IotaObjectResponseError { + #[error("Object {:?} does not exist.", object_id)] + NotExists { object_id: ObjectID }, + #[error("Cannot find dynamic field for parent object {:?}.", parent_object_id)] + DynamicFieldNotFound { parent_object_id: ObjectID }, + #[error( + "Object has been deleted object_id: {:?} at version: {:?} in digest {:?}", + object_id, + version, + digest + )] + Deleted { + object_id: ObjectID, + /// Object version. + version: SequenceNumber, + /// Base64 string representing the object digest + digest: ObjectDigest, + }, + #[error("Unknown Error.")] + Unknown, + #[error("Display Error: {:?}", error)] + DisplayError { error: String }, + // TODO: also integrate IotaPastObjectResponse (VersionNotFound, VersionTooHigh) +} + +/// Custom error type for Iota. +#[derive( + Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Error, Hash, AsRefStr, IntoStaticStr, +)] +pub enum IotaError { + #[error("Error checking transaction input objects: {:?}", error)] + UserInputError { error: UserInputError }, + + #[error("Error checking transaction object: {:?}", error)] + IotaObjectResponseError { error: IotaObjectResponseError }, + + #[error("Expecting a single owner, shared ownership found")] + UnexpectedOwnerType, + + #[error("There are already {queue_len} transactions pending, above threshold of {threshold}")] + TooManyTransactionsPendingExecution { queue_len: usize, threshold: usize }, + + #[error("There are too many transactions pending in consensus")] + TooManyTransactionsPendingConsensus, + + #[error( + "Input {object_id} already has {queue_len} transactions pending, above threshold of {threshold}" + )] + TooManyTransactionsPendingOnObject { + object_id: ObjectID, + queue_len: usize, + threshold: usize, + }, + + #[error( + "Input {object_id} has a transaction {txn_age_sec} seconds old pending, above threshold of {threshold} seconds" + )] + TooOldTransactionPendingOnObject { + object_id: ObjectID, + txn_age_sec: u64, + threshold: u64, + }, + + // Signature verification + #[error("Signature is not valid: {}", error)] + InvalidSignature { error: String }, + #[error("Required Signature from {expected} is absent {:?}.", actual)] + SignerSignatureAbsent { + expected: String, + actual: Vec, + }, + #[error("Expect {expected} signer signatures but got {actual}.")] + SignerSignatureNumberMismatch { expected: usize, actual: usize }, + #[error("Value was not signed by the correct sender: {}", error)] + IncorrectSigner { error: String }, + #[error( + "Value was not signed by a known authority. signer: {:?}, index: {:?}, committee: {committee}", + signer, + index + )] + UnknownSigner { + signer: Option, + index: Option, + committee: Box, + }, + #[error( + "Validator {:?} responded multiple signatures for the same message, conflicting: {:?}", + signer, + conflicting_sig + )] + StakeAggregatorRepeatedSigner { + signer: AuthorityName, + conflicting_sig: bool, + }, + // TODO: Used for distinguishing between different occurrences of invalid signatures, to allow + // retries in some cases. + #[error( + "Signature is not valid, but a retry may result in a valid one: {}", + error + )] + PotentiallyTemporarilyInvalidSignature { error: String }, + + // Certificate verification and execution + #[error( + "Signature or certificate from wrong epoch, expected {expected_epoch}, got {actual_epoch}" + )] + WrongEpoch { + expected_epoch: EpochId, + actual_epoch: EpochId, + }, + #[error("Signatures in a certificate must form a quorum")] + CertificateRequiresQuorum, + #[error("Transaction certificate processing failed: {err}")] + ErrorWhileProcessingCertificate { err: String }, + #[error( + "Failed to get a quorum of signed effects when processing transaction: {effects_map:?}" + )] + QuorumFailedToGetEffectsQuorumWhenProcessingTransaction { + effects_map: BTreeMap, StakeUnit)>, + }, + #[error( + "Failed to verify Tx certificate with executed effects, error: {error:?}, validator: {validator_name:?}" + )] + FailedToVerifyTxCertWithExecutedEffects { + validator_name: AuthorityName, + error: String, + }, + #[error("Transaction is already finalized but with different user signatures")] + TxAlreadyFinalizedWithDifferentUserSigs, + #[error("System Transaction not accepted")] + InvalidSystemTransaction, + + // Account access + #[error("Invalid authenticator")] + InvalidAuthenticator, + #[error("Invalid address")] + InvalidAddress, + #[error("Invalid transaction digest.")] + InvalidTransactionDigest, + + #[error("Invalid digest length. Expected {expected}, got {actual}")] + InvalidDigestLength { expected: usize, actual: usize }, + + #[error("Unexpected message.")] + UnexpectedMessage, + + // Move module publishing related errors + #[error("Failed to verify the Move module, reason: {error:?}.")] + ModuleVerificationFailure { error: String }, + #[error("Failed to deserialize the Move module, reason: {error:?}.")] + ModuleDeserializationFailure { error: String }, + #[error("Failed to publish the Move module(s), reason: {error}")] + ModulePublishFailure { error: String }, + #[error("Failed to build Move modules: {error}.")] + ModuleBuildFailure { error: String }, + + // Move call related errors + #[error("Function resolution failure: {error:?}.")] + FunctionNotFound { error: String }, + #[error("Module not found in package: {module_name:?}.")] + ModuleNotFound { module_name: String }, + #[error("Type error while binding function arguments: {error:?}.")] + TypeError { error: String }, + #[error("Circular object ownership detected")] + CircularObjectOwnership, + + // Internal state errors + #[error("Attempt to re-initialize a transaction lock for objects {:?}.", refs)] + ObjectLockAlreadyInitialized { refs: Vec }, + #[error( + "Object {obj_ref:?} already locked by a different transaction: {pending_transaction:?}" + )] + ObjectLockConflict { + obj_ref: ObjectRef, + pending_transaction: TransactionDigest, + }, + #[error( + "Objects {obj_refs:?} are already locked by a transaction from a future epoch {locked_epoch:?}), attempt to override with a transaction from epoch {new_epoch:?}" + )] + ObjectLockedAtFutureEpoch { + obj_refs: Vec, + locked_epoch: EpochId, + new_epoch: EpochId, + locked_by_tx: TransactionDigest, + }, + #[error("{TRANSACTION_NOT_FOUND_MSG_PREFIX} [{:?}].", digest)] + TransactionNotFound { digest: TransactionDigest }, + #[error("{TRANSACTIONS_NOT_FOUND_MSG_PREFIX} [{:?}].", digests)] + TransactionsNotFound { digests: Vec }, + #[error("Could not find the referenced transaction events [{digest:?}].")] + TransactionEventsNotFound { digest: TransactionEventsDigest }, + #[error( + "Attempt to move to `Executed` state an transaction that has already been executed: {:?}.", + digest + )] + TransactionAlreadyExecuted { digest: TransactionDigest }, + #[error("Object ID did not have the expected type")] + BadObjectType { error: String }, + #[error("Fail to retrieve Object layout for {st}")] + FailObjectLayout { st: String }, + + #[error("Execution invariant violated")] + ExecutionInvariantViolation, + #[error("Validator {authority:?} is faulty in a Byzantine manner: {reason:?}")] + ByzantineAuthoritySuspicion { + authority: AuthorityName, + reason: String, + }, + #[allow(non_camel_case_types)] + #[serde(rename = "StorageError")] + #[error("DEPRECATED")] + DEPRECATED_StorageError, + #[allow(non_camel_case_types)] + #[serde(rename = "GenericStorageError")] + #[error("DEPRECATED")] + DEPRECATED_GenericStorageError, + #[error( + "Attempted to access {object} through parent {given_parent}, \ + but it's actual parent is {actual_owner}" + )] + InvalidChildObjectAccess { + object: ObjectID, + given_parent: ObjectID, + actual_owner: Owner, + }, + + #[allow(non_camel_case_types)] + #[serde(rename = "StorageMissingFieldError")] + #[error("DEPRECATED")] + DEPRECATED_StorageMissingFieldError, + #[allow(non_camel_case_types)] + #[serde(rename = "StorageCorruptedFieldError")] + #[error("DEPRECATED")] + DEPRECATED_StorageCorruptedFieldError, + + #[error("Authority Error: {error:?}")] + GenericAuthorityError { error: String }, + + #[error("Failed to dispatch subscription: {error:?}")] + FailedToDispatchSubscription { error: String }, + + #[error("Failed to serialize Owner: {error:?}")] + OwnerFailedToSerialize { error: String }, + + #[error("Failed to deserialize fields into JSON: {error:?}")] + ExtraFieldFailedToDeserialize { error: String }, + + #[error("Failed to execute transaction locally by Orchestrator: {error:?}")] + TransactionOrchestratorLocalExecutionError { error: String }, + + // Errors returned by authority and client read API's + #[error("Failure serializing transaction in the requested format: {:?}", error)] + TransactionSerializationError { error: String }, + #[error("Failure serializing object in the requested format: {:?}", error)] + ObjectSerializationError { error: String }, + #[error("Failure deserializing object in the requested format: {:?}", error)] + ObjectDeserializationError { error: String }, + #[error("Event store component is not active on this node")] + NoEventStore, + + // Client side error + #[error("Too many authority errors were detected for {}: {:?}", action, errors)] + TooManyIncorrectAuthorities { + errors: Vec<(AuthorityName, IotaError)>, + action: String, + }, + #[error("Invalid transaction range query to the fullnode: {:?}", error)] + FullNodeInvalidTxRangeQuery { error: String }, + + // Errors related to the authority-consensus interface. + #[error("Failed to submit transaction to consensus: {0}")] + FailedToSubmitToConsensus(String), + #[error("Failed to connect with consensus node: {0}")] + ConsensusConnectionBroken(String), + #[error("Failed to execute handle_consensus_transaction on Iota: {0}")] + HandleConsensusTransactionFailure(String), + + // Cryptography errors. + #[error("Signature key generation error: {0}")] + SignatureKeyGenError(String), + #[error("Key Conversion Error: {0}")] + KeyConversionError(String), + #[error("Invalid Private Key provided")] + InvalidPrivateKey, + + // Unsupported Operations on Fullnode + #[error("Fullnode does not support handle_certificate")] + FullNodeCantHandleCertificate, + + // Epoch related errors. + #[error("Validator temporarily stopped processing transactions due to epoch change")] + ValidatorHaltedAtEpochEnd, + #[error("Validator has stopped operations for this epoch")] + EpochEnded, + #[error("Error when advancing epoch: {:?}", error)] + AdvanceEpochError { error: String }, + + #[error("Transaction Expired")] + TransactionExpired, + + // These are errors that occur when an RPC fails and is simply the utf8 message sent in a + // Tonic::Status + #[error("{1} - {0}")] + RpcError(String, String), + + #[error("Use of disabled feature: {:?}", error)] + UnsupportedFeatureError { error: String }, + + #[error("Unable to communicate with the Quorum Driver channel: {:?}", error)] + QuorumDriverCommunicationError { error: String }, + + #[error("Operation timed out")] + TimeoutError, + + #[error("Error executing {0}")] + ExecutionError(String), + + #[error("Invalid committee composition")] + InvalidCommittee(String), + + #[error("Missing committee information for epoch {0}")] + MissingCommitteeAtEpoch(EpochId), + + #[error("Index store not available on this Fullnode.")] + IndexStoreNotAvailable, + + #[error("Failed to read dynamic field from table in the object store: {0}")] + DynamicFieldReadError(String), + + #[error("Failed to read or deserialize system state related data structures on-chain: {0}")] + IotaSystemStateReadError(String), + + #[error("Unexpected version error: {0}")] + UnexpectedVersion(String), + + #[error("Message version is not supported at the current protocol version: {error}")] + WrongMessageVersion { error: String }, + + #[error("unknown error: {0}")] + Unknown(String), + + #[error("Failed to perform file operation: {0}")] + FileIOError(String), + + #[error("Failed to get JWK")] + JWKRetrievalError, + + #[error("Storage error: {0}")] + Storage(String), + + #[error( + "Validator cannot handle the request at the moment. Please retry after at least {retry_after_secs} seconds." + )] + ValidatorOverloadedRetryAfter { retry_after_secs: u64 }, +} + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +/// Sub-status codes for the `UNKNOWN_VERIFICATION_ERROR` VM Status Code which +/// provides more context TODO: add more Vm Status errors. We use +/// `UNKNOWN_VERIFICATION_ERROR` as a catchall for now. +pub enum VMMVerifierErrorSubStatusCode { + MULTIPLE_RETURN_VALUES_NOT_ALLOWED = 0, + INVALID_OBJECT_CREATION = 1, +} + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +/// Sub-status codes for the `MEMORY_LIMIT_EXCEEDED` VM Status Code which +/// provides more context +pub enum VMMemoryLimitExceededSubStatusCode { + EVENT_COUNT_LIMIT_EXCEEDED = 0, + EVENT_SIZE_LIMIT_EXCEEDED = 1, + NEW_ID_COUNT_LIMIT_EXCEEDED = 2, + DELETED_ID_COUNT_LIMIT_EXCEEDED = 3, + TRANSFER_ID_COUNT_LIMIT_EXCEEDED = 4, + OBJECT_RUNTIME_CACHE_LIMIT_EXCEEDED = 5, + OBJECT_RUNTIME_STORE_LIMIT_EXCEEDED = 6, + TOTAL_EVENT_SIZE_LIMIT_EXCEEDED = 7, +} + +pub type IotaResult = Result; +pub type UserInputResult = Result; + +impl From for IotaError { + fn from(error: iota_protocol_config::Error) -> Self { + IotaError::WrongMessageVersion { error: error.0 } + } +} + +impl From for IotaError { + fn from(error: ExecutionError) -> Self { + IotaError::ExecutionError(error.to_string()) + } +} + +impl From for IotaError { + fn from(status: Status) -> Self { + let result = bcs::from_bytes::(status.details()); + if let Ok(iota_error) = result { + iota_error + } else { + Self::RpcError( + status.message().to_owned(), + status.code().description().to_owned(), + ) + } + } +} + +impl From for IotaError { + fn from(e: TypedStoreError) -> Self { + Self::Storage(e.to_string()) + } +} + +impl From for IotaError { + fn from(e: crate::storage::error::Error) -> Self { + Self::Storage(e.to_string()) + } +} + +impl From for Status { + fn from(error: IotaError) -> Self { + let bytes = bcs::to_bytes(&error).unwrap(); + Status::with_details(tonic::Code::Internal, error.to_string(), bytes.into()) + } +} + +impl From for IotaError { + fn from(kind: ExecutionErrorKind) -> Self { + ExecutionError::from_kind(kind).into() + } +} + +impl From<&str> for IotaError { + fn from(error: &str) -> Self { + IotaError::GenericAuthorityError { + error: error.to_string(), + } + } +} + +impl TryFrom for UserInputError { + type Error = anyhow::Error; + + fn try_from(err: IotaError) -> Result { + match err { + IotaError::UserInputError { error } => Ok(error), + other => anyhow::bail!("error {:?} is not UserInputError", other), + } + } +} + +impl From for IotaError { + fn from(error: UserInputError) -> Self { + IotaError::UserInputError { error } + } +} + +impl From for IotaError { + fn from(error: IotaObjectResponseError) -> Self { + IotaError::IotaObjectResponseError { error } + } +} + +impl IotaError { + pub fn individual_error_indicates_epoch_change(&self) -> bool { + matches!( + self, + IotaError::ValidatorHaltedAtEpochEnd | IotaError::MissingCommitteeAtEpoch(_) + ) + } + + /// Returns if the error is retryable and if the error's retryability is + /// explicitly categorized. + /// There should be only a handful of retryable errors. For now we list + /// common non-retryable error below to help us find more retryable + /// errors in logs. + pub fn is_retryable(&self) -> (bool, bool) { + let retryable = match self { + // Network error + IotaError::RpcError { .. } => true, + + // Reconfig error + IotaError::ValidatorHaltedAtEpochEnd => true, + IotaError::MissingCommitteeAtEpoch(..) => true, + IotaError::WrongEpoch { .. } => true, + + IotaError::UserInputError { error } => { + match error { + // Only ObjectNotFound and DependentPackageNotFound is potentially retryable + UserInputError::ObjectNotFound { .. } => true, + UserInputError::DependentPackageNotFound { .. } => true, + _ => false, + } + } + + IotaError::PotentiallyTemporarilyInvalidSignature { .. } => true, + + // Overload errors + IotaError::TooManyTransactionsPendingExecution { .. } => true, + IotaError::TooManyTransactionsPendingOnObject { .. } => true, + IotaError::TooOldTransactionPendingOnObject { .. } => true, + IotaError::TooManyTransactionsPendingConsensus => true, + IotaError::ValidatorOverloadedRetryAfter { .. } => true, + + // Non retryable error + IotaError::ExecutionError(..) => false, + IotaError::ByzantineAuthoritySuspicion { .. } => false, + IotaError::QuorumFailedToGetEffectsQuorumWhenProcessingTransaction { .. } => false, + IotaError::TxAlreadyFinalizedWithDifferentUserSigs => false, + IotaError::FailedToVerifyTxCertWithExecutedEffects { .. } => false, + IotaError::ObjectLockConflict { .. } => false, + + // For all un-categorized errors, return here with categorized = false. + _ => return (false, false), + }; + + (retryable, true) + } + + pub fn is_object_or_package_not_found(&self) -> bool { + match self { + IotaError::UserInputError { error } => { + matches!( + error, + UserInputError::ObjectNotFound { .. } + | UserInputError::DependentPackageNotFound { .. } + ) + } + _ => false, + } + } + + pub fn is_overload(&self) -> bool { + matches!( + self, + IotaError::TooManyTransactionsPendingExecution { .. } + | IotaError::TooManyTransactionsPendingOnObject { .. } + | IotaError::TooOldTransactionPendingOnObject { .. } + | IotaError::TooManyTransactionsPendingConsensus + ) + } + + pub fn is_retryable_overload(&self) -> bool { + matches!(self, IotaError::ValidatorOverloadedRetryAfter { .. }) + } +} + +impl Ord for IotaError { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + Ord::cmp(self.as_ref(), other.as_ref()) + } +} + +impl PartialOrd for IotaError { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +type BoxError = Box; + +pub type ExecutionErrorKind = ExecutionFailureStatus; + +#[derive(Debug)] +pub struct ExecutionError { + inner: Box, +} + +#[derive(Debug)] +struct ExecutionErrorInner { + kind: ExecutionErrorKind, + source: Option, + command: Option, +} + +impl ExecutionError { + pub fn new(kind: ExecutionErrorKind, source: Option) -> Self { + Self { + inner: Box::new(ExecutionErrorInner { + kind, + source, + command: None, + }), + } + } + + pub fn new_with_source>(kind: ExecutionErrorKind, source: E) -> Self { + Self::new(kind, Some(source.into())) + } + + pub fn invariant_violation>(source: E) -> Self { + Self::new_with_source(ExecutionFailureStatus::InvariantViolation, source) + } + + pub fn with_command_index(mut self, command: CommandIndex) -> Self { + self.inner.command = Some(command); + self + } + + pub fn from_kind(kind: ExecutionErrorKind) -> Self { + Self::new(kind, None) + } + + pub fn kind(&self) -> &ExecutionErrorKind { + &self.inner.kind + } + + pub fn command(&self) -> Option { + self.inner.command + } + + pub fn source(&self) -> &Option { + &self.inner.source + } + + pub fn to_execution_status(&self) -> (ExecutionFailureStatus, Option) { + (self.kind().clone(), self.command()) + } +} + +impl std::fmt::Display for ExecutionError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "ExecutionError: {:?}", self) + } +} + +impl std::error::Error for ExecutionError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.inner.source.as_ref().map(|e| &**e as _) + } +} + +impl From for ExecutionError { + fn from(kind: ExecutionErrorKind) -> Self { + Self::from_kind(kind) + } +} + +pub fn command_argument_error(e: CommandArgumentError, arg_idx: usize) -> ExecutionError { + ExecutionError::from_kind(ExecutionErrorKind::command_argument_error( + e, + arg_idx as u16, + )) +} diff --git a/crates/iota-types/src/event.rs b/crates/iota-types/src/event.rs new file mode 100755 index 00000000000..58ad0f82c45 --- /dev/null +++ b/crates/iota-types/src/event.rs @@ -0,0 +1,180 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::str::FromStr; + +use anyhow::ensure; +use move_core_types::{ + account_address::AccountAddress, + annotated_value::{MoveStruct, MoveStructLayout}, + ident_str, + identifier::{IdentStr, Identifier}, + language_storage::StructTag, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use serde_with::{serde_as, Bytes}; + +use crate::{ + base_types::{IotaAddress, ObjectID, TransactionDigest}, + error::{IotaError, IotaResult}, + iota_serde::{BigInt, Readable}, + object::bounded_visitor::BoundedVisitor, + IOTA_SYSTEM_ADDRESS, +}; + +/// A universal Iota event type encapsulating different types of events +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EventEnvelope { + /// UTC timestamp in milliseconds since epoch (1/1/1970) + pub timestamp: u64, + /// Transaction digest of associated transaction + pub tx_digest: TransactionDigest, + /// Consecutive per-tx counter assigned to this event. + pub event_num: u64, + /// Specific event type + pub event: Event, + /// Move event's json value + pub parsed_json: Value, +} +/// Unique ID of a Iota Event, the ID is a combination of tx seq number and +/// event seq number, the ID is local to this particular fullnode and will be +/// different from other fullnode. +#[serde_as] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Hash)] +#[serde(rename_all = "camelCase")] +pub struct EventID { + pub tx_digest: TransactionDigest, + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub event_seq: u64, +} + +impl From<(TransactionDigest, u64)> for EventID { + fn from((tx_digest_num, event_seq_number): (TransactionDigest, u64)) -> Self { + Self { + tx_digest: tx_digest_num as TransactionDigest, + event_seq: event_seq_number, + } + } +} + +impl From for String { + fn from(id: EventID) -> Self { + format!("{:?}:{}", id.tx_digest, id.event_seq) + } +} + +impl TryFrom for EventID { + type Error = anyhow::Error; + + fn try_from(value: String) -> Result { + let values = value.split(':').collect::>(); + ensure!(values.len() == 2, "Malformed EventID : {value}"); + Ok(( + TransactionDigest::from_str(values[0])?, + u64::from_str(values[1])?, + ) + .into()) + } +} + +impl EventEnvelope { + pub fn new( + timestamp: u64, + tx_digest: TransactionDigest, + event_num: u64, + event: Event, + move_struct_json_value: Value, + ) -> Self { + Self { + timestamp, + tx_digest, + event_num, + event, + parsed_json: move_struct_json_value, + } + } +} + +/// Specific type of event +#[serde_as] +#[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)] +pub struct Event { + pub package_id: ObjectID, + pub transaction_module: Identifier, + pub sender: IotaAddress, + pub type_: StructTag, + #[serde_as(as = "Bytes")] + pub contents: Vec, +} + +impl Event { + pub fn new( + package_id: &AccountAddress, + module: &IdentStr, + sender: IotaAddress, + type_: StructTag, + contents: Vec, + ) -> Self { + Self { + package_id: ObjectID::from(*package_id), + transaction_module: Identifier::from(module), + sender, + type_, + contents, + } + } + pub fn move_event_to_move_struct( + contents: &[u8], + layout: MoveStructLayout, + ) -> IotaResult { + BoundedVisitor::deserialize_struct(contents, &layout).map_err(|e| { + IotaError::ObjectSerializationError { + error: e.to_string(), + } + }) + } + + pub fn is_system_epoch_info_event(&self) -> bool { + self.type_.address == IOTA_SYSTEM_ADDRESS + && self.type_.module.as_ident_str() == ident_str!("iota_system_state_inner") + && self.type_.name.as_ident_str() == ident_str!("SystemEpochInfoEvent") + } +} + +impl Event { + pub fn random_for_testing() -> Self { + Self { + package_id: ObjectID::random(), + transaction_module: Identifier::new("test").unwrap(), + sender: AccountAddress::random().into(), + type_: StructTag { + address: AccountAddress::random(), + module: Identifier::new("test").unwrap(), + name: Identifier::new("test").unwrap(), + type_params: vec![], + }, + contents: vec![], + } + } +} + +// Event emitted in move code `fun advance_epoch` +#[derive(Deserialize)] +pub struct SystemEpochInfoEvent { + pub epoch: u64, + pub protocol_version: u64, + pub reference_gas_price: u64, + pub total_stake: u64, + pub storage_fund_reinvestment: u64, + pub storage_charge: u64, + pub storage_rebate: u64, + pub storage_fund_balance: u64, + pub stake_subsidy_amount: u64, + pub total_gas_fees: u64, + pub total_stake_rewards_distributed: u64, + pub leftover_storage_fund_inflow: u64, +} diff --git a/crates/sui-types/src/executable_transaction.rs b/crates/iota-types/src/executable_transaction.rs similarity index 98% rename from crates/sui-types/src/executable_transaction.rs rename to crates/iota-types/src/executable_transaction.rs index 345319efe69..350a00d3508 100644 --- a/crates/sui-types/src/executable_transaction.rs +++ b/crates/iota-types/src/executable_transaction.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use serde::{Deserialize, Serialize}; diff --git a/crates/iota-types/src/execution.rs b/crates/iota-types/src/execution.rs new file mode 100644 index 00000000000..a8ab816b9b1 --- /dev/null +++ b/crates/iota-types/src/execution.rs @@ -0,0 +1,490 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::{BTreeMap, BTreeSet, HashSet}; + +use move_binary_format::file_format::AbilitySet; +use move_core_types::{identifier::IdentStr, resolver::ResourceResolver}; +use move_vm_types::loaded_data::runtime_types::Type; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +use crate::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber}, + coin::Coin, + digests::{ObjectDigest, TransactionDigest}, + error::{ExecutionError, ExecutionErrorKind, IotaError}, + event::Event, + execution_status::CommandArgumentError, + is_system_package, + object::{Data, Object, Owner}, + storage::{BackingPackageStore, ChildObjectResolver, ObjectChange, StorageView}, + transfer::Receiving, +}; + +pub trait IotaResolver: ResourceResolver + BackingPackageStore { + fn as_backing_package_store(&self) -> &dyn BackingPackageStore; +} + +/// A type containing all of the information needed to work with a deleted +/// shared object in execution and when committing the execution effects of the +/// transaction. This holds: +/// 0. The object ID of the deleted shared object. +/// 1. The version of the shared object. +/// 2. Whether the object appeared as mutable (or owned) in the transaction, or +/// as a read-only shared object. +/// 3. The transaction digest of the previous transaction that used this shared +/// object mutably or took it by value. +pub type DeletedSharedObjectInfo = (ObjectID, SequenceNumber, bool, TransactionDigest); + +/// A sequence of information about deleted shared objects in the transaction's +/// inputs. +pub type DeletedSharedObjects = Vec; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum SharedInput { + Existing(ObjectRef), + Deleted(DeletedSharedObjectInfo), +} + +impl IotaResolver for T +where + T: ResourceResolver, + T: BackingPackageStore, +{ + fn as_backing_package_store(&self) -> &dyn BackingPackageStore { + self + } +} + +/// Interface with the store necessary to execute a programmable transaction +pub trait ExecutionState: StorageView + IotaResolver { + fn as_iota_resolver(&self) -> &dyn IotaResolver; + fn as_child_resolver(&self) -> &dyn ChildObjectResolver; +} + +impl ExecutionState for T +where + T: StorageView, + T: IotaResolver, +{ + fn as_iota_resolver(&self) -> &dyn IotaResolver { + self + } + + fn as_child_resolver(&self) -> &dyn ChildObjectResolver { + self + } +} + +/// View of the store necessary to produce the layouts of types. +pub trait TypeLayoutStore: BackingPackageStore {} +impl TypeLayoutStore for T where T: BackingPackageStore {} + +#[derive(Debug)] +pub enum ExecutionResults { + V1(ExecutionResultsV1), + V2(ExecutionResultsV2), +} + +#[derive(Debug)] +pub struct ExecutionResultsV1 { + pub object_changes: BTreeMap, + pub user_events: Vec, +} + +/// Used by iota-execution v1 and above, to capture the execution results from +/// Move. The results represent the primitive information that can then be used +/// to construct both transaction effects V1 and V2. +#[derive(Debug, Default)] +pub struct ExecutionResultsV2 { + /// All objects written regardless of whether they were mutated, created, or + /// unwrapped. + pub written_objects: BTreeMap, + /// All objects that existed prior to this transaction, and are modified in + /// this transaction. This includes any type of modification, including + /// mutated, wrapped and deleted objects. + pub modified_objects: BTreeSet, + /// All object IDs created in this transaction. + pub created_object_ids: BTreeSet, + /// All object IDs deleted in this transaction. + /// No object ID should be in both created_object_ids and + /// deleted_object_ids. + pub deleted_object_ids: BTreeSet, + /// All Move events emitted in this transaction. + pub user_events: Vec, +} + +impl ExecutionResultsV2 { + pub fn drop_writes(&mut self) { + self.written_objects.clear(); + self.modified_objects.clear(); + self.created_object_ids.clear(); + self.deleted_object_ids.clear(); + self.user_events.clear(); + } + + pub fn merge_results(&mut self, new_results: Self) { + self.written_objects.extend(new_results.written_objects); + self.modified_objects.extend(new_results.modified_objects); + self.created_object_ids + .extend(new_results.created_object_ids); + self.deleted_object_ids + .extend(new_results.deleted_object_ids); + self.user_events.extend(new_results.user_events); + } + + pub fn update_version_and_previous_tx( + &mut self, + lamport_version: SequenceNumber, + prev_tx: TransactionDigest, + ) { + for (id, obj) in self.written_objects.iter_mut() { + // TODO: We can now get rid of the following logic by passing in lamport version + // into the execution layer, and create new objects using the lamport version + // directly. + + // Update the version for the written object. + match &mut obj.data { + Data::Move(obj) => { + // Move objects all get the transaction's lamport timestamp + obj.increment_version_to(lamport_version); + } + + Data::Package(pkg) => { + // Modified packages get their version incremented (this is a special case that + // only applies to system packages). All other packages can only be created, + // and they are left alone. + if self.modified_objects.contains(id) { + debug_assert!(is_system_package(*id)); + pkg.increment_version(); + } + } + } + + // Record the version that the shared object was created at in its owner field. + // Note, this only works because shared objects must be created as + // shared (not created as owned in one transaction and later + // converted to shared in another). + if let Owner::Shared { + initial_shared_version, + } = &mut obj.owner + { + if self.created_object_ids.contains(id) { + assert_eq!( + *initial_shared_version, + SequenceNumber::new(), + "Initial version should be blank before this point for {id:?}", + ); + *initial_shared_version = lamport_version; + } + } + + obj.previous_transaction = prev_tx; + } + } +} + +#[derive(Clone, Debug)] +pub enum InputObjectMetadata { + Receiving { + id: ObjectID, + version: SequenceNumber, + }, + InputObject { + id: ObjectID, + is_mutable_input: bool, + owner: Owner, + version: SequenceNumber, + }, +} + +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub struct DynamicallyLoadedObjectMetadata { + pub version: SequenceNumber, + pub digest: ObjectDigest, + pub owner: Owner, + pub storage_rebate: u64, + pub previous_transaction: TransactionDigest, +} + +#[derive(Clone, Debug)] +pub struct InputValue { + /// Used to remember the object ID and owner even if the value is taken + pub object_metadata: Option, + pub inner: ResultValue, +} + +#[derive(Clone, Debug)] +pub struct ResultValue { + /// This is used primarily for values that have `copy` but not `drop` as + /// they must have been copied after the last borrow, otherwise we + /// cannot consider the last "copy" to be instead a "move" of the value. + pub last_usage_kind: Option, + pub value: Option, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum UsageKind { + BorrowImm, + BorrowMut, + ByValue, +} + +#[derive(Debug, Clone)] +pub enum Value { + Object(ObjectValue), + Raw(RawValueType, Vec), + Receiving(ObjectID, SequenceNumber, Option), +} + +#[derive(Debug, Clone)] +pub struct ObjectValue { + pub type_: Type, + pub has_public_transfer: bool, + // true if it has been used in a public, non-entry Move call + // In other words, false if all usages have been with non-Move commands or + // entry Move functions + pub used_in_non_entry_move_call: bool, + pub contents: ObjectContents, +} + +#[derive(Debug, Clone)] +pub enum ObjectContents { + Coin(Coin), + Raw(Vec), +} + +#[derive(Debug, Clone)] +pub enum RawValueType { + Any, + Loaded { + ty: Type, + abilities: AbilitySet, + used_in_non_entry_move_call: bool, + }, +} + +#[derive(Clone, Copy)] +pub enum CommandKind<'a> { + MoveCall { + package: ObjectID, + module: &'a IdentStr, + function: &'a IdentStr, + }, + MakeMoveVec, + TransferObjects, + SplitCoins, + MergeCoins, + Publish, + Upgrade, +} + +impl InputObjectMetadata { + pub fn id(&self) -> ObjectID { + match self { + InputObjectMetadata::Receiving { id, .. } => *id, + InputObjectMetadata::InputObject { id, .. } => *id, + } + } + + pub fn version(&self) -> SequenceNumber { + match self { + InputObjectMetadata::Receiving { version, .. } => *version, + InputObjectMetadata::InputObject { version, .. } => *version, + } + } +} + +impl InputValue { + pub fn new_object(object_metadata: InputObjectMetadata, value: ObjectValue) -> Self { + InputValue { + object_metadata: Some(object_metadata), + inner: ResultValue::new(Value::Object(value)), + } + } + + pub fn new_raw(ty: RawValueType, value: Vec) -> Self { + InputValue { + object_metadata: None, + inner: ResultValue::new(Value::Raw(ty, value)), + } + } + + pub fn new_receiving_object(id: ObjectID, version: SequenceNumber) -> Self { + InputValue { + object_metadata: Some(InputObjectMetadata::Receiving { id, version }), + inner: ResultValue::new(Value::Receiving(id, version, None)), + } + } +} + +impl ResultValue { + pub fn new(value: Value) -> Self { + Self { + last_usage_kind: None, + value: Some(value), + } + } +} + +impl Value { + pub fn is_copyable(&self) -> bool { + match self { + Value::Object(_) => false, + Value::Raw(RawValueType::Any, _) => true, + Value::Raw(RawValueType::Loaded { abilities, .. }, _) => abilities.has_copy(), + Value::Receiving(_, _, _) => false, + } + } + + pub fn write_bcs_bytes(&self, buf: &mut Vec) { + match self { + Value::Object(obj_value) => obj_value.write_bcs_bytes(buf), + Value::Raw(_, bytes) => buf.extend(bytes), + Value::Receiving(id, version, _) => { + buf.extend(Receiving::new(*id, *version).to_bcs_bytes()) + } + } + } + + pub fn was_used_in_non_entry_move_call(&self) -> bool { + match self { + Value::Object(obj) => obj.used_in_non_entry_move_call, + // Any is only used for Pure inputs, and if it was used by &mut it would have switched + // to Loaded + Value::Raw(RawValueType::Any, _) => false, + Value::Raw( + RawValueType::Loaded { + used_in_non_entry_move_call, + .. + }, + _, + ) => *used_in_non_entry_move_call, + // Only thing you can do with a `Receiving` is consume it, so once it's used it + // can't be used again. + Value::Receiving(_, _, _) => false, + } + } +} + +impl ObjectValue { + /// # Safety + /// We must have the Type is the coin type, but we are unable to check it at + /// this spot + pub unsafe fn coin(type_: Type, coin: Coin) -> Self { + Self { + type_, + has_public_transfer: true, + used_in_non_entry_move_call: false, + contents: ObjectContents::Coin(coin), + } + } + + pub fn ensure_public_transfer_eligible(&self) -> Result<(), ExecutionError> { + if !self.has_public_transfer { + return Err(ExecutionErrorKind::InvalidTransferObject.into()); + } + Ok(()) + } + + pub fn write_bcs_bytes(&self, buf: &mut Vec) { + match &self.contents { + ObjectContents::Raw(bytes) => buf.extend(bytes), + ObjectContents::Coin(coin) => buf.extend(coin.to_bcs_bytes()), + } + } +} + +pub trait TryFromValue: Sized { + fn try_from_value(value: Value) -> Result; +} + +impl TryFromValue for Value { + fn try_from_value(value: Value) -> Result { + Ok(value) + } +} + +impl TryFromValue for ObjectValue { + fn try_from_value(value: Value) -> Result { + match value { + Value::Object(o) => Ok(o), + Value::Raw(RawValueType::Any, _) => Err(CommandArgumentError::TypeMismatch), + Value::Raw(RawValueType::Loaded { .. }, _) => Err(CommandArgumentError::TypeMismatch), + Value::Receiving(_, _, _) => Err(CommandArgumentError::TypeMismatch), + } + } +} + +impl TryFromValue for IotaAddress { + fn try_from_value(value: Value) -> Result { + try_from_value_prim(&value, Type::Address) + } +} + +impl TryFromValue for u64 { + fn try_from_value(value: Value) -> Result { + try_from_value_prim(&value, Type::U64) + } +} + +fn try_from_value_prim<'a, T: Deserialize<'a>>( + value: &'a Value, + expected_ty: Type, +) -> Result { + match value { + Value::Object(_) => Err(CommandArgumentError::TypeMismatch), + Value::Receiving(_, _, _) => Err(CommandArgumentError::TypeMismatch), + Value::Raw(RawValueType::Any, bytes) => { + bcs::from_bytes(bytes).map_err(|_| CommandArgumentError::InvalidBCSBytes) + } + Value::Raw(RawValueType::Loaded { ty, .. }, bytes) => { + if ty != &expected_ty { + return Err(CommandArgumentError::TypeMismatch); + } + bcs::from_bytes(bytes).map_err(|_| CommandArgumentError::InvalidBCSBytes) + } + } +} + +/// If a transaction digest shows up in this list, when executing such +/// transaction, we will always return `ExecutionError::CertificateDenied` +/// without executing it (but still do gas smashing). Because this list is not +/// gated by protocol version, there are a few important criteria for adding a +/// digest to this list: +/// 1. The certificate must be causing all validators to either panic or hang +/// forever deterministically. +/// 2. If we ever ship a fix to make it no longer panic or hang when executing +/// such transaction, +/// we must make sure the transaction is already in this list. Otherwise nodes +/// running the newer version without these transactions in the list will +/// generate forked result. Below is a scenario of when we need to use this +/// list: +/// 1. We detect that a specific transaction is causing all validators to either +/// panic or hang forever deterministically. +/// 2. We push a CertificateDenyConfig to deny such transaction to all +/// validators asap. +/// 3. To make sure that all fullnodes are able to sync to the latest version, +/// we need to add the transaction digest +/// to this list as well asap, and ship this binary to all fullnodes, so that +/// they can sync past this transaction. +/// 4. We then can start fixing the issue, and ship the fix to all nodes. +/// 5. Unfortunately, we can't remove the transaction digest from this list, +/// because if we do so, any future +/// node that sync from genesis will fork on this transaction. We may be able to +/// remove it once we have stable snapshots and the binary has a minimum +/// supported protocol version past the epoch. +pub fn get_denied_certificates() -> &'static HashSet { + static DENIED_CERTIFICATES: Lazy> = Lazy::new(|| HashSet::from([])); + Lazy::force(&DENIED_CERTIFICATES) +} + +pub fn is_certificate_denied( + transaction_digest: &TransactionDigest, + certificate_deny_set: &HashSet, +) -> bool { + certificate_deny_set.contains(transaction_digest) + || get_denied_certificates().contains(transaction_digest) +} diff --git a/crates/sui-types/src/execution_config_utils.rs b/crates/iota-types/src/execution_config_utils.rs similarity index 96% rename from crates/sui-types/src/execution_config_utils.rs rename to crates/iota-types/src/execution_config_utils.rs index 847927c84c9..cf492a49a77 100644 --- a/crates/sui-types/src/execution_config_utils.rs +++ b/crates/iota-types/src/execution_config_utils.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_protocol_config::ProtocolConfig; use move_binary_format::binary_config::{BinaryConfig, TableConfig}; -use sui_protocol_config::ProtocolConfig; /// Build a `BinaryConfig` from a `ProtocolConfig` pub fn to_binary_config(protocol_config: &ProtocolConfig) -> BinaryConfig { diff --git a/crates/sui-types/src/execution_mode.rs b/crates/iota-types/src/execution_mode.rs similarity index 99% rename from crates/sui-types/src/execution_mode.rs rename to crates/iota-types/src/execution_mode.rs index 430c23af334..60fe4142a47 100644 --- a/crates/sui-types/src/execution_mode.rs +++ b/crates/iota-types/src/execution_mode.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use move_core_types::language_storage::TypeTag; diff --git a/crates/sui-types/src/execution_status.rs b/crates/iota-types/src/execution_status.rs similarity index 96% rename from crates/sui-types/src/execution_status.rs rename to crates/iota-types/src/execution_status.rs index c711e6cbc02..1522c0c0ae7 100644 --- a/crates/sui-types/src/execution_status.rs +++ b/crates/iota-types/src/execution_status.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::fmt::{Display, Formatter}; +use iota_macros::EnumVariantOrder; use move_binary_format::file_format::{CodeOffset, TypeParameterIndex}; use move_core_types::language_storage::ModuleId; use serde::{Deserialize, Serialize}; -use sui_macros::EnumVariantOrder; use thiserror::Error; use crate::ObjectID; @@ -32,7 +33,7 @@ pub enum ExecutionFailureStatus { // General transaction errors #[error("Insufficient Gas.")] InsufficientGas, - #[error("Invalid Gas Object. Possibly not address-owned or possibly not a SUI coin.")] + #[error("Invalid Gas Object. Possibly not address-owned or possibly not a IOTA coin.")] InvalidGasObject, #[error("INVARIANT VIOLATION.")] InvariantViolation, @@ -71,10 +72,10 @@ pub enum ExecutionFailureStatus { PublishErrorNonZeroAddress, #[error( - "Sui Move Bytecode Verification Error. \ - Please run the Sui Move Verifier for more information." + "Iota Move Bytecode Verification Error. \ + Please run the Iota Move Verifier for more information." )] - SuiMoveVerificationError, + IotaMoveVerificationError, // Errors from the Move VM // @@ -170,10 +171,10 @@ pub enum ExecutionFailureStatus { CertificateDenied, #[error( - "Sui Move Bytecode Verification Timeout. \ - Please run the Sui Move Verifier for more information." + "Iota Move Bytecode Verification Timeout. \ + Please run the Iota Move Verifier for more information." )] - SuiMoveVerificationTimedout, + IotaMoveVerificationTimedout, #[error("The shared object operation is not allowed.")] SharedObjectOperationNotAllowed, diff --git a/crates/sui-types/src/full_checkpoint_content.rs b/crates/iota-types/src/full_checkpoint_content.rs similarity index 97% rename from crates/sui-types/src/full_checkpoint_content.rs rename to crates/iota-types/src/full_checkpoint_content.rs index b05db41619c..7e721339e0f 100644 --- a/crates/sui-types/src/full_checkpoint_content.rs +++ b/crates/iota-types/src/full_checkpoint_content.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use serde::{Deserialize, Serialize}; diff --git a/crates/iota-types/src/gas.rs b/crates/iota-types/src/gas.rs new file mode 100644 index 00000000000..f551c3370b1 --- /dev/null +++ b/crates/iota-types/src/gas.rs @@ -0,0 +1,290 @@ +// Copyright (c) 2021, Facebook, Inc. and its affiliates +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub use checked::*; + +#[iota_macros::with_checked_arithmetic] +pub mod checked { + + use enum_dispatch::enum_dispatch; + use iota_protocol_config::ProtocolConfig; + use itertools::MultiUnzip; + use schemars::JsonSchema; + use serde::{Deserialize, Serialize}; + use serde_with::serde_as; + + use crate::{ + effects::{TransactionEffects, TransactionEffectsAPI}, + error::{ExecutionError, IotaResult, UserInputError, UserInputResult}, + gas_model::{ + gas_predicates::gas_price_too_high, gas_v2::IotaGasStatus as IotaGasStatusV2, + tables::GasStatus, + }, + iota_serde::{BigInt, Readable}, + object::Object, + transaction::ObjectReadResult, + ObjectID, + }; + + #[enum_dispatch] + pub trait IotaGasStatusAPI { + fn is_unmetered(&self) -> bool; + fn move_gas_status(&self) -> &GasStatus; + fn move_gas_status_mut(&mut self) -> &mut GasStatus; + fn bucketize_computation(&mut self) -> Result<(), ExecutionError>; + fn summary(&self) -> GasCostSummary; + fn gas_budget(&self) -> u64; + fn storage_gas_units(&self) -> u64; + fn storage_rebate(&self) -> u64; + fn unmetered_storage_rebate(&self) -> u64; + fn gas_used(&self) -> u64; + fn reset_storage_cost_and_rebate(&mut self); + fn charge_storage_read(&mut self, size: usize) -> Result<(), ExecutionError>; + fn charge_publish_package(&mut self, size: usize) -> Result<(), ExecutionError>; + fn track_storage_mutation( + &mut self, + object_id: ObjectID, + new_size: usize, + storage_rebate: u64, + ) -> u64; + fn charge_storage_and_rebate(&mut self) -> Result<(), ExecutionError>; + fn adjust_computation_on_out_of_gas(&mut self); + } + + /// Version aware enum for gas status. + #[enum_dispatch(IotaGasStatusAPI)] + #[derive(Debug)] + pub enum IotaGasStatus { + // V1 does not exists any longer as it was a pre mainnet version. + // So we start the enum from V2 + V2(IotaGasStatusV2), + } + + impl IotaGasStatus { + pub fn new( + gas_budget: u64, + gas_price: u64, + reference_gas_price: u64, + config: &ProtocolConfig, + ) -> IotaResult { + // Common checks. We may pull them into version specific status as needed, but + // they are unlikely to change. + + // gas price must be bigger or equal to reference gas price + if gas_price < reference_gas_price { + return Err(UserInputError::GasPriceUnderRGP { + gas_price, + reference_gas_price, + } + .into()); + } + if gas_price_too_high(config.gas_model_version()) && gas_price >= config.max_gas_price() + { + return Err(UserInputError::GasPriceTooHigh { + max_gas_price: config.max_gas_price(), + } + .into()); + } + + Ok(Self::V2(IotaGasStatusV2::new_with_budget( + gas_budget, + gas_price, + reference_gas_price, + config, + ))) + } + + pub fn new_unmetered() -> Self { + Self::V2(IotaGasStatusV2::new_unmetered()) + } + + // This is the only public API on IotaGasStatus, all other gas related + // operations should go through `GasCharger` + pub fn check_gas_balance( + &self, + gas_objs: &[&ObjectReadResult], + gas_budget: u64, + ) -> UserInputResult { + match self { + Self::V2(status) => status.check_gas_balance(gas_objs, gas_budget), + } + } + } + + /// Summary of the charges in a transaction. + /// Storage is charged independently of computation. + /// There are 3 parts to the storage charges: + /// `storage_cost`: it is the charge of storage at the time the transaction + /// is executed. The cost of storage is the number of + /// bytes of the objects being mutated multiplied by a + /// variable storage cost per byte `storage_rebate`: this is the amount + /// a user gets back when manipulating an object. The + /// `storage_rebate` is the `storage_cost` for an object minus fees. + /// `non_refundable_storage_fee`: not all the value of the object storage + /// cost is given back to user and there + /// is a small fraction that is kept by + /// the system. This value tracks that charge. + /// + /// When looking at a gas cost summary the amount charged to the user is + /// `computation_cost + storage_cost - storage_rebate` + /// and that is the amount that is deducted from the gas coins. + /// `non_refundable_storage_fee` is collected from the objects being + /// mutated/deleted and it is tracked by the system in storage funds. + /// + /// Objects deleted, including the older versions of objects mutated, have + /// the storage field on the objects added up to a pool of "potential + /// rebate". This rebate then is reduced by the "nonrefundable rate" + /// such that: `potential_rebate(storage cost of deleted/mutated + /// objects) = storage_rebate + non_refundable_storage_fee` + + #[serde_as] + #[derive(Eq, PartialEq, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] + #[serde(rename_all = "camelCase")] + pub struct GasCostSummary { + /// Cost of computation/execution + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub computation_cost: u64, + /// Storage cost, it's the sum of all storage cost for all objects + /// created or mutated. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub storage_cost: u64, + /// The amount of storage cost refunded to the user for all objects + /// deleted or mutated in the transaction. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub storage_rebate: u64, + /// The fee for the rebate. The portion of the storage rebate kept by + /// the system. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub non_refundable_storage_fee: u64, + } + + impl GasCostSummary { + pub fn new( + computation_cost: u64, + storage_cost: u64, + storage_rebate: u64, + non_refundable_storage_fee: u64, + ) -> GasCostSummary { + GasCostSummary { + computation_cost, + storage_cost, + storage_rebate, + non_refundable_storage_fee, + } + } + + pub fn gas_used(&self) -> u64 { + self.computation_cost + self.storage_cost + } + + /// Portion of the storage rebate that gets passed on to the transaction + /// sender. The remainder will be burned, then re-minted + added + /// to the storage fund at the next epoch change + pub fn sender_rebate(&self, storage_rebate_rate: u64) -> u64 { + // we round storage rebate such that `>= x.5` goes to x+1 (rounds up) and + // `< x.5` goes to x (truncates). We replicate `f32/64::round()` + const BASIS_POINTS: u128 = 10000; + (((self.storage_rebate as u128 * storage_rebate_rate as u128) + + (BASIS_POINTS / 2)) // integer rounding adds half of the BASIS_POINTS (denominator) + / BASIS_POINTS) as u64 + } + + /// Get net gas usage, positive number means used gas; negative number + /// means refund. + pub fn net_gas_usage(&self) -> i64 { + self.gas_used() as i64 - self.storage_rebate as i64 + } + + pub fn new_from_txn_effects<'a>( + transactions: impl Iterator, + ) -> GasCostSummary { + let (storage_costs, computation_costs, storage_rebates, non_refundable_storage_fee): ( + Vec, + Vec, + Vec, + Vec, + ) = transactions + .map(|e| { + ( + e.gas_cost_summary().storage_cost, + e.gas_cost_summary().computation_cost, + e.gas_cost_summary().storage_rebate, + e.gas_cost_summary().non_refundable_storage_fee, + ) + }) + .multiunzip(); + + GasCostSummary { + storage_cost: storage_costs.iter().sum(), + computation_cost: computation_costs.iter().sum(), + storage_rebate: storage_rebates.iter().sum(), + non_refundable_storage_fee: non_refundable_storage_fee.iter().sum(), + } + } + } + + impl std::fmt::Display for GasCostSummary { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "computation_cost: {}, storage_cost: {}, storage_rebate: {}, non_refundable_storage_fee: {}", + self.computation_cost, + self.storage_cost, + self.storage_rebate, + self.non_refundable_storage_fee, + ) + } + } + + impl std::ops::AddAssign<&Self> for GasCostSummary { + fn add_assign(&mut self, other: &Self) { + self.computation_cost += other.computation_cost; + self.storage_cost += other.storage_cost; + self.storage_rebate += other.storage_rebate; + self.non_refundable_storage_fee += other.non_refundable_storage_fee; + } + } + + impl std::ops::AddAssign for GasCostSummary { + fn add_assign(&mut self, other: Self) { + self.add_assign(&other) + } + } + + // Helper functions to deal with gas coins operations. + // + + pub fn deduct_gas(gas_object: &mut Object, charge_or_rebate: i64) { + // The object must be a gas coin as we have checked in transaction handle phase. + let gas_coin = gas_object.data.try_as_move_mut().unwrap(); + let balance = gas_coin.get_coin_value_unsafe(); + let new_balance = if charge_or_rebate < 0 { + balance + (-charge_or_rebate as u64) + } else { + assert!(balance >= charge_or_rebate as u64); + balance - charge_or_rebate as u64 + }; + gas_coin.set_coin_value_unsafe(new_balance) + } + + pub fn get_gas_balance(gas_object: &Object) -> UserInputResult { + if let Some(move_obj) = gas_object.data.try_as_move() { + if !move_obj.type_().is_gas_coin() { + return Err(UserInputError::InvalidGasObject { + object_id: gas_object.id(), + }); + } + Ok(move_obj.get_coin_value_unsafe()) + } else { + Err(UserInputError::InvalidGasObject { + object_id: gas_object.id(), + }) + } + } +} diff --git a/crates/sui-types/src/gas_coin.rs b/crates/iota-types/src/gas_coin.rs similarity index 85% rename from crates/sui-types/src/gas_coin.rs rename to crates/iota-types/src/gas_coin.rs index d36b6373d31..a3a103822b2 100644 --- a/crates/sui-types/src/gas_coin.rs +++ b/crates/iota-types/src/gas_coin.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -21,26 +22,26 @@ use crate::{ error::{ExecutionError, ExecutionErrorKind}, id::UID, object::{Data, MoveObject, Object}, - SUI_FRAMEWORK_ADDRESS, + IOTA_FRAMEWORK_ADDRESS, }; -/// The number of Mist per Sui token -pub const MIST_PER_SUI: u64 = 1_000_000_000; +/// The number of Micros per Iota token +pub const MICROS_PER_IOTA: u64 = 1_000_000_000; -/// Total supply denominated in Sui -pub const TOTAL_SUPPLY_SUI: u64 = 10_000_000_000; +/// Total supply denominated in Iota +pub const TOTAL_SUPPLY_IOTA: u64 = 10_000_000_000; // Note: cannot use checked arithmetic here since `const unwrap` is still // unstable. -/// Total supply denominated in Mist -pub const TOTAL_SUPPLY_MIST: u64 = TOTAL_SUPPLY_SUI * MIST_PER_SUI; +/// Total supply denominated in Micros +pub const TOTAL_SUPPLY_MICROS: u64 = TOTAL_SUPPLY_IOTA * MICROS_PER_IOTA; -pub const GAS_MODULE_NAME: &IdentStr = ident_str!("sui"); -pub const GAS_STRUCT_NAME: &IdentStr = ident_str!("SUI"); +pub const GAS_MODULE_NAME: &IdentStr = ident_str!("iota"); +pub const GAS_STRUCT_NAME: &IdentStr = ident_str!("IOTA"); pub use checked::*; -#[sui_macros::with_checked_arithmetic] +#[iota_macros::with_checked_arithmetic] mod checked { use super::*; @@ -48,7 +49,7 @@ mod checked { impl GAS { pub fn type_() -> StructTag { StructTag { - address: SUI_FRAMEWORK_ADDRESS, + address: IOTA_FRAMEWORK_ADDRESS, name: GAS_STRUCT_NAME.to_owned(), module: GAS_MODULE_NAME.to_owned(), type_params: Vec::new(), @@ -71,7 +72,7 @@ mod checked { } } - /// Rust version of the Move sui::coin::Coin type + /// Rust version of the Move iota::coin::Coin type #[derive(Clone, Debug, Serialize, Deserialize)] pub struct GasCoin(pub Coin); @@ -89,13 +90,13 @@ mod checked { } /// Return `true` if `s` is the type of a gas coin (i.e., - /// 0x2::coin::Coin<0x2::sui::SUI>) + /// 0x2::coin::Coin<0x2::iota::IOTA>) pub fn is_gas_coin(s: &StructTag) -> bool { Coin::is_coin(s) && s.type_params.len() == 1 && GAS::is_gas_type(&s.type_params[0]) } /// Return `true` if `s` is the type of a gas balance (i.e., - /// 0x2::balance::Balance<0x2::sui::SUI>) + /// 0x2::balance::Balance<0x2::iota::IOTA>) pub fn is_gas_balance(s: &StructTag) -> bool { Balance::is_balance(s) && s.type_params.len() == 1 diff --git a/crates/sui-types/src/gas_model/gas_predicates.rs b/crates/iota-types/src/gas_model/gas_predicates.rs similarity index 95% rename from crates/sui-types/src/gas_model/gas_predicates.rs rename to crates/iota-types/src/gas_model/gas_predicates.rs index ad8f6e17e73..c7e431ec22b 100644 --- a/crates/sui-types/src/gas_model/gas_predicates.rs +++ b/crates/iota-types/src/gas_model/gas_predicates.rs @@ -1,11 +1,12 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Predicates and utility functions based on gas versions. // -use sui_protocol_config::ProtocolConfig; +use iota_protocol_config::ProtocolConfig; use crate::gas_model::{ tables::{ diff --git a/crates/sui-types/src/gas_model/gas_v2.rs b/crates/iota-types/src/gas_model/gas_v2.rs similarity index 95% rename from crates/sui-types/src/gas_model/gas_v2.rs rename to crates/iota-types/src/gas_model/gas_v2.rs index cd84ac649c5..091a0b101f9 100644 --- a/crates/sui-types/src/gas_model/gas_v2.rs +++ b/crates/iota-types/src/gas_model/gas_v2.rs @@ -1,17 +1,18 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 pub use checked::*; -#[sui_macros::with_checked_arithmetic] +#[iota_macros::with_checked_arithmetic] mod checked { + use iota_protocol_config::*; use move_core_types::vm_status::StatusCode; - use sui_protocol_config::*; use crate::{ error::{ExecutionError, ExecutionErrorKind, UserInputError, UserInputResult}, - gas::{self, GasCostSummary, SuiGasStatusAPI}, + gas::{self, GasCostSummary, IotaGasStatusAPI}, gas_model::{ gas_predicates::{cost_table_for_version, txn_base_cost_as_multiplier}, tables::{GasStatus, ZERO_COST_SCHEDULE}, @@ -83,8 +84,8 @@ mod checked { / BASIS_POINTS) as u64 } - /// A list of constant costs of various operations in Sui. - pub struct SuiCostTable { + /// A list of constant costs of various operations in Iota. + pub struct IotaCostTable { /// A flat fee charged for every transaction. This is also the minimum /// amount of gas charged for a transaction. pub(crate) min_transaction_cost: u64, @@ -110,14 +111,14 @@ mod checked { computation_bucket: Vec, } - impl std::fmt::Debug for SuiCostTable { + impl std::fmt::Debug for IotaCostTable { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // TODO: dump the fields. - write!(f, "SuiCostTable(...)") + write!(f, "IotaCostTable(...)") } } - impl SuiCostTable { + impl IotaCostTable { pub(crate) fn new(c: &ProtocolConfig, gas_price: u64) -> Self { // gas_price here is the Reference Gas Price, however we may decide // to change it to be the price passed in the transaction @@ -160,9 +161,9 @@ mod checked { /// It has been multiplied by the storage gas price. This is the new /// storage rebate. pub storage_cost: u64, - /// storage_rebate is the storage rebate (in Sui) for in this object. + /// storage_rebate is the storage rebate (in Iota) for in this object. /// This is computed at the end of execution while determining storage - /// charges. The value is in Sui. + /// charges. The value is in Iota. pub storage_rebate: u64, /// The object size post-transaction in bytes pub new_size: u64, @@ -170,11 +171,11 @@ mod checked { #[allow(dead_code)] #[derive(Debug)] - pub struct SuiGasStatus { + pub struct IotaGasStatus { // GasStatus as used by the VM, that is all the VM sees pub gas_status: GasStatus, // Cost table contains a set of constant/config for the gas model/charging - cost_table: SuiCostTable, + cost_table: IotaCostTable, // Gas budget for this gas status instance. // Typically the gas budget as defined in the `TransactionData::GasData` gas_budget: u64, @@ -215,7 +216,7 @@ mod checked { gas_rounding_step: Option, } - impl SuiGasStatus { + impl IotaGasStatus { fn new( move_gas_status: GasStatus, gas_budget: u64, @@ -225,10 +226,10 @@ mod checked { storage_gas_price: u64, rebate_rate: u64, gas_rounding_step: Option, - cost_table: SuiCostTable, - ) -> SuiGasStatus { + cost_table: IotaCostTable, + ) -> IotaGasStatus { let gas_rounding_step = gas_rounding_step.map(|val| val.max(1)); - SuiGasStatus { + IotaGasStatus { gas_status: move_gas_status, gas_budget, charge, @@ -249,7 +250,7 @@ mod checked { gas_price: u64, reference_gas_price: u64, config: &ProtocolConfig, - ) -> SuiGasStatus { + ) -> IotaGasStatus { let storage_gas_price = config.storage_gas_price(); let max_computation_budget = config.max_gas_computation_bucket() * gas_price; let computation_budget = if gas_budget > max_computation_budget { @@ -257,11 +258,11 @@ mod checked { } else { gas_budget }; - let sui_cost_table = SuiCostTable::new(config, gas_price); + let iota_cost_table = IotaCostTable::new(config, gas_price); let gas_rounding_step = config.gas_rounding_step_as_option(); Self::new( GasStatus::new( - sui_cost_table.execution_cost_table.clone(), + iota_cost_table.execution_cost_table.clone(), computation_budget, gas_price, config.gas_model_version(), @@ -273,11 +274,11 @@ mod checked { storage_gas_price, config.storage_rebate_rate(), gas_rounding_step, - sui_cost_table, + iota_cost_table, ) } - pub fn new_unmetered() -> SuiGasStatus { + pub fn new_unmetered() -> IotaGasStatus { Self::new( GasStatus::new_unmetered(), 0, @@ -287,7 +288,7 @@ mod checked { 0, 0, None, - SuiCostTable::unmetered(), + IotaCostTable::unmetered(), ) } @@ -361,7 +362,7 @@ mod checked { } } - impl SuiGasStatusAPI for SuiGasStatus { + impl IotaGasStatusAPI for IotaGasStatus { fn is_unmetered(&self) -> bool { !self.charge } diff --git a/crates/iota-types/src/gas_model/mod.rs b/crates/iota-types/src/gas_model/mod.rs new file mode 100644 index 00000000000..8e61cdcbc3a --- /dev/null +++ b/crates/iota-types/src/gas_model/mod.rs @@ -0,0 +1,8 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod gas_predicates; +pub mod gas_v2; +pub mod tables; +pub mod units_types; diff --git a/crates/iota-types/src/gas_model/tables.rs b/crates/iota-types/src/gas_model/tables.rs new file mode 100644 index 00000000000..be168c36625 --- /dev/null +++ b/crates/iota-types/src/gas_model/tables.rs @@ -0,0 +1,938 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use move_binary_format::errors::{PartialVMError, PartialVMResult}; +use move_core_types::{ + gas_algebra::{AbstractMemorySize, InternalGas, NumArgs, NumBytes}, + language_storage::ModuleId, + vm_status::StatusCode, +}; +use move_vm_profiler::GasProfiler; +use move_vm_types::{ + gas::{GasMeter, SimpleInstruction}, + loaded_data::runtime_types::Type, + views::{TypeView, ValueView}, +}; +use once_cell::sync::Lazy; + +use super::gas_predicates::{charge_input_as_memory, use_legacy_abstract_size}; +use crate::gas_model::units_types::{CostTable, Gas, GasCost}; + +/// VM flat fee +pub const VM_FLAT_FEE: Gas = Gas::new(8_000); + +/// The size in bytes for a non-string or address constant on the stack +pub const CONST_SIZE: AbstractMemorySize = AbstractMemorySize::new(16); + +/// The size in bytes for a reference on the stack +pub const REFERENCE_SIZE: AbstractMemorySize = AbstractMemorySize::new(8); + +/// The size of a struct in bytes +pub const STRUCT_SIZE: AbstractMemorySize = AbstractMemorySize::new(2); + +/// The size of a vector (without its containing data) in bytes +pub const VEC_SIZE: AbstractMemorySize = AbstractMemorySize::new(8); + +/// For exists checks on data that doesn't exists this is the multiplier that is +/// used. +pub const MIN_EXISTS_DATA_SIZE: AbstractMemorySize = AbstractMemorySize::new(100); + +pub static ZERO_COST_SCHEDULE: Lazy = Lazy::new(zero_cost_schedule); + +pub static INITIAL_COST_SCHEDULE: Lazy = Lazy::new(initial_cost_schedule_v1); + +/// The Move VM implementation of state for gas metering. +/// +/// Initialize with a `CostTable` and the gas provided to the transaction. +/// Provide all the proper guarantees about gas metering in the Move VM. +/// +/// Every client must use an instance of this type to interact with the Move VM. +#[allow(dead_code)] +#[derive(Debug)] +pub struct GasStatus { + pub gas_model_version: u64, + cost_table: CostTable, + gas_left: InternalGas, + gas_price: u64, + initial_budget: InternalGas, + charge: bool, + + // The current height of the operand stack, and the maximal height that it has reached. + stack_height_high_water_mark: u64, + stack_height_current: u64, + stack_height_next_tier_start: Option, + stack_height_current_tier_mult: u64, + + // The current (abstract) size of the operand stack and the maximal size that it has reached. + stack_size_high_water_mark: u64, + stack_size_current: u64, + stack_size_next_tier_start: Option, + stack_size_current_tier_mult: u64, + + // The total number of bytecode instructions that have been executed in the transaction. + instructions_executed: u64, + instructions_next_tier_start: Option, + instructions_current_tier_mult: u64, + + profiler: Option, +} + +impl GasStatus { + /// Initialize the gas state with metering enabled. + /// + /// Charge for every operation and fail when there is no more gas to pay for + /// operations. This is the instantiation that must be used when + /// executing a user script. + + pub fn new(cost_table: CostTable, budget: u64, gas_price: u64, gas_model_version: u64) -> Self { + assert!(gas_price > 0, "gas price cannot be 0"); + let budget_in_unit = budget / gas_price; + let gas_left = Self::to_internal_units(budget_in_unit); + let (stack_height_current_tier_mult, stack_height_next_tier_start) = + cost_table.stack_height_tier(0); + let (stack_size_current_tier_mult, stack_size_next_tier_start) = + cost_table.stack_size_tier(0); + let (instructions_current_tier_mult, instructions_next_tier_start) = + cost_table.instruction_tier(0); + Self { + gas_model_version, + gas_left, + gas_price, + initial_budget: gas_left, + cost_table, + charge: true, + stack_height_high_water_mark: 0, + stack_height_current: 0, + stack_size_high_water_mark: 0, + stack_size_current: 0, + instructions_executed: 0, + stack_height_current_tier_mult, + stack_size_current_tier_mult, + instructions_current_tier_mult, + stack_height_next_tier_start, + stack_size_next_tier_start, + instructions_next_tier_start, + profiler: None, + } + } + + /// Initialize the gas state with metering disabled. + /// + /// It should be used by clients in very specific cases and when executing + /// system code that does not have to charge the user. + pub fn new_unmetered() -> Self { + Self { + gas_model_version: 4, + gas_left: InternalGas::new(0), + gas_price: 1, + initial_budget: InternalGas::new(0), + cost_table: ZERO_COST_SCHEDULE.clone(), + charge: false, + stack_height_high_water_mark: 0, + stack_height_current: 0, + stack_size_high_water_mark: 0, + stack_size_current: 0, + instructions_executed: 0, + stack_height_current_tier_mult: 0, + stack_size_current_tier_mult: 0, + instructions_current_tier_mult: 0, + stack_height_next_tier_start: None, + stack_size_next_tier_start: None, + instructions_next_tier_start: None, + profiler: None, + } + } + + const INTERNAL_UNIT_MULTIPLIER: u64 = 1000; + + fn to_internal_units(val: u64) -> InternalGas { + InternalGas::new(val * Self::INTERNAL_UNIT_MULTIPLIER) + } + + #[allow(dead_code)] + fn to_micros(&self, val: InternalGas) -> u64 { + let gas: Gas = InternalGas::to_unit_round_down(val); + u64::from(gas) * self.gas_price + } + + pub fn push_stack(&mut self, pushes: u64) -> PartialVMResult<()> { + match self.stack_height_current.checked_add(pushes) { + // We should never hit this. + None => return Err(PartialVMError::new(StatusCode::ARITHMETIC_OVERFLOW)), + Some(new_height) => { + if new_height > self.stack_height_high_water_mark { + self.stack_height_high_water_mark = new_height; + } + self.stack_height_current = new_height; + } + } + + if let Some(stack_height_tier_next) = self.stack_height_next_tier_start { + if self.stack_height_current > stack_height_tier_next { + let (next_mul, next_tier) = + self.cost_table.stack_height_tier(self.stack_height_current); + self.stack_height_current_tier_mult = next_mul; + self.stack_height_next_tier_start = next_tier; + } + } + + Ok(()) + } + + pub fn pop_stack(&mut self, pops: u64) { + self.stack_height_current = self.stack_height_current.saturating_sub(pops); + } + + pub fn increase_instruction_count(&mut self, amount: u64) -> PartialVMResult<()> { + match self.instructions_executed.checked_add(amount) { + None => return Err(PartialVMError::new(StatusCode::PC_OVERFLOW)), + Some(new_pc) => { + self.instructions_executed = new_pc; + } + } + + if let Some(instr_tier_next) = self.instructions_next_tier_start { + if self.instructions_executed > instr_tier_next { + let (instr_cost, next_tier) = + self.cost_table.instruction_tier(self.instructions_executed); + self.instructions_current_tier_mult = instr_cost; + self.instructions_next_tier_start = next_tier; + } + } + + Ok(()) + } + + pub fn increase_stack_size(&mut self, size_amount: u64) -> PartialVMResult<()> { + match self.stack_size_current.checked_add(size_amount) { + None => return Err(PartialVMError::new(StatusCode::ARITHMETIC_OVERFLOW)), + Some(new_size) => { + if new_size > self.stack_size_high_water_mark { + self.stack_size_high_water_mark = new_size; + } + self.stack_size_current = new_size; + } + } + + if let Some(stack_size_tier_next) = self.stack_size_next_tier_start { + if self.stack_size_current > stack_size_tier_next { + let (next_mul, next_tier) = + self.cost_table.stack_size_tier(self.stack_size_current); + self.stack_size_current_tier_mult = next_mul; + self.stack_size_next_tier_start = next_tier; + } + } + + Ok(()) + } + + pub fn decrease_stack_size(&mut self, size_amount: u64) { + let new_size = self.stack_size_current.saturating_sub(size_amount); + if new_size > self.stack_size_high_water_mark { + self.stack_size_high_water_mark = new_size; + } + self.stack_size_current = new_size; + } + + /// Given: pushes + pops + increase + decrease in size for an instruction + /// charge for the execution of the instruction. + pub fn charge( + &mut self, + num_instructions: u64, + pushes: u64, + pops: u64, + incr_size: u64, + _decr_size: u64, + ) -> PartialVMResult<()> { + self.push_stack(pushes)?; + self.increase_instruction_count(num_instructions)?; + self.increase_stack_size(incr_size)?; + + self.deduct_gas( + GasCost::new( + self.instructions_current_tier_mult + .checked_mul(num_instructions) + .ok_or_else(|| PartialVMError::new(StatusCode::ARITHMETIC_OVERFLOW))?, + self.stack_size_current_tier_mult + .checked_mul(incr_size) + .ok_or_else(|| PartialVMError::new(StatusCode::ARITHMETIC_OVERFLOW))?, + self.stack_height_current_tier_mult + .checked_mul(pushes) + .ok_or_else(|| PartialVMError::new(StatusCode::ARITHMETIC_OVERFLOW))?, + ) + .total_internal(), + )?; + + // self.decrease_stack_size(decr_size); + self.pop_stack(pops); + Ok(()) + } + + /// Return the `CostTable` behind this `GasStatus`. + pub fn cost_table(&self) -> &CostTable { + &self.cost_table + } + + /// Return the gas left. + pub fn remaining_gas(&self) -> Gas { + self.gas_left.to_unit_round_down() + } + + /// Charge a given amount of gas and fail if not enough gas units are left. + pub fn deduct_gas(&mut self, amount: InternalGas) -> PartialVMResult<()> { + if !self.charge { + return Ok(()); + } + + match self.gas_left.checked_sub(amount) { + Some(gas_left) => { + self.gas_left = gas_left; + Ok(()) + } + None => { + self.gas_left = InternalGas::new(0); + Err(PartialVMError::new(StatusCode::OUT_OF_GAS)) + } + } + } + + // Deduct the amount provided with no conversion, as if it was InternalGasUnit + fn deduct_units(&mut self, amount: u64) -> PartialVMResult<()> { + self.deduct_gas(InternalGas::new(amount)) + } + + pub fn set_metering(&mut self, enabled: bool) { + self.charge = enabled + } + + // The amount of gas used, it does not include the multiplication for the gas + // price + pub fn gas_used_pre_gas_price(&self) -> u64 { + let gas: Gas = match self.initial_budget.checked_sub(self.gas_left) { + Some(val) => InternalGas::to_unit_round_down(val), + None => InternalGas::to_unit_round_down(self.initial_budget), + }; + u64::from(gas) + } + + // Charge the number of bytes with the cost per byte value + // As more bytes are read throughout the computation the cost per bytes is + // increased. + pub fn charge_bytes(&mut self, size: usize, cost_per_byte: u64) -> PartialVMResult<()> { + let computation_cost = if charge_input_as_memory(self.gas_model_version) { + self.increase_stack_size(size as u64)?; + self.stack_size_current_tier_mult * size as u64 * cost_per_byte + } else { + size as u64 * cost_per_byte + }; + self.deduct_units(computation_cost) + } + + fn abstract_memory_size(&self, val: impl ValueView) -> AbstractMemorySize { + if use_legacy_abstract_size(self.gas_model_version) { + val.legacy_abstract_memory_size() + } else { + val.abstract_memory_size() + } + } + + pub fn gas_price(&self) -> u64 { + self.gas_price + } + + pub fn stack_height_high_water_mark(&self) -> u64 { + self.stack_height_high_water_mark + } + + pub fn stack_size_high_water_mark(&self) -> u64 { + self.stack_size_high_water_mark + } + + pub fn instructions_executed(&self) -> u64 { + self.instructions_executed + } +} + +/// Returns a tuple of (, , , +/// ) +fn get_simple_instruction_stack_change( + instr: SimpleInstruction, +) -> (u64, u64, AbstractMemorySize, AbstractMemorySize) { + use SimpleInstruction::*; + + match instr { + // NB: The `Ret` pops are accounted for in `Call` instructions, so we say `Ret` has no pops. + Nop | Ret => (0, 0, 0.into(), 0.into()), + BrTrue | BrFalse => (1, 0, Type::Bool.size(), 0.into()), + Branch => (0, 0, 0.into(), 0.into()), + LdU8 => (0, 1, 0.into(), Type::U8.size()), + LdU16 => (0, 1, 0.into(), Type::U16.size()), + LdU32 => (0, 1, 0.into(), Type::U32.size()), + LdU64 => (0, 1, 0.into(), Type::U64.size()), + LdU128 => (0, 1, 0.into(), Type::U128.size()), + LdU256 => (0, 1, 0.into(), Type::U256.size()), + LdTrue | LdFalse => (0, 1, 0.into(), Type::Bool.size()), + FreezeRef => (1, 1, REFERENCE_SIZE, REFERENCE_SIZE), + ImmBorrowLoc | MutBorrowLoc => (0, 1, 0.into(), REFERENCE_SIZE), + ImmBorrowField | MutBorrowField | ImmBorrowFieldGeneric | MutBorrowFieldGeneric => { + (1, 1, REFERENCE_SIZE, REFERENCE_SIZE) + } + // Since we don't have the size of the value being cast here we take a conservative + // over-approximation: it is _always_ getting cast from the smallest integer type. + CastU8 => (1, 1, Type::U8.size(), Type::U8.size()), + CastU16 => (1, 1, Type::U8.size(), Type::U16.size()), + CastU32 => (1, 1, Type::U8.size(), Type::U32.size()), + CastU64 => (1, 1, Type::U8.size(), Type::U64.size()), + CastU128 => (1, 1, Type::U8.size(), Type::U128.size()), + CastU256 => (1, 1, Type::U8.size(), Type::U256.size()), + // NB: We don't know the size of what integers we're dealing with, so we conservatively + // over-approximate by popping the smallest integers, and push the largest. + Add | Sub | Mul | Mod | Div => (2, 1, Type::U8.size() + Type::U8.size(), Type::U256.size()), + BitOr | BitAnd | Xor => (2, 1, Type::U8.size() + Type::U8.size(), Type::U256.size()), + Shl | Shr => (2, 1, Type::U8.size() + Type::U8.size(), Type::U256.size()), + Or | And => ( + 2, + 1, + Type::Bool.size() + Type::Bool.size(), + Type::Bool.size(), + ), + Lt | Gt | Le | Ge => (2, 1, Type::U8.size() + Type::U8.size(), Type::Bool.size()), + Not => (1, 1, Type::Bool.size(), Type::Bool.size()), + Abort => (1, 0, Type::U64.size(), 0.into()), + } +} + +impl GasMeter for GasStatus { + /// Charge an instruction and fail if not enough gas units are left. + fn charge_simple_instr(&mut self, instr: SimpleInstruction) -> PartialVMResult<()> { + let (pops, pushes, pop_size, push_size) = get_simple_instruction_stack_change(instr); + self.charge(1, pushes, pops, push_size.into(), pop_size.into()) + } + + fn charge_pop(&mut self, popped_val: impl ValueView) -> PartialVMResult<()> { + self.charge(1, 0, 1, 0, self.abstract_memory_size(popped_val).into()) + } + + fn charge_native_function( + &mut self, + amount: InternalGas, + ret_vals: Option>, + ) -> PartialVMResult<()> { + // Charge for the number of pushes on to the stack that the return of this + // function is going to cause. + let pushes = ret_vals + .as_ref() + .map(|ret_vals| ret_vals.len()) + .unwrap_or(0) as u64; + // Calculate the number of bytes that are getting pushed onto the stack. + let size_increase = ret_vals + .map(|ret_vals| { + ret_vals.fold(AbstractMemorySize::zero(), |acc, elem| { + acc + self.abstract_memory_size(elem) + }) + }) + .unwrap_or_else(AbstractMemorySize::zero); + // Charge for the stack operations. We don't count this as an "instruction" + // since we already accounted for the `Call` instruction in the + // `charge_native_function_before_execution` call. + self.charge(0, pushes, 0, size_increase.into(), 0)?; + // Now charge the gas that the native function told us to charge. + self.deduct_gas(amount) + } + + fn charge_native_function_before_execution( + &mut self, + _ty_args: impl ExactSizeIterator, + args: impl ExactSizeIterator, + ) -> PartialVMResult<()> { + // Determine the number of pops that are going to be needed for this function + // call, and charge for them. + let pops = args.len() as u64; + // Calculate the size decrease of the stack from the above pops. + let stack_reduction_size = args.fold(AbstractMemorySize::new(pops), |acc, elem| { + acc + self.abstract_memory_size(elem) + }); + // Track that this is going to be popping from the operand stack. We also + // increment the instruction count as we need to account for the `Call` + // bytecode that initiated this native call. + self.charge(1, 0, pops, 0, stack_reduction_size.into()) + } + + fn charge_call( + &mut self, + _module_id: &ModuleId, + _func_name: &str, + args: impl ExactSizeIterator, + _num_locals: NumArgs, + ) -> PartialVMResult<()> { + // We will have to perform this many pops for the call. + let pops = args.len() as u64; + // Size stays the same -- we're just moving it from the operand stack to the + // locals. But the size on the operand stack is reduced by sum_{args} + // arg.size(). + let stack_reduction_size = args.fold(AbstractMemorySize::new(0), |acc, elem| { + acc + self.abstract_memory_size(elem) + }); + self.charge(1, 0, pops, 0, stack_reduction_size.into()) + } + + fn charge_call_generic( + &mut self, + _module_id: &ModuleId, + _func_name: &str, + _ty_args: impl ExactSizeIterator, + args: impl ExactSizeIterator, + _num_locals: NumArgs, + ) -> PartialVMResult<()> { + // We have to perform this many pops from the operand stack for this function + // call. + let pops = args.len() as u64; + // Calculate the size reduction on the operand stack. + let stack_reduction_size = args.fold(AbstractMemorySize::new(0), |acc, elem| { + acc + self.abstract_memory_size(elem) + }); + // Charge for the pops, no pushes, and account for the stack size decrease. Also + // track the `CallGeneric` instruction we must have encountered for + // this. + self.charge(1, 0, pops, 0, stack_reduction_size.into()) + } + + fn charge_ld_const(&mut self, size: NumBytes) -> PartialVMResult<()> { + // Charge for the load from the locals onto the stack. + self.charge(1, 1, 0, u64::from(size), 0) + } + + fn charge_ld_const_after_deserialization( + &mut self, + _val: impl ValueView, + ) -> PartialVMResult<()> { + // We already charged for this based on the bytes that we're loading so don't + // charge again. + Ok(()) + } + + fn charge_copy_loc(&mut self, val: impl ValueView) -> PartialVMResult<()> { + // Charge for the copy of the local onto the stack. + self.charge(1, 1, 0, self.abstract_memory_size(val).into(), 0) + } + + fn charge_move_loc(&mut self, val: impl ValueView) -> PartialVMResult<()> { + // Charge for the move of the local on to the stack. Note that we charge here + // since we aren't tracking the local size (at least not yet). If we + // were, this should be a net-zero operation in terms of memory usage. + self.charge(1, 1, 0, self.abstract_memory_size(val).into(), 0) + } + + fn charge_store_loc(&mut self, val: impl ValueView) -> PartialVMResult<()> { + // Charge for the storing of the value on the stack into a local. Note here that + // if we were also accounting for the size of the locals that this would + // be a net-zero operation in terms of memory. + self.charge(1, 0, 1, 0, self.abstract_memory_size(val).into()) + } + + fn charge_pack( + &mut self, + _is_generic: bool, + args: impl ExactSizeIterator, + ) -> PartialVMResult<()> { + // We perform `num_fields` number of pops. + let num_fields = args.len() as u64; + // The actual amount of memory on the stack is staying the same with the + // addition of some extra size for the struct, so the size doesn't + // really change much. + self.charge(1, 1, num_fields, STRUCT_SIZE.into(), 0) + } + + fn charge_unpack( + &mut self, + _is_generic: bool, + args: impl ExactSizeIterator, + ) -> PartialVMResult<()> { + // We perform `num_fields` number of pushes. + let num_fields = args.len() as u64; + self.charge(1, num_fields, 1, 0, STRUCT_SIZE.into()) + } + + fn charge_read_ref(&mut self, ref_val: impl ValueView) -> PartialVMResult<()> { + // We read the reference so we are decreasing the size of the stack by the size + // of the reference, and adding to it the size of the value that has + // been read from that reference. + self.charge( + 1, + 1, + 1, + self.abstract_memory_size(ref_val).into(), + REFERENCE_SIZE.into(), + ) + } + + fn charge_write_ref( + &mut self, + new_val: impl ValueView, + old_val: impl ValueView, + ) -> PartialVMResult<()> { + // TODO(tzakian): We should account for this elsewhere as the owner of data the + // the reference points to won't be on the stack. For now though, we + // treat it as adding to the stack size. + self.charge( + 1, + 1, + 2, + self.abstract_memory_size(new_val).into(), + self.abstract_memory_size(old_val).into(), + ) + } + + fn charge_eq(&mut self, lhs: impl ValueView, rhs: impl ValueView) -> PartialVMResult<()> { + let size_reduction = self.abstract_memory_size(lhs) + self.abstract_memory_size(rhs); + self.charge( + 1, + 1, + 2, + (Type::Bool.size() + size_reduction).into(), + size_reduction.into(), + ) + } + + fn charge_neq(&mut self, lhs: impl ValueView, rhs: impl ValueView) -> PartialVMResult<()> { + let size_reduction = self.abstract_memory_size(lhs) + self.abstract_memory_size(rhs); + self.charge(1, 1, 2, Type::Bool.size().into(), size_reduction.into()) + } + + fn charge_vec_pack<'a>( + &mut self, + _ty: impl TypeView + 'a, + args: impl ExactSizeIterator, + ) -> PartialVMResult<()> { + // We will perform `num_args` number of pops. + let num_args = args.len() as u64; + // The amount of data on the stack stays constant except we have some extra + // metadata for the vector to hold the length of the vector. + self.charge(1, 1, num_args, VEC_SIZE.into(), 0) + } + + fn charge_vec_len(&mut self, _ty: impl TypeView) -> PartialVMResult<()> { + self.charge(1, 1, 1, Type::U64.size().into(), REFERENCE_SIZE.into()) + } + + fn charge_vec_borrow( + &mut self, + _is_mut: bool, + _ty: impl TypeView, + _is_success: bool, + ) -> PartialVMResult<()> { + self.charge( + 1, + 1, + 2, + REFERENCE_SIZE.into(), + (REFERENCE_SIZE + Type::U64.size()).into(), + ) + } + + fn charge_vec_push_back( + &mut self, + _ty: impl TypeView, + _val: impl ValueView, + ) -> PartialVMResult<()> { + // The value was already on the stack, so we aren't increasing the number of + // bytes on the stack. + self.charge(1, 0, 2, 0, REFERENCE_SIZE.into()) + } + + fn charge_vec_pop_back( + &mut self, + _ty: impl TypeView, + _val: Option, + ) -> PartialVMResult<()> { + self.charge(1, 1, 1, 0, REFERENCE_SIZE.into()) + } + + fn charge_vec_unpack( + &mut self, + _ty: impl TypeView, + expect_num_elements: NumArgs, + _elems: impl ExactSizeIterator, + ) -> PartialVMResult<()> { + // Charge for the pushes + let pushes = u64::from(expect_num_elements); + // The stack size stays pretty much the same modulo the additional vector size + self.charge(1, pushes, 1, 0, VEC_SIZE.into()) + } + + fn charge_vec_swap(&mut self, _ty: impl TypeView) -> PartialVMResult<()> { + let size_decrease = REFERENCE_SIZE + Type::U64.size() + Type::U64.size(); + self.charge(1, 1, 1, 0, size_decrease.into()) + } + + fn charge_drop_frame( + &mut self, + _locals: impl Iterator, + ) -> PartialVMResult<()> { + Ok(()) + } + + fn remaining_gas(&self) -> InternalGas { + if !self.charge { + return InternalGas::new(u64::MAX); + } + self.gas_left + } + + fn get_profiler_mut(&mut self) -> Option<&mut GasProfiler> { + self.profiler.as_mut() + } + + fn set_profiler(&mut self, profiler: GasProfiler) { + self.profiler = Some(profiler); + } +} + +pub fn zero_cost_schedule() -> CostTable { + let mut zero_tier = BTreeMap::new(); + zero_tier.insert(0, 0); + CostTable { + instruction_tiers: zero_tier.clone(), + stack_size_tiers: zero_tier.clone(), + stack_height_tiers: zero_tier, + } +} + +pub fn unit_cost_schedule() -> CostTable { + let mut unit_tier = BTreeMap::new(); + unit_tier.insert(0, 1); + CostTable { + instruction_tiers: unit_tier.clone(), + stack_size_tiers: unit_tier.clone(), + stack_height_tiers: unit_tier, + } +} + +pub fn initial_cost_schedule_v1() -> CostTable { + let instruction_tiers: BTreeMap = vec![ + (0, 1), + (3000, 2), + (6000, 3), + (8000, 5), + (9000, 9), + (9500, 16), + (10000, 29), + (10500, 50), + ] + .into_iter() + .collect(); + + let stack_height_tiers: BTreeMap = vec![ + (0, 1), + (400, 2), + (800, 3), + (1200, 5), + (1500, 9), + (1800, 16), + (2000, 29), + (2200, 50), + ] + .into_iter() + .collect(); + + let stack_size_tiers: BTreeMap = vec![ + (0, 1), + (2000, 2), + (5000, 3), + (8000, 5), + (10000, 9), + (11000, 16), + (11500, 29), + (11500, 50), + ] + .into_iter() + .collect(); + + CostTable { + instruction_tiers, + stack_size_tiers, + stack_height_tiers, + } +} + +pub fn initial_cost_schedule_v2() -> CostTable { + let instruction_tiers: BTreeMap = vec![ + (0, 1), + (3000, 2), + (6000, 3), + (8000, 5), + (9000, 9), + (9500, 16), + (10000, 29), + (10500, 50), + (12000, 150), + (15000, 250), + ] + .into_iter() + .collect(); + + let stack_height_tiers: BTreeMap = vec![ + (0, 1), + (400, 2), + (800, 3), + (1200, 5), + (1500, 9), + (1800, 16), + (2000, 29), + (2200, 50), + (3000, 150), + (5000, 250), + ] + .into_iter() + .collect(); + + let stack_size_tiers: BTreeMap = vec![ + (0, 1), + (2000, 2), + (5000, 3), + (8000, 5), + (10000, 9), + (11000, 16), + (11500, 29), + (11500, 50), + (15000, 150), + (20000, 250), + ] + .into_iter() + .collect(); + + CostTable { + instruction_tiers, + stack_size_tiers, + stack_height_tiers, + } +} + +pub fn initial_cost_schedule_v3() -> CostTable { + let instruction_tiers: BTreeMap = vec![ + (0, 1), + (3000, 2), + (6000, 3), + (8000, 5), + (9000, 9), + (9500, 16), + (10000, 29), + (10500, 50), + (15000, 100), + ] + .into_iter() + .collect(); + + let stack_height_tiers: BTreeMap = vec![ + (0, 1), + (400, 2), + (800, 3), + (1200, 5), + (1500, 9), + (1800, 16), + (2000, 29), + (2200, 50), + (5000, 100), + ] + .into_iter() + .collect(); + + let stack_size_tiers: BTreeMap = vec![ + (0, 1), + (2000, 2), + (5000, 3), + (8000, 5), + (10000, 9), + (11000, 16), + (11500, 29), + (11500, 50), + (20000, 100), + ] + .into_iter() + .collect(); + + CostTable { + instruction_tiers, + stack_size_tiers, + stack_height_tiers, + } +} + +pub fn initial_cost_schedule_v4() -> CostTable { + let instruction_tiers: BTreeMap = vec![ + (0, 1), + (20_000, 2), + (50_000, 10), + (100_000, 50), + (200_000, 100), + ] + .into_iter() + .collect(); + + let stack_height_tiers: BTreeMap = + vec![(0, 1), (1_000, 2), (10_000, 10)].into_iter().collect(); + + let stack_size_tiers: BTreeMap = vec![ + (0, 1), + (100_000, 2), // ~100K + (500_000, 5), // ~500K + (1_000_000, 100), // ~1M + ] + .into_iter() + .collect(); + + CostTable { + instruction_tiers, + stack_size_tiers, + stack_height_tiers, + } +} + +pub fn initial_cost_schedule_v5() -> CostTable { + let instruction_tiers: BTreeMap = vec![ + (0, 1), + (20_000, 2), + (50_000, 10), + (100_000, 50), + (200_000, 100), + (10_000_000, 1000), + ] + .into_iter() + .collect(); + + let stack_height_tiers: BTreeMap = + vec![(0, 1), (1_000, 2), (10_000, 10)].into_iter().collect(); + + let stack_size_tiers: BTreeMap = vec![ + (0, 1), + (100_000, 2), // ~100K + (500_000, 5), // ~500K + (1_000_000, 100), // ~1M + (100_000_000, 1000), // ~100M + ] + .into_iter() + .collect(); + + CostTable { + instruction_tiers, + stack_size_tiers, + stack_height_tiers, + } +} + +// Convert from our representation of gas costs to the type that the MoveVM +// expects for unit tests. We don't want our gas depending on the MoveVM test +// utils and we don't want to fix our representation to whatever is there, so +// instead we perform this translation from our gas units and cost schedule to +// the one expected by the Move unit tests. +pub fn initial_cost_schedule_for_unit_tests() -> move_vm_test_utils::gas_schedule::CostTable { + let table = initial_cost_schedule_v5(); + move_vm_test_utils::gas_schedule::CostTable { + instruction_tiers: table.instruction_tiers.into_iter().collect(), + stack_height_tiers: table.stack_height_tiers.into_iter().collect(), + stack_size_tiers: table.stack_size_tiers.into_iter().collect(), + } +} diff --git a/crates/sui-types/src/gas_model/units_types.rs b/crates/iota-types/src/gas_model/units_types.rs similarity index 98% rename from crates/sui-types/src/gas_model/units_types.rs rename to crates/iota-types/src/gas_model/units_types.rs index 5a25fcdc6a7..0a494f781f1 100644 --- a/crates/sui-types/src/gas_model/units_types.rs +++ b/crates/iota-types/src/gas_model/units_types.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/iota-types/src/governance.rs b/crates/iota-types/src/governance.rs new file mode 100644 index 00000000000..ba54c7d797a --- /dev/null +++ b/crates/iota-types/src/governance.rs @@ -0,0 +1,118 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; +use serde::{Deserialize, Serialize}; + +use crate::{ + balance::Balance, + base_types::ObjectID, + committee::EpochId, + error::IotaError, + gas_coin::MICROS_PER_IOTA, + id::{ID, UID}, + object::{Data, Object}, + IOTA_SYSTEM_ADDRESS, +}; + +/// Maximum number of active validators at any moment. +/// We do not allow the number of validators in any epoch to go above this. +pub const MAX_VALIDATOR_COUNT: u64 = 150; + +/// Lower-bound on the amount of stake required to become a validator. +/// +/// 30 million IOTA +pub const MIN_VALIDATOR_JOINING_STAKE_MICROS: u64 = 30_000_000 * MICROS_PER_IOTA; + +/// Validators with stake amount below `validator_low_stake_threshold` are +/// considered to have low stake and will be escorted out of the validator set +/// after being below this threshold for more than +/// `validator_low_stake_grace_period` number of epochs. +/// +/// 20 million IOTA +pub const VALIDATOR_LOW_STAKE_THRESHOLD_MICROS: u64 = 20_000_000 * MICROS_PER_IOTA; + +/// Validators with stake below `validator_very_low_stake_threshold` will be +/// removed immediately at epoch change, no grace period. +/// +/// 15 million IOTA +pub const VALIDATOR_VERY_LOW_STAKE_THRESHOLD_MICROS: u64 = 15_000_000 * MICROS_PER_IOTA; + +/// A validator can have stake below `validator_low_stake_threshold` +/// for this many epochs before being kicked out. +pub const VALIDATOR_LOW_STAKE_GRACE_PERIOD: u64 = 7; + +pub const STAKING_POOL_MODULE_NAME: &IdentStr = ident_str!("staking_pool"); +pub const STAKED_IOTA_STRUCT_NAME: &IdentStr = ident_str!("StakedIota"); + +pub const ADD_STAKE_MUL_COIN_FUN_NAME: &IdentStr = ident_str!("request_add_stake_mul_coin"); +pub const ADD_STAKE_FUN_NAME: &IdentStr = ident_str!("request_add_stake"); +pub const WITHDRAW_STAKE_FUN_NAME: &IdentStr = ident_str!("request_withdraw_stake"); + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct StakedIota { + id: UID, + pool_id: ID, + stake_activation_epoch: u64, + principal: Balance, +} + +impl StakedIota { + pub fn type_() -> StructTag { + StructTag { + address: IOTA_SYSTEM_ADDRESS, + module: STAKING_POOL_MODULE_NAME.to_owned(), + name: STAKED_IOTA_STRUCT_NAME.to_owned(), + type_params: vec![], + } + } + + pub fn is_staked_iota(s: &StructTag) -> bool { + s.address == IOTA_SYSTEM_ADDRESS + && s.module.as_ident_str() == STAKING_POOL_MODULE_NAME + && s.name.as_ident_str() == STAKED_IOTA_STRUCT_NAME + && s.type_params.is_empty() + } + + pub fn id(&self) -> ObjectID { + self.id.id.bytes + } + + pub fn pool_id(&self) -> ObjectID { + self.pool_id.bytes + } + + pub fn activation_epoch(&self) -> EpochId { + self.stake_activation_epoch + } + + pub fn request_epoch(&self) -> EpochId { + // TODO: this might change when we implement warm up period. + self.stake_activation_epoch.saturating_sub(1) + } + + pub fn principal(&self) -> u64 { + self.principal.value() + } +} + +impl TryFrom<&Object> for StakedIota { + type Error = IotaError; + fn try_from(object: &Object) -> Result { + match &object.data { + Data::Move(o) => { + if o.type_().is_staked_iota() { + return bcs::from_bytes(o.contents()).map_err(|err| IotaError::TypeError { + error: format!("Unable to deserialize StakedIota object: {:?}", err), + }); + } + } + Data::Package(_) => {} + } + + Err(IotaError::TypeError { + error: format!("Object type is not a StakedIota: {:?}", object), + }) + } +} diff --git a/crates/sui-types/src/id.rs b/crates/iota-types/src/id.rs similarity index 83% rename from crates/sui-types/src/id.rs rename to crates/iota-types/src/id.rs index 853430c6b86..6cda6d11ae9 100644 --- a/crates/sui-types/src/id.rs +++ b/crates/iota-types/src/id.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use move_core_types::{ @@ -11,22 +12,22 @@ use move_core_types::{ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::{base_types::ObjectID, MoveTypeTagTrait, SUI_FRAMEWORK_ADDRESS}; +use crate::{base_types::ObjectID, MoveTypeTagTrait, IOTA_FRAMEWORK_ADDRESS}; pub const OBJECT_MODULE_NAME_STR: &str = "object"; pub const OBJECT_MODULE_NAME: &IdentStr = ident_str!(OBJECT_MODULE_NAME_STR); pub const UID_STRUCT_NAME: &IdentStr = ident_str!("UID"); pub const ID_STRUCT_NAME: &IdentStr = ident_str!("ID"); -pub const RESOLVED_SUI_ID: (&AccountAddress, &IdentStr, &IdentStr) = - (&SUI_FRAMEWORK_ADDRESS, OBJECT_MODULE_NAME, ID_STRUCT_NAME); +pub const RESOLVED_IOTA_ID: (&AccountAddress, &IdentStr, &IdentStr) = + (&IOTA_FRAMEWORK_ADDRESS, OBJECT_MODULE_NAME, ID_STRUCT_NAME); -/// Rust version of the Move sui::object::Info type +/// Rust version of the Move iota::object::Info type #[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, Eq, PartialEq)] pub struct UID { pub id: ID, } -/// Rust version of the Move sui::object::ID type +/// Rust version of the Move iota::object::ID type #[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, Eq, PartialEq)] #[serde(transparent)] pub struct ID { @@ -42,7 +43,7 @@ impl UID { pub fn type_() -> StructTag { StructTag { - address: SUI_FRAMEWORK_ADDRESS, + address: IOTA_FRAMEWORK_ADDRESS, module: OBJECT_MODULE_NAME.to_owned(), name: UID_STRUCT_NAME.to_owned(), type_params: Vec::new(), @@ -75,7 +76,7 @@ impl ID { pub fn type_() -> StructTag { StructTag { - address: SUI_FRAMEWORK_ADDRESS, + address: IOTA_FRAMEWORK_ADDRESS, module: OBJECT_MODULE_NAME.to_owned(), name: ID_STRUCT_NAME.to_owned(), type_params: Vec::new(), diff --git a/crates/sui-types/src/in_memory_storage.rs b/crates/iota-types/src/in_memory_storage.rs similarity index 91% rename from crates/sui-types/src/in_memory_storage.rs rename to crates/iota-types/src/in_memory_storage.rs index 6ea0a533c1d..b31f97ddcfe 100644 --- a/crates/sui-types/src/in_memory_storage.rs +++ b/crates/iota-types/src/in_memory_storage.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeMap; @@ -10,7 +11,7 @@ use move_core_types::{language_storage::ModuleId, resolver::ModuleResolver}; use crate::{ base_types::{ObjectID, ObjectRef, SequenceNumber, VersionNumber}, committee::EpochId, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, inner_temporary_store::WrittenObjects, object::{Object, Owner}, storage::{ @@ -27,7 +28,7 @@ pub struct InMemoryStorage { } impl BackingPackageStore for InMemoryStorage { - fn get_package_object(&self, package_id: &ObjectID) -> SuiResult> { + fn get_package_object(&self, package_id: &ObjectID) -> IotaResult> { load_package_object_from_object_store(self, package_id) } } @@ -38,21 +39,21 @@ impl ChildObjectResolver for InMemoryStorage { parent: &ObjectID, child: &ObjectID, child_version_upper_bound: SequenceNumber, - ) -> SuiResult> { + ) -> IotaResult> { let child_object = match self.persistent.get(child).cloned() { None => return Ok(None), Some(obj) => obj, }; let parent = *parent; if child_object.owner != Owner::ObjectOwner(parent.into()) { - return Err(SuiError::InvalidChildObjectAccess { + return Err(IotaError::InvalidChildObjectAccess { object: *child, given_parent: parent, actual_owner: child_object.owner, }); } if child_object.version() > child_version_upper_bound { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: "TODO InMemoryStorage::read_child_object does not yet support bounded reads" .to_owned(), }); @@ -66,7 +67,7 @@ impl ChildObjectResolver for InMemoryStorage { receiving_object_id: &ObjectID, receive_object_at_version: SequenceNumber, _epoch_id: EpochId, - ) -> SuiResult> { + ) -> IotaResult> { let recv_object = match self.persistent.get(receiving_object_id).cloned() { None => return Ok(None), Some(obj) => obj, @@ -86,13 +87,13 @@ impl ParentSync for InMemoryStorage { fn get_latest_parent_entry_ref_deprecated( &self, _object_id: ObjectID, - ) -> SuiResult> { + ) -> IotaResult> { unreachable!("Should not be called for InMemoryStorage as it's deprecated.") } } impl ModuleResolver for InMemoryStorage { - type Error = SuiError; + type Error = IotaError; fn get_module(&self, module_id: &ModuleId) -> Result>, Self::Error> { get_module(self, module_id) @@ -100,7 +101,7 @@ impl ModuleResolver for InMemoryStorage { } impl ModuleResolver for &mut InMemoryStorage { - type Error = SuiError; + type Error = IotaError; fn get_module(&self, module_id: &ModuleId) -> Result>, Self::Error> { (**self).get_module(module_id) @@ -156,7 +157,7 @@ impl ObjectStore for &mut InMemoryStorage { } impl GetModule for InMemoryStorage { - type Error = SuiError; + type Error = IotaError; type Item = CompiledModule; fn get_module_by_id(&self, id: &ModuleId) -> anyhow::Result, Self::Error> { diff --git a/crates/sui-types/src/inner_temporary_store.rs b/crates/iota-types/src/inner_temporary_store.rs similarity index 96% rename from crates/sui-types/src/inner_temporary_store.rs rename to crates/iota-types/src/inner_temporary_store.rs index 58eff2573ec..cca035b6da6 100644 --- a/crates/sui-types/src/inner_temporary_store.rs +++ b/crates/iota-types/src/inner_temporary_store.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -13,7 +14,7 @@ use move_core_types::language_storage::ModuleId; use crate::{ base_types::{ObjectID, SequenceNumber, VersionDigest}, effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, - error::SuiResult, + error::IotaResult, execution::DynamicallyLoadedObjectMetadata, object::{Object, Owner}, storage::{BackingPackageStore, InputKey, PackageObject}, @@ -144,7 +145,7 @@ impl BackingPackageStore for TemporaryPackageStore<'_, R> where R: BackingPackageStore, { - fn get_package_object(&self, package_id: &ObjectID) -> SuiResult> { + fn get_package_object(&self, package_id: &ObjectID) -> IotaResult> { // We first check the objects in the temporary store it is possible to read // packages that are just written in the same transaction. if let Some(obj) = self.temp_store.written.get(package_id) { diff --git a/crates/iota-types/src/iota_serde.rs b/crates/iota-types/src/iota_serde.rs new file mode 100644 index 00000000000..f9f286fa9de --- /dev/null +++ b/crates/iota-types/src/iota_serde.rs @@ -0,0 +1,375 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + fmt, + fmt::{Debug, Display, Formatter, Write}, + marker::PhantomData, + ops::Deref, + str::FromStr, +}; + +use fastcrypto::encoding::Hex; +use iota_protocol_config::ProtocolVersion; +use move_core_types::{ + account_address::AccountAddress, + language_storage::{StructTag, TypeTag}, +}; +use schemars::JsonSchema; +use serde::{ + self, + de::{Deserializer, Error}, + ser::{Error as SerError, Serializer}, + Deserialize, Serialize, +}; +use serde_with::{serde_as, Bytes, DeserializeAs, DisplayFromStr, SerializeAs}; + +use crate::{ + parse_iota_struct_tag, parse_iota_type_tag, DEEPBOOK_ADDRESS, IOTA_CLOCK_ADDRESS, + IOTA_FRAMEWORK_ADDRESS, IOTA_SYSTEM_ADDRESS, IOTA_SYSTEM_STATE_ADDRESS, STARDUST_ADDRESS, + TIMELOCK_ADDRESS, +}; + +#[inline] +fn to_custom_error<'de, D, E>(e: E) -> D::Error +where + E: Debug, + D: Deserializer<'de>, +{ + Error::custom(format!("byte deserialization failed, cause by: {:?}", e)) +} + +#[inline] +fn to_custom_ser_error(e: E) -> S::Error +where + E: Debug, + S: Serializer, +{ + S::Error::custom(format!("byte serialization failed, cause by: {:?}", e)) +} + +/// Use with serde_as to control serde for human-readable serialization and +/// deserialization `H` : serde_as SerializeAs/DeserializeAs delegation for +/// human readable in/output `R` : serde_as SerializeAs/DeserializeAs delegation +/// for non-human readable in/output +/// +/// # Example: +/// +/// ```text +/// #[serde_as] +/// #[derive(Deserialize, Serialize)] +/// struct Example(#[serde_as(as = "Readable")] [u8; 20]); +/// ``` +/// +/// The above example will delegate human-readable serde to `DisplayFromStr` +/// and array tuple (default) for non-human-readable serializer. +pub struct Readable { + human_readable: PhantomData, + non_human_readable: PhantomData, +} + +impl SerializeAs for Readable +where + H: SerializeAs, + R: SerializeAs, +{ + fn serialize_as(value: &T, serializer: S) -> Result + where + S: Serializer, + { + if serializer.is_human_readable() { + H::serialize_as(value, serializer) + } else { + R::serialize_as(value, serializer) + } + } +} + +impl<'de, R, H, T> DeserializeAs<'de, T> for Readable +where + H: DeserializeAs<'de, T>, + R: DeserializeAs<'de, T>, +{ + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + if deserializer.is_human_readable() { + H::deserialize_as(deserializer) + } else { + R::deserialize_as(deserializer) + } + } +} + +/// custom serde for AccountAddress +pub struct HexAccountAddress; + +impl SerializeAs for HexAccountAddress { + fn serialize_as(value: &AccountAddress, serializer: S) -> Result + where + S: Serializer, + { + Hex::serialize_as(value, serializer) + } +} + +impl<'de> DeserializeAs<'de, AccountAddress> for HexAccountAddress { + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + if s.starts_with("0x") { + AccountAddress::from_hex_literal(&s) + } else { + AccountAddress::from_hex(&s) + } + .map_err(to_custom_error::<'de, D, _>) + } +} + +/// Serializes a bitmap according to the roaring bitmap on-disk standard. +/// +pub struct IotaBitmap; + +impl SerializeAs for IotaBitmap { + fn serialize_as(source: &roaring::RoaringBitmap, serializer: S) -> Result + where + S: Serializer, + { + let mut bytes = vec![]; + + source + .serialize_into(&mut bytes) + .map_err(to_custom_ser_error::)?; + Bytes::serialize_as(&bytes, serializer) + } +} + +impl<'de> DeserializeAs<'de, roaring::RoaringBitmap> for IotaBitmap { + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let bytes: Vec = Bytes::deserialize_as(deserializer)?; + roaring::RoaringBitmap::deserialize_from(&bytes[..]).map_err(to_custom_error::<'de, D, _>) + } +} + +pub struct IotaStructTag; + +impl SerializeAs for IotaStructTag { + fn serialize_as(value: &StructTag, serializer: S) -> Result + where + S: Serializer, + { + let f = to_iota_struct_tag_string(value).map_err(S::Error::custom)?; + f.serialize(serializer) + } +} + +const IOTA_ADDRESSES: [AccountAddress; 9] = [ + AccountAddress::ZERO, + AccountAddress::ONE, + IOTA_FRAMEWORK_ADDRESS, + IOTA_SYSTEM_ADDRESS, + STARDUST_ADDRESS, + TIMELOCK_ADDRESS, + DEEPBOOK_ADDRESS, + IOTA_SYSTEM_STATE_ADDRESS, + IOTA_CLOCK_ADDRESS, +]; +/// Serialize StructTag as a string, retaining the leading zeros in the address. +pub fn to_iota_struct_tag_string(value: &StructTag) -> Result { + let mut f = String::new(); + // trim leading zeros if address is in IOTA_ADDRESSES + let address = if IOTA_ADDRESSES.contains(&value.address) { + value.address.short_str_lossless() + } else { + value.address.to_canonical_string(/* with_prefix */ false) + }; + + write!(f, "0x{}::{}::{}", address, value.module, value.name)?; + if let Some(first_ty) = value.type_params.first() { + write!(f, "<")?; + write!(f, "{}", to_iota_type_tag_string(first_ty)?)?; + for ty in value.type_params.iter().skip(1) { + write!(f, ", {}", to_iota_type_tag_string(ty)?)?; + } + write!(f, ">")?; + } + Ok(f) +} + +fn to_iota_type_tag_string(value: &TypeTag) -> Result { + match value { + TypeTag::Vector(t) => Ok(format!("vector<{}>", to_iota_type_tag_string(t)?)), + TypeTag::Struct(s) => to_iota_struct_tag_string(s), + _ => Ok(value.to_string()), + } +} + +impl<'de> DeserializeAs<'de, StructTag> for IotaStructTag { + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + parse_iota_struct_tag(&s).map_err(D::Error::custom) + } +} + +pub struct IotaTypeTag; + +impl SerializeAs for IotaTypeTag { + fn serialize_as(value: &TypeTag, serializer: S) -> Result + where + S: Serializer, + { + let s = to_iota_type_tag_string(value).map_err(S::Error::custom)?; + s.serialize(serializer) + } +} + +impl<'de> DeserializeAs<'de, TypeTag> for IotaTypeTag { + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + parse_iota_type_tag(&s).map_err(D::Error::custom) + } +} + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy, JsonSchema)] +pub struct BigInt( + #[schemars(with = "String")] + #[serde_as(as = "DisplayFromStr")] + T, +) +where + T: Display + FromStr, + ::Err: Display; + +impl BigInt +where + T: Display + FromStr, + ::Err: Display, +{ + pub fn into_inner(self) -> T { + self.0 + } +} + +impl SerializeAs for BigInt +where + T: Display + FromStr + Copy, + ::Err: Display, +{ + fn serialize_as(value: &T, serializer: S) -> Result + where + S: Serializer, + { + BigInt(*value).serialize(serializer) + } +} + +impl<'de, T> DeserializeAs<'de, T> for BigInt +where + T: Display + FromStr + Copy, + ::Err: Display, +{ + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Ok(*BigInt::deserialize(deserializer)?) + } +} + +impl From for BigInt +where + T: Display + FromStr, + ::Err: Display, +{ + fn from(v: T) -> BigInt { + BigInt(v) + } +} + +impl Deref for BigInt +where + T: Display + FromStr, + ::Err: Display, +{ + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Display for BigInt +where + T: Display + FromStr, + ::Err: Display, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy, JsonSchema)] +pub struct SequenceNumber(#[schemars(with = "BigInt")] u64); + +impl SerializeAs for SequenceNumber { + fn serialize_as( + value: &crate::base_types::SequenceNumber, + serializer: S, + ) -> Result + where + S: Serializer, + { + let s = value.value().to_string(); + s.serialize(serializer) + } +} + +impl<'de> DeserializeAs<'de, crate::base_types::SequenceNumber> for SequenceNumber { + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let b = BigInt::deserialize(deserializer)?; + Ok(crate::base_types::SequenceNumber::from_u64(*b)) + } +} + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy, JsonSchema)] +#[serde(rename = "ProtocolVersion")] +pub struct AsProtocolVersion(#[schemars(with = "BigInt")] u64); + +impl SerializeAs for AsProtocolVersion { + fn serialize_as(value: &ProtocolVersion, serializer: S) -> Result + where + S: Serializer, + { + let s = value.as_u64().to_string(); + s.serialize(serializer) + } +} + +impl<'de> DeserializeAs<'de, ProtocolVersion> for AsProtocolVersion { + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let b = BigInt::::deserialize(deserializer)?; + Ok(ProtocolVersion::from(*b)) + } +} diff --git a/crates/iota-types/src/iota_system_state/epoch_start_iota_system_state.rs b/crates/iota-types/src/iota_system_state/epoch_start_iota_system_state.rs new file mode 100644 index 00000000000..16e17003d34 --- /dev/null +++ b/crates/iota-types/src/iota_system_state/epoch_start_iota_system_state.rs @@ -0,0 +1,415 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::{BTreeMap, HashMap}; + +use anemo::{ + types::{PeerAffinity, PeerInfo}, + PeerId, +}; +use consensus_config::{ + Authority, AuthorityPublicKey, Committee as ConsensusCommittee, NetworkPublicKey, + ProtocolPublicKey, +}; +use enum_dispatch::enum_dispatch; +use iota_protocol_config::ProtocolVersion; +use narwhal_config::{Committee as NarwhalCommittee, CommitteeBuilder, WorkerCache, WorkerIndex}; +use serde::{Deserialize, Serialize}; +use tracing::{error, warn}; + +use crate::{ + base_types::{AuthorityName, EpochId, IotaAddress}, + committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata, StakeUnit}, + multiaddr::Multiaddr, +}; + +#[enum_dispatch] +pub trait EpochStartSystemStateTrait { + fn epoch(&self) -> EpochId; + fn protocol_version(&self) -> ProtocolVersion; + fn reference_gas_price(&self) -> u64; + fn safe_mode(&self) -> bool; + fn epoch_start_timestamp_ms(&self) -> u64; + fn epoch_duration_ms(&self) -> u64; + fn get_validator_addresses(&self) -> Vec; + fn get_iota_committee(&self) -> Committee; + fn get_iota_committee_with_network_metadata(&self) -> CommitteeWithNetworkMetadata; + fn get_narwhal_committee(&self) -> NarwhalCommittee; + fn get_mysticeti_committee(&self) -> ConsensusCommittee; + fn get_validator_as_p2p_peers(&self, excluding_self: AuthorityName) -> Vec; + fn get_authority_names_to_peer_ids(&self) -> HashMap; + fn get_authority_names_to_hostnames(&self) -> HashMap; + fn get_narwhal_worker_cache(&self, transactions_address: &Multiaddr) -> WorkerCache; +} + +/// This type captures the minimum amount of information from IotaSystemState +/// needed by a validator to run the protocol. This allows us to decouple from +/// the actual IotaSystemState type, and hence do not need to evolve it when we +/// upgrade the IotaSystemState type. Evolving EpochStartSystemState is also a +/// lot easier in that we could add optional fields and fill them with None for +/// older versions. When we absolutely must delete fields, we could also add new +/// db tables to store the new version. This is OK because we only store one +/// copy of this as part of EpochStartConfiguration for the most recent epoch in +/// the db. +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +#[enum_dispatch(EpochStartSystemStateTrait)] +pub enum EpochStartSystemState { + V1(EpochStartSystemStateV1), +} + +impl EpochStartSystemState { + pub fn new_v1( + epoch: EpochId, + protocol_version: u64, + reference_gas_price: u64, + safe_mode: bool, + epoch_start_timestamp_ms: u64, + epoch_duration_ms: u64, + active_validators: Vec, + ) -> Self { + Self::V1(EpochStartSystemStateV1 { + epoch, + protocol_version, + reference_gas_price, + safe_mode, + epoch_start_timestamp_ms, + epoch_duration_ms, + active_validators, + }) + } + + pub fn new_for_testing_with_epoch(epoch: EpochId) -> Self { + Self::V1(EpochStartSystemStateV1::new_for_testing_with_epoch(epoch)) + } +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct EpochStartSystemStateV1 { + epoch: EpochId, + protocol_version: u64, + reference_gas_price: u64, + safe_mode: bool, + epoch_start_timestamp_ms: u64, + epoch_duration_ms: u64, + active_validators: Vec, +} + +impl EpochStartSystemStateV1 { + pub fn new_for_testing() -> Self { + Self::new_for_testing_with_epoch(0) + } + + pub fn new_for_testing_with_epoch(epoch: EpochId) -> Self { + Self { + epoch, + protocol_version: ProtocolVersion::MAX.as_u64(), + reference_gas_price: crate::transaction::DEFAULT_VALIDATOR_GAS_PRICE, + safe_mode: false, + epoch_start_timestamp_ms: 0, + epoch_duration_ms: 1000, + active_validators: vec![], + } + } +} + +impl EpochStartSystemStateTrait for EpochStartSystemStateV1 { + fn epoch(&self) -> EpochId { + self.epoch + } + + fn protocol_version(&self) -> ProtocolVersion { + ProtocolVersion::new(self.protocol_version) + } + + fn reference_gas_price(&self) -> u64 { + self.reference_gas_price + } + + fn safe_mode(&self) -> bool { + self.safe_mode + } + + fn epoch_start_timestamp_ms(&self) -> u64 { + self.epoch_start_timestamp_ms + } + + fn epoch_duration_ms(&self) -> u64 { + self.epoch_duration_ms + } + + fn get_validator_addresses(&self) -> Vec { + self.active_validators + .iter() + .map(|validator| validator.iota_address) + .collect() + } + + fn get_iota_committee_with_network_metadata(&self) -> CommitteeWithNetworkMetadata { + let (voting_rights, network_metadata) = self + .active_validators + .iter() + .map(|validator| { + ( + (validator.authority_name(), validator.voting_power), + ( + validator.authority_name(), + NetworkMetadata { + network_address: validator.iota_net_address.clone(), + narwhal_primary_address: validator.narwhal_primary_address.clone(), + }, + ), + ) + }) + .unzip(); + + CommitteeWithNetworkMetadata { + committee: Committee::new(self.epoch, voting_rights), + network_metadata, + } + } + + fn get_iota_committee(&self) -> Committee { + let voting_rights = self + .active_validators + .iter() + .map(|validator| (validator.authority_name(), validator.voting_power)) + .collect(); + Committee::new(self.epoch, voting_rights) + } + + fn get_narwhal_committee(&self) -> NarwhalCommittee { + let mut committee_builder = CommitteeBuilder::new(self.epoch as narwhal_config::Epoch); + + for validator in self.active_validators.iter() { + committee_builder = committee_builder.add_authority( + validator.protocol_pubkey.clone(), + validator.voting_power as narwhal_config::Stake, + validator.narwhal_primary_address.clone(), + validator.narwhal_network_pubkey.clone(), + validator.hostname.clone(), + ); + } + + committee_builder.build() + } + + fn get_mysticeti_committee(&self) -> ConsensusCommittee { + let mut authorities = vec![]; + for validator in self.active_validators.iter() { + authorities.push(Authority { + stake: validator.voting_power as consensus_config::Stake, + // TODO(mysticeti): Add EpochStartValidatorInfoV2 with new field for mysticeti + // address. + address: validator.narwhal_primary_address.clone(), + hostname: validator.hostname.clone(), + authority_key: AuthorityPublicKey::new(validator.protocol_pubkey.clone()), + protocol_key: ProtocolPublicKey::new(validator.narwhal_worker_pubkey.clone()), + network_key: NetworkPublicKey::new(validator.narwhal_network_pubkey.clone()), + }); + } + + // Sort the authorities by their protocol (public) key in ascending order, same + // as the order in the Iota committee returned from get_iota_committee(). + authorities.sort_by(|a1, a2| a1.authority_key.cmp(&a2.authority_key)); + + for ((i, mysticeti_authority), iota_authority_name) in authorities + .iter() + .enumerate() + .zip(self.get_iota_committee().names()) + { + if iota_authority_name.0 != mysticeti_authority.authority_key.to_bytes() { + error!( + "Mismatched authority order between Iota and Mysticeti! Index {}, Mysticeti authority {:?}\nIota authority name {}", + i, mysticeti_authority, iota_authority_name + ); + } + } + + ConsensusCommittee::new(self.epoch as consensus_config::Epoch, authorities) + } + + fn get_validator_as_p2p_peers(&self, excluding_self: AuthorityName) -> Vec { + self.active_validators + .iter() + .filter(|validator| validator.authority_name() != excluding_self) + .map(|validator| { + let address = validator + .p2p_address + .to_anemo_address() + .into_iter() + .collect::>(); + let peer_id = PeerId(validator.narwhal_network_pubkey.0.to_bytes()); + if address.is_empty() { + warn!( + ?peer_id, + "Peer has invalid p2p address: {}", &validator.p2p_address + ); + } + PeerInfo { + peer_id, + affinity: PeerAffinity::High, + address, + } + }) + .collect() + } + + fn get_authority_names_to_peer_ids(&self) -> HashMap { + self.active_validators + .iter() + .map(|validator| { + let name = validator.authority_name(); + let peer_id = PeerId(validator.narwhal_network_pubkey.0.to_bytes()); + + (name, peer_id) + }) + .collect() + } + + fn get_authority_names_to_hostnames(&self) -> HashMap { + self.active_validators + .iter() + .map(|validator| { + let name = validator.authority_name(); + let hostname = validator.hostname.clone(); + + (name, hostname) + }) + .collect() + } + + #[allow(clippy::mutable_key_type)] + fn get_narwhal_worker_cache(&self, transactions_address: &Multiaddr) -> WorkerCache { + let workers: BTreeMap = self + .active_validators + .iter() + .map(|validator| { + let workers = [( + 0, + narwhal_config::WorkerInfo { + name: validator.narwhal_worker_pubkey.clone(), + transactions: transactions_address.clone(), + worker_address: validator.narwhal_worker_address.clone(), + }, + )] + .into_iter() + .collect(); + let worker_index = WorkerIndex(workers); + + (validator.protocol_pubkey.clone(), worker_index) + }) + .collect(); + WorkerCache { + workers, + epoch: self.epoch, + } + } +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct EpochStartValidatorInfoV1 { + pub iota_address: IotaAddress, + pub protocol_pubkey: narwhal_crypto::PublicKey, + pub narwhal_network_pubkey: narwhal_crypto::NetworkPublicKey, + pub narwhal_worker_pubkey: narwhal_crypto::NetworkPublicKey, + pub iota_net_address: Multiaddr, + pub p2p_address: Multiaddr, + pub narwhal_primary_address: Multiaddr, + pub narwhal_worker_address: Multiaddr, + pub voting_power: StakeUnit, + pub hostname: String, +} + +impl EpochStartValidatorInfoV1 { + pub fn authority_name(&self) -> AuthorityName { + (&self.protocol_pubkey).into() + } +} + +#[cfg(test)] +mod test { + use fastcrypto::traits::KeyPair; + use iota_protocol_config::ProtocolVersion; + use mysten_network::Multiaddr; + use narwhal_crypto::NetworkKeyPair; + use rand::thread_rng; + + use crate::{ + base_types::IotaAddress, + committee::CommitteeTrait, + crypto::{get_key_pair, AuthorityKeyPair}, + iota_system_state::epoch_start_iota_system_state::{ + EpochStartSystemStateTrait, EpochStartSystemStateV1, EpochStartValidatorInfoV1, + }, + }; + + #[test] + fn test_iota_and_mysticeti_committee_are_same() { + // GIVEN + let mut active_validators = vec![]; + + for i in 0..10 { + let (iota_address, protocol_key): (IotaAddress, AuthorityKeyPair) = get_key_pair(); + let narwhal_network_key = NetworkKeyPair::generate(&mut thread_rng()); + + active_validators.push(EpochStartValidatorInfoV1 { + iota_address, + protocol_pubkey: protocol_key.public().clone(), + narwhal_network_pubkey: narwhal_network_key.public().clone(), + narwhal_worker_pubkey: narwhal_network_key.public().clone(), + iota_net_address: Multiaddr::empty(), + p2p_address: Multiaddr::empty(), + narwhal_primary_address: Multiaddr::empty(), + narwhal_worker_address: Multiaddr::empty(), + voting_power: 1_000, + hostname: format!("host-{i}").to_string(), + }) + } + + let state = EpochStartSystemStateV1 { + epoch: 10, + protocol_version: ProtocolVersion::MAX.as_u64(), + reference_gas_price: 0, + safe_mode: false, + epoch_start_timestamp_ms: 0, + epoch_duration_ms: 0, + active_validators, + }; + + // WHEN + let iota_committee = state.get_iota_committee(); + let mysticeti_committee = state.get_mysticeti_committee(); + + // THEN + // assert the validators details + assert_eq!(iota_committee.num_members(), 10); + assert_eq!(iota_committee.num_members(), mysticeti_committee.size()); + assert_eq!( + iota_committee.validity_threshold(), + mysticeti_committee.validity_threshold() + ); + assert_eq!( + iota_committee.quorum_threshold(), + mysticeti_committee.quorum_threshold() + ); + assert_eq!(state.epoch, mysticeti_committee.epoch()); + + for (authority_index, mysticeti_authority) in mysticeti_committee.authorities() { + let iota_authority_name = iota_committee + .authority_by_index(authority_index.value() as u32) + .unwrap(); + + assert_eq!( + mysticeti_authority.authority_key.to_bytes(), + iota_authority_name.0, + "Mysten & IOTA committee member of same index correspond to different public key" + ); + assert_eq!( + mysticeti_authority.stake, + iota_committee.weight(iota_authority_name), + "Mysten & IOTA committee member stake differs" + ); + } + } +} diff --git a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs new file mode 100644 index 00000000000..614b6773adb --- /dev/null +++ b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs @@ -0,0 +1,756 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use anyhow::Result; +use fastcrypto::traits::ToFromBytes; +use once_cell::sync::OnceCell; +use serde::{Deserialize, Serialize}; + +use super::{ + epoch_start_iota_system_state::EpochStartValidatorInfoV1, + get_validators_from_table_vec, + iota_system_state_summary::{IotaSystemStateSummary, IotaValidatorSummary}, + AdvanceEpochParams, IotaSystemStateTrait, +}; +use crate::{ + balance::Balance, + base_types::{IotaAddress, ObjectID}, + collection_types::{Bag, Table, TableVec, VecMap, VecSet}, + committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata}, + crypto::{verify_proof_of_possession, AuthorityPublicKeyBytes}, + error::IotaError, + id::ID, + iota_system_state::epoch_start_iota_system_state::EpochStartSystemState, + multiaddr::Multiaddr, + storage::ObjectStore, +}; + +const E_METADATA_INVALID_POP: u64 = 0; +const E_METADATA_INVALID_PUBKEY: u64 = 1; +const E_METADATA_INVALID_NET_PUBKEY: u64 = 2; +const E_METADATA_INVALID_WORKER_PUBKEY: u64 = 3; +const E_METADATA_INVALID_NET_ADDR: u64 = 4; +const E_METADATA_INVALID_P2P_ADDR: u64 = 5; +const E_METADATA_INVALID_PRIMARY_ADDR: u64 = 6; +const E_METADATA_INVALID_WORKER_ADDR: u64 = 7; + +/// Rust version of the Move iota::iota_system::SystemParameters type +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct SystemParametersV1 { + /// The duration of an epoch, in milliseconds. + pub epoch_duration_ms: u64, + + /// The starting epoch in which stake subsidies start being paid out + pub stake_subsidy_start_epoch: u64, + + /// Maximum number of active validators at any moment. + /// We do not allow the number of validators in any epoch to go above this. + pub max_validator_count: u64, + + /// Lower-bound on the amount of stake required to become a validator. + pub min_validator_joining_stake: u64, + + /// Validators with stake amount below `validator_low_stake_threshold` are + /// considered to have low stake and will be escorted out of the + /// validator set after being below this threshold for more than + /// `validator_low_stake_grace_period` number of epochs. + pub validator_low_stake_threshold: u64, + + /// Validators with stake below `validator_very_low_stake_threshold` will be + /// removed immediately at epoch change, no grace period. + pub validator_very_low_stake_threshold: u64, + + /// A validator can have stake below `validator_low_stake_threshold` + /// for this many epochs before being kicked out. + pub validator_low_stake_grace_period: u64, + + pub extra_fields: Bag, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct ValidatorMetadataV1 { + pub iota_address: IotaAddress, + pub protocol_pubkey_bytes: Vec, + pub network_pubkey_bytes: Vec, + pub worker_pubkey_bytes: Vec, + pub proof_of_possession_bytes: Vec, + pub name: String, + pub description: String, + pub image_url: String, + pub project_url: String, + pub net_address: String, + pub p2p_address: String, + pub primary_address: String, + pub worker_address: String, + pub next_epoch_protocol_pubkey_bytes: Option>, + pub next_epoch_proof_of_possession: Option>, + pub next_epoch_network_pubkey_bytes: Option>, + pub next_epoch_worker_pubkey_bytes: Option>, + pub next_epoch_net_address: Option, + pub next_epoch_p2p_address: Option, + pub next_epoch_primary_address: Option, + pub next_epoch_worker_address: Option, + pub extra_fields: Bag, +} + +#[derive(derivative::Derivative, Clone, Eq, PartialEq)] +#[derivative(Debug)] +pub struct VerifiedValidatorMetadataV1 { + pub iota_address: IotaAddress, + pub protocol_pubkey: narwhal_crypto::PublicKey, + pub network_pubkey: narwhal_crypto::NetworkPublicKey, + pub worker_pubkey: narwhal_crypto::NetworkPublicKey, + #[derivative(Debug = "ignore")] + pub proof_of_possession_bytes: Vec, + pub name: String, + pub description: String, + pub image_url: String, + pub project_url: String, + pub net_address: Multiaddr, + pub p2p_address: Multiaddr, + pub primary_address: Multiaddr, + pub worker_address: Multiaddr, + pub next_epoch_protocol_pubkey: Option, + pub next_epoch_proof_of_possession: Option>, + pub next_epoch_network_pubkey: Option, + pub next_epoch_worker_pubkey: Option, + pub next_epoch_net_address: Option, + pub next_epoch_p2p_address: Option, + pub next_epoch_primary_address: Option, + pub next_epoch_worker_address: Option, +} + +impl VerifiedValidatorMetadataV1 { + pub fn iota_pubkey_bytes(&self) -> AuthorityPublicKeyBytes { + (&self.protocol_pubkey).into() + } +} + +impl ValidatorMetadataV1 { + /// Verify validator metadata and return a verified version (on success) or + /// error code (on failure) + pub fn verify(&self) -> Result { + let protocol_pubkey = + narwhal_crypto::PublicKey::from_bytes(self.protocol_pubkey_bytes.as_ref()) + .map_err(|_| E_METADATA_INVALID_PUBKEY)?; + + // Verify proof of possession for the protocol key + let pop = narwhal_crypto::Signature::from_bytes(self.proof_of_possession_bytes.as_ref()) + .map_err(|_| E_METADATA_INVALID_POP)?; + verify_proof_of_possession(&pop, &protocol_pubkey, self.iota_address) + .map_err(|_| E_METADATA_INVALID_POP)?; + + let network_pubkey = + narwhal_crypto::NetworkPublicKey::from_bytes(self.network_pubkey_bytes.as_ref()) + .map_err(|_| E_METADATA_INVALID_NET_PUBKEY)?; + let worker_pubkey = + narwhal_crypto::NetworkPublicKey::from_bytes(self.worker_pubkey_bytes.as_ref()) + .map_err(|_| E_METADATA_INVALID_WORKER_PUBKEY)?; + if worker_pubkey == network_pubkey { + return Err(E_METADATA_INVALID_WORKER_PUBKEY); + } + + let net_address = Multiaddr::try_from(self.net_address.clone()) + .map_err(|_| E_METADATA_INVALID_NET_ADDR)?; + + // Ensure p2p, primary, and worker addresses are both Multiaddr's and valid + // anemo addresses + let p2p_address = Multiaddr::try_from(self.p2p_address.clone()) + .map_err(|_| E_METADATA_INVALID_P2P_ADDR)?; + p2p_address + .to_anemo_address() + .map_err(|_| E_METADATA_INVALID_P2P_ADDR)?; + + let primary_address = Multiaddr::try_from(self.primary_address.clone()) + .map_err(|_| E_METADATA_INVALID_PRIMARY_ADDR)?; + primary_address + .to_anemo_address() + .map_err(|_| E_METADATA_INVALID_PRIMARY_ADDR)?; + + let worker_address = Multiaddr::try_from(self.worker_address.clone()) + .map_err(|_| E_METADATA_INVALID_WORKER_ADDR)?; + worker_address + .to_anemo_address() + .map_err(|_| E_METADATA_INVALID_WORKER_ADDR)?; + + let next_epoch_protocol_pubkey = match self.next_epoch_protocol_pubkey_bytes.clone() { + None => Ok::, u64>(None), + Some(bytes) => Ok(Some( + narwhal_crypto::PublicKey::from_bytes(bytes.as_ref()) + .map_err(|_| E_METADATA_INVALID_PUBKEY)?, + )), + }?; + + let next_epoch_pop = match self.next_epoch_proof_of_possession.clone() { + None => Ok::, u64>(None), + Some(bytes) => Ok(Some( + narwhal_crypto::Signature::from_bytes(bytes.as_ref()) + .map_err(|_| E_METADATA_INVALID_POP)?, + )), + }?; + // Verify proof of possession for the next epoch protocol key + if let Some(ref next_epoch_protocol_pubkey) = next_epoch_protocol_pubkey { + match next_epoch_pop { + Some(next_epoch_pop) => { + verify_proof_of_possession( + &next_epoch_pop, + next_epoch_protocol_pubkey, + self.iota_address, + ) + .map_err(|_| E_METADATA_INVALID_POP)?; + } + None => { + return Err(E_METADATA_INVALID_POP); + } + } + } + + let next_epoch_network_pubkey = match self.next_epoch_network_pubkey_bytes.clone() { + None => Ok::, u64>(None), + Some(bytes) => Ok(Some( + narwhal_crypto::NetworkPublicKey::from_bytes(bytes.as_ref()) + .map_err(|_| E_METADATA_INVALID_NET_PUBKEY)?, + )), + }?; + + let next_epoch_worker_pubkey: Option = + match self.next_epoch_worker_pubkey_bytes.clone() { + None => Ok::, u64>(None), + Some(bytes) => Ok(Some( + narwhal_crypto::NetworkPublicKey::from_bytes(bytes.as_ref()) + .map_err(|_| E_METADATA_INVALID_WORKER_PUBKEY)?, + )), + }?; + if next_epoch_network_pubkey.is_some() + && next_epoch_network_pubkey == next_epoch_worker_pubkey + { + return Err(E_METADATA_INVALID_WORKER_PUBKEY); + } + + let next_epoch_net_address = match self.next_epoch_net_address.clone() { + None => Ok::, u64>(None), + Some(address) => Ok(Some( + Multiaddr::try_from(address).map_err(|_| E_METADATA_INVALID_NET_ADDR)?, + )), + }?; + + let next_epoch_p2p_address = match self.next_epoch_p2p_address.clone() { + None => Ok::, u64>(None), + Some(address) => { + let address = + Multiaddr::try_from(address).map_err(|_| E_METADATA_INVALID_P2P_ADDR)?; + address + .to_anemo_address() + .map_err(|_| E_METADATA_INVALID_P2P_ADDR)?; + + Ok(Some(address)) + } + }?; + + let next_epoch_primary_address = match self.next_epoch_primary_address.clone() { + None => Ok::, u64>(None), + Some(address) => { + let address = + Multiaddr::try_from(address).map_err(|_| E_METADATA_INVALID_PRIMARY_ADDR)?; + address + .to_anemo_address() + .map_err(|_| E_METADATA_INVALID_PRIMARY_ADDR)?; + + Ok(Some(address)) + } + }?; + + let next_epoch_worker_address = match self.next_epoch_worker_address.clone() { + None => Ok::, u64>(None), + Some(address) => { + let address = + Multiaddr::try_from(address).map_err(|_| E_METADATA_INVALID_WORKER_ADDR)?; + address + .to_anemo_address() + .map_err(|_| E_METADATA_INVALID_WORKER_ADDR)?; + + Ok(Some(address)) + } + }?; + + Ok(VerifiedValidatorMetadataV1 { + iota_address: self.iota_address, + protocol_pubkey, + network_pubkey, + worker_pubkey, + proof_of_possession_bytes: self.proof_of_possession_bytes.clone(), + name: self.name.clone(), + description: self.description.clone(), + image_url: self.image_url.clone(), + project_url: self.project_url.clone(), + net_address, + p2p_address, + primary_address, + worker_address, + next_epoch_protocol_pubkey, + next_epoch_proof_of_possession: self.next_epoch_proof_of_possession.clone(), + next_epoch_network_pubkey, + next_epoch_worker_pubkey, + next_epoch_net_address, + next_epoch_p2p_address, + next_epoch_primary_address, + next_epoch_worker_address, + }) + } +} + +/// Rust version of the Move iota::validator::Validator type +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct ValidatorV1 { + metadata: ValidatorMetadataV1, + #[serde(skip)] + verified_metadata: OnceCell, + + pub voting_power: u64, + pub operation_cap_id: ID, + pub gas_price: u64, + pub staking_pool: StakingPoolV1, + pub commission_rate: u64, + pub next_epoch_stake: u64, + pub next_epoch_gas_price: u64, + pub next_epoch_commission_rate: u64, + pub extra_fields: Bag, +} + +impl ValidatorV1 { + pub fn verified_metadata(&self) -> &VerifiedValidatorMetadataV1 { + self.verified_metadata.get_or_init(|| { + self.metadata + .verify() + .expect("Validity of metadata should be verified on-chain") + }) + } + + pub fn into_iota_validator_summary(self) -> IotaValidatorSummary { + let Self { + metadata: + ValidatorMetadataV1 { + iota_address, + protocol_pubkey_bytes, + network_pubkey_bytes, + worker_pubkey_bytes, + proof_of_possession_bytes, + name, + description, + image_url, + project_url, + net_address, + p2p_address, + primary_address, + worker_address, + next_epoch_protocol_pubkey_bytes, + next_epoch_proof_of_possession, + next_epoch_network_pubkey_bytes, + next_epoch_worker_pubkey_bytes, + next_epoch_net_address, + next_epoch_p2p_address, + next_epoch_primary_address, + next_epoch_worker_address, + extra_fields: _, + }, + verified_metadata: _, + voting_power, + operation_cap_id, + gas_price, + staking_pool: + StakingPoolV1 { + id: staking_pool_id, + activation_epoch: staking_pool_activation_epoch, + deactivation_epoch: staking_pool_deactivation_epoch, + iota_balance: staking_pool_iota_balance, + rewards_pool, + pool_token_balance, + exchange_rates: + Table { + id: exchange_rates_id, + size: exchange_rates_size, + }, + pending_stake, + pending_total_iota_withdraw, + pending_pool_token_withdraw, + extra_fields: _, + }, + commission_rate, + next_epoch_stake, + next_epoch_gas_price, + next_epoch_commission_rate, + extra_fields: _, + } = self; + IotaValidatorSummary { + iota_address, + protocol_pubkey_bytes, + network_pubkey_bytes, + worker_pubkey_bytes, + proof_of_possession_bytes, + name, + description, + image_url, + project_url, + net_address, + p2p_address, + primary_address, + worker_address, + next_epoch_protocol_pubkey_bytes, + next_epoch_proof_of_possession, + next_epoch_network_pubkey_bytes, + next_epoch_worker_pubkey_bytes, + next_epoch_net_address, + next_epoch_p2p_address, + next_epoch_primary_address, + next_epoch_worker_address, + voting_power, + operation_cap_id: operation_cap_id.bytes, + gas_price, + staking_pool_id, + staking_pool_activation_epoch, + staking_pool_deactivation_epoch, + staking_pool_iota_balance, + rewards_pool: rewards_pool.value(), + pool_token_balance, + exchange_rates_id, + exchange_rates_size, + pending_stake, + pending_total_iota_withdraw, + pending_pool_token_withdraw, + commission_rate, + next_epoch_stake, + next_epoch_gas_price, + next_epoch_commission_rate, + } + } +} + +/// Rust version of the Move iota_system::staking_pool::StakingPool type +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct StakingPoolV1 { + pub id: ObjectID, + pub activation_epoch: Option, + pub deactivation_epoch: Option, + pub iota_balance: u64, + pub rewards_pool: Balance, + pub pool_token_balance: u64, + pub exchange_rates: Table, + pub pending_stake: u64, + pub pending_total_iota_withdraw: u64, + pub pending_pool_token_withdraw: u64, + pub extra_fields: Bag, +} + +/// Rust version of the Move iota_system::validator_set::ValidatorSet type +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct ValidatorSetV1 { + pub total_stake: u64, + pub active_validators: Vec, + pub pending_active_validators: TableVec, + pub pending_removals: Vec, + pub staking_pool_mappings: Table, + pub inactive_validators: Table, + pub validator_candidates: Table, + pub at_risk_validators: VecMap, + pub extra_fields: Bag, +} + +/// Rust version of the Move iota_system::storage_fund::StorageFund type +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct StorageFundV1 { + pub total_object_storage_rebates: Balance, + pub non_refundable_balance: Balance, +} + +/// Rust version of the Move iota_system::iota_system::IotaSystemStateInner type +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct IotaSystemStateInnerV1 { + pub epoch: u64, + pub protocol_version: u64, + pub system_state_version: u64, + pub validators: ValidatorSetV1, + pub storage_fund: StorageFundV1, + pub parameters: SystemParametersV1, + pub reference_gas_price: u64, + pub validator_report_records: VecMap>, + pub stake_subsidy: StakeSubsidyV1, + pub safe_mode: bool, + pub safe_mode_storage_rewards: Balance, + pub safe_mode_computation_rewards: Balance, + pub safe_mode_storage_rebates: u64, + pub safe_mode_non_refundable_storage_fee: u64, + pub epoch_start_timestamp_ms: u64, + pub extra_fields: Bag, + // TODO: Use getters instead of all pub. +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct StakeSubsidyV1 { + /// Balance of IOTA set aside for stake subsidies that will be drawn down + /// over time. + pub balance: Balance, + + /// Count of the number of times stake subsidies have been distributed. + pub distribution_counter: u64, + + /// The amount of stake subsidy to be drawn down per distribution. + /// This amount decays and decreases over time. + pub current_distribution_amount: u64, + + /// Number of distributions to occur before the distribution amount decays. + pub stake_subsidy_period_length: u64, + + /// The rate at which the distribution amount decays at the end of each + /// period. Expressed in basis points. + pub stake_subsidy_decrease_rate: u16, + + pub extra_fields: Bag, +} + +impl IotaSystemStateTrait for IotaSystemStateInnerV1 { + fn epoch(&self) -> u64 { + self.epoch + } + + fn reference_gas_price(&self) -> u64 { + self.reference_gas_price + } + + fn protocol_version(&self) -> u64 { + self.protocol_version + } + + fn system_state_version(&self) -> u64 { + self.system_state_version + } + + fn epoch_start_timestamp_ms(&self) -> u64 { + self.epoch_start_timestamp_ms + } + + fn epoch_duration_ms(&self) -> u64 { + self.parameters.epoch_duration_ms + } + + fn safe_mode(&self) -> bool { + self.safe_mode + } + + fn advance_epoch_safe_mode(&mut self, params: &AdvanceEpochParams) { + self.epoch = params.epoch; + self.safe_mode = true; + self.safe_mode_storage_rewards + .deposit_for_safe_mode(params.storage_charge); + self.safe_mode_storage_rebates += params.storage_rebate; + self.safe_mode_computation_rewards + .deposit_for_safe_mode(params.computation_charge); + self.safe_mode_non_refundable_storage_fee += params.non_refundable_storage_fee; + self.epoch_start_timestamp_ms = params.epoch_start_timestamp_ms; + self.protocol_version = params.next_protocol_version.as_u64(); + } + + fn get_current_epoch_committee(&self) -> CommitteeWithNetworkMetadata { + let mut voting_rights = BTreeMap::new(); + let mut network_metadata = BTreeMap::new(); + for validator in &self.validators.active_validators { + let verified_metadata = validator.verified_metadata(); + let name = verified_metadata.iota_pubkey_bytes(); + voting_rights.insert(name, validator.voting_power); + network_metadata.insert( + name, + NetworkMetadata { + network_address: verified_metadata.net_address.clone(), + narwhal_primary_address: verified_metadata.primary_address.clone(), + }, + ); + } + CommitteeWithNetworkMetadata { + committee: Committee::new(self.epoch, voting_rights), + network_metadata, + } + } + + fn get_pending_active_validators( + &self, + object_store: &S, + ) -> Result, IotaError> { + let table_id = self.validators.pending_active_validators.contents.id; + let table_size = self.validators.pending_active_validators.contents.size; + let validators: Vec = + get_validators_from_table_vec(object_store, table_id, table_size)?; + Ok(validators + .into_iter() + .map(|v| v.into_iota_validator_summary()) + .collect()) + } + + fn into_epoch_start_state(self) -> EpochStartSystemState { + EpochStartSystemState::new_v1( + self.epoch, + self.protocol_version, + self.reference_gas_price, + self.safe_mode, + self.epoch_start_timestamp_ms, + self.parameters.epoch_duration_ms, + self.validators + .active_validators + .iter() + .map(|validator| { + let metadata = validator.verified_metadata(); + EpochStartValidatorInfoV1 { + iota_address: metadata.iota_address, + protocol_pubkey: metadata.protocol_pubkey.clone(), + narwhal_network_pubkey: metadata.network_pubkey.clone(), + narwhal_worker_pubkey: metadata.worker_pubkey.clone(), + iota_net_address: metadata.net_address.clone(), + p2p_address: metadata.p2p_address.clone(), + narwhal_primary_address: metadata.primary_address.clone(), + narwhal_worker_address: metadata.worker_address.clone(), + voting_power: validator.voting_power, + hostname: metadata.name.clone(), + } + }) + .collect(), + ) + } + + fn into_iota_system_state_summary(self) -> IotaSystemStateSummary { + // If you are making any changes to IotaSystemStateV1 or any of its dependent + // types before mainnet, please also update IotaSystemStateSummary and + // its corresponding TS type. Post-mainnet, we will need to introduce a + // new version. + let Self { + epoch, + protocol_version, + system_state_version, + validators: + ValidatorSetV1 { + total_stake, + active_validators, + pending_active_validators: + TableVec { + contents: + Table { + id: pending_active_validators_id, + size: pending_active_validators_size, + }, + }, + pending_removals, + staking_pool_mappings: + Table { + id: staking_pool_mappings_id, + size: staking_pool_mappings_size, + }, + inactive_validators: + Table { + id: inactive_pools_id, + size: inactive_pools_size, + }, + validator_candidates: + Table { + id: validator_candidates_id, + size: validator_candidates_size, + }, + at_risk_validators: + VecMap { + contents: at_risk_validators, + }, + extra_fields: _, + }, + storage_fund, + parameters: + SystemParametersV1 { + stake_subsidy_start_epoch, + epoch_duration_ms, + max_validator_count, + min_validator_joining_stake, + validator_low_stake_threshold, + validator_very_low_stake_threshold, + validator_low_stake_grace_period, + extra_fields: _, + }, + reference_gas_price, + validator_report_records: + VecMap { + contents: validator_report_records, + }, + stake_subsidy: + StakeSubsidyV1 { + balance: stake_subsidy_balance, + distribution_counter: stake_subsidy_distribution_counter, + current_distribution_amount: stake_subsidy_current_distribution_amount, + stake_subsidy_period_length, + stake_subsidy_decrease_rate, + extra_fields: _, + }, + safe_mode, + safe_mode_storage_rewards, + safe_mode_computation_rewards, + safe_mode_storage_rebates, + safe_mode_non_refundable_storage_fee, + epoch_start_timestamp_ms, + extra_fields: _, + } = self; + IotaSystemStateSummary { + epoch, + protocol_version, + system_state_version, + storage_fund_total_object_storage_rebates: storage_fund + .total_object_storage_rebates + .value(), + storage_fund_non_refundable_balance: storage_fund.non_refundable_balance.value(), + reference_gas_price, + safe_mode, + safe_mode_storage_rewards: safe_mode_storage_rewards.value(), + safe_mode_computation_rewards: safe_mode_computation_rewards.value(), + safe_mode_storage_rebates, + safe_mode_non_refundable_storage_fee, + epoch_start_timestamp_ms, + stake_subsidy_start_epoch, + epoch_duration_ms, + stake_subsidy_distribution_counter, + stake_subsidy_balance: stake_subsidy_balance.value(), + stake_subsidy_current_distribution_amount, + total_stake, + active_validators: active_validators + .into_iter() + .map(|v| v.into_iota_validator_summary()) + .collect(), + pending_active_validators_id, + pending_active_validators_size, + pending_removals, + staking_pool_mappings_id, + staking_pool_mappings_size, + inactive_pools_id, + inactive_pools_size, + validator_candidates_id, + validator_candidates_size, + at_risk_validators: at_risk_validators + .into_iter() + .map(|e| (e.key, e.value)) + .collect(), + validator_report_records: validator_report_records + .into_iter() + .map(|e| (e.key, e.value.contents)) + .collect(), + max_validator_count, + min_validator_joining_stake, + validator_low_stake_threshold, + validator_very_low_stake_threshold, + validator_low_stake_grace_period, + stake_subsidy_period_length, + stake_subsidy_decrease_rate, + } + } +} + +/// Rust version of the Move +/// iota_system::validator_cap::UnverifiedValidatorOperationCap type +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct UnverifiedValidatorOperationCapV1 { + pub id: ObjectID, + pub authorizer_validator_address: IotaAddress, +} diff --git a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs new file mode 100644 index 00000000000..b81872a5128 --- /dev/null +++ b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs @@ -0,0 +1,324 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use serde::{Deserialize, Serialize}; + +use super::{ + epoch_start_iota_system_state::EpochStartValidatorInfoV1, + iota_system_state_inner_v1::ValidatorV1, + iota_system_state_summary::{IotaSystemStateSummary, IotaValidatorSummary}, + AdvanceEpochParams, IotaSystemStateTrait, +}; +use crate::{ + balance::Balance, + base_types::IotaAddress, + collection_types::{Bag, Table, TableVec, VecMap, VecSet}, + committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata}, + error::IotaError, + iota_system_state::{ + epoch_start_iota_system_state::EpochStartSystemState, + get_validators_from_table_vec, + iota_system_state_inner_v1::{StakeSubsidyV1, StorageFundV1, ValidatorSetV1}, + }, + storage::ObjectStore, +}; + +/// Rust version of the Move iota::iota_system::SystemParametersV2 type +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct SystemParametersV2 { + /// The duration of an epoch, in milliseconds. + pub epoch_duration_ms: u64, + + /// The starting epoch in which stake subsidies start being paid out + pub stake_subsidy_start_epoch: u64, + + /// Minimum number of active validators at any moment. + pub min_validator_count: u64, + + /// Maximum number of active validators at any moment. + /// We do not allow the number of validators in any epoch to go above this. + pub max_validator_count: u64, + + /// Lower-bound on the amount of stake required to become a validator. + pub min_validator_joining_stake: u64, + + /// Validators with stake amount below `validator_low_stake_threshold` are + /// considered to have low stake and will be escorted out of the + /// validator set after being below this threshold for more than + /// `validator_low_stake_grace_period` number of epochs. + pub validator_low_stake_threshold: u64, + + /// Validators with stake below `validator_very_low_stake_threshold` will be + /// removed immediately at epoch change, no grace period. + pub validator_very_low_stake_threshold: u64, + + /// A validator can have stake below `validator_low_stake_threshold` + /// for this many epochs before being kicked out. + pub validator_low_stake_grace_period: u64, + + pub extra_fields: Bag, +} + +/// Rust version of the Move iota_system::iota_system::IotaSystemStateInnerV2 +/// type +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct IotaSystemStateInnerV2 { + pub epoch: u64, + pub protocol_version: u64, + pub system_state_version: u64, + pub validators: ValidatorSetV1, + pub storage_fund: StorageFundV1, + pub parameters: SystemParametersV2, + pub reference_gas_price: u64, + pub validator_report_records: VecMap>, + pub stake_subsidy: StakeSubsidyV1, + pub safe_mode: bool, + pub safe_mode_storage_rewards: Balance, + pub safe_mode_computation_rewards: Balance, + pub safe_mode_storage_rebates: u64, + pub safe_mode_non_refundable_storage_fee: u64, + pub epoch_start_timestamp_ms: u64, + pub extra_fields: Bag, + // TODO: Use getters instead of all pub. +} + +impl IotaSystemStateTrait for IotaSystemStateInnerV2 { + fn epoch(&self) -> u64 { + self.epoch + } + + fn reference_gas_price(&self) -> u64 { + self.reference_gas_price + } + + fn protocol_version(&self) -> u64 { + self.protocol_version + } + + fn system_state_version(&self) -> u64 { + self.system_state_version + } + + fn epoch_start_timestamp_ms(&self) -> u64 { + self.epoch_start_timestamp_ms + } + + fn epoch_duration_ms(&self) -> u64 { + self.parameters.epoch_duration_ms + } + + fn safe_mode(&self) -> bool { + self.safe_mode + } + + fn advance_epoch_safe_mode(&mut self, params: &AdvanceEpochParams) { + self.epoch = params.epoch; + self.safe_mode = true; + self.safe_mode_storage_rewards + .deposit_for_safe_mode(params.storage_charge); + self.safe_mode_storage_rebates += params.storage_rebate; + self.safe_mode_computation_rewards + .deposit_for_safe_mode(params.computation_charge); + self.safe_mode_non_refundable_storage_fee += params.non_refundable_storage_fee; + self.epoch_start_timestamp_ms = params.epoch_start_timestamp_ms; + self.protocol_version = params.next_protocol_version.as_u64(); + } + + fn get_current_epoch_committee(&self) -> CommitteeWithNetworkMetadata { + let mut voting_rights = BTreeMap::new(); + let mut network_metadata = BTreeMap::new(); + for validator in &self.validators.active_validators { + let verified_metadata = validator.verified_metadata(); + let name = verified_metadata.iota_pubkey_bytes(); + voting_rights.insert(name, validator.voting_power); + network_metadata.insert( + name, + NetworkMetadata { + network_address: verified_metadata.net_address.clone(), + narwhal_primary_address: verified_metadata.primary_address.clone(), + }, + ); + } + CommitteeWithNetworkMetadata { + committee: Committee::new(self.epoch, voting_rights), + network_metadata, + } + } + + fn get_pending_active_validators( + &self, + object_store: &S, + ) -> Result, IotaError> { + let table_id = self.validators.pending_active_validators.contents.id; + let table_size = self.validators.pending_active_validators.contents.size; + let validators: Vec = + get_validators_from_table_vec(&object_store, table_id, table_size)?; + Ok(validators + .into_iter() + .map(|v| v.into_iota_validator_summary()) + .collect()) + } + + fn into_epoch_start_state(self) -> EpochStartSystemState { + EpochStartSystemState::new_v1( + self.epoch, + self.protocol_version, + self.reference_gas_price, + self.safe_mode, + self.epoch_start_timestamp_ms, + self.parameters.epoch_duration_ms, + self.validators + .active_validators + .iter() + .map(|validator| { + let metadata = validator.verified_metadata(); + EpochStartValidatorInfoV1 { + iota_address: metadata.iota_address, + protocol_pubkey: metadata.protocol_pubkey.clone(), + narwhal_network_pubkey: metadata.network_pubkey.clone(), + narwhal_worker_pubkey: metadata.worker_pubkey.clone(), + iota_net_address: metadata.net_address.clone(), + p2p_address: metadata.p2p_address.clone(), + narwhal_primary_address: metadata.primary_address.clone(), + narwhal_worker_address: metadata.worker_address.clone(), + voting_power: validator.voting_power, + hostname: metadata.name.clone(), + } + }) + .collect(), + ) + } + + fn into_iota_system_state_summary(self) -> IotaSystemStateSummary { + // If you are making any changes to IotaSystemStateV1 or any of its dependent + // types before mainnet, please also update IotaSystemStateSummary and + // its corresponding TS type. Post-mainnet, we will need to introduce a + // new version. + let Self { + epoch, + protocol_version, + system_state_version, + validators: + ValidatorSetV1 { + total_stake, + active_validators, + pending_active_validators: + TableVec { + contents: + Table { + id: pending_active_validators_id, + size: pending_active_validators_size, + }, + }, + pending_removals, + staking_pool_mappings: + Table { + id: staking_pool_mappings_id, + size: staking_pool_mappings_size, + }, + inactive_validators: + Table { + id: inactive_pools_id, + size: inactive_pools_size, + }, + validator_candidates: + Table { + id: validator_candidates_id, + size: validator_candidates_size, + }, + at_risk_validators: + VecMap { + contents: at_risk_validators, + }, + extra_fields: _, + }, + storage_fund, + parameters: + SystemParametersV2 { + stake_subsidy_start_epoch, + epoch_duration_ms, + min_validator_count: _, // TODO: Add it to RPC layer in the future. + max_validator_count, + min_validator_joining_stake, + validator_low_stake_threshold, + validator_very_low_stake_threshold, + validator_low_stake_grace_period, + extra_fields: _, + }, + reference_gas_price, + validator_report_records: + VecMap { + contents: validator_report_records, + }, + stake_subsidy: + StakeSubsidyV1 { + balance: stake_subsidy_balance, + distribution_counter: stake_subsidy_distribution_counter, + current_distribution_amount: stake_subsidy_current_distribution_amount, + stake_subsidy_period_length, + stake_subsidy_decrease_rate, + extra_fields: _, + }, + safe_mode, + safe_mode_storage_rewards, + safe_mode_computation_rewards, + safe_mode_storage_rebates, + safe_mode_non_refundable_storage_fee, + epoch_start_timestamp_ms, + extra_fields: _, + } = self; + IotaSystemStateSummary { + epoch, + protocol_version, + system_state_version, + storage_fund_total_object_storage_rebates: storage_fund + .total_object_storage_rebates + .value(), + storage_fund_non_refundable_balance: storage_fund.non_refundable_balance.value(), + reference_gas_price, + safe_mode, + safe_mode_storage_rewards: safe_mode_storage_rewards.value(), + safe_mode_computation_rewards: safe_mode_computation_rewards.value(), + safe_mode_storage_rebates, + safe_mode_non_refundable_storage_fee, + epoch_start_timestamp_ms, + stake_subsidy_start_epoch, + epoch_duration_ms, + stake_subsidy_distribution_counter, + stake_subsidy_balance: stake_subsidy_balance.value(), + stake_subsidy_current_distribution_amount, + total_stake, + active_validators: active_validators + .into_iter() + .map(|v| v.into_iota_validator_summary()) + .collect(), + pending_active_validators_id, + pending_active_validators_size, + pending_removals, + staking_pool_mappings_id, + staking_pool_mappings_size, + inactive_pools_id, + inactive_pools_size, + validator_candidates_id, + validator_candidates_size, + at_risk_validators: at_risk_validators + .into_iter() + .map(|e| (e.key, e.value)) + .collect(), + validator_report_records: validator_report_records + .into_iter() + .map(|e| (e.key, e.value.contents)) + .collect(), + max_validator_count, + min_validator_joining_stake, + validator_low_stake_threshold, + validator_very_low_stake_threshold, + validator_low_stake_grace_period, + stake_subsidy_period_length, + stake_subsidy_decrease_rate, + } + } +} diff --git a/crates/iota-types/src/iota_system_state/iota_system_state_summary.rs b/crates/iota-types/src/iota_system_state/iota_system_state_summary.rs new file mode 100644 index 00000000000..c6c11c80d04 --- /dev/null +++ b/crates/iota-types/src/iota_system_state/iota_system_state_summary.rs @@ -0,0 +1,479 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use fastcrypto::{encoding::Base64, traits::ToFromBytes}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +use super::{IotaSystemState, IotaSystemStateTrait}; +use crate::{ + base_types::{AuthorityName, IotaAddress, ObjectID}, + committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata}, + dynamic_field::get_dynamic_field_from_store, + error::IotaError, + id::ID, + iota_serde::{BigInt, Readable}, + iota_system_state::get_validator_from_table, + multiaddr::Multiaddr, + storage::ObjectStore, +}; + +/// This is the JSON-RPC type for the IOTA system state object. +/// It flattens all fields to make them top-level fields such that it as minimum +/// dependencies to the internal data structures of the IOTA system state type. + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct IotaSystemStateSummary { + /// The current epoch ID, starting from 0. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub epoch: u64, + /// The current protocol version, starting from 1. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub protocol_version: u64, + /// The current version of the system state data structure type. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub system_state_version: u64, + /// The storage rebates of all the objects on-chain stored in the storage + /// fund. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub storage_fund_total_object_storage_rebates: u64, + /// The non-refundable portion of the storage fund coming from storage + /// reinvestment, non-refundable storage rebates and any leftover + /// staking rewards. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub storage_fund_non_refundable_balance: u64, + /// The reference gas price for the current epoch. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub reference_gas_price: u64, + /// Whether the system is running in a downgraded safe mode due to a + /// non-recoverable bug. This is set whenever we failed to execute + /// advance_epoch, and ended up executing advance_epoch_safe_mode. + /// It can be reset once we are able to successfully execute advance_epoch. + pub safe_mode: bool, + /// Amount of storage rewards accumulated (and not yet distributed) during + /// safe mode. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub safe_mode_storage_rewards: u64, + /// Amount of computation rewards accumulated (and not yet distributed) + /// during safe mode. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub safe_mode_computation_rewards: u64, + /// Amount of storage rebates accumulated (and not yet burned) during safe + /// mode. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub safe_mode_storage_rebates: u64, + /// Amount of non-refundable storage fee accumulated during safe mode. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub safe_mode_non_refundable_storage_fee: u64, + /// Unix timestamp of the current epoch start + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub epoch_start_timestamp_ms: u64, + + // System parameters + /// The duration of an epoch, in milliseconds. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub epoch_duration_ms: u64, + + /// The starting epoch in which stake subsidies start being paid out + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub stake_subsidy_start_epoch: u64, + + /// Maximum number of active validators at any moment. + /// We do not allow the number of validators in any epoch to go above this. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub max_validator_count: u64, + + /// Lower-bound on the amount of stake required to become a validator. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub min_validator_joining_stake: u64, + + /// Validators with stake amount below `validator_low_stake_threshold` are + /// considered to have low stake and will be escorted out of the + /// validator set after being below this threshold for more than + /// `validator_low_stake_grace_period` number of epochs. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub validator_low_stake_threshold: u64, + + /// Validators with stake below `validator_very_low_stake_threshold` will be + /// removed immediately at epoch change, no grace period. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub validator_very_low_stake_threshold: u64, + + /// A validator can have stake below `validator_low_stake_threshold` + /// for this many epochs before being kicked out. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub validator_low_stake_grace_period: u64, + + // Stake subsidy information + /// Balance of IOTA set aside for stake subsidies that will be drawn down + /// over time. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub stake_subsidy_balance: u64, + /// This counter may be different from the current epoch number if + /// in some epochs we decide to skip the subsidy. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub stake_subsidy_distribution_counter: u64, + /// The amount of stake subsidy to be drawn down per epoch. + /// This amount decays and decreases over time. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub stake_subsidy_current_distribution_amount: u64, + /// Number of distributions to occur before the distribution amount decays. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub stake_subsidy_period_length: u64, + /// The rate at which the distribution amount decays at the end of each + /// period. Expressed in basis points. + pub stake_subsidy_decrease_rate: u16, + + // Validator set + /// Total amount of stake from all active validators at the beginning of the + /// epoch. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub total_stake: u64, + /// The list of active validators in the current epoch. + pub active_validators: Vec, + /// ID of the object that contains the list of new validators that will join + /// at the end of the epoch. + pub pending_active_validators_id: ObjectID, + /// Number of new validators that will join at the end of the epoch. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub pending_active_validators_size: u64, + /// Removal requests from the validators. Each element is an index + /// pointing to `active_validators`. + #[schemars(with = "Vec>")] + #[serde_as(as = "Vec, _>>")] + pub pending_removals: Vec, + /// ID of the object that maps from staking pool's ID to the iota address of + /// a validator. + pub staking_pool_mappings_id: ObjectID, + /// Number of staking pool mappings. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub staking_pool_mappings_size: u64, + /// ID of the object that maps from a staking pool ID to the inactive + /// validator that has that pool as its staking pool. + pub inactive_pools_id: ObjectID, + /// Number of inactive staking pools. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub inactive_pools_size: u64, + /// ID of the object that stores preactive validators, mapping their + /// addresses to their `Validator` structs. + pub validator_candidates_id: ObjectID, + /// Number of preactive validators. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub validator_candidates_size: u64, + /// Map storing the number of epochs for which each validator has been below + /// the low stake threshold. + #[schemars(with = "Vec<(IotaAddress, BigInt)>")] + #[serde_as(as = "Vec<(_, Readable, _>)>")] + pub at_risk_validators: Vec<(IotaAddress, u64)>, + /// A map storing the records of validator reporting each other. + pub validator_report_records: Vec<(IotaAddress, Vec)>, +} + +impl IotaSystemStateSummary { + pub fn get_iota_committee_for_benchmarking(&self) -> CommitteeWithNetworkMetadata { + let mut voting_rights = BTreeMap::new(); + let mut network_metadata = BTreeMap::new(); + for validator in &self.active_validators { + let name = AuthorityName::from_bytes(&validator.protocol_pubkey_bytes).unwrap(); + voting_rights.insert(name, validator.voting_power); + network_metadata.insert( + name, + NetworkMetadata { + network_address: Multiaddr::try_from(validator.net_address.clone()).unwrap(), + narwhal_primary_address: Multiaddr::try_from(validator.primary_address.clone()) + .unwrap(), + }, + ); + } + CommitteeWithNetworkMetadata { + committee: Committee::new(self.epoch, voting_rights), + network_metadata, + } + } +} + +/// This is the JSON-RPC type for the IOTA validator. It flattens all inner +/// structures to top-level fields so that they are decoupled from the internal +/// definitions. +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct IotaValidatorSummary { + // Metadata + pub iota_address: IotaAddress, + #[schemars(with = "Base64")] + #[serde_as(as = "Base64")] + pub protocol_pubkey_bytes: Vec, + #[schemars(with = "Base64")] + #[serde_as(as = "Base64")] + pub network_pubkey_bytes: Vec, + #[schemars(with = "Base64")] + #[serde_as(as = "Base64")] + pub worker_pubkey_bytes: Vec, + #[schemars(with = "Base64")] + #[serde_as(as = "Base64")] + pub proof_of_possession_bytes: Vec, + pub name: String, + pub description: String, + pub image_url: String, + pub project_url: String, + pub net_address: String, + pub p2p_address: String, + pub primary_address: String, + pub worker_address: String, + #[schemars(with = "Option")] + #[serde_as(as = "Option")] + pub next_epoch_protocol_pubkey_bytes: Option>, + #[schemars(with = "Option")] + #[serde_as(as = "Option")] + pub next_epoch_proof_of_possession: Option>, + #[schemars(with = "Option")] + #[serde_as(as = "Option")] + pub next_epoch_network_pubkey_bytes: Option>, + #[schemars(with = "Option")] + #[serde_as(as = "Option")] + pub next_epoch_worker_pubkey_bytes: Option>, + pub next_epoch_net_address: Option, + pub next_epoch_p2p_address: Option, + pub next_epoch_primary_address: Option, + pub next_epoch_worker_address: Option, + + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub voting_power: u64, + pub operation_cap_id: ObjectID, + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub gas_price: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub commission_rate: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub next_epoch_stake: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub next_epoch_gas_price: u64, + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub next_epoch_commission_rate: u64, + + // Staking pool information + /// ID of the staking pool object. + pub staking_pool_id: ObjectID, + /// The epoch at which this pool became active. + #[schemars(with = "Option>")] + #[serde_as(as = "Option, _>>")] + pub staking_pool_activation_epoch: Option, + /// The epoch at which this staking pool ceased to be active. `None` = + /// {pre-active, active}, + #[schemars(with = "Option>")] + #[serde_as(as = "Option, _>>")] + pub staking_pool_deactivation_epoch: Option, + /// The total number of IOTA tokens in this pool. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub staking_pool_iota_balance: u64, + /// The epoch stake rewards will be added here at the end of each epoch. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub rewards_pool: u64, + /// Total number of pool tokens issued by the pool. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub pool_token_balance: u64, + /// Pending stake amount for this epoch. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub pending_stake: u64, + /// Pending stake withdrawn during the current epoch, emptied at epoch + /// boundaries. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub pending_total_iota_withdraw: u64, + /// Pending pool token withdrawn during the current epoch, emptied at epoch + /// boundaries. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub pending_pool_token_withdraw: u64, + /// ID of the exchange rate table object. + pub exchange_rates_id: ObjectID, + /// Number of exchange rates in the table. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub exchange_rates_size: u64, +} + +impl Default for IotaSystemStateSummary { + fn default() -> Self { + Self { + epoch: 0, + protocol_version: 1, + system_state_version: 1, + storage_fund_total_object_storage_rebates: 0, + storage_fund_non_refundable_balance: 0, + reference_gas_price: 1, + safe_mode: false, + safe_mode_storage_rewards: 0, + safe_mode_computation_rewards: 0, + safe_mode_storage_rebates: 0, + safe_mode_non_refundable_storage_fee: 0, + epoch_start_timestamp_ms: 0, + epoch_duration_ms: 0, + stake_subsidy_start_epoch: 0, + max_validator_count: 0, + min_validator_joining_stake: 0, + validator_low_stake_threshold: 0, + validator_very_low_stake_threshold: 0, + validator_low_stake_grace_period: 0, + stake_subsidy_balance: 0, + stake_subsidy_distribution_counter: 0, + stake_subsidy_current_distribution_amount: 0, + stake_subsidy_period_length: 0, + stake_subsidy_decrease_rate: 0, + total_stake: 0, + active_validators: vec![], + pending_active_validators_id: ObjectID::ZERO, + pending_active_validators_size: 0, + pending_removals: vec![], + staking_pool_mappings_id: ObjectID::ZERO, + staking_pool_mappings_size: 0, + inactive_pools_id: ObjectID::ZERO, + inactive_pools_size: 0, + validator_candidates_id: ObjectID::ZERO, + validator_candidates_size: 0, + at_risk_validators: vec![], + validator_report_records: vec![], + } + } +} + +impl Default for IotaValidatorSummary { + fn default() -> Self { + Self { + iota_address: IotaAddress::default(), + protocol_pubkey_bytes: vec![], + network_pubkey_bytes: vec![], + worker_pubkey_bytes: vec![], + proof_of_possession_bytes: vec![], + name: String::new(), + description: String::new(), + image_url: String::new(), + project_url: String::new(), + net_address: String::new(), + p2p_address: String::new(), + primary_address: String::new(), + worker_address: String::new(), + next_epoch_protocol_pubkey_bytes: None, + next_epoch_proof_of_possession: None, + next_epoch_network_pubkey_bytes: None, + next_epoch_worker_pubkey_bytes: None, + next_epoch_net_address: None, + next_epoch_p2p_address: None, + next_epoch_primary_address: None, + next_epoch_worker_address: None, + voting_power: 0, + operation_cap_id: ObjectID::ZERO, + gas_price: 0, + commission_rate: 0, + next_epoch_stake: 0, + next_epoch_gas_price: 0, + next_epoch_commission_rate: 0, + staking_pool_id: ObjectID::ZERO, + staking_pool_activation_epoch: None, + staking_pool_deactivation_epoch: None, + staking_pool_iota_balance: 0, + rewards_pool: 0, + pool_token_balance: 0, + pending_stake: 0, + pending_total_iota_withdraw: 0, + pending_pool_token_withdraw: 0, + exchange_rates_id: ObjectID::ZERO, + exchange_rates_size: 0, + } + } +} + +/// Given the staking pool id of a validator, return the validator's +/// `IotaValidatorSummary`, works for validator candidates, active validators, +/// as well as inactive validators. +pub fn get_validator_by_pool_id( + object_store: &S, + system_state: &IotaSystemState, + system_state_summary: &IotaSystemStateSummary, + pool_id: ObjectID, +) -> Result +where + S: ObjectStore + ?Sized, +{ + // First try to find in active validator set. + let active_validator = system_state_summary + .active_validators + .iter() + .find(|v| v.staking_pool_id == pool_id); + if let Some(active) = active_validator { + return Ok(active.clone()); + } + // Then try to find in pending active validator set. + let pending_active_validators = system_state.get_pending_active_validators(object_store)?; + let pending_active = pending_active_validators + .iter() + .find(|v| v.staking_pool_id == pool_id); + if let Some(pending) = pending_active { + return Ok(pending.clone()); + } + // After that try to find in inactive pools. + let inactive_table_id = system_state_summary.inactive_pools_id; + if let Ok(inactive) = + get_validator_from_table(&object_store, inactive_table_id, &ID::new(pool_id)) + { + return Ok(inactive); + } + // Finally look up the candidates pool. + let candidate_address: IotaAddress = get_dynamic_field_from_store( + &object_store, + system_state_summary.staking_pool_mappings_id, + &ID::new(pool_id), + ) + .map_err(|err| { + IotaError::IotaSystemStateReadError(format!( + "Failed to load candidate address from pool mappings: {:?}", + err + )) + })?; + let candidate_table_id = system_state_summary.validator_candidates_id; + get_validator_from_table(&object_store, candidate_table_id, &candidate_address) +} diff --git a/crates/iota-types/src/iota_system_state/mod.rs b/crates/iota-types/src/iota_system_state/mod.rs new file mode 100644 index 00000000000..df1fb87e8b5 --- /dev/null +++ b/crates/iota-types/src/iota_system_state/mod.rs @@ -0,0 +1,489 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt; + +use anyhow::Result; +use enum_dispatch::enum_dispatch; +use iota_protocol_config::{ProtocolConfig, ProtocolVersion}; +use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; + +use self::{ + iota_system_state_inner_v1::{IotaSystemStateInnerV1, ValidatorV1}, + iota_system_state_summary::{IotaSystemStateSummary, IotaValidatorSummary}, +}; +use crate::{ + base_types::ObjectID, + committee::CommitteeWithNetworkMetadata, + dynamic_field::{get_dynamic_field_from_store, get_dynamic_field_object_from_store, Field}, + error::IotaError, + id::UID, + iota_system_state::{ + epoch_start_iota_system_state::EpochStartSystemState, + iota_system_state_inner_v2::IotaSystemStateInnerV2, + }, + object::{MoveObject, Object}, + storage::ObjectStore, + versioned::Versioned, + MoveTypeTagTrait, IOTA_SYSTEM_ADDRESS, IOTA_SYSTEM_STATE_OBJECT_ID, +}; + +pub mod epoch_start_iota_system_state; +pub mod iota_system_state_inner_v1; +pub mod iota_system_state_inner_v2; +pub mod iota_system_state_summary; + +#[cfg(msim)] +mod simtest_iota_system_state_inner; +#[cfg(msim)] +use self::simtest_iota_system_state_inner::{ + SimTestIotaSystemStateInnerDeepV2, SimTestIotaSystemStateInnerShallowV2, + SimTestIotaSystemStateInnerV1, SimTestValidatorDeepV2, SimTestValidatorV1, +}; + +const IOTA_SYSTEM_STATE_WRAPPER_STRUCT_NAME: &IdentStr = ident_str!("IotaSystemState"); + +pub const IOTA_SYSTEM_MODULE_NAME: &IdentStr = ident_str!("iota_system"); +pub const ADVANCE_EPOCH_FUNCTION_NAME: &IdentStr = ident_str!("advance_epoch"); +pub const ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME: &IdentStr = ident_str!("advance_epoch_safe_mode"); + +#[cfg(msim)] +pub const IOTA_SYSTEM_STATE_SIM_TEST_V1: u64 = 18446744073709551605; // u64::MAX - 10 +#[cfg(msim)] +pub const IOTA_SYSTEM_STATE_SIM_TEST_SHALLOW_V2: u64 = 18446744073709551606; // u64::MAX - 9 +#[cfg(msim)] +pub const IOTA_SYSTEM_STATE_SIM_TEST_DEEP_V2: u64 = 18446744073709551607; // u64::MAX - 8 + +/// Rust version of the Move iota::iota_system::IotaSystemState type +/// This repreents the object with 0x5 ID. +/// In Rust, this type should be rarely used since it's just a thin +/// wrapper used to access the inner object. +/// Within this module, we use it to determine the current version of the system +/// state inner object type, so that we could deserialize the inner object +/// correctly. Outside of this module, we only use it in genesis snapshot and +/// testing. +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct IotaSystemStateWrapper { + pub id: UID, + pub version: u64, +} + +impl IotaSystemStateWrapper { + pub fn type_() -> StructTag { + StructTag { + address: IOTA_SYSTEM_ADDRESS, + name: IOTA_SYSTEM_STATE_WRAPPER_STRUCT_NAME.to_owned(), + module: IOTA_SYSTEM_MODULE_NAME.to_owned(), + type_params: vec![], + } + } + + /// Advances epoch in safe mode natively in Rust, without involking Move. + /// This ensures that there cannot be any failure from Move and is + /// guaranteed to succeed. Returns the old and new inner system state + /// object. + pub fn advance_epoch_safe_mode( + &self, + params: &AdvanceEpochParams, + object_store: &dyn ObjectStore, + protocol_config: &ProtocolConfig, + ) -> (Object, Object) { + let id = self.id.id.bytes; + let old_field_object = get_dynamic_field_object_from_store(object_store, id, &self.version) + .expect("Dynamic field object of wrapper should always be present in the object store"); + let mut new_field_object = old_field_object.clone(); + let move_object = new_field_object + .data + .try_as_move_mut() + .expect("Dynamic field object must be a Move object"); + match self.version { + 1 => { + Self::advance_epoch_safe_mode_impl::( + move_object, + params, + protocol_config, + ); + } + 2 => { + Self::advance_epoch_safe_mode_impl::( + move_object, + params, + protocol_config, + ); + } + #[cfg(msim)] + IOTA_SYSTEM_STATE_SIM_TEST_V1 => { + Self::advance_epoch_safe_mode_impl::( + move_object, + params, + protocol_config, + ); + } + #[cfg(msim)] + IOTA_SYSTEM_STATE_SIM_TEST_SHALLOW_V2 => { + Self::advance_epoch_safe_mode_impl::( + move_object, + params, + protocol_config, + ); + } + #[cfg(msim)] + IOTA_SYSTEM_STATE_SIM_TEST_DEEP_V2 => { + Self::advance_epoch_safe_mode_impl::( + move_object, + params, + protocol_config, + ); + } + _ => unreachable!(), + } + (old_field_object, new_field_object) + } + + fn advance_epoch_safe_mode_impl( + move_object: &mut MoveObject, + params: &AdvanceEpochParams, + protocol_config: &ProtocolConfig, + ) where + T: Serialize + DeserializeOwned + IotaSystemStateTrait, + { + let mut field: Field = + bcs::from_bytes(move_object.contents()).expect("bcs deserialization should never fail"); + tracing::info!( + "Advance epoch safe mode: current epoch: {}, protocol_version: {}, system_state_version: {}", + field.value.epoch(), + field.value.protocol_version(), + field.value.system_state_version() + ); + field.value.advance_epoch_safe_mode(params); + tracing::info!( + "Safe mode activated. New epoch: {}, protocol_version: {}, system_state_version: {}", + field.value.epoch(), + field.value.protocol_version(), + field.value.system_state_version() + ); + let new_contents = bcs::to_bytes(&field).expect("bcs serialization should never fail"); + move_object + .update_contents(new_contents, protocol_config) + .expect("Update iota system object content cannot fail since it should be small"); + } +} + +/// This is the standard API that all inner system state object type should +/// implement. +#[enum_dispatch] +pub trait IotaSystemStateTrait { + fn epoch(&self) -> u64; + fn reference_gas_price(&self) -> u64; + fn protocol_version(&self) -> u64; + fn system_state_version(&self) -> u64; + fn epoch_start_timestamp_ms(&self) -> u64; + fn epoch_duration_ms(&self) -> u64; + fn safe_mode(&self) -> bool; + fn advance_epoch_safe_mode(&mut self, params: &AdvanceEpochParams); + fn get_current_epoch_committee(&self) -> CommitteeWithNetworkMetadata; + fn get_pending_active_validators( + &self, + object_store: &S, + ) -> Result, IotaError>; + fn into_epoch_start_state(self) -> EpochStartSystemState; + fn into_iota_system_state_summary(self) -> IotaSystemStateSummary; +} + +/// IotaSystemState provides an abstraction over multiple versions of the inner +/// IotaSystemStateInner object. This should be the primary interface to the +/// system state object in Rust. We use enum dispatch to dispatch all methods +/// defined in IotaSystemStateTrait to the actual implementation in the inner +/// types. +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +#[enum_dispatch(IotaSystemStateTrait)] +pub enum IotaSystemState { + V1(IotaSystemStateInnerV1), + V2(IotaSystemStateInnerV2), + #[cfg(msim)] + SimTestV1(SimTestIotaSystemStateInnerV1), + #[cfg(msim)] + SimTestShallowV2(SimTestIotaSystemStateInnerShallowV2), + #[cfg(msim)] + SimTestDeepV2(SimTestIotaSystemStateInnerDeepV2), +} + +/// This is the fixed type used by genesis. +pub type IotaSystemStateInnerGenesis = IotaSystemStateInnerV1; +pub type IotaValidatorGenesis = ValidatorV1; + +impl IotaSystemState { + /// Always return the version that we will be using for genesis. + /// Genesis always uses this version regardless of the current version. + /// Note that since it's possible for the actual genesis of the network to + /// diverge from the genesis of the latest Rust code, it's important + /// that we only use this for tooling purposes. + pub fn into_genesis_version_for_tooling(self) -> IotaSystemStateInnerGenesis { + match self { + IotaSystemState::V1(inner) => inner, + _ => unreachable!(), + } + } + + pub fn version(&self) -> u64 { + self.system_state_version() + } +} + +pub fn get_iota_system_state_wrapper( + object_store: &dyn ObjectStore, +) -> Result { + let wrapper = object_store + .get_object(&IOTA_SYSTEM_STATE_OBJECT_ID)? + // Don't panic here on None because object_store is a generic store. + .ok_or_else(|| { + IotaError::IotaSystemStateReadError( + "IotaSystemStateWrapper object not found".to_owned(), + ) + })?; + let move_object = wrapper.data.try_as_move().ok_or_else(|| { + IotaError::IotaSystemStateReadError( + "IotaSystemStateWrapper object must be a Move object".to_owned(), + ) + })?; + let result = bcs::from_bytes::(move_object.contents()) + .map_err(|err| IotaError::IotaSystemStateReadError(err.to_string()))?; + Ok(result) +} + +pub fn get_iota_system_state(object_store: &dyn ObjectStore) -> Result { + let wrapper = get_iota_system_state_wrapper(object_store)?; + let id = wrapper.id.id.bytes; + match wrapper.version { + 1 => { + let result: IotaSystemStateInnerV1 = + get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err( + |err| { + IotaError::DynamicFieldReadError(format!( + "Failed to load iota system state inner object with ID {:?} and version {:?}: {:?}", + id, wrapper.version, err + )) + }, + )?; + Ok(IotaSystemState::V1(result)) + } + 2 => { + let result: IotaSystemStateInnerV2 = + get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err( + |err| { + IotaError::DynamicFieldReadError(format!( + "Failed to load iota system state inner object with ID {:?} and version {:?}: {:?}", + id, wrapper.version, err + )) + }, + )?; + Ok(IotaSystemState::V2(result)) + } + #[cfg(msim)] + IOTA_SYSTEM_STATE_SIM_TEST_V1 => { + let result: SimTestIotaSystemStateInnerV1 = + get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err( + |err| { + IotaError::DynamicFieldReadError(format!( + "Failed to load iota system state inner object with ID {:?} and version {:?}: {:?}", + id, wrapper.version, err + )) + }, + )?; + Ok(IotaSystemState::SimTestV1(result)) + } + #[cfg(msim)] + IOTA_SYSTEM_STATE_SIM_TEST_SHALLOW_V2 => { + let result: SimTestIotaSystemStateInnerShallowV2 = + get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err( + |err| { + IotaError::DynamicFieldReadError(format!( + "Failed to load iota system state inner object with ID {:?} and version {:?}: {:?}", + id, wrapper.version, err + )) + }, + )?; + Ok(IotaSystemState::SimTestShallowV2(result)) + } + #[cfg(msim)] + IOTA_SYSTEM_STATE_SIM_TEST_DEEP_V2 => { + let result: SimTestIotaSystemStateInnerDeepV2 = + get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err( + |err| { + IotaError::DynamicFieldReadError(format!( + "Failed to load iota system state inner object with ID {:?} and version {:?}: {:?}", + id, wrapper.version, err + )) + }, + )?; + Ok(IotaSystemState::SimTestDeepV2(result)) + } + _ => Err(IotaError::IotaSystemStateReadError(format!( + "Unsupported IotaSystemState version: {}", + wrapper.version + ))), + } +} + +/// Given a system state type version, and the ID of the table, along with a +/// key, retrieve the dynamic field as a Validator type. We need the version to +/// determine which inner type to use for the Validator type. This is assuming +/// that the validator is stored in the table as ValidatorWrapper type. +pub fn get_validator_from_table( + object_store: &dyn ObjectStore, + table_id: ObjectID, + key: &K, +) -> Result +where + K: MoveTypeTagTrait + Serialize + DeserializeOwned + fmt::Debug, +{ + let field: ValidatorWrapper = get_dynamic_field_from_store(object_store, table_id, key) + .map_err(|err| { + IotaError::IotaSystemStateReadError(format!( + "Failed to load validator wrapper from table: {:?}", + err + )) + })?; + let versioned = field.inner; + let version = versioned.version; + match version { + 1 => { + let validator: ValidatorV1 = + get_dynamic_field_from_store(object_store, versioned.id.id.bytes, &version) + .map_err(|err| { + IotaError::IotaSystemStateReadError(format!( + "Failed to load inner validator from the wrapper: {:?}", + err + )) + })?; + Ok(validator.into_iota_validator_summary()) + } + #[cfg(msim)] + IOTA_SYSTEM_STATE_SIM_TEST_V1 => { + let validator: SimTestValidatorV1 = + get_dynamic_field_from_store(object_store, versioned.id.id.bytes, &version) + .map_err(|err| { + IotaError::IotaSystemStateReadError(format!( + "Failed to load inner validator from the wrapper: {:?}", + err + )) + })?; + Ok(validator.into_iota_validator_summary()) + } + #[cfg(msim)] + IOTA_SYSTEM_STATE_SIM_TEST_DEEP_V2 => { + let validator: SimTestValidatorDeepV2 = + get_dynamic_field_from_store(object_store, versioned.id.id.bytes, &version) + .map_err(|err| { + IotaError::IotaSystemStateReadError(format!( + "Failed to load inner validator from the wrapper: {:?}", + err + )) + })?; + Ok(validator.into_iota_validator_summary()) + } + _ => Err(IotaError::IotaSystemStateReadError(format!( + "Unsupported Validator version: {}", + version + ))), + } +} + +pub fn get_validators_from_table_vec( + object_store: &S, + table_id: ObjectID, + table_size: u64, +) -> Result, IotaError> +where + S: ObjectStore + ?Sized, + ValidatorType: Serialize + DeserializeOwned, +{ + let mut validators = vec![]; + for i in 0..table_size { + let validator: ValidatorType = get_dynamic_field_from_store(&object_store, table_id, &i) + .map_err(|err| { + IotaError::IotaSystemStateReadError(format!( + "Failed to load validator from table: {:?}", + err + )) + })?; + validators.push(validator); + } + Ok(validators) +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Default)] +pub struct PoolTokenExchangeRate { + iota_amount: u64, + pool_token_amount: u64, +} + +impl PoolTokenExchangeRate { + /// Rate of the staking pool, pool token amount : Iota amount + pub fn rate(&self) -> f64 { + if self.iota_amount == 0 { + 1_f64 + } else { + self.pool_token_amount as f64 / self.iota_amount as f64 + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct ValidatorWrapper { + pub inner: Versioned, +} + +#[derive(Debug)] +pub struct AdvanceEpochParams { + pub epoch: u64, + pub next_protocol_version: ProtocolVersion, + pub storage_charge: u64, + pub computation_charge: u64, + pub storage_rebate: u64, + pub non_refundable_storage_fee: u64, + pub storage_fund_reinvest_rate: u64, + pub reward_slashing_rate: u64, + pub epoch_start_timestamp_ms: u64, +} + +#[cfg(msim)] +pub mod advance_epoch_result_injection { + use std::cell::RefCell; + + use crate::{ + committee::EpochId, + error::{ExecutionError, ExecutionErrorKind}, + }; + + thread_local! { + /// Override the result of advance_epoch in the range [start, end). + static OVERRIDE: RefCell> = RefCell::new(None); + } + + /// Override the result of advance_epoch transaction if new epoch is in the + /// provided range [start, end). + pub fn set_override(value: Option<(EpochId, EpochId)>) { + OVERRIDE.with(|o| *o.borrow_mut() = value); + } + + /// This function is used to modify the result of advance_epoch transaction + /// for testing. If the override is set, the result will be an execution + /// error, otherwise the original result will be returned. + pub fn maybe_modify_result( + result: Result<(), ExecutionError>, + current_epoch: EpochId, + ) -> Result<(), ExecutionError> { + if let Some((start, end)) = OVERRIDE.with(|o| *o.borrow()) { + if current_epoch >= start && current_epoch < end { + return Err::<(), ExecutionError>(ExecutionError::new( + ExecutionErrorKind::FunctionNotFound, + None, + )); + } + } + result + } +} diff --git a/crates/iota-types/src/iota_system_state/simtest_iota_system_state_inner.rs b/crates/iota-types/src/iota_system_state/simtest_iota_system_state_inner.rs new file mode 100644 index 00000000000..a0bc57bc797 --- /dev/null +++ b/crates/iota-types/src/iota_system_state/simtest_iota_system_state_inner.rs @@ -0,0 +1,487 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use fastcrypto::traits::ToFromBytes; +use mysten_network::Multiaddr; +use once_cell::sync::OnceCell; +use serde::{Deserialize, Serialize}; + +use crate::{ + balance::Balance, + base_types::IotaAddress, + collection_types::{Bag, Table}, + committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata}, + crypto::AuthorityPublicKeyBytes, + error::IotaError, + iota_system_state::{ + epoch_start_iota_system_state::{EpochStartSystemState, EpochStartValidatorInfoV1}, + iota_system_state_summary::{IotaSystemStateSummary, IotaValidatorSummary}, + AdvanceEpochParams, IotaSystemStateTrait, + }, + storage::ObjectStore, +}; + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct SimTestIotaSystemStateInnerV1 { + pub epoch: u64, + pub protocol_version: u64, + pub system_state_version: u64, + pub validators: SimTestValidatorSetV1, + pub storage_fund: Balance, + pub parameters: SimTestSystemParametersV1, + pub reference_gas_price: u64, + pub safe_mode: bool, + pub epoch_start_timestamp_ms: u64, + pub extra_fields: Bag, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct SimTestSystemParametersV1 { + pub epoch_duration_ms: u64, + pub extra_fields: Bag, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct SimTestValidatorSetV1 { + pub active_validators: Vec, + pub inactive_validators: Table, + pub extra_fields: Bag, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct SimTestValidatorV1 { + metadata: SimTestValidatorMetadataV1, + #[serde(skip)] + verified_metadata: OnceCell, + pub voting_power: u64, + pub stake: Balance, + pub extra_fields: Bag, +} + +impl SimTestValidatorV1 { + pub fn verified_metadata(&self) -> &VerifiedSimTestValidatorMetadataV1 { + self.verified_metadata + .get_or_init(|| self.metadata.verify()) + } + + pub fn into_iota_validator_summary(self) -> IotaValidatorSummary { + IotaValidatorSummary::default() + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct SimTestValidatorMetadataV1 { + pub iota_address: IotaAddress, + pub protocol_pubkey_bytes: Vec, + pub network_pubkey_bytes: Vec, + pub worker_pubkey_bytes: Vec, + pub net_address: String, + pub p2p_address: String, + pub primary_address: String, + pub worker_address: String, + pub extra_fields: Bag, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct VerifiedSimTestValidatorMetadataV1 { + pub iota_address: IotaAddress, + pub protocol_pubkey: narwhal_crypto::PublicKey, + pub network_pubkey: narwhal_crypto::NetworkPublicKey, + pub worker_pubkey: narwhal_crypto::NetworkPublicKey, + pub net_address: Multiaddr, + pub p2p_address: Multiaddr, + pub primary_address: Multiaddr, + pub worker_address: Multiaddr, +} + +impl SimTestValidatorMetadataV1 { + pub fn verify(&self) -> VerifiedSimTestValidatorMetadataV1 { + let protocol_pubkey = + narwhal_crypto::PublicKey::from_bytes(self.protocol_pubkey_bytes.as_ref()).unwrap(); + let network_pubkey = + narwhal_crypto::NetworkPublicKey::from_bytes(self.network_pubkey_bytes.as_ref()) + .unwrap(); + let worker_pubkey = + narwhal_crypto::NetworkPublicKey::from_bytes(self.worker_pubkey_bytes.as_ref()) + .unwrap(); + let net_address = Multiaddr::try_from(self.net_address.clone()).unwrap(); + let p2p_address = Multiaddr::try_from(self.p2p_address.clone()).unwrap(); + let primary_address = Multiaddr::try_from(self.primary_address.clone()).unwrap(); + let worker_address = Multiaddr::try_from(self.worker_address.clone()).unwrap(); + VerifiedSimTestValidatorMetadataV1 { + iota_address: self.iota_address, + protocol_pubkey, + network_pubkey, + worker_pubkey, + net_address, + p2p_address, + primary_address, + worker_address, + } + } +} + +impl VerifiedSimTestValidatorMetadataV1 { + pub fn iota_pubkey_bytes(&self) -> AuthorityPublicKeyBytes { + (&self.protocol_pubkey).into() + } +} + +impl IotaSystemStateTrait for SimTestIotaSystemStateInnerV1 { + fn epoch(&self) -> u64 { + self.epoch + } + + fn reference_gas_price(&self) -> u64 { + self.reference_gas_price + } + + fn protocol_version(&self) -> u64 { + self.protocol_version + } + + fn system_state_version(&self) -> u64 { + self.system_state_version + } + + fn epoch_start_timestamp_ms(&self) -> u64 { + self.epoch_start_timestamp_ms + } + + fn epoch_duration_ms(&self) -> u64 { + self.parameters.epoch_duration_ms + } + + fn safe_mode(&self) -> bool { + self.safe_mode + } + + fn advance_epoch_safe_mode(&mut self, params: &AdvanceEpochParams) { + self.epoch = params.epoch; + self.safe_mode = true; + self.epoch_start_timestamp_ms = params.epoch_start_timestamp_ms; + self.protocol_version = params.next_protocol_version.as_u64(); + } + + fn get_current_epoch_committee(&self) -> CommitteeWithNetworkMetadata { + let mut voting_rights = BTreeMap::new(); + let mut network_metadata = BTreeMap::new(); + for validator in &self.validators.active_validators { + let verified_metadata = validator.verified_metadata(); + let name = verified_metadata.iota_pubkey_bytes(); + voting_rights.insert(name, validator.voting_power); + network_metadata.insert( + name, + NetworkMetadata { + network_address: verified_metadata.net_address.clone(), + narwhal_primary_address: verified_metadata.primary_address.clone(), + }, + ); + } + CommitteeWithNetworkMetadata { + committee: Committee::new(self.epoch, voting_rights), + network_metadata, + } + } + + fn get_pending_active_validators( + &self, + _object_store: &S, + ) -> Result, IotaError> { + Ok(vec![]) + } + + fn into_epoch_start_state(self) -> EpochStartSystemState { + EpochStartSystemState::new_v1( + self.epoch, + self.protocol_version, + self.reference_gas_price, + self.safe_mode, + self.epoch_start_timestamp_ms, + self.parameters.epoch_duration_ms, + self.validators + .active_validators + .iter() + .map(|validator| { + let metadata = validator.verified_metadata(); + EpochStartValidatorInfoV1 { + iota_address: metadata.iota_address, + protocol_pubkey: metadata.protocol_pubkey.clone(), + narwhal_network_pubkey: metadata.network_pubkey.clone(), + narwhal_worker_pubkey: metadata.worker_pubkey.clone(), + iota_net_address: metadata.net_address.clone(), + p2p_address: metadata.p2p_address.clone(), + narwhal_primary_address: metadata.primary_address.clone(), + narwhal_worker_address: metadata.worker_address.clone(), + voting_power: validator.voting_power, + hostname: "".to_string(), + } + }) + .collect(), + ) + } + + fn into_iota_system_state_summary(self) -> IotaSystemStateSummary { + IotaSystemStateSummary::default() + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct SimTestIotaSystemStateInnerShallowV2 { + pub new_dummy_field: u64, + pub epoch: u64, + pub protocol_version: u64, + pub system_state_version: u64, + pub validators: SimTestValidatorSetV1, + pub storage_fund: Balance, + pub parameters: SimTestSystemParametersV1, + pub reference_gas_price: u64, + pub safe_mode: bool, + pub epoch_start_timestamp_ms: u64, + pub extra_fields: Bag, +} + +impl IotaSystemStateTrait for SimTestIotaSystemStateInnerShallowV2 { + fn epoch(&self) -> u64 { + self.epoch + } + + fn reference_gas_price(&self) -> u64 { + self.reference_gas_price + } + + fn protocol_version(&self) -> u64 { + self.protocol_version + } + + fn system_state_version(&self) -> u64 { + self.system_state_version + } + + fn epoch_start_timestamp_ms(&self) -> u64 { + self.epoch_start_timestamp_ms + } + + fn epoch_duration_ms(&self) -> u64 { + self.parameters.epoch_duration_ms + } + + fn safe_mode(&self) -> bool { + self.safe_mode + } + + fn advance_epoch_safe_mode(&mut self, params: &AdvanceEpochParams) { + self.epoch = params.epoch; + self.safe_mode = true; + self.epoch_start_timestamp_ms = params.epoch_start_timestamp_ms; + self.protocol_version = params.next_protocol_version.as_u64(); + } + + fn get_current_epoch_committee(&self) -> CommitteeWithNetworkMetadata { + let mut voting_rights = BTreeMap::new(); + let mut network_metadata = BTreeMap::new(); + for validator in &self.validators.active_validators { + let verified_metadata = validator.verified_metadata(); + let name = verified_metadata.iota_pubkey_bytes(); + voting_rights.insert(name, validator.voting_power); + network_metadata.insert( + name, + NetworkMetadata { + network_address: verified_metadata.net_address.clone(), + narwhal_primary_address: verified_metadata.primary_address.clone(), + }, + ); + } + CommitteeWithNetworkMetadata { + committee: Committee::new(self.epoch, voting_rights), + network_metadata, + } + } + + fn get_pending_active_validators( + &self, + _object_store: &S, + ) -> Result, IotaError> { + Ok(vec![]) + } + + fn into_epoch_start_state(self) -> EpochStartSystemState { + EpochStartSystemState::new_v1( + self.epoch, + self.protocol_version, + self.reference_gas_price, + self.safe_mode, + self.epoch_start_timestamp_ms, + self.parameters.epoch_duration_ms, + self.validators + .active_validators + .iter() + .map(|validator| { + let metadata = validator.verified_metadata(); + EpochStartValidatorInfoV1 { + iota_address: metadata.iota_address, + protocol_pubkey: metadata.protocol_pubkey.clone(), + narwhal_network_pubkey: metadata.network_pubkey.clone(), + narwhal_worker_pubkey: metadata.worker_pubkey.clone(), + iota_net_address: metadata.net_address.clone(), + p2p_address: metadata.p2p_address.clone(), + narwhal_primary_address: metadata.primary_address.clone(), + narwhal_worker_address: metadata.worker_address.clone(), + voting_power: validator.voting_power, + hostname: "".to_string(), + } + }) + .collect(), + ) + } + + fn into_iota_system_state_summary(self) -> IotaSystemStateSummary { + IotaSystemStateSummary::default() + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct SimTestValidatorSetDeepV2 { + pub active_validators: Vec, + pub inactive_validators: Table, + pub extra_fields: Bag, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct SimTestValidatorDeepV2 { + pub new_dummy_field: u64, + metadata: SimTestValidatorMetadataV1, + #[serde(skip)] + verified_metadata: OnceCell, + pub voting_power: u64, + pub stake: Balance, + pub extra_fields: Bag, +} + +impl SimTestValidatorDeepV2 { + pub fn verified_metadata(&self) -> &VerifiedSimTestValidatorMetadataV1 { + self.verified_metadata + .get_or_init(|| self.metadata.verify()) + } + + pub fn into_iota_validator_summary(self) -> IotaValidatorSummary { + IotaValidatorSummary::default() + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct SimTestIotaSystemStateInnerDeepV2 { + pub new_dummy_field: u64, + pub epoch: u64, + pub protocol_version: u64, + pub system_state_version: u64, + pub validators: SimTestValidatorSetDeepV2, + pub storage_fund: Balance, + pub parameters: SimTestSystemParametersV1, + pub reference_gas_price: u64, + pub safe_mode: bool, + pub epoch_start_timestamp_ms: u64, + pub extra_fields: Bag, +} + +impl IotaSystemStateTrait for SimTestIotaSystemStateInnerDeepV2 { + fn epoch(&self) -> u64 { + self.epoch + } + + fn reference_gas_price(&self) -> u64 { + self.reference_gas_price + } + + fn protocol_version(&self) -> u64 { + self.protocol_version + } + + fn system_state_version(&self) -> u64 { + self.system_state_version + } + + fn epoch_start_timestamp_ms(&self) -> u64 { + self.epoch_start_timestamp_ms + } + + fn epoch_duration_ms(&self) -> u64 { + self.parameters.epoch_duration_ms + } + + fn safe_mode(&self) -> bool { + self.safe_mode + } + + fn advance_epoch_safe_mode(&mut self, params: &AdvanceEpochParams) { + self.epoch = params.epoch; + self.safe_mode = true; + self.epoch_start_timestamp_ms = params.epoch_start_timestamp_ms; + self.protocol_version = params.next_protocol_version.as_u64(); + } + + fn get_current_epoch_committee(&self) -> CommitteeWithNetworkMetadata { + let mut voting_rights = BTreeMap::new(); + let mut network_metadata = BTreeMap::new(); + for validator in &self.validators.active_validators { + let verified_metadata = validator.verified_metadata(); + let name = verified_metadata.iota_pubkey_bytes(); + voting_rights.insert(name, validator.voting_power); + network_metadata.insert( + name, + NetworkMetadata { + network_address: verified_metadata.net_address.clone(), + narwhal_primary_address: verified_metadata.primary_address.clone(), + }, + ); + } + CommitteeWithNetworkMetadata { + committee: Committee::new(self.epoch, voting_rights), + network_metadata, + } + } + + fn get_pending_active_validators( + &self, + _object_store: &S, + ) -> Result, IotaError> { + Ok(vec![]) + } + + fn into_epoch_start_state(self) -> EpochStartSystemState { + EpochStartSystemState::new_v1( + self.epoch, + self.protocol_version, + self.reference_gas_price, + self.safe_mode, + self.epoch_start_timestamp_ms, + self.parameters.epoch_duration_ms, + self.validators + .active_validators + .iter() + .map(|validator| { + let metadata = validator.verified_metadata(); + EpochStartValidatorInfoV1 { + iota_address: metadata.iota_address, + protocol_pubkey: metadata.protocol_pubkey.clone(), + narwhal_network_pubkey: metadata.network_pubkey.clone(), + narwhal_worker_pubkey: metadata.worker_pubkey.clone(), + iota_net_address: metadata.net_address.clone(), + p2p_address: metadata.p2p_address.clone(), + narwhal_primary_address: metadata.primary_address.clone(), + narwhal_worker_address: metadata.worker_address.clone(), + voting_power: validator.voting_power, + hostname: "".to_string(), + } + }) + .collect(), + ) + } + + fn into_iota_system_state_summary(self) -> IotaSystemStateSummary { + IotaSystemStateSummary::default() + } +} diff --git a/crates/iota-types/src/lib.rs b/crates/iota-types/src/lib.rs new file mode 100644 index 00000000000..1d7d2a8426c --- /dev/null +++ b/crates/iota-types/src/lib.rs @@ -0,0 +1,570 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +#![warn( + future_incompatible, + nonstandard_style, + rust_2018_idioms, + rust_2021_compatibility +)] + +use base_types::{IotaAddress, ObjectID, SequenceNumber}; +use move_binary_format::{ + binary_views::BinaryIndexedView, + file_format::{AbilitySet, SignatureToken}, +}; +use move_bytecode_utils::resolve_struct; +use move_core_types::{ + account_address::AccountAddress, + language_storage::{ModuleId, StructTag}, +}; +pub use move_core_types::{identifier::Identifier, language_storage::TypeTag}; +pub use mysten_network::multiaddr; +use object::OBJECT_START_VERSION; + +use crate::{ + base_types::{RESOLVED_ASCII_STR, RESOLVED_STD_OPTION, RESOLVED_UTF8_STR}, + id::RESOLVED_IOTA_ID, +}; + +#[macro_use] +pub mod error; + +pub mod accumulator; +pub mod authenticator_state; +pub mod balance; +pub mod base_types; +pub mod bridge; +pub mod clock; +pub mod coin; +pub mod collection_types; +pub mod committee; +pub mod crypto; +pub mod deny_list; +pub mod digests; +pub mod display; +pub mod dynamic_field; +pub mod effects; +pub mod epoch_data; +pub mod event; +pub mod executable_transaction; +pub mod execution; +pub mod execution_config_utils; +pub mod execution_mode; +pub mod execution_status; +pub mod full_checkpoint_content; +pub mod gas; +pub mod gas_coin; +pub mod gas_model; +pub mod governance; +pub mod id; +pub mod in_memory_storage; +pub mod inner_temporary_store; +pub mod iota_serde; +pub mod iota_system_state; +pub mod message_envelope; +pub mod messages_checkpoint; +pub mod messages_consensus; +pub mod messages_grpc; +pub mod messages_safe_client; +pub mod metrics; +pub mod mock_checkpoint_builder; +pub mod move_package; +pub mod multisig; +pub mod multisig_legacy; +pub mod object; +pub mod programmable_transaction_builder; +pub mod quorum_driver_types; +pub mod randomness_state; +pub mod signature; +pub mod storage; +pub mod timelock; +pub mod transaction; +pub mod transfer; +pub mod type_resolver; +pub mod versioned; +pub mod zk_login_authenticator; +pub mod zk_login_util; + +#[cfg(any(test, feature = "test-utils"))] +#[path = "./unit_tests/utils.rs"] +pub mod utils; + +/// 0x1-- account address where Move stdlib modules are stored +/// Same as the ObjectID +pub const MOVE_STDLIB_ADDRESS: AccountAddress = AccountAddress::ONE; +pub const MOVE_STDLIB_PACKAGE_ID: ObjectID = ObjectID::from_address(MOVE_STDLIB_ADDRESS); + +/// 0x2-- account address where iota framework modules are stored +/// Same as the ObjectID +pub const IOTA_FRAMEWORK_ADDRESS: AccountAddress = address_from_single_byte(2); +pub const IOTA_FRAMEWORK_PACKAGE_ID: ObjectID = ObjectID::from_address(IOTA_FRAMEWORK_ADDRESS); + +/// 0x3-- account address where iota system modules are stored +/// Same as the ObjectID +pub const IOTA_SYSTEM_ADDRESS: AccountAddress = address_from_single_byte(3); +pub const IOTA_SYSTEM_PACKAGE_ID: ObjectID = ObjectID::from_address(IOTA_SYSTEM_ADDRESS); + +/// 0xdee9-- account address where DeepBook modules are stored +/// Same as the ObjectID +pub const DEEPBOOK_ADDRESS: AccountAddress = deepbook_addr(); +pub const DEEPBOOK_PACKAGE_ID: ObjectID = ObjectID::from_address(DEEPBOOK_ADDRESS); + +/// 0x107a-- account address where Stardust modules are stored +/// Same as the ObjectID +pub const STARDUST_ADDRESS: AccountAddress = stardust_addr(); +pub const STARDUST_PACKAGE_ID: ObjectID = ObjectID::from_address(STARDUST_ADDRESS); + +/// 0x10cf-- account address where Timelock modules are stored +/// Same as the ObjectID +pub const TIMELOCK_ADDRESS: AccountAddress = timelock_addr(); +pub const TIMELOCK_PACKAGE_ID: ObjectID = ObjectID::from_address(TIMELOCK_ADDRESS); + +/// 0xb-- account address where Bridge modules are stored +/// Same as the ObjectID +pub const BRIDGE_ADDRESS: AccountAddress = address_from_single_byte(11); +pub const BRIDGE_PACKAGE_ID: ObjectID = ObjectID::from_address(BRIDGE_ADDRESS); + +/// 0x5: hardcoded object ID for the singleton iota system state object. +pub const IOTA_SYSTEM_STATE_ADDRESS: AccountAddress = address_from_single_byte(5); +pub const IOTA_SYSTEM_STATE_OBJECT_ID: ObjectID = ObjectID::from_address(IOTA_SYSTEM_STATE_ADDRESS); +pub const IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION; + +/// 0x6: hardcoded object ID for the singleton clock object. +pub const IOTA_CLOCK_ADDRESS: AccountAddress = address_from_single_byte(6); +pub const IOTA_CLOCK_OBJECT_ID: ObjectID = ObjectID::from_address(IOTA_CLOCK_ADDRESS); +pub const IOTA_CLOCK_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION; + +/// 0x7: hardcode object ID for the singleton authenticator state object. +pub const IOTA_AUTHENTICATOR_STATE_ADDRESS: AccountAddress = address_from_single_byte(7); +pub const IOTA_AUTHENTICATOR_STATE_OBJECT_ID: ObjectID = + ObjectID::from_address(IOTA_AUTHENTICATOR_STATE_ADDRESS); +pub const IOTA_AUTHENTICATOR_STATE_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION; + +/// 0x8: hardcode object ID for the singleton randomness state object. +pub const IOTA_RANDOMNESS_STATE_ADDRESS: AccountAddress = address_from_single_byte(8); +pub const IOTA_RANDOMNESS_STATE_OBJECT_ID: ObjectID = + ObjectID::from_address(IOTA_RANDOMNESS_STATE_ADDRESS); + +/// 0x403: hardcode object ID for the singleton DenyList object. +pub const IOTA_DENY_LIST_ADDRESS: AccountAddress = deny_list_addr(); +pub const IOTA_DENY_LIST_OBJECT_ID: ObjectID = ObjectID::from_address(IOTA_DENY_LIST_ADDRESS); + +/// 0x9: hardcode object ID for the singleton bridge object. +pub const IOTA_BRIDGE_ADDRESS: AccountAddress = address_from_single_byte(9); +pub const IOTA_BRIDGE_OBJECT_ID: ObjectID = ObjectID::from_address(IOTA_BRIDGE_ADDRESS); + +/// Return `true` if `addr` is a special system package that can be upgraded at +/// epoch boundaries. All new system package ID's must be added here. +pub fn is_system_package(addr: impl Into) -> bool { + matches!( + addr.into(), + MOVE_STDLIB_ADDRESS + | IOTA_FRAMEWORK_ADDRESS + | IOTA_SYSTEM_ADDRESS + | DEEPBOOK_ADDRESS + | STARDUST_ADDRESS + | TIMELOCK_ADDRESS + | BRIDGE_ADDRESS + ) +} + +const fn address_from_single_byte(b: u8) -> AccountAddress { + let mut addr = [0u8; AccountAddress::LENGTH]; + addr[AccountAddress::LENGTH - 1] = b; + AccountAddress::new(addr) +} + +/// return 0x0...dee9 +const fn deepbook_addr() -> AccountAddress { + let mut addr = [0u8; AccountAddress::LENGTH]; + addr[AccountAddress::LENGTH - 2] = 0xde; + addr[AccountAddress::LENGTH - 1] = 0xe9; + AccountAddress::new(addr) +} + +/// return 0x0...107a +const fn stardust_addr() -> AccountAddress { + let mut addr = [0u8; AccountAddress::LENGTH]; + addr[AccountAddress::LENGTH - 2] = 0x10; + addr[AccountAddress::LENGTH - 1] = 0x7a; + AccountAddress::new(addr) +} + +/// return 0x0...10cf +const fn timelock_addr() -> AccountAddress { + let mut addr = [0u8; AccountAddress::LENGTH]; + addr[AccountAddress::LENGTH - 2] = 0x10; + addr[AccountAddress::LENGTH - 1] = 0xcf; + AccountAddress::new(addr) +} + +/// return 0x0...403 +const fn deny_list_addr() -> AccountAddress { + let mut addr = [0u8; AccountAddress::LENGTH]; + addr[AccountAddress::LENGTH - 2] = 4; + addr[AccountAddress::LENGTH - 1] = 3; + AccountAddress::new(addr) +} + +pub fn iota_framework_address_concat_string(suffix: &str) -> String { + format!("{}{suffix}", IOTA_FRAMEWORK_ADDRESS.to_hex_literal()) +} + +/// Parses `s` as an address. Valid formats for addresses are: +/// +/// - A 256bit number, encoded in decimal, or hexadecimal with a leading "0x" +/// prefix. +/// - One of a number of pre-defined named addresses: std, iota, iota_system, +/// deepbook. +/// +/// Parsing succeeds if and only if `s` matches one of these formats exactly, +/// with no remaining suffix. This function is intended for use within the +/// authority codebases. +pub fn parse_iota_address(s: &str) -> anyhow::Result { + use move_command_line_common::address::ParsedAddress; + Ok(ParsedAddress::parse(s)? + .into_account_address(&resolve_address)? + .into()) +} + +/// Parse `s` as a Module ID: An address (see `parse_iota_address`), followed by +/// `::`, and then a module name (an identifier). Parsing succeeds if and only +/// if `s` matches this format exactly, with no remaining input. This function +/// is intended for use within the authority codebases. +pub fn parse_iota_module_id(s: &str) -> anyhow::Result { + use move_command_line_common::types::ParsedModuleId; + ParsedModuleId::parse(s)?.into_module_id(&resolve_address) +} + +/// Parse `s` as a fully-qualified name: A Module ID (see +/// `parse_iota_module_id`), followed by `::`, and then an identifier (for the +/// module member). Parsing succeeds if and only if `s` matches this +/// format exactly, with no remaining input. This function is intended for use +/// within the authority codebases. +pub fn parse_iota_fq_name(s: &str) -> anyhow::Result<(ModuleId, String)> { + use move_command_line_common::types::ParsedFqName; + ParsedFqName::parse(s)?.into_fq_name(&resolve_address) +} + +/// Parse `s` as a struct type: A fully-qualified name, optionally followed by a +/// list of type parameters (types -- see `parse_iota_type_tag`, separated by +/// commas, surrounded by angle brackets). Parsing succeeds if and only if `s` +/// matches this format exactly, with no remaining input. This function is +/// intended for use within the authority codebase. +pub fn parse_iota_struct_tag(s: &str) -> anyhow::Result { + use move_command_line_common::types::ParsedStructType; + ParsedStructType::parse(s)?.into_struct_tag(&resolve_address) +} + +/// Parse `s` as a type: Either a struct type (see `parse_iota_struct_tag`), a +/// primitive type, or a vector with a type parameter. Parsing succeeds if and +/// only if `s` matches this format exactly, with no remaining input. This +/// function is intended for use within the authority codebase. +pub fn parse_iota_type_tag(s: &str) -> anyhow::Result { + use move_command_line_common::types::ParsedType; + ParsedType::parse(s)?.into_type_tag(&resolve_address) +} + +/// Resolve well-known named addresses into numeric addresses. +pub fn resolve_address(addr: &str) -> Option { + match addr { + "deepbook" => Some(DEEPBOOK_ADDRESS), + "std" => Some(MOVE_STDLIB_ADDRESS), + "iota" => Some(IOTA_FRAMEWORK_ADDRESS), + "iota_system" => Some(IOTA_SYSTEM_ADDRESS), + "stardust" => Some(STARDUST_ADDRESS), + "timelock" => Some(TIMELOCK_ADDRESS), + "bridge" => Some(BRIDGE_ADDRESS), + _ => None, + } +} + +pub trait MoveTypeTagTrait { + fn get_type_tag() -> TypeTag; +} + +impl MoveTypeTagTrait for u8 { + fn get_type_tag() -> TypeTag { + TypeTag::U8 + } +} + +impl MoveTypeTagTrait for u64 { + fn get_type_tag() -> TypeTag { + TypeTag::U64 + } +} + +impl MoveTypeTagTrait for ObjectID { + fn get_type_tag() -> TypeTag { + TypeTag::Address + } +} + +impl MoveTypeTagTrait for IotaAddress { + fn get_type_tag() -> TypeTag { + TypeTag::Address + } +} + +impl MoveTypeTagTrait for Vec { + fn get_type_tag() -> TypeTag { + TypeTag::Vector(Box::new(T::get_type_tag())) + } +} + +pub fn is_primitive( + view: &BinaryIndexedView<'_>, + function_type_args: &[AbilitySet], + s: &SignatureToken, +) -> bool { + use SignatureToken as S; + match s { + S::Bool | S::U8 | S::U16 | S::U32 | S::U64 | S::U128 | S::U256 | S::Address => true, + S::Signer => false, + // optimistic, but no primitive has key + S::TypeParameter(idx) => !function_type_args[*idx as usize].has_key(), + + S::Struct(idx) => [RESOLVED_IOTA_ID, RESOLVED_ASCII_STR, RESOLVED_UTF8_STR] + .contains(&resolve_struct(view, *idx)), + + S::StructInstantiation(s) => { + let (idx, targs) = &**s; + let resolved_struct = resolve_struct(view, *idx); + // option is a primitive + resolved_struct == RESOLVED_STD_OPTION + && targs.len() == 1 + && is_primitive(view, function_type_args, &targs[0]) + } + + S::Vector(inner) => is_primitive(view, function_type_args, inner), + S::Reference(_) | S::MutableReference(_) => false, + } +} + +pub fn is_object( + view: &BinaryIndexedView<'_>, + function_type_args: &[AbilitySet], + t: &SignatureToken, +) -> Result { + use SignatureToken as S; + match t { + S::Reference(inner) | S::MutableReference(inner) => { + is_object(view, function_type_args, inner) + } + _ => is_object_struct(view, function_type_args, t), + } +} + +pub fn is_object_vector( + view: &BinaryIndexedView<'_>, + function_type_args: &[AbilitySet], + t: &SignatureToken, +) -> Result { + use SignatureToken as S; + match t { + S::Vector(inner) => is_object_struct(view, function_type_args, inner), + _ => is_object_struct(view, function_type_args, t), + } +} + +fn is_object_struct( + view: &BinaryIndexedView<'_>, + function_type_args: &[AbilitySet], + s: &SignatureToken, +) -> Result { + use SignatureToken as S; + match s { + S::Bool + | S::U8 + | S::U16 + | S::U32 + | S::U64 + | S::U128 + | S::U256 + | S::Address + | S::Signer + | S::Vector(_) + | S::Reference(_) + | S::MutableReference(_) => Ok(false), + S::TypeParameter(idx) => Ok(function_type_args + .get(*idx as usize) + .map(|abs| abs.has_key()) + .unwrap_or(false)), + S::Struct(_) | S::StructInstantiation(_) => { + let abilities = view + .abilities(s, function_type_args) + .map_err(|vm_err| vm_err.to_string())?; + Ok(abilities.has_key()) + } + } +} + +#[cfg(test)] +mod tests { + use expect_test::expect; + + use super::*; + + #[test] + fn test_parse_iota_numeric_address() { + let result = parse_iota_address("0x2").expect("should not error"); + + let expected = + expect!["0x0000000000000000000000000000000000000000000000000000000000000002"]; + expected.assert_eq(&result.to_string()); + } + + #[test] + fn test_parse_iota_named_address() { + let result = parse_iota_address("iota").expect("should not error"); + + let expected = + expect!["0x0000000000000000000000000000000000000000000000000000000000000002"]; + expected.assert_eq(&result.to_string()); + } + + #[test] + fn test_parse_iota_module_id() { + let result = parse_iota_module_id("0x2::iota").expect("should not error"); + let expected = + expect!["0x0000000000000000000000000000000000000000000000000000000000000002::iota"]; + expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); + } + + #[test] + fn test_parse_iota_fq_name() { + let (module, name) = parse_iota_fq_name("0x2::object::new").expect("should not error"); + let expected = expect![ + "0x0000000000000000000000000000000000000000000000000000000000000002::object::new" + ]; + expected.assert_eq(&format!( + "{}::{name}", + module.to_canonical_display(/* with_prefix */ true) + )); + } + + #[test] + fn test_parse_iota_struct_tag_short_account_addr() { + let result = parse_iota_struct_tag("0x2::iota::IOTA").expect("should not error"); + + let expected = expect!["0x2::iota::IOTA"]; + expected.assert_eq(&result.to_string()); + + let expected = expect![ + "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" + ]; + expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); + } + + #[test] + fn test_parse_iota_struct_tag_long_account_addr() { + let result = parse_iota_struct_tag( + "0x00000000000000000000000000000000000000000000000000000000000000002::iota::IOTA", + ) + .expect("should not error"); + + let expected = expect!["0x2::iota::IOTA"]; + expected.assert_eq(&result.to_string()); + + let expected = expect![ + "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA" + ]; + expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); + } + + #[test] + fn test_parse_iota_struct_with_type_param_short_addr() { + let result = + parse_iota_struct_tag("0x2::coin::COIN<0x2::iota::IOTA>").expect("should not error"); + + let expected = expect!["0x2::coin::COIN<0x2::iota::IOTA>"]; + expected.assert_eq(&result.to_string()); + + let expected = expect![ + "0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" + ]; + expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); + } + + #[test] + fn test_parse_iota_struct_with_type_param_long_addr() { + let result = parse_iota_struct_tag("0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>") + .expect("should not error"); + + let expected = expect!["0x2::coin::COIN<0x2::iota::IOTA>"]; + expected.assert_eq(&result.to_string()); + + let expected = expect![ + "0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>" + ]; + expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); + } + + #[test] + fn test_complex_struct_tag_with_short_addr() { + let result = parse_iota_struct_tag( + "0xe7::vec_coin::VecCoin>>", + ) + .expect("should not error"); + + let expected = expect!["0xe7::vec_coin::VecCoin>>"]; + expected.assert_eq(&result.to_string()); + + let expected = expect![ + "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin>>" + ]; + expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); + } + + #[test] + fn test_complex_struct_tag_with_long_addr() { + let result = parse_iota_struct_tag("0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin>>") + .expect("should not error"); + + let expected = expect!["0xe7::vec_coin::VecCoin>>"]; + expected.assert_eq(&result.to_string()); + + let expected = expect![ + "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin>>" + ]; + expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); + } + + #[test] + fn test_dynamic_field_short_addr() { + let result = parse_iota_struct_tag( + "0x2::dynamic_field::Field>", + ) + .expect("should not error"); + + let expected = expect![ + "0x2::dynamic_field::Field>" + ]; + expected.assert_eq(&result.to_string()); + + let expected = expect![ + "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field>" + ]; + expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); + } + + #[test] + fn test_dynamic_field_long_addr() { + let result = parse_iota_struct_tag( + "0x2::dynamic_field::Field>", + ) + .expect("should not error"); + + let expected = expect![ + "0x2::dynamic_field::Field>" + ]; + expected.assert_eq(&result.to_string()); + + let expected = expect![ + "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field>" + ]; + expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); + } +} diff --git a/crates/sui-types/src/message_envelope.rs b/crates/iota-types/src/message_envelope.rs similarity index 93% rename from crates/sui-types/src/message_envelope.rs rename to crates/iota-types/src/message_envelope.rs index e811b3dfc83..d52f1a74a25 100644 --- a/crates/sui-types/src/message_envelope.rs +++ b/crates/iota-types/src/message_envelope.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -8,10 +9,10 @@ use std::{ }; use fastcrypto::traits::KeyPair; +use iota_protocol_config::ProtocolConfig; use once_cell::sync::OnceCell; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use shared_crypto::intent::{Intent, IntentScope}; -use sui_protocol_config::ProtocolConfig; use crate::{ base_types::AuthorityName, @@ -20,7 +21,7 @@ use crate::{ AuthorityKeyPair, AuthorityQuorumSignInfo, AuthoritySignInfo, AuthoritySignInfoTrait, AuthoritySignature, AuthorityStrongQuorumSignInfo, EmptySignInfo, Signer, }, - error::SuiResult, + error::IotaResult, executable_transaction::CertificateProof, messages_checkpoint::CheckpointSequenceNumber, signature::VerifyParams, @@ -107,22 +108,22 @@ pub trait Message { fn digest(&self) -> Self::DigestType; /// Perform cheap validity checks before any expensive crypto verification. - fn verify_user_input(&self) -> SuiResult; + fn verify_user_input(&self) -> IotaResult; /// Verify that the message is from the correct epoch (e.g. for /// CertifiedCheckpointSummary we verify that the checkpoint is from the /// same epoch as the committee signatures). - fn verify_epoch(&self, epoch: EpochId) -> SuiResult; + fn verify_epoch(&self, epoch: EpochId) -> IotaResult; } /// A message type that has an internal authenticator, such as SenderSignedData pub trait AuthenticatedMessage { /// Verify internal signatures, e.g. for Transaction we verify the user /// signature(s). - fn verify_message_signature(&self, verify_params: &VerifyParams) -> SuiResult; + fn verify_message_signature(&self, verify_params: &VerifyParams) -> IotaResult; /// Checks that still need to be verified outside cache. - fn verify_uncached_checks(&self, verify_params: &VerifyParams) -> SuiResult; + fn verify_uncached_checks(&self, verify_params: &VerifyParams) -> IotaResult; } /// A marker trait to indicate !AuthenticatedMessage since rust does not allow @@ -191,7 +192,7 @@ impl Envelope { } impl VersionedProtocolMessage for Envelope { - fn check_version_supported(&self, protocol_config: &ProtocolConfig) -> SuiResult { + fn check_version_supported(&self, protocol_config: &ProtocolConfig) -> IotaResult { self.data.check_version_supported(protocol_config) } } @@ -213,14 +214,14 @@ impl Envelope { } impl Envelope { - pub fn verify_signature(&self, verify_params: &VerifyParams) -> SuiResult { + pub fn verify_signature(&self, verify_params: &VerifyParams) -> IotaResult { self.data.verify_message_signature(verify_params) } pub fn verify( self, verify_params: &VerifyParams, - ) -> SuiResult> { + ) -> IotaResult> { self.verify_signature(verify_params)?; Ok(VerifiedEnvelope::::new_from_verified( self, @@ -252,20 +253,20 @@ where secret: &dyn Signer, authority: AuthorityName, ) -> AuthoritySignInfo { - AuthoritySignInfo::new(epoch, &data, Intent::sui_app(T::SCOPE), authority, secret) + AuthoritySignInfo::new(epoch, &data, Intent::iota_app(T::SCOPE), authority, secret) } pub fn epoch(&self) -> EpochId { self.auth_signature.epoch } - pub fn verify_committee_sigs_only(&self, committee: &Committee) -> SuiResult + pub fn verify_committee_sigs_only(&self, committee: &Committee) -> IotaResult where ::DigestType: PartialEq, { self.data.verify_epoch(self.auth_sig().epoch)?; self.auth_signature - .verify_secure(self.data(), Intent::sui_app(T::SCOPE), committee) + .verify_secure(self.data(), Intent::iota_app(T::SCOPE), committee) } } @@ -277,18 +278,18 @@ where &self, committee: &Committee, verify_params: &VerifyParams, - ) -> SuiResult { + ) -> IotaResult { self.data.verify_epoch(self.auth_sig().epoch)?; self.data.verify_message_signature(verify_params)?; self.auth_signature - .verify_secure(self.data(), Intent::sui_app(T::SCOPE), committee) + .verify_secure(self.data(), Intent::iota_app(T::SCOPE), committee) } pub fn verify_authenticated( self, committee: &Committee, verify_params: &VerifyParams, - ) -> SuiResult> { + ) -> IotaResult> { self.verify_signatures_authenticated(committee, verify_params)?; Ok(VerifiedEnvelope::::new_from_verified( self, @@ -300,16 +301,16 @@ impl Envelope where T: Message + UnauthenticatedMessage + Serialize, { - pub fn verify_authority_signatures(&self, committee: &Committee) -> SuiResult { + pub fn verify_authority_signatures(&self, committee: &Committee) -> IotaResult { self.data.verify_epoch(self.auth_sig().epoch)?; self.auth_signature - .verify_secure(self.data(), Intent::sui_app(T::SCOPE), committee) + .verify_secure(self.data(), Intent::iota_app(T::SCOPE), committee) } pub fn verify( self, committee: &Committee, - ) -> SuiResult> { + ) -> IotaResult> { self.verify_authority_signatures(committee)?; Ok(VerifiedEnvelope::::new_from_verified( self, @@ -325,7 +326,7 @@ where data: T, signatures: Vec, committee: &Committee, - ) -> SuiResult { + ) -> IotaResult { let cert = Self { digest: OnceCell::new(), data, @@ -348,7 +349,7 @@ where AuthoritySignInfo::new( committee.epoch(), &data, - Intent::sui_app(T::SCOPE), + Intent::iota_app(T::SCOPE), keypair.public().into(), keypair, ) @@ -372,29 +373,29 @@ where &self, committee: &Committee, verify_params: &VerifyParams, - ) -> SuiResult { + ) -> IotaResult { self.data.verify_epoch(self.auth_sig().epoch)?; self.data.verify_message_signature(verify_params)?; self.auth_signature - .verify_secure(self.data(), Intent::sui_app(T::SCOPE), committee) + .verify_secure(self.data(), Intent::iota_app(T::SCOPE), committee) } pub fn verify_authenticated( self, committee: &Committee, verify_params: &VerifyParams, - ) -> SuiResult>> { + ) -> IotaResult>> { self.verify_signatures_authenticated(committee, verify_params)?; Ok(VerifiedEnvelope::>::new_from_verified(self)) } - pub fn verify_committee_sigs_only(&self, committee: &Committee) -> SuiResult + pub fn verify_committee_sigs_only(&self, committee: &Committee) -> IotaResult where ::DigestType: PartialEq, { self.data.verify_epoch(self.auth_sig().epoch)?; self.auth_signature - .verify_secure(self.data(), Intent::sui_app(T::SCOPE), committee) + .verify_secure(self.data(), Intent::iota_app(T::SCOPE), committee) } } @@ -402,16 +403,16 @@ impl Envelope> where T: Message + UnauthenticatedMessage + Serialize, { - pub fn verify_authority_signatures(&self, committee: &Committee) -> SuiResult { + pub fn verify_authority_signatures(&self, committee: &Committee) -> IotaResult { self.data.verify_epoch(self.auth_sig().epoch)?; self.auth_signature - .verify_secure(self.data(), Intent::sui_app(T::SCOPE), committee) + .verify_secure(self.data(), Intent::iota_app(T::SCOPE), committee) } pub fn verify( self, committee: &Committee, - ) -> SuiResult>> { + ) -> IotaResult>> { self.verify_authority_signatures(committee)?; Ok(VerifiedEnvelope::>::new_from_verified(self)) } @@ -516,7 +517,7 @@ impl VerifiedEnvelope { } impl VersionedProtocolMessage for VerifiedEnvelope { - fn check_version_supported(&self, protocol_config: &ProtocolConfig) -> SuiResult { + fn check_version_supported(&self, protocol_config: &ProtocolConfig) -> IotaResult { self.inner().check_version_supported(protocol_config) } } diff --git a/crates/sui-types/src/messages_checkpoint.rs b/crates/iota-types/src/messages_checkpoint.rs similarity index 98% rename from crates/sui-types/src/messages_checkpoint.rs rename to crates/iota-types/src/messages_checkpoint.rs index a748a14b169..edd870e446c 100644 --- a/crates/sui-types/src/messages_checkpoint.rs +++ b/crates/iota-types/src/messages_checkpoint.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -30,14 +31,14 @@ use crate::{ }, digests::Digest, effects::{TestEffectsBuilder, TransactionEffectsAPI}, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, gas::GasCostSummary, + iota_serde::{AsProtocolVersion, BigInt, Readable}, message_envelope::{ Envelope, Message, TrustedEnvelope, UnauthenticatedMessage, VerifiedEnvelope, }, signature::GenericSignature, storage::ReadStore, - sui_serde::{AsProtocolVersion, BigInt, Readable}, transaction::{Transaction, TransactionData}, }; @@ -205,14 +206,14 @@ impl Message for CheckpointSummary { CheckpointDigest::new(default_hash(self)) } - fn verify_user_input(&self) -> SuiResult { + fn verify_user_input(&self) -> IotaResult { Ok(()) } - fn verify_epoch(&self, epoch: EpochId) -> SuiResult { + fn verify_epoch(&self, epoch: EpochId) -> IotaResult { fp_ensure!( self.epoch == epoch, - SuiError::WrongEpoch { + IotaError::WrongEpoch { expected_epoch: epoch, actual_epoch: self.epoch, } @@ -316,14 +317,14 @@ impl CertifiedCheckpointSummary { &self, committee: &Committee, contents: Option<&CheckpointContents>, - ) -> SuiResult { + ) -> IotaResult { self.verify_authority_signatures(committee)?; if let Some(contents) = contents { let content_digest = *contents.digest(); fp_ensure!( content_digest == self.data().content_digest, - SuiError::GenericAuthorityError { + IotaError::GenericAuthorityError { error: format!( "Checkpoint contents digest mismatch: summary={:?}, received content digest {:?}, received {} transactions", self.data(), @@ -361,7 +362,7 @@ pub struct CheckpointSignatureMessage { } impl CheckpointSignatureMessage { - pub fn verify(&self, committee: &Committee) -> SuiResult { + pub fn verify(&self, committee: &Committee) -> IotaResult { self.summary.verify_authority_signatures(committee) } } diff --git a/crates/sui-types/src/messages_consensus.rs b/crates/iota-types/src/messages_consensus.rs similarity index 97% rename from crates/sui-types/src/messages_consensus.rs rename to crates/iota-types/src/messages_consensus.rs index 735f5df51b9..8b3a9d995f6 100644 --- a/crates/sui-types/src/messages_consensus.rs +++ b/crates/iota-types/src/messages_consensus.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -12,8 +13,8 @@ use byteorder::{BigEndian, ReadBytesExt}; use fastcrypto::groups::bls12381; use fastcrypto_tbls::dkg; use fastcrypto_zkp::bn254::zk_login::{JwkId, JWK}; +use iota_protocol_config::SupportedProtocolVersions; use serde::{Deserialize, Serialize}; -use sui_protocol_config::SupportedProtocolVersions; use crate::{ base_types::{AuthorityName, ConciseableName, ObjectRef, TransactionDigest}, @@ -62,7 +63,7 @@ pub fn check_total_jwk_size(id: &JwkId, jwk: &JWK) -> bool { #[derive(Serialize, Deserialize, Clone, Debug)] pub struct ConsensusTransaction { /// Encodes an u64 unique tracking id to allow us trace a message between - /// Sui and Narwhal. Use an byte array instead of u64 to ensure stable + /// Iota and Narwhal. Use an byte array instead of u64 to ensure stable /// serialization. pub tracking_id: [u8; 8], pub kind: ConsensusTransactionKind, @@ -160,10 +161,10 @@ impl AuthorityCapabilities { ) -> Self { let generation = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Sui did not exist prior to 1970") + .expect("Iota did not exist prior to 1970") .as_millis() .try_into() - .expect("This build of sui is not supported in the year 500,000,000"); + .expect("This build of iota is not supported in the year 500,000,000"); Self { authority, generation, diff --git a/crates/sui-types/src/messages_grpc.rs b/crates/iota-types/src/messages_grpc.rs similarity index 98% rename from crates/sui-types/src/messages_grpc.rs rename to crates/iota-types/src/messages_grpc.rs index b14b509840a..894f49d5361 100644 --- a/crates/sui-types/src/messages_grpc.rs +++ b/crates/iota-types/src/messages_grpc.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use move_core_types::annotated_value::MoveStructLayout; @@ -79,7 +80,7 @@ pub struct ObjectInfoResponse { pub layout: Option, /// Transaction the object is locked on in this authority. /// None if the object is not currently locked by this authority. - /// This should be only used for debugging purpose, such as from sui-tool. + /// This should be only used for debugging purpose, such as from iota-tool. /// No prod clients should rely on it. pub lock_for_debugging: Option, } diff --git a/crates/sui-types/src/messages_safe_client.rs b/crates/iota-types/src/messages_safe_client.rs similarity index 96% rename from crates/sui-types/src/messages_safe_client.rs rename to crates/iota-types/src/messages_safe_client.rs index 71a459caaec..4707d547a53 100644 --- a/crates/sui-types/src/messages_safe_client.rs +++ b/crates/iota-types/src/messages_safe_client.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use crate::{ diff --git a/crates/iota-types/src/metrics.rs b/crates/iota-types/src/metrics.rs new file mode 100644 index 00000000000..50895782d44 --- /dev/null +++ b/crates/iota-types/src/metrics.rs @@ -0,0 +1,141 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use prometheus::{ + register_histogram_with_registry, register_int_counter_vec_with_registry, Histogram, + IntCounterVec, +}; + +pub struct LimitsMetrics { + /// Execution limits metrics + pub excessive_estimated_effects_size: IntCounterVec, + pub excessive_written_objects_size: IntCounterVec, + pub excessive_new_move_object_ids: IntCounterVec, + pub excessive_deleted_move_object_ids: IntCounterVec, + pub excessive_transferred_move_object_ids: IntCounterVec, + pub excessive_object_runtime_cached_objects: IntCounterVec, + pub excessive_object_runtime_store_entries: IntCounterVec, +} + +impl LimitsMetrics { + pub fn new(registry: &prometheus::Registry) -> LimitsMetrics { + Self { + excessive_estimated_effects_size: register_int_counter_vec_with_registry!( + "excessive_estimated_effects_size", + "Number of transactions with estimated effects size exceeding the limit", + &["metered", "limit_type"], + registry, + ) + .unwrap(), + excessive_written_objects_size: register_int_counter_vec_with_registry!( + "excessive_written_objects_size", + "Number of transactions with written objects size exceeding the limit", + &["metered", "limit_type"], + registry, + ) + .unwrap(), + excessive_new_move_object_ids: register_int_counter_vec_with_registry!( + "excessive_new_move_object_ids_size", + "Number of transactions with new move object ID count exceeding the limit", + &["metered", "limit_type"], + registry, + ) + .unwrap(), + excessive_deleted_move_object_ids: register_int_counter_vec_with_registry!( + "excessive_deleted_move_object_ids_size", + "Number of transactions with deleted move object ID count exceeding the limit", + &["metered", "limit_type"], + registry, + ) + .unwrap(), + excessive_transferred_move_object_ids: register_int_counter_vec_with_registry!( + "excessive_transferred_move_object_ids_size", + "Number of transactions with transferred move object ID count exceeding the limit", + &["metered", "limit_type"], + registry, + ) + .unwrap(), + excessive_object_runtime_cached_objects: register_int_counter_vec_with_registry!( + "excessive_object_runtime_cached_objects_size", + "Number of transactions with object runtime cached object count exceeding the limit", + &["metered", "limit_type"], + registry, + ) + .unwrap(), + excessive_object_runtime_store_entries: register_int_counter_vec_with_registry!( + "excessive_object_runtime_store_entries_size", + "Number of transactions with object runtime store entry count exceeding the limit", + &["metered", "limit_type"], + registry, + ) + .unwrap(), + } + } +} + +pub struct BytecodeVerifierMetrics { + /// Bytecode verifier metrics timeout counter + pub verifier_timeout_metrics: IntCounterVec, + /// Bytecode verifier runtime latency for each module successfully verified + pub verifier_runtime_per_module_success_latency: Histogram, + /// Bytecode verifier runtime latency for each programmable transaction + /// block successfully verified + pub verifier_runtime_per_ptb_success_latency: Histogram, + /// Bytecode verifier runtime latency for each module which timed out + pub verifier_runtime_per_module_timeout_latency: Histogram, + /// Bytecode verifier runtime latency for each programmable transaction + /// block which timed out + pub verifier_runtime_per_ptb_timeout_latency: Histogram, +} + +impl BytecodeVerifierMetrics { + pub const MOVE_VERIFIER_TAG: &'static str = "move_verifier"; + pub const IOTA_VERIFIER_TAG: &'static str = "iota_verifier"; + pub const OVERALL_TAG: &'static str = "overall"; + pub const SUCCESS_TAG: &'static str = "success"; + pub const TIMEOUT_TAG: &'static str = "failed"; + const LATENCY_SEC_BUCKETS: &'static [f64] = &[ + 0.000_010, 0.000_025, 0.000_050, 0.000_100, // sub 100 micros + 0.000_250, 0.000_500, 0.001_000, 0.002_500, 0.005_000, 0.010_000, // sub 10 ms: p99 + 0.025_000, 0.050_000, 0.100_000, 0.250_000, 0.500_000, 1.000_000, // sub 1 s + 10.000_000, 20.000_000, 50.000_000, 100.0, // We should almost never get here + ]; + pub fn new(registry: &prometheus::Registry) -> Self { + Self { + verifier_timeout_metrics: register_int_counter_vec_with_registry!( + "verifier_timeout_metrics", + "Number of timeouts in bytecode verifier", + &["verifier_meter", "status"], + registry, + ) + .unwrap(), + verifier_runtime_per_module_success_latency: register_histogram_with_registry!( + "verifier_runtime_per_module_success_latency", + "Time spent running bytecode verifier to completion at `run_metered_move_bytecode_verifier_impl`", + Self::LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + verifier_runtime_per_ptb_success_latency: register_histogram_with_registry!( + "verifier_runtime_per_ptb_success_latency", + "Time spent running bytecode verifier to completion over the entire PTB at `transaction_input_checker::check_non_system_packages_to_be_published`", + Self::LATENCY_SEC_BUCKETS.to_vec(), + registry + ).unwrap(), + verifier_runtime_per_module_timeout_latency: register_histogram_with_registry!( + "verifier_runtime_per_module_timeout_latency", + "Time spent running bytecode verifier to timeout at `run_metered_move_bytecode_verifier_impl`", + Self::LATENCY_SEC_BUCKETS.to_vec(), + registry + ) + .unwrap(), + verifier_runtime_per_ptb_timeout_latency: register_histogram_with_registry!( + "verifier_runtime_per_ptb_timeout_latency", + "Time spent running bytecode verifier to timeout over the entire PTB at `transaction_input_checker::check_non_system_packages_to_be_published`", + Self::LATENCY_SEC_BUCKETS.to_vec(), + registry + ).unwrap(), + } + } +} diff --git a/crates/sui-types/src/mock_checkpoint_builder.rs b/crates/iota-types/src/mock_checkpoint_builder.rs similarity index 97% rename from crates/sui-types/src/mock_checkpoint_builder.rs rename to crates/iota-types/src/mock_checkpoint_builder.rs index b07cad60381..22df90575c7 100644 --- a/crates/sui-types/src/mock_checkpoint_builder.rs +++ b/crates/iota-types/src/mock_checkpoint_builder.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::mem; @@ -8,7 +9,7 @@ use fastcrypto::traits::Signer; use crate::{ base_types::{AuthorityName, VerifiedExecutionData}, committee::Committee, - crypto::{AuthoritySignInfo, AuthoritySignature, SuiAuthoritySignature}, + crypto::{AuthoritySignInfo, AuthoritySignature, IotaAuthoritySignature}, effects::{TransactionEffects, TransactionEffectsAPI}, gas::GasCostSummary, messages_checkpoint::{ @@ -170,7 +171,7 @@ impl MockCheckpointBuilder { .iter() .map(|(name, _)| { let intent_msg = shared_crypto::intent::IntentMessage::new( - shared_crypto::intent::Intent::sui_app( + shared_crypto::intent::Intent::iota_app( shared_crypto::intent::IntentScope::CheckpointSummary, ), &checkpoint, diff --git a/crates/iota-types/src/move_package.rs b/crates/iota-types/src/move_package.rs new file mode 100644 index 00000000000..59b69be6a95 --- /dev/null +++ b/crates/iota-types/src/move_package.rs @@ -0,0 +1,756 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::{BTreeMap, BTreeSet}; + +use derive_more::Display; +use fastcrypto::hash::HashFunction; +use iota_protocol_config::ProtocolConfig; +use move_binary_format::{ + access::ModuleAccess, binary_config::BinaryConfig, binary_views::BinaryIndexedView, + file_format::CompiledModule, normalized, +}; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::{IdentStr, Identifier}, + language_storage::{ModuleId, StructTag}, +}; +use move_disassembler::disassembler::Disassembler; +use move_ir_types::location::Spanned; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use serde_with::{serde_as, Bytes}; + +use crate::{ + base_types::{ObjectID, SequenceNumber}, + crypto::DefaultHash, + error::{ExecutionError, ExecutionErrorKind, IotaError, IotaResult}, + execution_status::PackageUpgradeError, + id::{ID, UID}, + object::OBJECT_START_VERSION, + IOTA_FRAMEWORK_ADDRESS, +}; + +// TODO: robust MovePackage tests +// #[cfg(test)] +// #[path = "unit_tests/move_package.rs"] +// mod base_types_tests; + +pub const PACKAGE_MODULE_NAME: &IdentStr = ident_str!("package"); +pub const UPGRADECAP_STRUCT_NAME: &IdentStr = ident_str!("UpgradeCap"); +pub const UPGRADETICKET_STRUCT_NAME: &IdentStr = ident_str!("UpgradeTicket"); +pub const UPGRADERECEIPT_STRUCT_NAME: &IdentStr = ident_str!("UpgradeReceipt"); + +#[derive(Clone, Debug)] +/// Additional information about a function +pub struct FnInfo { + /// If true, it's a function involved in testing (`[test]`, `[test_only]`, + /// `[expected_failure]`) + pub is_test: bool, +} + +#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +/// Uniquely identifies a function in a module +pub struct FnInfoKey { + pub fn_name: String, + pub mod_addr: AccountAddress, +} + +/// A map from function info keys to function info +pub type FnInfoMap = BTreeMap; + +/// Identifies a struct and the module it was defined in +#[derive( + Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize, Hash, JsonSchema, +)] +pub struct TypeOrigin { + pub module_name: String, + pub struct_name: String, + pub package: ObjectID, +} + +/// Upgraded package info for the linkage table +#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash, JsonSchema)] +pub struct UpgradeInfo { + /// ID of the upgraded packages + pub upgraded_id: ObjectID, + /// Version of the upgraded package + pub upgraded_version: SequenceNumber, +} + +// serde_bytes::ByteBuf is an analog of Vec with built-in fast +// serialization. +#[serde_as] +#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)] +pub struct MovePackage { + id: ObjectID, + /// Most move packages are uniquely identified by their ID (i.e. there is + /// only one version per ID), but the version is still stored because + /// one package may be an upgrade of another (at a different ID), in + /// which case its version will be one greater than the version of the + /// upgraded package. + /// + /// Framework packages are an exception to this rule -- all versions of the + /// framework packages exist at the same ID, at increasing versions. + /// + /// In all cases, packages are referred to by move calls using just their + /// ID, and they are always loaded at their latest version. + version: SequenceNumber, + // TODO use session cache + #[serde_as(as = "BTreeMap<_, Bytes>")] + module_map: BTreeMap>, + + /// Maps struct/module to a package version where it was first defined, + /// stored as a vector for simple serialization and deserialization. + type_origin_table: Vec, + + // For each dependency, maps original package ID to the info about the (upgraded) dependency + // version that this package is using + linkage_table: BTreeMap, +} + +// NB: do _not_ add `Serialize` or `Deserialize` to this enum. Convert to u8 +// first or use the associated constants before storing in any serialization +// setting. +/// Rust representation of upgrade policy constants in `iota::package`. +#[repr(u8)] +#[derive(Display, Debug, Clone, Copy)] +pub enum UpgradePolicy { + #[display(fmt = "COMPATIBLE")] + Compatible = 0, + #[display(fmt = "ADDITIVE")] + Additive = 128, + #[display(fmt = "DEP_ONLY")] + DepOnly = 192, +} + +impl UpgradePolicy { + /// Convenience accessors to the upgrade policies as u8s. + pub const COMPATIBLE: u8 = Self::Compatible as u8; + pub const ADDITIVE: u8 = Self::Additive as u8; + pub const DEP_ONLY: u8 = Self::DepOnly as u8; + + pub fn is_valid_policy(policy: &u8) -> bool { + Self::try_from(*policy).is_ok() + } +} + +impl TryFrom for UpgradePolicy { + type Error = (); + fn try_from(value: u8) -> Result { + match value { + x if x == Self::Compatible as u8 => Ok(Self::Compatible), + x if x == Self::Additive as u8 => Ok(Self::Additive), + x if x == Self::DepOnly as u8 => Ok(Self::DepOnly), + _ => Err(()), + } + } +} + +/// Rust representation of `iota::package::UpgradeCap`. +#[derive(Debug, Serialize, Deserialize)] +pub struct UpgradeCap { + pub id: UID, + pub package: ID, + pub version: u64, + pub policy: u8, +} + +/// Rust representation of `iota::package::UpgradeTicket`. +#[derive(Debug, Serialize, Deserialize)] +pub struct UpgradeTicket { + pub cap: ID, + pub package: ID, + pub policy: u8, + pub digest: Vec, +} + +/// Rust representation of `iota::package::UpgradeReceipt`. +#[derive(Debug, Serialize, Deserialize)] +pub struct UpgradeReceipt { + pub cap: ID, + pub package: ID, +} + +impl MovePackage { + /// Create a package with all required data (including serialized modules, + /// type origin and linkage tables) already supplied. + pub fn new( + id: ObjectID, + version: SequenceNumber, + module_map: BTreeMap>, + max_move_package_size: u64, + type_origin_table: Vec, + linkage_table: BTreeMap, + ) -> Result { + let pkg = Self { + id, + version, + module_map, + type_origin_table, + linkage_table, + }; + let object_size = pkg.size() as u64; + if object_size > max_move_package_size { + return Err(ExecutionErrorKind::MovePackageTooBig { + object_size, + max_object_size: max_move_package_size, + } + .into()); + } + Ok(pkg) + } + + pub fn digest(&self, hash_modules: bool) -> [u8; 32] { + Self::compute_digest_for_modules_and_deps( + self.module_map.values(), + self.linkage_table + .values() + .map(|UpgradeInfo { upgraded_id, .. }| upgraded_id), + hash_modules, + ) + } + + /// It is important that this function is shared across both the calculation + /// of the digest for the package, and the calculation of the digest + /// on-chain. + pub fn compute_digest_for_modules_and_deps<'a>( + modules: impl IntoIterator>, + object_ids: impl IntoIterator, + hash_modules: bool, + ) -> [u8; 32] { + let mut module_digests: Vec<[u8; 32]>; + let mut components: Vec<&[u8]> = vec![]; + if !hash_modules { + for module in modules { + components.push(module.as_ref()) + } + } else { + module_digests = vec![]; + for module in modules { + let mut digest = DefaultHash::default(); + digest.update(module); + module_digests.push(digest.finalize().digest); + } + components.extend(module_digests.iter().map(|d| d.as_ref())) + } + + components.extend(object_ids.into_iter().map(|o| o.as_ref())); + // NB: sorting so the order of the modules and the order of the dependencies + // does not matter. + components.sort(); + + let mut digest = DefaultHash::default(); + for c in components { + digest.update(c); + } + digest.finalize().digest + } + + /// Create an initial version of the package along with this version's type + /// origin and linkage tables. + pub fn new_initial<'p>( + modules: &[CompiledModule], + max_move_package_size: u64, + transitive_dependencies: impl IntoIterator, + ) -> Result { + let module = modules + .first() + .expect("Tried to build a Move package from an empty iterator of Compiled modules"); + let runtime_id = ObjectID::from(*module.address()); + let storage_id = runtime_id; + let type_origin_table = build_initial_type_origin_table(modules); + Self::from_module_iter_with_type_origin_table( + storage_id, + runtime_id, + OBJECT_START_VERSION, + modules, + max_move_package_size, + type_origin_table, + transitive_dependencies, + ) + } + + /// Create an upgraded version of the package along with this version's type + /// origin and linkage tables. + pub fn new_upgraded<'p>( + &self, + storage_id: ObjectID, + modules: &[CompiledModule], + protocol_config: &ProtocolConfig, + transitive_dependencies: impl IntoIterator, + ) -> Result { + let module = modules + .first() + .expect("Tried to build a Move package from an empty iterator of Compiled modules"); + let runtime_id = ObjectID::from(*module.address()); + let type_origin_table = + build_upgraded_type_origin_table(self, modules, storage_id, protocol_config)?; + let mut new_version = self.version(); + new_version.increment(); + Self::from_module_iter_with_type_origin_table( + storage_id, + runtime_id, + new_version, + modules, + protocol_config.max_move_package_size(), + type_origin_table, + transitive_dependencies, + ) + } + + pub fn new_system( + version: SequenceNumber, + modules: &[CompiledModule], + dependencies: impl IntoIterator, + ) -> Self { + let module = modules + .first() + .expect("Tried to build a Move package from an empty iterator of Compiled modules"); + + let storage_id = ObjectID::from(*module.address()); + let type_origin_table = build_initial_type_origin_table(modules); + + let linkage_table = BTreeMap::from_iter(dependencies.into_iter().map(|dep| { + let info = UpgradeInfo { + upgraded_id: dep, + // The upgraded version is used by other packages that transitively depend on this + // system package, to make sure that if they choose a different version to depend on + // compared to their dependencies, they pick a greater version. + // + // However, in the case of system packages, although they can be upgraded, unlike + // other packages, only one version can be in use on the network at any given time, + // so it is not possible for a package to require a different system package version + // compared to its dependencies. + // + // This reason, coupled with the fact that system packages can only depend on each + // other, mean that their own linkage tables always report a version of zero. + upgraded_version: SequenceNumber::new(), + }; + (dep, info) + })); + + let module_map = BTreeMap::from_iter(modules.iter().map(|module| { + let name = module.name().to_string(); + let mut bytes = Vec::new(); + module.serialize(&mut bytes).unwrap(); + (name, bytes) + })); + + Self::new( + storage_id, + version, + module_map, + u64::MAX, // System packages are not subject to the size limit + type_origin_table, + linkage_table, + ) + .expect("System packages are not subject to a size limit") + } + + fn from_module_iter_with_type_origin_table<'p>( + storage_id: ObjectID, + self_id: ObjectID, + version: SequenceNumber, + modules: &[CompiledModule], + max_move_package_size: u64, + type_origin_table: Vec, + transitive_dependencies: impl IntoIterator, + ) -> Result { + let mut module_map = BTreeMap::new(); + let mut immediate_dependencies = BTreeSet::new(); + + for module in modules { + let name = module.name().to_string(); + + immediate_dependencies.extend( + module + .immediate_dependencies() + .into_iter() + .map(|dep| ObjectID::from(*dep.address())), + ); + + let mut bytes = Vec::new(); + module.serialize(&mut bytes).unwrap(); + module_map.insert(name, bytes); + } + + immediate_dependencies.remove(&self_id); + let linkage_table = build_linkage_table(immediate_dependencies, transitive_dependencies)?; + Self::new( + storage_id, + version, + module_map, + max_move_package_size, + type_origin_table, + linkage_table, + ) + } + + // Retrieve the module with `ModuleId` in the given package. + // The module must be the `storage_id` or the call will return `None`. + // Check if the address of the module is the same of the package + // and return `None` if that is not the case. + // All modules in a package share the address with the package. + pub fn get_module(&self, storage_id: &ModuleId) -> Option<&Vec> { + if self.id != ObjectID::from(*storage_id.address()) { + None + } else { + self.module_map.get(&storage_id.name().to_string()) + } + } + + /// Return the size of the package in bytes + pub fn size(&self) -> usize { + let module_map_size = self + .module_map + .iter() + .map(|(name, module)| name.len() + module.len()) + .sum::(); + let type_origin_table_size = self + .type_origin_table + .iter() + .map( + |TypeOrigin { + module_name, + struct_name, + .. + }| module_name.len() + struct_name.len() + ObjectID::LENGTH, + ) + .sum::(); + + let linkage_table_size = self.linkage_table.len() + * (ObjectID::LENGTH + + ( + ObjectID::LENGTH + 8 + // SequenceNumber + )); + + 8 /* SequenceNumber */ + module_map_size + type_origin_table_size + linkage_table_size + } + + pub fn id(&self) -> ObjectID { + self.id + } + + pub fn version(&self) -> SequenceNumber { + self.version + } + + pub fn decrement_version(&mut self) { + self.version.decrement(); + } + + pub fn increment_version(&mut self) { + self.version.increment(); + } + + /// Approximate size of the package in bytes. This is used for gas metering. + pub fn object_size_for_gas_metering(&self) -> usize { + self.size() + } + + pub fn serialized_module_map(&self) -> &BTreeMap> { + &self.module_map + } + + pub fn type_origin_table(&self) -> &Vec { + &self.type_origin_table + } + + pub fn type_origin_map(&self) -> BTreeMap<(String, String), ObjectID> { + self.type_origin_table + .iter() + .map( + |TypeOrigin { + module_name, + struct_name, + package, + }| { ((module_name.clone(), struct_name.clone()), *package) }, + ) + .collect() + } + + pub fn linkage_table(&self) -> &BTreeMap { + &self.linkage_table + } + + /// The ObjectID that this package's modules believe they are from, at + /// runtime (can differ from `MovePackage::id()` in the case of package + /// upgrades). + pub fn original_package_id(&self) -> ObjectID { + let bytes = self.module_map.values().next().expect("Empty module map"); + let module = CompiledModule::deserialize_with_defaults(bytes) + .expect("A Move package contains a module that cannot be deserialized"); + (*module.address()).into() + } + + pub fn deserialize_module( + &self, + module: &Identifier, + binary_config: &BinaryConfig, + ) -> IotaResult { + // TODO use the session's cache + let bytes = self + .serialized_module_map() + .get(module.as_str()) + .ok_or_else(|| IotaError::ModuleNotFound { + module_name: module.to_string(), + })?; + CompiledModule::deserialize_with_config(bytes, binary_config).map_err(|error| { + IotaError::ModuleDeserializationFailure { + error: error.to_string(), + } + }) + } + + pub fn disassemble(&self) -> IotaResult> { + disassemble_modules(self.module_map.values()) + } + + pub fn normalize( + &self, + binary_config: &BinaryConfig, + ) -> IotaResult> { + normalize_modules(self.module_map.values(), binary_config) + } +} + +impl UpgradeCap { + pub fn type_() -> StructTag { + StructTag { + address: IOTA_FRAMEWORK_ADDRESS, + module: PACKAGE_MODULE_NAME.to_owned(), + name: UPGRADECAP_STRUCT_NAME.to_owned(), + type_params: vec![], + } + } + + /// Create an `UpgradeCap` for the newly published package at `package_id`, + /// and associate it with the fresh `uid`. + pub fn new(uid: ObjectID, package_id: ObjectID) -> Self { + UpgradeCap { + id: UID::new(uid), + package: ID::new(package_id), + version: 1, + policy: UpgradePolicy::COMPATIBLE, + } + } +} + +impl UpgradeTicket { + pub fn type_() -> StructTag { + StructTag { + address: IOTA_FRAMEWORK_ADDRESS, + module: PACKAGE_MODULE_NAME.to_owned(), + name: UPGRADETICKET_STRUCT_NAME.to_owned(), + type_params: vec![], + } + } +} + +impl UpgradeReceipt { + pub fn type_() -> StructTag { + StructTag { + address: IOTA_FRAMEWORK_ADDRESS, + module: PACKAGE_MODULE_NAME.to_owned(), + name: UPGRADERECEIPT_STRUCT_NAME.to_owned(), + type_params: vec![], + } + } + + /// Create an `UpgradeReceipt` for the upgraded package at `package_id` + /// using the `UpgradeTicket` and newly published package id. + pub fn new(upgrade_ticket: UpgradeTicket, upgraded_package_id: ObjectID) -> Self { + UpgradeReceipt { + cap: upgrade_ticket.cap, + package: ID::new(upgraded_package_id), + } + } +} + +/// Checks if a function is annotated with one of the test-related annotations +pub fn is_test_fun(name: &IdentStr, module: &CompiledModule, fn_info_map: &FnInfoMap) -> bool { + let fn_name = name.to_string(); + let mod_handle = module.self_handle(); + let mod_addr = *module.address_identifier_at(mod_handle.address); + let fn_info_key = FnInfoKey { fn_name, mod_addr }; + match fn_info_map.get(&fn_info_key) { + Some(fn_info) => fn_info.is_test, + None => false, + } +} + +pub fn disassemble_modules<'a, I>(modules: I) -> IotaResult> +where + I: Iterator>, +{ + let mut disassembled = BTreeMap::new(); + for bytecode in modules { + // this function is only from JSON RPC - it is OK to deserialize with max Move + // binary version + let module = CompiledModule::deserialize_with_defaults(bytecode).map_err(|error| { + IotaError::ModuleDeserializationFailure { + error: error.to_string(), + } + })?; + let view = BinaryIndexedView::Module(&module); + let d = Disassembler::from_view(view, Spanned::unsafe_no_loc(()).loc).map_err(|e| { + IotaError::ObjectSerializationError { + error: e.to_string(), + } + })?; + let bytecode_str = d + .disassemble() + .map_err(|e| IotaError::ObjectSerializationError { + error: e.to_string(), + })?; + disassembled.insert(module.name().to_string(), Value::String(bytecode_str)); + } + Ok(disassembled) +} + +pub fn normalize_modules<'a, I>( + modules: I, + binary_config: &BinaryConfig, +) -> IotaResult> +where + I: Iterator>, +{ + let mut normalized_modules = BTreeMap::new(); + for bytecode in modules { + let module = + CompiledModule::deserialize_with_config(bytecode, binary_config).map_err(|error| { + IotaError::ModuleDeserializationFailure { + error: error.to_string(), + } + })?; + let normalized_module = normalized::Module::new(&module); + normalized_modules.insert(normalized_module.name.to_string(), normalized_module); + } + Ok(normalized_modules) +} + +pub fn normalize_deserialized_modules<'a, I>(modules: I) -> BTreeMap +where + I: Iterator, +{ + let mut normalized_modules = BTreeMap::new(); + for module in modules { + let normalized_module = normalized::Module::new(module); + normalized_modules.insert(normalized_module.name.to_string(), normalized_module); + } + normalized_modules +} + +fn build_linkage_table<'p>( + mut immediate_dependencies: BTreeSet, + transitive_dependencies: impl IntoIterator, +) -> Result, ExecutionError> { + let mut linkage_table = BTreeMap::new(); + let mut dep_linkage_tables = vec![]; + + for transitive_dep in transitive_dependencies.into_iter() { + // original_package_id will deserialize a module but only for the purpose of + // obtaining "original ID" of the package containing it so using max + // Move binary version during deserialization is OK + let original_id = transitive_dep.original_package_id(); + + if immediate_dependencies.remove(&original_id) { + // Found an immediate dependency, mark it as seen, and stash a reference to its + // linkage table to check later. + dep_linkage_tables.push(&transitive_dep.linkage_table); + } + + linkage_table.insert( + original_id, + UpgradeInfo { + upgraded_id: transitive_dep.id, + upgraded_version: transitive_dep.version, + }, + ); + } + // (1) Every dependency is represented in the transitive dependencies + if !immediate_dependencies.is_empty() { + return Err(ExecutionErrorKind::PublishUpgradeMissingDependency.into()); + } + + // (2) Every dependency's linkage table is superseded by this linkage table + for dep_linkage_table in dep_linkage_tables { + for (original_id, dep_info) in dep_linkage_table { + let Some(our_info) = linkage_table.get(original_id) else { + return Err(ExecutionErrorKind::PublishUpgradeMissingDependency.into()); + }; + + if our_info.upgraded_version < dep_info.upgraded_version { + return Err(ExecutionErrorKind::PublishUpgradeDependencyDowngrade.into()); + } + } + } + + Ok(linkage_table) +} + +fn build_initial_type_origin_table(modules: &[CompiledModule]) -> Vec { + modules + .iter() + .flat_map(|m| { + m.struct_defs().iter().map(|struct_def| { + let struct_handle = m.struct_handle_at(struct_def.struct_handle); + let module_name = m.name().to_string(); + let struct_name = m.identifier_at(struct_handle.name).to_string(); + let package: ObjectID = (*m.self_id().address()).into(); + TypeOrigin { + module_name, + struct_name, + package, + } + }) + }) + .collect() +} + +fn build_upgraded_type_origin_table( + predecessor: &MovePackage, + modules: &[CompiledModule], + storage_id: ObjectID, + protocol_config: &ProtocolConfig, +) -> Result, ExecutionError> { + let mut new_table = vec![]; + let mut existing_table = predecessor.type_origin_map(); + for m in modules { + for struct_def in m.struct_defs() { + let struct_handle = m.struct_handle_at(struct_def.struct_handle); + let module_name = m.name().to_string(); + let struct_name = m.identifier_at(struct_handle.name).to_string(); + let mod_key = (module_name.clone(), struct_name.clone()); + // if id exists in the predecessor's table, use it, otherwise use the id of the + // upgraded module + let package = existing_table.remove(&mod_key).unwrap_or(storage_id); + new_table.push(TypeOrigin { + module_name, + struct_name, + package, + }); + } + } + + if !existing_table.is_empty() { + if protocol_config.missing_type_is_compatibility_error() { + Err(ExecutionError::from_kind( + ExecutionErrorKind::PackageUpgradeError { + upgrade_error: PackageUpgradeError::IncompatibleUpgrade, + }, + )) + } else { + Err(ExecutionError::invariant_violation( + "Package upgrade missing type from previous version.", + )) + } + } else { + Ok(new_table) + } +} diff --git a/crates/sui-types/src/multisig.rs b/crates/iota-types/src/multisig.rs similarity index 87% rename from crates/sui-types/src/multisig.rs rename to crates/iota-types/src/multisig.rs index 84e7960fe64..3917e2256db 100644 --- a/crates/sui-types/src/multisig.rs +++ b/crates/iota-types/src/multisig.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -23,9 +24,9 @@ use serde_with::serde_as; use shared_crypto::intent::IntentMessage; use crate::{ - base_types::{EpochId, SuiAddress}, + base_types::{EpochId, IotaAddress}, crypto::{CompressedSignature, DefaultHash, PublicKey, SignatureScheme}, - error::SuiError, + error::IotaError, signature::{AuthenticatorTrait, GenericSignature, VerifyParams}, zk_login_authenticator::ZkLoginAuthenticator, }; @@ -78,7 +79,7 @@ impl Hash for MultiSig { } impl AuthenticatorTrait for MultiSig { - fn verify_user_authenticator_epoch(&self, epoch_id: EpochId) -> Result<(), SuiError> { + fn verify_user_authenticator_epoch(&self, epoch_id: EpochId) -> Result<(), IotaError> { // If there is any zkLogin signatures, filter and check epoch for each. self.get_zklogin_sigs()? .iter() @@ -88,9 +89,9 @@ impl AuthenticatorTrait for MultiSig { fn verify_uncached_checks( &self, _value: &IntentMessage, - _author: SuiAddress, + _author: IotaAddress, _verify_params: &VerifyParams, - ) -> Result<(), SuiError> + ) -> Result<(), IotaError> where T: Serialize, { @@ -100,26 +101,26 @@ impl AuthenticatorTrait for MultiSig { fn verify_claims( &self, value: &IntentMessage, - multisig_address: SuiAddress, + multisig_address: IotaAddress, verify_params: &VerifyParams, - ) -> Result<(), SuiError> + ) -> Result<(), IotaError> where T: Serialize, { self.multisig_pk .validate() - .map_err(|_| SuiError::InvalidSignature { + .map_err(|_| IotaError::InvalidSignature { error: "Invalid multisig pubkey".to_string(), })?; - if SuiAddress::from(&self.multisig_pk) != multisig_address { - return Err(SuiError::InvalidSignature { + if IotaAddress::from(&self.multisig_pk) != multisig_address { + return Err(IotaError::InvalidSignature { error: "Invalid address derived from pks".to_string(), }); } if !self.get_zklogin_sigs()?.is_empty() && !verify_params.accept_zklogin_in_multisig { - return Err(SuiError::InvalidSignature { + return Err(IotaError::InvalidSignature { error: "zkLogin sig not supported inside multisig".to_string(), }); } @@ -137,20 +138,20 @@ impl AuthenticatorTrait for MultiSig { self.multisig_pk .pk_map .get(i as usize) - .ok_or(SuiError::InvalidSignature { + .ok_or(IotaError::InvalidSignature { error: "Invalid public keys index".to_string(), })?; let res = match sig { CompressedSignature::Ed25519(s) => { let pk = Ed25519PublicKey::from_bytes(subsig_pubkey.as_ref()).map_err(|_| { - SuiError::InvalidSignature { + IotaError::InvalidSignature { error: "Invalid ed25519 pk bytes".to_string(), } })?; pk.verify( &digest, - &s.try_into().map_err(|_| SuiError::InvalidSignature { + &s.try_into().map_err(|_| IotaError::InvalidSignature { error: "Invalid ed25519 signature bytes".to_string(), })?, ) @@ -158,13 +159,13 @@ impl AuthenticatorTrait for MultiSig { CompressedSignature::Secp256k1(s) => { let pk = Secp256k1PublicKey::from_bytes(subsig_pubkey.as_ref()).map_err(|_| { - SuiError::InvalidSignature { + IotaError::InvalidSignature { error: "Invalid k1 pk bytes".to_string(), } })?; pk.verify( &digest, - &s.try_into().map_err(|_| SuiError::InvalidSignature { + &s.try_into().map_err(|_| IotaError::InvalidSignature { error: "Invalid k1 signature bytes".to_string(), })?, ) @@ -172,36 +173,36 @@ impl AuthenticatorTrait for MultiSig { CompressedSignature::Secp256r1(s) => { let pk = Secp256r1PublicKey::from_bytes(subsig_pubkey.as_ref()).map_err(|_| { - SuiError::InvalidSignature { + IotaError::InvalidSignature { error: "Invalid r1 pk bytes".to_string(), } })?; pk.verify( &digest, - &s.try_into().map_err(|_| SuiError::InvalidSignature { + &s.try_into().map_err(|_| IotaError::InvalidSignature { error: "Invalid r1 signature bytes".to_string(), })?, ) } CompressedSignature::ZkLogin(z) => { let authenticator = ZkLoginAuthenticator::from_bytes(&z.0).map_err(|_| { - SuiError::InvalidSignature { + IotaError::InvalidSignature { error: "Invalid zklogin authenticator bytes".to_string(), } })?; authenticator - .verify_claims(value, SuiAddress::from(subsig_pubkey), verify_params) + .verify_claims(value, IotaAddress::from(subsig_pubkey), verify_params) .map_err(|e| FastCryptoError::GeneralError(e.to_string())) } }; if res.is_ok() { weight_sum += *weight as u16; } else { - return res.map_err(|e| SuiError::InvalidSignature { + return res.map_err(|e| IotaError::InvalidSignature { error: format!( "Invalid sig for pk={} address={:?} error={:?}", subsig_pubkey.encode_base64(), - SuiAddress::from(subsig_pubkey), + IotaAddress::from(subsig_pubkey), e.to_string() ), }); @@ -210,7 +211,7 @@ impl AuthenticatorTrait for MultiSig { if weight_sum >= self.multisig_pk.threshold { Ok(()) } else { - Err(SuiError::InvalidSignature { + Err(IotaError::InvalidSignature { error: format!( "Insufficient weight={:?} threshold={:?}", weight_sum, self.multisig_pk.threshold @@ -222,9 +223,9 @@ impl AuthenticatorTrait for MultiSig { /// Interpret a bitmap of 01s as a list of indices that is set to 1s. /// e.g. 22 = 0b10110, then the result is [1, 2, 4]. -pub fn as_indices(bitmap: u16) -> Result, SuiError> { +pub fn as_indices(bitmap: u16) -> Result, IotaError> { if bitmap > MAX_BITMAP_VALUE { - return Err(SuiError::InvalidSignature { + return Err(IotaError::InvalidSignature { error: "Invalid bitmap".to_string(), }); } @@ -259,15 +260,15 @@ impl MultiSig { pub fn combine( full_sigs: Vec, multisig_pk: MultiSigPublicKey, - ) -> Result { + ) -> Result { multisig_pk .validate() - .map_err(|_| SuiError::InvalidSignature { + .map_err(|_| IotaError::InvalidSignature { error: "Invalid multisig public key".to_string(), })?; if full_sigs.len() > multisig_pk.pk_map.len() || full_sigs.is_empty() { - return Err(SuiError::InvalidSignature { + return Err(IotaError::InvalidSignature { error: "Invalid number of signatures".to_string(), }); } @@ -277,11 +278,11 @@ impl MultiSig { let pk = s.to_public_key()?; let index = multisig_pk .get_index(&pk) - .ok_or(SuiError::IncorrectSigner { + .ok_or(IotaError::IncorrectSigner { error: format!("pk does not exist: {:?}", pk), })?; if bitmap & (1 << index) != 0 { - return Err(SuiError::InvalidSignature { + return Err(IotaError::InvalidSignature { error: "Duplicate public key".to_string(), }); } @@ -316,7 +317,7 @@ impl MultiSig { &self.sigs } - pub fn get_zklogin_sigs(&self) -> Result, SuiError> { + pub fn get_zklogin_sigs(&self) -> Result, IotaError> { let authenticator_as_bytes: Vec<_> = self .sigs .iter() @@ -328,14 +329,14 @@ impl MultiSig { authenticator_as_bytes .iter() .map(|z| { - ZkLoginAuthenticator::from_bytes(&z.0).map_err(|_| SuiError::InvalidSignature { + ZkLoginAuthenticator::from_bytes(&z.0).map_err(|_| IotaError::InvalidSignature { error: "Invalid zklogin authenticator bytes".to_string(), }) }) .collect() } - pub fn get_indices(&self) -> Result, SuiError> { + pub fn get_indices(&self) -> Result, IotaError> { as_indices(self.bitmap) } } @@ -354,13 +355,13 @@ impl ToFromBytes for MultiSig { } impl FromStr for MultiSig { - type Err = SuiError; + type Err = IotaError; fn from_str(s: &str) -> Result { - let bytes = Base64::decode(s).map_err(|_| SuiError::InvalidSignature { + let bytes = Base64::decode(s).map_err(|_| IotaError::InvalidSignature { error: "Invalid base64 string".to_string(), })?; - let sig = MultiSig::from_bytes(&bytes).map_err(|_| SuiError::InvalidSignature { + let sig = MultiSig::from_bytes(&bytes).map_err(|_| IotaError::InvalidSignature { error: "Invalid multisig bytes".to_string(), })?; Ok(sig) @@ -404,7 +405,7 @@ impl MultiSigPublicKey { pks: Vec, weights: Vec, threshold: ThresholdUnit, - ) -> Result { + ) -> Result { if pks.is_empty() || weights.is_empty() || threshold == 0 @@ -421,7 +422,7 @@ impl MultiSigPublicKey { .enumerate() .any(|(i, pk)| pks.iter().skip(i + 1).any(|other_pk| *pk == *other_pk)) { - return Err(SuiError::InvalidSignature { + return Err(IotaError::InvalidSignature { error: "Invalid multisig public key construction".to_string(), }); } diff --git a/crates/sui-types/src/multisig_legacy.rs b/crates/iota-types/src/multisig_legacy.rs similarity index 92% rename from crates/sui-types/src/multisig_legacy.rs rename to crates/iota-types/src/multisig_legacy.rs index fd8554b500e..891ebb212f9 100644 --- a/crates/sui-types/src/multisig_legacy.rs +++ b/crates/iota-types/src/multisig_legacy.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::hash::{Hash, Hasher}; @@ -17,12 +18,12 @@ use serde_with::serde_as; use shared_crypto::intent::IntentMessage; use crate::{ - base_types::{EpochId, SuiAddress}, + base_types::{EpochId, IotaAddress}, crypto::{CompressedSignature, PublicKey, SignatureScheme}, - error::SuiError, + error::IotaError, + iota_serde::IotaBitmap, multisig::{MultiSig, MultiSigPublicKey}, signature::{AuthenticatorTrait, GenericSignature, VerifyParams}, - sui_serde::SuiBitmap, }; pub type WeightUnit = u8; @@ -40,7 +41,7 @@ pub struct MultiSigLegacy { /// A bitmap that indicates the position of which public key the signature /// should be authenticated with. #[schemars(with = "Base64")] - #[serde_as(as = "SuiBitmap")] + #[serde_as(as = "IotaBitmap")] bitmap: RoaringBitmap, /// The public key encoded with each public key with its signature scheme /// used along with the corresponding weight. @@ -88,16 +89,16 @@ impl Hash for MultiSigLegacy { } impl AuthenticatorTrait for MultiSigLegacy { - fn verify_user_authenticator_epoch(&self, _: EpochId) -> Result<(), SuiError> { + fn verify_user_authenticator_epoch(&self, _: EpochId) -> Result<(), IotaError> { Ok(()) } fn verify_uncached_checks( &self, _value: &IntentMessage, - _author: SuiAddress, + _author: IotaAddress, _aux_verify_data: &VerifyParams, - ) -> Result<(), SuiError> + ) -> Result<(), IotaError> where T: Serialize, { @@ -107,16 +108,16 @@ impl AuthenticatorTrait for MultiSigLegacy { fn verify_claims( &self, value: &IntentMessage, - author: SuiAddress, + author: IotaAddress, aux_verify_data: &VerifyParams, - ) -> Result<(), SuiError> + ) -> Result<(), IotaError> where T: Serialize, { let multisig: MultiSig = self.clone() .try_into() - .map_err(|_| SuiError::InvalidSignature { + .map_err(|_| IotaError::InvalidSignature { error: "Invalid legacy multisig".to_string(), })?; multisig.verify_claims(value, author, aux_verify_data) @@ -125,17 +126,17 @@ impl AuthenticatorTrait for MultiSigLegacy { fn verify_authenticator( &self, value: &IntentMessage, - author: SuiAddress, + author: IotaAddress, epoch: Option, aux_verify_data: &VerifyParams, - ) -> Result<(), SuiError> + ) -> Result<(), IotaError> where T: Serialize, { let multisig: MultiSig = self.clone() .try_into() - .map_err(|_| SuiError::InvalidSignature { + .map_err(|_| IotaError::InvalidSignature { error: "Invalid legacy multisig".to_string(), })?; multisig.verify_authenticator(value, author, epoch, aux_verify_data) @@ -183,15 +184,15 @@ impl MultiSigLegacy { pub fn combine( full_sigs: Vec, multisig_pk: MultiSigPublicKeyLegacy, - ) -> Result { + ) -> Result { multisig_pk .validate() - .map_err(|_| SuiError::InvalidSignature { + .map_err(|_| IotaError::InvalidSignature { error: "Invalid multisig public key".to_string(), })?; if full_sigs.len() > multisig_pk.pk_map.len() || full_sigs.is_empty() { - return Err(SuiError::InvalidSignature { + return Err(IotaError::InvalidSignature { error: "Invalid number of signatures".to_string(), }); } @@ -200,12 +201,12 @@ impl MultiSigLegacy { for s in full_sigs { let pk = s.to_public_key()?; let inserted = bitmap.insert(multisig_pk.get_index(&pk).ok_or( - SuiError::IncorrectSigner { + IotaError::IncorrectSigner { error: format!("pk does not exist: {:?}", pk), }, )?); if !inserted { - return Err(SuiError::InvalidSignature { + return Err(IotaError::InvalidSignature { error: "Duplicate sigature".to_string(), }); } @@ -311,7 +312,7 @@ impl MultiSigPublicKeyLegacy { pks: Vec, weights: Vec, threshold: ThresholdUnit, - ) -> Result { + ) -> Result { if pks.is_empty() || weights.is_empty() || threshold == 0 @@ -324,7 +325,7 @@ impl MultiSigPublicKeyLegacy { .sum::() < threshold { - return Err(SuiError::InvalidSignature { + return Err(IotaError::InvalidSignature { error: "Invalid multisig public key construction".to_string(), }); } diff --git a/crates/iota-types/src/object.rs b/crates/iota-types/src/object.rs new file mode 100644 index 00000000000..bdf86ca51b8 --- /dev/null +++ b/crates/iota-types/src/object.rs @@ -0,0 +1,1298 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::BTreeMap, + convert::TryFrom, + fmt::{Debug, Display, Formatter}, + mem::size_of, + sync::Arc, +}; + +use iota_protocol_config::ProtocolConfig; +use move_binary_format::CompiledModule; +use move_bytecode_utils::{layout::TypeLayoutBuilder, module_cache::GetModule}; +use move_core_types::{ + annotated_value::{MoveStruct, MoveStructLayout, MoveTypeLayout}, + language_storage::{StructTag, TypeTag}, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, Bytes}; + +use self::{balance_traversal::BalanceTraversal, bounded_visitor::BoundedVisitor}; +use crate::{ + base_types::{ + IotaAddress, MoveObjectType, ObjectDigest, ObjectID, ObjectIDParseError, ObjectRef, + SequenceNumber, TransactionDigest, + }, + coin::{Coin, CoinMetadata, TreasuryCap}, + crypto::{default_hash, deterministic_random_account_key}, + error::{ + ExecutionError, ExecutionErrorKind, IotaError, IotaResult, UserInputError, UserInputResult, + }, + gas_coin::{GasCoin, GAS}, + is_system_package, + move_package::MovePackage, + type_resolver::LayoutResolver, +}; + +mod balance_traversal; +pub mod bounded_visitor; + +pub const GAS_VALUE_FOR_TESTING: u64 = 300_000_000_000_000; +pub const OBJECT_START_VERSION: SequenceNumber = SequenceNumber::from_u64(1); + +#[serde_as] +#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)] +pub struct MoveObject { + /// The type of this object. Immutable + type_: MoveObjectType, + /// DEPRECATED this field is no longer used to determine whether a tx can + /// transfer this object. Instead, it is always calculated from the + /// objects type when loaded in execution + has_public_transfer: bool, + /// Number that increases each time a tx takes this object as a mutable + /// input This is a lamport timestamp, not a sequentially increasing + /// version + version: SequenceNumber, + /// BCS bytes of a Move struct value + #[serde_as(as = "Bytes")] + contents: Vec, +} + +/// Index marking the end of the object's ID + the beginning of its version +pub const ID_END_INDEX: usize = ObjectID::LENGTH; + +impl MoveObject { + /// Creates a new Move object of type `type_` with BCS encoded bytes in + /// `contents` `has_public_transfer` is determined by the abilities of + /// the `type_`, but resolving the abilities requires the compiled + /// modules of the `type_: StructTag`. In other words, + /// `has_public_transfer` will be the same for all objects of the same + /// `type_`. + /// + /// # Safety + /// + /// This function should ONLY be called if has_public_transfer has been + /// determined by the type_. Yes, this is a bit of an abuse of the + /// `unsafe` marker, but bad things will happen if this is inconsistent + pub unsafe fn new_from_execution( + type_: MoveObjectType, + has_public_transfer: bool, + version: SequenceNumber, + contents: Vec, + protocol_config: &ProtocolConfig, + ) -> Result { + Self::new_from_execution_with_limit( + type_, + has_public_transfer, + version, + contents, + protocol_config.max_move_object_size(), + ) + } + + /// # Safety + /// This function should ONLY be called if has_public_transfer has been + /// determined by the type_ + pub unsafe fn new_from_execution_with_limit( + type_: MoveObjectType, + has_public_transfer: bool, + version: SequenceNumber, + contents: Vec, + max_move_object_size: u64, + ) -> Result { + // coins should always have public transfer, as they always should have store. + // Thus, type_ == GasCoin::type_() ==> has_public_transfer + // TODO: think this can be generalized to is_coin + debug_assert!(!type_.is_gas_coin() || has_public_transfer); + if contents.len() as u64 > max_move_object_size { + return Err(ExecutionError::from_kind( + ExecutionErrorKind::MoveObjectTooBig { + object_size: contents.len() as u64, + max_object_size: max_move_object_size, + }, + )); + } + Ok(Self { + type_, + has_public_transfer, + version, + contents, + }) + } + + pub fn new_gas_coin(version: SequenceNumber, id: ObjectID, value: u64) -> Self { + // unwrap safe because coins are always smaller than the max object size + unsafe { + Self::new_from_execution_with_limit( + GasCoin::type_().into(), + true, + version, + GasCoin::new(id, value).to_bcs_bytes(), + 256, + ) + .unwrap() + } + } + + pub fn new_coin( + coin_type: MoveObjectType, + version: SequenceNumber, + id: ObjectID, + value: u64, + ) -> Self { + // unwrap safe because coins are always smaller than the max object size + unsafe { + Self::new_from_execution_with_limit( + coin_type, + true, + version, + GasCoin::new(id, value).to_bcs_bytes(), + 256, + ) + .unwrap() + } + } + + pub fn type_(&self) -> &MoveObjectType { + &self.type_ + } + + pub fn is_type(&self, s: &StructTag) -> bool { + self.type_.is(s) + } + + pub fn has_public_transfer(&self) -> bool { + self.has_public_transfer + } + + pub fn id(&self) -> ObjectID { + Self::id_opt(&self.contents).unwrap() + } + + pub fn id_opt(contents: &[u8]) -> Result { + if ID_END_INDEX > contents.len() { + return Err(ObjectIDParseError::TryFromSliceError); + } + ObjectID::try_from(&contents[0..ID_END_INDEX]) + } + + /// Return the `value: u64` field of a `Coin` type. + /// Useful for reading the coin without deserializing the object into a Move + /// value It is the caller's responsibility to check that `self` is a + /// coin--this function may panic or do something unexpected otherwise. + pub fn get_coin_value_unsafe(&self) -> u64 { + debug_assert!(self.type_.is_coin()); + // 32 bytes for object ID, 8 for balance + debug_assert!(self.contents.len() == 40); + + // unwrap safe because we checked that it is a coin + u64::from_le_bytes(<[u8; 8]>::try_from(&self.contents[ID_END_INDEX..]).unwrap()) + } + + /// Update the `value: u64` field of a `Coin` type. + /// Useful for updating the coin without deserializing the object into a + /// Move value It is the caller's responsibility to check that `self` is + /// a coin--this function may panic or do something unexpected + /// otherwise. + pub fn set_coin_value_unsafe(&mut self, value: u64) { + debug_assert!(self.type_.is_coin()); + // 32 bytes for object ID, 8 for balance + debug_assert!(self.contents.len() == 40); + + self.contents.splice(ID_END_INDEX.., value.to_le_bytes()); + } + + /// Update the `timestamp_ms: u64` field of the `Clock` type. + /// + /// Panics if the object isn't a `Clock`. + pub fn set_clock_timestamp_ms_unsafe(&mut self, timestamp_ms: u64) { + assert!(self.is_clock()); + // 32 bytes for object ID, 8 for timestamp + assert!(self.contents.len() == 40); + + self.contents + .splice(ID_END_INDEX.., timestamp_ms.to_le_bytes()); + } + + pub fn is_coin(&self) -> bool { + self.type_.is_coin() + } + + pub fn is_staked_iota(&self) -> bool { + self.type_.is_staked_iota() + } + + pub fn is_clock(&self) -> bool { + self.type_.is(&crate::clock::Clock::type_()) + } + + pub fn version(&self) -> SequenceNumber { + self.version + } + + /// Contents of the object that are specific to its type--i.e., not its ID + /// and version, which all objects have For example if the object was + /// declared as `struct S has key { id: ID, f1: u64, f2: bool }, + /// this returns the slice containing `f1` and `f2`. + #[cfg(test)] + pub fn type_specific_contents(&self) -> &[u8] { + &self.contents[ID_END_INDEX..] + } + + /// Update the contents of this object but does not increment its version + pub fn update_contents( + &mut self, + new_contents: Vec, + protocol_config: &ProtocolConfig, + ) -> Result<(), ExecutionError> { + self.update_contents_with_limit(new_contents, protocol_config.max_move_object_size()) + } + + fn update_contents_with_limit( + &mut self, + new_contents: Vec, + max_move_object_size: u64, + ) -> Result<(), ExecutionError> { + if new_contents.len() as u64 > max_move_object_size { + return Err(ExecutionError::from_kind( + ExecutionErrorKind::MoveObjectTooBig { + object_size: new_contents.len() as u64, + max_object_size: max_move_object_size, + }, + )); + } + + #[cfg(debug_assertions)] + let old_id = self.id(); + self.contents = new_contents; + + // Update should not modify ID + #[cfg(debug_assertions)] + debug_assert_eq!(self.id(), old_id); + + Ok(()) + } + + /// Sets the version of this object to a new value which is assumed to be + /// higher (and checked to be higher in debug). + pub fn increment_version_to(&mut self, next: SequenceNumber) { + self.version.increment_to(next); + } + + pub fn decrement_version_to(&mut self, prev: SequenceNumber) { + self.version.decrement_to(prev); + } + + pub fn contents(&self) -> &[u8] { + &self.contents + } + + pub fn into_contents(self) -> Vec { + self.contents + } + + pub fn into_type(self) -> MoveObjectType { + self.type_ + } + + pub fn into_inner(self) -> (MoveObjectType, Vec) { + (self.type_, self.contents) + } + + /// Get a `MoveStructLayout` for `self`. + /// The `resolver` value must contain the module that declares `self.type_` + /// and the (transitive) dependencies of `self.type_` in order for this + /// to succeed. Failure will result in an `ObjectSerializationError` + pub fn get_layout(&self, resolver: &impl GetModule) -> Result { + Self::get_layout_from_struct_tag(self.type_().clone().into(), resolver) + } + + pub fn get_layout_from_struct_tag( + struct_tag: StructTag, + resolver: &impl GetModule, + ) -> Result { + let type_ = TypeTag::Struct(Box::new(struct_tag)); + let layout = TypeLayoutBuilder::build_with_types(&type_, resolver).map_err(|e| { + IotaError::ObjectSerializationError { + error: e.to_string(), + } + })?; + match layout { + MoveTypeLayout::Struct(l) => Ok(l), + _ => unreachable!( + "We called build_with_types on Struct type, should get a struct layout" + ), + } + } + + /// Convert `self` to the JSON representation dictated by `layout`. + pub fn to_move_struct(&self, layout: &MoveStructLayout) -> Result { + BoundedVisitor::deserialize_struct(&self.contents, layout).map_err(|e| { + IotaError::ObjectSerializationError { + error: e.to_string(), + } + }) + } + + /// Convert `self` to the JSON representation dictated by `layout`. + pub fn to_move_struct_with_resolver( + &self, + resolver: &impl GetModule, + ) -> Result { + self.to_move_struct(&self.get_layout(resolver)?) + } + + pub fn to_rust<'de, T: Deserialize<'de>>(&'de self) -> Option { + bcs::from_bytes(self.contents()).ok() + } + + /// Approximate size of the object in bytes. This is used for gas metering. + /// For the type tag field, we serialize it on the spot to get the accurate + /// size. This should not be very expensive since the type tag is + /// usually simple, and we only do this once per object being mutated. + pub fn object_size_for_gas_metering(&self) -> usize { + let serialized_type_tag_size = + bcs::serialized_size(&self.type_).expect("Serializing type tag should not fail"); + // + 1 for 'has_public_transfer' + // + 8 for `version` + self.contents.len() + serialized_type_tag_size + 1 + 8 + } + + /// Get the total amount of IOTA embedded in `self`. Intended for testing + /// purposes + pub fn get_total_iota( + &self, + layout_resolver: &mut dyn LayoutResolver, + ) -> Result { + let balances = self.get_coin_balances(layout_resolver)?; + Ok(balances.get(&GAS::type_tag()).copied().unwrap_or(0)) + } +} + +// Helpers for extracting Coin balances for all T +impl MoveObject { + /// Get the total balances for all `Coin` embedded in `self`. + pub fn get_coin_balances( + &self, + layout_resolver: &mut dyn LayoutResolver, + ) -> Result, IotaError> { + // Fast path without deserialization. + if let Some(type_tag) = self.type_.coin_type_maybe() { + let balance = self.get_coin_value_unsafe(); + Ok(if balance > 0 { + BTreeMap::from([(type_tag.clone(), balance)]) + } else { + BTreeMap::default() + }) + } else { + let layout = layout_resolver.get_annotated_layout(&self.type_().clone().into())?; + + let mut traversal = BalanceTraversal::default(); + MoveStruct::visit_deserialize(&self.contents, &layout, &mut traversal).map_err( + |e| IotaError::ObjectSerializationError { + error: e.to_string(), + }, + )?; + + Ok(traversal.finish()) + } + } +} + +#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)] +#[allow(clippy::large_enum_variant)] +pub enum Data { + /// An object whose governing logic lives in a published Move module + Move(MoveObject), + /// Map from each module name to raw serialized Move module bytes + Package(MovePackage), + // ... Iota "native" types go here +} + +impl Data { + pub fn try_as_move(&self) -> Option<&MoveObject> { + use Data::*; + match self { + Move(m) => Some(m), + Package(_) => None, + } + } + + pub fn try_as_move_mut(&mut self) -> Option<&mut MoveObject> { + use Data::*; + match self { + Move(m) => Some(m), + Package(_) => None, + } + } + + pub fn try_as_package(&self) -> Option<&MovePackage> { + use Data::*; + match self { + Move(_) => None, + Package(p) => Some(p), + } + } + + pub fn try_as_package_mut(&mut self) -> Option<&mut MovePackage> { + use Data::*; + match self { + Move(_) => None, + Package(p) => Some(p), + } + } + + pub fn try_into_package(self) -> Option { + use Data::*; + match self { + Move(_) => None, + Package(p) => Some(p), + } + } + + pub fn type_(&self) -> Option<&MoveObjectType> { + use Data::*; + match self { + Move(m) => Some(m.type_()), + Package(_) => None, + } + } + + pub fn struct_tag(&self) -> Option { + use Data::*; + match self { + Move(m) => Some(m.type_().clone().into()), + Package(_) => None, + } + } + + pub fn id(&self) -> ObjectID { + match self { + Self::Move(v) => v.id(), + Self::Package(m) => m.id(), + } + } +} + +#[derive( + Eq, PartialEq, Debug, Clone, Copy, Deserialize, Serialize, Hash, JsonSchema, Ord, PartialOrd, +)] +#[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))] +pub enum Owner { + /// Object is exclusively owned by a single address, and is mutable. + AddressOwner(IotaAddress), + /// Object is exclusively owned by a single object, and is mutable. + /// The object ID is converted to IotaAddress as IotaAddress is universal. + ObjectOwner(IotaAddress), + /// Object is shared, can be used by any address, and is mutable. + Shared { + /// The version at which the object became shared + initial_shared_version: SequenceNumber, + }, + /// Object is immutable, and hence ownership doesn't matter. + Immutable, +} + +impl Owner { + // NOTE: only return address of AddressOwner, otherwise return error, + // ObjectOwner's address is converted from object id, thus we will skip it. + pub fn get_address_owner_address(&self) -> IotaResult { + match self { + Self::AddressOwner(address) => Ok(*address), + Self::Shared { .. } | Self::Immutable | Self::ObjectOwner(_) => { + Err(IotaError::UnexpectedOwnerType) + } + } + } + + // NOTE: this function will return address of both AddressOwner and ObjectOwner, + // address of ObjectOwner is converted from object id, even though the type is + // IotaAddress. + pub fn get_owner_address(&self) -> IotaResult { + match self { + Self::AddressOwner(address) | Self::ObjectOwner(address) => Ok(*address), + Self::Shared { .. } | Self::Immutable => Err(IotaError::UnexpectedOwnerType), + } + } + + pub fn is_immutable(&self) -> bool { + matches!(self, Owner::Immutable) + } + + pub fn is_address_owned(&self) -> bool { + matches!(self, Owner::AddressOwner(_)) + } + + pub fn is_child_object(&self) -> bool { + matches!(self, Owner::ObjectOwner(_)) + } + + pub fn is_shared(&self) -> bool { + matches!(self, Owner::Shared { .. }) + } +} + +impl PartialEq for Owner { + fn eq(&self, other: &IotaAddress) -> bool { + match self { + Self::AddressOwner(address) => address == other, + Self::ObjectOwner(_) | Self::Shared { .. } | Self::Immutable => false, + } + } +} + +impl PartialEq for Owner { + fn eq(&self, other: &ObjectID) -> bool { + let other_id: IotaAddress = (*other).into(); + match self { + Self::ObjectOwner(id) => id == &other_id, + Self::AddressOwner(_) | Self::Shared { .. } | Self::Immutable => false, + } + } +} + +impl Display for Owner { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::AddressOwner(address) => { + write!(f, "Account Address ( {} )", address) + } + Self::ObjectOwner(address) => { + write!(f, "Object ID: ( {} )", address) + } + Self::Immutable => { + write!(f, "Immutable") + } + Self::Shared { .. } => { + write!(f, "Shared") + } + } + } +} + +#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)] +#[serde(rename = "Object")] +pub struct ObjectInner { + /// The meat of the object + pub data: Data, + /// The owner that unlocks this object + pub owner: Owner, + /// The digest of the transaction that created or last mutated this object + pub previous_transaction: TransactionDigest, + /// The amount of IOTA we would rebate if this object gets deleted. + /// This number is re-calculated each time the object is mutated based on + /// the present storage gas price. + pub storage_rebate: u64, +} + +#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)] +pub struct Object(Arc); + +impl From for Object { + fn from(inner: ObjectInner) -> Self { + Self(Arc::new(inner)) + } +} + +impl Object { + pub fn into_inner(self) -> ObjectInner { + match Arc::try_unwrap(self.0) { + Ok(inner) => inner, + Err(inner_arc) => (*inner_arc).clone(), + } + } + + pub fn as_inner(&self) -> &ObjectInner { + &self.0 + } + + pub fn new_from_genesis( + data: Data, + owner: Owner, + previous_transaction: TransactionDigest, + ) -> Self { + ObjectInner { + data, + owner, + previous_transaction, + storage_rebate: 0, + } + .into() + } + + /// Create a new Move object + pub fn new_move(o: MoveObject, owner: Owner, previous_transaction: TransactionDigest) -> Self { + ObjectInner { + data: Data::Move(o), + owner, + previous_transaction, + storage_rebate: 0, + } + .into() + } + + pub fn new_package_from_data(data: Data, previous_transaction: TransactionDigest) -> Self { + ObjectInner { + data, + owner: Owner::Immutable, + previous_transaction, + storage_rebate: 0, + } + .into() + } + + // Note: this will panic if `modules` is empty + pub fn new_from_package(package: MovePackage, previous_transaction: TransactionDigest) -> Self { + Self::new_package_from_data(Data::Package(package), previous_transaction) + } + + pub fn new_package<'p>( + modules: &[CompiledModule], + previous_transaction: TransactionDigest, + max_move_package_size: u64, + dependencies: impl IntoIterator, + ) -> Result { + Ok(Self::new_package_from_data( + Data::Package(MovePackage::new_initial( + modules, + max_move_package_size, + dependencies, + )?), + previous_transaction, + )) + } + + pub fn new_upgraded_package<'p>( + previous_package: &MovePackage, + new_package_id: ObjectID, + modules: &[CompiledModule], + previous_transaction: TransactionDigest, + protocol_config: &ProtocolConfig, + dependencies: impl IntoIterator, + ) -> Result { + Ok(Self::new_package_from_data( + Data::Package(previous_package.new_upgraded( + new_package_id, + modules, + protocol_config, + dependencies, + )?), + previous_transaction, + )) + } + + pub fn new_package_for_testing( + modules: &[CompiledModule], + previous_transaction: TransactionDigest, + dependencies: impl IntoIterator, + ) -> Result { + let dependencies: Vec<_> = dependencies.into_iter().collect(); + Self::new_package( + modules, + previous_transaction, + ProtocolConfig::get_for_max_version_UNSAFE().max_move_package_size(), + &dependencies, + ) + } + + /// Create a system package which is not subject to size limits. Panics if + /// the object ID is not a known system package. + pub fn new_system_package( + modules: &[CompiledModule], + version: SequenceNumber, + dependencies: Vec, + previous_transaction: TransactionDigest, + ) -> Self { + let ret = Self::new_package_from_data( + Data::Package(MovePackage::new_system(version, modules, dependencies)), + previous_transaction, + ); + + #[cfg(not(msim))] + assert!(ret.is_system_package()); + + ret + } +} + +impl std::ops::Deref for Object { + type Target = ObjectInner; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::ops::DerefMut for Object { + fn deref_mut(&mut self) -> &mut Self::Target { + Arc::make_mut(&mut self.0) + } +} + +impl ObjectInner { + /// Returns true if the object is a system package. + pub fn is_system_package(&self) -> bool { + self.is_package() && is_system_package(self.id()) + } + + pub fn is_immutable(&self) -> bool { + self.owner.is_immutable() + } + + pub fn is_address_owned(&self) -> bool { + self.owner.is_address_owned() + } + + pub fn is_child_object(&self) -> bool { + self.owner.is_child_object() + } + + pub fn is_shared(&self) -> bool { + self.owner.is_shared() + } + + pub fn get_single_owner(&self) -> Option { + self.owner.get_owner_address().ok() + } + + // It's a common pattern to retrieve both the owner and object ID + // together, if it's owned by a singler owner. + pub fn get_owner_and_id(&self) -> Option<(Owner, ObjectID)> { + Some((self.owner, self.id())) + } + + /// Return true if this object is a Move package, false if it is a Move + /// value + pub fn is_package(&self) -> bool { + matches!(&self.data, Data::Package(_)) + } + + pub fn compute_object_reference(&self) -> ObjectRef { + (self.id(), self.version(), self.digest()) + } + + pub fn digest(&self) -> ObjectDigest { + ObjectDigest::new(default_hash(self)) + } + + pub fn id(&self) -> ObjectID { + use Data::*; + + match &self.data { + Move(v) => v.id(), + Package(m) => m.id(), + } + } + + pub fn version(&self) -> SequenceNumber { + use Data::*; + + match &self.data { + Move(o) => o.version(), + Package(p) => p.version(), + } + } + + pub fn type_(&self) -> Option<&MoveObjectType> { + self.data.type_() + } + + pub fn struct_tag(&self) -> Option { + self.data.struct_tag() + } + + pub fn is_coin(&self) -> bool { + if let Some(move_object) = self.data.try_as_move() { + move_object.type_().is_coin() + } else { + false + } + } + + pub fn is_gas_coin(&self) -> bool { + if let Some(move_object) = self.data.try_as_move() { + move_object.type_().is_gas_coin() + } else { + false + } + } + + // TODO: use `MoveObj::get_balance_unsafe` instead. + // context: https://github.com/iotaledger/iota/pull/10679#discussion_r1165877816 + pub fn as_coin_maybe(&self) -> Option { + if let Some(move_object) = self.data.try_as_move() { + let coin: Coin = bcs::from_bytes(move_object.contents()).ok()?; + Some(coin) + } else { + None + } + } + + pub fn coin_type_maybe(&self) -> Option { + if let Some(move_object) = self.data.try_as_move() { + move_object.type_().coin_type_maybe() + } else { + None + } + } + + /// Return the `value: u64` field of a `Coin` type. + /// Useful for reading the coin without deserializing the object into a Move + /// value It is the caller's responsibility to check that `self` is a + /// coin--this function may panic or do something unexpected otherwise. + pub fn get_coin_value_unsafe(&self) -> u64 { + self.data.try_as_move().unwrap().get_coin_value_unsafe() + } + + /// Approximate size of the object in bytes. This is used for gas metering. + /// This will be slgihtly different from the serialized size, but + /// we also don't want to serialize the object just to get the size. + /// This approximation should be good enough for gas metering. + pub fn object_size_for_gas_metering(&self) -> usize { + let meta_data_size = size_of::() + size_of::() + size_of::(); + let data_size = match &self.data { + Data::Move(m) => m.object_size_for_gas_metering(), + Data::Package(p) => p.object_size_for_gas_metering(), + }; + meta_data_size + data_size + } + + /// Change the owner of `self` to `new_owner`. + pub fn transfer(&mut self, new_owner: IotaAddress) { + self.owner = Owner::AddressOwner(new_owner); + } + + /// Get a `MoveStructLayout` for `self`. + /// The `resolver` value must contain the module that declares `self.type_` + /// and the (transitive) dependencies of `self.type_` in order for this + /// to succeed. Failure will result in an `ObjectSerializationError` + pub fn get_layout( + &self, + resolver: &impl GetModule, + ) -> Result, IotaError> { + match &self.data { + Data::Move(m) => Ok(Some(m.get_layout(resolver)?)), + Data::Package(_) => Ok(None), + } + } + + /// Treat the object type as a Move struct with one type parameter, + /// like this: `S`. + /// Returns the inner parameter type `T`. + pub fn get_move_template_type(&self) -> IotaResult { + let move_struct = self.data.struct_tag().ok_or_else(|| IotaError::TypeError { + error: "Object must be a Move object".to_owned(), + })?; + fp_ensure!( + move_struct.type_params.len() == 1, + IotaError::TypeError { + error: "Move object struct must have one type parameter".to_owned() + } + ); + // Index access safe due to checks above. + let type_tag = move_struct.type_params[0].clone(); + Ok(type_tag) + } + + pub fn to_rust<'de, T: Deserialize<'de>>(&'de self) -> Option { + self.data.try_as_move().and_then(|data| data.to_rust()) + } +} + +// Testing-related APIs. +impl Object { + /// Get the total amount of IOTA embedded in `self`, including both Move + /// objects and the storage rebate + pub fn get_total_iota( + &self, + layout_resolver: &mut dyn LayoutResolver, + ) -> Result { + Ok(self.storage_rebate + + match &self.data { + Data::Move(m) => m.get_total_iota(layout_resolver)?, + Data::Package(_) => 0, + }) + } + + pub fn immutable_with_id_for_testing(id: ObjectID) -> Self { + let data = Data::Move(MoveObject { + type_: GasCoin::type_().into(), + has_public_transfer: true, + version: OBJECT_START_VERSION, + contents: GasCoin::new(id, GAS_VALUE_FOR_TESTING).to_bcs_bytes(), + }); + ObjectInner { + owner: Owner::Immutable, + data, + previous_transaction: TransactionDigest::genesis_marker(), + storage_rebate: 0, + } + .into() + } + + pub fn immutable_for_testing() -> Self { + thread_local! { + static IMMUTABLE_OBJECT_ID: ObjectID = ObjectID::random(); + } + + Self::immutable_with_id_for_testing(IMMUTABLE_OBJECT_ID.with(|id| *id)) + } + + /// make a test shared object. + pub fn shared_for_testing() -> Object { + thread_local! { + static SHARED_OBJECT_ID: ObjectID = ObjectID::random(); + } + + let obj = + MoveObject::new_gas_coin(OBJECT_START_VERSION, SHARED_OBJECT_ID.with(|id| *id), 10); + let owner = Owner::Shared { + initial_shared_version: obj.version(), + }; + Object::new_move(obj, owner, TransactionDigest::genesis_marker()) + } + + pub fn with_id_owner_gas_for_testing(id: ObjectID, owner: IotaAddress, gas: u64) -> Self { + let data = Data::Move(MoveObject { + type_: GasCoin::type_().into(), + has_public_transfer: true, + version: OBJECT_START_VERSION, + contents: GasCoin::new(id, gas).to_bcs_bytes(), + }); + ObjectInner { + owner: Owner::AddressOwner(owner), + data, + previous_transaction: TransactionDigest::genesis_marker(), + storage_rebate: 0, + } + .into() + } + + pub fn treasury_cap_for_testing(struct_tag: StructTag, treasury_cap: TreasuryCap) -> Self { + let data = Data::Move(MoveObject { + type_: TreasuryCap::type_(struct_tag).into(), + has_public_transfer: true, + version: OBJECT_START_VERSION, + contents: bcs::to_bytes(&treasury_cap).expect("Failed to serialize"), + }); + ObjectInner { + owner: Owner::Immutable, + data, + previous_transaction: TransactionDigest::genesis_marker(), + storage_rebate: 0, + } + .into() + } + + pub fn coin_metadata_for_testing(struct_tag: StructTag, metadata: CoinMetadata) -> Self { + let data = Data::Move(MoveObject { + type_: CoinMetadata::type_(struct_tag).into(), + has_public_transfer: true, + version: OBJECT_START_VERSION, + contents: bcs::to_bytes(&metadata).expect("Failed to serialize"), + }); + ObjectInner { + owner: Owner::Immutable, + data, + previous_transaction: TransactionDigest::genesis_marker(), + storage_rebate: 0, + } + .into() + } + + pub fn with_object_owner_for_testing(id: ObjectID, owner: ObjectID) -> Self { + let data = Data::Move(MoveObject { + type_: GasCoin::type_().into(), + has_public_transfer: true, + version: OBJECT_START_VERSION, + contents: GasCoin::new(id, GAS_VALUE_FOR_TESTING).to_bcs_bytes(), + }); + ObjectInner { + owner: Owner::ObjectOwner(owner.into()), + data, + previous_transaction: TransactionDigest::genesis_marker(), + storage_rebate: 0, + } + .into() + } + + pub fn with_id_owner_for_testing(id: ObjectID, owner: IotaAddress) -> Self { + // For testing, we provide sufficient gas by default. + Self::with_id_owner_gas_for_testing(id, owner, GAS_VALUE_FOR_TESTING) + } + + pub fn with_id_owner_version_for_testing( + id: ObjectID, + version: SequenceNumber, + owner: IotaAddress, + ) -> Self { + let data = Data::Move(MoveObject { + type_: GasCoin::type_().into(), + has_public_transfer: true, + version, + contents: GasCoin::new(id, GAS_VALUE_FOR_TESTING).to_bcs_bytes(), + }); + ObjectInner { + owner: Owner::AddressOwner(owner), + data, + previous_transaction: TransactionDigest::genesis_marker(), + storage_rebate: 0, + } + .into() + } + + pub fn with_owner_for_testing(owner: IotaAddress) -> Self { + Self::with_id_owner_for_testing(ObjectID::random(), owner) + } + + /// Generate a new gas coin worth `value` with a random object ID and owner + /// For testing purposes only + pub fn new_gas_with_balance_and_owner_for_testing(value: u64, owner: IotaAddress) -> Self { + let obj = MoveObject::new_gas_coin(OBJECT_START_VERSION, ObjectID::random(), value); + Object::new_move( + obj, + Owner::AddressOwner(owner), + TransactionDigest::genesis_marker(), + ) + } + + /// Generate a new gas coin object with default balance and random owner. + pub fn new_gas_for_testing() -> Self { + let gas_object_id = ObjectID::random(); + let (owner, _) = deterministic_random_account_key(); + Object::with_id_owner_for_testing(gas_object_id, owner) + } +} + +/// Make a few test gas objects (all with the same random owner). +pub fn generate_test_gas_objects() -> Vec { + thread_local! { + static GAS_OBJECTS: Vec = (0..50) + .map(|_| { + let gas_object_id = ObjectID::random(); + let (owner, _) = deterministic_random_account_key(); + Object::with_id_owner_for_testing(gas_object_id, owner) + }) + .collect(); + } + + GAS_OBJECTS.with(|v| v.clone()) +} + +#[allow(clippy::large_enum_variant)] +#[derive(Serialize, Deserialize, Debug)] +#[serde(tag = "status", content = "details")] +pub enum ObjectRead { + NotExists(ObjectID), + Exists(ObjectRef, Object, Option), + Deleted(ObjectRef), +} + +impl ObjectRead { + /// Returns the object value if there is any, otherwise an Err if + /// the object does not exist or is deleted. + pub fn into_object(self) -> UserInputResult { + match self { + Self::Deleted(oref) => Err(UserInputError::ObjectDeleted { object_ref: oref }), + Self::NotExists(id) => Err(UserInputError::ObjectNotFound { + object_id: id, + version: None, + }), + Self::Exists(_, o, _) => Ok(o), + } + } + + pub fn object(&self) -> UserInputResult<&Object> { + match self { + Self::Deleted(oref) => Err(UserInputError::ObjectDeleted { object_ref: *oref }), + Self::NotExists(id) => Err(UserInputError::ObjectNotFound { + object_id: *id, + version: None, + }), + Self::Exists(_, o, _) => Ok(o), + } + } + + pub fn object_id(&self) -> ObjectID { + match self { + Self::Deleted(oref) => oref.0, + Self::NotExists(id) => *id, + Self::Exists(oref, _, _) => oref.0, + } + } +} + +impl Display for ObjectRead { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::Deleted(oref) => { + write!(f, "ObjectRead::Deleted ({:?})", oref) + } + Self::NotExists(id) => { + write!(f, "ObjectRead::NotExists ({:?})", id) + } + Self::Exists(oref, _, _) => { + write!(f, "ObjectRead::Exists ({:?})", oref) + } + } + } +} + +#[allow(clippy::large_enum_variant)] +#[derive(Serialize, Deserialize, Debug)] +#[serde(tag = "status", content = "details")] +pub enum PastObjectRead { + /// The object does not exist + ObjectNotExists(ObjectID), + /// The object is found to be deleted with this version + ObjectDeleted(ObjectRef), + /// The object exists and is found with this version + VersionFound(ObjectRef, Object, Option), + /// The object exists but not found with this version + VersionNotFound(ObjectID, SequenceNumber), + /// The asked object version is higher than the latest + VersionTooHigh { + object_id: ObjectID, + asked_version: SequenceNumber, + latest_version: SequenceNumber, + }, +} + +impl PastObjectRead { + /// Returns the object value if there is any, otherwise an Err + pub fn into_object(self) -> UserInputResult { + match self { + Self::ObjectDeleted(oref) => Err(UserInputError::ObjectDeleted { object_ref: oref }), + Self::ObjectNotExists(id) => Err(UserInputError::ObjectNotFound { + object_id: id, + version: None, + }), + Self::VersionFound(_, o, _) => Ok(o), + Self::VersionNotFound(object_id, version) => Err(UserInputError::ObjectNotFound { + object_id, + version: Some(version), + }), + Self::VersionTooHigh { + object_id, + asked_version, + latest_version, + } => Err(UserInputError::ObjectSequenceNumberTooHigh { + object_id, + asked_version, + latest_version, + }), + } + } +} + +impl Display for PastObjectRead { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::ObjectDeleted(oref) => { + write!(f, "PastObjectRead::ObjectDeleted ({:?})", oref) + } + Self::ObjectNotExists(id) => { + write!(f, "PastObjectRead::ObjectNotExists ({:?})", id) + } + Self::VersionFound(oref, _, _) => { + write!(f, "PastObjectRead::VersionFound ({:?})", oref) + } + Self::VersionNotFound(object_id, version) => { + write!( + f, + "PastObjectRead::VersionNotFound ({:?}, asked sequence number {:?})", + object_id, version + ) + } + Self::VersionTooHigh { + object_id, + asked_version, + latest_version, + } => { + write!( + f, + "PastObjectRead::VersionTooHigh ({:?}, asked sequence number {:?}, latest sequence number {:?})", + object_id, asked_version, latest_version + ) + } + } + } +} + +// Ensure that object digest computation and bcs serialized format are not +// inadvertently changed. +#[test] +fn test_object_digest_and_serialized_format() { + let g = GasCoin::new_for_testing_with_id(ObjectID::ZERO, 123).to_object(OBJECT_START_VERSION); + let o = Object::new_move( + g, + Owner::AddressOwner(IotaAddress::ZERO), + TransactionDigest::ZERO, + ); + let bytes = bcs::to_bytes(&o).unwrap(); + + assert_eq!( + bytes, + [ + 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ] + ); + + let objref = format!("{:?}", o.compute_object_reference()); + assert_eq!( + objref, + "(0x0000000000000000000000000000000000000000000000000000000000000000, SequenceNumber(1), o#59tZq65HVqZjUyNtD7BCGLTD87N5cpayYwEFrtwR4aMz)" + ); +} + +#[test] +fn test_get_coin_value_unsafe() { + fn test_for_value(v: u64) { + let g = GasCoin::new_for_testing(v).to_object(OBJECT_START_VERSION); + assert_eq!(g.get_coin_value_unsafe(), v); + assert_eq!(GasCoin::try_from(&g).unwrap().value(), v); + } + + test_for_value(0); + test_for_value(1); + test_for_value(8); + test_for_value(9); + test_for_value(u8::MAX as u64); + test_for_value(u8::MAX as u64 + 1); + test_for_value(u16::MAX as u64); + test_for_value(u16::MAX as u64 + 1); + test_for_value(u32::MAX as u64); + test_for_value(u32::MAX as u64 + 1); + test_for_value(u64::MAX); +} + +#[test] +fn test_set_coin_value_unsafe() { + fn test_for_value(v: u64) { + let mut g = GasCoin::new_for_testing(u64::MAX).to_object(OBJECT_START_VERSION); + g.set_coin_value_unsafe(v); + assert_eq!(g.get_coin_value_unsafe(), v); + assert_eq!(GasCoin::try_from(&g).unwrap().value(), v); + assert_eq!(g.version(), OBJECT_START_VERSION); + assert_eq!(g.contents().len(), 40); + } + + test_for_value(0); + test_for_value(1); + test_for_value(8); + test_for_value(9); + test_for_value(u8::MAX as u64); + test_for_value(u8::MAX as u64 + 1); + test_for_value(u16::MAX as u64); + test_for_value(u16::MAX as u64 + 1); + test_for_value(u32::MAX as u64); + test_for_value(u32::MAX as u64 + 1); + test_for_value(u64::MAX); +} diff --git a/crates/sui-types/src/object/balance_traversal.rs b/crates/iota-types/src/object/balance_traversal.rs similarity index 98% rename from crates/sui-types/src/object/balance_traversal.rs rename to crates/iota-types/src/object/balance_traversal.rs index c6974968e0a..0a3c41a25b4 100644 --- a/crates/sui-types/src/object/balance_traversal.rs +++ b/crates/iota-types/src/object/balance_traversal.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeMap; @@ -58,7 +59,7 @@ impl Traversal for Accumulator { } } -/// Returns `Some(T)` if the struct is a `sui::balance::Balance`, and `None` +/// Returns `Some(T)` if the struct is a `iota::balance::Balance`, and `None` /// otherwise. fn is_balance(s: &StructTag) -> Option { (Balance::is_balance(s) && s.type_params.len() == 1).then(|| s.type_params[0].clone()) diff --git a/crates/sui-types/src/object/bounded_visitor.rs b/crates/iota-types/src/object/bounded_visitor.rs similarity index 99% rename from crates/sui-types/src/object/bounded_visitor.rs rename to crates/iota-types/src/object/bounded_visitor.rs index 0f6f67c4070..e89a4221bc4 100644 --- a/crates/sui-types/src/object/bounded_visitor.rs +++ b/crates/iota-types/src/object/bounded_visitor.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::bail; diff --git a/crates/sui-types/src/programmable_transaction_builder.rs b/crates/iota-types/src/programmable_transaction_builder.rs similarity index 93% rename from crates/sui-types/src/programmable_transaction_builder.rs rename to crates/iota-types/src/programmable_transaction_builder.rs index f8e7388f797..a06cfe85375 100644 --- a/crates/sui-types/src/programmable_transaction_builder.rs +++ b/crates/iota-types/src/programmable_transaction_builder.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! Utility for generating programmable transactions, either by specifying a @@ -10,12 +11,12 @@ use move_core_types::{ident_str, identifier::Identifier, language_storage::TypeT use serde::Serialize; use crate::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, + base_types::{IotaAddress, ObjectID, ObjectRef}, move_package::PACKAGE_MODULE_NAME, transaction::{ Argument, CallArg, Command, ObjectArg, ProgrammableMoveCall, ProgrammableTransaction, }, - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, }; #[derive(PartialEq, Eq, Hash)] @@ -193,7 +194,7 @@ impl ProgrammableTransactionBuilder { let cap = self.publish_upgradeable(modules, dep_ids); self.commands .push(Command::MoveCall(Box::new(ProgrammableMoveCall { - package: SUI_FRAMEWORK_PACKAGE_ID, + package: IOTA_FRAMEWORK_PACKAGE_ID, module: PACKAGE_MODULE_NAME.to_owned(), function: ident_str!("make_immutable").to_owned(), type_arguments: vec![], @@ -216,18 +217,18 @@ impl ProgrammableTransactionBuilder { )) } - pub fn transfer_arg(&mut self, recipient: SuiAddress, arg: Argument) { + pub fn transfer_arg(&mut self, recipient: IotaAddress, arg: Argument) { self.transfer_args(recipient, vec![arg]) } - pub fn transfer_args(&mut self, recipient: SuiAddress, args: Vec) { + pub fn transfer_args(&mut self, recipient: IotaAddress, args: Vec) { let rec_arg = self.pure(recipient).unwrap(); self.commands.push(Command::TransferObjects(args, rec_arg)); } pub fn transfer_object( &mut self, - recipient: SuiAddress, + recipient: IotaAddress, object_ref: ObjectRef, ) -> anyhow::Result<()> { let rec_arg = self.pure(recipient).unwrap(); @@ -237,7 +238,7 @@ impl ProgrammableTransactionBuilder { Ok(()) } - pub fn transfer_sui(&mut self, recipient: SuiAddress, amount: Option) { + pub fn transfer_iota(&mut self, recipient: IotaAddress, amount: Option) { let rec_arg = self.pure(recipient).unwrap(); let coin_arg = if let Some(amount) = amount { let amt_arg = self.pure(amount).unwrap(); @@ -248,16 +249,16 @@ impl ProgrammableTransactionBuilder { self.command(Command::TransferObjects(vec![coin_arg], rec_arg)); } - pub fn pay_all_sui(&mut self, recipient: SuiAddress) { + pub fn pay_all_iota(&mut self, recipient: IotaAddress) { let rec_arg = self.pure(recipient).unwrap(); self.command(Command::TransferObjects(vec![Argument::GasCoin], rec_arg)); } /// Will fail to generate if recipients and amounts do not have the same /// lengths - pub fn pay_sui( + pub fn pay_iota( &mut self, - recipients: Vec, + recipients: Vec, amounts: Vec, ) -> anyhow::Result<()> { self.pay_impl(recipients, amounts, Argument::GasCoin) @@ -268,7 +269,7 @@ impl ProgrammableTransactionBuilder { pub fn pay( &mut self, coins: Vec, - recipients: Vec, + recipients: Vec, amounts: Vec, ) -> anyhow::Result<()> { let mut coins = coins.into_iter(); @@ -287,7 +288,7 @@ impl ProgrammableTransactionBuilder { fn pay_impl( &mut self, - recipients: Vec, + recipients: Vec, amounts: Vec, coin: Argument, ) -> anyhow::Result<()> { @@ -304,7 +305,7 @@ impl ProgrammableTransactionBuilder { // collect recipients in the case where they are non-unique in order // to minimize the number of transfers that must be performed - let mut recipient_map: IndexMap> = IndexMap::new(); + let mut recipient_map: IndexMap> = IndexMap::new(); let mut amt_args = vec![]; for (i, (recipient, amount)) in recipients.into_iter().zip(amounts).enumerate() { recipient_map.entry(recipient).or_default().push(i); diff --git a/crates/sui-types/src/quorum_driver_types.rs b/crates/iota-types/src/quorum_driver_types.rs similarity index 95% rename from crates/sui-types/src/quorum_driver_types.rs rename to crates/iota-types/src/quorum_driver_types.rs index 51385727f45..5a154380e33 100644 --- a/crates/sui-types/src/quorum_driver_types.rs +++ b/crates/iota-types/src/quorum_driver_types.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeMap; @@ -16,7 +17,7 @@ use crate::{ CertifiedTransactionEffects, TransactionEffects, TransactionEvents, VerifiedCertifiedTransactionEffects, }, - error::SuiError, + error::IotaError, messages_checkpoint::CheckpointSequenceNumber, transaction::{Transaction, VerifiedTransaction}, }; @@ -34,9 +35,9 @@ pub const NON_RECOVERABLE_ERROR_MSG: &str = #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Error, Hash, AsRefStr)] pub enum QuorumDriverError { #[error("QuorumDriver internal error: {0:?}.")] - QuorumDriverInternalError(SuiError), + QuorumDriverInternalError(IotaError), #[error("Invalid user signature: {0:?}.")] - InvalidUserSignature(SuiError), + InvalidUserSignature(IotaError), #[error( "Failed to sign transaction by a quorum of validators because of locked objects: {:?}, retried a conflicting transaction {:?}, success: {:?}", conflicting_txes, @@ -75,7 +76,7 @@ pub enum QuorumDriverError { }, } -pub type GroupedErrors = Vec<(SuiError, StakeUnit, Vec)>; +pub type GroupedErrors = Vec<(IotaError, StakeUnit, Vec)>; #[derive(Serialize, Deserialize, Clone, Debug, schemars::JsonSchema)] pub enum ExecuteTransactionRequestType { diff --git a/crates/iota-types/src/randomness_state.rs b/crates/iota-types/src/randomness_state.rs new file mode 100644 index 00000000000..bfbc1a53bf8 --- /dev/null +++ b/crates/iota-types/src/randomness_state.rs @@ -0,0 +1,43 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use move_binary_format::{binary_views::BinaryIndexedView, file_format::SignatureToken}; +use move_bytecode_utils::resolve_struct; +use move_core_types::{account_address::AccountAddress, ident_str, identifier::IdentStr}; + +use crate::{ + base_types::SequenceNumber, error::IotaResult, object::Owner, storage::ObjectStore, + IOTA_FRAMEWORK_ADDRESS, IOTA_RANDOMNESS_STATE_OBJECT_ID, +}; + +pub const RANDOMNESS_MODULE_NAME: &IdentStr = ident_str!("random"); +pub const RANDOMNESS_STATE_STRUCT_NAME: &IdentStr = ident_str!("Random"); +pub const RANDOMNESS_STATE_UPDATE_FUNCTION_NAME: &IdentStr = ident_str!("update_randomness_state"); +pub const RANDOMNESS_STATE_CREATE_FUNCTION_NAME: &IdentStr = ident_str!("create"); +pub const RESOLVED_IOTA_RANDOMNESS_STATE: (&AccountAddress, &IdentStr, &IdentStr) = ( + &IOTA_FRAMEWORK_ADDRESS, + RANDOMNESS_MODULE_NAME, + RANDOMNESS_STATE_STRUCT_NAME, +); + +pub fn get_randomness_state_obj_initial_shared_version( + object_store: &dyn ObjectStore, +) -> IotaResult> { + Ok(object_store + .get_object(&IOTA_RANDOMNESS_STATE_OBJECT_ID)? + .map(|obj| match obj.owner { + Owner::Shared { + initial_shared_version, + } => initial_shared_version, + _ => unreachable!("Randomness state object must be shared"), + })) +} + +pub fn is_mutable_random(view: &BinaryIndexedView<'_>, s: &SignatureToken) -> bool { + match s { + SignatureToken::MutableReference(inner) => is_mutable_random(view, inner), + SignatureToken::Struct(idx) => resolve_struct(view, *idx) == RESOLVED_IOTA_RANDOMNESS_STATE, + _ => false, + } +} diff --git a/crates/sui-types/src/signature.rs b/crates/iota-types/src/signature.rs similarity index 86% rename from crates/sui-types/src/signature.rs rename to crates/iota-types/src/signature.rs index cdb5c299abf..01c5205c193 100644 --- a/crates/sui-types/src/signature.rs +++ b/crates/iota-types/src/signature.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::hash::Hash; @@ -21,13 +22,13 @@ use serde::Serialize; use shared_crypto::intent::IntentMessage; use crate::{ - base_types::SuiAddress, + base_types::IotaAddress, committee::EpochId, crypto::{ - CompressedSignature, PublicKey, Signature, SignatureScheme, SuiSignature, + CompressedSignature, IotaSignature, PublicKey, Signature, SignatureScheme, ZkLoginAuthenticatorAsBytes, }, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, multisig::MultiSig, multisig_legacy::MultiSigLegacy, zk_login_authenticator::ZkLoginAuthenticator, @@ -63,24 +64,24 @@ impl VerifyParams { /// A lightweight trait that all members of [enum GenericSignature] implement. #[enum_dispatch] pub trait AuthenticatorTrait { - fn verify_user_authenticator_epoch(&self, epoch: EpochId) -> SuiResult; + fn verify_user_authenticator_epoch(&self, epoch: EpochId) -> IotaResult; fn verify_claims( &self, value: &IntentMessage, - author: SuiAddress, + author: IotaAddress, aux_verify_data: &VerifyParams, - ) -> SuiResult + ) -> IotaResult where T: Serialize; fn verify_authenticator( &self, value: &IntentMessage, - author: SuiAddress, + author: IotaAddress, epoch: Option, aux_verify_data: &VerifyParams, - ) -> SuiResult + ) -> IotaResult where T: Serialize, { @@ -93,9 +94,9 @@ pub trait AuthenticatorTrait { fn verify_uncached_checks( &self, value: &IntentMessage, - author: SuiAddress, + author: IotaAddress, aux_verify_data: &VerifyParams, - ) -> SuiResult + ) -> IotaResult where T: Serialize; } @@ -123,17 +124,17 @@ impl GenericSignature { matches!(self, GenericSignature::MultiSig(_)) } - /// Parse [enum CompressedSignature] from trait SuiSignature `flag || sig || - /// pk`. This is useful for the MultiSig to combine partial signature + /// Parse [enum CompressedSignature] from trait IotaSignature `flag || sig + /// || pk`. This is useful for the MultiSig to combine partial signature /// into a MultiSig public key. - pub fn to_compressed(&self) -> Result { + pub fn to_compressed(&self) -> Result { match self { GenericSignature::Signature(s) => { let bytes = s.signature_bytes(); match s.scheme() { SignatureScheme::ED25519 => Ok(CompressedSignature::Ed25519( (&Ed25519Signature::from_bytes(bytes).map_err(|_| { - SuiError::InvalidSignature { + IotaError::InvalidSignature { error: "Cannot parse ed25519 sig".to_string(), } })?) @@ -141,7 +142,7 @@ impl GenericSignature { )), SignatureScheme::Secp256k1 => Ok(CompressedSignature::Secp256k1( (&Secp256k1Signature::from_bytes(bytes).map_err(|_| { - SuiError::InvalidSignature { + IotaError::InvalidSignature { error: "Cannot parse secp256k1 sig".to_string(), } })?) @@ -149,13 +150,13 @@ impl GenericSignature { )), SignatureScheme::Secp256r1 => Ok(CompressedSignature::Secp256r1( (&Secp256r1Signature::from_bytes(bytes).map_err(|_| { - SuiError::InvalidSignature { + IotaError::InvalidSignature { error: "Cannot parse secp256r1 sig".to_string(), } })?) .into(), )), - _ => Err(SuiError::UnsupportedFeatureError { + _ => Err(IotaError::UnsupportedFeatureError { error: "Unsupported signature scheme".to_string(), }), } @@ -163,45 +164,45 @@ impl GenericSignature { GenericSignature::ZkLoginAuthenticator(s) => Ok(CompressedSignature::ZkLogin( ZkLoginAuthenticatorAsBytes(s.as_ref().to_vec()), )), - _ => Err(SuiError::UnsupportedFeatureError { + _ => Err(IotaError::UnsupportedFeatureError { error: "Unsupported signature scheme".to_string(), }), } } - /// Parse [struct PublicKey] from trait SuiSignature `flag || sig || pk`. + /// Parse [struct PublicKey] from trait IotaSignature `flag || sig || pk`. /// This is useful for the MultiSig to construct the bitmap in [struct /// MultiPublicKey]. - pub fn to_public_key(&self) -> Result { + pub fn to_public_key(&self) -> Result { match self { GenericSignature::Signature(s) => { let bytes = s.public_key_bytes(); match s.scheme() { SignatureScheme::ED25519 => Ok(PublicKey::Ed25519( (&Ed25519PublicKey::from_bytes(bytes).map_err(|_| { - SuiError::KeyConversionError("Cannot parse ed25519 pk".to_string()) + IotaError::KeyConversionError("Cannot parse ed25519 pk".to_string()) })?) .into(), )), SignatureScheme::Secp256k1 => Ok(PublicKey::Secp256k1( (&Secp256k1PublicKey::from_bytes(bytes).map_err(|_| { - SuiError::KeyConversionError("Cannot parse secp256k1 pk".to_string()) + IotaError::KeyConversionError("Cannot parse secp256k1 pk".to_string()) })?) .into(), )), SignatureScheme::Secp256r1 => Ok(PublicKey::Secp256r1( (&Secp256r1PublicKey::from_bytes(bytes).map_err(|_| { - SuiError::KeyConversionError("Cannot parse secp256r1 pk".to_string()) + IotaError::KeyConversionError("Cannot parse secp256r1 pk".to_string()) })?) .into(), )), - _ => Err(SuiError::UnsupportedFeatureError { + _ => Err(IotaError::UnsupportedFeatureError { error: "Unsupported signature scheme in MultiSig".to_string(), }), } } GenericSignature::ZkLoginAuthenticator(s) => s.get_pk(), - _ => Err(SuiError::UnsupportedFeatureError { + _ => Err(IotaError::UnsupportedFeatureError { error: "Unsupported signature scheme".to_string(), }), } @@ -291,15 +292,15 @@ impl<'de> ::serde::Deserialize<'de> for GenericSignature { /// This ports the wrapper trait to the verify_secure defined on [enum /// Signature]. impl AuthenticatorTrait for Signature { - fn verify_user_authenticator_epoch(&self, _: EpochId) -> SuiResult { + fn verify_user_authenticator_epoch(&self, _: EpochId) -> IotaResult { Ok(()) } fn verify_uncached_checks( &self, _value: &IntentMessage, - _author: SuiAddress, + _author: IotaAddress, _aux_verify_data: &VerifyParams, - ) -> SuiResult + ) -> IotaResult where T: Serialize, { @@ -309,9 +310,9 @@ impl AuthenticatorTrait for Signature { fn verify_claims( &self, value: &IntentMessage, - author: SuiAddress, + author: IotaAddress, _aux_verify_data: &VerifyParams, - ) -> SuiResult + ) -> IotaResult where T: Serialize, { diff --git a/crates/iota-types/src/storage/error.rs b/crates/iota-types/src/storage/error.rs new file mode 100644 index 00000000000..f8388264a36 --- /dev/null +++ b/crates/iota-types/src/storage/error.rs @@ -0,0 +1,75 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use typed_store_error::TypedStoreError; + +pub type Result = ::std::result::Result; + +#[derive(Debug)] +pub struct Error { + inner: Box, +} + +type BoxError = Box; + +#[derive(Debug)] +struct Inner { + kind: Kind, + source: Option, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Kind { + Serialization, + Missing, + Custom, +} + +impl Error { + fn new>(kind: Kind, source: Option) -> Self { + Self { + inner: Box::new(Inner { + kind, + source: source.map(Into::into), + }), + } + } + + pub fn serialization>(e: E) -> Self { + Self::new(Kind::Serialization, Some(e)) + } + + pub fn missing>(e: E) -> Self { + Self::new(Kind::Missing, Some(e)) + } + + pub fn custom>(e: E) -> Self { + Self::new(Kind::Custom, Some(e)) + } + + pub fn kind(&self) -> Kind { + self.inner.kind + } +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.inner.source.as_ref().map(|e| &**e as _) + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // TODO: change output based on kind? + write!(f, "{:?}", self) + } +} + +impl From for Error { + fn from(e: TypedStoreError) -> Self { + Self::custom(e) + } +} diff --git a/crates/iota-types/src/storage/mod.rs b/crates/iota-types/src/storage/mod.rs new file mode 100644 index 00000000000..b3c442e89af --- /dev/null +++ b/crates/iota-types/src/storage/mod.rs @@ -0,0 +1,542 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod error; +mod object_store_trait; +mod read_store; +mod shared_in_memory_store; +mod write_store; + +use std::{ + collections::BTreeMap, + fmt::{Display, Formatter}, + sync::Arc, +}; + +use itertools::Itertools; +use move_binary_format::CompiledModule; +use move_core_types::language_storage::ModuleId; +pub use object_store_trait::ObjectStore; +pub use read_store::ReadStore; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; +pub use shared_in_memory_store::{SharedInMemoryStore, SingleCheckpointSharedInMemoryStore}; +pub use write_store::WriteStore; + +use crate::{ + base_types::{ObjectID, ObjectRef, SequenceNumber, TransactionDigest, VersionNumber}, + committee::EpochId, + error::{IotaError, IotaResult}, + execution::{DynamicallyLoadedObjectMetadata, ExecutionResults}, + move_package::MovePackage, + object::Object, + transaction::{SenderSignedData, TransactionDataAPI, TransactionKey}, +}; + +/// A potential input to a transaction. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum InputKey { + VersionedObject { + id: ObjectID, + version: SequenceNumber, + }, + Package { + id: ObjectID, + }, +} + +impl InputKey { + pub fn id(&self) -> ObjectID { + match self { + InputKey::VersionedObject { id, .. } => *id, + InputKey::Package { id } => *id, + } + } + + pub fn version(&self) -> Option { + match self { + InputKey::VersionedObject { version, .. } => Some(*version), + InputKey::Package { .. } => None, + } + } +} + +impl From<&Object> for InputKey { + fn from(obj: &Object) -> Self { + if obj.is_package() { + InputKey::Package { id: obj.id() } + } else { + InputKey::VersionedObject { + id: obj.id(), + version: obj.version(), + } + } + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] +pub enum WriteKind { + /// The object was in storage already but has been modified + Mutate, + /// The object was created in this transaction + Create, + /// The object was previously wrapped in another object, but has been + /// restored to storage + Unwrap, +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] +pub enum DeleteKind { + /// An object is provided in the call input, and gets deleted. + Normal, + /// An object is not provided in the call input, but gets unwrapped + /// from another object, and then gets deleted. + UnwrapThenDelete, + /// An object is provided in the call input, and gets wrapped into another + /// object. + Wrap, +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] +pub enum MarkerValue { + /// An object was received at the given version in the transaction and is no + /// longer able to be received at that version in subequent + /// transactions. + Received, + /// An owned object was deleted (or wrapped) at the given version, and is no + /// longer able to be accessed or used in subsequent transactions. + OwnedDeleted, + /// A shared object was deleted by the transaction and is no longer able to + /// be accessed or used in subsequent transactions. + SharedDeleted(TransactionDigest), +} + +/// DeleteKind together with the old sequence number prior to the deletion, if +/// available. For normal deletion and wrap, we always will consult the object +/// store to obtain the old sequence number. For UnwrapThenDelete however, in +/// the old protocol where simplified_unwrap_then_delete is false, +/// we will consult the object store to obtain the old sequence number, which +/// latter will be put in modified_at_versions; in the new protocol where +/// simplified_unwrap_then_delete is true, we will not consult the object store, +/// and hence won't have the old sequence number. +#[derive(Debug)] +pub enum DeleteKindWithOldVersion { + Normal(SequenceNumber), + // This variant will be deprecated when we turn on simplified_unwrap_then_delete. + UnwrapThenDeleteDEPRECATED(SequenceNumber), + UnwrapThenDelete, + Wrap(SequenceNumber), +} + +impl DeleteKindWithOldVersion { + pub fn old_version(&self) -> Option { + match self { + DeleteKindWithOldVersion::Normal(version) + | DeleteKindWithOldVersion::UnwrapThenDeleteDEPRECATED(version) + | DeleteKindWithOldVersion::Wrap(version) => Some(*version), + DeleteKindWithOldVersion::UnwrapThenDelete => None, + } + } + + pub fn to_delete_kind(&self) -> DeleteKind { + match self { + DeleteKindWithOldVersion::Normal(_) => DeleteKind::Normal, + DeleteKindWithOldVersion::UnwrapThenDeleteDEPRECATED(_) + | DeleteKindWithOldVersion::UnwrapThenDelete => DeleteKind::UnwrapThenDelete, + DeleteKindWithOldVersion::Wrap(_) => DeleteKind::Wrap, + } + } +} + +#[derive(Debug)] +pub enum ObjectChange { + Write(Object, WriteKind), + // DeleteKind together with the old sequence number prior to the deletion, if available. + Delete(DeleteKindWithOldVersion), +} + +pub trait StorageView: Storage + ParentSync + ChildObjectResolver {} +impl StorageView for T {} + +/// An abstraction of the (possibly distributed) store for objects. This +/// API only allows for the retrieval of objects, not any state changes +pub trait ChildObjectResolver { + /// `child` must have an `ObjectOwner` ownership equal to `owner`. + fn read_child_object( + &self, + parent: &ObjectID, + child: &ObjectID, + child_version_upper_bound: SequenceNumber, + ) -> IotaResult>; + + /// `receiving_object_id` must have an `AddressOwner` ownership equal to + /// `owner`. `get_object_received_at_version` must be the exact version + /// at which the object will be received, and it cannot have been + /// previously received at that version. NB: An object not existing at + /// that version, and not having valid access to the object will be treated + /// exactly the same and `Ok(None)` must be returned. + fn get_object_received_at_version( + &self, + owner: &ObjectID, + receiving_object_id: &ObjectID, + receive_object_at_version: SequenceNumber, + epoch_id: EpochId, + ) -> IotaResult>; +} + +/// An abstraction of the (possibly distributed) store for objects, and (soon) +/// events and transactions +pub trait Storage { + fn reset(&mut self); + + fn read_object(&self, id: &ObjectID) -> Option<&Object>; + + fn record_execution_results(&mut self, results: ExecutionResults); + + fn save_loaded_runtime_objects( + &mut self, + loaded_runtime_objects: BTreeMap, + ); + + fn save_wrapped_object_containers( + &mut self, + wrapped_object_containers: BTreeMap, + ); +} + +pub type PackageFetchResults = Result, Vec>; + +#[derive(Clone, Debug)] +pub struct PackageObject { + package_object: Object, +} + +impl PackageObject { + pub fn new(package_object: Object) -> Self { + assert!(package_object.is_package()); + Self { package_object } + } + + pub fn object(&self) -> &Object { + &self.package_object + } + + pub fn move_package(&self) -> &MovePackage { + self.package_object.data.try_as_package().unwrap() + } +} + +impl From for Object { + fn from(package_object_arc: PackageObject) -> Self { + package_object_arc.package_object + } +} + +pub trait BackingPackageStore { + fn get_package_object(&self, package_id: &ObjectID) -> IotaResult>; +} + +impl BackingPackageStore for Arc { + fn get_package_object(&self, package_id: &ObjectID) -> IotaResult> { + BackingPackageStore::get_package_object(self.as_ref(), package_id) + } +} + +impl BackingPackageStore for &S { + fn get_package_object(&self, package_id: &ObjectID) -> IotaResult> { + BackingPackageStore::get_package_object(*self, package_id) + } +} + +impl BackingPackageStore for &mut S { + fn get_package_object(&self, package_id: &ObjectID) -> IotaResult> { + BackingPackageStore::get_package_object(*self, package_id) + } +} + +pub fn load_package_object_from_object_store( + store: &impl ObjectStore, + package_id: &ObjectID, +) -> IotaResult> { + let package = store.get_object(package_id)?; + if let Some(obj) = &package { + fp_ensure!( + obj.is_package(), + IotaError::BadObjectType { + error: format!("Package expected, Move object found: {package_id}"), + } + ); + } + Ok(package.map(PackageObject::new)) +} + +/// Returns Ok() if all +/// package IDs in `package_id` were found. If any package in `package_ids` was +/// not found it returns a list of any package ids that are unable to be +/// found>). +pub fn get_package_objects<'a>( + store: &impl BackingPackageStore, + package_ids: impl IntoIterator, +) -> IotaResult> { + let packages: Vec> = package_ids + .into_iter() + .map(|id| match store.get_package_object(id) { + Ok(None) => Ok(Err(*id)), + Ok(Some(o)) => Ok(Ok(o)), + Err(x) => Err(x), + }) + .collect::>()?; + + let (fetched, failed_to_fetch): (Vec<_>, Vec<_>) = packages.into_iter().partition_result(); + if !failed_to_fetch.is_empty() { + Ok(Err(failed_to_fetch)) + } else { + Ok(Ok(fetched)) + } +} + +pub fn get_module( + store: S, + module_id: &ModuleId, +) -> Result>, IotaError> { + Ok(store + .get_package_object(&ObjectID::from(*module_id.address()))? + .and_then(|package| { + package + .move_package() + .serialized_module_map() + .get(module_id.name().as_str()) + .cloned() + })) +} + +pub fn get_module_by_id( + store: S, + id: &ModuleId, +) -> anyhow::Result, IotaError> { + Ok(get_module(store, id)? + .map(|bytes| CompiledModule::deserialize_with_defaults(&bytes).unwrap())) +} + +pub trait ParentSync { + /// This function is only called by older protocol versions. + /// It creates an explicit dependency to tombstones, which is not desired. + fn get_latest_parent_entry_ref_deprecated( + &self, + object_id: ObjectID, + ) -> IotaResult>; +} + +impl ParentSync for std::sync::Arc { + fn get_latest_parent_entry_ref_deprecated( + &self, + object_id: ObjectID, + ) -> IotaResult> { + ParentSync::get_latest_parent_entry_ref_deprecated(self.as_ref(), object_id) + } +} + +impl ParentSync for &S { + fn get_latest_parent_entry_ref_deprecated( + &self, + object_id: ObjectID, + ) -> IotaResult> { + ParentSync::get_latest_parent_entry_ref_deprecated(*self, object_id) + } +} + +impl ParentSync for &mut S { + fn get_latest_parent_entry_ref_deprecated( + &self, + object_id: ObjectID, + ) -> IotaResult> { + ParentSync::get_latest_parent_entry_ref_deprecated(*self, object_id) + } +} + +impl ChildObjectResolver for std::sync::Arc { + fn read_child_object( + &self, + parent: &ObjectID, + child: &ObjectID, + child_version_upper_bound: SequenceNumber, + ) -> IotaResult> { + ChildObjectResolver::read_child_object( + self.as_ref(), + parent, + child, + child_version_upper_bound, + ) + } + fn get_object_received_at_version( + &self, + owner: &ObjectID, + receiving_object_id: &ObjectID, + receive_object_at_version: SequenceNumber, + epoch_id: EpochId, + ) -> IotaResult> { + ChildObjectResolver::get_object_received_at_version( + self.as_ref(), + owner, + receiving_object_id, + receive_object_at_version, + epoch_id, + ) + } +} + +impl ChildObjectResolver for &S { + fn read_child_object( + &self, + parent: &ObjectID, + child: &ObjectID, + child_version_upper_bound: SequenceNumber, + ) -> IotaResult> { + ChildObjectResolver::read_child_object(*self, parent, child, child_version_upper_bound) + } + fn get_object_received_at_version( + &self, + owner: &ObjectID, + receiving_object_id: &ObjectID, + receive_object_at_version: SequenceNumber, + epoch_id: EpochId, + ) -> IotaResult> { + ChildObjectResolver::get_object_received_at_version( + *self, + owner, + receiving_object_id, + receive_object_at_version, + epoch_id, + ) + } +} + +impl ChildObjectResolver for &mut S { + fn read_child_object( + &self, + parent: &ObjectID, + child: &ObjectID, + child_version_upper_bound: SequenceNumber, + ) -> IotaResult> { + ChildObjectResolver::read_child_object(*self, parent, child, child_version_upper_bound) + } + fn get_object_received_at_version( + &self, + owner: &ObjectID, + receiving_object_id: &ObjectID, + receive_object_at_version: SequenceNumber, + epoch_id: EpochId, + ) -> IotaResult> { + ChildObjectResolver::get_object_received_at_version( + *self, + owner, + receiving_object_id, + receive_object_at_version, + epoch_id, + ) + } +} + +// The primary key type for object storage. +#[serde_as] +#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)] +pub struct ObjectKey(pub ObjectID, pub VersionNumber); + +impl ObjectKey { + pub const ZERO: ObjectKey = ObjectKey(ObjectID::ZERO, VersionNumber::MIN); + + pub fn max_for_id(id: &ObjectID) -> Self { + Self(*id, VersionNumber::MAX) + } + + pub fn min_for_id(id: &ObjectID) -> Self { + Self(*id, VersionNumber::MIN) + } +} + +impl From for ObjectKey { + fn from(object_ref: ObjectRef) -> Self { + ObjectKey::from(&object_ref) + } +} + +impl From<&ObjectRef> for ObjectKey { + fn from(object_ref: &ObjectRef) -> Self { + Self(object_ref.0, object_ref.1) + } +} + +pub enum ObjectOrTombstone { + Object(Object), + Tombstone(ObjectRef), +} + +impl From for ObjectOrTombstone { + fn from(object: Object) -> Self { + ObjectOrTombstone::Object(object) + } +} + +/// Fetch the `ObjectKey`s (IDs and versions) for non-shared input objects. +/// Includes owned, and immutable objects as well as the gas objects, but not +/// move packages or shared objects. +pub fn transaction_input_object_keys(tx: &SenderSignedData) -> IotaResult> { + use crate::transaction::InputObjectKind as I; + Ok(tx + .intent_message() + .value + .input_objects()? + .into_iter() + .filter_map(|object| match object { + I::MovePackage(_) | I::SharedMoveObject { .. } => None, + I::ImmOrOwnedMoveObject(obj) => Some(obj.into()), + }) + .collect()) +} + +pub fn transaction_receiving_object_keys(tx: &SenderSignedData) -> Vec { + tx.intent_message() + .value + .receiving_objects() + .into_iter() + .map(|oref| oref.into()) + .collect() +} + +impl Display for DeleteKind { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + DeleteKind::Wrap => write!(f, "Wrap"), + DeleteKind::Normal => write!(f, "Normal"), + DeleteKind::UnwrapThenDelete => write!(f, "UnwrapThenDelete"), + } + } +} + +pub trait BackingStore: + BackingPackageStore + ChildObjectResolver + ObjectStore + ParentSync +{ + fn as_object_store(&self) -> &dyn ObjectStore; +} + +impl BackingStore for T +where + T: BackingPackageStore, + T: ChildObjectResolver, + T: ObjectStore, + T: ParentSync, +{ + fn as_object_store(&self) -> &dyn ObjectStore { + self + } +} + +pub trait GetSharedLocks: Send + Sync { + fn get_shared_locks( + &self, + key: &TransactionKey, + ) -> Result, IotaError>; +} diff --git a/crates/sui-types/src/storage/object_store_trait.rs b/crates/iota-types/src/storage/object_store_trait.rs similarity index 98% rename from crates/sui-types/src/storage/object_store_trait.rs rename to crates/iota-types/src/storage/object_store_trait.rs index da9b36e14cb..67bf9806e62 100644 --- a/crates/sui-types/src/storage/object_store_trait.rs +++ b/crates/iota-types/src/storage/object_store_trait.rs @@ -1,6 +1,9 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + use std::{collections::BTreeMap, sync::Arc}; use super::{error::Result, ObjectKey}; diff --git a/crates/sui-types/src/storage/read_store.rs b/crates/iota-types/src/storage/read_store.rs similarity index 99% rename from crates/sui-types/src/storage/read_store.rs rename to crates/iota-types/src/storage/read_store.rs index 6748c02b056..0f18d0494b4 100644 --- a/crates/sui-types/src/storage/read_store.rs +++ b/crates/iota-types/src/storage/read_store.rs @@ -1,6 +1,9 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + use std::sync::Arc; use super::{error::Result, ObjectStore}; diff --git a/crates/sui-types/src/storage/shared_in_memory_store.rs b/crates/iota-types/src/storage/shared_in_memory_store.rs similarity index 99% rename from crates/sui-types/src/storage/shared_in_memory_store.rs rename to crates/iota-types/src/storage/shared_in_memory_store.rs index 0c05edb1737..a18bd80e788 100644 --- a/crates/sui-types/src/storage/shared_in_memory_store.rs +++ b/crates/iota-types/src/storage/shared_in_memory_store.rs @@ -1,6 +1,9 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + use std::{collections::HashMap, sync::Arc}; use tap::Pipe; diff --git a/crates/sui-types/src/storage/write_store.rs b/crates/iota-types/src/storage/write_store.rs similarity index 97% rename from crates/sui-types/src/storage/write_store.rs rename to crates/iota-types/src/storage/write_store.rs index faa3e96ec8f..a66682a8f7c 100644 --- a/crates/sui-types/src/storage/write_store.rs +++ b/crates/iota-types/src/storage/write_store.rs @@ -1,6 +1,9 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + use std::sync::Arc; use super::error::Result; diff --git a/crates/iota-types/src/timelock/mod.rs b/crates/iota-types/src/timelock/mod.rs new file mode 100644 index 00000000000..7c9858e8c45 --- /dev/null +++ b/crates/iota-types/src/timelock/mod.rs @@ -0,0 +1,8 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#[allow(clippy::module_inception)] +pub mod timelock; +pub mod timelocked_staked_iota; +pub mod timelocked_staking; diff --git a/crates/iota-types/src/timelock/timelock.rs b/crates/iota-types/src/timelock/timelock.rs new file mode 100644 index 00000000000..8b21150278a --- /dev/null +++ b/crates/iota-types/src/timelock/timelock.rs @@ -0,0 +1,105 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use move_core_types::{ + // annotated_value::{MoveFieldLayout, MoveStructLayout, MoveTypeLayout}, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag}, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use crate::{balance::Balance, base_types::ObjectID, id::UID, TIMELOCK_ADDRESS}; + +#[cfg(test)] +#[path = "../unit_tests/timelock/timelock_tests.rs"] +mod timelock_tests; + +pub const TIMELOCK_MODULE_NAME: &IdentStr = ident_str!("timelock"); +pub const TIMELOCK_STRUCT_NAME: &IdentStr = ident_str!("TimeLock"); + +/// Rust version of the Move stardust::timelock::TimeLock type. +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema, Eq, PartialEq)] +pub struct TimeLock { + pub id: UID, + /// The locked object. + pub locked: T, + /// This is the epoch time stamp of when the lock expires. + pub expiration_timestamp_ms: u64, +} + +impl TimeLock { + /// Constructor. + pub fn new(id: UID, locked: T, expiration_timestamp_ms: u64) -> Self { + Self { + id, + locked, + expiration_timestamp_ms, + } + } + + /// Get the TimeLock's `type`. + pub fn type_(type_param: TypeTag) -> StructTag { + StructTag { + address: TIMELOCK_ADDRESS, + module: TIMELOCK_MODULE_NAME.to_owned(), + name: TIMELOCK_STRUCT_NAME.to_owned(), + type_params: vec![type_param], + } + } + + /// Get the TimeLock's `id`. + pub fn id(&self) -> &ObjectID { + self.id.object_id() + } + + /// Get the TimeLock's `locked` object. + pub fn locked(&self) -> &T { + &self.locked + } + + /// Get the TimeLock's `expiration_timestamp_ms`. + pub fn expiration_timestamp_ms(&self) -> u64 { + self.expiration_timestamp_ms + } +} + +impl<'de, T> TimeLock +where + T: Serialize + Deserialize<'de>, +{ + /// Create a `TimeLock` from BCS bytes. + pub fn from_bcs_bytes(content: &'de [u8]) -> Result { + bcs::from_bytes(content) + } + + /// Serialize a `TimeLock` as a `Vec` of BCS. + pub fn to_bcs_bytes(&self) -> Vec { + bcs::to_bytes(&self).unwrap() + } +} + +/// Is this other StructTag representing a TimeLock? +pub fn is_timelock(other: &StructTag) -> bool { + other.address == TIMELOCK_ADDRESS + && other.module.as_ident_str() == TIMELOCK_MODULE_NAME + && other.name.as_ident_str() == TIMELOCK_STRUCT_NAME +} + +/// Is this other StructTag representing a TimeLock>? +pub fn is_timelocked_balance(other: &StructTag) -> bool { + if !is_timelock(other) { + return false; + } + + if other.type_params.len() != 1 { + return false; + } + + match &other.type_params[0] { + TypeTag::Struct(tag) => Balance::is_balance(tag), + _ => false, + } +} diff --git a/crates/iota-types/src/timelock/timelocked_staked_iota.rs b/crates/iota-types/src/timelock/timelocked_staked_iota.rs new file mode 100644 index 00000000000..ec1196b91ca --- /dev/null +++ b/crates/iota-types/src/timelock/timelocked_staked_iota.rs @@ -0,0 +1,104 @@ +// Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; +use serde::{Deserialize, Serialize}; + +use crate::{ + base_types::ObjectID, + committee::EpochId, + error::IotaError, + governance::StakedIota, + id::UID, + object::{Data, Object}, + TIMELOCK_ADDRESS, +}; + +pub const TIMELOCKED_STAKED_IOTA_MODULE_NAME: &IdentStr = ident_str!("timelocked_staked_iota"); +pub const TIMELOCKED_STAKED_IOTA_STRUCT_NAME: &IdentStr = ident_str!("TimelockedStakedIota"); + +/// Rust version of the Move +/// stardust::timelocked_staked_iota::TimelockedStakedIota type. +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct TimelockedStakedIota { + id: UID, + /// A self-custodial object holding the staked IOTA tokens. + staked_iota: StakedIota, + /// This is the epoch time stamp of when the lock expires. + expiration_timestamp_ms: u64, +} + +impl TimelockedStakedIota { + /// Get the TimeLock's `type`. + pub fn type_() -> StructTag { + StructTag { + address: TIMELOCK_ADDRESS, + module: TIMELOCKED_STAKED_IOTA_MODULE_NAME.to_owned(), + name: TIMELOCKED_STAKED_IOTA_STRUCT_NAME.to_owned(), + type_params: vec![], + } + } + + /// Is this other StructTag representing a TimelockedStakedIota? + pub fn is_timelocked_staked_iota(s: &StructTag) -> bool { + s.address == TIMELOCK_ADDRESS + && s.module.as_ident_str() == TIMELOCKED_STAKED_IOTA_MODULE_NAME + && s.name.as_ident_str() == TIMELOCKED_STAKED_IOTA_STRUCT_NAME + && s.type_params.is_empty() + } + + /// Get the TimelockedStakedIota's `id`. + pub fn id(&self) -> ObjectID { + self.id.id.bytes + } + + /// Get the wrapped StakedIota's `pool_id`. + pub fn pool_id(&self) -> ObjectID { + self.staked_iota.pool_id() + } + + /// Get the wrapped StakedIota's `activation_epoch`. + pub fn activation_epoch(&self) -> EpochId { + self.staked_iota.activation_epoch() + } + + /// Get the wrapped StakedIota's `request_epoch`. + pub fn request_epoch(&self) -> EpochId { + // TODO: this might change when we implement warm up period. + self.staked_iota.activation_epoch().saturating_sub(1) + } + + /// Get the wrapped StakedIota's `principal`. + pub fn principal(&self) -> u64 { + self.staked_iota.principal() + } + + /// Get the TimelockedStakedIota's `expiration_timestamp_ms`. + pub fn expiration_timestamp_ms(&self) -> u64 { + self.expiration_timestamp_ms + } +} + +impl TryFrom<&Object> for TimelockedStakedIota { + type Error = IotaError; + fn try_from(object: &Object) -> Result { + match &object.data { + Data::Move(o) => { + if o.type_().is_timelocked_staked_iota() { + return bcs::from_bytes(o.contents()).map_err(|err| IotaError::TypeError { + error: format!( + "Unable to deserialize TimelockedStakedIota object: {:?}", + err + ), + }); + } + } + Data::Package(_) => {} + } + + Err(IotaError::TypeError { + error: format!("Object type is not a TimelockedStakedIota: {:?}", object), + }) + } +} diff --git a/crates/sui-types/src/timelock/timelocked_staking.rs b/crates/iota-types/src/timelock/timelocked_staking.rs similarity index 88% rename from crates/sui-types/src/timelock/timelocked_staking.rs rename to crates/iota-types/src/timelock/timelocked_staking.rs index 9d80be6a078..21e98096afb 100644 --- a/crates/sui-types/src/timelock/timelocked_staking.rs +++ b/crates/iota-types/src/timelock/timelocked_staking.rs @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use move_core_types::{ident_str, identifier::IdentStr}; diff --git a/crates/sui-types/src/transaction.rs b/crates/iota-types/src/transaction.rs similarity index 94% rename from crates/sui-types/src/transaction.rs rename to crates/iota-types/src/transaction.rs index 8a7cb7f2b6f..6f31b27db3e 100644 --- a/crates/sui-types/src/transaction.rs +++ b/crates/iota-types/src/transaction.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -12,6 +13,7 @@ use std::{ use enum_dispatch::enum_dispatch; use fastcrypto::{encoding::Base64, hash::HashFunction}; +use iota_protocol_config::{ProtocolConfig, SupportedProtocolVersions}; use itertools::Either; use move_core_types::{ ident_str, @@ -22,7 +24,6 @@ use nonempty::{nonempty, NonEmpty}; use serde::{Deserialize, Serialize}; use shared_crypto::intent::{Intent, IntentMessage, IntentScope}; use strum::IntoStaticStr; -use sui_protocol_config::{ProtocolConfig, SupportedProtocolVersions}; use tap::Pipe; use tracing::trace; @@ -32,8 +33,8 @@ use crate::{ committee::{EpochId, ProtocolVersion}, crypto::{ default_hash, AuthoritySignInfo, AuthoritySignature, AuthorityStrongQuorumSignInfo, - DefaultHash, Ed25519SuiSignature, EmptySignInfo, RandomnessRound, Signature, Signer, - SuiSignatureInner, ToFromBytes, + DefaultHash, Ed25519IotaSignature, EmptySignInfo, IotaSignatureInner, RandomnessRound, + Signature, Signer, ToFromBytes, }, digests::{CertificateDigest, ConsensusCommitDigest, SenderSignedDataDigest}, execution::SharedInput, @@ -45,10 +46,10 @@ use crate::{ object::{MoveObject, Object, Owner}, programmable_transaction_builder::ProgrammableTransactionBuilder, signature::{AuthenticatorTrait, GenericSignature, VerifyParams}, - SUI_AUTHENTICATOR_STATE_OBJECT_ID, SUI_AUTHENTICATOR_STATE_OBJECT_SHARED_VERSION, - SUI_CLOCK_OBJECT_ID, SUI_CLOCK_OBJECT_SHARED_VERSION, SUI_FRAMEWORK_PACKAGE_ID, - SUI_RANDOMNESS_STATE_OBJECT_ID, SUI_SYSTEM_STATE_OBJECT_ID, - SUI_SYSTEM_STATE_OBJECT_SHARED_VERSION, + IOTA_AUTHENTICATOR_STATE_OBJECT_ID, IOTA_AUTHENTICATOR_STATE_OBJECT_SHARED_VERSION, + IOTA_CLOCK_OBJECT_ID, IOTA_CLOCK_OBJECT_SHARED_VERSION, IOTA_FRAMEWORK_PACKAGE_ID, + IOTA_RANDOMNESS_STATE_OBJECT_ID, IOTA_SYSTEM_STATE_OBJECT_ID, + IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION, }; pub const TEST_ONLY_GAS_UNIT_FOR_TRANSFER: u64 = 10_000; @@ -83,20 +84,20 @@ pub enum CallArg { } impl CallArg { - pub const SUI_SYSTEM_MUT: Self = Self::Object(ObjectArg::SUI_SYSTEM_MUT); + pub const IOTA_SYSTEM_MUT: Self = Self::Object(ObjectArg::IOTA_SYSTEM_MUT); pub const CLOCK_IMM: Self = Self::Object(ObjectArg::SharedObject { - id: SUI_CLOCK_OBJECT_ID, - initial_shared_version: SUI_CLOCK_OBJECT_SHARED_VERSION, + id: IOTA_CLOCK_OBJECT_ID, + initial_shared_version: IOTA_CLOCK_OBJECT_SHARED_VERSION, mutable: false, }); pub const CLOCK_MUT: Self = Self::Object(ObjectArg::SharedObject { - id: SUI_CLOCK_OBJECT_ID, - initial_shared_version: SUI_CLOCK_OBJECT_SHARED_VERSION, + id: IOTA_CLOCK_OBJECT_ID, + initial_shared_version: IOTA_CLOCK_OBJECT_SHARED_VERSION, mutable: true, }); pub const AUTHENTICATOR_MUT: Self = Self::Object(ObjectArg::SharedObject { - id: SUI_AUTHENTICATOR_STATE_OBJECT_ID, - initial_shared_version: SUI_AUTHENTICATOR_STATE_OBJECT_SHARED_VERSION, + id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID, + initial_shared_version: IOTA_AUTHENTICATOR_STATE_OBJECT_SHARED_VERSION, mutable: true, }); } @@ -351,15 +352,15 @@ impl EndOfEpochTransactionKind { match self { Self::ChangeEpoch(_) => { vec![InputObjectKind::SharedMoveObject { - id: SUI_SYSTEM_STATE_OBJECT_ID, - initial_shared_version: SUI_SYSTEM_STATE_OBJECT_SHARED_VERSION, + id: IOTA_SYSTEM_STATE_OBJECT_ID, + initial_shared_version: IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION, mutable: true, }] } Self::AuthenticatorStateCreate => vec![], Self::AuthenticatorStateExpire(expire) => { vec![InputObjectKind::SharedMoveObject { - id: SUI_AUTHENTICATOR_STATE_OBJECT_ID, + id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID, initial_shared_version: expire.authenticator_obj_initial_shared_version(), mutable: true, }] @@ -371,9 +372,9 @@ impl EndOfEpochTransactionKind { fn shared_input_objects(&self) -> impl Iterator + '_ { match self { - Self::ChangeEpoch(_) => Either::Left(iter::once(SharedInputObject::SUI_SYSTEM_OBJ)), + Self::ChangeEpoch(_) => Either::Left(iter::once(SharedInputObject::IOTA_SYSTEM_OBJ)), Self::AuthenticatorStateExpire(expire) => Either::Left(iter::once(SharedInputObject { - id: SUI_AUTHENTICATOR_STATE_OBJECT_ID, + id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID, initial_shared_version: expire.authenticator_obj_initial_shared_version(), mutable: true, })), @@ -404,7 +405,7 @@ impl EndOfEpochTransactionKind { } impl VersionedProtocolMessage for TransactionKind { - fn check_version_supported(&self, protocol_config: &ProtocolConfig) -> SuiResult { + fn check_version_supported(&self, protocol_config: &ProtocolConfig) -> IotaResult { // When adding new cases, they must be guarded by a feature flag and return // UnsupportedFeatureError if the flag is not set. match &self { @@ -421,7 +422,7 @@ impl VersionedProtocolMessage for TransactionKind { .iter() .any(|arg| !arg.receiving_objects().is_empty()); if has_receiving_objects { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: format!( "receiving objects is not supported at {:?}", protocol_config.version @@ -435,7 +436,7 @@ impl VersionedProtocolMessage for TransactionKind { if protocol_config.enable_jwk_consensus_updates() { Ok(()) } else { - Err(SuiError::UnsupportedFeatureError { + Err(IotaError::UnsupportedFeatureError { error: "authenticator state updates not enabled".to_string(), }) } @@ -444,14 +445,14 @@ impl VersionedProtocolMessage for TransactionKind { if protocol_config.random_beacon() { Ok(()) } else { - Err(SuiError::UnsupportedFeatureError { + Err(IotaError::UnsupportedFeatureError { error: "randomness state updates not enabled".to_string(), }) } } TransactionKind::EndOfEpochTransaction(txns) => { if !protocol_config.end_of_epoch_transaction_supported() { - Err(SuiError::UnsupportedFeatureError { + Err(IotaError::UnsupportedFeatureError { error: "EndOfEpochTransaction is not supported".to_string(), }) } else { @@ -461,7 +462,7 @@ impl VersionedProtocolMessage for TransactionKind { EndOfEpochTransactionKind::AuthenticatorStateCreate | EndOfEpochTransactionKind::AuthenticatorStateExpire(_) => { if !protocol_config.enable_jwk_consensus_updates() { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: "authenticator state updates not enabled" .to_string(), }); @@ -469,14 +470,14 @@ impl VersionedProtocolMessage for TransactionKind { } EndOfEpochTransactionKind::RandomnessStateCreate => { if !protocol_config.random_beacon() { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: "random beacon not enabled".to_string(), }); } } EndOfEpochTransactionKind::DenyListStateCreate => { if !protocol_config.enable_coin_deny_list() { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: "coin deny list not enabled".to_string(), }); } @@ -491,7 +492,7 @@ impl VersionedProtocolMessage for TransactionKind { if protocol_config.include_consensus_digest_in_prologue() { Ok(()) } else { - Err(SuiError::UnsupportedFeatureError { + Err(IotaError::UnsupportedFeatureError { error: "ConsensusCommitPrologueV2 is not supported".to_string(), }) } @@ -610,9 +611,9 @@ impl From for CallArg { } impl ObjectArg { - pub const SUI_SYSTEM_MUT: Self = Self::SharedObject { - id: SUI_SYSTEM_STATE_OBJECT_ID, - initial_shared_version: SUI_SYSTEM_STATE_OBJECT_SHARED_VERSION, + pub const IOTA_SYSTEM_MUT: Self = Self::SharedObject { + id: IOTA_SYSTEM_STATE_OBJECT_ID, + initial_shared_version: IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION, mutable: true, }; @@ -994,7 +995,7 @@ impl ProgrammableTransaction { // A command that uses Random can only be followed by TransferObjects or // MergeCoins. if let Some(random_index) = inputs.iter().position(|obj| { - matches!(obj, CallArg::Object(ObjectArg::SharedObject { id, .. }) if *id == SUI_RANDOMNESS_STATE_OBJECT_ID) + matches!(obj, CallArg::Object(ObjectArg::SharedObject { id, .. }) if *id == IOTA_RANDOMNESS_STATE_OBJECT_ID) }) { let mut used_random_object = false; let random_index = random_index.try_into().unwrap(); @@ -1157,9 +1158,9 @@ pub struct SharedInputObject { } impl SharedInputObject { - pub const SUI_SYSTEM_OBJ: Self = Self { - id: SUI_SYSTEM_STATE_OBJECT_ID, - initial_shared_version: SUI_SYSTEM_STATE_OBJECT_SHARED_VERSION, + pub const IOTA_SYSTEM_OBJ: Self = Self { + id: IOTA_SYSTEM_STATE_OBJECT_ID, + initial_shared_version: IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION, mutable: true, }; @@ -1231,26 +1232,26 @@ impl TransactionKind { pub fn shared_input_objects(&self) -> impl Iterator + '_ { match &self { Self::ChangeEpoch(_) => { - Either::Left(Either::Left(iter::once(SharedInputObject::SUI_SYSTEM_OBJ))) + Either::Left(Either::Left(iter::once(SharedInputObject::IOTA_SYSTEM_OBJ))) } Self::ConsensusCommitPrologue(_) | Self::ConsensusCommitPrologueV2(_) => { Either::Left(Either::Left(iter::once(SharedInputObject { - id: SUI_CLOCK_OBJECT_ID, - initial_shared_version: SUI_CLOCK_OBJECT_SHARED_VERSION, + id: IOTA_CLOCK_OBJECT_ID, + initial_shared_version: IOTA_CLOCK_OBJECT_SHARED_VERSION, mutable: true, }))) } Self::AuthenticatorStateUpdate(update) => { Either::Left(Either::Left(iter::once(SharedInputObject { - id: SUI_AUTHENTICATOR_STATE_OBJECT_ID, + id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID, initial_shared_version: update.authenticator_obj_initial_shared_version, mutable: true, }))) } Self::RandomnessStateUpdate(update) => { Either::Left(Either::Left(iter::once(SharedInputObject { - id: SUI_RANDOMNESS_STATE_OBJECT_ID, + id: IOTA_RANDOMNESS_STATE_OBJECT_ID, initial_shared_version: update.randomness_obj_initial_shared_version, mutable: true, }))) @@ -1294,8 +1295,8 @@ impl TransactionKind { let input_objects = match &self { Self::ChangeEpoch(_) => { vec![InputObjectKind::SharedMoveObject { - id: SUI_SYSTEM_STATE_OBJECT_ID, - initial_shared_version: SUI_SYSTEM_STATE_OBJECT_SHARED_VERSION, + id: IOTA_SYSTEM_STATE_OBJECT_ID, + initial_shared_version: IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION, mutable: true, }] } @@ -1304,21 +1305,21 @@ impl TransactionKind { } Self::ConsensusCommitPrologue(_) | Self::ConsensusCommitPrologueV2(_) => { vec![InputObjectKind::SharedMoveObject { - id: SUI_CLOCK_OBJECT_ID, - initial_shared_version: SUI_CLOCK_OBJECT_SHARED_VERSION, + id: IOTA_CLOCK_OBJECT_ID, + initial_shared_version: IOTA_CLOCK_OBJECT_SHARED_VERSION, mutable: true, }] } Self::AuthenticatorStateUpdate(update) => { vec![InputObjectKind::SharedMoveObject { - id: SUI_AUTHENTICATOR_STATE_OBJECT_ID, + id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID, initial_shared_version: update.authenticator_obj_initial_shared_version(), mutable: true, }] } Self::RandomnessStateUpdate(update) => { vec![InputObjectKind::SharedMoveObject { - id: SUI_RANDOMNESS_STATE_OBJECT_ID, + id: IOTA_RANDOMNESS_STATE_OBJECT_ID, initial_shared_version: update.randomness_obj_initial_shared_version(), mutable: true, }] @@ -1457,7 +1458,7 @@ impl Display for TransactionKind { #[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)] pub struct GasData { pub payment: Vec, - pub owner: SuiAddress, + pub owner: IotaAddress, pub price: u64, pub budget: u64, } @@ -1484,7 +1485,7 @@ impl VersionedProtocolMessage for TransactionData { }) } - fn check_version_supported(&self, protocol_config: &ProtocolConfig) -> SuiResult { + fn check_version_supported(&self, protocol_config: &ProtocolConfig) -> IotaResult { // First check the gross version let (message_version, supported) = match self { Self::V1(_) => (1, SupportedProtocolVersions::new_for_message(1, u64::MAX)), @@ -1497,7 +1498,7 @@ impl VersionedProtocolMessage for TransactionData { }; if !supported.is_version_supported(protocol_config.version) { - return Err(SuiError::WrongMessageVersion { + return Err(IotaError::WrongMessageVersion { error: format!( "TransactionDataV{} is not supported at {:?}. (Supported range is {:?}", message_version, protocol_config.version, supported @@ -1515,7 +1516,7 @@ impl VersionedProtocolMessage for TransactionData { #[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)] pub struct TransactionDataV1 { pub kind: TransactionKind, - pub sender: SuiAddress, + pub sender: IotaAddress, pub gas_data: GasData, pub expiration: TransactionExpiration, } @@ -1524,7 +1525,7 @@ impl TransactionData { fn new_system_transaction(kind: TransactionKind) -> Self { // assert transaction kind if a system transaction assert!(kind.is_system_tx()); - let sender = SuiAddress::default(); + let sender = IotaAddress::default(); TransactionData::V1(TransactionDataV1 { kind, sender, @@ -1540,7 +1541,7 @@ impl TransactionData { pub fn new( kind: TransactionKind, - sender: SuiAddress, + sender: IotaAddress, gas_payment: ObjectRef, gas_budget: u64, gas_price: u64, @@ -1560,7 +1561,7 @@ impl TransactionData { pub fn new_with_gas_coins( kind: TransactionKind, - sender: SuiAddress, + sender: IotaAddress, gas_payment: Vec, gas_budget: u64, gas_price: u64, @@ -1577,11 +1578,11 @@ impl TransactionData { pub fn new_with_gas_coins_allow_sponsor( kind: TransactionKind, - sender: SuiAddress, + sender: IotaAddress, gas_payment: Vec, gas_budget: u64, gas_price: u64, - gas_sponsor: SuiAddress, + gas_sponsor: IotaAddress, ) -> Self { TransactionData::V1(TransactionDataV1 { kind, @@ -1596,7 +1597,11 @@ impl TransactionData { }) } - pub fn new_with_gas_data(kind: TransactionKind, sender: SuiAddress, gas_data: GasData) -> Self { + pub fn new_with_gas_data( + kind: TransactionKind, + sender: IotaAddress, + gas_data: GasData, + ) -> Self { TransactionData::V1(TransactionDataV1 { kind, sender, @@ -1606,7 +1611,7 @@ impl TransactionData { } pub fn new_move_call( - sender: SuiAddress, + sender: IotaAddress, package: ObjectID, module: Identifier, function: Identifier, @@ -1630,7 +1635,7 @@ impl TransactionData { } pub fn new_move_call_with_gas_coins( - sender: SuiAddress, + sender: IotaAddress, package: ObjectID, module: Identifier, function: Identifier, @@ -1655,9 +1660,9 @@ impl TransactionData { } pub fn new_transfer( - recipient: SuiAddress, + recipient: IotaAddress, object_ref: ObjectRef, - sender: SuiAddress, + sender: IotaAddress, gas_payment: ObjectRef, gas_budget: u64, gas_price: u64, @@ -1670,15 +1675,15 @@ impl TransactionData { Self::new_programmable(sender, vec![gas_payment], pt, gas_budget, gas_price) } - pub fn new_transfer_sui( - recipient: SuiAddress, - sender: SuiAddress, + pub fn new_transfer_iota( + recipient: IotaAddress, + sender: IotaAddress, amount: Option, gas_payment: ObjectRef, gas_budget: u64, gas_price: u64, ) -> Self { - Self::new_transfer_sui_allow_sponsor( + Self::new_transfer_iota_allow_sponsor( recipient, sender, amount, @@ -1689,18 +1694,18 @@ impl TransactionData { ) } - pub fn new_transfer_sui_allow_sponsor( - recipient: SuiAddress, - sender: SuiAddress, + pub fn new_transfer_iota_allow_sponsor( + recipient: IotaAddress, + sender: IotaAddress, amount: Option, gas_payment: ObjectRef, gas_budget: u64, gas_price: u64, - gas_sponsor: SuiAddress, + gas_sponsor: IotaAddress, ) -> Self { let pt = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.transfer_sui(recipient, amount); + builder.transfer_iota(recipient, amount); builder.finish() }; Self::new_programmable_allow_sponsor( @@ -1714,9 +1719,9 @@ impl TransactionData { } pub fn new_pay( - sender: SuiAddress, + sender: IotaAddress, coins: Vec, - recipients: Vec, + recipients: Vec, amounts: Vec, gas_payment: ObjectRef, gas_budget: u64, @@ -1736,10 +1741,10 @@ impl TransactionData { )) } - pub fn new_pay_sui( - sender: SuiAddress, + pub fn new_pay_iota( + sender: IotaAddress, mut coins: Vec, - recipients: Vec, + recipients: Vec, amounts: Vec, gas_payment: ObjectRef, gas_budget: u64, @@ -1748,7 +1753,7 @@ impl TransactionData { coins.insert(0, gas_payment); let pt = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.pay_sui(recipients, amounts)?; + builder.pay_iota(recipients, amounts)?; builder.finish() }; Ok(Self::new_programmable( @@ -1756,10 +1761,10 @@ impl TransactionData { )) } - pub fn new_pay_all_sui( - sender: SuiAddress, + pub fn new_pay_all_iota( + sender: IotaAddress, mut coins: Vec, - recipient: SuiAddress, + recipient: IotaAddress, gas_payment: ObjectRef, gas_budget: u64, gas_price: u64, @@ -1767,14 +1772,14 @@ impl TransactionData { coins.insert(0, gas_payment); let pt = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.pay_all_sui(recipient); + builder.pay_all_iota(recipient); builder.finish() }; Self::new_programmable(sender, coins, pt, gas_budget, gas_price) } pub fn new_module( - sender: SuiAddress, + sender: IotaAddress, gas_payment: ObjectRef, modules: Vec>, dep_ids: Vec, @@ -1791,7 +1796,7 @@ impl TransactionData { } pub fn new_upgrade( - sender: SuiAddress, + sender: IotaAddress, gas_payment: ObjectRef, package_id: ObjectID, modules: Vec>, @@ -1828,7 +1833,7 @@ impl TransactionData { let upgrade_arg = builder.pure(upgrade_policy).unwrap(); let digest_arg = builder.pure(digest).unwrap(); let upgrade_ticket = builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, ident_str!("package").to_owned(), ident_str!("authorize_upgrade").to_owned(), vec![], @@ -1837,7 +1842,7 @@ impl TransactionData { let upgrade_receipt = builder.upgrade(package_id, upgrade_ticket, dep_ids, modules); builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, ident_str!("package").to_owned(), ident_str!("commit_upgrade").to_owned(), vec![], @@ -1856,7 +1861,7 @@ impl TransactionData { } pub fn new_programmable( - sender: SuiAddress, + sender: IotaAddress, gas_payment: Vec, pt: ProgrammableTransaction, gas_budget: u64, @@ -1866,12 +1871,12 @@ impl TransactionData { } pub fn new_programmable_allow_sponsor( - sender: SuiAddress, + sender: IotaAddress, gas_payment: Vec, pt: ProgrammableTransaction, gas_budget: u64, gas_price: u64, - sponsor: SuiAddress, + sponsor: IotaAddress, ) -> Self { let kind = TransactionKind::ProgrammableTransaction(pt); Self::new_with_gas_coins_allow_sponsor( @@ -1884,7 +1889,7 @@ impl TransactionData { ) } - pub fn execution_parts(&self) -> (TransactionKind, SuiAddress, Vec) { + pub fn execution_parts(&self) -> (TransactionKind, IotaAddress, Vec) { ( self.kind().clone(), self.sender(), @@ -1895,7 +1900,7 @@ impl TransactionData { #[enum_dispatch] pub trait TransactionDataAPI { - fn sender(&self) -> SuiAddress; + fn sender(&self) -> IotaAddress; // Note: this implies that SingleTransactionKind itself must be versioned, so // that it can be shared across versions. This will be easy to do since it @@ -1909,11 +1914,11 @@ pub trait TransactionDataAPI { fn into_kind(self) -> TransactionKind; /// Transaction signer and Gas owner - fn signers(&self) -> NonEmpty; + fn signers(&self) -> NonEmpty; fn gas_data(&self) -> &GasData; - fn gas_owner(&self) -> SuiAddress; + fn gas_owner(&self) -> IotaAddress; fn gas(&self) -> &[ObjectRef]; @@ -1950,7 +1955,7 @@ pub trait TransactionDataAPI { /// Check if the transaction is sponsored (namely gas owner != sender) fn is_sponsored_tx(&self) -> bool; - fn sender_mut_for_testing(&mut self) -> &mut SuiAddress; + fn sender_mut_for_testing(&mut self) -> &mut IotaAddress; fn gas_data_mut(&mut self) -> &mut GasData; @@ -1959,7 +1964,7 @@ pub trait TransactionDataAPI { } impl TransactionDataAPI for TransactionDataV1 { - fn sender(&self) -> SuiAddress { + fn sender(&self) -> IotaAddress { self.sender } @@ -1976,7 +1981,7 @@ impl TransactionDataAPI for TransactionDataV1 { } /// Transaction signer and Gas owner - fn signers(&self) -> NonEmpty { + fn signers(&self) -> NonEmpty { let mut signers = nonempty![self.sender]; if self.gas_owner() != self.sender { signers.push(self.gas_owner()); @@ -1988,7 +1993,7 @@ impl TransactionDataAPI for TransactionDataV1 { &self.gas_data } - fn gas_owner(&self) -> SuiAddress { + fn gas_owner(&self) -> IotaAddress { self.gas_data.owner } @@ -2088,7 +2093,7 @@ impl TransactionDataAPI for TransactionDataV1 { matches!(self.kind, TransactionKind::Genesis(_)) } - fn sender_mut_for_testing(&mut self) -> &mut SuiAddress { + fn sender_mut_for_testing(&mut self) -> &mut IotaAddress { &mut self.sender } @@ -2167,13 +2172,13 @@ impl SenderSignedData { fn get_signer_sig_mapping( &self, verify_legacy_zklogin_address: bool, - ) -> SuiResult> { + ) -> IotaResult> { let mut mapping = BTreeMap::new(); for sig in &self.inner().tx_signatures { if verify_legacy_zklogin_address { // Try deriving the address from the legacy padded way. if let GenericSignature::ZkLoginAuthenticator(z) = sig { - mapping.insert(SuiAddress::try_from_padded(&z.inputs)?, sig); + mapping.insert(IotaAddress::try_from_padded(&z.inputs)?, sig); }; } let address = sig.try_into()?; @@ -2221,22 +2226,22 @@ impl SenderSignedData { SenderSignedDataDigest::new(hash.into()) } - pub fn serialized_size(&self) -> SuiResult { - bcs::serialized_size(self).map_err(|e| SuiError::TransactionSerializationError { + pub fn serialized_size(&self) -> IotaResult { + bcs::serialized_size(self).map_err(|e| IotaError::TransactionSerializationError { error: e.to_string(), }) } /// Perform cheap validity checks on the sender signed transaction, /// including its size, input count, command count, etc. - pub fn validity_check(&self, config: &ProtocolConfig) -> SuiResult { + pub fn validity_check(&self, config: &ProtocolConfig) -> IotaResult { // Enforce overall transaction size limit. let tx_size = self.serialized_size()?; let max_tx_size_bytes = config.max_tx_size_bytes(); fp_ensure!( tx_size as u64 <= max_tx_size_bytes, - SuiError::UserInputError { + IotaError::UserInputError { error: UserInputError::SizeLimitExceeded { limit: format!( "serialized transaction size exceeded maximum of {max_tx_size_bytes}" @@ -2251,10 +2256,10 @@ impl SenderSignedData { let tx_data = self.transaction_data(); tx_data .check_version_supported(config) - .map_err(Into::::into)?; + .map_err(Into::::into)?; tx_data .validity_check(config) - .map_err(Into::::into)?; + .map_err(Into::::into)?; Ok(()) } @@ -2265,7 +2270,7 @@ impl VersionedProtocolMessage for SenderSignedData { self.transaction_data().message_version() } - fn check_version_supported(&self, protocol_config: &ProtocolConfig) -> SuiResult { + fn check_version_supported(&self, protocol_config: &ProtocolConfig) -> IotaResult { self.transaction_data() .check_version_supported(protocol_config)?; @@ -2274,12 +2279,12 @@ impl VersionedProtocolMessage for SenderSignedData { // // When adding a new signature type, check if current_protocol_version // predates support for the new type. If it does, return - // SuiError::WrongMessageVersion + // IotaError::WrongMessageVersion for sig in &self.inner().tx_signatures { match sig { GenericSignature::MultiSig(_) => { if !protocol_config.supports_upgraded_multisig() { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: "multisig format not enabled on this network".to_string(), }); } @@ -2301,10 +2306,10 @@ impl Message for SenderSignedData { TransactionDigest::new(default_hash(&self.intent_message().value)) } - fn verify_user_input(&self) -> SuiResult { + fn verify_user_input(&self) -> IotaResult { fp_ensure!( self.0.len() == 1, - SuiError::UserInputError { + IotaError::UserInputError { error: UserInputError::Unsupported( "SenderSignedData must contain exactly one transaction".to_string() ) @@ -2313,7 +2318,7 @@ impl Message for SenderSignedData { let tx_data = &self.intent_message().value; fp_ensure!( !tx_data.is_system_tx(), - SuiError::UserInputError { + IotaError::UserInputError { error: UserInputError::Unsupported( "SenderSignedData must not contain system transaction".to_string() ) @@ -2326,7 +2331,7 @@ impl Message for SenderSignedData { // Signature number needs to match fp_ensure!( self.inner().tx_signatures.len() == signers.len(), - SuiError::SignerSignatureNumberMismatch { + IotaError::SignerSignatureNumberMismatch { actual: self.inner().tx_signatures.len(), expected: signers.len() } @@ -2336,7 +2341,7 @@ impl Message for SenderSignedData { let present_sigs = self.get_signer_sig_mapping(true)?; for s in signers { if !present_sigs.contains_key(&s) { - return Err(SuiError::SignerSignatureAbsent { + return Err(IotaError::SignerSignatureAbsent { expected: s.to_string(), actual: present_sigs.keys().map(|s| s.to_string()).collect(), }); @@ -2346,7 +2351,7 @@ impl Message for SenderSignedData { Ok(()) } - fn verify_epoch(&self, epoch: EpochId) -> SuiResult { + fn verify_epoch(&self, epoch: EpochId) -> IotaResult { for sig in &self.inner().tx_signatures { sig.verify_user_authenticator_epoch(epoch)?; } @@ -2357,7 +2362,7 @@ impl Message for SenderSignedData { impl AuthenticatedMessage for SenderSignedData { // Checks that are required to be done outside cache. - fn verify_uncached_checks(&self, verify_params: &VerifyParams) -> SuiResult { + fn verify_uncached_checks(&self, verify_params: &VerifyParams) -> IotaResult { for (signer, signature) in self.get_signer_sig_mapping(verify_params.verify_legacy_zklogin_address)? { @@ -2366,10 +2371,10 @@ impl AuthenticatedMessage for SenderSignedData { Ok(()) } - fn verify_message_signature(&self, verify_params: &VerifyParams) -> SuiResult { + fn verify_message_signature(&self, verify_params: &VerifyParams) -> IotaResult { fp_ensure!( self.0.len() == 1, - SuiError::UserInputError { + IotaError::UserInputError { error: UserInputError::Unsupported( "SenderSignedData must contain exactly one transaction".to_string() ) @@ -2385,7 +2390,7 @@ impl AuthenticatedMessage for SenderSignedData { // Signature number needs to match fp_ensure!( self.inner().tx_signatures.len() == signers.len(), - SuiError::SignerSignatureNumberMismatch { + IotaError::SignerSignatureNumberMismatch { actual: self.inner().tx_signatures.len(), expected: signers.len() } @@ -2395,7 +2400,7 @@ impl AuthenticatedMessage for SenderSignedData { self.get_signer_sig_mapping(verify_params.verify_legacy_zklogin_address)?; for s in signers { if !present_sigs.contains_key(&s) { - return Err(SuiError::SignerSignatureAbsent { + return Err(IotaError::SignerSignatureAbsent { expected: s.to_string(), actual: present_sigs.keys().map(|s| s.to_string()).collect(), }); @@ -2411,7 +2416,7 @@ impl AuthenticatedMessage for SenderSignedData { } impl Envelope { - pub fn sender_address(&self) -> SuiAddress { + pub fn sender_address(&self) -> IotaAddress { self.data().intent_message().value.sender() } @@ -2466,7 +2471,7 @@ impl Envelope { pub fn is_randomness_reader(&self) -> bool { self.shared_input_objects() - .any(|obj| obj.id() == SUI_RANDOMNESS_STATE_OBJECT_ID) + .any(|obj| obj.id() == IOTA_RANDOMNESS_STATE_OBJECT_ID) } } @@ -2476,7 +2481,7 @@ impl Transaction { signers: Vec<&dyn Signer>, ) -> Self { let signatures = { - let intent_msg = IntentMessage::new(Intent::sui_transaction(), &data); + let intent_msg = IntentMessage::new(Intent::iota_transaction(), &data); signers .into_iter() .map(|s| Signature::new_secure(&intent_msg, s)) @@ -2502,7 +2507,7 @@ impl Transaction { pub fn from_generic_sig_data(data: TransactionData, signatures: Vec) -> Self { Self::new(SenderSignedData::new( data, - Intent::sui_transaction(), + Intent::iota_transaction(), signatures, )) } @@ -2625,8 +2630,8 @@ impl VerifiedTransaction { .pipe(|data| { SenderSignedData::new_from_sender_signature( data, - Intent::sui_transaction(), - Ed25519SuiSignature::from_bytes(&[0; Ed25519SuiSignature::LENGTH]) + Intent::iota_transaction(), + Ed25519IotaSignature::from_bytes(&[0; Ed25519IotaSignature::LENGTH]) .unwrap() .into(), ) @@ -2690,7 +2695,7 @@ pub trait VersionedProtocolMessage { /// Check that the version of the message is the correct one to use at this /// protocol version. - fn check_version_supported(&self, protocol_config: &ProtocolConfig) -> SuiResult; + fn check_version_supported(&self, protocol_config: &ProtocolConfig) -> IotaResult; } #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, PartialOrd, Ord)] @@ -2895,17 +2900,17 @@ pub struct InputObjects { objects: Vec, } -// An InputObjects new-type that has been verified by sui-transaction-checks, +// An InputObjects new-type that has been verified by iota-transaction-checks, // and can be safely passed to execution. pub struct CheckedInputObjects(InputObjects); -// DO NOT CALL outside of sui-transaction-checks, genesis, or replay. +// DO NOT CALL outside of iota-transaction-checks, genesis, or replay. // -// CheckedInputObjects should really be defined in sui-transaction-checks so +// CheckedInputObjects should really be defined in iota-transaction-checks so // that we can make public construction impossible. But we can't do that because // it would result in circular dependencies. impl CheckedInputObjects { - // Only called by sui-transaction-checks. + // Only called by iota-transaction-checks. pub fn new_with_checked_transaction_inputs(inputs: InputObjects) -> Self { Self(inputs) } diff --git a/crates/iota-types/src/transfer.rs b/crates/iota-types/src/transfer.rs new file mode 100644 index 00000000000..58781262442 --- /dev/null +++ b/crates/iota-types/src/transfer.rs @@ -0,0 +1,76 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use move_binary_format::{binary_views::BinaryIndexedView, file_format::SignatureToken}; +use move_bytecode_utils::resolve_struct; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + language_storage::{StructTag, TypeTag}, +}; +use serde::{Deserialize, Serialize}; + +use crate::{ + base_types::{ObjectID, SequenceNumber}, + id::ID, + IOTA_FRAMEWORK_ADDRESS, +}; + +const TRANSFER_MODULE_NAME: &IdentStr = ident_str!("transfer"); +const RECEIVING_STRUCT_NAME: &IdentStr = ident_str!("Receiving"); + +pub const RESOLVED_RECEIVING_STRUCT: (&AccountAddress, &IdentStr, &IdentStr) = ( + &IOTA_FRAMEWORK_ADDRESS, + TRANSFER_MODULE_NAME, + RECEIVING_STRUCT_NAME, +); + +/// Rust version of the Move iota::transfer::Receiving type +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct Receiving { + pub id: ID, + pub version: SequenceNumber, +} + +impl Receiving { + pub fn new(id: ObjectID, version: SequenceNumber) -> Self { + Self { + id: ID::new(id), + version, + } + } + + pub fn to_bcs_bytes(&self) -> Vec { + bcs::to_bytes(self).expect("Value representation is owned and should always serialize") + } + + pub fn struct_tag() -> StructTag { + StructTag { + address: IOTA_FRAMEWORK_ADDRESS, + module: TRANSFER_MODULE_NAME.to_owned(), + name: RECEIVING_STRUCT_NAME.to_owned(), + // TODO: this should really include the type parameters eventually when we add type + // parameters to the other polymorphic types like this. + type_params: vec![], + } + } + + pub fn type_tag() -> TypeTag { + TypeTag::Struct(Box::new(Self::struct_tag())) + } + + pub fn is_receiving(view: &BinaryIndexedView<'_>, s: &SignatureToken) -> bool { + use SignatureToken as S; + match s { + S::MutableReference(inner) | S::Reference(inner) => Self::is_receiving(view, inner), + S::StructInstantiation(s) => { + let (idx, type_args) = &**s; + let struct_tag = resolve_struct(view, *idx); + struct_tag == RESOLVED_RECEIVING_STRUCT && type_args.len() == 1 + } + _ => false, + } + } +} diff --git a/crates/sui-types/src/type_resolver.rs b/crates/iota-types/src/type_resolver.rs similarity index 75% rename from crates/sui-types/src/type_resolver.rs rename to crates/iota-types/src/type_resolver.rs index 1da71369064..ca41575a915 100644 --- a/crates/sui-types/src/type_resolver.rs +++ b/crates/iota-types/src/type_resolver.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use move_core_types::{ @@ -7,13 +8,13 @@ use move_core_types::{ }; use move_vm_types::loaded_data::runtime_types::Type; -use crate::error::{ExecutionError, SuiError}; +use crate::error::{ExecutionError, IotaError}; pub trait LayoutResolver { fn get_annotated_layout( &mut self, struct_tag: &StructTag, - ) -> Result; + ) -> Result; } pub trait TypeTagResolver { diff --git a/crates/sui-types/src/unit_tests/base_types_tests.rs b/crates/iota-types/src/unit_tests/base_types_tests.rs similarity index 88% rename from crates/sui-types/src/unit_tests/base_types_tests.rs rename to crates/iota-types/src/unit_tests/base_types_tests.rs index 82535f455a4..47e449d740e 100644 --- a/crates/sui-types/src/unit_tests/base_types_tests.rs +++ b/crates/iota-types/src/unit_tests/base_types_tests.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #![allow(clippy::disallowed_names)] @@ -8,9 +9,9 @@ use std::str::FromStr; use base_types_tests::timelock::TimeLock; use fastcrypto::{encoding::Base58, traits::EncodeDecodeBase64}; +use iota_protocol_config::ProtocolConfig; use move_binary_format::file_format; use shared_crypto::intent::{Intent, IntentMessage, IntentScope}; -use sui_protocol_config::ProtocolConfig; use super::*; use crate::{ @@ -18,13 +19,13 @@ use crate::{ crypto::{ bcs_signable_test::{Bar, Foo}, get_key_pair, get_key_pair_from_bytes, AccountKeyPair, AuthorityKeyPair, - AuthoritySignature, Signature, SuiAuthoritySignature, SuiSignature, + AuthoritySignature, IotaAuthoritySignature, IotaSignature, Signature, }, digests::Digest, gas_coin::GasCoin, id::{ID, UID}, object::Object, - SUI_FRAMEWORK_ADDRESS, + IOTA_FRAMEWORK_ADDRESS, }; #[test] @@ -32,9 +33,9 @@ fn test_signatures() { let (addr1, sec1): (_, AccountKeyPair) = get_key_pair(); let (addr2, _sec2): (_, AccountKeyPair) = get_key_pair(); - let foo = IntentMessage::new(Intent::sui_transaction(), Foo("hello".into())); - let foox = IntentMessage::new(Intent::sui_transaction(), Foo("hellox".into())); - let bar = IntentMessage::new(Intent::sui_transaction(), Bar("hello".into())); + let foo = IntentMessage::new(Intent::iota_transaction(), Foo("hello".into())); + let foox = IntentMessage::new(Intent::iota_transaction(), Foo("hellox".into())); + let bar = IntentMessage::new(Intent::iota_transaction(), Bar("hello".into())); let s = Signature::new_secure(&foo, &sec1); assert!( @@ -52,7 +53,7 @@ fn test_signatures() { assert!( s.verify_secure( &IntentMessage::new( - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), Foo("hello".into()) ), addr1, @@ -72,7 +73,7 @@ fn test_signatures() { fn test_signatures_serde() { let (_, sec1): (_, AccountKeyPair) = get_key_pair(); let foo = Foo("hello".into()); - let s = Signature::new_secure(&IntentMessage::new(Intent::sui_transaction(), foo), &sec1); + let s = Signature::new_secure(&IntentMessage::new(Intent::iota_transaction(), foo), &sec1); let serialized = bcs::to_bytes(&s).unwrap(); println!("{:?}", serialized); @@ -230,45 +231,45 @@ fn test_object_id_zero_padding() { let obj_id_4: ObjectID = serde_json::from_str(&format!("\"{}\"", hex)).unwrap(); let obj_id_5: ObjectID = serde_json::from_str(&format!("\"{}\"", long_hex)).unwrap(); let obj_id_6: ObjectID = serde_json::from_str(&format!("\"{}\"", long_hex_alt)).unwrap(); - assert_eq!(SUI_FRAMEWORK_ADDRESS, obj_id_1.0); - assert_eq!(SUI_FRAMEWORK_ADDRESS, obj_id_2.0); - assert_eq!(SUI_FRAMEWORK_ADDRESS, obj_id_3.0); - assert_eq!(SUI_FRAMEWORK_ADDRESS, obj_id_4.0); - assert_eq!(SUI_FRAMEWORK_ADDRESS, obj_id_5.0); - assert_eq!(SUI_FRAMEWORK_ADDRESS, obj_id_6.0); + assert_eq!(IOTA_FRAMEWORK_ADDRESS, obj_id_1.0); + assert_eq!(IOTA_FRAMEWORK_ADDRESS, obj_id_2.0); + assert_eq!(IOTA_FRAMEWORK_ADDRESS, obj_id_3.0); + assert_eq!(IOTA_FRAMEWORK_ADDRESS, obj_id_4.0); + assert_eq!(IOTA_FRAMEWORK_ADDRESS, obj_id_5.0); + assert_eq!(IOTA_FRAMEWORK_ADDRESS, obj_id_6.0); } #[test] fn test_address_display() { let hex = SAMPLE_ADDRESS; - let id = SuiAddress::from_str(hex).unwrap(); + let id = IotaAddress::from_str(hex).unwrap(); assert_eq!(format!("{:?}", id), format!("0x{hex}")); } #[test] fn test_address_serde_not_human_readable() { - let address = SuiAddress::random_for_testing_only(); + let address = IotaAddress::random_for_testing_only(); let serialized = bincode::serialize(&address).unwrap(); let bcs_serialized = bcs::to_bytes(&address).unwrap(); // bincode use 8 bytes for BYTES len and bcs use 1 byte assert_eq!(serialized, bcs_serialized); assert_eq!(address.0, serialized[..]); - let deserialized: SuiAddress = bincode::deserialize(&serialized).unwrap(); + let deserialized: IotaAddress = bincode::deserialize(&serialized).unwrap(); assert_eq!(deserialized, address); } #[test] fn test_address_serde_human_readable() { - let address = SuiAddress::random_for_testing_only(); + let address = IotaAddress::random_for_testing_only(); let serialized = serde_json::to_string(&address).unwrap(); assert_eq!(format!("\"0x{}\"", Hex::encode(address)), serialized); - let deserialized: SuiAddress = serde_json::from_str(&serialized).unwrap(); + let deserialized: IotaAddress = serde_json::from_str(&serialized).unwrap(); assert_eq!(deserialized, address); } #[test] fn test_address_serde_with_expected_value() { - let address = SuiAddress::try_from(SAMPLE_ADDRESS_VEC.to_vec()).unwrap(); + let address = IotaAddress::try_from(SAMPLE_ADDRESS_VEC.to_vec()).unwrap(); let json_serialized = serde_json::to_string(&address).unwrap(); let bcs_serialized = bcs::to_bytes(&address).unwrap(); @@ -305,7 +306,7 @@ fn test_transaction_digest_serde_human_readable() { fn test_authority_signature_serde_not_human_readable() { let (_, key): (_, AuthorityKeyPair) = get_key_pair(); let sig = AuthoritySignature::new_secure( - &IntentMessage::new(Intent::sui_transaction(), Foo("some data".to_string())), + &IntentMessage::new(Intent::iota_transaction(), Foo("some data".to_string())), &0, &key, ); @@ -321,7 +322,7 @@ fn test_authority_signature_serde_not_human_readable() { fn test_authority_signature_serde_human_readable() { let (_, key): (_, AuthorityKeyPair) = get_key_pair(); let sig = AuthoritySignature::new_secure( - &IntentMessage::new(Intent::sui_transaction(), Foo("some data".to_string())), + &IntentMessage::new(Intent::iota_transaction(), Foo("some data".to_string())), &0, &key, ); @@ -340,7 +341,7 @@ fn test_object_id_from_empty_string() { fn test_move_object_size_for_gas_metering() { let object = Object::with_id_owner_for_testing( ObjectID::random(), - SuiAddress::random_for_testing_only(), + IotaAddress::random_for_testing_only(), ); let size = object.object_size_for_gas_metering(); let serialized = bcs::to_bytes(&object).unwrap(); @@ -378,7 +379,7 @@ const SAMPLE_ADDRESS_VEC: [u8; 32] = [ ]; // Derive a sample address and public key tuple from KeyPair bytes. -fn derive_sample_address() -> (SuiAddress, AccountKeyPair) { +fn derive_sample_address() -> (IotaAddress, AccountKeyPair) { let (address, pub_key) = get_key_pair_from_bytes(&[ 10, 112, 5, 142, 174, 127, 187, 146, 251, 68, 22, 191, 128, 68, 84, 13, 102, 71, 77, 57, 92, 154, 128, 240, 158, 45, 13, 123, 57, 21, 194, 214, 189, 215, 127, 86, 129, 189, 1, 4, @@ -427,11 +428,11 @@ fn move_object_type_consistency() { assert!(!ty.is_timelocked_balance() || ty.is_timelock()); let cases = [ ty.is_coin(), - ty.is_staked_sui(), + ty.is_staked_iota(), ty.is_coin_metadata(), ty.is_dynamic_field(), ty.is_timelock(), - ty.is_timelocked_staked_sui(), + ty.is_timelocked_staked_iota(), ]; assert!(cases.into_iter().map(|is_ty| is_ty as u8).sum::() <= 1); ty @@ -440,8 +441,8 @@ fn move_object_type_consistency() { let ty = assert_consistent(&GasCoin::type_()); assert!(ty.is_coin()); assert!(ty.is_gas_coin()); - let ty = assert_consistent(&StakedSui::type_()); - assert!(ty.is_staked_sui()); + let ty = assert_consistent(&StakedIota::type_()); + assert!(ty.is_staked_iota()); let ty = assert_consistent(&Coin::type_(TypeTag::U64)); assert!(ty.is_coin()); let ty = assert_consistent(&CoinMetadata::type_(GasCoin::type_())); @@ -454,15 +455,15 @@ fn move_object_type_consistency() { let ty = assert_consistent(&TimeLock::::type_( Balance::type_(GAS::type_().into()).into(), )); - assert_eq!(ty, MoveObjectType::timelocked_sui_balance()); + assert_eq!(ty, MoveObjectType::timelocked_iota_balance()); assert!(ty.is_timelock()); assert!(ty.is_timelocked_balance()); let ty = assert_consistent(&TimeLock::::type_(GasCoin::type_().into())); assert!(ty.is_timelock()); assert!(!ty.is_timelocked_balance()); - let ty = assert_consistent(&TimelockedStakedSui::type_()); - assert_eq!(ty, MoveObjectType::timelocked_staked_sui()); - assert!(ty.is_timelocked_staked_sui()); + let ty = assert_consistent(&TimelockedStakedIota::type_()); + assert_eq!(ty, MoveObjectType::timelocked_staked_iota()); + assert!(ty.is_timelocked_staked_iota()); assert_consistent(&UID::type_()); assert_consistent(&ID::type_()); } diff --git a/crates/sui-types/src/unit_tests/crypto_tests.rs b/crates/iota-types/src/unit_tests/crypto_tests.rs similarity index 81% rename from crates/sui-types/src/unit_tests/crypto_tests.rs rename to crates/iota-types/src/unit_tests/crypto_tests.rs index d6e9221cc49..fe92cdad4d9 100644 --- a/crates/sui-types/src/unit_tests/crypto_tests.rs +++ b/crates/iota-types/src/unit_tests/crypto_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use proptest::{collection, prelude::*}; @@ -7,19 +8,19 @@ use crate::crypto::bcs_signable_test::Foo; #[test] fn serde_keypair() { - let skp = SuiKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))); + let skp = IotaKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))); let encoded = skp.encode().unwrap(); assert_eq!( encoded, - "suiprivkey1qzdlfxn2qa2lj5uprl8pyhexs02sg2wrhdy7qaq50cqgnffw4c2477kg9h3" + "iotaprivkey1qzdlfxn2qa2lj5uprl8pyhexs02sg2wrhdy7qaq50cqgnffw4c2477kg9h3" ); - let decoded = SuiKeyPair::decode(&encoded).unwrap(); + let decoded = IotaKeyPair::decode(&encoded).unwrap(); assert_eq!(skp, decoded); } #[test] fn serde_pubkey() { - let skp = SuiKeyPair::Ed25519(get_key_pair().1); + let skp = IotaKeyPair::Ed25519(get_key_pair().1); let ser = serde_json::to_string(&skp.public()).unwrap(); assert_eq!( ser, @@ -49,10 +50,10 @@ fn serde_round_trip_authority_quorum_sign_info() { #[test] fn public_key_equality() { - let ed_kp1: SuiKeyPair = SuiKeyPair::Ed25519(get_key_pair().1); - let ed_kp2: SuiKeyPair = SuiKeyPair::Ed25519(get_key_pair().1); - let k1_kp1: SuiKeyPair = SuiKeyPair::Secp256k1(get_key_pair().1); - let k1_kp2: SuiKeyPair = SuiKeyPair::Secp256k1(get_key_pair().1); + let ed_kp1: IotaKeyPair = IotaKeyPair::Ed25519(get_key_pair().1); + let ed_kp2: IotaKeyPair = IotaKeyPair::Ed25519(get_key_pair().1); + let k1_kp1: IotaKeyPair = IotaKeyPair::Secp256k1(get_key_pair().1); + let k1_kp2: IotaKeyPair = IotaKeyPair::Secp256k1(get_key_pair().1); let ed_pk1 = ed_kp1.public(); let ed_pk2 = ed_kp2.public(); @@ -79,7 +80,7 @@ fn public_key_equality() { #[test] fn test_proof_of_possession() { let address = - SuiAddress::from_str("0x1a4623343cd42be47d67314fce0ad042f3c82685544bc91d8c11d24e74ba7357") + IotaAddress::from_str("0x1a4623343cd42be47d67314fce0ad042f3c82685544bc91d8c11d24e74ba7357") .unwrap(); let kp: AuthorityKeyPair = get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1; let pop = generate_proof_of_possession(&kp, address); @@ -91,7 +92,7 @@ fn test_proof_of_possession() { println!("Proof of possession: {:?}", Hex::encode(&pop)); assert!(verify_proof_of_possession(&pop, kp.public(), address).is_ok()); - // Result from: target/debug/sui validator serialize-payload-pop + // Result from: target/debug/iota validator serialize-payload-pop // --account-address // 0x1a4623343cd42be47d67314fce0ad042f3c82685544bc91d8c11d24e74ba7357 // --protocol-public-key @@ -124,8 +125,8 @@ proptest! { bytes in collection::vec(any::(), 0..1024) ){ let _apkb = AuthorityPublicKeyBytes::from_bytes(&bytes); - let _suisig = Ed25519SuiSignature::from_bytes(&bytes); - let _suisig = Secp256k1SuiSignature::from_bytes(&bytes); + let _iotasig = Ed25519IotaSignature::from_bytes(&bytes); + let _iotasig = Secp256k1IotaSignature::from_bytes(&bytes); let _pk = PublicKey::try_from_bytes(SignatureScheme::BLS12381, &bytes); let _pk = PublicKey::try_from_bytes(SignatureScheme::ED25519, &bytes); let _pk = PublicKey::try_from_bytes(SignatureScheme::Secp256k1, &bytes); @@ -136,7 +137,7 @@ proptest! { fn test_deserialize_keypair( bytes in collection::vec(any::(), 0..1024) ){ - let _skp: Result = bcs::from_bytes(&bytes); + let _skp: Result = bcs::from_bytes(&bytes); let _pk: Result = bcs::from_bytes(&bytes); } diff --git a/crates/sui-types/src/unit_tests/event_filter_tests.rs b/crates/iota-types/src/unit_tests/event_filter_tests.rs similarity index 88% rename from crates/sui-types/src/unit_tests/event_filter_tests.rs rename to crates/iota-types/src/unit_tests/event_filter_tests.rs index 0388662069e..d6fb37a6a7d 100644 --- a/crates/sui-types/src/unit_tests/event_filter_tests.rs +++ b/crates/iota-types/src/unit_tests/event_filter_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeMap; @@ -7,12 +8,12 @@ use move_core_types::ident_str; use move_core_types::identifier::Identifier; use serde_json::json; -use crate::base_types::{ObjectDigest, SuiAddress, TransactionDigest}; +use crate::base_types::{ObjectDigest, IotaAddress, TransactionDigest}; use crate::event::{Event, EventEnvelope}; use crate::filter::{EventFilter, Filter}; use crate::gas_coin::GasCoin; use crate::object::OBJECT_START_VERSION; -use crate::{ObjectID, MOVE_STDLIB_ADDRESS, SUI_FRAMEWORK_ADDRESS}; +use crate::{ObjectID, MOVE_STDLIB_ADDRESS, IOTA_FRAMEWORK_ADDRESS}; #[test] fn test_move_event_filter() { @@ -21,9 +22,9 @@ fn test_move_event_filter() { // TODO this is a bit of a nonsensical test as GasCoin does not implement drop, but it likely // doesn't matter as we just are testing a BCS type + value let move_event = Event { - package_id: ObjectID::from(SUI_FRAMEWORK_ADDRESS), + package_id: ObjectID::from(IOTA_FRAMEWORK_ADDRESS), transaction_module: Identifier::from(ident_str!("test_module")), - sender: SuiAddress::random_for_testing_only(), + sender: IotaAddress::random_for_testing_only(), type_: GasCoin::type_(), contents: GasCoin::new(event_coin_id, 10000).to_bcs_bytes(), }; @@ -39,7 +40,7 @@ fn test_move_event_filter() { let filters = vec![ EventFilter::MoveEventType(GasCoin::type_()), EventFilter::Module(Identifier::from(ident_str!("test_module"))), - EventFilter::Package(ObjectID::from(SUI_FRAMEWORK_ADDRESS)), + EventFilter::Package(ObjectID::from(IOTA_FRAMEWORK_ADDRESS)), EventFilter::MoveEventField { path: "/balance".to_string(), value: json!(10000), @@ -70,11 +71,11 @@ fn test_move_event_filter() { /*#[test] fn test_transfer_filter() { let object_id = ObjectID::random(); - let sender = SuiAddress::random_for_testing_only(); - let recipient = Owner::AddressOwner(SuiAddress::random_for_testing_only()); + let sender = IotaAddress::random_for_testing_only(); + let recipient = Owner::AddressOwner(IotaAddress::random_for_testing_only()); // Create a test transfer event. let move_event = Event::TransferObject { - package_id: ObjectID::from(SUI_FRAMEWORK_ADDRESS), + package_id: ObjectID::from(IOTA_FRAMEWORK_ADDRESS), transaction_module: Identifier::from(ident_str!("test_module")), sender, recipient, @@ -92,7 +93,7 @@ fn test_transfer_filter() { }; let filters = vec![ - EventFilter::Package(ObjectID::from(SUI_FRAMEWORK_ADDRESS)), + EventFilter::Package(ObjectID::from(IOTA_FRAMEWORK_ADDRESS)), EventFilter::Module(Identifier::from(ident_str!("test_module"))), EventFilter::SenderAddress(sender), ]; @@ -111,7 +112,7 @@ fn test_transfer_filter() { /*#[test] fn test_publish_filter() { let package_id = ObjectID::random(); - let sender = SuiAddress::random_for_testing_only(); + let sender = IotaAddress::random_for_testing_only(); let version = OBJECT_START_VERSION; let digest = ObjectDigest::random(); // Create a test publish event. @@ -150,7 +151,7 @@ fn test_publish_filter() { fn test_delete_object_filter() { let package_id = ObjectID::random(); let object_id = ObjectID::random(); - let sender = SuiAddress::random_for_testing_only(); + let sender = IotaAddress::random_for_testing_only(); // Create a test delete object event. let move_event = Event::DeleteObject { package_id, @@ -189,8 +190,8 @@ fn test_delete_object_filter() { fn test_new_object_filter() { let package_id = ObjectID::random(); let object_id = ObjectID::random(); - let sender = SuiAddress::random_for_testing_only(); - let recipient = Owner::AddressOwner(SuiAddress::random_for_testing_only()); + let sender = IotaAddress::random_for_testing_only(); + let recipient = Owner::AddressOwner(IotaAddress::random_for_testing_only()); // Create a test new object event. let move_event = Event::NewObject { package_id, diff --git a/crates/sui-types/src/unit_tests/execution_status_tests.rs b/crates/iota-types/src/unit_tests/execution_status_tests.rs similarity index 82% rename from crates/sui-types/src/unit_tests/execution_status_tests.rs rename to crates/iota-types/src/unit_tests/execution_status_tests.rs index 5ee1cc8e5b4..b89ac1c2a27 100644 --- a/crates/sui-types/src/unit_tests/execution_status_tests.rs +++ b/crates/iota-types/src/unit_tests/execution_status_tests.rs @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use sui_enum_compat_util::*; +use iota_enum_compat_util::*; use crate::execution_status::ExecutionFailureStatus; #[test] diff --git a/crates/sui-types/src/unit_tests/intent_tests.rs b/crates/iota-types/src/unit_tests/intent_tests.rs similarity index 89% rename from crates/sui-types/src/unit_tests/intent_tests.rs rename to crates/iota-types/src/unit_tests/intent_tests.rs index c1e3fad51ee..1db04920b97 100644 --- a/crates/sui-types/src/unit_tests/intent_tests.rs +++ b/crates/iota-types/src/unit_tests/intent_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use fastcrypto::traits::KeyPair; @@ -9,8 +10,8 @@ use shared_crypto::intent::{ use crate::{ base_types::{dbg_addr, ObjectID}, crypto::{ - get_key_pair, AccountKeyPair, AuthorityKeyPair, AuthoritySignature, Signature, - SignatureScheme, SuiAuthoritySignature, SuiSignature, + get_key_pair, AccountKeyPair, AuthorityKeyPair, AuthoritySignature, IotaAuthoritySignature, + IotaSignature, Signature, SignatureScheme, }, object::Object, transaction::{Transaction, TransactionData, TEST_ONLY_GAS_UNIT_FOR_TRANSFER}, @@ -24,7 +25,7 @@ fn test_personal_message_intent() { let p_message_2 = p_message.clone(); let p_message_bcs = bcs::to_bytes(&p_message).unwrap(); - let intent = Intent::sui_app(IntentScope::PersonalMessage); + let intent = Intent::iota_app(IntentScope::PersonalMessage); let intent1 = intent.clone(); let intent2 = intent.clone(); let intent_bcs = bcs::to_bytes(&IntentMessage::new(intent, &p_message)).unwrap(); @@ -36,7 +37,7 @@ fn test_personal_message_intent() { vec![ IntentScope::PersonalMessage as u8, IntentVersion::V0 as u8, - AppId::Sui as u8, + AppId::Iota as u8, ] ); @@ -63,7 +64,7 @@ fn test_authority_signature_intent() { let object_id = ObjectID::random(); let object = Object::immutable_with_id_for_testing(object_id); let gas_price = 1000; - let data = TransactionData::new_transfer_sui( + let data = TransactionData::new_transfer_iota( recipient, sender, None, @@ -72,7 +73,7 @@ fn test_authority_signature_intent() { gas_price, ); let signature = Signature::new_secure( - &IntentMessage::new(Intent::sui_transaction(), data.clone()), + &IntentMessage::new(Intent::iota_transaction(), data.clone()), &sender_key, ); let tx = Transaction::from_data(data, vec![signature]); @@ -88,7 +89,7 @@ fn test_authority_signature_intent() { vec![ IntentScope::TransactionData as u8, IntentVersion::V0 as u8, - AppId::Sui as u8, + AppId::Iota as u8, ] ); diff --git a/crates/sui-types/src/unit_tests/messages_tests.rs b/crates/iota-types/src/unit_tests/messages_tests.rs similarity index 93% rename from crates/sui-types/src/unit_tests/messages_tests.rs rename to crates/iota-types/src/unit_tests/messages_tests.rs index 4e9b853d149..c85307502c3 100644 --- a/crates/sui-types/src/unit_tests/messages_tests.rs +++ b/crates/iota-types/src/unit_tests/messages_tests.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -18,8 +19,8 @@ use crate::{ crypto::{ bcs_signable_test::{get_obligation_input, Foo}, get_key_pair, AccountKeyPair, AuthorityKeyPair, AuthorityPublicKeyBytes, - AuthoritySignInfoTrait, Secp256k1SuiSignature, SuiAuthoritySignature, SuiKeyPair, - SuiSignature, SuiSignatureInner, VerificationObligation, + AuthoritySignInfoTrait, IotaAuthoritySignature, IotaKeyPair, IotaSignature, + IotaSignatureInner, Secp256k1IotaSignature, VerificationObligation, }, digests::TransactionEventsDigest, effects::{SignedTransactionEffects, TestEffectsBuilder, TransactionEffectsAPI}, @@ -209,7 +210,7 @@ fn test_new_with_signatures() { signatures.push(AuthoritySignInfo::new( 0, &message, - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), name, &sec, )); @@ -232,7 +233,7 @@ fn test_new_with_signatures() { assert_eq!( quorum .authorities(&committee) - .collect::>>() + .collect::>>() .unwrap(), alphabetical_authorities ); @@ -260,7 +261,7 @@ fn test_handle_reject_malicious_signature() { signatures.push(AuthoritySignInfo::new( 0, &Foo("some data".to_string()), - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), name, &sec, )) @@ -273,7 +274,7 @@ fn test_handle_reject_malicious_signature() { { let (_, sec): (_, AuthorityKeyPair) = get_key_pair(); let sig = AuthoritySignature::new_secure( - &IntentMessage::new(Intent::sui_transaction(), message.clone()), + &IntentMessage::new(Intent::iota_transaction(), message.clone()), &committee.epoch, &sec, ); @@ -295,14 +296,14 @@ fn test_auth_sig_commit_to_wrong_epoch_id_fail() { let idx = obligation.add_message( &message, 0, // Obligation added with correct epoch id. - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), ); let (_, sec): (_, AuthorityKeyPair) = get_key_pair(); // Auth signtaure commits to epoch 0 verifies ok. let sig = AuthoritySignature::new_secure( &IntentMessage::new( - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), message.clone(), ), &0, @@ -317,11 +318,11 @@ fn test_auth_sig_commit_to_wrong_epoch_id_fail() { let idx1 = obligation.add_message( &message, 0, // Obligation added with correct epoch id. - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), ); let sig1 = AuthoritySignature::new_secure( &IntentMessage::new( - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), message.clone(), ), &1, @@ -344,7 +345,7 @@ fn test_bitmap_out_of_range() { signatures.push(AuthoritySignInfo::new( 0, &Foo("some data".to_string()), - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), name, &sec, )); @@ -378,7 +379,7 @@ fn test_reject_extra_public_key() { signatures.push(AuthoritySignInfo::new( 0, &Foo("some data".to_string()), - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), name, &sec, )); @@ -420,7 +421,7 @@ fn test_reject_reuse_signatures() { signatures.push(AuthoritySignInfo::new( 0, &Foo("some data".to_string()), - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), name, &sec, )); @@ -458,7 +459,7 @@ fn test_empty_bitmap() { signatures.push(AuthoritySignInfo::new( 0, &Foo("some data".to_string()), - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), name, &sec, )); @@ -671,7 +672,7 @@ fn test_user_signature_committed_in_signed_transactions() { .auth_sig() .verify_secure( transaction_a.data(), - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), &committee ) .is_ok() @@ -681,7 +682,7 @@ fn test_user_signature_committed_in_signed_transactions() { .auth_sig() .verify_secure( transaction_b.data(), - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), &committee ) .is_err() @@ -711,9 +712,9 @@ fn signature_from_signer( #[test] fn test_sponsored_transaction_message() { - let sender_kp = SuiKeyPair::Ed25519(get_key_pair().1); + let sender_kp = IotaKeyPair::Ed25519(get_key_pair().1); let sender = (&sender_kp.public()).into(); - let sponsor_kp = SuiKeyPair::Ed25519(get_key_pair().1); + let sponsor_kp = IotaKeyPair::Ed25519(get_key_pair().1); let sponsor = (&sponsor_kp.public()).into(); let pt = { let mut builder = ProgrammableTransactionBuilder::new(); @@ -732,7 +733,7 @@ fn test_sponsored_transaction_message() { budget: gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, }; let tx_data = TransactionData::new_with_gas_data(kind, sender, gas_data.clone()); - let intent = Intent::sui_transaction(); + let intent = Intent::iota_transaction(); let sender_sig: GenericSignature = signature_from_signer(tx_data.clone(), intent.clone(), &sender_kp).into(); let sponsor_sig: GenericSignature = @@ -765,7 +766,7 @@ fn test_sponsored_transaction_message() { Transaction::from_generic_sig_data(tx_data.clone(), vec![sender_sig.clone()],) .verify(&Default::default()) .unwrap_err(), - SuiError::SignerSignatureNumberMismatch { .. } + IotaError::SignerSignatureNumberMismatch { .. } )); // Test incomplete signature lists (missing sender sig) @@ -773,11 +774,11 @@ fn test_sponsored_transaction_message() { Transaction::from_generic_sig_data(tx_data.clone(), vec![sponsor_sig.clone()],) .verify(&Default::default()) .unwrap_err(), - SuiError::SignerSignatureNumberMismatch { .. } + IotaError::SignerSignatureNumberMismatch { .. } )); // Test incomplete signature lists (more sigs than expected) - let third_party_kp = SuiKeyPair::Ed25519(get_key_pair().1); + let third_party_kp = IotaKeyPair::Ed25519(get_key_pair().1); let third_party_sig: GenericSignature = signature_from_signer(tx_data.clone(), intent.clone(), &third_party_kp).into(); assert!(matches!( @@ -787,7 +788,7 @@ fn test_sponsored_transaction_message() { ) .verify(&Default::default()) .unwrap_err(), - SuiError::SignerSignatureNumberMismatch { .. } + IotaError::SignerSignatureNumberMismatch { .. } )); // Test irrelevant sigs @@ -795,7 +796,7 @@ fn test_sponsored_transaction_message() { Transaction::from_generic_sig_data(tx_data, vec![sponsor_sig, third_party_sig],) .verify(&Default::default()) .unwrap_err(), - SuiError::SignerSignatureAbsent { .. } + IotaError::SignerSignatureAbsent { .. } )); let tx = transaction.data().transaction_data(); @@ -807,9 +808,9 @@ fn test_sponsored_transaction_message() { #[test] fn test_sponsored_transaction_validity_check() { - let sender_kp = SuiKeyPair::Ed25519(get_key_pair().1); + let sender_kp = IotaKeyPair::Ed25519(get_key_pair().1); let sender = (&sender_kp.public()).into(); - let sponsor_kp = SuiKeyPair::Ed25519(get_key_pair().1); + let sponsor_kp = IotaKeyPair::Ed25519(get_key_pair().1); let sponsor = (&sponsor_kp.public()).into(); // This is a sponsored transaction @@ -870,7 +871,7 @@ fn test_sponsored_transaction_validity_check() { builder .pay( vec![random_object_ref()], - vec![SuiAddress::random_for_testing_only()], + vec![IotaAddress::random_for_testing_only()], vec![100000], ) .unwrap(); @@ -881,10 +882,10 @@ fn test_sponsored_transaction_validity_check() { .validity_check(&ProtocolConfig::get_for_max_version_UNSAFE()) .unwrap(); - // TransferSui + // TransferIota let pt = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.transfer_sui(SuiAddress::random_for_testing_only(), Some(50000)); + builder.transfer_iota(IotaAddress::random_for_testing_only(), Some(50000)); builder.finish() }; let kind = TransactionKind::programmable(pt); @@ -892,10 +893,10 @@ fn test_sponsored_transaction_validity_check() { .validity_check(&ProtocolConfig::get_for_max_version_UNSAFE()) .unwrap(); - // PaySui + // PayIota let pt = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.pay_sui(vec![], vec![]).unwrap(); + builder.pay_iota(vec![], vec![]).unwrap(); builder.finish() }; let kind = TransactionKind::programmable(pt); @@ -903,10 +904,10 @@ fn test_sponsored_transaction_validity_check() { .validity_check(&ProtocolConfig::get_for_max_version_UNSAFE()) .unwrap(); - // PayAllSui + // PayAllIota let pt = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.pay_all_sui(SuiAddress::random_for_testing_only()); + builder.pay_all_iota(IotaAddress::random_for_testing_only()); builder.finish() }; let kind = TransactionKind::programmable(pt); @@ -926,11 +927,11 @@ fn verify_sender_signature_correctly_with_flag() { let committee = Committee::new_for_testing_with_normalized_voting_power(0, authorities); // create a receiver keypair with Secp256k1 - let receiver_kp = SuiKeyPair::Secp256k1(get_key_pair().1); + let receiver_kp = IotaKeyPair::Secp256k1(get_key_pair().1); let receiver_address = (&receiver_kp.public()).into(); // create a sender keypair with Secp256k1 - let sender_kp = SuiKeyPair::Secp256k1(get_key_pair().1); + let sender_kp = IotaKeyPair::Secp256k1(get_key_pair().1); // and creates a corresponding transaction let gas_price = 10; let tx_data = TransactionData::new_transfer( @@ -943,13 +944,13 @@ fn verify_sender_signature_correctly_with_flag() { ); // create a sender keypair with Ed25519 - let sender_kp_2 = SuiKeyPair::Ed25519(get_key_pair().1); + let sender_kp_2 = IotaKeyPair::Ed25519(get_key_pair().1); let mut tx_data_2 = tx_data.clone(); *tx_data_2.sender_mut_for_testing() = (&sender_kp_2.public()).into(); tx_data_2.gas_data_mut().owner = tx_data_2.sender(); // create a sender keypair with Secp256r1 - let sender_kp_3 = SuiKeyPair::Secp256r1(get_key_pair().1); + let sender_kp_3 = IotaKeyPair::Secp256r1(get_key_pair().1); let mut tx_data_3 = tx_data.clone(); *tx_data_3.sender_mut_for_testing() = (&sender_kp_3.public()).into(); tx_data_3.gas_data_mut().owner = tx_data_3.sender(); @@ -971,7 +972,7 @@ fn verify_sender_signature_correctly_with_flag() { _ => panic!("invalid"), }; // signature contains the correct Secp256k1 flag - assert_eq!(s.scheme().flag(), Secp256k1SuiSignature::SCHEME.flag()); + assert_eq!(s.scheme().flag(), Secp256k1IotaSignature::SCHEME.flag()); // authority accepts signs tx after verification assert!( @@ -979,7 +980,7 @@ fn verify_sender_signature_correctly_with_flag() { .auth_sig() .verify_secure( transaction.data(), - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), &committee ) .is_ok() @@ -1001,7 +1002,7 @@ fn verify_sender_signature_correctly_with_flag() { }; // signature contains the correct Ed25519 flag - assert_eq!(s.scheme().flag(), Ed25519SuiSignature::SCHEME.flag()); + assert_eq!(s.scheme().flag(), Ed25519IotaSignature::SCHEME.flag()); // signature verified assert!( @@ -1009,7 +1010,7 @@ fn verify_sender_signature_correctly_with_flag() { .auth_sig() .verify_secure( transaction_1.data(), - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), &committee ) .is_ok() @@ -1020,7 +1021,7 @@ fn verify_sender_signature_correctly_with_flag() { .auth_sig() .verify_secure( transaction.data(), - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), &committee ) .is_err() @@ -1046,7 +1047,7 @@ fn verify_sender_signature_correctly_with_flag() { .auth_sig() .verify_secure( tx_32.data(), - Intent::sui_app(IntentScope::SenderSignedTransaction), + Intent::iota_app(IntentScope::SenderSignedTransaction), &committee ) .is_ok() @@ -1059,7 +1060,7 @@ fn test_change_epoch_transaction() { assert!(tx.contains_shared_object()); assert_eq!( tx.shared_input_objects().next().unwrap(), - SharedInputObject::SUI_SYSTEM_OBJ + SharedInputObject::IOTA_SYSTEM_OBJ ); assert!(tx.is_system_tx()); assert_eq!( @@ -1080,8 +1081,8 @@ fn test_consensus_commit_prologue_transaction() { assert_eq!( tx.shared_input_objects().next().unwrap(), SharedInputObject { - id: SUI_CLOCK_OBJECT_ID, - initial_shared_version: SUI_CLOCK_OBJECT_SHARED_VERSION, + id: IOTA_CLOCK_OBJECT_ID, + initial_shared_version: IOTA_CLOCK_OBJECT_SHARED_VERSION, mutable: true, }, ); @@ -1109,8 +1110,8 @@ fn test_consensus_commit_prologue_v2_transaction() { assert_eq!( tx.shared_input_objects().next().unwrap(), SharedInputObject { - id: SUI_CLOCK_OBJECT_ID, - initial_shared_version: SUI_CLOCK_OBJECT_SHARED_VERSION, + id: IOTA_CLOCK_OBJECT_ID, + initial_shared_version: IOTA_CLOCK_OBJECT_SHARED_VERSION, mutable: true, }, ); @@ -1179,7 +1180,7 @@ fn test_move_input_objects() { args, )); let data = TransactionData::new_programmable( - SuiAddress::random_for_testing_only(), + IotaAddress::random_for_testing_only(), vec![gas_object_ref], builder.finish(), 1_000_000, // any random number the transaction is not run @@ -1263,7 +1264,7 @@ fn test_unique_input_objects() { .unwrap(), ]; - let sender_kp = SuiKeyPair::Ed25519(get_key_pair().1); + let sender_kp = IotaKeyPair::Ed25519(get_key_pair().1); let sender = (&sender_kp.public()).into(); let gas_price = 10; let gas_object_ref = random_object_ref(); diff --git a/crates/iota-types/src/unit_tests/multisig_tests.rs b/crates/iota-types/src/unit_tests/multisig_tests.rs new file mode 100644 index 00000000000..505f47ba33d --- /dev/null +++ b/crates/iota-types/src/unit_tests/multisig_tests.rs @@ -0,0 +1,514 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::str::FromStr; + +use fastcrypto::{ + ed25519::Ed25519KeyPair, + encoding::{Base64, Encoding}, + traits::ToFromBytes, +}; +use fastcrypto_zkp::{ + bn254::{ + zk_login::{parse_jwks, JwkId, OIDCProvider, ZkLoginInputs, JWK}, + zk_login_api::ZkLoginEnv, + }, + zk_login_utils::Bn254FrElement, +}; +use im::hashmap::HashMap as ImHashMap; +use once_cell::sync::OnceCell; +use rand::{rngs::StdRng, SeedableRng}; +use roaring::RoaringBitmap; +use shared_crypto::intent::{Intent, IntentMessage, PersonalMessage}; + +use super::{MultiSigPublicKey, ThresholdUnit, WeightUnit}; +use crate::{ + base_types::IotaAddress, + crypto::{ + get_key_pair, get_key_pair_from_rng, Ed25519IotaSignature, IotaKeyPair, IotaSignatureInner, + PublicKey, Signature, ZkLoginPublicIdentifier, + }, + multisig::{as_indices, MultiSig, MAX_SIGNER_IN_MULTISIG}, + multisig_legacy::bitmap_to_u16, + signature::{AuthenticatorTrait, GenericSignature, VerifyParams}, + utils::{ + keys, load_test_vectors, make_transaction_data, make_zklogin_tx, DEFAULT_ADDRESS_SEED, + SHORT_ADDRESS_SEED, + }, + zk_login_authenticator::ZkLoginAuthenticator, + zk_login_util::DEFAULT_JWK_BYTES, +}; +#[test] +fn test_combine_sigs() { + let kp1: IotaKeyPair = IotaKeyPair::Ed25519(get_key_pair().1); + let kp2: IotaKeyPair = IotaKeyPair::Secp256k1(get_key_pair().1); + let kp3: IotaKeyPair = IotaKeyPair::Secp256r1(get_key_pair().1); + + let pk1 = kp1.public(); + let pk2 = kp2.public(); + + let multisig_pk = MultiSigPublicKey::new(vec![pk1, pk2], vec![1, 1], 2).unwrap(); + + let msg = IntentMessage::new( + Intent::iota_transaction(), + PersonalMessage { + message: "Hello".as_bytes().to_vec(), + }, + ); + let sig1: GenericSignature = Signature::new_secure(&msg, &kp1).into(); + let sig2 = Signature::new_secure(&msg, &kp2).into(); + let sig3 = Signature::new_secure(&msg, &kp3).into(); + + // MultiSigPublicKey contains only 2 public key but 3 signatures are passed, + // fails to combine. + assert!(MultiSig::combine(vec![sig1.clone(), sig2, sig3], multisig_pk.clone()).is_err()); + + // Cannot create malformed MultiSig. + assert!(MultiSig::combine(vec![], multisig_pk.clone()).is_err()); + assert!(MultiSig::combine(vec![sig1.clone(), sig1], multisig_pk).is_err()); +} +#[test] +fn test_serde_roundtrip() { + let msg = IntentMessage::new( + Intent::iota_transaction(), + PersonalMessage { + message: "Hello".as_bytes().to_vec(), + }, + ); + + for kp in keys() { + let pk = kp.public(); + let multisig_pk = MultiSigPublicKey::new(vec![pk], vec![1], 1).unwrap(); + let sig = Signature::new_secure(&msg, &kp).into(); + let multisig = MultiSig::combine(vec![sig], multisig_pk).unwrap(); + let plain_bytes = bcs::to_bytes(&multisig).unwrap(); + + let generic_sig = GenericSignature::MultiSig(multisig); + let generic_sig_bytes = generic_sig.as_bytes(); + let generic_sig_roundtrip = GenericSignature::from_bytes(generic_sig_bytes).unwrap(); + assert_eq!(generic_sig, generic_sig_roundtrip); + + // A MultiSig flag 0x03 is appended before the bcs serialized bytes. + assert_eq!(plain_bytes.len() + 1, generic_sig_bytes.len()); + assert_eq!(generic_sig_bytes.first().unwrap(), &0x03); + } + + // Malformed multisig cannot be deserialized + let multisig_pk = MultiSigPublicKey { + pk_map: vec![(keys()[0].public(), 1)], + threshold: 1, + }; + let multisig = MultiSig { + sigs: vec![], // No sigs + bitmap: 0, + multisig_pk, + bytes: OnceCell::new(), + }; + + let generic_sig = GenericSignature::MultiSig(multisig); + let generic_sig_bytes = generic_sig.as_bytes(); + assert!(GenericSignature::from_bytes(generic_sig_bytes).is_err()); + + // Malformed multisig_pk cannot be deserialized + let multisig_pk_1 = MultiSigPublicKey { + pk_map: vec![], + threshold: 0, + }; + + let multisig_1 = MultiSig { + sigs: vec![], + bitmap: 0, + multisig_pk: multisig_pk_1, + bytes: OnceCell::new(), + }; + + let generic_sig_1 = GenericSignature::MultiSig(multisig_1); + let generic_sig_bytes = generic_sig_1.as_bytes(); + assert!(GenericSignature::from_bytes(generic_sig_bytes).is_err()); + + // Single sig serialization unchanged. + let sig = Ed25519IotaSignature::default(); + let single_sig = GenericSignature::Signature(sig.clone().into()); + let single_sig_bytes = single_sig.as_bytes(); + let single_sig_roundtrip = GenericSignature::from_bytes(single_sig_bytes).unwrap(); + assert_eq!(single_sig, single_sig_roundtrip); + assert_eq!(single_sig_bytes.len(), Ed25519IotaSignature::LENGTH); + assert_eq!( + single_sig_bytes.first().unwrap(), + &Ed25519IotaSignature::SCHEME.flag() + ); + assert_eq!(sig.as_bytes().len(), single_sig_bytes.len()); +} + +#[test] +fn test_multisig_pk_new() { + let keys = keys(); + let pk1 = keys[0].public(); + let pk2 = keys[1].public(); + let pk3 = keys[2].public(); + + // Fails on weight 0. + assert!( + MultiSigPublicKey::new( + vec![pk1.clone(), pk2.clone(), pk3.clone()], + vec![0, 1, 1], + 2 + ) + .is_err() + ); + + // Fails on threshold 0. + assert!( + MultiSigPublicKey::new( + vec![pk1.clone(), pk2.clone(), pk3.clone()], + vec![1, 1, 1], + 0 + ) + .is_err() + ); + + // Fails on incorrect array length. + assert!( + MultiSigPublicKey::new(vec![pk1.clone(), pk2.clone(), pk3.clone()], vec![1], 2).is_err() + ); + + // Fails on empty array length. + assert!(MultiSigPublicKey::new(vec![pk1.clone(), pk2, pk3], vec![], 2).is_err()); + + // Fails on dup pks. + assert!( + MultiSigPublicKey::new(vec![pk1.clone(), pk1.clone(), pk1], vec![1, 2, 3], 4,).is_err() + ); +} + +#[test] +fn test_multisig_address() { + // Pin an hardcoded multisig address generation here. If this fails, the address + // generation logic may have changed. If this is intended, update the hardcoded + // value below. + let keys = keys(); + let pk1 = keys[0].public(); + let pk2 = keys[1].public(); + let pk3 = keys[2].public(); + + let threshold: ThresholdUnit = 2; + let w1: WeightUnit = 1; + let w2: WeightUnit = 2; + let w3: WeightUnit = 3; + + let multisig_pk = + MultiSigPublicKey::new(vec![pk1, pk2, pk3], vec![w1, w2, w3], threshold).unwrap(); + let address: IotaAddress = (&multisig_pk).into(); + assert_eq!( + IotaAddress::from_str("0xe35c69eb504de34afdbd9f307fb3ca152646c92d549fea00065d26fc422109ea") + .unwrap(), + address + ); +} + +#[test] +fn test_max_sig() { + let msg = IntentMessage::new( + Intent::iota_transaction(), + PersonalMessage { + message: "Hello".as_bytes().to_vec(), + }, + ); + let mut seed = StdRng::from_seed([0; 32]); + let mut keys = Vec::new(); + let mut pks = Vec::new(); + + for _ in 0..11 { + let k = IotaKeyPair::Ed25519(get_key_pair_from_rng(&mut seed).1); + pks.push(k.public()); + keys.push(k); + } + + // multisig_pk with larger that max number of pks fails. + assert!( + MultiSigPublicKey::new( + pks.clone(), + vec![WeightUnit::MAX; MAX_SIGNER_IN_MULTISIG + 1], + ThresholdUnit::MAX + ) + .is_err() + ); + + // multisig_pk with unreachable threshold fails. + assert!(MultiSigPublicKey::new(pks.clone()[..5].to_vec(), vec![3; 5], 16).is_err()); + + // multisig_pk with max weights for each pk and max reachable threshold is ok. + let res = MultiSigPublicKey::new( + pks.clone()[..10].to_vec(), + vec![WeightUnit::MAX; MAX_SIGNER_IN_MULTISIG], + (WeightUnit::MAX as ThresholdUnit) * (MAX_SIGNER_IN_MULTISIG as ThresholdUnit), + ); + assert!(res.is_ok()); + + // multisig_pk with unreachable threshold fails. + let res = MultiSigPublicKey::new( + pks.clone()[..10].to_vec(), + vec![WeightUnit::MAX; MAX_SIGNER_IN_MULTISIG], + (WeightUnit::MAX as ThresholdUnit) * (MAX_SIGNER_IN_MULTISIG as ThresholdUnit) + 1, + ); + assert!(res.is_err()); + + // multisig_pk with max weights for each pk with threshold is 1x max weight + // validates ok. + let low_threshold_pk = MultiSigPublicKey::new( + pks.clone()[..10].to_vec(), + vec![WeightUnit::MAX; 10], + WeightUnit::MAX.into(), + ) + .unwrap(); + let sig = Signature::new_secure(&msg, &keys[0]).into(); + assert!( + MultiSig::combine(vec![sig; 1], low_threshold_pk) + .unwrap() + .init_and_validate() + .is_ok() + ); +} + +#[test] +fn test_to_from_indices() { + assert!(as_indices(0b11111111110).is_err()); + assert_eq!(as_indices(0b0000010110).unwrap(), vec![1, 2, 4]); + assert_eq!( + as_indices(0b1111111111).unwrap(), + vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + ); + + let mut bitmap = RoaringBitmap::new(); + bitmap.insert(1); + bitmap.insert(2); + bitmap.insert(4); + assert_eq!(bitmap_to_u16(bitmap.clone()).unwrap(), 0b0000010110); + bitmap.insert(11); + assert!(bitmap_to_u16(bitmap).is_err()); +} + +#[test] +fn multisig_get_pk() { + let keys = keys(); + let pk1 = keys[0].public(); + let pk2 = keys[1].public(); + + let multisig_pk = MultiSigPublicKey::new(vec![pk1, pk2], vec![1, 1], 2).unwrap(); + let msg = IntentMessage::new( + Intent::iota_transaction(), + PersonalMessage { + message: "Hello".as_bytes().to_vec(), + }, + ); + let sig1: GenericSignature = Signature::new_secure(&msg, &keys[0]).into(); + let sig2: GenericSignature = Signature::new_secure(&msg, &keys[1]).into(); + + let multi_sig = + MultiSig::combine(vec![sig1.clone(), sig2.clone()], multisig_pk.clone()).unwrap(); + + assert!(multi_sig.get_pk().clone() == multisig_pk); + assert!( + *multi_sig.get_sigs() == vec![sig1.to_compressed().unwrap(), sig2.to_compressed().unwrap()] + ); +} + +#[test] +fn multisig_get_indices() { + let keys = keys(); + let pk1 = keys[0].public(); + let pk2 = keys[1].public(); + let pk3 = keys[2].public(); + + let multisig_pk = MultiSigPublicKey::new(vec![pk1, pk2, pk3], vec![1, 1, 1], 2).unwrap(); + let msg = IntentMessage::new( + Intent::iota_transaction(), + PersonalMessage { + message: "Hello".as_bytes().to_vec(), + }, + ); + let sig1: GenericSignature = Signature::new_secure(&msg, &keys[0]).into(); + let sig2: GenericSignature = Signature::new_secure(&msg, &keys[1]).into(); + let sig3: GenericSignature = Signature::new_secure(&msg, &keys[2]).into(); + + let multi_sig1 = + MultiSig::combine(vec![sig2.clone(), sig3.clone()], multisig_pk.clone()).unwrap(); + + let multi_sig2 = MultiSig::combine( + vec![sig1.clone(), sig2.clone(), sig3.clone()], + multisig_pk.clone(), + ) + .unwrap(); + + let invalid_multisig = MultiSig::combine(vec![sig3, sig2, sig1], multisig_pk).unwrap(); + + // Indexes of public keys in multisig public key instance according to the + // combined sigs. + assert!(multi_sig1.get_indices().unwrap() == vec![1, 2]); + assert!(multi_sig2.get_indices().unwrap() == vec![0, 1, 2]); + assert!(invalid_multisig.get_indices().unwrap() == vec![0, 1, 2]); +} + +#[test] +fn multisig_zklogin_scenarios() { + // consistency test with + // iota/sdk/typescript/test/unit/cryptography/multisig.test.ts + let mut seed = StdRng::from_seed([0; 32]); + let kp: Ed25519KeyPair = get_key_pair_from_rng(&mut seed).1; + let skp: IotaKeyPair = IotaKeyPair::Ed25519(kp); + let pk1 = skp.public(); + + let (_, _, inputs) = &load_test_vectors("./src/unit_tests/zklogin_test_vectors.json")[0]; + // pk consistent with the one in make_zklogin_tx + let pk2 = PublicKey::ZkLogin( + ZkLoginPublicIdentifier::new( + &OIDCProvider::Twitch.get_config().iss, + inputs.get_address_seed(), + ) + .unwrap(), + ); + + // set up 1-out-of-2 multisig with one zklogin public identifier and one + // traditional public key. + let multisig_pk = MultiSigPublicKey::new(vec![pk1, pk2], vec![1, 1], 1).unwrap(); + let multisig_addr = IotaAddress::from(&multisig_pk); + assert_eq!( + multisig_addr, + IotaAddress::from_str("0xb9c0780a3943cde13a2409bf1a6f06ae60b0dff2b2f373260cf627aa4f43a588") + .unwrap() + ); + + let (_, envelop, zklogin_sig) = make_zklogin_tx(multisig_addr, false); + let binding = envelop.into_data(); + let tx = binding.transaction_data(); + assert_eq!(Base64::encode(bcs::to_bytes(tx).unwrap()), "AAABACACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgEBAQABAAC5wHgKOUPN4TokCb8abwauYLDf8rLzcyYM9ieqT0OliAGbB4FfBEl+LgXSLKw6oGFBCyCGjMYZFUxCocYb6ZAnFwEAAAAAAAAAIJZw7UpW1XHubORIOaY8d2+WyBNwoJ+FEAxlsa7h7JHrucB4CjlDzeE6JAm/Gm8GrmCw3/Ky83MmDPYnqk9DpYgBAAAAAAAAABAnAAAAAAAAAA==".to_string()); + + let intent_msg = &IntentMessage::new(Intent::iota_transaction(), tx.clone()); + assert_eq!(Base64::encode(zklogin_sig.as_ref()), "BQNNMTczMTgwODkxMjU5NTI0MjE3MzYzNDIyNjM3MTc5MzI3MTk0Mzc3MTc4NDQyODI0MTAxODc5NTc5ODQ3NTE5Mzk5NDI4OTgyNTEyNTBNMTEzNzM5NjY2NDU0NjkxMjI1ODIwNzQwODIyOTU5ODUzODgyNTg4NDA2ODE2MTgyNjg1OTM5NzY2OTczMjU4OTIyODA5MTU2ODEyMDcBMQMCTDU5Mzk4NzExNDczNDg4MzQ5OTczNjE3MjAxMjIyMzg5ODAxNzcxNTIzMDMyNzQzMTEwNDcyNDk5MDU5NDIzODQ5MTU3Njg2OTA4OTVMNDUzMzU2ODI3MTEzNDc4NTI3ODczMTIzNDU3MDM2MTQ4MjY1MTk5Njc0MDc5MTg4ODI4NTg2NDk2Njg4NDAzMjcxNzA0OTgxMTcwOAJNMTA1NjQzODcyODUwNzE1NTU0Njk3NTM5OTA2NjE0MTA4NDAxMTg2MzU5MjU0NjY1OTcwMzcwMTgwNTg3NzAwNDEzNDc1MTg0NjEzNjhNMTI1OTczMjM1NDcyNzc1NzkxNDQ2OTg0OTYzNzIyNDI2MTUzNjgwODU4MDEzMTMzNDMxNTU3MzU1MTEzMzAwMDM4ODQ3Njc5NTc4NTQCATEBMANNMTU3OTE1ODk0NzI1NTY4MjYyNjMyMzE2NDQ3Mjg4NzMzMzc2MjkwMTUyNjk5ODQ2OTk0MDQwNzM2MjM2MDMzNTI1Mzc2Nzg4MTMxNzFMNDU0Nzg2NjQ5OTI0ODg4MTQ0OTY3NjE2MTE1ODAyNDc0ODA2MDQ4NTM3MzI1MDAyOTQyMzkwNDExMzAxNzQyMjUzOTAzNzE2MjUyNwExMXdpYVhOeklqb2lhSFIwY0hNNkx5OXBaQzUwZDJsMFkyZ3VkSFl2YjJGMWRHZ3lJaXcCMmV5SmhiR2NpT2lKU1V6STFOaUlzSW5SNWNDSTZJa3BYVkNJc0ltdHBaQ0k2SWpFaWZRTTIwNzk0Nzg4NTU5NjIwNjY5NTk2MjA2NDU3MDIyOTY2MTc2OTg2Njg4NzI3ODc2MTI4MjIzNjI4MTEzOTE2MzgwOTI3NTAyNzM3OTExCgAAAAAAAABhABHpkQ5JvxqbqCKtqh9M0U5c3o3l62B6ALVOxMq6nsc0y3JlY8Gf1ZoPA976dom6y3JGBUTsry6axfqHcVrtRAy5xu4WMO8+cRFEpkjbBruyKE9ydM++5T/87lA8waSSAA==".to_string()); + + let single_sig = GenericSignature::Signature(Signature::new_secure(intent_msg, &skp)); + let multisig = GenericSignature::MultiSig( + MultiSig::combine(vec![single_sig, zklogin_sig], multisig_pk.clone()).unwrap(), + ); + assert_eq!(Base64::encode(multisig.as_ref()), "AwIAcAEsWrZtlsE3AdGUKJAPag8Tu6HPfMW7gEemeneO9fmNGiJP/rDZu/tL75lr8A22eFDx9K2G1DL4v8XlmuTtCgOaBwUDTTE3MzE4MDg5MTI1OTUyNDIxNzM2MzQyMjYzNzE3OTMyNzE5NDM3NzE3ODQ0MjgyNDEwMTg3OTU3OTg0NzUxOTM5OTQyODk4MjUxMjUwTTExMzczOTY2NjQ1NDY5MTIyNTgyMDc0MDgyMjk1OTg1Mzg4MjU4ODQwNjgxNjE4MjY4NTkzOTc2Njk3MzI1ODkyMjgwOTE1NjgxMjA3ATEDAkw1OTM5ODcxMTQ3MzQ4ODM0OTk3MzYxNzIwMTIyMjM4OTgwMTc3MTUyMzAzMjc0MzExMDQ3MjQ5OTA1OTQyMzg0OTE1NzY4NjkwODk1TDQ1MzM1NjgyNzExMzQ3ODUyNzg3MzEyMzQ1NzAzNjE0ODI2NTE5OTY3NDA3OTE4ODgyODU4NjQ5NjY4ODQwMzI3MTcwNDk4MTE3MDgCTTEwNTY0Mzg3Mjg1MDcxNTU1NDY5NzUzOTkwNjYxNDEwODQwMTE4NjM1OTI1NDY2NTk3MDM3MDE4MDU4NzcwMDQxMzQ3NTE4NDYxMzY4TTEyNTk3MzIzNTQ3Mjc3NTc5MTQ0Njk4NDk2MzcyMjQyNjE1MzY4MDg1ODAxMzEzMzQzMTU1NzM1NTExMzMwMDAzODg0NzY3OTU3ODU0AgExATADTTE1NzkxNTg5NDcyNTU2ODI2MjYzMjMxNjQ0NzI4ODczMzM3NjI5MDE1MjY5OTg0Njk5NDA0MDczNjIzNjAzMzUyNTM3Njc4ODEzMTcxTDQ1NDc4NjY0OTkyNDg4ODE0NDk2NzYxNjExNTgwMjQ3NDgwNjA0ODUzNzMyNTAwMjk0MjM5MDQxMTMwMTc0MjI1MzkwMzcxNjI1MjcBMTF3aWFYTnpJam9pYUhSMGNITTZMeTlwWkM1MGQybDBZMmd1ZEhZdmIyRjFkR2d5SWl3AjJleUpoYkdjaU9pSlNVekkxTmlJc0luUjVjQ0k2SWtwWFZDSXNJbXRwWkNJNklqRWlmUU0yMDc5NDc4ODU1OTYyMDY2OTU5NjIwNjQ1NzAyMjk2NjE3Njk4NjY4ODcyNzg3NjEyODIyMzYyODExMzkxNjM4MDkyNzUwMjczNzkxMQoAAAAAAAAAYQAR6ZEOSb8am6giraofTNFOXN6N5etgegC1TsTKup7HNMtyZWPBn9WaDwPe+naJustyRgVE7K8umsX6h3Fa7UQMucbuFjDvPnERRKZI2wa7sihPcnTPvuU//O5QPMGkkgADAAIADX2rNYyNrapO+gBJp1sHQ2VVsQo2ghm7aA9wVxNJ13UBAzwbaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyLflu6Eag/zG3tLd5CtZRYx9p1t34RovVSn/+uHFiYfcBAQA=".to_string()); +} + +#[test] +fn zklogin_in_multisig_works_with_both_addresses() { + let mut seed = StdRng::from_seed([0; 32]); + let kp: Ed25519KeyPair = get_key_pair_from_rng(&mut seed).1; + let skp: IotaKeyPair = IotaKeyPair::Ed25519(kp); + + // create a new multisig address based on pk1 and pk2 where pk1 is a zklogin + // public identifier, with a crafted unpadded bytes. + let mut bytes = Vec::new(); + let binding = OIDCProvider::Twitch.get_config(); + let iss_bytes = binding.iss.as_bytes(); + bytes.extend([iss_bytes.len() as u8]); + bytes.extend(iss_bytes); + // length here is 31 bytes and left unpadded. + let address_seed = Bn254FrElement::from_str(SHORT_ADDRESS_SEED).unwrap(); + bytes.extend(address_seed.unpadded()); + + let pk1 = PublicKey::ZkLogin(ZkLoginPublicIdentifier(bytes)); + let pk2 = skp.public(); + let multisig_pk = MultiSigPublicKey::new(vec![pk1, pk2.clone()], vec![1; 2], 1).unwrap(); + let multisig_address = IotaAddress::from(&multisig_pk); + + let (kp, _pk, input) = &load_test_vectors("./src/unit_tests/zklogin_test_vectors.json")[0]; + let intent_msg = &IntentMessage::new( + Intent::iota_transaction(), + make_transaction_data(multisig_address), + ); + let user_signature = Signature::new_secure(intent_msg, kp); + + let modified_inputs = + ZkLoginInputs::from_json(&serde_json::to_string(input).unwrap(), SHORT_ADDRESS_SEED) + .unwrap(); + let zklogin_sig = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( + modified_inputs.clone(), + 10, + user_signature, + )); + let multisig = + MultiSig::insecure_new(vec![zklogin_sig.to_compressed().unwrap()], 1, multisig_pk); + + let parsed: ImHashMap = parse_jwks(DEFAULT_JWK_BYTES, &OIDCProvider::Twitch) + .unwrap() + .into_iter() + .collect(); + + let aux_verify_data = VerifyParams::new(parsed, vec![], ZkLoginEnv::Test, true, true); + let res = multisig.verify_claims(intent_msg, multisig_address, &aux_verify_data); + // since the zklogin inputs is crafted, it is expected that the proof verify + // failed, but all checks before passes. + assert!( + matches!(res, Err(crate::error::IotaError::InvalidSignature { error }) if error.contains("General cryptographic error: Groth16 proof verify failed")) + ); + + // initialize zklogin pk (pk1_padd) with padded address seed + let pk1_padded = PublicKey::ZkLogin( + ZkLoginPublicIdentifier::new( + &OIDCProvider::Twitch.get_config().iss, + &Bn254FrElement::from_str(SHORT_ADDRESS_SEED).unwrap(), + ) + .unwrap(), + ); + let multisig_pk_padded = MultiSigPublicKey::new(vec![pk1_padded, pk2], vec![1; 2], 1).unwrap(); + let multisig_address_padded = IotaAddress::from(&multisig_pk_padded); + let modified_inputs_padded = + ZkLoginInputs::from_json(&serde_json::to_string(input).unwrap(), SHORT_ADDRESS_SEED) + .unwrap(); + let intent_msg_padded = &IntentMessage::new( + Intent::iota_transaction(), + make_transaction_data(multisig_address_padded), + ); + let user_signature_padded = Signature::new_secure(intent_msg_padded, kp); + let zklogin_sig_padded = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( + modified_inputs_padded.clone(), + 10, + user_signature_padded, + )); + let multisig_padded = MultiSig::insecure_new( + vec![zklogin_sig_padded.to_compressed().unwrap()], + 1, + multisig_pk_padded, + ); + + let res = + multisig_padded.verify_claims(intent_msg_padded, multisig_address_padded, &aux_verify_data); + assert!( + matches!(res, Err(crate::error::IotaError::InvalidSignature { error }) if error.contains("General cryptographic error: Groth16 proof verify failed")) + ); +} + +#[test] +fn test_derive_multisig_address() { + // consistency test with typescript: + // /sdk/typescript/test/unit/cryptography/multisig.test.ts + let pk1 = PublicKey::ZkLogin( + ZkLoginPublicIdentifier::new( + &OIDCProvider::Twitch.get_config().iss, + &Bn254FrElement::from_str(DEFAULT_ADDRESS_SEED).unwrap(), + ) + .unwrap(), + ); + // address seed here is padded with leading 0 to 32 bytes. + let pk2 = PublicKey::ZkLogin( + ZkLoginPublicIdentifier::new( + &OIDCProvider::Twitch.get_config().iss, + &Bn254FrElement::from_str(SHORT_ADDRESS_SEED).unwrap(), + ) + .unwrap(), + ); + assert_eq!(pk1.as_ref().len(), pk2.as_ref().len()); + + let multisig_pk = MultiSigPublicKey::new(vec![pk1, pk2], vec![1, 1], 1).unwrap(); + let multisig_addr = IotaAddress::from(&multisig_pk); + assert_eq!( + multisig_addr, + IotaAddress::from_str("0x77a9fbf3c695d78dd83449a81a9e70aa79a77dbfd6fb72037bf09201c12052cd") + .unwrap() + ); +} diff --git a/crates/sui-types/src/unit_tests/timelock/timelock_tests.rs b/crates/iota-types/src/unit_tests/timelock/timelock_tests.rs similarity index 93% rename from crates/sui-types/src/unit_tests/timelock/timelock_tests.rs rename to crates/iota-types/src/unit_tests/timelock/timelock_tests.rs index 0151f5bea38..bf24fcd3699 100644 --- a/crates/sui-types/src/unit_tests/timelock/timelock_tests.rs +++ b/crates/iota-types/src/unit_tests/timelock/timelock_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) 2024 IOTA Stiftung +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use crate::{balance::Balance, base_types::ObjectID, id::UID, timelock::timelock::TimeLock}; diff --git a/crates/iota-types/src/unit_tests/utils.rs b/crates/iota-types/src/unit_tests/utils.rs new file mode 100644 index 00000000000..1321a96feda --- /dev/null +++ b/crates/iota-types/src/unit_tests/utils.rs @@ -0,0 +1,320 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use fastcrypto::{ed25519::Ed25519KeyPair, hash::HashFunction, traits::KeyPair as KeypairTraits}; +use rand::{rngs::StdRng, SeedableRng}; +use serde::Deserialize; +use shared_crypto::intent::{Intent, IntentMessage}; + +use crate::{ + base_types::{dbg_addr, ExecutionDigests, ObjectID}, + committee::Committee, + crypto::{ + get_key_pair, get_key_pair_from_rng, AccountKeyPair, AuthorityKeyPair, + AuthorityPublicKeyBytes, DefaultHash, IotaKeyPair, Signature, SignatureScheme, Signer, + }, + gas::GasCostSummary, + messages_checkpoint::{ + CertifiedCheckpointSummary, CheckpointContents, CheckpointSummary, SignedCheckpointSummary, + }, + multisig::{MultiSig, MultiSigPublicKey}, + object::Object, + programmable_transaction_builder::ProgrammableTransactionBuilder, + signature::GenericSignature, + transaction::{ + SenderSignedData, Transaction, TransactionData, TEST_ONLY_GAS_UNIT_FOR_TRANSFER, + }, + zk_login_authenticator::ZkLoginAuthenticator, + IotaAddress, +}; + +#[derive(Deserialize)] +pub struct TestData { + pub zklogin_inputs: String, + pub kp: String, + pub pk_bigint: String, + pub salt: String, + pub address_seed: String, +} + +pub fn make_committee_key(rand: &mut R) -> (Vec, Committee) +where + R: rand::CryptoRng + rand::RngCore, +{ + make_committee_key_num(4, rand) +} + +pub fn make_committee_key_num(num: usize, rand: &mut R) -> (Vec, Committee) +where + R: rand::CryptoRng + rand::RngCore, +{ + let mut authorities: BTreeMap = BTreeMap::new(); + let mut keys = Vec::new(); + + for _ in 0..num { + let (_, inner_authority_key): (_, AuthorityKeyPair) = get_key_pair_from_rng(rand); + authorities.insert( + // address + AuthorityPublicKeyBytes::from(inner_authority_key.public()), + // voting right + 1, + ); + keys.push(inner_authority_key); + } + + let committee = Committee::new_for_testing_with_normalized_voting_power(0, authorities); + (keys, committee) +} + +// Creates a fake sender-signed transaction for testing. This transaction will +// not actually work. +pub fn create_fake_transaction() -> Transaction { + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let recipient = dbg_addr(2); + let object_id = ObjectID::random(); + let object = Object::immutable_with_id_for_testing(object_id); + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + builder.transfer_iota(recipient, None); + builder.finish() + }; + let data = TransactionData::new_programmable( + sender, + vec![object.compute_object_reference()], + pt, + TEST_ONLY_GAS_UNIT_FOR_TRANSFER, // gas price is 1 + 1, + ); + to_sender_signed_transaction(data, &sender_key) +} + +pub fn make_transaction_data(sender: IotaAddress) -> TransactionData { + let object = Object::immutable_with_id_for_testing(ObjectID::random_from_rng( + &mut StdRng::from_seed([0; 32]), + )); + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + builder.transfer_iota(dbg_addr(2), None); + builder.finish() + }; + TransactionData::new_programmable( + sender, + vec![object.compute_object_reference()], + pt, + TEST_ONLY_GAS_UNIT_FOR_TRANSFER, // gas price is 1 + 1, + ) +} + +/// Make a user signed transaction with the given sender and its keypair. This +/// is not verified or signed by authority. +pub fn make_transaction(sender: IotaAddress, kp: &IotaKeyPair) -> Transaction { + let data = make_transaction_data(sender); + Transaction::from_data_and_signer(data, vec![kp]) +} + +// This is used to sign transaction with signer using default Intent. +pub fn to_sender_signed_transaction( + data: TransactionData, + signer: &dyn Signer, +) -> Transaction { + to_sender_signed_transaction_with_multi_signers(data, vec![signer]) +} + +pub fn to_sender_signed_transaction_with_multi_signers( + data: TransactionData, + signers: Vec<&dyn Signer>, +) -> Transaction { + Transaction::from_data_and_signer(data, signers) +} + +pub fn mock_certified_checkpoint<'a>( + keys: impl Iterator, + committee: Committee, + seq_num: u64, +) -> CertifiedCheckpointSummary { + let contents = + CheckpointContents::new_with_digests_only_for_tests([ExecutionDigests::random()]); + + let summary = CheckpointSummary::new( + committee.epoch, + seq_num, + 0, + &contents, + None, + GasCostSummary::default(), + None, + 0, + ); + + let sign_infos: Vec<_> = keys + .map(|k| { + let name = k.public().into(); + + SignedCheckpointSummary::sign(committee.epoch, &summary, k, name) + }) + .collect(); + + CertifiedCheckpointSummary::new(summary, sign_infos, &committee).expect("Cert is OK") +} + +mod zk_login { + use fastcrypto_zkp::bn254::zk_login::ZkLoginInputs; + use shared_crypto::intent::PersonalMessage; + + use super::*; + use crate::{crypto::PublicKey, zk_login_util::get_zklogin_inputs}; + pub static DEFAULT_ADDRESS_SEED: &str = + "20794788559620669596206457022966176986688727876128223628113916380927502737911"; + pub static SHORT_ADDRESS_SEED: &str = + "380704556853533152350240698167704405529973457670972223618755249929828551006"; + + pub fn load_test_vectors(path: &str) -> Vec<(IotaKeyPair, PublicKey, ZkLoginInputs)> { + // read in test files that has a list of matching zklogin_inputs and its + // ephemeral private keys. + let file = std::fs::File::open(path).expect("Unable to open file"); + + let test_datum: Vec = serde_json::from_reader(file).unwrap(); + let mut res = vec![]; + for test in test_datum { + let kp = IotaKeyPair::decode(&test.kp).unwrap(); + let inputs = + ZkLoginInputs::from_json(&test.zklogin_inputs, &test.address_seed).unwrap(); + let pk_zklogin = PublicKey::from_zklogin_inputs(&inputs).unwrap(); + res.push((kp, pk_zklogin, inputs)); + } + res + } + + pub fn get_zklogin_user_address() -> IotaAddress { + thread_local! { + static USER_ADDRESS: IotaAddress = { + // Derive user address manually: Blake2b_256 hash of [zklogin_flag || iss_bytes_length || iss_bytes || address seed in bytes]) + let mut hasher = DefaultHash::default(); + hasher.update([SignatureScheme::ZkLoginAuthenticator.flag()]); + let inputs = get_zklogin_inputs(); + let iss_bytes = inputs.get_iss().as_bytes(); + hasher.update([iss_bytes.len() as u8]); + hasher.update(iss_bytes); + hasher.update(inputs.get_address_seed().unpadded()); + IotaAddress::from_bytes(hasher.finalize().digest).unwrap() + }; + } + USER_ADDRESS.with(|a| *a) + } + + fn get_zklogin_user_key() -> IotaKeyPair { + IotaKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))) + } + + fn get_inputs_with_bad_address_seed() -> ZkLoginInputs { + thread_local! { + static ZKLOGIN_INPUTS: ZkLoginInputs = ZkLoginInputs::from_json("{\"proofPoints\":{\"a\":[\"17276311605393076686048412951904952585208929623427027497902331765285829154985\",\"2195957390349729412627479867125563520760023859523358729791332629632025124364\",\"1\"],\"b\":[[\"10285059021604767951039627893758482248204478992077021270802057708215366770814\",\"20086937595807139308592304218494658586282197458549968652049579308384943311509\"],[\"7481123765095657256931104563876569626157448050870256177668773471703520958615\",\"11912752790863530118410797223176516777328266521602785233083571774104055633375\"],[\"1\",\"0\"]],\"c\":[\"15742763887654796666500488588763616323599882100448686869458326409877111249163\",\"6112916537574993759490787691149241262893771114597679488354854987586060572876\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", SHORT_ADDRESS_SEED).unwrap(); } + ZKLOGIN_INPUTS.with(|a| a.clone()) + } + + pub fn get_legacy_zklogin_user_address() -> IotaAddress { + thread_local! { + static USER_ADDRESS: IotaAddress = { + let inputs = get_inputs_with_bad_address_seed(); + IotaAddress::from(&PublicKey::from_zklogin_inputs(&inputs).unwrap()) + }; + } + USER_ADDRESS.with(|a| *a) + } + + pub fn sign_zklogin_personal_msg(data: PersonalMessage) -> (IotaAddress, GenericSignature) { + let inputs = get_zklogin_inputs(); + let msg = IntentMessage::new(Intent::personal_message(), data); + let s = Signature::new_secure(&msg, &get_zklogin_user_key()); + let authenticator = + GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new(inputs, 10, s)); + let address = get_zklogin_user_address(); + (address, authenticator) + } + + pub fn sign_zklogin_tx_with_default_proof( + data: TransactionData, + legacy: bool, + ) -> (IotaAddress, Transaction, GenericSignature) { + let inputs = if legacy { + get_inputs_with_bad_address_seed() + } else { + get_zklogin_inputs() + }; + + sign_zklogin_tx(&get_zklogin_user_key(), inputs, data) + } + + pub fn sign_zklogin_tx( + user_key: &IotaKeyPair, + proof: ZkLoginInputs, + data: TransactionData, + ) -> (IotaAddress, Transaction, GenericSignature) { + let tx = Transaction::from_data_and_signer(data.clone(), vec![user_key]); + + let s = match tx.inner().tx_signatures.first().unwrap() { + GenericSignature::Signature(s) => s, + _ => panic!("Expected a signature"), + }; + + // Construct the authenticator with all user submitted components. + let authenticator = + GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new(proof, 10, s.clone())); + + let tx = Transaction::new(SenderSignedData::new( + tx.transaction_data().clone(), + Intent::iota_transaction(), + vec![authenticator.clone()], + )); + (data.execution_parts().1, tx, authenticator) + } + + pub fn make_zklogin_tx( + address: IotaAddress, + legacy: bool, + ) -> (IotaAddress, Transaction, GenericSignature) { + let data = make_transaction_data(address); + sign_zklogin_tx_with_default_proof(data, legacy) + } + + pub fn keys() -> Vec { + let mut seed = StdRng::from_seed([0; 32]); + let kp1: IotaKeyPair = IotaKeyPair::Ed25519(get_key_pair_from_rng(&mut seed).1); + let kp2: IotaKeyPair = IotaKeyPair::Secp256k1(get_key_pair_from_rng(&mut seed).1); + let kp3: IotaKeyPair = IotaKeyPair::Secp256r1(get_key_pair_from_rng(&mut seed).1); + vec![kp1, kp2, kp3] + } + + pub fn make_upgraded_multisig_tx() -> Transaction { + let keys = keys(); + let pk1 = &keys[0].public(); + let pk2 = &keys[1].public(); + let pk3 = &keys[2].public(); + + let multisig_pk = MultiSigPublicKey::new( + vec![pk1.clone(), pk2.clone(), pk3.clone()], + vec![1, 1, 1], + 2, + ) + .unwrap(); + let addr = IotaAddress::from(&multisig_pk); + let tx = make_transaction(addr, &keys[0]); + + let msg = IntentMessage::new(Intent::iota_transaction(), tx.transaction_data().clone()); + let sig1 = Signature::new_secure(&msg, &keys[0]).into(); + let sig2 = Signature::new_secure(&msg, &keys[1]).into(); + + // Any 2 of 3 signatures verifies ok. + let multi_sig1 = MultiSig::combine(vec![sig1, sig2], multisig_pk).unwrap(); + Transaction::new(SenderSignedData::new( + tx.transaction_data().clone(), + Intent::iota_transaction(), + vec![GenericSignature::MultiSig(multi_sig1)], + )) + } +} +pub use zk_login::*; diff --git a/crates/sui-types/src/unit_tests/zk_login_authenticator_test.rs b/crates/iota-types/src/unit_tests/zk_login_authenticator_test.rs similarity index 93% rename from crates/sui-types/src/unit_tests/zk_login_authenticator_test.rs rename to crates/iota-types/src/unit_tests/zk_login_authenticator_test.rs index 71d3089d4ee..f3cc0429863 100644 --- a/crates/sui-types/src/unit_tests/zk_login_authenticator_test.rs +++ b/crates/iota-types/src/unit_tests/zk_login_authenticator_test.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::str::FromStr; @@ -15,7 +16,7 @@ use im::hashmap::HashMap as ImHashMap; use shared_crypto::intent::{Intent, IntentMessage, PersonalMessage}; use crate::{ - base_types::SuiAddress, + base_types::IotaAddress, crypto::{PublicKey, SignatureScheme, ZkLoginPublicIdentifier}, signature::{AuthenticatorTrait, GenericSignature, VerifyParams}, utils::{ @@ -36,7 +37,7 @@ fn test_serde_zk_login_signature() { let deserialized = GenericSignature::from_bytes(serialized).unwrap(); assert_eq!(deserialized, authenticator); - let addr: SuiAddress = (&authenticator).try_into().unwrap(); + let addr: IotaAddress = (&authenticator).try_into().unwrap(); assert_eq!(addr, user_address); } @@ -65,8 +66,8 @@ fn test_serde_zk_public_identifier() { let deserialized: PublicKey = bcs::from_bytes(&serialized).unwrap(); assert_eq!(deserialized, pk1); assert_eq!( - SuiAddress::try_from_unpadded(&modified_inputs).unwrap(), - SuiAddress::from(&pk1) + IotaAddress::try_from_unpadded(&modified_inputs).unwrap(), + IotaAddress::from(&pk1) ); let pk2 = PublicKey::ZkLogin( @@ -84,8 +85,8 @@ fn test_serde_zk_public_identifier() { let deserialized2: PublicKey = bcs::from_bytes(&serialized2).unwrap(); assert_eq!(deserialized2, pk2); assert_eq!( - SuiAddress::try_from_padded(&modified_inputs).unwrap(), - SuiAddress::from(&pk2) + IotaAddress::try_from_padded(&modified_inputs).unwrap(), + IotaAddress::from(&pk2) ); assert_eq!(serialized.len() + 1, serialized2.len()); diff --git a/crates/sui-types/src/unit_tests/zklogin_test_vectors.json b/crates/iota-types/src/unit_tests/zklogin_test_vectors.json similarity index 93% rename from crates/sui-types/src/unit_tests/zklogin_test_vectors.json rename to crates/iota-types/src/unit_tests/zklogin_test_vectors.json index ab3fe1e260a..b8dd295b31a 100644 --- a/crates/sui-types/src/unit_tests/zklogin_test_vectors.json +++ b/crates/iota-types/src/unit_tests/zklogin_test_vectors.json @@ -1,77 +1,77 @@ [ { "zklogin_inputs": "{\"proofPoints\":{\"a\":[\"17318089125952421736342263717932719437717844282410187957984751939942898251250\",\"11373966645469122582074082295985388258840681618268593976697325892280915681207\",\"1\"],\"b\":[[\"5939871147348834997361720122238980177152303274311047249905942384915768690895\",\"4533568271134785278731234570361482651996740791888285864966884032717049811708\"],[\"10564387285071555469753990661410840118635925466597037018058770041347518461368\",\"12597323547277579144698496372242615368085801313343155735511330003884767957854\"],[\"1\",\"0\"]],\"c\":[\"15791589472556826263231644728873337629015269984699404073623603352537678813171\",\"4547866499248881449676161158024748060485373250029423904113017422539037162527\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", - "kp": "suiprivkey1qplrnsltlrzxj3rn5syd6e863xs0227u4rayja6lz0exg623wftxjx4mql0", + "kp": "iotaprivkey1qplrnsltlrzxj3rn5syd6e863xs0227u4rayja6lz0exg623wftxjx4mql0", "pk_bigint": "84029355920633174015103288781128426107680789454168570548782290541079926444544", "salt": "100681567828351849884072155819400689117", "address_seed": "20794788559620669596206457022966176986688727876128223628113916380927502737911" }, { "zklogin_inputs": "{\"proofPoints\":{\"a\":[\"2557188010312611627171871816260238532309920510408732193456156090279866747728\",\"19071990941441318350711693802255556881405833839657840819058116822481115301678\",\"1\"],\"b\":[[\"135230770152349711361478655152288995176559604356405117885164129359471890574\",\"7216898009175721143474942227108999120632545700438440510233575843810308715248\"],[\"13253503214497870514695718691991905909426624538921072690977377011920360793667\",\"9020530007799152621750172565457249844990381864119377955672172301732296026267\"],[\"1\",\"0\"]],\"c\":[\"873909373264079078688783673576894039693316815418733093168579354008866728804\",\"17533051555163888509441575111667473521314561492884091535743445342304799397998\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", - "kp": "suiprivkey1qzdlfxn2qa2lj5uprl8pyhexs02sg2wrhdy7qaq50cqgnffw4c2477kg9h3", + "kp": "iotaprivkey1qzdlfxn2qa2lj5uprl8pyhexs02sg2wrhdy7qaq50cqgnffw4c2477kg9h3", "pk_bigint": "84029355920633174015103288781128426107680789454168570548782290541079926444544", "salt": "273433093298713110279184621508435880823", "address_seed": "2455937816256448139232531453880118833510874847675649348355284726183344259587" }, { "zklogin_inputs": "{\"proofPoints\":{\"a\":[\"13753283859961640774557329566454596327364163271715818531426251933596506842705\",\"13570333719083566710849312719994093537853591700959384915502628471776153024390\",\"1\"],\"b\":[[\"7580924432809543210638123045367379735390484041802113618913314880726181062182\",\"15118473676605122618683472895945751181477946234747527796751092678966402106835\"],[\"20520238577736567405837286696135957487356130871054373418345571610797672510109\",\"7195976176520822779868898810555875653051897176783287542643940001838475948976\"],[\"1\",\"0\"]],\"c\":[\"3227538374438197958481978448994417711717421215390429790187037112321809703290\",\"8962838480920136786000381383695133007785364808079905115840852441109751024006\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", - "kp": "suiprivkey1qqesr6xhua2dkt840v9yefely578q5ad90znnpmhhgpekfvwtxke6ef2xyg", + "kp": "iotaprivkey1qqesr6xhua2dkt840v9yefely578q5ad90znnpmhhgpekfvwtxke6ef2xyg", "pk_bigint": "63474334245264100054858690294269280156015492289955642868240277397884359034564", "salt": "35726441742604318121804114019251029659", "address_seed": "14279110547995066469842535622712920033888068863801582527741702330179989485471" }, { "zklogin_inputs": "{\"proofPoints\":{\"a\":[\"1936955650306562115660529540312062453885389757337962709056179590378186149122\",\"12431236161844987315223852479137191348678562329481778086250472566359123925254\",\"1\"],\"b\":[[\"16616419247424665542696807692385552452456989005063847239766452401225888797977\",\"21707234463633444702549353351284091430572822448026696847789131548228161139007\"],[\"1312492104641834344727915515468201155226829358368350262605729554453598739212\",\"10600616904917943964317558925919917941944641899145137735588075420744485684001\"],[\"1\",\"0\"]],\"c\":[\"8246655356740019051648512518365995533363585024363578489787745527401315248089\",\"4373978063527264940581683285413159655503973204310335072709540248274119838417\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", - "kp": "suiprivkey1qprzkcs823gcrk7n4hy8pzhntdxakpqk32qwjg9f2wyc3myj78egvtw3ecr", + "kp": "iotaprivkey1qprzkcs823gcrk7n4hy8pzhntdxakpqk32qwjg9f2wyc3myj78egvtw3ecr", "pk_bigint": "75812421556494218383181193737102779368268748635728793167976883795325330616458", "salt": "258978740938576095189220495277050466928", "address_seed": "17414400377073052989190340696276318681834060934243166229739329847440687026723" }, { "zklogin_inputs": "{\"proofPoints\":{\"a\":[\"9939571087857238232481231159691695350703616819167643588232315487281633078702\",\"1147126757542310655119619840196454156414404631934346898343818853730007639255\",\"1\"],\"b\":[[\"12771727443322561601836428328097365956253351286093566235390596712012822306431\",\"18806682339418188017840841662924722175828838986054068990164812684844211919496\"],[\"19173484831857295710608381505177716676973587497587973777215306370301376467074\",\"15649923555627440575541391691382175186543437583942858555753858003884248236016\"],[\"1\",\"0\"]],\"c\":[\"18432178381619698185449245841916593593904874917800615571273842987217352452231\",\"11753404193599542517445426855439582371270562958323156494951162119703927847649\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", - "kp": "suiprivkey1qzr9qgyzg7zxal66r33weu52cenpu25emdzgas8vg447dc4he2r9jczetul", + "kp": "iotaprivkey1qzr9qgyzg7zxal66r33weu52cenpu25emdzgas8vg447dc4he2r9jczetul", "pk_bigint": "63229411998646057802711528553531152030949495808851454701083157966618591060088", "salt": "123892833446846900471592038424790840333", "address_seed": "11379134415746370964846456156600618932535275647905062325854318575449293442468" }, { "zklogin_inputs": "{\"proofPoints\":{\"a\":[\"3423466057567554834513970456333172580110990485928208291710699608920967821561\",\"19922461738665279881223646209611709967087900059278763683415636548990192608234\",\"1\"],\"b\":[[\"17450808190343225096310070667043991260397466308181134972663204441287464061776\",\"21496194594743538128764925300253991828155956693197926952040804037020927419911\"],[\"13763797588072081830752563518362461194014063526664404024839408047653359641298\",\"4678215427750220517403879251115482261953079259261122498730849510125999185865\"],[\"1\",\"0\"]],\"c\":[\"15921612372962498250711738213023660461846862690411471005369751331275546751867\",\"18390152753918190363311890828749937929918312710978423127994370773769304802248\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", - "kp": "suiprivkey1qz32jzsz6fv5lsnnw362skxfjez3ln7j3qnx45jwejnxul6qf4uu5vs7zec", + "kp": "iotaprivkey1qz32jzsz6fv5lsnnw362skxfjez3ln7j3qnx45jwejnxul6qf4uu5vs7zec", "pk_bigint": "12442541491243456394568748919748109207570536222519970981342385143015026586240", "salt": "8598084354949595080471752834901686378", "address_seed": "1710186149082035644047167754597764206700375358730028910087862142495364074846" }, { "zklogin_inputs": "{\"proofPoints\":{\"a\":[\"16257468170714484278047263654399511379414686760659131625040251970796211237971\",\"1009861250549923555335964613981708425763495543931476036631048268730173517977\",\"1\"],\"b\":[[\"4094855041501525829795666897512336625575007656712459953242110458489718202834\",\"6695963309761711108688588696835590514566688255424212900759054359699737942809\"],[\"21083204930599146752957144516134646066931487334987127442913526757390215275855\",\"18543218052567528155011567494399892285753498534966033826564002694116806692146\"],[\"1\",\"0\"]],\"c\":[\"4480308314527051169290724600561132671954163099129754427189583508500857288491\",\"6899230160849605542578624368195585187162611203923968363379004819331597130041\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", - "kp": "suiprivkey1qpeash2egkjp9mwn7ley0ep0nxah82r87zwuhv5g5ea52q0stl0xwu4l68u", + "kp": "iotaprivkey1qpeash2egkjp9mwn7ley0ep0nxah82r87zwuhv5g5ea52q0stl0xwu4l68u", "pk_bigint": "42021220992881235617518907891999256116760062426860285619488448141933291757142", "salt": "193889418029142074272893012308701903628", "address_seed": "8728191524047743150997179699567274557916183857756309640198949334608375300926" }, { "zklogin_inputs": "{\"proofPoints\":{\"a\":[\"4109393700462732146450976145230430106879095877160029270438013267669580513934\",\"11443088837921951872335447731198077118046465143399980579249543814119394199389\",\"1\"],\"b\":[[\"16540065768731131201841683874068414490072530802995503621906726100175848855641\",\"15585082908357765791153607042035609449648175748716508937723304525308200724582\"],[\"10204833369528242678709288226749797718500698181180114851401440095192514121271\",\"857110519006036105436837120291349291424152305235216600859613049592153280160\"],[\"1\",\"0\"]],\"c\":[\"3453533589001131527965835312324587495509230689790177746818975285132392613485\",\"6744550822270535731404317306416116584847404481282382248919943126713466444180\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", - "kp": "suiprivkey1qqzr706m3e47e7v6r04l2ls9hpnkcpu4xnckl7sag53hl0ctz9c37lp6zam", + "kp": "iotaprivkey1qqzr706m3e47e7v6r04l2ls9hpnkcpu4xnckl7sag53hl0ctz9c37lp6zam", "pk_bigint": "42947354132844511824548458626229538117632327318196333606282948128817007471625", "salt": "147447228906687027005055754749842312659", "address_seed": "9982176996914865538290787277132740258459678879068649454064350102260597447290" }, { "zklogin_inputs": "{\"proofPoints\":{\"a\":[\"13137745360387126697107295178423911919607017346384000705858558071919971856079\",\"17337591742915315431951622444533488262548314793231396042506339296617588098577\",\"1\"],\"b\":[[\"14960418449692927012175685462283701732459064801393971688109664012124546524146\",\"10609812751230610233150003980777473915844941695941239755973524073497339273781\"],[\"2163621414368946754154786382307855750340437455735051208909334137981847034162\",\"15406864054196108397352334056140173473389346908413720267359110317028255723450\"],[\"1\",\"0\"]],\"c\":[\"2569816316217411433822976513037390759586619970173628788163715174579626608334\",\"18827557069808144978000649627254928486417399255758930091958193753030863438000\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", - "kp": "suiprivkey1qrmf9ztcshqvkg9runx3q6stzk7rvpu579l8x2vfpxc8nzrna36yza5xtet", + "kp": "iotaprivkey1qrmf9ztcshqvkg9runx3q6stzk7rvpu579l8x2vfpxc8nzrna36yza5xtet", "pk_bigint": "94211974007060318934867804554730986875975286778311414289350981769140084027695", "salt": "37989946093984487835448994355889757534", "address_seed": "18436212806185397433828993667029161217272927472922043743697900376682660978903" }, { "zklogin_inputs": "{\"proofPoints\":{\"a\":[\"393921145946271101262816461433026293206859723374660111809659027471333669809\",\"1695312937250340147780678913875336063749095591960542544282767324393776222862\",\"1\"],\"b\":[[\"2863294170072012809863334307415379590748791875731295045829252375011865893575\",\"2498743744184810080485020292276692287116751867000666184474211818929583819195\"],[\"1943067262619220459383977725348224604639421814810050112636251308383191303068\",\"11316794356803297824086793198500476314017973279073364384360063559906122126940\"],[\"1\",\"0\"]],\"c\":[\"13704659347359609878617721759609758979293119096977613373526918331671454630033\",\"14885439875260337716840442832157683555027001961697261543363447283069349344930\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", - "kp": "suiprivkey1qzlhsppug8zj98lav4m2jxkgpelvfnr95q2gkjyg4dfnq5hlzmlrg72g8xu", + "kp": "iotaprivkey1qzlhsppug8zj98lav4m2jxkgpelvfnr95q2gkjyg4dfnq5hlzmlrg72g8xu", "pk_bigint": "44579885989388991318528302649555017599090746185850354233609193578820401747228", "salt": "65127547627613020270229731985492223420", "address_seed": "21287725386775029590763742383932776050723168124426723929699690606977162591926" }, { "zklogin_inputs": "{\"proofPoints\":{\"a\":[\"10016642691474022865283162321705145534150381775673039155087481161628607849909\",\"10909252848708959493886608108431850915142170758004010723889985187841362862152\",\"1\"],\"b\":[[\"13414329195774221301478607935939177888737496562286896837938350210962073410945\",\"17349250638004180430165565845446564651713111139519342588584294856118521973705\"],[\"18066073836819984435894424139180702439454893025745546869290683111266389836389\",\"15759947572614650049503526817703363388208972002656798614303272936795944316217\"],[\"1\",\"0\"]],\"c\":[\"14380402505947710990783091135425713254563137823215414391497610865467244170780\",\"18651970889641203838158463785043061606099497442337713985252406607444142428394\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", - "kp": "suiprivkey1qzcddpu04t5qrhv9r2zla9knk9l2y9gqs6777utjrayy8flagawpzcgwky5", + "kp": "iotaprivkey1qzcddpu04t5qrhv9r2zla9knk9l2y9gqs6777utjrayy8flagawpzcgwky5", "pk_bigint": "68198542324184554624513340204614501842933087504349780955169089159762849020408", "salt": "287328909036170051414348258263117716986", "address_seed": "8720107327972330093530736950184445012250616904974209434383033085448288666732" diff --git a/crates/iota-types/src/versioned.rs b/crates/iota-types/src/versioned.rs new file mode 100644 index 00000000000..95750e5514b --- /dev/null +++ b/crates/iota-types/src/versioned.rs @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use serde::{Deserialize, Serialize}; + +use crate::id::UID; + +/// Rust version of the Move iota::versioned::Versioned type. +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct Versioned { + pub id: UID, + pub version: u64, +} diff --git a/crates/sui-types/src/zk_login_authenticator.rs b/crates/iota-types/src/zk_login_authenticator.rs similarity index 92% rename from crates/sui-types/src/zk_login_authenticator.rs rename to crates/iota-types/src/zk_login_authenticator.rs index 982a30bf697..eae5e5842dc 100644 --- a/crates/sui-types/src/zk_login_authenticator.rs +++ b/crates/iota-types/src/zk_login_authenticator.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::hash::{Hash, Hasher}; @@ -14,10 +15,10 @@ use serde::{Deserialize, Serialize}; use shared_crypto::intent::IntentMessage; use crate::{ - base_types::{EpochId, SuiAddress}, - crypto::{DefaultHash, PublicKey, Signature, SignatureScheme, SuiSignature}, + base_types::{EpochId, IotaAddress}, + crypto::{DefaultHash, IotaSignature, PublicKey, Signature, SignatureScheme}, digests::ZKLoginInputsDigest, - error::{SuiError, SuiResult}, + error::{IotaError, IotaResult}, signature::{AuthenticatorTrait, VerifyParams}, }; @@ -55,7 +56,7 @@ impl ZkLoginAuthenticator { } } - pub fn get_pk(&self) -> SuiResult { + pub fn get_pk(&self) -> IotaResult { PublicKey::from_zklogin_inputs(&self.inputs) } @@ -91,10 +92,10 @@ impl Hash for ZkLoginAuthenticator { } impl AuthenticatorTrait for ZkLoginAuthenticator { - fn verify_user_authenticator_epoch(&self, epoch: EpochId) -> SuiResult { + fn verify_user_authenticator_epoch(&self, epoch: EpochId) -> IotaResult { // Verify the max epoch in aux inputs is <= the current epoch of authority. if epoch > self.get_max_epoch() { - return Err(SuiError::InvalidSignature { + return Err(IotaError::InvalidSignature { error: format!("ZKLogin expired at epoch {}", self.get_max_epoch()), }); } @@ -107,20 +108,20 @@ impl AuthenticatorTrait for ZkLoginAuthenticator { fn verify_uncached_checks( &self, intent_msg: &IntentMessage, - author: SuiAddress, + author: IotaAddress, aux_verify_data: &VerifyParams, - ) -> SuiResult + ) -> IotaResult where T: Serialize, { // Always evaluate the unpadded address derivation. - if author != SuiAddress::try_from_unpadded(&self.inputs)? { + if author != IotaAddress::try_from_unpadded(&self.inputs)? { // If the verify_legacy_zklogin_address flag is set, also evaluate the padded // address derivation. if !aux_verify_data.verify_legacy_zklogin_address - || author != SuiAddress::try_from_padded(&self.inputs)? + || author != IotaAddress::try_from_padded(&self.inputs)? { - return Err(SuiError::InvalidAddress); + return Err(IotaError::InvalidAddress); } } @@ -130,13 +131,13 @@ impl AuthenticatorTrait for ZkLoginAuthenticator { if !aux_verify_data.supported_providers.is_empty() && !aux_verify_data.supported_providers.contains( &OIDCProvider::from_iss(self.inputs.get_iss()).map_err(|_| { - SuiError::InvalidSignature { + IotaError::InvalidSignature { error: "Unknown provider".to_string(), } })?, ) { - return Err(SuiError::InvalidSignature { + return Err(IotaError::InvalidSignature { error: format!("OIDC provider not supported: {}", self.inputs.get_iss()), }); } @@ -152,9 +153,9 @@ impl AuthenticatorTrait for ZkLoginAuthenticator { fn verify_claims( &self, intent_msg: &IntentMessage, - author: SuiAddress, + author: IotaAddress, aux_verify_data: &VerifyParams, - ) -> SuiResult + ) -> IotaResult where T: Serialize, { @@ -170,7 +171,7 @@ impl AuthenticatorTrait for ZkLoginAuthenticator { &aux_verify_data.oidc_provider_jwks, &aux_verify_data.zk_login_env, ) - .map_err(|e| SuiError::InvalidSignature { + .map_err(|e| IotaError::InvalidSignature { error: e.to_string(), }) } diff --git a/crates/sui-types/src/zk_login_util.rs b/crates/iota-types/src/zk_login_util.rs similarity index 97% rename from crates/sui-types/src/zk_login_util.rs rename to crates/iota-types/src/zk_login_util.rs index 49f36673e26..648ef37fdf8 100644 --- a/crates/sui-types/src/zk_login_util.rs +++ b/crates/iota-types/src/zk_login_util.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use fastcrypto_zkp::bn254::zk_login::ZkLoginInputs; diff --git a/crates/iota-types/tests/serde_tests.rs b/crates/iota-types/tests/serde_tests.rs new file mode 100644 index 00000000000..1f5c0ad4688 --- /dev/null +++ b/crates/iota-types/tests/serde_tests.rs @@ -0,0 +1,43 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::str::FromStr; + +use iota_types::{base_types::ObjectType, iota_serde::IotaStructTag, parse_iota_struct_tag}; +use move_core_types::language_storage::StructTag; +use serde::Serialize; +use serde_json::Value; +use serde_with::serde_as; + +#[test] +fn test_struct_tag_serde() { + let tag = parse_iota_struct_tag("0x7f89cdffd8968affa0b47bef91adc5314e19509080470c45bfd434cd83a766b::iotafrens::IotaFren<0x7f89cdffd8968affa0b47bef91adc5314e19509080470c45bfd434cd83a766b::capy::Capy>").unwrap(); + #[serde_as] + #[derive(Serialize)] + struct TestStructTag(#[serde_as(as = "IotaStructTag")] StructTag); + + // serialize to json should not trim the leading 0 + let Value::String(json) = serde_json::to_value(&TestStructTag(tag.clone())).unwrap() else { + panic!() + }; + assert_eq!( + json, + "0x07f89cdffd8968affa0b47bef91adc5314e19509080470c45bfd434cd83a766b::iotafrens::IotaFren<0x07f89cdffd8968affa0b47bef91adc5314e19509080470c45bfd434cd83a766b::capy::Capy>" + ); + + let tag2 = parse_iota_struct_tag(&json).unwrap(); + assert_eq!(tag, tag2); +} + +#[test] +fn test_object_type_to_string() { + let object_type = ObjectType::from_str( + "0x1a1aa18691be519899bf5187f5ce80af629407dd4f68d4175b99f4dc09497c1::custodian::AccountCap", + ) + .unwrap(); + assert_eq!( + object_type.to_string(), + "0x01a1aa18691be519899bf5187f5ce80af629407dd4f68d4175b99f4dc09497c1::custodian::AccountCap" + ); +} diff --git a/crates/sui-types/tests/staged/exec_failure_status.yaml b/crates/iota-types/tests/staged/exec_failure_status.yaml similarity index 92% rename from crates/sui-types/tests/staged/exec_failure_status.yaml rename to crates/iota-types/tests/staged/exec_failure_status.yaml index 5638031da72..fc1c7a533e4 100644 --- a/crates/sui-types/tests/staged/exec_failure_status.yaml +++ b/crates/iota-types/tests/staged/exec_failure_status.yaml @@ -9,7 +9,7 @@ 7: InsufficientCoinBalance 8: CoinBalanceOverflow 9: PublishErrorNonZeroAddress -10: SuiMoveVerificationError +10: IotaMoveVerificationError 11: MovePrimitiveRuntimeError 12: MoveAbort 13: VMVerificationOrDeserializationError @@ -29,6 +29,6 @@ 27: PackageUpgradeError 28: WrittenObjectsTooLarge 29: CertificateDenied -30: SuiMoveVerificationTimedout +30: IotaMoveVerificationTimedout 31: SharedObjectOperationNotAllowed 32: InputObjectDeleted diff --git a/crates/iota-upgrade-compatibility-transactional-tests/Cargo.toml b/crates/iota-upgrade-compatibility-transactional-tests/Cargo.toml new file mode 100644 index 00000000000..bb604613d84 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "iota-upgrade-compatibility-transactional-tests" +version = "0.1.0" +authors = ["Mysten Labs "] +description = "Transactional tests for package upgrade compatibility checking" +license = "Apache-2.0" +publish = false +edition = "2021" + +[dev-dependencies] +anyhow.workspace = true +datatest-stable.workspace = true +insta.workspace = true +move-compiler.workspace = true +move-package.workspace = true +move-binary-format.workspace = true +move-command-line-common.workspace = true +iota-move-build.workspace = true + +[[test]] +name = "tests" +harness = false + +[dependencies] diff --git a/crates/iota-upgrade-compatibility-transactional-tests/src/lib.rs b/crates/iota-upgrade-compatibility-transactional-tests/src/lib.rs new file mode 100644 index 00000000000..7de55296af9 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/src/lib.rs @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#![forbid(unsafe_code)] + +// Empty src/lib.rs to get rusty-tags working. diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_name_change/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_name_change/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/constant_name_change/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/constant_name_change/about.package diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_name_change/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_name_change/base/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/constant_name_change/base/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/constant_name_change/base/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_name_change/base/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_name_change/base/sources/base.move new file mode 100644 index 00000000000..e7b7fc24b3d --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_name_change/base/sources/base.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + + const A: u64 = 0; + + struct X { + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { A } + fun private_fun(): u64 { A } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_name_change/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_name_change/upgraded/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/constant_name_change/upgraded/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/constant_name_change/upgraded/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_name_change/upgraded/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_name_change/upgraded/sources/base.move new file mode 100644 index 00000000000..6d07a69af20 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_name_change/upgraded/sources/base.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + + const B: u64 = 0; + + struct X { + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { B } + fun private_fun(): u64 { B } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_value_changed/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_value_changed/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/constant_value_changed/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/constant_value_changed/about.package diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_value_changed/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_value_changed/base/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/constant_value_changed/base/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/constant_value_changed/base/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_value_changed/base/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_value_changed/base/sources/base.move new file mode 100644 index 00000000000..e7b7fc24b3d --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_value_changed/base/sources/base.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + + const A: u64 = 0; + + struct X { + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { A } + fun private_fun(): u64 { A } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_value_changed/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_value_changed/upgraded/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/constant_value_changed/upgraded/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/constant_value_changed/upgraded/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_value_changed/upgraded/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_value_changed/upgraded/sources/base.move new file mode 100644 index 00000000000..ef7ccfd24bd --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/constant_value_changed/upgraded/sources/base.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + + const A: u64 = 1; + + struct X { + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { A } + fun private_fun(): u64 { A } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/about.package diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/sources/base.move new file mode 100644 index 00000000000..13823ca646e --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/sources/base.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + friend base::friend_module; + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } + public(friend) entry fun friend_fun(): u64 { 0 } +} diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/sources/friend.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/sources/friend.move new file mode 100644 index 00000000000..63c29a7a4aa --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/sources/friend.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::friend_module { + public fun call_friend(): u64 { base::base_module::friend_fun() } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/sources/base.move new file mode 100644 index 00000000000..bf6dc6c7c6f --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/sources/base.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + friend base::friend_module; + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } + public(friend) fun friend_fun(): u64 { 0 } +} diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/sources/friend.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/sources/friend.move new file mode 100644 index 00000000000..63c29a7a4aa --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/sources/friend.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::friend_module { + public fun call_friend(): u64 { base::base_module::friend_fun() } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/about.package diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/sources/base.move new file mode 100644 index 00000000000..bf6dc6c7c6f --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/sources/base.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + friend base::friend_module; + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } + public(friend) fun friend_fun(): u64 { 0 } +} diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/sources/friend.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/sources/friend.move new file mode 100644 index 00000000000..63c29a7a4aa --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/sources/friend.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::friend_module { + public fun call_friend(): u64 { base::base_module::friend_fun() } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/sources/base.move new file mode 100644 index 00000000000..ce8c52aed0b --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/sources/base.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + friend base::friend_module; + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } + public(friend) fun friend_fun(x: u64): u64 { x } +} diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/sources/friend.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/sources/friend.move new file mode 100644 index 00000000000..812cbfd7015 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/sources/friend.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::friend_module { + public fun call_friend(): u64 { base::base_module::friend_fun(0) } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/about.package diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/base/Move.toml new file mode 100644 index 00000000000..997a4d798b3 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/base/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "base" +version = "0.0.1" + +[dependencies] +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +base = "0x0" +std = "0x1" diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/base/sources/ascii.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/base/sources/ascii.move new file mode 100644 index 00000000000..cf73382e94a --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/base/sources/ascii.move @@ -0,0 +1,110 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// The `ASCII` module defines basic string and char newtypes in Move that verify +/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. +module base::ascii { + use std::vector; + use std::option::{Self, Option}; + + /// An invalid ASCII character was encountered when creating an ASCII string. + const EINVALID_ASCII_CHARACTER: u64 = 0x10000; + + /// The `String` struct holds a vector of bytes that all represent + /// valid ASCII characters. Note that these ASCII characters may not all + /// be printable. To determine if a `String` contains only "printable" + /// characters you should use the `all_characters_printable` predicate + /// defined in this module. + struct String has copy, drop, store { + bytes: vector, + } + + /// An ASCII character. + struct Char has copy, drop, store { + byte: u8, + } + + /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. + public fun char(byte: u8): Char { + assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); + Char { byte } + } + + /// Convert a vector of bytes `bytes` into an `String`. Aborts if + /// `bytes` contains non-ASCII characters. + public fun string(bytes: vector): String { + let x = try_string(bytes); + assert!( + option::is_some(&x), + EINVALID_ASCII_CHARACTER + ); + option::destroy_some(x) + } + /// Convert a vector of bytes `bytes` into an `String`. Returns + /// `Some()` if the `bytes` contains all valid ASCII + /// characters. Otherwise returns `None`. + public fun try_string(bytes: vector): Option { + let len = vector::length(&bytes); + let i = 0; + while (i < len) { + let possible_byte = *vector::borrow(&bytes, i); + if (!is_valid_char(possible_byte)) return option::none(); + i = i + 1; + }; + option::some(String { bytes }) + } + + /// Returns `true` if all characters in `string` are printable characters + /// Returns `false` otherwise. Not all `String`s are printable strings. + public fun all_characters_printable(string: &String): bool { + let len = vector::length(&string.bytes); + let i = 0; + while (i < len) { + let byte = *vector::borrow(&string.bytes, i); + if (!is_printable_char(byte)) return false; + i = i + 1; + }; + true + } + + public fun push_char(string: &mut String, char: Char) { + vector::push_back(&mut string.bytes, char.byte); + } + + public fun pop_char(string: &mut String): Char { + Char { byte: vector::pop_back(&mut string.bytes) } + } + + public fun length(string: &String): u64 { + vector::length(as_bytes(string)) + } + + /// Get the inner bytes of the `string` as a reference + public fun as_bytes(string: &String): &vector { + &string.bytes + } + + /// Unpack the `string` to get its backing bytes + public fun into_bytes(string: String): vector { + let String { bytes } = string; + bytes + } + + /// Unpack the `char` into its underlying byte. + public fun byte(char: Char): u8 { + let Char { byte } = char; + byte + } + + /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. + public fun is_valid_char(b: u8): bool { + b <= 0x7F + } + + /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. + public fun is_printable_char(byte: u8): bool { + byte >= 0x20 && // Disallow metacharacters + byte <= 0x7E // Don't allow DEL metacharacter + } +} diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/upgraded/Move.toml new file mode 100644 index 00000000000..997a4d798b3 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/upgraded/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "base" +version = "0.0.1" + +[dependencies] +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +base = "0x0" +std = "0x1" diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/upgraded/sources/ascii.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/upgraded/sources/ascii.move new file mode 100644 index 00000000000..21a7b8461a5 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/upgraded/sources/ascii.move @@ -0,0 +1,111 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// The `ASCII` module defines basic string and char newtypes in Move that verify +/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. +module base::ascii { + use std::option::{Option, Self}; + use std::vector; + + /// An ASCII character. + struct Char has copy, drop, store { + byte: u8, + } + + /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. + public fun char(byte: u8): Char { + assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); + Char { byte } + } + + /// Returns `true` if all characters in `string` are printable characters + /// Returns `false` otherwise. Not all `String`s are printable strings. + public fun all_characters_printable(string: &String): bool { + let len = vector::length(&string.bytes); + let i = 0; + while (i < len) { + let byte = *vector::borrow(&string.bytes, i); + if (!is_printable_char(byte)) return false; + i = i + 1; + }; + true + } + + /// Convert a vector of bytes `bytes` into an `String`. Returns + /// `Some()` if the `bytes` contains all valid ASCII + /// characters. Otherwise returns `None`. + public fun try_string(bytes: vector): Option { + let len = vector::length(&bytes); + let i = 0; + while (i < len) { + let possible_byte = *vector::borrow(&bytes, i); + if (!is_valid_char(possible_byte)) return option::none(); + i = i + 1; + }; + option::some(String { bytes }) + } + + public fun push_char(string: &mut String, char: Char) { + vector::push_back(&mut string.bytes, char.byte); + } + + /// The `String` struct holds a vector of bytes that all represent + /// valid ASCII characters. Note that these ASCII characters may not all + /// be printable. To determine if a `String` contains only "printable" + /// characters you should use the `all_characters_printable` predicate + /// defined in this module. + struct String has copy, drop, store { + bytes: vector, + } + + /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. + public fun is_printable_char(byte: u8): bool { + byte >= 0x20 && // Disallow metacharacters + byte <= 0x7E // Don't allow DEL metacharacter + } + + public fun pop_char(string: &mut String): Char { + Char { byte: vector::pop_back(&mut string.bytes) } + } + + /// Convert a vector of bytes `bytes` into an `String`. Aborts if + /// `bytes` contains non-ASCII characters. + public fun string(bytes: vector): String { + let x = try_string(bytes); + assert!( + option::is_some(&x), + EINVALID_ASCII_CHARACTER + ); + option::destroy_some(x) + } + + public fun length(string: &String): u64 { + vector::length(as_bytes(string)) + } + + /// Get the inner bytes of the `string` as a reference + public fun as_bytes(string: &String): &vector { + &string.bytes + } + + /// Unpack the `string` to get its backing bytes + public fun into_bytes(string: String): vector { + let String { bytes } = string; + bytes + } + + /// Unpack the `char` into its underlying byte. + public fun byte(char: Char): u8 { + let Char { byte } = char; + byte + } + + /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. + public fun is_valid_char(b: u8): bool { + b <= 0x7F + } + + /// An invalid ASCII character was encountered when creating an ASCII string. + const EINVALID_ASCII_CHARACTER: u64 = 0x10000; +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/about.package diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/base/Move.toml new file mode 100644 index 00000000000..997a4d798b3 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/base/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "base" +version = "0.0.1" + +[dependencies] +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +base = "0x0" +std = "0x1" diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/base/sources/ascii.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/base/sources/ascii.move new file mode 100644 index 00000000000..adf42f1bd10 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/base/sources/ascii.move @@ -0,0 +1,111 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// The `ASCII` module defines basic string and char newtypes in Move that verify +/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. +module base::ascii { + use std::vector; + use std::option::{Self, Option}; + + /// An invalid ASCII character was encountered when creating an ASCII string. + const EINVALID_ASCII_CHARACTER: u64 = 0x10000; + + /// The `String` struct holds a vector of bytes that all represent + /// valid ASCII characters. Note that these ASCII characters may not all + /// be printable. To determine if a `String` contains only "printable" + /// characters you should use the `all_characters_printable` predicate + /// defined in this module. + struct String has copy, drop, store { + bytes: vector, + } + + /// An ASCII character. + struct Char has copy, drop, store { + byte: u8, + } + + /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. + public fun char(byte: u8): Char { + assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); + Char { byte } + } + + /// Convert a vector of bytes `bytes` into an `String`. Aborts if + /// `bytes` contains non-ASCII characters. + public fun string(bytes: vector): String { + let x = try_string(bytes); + assert!( + option::is_some(&x), + EINVALID_ASCII_CHARACTER + ); + option::destroy_some(x) + } + + /// Convert a vector of bytes `bytes` into an `String`. Returns + /// `Some()` if the `bytes` contains all valid ASCII + /// characters. Otherwise returns `None`. + public fun try_string(bytes: vector): Option { + let len = vector::length(&bytes); + let i = 0; + while (i < len) { + let possible_byte = *vector::borrow(&bytes, i); + if (!is_valid_char(possible_byte)) return option::none(); + i = i + 1; + }; + option::some(String { bytes }) + } + + /// Returns `true` if all characters in `string` are printable characters + /// Returns `false` otherwise. Not all `String`s are printable strings. + public fun all_characters_printable(string: &String): bool { + let len = vector::length(&string.bytes); + let i = 0; + while (i < len) { + let byte = *vector::borrow(&string.bytes, i); + if (!is_printable_char(byte)) return false; + i = i + 1; + }; + true + } + + public fun push_char(string: &mut String, char: Char) { + vector::push_back(&mut string.bytes, char.byte); + } + + public fun pop_char(string: &mut String): Char { + Char { byte: vector::pop_back(&mut string.bytes) } + } + + public fun length(string: &String): u64 { + vector::length(as_bytes(string)) + } + + /// Get the inner bytes of the `string` as a reference + public fun as_bytes(string: &String): &vector { + &string.bytes + } + + /// Unpack the `string` to get its backing bytes + public fun into_bytes(string: String): vector { + let String { bytes } = string; + bytes + } + + /// Unpack the `char` into its underlying byte. + public fun byte(char: Char): u8 { + let Char { byte } = char; + byte + } + + /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. + public fun is_valid_char(b: u8): bool { + b <= 0x7F + } + + /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. + public fun is_printable_char(byte: u8): bool { + byte >= 0x20 && // Disallow metacharacters + byte <= 0x7E // Don't allow DEL metacharacter + } +} diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/upgraded/Move.toml new file mode 100644 index 00000000000..997a4d798b3 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/upgraded/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "base" +version = "0.0.1" + +[dependencies] +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +base = "0x0" +std = "0x1" diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/upgraded/sources/ascii.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/upgraded/sources/ascii.move new file mode 100644 index 00000000000..df19dd475dd --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/upgraded/sources/ascii.move @@ -0,0 +1,111 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// The `ASCII` module defines basic string and char newtypes in Move that verify +/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. +module base::ascii { + use std::option::{Option, Self}; + use std::vector; + + /// An ASCII character. + struct Char has copy, drop, store { + byte: u8, + } + + /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. + public fun char(byte: u8): Char { + assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); + Char { byte } + } + + /// Returns `true` if all characters in `string` are printable characters + /// Returns `false` otherwise. Not all `String`s are printable strings. + public fun all_characters_printable(my_string: &String): bool { // !!!! <<<<<<<< This has been renamed from "string" to "my_string" + let length = vector::length(&my_string.bytes); // !!!! <<<<<<<< This has been renamed from "len" to "length" + let i = 0; + while (i < length) { + let byte = *vector::borrow(&my_string.bytes, i); + if (!is_printable_char(byte)) return false; + i = i + 1; + }; + true + } + + /// Convert a vector of bytes `bytes` into an `String`. Returns + /// `Some()` if the `bytes` contains all valid ASCII + /// characters. Otherwise returns `None`. + public fun try_string(bytes: vector): Option { + let len = vector::length(&bytes); + let i = 0; + while (i < len) { + let possible_byte = *vector::borrow(&bytes, i); + if (!is_valid_char(possible_byte)) return option::none(); + i = i + 1; + }; + option::some(String { bytes }) + } + + public fun push_char(string: &mut String, char: Char) { + vector::push_back(&mut string.bytes, char.byte); + } + + /// The `String` struct holds a vector of bytes that all represent + /// valid ASCII characters. Note that these ASCII characters may not all + /// be printable. To determine if a `String` contains only "printable" + /// characters you should use the `all_characters_printable` predicate + /// defined in this module. + struct String has copy, drop, store { + bytes: vector, + } + + /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. + public fun is_printable_char(byte: u8): bool { + byte >= 0x20 && // Disallow metacharacters + byte <= 0x7E // Don't allow DEL metacharacter + } + + public fun pop_char(string: &mut String): Char { + Char { byte: vector::pop_back(&mut string.bytes) } + } + + /// Convert a vector of bytes `bytes` into an `String`. Aborts if + /// `bytes` contains non-ASCII characters. + public fun string(bytes: vector): String { + let x = try_string(bytes); + assert!( + option::is_some(&x), + EINVALID_ASCII_CHARACTER + ); + option::destroy_some(x) + } + + public fun length(string: &String): u64 { + vector::length(as_bytes(string)) + } + + /// Get the inner bytes of the `string` as a reference + public fun as_bytes(string: &String): &vector { + &string.bytes + } + + /// Unpack the `string` to get its backing bytes + public fun into_bytes(string: String): vector { + let String { bytes } = string; + bytes + } + + /// Unpack the `char` into its underlying byte. + public fun byte(char: Char): u8 { + let Char { byte } = char; + byte + } + + /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. + public fun is_valid_char(b: u8): bool { + b <= 0x7F + } + + /// An invalid ASCII character was encountered when creating an ASCII string. + const EINVALID_ASCII_CHARACTER: u64 = 0x10000; +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/about.package diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/base/Move.toml new file mode 100644 index 00000000000..997a4d798b3 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/base/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "base" +version = "0.0.1" + +[dependencies] +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +base = "0x0" +std = "0x1" diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/base/sources/ascii.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/base/sources/ascii.move new file mode 100644 index 00000000000..adf42f1bd10 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/base/sources/ascii.move @@ -0,0 +1,111 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// The `ASCII` module defines basic string and char newtypes in Move that verify +/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. +module base::ascii { + use std::vector; + use std::option::{Self, Option}; + + /// An invalid ASCII character was encountered when creating an ASCII string. + const EINVALID_ASCII_CHARACTER: u64 = 0x10000; + + /// The `String` struct holds a vector of bytes that all represent + /// valid ASCII characters. Note that these ASCII characters may not all + /// be printable. To determine if a `String` contains only "printable" + /// characters you should use the `all_characters_printable` predicate + /// defined in this module. + struct String has copy, drop, store { + bytes: vector, + } + + /// An ASCII character. + struct Char has copy, drop, store { + byte: u8, + } + + /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. + public fun char(byte: u8): Char { + assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); + Char { byte } + } + + /// Convert a vector of bytes `bytes` into an `String`. Aborts if + /// `bytes` contains non-ASCII characters. + public fun string(bytes: vector): String { + let x = try_string(bytes); + assert!( + option::is_some(&x), + EINVALID_ASCII_CHARACTER + ); + option::destroy_some(x) + } + + /// Convert a vector of bytes `bytes` into an `String`. Returns + /// `Some()` if the `bytes` contains all valid ASCII + /// characters. Otherwise returns `None`. + public fun try_string(bytes: vector): Option { + let len = vector::length(&bytes); + let i = 0; + while (i < len) { + let possible_byte = *vector::borrow(&bytes, i); + if (!is_valid_char(possible_byte)) return option::none(); + i = i + 1; + }; + option::some(String { bytes }) + } + + /// Returns `true` if all characters in `string` are printable characters + /// Returns `false` otherwise. Not all `String`s are printable strings. + public fun all_characters_printable(string: &String): bool { + let len = vector::length(&string.bytes); + let i = 0; + while (i < len) { + let byte = *vector::borrow(&string.bytes, i); + if (!is_printable_char(byte)) return false; + i = i + 1; + }; + true + } + + public fun push_char(string: &mut String, char: Char) { + vector::push_back(&mut string.bytes, char.byte); + } + + public fun pop_char(string: &mut String): Char { + Char { byte: vector::pop_back(&mut string.bytes) } + } + + public fun length(string: &String): u64 { + vector::length(as_bytes(string)) + } + + /// Get the inner bytes of the `string` as a reference + public fun as_bytes(string: &String): &vector { + &string.bytes + } + + /// Unpack the `string` to get its backing bytes + public fun into_bytes(string: String): vector { + let String { bytes } = string; + bytes + } + + /// Unpack the `char` into its underlying byte. + public fun byte(char: Char): u8 { + let Char { byte } = char; + byte + } + + /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. + public fun is_valid_char(b: u8): bool { + b <= 0x7F + } + + /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. + public fun is_printable_char(byte: u8): bool { + byte >= 0x20 && // Disallow metacharacters + byte <= 0x7E // Don't allow DEL metacharacter + } +} diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/upgraded/Move.toml new file mode 100644 index 00000000000..997a4d798b3 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/upgraded/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "base" +version = "0.0.1" + +[dependencies] +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +base = "0x0" +std = "0x1" diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/upgraded/sources/ascii.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/upgraded/sources/ascii.move new file mode 100644 index 00000000000..b9f1f3e2d67 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/upgraded/sources/ascii.move @@ -0,0 +1,111 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// The `ASCII` module defines basic string and char newtypes in Move that verify +/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. +module base::ascii { + use std::option::{Option, Self}; + use std::vector; + + /// An ASCII character. + struct Char has copy, drop, store { + byte: u8, + } + + /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. + public fun char(byte: u8): Char { + assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); + Char { byte } + } + + /// Returns `true` if all characters in `string` are printable characters + /// Returns `false` otherwise. Not all `String`s are printable strings. + public fun all_characters_printable(string: &String): bool { + let i = 0; + let len = vector::length(&string.bytes); + while (i < len) { + let byte = *vector::borrow(&string.bytes, i); + if (!is_printable_char(byte)) return false; + i = i + 1; + }; + true + } + + /// Convert a vector of bytes `bytes` into an `String`. Returns + /// `Some()` if the `bytes` contains all valid ASCII + /// characters. Otherwise returns `None`. + public fun try_string(bytes: vector): Option { + let i = 0; + let len = vector::length(&bytes); + while (i < len) { + let possible_byte = *vector::borrow(&bytes, i); + if (!is_valid_char(possible_byte)) return option::none(); + i = i + 1; + }; + option::some(String { bytes }) + } + + public fun push_char(string: &mut String, char: Char) { + vector::push_back(&mut string.bytes, char.byte); + } + + /// The `String` struct holds a vector of bytes that all represent + /// valid ASCII characters. Note that these ASCII characters may not all + /// be printable. To determine if a `String` contains only "printable" + /// characters you should use the `all_characters_printable` predicate + /// defined in this module. + struct String has copy, drop, store { + bytes: vector, + } + + /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. + public fun is_printable_char(byte: u8): bool { + byte >= 0x20 && // Disallow metacharacters + byte <= 0x7E // Don't allow DEL metacharacter + } + + public fun pop_char(string: &mut String): Char { + Char { byte: vector::pop_back(&mut string.bytes) } + } + + /// Convert a vector of bytes `bytes` into an `String`. Aborts if + /// `bytes` contains non-ASCII characters. + public fun string(bytes: vector): String { + let x = try_string(bytes); + assert!( + option::is_some(&x), + EINVALID_ASCII_CHARACTER + ); + option::destroy_some(x) + } + + public fun length(string: &String): u64 { + vector::length(as_bytes(string)) + } + + /// Get the inner bytes of the `string` as a reference + public fun as_bytes(string: &String): &vector { + &string.bytes + } + + /// Unpack the `string` to get its backing bytes + public fun into_bytes(string: String): vector { + let String { bytes } = string; + bytes + } + + /// Unpack the `char` into its underlying byte. + public fun byte(char: Char): u8 { + let Char { byte } = char; + byte + } + + /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. + public fun is_valid_char(b: u8): bool { + b <= 0x7F + } + + /// An invalid ASCII character was encountered when creating an ASCII string. + const EINVALID_ASCII_CHARACTER: u64 = 0x10000; +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/about.package diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/base/Move.toml new file mode 100644 index 00000000000..997a4d798b3 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/base/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "base" +version = "0.0.1" + +[dependencies] +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +base = "0x0" +std = "0x1" diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/base/sources/ascii.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/base/sources/ascii.move new file mode 100644 index 00000000000..adf42f1bd10 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/base/sources/ascii.move @@ -0,0 +1,111 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// The `ASCII` module defines basic string and char newtypes in Move that verify +/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. +module base::ascii { + use std::vector; + use std::option::{Self, Option}; + + /// An invalid ASCII character was encountered when creating an ASCII string. + const EINVALID_ASCII_CHARACTER: u64 = 0x10000; + + /// The `String` struct holds a vector of bytes that all represent + /// valid ASCII characters. Note that these ASCII characters may not all + /// be printable. To determine if a `String` contains only "printable" + /// characters you should use the `all_characters_printable` predicate + /// defined in this module. + struct String has copy, drop, store { + bytes: vector, + } + + /// An ASCII character. + struct Char has copy, drop, store { + byte: u8, + } + + /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. + public fun char(byte: u8): Char { + assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); + Char { byte } + } + + /// Convert a vector of bytes `bytes` into an `String`. Aborts if + /// `bytes` contains non-ASCII characters. + public fun string(bytes: vector): String { + let x = try_string(bytes); + assert!( + option::is_some(&x), + EINVALID_ASCII_CHARACTER + ); + option::destroy_some(x) + } + + /// Convert a vector of bytes `bytes` into an `String`. Returns + /// `Some()` if the `bytes` contains all valid ASCII + /// characters. Otherwise returns `None`. + public fun try_string(bytes: vector): Option { + let len = vector::length(&bytes); + let i = 0; + while (i < len) { + let possible_byte = *vector::borrow(&bytes, i); + if (!is_valid_char(possible_byte)) return option::none(); + i = i + 1; + }; + option::some(String { bytes }) + } + + /// Returns `true` if all characters in `string` are printable characters + /// Returns `false` otherwise. Not all `String`s are printable strings. + public fun all_characters_printable(string: &String): bool { + let len = vector::length(&string.bytes); + let i = 0; + while (i < len) { + let byte = *vector::borrow(&string.bytes, i); + if (!is_printable_char(byte)) return false; + i = i + 1; + }; + true + } + + public fun push_char(string: &mut String, char: Char) { + vector::push_back(&mut string.bytes, char.byte); + } + + public fun pop_char(string: &mut String): Char { + Char { byte: vector::pop_back(&mut string.bytes) } + } + + public fun length(string: &String): u64 { + vector::length(as_bytes(string)) + } + + /// Get the inner bytes of the `string` as a reference + public fun as_bytes(string: &String): &vector { + &string.bytes + } + + /// Unpack the `string` to get its backing bytes + public fun into_bytes(string: String): vector { + let String { bytes } = string; + bytes + } + + /// Unpack the `char` into its underlying byte. + public fun byte(char: Char): u8 { + let Char { byte } = char; + byte + } + + /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. + public fun is_valid_char(b: u8): bool { + b <= 0x7F + } + + /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. + public fun is_printable_char(byte: u8): bool { + byte >= 0x20 && // Disallow metacharacters + byte <= 0x7E // Don't allow DEL metacharacter + } +} diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/upgraded/Move.toml new file mode 100644 index 00000000000..997a4d798b3 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/upgraded/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "base" +version = "0.0.1" + +[dependencies] +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +base = "0x0" +std = "0x1" diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/upgraded/sources/ascii.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/upgraded/sources/ascii.move new file mode 100644 index 00000000000..8decf4dc058 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/upgraded/sources/ascii.move @@ -0,0 +1,113 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// The `ASCII` module defines basic string and char newtypes in Move that verify +/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. +module base::ascii { + use std::option::{Option, Self}; + use std::vector; + + /// An ASCII character. + struct Char has copy, drop, store { + byte: u8, + } + + /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. + public fun char(byte: u8): Char { + assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); + Char { byte } + } + + fun additional_function() { } + + /// Returns `true` if all characters in `string` are printable characters + /// Returns `false` otherwise. Not all `String`s are printable strings. + public fun all_characters_printable(string: &String): bool { + let len = vector::length(&string.bytes); + let i = 0; + while (i < len) { + let byte = *vector::borrow(&string.bytes, i); + if (!is_printable_char(byte)) return false; + i = i + 1; + }; + true + } + + /// Convert a vector of bytes `bytes` into an `String`. Returns + /// `Some()` if the `bytes` contains all valid ASCII + /// characters. Otherwise returns `None`. + public fun try_string(bytes: vector): Option { + let len = vector::length(&bytes); + let i = 0; + while (i < len) { + let possible_byte = *vector::borrow(&bytes, i); + if (!is_valid_char(possible_byte)) return option::none(); + i = i + 1; + }; + option::some(String { bytes }) + } + + public fun push_char(string: &mut String, char: Char) { + vector::push_back(&mut string.bytes, char.byte); + } + + /// The `String` struct holds a vector of bytes that all represent + /// valid ASCII characters. Note that these ASCII characters may not all + /// be printable. To determine if a `String` contains only "printable" + /// characters you should use the `all_characters_printable` predicate + /// defined in this module. + struct String has copy, drop, store { + bytes: vector, + } + + /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. + public fun is_printable_char(byte: u8): bool { + byte >= 0x20 && // Disallow metacharacters + byte <= 0x7E // Don't allow DEL metacharacter + } + + public fun pop_char(string: &mut String): Char { + Char { byte: vector::pop_back(&mut string.bytes) } + } + + /// Convert a vector of bytes `bytes` into an `String`. Aborts if + /// `bytes` contains non-ASCII characters. + public fun string(bytes: vector): String { + let x = try_string(bytes); + assert!( + option::is_some(&x), + EINVALID_ASCII_CHARACTER + ); + option::destroy_some(x) + } + + public fun length(string: &String): u64 { + vector::length(as_bytes(string)) + } + + /// Get the inner bytes of the `string` as a reference + public fun as_bytes(string: &String): &vector { + &string.bytes + } + + /// Unpack the `string` to get its backing bytes + public fun into_bytes(string: String): vector { + let String { bytes } = string; + bytes + } + + /// Unpack the `char` into its underlying byte. + public fun byte(char: Char): u8 { + let Char { byte } = char; + byte + } + + /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. + public fun is_valid_char(b: u8): bool { + b <= 0x7F + } + + /// An invalid ASCII character was encountered when creating an ASCII string. + const EINVALID_ASCII_CHARACTER: u64 = 0x10000; +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/about.package diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/base/Move.toml new file mode 100644 index 00000000000..997a4d798b3 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/base/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "base" +version = "0.0.1" + +[dependencies] +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +base = "0x0" +std = "0x1" diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/base/sources/ascii.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/base/sources/ascii.move new file mode 100644 index 00000000000..5bc16d89584 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/base/sources/ascii.move @@ -0,0 +1,111 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// The `ASCII` module defines basic string and char newtypes in Move that verify +/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. +module base::ascii { + use std::vector; + use std::option::{Self, Option}; + + /// An invalid ASCII character was encountered when creating an ASCII string. + const EINVALID_ASCII_CHARACTER: u64 = 0x10000; + + /// The `String` struct holds a vector of bytes that all represent + /// valid ASCII characters. Note that these ASCII characters may not all + /// be printable. To determine if a `String` contains only "printable" + /// characters you should use the `all_characters_printable` predicate + /// defined in this module. + struct String has copy, drop, store { + bytes: vector, + } + + /// An ASCII character. + struct Char has copy, drop, store { + byte: u8, + } + + /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. + public fun char(byte: u8): Char { + assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); + Char { byte } + } + + /// Convert a vector of bytes `bytes` into an `String`. Aborts if + /// `bytes` contains non-ASCII characters. + public fun string(bytes: vector): String { + let x = try_string(bytes); + assert!( + option::is_some(&x), + EINVALID_ASCII_CHARACTER + ); + option::destroy_some(x) + } + + /// Convert a vector of bytes `bytes` into an `String`. Returns + /// `Some()` if the `bytes` contains all valid ASCII + /// characters. Otherwise returns `None`. + public fun try_string(bytes: vector): Option { + let len = vector::length(&bytes); + let i = 0; + while (i < len) { + let possible_byte = *vector::borrow(&bytes, i); + if (!is_valid_char(possible_byte)) return option::none(); + i = i + 1; + }; + option::some(String { bytes }) + } + + /// Returns `true` if all characters in `string` are printable characters + /// Returns `false` otherwise. Not all `String`s are printable strings. + public fun all_characters_printable(string: &String): bool { + let len = vector::length(&string.bytes); + let i = 0; + while (i < len) { + let byte = *vector::borrow(&string.bytes, i); + if (!is_printable_char(byte)) return false; + i = i + 1; + }; + true + } + + public fun push_char(string: &mut String, char: Char) { + vector::push_back(&mut string.bytes, char.byte); + } + + public fun pop_char(string: &mut String): Char { + Char { byte: vector::pop_back(&mut string.bytes) } + } + + public fun length(string: &String): u64 { + vector::length(as_bytes(string)) + } + + /// Get the inner bytes of the `string` as a reference + public fun as_bytes(string: &String): &vector { + &string.bytes + } + + /// Unpack the `string` to get its backing bytes + public fun into_bytes(string: String): vector { + let String { bytes } = string; + bytes + } + + /// Unpack the `char` into its underlying byte. + public fun byte(char: Char): u8 { + let Char { byte } = char; + byte + } + + /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. + public fun is_valid_char(b: u8): bool { + b <= 0x7F + } + + /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. + public fun is_printable_char(byte: u8): bool { + byte >= 0x20 && // Disallow metacharacters + byte <= 0x7E // Don't allow DEL metacharacter + } +} diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/upgraded/Move.toml new file mode 100644 index 00000000000..997a4d798b3 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/upgraded/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "base" +version = "0.0.1" + +[dependencies] +MoveStdlib = { local = "../../../../iota-framework/packages/move-stdlib" } + +[addresses] +base = "0x0" +std = "0x1" diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/upgraded/sources/ascii.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/upgraded/sources/ascii.move new file mode 100644 index 00000000000..3b61bdc302e --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/upgraded/sources/ascii.move @@ -0,0 +1,111 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// The `ASCII` module defines basic string and char newtypes in Move that verify +/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. +module base::ascii { + use std::vector; + use std::option::{Self, Option}; + + /// An invalid ASCII character was encountered when creating an ASCII string. + const EINVALID_ASCII_CHARACTER: u64 = 0x10000; + + /// The `String` struct holds a vector of bytes that all represent + /// valid ASCII characters. Note that these ASCII characters may not all + /// be printable. To determine if a `String` contains only "printable" + /// characters you should use the `all_characters_printable` predicate + /// defined in this module. + struct String has copy, drop, store { + bytes: vector, + } + + /// An ASCII character. + struct Char has copy, drop, store { + byte: u8, + } + + /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. + public fun char(byte: u8): Char { + assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); + Char { byte } + } + + /// Convert a vector of bytes `bytes` into an `String`. Aborts if + /// `bytes` contains non-ASCII characters. + public fun string(bytes: vector): String { + let x = try_string(bytes); + assert!( + option::is_some(&x), + EINVALID_ASCII_CHARACTER + 1 // !!!!!!! <<<<<< Addition here! + ); + option::destroy_some(x) + } + + /// Convert a vector of bytes `bytes` into an `String`. Returns + /// `Some()` if the `bytes` contains all valid ASCII + /// characters. Otherwise returns `None`. + public fun try_string(bytes: vector): Option { + let len = vector::length(&bytes); + let i = 0; + while (i < len) { + let possible_byte = *vector::borrow(&bytes, i); + if (!is_valid_char(possible_byte)) return option::none(); + i = i + 1; + }; + option::some(String { bytes }) + } + + /// Returns `true` if all characters in `string` are printable characters + /// Returns `false` otherwise. Not all `String`s are printable strings. + public fun all_characters_printable(string: &String): bool { + let len = vector::length(&string.bytes); + let i = 0; + while (i < len) { + let byte = *vector::borrow(&string.bytes, i); + if (!is_printable_char(byte)) return false; + i = i + 1; + }; + true + } + + public fun push_char(string: &mut String, char: Char) { + vector::push_back(&mut string.bytes, char.byte); + } + + public fun pop_char(string: &mut String): Char { + Char { byte: vector::pop_back(&mut string.bytes) } + } + + public fun length(string: &String): u64 { + vector::length(as_bytes(string)) + } + + /// Get the inner bytes of the `string` as a reference + public fun as_bytes(string: &String): &vector { + &string.bytes + } + + /// Unpack the `string` to get its backing bytes + public fun into_bytes(string: String): vector { + let String { bytes } = string; + bytes + } + + /// Unpack the `char` into its underlying byte. + public fun byte(char: Char): u8 { + let Char { byte } = char; + byte + } + + /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. + public fun is_valid_char(b: u8): bool { + b <= 0x7F + } + + /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. + public fun is_printable_char(byte: u8): bool { + byte >= 0x20 && // Disallow metacharacters + byte <= 0x7E // Don't allow DEL metacharacter + } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/about.package diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/sources/base.move new file mode 100644 index 00000000000..bf6dc6c7c6f --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/sources/base.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + friend base::friend_module; + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } + public(friend) fun friend_fun(): u64 { 0 } +} diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/sources/friend.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/sources/friend.move new file mode 100644 index 00000000000..63c29a7a4aa --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/sources/friend.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::friend_module { + public fun call_friend(): u64 { base::base_module::friend_fun() } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/sources/base.move new file mode 100644 index 00000000000..2f0cab16427 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/sources/base.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + friend base::friend_module; + + public fun public_fun(): u64 { 0 } + fun private_fun(x: u64): u64 { x } + fun private_entry_fun(_x: u64) { } + public(friend) fun friend_fun(x: u64): u64 { x } +} diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/sources/friend.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/sources/friend.move new file mode 100644 index 00000000000..812cbfd7015 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/sources/friend.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::friend_module { + public fun call_friend(): u64 { base::base_module::friend_fun(0) } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/about.package diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/sources/base.move new file mode 100644 index 00000000000..bf6dc6c7c6f --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/sources/base.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + friend base::friend_module; + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } + public(friend) fun friend_fun(): u64 { 0 } +} diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/sources/friend.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/sources/friend.move new file mode 100644 index 00000000000..63c29a7a4aa --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/sources/friend.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::friend_module { + public fun call_friend(): u64 { base::base_module::friend_fun() } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/sources/base.move new file mode 100644 index 00000000000..334e9d33478 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/sources/base.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + friend base::friend_module; + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + fun private_entry_fun(_x: u64) { } + public(friend) fun friend_fun(): u64 { 0 } +} diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/sources/friend.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/sources/friend.move new file mode 100644 index 00000000000..63c29a7a4aa --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/sources/friend.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::friend_module { + public fun call_friend(): u64 { base::base_module::friend_fun() } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/about.package diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/base/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/base/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/base/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/base/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/base/sources/base.move new file mode 100644 index 00000000000..a4435c48e92 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/base/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + public fun public_fun(x: u64, y: u64): u64 { x + y } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/upgraded/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/upgraded/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/upgraded/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/upgraded/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/upgraded/sources/base.move new file mode 100644 index 00000000000..37e30767bd6 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/upgraded/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + public fun public_fun(y: u64, x: u64): u64 { y + x } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/about.package diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/base/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/base/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/base/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/base/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/base/sources/base.move new file mode 100644 index 00000000000..a4435c48e92 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/base/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + public fun public_fun(x: u64, y: u64): u64 { x + y } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/upgraded/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/upgraded/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/upgraded/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/upgraded/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/upgraded/sources/base.move new file mode 100644 index 00000000000..c6c9af1898c --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/upgraded/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + public fun public_fun(y: u64, x: u64): u64 { x + y } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_rename/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_rename/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_rename/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_rename/about.package diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_rename/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_rename/base/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_rename/base/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_rename/base/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_rename/base/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_rename/base/sources/base.move new file mode 100644 index 00000000000..5ffc5ff619d --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_rename/base/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_rename/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_rename/upgraded/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_rename/upgraded/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_rename/upgraded/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_rename/upgraded/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_rename/upgraded/sources/base.move new file mode 100644 index 00000000000..3953707e4b2 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/public_fun_rename/upgraded/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + public fun renamed_public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__constant_name_change.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__constant_name_change.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__constant_name_change.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__constant_name_change.snap index a93d4caf98e..657bda57191 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__constant_name_change.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__constant_name_change.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__constant_value_changed.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__constant_value_changed.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__constant_value_changed.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__constant_value_changed.snap index 2f83218e237..6e16ee374ac 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__constant_value_changed.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__constant_value_changed.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__friend_entry_changed.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__friend_entry_changed.snap similarity index 97% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__friend_entry_changed.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__friend_entry_changed.snap index aa7cced862a..74ece59d682 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__friend_entry_changed.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__friend_entry_changed.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__friend_function_change.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__friend_function_change.snap similarity index 97% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__friend_function_change.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__friend_function_change.snap index 24eb0063ef6..9bbf832b510 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__friend_function_change.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__friend_function_change.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check.snap index 705f5523351..d6ecdae5843 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check_alpha_rename.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check_alpha_rename.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check_alpha_rename.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check_alpha_rename.snap index 705f5523351..d6ecdae5843 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check_alpha_rename.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check_alpha_rename.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check_local_shuffle.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check_local_shuffle.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check_local_shuffle.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check_local_shuffle.snap index ce61264d0c5..ba3ad2f5d3c 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check_local_shuffle.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_equality_check_local_shuffle.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_inclusion_check.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_inclusion_check.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_inclusion_check.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_inclusion_check.snap index 724fb1dded5..af25532a1a2 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_inclusion_check.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_inclusion_check.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_invalid_equality_inclusion_check.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_invalid_equality_inclusion_check.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_invalid_equality_inclusion_check.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_invalid_equality_inclusion_check.snap index ce61264d0c5..ba3ad2f5d3c 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_invalid_equality_inclusion_check.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__large_package_invalid_equality_inclusion_check.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__private_entry_and_friend_changes.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__private_entry_and_friend_changes.snap similarity index 97% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__private_entry_and_friend_changes.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__private_entry_and_friend_changes.snap index 5e9bb8bd4db..382079e3b1a 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__private_entry_and_friend_changes.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__private_entry_and_friend_changes.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__private_entry_fun_entry_removed.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__private_entry_fun_entry_removed.snap similarity index 97% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__private_entry_fun_entry_removed.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__private_entry_fun_entry_removed.snap index aa7cced862a..74ece59d682 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__private_entry_fun_entry_removed.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__private_entry_fun_entry_removed.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_param_alpha_rename.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_param_alpha_rename.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_param_alpha_rename.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_param_alpha_rename.snap index a93d4caf98e..657bda57191 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_param_alpha_rename.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_param_alpha_rename.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_param_permute.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_param_permute.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_param_permute.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_param_permute.snap index 2f83218e237..6e16ee374ac 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_param_permute.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_param_permute.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_rename.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_rename.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_rename.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_rename.snap index 48d7906e58a..a80855b9e9e 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_rename.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__public_fun_rename.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_name_change.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_name_change.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_name_change.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_name_change.snap index 48d7906e58a..a80855b9e9e 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_name_change.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_name_change.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_reorder.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_reorder.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_reorder.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_reorder.snap index 48d7906e58a..a80855b9e9e 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_reorder.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_reorder.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_reorder_no_name_change.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_reorder_no_name_change.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_reorder_no_name_change.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_reorder_no_name_change.snap index 48d7906e58a..a80855b9e9e 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_reorder_no_name_change.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_field_reorder_no_name_change.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_layout_change.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_layout_change.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_layout_change.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_layout_change.snap index 48d7906e58a..a80855b9e9e 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_layout_change.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_layout_change.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_name_change.snap b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_name_change.snap similarity index 96% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_name_change.snap rename to crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_name_change.snap index 48d7906e58a..a80855b9e9e 100644 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_name_change.snap +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/snapshots/tests__struct_name_change.snap @@ -1,5 +1,5 @@ --- -source: crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +source: crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs expression: results --- ==== diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/about.package diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/base/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/base/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/base/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/base/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/base/sources/base.move new file mode 100644 index 00000000000..5ffc5ff619d --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/base/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/upgraded/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/upgraded/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/upgraded/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/upgraded/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/upgraded/sources/base.move new file mode 100644 index 00000000000..5caa291694a --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/upgraded/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field2: u64, + field1: u64, + } + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/about.package diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/base/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/base/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/base/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/base/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/base/sources/base.move new file mode 100644 index 00000000000..09074f73a6c --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/base/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: bool, + } + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/upgraded/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/upgraded/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/upgraded/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/upgraded/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/upgraded/sources/base.move new file mode 100644 index 00000000000..6af11f03f5a --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/upgraded/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field1: bool, + field0: u64, + } + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/about.package diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/base/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/base/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/base/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/base/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/base/sources/base.move new file mode 100644 index 00000000000..09074f73a6c --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/base/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: bool, + } + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/upgraded/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/upgraded/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/upgraded/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/upgraded/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/upgraded/sources/base.move new file mode 100644 index 00000000000..380876574dc --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/upgraded/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: bool, + field1: u64, + } + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_layout_change/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_layout_change/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_layout_change/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_layout_change/about.package diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_layout_change/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_layout_change/base/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_layout_change/base/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_layout_change/base/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_layout_change/base/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_layout_change/base/sources/base.move new file mode 100644 index 00000000000..5ffc5ff619d --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_layout_change/base/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_layout_change/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_layout_change/upgraded/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_layout_change/upgraded/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_layout_change/upgraded/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_layout_change/upgraded/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_layout_change/upgraded/sources/base.move new file mode 100644 index 00000000000..d19e4574e75 --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_layout_change/upgraded/sources/base.move @@ -0,0 +1,15 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + extra_field: u64, + } + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_name_change/about.package b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_name_change/about.package similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_name_change/about.package rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_name_change/about.package diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_name_change/base/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_name_change/base/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_name_change/base/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_name_change/base/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_name_change/base/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_name_change/base/sources/base.move new file mode 100644 index 00000000000..5ffc5ff619d --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_name_change/base/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct X { + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_name_change/upgraded/Move.toml b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_name_change/upgraded/Move.toml similarity index 100% rename from crates/sui-upgrade-compatibility-transactional-tests/tests/struct_name_change/upgraded/Move.toml rename to crates/iota-upgrade-compatibility-transactional-tests/tests/struct_name_change/upgraded/Move.toml diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_name_change/upgraded/sources/base.move b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_name_change/upgraded/sources/base.move new file mode 100644 index 00000000000..a0a3702b2ac --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/struct_name_change/upgraded/sources/base.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module base::base_module { + struct Y { + field0: u64, + field1: u64, + } + + public fun public_fun(): u64 { 0 } + fun private_fun(): u64 { 0 } + entry fun private_entry_fun(_x: u64) { } +} diff --git a/crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs b/crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs new file mode 100644 index 00000000000..7708029680e --- /dev/null +++ b/crates/iota-upgrade-compatibility-transactional-tests/tests/tests.rs @@ -0,0 +1,147 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::path::{Path, PathBuf}; + +use iota_move_build::{BuildConfig, IotaPackageHooks}; +use move_binary_format::{ + compatibility::{Compatibility, InclusionCheck}, + file_format::AbilitySet, + normalized, CompiledModule, +}; + +pub const TEST_DIR: &str = "tests"; + +fn run_test(path: &Path) -> datatest_stable::Result<()> { + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); + let mut pathbuf = path.to_path_buf(); + pathbuf.pop(); + pathbuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(pathbuf); + let mut base_path = pathbuf.clone(); + let mut upgraded_path = pathbuf.clone(); + + base_path.push("base"); + upgraded_path.push("upgraded"); + + let base = compile(base_path)?; + let base_normalized = normalize(&base); + + let upgraded = compile(upgraded_path)?; + let upgraded_normalized = normalize(&upgraded); + + check_all_compatibilities( + base_normalized, + upgraded_normalized, + pathbuf.file_name().unwrap().to_string_lossy().to_string(), + ) +} + +fn compile(path: PathBuf) -> anyhow::Result> { + Ok(BuildConfig::new_for_testing() + .build(path) + .unwrap() + .into_modules()) +} + +fn normalize(modules: &[CompiledModule]) -> Vec { + modules.iter().map(normalized::Module::new).collect() +} + +fn check_all_compatibilities( + base: Vec, + upgraded: Vec, + name: String, +) -> datatest_stable::Result<()> { + assert_eq!(base.len(), upgraded.len()); + + let compatibility_types = [ + Compatibility::full_check(), + // Full compat but allow private entry functions to change + Compatibility { + check_struct_and_pub_function_linking: true, + check_struct_layout: true, + check_friend_linking: true, + check_private_entry_linking: false, + disallowed_new_abilities: AbilitySet::ALL, + disallow_change_struct_type_params: true, + }, + // Full compat but allow private entry functions and friends to change + Compatibility { + check_struct_and_pub_function_linking: true, + check_struct_layout: true, + check_friend_linking: false, + check_private_entry_linking: false, + disallowed_new_abilities: AbilitySet::ALL, + disallow_change_struct_type_params: true, + }, + // Full compat but allow friends to change + Compatibility { + check_struct_and_pub_function_linking: true, + check_struct_layout: true, + check_friend_linking: false, + check_private_entry_linking: true, + disallowed_new_abilities: AbilitySet::ALL, + disallow_change_struct_type_params: true, + }, + Compatibility::no_check(), + ]; + + let mut results = compatibility_types + .iter() + .map(|compat| { + let compatibility_checks: Vec<_> = base + .iter() + .zip(upgraded.iter()) + .map(|(base, upgraded)| { + format!( + "{}::{}:\n\tbase->upgrade: {}\n\tupgrade->base: {}", + base.address, + base.name, + compat.check(base, upgraded).is_ok(), + compat.check(upgraded, base).is_ok() + ) + }) + .collect(); + + format!( + "====\n{:?}\n{}\n====", + compat, + compatibility_checks.join("\n") + ) + }) + .collect::>() + .join("\n"); + + let inclusion_results = [InclusionCheck::Equal, InclusionCheck::Subset] + .iter() + .map(|compat| { + let compatibility_checks: Vec<_> = base + .iter() + .zip(upgraded.iter()) + .map(|(base, upgraded)| { + format!( + "{}::{}:\n\tbase->upgrade: {}\n\tupgrade->base: {}", + base.address, + base.name, + compat.check(base, upgraded).is_ok(), + compat.check(upgraded, base).is_ok() + ) + }) + .collect(); + + format!( + "====\n{:?}\n{}\n====", + compat, + compatibility_checks.join("\n") + ) + }) + .collect::>() + .join("\n"); + + results.push_str(&inclusion_results); + insta::assert_display_snapshot!(name, results); + Ok(()) +} + +datatest_stable::harness!(run_test, TEST_DIR, r".*\.package$"); diff --git a/crates/iota-verifier-transactional-tests/Cargo.toml b/crates/iota-verifier-transactional-tests/Cargo.toml new file mode 100644 index 00000000000..2bf7668b0db --- /dev/null +++ b/crates/iota-verifier-transactional-tests/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "iota-verifier-transactional-tests" +version = "0.1.0" +authors = ["Mysten Labs "] +description = "Transactional tests for Iota Verifier" +license = "Apache-2.0" +publish = false +edition = "2021" + +[dev-dependencies] +datatest-stable.workspace = true +iota-transactional-test-runner.workspace = true + +[[test]] +name = "tests" +harness = false + +[dependencies] diff --git a/crates/iota-verifier-transactional-tests/src/lib.rs b/crates/iota-verifier-transactional-tests/src/lib.rs new file mode 100644 index 00000000000..7de55296af9 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/src/lib.rs @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#![forbid(unsafe_code)] + +// Empty src/lib.rs to get rusty-tags working. diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/clock_mut.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/clock_mut.exp new file mode 100644 index 00000000000..3e20d159cd1 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/clock_mut.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-14: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Clock must be passed by immutable reference. got: &mut iota::clock::Clock"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/clock_mut.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/clock_mut.mvir similarity index 83% rename from crates/sui-verifier-transactional-tests/tests/entry_points/clock_mut.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/clock_mut.mvir index 43162806d56..66fb5a37867 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/clock_mut.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/clock_mut.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, Clock by mutable reference diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/clock_ref.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/clock_ref.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/clock_ref.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/clock_ref.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/clock_ref.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/clock_ref.mvir similarity index 83% rename from crates/sui-verifier-transactional-tests/tests/entry_points/clock_ref.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/clock_ref.mvir index 3867d4c4dee..88e36b918c4 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/clock_ref.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/clock_ref.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // valid, Clock by immutable reference diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/clock_val.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/clock_val.exp new file mode 100644 index 00000000000..9778ca39f4e --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/clock_val.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-14: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Clock must be passed by immutable reference. got: iota::clock::Clock"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/clock_val.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/clock_val.mvir similarity index 83% rename from crates/sui-verifier-transactional-tests/tests/entry_points/clock_val.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/clock_val.mvir index 643b1180e83..e96e542dd6f 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/clock_val.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/clock_val.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, Clock by value diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_and_generic_object_params.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_and_generic_object_params.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/generic_and_generic_object_params.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/generic_and_generic_object_params.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_and_generic_object_params.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_and_generic_object_params.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/entry_points/generic_and_generic_object_params.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/generic_and_generic_object_params.mvir index c99a6a937c6..a0c53ea5e01 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_and_generic_object_params.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_and_generic_object_params.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/generic_obj_mut_ref_vector.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_obj_mut_ref_vector.exp new file mode 100644 index 00000000000..13fd5f0e8b8 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_obj_mut_ref_vector.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-15: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &mut vector"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_obj_mut_ref_vector.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_obj_mut_ref_vector.mvir similarity index 86% rename from crates/sui-verifier-transactional-tests/tests/entry_points/generic_obj_mut_ref_vector.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/generic_obj_mut_ref_vector.mvir index 6d27f529e91..46a46d47ee8 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_obj_mut_ref_vector.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_obj_mut_ref_vector.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, a mutable reference to vector of objects diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/generic_obj_ref_vector.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_obj_ref_vector.exp new file mode 100644 index 00000000000..efd9c6462f9 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_obj_ref_vector.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-15: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &vector"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_obj_ref_vector.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_obj_ref_vector.mvir similarity index 85% rename from crates/sui-verifier-transactional-tests/tests/entry_points/generic_obj_ref_vector.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/generic_obj_ref_vector.mvir index 487034ece09..e64ac6c0a29 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_obj_ref_vector.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_obj_ref_vector.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, a mutable reference to vector of objects diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_param_after_primitive.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_param_after_primitive.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/generic_param_after_primitive.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/generic_param_after_primitive.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_param_after_primitive.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_param_after_primitive.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/entry_points/generic_param_after_primitive.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/generic_param_after_primitive.mvir index 5554d36c710..72d4c07ac9b 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_param_after_primitive.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_param_after_primitive.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/generic_with_key_invalid.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_with_key_invalid.exp new file mode 100644 index 00000000000..e8b5e704e30 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_with_key_invalid.exp @@ -0,0 +1,9 @@ +processed 2 tasks + +task 0 'publish'. lines 6-16: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: std::option::Option"), command: Some(0) } } + +task 1 'publish'. lines 18-28: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: vector>"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_with_key_invalid.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_with_key_invalid.mvir similarity index 92% rename from crates/sui-verifier-transactional-tests/tests/entry_points/generic_with_key_invalid.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/generic_with_key_invalid.mvir index 928470883ba..86d319e914f 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_with_key_invalid.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_with_key_invalid.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, type parameters with key are not valid when nested as no primitive has key diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_with_key_valid.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_with_key_valid.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/generic_with_key_valid.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/generic_with_key_valid.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_with_key_valid.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_with_key_valid.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/entry_points/generic_with_key_valid.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/generic_with_key_valid.mvir index e19c9b84c3c..d91f170ab41 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_with_key_valid.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/generic_with_key_valid.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // valid, type parameters with key are valid as long as they are not nested diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/id.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/id.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/id.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/id.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/id.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/id.mvir similarity index 88% rename from crates/sui-verifier-transactional-tests/tests/entry_points/id.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/id.mvir index 93ad556c859..8e7b6c528c9 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/id.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/id.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // valid, ID is allowed diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/nested_generic_vector_param.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/nested_generic_vector_param.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/nested_generic_vector_param.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/nested_generic_vector_param.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/nested_generic_vector_param.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/nested_generic_vector_param.mvir similarity index 83% rename from crates/sui-verifier-transactional-tests/tests/entry_points/nested_generic_vector_param.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/nested_generic_vector_param.mvir index 2b5c519e801..75b39d0c6aa 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/nested_generic_vector_param.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/nested_generic_vector_param.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/nested_key_generic_vector_param.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/nested_key_generic_vector_param.exp new file mode 100644 index 00000000000..30b4b603ba1 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/nested_key_generic_vector_param.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 4-13: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: vector>"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/nested_key_generic_vector_param.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/nested_key_generic_vector_param.mvir similarity index 83% rename from crates/sui-verifier-transactional-tests/tests/entry_points/nested_key_generic_vector_param.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/nested_key_generic_vector_param.mvir index 32bd8db6354..c52f2bfa0df 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/nested_key_generic_vector_param.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/nested_key_generic_vector_param.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct.exp new file mode 100644 index 00000000000..9f6df203bf9 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-17: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: _::m::S"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct.mvir index a5ab60c8310..5129343992c 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, non key structs are not supported diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_generic.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_generic.exp new file mode 100644 index 00000000000..3eb889a462a --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_generic.exp @@ -0,0 +1,9 @@ +processed 2 tasks + +task 0 'publish'. lines 6-21: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: _::m::Obj<_::m::NoStore>"), command: Some(0) } } + +task 1 'publish'. lines 23-35: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: _::m::Obj"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_generic.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_generic.mvir similarity index 93% rename from crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_generic.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_generic.mvir index 6ef5230da4d..d11cd8c0d45 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_generic.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_generic.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid as NoStore doesn't have store, so Obj doesn't have key diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_generic_valid.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_generic_valid.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_generic_valid.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_generic_valid.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_generic_valid.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_generic_valid.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_generic_valid.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_generic_valid.mvir index bd760de8c18..9497b7a2cfb 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_generic_valid.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_generic_valid.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // valid, T has store, thus Obj has key diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_vector.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_vector.exp new file mode 100644 index 00000000000..715e72e8458 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_vector.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-17: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: vector<_::m::S>"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_vector.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_vector.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_vector.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_vector.mvir index dbdca0c9b58..3a2c242c09f 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_vector.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/non_key_struct_vector.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, non key structs are not supported, even in vectors diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/obj_mut_ref_vector.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/obj_mut_ref_vector.exp new file mode 100644 index 00000000000..c9e3f06cb77 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/obj_mut_ref_vector.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-18: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &mut vector<_::m::S>"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/obj_mut_ref_vector.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/obj_mut_ref_vector.mvir similarity index 88% rename from crates/sui-verifier-transactional-tests/tests/entry_points/obj_mut_ref_vector.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/obj_mut_ref_vector.mvir index d57f4699aac..8af377cbf79 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/obj_mut_ref_vector.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/obj_mut_ref_vector.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, a mutable reference to vector of objects diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/obj_ref_vector.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/obj_ref_vector.exp new file mode 100644 index 00000000000..0ec021ec7b8 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/obj_ref_vector.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-18: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &vector<_::m::S>"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/obj_ref_vector.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/obj_ref_vector.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/entry_points/obj_ref_vector.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/obj_ref_vector.mvir index c158b9c71ce..79e13040bb6 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/obj_ref_vector.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/obj_ref_vector.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, a reference to vector of objects diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/ok.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/ok.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/ok.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/ok.exp diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/ok.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/ok.mvir new file mode 100644 index 00000000000..7ca1b2987c4 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/ok.mvir @@ -0,0 +1,21 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# publish +module 0x0.m { + import 0x2.tx_context; + public entry t(arg: &tx_context.TxContext) { + label l0: + abort 0; + } +} + +//# publish +module 0x0.m { + import 0x2.tx_context; + public entry t(arg: &mut tx_context.TxContext) { + label l0: + abort 0; + } +} diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/option.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/option.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/option.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/option.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/option.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/option.mvir similarity index 91% rename from crates/sui-verifier-transactional-tests/tests/entry_points/option.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/option.mvir index 9f8a96ff86e..f05ff58def9 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/option.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/option.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // valid, option of primitives is allowed diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/optional_txn_context.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/optional_txn_context.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/optional_txn_context.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/optional_txn_context.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/optional_txn_context.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/optional_txn_context.mvir similarity index 89% rename from crates/sui-verifier-transactional-tests/tests/entry_points/optional_txn_context.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/optional_txn_context.mvir index 10094568e7b..1546dc10756 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/optional_txn_context.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/optional_txn_context.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/random_mut.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/random_mut.exp new file mode 100644 index 00000000000..2bf2a759fba --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/random_mut.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-14: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Random must be passed by immutable reference. got: &mut iota::random::Random"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/random_mut.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/random_mut.mvir similarity index 84% rename from crates/sui-verifier-transactional-tests/tests/entry_points/random_mut.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/random_mut.mvir index 38d35e9fed3..8cf89a16cb5 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/random_mut.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/random_mut.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, Random by mutable reference diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/random_ref.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/random_ref.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/random_ref.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/random_ref.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/random_ref.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/random_ref.mvir similarity index 84% rename from crates/sui-verifier-transactional-tests/tests/entry_points/random_ref.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/random_ref.mvir index ee31d1e14a0..7eb16686f6b 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/random_ref.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/random_ref.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // valid, Random by immutable reference diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/random_val.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/random_val.exp new file mode 100644 index 00000000000..fe998c07e49 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/random_val.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-14: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point parameter type. Random must be passed by immutable reference. got: iota::random::Random"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/random_val.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/random_val.mvir similarity index 83% rename from crates/sui-verifier-transactional-tests/tests/entry_points/random_val.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/random_val.mvir index 6d2a7e358a6..8fac52dda9b 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/random_val.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/random_val.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, Random by value diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/return_values.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/return_values.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/return_values.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/return_values.exp diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/return_values.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/return_values.mvir new file mode 100644 index 00000000000..f5a2b8497a5 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/return_values.mvir @@ -0,0 +1,52 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// return values from entry functions must have drop + +//# publish +module 0x0.m { + import 0x2.tx_context; + public entry foo(ctx: &mut tx_context.TxContext): u64 { + label l0: + abort 0; + } +} + +//# publish +module 0x0.m { + import 0x2.tx_context; + public entry foo(ctx: &mut tx_context.TxContext): u64 * u8 { + label l0: + abort 0; + } +} + +//# publish +module 0x0.m { + import 0x2.tx_context; + public entry foo(ctx: &mut tx_context.TxContext): vector { + label l0: + abort 0; + } +} + +//# publish +module 0x0.m { + import 0x2.tx_context; + struct Droppable has drop { flag: bool } + public entry foo(ctx: &mut tx_context.TxContext): Self.Droppable { + label l0: + abort 0; + } +} + +//# publish +module 0x0.m { + import 0x2.tx_context; + struct Droppable has drop { flag: bool } + public entry foo(ctx: &mut tx_context.TxContext): vector * u64 { + label l0: + abort 0; + } +} diff --git a/crates/iota-verifier-transactional-tests/tests/entry_points/return_values_invalid.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/return_values_invalid.exp new file mode 100644 index 00000000000..1ddaea699b7 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/return_values_invalid.exp @@ -0,0 +1,25 @@ +processed 6 tasks + +task 0 'publish'. lines 6-13: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point return type. Expected a non reference type."), command: Some(0) } } + +task 1 'publish'. lines 15-22: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point return type. Expected a non reference type."), command: Some(0) } } + +task 2 'publish'. lines 24-31: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point return type. Expected a non reference type."), command: Some(0) } } + +task 3 'publish'. lines 33-41: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point return type. The specified return type does not have the 'drop' ability: _::m::Copyable"), command: Some(0) } } + +task 4 'publish'. lines 43-52: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point return type. The specified return type does not have the 'drop' ability: _::m::Obj"), command: Some(0) } } + +task 5 'publish'. lines 54-63: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Invalid entry point return type. The specified return type does not have the 'drop' ability: vector<_::m::Obj>"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/return_values_invalid.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/return_values_invalid.mvir similarity index 96% rename from crates/sui-verifier-transactional-tests/tests/entry_points/return_values_invalid.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/return_values_invalid.mvir index b95e54903c6..3bed3671d16 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/return_values_invalid.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/return_values_invalid.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // return values from entry functions must have drop diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/single_generic_vector_param.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/single_generic_vector_param.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/single_generic_vector_param.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/single_generic_vector_param.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/single_generic_vector_param.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/single_generic_vector_param.mvir similarity index 83% rename from crates/sui-verifier-transactional-tests/tests/entry_points/single_generic_vector_param.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/single_generic_vector_param.mvir index b7ef26033b8..7f9efcaff31 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/single_generic_vector_param.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/single_generic_vector_param.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param.mvir similarity index 82% rename from crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param.mvir index 620e4b3b3c3..c7cb4ad2e58 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param_generic_object.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param_generic_object.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param_generic_object.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param_generic_object.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param_generic_object.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param_generic_object.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param_generic_object.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param_generic_object.mvir index e01fd320810..c7e8c594d1f 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param_generic_object.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param_generic_object.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param_key.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param_key.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param_key.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param_key.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param_key.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param_key.mvir similarity index 82% rename from crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param_key.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param_key.mvir index 7063b40b6ca..d3090b2571a 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/single_type_param_key.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/single_type_param_key.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/string.exp b/crates/iota-verifier-transactional-tests/tests/entry_points/string.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/entry_points/string.exp rename to crates/iota-verifier-transactional-tests/tests/entry_points/string.exp diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/string.mvir b/crates/iota-verifier-transactional-tests/tests/entry_points/string.mvir similarity index 93% rename from crates/sui-verifier-transactional-tests/tests/entry_points/string.mvir rename to crates/iota-verifier-transactional-tests/tests/entry_points/string.mvir index b03db8db567..f10d24ce90c 100644 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/string.mvir +++ b/crates/iota-verifier-transactional-tests/tests/entry_points/string.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // valid, ASCII and UTF strings is allowed diff --git a/crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_generic_key_struct_id_field.exp b/crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_generic_key_struct_id_field.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_generic_key_struct_id_field.exp rename to crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_generic_key_struct_id_field.exp diff --git a/crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_generic_key_struct_id_field.mvir b/crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_generic_key_struct_id_field.mvir similarity index 85% rename from crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_generic_key_struct_id_field.mvir rename to crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_generic_key_struct_id_field.mvir index c86e57e15bc..1f4b1dd463b 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_generic_key_struct_id_field.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_generic_key_struct_id_field.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_id_field.exp b/crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_id_field.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_id_field.exp rename to crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_id_field.exp diff --git a/crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_id_field.mvir b/crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_id_field.mvir similarity index 85% rename from crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_id_field.mvir rename to crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_id_field.mvir index 833da499c63..fe705f5eff7 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_id_field.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_id_field.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_non_id_field.exp b/crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_non_id_field.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_non_id_field.exp rename to crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_non_id_field.exp diff --git a/crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_non_id_field.mvir b/crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_non_id_field.mvir similarity index 86% rename from crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_non_id_field.mvir rename to crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_non_id_field.mvir index b2679282329..fda488059a8 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_non_id_field.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_key_struct_non_id_field.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_non_key_struct_id_field.exp b/crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_non_key_struct_id_field.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_non_key_struct_id_field.exp rename to crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_non_key_struct_id_field.exp diff --git a/crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_non_key_struct_id_field.mvir b/crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_non_key_struct_id_field.mvir similarity index 84% rename from crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_non_key_struct_id_field.mvir rename to crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_non_key_struct_id_field.mvir index ed09b58ecfd..b68527641c3 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_immutable/mut_borrow_non_key_struct_id_field.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_immutable/mut_borrow_non_key_struct_id_field.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/id_immutable/write_id_field.exp b/crates/iota-verifier-transactional-tests/tests/id_immutable/write_id_field.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/id_immutable/write_id_field.exp rename to crates/iota-verifier-transactional-tests/tests/id_immutable/write_id_field.exp diff --git a/crates/sui-verifier-transactional-tests/tests/id_immutable/write_id_field.mvir b/crates/iota-verifier-transactional-tests/tests/id_immutable/write_id_field.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/id_immutable/write_id_field.mvir rename to crates/iota-verifier-transactional-tests/tests/id_immutable/write_id_field.mvir index 0441b97c89a..f37cab78881 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_immutable/write_id_field.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_immutable/write_id_field.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/direct_leak_through_call.exp b/crates/iota-verifier-transactional-tests/tests/id_leak/direct_leak_through_call.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/id_leak/direct_leak_through_call.exp rename to crates/iota-verifier-transactional-tests/tests/id_leak/direct_leak_through_call.exp diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/direct_leak_through_call.mvir b/crates/iota-verifier-transactional-tests/tests/id_leak/direct_leak_through_call.mvir similarity index 90% rename from crates/sui-verifier-transactional-tests/tests/id_leak/direct_leak_through_call.mvir rename to crates/iota-verifier-transactional-tests/tests/id_leak/direct_leak_through_call.mvir index ce921f42858..018226156d9 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/direct_leak_through_call.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/direct_leak_through_call.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/id_leak/indirect_leak_through_call.exp b/crates/iota-verifier-transactional-tests/tests/id_leak/indirect_leak_through_call.exp new file mode 100644 index 00000000000..0bdf098b744 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/indirect_leak_through_call.exp @@ -0,0 +1,10 @@ +processed 2 tasks + +task 0 'publish'. lines 4-26: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("PartialVMError with status UNKNOWN_VERIFICATION_ERROR with sub status 1 and message Invalid object creation in _::m::foo. Object created without a newly created UID. The UID must come directly from iota::object::new. Or for tests, it can come from iota::test_scenario::new_object"), command: Some(0) } } + +task 1 'publish'. lines 28-50: +created: object(2,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 4590400, storage_rebate: 978120, non_refundable_storage_fee: 9880 diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/indirect_leak_through_call.mvir b/crates/iota-verifier-transactional-tests/tests/id_leak/indirect_leak_through_call.mvir similarity index 94% rename from crates/sui-verifier-transactional-tests/tests/id_leak/indirect_leak_through_call.mvir rename to crates/iota-verifier-transactional-tests/tests/id_leak/indirect_leak_through_call.mvir index 2bbf3241eb2..e4ef6db7dc6 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/indirect_leak_through_call.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/indirect_leak_through_call.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/infinite_loop.exp b/crates/iota-verifier-transactional-tests/tests/id_leak/infinite_loop.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/id_leak/infinite_loop.exp rename to crates/iota-verifier-transactional-tests/tests/id_leak/infinite_loop.exp diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/infinite_loop.mvir b/crates/iota-verifier-transactional-tests/tests/id_leak/infinite_loop.mvir similarity index 96% rename from crates/sui-verifier-transactional-tests/tests/id_leak/infinite_loop.mvir rename to crates/iota-verifier-transactional-tests/tests/id_leak/infinite_loop.mvir index f3e48d9f9f7..d9bf396a459 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/infinite_loop.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/infinite_loop.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Modules with infinite loops to stress the ID leak verifier diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/loop.exp b/crates/iota-verifier-transactional-tests/tests/id_leak/loop.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/id_leak/loop.exp rename to crates/iota-verifier-transactional-tests/tests/id_leak/loop.exp diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/loop.mvir b/crates/iota-verifier-transactional-tests/tests/id_leak/loop.mvir similarity index 94% rename from crates/sui-verifier-transactional-tests/tests/id_leak/loop.mvir rename to crates/iota-verifier-transactional-tests/tests/id_leak/loop.mvir index 9b562a911e1..f1a8fec918a 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/loop.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/loop.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/id_leak/through_call_with_borrow_field.exp b/crates/iota-verifier-transactional-tests/tests/id_leak/through_call_with_borrow_field.exp new file mode 100644 index 00000000000..c40b602cc47 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/through_call_with_borrow_field.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 4-34: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("PartialVMError with status UNKNOWN_VERIFICATION_ERROR with sub status 1 and message Invalid object creation in _::m::new. Object created without a newly created UID. The UID must come directly from iota::object::new. Or for tests, it can come from iota::test_scenario::new_object"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/through_call_with_borrow_field.mvir b/crates/iota-verifier-transactional-tests/tests/id_leak/through_call_with_borrow_field.mvir similarity index 93% rename from crates/sui-verifier-transactional-tests/tests/id_leak/through_call_with_borrow_field.mvir rename to crates/iota-verifier-transactional-tests/tests/id_leak/through_call_with_borrow_field.mvir index bc3a61fbe97..ca464920488 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/through_call_with_borrow_field.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/through_call_with_borrow_field.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/through_direct_return.exp b/crates/iota-verifier-transactional-tests/tests/id_leak/through_direct_return.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/id_leak/through_direct_return.exp rename to crates/iota-verifier-transactional-tests/tests/id_leak/through_direct_return.exp diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/through_direct_return.mvir b/crates/iota-verifier-transactional-tests/tests/id_leak/through_direct_return.mvir similarity index 88% rename from crates/sui-verifier-transactional-tests/tests/id_leak/through_direct_return.mvir rename to crates/iota-verifier-transactional-tests/tests/id_leak/through_direct_return.mvir index 887357b5d30..b406ead2c0c 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/through_direct_return.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/through_direct_return.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/id_leak/through_indirect_return.exp b/crates/iota-verifier-transactional-tests/tests/id_leak/through_indirect_return.exp new file mode 100644 index 00000000000..72279e071fb --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/through_indirect_return.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 4-20: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("PartialVMError with status UNKNOWN_VERIFICATION_ERROR with sub status 1 and message Invalid object creation in _::m::foo. Object created without a newly created UID. The UID must come directly from iota::object::new. Or for tests, it can come from iota::test_scenario::new_object"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/through_indirect_return.mvir b/crates/iota-verifier-transactional-tests/tests/id_leak/through_indirect_return.mvir similarity index 88% rename from crates/sui-verifier-transactional-tests/tests/id_leak/through_indirect_return.mvir rename to crates/iota-verifier-transactional-tests/tests/id_leak/through_indirect_return.mvir index c5a5db6edf2..8d09240e659 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/through_indirect_return.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/through_indirect_return.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/id_leak/through_pack.exp b/crates/iota-verifier-transactional-tests/tests/id_leak/through_pack.exp new file mode 100644 index 00000000000..fec9f3bc852 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/through_pack.exp @@ -0,0 +1,10 @@ +processed 2 tasks + +task 0 'publish'. lines 4-37: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("PartialVMError with status UNKNOWN_VERIFICATION_ERROR with sub status 1 and message Invalid object creation in _::test::test. Object created without a newly created UID. The UID must come directly from iota::object::new. Or for tests, it can come from iota::test_scenario::new_object"), command: Some(0) } } + +task 1 'publish'. lines 39-62: +created: object(2,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 4902000, storage_rebate: 978120, non_refundable_storage_fee: 9880 diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/through_pack.mvir b/crates/iota-verifier-transactional-tests/tests/id_leak/through_pack.mvir similarity index 95% rename from crates/sui-verifier-transactional-tests/tests/id_leak/through_pack.mvir rename to crates/iota-verifier-transactional-tests/tests/id_leak/through_pack.mvir index 6d94e3a1a27..800847e8e4d 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/through_pack.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/through_pack.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/through_reference.exp b/crates/iota-verifier-transactional-tests/tests/id_leak/through_reference.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/id_leak/through_reference.exp rename to crates/iota-verifier-transactional-tests/tests/id_leak/through_reference.exp diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/through_reference.mvir b/crates/iota-verifier-transactional-tests/tests/id_leak/through_reference.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/id_leak/through_reference.mvir rename to crates/iota-verifier-transactional-tests/tests/id_leak/through_reference.mvir index a940ec0c799..f4d0e1072b0 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/through_reference.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/through_reference.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/through_vector.exp b/crates/iota-verifier-transactional-tests/tests/id_leak/through_vector.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/id_leak/through_vector.exp rename to crates/iota-verifier-transactional-tests/tests/id_leak/through_vector.exp diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/through_vector.mvir b/crates/iota-verifier-transactional-tests/tests/id_leak/through_vector.mvir similarity index 90% rename from crates/sui-verifier-transactional-tests/tests/id_leak/through_vector.mvir rename to crates/iota-verifier-transactional-tests/tests/id_leak/through_vector.mvir index ae1ea052f87..01566178449 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/through_vector.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/through_vector.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/id_leak/transmute.exp b/crates/iota-verifier-transactional-tests/tests/id_leak/transmute.exp new file mode 100644 index 00000000000..687cc7e8844 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/transmute.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 4-28: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("PartialVMError with status UNKNOWN_VERIFICATION_ERROR with sub status 1 and message Invalid object creation in _::m::transmute. Object created without a newly created UID. The UID must come directly from iota::object::new. Or for tests, it can come from iota::test_scenario::new_object"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/transmute.mvir b/crates/iota-verifier-transactional-tests/tests/id_leak/transmute.mvir similarity index 92% rename from crates/sui-verifier-transactional-tests/tests/id_leak/transmute.mvir rename to crates/iota-verifier-transactional-tests/tests/id_leak/transmute.mvir index d28b8f118dc..a915785f481 100644 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/transmute.mvir +++ b/crates/iota-verifier-transactional-tests/tests/id_leak/transmute.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/init/cannot_call_init.exp b/crates/iota-verifier-transactional-tests/tests/init/cannot_call_init.exp new file mode 100644 index 00000000000..e2eb7abd1cd --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/init/cannot_call_init.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 4-17: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::init at offset 1. Cannot call a module's 'init' function from another Move function"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/init/cannot_call_init.mvir b/crates/iota-verifier-transactional-tests/tests/init/cannot_call_init.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/init/cannot_call_init.mvir rename to crates/iota-verifier-transactional-tests/tests/init/cannot_call_init.mvir index 3299538c969..284ac74cbdb 100644 --- a/crates/sui-verifier-transactional-tests/tests/init/cannot_call_init.mvir +++ b/crates/iota-verifier-transactional-tests/tests/init/cannot_call_init.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/init/imm_tx_context.exp b/crates/iota-verifier-transactional-tests/tests/init/imm_tx_context.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/init/imm_tx_context.exp rename to crates/iota-verifier-transactional-tests/tests/init/imm_tx_context.exp diff --git a/crates/sui-verifier-transactional-tests/tests/init/imm_tx_context.mvir b/crates/iota-verifier-transactional-tests/tests/init/imm_tx_context.mvir similarity index 83% rename from crates/sui-verifier-transactional-tests/tests/init/imm_tx_context.mvir rename to crates/iota-verifier-transactional-tests/tests/init/imm_tx_context.mvir index 6a5e41717f0..2f8e93af6d5 100644 --- a/crates/sui-verifier-transactional-tests/tests/init/imm_tx_context.mvir +++ b/crates/iota-verifier-transactional-tests/tests/init/imm_tx_context.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // TxContext can be immutable, even for init diff --git a/crates/iota-verifier-transactional-tests/tests/init/must_have_txn_context.exp b/crates/iota-verifier-transactional-tests/tests/init/must_have_txn_context.exp new file mode 100644 index 00000000000..9fc2c5b6396 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/init/must_have_txn_context.exp @@ -0,0 +1,9 @@ +processed 2 tasks + +task 0 'publish'. lines 4-11: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Expected at least one and at most two parameters for _::m::init"), command: Some(0) } } + +task 1 'publish'. lines 14-21: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Expected last (and at most second) parameter for _::m::init to be &mut iota::tx_context::TxContext or &iota::tx_context::TxContext; optional first parameter must be of one-time witness type whose name is the same as the capitalized module name (_::m::M) and which has no fields or a single field of type bool"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/init/must_have_txn_context.mvir b/crates/iota-verifier-transactional-tests/tests/init/must_have_txn_context.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/init/must_have_txn_context.mvir rename to crates/iota-verifier-transactional-tests/tests/init/must_have_txn_context.mvir index 0f204b13c53..ca081986724 100644 --- a/crates/sui-verifier-transactional-tests/tests/init/must_have_txn_context.mvir +++ b/crates/iota-verifier-transactional-tests/tests/init/must_have_txn_context.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/init/not_generic.exp b/crates/iota-verifier-transactional-tests/tests/init/not_generic.exp new file mode 100644 index 00000000000..f8b6dc82742 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/init/not_generic.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 4-11: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m. 'init' function cannot have type parameters"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/init/not_generic.mvir b/crates/iota-verifier-transactional-tests/tests/init/not_generic.mvir similarity index 81% rename from crates/sui-verifier-transactional-tests/tests/init/not_generic.mvir rename to crates/iota-verifier-transactional-tests/tests/init/not_generic.mvir index 749d1344727..87c364e369e 100644 --- a/crates/sui-verifier-transactional-tests/tests/init/not_generic.mvir +++ b/crates/iota-verifier-transactional-tests/tests/init/not_generic.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/init/not_private.exp b/crates/iota-verifier-transactional-tests/tests/init/not_private.exp new file mode 100644 index 00000000000..689a7a7e1f3 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/init/not_private.exp @@ -0,0 +1,13 @@ +processed 3 tasks + +task 0 'publish'. lines 4-11: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m. 'init' function must be private"), command: Some(0) } } + +task 1 'publish'. lines 13-20: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m. 'init' function must be private"), command: Some(0) } } + +task 2 'publish'. lines 22-29: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m. 'init' function must be private"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/init/not_private.mvir b/crates/iota-verifier-transactional-tests/tests/init/not_private.mvir similarity index 91% rename from crates/sui-verifier-transactional-tests/tests/init/not_private.mvir rename to crates/iota-verifier-transactional-tests/tests/init/not_private.mvir index 50a86e61d16..30ff566141b 100644 --- a/crates/sui-verifier-transactional-tests/tests/init/not_private.mvir +++ b/crates/iota-verifier-transactional-tests/tests/init/not_private.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/init/not_txn_context.exp b/crates/iota-verifier-transactional-tests/tests/init/not_txn_context.exp new file mode 100644 index 00000000000..1b07a77b5c3 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/init/not_txn_context.exp @@ -0,0 +1,13 @@ +processed 3 tasks + +task 0 'publish'. lines 4-11: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Expected last parameter for _::m::init to be &mut iota::tx_context::TxContext or &iota::tx_context::TxContext, but found u64"), command: Some(0) } } + +task 1 'publish'. lines 13-20: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Expected last parameter for _::tx_context::init to be &mut iota::tx_context::TxContext or &iota::tx_context::TxContext, but found _::tx_context::TxContext"), command: Some(0) } } + +task 2 'publish'. lines 22-29: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Expected last parameter for _::m::init to be &mut iota::tx_context::TxContext or &iota::tx_context::TxContext, but found iota::tx_context::TxContext"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/init/not_txn_context.mvir b/crates/iota-verifier-transactional-tests/tests/init/not_txn_context.mvir similarity index 90% rename from crates/sui-verifier-transactional-tests/tests/init/not_txn_context.mvir rename to crates/iota-verifier-transactional-tests/tests/init/not_txn_context.mvir index ee967ae710b..8a51782d7f2 100644 --- a/crates/sui-verifier-transactional-tests/tests/init/not_txn_context.mvir +++ b/crates/iota-verifier-transactional-tests/tests/init/not_txn_context.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/init/ok.exp b/crates/iota-verifier-transactional-tests/tests/init/ok.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/init/ok.exp rename to crates/iota-verifier-transactional-tests/tests/init/ok.exp diff --git a/crates/iota-verifier-transactional-tests/tests/init/ok.mvir b/crates/iota-verifier-transactional-tests/tests/init/ok.mvir new file mode 100644 index 00000000000..21b2492fb57 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/init/ok.mvir @@ -0,0 +1,12 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# publish +module 0x0.m { + import 0x2.tx_context; + init(ctx: &mut tx_context.TxContext) { + label l0: + abort 0; + } +} diff --git a/crates/iota-verifier-transactional-tests/tests/init/return_values.exp b/crates/iota-verifier-transactional-tests/tests/init/return_values.exp new file mode 100644 index 00000000000..35eebd67d92 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/init/return_values.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 4-11: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m, 'init' function cannot have return values"), command: Some(0) } } diff --git a/crates/iota-verifier-transactional-tests/tests/init/return_values.mvir b/crates/iota-verifier-transactional-tests/tests/init/return_values.mvir new file mode 100644 index 00000000000..c6a48a7d4ff --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/init/return_values.mvir @@ -0,0 +1,12 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//# publish +module 0x0.m { + import 0x2.tx_context; + init(ctx: &mut tx_context.TxContext): u64 { + label l0: + abort 0; + } +} diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/bool_field.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/bool_field.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/bool_field.exp rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/bool_field.exp diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/bool_field.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/bool_field.mvir similarity index 86% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/bool_field.mvir rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/bool_field.mvir index d43a0a53461..c6f8cbe7a88 100644 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/bool_field.mvir +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/bool_field.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // correct, bool field specified at source level diff --git a/crates/iota-verifier-transactional-tests/tests/one_time_witness/instantiate.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/instantiate.exp new file mode 100644 index 00000000000..ca85d375f7c --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/instantiate.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-24: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("one-time witness type _::m::M is instantiated in the _::m::pack function and must never be"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/instantiate.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/instantiate.mvir similarity index 88% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/instantiate.mvir rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/instantiate.mvir index 8af27b822ee..2aa76dc5932 100644 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/instantiate.mvir +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/instantiate.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, otw type instantiated diff --git a/crates/iota-verifier-transactional-tests/tests/one_time_witness/many_fields_invalid.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/many_fields_invalid.exp new file mode 100644 index 00000000000..4184bd771c8 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/many_fields_invalid.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-16: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Expected last (and at most second) parameter for _::m::init to be &mut iota::tx_context::TxContext or &iota::tx_context::TxContext; optional first parameter must be of one-time witness type whose name is the same as the capitalized module name (_::m::M) and which has no fields or a single field of type bool"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/many_fields_invalid.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/many_fields_invalid.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/many_fields_invalid.mvir rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/many_fields_invalid.mvir index 5ef733b9688..1082c74cd08 100644 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/many_fields_invalid.mvir +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/many_fields_invalid.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Incorrect, more than one field means not a OTW diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/many_fields_valid.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/many_fields_valid.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/many_fields_valid.exp rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/many_fields_valid.exp diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/many_fields_valid.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/many_fields_valid.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/many_fields_valid.mvir rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/many_fields_valid.mvir index f7d33c5d52f..e1cb496ccd9 100644 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/many_fields_valid.mvir +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/many_fields_valid.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Since it is not a OTW (because of the multiple fields), we can pack it diff --git a/crates/iota-verifier-transactional-tests/tests/one_time_witness/more_abilities.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/more_abilities.exp new file mode 100644 index 00000000000..e0227122370 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/more_abilities.exp @@ -0,0 +1,13 @@ +processed 4 tasks + +task 1 'publish'. lines 8-19: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("one-time witness type candidate _::m::M must have a single ability: drop"), command: Some(0) } } + +task 2 'publish'. lines 21-32: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("one-time witness type candidate _::m::M must have a single ability: drop"), command: Some(0) } } + +task 3 'publish'. lines 34-45: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("one-time witness type candidate _::m::M must have a single ability: drop"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/more_abilities.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/more_abilities.mvir similarity index 93% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/more_abilities.mvir rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/more_abilities.mvir index 84d8c10cc87..639149bbef1 100644 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/more_abilities.mvir +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/more_abilities.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, struct type has abilities beyond drop diff --git a/crates/iota-verifier-transactional-tests/tests/one_time_witness/no_drop.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/no_drop.exp new file mode 100644 index 00000000000..18418fe38f9 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/no_drop.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-18: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("one-time witness type candidate _::m::M must have a single ability: drop"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/no_drop.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/no_drop.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/no_drop.mvir rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/no_drop.mvir index 9145cb43247..1aefaaf4cbf 100644 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/no_drop.mvir +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/no_drop.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, one-time witness type has no drop ability diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/no_field.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/no_field.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/no_field.exp rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/no_field.exp diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/no_field.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/no_field.mvir similarity index 85% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/no_field.mvir rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/no_field.mvir index e148af214cb..0f6ad1862e8 100644 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/no_field.mvir +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/no_field.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // structs must have a field diff --git a/crates/iota-verifier-transactional-tests/tests/one_time_witness/no_init_arg.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/no_init_arg.exp new file mode 100644 index 00000000000..4a02dc8e6fc --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/no_init_arg.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-16: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("init function of a module containing one-time witness type candidate must have _::m::M as the first parameter (a struct which has no fields or a single field of type bool)"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/no_init_arg.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/no_init_arg.mvir similarity index 86% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/no_init_arg.mvir rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/no_init_arg.mvir index 248c47a90b6..64e9ac08644 100644 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/no_init_arg.mvir +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/no_init_arg.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, no one-time witness type parameter in init diff --git a/crates/iota-verifier-transactional-tests/tests/one_time_witness/other_mod_def.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/other_mod_def.exp new file mode 100644 index 00000000000..b8f329ccc00 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/other_mod_def.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-16: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Expected last (and at most second) parameter for _::n::init to be &mut iota::tx_context::TxContext or &iota::tx_context::TxContext; optional first parameter must be of one-time witness type whose name is the same as the capitalized module name (_::n::N) and which has no fields or a single field of type bool"), command: Some(0) } } diff --git a/crates/iota-verifier-transactional-tests/tests/one_time_witness/other_mod_def.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/other_mod_def.mvir new file mode 100644 index 00000000000..2249dc514eb --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/other_mod_def.mvir @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// invalid, one-time witness type candidate used in a different module + +//# publish +module 0x0.n { + import 0x2.iota; + import 0x2.tx_context; + + init(_otw: iota.IOTA, _ctx: &mut tx_context.TxContext) { + label l0: + return; + } + +} diff --git a/crates/iota-verifier-transactional-tests/tests/one_time_witness/type_param.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/type_param.exp new file mode 100644 index 00000000000..e58326f3d23 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/type_param.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-16: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m. 'init' function cannot have type parameters"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/type_param.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/type_param.mvir similarity index 86% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/type_param.mvir rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/type_param.mvir index c6e22c98f4a..c530160f9ab 100644 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/type_param.mvir +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/type_param.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, struct type has type param diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_field_type.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_field_type.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_field_type.exp rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_field_type.exp diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_field_type.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_field_type.mvir similarity index 94% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_field_type.mvir rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_field_type.mvir index 2333ef797ae..66dcba57ec9 100644 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_field_type.mvir +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_field_type.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // correct, wrong struct field type but not one-time witness candidate diff --git a/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_field_type_with_init.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_field_type_with_init.exp new file mode 100644 index 00000000000..4184bd771c8 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_field_type_with_init.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-16: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Expected last (and at most second) parameter for _::m::init to be &mut iota::tx_context::TxContext or &iota::tx_context::TxContext; optional first parameter must be of one-time witness type whose name is the same as the capitalized module name (_::m::M) and which has no fields or a single field of type bool"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_field_type_with_init.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_field_type_with_init.mvir similarity index 85% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_field_type_with_init.mvir rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_field_type_with_init.mvir index b1d414ca716..b59518fedb0 100644 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_field_type_with_init.mvir +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_field_type_with_init.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, wrong struct field type diff --git a/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_init_type.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_init_type.exp new file mode 100644 index 00000000000..92dbfabaccb --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_init_type.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-17: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("init function of a module containing one-time witness type candidate must have _::m::M as the first parameter (a struct which has no fields or a single field of type bool)"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_init_type.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_init_type.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_init_type.mvir rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_init_type.mvir index c6c2094a690..819d0103e5a 100644 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_init_type.mvir +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_init_type.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, wrong type of the init function's first param diff --git a/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_name.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_name.exp new file mode 100644 index 00000000000..4184bd771c8 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_name.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-16: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Expected last (and at most second) parameter for _::m::init to be &mut iota::tx_context::TxContext or &iota::tx_context::TxContext; optional first parameter must be of one-time witness type whose name is the same as the capitalized module name (_::m::M) and which has no fields or a single field of type bool"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_name.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_name.mvir similarity index 87% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_name.mvir rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_name.mvir index 92858702606..54a44d2c111 100644 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_name.mvir +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_name.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, wrong one-time witness type name diff --git a/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_name_format.exp b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_name_format.exp new file mode 100644 index 00000000000..a2081c54fcf --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_name_format.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 6-16: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("Expected last (and at most second) parameter for _::mod::init to be &mut iota::tx_context::TxContext or &iota::tx_context::TxContext; optional first parameter must be of one-time witness type whose name is the same as the capitalized module name (_::mod::MOD) and which has no fields or a single field of type bool"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_name_format.mvir b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_name_format.mvir similarity index 86% rename from crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_name_format.mvir rename to crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_name_format.mvir index 4d1433e6208..c097dc220ad 100644 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_name_format.mvir +++ b/crates/iota-verifier-transactional-tests/tests/one_time_witness/wrong_name_format.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // invalid, wrong one-time witness type name format diff --git a/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer.exp b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer.exp new file mode 100644 index 00000000000..b779e372e8e --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer.exp @@ -0,0 +1,17 @@ +processed 4 tasks + +task 0 'publish'. lines 6-16: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::transfer' on an object of type 'iota::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_transfer'"), command: Some(0) } } + +task 1 'publish'. lines 18-28: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::freeze_object' on an object of type 'iota::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_freeze_object'"), command: Some(0) } } + +task 2 'publish'. lines 30-40: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::share_object' on an object of type 'iota::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_share_object'"), command: Some(0) } } + +task 3 'publish'. lines 42-54: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::receive' on an object of type 'iota::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_receive'"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer.mvir b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer.mvir similarity index 95% rename from crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer.mvir rename to crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer.mvir index 4586da5c13d..04e04b64384 100644 --- a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer.mvir +++ b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests modules cannot use transfer internal functions outside of the defining module diff --git a/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_generic.exp b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_generic.exp new file mode 100644 index 00000000000..05f21055948 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_generic.exp @@ -0,0 +1,17 @@ +processed 4 tasks + +task 0 'publish'. lines 8-17: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::transfer' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_transfer'"), command: Some(0) } } + +task 1 'publish'. lines 19-28: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::freeze_object' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_freeze_object'"), command: Some(0) } } + +task 2 'publish'. lines 30-39: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::share_object' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_share_object'"), command: Some(0) } } + +task 3 'publish'. lines 41-52: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::receive' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_receive'"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_generic.mvir b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_generic.mvir similarity index 95% rename from crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_generic.mvir rename to crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_generic.mvir index 3a5b28342dd..7d77a071ce1 100644 --- a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_generic.mvir +++ b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_generic.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests modules cannot use transfer internal functions outside of the defining module diff --git a/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_store.exp b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_store.exp new file mode 100644 index 00000000000..b779e372e8e --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_store.exp @@ -0,0 +1,17 @@ +processed 4 tasks + +task 0 'publish'. lines 6-16: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::transfer' on an object of type 'iota::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_transfer'"), command: Some(0) } } + +task 1 'publish'. lines 18-28: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::freeze_object' on an object of type 'iota::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_freeze_object'"), command: Some(0) } } + +task 2 'publish'. lines 30-40: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::share_object' on an object of type 'iota::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_share_object'"), command: Some(0) } } + +task 3 'publish'. lines 42-54: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::receive' on an object of type 'iota::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_receive'"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_store.mvir b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_store.mvir similarity index 95% rename from crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_store.mvir rename to crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_store.mvir index 4586da5c13d..04e04b64384 100644 --- a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_store.mvir +++ b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_store.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests modules cannot use transfer internal functions outside of the defining module diff --git a/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_store_generic.exp b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_store_generic.exp new file mode 100644 index 00000000000..1f220473bd4 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_store_generic.exp @@ -0,0 +1,17 @@ +processed 5 tasks + +task 1 'publish'. lines 10-19: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::transfer' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_transfer'"), command: Some(0) } } + +task 2 'publish'. lines 21-30: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::freeze_object' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_freeze_object'"), command: Some(0) } } + +task 3 'publish'. lines 32-41: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::share_object' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_share_object'"), command: Some(0) } } + +task 4 'publish'. lines 43-54: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::receive' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_receive'"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_store_generic.mvir b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_store_generic.mvir similarity index 95% rename from crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_store_generic.mvir rename to crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_store_generic.mvir index d6349839bee..667204ef97d 100644 --- a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_store_generic.mvir +++ b/crates/iota-verifier-transactional-tests/tests/private_generics/no_public_transfer_store_generic.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests modules cannot use transfer internal functions outside of the defining module diff --git a/crates/iota-verifier-transactional-tests/tests/private_generics/private_event_emit.exp b/crates/iota-verifier-transactional-tests/tests/private_generics/private_event_emit.exp new file mode 100644 index 00000000000..2b71216ff42 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/private_generics/private_event_emit.exp @@ -0,0 +1,17 @@ +processed 4 tasks + +task 0 'publish'. lines 6-16: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::event::emit' with an event type 'iota::coin::CurrencyCreated'. The event's type must be defined in the current module"), command: Some(0) } } + +task 1 'publish'. lines 18-27: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::event::emit' with an event type 'T0'. The event's type must be defined in the current module"), command: Some(0) } } + +task 2 'publish'. lines 29-38: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::event::emit' with an event type 'u64'. The event's type must be defined in the current module"), command: Some(0) } } + +task 3 'publish'. lines 40-53: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::event::emit' with an event type 'vector<_::m::X>'. The event's type must be defined in the current module"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/private_event_emit.mvir b/crates/iota-verifier-transactional-tests/tests/private_generics/private_event_emit.mvir similarity index 94% rename from crates/sui-verifier-transactional-tests/tests/private_generics/private_event_emit.mvir rename to crates/iota-verifier-transactional-tests/tests/private_generics/private_event_emit.mvir index 59bc4322529..f09dde0fc33 100644 --- a/crates/sui-verifier-transactional-tests/tests/private_generics/private_event_emit.mvir +++ b/crates/iota-verifier-transactional-tests/tests/private_generics/private_event_emit.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests modules cannot emit events for types not defined in the current module diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/public_transfer_with_store.exp b/crates/iota-verifier-transactional-tests/tests/private_generics/public_transfer_with_store.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/private_generics/public_transfer_with_store.exp rename to crates/iota-verifier-transactional-tests/tests/private_generics/public_transfer_with_store.exp diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/public_transfer_with_store.mvir b/crates/iota-verifier-transactional-tests/tests/private_generics/public_transfer_with_store.mvir similarity index 95% rename from crates/sui-verifier-transactional-tests/tests/private_generics/public_transfer_with_store.mvir rename to crates/iota-verifier-transactional-tests/tests/private_generics/public_transfer_with_store.mvir index 79a5c248bf3..aff87546465 100644 --- a/crates/sui-verifier-transactional-tests/tests/private_generics/public_transfer_with_store.mvir +++ b/crates/iota-verifier-transactional-tests/tests/private_generics/public_transfer_with_store.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests modules can use transfer functions outside of the defining module, if the type diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/public_transfer_with_store_generic.exp b/crates/iota-verifier-transactional-tests/tests/private_generics/public_transfer_with_store_generic.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/private_generics/public_transfer_with_store_generic.exp rename to crates/iota-verifier-transactional-tests/tests/private_generics/public_transfer_with_store_generic.exp diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/public_transfer_with_store_generic.mvir b/crates/iota-verifier-transactional-tests/tests/private_generics/public_transfer_with_store_generic.mvir similarity index 97% rename from crates/sui-verifier-transactional-tests/tests/private_generics/public_transfer_with_store_generic.mvir rename to crates/iota-verifier-transactional-tests/tests/private_generics/public_transfer_with_store_generic.mvir index e8959558e86..241c2ad3715 100644 --- a/crates/sui-verifier-transactional-tests/tests/private_generics/public_transfer_with_store_generic.mvir +++ b/crates/iota-verifier-transactional-tests/tests/private_generics/public_transfer_with_store_generic.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // tests modules can use transfer functions outside of the defining module, if the type diff --git a/crates/iota-verifier-transactional-tests/tests/private_generics/receive_with_and_without_store.exp b/crates/iota-verifier-transactional-tests/tests/private_generics/receive_with_and_without_store.exp new file mode 100644 index 00000000000..cb899c2c035 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/private_generics/receive_with_and_without_store.exp @@ -0,0 +1,19 @@ +processed 4 tasks + +task 0 'publish'. lines 1-12: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::receive_bad. Invalid call to 'iota::transfer::receive' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_receive'"), command: Some(0) } } + +task 1 'publish'. lines 14-25: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m1::receive_bad. Invalid call to 'iota::transfer::receive' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_receive'"), command: Some(0) } } + +task 2 'publish'. lines 27-41: +created: object(3,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 4848800, storage_rebate: 978120, non_refundable_storage_fee: 9880 + +task 3 'publish'. lines 43-54: +created: object(4,0) +mutated: object(0,0) +gas summary: computation_cost: 1000000, storage_cost: 4430800, storage_rebate: 978120, non_refundable_storage_fee: 9880 diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/receive_with_and_without_store.mvir b/crates/iota-verifier-transactional-tests/tests/private_generics/receive_with_and_without_store.mvir similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/private_generics/receive_with_and_without_store.mvir rename to crates/iota-verifier-transactional-tests/tests/private_generics/receive_with_and_without_store.mvir diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/receive_without_key.exp b/crates/iota-verifier-transactional-tests/tests/private_generics/receive_without_key.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/private_generics/receive_without_key.exp rename to crates/iota-verifier-transactional-tests/tests/private_generics/receive_without_key.exp diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/receive_without_key.mvir b/crates/iota-verifier-transactional-tests/tests/private_generics/receive_without_key.mvir similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/private_generics/receive_without_key.mvir rename to crates/iota-verifier-transactional-tests/tests/private_generics/receive_without_key.mvir diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/receive_without_key_version30.exp b/crates/iota-verifier-transactional-tests/tests/private_generics/receive_without_key_version30.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/private_generics/receive_without_key_version30.exp rename to crates/iota-verifier-transactional-tests/tests/private_generics/receive_without_key_version30.exp diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/receive_without_key_version30.mvir b/crates/iota-verifier-transactional-tests/tests/private_generics/receive_without_key_version30.mvir similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/private_generics/receive_without_key_version30.mvir rename to crates/iota-verifier-transactional-tests/tests/private_generics/receive_without_key_version30.mvir diff --git a/crates/iota-verifier-transactional-tests/tests/private_transfer/transfer_invalid.exp b/crates/iota-verifier-transactional-tests/tests/private_transfer/transfer_invalid.exp new file mode 100644 index 00000000000..00eccaa8aa6 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/private_transfer/transfer_invalid.exp @@ -0,0 +1,17 @@ +processed 4 tasks + +task 0 'publish'. lines 6-16: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::transfer' on an object of type 'iota::clock::Clock'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_transfer'"), command: Some(0) } } + +task 1 'publish'. lines 18-28: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::share_object' on an object of type 'iota::clock::Clock'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_share_object'"), command: Some(0) } } + +task 2 'publish'. lines 30-40: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::freeze_object' on an object of type 'iota::clock::Clock'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_freeze_object'"), command: Some(0) } } + +task 3 'publish'. lines 42-54: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("_::m::t. Invalid call to 'iota::transfer::receive' on an object of type 'iota::clock::Clock'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'iota::transfer::public_receive'"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/private_transfer/transfer_invalid.mvir b/crates/iota-verifier-transactional-tests/tests/private_transfer/transfer_invalid.mvir similarity index 95% rename from crates/sui-verifier-transactional-tests/tests/private_transfer/transfer_invalid.mvir rename to crates/iota-verifier-transactional-tests/tests/private_transfer/transfer_invalid.mvir index cea2e521809..e68ddcecf4b 100644 --- a/crates/sui-verifier-transactional-tests/tests/private_transfer/transfer_invalid.mvir +++ b/crates/iota-verifier-transactional-tests/tests/private_transfer/transfer_invalid.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // clock has only key ability diff --git a/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_first_field_not_id.exp b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_first_field_not_id.exp new file mode 100644 index 00000000000..c8d00dc9f4d --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_first_field_not_id.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 4-10: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("First field of struct S must be 'id', flag found"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_first_field_not_id.mvir b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_first_field_not_id.mvir similarity index 77% rename from crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_first_field_not_id.mvir rename to crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_first_field_not_id.mvir index 31dc2ce8746..61075802f15 100644 --- a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_first_field_not_id.mvir +++ b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_first_field_not_id.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_address.exp b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_address.exp new file mode 100644 index 00000000000..47511bb11b5 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_address.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 4-11: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("First field of struct S must be of type iota::object::UID, _::object::UID type found"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_address.mvir b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_address.mvir similarity index 81% rename from crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_address.mvir rename to crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_address.mvir index 25b077c5098..d2acc7ee168 100644 --- a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_address.mvir +++ b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_address.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_name.exp b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_name.exp new file mode 100644 index 00000000000..83817b2d0bb --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_name.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 4-10: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("First field of struct S must be of type iota::object::UID, iota::object::ID type found"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_name.mvir b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_name.mvir similarity index 78% rename from crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_name.mvir rename to crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_name.mvir index 9e59c199368..206f0966dc5 100644 --- a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_name.mvir +++ b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_name.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_type.exp b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_type.exp new file mode 100644 index 00000000000..f8d65b119e3 --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_type.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 4-10: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("First field of struct S must be of type iota::object::UID, Bool type found"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_type.mvir b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_type.mvir similarity index 77% rename from crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_type.mvir rename to crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_type.mvir index 136f308f0ce..4e0a570aa8d 100644 --- a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_type.mvir +++ b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_type.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_valid.exp b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_valid.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_valid.exp rename to crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_valid.exp diff --git a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_valid.mvir b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_valid.mvir similarity index 78% rename from crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_valid.mvir rename to crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_valid.mvir index c7c66fe1782..f05035f1046 100644 --- a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_valid.mvir +++ b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_valid.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_second_field_id.exp b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_second_field_id.exp new file mode 100644 index 00000000000..0055712b2fe --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_second_field_id.exp @@ -0,0 +1,5 @@ +processed 1 task + +task 0 'publish'. lines 4-11: +Error: Transaction Effects Status: Iota Move Bytecode Verification Error. Please run the Iota Move Verifier for more information. +Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: IotaMoveVerificationError, source: Some("First field of struct S must be 'id', flag found"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_second_field_id.mvir b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_second_field_id.mvir similarity index 80% rename from crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_second_field_id.mvir rename to crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_second_field_id.mvir index 4c31979cfdd..c85b2597318 100644 --- a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_second_field_id.mvir +++ b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_second_field_id.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_with_drop.exp b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_with_drop.exp similarity index 100% rename from crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_with_drop.exp rename to crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_with_drop.exp diff --git a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_with_drop.mvir b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_with_drop.mvir similarity index 80% rename from crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_with_drop.mvir rename to crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_with_drop.mvir index 1e152e46e6c..5049548195f 100644 --- a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_with_drop.mvir +++ b/crates/iota-verifier-transactional-tests/tests/struct_with_key/key_struct_with_drop.mvir @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //# publish diff --git a/crates/iota-verifier-transactional-tests/tests/tests.rs b/crates/iota-verifier-transactional-tests/tests/tests.rs new file mode 100644 index 00000000000..23f2350a3fd --- /dev/null +++ b/crates/iota-verifier-transactional-tests/tests/tests.rs @@ -0,0 +1,8 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub const TEST_DIR: &str = "tests"; +use iota_transactional_test_runner::run_test; + +datatest_stable::harness!(run_test, TEST_DIR, r".*\.(mvir|move)$"); diff --git a/crates/iota/Cargo.toml b/crates/iota/Cargo.toml new file mode 100644 index 00000000000..9c79f5dcb94 --- /dev/null +++ b/crates/iota/Cargo.toml @@ -0,0 +1,115 @@ +[package] +name = "iota" +version.workspace = true +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +json_to_table.workspace = true +tabled.workspace = true +anemo.workspace = true +anyhow.workspace = true +serde.workspace = true +serde_json.workspace = true +serde_yaml.workspace = true +signature.workspace = true +camino.workspace = true +tokio = { workspace = true, features = ["full"] } +async-trait.workspace = true +tracing.workspace = true +bcs.workspace = true +clap.workspace = true +bip32.workspace = true +rand.workspace = true +tap.workspace = true +inquire.workspace = true +rusoto_core.workspace = true +rusoto_kms.workspace = true +prometheus.workspace = true +git-version.workspace = true +const-str.workspace = true +num-bigint.workspace = true +regex.workspace = true +reqwest.workspace = true +im.workspace = true +async-recursion.workspace = true +thiserror.workspace = true +miette.workspace = true +datatest-stable.workspace = true +insta.workspace = true +shlex.workspace = true + +iota-config.workspace = true +iota-execution = { path = "../../iota-execution" } +iota-swarm-config.workspace = true +iota-genesis-builder.workspace = true +iota-types.workspace = true +iota-json.workspace = true +iota-swarm.workspace = true +iota-json-rpc-types.workspace = true +iota-sdk.workspace = true +iota-keys.workspace = true +iota-source-validation.workspace = true +iota-move = { workspace = true, features = ["all"] } +iota-move-build.workspace = true +iota-protocol-config.workspace = true +shared-crypto.workspace = true +iota-replay.workspace = true +iota-transaction-builder.workspace = true +move-binary-format.workspace = true + +fastcrypto.workspace = true +fastcrypto-zkp.workspace = true + +rustyline.workspace = true +rustyline-derive.workspace = true +colored.workspace = true +unescape.workspace = true +shell-words.workspace = true + +tempfile.workspace = true +telemetry-subscribers.workspace = true + +move-core-types.workspace = true +move-package.workspace = true +csv.workspace = true +move-vm-profiler.workspace = true +move-command-line-common.workspace = true + +[target.'cfg(not(target_env = "msvc"))'.dependencies] +jemalloc-ctl.workspace = true + +[dev-dependencies] +prometheus.workspace = true +fs_extra.workspace = true +expect-test.workspace = true +assert_cmd.workspace = true + +test-cluster.workspace = true +iota-macros.workspace = true +iota-simulator.workspace = true +iota-test-transaction-builder.workspace = true +serde_json.workspace = true + +[target.'cfg(msim)'.dependencies] +msim.workspace = true + +[package.metadata.cargo-udeps.ignore] +normal = ["jemalloc-ctl"] + +[[example]] +name = "generate-genesis-checkpoint" +path = "src/generate_genesis_checkpoint.rs" +test = false + +[[test]] +name = "ptb_files_tests" +harness = false + +[features] +gas-profiler = [ + "iota-types/gas-profiler", + "iota-execution/gas-profiler", +] diff --git a/crates/iota/genesis.md b/crates/iota/genesis.md new file mode 100644 index 00000000000..26251a4af13 --- /dev/null +++ b/crates/iota/genesis.md @@ -0,0 +1,105 @@ +# Genesis Ceremony + +This document lays out the step-by-step process for orchestrating a Iota Genesis Ceremony. + +## Prerequisites + +Each validator participating in the ceremony will need the following: + +- Ed25519 Public key +- Iota network address // WAN +- Narwhal_primary_to_primary network address // WAN +- Narwhal_worker_to_primary network address // LAN +- Narwhal_primary_to_worker network address // LAN +- Narwhal_worker_to_worker network address // WAN +- Narwhal_consensus_address network address // LAN + +Note: +- Network addresses should be Multiaddrs in the form of `/dns/{dns name}/tcp/{port}/http` and +only the addresses marked WAN need to be publicly accessible by the wider internet. +- An Ed25519 key can be created using `iota keytool generate` + +## Ceremony + +1. Creation of a shared workspace + +To start, you'll need to create a shared workspace where all validators will be able to share their +information. For these instructions, we'll assume that such a shared workspace is created and managed +using a git repository hosted on git hosting provider. + +The MC (Master of Ceremony) will create a new git repository and initialize the directory: + +``` +$ git init genesis && cd genesis +$ iota genesis-ceremony +$ git add . +$ git commit -m "init genesis" +$ git push +``` + +2. Contribute Validator information + +Once the shared workspace has been initialized, each validator can contribute their information: + +``` +$ git clone && cd genesis +$ iota genesis-ceremony add-validator \ + --name \ + --key-file \ + --network-address \ + --narwhal-primary-to-primary \ + --narwhal-worker-to-primary \ + --narwhal-primary-to-worker \ + --narwhal-worker-to-worker \ + --narwhal-consensus-address + +$ git add . +$ git commit -m "add validator 's information" +$ git push # either to the shared workspace or another branch followed by a PR +``` + +3. Add Initial Gas Objects + +Add configuration for any initial gas objects that should be created at genesis. + +``` +$ iota genesis-ceremony add-gas-object \ + --address \ + --object-id \ + --valud <# of iota coins> +$ git add . +$ git commit -m "add gas object" +$ git push +``` + +4. Build Genesis + +Once all validators and gas objects have been added, the MC can build the genesis object: + +``` +$ iota genesis-ceremony build +$ git add . +$ git commit -m "build genesis" +$ git push +``` + +5. Verify and Sign Genesis + +Once genesis is built each validator will need to verify and sign genesis: + +``` +$ iota genesis-ceremony verify-and-sign \ + --key-file +$ git add . +$ git commit -m "sign genesis" +$ git push +``` + +6. Finalize Genesis + +Once all validators have successfully verified and signed genesis, the MC can finalize the ceremony +and then the genesis state can be distributed: + +``` +$ iota genesis-ceremony finalize +``` diff --git a/crates/sui/src/client_commands.rs b/crates/iota/src/client_commands.rs similarity index 84% rename from crates/sui/src/client_commands.rs rename to crates/iota/src/client_commands.rs index 54ec568e2a5..94a2d857d62 100644 --- a/crates/sui/src/client_commands.rs +++ b/crates/iota/src/client_commands.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -18,51 +19,52 @@ use fastcrypto::{ encoding::{Base64, Encoding}, traits::ToFromBytes, }; -use json_to_table::json_to_table; -use move_binary_format::CompiledModule; -use move_core_types::language_storage::TypeTag; -use move_package::BuildConfig as MoveBuildConfig; -use prometheus::Registry; -use serde::Serialize; -use serde_json::{json, Value}; -use shared_crypto::intent::Intent; -use sui_execution::verifier::VerifierOverrides; -use sui_json::SuiJsonValue; -use sui_json_rpc_types::{ - Coin, DynamicFieldPage, SuiCoinMetadata, SuiData, SuiExecutionStatus, SuiObjectData, - SuiObjectDataOptions, SuiObjectResponse, SuiObjectResponseQuery, SuiParsedData, SuiRawData, - SuiTransactionBlockEffectsAPI, SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, +use iota_execution::verifier::VerifierOverrides; +use iota_json::IotaJsonValue; +use iota_json_rpc_types::{ + Coin, DynamicFieldPage, IotaCoinMetadata, IotaData, IotaExecutionStatus, IotaObjectData, + IotaObjectDataOptions, IotaObjectResponse, IotaObjectResponseQuery, IotaParsedData, + IotaRawData, IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponse, + IotaTransactionBlockResponseOptions, }; -use sui_keys::keystore::AccountKeystore; -use sui_move::build::resolve_lock_file_path; -use sui_move_build::{ +use iota_keys::keystore::AccountKeystore; +use iota_move::build::resolve_lock_file_path; +use iota_move_build::{ build_from_resolution_graph, check_invalid_dependencies, check_unpublished_dependencies, gather_published_ids, BuildConfig, CompiledPackage, PackageDependencies, PublishedAtError, }; -use sui_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; -use sui_replay::ReplayToolCommand; -use sui_sdk::{ +use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; +use iota_replay::ReplayToolCommand; +use iota_sdk::{ apis::ReadApi, - sui_client_config::{SuiClientConfig, SuiEnv}, + iota_client_config::{IotaClientConfig, IotaEnv}, wallet_context::WalletContext, - SUI_COIN_TYPE, SUI_DEVNET_URL, SUI_LOCAL_NETWORK_URL, SUI_TESTNET_URL, + IOTA_COIN_TYPE, IOTA_DEVNET_URL, IOTA_LOCAL_NETWORK_URL, IOTA_TESTNET_URL, }; -use sui_source_validation::{BytecodeSourceVerifier, SourceMode}; -use sui_types::{ - base_types::{ObjectID, SequenceNumber, SuiAddress}, +use iota_source_validation::{BytecodeSourceVerifier, SourceMode}; +use iota_types::{ + base_types::{IotaAddress, ObjectID, SequenceNumber}, crypto::{EmptySignInfo, SignatureScheme}, digests::TransactionDigest, dynamic_field::DynamicFieldInfo, - error::SuiError, + error::IotaError, gas_coin::GasCoin, message_envelope::Envelope, metrics::BytecodeVerifierMetrics, move_package::UpgradeCap, object::Owner, - parse_sui_type_tag, + parse_iota_type_tag, signature::GenericSignature, transaction::{SenderSignedData, Transaction, TransactionData, TransactionDataAPI}, }; +use json_to_table::json_to_table; +use move_binary_format::CompiledModule; +use move_core_types::language_storage::TypeTag; +use move_package::BuildConfig as MoveBuildConfig; +use prometheus::Registry; +use serde::Serialize; +use serde_json::{json, Value}; +use shared_crypto::intent::Intent; use tabled::{ builder::Builder as TableBuilder, settings::{ @@ -89,33 +91,33 @@ macro_rules! serialize_or_execute { "Cannot specify both --serialize-unsigned-transaction and --serialize-signed-transaction" ); if $serialize_unsigned { - SuiClientCommandResult::SerializedUnsignedTransaction($tx_data) + IotaClientCommandResult::SerializedUnsignedTransaction($tx_data) } else { let signature = $context.config.keystore.sign_secure( &$tx_data.sender(), &$tx_data, - Intent::sui_transaction(), + Intent::iota_transaction(), )?; let sender_signed_data = SenderSignedData::new_from_sender_signature( $tx_data, - Intent::sui_transaction(), + Intent::iota_transaction(), signature, ); if $serialize_signed { - SuiClientCommandResult::SerializedSignedTransaction(sender_signed_data) + IotaClientCommandResult::SerializedSignedTransaction(sender_signed_data) } else { let transaction = Transaction::new(sender_signed_data); let response = $context.execute_transaction_may_fail(transaction).await?; let effects = response.effects.as_ref().ok_or_else(|| { - anyhow!("Effects from SuiTransactionBlockResult should not be empty") + anyhow!("Effects from IotaTransactionBlockResult should not be empty") })?; - if matches!(effects.status(), SuiExecutionStatus::Failure { .. }) { + if matches!(effects.status(), IotaExecutionStatus::Failure { .. }) { return Err(anyhow!( "Error executing transaction: {:#?}", effects.status() )); } - SuiClientCommandResult::$result_variant(response) + IotaClientCommandResult::$result_variant(response) } } }}; @@ -123,7 +125,7 @@ macro_rules! serialize_or_execute { #[derive(Parser)] #[clap(rename_all = "kebab-case")] -pub enum SuiClientCommands { +pub enum IotaClientCommands { /// Default address used for commands when none specified #[clap(name = "active-address")] ActiveAddress, @@ -143,7 +145,7 @@ pub enum SuiClientCommands { /// Address (or its alias) #[arg(value_parser)] address: Option, - /// Show balance for the specified coin (e.g., 0x2::sui::SUI). + /// Show balance for the specified coin (e.g., 0x2::iota::IOTA). /// All coins will be shown if none is passed. #[clap(long, required = false)] coin_type: Option, @@ -167,14 +169,14 @@ pub enum SuiClientCommands { /// All must be specified, or the call will fail. #[clap( long, - value_parser = parse_sui_type_tag, + value_parser = parse_iota_type_tag, num_args(1..), )] type_args: Vec, /// Simplified ordered args like in the function syntax /// ObjectIDs, Addresses must be hex strings #[clap(long, num_args(1..))] - args: Vec, + args: Vec, /// ID of the gas object for gas payment, in 20 bytes Hex string #[clap(long)] /// If not provided, a gas object with at least gas_budget value will be @@ -193,7 +195,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// unsigned transaction data (TransactionData) using base64 /// encoding, and print out the string . The string can - /// be used to execute transaction with `sui client execute-signed-tx + /// be used to execute transaction with `iota client execute-signed-tx /// --tx-bytes `. #[clap(long, required = false)] serialize_unsigned_transaction: bool, @@ -201,7 +203,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// signed transaction data (SenderSignedData) using base64 /// encoding, and print out the string . The string - /// can be used to execute transaction with `sui client + /// can be used to execute transaction with `iota client /// execute-combined-signed-tx --signed-tx-bytes /// `. #[clap(long, required = false)] @@ -226,14 +228,14 @@ pub enum SuiClientCommands { limit: usize, }, - /// List all Sui environments + /// List all Iota environments Envs, /// Execute a Signed Transaction. This is useful when the user prefers to /// sign elsewhere and use this command to execute. ExecuteSignedTx { /// BCS serialized transaction data bytes without its type tag, as - /// base64 encoded string. This is the output of sui client command + /// base64 encoded string. This is the output of iota client command /// using --serialize-unsigned-transaction. #[clap(long)] tx_bytes: String, @@ -245,7 +247,7 @@ pub enum SuiClientCommands { /// Execute a combined serialized SenderSignedData string. ExecuteCombinedSignedTx { /// BCS serialized sender signed data, as base64 encoded string. This is - /// the output of sui client command using + /// the output of iota client command using /// --serialize-signed-transaction. #[clap(long)] signed_tx_bytes: String, @@ -294,7 +296,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// unsigned transaction data (TransactionData) using base64 /// encoding, and print out the string . The string can - /// be used to execute transaction with `sui client execute-signed-tx + /// be used to execute transaction with `iota client execute-signed-tx /// --tx-bytes `. #[clap(long, required = false)] serialize_unsigned_transaction: bool, @@ -302,7 +304,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// signed transaction data (SenderSignedData) using base64 /// encoding, and print out the string . The string - /// can be used to execute transaction with `sui client + /// can be used to execute transaction with `iota client /// execute-combined-signed-tx --signed-tx-bytes /// `. #[clap(long, required = false)] @@ -324,7 +326,7 @@ pub enum SuiClientCommands { derivation_path: Option, }, - /// Add new Sui environment. + /// Add new Iota environment. #[clap(name = "new-env")] NewEnv { #[clap(long)] @@ -351,7 +353,7 @@ pub enum SuiClientCommands { #[clap(name = "objects")] Objects { /// Address owning the object. If no address is provided, it will show - /// all objects owned by `sui client active-address`. + /// all objects owned by `iota client active-address`. #[clap(name = "owner_address")] address: Option, }, @@ -386,7 +388,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// unsigned transaction data (TransactionData) using base64 /// encoding, and print out the string . The string can - /// be used to execute transaction with `sui client execute-signed-tx + /// be used to execute transaction with `iota client execute-signed-tx /// --tx-bytes `. #[clap(long, required = false)] serialize_unsigned_transaction: bool, @@ -394,17 +396,17 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// signed transaction data (SenderSignedData) using base64 /// encoding, and print out the string . The string - /// can be used to execute transaction with `sui client + /// can be used to execute transaction with `iota client /// execute-combined-signed-tx --signed-tx-bytes /// `. #[clap(long, required = false)] serialize_signed_transaction: bool, }, - /// Pay all residual SUI coins to the recipient with input coins, after + /// Pay all residual IOTA coins to the recipient with input coins, after /// deducting the gas cost. The input coins also include the coin for /// gas payment, so no extra gas coin is required. - PayAllSui { + PayAllIota { /// The input coins to be used for pay recipients, including the gas /// coin. #[clap(long, num_args(1..))] @@ -422,7 +424,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// unsigned transaction data (TransactionData) using base64 /// encoding, and print out the string . The string can - /// be used to execute transaction with `sui client execute-signed-tx + /// be used to execute transaction with `iota client execute-signed-tx /// --tx-bytes `. #[clap(long, required = false)] serialize_unsigned_transaction: bool, @@ -430,18 +432,18 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// signed transaction data (SenderSignedData) using base64 /// encoding, and print out the string . The string - /// can be used to execute transaction with `sui client + /// can be used to execute transaction with `iota client /// execute-combined-signed-tx --signed-tx-bytes /// `. #[clap(long, required = false)] serialize_signed_transaction: bool, }, - /// Pay SUI coins to recipients following following specified amounts, with + /// Pay IOTA coins to recipients following following specified amounts, with /// input coins. Length of recipients must be the same as that of /// amounts. The input coins also include the coin for gas payment, so /// no extra gas coin is required. - PaySui { + PayIota { /// The input coins to be used for pay recipients, including the gas /// coin. #[clap(long, num_args(1..))] @@ -463,7 +465,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// unsigned transaction data (TransactionData) using base64 /// encoding, and print out the string . The string can - /// be used to execute transaction with `sui client execute-signed-tx + /// be used to execute transaction with `iota client execute-signed-tx /// --tx-bytes `. #[clap(long, required = false)] serialize_unsigned_transaction: bool, @@ -471,7 +473,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// signed transaction data (SenderSignedData) using base64 /// encoding, and print out the string . The string - /// can be used to execute transaction with `sui client + /// can be used to execute transaction with `iota client /// execute-combined-signed-tx --signed-tx-bytes /// `. #[clap(long, required = false)] @@ -517,7 +519,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// unsigned transaction data (TransactionData) using base64 /// encoding, and print out the string . The string can - /// be used to execute transaction with `sui client execute-signed-tx + /// be used to execute transaction with `iota client execute-signed-tx /// --tx-bytes `. #[clap(long, required = false)] serialize_unsigned_transaction: bool, @@ -525,7 +527,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// signed transaction data (SenderSignedData) using base64 /// encoding, and print out the string . The string - /// can be used to execute transaction with `sui client + /// can be used to execute transaction with `iota client /// execute-combined-signed-tx --signed-tx-bytes /// `. #[clap(long, required = false)] @@ -556,7 +558,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// unsigned transaction data (TransactionData) using base64 /// encoding, and print out the string . The string can - /// be used to execute transaction with `sui client execute-signed-tx + /// be used to execute transaction with `iota client execute-signed-tx /// --tx-bytes `. #[clap(long, required = false)] serialize_unsigned_transaction: bool, @@ -564,7 +566,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// signed transaction data (SenderSignedData) using base64 /// encoding, and print out the string . The string - /// can be used to execute transaction with `sui client + /// can be used to execute transaction with `iota client /// execute-combined-signed-tx --signed-tx-bytes /// `. #[clap(long, required = false)] @@ -616,7 +618,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// unsigned transaction data (TransactionData) using base64 /// encoding, and print out the string . The string can - /// be used to execute transaction with `sui client execute-signed-tx + /// be used to execute transaction with `iota client execute-signed-tx /// --tx-bytes `. #[clap(long, required = false)] serialize_unsigned_transaction: bool, @@ -624,26 +626,26 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// signed transaction data (SenderSignedData) using base64 /// encoding, and print out the string . The string - /// can be used to execute transaction with `sui client + /// can be used to execute transaction with `iota client /// execute-combined-signed-tx --signed-tx-bytes /// `. #[clap(long, required = false)] serialize_signed_transaction: bool, }, - /// Transfer SUI, and pay gas with the same SUI coin object. + /// Transfer IOTA, and pay gas with the same IOTA coin object. /// If amount is specified, only the amount is transferred; otherwise the /// entire object is transferred. - #[clap(name = "transfer-sui")] - TransferSui { + #[clap(name = "transfer-iota")] + TransferIota { /// Recipient address (or its alias if it's an address in the keystore) #[clap(long)] to: KeyIdentity, - /// Sui coin object to transfer, ID in 20 bytes Hex string. This is also - /// the gas object. + /// Iota coin object to transfer, ID in 20 bytes Hex string. This is + /// also the gas object. #[clap(long)] - sui_coin_object_id: ObjectID, + iota_coin_object_id: ObjectID, /// Gas budget for this transfer #[clap(long)] @@ -657,7 +659,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// unsigned transaction data (TransactionData) using base64 /// encoding, and print out the string . The string can - /// be used to execute transaction with `sui client execute-signed-tx + /// be used to execute transaction with `iota client execute-signed-tx /// --tx-bytes `. #[clap(long, required = false)] serialize_unsigned_transaction: bool, @@ -665,7 +667,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// signed transaction data (SenderSignedData) using base64 /// encoding, and print out the string . The string - /// can be used to execute transaction with `sui client + /// can be used to execute transaction with `iota client /// execute-combined-signed-tx --signed-tx-bytes /// `. #[clap(long, required = false)] @@ -711,7 +713,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// unsigned transaction data (TransactionData) using base64 /// encoding, and print out the string . The string can - /// be used to execute transaction with `sui client execute-signed-tx + /// be used to execute transaction with `iota client execute-signed-tx /// --tx-bytes `. #[clap(long, required = false)] serialize_unsigned_transaction: bool, @@ -719,7 +721,7 @@ pub enum SuiClientCommands { /// Instead of executing the transaction, serialize the bcs bytes of the /// signed transaction data (SenderSignedData) using base64 /// encoding, and print out the string . The string - /// can be used to execute transaction with `sui client + /// can be used to execute transaction with `iota client /// execute-combined-signed-tx --signed-tx-bytes /// `. #[clap(long, required = false)] @@ -862,13 +864,13 @@ struct FaucetResponse { error: Option, } -impl SuiClientCommands { +impl IotaClientCommands { pub async fn execute( self, context: &mut WalletContext, - ) -> Result { + ) -> Result { let ret = Ok(match self { - SuiClientCommands::ProfileTransaction { + IotaClientCommands::ProfileTransaction { tx_digest, profile_output, } => { @@ -887,11 +889,11 @@ impl SuiClientCommands { }; let rpc = context.config.get_active_env()?.rpc.clone(); let _command_result = - sui_replay::execute_replay_command(Some(rpc), false, false, None, cmd).await?; + iota_replay::execute_replay_command(Some(rpc), false, false, None, cmd).await?; // this will be displayed via trace info, so no output is needed here - SuiClientCommandResult::NoOutput + IotaClientCommandResult::NoOutput } - SuiClientCommands::ReplayTransaction { + IotaClientCommands::ReplayTransaction { tx_digest, gas_info: _, ptb_info: _, @@ -908,11 +910,11 @@ impl SuiClientCommands { let rpc = context.config.get_active_env()?.rpc.clone(); let _command_result = - sui_replay::execute_replay_command(Some(rpc), false, false, None, cmd).await?; + iota_replay::execute_replay_command(Some(rpc), false, false, None, cmd).await?; // this will be displayed via trace info, so no output is needed here - SuiClientCommandResult::NoOutput + IotaClientCommandResult::NoOutput } - SuiClientCommands::ReplayBatch { + IotaClientCommands::ReplayBatch { path, terminate_early, } => { @@ -923,11 +925,11 @@ impl SuiClientCommands { }; let rpc = context.config.get_active_env()?.rpc.clone(); let _command_result = - sui_replay::execute_replay_command(Some(rpc), false, false, None, cmd).await?; + iota_replay::execute_replay_command(Some(rpc), false, false, None, cmd).await?; // this will be displayed via trace info, so no output is needed here - SuiClientCommandResult::NoOutput + IotaClientCommandResult::NoOutput } - SuiClientCommands::ReplayCheckpoints { + IotaClientCommands::ReplayCheckpoints { start, end, terminate_early, @@ -940,13 +942,13 @@ impl SuiClientCommands { }; let rpc = context.config.get_active_env()?.rpc.clone(); let _command_result = - sui_replay::execute_replay_command(Some(rpc), false, false, None, cmd).await?; + iota_replay::execute_replay_command(Some(rpc), false, false, None, cmd).await?; // this will be displayed via trace info, so no output is needed here - SuiClientCommandResult::NoOutput + IotaClientCommandResult::NoOutput } - SuiClientCommands::Addresses { sort_by_alias } => { + IotaClientCommands::Addresses { sort_by_alias } => { let active_address = context.active_address()?; - let mut addresses: Vec<(String, SuiAddress)> = context + let mut addresses: Vec<(String, IotaAddress)> = context .config .keystore .addresses_with_alias() @@ -961,9 +963,9 @@ impl SuiClientCommands { active_address, addresses, }; - SuiClientCommandResult::Addresses(output) + IotaClientCommandResult::Addresses(output) } - SuiClientCommands::Balance { + IotaClientCommands::Balance { address, coin_type, with_coins, @@ -1026,28 +1028,28 @@ impl SuiClientCommands { coins.push(c); } - let sui_type_tag = canonicalize_type(SUI_COIN_TYPE)?; + let iota_type_tag = canonicalize_type(IOTA_COIN_TYPE)?; - // show SUI first - let ordered_coins_sui_first = coins_by_type - .remove(&sui_type_tag) + // show IOTA first + let ordered_coins_iota_first = coins_by_type + .remove(&iota_type_tag) .into_iter() .chain(coins_by_type.into_values()) .collect(); - SuiClientCommandResult::Balance(ordered_coins_sui_first, with_coins) + IotaClientCommandResult::Balance(ordered_coins_iota_first, with_coins) } - SuiClientCommands::DynamicFieldQuery { id, cursor, limit } => { + IotaClientCommands::DynamicFieldQuery { id, cursor, limit } => { let client = context.get_client().await?; let df_read = client .read_api() .get_dynamic_fields(id, cursor, Some(limit)) .await?; - SuiClientCommandResult::DynamicFieldQuery(df_read) + IotaClientCommandResult::DynamicFieldQuery(df_read) } - SuiClientCommands::Upgrade { + IotaClientCommands::Upgrade { package_path, upgrade_capability, build_config, @@ -1096,7 +1098,7 @@ impl SuiClientCommands { Upgrade ) } - SuiClientCommands::Publish { + IotaClientCommands::Publish { package_path, gas, build_config, @@ -1107,7 +1109,7 @@ impl SuiClientCommands { serialize_signed_transaction, } => { if build_config.test_mode { - return Err(SuiError::ModulePublishFailure { + return Err(IotaError::ModulePublishFailure { error: "The `publish` subcommand should not be used with the `--test` flag\n\ \n\ @@ -1115,7 +1117,7 @@ impl SuiClientCommands { In order to fix this and publish the package without `--test`, \ remove any non-test dependencies on test-only code.\n\ You can ensure all test-only dependencies have been removed by \ - compiling the package normally with `sui move build`." + compiling the package normally with `iota move build`." .to_string(), } .into()); @@ -1153,7 +1155,7 @@ impl SuiClientCommands { ) } - SuiClientCommands::VerifyBytecodeMeter { + IotaClientCommands::VerifyBytecodeMeter { protocol_version, module_path, package_path, @@ -1188,7 +1190,7 @@ impl SuiClientCommands { }; let mut verifier = - sui_execution::verifier(&protocol_config, true, &bytecode_verifier_metrics); + iota_execution::verifier(&protocol_config, true, &bytecode_verifier_metrics); let overrides = VerifierOverrides::new(None, None); println!( @@ -1202,7 +1204,7 @@ impl SuiClientCommands { &protocol_config, &overrides, )?; - SuiClientCommandResult::VerifyBytecodeMeter { + IotaClientCommandResult::VerifyBytecodeMeter { max_module_ticks: verifier_values .max_per_mod_meter_current .unwrap_or(u128::MAX), @@ -1214,31 +1216,31 @@ impl SuiClientCommands { } } - SuiClientCommands::Object { id, bcs } => { + IotaClientCommands::Object { id, bcs } => { // Fetch the object ref let client = context.get_client().await?; if !bcs { let object_read = client .read_api() - .get_object_with_options(id, SuiObjectDataOptions::full_content()) + .get_object_with_options(id, IotaObjectDataOptions::full_content()) .await?; - SuiClientCommandResult::Object(object_read) + IotaClientCommandResult::Object(object_read) } else { let raw_object_read = client .read_api() - .get_object_with_options(id, SuiObjectDataOptions::bcs_lossless()) + .get_object_with_options(id, IotaObjectDataOptions::bcs_lossless()) .await?; - SuiClientCommandResult::RawObject(raw_object_read) + IotaClientCommandResult::RawObject(raw_object_read) } } - SuiClientCommands::TransactionBlock { digest } => { + IotaClientCommands::TransactionBlock { digest } => { let client = context.get_client().await?; let tx_read = client .read_api() .get_transaction_with_options( digest, - SuiTransactionBlockResponseOptions { + IotaTransactionBlockResponseOptions { show_input: true, show_raw_input: false, show_effects: true, @@ -1249,10 +1251,10 @@ impl SuiClientCommands { }, ) .await?; - SuiClientCommandResult::TransactionBlock(tx_read) + IotaClientCommandResult::TransactionBlock(tx_read) } - SuiClientCommands::Call { + IotaClientCommands::Call { package, module, function, @@ -1278,7 +1280,7 @@ impl SuiClientCommands { ) } - SuiClientCommands::Transfer { + IotaClientCommands::Transfer { to, object_id, gas, @@ -1302,9 +1304,9 @@ impl SuiClientCommands { ) } - SuiClientCommands::TransferSui { + IotaClientCommands::TransferIota { to, - sui_coin_object_id: object_id, + iota_coin_object_id: object_id, gas_budget, amount, serialize_unsigned_transaction, @@ -1315,18 +1317,18 @@ impl SuiClientCommands { let client = context.get_client().await?; let data = client .transaction_builder() - .transfer_sui(from, object_id, gas_budget, to, amount) + .transfer_iota(from, object_id, gas_budget, to, amount) .await?; serialize_or_execute!( data, serialize_unsigned_transaction, serialize_signed_transaction, context, - TransferSui + TransferIota ) } - SuiClientCommands::Pay { + IotaClientCommands::Pay { input_coins, recipients, amounts, @@ -1354,7 +1356,7 @@ impl SuiClientCommands { let recipients = recipients .into_iter() .map(|x| get_identity_address(Some(x), context)) - .collect::, anyhow::Error>>() + .collect::, anyhow::Error>>() .map_err(|e| anyhow!("{e}"))?; let from = context.get_object_owner(&input_coins[0]).await?; let client = context.get_client().await?; @@ -1371,7 +1373,7 @@ impl SuiClientCommands { ) } - SuiClientCommands::PaySui { + IotaClientCommands::PayIota { input_coins, recipients, amounts, @@ -1381,11 +1383,11 @@ impl SuiClientCommands { } => { ensure!( !input_coins.is_empty(), - "PaySui transaction requires a non-empty list of input coins" + "PayIota transaction requires a non-empty list of input coins" ); ensure!( !recipients.is_empty(), - "PaySui transaction requires a non-empty list of recipient addresses" + "PayIota transaction requires a non-empty list of recipient addresses" ); ensure!( recipients.len() == amounts.len(), @@ -1398,24 +1400,24 @@ impl SuiClientCommands { let recipients = recipients .into_iter() .map(|x| get_identity_address(Some(x), context)) - .collect::, anyhow::Error>>() + .collect::, anyhow::Error>>() .map_err(|e| anyhow!("{e}"))?; let signer = context.get_object_owner(&input_coins[0]).await?; let client = context.get_client().await?; let data = client .transaction_builder() - .pay_sui(signer, input_coins, recipients, amounts, gas_budget) + .pay_iota(signer, input_coins, recipients, amounts, gas_budget) .await?; serialize_or_execute!( data, serialize_unsigned_transaction, serialize_signed_transaction, context, - PaySui + PayIota ) } - SuiClientCommands::PayAllSui { + IotaClientCommands::PayAllIota { input_coins, recipient, gas_budget, @@ -1424,14 +1426,14 @@ impl SuiClientCommands { } => { ensure!( !input_coins.is_empty(), - "PayAllSui transaction requires a non-empty list of input coins" + "PayAllIota transaction requires a non-empty list of input coins" ); let recipient = get_identity_address(Some(recipient), context)?; let signer = context.get_object_owner(&input_coins[0]).await?; let client = context.get_client().await?; let data = client .transaction_builder() - .pay_all_sui(signer, input_coins, recipient, gas_budget) + .pay_all_iota(signer, input_coins, recipient, gas_budget) .await?; serialize_or_execute!( @@ -1439,22 +1441,22 @@ impl SuiClientCommands { serialize_unsigned_transaction, serialize_signed_transaction, context, - PayAllSui + PayAllIota ) } - SuiClientCommands::Objects { address } => { + IotaClientCommands::Objects { address } => { let address = get_identity_address(address, context)?; let client = context.get_client().await?; - let mut objects: Vec = Vec::new(); + let mut objects: Vec = Vec::new(); let mut cursor = None; loop { let response = client .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::full_content(), + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::full_content(), )), cursor, None, @@ -1468,10 +1470,10 @@ impl SuiClientCommands { break; } } - SuiClientCommandResult::Objects(objects) + IotaClientCommandResult::Objects(objects) } - SuiClientCommands::NewAddress { + IotaClientCommands::NewAddress { key_scheme, alias, derivation_path, @@ -1489,14 +1491,14 @@ impl SuiClientCommands { None => context.config.keystore.get_alias_by_address(&address)?, }; - SuiClientCommandResult::NewAddress(NewAddressOutput { + IotaClientCommandResult::NewAddress(NewAddressOutput { alias, address, key_scheme: scheme, recovery_phrase: phrase, }) } - SuiClientCommands::Gas { address } => { + IotaClientCommands::Gas { address } => { let address = get_identity_address(address, context)?; let coins = context .gas_objects(address) @@ -1505,9 +1507,9 @@ impl SuiClientCommands { // Ok to unwrap() since `get_gas_objects` guarantees gas .map(|(_val, object)| GasCoin::try_from(object).unwrap()) .collect(); - SuiClientCommandResult::Gas(coins) + IotaClientCommandResult::Gas(coins) } - SuiClientCommands::Faucet { address, url } => { + IotaClientCommands::Faucet { address, url } => { let address = get_identity_address(address, context)?; let url = if let Some(url) = url { url @@ -1516,10 +1518,10 @@ impl SuiClientCommands { if let Ok(env) = active_env { let network = match env.rpc.as_str() { - SUI_DEVNET_URL => "https://faucet.devnet.sui.io/v1/gas", - SUI_TESTNET_URL => "https://faucet.testnet.sui.io/v1/gas", - // TODO when using sui-test-validator, and 5003 when using sui start - SUI_LOCAL_NETWORK_URL => "http://127.0.0.1:9123/gas", + IOTA_DEVNET_URL => "https://faucet.devnet.iota.io/v1/gas", + IOTA_TESTNET_URL => "https://faucet.testnet.iota.io/v1/gas", + // TODO when using iota-test-validator, and 5003 when using iota start + IOTA_LOCAL_NETWORK_URL => "http://127.0.0.1:9123/gas", _ => bail!( "Cannot recognize the active network. Please provide the gas faucet full URL." ), @@ -1530,18 +1532,18 @@ impl SuiClientCommands { } }; request_tokens_from_faucet(address, url).await?; - SuiClientCommandResult::NoOutput + IotaClientCommandResult::NoOutput } - SuiClientCommands::ChainIdentifier => { + IotaClientCommands::ChainIdentifier => { let ci = context .get_client() .await? .read_api() .get_chain_identifier() .await?; - SuiClientCommandResult::ChainIdentifier(ci) + IotaClientCommandResult::ChainIdentifier(ci) } - SuiClientCommands::SplitCoin { + IotaClientCommands::SplitCoin { coin_id, amounts, count, @@ -1582,7 +1584,7 @@ impl SuiClientCommands { SplitCoin ) } - SuiClientCommands::MergeCoin { + IotaClientCommands::MergeCoin { primary_coin, coin_to_merge, gas, @@ -1604,7 +1606,7 @@ impl SuiClientCommands { MergeCoin ) } - SuiClientCommands::Switch { address, env } => { + IotaClientCommands::Switch { address, env } => { let mut addr = None; if address.is_none() && env.is_none() { @@ -1626,13 +1628,13 @@ impl SuiClientCommands { Self::switch_env(&mut context.config, env)?; } context.config.save()?; - SuiClientCommandResult::Switch(SwitchResponse { address: addr, env }) + IotaClientCommandResult::Switch(SwitchResponse { address: addr, env }) } - SuiClientCommands::ActiveAddress => { - SuiClientCommandResult::ActiveAddress(context.active_address().ok()) + IotaClientCommands::ActiveAddress => { + IotaClientCommandResult::ActiveAddress(context.active_address().ok()) } - SuiClientCommands::ExecuteSignedTx { + IotaClientCommands::ExecuteSignedTx { tx_bytes, signatures, } => { @@ -1641,7 +1643,7 @@ impl SuiClientCommands { .map_err(|_| anyhow!("Invalid Base64 encoding"))? .to_vec() .map_err(|_| anyhow!("Invalid Base64 encoding"))? - ).map_err(|_| anyhow!("Failed to parse tx bytes, check if it matches the output of sui client commands with --serialize-unsigned-transaction"))?; + ).map_err(|_| anyhow!("Failed to parse tx bytes, check if it matches the output of iota client commands with --serialize-unsigned-transaction"))?; let mut sigs = Vec::new(); for sig in signatures { @@ -1658,41 +1660,41 @@ impl SuiClientCommands { let transaction = Transaction::from_generic_sig_data(data, sigs); let response = context.execute_transaction_may_fail(transaction).await?; - SuiClientCommandResult::ExecuteSignedTx(response) + IotaClientCommandResult::ExecuteSignedTx(response) } - SuiClientCommands::ExecuteCombinedSignedTx { signed_tx_bytes } => { + IotaClientCommands::ExecuteCombinedSignedTx { signed_tx_bytes } => { let data: SenderSignedData = bcs::from_bytes( &Base64::try_from(signed_tx_bytes) .map_err(|_| anyhow!("Invalid Base64 encoding"))? .to_vec() .map_err(|_| anyhow!("Invalid Base64 encoding"))? - ).map_err(|_| anyhow!("Failed to parse SenderSignedData bytes, check if it matches the output of sui client commands with --serialize-signed-transaction"))?; + ).map_err(|_| anyhow!("Failed to parse SenderSignedData bytes, check if it matches the output of iota client commands with --serialize-signed-transaction"))?; let transaction = Envelope::::new(data); let response = context.execute_transaction_may_fail(transaction).await?; - SuiClientCommandResult::ExecuteSignedTx(response) + IotaClientCommandResult::ExecuteSignedTx(response) } - SuiClientCommands::NewEnv { alias, rpc, ws } => { + IotaClientCommands::NewEnv { alias, rpc, ws } => { if context.config.envs.iter().any(|env| env.alias == alias) { return Err(anyhow!( "Environment config with name [{alias}] already exists." )); } - let env = SuiEnv { alias, rpc, ws }; + let env = IotaEnv { alias, rpc, ws }; // Check urls are valid and server is reachable env.create_rpc_client(None, None).await?; context.config.envs.push(env.clone()); context.config.save()?; - SuiClientCommandResult::NewEnv(env) + IotaClientCommandResult::NewEnv(env) } - SuiClientCommands::ActiveEnv => { - SuiClientCommandResult::ActiveEnv(context.config.active_env.clone()) + IotaClientCommands::ActiveEnv => { + IotaClientCommandResult::ActiveEnv(context.config.active_env.clone()) } - SuiClientCommands::Envs => SuiClientCommandResult::Envs( + IotaClientCommands::Envs => IotaClientCommandResult::Envs( context.config.envs.clone(), context.config.active_env.clone(), ), - SuiClientCommands::VerifySource { + IotaClientCommands::VerifySource { package_path, build_config, verify_deps, @@ -1728,21 +1730,21 @@ impl SuiClientCommands { ) .await?; - SuiClientCommandResult::VerifySource + IotaClientCommandResult::VerifySource } - SuiClientCommands::PTB(ptb) => { + IotaClientCommands::PTB(ptb) => { ptb.execute(context).await?; - SuiClientCommandResult::NoOutput + IotaClientCommandResult::NoOutput } }); ret } - pub fn switch_env(config: &mut SuiClientConfig, env: &str) -> Result<(), anyhow::Error> { + pub fn switch_env(config: &mut IotaClientConfig, env: &str) -> Result<(), anyhow::Error> { let env = Some(env.into()); ensure!( config.get_env(&env).is_some(), - "Environment config not found for [{env:?}], add new environment config using the `sui client new-env` command." + "Environment config not found for [{env:?}], add new environment config using the `iota client new-env` command." ); config.active_env = env; Ok(()) @@ -1798,7 +1800,7 @@ pub(crate) async fn upgrade_package( let resp = read_api .get_object_with_options( upgrade_capability, - SuiObjectDataOptions::default().with_bcs().with_owner(), + IotaObjectDataOptions::default().with_bcs().with_owner(), ) .await?; @@ -1866,7 +1868,7 @@ pub(crate) async fn compile_package( )?; if !compiled_package.is_system_package() { if let Some(already_published) = compiled_package.published_root_module() { - return Err(SuiError::ModulePublishFailure { + return Err(IotaError::ModulePublishFailure { error: format!( "Modules must all have 0x0 as their addresses. \ Violated by module {:?}", @@ -1883,7 +1885,7 @@ pub(crate) async fn compile_package( if !skip_dependency_verification { let verifier = BytecodeSourceVerifier::new(read_api); if let Err(e) = verifier.verify_package_deps(&compiled_package).await { - return Err(SuiError::ModulePublishFailure { + return Err(IotaError::ModulePublishFailure { error: format!( "[warning] {e}\n\ \n\ @@ -1911,11 +1913,11 @@ pub(crate) async fn compile_package( Ok((dependencies, compiled_modules, compiled_package, package_id)) } -impl Display for SuiClientCommandResult { +impl Display for IotaClientCommandResult { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut writer = String::new(); match self { - SuiClientCommandResult::Addresses(addresses) => { + IotaClientCommandResult::Addresses(addresses) => { let mut builder = TableBuilder::default(); builder.set_header(vec!["alias", "address", "active address"]); for (alias, address) in &addresses.addresses { @@ -1931,7 +1933,7 @@ impl Display for SuiClientCommandResult { table.with(style); write!(f, "{}", table)? } - SuiClientCommandResult::Balance(coins, with_coins) => { + IotaClientCommandResult::Balance(coins, with_coins) => { if coins.is_empty() { return write!(f, "No coins found for this address."); } @@ -1946,7 +1948,7 @@ impl Display for SuiClientCommandResult { table.with(tabled::settings::style::BorderSpanCorrection); write!(f, "{}", table)?; } - SuiClientCommandResult::DynamicFieldQuery(df_refs) => { + IotaClientCommandResult::DynamicFieldQuery(df_refs) => { let df_refs = DynamicFieldOutput { has_next_page: df_refs.has_next_page, next_cursor: df_refs.next_cursor, @@ -1959,7 +1961,7 @@ impl Display for SuiClientCommandResult { table.with(style); write!(f, "{}", table)? } - SuiClientCommandResult::Gas(gas_coins) => { + IotaClientCommandResult::Gas(gas_coins) => { let gas_coins = gas_coins .iter() .map(GasCoinOutput::from) @@ -1970,12 +1972,16 @@ impl Display for SuiClientCommandResult { } let mut builder = TableBuilder::default(); - builder.set_header(vec!["gasCoinId", "mistBalance (MIST)", "suiBalance (SUI)"]); + builder.set_header(vec![ + "gasCoinId", + "microsBalance (MICROS)", + "iotaBalance (IOTA)", + ]); for coin in &gas_coins { builder.push_record(vec![ coin.gas_coin_id.to_string(), - coin.mist_balance.to_string(), - coin.sui_balance.to_string(), + coin.micros_balance.to_string(), + coin.iota_balance.to_string(), ]); } let mut table = builder.build(); @@ -2001,7 +2007,7 @@ impl Display for SuiClientCommandResult { } write!(f, "{}", table)?; } - SuiClientCommandResult::NewAddress(new_address) => { + IotaClientCommandResult::NewAddress(new_address) => { let mut builder = TableBuilder::default(); builder.push_record(vec!["alias", new_address.alias.as_str()]); builder.push_record(vec!["address", new_address.address.to_string().as_str()]); @@ -2031,7 +2037,7 @@ impl Display for SuiClientCommandResult { write!(f, "{}", table)? } - SuiClientCommandResult::Object(object_read) => match object_read.object() { + IotaClientCommandResult::Object(object_read) => match object_read.object() { Ok(obj) => { let object = ObjectOutput::from(obj); let json_obj = json!(&object); @@ -2041,7 +2047,7 @@ impl Display for SuiClientCommandResult { } Err(e) => writeln!(f, "Internal error, cannot read the object: {e}")?, }, - SuiClientCommandResult::Objects(object_refs) => { + IotaClientCommandResult::Objects(object_refs) => { if object_refs.is_empty() { writeln!(f, "This address has no owned objects.")? } else { @@ -2057,20 +2063,20 @@ impl Display for SuiClientCommandResult { } } } - SuiClientCommandResult::Upgrade(response) - | SuiClientCommandResult::Publish(response) => { + IotaClientCommandResult::Upgrade(response) + | IotaClientCommandResult::Publish(response) => { write!(writer, "{}", response)?; } - SuiClientCommandResult::TransactionBlock(response) => { + IotaClientCommandResult::TransactionBlock(response) => { write!(writer, "{}", response)?; } - SuiClientCommandResult::RawObject(raw_object_read) => { + IotaClientCommandResult::RawObject(raw_object_read) => { let raw_object = match raw_object_read.object() { Ok(v) => match &v.bcs { - Some(SuiRawData::MoveObject(o)) => { + Some(IotaRawData::MoveObject(o)) => { format!("{:?}\nNumber of bytes: {}", o.bcs_bytes, o.bcs_bytes.len()) } - Some(SuiRawData::Package(p)) => { + Some(IotaRawData::Package(p)) => { let mut temp = String::new(); let mut bcs_bytes = 0usize; for m in &p.module_map { @@ -2085,69 +2091,69 @@ impl Display for SuiClientCommandResult { }; writeln!(writer, "{}", raw_object)?; } - SuiClientCommandResult::Call(response) => { + IotaClientCommandResult::Call(response) => { write!(writer, "{}", response)?; } - SuiClientCommandResult::SerializedUnsignedTransaction(tx_data) => { + IotaClientCommandResult::SerializedUnsignedTransaction(tx_data) => { writeln!( writer, "{}", fastcrypto::encoding::Base64::encode(bcs::to_bytes(tx_data).unwrap()) )?; } - SuiClientCommandResult::SerializedSignedTransaction(sender_signed_tx) => { + IotaClientCommandResult::SerializedSignedTransaction(sender_signed_tx) => { writeln!( writer, "{}", fastcrypto::encoding::Base64::encode(bcs::to_bytes(sender_signed_tx).unwrap()) )?; } - SuiClientCommandResult::Transfer(response) => { + IotaClientCommandResult::Transfer(response) => { write!(writer, "{}", response)?; } - SuiClientCommandResult::TransferSui(response) => { + IotaClientCommandResult::TransferIota(response) => { write!(writer, "{}", response)?; } - SuiClientCommandResult::Pay(response) => { + IotaClientCommandResult::Pay(response) => { write!(writer, "{}", response)?; } - SuiClientCommandResult::PaySui(response) => { + IotaClientCommandResult::PayIota(response) => { write!(writer, "{}", response)?; } - SuiClientCommandResult::PayAllSui(response) => { + IotaClientCommandResult::PayAllIota(response) => { write!(writer, "{}", response)?; } - SuiClientCommandResult::SyncClientState => { + IotaClientCommandResult::SyncClientState => { writeln!(writer, "Client state sync complete.")?; } - SuiClientCommandResult::ChainIdentifier(ci) => { + IotaClientCommandResult::ChainIdentifier(ci) => { writeln!(writer, "{}", ci)?; } - SuiClientCommandResult::SplitCoin(response) => { + IotaClientCommandResult::SplitCoin(response) => { write!(writer, "{}", response)?; } - SuiClientCommandResult::MergeCoin(response) => { + IotaClientCommandResult::MergeCoin(response) => { write!(writer, "{}", response)?; } - SuiClientCommandResult::Switch(response) => { + IotaClientCommandResult::Switch(response) => { write!(writer, "{}", response)?; } - SuiClientCommandResult::ActiveAddress(response) => { + IotaClientCommandResult::ActiveAddress(response) => { match response { Some(r) => write!(writer, "{}", r)?, None => write!(writer, "None")?, }; } - SuiClientCommandResult::ExecuteSignedTx(response) => { + IotaClientCommandResult::ExecuteSignedTx(response) => { write!(writer, "{}", response)?; } - SuiClientCommandResult::ActiveEnv(env) => { + IotaClientCommandResult::ActiveEnv(env) => { write!(writer, "{}", env.as_deref().unwrap_or("None"))?; } - SuiClientCommandResult::NewEnv(env) => { - writeln!(writer, "Added new Sui env [{}] to config.", env.alias)?; + IotaClientCommandResult::NewEnv(env) => { + writeln!(writer, "Added new Iota env [{}] to config.", env.alias)?; } - SuiClientCommandResult::Envs(envs, active) => { + IotaClientCommandResult::Envs(envs, active) => { let mut builder = TableBuilder::default(); builder.set_header(["alias", "url", "active"]); for env in envs { @@ -2163,10 +2169,10 @@ impl Display for SuiClientCommandResult { table.with(TableStyle::rounded()); write!(f, "{}", table)? } - SuiClientCommandResult::VerifySource => { + IotaClientCommandResult::VerifySource => { writeln!(writer, "Source verification succeeded!")?; } - SuiClientCommandResult::VerifyBytecodeMeter { + IotaClientCommandResult::VerifyBytecodeMeter { max_module_ticks, max_function_ticks, used_function_ticks, @@ -2196,8 +2202,8 @@ impl Display for SuiClientCommandResult { table.with(tabled::settings::style::BorderSpanCorrection); writeln!(f, "{}", table)?; } - SuiClientCommandResult::NoOutput => {} - SuiClientCommandResult::PTB(_) => {} // this is handled in PTB execute + IotaClientCommandResult::NoOutput => {} + IotaClientCommandResult::PTB(_) => {} // this is handled in PTB execute } write!(f, "{}", writer.trim_end_matches('\n')) } @@ -2211,14 +2217,14 @@ async fn construct_move_call_transaction( gas: Option, gas_budget: u64, gas_price: Option, - args: Vec, + args: Vec, context: &mut WalletContext, ) -> Result { // Convert all numeric input to String, this will allow number input from the - // CLI without failing SuiJSON's checks. + // CLI without failing IotaJSON's checks. let args = args .into_iter() - .map(|value| SuiJsonValue::new(convert_number_to_string(value.to_json_value()))) + .map(|value| IotaJsonValue::new(convert_number_to_string(value.to_json_value()))) .collect::>()?; let type_args = type_args @@ -2250,21 +2256,21 @@ fn convert_number_to_string(value: Value) -> Value { } } -impl Debug for SuiClientCommandResult { +impl Debug for IotaClientCommandResult { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let s = unwrap_err_to_string(|| match self { - SuiClientCommandResult::Gas(gas_coins) => { + IotaClientCommandResult::Gas(gas_coins) => { let gas_coins = gas_coins .iter() .map(GasCoinOutput::from) .collect::>(); Ok(serde_json::to_string_pretty(&gas_coins)?) } - SuiClientCommandResult::Object(object_read) => { + IotaClientCommandResult::Object(object_read) => { let object = object_read.object()?; Ok(serde_json::to_string_pretty(&object)?) } - SuiClientCommandResult::RawObject(raw_object_read) => { + IotaClientCommandResult::RawObject(raw_object_read) => { let raw_object = raw_object_read.object()?; Ok(serde_json::to_string_pretty(&raw_object)?) } @@ -2281,9 +2287,9 @@ fn unwrap_err_to_string Result>(fun } } -impl SuiClientCommandResult { - pub fn objects_response(&self) -> Option> { - use SuiClientCommandResult::*; +impl IotaClientCommandResult { + pub fn objects_response(&self) -> Option> { + use IotaClientCommandResult::*; match self { Object(o) | RawObject(o) => Some(vec![o.clone()]), Objects(o) => Some(o.clone()), @@ -2306,12 +2312,12 @@ impl SuiClientCommandResult { } } - pub fn tx_block_response(&self) -> Option<&SuiTransactionBlockResponse> { - use SuiClientCommandResult::*; + pub fn tx_block_response(&self) -> Option<&IotaTransactionBlockResponse> { + use IotaClientCommandResult::*; match self { Upgrade(b) | Publish(b) | TransactionBlock(b) | Call(b) | Transfer(b) - | TransferSui(b) | Pay(b) | PaySui(b) | PayAllSui(b) | SplitCoin(b) | MergeCoin(b) - | ExecuteSignedTx(b) => Some(b), + | TransferIota(b) | Pay(b) | PayIota(b) | PayAllIota(b) | SplitCoin(b) + | MergeCoin(b) | ExecuteSignedTx(b) => Some(b), _ => None, } } @@ -2320,8 +2326,8 @@ impl SuiClientCommandResult { #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct AddressesOutput { - pub active_address: SuiAddress, - pub addresses: Vec<(String, SuiAddress)>, + pub active_address: IotaAddress, + pub addresses: Vec<(String, IotaAddress)>, } #[derive(Serialize)] @@ -2336,7 +2342,7 @@ pub struct DynamicFieldOutput { #[serde(rename_all = "camelCase")] pub struct NewAddressOutput { pub alias: String, - pub address: SuiAddress, + pub address: IotaAddress, pub key_scheme: SignatureScheme, pub recovery_phrase: String, } @@ -2355,11 +2361,11 @@ pub struct ObjectOutput { #[serde(skip_serializing_if = "Option::is_none")] pub storage_rebate: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub content: Option, + pub content: Option, } -impl From<&SuiObjectData> for ObjectOutput { - fn from(obj: &SuiObjectData) -> Self { +impl From<&IotaObjectData> for ObjectOutput { + fn from(obj: &IotaObjectData) -> Self { let obj_type = match obj.type_.as_ref() { Some(x) => x.to_string(), None => "unknown".to_string(), @@ -2381,16 +2387,16 @@ impl From<&SuiObjectData> for ObjectOutput { #[serde(rename_all = "camelCase")] pub struct GasCoinOutput { pub gas_coin_id: ObjectID, - pub mist_balance: u64, - pub sui_balance: String, + pub micros_balance: u64, + pub iota_balance: String, } impl From<&GasCoin> for GasCoinOutput { fn from(gas_coin: &GasCoin) -> Self { Self { gas_coin_id: *gas_coin.id(), - mist_balance: gas_coin.value(), - sui_balance: format_balance(gas_coin.value() as u128, 9, 2, None), + micros_balance: gas_coin.value(), + iota_balance: format_balance(gas_coin.value() as u128, 9, 2, None), } } } @@ -2405,11 +2411,11 @@ pub struct ObjectsOutput { } impl ObjectsOutput { - fn from(obj: SuiObjectResponse) -> Result { + fn from(obj: IotaObjectResponse) -> Result { let obj = obj.into_object()?; - // this replicates the object type display as in the sui explorer + // this replicates the object type display as in the iota explorer let object_type = match obj.type_ { - Some(sui_types::base_types::ObjectType::Struct(x)) => { + Some(iota_types::base_types::ObjectType::Struct(x)) => { let address = x.address().to_string(); // check if the address has length of 64 characters // otherwise, keep it as it is @@ -2420,7 +2426,7 @@ impl ObjectsOutput { }; format!("{}::{}::{}", address, x.module(), x.name(),) } - Some(sui_types::base_types::ObjectType::Package) => "Package".to_string(), + Some(iota_types::base_types::ObjectType::Package) => "Package".to_string(), None => "unknown".to_string(), }; Ok(Self { @@ -2430,7 +2436,7 @@ impl ObjectsOutput { object_type, }) } - fn from_vec(objs: Vec) -> Result, anyhow::Error> { + fn from_vec(objs: Vec) -> Result, anyhow::Error> { objs.into_iter() .map(ObjectsOutput::from) .collect::, _>>() @@ -2439,38 +2445,38 @@ impl ObjectsOutput { #[derive(Serialize)] #[serde(untagged)] -pub enum SuiClientCommandResult { - ActiveAddress(Option), +pub enum IotaClientCommandResult { + ActiveAddress(Option), ActiveEnv(Option), Addresses(AddressesOutput), - Balance(Vec<(Option, Vec)>, bool), - Call(SuiTransactionBlockResponse), + Balance(Vec<(Option, Vec)>, bool), + Call(IotaTransactionBlockResponse), ChainIdentifier(String), DynamicFieldQuery(DynamicFieldPage), - Envs(Vec, Option), - ExecuteSignedTx(SuiTransactionBlockResponse), + Envs(Vec, Option), + ExecuteSignedTx(IotaTransactionBlockResponse), Gas(Vec), - MergeCoin(SuiTransactionBlockResponse), + MergeCoin(IotaTransactionBlockResponse), NewAddress(NewAddressOutput), - NewEnv(SuiEnv), + NewEnv(IotaEnv), NoOutput, - Object(SuiObjectResponse), - Objects(Vec), - Pay(SuiTransactionBlockResponse), - PayAllSui(SuiTransactionBlockResponse), - PaySui(SuiTransactionBlockResponse), - PTB(SuiTransactionBlockResponse), - Publish(SuiTransactionBlockResponse), - RawObject(SuiObjectResponse), + Object(IotaObjectResponse), + Objects(Vec), + Pay(IotaTransactionBlockResponse), + PayAllIota(IotaTransactionBlockResponse), + PayIota(IotaTransactionBlockResponse), + PTB(IotaTransactionBlockResponse), + Publish(IotaTransactionBlockResponse), + RawObject(IotaObjectResponse), SerializedSignedTransaction(SenderSignedData), SerializedUnsignedTransaction(TransactionData), - SplitCoin(SuiTransactionBlockResponse), + SplitCoin(IotaTransactionBlockResponse), Switch(SwitchResponse), SyncClientState, - TransactionBlock(SuiTransactionBlockResponse), - Transfer(SuiTransactionBlockResponse), - TransferSui(SuiTransactionBlockResponse), - Upgrade(SuiTransactionBlockResponse), + TransactionBlock(IotaTransactionBlockResponse), + Transfer(IotaTransactionBlockResponse), + TransferIota(IotaTransactionBlockResponse), + Upgrade(IotaTransactionBlockResponse), VerifyBytecodeMeter { max_module_ticks: u128, max_function_ticks: u128, @@ -2503,7 +2509,7 @@ impl Display for SwitchResponse { /// Request tokens from the Faucet for the given address pub async fn request_tokens_from_faucet( - address: SuiAddress, + address: IotaAddress, url: String, ) -> Result<(), anyhow::Error> { let address_str = address.to_string(); @@ -2532,14 +2538,14 @@ pub async fn request_tokens_from_faucet( bail!("Faucet request was unsuccessful: {err}") } else { println!( - "Request successful. It can take up to 1 minute to get the coin. Run sui client gas to check your gas coins." + "Request successful. It can take up to 1 minute to get the coin. Run iota client gas to check your gas coins." ); } Ok(()) } fn pretty_print_balance( - coins_by_type: &Vec<(Option, Vec)>, + coins_by_type: &Vec<(Option, Vec)>, builder: &mut TableBuilder, with_coins: bool, ) { diff --git a/crates/sui/src/client_ptb/ast.rs b/crates/iota/src/client_ptb/ast.rs similarity index 99% rename from crates/sui/src/client_ptb/ast.rs rename to crates/iota/src/client_ptb/ast.rs index 2b92d3ca381..9c803d74e50 100644 --- a/crates/sui/src/client_ptb/ast.rs +++ b/crates/iota/src/client_ptb/ast.rs @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::fmt; +use iota_types::{base_types::ObjectID, Identifier}; use move_command_line_common::{ address::{NumericalAddress, ParsedAddress}, types::{ParsedFqName, ParsedModuleId, ParsedStructType, ParsedType}, }; use move_core_types::runtime_value::MoveValue; -use sui_types::{base_types::ObjectID, Identifier}; use super::error::{PTBResult, Span, Spanned}; use crate::{error, sp}; diff --git a/crates/iota/src/client_ptb/builder.rs b/crates/iota/src/client_ptb/builder.rs new file mode 100644 index 00000000000..6a2a5eacbb8 --- /dev/null +++ b/crates/iota/src/client_ptb/builder.rs @@ -0,0 +1,1135 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{collections::BTreeMap, path::PathBuf}; + +use anyhow::Result; +use async_recursion::async_recursion; +use async_trait::async_trait; +use iota_json::{is_receiving_argument, primitive_type}; +use iota_json_rpc_types::{IotaObjectData, IotaObjectDataOptions, IotaRawData}; +use iota_protocol_config::{Chain, ProtocolConfig}; +use iota_sdk::apis::ReadApi; +use iota_types::{ + base_types::{is_primitive_type_tag, ObjectID, TxContext, TxContextKind}, + digests::{get_mainnet_chain_identifier, get_testnet_chain_identifier}, + move_package::MovePackage, + object::Owner, + programmable_transaction_builder::ProgrammableTransactionBuilder, + resolve_address, + transaction::{self as Tx, ObjectArg}, + Identifier, TypeTag, IOTA_FRAMEWORK_PACKAGE_ID, +}; +use miette::Severity; +use move_binary_format::{ + access::ModuleAccess, binary_config::BinaryConfig, binary_views::BinaryIndexedView, + file_format::SignatureToken, +}; +use move_command_line_common::{ + address::{NumericalAddress, ParsedAddress}, + parser::NumberFormat, +}; +use move_core_types::{account_address::AccountAddress, ident_str, runtime_value::MoveValue}; +use move_package::BuildConfig; + +use super::ast::{ModuleAccess as PTBModuleAccess, ParsedPTBCommand, Program}; +use crate::{ + client_commands::{compile_package, upgrade_package}, + client_ptb::{ + ast::{Argument as PTBArg, ASSIGN, GAS_BUDGET}, + error::{PTBError, PTBResult, Span, Spanned}, + }, + err, error, sp, +}; + +// =========================================================================== +// Object Resolution +// =========================================================================== +// We need to resolve the same argument in different ways depending on the +// context in which that argument is used. For example, if we are using an +// object ID as an argument to a move call that expects an object argument in +// that position, the object ID should be resolved to an object, whereas if we +// are using the same object ID as an argument to a pure value, it should be +// resolved to a pure value (e.g., the object ID itself). The different ways of +// resolving this is the purpose of the `Resolver` trait -- different contexts +// will implement this trait in different ways. + +/// A resolver is used to resolve arguments to a PTB. Depending on the context, +/// we may resolve object IDs in different ways -- e.g., in a pure context they +/// should be resolved to a pure value, whereas in an object context they should +/// be resolved to the appropriate object argument. +#[async_trait] +trait Resolver<'a>: Send { + /// Resolve a pure value. This should almost always resolve to a pure value. + async fn pure( + &mut self, + builder: &mut PTBBuilder<'a>, + loc: Span, + val: MoveValue, + ) -> PTBResult { + builder.ptb.pure(val).map_err(|e| err!(loc, "{e}")) + } + + async fn resolve_object_id( + &mut self, + builder: &mut PTBBuilder<'a>, + loc: Span, + obj_id: ObjectID, + ) -> PTBResult; + + fn re_resolve(&self) -> bool { + false + } +} + +/// A resolver that resolves object IDs to object arguments. +/// * If `is_receiving` is true, then the object argument will be resolved to a +/// receiving object argument. +/// * If `is_mut` is true, then the object argument will be resolved to a +/// mutable object argument. +struct ToObject { + is_receiving: bool, + is_mut: bool, +} + +impl Default for ToObject { + fn default() -> Self { + Self { + is_receiving: false, + is_mut: true, + } + } +} + +impl ToObject { + fn new(is_receiving: bool, is_mut: bool) -> Self { + Self { + is_receiving, + is_mut, + } + } +} + +#[async_trait] +impl<'a> Resolver<'a> for ToObject { + async fn resolve_object_id( + &mut self, + builder: &mut PTBBuilder<'a>, + loc: Span, + obj_id: ObjectID, + ) -> PTBResult { + // Get the object from the reader to get metadata about the object. + let obj = builder.get_object(obj_id, loc).await?; + let owner = obj + .owner + .ok_or_else(|| err!(loc, "Unable to get owner info for object {obj_id}"))?; + let object_ref = obj.object_ref(); + // Depending on the ownership of the object, we resolve it to different types of + // object arguments for the transaction. + let obj_arg = match owner { + Owner::AddressOwner(_) if self.is_receiving => ObjectArg::Receiving(object_ref), + Owner::Immutable | Owner::AddressOwner(_) => ObjectArg::ImmOrOwnedObject(object_ref), + Owner::Shared { + initial_shared_version, + } => ObjectArg::SharedObject { + id: object_ref.0, + initial_shared_version, + mutable: self.is_mut, + }, + Owner::ObjectOwner(_) => { + error!(loc => help: { + "{obj_id} is an object-owned object, you can only use immutable, shared, or owned objects here." + }, "Cannot use an object-owned object as an argument") + } + }; + // Insert the correct object arg that we built above into the transaction. + builder.ptb.obj(obj_arg).map_err(|e| err!(loc, "{e}")) + } + + // We always re-resolve object IDs to object arguments if we need it mutably -- + // we could have added it earlier as an immutable argument. + fn re_resolve(&self) -> bool { + self.is_mut + } +} + +/// A resolver that resolves object IDs that it encounters to pure PTB values. +struct ToPure; + +#[async_trait] +impl<'a> Resolver<'a> for ToPure { + async fn resolve_object_id( + &mut self, + builder: &mut PTBBuilder<'a>, + loc: Span, + obj_id: ObjectID, + ) -> PTBResult { + builder.ptb.pure(obj_id).map_err(|e| err!(loc, "{e}")) + } +} + +// =========================================================================== +// PTB Builder and PTB Creation +// =========================================================================== + +/// The PTBBuilder struct is the main workhorse that transforms a sequence of +/// `ParsedPTBCommand`s into an actual PTB that can be run. The main things to +/// keep in mind are that this contains: +/// - A way to handle identifiers -- note that we "lazily" resolve identifiers +/// to arguments, so that the first usage of the identifier determines what it +/// is resolved to. If an identifier is used in multiple positions at +/// different resolutions (e.g., in one place as an object argument, and in +/// another as a pure value), this will result in an error. This error can be +/// avoided by creating another identifier for the second usage. +/// - A way to resolve arguments -- this is done by calling `resolve` on a +/// `PTBArg` and passing in appropriate context. The context is used to +/// determine how to resolve the argument -- e.g., if an object ID should be +/// resolved to a pure value or an object argument. +/// - A way to bind the result of a command to an identifier. +pub struct PTBBuilder<'a> { + /// A map from identifiers to addresses. This is used to support address + /// resolution, and also supports external address sources (e.g., + /// keystore). + addresses: BTreeMap, + /// A map from identifiers to the file scopes in which they were declared. + /// This is used for reporting shadowing warnings. + identifiers: BTreeMap>, + /// The arguments that we need to resolve. This is a map from identifiers to + /// the argument values -- they haven't been resolved to a transaction + /// argument yet. + arguments_to_resolve: BTreeMap, + /// The arguments that we have resolved. This is a map from identifiers to + /// the actual transaction arguments. + resolved_arguments: BTreeMap, + /// Read API for reading objects from chain. Needed for object resolution. + reader: &'a ReadApi, + /// The last command that we have added. This is used to support assignment + /// commands. + last_command: Option, + /// The actual PTB that we are building up. + ptb: ProgrammableTransactionBuilder, + /// The list of errors that we have built up while processing commands. We + /// do not report errors eagerly but instead wait until we have + /// processed all commands to report any errors. + errors: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +enum ResolvedAccess { + ResultAccess(u16), + DottedString(String), +} + +/// Hold a PTB argument, always remembering its most recent state even if it's +/// already been resolved. +#[derive(Debug)] +enum ArgWithHistory { + Resolved(Spanned), + Unresolved(Spanned), +} + +impl ArgWithHistory { + fn get_unresolved(&self) -> Option<&Spanned> { + match self { + ArgWithHistory::Resolved(_) => None, + ArgWithHistory::Unresolved(x) => Some(x), + } + } + + fn get(&self) -> &Spanned { + match self { + ArgWithHistory::Resolved(x) => x, + ArgWithHistory::Unresolved(x) => x, + } + } + + fn resolve(&mut self) { + *self = match self { + ArgWithHistory::Resolved(x) => ArgWithHistory::Resolved(x.clone()), + ArgWithHistory::Unresolved(x) => ArgWithHistory::Resolved(x.clone()), + } + } + + fn is_resolved(&self) -> bool { + matches!(self, ArgWithHistory::Resolved(_)) + } +} + +impl<'a> PTBBuilder<'a> { + pub fn new(starting_env: BTreeMap, reader: &'a ReadApi) -> Self { + Self { + addresses: starting_env, + identifiers: BTreeMap::new(), + arguments_to_resolve: BTreeMap::new(), + resolved_arguments: BTreeMap::new(), + ptb: ProgrammableTransactionBuilder::new(), + reader, + last_command: None, + errors: Vec::new(), + } + } + + /// Finalize a PTB. If there were errors during the construction of the PTB + /// these are returned now. Otherwise, the PTB is finalized and + /// returned. If the warn_on_shadowing flag was set, then we will print + /// warnings for any shadowed variables that we encountered during the + /// building of the PTB. + pub fn finish( + self, + warn_on_shadowing: bool, + ) -> ( + Result>, + Vec, + ) { + let mut warnings = vec![]; + if warn_on_shadowing { + for (ident, commands) in self.identifiers.iter() { + if commands.len() == 1 { + continue; + } + + for (i, command_loc) in commands.iter().enumerate() { + if i == 0 { + warnings.push(PTBError { + message: format!("Variable '{}' first declared here", ident), + span: *command_loc, + help: None, + severity: Severity::Warning, + }); + } else { + warnings.push(PTBError { + message: format!( + "Variable '{}' used again here (shadowed) for the {} time.", + ident, to_ordinal_contraction(i + 1) + ), + span: *command_loc, + help: Some("You can either rename this variable, or do not \ + pass the `warn-shadows` flag to ignore these types of errors.".to_string()), + severity: Severity::Warning, + }); + } + } + } + } + + if !self.errors.is_empty() { + return (Err(self.errors), warnings); + } + + let ptb = self.ptb.finish(); + (Ok(ptb), warnings) + } + + pub async fn build( + mut self, + program: Program, + ) -> ( + Result>, + Vec, + ) { + for command in program.commands.into_iter() { + self.handle_command(command).await; + } + self.finish(program.warn_shadows_set) + } + + /// Add a single PTB command to the PTB that we are building up. + /// Errors are added to the `errors` field of the PTBBuilder. + async fn handle_command(&mut self, sp!(span, command): Spanned) { + if let Err(e) = self.handle_command_(span, command).await { + self.errors.push(e); + } + } + + // =========================================================================== + // Declaring and handling identifiers and variables + // =========================================================================== + + /// Declare an identifier. This is used to support shadowing warnings. + fn declare_identifier(&mut self, ident: String, ident_loc: Span) { + let e = self.identifiers.entry(ident).or_default(); + e.push(ident_loc); + } + + /// Declare a possible address binding. This is used to support address + /// resolution. If the `possible_addr` is not an address, then this is a + /// no-op. + fn declare_possible_address_binding(&mut self, ident: String, possible_addr: &Spanned) { + match possible_addr.value { + PTBArg::Address(addr) => { + self.addresses.insert(ident, addr.into_inner()); + } + PTBArg::Identifier(ref i) => { + // We do a one-hop resolution here to see if we can resolve the identifier to an + // externally-bound address (i.e., one coming in through the initial + // environment). This will also handle direct aliasing of + // addresses throughout the ptb. Note that we don't do this + // recursively so no need to worry about loops/cycles. + if let Some(addr) = self.addresses.get(i) { + self.addresses.insert(ident, *addr); + } + } + // If we encounter a dotted string e.g., "foo.0" or "iota.io" or something like that + // this see if we can find an address for it in the environment and bind to it. + PTBArg::VariableAccess(ref head, ref fields) => { + let key = format!( + "{}.{}", + head.value, + fields + .iter() + .map(|f| f.value.clone()) + .collect::>() + .join(".") + ); + if let Some(addr) = self.addresses.get(&key) { + self.addresses.insert(ident, *addr); + } + } + _ => (), + } + } + + async fn get_protocol_config(&self, loc: Span) -> PTBResult { + let config = self + .reader + .get_protocol_config(None) + .await + .map_err(|e| err!(loc, "{e}"))?; + let chain_id = self + .reader + .get_chain_identifier() + .await + .map_err(|e| err!(loc, "{e}"))?; + Ok(if chain_id == get_mainnet_chain_identifier().to_string() { + ProtocolConfig::get_for_version(config.protocol_version, Chain::Mainnet) + } else if chain_id == get_testnet_chain_identifier().to_string() { + ProtocolConfig::get_for_version(config.protocol_version, Chain::Testnet) + } else { + ProtocolConfig::get_for_version(config.protocol_version, Chain::Unknown) + }) + } + + /// Resolve an object ID to a Move package. + async fn resolve_to_package( + &mut self, + package_id: ObjectID, + loc: Span, + ) -> PTBResult { + let object = self + .reader + .get_object_with_options(package_id, IotaObjectDataOptions::bcs_lossless()) + .await + .map_err(|e| err!(loc, "{e}"))? + .into_object() + .map_err(|e| err!(loc, "{e}"))?; + let Some(IotaRawData::Package(package)) = object.bcs else { + error!( + loc, + "BCS field in object '{}' is missing or not a package.", package_id + ); + }; + let protocol_config = self.get_protocol_config(loc).await?; + let package: MovePackage = MovePackage::new( + package.id, + object.version, + package.module_map, + protocol_config.max_move_package_size(), + package.type_origin_table, + package.linkage_table, + ) + .map_err(|e| err!(loc, "{e}"))?; + Ok(package) + } + + /// Resolves the argument to the move call based on the type information of + /// the function being called. + async fn resolve_move_call_arg( + &mut self, + view: &BinaryIndexedView<'_>, + ty_args: &[TypeTag], + sp!(loc, arg): Spanned, + param: &SignatureToken, + ) -> PTBResult { + let (is_primitive, _) = primitive_type(view, ty_args, param); + + // If it's a primitive value, see if we've already resolved this argument. + // Otherwise, we need to resolve it. + if is_primitive { + return self.resolve(loc.wrap(arg), ToPure).await; + } + + // Otherwise it's ambiguous what the value should be, and we need to turn to the + // signature to determine it. + let mut is_receiving = false; + // A value is mutable by default. + let mut is_mutable = true; + + // traverse the types in the signature to see if the argument is an object + // argument or not, and also determine if it's a receiving argument or + // not. + for tok in param.preorder_traversal() { + match tok { + SignatureToken::Struct(..) | SignatureToken::StructInstantiation(..) => { + is_receiving |= is_receiving_argument(view, tok); + } + SignatureToken::TypeParameter(idx) => { + if *idx as usize >= ty_args.len() { + error!(loc, "Not enough type parameters supplied for Move call"); + } + } + SignatureToken::Reference(_) => { + is_mutable = false; + } + SignatureToken::MutableReference(_) => { + // Not strictly needed, but for clarity + is_mutable = true; + } + SignatureToken::Bool + | SignatureToken::U8 + | SignatureToken::U64 + | SignatureToken::U128 + | SignatureToken::Address + | SignatureToken::Signer + | SignatureToken::Vector(_) + | SignatureToken::U16 + | SignatureToken::U32 + | SignatureToken::U256 => { + is_mutable = false; + } + } + } + + // Note: need to re-resolve an argument possibly since it may be used immutably + // first, and then mutably. + self.resolve(loc.wrap(arg), ToObject::new(is_receiving, is_mutable)) + .await + } + + /// Resolve the arguments to a Move call based on the type information about + /// the function being called. + async fn resolve_move_call_args( + &mut self, + package: MovePackage, + sp!(mloc, module_name): &Spanned, + sp!(floc, function_name): &Spanned, + ty_args: &[TypeTag], + args: Vec>, + package_name_loc: Span, + ) -> PTBResult> { + let module = package + .deserialize_module(module_name, &BinaryConfig::standard()) + .map_err(|e| { + let help_message = if package.serialized_module_map().is_empty() { + Some("No modules found in this package".to_string()) + } else { + display_did_you_mean(find_did_you_means( + module_name.as_str(), + package + .serialized_module_map() + .iter() + .map(|(x, _)| x.as_str()), + )) + }; + let e = err!(*mloc, "{e}"); + if let Some(help_message) = help_message { + e.with_help(help_message) + } else { + e + } + })?; + let fdef = module + .function_defs + .iter() + .find(|fdef| { + module.identifier_at(module.function_handle_at(fdef.function).name) + == function_name.as_ident_str() + }) + .ok_or_else(|| { + let e = err!( + *floc, + "Could not resolve function '{}' in module '{}'", + function_name, + module_name + ); + if let Some(help_message) = display_did_you_mean(find_did_you_means( + function_name.as_str(), + module.function_defs.iter().map(|fdef| { + module + .identifier_at(module.function_handle_at(fdef.function).name) + .as_str() + }), + )) { + e.with_help(help_message) + } else { + e + } + })?; + let function_signature = module.function_handle_at(fdef.function); + let view = BinaryIndexedView::Module(&module); + let parameters: Vec<_> = module + .signature_at(function_signature.parameters) + .0 + .clone() + .into_iter() + .filter(|tok| matches!(TxContext::kind(&view, tok), TxContextKind::None)) + .collect(); + + if parameters.len() != args.len() { + let loc = if args.is_empty() { + package_name_loc.widen(*mloc).widen(*floc) + } else { + args[0].span.widen_opt(args.last().map(|x| x.span)) + }; + error!( + loc, + "Expected {} argument{}, but got {}", + parameters.len(), + if parameters.len() == 1 { "" } else { "s" }, + args.len() + ); + } + + let mut call_args = vec![]; + for (param, arg) in parameters.iter().zip(args.into_iter()) { + let call_arg = self + .resolve_move_call_arg(&view, ty_args, arg, param) + .await?; + call_args.push(call_arg); + } + Ok(call_args) + } + + fn resolve_variable_access( + &self, + head: &Spanned, + fields: Vec>, + ) -> Spanned { + if fields.len() == 1 { + // Get the span and value of the field zero'th field. Safe since we just checked + // the length above. Since the length is 1, we know that the field + // is non-empty. + let sp!(field_loc, field) = &fields[0]; + if let Ok(n) = field.parse::() { + return field_loc.wrap(ResolvedAccess::ResultAccess(n)); + } + } + let tl_loc = head.span.widen_opt(fields.last().map(|x| x.span)); + tl_loc.wrap(ResolvedAccess::DottedString(format!( + "{}.{}", + head.value, + fields + .into_iter() + .map(|f| f.value) + .collect::>() + .join(".") + ))) + } + + /// Resolve an argument based on the argument value, and the `resolver` that + /// is passed in. + #[async_recursion] + async fn resolve( + &mut self, + sp!(arg_loc, arg): Spanned, + mut ctx: impl Resolver<'a> + 'async_recursion, + ) -> PTBResult { + match arg { + a @ (PTBArg::Bool(_) + | PTBArg::U8(_) + | PTBArg::U16(_) + | PTBArg::U32(_) + | PTBArg::U64(_) + | PTBArg::U128(_) + | PTBArg::U256(_) + | PTBArg::String(_) + | PTBArg::Option(_) + | PTBArg::Vector(_)) => { + ctx.pure(self, arg_loc, a.to_pure_move_value(arg_loc)?) + .await + } + PTBArg::Gas => Ok(Tx::Argument::GasCoin), + // NB: the ordering of these lines is important so that shadowing is properly + // supported. + // If we encounter an identifier that we have not already resolved, then we resolve the + // value and return it. + PTBArg::Identifier(i) + if self + .arguments_to_resolve + .get(&i) + .is_some_and(|arg_hist| !arg_hist.is_resolved()) => + { + let arg_hist = self.arguments_to_resolve.get(&i).unwrap(); + let arg = arg_hist.get().clone(); + let resolved = self.resolve(arg, ctx).await?; + self.arguments_to_resolve.get_mut(&i).unwrap().resolve(); + self.resolved_arguments.insert(i, resolved); + Ok(resolved) + } + // If the identifier does not need to be resolved, but has already been resolved, then + // we return the resolved value. + PTBArg::Identifier(i) if self.resolved_arguments.contains_key(&i) => { + if ctx.re_resolve() && self.arguments_to_resolve.contains_key(&i) { + self.resolve(self.arguments_to_resolve[&i].get().clone(), ctx) + .await + } else { + Ok(self.resolved_arguments[&i]) + } + } + // Lastly -- look to see if this is an address that has been either declared in scope, + // or that is coming from an external source (e.g., the keystore). + PTBArg::Identifier(i) if self.addresses.contains_key(&i) => { + // We now have a location for this address (which may have come from the + // keystore so we didnt' have an address for it before), so we + // tag it with its first usage location put it in the arguments + // to resolve and resolve away. + let addr = self.addresses[&i]; + let arg = arg_loc.wrap(PTBArg::Address(NumericalAddress::new( + addr.into_bytes(), + NumberFormat::Hex, + ))); + self.arguments_to_resolve + .insert(i.clone(), ArgWithHistory::Unresolved(arg.clone())); + self.resolve(arg_loc.wrap(PTBArg::Identifier(i)), ctx).await + } + PTBArg::Address(addr) => { + let object_id = ObjectID::from_address(addr.into_inner()); + ctx.resolve_object_id(self, arg_loc, object_id).await + } + PTBArg::VariableAccess(head, fields) => { + // Since keystore aliases can contain dots, we need to resolve + // these/disambiguate them as best as possible here. + // First: See if structurally we know whether this is a dotted access or a + // string(alias) containing dot(s). If there is more than one dotted access, or + // if the field(s) are not all numbers, then we assume it's a alias. + match self.resolve_variable_access(&head, fields) { + sp!(l, ResolvedAccess::DottedString(string)) => { + self.resolve(l.wrap(PTBArg::Identifier(string)), ctx).await + } + sp!(_, ResolvedAccess::ResultAccess(access)) => { + match self.resolved_arguments.get(&head.value) { + Some(Tx::Argument::Result(u)) => { + Ok(Tx::Argument::NestedResult(*u, access)) + } + // Tried to access into a nested result, input, or gascoin + Some( + x @ (Tx::Argument::NestedResult(..) + | Tx::Argument::Input(..) + | Tx::Argument::GasCoin), + ) => { + error!( + arg_loc, + "Tried to access a nested result, input, or gascoin {}: {}", + head.value, + x, + ); + } + // Unable to resolve, so now see if we can resolve it to an alias, i.e., + // handle a alias that looks something like `foo.0` + None => { + let formatted_access = format!("{}.{}", head.value, access); + if !self.addresses.contains_key(&formatted_access) + && !self.identifiers.contains_key(&formatted_access) + { + match self.did_you_mean_identifier(&head.value) { + Some(similars) => { + error!( + head.span => help: { "{}", similars }, + "Tried to access an unresolved identifier: {}", head.value + ); + } + None => { + error!( + head.span, + "Tried to access an unresolved identifier: {}", + head.value + ); + } + } + } + self.resolve( + arg_loc.wrap(PTBArg::Identifier(formatted_access.clone())), + ctx, + ) + .await + } + } + } + } + } + // Unable to resolve an identifer to anything at this point -- error and see if we can + // find a similar identifier to suggest. + PTBArg::Identifier(i) => match self.did_you_mean_identifier(&i) { + Some(similars) => { + error!(arg_loc => help: { "{}", similars }, "Unresolved identifier: '{}'", i) + } + None => error!(arg_loc, "Unresolved identifier: '{}'", i), + }, + } + } + + /// Fetch the `IotaObjectData` for an object ID -- this is used for object + /// resolution. + async fn get_object(&self, object_id: ObjectID, obj_loc: Span) -> PTBResult { + let res = self + .reader + .get_object_with_options( + object_id, + IotaObjectDataOptions::new().with_type().with_owner(), + ) + .await + .map_err(|e| err!(obj_loc, "{e}"))? + .into_object() + .map_err(|e| err!(obj_loc, "{e}"))?; + Ok(res) + } + + /// Create a "did you mean" message for an identifier with the context of + /// our different binding environments. + fn did_you_mean_identifier(&self, ident: &str) -> Option { + let did_you_means = find_did_you_means( + ident, + self.resolved_arguments + .keys() + .chain(self.arguments_to_resolve.keys()) + .chain(self.addresses.keys()) + .map(|x| x.as_str()), + ); + display_did_you_mean(did_you_means) + } + + /// Add a single PTB command to the PTB that we are building up. This is the + /// workhorse of it all. + async fn handle_command_( + &mut self, + cmd_span: Span, + command: ParsedPTBCommand, + ) -> PTBResult<()> { + // let sp!(cmd_span, tok) = &command.name; + match command { + ParsedPTBCommand::TransferObjects(obj_args, to_address) => { + let to_arg = self.resolve(to_address, ToPure).await?; + let mut transfer_args = vec![]; + for o in obj_args.value.into_iter() { + let arg = self.resolve(o, ToObject::default()).await?; + transfer_args.push(arg); + } + self.last_command = Some( + self.ptb + .command(Tx::Command::TransferObjects(transfer_args, to_arg)), + ); + } + ParsedPTBCommand::Assign(sp!(ident_loc, i), None) => { + let Some(prev_ptb_arg) = self.last_command.take() else { + error!( + ident_loc => help: { + "This is most likely because the previous command did not \ + produce a result. E.g., '{ASSIGN}' or '{GAS_BUDGET}' commands do not produce results." + + }, + "Cannot assign a value to this variable." + ); + }; + self.declare_identifier(i.clone(), ident_loc); + self.resolved_arguments.insert(i, prev_ptb_arg); + } + ParsedPTBCommand::Assign(sp!(ident_loc, i), Some(arg_w_loc)) => { + self.declare_identifier(i.clone(), ident_loc); + self.declare_possible_address_binding(i.clone(), &arg_w_loc); + self.arguments_to_resolve + .insert(i, ArgWithHistory::Unresolved(arg_w_loc)); + } + ParsedPTBCommand::MakeMoveVec(sp!(ty_loc, ty_arg), sp!(_, args)) => { + let ty_arg = ty_arg + .into_type_tag(&resolve_address) + .map_err(|e| err!(ty_loc, "{e}"))?; + let mut vec_args: Vec = vec![]; + if is_primitive_type_tag(&ty_arg) { + for arg in args.into_iter() { + let arg = self.resolve(arg, ToPure).await?; + vec_args.push(arg); + } + } else { + for arg in args.into_iter() { + let arg = self.resolve(arg, ToObject::default()).await?; + vec_args.push(arg); + } + } + let res = self + .ptb + .command(Tx::Command::MakeMoveVec(Some(ty_arg), vec_args)); + self.last_command = Some(res); + } + ParsedPTBCommand::SplitCoins(pre_coin, sp!(_, amounts)) => { + let coin = self.resolve(pre_coin, ToObject::default()).await?; + let mut args = vec![]; + for arg in amounts.into_iter() { + let arg = self.resolve(arg, ToPure).await?; + args.push(arg); + } + let res = self.ptb.command(Tx::Command::SplitCoins(coin, args)); + self.last_command = Some(res); + } + ParsedPTBCommand::MergeCoins(pre_coin, sp!(_, coins)) => { + let coin = self.resolve(pre_coin, ToObject::default()).await?; + let mut args = vec![]; + for arg in coins.into_iter() { + let arg = self.resolve(arg, ToObject::default()).await?; + args.push(arg); + } + let res = self.ptb.command(Tx::Command::MergeCoins(coin, args)); + self.last_command = Some(res); + } + ParsedPTBCommand::MoveCall( + sp!( + mod_access_loc, + PTBModuleAccess { + address, + module_name, + function_name, + } + ), + in_ty_args, + args, + ) => { + let mut ty_args = vec![]; + + if let Some(sp!(ty_loc, in_ty_args)) = in_ty_args { + for t in in_ty_args.into_iter() { + ty_args.push( + t.into_type_tag(&resolve_address) + .map_err(|e| err!(ty_loc, "{e}"))?, + ) + } + } + + let resolved_address = address.value.clone().into_account_address(&|s| { + self.addresses.get(s).cloned().or_else(|| resolve_address(s)) + }).map_err(|e| { + let e = err!(address.span, "{e}"); + if let ParsedAddress::Named(name) = address.value { + e.with_help( + format!("This is most likely because the named address '{name}' is not in scope. \ + You can either bind a variable to the address that you want to use or use the address in the command.")) + } else { + e + } + })?; + + let package_id = ObjectID::from_address(resolved_address); + let package = self.resolve_to_package(package_id, address.span).await?; + let args = self + .resolve_move_call_args( + package, + &module_name, + &function_name, + &ty_args, + args, + mod_access_loc, + ) + .await?; + let move_call = Tx::ProgrammableMoveCall { + package: package_id, + module: module_name.value, + function: function_name.value, + type_arguments: ty_args, + arguments: args, + }; + let res = self.ptb.command(Tx::Command::MoveCall(Box::new(move_call))); + self.last_command = Some(res); + } + ParsedPTBCommand::Publish(sp!(pkg_loc, package_path)) => { + let (dependencies, compiled_modules, _, _) = compile_package( + self.reader, + BuildConfig::default(), + PathBuf::from(package_path), + false, // with_unpublished_dependencies + false, // skip_dependency_verification + ) + .await + .map_err(|e| err!(pkg_loc, "{e}"))?; + + let res = self.ptb.publish_upgradeable( + compiled_modules, + dependencies.published.into_values().collect(), + ); + self.last_command = Some(res); + } + // Update this command to not do as many things. It should result in a single command. + ParsedPTBCommand::Upgrade(sp!(path_loc, package_path), mut arg) => { + if let sp!(loc, PTBArg::Identifier(id)) = arg { + arg = self + .arguments_to_resolve + .get(&id) + .and_then(|x| x.get_unresolved()) + .ok_or_else(|| err!(loc, "Unable to find object ID argument"))? + .clone(); + } + let (cap_loc, upgrade_cap_id) = match arg { + sp!(loc, PTBArg::Address(id)) => (loc, id), + sp!(loc, _) => { + error!(loc, "Expected upgrade capability object ID"); + } + }; + + let upgrade_cap_arg = self + .resolve( + cap_loc.wrap(PTBArg::Address(upgrade_cap_id)), + ToObject::default(), + ) + .await?; + + let (package_id, compiled_modules, dependencies, package_digest, upgrade_policy) = + upgrade_package( + self.reader, + BuildConfig::default(), + PathBuf::from(package_path), + ObjectID::from_address(upgrade_cap_id.into_inner()), + false, // with_unpublished_dependencies + false, // skip_dependency_verification + ) + .await + .map_err(|e| err!(path_loc, "{e}"))?; + + let upgrade_arg = self + .ptb + .pure(upgrade_policy) + .map_err(|e| err!(cmd_span, "{e}"))?; + let digest_arg = self + .ptb + .pure(package_digest) + .map_err(|e| err!(cmd_span, "{e}"))?; + let upgrade_ticket = + self.ptb + .command(Tx::Command::MoveCall(Box::new(Tx::ProgrammableMoveCall { + package: IOTA_FRAMEWORK_PACKAGE_ID, + module: ident_str!("package").to_owned(), + function: ident_str!("authorize_upgrade").to_owned(), + type_arguments: vec![], + arguments: vec![upgrade_cap_arg, upgrade_arg, digest_arg], + }))); + let upgrade_receipt = self.ptb.upgrade( + package_id, + upgrade_ticket, + dependencies.published.into_values().collect(), + compiled_modules, + ); + let res = + self.ptb + .command(Tx::Command::MoveCall(Box::new(Tx::ProgrammableMoveCall { + package: IOTA_FRAMEWORK_PACKAGE_ID, + module: ident_str!("package").to_owned(), + function: ident_str!("commit_upgrade").to_owned(), + type_arguments: vec![], + arguments: vec![upgrade_cap_arg, upgrade_receipt], + }))); + self.last_command = Some(res); + } + ParsedPTBCommand::WarnShadows => {} + ParsedPTBCommand::Preview => {} + } + Ok(()) + } +} + +// =========================================================================== +// Helper methods +// =========================================================================== +pub fn to_ordinal_contraction(num: usize) -> String { + let suffix = match num % 100 { + // exceptions + 11..=13 => "th", + _ => match num % 10 { + 1 => "st", + 2 => "nd", + 3 => "rd", + _ => "th", + }, + }; + format!("{}{}", num, suffix) +} + +pub(crate) fn find_did_you_means<'a>( + needle: &str, + haystack: impl IntoIterator, +) -> Vec<&'a str> { + let mut results = Vec::new(); + let mut best_distance = usize::MAX; + + for item in haystack { + let distance = edit_distance(needle, item); + + match distance.cmp(&best_distance) { + std::cmp::Ordering::Less => { + best_distance = distance; + results.clear(); + results.push(item); + } + std::cmp::Ordering::Equal => { + results.push(item); + } + std::cmp::Ordering::Greater => {} + } + } + + results +} + +pub(crate) fn display_did_you_mean + std::fmt::Display>( + possibles: Vec, +) -> Option { + if possibles.is_empty() { + return None; + } + + let mut strs = vec![]; + + let preposition = if possibles.len() == 1 { + "Did you mean " + } else { + "Did you mean one of " + }; + + let len = possibles.len(); + for (i, possible) in possibles.into_iter().enumerate() { + if i == len - 1 && len > 1 { + strs.push(format!("or '{}'", possible)); + } else { + strs.push(format!("'{}'", possible)); + } + } + + Some(format!("{preposition}{}?", strs.join(", "))) +} + +// This lint is is disabled because it's not good and doesn't look at what +// you're actually iterating over. This seems to be a common problem with this +// lint. See e.g., https://github.com/rust-lang/rust-clippy/issues/6075 +#[allow(clippy::needless_range_loop)] +fn edit_distance(a: &str, b: &str) -> usize { + let mut cache = vec![vec![0; b.len() + 1]; a.len() + 1]; + + for i in 0..=a.len() { + cache[i][0] = i; + } + + for j in 0..=b.len() { + cache[0][j] = j; + } + + for (i, char_a) in a.chars().enumerate().map(|(i, c)| (i + 1, c)) { + for (j, char_b) in b.chars().enumerate().map(|(j, c)| (j + 1, c)) { + if char_a == char_b { + cache[i][j] = cache[i - 1][j - 1]; + } else { + let insert = cache[i][j - 1]; + let delete = cache[i - 1][j]; + let replace = cache[i - 1][j - 1]; + + cache[i][j] = 1 + std::cmp::min(insert, std::cmp::min(delete, replace)); + } + } + } + + cache[a.len()][b.len()] +} diff --git a/crates/sui/src/client_ptb/displays/gas_cost_summary.rs b/crates/iota/src/client_ptb/displays/gas_cost_summary.rs similarity index 90% rename from crates/sui/src/client_ptb/displays/gas_cost_summary.rs rename to crates/iota/src/client_ptb/displays/gas_cost_summary.rs index 6a8e6fee93f..fa8f017179f 100644 --- a/crates/sui/src/client_ptb/displays/gas_cost_summary.rs +++ b/crates/iota/src/client_ptb/displays/gas_cost_summary.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::fmt::{Display, Formatter}; -use sui_types::gas::GasCostSummary; +use iota_types::gas::GasCostSummary; use crate::client_ptb::displays::Pretty; diff --git a/crates/iota/src/client_ptb/displays/mod.rs b/crates/iota/src/client_ptb/displays/mod.rs new file mode 100644 index 00000000000..b99f755de8e --- /dev/null +++ b/crates/iota/src/client_ptb/displays/mod.rs @@ -0,0 +1,10 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod gas_cost_summary; +mod ptb_preview; +mod status; +mod summary; + +pub struct Pretty<'a, T>(pub &'a T); diff --git a/crates/sui/src/client_ptb/displays/ptb_preview.rs b/crates/iota/src/client_ptb/displays/ptb_preview.rs similarity index 98% rename from crates/sui/src/client_ptb/displays/ptb_preview.rs rename to crates/iota/src/client_ptb/displays/ptb_preview.rs index a5eb4025f21..3e6fff0bbfe 100644 --- a/crates/sui/src/client_ptb/displays/ptb_preview.rs +++ b/crates/iota/src/client_ptb/displays/ptb_preview.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::fmt::{Display, Formatter}; diff --git a/crates/iota/src/client_ptb/displays/status.rs b/crates/iota/src/client_ptb/displays/status.rs new file mode 100644 index 00000000000..0a7bc97f144 --- /dev/null +++ b/crates/iota/src/client_ptb/displays/status.rs @@ -0,0 +1,22 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt::{Display, Formatter}; + +use iota_json_rpc_types::IotaExecutionStatus::{self, Failure, Success}; + +use crate::client_ptb::displays::Pretty; + +impl<'a> Display for Pretty<'a, IotaExecutionStatus> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let Pretty(status) = self; + + let output = match status { + Success => "success".to_string(), + Failure { error } => format!("failed due to {error}"), + }; + + write!(f, "{}", output) + } +} diff --git a/crates/sui/src/client_ptb/displays/summary.rs b/crates/iota/src/client_ptb/displays/summary.rs similarity index 95% rename from crates/sui/src/client_ptb/displays/summary.rs rename to crates/iota/src/client_ptb/displays/summary.rs index 9e438ed9f3e..dad3c7d8d45 100644 --- a/crates/sui/src/client_ptb/displays/summary.rs +++ b/crates/iota/src/client_ptb/displays/summary.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::fmt::{Display, Formatter}; diff --git a/crates/iota/src/client_ptb/error.rs b/crates/iota/src/client_ptb/error.rs new file mode 100644 index 00000000000..e9a466cc74d --- /dev/null +++ b/crates/iota/src/client_ptb/error.rs @@ -0,0 +1,212 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt; + +use miette::{miette, LabeledSpan, Severity}; +use thiserror::Error; + +pub type PTBResult = Result; + +/// Represents the location of a range of text in the PTB source. +#[derive(Debug, Clone, PartialEq, Eq, Copy)] +pub struct Span { + pub start: usize, + pub end: usize, +} + +/// A value that has an associated location in source code. +pub struct Spanned { + pub span: Span, + pub value: T, +} + +/// An error with a message, a location in the source code, and an optional help +/// message. +#[derive(Debug, Clone, Error)] +#[error("{message}")] +pub struct PTBError { + pub message: String, + pub span: Span, + pub help: Option, + pub severity: Severity, +} + +#[macro_export] +macro_rules! sp { + (_, $value:pat) => { + $crate::client_ptb::error::Spanned { value: $value, .. } + }; + ($loc:pat, _) => { + $crate::client_ptb::error::Spanned { span: $loc, .. } + }; + ($loc:pat, $value:pat) => { + $crate::client_ptb::error::Spanned { + span: $loc, + value: $value, + } + }; +} + +#[macro_export] +macro_rules! error { + ($l:expr, $($arg:tt)*) => { + return Err($crate::err!($l, $($arg)*)) + }; + ($l:expr => help: { $($h:expr),* }, $($arg:tt)*) => { + return Err($crate::err!($l => help: { $($h),* }, $($arg)*)) + }; +} + +#[macro_export] +macro_rules! err { + ($l:expr, $($arg:tt)*) => { + $crate::client_ptb::error::PTBError { + message: format!($($arg)*), + span: $l, + help: None, + severity: miette::Severity::Error, + } + }; + ($l:expr => help: { $($h:expr),* }, $($arg:tt)*) => { + $crate::client_ptb::error::PTBError { + message: format!($($arg)*), + span: $l, + help: Some(format!($($h),*)), + severity: miette::Severity::Error, + } + }; +} + +pub use sp; + +impl PTBError { + /// Add a help message to an error. + pub fn with_help(self, help: String) -> Self { + let PTBError { + message, + span, + help: _, + severity, + } = self; + PTBError { + message, + span, + help: Some(help), + severity, + } + } +} + +impl Span { + /// Wrap a value with a span. + pub fn wrap(self, value: T) -> Spanned { + Spanned { span: self, value } + } + + /// Widen the span to include another span. The resulting span will start at + /// the minimum of the two start positions and end at the maximum of the + /// two end positions. + pub fn widen(self, other: Span) -> Span { + Span { + start: self.start.min(other.start), + end: self.end.max(other.end), + } + } + + /// Widen the span to include another if it is Some, otherwise return the + /// original span. + pub fn widen_opt(self, other: Option) -> Span { + other.map_or(self, |other| self.widen(other)) + } + + /// Create a span that points to the end of the file/string contents. + pub fn eof_span() -> Span { + Self { + start: usize::MAX, + end: usize::MAX, + } + } +} + +impl Spanned { + /// Apply a function `f` to the underlying value, returning a new `Spanned` + /// with the same span. + pub fn map(self, f: impl FnOnce(T) -> U) -> Spanned { + Spanned { + span: self.span, + value: f(self.value), + } + } + + /// Widen the span to include another span. The resulting span will start at + /// the minimum of the two start positions and end at the maximum of the + /// two end positions. + pub fn widen(self, other: Spanned) -> Spanned { + self.widen_span(other.span) + } + + /// Widen the span to include another span. The resulting span will start at + /// the minimum of the two start positions and end at the maximum of the + /// two end positions. + pub fn widen_span(self, other: Span) -> Spanned { + Spanned { + span: self.span.widen(other), + value: self.value, + } + } +} + +impl fmt::Debug for Spanned { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Spanned") + .field("span", &self.span) + .field("value", &self.value) + .finish() + } +} + +impl Clone for Spanned { + fn clone(&self) -> Self { + Spanned { + span: self.span, + value: self.value.clone(), + } + } +} + +impl Copy for Spanned {} + +fn build_error_report(file_string: &str, error: PTBError) -> miette::Report { + let PTBError { + span, + message, + help, + severity, + } = error; + let clamp = |x: usize| x.min(file_string.len() - 1); + let label = LabeledSpan::at(clamp(span.start)..clamp(span.end), message.clone()); + let error_string = match severity { + Severity::Advice => "Advice found when processing PTB".to_string(), + Severity::Warning => "Warning when processing PTB".to_string(), + Severity::Error => "Error when processing PTB".to_string(), + }; + match help { + Some(help_msg) => miette!(labels = vec![label], help = help_msg, "{}", error_string), + None => miette!( + labels = vec![label], + severity = severity, + "{}", + error_string + ), + } + .with_source_code(file_string.to_string()) +} + +pub fn build_error_reports(source_string: &str, errors: Vec) -> Vec { + errors + .into_iter() + .map(|e| build_error_report(source_string, e)) + .collect() +} diff --git a/crates/sui/src/client_ptb/lexer.rs b/crates/iota/src/client_ptb/lexer.rs similarity index 99% rename from crates/sui/src/client_ptb/lexer.rs rename to crates/iota/src/client_ptb/lexer.rs index 48501ac4cf0..4b7ae69a971 100644 --- a/crates/sui/src/client_ptb/lexer.rs +++ b/crates/iota/src/client_ptb/lexer.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use super::{ diff --git a/crates/iota/src/client_ptb/mod.rs b/crates/iota/src/client_ptb/mod.rs new file mode 100644 index 00000000000..8e130dd39b5 --- /dev/null +++ b/crates/iota/src/client_ptb/mod.rs @@ -0,0 +1,12 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod ast; +pub mod builder; +pub mod displays; +pub mod error; +pub mod lexer; +pub mod parser; +pub mod ptb; +pub mod token; diff --git a/crates/iota/src/client_ptb/parser.rs b/crates/iota/src/client_ptb/parser.rs new file mode 100644 index 00000000000..85174cf94bd --- /dev/null +++ b/crates/iota/src/client_ptb/parser.rs @@ -0,0 +1,1032 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::iter::Peekable; + +use iota_types::{base_types::ObjectID, Identifier}; +use move_command_line_common::{ + address::{NumericalAddress, ParsedAddress}, + parser::{parse_u128, parse_u16, parse_u256, parse_u32, parse_u64, parse_u8}, + types::{ParsedFqName, ParsedModuleId, ParsedStructType, ParsedType}, +}; + +use super::{ + ast::{self as A, is_keyword, Argument, ModuleAccess, ParsedPTBCommand, ParsedProgram}, + error::{PTBError, PTBResult, Span, Spanned}, + lexer::Lexer, + token::{Lexeme, Token}, +}; +use crate::{ + client_ptb::{ + ast::{all_keywords, COMMANDS}, + builder::{display_did_you_mean, find_did_you_means}, + }, + err, error, sp, +}; + +/// Parse a program +pub struct ProgramParser<'a, I: Iterator> { + tokens: Peekable>, + state: ProgramParsingState, +} + +struct ProgramParsingState { + parsed: Vec>, + errors: Vec, + preview_set: bool, + summary_set: bool, + warn_shadows_set: bool, + serialize_unsigned_set: bool, + serialize_signed_set: bool, + json_set: bool, + gas_object_id: Option>, + gas_budget: Option>, +} + +impl<'a, I: Iterator> ProgramParser<'a, I> { + /// Create a PTB program parser from a sequence of string. + pub fn new(tokens: I) -> PTBResult { + let Some(tokens) = Lexer::new(tokens) else { + error!(Span { start: 0, end: 0 }, "No tokens") + }; + Ok(Self { + tokens: tokens.peekable(), + state: ProgramParsingState { + parsed: Vec::new(), + errors: Vec::new(), + preview_set: false, + summary_set: false, + warn_shadows_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + json_set: false, + gas_object_id: None, + gas_budget: None, + }, + }) + } + + /// Parse the sequence of strings into a PTB program. We continue to parse + /// even if an error is raised, and return the errors at the end. If no + /// errors are raised, we return the parsed PTB program along with the + /// metadata that we have parsed (e.g., json output, summary). + pub fn parse(mut self) -> Result> { + use Lexeme as L; + use Token as T; + + while let Some(sp!(sp, lexeme)) = self.tokens.next() { + macro_rules! try_ { + ($expr: expr) => { + match $expr { + Ok(arg) => arg, + Err(err) => { + self.state.errors.push(err); + self.fast_forward_to_next_command(); + continue; + } + } + }; + } + + macro_rules! command { + ($args:expr) => {{ + let sp!(sp_args, value) = try_!($args); + let cmd = sp.widen(sp_args).wrap(value); + self.state.parsed.push(cmd); + }}; + } + + macro_rules! flag { + ($flag:ident) => {{ + self.state.$flag = true; + }}; + } + + match lexeme { + L(T::Command, A::SERIALIZE_UNSIGNED) => flag!(serialize_unsigned_set), + L(T::Command, A::SERIALIZE_SIGNED) => flag!(serialize_signed_set), + L(T::Command, A::SUMMARY) => flag!(summary_set), + L(T::Command, A::JSON) => flag!(json_set), + L(T::Command, A::PREVIEW) => flag!(preview_set), + L(T::Command, A::WARN_SHADOWS) => flag!(warn_shadows_set), + L(T::Command, A::GAS_COIN) => { + let specifier = try_!(self.parse_gas_specifier()); + self.state.gas_object_id = Some(specifier); + } + L(T::Command, A::GAS_BUDGET) => { + let budget = try_!(self.parse_gas_budget()).widen_span(sp); + if let Some(other) = self.state.gas_budget.replace(budget) { + self.state.errors.extend([ + err!( + other.span, + "Multiple gas budgets found. Gas budget first set here.", + ), + err!(budget.span => help: { + "PTBs must have exactly one gas budget set." + },"Budget set again here."), + ]); + self.fast_forward_to_next_command(); + } + } + + L(T::Command, A::TRANSFER_OBJECTS) => command!(self.parse_transfer_objects()), + L(T::Command, A::SPLIT_COINS) => command!(self.parse_split_coins()), + L(T::Command, A::MERGE_COINS) => command!(self.parse_merge_coins()), + L(T::Command, A::ASSIGN) => command!(self.parse_assign()), + L(T::Command, A::MAKE_MOVE_VEC) => command!(self.parse_make_move_vec()), + L(T::Command, A::MOVE_CALL) => command!(self.parse_move_call()), + + L(T::Publish, src) => command!({ + let src = sp.wrap(src.to_owned()); + Ok(sp.wrap(ParsedPTBCommand::Publish(src))) + }), + + L(T::Upgrade, src) => command!({ + let src = sp.wrap(src.to_owned()); + let cap = try_!(self.parse_argument()); + Ok(cap.span.wrap(ParsedPTBCommand::Upgrade(src, cap))) + }), + + L(T::Command, s) => { + let possibles = find_did_you_means(s, COMMANDS.iter().copied()) + .into_iter() + .map(|s| format!("--{s}")) + .collect(); + let err = if let Some(suggestion) = display_did_you_mean(possibles) { + err!( + sp => help: { "{suggestion}" }, + "Unknown {lexeme}", + ) + } else { + err!(sp, "Unknown {lexeme}") + }; + self.state.errors.push(err); + self.fast_forward_to_next_command(); + } + + L(T::Eof, _) => break, + + unexpected => { + let err = err!( + sp => help: { "Expected to find a command here" }, + "Unexpected {unexpected}", + ); + + self.state.errors.push(err); + if unexpected.is_terminal() { + break; + } else { + self.fast_forward_to_next_command(); + } + } + } + } + + let sp!(sp, tok) = self.peek(); + + if !tok.is_terminal() { + self.state + .errors + .push(err!(sp, "Trailing {tok} found after the last command",)); + } + + let Some(gas_budget) = self.state.gas_budget else { + self.state.errors.push(err!( + sp => help: { "Use --gas-budget to set a gas budget" }, + "Gas budget not set." + )); + return Err(self.state.errors); + }; + + if self.state.errors.is_empty() { + Ok(( + A::Program { + commands: self.state.parsed, + warn_shadows_set: self.state.warn_shadows_set, + }, + A::ProgramMetadata { + preview_set: self.state.preview_set, + summary_set: self.state.summary_set, + serialize_unsigned_set: self.state.serialize_unsigned_set, + serialize_signed_set: self.state.serialize_signed_set, + gas_object_id: self.state.gas_object_id, + json_set: self.state.json_set, + gas_budget, + }, + )) + } else { + Err(self.state.errors) + } + } +} + +/// Iterator convenience methods over tokens +impl<'a, I: Iterator> ProgramParser<'a, I> { + /// Advance the iterator and return the next lexeme. If the next lexeme's + /// token is not the expected one, return an error, and don't advance + /// the token stream. + fn expect(&mut self, expected: Token) -> PTBResult>> { + let result @ sp!(sp, lexeme@Lexeme(token, _)) = self.peek(); + Ok(if token == expected { + self.bump(); + result + } else { + error!(sp, "Expected {expected} but found {lexeme}"); + }) + } + + /// Peek at the next token without advancing the iterator. + fn peek(&mut self) -> Spanned> { + *self + .tokens + .peek() + .expect("Lexer returns an infinite stream") + } + + /// Unconditionally advance the next token. It is always safe to do this, + /// because the underlying token stream is "infinite" (the lexer will + /// repeatedly return its terminal token). + fn bump(&mut self) { + self.tokens.next(); + } + + /// Fast forward to the next command token (if any). + fn fast_forward_to_next_command(&mut self) { + loop { + let sp!(_, lexeme) = self.peek(); + if lexeme.is_command_end() { + break; + } + self.bump(); + } + } +} + +/// Methods for parsing commands +impl<'a, I: Iterator> ProgramParser<'a, I> { + /// Parse a transfer-objects command. + /// The expected format is: `--transfer-objects [, ...] ` + fn parse_transfer_objects(&mut self) -> PTBResult> { + let transfer_froms = self.parse_array()?; + let transfer_to = self.parse_argument()?; + let sp = transfer_to.span.widen(transfer_froms.span); + Ok(sp.wrap(ParsedPTBCommand::TransferObjects( + transfer_froms, + transfer_to, + ))) + } + + /// Parse a split-coins command. + /// The expected format is: `--split-coins [, ...]` + fn parse_split_coins(&mut self) -> PTBResult> { + let split_from = self.parse_argument()?; + let splits = self.parse_array()?; + let sp = split_from.span.widen(splits.span); + Ok(sp.wrap(ParsedPTBCommand::SplitCoins(split_from, splits))) + } + + /// Parse a merge-coins command. + /// The expected format is: `--merge-coins [, ...]` + fn parse_merge_coins(&mut self) -> PTBResult> { + let merge_into = self.parse_argument()?; + let coins = self.parse_array()?; + let sp = merge_into.span.widen(coins.span); + Ok(sp.wrap(ParsedPTBCommand::MergeCoins(merge_into, coins))) + } + + /// Parse an assign command. + /// The expected format is: `--assign ()?` + fn parse_assign(&mut self) -> PTBResult> { + use Lexeme as L; + let sp!(sp, L(_, contents)) = self.expect(Token::Ident)?; + if is_keyword(contents) { + error!(sp => help: { + "Variable names cannot be {}.", + all_keywords() + }, + "Expected a variable name but found reserved word '{contents}'."); + } + + let ident = sp.wrap(contents.to_owned()); + + Ok(if self.peek().value.is_command_end() { + ident.span.wrap(ParsedPTBCommand::Assign(ident, None)) + } else { + let value = self.parse_argument()?; + let sp = ident.span.widen(value.span); + sp.wrap(ParsedPTBCommand::Assign(ident, Some(value))) + }) + } + + /// Parse a make-move-vec command + /// The expected format is: `--make-move-vec [, ...]` + fn parse_make_move_vec(&mut self) -> PTBResult> { + use Token as T; + + let sp!(start_sp, _) = self.expect(T::LAngle)?; + let type_ = self.parse_type()?; + self.expect(T::RAngle)?; + + let elems = self.parse_array()?; + + let sp = start_sp.widen(elems.span); + Ok(sp.wrap(ParsedPTBCommand::MakeMoveVec(type_, elems))) + } + + /// Parse a move-call command + /// The expected format is: `--move-call
    :::: + /// (<, ...>)? ...` + fn parse_move_call(&mut self) -> PTBResult> { + use Lexeme as L; + use Token as T; + + let function = self.parse_module_access()?; + let mut end_sp = function.span; + + let ty_args = if let sp!(_, L(T::LAngle, _)) = self.peek() { + let type_args = self.parse_type_args()?; + end_sp = type_args.span; + Some(type_args) + } else { + None + }; + + let mut args = vec![]; + while !self.peek().value.is_command_end() { + let arg = self.parse_argument()?; + end_sp = arg.span; + args.push(arg); + } + + let sp = function.span.widen(end_sp); + Ok(sp.wrap(ParsedPTBCommand::MoveCall(function, ty_args, args))) + } + + /// Parse a gas-budget command. + /// The expected format is: `--gas-budget ` + fn parse_gas_budget(&mut self) -> PTBResult> { + Ok(match self.parse_argument()? { + sp!(sp, Argument::U64(u)) => sp.wrap(u), + sp!(sp, _) => error!(sp, "Expected a u64 value"), + }) + } + + /// Parse a gas specifier. + /// The expected format is: `--gas-coin
    ` + fn parse_gas_specifier(&mut self) -> PTBResult> { + Ok(self + .parse_address_literal()? + .map(|a| ObjectID::from(a.into_inner()))) + } +} + +/// Methods for parsing arguments and types in commands +impl<'a, I: Iterator> ProgramParser<'a, I> { + /// Parse a single PTB argument from the beginning of the token stream. + fn parse_argument(&mut self) -> PTBResult> { + use Argument as V; + use Lexeme as L; + use Token as T; + + let sp!(sp, lexeme) = self.peek(); + Ok(match lexeme { + L(T::Ident, "true") => { + self.bump(); + sp.wrap(V::Bool(true)) + } + + L(T::Ident, "false") => { + self.bump(); + sp.wrap(V::Bool(false)) + } + + L(T::Ident, A::GAS) => { + self.bump(); + sp.wrap(V::Gas) + } + + L(T::Number | T::HexNumber, number) => { + let number = if lexeme.0 == T::HexNumber { + format!("0x{number}") + } else { + number.to_owned() + }; + + self.bump(); + self.parse_number(sp.wrap(&number))? + } + + L(T::At, _) => self.parse_address_literal()?.map(V::Address), + + L(T::Ident, A::NONE) => { + self.bump(); + sp.wrap(V::Option(sp.wrap(None))) + } + + L(T::Ident, A::SOME) => { + self.bump(); + self.expect(T::LParen)?; + let sp!(arg_sp, arg) = self.parse_argument()?; + let sp!(end_sp, _) = self.expect(T::RParen)?; + + let sp = sp.widen(end_sp); + sp.wrap(V::Option(arg_sp.wrap(Some(Box::new(arg))))) + } + + L(T::Ident, A::VECTOR) => { + self.bump(); + self.parse_array()?.map(V::Vector).widen_span(sp) + } + + L(T::Ident, _) => self.parse_variable()?, + + L(T::String, contents) => { + self.bump(); + sp.wrap(V::String(contents.to_owned())) + } + + unexpected => error!( + sp => help: { "Expected an argument here" }, + "Unexpected {unexpected}", + ), + }) + } + + /// Parse a type. + fn parse_type(&mut self) -> PTBResult> { + use Lexeme as L; + use Token as T; + + let sp!(sp, lexeme) = self.peek(); + + macro_rules! type_ { + ($ty: expr) => {{ + self.bump(); + sp.wrap($ty) + }}; + } + + Ok(match lexeme { + L(T::Ident, A::U8) => type_!(ParsedType::U8), + L(T::Ident, A::U16) => type_!(ParsedType::U16), + L(T::Ident, A::U32) => type_!(ParsedType::U32), + L(T::Ident, A::U64) => type_!(ParsedType::U64), + L(T::Ident, A::U128) => type_!(ParsedType::U128), + L(T::Ident, A::U256) => type_!(ParsedType::U256), + L(T::Ident, A::BOOL) => type_!(ParsedType::Bool), + L(T::Ident, A::ADDRESS) => type_!(ParsedType::Address), + + L(T::Ident, A::VECTOR) => { + self.bump(); + self.expect(T::LAngle)?; + let sp!(_, ty) = self.parse_type()?; + let sp!(end_sp, _) = self.expect(T::RAngle)?; + + let sp = sp.widen(end_sp); + sp.wrap(ParsedType::Vector(Box::new(ty))) + } + + L(T::Ident | T::Number | T::HexNumber, _) => 'fq: { + let sp!(_, module_access) = self.parse_module_access()?; + let sp!(_, address) = module_access.address; + let sp!(_, module_name) = module_access.module_name; + let sp!(fun_sp, function_name) = module_access.function_name; + + let module = ParsedModuleId { + address, + name: module_name.to_string(), + }; + + let name = function_name.to_string(); + let fq_name = ParsedFqName { module, name }; + + let sp!(_, L(T::LAngle, _)) = self.peek() else { + let sp = sp.widen(fun_sp); + break 'fq sp.wrap(ParsedType::Struct(ParsedStructType { + fq_name, + type_args: vec![], + })); + }; + + let sp!(tys_sp, type_args) = self.parse_type_args()?; + + let sp = sp.widen(tys_sp); + sp.wrap(ParsedType::Struct(ParsedStructType { fq_name, type_args })) + } + + unexpected => error!( + sp => help: { "Expected a type here" }, + "Unexpected {unexpected}", + ), + }) + } + + /// Parse a fully-qualified name, corresponding to accessing a function or + /// type from a module. + fn parse_module_access(&mut self) -> PTBResult> { + use Lexeme as L; + use Token as T; + + let address = self.parse_address()?; + + self.expect(T::ColonColon)?; + let sp!(mod_sp, L(_, module_name)) = self.expect(T::Ident)?; + let module_name = Identifier::new(module_name) + .map_err(|_| err!(mod_sp, "Invalid module name {module_name:?}"))?; + + self.expect(T::ColonColon)?; + let sp!(fun_sp, L(_, function_name)) = self.expect(T::Ident)?; + let function_name = Identifier::new(function_name) + .map_err(|_| err!(fun_sp, "Invalid function name {function_name:?}"))?; + + let sp = address.span.widen(fun_sp); + Ok(sp.wrap(ModuleAccess { + address, + module_name: mod_sp.wrap(module_name), + function_name: fun_sp.wrap(function_name), + })) + } + + /// Parse a list of type arguments, surrounded by angle brackets, and + /// separated by commas. + fn parse_type_args(&mut self) -> PTBResult>> { + use Lexeme as L; + use Token as T; + + let sp!(start_sp, _) = self.expect(T::LAngle)?; + + let mut type_args = vec![]; + loop { + type_args.push(self.parse_type()?.value); + + let sp!(sp, lexeme) = self.peek(); + match lexeme { + L(T::Comma, _) => self.bump(), + L(T::RAngle, _) => break, + unexpected => error!( + sp => help: { "Expected {} or {}", T::Comma, T::RAngle }, + "Unexpected {unexpected}", + ), + } + } + + let sp!(end_sp, _) = self.expect(T::RAngle)?; + Ok(start_sp.widen(end_sp).wrap(type_args)) + } + + /// Parse a variable access (a non-empty chain of identifiers, separated by + /// '.') + fn parse_variable(&mut self) -> PTBResult> { + use Lexeme as L; + use Token as T; + + let sp!(start_sp, L(_, ident)) = self.expect(T::Ident)?; + let ident = start_sp.wrap(ident.to_owned()); + + let sp!(_, L(T::Dot, _)) = self.peek() else { + return Ok(start_sp.wrap(Argument::Identifier(ident.value))); + }; + + self.bump(); + let mut fields = vec![]; + loop { + // A field can be any non-terminal token (identifier, number, etc). + let sp!(sp, lexeme@L(_, field)) = self.peek(); + if lexeme.is_terminal() { + error!(sp, "Expected a field name after '.'"); + } + + self.bump(); + fields.push(sp.wrap(field.to_owned())); + + if let sp!(_, L(T::Dot, _)) = self.peek() { + self.bump(); + } else { + break; + } + } + + let end_sp = fields.last().map(|f| f.span).unwrap_or(start_sp); + let sp = start_sp.widen(end_sp); + Ok(sp.wrap(Argument::VariableAccess(ident, fields))) + } + + /// Parse a decimal or hexadecimal number, optionally followed by a type + /// suffix. + fn parse_number(&mut self, contents: Spanned<&str>) -> PTBResult> { + use Argument as V; + use Lexeme as L; + use Token as T; + + let sp!(sp, suffix) = self.peek(); + + macro_rules! parse_num { + ($fn: ident, $ty: expr) => {{ + self.bump(); + let sp = sp.widen(contents.span); + match $fn(contents.value) { + Ok((value, _)) => sp.wrap($ty(value)), + Err(e) => error!(sp, "{e}"), + } + }}; + } + + Ok(match suffix { + L(T::Ident, A::U8) => parse_num!(parse_u8, V::U8), + L(T::Ident, A::U16) => parse_num!(parse_u16, V::U16), + L(T::Ident, A::U32) => parse_num!(parse_u32, V::U32), + L(T::Ident, A::U64) => parse_num!(parse_u64, V::U64), + L(T::Ident, A::U128) => parse_num!(parse_u128, V::U128), + L(T::Ident, A::U256) => parse_num!(parse_u256, V::U256), + + // If there's no suffix, assume u64, and don't consume the peeked character. + _ => match parse_u64(contents.value) { + Ok((value, _)) => contents.span.wrap(V::U64(value)), + Err(e) => error!(contents.span, "{e}"), + }, + }) + } + + /// Parse a numerical or named address. + fn parse_address(&mut self) -> PTBResult> { + use Lexeme as L; + use Token as T; + + let sp!(sp, lexeme) = self.peek(); + let addr = match lexeme { + L(T::Ident, name) => { + self.bump(); + ParsedAddress::Named(name.to_owned()) + } + + L(T::Number, number) => { + self.bump(); + NumericalAddress::parse_str(number) + .map_err(|e| err!(sp, "Failed to parse address {number:?}: {e}")) + .map(ParsedAddress::Numerical)? + } + + L(T::HexNumber, number) => { + self.bump(); + let number = format!("0x{number}"); + NumericalAddress::parse_str(&number) + .map_err(|e| err!(sp, "Failed to parse address {number:?}: {e}")) + .map(ParsedAddress::Numerical)? + } + + unexpected => error!( + sp => help: { + "Value addresses can either be a variable in-scope, or a numerical address, \ + e.g., 0xc0ffee" + }, + "Unexpected {unexpected}", + ), + }; + + Ok(sp.wrap(addr)) + } + + /// Parse a numeric addres literal (must be prefixed by an `@` symbol). + fn parse_address_literal(&mut self) -> PTBResult> { + let sp!(sp, _) = self.expect(Token::At).map_err(|e| { + err!(e.span => help: { + "Addresses or object IDs require the character '@' in front" + }, "Expected an address") + })?; + + Ok(match self.parse_address()?.widen_span(sp) { + sp!(sp, ParsedAddress::Numerical(n)) => sp.wrap(n), + sp!(sp, ParsedAddress::Named(n)) => error!( + sp, + "Expected a numerical address but got a named address '{n}'", + ), + }) + } + + // Parse an array of arguments. Each element of the array is separated by a + // comma. + fn parse_array(&mut self) -> PTBResult>>> { + use Lexeme as L; + use Token as T; + let sp!(start_sp, _) = self.expect(T::LBracket)?; + + let mut values = vec![]; + loop { + let sp!(sp, lexeme) = self.peek(); + if lexeme.is_terminal() { + error!( + sp => help: { "Expected an array here" }, + "Unexpected {lexeme}" + ); + } else if let L(T::RBracket, _) = lexeme { + break; + } + + values.push(self.parse_argument()?); + + let sp!(sp, lexeme) = self.peek(); + match lexeme { + L(T::RBracket, _) => break, + L(T::Comma, _) => self.bump(), + unexpected => error!( + sp => help: { "Expected {} or {}", T::RBracket, T::Comma }, + "Unexpected {unexpected}", + ), + } + } + + let sp!(end_sp, _) = self.expect(T::RBracket)?; + Ok(start_sp.widen(end_sp).wrap(values)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse() { + let input = "--transfer-objects [b, c] a"; + let mut x = shlex::split(input).unwrap(); + x.push("--gas-budget 1".to_owned()); + let parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); + let result = parser.parse(); + assert!(result.is_ok()); + } + + #[test] + fn test_parse_unexpected_top_level() { + let input = "\"0x\" "; + let x = shlex::split(input).unwrap(); + let parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); + let result = parser.parse(); + insta::assert_debug_snapshot!(result.unwrap_err()); + } + + #[test] + fn test_parse_publish() { + let inputs = vec!["--publish \"foo/bar\"", "--publish foo/bar"]; + let mut parsed = Vec::new(); + for input in inputs { + let mut x = shlex::split(input).unwrap(); + x.push("--gas-budget 1".to_owned()); + let parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); + let result = parser.parse().unwrap(); + parsed.push(result); + } + insta::assert_debug_snapshot!(parsed); + } + + #[test] + fn test_parse_args() { + let inputs = vec![ + // Bools + "true", + "false", + // Integers + "1", + "1_000", + "100_000_000", + "100_000u64", + "1u8", + "1_u128", + "0x1", + "0x1_000", + "0x100_000_000", + "0x100_000u64", + "0x1u8", + "0x1_u128", + // Addresses + "@0x1", + "@0x1_000", + "@0x100_000_000", + "@0x100_000u64", + "@0x1u8", + "@0x1_u128", + // Option + "none", + "some(1)", + "some(0x1)", + "some(some(some(some(1u128))))", + // vector + "vector[]", + "vector[1, 2, 3]", + "vector[1, 2, 3,]", + // Dotted access + "foo.bar", + "foo.bar.baz", + "foo.bar.baz.qux", + "foo.0", + "foo.0.1", + ]; + let mut parsed = Vec::new(); + for input in inputs { + let mut x = shlex::split(input).unwrap(); + x.push("--gas-budget 1".to_owned()); + let mut parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); + let result = parser + .parse_argument() + .unwrap_or_else(|e| panic!("Failed on {input:?}: {e:?}")); + parsed.push(result); + } + insta::assert_debug_snapshot!(parsed); + } + + #[test] + fn test_parse_args_invalid() { + let inputs = vec![ + // Integers + "0xfffu8", // addresses + "@n", // options + "some", + "some(", + "some(1", + // vectors + "vector", + "vector[", + "vector[1,", + "vector[1 2]", + "vector[,]", + // Dotted access + "foo.", + ".", + ]; + let mut parsed = Vec::new(); + for input in inputs { + let x = shlex::split(input).unwrap(); + let mut parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); + let result = parser.parse_argument().unwrap_err(); + parsed.push(result); + } + insta::assert_debug_snapshot!(parsed); + } + + #[test] + fn test_parse_types() { + let inputs = vec![ + // Primitives + "u8", + "u16", + "u32", + "u64", + "u128", + "u256", + "bool", + "address", + "vector", + // Structs + "iota::object::ID", + "0x2::object::UID", + "3::staking_pool::StakedIota", + // Generic types + "0x2::coin::Coin<2::iota::IOTA>", + "iota::table::Table>>", + ]; + let mut parsed = Vec::new(); + for input in inputs { + let mut x = shlex::split(input).unwrap(); + x.push("--gas-budget 1".to_owned()); + let mut parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); + let result = parser + .parse_type() + .unwrap_or_else(|e| panic!("Failed on {input:?}: {e:?}")); + parsed.push(result); + } + insta::assert_debug_snapshot!(parsed); + } + + #[test] + fn test_parse_types_invalid() { + let inputs = vec![ + "signer", + "not-an-identifier", + "vector", + "foo::", + "foo::bar", + "foo::bar::Baz<", + "foo::bar::Baz []", + "--make-move-vec [1u8, 2u8]", + // Move Call + "--move-call 0x3::iota_system::request_add_stake system coins.0 validator", + "--move-call std::option::is_none p", + "--move-call std::option::is_some q", + // Assign + "--assign a", + "--assign a b.1", + "--assign a 1u8", + "--assign a @0x1", + "--assign a vector[1, 2, 3]", + "--assign a none", + "--assign a some(1)", + // Gas-coin + "--gas-coin @0x1", + "--summary", + "--json", + "--preview", + "--warn-shadows", + ]; + let mut parsed = Vec::new(); + for input in inputs { + let mut x = shlex::split(input).unwrap(); + x.push("--gas-budget 1".to_owned()); + let parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); + let result = parser + .parse() + .unwrap_or_else(|e| panic!("Failed on {input:?}: {e:?}")); + parsed.push(result); + } + insta::assert_debug_snapshot!(parsed); + } + + #[test] + fn test_parse_commands_invalid() { + let inputs = vec![ + // Publish + "--publish", + // Upgrade + "--upgrade", + "--upgrade 1", + // Transfer objects + "--transfer-objects a", + "--transfer-objects [b]", + "--transfer-objects", + "--transfer-objects [a] [b]", + // Split coins + "--split-coins a", + "--split-coins [b]", + "--split-coins", + "--split-coins a b c", + "--split-coins a [b] c", + // Merge coins + "--merge-coins a", + "--merge-coins [b]", + "--merge-coins", + "--merge-coins a b c", + "--merge-coins a [b] c", + // Make Move Vec + "--make-move-vec", + "--make-move-vec [1, 2, 3]", + "--make-move-vec ", + // Move Call + "--move-call", + "--move-call 0x1::option::is_none []", + // Assign + "--assign", + "--assign a b c", + "--assign none b", + "--assign some none", + "--assign a.3 1u8", + // Gas budget + "--gas-budget 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "--gas-budget [1]", + "--gas-budget @0x1", + "--gas-budget woah", + // Gas-coin + "--gas-coin nope", + "--gas-coin", + "--gas-coin @0x1 @0x2", + "--gas-coin 1", + ]; + let mut parsed = Vec::new(); + for input in inputs { + let x = shlex::split(input).unwrap(); + let parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); + let result = parser.parse().unwrap_err(); + parsed.push(result); + } + insta::assert_debug_snapshot!(parsed); + } +} diff --git a/crates/sui/src/client_ptb/ptb.rs b/crates/iota/src/client_ptb/ptb.rs similarity index 94% rename from crates/sui/src/client_ptb/ptb.rs rename to crates/iota/src/client_ptb/ptb.rs index f1030490848..66d1188ef66 100644 --- a/crates/sui/src/client_ptb/ptb.rs +++ b/crates/iota/src/client_ptb/ptb.rs @@ -1,19 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeSet; use anyhow::{anyhow, Error}; use clap::{arg, Args, ValueHint}; -use move_core_types::account_address::AccountAddress; -use serde::Serialize; -use shared_crypto::intent::Intent; -use sui_json_rpc_types::{ - SuiExecutionStatus, SuiTransactionBlockEffectsAPI, SuiTransactionBlockResponseOptions, +use iota_json_rpc_types::{ + IotaExecutionStatus, IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponseOptions, }; -use sui_keys::keystore::AccountKeystore; -use sui_sdk::{wallet_context::WalletContext, SuiClient}; -use sui_types::{ +use iota_keys::keystore::AccountKeystore; +use iota_sdk::{wallet_context::WalletContext, IotaClient}; +use iota_types::{ digests::TransactionDigest, gas::GasCostSummary, quorum_driver_types::ExecuteTransactionRequestType, @@ -21,10 +19,13 @@ use sui_types::{ ProgrammableTransaction, SenderSignedData, Transaction, TransactionData, TransactionDataAPI, }, }; +use move_core_types::account_address::AccountAddress; +use serde::Serialize; +use shared_crypto::intent::Intent; use super::{ast::ProgramMetadata, lexer::Lexer, parser::ProgramParser}; use crate::{ - client_commands::SuiClientCommandResult, + client_commands::IotaClientCommandResult, client_ptb::{ ast::{ParsedProgram, Program}, builder::PTBBuilder, @@ -50,7 +51,7 @@ pub struct PTBPreview<'a> { #[derive(Serialize)] pub struct Summary { pub digest: TransactionDigest, - pub status: SuiExecutionStatus, + pub status: IotaExecutionStatus, pub gas_cost: GasCostSummary, } @@ -181,7 +182,7 @@ impl PTB { context .config .keystore - .sign_secure(&sender, &tx_data, Intent::sui_transaction())?; + .sign_secure(&sender, &tx_data, Intent::iota_transaction())?; // execute the transaction let transaction_response = context @@ -190,7 +191,7 @@ impl PTB { .quorum_driver_api() .execute_transaction_block( Transaction::from_data(tx_data, vec![signature]), - SuiTransactionBlockResponseOptions::full_content(), + IotaTransactionBlockResponseOptions::full_content(), Some(ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?; @@ -238,7 +239,7 @@ impl PTB { pub async fn build_ptb( program: Program, context: &WalletContext, - client: SuiClient, + client: IotaClient, ) -> ( Result>, Vec, @@ -289,7 +290,7 @@ pub fn to_source_string(strings: Vec) -> String { } pub fn ptb_description() -> clap::Command { - clap::Command::new("sui client ptb") + clap::Command::new("iota client ptb") .about( "Build, preview, and execute programmable transaction blocks. Depending on your \ shell, you might have to use quotes around arrays or other passed values. \ @@ -317,8 +318,8 @@ pub fn ptb_description() -> clap::Command { gas coin that it finds that has at least the requested gas-budget balance." )) .arg(arg!( - --"gas-budget" - "The gas budget for the transaction, in MIST." + --"gas-budget" + "The gas budget for the transaction, in MICROS." )) .arg(arg!( --"make-move-vec" @@ -332,7 +333,7 @@ pub fn ptb_description() -> clap::Command { \n --make-move-vec []\ \n --make-move-vec [1, 2, 3, 4]\ \n --make-move-vec > [none,none]\ - \n --make-move-vec > [gas]" + \n --make-move-vec > [gas]" ) .value_names(["TYPE", "[VALUES]"])) .arg(arg!( @@ -387,7 +388,7 @@ pub fn ptb_description() -> clap::Command { ).long_help( "Publish the Move package. It takes as input the folder where the package exists.\ \n\nExamples:\ - \n --move-call sui::tx_context::sender\ + \n --move-call iota::tx_context::sender\ \n --assign sender\ \n --publish \".\"\ \n --assign upgrade_cap\ diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__dotted_idents.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__dotted_idents.snap new file mode 100644 index 00000000000..ef8f6c7a8c6 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__dotted_idents.snap @@ -0,0 +1,266 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: lex(idents) +--- +[ + Spanned { + span: Span { + start: 0, + end: 1, + }, + value: Lexeme( + Ident, + "a", + ), + }, + Spanned { + span: Span { + start: 2, + end: 3, + }, + value: Lexeme( + Ident, + "a", + ), + }, + Spanned { + span: Span { + start: 3, + end: 4, + }, + value: Lexeme( + Dot, + ".", + ), + }, + Spanned { + span: Span { + start: 4, + end: 5, + }, + value: Lexeme( + Ident, + "b", + ), + }, + Spanned { + span: Span { + start: 6, + end: 7, + }, + value: Lexeme( + Ident, + "a", + ), + }, + Spanned { + span: Span { + start: 7, + end: 8, + }, + value: Lexeme( + Dot, + ".", + ), + }, + Spanned { + span: Span { + start: 8, + end: 9, + }, + value: Lexeme( + Ident, + "b", + ), + }, + Spanned { + span: Span { + start: 9, + end: 10, + }, + value: Lexeme( + Dot, + ".", + ), + }, + Spanned { + span: Span { + start: 10, + end: 11, + }, + value: Lexeme( + Ident, + "c", + ), + }, + Spanned { + span: Span { + start: 12, + end: 13, + }, + value: Lexeme( + Ident, + "a", + ), + }, + Spanned { + span: Span { + start: 13, + end: 14, + }, + value: Lexeme( + Dot, + ".", + ), + }, + Spanned { + span: Span { + start: 14, + end: 15, + }, + value: Lexeme( + Ident, + "b", + ), + }, + Spanned { + span: Span { + start: 15, + end: 16, + }, + value: Lexeme( + Dot, + ".", + ), + }, + Spanned { + span: Span { + start: 16, + end: 17, + }, + value: Lexeme( + Ident, + "c", + ), + }, + Spanned { + span: Span { + start: 17, + end: 18, + }, + value: Lexeme( + Dot, + ".", + ), + }, + Spanned { + span: Span { + start: 18, + end: 19, + }, + value: Lexeme( + Ident, + "d", + ), + }, + Spanned { + span: Span { + start: 20, + end: 21, + }, + value: Lexeme( + Ident, + "a", + ), + }, + Spanned { + span: Span { + start: 21, + end: 22, + }, + value: Lexeme( + Dot, + ".", + ), + }, + Spanned { + span: Span { + start: 22, + end: 23, + }, + value: Lexeme( + Ident, + "b", + ), + }, + Spanned { + span: Span { + start: 23, + end: 24, + }, + value: Lexeme( + Dot, + ".", + ), + }, + Spanned { + span: Span { + start: 24, + end: 25, + }, + value: Lexeme( + Ident, + "c", + ), + }, + Spanned { + span: Span { + start: 25, + end: 26, + }, + value: Lexeme( + Dot, + ".", + ), + }, + Spanned { + span: Span { + start: 26, + end: 27, + }, + value: Lexeme( + Ident, + "d", + ), + }, + Spanned { + span: Span { + start: 27, + end: 28, + }, + value: Lexeme( + Dot, + ".", + ), + }, + Spanned { + span: Span { + start: 28, + end: 29, + }, + value: Lexeme( + Ident, + "e", + ), + }, + Spanned { + span: Span { + start: 29, + end: 29, + }, + value: Lexeme( + Eof, + "", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__functions.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__functions.snap new file mode 100644 index 00000000000..cc072334601 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__functions.snap @@ -0,0 +1,376 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: lex(funs) +--- +[ + Spanned { + span: Span { + start: 0, + end: 3, + }, + value: Lexeme( + HexNumber, + "2", + ), + }, + Spanned { + span: Span { + start: 3, + end: 5, + }, + value: Lexeme( + ColonColon, + "::", + ), + }, + Spanned { + span: Span { + start: 5, + end: 13, + }, + value: Lexeme( + Ident, + "transfer", + ), + }, + Spanned { + span: Span { + start: 13, + end: 15, + }, + value: Lexeme( + ColonColon, + "::", + ), + }, + Spanned { + span: Span { + start: 15, + end: 30, + }, + value: Lexeme( + Ident, + "public_transfer", + ), + }, + Spanned { + span: Span { + start: 30, + end: 31, + }, + value: Lexeme( + LAngle, + "<", + ), + }, + Spanned { + span: Span { + start: 31, + end: 35, + }, + value: Lexeme( + HexNumber, + "42", + ), + }, + Spanned { + span: Span { + start: 35, + end: 37, + }, + value: Lexeme( + ColonColon, + "::", + ), + }, + Spanned { + span: Span { + start: 37, + end: 40, + }, + value: Lexeme( + Ident, + "foo", + ), + }, + Spanned { + span: Span { + start: 40, + end: 42, + }, + value: Lexeme( + ColonColon, + "::", + ), + }, + Spanned { + span: Span { + start: 42, + end: 45, + }, + value: Lexeme( + Ident, + "Bar", + ), + }, + Spanned { + span: Span { + start: 45, + end: 46, + }, + value: Lexeme( + RAngle, + ">", + ), + }, + Spanned { + span: Span { + start: 47, + end: 50, + }, + value: Lexeme( + Ident, + "std", + ), + }, + Spanned { + span: Span { + start: 50, + end: 52, + }, + value: Lexeme( + ColonColon, + "::", + ), + }, + Spanned { + span: Span { + start: 52, + end: 58, + }, + value: Lexeme( + Ident, + "option", + ), + }, + Spanned { + span: Span { + start: 58, + end: 60, + }, + value: Lexeme( + ColonColon, + "::", + ), + }, + Spanned { + span: Span { + start: 60, + end: 67, + }, + value: Lexeme( + Ident, + "is_none", + ), + }, + Spanned { + span: Span { + start: 67, + end: 68, + }, + value: Lexeme( + LAngle, + "<", + ), + }, + Spanned { + span: Span { + start: 68, + end: 71, + }, + value: Lexeme( + Ident, + "u64", + ), + }, + Spanned { + span: Span { + start: 71, + end: 72, + }, + value: Lexeme( + RAngle, + ">", + ), + }, + Spanned { + span: Span { + start: 73, + end: 76, + }, + value: Lexeme( + HexNumber, + "1", + ), + }, + Spanned { + span: Span { + start: 76, + end: 78, + }, + value: Lexeme( + ColonColon, + "::", + ), + }, + Spanned { + span: Span { + start: 78, + end: 84, + }, + value: Lexeme( + Ident, + "option", + ), + }, + Spanned { + span: Span { + start: 84, + end: 86, + }, + value: Lexeme( + ColonColon, + "::", + ), + }, + Spanned { + span: Span { + start: 86, + end: 93, + }, + value: Lexeme( + Ident, + "is_some", + ), + }, + Spanned { + span: Span { + start: 94, + end: 95, + }, + value: Lexeme( + LAngle, + "<", + ), + }, + Spanned { + span: Span { + start: 95, + end: 98, + }, + value: Lexeme( + Ident, + "u64", + ), + }, + Spanned { + span: Span { + start: 98, + end: 99, + }, + value: Lexeme( + RAngle, + ">", + ), + }, + Spanned { + span: Span { + start: 100, + end: 103, + }, + value: Lexeme( + HexNumber, + "1", + ), + }, + Spanned { + span: Span { + start: 103, + end: 105, + }, + value: Lexeme( + ColonColon, + "::", + ), + }, + Spanned { + span: Span { + start: 105, + end: 111, + }, + value: Lexeme( + Ident, + "option", + ), + }, + Spanned { + span: Span { + start: 111, + end: 113, + }, + value: Lexeme( + ColonColon, + "::", + ), + }, + Spanned { + span: Span { + start: 113, + end: 120, + }, + value: Lexeme( + Ident, + "is_none", + ), + }, + Spanned { + span: Span { + start: 121, + end: 122, + }, + value: Lexeme( + LAngle, + "<", + ), + }, + Spanned { + span: Span { + start: 122, + end: 125, + }, + value: Lexeme( + Ident, + "u64", + ), + }, + Spanned { + span: Span { + start: 125, + end: 126, + }, + value: Lexeme( + RAngle, + ">", + ), + }, + Spanned { + span: Span { + start: 126, + end: 126, + }, + value: Lexeme( + Eof, + "", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__gas.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__gas.snap new file mode 100644 index 00000000000..07ca48d57eb --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__gas.snap @@ -0,0 +1,26 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: lex(gas) +--- +[ + Spanned { + span: Span { + start: 0, + end: 3, + }, + value: Lexeme( + Ident, + "gas", + ), + }, + Spanned { + span: Span { + start: 3, + end: 3, + }, + value: Lexeme( + Eof, + "", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_address.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_address.snap new file mode 100644 index 00000000000..7571da24143 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_address.snap @@ -0,0 +1,166 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: lex(addrs) +--- +[ + Spanned { + span: Span { + start: 0, + end: 1, + }, + value: Lexeme( + At, + "@", + ), + }, + Spanned { + span: Span { + start: 1, + end: 4, + }, + value: Lexeme( + HexNumber, + "1", + ), + }, + Spanned { + span: Span { + start: 5, + end: 6, + }, + value: Lexeme( + At, + "@", + ), + }, + Spanned { + span: Span { + start: 6, + end: 13, + }, + value: Lexeme( + HexNumber, + "1_000", + ), + }, + Spanned { + span: Span { + start: 14, + end: 15, + }, + value: Lexeme( + At, + "@", + ), + }, + Spanned { + span: Span { + start: 15, + end: 28, + }, + value: Lexeme( + HexNumber, + "100_000_000", + ), + }, + Spanned { + span: Span { + start: 29, + end: 30, + }, + value: Lexeme( + At, + "@", + ), + }, + Spanned { + span: Span { + start: 30, + end: 39, + }, + value: Lexeme( + HexNumber, + "100_000", + ), + }, + Spanned { + span: Span { + start: 39, + end: 42, + }, + value: Lexeme( + Ident, + "u64", + ), + }, + Spanned { + span: Span { + start: 43, + end: 44, + }, + value: Lexeme( + At, + "@", + ), + }, + Spanned { + span: Span { + start: 44, + end: 47, + }, + value: Lexeme( + HexNumber, + "1", + ), + }, + Spanned { + span: Span { + start: 47, + end: 49, + }, + value: Lexeme( + Ident, + "u8", + ), + }, + Spanned { + span: Span { + start: 50, + end: 51, + }, + value: Lexeme( + At, + "@", + ), + }, + Spanned { + span: Span { + start: 51, + end: 55, + }, + value: Lexeme( + HexNumber, + "1_", + ), + }, + Spanned { + span: Span { + start: 55, + end: 59, + }, + value: Lexeme( + Ident, + "u128", + ), + }, + Spanned { + span: Span { + start: 59, + end: 59, + }, + value: Lexeme( + Eof, + "", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_args.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_args.snap new file mode 100644 index 00000000000..0bab36a62a5 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_args.snap @@ -0,0 +1,796 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: lex(args) +--- +[ + Spanned { + span: Span { + start: 0, + end: 1, + }, + value: Lexeme( + At, + "@", + ), + }, + Spanned { + span: Span { + start: 1, + end: 4, + }, + value: Lexeme( + HexNumber, + "1", + ), + }, + Spanned { + span: Span { + start: 5, + end: 6, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 7, + end: 8, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 8, + end: 10, + }, + value: Lexeme( + Ident, + "u8", + ), + }, + Spanned { + span: Span { + start: 11, + end: 13, + }, + value: Lexeme( + Number, + "1_", + ), + }, + Spanned { + span: Span { + start: 13, + end: 17, + }, + value: Lexeme( + Ident, + "u128", + ), + }, + Spanned { + span: Span { + start: 18, + end: 23, + }, + value: Lexeme( + Number, + "1_000", + ), + }, + Spanned { + span: Span { + start: 24, + end: 35, + }, + value: Lexeme( + Number, + "100_000_000", + ), + }, + Spanned { + span: Span { + start: 36, + end: 43, + }, + value: Lexeme( + Number, + "100_000", + ), + }, + Spanned { + span: Span { + start: 43, + end: 46, + }, + value: Lexeme( + Ident, + "u64", + ), + }, + Spanned { + span: Span { + start: 47, + end: 48, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 49, + end: 50, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 50, + end: 51, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 51, + end: 52, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 53, + end: 54, + }, + value: Lexeme( + Number, + "2", + ), + }, + Spanned { + span: Span { + start: 54, + end: 55, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 56, + end: 57, + }, + value: Lexeme( + Number, + "3", + ), + }, + Spanned { + span: Span { + start: 57, + end: 58, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 59, + end: 60, + }, + value: Lexeme( + Number, + "4", + ), + }, + Spanned { + span: Span { + start: 60, + end: 61, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 62, + end: 63, + }, + value: Lexeme( + Number, + "5", + ), + }, + Spanned { + span: Span { + start: 63, + end: 64, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 65, + end: 66, + }, + value: Lexeme( + Number, + "6", + ), + }, + Spanned { + span: Span { + start: 66, + end: 67, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 68, + end: 69, + }, + value: Lexeme( + Number, + "7", + ), + }, + Spanned { + span: Span { + start: 69, + end: 70, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 71, + end: 72, + }, + value: Lexeme( + Number, + "8", + ), + }, + Spanned { + span: Span { + start: 72, + end: 73, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 74, + end: 75, + }, + value: Lexeme( + Number, + "9", + ), + }, + Spanned { + span: Span { + start: 75, + end: 76, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 77, + end: 79, + }, + value: Lexeme( + Number, + "10", + ), + }, + Spanned { + span: Span { + start: 79, + end: 80, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 81, + end: 87, + }, + value: Lexeme( + Ident, + "vector", + ), + }, + Spanned { + span: Span { + start: 87, + end: 88, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 88, + end: 89, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 90, + end: 96, + }, + value: Lexeme( + Ident, + "vector", + ), + }, + Spanned { + span: Span { + start: 96, + end: 97, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 97, + end: 98, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 98, + end: 99, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 99, + end: 100, + }, + value: Lexeme( + Number, + "2", + ), + }, + Spanned { + span: Span { + start: 100, + end: 101, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 101, + end: 102, + }, + value: Lexeme( + Number, + "3", + ), + }, + Spanned { + span: Span { + start: 102, + end: 103, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 104, + end: 110, + }, + value: Lexeme( + Ident, + "vector", + ), + }, + Spanned { + span: Span { + start: 110, + end: 111, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 111, + end: 112, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 112, + end: 113, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 114, + end: 118, + }, + value: Lexeme( + Ident, + "some", + ), + }, + Spanned { + span: Span { + start: 118, + end: 119, + }, + value: Lexeme( + LParen, + "(", + ), + }, + Spanned { + span: Span { + start: 119, + end: 120, + }, + value: Lexeme( + At, + "@", + ), + }, + Spanned { + span: Span { + start: 120, + end: 123, + }, + value: Lexeme( + HexNumber, + "1", + ), + }, + Spanned { + span: Span { + start: 123, + end: 124, + }, + value: Lexeme( + RParen, + ")", + ), + }, + Spanned { + span: Span { + start: 125, + end: 129, + }, + value: Lexeme( + Ident, + "none", + ), + }, + Spanned { + span: Span { + start: 130, + end: 134, + }, + value: Lexeme( + Ident, + "some", + ), + }, + Spanned { + span: Span { + start: 134, + end: 135, + }, + value: Lexeme( + LParen, + "(", + ), + }, + Spanned { + span: Span { + start: 135, + end: 141, + }, + value: Lexeme( + Ident, + "vector", + ), + }, + Spanned { + span: Span { + start: 141, + end: 142, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 142, + end: 143, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 143, + end: 144, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 144, + end: 145, + }, + value: Lexeme( + Number, + "2", + ), + }, + Spanned { + span: Span { + start: 145, + end: 146, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 146, + end: 147, + }, + value: Lexeme( + Number, + "3", + ), + }, + Spanned { + span: Span { + start: 147, + end: 148, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 148, + end: 149, + }, + value: Lexeme( + RParen, + ")", + ), + }, + Spanned { + span: Span { + start: 150, + end: 158, + }, + value: Lexeme( + Command, + "assign", + ), + }, + Spanned { + span: Span { + start: 159, + end: 177, + }, + value: Lexeme( + Command, + "transfer-objects", + ), + }, + Spanned { + span: Span { + start: 178, + end: 191, + }, + value: Lexeme( + Command, + "split-coins", + ), + }, + Spanned { + span: Span { + start: 192, + end: 205, + }, + value: Lexeme( + Command, + "merge-coins", + ), + }, + Spanned { + span: Span { + start: 206, + end: 221, + }, + value: Lexeme( + Command, + "make-move-vec", + ), + }, + Spanned { + span: Span { + start: 222, + end: 233, + }, + value: Lexeme( + Command, + "move-call", + ), + }, + Spanned { + span: Span { + start: 234, + end: 243, + }, + value: Lexeme( + Command, + "preview", + ), + }, + Spanned { + span: Span { + start: 244, + end: 258, + }, + value: Lexeme( + Command, + "warn-shadows", + ), + }, + Spanned { + span: Span { + start: 259, + end: 276, + }, + value: Lexeme( + Command, + "pick-gas-budget", + ), + }, + Spanned { + span: Span { + start: 277, + end: 289, + }, + value: Lexeme( + Command, + "gas-budget", + ), + }, + Spanned { + span: Span { + start: 290, + end: 299, + }, + value: Lexeme( + Command, + "summary", + ), + }, + Spanned { + span: Span { + start: 300, + end: 319, + }, + value: Lexeme( + Publish, + "package-a", + ), + }, + Spanned { + span: Span { + start: 320, + end: 339, + }, + value: Lexeme( + Upgrade, + "package-b", + ), + }, + Spanned { + span: Span { + start: 339, + end: 339, + }, + value: Lexeme( + Eof, + "", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_array.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_array.snap new file mode 100644 index 00000000000..d65ba095cf3 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_array.snap @@ -0,0 +1,246 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: lex(arrays) +--- +[ + Spanned { + span: Span { + start: 0, + end: 1, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 1, + end: 2, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 2, + end: 3, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 3, + end: 4, + }, + value: Lexeme( + Number, + "2", + ), + }, + Spanned { + span: Span { + start: 4, + end: 5, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 5, + end: 6, + }, + value: Lexeme( + Number, + "3", + ), + }, + Spanned { + span: Span { + start: 6, + end: 7, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 8, + end: 9, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 9, + end: 10, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 10, + end: 11, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 12, + end: 13, + }, + value: Lexeme( + Number, + "2", + ), + }, + Spanned { + span: Span { + start: 13, + end: 14, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 15, + end: 16, + }, + value: Lexeme( + Number, + "3", + ), + }, + Spanned { + span: Span { + start: 16, + end: 17, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 18, + end: 19, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 19, + end: 20, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 21, + end: 22, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 22, + end: 23, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 23, + end: 24, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 25, + end: 26, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 26, + end: 27, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 27, + end: 28, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 28, + end: 29, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 29, + end: 29, + }, + value: Lexeme( + Eof, + "", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_commands.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_commands.snap new file mode 100644 index 00000000000..599949b05fb --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_commands.snap @@ -0,0 +1,46 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: lex(cmds) +--- +[ + Spanned { + span: Span { + start: 0, + end: 5, + }, + value: Lexeme( + Command, + "f00", + ), + }, + Spanned { + span: Span { + start: 6, + end: 15, + }, + value: Lexeme( + Command, + "Bar_baz", + ), + }, + Spanned { + span: Span { + start: 16, + end: 25, + }, + value: Lexeme( + Command, + "qux-quy", + ), + }, + Spanned { + span: Span { + start: 25, + end: 25, + }, + value: Lexeme( + Eof, + "", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_flags.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_flags.snap new file mode 100644 index 00000000000..753e30e3439 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_flags.snap @@ -0,0 +1,56 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: lex(flags) +--- +[ + Spanned { + span: Span { + start: 0, + end: 2, + }, + value: Lexeme( + Flag, + "h", + ), + }, + Spanned { + span: Span { + start: 3, + end: 5, + }, + value: Lexeme( + Flag, + "a", + ), + }, + Spanned { + span: Span { + start: 6, + end: 8, + }, + value: Lexeme( + Flag, + "Z", + ), + }, + Spanned { + span: Span { + start: 9, + end: 11, + }, + value: Lexeme( + Flag, + "1", + ), + }, + Spanned { + span: Span { + start: 11, + end: 11, + }, + value: Lexeme( + Eof, + "", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_num.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_num.snap new file mode 100644 index 00000000000..0317ba459b4 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_num.snap @@ -0,0 +1,196 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: lex(nums) +--- +[ + Spanned { + span: Span { + start: 0, + end: 1, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 2, + end: 7, + }, + value: Lexeme( + Number, + "1_000", + ), + }, + Spanned { + span: Span { + start: 8, + end: 19, + }, + value: Lexeme( + Number, + "100_000_000", + ), + }, + Spanned { + span: Span { + start: 20, + end: 27, + }, + value: Lexeme( + Number, + "100_000", + ), + }, + Spanned { + span: Span { + start: 27, + end: 30, + }, + value: Lexeme( + Ident, + "u64", + ), + }, + Spanned { + span: Span { + start: 31, + end: 32, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 32, + end: 34, + }, + value: Lexeme( + Ident, + "u8", + ), + }, + Spanned { + span: Span { + start: 35, + end: 37, + }, + value: Lexeme( + Number, + "1_", + ), + }, + Spanned { + span: Span { + start: 37, + end: 41, + }, + value: Lexeme( + Ident, + "u128", + ), + }, + Spanned { + span: Span { + start: 42, + end: 45, + }, + value: Lexeme( + HexNumber, + "1", + ), + }, + Spanned { + span: Span { + start: 46, + end: 53, + }, + value: Lexeme( + HexNumber, + "1_000", + ), + }, + Spanned { + span: Span { + start: 54, + end: 67, + }, + value: Lexeme( + HexNumber, + "100_000_000", + ), + }, + Spanned { + span: Span { + start: 68, + end: 77, + }, + value: Lexeme( + HexNumber, + "100_000", + ), + }, + Spanned { + span: Span { + start: 77, + end: 80, + }, + value: Lexeme( + Ident, + "u64", + ), + }, + Spanned { + span: Span { + start: 81, + end: 84, + }, + value: Lexeme( + HexNumber, + "1", + ), + }, + Spanned { + span: Span { + start: 84, + end: 86, + }, + value: Lexeme( + Ident, + "u8", + ), + }, + Spanned { + span: Span { + start: 87, + end: 91, + }, + value: Lexeme( + HexNumber, + "1_", + ), + }, + Spanned { + span: Span { + start: 91, + end: 95, + }, + value: Lexeme( + Ident, + "u128", + ), + }, + Spanned { + span: Span { + start: 95, + end: 95, + }, + value: Lexeme( + Eof, + "", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_vector.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_vector.snap new file mode 100644 index 00000000000..3ae118c16cf --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__tokenize_vector.snap @@ -0,0 +1,296 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: lex(vecs) +--- +[ + Spanned { + span: Span { + start: 0, + end: 6, + }, + value: Lexeme( + Ident, + "vector", + ), + }, + Spanned { + span: Span { + start: 6, + end: 7, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 7, + end: 8, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 8, + end: 9, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 9, + end: 10, + }, + value: Lexeme( + Number, + "2", + ), + }, + Spanned { + span: Span { + start: 10, + end: 11, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 11, + end: 12, + }, + value: Lexeme( + Number, + "3", + ), + }, + Spanned { + span: Span { + start: 12, + end: 13, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 14, + end: 20, + }, + value: Lexeme( + Ident, + "vector", + ), + }, + Spanned { + span: Span { + start: 20, + end: 21, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 21, + end: 22, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 22, + end: 23, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 24, + end: 25, + }, + value: Lexeme( + Number, + "2", + ), + }, + Spanned { + span: Span { + start: 25, + end: 26, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 27, + end: 28, + }, + value: Lexeme( + Number, + "3", + ), + }, + Spanned { + span: Span { + start: 28, + end: 29, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 30, + end: 36, + }, + value: Lexeme( + Ident, + "vector", + ), + }, + Spanned { + span: Span { + start: 36, + end: 37, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 37, + end: 38, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 39, + end: 45, + }, + value: Lexeme( + Ident, + "vector", + ), + }, + Spanned { + span: Span { + start: 45, + end: 46, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 46, + end: 47, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 47, + end: 48, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 49, + end: 55, + }, + value: Lexeme( + Ident, + "vector", + ), + }, + Spanned { + span: Span { + start: 55, + end: 56, + }, + value: Lexeme( + LBracket, + "[", + ), + }, + Spanned { + span: Span { + start: 56, + end: 57, + }, + value: Lexeme( + Number, + "1", + ), + }, + Spanned { + span: Span { + start: 57, + end: 58, + }, + value: Lexeme( + Comma, + ",", + ), + }, + Spanned { + span: Span { + start: 58, + end: 59, + }, + value: Lexeme( + RBracket, + "]", + ), + }, + Spanned { + span: Span { + start: 59, + end: 59, + }, + value: Lexeme( + Eof, + "", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_0x.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_0x.snap new file mode 100644 index 00000000000..f5c19e31d7a --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_0x.snap @@ -0,0 +1,16 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: tokens +--- +[ + Spanned { + span: Span { + start: 0, + end: 2, + }, + value: Lexeme( + Unexpected, + "0x", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_colon.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_colon.snap new file mode 100644 index 00000000000..ef4bb3e29d4 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_colon.snap @@ -0,0 +1,26 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: tokens +--- +[ + Spanned { + span: Span { + start: 0, + end: 5, + }, + value: Lexeme( + Ident, + "hello", + ), + }, + Spanned { + span: Span { + start: 5, + end: 6, + }, + value: Lexeme( + Unexpected, + ":", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_dash.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_dash.snap new file mode 100644 index 00000000000..bd6f043fa32 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_dash.snap @@ -0,0 +1,16 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: tokens +--- +[ + Spanned { + span: Span { + start: 0, + end: 1, + }, + value: Lexeme( + Unexpected, + "-", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_dash_dash.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_dash_dash.snap new file mode 100644 index 00000000000..2f9ad38c5f9 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_dash_dash.snap @@ -0,0 +1,16 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: lex(unexpected) +--- +[ + Spanned { + span: Span { + start: 0, + end: 1, + }, + value: Lexeme( + Unexpected, + "-", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_publish_trailing.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_publish_trailing.snap new file mode 100644 index 00000000000..d15dc7e72b3 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_publish_trailing.snap @@ -0,0 +1,16 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: tokens +--- +[ + Spanned { + span: Span { + start: 9, + end: 10, + }, + value: Lexeme( + Unexpected, + " ", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_random_chars.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_random_chars.snap new file mode 100644 index 00000000000..80ab12ee4fc --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_random_chars.snap @@ -0,0 +1,26 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: tokens +--- +[ + Spanned { + span: Span { + start: 0, + end: 1, + }, + value: Lexeme( + Number, + "4", + ), + }, + Spanned { + span: Span { + start: 2, + end: 3, + }, + value: Lexeme( + Unexpected, + "*", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_upgrade_eof.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_upgrade_eof.snap new file mode 100644 index 00000000000..7b2612ac547 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__lexer__tests__unexpected_upgrade_eof.snap @@ -0,0 +1,16 @@ +--- +source: crates/iota/src/client_ptb/lexer.rs +expression: tokens +--- +[ + Spanned { + span: Span { + start: 9, + end: 9, + }, + value: Lexeme( + EarlyEof, + "", + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_args.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_args.snap new file mode 100644 index 00000000000..61a6a215647 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_args.snap @@ -0,0 +1,519 @@ +--- +source: crates/iota/src/client_ptb/parser.rs +expression: parsed +--- +[ + Spanned { + span: Span { + start: 0, + end: 4, + }, + value: Bool( + true, + ), + }, + Spanned { + span: Span { + start: 0, + end: 5, + }, + value: Bool( + false, + ), + }, + Spanned { + span: Span { + start: 0, + end: 1, + }, + value: U64( + 1, + ), + }, + Spanned { + span: Span { + start: 0, + end: 5, + }, + value: U64( + 1000, + ), + }, + Spanned { + span: Span { + start: 0, + end: 11, + }, + value: U64( + 100000000, + ), + }, + Spanned { + span: Span { + start: 0, + end: 10, + }, + value: U64( + 100000, + ), + }, + Spanned { + span: Span { + start: 0, + end: 3, + }, + value: U8( + 1, + ), + }, + Spanned { + span: Span { + start: 0, + end: 6, + }, + value: U128( + 1, + ), + }, + Spanned { + span: Span { + start: 0, + end: 3, + }, + value: U64( + 1, + ), + }, + Spanned { + span: Span { + start: 0, + end: 7, + }, + value: U64( + 4096, + ), + }, + Spanned { + span: Span { + start: 0, + end: 13, + }, + value: U64( + 4294967296, + ), + }, + Spanned { + span: Span { + start: 0, + end: 12, + }, + value: U64( + 1048576, + ), + }, + Spanned { + span: Span { + start: 0, + end: 5, + }, + value: U8( + 1, + ), + }, + Spanned { + span: Span { + start: 0, + end: 8, + }, + value: U128( + 1, + ), + }, + Spanned { + span: Span { + start: 0, + end: 4, + }, + value: Address( + 0x1, + ), + }, + Spanned { + span: Span { + start: 0, + end: 8, + }, + value: Address( + 0x1000, + ), + }, + Spanned { + span: Span { + start: 0, + end: 14, + }, + value: Address( + 0x100000000, + ), + }, + Spanned { + span: Span { + start: 0, + end: 10, + }, + value: Address( + 0x100000, + ), + }, + Spanned { + span: Span { + start: 0, + end: 4, + }, + value: Address( + 0x1, + ), + }, + Spanned { + span: Span { + start: 0, + end: 5, + }, + value: Address( + 0x1, + ), + }, + Spanned { + span: Span { + start: 0, + end: 4, + }, + value: Option( + Spanned { + span: Span { + start: 0, + end: 4, + }, + value: None, + }, + ), + }, + Spanned { + span: Span { + start: 0, + end: 7, + }, + value: Option( + Spanned { + span: Span { + start: 5, + end: 6, + }, + value: Some( + U64( + 1, + ), + ), + }, + ), + }, + Spanned { + span: Span { + start: 0, + end: 9, + }, + value: Option( + Spanned { + span: Span { + start: 5, + end: 8, + }, + value: Some( + U64( + 1, + ), + ), + }, + ), + }, + Spanned { + span: Span { + start: 0, + end: 29, + }, + value: Option( + Spanned { + span: Span { + start: 5, + end: 28, + }, + value: Some( + Option( + Spanned { + span: Span { + start: 10, + end: 27, + }, + value: Some( + Option( + Spanned { + span: Span { + start: 15, + end: 26, + }, + value: Some( + Option( + Spanned { + span: Span { + start: 20, + end: 25, + }, + value: Some( + U128( + 1, + ), + ), + }, + ), + ), + }, + ), + ), + }, + ), + ), + }, + ), + }, + Spanned { + span: Span { + start: 0, + end: 8, + }, + value: Vector( + [], + ), + }, + Spanned { + span: Span { + start: 0, + end: 15, + }, + value: Vector( + [ + Spanned { + span: Span { + start: 7, + end: 8, + }, + value: U64( + 1, + ), + }, + Spanned { + span: Span { + start: 10, + end: 11, + }, + value: U64( + 2, + ), + }, + Spanned { + span: Span { + start: 13, + end: 14, + }, + value: U64( + 3, + ), + }, + ], + ), + }, + Spanned { + span: Span { + start: 0, + end: 16, + }, + value: Vector( + [ + Spanned { + span: Span { + start: 7, + end: 8, + }, + value: U64( + 1, + ), + }, + Spanned { + span: Span { + start: 10, + end: 11, + }, + value: U64( + 2, + ), + }, + Spanned { + span: Span { + start: 13, + end: 14, + }, + value: U64( + 3, + ), + }, + ], + ), + }, + Spanned { + span: Span { + start: 0, + end: 7, + }, + value: VariableAccess( + Spanned { + span: Span { + start: 0, + end: 3, + }, + value: "foo", + }, + [ + Spanned { + span: Span { + start: 4, + end: 7, + }, + value: "bar", + }, + ], + ), + }, + Spanned { + span: Span { + start: 0, + end: 11, + }, + value: VariableAccess( + Spanned { + span: Span { + start: 0, + end: 3, + }, + value: "foo", + }, + [ + Spanned { + span: Span { + start: 4, + end: 7, + }, + value: "bar", + }, + Spanned { + span: Span { + start: 8, + end: 11, + }, + value: "baz", + }, + ], + ), + }, + Spanned { + span: Span { + start: 0, + end: 15, + }, + value: VariableAccess( + Spanned { + span: Span { + start: 0, + end: 3, + }, + value: "foo", + }, + [ + Spanned { + span: Span { + start: 4, + end: 7, + }, + value: "bar", + }, + Spanned { + span: Span { + start: 8, + end: 11, + }, + value: "baz", + }, + Spanned { + span: Span { + start: 12, + end: 15, + }, + value: "qux", + }, + ], + ), + }, + Spanned { + span: Span { + start: 0, + end: 5, + }, + value: VariableAccess( + Spanned { + span: Span { + start: 0, + end: 3, + }, + value: "foo", + }, + [ + Spanned { + span: Span { + start: 4, + end: 5, + }, + value: "0", + }, + ], + ), + }, + Spanned { + span: Span { + start: 0, + end: 7, + }, + value: VariableAccess( + Spanned { + span: Span { + start: 0, + end: 3, + }, + value: "foo", + }, + [ + Spanned { + span: Span { + start: 4, + end: 5, + }, + value: "0", + }, + Spanned { + span: Span { + start: 6, + end: 7, + }, + value: "1", + }, + ], + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_args_invalid.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_args_invalid.snap new file mode 100644 index 00000000000..ddd8702761d --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_args_invalid.snap @@ -0,0 +1,126 @@ +--- +source: crates/iota/src/client_ptb/parser.rs +expression: parsed +--- +[ + PTBError { + message: "number too large to fit in target type", + span: Span { + start: 0, + end: 7, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Expected a numerical address but got a named address 'n'", + span: Span { + start: 0, + end: 2, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Expected '(' but found end of input", + span: Span { + start: 4, + end: 4, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Unexpected end of input", + span: Span { + start: 5, + end: 5, + }, + help: Some( + "Expected an argument here", + ), + severity: Error, + }, + PTBError { + message: "Expected ')' but found end of input", + span: Span { + start: 6, + end: 6, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Expected '[' but found end of input", + span: Span { + start: 6, + end: 6, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Unexpected end of input", + span: Span { + start: 7, + end: 7, + }, + help: Some( + "Expected an array here", + ), + severity: Error, + }, + PTBError { + message: "Unexpected end of input", + span: Span { + start: 9, + end: 9, + }, + help: Some( + "Expected an array here", + ), + severity: Error, + }, + PTBError { + message: "Unexpected number '2'", + span: Span { + start: 9, + end: 10, + }, + help: Some( + "Expected ']' or ','", + ), + severity: Error, + }, + PTBError { + message: "Unexpected ','", + span: Span { + start: 7, + end: 8, + }, + help: Some( + "Expected an argument here", + ), + severity: Error, + }, + PTBError { + message: "Expected a field name after '.'", + span: Span { + start: 4, + end: 4, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Unexpected '.'", + span: Span { + start: 0, + end: 1, + }, + help: Some( + "Expected an argument here", + ), + severity: Error, + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_commands.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_commands.snap new file mode 100644 index 00000000000..6d6474d4845 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_commands.snap @@ -0,0 +1,1449 @@ +--- +source: crates/iota/src/client_ptb/parser.rs +expression: parsed +--- +[ + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 17, + }, + value: Publish( + Spanned { + span: Span { + start: 0, + end: 17, + }, + value: "foo/bar", + }, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 18, + end: 32, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 21, + }, + value: Publish( + Spanned { + span: Span { + start: 0, + end: 21, + }, + value: "foo/bar.ptb", + }, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 22, + end: 36, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 18, + }, + value: Upgrade( + Spanned { + span: Span { + start: 0, + end: 13, + }, + value: "foo", + }, + Spanned { + span: Span { + start: 14, + end: 18, + }, + value: Address( + 0x1, + ), + }, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 19, + end: 33, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 27, + }, + value: TransferObjects( + Spanned { + span: Span { + start: 19, + end: 25, + }, + value: [ + Spanned { + span: Span { + start: 20, + end: 21, + }, + value: Identifier( + "b", + ), + }, + Spanned { + span: Span { + start: 23, + end: 24, + }, + value: Identifier( + "c", + ), + }, + ], + }, + Spanned { + span: Span { + start: 26, + end: 27, + }, + value: Identifier( + "a", + ), + }, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 28, + end: 42, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 24, + }, + value: TransferObjects( + Spanned { + span: Span { + start: 19, + end: 22, + }, + value: [ + Spanned { + span: Span { + start: 20, + end: 21, + }, + value: Identifier( + "b", + ), + }, + ], + }, + Spanned { + span: Span { + start: 23, + end: 24, + }, + value: Identifier( + "a", + ), + }, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 25, + end: 39, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 26, + }, + value: TransferObjects( + Spanned { + span: Span { + start: 19, + end: 22, + }, + value: [ + Spanned { + span: Span { + start: 20, + end: 21, + }, + value: Identifier( + "b", + ), + }, + ], + }, + Spanned { + span: Span { + start: 23, + end: 26, + }, + value: VariableAccess( + Spanned { + span: Span { + start: 23, + end: 24, + }, + value: "a", + }, + [ + Spanned { + span: Span { + start: 25, + end: 26, + }, + value: "0", + }, + ], + ), + }, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 27, + end: 41, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 22, + }, + value: SplitCoins( + Spanned { + span: Span { + start: 14, + end: 15, + }, + value: Identifier( + "a", + ), + }, + Spanned { + span: Span { + start: 16, + end: 22, + }, + value: [ + Spanned { + span: Span { + start: 17, + end: 18, + }, + value: Identifier( + "b", + ), + }, + Spanned { + span: Span { + start: 20, + end: 21, + }, + value: Identifier( + "c", + ), + }, + ], + }, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 23, + end: 37, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 19, + }, + value: SplitCoins( + Spanned { + span: Span { + start: 14, + end: 15, + }, + value: Identifier( + "a", + ), + }, + Spanned { + span: Span { + start: 16, + end: 19, + }, + value: [ + Spanned { + span: Span { + start: 17, + end: 18, + }, + value: Identifier( + "c", + ), + }, + ], + }, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 20, + end: 34, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 22, + }, + value: MergeCoins( + Spanned { + span: Span { + start: 14, + end: 15, + }, + value: Identifier( + "a", + ), + }, + Spanned { + span: Span { + start: 16, + end: 22, + }, + value: [ + Spanned { + span: Span { + start: 17, + end: 18, + }, + value: Identifier( + "b", + ), + }, + Spanned { + span: Span { + start: 20, + end: 21, + }, + value: Identifier( + "c", + ), + }, + ], + }, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 23, + end: 37, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 19, + }, + value: MergeCoins( + Spanned { + span: Span { + start: 14, + end: 15, + }, + value: Identifier( + "a", + ), + }, + Spanned { + span: Span { + start: 16, + end: 19, + }, + value: [ + Spanned { + span: Span { + start: 17, + end: 18, + }, + value: Identifier( + "c", + ), + }, + ], + }, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 20, + end: 34, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 24, + }, + value: MakeMoveVec( + Spanned { + span: Span { + start: 17, + end: 20, + }, + value: U64, + }, + Spanned { + span: Span { + start: 22, + end: 24, + }, + value: [], + }, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 25, + end: 39, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 31, + }, + value: MakeMoveVec( + Spanned { + span: Span { + start: 17, + end: 19, + }, + value: U8, + }, + Spanned { + span: Span { + start: 21, + end: 31, + }, + value: [ + Spanned { + span: Span { + start: 22, + end: 25, + }, + value: U8( + 1, + ), + }, + Spanned { + span: Span { + start: 27, + end: 30, + }, + value: U8( + 2, + ), + }, + ], + }, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 32, + end: 46, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 71, + }, + value: MoveCall( + Spanned { + span: Span { + start: 12, + end: 46, + }, + value: ModuleAccess { + address: Spanned { + span: Span { + start: 12, + end: 15, + }, + value: Numerical( + 0x3, + ), + }, + module_name: Spanned { + span: Span { + start: 17, + end: 27, + }, + value: Identifier( + "iota_system", + ), + }, + function_name: Spanned { + span: Span { + start: 29, + end: 46, + }, + value: Identifier( + "request_add_stake", + ), + }, + }, + }, + None, + [ + Spanned { + span: Span { + start: 47, + end: 53, + }, + value: Identifier( + "system", + ), + }, + Spanned { + span: Span { + start: 54, + end: 61, + }, + value: VariableAccess( + Spanned { + span: Span { + start: 54, + end: 59, + }, + value: "coins", + }, + [ + Spanned { + span: Span { + start: 60, + end: 61, + }, + value: "0", + }, + ], + ), + }, + Spanned { + span: Span { + start: 62, + end: 71, + }, + value: Identifier( + "validator", + ), + }, + ], + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 72, + end: 86, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 40, + }, + value: MoveCall( + Spanned { + span: Span { + start: 12, + end: 32, + }, + value: ModuleAccess { + address: Spanned { + span: Span { + start: 12, + end: 15, + }, + value: Named( + "std", + ), + }, + module_name: Spanned { + span: Span { + start: 17, + end: 23, + }, + value: Identifier( + "option", + ), + }, + function_name: Spanned { + span: Span { + start: 25, + end: 32, + }, + value: Identifier( + "is_none", + ), + }, + }, + }, + Some( + Spanned { + span: Span { + start: 33, + end: 38, + }, + value: [ + U64, + ], + }, + ), + [ + Spanned { + span: Span { + start: 39, + end: 40, + }, + value: Identifier( + "p", + ), + }, + ], + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 41, + end: 55, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 39, + }, + value: MoveCall( + Spanned { + span: Span { + start: 12, + end: 32, + }, + value: ModuleAccess { + address: Spanned { + span: Span { + start: 12, + end: 15, + }, + value: Named( + "std", + ), + }, + module_name: Spanned { + span: Span { + start: 17, + end: 23, + }, + value: Identifier( + "option", + ), + }, + function_name: Spanned { + span: Span { + start: 25, + end: 32, + }, + value: Identifier( + "is_some", + ), + }, + }, + }, + Some( + Spanned { + span: Span { + start: 32, + end: 37, + }, + value: [ + U32, + ], + }, + ), + [ + Spanned { + span: Span { + start: 38, + end: 39, + }, + value: Identifier( + "q", + ), + }, + ], + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 40, + end: 54, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 10, + }, + value: Assign( + Spanned { + span: Span { + start: 9, + end: 10, + }, + value: "a", + }, + None, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 11, + end: 25, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 14, + }, + value: Assign( + Spanned { + span: Span { + start: 9, + end: 10, + }, + value: "a", + }, + Some( + Spanned { + span: Span { + start: 11, + end: 14, + }, + value: VariableAccess( + Spanned { + span: Span { + start: 11, + end: 12, + }, + value: "b", + }, + [ + Spanned { + span: Span { + start: 13, + end: 14, + }, + value: "1", + }, + ], + ), + }, + ), + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 15, + end: 29, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 14, + }, + value: Assign( + Spanned { + span: Span { + start: 9, + end: 10, + }, + value: "a", + }, + Some( + Spanned { + span: Span { + start: 11, + end: 14, + }, + value: U8( + 1, + ), + }, + ), + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 15, + end: 29, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 15, + }, + value: Assign( + Spanned { + span: Span { + start: 9, + end: 10, + }, + value: "a", + }, + Some( + Spanned { + span: Span { + start: 11, + end: 15, + }, + value: Address( + 0x1, + ), + }, + ), + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 16, + end: 30, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 26, + }, + value: Assign( + Spanned { + span: Span { + start: 9, + end: 10, + }, + value: "a", + }, + Some( + Spanned { + span: Span { + start: 11, + end: 26, + }, + value: Vector( + [ + Spanned { + span: Span { + start: 18, + end: 19, + }, + value: U64( + 1, + ), + }, + Spanned { + span: Span { + start: 21, + end: 22, + }, + value: U64( + 2, + ), + }, + Spanned { + span: Span { + start: 24, + end: 25, + }, + value: U64( + 3, + ), + }, + ], + ), + }, + ), + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 27, + end: 41, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 15, + }, + value: Assign( + Spanned { + span: Span { + start: 9, + end: 10, + }, + value: "a", + }, + Some( + Spanned { + span: Span { + start: 11, + end: 15, + }, + value: Option( + Spanned { + span: Span { + start: 11, + end: 15, + }, + value: None, + }, + ), + }, + ), + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 16, + end: 30, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 18, + }, + value: Assign( + Spanned { + span: Span { + start: 9, + end: 10, + }, + value: "a", + }, + Some( + Spanned { + span: Span { + start: 11, + end: 18, + }, + value: Option( + Spanned { + span: Span { + start: 16, + end: 17, + }, + value: Some( + U64( + 1, + ), + ), + }, + ), + }, + ), + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 19, + end: 33, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: Some( + Spanned { + span: Span { + start: 11, + end: 15, + }, + value: 0x0000000000000000000000000000000000000000000000000000000000000001, + }, + ), + json_set: false, + gas_budget: Spanned { + span: Span { + start: 16, + end: 30, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: true, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 10, + end: 24, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: true, + gas_budget: Spanned { + span: Span { + start: 7, + end: 21, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: true, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 10, + end: 24, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [], + warn_shadows_set: true, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 15, + end: 29, + }, + value: 1, + }, + }, + ), +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_commands_invalid.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_commands_invalid.snap new file mode 100644 index 00000000000..9d7b1d8682e --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_commands_invalid.snap @@ -0,0 +1,820 @@ +--- +source: crates/iota/src/client_ptb/parser.rs +expression: parsed +--- +[ + [ + PTBError { + message: "Unexpected end of input", + span: Span { + start: 9, + end: 9, + }, + help: Some( + "Expected to find a command here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 9, + end: 9, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected end of input", + span: Span { + start: 9, + end: 9, + }, + help: Some( + "Expected to find a command here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 9, + end: 9, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected end of input", + span: Span { + start: 11, + end: 11, + }, + help: Some( + "Expected an argument here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 11, + end: 11, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected '[' but found identifier 'a'", + span: Span { + start: 19, + end: 20, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 20, + end: 20, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected end of input", + span: Span { + start: 22, + end: 22, + }, + help: Some( + "Expected an argument here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 22, + end: 22, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected '[' but found end of input", + span: Span { + start: 18, + end: 18, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 18, + end: 18, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected '['", + span: Span { + start: 23, + end: 24, + }, + help: Some( + "Expected an argument here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 26, + end: 26, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected '[' but found end of input", + span: Span { + start: 15, + end: 15, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 15, + end: 15, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected '['", + span: Span { + start: 14, + end: 15, + }, + help: Some( + "Expected an argument here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 17, + end: 17, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected end of input", + span: Span { + start: 13, + end: 13, + }, + help: Some( + "Expected an argument here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 13, + end: 13, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected '[' but found identifier 'b'", + span: Span { + start: 16, + end: 17, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 19, + end: 19, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected identifier 'c'", + span: Span { + start: 20, + end: 21, + }, + help: Some( + "Expected to find a command here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 21, + end: 21, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected '[' but found end of input", + span: Span { + start: 15, + end: 15, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 15, + end: 15, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected '['", + span: Span { + start: 14, + end: 15, + }, + help: Some( + "Expected an argument here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 17, + end: 17, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected end of input", + span: Span { + start: 13, + end: 13, + }, + help: Some( + "Expected an argument here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 13, + end: 13, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected '[' but found identifier 'b'", + span: Span { + start: 16, + end: 17, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 19, + end: 19, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected identifier 'c'", + span: Span { + start: 20, + end: 21, + }, + help: Some( + "Expected to find a command here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 21, + end: 21, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected '<' but found end of input", + span: Span { + start: 15, + end: 15, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 15, + end: 15, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected '<' but found '['", + span: Span { + start: 16, + end: 17, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 25, + end: 25, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected '[' but found end of input", + span: Span { + start: 21, + end: 21, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 21, + end: 21, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected end of input", + span: Span { + start: 11, + end: 11, + }, + help: Some( + "Value addresses can either be a variable in-scope, or a numerical address, e.g., 0xc0ffee", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 11, + end: 11, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected '['", + span: Span { + start: 37, + end: 38, + }, + help: Some( + "Expected an argument here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 39, + end: 39, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected an identifier but found end of input", + span: Span { + start: 8, + end: 8, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 8, + end: 8, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected identifier 'c'", + span: Span { + start: 13, + end: 14, + }, + help: Some( + "Expected to find a command here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 14, + end: 14, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected a variable name but found reserved word 'none'.", + span: Span { + start: 9, + end: 13, + }, + help: Some( + "Variable names cannot be 'address', 'bool', 'vector', 'some', 'none', 'gas', 'u8', 'u16', 'u32', 'u64', 'u128', or 'u256'.", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 15, + end: 15, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected a variable name but found reserved word 'some'.", + span: Span { + start: 9, + end: 13, + }, + help: Some( + "Variable names cannot be 'address', 'bool', 'vector', 'some', 'none', 'gas', 'u8', 'u16', 'u32', 'u64', 'u128', or 'u256'.", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 18, + end: 18, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected '.'", + span: Span { + start: 10, + end: 11, + }, + help: Some( + "Expected an argument here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 16, + end: 16, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "number too large to fit in target type", + span: Span { + start: 13, + end: 75, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 75, + end: 75, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected '['", + span: Span { + start: 13, + end: 14, + }, + help: Some( + "Expected an argument here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 16, + end: 16, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected a u64 value", + span: Span { + start: 13, + end: 17, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 17, + end: 17, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected a u64 value", + span: Span { + start: 13, + end: 17, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 17, + end: 17, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected an address", + span: Span { + start: 11, + end: 15, + }, + help: Some( + "Addresses or object IDs require the character '@' in front", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 15, + end: 15, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected an address", + span: Span { + start: 10, + end: 10, + }, + help: Some( + "Addresses or object IDs require the character '@' in front", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 10, + end: 10, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Unexpected '@'", + span: Span { + start: 16, + end: 17, + }, + help: Some( + "Expected to find a command here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 20, + end: 20, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], + [ + PTBError { + message: "Expected an address", + span: Span { + start: 11, + end: 12, + }, + help: Some( + "Addresses or object IDs require the character '@' in front", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 12, + end: 12, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, + ], +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_publish.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_publish.snap new file mode 100644 index 00000000000..50a8a0c3a87 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_publish.snap @@ -0,0 +1,80 @@ +--- +source: crates/iota/src/client_ptb/parser.rs +expression: parsed +--- +[ + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 17, + }, + value: Publish( + Spanned { + span: Span { + start: 0, + end: 17, + }, + value: "foo/bar", + }, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 18, + end: 32, + }, + value: 1, + }, + }, + ), + ( + Program { + commands: [ + Spanned { + span: Span { + start: 0, + end: 17, + }, + value: Publish( + Spanned { + span: Span { + start: 0, + end: 17, + }, + value: "foo/bar", + }, + ), + }, + ], + warn_shadows_set: false, + }, + ProgramMetadata { + preview_set: false, + summary_set: false, + serialize_unsigned_set: false, + serialize_signed_set: false, + gas_object_id: None, + json_set: false, + gas_budget: Spanned { + span: Span { + start: 18, + end: 32, + }, + value: 1, + }, + }, + ), +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_types.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_types.snap new file mode 100644 index 00000000000..bd8de226815 --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_types.snap @@ -0,0 +1,219 @@ +--- +source: crates/iota/src/client_ptb/parser.rs +expression: parsed +--- +[ + Spanned { + span: Span { + start: 0, + end: 2, + }, + value: U8, + }, + Spanned { + span: Span { + start: 0, + end: 3, + }, + value: U16, + }, + Spanned { + span: Span { + start: 0, + end: 3, + }, + value: U32, + }, + Spanned { + span: Span { + start: 0, + end: 3, + }, + value: U64, + }, + Spanned { + span: Span { + start: 0, + end: 4, + }, + value: U128, + }, + Spanned { + span: Span { + start: 0, + end: 4, + }, + value: U256, + }, + Spanned { + span: Span { + start: 0, + end: 4, + }, + value: Bool, + }, + Spanned { + span: Span { + start: 0, + end: 7, + }, + value: Address, + }, + Spanned { + span: Span { + start: 0, + end: 10, + }, + value: Vector( + U8, + ), + }, + Spanned { + span: Span { + start: 0, + end: 15, + }, + value: Struct( + ParsedStructType { + fq_name: ParsedFqName { + module: ParsedModuleId { + address: Named( + "iota", + ), + name: "object", + }, + name: "ID", + }, + type_args: [], + }, + ), + }, + Spanned { + span: Span { + start: 0, + end: 16, + }, + value: Struct( + ParsedStructType { + fq_name: ParsedFqName { + module: ParsedModuleId { + address: Numerical( + 0x2, + ), + name: "object", + }, + name: "UID", + }, + type_args: [], + }, + ), + }, + Spanned { + span: Span { + start: 0, + end: 26, + }, + value: Struct( + ParsedStructType { + fq_name: ParsedFqName { + module: ParsedModuleId { + address: Numerical( + 3, + ), + name: "staking_pool", + }, + name: "StakedIota", + }, + type_args: [], + }, + ), + }, + Spanned { + span: Span { + start: 0, + end: 28, + }, + value: Struct( + ParsedStructType { + fq_name: ParsedFqName { + module: ParsedModuleId { + address: Numerical( + 0x2, + ), + name: "coin", + }, + name: "Coin", + }, + type_args: [ + Struct( + ParsedStructType { + fq_name: ParsedFqName { + module: ParsedModuleId { + address: Numerical( + 2, + ), + name: "iota", + }, + name: "IOTA", + }, + type_args: [], + }, + ), + ], + }, + ), + }, + Spanned { + span: Span { + start: 0, + end: 68, + }, + value: Struct( + ParsedStructType { + fq_name: ParsedFqName { + module: ParsedModuleId { + address: Named( + "iota", + ), + name: "table", + }, + name: "Table", + }, + type_args: [ + Struct( + ParsedStructType { + fq_name: ParsedFqName { + module: ParsedModuleId { + address: Named( + "iota", + ), + name: "object", + }, + name: "ID", + }, + type_args: [], + }, + ), + Vector( + Struct( + ParsedStructType { + fq_name: ParsedFqName { + module: ParsedModuleId { + address: Numerical( + 0x1, + ), + name: "option", + }, + name: "Option", + }, + type_args: [ + U32, + ], + }, + ), + ), + ], + }, + ), + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_types_invalid.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_types_invalid.snap new file mode 100644 index 00000000000..dd2e4b87c0c --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_types_invalid.snap @@ -0,0 +1,84 @@ +--- +source: crates/iota/src/client_ptb/parser.rs +expression: parsed +--- +[ + PTBError { + message: "Expected '::' but found end of input", + span: Span { + start: 6, + end: 6, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Expected '::' but found end of input", + span: Span { + start: 17, + end: 17, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Expected '>' but found ','", + span: Span { + start: 9, + end: 10, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Expected an identifier but found end of input", + span: Span { + start: 5, + end: 5, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Expected '::' but found end of input", + span: Span { + start: 8, + end: 8, + }, + help: None, + severity: Error, + }, + PTBError { + message: "Unexpected end of input", + span: Span { + start: 14, + end: 14, + }, + help: Some( + "Expected a type here", + ), + severity: Error, + }, + PTBError { + message: "Unexpected end of input", + span: Span { + start: 16, + end: 16, + }, + help: Some( + "Expected ',' or '>'", + ), + severity: Error, + }, + PTBError { + message: "Unexpected end of input", + span: Span { + start: 17, + end: 17, + }, + help: Some( + "Expected a type here", + ), + severity: Error, + }, +] diff --git a/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_unexpected_top_level.snap b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_unexpected_top_level.snap new file mode 100644 index 00000000000..67516679b5f --- /dev/null +++ b/crates/iota/src/client_ptb/snapshots/iota__client_ptb__parser__tests__parse_unexpected_top_level.snap @@ -0,0 +1,28 @@ +--- +source: crates/iota/src/client_ptb/parser.rs +expression: result.unwrap_err() +--- +[ + PTBError { + message: "Unexpected input \"0x\"", + span: Span { + start: 0, + end: 2, + }, + help: Some( + "Expected to find a command here", + ), + severity: Error, + }, + PTBError { + message: "Gas budget not set.", + span: Span { + start: 0, + end: 2, + }, + help: Some( + "Use --gas-budget to set a gas budget", + ), + severity: Error, + }, +] diff --git a/crates/iota/src/client_ptb/token.rs b/crates/iota/src/client_ptb/token.rs new file mode 100644 index 00000000000..c4e184eb288 --- /dev/null +++ b/crates/iota/src/client_ptb/token.rs @@ -0,0 +1,145 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt; + +#[derive(Clone, Copy, Debug)] +pub struct Lexeme<'t>( + /// The kind of lexeme. + pub Token, + /// Slice from source that identifies this lexeme (among other instances of + /// this token). + pub &'t str, +); + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum Token { + /// --[a-zA-Z0-9_-]+ + Command, + /// -[a-zA-Z0-9] + Flag, + /// [a-zA-Z_][a-zA-Z0-9_-]* + Ident, + /// [1-9][0-9_]* + Number, + /// 0x[0-9a-fA-F][0-9a-fA-F_]* + HexNumber, + /// "..." | '...' + String, + /// :: + ColonColon, + /// , + Comma, + /// [ + LBracket, + /// ] + RBracket, + /// ( + LParen, + /// ) + RParen, + /// < + LAngle, + /// > + RAngle, + /// @ + At, + /// . + Dot, + + /// End of input. + Eof, + + /// Special tokens for unexpected lexer states that the parser should error + /// on. + Unexpected, + UnfinishedString, + EarlyEof, + + // The following tokens are special -- they consume multiple shell tokens, to ensure we + // capture the path for a publish or an upgrade command. + /// --publish \ + Publish, + /// --upgraded \ + Upgrade, +} + +impl<'l> Lexeme<'l> { + /// Returns true if this lexeme corresponds to a special error token. + pub fn is_error(&self) -> bool { + use Token as T; + matches!(self.0, T::Unexpected | T::UnfinishedString | T::EarlyEof) + } + + /// Returns true if this is the kind of lexeme that finishes the token + /// stream. + pub fn is_terminal(&self) -> bool { + self.is_error() || self.0 == Token::Eof + } + + /// Returns true if this lexeme signifies the end of the current command. + pub fn is_command_end(&self) -> bool { + self.is_terminal() || [Token::Command, Token::Publish, Token::Upgrade].contains(&self.0) + } +} + +impl<'a> fmt::Display for Lexeme<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use Token as T; + + match self.0 { + T::Command => write!(f, "command '--{}'", self.1), + T::Flag => write!(f, "flag '-{}'", self.1), + T::Ident => write!(f, "identifier '{}'", self.1), + T::Number => write!(f, "number '{}'", self.1), + T::HexNumber => write!(f, "hexadecimal number '0x{}'", self.1), + T::String => write!(f, "string {:?}", self.1), + T::ColonColon => write!(f, "'::'"), + T::Comma => write!(f, "','"), + T::LBracket => write!(f, "'['"), + T::RBracket => write!(f, "']'"), + T::LParen => write!(f, "'('"), + T::RParen => write!(f, "')'"), + T::LAngle => write!(f, "'<'"), + T::RAngle => write!(f, "'>'"), + T::At => write!(f, "'@'"), + T::Dot => write!(f, "'.'"), + T::Unexpected => write!(f, "input {:?}", self.1), + T::UnfinishedString => write!(f, "unfinished string {:?}", format!("{}...", self.1)), + T::EarlyEof | T::Eof => write!(f, "end of input"), + T::Publish => write!(f, "command '--publish {:?}'", self.1), + T::Upgrade => write!(f, "command '--upgrade {:?}'", self.1), + } + } +} + +impl fmt::Display for Token { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use Token as T; + match self { + T::Command => write!(f, "a command"), + T::Flag => write!(f, "a flag"), + T::Ident => write!(f, "an identifier"), + T::Number => write!(f, "a number"), + T::HexNumber => write!(f, "a hexadecimal number"), + T::String => write!(f, "a string"), + T::ColonColon => write!(f, "'::'"), + T::Comma => write!(f, "','"), + T::LBracket => write!(f, "'['"), + T::RBracket => write!(f, "']'"), + T::LParen => write!(f, "'('"), + T::RParen => write!(f, "')'"), + T::LAngle => write!(f, "'<'"), + T::RAngle => write!(f, "'>'"), + T::At => write!(f, "'@'"), + T::Dot => write!(f, "'.'"), + T::Eof => write!(f, "end of input"), + T::Unexpected => write!(f, "unexpected input"), + T::UnfinishedString => write!(f, "an unfinished string"), + T::EarlyEof => write!(f, "unexpected end of input"), + T::Publish => write!(f, "a '--publish' command"), + T::Upgrade => write!(f, "an '--upgrade' command"), + } + } +} diff --git a/crates/sui/src/console.rs b/crates/iota/src/console.rs similarity index 83% rename from crates/sui/src/console.rs rename to crates/iota/src/console.rs index 599cb3741c3..1a261130cea 100644 --- a/crates/sui/src/console.rs +++ b/crates/iota/src/console.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -9,16 +10,16 @@ use std::{ use async_trait::async_trait; use clap::{Command, CommandFactory, FromArgMatches, Parser}; use colored::Colorize; -use sui_sdk::wallet_context::WalletContext; +use iota_sdk::wallet_context::WalletContext; use crate::{ - client_commands::{SuiClientCommandResult, SuiClientCommands, SwitchResponse}, + client_commands::{IotaClientCommandResult, IotaClientCommands, SwitchResponse}, shell::{ install_shell_plugins, AsyncHandler, CacheKey, CommandStructure, CompletionCache, Shell, }, }; -const SUI: &str = " _____ _ ______ __ +const IOTA: &str = " _____ _ ______ __ / ___/__ __(_) / ____/___ ____ _________ / /__ \\__ \\/ / / / / / / / __ \\/ __ \\/ ___/ __ \\/ / _ \\ ___/ / /_/ / / / /___/ /_/ / / / (__ ) /_/ / / __/ @@ -28,7 +29,7 @@ const SUI: &str = " _____ _ ______ __ #[clap(name = "", rename_all = "kebab-case", no_binary_name = true)] pub struct ConsoleOpts { #[clap(subcommand)] - pub command: SuiClientCommands, + pub command: IotaClientCommands, /// Returns command outputs in JSON format. #[clap(long, global = true)] pub json: bool, @@ -39,21 +40,21 @@ pub async fn start_console( out: &mut (dyn Write + Send), err: &mut (dyn Write + Send), ) -> Result<(), anyhow::Error> { - let app: Command = SuiClientCommands::command(); - writeln!(out, "{}", SUI.cyan().bold())?; + let app: Command = IotaClientCommands::command(); + writeln!(out, "{}", IOTA.cyan().bold())?; let mut version = env!("CARGO_PKG_VERSION").to_owned(); if let Some(git_rev) = std::option_env!("GIT_REVISION") { version.push('-'); version.push_str(git_rev); } - writeln!(out, "--- Sui Console {version} ---")?; + writeln!(out, "--- Iota Console {version} ---")?; writeln!(out)?; writeln!(out, "{}", context.config.deref())?; let client = context.get_client().await?; writeln!( out, - "Connecting to Sui full node. API version {}", + "Connecting to Iota full node. API version {}", client.api_version() )?; @@ -75,11 +76,11 @@ pub async fn start_console( } writeln!(out)?; - writeln!(out, "Welcome to the Sui interactive console.")?; + writeln!(out, "Welcome to the Iota interactive console.")?; writeln!(out)?; let mut shell = Shell::new( - "sui>-$ ", + "iota>-$ ", context, ClientCommandHandler, CommandStructure::from_clap(&install_shell_plugins(app)), @@ -128,7 +129,7 @@ async fn handle_command( // error proof? if let Ok(mut cache) = completion_cache.write() { match result { - SuiClientCommandResult::Addresses(ref addresses) => { + IotaClientCommandResult::Addresses(ref addresses) => { let addresses = addresses .addresses .iter() @@ -137,7 +138,7 @@ async fn handle_command( cache.insert(CacheKey::flag("--address"), addresses.clone()); cache.insert(CacheKey::flag("--to"), addresses); } - SuiClientCommandResult::Objects(ref objects) => { + IotaClientCommandResult::Objects(ref objects) => { let objects = objects .iter() .map(|oref| format!("{}", oref.clone().into_object().unwrap().object_id)) @@ -154,9 +155,9 @@ async fn handle_command( // Quit shell after RPC switch if matches!( result, - SuiClientCommandResult::Switch(SwitchResponse { env: Some(_), .. }) + IotaClientCommandResult::Switch(SwitchResponse { env: Some(_), .. }) ) { - println!("Sui environment switch completed, please restart Sui console."); + println!("Iota environment switch completed, please restart Iota console."); return Ok(true); } Ok(false) diff --git a/crates/iota/src/fire_drill.rs b/crates/iota/src/fire_drill.rs new file mode 100644 index 00000000000..812044da2cc --- /dev/null +++ b/crates/iota/src/fire_drill.rs @@ -0,0 +1,392 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! A tool to semi automate fire drills. It still requires some manual work +//! today. For example, +//! 1. update iptables for new tpc/udp ports +//! 2. restart the node in a new epoch when config file will be reloaded and +//! take effects +//! +//! Example usage: +//! iota fire-drill metadata-rotation \ +//! --iota-node-config-path validator.yaml \ +//! --account-key-path account.key \ +//! --fullnode-rpc-url http://fullnode-my-local-net:9000 + +use std::path::{Path, PathBuf}; + +use anyhow::bail; +use clap::*; +use fastcrypto::{ + ed25519::Ed25519KeyPair, + traits::{KeyPair, ToFromBytes}, +}; +use iota_config::{ + local_ip_utils, + node::{AuthorityKeyPairWithPath, KeyPairWithPath}, + Config, NodeConfig, PersistedConfig, +}; +use iota_json_rpc_types::{IotaExecutionStatus, IotaTransactionBlockResponseOptions}; +use iota_keys::keypair_file::read_keypair_from_file; +use iota_sdk::{rpc_types::IotaTransactionBlockEffectsAPI, IotaClient, IotaClientBuilder}; +use iota_types::{ + base_types::{IotaAddress, ObjectRef}, + committee::EpochId, + crypto::{generate_proof_of_possession, get_authority_key_pair, get_key_pair, IotaKeyPair}, + multiaddr::{Multiaddr, Protocol}, + transaction::{CallArg, Transaction, TransactionData, TEST_ONLY_GAS_UNIT_FOR_GENERIC}, + IOTA_SYSTEM_PACKAGE_ID, +}; +use move_core_types::ident_str; +use tracing::info; + +#[derive(Parser)] +pub enum FireDrill { + MetadataRotation(MetadataRotation), +} + +#[derive(Parser)] +pub struct MetadataRotation { + /// Path to iota node config. + #[clap(long = "iota-node-config-path")] + iota_node_config_path: PathBuf, + /// Path to account key file. + #[clap(long = "account-key-path")] + account_key_path: PathBuf, + /// Jsonrpc url for a reliable fullnode. + #[clap(long = "fullnode-rpc-url")] + fullnode_rpc_url: String, +} + +pub async fn run_fire_drill(fire_drill: FireDrill) -> anyhow::Result<()> { + match fire_drill { + FireDrill::MetadataRotation(metadata_rotation) => { + run_metadata_rotation(metadata_rotation).await?; + } + } + Ok(()) +} + +async fn run_metadata_rotation(metadata_rotation: MetadataRotation) -> anyhow::Result<()> { + let MetadataRotation { + iota_node_config_path, + account_key_path, + fullnode_rpc_url, + } = metadata_rotation; + let account_key = read_keypair_from_file(&account_key_path)?; + let config: NodeConfig = PersistedConfig::read(&iota_node_config_path).map_err(|err| { + err.context(format!( + "Cannot open Iota Node Config file at {:?}", + iota_node_config_path + )) + })?; + + let iota_client = IotaClientBuilder::default().build(fullnode_rpc_url).await?; + let iota_address = IotaAddress::from(&account_key.public()); + let starting_epoch = current_epoch(&iota_client).await?; + info!( + "Running Metadata Rotation fire drill for validator address {iota_address} in epoch {starting_epoch}." + ); + + // Prepare new metadata for next epoch + let new_config_path = + update_next_epoch_metadata(&iota_node_config_path, &config, &iota_client, &account_key) + .await?; + + let current_epoch = current_epoch(&iota_client).await?; + if current_epoch > starting_epoch { + bail!("Epoch already advanced to {current_epoch}"); + } + let target_epoch = starting_epoch + 1; + wait_for_next_epoch(&iota_client, target_epoch).await?; + info!("Just advanced to epoch {target_epoch}"); + + // Replace new config + std::fs::rename(new_config_path, iota_node_config_path)?; + info!("Updated Iota Node config."); + + Ok(()) +} + +// TODO move this to a shared lib +pub async fn get_gas_obj_ref( + iota_address: IotaAddress, + iota_client: &IotaClient, + minimal_gas_balance: u64, +) -> anyhow::Result { + let coins = iota_client + .coin_read_api() + .get_coins(iota_address, Some("0x2::iota::IOTA".into()), None, None) + .await? + .data; + let gas_obj = coins.iter().find(|c| c.balance >= minimal_gas_balance); + if gas_obj.is_none() { + bail!("Validator doesn't have enough Iota coins to cover transaction fees."); + } + Ok(gas_obj.unwrap().object_ref()) +} + +async fn update_next_epoch_metadata( + iota_node_config_path: &Path, + config: &NodeConfig, + iota_client: &IotaClient, + account_key: &IotaKeyPair, +) -> anyhow::Result { + // Save backup config just in case + let mut backup_config_path = iota_node_config_path.to_path_buf(); + backup_config_path.pop(); + backup_config_path.push("node_config_backup.yaml"); + let backup_config = config.clone(); + backup_config.persisted(&backup_config_path).save()?; + + let iota_address = IotaAddress::from(&account_key.public()); + + let mut new_config = config.clone(); + + // protocol key + let new_protocol_key_pair = get_authority_key_pair().1; + let new_protocol_key_pair_copy = new_protocol_key_pair.copy(); + let pop = generate_proof_of_possession(&new_protocol_key_pair, iota_address); + new_config.protocol_key_pair = AuthorityKeyPairWithPath::new(new_protocol_key_pair); + + // network key + let new_network_key_pair: Ed25519KeyPair = get_key_pair().1; + let new_network_key_pair_copy = new_network_key_pair.copy(); + new_config.network_key_pair = KeyPairWithPath::new(IotaKeyPair::Ed25519(new_network_key_pair)); + + // worker key + let new_worker_key_pair: Ed25519KeyPair = get_key_pair().1; + let new_worker_key_pair_copy = new_worker_key_pair.copy(); + new_config.worker_key_pair = KeyPairWithPath::new(IotaKeyPair::Ed25519(new_worker_key_pair)); + + let validators = iota_client + .governance_api() + .get_latest_iota_system_state() + .await? + .active_validators; + let self_validator = validators + .iter() + .find(|v| v.iota_address == iota_address) + .unwrap(); + + // Network address + let mut new_network_address = Multiaddr::try_from(self_validator.net_address.clone()).unwrap(); + info!("Current network address: {:?}", new_network_address); + let http = new_network_address.pop().unwrap(); + // pop out tcp + new_network_address.pop().unwrap(); + let localhost = local_ip_utils::localhost_for_testing(); + let new_port = local_ip_utils::get_available_port(&localhost); + new_network_address.push(Protocol::Tcp(new_port)); + new_network_address.push(http); + info!("New network address: {:?}", new_network_address); + new_config.network_address = new_network_address.clone(); + + // p2p address + let mut new_external_address = config.p2p_config.external_address.clone().unwrap(); + info!("Current P2P external address: {:?}", new_external_address); + // pop out udp + new_external_address.pop().unwrap(); + let new_port = local_ip_utils::get_available_port(&localhost); + new_external_address.push(Protocol::Udp(new_port)); + info!("New P2P external address: {:?}", new_external_address); + new_config.p2p_config.external_address = Some(new_external_address.clone()); + + let mut new_listen_address = config.p2p_config.listen_address; + info!("Current P2P local listen address: {:?}", new_listen_address); + new_listen_address.set_port(new_port); + info!("New P2P local listen address: {:?}", new_listen_address); + new_config.p2p_config.listen_address = new_listen_address; + + // primary address + let mut new_primary_addresses = + Multiaddr::try_from(self_validator.primary_address.clone()).unwrap(); + info!("Current primary address: {:?}", new_primary_addresses); + // pop out udp + new_primary_addresses.pop().unwrap(); + let new_port = local_ip_utils::get_available_port(&localhost); + new_primary_addresses.push(Protocol::Udp(new_port)); + info!("New primary address: {:?}", new_primary_addresses); + + // worker address + let mut new_worker_addresses = Multiaddr::try_from( + validators + .iter() + .find(|v| v.iota_address == iota_address) + .unwrap() + .worker_address + .clone(), + ) + .unwrap(); + info!("Current worker address: {:?}", new_worker_addresses); + // pop out udp + new_worker_addresses.pop().unwrap(); + let new_port = local_ip_utils::get_available_port(&localhost); + new_worker_addresses.push(Protocol::Udp(new_port)); + info!("New worker address:: {:?}", new_worker_addresses); + + // Save new config + let mut new_config_path = iota_node_config_path.to_path_buf(); + new_config_path.pop(); + new_config_path.push( + String::from(iota_node_config_path.file_name().unwrap().to_str().unwrap()) + ".next_epoch", + ); + new_config.persisted(&new_config_path).save()?; + + // update protocol pubkey on chain + update_metadata_on_chain( + account_key, + "update_validator_next_epoch_protocol_pubkey", + vec![ + CallArg::Pure( + bcs::to_bytes(&new_protocol_key_pair_copy.public().as_bytes().to_vec()).unwrap(), + ), + CallArg::Pure(bcs::to_bytes(&pop.as_bytes().to_vec()).unwrap()), + ], + iota_client, + ) + .await?; + + // update network pubkey on chain + update_metadata_on_chain( + account_key, + "update_validator_next_epoch_network_pubkey", + vec![CallArg::Pure( + bcs::to_bytes(&new_network_key_pair_copy.public().as_bytes().to_vec()).unwrap(), + )], + iota_client, + ) + .await?; + + // update worker pubkey on chain + update_metadata_on_chain( + account_key, + "update_validator_next_epoch_worker_pubkey", + vec![CallArg::Pure( + bcs::to_bytes(&new_worker_key_pair_copy.public().as_bytes().to_vec()).unwrap(), + )], + iota_client, + ) + .await?; + + // update network address + update_metadata_on_chain( + account_key, + "update_validator_next_epoch_network_address", + vec![CallArg::Pure(bcs::to_bytes(&new_network_address).unwrap())], + iota_client, + ) + .await?; + + // update p2p address + update_metadata_on_chain( + account_key, + "update_validator_next_epoch_p2p_address", + vec![CallArg::Pure(bcs::to_bytes(&new_external_address).unwrap())], + iota_client, + ) + .await?; + + // update primary address + update_metadata_on_chain( + account_key, + "update_validator_next_epoch_primary_address", + vec![CallArg::Pure( + bcs::to_bytes(&new_primary_addresses).unwrap(), + )], + iota_client, + ) + .await?; + + // update worker address + update_metadata_on_chain( + account_key, + "update_validator_next_epoch_worker_address", + vec![CallArg::Pure(bcs::to_bytes(&new_worker_addresses).unwrap())], + iota_client, + ) + .await?; + + Ok(new_config_path) +} + +async fn update_metadata_on_chain( + account_key: &IotaKeyPair, + function: &'static str, + call_args: Vec, + iota_client: &IotaClient, +) -> anyhow::Result<()> { + let iota_address = IotaAddress::from(&account_key.public()); + let gas_obj_ref = get_gas_obj_ref(iota_address, iota_client, 10000 * 100).await?; + let rgp = iota_client + .governance_api() + .get_reference_gas_price() + .await?; + let mut args = vec![CallArg::IOTA_SYSTEM_MUT]; + args.extend(call_args); + let tx_data = TransactionData::new_move_call( + iota_address, + IOTA_SYSTEM_PACKAGE_ID, + ident_str!("iota_system").to_owned(), + ident_str!(function).to_owned(), + vec![], + gas_obj_ref, + args, + rgp * TEST_ONLY_GAS_UNIT_FOR_GENERIC, + rgp, + ) + .unwrap(); + execute_tx(account_key, iota_client, tx_data, function).await?; + tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; + Ok(()) +} + +async fn execute_tx( + account_key: &IotaKeyPair, + iota_client: &IotaClient, + tx_data: TransactionData, + action: &str, +) -> anyhow::Result<()> { + let tx = Transaction::from_data_and_signer(tx_data, vec![account_key]); + info!("Executing {:?}", tx.digest()); + let tx_digest = *tx.digest(); + let resp = iota_client + .quorum_driver_api() + .execute_transaction_block( + tx, + IotaTransactionBlockResponseOptions::full_content(), + Some(iota_types::quorum_driver_types::ExecuteTransactionRequestType::WaitForLocalExecution), + ) + .await + .unwrap(); + if *resp.effects.unwrap().status() != IotaExecutionStatus::Success { + anyhow::bail!("Tx to update metadata {:?} failed", tx_digest); + } + info!("{action} succeeded"); + Ok(()) +} + +async fn wait_for_next_epoch( + iota_client: &IotaClient, + target_epoch: EpochId, +) -> anyhow::Result<()> { + loop { + let epoch_id = current_epoch(iota_client).await?; + if epoch_id > target_epoch { + bail!( + "Current epoch ID {} is higher than target {}, likely something is off.", + epoch_id, + target_epoch + ); + } + if epoch_id == target_epoch { + return Ok(()); + } + tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; + } +} + +async fn current_epoch(iota_client: &IotaClient) -> anyhow::Result { + Ok(iota_client.read_api().get_committee_info(None).await?.epoch) +} diff --git a/crates/sui/src/generate_genesis_checkpoint.rs b/crates/iota/src/generate_genesis_checkpoint.rs similarity index 81% rename from crates/sui/src/generate_genesis_checkpoint.rs rename to crates/iota/src/generate_genesis_checkpoint.rs index 1cc1b7a9d24..0b2a85f6e91 100644 --- a/crates/sui/src/generate_genesis_checkpoint.rs +++ b/crates/iota/src/generate_genesis_checkpoint.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use camino::Utf8PathBuf; -use sui_config::local_ip_utils; -use sui_genesis_builder::{validator_info::ValidatorInfo, Builder}; -use sui_types::{ - base_types::SuiAddress, +use iota_config::local_ip_utils; +use iota_genesis_builder::{validator_info::ValidatorInfo, Builder}; +use iota_types::{ + base_types::IotaAddress, crypto::{ generate_proof_of_possession, get_key_pair_from_rng, AccountKeyPair, AuthorityKeyPair, KeypairTraits, NetworkKeyPair, @@ -28,10 +29,10 @@ async fn main() { name: format!("Validator {}", i), protocol_key: key.public().into(), worker_key: worker_key.public().clone(), - account_address: SuiAddress::from(account_key.public()), + account_address: IotaAddress::from(account_key.public()), network_key: network_key.public().clone(), - gas_price: sui_config::node::DEFAULT_VALIDATOR_GAS_PRICE, - commission_rate: sui_config::node::DEFAULT_COMMISSION_RATE, + gas_price: iota_config::node::DEFAULT_VALIDATOR_GAS_PRICE, + commission_rate: iota_config::node::DEFAULT_COMMISSION_RATE, network_address: local_ip_utils::new_local_tcp_address_for_testing(), p2p_address: local_ip_utils::new_local_udp_address_for_testing(), narwhal_primary_address: local_ip_utils::new_local_udp_address_for_testing(), diff --git a/crates/sui/src/genesis_ceremony.rs b/crates/iota/src/genesis_ceremony.rs similarity index 86% rename from crates/sui/src/genesis_ceremony.rs rename to crates/iota/src/genesis_ceremony.rs index 09e56112ce6..36c3cdc6608 100644 --- a/crates/sui/src/genesis_ceremony.rs +++ b/crates/iota/src/genesis_ceremony.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::PathBuf; @@ -7,16 +8,16 @@ use anyhow::Result; use camino::Utf8PathBuf; use clap::Parser; use fastcrypto::encoding::{Encoding, Hex}; -use sui_config::{genesis::UnsignedGenesis, SUI_GENESIS_FILENAME}; -use sui_genesis_builder::Builder; -use sui_keys::keypair_file::{ +use iota_config::{genesis::UnsignedGenesis, IOTA_GENESIS_FILENAME}; +use iota_genesis_builder::Builder; +use iota_keys::keypair_file::{ read_authority_keypair_from_file, read_keypair_from_file, read_network_keypair_from_file, }; -use sui_types::{ - base_types::SuiAddress, +use iota_types::{ + base_types::IotaAddress, committee::ProtocolVersion, crypto::{ - generate_proof_of_possession, AuthorityKeyPair, KeypairTraits, NetworkKeyPair, SuiKeyPair, + generate_proof_of_possession, AuthorityKeyPair, IotaKeyPair, KeypairTraits, NetworkKeyPair, }, message_envelope::Message, multiaddr::Multiaddr, @@ -129,19 +130,19 @@ pub fn run(cmd: Ceremony) -> Result<()> { } => { let mut builder = Builder::load(&dir)?; let keypair: AuthorityKeyPair = read_authority_keypair_from_file(validator_key_file)?; - let account_keypair: SuiKeyPair = read_keypair_from_file(account_key_file)?; + let account_keypair: IotaKeyPair = read_keypair_from_file(account_key_file)?; let worker_keypair: NetworkKeyPair = read_network_keypair_from_file(worker_key_file)?; let network_keypair: NetworkKeyPair = read_network_keypair_from_file(network_key_file)?; let pop = generate_proof_of_possession(&keypair, (&account_keypair.public()).into()); builder = builder.add_validator( - sui_genesis_builder::validator_info::ValidatorInfo { + iota_genesis_builder::validator_info::ValidatorInfo { name, protocol_key: keypair.public().into(), worker_key: worker_keypair.public().clone(), - account_address: SuiAddress::from(&account_keypair.public()), + account_address: IotaAddress::from(&account_keypair.public()), network_key: network_keypair.public().clone(), - gas_price: sui_config::node::DEFAULT_VALIDATOR_GAS_PRICE, - commission_rate: sui_config::node::DEFAULT_COMMISSION_RATE, + gas_price: iota_config::node::DEFAULT_VALIDATOR_GAS_PRICE, + commission_rate: iota_config::node::DEFAULT_COMMISSION_RATE, network_address, p2p_address, narwhal_primary_address, @@ -233,11 +234,11 @@ pub fn run(cmd: Ceremony) -> Result<()> { let genesis = builder.build(); - genesis.save(dir.join(SUI_GENESIS_FILENAME))?; + genesis.save(dir.join(IOTA_GENESIS_FILENAME))?; - println!("Successfully built {SUI_GENESIS_FILENAME}"); + println!("Successfully built {IOTA_GENESIS_FILENAME}"); println!( - "{SUI_GENESIS_FILENAME} blake2b-256: {}", + "{IOTA_GENESIS_FILENAME} blake2b-256: {}", Hex::encode(genesis.hash()) ); } @@ -249,7 +250,7 @@ pub fn run(cmd: Ceremony) -> Result<()> { fn check_protocol_version(builder: &Builder, protocol_version: ProtocolVersion) -> Result<()> { // It is entirely possible for the user to sign a genesis blob with an unknown // protocol version, but if this happens there is almost certainly some - // confusion (e.g. using a `sui` binary built at the wrong commit). + // confusion (e.g. using a `iota` binary built at the wrong commit). if builder.protocol_version() != protocol_version { return Err(anyhow::anyhow!( "Serialized protocol version does not match local --protocol-version argument. ({:?} vs {:?})", @@ -263,11 +264,13 @@ fn check_protocol_version(builder: &Builder, protocol_version: ProtocolVersion) #[cfg(test)] mod test { use anyhow::Result; - use sui_config::local_ip_utils; - use sui_genesis_builder::validator_info::ValidatorInfo; - use sui_keys::keypair_file::{write_authority_keypair_to_file, write_keypair_to_file}; - use sui_macros::nondeterministic; - use sui_types::crypto::{get_key_pair_from_rng, AccountKeyPair, AuthorityKeyPair, SuiKeyPair}; + use iota_config::local_ip_utils; + use iota_genesis_builder::validator_info::ValidatorInfo; + use iota_keys::keypair_file::{write_authority_keypair_to_file, write_keypair_to_file}; + use iota_macros::nondeterministic; + use iota_types::crypto::{ + get_key_pair_from_rng, AccountKeyPair, AuthorityKeyPair, IotaKeyPair, + }; use super::*; @@ -289,10 +292,10 @@ mod test { name: format!("validator-{i}"), protocol_key: keypair.public().into(), worker_key: worker_keypair.public().clone(), - account_address: SuiAddress::from(account_keypair.public()), + account_address: IotaAddress::from(account_keypair.public()), network_key: network_keypair.public().clone(), - gas_price: sui_config::node::DEFAULT_VALIDATOR_GAS_PRICE, - commission_rate: sui_config::node::DEFAULT_COMMISSION_RATE, + gas_price: iota_config::node::DEFAULT_VALIDATOR_GAS_PRICE, + commission_rate: iota_config::node::DEFAULT_COMMISSION_RATE, network_address: local_ip_utils::new_local_tcp_address_for_testing(), p2p_address: local_ip_utils::new_local_udp_address_for_testing(), narwhal_primary_address: local_ip_utils::new_local_udp_address_for_testing(), @@ -305,15 +308,15 @@ mod test { write_authority_keypair_to_file(&keypair, &key_file).unwrap(); let worker_key_file = dir.path().join(format!("{}.key", info.name)); - write_keypair_to_file(&SuiKeyPair::Ed25519(worker_keypair), &worker_key_file) + write_keypair_to_file(&IotaKeyPair::Ed25519(worker_keypair), &worker_key_file) .unwrap(); let network_key_file = dir.path().join(format!("{}-1.key", info.name)); - write_keypair_to_file(&SuiKeyPair::Ed25519(network_keypair), &network_key_file) + write_keypair_to_file(&IotaKeyPair::Ed25519(network_keypair), &network_key_file) .unwrap(); let account_key_file = dir.path().join(format!("{}-2.key", info.name)); - write_keypair_to_file(&SuiKeyPair::Ed25519(account_keypair), &account_key_file) + write_keypair_to_file(&IotaKeyPair::Ed25519(account_keypair), &account_key_file) .unwrap(); ( diff --git a/crates/iota/src/genesis_inspector.rs b/crates/iota/src/genesis_inspector.rs new file mode 100644 index 00000000000..ecfb19e0389 --- /dev/null +++ b/crates/iota/src/genesis_inspector.rs @@ -0,0 +1,384 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; + +use inquire::Select; +use iota_config::genesis::UnsignedGenesis; +use iota_types::{ + base_types::ObjectID, + coin::CoinMetadata, + gas_coin::{GasCoin, MICROS_PER_IOTA, TOTAL_SUPPLY_MICROS}, + governance::StakedIota, + iota_system_state::IotaValidatorGenesis, + move_package::MovePackage, + object::{MoveObject, Owner}, +}; + +const STR_ALL: &str = "All"; +const STR_EXIT: &str = "Exit"; +const STR_IOTA: &str = "Iota"; +const STR_STAKED_IOTA: &str = "StakedIota"; +const STR_PACKAGE: &str = "Package"; +const STR_COIN_METADATA: &str = "CoinMetadata"; +const STR_OTHER: &str = "Other"; +const STR_IOTA_DISTRIBUTION: &str = "Iota Distribution"; +const STR_OBJECTS: &str = "Objects"; +const STR_VALIDATORS: &str = "Validators"; + +#[allow(clippy::or_fun_call)] +pub(crate) fn examine_genesis_checkpoint(genesis: UnsignedGenesis) { + let system_object = genesis + .iota_system_object() + .into_genesis_version_for_tooling(); + + // Prepare Validator info + let validator_set = &system_object.validators.active_validators; + let validator_map = validator_set + .iter() + .map(|v| (v.verified_metadata().name.as_str(), v)) + .collect::>(); + let validator_pool_id_map = validator_set + .iter() + .map(|v| (v.staking_pool.id, v)) + .collect::>(); + + let mut validator_options: Vec<_> = validator_map.keys().copied().collect(); + validator_options.extend_from_slice(&[STR_ALL, STR_EXIT]); + println!("Total Number of Validators: {}", validator_set.len()); + + // Prepare Iota distribution info + let mut iota_distribution = BTreeMap::new(); + let entry = iota_distribution + .entry("Iota System".to_string()) + .or_insert(BTreeMap::new()); + entry.insert( + "Storage Fund".to_string(), + ( + STR_IOTA, + system_object.storage_fund.non_refundable_balance.value(), + ), + ); + entry.insert( + "Stake Subsidy".to_string(), + (STR_IOTA, system_object.stake_subsidy.balance.value()), + ); + + // Prepare Object Info + let mut owner_map = BTreeMap::new(); + let mut package_map = BTreeMap::new(); + let mut iota_map = BTreeMap::new(); + let mut staked_iota_map = BTreeMap::new(); + let mut coin_metadata_map = BTreeMap::new(); + let mut other_object_map = BTreeMap::new(); + + for object in genesis.objects() { + let object_id = object.id(); + let object_id_str = object_id.to_string(); + assert_eq!(object.storage_rebate, 0); + owner_map.insert(object.id(), object.owner); + + match &object.data { + iota_types::object::Data::Move(move_object) => { + if let Ok(gas) = GasCoin::try_from(object) { + let entry = iota_distribution + .entry(object.owner.to_string()) + .or_default(); + entry.insert(object_id_str.clone(), (STR_IOTA, gas.value())); + iota_map.insert(object.id(), gas); + } else if let Ok(coin_metadata) = CoinMetadata::try_from(object) { + coin_metadata_map.insert(object.id(), coin_metadata); + } else if let Ok(staked_iota) = StakedIota::try_from(object) { + let entry = iota_distribution + .entry(object.owner.to_string()) + .or_default(); + entry.insert(object_id_str, (STR_STAKED_IOTA, staked_iota.principal())); + // Assert pool id is associated with a knonw validator. + let validator = validator_pool_id_map.get(&staked_iota.pool_id()).unwrap(); + assert_eq!(validator.staking_pool.id, staked_iota.pool_id()); + + staked_iota_map.insert(object.id(), staked_iota); + } else { + other_object_map.insert(object.id(), move_object); + } + } + iota_types::object::Data::Package(p) => { + package_map.insert(object.id(), p); + } + } + } + println!( + "Total Number of Objects/Pacakges: {}", + genesis.objects().len() + ); + + // Always check the Total Supply + examine_total_supply(&iota_distribution, false); + + // Main loop for inspection + let main_options: Vec<&str> = + vec![STR_IOTA_DISTRIBUTION, STR_VALIDATORS, STR_OBJECTS, STR_EXIT]; + loop { + let ans = Select::new( + "Select one main category to examine ('Exit' to exit the program):", + main_options.clone(), + ) + .prompt(); + match ans { + Ok(name) if name == STR_IOTA_DISTRIBUTION => { + examine_total_supply(&iota_distribution, true) + } + Ok(name) if name == STR_VALIDATORS => { + examine_validators(&validator_options, &validator_map); + } + Ok(name) if name == STR_OBJECTS => { + println!("Examine Objects (total: {})", genesis.objects().len()); + examine_object( + &owner_map, + &validator_pool_id_map, + &package_map, + &iota_map, + &staked_iota_map, + &coin_metadata_map, + &other_object_map, + ); + } + Ok(name) if name == STR_EXIT => break, + Ok(_) => (), + Err(err) => { + println!("Error: {err}"); + break; + } + } + } +} + +#[allow(clippy::ptr_arg)] +fn examine_validators( + validator_options: &Vec<&str>, + validator_map: &BTreeMap<&str, &IotaValidatorGenesis>, +) { + loop { + let ans = Select::new("Select one validator to examine ('All' to display all Validators, 'Exit' to return to Main):", validator_options.clone()).prompt(); + match ans { + Ok(name) if name == STR_ALL => { + for validator in validator_map.values() { + display_validator(validator); + } + } + Ok(name) if name == STR_EXIT => break, + Ok(name) => { + let validator = validator_map.get(name).unwrap(); + display_validator(validator); + } + Err(err) => { + println!("Error: {err}"); + break; + } + } + } + print_divider("Validator"); +} + +fn examine_object( + owner_map: &BTreeMap, + validator_pool_id_map: &BTreeMap, + package_map: &BTreeMap, + iota_map: &BTreeMap, + staked_iota_map: &BTreeMap, + coin_metadata_map: &BTreeMap, + other_object_map: &BTreeMap, +) { + let object_options: Vec<&str> = vec![ + STR_IOTA, + STR_STAKED_IOTA, + STR_COIN_METADATA, + STR_PACKAGE, + STR_OTHER, + STR_EXIT, + ]; + loop { + let ans = Select::new( + "Select one object category to examine ('Exit' to return to Main):", + object_options.clone(), + ) + .prompt(); + match ans { + Ok(name) if name == STR_EXIT => break, + Ok(name) if name == STR_IOTA => { + for gas_coin in iota_map.values() { + display_iota(gas_coin, owner_map); + } + print_divider("Iota"); + } + Ok(name) if name == STR_STAKED_IOTA => { + for staked_iota_coin in staked_iota_map.values() { + display_staked_iota(staked_iota_coin, validator_pool_id_map, owner_map); + } + print_divider(STR_STAKED_IOTA); + } + Ok(name) if name == STR_PACKAGE => { + for package in package_map.values() { + println!("Package ID: {}", package.id()); + println!("Version: {}", package.version()); + println!("Modules: {:?}\n", package.serialized_module_map().keys()); + } + print_divider("Package"); + } + Ok(name) if name == STR_OTHER => { + for other_obj in other_object_map.values() { + println!("{:#?}", other_obj.type_()); + println!("{:?}", other_obj.version()); + println!("Has Public Transfer: {}\n", other_obj.has_public_transfer()); + } + print_divider("Other"); + } + Ok(name) if name == STR_COIN_METADATA => { + for coin_metadata in coin_metadata_map.values() { + println!("{:#?}\n", coin_metadata); + } + print_divider("CoinMetadata"); + } + Ok(_) => (), + Err(err) => { + println!("Error: {err}"); + break; + } + } + } + print_divider("Object"); +} + +fn examine_total_supply( + iota_distribution: &BTreeMap>, + print: bool, +) { + let mut total_iota = 0; + let mut total_staked_iota = 0; + for (owner, coins) in iota_distribution { + let mut amount_sum = 0; + for (owner, value) in coins.values() { + amount_sum += value; + if *owner == STR_STAKED_IOTA { + total_staked_iota += value; + } + } + total_iota += amount_sum; + if print { + println!("Owner {:?}", owner); + println!( + "Total Amount of Iota/StakedIota Owned: {amount_sum} MICROS or {} IOTA:", + amount_sum / MICROS_PER_IOTA + ); + println!("{:#?}\n", coins); + } + } + assert_eq!(total_iota, TOTAL_SUPPLY_MICROS); + // Always print this. + println!( + "Total Supply of Iota: {total_iota} MICROS or {} IOTA", + total_iota / MICROS_PER_IOTA + ); + println!( + "Total Amount of StakedIota: {total_staked_iota} MICROS or {} IOTA\n", + total_staked_iota / MICROS_PER_IOTA + ); + if print { + print_divider("Iota Distribution"); + } +} + +fn display_validator(validator: &IotaValidatorGenesis) { + let metadata = validator.verified_metadata(); + println!("Validator name: {}", metadata.name); + println!("{:#?}", metadata); + println!("Voting Power: {}", validator.voting_power); + println!("Gas Price: {}", validator.gas_price); + println!("Next Epoch Gas Price: {}", validator.next_epoch_gas_price); + println!("Commission Rate: {}", validator.commission_rate); + println!( + "Next Epoch Commission Rate: {}", + validator.next_epoch_commission_rate + ); + println!("Next Epoch Stake: {}", validator.next_epoch_stake); + println!("Staking Pool ID: {}", validator.staking_pool.id); + println!( + "Staking Pool Activation Epoch: {:?}", + validator.staking_pool.activation_epoch + ); + println!( + "Staking Pool Deactivation Epoch: {:?}", + validator.staking_pool.deactivation_epoch + ); + println!( + "Staking Pool Iota Balance: {:?}", + validator.staking_pool.iota_balance + ); + println!( + "Rewards Pool: {}", + validator.staking_pool.rewards_pool.value() + ); + println!( + "Pool Token Balance: {}", + validator.staking_pool.pool_token_balance + ); + println!( + "Pending Delegation: {}", + validator.staking_pool.pending_stake + ); + println!( + "Pending Total Iota Withdraw: {}", + validator.staking_pool.pending_total_iota_withdraw + ); + println!( + "Pendign Pool Token Withdraw: {}", + validator.staking_pool.pending_pool_token_withdraw + ); + println!( + "Exchange Rates ID: {}", + validator.staking_pool.exchange_rates.id + ); + println!( + "Exchange Rates Size: {}", + validator.staking_pool.exchange_rates.size + ); + print_divider(&metadata.name); +} + +fn display_iota(gas_coin: &GasCoin, owner_map: &BTreeMap) { + println!("ID: {}", gas_coin.id()); + println!("Balance: {}", gas_coin.value()); + println!("Owner: {}\n", owner_map.get(gas_coin.id()).unwrap()); +} + +fn display_staked_iota( + staked_iota: &StakedIota, + validator_pool_id_map: &BTreeMap, + owner_map: &BTreeMap, +) { + let validator = validator_pool_id_map.get(&staked_iota.pool_id()).unwrap(); + println!("{:#?}", staked_iota); + println!( + "Staked to Validator: {}", + validator.verified_metadata().name + ); + println!("Owner: {}\n", owner_map.get(&staked_iota.id()).unwrap()); +} + +fn print_divider(title: &str) { + let title = format!("End of {title}"); + let divider_length = 80; + let left_divider_length = 10; + assert!(title.len() <= divider_length - left_divider_length * 2); + let divider_op = "-"; + let divider = divider_op.repeat(divider_length); + let left_divider = divider_op.repeat(left_divider_length); + let margin_length = (divider_length - left_divider_length * 2 - title.len()) / 2; + let margin = " ".repeat(margin_length); + println!(); + println!("{divider}"); + println!("{left_divider}{margin}{title}{margin}{left_divider}"); + println!("{divider}"); + println!(); +} diff --git a/crates/iota/src/iota_commands.rs b/crates/iota/src/iota_commands.rs new file mode 100644 index 00000000000..5de0ebdc3d0 --- /dev/null +++ b/crates/iota/src/iota_commands.rs @@ -0,0 +1,680 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + fs, io, + io::{stderr, stdout, Write}, + num::NonZeroUsize, + path::{Path, PathBuf}, +}; + +use anyhow::{anyhow, bail}; +use clap::*; +use fastcrypto::traits::KeyPair; +use iota_config::{ + iota_config_dir, node::Genesis, p2p::SeedPeer, Config, PersistedConfig, FULL_NODE_DB_PATH, + IOTA_BENCHMARK_GENESIS_GAS_KEYSTORE_FILENAME, IOTA_CLIENT_CONFIG, IOTA_FULLNODE_CONFIG, + IOTA_GENESIS_FILENAME, IOTA_KEYSTORE_FILENAME, IOTA_NETWORK_CONFIG, +}; +use iota_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; +use iota_move::{self, execute_move_command}; +use iota_move_build::IotaPackageHooks; +use iota_sdk::{ + iota_client_config::{IotaClientConfig, IotaEnv}, + wallet_context::WalletContext, +}; +use iota_swarm::memory::Swarm; +use iota_swarm_config::{ + genesis_config::{GenesisConfig, DEFAULT_NUMBER_OF_AUTHORITIES}, + network_config::NetworkConfig, + network_config_builder::ConfigBuilder, + node_config_builder::FullnodeConfigBuilder, +}; +use iota_types::crypto::{IotaKeyPair, SignatureScheme}; +use move_package::BuildConfig; +use rand::rngs::OsRng; +use tracing::info; + +use crate::{ + client_commands::IotaClientCommands, + console::start_console, + fire_drill::{run_fire_drill, FireDrill}, + genesis_ceremony::{run, Ceremony}, + keytool::KeyToolCommand, + validator_commands::IotaValidatorCommand, +}; + +#[allow(clippy::large_enum_variant)] +#[derive(Parser)] +#[clap(rename_all = "kebab-case")] +pub enum IotaCommand { + /// Start iota network. + #[clap(name = "start")] + Start { + #[clap(long = "network.config")] + config: Option, + #[clap(long = "no-full-node")] + no_full_node: bool, + }, + #[clap(name = "network")] + Network { + #[clap(long = "network.config")] + config: Option, + #[clap(short, long, help = "Dump the public keys of all authorities")] + dump_addresses: bool, + }, + /// Bootstrap and initialize a new iota network + #[clap(name = "genesis")] + Genesis { + #[clap(long, help = "Start genesis with a given config file")] + from_config: Option, + #[clap( + long, + help = "Build a genesis config, write it to the specified path, and exit" + )] + write_config: Option, + #[clap(long)] + working_dir: Option, + #[clap(short, long, help = "Forces overwriting existing configuration")] + force: bool, + #[clap(long = "epoch-duration-ms")] + epoch_duration_ms: Option, + #[clap( + long, + value_name = "ADDR", + num_args(1..), + value_delimiter = ',', + help = "A list of ip addresses to generate a genesis suitable for benchmarks" + )] + benchmark_ips: Option>, + #[clap( + long, + help = "Creates an extra faucet configuration for iota-test-validator persisted runs." + )] + with_faucet: bool, + }, + GenesisCeremony(Ceremony), + /// Iota keystore tool. + #[clap(name = "keytool")] + KeyTool { + #[clap(long)] + keystore_path: Option, + /// Return command outputs in json format + #[clap(long, global = true)] + json: bool, + /// Subcommands. + #[clap(subcommand)] + cmd: KeyToolCommand, + }, + /// Start Iota interactive console. + #[clap(name = "console")] + Console { + /// Sets the file storing the state of our user accounts (an empty one + /// will be created if missing) + #[clap(long = "client.config")] + config: Option, + }, + /// Client for interacting with the Iota network. + #[clap(name = "client")] + Client { + /// Sets the file storing the state of our user accounts (an empty one + /// will be created if missing) + #[clap(long = "client.config")] + config: Option, + #[clap(subcommand)] + cmd: Option, + /// Return command outputs in json format. + #[clap(long, global = true)] + json: bool, + #[clap(short = 'y', long = "yes")] + accept_defaults: bool, + }, + /// A tool for validators and validator candidates. + #[clap(name = "validator")] + Validator { + /// Sets the file storing the state of our user accounts (an empty one + /// will be created if missing) + #[clap(long = "client.config")] + config: Option, + #[clap(subcommand)] + cmd: Option, + /// Return command outputs in json format. + #[clap(long, global = true)] + json: bool, + #[clap(short = 'y', long = "yes")] + accept_defaults: bool, + }, + + /// Tool to build and test Move applications. + #[clap(name = "move")] + Move { + /// Path to a package which the command should be run with respect to. + #[clap(long = "path", short = 'p', global = true)] + package_path: Option, + /// Package build options + #[clap(flatten)] + build_config: BuildConfig, + /// Subcommands. + #[clap(subcommand)] + cmd: iota_move::Command, + }, + + /// Tool for Fire Drill + FireDrill { + #[clap(subcommand)] + fire_drill: FireDrill, + }, +} + +impl IotaCommand { + pub async fn execute(self) -> Result<(), anyhow::Error> { + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); + match self { + IotaCommand::Start { + config, + no_full_node, + } => { + // Auto genesis if path is none and iota directory doesn't exists. + if config.is_none() && !iota_config_dir()?.join(IOTA_NETWORK_CONFIG).exists() { + genesis(None, None, None, false, None, None, false).await?; + } + + // Load the config of the Iota authority. + let network_config_path = config + .clone() + .unwrap_or(iota_config_dir()?.join(IOTA_NETWORK_CONFIG)); + let network_config: NetworkConfig = PersistedConfig::read(&network_config_path) + .map_err(|err| { + err.context(format!( + "Cannot open Iota network config file at {:?}", + network_config_path + )) + })?; + let mut swarm_builder = Swarm::builder() + .dir(iota_config_dir()?) + .with_network_config(network_config); + if no_full_node { + swarm_builder = swarm_builder.with_fullnode_count(0); + } else { + swarm_builder = swarm_builder + .with_fullnode_count(1) + .with_fullnode_rpc_addr(iota_config::node::default_json_rpc_address()); + } + let mut swarm = swarm_builder.build(); + swarm.launch().await?; + + let mut interval = tokio::time::interval(std::time::Duration::from_secs(3)); + let mut unhealthy_cnt = 0; + loop { + for node in swarm.validator_nodes() { + if let Err(err) = node.health_check(true).await { + unhealthy_cnt += 1; + if unhealthy_cnt > 3 { + // The network could temporarily go down during reconfiguration. + // If we detect a failed validator 3 times in a row, give up. + return Err(err.into()); + } + // Break the inner loop so that we could retry latter. + break; + } else { + unhealthy_cnt = 0; + } + } + + interval.tick().await; + } + } + IotaCommand::Network { + config, + dump_addresses, + } => { + let config_path = config.unwrap_or(iota_config_dir()?.join(IOTA_NETWORK_CONFIG)); + let config: NetworkConfig = PersistedConfig::read(&config_path).map_err(|err| { + err.context(format!( + "Cannot open Iota network config file at {:?}", + config_path + )) + })?; + + if dump_addresses { + for validator in config.validator_configs() { + println!( + "{} - {}", + validator.network_address(), + validator.protocol_key_pair().public(), + ); + } + } + Ok(()) + } + IotaCommand::Genesis { + working_dir, + force, + from_config, + write_config, + epoch_duration_ms, + benchmark_ips, + with_faucet, + } => { + genesis( + from_config, + write_config, + working_dir, + force, + epoch_duration_ms, + benchmark_ips, + with_faucet, + ) + .await + } + IotaCommand::GenesisCeremony(cmd) => run(cmd), + IotaCommand::KeyTool { + keystore_path, + json, + cmd, + } => { + let keystore_path = + keystore_path.unwrap_or(iota_config_dir()?.join(IOTA_KEYSTORE_FILENAME)); + let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path)?); + cmd.execute(&mut keystore).await?.print(!json); + Ok(()) + } + IotaCommand::Console { config } => { + let config = config.unwrap_or(iota_config_dir()?.join(IOTA_CLIENT_CONFIG)); + prompt_if_no_config(&config, false).await?; + let context = WalletContext::new(&config, None, None)?; + start_console(context, &mut stdout(), &mut stderr()).await + } + IotaCommand::Client { + config, + cmd, + json, + accept_defaults, + } => { + let config_path = config.unwrap_or(iota_config_dir()?.join(IOTA_CLIENT_CONFIG)); + prompt_if_no_config(&config_path, accept_defaults).await?; + let mut context = WalletContext::new(&config_path, None, None)?; + if let Some(cmd) = cmd { + cmd.execute(&mut context).await?.print(!json); + } else { + // Print help + let mut app: Command = IotaCommand::command(); + app.build(); + app.find_subcommand_mut("client").unwrap().print_help()?; + } + Ok(()) + } + IotaCommand::Validator { + config, + cmd, + json, + accept_defaults, + } => { + let config_path = config.unwrap_or(iota_config_dir()?.join(IOTA_CLIENT_CONFIG)); + prompt_if_no_config(&config_path, accept_defaults).await?; + let mut context = WalletContext::new(&config_path, None, None)?; + if let Some(cmd) = cmd { + cmd.execute(&mut context).await?.print(!json); + } else { + // Print help + let mut app: Command = IotaCommand::command(); + app.build(); + app.find_subcommand_mut("validator").unwrap().print_help()?; + } + Ok(()) + } + IotaCommand::Move { + package_path, + build_config, + cmd, + } => execute_move_command(package_path, build_config, cmd), + IotaCommand::FireDrill { fire_drill } => run_fire_drill(fire_drill).await, + } + } +} + +async fn genesis( + from_config: Option, + write_config: Option, + working_dir: Option, + force: bool, + epoch_duration_ms: Option, + benchmark_ips: Option>, + with_faucet: bool, +) -> Result<(), anyhow::Error> { + let iota_config_dir = &match working_dir { + // if a directory is specified, it must exist (it + // will not be created) + Some(v) => v, + // create default Iota config dir if not specified + // on the command line and if it does not exist + // yet + None => { + let config_path = iota_config_dir()?; + fs::create_dir_all(&config_path)?; + config_path + } + }; + + // if Iota config dir is not empty then either clean it + // up (if --force/-f option was specified or report an + // error + let dir = iota_config_dir.read_dir().map_err(|err| { + anyhow!(err).context(format!("Cannot open Iota config dir {:?}", iota_config_dir)) + })?; + let files = dir.collect::, _>>()?; + + let client_path = iota_config_dir.join(IOTA_CLIENT_CONFIG); + let keystore_path = iota_config_dir.join(IOTA_KEYSTORE_FILENAME); + + if write_config.is_none() && !files.is_empty() { + if force { + // check old keystore and client.yaml is compatible + let is_compatible = FileBasedKeystore::new(&keystore_path).is_ok() + && PersistedConfig::::read(&client_path).is_ok(); + // Keep keystore and client.yaml if they are compatible + if is_compatible { + for file in files { + let path = file.path(); + if path != client_path && path != keystore_path { + if path.is_file() { + fs::remove_file(path) + } else { + fs::remove_dir_all(path) + } + .map_err(|err| { + anyhow!(err).context(format!("Cannot remove file {:?}", file.path())) + })?; + } + } + } else { + fs::remove_dir_all(iota_config_dir).map_err(|err| { + anyhow!(err).context(format!( + "Cannot remove Iota config dir {:?}", + iota_config_dir + )) + })?; + fs::create_dir(iota_config_dir).map_err(|err| { + anyhow!(err).context(format!( + "Cannot create Iota config dir {:?}", + iota_config_dir + )) + })?; + } + } else if files.len() != 2 || !client_path.exists() || !keystore_path.exists() { + bail!( + "Cannot run genesis with non-empty Iota config directory {}, please use the --force/-f option to remove the existing configuration", + iota_config_dir.to_str().unwrap() + ); + } + } + + let network_path = iota_config_dir.join(IOTA_NETWORK_CONFIG); + let genesis_path = iota_config_dir.join(IOTA_GENESIS_FILENAME); + + let mut genesis_conf = match from_config { + Some(path) => PersistedConfig::read(&path)?, + None => { + if let Some(ips) = benchmark_ips { + // Make a keystore containing the key for the genesis gas object. + let path = iota_config_dir.join(IOTA_BENCHMARK_GENESIS_GAS_KEYSTORE_FILENAME); + let mut keystore = FileBasedKeystore::new(&path)?; + for gas_key in GenesisConfig::benchmark_gas_keys(ips.len()) { + keystore.add_key(None, gas_key)?; + } + keystore.save()?; + + // Make a new genesis config from the provided ip addresses. + GenesisConfig::new_for_benchmarks(&ips) + } else if keystore_path.exists() { + let existing_keys = FileBasedKeystore::new(&keystore_path)?.addresses(); + GenesisConfig::for_local_testing_with_addresses(existing_keys) + } else { + GenesisConfig::for_local_testing() + } + } + }; + + // Adds an extra faucet account to the genesis + if with_faucet { + info!("Adding faucet account in genesis config..."); + genesis_conf = genesis_conf.add_faucet_account(); + } + + if let Some(path) = write_config { + let persisted = genesis_conf.persisted(&path); + persisted.save()?; + return Ok(()); + } + + let validator_info = genesis_conf.validator_config_info.take(); + let ssfn_info = genesis_conf.ssfn_config_info.take(); + + let builder = ConfigBuilder::new(iota_config_dir); + if let Some(epoch_duration_ms) = epoch_duration_ms { + genesis_conf.parameters.epoch_duration_ms = epoch_duration_ms; + } + let mut network_config = if let Some(validators) = validator_info { + builder + .with_genesis_config(genesis_conf) + .with_validators(validators) + .build() + } else { + builder + .committee_size(NonZeroUsize::new(DEFAULT_NUMBER_OF_AUTHORITIES).unwrap()) + .with_genesis_config(genesis_conf) + .build() + }; + + let mut keystore = FileBasedKeystore::new(&keystore_path)?; + for key in &network_config.account_keys { + keystore.add_key(None, IotaKeyPair::Ed25519(key.copy()))?; + } + let active_address = keystore.addresses().pop(); + + network_config.genesis.save(&genesis_path)?; + for validator in &mut network_config.validator_configs { + validator.genesis = iota_config::node::Genesis::new_from_file(&genesis_path); + } + + info!("Network genesis completed."); + network_config.save(&network_path)?; + info!("Network config file is stored in {:?}.", network_path); + + info!("Client keystore is stored in {:?}.", keystore_path); + + let fullnode_config = FullnodeConfigBuilder::new() + .with_config_directory(FULL_NODE_DB_PATH.into()) + .with_rpc_addr(iota_config::node::default_json_rpc_address()) + .build(&mut OsRng, &network_config); + + fullnode_config.save(iota_config_dir.join(IOTA_FULLNODE_CONFIG))?; + let mut ssfn_nodes = vec![]; + if let Some(ssfn_info) = ssfn_info { + for (i, ssfn) in ssfn_info.into_iter().enumerate() { + let path = + iota_config_dir.join(iota_config::ssfn_config_file(ssfn.p2p_address.clone(), i)); + // join base fullnode config with each SsfnGenesisConfig entry + let ssfn_config = FullnodeConfigBuilder::new() + .with_config_directory(FULL_NODE_DB_PATH.into()) + .with_p2p_external_address(ssfn.p2p_address) + .with_network_key_pair(ssfn.network_key_pair) + .with_p2p_listen_address("0.0.0.0:8084".parse().unwrap()) + .with_db_path(PathBuf::from("/opt/iota/db/authorities_db/full_node_db")) + .with_network_address("/ip4/0.0.0.0/tcp/8080/http".parse().unwrap()) + .with_metrics_address("0.0.0.0:9184".parse().unwrap()) + .with_admin_interface_port(1337) + .with_json_rpc_address("0.0.0.0:9000".parse().unwrap()) + .with_genesis(Genesis::new_from_file("/opt/iota/config/genesis.blob")) + .build(&mut OsRng, &network_config); + ssfn_nodes.push(ssfn_config.clone()); + ssfn_config.save(path)?; + } + + let ssfn_seed_peers: Vec = ssfn_nodes + .iter() + .map(|config| SeedPeer { + peer_id: Some(anemo::PeerId( + config.network_key_pair().public().0.to_bytes(), + )), + address: config.p2p_config.external_address.clone().unwrap(), + }) + .collect(); + + for (i, mut validator) in network_config + .into_validator_configs() + .into_iter() + .enumerate() + { + let path = iota_config_dir.join(iota_config::validator_config_file( + validator.network_address.clone(), + i, + )); + let mut val_p2p = validator.p2p_config.clone(); + val_p2p.seed_peers = ssfn_seed_peers.clone(); + validator.p2p_config = val_p2p; + validator.save(path)?; + } + } else { + for (i, validator) in network_config + .into_validator_configs() + .into_iter() + .enumerate() + { + let path = iota_config_dir.join(iota_config::validator_config_file( + validator.network_address.clone(), + i, + )); + validator.save(path)?; + } + } + + let mut client_config = if client_path.exists() { + PersistedConfig::read(&client_path)? + } else { + IotaClientConfig::new(keystore.into()) + }; + + if client_config.active_address.is_none() { + client_config.active_address = active_address; + } + client_config.add_env(IotaEnv { + alias: "localnet".to_string(), + rpc: format!("http://{}", fullnode_config.json_rpc_address), + ws: None, + }); + client_config.add_env(IotaEnv::devnet()); + + if client_config.active_env.is_none() { + client_config.active_env = client_config.envs.first().map(|env| env.alias.clone()); + } + + client_config.save(&client_path)?; + info!("Client config file is stored in {:?}.", client_path); + + Ok(()) +} + +async fn prompt_if_no_config( + wallet_conf_path: &Path, + accept_defaults: bool, +) -> Result<(), anyhow::Error> { + // Prompt user for connect to devnet fullnode if config does not exist. + if !wallet_conf_path.exists() { + let env = match std::env::var_os("IOTA_CONFIG_WITH_RPC_URL") { + Some(v) => Some(IotaEnv { + alias: "custom".to_string(), + rpc: v.into_string().unwrap(), + ws: None, + }), + None => { + if accept_defaults { + print!( + "Creating config file [{:?}] with default (devnet) Full node server and ed25519 key scheme.", + wallet_conf_path + ); + } else { + print!( + "Config file [{:?}] doesn't exist, do you want to connect to a Iota Full node server [y/N]?", + wallet_conf_path + ); + } + if accept_defaults + || matches!(read_line(), Ok(line) if line.trim().to_lowercase() == "y") + { + let url = if accept_defaults { + String::new() + } else { + print!( + "Iota Full node server URL (Defaults to Iota Devnet if not specified) : " + ); + read_line()? + }; + Some(if url.trim().is_empty() { + IotaEnv::devnet() + } else { + print!("Environment alias for [{url}] : "); + let alias = read_line()?; + let alias = if alias.trim().is_empty() { + "custom".to_string() + } else { + alias + }; + IotaEnv { + alias, + rpc: url, + ws: None, + } + }) + } else { + None + } + } + }; + + if let Some(env) = env { + let keystore_path = wallet_conf_path + .parent() + .unwrap_or(&iota_config_dir()?) + .join(IOTA_KEYSTORE_FILENAME); + let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path)?); + let key_scheme = if accept_defaults { + SignatureScheme::ED25519 + } else { + println!( + "Select key scheme to generate keypair (0 for ed25519, 1 for secp256k1, 2: for secp256r1):" + ); + match SignatureScheme::from_flag(read_line()?.trim()) { + Ok(s) => s, + Err(e) => return Err(anyhow!("{e}")), + } + }; + let (new_address, phrase, scheme) = + keystore.generate_and_add_new_key(key_scheme, None, None, None)?; + let alias = keystore.get_alias_by_address(&new_address)?; + println!( + "Generated new keypair and alias for address with scheme {:?} [{alias}: {new_address}]", + scheme.to_string() + ); + println!("Secret Recovery Phrase : [{phrase}]"); + let alias = env.alias.clone(); + IotaClientConfig { + keystore, + envs: vec![env], + active_address: Some(new_address), + active_env: Some(alias), + } + .persisted(wallet_conf_path) + .save()?; + } + } + Ok(()) +} + +fn read_line() -> Result { + let mut s = String::new(); + let _ = stdout().flush(); + io::stdin().read_line(&mut s)?; + Ok(s.trim_end().to_string()) +} diff --git a/crates/sui/src/key_identity.rs b/crates/iota/src/key_identity.rs similarity index 78% rename from crates/sui/src/key_identity.rs rename to crates/iota/src/key_identity.rs index 1b36a66ae77..3b7d7ba2863 100644 --- a/crates/sui/src/key_identity.rs +++ b/crates/iota/src/key_identity.rs @@ -1,20 +1,21 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fmt::Display, str::FromStr}; use anyhow::Error; +use iota_keys::keystore::{AccountKeystore, Keystore}; +use iota_sdk::wallet_context::WalletContext; +use iota_types::base_types::IotaAddress; use serde::Serialize; -use sui_keys::keystore::{AccountKeystore, Keystore}; -use sui_sdk::wallet_context::WalletContext; -use sui_types::base_types::SuiAddress; /// An address or an alias associated with a key in the wallet /// This is used to distinguish between an address or an alias, /// enabling a user to use an alias for any command that requires an address. #[derive(Serialize, Clone)] pub enum KeyIdentity { - Address(SuiAddress), + Address(IotaAddress), Alias(String), } @@ -22,7 +23,7 @@ impl FromStr for KeyIdentity { type Err = anyhow::Error; fn from_str(s: &str) -> Result { if s.starts_with("0x") { - Ok(KeyIdentity::Address(SuiAddress::from_str(s)?)) + Ok(KeyIdentity::Address(IotaAddress::from_str(s)?)) } else { Ok(KeyIdentity::Alias(s.to_string())) } @@ -39,12 +40,12 @@ impl Display for KeyIdentity { } } -/// Get the SuiAddress corresponding to this key identity. +/// Get the IotaAddress corresponding to this key identity. /// If no string is provided, then the curernt active address is returned. pub fn get_identity_address( input: Option, ctx: &mut WalletContext, -) -> Result { +) -> Result { if let Some(addr) = input { get_identity_address_from_keystore(addr, &ctx.config.keystore) } else { @@ -55,7 +56,7 @@ pub fn get_identity_address( pub fn get_identity_address_from_keystore( input: KeyIdentity, keystore: &Keystore, -) -> Result { +) -> Result { match input { KeyIdentity::Address(x) => Ok(x), KeyIdentity::Alias(x) => Ok(*keystore.get_address_by_alias(x)?), diff --git a/crates/sui/src/keytool.rs b/crates/iota/src/keytool.rs similarity index 88% rename from crates/sui/src/keytool.rs rename to crates/iota/src/keytool.rs index 9fc218f0917..edbc8e12312 100644 --- a/crates/sui/src/keytool.rs +++ b/crates/iota/src/keytool.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ fmt::{Debug, Display, Formatter}, @@ -22,15 +23,7 @@ use fastcrypto_zkp::bn254::{ zk_login_api::ZkLoginEnv, }; use im::hashmap::HashMap as ImHashMap; -use json_to_table::{json_to_table, Orientation}; -use num_bigint::BigUint; -use rand::{rngs::StdRng, Rng, SeedableRng}; -use rusoto_core::Region; -use rusoto_kms::{Kms, KmsClient, SignRequest}; -use serde::Serialize; -use serde_json::json; -use shared_crypto::intent::{Intent, IntentMessage, IntentScope, PersonalMessage}; -use sui_keys::{ +use iota_keys::{ key_derive::generate_new_key, keypair_file::{ read_authority_keypair_from_file, read_keypair_from_file, write_authority_keypair_to_file, @@ -38,14 +31,14 @@ use sui_keys::{ }, keystore::{AccountKeystore, Keystore}, }; -use sui_types::{ - base_types::SuiAddress, +use iota_types::{ + base_types::IotaAddress, committee::EpochId, crypto::{ - get_authority_key_pair, DefaultHash, EncodeDecodeBase64, PublicKey, Signature, - SignatureScheme, SuiKeyPair, + get_authority_key_pair, DefaultHash, EncodeDecodeBase64, IotaKeyPair, PublicKey, Signature, + SignatureScheme, }, - error::SuiResult, + error::IotaResult, multisig::{MultiSig, MultiSigPublicKey, ThresholdUnit, WeightUnit}, multisig_legacy::{MultiSigLegacy, MultiSigPublicKeyLegacy}, signature::{AuthenticatorTrait, GenericSignature, VerifyParams}, @@ -53,6 +46,14 @@ use sui_types::{ zk_login_authenticator::ZkLoginAuthenticator, zk_login_util::get_zklogin_inputs, }; +use json_to_table::{json_to_table, Orientation}; +use num_bigint::BigUint; +use rand::{rngs::StdRng, Rng, SeedableRng}; +use rusoto_core::Region; +use rusoto_kms::{Kms, KmsClient, SignRequest}; +use serde::Serialize; +use serde_json::json; +use shared_crypto::intent::{Intent, IntentMessage, IntentScope, PersonalMessage}; use tabled::{ builder::Builder, settings::{object::Rows, Modify, Rotate, Width}, @@ -81,10 +82,10 @@ pub enum KeyToolCommand { new_alias: Option, }, /// Convert private key in Hex or Base64 to new format (Bech32 - /// encoded 33 byte flag || private key starting with "suiprivkey"). + /// encoded 33 byte flag || private key starting with "iotaprivkey"). /// Hex private key format import and export are both deprecated in - /// Sui Wallet and Sui CLI Keystore. Use `sui keytool import` if you - /// wish to import a key to Sui Keystore. + /// Iota Wallet and Iota CLI Keystore. Use `iota keytool import` if you + /// wish to import a key to Iota Keystore. Convert { value: String }, /// Given a Base64 encoded transaction bytes, decode its components. If a /// signature is provided, verify the signature against the transaction @@ -113,17 +114,17 @@ pub enum KeyToolCommand { /// The keypair file is output to the current directory. The content of the /// file is a Base64 encoded string of 33-byte `flag || privkey`. /// - /// Use `sui client new-address` if you want to generate and save the key - /// into sui.keystore. + /// Use `iota client new-address` if you want to generate and save the key + /// into iota.keystore. Generate { key_scheme: SignatureScheme, derivation_path: Option, word_length: Option, }, - /// Add a new key to Sui CLI Keystore using either the input mnemonic phrase - /// or a Bech32 encoded 33-byte `flag || privkey` starting with - /// "suiprivkey", the key scheme flag {ed25519 | secp256k1 | secp256r1} + /// Add a new key to Iota CLI Keystore using either the input mnemonic + /// phrase or a Bech32 encoded 33-byte `flag || privkey` starting with + /// "iotaprivkey", the key scheme flag {ed25519 | secp256k1 | secp256r1} /// and an optional derivation path, default to m/44'/4218'/0'/0'/0' for /// ed25519 or m/54'/4218'/0'/0/0 for secp256k1 or m/74'/4218'/0'/0/0 /// for secp256r1. Supports mnemonic phrase of word length 12, 15, @@ -139,27 +140,27 @@ pub enum KeyToolCommand { key_scheme: SignatureScheme, derivation_path: Option, }, - /// Output the private key of the given key identity in Sui CLI Keystore as - /// Bech32 encoded string starting with `suiprivkey`. + /// Output the private key of the given key identity in Iota CLI Keystore as + /// Bech32 encoded string starting with `iotaprivkey`. Export { #[clap(long)] key_identity: KeyIdentity, }, - /// List all keys by its Sui address, Base64 encoded public key, key scheme - /// name in sui.keystore. + /// List all keys by its Iota address, Base64 encoded public key, key scheme + /// name in iota.keystore. List { /// Sort by alias #[clap(long, short = 's')] sort_by_alias: bool, }, /// This reads the content at the provided file path. The accepted format - /// can be [enum SuiKeyPair] (Base64 encoded of 33-byte `flag || + /// can be [enum IotaKeyPair] (Base64 encoded of 33-byte `flag || /// privkey`) or `type AuthorityKeyPair` (Base64 encoded `privkey`). /// This prints out the account keypair as Base64 encoded `flag || privkey`, /// the network keypair, worker keypair, protocol keypair as Base64 encoded /// `privkey`. LoadKeypair { file: PathBuf }, - /// To MultiSig Sui Address. Pass in a list of all public keys `flag || pk` + /// To MultiSig Iota Address. Pass in a list of all public keys `flag || pk` /// in Base64. See `keytool list` for example public keys. MultiSigAddress { #[clap(long)] @@ -173,7 +174,7 @@ pub enum KeyToolCommand { /// in Base64), threshold, a list of all public keys and a list of their /// weights that define the MultiSig address. Returns a valid MultiSig /// signature and its sender address. The result can be used as - /// signature field for `sui client execute-signed-tx`. The sum + /// signature field for `iota client execute-signed-tx`. The sum /// of weights of all signatures must be >= the threshold. /// /// The order of `sigs` must be the same as the order of `pks`. @@ -201,12 +202,12 @@ pub enum KeyToolCommand { }, /// Read the content at the provided file path. The accepted format can be - /// [enum SuiKeyPair] (Base64 encoded of 33-byte `flag || privkey`) or `type - /// AuthorityKeyPair` (Base64 encoded `privkey`). It prints its Base64 - /// encoded public key and the key scheme flag. + /// [enum IotaKeyPair] (Base64 encoded of 33-byte `flag || privkey`) or + /// `type AuthorityKeyPair` (Base64 encoded `privkey`). It prints its + /// Base64 encoded public key and the key scheme flag. Show { file: PathBuf }, /// Create signature using the private key for for the given address (or its - /// alias) in sui keystore. Any signature commits to a [struct + /// alias) in iota keystore. Any signature commits to a [struct /// IntentMessage] consisting of the Base64 encoded of the BCS /// serialized transaction bytes itself and its intent. If intent is absent, /// default will be used. @@ -234,9 +235,9 @@ pub enum KeyToolCommand { #[clap(long)] base64pk: String, }, - /// This takes [enum SuiKeyPair] of Base64 encoded of 33-byte `flag || + /// This takes [enum IotaKeyPair] of Base64 encoded of 33-byte `flag || /// privkey`). It outputs the keypair into a file at the current - /// directory where the address is the filename, and prints out its Sui + /// directory where the address is the filename, and prints out its Iota /// address, Base64 encoded public key, the key scheme, and the key scheme /// flag. Unpack { keypair: String }, @@ -272,7 +273,7 @@ pub enum KeyToolCommand { #[clap(long)] kp_bigint: String, #[clap(long)] - ephemeral_key_identifier: SuiAddress, + ephemeral_key_identifier: IotaAddress, #[clap(long, default_value = "devnet")] network: String, #[clap(long, default_value = "true")] @@ -284,7 +285,7 @@ pub enum KeyToolCommand { /// Given a zkLogin signature, parse it if valid. If `bytes` provided, /// parse it as either as TransactionData or PersonalMessage based on /// `intent_scope`. It verifies the zkLogin signature based its latest - /// JWK fetched. Example request: sui keytool zk-login-sig-verify --sig + /// JWK fetched. Example request: iota keytool zk-login-sig-verify --sig /// $SERIALIZED_ZKLOGIN_SIG --bytes $BYTES --intent-scope 0 --network devnet /// --curr-epoch 10 ZkLoginSigVerify { @@ -335,7 +336,7 @@ pub struct DecodedMultiSig { #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct DecodedMultiSigOutput { - multisig_address: SuiAddress, + multisig_address: IotaAddress, participating_keys_signatures: Vec, pub_keys: Vec, threshold: usize, @@ -346,14 +347,14 @@ pub struct DecodedMultiSigOutput { #[serde(rename_all = "camelCase")] pub struct DecodeOrVerifyTxOutput { tx: TransactionData, - result: Option, + result: Option, } #[derive(PartialEq, Eq, PartialOrd, Ord, Serialize)] #[serde(rename_all = "camelCase")] pub struct Key { alias: Option, - sui_address: SuiAddress, + iota_address: IotaAddress, public_base64_key: String, key_scheme: String, flag: u8, @@ -388,7 +389,7 @@ pub struct MultiSigAddress { #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct MultiSigCombinePartialSig { - multisig_address: SuiAddress, + multisig_address: IotaAddress, multisig_parsed: GenericSignature, multisig_serialized: String, } @@ -396,7 +397,7 @@ pub struct MultiSigCombinePartialSig { #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct MultiSigCombinePartialSigLegacyOutput { - multisig_address: SuiAddress, + multisig_address: IotaAddress, multisig_legacy_parsed: GenericSignature, multisig_legacy_serialized: String, } @@ -404,7 +405,7 @@ pub struct MultiSigCombinePartialSigLegacyOutput { #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct MultiSigOutput { - address: SuiAddress, + address: IotaAddress, public_base64_key: String, weight: u8, } @@ -412,9 +413,9 @@ pub struct MultiSigOutput { #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct ConvertOutput { - bech32_with_flag: String, // latest Sui Keystore and Sui Wallet import/export format - base64_with_flag: String, // Sui Keystore storage format - hex_without_flag: String, // Legacy Sui Wallet format + bech32_with_flag: String, // latest Iota Keystore and Iota Wallet import/export format + base64_with_flag: String, // Iota Keystore storage format + hex_without_flag: String, // Legacy Iota Wallet format scheme: String, } @@ -433,7 +434,7 @@ pub struct SerializedSig { #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct SignData { - sui_address: SuiAddress, + iota_address: IotaAddress, // Base64 encoded string of serialized transaction data. raw_tx_data: String, // Intent struct used, see [struct Intent] for field definitions. @@ -444,8 +445,8 @@ pub struct SignData { // Base64 encoded blake2b hash of the intent message, this is what the signature commits to. digest: String, // Base64 encoded `flag || signature || pubkey` for a complete - // serialized Sui signature to be send for executing the transaction. - sui_signature: String, + // serialized Iota signature to be send for executing the transaction. + iota_signature: String, } #[derive(Serialize)] @@ -460,7 +461,7 @@ pub struct ZkLoginSigVerifyResponse { data: Option, parsed: Option, jwks: Option, - res: Option, + res: Option, } #[derive(Serialize)] @@ -517,7 +518,7 @@ impl KeyToolCommand { let pks = multisig.get_pk().pubkeys(); let sigs = multisig.get_sigs(); let bitmap = multisig.get_indices()?; - let address = SuiAddress::from(multisig.get_pk()); + let address = IotaAddress::from(multisig.get_pk()); let pub_keys = pks .iter() @@ -555,7 +556,7 @@ impl KeyToolCommand { let tx_data: TransactionData = bcs::from_bytes(&tx_bytes)?; let s = GenericSignature::MultiSig(multisig); let res = s.verify_authenticator( - &IntentMessage::new(Intent::sui_transaction(), tx_data), + &IntentMessage::new(Intent::iota_transaction(), tx_data), address, None, &VerifyParams::default(), @@ -577,7 +578,7 @@ impl KeyToolCommand { }), Some(s) => { let res = s.verify_authenticator( - &IntentMessage::new(Intent::sui_transaction(), tx_data.clone()), + &IntentMessage::new(Intent::iota_transaction(), tx_data.clone()), tx_data.sender(), None, &VerifyParams::default(), @@ -595,12 +596,12 @@ impl KeyToolCommand { word_length, } => match key_scheme { SignatureScheme::BLS12381 => { - let (sui_address, kp) = get_authority_key_pair(); - let file_name = format!("bls-{sui_address}.key"); + let (iota_address, kp) = get_authority_key_pair(); + let file_name = format!("bls-{iota_address}.key"); write_authority_keypair_to_file(&kp, file_name)?; CommandOutput::Generate(Key { alias: None, - sui_address, + iota_address, public_base64_key: kp.public().encode_base64(), key_scheme: key_scheme.to_string(), flag: SignatureScheme::BLS12381.flag(), @@ -609,9 +610,9 @@ impl KeyToolCommand { }) } _ => { - let (sui_address, skp, _scheme, phrase) = + let (iota_address, skp, _scheme, phrase) = generate_new_key(key_scheme, derivation_path, word_length)?; - let file = format!("{sui_address}.key"); + let file = format!("{iota_address}.key"); write_keypair_to_file(&skp, file)?; let mut key = Key::from(&skp); key.mnemonic = Some(phrase); @@ -627,14 +628,14 @@ impl KeyToolCommand { } => { if Hex::decode(&input_string).is_ok() { return Err(anyhow!( - "Sui Keystore and Sui Wallet no longer support importing + "Iota Keystore and Iota Wallet no longer support importing private key as Hex, if you are sure your private key is encoded in Hex, use - `sui keytool convert $HEX` to convert first then import the Bech32 encoded - private key starting with `suiprivkey`." + `iota keytool convert $HEX` to convert first then import the Bech32 encoded + private key starting with `iotaprivkey`." )); } - match SuiKeyPair::decode(&input_string) { + match IotaKeyPair::decode(&input_string) { Ok(skp) => { info!("Importing Bech32 encoded private key to keystore"); let key = Key::from(&skp); @@ -643,12 +644,12 @@ impl KeyToolCommand { } Err(_) => { info!("Importing mneomonics to keystore"); - let sui_address = keystore.import_from_mnemonic( + let iota_address = keystore.import_from_mnemonic( &input_string, key_scheme, derivation_path, )?; - let skp = keystore.get_key(&sui_address)?; + let skp = keystore.get_key(&iota_address)?; let key = Key::from(skp); CommandOutput::Import(key) } @@ -671,7 +672,7 @@ impl KeyToolCommand { .into_iter() .map(|pk| { let mut key = Key::from(pk); - key.alias = keystore.get_alias_by_address(&key.sui_address).ok(); + key.alias = keystore.get_alias_by_address(&key.iota_address).ok(); key }) .collect::>(); @@ -687,9 +688,9 @@ impl KeyToolCommand { // Account keypair is encoded with the key scheme flag {}, // and network and worker keypair are not. let network_worker_keypair = match &keypair { - SuiKeyPair::Ed25519(kp) => kp.encode_base64(), - SuiKeyPair::Secp256k1(kp) => kp.encode_base64(), - SuiKeyPair::Secp256r1(kp) => kp.encode_base64(), + IotaKeyPair::Ed25519(kp) => kp.encode_base64(), + IotaKeyPair::Secp256k1(kp) => kp.encode_base64(), + IotaKeyPair::Secp256r1(kp) => kp.encode_base64(), }; KeypairData { account_keypair: keypair.encode_base64(), @@ -726,7 +727,7 @@ impl KeyToolCommand { weights, } => { let multisig_pk = MultiSigPublicKey::new(pks.clone(), weights.clone(), threshold)?; - let address: SuiAddress = (&multisig_pk).into(); + let address: IotaAddress = (&multisig_pk).into(); let mut output = MultiSigAddress { multisig_address: address.to_string(), multisig: vec![], @@ -734,7 +735,7 @@ impl KeyToolCommand { for (pk, w) in pks.into_iter().zip(weights.into_iter()) { output.multisig.push(MultiSigOutput { - address: Into::::into(&pk), + address: Into::::into(&pk), public_base64_key: pk.encode_base64(), weight: w, }); @@ -749,7 +750,7 @@ impl KeyToolCommand { threshold, } => { let multisig_pk = MultiSigPublicKey::new(pks, weights, threshold)?; - let address: SuiAddress = (&multisig_pk).into(); + let address: IotaAddress = (&multisig_pk).into(); let multisig = MultiSig::combine(sigs, multisig_pk)?; let generic_sig: GenericSignature = multisig.into(); let multisig_serialized = generic_sig.encode_base64(); @@ -769,7 +770,7 @@ impl KeyToolCommand { let multisig_pk_legacy = MultiSigPublicKeyLegacy::new(pks.clone(), weights.clone(), threshold)?; let multisig_pk = MultiSigPublicKey::new(pks, weights, threshold)?; - let address: SuiAddress = (&multisig_pk).into(); + let address: IotaAddress = (&multisig_pk).into(); let multisig = MultiSigLegacy::combine(sigs, multisig_pk_legacy)?; let generic_sig: GenericSignature = multisig.into(); let multisig_legacy_serialized = generic_sig.encode_base64(); @@ -795,7 +796,7 @@ impl KeyToolCommand { let public_base64_key = keypair.public().encode_base64(); CommandOutput::Show(Key { alias: None, // alias does not get stored in key files - sui_address: (keypair.public()).into(), + iota_address: (keypair.public()).into(), public_base64_key, key_scheme: SignatureScheme::BLS12381.to_string(), flag: SignatureScheme::BLS12381.flag(), @@ -817,7 +818,7 @@ impl KeyToolCommand { intent, } => { let address = get_identity_address_from_keystore(address, keystore)?; - let intent = intent.unwrap_or_else(Intent::sui_transaction); + let intent = intent.unwrap_or_else(Intent::iota_transaction); let intent_clone = intent.clone(); let msg: TransactionData = bcs::from_bytes(&Base64::decode(&data).map_err(|e| { @@ -828,15 +829,15 @@ impl KeyToolCommand { let mut hasher = DefaultHash::default(); hasher.update(bcs::to_bytes(&intent_msg)?); let digest = hasher.finalize().digest; - let sui_signature = + let iota_signature = keystore.sign_secure(&address, &intent_msg.value, intent_msg.intent)?; CommandOutput::Sign(SignData { - sui_address: address, + iota_address: address, raw_tx_data: data, intent: intent_clone, raw_intent_msg, digest: Base64::encode(digest), - sui_signature: sui_signature.encode_base64(), + iota_signature: iota_signature.encode_base64(), }) } @@ -849,10 +850,10 @@ impl KeyToolCommand { // Currently only supports secp256k1 keys let pk_owner = PublicKey::decode_base64(&base64pk) .map_err(|e| anyhow!("Invalid base64 key: {:?}", e))?; - let address_owner = SuiAddress::from(&pk_owner); + let address_owner = IotaAddress::from(&pk_owner); info!("Address For Corresponding KMS Key: {}", address_owner); info!("Raw tx_bytes to execute: {}", data); - let intent = intent.unwrap_or_else(Intent::sui_transaction); + let intent = intent.unwrap_or_else(Intent::iota_transaction); info!("Intent: {:?}", intent); let msg: TransactionData = bcs::from_bytes(&Base64::decode(&data).map_err(|e| { @@ -903,15 +904,15 @@ impl KeyToolCommand { } KeyToolCommand::Unpack { keypair } => { - let keypair = SuiKeyPair::decode_base64(&keypair) + let keypair = IotaKeyPair::decode_base64(&keypair) .map_err(|_| anyhow!("Invalid Base64 encode keypair"))?; let key = Key::from(&keypair); - let path_str = format!("{}.key", key.sui_address).to_lowercase(); + let path_str = format!("{}.key", key.iota_address).to_lowercase(); let path = Path::new(&path_str); let out_str = format!( "address: {}\nkeypair: {}\nflag: {}", - key.sui_address, + key.iota_address, keypair.encode_base64(), key.flag ); @@ -926,7 +927,7 @@ impl KeyToolCommand { let intent_msg = IntentMessage::new(Intent::personal_message(), msg.clone()); let skp = - SuiKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))); + IotaKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))); let s = Signature::new_secure(&intent_msg, &skp); let sig = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( @@ -949,13 +950,13 @@ impl KeyToolCommand { sign_with_sk, } => { let skp = if fixed { - SuiKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))) + IotaKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))) } else { - SuiKeyPair::Ed25519(Ed25519KeyPair::generate(&mut rand::thread_rng())) + IotaKeyPair::Ed25519(Ed25519KeyPair::generate(&mut rand::thread_rng())) }; println!("Ephemeral keypair: {:?}", skp.encode()); let pk = skp.public(); - let ephemeral_key_identifier: SuiAddress = (&skp.public()).into(); + let ephemeral_key_identifier: IotaAddress = (&skp.public()).into(); println!("Ephemeral key identifier: {ephemeral_key_identifier}"); keystore.add_key(None, skp)?; @@ -977,7 +978,7 @@ impl KeyToolCommand { &eph_pk_bytes, max_epoch, "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", - "https://sui.io/", + "https://iota.io/", &jwt_randomness, )?; let url_2 = get_oidc_url( @@ -985,7 +986,7 @@ impl KeyToolCommand { &eph_pk_bytes, max_epoch, "rs1bh065i9ya4ydvifixl4kss0uhpt", - "https://sui.io/", + "https://iota.io/", &jwt_randomness, )?; let url_3 = get_oidc_url( @@ -993,7 +994,7 @@ impl KeyToolCommand { &eph_pk_bytes, max_epoch, "233307156352917", - "https://sui.io/", + "https://iota.io/", &jwt_randomness, )?; let url_4 = get_oidc_url( @@ -1001,13 +1002,13 @@ impl KeyToolCommand { &eph_pk_bytes, max_epoch, "aa6bddf393b54d4e0d42ae0014edfd2f", - "https://sui.io/", + "https://iota.io/", &jwt_randomness, )?; let url_5 = get_token_exchange_url( OIDCProvider::Kakao, "aa6bddf393b54d4e0d42ae0014edfd2f", - "https://sui.io/", + "https://iota.io/", "$YOUR_AUTH_CODE", "", // not needed )?; @@ -1016,7 +1017,7 @@ impl KeyToolCommand { &eph_pk_bytes, max_epoch, "nl.digkas.wallet.client", - "https://sui.io/", + "https://iota.io/", &jwt_randomness, )?; let url_7 = get_oidc_url( @@ -1024,13 +1025,13 @@ impl KeyToolCommand { &eph_pk_bytes, max_epoch, "2426087588661.5742457039348", - "https://sui.io/", + "https://iota.io/", &jwt_randomness, )?; let url_8 = get_token_exchange_url( OIDCProvider::Slack, "2426087588661.5742457039348", - "https://sui.io/", + "https://iota.io/", "$YOUR_AUTH_CODE", "39b955a118f2f21110939bf3dff1de90", )?; @@ -1044,7 +1045,7 @@ impl KeyToolCommand { println!("Token exchange URL (Slack): {url_8}"); println!( - "Finish login and paste the entire URL here (e.g. https://sui.io/#id_token=...):" + "Finish login and paste the entire URL here (e.g. https://iota.io/#id_token=...):" ); let parsed_token = read_cli_line()?; @@ -1129,7 +1130,10 @@ impl KeyToolCommand { )?; let res = zk.verify_authenticator( - &IntentMessage::new(Intent::sui_transaction(), tx_data.clone()), + &IntentMessage::new( + Intent::iota_transaction(), + tx_data.clone(), + ), tx_data.execution_parts().1, Some(curr_epoch.unwrap()), &aux_verify_data, @@ -1169,8 +1173,8 @@ impl KeyToolCommand { } } -impl From<&SuiKeyPair> for Key { - fn from(skp: &SuiKeyPair) -> Self { +impl From<&IotaKeyPair> for Key { + fn from(skp: &IotaKeyPair) -> Self { Key::from(skp.public()) } } @@ -1179,7 +1183,7 @@ impl From for Key { fn from(pk: PublicKey) -> Self { Key { alias: None, // this is retrieved later - sui_address: SuiAddress::from(&pk), + iota_address: IotaAddress::from(&pk), public_base64_key: pk.encode_base64(), key_scheme: pk.scheme().to_string(), mnemonic: None, @@ -1210,20 +1214,20 @@ impl Display for CommandOutput { let mut builder = Builder::default(); builder .set_header([ - "suiSignature", + "iotaSignature", "digest", "rawIntentMsg", "intent", "rawTxData", - "suiAddress", + "iotaAddress", ]) .push_record([ - &data.sui_signature, + &data.iota_signature, &data.digest, &data.raw_intent_msg, &intent_table, &data.raw_tx_data, - &data.sui_address.to_string(), + &data.iota_address.to_string(), ]); let mut table = builder.build(); table.with(Rotate::Left); @@ -1279,7 +1283,7 @@ impl Debug for CommandOutput { /// 3) Base64 encoded 33 bytes private key with flag. /// 4) Bech32 encoded 33 bytes private key with flag. fn convert_private_key_to_bech32(value: String) -> Result { - let skp = match SuiKeyPair::decode(&value) { + let skp = match IotaKeyPair::decode(&value) { Ok(s) => s, Err(_) => match Hex::decode(&value) { Ok(decoded) => { @@ -1289,12 +1293,12 @@ fn convert_private_key_to_bech32(value: String) -> Result match SuiKeyPair::decode_base64(&value) { + Err(_) => match IotaKeyPair::decode_base64(&value) { Ok(skp) => skp, Err(_) => match Ed25519KeyPair::decode_base64(&value) { - Ok(kp) => SuiKeyPair::Ed25519(kp), + Ok(kp) => IotaKeyPair::Ed25519(kp), Err(_) => return Err(anyhow!("Invalid private key encoding")), }, }, diff --git a/crates/iota/src/lib.rs b/crates/iota/src/lib.rs new file mode 100644 index 00000000000..420f101da65 --- /dev/null +++ b/crates/iota/src/lib.rs @@ -0,0 +1,18 @@ +// Copyright (c) 2021, Facebook, Inc. and its affiliates +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod client_commands; +#[macro_use] +pub mod client_ptb; +pub mod console; +pub mod fire_drill; +pub mod genesis_ceremony; +pub mod genesis_inspector; +pub mod iota_commands; +pub mod key_identity; +pub mod keytool; +pub mod shell; +pub mod validator_commands; +pub mod zklogin_commands_util; diff --git a/crates/iota/src/main.rs b/crates/iota/src/main.rs new file mode 100644 index 00000000000..167c9cd91cf --- /dev/null +++ b/crates/iota/src/main.rs @@ -0,0 +1,96 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use clap::*; +use colored::Colorize; +use iota::{ + client_commands::IotaClientCommands::{ProfileTransaction, ReplayTransaction}, + iota_commands::IotaCommand, +}; +use iota_types::exit_main; +use tracing::debug; + +const GIT_REVISION: &str = { + if let Some(revision) = option_env!("GIT_REVISION") { + revision + } else { + let version = git_version::git_version!( + args = ["--always", "--dirty", "--exclude", "*"], + fallback = "" + ); + version + } +}; + +const VERSION: &str = { + if GIT_REVISION.is_empty() { + env!("CARGO_PKG_VERSION") + } else { + const_str::concat!(env!("CARGO_PKG_VERSION"), "-", GIT_REVISION) + } +}; + +#[derive(Parser)] +#[clap( + name = env!("CARGO_BIN_NAME"), + about = "A Byzantine fault tolerant chain with low-latency finality and high throughput", + rename_all = "kebab-case", + author, + version = VERSION, + propagate_version = true, +)] +struct Args { + #[clap(subcommand)] + command: IotaCommand, +} + +#[tokio::main] +async fn main() { + #[cfg(windows)] + colored::control::set_virtual_terminal(true).unwrap(); + + let args = Args::parse(); + let _guard = match args.command { + IotaCommand::Console { .. } | IotaCommand::KeyTool { .. } | IotaCommand::Move { .. } => { + telemetry_subscribers::TelemetryConfig::new() + .with_log_level("error") + .with_env() + .init() + } + + IotaCommand::Client { + cmd: Some(ReplayTransaction { + gas_info, ptb_info, .. + }), + .. + } => { + let mut config = telemetry_subscribers::TelemetryConfig::new() + .with_log_level("info") + .with_env(); + if gas_info { + config = config.with_trace_target("replay_gas_info"); + } + if ptb_info { + config = config.with_trace_target("replay_ptb_info"); + } + config.init() + } + IotaCommand::Client { + cmd: Some(ProfileTransaction { .. }), + .. + } => { + // enable full logging for ProfileTransaction and ReplayTransaction + telemetry_subscribers::TelemetryConfig::new() + .with_env() + .init() + } + + _ => telemetry_subscribers::TelemetryConfig::new() + .with_log_level("error") + .with_env() + .init(), + }; + debug!("Iota CLI version: {VERSION}"); + exit_main!(args.command.execute().await); +} diff --git a/crates/sui/src/shell.rs b/crates/iota/src/shell.rs similarity index 99% rename from crates/sui/src/shell.rs rename to crates/iota/src/shell.rs index f1b82b986c0..1c152b3440a 100644 --- a/crates/sui/src/shell.rs +++ b/crates/iota/src/shell.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -364,7 +365,7 @@ impl PartialOrd for CacheKey { /// ``` /// use std::{cmp::Ordering, collections::BTreeMap}; /// -/// use sui::shell::CacheKey; +/// use iota::shell::CacheKey; /// /// assert_eq!( /// Ordering::Equal, diff --git a/crates/sui/src/unit_tests/keytool_tests.rs b/crates/iota/src/unit_tests/keytool_tests.rs similarity index 77% rename from crates/sui/src/unit_tests/keytool_tests.rs rename to crates/iota/src/unit_tests/keytool_tests.rs index 4364c4f7ac2..4a484017407 100644 --- a/crates/sui/src/unit_tests/keytool_tests.rs +++ b/crates/iota/src/unit_tests/keytool_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::str::FromStr; @@ -9,18 +10,18 @@ use fastcrypto::{ encoding::{Base64, Encoding, Hex}, traits::ToFromBytes, }; -use rand::{rngs::StdRng, SeedableRng}; -use shared_crypto::intent::{Intent, IntentScope}; -use sui_keys::keystore::{AccountKeystore, FileBasedKeystore, InMemKeystore, Keystore}; -use sui_types::{ - base_types::{ObjectDigest, ObjectID, SequenceNumber, SuiAddress}, +use iota_keys::keystore::{AccountKeystore, FileBasedKeystore, InMemKeystore, Keystore}; +use iota_types::{ + base_types::{IotaAddress, ObjectDigest, ObjectID, SequenceNumber}, crypto::{ - get_key_pair, get_key_pair_from_rng, AuthorityKeyPair, Ed25519SuiSignature, - EncodeDecodeBase64, Secp256k1SuiSignature, Secp256r1SuiSignature, Signature, - SignatureScheme, SuiKeyPair, SuiSignatureInner, + get_key_pair, get_key_pair_from_rng, AuthorityKeyPair, Ed25519IotaSignature, + EncodeDecodeBase64, IotaKeyPair, IotaSignatureInner, Secp256k1IotaSignature, + Secp256r1IotaSignature, Signature, SignatureScheme, }, transaction::{TransactionData, TEST_ONLY_GAS_UNIT_FOR_TRANSFER}, }; +use rand::{rngs::StdRng, SeedableRng}; +use shared_crypto::intent::{Intent, IntentScope}; use tempfile::TempDir; use tokio::test; @@ -39,7 +40,7 @@ async fn test_addresses_command() -> Result<(), anyhow::Error> { // Add another 3 Secp256k1 KeyPairs for _ in 0..3 { - keystore.add_key(None, SuiKeyPair::Secp256k1(get_key_pair().1))?; + keystore.add_key(None, IotaKeyPair::Secp256k1(get_key_pair().1))?; } // List all addresses with flag @@ -56,35 +57,35 @@ async fn test_addresses_command() -> Result<(), anyhow::Error> { async fn test_flag_in_signature_and_keypair() -> Result<(), anyhow::Error> { let mut keystore = Keystore::from(InMemKeystore::new_insecure_for_tests(0)); - keystore.add_key(None, SuiKeyPair::Secp256k1(get_key_pair().1))?; - keystore.add_key(None, SuiKeyPair::Ed25519(get_key_pair().1))?; + keystore.add_key(None, IotaKeyPair::Secp256k1(get_key_pair().1))?; + keystore.add_key(None, IotaKeyPair::Ed25519(get_key_pair().1))?; for pk in keystore.keys() { let pk1 = pk.clone(); - let sig = keystore.sign_secure(&(&pk).into(), b"hello", Intent::sui_transaction())?; + let sig = keystore.sign_secure(&(&pk).into(), b"hello", Intent::iota_transaction())?; match sig { - Signature::Ed25519SuiSignature(_) => { + Signature::Ed25519IotaSignature(_) => { // signature contains corresponding flag assert_eq!( *sig.as_ref().first().unwrap(), - Ed25519SuiSignature::SCHEME.flag() + Ed25519IotaSignature::SCHEME.flag() ); // keystore stores pubkey with corresponding flag - assert!(pk1.flag() == Ed25519SuiSignature::SCHEME.flag()) + assert!(pk1.flag() == Ed25519IotaSignature::SCHEME.flag()) } - Signature::Secp256k1SuiSignature(_) => { + Signature::Secp256k1IotaSignature(_) => { assert_eq!( *sig.as_ref().first().unwrap(), - Secp256k1SuiSignature::SCHEME.flag() + Secp256k1IotaSignature::SCHEME.flag() ); - assert!(pk1.flag() == Secp256k1SuiSignature::SCHEME.flag()) + assert!(pk1.flag() == Secp256k1IotaSignature::SCHEME.flag()) } - Signature::Secp256r1SuiSignature(_) => { + Signature::Secp256r1IotaSignature(_) => { assert_eq!( *sig.as_ref().first().unwrap(), - Secp256r1SuiSignature::SCHEME.flag() + Secp256r1IotaSignature::SCHEME.flag() ); - assert!(pk1.flag() == Secp256r1SuiSignature::SCHEME.flag()) + assert!(pk1.flag() == Secp256r1IotaSignature::SCHEME.flag()) } } } @@ -96,8 +97,8 @@ async fn test_read_write_keystore_with_flag() { let dir = tempfile::TempDir::new().unwrap(); // create Secp256k1 keypair - let kp_secp = SuiKeyPair::Secp256k1(get_key_pair().1); - let addr_secp: SuiAddress = (&kp_secp.public()).into(); + let kp_secp = IotaKeyPair::Secp256k1(get_key_pair().1); + let addr_secp: IotaAddress = (&kp_secp.public()).into(); let fp_secp = dir.path().join(format!("{}.key", addr_secp)); let fp_secp_2 = fp_secp.clone(); @@ -120,8 +121,8 @@ async fn test_read_write_keystore_with_flag() { assert!(kp_secp_read.is_err()); // create Ed25519 keypair - let kp_ed = SuiKeyPair::Ed25519(get_key_pair().1); - let addr_ed: SuiAddress = (&kp_ed.public()).into(); + let kp_ed = IotaKeyPair::Ed25519(get_key_pair().1); + let addr_ed: IotaAddress = (&kp_ed.public()).into(); let fp_ed = dir.path().join(format!("{}.key", addr_ed)); let fp_ed_2 = fp_ed.clone(); @@ -145,37 +146,37 @@ async fn test_read_write_keystore_with_flag() { } #[test] -async fn test_sui_operations_config() { +async fn test_iota_operations_config() { let temp_dir = TempDir::new().unwrap(); - let path = temp_dir.path().join("sui.keystore"); + let path = temp_dir.path().join("iota.keystore"); let path1 = path.clone(); - // This is the hardcoded keystore in sui-operation: https://github.com/MystenLabs/sui-operations/blob/af04c9d3b61610dbb36401aff6bef29d06ef89f8/docker/config/generate/static/sui.keystore - // If this test fails, address hardcoded in sui-operations is likely needed be + // This is the hardcoded keystore in iota-operation: https://github.com/iotaledger/iota-operations/blob/af04c9d3b61610dbb36401aff6bef29d06ef89f8/docker/config/generate/static/iota.keystore + // If this test fails, address hardcoded in iota-operations is likely needed be // updated. - let kp = SuiKeyPair::decode_base64("ANRj4Rx5FZRehqwrctiLgZDPrY/3tI5+uJLCdaXPCj6C").unwrap(); + let kp = IotaKeyPair::decode_base64("ANRj4Rx5FZRehqwrctiLgZDPrY/3tI5+uJLCdaXPCj6C").unwrap(); let contents = vec![kp.encode_base64()]; let res = std::fs::write(path, serde_json::to_string_pretty(&contents).unwrap()); assert!(res.is_ok()); let read = FileBasedKeystore::new(&path1); assert!(read.is_ok()); assert_eq!( - SuiAddress::from_str("bc14937ffd5874a57afa10edf2d267d8eaaaf61081d718d9ba19cae85c00c6e8") + IotaAddress::from_str("bc14937ffd5874a57afa10edf2d267d8eaaaf61081d718d9ba19cae85c00c6e8") .unwrap(), read.unwrap().addresses()[0] ); - // This is the hardcoded keystore in sui-operation: https://github.com/MystenLabs/sui-operations/blob/af04c9d3b61610dbb36401aff6bef29d06ef89f8/docker/config/generate/static/sui-benchmark.keystore - // If this test fails, address hardcoded in sui-operations is likely needed be + // This is the hardcoded keystore in iota-operation: https://github.com/iotaledger/iota-operations/blob/af04c9d3b61610dbb36401aff6bef29d06ef89f8/docker/config/generate/static/iota-benchmark.keystore + // If this test fails, address hardcoded in iota-operations is likely needed be // updated. - let path2 = temp_dir.path().join("sui-benchmark.keystore"); + let path2 = temp_dir.path().join("iota-benchmark.keystore"); let path3 = path2.clone(); - let kp = SuiKeyPair::decode_base64("APCWxPNCbgGxOYKeMfPqPmXmwdNVyau9y4IsyBcmC14A").unwrap(); + let kp = IotaKeyPair::decode_base64("APCWxPNCbgGxOYKeMfPqPmXmwdNVyau9y4IsyBcmC14A").unwrap(); let contents = vec![kp.encode_base64()]; let res = std::fs::write(path2, serde_json::to_string_pretty(&contents).unwrap()); assert!(res.is_ok()); let read = FileBasedKeystore::new(&path3); assert_eq!( - SuiAddress::from_str("e988a8fb85944173237d287e98e542ae50c119c02644856ed8db17fe9f528b13") + IotaAddress::from_str("e988a8fb85944173237d287e98e542ae50c119c02644856ed8db17fe9f528b13") .unwrap(), read.unwrap().addresses()[0] ); @@ -184,7 +185,7 @@ async fn test_sui_operations_config() { #[test] async fn test_load_keystore_err() { let temp_dir = TempDir::new().unwrap(); - let path = temp_dir.path().join("sui.keystore"); + let path = temp_dir.path().join("iota.keystore"); let path2 = path.clone(); // write encoded AuthorityKeyPair without flag byte to file @@ -199,23 +200,23 @@ async fn test_load_keystore_err() { #[test] async fn test_private_keys_import_export() -> Result<(), anyhow::Error> { - // private key in Bech32, private key in Hex, private key in Base64, derived Sui - // address in Hex + // private key in Bech32, private key in Hex, private key in Base64, derived + // Iota address in Hex const TEST_CASES: &[(&str, &str, &str, &str)] = &[ ( - "suiprivkey1qzwant3kaegmjy4qxex93s0jzvemekkjmyv3r2sjwgnv2y479pgsywhveae", + "iotaprivkey1qzwant3kaegmjy4qxex93s0jzvemekkjmyv3r2sjwgnv2y479pgsywhveae", "0x9dd9ae36ee51b912a0364c58c1f21333bcdad2d91911aa127226c512be285102", "AJ3ZrjbuUbkSoDZMWMHyEzO82tLZGRGqEnImxRK+KFEC", "0x80ebb793af9b40569ed2c3be16e5bd76358997e28cc35ff48681157224c8b038", ), ( - "suiprivkey1qrh2sjl88rze74hwjndw3l26dqyz63tea5u9frtwcsqhmfk9vxdlx8cpv0g", + "iotaprivkey1qrh2sjl88rze74hwjndw3l26dqyz63tea5u9frtwcsqhmfk9vxdlx8cpv0g", "0xeea84be738c59f56ee94dae8fd5a68082d4579ed38548d6ec4017da6c5619bf3", "AO6oS+c4xZ9W7pTa6P1aaAgtRXntOFSNbsQBfabFYZvz", "0xee64bf4dedc0d6d853e156b04b4adae937da0b549d740b9de26d0360813f8f1c", ), ( - "suiprivkey1qzg73qyvfz0wpnyectkl08nrhe4pgnu0vqx8gydu96qx7uj4wyr8gcrjlh3", + "iotaprivkey1qzg73qyvfz0wpnyectkl08nrhe4pgnu0vqx8gydu96qx7uj4wyr8gcrjlh3", "0x91e8808c489ee0cc99c2edf79e63be6a144f8f600c7411bc2e806f7255710674", "AJHogIxInuDMmcLt955jvmoUT49gDHQRvC6Ab3JVcQZ0", "0x3a3bf7803ccb4903e2d9c4c11f80a24fe0c57a3a298f4ebd52667849554021b5", @@ -232,17 +233,17 @@ async fn test_private_keys_import_export() -> Result<(), anyhow::Error> { } .execute(&mut keystore) .await?; - let kp = SuiKeyPair::decode(private_key).unwrap(); - let kp_from_hex = SuiKeyPair::Ed25519( + let kp = IotaKeyPair::decode(private_key).unwrap(); + let kp_from_hex = IotaKeyPair::Ed25519( Ed25519KeyPair::from_bytes(&Hex::decode(private_key_hex).unwrap()).unwrap(), ); assert_eq!(kp, kp_from_hex); - let kp_from_base64 = SuiKeyPair::decode_base64(private_key_base64).unwrap(); + let kp_from_base64 = IotaKeyPair::decode_base64(private_key_base64).unwrap(); assert_eq!(kp, kp_from_base64); - let addr = SuiAddress::from_str(address).unwrap(); - assert_eq!(SuiAddress::from(&kp.public()), addr); + let addr = IotaAddress::from_str(address).unwrap(); + assert_eq!(IotaAddress::from(&kp.public()), addr); assert!(keystore.addresses().contains(&addr)); // Export output shows the private key in Bech32 @@ -290,21 +291,21 @@ async fn test_private_keys_import_export() -> Result<(), anyhow::Error> { #[test] async fn test_mnemonics_ed25519() -> Result<(), anyhow::Error> { // Test case matches with - // /mysten/sui/sdk/typescript/test/unit/cryptography/ed25519-keypair.test.ts + // /mysten/iota/sdk/typescript/test/unit/cryptography/ed25519-keypair.test.ts const TEST_CASES: [[&str; 3]; 3] = [ [ "film crazy soon outside stand loop subway crumble thrive popular green nuclear struggle pistol arm wife phrase warfare march wheat nephew ask sunny firm", - "suiprivkey1qrqqxhsu3ndp96644fjk4z5ams5ulgmvprklngt2jhvg2ujn5w4q23vm2y8", + "iotaprivkey1qrqqxhsu3ndp96644fjk4z5ams5ulgmvprklngt2jhvg2ujn5w4q23vm2y8", "0x9f8e5379678525edf768d7b507dc1ba9016fc4f0eac976ab7f74077d95fba312", ], [ "require decline left thought grid priority false tiny gasp angle royal system attack beef setup reward aunt skill wasp tray vital bounce inflict level", - "suiprivkey1qqcxaf57fnenvflpacacaumf6vl0rt0edddhytanvzhkqhwnjk0zsawjy3x", + "iotaprivkey1qqcxaf57fnenvflpacacaumf6vl0rt0edddhytanvzhkqhwnjk0zsawjy3x", "0x862738192e40540e0a5c9a5aca636f53b0cd76b0a9bef3386e05647feb4914ac", ], [ "organ crash swim stick traffic remember army arctic mesh slice swear summer police vast chaos cradle squirrel hood useless evidence pet hub soap lake", - "suiprivkey1qzq39vxzm0gq7l8dc5dj5allpuww4mavhwhg8mua4cl3lj2c3fvhcsjgphc", + "iotaprivkey1qzq39vxzm0gq7l8dc5dj5allpuww4mavhwhg8mua4cl3lj2c3fvhcsjgphc", "0x2391788ca49c7f0f00699bc2bad45f80c343b4d1df024285c132259433d7ff31", ], ]; @@ -319,9 +320,9 @@ async fn test_mnemonics_ed25519() -> Result<(), anyhow::Error> { } .execute(&mut keystore) .await?; - let kp = SuiKeyPair::decode(t[1]).unwrap(); - let addr = SuiAddress::from_str(t[2]).unwrap(); - assert_eq!(SuiAddress::from(&kp.public()), addr); + let kp = IotaKeyPair::decode(t[1]).unwrap(); + let addr = IotaAddress::from_str(t[2]).unwrap(); + assert_eq!(IotaAddress::from(&kp.public()), addr); assert!(keystore.addresses().contains(&addr)); } Ok(()) @@ -330,21 +331,21 @@ async fn test_mnemonics_ed25519() -> Result<(), anyhow::Error> { #[test] async fn test_mnemonics_secp256k1() -> Result<(), anyhow::Error> { // Test case matches with - // /mysten/sui/sdk/typescript/test/unit/cryptography/secp256k1-keypair.test.ts + // /mysten/iota/sdk/typescript/test/unit/cryptography/secp256k1-keypair.test.ts const TEST_CASES: [[&str; 3]; 3] = [ [ "film crazy soon outside stand loop subway crumble thrive popular green nuclear struggle pistol arm wife phrase warfare march wheat nephew ask sunny firm", - "suiprivkey1q8cy2ll8a0dmzzzwn9zavrug0qf47cyuj6k2r4r6rnjtpjhrdh52vallxwz", + "iotaprivkey1q8cy2ll8a0dmzzzwn9zavrug0qf47cyuj6k2r4r6rnjtpjhrdh52vallxwz", "0x8520d58dde1ab268349b9a46e5124ae6fe7e4c61df4ca2bc9c97d3c4d07b0b55", ], [ "require decline left thought grid priority false tiny gasp angle royal system attack beef setup reward aunt skill wasp tray vital bounce inflict level", - "suiprivkey1q9hm330d05jcxfvmztv046p8kclyaj39hk6elqghgpq4sz4x23hk2jtdnjf", + "iotaprivkey1q9hm330d05jcxfvmztv046p8kclyaj39hk6elqghgpq4sz4x23hk2jtdnjf", "0x3740d570eefba29dfc0fdd5829848902064e31ecd059ca05c401907fa8646f61", ], [ "organ crash swim stick traffic remember army arctic mesh slice swear summer police vast chaos cradle squirrel hood useless evidence pet hub soap lake", - "suiprivkey1qx2dnch6363h7gdqqfkzmmlequzj4ul3x4fq6dzyajk7wc2c0jgcxdv2dvl", + "iotaprivkey1qx2dnch6363h7gdqqfkzmmlequzj4ul3x4fq6dzyajk7wc2c0jgcxdv2dvl", "0x943b852c37fef403047e06ff5a2fa216557a4386212fb29554babdd3e1899da5", ], ]; @@ -359,9 +360,9 @@ async fn test_mnemonics_secp256k1() -> Result<(), anyhow::Error> { } .execute(&mut keystore) .await?; - let kp = SuiKeyPair::decode(t[1]).unwrap(); - let addr = SuiAddress::from_str(t[2]).unwrap(); - assert_eq!(SuiAddress::from(&kp.public()), addr); + let kp = IotaKeyPair::decode(t[1]).unwrap(); + let addr = IotaAddress::from_str(t[2]).unwrap(); + assert_eq!(IotaAddress::from(&kp.public()), addr); assert!(keystore.addresses().contains(&addr)); } Ok(()) @@ -370,21 +371,21 @@ async fn test_mnemonics_secp256k1() -> Result<(), anyhow::Error> { #[test] async fn test_mnemonics_secp256r1() -> Result<(), anyhow::Error> { // Test case matches with - // /mysten/sui/sdk/typescript/test/unit/cryptography/secp256r1-keypair.test.ts + // /mysten/iota/sdk/typescript/test/unit/cryptography/secp256r1-keypair.test.ts const TEST_CASES: [[&str; 3]; 3] = [ [ "act wing dilemma glory episode region allow mad tourist humble muffin oblige", - "suiprivkey1qtt65ua2lhal76zg4cxd6umdqynv2rj2gzrntp5rwlnyj370jg3pwhxg9kc", + "iotaprivkey1qtt65ua2lhal76zg4cxd6umdqynv2rj2gzrntp5rwlnyj370jg3pwhxg9kc", "0x779a63b28528210a5ec6c4af5a70382fa3f0c2d3f98dcbe4e3a4ae2f8c39cc9c", ], [ "flag rebel cabbage captain minimum purpose long already valley horn enrich salt", - "suiprivkey1qtcjgmue7q8u4gtutfvfpx3zj3aa2r9pqssuusrltxfv68eqhzsgjyhk7e4", + "iotaprivkey1qtcjgmue7q8u4gtutfvfpx3zj3aa2r9pqssuusrltxfv68eqhzsgjyhk7e4", "0x8b45523042933aa55f57e2ccc661304baed292529b6e67a0c9857c1f3f871806", ], [ "area renew bar language pudding trial small host remind supreme cabbage era", - "suiprivkey1qtxafg26qxeqy7f56gd2rvsup0a5kl4cre7nt2rtcrf0p3v5pwd4c595zjp", + "iotaprivkey1qtxafg26qxeqy7f56gd2rvsup0a5kl4cre7nt2rtcrf0p3v5pwd4c595zjp", "0x8528ef86150ec331928a8b3edb8adbe2fb523db8c84679aa57a931da6a4cdb25", ], ]; @@ -400,9 +401,9 @@ async fn test_mnemonics_secp256r1() -> Result<(), anyhow::Error> { .execute(&mut keystore) .await?; - let kp = SuiKeyPair::decode(sk).unwrap(); - let addr = SuiAddress::from_str(address).unwrap(); - assert_eq!(SuiAddress::from(&kp.public()), addr); + let kp = IotaKeyPair::decode(sk).unwrap(); + let addr = IotaAddress::from_str(address).unwrap(); + assert_eq!(IotaAddress::from(&kp.public()), addr); assert!(keystore.addresses().contains(&addr)); } @@ -568,10 +569,10 @@ async fn test_sign_command() -> Result<(), anyhow::Error> { ObjectDigest::random(), ); let gas_price = 1; - let tx_data = TransactionData::new_pay_sui( + let tx_data = TransactionData::new_pay_iota( *sender, vec![gas], - vec![SuiAddress::random_for_testing_only()], + vec![IotaAddress::random_for_testing_only()], vec![10000], gas, gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, @@ -584,7 +585,7 @@ async fn test_sign_command() -> Result<(), anyhow::Error> { KeyToolCommand::Sign { address: KeyIdentity::Address(*sender), data: Base64::encode(bcs::to_bytes(&tx_data)?), - intent: Some(Intent::sui_app(IntentScope::PersonalMessage)), + intent: Some(Intent::iota_app(IntentScope::PersonalMessage)), } .execute(&mut keystore) .await?; diff --git a/crates/sui/src/unit_tests/profiler_tests.rs b/crates/iota/src/unit_tests/profiler_tests.rs similarity index 88% rename from crates/sui/src/unit_tests/profiler_tests.rs rename to crates/iota/src/unit_tests/profiler_tests.rs index 9f199afff1b..567b9a13c13 100644 --- a/crates/sui/src/unit_tests/profiler_tests.rs +++ b/crates/iota/src/unit_tests/profiler_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// This test exists to make sure that the feature gating for all the code under @@ -24,7 +25,7 @@ /// current crate depends on. /// /// Note this crate will always have the feature enabled in testing due to the -/// addition of `sui = { path = ".", features = ["gas-profiler"] }` to our +/// addition of `iota = { path = ".", features = ["gas-profiler"] }` to our /// dev-dependencies. #[cfg(feature = "gas-profiler")] @@ -41,13 +42,13 @@ fn test_macro_shows_feature_enabled() { async fn test_profiler() { use std::fs; - use sui_replay::ReplayToolCommand; + use iota_replay::ReplayToolCommand; use tempfile::tempdir; let output_dir = tempdir().unwrap(); let profile_output = output_dir.path().join("profile.json"); - let testnet_url = "https://fullnode.testnet.sui.io:443".to_string(); + let testnet_url = "https://fullnode.testnet.iota.io:443".to_string(); let tx_digest = "98KxVD14f2JgceKx4X27HaVAA2YGJ3Aazf6Y4tabpHa8".to_string(); let cmd = ReplayToolCommand::ProfileTransaction { @@ -58,7 +59,7 @@ async fn test_profiler() { }; let command_result = - sui_replay::execute_replay_command(Some(testnet_url), false, false, None, cmd).await; + iota_replay::execute_replay_command(Some(testnet_url), false, false, None, cmd).await; assert!(command_result.is_ok()); diff --git a/crates/sui/src/unit_tests/shell_tests.rs b/crates/iota/src/unit_tests/shell_tests.rs similarity index 98% rename from crates/sui/src/unit_tests/shell_tests.rs rename to crates/iota/src/unit_tests/shell_tests.rs index f82f1f3fc9a..14651964d45 100644 --- a/crates/sui/src/unit_tests/shell_tests.rs +++ b/crates/iota/src/unit_tests/shell_tests.rs @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::BTreeMap, env, sync::Arc}; +use iota_types::base_types::ObjectID; use rustyline::{completion::Completer, history::History, Context}; -use sui_types::base_types::ObjectID; use crate::shell::{ split_and_unescape, substitute_env_variables, CacheKey, CommandStructure, CompletionCache, diff --git a/crates/iota/src/unit_tests/validator_tests.rs b/crates/iota/src/unit_tests/validator_tests.rs new file mode 100644 index 00000000000..dc0ac36a9dd --- /dev/null +++ b/crates/iota/src/unit_tests/validator_tests.rs @@ -0,0 +1,71 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::Ok; +use fastcrypto::encoding::{Base64, Encoding}; +use iota_types::{ + base_types::IotaAddress, + crypto::{IotaKeyPair, Signature}, + transaction::{Transaction, TransactionData}, +}; +use shared_crypto::intent::{Intent, IntentMessage}; +use test_cluster::TestClusterBuilder; + +use crate::validator_commands::{ + get_validator_summary, IotaValidatorCommand, IotaValidatorCommandResponse, +}; + +#[tokio::test] +async fn test_print_raw_rgp_txn() -> Result<(), anyhow::Error> { + let test_cluster = TestClusterBuilder::new().build().await; + let keypair: &IotaKeyPair = test_cluster + .swarm + .config() + .validator_configs + .first() + .unwrap() + .account_key_pair + .keypair(); + let validator_address: IotaAddress = IotaAddress::from(&keypair.public()); + let mut context = test_cluster.wallet; + let iota_client = context.get_client().await?; + let (_, summary) = get_validator_summary(&iota_client, validator_address) + .await? + .unwrap(); + let operation_cap_id = summary.operation_cap_id; + + // Execute the command and get the serialized transaction data. + let response = IotaValidatorCommand::DisplayGasPriceUpdateRawTxn { + sender_address: validator_address, + new_gas_price: 42, + operation_cap_id, + gas_budget: None, + } + .execute(&mut context) + .await?; + let IotaValidatorCommandResponse::DisplayGasPriceUpdateRawTxn { + data, + serialized_data, + } = response + else { + panic!("Expected DisplayGasPriceUpdateRawTxn"); + }; + + // Construct the signed transaction and execute it. + let deserialized_data = + bcs::from_bytes::(&Base64::decode(&serialized_data).unwrap())?; + let signature = Signature::new_secure( + &IntentMessage::new(Intent::iota_transaction(), deserialized_data), + keypair, + ); + let txn = Transaction::from_data(data, vec![signature]); + context.execute_transaction_must_succeed(txn).await; + let (_, summary) = get_validator_summary(&iota_client, validator_address) + .await? + .unwrap(); + + // Check that the gas price is updated correctly. + assert_eq!(summary.next_epoch_gas_price, 42); + Ok(()) +} diff --git a/crates/sui/src/validator_commands.rs b/crates/iota/src/validator_commands.rs similarity index 82% rename from crates/sui/src/validator_commands.rs rename to crates/iota/src/validator_commands.rs index 62dedc1b7d2..4ac98852d66 100644 --- a/crates/sui/src/validator_commands.rs +++ b/crates/iota/src/validator_commands.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -15,14 +16,11 @@ use fastcrypto::{ encoding::{Base64, Encoding}, traits::{KeyPair, ToFromBytes}, }; -use move_core_types::ident_str; -use serde::Serialize; -use shared_crypto::intent::{Intent, IntentMessage, IntentScope}; -use sui_genesis_builder::validator_info::GenesisValidatorInfo; -use sui_json_rpc_types::{ - SuiObjectDataOptions, SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, +use iota_genesis_builder::validator_info::GenesisValidatorInfo; +use iota_json_rpc_types::{ + IotaObjectDataOptions, IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, }; -use sui_keys::{ +use iota_keys::{ key_derive::generate_new_key, keypair_file::{ read_authority_keypair_from_file, read_keypair_from_file, read_network_keypair_from_file, @@ -30,23 +28,26 @@ use sui_keys::{ }, keystore::AccountKeystore, }; -use sui_sdk::{wallet_context::WalletContext, SuiClient}; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, +use iota_sdk::{wallet_context::WalletContext, IotaClient}; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef}, crypto::{ generate_proof_of_possession, get_authority_key_pair, AuthorityKeyPair, AuthorityPublicKey, - AuthorityPublicKeyBytes, NetworkKeyPair, NetworkPublicKey, Signable, SignatureScheme, - SuiKeyPair, DEFAULT_EPOCH_ID, + AuthorityPublicKeyBytes, IotaKeyPair, NetworkKeyPair, NetworkPublicKey, Signable, + SignatureScheme, DEFAULT_EPOCH_ID, + }, + iota_system_state::{ + iota_system_state_inner_v1::{UnverifiedValidatorOperationCapV1, ValidatorV1}, + iota_system_state_summary::{IotaSystemStateSummary, IotaValidatorSummary}, }, multiaddr::Multiaddr, object::Owner, - sui_system_state::{ - sui_system_state_inner_v1::{UnverifiedValidatorOperationCapV1, ValidatorV1}, - sui_system_state_summary::{SuiSystemStateSummary, SuiValidatorSummary}, - }, transaction::{CallArg, ObjectArg, Transaction, TransactionData}, - SUI_SYSTEM_PACKAGE_ID, + IOTA_SYSTEM_PACKAGE_ID, }; +use move_core_types::ident_str; +use serde::Serialize; +use shared_crypto::intent::{Intent, IntentMessage, IntentScope}; use tap::tap::TapOptional; use crate::fire_drill::get_gas_obj_ref; @@ -55,11 +56,11 @@ use crate::fire_drill::get_gas_obj_ref; #[cfg(test)] mod validator_tests; -const DEFAULT_GAS_BUDGET: u64 = 200_000_000; // 0.2 SUI +const DEFAULT_GAS_BUDGET: u64 = 200_000_000; // 0.2 IOTA #[derive(Parser)] #[clap(rename_all = "kebab-case")] -pub enum SuiValidatorCommand { +pub enum IotaValidatorCommand { #[clap(name = "make-validator-info")] MakeValidatorInfo { name: String, @@ -91,7 +92,7 @@ pub enum SuiValidatorCommand { #[clap(name = "display-metadata")] DisplayMetadata { #[clap(name = "validator-address")] - validator_address: Option, + validator_address: Option, #[clap(name = "json", long)] json: Option, }, @@ -127,9 +128,9 @@ pub enum SuiValidatorCommand { /// by using the `display-metadata` subcommand. #[clap(name = "operation-cap-id", long)] operation_cap_id: Option, - /// The Sui Address of the validator is being reported or un-reported + /// The Iota Address of the validator is being reported or un-reported #[clap(name = "reportee-address")] - reportee_address: SuiAddress, + reportee_address: IotaAddress, /// If true, undo an existing report. #[clap(name = "undo-report", long)] undo_report: Option, @@ -144,7 +145,7 @@ pub enum SuiValidatorCommand { SerializePayloadForPoP { /// Authority account address encoded in hex with 0x prefix. #[clap(name = "account-address", long)] - account_address: SuiAddress, + account_address: IotaAddress, /// Authority protocol public key encoded in hex. #[clap(name = "protocol-public-key", long)] protocol_public_key: AuthorityPublicKeyBytes, @@ -154,7 +155,7 @@ pub enum SuiValidatorCommand { DisplayGasPriceUpdateRawTxn { /// Address of the transaction sender. #[clap(name = "sender-address", long)] - sender_address: SuiAddress, + sender_address: IotaAddress, /// Object ID of a validator's OperationCap, used for setting gas price /// and reportng validators. #[clap(name = "operation-cap-id", long)] @@ -170,15 +171,15 @@ pub enum SuiValidatorCommand { #[derive(Serialize)] #[serde(untagged)] -pub enum SuiValidatorCommandResponse { +pub enum IotaValidatorCommandResponse { MakeValidatorInfo, DisplayMetadata, - BecomeCandidate(SuiTransactionBlockResponse), - JoinCommittee(SuiTransactionBlockResponse), - LeaveCommittee(SuiTransactionBlockResponse), - UpdateMetadata(SuiTransactionBlockResponse), - UpdateGasPrice(SuiTransactionBlockResponse), - ReportValidator(SuiTransactionBlockResponse), + BecomeCandidate(IotaTransactionBlockResponse), + JoinCommittee(IotaTransactionBlockResponse), + LeaveCommittee(IotaTransactionBlockResponse), + UpdateMetadata(IotaTransactionBlockResponse), + UpdateGasPrice(IotaTransactionBlockResponse), + ReportValidator(IotaTransactionBlockResponse), SerializedPayload(String), DisplayGasPriceUpdateRawTxn { data: TransactionData, @@ -189,7 +190,7 @@ pub enum SuiValidatorCommandResponse { fn make_key_files( file_name: PathBuf, is_protocol_key: bool, - key: Option, + key: Option, ) -> anyhow::Result<()> { if file_name.exists() { println!("Use existing {:?} key file.", file_name); @@ -202,7 +203,7 @@ fn make_key_files( let kp = match key { Some(key) => { println!( - "Generated new key file {:?} based on sui.keystore file.", + "Generated new key file {:?} based on iota.keystore file.", file_name ); key @@ -218,15 +219,15 @@ fn make_key_files( Ok(()) } -impl SuiValidatorCommand { +impl IotaValidatorCommand { pub async fn execute( self, context: &mut WalletContext, - ) -> Result { - let sui_address = context.active_address()?; + ) -> Result { + let iota_address = context.active_address()?; let ret = Ok(match self { - SuiValidatorCommand::MakeValidatorInfo { + IotaValidatorCommand::MakeValidatorInfo { name, description, image_url, @@ -236,8 +237,8 @@ impl SuiValidatorCommand { } => { let dir = std::env::current_dir()?; let protocol_key_file_name = dir.join("protocol.key"); - let account_key = match context.config.keystore.get_key(&sui_address)? { - SuiKeyPair::Ed25519(account_key) => SuiKeyPair::Ed25519(account_key.copy()), + let account_key = match context.config.keystore.get_key(&iota_address)? { + IotaKeyPair::Ed25519(account_key) => IotaKeyPair::Ed25519(account_key.copy()), _ => panic!( "Other account key types supported yet, please use Ed25519 keys for now." ), @@ -252,7 +253,7 @@ impl SuiValidatorCommand { let keypair: AuthorityKeyPair = read_authority_keypair_from_file(protocol_key_file_name)?; - let account_keypair: SuiKeyPair = read_keypair_from_file(account_key_file_name)?; + let account_keypair: IotaKeyPair = read_keypair_from_file(account_key_file_name)?; let worker_keypair: NetworkKeyPair = read_network_keypair_from_file(worker_key_file_name)?; let network_keypair: NetworkKeyPair = @@ -260,14 +261,14 @@ impl SuiValidatorCommand { let pop = generate_proof_of_possession(&keypair, (&account_keypair.public()).into()); let validator_info = GenesisValidatorInfo { - info: sui_genesis_builder::validator_info::ValidatorInfo { + info: iota_genesis_builder::validator_info::ValidatorInfo { name, protocol_key: keypair.public().into(), worker_key: worker_keypair.public().clone(), - account_address: SuiAddress::from(&account_keypair.public()), + account_address: IotaAddress::from(&account_keypair.public()), network_key: network_keypair.public().clone(), gas_price, - commission_rate: sui_config::node::DEFAULT_COMMISSION_RATE, + commission_rate: iota_config::node::DEFAULT_COMMISSION_RATE, network_address: Multiaddr::try_from(format!( "/dns/{}/tcp/8080/http", host_name @@ -295,9 +296,9 @@ impl SuiValidatorCommand { "Generated validator info file: {:?}.", validator_info_file_name ); - SuiValidatorCommandResponse::MakeValidatorInfo + IotaValidatorCommandResponse::MakeValidatorInfo } - SuiValidatorCommand::BecomeCandidate { file, gas_budget } => { + IotaValidatorCommand::BecomeCandidate { file, gas_budget } => { let gas_budget = gas_budget.unwrap_or(DEFAULT_GAS_BUDGET); let validator_info_bytes = fs::read(file)?; // Note: we should probably rename the struct or evolve it accordingly. @@ -343,47 +344,47 @@ impl SuiValidatorCommand { ]; let response = call_0x5(context, "request_add_validator_candidate", args, gas_budget).await?; - SuiValidatorCommandResponse::BecomeCandidate(response) + IotaValidatorCommandResponse::BecomeCandidate(response) } - SuiValidatorCommand::JoinCommittee { gas_budget } => { + IotaValidatorCommand::JoinCommittee { gas_budget } => { let gas_budget = gas_budget.unwrap_or(DEFAULT_GAS_BUDGET); let response = call_0x5(context, "request_add_validator", vec![], gas_budget).await?; - SuiValidatorCommandResponse::JoinCommittee(response) + IotaValidatorCommandResponse::JoinCommittee(response) } - SuiValidatorCommand::LeaveCommittee { gas_budget } => { + IotaValidatorCommand::LeaveCommittee { gas_budget } => { // Only an active validator can leave committee. let _status = check_status(context, HashSet::from([ValidatorStatus::Active])).await?; let gas_budget = gas_budget.unwrap_or(DEFAULT_GAS_BUDGET); let response = call_0x5(context, "request_remove_validator", vec![], gas_budget).await?; - SuiValidatorCommandResponse::LeaveCommittee(response) + IotaValidatorCommandResponse::LeaveCommittee(response) } - SuiValidatorCommand::DisplayMetadata { + IotaValidatorCommand::DisplayMetadata { validator_address, json, } => { let validator_address = validator_address.unwrap_or(context.active_address()?); // Default display with json serialization for better UX. - let sui_client = context.get_client().await?; - display_metadata(&sui_client, validator_address, json.unwrap_or(true)).await?; - SuiValidatorCommandResponse::DisplayMetadata + let iota_client = context.get_client().await?; + display_metadata(&iota_client, validator_address, json.unwrap_or(true)).await?; + IotaValidatorCommandResponse::DisplayMetadata } - SuiValidatorCommand::UpdateMetadata { + IotaValidatorCommand::UpdateMetadata { metadata, gas_budget, } => { let gas_budget = gas_budget.unwrap_or(DEFAULT_GAS_BUDGET); let resp = update_metadata(context, metadata, gas_budget).await?; - SuiValidatorCommandResponse::UpdateMetadata(resp) + IotaValidatorCommandResponse::UpdateMetadata(resp) } - SuiValidatorCommand::UpdateGasPrice { + IotaValidatorCommand::UpdateGasPrice { operation_cap_id, gas_price, gas_budget, @@ -391,10 +392,10 @@ impl SuiValidatorCommand { let gas_budget = gas_budget.unwrap_or(DEFAULT_GAS_BUDGET); let resp = update_gas_price(context, operation_cap_id, gas_price, gas_budget).await?; - SuiValidatorCommandResponse::UpdateGasPrice(resp) + IotaValidatorCommandResponse::UpdateGasPrice(resp) } - SuiValidatorCommand::ReportValidator { + IotaValidatorCommand::ReportValidator { operation_cap_id, reportee_address, undo_report, @@ -410,10 +411,10 @@ impl SuiValidatorCommand { gas_budget, ) .await?; - SuiValidatorCommandResponse::ReportValidator(resp) + IotaValidatorCommandResponse::ReportValidator(resp) } - SuiValidatorCommand::SerializePayloadForPoP { + IotaValidatorCommand::SerializePayloadForPoP { account_address, protocol_public_key, } => { @@ -421,15 +422,15 @@ impl SuiValidatorCommand { msg.extend_from_slice(protocol_public_key.as_bytes()); msg.extend_from_slice(account_address.as_ref()); let mut intent_msg_bytes = bcs::to_bytes(&IntentMessage::new( - Intent::sui_app(IntentScope::ProofOfPossession), + Intent::iota_app(IntentScope::ProofOfPossession), msg, )) .expect("Message serialization should not fail"); DEFAULT_EPOCH_ID.write(&mut intent_msg_bytes); - SuiValidatorCommandResponse::SerializedPayload(Base64::encode(&intent_msg_bytes)) + IotaValidatorCommandResponse::SerializedPayload(Base64::encode(&intent_msg_bytes)) } - SuiValidatorCommand::DisplayGasPriceUpdateRawTxn { + IotaValidatorCommand::DisplayGasPriceUpdateRawTxn { sender_address, operation_cap_id, new_gas_price, @@ -452,7 +453,7 @@ impl SuiValidatorCommand { ) .await?; let serialized_data = Base64::encode(bcs::to_bytes(&data)?); - SuiValidatorCommandResponse::DisplayGasPriceUpdateRawTxn { + IotaValidatorCommandResponse::DisplayGasPriceUpdateRawTxn { data, serialized_data, } @@ -465,21 +466,21 @@ impl SuiValidatorCommand { async fn get_cap_object_ref( context: &mut WalletContext, operation_cap_id: Option, -) -> Result<(ValidatorStatus, SuiValidatorSummary, ObjectRef)> { - let sui_client = context.get_client().await?; +) -> Result<(ValidatorStatus, IotaValidatorSummary, ObjectRef)> { + let iota_client = context.get_client().await?; if let Some(operation_cap_id) = operation_cap_id { let (status, summary) = - get_validator_summary_from_cap_id(&sui_client, operation_cap_id).await?; - let cap_obj_ref = sui_client + get_validator_summary_from_cap_id(&iota_client, operation_cap_id).await?; + let cap_obj_ref = iota_client .read_api() .get_object_with_options( summary.operation_cap_id, - SuiObjectDataOptions::default().with_owner(), + IotaObjectDataOptions::default().with_owner(), ) .await? .object_ref_if_exists() .ok_or_else(|| anyhow!("OperationCap {} does not exist", operation_cap_id))?; - Ok::<(ValidatorStatus, SuiValidatorSummary, ObjectRef), anyhow::Error>(( + Ok::<(ValidatorStatus, IotaValidatorSummary, ObjectRef), anyhow::Error>(( status, summary, cap_obj_ref, @@ -487,16 +488,16 @@ async fn get_cap_object_ref( } else { // Sender is Reporter Validator itself. let validator_address = context.active_address()?; - let (status, summary) = get_validator_summary(&sui_client, validator_address) + let (status, summary) = get_validator_summary(&iota_client, validator_address) .await? .ok_or_else(|| anyhow::anyhow!("{} is not a validator.", validator_address))?; // TODO we should allow validator to perform this operation even though the Cap // is not at hand. But for now we need to make sure the cap is owned by // the sender. let cap_object_id = summary.operation_cap_id; - let resp = sui_client + let resp = iota_client .read_api() - .get_object_with_options(cap_object_id, SuiObjectDataOptions::default().with_owner()) + .get_object_with_options(cap_object_id, IotaObjectDataOptions::default().with_owner()) .await .map_err(|e| anyhow!(e))?; // Safe to unwrap as we ask with `with_owner`. @@ -521,7 +522,7 @@ async fn update_gas_price( operation_cap_id: Option, gas_price: u64, gas_budget: u64, -) -> Result { +) -> Result { let (_status, _summary, cap_obj_ref) = get_cap_object_ref(context, operation_cap_id).await?; // TODO: Only active/pending validators can set gas price. @@ -535,14 +536,14 @@ async fn update_gas_price( async fn report_validator( context: &mut WalletContext, - reportee_address: SuiAddress, + reportee_address: IotaAddress, operation_cap_id: Option, undo_report: bool, gas_budget: u64, -) -> Result { +) -> Result { let (status, summary, cap_obj_ref) = get_cap_object_ref(context, operation_cap_id).await?; - let validator_address = summary.sui_address; + let validator_address = summary.iota_address; // Only active validators can report/un-report. if !matches!(status, ValidatorStatus::Active) { anyhow::bail!( @@ -564,12 +565,15 @@ async fn report_validator( } async fn get_validator_summary_from_cap_id( - client: &SuiClient, + client: &IotaClient, operation_cap_id: ObjectID, -) -> anyhow::Result<(ValidatorStatus, SuiValidatorSummary)> { +) -> anyhow::Result<(ValidatorStatus, IotaValidatorSummary)> { let resp = client .read_api() - .get_object_with_options(operation_cap_id, SuiObjectDataOptions::default().with_bcs()) + .get_object_with_options( + operation_cap_id, + IotaObjectDataOptions::default().with_bcs(), + ) .await?; let bcs = resp.move_object_bcs().ok_or_else(|| { anyhow::anyhow!( @@ -600,24 +604,24 @@ async fn get_validator_summary_from_cap_id( async fn construct_unsigned_0x5_txn( context: &mut WalletContext, - sender: SuiAddress, + sender: IotaAddress, function: &'static str, call_args: Vec, gas_budget: u64, ) -> anyhow::Result { - let sui_client = context.get_client().await?; - let mut args = vec![CallArg::SUI_SYSTEM_MUT]; + let iota_client = context.get_client().await?; + let mut args = vec![CallArg::IOTA_SYSTEM_MUT]; args.extend(call_args); - let rgp = sui_client + let rgp = iota_client .governance_api() .get_reference_gas_price() .await?; - let gas_obj_ref = get_gas_obj_ref(sender, &sui_client, gas_budget).await?; + let gas_obj_ref = get_gas_obj_ref(sender, &iota_client, gas_budget).await?; TransactionData::new_move_call( sender, - SUI_SYSTEM_PACKAGE_ID, - ident_str!("sui_system").to_owned(), + IOTA_SYSTEM_PACKAGE_ID, + ident_str!("iota_system").to_owned(), ident_str!(function).to_owned(), vec![], gas_obj_ref, @@ -632,7 +636,7 @@ async fn call_0x5( function: &'static str, call_args: Vec, gas_budget: u64, -) -> anyhow::Result { +) -> anyhow::Result { let sender = context.active_address()?; let tx_data = construct_unsigned_0x5_txn(context, sender, function, call_args, gas_budget).await?; @@ -640,50 +644,50 @@ async fn call_0x5( context .config .keystore - .sign_secure(&sender, &tx_data, Intent::sui_transaction())?; + .sign_secure(&sender, &tx_data, Intent::iota_transaction())?; let transaction = Transaction::from_data(tx_data, vec![signature]); - let sui_client = context.get_client().await?; - sui_client + let iota_client = context.get_client().await?; + iota_client .quorum_driver_api() .execute_transaction_block( transaction, - SuiTransactionBlockResponseOptions::new() + IotaTransactionBlockResponseOptions::new() .with_input() .with_effects(), - Some(sui_types::quorum_driver_types::ExecuteTransactionRequestType::WaitForLocalExecution), + Some(iota_types::quorum_driver_types::ExecuteTransactionRequestType::WaitForLocalExecution), ) .await .map_err(|err| anyhow::anyhow!(err.to_string())) } -impl Display for SuiValidatorCommandResponse { +impl Display for IotaValidatorCommandResponse { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut writer = String::new(); match self { - SuiValidatorCommandResponse::MakeValidatorInfo => {} - SuiValidatorCommandResponse::DisplayMetadata => {} - SuiValidatorCommandResponse::BecomeCandidate(response) => { + IotaValidatorCommandResponse::MakeValidatorInfo => {} + IotaValidatorCommandResponse::DisplayMetadata => {} + IotaValidatorCommandResponse::BecomeCandidate(response) => { write!(writer, "{}", write_transaction_response(response)?)?; } - SuiValidatorCommandResponse::JoinCommittee(response) => { + IotaValidatorCommandResponse::JoinCommittee(response) => { write!(writer, "{}", write_transaction_response(response)?)?; } - SuiValidatorCommandResponse::LeaveCommittee(response) => { + IotaValidatorCommandResponse::LeaveCommittee(response) => { write!(writer, "{}", write_transaction_response(response)?)?; } - SuiValidatorCommandResponse::UpdateMetadata(response) => { + IotaValidatorCommandResponse::UpdateMetadata(response) => { write!(writer, "{}", write_transaction_response(response)?)?; } - SuiValidatorCommandResponse::UpdateGasPrice(response) => { + IotaValidatorCommandResponse::UpdateGasPrice(response) => { write!(writer, "{}", write_transaction_response(response)?)?; } - SuiValidatorCommandResponse::ReportValidator(response) => { + IotaValidatorCommandResponse::ReportValidator(response) => { write!(writer, "{}", write_transaction_response(response)?)?; } - SuiValidatorCommandResponse::SerializedPayload(response) => { + IotaValidatorCommandResponse::SerializedPayload(response) => { write!(writer, "Serialized payload: {}", response)?; } - SuiValidatorCommandResponse::DisplayGasPriceUpdateRawTxn { + IotaValidatorCommandResponse::DisplayGasPriceUpdateRawTxn { data, serialized_data, } => { @@ -699,7 +703,7 @@ impl Display for SuiValidatorCommandResponse { } pub fn write_transaction_response( - response: &SuiTransactionBlockResponse, + response: &IotaTransactionBlockResponse, ) -> Result { // we requested with for full_content, so the following content should be // available. @@ -720,7 +724,7 @@ pub fn write_transaction_response( Ok(writer) } -impl Debug for SuiValidatorCommandResponse { +impl Debug for IotaValidatorCommandResponse { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let string = serde_json::to_string_pretty(self); let s = match string { @@ -731,12 +735,12 @@ impl Debug for SuiValidatorCommandResponse { } } -impl SuiValidatorCommandResponse { +impl IotaValidatorCommandResponse { pub fn print(&self, pretty: bool) { match self { // Don't print empty responses - SuiValidatorCommandResponse::MakeValidatorInfo - | SuiValidatorCommandResponse::DisplayMetadata => {} + IotaValidatorCommandResponse::MakeValidatorInfo + | IotaValidatorCommandResponse::DisplayMetadata => {} other => { let line = if pretty { format!("{other}") @@ -759,21 +763,21 @@ pub enum ValidatorStatus { } pub async fn get_validator_summary( - client: &SuiClient, - validator_address: SuiAddress, -) -> anyhow::Result> { - let SuiSystemStateSummary { + client: &IotaClient, + validator_address: IotaAddress, +) -> anyhow::Result> { + let IotaSystemStateSummary { active_validators, pending_active_validators_id, .. } = client .governance_api() - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await?; let mut status = None; let mut active_validators = active_validators .into_iter() - .map(|s| (s.sui_address, s)) + .map(|s| (s.iota_address, s)) .collect::>(); let validator_info = if active_validators.contains_key(&validator_address) { status = Some(ValidatorStatus::Active); @@ -782,7 +786,7 @@ pub async fn get_validator_summary( // Check panding validators get_pending_candidate_summary(validator_address, client, pending_active_validators_id) .await? - .map(|v| v.into_sui_validator_summary()) + .map(|v| v.into_iota_validator_summary()) .tap_some(|_s| status = Some(ValidatorStatus::Pending)) // TODO also check candidate and inactive valdiators @@ -796,8 +800,8 @@ pub async fn get_validator_summary( } async fn display_metadata( - client: &SuiClient, - validator_address: SuiAddress, + client: &IotaClient, + validator_address: IotaAddress, json: bool, ) -> anyhow::Result<()> { match get_validator_summary(client, validator_address).await? { @@ -818,11 +822,11 @@ async fn display_metadata( } async fn get_pending_candidate_summary( - validator_address: SuiAddress, - sui_client: &SuiClient, + validator_address: IotaAddress, + iota_client: &IotaClient, pending_active_validators_id: ObjectID, ) -> anyhow::Result> { - let pending_validators = sui_client + let pending_validators = iota_client .read_api() .get_dynamic_fields(pending_active_validators_id, None, None) .await? @@ -830,11 +834,11 @@ async fn get_pending_candidate_summary( .into_iter() .map(|dyi| dyi.object_id) .collect::>(); - let resps = sui_client + let resps = iota_client .read_api() .multi_get_object_with_options( pending_validators, - SuiObjectDataOptions::default().with_bcs(), + IotaObjectDataOptions::default().with_bcs(), ) .await?; for resp in resps { @@ -854,7 +858,7 @@ async fn get_pending_candidate_summary( e, ) })?; - if val.verified_metadata().sui_address == validator_address { + if val.verified_metadata().iota_address == validator_address { return Ok(Some(val)); } } @@ -902,7 +906,7 @@ async fn update_metadata( context: &mut WalletContext, metadata: MetadataUpdate, gas_budget: u64, -) -> anyhow::Result { +) -> anyhow::Result { use ValidatorStatus::*; match metadata { MetadataUpdate::Name { name } => { @@ -1004,10 +1008,10 @@ async fn update_metadata( } MetadataUpdate::ProtocolPubKey { file } => { let _status = check_status(context, HashSet::from([Pending, Active])).await?; - let sui_address = context.active_address()?; + let iota_address = context.active_address()?; let protocol_key_pair: AuthorityKeyPair = read_authority_keypair_from_file(file)?; let protocol_pub_key: AuthorityPublicKey = protocol_key_pair.public().clone(); - let pop = generate_proof_of_possession(&protocol_key_pair, sui_address); + let pop = generate_proof_of_possession(&protocol_key_pair, iota_address); let args = vec![ CallArg::Pure( bcs::to_bytes(&AuthorityPublicKeyBytes::from_bytes( @@ -1032,9 +1036,9 @@ async fn check_status( context: &mut WalletContext, allowed_status: HashSet, ) -> Result { - let sui_client = context.get_client().await?; + let iota_client = context.get_client().await?; let validator_address = context.active_address()?; - let summary = get_validator_summary(&sui_client, validator_address).await?; + let summary = get_validator_summary(&iota_client, validator_address).await?; if summary.is_none() { bail!("{validator_address} is not a Validator."); } diff --git a/crates/sui/src/zklogin_commands_util.rs b/crates/iota/src/zklogin_commands_util.rs similarity index 83% rename from crates/sui/src/zklogin_commands_util.rs rename to crates/iota/src/zklogin_commands_util.rs index 9bf79070411..f3236a20241 100644 --- a/crates/sui/src/zklogin_commands_util.rs +++ b/crates/iota/src/zklogin_commands_util.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{io, io::Write, thread::sleep, time::Duration}; @@ -14,23 +15,23 @@ use fastcrypto_zkp::bn254::{ utils::{gen_address_seed, get_proof, get_salt, get_zk_login_address}, zk_login::ZkLoginInputs, }; -use rand::{rngs::StdRng, SeedableRng}; -use regex::Regex; -use reqwest::Client; -use serde_json::json; -use shared_crypto::intent::Intent; -use sui_json_rpc_types::SuiTransactionBlockResponseOptions; -use sui_keys::keystore::{AccountKeystore, Keystore}; -use sui_sdk::SuiClientBuilder; -use sui_types::{ - base_types::SuiAddress, +use iota_json_rpc_types::IotaTransactionBlockResponseOptions; +use iota_keys::keystore::{AccountKeystore, Keystore}; +use iota_sdk::IotaClientBuilder; +use iota_types::{ + base_types::IotaAddress, committee::EpochId, - crypto::{PublicKey, SuiKeyPair}, + crypto::{IotaKeyPair, PublicKey}, multisig::{MultiSig, MultiSigPublicKey}, signature::GenericSignature, transaction::Transaction, zk_login_authenticator::ZkLoginAuthenticator, }; +use rand::{rngs::StdRng, SeedableRng}; +use regex::Regex; +use reqwest::Client; +use serde_json::json; +use shared_crypto::intent::Intent; /// Read a line from stdin, parse the id_token field and return. pub fn read_cli_line() -> Result { @@ -50,7 +51,7 @@ pub fn read_cli_line() -> Result { /// A util function to request gas token from faucet for the given address. pub(crate) async fn request_tokens_from_faucet( - address: SuiAddress, + address: IotaAddress, gas_url: &str, ) -> Result<(), anyhow::Error> { let client = Client::new(); @@ -74,7 +75,7 @@ pub async fn perform_zk_login_test_tx( max_epoch: EpochId, jwt_randomness: &str, kp_bigint: &str, - ephemeral_key_identifier: SuiAddress, + ephemeral_key_identifier: IotaAddress, keystore: &mut Keystore, network: &str, test_multisig: bool, /* if true, put zklogin in a multisig address with another traditional @@ -104,7 +105,7 @@ pub async fn perform_zk_login_test_tx( let address_seed = gen_address_seed(&user_salt, "sub", &sub, &aud)?; let zk_login_inputs = ZkLoginInputs::from_reader(reader, &address_seed)?; - let skp1 = SuiKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([1; 32]))); + let skp1 = IotaKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([1; 32]))); let multisig_pk = MultiSigPublicKey::new( vec![ PublicKey::from_zklogin_inputs(&zk_login_inputs)?, @@ -117,9 +118,9 @@ pub async fn perform_zk_login_test_tx( let sender = if test_multisig { keystore.add_key(None, skp1)?; println!("Use multisig address as sender"); - SuiAddress::from(&multisig_pk) + IotaAddress::from(&multisig_pk) } else { - SuiAddress::from_bytes(get_zk_login_address( + IotaAddress::from_bytes(get_zk_login_address( zk_login_inputs.get_address_seed(), zk_login_inputs.get_iss(), )?)? @@ -127,26 +128,26 @@ pub async fn perform_zk_login_test_tx( println!("Sender: {:?}", sender); // Request some coin from faucet and build a test transaction. - let sui = SuiClientBuilder::default().build(fullnode_url).await?; + let iota = IotaClientBuilder::default().build(fullnode_url).await?; request_tokens_from_faucet(sender, gas_url).await?; sleep(Duration::from_secs(10)); - let Some(coin) = sui + let Some(coin) = iota .coin_read_api() .get_coins(sender, None, None, None) .await? .next_cursor else { - panic!("Faucet did not work correctly and the provided Sui address has no coins") + panic!("Faucet did not work correctly and the provided Iota address has no coins") }; - let txb_res = sui + let txb_res = iota .transaction_builder() .transfer_object( sender, coin, None, 5000000, - SuiAddress::ZERO, // as a demo, send to a dummy address + IotaAddress::ZERO, // as a demo, send to a dummy address ) .await?; println!( @@ -159,14 +160,14 @@ pub async fn perform_zk_login_test_tx( GenericSignature::Signature(keystore.sign_secure( &ephemeral_key_identifier, &txb_res, - Intent::sui_transaction(), + Intent::iota_transaction(), )?) } else { // Sign transaction with the ephemeral key let signature = keystore.sign_secure( &ephemeral_key_identifier, &txb_res, - Intent::sui_transaction(), + Intent::iota_transaction(), )?; GenericSignature::from(ZkLoginAuthenticator::new( @@ -179,11 +180,11 @@ pub async fn perform_zk_login_test_tx( let multisig = GenericSignature::MultiSig(MultiSig::combine(vec![sig], multisig_pk)?); println!("Signature Serialized: {:?}", multisig.encode_base64()); - let transaction_response = sui + let transaction_response = iota .quorum_driver_api() .execute_transaction_block( Transaction::from_generic_sig_data(txb_res, vec![multisig]), - SuiTransactionBlockResponseOptions::full_content(), + IotaTransactionBlockResponseOptions::full_content(), None, ) .await?; @@ -193,8 +194,8 @@ pub async fn perform_zk_login_test_tx( fn get_config(network: &str) -> (&str, &str) { match network { "devnet" => ( - "https://faucet.devnet.sui.io/gas", - "https://rpc.devnet.sui.io:443", + "https://faucet.devnet.iota.io/gas", + "https://rpc.devnet.iota.io:443", ), "localnet" => ("http://127.0.0.1:9123/gas", "http://127.0.0.1:9000"), _ => panic!("Invalid network"), diff --git a/crates/sui/tests/cli_tests.rs b/crates/iota/tests/cli_tests.rs similarity index 84% rename from crates/sui/tests/cli_tests.rs rename to crates/iota/tests/cli_tests.rs index eb228e2e26b..a26227c70d2 100644 --- a/crates/sui/tests/cli_tests.rs +++ b/crates/iota/tests/cli_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[cfg(not(target_os = "windows"))] @@ -11,39 +12,37 @@ use std::{ }; use expect_test::expect; -use move_package::BuildConfig as MoveBuildConfig; -use serde_json::json; -use sui::{ - client_commands::{SuiClientCommandResult, SuiClientCommands, SwitchResponse}, +use iota::{ + client_commands::{IotaClientCommandResult, IotaClientCommands, SwitchResponse}, + iota_commands::IotaCommand, key_identity::{get_identity_address, KeyIdentity}, - sui_commands::SuiCommand, }; -use sui_config::{ - PersistedConfig, SUI_CLIENT_CONFIG, SUI_FULLNODE_CONFIG, SUI_GENESIS_FILENAME, - SUI_KEYSTORE_ALIASES_FILENAME, SUI_KEYSTORE_FILENAME, SUI_NETWORK_CONFIG, +use iota_config::{ + PersistedConfig, IOTA_CLIENT_CONFIG, IOTA_FULLNODE_CONFIG, IOTA_GENESIS_FILENAME, + IOTA_KEYSTORE_ALIASES_FILENAME, IOTA_KEYSTORE_FILENAME, IOTA_NETWORK_CONFIG, }; -use sui_json::SuiJsonValue; -use sui_json_rpc_types::{ - OwnedObjectRef, SuiObjectData, SuiObjectDataFilter, SuiObjectDataOptions, SuiObjectResponse, - SuiObjectResponseQuery, SuiTransactionBlockDataAPI, SuiTransactionBlockEffects, - SuiTransactionBlockEffectsAPI, +use iota_json::IotaJsonValue; +use iota_json_rpc_types::{ + IotaObjectData, IotaObjectDataFilter, IotaObjectDataOptions, IotaObjectResponse, + IotaObjectResponseQuery, IotaTransactionBlockDataAPI, IotaTransactionBlockEffects, + IotaTransactionBlockEffectsAPI, OwnedObjectRef, }; -use sui_keys::keystore::AccountKeystore; -use sui_macros::sim_test; -use sui_move_build::{BuildConfig, SuiPackageHooks}; -use sui_sdk::{sui_client_config::SuiClientConfig, wallet_context::WalletContext}; -use sui_swarm_config::{ +use iota_keys::keystore::AccountKeystore; +use iota_macros::sim_test; +use iota_move_build::{BuildConfig, IotaPackageHooks}; +use iota_sdk::{iota_client_config::IotaClientConfig, wallet_context::WalletContext}; +use iota_swarm_config::{ genesis_config::{AccountConfig, GenesisConfig}, network_config::NetworkConfig, }; -use sui_test_transaction_builder::batch_make_transfer_transactions; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, +use iota_test_transaction_builder::batch_make_transfer_transactions; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, crypto::{ - get_key_pair, Ed25519SuiSignature, Secp256k1SuiSignature, SignatureScheme, SuiKeyPair, - SuiSignatureInner, + get_key_pair, Ed25519IotaSignature, IotaKeyPair, IotaSignatureInner, + Secp256k1IotaSignature, SignatureScheme, }, - error::SuiObjectResponseError, + error::IotaObjectResponseError, gas_coin::GasCoin, object::Owner, transaction::{ @@ -52,6 +51,8 @@ use sui_types::{ TEST_ONLY_GAS_UNIT_FOR_TRANSFER, }, }; +use move_package::BuildConfig as MoveBuildConfig; +use serde_json::json; use test_cluster::TestClusterBuilder; use tokio::time::sleep; @@ -61,10 +62,10 @@ const TEST_DATA_DIR: &str = "tests/data/"; async fn test_genesis() -> Result<(), anyhow::Error> { let temp_dir = tempfile::tempdir()?; let working_dir = temp_dir.path(); - let config = working_dir.join(SUI_NETWORK_CONFIG); + let config = working_dir.join(IOTA_NETWORK_CONFIG); // Start network without authorities - let start = SuiCommand::Start { + let start = IotaCommand::Start { config: Some(config), no_full_node: false, } @@ -72,7 +73,7 @@ async fn test_genesis() -> Result<(), anyhow::Error> { .await; assert!(matches!(start, Err(..))); // Genesis - SuiCommand::Genesis { + IotaCommand::Genesis { working_dir: Some(working_dir.to_path_buf()), write_config: None, force: false, @@ -90,28 +91,28 @@ async fn test_genesis() -> Result<(), anyhow::Error> { .collect::>(); assert_eq!(10, files.len()); - assert!(files.contains(&SUI_CLIENT_CONFIG.to_string())); - assert!(files.contains(&SUI_NETWORK_CONFIG.to_string())); - assert!(files.contains(&SUI_FULLNODE_CONFIG.to_string())); - assert!(files.contains(&SUI_GENESIS_FILENAME.to_string())); - assert!(files.contains(&SUI_KEYSTORE_FILENAME.to_string())); - assert!(files.contains(&SUI_KEYSTORE_ALIASES_FILENAME.to_string())); + assert!(files.contains(&IOTA_CLIENT_CONFIG.to_string())); + assert!(files.contains(&IOTA_NETWORK_CONFIG.to_string())); + assert!(files.contains(&IOTA_FULLNODE_CONFIG.to_string())); + assert!(files.contains(&IOTA_GENESIS_FILENAME.to_string())); + assert!(files.contains(&IOTA_KEYSTORE_FILENAME.to_string())); + assert!(files.contains(&IOTA_KEYSTORE_ALIASES_FILENAME.to_string())); // Check network config let network_conf = - PersistedConfig::::read(&working_dir.join(SUI_NETWORK_CONFIG))?; + PersistedConfig::::read(&working_dir.join(IOTA_NETWORK_CONFIG))?; assert_eq!(4, network_conf.validator_configs().len()); // Check wallet config let wallet_conf = - PersistedConfig::::read(&working_dir.join(SUI_CLIENT_CONFIG))?; + PersistedConfig::::read(&working_dir.join(IOTA_CLIENT_CONFIG))?; assert!(!wallet_conf.envs.is_empty()); assert_eq!(5, wallet_conf.keystore.addresses().len()); // Genesis 2nd time should fail - let result = SuiCommand::Genesis { + let result = IotaCommand::Genesis { working_dir: Some(working_dir.to_path_buf()), write_config: None, force: false, @@ -138,11 +139,11 @@ async fn test_addresses_command() -> Result<(), anyhow::Error> { context .config .keystore - .add_key(None, SuiKeyPair::Ed25519(get_key_pair().1))?; + .add_key(None, IotaKeyPair::Ed25519(get_key_pair().1))?; } // Print all addresses - SuiClientCommands::Addresses { + IotaClientCommands::Addresses { sort_by_alias: true, } .execute(&mut context) @@ -164,14 +165,14 @@ async fn test_objects_command() -> Result<(), anyhow::Error> { .get_alias_by_address(&address) .unwrap(); // Print objects owned by `address` - SuiClientCommands::Objects { + IotaClientCommands::Objects { address: Some(KeyIdentity::Address(address)), } .execute(context) .await? .print(true); // Print objects owned by `address`, passing its alias - SuiClientCommands::Objects { + IotaClientCommands::Objects { address: Some(KeyIdentity::Alias(alias)), } .execute(context) @@ -182,8 +183,8 @@ async fn test_objects_command() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -199,7 +200,7 @@ async fn test_objects_command() -> Result<(), anyhow::Error> { #[sim_test] async fn test_ptb_publish_and_complex_arg_resolution() -> Result<(), anyhow::Error> { // Publish the package - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); let mut test_cluster = TestClusterBuilder::new().build().await; let rgp = test_cluster.get_reference_gas_price().await; let address = test_cluster.get_address_0(); @@ -209,8 +210,8 @@ async fn test_ptb_publish_and_complex_arg_resolution() -> Result<(), anyhow::Err .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -228,7 +229,7 @@ async fn test_ptb_publish_and_complex_arg_resolution() -> Result<(), anyhow::Err let mut package_path = PathBuf::from(TEST_DATA_DIR); package_path.push("ptb_complex_args_test_functions"); let build_config = BuildConfig::new_for_testing().config; - let resp = SuiClientCommands::Publish { + let resp = IotaClientCommands::Publish { package_path: package_path.clone(), build_config, gas: Some(gas_obj_id), @@ -244,11 +245,11 @@ async fn test_ptb_publish_and_complex_arg_resolution() -> Result<(), anyhow::Err // Print it out to CLI/logs resp.print(true); - let SuiClientCommandResult::Publish(response) = resp else { + let IotaClientCommandResult::Publish(response) = resp else { unreachable!("Invalid response"); }; - let SuiTransactionBlockEffects::V1(effects) = response.effects.unwrap(); + let IotaTransactionBlockEffects::V1(effects) = response.effects.unwrap(); assert!(effects.status.is_ok()); let package = effects @@ -258,7 +259,7 @@ async fn test_ptb_publish_and_complex_arg_resolution() -> Result<(), anyhow::Err .unwrap(); let package_id_str = package.reference.object_id.to_string(); - let start_call_result = SuiClientCommands::Call { + let start_call_result = IotaClientCommands::Call { package: package.reference.object_id, module: "test_module".to_string(), function: "new_shared".to_string(), @@ -273,7 +274,7 @@ async fn test_ptb_publish_and_complex_arg_resolution() -> Result<(), anyhow::Err .execute(context) .await?; - let shared_id_str = if let SuiClientCommandResult::Call(response) = start_call_result { + let shared_id_str = if let IotaClientCommandResult::Call(response) = start_call_result { response.effects.unwrap().created().to_vec()[0] .reference .object_id @@ -298,7 +299,7 @@ async fn test_ptb_publish_and_complex_arg_resolution() -> Result<(), anyhow::Err ); let args = shlex::split(&complex_ptb_string).unwrap(); - sui::client_ptb::ptb::PTB { args: args.clone() } + iota::client_ptb::ptb::PTB { args: args.clone() } .execute(context) .await?; @@ -314,21 +315,21 @@ async fn test_ptb_publish_and_complex_arg_resolution() -> Result<(), anyhow::Err ); let args = shlex::split(&delete_object_ptb_string).unwrap(); - sui::client_ptb::ptb::PTB { args: args.clone() } + iota::client_ptb::ptb::PTB { args: args.clone() } .execute(context) .await?; Ok(()) } -// fixing issue https://github.com/MystenLabs/sui/issues/6546 +// fixing issue https://github.com/iotaledger/iota/issues/6546 #[tokio::test] async fn test_regression_6546() -> Result<(), anyhow::Error> { let mut test_cluster = TestClusterBuilder::new().build().await; let address = test_cluster.get_address_0(); let context = &mut test_cluster.wallet; - let SuiClientCommandResult::Objects(coins) = SuiClientCommands::Objects { + let IotaClientCommandResult::Objects(coins) = IotaClientCommands::Objects { address: Some(KeyIdentity::Address(address)), } .execute(context) @@ -336,9 +337,9 @@ async fn test_regression_6546() -> Result<(), anyhow::Error> { else { panic!() }; - let config_path = test_cluster.swarm.dir().join(SUI_CLIENT_CONFIG); + let config_path = test_cluster.swarm.dir().join(IOTA_CLIENT_CONFIG); - test_with_sui_binary(&[ + test_with_iota_binary(&[ "client", "--client.config", config_path.to_str().unwrap(), @@ -346,7 +347,7 @@ async fn test_regression_6546() -> Result<(), anyhow::Error> { "--package", "0x2", "--module", - "sui", + "iota", "--function", "transfer", "--args", @@ -379,7 +380,7 @@ async fn test_custom_genesis() -> Result<(), anyhow::Error> { assert_eq!(1, context.config.keystore.addresses().len()); // Print objects owned by `address` - SuiClientCommands::Objects { + IotaClientCommands::Objects { address: Some(KeyIdentity::Address(address)), } .execute(context) @@ -401,8 +402,8 @@ async fn test_object_info_get_command() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new(), + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new(), )), None, None, @@ -413,7 +414,7 @@ async fn test_object_info_get_command() -> Result<(), anyhow::Error> { // Check log output contains all object ids. let object_id = object_refs.first().unwrap().object().unwrap().object_id; - SuiClientCommands::Object { + IotaClientCommands::Object { id: object_id, bcs: false, } @@ -421,7 +422,7 @@ async fn test_object_info_get_command() -> Result<(), anyhow::Error> { .await? .print(true); - SuiClientCommands::Object { + IotaClientCommands::Object { id: object_id, bcs: true, } @@ -449,8 +450,8 @@ async fn test_gas_command() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::full_content(), + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::full_content(), )), None, None, @@ -466,7 +467,7 @@ async fn test_gas_command() -> Result<(), anyhow::Error> { .object_id; let object_to_send = object_refs.data.get(1).unwrap().object().unwrap().object_id; - SuiClientCommands::Gas { + IotaClientCommands::Gas { address: Some(KeyIdentity::Address(address)), } .execute(context) @@ -476,8 +477,8 @@ async fn test_gas_command() -> Result<(), anyhow::Error> { tokio::time::sleep(Duration::from_millis(100)).await; // Send an object - SuiClientCommands::Transfer { - to: KeyIdentity::Address(SuiAddress::random_for_testing_only()), + IotaClientCommands::Transfer { + to: KeyIdentity::Address(IotaAddress::random_for_testing_only()), object_id: object_to_send, gas: Some(object_id), gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, @@ -488,7 +489,7 @@ async fn test_gas_command() -> Result<(), anyhow::Error> { .await?; // Fetch gas again, and use the alias instead of the address - SuiClientCommands::Gas { + IotaClientCommands::Gas { address: Some(KeyIdentity::Alias(alias)), } .execute(context) @@ -505,7 +506,7 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { let address1 = test_cluster.get_address_0(); let context = &mut test_cluster.wallet; - let address2 = SuiAddress::random_for_testing_only(); + let address2 = IotaAddress::random_for_testing_only(); let client = context.get_client().await?; // publish the object basics package @@ -513,8 +514,8 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address1, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::full_content(), + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::full_content(), )), None, None, @@ -525,7 +526,7 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { let mut package_path = PathBuf::from(TEST_DATA_DIR); package_path.push("move_call_args_linter"); let build_config = BuildConfig::new_for_testing().config; - let resp = SuiClientCommands::Publish { + let resp = IotaClientCommands::Publish { package_path, build_config, gas: Some(gas_obj_id), @@ -538,7 +539,7 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { .execute(context) .await?; - let package = if let SuiClientCommandResult::Publish(response) = resp { + let package = if let IotaClientCommandResult::Publish(response) = resp { assert!( response.status_ok().unwrap(), "Command failed: {:?}", @@ -563,7 +564,7 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { }; // Print objects owned by `address1` - SuiClientCommands::Objects { + IotaClientCommands::Objects { address: Some(KeyIdentity::Address(address1)), } .execute(context) @@ -575,8 +576,8 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address1, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -600,12 +601,12 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { // Create the args let args = vec![ - SuiJsonValue::new(json!("123"))?, - SuiJsonValue::new(json!(address1))?, + IotaJsonValue::new(json!("123"))?, + IotaJsonValue::new(json!(address1))?, ]; // Test case with no gas specified - let resp = SuiClientCommands::Call { + let resp = IotaClientCommands::Call { package, module: "object_basics".to_string(), function: "create".to_string(), @@ -622,7 +623,7 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { resp.print(true); // Get the created object - let created_obj: ObjectID = if let SuiClientCommandResult::Call(resp) = resp { + let created_obj: ObjectID = if let IotaClientCommandResult::Call(resp) = resp { resp.effects .unwrap() .created() @@ -636,16 +637,16 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { // Try a bad argument: decimal let args_json = json!([0.3f32, address1]); - assert!(SuiJsonValue::new(args_json.as_array().unwrap().first().unwrap().clone()).is_err()); + assert!(IotaJsonValue::new(args_json.as_array().unwrap().first().unwrap().clone()).is_err()); // Try a bad argument: too few args let args_json = json!([300usize]); let mut args = vec![]; for a in args_json.as_array().unwrap() { - args.push(SuiJsonValue::new(a.clone()).unwrap()); + args.push(IotaJsonValue::new(a.clone()).unwrap()); } - let resp = SuiClientCommands::Call { + let resp = IotaClientCommands::Call { package, module: "object_basics".to_string(), function: "create".to_string(), @@ -668,11 +669,11 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { // Try a transfer // This should fail due to mismatch of object being sent let args = vec![ - SuiJsonValue::new(json!(obj))?, - SuiJsonValue::new(json!(address2))?, + IotaJsonValue::new(json!(obj))?, + IotaJsonValue::new(json!(address2))?, ]; - let resp = SuiClientCommands::Call { + let resp = IotaClientCommands::Call { package, module: "object_basics".to_string(), function: "transfer".to_string(), @@ -692,11 +693,11 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { // Try a transfer with explicitly set gas price. // It should fail due to that gas price is below RGP. let args = vec![ - SuiJsonValue::new(json!(created_obj))?, - SuiJsonValue::new(json!(address2))?, + IotaJsonValue::new(json!(created_obj))?, + IotaJsonValue::new(json!(address2))?, ]; - let resp = SuiClientCommands::Call { + let resp = IotaClientCommands::Call { package, module: "object_basics".to_string(), function: "transfer".to_string(), @@ -718,18 +719,18 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { // FIXME: uncomment once we figure out what is going on with // `resolve_and_type_check` let err_string = format!("{} ", // resp.err().unwrap()); let framework_addr = - // SUI_FRAMEWORK_ADDRESS.to_hex_literal(); let package_addr = + // IOTA_FRAMEWORK_ADDRESS.to_hex_literal(); let package_addr = // package.to_hex_literal(); assert!(err_string.contains(&format!("Expected // argument of type {package_addr}::object_basics::Object, but found type - // {framework_addr}::coin::Coin<{framework_addr}::sui::SUI>"))); + // {framework_addr}::coin::Coin<{framework_addr}::iota::IOTA>"))); // Try a proper transfer let args = vec![ - SuiJsonValue::new(json!(created_obj))?, - SuiJsonValue::new(json!(address2))?, + IotaJsonValue::new(json!(created_obj))?, + IotaJsonValue::new(json!(address2))?, ]; - SuiClientCommands::Call { + IotaClientCommands::Call { package, module: "object_basics".to_string(), function: "transfer".to_string(), @@ -746,11 +747,11 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { // Try a call with customized gas price. let args = vec![ - SuiJsonValue::new(json!("123"))?, - SuiJsonValue::new(json!(address1))?, + IotaJsonValue::new(json!("123"))?, + IotaJsonValue::new(json!(address1))?, ]; - let result = SuiClientCommands::Call { + let result = IotaClientCommands::Call { package, module: "object_basics".to_string(), function: "create".to_string(), @@ -765,7 +766,7 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { .execute(context) .await?; - if let SuiClientCommandResult::Call(txn_response) = result { + if let IotaClientCommandResult::Call(txn_response) = result { assert_eq!( txn_response.transaction.unwrap().data.gas_data().price, 12345 @@ -789,8 +790,8 @@ async fn test_package_publish_command() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -808,7 +809,7 @@ async fn test_package_publish_command() -> Result<(), anyhow::Error> { let mut package_path = PathBuf::from(TEST_DATA_DIR); package_path.push("dummy_modules_publish"); let build_config = BuildConfig::new_for_testing().config; - let resp = SuiClientCommands::Publish { + let resp = IotaClientCommands::Publish { package_path, build_config, gas: Some(gas_obj_id), @@ -824,7 +825,7 @@ async fn test_package_publish_command() -> Result<(), anyhow::Error> { // Print it out to CLI/logs resp.print(true); - let obj_ids = if let SuiClientCommandResult::Publish(response) = resp { + let obj_ids = if let IotaClientCommandResult::Publish(response) = resp { response .effects .as_ref() @@ -857,8 +858,8 @@ async fn test_delete_shared_object() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -875,7 +876,7 @@ async fn test_delete_shared_object() -> Result<(), anyhow::Error> { let mut package_path = PathBuf::from(TEST_DATA_DIR); package_path.push("sod"); let build_config = BuildConfig::new_for_testing().config; - let resp = SuiClientCommands::Publish { + let resp = IotaClientCommands::Publish { package_path, build_config, gas: Some(gas_obj_id), @@ -888,7 +889,7 @@ async fn test_delete_shared_object() -> Result<(), anyhow::Error> { .execute(context) .await?; - let owned_obj_ids = if let SuiClientCommandResult::Publish(response) = resp { + let owned_obj_ids = if let IotaClientCommandResult::Publish(response) = resp { let x = response.effects.unwrap(); x.created().to_vec() } else { @@ -907,7 +908,7 @@ async fn test_delete_shared_object() -> Result<(), anyhow::Error> { .reference; // Start and then receive the object - let start_call_result = SuiClientCommands::Call { + let start_call_result = IotaClientCommands::Call { package: (*package_id.object_id).into(), module: "sod".to_string(), function: "start".to_string(), @@ -922,7 +923,7 @@ async fn test_delete_shared_object() -> Result<(), anyhow::Error> { .execute(context) .await?; - let shared_id = if let SuiClientCommandResult::Call(response) = start_call_result { + let shared_id = if let IotaClientCommandResult::Call(response) = start_call_result { response.effects.unwrap().created().to_vec()[0] .reference .object_id @@ -930,7 +931,7 @@ async fn test_delete_shared_object() -> Result<(), anyhow::Error> { unreachable!("Invalid response"); }; - let delete_result = SuiClientCommands::Call { + let delete_result = IotaClientCommands::Call { package: (*package_id.object_id).into(), module: "sod".to_string(), function: "delete".to_string(), @@ -938,14 +939,14 @@ async fn test_delete_shared_object() -> Result<(), anyhow::Error> { gas: None, gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, gas_price: None, - args: vec![SuiJsonValue::from_str(&shared_id.to_string()).unwrap()], + args: vec![IotaJsonValue::from_str(&shared_id.to_string()).unwrap()], serialize_unsigned_transaction: false, serialize_signed_transaction: false, } .execute(context) .await?; - if let SuiClientCommandResult::Call(response) = delete_result { + if let IotaClientCommandResult::Call(response) = delete_result { assert!(response.effects.unwrap().into_status().is_ok()); } else { unreachable!("Invalid response"); @@ -966,8 +967,8 @@ async fn test_receive_argument() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -984,7 +985,7 @@ async fn test_receive_argument() -> Result<(), anyhow::Error> { let mut package_path = PathBuf::from(TEST_DATA_DIR); package_path.push("tto"); let build_config = BuildConfig::new_for_testing().config; - let resp = SuiClientCommands::Publish { + let resp = IotaClientCommands::Publish { package_path, build_config, gas: Some(gas_obj_id), @@ -997,7 +998,7 @@ async fn test_receive_argument() -> Result<(), anyhow::Error> { .execute(context) .await?; - let owned_obj_ids = if let SuiClientCommandResult::Publish(response) = resp { + let owned_obj_ids = if let IotaClientCommandResult::Publish(response) = resp { let x = response.effects.unwrap(); x.created().to_vec() } else { @@ -1016,7 +1017,7 @@ async fn test_receive_argument() -> Result<(), anyhow::Error> { .reference; // Start and then receive the object - let start_call_result = SuiClientCommands::Call { + let start_call_result = IotaClientCommands::Call { package: (*package_id.object_id).into(), module: "tto".to_string(), function: "start".to_string(), @@ -1031,7 +1032,7 @@ async fn test_receive_argument() -> Result<(), anyhow::Error> { .execute(context) .await?; - let (parent, child) = if let SuiClientCommandResult::Call(response) = start_call_result { + let (parent, child) = if let IotaClientCommandResult::Call(response) = start_call_result { let created = response.effects.unwrap().created().to_vec(); let owners: BTreeSet = created .iter() @@ -1055,7 +1056,7 @@ async fn test_receive_argument() -> Result<(), anyhow::Error> { unreachable!("Invalid response"); }; - let receive_result = SuiClientCommands::Call { + let receive_result = IotaClientCommands::Call { package: (*package_id.object_id).into(), module: "tto".to_string(), function: "receiver".to_string(), @@ -1064,8 +1065,8 @@ async fn test_receive_argument() -> Result<(), anyhow::Error> { gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, gas_price: None, args: vec![ - SuiJsonValue::from_str(&parent.object_id.to_string()).unwrap(), - SuiJsonValue::from_str(&child.object_id.to_string()).unwrap(), + IotaJsonValue::from_str(&parent.object_id.to_string()).unwrap(), + IotaJsonValue::from_str(&child.object_id.to_string()).unwrap(), ], serialize_unsigned_transaction: false, serialize_signed_transaction: false, @@ -1073,7 +1074,7 @@ async fn test_receive_argument() -> Result<(), anyhow::Error> { .execute(context) .await?; - if let SuiClientCommandResult::Call(response) = receive_result { + if let IotaClientCommandResult::Call(response) = receive_result { assert!(response.effects.unwrap().into_status().is_ok()); } else { unreachable!("Invalid response"); @@ -1094,8 +1095,8 @@ async fn test_receive_argument_by_immut_ref() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -1112,7 +1113,7 @@ async fn test_receive_argument_by_immut_ref() -> Result<(), anyhow::Error> { let mut package_path = PathBuf::from(TEST_DATA_DIR); package_path.push("tto"); let build_config = BuildConfig::new_for_testing().config; - let resp = SuiClientCommands::Publish { + let resp = IotaClientCommands::Publish { package_path, build_config, gas: Some(gas_obj_id), @@ -1125,7 +1126,7 @@ async fn test_receive_argument_by_immut_ref() -> Result<(), anyhow::Error> { .execute(context) .await?; - let owned_obj_ids = if let SuiClientCommandResult::Publish(response) = resp { + let owned_obj_ids = if let IotaClientCommandResult::Publish(response) = resp { let x = response.effects.unwrap(); x.created().to_vec() } else { @@ -1144,7 +1145,7 @@ async fn test_receive_argument_by_immut_ref() -> Result<(), anyhow::Error> { .reference; // Start and then receive the object - let start_call_result = SuiClientCommands::Call { + let start_call_result = IotaClientCommands::Call { package: (*package_id.object_id).into(), module: "tto".to_string(), function: "start".to_string(), @@ -1159,7 +1160,7 @@ async fn test_receive_argument_by_immut_ref() -> Result<(), anyhow::Error> { .execute(context) .await?; - let (parent, child) = if let SuiClientCommandResult::Call(response) = start_call_result { + let (parent, child) = if let IotaClientCommandResult::Call(response) = start_call_result { let created = response.effects.unwrap().created().to_vec(); let owners: BTreeSet = created .iter() @@ -1183,7 +1184,7 @@ async fn test_receive_argument_by_immut_ref() -> Result<(), anyhow::Error> { unreachable!("Invalid response"); }; - let receive_result = SuiClientCommands::Call { + let receive_result = IotaClientCommands::Call { package: (*package_id.object_id).into(), module: "tto".to_string(), function: "invalid_call_immut_ref".to_string(), @@ -1192,8 +1193,8 @@ async fn test_receive_argument_by_immut_ref() -> Result<(), anyhow::Error> { gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, gas_price: None, args: vec![ - SuiJsonValue::from_str(&parent.object_id.to_string()).unwrap(), - SuiJsonValue::from_str(&child.object_id.to_string()).unwrap(), + IotaJsonValue::from_str(&parent.object_id.to_string()).unwrap(), + IotaJsonValue::from_str(&child.object_id.to_string()).unwrap(), ], serialize_unsigned_transaction: false, serialize_signed_transaction: false, @@ -1201,7 +1202,7 @@ async fn test_receive_argument_by_immut_ref() -> Result<(), anyhow::Error> { .execute(context) .await?; - if let SuiClientCommandResult::Call(response) = receive_result { + if let IotaClientCommandResult::Call(response) = receive_result { assert!(response.effects.unwrap().into_status().is_ok()); } else { unreachable!("Invalid response"); @@ -1222,8 +1223,8 @@ async fn test_receive_argument_by_mut_ref() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -1240,7 +1241,7 @@ async fn test_receive_argument_by_mut_ref() -> Result<(), anyhow::Error> { let mut package_path = PathBuf::from(TEST_DATA_DIR); package_path.push("tto"); let build_config = BuildConfig::new_for_testing().config; - let resp = SuiClientCommands::Publish { + let resp = IotaClientCommands::Publish { package_path, build_config, gas: Some(gas_obj_id), @@ -1253,7 +1254,7 @@ async fn test_receive_argument_by_mut_ref() -> Result<(), anyhow::Error> { .execute(context) .await?; - let owned_obj_ids = if let SuiClientCommandResult::Publish(response) = resp { + let owned_obj_ids = if let IotaClientCommandResult::Publish(response) = resp { let x = response.effects.unwrap(); x.created().to_vec() } else { @@ -1272,7 +1273,7 @@ async fn test_receive_argument_by_mut_ref() -> Result<(), anyhow::Error> { .reference; // Start and then receive the object - let start_call_result = SuiClientCommands::Call { + let start_call_result = IotaClientCommands::Call { package: (*package_id.object_id).into(), module: "tto".to_string(), function: "start".to_string(), @@ -1287,7 +1288,7 @@ async fn test_receive_argument_by_mut_ref() -> Result<(), anyhow::Error> { .execute(context) .await?; - let (parent, child) = if let SuiClientCommandResult::Call(response) = start_call_result { + let (parent, child) = if let IotaClientCommandResult::Call(response) = start_call_result { let created = response.effects.unwrap().created().to_vec(); let owners: BTreeSet = created .iter() @@ -1311,7 +1312,7 @@ async fn test_receive_argument_by_mut_ref() -> Result<(), anyhow::Error> { unreachable!("Invalid response"); }; - let receive_result = SuiClientCommands::Call { + let receive_result = IotaClientCommands::Call { package: (*package_id.object_id).into(), module: "tto".to_string(), function: "invalid_call_mut_ref".to_string(), @@ -1320,8 +1321,8 @@ async fn test_receive_argument_by_mut_ref() -> Result<(), anyhow::Error> { gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, gas_price: None, args: vec![ - SuiJsonValue::from_str(&parent.object_id.to_string()).unwrap(), - SuiJsonValue::from_str(&child.object_id.to_string()).unwrap(), + IotaJsonValue::from_str(&parent.object_id.to_string()).unwrap(), + IotaJsonValue::from_str(&child.object_id.to_string()).unwrap(), ], serialize_unsigned_transaction: false, serialize_signed_transaction: false, @@ -1329,7 +1330,7 @@ async fn test_receive_argument_by_mut_ref() -> Result<(), anyhow::Error> { .execute(context) .await?; - if let SuiClientCommandResult::Call(response) = receive_result { + if let IotaClientCommandResult::Call(response) = receive_result { assert!(response.effects.unwrap().into_status().is_ok()); } else { unreachable!("Invalid response"); @@ -1353,8 +1354,8 @@ async fn test_package_publish_command_with_unpublished_dependency_succeeds() .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -1370,7 +1371,7 @@ async fn test_package_publish_command_with_unpublished_dependency_succeeds() let mut package_path = PathBuf::from(TEST_DATA_DIR); package_path.push("module_publish_with_unpublished_dependency"); let build_config = BuildConfig::new_for_testing().config; - let resp = SuiClientCommands::Publish { + let resp = IotaClientCommands::Publish { package_path, build_config, gas: Some(gas_obj_id), @@ -1386,7 +1387,7 @@ async fn test_package_publish_command_with_unpublished_dependency_succeeds() // Print it out to CLI/logs resp.print(true); - let obj_ids = if let SuiClientCommandResult::Publish(response) = resp { + let obj_ids = if let IotaClientCommandResult::Publish(response) = resp { response .effects .as_ref() @@ -1421,8 +1422,8 @@ async fn test_package_publish_command_with_unpublished_dependency_fails() .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -1438,7 +1439,7 @@ async fn test_package_publish_command_with_unpublished_dependency_fails() let mut package_path = PathBuf::from(TEST_DATA_DIR); package_path.push("module_publish_with_unpublished_dependency"); let build_config = BuildConfig::new_for_testing().config; - let result = SuiClientCommands::Publish { + let result = IotaClientCommands::Publish { package_path, build_config, gas: Some(gas_obj_id), @@ -1484,7 +1485,7 @@ async fn test_package_publish_command_non_zero_unpublished_dep_fails() -> Result let mut package_path = PathBuf::from(TEST_DATA_DIR); package_path.push("module_publish_with_unpublished_dependency_with_non_zero_address"); let build_config = BuildConfig::new_for_testing().config; - let result = SuiClientCommands::Publish { + let result = IotaClientCommands::Publish { package_path, build_config, gas: Some(gas_obj_id), @@ -1522,8 +1523,8 @@ async fn test_package_publish_command_failure_invalid() -> Result<(), anyhow::Er .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -1539,7 +1540,7 @@ async fn test_package_publish_command_failure_invalid() -> Result<(), anyhow::Er let mut package_path = PathBuf::from(TEST_DATA_DIR); package_path.push("module_publish_failure_invalid"); let build_config = BuildConfig::new_for_testing().config; - let result = SuiClientCommands::Publish { + let result = IotaClientCommands::Publish { package_path, build_config, gas: Some(gas_obj_id), @@ -1581,7 +1582,7 @@ async fn test_package_publish_nonexistent_dependency() -> Result<(), anyhow::Err let mut package_path = PathBuf::from(TEST_DATA_DIR); package_path.push("module_publish_with_nonexistent_dependency"); let build_config = BuildConfig::new_for_testing().config; - let result = SuiClientCommands::Publish { + let result = IotaClientCommands::Publish { package_path, build_config, gas: Some(gas_obj_id), @@ -1621,10 +1622,10 @@ async fn test_package_publish_test_flag() -> Result<(), anyhow::Error> { let mut package_path = PathBuf::from(TEST_DATA_DIR); package_path.push("module_publish_with_nonexistent_dependency"); let mut build_config: MoveBuildConfig = BuildConfig::new_for_testing().config; - // this would have been the result of calling `sui client publish --test` + // this would have been the result of calling `iota client publish --test` build_config.test_mode = true; - let result = SuiClientCommands::Publish { + let result = IotaClientCommands::Publish { package_path, build_config, gas: Some(gas_obj_id), @@ -1640,7 +1641,7 @@ async fn test_package_publish_test_flag() -> Result<(), anyhow::Error> { let expect = expect![[r#" Err( ModulePublishFailure { - error: "The `publish` subcommand should not be used with the `--test` flag\n\nCode in published packages must not depend on test code.\nIn order to fix this and publish the package without `--test`, remove any non-test dependencies on test-only code.\nYou can ensure all test-only dependencies have been removed by compiling the package normally with `sui move build`.", + error: "The `publish` subcommand should not be used with the `--test` flag\n\nCode in published packages must not depend on test code.\nIn order to fix this and publish the package without `--test`, remove any non-test dependencies on test-only code.\nYou can ensure all test-only dependencies have been removed by compiling the package normally with `iota move build`.", }, ) "#]]; @@ -1650,7 +1651,7 @@ async fn test_package_publish_test_flag() -> Result<(), anyhow::Error> { #[sim_test] async fn test_package_upgrade_command() -> Result<(), anyhow::Error> { - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); let mut test_cluster = TestClusterBuilder::new().build().await; let rgp = test_cluster.get_reference_gas_price().await; let address = test_cluster.get_address_0(); @@ -1660,8 +1661,8 @@ async fn test_package_upgrade_command() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -1679,7 +1680,7 @@ async fn test_package_upgrade_command() -> Result<(), anyhow::Error> { let mut package_path = PathBuf::from(TEST_DATA_DIR); package_path.push("dummy_modules_upgrade"); let build_config = BuildConfig::new_for_testing().config; - let resp = SuiClientCommands::Publish { + let resp = IotaClientCommands::Publish { package_path: package_path.clone(), build_config, gas: Some(gas_obj_id), @@ -1695,11 +1696,11 @@ async fn test_package_upgrade_command() -> Result<(), anyhow::Error> { // Print it out to CLI/logs resp.print(true); - let SuiClientCommandResult::Publish(response) = resp else { + let IotaClientCommandResult::Publish(response) = resp else { unreachable!("Invalid response"); }; - let SuiTransactionBlockEffects::V1(effects) = response.effects.unwrap(); + let IotaTransactionBlockEffects::V1(effects) = response.effects.unwrap(); assert!(effects.status.is_ok()); let package = effects @@ -1754,7 +1755,7 @@ async fn test_package_upgrade_command() -> Result<(), anyhow::Error> { // Now run the upgrade let build_config = BuildConfig::new_for_testing().config; - let resp = SuiClientCommands::Upgrade { + let resp = IotaClientCommands::Upgrade { package_path: upgrade_pkg_path, upgrade_capability: cap.reference.object_id, build_config, @@ -1770,10 +1771,10 @@ async fn test_package_upgrade_command() -> Result<(), anyhow::Error> { resp.print(true); - let SuiClientCommandResult::Upgrade(response) = resp else { + let IotaClientCommandResult::Upgrade(response) = resp else { unreachable!("Invalid upgrade response"); }; - let SuiTransactionBlockEffects::V1(effects) = response.effects.unwrap(); + let IotaTransactionBlockEffects::V1(effects) = response.effects.unwrap(); assert!(effects.status.is_ok()); @@ -1797,14 +1798,14 @@ async fn test_native_transfer() -> Result<(), anyhow::Error> { let rgp = test_cluster.get_reference_gas_price().await; let address = test_cluster.get_address_0(); let context = &mut test_cluster.wallet; - let recipient = SuiAddress::random_for_testing_only(); + let recipient = IotaAddress::random_for_testing_only(); let client = context.get_client().await?; let object_refs = client .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -1819,7 +1820,7 @@ async fn test_native_transfer() -> Result<(), anyhow::Error> { let gas_obj_id = object_refs.first().unwrap().object().unwrap().object_id; let obj_id = object_refs.get(1).unwrap().object().unwrap().object_id; - let resp = SuiClientCommands::Transfer { + let resp = IotaClientCommands::Transfer { gas: Some(gas_obj_id), to: KeyIdentity::Address(recipient), object_id: obj_id, @@ -1834,7 +1835,7 @@ async fn test_native_transfer() -> Result<(), anyhow::Error> { resp.print(true); // Get the mutated objects - let (mut_obj1, mut_obj2) = if let SuiClientCommandResult::Transfer(response) = resp { + let (mut_obj1, mut_obj2) = if let IotaClientCommandResult::Transfer(response) = resp { assert!( response.status_ok().unwrap(), "Command failed: {:?}", @@ -1865,13 +1866,13 @@ async fn test_native_transfer() -> Result<(), anyhow::Error> { }; // Check the objects - let resp = SuiClientCommands::Object { + let resp = IotaClientCommands::Object { id: mut_obj1, bcs: false, } .execute(context) .await?; - let mut_obj1 = if let SuiClientCommandResult::Object(resp) = resp { + let mut_obj1 = if let IotaClientCommandResult::Object(resp) = resp { if let Some(obj) = resp.data { obj } else { @@ -1881,13 +1882,13 @@ async fn test_native_transfer() -> Result<(), anyhow::Error> { panic!(); }; - let resp2 = SuiClientCommands::Object { + let resp2 = IotaClientCommands::Object { id: mut_obj2, bcs: false, } .execute(context) .await?; - let mut_obj2 = if let SuiClientCommandResult::Object(resp2) = resp2 { + let mut_obj2 = if let IotaClientCommandResult::Object(resp2) = resp2 { if let Some(obj) = resp2.data { obj } else { @@ -1910,8 +1911,8 @@ async fn test_native_transfer() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -1924,7 +1925,7 @@ async fn test_native_transfer() -> Result<(), anyhow::Error> { // Check log output contains all object ids. let obj_id = object_refs.data.get(1).unwrap().object().unwrap().object_id; - let resp = SuiClientCommands::Transfer { + let resp = IotaClientCommands::Transfer { gas: None, to: KeyIdentity::Address(recipient), object_id: obj_id, @@ -1939,7 +1940,7 @@ async fn test_native_transfer() -> Result<(), anyhow::Error> { resp.print(true); // Get the mutated objects - let (_mut_obj1, _mut_obj2) = if let SuiClientCommandResult::Transfer(response) = resp { + let (_mut_obj1, _mut_obj2) = if let IotaClientCommandResult::Transfer(response) = resp { ( response .effects @@ -1968,10 +1969,10 @@ async fn test_native_transfer() -> Result<(), anyhow::Error> { } #[test] -// Test for issue https://github.com/MystenLabs/sui/issues/1078 +// Test for issue https://github.com/iotaledger/iota/issues/1078 fn test_bug_1078() { - let read = SuiClientCommandResult::Object(SuiObjectResponse::new_with_error( - SuiObjectResponseError::NotExists { + let read = IotaClientCommandResult::Object(IotaObjectResponse::new_with_error( + IotaObjectResponseError::NotExists { object_id: ObjectID::random(), }, )); @@ -1991,11 +1992,11 @@ async fn test_switch_command() -> Result<(), anyhow::Error> { let addr1 = context.active_address()?; // Run a command with address omitted - let os = SuiClientCommands::Objects { address: None } + let os = IotaClientCommands::Objects { address: None } .execute(context) .await?; - let mut cmd_objs = if let SuiClientCommandResult::Objects(v) = os { + let mut cmd_objs = if let IotaClientCommandResult::Objects(v) = os { v } else { panic!("Command failed") @@ -2007,8 +2008,8 @@ async fn test_switch_command() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( addr1, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::full_content(), + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::full_content(), )), None, None, @@ -2021,7 +2022,7 @@ async fn test_switch_command() -> Result<(), anyhow::Error> { assert_eq!(cmd_objs, actual_objs); // Switch the address - let resp = SuiClientCommands::Switch { + let resp = IotaClientCommands::Switch { address: Some(KeyIdentity::Address(addr2)), env: None, } @@ -2033,7 +2034,7 @@ async fn test_switch_command() -> Result<(), anyhow::Error> { format!("{resp}"), format!( "{}", - SuiClientCommandResult::Switch(SwitchResponse { + IotaClientCommandResult::Switch(SwitchResponse { address: Some(addr2.to_string()), env: None }) @@ -2044,7 +2045,7 @@ async fn test_switch_command() -> Result<(), anyhow::Error> { context.config.active_address = None; // Create a new address - let os = SuiClientCommands::NewAddress { + let os = IotaClientCommands::NewAddress { key_scheme: SignatureScheme::ED25519, alias: None, derivation_path: None, @@ -2052,7 +2053,7 @@ async fn test_switch_command() -> Result<(), anyhow::Error> { } .execute(context) .await?; - let new_addr = if let SuiClientCommandResult::NewAddress(x) = os { + let new_addr = if let IotaClientCommandResult::NewAddress(x) = os { x.address } else { panic!("Command failed") @@ -2060,7 +2061,7 @@ async fn test_switch_command() -> Result<(), anyhow::Error> { // Check that we can switch to this address // Switch the address - let resp = SuiClientCommands::Switch { + let resp = IotaClientCommands::Switch { address: Some(KeyIdentity::Address(new_addr)), env: None, } @@ -2071,7 +2072,7 @@ async fn test_switch_command() -> Result<(), anyhow::Error> { format!("{resp}"), format!( "{}", - SuiClientCommandResult::Switch(SwitchResponse { + IotaClientCommandResult::Switch(SwitchResponse { address: Some(new_addr.to_string()), env: None }) @@ -2092,12 +2093,12 @@ async fn test_new_address_command_by_flag() -> Result<(), anyhow::Error> { .keystore .keys() .iter() - .filter(|k| k.flag() == Ed25519SuiSignature::SCHEME.flag()) + .filter(|k| k.flag() == Ed25519IotaSignature::SCHEME.flag()) .count(), 5 ); - SuiClientCommands::NewAddress { + IotaClientCommands::NewAddress { key_scheme: SignatureScheme::Secp256k1, alias: None, derivation_path: None, @@ -2113,7 +2114,7 @@ async fn test_new_address_command_by_flag() -> Result<(), anyhow::Error> { .keystore .keys() .iter() - .filter(|k| k.flag() == Secp256k1SuiSignature::SCHEME.flag()) + .filter(|k| k.flag() == Secp256k1IotaSignature::SCHEME.flag()) .count(), 1 ); @@ -2130,9 +2131,11 @@ async fn test_active_address_command() -> Result<(), anyhow::Error> { let addr1 = context.active_address()?; // Run a command with address omitted - let os = SuiClientCommands::ActiveAddress {}.execute(context).await?; + let os = IotaClientCommands::ActiveAddress {} + .execute(context) + .await?; - let a = if let SuiClientCommandResult::ActiveAddress(Some(v)) = os { + let a = if let IotaClientCommandResult::ActiveAddress(Some(v)) = os { v } else { panic!("Command failed") @@ -2140,7 +2143,7 @@ async fn test_active_address_command() -> Result<(), anyhow::Error> { assert_eq!(a, addr1); let addr2 = context.config.keystore.addresses().get(1).cloned().unwrap(); - let resp = SuiClientCommands::Switch { + let resp = IotaClientCommands::Switch { address: Some(KeyIdentity::Address(addr2)), env: None, } @@ -2150,7 +2153,7 @@ async fn test_active_address_command() -> Result<(), anyhow::Error> { format!("{resp}"), format!( "{}", - SuiClientCommandResult::Switch(SwitchResponse { + IotaClientCommandResult::Switch(SwitchResponse { address: Some(addr2.to_string()), env: None }) @@ -2163,7 +2166,7 @@ async fn test_active_address_command() -> Result<(), anyhow::Error> { .keystore .get_alias_by_address(&addr1) .unwrap(); - let resp = SuiClientCommands::Switch { + let resp = IotaClientCommands::Switch { address: Some(KeyIdentity::Alias(alias1)), env: None, } @@ -2173,7 +2176,7 @@ async fn test_active_address_command() -> Result<(), anyhow::Error> { format!("{resp}"), format!( "{}", - SuiClientCommandResult::Switch(SwitchResponse { + IotaClientCommandResult::Switch(SwitchResponse { address: Some(addr1.to_string()), env: None }) @@ -2183,15 +2186,15 @@ async fn test_active_address_command() -> Result<(), anyhow::Error> { Ok(()) } -fn get_gas_value(o: &SuiObjectData) -> u64 { +fn get_gas_value(o: &IotaObjectData) -> u64 { GasCoin::try_from(o).unwrap().value() } -async fn get_object(id: ObjectID, context: &WalletContext) -> Option { +async fn get_object(id: ObjectID, context: &WalletContext) -> Option { let client = context.get_client().await.unwrap(); let response = client .read_api() - .get_object_with_options(id, SuiObjectDataOptions::full_content()) + .get_object_with_options(id, IotaObjectDataOptions::full_content()) .await .unwrap(); response.data @@ -2200,7 +2203,7 @@ async fn get_object(id: ObjectID, context: &WalletContext) -> Option SuiObjectData { +) -> IotaObjectData { get_object(object_id, context) .await .expect("Object {object_id} does not exist.") @@ -2218,8 +2221,8 @@ async fn test_merge_coin() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -2239,7 +2242,7 @@ async fn test_merge_coin() -> Result<(), anyhow::Error> { + get_gas_value(&get_object(coin_to_merge, context).await.unwrap()); // Test with gas specified - let resp = SuiClientCommands::MergeCoin { + let resp = IotaClientCommands::MergeCoin { primary_coin, coin_to_merge, gas: Some(gas), @@ -2249,7 +2252,7 @@ async fn test_merge_coin() -> Result<(), anyhow::Error> { } .execute(context) .await?; - let g = if let SuiClientCommandResult::MergeCoin(r) = resp { + let g = if let IotaClientCommandResult::MergeCoin(r) = resp { assert!(r.status_ok().unwrap(), "Command failed: {:?}", r); let object_id = r .effects @@ -2276,8 +2279,8 @@ async fn test_merge_coin() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -2294,7 +2297,7 @@ async fn test_merge_coin() -> Result<(), anyhow::Error> { + get_gas_value(&get_object(coin_to_merge, context).await.unwrap()); // Test with no gas specified - let resp = SuiClientCommands::MergeCoin { + let resp = IotaClientCommands::MergeCoin { primary_coin, coin_to_merge, gas: None, @@ -2305,7 +2308,7 @@ async fn test_merge_coin() -> Result<(), anyhow::Error> { .execute(context) .await?; - let g = if let SuiClientCommandResult::MergeCoin(r) = resp { + let g = if let IotaClientCommandResult::MergeCoin(r) = resp { let object_id = r .effects .as_ref() @@ -2341,8 +2344,8 @@ async fn test_split_coin() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -2359,7 +2362,7 @@ async fn test_split_coin() -> Result<(), anyhow::Error> { let orig_value = get_gas_value(&get_object(coin, context).await.unwrap()); // Test with gas specified - let resp = SuiClientCommands::SplitCoin { + let resp = IotaClientCommands::SplitCoin { gas: Some(gas), gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_SPLIT_COIN, coin_id: coin, @@ -2371,7 +2374,7 @@ async fn test_split_coin() -> Result<(), anyhow::Error> { .execute(context) .await?; - let (updated_coin, new_coins) = if let SuiClientCommandResult::SplitCoin(r) = resp { + let (updated_coin, new_coins) = if let IotaClientCommandResult::SplitCoin(r) = resp { assert!(r.status_ok().unwrap(), "Command failed: {:?}", r); let updated_object_id = r .effects @@ -2405,8 +2408,8 @@ async fn test_split_coin() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -2427,7 +2430,7 @@ async fn test_split_coin() -> Result<(), anyhow::Error> { let orig_value = get_gas_value(&get_object(coin, context).await.unwrap()); // Test split coin into equal parts - let resp = SuiClientCommands::SplitCoin { + let resp = IotaClientCommands::SplitCoin { gas: None, gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_SPLIT_COIN, coin_id: coin, @@ -2439,7 +2442,7 @@ async fn test_split_coin() -> Result<(), anyhow::Error> { .execute(context) .await?; - let (updated_coin, new_coins) = if let SuiClientCommandResult::SplitCoin(r) = resp { + let (updated_coin, new_coins) = if let IotaClientCommandResult::SplitCoin(r) = resp { assert!(r.status_ok().unwrap(), "Command failed: {:?}", r); let updated_object_id = r .effects @@ -2476,8 +2479,8 @@ async fn test_split_coin() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -2498,7 +2501,7 @@ async fn test_split_coin() -> Result<(), anyhow::Error> { let orig_value = get_gas_value(&get_object(coin, context).await.unwrap()); // Test with no gas specified - let resp = SuiClientCommands::SplitCoin { + let resp = IotaClientCommands::SplitCoin { gas: None, gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_SPLIT_COIN, coin_id: coin, @@ -2510,7 +2513,7 @@ async fn test_split_coin() -> Result<(), anyhow::Error> { .execute(context) .await?; - let (updated_coin, new_coins) = if let SuiClientCommandResult::SplitCoin(r) = resp { + let (updated_coin, new_coins) = if let IotaClientCommandResult::SplitCoin(r) = resp { assert!(r.status_ok().unwrap(), "Command failed: {:?}", r); let updated_object_id = r .effects @@ -2569,7 +2572,7 @@ async fn test_execute_signed_tx() -> Result<(), anyhow::Error> { let txn = txns.swap_remove(0); let (tx_data, signatures) = txn.to_tx_bytes_and_signatures(); - SuiClientCommands::ExecuteSignedTx { + IotaClientCommands::ExecuteSignedTx { tx_bytes: tx_data.encoded(), signatures: signatures.into_iter().map(|s| s.encoded()).collect(), } @@ -2595,8 +2598,8 @@ async fn test_serialize_tx() -> Result<(), anyhow::Error> { .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -2608,9 +2611,9 @@ async fn test_serialize_tx() -> Result<(), anyhow::Error> { .data; let coin = object_refs.get(1).unwrap().object().unwrap().object_id; - SuiClientCommands::TransferSui { + IotaClientCommands::TransferIota { to: KeyIdentity::Address(address1), - sui_coin_object_id: coin, + iota_coin_object_id: coin, gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, amount: Some(1), serialize_unsigned_transaction: true, @@ -2619,9 +2622,9 @@ async fn test_serialize_tx() -> Result<(), anyhow::Error> { .execute(context) .await?; - SuiClientCommands::TransferSui { + IotaClientCommands::TransferIota { to: KeyIdentity::Address(address1), - sui_coin_object_id: coin, + iota_coin_object_id: coin, gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, amount: Some(1), serialize_unsigned_transaction: false, @@ -2631,9 +2634,9 @@ async fn test_serialize_tx() -> Result<(), anyhow::Error> { .await?; // use alias for transfer - SuiClientCommands::TransferSui { + IotaClientCommands::TransferIota { to: KeyIdentity::Alias(alias1), - sui_coin_object_id: coin, + iota_coin_object_id: coin, gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, amount: Some(1), serialize_unsigned_transaction: false, @@ -2657,15 +2660,15 @@ async fn test_stake_with_none_amount() -> Result<(), anyhow::Error> { .await? .data; - let config_path = test_cluster.swarm.dir().join(SUI_CLIENT_CONFIG); + let config_path = test_cluster.swarm.dir().join(IOTA_CLIENT_CONFIG); let validator_addr = client .governance_api() - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await? .active_validators[0] - .sui_address; + .iota_address; - test_with_sui_binary(&[ + test_with_iota_binary(&[ "client", "--client.config", config_path.to_str().unwrap(), @@ -2673,7 +2676,7 @@ async fn test_stake_with_none_amount() -> Result<(), anyhow::Error> { "--package", "0x3", "--module", - "sui_system", + "iota_system", "--function", "request_add_stake_mul_coin", "--args", @@ -2709,15 +2712,15 @@ async fn test_stake_with_u64_amount() -> Result<(), anyhow::Error> { .await? .data; - let config_path = test_cluster.swarm.dir().join(SUI_CLIENT_CONFIG); + let config_path = test_cluster.swarm.dir().join(IOTA_CLIENT_CONFIG); let validator_addr = client .governance_api() - .get_latest_sui_system_state() + .get_latest_iota_system_state() .await? .active_validators[0] - .sui_address; + .iota_address; - test_with_sui_binary(&[ + test_with_iota_binary(&[ "client", "--client.config", config_path.to_str().unwrap(), @@ -2725,7 +2728,7 @@ async fn test_stake_with_u64_amount() -> Result<(), anyhow::Error> { "--package", "0x3", "--module", - "sui_system", + "iota_system", "--function", "request_add_stake_mul_coin", "--args", @@ -2748,8 +2751,8 @@ async fn test_stake_with_u64_amount() -> Result<(), anyhow::Error> { Ok(()) } -async fn test_with_sui_binary(args: &[&str]) -> Result<(), anyhow::Error> { - let mut cmd = assert_cmd::Command::cargo_bin("sui").unwrap(); +async fn test_with_iota_binary(args: &[&str]) -> Result<(), anyhow::Error> { + let mut cmd = assert_cmd::Command::cargo_bin("iota").unwrap(); let args = args.iter().map(|s| s.to_string()).collect::>(); // test cluster will not response if this call is in the same thread let out = thread::spawn(move || cmd.args(args).assert()); @@ -2772,10 +2775,10 @@ async fn test_get_owned_objects_owned_by_address_and_check_pagination() -> Resul .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new( - Some(SuiObjectDataFilter::StructType(GasCoin::type_())), + Some(IotaObjectResponseQuery::new( + Some(IotaObjectDataFilter::StructType(GasCoin::type_())), Some( - SuiObjectDataOptions::new() + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -2800,16 +2803,16 @@ async fn test_get_owned_objects_owned_by_address_and_check_pagination() -> Resul // Pagination check let mut has_next = true; let mut cursor = None; - let mut response_data: Vec = Vec::new(); + let mut response_data: Vec = Vec::new(); while has_next { let object_responses = client .read_api() .get_owned_objects( address, - Some(SuiObjectResponseQuery::new( - Some(SuiObjectDataFilter::StructType(GasCoin::type_())), + Some(IotaObjectResponseQuery::new( + Some(IotaObjectDataFilter::StructType(GasCoin::type_())), Some( - SuiObjectDataOptions::new() + IotaObjectDataOptions::new() .with_type() .with_owner() .with_previous_transaction(), @@ -2838,12 +2841,12 @@ async fn test_get_owned_objects_owned_by_address_and_check_pagination() -> Resul async fn test_linter_suppression_stats() -> Result<(), anyhow::Error> { const LINTER_MSG: &str = "Total number of linter warnings suppressed: 5 (filtered categories: 3)"; - let mut cmd = assert_cmd::Command::cargo_bin("sui").unwrap(); + let mut cmd = assert_cmd::Command::cargo_bin("iota").unwrap(); let args = vec!["move", "test", "--path", "tests/data/linter"]; let output = cmd .args(&args) .output() - .expect("failed to run 'sui move test'"); + .expect("failed to run 'iota move test'"); let out_str = str::from_utf8(&output.stderr).unwrap(); assert!(out_str.contains(LINTER_MSG)); // test no-lint suppresses @@ -2851,7 +2854,7 @@ async fn test_linter_suppression_stats() -> Result<(), anyhow::Error> { let output = cmd .args(&args) .output() - .expect("failed to run 'sui move test'"); + .expect("failed to run 'iota move test'"); let out_str = str::from_utf8(&output.stderr).unwrap(); assert!(!out_str.contains(LINTER_MSG)); Ok(()) diff --git a/crates/iota/tests/data/dummy_modules_publish/Move.toml b/crates/iota/tests/data/dummy_modules_publish/Move.toml new file mode 100644 index 00000000000..e518fc169a9 --- /dev/null +++ b/crates/iota/tests/data/dummy_modules_publish/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "Examples" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../iota-framework/packages/iota-framework" } + +[addresses] +examples = "0x0" diff --git a/crates/iota/tests/data/dummy_modules_publish/sources/trusted_coin.move b/crates/iota/tests/data/dummy_modules_publish/sources/trusted_coin.move new file mode 100644 index 00000000000..8bd58e13e00 --- /dev/null +++ b/crates/iota/tests/data/dummy_modules_publish/sources/trusted_coin.move @@ -0,0 +1,40 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Example coin with a trusted owner responsible for minting/burning (e.g., a stablecoin) +module examples::trusted_coin { + use std::option; + use iota::coin::{Self, TreasuryCap}; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; + + /// Name of the coin + struct TRUSTED_COIN has drop {} + + /// Register the trusted currency to acquire its `TreasuryCap`. Because + /// this is a module initializer, it ensures the currency only gets + /// registered once. + fun init(witness: TRUSTED_COIN, ctx: &mut TxContext) { + // Get a treasury cap for the coin and give it to the transaction + // sender + let (treasury_cap, metadata) = coin::create_currency(witness, 2, b"TRUSTED", b"", b"", option::none(), ctx); + transfer::public_freeze_object(metadata); + transfer::public_transfer(treasury_cap, tx_context::sender(ctx)) + } + + public entry fun mint(treasury_cap: &mut TreasuryCap, amount: u64, ctx: &mut TxContext) { + let coin = coin::mint(treasury_cap, amount, ctx); + transfer::public_transfer(coin, tx_context::sender(ctx)); + } + + public entry fun transfer(treasury_cap: TreasuryCap, recipient: address) { + transfer::public_transfer(treasury_cap, recipient); + } + + #[test_only] + /// Wrapper of module initializer for testing + public fun test_init(ctx: &mut TxContext) { + init(TRUSTED_COIN {}, ctx) + } +} diff --git a/crates/sui/tests/data/dummy_modules_upgrade/Move.toml b/crates/iota/tests/data/dummy_modules_upgrade/Move.toml similarity index 100% rename from crates/sui/tests/data/dummy_modules_upgrade/Move.toml rename to crates/iota/tests/data/dummy_modules_upgrade/Move.toml diff --git a/crates/iota/tests/data/dummy_modules_upgrade/sources/trusted_coin.move b/crates/iota/tests/data/dummy_modules_upgrade/sources/trusted_coin.move new file mode 100644 index 00000000000..668678b81bc --- /dev/null +++ b/crates/iota/tests/data/dummy_modules_upgrade/sources/trusted_coin.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module examples::trusted_coin { + public fun f() { } +} diff --git a/crates/iota/tests/data/linter/Move.toml b/crates/iota/tests/data/linter/Move.toml new file mode 100644 index 00000000000..9896aa05f64 --- /dev/null +++ b/crates/iota/tests/data/linter/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "linter" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../iota-framework/packages/iota-framework" } + +[addresses] +linter = "0x0" diff --git a/crates/sui/tests/data/linter/sources/suppression_stats.move b/crates/iota/tests/data/linter/sources/suppression_stats.move similarity index 80% rename from crates/sui/tests/data/linter/sources/suppression_stats.move rename to crates/iota/tests/data/linter/sources/suppression_stats.move index 409a61669f3..e5ee1ec586d 100644 --- a/crates/sui/tests/data/linter/sources/suppression_stats.move +++ b/crates/iota/tests/data/linter/sources/suppression_stats.move @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // This file is used to test linter suppression stats output (the test itself is part of CLI tests -// in the sui crate) +// in the iota crate) #[allow(lint(custom_state_change))] module linter::suppression_stats { - use sui::object::UID; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; + use iota::object::UID; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; #[allow(unused_field)] struct S1 has key, store { diff --git a/crates/sui/tests/data/module_dependency_invalid/Move.toml b/crates/iota/tests/data/module_dependency_invalid/Move.toml similarity index 100% rename from crates/sui/tests/data/module_dependency_invalid/Move.toml rename to crates/iota/tests/data/module_dependency_invalid/Move.toml diff --git a/crates/iota/tests/data/module_dependency_invalid/sources/invalid.move b/crates/iota/tests/data/module_dependency_invalid/sources/invalid.move new file mode 100644 index 00000000000..cf2879c4cb9 --- /dev/null +++ b/crates/iota/tests/data/module_dependency_invalid/sources/invalid.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module invalid::invalid { + public entry fun main() {} +} diff --git a/crates/sui/tests/data/module_dependency_nonexistent/Move.toml b/crates/iota/tests/data/module_dependency_nonexistent/Move.toml similarity index 100% rename from crates/sui/tests/data/module_dependency_nonexistent/Move.toml rename to crates/iota/tests/data/module_dependency_nonexistent/Move.toml diff --git a/crates/iota/tests/data/module_dependency_nonexistent/sources/nonexistent.move b/crates/iota/tests/data/module_dependency_nonexistent/sources/nonexistent.move new file mode 100644 index 00000000000..f3ffd147555 --- /dev/null +++ b/crates/iota/tests/data/module_dependency_nonexistent/sources/nonexistent.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module nonexistent::nonexistent { + public entry fun main() {} +} diff --git a/crates/sui/tests/data/module_dependency_unpublished/Move.toml b/crates/iota/tests/data/module_dependency_unpublished/Move.toml similarity index 100% rename from crates/sui/tests/data/module_dependency_unpublished/Move.toml rename to crates/iota/tests/data/module_dependency_unpublished/Move.toml diff --git a/crates/iota/tests/data/module_dependency_unpublished/sources/invalid.move b/crates/iota/tests/data/module_dependency_unpublished/sources/invalid.move new file mode 100644 index 00000000000..cf2879c4cb9 --- /dev/null +++ b/crates/iota/tests/data/module_dependency_unpublished/sources/invalid.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module invalid::invalid { + public entry fun main() {} +} diff --git a/crates/sui/tests/data/module_dependency_unpublished_non_zero_address/Move.toml b/crates/iota/tests/data/module_dependency_unpublished_non_zero_address/Move.toml similarity index 100% rename from crates/sui/tests/data/module_dependency_unpublished_non_zero_address/Move.toml rename to crates/iota/tests/data/module_dependency_unpublished_non_zero_address/Move.toml diff --git a/crates/iota/tests/data/module_dependency_unpublished_non_zero_address/sources/non_zero.move b/crates/iota/tests/data/module_dependency_unpublished_non_zero_address/sources/non_zero.move new file mode 100644 index 00000000000..67c2e87a124 --- /dev/null +++ b/crates/iota/tests/data/module_dependency_unpublished_non_zero_address/sources/non_zero.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module non_zero::non_zero { + public entry fun main() {} +} diff --git a/crates/iota/tests/data/module_publish_failure_invalid/Move.toml b/crates/iota/tests/data/module_publish_failure_invalid/Move.toml new file mode 100644 index 00000000000..dfad812d9e4 --- /dev/null +++ b/crates/iota/tests/data/module_publish_failure_invalid/Move.toml @@ -0,0 +1,11 @@ +[package] +name = "Examples" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../iota-framework/packages/iota-framework" } +Invalid = { local = "../module_dependency_invalid" } +Unpublished = { local = "../module_dependency_unpublished" } + +[addresses] +examples = "0x0" diff --git a/crates/iota/tests/data/module_publish_failure_invalid/sources/main.move b/crates/iota/tests/data/module_publish_failure_invalid/sources/main.move new file mode 100644 index 00000000000..dccb5650506 --- /dev/null +++ b/crates/iota/tests/data/module_publish_failure_invalid/sources/main.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module examples::main { + public entry fun main() {} +} diff --git a/crates/iota/tests/data/module_publish_with_nonexistent_dependency/Move.toml b/crates/iota/tests/data/module_publish_with_nonexistent_dependency/Move.toml new file mode 100644 index 00000000000..b146870b59d --- /dev/null +++ b/crates/iota/tests/data/module_publish_with_nonexistent_dependency/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "Examples" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../iota-framework/packages/iota-framework" } +Nonexistent = { local = "../module_dependency_nonexistent" } + +[addresses] +examples = "0x0" diff --git a/crates/iota/tests/data/module_publish_with_nonexistent_dependency/sources/main.move b/crates/iota/tests/data/module_publish_with_nonexistent_dependency/sources/main.move new file mode 100644 index 00000000000..dccb5650506 --- /dev/null +++ b/crates/iota/tests/data/module_publish_with_nonexistent_dependency/sources/main.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module examples::main { + public entry fun main() {} +} diff --git a/crates/iota/tests/data/module_publish_with_unpublished_dependency/Move.toml b/crates/iota/tests/data/module_publish_with_unpublished_dependency/Move.toml new file mode 100644 index 00000000000..98ba20aca6a --- /dev/null +++ b/crates/iota/tests/data/module_publish_with_unpublished_dependency/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "Examples" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../iota-framework/packages/iota-framework" } +Unpublished = { local = "../module_dependency_unpublished" } + +[addresses] +examples = "0x0" diff --git a/crates/iota/tests/data/module_publish_with_unpublished_dependency/sources/main.move b/crates/iota/tests/data/module_publish_with_unpublished_dependency/sources/main.move new file mode 100644 index 00000000000..dccb5650506 --- /dev/null +++ b/crates/iota/tests/data/module_publish_with_unpublished_dependency/sources/main.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module examples::main { + public entry fun main() {} +} diff --git a/crates/iota/tests/data/module_publish_with_unpublished_dependency_with_non_zero_address/Move.toml b/crates/iota/tests/data/module_publish_with_unpublished_dependency_with_non_zero_address/Move.toml new file mode 100644 index 00000000000..445fae403d7 --- /dev/null +++ b/crates/iota/tests/data/module_publish_with_unpublished_dependency_with_non_zero_address/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "Examples" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../iota-framework/packages/iota-framework" } +UnpublishedNonZeroAddress = { local = "../module_dependency_unpublished_non_zero_address" } + +[addresses] +examples = "0x0" diff --git a/crates/iota/tests/data/module_publish_with_unpublished_dependency_with_non_zero_address/sources/main.move b/crates/iota/tests/data/module_publish_with_unpublished_dependency_with_non_zero_address/sources/main.move new file mode 100644 index 00000000000..dccb5650506 --- /dev/null +++ b/crates/iota/tests/data/module_publish_with_unpublished_dependency_with_non_zero_address/sources/main.move @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module examples::main { + public entry fun main() {} +} diff --git a/crates/iota/tests/data/move_call_args_linter/Move.toml b/crates/iota/tests/data/move_call_args_linter/Move.toml new file mode 100644 index 00000000000..e518fc169a9 --- /dev/null +++ b/crates/iota/tests/data/move_call_args_linter/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "Examples" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../iota-framework/packages/iota-framework" } + +[addresses] +examples = "0x0" diff --git a/crates/iota/tests/data/move_call_args_linter/sources/object_basics.move b/crates/iota/tests/data/move_call_args_linter/sources/object_basics.move new file mode 100644 index 00000000000..257c083f789 --- /dev/null +++ b/crates/iota/tests/data/move_call_args_linter/sources/object_basics.move @@ -0,0 +1,66 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// Test CTURD object basics (create, transfer, update, read, delete) +module examples::object_basics { + use iota::event; + use iota::object::{Self, UID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer; + + struct Object has key, store { + id: UID, + value: u64, + } + + struct Wrapper has key { + id: UID, + o: Object + } + + struct NewValueEvent has copy, drop { + new_value: u64 + } + + public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { + transfer::public_transfer( + Object { id: object::new(ctx), value }, + recipient + ) + } + + public entry fun transfer(o: Object, recipient: address) { + transfer::public_transfer(o, recipient) + } + + public entry fun freeze_object(o: Object) { + transfer::public_freeze_object(o) + } + + public entry fun set_value(o: &mut Object, value: u64) { + o.value = value; + } + + // test that reading o2 and updating o1 works + public entry fun update(o1: &mut Object, o2: &Object) { + o1.value = o2.value; + // emit an event so the world can see the new value + event::emit(NewValueEvent { new_value: o2.value }) + } + + public entry fun delete(o: Object) { + let Object { id, value: _ } = o; + object::delete(id); + } + + public entry fun wrap(o: Object, ctx: &mut TxContext) { + transfer::transfer(Wrapper { id: object::new(ctx), o }, tx_context::sender(ctx)) + } + + public entry fun unwrap(w: Wrapper, ctx: &mut TxContext) { + let Wrapper { id, o } = w; + object::delete(id); + transfer::public_transfer(o, tx_context::sender(ctx)) + } +} diff --git a/crates/iota/tests/data/ptb_complex_args_test_functions/Move.toml b/crates/iota/tests/data/ptb_complex_args_test_functions/Move.toml new file mode 100644 index 00000000000..78b1b1bdff4 --- /dev/null +++ b/crates/iota/tests/data/ptb_complex_args_test_functions/Move.toml @@ -0,0 +1,8 @@ +[package] +name = "test_functions" + +[dependencies] +Iota = { local = "../../../../iota-framework/packages/iota-framework" } + +[addresses] +test_functions = "0x0" diff --git a/crates/iota/tests/data/ptb_complex_args_test_functions/sources/test_module.move b/crates/iota/tests/data/ptb_complex_args_test_functions/sources/test_module.move new file mode 100644 index 00000000000..c6d6b9727d7 --- /dev/null +++ b/crates/iota/tests/data/ptb_complex_args_test_functions/sources/test_module.move @@ -0,0 +1,40 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module test_functions::test_module { + use iota::object::{Self, UID}; + use iota::tx_context::TxContext; + use iota::transfer; + use std::ascii::String as AS; + use std::string::String as US; + + struct Shared has key, store { + id: UID, + } + + public fun new_shared(ctx: &mut TxContext) { + transfer::share_object(Shared { id: object::new(ctx) }) + } + + public fun use_immut(_: &Shared) { + // do nothing + } + + public fun use_mut(_: &mut Shared) { + // do nothing + } + + public fun use_ascii_string(_: AS) { + // do nothing + } + + public fun use_utf8_string(_: US) { + // do nothing + } + + public fun delete_shared_object(shared: Shared) { + let Shared { id } = shared; + object::delete(id); + } +} diff --git a/crates/iota/tests/data/sod/Move.toml b/crates/iota/tests/data/sod/Move.toml new file mode 100644 index 00000000000..9cc790b3acb --- /dev/null +++ b/crates/iota/tests/data/sod/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "sod" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../iota-framework/packages/iota-framework" } + +[addresses] +sod = "0x0" diff --git a/crates/iota/tests/data/sod/sources/sod.move b/crates/iota/tests/data/sod/sources/sod.move new file mode 100644 index 00000000000..e262ffa612d --- /dev/null +++ b/crates/iota/tests/data/sod/sources/sod.move @@ -0,0 +1,23 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module sod::sod { + use iota::object::{Self, UID}; + use iota::tx_context::TxContext; + use iota::transfer; + + struct A has key, store { + id: UID, + } + + public fun start(ctx: &mut TxContext) { + let a = A { id: object::new(ctx) }; + transfer::public_share_object(a); + } + + public entry fun delete(a: A) { + let A { id } = a; + object::delete(id); + } +} diff --git a/crates/iota/tests/data/tto/Move.toml b/crates/iota/tests/data/tto/Move.toml new file mode 100644 index 00000000000..0ef57a7bba5 --- /dev/null +++ b/crates/iota/tests/data/tto/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "tto" +version = "0.0.1" + +[dependencies] +Iota = { local = "../../../../iota-framework/packages/iota-framework" } + +[addresses] +tto = "0x0" diff --git a/crates/iota/tests/data/tto/sources/tto1.move b/crates/iota/tests/data/tto/sources/tto1.move new file mode 100644 index 00000000000..0cc3c6360a5 --- /dev/null +++ b/crates/iota/tests/data/tto/sources/tto1.move @@ -0,0 +1,33 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module tto::tto { + use iota::object::{Self, UID}; + use iota::tx_context::{Self, TxContext}; + use iota::transfer::{Self, Receiving}; + + struct A has key, store { + id: UID, + } + + struct B has key, store { + id: UID, + } + + public fun start(ctx: &mut TxContext) { + let a = A { id: object::new(ctx) }; + let a_address = object::id_address(&a); + let b = B { id: object::new(ctx) }; + transfer::public_transfer(a, tx_context::sender(ctx)); + transfer::public_transfer(b, a_address); + } + + public entry fun receiver(parent: &mut A, x: Receiving) { + let b = transfer::receive(&mut parent.id, x); + transfer::public_transfer(b, @tto); + } + + public fun invalid_call_immut_ref(_parent: &mut A, _x: &Receiving) { } + public fun invalid_call_mut_ref(_parent: &mut A, _x: &mut Receiving) { } +} diff --git a/crates/sui/tests/ptb_files/assign/assign_invalid.ptb b/crates/iota/tests/ptb_files/assign/assign_invalid.ptb similarity index 100% rename from crates/sui/tests/ptb_files/assign/assign_invalid.ptb rename to crates/iota/tests/ptb_files/assign/assign_invalid.ptb diff --git a/crates/sui/tests/ptb_files/assign/assign_valid.ptb b/crates/iota/tests/ptb_files/assign/assign_valid.ptb similarity index 100% rename from crates/sui/tests/ptb_files/assign/assign_valid.ptb rename to crates/iota/tests/ptb_files/assign/assign_valid.ptb diff --git a/crates/sui/tests/ptb_files/assign/basic_assign.ptb b/crates/iota/tests/ptb_files/assign/basic_assign.ptb similarity index 100% rename from crates/sui/tests/ptb_files/assign/basic_assign.ptb rename to crates/iota/tests/ptb_files/assign/basic_assign.ptb diff --git a/crates/sui/tests/ptb_files/assign/shadow_warnings.ptb b/crates/iota/tests/ptb_files/assign/shadow_warnings.ptb similarity index 100% rename from crates/sui/tests/ptb_files/assign/shadow_warnings.ptb rename to crates/iota/tests/ptb_files/assign/shadow_warnings.ptb diff --git a/crates/sui/tests/ptb_files/bad_ptb.ptb b/crates/iota/tests/ptb_files/bad_ptb.ptb similarity index 100% rename from crates/sui/tests/ptb_files/bad_ptb.ptb rename to crates/iota/tests/ptb_files/bad_ptb.ptb diff --git a/crates/sui/tests/ptb_files/comments/ptb_with_comments.ptb b/crates/iota/tests/ptb_files/comments/ptb_with_comments.ptb similarity index 100% rename from crates/sui/tests/ptb_files/comments/ptb_with_comments.ptb rename to crates/iota/tests/ptb_files/comments/ptb_with_comments.ptb diff --git a/crates/sui/tests/ptb_files/gas/gas_outside_range.ptb b/crates/iota/tests/ptb_files/gas/gas_outside_range.ptb similarity index 100% rename from crates/sui/tests/ptb_files/gas/gas_outside_range.ptb rename to crates/iota/tests/ptb_files/gas/gas_outside_range.ptb diff --git a/crates/sui/tests/ptb_files/gas/no_gas_picker.ptb b/crates/iota/tests/ptb_files/gas/no_gas_picker.ptb similarity index 100% rename from crates/sui/tests/ptb_files/gas/no_gas_picker.ptb rename to crates/iota/tests/ptb_files/gas/no_gas_picker.ptb diff --git a/crates/sui/tests/ptb_files/gas/non_integer_gas_budget.ptb b/crates/iota/tests/ptb_files/gas/non_integer_gas_budget.ptb similarity index 100% rename from crates/sui/tests/ptb_files/gas/non_integer_gas_budget.ptb rename to crates/iota/tests/ptb_files/gas/non_integer_gas_budget.ptb diff --git a/crates/sui/tests/ptb_files/gas/valid_gas.ptb b/crates/iota/tests/ptb_files/gas/valid_gas.ptb similarity index 100% rename from crates/sui/tests/ptb_files/gas/valid_gas.ptb rename to crates/iota/tests/ptb_files/gas/valid_gas.ptb diff --git a/crates/sui/tests/ptb_files/make_move_vec/make_move_vec.ptb b/crates/iota/tests/ptb_files/make_move_vec/make_move_vec.ptb similarity index 92% rename from crates/sui/tests/ptb_files/make_move_vec/make_move_vec.ptb rename to crates/iota/tests/ptb_files/make_move_vec/make_move_vec.ptb index c6ce62ecb9b..4250e366ac5 100644 --- a/crates/sui/tests/ptb_files/make_move_vec/make_move_vec.ptb +++ b/crates/iota/tests/ptb_files/make_move_vec/make_move_vec.ptb @@ -14,4 +14,4 @@ --make-move-vec > [none,some(1)] --make-move-vec > [none,some(some(1))] # Can have non-pure values inside of arrays ---make-move-vec > [gas] +--make-move-vec > [gas] diff --git a/crates/sui/tests/ptb_files/make_move_vec/make_move_vec_invalid.ptb b/crates/iota/tests/ptb_files/make_move_vec/make_move_vec_invalid.ptb similarity index 100% rename from crates/sui/tests/ptb_files/make_move_vec/make_move_vec_invalid.ptb rename to crates/iota/tests/ptb_files/make_move_vec/make_move_vec_invalid.ptb diff --git a/crates/sui/tests/ptb_files/make_move_vec/make_move_vec_invalid_args.ptb b/crates/iota/tests/ptb_files/make_move_vec/make_move_vec_invalid_args.ptb similarity index 100% rename from crates/sui/tests/ptb_files/make_move_vec/make_move_vec_invalid_args.ptb rename to crates/iota/tests/ptb_files/make_move_vec/make_move_vec_invalid_args.ptb diff --git a/crates/sui/tests/ptb_files/make_move_vec/resolve_array_inside_array.ptb b/crates/iota/tests/ptb_files/make_move_vec/resolve_array_inside_array.ptb similarity index 100% rename from crates/sui/tests/ptb_files/make_move_vec/resolve_array_inside_array.ptb rename to crates/iota/tests/ptb_files/make_move_vec/resolve_array_inside_array.ptb diff --git a/crates/sui/tests/ptb_files/make_move_vec/resolve_array_inside_array_through_bindings.ptb b/crates/iota/tests/ptb_files/make_move_vec/resolve_array_inside_array_through_bindings.ptb similarity index 100% rename from crates/sui/tests/ptb_files/make_move_vec/resolve_array_inside_array_through_bindings.ptb rename to crates/iota/tests/ptb_files/make_move_vec/resolve_array_inside_array_through_bindings.ptb diff --git a/crates/sui/tests/ptb_files/merge_coins/merge_coins_invalid_args.ptb b/crates/iota/tests/ptb_files/merge_coins/merge_coins_invalid_args.ptb similarity index 100% rename from crates/sui/tests/ptb_files/merge_coins/merge_coins_invalid_args.ptb rename to crates/iota/tests/ptb_files/merge_coins/merge_coins_invalid_args.ptb diff --git a/crates/sui/tests/ptb_files/merge_coins/merge_coins_valid.ptb b/crates/iota/tests/ptb_files/merge_coins/merge_coins_valid.ptb similarity index 100% rename from crates/sui/tests/ptb_files/merge_coins/merge_coins_valid.ptb rename to crates/iota/tests/ptb_files/merge_coins/merge_coins_valid.ptb diff --git a/crates/sui/tests/ptb_files/move_call/move_call.ptb b/crates/iota/tests/ptb_files/move_call/move_call.ptb similarity index 100% rename from crates/sui/tests/ptb_files/move_call/move_call.ptb rename to crates/iota/tests/ptb_files/move_call/move_call.ptb diff --git a/crates/sui/tests/ptb_files/move_call/move_call_fun_resolution.ptb b/crates/iota/tests/ptb_files/move_call/move_call_fun_resolution.ptb similarity index 94% rename from crates/sui/tests/ptb_files/move_call/move_call_fun_resolution.ptb rename to crates/iota/tests/ptb_files/move_call/move_call_fun_resolution.ptb index 0503799dd7b..4f461f9f080 100644 --- a/crates/sui/tests/ptb_files/move_call/move_call_fun_resolution.ptb +++ b/crates/iota/tests/ptb_files/move_call/move_call_fun_resolution.ptb @@ -14,6 +14,6 @@ # Too many arguments --move-call std::option::is_none "a b" # Missing type argument -- we ---move-call sui::coin::destroy_zero @0x1 +--move-call iota::coin::destroy_zero @0x1 # Too many type args -- won't catch this until we run --move-call std::option::is_none a diff --git a/crates/sui/tests/ptb_files/move_call/move_call_parsing.ptb b/crates/iota/tests/ptb_files/move_call/move_call_parsing.ptb similarity index 100% rename from crates/sui/tests/ptb_files/move_call/move_call_parsing.ptb rename to crates/iota/tests/ptb_files/move_call/move_call_parsing.ptb diff --git a/crates/sui/tests/ptb_files/parsing/invalid_commands.ptb b/crates/iota/tests/ptb_files/parsing/invalid_commands.ptb similarity index 100% rename from crates/sui/tests/ptb_files/parsing/invalid_commands.ptb rename to crates/iota/tests/ptb_files/parsing/invalid_commands.ptb diff --git a/crates/sui/tests/ptb_files/parsing/invalid_types.ptb b/crates/iota/tests/ptb_files/parsing/invalid_types.ptb similarity index 100% rename from crates/sui/tests/ptb_files/parsing/invalid_types.ptb rename to crates/iota/tests/ptb_files/parsing/invalid_types.ptb diff --git a/crates/sui/tests/ptb_files/parsing/keywords.ptb b/crates/iota/tests/ptb_files/parsing/keywords.ptb similarity index 100% rename from crates/sui/tests/ptb_files/parsing/keywords.ptb rename to crates/iota/tests/ptb_files/parsing/keywords.ptb diff --git a/crates/sui/tests/ptb_files/parsing/multiple_function_args.ptb b/crates/iota/tests/ptb_files/parsing/multiple_function_args.ptb similarity index 100% rename from crates/sui/tests/ptb_files/parsing/multiple_function_args.ptb rename to crates/iota/tests/ptb_files/parsing/multiple_function_args.ptb diff --git a/crates/sui/tests/ptb_files/parsing/not_keywords.ptb b/crates/iota/tests/ptb_files/parsing/not_keywords.ptb similarity index 100% rename from crates/sui/tests/ptb_files/parsing/not_keywords.ptb rename to crates/iota/tests/ptb_files/parsing/not_keywords.ptb diff --git a/crates/sui/tests/ptb_files/parsing/quote_escapes.ptb b/crates/iota/tests/ptb_files/parsing/quote_escapes.ptb similarity index 100% rename from crates/sui/tests/ptb_files/parsing/quote_escapes.ptb rename to crates/iota/tests/ptb_files/parsing/quote_escapes.ptb diff --git a/crates/sui/tests/ptb_files/parsing/valid_types.ptb b/crates/iota/tests/ptb_files/parsing/valid_types.ptb similarity index 100% rename from crates/sui/tests/ptb_files/parsing/valid_types.ptb rename to crates/iota/tests/ptb_files/parsing/valid_types.ptb diff --git a/crates/iota/tests/ptb_files/parsing/whitespace_handling.ptb b/crates/iota/tests/ptb_files/parsing/whitespace_handling.ptb new file mode 100644 index 00000000000..c89214048fa --- /dev/null +++ b/crates/iota/tests/ptb_files/parsing/whitespace_handling.ptb @@ -0,0 +1,17 @@ +# Note: Yes, it looks messed up -- it should so don't try and format this nicely! + +# Make sure we handle weird spacing inside vectors and arrays +--assign x vector[1, 2, 3,4 ] +--assign x "vector[1, 2, 3,4 ]" +--assign x "vector['1', '2, 3','',\"4 \"]" +--assign x "vector['1', '2, 3','',\"4 + \"]" + +# Same tests but with arrays +--make-move-vec [1, 2, 3,4 ] +--make-move-vec "[1, 2, 3,4 ]" +--make-move-vec "['1', '2, 3','',\"4 \"]" +--make-move-vec "['1', '2, 3','',\"4 + \"]" + +--gas-budget 100 diff --git a/crates/sui/tests/ptb_files/publish/publish_non_existent_package.ptb b/crates/iota/tests/ptb_files/publish/publish_non_existent_package.ptb similarity index 100% rename from crates/sui/tests/ptb_files/publish/publish_non_existent_package.ptb rename to crates/iota/tests/ptb_files/publish/publish_non_existent_package.ptb diff --git a/crates/sui/tests/ptb_files/publish/publish_not_a_package.ptb b/crates/iota/tests/ptb_files/publish/publish_not_a_package.ptb similarity index 100% rename from crates/sui/tests/ptb_files/publish/publish_not_a_package.ptb rename to crates/iota/tests/ptb_files/publish/publish_not_a_package.ptb diff --git a/crates/sui/tests/ptb_files/publish/publish_too_many_args.ptb b/crates/iota/tests/ptb_files/publish/publish_too_many_args.ptb similarity index 100% rename from crates/sui/tests/ptb_files/publish/publish_too_many_args.ptb rename to crates/iota/tests/ptb_files/publish/publish_too_many_args.ptb diff --git a/crates/sui/tests/ptb_files/publish/publish_valid.ptb b/crates/iota/tests/ptb_files/publish/publish_valid.ptb similarity index 100% rename from crates/sui/tests/ptb_files/publish/publish_valid.ptb rename to crates/iota/tests/ptb_files/publish/publish_valid.ptb diff --git a/crates/sui/tests/ptb_files/publish/test_pkg/Move.toml b/crates/iota/tests/ptb_files/publish/test_pkg/Move.toml similarity index 100% rename from crates/sui/tests/ptb_files/publish/test_pkg/Move.toml rename to crates/iota/tests/ptb_files/publish/test_pkg/Move.toml diff --git a/crates/iota/tests/ptb_files/publish/test_pkg/sources/a.move b/crates/iota/tests/ptb_files/publish/test_pkg/sources/a.move new file mode 100644 index 00000000000..3bddcf4a0fc --- /dev/null +++ b/crates/iota/tests/ptb_files/publish/test_pkg/sources/a.move @@ -0,0 +1,5 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module test_pkg::a { } diff --git a/crates/sui/tests/ptb_files/resolution/keyword_resolution.ptb b/crates/iota/tests/ptb_files/resolution/keyword_resolution.ptb similarity index 100% rename from crates/sui/tests/ptb_files/resolution/keyword_resolution.ptb rename to crates/iota/tests/ptb_files/resolution/keyword_resolution.ptb diff --git a/crates/sui/tests/ptb_files/resolution/variable_resolution_fixing.ptb b/crates/iota/tests/ptb_files/resolution/variable_resolution_fixing.ptb similarity index 76% rename from crates/sui/tests/ptb_files/resolution/variable_resolution_fixing.ptb rename to crates/iota/tests/ptb_files/resolution/variable_resolution_fixing.ptb index 1218dce77bb..9ca4440890e 100644 --- a/crates/sui/tests/ptb_files/resolution/variable_resolution_fixing.ptb +++ b/crates/iota/tests/ptb_files/resolution/variable_resolution_fixing.ptb @@ -1,5 +1,5 @@ --assign s @0x1 ---move-call sui::coin::value s +--move-call iota::coin::value s # Make sure that the second usage of 's' here binds to/uses the same input as the move call above --make-move-vec
    [s] diff --git a/crates/sui/tests/ptb_files/resolution/variable_shadowing.ptb b/crates/iota/tests/ptb_files/resolution/variable_shadowing.ptb similarity index 75% rename from crates/sui/tests/ptb_files/resolution/variable_shadowing.ptb rename to crates/iota/tests/ptb_files/resolution/variable_shadowing.ptb index 97b70e08d80..6fae76f7356 100644 --- a/crates/sui/tests/ptb_files/resolution/variable_shadowing.ptb +++ b/crates/iota/tests/ptb_files/resolution/variable_shadowing.ptb @@ -1,5 +1,5 @@ --assign s @0x1 ---move-call sui::coin::destroy_zero s +--move-call iota::coin::destroy_zero s --assign s @0x2 # Make sure that the second usage of 's' here is not the same as the first definition of 's' --make-move-vec
    [s] diff --git a/crates/sui/tests/ptb_files/split_coins/split_coins_invalid.ptb b/crates/iota/tests/ptb_files/split_coins/split_coins_invalid.ptb similarity index 100% rename from crates/sui/tests/ptb_files/split_coins/split_coins_invalid.ptb rename to crates/iota/tests/ptb_files/split_coins/split_coins_invalid.ptb diff --git a/crates/iota/tests/ptb_files/split_coins/split_coins_valid.ptb b/crates/iota/tests/ptb_files/split_coins/split_coins_valid.ptb new file mode 100644 index 00000000000..0c5e17857f4 --- /dev/null +++ b/crates/iota/tests/ptb_files/split_coins/split_coins_valid.ptb @@ -0,0 +1,12 @@ +# Split off from gas +--split-coins gas [0,1,2,3] +--assign coins +--move-call iota::coin::destroy_zero coins.0 +# Can further split a split coin (and through variable bindings/result accesses) +--split-coins coins.1 [0,0] +--assign zcoins +--move-call iota::coin::destroy_zero zcoins.0 +--move-call iota::coin::destroy_zero zcoins.1 +# Can merge the split coins back +--merge-coins gas [coins.1, coins.2, coins.3] +--gas-budget 10000000 diff --git a/crates/sui/tests/ptb_files/transfer_objects/transfer_objects_invalid.ptb b/crates/iota/tests/ptb_files/transfer_objects/transfer_objects_invalid.ptb similarity index 100% rename from crates/sui/tests/ptb_files/transfer_objects/transfer_objects_invalid.ptb rename to crates/iota/tests/ptb_files/transfer_objects/transfer_objects_invalid.ptb diff --git a/crates/sui/tests/ptb_files/transfer_objects/transfer_objects_valid.ptb b/crates/iota/tests/ptb_files/transfer_objects/transfer_objects_valid.ptb similarity index 100% rename from crates/sui/tests/ptb_files/transfer_objects/transfer_objects_valid.ptb rename to crates/iota/tests/ptb_files/transfer_objects/transfer_objects_valid.ptb diff --git a/crates/sui/tests/ptb_files_tests.rs b/crates/iota/tests/ptb_files_tests.rs similarity index 96% rename from crates/sui/tests/ptb_files_tests.rs rename to crates/iota/tests/ptb_files_tests.rs index b526801899c..2e5c28512ae 100644 --- a/crates/sui/tests/ptb_files_tests.rs +++ b/crates/iota/tests/ptb_files_tests.rs @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[cfg(not(msim))] use std::path::Path; #[cfg(not(msim))] -use sui_types::transaction::{CallArg, ObjectArg}; +use iota_types::transaction::{CallArg, ObjectArg}; #[cfg(not(msim))] const TEST_DIR: &str = "tests"; @@ -13,7 +14,7 @@ const TEST_DIR: &str = "tests"; #[cfg(not(msim))] #[tokio::main] async fn test_ptb_files(path: &Path) -> datatest_stable::Result<()> { - use sui::client_ptb::{ + use iota::client_ptb::{ error::build_error_reports, ptb::{to_source_string, PTBPreview, PTB}, }; diff --git a/crates/sui/tests/snapshots/ptb_files_tests__assign_cross_files.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__assign_cross_files.ptb.snap similarity index 95% rename from crates/sui/tests/snapshots/ptb_files_tests__assign_cross_files.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__assign_cross_files.ptb.snap index 83ab229d61d..452429cc28a 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__assign_cross_files.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__assign_cross_files.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__assign_invalid.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__assign_invalid.ptb.snap similarity index 98% rename from crates/sui/tests/snapshots/ptb_files_tests__assign_invalid.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__assign_invalid.ptb.snap index 836a46711cc..fa826e19719 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__assign_invalid.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__assign_invalid.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__assign_valid.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__assign_valid.ptb.snap similarity index 97% rename from crates/sui/tests/snapshots/ptb_files_tests__assign_valid.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__assign_valid.ptb.snap index 674f749d901..52c8c6d4365 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__assign_valid.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__assign_valid.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__bad_ptb.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__bad_ptb.ptb.snap similarity index 97% rename from crates/sui/tests/snapshots/ptb_files_tests__bad_ptb.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__bad_ptb.ptb.snap index 70f3b8b7991..e79067bdd9a 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__bad_ptb.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__bad_ptb.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__basic_assign.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__basic_assign.ptb.snap similarity index 96% rename from crates/sui/tests/snapshots/ptb_files_tests__basic_assign.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__basic_assign.ptb.snap index d4feaf5575b..ff0bfe0512f 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__basic_assign.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__basic_assign.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__gas_outside_range.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__gas_outside_range.ptb.snap similarity index 95% rename from crates/sui/tests/snapshots/ptb_files_tests__gas_outside_range.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__gas_outside_range.ptb.snap index 2ff0911b80c..8de6ae920f7 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__gas_outside_range.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__gas_outside_range.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__invalid_commands.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__invalid_commands.ptb.snap similarity index 97% rename from crates/sui/tests/snapshots/ptb_files_tests__invalid_commands.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__invalid_commands.ptb.snap index 126c760e383..7c084c07539 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__invalid_commands.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__invalid_commands.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__invalid_types.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__invalid_types.ptb.snap similarity index 99% rename from crates/sui/tests/snapshots/ptb_files_tests__invalid_types.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__invalid_types.ptb.snap index 44689ad5e9e..fa19b4d237a 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__invalid_types.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__invalid_types.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__keyword_resolution.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__keyword_resolution.ptb.snap similarity index 94% rename from crates/sui/tests/snapshots/ptb_files_tests__keyword_resolution.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__keyword_resolution.ptb.snap index 9790fb17a79..be414b965ee 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__keyword_resolution.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__keyword_resolution.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__keywords.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__keywords.ptb.snap similarity index 97% rename from crates/sui/tests/snapshots/ptb_files_tests__keywords.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__keywords.ptb.snap index d4ac2236af3..562b20da3a9 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__keywords.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__keywords.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__make_move_vec.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__make_move_vec.ptb.snap similarity index 94% rename from crates/sui/tests/snapshots/ptb_files_tests__make_move_vec.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__make_move_vec.ptb.snap index b1e26108dc7..2abc4b2ba93 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__make_move_vec.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__make_move_vec.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === @@ -17,7 +17,7 @@ expression: "results.join(\"\\n\")" │ make-move-vec │ > [none, none] │ │ make-move-vec │ > [none, some(1u64)] │ │ make-move-vec │ > [none, some(some(1u64))] │ -│ make-move-vec │ > [gas] │ +│ make-move-vec │ > [gas] │ ├───────────────┼─────────────────────────────────────────────────────┤ │ gas-budget │ 1000 │ ╰───────────────┴─────────────────────────────────────────────────────╯ @@ -44,4 +44,4 @@ Command 5: MakeMoveVec(Some0x1::option::Option,[Input(10),Input(10)]) Command 6: MakeMoveVec(Some0x1::option::Option,[Input(10),Input(10)]) Command 7: MakeMoveVec(Some0x1::option::Option,[Input(10),Input(11)]) Command 8: MakeMoveVec(Some0x1::option::Option,[Input(10),Input(12)]) -Command 9: MakeMoveVec(Some0x2::coin::Coin<0x2::sui::SUI>,[GasCoin]) +Command 9: MakeMoveVec(Some0x2::coin::Coin<0x2::iota::IOTA>,[GasCoin]) diff --git a/crates/sui/tests/snapshots/ptb_files_tests__make_move_vec_invalid.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__make_move_vec_invalid.ptb.snap similarity index 97% rename from crates/sui/tests/snapshots/ptb_files_tests__make_move_vec_invalid.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__make_move_vec_invalid.ptb.snap index 622f3e6bf88..fbce24934d3 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__make_move_vec_invalid.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__make_move_vec_invalid.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__make_move_vec_invalid_args.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__make_move_vec_invalid_args.ptb.snap similarity index 97% rename from crates/sui/tests/snapshots/ptb_files_tests__make_move_vec_invalid_args.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__make_move_vec_invalid_args.ptb.snap index 48cf7978c97..ec94d47fb28 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__make_move_vec_invalid_args.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__make_move_vec_invalid_args.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__merge_coins_invalid_args.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__merge_coins_invalid_args.ptb.snap similarity index 93% rename from crates/sui/tests/snapshots/ptb_files_tests__merge_coins_invalid_args.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__merge_coins_invalid_args.ptb.snap index 60f6bc8496b..00c68b03698 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__merge_coins_invalid_args.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__merge_coins_invalid_args.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__merge_coins_valid.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__merge_coins_valid.ptb.snap similarity index 97% rename from crates/sui/tests/snapshots/ptb_files_tests__merge_coins_valid.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__merge_coins_valid.ptb.snap index b38d920674d..d590bb529d1 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__merge_coins_valid.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__merge_coins_valid.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__move_call.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__move_call.ptb.snap similarity index 97% rename from crates/sui/tests/snapshots/ptb_files_tests__move_call.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__move_call.ptb.snap index 4be161e9220..e57fad5f126 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__move_call.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__move_call.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__move_call_fun_resolution.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__move_call_fun_resolution.ptb.snap similarity index 95% rename from crates/sui/tests/snapshots/ptb_files_tests__move_call_fun_resolution.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__move_call_fun_resolution.ptb.snap index 200356fd1cc..3f5c01e3964 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__move_call_fun_resolution.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__move_call_fun_resolution.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === @@ -16,7 +16,7 @@ expression: "results.join(\"\\n\")" │ move-call │ std::option::isnone a │ │ move-call │ std::option::is_none │ │ move-call │ std::option::is_none a b │ -│ move-call │ sui::coin::destroy_zero @0x1 │ +│ move-call │ iota::coin::destroy_zero @0x1 │ │ move-call │ std::option::is_none a │ ├────────────┼────────────────────────────────────────┤ │ gas-budget │ 1000 │ @@ -78,13 +78,13 @@ expression: "results.join(\"\\n\")" 9 │ --move-call std::option::is_none a b · ─┬─ · ╰── Expected 1 argument, but got 2 - 10 │ --move-call sui::coin::destroy_zero @0x1 + 10 │ --move-call iota::coin::destroy_zero @0x1 ╰──── × Error when processing PTB ╭─[10:37] 9 │ --move-call std::option::is_none a b - 10 │ --move-call sui::coin::destroy_zero @0x1 + 10 │ --move-call iota::coin::destroy_zero @0x1 · ──┬─ · ╰── Not enough type parameters supplied for Move call 11 │ --move-call std::option::is_none a diff --git a/crates/sui/tests/snapshots/ptb_files_tests__move_call_parsing.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__move_call_parsing.ptb.snap similarity index 88% rename from crates/sui/tests/snapshots/ptb_files_tests__move_call_parsing.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__move_call_parsing.ptb.snap index 03e4be538f9..ec136b63177 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__move_call_parsing.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__move_call_parsing.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__multiple_function_args.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__multiple_function_args.ptb.snap similarity index 98% rename from crates/sui/tests/snapshots/ptb_files_tests__multiple_function_args.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__multiple_function_args.ptb.snap index 1727ace9109..16ee8f35532 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__multiple_function_args.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__multiple_function_args.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__no_gas_picker.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__no_gas_picker.ptb.snap similarity index 93% rename from crates/sui/tests/snapshots/ptb_files_tests__no_gas_picker.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__no_gas_picker.ptb.snap index 8558c3a3613..11158562cfd 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__no_gas_picker.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__no_gas_picker.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__non_integer_gas_budget.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__non_integer_gas_budget.ptb.snap similarity index 91% rename from crates/sui/tests/snapshots/ptb_files_tests__non_integer_gas_budget.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__non_integer_gas_budget.ptb.snap index c4942541956..12b983eb394 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__non_integer_gas_budget.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__non_integer_gas_budget.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__not_keywords.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__not_keywords.ptb.snap similarity index 95% rename from crates/sui/tests/snapshots/ptb_files_tests__not_keywords.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__not_keywords.ptb.snap index 101baa222dc..4f52e80008e 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__not_keywords.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__not_keywords.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__ptb_with_comments.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__ptb_with_comments.ptb.snap similarity index 96% rename from crates/sui/tests/snapshots/ptb_files_tests__ptb_with_comments.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__ptb_with_comments.ptb.snap index 86bce195b47..6abfb1298eb 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__ptb_with_comments.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__ptb_with_comments.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__publish_non_existent_package.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__publish_non_existent_package.ptb.snap similarity index 95% rename from crates/sui/tests/snapshots/ptb_files_tests__publish_non_existent_package.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__publish_non_existent_package.ptb.snap index 92ae6f8183d..7e19919bd9c 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__publish_non_existent_package.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__publish_non_existent_package.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__publish_not_a_package.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__publish_not_a_package.ptb.snap similarity index 90% rename from crates/sui/tests/snapshots/ptb_files_tests__publish_not_a_package.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__publish_not_a_package.ptb.snap index 4d4c0e74fb4..e1f3762beaa 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__publish_not_a_package.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__publish_not_a_package.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__publish_too_many_args.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__publish_too_many_args.ptb.snap similarity index 88% rename from crates/sui/tests/snapshots/ptb_files_tests__publish_too_many_args.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__publish_too_many_args.ptb.snap index 0d2136d2fcf..66edce1940d 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__publish_too_many_args.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__publish_too_many_args.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__publish_valid.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__publish_valid.ptb.snap similarity index 95% rename from crates/sui/tests/snapshots/ptb_files_tests__publish_valid.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__publish_valid.ptb.snap index b123f5b1921..99256cbcbd4 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__publish_valid.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__publish_valid.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__quote_escapes.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__quote_escapes.ptb.snap similarity index 94% rename from crates/sui/tests/snapshots/ptb_files_tests__quote_escapes.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__quote_escapes.ptb.snap index 717763c3c1b..6440a828130 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__quote_escapes.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__quote_escapes.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__resolve_array_inside_array.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__resolve_array_inside_array.ptb.snap similarity index 89% rename from crates/sui/tests/snapshots/ptb_files_tests__resolve_array_inside_array.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__resolve_array_inside_array.ptb.snap index e05d349e727..aa22164b609 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__resolve_array_inside_array.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__resolve_array_inside_array.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__resolve_array_inside_array_through_bindings.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__resolve_array_inside_array_through_bindings.ptb.snap similarity index 96% rename from crates/sui/tests/snapshots/ptb_files_tests__resolve_array_inside_array_through_bindings.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__resolve_array_inside_array_through_bindings.ptb.snap index 525c326695a..be4558d0dd5 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__resolve_array_inside_array_through_bindings.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__resolve_array_inside_array_through_bindings.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__shadow_warnings.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__shadow_warnings.ptb.snap similarity index 97% rename from crates/sui/tests/snapshots/ptb_files_tests__shadow_warnings.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__shadow_warnings.ptb.snap index 5f5003389fe..5e33ed58ca9 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__shadow_warnings.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__shadow_warnings.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__split_coins_invalid.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__split_coins_invalid.ptb.snap similarity index 96% rename from crates/sui/tests/snapshots/ptb_files_tests__split_coins_invalid.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__split_coins_invalid.ptb.snap index 1c6634b52fc..6367a127acb 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__split_coins_invalid.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__split_coins_invalid.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__split_coins_valid.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__split_coins_valid.ptb.snap similarity index 81% rename from crates/sui/tests/snapshots/ptb_files_tests__split_coins_valid.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__split_coins_valid.ptb.snap index f097b40c251..2eda16e0953 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__split_coins_valid.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__split_coins_valid.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === @@ -10,11 +10,11 @@ expression: "results.join(\"\\n\")" ├─────────────┼─────────────────────────────────────────────────┤ │ split-coins │ gas [0u64, 1u64, 2u64, 3u64] │ │ assign │ coins │ -│ move-call │ sui::coin::destroy_zero coins.0 │ +│ move-call │ iota::coin::destroy_zero coins.0 │ │ split-coins │ coins.1 [0u64, 0u64] │ │ assign │ zcoins │ -│ move-call │ sui::coin::destroy_zero zcoins.0 │ -│ move-call │ sui::coin::destroy_zero zcoins.1 │ +│ move-call │ iota::coin::destroy_zero zcoins.0 │ +│ move-call │ iota::coin::destroy_zero zcoins.1 │ │ merge-coins │ gas [coins.1, coins.2, coins.3] │ ├─────────────┼─────────────────────────────────────────────────┤ │ gas-budget │ 10000000 │ @@ -25,8 +25,8 @@ Input 1: Pure([1, 0, 0, 0, 0, 0, 0, 0]) Input 2: Pure([2, 0, 0, 0, 0, 0, 0, 0]) Input 3: Pure([3, 0, 0, 0, 0, 0, 0, 0]) Command 0: SplitCoins(GasCoinInput(0),Input(1),Input(2),Input(3)) -Command 1: MoveCall(0x0000000000000000000000000000000000000000000000000000000000000002::coin::destroy_zero<0x2::sui::SUI>(NestedResult(0,0))) +Command 1: MoveCall(0x0000000000000000000000000000000000000000000000000000000000000002::coin::destroy_zero<0x2::iota::IOTA>(NestedResult(0,0))) Command 2: SplitCoins(NestedResult(0,1)Input(0),Input(0)) -Command 3: MoveCall(0x0000000000000000000000000000000000000000000000000000000000000002::coin::destroy_zero<0x2::sui::SUI>(NestedResult(2,0))) -Command 4: MoveCall(0x0000000000000000000000000000000000000000000000000000000000000002::coin::destroy_zero<0x2::sui::SUI>(NestedResult(2,1))) +Command 3: MoveCall(0x0000000000000000000000000000000000000000000000000000000000000002::coin::destroy_zero<0x2::iota::IOTA>(NestedResult(2,0))) +Command 4: MoveCall(0x0000000000000000000000000000000000000000000000000000000000000002::coin::destroy_zero<0x2::iota::IOTA>(NestedResult(2,1))) Command 5: MergeCoins(GasCoin,NestedResult(0,1),NestedResult(0,2),NestedResult(0,3)) diff --git a/crates/sui/tests/snapshots/ptb_files_tests__too_many_ty_params.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__too_many_ty_params.ptb.snap similarity index 97% rename from crates/sui/tests/snapshots/ptb_files_tests__too_many_ty_params.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__too_many_ty_params.ptb.snap index 36bbd8f1086..35bc725a553 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__too_many_ty_params.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__too_many_ty_params.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__transfer_objects_invalid.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__transfer_objects_invalid.ptb.snap similarity index 94% rename from crates/sui/tests/snapshots/ptb_files_tests__transfer_objects_invalid.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__transfer_objects_invalid.ptb.snap index 12d148be328..61e08f977fd 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__transfer_objects_invalid.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__transfer_objects_invalid.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === ERRORS AFTER PARSING INPUT COMMANDS === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__transfer_objects_valid.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__transfer_objects_valid.ptb.snap similarity index 96% rename from crates/sui/tests/snapshots/ptb_files_tests__transfer_objects_valid.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__transfer_objects_valid.ptb.snap index b8df2a012f8..f75e923d56c 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__transfer_objects_valid.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__transfer_objects_valid.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__valid_gas.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__valid_gas.ptb.snap similarity index 90% rename from crates/sui/tests/snapshots/ptb_files_tests__valid_gas.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__valid_gas.ptb.snap index eeaedf86eba..df313492c60 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__valid_gas.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__valid_gas.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__valid_types.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__valid_types.ptb.snap similarity index 99% rename from crates/sui/tests/snapshots/ptb_files_tests__valid_types.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__valid_types.ptb.snap index cd19e22d104..00cbb22fd19 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__valid_types.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__valid_types.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === diff --git a/crates/sui/tests/snapshots/ptb_files_tests__variable_resolution_fixing.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__variable_resolution_fixing.ptb.snap similarity index 88% rename from crates/sui/tests/snapshots/ptb_files_tests__variable_resolution_fixing.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__variable_resolution_fixing.ptb.snap index b43710b336f..ace0cc42e5f 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__variable_resolution_fixing.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__variable_resolution_fixing.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === @@ -9,12 +9,12 @@ expression: "results.join(\"\\n\")" │ command │ values │ ├───────────────┼───────────────────────────────────┤ │ assign │ s @0x1 │ -│ move-call │ sui::coin::value s │ +│ move-call │ iota::coin::value s │ │ make-move-vec │
    [s] │ ├───────────────┼───────────────────────────────────┤ │ gas-budget │ 100000 │ ╰───────────────┴───────────────────────────────────╯ === BUILT PTB === Input 0: ImmutableOrOwnedObject -Command 0: MoveCall(0x0000000000000000000000000000000000000000000000000000000000000002::coin::value<0x2::sui::SUI>(Input(0))) +Command 0: MoveCall(0x0000000000000000000000000000000000000000000000000000000000000002::coin::value<0x2::iota::IOTA>(Input(0))) Command 1: MakeMoveVec(Someaddress,[Input(0)]) diff --git a/crates/sui/tests/snapshots/ptb_files_tests__variable_shadowing.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__variable_shadowing.ptb.snap similarity index 89% rename from crates/sui/tests/snapshots/ptb_files_tests__variable_shadowing.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__variable_shadowing.ptb.snap index 9759ce77fca..cb8badf52fe 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__variable_shadowing.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__variable_shadowing.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === @@ -9,7 +9,7 @@ expression: "results.join(\"\\n\")" │ command │ values │ ├───────────────┼──────────────────────────────────────────┤ │ assign │ s @0x1 │ -│ move-call │ sui::coin::destroy_zero s │ +│ move-call │ iota::coin::destroy_zero s │ │ assign │ s @0x2 │ │ make-move-vec │
    [s] │ ├───────────────┼──────────────────────────────────────────┤ @@ -18,5 +18,5 @@ expression: "results.join(\"\\n\")" === BUILT PTB === Input 0: ImmutableOrOwnedObject Input 1: Pure([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]) -Command 0: MoveCall(0x0000000000000000000000000000000000000000000000000000000000000002::coin::destroy_zero<0x2::sui::SUI>(Input(0))) +Command 0: MoveCall(0x0000000000000000000000000000000000000000000000000000000000000002::coin::destroy_zero<0x2::iota::IOTA>(Input(0))) Command 1: MakeMoveVec(Someaddress,[Input(1)]) diff --git a/crates/sui/tests/snapshots/ptb_files_tests__whitespace_handling.ptb.snap b/crates/iota/tests/snapshots/ptb_files_tests__whitespace_handling.ptb.snap similarity index 89% rename from crates/sui/tests/snapshots/ptb_files_tests__whitespace_handling.ptb.snap rename to crates/iota/tests/snapshots/ptb_files_tests__whitespace_handling.ptb.snap index 649bf7d58c2..0901ed4abec 100644 --- a/crates/sui/tests/snapshots/ptb_files_tests__whitespace_handling.ptb.snap +++ b/crates/iota/tests/snapshots/ptb_files_tests__whitespace_handling.ptb.snap @@ -1,5 +1,5 @@ --- -source: crates/sui/tests/ptb_files_tests.rs +source: crates/iota/tests/ptb_files_tests.rs expression: "results.join(\"\\n\")" --- === PREVIEW === @@ -13,9 +13,9 @@ expression: "results.join(\"\\n\")" │ assign │ x vector["1", "2, 3", "", "4 "] │ │ assign │ x vector["1", "2, 3", "", "4 \n "] │ │ make-move-vec │ [1u64, 2u64, 3u64, 4u64] │ -│ make-move-vec │ [1u64, 2u64, 3u64, 4u64] │ -│ make-move-vec │ ["1", "2, 3", "", "4 "] │ -│ make-move-vec │ ["1", "2, 3", "", "4 \n "] │ +│ make-move-vec │ [1u64, 2u64, 3u64, 4u64] │ +│ make-move-vec │ ["1", "2, 3", "", "4 "] │ +│ make-move-vec │ ["1", "2, 3", "", "4 \n "] │ ├───────────────┼─────────────────────────────────────────────────────────────────────────────────────────┤ │ gas-budget │ 100 │ ╰───────────────┴─────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/crates/suins-indexer/.env.sample b/crates/iotans-indexer/.env.sample similarity index 100% rename from crates/suins-indexer/.env.sample rename to crates/iotans-indexer/.env.sample diff --git a/crates/iotans-indexer/Cargo.toml b/crates/iotans-indexer/Cargo.toml new file mode 100644 index 00000000000..88aaf99f9a0 --- /dev/null +++ b/crates/iotans-indexer/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "iotans-indexer" +authors = ["Mysten Labs "] +license = "Apache-2.0" +publish = false +edition = "2021" +version = "0.1.0" + +[dependencies] +diesel = { version = "2.1.4", features = ["postgres", "r2d2", "serde_json"] } +iota-data-ingestion-core.workspace = true +anyhow.workspace = true +async-trait.workspace = true +backoff.workspace = true +base64-url.workspace = true +bcs.workspace = true +bytes.workspace = true +futures.workspace = true +mysten-metrics.workspace = true +notify.workspace = true +object_store.workspace = true +serde.workspace = true +serde_json.workspace = true +serde_yaml.workspace = true +prometheus.workspace = true +telemetry-subscribers.workspace = true +tokio = { workspace = true, features = ["full"] } +tracing.workspace = true +iota-storage.workspace = true +iota-types.workspace = true +url.workspace = true +iota-json-rpc.workspace = true +dotenvy = "0.15" +move-core-types.workspace = true + +[dev-dependencies] +rand.workspace = true +tempfile.workspace = true +iota-types = { workspace = true, features = ["test-utils"] } diff --git a/crates/suins-indexer/diesel.toml b/crates/iotans-indexer/diesel.toml similarity index 100% rename from crates/suins-indexer/diesel.toml rename to crates/iotans-indexer/diesel.toml diff --git a/crates/suins-indexer/migrations/00000000000000_diesel_initial_setup/down.sql b/crates/iotans-indexer/migrations/00000000000000_diesel_initial_setup/down.sql similarity index 100% rename from crates/suins-indexer/migrations/00000000000000_diesel_initial_setup/down.sql rename to crates/iotans-indexer/migrations/00000000000000_diesel_initial_setup/down.sql diff --git a/crates/suins-indexer/migrations/00000000000000_diesel_initial_setup/up.sql b/crates/iotans-indexer/migrations/00000000000000_diesel_initial_setup/up.sql similarity index 100% rename from crates/suins-indexer/migrations/00000000000000_diesel_initial_setup/up.sql rename to crates/iotans-indexer/migrations/00000000000000_diesel_initial_setup/up.sql diff --git a/crates/suins-indexer/migrations/2024-01-25-152044_init/down.sql b/crates/iotans-indexer/migrations/2024-01-25-152044_init/down.sql similarity index 100% rename from crates/suins-indexer/migrations/2024-01-25-152044_init/down.sql rename to crates/iotans-indexer/migrations/2024-01-25-152044_init/down.sql diff --git a/crates/suins-indexer/migrations/2024-01-25-152044_init/up.sql b/crates/iotans-indexer/migrations/2024-01-25-152044_init/up.sql similarity index 100% rename from crates/suins-indexer/migrations/2024-01-25-152044_init/up.sql rename to crates/iotans-indexer/migrations/2024-01-25-152044_init/up.sql diff --git a/crates/suins-indexer/migrations/2024-01-29-122521_indexes/down.sql b/crates/iotans-indexer/migrations/2024-01-29-122521_indexes/down.sql similarity index 100% rename from crates/suins-indexer/migrations/2024-01-29-122521_indexes/down.sql rename to crates/iotans-indexer/migrations/2024-01-29-122521_indexes/down.sql diff --git a/crates/suins-indexer/migrations/2024-01-29-122521_indexes/up.sql b/crates/iotans-indexer/migrations/2024-01-29-122521_indexes/up.sql similarity index 100% rename from crates/suins-indexer/migrations/2024-01-29-122521_indexes/up.sql rename to crates/iotans-indexer/migrations/2024-01-29-122521_indexes/up.sql diff --git a/crates/iotans-indexer/src/indexer.rs b/crates/iotans-indexer/src/indexer.rs new file mode 100644 index 00000000000..1fbecdfdbbf --- /dev/null +++ b/crates/iotans-indexer/src/indexer.rs @@ -0,0 +1,262 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{HashMap, HashSet}, + str::FromStr, +}; + +use iota_json_rpc::name_service::{Domain, NameRecord, SubDomainRegistration}; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, + dynamic_field::Field, + full_checkpoint_content::{CheckpointData, CheckpointTransaction}, + object::Object, +}; +use move_core_types::language_storage::StructTag; + +use crate::models::VerifiedDomain; + +const REGISTRY_TABLE_ID: &str = + "0xe64cd9db9f829c6cc405d9790bd71567ae07259855f4fba6f02c84f52298c106"; +/// TODO(manos): Hardcode mainnet once we publish the subdomains package. +const SUBDOMAIN_REGISTRATION_TYPE: &str = + "0xPackageIdTBD::subdomain_registration::SubDomainRegistration"; + +#[derive(Debug, Clone)] +pub struct NameRecordChange(Field); + +pub struct IotansIndexer { + registry_table_id: IotaAddress, + subdomain_wrapper_type: StructTag, +} + +impl std::default::Default for IotansIndexer { + fn default() -> Self { + Self::new( + REGISTRY_TABLE_ID.to_owned(), + SUBDOMAIN_REGISTRATION_TYPE.to_owned(), + ) + } +} + +impl IotansIndexer { + /// Create a new config by passing the table ID + subdomain wrapper type. + /// Useful for testing or custom environments. + pub fn new(registry_address: String, wrapper_type: String) -> Self { + let registry_table_id = IotaAddress::from_str(®istry_address).unwrap(); + let subdomain_wrapper_type = StructTag::from_str(&wrapper_type).unwrap(); + + Self { + registry_table_id, + subdomain_wrapper_type, + } + } + + /// Checks if the object referenced is a subdomain wrapper. + /// For subdomain wrappers, we're saving the ID of the wrapper object, + /// to make it easy to locate the NFT (since the base NFT gets wrapped and + /// indexing won't work there). + pub fn is_subdomain_wrapper(&self, object: &Object) -> bool { + object + .struct_tag() + .is_some_and(|tag| tag == self.subdomain_wrapper_type) + } + + // Filter by owner. + // Owner has to be the TABLE of the registry. + // A table of that type can only have `Field as a child so + // that check is enough to make sure we're dealing with a registry change. + pub fn is_name_record(&self, object: &Object) -> bool { + object + .get_single_owner() + .is_some_and(|owner| owner == self.registry_table_id) + } + + /// Processes a checkpoint and produces a list of `updates` and a list of + /// `removals` + /// + /// We can then use these to execute our DB bulk insertions + bulk + /// deletions. + /// + /// Returns + /// - `Vec`: A list of NameRecord updates for the database + /// (including sequence number) + /// - `Vec`: A list of IDs to be deleted from the database + /// (`field_id` is the matching column) + pub fn process_checkpoint(&self, data: &CheckpointData) -> (Vec, Vec) { + let mut checkpoint = IotansIndexerCheckpoint::new(data.checkpoint_summary.sequence_number); + + // loop through all the transactions in the checkpoint + // Since the transactions are sequenced inside the checkpoint, we can safely + // assume that we have the latest data for each name record in the end + // of the loop. + for transaction in &data.transactions { + // Add all name record changes to the name_records HashMap. + // Remove any removals that got re-created. + checkpoint.parse_record_changes(self, &transaction.output_objects); + + // Gather all removals from the transaction, + // and delete any name records from the name_records if it got deleted. + checkpoint.parse_record_deletions(self, transaction); + } + + ( + // Convert our name_records & wrappers into a list of updates for the DB. + checkpoint.prepare_db_updates(), + checkpoint + .removals + .into_iter() + .map(|id| id.to_string()) + .collect(), + ) + } +} + +pub struct IotansIndexerCheckpoint { + /// A list of name records that have been updated in the checkpoint. + name_records: HashMap, + /// A list of subdomain wrappers that have been created in the checkpoint. + subdomain_wrappers: HashMap, + /// A list of name records that have been deleted in the checkpoint. + removals: HashSet, + /// The sequence number of the checkpoint. + checkpoint_sequence_number: u64, +} + +impl IotansIndexerCheckpoint { + pub fn new(checkpoint_sequence_number: u64) -> Self { + Self { + name_records: HashMap::new(), + subdomain_wrappers: HashMap::new(), + removals: HashSet::new(), + checkpoint_sequence_number, + } + } + + /// Parses the name record changes + subdomain wraps. + /// and pushes them into the supplied vector + hashmap. + /// + /// It is implemented in a way to do just a single iteration over the + /// objects. + pub fn parse_record_changes(&mut self, config: &IotansIndexer, objects: &[Object]) { + for object in objects { + // Parse all the changes to a `NameRecord` + if config.is_name_record(object) { + let name_record: Field = object + .to_rust() + .unwrap_or_else(|| panic!("Failed to parse name record for {:?}", object)); + + let id = object.id(); + + // Remove from the removals list if it's there. + // The reason it might have been there is that the same name record might have + // been deleted in a previous transaction in the same + // checkpoint, and now it got re-created. + self.removals.remove(&id); + + self.name_records.insert(id, NameRecordChange(name_record)); + } + // Parse subdomain wrappers and save them in our hashmap. + // Later, we'll save the id of the wrapper in the name record. + // NameRecords & their equivalent SubdomainWrappers are always created in the + // same PTB, so we can safely assume that the wrapper will be + // created on the same checkpoint as the name record and vice versa. + if config.is_subdomain_wrapper(object) { + let sub_domain: SubDomainRegistration = object.to_rust().unwrap(); + self.subdomain_wrappers.insert( + sub_domain.nft.domain_name, + sub_domain.id.id.bytes.to_string(), + ); + }; + } + } + + /// Parses a list of the deletions in the checkpoint and adds them to the + /// removals list. Also removes any name records from the updates, if + /// they ended up being deleted in the same checkpoint. + pub fn parse_record_deletions( + &mut self, + config: &IotansIndexer, + transaction: &CheckpointTransaction, + ) { + // a list of all the deleted objects in the transaction. + let deleted_objects: HashSet<_> = transaction + .effects + .all_tombstones() + .into_iter() + .map(|(id, _)| id) + .collect(); + + for input in transaction.input_objects.iter() { + if config.is_name_record(input) && deleted_objects.contains(&input.id()) { + // since this record was deleted, we need to remove it from the name_records + // hashmap. that catches a case where a name record was edited + // on a previous transaction in the checkpoint and deleted from + // a different tx later in the checkpoint. + self.name_records.remove(&input.id()); + + // add it in the list of removals + self.removals.insert(input.id()); + } + } + } + + /// Prepares a vector of `VerifiedDomain`s to be inserted into the DB, + /// taking in account the list of subdomain wrappers created as well as + /// the checkpoint's sequence number. + pub fn prepare_db_updates(&self) -> Vec { + let mut updates: Vec = vec![]; + + for (field_id, name_record_change) in self.name_records.iter() { + let name_record = &name_record_change.0; + + let parent = name_record.name.parent().to_string(); + let nft_id = name_record.value.nft_id.bytes.to_string(); + + updates.push(VerifiedDomain { + field_id: field_id.to_string(), + name: name_record.name.to_string(), + parent, + expiration_timestamp_ms: name_record.value.expiration_timestamp_ms as i64, + nft_id, + target_address: if name_record.value.target_address.is_some() { + Some(IotaAddress::to_string( + &name_record.value.target_address.unwrap(), + )) + } else { + None + }, + // unwrapping must be safe as `value.data` is an on-chain value with + // VecMap type. + data: serde_json::to_value(&name_record.value.data).unwrap(), + last_checkpoint_updated: self.checkpoint_sequence_number as i64, + subdomain_wrapper_id: self + .subdomain_wrappers + .get(&name_record.name.to_string()) + .cloned(), + }); + } + + updates + } +} + +/// Allows us to format a IotaNS specific query for updating the DB entries +/// only if the checkpoint is newer than the last checkpoint we have in the DB. +/// Doing that, we do not care about the order of execution and we can use +/// multiple threads to commit from later checkpoints to the DB. +/// +/// WARNING: This can easily be SQL-injected, so make sure to use it only with +/// trusted inputs. +pub fn format_update_field_query(field: &str) -> String { + format!( + "CASE WHEN excluded.last_checkpoint_updated > domains.last_checkpoint_updated THEN excluded.{field} ELSE domains.{field} END" + ) +} + +/// Update the subdomain wrapper ID only if it is part of the checkpoint. +pub fn format_update_subdomain_wrapper_query() -> String { + "CASE WHEN excluded.subdomain_wrapper_id IS NOT NULL THEN excluded.subdomain_wrapper_id ELSE domains.subdomain_wrapper_id END".to_string() +} diff --git a/crates/iotans-indexer/src/lib.rs b/crates/iotans-indexer/src/lib.rs new file mode 100644 index 00000000000..44d0e12bf49 --- /dev/null +++ b/crates/iotans-indexer/src/lib.rs @@ -0,0 +1,30 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod indexer; +pub mod models; +pub mod schema; + +use std::env; + +use diesel::{ + pg::PgConnection, + r2d2::{ConnectionManager, Pool}, +}; +use dotenvy::dotenv; + +pub type PgConnectionPool = diesel::r2d2::Pool>; +pub type PgPoolConnection = diesel::r2d2::PooledConnection>; + +pub fn get_connection_pool() -> PgConnectionPool { + dotenv().ok(); + + let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); + let manager = ConnectionManager::::new(database_url); + + Pool::builder() + .test_on_check_out(true) + .build(manager) + .expect("Could not build Postgres DB connection pool") +} diff --git a/crates/iotans-indexer/src/main.rs b/crates/iotans-indexer/src/main.rs new file mode 100644 index 00000000000..1b4a912e6fb --- /dev/null +++ b/crates/iotans-indexer/src/main.rs @@ -0,0 +1,163 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{env, path::PathBuf}; + +use anyhow::Result; +use async_trait::async_trait; +use diesel::{dsl::sql, BoolExpressionMethods, Connection, ExpressionMethods, RunQueryDsl}; +use dotenvy::dotenv; +use iota_data_ingestion_core::{ + DataIngestionMetrics, FileProgressStore, IndexerExecutor, ReaderOptions, Worker, WorkerPool, +}; +use iota_types::full_checkpoint_content::CheckpointData; +use iotans_indexer::{ + get_connection_pool, + indexer::{format_update_field_query, format_update_subdomain_wrapper_query, IotansIndexer}, + models::VerifiedDomain, + schema::domains, + PgConnectionPool, +}; +use prometheus::Registry; +use tokio::sync::oneshot; + +struct IotansIndexerWorker { + pg_pool: PgConnectionPool, + indexer: IotansIndexer, +} + +impl IotansIndexerWorker { + /// Creates a transcation that upserts the given name record updates, + /// and deletes the given name record deletions. + /// + /// This is done using 1 or 2 queries, depending on whether there are any + /// deletions/updates in the checkpoint. + /// + /// - The first query is a bulk insert of all updates, with an upsert on + /// conflict. + /// - The second query is a bulk delete of all deletions. + /// + /// You can safely call this with empty updates/deletions as it will return + /// Ok. + fn commit_to_db( + &self, + updates: &[VerifiedDomain], + removals: &[String], + checkpoint_seq_num: u64, + ) -> Result<()> { + if updates.is_empty() && removals.is_empty() { + return Ok(()); + } + + let connection = &mut self.pg_pool.get().unwrap(); + + connection.transaction(|tx| { + if !updates.is_empty() { + // Bulk insert all updates and override with data. + diesel::insert_into(domains::table) + .values(updates) + .on_conflict(domains::name) + .do_update() + .set(( + domains::expiration_timestamp_ms + .eq(sql(&format_update_field_query("expiration_timestamp_ms"))), + domains::nft_id.eq(sql(&format_update_field_query("nft_id"))), + domains::target_address + .eq(sql(&format_update_field_query("target_address"))), + domains::data.eq(sql(&format_update_field_query("data"))), + domains::last_checkpoint_updated + .eq(sql(&format_update_field_query("last_checkpoint_updated"))), + domains::field_id.eq(sql(&format_update_field_query("field_id"))), + // We always want to respect the subdomain_wrapper re-assignment, even if + // the checkpoint is older. That prevents a + // scenario where we first process a later checkpoint that did an update to + // the name record (e..g change target address), + // without first executing the checkpoint that created the subdomain + // wrapper. Since wrapper re-assignment can only + // happen every 2 days, we can't write invalid data here. + domains::subdomain_wrapper_id + .eq(sql(&format_update_subdomain_wrapper_query())), + )) + .execute(tx) + .unwrap_or_else(|_| panic!("Failed to process updates: {:?}", updates)); + } + + if !removals.is_empty() { + // We want to remove from the database all name records that were removed in the + // checkpoint but only if the checkpoint is newer than the last + // time the name record was updated. + diesel::delete(domains::table) + .filter( + domains::field_id + .eq_any(removals) + .and(domains::last_checkpoint_updated.le(checkpoint_seq_num as i64)), + ) + .execute(tx) + .unwrap_or_else(|_| panic!("Failed to process deletions: {:?}", removals)); + } + + Ok(()) + }) + } +} + +#[async_trait] +impl Worker for IotansIndexerWorker { + async fn process_checkpoint(&self, checkpoint: CheckpointData) -> Result<()> { + let checkpoint_seq_number = checkpoint.checkpoint_summary.sequence_number; + let (updates, removals) = self.indexer.process_checkpoint(&checkpoint); + + self.commit_to_db(&updates, &removals, checkpoint_seq_number)?; + Ok(()) + } +} + +#[tokio::main] +async fn main() -> Result<()> { + dotenv().ok(); + let (remote_storage, registry_id, subdomain_wrapper_type) = ( + env::var("REMOTE_STORAGE").ok(), + env::var("REGISTRY_ID").ok(), + env::var("SUBDOMAIN_WRAPPER_TYPE").ok(), + ); + let backfill_progress_file_path = + env::var("BACKFILL_PROGRESS_FILE_PATH").unwrap_or("/tmp/backfill_progress".to_string()); + let checkpoints_dir = env::var("CHECKPOINTS_DIR").unwrap_or("/tmp/checkpoints".to_string()); + + println!("Starting indexer with checkpoints dir: {}", checkpoints_dir); + + let (_exit_sender, exit_receiver) = oneshot::channel(); + let progress_store = FileProgressStore::new(PathBuf::from(backfill_progress_file_path)); + let metrics = DataIngestionMetrics::new(&Registry::new()); + let mut executor = IndexerExecutor::new(progress_store, 1, metrics); + + let indexer_setup = if let (Some(registry_id), Some(subdomain_wrapper_type)) = + (registry_id, subdomain_wrapper_type) + { + IotansIndexer::new(registry_id, subdomain_wrapper_type) + } else { + IotansIndexer::default() + }; + + let worker_pool = WorkerPool::new( + IotansIndexerWorker { + pg_pool: get_connection_pool(), + indexer: indexer_setup, + }, + "iotans_indexing".to_string(), // task name used as a key in the progress store + 100, // concurrency + ); + executor.register(worker_pool).await?; + + executor + .run( + PathBuf::from(checkpoints_dir), // directory should exist but can be empty + remote_storage, // remote_read_endpoint: If set + vec![], // aws credentials + ReaderOptions::default(), // remote_read_batch_size + exit_receiver, + ) + .await?; + Ok(()) +} diff --git a/crates/suins-indexer/src/models.rs b/crates/iotans-indexer/src/models.rs similarity index 92% rename from crates/suins-indexer/src/models.rs rename to crates/iotans-indexer/src/models.rs index fa16629100b..a0b551001ab 100644 --- a/crates/suins-indexer/src/models.rs +++ b/crates/iotans-indexer/src/models.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use diesel::prelude::*; diff --git a/crates/iotans-indexer/src/schema.rs b/crates/iotans-indexer/src/schema.rs new file mode 100644 index 00000000000..68695f4e4bd --- /dev/null +++ b/crates/iotans-indexer/src/schema.rs @@ -0,0 +1,19 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +// @generated automatically by Diesel CLI. + +diesel::table! { + domains (name) { + name -> Varchar, + parent -> Varchar, + expiration_timestamp_ms -> Int8, + nft_id -> Varchar, + field_id -> Varchar, + target_address -> Nullable, + data -> Json, + last_checkpoint_updated -> Int8, + subdomain_wrapper_id -> Nullable, + } +} diff --git a/crates/suins-indexer/tests/checkpoint_process_tests.rs b/crates/iotans-indexer/tests/checkpoint_process_tests.rs similarity index 82% rename from crates/suins-indexer/tests/checkpoint_process_tests.rs rename to crates/iotans-indexer/tests/checkpoint_process_tests.rs index 41120ce149b..42d652e9ee1 100644 --- a/crates/suins-indexer/tests/checkpoint_process_tests.rs +++ b/crates/iotans-indexer/tests/checkpoint_process_tests.rs @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use sui_storage::blob::Blob; -use sui_types::full_checkpoint_content::CheckpointData; -use suins_indexer::indexer::SuinsIndexer; +use iota_storage::blob::Blob; +use iota_types::full_checkpoint_content::CheckpointData; +use iotans_indexer::indexer::IotansIndexer; /// Test ids. const TEST_REGISTRY_TABLE_ID: &str = @@ -15,9 +16,9 @@ const TEST_SUBDOMAIN_REGISTRATION_TYPE: &str = "0x22fa05f21b1ad71442491220bb9338 /// /// Checkpoint 22279187: Adds 3 different names (1 SLD, 1 leaf, 1 node). Deletes /// none. Checkpoint 22279365: Removes 1 leaf name. Adds 1 leaf name. -/// Checkpoint 22279496: Replaces the name added on `22279365` (new.test.sui) by -/// removing it and then adding it as a node name. Checkpoint 22279944: Adds -/// `remove.test.sui`. Checkpoint 22280030: Adds `remove.test.sui` as a +/// Checkpoint 22279496: Replaces the name added on `22279365` (new.test.iota) +/// by removing it and then adding it as a node name. Checkpoint 22279944: Adds +/// `remove.test.iota`. Checkpoint 22280030: Adds `remove.test.iota` as a /// replacement (the previous one expired!). [This was only /// simulated using a dummy contract and cannot happen in realistic scenarios.] #[test] @@ -33,9 +34,9 @@ fn process_22279187_checkpoint() { let names: Vec<_> = updates.iter().map(|n| n.name.clone()).collect(); - assert!(names.contains(&"leaf.test.sui".to_string())); - assert!(names.contains(&"node.test.sui".to_string())); - assert!(names.contains(&"test.sui".to_string())); + assert!(names.contains(&"leaf.test.iota".to_string())); + assert!(names.contains(&"node.test.iota".to_string())); + assert!(names.contains(&"test.iota".to_string())); } #[test] @@ -49,8 +50,8 @@ fn process_22279365_checkpoint() { assert_eq!(updates.len(), 1); let addition = updates.first().unwrap(); - assert_eq!(addition.name, "new.test.sui".to_string()); - assert_eq!(addition.parent, "test.sui".to_string()); + assert_eq!(addition.name, "new.test.iota".to_string()); + assert_eq!(addition.parent, "test.iota".to_string()); assert_eq!( addition.nft_id, "0xa4891f3754b203ef230a5e2a08822c835c808eab71e2bc6ca33a73cec9728376".to_string() @@ -69,8 +70,8 @@ fn process_22279496_checkpoint() { assert_eq!(updates.len(), 1); let addition = updates.first().unwrap(); - assert_eq!(addition.name, "new.test.sui".to_string()); - assert_eq!(addition.parent, "test.sui".to_string()); + assert_eq!(addition.name, "new.test.iota".to_string()); + assert_eq!(addition.parent, "test.iota".to_string()); assert_eq!( addition.nft_id, "0x87f04a4ffa1713e0a7e3a9e5ebf56f0ab24ce0bba87b17eb11a7532cb381bd58".to_string() @@ -92,7 +93,7 @@ fn process_22279944_checkpoint() { assert_eq!(updates.len(), 1); let addition = updates.first().unwrap(); - assert_eq!(addition.name, "remove.test.sui".to_string()); + assert_eq!(addition.name, "remove.test.iota".to_string()); assert_eq!( addition.nft_id, "0x7c230e1a4cd7b708232a713a138f4c950e7f579b61d01b988f06d7dc53e99211".to_string() @@ -117,7 +118,7 @@ fn process_22280030_checkpoint() { assert_eq!(updates.len(), 1); let addition = updates.first().unwrap(); - assert_eq!(addition.name, "remove.test.sui".to_string()); + assert_eq!(addition.name, "remove.test.iota".to_string()); assert_eq!( addition.nft_id, "0xdd513860269b0768c6ed77ddaf48cd579ba0c2995e793eab182d6ab861818250".to_string() @@ -138,10 +139,10 @@ fn read_checkpoint_from_file(file: &[u8]) -> CheckpointData { Blob::from_bytes::(file).unwrap() } -/// Return a suins_indexer instance for testing. +/// Return a iotans_indexer instance for testing. /// Uses the testnet demo we used to extract the checkpoints being processed. -fn get_test_indexer() -> SuinsIndexer { - SuinsIndexer::new( +fn get_test_indexer() -> IotansIndexer { + IotansIndexer::new( TEST_REGISTRY_TABLE_ID.to_string(), TEST_SUBDOMAIN_REGISTRATION_TYPE.to_string(), ) diff --git a/crates/suins-indexer/tests/data/22279187.chk b/crates/iotans-indexer/tests/data/22279187.chk similarity index 100% rename from crates/suins-indexer/tests/data/22279187.chk rename to crates/iotans-indexer/tests/data/22279187.chk diff --git a/crates/suins-indexer/tests/data/22279365.chk b/crates/iotans-indexer/tests/data/22279365.chk similarity index 100% rename from crates/suins-indexer/tests/data/22279365.chk rename to crates/iotans-indexer/tests/data/22279365.chk diff --git a/crates/suins-indexer/tests/data/22279496.chk b/crates/iotans-indexer/tests/data/22279496.chk similarity index 100% rename from crates/suins-indexer/tests/data/22279496.chk rename to crates/iotans-indexer/tests/data/22279496.chk diff --git a/crates/suins-indexer/tests/data/22279944.chk b/crates/iotans-indexer/tests/data/22279944.chk similarity index 100% rename from crates/suins-indexer/tests/data/22279944.chk rename to crates/iotans-indexer/tests/data/22279944.chk diff --git a/crates/suins-indexer/tests/data/22280030.chk b/crates/iotans-indexer/tests/data/22280030.chk similarity index 100% rename from crates/suins-indexer/tests/data/22280030.chk rename to crates/iotans-indexer/tests/data/22280030.chk diff --git a/crates/suiop-cli/Cargo.lock b/crates/iotaop-cli/Cargo.lock similarity index 99% rename from crates/suiop-cli/Cargo.lock rename to crates/iotaop-cli/Cargo.lock index deb5cfb996e..3125b3a6337 100644 --- a/crates/suiop-cli/Cargo.lock +++ b/crates/iotaop-cli/Cargo.lock @@ -1753,7 +1753,7 @@ dependencies = [ ] [[package]] -name = "suiop" +name = "iotaop" version = "0.1.4" dependencies = [ "anyhow", diff --git a/crates/iotaop-cli/Cargo.toml b/crates/iotaop-cli/Cargo.toml new file mode 100644 index 00000000000..2d75fac9e54 --- /dev/null +++ b/crates/iotaop-cli/Cargo.toml @@ -0,0 +1,47 @@ +[package] +authors = [ + "Jk Jensen ", + "Mysten Labs ", +] +edition = "2021" +license = "Apache-2.0" +name = "iotaop-cli" +publish = false +version = "0.1.9" + +[lib] +name = "iotaoplib" +path = "src/lib.rs" + +[[bin]] +name = "iotaop" +path = "src/main.rs" + +[dependencies] +anyhow.workspace = true +chrono.workspace = true +clap.workspace = true +colored.workspace = true +docker-api.workspace = true +field_names.workspace = true +include_dir.workspace = true +inquire.workspace = true +prettytable-rs.workspace = true +regex.workspace = true +reqwest = { workspace = true, features = [ + "rustls-tls", + "json", +], default-features = false } +semver.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +serde_yaml.workspace = true +spinners.workspace = true +strum.workspace = true +tokio = { workspace = true, features = ["full"] } +toml_edit.workspace = true +tracing-subscriber.workspace = true +tracing.workspace = true + +[dev-dependencies] +tempfile.workspace = true diff --git a/crates/suiop-cli/boilerplate b/crates/iotaop-cli/boilerplate similarity index 100% rename from crates/suiop-cli/boilerplate rename to crates/iotaop-cli/boilerplate diff --git a/crates/suiop-cli/src/cli/incidents/jira.rs b/crates/iotaop-cli/src/cli/incidents/jira.rs similarity index 98% rename from crates/suiop-cli/src/cli/incidents/jira.rs rename to crates/iotaop-cli/src/cli/incidents/jira.rs index 817f3fccf3f..887d7a27324 100644 --- a/crates/suiop-cli/src/cli/incidents/jira.rs +++ b/crates/iotaop-cli/src/cli/incidents/jira.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{env, fmt, fs, path::PathBuf}; diff --git a/crates/iotaop-cli/src/cli/incidents/mod.rs b/crates/iotaop-cli/src/cli/incidents/mod.rs new file mode 100644 index 00000000000..732afd9f60a --- /dev/null +++ b/crates/iotaop-cli/src/cli/incidents/mod.rs @@ -0,0 +1,55 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod jira; +mod pd; + +use std::path::PathBuf; + +use anyhow::Result; +use clap::Parser; +use jira::generate_follow_up_tasks; +use pd::print_recent_incidents; + +#[derive(Parser, Debug, Clone)] +pub struct IncidentsArgs { + #[command(subcommand)] + action: IncidentsAction, +} + +#[derive(clap::Subcommand, Debug, Clone)] +pub enum IncidentsAction { + /// show recent incident details + #[command(name = "recent", aliases=["r", "recent_incidents"])] + GetRecentIncidents { + /// extended output with additional fields + #[arg(short, long)] + long: bool, + /// the max number of incidents to show + #[arg(long, default_value = "500")] + limit: usize, + /// the days to go back + #[arg(short, long, default_value = "7")] + days: usize, + }, + /// generate Jira tasks for incident follow ups + #[command(name = "generate follow up tasks", aliases=["g", "gen", "generate"])] + GenerateFollowUpTasks { + /// filename with tasks to add. should be named {incident number}.txt + #[arg(short, long)] + input_filename: PathBuf, + }, +} + +pub async fn incidents_cmd(args: &IncidentsArgs) -> Result<()> { + match &args.action { + IncidentsAction::GetRecentIncidents { long, limit, days } => { + print_recent_incidents(*long, *limit, *days).await? + } + IncidentsAction::GenerateFollowUpTasks { input_filename } => { + generate_follow_up_tasks(input_filename).await? + } + } + Ok(()) +} diff --git a/crates/suiop-cli/src/cli/incidents/pd.rs b/crates/iotaop-cli/src/cli/incidents/pd.rs similarity index 99% rename from crates/suiop-cli/src/cli/incidents/pd.rs rename to crates/iotaop-cli/src/cli/incidents/pd.rs index 3a414742962..507913def13 100644 --- a/crates/suiop-cli/src/cli/incidents/pd.rs +++ b/crates/iotaop-cli/src/cli/incidents/pd.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::env; diff --git a/crates/iotaop-cli/src/cli/mod.rs b/crates/iotaop-cli/src/cli/mod.rs new file mode 100644 index 00000000000..f74fbf0c125 --- /dev/null +++ b/crates/iotaop-cli/src/cli/mod.rs @@ -0,0 +1,11 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod incidents; +pub mod pulumi; +mod service; + +pub use incidents::{incidents_cmd, IncidentsArgs}; +pub use pulumi::{pulumi_cmd, PulumiArgs}; +pub use service::{service_cmd, ServiceArgs}; diff --git a/crates/iotaop-cli/src/cli/pulumi/init.rs b/crates/iotaop-cli/src/cli/pulumi/init.rs new file mode 100644 index 00000000000..6e6240b4c34 --- /dev/null +++ b/crates/iotaop-cli/src/cli/pulumi/init.rs @@ -0,0 +1,348 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{fs, path::PathBuf}; + +use anyhow::{anyhow, Context, Result}; +use colored::Colorize; +use inquire::Text; +use serde::{Deserialize, Serialize}; +use tracing::{debug, error, info, warn}; + +use crate::{command::CommandOptions, run_cmd}; + +pub enum ProjectType { + App, + Service, + Basic, + CronJob, +} + +const KEYRING: &str = "pulumi-kms-automation-f22939d"; + +impl ProjectType { + pub fn create_project(&self, use_kms: &bool, project_name: Option) -> Result<()> { + // make sure we're in iotaops + ensure_in_iotaops_repo()?; + // inquire params from user + let project_name = project_name.unwrap_or_else(|| { + Text::new("project name:") + .prompt() + .expect("couldn't get project name") + }); + // create dir + let project_subdir = match self { + Self::App | Self::CronJob => "apps".to_owned(), + Self::Service => "services".to_owned(), + Self::Basic => Text::new("project subdir (under iota-operations/pulumi/):") + .prompt() + .expect("couldn't get subdir"), + }; + let project_dir = get_pulumi_dir()?.join(project_subdir).join(&project_name); + let mut project_opts = vec![]; + if *use_kms { + let encryption_key_id = get_encryption_key_id(&project_name)?; + project_opts.push(format!("--secrets-provider=gcpkms://{}", encryption_key_id)); + } + if project_dir.exists() { + Err(anyhow!( + "{} already exists. Please use a project name that doesn't already exist", + project_dir + .to_str() + .expect("project dir to str") + .bright_purple() + )) + } else { + match self { + Self::App | Self::Service => { + info!("creating k8s containerized application/service"); + create_mysten_k8s_project( + &project_name, + &project_dir, + Self::App, + &project_opts, + )?; + } + Self::Basic => { + info!("creating basic pulumi project"); + create_basic_project(&project_name, &project_dir, &project_opts)?; + } + Self::CronJob => { + info!("creating k8s cronjob project"); + create_mysten_k8s_project( + &project_name, + &project_dir, + Self::CronJob, + &project_opts, + )?; + } + } + info!("your new project is ready to go!"); + Ok(()) + } + } +} + +fn ensure_in_iotaops_repo() -> Result<()> { + let remote_stdout = run_cmd( + vec!["git", "config", "--get", "remote.origin.url"], + Some(CommandOptions::new(false, false)), + ) + .context("run this command within the iota-operations repository")? + .stdout; + let in_iotaops = String::from_utf8_lossy(&remote_stdout) + .trim() + .contains("iota-operations"); + if !in_iotaops { + Err(anyhow!( + "please run this command from within the iota-operations repository" + )) + } else { + Ok(()) + } +} + +fn get_pulumi_dir() -> Result { + let iotaops_dir_stdout = run_cmd( + vec!["git", "rev-parse", "--show-toplevel"], + Some(CommandOptions::new(false, false)), + ) + .context("run this command from within the iota-operations repository")? + .stdout; + let iotaops_dir = PathBuf::from(String::from_utf8_lossy(&iotaops_dir_stdout).trim()); + Ok(iotaops_dir.join("pulumi")) +} + +fn run_pulumi_new( + project_name: &str, + project_dir_str: &str, + project_opts: &[String], +) -> Result<()> { + info!( + "creating new pulumi project in {}", + project_dir_str.bright_purple() + ); + let opts = project_opts.join(" "); + info!("extra pulumi options added: {}", &opts.bright_purple()); + run_cmd( + vec![ + "bash", + "-c", + &format!( + r#"pulumi new go --dir {0} -d "pulumi project for {1}" --name "{1}" --stack mysten/dev --yes {2}"#, + project_dir_str, project_name, opts + ), + ], + None, + )?; + Ok(()) +} + +fn run_pulumi_new_from_template( + project_name: &str, + project_dir_str: &str, + project_type: ProjectType, + project_opts: &[String], +) -> Result<()> { + info!( + "creating new pulumi project in {}", + project_dir_str.bright_purple() + ); + let template_dir = match project_type { + ProjectType::App | ProjectType::Service => "app-go", + ProjectType::CronJob => "cronjob-go", + _ => "app-go", + }; + let opts = project_opts.join(" "); + info!("extra pulumi options added: {}", &opts.bright_purple()); + let cmd = &format!( + r#"pulumi new {3}/templates/{2} --dir {0} -d "pulumi project for {1}" --name "{1}" --stack mysten/dev {4}"#, + project_dir_str, + project_name, + template_dir, + get_pulumi_dir()? + .to_str() + .expect("getting pulumi dir for template"), + opts, + ); + info!("running command: {}", cmd.bright_purple()); + + run_cmd( + vec!["bash", "-c", cmd], + Some(CommandOptions::new(true, false)), + )?; + Ok(()) +} + +fn run_go_mod_tidy(project_dir_str: &str) -> Result<()> { + let cmd = &format!("cd {} && go mod tidy", project_dir_str); + info!( + "running `{}` to make sure all Golang dependencies are installed.", + cmd + ); + run_cmd(vec!["bash", "-c", cmd], None)?; + Ok(()) +} + +fn run_pulumi_preview(project_dir_str: &str) -> Result<()> { + info!("running pulumi preview to make sure everything is functional"); + run_cmd( + vec![ + "bash", + "-c", + &format!("pulumi preview -C {}", project_dir_str), + ], + None, + )?; + Ok(()) +} + +fn remove_project_dir(project_dir: &PathBuf) -> Result<()> { + fs::remove_dir_all(project_dir).context("removing project dir") +} + +#[derive(Serialize, Deserialize)] +struct PulumiBackendURL { + url: String, +} + +fn get_current_backend() -> Result { + debug!("running pulumi whoami -v -j to get the Backend URL"); + let output = run_cmd(vec!["bash", "-c", "pulumi whoami -v -j"], None)?; + let stdout_str = std::str::from_utf8(&output.stdout)?; + let val: PulumiBackendURL = serde_json::from_str(stdout_str)?; + let mut parts = val.url.split("com/"); + if let Some(answer) = parts.nth(1) { + if !answer.is_empty() { + let ret = answer.trim().to_string(); + debug!("Backend URL is pointing to: {ret}"); + Ok(ret) + } else { + Err(anyhow!("Backend URL is incomplete")) + } + } else { + Err(anyhow!("Backend URL is incomplete")) + } +} + +fn remove_stack(backend: &str, project_name: &str, stack_name: &str) -> Result<()> { + let stack_str = format!("{}/{}/{}", backend, project_name, stack_name); + debug!("cleaning up {}...", &stack_str); + run_cmd( + vec![ + "bash", + "-c", + &format!("pulumi stack rm {} --yes", stack_str), + ], + None, + )?; + warn!( + "{} cleaned up successfully, you'll have a clean start next time.", + &stack_str.bright_purple() + ); + Ok(()) +} + +fn create_basic_project( + project_name: &str, + project_dir: &PathBuf, + project_opts: &[String], +) -> Result<()> { + let project_dir_str = project_dir.to_str().expect("project dir to str"); + info!( + "creating project directory at {}", + project_dir_str.bright_purple() + ); + fs::create_dir_all(project_dir).context("failed to create project directory")?; + // initialize pulumi project + run_pulumi_new(project_name, project_dir_str, project_opts).map_err(|e| { + remove_project_dir(project_dir).unwrap(); + let backend = get_current_backend().unwrap(); + remove_stack(&backend, project_name, "mysten/dev").unwrap(); + e + })?; + // run go mod tidy to make sure all dependencies are installed + run_go_mod_tidy(project_dir_str)?; + // try a pulumi preview to make sure it's good + run_pulumi_preview(project_dir_str) +} + +fn create_mysten_k8s_project( + project_name: &str, + project_dir: &PathBuf, + project_type: ProjectType, + project_opts: &[String], +) -> Result<()> { + let project_dir_str = project_dir.to_str().expect("project dir to str"); + info!( + "creating project directory at {}", + project_dir_str.bright_purple() + ); + fs::create_dir_all(project_dir).context("failed to create project directory")?; + // initialize pulumi project + run_pulumi_new_from_template(project_name, project_dir_str, project_type, project_opts) + .map_err(|e| { + remove_project_dir(project_dir).unwrap(); + let backend = get_current_backend().unwrap(); + remove_stack(&backend, project_name, "mysten/dev").unwrap(); + e + })?; + // run go mod tidy to make sure all dependencies are installed + run_go_mod_tidy(project_dir_str) + // we don't run preview for templated apps because the user + // has to give the repo dir (improvements to this coming soon) +} + +#[derive(Serialize, Deserialize)] +struct KMSKeyPrimary { + state: String, + algorithm: String, +} +#[derive(Serialize, Deserialize)] +struct KMSKey { + name: String, + primary: KMSKeyPrimary, +} +fn get_encryption_key_id(project_name: &str) -> Result { + let output = run_cmd( + vec![ + "bash", + "-c", + &format!( + "gcloud kms keys list --location=global --keyring={} --format json", + KEYRING + ), + ], + None, + ) + .map_err(|e| { + error!( + "Cannot list KMS keys, please add your Google account to {}", + "pulumi/meta/gcp-iam-automation/config.toml".bright_yellow() + ); + e + })?; + let stdout_str = String::from_utf8(output.stdout)?; + let keys: Vec = serde_json::from_str(&stdout_str)?; + for key in keys { + let key_id = key.name; + if let Some((_, key_name)) = key_id.rsplit_once('/') { + if key_name.starts_with(project_name) + && key.primary.state == "ENABLED" + && key.primary.algorithm == "GOOGLE_SYMMETRIC_ENCRYPTION" + { + return Ok(key_id); + } + } + } + error!( + "Cannot find encryption key matching project name: {0}.\n + Please add a new entry {1} to {2}, create a PR then land it.\n + A Github workflow will be triggered automatically to create a key for this pulumi project.", + project_name.bright_purple(), + format!("[kms.{}]", project_name).bright_purple(), + "pulumi/meta/gcp-iam-automation/config.toml".bright_yellow() + ); + Err(anyhow!("Missing encryption key")) +} diff --git a/crates/iotaop-cli/src/cli/pulumi/mod.rs b/crates/iotaop-cli/src/cli/pulumi/mod.rs new file mode 100644 index 00000000000..2db7915e5e9 --- /dev/null +++ b/crates/iotaop-cli/src/cli/pulumi/mod.rs @@ -0,0 +1,72 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod init; +mod setup; + +use anyhow::Result; +use clap::Parser; +use init::ProjectType; +use setup::{ensure_gcloud, ensure_setup}; + +#[derive(Parser, Debug, Clone)] +pub struct PulumiArgs { + #[command(subcommand)] + action: PulumiAction, +} + +#[derive(clap::Subcommand, Debug, Clone)] +pub enum PulumiAction { + /// initialize a new pulumi project + #[command(name = "init", aliases=["i"])] + InitProject { + /// initialize app project + #[arg(short, long, group = "type")] + app: bool, + + #[arg(short, long, group = "type")] + service: bool, + + /// initialize barebones project (default) + #[arg(short, long, group = "type")] + basic: bool, + + /// initialize cronjob project + #[arg(short, long, group = "type")] + cronjob: bool, + + /// use GCP KMS as encryption provider + #[arg(short, long, group = "feature")] + kms: bool, + + /// the name of the project to be created + #[arg(long, aliases = ["name"])] + project_name: Option, + }, +} + +pub async fn pulumi_cmd(args: &PulumiArgs) -> Result<()> { + ensure_setup()?; + match &args.action { + PulumiAction::InitProject { + app, + service, + basic, + cronjob, + kms, + project_name, + } => { + if *kms { + ensure_gcloud()?; + } + let project_type = match (app, service, basic, cronjob) { + (false, true, false, false) => ProjectType::Service, + (true, false, false, false) => ProjectType::App, + (false, false, false, true) => ProjectType::CronJob, + (_, _, _, _) => ProjectType::Basic, + }; + project_type.create_project(kms, project_name.clone()) + } + } +} diff --git a/crates/suiop-cli/src/cli/pulumi/setup.rs b/crates/iotaop-cli/src/cli/pulumi/setup.rs similarity index 97% rename from crates/suiop-cli/src/cli/pulumi/setup.rs rename to crates/iotaop-cli/src/cli/pulumi/setup.rs index 750d62f9dfe..1281df5d1b2 100644 --- a/crates/suiop-cli/src/cli/pulumi/setup.rs +++ b/crates/iotaop-cli/src/cli/pulumi/setup.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -161,7 +162,7 @@ pub fn ensure_gcloud() -> Result<()> { pub fn ensure_setup() -> Result<()> { let home = env::var("HOME").unwrap(); // check for marker file - let setup_marker = PathBuf::from(format!("{}/.suiop/pulumi_setup", home)); + let setup_marker = PathBuf::from(format!("{}/.iotaop/pulumi_setup", home)); if setup_marker.exists() { // our work here is done, it's set up! Ok(()) diff --git a/crates/iotaop-cli/src/cli/service/init.rs b/crates/iotaop-cli/src/cli/service/init.rs new file mode 100644 index 00000000000..a0703095908 --- /dev/null +++ b/crates/iotaop-cli/src/cli/service/init.rs @@ -0,0 +1,144 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + fs, + fs::{create_dir_all, File}, + io::prelude::*, + path::Path, +}; + +use anyhow::{Context, Result}; +use clap::{Parser, ValueEnum}; +use include_dir::{include_dir, Dir}; +use tracing::{debug, info}; + +// include the boilerplate code in this binary + +// hardcode the 'boilerplate' symlink in the Windows compilation for now +#[cfg(target_os = "windows")] +static PROJECT_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/../mysten-service-boilerplate"); +#[cfg(not(target_os = "windows"))] +static PROJECT_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/boilerplate"); + +#[derive(ValueEnum, Parser, Debug, Clone)] +pub enum ServiceLanguage { + Rust, + Typescript, +} + +pub fn bootstrap_service(lang: &ServiceLanguage, path: &Path) -> Result<()> { + match lang { + ServiceLanguage::Rust => create_rust_service(path), + ServiceLanguage::Typescript => todo!(), + } +} + +/// Add the new service to the iota-services dockerfile in the iota repository +fn add_to_iota_dockerfile(path: &Path) -> Result<()> { + let path = path.canonicalize().context("canonicalizing service path")?; + let crates_dir = path.parent().unwrap(); + if !crates_dir.ends_with("iota/crates") { + panic!("directory wasn't in the iota repo"); + } + let iota_services_dockerfile_path = &crates_dir.join("../docker/iota-services/Dockerfile"); + // read the dockerfile + let dockerfile = fs::read_to_string(iota_services_dockerfile_path) + .context("reading iota-services dockerfile")?; + + // find the line with the build cmd + let build_line = dockerfile + .lines() + .enumerate() + .find(|(_, line)| line.contains("RUN cargo build --release \\")) + .expect("couldn't find build line in iota-services dockerfile") + .0; + // update with the new service + let mut final_dockerfile = dockerfile.lines().collect::>(); + let bin_str = format!( + " --bin {} \\", + path.file_name() + .expect("getting the project name from the given path") + .to_str() + .unwrap() + ); + final_dockerfile.insert(build_line + 1, &bin_str); + // write the file back + fs::write(iota_services_dockerfile_path, final_dockerfile.join("\n")) + .context("writing iota-services dockerfile after modifying it")?; + + Ok(()) +} + +fn add_member_to_workspace(path: &Path) -> Result<()> { + // test + let path = path.canonicalize().context("canonicalizing service path")?; + let crates_dir = path.parent().unwrap(); + if !crates_dir.ends_with("iota/crates") { + panic!("directory wasn't in the iota repo"); + } + let workspace_toml_path = &crates_dir.join("../Cargo.toml"); + // read the workspace toml + let toml_content = fs::read_to_string(workspace_toml_path)?; + let mut toml = toml_content.parse::()?; + toml["workspace"]["members"] + .as_array_mut() + .unwrap() + .push_formatted(toml_edit::Value::String(toml_edit::Formatted::new( + Path::new("crates/") + .join( + path.file_name() + .expect("getting the project name from the given path"), + ) + .to_str() + .expect("converting the path to a str") + .to_string(), + ))); + fs::write(workspace_toml_path, toml.to_string()) + .context("failed to write workspace Cargo.toml back after update")?; + Ok(()) +} + +fn create_rust_service(path: &Path) -> Result<()> { + info!("creating rust service in {}", path.to_string_lossy()); + // create the dir to ensure we can canonicalize any relative paths + create_dir_all(path)?; + let is_iota_service = path + // expand relative paths and symlinks + .canonicalize() + .context("canonicalizing service path")? + .to_string_lossy() + .contains("iota/crates"); + debug!("iota service: {:?}", is_iota_service); + let cargo_toml_path = if is_iota_service { + "Cargo.toml" + } else { + "Cargo-external.toml" + }; + let cargo_toml = PROJECT_DIR.get_file(cargo_toml_path).unwrap(); + let main_rs = PROJECT_DIR.get_file("src/main.rs").unwrap(); + let main_body = main_rs.contents(); + let cargo_body = std::str::from_utf8(cargo_toml.contents())?; + let mut toml_content = cargo_body.parse::()?; + toml_content["package"]["name"] = toml_edit::value(path.file_name().unwrap().to_str().unwrap()); + create_dir_all(path.join("src"))?; + let mut main_file = File::create(path.join("src/main.rs"))?; + main_file.write_all(main_body)?; + let mut cargo_file = File::create(path.join("Cargo.toml"))?; + cargo_file.write_all(toml_content.to_string().as_bytes())?; + + // add the project as a member of the cargo workspace + if is_iota_service { + add_member_to_workspace(path)?; + } + // now that the source directory works, let's update/add a dockerfile + if is_iota_service { + // update iota-services dockerfile + add_to_iota_dockerfile(path)?; + } else { + // TODO: create a new dockerfile where the user designates + } + + Ok(()) +} diff --git a/crates/iotaop-cli/src/cli/service/mod.rs b/crates/iotaop-cli/src/cli/service/mod.rs new file mode 100644 index 00000000000..6229bd21df4 --- /dev/null +++ b/crates/iotaop-cli/src/cli/service/mod.rs @@ -0,0 +1,39 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod init; + +use std::path::PathBuf; + +use anyhow::Result; +use clap::Parser; +pub use init::bootstrap_service; +use init::ServiceLanguage; + +#[derive(Parser, Debug, Clone)] +pub struct ServiceArgs { + #[command(subcommand)] + action: ServiceAction, +} + +#[derive(clap::Subcommand, Debug, Clone)] +pub enum ServiceAction { + /// initialize new service boilerplate + #[command(name = "init", aliases=["i"])] + InitService { + /// service boilerplate language + #[arg(value_enum, short, long, default_value_t = ServiceLanguage::Rust)] + lang: ServiceLanguage, + + /// directory to create service boilerplate in + #[arg(short, long)] + path: PathBuf, + }, +} + +pub async fn service_cmd(args: &ServiceArgs) -> Result<()> { + match &args.action { + ServiceAction::InitService { lang, path } => bootstrap_service(lang, path), + } +} diff --git a/crates/iotaop-cli/src/command.rs b/crates/iotaop-cli/src/command.rs new file mode 100644 index 00000000000..a1d3efbc09d --- /dev/null +++ b/crates/iotaop-cli/src/command.rs @@ -0,0 +1,80 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::process::{Command, Output, Stdio}; + +use anyhow::{anyhow, Context, Result}; +use spinners::{Spinner, Spinners}; +use tracing::debug; +const SPINNER: Spinners = Spinners::Dots12; + +#[derive(Debug, Clone)] +pub struct CommandOptions { + shared_stdio: bool, + show_spinner: bool, +} + +impl CommandOptions { + pub fn new(shared_stdio: bool, show_spinner: bool) -> Self { + CommandOptions { + shared_stdio, + show_spinner, + } + } +} + +impl Default for CommandOptions { + fn default() -> Self { + CommandOptions { + shared_stdio: false, + show_spinner: true, + } + } +} + +pub fn run_cmd(cmd_in: Vec<&str>, options: Option) -> Result { + debug!("attempting to run {}", cmd_in.join(" ")); + let opts = if let Some(opts) = options { + opts + } else { + CommandOptions::default() + }; + + let mut cmd = Command::new(cmd_in[0]); + // add extra args + let cmd = if cmd_in.len() > 1 { + cmd.args(cmd_in[1..].iter()) + } else { + &mut cmd + }; + // add stdio + let cmd = if opts.shared_stdio { + debug!("stdio will be shared between parent shell and command process"); + cmd.stdout(Stdio::inherit()).stdin(Stdio::inherit()) + } else { + cmd + }; + let res = if opts.show_spinner { + let mut sp = Spinner::new(SPINNER, "".into()); + let result = cmd.output().context(format!( + "failed to run command with spinner {}", + cmd_in.join(" ") + ))?; + sp.stop(); + print!("\r"); + result + } else { + cmd.output() + .context(format!("failed to run command {}", cmd_in.join(" ")))? + }; + + if !res.status.success() { + Err(anyhow!( + "command failed to run: {}", + std::str::from_utf8(&res.stderr)? + )) + } else { + Ok(res) + } +} diff --git a/crates/iotaop-cli/src/lib.rs b/crates/iotaop-cli/src/lib.rs new file mode 100644 index 00000000000..69cc1eec0f1 --- /dev/null +++ b/crates/iotaop-cli/src/lib.rs @@ -0,0 +1,7 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod cli; +pub mod command; +pub use command::run_cmd; diff --git a/crates/iotaop-cli/src/main.rs b/crates/iotaop-cli/src/main.rs new file mode 100644 index 00000000000..06c38786599 --- /dev/null +++ b/crates/iotaop-cli/src/main.rs @@ -0,0 +1,59 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::Result; +use clap::Parser; +use iotaoplib::cli::{ + incidents_cmd, pulumi_cmd, service_cmd, IncidentsArgs, PulumiArgs, ServiceArgs, +}; +use tracing_subscriber::{ + filter::{EnvFilter, LevelFilter}, + FmtSubscriber, +}; + +#[derive(Parser, Debug)] +#[command(author="build@mystenlabs.com", version, about, long_about = None)] +pub(crate) struct IotaOpArgs { + /// The resource type we're operating on. + #[command(subcommand)] + resource: Resource, +} + +#[derive(clap::Subcommand, Debug)] +pub(crate) enum Resource { + #[clap(aliases = ["inc", "i"])] + Incidents(IncidentsArgs), + #[clap(aliases = ["p"])] + Pulumi(PulumiArgs), + #[clap(aliases = ["s", "svc"])] + Service(ServiceArgs), +} + +#[tokio::main(flavor = "current_thread")] +async fn main() -> Result<()> { + let subscriber = FmtSubscriber::builder() + .with_env_filter( + EnvFilter::builder() + .with_default_directive(LevelFilter::INFO.into()) + .from_env_lossy(), + ) + .finish(); + + tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed"); + + let args = IotaOpArgs::parse(); + match args.resource { + Resource::Incidents(args) => { + incidents_cmd(&args).await?; + } + Resource::Pulumi(args) => { + pulumi_cmd(&args).await?; + } + Resource::Service(args) => { + service_cmd(&args).await?; + } + } + + Ok(()) +} diff --git a/crates/mysten-common/src/lib.rs b/crates/mysten-common/src/lib.rs index 3c4df66b8a4..cd9b65b1dd5 100644 --- a/crates/mysten-common/src/lib.rs +++ b/crates/mysten-common/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 pub mod sync; diff --git a/crates/mysten-common/src/sync/async_once_cell.rs b/crates/mysten-common/src/sync/async_once_cell.rs index 4ca6c20d69a..b2759e4ba62 100644 --- a/crates/mysten-common/src/sync/async_once_cell.rs +++ b/crates/mysten-common/src/sync/async_once_cell.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; diff --git a/crates/mysten-common/src/sync/mod.rs b/crates/mysten-common/src/sync/mod.rs index c405ff12697..1bdf86d4156 100644 --- a/crates/mysten-common/src/sync/mod.rs +++ b/crates/mysten-common/src/sync/mod.rs @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 pub mod async_once_cell; -/// Low level ultilities shared between Sui and Narwhal. +/// Low level ultilities shared between Iota and Narwhal. pub mod notify_once; pub mod notify_read; diff --git a/crates/mysten-common/src/sync/notify_once.rs b/crates/mysten-common/src/sync/notify_once.rs index 8e52a478969..f8a54998f67 100644 --- a/crates/mysten-common/src/sync/notify_once.rs +++ b/crates/mysten-common/src/sync/notify_once.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; diff --git a/crates/mysten-common/src/sync/notify_read.rs b/crates/mysten-common/src/sync/notify_read.rs index 98e7594cf1e..dab378bbeb0 100644 --- a/crates/mysten-common/src/sync/notify_read.rs +++ b/crates/mysten-common/src/sync/notify_read.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/mysten-metrics/src/guards.rs b/crates/mysten-metrics/src/guards.rs index d23c519a57c..ee957918a00 100644 --- a/crates/mysten-metrics/src/guards.rs +++ b/crates/mysten-metrics/src/guards.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/mysten-metrics/src/histogram.rs b/crates/mysten-metrics/src/histogram.rs index 0bb007fdea7..59eb07f305b 100644 --- a/crates/mysten-metrics/src/histogram.rs +++ b/crates/mysten-metrics/src/histogram.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/mysten-metrics/src/lib.rs b/crates/mysten-metrics/src/lib.rs index f445888a7a0..209f9a0863a 100644 --- a/crates/mysten-metrics/src/lib.rs +++ b/crates/mysten-metrics/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -442,7 +443,7 @@ mod tests { assert_eq!(metric_1.get_help(), "counter_1_desc"); // AND add a second registry with a metric - let registry_2 = Registry::new_custom(Some("sui".to_string()), None).unwrap(); + let registry_2 = Registry::new_custom(Some("iota".to_string()), None).unwrap(); registry_2 .register(Box::new( IntCounter::new("counter_2", "counter_2_desc").unwrap(), @@ -465,7 +466,7 @@ mod tests { assert_eq!(metric_1.get_help(), "counter_1_desc"); let metric_2 = metrics.remove(0); - assert_eq!(metric_2.get_name(), "sui_counter_2"); + assert_eq!(metric_2.get_name(), "iota_counter_2"); assert_eq!(metric_2.get_help(), "counter_2_desc"); // AND remove first registry @@ -482,7 +483,7 @@ mod tests { assert_eq!(metric_default.get_help(), "counter_desc"); let metric_1 = metrics.remove(0); - assert_eq!(metric_1.get_name(), "sui_counter_2"); + assert_eq!(metric_1.get_name(), "iota_counter_2"); assert_eq!(metric_1.get_help(), "counter_2_desc"); } } diff --git a/crates/mysten-metrics/src/metered_channel.rs b/crates/mysten-metrics/src/metered_channel.rs index 1379ff3a560..97dec4a541a 100644 --- a/crates/mysten-metrics/src/metered_channel.rs +++ b/crates/mysten-metrics/src/metered_channel.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #![allow(dead_code)] diff --git a/crates/mysten-metrics/src/tests/metered_channel_tests.rs b/crates/mysten-metrics/src/tests/metered_channel_tests.rs index 53f756e8fc1..7d72f41bda4 100644 --- a/crates/mysten-metrics/src/tests/metered_channel_tests.rs +++ b/crates/mysten-metrics/src/tests/metered_channel_tests.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use futures::{ task::{noop_waker, Context, Poll}, diff --git a/crates/mysten-network/src/anemo_ext.rs b/crates/mysten-network/src/anemo_ext.rs index eb81e6698c4..11ca1c0fed0 100644 --- a/crates/mysten-network/src/anemo_ext.rs +++ b/crates/mysten-network/src/anemo_ext.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::time::Instant; diff --git a/crates/mysten-network/src/callback/future.rs b/crates/mysten-network/src/callback/future.rs index 36407fb29c6..aaad8548087 100644 --- a/crates/mysten-network/src/callback/future.rs +++ b/crates/mysten-network/src/callback/future.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/mysten-network/src/callback/layer.rs b/crates/mysten-network/src/callback/layer.rs index 75f56bf7450..9e1722bd0d0 100644 --- a/crates/mysten-network/src/callback/layer.rs +++ b/crates/mysten-network/src/callback/layer.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use tower::Layer; diff --git a/crates/mysten-network/src/callback/mod.rs b/crates/mysten-network/src/callback/mod.rs index cb35c2fe8d0..7727cc1b022 100644 --- a/crates/mysten-network/src/callback/mod.rs +++ b/crates/mysten-network/src/callback/mod.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use http::{request, response}; diff --git a/crates/mysten-network/src/callback/service.rs b/crates/mysten-network/src/callback/service.rs index 447d46dcde0..efdb017e349 100644 --- a/crates/mysten-network/src/callback/service.rs +++ b/crates/mysten-network/src/callback/service.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::task::{Context, Poll}; diff --git a/crates/mysten-network/src/client.rs b/crates/mysten-network/src/client.rs index b3f6e66cdff..7c7507b412a 100644 --- a/crates/mysten-network/src/client.rs +++ b/crates/mysten-network/src/client.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use eyre::{eyre, Context, Result}; diff --git a/crates/mysten-network/src/codec.rs b/crates/mysten-network/src/codec.rs index 219760f92a4..790f8ce901f 100644 --- a/crates/mysten-network/src/codec.rs +++ b/crates/mysten-network/src/codec.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{io::Read, marker::PhantomData}; diff --git a/crates/mysten-network/src/config.rs b/crates/mysten-network/src/config.rs index cafb340fcb9..d9735b8c45c 100644 --- a/crates/mysten-network/src/config.rs +++ b/crates/mysten-network/src/config.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::time::Duration; diff --git a/crates/mysten-network/src/lib.rs b/crates/mysten-network/src/lib.rs index 8c226fabdf7..740d66dd1f8 100644 --- a/crates/mysten-network/src/lib.rs +++ b/crates/mysten-network/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 pub mod anemo_ext; pub mod callback; diff --git a/crates/mysten-network/src/metrics.rs b/crates/mysten-network/src/metrics.rs index 7610ac37a26..246e00fc7f8 100644 --- a/crates/mysten-network/src/metrics.rs +++ b/crates/mysten-network/src/metrics.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::time::Duration; diff --git a/crates/mysten-network/src/multiaddr.rs b/crates/mysten-network/src/multiaddr.rs index d5d147af3cf..e9130dbf6f4 100644 --- a/crates/mysten-network/src/multiaddr.rs +++ b/crates/mysten-network/src/multiaddr.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -362,7 +363,7 @@ mod test { #[test] fn test_to_socket_addr_unsupported_protocol() { - let multi_addr_dns = Multiaddr(multiaddr!(Dnsaddr("mysten.sui"), Tcp(10500u16))); + let multi_addr_dns = Multiaddr(multiaddr!(Dnsaddr("mysten.iota"), Tcp(10500u16))); let _ = multi_addr_dns .to_socket_addr() .expect_err("DNS is unsupported"); @@ -374,8 +375,8 @@ mod test { assert_eq!(Some("127.0.0.1".to_string()), multi_addr_ip4.hostname()); assert_eq!(Some(10500u16), multi_addr_ip4.port()); - let multi_addr_dns = Multiaddr(multiaddr!(Dns("mysten.sui"), Tcp(10501u16))); - assert_eq!(Some("mysten.sui".to_string()), multi_addr_dns.hostname()); + let multi_addr_dns = Multiaddr(multiaddr!(Dns("mysten.iota"), Tcp(10501u16))); + assert_eq!(Some("mysten.iota".to_string()), multi_addr_dns.hostname()); assert_eq!(Some(10501u16), multi_addr_dns.port()); } @@ -394,13 +395,13 @@ mod test { .unwrap(); assert_eq!("[f:f:f:f:f:f:f:1]:10500".to_string(), addr_ip6.to_string()); - let addr_dns = Multiaddr(multiaddr!(Dns("mysten.sui"), Udp(10501u16))) + let addr_dns = Multiaddr(multiaddr!(Dns("mysten.iota"), Udp(10501u16))) .to_anemo_address() .unwrap(); - assert_eq!("mysten.sui:10501".to_string(), addr_dns.to_string()); + assert_eq!("mysten.iota:10501".to_string(), addr_dns.to_string()); let addr_invalid = - Multiaddr(multiaddr!(Dns("mysten.sui"), Tcp(10501u16))).to_anemo_address(); + Multiaddr(multiaddr!(Dns("mysten.iota"), Tcp(10501u16))).to_anemo_address(); assert!(addr_invalid.is_err()); } @@ -419,7 +420,8 @@ mod test { assert_eq!(Some("::".to_string()), multi_addr_ip6.hostname()); assert_eq!(Some(10500u16), multi_addr_ip4.port()); - let multi_addr_dns = Multiaddr(multiaddr!(Dns("mysten.sui"), Tcp(10501u16))).with_zero_ip(); + let multi_addr_dns = + Multiaddr(multiaddr!(Dns("mysten.iota"), Tcp(10501u16))).with_zero_ip(); assert_eq!(Some("0.0.0.0".to_string()), multi_addr_dns.hostname()); assert_eq!(Some(10501u16), multi_addr_dns.port()); } @@ -440,7 +442,7 @@ mod test { assert_eq!(Some(10500u16), multi_addr_ip4.port()); let multi_addr_dns = - Multiaddr(multiaddr!(Dns("mysten.sui"), Tcp(10501u16))).with_localhost_ip(); + Multiaddr(multiaddr!(Dns("mysten.iota"), Tcp(10501u16))).with_localhost_ip(); assert_eq!(Some("127.0.0.1".to_string()), multi_addr_dns.hostname()); assert_eq!(Some(10501u16), multi_addr_dns.port()); } diff --git a/crates/mysten-network/src/server.rs b/crates/mysten-network/src/server.rs index 7e6436e4194..013efc4ea21 100644 --- a/crates/mysten-network/src/server.rs +++ b/crates/mysten-network/src/server.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ convert::Infallible, diff --git a/crates/mysten-service-boilerplate/Cargo-sui.toml b/crates/mysten-service-boilerplate/Cargo-iota.toml similarity index 100% rename from crates/mysten-service-boilerplate/Cargo-sui.toml rename to crates/mysten-service-boilerplate/Cargo-iota.toml diff --git a/crates/mysten-service-boilerplate/src/main.rs b/crates/mysten-service-boilerplate/src/main.rs index a39c0ff3934..610613ce5bf 100644 --- a/crates/mysten-service-boilerplate/src/main.rs +++ b/crates/mysten-service-boilerplate/src/main.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; diff --git a/crates/mysten-service/src/health.rs b/crates/mysten-service/src/health.rs index 47e757dbd6f..9197e62ef8b 100644 --- a/crates/mysten-service/src/health.rs +++ b/crates/mysten-service/src/health.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// service health related utilities diff --git a/crates/mysten-service/src/lib.rs b/crates/mysten-service/src/lib.rs index 0db49c4dfec..bce7dd557d1 100644 --- a/crates/mysten-service/src/lib.rs +++ b/crates/mysten-service/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 mod health; diff --git a/crates/mysten-service/src/logging.rs b/crates/mysten-service/src/logging.rs index b1b71ff6c68..21e6c37096d 100644 --- a/crates/mysten-service/src/logging.rs +++ b/crates/mysten-service/src/logging.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use telemetry_subscribers::TelemetryConfig; diff --git a/crates/mysten-service/src/metrics.rs b/crates/mysten-service/src/metrics.rs index 7ef0dd16ca0..db886f80ece 100644 --- a/crates/mysten-service/src/metrics.rs +++ b/crates/mysten-service/src/metrics.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::net::{IpAddr, Ipv4Addr, SocketAddr}; diff --git a/crates/mysten-service/src/service.rs b/crates/mysten-service/src/service.rs index 9d7e1c6b669..95d7d455b30 100644 --- a/crates/mysten-service/src/service.rs +++ b/crates/mysten-service/src/service.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; diff --git a/crates/mysten-service/tests/integration_test.rs b/crates/mysten-service/tests/integration_test.rs index 760a785b18d..5c90b52a3a5 100644 --- a/crates/mysten-service/tests/integration_test.rs +++ b/crates/mysten-service/tests/integration_test.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use axum::{ diff --git a/crates/mysten-util-mem-derive/lib.rs b/crates/mysten-util-mem-derive/lib.rs index 77d92c7482e..1fd9edb929f 100644 --- a/crates/mysten-util-mem-derive/lib.rs +++ b/crates/mysten-util-mem-derive/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Parity Technologies diff --git a/crates/mysten-util-mem/src/allocators.rs b/crates/mysten-util-mem/src/allocators.rs index 91b5cddadca..88fa19a5594 100644 --- a/crates/mysten-util-mem/src/allocators.rs +++ b/crates/mysten-util-mem/src/allocators.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Parity Technologies diff --git a/crates/mysten-util-mem/src/external_impls.rs b/crates/mysten-util-mem/src/external_impls.rs index d8168aba786..f22b1425357 100644 --- a/crates/mysten-util-mem/src/external_impls.rs +++ b/crates/mysten-util-mem/src/external_impls.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use crate::{MallocShallowSizeOf, MallocSizeOf}; diff --git a/crates/mysten-util-mem/src/lib.rs b/crates/mysten-util-mem/src/lib.rs index a07d3247654..91ff0e82fd4 100644 --- a/crates/mysten-util-mem/src/lib.rs +++ b/crates/mysten-util-mem/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Parity Technologies diff --git a/crates/mysten-util-mem/src/malloc_size.rs b/crates/mysten-util-mem/src/malloc_size.rs index 261848ec042..57c3d52cf94 100644 --- a/crates/mysten-util-mem/src/malloc_size.rs +++ b/crates/mysten-util-mem/src/malloc_size.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Copyright 2016-2017 The Servo Project Developers. See the COPYRIGHT diff --git a/crates/mysten-util-mem/src/memory_stats_noop.rs b/crates/mysten-util-mem/src/memory_stats_noop.rs index fee053a4997..40d225de289 100644 --- a/crates/mysten-util-mem/src/memory_stats_noop.rs +++ b/crates/mysten-util-mem/src/memory_stats_noop.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Copyright 2021 Parity Technologies diff --git a/crates/mysten-util-mem/src/sizeof.rs b/crates/mysten-util-mem/src/sizeof.rs index 8d2dd06105a..b038017c12f 100644 --- a/crates/mysten-util-mem/src/sizeof.rs +++ b/crates/mysten-util-mem/src/sizeof.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Parity Technologies diff --git a/crates/mysten-util-mem/tests/derive.rs b/crates/mysten-util-mem/tests/derive.rs index 0beeb6fb11c..6aedd77d994 100644 --- a/crates/mysten-util-mem/tests/derive.rs +++ b/crates/mysten-util-mem/tests/derive.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Parity Technologies diff --git a/crates/prometheus-closure-metric/src/lib.rs b/crates/prometheus-closure-metric/src/lib.rs index c978552af7f..d39a83ebc4d 100644 --- a/crates/prometheus-closure-metric/src/lib.rs +++ b/crates/prometheus-closure-metric/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 // Copyright 2014 The Prometheus Authors diff --git a/crates/prometheus-closure-metric/tests/closure_metric.rs b/crates/prometheus-closure-metric/tests/closure_metric.rs index 039a9372227..e81ecad1a4e 100644 --- a/crates/prometheus-closure-metric/tests/closure_metric.rs +++ b/crates/prometheus-closure-metric/tests/closure_metric.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use prometheus_closure_metric::ClosureMetric; diff --git a/crates/shared-crypto/src/intent.rs b/crates/shared-crypto/src/intent.rs index efdc149aedb..31851fc832d 100644 --- a/crates/shared-crypto/src/intent.rs +++ b/crates/shared-crypto/src/intent.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::str::FromStr; @@ -27,14 +28,14 @@ impl TryFrom for IntentVersion { } /// This enums specifies the application ID. Two intents in two different -/// applications (i.e., Narwhal, Sui, Ethereum etc) should never collide, so +/// applications (i.e., Narwhal, Iota, Ethereum etc) should never collide, so /// that even when a signing key is reused, nobody can take a signature /// designated for app_1 and present it as a valid signature for an (any) intent /// in app_2. #[derive(Serialize_repr, Deserialize_repr, Copy, Clone, PartialEq, Eq, Debug, Hash)] #[repr(u8)] pub enum AppId { - Sui = 0, + Iota = 0, Narwhal = 1, Consensus = 2, } @@ -49,7 +50,7 @@ impl TryFrom for AppId { impl Default for AppId { fn default() -> Self { - Self::Sui + Self::Iota } } @@ -109,19 +110,19 @@ impl FromStr for Intent { } impl Intent { - pub fn sui_app(scope: IntentScope) -> Self { + pub fn iota_app(scope: IntentScope) -> Self { Self { version: IntentVersion::V0, scope, - app_id: AppId::Sui, + app_id: AppId::Iota, } } - pub fn sui_transaction() -> Self { + pub fn iota_transaction() -> Self { Self { scope: IntentScope::TransactionData, version: IntentVersion::V0, - app_id: AppId::Sui, + app_id: AppId::Iota, } } @@ -129,7 +130,7 @@ impl Intent { Self { scope: IntentScope::PersonalMessage, version: IntentVersion::V0, - app_id: AppId::Sui, + app_id: AppId::Iota, } } @@ -151,7 +152,7 @@ impl Intent { } /// Intent Message is a wrapper around a message with its intent. The message -/// can be any type that implements [trait Serialize]. *ALL* signatures in Sui +/// can be any type that implements [trait Serialize]. *ALL* signatures in Iota /// must commits to the intent message, not the message itself. This guarantees /// any intent message signed in the system cannot collide with another since /// they are domain separated by intent. @@ -185,10 +186,10 @@ pub(crate) mod private { impl SealedIntent for IntentMessage {} } -/// A 1-byte domain separator for hashing Object ID in Sui. It is starting from -/// 0xf0 to ensure no hashing collision for any ObjectID vs SuiAddress which is +/// A 1-byte domain separator for hashing Object ID in Iota. It is starting from +/// 0xf0 to ensure no hashing collision for any ObjectID vs IotaAddress which is /// derived as the hash of `flag || pubkey`. See -/// `sui_types::crypto::SignatureScheme::flag()`. +/// `iota_types::crypto::SignatureScheme::flag()`. #[derive(Serialize_repr, Deserialize_repr, Copy, Clone, PartialEq, Eq, Debug, Hash)] #[repr(u8)] pub enum HashingIntentScope { diff --git a/crates/shared-crypto/src/lib.rs b/crates/shared-crypto/src/lib.rs index 7e26a8fbdea..61d1590cce9 100644 --- a/crates/shared-crypto/src/lib.rs +++ b/crates/shared-crypto/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 pub mod intent; diff --git a/crates/simulacrum/Cargo.toml b/crates/simulacrum/Cargo.toml index c8f8d24f43f..1b6f87caf5e 100644 --- a/crates/simulacrum/Cargo.toml +++ b/crates/simulacrum/Cargo.toml @@ -22,13 +22,13 @@ futures.workspace = true move-bytecode-utils.workspace = true shared-crypto.workspace = true -sui-config.workspace = true -sui-framework.workspace = true -sui-keys.workspace = true -sui-protocol-config.workspace = true -sui-storage.workspace = true -sui-types.workspace = true -sui-genesis-builder.workspace = true -sui-execution.workspace = true -sui-swarm-config.workspace = true -sui-transaction-checks.workspace = true +iota-config.workspace = true +iota-framework.workspace = true +iota-keys.workspace = true +iota-protocol-config.workspace = true +iota-storage.workspace = true +iota-types.workspace = true +iota-genesis-builder.workspace = true +iota-execution.workspace = true +iota-swarm-config.workspace = true +iota-transaction-checks.workspace = true diff --git a/crates/simulacrum/src/epoch_state.rs b/crates/simulacrum/src/epoch_state.rs index a949710fb8b..8437fbed599 100644 --- a/crates/simulacrum/src/epoch_state.rs +++ b/crates/simulacrum/src/epoch_state.rs @@ -1,22 +1,23 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{collections::HashSet, sync::Arc}; use anyhow::Result; -use sui_config::transaction_deny_config::TransactionDenyConfig; -use sui_execution::Executor; -use sui_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; -use sui_types::{ +use iota_config::transaction_deny_config::TransactionDenyConfig; +use iota_execution::Executor; +use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; +use iota_types::{ committee::{Committee, EpochId}, effects::TransactionEffects, - gas::SuiGasStatus, + gas::IotaGasStatus, inner_temporary_store::InnerTemporaryStore, - metrics::{BytecodeVerifierMetrics, LimitsMetrics}, - sui_system_state::{ - epoch_start_sui_system_state::{EpochStartSystemState, EpochStartSystemStateTrait}, - SuiSystemState, SuiSystemStateTrait, + iota_system_state::{ + epoch_start_iota_system_state::{EpochStartSystemState, EpochStartSystemStateTrait}, + IotaSystemState, IotaSystemStateTrait, }, + metrics::{BytecodeVerifierMetrics, LimitsMetrics}, transaction::{TransactionDataAPI, VerifiedTransaction}, }; @@ -36,15 +37,15 @@ pub struct EpochState { } impl EpochState { - pub fn new(system_state: SuiSystemState) -> Self { + pub fn new(system_state: IotaSystemState) -> Self { let epoch_start_state = system_state.into_epoch_start_state(); - let committee = epoch_start_state.get_sui_committee(); + let committee = epoch_start_state.get_iota_committee(); let protocol_config = ProtocolConfig::get_for_version(epoch_start_state.protocol_version(), Chain::Unknown); let registry = prometheus::Registry::new(); let limits_metrics = Arc::new(LimitsMetrics::new(®istry)); let bytecode_verifier_metrics = Arc::new(BytecodeVerifierMetrics::new(®istry)); - let executor = sui_execution::executor(&protocol_config, true, None).unwrap(); + let executor = iota_execution::executor(&protocol_config, true, None).unwrap(); Self { epoch_start_state, @@ -94,16 +95,16 @@ impl EpochState { transaction: &VerifiedTransaction, ) -> Result<( InnerTemporaryStore, - SuiGasStatus, + IotaGasStatus, TransactionEffects, - Result<(), sui_types::error::ExecutionError>, + Result<(), iota_types::error::ExecutionError>, )> { let tx_digest = *transaction.digest(); let tx_data = &transaction.data().intent_message().value; let input_object_kinds = tx_data.input_objects()?; let receiving_object_refs = tx_data.receiving_objects(); - sui_transaction_checks::deny::check_transaction_for_signing( + iota_transaction_checks::deny::check_transaction_for_signing( tx_data, transaction.tx_signatures(), &input_object_kinds, @@ -120,7 +121,7 @@ impl EpochState { // Run the transaction input checks that would run when submitting the txn to a // validator for signing - let (gas_status, checked_input_objects) = sui_transaction_checks::check_transaction_input( + let (gas_status, checked_input_objects) = iota_transaction_checks::check_transaction_input( &self.protocol_config, self.epoch_start_state.reference_gas_price(), transaction.data().transaction_data(), diff --git a/crates/simulacrum/src/lib.rs b/crates/simulacrum/src/lib.rs index cd759513746..4166e9d5121 100644 --- a/crates/simulacrum/src/lib.rs +++ b/crates/simulacrum/src/lib.rs @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -//! A `Simulacrum` of Sui. +//! A `Simulacrum` of Iota. //! //! The word simulacrum is latin for "likeness, semblance", it is also a spell //! in D&D which creates a copy of a creature which then follows the player's //! commands and wishes. As such this crate provides the [`Simulacrum`] type -//! which is a implementation or instantiation of a sui blockchain, one which +//! which is a implementation or instantiation of a iota blockchain, one which //! doesn't do anything unless acted upon. //! //! [`Simulacrum`]: crate::Simulacrum @@ -15,43 +16,43 @@ use std::{num::NonZeroUsize, sync::Arc}; use anyhow::{anyhow, Result}; use fastcrypto::traits::Signer; -use rand::rngs::OsRng; -use sui_config::{genesis, transaction_deny_config::TransactionDenyConfig}; -use sui_protocol_config::ProtocolVersion; -use sui_swarm_config::{ +use iota_config::{genesis, transaction_deny_config::TransactionDenyConfig}; +use iota_protocol_config::ProtocolVersion; +use iota_swarm_config::{ genesis_config::AccountConfig, network_config::NetworkConfig, network_config_builder::ConfigBuilder, }; -use sui_types::{ - base_types::{AuthorityName, ObjectID, SuiAddress, VersionNumber}, +use iota_types::{ + base_types::{AuthorityName, IotaAddress, ObjectID, VersionNumber}, committee::Committee, crypto::AuthoritySignature, digests::ConsensusCommitDigest, effects::TransactionEffects, error::ExecutionError, - gas_coin::{GasCoin, MIST_PER_SUI}, + gas_coin::{GasCoin, MICROS_PER_IOTA}, inner_temporary_store::InnerTemporaryStore, + iota_system_state::epoch_start_iota_system_state::EpochStartSystemState, messages_checkpoint::{EndOfEpochData, VerifiedCheckpoint}, mock_checkpoint_builder::{MockCheckpointBuilder, ValidatorKeypairProvider}, object::Object, programmable_transaction_builder::ProgrammableTransactionBuilder, signature::VerifyParams, storage::{ObjectStore, ReadStore}, - sui_system_state::epoch_start_sui_system_state::EpochStartSystemState, transaction::{ EndOfEpochTransactionKind, GasData, Transaction, TransactionData, TransactionKind, VerifiedTransaction, }, }; +use rand::rngs::OsRng; pub use self::store::{in_mem_store::InMemoryStore, SimulatorStore}; use self::{epoch_state::EpochState, store::in_mem_store::KeyStore}; mod epoch_state; pub mod store; -/// A `Simulacrum` of Sui. +/// A `Simulacrum` of Iota. /// -/// This type represents a simulated instantiation of a Sui blockchain that +/// This type represents a simulated instantiation of a Iota blockchain that /// needs to be driven manually, that is time doesn't advance and checkpoints /// are not formed unless explicitly requested. /// @@ -137,7 +138,7 @@ impl Simulacrum { let checkpoint_builder = MockCheckpointBuilder::new(config.genesis.checkpoint()); let genesis = &config.genesis; - let epoch_state = EpochState::new(genesis.sui_system_object()); + let epoch_state = EpochState::new(genesis.iota_system_object()); Self { rng, @@ -310,22 +311,22 @@ impl Simulacrum { self.epoch_state.reference_gas_price() } - /// Request that `amount` Mist be sent to `address` from a faucet account. + /// Request that `amount` Micros be sent to `address` from a faucet account. /// /// ``` + /// use iota_types::{base_types::IotaAddress, gas_coin::MICROS_PER_IOTA}; /// use simulacrum::Simulacrum; - /// use sui_types::{base_types::SuiAddress, gas_coin::MIST_PER_SUI}; /// /// # fn main() { /// let mut simulacrum = Simulacrum::new(); - /// let address = SuiAddress::generate(simulacrum.rng()); - /// simulacrum.request_gas(address, MIST_PER_SUI).unwrap(); + /// let address = IotaAddress::generate(simulacrum.rng()); + /// simulacrum.request_gas(address, MICROS_PER_IOTA).unwrap(); /// - /// // `account` now has a Coin object with single SUI in it. + /// // `account` now has a Coin object with single IOTA in it. /// // ... /// # } /// ``` - pub fn request_gas(&mut self, address: SuiAddress, amount: u64) -> Result { + pub fn request_gas(&mut self, address: IotaAddress, amount: u64) -> Result { // For right now we'll just use the first account as the `faucet` account. We // may want to explicitly cordon off the faucet account from the rest of // the accounts though. @@ -334,29 +335,29 @@ impl Simulacrum { .store() .owned_objects(*sender) .find(|object| { - object.is_gas_coin() && object.get_coin_value_unsafe() > amount + MIST_PER_SUI + object.is_gas_coin() && object.get_coin_value_unsafe() > amount + MICROS_PER_IOTA }) .ok_or_else(|| { - anyhow!("unable to find a coin with enough to satisfy request for {amount} Mist") + anyhow!("unable to find a coin with enough to satisfy request for {amount} Micros") })?; - let gas_data = sui_types::transaction::GasData { + let gas_data = iota_types::transaction::GasData { payment: vec![object.compute_object_reference()], owner: *sender, price: self.reference_gas_price(), - budget: MIST_PER_SUI, + budget: MICROS_PER_IOTA, }; let pt = { let mut builder = - sui_types::programmable_transaction_builder::ProgrammableTransactionBuilder::new(); - builder.transfer_sui(address, Some(amount)); + iota_types::programmable_transaction_builder::ProgrammableTransactionBuilder::new(); + builder.transfer_iota(address, Some(amount)); builder.finish() }; - let kind = sui_types::transaction::TransactionKind::ProgrammableTransaction(pt); + let kind = iota_types::transaction::TransactionKind::ProgrammableTransaction(pt); let tx_data = - sui_types::transaction::TransactionData::new_with_gas_data(kind, *sender, gas_data); + iota_types::transaction::TransactionData::new_with_gas_data(kind, *sender, gas_data); let tx = Transaction::from_data_and_signer(tx_data, vec![key]); self.execute_transaction(tx).map(|x| x.0) @@ -395,7 +396,7 @@ impl ObjectStore for Simulacrum { fn get_object( &self, object_id: &ObjectID, - ) -> Result, sui_types::storage::error::Error> { + ) -> Result, iota_types::storage::error::Error> { Ok(store::SimulatorStore::get_object(&self.store, object_id)) } @@ -403,7 +404,7 @@ impl ObjectStore for Simulacrum { &self, object_id: &ObjectID, version: VersionNumber, - ) -> Result, sui_types::storage::error::Error> { + ) -> Result, iota_types::storage::error::Error> { self.store.get_object_by_key(object_id, version) } } @@ -411,30 +412,30 @@ impl ObjectStore for Simulacrum { impl ReadStore for Simulacrum { fn get_committee( &self, - _epoch: sui_types::committee::EpochId, - ) -> sui_types::storage::error::Result>> { + _epoch: iota_types::committee::EpochId, + ) -> iota_types::storage::error::Result>> { todo!() } - fn get_latest_checkpoint(&self) -> sui_types::storage::error::Result { + fn get_latest_checkpoint(&self) -> iota_types::storage::error::Result { Ok(self.store().get_highest_checkpint().unwrap()) } fn get_highest_verified_checkpoint( &self, - ) -> sui_types::storage::error::Result { + ) -> iota_types::storage::error::Result { todo!() } fn get_highest_synced_checkpoint( &self, - ) -> sui_types::storage::error::Result { + ) -> iota_types::storage::error::Result { todo!() } fn get_lowest_available_checkpoint( &self, - ) -> sui_types::storage::error::Result + ) -> iota_types::storage::error::Result { // TODO wire this up to the underlying sim store, for now this will work since // we never prune the sim store @@ -443,15 +444,15 @@ impl ReadStore for Simulacrum { fn get_checkpoint_by_digest( &self, - digest: &sui_types::messages_checkpoint::CheckpointDigest, - ) -> sui_types::storage::error::Result> { + digest: &iota_types::messages_checkpoint::CheckpointDigest, + ) -> iota_types::storage::error::Result> { Ok(self.store().get_checkpoint_by_digest(digest)) } fn get_checkpoint_by_sequence_number( &self, - sequence_number: sui_types::messages_checkpoint::CheckpointSequenceNumber, - ) -> sui_types::storage::error::Result> { + sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber, + ) -> iota_types::storage::error::Result> { Ok(self .store() .get_checkpoint_by_sequence_number(sequence_number)) @@ -459,55 +460,57 @@ impl ReadStore for Simulacrum { fn get_checkpoint_contents_by_digest( &self, - digest: &sui_types::messages_checkpoint::CheckpointContentsDigest, - ) -> sui_types::storage::error::Result> - { + digest: &iota_types::messages_checkpoint::CheckpointContentsDigest, + ) -> iota_types::storage::error::Result< + Option, + > { Ok(self.store().get_checkpoint_contents(digest)) } fn get_checkpoint_contents_by_sequence_number( &self, - _sequence_number: sui_types::messages_checkpoint::CheckpointSequenceNumber, - ) -> sui_types::storage::error::Result> - { + _sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber, + ) -> iota_types::storage::error::Result< + Option, + > { todo!() } fn get_transaction( &self, - tx_digest: &sui_types::digests::TransactionDigest, - ) -> sui_types::storage::error::Result>> { + tx_digest: &iota_types::digests::TransactionDigest, + ) -> iota_types::storage::error::Result>> { Ok(self.store().get_transaction(tx_digest).map(Arc::new)) } fn get_transaction_effects( &self, - tx_digest: &sui_types::digests::TransactionDigest, - ) -> sui_types::storage::error::Result> { + tx_digest: &iota_types::digests::TransactionDigest, + ) -> iota_types::storage::error::Result> { Ok(self.store().get_transaction_effects(tx_digest)) } fn get_events( &self, - event_digest: &sui_types::digests::TransactionEventsDigest, - ) -> sui_types::storage::error::Result> { + event_digest: &iota_types::digests::TransactionEventsDigest, + ) -> iota_types::storage::error::Result> { Ok(self.store().get_transaction_events(event_digest)) } fn get_full_checkpoint_contents_by_sequence_number( &self, - _sequence_number: sui_types::messages_checkpoint::CheckpointSequenceNumber, - ) -> sui_types::storage::error::Result< - Option, + _sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber, + ) -> iota_types::storage::error::Result< + Option, > { todo!() } fn get_full_checkpoint_contents( &self, - _digest: &sui_types::messages_checkpoint::CheckpointContentsDigest, - ) -> sui_types::storage::error::Result< - Option, + _digest: &iota_types::messages_checkpoint::CheckpointContentsDigest, + ) -> iota_types::storage::error::Result< + Option, > { todo!() } @@ -517,10 +520,10 @@ impl Simulacrum { /// Generate a random transfer transaction. /// TODO: This is here today to make it easier to write tests. But we should /// utilize all the existing code for generating transactions in - /// sui-test-transaction-builder by defining a trait + /// iota-test-transaction-builder by defining a trait /// that both WalletContext and Simulacrum implement. Then we can remove /// this function. - pub fn transfer_txn(&mut self, recipient: SuiAddress) -> (Transaction, u64) { + pub fn transfer_txn(&mut self, recipient: IotaAddress) -> (Transaction, u64) { let (sender, key) = self.keystore().accounts().next().unwrap(); let sender = *sender; @@ -534,7 +537,7 @@ impl Simulacrum { let pt = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.transfer_sui(recipient, Some(transfer_amount)); + builder.transfer_iota(recipient, Some(transfer_amount)); builder.finish() }; @@ -555,11 +558,11 @@ impl Simulacrum { mod tests { use std::time::Duration; - use rand::{rngs::StdRng, SeedableRng}; - use sui_types::{ - base_types::SuiAddress, effects::TransactionEffectsAPI, gas_coin::GasCoin, + use iota_types::{ + base_types::IotaAddress, effects::TransactionEffectsAPI, gas_coin::GasCoin, transaction::TransactionDataAPI, }; + use rand::{rngs::StdRng, SeedableRng}; use super::*; @@ -632,7 +635,7 @@ mod tests { #[test] fn transfer() { let mut sim = Simulacrum::new(); - let recipient = SuiAddress::random_for_testing_only(); + let recipient = IotaAddress::random_for_testing_only(); let (tx, transfer_amount) = sim.transfer_txn(recipient); let gas_id = tx.data().transaction_data().gas_data().payment[0].0; diff --git a/crates/simulacrum/src/store/in_mem_store.rs b/crates/simulacrum/src/store/in_mem_store.rs index fe9fc48dda0..2e45e05a7d1 100644 --- a/crates/simulacrum/src/store/in_mem_store.rs +++ b/crates/simulacrum/src/store/in_mem_store.rs @@ -1,19 +1,17 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::{BTreeMap, HashMap}; -use move_binary_format::CompiledModule; -use move_bytecode_utils::module_cache::GetModule; -use move_core_types::{language_storage::ModuleId, resolver::ModuleResolver}; -use sui_config::genesis; -use sui_types::{ - base_types::{AuthorityName, ObjectID, SequenceNumber, SuiAddress}, +use iota_config::genesis; +use iota_types::{ + base_types::{AuthorityName, IotaAddress, ObjectID, SequenceNumber}, committee::{Committee, EpochId}, crypto::{AccountKeyPair, AuthorityKeyPair}, digests::{ObjectDigest, TransactionDigest, TransactionEventsDigest}, effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, - error::SuiError, + error::IotaError, messages_checkpoint::{ CheckpointContents, CheckpointContentsDigest, CheckpointDigest, CheckpointSequenceNumber, VerifiedCheckpoint, @@ -25,6 +23,9 @@ use sui_types::{ }, transaction::VerifiedTransaction, }; +use move_binary_format::CompiledModule; +use move_bytecode_utils::module_cache::GetModule; +use move_core_types::{language_storage::ModuleId, resolver::ModuleResolver}; use super::SimulatorStore; @@ -118,18 +119,18 @@ impl InMemoryStore { .and_then(|versions| versions.get(&version)) } - pub fn get_system_state(&self) -> sui_types::sui_system_state::SuiSystemState { - sui_types::sui_system_state::get_sui_system_state(self).expect("system state must exist") + pub fn get_system_state(&self) -> iota_types::iota_system_state::IotaSystemState { + iota_types::iota_system_state::get_iota_system_state(self).expect("system state must exist") } - pub fn get_clock(&self) -> sui_types::clock::Clock { - self.get_object(&sui_types::SUI_CLOCK_OBJECT_ID) + pub fn get_clock(&self) -> iota_types::clock::Clock { + self.get_object(&iota_types::IOTA_CLOCK_OBJECT_ID) .expect("clock should exist") .to_rust() .expect("clock object should deserialize") } - pub fn owned_objects(&self, owner: SuiAddress) -> impl Iterator { + pub fn owned_objects(&self, owner: IotaAddress) -> impl Iterator { self.live_objects .iter() .flat_map(|(id, version)| self.get_object_at_version(id, *version)) @@ -230,7 +231,7 @@ impl BackingPackageStore for InMemoryStore { fn get_package_object( &self, package_id: &ObjectID, - ) -> sui_types::error::SuiResult> { + ) -> iota_types::error::IotaResult> { load_package_object_from_object_store(self, package_id) } } @@ -241,7 +242,7 @@ impl ChildObjectResolver for InMemoryStore { parent: &ObjectID, child: &ObjectID, child_version_upper_bound: SequenceNumber, - ) -> sui_types::error::SuiResult> { + ) -> iota_types::error::IotaResult> { let child_object = match crate::store::SimulatorStore::get_object(self, child) { None => return Ok(None), Some(obj) => obj, @@ -249,7 +250,7 @@ impl ChildObjectResolver for InMemoryStore { let parent = *parent; if child_object.owner != Owner::ObjectOwner(parent.into()) { - return Err(SuiError::InvalidChildObjectAccess { + return Err(IotaError::InvalidChildObjectAccess { object: *child, given_parent: parent, actual_owner: child_object.owner, @@ -257,7 +258,7 @@ impl ChildObjectResolver for InMemoryStore { } if child_object.version() > child_version_upper_bound { - return Err(SuiError::UnsupportedFeatureError { + return Err(IotaError::UnsupportedFeatureError { error: "TODO InMemoryStorage::read_child_object does not yet support bounded reads" .to_owned(), }); @@ -272,7 +273,7 @@ impl ChildObjectResolver for InMemoryStore { receiving_object_id: &ObjectID, receive_object_at_version: SequenceNumber, _epoch_id: EpochId, - ) -> sui_types::error::SuiResult> { + ) -> iota_types::error::IotaResult> { let recv_object = match crate::store::SimulatorStore::get_object(self, receiving_object_id) { None => return Ok(None), @@ -290,7 +291,7 @@ impl ChildObjectResolver for InMemoryStore { } impl GetModule for InMemoryStore { - type Error = SuiError; + type Error = IotaError; type Item = CompiledModule; fn get_module_by_id(&self, id: &ModuleId) -> Result, Self::Error> { @@ -301,7 +302,7 @@ impl GetModule for InMemoryStore { } impl ModuleResolver for InMemoryStore { - type Error = SuiError; + type Error = IotaError; fn get_module(&self, module_id: &ModuleId) -> Result>, Self::Error> { get_module(self, module_id) @@ -312,15 +313,15 @@ impl ObjectStore for InMemoryStore { fn get_object( &self, object_id: &ObjectID, - ) -> Result, sui_types::storage::error::Error> { + ) -> Result, iota_types::storage::error::Error> { Ok(self.get_object(object_id).cloned()) } fn get_object_by_key( &self, object_id: &ObjectID, - version: sui_types::base_types::VersionNumber, - ) -> Result, sui_types::storage::error::Error> { + version: iota_types::base_types::VersionNumber, + ) -> Result, iota_types::storage::error::Error> { Ok(self.get_object_at_version(object_id, version).cloned()) } } @@ -329,7 +330,7 @@ impl ParentSync for InMemoryStore { fn get_latest_parent_entry_ref_deprecated( &self, _object_id: ObjectID, - ) -> sui_types::error::SuiResult> { + ) -> iota_types::error::IotaResult> { panic!("Never called in newer protocol versions") } } @@ -338,12 +339,12 @@ impl ParentSync for InMemoryStore { pub struct KeyStore { validator_keys: BTreeMap, #[allow(unused)] - account_keys: BTreeMap, + account_keys: BTreeMap, } impl KeyStore { pub fn from_network_config( - network_config: &sui_swarm_config::network_config::NetworkConfig, + network_config: &iota_swarm_config::network_config::NetworkConfig, ) -> Self { use fastcrypto::traits::KeyPair; @@ -373,7 +374,7 @@ impl KeyStore { self.validator_keys.get(name) } - pub fn accounts(&self) -> impl Iterator { + pub fn accounts(&self) -> impl Iterator { self.account_keys.iter() } } @@ -439,15 +440,15 @@ impl SimulatorStore for InMemoryStore { self.get_object_at_version(id, version).cloned() } - fn get_system_state(&self) -> sui_types::sui_system_state::SuiSystemState { + fn get_system_state(&self) -> iota_types::iota_system_state::IotaSystemState { self.get_system_state() } - fn get_clock(&self) -> sui_types::clock::Clock { + fn get_clock(&self) -> iota_types::clock::Clock { self.get_clock() } - fn owned_objects(&self, owner: SuiAddress) -> Box + '_> { + fn owned_objects(&self, owner: IotaAddress) -> Box + '_> { Box::new(self.owned_objects(owner).cloned()) } @@ -493,7 +494,7 @@ impl SimulatorStore for InMemoryStore { self.update_objects(written_objects, deleted_objects) } - fn backing_store(&self) -> &dyn sui_types::storage::BackingStore { + fn backing_store(&self) -> &dyn iota_types::storage::BackingStore { self } } diff --git a/crates/simulacrum/src/store/mod.rs b/crates/simulacrum/src/store/mod.rs index dfe91c89dfb..95922499850 100644 --- a/crates/simulacrum/src/store/mod.rs +++ b/crates/simulacrum/src/store/mod.rs @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeMap; -use sui_config::genesis; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress}, +use iota_config::genesis; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber}, committee::{Committee, EpochId}, digests::{ObjectDigest, TransactionDigest, TransactionEventsDigest}, effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, - error::{SuiResult, UserInputError}, + error::{IotaResult, UserInputError}, messages_checkpoint::{ CheckpointContents, CheckpointContentsDigest, CheckpointDigest, CheckpointSequenceNumber, VerifiedCheckpoint, @@ -24,8 +25,8 @@ use sui_types::{ pub mod in_mem_store; pub trait SimulatorStore: - sui_types::storage::BackingPackageStore - + sui_types::storage::ObjectStore + iota_types::storage::BackingPackageStore + + iota_types::storage::ObjectStore + ParentSync + ChildObjectResolver { @@ -84,11 +85,11 @@ pub trait SimulatorStore: fn get_object_at_version(&self, id: &ObjectID, version: SequenceNumber) -> Option; - fn get_system_state(&self) -> sui_types::sui_system_state::SuiSystemState; + fn get_system_state(&self) -> iota_types::iota_system_state::IotaSystemState; - fn get_clock(&self) -> sui_types::clock::Clock; + fn get_clock(&self) -> iota_types::clock::Clock; - fn owned_objects(&self, owner: SuiAddress) -> Box + '_>; + fn owned_objects(&self, owner: IotaAddress) -> Box + '_>; fn insert_checkpoint(&mut self, checkpoint: VerifiedCheckpoint); @@ -119,14 +120,14 @@ pub trait SimulatorStore: fn backing_store(&self) -> &dyn BackingStore; // TODO: After we abstract object storage into the ExecutionCache trait, we can - // replace this with sui_core::TransactionInputLoad using an appropriate + // replace this with iota_core::TransactionInputLoad using an appropriate // cache implementation. fn read_objects_for_synchronous_execution( &self, _tx_digest: &TransactionDigest, input_object_kinds: &[InputObjectKind], receiving_object_refs: &[ObjectRef], - ) -> SuiResult<(InputObjects, ReceivingObjects)> { + ) -> IotaResult<(InputObjects, ReceivingObjects)> { let mut input_objects = Vec::new(); for kind in input_object_kinds { let obj = match kind { diff --git a/crates/sui-adapter-transactional-tests/Cargo.toml b/crates/sui-adapter-transactional-tests/Cargo.toml deleted file mode 100644 index 25538480c9d..00000000000 --- a/crates/sui-adapter-transactional-tests/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "sui-adapter-transactional-tests" -version = "0.1.0" -authors = ["Mysten Labs "] -description = "Transactional tests for Sui Adapter" -license = "Apache-2.0" -publish = false -edition = "2021" - -[dev-dependencies] -datatest-stable.workspace = true -sui-transactional-test-runner.workspace = true - -[[test]] -name = "tests" -harness = false - -[dependencies] diff --git a/crates/sui-adapter-transactional-tests/src/lib.rs b/crates/sui-adapter-transactional-tests/src/lib.rs deleted file mode 100644 index 07fe81c224d..00000000000 --- a/crates/sui-adapter-transactional-tests/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#![forbid(unsafe_code)] - -// Empty src/lib.rs to get rusty-tags working. diff --git a/crates/sui-adapter-transactional-tests/tests/call/simple.exp b/crates/sui-adapter-transactional-tests/tests/call/simple.exp deleted file mode 100644 index 85e0cc2b243..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/call/simple.exp +++ /dev/null @@ -1,16 +0,0 @@ -processed 4 tasks - -task 1 'publish'. lines 6-25: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5570800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 27-27: -created: object(2,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2302800, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'view-object'. lines 29-29: -Owner: Account Address ( A ) -Version: 3 -Contents: Test::M1::Object {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, value: 0u64} diff --git a/crates/sui-adapter-transactional-tests/tests/call/simple.move b/crates/sui-adapter-transactional-tests/tests/call/simple.move deleted file mode 100644 index 34944bd154b..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/call/simple.move +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --addresses Test=0x0 A=0x42 - -//# publish -module Test::M1 { - use sui::coin::Coin; - - public struct Object has key, store { - id: UID, - value: u64, - } - - fun foo(_p1: u64, value1: T, _value2: &Coin, _p2: u64): T { - value1 - } - - public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { - transfer::public_transfer( - Object { id: object::new(ctx), value }, - recipient - ) - } -} - -//# run Test::M1::create --args 0 @A - -//# view-object 2,0 diff --git a/crates/sui-adapter-transactional-tests/tests/checkpoint/clock.move b/crates/sui-adapter-transactional-tests/tests/checkpoint/clock.move deleted file mode 100644 index fa23c81696a..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/checkpoint/clock.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// TODO support system transactions -//# init - -// //# consensus-commit-prologue --timestamp-ms 43 - -// //# view-object 6 - -// //# consensus-commit-prologue --timestamp-ms 45 - -// //# view-object 6 diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/delete_by_wrap.move b/crates/sui-adapter-transactional-tests/tests/child_count/delete_by_wrap.move deleted file mode 100644 index c875a9ce40c..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/child_count/delete_by_wrap.move +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// DEPRECATED child count no longer tracked -// tests invalid wrapping of a parent object with children - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct S has key, store { - id: sui::object::UID, - } - - public struct R has key, store { - id: sui::object::UID, - s: S, - } - - public entry fun mint(ctx: &mut TxContext) { - let id = sui::object::new(ctx); - sui::transfer::public_transfer(S { id }, tx_context::sender(ctx)) - } - - public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { - let child = S { id: sui::object::new(ctx) }; - ofield::add(&mut parent.id, idx, child); - } - - public entry fun wrap(s: S, ctx: &mut TxContext) { - let r = R { id: sui::object::new(ctx), s }; - sui::transfer::public_transfer(r, tx_context::sender(ctx)) - } -} - -//# run test::m::mint --sender A - -//# run test::m::add --sender A --args object(2,0) 0 - -//# view-object 2,0 - -//# run test::m::wrap --sender A --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/delete_by_wrap_one_txn.move b/crates/sui-adapter-transactional-tests/tests/child_count/delete_by_wrap_one_txn.move deleted file mode 100644 index 25b2a990aee..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/child_count/delete_by_wrap_one_txn.move +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// DEPRECATED child count no longer tracked -// tests invalid wrapping of a parent object with children, in a single transaction - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct S has key, store { - id: sui::object::UID, - } - - public struct R has key { - id: sui::object::UID, - s: S, - } - - public entry fun test_wrap(ctx: &mut TxContext) { - let mut id = sui::object::new(ctx); - let child = S { id: sui::object::new(ctx) }; - ofield::add(&mut id, 0, child); - let parent = S { id }; - let r = R { id: sui::object::new(ctx), s: parent }; - sui::transfer::transfer(r, tx_context::sender(ctx)) - } -} - -//# run test::m::test_wrap --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_invalid.move b/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_invalid.move deleted file mode 100644 index f740feffe3d..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_invalid.move +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// DEPRECATED child count no longer tracked -// tests that the parent cannot be deleted while it has children - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct S has key, store { - id: sui::object::UID, - } - - public entry fun mint(ctx: &mut TxContext) { - let id = sui::object::new(ctx); - sui::transfer::public_transfer(S { id }, tx_context::sender(ctx)) - } - - public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { - let child = S { id: sui::object::new(ctx) }; - ofield::add(&mut parent.id, idx, child); - } - - public entry fun delete(s: S) { - let S { id } = s; - sui::object::delete(id) - } -} - -//# run test::m::mint --sender A - -//# run test::m::add --sender A --args object(2,0) 0 - -//# view-object 2,0 - -//# run test::m::delete --sender A --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_valid.move b/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_valid.move deleted file mode 100644 index 780c4f8333d..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_valid.move +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// DEPRECATED child count no longer tracked -// tests valid deletion of an object that has children - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct S has key, store { - id: sui::object::UID, - } - - public struct R has key, store { - id: sui::object::UID, - s: S, - } - - public entry fun mint(ctx: &mut TxContext) { - let id = sui::object::new(ctx); - sui::transfer::public_transfer(S { id }, tx_context::sender(ctx)) - } - - public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { - let child = S { id: sui::object::new(ctx) }; - ofield::add(&mut parent.id, idx, child); - } - - public entry fun remove(parent: &mut S, idx: u64) { - let S { id } = ofield::remove(&mut parent.id, idx); - sui::object::delete(id) - } - - public entry fun remove_and_add(parent: &mut S, idx: u64) { - let child: S = ofield::remove(&mut parent.id, idx); - ofield::add(&mut parent.id, idx, child) - } - - public entry fun remove_and_wrap(parent: &mut S, idx: u64, ctx: &mut TxContext) { - let child: S = ofield::remove(&mut parent.id, idx); - ofield::add(&mut parent.id, idx, R { id: sui::object::new(ctx), s: child }) - } - - public entry fun delete(s: S) { - let S { id } = s; - sui::object::delete(id) - } - - public entry fun wrap(s: S, ctx: &mut TxContext) { - let r = R { id: sui::object::new(ctx), s }; - sui::transfer::public_transfer(r, tx_context::sender(ctx)) - } -} -//# run test::m::mint --sender A - -//# run test::m::add --sender A --args object(2,0) 0 - -//# view-object 2,0 - -//# run test::m::remove --sender A --args object(2,0) 0 - -//# run test::m::delete --sender A --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_valid_one_txn.move b/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_valid_one_txn.move deleted file mode 100644 index a4db5a04624..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/child_count/delete_parent_valid_one_txn.move +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// DEPRECATED child count no longer tracked -// tests valid deletion of an object that has children -// Both child and parent are deleted in one transaction - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct S has key, store { - id: sui::object::UID, - } - - public struct R has key, store { - id: sui::object::UID, - s: S, - } - - public entry fun mint(ctx: &mut TxContext) { - let id = sui::object::new(ctx); - sui::transfer::public_transfer(S { id }, tx_context::sender(ctx)) - } - - public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { - let child = S { id: sui::object::new(ctx) }; - ofield::add(&mut parent.id, idx, child); - } - - public entry fun remove(parent: &mut S, idx: u64) { - let S { id } = ofield::remove(&mut parent.id, idx); - sui::object::delete(id) - } - - public entry fun remove_and_add(parent: &mut S, idx: u64) { - let child: S = ofield::remove(&mut parent.id, idx); - ofield::add(&mut parent.id, idx, child) - } - - public entry fun remove_and_wrap(parent: &mut S, idx: u64, ctx: &mut TxContext) { - let child: S = ofield::remove(&mut parent.id, idx); - ofield::add(&mut parent.id, idx, R { id: sui::object::new(ctx), s: child }) - } - - public entry fun delete(s: S) { - let S { id } = s; - sui::object::delete(id) - } - - public entry fun wrap(s: S, ctx: &mut TxContext) { - let r = R { id: sui::object::new(ctx), s }; - sui::transfer::public_transfer(r, tx_context::sender(ctx)) - } - - public entry fun remove_and_delete(mut s: S, idx: u64) { - let S { id } = ofield::remove(&mut s.id, idx); - sui::object::delete(id); - let S { id } = s; - sui::object::delete(id) - } -} - -// -// Test deleting parent and child in the same txn, parent first -// - -//# run test::m::mint --sender A - -//# run test::m::add --sender A --args object(2,0) 0 - -//# view-object 2,0 - -//# run test::m::remove_and_delete --sender A --args object(2,0) 0 diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_invalid.move b/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_invalid.move deleted file mode 100644 index 59ade67e24c..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_invalid.move +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// DEPRECATED child count no longer tracked -// tests that the parent cannot be frozen while it has children - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct S has key, store { - id: sui::object::UID, - } - - public struct R has key, store { - id: sui::object::UID, - s: S, - } - - public entry fun mint(ctx: &mut TxContext) { - let id = sui::object::new(ctx); - sui::transfer::public_transfer(S { id }, tx_context::sender(ctx)) - } - - public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { - let child = S { id: sui::object::new(ctx) }; - ofield::add(&mut parent.id, idx, child); - } - - public entry fun remove(parent: &mut S, idx: u64) { - let S { id } = ofield::remove(&mut parent.id, idx); - sui::object::delete(id) - } - - public entry fun remove_and_add(parent: &mut S, idx: u64) { - let child: S = ofield::remove(&mut parent.id, idx); - ofield::add(&mut parent.id, idx, child) - } - - public entry fun remove_and_wrap(parent: &mut S, idx: u64, ctx: &mut TxContext) { - let child: S = ofield::remove(&mut parent.id, idx); - ofield::add(&mut parent.id, idx, R { id: sui::object::new(ctx), s: child }) - } - - public entry fun delete(s: S) { - let S { id } = s; - sui::object::delete(id) - } - - public entry fun wrap(s: S, ctx: &mut TxContext) { - let r = R { id: sui::object::new(ctx), s }; - sui::transfer::public_transfer(r, tx_context::sender(ctx)) - } - - public entry fun freeze_object(s: S) { - sui::transfer::public_freeze_object(s) - } -} - -//# run test::m::mint --sender A - -//# run test::m::add --sender A --args object(2,0) 0 - -//# view-object 2,0 - -//# run test::m::freeze_object --sender A --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_valid.move b/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_valid.move deleted file mode 100644 index 2deb558ba67..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_valid.move +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// DEPRECATED child count no longer tracked -// tests valid freezing of an object that has children - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct S has key, store { - id: sui::object::UID, - } - - public struct R has key, store { - id: sui::object::UID, - s: S, - } - - public entry fun mint(ctx: &mut TxContext) { - let id = sui::object::new(ctx); - sui::transfer::public_transfer(S { id }, tx_context::sender(ctx)) - } - - public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { - let child = S { id: sui::object::new(ctx) }; - ofield::add(&mut parent.id, idx, child); - } - - public entry fun remove(parent: &mut S, idx: u64) { - let S { id } = ofield::remove(&mut parent.id, idx); - sui::object::delete(id) - } - - public entry fun remove_and_add(parent: &mut S, idx: u64) { - let child: S = ofield::remove(&mut parent.id, idx); - ofield::add(&mut parent.id, idx, child) - } - - public entry fun remove_and_wrap(parent: &mut S, idx: u64, ctx: &mut TxContext) { - let child: S = ofield::remove(&mut parent.id, idx); - ofield::add(&mut parent.id, idx, R { id: sui::object::new(ctx), s: child }) - } - - public entry fun delete(s: S) { - let S { id } = s; - sui::object::delete(id) - } - - public entry fun wrap(s: S, ctx: &mut TxContext) { - let r = R { id: sui::object::new(ctx), s }; - sui::transfer::public_transfer(r, tx_context::sender(ctx)) - } - - public entry fun freeze_object(s: S) { - sui::transfer::public_freeze_object(s) - } -} - -//# run test::m::mint --sender A - -//# run test::m::add --sender A --args object(2,0) 0 - -//# view-object 2,0 - -//# run test::m::remove --sender A --args object(2,0) 0 - -//# run test::m::freeze_object --sender A --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_valid_one_txn.move b/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_valid_one_txn.move deleted file mode 100644 index 024c2d9fbfb..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/child_count/freeze_parent_valid_one_txn.move +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// DEPRECATED child count no longer tracked -// tests valid freezing of an object that has children -// child is deleted and parent is frozen in one transaction - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct S has key, store { - id: sui::object::UID, - } - - public struct R has key, store { - id: sui::object::UID, - s: S, - } - - public entry fun mint(ctx: &mut TxContext) { - let id = sui::object::new(ctx); - sui::transfer::public_transfer(S { id }, tx_context::sender(ctx)) - } - - public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { - let child = S { id: sui::object::new(ctx) }; - ofield::add(&mut parent.id, idx, child); - } - - public entry fun remove(parent: &mut S, idx: u64) { - let S { id } = ofield::remove(&mut parent.id, idx); - sui::object::delete(id) - } - - public entry fun remove_and_add(parent: &mut S, idx: u64) { - let child: S = ofield::remove(&mut parent.id, idx); - ofield::add(&mut parent.id, idx, child) - } - - public entry fun remove_and_wrap(parent: &mut S, idx: u64, ctx: &mut TxContext) { - let child: S = ofield::remove(&mut parent.id, idx); - ofield::add(&mut parent.id, idx, R { id: sui::object::new(ctx), s: child }) - } - - public entry fun delete(s: S) { - let S { id } = s; - sui::object::delete(id) - } - - public entry fun wrap(s: S, ctx: &mut TxContext) { - let r = R { id: sui::object::new(ctx), s }; - sui::transfer::public_transfer(r, tx_context::sender(ctx)) - } - - public entry fun remove_and_freeze(mut s: S, idx: u64) { - let S { id } = ofield::remove(&mut s.id, idx); - sui::object::delete(id); - sui::transfer::public_freeze_object(s) - } -} - -//# run test::m::mint --sender A - -//# run test::m::add --sender A --args object(2,0) 0 - -//# view-object 2,0 - -//# run test::m::remove_and_freeze --sender A --args object(2,0) 0 diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid.move b/crates/sui-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid.move deleted file mode 100644 index 2ea08894cb6..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid.move +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// DEPRECATED child count no longer tracked -// tests valid transfers of an object that has children - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct S has key, store { - id: sui::object::UID, - } - - public struct R has key, store { - id: sui::object::UID, - s: S, - } - - public entry fun mint(ctx: &mut TxContext) { - let mut id = sui::object::new(ctx); - let child = S { id: sui::object::new(ctx) }; - ofield::add(&mut id, 0, child); - sui::transfer::public_transfer(S { id }, tx_context::sender(ctx)) - } - - public entry fun mint_and_share(ctx: &mut TxContext) { - let mut id = sui::object::new(ctx); - let child = S { id: sui::object::new(ctx) }; - ofield::add(&mut id, 0, child); - sui::transfer::public_share_object(S { id }) - } - - public entry fun transfer(s: S, recipient: address) { - sui::transfer::public_transfer(s, recipient) - } - -} - -// -// Test share object allows non-zero child count -// - -//# run test::m::mint_and_share --sender A - -//# view-object 2,1 - -// -// Test transfer allows non-zero child count -// - -//# run test::m::mint --sender A - -//# run test::m::transfer --sender A --args object(4,2) @B - -//# view-object 4,2 - -// -// Test TransferObject allows non-zero child count -// - -//# run test::m::mint --sender A - -//# transfer-object 7,1 --sender A --recipient B - -//# view-object 7,1 diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid_one_txn.move b/crates/sui-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid_one_txn.move deleted file mode 100644 index 8fe71824f1f..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/child_count/non_zero_child_count_valid_one_txn.move +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// DEPRECATED child count no longer tracked -// tests valid transfers of an object that has children -// all transfers done in a single transaction - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct S has key, store { - id: sui::object::UID, - } - - public struct R has key, store { - id: sui::object::UID, - s: S, - } - - public entry fun share(ctx: &mut TxContext) { - let mut id = sui::object::new(ctx); - let child = S { id: sui::object::new(ctx) }; - ofield::add(&mut id, 0, child); - sui::transfer::public_share_object(S { id }) - } - -} - -// -// Test share object allows non-zero child count -// - -//# run test::m::share --sender A - -//# view-object 2,1 diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/temp_parent_invalid.move b/crates/sui-adapter-transactional-tests/tests/child_count/temp_parent_invalid.move deleted file mode 100644 index df2b57d717d..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/child_count/temp_parent_invalid.move +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// DEPRECATED child count no longer tracked -// tests the invalid creation and deletion of a parent object - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::m { - public struct S has key, store { - id: sui::object::UID, - } - - public entry fun t(ctx: &mut TxContext) { - let mut parent = sui::object::new(ctx); - let child = S { id: sui::object::new(ctx) }; - sui::dynamic_object_field::add(&mut parent, 0, child); - sui::object::delete(parent); - } -} - -//# run test::m::t --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/unwrap_never_stored.move b/crates/sui-adapter-transactional-tests/tests/child_count/unwrap_never_stored.move deleted file mode 100644 index 74f6930f3bc..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/child_count/unwrap_never_stored.move +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// DEPRECATED child count no longer tracked -// tests deleting a wrapped object that has never been in storage - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::m { - public struct S has key, store { - id: sui::object::UID, - } - - public struct R has key { - id: sui::object::UID, - s: S, - } - - public entry fun create(ctx: &mut TxContext) { - let parent = sui::object::new(ctx); - let child = S { id: sui::object::new(ctx) }; - sui::transfer::transfer(R { id: parent, s: child }, tx_context::sender(ctx)) - } - - public entry fun delete(r: R) { - let R { id, s } = r; - sui::object::delete(id); - let S { id } = s; - sui::object::delete(id); - } -} - -// -// Test sharing -// - -//# run test::m::create --sender A - -//# run test::m::delete --args object(2,0) --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/unwrap_never_stored_transfer.move b/crates/sui-adapter-transactional-tests/tests/child_count/unwrap_never_stored_transfer.move deleted file mode 100644 index 60d34a3aa7e..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/child_count/unwrap_never_stored_transfer.move +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// DEPRECATED child count no longer tracked -// tests transferring a wrapped object that has never previously been in storage - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::m { - public struct S has key, store { - id: sui::object::UID, - } - - public struct R has key { - id: sui::object::UID, - s: S, - } - - public entry fun create(ctx: &mut TxContext) { - let parent = sui::object::new(ctx); - let child = S { id: sui::object::new(ctx) }; - sui::transfer::transfer(R { id: parent, s: child }, tx_context::sender(ctx)) - } - - public entry fun unwrap_and_transfer(r: R, ctx: &mut TxContext) { - let R { id, s } = r; - sui::object::delete(id); - sui::transfer::transfer(s, tx_context::sender(ctx)); - } -} - -// -// Test sharing -// - -//# run test::m::create --sender A - -//# run test::m::unwrap_and_transfer --args object(2,0) --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/child_count/unwrap_then_delete_invalid.move b/crates/sui-adapter-transactional-tests/tests/child_count/unwrap_then_delete_invalid.move deleted file mode 100644 index 5bda7ed3a1e..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/child_count/unwrap_then_delete_invalid.move +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// DEPRECATED child count no longer tracked -// tests invalid deletion of an object that has children - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct S has key, store { - id: sui::object::UID, - } - - public struct R has key { - id: sui::object::UID, - s: S, - } - - public entry fun mint(ctx: &mut TxContext) { - let s = S { id: sui::object::new(ctx) }; - sui::transfer::transfer(s, tx_context::sender(ctx)) - } - - public entry fun add(parent: &mut S, idx: u64, ctx: &mut TxContext) { - let child = S { id: sui::object::new(ctx) }; - ofield::add(&mut parent.id, idx, child); - } - - public entry fun wrap(s: S, ctx: &mut TxContext) { - let r = R { id: sui::object::new(ctx), s }; - sui::transfer::transfer(r, tx_context::sender(ctx)) - } - - public entry fun delete(r: R) { - let R { id, s } = r; - sui::object::delete(id); - let S { id } = s; - sui::object::delete(id); - } -} - -//# run test::m::mint --sender A - -//# run test::m::add --sender A --args object(2,0) 0 - -//# run test::m::wrap --sender A --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_and_undeny.exp b/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_and_undeny.exp deleted file mode 100644 index ffdefa1162a..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_and_undeny.exp +++ /dev/null @@ -1,62 +0,0 @@ -processed 14 tasks - -init: -A: object(0,0), B: object(0,1) - -task 1 'publish'. lines 12-34: -created: object(1,0), object(1,1), object(1,2), object(1,3), object(1,4), object(1,5) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 18316000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'view-object'. lines 36-36: -1,0::regulated_coin - -task 3 'view-object'. lines 38-38: -Owner: Account Address ( A ) -Version: 2 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,1)}}, balance: sui::balance::Balance {value: 10000u64}} - -task 4 'view-object'. lines 40-40: -Owner: Immutable -Version: 2 -Contents: sui::coin::CoinMetadata {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,2)}}, decimals: 9u8, name: std::string::String {bytes: vector[82u8, 69u8, 71u8, 85u8, 76u8, 65u8, 84u8, 69u8, 68u8, 95u8, 67u8, 79u8, 73u8, 78u8]}, symbol: std::ascii::String {bytes: vector[82u8, 67u8]}, description: std::string::String {bytes: vector[65u8, 32u8, 110u8, 101u8, 119u8, 32u8, 114u8, 101u8, 103u8, 117u8, 108u8, 97u8, 116u8, 101u8, 100u8, 32u8, 99u8, 111u8, 105u8, 110u8]}, icon_url: std::option::Option {vec: vector[]}} - -task 5 'view-object'. lines 42-42: -Owner: Account Address ( A ) -Version: 2 -Contents: sui::coin::DenyCap {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,3)}}} - -task 6 'view-object'. lines 44-44: -Owner: Immutable -Version: 2 -Contents: sui::coin::RegulatedCoinMetadata {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,4)}}, coin_metadata_object: sui::object::ID {bytes: fake(1,2)}, deny_cap_object: sui::object::ID {bytes: fake(1,3)}} - -task 7 'view-object'. lines 46-48: -Owner: Immutable -Version: 2 -Contents: sui::coin::TreasuryCap {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,5)}}, total_supply: sui::balance::Supply {value: 10000u64}} - -task 8 'run'. lines 49-51: -created: object(8,0) -mutated: object(0,0), object(1,1) -gas summary: computation_cost: 1000000, storage_cost: 3936800, storage_rebate: 2437776, non_refundable_storage_fee: 24624 - -task 9 'run'. lines 52-54: -created: object(9,0), object(9,1) -mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000403, object(0,0), object(1,3) -gas summary: computation_cost: 1000000, storage_cost: 11415200, storage_rebate: 2723688, non_refundable_storage_fee: 27512 - -task 10 'transfer-object'. lines 55-57: -Error: Error checking transaction input objects: AddressDeniedForCoin { address: @B, coin_type: "object(1,0)::regulated_coin::REGULATED_COIN" } - -task 11 'run'. lines 58-60: -Error: Error checking transaction input objects: AddressDeniedForCoin { address: @B, coin_type: "object(1,0)::regulated_coin::REGULATED_COIN" } - -task 12 'run'. lines 61-63: -mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000403, object(0,0), object(1,3), object(9,1) -deleted: object(9,0) -gas summary: computation_cost: 1000000, storage_cost: 9522800, storage_rebate: 11301048, non_refundable_storage_fee: 114152 - -task 13 'transfer-object'. lines 64-64: -mutated: object(0,1), object(8,0) -gas summary: computation_cost: 1000000, storage_cost: 2462400, storage_rebate: 1459656, non_refundable_storage_fee: 14744 diff --git a/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_and_undeny.move b/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_and_undeny.move deleted file mode 100644 index 0fb3820b6d4..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_and_undeny.move +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// This test verifies the basic e2e work flow of coin deny list. -// A newly created regulated coin type should come with the deny cap object. -// Coin isser can use the deny cap to deny addresses, which will no longer be able to -// transfer the coin or use it in Move calls. -// Undeny the address will restore the original behavior. - -//# init --accounts A B --addresses test=0x0 - -//# publish --sender A -module test::regulated_coin { - use sui::coin; - - public struct REGULATED_COIN has drop {} - - fun init(otw: REGULATED_COIN, ctx: &mut TxContext) { - let (mut treasury_cap, deny_cap, metadata) = coin::create_regulated_currency( - otw, - 9, - b"RC", - b"REGULATED_COIN", - b"A new regulated coin", - option::none(), - ctx - ); - let coin = coin::mint(&mut treasury_cap, 10000, ctx); - transfer::public_transfer(coin, tx_context::sender(ctx)); - transfer::public_transfer(deny_cap, tx_context::sender(ctx)); - transfer::public_freeze_object(treasury_cap); - transfer::public_freeze_object(metadata); - } -} - -//# view-object 1,0 - -//# view-object 1,1 - -//# view-object 1,2 - -//# view-object 1,3 - -//# view-object 1,4 - -//# view-object 1,5 - -// Transfer away the newly minted coin works normally. -//# run sui::pay::split_and_transfer --args object(1,1) 1 @B --type-args test::regulated_coin::REGULATED_COIN --sender A - -// Deny account B. -//# run sui::coin::deny_list_add --args object(0x403) object(1,3) @B --type-args test::regulated_coin::REGULATED_COIN --sender A - -// Try transfer the coin from B. This should now be denied. -//# transfer-object 8,0 --sender B --recipient A - -// Try using the coin in a Move call. This should also be denied. -//# run sui::pay::split_and_transfer --args object(8,0) 1 @A --type-args test::regulated_coin::REGULATED_COIN --sender B - -// Undeny account B. -//# run sui::coin::deny_list_remove --args object(0x403) object(1,3) @B --type-args test::regulated_coin::REGULATED_COIN --sender A - -// This time the transfer should work. -//# transfer-object 8,0 --sender B --recipient A diff --git a/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_multiple_per_module.exp b/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_multiple_per_module.exp deleted file mode 100644 index a3f932134c8..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_multiple_per_module.exp +++ /dev/null @@ -1,74 +0,0 @@ -processed 16 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 9-54: -created: object(1,0), object(1,1), object(1,2), object(1,3), object(1,4), object(1,5), object(1,6), object(1,7), object(1,8), object(1,9), object(1,10) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 33082800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'view-object'. lines 56-56: -1,0::{first_coin, second_coin} - -task 3 'view-object'. lines 58-58: -Owner: Account Address ( A ) -Version: 2 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,1)}}, balance: sui::balance::Balance {value: 10000u64}} - -task 4 'view-object'. lines 60-60: -Owner: Account Address ( A ) -Version: 2 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,2)}}, balance: sui::balance::Balance {value: 10000u64}} - -task 5 'view-object'. lines 62-62: -Owner: Immutable -Version: 2 -Contents: sui::coin::CoinMetadata {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,3)}}, decimals: 9u8, name: std::string::String {bytes: vector[82u8, 69u8, 71u8, 85u8, 76u8, 65u8, 84u8, 69u8, 68u8, 95u8, 67u8, 79u8, 73u8, 78u8]}, symbol: std::ascii::String {bytes: vector[82u8, 67u8]}, description: std::string::String {bytes: vector[65u8, 32u8, 110u8, 101u8, 119u8, 32u8, 114u8, 101u8, 103u8, 117u8, 108u8, 97u8, 116u8, 101u8, 100u8, 32u8, 99u8, 111u8, 105u8, 110u8]}, icon_url: std::option::Option {vec: vector[]}} - -task 6 'view-object'. lines 64-64: -Owner: Immutable -Version: 2 -Contents: sui::coin::CoinMetadata {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,4)}}, decimals: 9u8, name: std::string::String {bytes: vector[82u8, 69u8, 71u8, 85u8, 76u8, 65u8, 84u8, 69u8, 68u8, 95u8, 67u8, 79u8, 73u8, 78u8]}, symbol: std::ascii::String {bytes: vector[82u8, 67u8]}, description: std::string::String {bytes: vector[65u8, 32u8, 110u8, 101u8, 119u8, 32u8, 114u8, 101u8, 103u8, 117u8, 108u8, 97u8, 116u8, 101u8, 100u8, 32u8, 99u8, 111u8, 105u8, 110u8]}, icon_url: std::option::Option {vec: vector[]}} - -task 7 'view-object'. lines 66-66: -Owner: Account Address ( A ) -Version: 2 -Contents: sui::coin::DenyCap {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,5)}}} - -task 8 'view-object'. lines 68-68: -Owner: Account Address ( A ) -Version: 2 -Contents: sui::coin::DenyCap {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,6)}}} - -task 9 'view-object'. lines 70-70: -Owner: Immutable -Version: 2 -Contents: sui::coin::RegulatedCoinMetadata {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,7)}}, coin_metadata_object: sui::object::ID {bytes: fake(1,3)}, deny_cap_object: sui::object::ID {bytes: fake(1,5)}} - -task 10 'view-object'. lines 72-72: -Owner: Immutable -Version: 2 -Contents: sui::coin::RegulatedCoinMetadata {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,8)}}, coin_metadata_object: sui::object::ID {bytes: fake(1,4)}, deny_cap_object: sui::object::ID {bytes: fake(1,6)}} - -task 11 'view-object'. lines 74-74: -Owner: Immutable -Version: 2 -Contents: sui::coin::TreasuryCap {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,9)}}, total_supply: sui::balance::Supply {value: 10000u64}} - -task 12 'view-object'. lines 76-78: -Owner: Immutable -Version: 2 -Contents: sui::coin::TreasuryCap {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,10)}}, total_supply: sui::balance::Supply {value: 10000u64}} - -task 13 'run'. lines 79-81: -created: object(13,0), object(13,1) -mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000403, object(0,0), object(1,5) -gas summary: computation_cost: 1000000, storage_cost: 11293600, storage_rebate: 2663496, non_refundable_storage_fee: 26904 - -task 14 'transfer-object'. lines 82-84: -Error: Error checking transaction input objects: AddressDeniedForCoin { address: @A, coin_type: "object(1,0)::first_coin::FIRST_COIN" } - -task 15 'transfer-object'. lines 85-85: -mutated: object(0,0), object(1,2) -gas summary: computation_cost: 1000000, storage_cost: 2416800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 diff --git a/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_tto.exp b/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_tto.exp deleted file mode 100644 index d092ac206de..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/deny_list/coin_deny_tto.exp +++ /dev/null @@ -1,59 +0,0 @@ -processed 13 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-46: -created: object(1,0), object(1,1), object(1,2), object(1,3), object(1,4), object(1,5), object(1,6) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 21766400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'view-object'. lines 48-48: -Owner: Account Address ( A ) -Version: 2 -Contents: test::regulated_coin::Wallet {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,0)}}} - -task 3 'view-object'. lines 50-50: -1,1::regulated_coin - -task 4 'view-object'. lines 52-52: -Owner: Account Address ( fake(1,0) ) -Version: 2 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,2)}}, balance: sui::balance::Balance {value: 10000u64}} - -task 5 'view-object'. lines 54-54: -Owner: Immutable -Version: 2 -Contents: sui::coin::CoinMetadata {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,3)}}, decimals: 9u8, name: std::string::String {bytes: vector[82u8, 69u8, 71u8, 85u8, 76u8, 65u8, 84u8, 69u8, 68u8, 95u8, 67u8, 79u8, 73u8, 78u8]}, symbol: std::ascii::String {bytes: vector[82u8, 67u8]}, description: std::string::String {bytes: vector[65u8, 32u8, 110u8, 101u8, 119u8, 32u8, 114u8, 101u8, 103u8, 117u8, 108u8, 97u8, 116u8, 101u8, 100u8, 32u8, 99u8, 111u8, 105u8, 110u8]}, icon_url: std::option::Option {vec: vector[]}} - -task 6 'view-object'. lines 56-56: -Owner: Account Address ( A ) -Version: 2 -Contents: sui::coin::DenyCap {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,4)}}} - -task 7 'view-object'. lines 58-58: -Owner: Immutable -Version: 2 -Contents: sui::coin::RegulatedCoinMetadata {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,5)}}, coin_metadata_object: sui::object::ID {bytes: fake(1,3)}, deny_cap_object: sui::object::ID {bytes: fake(1,4)}} - -task 8 'view-object'. lines 60-62: -Owner: Immutable -Version: 2 -Contents: sui::coin::TreasuryCap {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,6)}}, total_supply: sui::balance::Supply {value: 10000u64}} - -task 9 'run'. lines 63-65: -created: object(9,0), object(9,1) -mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000403, object(0,0), object(1,4) -gas summary: computation_cost: 1000000, storage_cost: 11415200, storage_rebate: 2723688, non_refundable_storage_fee: 27512 - -task 10 'run'. lines 66-68: -Error: Error checking transaction input objects: AddressDeniedForCoin { address: @A, coin_type: "object(1,1)::regulated_coin::REGULATED_COIN" } - -task 11 'run'. lines 69-71: -mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000403, object(0,0), object(1,4), object(9,1) -deleted: object(9,0) -gas summary: computation_cost: 1000000, storage_cost: 9522800, storage_rebate: 11301048, non_refundable_storage_fee: 114152 - -task 12 'run'. lines 72-72: -mutated: object(0,0), object(1,0), object(1,2) -gas summary: computation_cost: 1000000, storage_cost: 3807600, storage_rebate: 3769524, non_refundable_storage_fee: 38076 diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/add_duplicate.exp b/crates/sui-adapter-transactional-tests/tests/dynamic_fields/add_duplicate.exp deleted file mode 100644 index 68190f5392a..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/add_duplicate.exp +++ /dev/null @@ -1,18 +0,0 @@ -processed 4 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 9-28: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 5867200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 30-30: -created: object(2,0), object(2,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 3678400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'run'. lines 32-32: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::dynamic_field::add (function index 0) at offset 15, Abort Code: 0 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 0, instruction: 15, function_name: Some("add") }, 0), source: Some(VMError { major_status: ABORTED, sub_status: Some(0), message: Some("sui::dynamic_field::add at offset 15"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 15)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/add_duplicate_object.exp b/crates/sui-adapter-transactional-tests/tests/dynamic_fields/add_duplicate_object.exp deleted file mode 100644 index 8fa87f1b59a..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/add_duplicate_object.exp +++ /dev/null @@ -1,18 +0,0 @@ -processed 4 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 10-29: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 6026800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 31-31: -created: object(2,0), object(2,1), object(2,2) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'run'. lines 33-33: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::dynamic_field::add (function index 0) at offset 15, Abort Code: 0 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 0, instruction: 15, function_name: Some("add") }, 0), source: Some(VMError { major_status: ABORTED, sub_status: Some(0), message: Some("sui::dynamic_field::add at offset 15"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 15)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type.exp b/crates/sui-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type.exp deleted file mode 100644 index 2b739c74dc2..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type.exp +++ /dev/null @@ -1,22 +0,0 @@ -processed 5 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 9-32: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 6505600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 34-34: -created: object(2,0), object(2,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 3678400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'run'. lines 36-36: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::dynamic_field::borrow_child_object (function index 11) at offset 0, Abort Code: 2 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(11), 0)] }), command: Some(0) } } - -task 4 'run'. lines 38-38: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::dynamic_field::borrow_child_object_mut (function index 12) at offset 0, Abort Code: 2 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 12, instruction: 0, function_name: Some("borrow_child_object_mut") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type_object.exp b/crates/sui-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type_object.exp deleted file mode 100644 index 1e859ff9e34..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/borrow_wrong_type_object.exp +++ /dev/null @@ -1,22 +0,0 @@ -processed 5 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 10-37: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 7075600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 39-39: -created: object(2,0), object(2,1), object(2,2) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'run'. lines 41-41: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::dynamic_field::borrow_child_object (function index 11) at offset 0, Abort Code: 2 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(11), 0)] }), command: Some(0) } } - -task 4 'run'. lines 43-43: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::dynamic_field::borrow_child_object_mut (function index 12) at offset 0, Abort Code: 2 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 12, instruction: 0, function_name: Some("borrow_child_object_mut") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/receive_remove_add_back_and_remove_type.move b/crates/sui-adapter-transactional-tests/tests/dynamic_fields/receive_remove_add_back_and_remove_type.move deleted file mode 100644 index 307961b3a25..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/receive_remove_add_back_and_remove_type.move +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// This test attempts to receive two objects, remove a child, add it back, remove it again, and then transfer/delete it. -// This is an interesting test case because when child objects are removed, added back and removed again, -// they won't show up in the child_object_effects in the object runtiem. We must look at either transfers -// or deleted_object_ids to figure them out. - -//# init --addresses test=0x0 --accounts A - -//# publish -module test::m1 { - use sui::transfer::Receiving; - - public struct Object has key, store { - id: UID, - } - - public struct C1 has key, store { - id: UID, - } - - public struct C2 has key, store { - id: UID, - } - - public struct Wrapper has key, store { - id: UID, - value: T, - } - - public entry fun create(ctx: &mut TxContext) { - let o = Object { id: object::new(ctx) }; - let c1 = C1 { id: object::new(ctx) }; - let c2 = C2 { id: object::new(ctx) }; - let o_address = object::id_address(&o); - transfer::public_transfer(o, tx_context::sender(ctx)); - transfer::public_transfer(c1, o_address); - transfer::public_transfer(c2, o_address); - } - - public entry fun test_dof(parent: &mut Object, c1: Receiving, c2: Receiving) { - let c1 = transfer::receive(&mut parent.id, c1); - sui::dynamic_object_field::add(&mut parent.id, 0, c1); - let c1: C1 = sui::dynamic_object_field::remove(&mut parent.id, 0); - transfer::public_transfer(c1, @test); - - let c2 = transfer::receive(&mut parent.id, c2); - sui::dynamic_object_field::add(&mut parent.id, 0, c2); - let C2 { id } = sui::dynamic_object_field::remove(&mut parent.id, 0); - object::delete(id); - } - - public entry fun test_df(parent: &mut Object, c1: Receiving, c2: Receiving) { - let c1 = transfer::receive(&mut parent.id, c1); - sui::dynamic_field::add(&mut parent.id, 0, c1); - let c1: C1 = sui::dynamic_field::remove(&mut parent.id, 0); - transfer::public_transfer(c1, @test); - - let c2 = transfer::receive(&mut parent.id, c2); - sui::dynamic_field::add(&mut parent.id, 0, c2); - let C2 { id } = sui::dynamic_field::remove(&mut parent.id, 0); - object::delete(id); - } - - // Try to "wash" the receiving object through a dynamic object field and then wrap it in a wrapper object. - public entry fun test_dof_wrapper(parent: &mut Object, c1: Receiving, _c2: Receiving, ctx: &mut TxContext) { - let c1 = transfer::receive(&mut parent.id, c1); - sui::dynamic_object_field::add(&mut parent.id, 0, c1); - let c1: C1 = sui::dynamic_object_field::remove(&mut parent.id, 0); - let w = Wrapper { id: object::new(ctx), value: c1 }; - sui::dynamic_object_field::add(&mut parent.id, 0, w); - let w: Wrapper = sui::dynamic_object_field::remove(&mut parent.id, 0); - transfer::public_transfer(w, @test); - } - - // Try to "wash" the receiving object through a dynamic field and then wrap it in a wrapper object. - public entry fun test_df_wrapper(parent: &mut Object, c1: Receiving, _c2: Receiving, ctx: &mut TxContext) { - let c1 = transfer::receive(&mut parent.id, c1); - sui::dynamic_field::add(&mut parent.id, 0, c1); - let c1: C1 = sui::dynamic_field::remove(&mut parent.id, 0); - let w = Wrapper { id: object::new(ctx), value: c1 }; - sui::dynamic_field::add(&mut parent.id, 0, w); - let w: Wrapper = sui::dynamic_field::remove(&mut parent.id, 0); - transfer::public_transfer(w, @test); - } -} - -//# run test::m1::create --sender A - -//# run test::m1::test_dof --args object(2,2) receiving(2,0) receiving(2,1) --sender A - -//# run test::m1::create --sender A - -//# run test::m1::test_df --args object(4,2) receiving(4,0) receiving(4,1) --sender A - -//# run test::m1::create --sender A - -//# run test::m1::test_dof_wrapper --args object(6,2) receiving(6,0) receiving(6,1) --sender A - -//# run test::m1::create --sender A - -//# run test::m1::test_df_wrapper --args object(8,2) receiving(8,0) receiving(8,1) --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove.move b/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove.move deleted file mode 100644 index 4d562701afb..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove.move +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// This test attempts to remove a child, add it back, remove it again, and then transfer/delete it. -// This is an interesting test case because when child objects are removed, added back and removed again, -// they won't show up in the child_object_effects in the object runtiem. We must look at either transfers -// or deleted_object_ids to figure them out. - -//# init --addresses test=0x0 --accounts A - -//# publish -module test::m1 { - public struct Object has key, store { - id: UID, - wrapped: Option, - } - - public struct Child has key, store { - id: UID, - } - - public entry fun create(ctx: &mut TxContext) { - let o = Object { id: object::new(ctx), wrapped: option::none() }; - transfer::public_transfer(o, tx_context::sender(ctx)) - } - - public entry fun add_child(parent: &mut Object, ctx: &mut TxContext) { - let child = Child { id: object::new(ctx) }; - sui::dynamic_object_field::add(&mut parent.id, 0, child); - } - - public fun transfer_child(parent: &mut Object, ctx: &TxContext) { - let child: Child = sui::dynamic_object_field::remove(&mut parent.id, 0); - sui::dynamic_object_field::add(&mut parent.id, 1, child); - let child: Child = sui::dynamic_object_field::remove(&mut parent.id, 1); - transfer::public_transfer(child, tx_context::sender(ctx)) - } - - public fun delete_child(parent: &mut Object) { - let child: Child = sui::dynamic_object_field::remove(&mut parent.id, 0); - sui::dynamic_object_field::add(&mut parent.id, 1, child); - let Child { id } = sui::dynamic_object_field::remove(&mut parent.id, 1); - object::delete(id); - } - - public fun wrap_child(parent: &mut Object) { - let child: Child = sui::dynamic_object_field::remove(&mut parent.id, 0); - sui::dynamic_object_field::add(&mut parent.id, 1, child); - let child = sui::dynamic_object_field::remove(&mut parent.id, 1); - option::fill(&mut parent.wrapped, child); - } -} - -//# run test::m1::create --sender A - -// transfer -//# run test::m1::add_child --args object(2,0) --sender A - -//# run test::m1::transfer_child --args object(2,0) --sender A - -// delete -//# run test::m1::add_child --args object(2,0) --sender A - -//# run test::m1::delete_child --args object(2,0) --sender A - -// wrap -//# run test::m1::add_child --args object(2,0) --sender A - -//# run test::m1::wrap_child --args object(2,0) --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove_type.move b/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove_type.move deleted file mode 100644 index 334e67ef2ff..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_add_back_and_remove_type.move +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// This test attempts to remove a child, add it back, remove it again, and then transfer/delete it. -// This is an interesting test case because when child objects are removed, added back and removed again, -// they won't show up in the child_object_effects in the object runtiem. We must look at either transfers -// or deleted_object_ids to figure them out. - -//# init --addresses test=0x0 --accounts A - -//# publish -module test::m1 { - public struct Object has key, store { - id: UID, - } - - public struct C1 has key, store { - id: UID, - } - - public struct C2 has key, store { - id: UID, - } - - public entry fun create(ctx: &mut TxContext) { - let o = Object { id: object::new(ctx) }; - transfer::public_transfer(o, tx_context::sender(ctx)) - } - - public entry fun test_dof(parent: &mut Object, ctx: &mut TxContext) { - let c1 = C1 { id: object::new(ctx) }; - sui::dynamic_object_field::add(&mut parent.id, 0, c1); - let C1 { id } = sui::dynamic_object_field::remove(&mut parent.id, 0); - object::delete(id); - - let c2 = C2 { id: object::new(ctx) }; - sui::dynamic_object_field::add(&mut parent.id, 0, c2); - let C2 { id } = sui::dynamic_object_field::remove(&mut parent.id, 0); - object::delete(id); - } - - public entry fun test_df(parent: &mut Object) { - sui::dynamic_field::add(&mut parent.id, 0, b"true"); - let _: vector = sui::dynamic_field::remove(&mut parent.id, 0); - sui::dynamic_field::add(&mut parent.id, 0, true); - let _: bool = sui::dynamic_field::remove(&mut parent.id, 0); - } -} - -//# run test::m1::create --sender A - -//# run test::m1::test_dof --args object(2,0) --sender A - -//# run test::m1::test_df --args object(2,0) --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type.exp b/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type.exp deleted file mode 100644 index 0dc8bb4f79c..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type.exp +++ /dev/null @@ -1,18 +0,0 @@ -processed 4 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 9-29: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 6019200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 31-31: -created: object(2,0), object(2,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 3678400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'run'. lines 33-33: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::dynamic_field::remove_child_object (function index 13) at offset 0, Abort Code: 2 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 13, instruction: 0, function_name: Some("remove_child_object") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(13), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type_object.exp b/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type_object.exp deleted file mode 100644 index 6e646b87c52..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/remove_wrong_type_object.exp +++ /dev/null @@ -1,18 +0,0 @@ -processed 4 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 10-34: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 6695600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 36-36: -created: object(2,0), object(2,1), object(2,2) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'run'. lines 38-38: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::dynamic_field::remove_child_object (function index 13) at offset 0, Abort Code: 2 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 13, instruction: 0, function_name: Some("remove_child_object") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(13), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/shared_object.exp b/crates/sui-adapter-transactional-tests/tests/dynamic_fields/shared_object.exp deleted file mode 100644 index 7b262758f15..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/shared_object.exp +++ /dev/null @@ -1,41 +0,0 @@ -processed 9 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-72: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 9690000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 74-74: -created: object(2,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2470000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'run'. lines 76-78: -created: object(3,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2287600, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 4 'run'. lines 79-79: -Error: Transaction Effects Status: The shared object operation is not allowed. -Debug of error: SharedObjectOperationNotAllowed at command None - -task 5 'view-object'. lines 81-81: -Owner: Shared -Version: 4 -Contents: test::m::Child {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, value: 0u64} - -task 6 'run'. lines 83-83: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::dynamic_field::borrow_child_object (function index 11) at offset 0, Abort Code: 1 -Debug of error: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) at command Some(0) - -task 7 'view-object'. lines 85-85: -Owner: Shared -Version: 4 -Contents: test::m::Child {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, value: 0u64} - -task 8 'run'. lines 87-87: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::dynamic_field::borrow_child_object (function index 11) at offset 0, Abort Code: 1 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1), source: Some(VMError { major_status: ABORTED, sub_status: Some(1), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(11), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/wrap_object.exp b/crates/sui-adapter-transactional-tests/tests/dynamic_fields/wrap_object.exp deleted file mode 100644 index 971a18a23c2..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/dynamic_fields/wrap_object.exp +++ /dev/null @@ -1,59 +0,0 @@ -processed 12 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-39: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 7478400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 41-41: -created: object(2,0), object(2,1), object(2,2) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 43-43: -Owner: Object ID: ( fake(2,2) ) -Version: 2 -Contents: a::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 4 'run'. lines 45-45: -created: object(4,0) -mutated: object(0,0), object(2,0) -deleted: object(2,2) -wrapped: object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 4157200, storage_rebate: 5831100, non_refundable_storage_fee: 58900 - -task 5 'run'. lines 48-48: -created: object(5,0), object(5,1), object(5,2) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 6 'view-object'. lines 50-50: -Owner: Object ID: ( fake(5,1) ) -Version: 4 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(5,2)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(5,0)}} - -task 7 'run'. lines 52-52: -mutated: object(0,0), object(5,1) -deleted: object(5,0), object(5,2) -gas summary: computation_cost: 1000000, storage_cost: 2211600, storage_rebate: 5831100, non_refundable_storage_fee: 58900 - -task 8 'run'. lines 55-55: -created: object(8,0), object(8,1), object(8,2) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 9 'view-object'. lines 57-57: -Owner: Object ID: ( fake(8,0) ) -Version: 6 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(8,2)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(8,1)}} - -task 10 'run'. lines 59-59: -mutated: object(0,0), object(8,0), object(8,1) -deleted: object(8,2) -gas summary: computation_cost: 1000000, storage_cost: 3435200, storage_rebate: 5831100, non_refundable_storage_fee: 58900 - -task 11 'view-object'. lines 61-61: -No object at id 8,2 diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/ascii.move b/crates/sui-adapter-transactional-tests/tests/entry_points/ascii.move deleted file mode 100644 index 4581c7307d0..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/entry_points/ascii.move +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --addresses Test=0x0 --accounts A - -//# publish -module Test::M { - use std::ascii; - - public entry fun ascii_arg(s: ascii::String, _: &mut TxContext) { - assert!(ascii::length(&s) == 10, 0); - } - - public entry fun ascii_vec_arg(mut v: vector, _: &mut TxContext) { - let mut l = 0; - while (!vector::is_empty(&v)) { - let s = vector::pop_back(&mut v); - l = l + ascii::length(&s) - }; - assert!(l == 10, 0); - } - -} - -// string of ASCII characters as byte string - -//# run Test::M::ascii_arg --sender A --args b"SomeString" - - -// string of ASCII characters as UTF8 string - -//# run Test::M::ascii_arg --sender A --args "SomeString" - - -// vector of ASCII character strings as byte strings - -//# run Test::M::ascii_vec_arg --sender A --args vector[b"Some",b"String"] - - -// vector of ASCII character strings as UTF8 strings - -// run Test::M::ascii_vec_arg --sender A --args vector["Some","String"] - - -// error - a character out of ASCII range - -//# run Test::M::ascii_arg --sender A --args "Some∫tring" diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/generic_by_ref_invalid.exp b/crates/sui-adapter-transactional-tests/tests/entry_points/generic_by_ref_invalid.exp deleted file mode 100644 index 4ba95571e90..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/entry_points/generic_by_ref_invalid.exp +++ /dev/null @@ -1,20 +0,0 @@ -processed 5 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-11: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &T0"), command: Some(0) } } - -task 2 'publish'. lines 13-16: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &mut T0"), command: Some(0) } } - -task 3 'publish'. lines 18-21: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &T0"), command: Some(0) } } - -task 4 'publish'. lines 23-26: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &mut T0"), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/entry_points/no_txn_context.move b/crates/sui-adapter-transactional-tests/tests/entry_points/no_txn_context.move deleted file mode 100644 index 241d75733b9..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/entry_points/no_txn_context.move +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --addresses Test=0x0 --accounts A - -//# publish -module Test::M { - public struct Obj has key { - id: sui::object::UID, - value: u64 - } - - public entry fun mint(ctx: &mut TxContext) { - sui::transfer::transfer( - Obj { id: sui::object::new(ctx), value: 0 }, - tx_context::sender(ctx), - ) - } - - public entry fun incr(obj: &mut Obj) { - obj.value = obj.value + 1 - } -} - -//# run Test::M::mint --sender A - -//# run Test::M::incr --sender A --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/init/entry_new.exp b/crates/sui-adapter-transactional-tests/tests/init/entry_new.exp deleted file mode 100644 index 7374d6e10fc..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/init/entry_new.exp +++ /dev/null @@ -1,8 +0,0 @@ -processed 3 tasks - -task 1 'publish'. lines 8-17: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m. 'init' cannot be 'entry'"), command: Some(0) } } - -task 2 'run'. lines 18-18: -Error: Error checking transaction input objects: DependentPackageNotFound { package_id: 0x0000000000000000000000000000000000000000000000000000000000000000 } diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/child_of_child.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/child_of_child.exp deleted file mode 100644 index c1ff3ec4141..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/child_of_child.exp +++ /dev/null @@ -1,62 +0,0 @@ -processed 14 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-66: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 9218800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 68-70: -created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 9750800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 72-72: -Owner: Account Address ( A ) -Version: 2 -Contents: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,4)}}, value: 0u64} - -task 4 'programmable'. lines 74-75: -mutated: object(0,0), object(2,2), object(2,3), object(2,4) -gas summary: computation_cost: 1000000, storage_cost: 4841200, storage_rebate: 4792788, non_refundable_storage_fee: 48412 - -task 5 'view-object'. lines 77-77: -Owner: Account Address ( A ) -Version: 3 -Contents: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,4)}}, value: 1u64} - -task 6 'programmable'. lines 79-80: -mutated: object(0,0), object(2,4) -deleted: object(2,0), object(2,2) -gas summary: computation_cost: 1000000, storage_cost: 2272400, storage_rebate: 5951484, non_refundable_storage_fee: 60116 - -task 7 'view-object'. lines 82-85: -Owner: Account Address ( A ) -Version: 4 -Contents: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,4)}}, value: 1u64} - -task 8 'programmable'. lines 87-88: -mutated: object(_), object(2,4) -gas summary: computation_cost: 500000, storage_cost: 2272400, storage_rebate: 1271556, non_refundable_storage_fee: 12844 - -task 9 'programmable'. lines 90-91: -mutated: object(_), object(2,4) -gas summary: computation_cost: 500000, storage_cost: 2272400, storage_rebate: 1271556, non_refundable_storage_fee: 12844 - -task 10 'programmable'. lines 93-97: -mutated: object(_), object(2,4) -gas summary: computation_cost: 500000, storage_cost: 2272400, storage_rebate: 1271556, non_refundable_storage_fee: 12844 - -task 11 'programmable'. lines 99-100: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 - -task 12 'programmable'. lines 102-103: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 - -task 13 'programmable'. lines 105-106: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/child_of_child.move b/crates/sui-adapter-transactional-tests/tests/mvcc/child_of_child.move deleted file mode 100644 index 13bf6fb8ae1..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/child_of_child.move +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests accessing the versions of a child of a child - -//# init --addresses test=0x0 --accounts A - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct Obj has key, store { - id: UID, - value: u64, - } - - const KEY: u64 = 0; - - ////////////////////////////////////////////////////////////// - // new - - public fun new(ctx: &mut TxContext): Obj { - let mut grand = Obj { id: object::new(ctx), value: 0 }; - let mut parent = Obj { id: object::new(ctx), value: 0 }; - let child = Obj { id: object::new(ctx), value: 0 }; - ofield::add(&mut parent.id, KEY, child); - ofield::add(&mut grand.id, KEY, parent); - grand - } - - ////////////////////////////////////////////////////////////// - // set - - public fun set(grand: &mut Obj, v1: u64, v2: u64, v3: u64) { - grand.value = v1; - let parent: &mut Obj = ofield::borrow_mut(&mut grand.id, KEY); - parent.value = v2; - let child: &mut Obj = ofield::borrow_mut(&mut parent.id, KEY); - child.value = v3; - } - - ////////////////////////////////////////////////////////////// - // remove - - public fun remove(grand: &mut Obj) { - let parent: &mut Obj = ofield::borrow_mut(&mut grand.id, KEY); - let Obj { id, value: _ } = ofield::remove(&mut parent.id, KEY); - object::delete(id); - } - - ////////////////////////////////////////////////////////////// - // check - - public fun check(grand: &Obj, v1: u64, v2: u64, v3: Option) { - assert!(grand.value == v1, 0); - let parent: &Obj = ofield::borrow(&grand.id, KEY); - assert!(parent.value == v2, 0); - if (option::is_some(&v3)) { - let child: &Obj = ofield::borrow(&parent.id, KEY); - assert!(&child.value == option::borrow(&v3), 0); - } else { - assert!(!ofield::exists_(&parent.id, KEY), 0); - } - } -} - -//# programmable --sender A --inputs @A -//> 0: test::m::new(); -//> TransferObjects([Result(0)], Input(0)) - -//# view-object 2,4 - -//# programmable --sender A --inputs object(2,4) 1 2 3 -//> test::m::set(Input(0), Input(1), Input(2), Input(3)) - -//# view-object 2,4 - -//# programmable --sender A --inputs object(2,4) -//> test::m::remove(Input(0)) - -//# view-object 2,4 - - -// dev-inspect with 'check' and correct values - -//# programmable --sender A --inputs object(2,4)@2 0 0 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1), Input(2), Input(3)) - -//# programmable --sender A --inputs object(2,4)@3 1 2 vector[3] --dev-inspect -//> test::m::check(Input(0), Input(1), Input(2), Input(3)) - -//# programmable --sender A --inputs object(2,4)@4 1 2 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1), Input(2), Input(3)) - - -// dev-inspect with 'check' and _incorrect_ values - -//# programmable --sender A --inputs object(2,4)@3 0 0 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1), Input(2), Input(3)) - -//# programmable --sender A --inputs object(2,4)@4 1 2 vector[3] --dev-inspect -//> test::m::check(Input(0), Input(1), Input(2), Input(3)) - -//# programmable --sender A --inputs object(2,4)@2 1 2 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1), Input(2), Input(3)) diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids.exp deleted file mode 100644 index 5f7a9c46ac9..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids.exp +++ /dev/null @@ -1,62 +0,0 @@ -processed 14 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-117: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 12205600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 119-121: -created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 15640800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 123-123: -Owner: Account Address ( A ) -Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,8)}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}]} - -task 4 'programmable'. lines 125-126: -mutated: object(0,0), object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8) -gas summary: computation_cost: 1000000, storage_cost: 15640800, storage_rebate: 15484392, non_refundable_storage_fee: 156408 - -task 5 'view-object'. lines 128-128: -Owner: Account Address ( A ) -Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,8)}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}]} - -task 6 'programmable'. lines 130-131: -mutated: object(0,0), object(2,8) -deleted: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7) -gas summary: computation_cost: 1000000, storage_cost: 3906400, storage_rebate: 15484392, non_refundable_storage_fee: 156408 - -task 7 'view-object'. lines 133-136: -Owner: Account Address ( A ) -Version: 4 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,8)}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}]} - -task 8 'programmable'. lines 138-139: -mutated: object(_), object(2,8) -gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 - -task 9 'programmable'. lines 141-142: -mutated: object(_), object(2,8) -gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 - -task 10 'programmable'. lines 144-148: -mutated: object(_), object(2,8) -gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 - -task 11 'programmable'. lines 150-151: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 12, function_name: Some("check_") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 12, function_name: Some("check_") }, 0) in command 0 - -task 12 'programmable'. lines 153-154: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 - -task 13 'programmable'. lines 156-157: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 20, function_name: Some("check_") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 20, function_name: Some("check_") }, 0) in command 0 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids.move b/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids.move deleted file mode 100644 index f5321bbe16d..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids.move +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests finding UIDs for dynamic field access - -//# init --addresses test=0x0 --accounts A - -//# publish - -module test::m { - use sui::dynamic_field as field; - - public struct S has key, store { - id: UID, - other: UID, - wrapped: Wrapped, - many: vector, - } - - public struct Wrapped has key, store { - id: UID, - other: UID, - } - - const KEY: u64 = 0; - - ////////////////////////////////////////////////////////////// - // new - - public fun new(ctx: &mut TxContext): S { - let mut s = S { - id: object::new(ctx), - other: object::new(ctx), - wrapped: wrapped(ctx), - many: vector[wrapped(ctx), wrapped(ctx)], - }; - field::add(&mut s.id, KEY, 0); - field::add(&mut s.other, KEY, 0); - s - } - - fun wrapped(ctx: &mut TxContext): Wrapped { - let mut w = Wrapped { - id: object::new(ctx), - other: object::new(ctx), - }; - field::add(&mut w.id, KEY, 0); - field::add(&mut w.other, KEY, 0); - w - } - - ////////////////////////////////////////////////////////////// - // set - - public fun set(s: &mut S, value: u64) { - set_(&mut s.id, value); - set_(&mut s.other, value); - set_wrapped(&mut s.wrapped, value); - set_wrapped(vector::borrow_mut(&mut s.many, 0), value); - set_wrapped(vector::borrow_mut(&mut s.many, 1), value); - } - - fun set_wrapped(w: &mut Wrapped, value: u64) { - set_(&mut w.id, value); - set_(&mut w.other, value); - - } - - fun set_(id: &mut UID, value: u64) { - *field::borrow_mut(id, KEY) = value; - } - - ////////////////////////////////////////////////////////////// - // remove - - public fun remove(s: &mut S) { - remove_(&mut s.id); - remove_(&mut s.other); - remove_wrapped(&mut s.wrapped); - remove_wrapped(vector::borrow_mut(&mut s.many, 0)); - remove_wrapped(vector::borrow_mut(&mut s.many, 1)); - } - - fun remove_wrapped(w: &mut Wrapped) { - remove_(&mut w.id); - remove_(&mut w.other); - } - - fun remove_(id: &mut UID) { - field::remove(id, KEY); - } - - ////////////////////////////////////////////////////////////// - // check - - public fun check(s: &S, expected: Option) { - check_(&s.id, expected); - check_(&s.other, expected); - check_wrapped(&s.wrapped, expected); - check_wrapped(vector::borrow(&s.many, 0), expected); - check_wrapped(vector::borrow(&s.many, 1), expected); - } - - fun check_wrapped(w: &Wrapped, expected: Option) { - check_(&w.id, expected); - check_(&w.other, expected); - } - - fun check_(id: &UID, expected: Option) { - if (option::is_some(&expected)) { - let f = field::borrow(id, KEY); - assert!(f == option::borrow(&expected), 0); - } else { - assert!(!field::exists_with_type(id, KEY), 0); - } - } -} - -//# programmable --sender A --inputs @A -//> 0: test::m::new(); -//> TransferObjects([Result(0)], Input(0)) - -//# view-object 2,8 - -//# programmable --sender A --inputs object(2,8) 112 -//> test::m::set(Input(0), Input(1)) - -//# view-object 2,8 - -//# programmable --sender A --inputs object(2,8) 112 -//> test::m::remove(Input(0)) - -//# view-object 2,8 - - -// dev-inspect with 'check' and correct values - -//# programmable --sender A --inputs object(2,8)@2 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@3 vector[112] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@4 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1)) - - -// dev-inspect with 'check' and _incorrect_ values - -//# programmable --sender A --inputs object(2,8)@3 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@4 vector[112] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@2 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1)) diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids_dof.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids_dof.exp deleted file mode 100644 index 873fe2ab489..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids_dof.exp +++ /dev/null @@ -1,62 +0,0 @@ -processed 14 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-130: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 13353200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 132-134: -created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8), object(2,9), object(2,10), object(2,11), object(2,12), object(2,13), object(2,14), object(2,15), object(2,16) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 33941600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 136-136: -Owner: Account Address ( A ) -Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,8)}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}]} - -task 4 'programmable'. lines 138-139: -mutated: object(0,0), object(2,8), object(2,9), object(2,10), object(2,11), object(2,12), object(2,13), object(2,14), object(2,15), object(2,16) -gas summary: computation_cost: 1000000, storage_cost: 14303200, storage_rebate: 14160168, non_refundable_storage_fee: 143032 - -task 5 'view-object'. lines 141-141: -Owner: Account Address ( A ) -Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,8)}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}]} - -task 6 'programmable'. lines 143-144: -mutated: object(0,0), object(2,8) -deleted: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,9), object(2,10), object(2,11), object(2,12), object(2,13), object(2,14), object(2,15), object(2,16) -gas summary: computation_cost: 1000000, storage_cost: 3906400, storage_rebate: 33602184, non_refundable_storage_fee: 339416 - -task 7 'view-object'. lines 146-149: -Owner: Account Address ( A ) -Version: 4 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,8)}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}]} - -task 8 'programmable'. lines 151-152: -mutated: object(_), object(2,8) -gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 - -task 9 'programmable'. lines 154-155: -mutated: object(_), object(2,8) -gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 - -task 10 'programmable'. lines 157-161: -mutated: object(_), object(2,8) -gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 - -task 11 'programmable'. lines 163-164: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 18, function_name: Some("check_") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 18, function_name: Some("check_") }, 0) in command 0 - -task 12 'programmable'. lines 166-167: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 - -task 13 'programmable'. lines 169-170: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 26, function_name: Some("check_") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 26, function_name: Some("check_") }, 0) in command 0 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids_dof.move b/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids_dof.move deleted file mode 100644 index 86fa72f2a4f..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids_dof.move +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests finding UIDs for dynamic object field access - -//# init --addresses test=0x0 --accounts A - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct S has key, store { - id: UID, - other: UID, - wrapped: Wrapped, - many: vector, - } - - public struct Wrapped has key, store { - id: UID, - other: UID, - } - - public struct Value has key, store { - id: UID, - value: u64, - } - - const KEY: u64 = 0; - - ////////////////////////////////////////////////////////////// - // new - - public fun new(ctx: &mut TxContext): S { - let mut s = S { - id: object::new(ctx), - other: object::new(ctx), - wrapped: wrapped(ctx), - many: vector[wrapped(ctx), wrapped(ctx)], - }; - ofield::add(&mut s.id, KEY, value(0, ctx)); - ofield::add(&mut s.other, KEY, value(0, ctx)); - s - } - - fun wrapped(ctx: &mut TxContext): Wrapped { - let mut w = Wrapped { - id: object::new(ctx), - other: object::new(ctx), - }; - ofield::add(&mut w.id, KEY, value(0, ctx)); - ofield::add(&mut w.other, KEY, value(0, ctx)); - w - } - - fun value(value: u64, ctx: &mut TxContext): Value { - Value { - id: object::new(ctx), - value - } - } - - ////////////////////////////////////////////////////////////// - // set - - public fun set(s: &mut S, value: u64) { - set_(&mut s.id, value); - set_(&mut s.other, value); - set_wrapped(&mut s.wrapped, value); - set_wrapped(vector::borrow_mut(&mut s.many, 0), value); - set_wrapped(vector::borrow_mut(&mut s.many, 1), value); - } - - fun set_wrapped(w: &mut Wrapped, value: u64) { - set_(&mut w.id, value); - set_(&mut w.other, value); - - } - - fun set_(id: &mut UID, value: u64) { - ofield::borrow_mut(id, KEY).value = value; - } - - ////////////////////////////////////////////////////////////// - // remove - - public fun remove(s: &mut S) { - remove_(&mut s.id); - remove_(&mut s.other); - remove_wrapped(&mut s.wrapped); - remove_wrapped(vector::borrow_mut(&mut s.many, 0)); - remove_wrapped(vector::borrow_mut(&mut s.many, 1)); - } - - fun remove_wrapped(w: &mut Wrapped) { - remove_(&mut w.id); - remove_(&mut w.other); - } - - fun remove_(id: &mut UID) { - let Value { id, value: _ } = ofield::remove(id, KEY); - object::delete(id); - } - - ////////////////////////////////////////////////////////////// - // check - - public fun check(s: &S, expected: Option) { - check_(&s.id, expected); - check_(&s.other, expected); - check_wrapped(&s.wrapped, expected); - check_wrapped(vector::borrow(&s.many, 0), expected); - check_wrapped(vector::borrow(&s.many, 1), expected); - } - - fun check_wrapped(w: &Wrapped, expected: Option) { - check_(&w.id, expected); - check_(&w.other, expected); - } - - fun check_(id: &UID, expected: Option) { - if (option::is_some(&expected)) { - let Value { id: _, value } = ofield::borrow(id, KEY); - assert!(value == option::borrow(&expected), 0); - } else { - assert!(!ofield::exists_with_type(id, KEY), 0); - } - } -} - -//# programmable --sender A --inputs @A -//> 0: test::m::new(); -//> TransferObjects([Result(0)], Input(0)) - -//# view-object 2,8 - -//# programmable --sender A --inputs object(2,8) 112 -//> test::m::set(Input(0), Input(1)) - -//# view-object 2,8 - -//# programmable --sender A --inputs object(2,8) 112 -//> test::m::remove(Input(0)) - -//# view-object 2,8 - - -// dev-inspect with 'check' and correct values - -//# programmable --sender A --inputs object(2,8)@2 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@3 vector[112] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@4 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1)) - - -// dev-inspect with 'check' and _incorrect_ values - -//# programmable --sender A --inputs object(2,8)@3 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@4 vector[112] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@2 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1)) diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids_on_child.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids_on_child.exp deleted file mode 100644 index 0d5baf3992e..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids_on_child.exp +++ /dev/null @@ -1,62 +0,0 @@ -processed 14 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-140: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 13862400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 142-144: -created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8), object(2,9) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 17609200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 146-146: -Owner: Account Address ( A ) -Version: 2 -Contents: test::m::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,9)}}} - -task 4 'programmable'. lines 148-149: -mutated: object(0,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8), object(2,9) -gas summary: computation_cost: 1000000, storage_cost: 13968800, storage_rebate: 13829112, non_refundable_storage_fee: 139688 - -task 5 'view-object'. lines 151-151: -Owner: Account Address ( A ) -Version: 3 -Contents: test::m::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,9)}}} - -task 6 'programmable'. lines 153-154: -mutated: object(0,0), object(2,9) -deleted: object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8) -gas summary: computation_cost: 1000000, storage_cost: 2234400, storage_rebate: 13829112, non_refundable_storage_fee: 139688 - -task 7 'view-object'. lines 156-159: -Owner: Account Address ( A ) -Version: 4 -Contents: test::m::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,9)}}} - -task 8 'programmable'. lines 161-162: -mutated: object(_), object(2,9) -gas summary: computation_cost: 500000, storage_cost: 2234400, storage_rebate: 1233936, non_refundable_storage_fee: 12464 - -task 9 'programmable'. lines 164-165: -mutated: object(_), object(2,9) -gas summary: computation_cost: 500000, storage_cost: 2234400, storage_rebate: 1233936, non_refundable_storage_fee: 12464 - -task 10 'programmable'. lines 167-171: -mutated: object(_), object(2,9) -gas summary: computation_cost: 500000, storage_cost: 2234400, storage_rebate: 1233936, non_refundable_storage_fee: 12464 - -task 11 'programmable'. lines 173-174: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 12, function_name: Some("check_") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 12, function_name: Some("check_") }, 0) in command 0 - -task 12 'programmable'. lines 176-177: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 - -task 13 'programmable'. lines 179-180: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 20, function_name: Some("check_") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 20, function_name: Some("check_") }, 0) in command 0 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids_on_child.move b/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids_on_child.move deleted file mode 100644 index c387eac2a20..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/find_all_uids_on_child.move +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests finding UIDs for dynamic field access on a child object (non-input) - -//# init --addresses test=0x0 --accounts A - -//# publish - -module test::m { - use sui::dynamic_field as field; - - public struct Parent has key, store { - id: UID, - } - - public struct S has key, store { - id: UID, - other: UID, - wrapped: Wrapped, - many: vector, - } - - public struct Wrapped has key, store { - id: UID, - other: UID, - } - - const KEY: u64 = 0; - - ////////////////////////////////////////////////////////////// - // new - - public fun new(ctx: &mut TxContext): Parent { - let mut parent = Parent { id: object::new(ctx) }; - field::add(&mut parent.id, KEY, s(ctx)); - parent - } - - fun s(ctx: &mut TxContext): S { - let mut s = S { - id: object::new(ctx), - other: object::new(ctx), - wrapped: wrapped(ctx), - many: vector[wrapped(ctx), wrapped(ctx)], - }; - field::add(&mut s.id, KEY, 0); - field::add(&mut s.other, KEY, 0); - s - } - - fun wrapped(ctx: &mut TxContext): Wrapped { - let mut w = Wrapped { - id: object::new(ctx), - other: object::new(ctx), - }; - field::add(&mut w.id, KEY, 0); - field::add(&mut w.other, KEY, 0); - w - } - - ////////////////////////////////////////////////////////////// - // set - - public fun set(parent: &mut Parent, value: u64) { - set_s(field::borrow_mut(&mut parent.id, KEY), value); - } - - - fun set_s(s: &mut S, value: u64) { - set_(&mut s.id, value); - set_(&mut s.other, value); - set_wrapped(&mut s.wrapped, value); - set_wrapped(vector::borrow_mut(&mut s.many, 0), value); - set_wrapped(vector::borrow_mut(&mut s.many, 1), value); - } - - fun set_wrapped(w: &mut Wrapped, value: u64) { - set_(&mut w.id, value); - set_(&mut w.other, value); - - } - - fun set_(id: &mut UID, value: u64) { - *field::borrow_mut(id, KEY) = value; - } - - ////////////////////////////////////////////////////////////// - // remove - - public fun remove(parent: &mut Parent) { - remove_s(field::borrow_mut(&mut parent.id, KEY)); - } - - fun remove_s(s: &mut S) { - remove_(&mut s.id); - remove_(&mut s.other); - remove_wrapped(&mut s.wrapped); - remove_wrapped(vector::borrow_mut(&mut s.many, 0)); - remove_wrapped(vector::borrow_mut(&mut s.many, 1)); - } - - fun remove_wrapped(w: &mut Wrapped) { - remove_(&mut w.id); - remove_(&mut w.other); - } - - fun remove_(id: &mut UID) { - field::remove(id, KEY); - } - - ////////////////////////////////////////////////////////////// - // check - - public fun check(parent: &Parent, expected: Option) { - check_s(field::borrow(&parent.id, KEY), expected); - } - - fun check_s(s: &S, expected: Option) { - check_(&s.id, expected); - check_(&s.other, expected); - check_wrapped(&s.wrapped, expected); - check_wrapped(vector::borrow(&s.many, 0), expected); - check_wrapped(vector::borrow(&s.many, 1), expected); - } - - fun check_wrapped(w: &Wrapped, expected: Option) { - check_(&w.id, expected); - check_(&w.other, expected); - } - - fun check_(id: &UID, expected: Option) { - if (option::is_some(&expected)) { - let f = field::borrow(id, KEY); - assert!(f == option::borrow(&expected), 0); - } else { - assert!(!field::exists_with_type(id, KEY), 0); - } - } -} - -//# programmable --sender A --inputs @A -//> 0: test::m::new(); -//> TransferObjects([Result(0)], Input(0)) - -//# view-object 2,9 - -//# programmable --sender A --inputs object(2,9) 112 -//> test::m::set(Input(0), Input(1)) - -//# view-object 2,9 - -//# programmable --sender A --inputs object(2,9) 112 -//> test::m::remove(Input(0)) - -//# view-object 2,9 - - -// dev-inspect with 'check' and correct values - -//# programmable --sender A --inputs object(2,9)@2 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,9)@3 vector[112] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,9)@4 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1)) - - -// dev-inspect with 'check' and _incorrect_ values - -//# programmable --sender A --inputs object(2,9)@3 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,9)@4 vector[112] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,9)@2 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1)) diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/middle_version_less_than_child.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/middle_version_less_than_child.exp deleted file mode 100644 index b4503102371..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/middle_version_less_than_child.exp +++ /dev/null @@ -1,52 +0,0 @@ -processed 11 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-51: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 7493600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 53-57: -created: object(2,0), object(2,1), object(2,2) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 6285200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 59-59: -Owner: Object ID: ( _ ) -Version: 2 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, name: 0u64, value: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: _}}, value: 0u64}} - -task 4 'view-object'. lines 61-61: -Owner: Object ID: ( fake(2,2) ) -Version: 2 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, name: 0u64, value: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: _}}, value: 0u64}} - -task 5 'view-object'. lines 63-63: -Owner: Account Address ( A ) -Version: 2 -Contents: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}, value: 0u64} - -task 6 'programmable'. lines 65-68: -mutated: object(0,0), object(2,0), object(2,2) -gas summary: computation_cost: 1000000, storage_cost: 4278800, storage_rebate: 4236012, non_refundable_storage_fee: 42788 - -task 7 'view-object'. lines 70-70: -Owner: Object ID: ( _ ) -Version: 3 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, name: 0u64, value: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: _}}, value: 112u64}} - -task 8 'view-object'. lines 72-72: -Owner: Object ID: ( fake(2,2) ) -Version: 2 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, name: 0u64, value: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: _}}, value: 0u64}} - -task 9 'view-object'. lines 74-77: -Owner: Account Address ( A ) -Version: 3 -Contents: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}, value: 0u64} - -task 10 'programmable'. lines 79-80: -mutated: object(0,0), object(2,2) -gas summary: computation_cost: 1000000, storage_cost: 2272400, storage_rebate: 2249676, non_refundable_storage_fee: 22724 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/middle_version_less_than_child.move b/crates/sui-adapter-transactional-tests/tests/mvcc/middle_version_less_than_child.move deleted file mode 100644 index 5f6ca9572f2..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/middle_version_less_than_child.move +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests accessing the versions of a child of a child - -//# init --addresses test=0x0 --accounts A - -//# publish - -module test::m { - use sui::dynamic_field as field; - - public struct Obj has key, store { - id: UID, - value: u64, - } - - const KEY: u64 = 0; - - ////////////////////////////////////////////////////////////// - // new - - public fun new(ctx: &mut TxContext): Obj { - let mut grand = Obj { id: object::new(ctx), value: 0 }; - let mut parent = Obj { id: object::new(ctx), value: 0 }; - let child = Obj { id: object::new(ctx), value: 0 }; - field::add(&mut parent.id, KEY, child); - field::add(&mut grand.id, KEY, parent); - grand - } - - ////////////////////////////////////////////////////////////// - // set - - public fun set(grand: &mut Obj, v: u64) { - let parent: &mut Obj = field::borrow_mut(&mut grand.id, KEY); - let child: &mut Obj = field::borrow_mut(&mut parent.id, KEY); - child.value = v; - } - - ////////////////////////////////////////////////////////////// - // check - - public fun check(grand: &Obj, expected: u64) { - assert!(grand.value == 0, 0); - let parent: &Obj = field::borrow(&grand.id, KEY); - assert!(parent.value == 0, 0); - let child: &Obj = field::borrow(&parent.id, KEY); - assert!(child.value == expected, 0); - } -} - -//# programmable --sender A --inputs @A -//> 0: test::m::new(); -//> TransferObjects([Result(0)], Input(0)) - -// All 3 objects have version 2 - -//# view-object 2,0 - -//# view-object 2,1 - -//# view-object 2,2 - -//# programmable --sender A --inputs object(2,2) 112 -//> test::m::set(Input(0), Input(1)) - -// The middle object has version 2, while the root and modified leaf have version 3 - -//# view-object 2,0 - -//# view-object 2,1 - -//# view-object 2,2 - -// correctly load the leaf even though it has a version greater than its immediate -// parent - -//# programmable --sender A --inputs object(2,2) 112 -//> test::m::check(Input(0), Input(1)) diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/not_root_version.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/not_root_version.exp deleted file mode 100644 index 597d38e9f90..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/not_root_version.exp +++ /dev/null @@ -1,66 +0,0 @@ -processed 14 tasks - -init: -P1: object(0,0), P2: object(0,1) - -task 1 'publish'. lines 8-53: -created: object(1,0) -mutated: object(0,2) -gas summary: computation_cost: 1000000, storage_cost: 7432800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 55-57: -created: object(2,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'programmable'. lines 59-60: -mutated: object(0,0), object(2,0) -gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 2174436, non_refundable_storage_fee: 21964 - -task 4 'programmable'. lines 62-63: -mutated: object(0,0), object(2,0) -gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 2174436, non_refundable_storage_fee: 21964 - -task 5 'view-object'. lines 65-68: -Owner: Account Address ( P1 ) -Version: 4 -Contents: test::m::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 6 'programmable'. lines 70-72: -created: object(6,0), object(6,1) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 7 'view-object'. lines 74-74: -Owner: Object ID: ( fake(6,1) ) -Version: 2 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}, name: 0u64, value: 0u64} - -task 8 'programmable'. lines 76-77: -mutated: object(0,1), object(6,0), object(6,1) -gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 3626568, non_refundable_storage_fee: 36632 - -task 9 'view-object'. lines 79-83: -Owner: Object ID: ( fake(6,1) ) -Version: 3 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}, name: 0u64, value: 1u64} - -task 10 'programmable'. lines 85-90: -created: object(10,0) -mutated: object(_), object(2,0) -wrapped: object(6,1) -gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 - -task 11 'programmable'. lines 92-96: -created: object(10,0) -mutated: object(_), object(2,0) -wrapped: object(6,1) -gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 - -task 12 'programmable'. lines 98-102: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 - -task 13 'programmable'. lines 104-106: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/not_root_version.move b/crates/sui-adapter-transactional-tests/tests/mvcc/not_root_version.move deleted file mode 100644 index fb6876aa363..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/not_root_version.move +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests accessing version of the input parent, not the runtime parent - -//# init --addresses test=0x0 --accounts P1 P2 - -//# publish - -module test::m { - use sui::dynamic_field as field; - - public struct A has key, store { - id: UID, - } - - public struct B has key, store { - id: UID, - } - - const KEY: u64 = 0; - - public fun a(ctx: &mut TxContext): A { - A { id: object::new(ctx) } - } - - public fun b(ctx: &mut TxContext): B { - let mut b = B { id: object::new(ctx) }; - field::add(&mut b.id, KEY, 0); - b - - } - - public fun bump(b: &mut B) { - let f = field::borrow_mut(&mut b.id, KEY); - *f = *f + 1; - } - - public fun append(a: &mut A, b: B) { - field::add(&mut a.id, KEY, b); - } - - public fun check(a: &A, expected: u64) { - let b: &B = field::borrow(&a.id, KEY); - let v = *field::borrow(&b.id, KEY); - assert!(v == expected, 0); - } - - public fun nop() { - } -} - -// Create object A and bump the version to 4 - -//# programmable --sender P1 --inputs @P1 -//> 0: test::m::a(); -//> TransferObjects([Result(0)], Input(0)) - -//# programmable --sender P1 --inputs object(2,0) -//> test::m::nop(); - -//# programmable --sender P1 --inputs object(2,0) -//> test::m::nop(); - -//# view-object 2,0 - - -// Create object B witha version 2 and 3 for it's dynamic field - -//# programmable --sender P2 --inputs @P2 -//> 0: test::m::b(); -//> TransferObjects([Result(0)], Input(0)) - -//# view-object 6,0 - -//# programmable --sender P2 --inputs object(6,1) -//> 0: test::m::bump(Input(0)); - -//# view-object 6,0 - - -// Append object B to object A, but using version 2 of object B. And ensure that -// when we later read the dynamic field of object B, we get the version 2 value. - -//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@2 0 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); - -// checking that with version 3 we get the other value, then flip them to ensure -// they abort - -//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@3 1 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); - -// @2 with value 1 aborts - -//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@2 1 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); - -// @3 with value 0 aborts - -//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@3 0 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/not_root_version_flipped_case.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/not_root_version_flipped_case.exp deleted file mode 100644 index 296e99efa56..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/not_root_version_flipped_case.exp +++ /dev/null @@ -1,58 +0,0 @@ -processed 12 tasks - -init: -P1: object(0,0), P2: object(0,1) - -task 1 'publish'. lines 8-53: -created: object(1,0) -mutated: object(0,2) -gas summary: computation_cost: 1000000, storage_cost: 7432800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 55-57: -created: object(2,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 60-63: -Owner: Account Address ( P1 ) -Version: 2 -Contents: test::m::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 4 'programmable'. lines 65-67: -created: object(4,0), object(4,1) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 5 'view-object'. lines 69-69: -Owner: Object ID: ( fake(4,1) ) -Version: 2 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(4,0)}}, name: 0u64, value: 0u64} - -task 6 'programmable'. lines 71-72: -mutated: object(0,1), object(4,0), object(4,1) -gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 3626568, non_refundable_storage_fee: 36632 - -task 7 'view-object'. lines 74-77: -Owner: Object ID: ( fake(4,1) ) -Version: 3 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(4,0)}}, name: 0u64, value: 1u64} - -task 8 'programmable'. lines 79-84: -created: object(8,0) -mutated: object(_), object(2,0) -wrapped: object(4,1) -gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 - -task 9 'programmable'. lines 86-90: -created: object(8,0) -mutated: object(_), object(2,0) -wrapped: object(4,1) -gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 - -task 10 'programmable'. lines 92-96: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 - -task 11 'programmable'. lines 98-100: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/not_root_version_flipped_case.move b/crates/sui-adapter-transactional-tests/tests/mvcc/not_root_version_flipped_case.move deleted file mode 100644 index 2afd7d1bf2f..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/not_root_version_flipped_case.move +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests accessing version of the input parent, not the runtime parent - -//# init --addresses test=0x0 --accounts P1 P2 - -//# publish - -module test::m { - use sui::dynamic_field as field; - - public struct A has key, store { - id: UID, - } - - public struct B has key, store { - id: UID, - } - - const KEY: u64 = 0; - - public fun a(ctx: &mut TxContext): A { - A { id: object::new(ctx) } - } - - public fun b(ctx: &mut TxContext): B { - let mut b = B { id: object::new(ctx) }; - field::add(&mut b.id, KEY, 0); - b - - } - - public fun bump(b: &mut B) { - let f = field::borrow_mut(&mut b.id, KEY); - *f = *f + 1; - } - - public fun append(a: &mut A, b: B) { - field::add(&mut a.id, KEY, b); - } - - public fun check(a: &A, expected: u64) { - let b: &B = field::borrow(&a.id, KEY); - let v = *field::borrow(&b.id, KEY); - assert!(v == expected, 0); - } - - public fun nop() { - } -} - -// Create object A at version 2 - -//# programmable --sender P1 --inputs @P1 -//> 0: test::m::a(); -//> TransferObjects([Result(0)], Input(0)) - - -//# view-object 2,0 - - -// Create object B with a version 2 and 3 for it's dynamic field - -//# programmable --sender P2 --inputs @P2 -//> 0: test::m::b(); -//> TransferObjects([Result(0)], Input(0)) - -//# view-object 4,0 - -//# programmable --sender P2 --inputs object(4,1) -//> 0: test::m::bump(Input(0)); - -//# view-object 4,0 - -// Append object B to object A. And ensure that when we later read the dynamic -// field of object B, we get the most recent version. - -//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@3 1 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); - -// checking that with version 3 we get the other value, then flip them to ensure -// they abort - -//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@2 0 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); - -// @2 with value 1 aborts - -//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@2 1 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); - -// @3 with value 0 aborts - -//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@3 0 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_df.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_df.exp deleted file mode 100644 index c4a41e38fe7..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_df.exp +++ /dev/null @@ -1,70 +0,0 @@ -processed 14 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 6-76: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 12524800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 78-78: -created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 15298800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 80-80: -Owner: Object ID: ( _ ) -Version: 2 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, name: sui::dynamic_object_field::Wrapper {name: 1u64}, value: sui::object::ID {bytes: fake(2,5)}} - -task 4 'view-object'. lines 82-82: -Owner: Object ID: ( fake(2,6) ) -Version: 2 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, name: 0u64, value: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: _}}, value: vector[98u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8]}} - -task 5 'view-object'. lines 84-84: -Owner: Object ID: ( _ ) -Version: 2 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}, name: 0u64, value: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: _}}, value: vector[98u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8]}} - -task 6 'view-object'. lines 86-86: -Owner: Object ID: ( _ ) -Version: 2 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,3)}}, name: 0u64, value: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: _}}, value: vector[119u8, 114u8, 97u8, 112u8, 112u8, 101u8, 100u8, 95u8, 100u8, 111u8, 102u8]}} - -task 7 'view-object'. lines 88-88: -Owner: Account Address ( A ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,4)}}, value: vector[97u8, 95u8, 112u8, 97u8, 114u8, 101u8, 110u8, 116u8]} - -task 8 'view-object'. lines 90-90: -Owner: Object ID: ( fake(2,0) ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,5)}}, value: vector[98u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8, 95u8, 100u8, 111u8, 102u8]} - -task 9 'view-object'. lines 92-92: -Owner: Account Address ( fake(2,4) ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,6)}}, value: vector[98u8, 95u8, 112u8, 97u8, 114u8, 101u8, 110u8, 116u8]} - -task 10 'view-object'. lines 94-97: -Owner: Account Address ( fake(2,4) ) -Version: 2 -Contents: tto::M1::Wrapper {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,7)}}, value: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: _}}, value: vector[119u8, 114u8, 97u8, 112u8, 112u8, 101u8, 100u8]}} - -task 11 'run'. lines 98-98: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::receive_impl (function index 12) at offset 0, Abort Code: 2 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } - -task 12 'run'. lines 100-100: -created: object(12,0) -mutated: object(0,0), object(2,4) -wrapped: object(2,6) -gas summary: computation_cost: 1000000, storage_cost: 4278800, storage_rebate: 3521232, non_refundable_storage_fee: 35568 - -task 13 'run'. lines 102-102: -created: object(13,0) -mutated: object(0,0), object(2,4) -wrapped: object(2,7) -gas summary: computation_cost: 1000000, storage_cost: 4856400, storage_rebate: 4093056, non_refundable_storage_fee: 41344 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_dof.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_dof.exp deleted file mode 100644 index 3fbeb16ab34..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_access_through_parent_dof.exp +++ /dev/null @@ -1,78 +0,0 @@ -processed 16 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 6-76: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 12509600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 78-78: -created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8), object(2,9) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 18749200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 80-80: -Owner: Object ID: ( fake(2,7) ) -Version: 2 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(2,4)}} - -task 4 'view-object'. lines 82-82: -Owner: Object ID: ( _ ) -Version: 2 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(2,5)}} - -task 5 'view-object'. lines 84-84: -Owner: Object ID: ( fake(2,6) ) -Version: 2 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(2,7)}} - -task 6 'view-object'. lines 86-86: -Owner: Object ID: ( fake(2,7) ) -Version: 2 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,3)}}, name: 1u64, value: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: _}}, value: vector[98u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8, 95u8, 100u8, 102u8]}} - -task 7 'view-object'. lines 88-88: -Owner: Object ID: ( fake(2,0) ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,4)}}, value: vector[98u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8]} - -task 8 'view-object'. lines 90-90: -Owner: Object ID: ( fake(2,1) ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,5)}}, value: vector[119u8, 114u8, 97u8, 112u8, 112u8, 101u8, 100u8, 95u8, 100u8, 102u8]} - -task 9 'view-object'. lines 92-92: -Owner: Account Address ( fake(2,8) ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,6)}}, value: vector[98u8, 95u8, 112u8, 97u8, 114u8, 101u8, 110u8, 116u8]} - -task 10 'view-object'. lines 94-94: -Owner: Object ID: ( fake(2,2) ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,7)}}, value: vector[98u8, 95u8, 99u8, 104u8, 105u8, 108u8, 100u8]} - -task 11 'view-object'. lines 96-96: -Owner: Account Address ( A ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,8)}}, value: vector[97u8, 95u8, 112u8, 97u8, 114u8, 101u8, 110u8, 116u8]} - -task 12 'view-object'. lines 98-101: -Owner: Account Address ( fake(2,8) ) -Version: 2 -Contents: tto::M1::Wrapper {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,9)}}, value: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: _}}, value: vector[119u8, 114u8, 97u8, 112u8, 112u8, 101u8, 100u8]}} - -task 13 'run'. lines 102-102: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::receive_impl (function index 12) at offset 0, Abort Code: 2 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } - -task 14 'run'. lines 104-104: -created: object(14,0) -mutated: object(0,0), object(2,6), object(2,8) -gas summary: computation_cost: 1000000, storage_cost: 6011600, storage_rebate: 3521232, non_refundable_storage_fee: 35568 - -task 15 'run'. lines 106-106: -created: object(15,0) -mutated: object(0,0), object(2,8), object(2,9) -gas summary: computation_cost: 1000000, storage_cost: 6589200, storage_rebate: 4093056, non_refundable_storage_fee: 41344 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_dof.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_dof.exp deleted file mode 100644 index 55d683f3162..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/receive_object_dof.exp +++ /dev/null @@ -1,112 +0,0 @@ -processed 24 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 6-58: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 10533600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 60-60: -created: object(2,0), object(2,1), object(2,2), object(2,3) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 7273200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 62-62: -Owner: Object ID: ( fake(2,1) ) -Version: 2 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(2,3)}} - -task 4 'view-object'. lines 64-64: -Owner: Object ID: ( fake(2,0) ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,3)}}, value: 0u64} - -task 5 'view-object'. lines 66-66: -Owner: Account Address ( fake(2,2) ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, value: 0u64} - -task 6 'view-object'. lines 68-68: -Owner: Account Address ( A ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}, value: 0u64} - -task 7 'run'. lines 70-70: -created: object(7,0) -mutated: object(0,0), object(2,1), object(2,2) -gas summary: computation_cost: 1000000, storage_cost: 5996400, storage_rebate: 3506184, non_refundable_storage_fee: 35416 - -task 8 'view-object'. lines 72-74: -Owner: Object ID: ( fake(2,1) ) -Version: 2 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(2,3)}} - -task 9 'view-object'. lines 75-75: -Owner: Object ID: ( fake(2,0) ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,3)}}, value: 0u64} - -task 10 'view-object'. lines 77-77: -Owner: Object ID: ( fake(7,0) ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, value: 0u64} - -task 11 'view-object'. lines 79-79: -Owner: Account Address ( A ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}, value: 0u64} - -task 12 'programmable'. lines 81-82: -mutated: object(0,0), object(2,1), object(2,2), object(2,3) -gas summary: computation_cost: 1000000, storage_cost: 4818400, storage_rebate: 4770216, non_refundable_storage_fee: 48184 - -task 13 'view-object'. lines 84-86: -Owner: Object ID: ( fake(2,1) ) -Version: 2 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(2,3)}} - -task 14 'view-object'. lines 87-87: -Owner: Object ID: ( fake(2,0) ) -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,3)}}, value: 3u64} - -task 15 'view-object'. lines 89-89: -Owner: Object ID: ( fake(7,0) ) -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, value: 2u64} - -task 16 'view-object'. lines 91-91: -Owner: Account Address ( A ) -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}, value: 1u64} - -task 17 'programmable'. lines 93-96: -mutated: object(0,0), object(2,2) -deleted: object(2,0), object(2,3) -gas summary: computation_cost: 1000000, storage_cost: 2264800, storage_rebate: 5936436, non_refundable_storage_fee: 59964 - -task 18 'programmable'. lines 98-99: -mutated: object(_), object(2,2) -gas summary: computation_cost: 500000, storage_cost: 2264800, storage_rebate: 1264032, non_refundable_storage_fee: 12768 - -task 19 'programmable'. lines 101-102: -mutated: object(_), object(2,2) -gas summary: computation_cost: 500000, storage_cost: 2264800, storage_rebate: 1264032, non_refundable_storage_fee: 12768 - -task 20 'programmable'. lines 104-107: -mutated: object(_), object(2,2) -gas summary: computation_cost: 500000, storage_cost: 2264800, storage_rebate: 1264032, non_refundable_storage_fee: 12768 - -task 21 'programmable'. lines 109-110: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: tto, name: Identifier("M1") }, function: 4, instruction: 10, function_name: Some("check") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: tto, name: Identifier("M1") }, function: 4, instruction: 10, function_name: Some("check") }, 0) in command 0 - -task 22 'programmable'. lines 112-113: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 - -task 23 'programmable'. lines 115-116: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: tto, name: Identifier("M1") }, function: 4, instruction: 10, function_name: Some("check") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: tto, name: Identifier("M1") }, function: 4, instruction: 10, function_name: Some("check") }, 0) in command 0 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/child_of_child.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/v0/child_of_child.exp deleted file mode 100644 index c1ff3ec4141..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/child_of_child.exp +++ /dev/null @@ -1,62 +0,0 @@ -processed 14 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-66: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 9218800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 68-70: -created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 9750800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 72-72: -Owner: Account Address ( A ) -Version: 2 -Contents: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,4)}}, value: 0u64} - -task 4 'programmable'. lines 74-75: -mutated: object(0,0), object(2,2), object(2,3), object(2,4) -gas summary: computation_cost: 1000000, storage_cost: 4841200, storage_rebate: 4792788, non_refundable_storage_fee: 48412 - -task 5 'view-object'. lines 77-77: -Owner: Account Address ( A ) -Version: 3 -Contents: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,4)}}, value: 1u64} - -task 6 'programmable'. lines 79-80: -mutated: object(0,0), object(2,4) -deleted: object(2,0), object(2,2) -gas summary: computation_cost: 1000000, storage_cost: 2272400, storage_rebate: 5951484, non_refundable_storage_fee: 60116 - -task 7 'view-object'. lines 82-85: -Owner: Account Address ( A ) -Version: 4 -Contents: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,4)}}, value: 1u64} - -task 8 'programmable'. lines 87-88: -mutated: object(_), object(2,4) -gas summary: computation_cost: 500000, storage_cost: 2272400, storage_rebate: 1271556, non_refundable_storage_fee: 12844 - -task 9 'programmable'. lines 90-91: -mutated: object(_), object(2,4) -gas summary: computation_cost: 500000, storage_cost: 2272400, storage_rebate: 1271556, non_refundable_storage_fee: 12844 - -task 10 'programmable'. lines 93-97: -mutated: object(_), object(2,4) -gas summary: computation_cost: 500000, storage_cost: 2272400, storage_rebate: 1271556, non_refundable_storage_fee: 12844 - -task 11 'programmable'. lines 99-100: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 - -task 12 'programmable'. lines 102-103: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 - -task 13 'programmable'. lines 105-106: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 3, instruction: 10, function_name: Some("check") }, 0) in command 0 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/child_of_child.move b/crates/sui-adapter-transactional-tests/tests/mvcc/v0/child_of_child.move deleted file mode 100644 index f4a8734e49f..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/child_of_child.move +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests accessing the versions of a child of a child - -//# init --addresses test=0x0 --accounts A --protocol-version 16 - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct Obj has key, store { - id: UID, - value: u64, - } - - const KEY: u64 = 0; - - ////////////////////////////////////////////////////////////// - // new - - public fun new(ctx: &mut TxContext): Obj { - let mut grand = Obj { id: object::new(ctx), value: 0 }; - let mut parent = Obj { id: object::new(ctx), value: 0 }; - let child = Obj { id: object::new(ctx), value: 0 }; - ofield::add(&mut parent.id, KEY, child); - ofield::add(&mut grand.id, KEY, parent); - grand - } - - ////////////////////////////////////////////////////////////// - // set - - public fun set(grand: &mut Obj, v1: u64, v2: u64, v3: u64) { - grand.value = v1; - let parent: &mut Obj = ofield::borrow_mut(&mut grand.id, KEY); - parent.value = v2; - let child: &mut Obj = ofield::borrow_mut(&mut parent.id, KEY); - child.value = v3; - } - - ////////////////////////////////////////////////////////////// - // remove - - public fun remove(grand: &mut Obj) { - let parent: &mut Obj = ofield::borrow_mut(&mut grand.id, KEY); - let Obj { id, value: _ } = ofield::remove(&mut parent.id, KEY); - object::delete(id); - } - - ////////////////////////////////////////////////////////////// - // check - - public fun check(grand: &Obj, v1: u64, v2: u64, v3: Option) { - assert!(grand.value == v1, 0); - let parent: &Obj = ofield::borrow(&grand.id, KEY); - assert!(parent.value == v2, 0); - if (option::is_some(&v3)) { - let child: &Obj = ofield::borrow(&parent.id, KEY); - assert!(&child.value == option::borrow(&v3), 0); - } else { - assert!(!ofield::exists_(&parent.id, KEY), 0); - } - } -} - -//# programmable --sender A --inputs @A -//> 0: test::m::new(); -//> TransferObjects([Result(0)], Input(0)) - -//# view-object 2,4 - -//# programmable --sender A --inputs object(2,4) 1 2 3 -//> test::m::set(Input(0), Input(1), Input(2), Input(3)) - -//# view-object 2,4 - -//# programmable --sender A --inputs object(2,4) -//> test::m::remove(Input(0)) - -//# view-object 2,4 - - -// dev-inspect with 'check' and correct values - -//# programmable --sender A --inputs object(2,4)@2 0 0 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1), Input(2), Input(3)) - -//# programmable --sender A --inputs object(2,4)@3 1 2 vector[3] --dev-inspect -//> test::m::check(Input(0), Input(1), Input(2), Input(3)) - -//# programmable --sender A --inputs object(2,4)@4 1 2 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1), Input(2), Input(3)) - - -// dev-inspect with 'check' and _incorrect_ values - -//# programmable --sender A --inputs object(2,4)@3 0 0 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1), Input(2), Input(3)) - -//# programmable --sender A --inputs object(2,4)@4 1 2 vector[3] --dev-inspect -//> test::m::check(Input(0), Input(1), Input(2), Input(3)) - -//# programmable --sender A --inputs object(2,4)@2 1 2 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1), Input(2), Input(3)) diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids.exp deleted file mode 100644 index 5f7a9c46ac9..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids.exp +++ /dev/null @@ -1,62 +0,0 @@ -processed 14 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-117: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 12205600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 119-121: -created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 15640800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 123-123: -Owner: Account Address ( A ) -Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,8)}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}]} - -task 4 'programmable'. lines 125-126: -mutated: object(0,0), object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8) -gas summary: computation_cost: 1000000, storage_cost: 15640800, storage_rebate: 15484392, non_refundable_storage_fee: 156408 - -task 5 'view-object'. lines 128-128: -Owner: Account Address ( A ) -Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,8)}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}]} - -task 6 'programmable'. lines 130-131: -mutated: object(0,0), object(2,8) -deleted: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7) -gas summary: computation_cost: 1000000, storage_cost: 3906400, storage_rebate: 15484392, non_refundable_storage_fee: 156408 - -task 7 'view-object'. lines 133-136: -Owner: Account Address ( A ) -Version: 4 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,8)}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}]} - -task 8 'programmable'. lines 138-139: -mutated: object(_), object(2,8) -gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 - -task 9 'programmable'. lines 141-142: -mutated: object(_), object(2,8) -gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 - -task 10 'programmable'. lines 144-148: -mutated: object(_), object(2,8) -gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 - -task 11 'programmable'. lines 150-151: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 12, function_name: Some("check_") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 12, function_name: Some("check_") }, 0) in command 0 - -task 12 'programmable'. lines 153-154: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 - -task 13 'programmable'. lines 156-157: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 20, function_name: Some("check_") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 10, instruction: 20, function_name: Some("check_") }, 0) in command 0 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids.move b/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids.move deleted file mode 100644 index b36dff06324..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids.move +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests finding UIDs for dynamic field access - -//# init --addresses test=0x0 --accounts A --protocol-version 16 - -//# publish - -module test::m { - use sui::dynamic_field as field; - - public struct S has key, store { - id: UID, - other: UID, - wrapped: Wrapped, - many: vector, - } - - public struct Wrapped has key, store { - id: UID, - other: UID, - } - - const KEY: u64 = 0; - - ////////////////////////////////////////////////////////////// - // new - - public fun new(ctx: &mut TxContext): S { - let mut s = S { - id: object::new(ctx), - other: object::new(ctx), - wrapped: wrapped(ctx), - many: vector[wrapped(ctx), wrapped(ctx)], - }; - field::add(&mut s.id, KEY, 0); - field::add(&mut s.other, KEY, 0); - s - } - - fun wrapped(ctx: &mut TxContext): Wrapped { - let mut w = Wrapped { - id: object::new(ctx), - other: object::new(ctx), - }; - field::add(&mut w.id, KEY, 0); - field::add(&mut w.other, KEY, 0); - w - } - - ////////////////////////////////////////////////////////////// - // set - - public fun set(s: &mut S, value: u64) { - set_(&mut s.id, value); - set_(&mut s.other, value); - set_wrapped(&mut s.wrapped, value); - set_wrapped(vector::borrow_mut(&mut s.many, 0), value); - set_wrapped(vector::borrow_mut(&mut s.many, 1), value); - } - - fun set_wrapped(w: &mut Wrapped, value: u64) { - set_(&mut w.id, value); - set_(&mut w.other, value); - - } - - fun set_(id: &mut UID, value: u64) { - *field::borrow_mut(id, KEY) = value; - } - - ////////////////////////////////////////////////////////////// - // remove - - public fun remove(s: &mut S) { - remove_(&mut s.id); - remove_(&mut s.other); - remove_wrapped(&mut s.wrapped); - remove_wrapped(vector::borrow_mut(&mut s.many, 0)); - remove_wrapped(vector::borrow_mut(&mut s.many, 1)); - } - - fun remove_wrapped(w: &mut Wrapped) { - remove_(&mut w.id); - remove_(&mut w.other); - } - - fun remove_(id: &mut UID) { - field::remove(id, KEY); - } - - ////////////////////////////////////////////////////////////// - // check - - public fun check(s: &S, expected: Option) { - check_(&s.id, expected); - check_(&s.other, expected); - check_wrapped(&s.wrapped, expected); - check_wrapped(vector::borrow(&s.many, 0), expected); - check_wrapped(vector::borrow(&s.many, 1), expected); - } - - fun check_wrapped(w: &Wrapped, expected: Option) { - check_(&w.id, expected); - check_(&w.other, expected); - } - - fun check_(id: &UID, expected: Option) { - if (option::is_some(&expected)) { - let f = field::borrow(id, KEY); - assert!(f == option::borrow(&expected), 0); - } else { - assert!(!field::exists_with_type(id, KEY), 0); - } - } -} - -//# programmable --sender A --inputs @A -//> 0: test::m::new(); -//> TransferObjects([Result(0)], Input(0)) - -//# view-object 2,8 - -//# programmable --sender A --inputs object(2,8) 112 -//> test::m::set(Input(0), Input(1)) - -//# view-object 2,8 - -//# programmable --sender A --inputs object(2,8) 112 -//> test::m::remove(Input(0)) - -//# view-object 2,8 - - -// dev-inspect with 'check' and correct values - -//# programmable --sender A --inputs object(2,8)@2 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@3 vector[112] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@4 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1)) - - -// dev-inspect with 'check' and _incorrect_ values - -//# programmable --sender A --inputs object(2,8)@3 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@4 vector[112] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@2 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1)) diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_dof.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_dof.exp deleted file mode 100644 index 873fe2ab489..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_dof.exp +++ /dev/null @@ -1,62 +0,0 @@ -processed 14 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-130: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 13353200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 132-134: -created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8), object(2,9), object(2,10), object(2,11), object(2,12), object(2,13), object(2,14), object(2,15), object(2,16) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 33941600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 136-136: -Owner: Account Address ( A ) -Version: 2 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,8)}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}]} - -task 4 'programmable'. lines 138-139: -mutated: object(0,0), object(2,8), object(2,9), object(2,10), object(2,11), object(2,12), object(2,13), object(2,14), object(2,15), object(2,16) -gas summary: computation_cost: 1000000, storage_cost: 14303200, storage_rebate: 14160168, non_refundable_storage_fee: 143032 - -task 5 'view-object'. lines 141-141: -Owner: Account Address ( A ) -Version: 3 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,8)}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}]} - -task 6 'programmable'. lines 143-144: -mutated: object(0,0), object(2,8) -deleted: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,9), object(2,10), object(2,11), object(2,12), object(2,13), object(2,14), object(2,15), object(2,16) -gas summary: computation_cost: 1000000, storage_cost: 3906400, storage_rebate: 33602184, non_refundable_storage_fee: 339416 - -task 7 'view-object'. lines 146-149: -Owner: Account Address ( A ) -Version: 4 -Contents: test::m::S {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,8)}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}, wrapped: test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, many: vector[test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}, test::m::Wrapped {id: sui::object::UID {id: sui::object::ID {bytes: _}}, other: sui::object::UID {id: sui::object::ID {bytes: _}}}]} - -task 8 'programmable'. lines 151-152: -mutated: object(_), object(2,8) -gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 - -task 9 'programmable'. lines 154-155: -mutated: object(_), object(2,8) -gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 - -task 10 'programmable'. lines 157-161: -mutated: object(_), object(2,8) -gas summary: computation_cost: 500000, storage_cost: 3906400, storage_rebate: 2889216, non_refundable_storage_fee: 29184 - -task 11 'programmable'. lines 163-164: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 18, function_name: Some("check_") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 18, function_name: Some("check_") }, 0) in command 0 - -task 12 'programmable'. lines 166-167: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 - -task 13 'programmable'. lines 169-170: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 26, function_name: Some("check_") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 11, instruction: 26, function_name: Some("check_") }, 0) in command 0 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_dof.move b/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_dof.move deleted file mode 100644 index afc084b6a07..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_dof.move +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests finding UIDs for dynamic object field access - -//# init --addresses test=0x0 --accounts A --protocol-version 16 - -//# publish - -module test::m { - use sui::dynamic_object_field as ofield; - - public struct S has key, store { - id: UID, - other: UID, - wrapped: Wrapped, - many: vector, - } - - public struct Wrapped has key, store { - id: UID, - other: UID, - } - - public struct Value has key, store { - id: UID, - value: u64, - } - - const KEY: u64 = 0; - - ////////////////////////////////////////////////////////////// - // new - - public fun new(ctx: &mut TxContext): S { - let mut s = S { - id: object::new(ctx), - other: object::new(ctx), - wrapped: wrapped(ctx), - many: vector[wrapped(ctx), wrapped(ctx)], - }; - ofield::add(&mut s.id, KEY, value(0, ctx)); - ofield::add(&mut s.other, KEY, value(0, ctx)); - s - } - - fun wrapped(ctx: &mut TxContext): Wrapped { - let mut w = Wrapped { - id: object::new(ctx), - other: object::new(ctx), - }; - ofield::add(&mut w.id, KEY, value(0, ctx)); - ofield::add(&mut w.other, KEY, value(0, ctx)); - w - } - - fun value(value: u64, ctx: &mut TxContext): Value { - Value { - id: object::new(ctx), - value - } - } - - ////////////////////////////////////////////////////////////// - // set - - public fun set(s: &mut S, value: u64) { - set_(&mut s.id, value); - set_(&mut s.other, value); - set_wrapped(&mut s.wrapped, value); - set_wrapped(vector::borrow_mut(&mut s.many, 0), value); - set_wrapped(vector::borrow_mut(&mut s.many, 1), value); - } - - fun set_wrapped(w: &mut Wrapped, value: u64) { - set_(&mut w.id, value); - set_(&mut w.other, value); - - } - - fun set_(id: &mut UID, value: u64) { - ofield::borrow_mut(id, KEY).value = value; - } - - ////////////////////////////////////////////////////////////// - // remove - - public fun remove(s: &mut S) { - remove_(&mut s.id); - remove_(&mut s.other); - remove_wrapped(&mut s.wrapped); - remove_wrapped(vector::borrow_mut(&mut s.many, 0)); - remove_wrapped(vector::borrow_mut(&mut s.many, 1)); - } - - fun remove_wrapped(w: &mut Wrapped) { - remove_(&mut w.id); - remove_(&mut w.other); - } - - fun remove_(id: &mut UID) { - let Value { id, value: _ } = ofield::remove(id, KEY); - object::delete(id); - } - - ////////////////////////////////////////////////////////////// - // check - - public fun check(s: &S, expected: Option) { - check_(&s.id, expected); - check_(&s.other, expected); - check_wrapped(&s.wrapped, expected); - check_wrapped(vector::borrow(&s.many, 0), expected); - check_wrapped(vector::borrow(&s.many, 1), expected); - } - - fun check_wrapped(w: &Wrapped, expected: Option) { - check_(&w.id, expected); - check_(&w.other, expected); - } - - fun check_(id: &UID, expected: Option) { - if (option::is_some(&expected)) { - let Value { id: _, value } = ofield::borrow(id, KEY); - assert!(value == option::borrow(&expected), 0); - } else { - assert!(!ofield::exists_with_type(id, KEY), 0); - } - } -} - -//# programmable --sender A --inputs @A -//> 0: test::m::new(); -//> TransferObjects([Result(0)], Input(0)) - -//# view-object 2,8 - -//# programmable --sender A --inputs object(2,8) 112 -//> test::m::set(Input(0), Input(1)) - -//# view-object 2,8 - -//# programmable --sender A --inputs object(2,8) 112 -//> test::m::remove(Input(0)) - -//# view-object 2,8 - - -// dev-inspect with 'check' and correct values - -//# programmable --sender A --inputs object(2,8)@2 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@3 vector[112] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@4 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1)) - - -// dev-inspect with 'check' and _incorrect_ values - -//# programmable --sender A --inputs object(2,8)@3 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@4 vector[112] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,8)@2 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1)) diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_on_child.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_on_child.exp deleted file mode 100644 index 0d5baf3992e..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_on_child.exp +++ /dev/null @@ -1,62 +0,0 @@ -processed 14 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-140: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 13862400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 142-144: -created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8), object(2,9) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 17609200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 146-146: -Owner: Account Address ( A ) -Version: 2 -Contents: test::m::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,9)}}} - -task 4 'programmable'. lines 148-149: -mutated: object(0,0), object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8), object(2,9) -gas summary: computation_cost: 1000000, storage_cost: 13968800, storage_rebate: 13829112, non_refundable_storage_fee: 139688 - -task 5 'view-object'. lines 151-151: -Owner: Account Address ( A ) -Version: 3 -Contents: test::m::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,9)}}} - -task 6 'programmable'. lines 153-154: -mutated: object(0,0), object(2,9) -deleted: object(2,1), object(2,2), object(2,3), object(2,4), object(2,5), object(2,6), object(2,7), object(2,8) -gas summary: computation_cost: 1000000, storage_cost: 2234400, storage_rebate: 13829112, non_refundable_storage_fee: 139688 - -task 7 'view-object'. lines 156-159: -Owner: Account Address ( A ) -Version: 4 -Contents: test::m::Parent {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,9)}}} - -task 8 'programmable'. lines 161-162: -mutated: object(_), object(2,9) -gas summary: computation_cost: 500000, storage_cost: 2234400, storage_rebate: 1233936, non_refundable_storage_fee: 12464 - -task 9 'programmable'. lines 164-165: -mutated: object(_), object(2,9) -gas summary: computation_cost: 500000, storage_cost: 2234400, storage_rebate: 1233936, non_refundable_storage_fee: 12464 - -task 10 'programmable'. lines 167-171: -mutated: object(_), object(2,9) -gas summary: computation_cost: 500000, storage_cost: 2234400, storage_rebate: 1233936, non_refundable_storage_fee: 12464 - -task 11 'programmable'. lines 173-174: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 12, function_name: Some("check_") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 12, function_name: Some("check_") }, 0) in command 0 - -task 12 'programmable'. lines 176-177: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 11, instruction: 0, function_name: Some("borrow_child_object") }, 1) in command 0 - -task 13 'programmable'. lines 179-180: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 20, function_name: Some("check_") }, 0) in command 0 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 14, instruction: 20, function_name: Some("check_") }, 0) in command 0 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_on_child.move b/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_on_child.move deleted file mode 100644 index 23409db9375..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/find_all_uids_on_child.move +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests finding UIDs for dynamic field access on a child object (non-input) - -//# init --addresses test=0x0 --accounts A --protocol-version 16 - -//# publish - -module test::m { - use sui::dynamic_field as field; - - public struct Parent has key, store { - id: UID, - } - - public struct S has key, store { - id: UID, - other: UID, - wrapped: Wrapped, - many: vector, - } - - public struct Wrapped has key, store { - id: UID, - other: UID, - } - - const KEY: u64 = 0; - - ////////////////////////////////////////////////////////////// - // new - - public fun new(ctx: &mut TxContext): Parent { - let mut parent = Parent { id: object::new(ctx) }; - field::add(&mut parent.id, KEY, s(ctx)); - parent - } - - fun s(ctx: &mut TxContext): S { - let mut s = S { - id: object::new(ctx), - other: object::new(ctx), - wrapped: wrapped(ctx), - many: vector[wrapped(ctx), wrapped(ctx)], - }; - field::add(&mut s.id, KEY, 0); - field::add(&mut s.other, KEY, 0); - s - } - - fun wrapped(ctx: &mut TxContext): Wrapped { - let mut w = Wrapped { - id: object::new(ctx), - other: object::new(ctx), - }; - field::add(&mut w.id, KEY, 0); - field::add(&mut w.other, KEY, 0); - w - } - - ////////////////////////////////////////////////////////////// - // set - - public fun set(parent: &mut Parent, value: u64) { - set_s(field::borrow_mut(&mut parent.id, KEY), value); - } - - - fun set_s(s: &mut S, value: u64) { - set_(&mut s.id, value); - set_(&mut s.other, value); - set_wrapped(&mut s.wrapped, value); - set_wrapped(vector::borrow_mut(&mut s.many, 0), value); - set_wrapped(vector::borrow_mut(&mut s.many, 1), value); - } - - fun set_wrapped(w: &mut Wrapped, value: u64) { - set_(&mut w.id, value); - set_(&mut w.other, value); - - } - - fun set_(id: &mut UID, value: u64) { - *field::borrow_mut(id, KEY) = value; - } - - ////////////////////////////////////////////////////////////// - // remove - - public fun remove(parent: &mut Parent) { - remove_s(field::borrow_mut(&mut parent.id, KEY)); - } - - fun remove_s(s: &mut S) { - remove_(&mut s.id); - remove_(&mut s.other); - remove_wrapped(&mut s.wrapped); - remove_wrapped(vector::borrow_mut(&mut s.many, 0)); - remove_wrapped(vector::borrow_mut(&mut s.many, 1)); - } - - fun remove_wrapped(w: &mut Wrapped) { - remove_(&mut w.id); - remove_(&mut w.other); - } - - fun remove_(id: &mut UID) { - field::remove(id, KEY); - } - - ////////////////////////////////////////////////////////////// - // check - - public fun check(parent: &Parent, expected: Option) { - check_s(field::borrow(&parent.id, KEY), expected); - } - - fun check_s(s: &S, expected: Option) { - check_(&s.id, expected); - check_(&s.other, expected); - check_wrapped(&s.wrapped, expected); - check_wrapped(vector::borrow(&s.many, 0), expected); - check_wrapped(vector::borrow(&s.many, 1), expected); - } - - fun check_wrapped(w: &Wrapped, expected: Option) { - check_(&w.id, expected); - check_(&w.other, expected); - } - - fun check_(id: &UID, expected: Option) { - if (option::is_some(&expected)) { - let f = field::borrow(id, KEY); - assert!(f == option::borrow(&expected), 0); - } else { - assert!(!field::exists_with_type(id, KEY), 0); - } - } -} - -//# programmable --sender A --inputs @A -//> 0: test::m::new(); -//> TransferObjects([Result(0)], Input(0)) - -//# view-object 2,9 - -//# programmable --sender A --inputs object(2,9) 112 -//> test::m::set(Input(0), Input(1)) - -//# view-object 2,9 - -//# programmable --sender A --inputs object(2,9) 112 -//> test::m::remove(Input(0)) - -//# view-object 2,9 - - -// dev-inspect with 'check' and correct values - -//# programmable --sender A --inputs object(2,9)@2 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,9)@3 vector[112] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,9)@4 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1)) - - -// dev-inspect with 'check' and _incorrect_ values - -//# programmable --sender A --inputs object(2,9)@3 vector[0] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,9)@4 vector[112] --dev-inspect -//> test::m::check(Input(0), Input(1)) - -//# programmable --sender A --inputs object(2,9)@2 vector[] --dev-inspect -//> test::m::check(Input(0), Input(1)) diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/middle_version_less_than_child.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/v0/middle_version_less_than_child.exp deleted file mode 100644 index b4503102371..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/middle_version_less_than_child.exp +++ /dev/null @@ -1,52 +0,0 @@ -processed 11 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-51: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 7493600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 53-57: -created: object(2,0), object(2,1), object(2,2) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 6285200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 59-59: -Owner: Object ID: ( _ ) -Version: 2 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, name: 0u64, value: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: _}}, value: 0u64}} - -task 4 'view-object'. lines 61-61: -Owner: Object ID: ( fake(2,2) ) -Version: 2 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, name: 0u64, value: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: _}}, value: 0u64}} - -task 5 'view-object'. lines 63-63: -Owner: Account Address ( A ) -Version: 2 -Contents: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}, value: 0u64} - -task 6 'programmable'. lines 65-68: -mutated: object(0,0), object(2,0), object(2,2) -gas summary: computation_cost: 1000000, storage_cost: 4278800, storage_rebate: 4236012, non_refundable_storage_fee: 42788 - -task 7 'view-object'. lines 70-70: -Owner: Object ID: ( _ ) -Version: 3 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, name: 0u64, value: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: _}}, value: 112u64}} - -task 8 'view-object'. lines 72-72: -Owner: Object ID: ( fake(2,2) ) -Version: 2 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, name: 0u64, value: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: _}}, value: 0u64}} - -task 9 'view-object'. lines 74-77: -Owner: Account Address ( A ) -Version: 3 -Contents: test::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}, value: 0u64} - -task 10 'programmable'. lines 79-80: -mutated: object(0,0), object(2,2) -gas summary: computation_cost: 1000000, storage_cost: 2272400, storage_rebate: 2249676, non_refundable_storage_fee: 22724 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/middle_version_less_than_child.move b/crates/sui-adapter-transactional-tests/tests/mvcc/v0/middle_version_less_than_child.move deleted file mode 100644 index 2d9f004c29b..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/middle_version_less_than_child.move +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests accessing the versions of a child of a child - -//# init --addresses test=0x0 --accounts A --protocol-version 16 - -//# publish - -module test::m { - use sui::dynamic_field as field; - - public struct Obj has key, store { - id: UID, - value: u64, - } - - const KEY: u64 = 0; - - ////////////////////////////////////////////////////////////// - // new - - public fun new(ctx: &mut TxContext): Obj { - let mut grand = Obj { id: object::new(ctx), value: 0 }; - let mut parent = Obj { id: object::new(ctx), value: 0 }; - let child = Obj { id: object::new(ctx), value: 0 }; - field::add(&mut parent.id, KEY, child); - field::add(&mut grand.id, KEY, parent); - grand - } - - ////////////////////////////////////////////////////////////// - // set - - public fun set(grand: &mut Obj, v: u64) { - let parent: &mut Obj = field::borrow_mut(&mut grand.id, KEY); - let child: &mut Obj = field::borrow_mut(&mut parent.id, KEY); - child.value = v; - } - - ////////////////////////////////////////////////////////////// - // check - - public fun check(grand: &Obj, expected: u64) { - assert!(grand.value == 0, 0); - let parent: &Obj = field::borrow(&grand.id, KEY); - assert!(parent.value == 0, 0); - let child: &Obj = field::borrow(&parent.id, KEY); - assert!(child.value == expected, 0); - } -} - -//# programmable --sender A --inputs @A -//> 0: test::m::new(); -//> TransferObjects([Result(0)], Input(0)) - -// All 3 objects have version 2 - -//# view-object 2,0 - -//# view-object 2,1 - -//# view-object 2,2 - -//# programmable --sender A --inputs object(2,2) 112 -//> test::m::set(Input(0), Input(1)) - -// The middle object has version 2, while the root and modified leaf have version 3 - -//# view-object 2,0 - -//# view-object 2,1 - -//# view-object 2,2 - -// correctly load the leaf even though it has a version greater than its immediate -// parent - -//# programmable --sender A --inputs object(2,2) 112 -//> test::m::check(Input(0), Input(1)) diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/not_root_version.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/v0/not_root_version.exp deleted file mode 100644 index 597d38e9f90..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/not_root_version.exp +++ /dev/null @@ -1,66 +0,0 @@ -processed 14 tasks - -init: -P1: object(0,0), P2: object(0,1) - -task 1 'publish'. lines 8-53: -created: object(1,0) -mutated: object(0,2) -gas summary: computation_cost: 1000000, storage_cost: 7432800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 55-57: -created: object(2,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'programmable'. lines 59-60: -mutated: object(0,0), object(2,0) -gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 2174436, non_refundable_storage_fee: 21964 - -task 4 'programmable'. lines 62-63: -mutated: object(0,0), object(2,0) -gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 2174436, non_refundable_storage_fee: 21964 - -task 5 'view-object'. lines 65-68: -Owner: Account Address ( P1 ) -Version: 4 -Contents: test::m::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 6 'programmable'. lines 70-72: -created: object(6,0), object(6,1) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 7 'view-object'. lines 74-74: -Owner: Object ID: ( fake(6,1) ) -Version: 2 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}, name: 0u64, value: 0u64} - -task 8 'programmable'. lines 76-77: -mutated: object(0,1), object(6,0), object(6,1) -gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 3626568, non_refundable_storage_fee: 36632 - -task 9 'view-object'. lines 79-83: -Owner: Object ID: ( fake(6,1) ) -Version: 3 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}, name: 0u64, value: 1u64} - -task 10 'programmable'. lines 85-90: -created: object(10,0) -mutated: object(_), object(2,0) -wrapped: object(6,1) -gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 - -task 11 'programmable'. lines 92-96: -created: object(10,0) -mutated: object(_), object(2,0) -wrapped: object(6,1) -gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 - -task 12 'programmable'. lines 98-102: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 - -task 13 'programmable'. lines 104-106: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/not_root_version.move b/crates/sui-adapter-transactional-tests/tests/mvcc/v0/not_root_version.move deleted file mode 100644 index 2dd50754bc1..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/not_root_version.move +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests accessing version of the input parent, not the runtime parent - -//# init --addresses test=0x0 --accounts P1 P2 --protocol-version 16 - -//# publish - -module test::m { - use sui::dynamic_field as field; - - public struct A has key, store { - id: UID, - } - - public struct B has key, store { - id: UID, - } - - const KEY: u64 = 0; - - public fun a(ctx: &mut TxContext): A { - A { id: object::new(ctx) } - } - - public fun b(ctx: &mut TxContext): B { - let mut b = B { id: object::new(ctx) }; - field::add(&mut b.id, KEY, 0); - b - - } - - public fun bump(b: &mut B) { - let f = field::borrow_mut(&mut b.id, KEY); - *f = *f + 1; - } - - public fun append(a: &mut A, b: B) { - field::add(&mut a.id, KEY, b); - } - - public fun check(a: &A, expected: u64) { - let b: &B = field::borrow(&a.id, KEY); - let v = *field::borrow(&b.id, KEY); - assert!(v == expected, 0); - } - - public fun nop() { - } -} - -// Create object A and bump the version to 4 - -//# programmable --sender P1 --inputs @P1 -//> 0: test::m::a(); -//> TransferObjects([Result(0)], Input(0)) - -//# programmable --sender P1 --inputs object(2,0) -//> test::m::nop(); - -//# programmable --sender P1 --inputs object(2,0) -//> test::m::nop(); - -//# view-object 2,0 - - -// Create object B witha version 2 and 3 for it's dynamic field - -//# programmable --sender P2 --inputs @P2 -//> 0: test::m::b(); -//> TransferObjects([Result(0)], Input(0)) - -//# view-object 6,0 - -//# programmable --sender P2 --inputs object(6,1) -//> 0: test::m::bump(Input(0)); - -//# view-object 6,0 - - -// Append object B to object A, but using version 2 of object B. And ensure that -// when we later read the dynamic field of object B, we get the version 2 value. - -//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@2 0 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); - -// checking that with version 3 we get the other value, then flip them to ensure -// they abort - -//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@3 1 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); - -// @2 with value 1 aborts - -//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@2 1 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); - -// @3 with value 0 aborts - -//# programmable --sender P2 --inputs object(2,0)@4 object(6,1)@3 0 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/not_root_version_flipped_case.exp b/crates/sui-adapter-transactional-tests/tests/mvcc/v0/not_root_version_flipped_case.exp deleted file mode 100644 index 296e99efa56..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/not_root_version_flipped_case.exp +++ /dev/null @@ -1,58 +0,0 @@ -processed 12 tasks - -init: -P1: object(0,0), P2: object(0,1) - -task 1 'publish'. lines 8-53: -created: object(1,0) -mutated: object(0,2) -gas summary: computation_cost: 1000000, storage_cost: 7432800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 55-57: -created: object(2,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 60-63: -Owner: Account Address ( P1 ) -Version: 2 -Contents: test::m::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 4 'programmable'. lines 65-67: -created: object(4,0), object(4,1) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 5 'view-object'. lines 69-69: -Owner: Object ID: ( fake(4,1) ) -Version: 2 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(4,0)}}, name: 0u64, value: 0u64} - -task 6 'programmable'. lines 71-72: -mutated: object(0,1), object(4,0), object(4,1) -gas summary: computation_cost: 1000000, storage_cost: 3663200, storage_rebate: 3626568, non_refundable_storage_fee: 36632 - -task 7 'view-object'. lines 74-77: -Owner: Object ID: ( fake(4,1) ) -Version: 3 -Contents: sui::dynamic_field::Field {id: sui::object::UID {id: sui::object::ID {bytes: fake(4,0)}}, name: 0u64, value: 1u64} - -task 8 'programmable'. lines 79-84: -created: object(8,0) -mutated: object(_), object(2,0) -wrapped: object(4,1) -gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 - -task 9 'programmable'. lines 86-90: -created: object(8,0) -mutated: object(_), object(2,0) -wrapped: object(4,1) -gas summary: computation_cost: 500000, storage_cost: 4126800, storage_rebate: 2392632, non_refundable_storage_fee: 24168 - -task 10 'programmable'. lines 92-96: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 - -task 11 'programmable'. lines 98-100: -Error: Transaction Effects Status: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 -Execution Error: MoveAbort(MoveLocation { module: ModuleId { address: test, name: Identifier("m") }, function: 4, instruction: 13, function_name: Some("check") }, 0) in command 1 diff --git a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/not_root_version_flipped_case.move b/crates/sui-adapter-transactional-tests/tests/mvcc/v0/not_root_version_flipped_case.move deleted file mode 100644 index 297de04e016..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/mvcc/v0/not_root_version_flipped_case.move +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests accessing version of the input parent, not the runtime parent - -//# init --addresses test=0x0 --accounts P1 P2 --protocol-version 16 - -//# publish - -module test::m { - use sui::dynamic_field as field; - - public struct A has key, store { - id: UID, - } - - public struct B has key, store { - id: UID, - } - - const KEY: u64 = 0; - - public fun a(ctx: &mut TxContext): A { - A { id: object::new(ctx) } - } - - public fun b(ctx: &mut TxContext): B { - let mut b = B { id: object::new(ctx) }; - field::add(&mut b.id, KEY, 0); - b - - } - - public fun bump(b: &mut B) { - let f = field::borrow_mut(&mut b.id, KEY); - *f = *f + 1; - } - - public fun append(a: &mut A, b: B) { - field::add(&mut a.id, KEY, b); - } - - public fun check(a: &A, expected: u64) { - let b: &B = field::borrow(&a.id, KEY); - let v = *field::borrow(&b.id, KEY); - assert!(v == expected, 0); - } - - public fun nop() { - } -} - -// Create object A at version 2 - -//# programmable --sender P1 --inputs @P1 -//> 0: test::m::a(); -//> TransferObjects([Result(0)], Input(0)) - - -//# view-object 2,0 - - -// Create object B with a version 2 and 3 for it's dynamic field - -//# programmable --sender P2 --inputs @P2 -//> 0: test::m::b(); -//> TransferObjects([Result(0)], Input(0)) - -//# view-object 4,0 - -//# programmable --sender P2 --inputs object(4,1) -//> 0: test::m::bump(Input(0)); - -//# view-object 4,0 - -// Append object B to object A. And ensure that when we later read the dynamic -// field of object B, we get the most recent version. - -//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@3 1 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); - -// checking that with version 3 we get the other value, then flip them to ensure -// they abort - -//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@2 0 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); - -// @2 with value 1 aborts - -//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@2 1 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); - -// @3 with value 0 aborts - -//# programmable --sender P2 --inputs object(2,0)@2 object(4,1)@3 0 --dev-inspect -//> 0: test::m::append(Input(0), Input(1)); -//> 1: test::m::check(Input(0), Input(2)); diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_emit.move b/crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_emit.move deleted file mode 100644 index f062a862e88..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_emit.move +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests cannot call init with programmable transactions - -//# init --addresses test=0x0 --accounts A - -//# publish -module test::m1 { - public struct A has copy, drop, store {} - public fun a(): A { A {} } -} - -//# programmable -//> 0: test::m1::a(); -//> sui::event::emit(Result(0)); - -//# programmable -//> 0: test::m1::a(); -// wrong type annotation doesn't matter -//> sui::event::emit(Result(0)); - -//# programmable -//> 0: test::m1::a(); -// function doesn't exist -//> sui::event::does_not_exist(Result(0)); diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_init.move b/crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_init.move deleted file mode 100644 index 55709fe3f57..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_init.move +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests cannot call init with programmable transactions - -//# init --addresses test=0x0 --accounts A - -//# publish -module test::m1 { - fun init(_: &mut sui::tx_context::TxContext) {} -} - -//# programmable -//> 0: test::m1::init(); diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_private.move b/crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_private.move deleted file mode 100644 index 8138e561813..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable/cannot_call_private.move +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests cannot call private with programmable transactions - -//# init --addresses test=0x0 --accounts A - -//# publish -module test::m1 { - fun priv(_: &mut sui::tx_context::TxContext) {} -} - -//# programmable -//> 0: test::m1::priv(); diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/coin_overflow.exp b/crates/sui-adapter-transactional-tests/tests/programmable/coin_overflow.exp deleted file mode 100644 index 346c811f62a..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable/coin_overflow.exp +++ /dev/null @@ -1,22 +0,0 @@ -processed 5 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-20: -created: object(1,0), object(1,1), object(1,2) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 10617200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 22-24: -created: object(2,0) -mutated: object(0,0), object(1,2) -gas summary: computation_cost: 1000000, storage_cost: 4012800, storage_rebate: 2663496, non_refundable_storage_fee: 26904 - -task 3 'programmable'. lines 26-28: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::balance::increase_supply (function index 3) at offset 12, Abort Code: 1 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("balance") }, function: 3, instruction: 12, function_name: Some("increase_supply") }, 1), source: Some(VMError { major_status: ABORTED, sub_status: Some(1), message: Some("sui::balance::increase_supply at offset 12"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("balance") }), indices: [], offsets: [(FunctionDefinitionIndex(3), 12)] }), command: Some(0) } } - -task 4 'programmable'. lines 30-31: -Error: Transaction Effects Status: Invalid command argument at 1. Invalid usage of value. Mutably borrowed values require unique usage. Immutably borrowed values cannot be taken or borrowed mutably. Taken values cannot be used again. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: CommandArgumentError { arg_idx: 1, kind: InvalidValueUsage }, source: None, command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/delayed_invalid_gas_by_value.move b/crates/sui-adapter-transactional-tests/tests/programmable/delayed_invalid_gas_by_value.move deleted file mode 100644 index 8f7dc46ead1..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable/delayed_invalid_gas_by_value.move +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests that gas-by-value rules come after taken/borrow rules - -//# init --addresses test=0x0 --accounts A - -//# publish -module test::m1 { - public fun take(_: T) { abort 0 } - public fun imm(_: &T, _: T) { abort 0 } - public fun mut_(_: &mut T, _: T) { abort 0 } -} - -//# programmable --sender A --inputs @A -//> TransferObjects([Gas], Input(0)); -//> test::m1::take>(Gas) - -//# programmable -//> test::m1::imm>(Gas, Gas) - -//# programmable -//> test::m1::mut_>(Gas, Gas) diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_reference.move b/crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_reference.move deleted file mode 100644 index d594e25e53e..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_reference.move +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests valid gas coin usage by reference - -//# init --addresses test=0x0 --accounts A - -//# publish -module test::m1 { - public entry fun t1(_: &T) { - } - public fun t2(_: &T) { - } - entry fun t3(_: &T) { - } - public entry fun t4(_: &mut T) { - } - public fun t5(_: &mut T) { - } - entry fun t6(_: &mut T) { - } -} - -// can pass to Move function by ref -//# programmable --sender A -//> test::m1::t1>(Gas) - -//# programmable --sender A -//> test::m1::t2>(Gas) - -//# programmable --sender A -//> test::m1::t2>(Gas) - -//# programmable --sender A -//> test::m1::t4>(Gas) - -//# programmable --sender A -//> test::m1::t5>(Gas) - -//# programmable --sender A -//> test::m1::t6>(Gas) - -// can pass to merge and split -//# programmable --sender A --inputs 10 --gas-budget 10000000000 -//> 0: SplitCoins(Gas, [Input(0)]); -//> MergeCoins(Gas, [Result(0)]) diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_value.exp b/crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_value.exp deleted file mode 100644 index 313a5a5eba8..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable/gas_coin_by_value.exp +++ /dev/null @@ -1,13 +0,0 @@ -processed 3 tasks - -init: -A: object(0,0), B: object(0,1) - -task 1 'programmable'. lines 8-9: -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'view-object'. lines 11-11: -Owner: Account Address ( B ) -Version: 2 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(0,0)}}, balance: sui::balance::Balance {value: 299999998012000u64}} diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_transfer_invalid.exp b/crates/sui-adapter-transactional-tests/tests/programmable/private_transfer_invalid.exp deleted file mode 100644 index 78878d8f9b6..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable/private_transfer_invalid.exp +++ /dev/null @@ -1,45 +0,0 @@ -processed 11 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-17: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 5228800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 19-21: -Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call sui::transfer::transfer. Use the public variant instead, sui::transfer::public_transfer"), command: Some(1) } } - -task 3 'programmable'. lines 23-25: -Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call sui::transfer::share_object. Use the public variant instead, sui::transfer::public_share_object"), command: Some(1) } } - -task 4 'programmable'. lines 27-32: -Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call sui::transfer::freeze_object. Use the public variant instead, sui::transfer::public_freeze_object"), command: Some(1) } } - -task 5 'programmable'. lines 34-36: -Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call sui::transfer::transfer. Use the public variant instead, sui::transfer::public_transfer"), command: Some(1) } } - -task 6 'programmable'. lines 38-40: -Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call sui::transfer::share_object. Use the public variant instead, sui::transfer::public_share_object"), command: Some(1) } } - -task 7 'programmable'. lines 42-47: -Error: Transaction Effects Status: Non Entry Function Invoked. Move Call must start with an entry function -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: NonEntryFunctionInvoked, source: Some("Cannot directly call sui::transfer::freeze_object. Use the public variant instead, sui::transfer::public_freeze_object"), command: Some(1) } } - -task 8 'programmable'. lines 49-51: -Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: CONSTRAINT_NOT_SATISFIED, sub_status: None, message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [] }), command: Some(1) } } - -task 9 'programmable'. lines 53-55: -Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: CONSTRAINT_NOT_SATISFIED, sub_status: None, message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [] }), command: Some(1) } } - -task 10 'programmable'. lines 57-59: -Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: CONSTRAINT_NOT_SATISFIED, sub_status: None, message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [] }), command: Some(1) } } diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_transfer_invalid.move b/crates/sui-adapter-transactional-tests/tests/programmable/private_transfer_invalid.move deleted file mode 100644 index e3d643cd6ed..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable/private_transfer_invalid.move +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests calling public transfer functions - -//# init --addresses test=0x0 --accounts A - -//# publish -module test::m1 { - public struct Pub has key, store { id: UID } - public fun pub(ctx: &mut TxContext): Pub { Pub { id: object::new(ctx) } } - - public struct Priv has key { id: UID } - public fun priv(ctx: &mut TxContext): Priv { Priv { id: object::new(ctx) } } -} - -// Has store, but cannot be used with internal variants - -//# programmable --sender A --inputs @A -//> 0: test::m1::pub(); -//> sui::transfer::transfer(Result(0), Input(0)); - -//# programmable -//> 0: test::m1::pub(); -//> sui::transfer::share_object(Result(0)); - -//# programmable -//> 0: test::m1::pub(); -//> sui::transfer::freeze_object(Result(0)); - - -// Does not have store, cannot be used with internal variants - -//# programmable --sender A --inputs @A -//> 0: test::m1::priv(); -//> sui::transfer::transfer(Result(0), Input(0)); - -//# programmable -//> 0: test::m1::priv(); -//> sui::transfer::share_object(Result(0)); - -//# programmable -//> 0: test::m1::priv(); -//> sui::transfer::freeze_object(Result(0)); - - -// Does not have store, cannot be used with public variants - -//# programmable --sender A --inputs @A -//> 0: test::m1::priv(); -//> sui::transfer::public_transfer(Result(0), Input(0)); - -//# programmable -//> 0: test::m1::priv(); -//> sui::transfer::public_share_object(Result(0)); - -//# programmable -//> 0: test::m1::priv(); -//> sui::transfer::public_freeze_object(Result(0)); diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/private_transfer_valid.move b/crates/sui-adapter-transactional-tests/tests/programmable/private_transfer_valid.move deleted file mode 100644 index ba35b430219..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable/private_transfer_valid.move +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests calling public transfer functions - -//# init --addresses test=0x0 --accounts A - -//# publish -module test::m1 { - public struct Pub has key, store { id: UID } - public fun pub(ctx: &mut TxContext): Pub { Pub { id: object::new(ctx) } } -} - -//# programmable --sender A --inputs @A -//> 0: test::m1::pub(); -//> sui::transfer::public_transfer(Result(0), Input(0)); - -//# view-object 2,0 - -//# programmable -//> 0: test::m1::pub(); -//> sui::transfer::public_share_object(Result(0)); - -//# view-object 4,0 - -//# programmable -//> 0: test::m1::pub(); -//> sui::transfer::public_freeze_object(Result(0)); - -//# view-object 6,0 diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/split_coins.exp b/crates/sui-adapter-transactional-tests/tests/programmable/split_coins.exp deleted file mode 100644 index 6a20f61f069..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable/split_coins.exp +++ /dev/null @@ -1,99 +0,0 @@ -processed 20 tasks - -init: -A: object(0,0), B: object(0,1) - -task 1 'publish'. lines 9-24: -created: object(1,0) -mutated: object(0,2) -gas summary: computation_cost: 1000000, storage_cost: 5403600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 26-30: -created: object(2,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'run'. lines 31-31: -created: object(3,0) -mutated: object(0,0), object(2,0) -gas summary: computation_cost: 1000000, storage_cost: 2964000, storage_rebate: 1956240, non_refundable_storage_fee: 19760 - -task 4 'view-object'. lines 33-35: -Owner: Account Address ( A ) -Version: 3 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, balance: sui::balance::Balance {value: 1000u64}} - -task 5 'programmable'. lines 36-38: -created: object(5,0) -mutated: object(0,0), object(3,0) -gas summary: computation_cost: 1000000, storage_cost: 2964000, storage_rebate: 1956240, non_refundable_storage_fee: 19760 - -task 6 'view-object'. lines 40-40: -Owner: Account Address ( A ) -Version: 4 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, balance: sui::balance::Balance {value: 900u64}} - -task 7 'view-object'. lines 42-45: -Owner: Account Address ( B ) -Version: 4 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(5,0)}}, balance: sui::balance::Balance {value: 100u64}} - -task 8 'programmable'. lines 46-48: -created: object(8,0), object(8,1) -mutated: object(0,0), object(3,0) -gas summary: computation_cost: 1000000, storage_cost: 3952000, storage_rebate: 1956240, non_refundable_storage_fee: 19760 - -task 9 'view-object'. lines 50-50: -Owner: Account Address ( A ) -Version: 5 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, balance: sui::balance::Balance {value: 700u64}} - -task 10 'view-object'. lines 52-52: -Owner: Account Address ( B ) -Version: 5 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(8,0)}}, balance: sui::balance::Balance {value: 100u64}} - -task 11 'view-object'. lines 54-56: -Owner: Account Address ( B ) -Version: 5 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(8,1)}}, balance: sui::balance::Balance {value: 100u64}} - -task 12 'programmable'. lines 57-60: -created: object(12,0), object(12,1) -mutated: object(0,0), object(3,0) -gas summary: computation_cost: 1000000, storage_cost: 3952000, storage_rebate: 1956240, non_refundable_storage_fee: 19760 - -task 13 'view-object'. lines 62-62: -Owner: Account Address ( A ) -Version: 6 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, balance: sui::balance::Balance {value: 500u64}} - -task 14 'view-object'. lines 64-64: -Owner: Account Address ( B ) -Version: 6 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(12,0)}}, balance: sui::balance::Balance {value: 100u64}} - -task 15 'view-object'. lines 66-69: -Owner: Account Address ( B ) -Version: 6 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(12,1)}}, balance: sui::balance::Balance {value: 100u64}} - -task 16 'programmable'. lines 70-74: -created: object(16,0), object(16,1) -mutated: object(0,0), object(3,0) -gas summary: computation_cost: 1000000, storage_cost: 3952000, storage_rebate: 1956240, non_refundable_storage_fee: 19760 - -task 17 'view-object'. lines 76-76: -Owner: Account Address ( A ) -Version: 7 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, balance: sui::balance::Balance {value: 300u64}} - -task 18 'view-object'. lines 78-78: -Owner: Account Address ( B ) -Version: 7 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(16,0)}}, balance: sui::balance::Balance {value: 100u64}} - -task 19 'view-object'. lines 80-80: -Owner: Account Address ( B ) -Version: 7 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(16,1)}}, balance: sui::balance::Balance {value: 100u64}} diff --git a/crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects.exp b/crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects.exp deleted file mode 100644 index 5f56f6052ec..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable/transfer_objects.exp +++ /dev/null @@ -1,59 +0,0 @@ -processed 12 tasks - -init: -A: object(0,0), B: object(0,1) - -task 1 'publish'. lines 8-32: -created: object(1,0) -mutated: object(0,2) -gas summary: computation_cost: 1000000, storage_cost: 6004000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 33-35: -created: object(2,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2280000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 37-39: -Owner: Account Address ( A ) -Version: 2 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(0,0)}}, balance: sui::balance::Balance {value: 299999996720000u64}} - -task 4 'programmable'. lines 40-43: -created: object(4,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2280000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 5 'view-object'. lines 45-47: -Owner: Account Address ( _ ) -Version: 3 -Contents: test::m1::Pub {id: sui::object::UID {id: sui::object::ID {bytes: fake(4,0)}}, value: 112u64} - -task 6 'programmable'. lines 48-53: -created: object(6,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2280000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 7 'view-object'. lines 55-57: -Owner: Account Address ( B ) -Version: 4 -Contents: test::m1::Pub {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}, value: 112u64} - -task 8 'programmable'. lines 58-65: -created: object(8,0), object(8,1), object(8,2) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5388400, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 9 'view-object'. lines 67-67: -Owner: Account Address ( B ) -Version: 5 -Contents: test::m1::Cup {id: sui::object::UID {id: sui::object::ID {bytes: fake(8,0)}}} - -task 10 'view-object'. lines 69-69: -Owner: Account Address ( B ) -Version: 5 -Contents: test::m1::Cup {id: sui::object::UID {id: sui::object::ID {bytes: fake(8,1)}}} - -task 11 'view-object'. lines 71-71: -Owner: Account Address ( B ) -Version: 5 -Contents: test::m1::Pub {id: sui::object::UID {id: sui::object::ID {bytes: fake(8,2)}}, value: 112u64} diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/coin_limit.exp b/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/coin_limit.exp deleted file mode 100644 index 59b9bbf2d8e..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/coin_limit.exp +++ /dev/null @@ -1,53 +0,0 @@ -processed 11 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 6-25: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 6650000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'programmable'. lines 26-29: -created: object(2,0), object(2,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 3260400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 31-31: -Owner: Account Address ( _ ) -Version: 2 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, balance: sui::balance::Balance {value: 100u64}} - -task 4 'view-object'. lines 33-35: -Owner: Account Address ( A ) -Version: 2 -Contents: test::m1::CoolMarker {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 5 'programmable'. lines 36-41: -Error: Transaction Effects Status: Unused result without the drop ability. Command result 1, return value 0 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: UnusedValueWithoutDrop { result_idx: 1, secondary_idx: 0 }, source: None, command: None } } - -task 6 'programmable'. lines 42-47: -created: object(6,0), object(6,1), object(6,2), object(6,3) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5532800, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 7 'view-object'. lines 49-49: -Owner: Account Address ( _ ) -Version: 4 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}, balance: sui::balance::Balance {value: 100u64}} - -task 8 'view-object'. lines 51-51: -Owner: Account Address ( _ ) -Version: 4 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,1)}}, balance: sui::balance::Balance {value: 100u64}} - -task 9 'view-object'. lines 53-53: -Owner: Account Address ( A ) -Version: 4 -Contents: test::m1::CoolMarker {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,2)}}} - -task 10 'view-object'. lines 55-55: -Owner: Account Address ( A ) -Version: 4 -Contents: test::m1::CoolMarker {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,3)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared_real_coin.move b/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared_real_coin.move deleted file mode 100644 index eee60a4eb43..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/merge_coin_shared_real_coin.move +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// test valid usages of shared coin - -//# init --addresses test=0x0 --accounts A --shared-object-deletion true - -//# publish - -module test::m1 { - use sui::sui::SUI; - use sui::coin; - - public fun mint_shared(ctx: &mut TxContext) { - transfer::public_share_object(coin::zero(ctx)) - } -} - -//# run test::m1::mint_shared - -//# view-object 2,0 - -//# programmable --sender A --inputs object(2,0) -//> MergeCoins(Gas, [Input(0)]) diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/publish.move b/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/publish.move deleted file mode 100644 index 4480478bf03..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/publish.move +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// simple test of publish - -//# init --addresses p=0x0 q=0x0 r=0x0 --accounts A - -//# stage-package -module p::m { - public fun foo(x: u64) { - p::n::bar(x) - } -} -module p::n { - public fun bar(x: u64) { - assert!(x == 0, 0); - } -} - - -//# stage-package -module q::m { - public fun x(): u64 { 0 } -} - - -//# programmable --sender A --inputs 10 @A -//> 0: SplitCoins(Gas, [Input(0)]); -//> 1: Publish(q, []); -//> 2: TransferObjects([Result(0)], Input(1)); -//> 3: Publish(p, []); -//> TransferObjects([Result(1), Result(3)], Input(1)) - -//# set-address p object(3,1) - -//# set-address q object(3,0) - -//# programmable --sender A -//> 0: q::m::x(); -//> p::m::foo(Result(0)) - -//# publish --dependencies p q -module r::all { - public fun foo_x() { - p::m::foo(q::m::x()) - } -} - -//# run r::all::foo_x diff --git a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/upgrade.move b/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/upgrade.move deleted file mode 100644 index 6391796a07e..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/programmable_transaction_examples/upgrade.move +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// simple test of upgrade - -//# init --addresses p=0x0 q=0x0 q_2=0x0 r=0x0 s=0x0 --accounts A - -//# publish -module p::m { - public fun foo(x: u64) { - p::n::bar(x) - } -} -module p::n { - public fun bar(x: u64) { - assert!(x == 1, 0); - } -} - -//# publish --upgradeable --sender A -module q::m { - public fun x(): u64 { 0 } -} - -//# publish -module r::m { - public fun y(): u64 { 0 } -} - -//# stage-package --dependencies r -module q_2::m { - public fun x(): u64 { y() + 1 } - public fun y(): u64 { r::m::y() } -} - -//# programmable --sender A --inputs 10 @A object(2,1) 0u8 digest(q_2) -//> 0: sui::package::authorize_upgrade(Input(2), Input(3), Input(4)); -//> 1: SplitCoins(Gas, [Input(0)]); -//> 2: Upgrade(q_2, [sui,std,r], q, Result(0)); -//> TransferObjects([Result(1)], Input(1)); -//> sui::package::commit_upgrade(Input(2), Result(2)) - -//# programmable --sender A -//> 0: q::m::x(); -//> p::m::foo(Result(0)) - -//# set-address q_2 object(5,0) - -//# programmable --sender A -//> 0: q_2::m::x(); -//> p::m::foo(Result(0)) - -//# publish --dependencies p q_2 r -module s::all { - public fun foo_x() { - p::m::foo(q::m::x()) - } -} - -//# run s::all::foo_x diff --git a/crates/sui-adapter-transactional-tests/tests/publish/init_param.exp b/crates/sui-adapter-transactional-tests/tests/publish/init_param.exp deleted file mode 100644 index 8fdabd2f78f..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/publish/init_param.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 2 tasks - -task 1 'publish'. lines 5-27: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Expected last parameter for _::M1::init to be &mut sui::tx_context::TxContext or &sui::tx_context::TxContext, but found &mut sui::tx_context::TxContext"), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/publish/init_public.exp b/crates/sui-adapter-transactional-tests/tests/publish/init_public.exp deleted file mode 100644 index 2d35bee0c04..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/publish/init_public.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 2 tasks - -task 1 'publish'. lines 5-27: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::M1. 'init' function must be private"), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/publish/init_ret.exp b/crates/sui-adapter-transactional-tests/tests/publish/init_ret.exp deleted file mode 100644 index bca6b63f25c..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/publish/init_ret.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 2 tasks - -task 1 'publish'. lines 5-27: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::M1, 'init' function cannot have return values"), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/publish/publish_with_upgrade.exp b/crates/sui-adapter-transactional-tests/tests/publish/publish_with_upgrade.exp deleted file mode 100644 index 0512f0e1a26..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/publish/publish_with_upgrade.exp +++ /dev/null @@ -1,11 +0,0 @@ -processed 3 tasks - -task 1 'publish'. lines 6-9: -created: object(1,0), object(1,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5532800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'view-object'. lines 11-11: -Owner: Account Address ( _ ) -Version: 2 -Contents: sui::package::UpgradeCap {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,1)}}, package: sui::object::ID {bytes: Test}, version: 1u64, policy: 0u8} diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/basic_receive.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/basic_receive.exp deleted file mode 100644 index 0bf00e7c48d..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/basic_receive.exp +++ /dev/null @@ -1,39 +0,0 @@ -processed 9 tasks - -task 1 'publish'. lines 6-30: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 6923600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 32-32: -created: object(2,0), object(2,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'view-object'. lines 34-34: -Owner: Account Address ( _ ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 4 'view-object'. lines 36-38: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 5 'run'. lines 39-39: -mutated: object(0,0), object(2,0), object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 - -task 6 'view-object'. lines 41-41: -Owner: Account Address ( _ ) -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 7 'view-object'. lines 43-45: -Owner: Account Address ( _ ) -Version: 4 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 8 'run'. lines 46-46: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3), source: Some(VMError { major_status: ABORTED, sub_status: Some(3), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/basic_receive.move b/crates/sui-adapter-transactional-tests/tests/receive_object/basic_receive.move deleted file mode 100644 index 1dee8ea3ab0..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/basic_receive.move +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --addresses tto=0x0 - -//# publish -module tto::M1 { - use sui::transfer::Receiving; - - public struct A has key, store { - id: UID, - } - - public struct B has key, store { - id: UID, - } - - public fun start(ctx: &mut TxContext) { - let a = A { id: object::new(ctx) }; - let a_address = object::id_address(&a); - let b = B { id: object::new(ctx) }; - transfer::public_transfer(a, tx_context::sender(ctx)); - transfer::public_transfer(b, a_address); - } - - public entry fun receiver(parent: &mut A, x: Receiving) { - let b = transfer::receive(&mut parent.id, x); - transfer::public_transfer(b, @tto); - } -} - -//# run tto::M1::start - -//# view-object 2,0 - -//# view-object 2,1 - -// Can receive the object -//# run tto::M1::receiver --args object(2,0) receiving(2,1) - -//# view-object 2,0 - -//# view-object 2,1 - -// Cannot receive the object again at the old version -//# run tto::M1::receiver --args object(2,0) receiving(2,1)@3 diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/drop_receiving.move b/crates/sui-adapter-transactional-tests/tests/receive_object/drop_receiving.move deleted file mode 100644 index 8430fc44fb7..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/drop_receiving.move +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --addresses tto=0x0 - -//# publish -module tto::M1 { - use sui::transfer::Receiving; - - public struct A has key, store { - id: UID, - } - - public struct B has key, store { - id: UID, - } - - public fun start(ctx: &mut TxContext) { - let a = A { id: object::new(ctx) }; - let a_address = object::id_address(&a); - let b = B { id: object::new(ctx) }; - transfer::public_transfer(a, tx_context::sender(ctx)); - transfer::public_transfer(b, a_address); - } - - public entry fun send_back(parent: &mut A, x: Receiving) { - let b = transfer::receive(&mut parent.id, x); - let parent_address = object::id_address(parent); - transfer::public_transfer(b, parent_address); - } - - public entry fun nop(_parent: &mut A) { } - public entry fun nop_with_receiver(_parent: &mut A, _x: Receiving) { } -} - -//# run tto::M1::start - -//# programmable --inputs object(2,0) receiving(2,1) -//> tto::M1::send_back(Input(0), Input(1)) - -// Include the receiving argument, but don't use it at the PTB level -//# programmable --inputs object(2,0) receiving(2,1) -//> tto::M1::nop(Input(0)) - -// Include the receiving argument, but don't use it at the Move level. The -// receiving object should not be mutated by this. -//# programmable --inputs object(2,0) receiving(2,1) -//> tto::M1::nop_with_receiver(Input(0), Input(1)) diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/move_vec_receiving_types.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/move_vec_receiving_types.exp deleted file mode 100644 index 93f8b699fbf..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/move_vec_receiving_types.exp +++ /dev/null @@ -1,60 +0,0 @@ -processed 14 tasks - -task 1 'publish'. lines 6-63: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 10579200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 65-65: -created: object(2,0), object(2,1), object(2,2), object(2,3), object(2,4) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 7068000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'view-object'. lines 67-67: -Owner: Account Address ( _ ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 4 'view-object'. lines 69-69: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 5 'view-object'. lines 71-71: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}} - -task 6 'view-object'. lines 73-73: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::C {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,3)}}} - -task 7 'view-object'. lines 75-77: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::C {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,4)}}} - -task 8 'programmable'. lines 78-81: -mutated: object(0,0), object(2,0) -gas summary: computation_cost: 1000000, storage_cost: 2204000, storage_rebate: 2181960, non_refundable_storage_fee: 22040 - -task 9 'programmable'. lines 82-86: -mutated: object(0,0), object(2,0) -gas summary: computation_cost: 1000000, storage_cost: 2204000, storage_rebate: 2181960, non_refundable_storage_fee: 22040 - -task 10 'programmable'. lines 87-92: -Error: Transaction Effects Status: Invalid command argument at 0. The type of the value does not match the expected type -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: CommandArgumentError { arg_idx: 0, kind: TypeMismatch }, source: None, command: Some(1) } } - -task 11 'programmable'. lines 93-97: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::receive_impl (function index 12) at offset 0, Abort Code: 2 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(1) } } - -task 12 'programmable'. lines 98-100: -Error: Transaction Effects Status: Invalid command argument at 4. The type of the value does not match the expected type -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: CommandArgumentError { arg_idx: 4, kind: TypeMismatch }, source: None, command: Some(1) } } - -task 13 'programmable'. lines 102-105: -Error: Transaction Effects Status: Invalid command argument at 4. The type of the value does not match the expected type -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: CommandArgumentError { arg_idx: 4, kind: TypeMismatch }, source: None, command: Some(2) } } diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_add_dof_and_mutate.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/receive_add_dof_and_mutate.exp deleted file mode 100644 index df45dcd27ab..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_add_dof_and_mutate.exp +++ /dev/null @@ -1,54 +0,0 @@ -processed 11 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 6-36: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 7835600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 38-38: -created: object(2,0), object(2,1) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 3541600, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'view-object'. lines 40-40: -Owner: Account Address ( _ ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, value: 0u64} - -task 4 'view-object'. lines 42-42: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, value: 0u64} - -task 5 'run'. lines 44-44: -created: object(5,0), object(5,1), object(5,2) -mutated: object(0,1), object(2,0), object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 9728000, storage_rebate: 3506184, non_refundable_storage_fee: 35416 - -task 6 'view-object'. lines 46-46: -Owner: Account Address ( _ ) -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, value: 0u64} - -task 7 'view-object'. lines 48-48: -Owner: Object ID: ( fake(5,0) ) -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, value: 100u64} - -task 8 'view-object'. lines 50-50: -Owner: Object ID: ( fake(2,0) ) -Version: 4 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(5,0)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(2,1)}} - -task 9 'view-object'. lines 52-52: -Owner: Object ID: ( fake(2,1) ) -Version: 4 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(5,1)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(5,2)}} - -task 10 'view-object'. lines 54-54: -Owner: Object ID: ( fake(5,1) ) -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(5,2)}}, value: 100u64} diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_deleted.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_deleted.exp deleted file mode 100644 index b038f326ed5..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_deleted.exp +++ /dev/null @@ -1,38 +0,0 @@ -processed 9 tasks - -task 1 'publish'. lines 6-30: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 6726000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 32-32: -created: object(2,0), object(2,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'view-object'. lines 34-34: -Owner: Account Address ( _ ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 4 'view-object'. lines 36-38: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 5 'run'. lines 39-39: -mutated: object(0,0), object(2,0) -deleted: object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 2204000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 - -task 6 'view-object'. lines 41-41: -Owner: Account Address ( _ ) -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 7 'view-object'. lines 43-45: -No object at id 2,1 - -task 8 'run'. lines 46-46: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3), source: Some(VMError { major_status: ABORTED, sub_status: Some(3), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_send_back.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_send_back.exp deleted file mode 100644 index 3d329620420..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_send_back.exp +++ /dev/null @@ -1,39 +0,0 @@ -processed 9 tasks - -task 1 'publish'. lines 6-31: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 6756400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 33-33: -created: object(2,0), object(2,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'view-object'. lines 35-35: -Owner: Account Address ( _ ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 4 'view-object'. lines 37-39: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 5 'run'. lines 40-40: -mutated: object(0,0), object(2,0), object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 - -task 6 'view-object'. lines 42-42: -Owner: Account Address ( _ ) -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 7 'view-object'. lines 44-46: -Owner: Account Address ( fake(2,0) ) -Version: 4 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 8 'run'. lines 47-47: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3), source: Some(VMError { major_status: ABORTED, sub_status: Some(3), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_wrap.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_wrap.exp deleted file mode 100644 index 1d707f5b97a..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_and_wrap.exp +++ /dev/null @@ -1,39 +0,0 @@ -processed 9 tasks - -task 1 'publish'. lines 6-39: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 7569600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 41-41: -created: object(2,0), object(2,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'view-object'. lines 43-43: -Owner: Account Address ( _ ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 4 'view-object'. lines 45-47: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 5 'run'. lines 48-48: -created: object(5,0) -mutated: object(0,0), object(2,0) -wrapped: object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 3708800, storage_rebate: 3385800, non_refundable_storage_fee: 34200 - -task 6 'view-object'. lines 50-50: -Owner: Account Address ( _ ) -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 7 'view-object'. lines 52-54: -No object at id 2,1 - -task 8 'run'. lines 55-55: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3), source: Some(VMError { major_status: ABORTED, sub_status: Some(3), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_dof_and_mutate.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/receive_dof_and_mutate.exp deleted file mode 100644 index f6fad9d01d8..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_dof_and_mutate.exp +++ /dev/null @@ -1,59 +0,0 @@ -processed 12 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 6-34: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 7828000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 36-36: -created: object(2,0), object(2,1), object(2,2), object(2,3) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 7273200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 38-38: -Owner: Object ID: ( fake(2,2) ) -Version: 2 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(2,3)}} - -task 4 'view-object'. lines 40-40: -Owner: Account Address ( A ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, value: 0u64} - -task 5 'view-object'. lines 42-42: -Owner: Account Address ( fake(2,1) ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}, value: 0u64} - -task 6 'view-object'. lines 44-44: -Owner: Object ID: ( fake(2,0) ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,3)}}, value: 0u64} - -task 7 'run'. lines 46-46: -created: object(7,0) -mutated: object(0,0), object(2,1), object(2,2) -gas summary: computation_cost: 1000000, storage_cost: 5996400, storage_rebate: 3506184, non_refundable_storage_fee: 35416 - -task 8 'view-object'. lines 48-48: -Owner: Object ID: ( fake(2,2) ) -Version: 2 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(2,3)}} - -task 9 'view-object'. lines 50-50: -Owner: Account Address ( A ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, value: 0u64} - -task 10 'view-object'. lines 52-52: -Owner: Object ID: ( fake(7,0) ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}, value: 100u64} - -task 11 'view-object'. lines 54-54: -Owner: Object ID: ( fake(2,0) ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,3)}}, value: 0u64} diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_dof_and_mutate.move b/crates/sui-adapter-transactional-tests/tests/receive_object/receive_dof_and_mutate.move deleted file mode 100644 index 994a6fe4b20..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_dof_and_mutate.move +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --addresses tto=0x0 --accounts A - -//# publish -module tto::M1 { - use sui::transfer::Receiving; - use sui::dynamic_object_field as dof; - - const KEY: u64 = 0; - - public struct A has key, store { - id: UID, - value: u64, - } - - public fun start(ctx: &mut TxContext) { - let a = A { id: object::new(ctx), value: 0 }; - let a_address = object::id_address(&a); - let mut b = A { id: object::new(ctx), value: 0 }; - dof::add(&mut b.id, KEY, A { id: object::new(ctx), value: 0 }); - transfer::public_transfer(a, tx_context::sender(ctx)); - transfer::public_transfer(b, a_address); - } - - public entry fun receive(parent: &mut A, x: Receiving) { - let b = transfer::receive(&mut parent.id, x); - dof::add(&mut parent.id, KEY, b); - let _: &A = dof::borrow(&parent.id, KEY); - let x: &mut A = dof::borrow_mut(&mut parent.id, KEY); - x.value = 100; - } -} - -//# run tto::M1::start --sender A - -//# view-object 2,0 - -//# view-object 2,1 - -//# view-object 2,2 - -//# view-object 2,3 - -//# run tto::M1::receive --args object(2,1) receiving(2,2) --sender A - -//# view-object 2,0 - -//# view-object 2,1 - -//# view-object 2,2 - -//# view-object 2,3 diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_invalid_type.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/receive_invalid_type.exp deleted file mode 100644 index 20fe33412c2..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_invalid_type.exp +++ /dev/null @@ -1,25 +0,0 @@ -processed 6 tasks - -task 1 'publish'. lines 6-30: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 6923600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 32-32: -created: object(2,0), object(2,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'view-object'. lines 34-34: -Owner: Account Address ( _ ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 4 'view-object'. lines 36-38: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 5 'run'. lines 39-39: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::receive_impl (function index 12) at offset 0, Abort Code: 2 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 2), source: Some(VMError { major_status: ABORTED, sub_status: Some(2), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_multiple_times_in_row.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/receive_multiple_times_in_row.exp deleted file mode 100644 index b288711b2a7..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_multiple_times_in_row.exp +++ /dev/null @@ -1,59 +0,0 @@ -processed 13 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 6-36: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 7007200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 38-38: -created: object(2,0), object(2,1) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'run'. lines 40-40: -created: object(3,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2204000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 4 'view-object'. lines 42-42: -Owner: Account Address ( _ ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 5 'view-object'. lines 44-46: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 6 'run'. lines 47-47: -mutated: object(0,1), object(2,0), object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 - -task 7 'view-object'. lines 49-49: -Owner: Account Address ( _ ) -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 8 'view-object'. lines 51-53: -Owner: Account Address ( fake(2,0) ) -Version: 4 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 9 'run'. lines 54-56: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3), source: Some(VMError { major_status: ABORTED, sub_status: Some(3), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } - -task 10 'run'. lines 57-59: -mutated: object(0,1), object(2,0), object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 - -task 11 'run'. lines 60-62: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3), source: Some(VMError { major_status: ABORTED, sub_status: Some(3), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } - -task 12 'run'. lines 63-63: -mutated: object(0,1), object(2,0), object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_multiple_times_in_row.move b/crates/sui-adapter-transactional-tests/tests/receive_object/receive_multiple_times_in_row.move deleted file mode 100644 index 921ba06860f..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_multiple_times_in_row.move +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --addresses tto=0x0 --accounts A - -//# publish -module tto::M1 { - use sui::transfer::Receiving; - - public struct A has key, store { - id: UID, - } - - public struct B has key, store { - id: UID, - } - - public fun start(ctx: &mut TxContext) { - let a = A { id: object::new(ctx) }; - let a_address = object::id_address(&a); - let b = B { id: object::new(ctx) }; - transfer::public_transfer(a, tx_context::sender(ctx)); - transfer::public_transfer(b, a_address); - } - - public fun middle(ctx: &mut TxContext) { - let a = A { id: object::new(ctx) }; - transfer::public_transfer(a, tx_context::sender(ctx)); - } - - public entry fun send_back(parent: &mut A, x: Receiving) { - let b = transfer::receive(&mut parent.id, x); - let parent_address = object::id_address(parent); - transfer::public_transfer(b, parent_address); - } -} - -//# run tto::M1::start - -//# run tto::M1::middle --sender A - -//# view-object 2,0 - -//# view-object 2,1 - -// Receive the object and then send it -//# run tto::M1::send_back --args object(2,0) receiving(2,1) - -//# view-object 2,0 - -//# view-object 2,1 - -// Can no longer receive that object at the previous version number -//# run tto::M1::send_back --args object(2,0) receiving(2,1)@3 - -// Can receive the object at the new version number -//# run tto::M1::send_back --args object(2,0) receiving(2,1)@4 - -// Cannot try and receive the object with an invalid owner even if it has the right type -//# run tto::M1::send_back --summarize --args object(3,0) receiving(2,1)@6 --sender A - -// Can still receive and send back so state is all good still, and version number hasn't been incremented for the receiving object due to the failed tx above. -//# run tto::M1::send_back --args object(2,0) receiving(2,1)@6 diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_object_owner.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/receive_object_owner.exp deleted file mode 100644 index 7c153102478..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_object_owner.exp +++ /dev/null @@ -1,35 +0,0 @@ -processed 8 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 6-28: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 6634800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 30-30: -created: object(2,0), object(2,1), object(2,2) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5996400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 32-32: -Owner: Object ID: ( fake(2,2) ) -Version: 2 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(2,1)}} - -task 4 'view-object'. lines 34-34: -Owner: Object ID: ( fake(2,0) ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, value: 0u64} - -task 5 'view-object'. lines 36-38: -Owner: Account Address ( A ) -Version: 2 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}, value: 0u64} - -task 6 'run'. lines 39-41: -Error: Error checking transaction input objects: InvalidChildObjectArgument { child_id: object(2,1), parent_id: object(2,0) } - -task 7 'run'. lines 42-42: -Error: Error checking transaction input objects: InvalidChildObjectArgument { child_id: object(2,0), parent_id: object(2,2) } diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_return_object_then_transfer.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/receive_return_object_then_transfer.exp deleted file mode 100644 index b3f897430a6..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/receive_return_object_then_transfer.exp +++ /dev/null @@ -1,35 +0,0 @@ -processed 8 tasks - -task 1 'publish'. lines 6-29: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 6604400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 31-31: -created: object(2,0), object(2,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'view-object'. lines 33-33: -Owner: Account Address ( _ ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 4 'view-object'. lines 35-37: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 5 'programmable'. lines 38-40: -mutated: object(0,0), object(2,0), object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 - -task 6 'view-object'. lines 42-42: -Owner: Account Address ( _ ) -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 7 'view-object'. lines 44-44: -Owner: Account Address ( tto ) -Version: 4 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/basic_receive.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/basic_receive.exp deleted file mode 100644 index ed297f3890e..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/basic_receive.exp +++ /dev/null @@ -1,39 +0,0 @@ -processed 9 tasks - -task 1 'publish'. lines 6-30: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 6969200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 32-32: -created: object(2,0), object(2,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'view-object'. lines 34-34: -Owner: Shared -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 4 'view-object'. lines 36-36: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 5 'run'. lines 38-38: -mutated: object(0,0), object(2,0), object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 - -task 6 'view-object'. lines 40-40: -Owner: Shared -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 7 'view-object'. lines 42-42: -Owner: Account Address ( _ ) -Version: 4 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 8 'run'. lines 44-44: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 -Debug of error: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3) at command Some(0) diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/basic_receive.move b/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/basic_receive.move deleted file mode 100644 index 273444436fe..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/basic_receive.move +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --addresses tto=0x0 - -//# publish -module tto::M1 { - use sui::transfer::Receiving; - - public struct A has key, store { - id: UID, - } - - public struct B has key, store { - id: UID, - } - - public fun start(ctx: &mut TxContext) { - let a = A { id: object::new(ctx) }; - let a_address = object::id_address(&a); - let b = B { id: object::new(ctx) }; - transfer::public_share_object(a); - transfer::public_transfer(b, a_address); - } - - public entry fun receiver(parent: &mut A, x: Receiving) { - let b = transfer::receive(&mut parent.id, x); - transfer::public_transfer(b, @tto); - } -} - -//# run tto::M1::start - -//# view-object 2,0 - -//# view-object 2,1 - -//# run tto::M1::receiver --args object(2,0) receiving(2,1) - -//# view-object 2,0 - -//# view-object 2,1 - -//# run tto::M1::receiver --args object(2,0) receiving(2,1)@3 diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/drop_receiving.move b/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/drop_receiving.move deleted file mode 100644 index 6cc6a9eb782..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/drop_receiving.move +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --addresses tto=0x0 - -//# publish -module tto::M1 { - use sui::transfer::Receiving; - - public struct A has key, store { - id: UID, - } - - public struct B has key, store { - id: UID, - } - public fun start(ctx: &mut TxContext) { - let a = A { id: object::new(ctx) }; - let a_address = object::id_address(&a); - let b = B { id: object::new(ctx) }; - transfer::public_share_object(a); - transfer::public_transfer(b, a_address); - } - - public entry fun send_back(parent: &mut A, x: Receiving) { - let b = transfer::receive(&mut parent.id, x); - let parent_address = object::id_address(parent); - transfer::public_transfer(b, parent_address); - } - - public entry fun nop(_parent: &mut A) { } - public entry fun nop_with_receiver(_parent: &mut A, _x: Receiving) { } -} - -//# run tto::M1::start - -//# programmable --inputs object(2,0) receiving(2,1) -//> tto::M1::send_back(Input(0), Input(1)) - -// Include the receiving argument, but don't use it at the PTB level -//# programmable --inputs object(2,0) receiving(2,1) -//> tto::M1::nop(Input(0)) - -// Include the receiving argument, but don't use it at the Move level. The -// receiving object should not be mutated by this. -//# programmable --inputs object(2,0) receiving(2,1) -//> tto::M1::nop_with_receiver(Input(0), Input(1)) diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/receive_dof_and_mutate.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/receive_dof_and_mutate.exp deleted file mode 100644 index 5695b58253b..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/receive_dof_and_mutate.exp +++ /dev/null @@ -1,59 +0,0 @@ -processed 12 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 6-34: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 7881200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 36-36: -created: object(2,0), object(2,1), object(2,2), object(2,3) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 7273200, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'view-object'. lines 38-38: -Owner: Object ID: ( fake(2,3) ) -Version: 3 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(2,2)}} - -task 4 'view-object'. lines 40-40: -Owner: Shared -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, value: 0u64} - -task 5 'view-object'. lines 42-42: -Owner: Object ID: ( fake(2,0) ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}, value: 0u64} - -task 6 'view-object'. lines 44-44: -Owner: Account Address ( fake(2,1) ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,3)}}, value: 0u64} - -task 7 'run'. lines 46-46: -created: object(7,0) -mutated: object(0,1), object(2,1), object(2,3) -gas summary: computation_cost: 1000000, storage_cost: 5996400, storage_rebate: 3506184, non_refundable_storage_fee: 35416 - -task 8 'view-object'. lines 48-48: -Owner: Object ID: ( fake(2,3) ) -Version: 3 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(2,2)}} - -task 9 'view-object'. lines 50-50: -Owner: Shared -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}, value: 0u64} - -task 10 'view-object'. lines 52-52: -Owner: Object ID: ( fake(2,0) ) -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}, value: 0u64} - -task 11 'view-object'. lines 54-54: -Owner: Object ID: ( fake(7,0) ) -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,3)}}, value: 100u64} diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/receive_dof_and_mutate.move b/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/receive_dof_and_mutate.move deleted file mode 100644 index 8a16e051248..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/receive_dof_and_mutate.move +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --addresses tto=0x0 --accounts A - -//# publish -module tto::M1 { - use sui::transfer::Receiving; - use sui::dynamic_object_field as dof; - - const KEY: u64 = 0; - - public struct A has key, store { - id: UID, - value: u64, - } - - public fun start(ctx: &mut TxContext) { - let a = A { id: object::new(ctx), value: 0 }; - let a_address = object::id_address(&a); - let mut b = A { id: object::new(ctx), value: 0 }; - dof::add(&mut b.id, KEY, A { id: object::new(ctx), value: 0 }); - transfer::public_share_object(a); - transfer::public_transfer(b, a_address); - } - - public entry fun receive(parent: &mut A, x: Receiving) { - let b = transfer::receive(&mut parent.id, x); - dof::add(&mut parent.id, KEY, b); - let _: &A = dof::borrow(&parent.id, KEY); - let x: &mut A = dof::borrow_mut(&mut parent.id, KEY); - x.value = 100; - } -} - -//# run tto::M1::start - -//# view-object 2,0 - -//# view-object 2,1 - -//# view-object 2,2 - -//# view-object 2,3 - -//# run tto::M1::receive --args object(2,1) receiving(2,3) - -//# view-object 2,0 - -//# view-object 2,1 - -//# view-object 2,2 - -//# view-object 2,3 diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/receive_multiple_times_in_row.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/receive_multiple_times_in_row.exp deleted file mode 100644 index 939ac348efb..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/receive_multiple_times_in_row.exp +++ /dev/null @@ -1,59 +0,0 @@ -processed 13 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 6-37: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 7182000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 39-39: -created: object(2,0), object(2,1) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'run'. lines 41-41: -created: object(3,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2204000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 4 'view-object'. lines 43-43: -Owner: Shared -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 5 'view-object'. lines 45-47: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 6 'run'. lines 48-48: -mutated: object(0,1), object(2,0), object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 - -task 7 'view-object'. lines 50-50: -Owner: Shared -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 8 'view-object'. lines 52-54: -Owner: Account Address ( fake(2,0) ) -Version: 4 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 9 'run'. lines 55-57: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 -Debug of error: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3) at command Some(0) - -task 10 'run'. lines 58-60: -mutated: object(0,1), object(2,0), object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 - -task 11 'run'. lines 61-63: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3), source: Some(VMError { major_status: ABORTED, sub_status: Some(3), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(12), 0)] }), command: Some(0) } } - -task 12 'run'. lines 64-64: -mutated: object(0,1), object(2,0), object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/receive_multiple_times_in_row.move b/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/receive_multiple_times_in_row.move deleted file mode 100644 index 9bf1ce58c0e..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/receive_multiple_times_in_row.move +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --addresses tto=0x0 --accounts A - -//# publish -module tto::M1 { - use sui::transfer::Receiving; - - public struct A has key, store { - id: UID, - } - - public struct B has key, store { - id: UID, - } - - public fun start(ctx: &mut TxContext) { - let a = A { id: object::new(ctx) }; - let a_address = object::id_address(&a); - let b = B { id: object::new(ctx) }; - transfer::public_share_object(a); - transfer::public_transfer(b, a_address); - } - - - public fun middle(ctx: &mut TxContext) { - let a = A { id: object::new(ctx) }; - transfer::public_transfer(a, tx_context::sender(ctx)); - } - - public entry fun send_back(parent: &mut A, x: Receiving) { - let b = transfer::receive(&mut parent.id, x); - let parent_address = object::id_address(parent); - transfer::public_transfer(b, parent_address); - } -} - -//# run tto::M1::start - -//# run tto::M1::middle --sender A - -//# view-object 2,0 - -//# view-object 2,1 - -// Can receive the object and then send it -//# run tto::M1::send_back --args object(2,0) receiving(2,1) - -//# view-object 2,0 - -//# view-object 2,1 - -// Can no longer receive that object at the previous version number -//# run tto::M1::send_back --args object(2,0) receiving(2,1)@3 - -// Can receive the object at the new version number -//# run tto::M1::send_back --args object(2,0) receiving(2,1)@4 - -// Cannot try and receive the object with an invalid owner even if it has the right type -//# run tto::M1::send_back --summarize --args object(3,0) receiving(2,1)@6 --sender A - -// Can run still receive and send back so state is all good still, and version number hasn't been incremented for the object -//# run tto::M1::send_back --args object(2,0) receiving(2,1)@6 diff --git a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/transfer_then_share.exp b/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/transfer_then_share.exp deleted file mode 100644 index 0e00ffcad98..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/receive_object/shared_parent/transfer_then_share.exp +++ /dev/null @@ -1,39 +0,0 @@ -processed 9 tasks - -task 1 'publish'. lines 6-31: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 6916000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 33-33: -created: object(2,0), object(2,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'view-object'. lines 35-35: -Owner: Shared -Version: 3 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 4 'view-object'. lines 37-37: -Owner: Account Address ( fake(2,0) ) -Version: 3 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 5 'run'. lines 39-39: -mutated: object(0,0), object(2,0), object(2,1) -gas summary: computation_cost: 1000000, storage_cost: 3420000, storage_rebate: 3385800, non_refundable_storage_fee: 34200 - -task 6 'view-object'. lines 41-41: -Owner: Shared -Version: 4 -Contents: tto::M1::A {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}} - -task 7 'view-object'. lines 43-43: -Owner: Account Address ( _ ) -Version: 4 -Contents: tto::M1::B {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,1)}}} - -task 8 'run'. lines 45-45: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::receive_impl (function index 12) at offset 0, Abort Code: 3 -Debug of error: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 12, instruction: 0, function_name: Some("receive_impl") }, 3) at command Some(0) diff --git a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge.exp b/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge.exp deleted file mode 100644 index 3a61ecdfcd9..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/shared/by_value_shared_object_deletion_via_merge.exp +++ /dev/null @@ -1,104 +0,0 @@ -processed 21 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 13-60: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 9264400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 62-62: -created: object(2,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'run'. lines 64-64: -created: object(3,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 4 'view-object'. lines 66-66: -Owner: Shared -Version: 3 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, balance: sui::balance::Balance {value: 0u64}} - -task 5 'view-object'. lines 68-71: -Owner: Account Address ( A ) -Version: 4 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, balance: sui::balance::Balance {value: 0u64}} - -task 6 'programmable'. lines 72-76: -mutated: object(0,0), object(3,0) -deleted: object(2,0) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 1956240, non_refundable_storage_fee: 19760 - -task 7 'run'. lines 78-78: -created: object(7,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 8 'run'. lines 80-80: -created: object(8,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 9 'run'. lines 82-82: -created: object(9,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 10 'view-object'. lines 84-84: -Owner: Account Address ( A ) -Version: 5 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(7,0)}}, balance: sui::balance::Balance {value: 0u64}} - -task 11 'view-object'. lines 86-86: -Owner: Shared -Version: 6 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(8,0)}}, balance: sui::balance::Balance {value: 0u64}} - -task 12 'view-object'. lines 88-90: -Owner: Shared -Version: 7 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(9,0)}}} - -task 13 'programmable'. lines 91-95: -mutated: object(0,0), object(9,0) -deleted: object(7,0), object(8,0) -gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: 4160772, non_refundable_storage_fee: 42028 - -task 14 'run'. lines 97-97: -created: object(14,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 15 'run'. lines 99-99: -created: object(15,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 16 'run'. lines 101-101: -created: object(16,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 17 'view-object'. lines 103-103: -Owner: Shared -Version: 8 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(14,0)}}, balance: sui::balance::Balance {value: 0u64}} - -task 18 'view-object'. lines 105-105: -Owner: Shared -Version: 9 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(15,0)}}, balance: sui::balance::Balance {value: 0u64}} - -task 19 'view-object'. lines 107-109: -Owner: Shared -Version: 10 -Contents: t2::o2::Obj2 {id: sui::object::UID {id: sui::object::ID {bytes: fake(16,0)}}} - -task 20 'programmable'. lines 110-112: -mutated: object(0,0), object(16,0) -deleted: object(14,0), object(15,0) -gas summary: computation_cost: 1000000, storage_cost: 2226800, storage_rebate: 4160772, non_refundable_storage_fee: 42028 diff --git a/crates/sui-adapter-transactional-tests/tests/shared/freeze.move b/crates/sui-adapter-transactional-tests/tests/shared/freeze.move deleted file mode 100644 index 942aede08c7..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/shared/freeze.move +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests that shared objects cannot be freezed - -//# init --addresses t1=0x0 t2=0x0 --shared-object-deletion true - -//# publish - - -module t2::o2 { - public struct Obj2 has key, store { - id: UID, - } - - public entry fun create(ctx: &mut TxContext) { - let o = Obj2 { id: object::new(ctx) }; - transfer::public_share_object(o) - } - - public entry fun freeze_o2(o2: Obj2) { - transfer::freeze_object(o2); - } - -} - -//# run t2::o2::create - -//# view-object 2,0 - -//# run t2::o2::freeze_o2 --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/shared/transfer.move b/crates/sui-adapter-transactional-tests/tests/shared/transfer.move deleted file mode 100644 index 3054e554603..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/shared/transfer.move +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests that shared objects cannot be transfered in a way that will result -// in their ownership no longer being shared - -//# init --addresses t1=0x0 t2=0x0 --shared-object-deletion true - -//# publish - -module t2::o2 { - public struct Obj2 has key, store { - id: UID, - } - - public entry fun create(ctx: &mut TxContext) { - let o = Obj2 { id: object::new(ctx) }; - transfer::public_share_object(o) - } - - public entry fun transfer_to_single_owner(o2: Obj2, ctx: &mut TxContext) { - transfer::transfer(o2, tx_context::sender(ctx)) - } -} - -//# run t2::o2::create - -//# view-object 2,0 - -//# run t2::o2::transfer_to_single_owner --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/shared/upgrade.exp b/crates/sui-adapter-transactional-tests/tests/shared/upgrade.exp deleted file mode 100644 index cbb790eeddc..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/shared/upgrade.exp +++ /dev/null @@ -1,31 +0,0 @@ -processed 7 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 8-36: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 7440400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 38-38: -created: object(2,0), object(2,1), object(2,2), object(2,3) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 7835600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'view-object'. lines 40-40: -Owner: Account Address ( A ) -Version: 2 -Contents: t::m::Obj {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,2)}}} - -task 4 'run'. lines 42-42: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::share_object_impl (function index 10) at offset 0, Abort Code: 0 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 10, instruction: 0, function_name: Some("share_object_impl") }, 0), source: Some(VMError { major_status: ABORTED, sub_status: Some(0), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(10), 0)] }), command: Some(0) } } - -task 5 'run'. lines 44-44: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::share_object_impl (function index 10) at offset 0, Abort Code: 0 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 10, instruction: 0, function_name: Some("share_object_impl") }, 0), source: Some(VMError { major_status: ABORTED, sub_status: Some(0), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(10), 0)] }), command: Some(0) } } - -task 6 'run'. lines 46-46: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::transfer::share_object_impl (function index 10) at offset 0, Abort Code: 0 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("transfer") }, function: 10, instruction: 0, function_name: Some("share_object_impl") }, 0), source: Some(VMError { major_status: ABORTED, sub_status: Some(0), message: None, exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("transfer") }), indices: [], offsets: [(FunctionDefinitionIndex(10), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/shared/upgrade.move b/crates/sui-adapter-transactional-tests/tests/shared/upgrade.move deleted file mode 100644 index 82ec3cadb9f..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/shared/upgrade.move +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests that shared objects must be newly created - -//# init --addresses t=0x0 --accounts A - -//# publish - -module t::m { - public struct Obj has key, store { - id: UID, - } - - public entry fun create(ctx: &mut TxContext) { - let mut o = Obj { id: object::new(ctx) }; - sui::dynamic_field::add(&mut o.id, 0, Obj { id: object::new(ctx) }); - sui::dynamic_object_field::add(&mut o.id, 0, Obj { id: object::new(ctx) }); - transfer::public_transfer(o, ctx.sender()) - } - - public entry fun share(o: Obj) { - transfer::public_share_object(o) - } - - public entry fun share_wrapped(o: &mut Obj) { - let inner: Obj = sui::dynamic_field::remove(&mut o.id, 0); - transfer::public_share_object(inner) - } - - public entry fun share_child(o: &mut Obj) { - let inner: Obj = sui::dynamic_object_field::remove(&mut o.id, 0); - transfer::public_share_object(inner) - } - -} - -//# run t::m::create --sender A - -//# view-object 2,2 - -//# run t::m::share --args object(2,2) --sender A - -//# run t::m::share_wrapped --args object(2,2) --sender A - -//# run t::m::share_child --args object(2,2) --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.exp b/crates/sui-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.exp deleted file mode 100644 index 14c71aafb77..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/deleted_id_limits_tests.exp +++ /dev/null @@ -1,26 +0,0 @@ -processed 7 tasks - -task 1 'publish'. lines 8-32: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5259200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 33-35: -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'run'. lines 36-38: -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 4 'run'. lines 39-41: -mutated: object(0,0) -gas summary: computation_cost: 5000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 5 'run'. lines 42-44: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } - -task 6 'run'. lines 45-45: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/event_limits_tests.exp b/crates/sui-adapter-transactional-tests/tests/size_limits/event_limits_tests.exp deleted file mode 100644 index 8cfd8264693..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/event_limits_tests.exp +++ /dev/null @@ -1,42 +0,0 @@ -processed 10 tasks - -task 1 'publish'. lines 8-55: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 7311200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 56-58: -events: 1 -mutated: 1 -gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'run'. lines 59-61: -events: 50 -mutated: 1 -gas summary: computation_cost: 3000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 4 'run'. lines 62-64: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::event::emit (function index 0) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("event") }, function: 0, instruction: 0, function_name: Some("emit") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(0), message: Some("Emitting more than 1024 events is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("event") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 0)] }), command: Some(0) } } - -task 5 'run'. lines 65-67: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::event::emit (function index 0) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("event") }, function: 0, instruction: 0, function_name: Some("emit") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(0), message: Some("Emitting more than 1024 events is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("event") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 0)] }), command: Some(0) } } - -task 6 'run'. lines 68-70: -events: 1 -mutated: 1 -gas summary: computation_cost: 1393000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 7 'run'. lines 71-73: -events: 1 -mutated: 1 -gas summary: computation_cost: 1814000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 8 'run'. lines 74-76: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::event::emit (function index 0) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("event") }, function: 0, instruction: 0, function_name: Some("emit") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(1), message: Some("Emitting event of size 256001 bytes. Limit is 256000 bytes."), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("event") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 0)] }), command: Some(0) } } - -task 9 'run'. lines 77-77: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::event::emit (function index 0) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("event") }, function: 0, instruction: 0, function_name: Some("emit") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(1), message: Some("Emitting event of size 259000 bytes. Limit is 256000 bytes."), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("event") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/event_limits_tests_out_of_gas.exp b/crates/sui-adapter-transactional-tests/tests/size_limits/event_limits_tests_out_of_gas.exp deleted file mode 100644 index 780bdae769f..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/event_limits_tests_out_of_gas.exp +++ /dev/null @@ -1,22 +0,0 @@ -processed 6 tasks - -task 1 'publish'. lines 8-66: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 7919200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 67-69: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::event::emit (function index 0) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("event") }, function: 0, instruction: 0, function_name: Some("emit") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(0), message: Some("Emitting more than 1024 events is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("event") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 0)] }), command: Some(0) } } - -task 3 'run'. lines 70-72: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::event::emit (function index 0) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("event") }, function: 0, instruction: 0, function_name: Some("emit") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(0), message: Some("Emitting more than 1024 events is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("event") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 0)] }), command: Some(0) } } - -task 4 'run'. lines 73-75: -Error: Transaction Effects Status: Insufficient Gas. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: InsufficientGas, source: Some(VMError { major_status: OUT_OF_GAS, sub_status: None, message: None, exec_state: None, location: Module(ModuleId { address: Test, name: Identifier("M1") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 27)] }), command: Some(0) } } - -task 5 'run'. lines 76-76: -Error: Transaction Effects Status: Insufficient Gas. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: InsufficientGas, source: Some(VMError { major_status: OUT_OF_GAS, sub_status: None, message: None, exec_state: None, location: Module(ModuleId { address: Test, name: Identifier("M1") }), indices: [], offsets: [(FunctionDefinitionIndex(0), 33)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.exp b/crates/sui-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.exp deleted file mode 100644 index 165119846ad..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/new_id_limits_tests.exp +++ /dev/null @@ -1,26 +0,0 @@ -processed 7 tasks - -task 1 'publish'. lines 8-33: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5259200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 34-36: -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'run'. lines 37-39: -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 4 'run'. lines 40-42: -mutated: object(0,0) -gas summary: computation_cost: 5000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 5 'run'. lines 43-45: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } - -task 6 'run'. lines 46-46: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/object_runtime_limits.exp b/crates/sui-adapter-transactional-tests/tests/size_limits/object_runtime_limits.exp deleted file mode 100644 index 7f1c4e66b04..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/object_runtime_limits.exp +++ /dev/null @@ -1,27 +0,0 @@ -processed 6 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 7-26: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 5821600, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 28-28: -created: 200 -mutated: 1 -gas summary: computation_cost: 1000000, storage_cost: 270028000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'run'. lines 30-30: -created: 2000 -mutated: 1 -gas summary: computation_cost: 7000000, storage_cost: 2691388000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 4 'run'. lines 32-32: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::dynamic_field::has_child_object (function index 14) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 14, instruction: 0, function_name: Some("has_child_object") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(5), message: Some("Object runtime cached objects limit (1000 entries) reached"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(14), 0)] }), command: Some(0) } } - -task 5 'run'. lines 34-34: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::dynamic_field::has_child_object (function index 14) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("dynamic_field") }, function: 14, instruction: 0, function_name: Some("has_child_object") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(5), message: Some("Object runtime cached objects limit (1000 entries) reached"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("dynamic_field") }), indices: [], offsets: [(FunctionDefinitionIndex(14), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.exp b/crates/sui-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.exp deleted file mode 100644 index 6caea53cd0e..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/size_limits/transfered_id_limits_tests.exp +++ /dev/null @@ -1,37 +0,0 @@ -processed 9 tasks - -task 1 'publish'. lines 8-32: -created: object(1,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5578400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 33-35: -created: 1 -mutated: 1 -gas summary: computation_cost: 1000000, storage_cost: 2219200, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'run'. lines 36-38: -created: 256 -mutated: 1 -gas summary: computation_cost: 1000000, storage_cost: 316175200, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 4 'run'. lines 39-41: -created: 2048 -mutated: 1 -gas summary: computation_cost: 4000000, storage_cost: 2522485600, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 5 'run'. lines 42-44: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } - -task 6 'run'. lines 45-47: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } - -task 7 'run'. lines 48-50: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } - -task 8 'run'. lines 51-51: -Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::tx_context::derive_id (function index 6) at offset 0. Arithmetic error, stack overflow, max value depth, etc. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("tx_context") }, function: 6, instruction: 0, function_name: Some("derive_id") }))), source: Some(VMError { major_status: MEMORY_LIMIT_EXCEEDED, sub_status: Some(2), message: Some("Creating more than 2048 IDs is not allowed"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("tx_context") }), indices: [], offsets: [(FunctionDefinitionIndex(6), 0)] }), command: Some(0) } } diff --git a/crates/sui-adapter-transactional-tests/tests/sui/coin_transfer.exp b/crates/sui-adapter-transactional-tests/tests/sui/coin_transfer.exp deleted file mode 100644 index 65651f4508a..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/sui/coin_transfer.exp +++ /dev/null @@ -1,37 +0,0 @@ -processed 8 tasks - -init: -A: object(0,0), B: object(0,1), C: object(0,2) - -task 1 'programmable'. lines 8-10: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'view-object'. lines 12-12: -Owner: Account Address ( B ) -Version: 2 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,0)}}, balance: sui::balance::Balance {value: 10u64}} - -task 3 'run'. lines 14-14: -created: object(3,0) -mutated: object(0,1), object(1,0) -gas summary: computation_cost: 1000000, storage_cost: 2964000, storage_rebate: 1956240, non_refundable_storage_fee: 19760 - -task 4 'view-object'. lines 16-16: -Owner: Account Address ( B ) -Version: 3 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,0)}}, balance: sui::balance::Balance {value: 0u64}} - -task 5 'view-object'. lines 18-18: -Owner: Account Address ( A ) -Version: 3 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, balance: sui::balance::Balance {value: 10u64}} - -task 6 'run'. lines 20-20: -Error: Error checking transaction input objects: IncorrectUserSignature { error: "Object object(1,0) is owned by account address @B, but given owner/signer address is @A" } - -task 7 'view-object'. lines 22-22: -Owner: Account Address ( B ) -Version: 3 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(1,0)}}, balance: sui::balance::Balance {value: 0u64}} diff --git a/crates/sui-adapter-transactional-tests/tests/sui/coin_transfer.move b/crates/sui-adapter-transactional-tests/tests/sui/coin_transfer.move deleted file mode 100644 index 9816d8136c0..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/sui/coin_transfer.move +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// Test basic coin transfer - -//# init --accounts A B C - -//# programmable --sender B --inputs 10 @B -//> SplitCoins(Gas, [Input(0)]); -//> TransferObjects([Result(0)], Input(1)) - -//# view-object 1,0 - -//# run sui::pay::split_and_transfer --type-args sui::sui::SUI --args object(1,0) 10 @A --sender B - -//# view-object 1,0 - -//# view-object 3,0 - -//# run sui::pay::split_and_transfer --type-args sui::sui::SUI --args object(1,0) 0 @C --sender A - -//# view-object 1,0 diff --git a/crates/sui-adapter-transactional-tests/tests/sui/freeze.move b/crates/sui-adapter-transactional-tests/tests/sui/freeze.move deleted file mode 100644 index efbe891af31..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/sui/freeze.move +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// test that freezing prevents transfers/mutations - -//# init --addresses test=0x0 --accounts A --shared-object-deletion true - -//# publish - -module test::object_basics { - use sui::event; - - public struct Object has key, store { - id: UID, - value: u64, - } - - public struct Wrapper has key { - id: UID, - o: Object - } - - public struct NewValueEvent has copy, drop { - new_value: u64 - } - - public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { - transfer::public_transfer( - Object { id: object::new(ctx), value }, - recipient - ) - } - - public entry fun transfer_(o: Object, recipient: address) { - transfer::public_transfer(o, recipient) - } - - public entry fun freeze_object(o: Object) { - transfer::public_freeze_object(o) - } - - public entry fun set_value(o: &mut Object, value: u64) { - o.value = value; - } - - // test that reading o2 and updating o1 works - public entry fun update(o1: &mut Object, o2: &Object) { - o1.value = o2.value; - // emit an event so the world can see the new value - event::emit(NewValueEvent { new_value: o2.value }) - } - - public entry fun delete(o: Object) { - let Object { id, value: _ } = o; - object::delete(id); - } - - public entry fun wrap(o: Object, ctx: &mut TxContext) { - transfer::transfer(Wrapper { id: object::new(ctx), o }, tx_context::sender(ctx)) - } - - public entry fun unwrap(w: Wrapper, ctx: &mut TxContext) { - let Wrapper { id, o } = w; - object::delete(id); - transfer::public_transfer(o, tx_context::sender(ctx)) - } -} - -//# run test::object_basics::create --args 10 @A --sender A - -//# run test::object_basics::freeze_object --args object(2,0) --sender A - -//# run test::object_basics::transfer_ --args object(2,0) @A --sender A - -//# run test::object_basics::set_value --args object(2,0) 1 --sender A diff --git a/crates/sui-adapter-transactional-tests/tests/sui/object_basics.move b/crates/sui-adapter-transactional-tests/tests/sui/object_basics.move deleted file mode 100644 index c89267dadf4..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/sui/object_basics.move +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// Exercise test functions that create, transfer, read, update, and delete objects - -//# init --addresses test=0x0 --accounts A B - -//# publish - -module test::object_basics { - use sui::event; - - public struct Object has key, store { - id: UID, - value: u64, - } - - public struct Wrapper has key { - id: UID, - o: Object - } - - public struct NewValueEvent has copy, drop { - new_value: u64 - } - - public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { - transfer::public_transfer( - Object { id: object::new(ctx), value }, - recipient - ) - } - - public entry fun transfer_(o: Object, recipient: address) { - transfer::public_transfer(o, recipient) - } - - public entry fun freeze_object(o: Object) { - transfer::public_freeze_object(o) - } - - public entry fun set_value(o: &mut Object, value: u64) { - o.value = value; - } - - // test that reading o2 and updating o1 works - public entry fun update(o1: &mut Object, o2: &Object) { - o1.value = o2.value; - // emit an event so the world can see the new value - event::emit(NewValueEvent { new_value: o2.value }) - } - - public entry fun delete(o: Object) { - let Object { id, value: _ } = o; - object::delete(id); - } - - public entry fun wrap(o: Object, ctx: &mut TxContext) { - transfer::transfer(Wrapper { id: object::new(ctx), o }, tx_context::sender(ctx)) - } - - public entry fun unwrap(w: Wrapper, ctx: &mut TxContext) { - let Wrapper { id, o } = w; - object::delete(id); - transfer::public_transfer(o, tx_context::sender(ctx)) - } -} - -//# run test::object_basics::create --sender A --args 10 @A - -//# view-object 2,0 - -//# run test::object_basics::transfer_ --sender A --args object(2,0) @B - -//# view-object 2,0 - -//# run test::object_basics::create --sender B --args 20 @B - -//# run test::object_basics::update --sender B --args object(2,0) object(6,0) - -//# run test::object_basics::delete --sender B --args object(2,0) diff --git a/crates/sui-adapter-transactional-tests/tests/tests.rs b/crates/sui-adapter-transactional-tests/tests/tests.rs deleted file mode 100644 index 7b67b8d382f..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/tests.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub const TEST_DIR: &str = "tests"; -use sui_transactional_test_runner::run_test; - -datatest_stable::harness!(run_test, TEST_DIR, r".*\.(mvir|move)$"); diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/package.move b/crates/sui-adapter-transactional-tests/tests/transfer_object/package.move deleted file mode 100644 index 08c60fdc8c7..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/package.move +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests TransferObject should fail for a package - -//# init --accounts A B --addresses test=0x0 - -//# publish --sender A - -module test::m {} - - -//# view-object 1,0 - -//# transfer-object 1,0 --sender A --recipient B - -//# view-object 1,0 diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/quasi_shared.exp b/crates/sui-adapter-transactional-tests/tests/transfer_object/quasi_shared.exp deleted file mode 100644 index 1eea043008f..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/quasi_shared.exp +++ /dev/null @@ -1,32 +0,0 @@ -processed 7 tasks - -init: -A: object(0,0), B: object(0,1) - -task 1 'publish'. lines 8-23: -created: object(1,0) -mutated: object(0,2) -gas summary: computation_cost: 1000000, storage_cost: 6148400, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 25-25: -created: object(2,0) -mutated: object(0,2) -gas summary: computation_cost: 1000000, storage_cost: 2196400, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'run'. lines 27-27: -created: object(3,0), object(3,1) -mutated: object(0,2), object(2,0) -gas summary: computation_cost: 1000000, storage_cost: 5890000, storage_rebate: 2174436, non_refundable_storage_fee: 21964 - -task 4 'view-object'. lines 29-29: -Owner: Object ID: ( fake(2,0) ) -Version: 4 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(3,1)}} - -task 5 'transfer-object'. lines 31-31: -Error: Error checking transaction input objects: InvalidChildObjectArgument { child_id: object(3,0), parent_id: object(2,0) } - -task 6 'view-object'. lines 33-33: -Owner: Object ID: ( fake(2,0) ) -Version: 4 -Contents: sui::dynamic_field::Field, sui::object::ID> {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, name: sui::dynamic_object_field::Wrapper {name: 0u64}, value: sui::object::ID {bytes: fake(3,1)}} diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/shared.move b/crates/sui-adapter-transactional-tests/tests/transfer_object/shared.move deleted file mode 100644 index de4c02d0be3..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/shared.move +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests TransferObject should fail for a shared object with and without store - -//# init --accounts A B --addresses test=0x0 --shared-object-deletion true - -//# publish - -module test::m { - - public struct S has key { id: UID } - - public struct S2 has key, store { id: UID } - - public fun mint_s(ctx: &mut TxContext) { - let id = object::new(ctx); - transfer::share_object(S { id }) - } - - public fun mint_s2(ctx: &mut TxContext) { - let id = object::new(ctx); - transfer::share_object(S2 { id }) - } -} - -//# run test::m::mint_s - -//# run test::m::mint_s2 - -//# view-object 2,0 - -//# view-object 3,0 - -//# transfer-object 2,0 --sender A --recipient B - -//# transfer-object 3,0 --sender A --recipient B - -//# view-object 2,0 - -//# view-object 3,0 diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/transfer_coin.exp b/crates/sui-adapter-transactional-tests/tests/transfer_object/transfer_coin.exp deleted file mode 100644 index 0adbddcfcc3..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/transfer_coin.exp +++ /dev/null @@ -1,22 +0,0 @@ -processed 5 tasks - -init: -A: object(0,0), B: object(0,1), C: object(0,2) - -task 1 'programmable'. lines 8-9: -mutated: object(0,2) -gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'view-object'. lines 11-11: -Owner: Account Address ( A ) -Version: 2 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(0,2)}}, balance: sui::balance::Balance {value: 299999998012000u64}} - -task 3 'transfer-object'. lines 13-13: -mutated: object(0,0), object(0,2) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 4 'view-object'. lines 15-15: -Owner: Account Address ( B ) -Version: 3 -Contents: sui::coin::Coin {id: sui::object::UID {id: sui::object::ID {bytes: fake(0,2)}}, balance: sui::balance::Balance {value: 299999998012000u64}} diff --git a/crates/sui-adapter-transactional-tests/tests/transfer_object/transfer_coin.move b/crates/sui-adapter-transactional-tests/tests/transfer_object/transfer_coin.move deleted file mode 100644 index 053d9f38130..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/transfer_object/transfer_coin.move +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tests TransferObject with a SUI coin - -//# init --accounts A B C - -//# programmable --sender C --inputs @A -//> TransferObjects([Gas], Input(0)) - -//# view-object 0,2 - -//# transfer-object 0,2 --sender A --recipient B - -//# view-object 0,2 diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/dep_override.move b/crates/sui-adapter-transactional-tests/tests/upgrade/dep_override.move deleted file mode 100644 index a826ff05894..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/dep_override.move +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --addresses Test_DepDepV1=0x0 Test_DepDepV2=0x0 Test_DepDepV3=0x0 Test_DepV1=0x0 Test_DepV2=0x0 Test_V1=0x0 Test_V2=0x0 Test_V3=0x0 Test_V4=0x0 --accounts A - - -// 3 versions of the transitive dependency - - -//# publish --upgradeable --sender A -module Test_DepDepV1::DepDepM1 { - - public struct Obj has key, store { id: sui::object::UID, v: u64 } - - public fun foo(ctx: &mut sui::tx_context::TxContext) { - sui::transfer::share_object(Obj { id: sui::object::new(ctx), v: 42 }) - } -} - -//# upgrade --package Test_DepDepV1 --upgrade-capability 1,1 --sender A -module Test_DepDepV2::DepDepM1 { - - public struct Obj has key, store { id: sui::object::UID, v: u64 } - - public fun foo(ctx: &mut sui::tx_context::TxContext) { - sui::transfer::share_object(Obj { id: sui::object::new(ctx), v: 7 }) - } -} - -//# upgrade --package Test_DepDepV2 --upgrade-capability 1,1 --sender A -module Test_DepDepV3::DepDepM1 { - - public struct Obj has key, store { id: sui::object::UID, v: u64 } - - public fun foo(ctx: &mut sui::tx_context::TxContext) { - sui::transfer::share_object(Obj { id: sui::object::new(ctx), v: 0 }) - } -} - - -// 2 versions of the direct dependency - - -//# publish --upgradeable --dependencies Test_DepDepV1 --sender A -module Test_DepV1::DepM1 { - use Test_DepDepV1::DepDepM1; - - public fun bar(ctx: &mut sui::tx_context::TxContext) { DepDepM1::foo(ctx) } -} - -//# upgrade --package Test_DepV1 --upgrade-capability 4,1 --dependencies Test_DepDepV2 --sender A -module Test_DepV2::DepM1 { - use Test_DepDepV2::DepDepM1; - - public fun bar(ctx: &mut sui::tx_context::TxContext) { DepDepM1::foo(ctx) } -} - - -// 3 versions of the root package - - -//# publish --upgradeable --dependencies Test_DepV1 Test_DepDepV1 --sender A -module Test_V1::M1 { - use Test_DepV1::DepM1; - - public entry fun baz(ctx: &mut sui::tx_context::TxContext) { DepM1::bar(ctx) } -} - -// override direct dependency - -//# upgrade --package Test_V1 --upgrade-capability 6,1 --dependencies Test_DepV2 Test_DepDepV2 --sender A -module Test_V2::M1 { - use Test_DepV2::DepM1; - - public entry fun baz(ctx: &mut sui::tx_context::TxContext) { DepM1::bar(ctx) } -} - -// override indirect dependency - -//# upgrade --package Test_V2 --upgrade-capability 6,1 --dependencies Test_DepV1 Test_DepDepV3 --sender A -module Test_V3::M1 { - use Test_DepV1::DepM1; - - public entry fun baz(ctx: &mut sui::tx_context::TxContext) { DepM1::bar(ctx) } -} - -//# run Test_V1::M1::baz - -//# view-object 9,0 - -//# run Test_V2::M1::baz - -//# view-object 11,0 - -//# run Test_V3::M1::baz - -//# view-object 13,0 - -// call same function from two different module versions but defined in both modules (should produce -// different result due to overrides) -//# programmable --sender A -//> 0: Test_V2::M1::baz(); -//> 1: Test_V3::M1::baz(); - -//# view-object 15,0 - -//# view-object 15,1 - - -// expected upgrade errors - -// missing direct dependency (should fail) - -//# upgrade --package Test_V3 --upgrade-capability 6,1 --dependencies Test_DepDepV1 --sender A -module Test_V4::M1 { - use Test_DepV1::DepM1; - public entry fun baz(ctx: &mut sui::tx_context::TxContext) { DepM1::bar(ctx) } -} - -// missing indirect dependency (should fail) - -//# upgrade --package Test_V3 --upgrade-capability 6,1 --dependencies Test_DepV2 --sender A -module Test_V4::M1 { - use Test_DepV2::DepM1; - public entry fun baz(ctx: &mut sui::tx_context::TxContext) { DepM1::bar(ctx) } -} - -// downgrade indirect dependency (should fail) - -//# upgrade --package Test_V3 --upgrade-capability 6,1 --dependencies Test_DepV2 Test_DepDepV1 --sender A -module Test_V4::M1 { - use Test_DepV2::DepM1; - public entry fun baz(ctx: &mut sui::tx_context::TxContext) { DepM1::bar(ctx) } -} diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/modules.move b/crates/sui-adapter-transactional-tests/tests/upgrade/modules.move deleted file mode 100644 index d2678d4cc3f..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/modules.move +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --addresses V0=0x0 V1=0x0 V2=0x0 V3=0x0 --accounts A - -//# publish --upgradeable --sender A -module V0::base_module { - public struct Object has key, store { - id: UID, - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { 0 } -} -module V0::a { - fun call_friend(): u64 { V0::base_module::public_fun() } -} -module V0::b { - public fun public_fun(): u64 { 0 } -} -module V0::other_module { - public struct Y { } - fun public_fun(): u64 { 0 } -} - -// other_module::Y is missing in V1 -//# upgrade --package V0 --upgrade-capability 1,1 --sender A -module V1::base_module { - public struct Object has key, store { - id: UID, - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { 0 } -} -module V1::a { - fun call_friend(): u64 { V0::base_module::public_fun() } -} -module V1::b { - public fun public_fun(): u64 { 0 } -} -module V1::other_module { - fun public_fun(): u64 { 0 } -} - -// other_module missing in V1 -//# upgrade --package V0 --upgrade-capability 1,1 --sender A -module V1::base_module { - public struct Object has key, store { - id: UID, - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { 0 } -} -module V1::a { - fun call_friend(): u64 { V0::base_module::public_fun() } -} -module V1::b { - public fun public_fun(): u64 { 0 } -} - -// `b` missing in V1 -//# upgrade --package V0 --upgrade-capability 1,1 --sender A -module V1::base_module { - public struct Object has key, store { - id: UID, - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { 0 } -} -module V1::a { - fun call_friend(): u64 { V0::base_module::public_fun() } -} -module V1::other_module { - public struct Y { } - fun public_fun(): u64 { 0 } -} - -// `a` missing in V1 -//# upgrade --package V0 --upgrade-capability 1,1 --sender A -module V0::base_module { - public struct Object has key, store { - id: UID, - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { 0 } -} -module V0::b { - public fun public_fun(): u64 { 0 } -} -module V0::other_module { - public struct Y { } - fun public_fun(): u64 { 0 } -} diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/structs.move b/crates/sui-adapter-transactional-tests/tests/upgrade/structs.move deleted file mode 100644 index 94760c9615d..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/structs.move +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --addresses Test_V0=0x0 Test_V1=0x0 --accounts A - -//# publish --upgradeable --sender A -module Test_V0::base_module { - public struct X { - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { 0 } -} - -//# upgrade --package Test_V0 --upgrade-capability 1,1 --sender A -module Test_V1::base_module { - public struct Y { - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { 0 } -} - -//# upgrade --package Test_V0 --upgrade-capability 1,1 --sender A -module Test_V1::base_module { - public fun public_fun(): u64 { 0 } -} - -//# upgrade --package Test_V0 --upgrade-capability 1,1 --sender A -module Test_V1::base_module { - public struct X { - field2: u64, - field1: u64, - } - - public fun public_fun(): u64 { 0 } -} - -//# upgrade --package Test_V0 --upgrade-capability 1,1 --sender A -module Test_V1::base_module { - public struct X { - field1: u64, - field0: u64, - } - - public fun public_fun(): u64 { 0 } -} - -//# upgrade --package Test_V0 --upgrade-capability 1,1 --sender A -module Test_V1::base_module { - public struct X { - field0: u64, - field1: u64, - field2: u64, - } - - public fun public_fun(): u64 { 0 } -} diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/type_names.exp b/crates/sui-adapter-transactional-tests/tests/upgrade/type_names.exp deleted file mode 100644 index 0ef10c10f51..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/type_names.exp +++ /dev/null @@ -1,59 +0,0 @@ -processed 12 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 6-15: -created: object(1,0), object(1,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 6171200, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'upgrade'. lines 17-26: -created: object(2,0) -mutated: object(0,0), object(1,1) -gas summary: computation_cost: 1000000, storage_cost: 6520800, storage_rebate: 2595780, non_refundable_storage_fee: 26220 - -task 3 'upgrade'. lines 28-55: -created: object(3,0) -mutated: object(0,0), object(1,1) -gas summary: computation_cost: 1000000, storage_cost: 9135200, storage_rebate: 2595780, non_refundable_storage_fee: 26220 - -task 4 'run'. lines 57-57: -created: object(4,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2728400, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 5 'run'. lines 59-59: -created: object(5,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2728400, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 6 'run'. lines 61-61: -created: object(6,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2728400, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 7 'run'. lines 63-63: -created: object(7,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 2728400, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 8 'view-object'. lines 65-65: -Owner: Account Address ( A ) -Version: 5 -Contents: A0::m::Canary {id: sui::object::UID {id: sui::object::ID {bytes: fake(4,0)}}, addr: vector[55u8, 99u8, 53u8, 56u8, 50u8, 49u8, 97u8, 97u8, 54u8, 56u8, 54u8, 55u8, 100u8, 97u8, 48u8, 101u8, 102u8, 97u8, 55u8, 101u8, 50u8, 54u8, 48u8, 54u8, 101u8, 56u8, 97u8, 102u8, 49u8, 54u8, 52u8, 52u8, 100u8, 97u8, 48u8, 54u8, 55u8, 49u8, 99u8, 52u8, 49u8, 102u8, 100u8, 57u8, 51u8, 52u8, 56u8, 97u8, 98u8, 97u8, 97u8, 51u8, 54u8, 49u8, 57u8, 101u8, 97u8, 53u8, 49u8, 100u8, 57u8, 99u8, 100u8, 97u8]} - -task 9 'view-object'. lines 67-67: -Owner: Account Address ( A ) -Version: 6 -Contents: A0::m::Canary {id: sui::object::UID {id: sui::object::ID {bytes: fake(5,0)}}, addr: vector[55u8, 99u8, 53u8, 56u8, 50u8, 49u8, 97u8, 97u8, 54u8, 56u8, 54u8, 55u8, 100u8, 97u8, 48u8, 101u8, 102u8, 97u8, 55u8, 101u8, 50u8, 54u8, 48u8, 54u8, 101u8, 56u8, 97u8, 102u8, 49u8, 54u8, 52u8, 52u8, 100u8, 97u8, 48u8, 54u8, 55u8, 49u8, 99u8, 52u8, 49u8, 102u8, 100u8, 57u8, 51u8, 52u8, 56u8, 97u8, 98u8, 97u8, 97u8, 51u8, 54u8, 49u8, 57u8, 101u8, 97u8, 53u8, 49u8, 100u8, 57u8, 99u8, 100u8, 97u8]} - -task 10 'view-object'. lines 69-69: -Owner: Account Address ( A ) -Version: 7 -Contents: A0::m::Canary {id: sui::object::UID {id: sui::object::ID {bytes: fake(6,0)}}, addr: vector[55u8, 99u8, 53u8, 56u8, 50u8, 49u8, 97u8, 97u8, 54u8, 56u8, 54u8, 55u8, 100u8, 97u8, 48u8, 101u8, 102u8, 97u8, 55u8, 101u8, 50u8, 54u8, 48u8, 54u8, 101u8, 56u8, 97u8, 102u8, 49u8, 54u8, 52u8, 52u8, 100u8, 97u8, 48u8, 54u8, 55u8, 49u8, 99u8, 52u8, 49u8, 102u8, 100u8, 57u8, 51u8, 52u8, 56u8, 97u8, 98u8, 97u8, 97u8, 51u8, 54u8, 49u8, 57u8, 101u8, 97u8, 53u8, 49u8, 100u8, 57u8, 99u8, 100u8, 97u8]} - -task 11 'view-object'. lines 71-71: -Owner: Account Address ( A ) -Version: 8 -Contents: A0::m::Canary {id: sui::object::UID {id: sui::object::ID {bytes: fake(7,0)}}, addr: vector[100u8, 51u8, 100u8, 99u8, 49u8, 54u8, 99u8, 53u8, 53u8, 50u8, 100u8, 57u8, 50u8, 53u8, 50u8, 100u8, 97u8, 56u8, 97u8, 100u8, 57u8, 97u8, 98u8, 52u8, 101u8, 50u8, 50u8, 57u8, 49u8, 57u8, 100u8, 51u8, 54u8, 48u8, 98u8, 55u8, 100u8, 101u8, 97u8, 97u8, 52u8, 53u8, 100u8, 97u8, 57u8, 102u8, 51u8, 97u8, 54u8, 57u8, 52u8, 57u8, 50u8, 102u8, 98u8, 99u8, 99u8, 99u8, 57u8, 98u8, 102u8, 98u8, 48u8, 56u8]} diff --git a/crates/sui-adapter-transactional-tests/tests/upgrade/upgrade_ratchet.exp b/crates/sui-adapter-transactional-tests/tests/upgrade/upgrade_ratchet.exp deleted file mode 100644 index 4354d89f95f..00000000000 --- a/crates/sui-adapter-transactional-tests/tests/upgrade/upgrade_ratchet.exp +++ /dev/null @@ -1,64 +0,0 @@ -processed 15 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 6-12: -created: object(1,0), object(1,1) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 5646800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'upgrade'. lines 13-16: -created: object(2,0) -mutated: object(0,0), object(1,1) -gas summary: computation_cost: 1000000, storage_cost: 5016000, storage_rebate: 2595780, non_refundable_storage_fee: 26220 - -task 3 'run'. lines 18-20: -mutated: object(0,0), object(1,1) -gas summary: computation_cost: 1000000, storage_cost: 2622000, storage_rebate: 2595780, non_refundable_storage_fee: 26220 - -task 4 'upgrade'. lines 21-26: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::package::authorize_upgrade (function index 21) at offset 24, Abort Code: 1 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("package") }, function: 21, instruction: 24, function_name: Some("authorize_upgrade") }, 1), source: Some(VMError { major_status: ABORTED, sub_status: Some(1), message: Some("sui::package::authorize_upgrade at offset 24"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("package") }), indices: [], offsets: [(FunctionDefinitionIndex(21), 24)] }), command: Some(0) } } - -task 5 'upgrade'. lines 27-32: -created: object(5,0) -mutated: object(0,0), object(1,1) -gas summary: computation_cost: 1000000, storage_cost: 5016000, storage_rebate: 2595780, non_refundable_storage_fee: 26220 - -task 6 'upgrade'. lines 33-36: -created: object(6,0) -mutated: object(0,0), object(1,1) -gas summary: computation_cost: 1000000, storage_cost: 5016000, storage_rebate: 2595780, non_refundable_storage_fee: 26220 - -task 7 'run'. lines 38-40: -mutated: object(0,0), object(1,1) -gas summary: computation_cost: 1000000, storage_cost: 2622000, storage_rebate: 2595780, non_refundable_storage_fee: 26220 - -task 8 'upgrade'. lines 41-46: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::package::authorize_upgrade (function index 21) at offset 24, Abort Code: 1 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("package") }, function: 21, instruction: 24, function_name: Some("authorize_upgrade") }, 1), source: Some(VMError { major_status: ABORTED, sub_status: Some(1), message: Some("sui::package::authorize_upgrade at offset 24"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("package") }), indices: [], offsets: [(FunctionDefinitionIndex(21), 24)] }), command: Some(0) } } - -task 9 'upgrade'. lines 47-52: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::package::authorize_upgrade (function index 21) at offset 24, Abort Code: 1 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("package") }, function: 21, instruction: 24, function_name: Some("authorize_upgrade") }, 1), source: Some(VMError { major_status: ABORTED, sub_status: Some(1), message: Some("sui::package::authorize_upgrade at offset 24"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("package") }), indices: [], offsets: [(FunctionDefinitionIndex(21), 24)] }), command: Some(0) } } - -task 10 'upgrade'. lines 53-58: -created: object(10,0) -mutated: object(0,0), object(1,1) -gas summary: computation_cost: 1000000, storage_cost: 5016000, storage_rebate: 2595780, non_refundable_storage_fee: 26220 - -task 11 'run'. lines 59-61: -Error: Transaction Effects Status: Move Runtime Abort. Location: sui::package::restrict (function index 23) at offset 10, Abort Code: 1 -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MoveAbort(MoveLocation { module: ModuleId { address: sui, name: Identifier("package") }, function: 23, instruction: 10, function_name: Some("restrict") }, 1), source: Some(VMError { major_status: ABORTED, sub_status: Some(1), message: Some("sui::package::restrict at offset 10"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("package") }), indices: [], offsets: [(FunctionDefinitionIndex(23), 10)] }), command: Some(0) } } - -task 12 'run'. lines 62-62: -mutated: object(0,0) -deleted: object(1,1) -gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 2595780, non_refundable_storage_fee: 26220 - -task 13 'view-object'. lines 64-66: -No object at id 1,1 - -task 14 'upgrade'. lines 67-70: -Error: INVALID TEST. Could not load object argument object(1,1) diff --git a/crates/sui-analytics-indexer-derive/Cargo.toml b/crates/sui-analytics-indexer-derive/Cargo.toml deleted file mode 100644 index 767aff8acd2..00000000000 --- a/crates/sui-analytics-indexer-derive/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "sui-analytics-indexer-derive" -version.workspace = true -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2.workspace = true -quote.workspace = true -syn.workspace = true diff --git a/crates/sui-analytics-indexer-derive/src/lib.rs b/crates/sui-analytics-indexer-derive/src/lib.rs deleted file mode 100644 index aee7dd9042b..00000000000 --- a/crates/sui-analytics-indexer-derive/src/lib.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use proc_macro::TokenStream; -use quote::quote; -use syn::{parse_macro_input, Data, DeriveInput, Fields}; - -#[proc_macro_derive(SerializeParquet)] -pub fn schema_derive(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - let struct_name = &input.ident; - let (schema, getter_implementation) = match &input.data { - Data::Struct(data_struct) => match &data_struct.fields { - Fields::Named(fields) => { - let (schema_iter, getter_iter): (Vec<_>, Vec<_>) = fields - .named - .iter() - .enumerate() - .map(|(idx, field)| { - let field_name = field.ident.as_ref().unwrap().to_string(); - ( - format!("\"{}\".to_string()", field_name), - format!( - "if idx == {} {{ return self.{}.clone().into(); }}", - idx, field_name - ), - ) - }) - .unzip(); - (schema_iter.join(", "), getter_iter.join("\n")) - } - _ => panic!("not supported struct for parquet serialization"), - }, - _ => panic!("not supported struct for parquet serialization"), - }; - let schema_tokens: proc_macro2::TokenStream = schema.parse().unwrap(); - let getter_implementation_tokens: proc_macro2::TokenStream = - getter_implementation.parse().unwrap(); - quote! { - impl ParquetSchema for #struct_name { - fn schema() -> Vec { - vec![#schema_tokens] - } - - fn get_column(&self, idx: usize) -> ParquetValue { - #getter_implementation_tokens - panic!("not supported column {:?}", idx); - } - } - } - .into() -} diff --git a/crates/sui-analytics-indexer/Cargo.toml b/crates/sui-analytics-indexer/Cargo.toml deleted file mode 100644 index bb3e4e813ef..00000000000 --- a/crates/sui-analytics-indexer/Cargo.toml +++ /dev/null @@ -1,63 +0,0 @@ -[package] -name = "sui-analytics-indexer" -version.workspace = true -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - - -[dependencies] -anyhow.workspace = true -async-trait.workspace = true -axum.workspace = true -bcs.workspace = true -byteorder.workspace = true -bytes.workspace = true -chrono.workspace = true -clap.workspace = true -csv.workspace = true -move-core-types.workspace = true -object_store.workspace = true -num_enum.workspace = true -prometheus.workspace = true -serde.workspace = true -thiserror.workspace = true -tracing.workspace = true -tokio = { workspace = true, features = ["full"] } -tokio-stream.workspace = true -url.workspace = true -serde_json.workspace = true -strum.workspace = true -strum_macros.workspace = true -parquet.workspace = true -arrow-array.workspace = true -fastcrypto = { workspace = true, features = ["copy_key"] } -mysten-metrics.workspace = true -sui-analytics-indexer-derive.workspace = true -sui-indexer.workspace = true -eyre.workspace = true -rocksdb.workspace = true -tempfile.workspace = true -sui-types.workspace = true -telemetry-subscribers.workspace = true -sui-rest-api.workspace = true -sui-storage.workspace = true -sui-config.workspace = true -typed-store-derive.workspace = true -typed-store.workspace = true -move-binary-format.workspace = true -move-bytecode-utils.workspace = true -sui-json-rpc-types.workspace = true -sui-package-resolver.workspace = true -simulacrum.workspace = true -arrow = { version = "50.0.0"} -gcp-bigquery-client = "0.18.0" -snowflake-api = { version = "0.6.0" } -tap = { version = "1.0.1", features = [] } - -[dev-dependencies] - -[[bin]] -name = "sui-analytics-indexer" -path = "src/main.rs" diff --git a/crates/sui-analytics-indexer/src/errors.rs b/crates/sui-analytics-indexer/src/errors.rs deleted file mode 100644 index 005e341eba2..00000000000 --- a/crates/sui-analytics-indexer/src/errors.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum AnalyticsIndexerError { - #[error("Generic error: `{0}`")] - GenericError(String), - #[error("Failed to retrieve the current directory.")] - CurrentDirError, -} diff --git a/crates/sui-analytics-indexer/src/handlers/checkpoint_handler.rs b/crates/sui-analytics-indexer/src/handlers/checkpoint_handler.rs deleted file mode 100644 index 6a20eb728d0..00000000000 --- a/crates/sui-analytics-indexer/src/handlers/checkpoint_handler.rs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use anyhow::Result; -use fastcrypto::traits::EncodeDecodeBase64; -use sui_indexer::framework::Handler; -use sui_rest_api::{CheckpointData, CheckpointTransaction}; -use sui_types::{ - effects::TransactionEffectsAPI, - messages_checkpoint::{CertifiedCheckpointSummary, CheckpointSummary}, - transaction::TransactionDataAPI, -}; - -use crate::{handlers::AnalyticsHandler, tables::CheckpointEntry, FileType}; - -pub struct CheckpointHandler { - checkpoints: Vec, -} - -#[async_trait::async_trait] -impl Handler for CheckpointHandler { - fn name(&self) -> &str { - "checkpoint" - } - async fn process_checkpoint(&mut self, checkpoint_data: &CheckpointData) -> Result<()> { - let CheckpointData { - checkpoint_summary, - transactions: checkpoint_transactions, - .. - } = checkpoint_data; - self.process_checkpoint_transactions(checkpoint_summary, checkpoint_transactions); - Ok(()) - } -} - -#[async_trait::async_trait] -impl AnalyticsHandler for CheckpointHandler { - fn read(&mut self) -> Result> { - let cloned = self.checkpoints.clone(); - self.checkpoints.clear(); - Ok(cloned) - } - - fn file_type(&self) -> Result { - Ok(FileType::Checkpoint) - } -} - -impl CheckpointHandler { - pub fn new() -> Self { - CheckpointHandler { - checkpoints: vec![], - } - } - fn process_checkpoint_transactions( - &mut self, - summary: &CertifiedCheckpointSummary, - checkpoint_transactions: &[CheckpointTransaction], - ) { - let CheckpointSummary { - epoch, - sequence_number, - network_total_transactions, - previous_digest, - epoch_rolling_gas_cost_summary, - timestamp_ms, - end_of_epoch_data, - .. - } = summary.data(); - - let total_gas_cost = epoch_rolling_gas_cost_summary.computation_cost as i64 - + epoch_rolling_gas_cost_summary.storage_cost as i64 - - epoch_rolling_gas_cost_summary.storage_rebate as i64; - let total_transaction_blocks = checkpoint_transactions.len() as u64; - let mut total_transactions: u64 = 0; - let mut total_successful_transaction_blocks: u64 = 0; - let mut total_successful_transactions: u64 = 0; - for checkpoint_transaction in checkpoint_transactions { - let txn_data = checkpoint_transaction.transaction.transaction_data(); - let cmds = txn_data.kind().num_commands() as u64; - total_transactions += cmds; - if checkpoint_transaction.effects.status().is_ok() { - total_successful_transaction_blocks += 1; - total_successful_transactions += cmds; - } - } - - let checkpoint_entry = CheckpointEntry { - sequence_number: *sequence_number, - checkpoint_digest: summary.digest().base58_encode(), - previous_checkpoint_digest: previous_digest.map(|d| d.base58_encode()), - epoch: *epoch, - end_of_epoch: end_of_epoch_data.is_some(), - total_gas_cost, - computation_cost: epoch_rolling_gas_cost_summary.computation_cost, - storage_cost: epoch_rolling_gas_cost_summary.storage_cost, - storage_rebate: epoch_rolling_gas_cost_summary.storage_rebate, - non_refundable_storage_fee: epoch_rolling_gas_cost_summary.non_refundable_storage_fee, - total_transaction_blocks, - total_transactions, - total_successful_transaction_blocks, - total_successful_transactions, - network_total_transaction: *network_total_transactions, - timestamp_ms: *timestamp_ms, - validator_signature: summary.auth_sig().signature.encode_base64(), - }; - self.checkpoints.push(checkpoint_entry); - } -} diff --git a/crates/sui-analytics-indexer/src/handlers/mod.rs b/crates/sui-analytics-indexer/src/handlers/mod.rs deleted file mode 100644 index 4bccc5aabff..00000000000 --- a/crates/sui-analytics-indexer/src/handlers/mod.rs +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::{BTreeMap, BTreeSet}; - -use anyhow::{anyhow, Result}; -use move_core_types::{ - annotated_value::{MoveStruct, MoveTypeLayout, MoveValue}, - language_storage::{StructTag, TypeTag}, -}; -use sui_indexer::framework::Handler; -use sui_package_resolver::{PackageStore, Resolver}; -use sui_types::{ - base_types::ObjectID, - effects::{TransactionEffects, TransactionEffectsAPI}, - object::{bounded_visitor::BoundedVisitor, Object, Owner}, - transaction::{TransactionData, TransactionDataAPI}, -}; - -use crate::{ - tables::{InputObjectKind, ObjectStatus, OwnerType}, - FileType, -}; - -pub mod checkpoint_handler; -pub mod df_handler; -pub mod event_handler; -pub mod move_call_handler; -pub mod object_handler; -pub mod package_handler; -pub mod transaction_handler; -pub mod transaction_objects_handler; -pub mod wrapped_object_handler; - -const WRAPPED_INDEXING_DISALLOW_LIST: [&str; 4] = [ - "0x1::string::String", - "0x1::ascii::String", - "0x2::url::Url", - "0x2::object::ID", -]; - -#[async_trait::async_trait] -pub trait AnalyticsHandler: Handler { - /// Read back rows which are ready to be persisted. This function - /// will be invoked by the analytics processor after every call to - /// process_checkpoint - fn read(&mut self) -> Result>; - /// Type of data being written by this processor i.e. checkpoint, object, - /// etc - fn file_type(&self) -> Result; -} - -fn initial_shared_version(object: &Object) -> Option { - match object.owner { - Owner::Shared { - initial_shared_version, - } => Some(initial_shared_version.value()), - _ => None, - } -} - -fn get_owner_type(object: &Object) -> OwnerType { - match object.owner { - Owner::AddressOwner(_) => OwnerType::AddressOwner, - Owner::ObjectOwner(_) => OwnerType::ObjectOwner, - Owner::Shared { .. } => OwnerType::Shared, - Owner::Immutable => OwnerType::Immutable, - } -} - -fn get_owner_address(object: &Object) -> Option { - match object.owner { - Owner::AddressOwner(address) => Some(address.to_string()), - Owner::ObjectOwner(address) => Some(address.to_string()), - Owner::Shared { .. } => None, - Owner::Immutable => None, - } -} - -// Helper class to track input object kind. -// Build sets of object ids for input, shared input and gas coin objects as -// defined in the transaction data. -// Input objects include coins and shared. -struct InputObjectTracker { - shared: BTreeSet, - coins: BTreeSet, - input: BTreeSet, -} - -impl InputObjectTracker { - fn new(txn_data: &TransactionData) -> Self { - let shared: BTreeSet = txn_data - .shared_input_objects() - .iter() - .map(|shared_io| shared_io.id()) - .collect(); - let coins: BTreeSet = txn_data.gas().iter().map(|obj_ref| obj_ref.0).collect(); - let input: BTreeSet = txn_data - .input_objects() - .expect("Input objects must be valid") - .iter() - .map(|io_kind| io_kind.object_id()) - .collect(); - Self { - shared, - coins, - input, - } - } - - fn get_input_object_kind(&self, object_id: &ObjectID) -> Option { - if self.coins.contains(object_id) { - Some(InputObjectKind::GasCoin) - } else if self.shared.contains(object_id) { - Some(InputObjectKind::SharedInput) - } else if self.input.contains(object_id) { - Some(InputObjectKind::Input) - } else { - None - } - } -} - -// Helper class to track object status. -// Build sets of object ids for created, mutated and deleted objects as reported -// in the transaction effects. -struct ObjectStatusTracker { - created: BTreeSet, - mutated: BTreeSet, - deleted: BTreeSet, -} - -impl ObjectStatusTracker { - fn new(effects: &TransactionEffects) -> Self { - let created: BTreeSet = effects - .created() - .iter() - .map(|(obj_ref, _)| obj_ref.0) - .collect(); - let mutated: BTreeSet = effects - .mutated() - .iter() - .chain(effects.unwrapped().iter()) - .map(|(obj_ref, _)| obj_ref.0) - .collect(); - let deleted: BTreeSet = effects - .all_tombstones() - .into_iter() - .map(|(id, _)| id) - .collect(); - Self { - created, - mutated, - deleted, - } - } - - fn get_object_status(&self, object_id: &ObjectID) -> Option { - if self.mutated.contains(object_id) { - Some(ObjectStatus::Mutated) - } else if self.deleted.contains(object_id) { - Some(ObjectStatus::Deleted) - } else if self.created.contains(object_id) { - Some(ObjectStatus::Created) - } else { - None - } - } -} - -async fn get_move_struct( - struct_tag: &StructTag, - contents: &[u8], - resolver: &Resolver, -) -> Result { - let move_struct = match resolver - .type_layout(TypeTag::Struct(Box::new(struct_tag.clone()))) - .await? - { - MoveTypeLayout::Struct(move_struct_layout) => { - BoundedVisitor::deserialize_struct(contents, &move_struct_layout) - } - _ => Err(anyhow!("Object is not a move struct")), - }?; - Ok(move_struct) -} - -#[derive(Debug, Default)] -pub struct WrappedStruct { - object_id: Option, - struct_tag: Option, -} - -fn parse_struct( - path: &str, - move_struct: MoveStruct, - all_structs: &mut BTreeMap, -) { - let mut wrapped_struct = WrappedStruct { - struct_tag: Some(move_struct.type_), - ..Default::default() - }; - for (k, v) in move_struct.fields { - parse_struct_field( - &format!("{}.{}", path, &k), - v, - &mut wrapped_struct, - all_structs, - ); - } - all_structs.insert(path.to_string(), wrapped_struct); -} - -fn parse_struct_field( - path: &str, - move_value: MoveValue, - curr_struct: &mut WrappedStruct, - all_structs: &mut BTreeMap, -) { - match move_value { - MoveValue::Struct(move_struct) => { - let values = move_struct - .fields - .iter() - .map(|(id, value)| (id.to_string(), value)) - .collect::>(); - let struct_name = format!( - "0x{}::{}::{}", - move_struct.type_.address.short_str_lossless(), - move_struct.type_.module, - move_struct.type_.name - ); - if "0x2::object::UID" == struct_name { - if let Some(MoveValue::Struct(id_struct)) = values.get("id").cloned() { - let id_values = id_struct - .fields - .iter() - .map(|(id, value)| (id.to_string(), value)) - .collect::>(); - if let Some(MoveValue::Address(address) | MoveValue::Signer(address)) = - id_values.get("bytes").cloned() - { - curr_struct.object_id = Some(ObjectID::from_address(*address)) - } - } - } else if "0x1::option::Option" == struct_name { - // Option in sui move is implemented as vector of size 1 - if let Some(MoveValue::Vector(vec_values)) = values.get("vec").cloned() { - if let Some(first_value) = vec_values.first() { - parse_struct_field( - &format!("{}[0]", path), - first_value.clone(), - curr_struct, - all_structs, - ); - } - } - } else if !WRAPPED_INDEXING_DISALLOW_LIST.contains(&&*struct_name) { - // Do not index most common struct types i.e. string, url, etc - parse_struct(path, move_struct, all_structs) - } - } - MoveValue::Vector(fields) => { - for (index, field) in fields.iter().enumerate() { - parse_struct_field( - &format!("{}[{}]", path, &index), - field.clone(), - curr_struct, - all_structs, - ); - } - } - _ => {} - } -} - -#[cfg(test)] -mod tests { - use std::{collections::BTreeMap, str::FromStr}; - - use move_core_types::{ - account_address::AccountAddress, - annotated_value::{MoveStruct, MoveValue}, - identifier::Identifier, - language_storage::StructTag, - }; - use sui_types::base_types::ObjectID; - - use crate::handlers::parse_struct; - - #[tokio::test] - async fn test_wrapped_object_parsing() -> anyhow::Result<()> { - let uid_field = MoveValue::Struct(MoveStruct { - type_: StructTag::from_str("0x2::object::UID")?, - fields: vec![( - Identifier::from_str("id")?, - MoveValue::Struct(MoveStruct { - type_: StructTag::from_str("0x2::object::ID")?, - fields: vec![( - Identifier::from_str("bytes")?, - MoveValue::Signer(AccountAddress::from_hex_literal("0x300")?), - )], - }), - )], - }); - let balance_field = MoveValue::Struct(MoveStruct { - type_: StructTag::from_str("0x2::balance::Balance")?, - fields: vec![(Identifier::from_str("value")?, MoveValue::U32(10))], - }); - let move_struct = MoveStruct { - type_: StructTag::from_str("0x2::test::Test")?, - fields: vec![ - (Identifier::from_str("id")?, uid_field), - (Identifier::from_str("principal")?, balance_field), - ], - }; - let mut all_structs = BTreeMap::new(); - parse_struct("$", move_struct, &mut all_structs); - assert_eq!( - all_structs.get("$").unwrap().object_id, - Some(ObjectID::from_hex_literal("0x300")?) - ); - assert_eq!( - all_structs.get("$.principal").unwrap().struct_tag, - Some(StructTag::from_str("0x2::balance::Balance")?) - ); - Ok(()) - } -} diff --git a/crates/sui-analytics-indexer/src/lib.rs b/crates/sui-analytics-indexer/src/lib.rs deleted file mode 100644 index 38395a2b5c2..00000000000 --- a/crates/sui-analytics-indexer/src/lib.rs +++ /dev/null @@ -1,916 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ops::Range, path::PathBuf}; - -use anyhow::{anyhow, Result}; -use arrow_array::{Array, Int32Array}; -use clap::*; -use gcp_bigquery_client::{model::query_request::QueryRequest, Client}; -use num_enum::{IntoPrimitive, TryFromPrimitive}; -use object_store::path::Path; -use serde::{Deserialize, Serialize}; -use snowflake_api::{QueryResult, SnowflakeApi}; -use strum_macros::EnumIter; -use sui_config::object_storage_config::ObjectStoreConfig; -use sui_indexer::framework::Handler; -use sui_rest_api::CheckpointData; -use sui_storage::object_store::util::{ - find_all_dirs_with_epoch_prefix, find_all_files_with_epoch_prefix, -}; -use sui_types::{ - base_types::EpochId, dynamic_field::DynamicFieldType, - messages_checkpoint::CheckpointSequenceNumber, -}; -use tracing::info; - -use crate::{ - analytics_metrics::AnalyticsMetrics, - analytics_processor::AnalyticsProcessor, - handlers::{ - checkpoint_handler::CheckpointHandler, df_handler::DynamicFieldHandler, - event_handler::EventHandler, move_call_handler::MoveCallHandler, - object_handler::ObjectHandler, package_handler::PackageHandler, - transaction_handler::TransactionHandler, - transaction_objects_handler::TransactionObjectsHandler, - wrapped_object_handler::WrappedObjectHandler, AnalyticsHandler, - }, - tables::{ - CheckpointEntry, DynamicFieldEntry, EventEntry, InputObjectKind, MoveCallEntry, - MovePackageEntry, ObjectEntry, ObjectStatus, OwnerType, TransactionEntry, - TransactionObjectEntry, WrappedObjectEntry, - }, - writers::{csv_writer::CSVWriter, parquet_writer::ParquetWriter, AnalyticsWriter}, -}; - -pub mod analytics_metrics; -pub mod analytics_processor; -pub mod errors; -mod handlers; -mod package_store; -pub mod tables; -mod writers; - -const EPOCH_DIR_PREFIX: &str = "epoch_"; -const CHECKPOINT_DIR_PREFIX: &str = "checkpoints"; -const OBJECT_DIR_PREFIX: &str = "objects"; -const TRANSACTION_DIR_PREFIX: &str = "transactions"; -const EVENT_DIR_PREFIX: &str = "events"; -const TRANSACTION_OBJECT_DIR_PREFIX: &str = "transaction_objects"; -const MOVE_CALL_PREFIX: &str = "move_call"; -const MOVE_PACKAGE_PREFIX: &str = "move_package"; -const DYNAMIC_FIELD_PREFIX: &str = "dynamic_field"; - -const WRAPPED_OBJECT_PREFIX: &str = "wrapped_object"; - -#[derive(Parser, Clone, Debug)] -#[clap( - name = "Sui Analytics Indexer", - about = "Indexer service to upload data for the analytics pipeline.", - rename_all = "kebab-case" -)] -pub struct AnalyticsIndexerConfig { - /// The url of the checkpoint client to connect to. - #[clap(long)] - pub rest_url: String, - /// The url of the metrics client to connect to. - #[clap(long, default_value = "127.0.0.1", global = true)] - pub client_metric_host: String, - /// The port of the metrics client to connect to. - #[clap(long, default_value = "8081", global = true)] - pub client_metric_port: u16, - /// Directory to contain the temporary files for checkpoint entries. - #[clap(long, global = true, default_value = "/tmp")] - pub checkpoint_dir: PathBuf, - /// Number of checkpoints to process before uploading to the datastore. - #[clap(long, default_value = "10000", global = true)] - pub checkpoint_interval: u64, - /// Maximum file size in mb before uploading to the datastore. - #[clap(long, default_value = "100", global = true)] - pub max_file_size_mb: u64, - /// Checkpoint sequence number to start the download from - #[clap(long, default_value = None, global = true)] - pub starting_checkpoint_seq_num: Option, - /// Time to process in seconds before uploading to the datastore. - #[clap(long, default_value = "600", global = true)] - pub time_interval_s: u64, - // Remote object store where data gets written to - #[command(flatten)] - pub remote_store_config: ObjectStoreConfig, - // Remote object store path prefix to use while writing - #[clap(long, default_value = None, global = true)] - pub remote_store_path_prefix: Option, - // File format to store data in i.e. csv, parquet, etc - #[clap(long, value_enum, default_value = "csv", global = true)] - pub file_format: FileFormat, - // Type of data to write i.e. checkpoint, object, transaction, etc - #[clap(long, value_enum, long, global = true)] - pub file_type: FileType, - // Directory to contain the package cache for pipelines - #[clap( - long, - value_enum, - long, - global = true, - default_value = "/opt/sui/db/package_cache" - )] - pub package_cache_path: PathBuf, - #[clap(long, default_value = None, global = true)] - pub bq_service_account_key_file: Option, - #[clap(long, default_value = None, global = true)] - pub bq_project_id: Option, - #[clap(long, default_value = None, global = true)] - pub bq_dataset_id: Option, - #[clap(long, default_value = None, global = true)] - pub bq_table_id: Option, - #[clap(long, default_value = None, global = true)] - pub bq_checkpoint_col_id: Option, - #[clap(long, global = true)] - pub report_bq_max_table_checkpoint: bool, - #[clap(long, default_value = None, global = true)] - pub sf_account_identifier: Option, - #[clap(long, default_value = None, global = true)] - pub sf_warehouse: Option, - #[clap(long, default_value = None, global = true)] - pub sf_database: Option, - #[clap(long, default_value = None, global = true)] - pub sf_schema: Option, - #[clap(long, default_value = None, global = true)] - pub sf_username: Option, - #[clap(long, default_value = None, global = true)] - pub sf_role: Option, - #[clap(long, default_value = None, global = true)] - pub sf_password: Option, - #[clap(long, default_value = None, global = true)] - pub sf_table_id: Option, - #[clap(long, default_value = None, global = true)] - pub sf_checkpoint_col_id: Option, - #[clap(long, global = true)] - pub report_sf_max_table_checkpoint: bool, -} - -#[async_trait::async_trait] -pub trait MaxCheckpointReader: Send + Sync + 'static { - async fn max_checkpoint(&self) -> Result; -} - -struct SnowflakeMaxCheckpointReader { - query: String, - api: SnowflakeApi, -} - -impl SnowflakeMaxCheckpointReader { - pub async fn new( - account_identifier: &str, - warehouse: &str, - database: &str, - schema: &str, - user: &str, - role: &str, - passwd: &str, - table_id: &str, - col_id: &str, - ) -> anyhow::Result { - let api = SnowflakeApi::with_password_auth( - account_identifier, - Some(warehouse), - Some(database), - Some(schema), - user, - Some(role), - passwd, - ) - .expect("Failed to build sf api client"); - Ok(SnowflakeMaxCheckpointReader { - query: format!("SELECT max({}) from {}", col_id, table_id), - api, - }) - } -} - -#[async_trait::async_trait] -impl MaxCheckpointReader for SnowflakeMaxCheckpointReader { - async fn max_checkpoint(&self) -> Result { - let res = self.api.exec(&self.query).await?; - match res { - QueryResult::Arrow(a) => { - if let Some(record_batch) = a.first() { - let col = record_batch.column(0); - let col_array = col - .as_any() - .downcast_ref::() - .expect("Failed to downcast arrow column"); - Ok(col_array.value(0) as i64) - } else { - Ok(-1) - } - } - QueryResult::Json(_j) => Err(anyhow!("Unexpected query result")), - QueryResult::Empty => Err(anyhow!("Unexpected query result")), - } - } -} - -struct BQMaxCheckpointReader { - query: String, - project_id: String, - client: Client, -} - -impl BQMaxCheckpointReader { - pub async fn new( - key_path: &str, - project_id: &str, - dataset_id: &str, - table_id: &str, - col_id: &str, - ) -> anyhow::Result { - Ok(BQMaxCheckpointReader { - query: format!( - "SELECT max({}) from `{}.{}.{}`", - col_id, project_id, dataset_id, table_id - ), - client: Client::from_service_account_key_file(key_path).await?, - project_id: project_id.to_string(), - }) - } -} - -#[async_trait::async_trait] -impl MaxCheckpointReader for BQMaxCheckpointReader { - async fn max_checkpoint(&self) -> Result { - let mut result = self - .client - .job() - .query(&self.project_id, QueryRequest::new(&self.query)) - .await?; - if result.next_row() { - let max_checkpoint = result.get_i64(0)?.ok_or(anyhow!("No rows returned"))?; - Ok(max_checkpoint) - } else { - Ok(-1) - } - } -} - -struct NoOpCheckpointReader; - -#[async_trait::async_trait] -impl MaxCheckpointReader for NoOpCheckpointReader { - async fn max_checkpoint(&self) -> Result { - Ok(-1) - } -} - -#[derive( - Copy, - Clone, - Debug, - Eq, - PartialEq, - Parser, - strum_macros::Display, - ValueEnum, - Serialize, - Deserialize, - TryFromPrimitive, - IntoPrimitive, - EnumIter, -)] -#[repr(u8)] -pub enum FileFormat { - CSV = 0, - PARQUET = 1, -} - -impl FileFormat { - pub fn file_suffix(&self) -> &str { - match self { - FileFormat::CSV => "csv", - FileFormat::PARQUET => "parquet", - } - } -} - -#[derive( - Copy, - Clone, - Debug, - Eq, - PartialEq, - Serialize, - Deserialize, - TryFromPrimitive, - IntoPrimitive, - EnumIter, - ValueEnum, -)] -#[repr(u8)] -pub enum FileType { - Checkpoint = 0, - Object, - Transaction, - TransactionObjects, - Event, - MoveCall, - MovePackage, - DynamicField, - WrappedObject, -} - -impl FileType { - pub fn dir_prefix(&self) -> Path { - match self { - FileType::Checkpoint => Path::from(CHECKPOINT_DIR_PREFIX), - FileType::Transaction => Path::from(TRANSACTION_DIR_PREFIX), - FileType::TransactionObjects => Path::from(TRANSACTION_OBJECT_DIR_PREFIX), - FileType::Object => Path::from(OBJECT_DIR_PREFIX), - FileType::Event => Path::from(EVENT_DIR_PREFIX), - FileType::MoveCall => Path::from(MOVE_CALL_PREFIX), - FileType::MovePackage => Path::from(MOVE_PACKAGE_PREFIX), - FileType::DynamicField => Path::from(DYNAMIC_FIELD_PREFIX), - FileType::WrappedObject => Path::from(WRAPPED_OBJECT_PREFIX), - } - } - - pub fn file_path( - &self, - file_format: FileFormat, - epoch_num: EpochId, - checkpoint_range: Range, - ) -> Path { - self.dir_prefix() - .child(format!("{}{}", EPOCH_DIR_PREFIX, epoch_num)) - .child(format!( - "{}_{}.{}", - checkpoint_range.start, - checkpoint_range.end, - file_format.file_suffix() - )) - } -} - -pub enum ParquetValue { - U64(u64), - Str(String), - Bool(bool), - I64(i64), - OptionU64(Option), - OptionStr(Option), -} - -impl From for ParquetValue { - fn from(value: u64) -> Self { - Self::U64(value) - } -} - -impl From for ParquetValue { - fn from(value: i64) -> Self { - Self::I64(value) - } -} - -impl From for ParquetValue { - fn from(value: String) -> Self { - Self::Str(value) - } -} - -impl From> for ParquetValue { - fn from(value: Option) -> Self { - Self::OptionU64(value) - } -} - -impl From> for ParquetValue { - fn from(value: Option) -> Self { - Self::OptionStr(value) - } -} - -impl From for ParquetValue { - fn from(value: bool) -> Self { - Self::Bool(value) - } -} - -impl From for ParquetValue { - fn from(value: OwnerType) -> Self { - Self::Str(value.to_string()) - } -} - -impl From> for ParquetValue { - fn from(value: Option) -> Self { - value.map(|v| v.to_string()).into() - } -} - -impl From for ParquetValue { - fn from(value: ObjectStatus) -> Self { - Self::Str(value.to_string()) - } -} - -impl From> for ParquetValue { - fn from(value: Option) -> Self { - Self::OptionStr(value.map(|v| v.to_string())) - } -} - -impl From> for ParquetValue { - fn from(value: Option) -> Self { - Self::OptionStr(value.map(|v| v.to_string())) - } -} - -impl From for ParquetValue { - fn from(value: DynamicFieldType) -> Self { - Self::Str(value.to_string()) - } -} - -impl From> for ParquetValue { - fn from(value: Option) -> Self { - Self::OptionStr(value.map(|v| v.to_string())) - } -} - -pub trait ParquetSchema { - fn schema() -> Vec; - - fn get_column(&self, idx: usize) -> ParquetValue; -} - -#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] -pub struct FileMetadata { - pub file_type: FileType, - pub file_format: FileFormat, - pub epoch_num: u64, - pub checkpoint_seq_range: Range, -} - -impl FileMetadata { - fn new( - file_type: FileType, - file_format: FileFormat, - epoch_num: u64, - checkpoint_seq_range: Range, - ) -> FileMetadata { - FileMetadata { - file_type, - file_format, - epoch_num, - checkpoint_seq_range, - } - } - - pub fn file_path(&self) -> Path { - self.file_type.file_path( - self.file_format, - self.epoch_num, - self.checkpoint_seq_range.clone(), - ) - } -} - -pub struct Processor { - pub processor: Box, - pub starting_checkpoint_seq_num: CheckpointSequenceNumber, -} - -#[async_trait::async_trait] -impl Handler for Processor { - #[inline] - fn name(&self) -> &str { - self.processor.name() - } - - #[inline] - async fn process_checkpoint(&mut self, checkpoint_data: &CheckpointData) -> Result<()> { - self.processor.process_checkpoint(checkpoint_data).await - } -} - -impl Processor { - pub async fn new( - handler: Box>, - writer: Box>, - max_checkpoint_reader: Box, - starting_checkpoint_seq_num: CheckpointSequenceNumber, - metrics: AnalyticsMetrics, - config: AnalyticsIndexerConfig, - ) -> Result { - let processor = Box::new( - AnalyticsProcessor::new( - handler, - writer, - max_checkpoint_reader, - starting_checkpoint_seq_num, - metrics, - config, - ) - .await?, - ); - - Ok(Processor { - processor, - starting_checkpoint_seq_num, - }) - } - - pub fn last_committed_checkpoint(&self) -> Option { - Some(self.starting_checkpoint_seq_num.saturating_sub(1)).filter(|x| *x > 0) - } -} - -pub async fn read_store_for_checkpoint( - remote_store_config: ObjectStoreConfig, - file_type: FileType, - dir_prefix: Option, -) -> Result { - let remote_object_store = remote_store_config.make()?; - let remote_store_is_empty = remote_object_store - .list_with_delimiter(None) - .await - .expect("Failed to read remote analytics store") - .common_prefixes - .is_empty(); - info!("Remote store is empty: {remote_store_is_empty}"); - let file_type_prefix = file_type.dir_prefix(); - let prefix = join_paths(dir_prefix, &file_type_prefix); - let epoch_dirs = find_all_dirs_with_epoch_prefix(&remote_object_store, Some(&prefix)).await?; - let epoch = epoch_dirs.last_key_value().map(|(k, _v)| *k).unwrap_or(0); - let epoch_prefix = prefix.child(format!("epoch_{}", epoch)); - let checkpoints = - find_all_files_with_epoch_prefix(&remote_object_store, Some(&epoch_prefix)).await?; - let next_checkpoint_seq_num = checkpoints - .iter() - .max_by(|x, y| x.end.cmp(&y.end)) - .map(|r| r.end) - .unwrap_or(0); - Ok(next_checkpoint_seq_num) -} - -pub async fn make_max_checkpoint_reader( - config: &AnalyticsIndexerConfig, -) -> Result> { - let res: Box = if config.report_bq_max_table_checkpoint { - Box::new( - BQMaxCheckpointReader::new( - config - .bq_service_account_key_file - .as_ref() - .ok_or(anyhow!("Missing gcp key file"))?, - config - .bq_project_id - .as_ref() - .ok_or(anyhow!("Missing big query project id"))?, - config - .bq_dataset_id - .as_ref() - .ok_or(anyhow!("Missing big query dataset id"))?, - config - .bq_table_id - .as_ref() - .ok_or(anyhow!("Missing big query table id"))?, - config - .bq_checkpoint_col_id - .as_ref() - .ok_or(anyhow!("Missing big query checkpoint col id"))?, - ) - .await?, - ) - } else if config.report_sf_max_table_checkpoint { - Box::new( - SnowflakeMaxCheckpointReader::new( - config - .sf_account_identifier - .as_ref() - .ok_or(anyhow!("Missing sf account identifier"))?, - config - .sf_warehouse - .as_ref() - .ok_or(anyhow!("Missing sf warehouse"))?, - config - .sf_database - .as_ref() - .ok_or(anyhow!("Missing sf database"))?, - config - .sf_schema - .as_ref() - .ok_or(anyhow!("Missing sf schema"))?, - config - .sf_username - .as_ref() - .ok_or(anyhow!("Missing sf username"))?, - config.sf_role.as_ref().ok_or(anyhow!("Missing sf role"))?, - config - .sf_password - .as_ref() - .ok_or(anyhow!("Missing sf password"))?, - config - .sf_table_id - .as_ref() - .ok_or(anyhow!("Missing sf table id"))?, - config - .sf_checkpoint_col_id - .as_ref() - .ok_or(anyhow!("Missing sf checkpoint col id"))?, - ) - .await?, - ) - } else { - Box::new(NoOpCheckpointReader {}) - }; - Ok(res) -} - -pub async fn make_checkpoint_processor( - config: AnalyticsIndexerConfig, - metrics: AnalyticsMetrics, -) -> Result { - let handler: Box> = Box::new(CheckpointHandler::new()); - let starting_checkpoint_seq_num = - get_starting_checkpoint_seq_num(config.clone(), FileType::Checkpoint).await?; - let writer = make_writer::( - config.clone(), - FileType::Checkpoint, - starting_checkpoint_seq_num, - )?; - let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; - Processor::new::( - handler, - writer, - max_checkpoint_reader, - starting_checkpoint_seq_num, - metrics, - config, - ) - .await -} - -pub async fn make_transaction_processor( - config: AnalyticsIndexerConfig, - metrics: AnalyticsMetrics, -) -> Result { - let handler: Box> = Box::new(TransactionHandler::new()); - let starting_checkpoint_seq_num = - get_starting_checkpoint_seq_num(config.clone(), FileType::Transaction).await?; - let writer = make_writer::( - config.clone(), - FileType::Transaction, - starting_checkpoint_seq_num, - )?; - let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; - Processor::new::( - handler, - writer, - max_checkpoint_reader, - starting_checkpoint_seq_num, - metrics, - config, - ) - .await -} - -pub async fn make_object_processor( - config: AnalyticsIndexerConfig, - metrics: AnalyticsMetrics, -) -> Result { - let handler: Box> = Box::new(ObjectHandler::new( - &config.package_cache_path, - &config.rest_url, - )); - let starting_checkpoint_seq_num = - get_starting_checkpoint_seq_num(config.clone(), FileType::Object).await?; - let writer = make_writer::( - config.clone(), - FileType::Object, - starting_checkpoint_seq_num, - )?; - let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; - Processor::new::( - handler, - writer, - max_checkpoint_reader, - starting_checkpoint_seq_num, - metrics, - config, - ) - .await -} - -pub async fn make_event_processor( - config: AnalyticsIndexerConfig, - metrics: AnalyticsMetrics, -) -> Result { - let handler: Box> = Box::new(EventHandler::new( - &config.package_cache_path, - &config.rest_url, - )); - let starting_checkpoint_seq_num = - get_starting_checkpoint_seq_num(config.clone(), FileType::Event).await?; - let writer = - make_writer::(config.clone(), FileType::Event, starting_checkpoint_seq_num)?; - let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; - Processor::new::( - handler, - writer, - max_checkpoint_reader, - starting_checkpoint_seq_num, - metrics, - config, - ) - .await -} - -pub async fn make_transaction_objects_processor( - config: AnalyticsIndexerConfig, - metrics: AnalyticsMetrics, -) -> Result { - let starting_checkpoint_seq_num = - get_starting_checkpoint_seq_num(config.clone(), FileType::TransactionObjects).await?; - let handler = Box::new(TransactionObjectsHandler::new()); - let writer = make_writer( - config.clone(), - FileType::TransactionObjects, - starting_checkpoint_seq_num, - )?; - let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; - Processor::new::( - handler, - writer, - max_checkpoint_reader, - starting_checkpoint_seq_num, - metrics, - config, - ) - .await -} - -pub async fn make_move_package_processor( - config: AnalyticsIndexerConfig, - metrics: AnalyticsMetrics, -) -> Result { - let handler: Box> = Box::new(PackageHandler::new()); - let starting_checkpoint_seq_num = - get_starting_checkpoint_seq_num(config.clone(), FileType::MovePackage).await?; - let writer = make_writer::( - config.clone(), - FileType::MovePackage, - starting_checkpoint_seq_num, - )?; - let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; - Processor::new::( - handler, - writer, - max_checkpoint_reader, - starting_checkpoint_seq_num, - metrics, - config, - ) - .await -} - -pub async fn make_move_call_processor( - config: AnalyticsIndexerConfig, - metrics: AnalyticsMetrics, -) -> Result { - let starting_checkpoint_seq_num = - get_starting_checkpoint_seq_num(config.clone(), FileType::MoveCall).await?; - let handler: Box> = Box::new(MoveCallHandler::new()); - let writer = make_writer::( - config.clone(), - FileType::MoveCall, - starting_checkpoint_seq_num, - )?; - let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; - Processor::new::( - handler, - writer, - max_checkpoint_reader, - starting_checkpoint_seq_num, - metrics, - config, - ) - .await -} - -pub async fn make_dynamic_field_processor( - config: AnalyticsIndexerConfig, - metrics: AnalyticsMetrics, -) -> Result { - let starting_checkpoint_seq_num = - get_starting_checkpoint_seq_num(config.clone(), FileType::DynamicField).await?; - let handler: Box> = Box::new(DynamicFieldHandler::new( - &config.package_cache_path, - &config.rest_url, - )); - let writer = make_writer::( - config.clone(), - FileType::DynamicField, - starting_checkpoint_seq_num, - )?; - let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; - Processor::new::( - handler, - writer, - max_checkpoint_reader, - starting_checkpoint_seq_num, - metrics, - config, - ) - .await -} - -pub async fn make_wrapped_object_processor( - config: AnalyticsIndexerConfig, - metrics: AnalyticsMetrics, -) -> Result { - let starting_checkpoint_seq_num = - get_starting_checkpoint_seq_num(config.clone(), FileType::WrappedObject).await?; - let handler: Box> = Box::new( - WrappedObjectHandler::new(&config.package_cache_path, &config.rest_url), - ); - let writer = make_writer::( - config.clone(), - FileType::WrappedObject, - starting_checkpoint_seq_num, - )?; - let max_checkpoint_reader = make_max_checkpoint_reader(&config).await?; - Processor::new::( - handler, - writer, - max_checkpoint_reader, - starting_checkpoint_seq_num, - metrics, - config, - ) - .await -} - -pub fn make_writer( - config: AnalyticsIndexerConfig, - file_type: FileType, - starting_checkpoint_seq_num: u64, -) -> Result>> { - Ok(match config.file_format { - FileFormat::CSV => Box::new(CSVWriter::new( - &config.checkpoint_dir, - file_type, - starting_checkpoint_seq_num, - )?), - FileFormat::PARQUET => Box::new(ParquetWriter::new( - &config.checkpoint_dir, - file_type, - starting_checkpoint_seq_num, - )?), - }) -} - -pub async fn get_starting_checkpoint_seq_num( - config: AnalyticsIndexerConfig, - file_type: FileType, -) -> Result { - let checkpoint = if let Some(starting_checkpoint_seq_num) = config.starting_checkpoint_seq_num { - starting_checkpoint_seq_num - } else { - read_store_for_checkpoint( - config.remote_store_config.clone(), - file_type, - config.remote_store_path_prefix, - ) - .await? - }; - Ok(checkpoint) -} - -pub async fn make_analytics_processor( - config: AnalyticsIndexerConfig, - metrics: AnalyticsMetrics, -) -> Result { - match config.file_type { - FileType::Checkpoint => make_checkpoint_processor(config, metrics).await, - FileType::Object => make_object_processor(config, metrics).await, - FileType::Transaction => make_transaction_processor(config, metrics).await, - FileType::Event => make_event_processor(config, metrics).await, - FileType::TransactionObjects => make_transaction_objects_processor(config, metrics).await, - FileType::MoveCall => make_move_call_processor(config, metrics).await, - FileType::MovePackage => make_move_package_processor(config, metrics).await, - FileType::DynamicField => make_dynamic_field_processor(config, metrics).await, - FileType::WrappedObject => make_wrapped_object_processor(config, metrics).await, - } -} - -pub fn join_paths(base: Option, child: &Path) -> Path { - base.map(|p| { - let mut out_path = p.clone(); - for part in child.parts() { - out_path = out_path.child(part) - } - out_path - }) - .unwrap_or(child.clone()) -} diff --git a/crates/sui-analytics-indexer/src/main.rs b/crates/sui-analytics-indexer/src/main.rs deleted file mode 100644 index 23c36762a27..00000000000 --- a/crates/sui-analytics-indexer/src/main.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use clap::*; -use prometheus::Registry; -use sui_analytics_indexer::{ - analytics_metrics::AnalyticsMetrics, errors::AnalyticsIndexerError, make_analytics_processor, - AnalyticsIndexerConfig, -}; -use sui_indexer::{framework::IndexerBuilder, metrics::IndexerMetrics}; -use tracing::info; - -#[tokio::main] -async fn main() -> Result<(), AnalyticsIndexerError> { - let _guard = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .init(); - - let config = AnalyticsIndexerConfig::parse(); - info!("Parsed config: {:#?}", config); - let registry_service = mysten_metrics::start_prometheus_server( - format!( - "{}:{}", - config.client_metric_host, config.client_metric_port - ) - .parse() - .unwrap(), - ); - let registry: Registry = registry_service.default_registry(); - mysten_metrics::init_metrics(®istry); - let metrics = AnalyticsMetrics::new(®istry); - let indexer_metrics = IndexerMetrics::new(®istry); - - let rest_url = config.rest_url.clone(); - let processor = make_analytics_processor(config, metrics) - .await - .map_err(|e| AnalyticsIndexerError::GenericError(e.to_string()))?; - IndexerBuilder::new(indexer_metrics) - .last_downloaded_checkpoint(processor.last_committed_checkpoint()) - .rest_url(&rest_url) - .handler(processor) - .run() - .await; - Ok(()) -} diff --git a/crates/sui-analytics-indexer/src/tables.rs b/crates/sui-analytics-indexer/src/tables.rs deleted file mode 100644 index 5831546c877..00000000000 --- a/crates/sui-analytics-indexer/src/tables.rs +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -#![allow(dead_code)] - -use serde::Serialize; -use strum_macros::Display; -use sui_analytics_indexer_derive::SerializeParquet; -use sui_types::dynamic_field::DynamicFieldType; - -use crate::{ParquetSchema, ParquetValue}; - -// Table entries for the analytics database. -// Each entry is a row in the database. -// - -// Checkpoint information. -#[derive(Serialize, Clone, SerializeParquet)] -pub(crate) struct CheckpointEntry { - // indexes - pub(crate) checkpoint_digest: String, - pub(crate) sequence_number: u64, - pub(crate) epoch: u64, - pub(crate) timestamp_ms: u64, - - pub(crate) previous_checkpoint_digest: Option, - pub(crate) end_of_epoch: bool, - // gas stats - pub(crate) total_gas_cost: i64, - pub(crate) computation_cost: u64, - pub(crate) storage_cost: u64, - pub(crate) storage_rebate: u64, - pub(crate) non_refundable_storage_fee: u64, - // transaction stats - pub(crate) total_transaction_blocks: u64, - pub(crate) total_transactions: u64, - pub(crate) total_successful_transaction_blocks: u64, - pub(crate) total_successful_transactions: u64, - - pub(crate) network_total_transaction: u64, - pub(crate) validator_signature: String, -} - -// Transaction information. -#[derive(Serialize, Clone, SerializeParquet)] -pub(crate) struct TransactionEntry { - // main indexes - pub(crate) transaction_digest: String, - pub(crate) checkpoint: u64, - pub(crate) epoch: u64, - pub(crate) timestamp_ms: u64, - // transaction info - pub(crate) sender: String, - pub(crate) transaction_kind: String, - pub(crate) is_system_txn: bool, - pub(crate) is_sponsored_tx: bool, - pub(crate) transaction_count: u64, - pub(crate) execution_success: bool, - // object info - pub(crate) input: u64, - pub(crate) shared_input: u64, - pub(crate) gas_coins: u64, - // objects are broken up in created, mutated and deleted. - // No wrap or unwrap information is provided - pub(crate) created: u64, - pub(crate) mutated: u64, - pub(crate) deleted: u64, - // PTB info - pub(crate) transfers: u64, - pub(crate) split_coins: u64, - pub(crate) merge_coins: u64, - pub(crate) publish: u64, - pub(crate) upgrade: u64, - // move_vec or default for future commands - pub(crate) others: u64, - pub(crate) move_calls: u64, - // pub(crate) packages: BTreeSet, - // commas separated list of packages used by the transaction. - // Use as a simple way to query for transactions that use a specific package. - pub(crate) packages: String, - // gas info - pub(crate) gas_owner: String, - pub(crate) gas_object_id: String, - pub(crate) gas_object_sequence: u64, - pub(crate) gas_object_digest: String, - pub(crate) gas_budget: u64, - pub(crate) total_gas_cost: i64, - pub(crate) computation_cost: u64, - pub(crate) storage_cost: u64, - pub(crate) storage_rebate: u64, - pub(crate) non_refundable_storage_fee: u64, - pub(crate) gas_price: u64, - // raw transaction bytes - // pub(crate) raw_transaction: Vec, - // We represent them in base64 encoding so they work with the csv. - // TODO: review and possibly move back to Vec - pub(crate) raw_transaction: String, - pub(crate) has_zklogin_sig: bool, - pub(crate) has_upgraded_multisig: bool, - pub(crate) transaction_json: Option, - pub(crate) effects_json: Option, -} - -// Event information. -// Events identity is via `transaction_digest` and `event_index`. -#[derive(Serialize, Clone, SerializeParquet)] -pub(crate) struct EventEntry { - // indexes - pub(crate) transaction_digest: String, - pub(crate) event_index: u64, - pub(crate) checkpoint: u64, - pub(crate) epoch: u64, - pub(crate) timestamp_ms: u64, - // sender - pub(crate) sender: String, - // event type - pub(crate) package: String, - pub(crate) module: String, - pub(crate) event_type: String, - // raw event bytes - // pub(crate) bcs: Vec, - // We represent them in base64 encoding so they work with the csv. - // TODO: review and possibly move back to Vec - pub(crate) bcs: String, - pub(crate) event_json: String, -} - -// Used in the transaction object table to identify the type of input object. -#[derive(Serialize, Clone, Display)] -pub enum InputObjectKind { - Input, - SharedInput, - GasCoin, -} - -// Used in the object table to identify the status of object, its result in the -// last transaction effect. -#[derive(Serialize, Clone, Display)] -pub enum ObjectStatus { - Created, - Mutated, - Deleted, -} - -// Object owner information. -#[derive(Serialize, Clone, Display)] -pub enum OwnerType { - AddressOwner, - ObjectOwner, - Shared, - Immutable, -} - -// Object information. -// A row in the live object table. -#[derive(Serialize, Clone, SerializeParquet)] -pub(crate) struct ObjectEntry { - // indexes - pub(crate) object_id: String, - pub(crate) version: u64, - pub(crate) digest: String, - pub(crate) type_: Option, // None is for packages - pub(crate) checkpoint: u64, - pub(crate) epoch: u64, - pub(crate) timestamp_ms: u64, - // owner info - pub(crate) owner_type: Option, - pub(crate) owner_address: Option, - // object info - pub(crate) object_status: ObjectStatus, - pub(crate) initial_shared_version: Option, - pub(crate) previous_transaction: String, - pub(crate) has_public_transfer: bool, - pub(crate) storage_rebate: Option, - // raw object bytes - // pub(crate) bcs: Vec, - // We represent them in base64 encoding so they work with the csv. - // TODO: review and possibly move back to Vec - pub(crate) bcs: Option, - - pub(crate) coin_type: Option, - pub(crate) coin_balance: Option, - - pub(crate) struct_tag: Option, - pub(crate) object_json: Option, -} - -// Objects used and manipulated in a transaction. -// Both input object and objects in effects are reported here with the proper -// input kind (for input objects) and status (for objets in effects). -// An object may appear twice as an input and output object. In that case, the -// version will be different. -#[derive(Serialize, Clone, SerializeParquet)] -pub(crate) struct TransactionObjectEntry { - // indexes - pub(crate) object_id: String, - pub(crate) version: Option, - pub(crate) transaction_digest: String, - pub(crate) checkpoint: u64, - pub(crate) epoch: u64, - pub(crate) timestamp_ms: u64, - // input/output information - pub(crate) input_kind: Option, - pub(crate) object_status: Option, -} - -// A Move call expressed as a package, module and function. -#[derive(Serialize, Clone, SerializeParquet)] -pub(crate) struct MoveCallEntry { - // indexes - pub(crate) transaction_digest: String, - pub(crate) checkpoint: u64, - pub(crate) epoch: u64, - pub(crate) timestamp_ms: u64, - // move call info - pub(crate) package: String, - pub(crate) module: String, - pub(crate) function: String, -} - -// A Move package. Package id and MovePackage object bytes -#[derive(Serialize, Clone, SerializeParquet)] -pub(crate) struct MovePackageEntry { - // indexes - pub(crate) package_id: String, - pub(crate) checkpoint: u64, - pub(crate) epoch: u64, - pub(crate) timestamp_ms: u64, - // raw package bytes - // pub(crate) bcs: Vec, - // We represent them in base64 encoding so they work with the csv. - // TODO: review and possibly move back to Vec - pub(crate) bcs: String, - // txn publishing the package - pub(crate) transaction_digest: String, - pub(crate) package_version: Option, - pub(crate) original_package_id: Option, -} - -#[derive(Serialize, Clone, SerializeParquet)] -pub(crate) struct DynamicFieldEntry { - // indexes - pub(crate) parent_object_id: String, - pub(crate) transaction_digest: String, - pub(crate) checkpoint: u64, - pub(crate) epoch: u64, - pub(crate) timestamp_ms: u64, - // df information - pub(crate) name: String, - pub(crate) bcs_name: String, - pub(crate) type_: DynamicFieldType, - pub(crate) object_id: String, - pub(crate) version: u64, - pub(crate) digest: String, - pub(crate) object_type: String, -} - -// Object information. -// A row in the live object table. -#[derive(Serialize, Clone, SerializeParquet)] -pub(crate) struct WrappedObjectEntry { - // indexes - pub(crate) object_id: Option, - pub(crate) root_object_id: String, - pub(crate) root_object_version: u64, - pub(crate) checkpoint: u64, - pub(crate) epoch: u64, - pub(crate) timestamp_ms: u64, - // wrapped info - pub(crate) json_path: String, - pub(crate) struct_tag: Option, -} diff --git a/crates/sui-analytics-indexer/src/writers/mod.rs b/crates/sui-analytics-indexer/src/writers/mod.rs deleted file mode 100644 index 9435715fc80..00000000000 --- a/crates/sui-analytics-indexer/src/writers/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use anyhow::Result; -use serde::Serialize; -use sui_types::base_types::EpochId; - -use crate::{FileFormat, ParquetSchema}; - -pub mod csv_writer; -pub mod parquet_writer; - -pub trait AnalyticsWriter: Send + Sync + 'static { - /// File format i.e. csv, parquet, etc - fn file_format(&self) -> Result; - /// Persist given rows into a file - fn write(&mut self, rows: &[S]) -> Result<()>; - /// Flush the current file - fn flush(&mut self, end_checkpoint_seq_num: u64) -> Result; - /// Reset internal state with given epoch and checkpoint sequence number - fn reset(&mut self, epoch_num: EpochId, start_checkpoint_seq_num: u64) -> Result<()>; - /// Approx size in bytes of the current staging file if available - fn file_size(&self) -> Result>; -} diff --git a/crates/sui-archival/Cargo.toml b/crates/sui-archival/Cargo.toml deleted file mode 100644 index cbf3b8fdb2a..00000000000 --- a/crates/sui-archival/Cargo.toml +++ /dev/null @@ -1,42 +0,0 @@ -[package] -name = "sui-archival" -version = "0.1.0" -edition = "2021" -publish = false -license = "Apache-2.0" -authors = ["Mysten Labs "] - -[dependencies] -indicatif.workspace = true -anyhow.workspace = true -serde.workspace = true -byteorder.workspace = true -tracing.workspace = true -bytes.workspace = true -num_enum.workspace = true -futures.workspace = true -rand.workspace = true -object_store.workspace = true -prometheus.workspace = true -sui-config.workspace = true -sui-types = { workspace = true, features = ["test-utils"]} -sui-storage.workspace = true -fastcrypto = { workspace = true, features = ["copy_key"] } -tokio = { workspace = true, features = ["full"] } -serde_json = "1.0.95" - -[dev-dependencies] -tempfile.workspace = true -more-asserts.workspace = true -telemetry-subscribers.workspace = true -move-binary-format.workspace = true -move-core-types.workspace = true -move-package.workspace = true -tokio = { workspace = true, features = ["test-util"] } -ed25519-consensus.workspace = true -fastcrypto = { workspace = true } -sui-swarm-config.workspace = true -sui-macros.workspace = true - -[target.'cfg(msim)'.dependencies] -sui-simulator.workspace = true diff --git a/crates/sui-archival/src/lib.rs b/crates/sui-archival/src/lib.rs deleted file mode 100644 index 8c3516cc0c2..00000000000 --- a/crates/sui-archival/src/lib.rs +++ /dev/null @@ -1,546 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -#![allow(dead_code)] - -pub mod reader; -pub mod writer; - -#[cfg(test)] -mod tests; - -use std::{ - fs, - io::{BufWriter, Cursor, Read, Seek, SeekFrom, Write}, - num::NonZeroUsize, - ops::Range, - sync::{ - atomic::{AtomicU64, Ordering}, - Arc, - }, - time::{Duration, Instant}, -}; - -use anyhow::{anyhow, Result}; -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; -use bytes::Bytes; -use fastcrypto::hash::{HashFunction, Sha3_256}; -use indicatif::{ProgressBar, ProgressStyle}; -use num_enum::{IntoPrimitive, TryFromPrimitive}; -use object_store::path::Path; -use prometheus::Registry; -use serde::{Deserialize, Serialize}; -use sui_config::{ - genesis::Genesis, node::ArchiveReaderConfig, object_storage_config::ObjectStoreConfig, -}; -use sui_storage::{ - blob::{Blob, BlobEncoding}, - compute_sha3_checksum, compute_sha3_checksum_for_bytes, - object_store::{ - util::{get, put}, - ObjectStoreGetExt, ObjectStorePutExt, - }, - SHA3_BYTES, -}; -use sui_types::{ - base_types::ExecutionData, - messages_checkpoint::{FullCheckpointContents, VerifiedCheckpointContents}, - storage::{SingleCheckpointSharedInMemoryStore, WriteStore}, -}; -use tracing::{error, info}; - -use crate::reader::{ArchiveReader, ArchiveReaderMetrics}; - -#[allow(rustdoc::invalid_html_tags)] -/// Checkpoints and summaries are persisted as blob files. Files are committed -/// to local store by duration or file size. Committed files are synced with the -/// remote store continuously. Files are optionally compressed with the zstd -/// compression format. Filenames follow the format . -/// where `checkpoint_seq_num` is the first checkpoint present in that -/// file. MANIFEST is the index and source of truth for all files present in the -/// archive. -/// -/// State Archival Directory Layout -/// - archive/ -/// - MANIFEST -/// - epoch_0/ -/// - 0.chk -/// - 0.sum -/// - 1000.chk -/// - 1000.sum -/// - 3000.chk -/// - 3000.sum -/// - ... -/// - 100000.chk -/// - 100000.sum -/// - epoch_1/ -/// - 101000.chk -/// - ... -/// Blob File Disk Format -/// ┌──────────────────────────────┐ -/// │ magic <4 byte> │ -/// ├──────────────────────────────┤ -/// │ storage format <1 byte> │ -// ├──────────────────────────────┤ -/// │ file compression <1 byte> │ -// ├──────────────────────────────┤ -/// │ ┌──────────────────────────┐ │ -/// │ │ Blob 1 │ │ -/// │ ├──────────────────────────┤ │ -/// │ │ ... │ │ -/// │ ├──────────────────────────┤ │ -/// │ │ Blob N │ │ -/// │ └──────────────────────────┘ │ -/// └──────────────────────────────┘ -/// Blob -/// ┌───────────────┬───────────────────┬──────────────┐ -/// │ len │ encoding <1 byte> │ data │ -/// └───────────────┴───────────────────┴──────────────┘ -/// -/// MANIFEST File Disk Format -/// ┌──────────────────────────────┐ -/// │ magic<4 byte> │ -/// ├──────────────────────────────┤ -/// │ serialized manifest │ -/// ├──────────────────────────────┤ -/// │ sha3 <32 bytes> │ -/// └──────────────────────────────┘ -pub const CHECKPOINT_FILE_MAGIC: u32 = 0x0000DEAD; -pub const SUMMARY_FILE_MAGIC: u32 = 0x0000CAFE; -const MANIFEST_FILE_MAGIC: u32 = 0x00C0FFEE; -const MAGIC_BYTES: usize = 4; -const CHECKPOINT_FILE_SUFFIX: &str = "chk"; -const SUMMARY_FILE_SUFFIX: &str = "sum"; -const EPOCH_DIR_PREFIX: &str = "epoch_"; -const MANIFEST_FILENAME: &str = "MANIFEST"; - -#[derive( - Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, TryFromPrimitive, IntoPrimitive, -)] -#[repr(u8)] -pub enum FileType { - CheckpointContent = 0, - CheckpointSummary, -} - -#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] -pub struct FileMetadata { - pub file_type: FileType, - pub epoch_num: u64, - pub checkpoint_seq_range: Range, - pub sha3_digest: [u8; 32], -} - -impl FileMetadata { - pub fn file_path(&self) -> Path { - let dir_path = Path::from(format!("{}{}", EPOCH_DIR_PREFIX, self.epoch_num)); - match self.file_type { - FileType::CheckpointContent => dir_path.child(&*format!( - "{}.{CHECKPOINT_FILE_SUFFIX}", - self.checkpoint_seq_range.start - )), - FileType::CheckpointSummary => dir_path.child(&*format!( - "{}.{SUMMARY_FILE_SUFFIX}", - self.checkpoint_seq_range.start - )), - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] -pub struct ManifestV1 { - pub archive_version: u8, - pub next_checkpoint_seq_num: u64, - pub file_metadata: Vec, - pub epoch: u64, -} - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub enum Manifest { - V1(ManifestV1), -} - -impl Manifest { - pub fn new(epoch: u64, next_checkpoint_seq_num: u64) -> Self { - Manifest::V1(ManifestV1 { - archive_version: 1, - next_checkpoint_seq_num, - file_metadata: vec![], - epoch, - }) - } - pub fn files(&self) -> Vec { - match self { - Manifest::V1(manifest) => manifest.file_metadata.clone(), - } - } - pub fn epoch_num(&self) -> u64 { - match self { - Manifest::V1(manifest) => manifest.epoch, - } - } - pub fn next_checkpoint_seq_num(&self) -> u64 { - match self { - Manifest::V1(manifest) => manifest.next_checkpoint_seq_num, - } - } - pub fn next_checkpoint_after_epoch(&self, epoch_num: u64) -> u64 { - match self { - Manifest::V1(manifest) => { - let mut summary_files: Vec<_> = manifest - .file_metadata - .clone() - .into_iter() - .filter(|f| f.file_type == FileType::CheckpointSummary) - .collect(); - summary_files.sort_by_key(|f| f.checkpoint_seq_range.start); - assert!( - summary_files - .windows(2) - .all(|w| w[1].checkpoint_seq_range.start == w[0].checkpoint_seq_range.end) - ); - assert_eq!(summary_files.first().unwrap().checkpoint_seq_range.start, 0); - summary_files - .iter() - .find(|f| f.epoch_num > epoch_num) - .map(|f| f.checkpoint_seq_range.start) - .unwrap_or(u64::MAX) - } - } - } - pub fn update( - &mut self, - epoch_num: u64, - checkpoint_sequence_number: u64, - checkpoint_file_metadata: FileMetadata, - summary_file_metadata: FileMetadata, - ) { - match self { - Manifest::V1(manifest) => { - manifest - .file_metadata - .extend(vec![checkpoint_file_metadata, summary_file_metadata]); - manifest.epoch = epoch_num; - manifest.next_checkpoint_seq_num = checkpoint_sequence_number; - } - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] -pub struct CheckpointUpdates { - checkpoint_file_metadata: FileMetadata, - summary_file_metadata: FileMetadata, - manifest: Manifest, -} - -impl CheckpointUpdates { - pub fn new( - epoch_num: u64, - checkpoint_sequence_number: u64, - checkpoint_file_metadata: FileMetadata, - summary_file_metadata: FileMetadata, - manifest: &mut Manifest, - ) -> Self { - manifest.update( - epoch_num, - checkpoint_sequence_number, - checkpoint_file_metadata.clone(), - summary_file_metadata.clone(), - ); - CheckpointUpdates { - checkpoint_file_metadata, - summary_file_metadata, - manifest: manifest.clone(), - } - } - pub fn content_file_path(&self) -> Path { - self.checkpoint_file_metadata.file_path() - } - pub fn summary_file_path(&self) -> Path { - self.summary_file_metadata.file_path() - } - pub fn manifest_file_path(&self) -> Path { - Path::from(MANIFEST_FILENAME) - } -} - -pub fn create_file_metadata( - file_path: &std::path::Path, - file_type: FileType, - epoch_num: u64, - checkpoint_seq_range: Range, -) -> Result { - let sha3_digest = compute_sha3_checksum(file_path)?; - let file_metadata = FileMetadata { - file_type, - epoch_num, - checkpoint_seq_range, - sha3_digest, - }; - Ok(file_metadata) -} - -pub fn create_file_metadata_from_bytes( - bytes: Bytes, - file_type: FileType, - epoch_num: u64, - checkpoint_seq_range: Range, -) -> Result { - let sha3_digest = compute_sha3_checksum_for_bytes(bytes)?; - let file_metadata = FileMetadata { - file_type, - epoch_num, - checkpoint_seq_range, - sha3_digest, - }; - Ok(file_metadata) -} - -pub async fn read_manifest(remote_store: S) -> Result { - let manifest_file_path = Path::from(MANIFEST_FILENAME); - let vec = get(&remote_store, &manifest_file_path).await?.to_vec(); - read_manifest_from_bytes(vec) -} - -pub fn read_manifest_from_bytes(vec: Vec) -> Result { - let manifest_file_size = vec.len(); - let mut manifest_reader = Cursor::new(vec); - manifest_reader.rewind()?; - let magic = manifest_reader.read_u32::()?; - if magic != MANIFEST_FILE_MAGIC { - return Err(anyhow!("Unexpected magic byte in manifest: {}", magic)); - } - manifest_reader.seek(SeekFrom::End(-(SHA3_BYTES as i64)))?; - let mut sha3_digest = [0u8; SHA3_BYTES]; - manifest_reader.read_exact(&mut sha3_digest)?; - manifest_reader.rewind()?; - let mut content_buf = vec![0u8; manifest_file_size - SHA3_BYTES]; - manifest_reader.read_exact(&mut content_buf)?; - let mut hasher = Sha3_256::default(); - hasher.update(&content_buf); - let computed_digest = hasher.finalize().digest; - if computed_digest != sha3_digest { - return Err(anyhow!( - "Manifest corrupted, computed checksum: {:?}, stored checksum: {:?}", - computed_digest, - sha3_digest - )); - } - manifest_reader.rewind()?; - manifest_reader.seek(SeekFrom::Start(MAGIC_BYTES as u64))?; - Blob::read(&mut manifest_reader)?.decode() -} - -pub fn finalize_manifest(manifest: Manifest) -> Result { - let mut buf = BufWriter::new(vec![]); - buf.write_u32::(MANIFEST_FILE_MAGIC)?; - let blob = Blob::encode(&manifest, BlobEncoding::Bcs)?; - blob.write(&mut buf)?; - buf.flush()?; - let mut hasher = Sha3_256::default(); - hasher.update(buf.get_ref()); - let computed_digest = hasher.finalize().digest; - buf.write_all(&computed_digest)?; - Ok(Bytes::from(buf.into_inner()?)) -} - -pub async fn write_manifest( - manifest: Manifest, - remote_store: S, -) -> Result<()> { - let path = Path::from(MANIFEST_FILENAME); - let bytes = finalize_manifest(manifest)?; - put(&remote_store, &path, bytes).await?; - Ok(()) -} - -pub async fn read_manifest_as_json(remote_store_config: ObjectStoreConfig) -> Result { - let metrics = ArchiveReaderMetrics::new(&Registry::default()); - let config = ArchiveReaderConfig { - remote_store_config, - download_concurrency: NonZeroUsize::new(1).unwrap(), - use_for_pruning_watermark: false, - }; - let archive_reader = ArchiveReader::new(config, &metrics)?; - archive_reader.sync_manifest_once().await?; - let manifest = archive_reader.get_manifest().await?; - let json = serde_json::to_string(&manifest).expect("Failed to serialize object"); - Ok(json) -} - -pub async fn write_manifest_from_json( - remote_store_config: ObjectStoreConfig, - json_manifest_path: std::path::PathBuf, -) -> Result<()> { - let manifest: Manifest = serde_json::from_str(&fs::read_to_string(json_manifest_path)?)?; - let store = remote_store_config.make()?; - write_manifest(manifest, store).await?; - Ok(()) -} - -pub async fn verify_archive_with_genesis_config( - genesis: &std::path::Path, - remote_store_config: ObjectStoreConfig, - concurrency: usize, - interactive: bool, - num_retries: u32, -) -> Result<()> { - let genesis = Genesis::load(genesis).unwrap(); - let genesis_committee = genesis.committee()?; - let mut store = SingleCheckpointSharedInMemoryStore::default(); - let contents = genesis.checkpoint_contents(); - let fullcheckpoint_contents = FullCheckpointContents::from_contents_and_execution_data( - contents.clone(), - std::iter::once(ExecutionData::new( - genesis.transaction().clone(), - genesis.effects().clone(), - )), - ); - store.insert_genesis_state( - genesis.checkpoint(), - VerifiedCheckpointContents::new_unchecked(fullcheckpoint_contents), - genesis_committee, - ); - - let num_retries = std::cmp::max(num_retries, 1); - for _ in 0..num_retries { - match verify_archive_with_local_store( - store.clone(), - remote_store_config.clone(), - concurrency, - interactive, - ) - .await - { - Ok(_) => return Ok(()), - Err(e) => { - error!("Error while verifying archive: {}", e); - tokio::time::sleep(Duration::from_secs(10)).await; - } - } - } - - Err::<(), anyhow::Error>(anyhow!( - "Failed to verify archive after {} retries", - num_retries - )) -} - -pub async fn verify_archive_with_checksums( - remote_store_config: ObjectStoreConfig, - concurrency: usize, -) -> Result<()> { - let metrics = ArchiveReaderMetrics::new(&Registry::default()); - let config = ArchiveReaderConfig { - remote_store_config, - download_concurrency: NonZeroUsize::new(concurrency).unwrap(), - use_for_pruning_watermark: false, - }; - let archive_reader = ArchiveReader::new(config, &metrics)?; - archive_reader.sync_manifest_once().await?; - let manifest = archive_reader.get_manifest().await?; - info!( - "Next checkpoint in archive store: {}", - manifest.next_checkpoint_seq_num() - ); - - let file_metadata = archive_reader.verify_manifest(manifest).await?; - // Account for both summary and content files - let num_files = file_metadata.len() * 2; - archive_reader - .verify_file_consistency(file_metadata) - .await?; - info!("All {} files are valid", num_files); - Ok(()) -} - -pub async fn verify_archive_with_local_store( - store: S, - remote_store_config: ObjectStoreConfig, - concurrency: usize, - interactive: bool, -) -> Result<()> -where - S: WriteStore + Clone + Send + 'static, -{ - let metrics = ArchiveReaderMetrics::new(&Registry::default()); - let config = ArchiveReaderConfig { - remote_store_config, - download_concurrency: NonZeroUsize::new(concurrency).unwrap(), - use_for_pruning_watermark: false, - }; - let archive_reader = ArchiveReader::new(config, &metrics)?; - archive_reader.sync_manifest_once().await?; - let latest_checkpoint_in_archive = archive_reader.latest_available_checkpoint().await?; - info!( - "Latest available checkpoint in archive store: {}", - latest_checkpoint_in_archive - ); - let latest_checkpoint = store - .get_highest_synced_checkpoint() - .map_err(|_| anyhow!("Failed to read highest synced checkpoint"))? - .sequence_number; - info!("Highest synced checkpoint in db: {latest_checkpoint}"); - let txn_counter = Arc::new(AtomicU64::new(0)); - let checkpoint_counter = Arc::new(AtomicU64::new(0)); - let progress_bar = if interactive { - let progress_bar = ProgressBar::new(latest_checkpoint_in_archive).with_style( - ProgressStyle::with_template("[{elapsed_precise}] {wide_bar} {pos}/{len}({msg})") - .unwrap(), - ); - let cloned_progress_bar = progress_bar.clone(); - let cloned_counter = txn_counter.clone(); - let cloned_checkpoint_counter = checkpoint_counter.clone(); - let instant = Instant::now(); - tokio::spawn(async move { - loop { - let total_checkpoints_loaded = cloned_checkpoint_counter.load(Ordering::Relaxed); - let total_checkpoints_per_sec = - total_checkpoints_loaded as f64 / instant.elapsed().as_secs_f64(); - let total_txns_per_sec = - cloned_counter.load(Ordering::Relaxed) as f64 / instant.elapsed().as_secs_f64(); - cloned_progress_bar.set_position(latest_checkpoint + total_checkpoints_loaded); - cloned_progress_bar.set_message(format!( - "checkpoints/s: {}, txns/s: {}", - total_checkpoints_per_sec, total_txns_per_sec - )); - tokio::time::sleep(Duration::from_secs(1)).await; - } - }); - Some(progress_bar) - } else { - let cloned_store = store.clone(); - tokio::spawn(async move { - loop { - let latest_checkpoint = cloned_store - .get_highest_synced_checkpoint() - .map_err(|_| anyhow!("Failed to read highest synced checkpoint"))? - .sequence_number; - let percent = (latest_checkpoint * 100) / latest_checkpoint_in_archive; - info!("done = {percent}%"); - tokio::time::sleep(Duration::from_secs(60)).await; - if percent >= 100 { - break; - } - } - Ok::<(), anyhow::Error>(()) - }); - None - }; - archive_reader - .read( - store.clone(), - (latest_checkpoint + 1)..u64::MAX, - txn_counter, - checkpoint_counter, - true, - ) - .await?; - progress_bar.iter().for_each(|p| p.finish_and_clear()); - let end = store - .get_highest_synced_checkpoint() - .map_err(|_| anyhow!("Failed to read watermark"))? - .sequence_number; - info!("Highest verified checkpoint: {}", end); - Ok(()) -} diff --git a/crates/sui-archival/src/reader.rs b/crates/sui-archival/src/reader.rs deleted file mode 100644 index 328451ec98c..00000000000 --- a/crates/sui-archival/src/reader.rs +++ /dev/null @@ -1,648 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - borrow::Borrow, - future, - ops::Range, - sync::{ - atomic::{AtomicU64, Ordering}, - Arc, - }, - time::Duration, -}; - -use anyhow::{anyhow, Context, Result}; -use bytes::{buf::Reader, Buf, Bytes}; -use futures::{StreamExt, TryStreamExt}; -use prometheus::{register_int_counter_vec_with_registry, IntCounterVec, Registry}; -use rand::seq::SliceRandom; -use sui_config::node::ArchiveReaderConfig; -use sui_storage::{ - compute_sha3_checksum_for_bytes, make_iterator, - object_store::{http::HttpDownloaderBuilder, util::get, ObjectStoreGetExt}, - verify_checkpoint, -}; -use sui_types::{ - messages_checkpoint::{ - CertifiedCheckpointSummary, CheckpointSequenceNumber, - FullCheckpointContents as CheckpointContents, VerifiedCheckpoint, - VerifiedCheckpointContents, - }, - storage::WriteStore, -}; -use tokio::sync::{oneshot, oneshot::Sender, Mutex}; -use tracing::info; - -use crate::{ - read_manifest, FileMetadata, FileType, Manifest, CHECKPOINT_FILE_MAGIC, SUMMARY_FILE_MAGIC, -}; - -#[derive(Debug)] -pub struct ArchiveReaderMetrics { - pub archive_txns_read: IntCounterVec, - pub archive_checkpoints_read: IntCounterVec, -} - -impl ArchiveReaderMetrics { - pub fn new(registry: &Registry) -> Arc { - let this = Self { - archive_txns_read: register_int_counter_vec_with_registry!( - "archive_txns_read", - "Number of transactions read from archive", - &["bucket"], - registry - ) - .unwrap(), - archive_checkpoints_read: register_int_counter_vec_with_registry!( - "archive_checkpoints_read", - "Number of checkpoints read from archive", - &["bucket"], - registry - ) - .unwrap(), - }; - Arc::new(this) - } -} - -// ArchiveReaderBalancer selects archives for reading based on whether they can -// fulfill a checkpoint request -#[derive(Default, Clone)] -pub struct ArchiveReaderBalancer { - readers: Vec>, -} - -impl ArchiveReaderBalancer { - pub fn new(configs: Vec, registry: &Registry) -> Result { - let mut readers = vec![]; - let metrics = ArchiveReaderMetrics::new(registry); - for config in configs.into_iter() { - readers.push(Arc::new(ArchiveReader::new(config.clone(), &metrics)?)); - } - Ok(ArchiveReaderBalancer { readers }) - } - pub async fn get_archive_watermark(&self) -> Result> { - let mut checkpoints: Vec> = vec![]; - for reader in self - .readers - .iter() - .filter(|r| r.use_for_pruning_watermark()) - { - let latest_checkpoint = reader.latest_available_checkpoint().await; - info!( - "Latest archived checkpoint in remote store: {:?} is: {:?}", - reader.remote_store_identifier(), - latest_checkpoint - ); - checkpoints.push(latest_checkpoint) - } - let checkpoints: Result> = checkpoints.into_iter().collect(); - checkpoints.map(|vec| vec.into_iter().min()) - } - pub async fn pick_one_random( - &self, - checkpoint_range: Range, - ) -> Option> { - let mut archives_with_complete_range = vec![]; - for reader in self.readers.iter() { - let latest_checkpoint = reader.latest_available_checkpoint().await.unwrap_or(0); - if latest_checkpoint >= checkpoint_range.end { - archives_with_complete_range.push(reader.clone()); - } - } - if !archives_with_complete_range.is_empty() { - return Some( - archives_with_complete_range - .choose(&mut rand::thread_rng()) - .unwrap() - .clone(), - ); - } - let mut archives_with_partial_range = vec![]; - for reader in self.readers.iter() { - let latest_checkpoint = reader.latest_available_checkpoint().await.unwrap_or(0); - if latest_checkpoint >= checkpoint_range.start { - archives_with_partial_range.push(reader.clone()); - } - } - if !archives_with_partial_range.is_empty() { - return Some( - archives_with_partial_range - .choose(&mut rand::thread_rng()) - .unwrap() - .clone(), - ); - } - None - } -} - -#[derive(Clone)] -pub struct ArchiveReader { - bucket: String, - concurrency: usize, - sender: Arc>, - manifest: Arc>, - use_for_pruning_watermark: bool, - remote_object_store: Arc, - archive_reader_metrics: Arc, -} - -impl ArchiveReader { - pub fn new(config: ArchiveReaderConfig, metrics: &Arc) -> Result { - let bucket = config - .remote_store_config - .bucket - .clone() - .unwrap_or("unknown".to_string()); - let remote_object_store = if config.remote_store_config.no_sign_request { - config.remote_store_config.make_http()? - } else { - config.remote_store_config.make().map(Arc::new)? - }; - let (sender, recv) = oneshot::channel(); - let manifest = Arc::new(Mutex::new(Manifest::new(0, 0))); - // Start a background tokio task to keep local manifest in sync with remote - Self::spawn_manifest_sync_task(remote_object_store.clone(), manifest.clone(), recv); - Ok(ArchiveReader { - bucket, - manifest, - sender: Arc::new(sender), - remote_object_store, - use_for_pruning_watermark: config.use_for_pruning_watermark, - concurrency: config.download_concurrency.get(), - archive_reader_metrics: metrics.clone(), - }) - } - - /// This function verifies that the files in archive cover the entire range - /// of checkpoints from sequence number 0 until the latest available - /// checkpoint with no missing checkpoint - pub async fn verify_manifest( - &self, - manifest: Manifest, - ) -> Result> { - let files = manifest.files(); - if files.is_empty() { - return Err(anyhow!("Unexpected empty archive store")); - } - - let mut summary_files: Vec<_> = files - .clone() - .into_iter() - .filter(|f| f.file_type == FileType::CheckpointSummary) - .collect(); - let mut contents_files: Vec<_> = files - .into_iter() - .filter(|f| f.file_type == FileType::CheckpointContent) - .collect(); - assert_eq!(summary_files.len(), contents_files.len()); - - summary_files.sort_by_key(|f| f.checkpoint_seq_range.start); - contents_files.sort_by_key(|f| f.checkpoint_seq_range.start); - - assert!( - summary_files - .windows(2) - .all(|w| w[1].checkpoint_seq_range.start == w[0].checkpoint_seq_range.end) - ); - assert!( - contents_files - .windows(2) - .all(|w| w[1].checkpoint_seq_range.start == w[0].checkpoint_seq_range.end) - ); - - let files: Vec<(FileMetadata, FileMetadata)> = summary_files - .into_iter() - .zip(contents_files.into_iter()) - .map(|(s, c)| { - assert_eq!(s.checkpoint_seq_range, c.checkpoint_seq_range); - (s, c) - }) - .collect(); - - assert_eq!(files.first().unwrap().0.checkpoint_seq_range.start, 0); - - Ok(files) - } - - /// This function downloads summary and content files and ensures their - /// computed checksum matches the one in manifest - pub async fn verify_file_consistency( - &self, - files: Vec<(FileMetadata, FileMetadata)>, - ) -> Result<()> { - let remote_object_store = self.remote_object_store.clone(); - futures::stream::iter(files.iter()) - .enumerate() - .map(|(_, (summary_metadata, content_metadata))| { - let remote_object_store = remote_object_store.clone(); - async move { - let summary_data = - get(&remote_object_store, &summary_metadata.file_path()).await?; - let content_data = - get(&remote_object_store, &content_metadata.file_path()).await?; - Ok::<((Bytes, &FileMetadata), (Bytes, &FileMetadata)), anyhow::Error>(( - (summary_data, summary_metadata), - (content_data, content_metadata), - )) - } - }) - .boxed() - .buffer_unordered(self.concurrency) - .try_for_each( - |((summary_data, summary_metadata), (content_data, content_metadata))| { - let checksums = compute_sha3_checksum_for_bytes(summary_data).and_then(|s| { - compute_sha3_checksum_for_bytes(content_data).map(|c| (s, c)) - }); - let result = checksums.and_then(|(summary_checksum, content_checksum)| { - (summary_checksum == summary_metadata.sha3_digest) - .then_some(()) - .ok_or(anyhow!( - "Summary checksum doesn't match for file: {:?}", - summary_metadata.file_path() - ))?; - (content_checksum == content_metadata.sha3_digest) - .then_some(()) - .ok_or(anyhow!( - "Content checksum doesn't match for file: {:?}", - content_metadata.file_path() - ))?; - Ok::<(), anyhow::Error>(()) - }); - futures::future::ready(result) - }, - ) - .await - } - - /// Load checkpoints+txns+effects from archive into the input store `S` for - /// the given checkpoint range. Summaries are downloaded out of order - /// and inserted without verification - pub async fn read_summaries( - &self, - store: S, - checkpoint_range: Range, - checkpoint_counter: Arc, - verify: bool, - ) -> Result<()> - where - S: WriteStore + Clone, - { - let (summary_files, start_index, end_index) = - self.get_summary_files(checkpoint_range.clone()).await?; - let remote_object_store = self.remote_object_store.clone(); - let stream = futures::stream::iter(summary_files.iter()) - .enumerate() - .filter(|(index, _s)| future::ready(*index >= start_index && *index < end_index)) - .map(|(_, summary_metadata)| { - let remote_object_store = remote_object_store.clone(); - async move { - let summary_data = - get(&remote_object_store, &summary_metadata.file_path()).await?; - Ok::(summary_data) - } - }) - .boxed(); - if verify { - stream - .buffered(self.concurrency) - .try_for_each(|summary_data| { - let result: Result<(), anyhow::Error> = - make_iterator::>( - SUMMARY_FILE_MAGIC, - summary_data.reader(), - ) - .and_then(|summary_iter| { - summary_iter - .filter(|s| { - s.sequence_number >= checkpoint_range.start - && s.sequence_number < checkpoint_range.end - }) - .try_for_each(|summary| { - let verified_checkpoint = Self::get_or_insert_verified_checkpoint( - &store, - summary.clone(), - true, - ) - .unwrap_or_else(|_| { - panic!( - "Checkpoint verification failed for checkpoint {}", - summary.sequence_number - ) - }); - // Update highest synced watermark - store - .update_highest_verified_checkpoint(&verified_checkpoint) - .expect("Failed to update watermark"); - checkpoint_counter.fetch_add(1, Ordering::Relaxed); - Ok::<(), anyhow::Error>(()) - }) - }); - futures::future::ready(result) - }) - .await - } else { - stream - .buffer_unordered(self.concurrency) - .try_for_each(|summary_data| { - let result: Result<(), anyhow::Error> = - make_iterator::>( - SUMMARY_FILE_MAGIC, - summary_data.reader(), - ) - .and_then(|summary_iter| { - summary_iter - .filter(|s| { - s.sequence_number >= checkpoint_range.start - && s.sequence_number < checkpoint_range.end - }) - .try_for_each(|summary| { - Self::insert_certified_checkpoint(&store, summary)?; - checkpoint_counter.fetch_add(1, Ordering::Relaxed); - Ok::<(), anyhow::Error>(()) - }) - }); - futures::future::ready(result) - }) - .await - } - } - - /// Load checkpoints+txns+effects from archive into the input store `S` for - /// the given checkpoint range. If latest available checkpoint in - /// archive is older than the start of the input range then this call - /// fails with an error otherwise we load as many checkpoints as - /// possible until the end of the provided checkpoint range. - pub async fn read( - &self, - store: S, - checkpoint_range: Range, - txn_counter: Arc, - checkpoint_counter: Arc, - verify: bool, - ) -> Result<()> - where - S: WriteStore + Clone, - { - let manifest = self.manifest.lock().await.clone(); - - let latest_available_checkpoint = manifest - .next_checkpoint_seq_num() - .checked_sub(1) - .context("Checkpoint seq num underflow")?; - - if checkpoint_range.start > latest_available_checkpoint { - return Err(anyhow!( - "Latest available checkpoint is: {}", - latest_available_checkpoint - )); - } - - let files: Vec<(FileMetadata, FileMetadata)> = self.verify_manifest(manifest).await?; - - let start_index = match files.binary_search_by_key(&checkpoint_range.start, |(s, _c)| { - s.checkpoint_seq_range.start - }) { - Ok(index) => index, - Err(index) => index - 1, - }; - - let end_index = match files.binary_search_by_key(&checkpoint_range.end, |(s, _c)| { - s.checkpoint_seq_range.start - }) { - Ok(index) => index, - Err(index) => index, - }; - - let remote_object_store = self.remote_object_store.clone(); - futures::stream::iter(files.iter()) - .enumerate() - .filter(|(index, (_s, _c))| future::ready(*index >= start_index && *index < end_index)) - .map(|(_, (summary_metadata, content_metadata))| { - let remote_object_store = remote_object_store.clone(); - async move { - let summary_data = - get(&remote_object_store, &summary_metadata.file_path()).await?; - let content_data = - get(&remote_object_store, &content_metadata.file_path()).await?; - Ok::<(Bytes, Bytes), anyhow::Error>((summary_data, content_data)) - } - }) - .boxed() - .buffered(self.concurrency) - .try_for_each(|(summary_data, content_data)| { - let result: Result<(), anyhow::Error> = make_iterator::< - CertifiedCheckpointSummary, - Reader, - >( - SUMMARY_FILE_MAGIC, summary_data.reader() - ) - .and_then(|s| { - make_iterator::>( - CHECKPOINT_FILE_MAGIC, - content_data.reader(), - ) - .map(|c| (s, c)) - }) - .and_then(|(summary_iter, content_iter)| { - summary_iter - .zip(content_iter) - .filter(|(s, _c)| { - s.sequence_number >= checkpoint_range.start - && s.sequence_number < checkpoint_range.end - }) - .try_for_each(|(summary, contents)| { - let verified_checkpoint = - Self::get_or_insert_verified_checkpoint(&store, summary, verify)?; - // Verify content - let digest = verified_checkpoint.content_digest; - contents.verify_digests(digest)?; - let verified_contents = - VerifiedCheckpointContents::new_unchecked(contents.clone()); - // Insert content - store - .insert_checkpoint_contents(&verified_checkpoint, verified_contents) - .map_err(|e| anyhow!("Failed to insert content: {e}"))?; - // Update highest synced watermark - store - .update_highest_synced_checkpoint(&verified_checkpoint) - .map_err(|e| anyhow!("Failed to update watermark: {e}"))?; - txn_counter.fetch_add(contents.size() as u64, Ordering::Relaxed); - self.archive_reader_metrics - .archive_txns_read - .with_label_values(&[&self.bucket]) - .inc_by(contents.size() as u64); - checkpoint_counter.fetch_add(1, Ordering::Relaxed); - self.archive_reader_metrics - .archive_checkpoints_read - .with_label_values(&[&self.bucket]) - .inc_by(1); - Ok::<(), anyhow::Error>(()) - }) - }); - futures::future::ready(result) - }) - .await - } - - /// Return latest available checkpoint in archive - pub async fn latest_available_checkpoint(&self) -> Result { - let manifest = self.manifest.lock().await.clone(); - manifest - .next_checkpoint_seq_num() - .checked_sub(1) - .context("No checkpoint data in archive") - } - - pub fn use_for_pruning_watermark(&self) -> bool { - self.use_for_pruning_watermark - } - - pub fn remote_store_identifier(&self) -> String { - self.remote_object_store.to_string() - } - - pub async fn sync_manifest_once(&self) -> Result<()> { - Self::sync_manifest(self.remote_object_store.clone(), self.manifest.clone()).await?; - Ok(()) - } - - pub async fn get_manifest(&self) -> Result { - Ok(self.manifest.lock().await.clone()) - } - - async fn sync_manifest( - remote_store: Arc, - manifest: Arc>, - ) -> Result<()> { - let new_manifest = read_manifest(remote_store.clone()).await?; - let mut locked = manifest.lock().await; - *locked = new_manifest; - Ok(()) - } - - /// Insert checkpoint summary without verifying it - fn insert_certified_checkpoint( - store: &S, - certified_checkpoint: CertifiedCheckpointSummary, - ) -> Result<()> - where - S: WriteStore + Clone, - { - store - .insert_checkpoint(VerifiedCheckpoint::new_unchecked(certified_checkpoint).borrow()) - .map_err(|e| anyhow!("Failed to insert checkpoint: {e}")) - } - - /// Insert checkpoint summary if it doesn't already exist after verifying it - fn get_or_insert_verified_checkpoint( - store: &S, - certified_checkpoint: CertifiedCheckpointSummary, - verify: bool, - ) -> Result - where - S: WriteStore + Clone, - { - store - .get_checkpoint_by_sequence_number(certified_checkpoint.sequence_number) - .map_err(|e| anyhow!("Store op failed: {e}"))? - .map(Ok::) - .unwrap_or_else(|| { - let verified_checkpoint = if verify { - // Verify checkpoint summary - let prev_checkpoint_seq_num = certified_checkpoint - .sequence_number - .checked_sub(1) - .context("Checkpoint seq num underflow")?; - let prev_checkpoint = store - .get_checkpoint_by_sequence_number(prev_checkpoint_seq_num) - .map_err(|e| anyhow!("Store op failed: {e}"))? - .context(format!( - "Missing previous checkpoint {} in store", - prev_checkpoint_seq_num - ))?; - - verify_checkpoint(&prev_checkpoint, store, certified_checkpoint) - .map_err(|_| anyhow!("Checkpoint verification failed"))? - } else { - VerifiedCheckpoint::new_unchecked(certified_checkpoint) - }; - // Insert checkpoint summary - store - .insert_checkpoint(&verified_checkpoint) - .map_err(|e| anyhow!("Failed to insert checkpoint: {e}"))?; - // Update highest verified checkpoint watermark - store - .update_highest_verified_checkpoint(&verified_checkpoint) - .expect("store operation should not fail"); - Ok::(verified_checkpoint) - }) - .map_err(|e| anyhow!("Failed to get verified checkpoint: {:?}", e)) - } - - async fn get_summary_files( - &self, - checkpoint_range: Range, - ) -> Result<(Vec, usize, usize)> { - let manifest = self.manifest.lock().await.clone(); - - let latest_available_checkpoint = manifest - .next_checkpoint_seq_num() - .checked_sub(1) - .context("Checkpoint seq num underflow")?; - - if checkpoint_range.start > latest_available_checkpoint { - return Err(anyhow!( - "Latest available checkpoint is: {}", - latest_available_checkpoint - )); - } - - let summary_files: Vec = self - .verify_manifest(manifest) - .await? - .iter() - .map(|(s, _)| s.clone()) - .collect(); - - let start_index = match summary_files - .binary_search_by_key(&checkpoint_range.start, |s| s.checkpoint_seq_range.start) - { - Ok(index) => index, - Err(index) => index - 1, - }; - - let end_index = match summary_files - .binary_search_by_key(&checkpoint_range.end, |s| s.checkpoint_seq_range.start) - { - Ok(index) => index, - Err(index) => index, - }; - - Ok((summary_files, start_index, end_index)) - } - - fn spawn_manifest_sync_task( - remote_store: S, - manifest: Arc>, - mut recv: oneshot::Receiver<()>, - ) { - tokio::task::spawn(async move { - let mut interval = tokio::time::interval(Duration::from_secs(60)); - loop { - tokio::select! { - _ = interval.tick() => { - let new_manifest = read_manifest(remote_store.clone()).await?; - let mut locked = manifest.lock().await; - *locked = new_manifest; - } - _ = &mut recv => break, - } - } - info!("Terminating the manifest sync loop"); - Ok::<(), anyhow::Error>(()) - }); - } -} diff --git a/crates/sui-archival/src/tests.rs b/crates/sui-archival/src/tests.rs deleted file mode 100644 index b3de1713f0d..00000000000 --- a/crates/sui-archival/src/tests.rs +++ /dev/null @@ -1,388 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - fs, - fs::File, - io::Write, - num::NonZeroUsize, - path::PathBuf, - sync::{atomic::AtomicU64, Arc}, - time::Duration, -}; - -use anyhow::{anyhow, Context, Result}; -use more_asserts as ma; -use object_store::DynObjectStore; -use prometheus::Registry; -use sui_config::{ - node::ArchiveReaderConfig, - object_storage_config::{ObjectStoreConfig, ObjectStoreType}, -}; -use sui_storage::{object_store::util::path_to_filesystem, FileCompression, StorageFormat}; -use sui_swarm_config::test_utils::{empty_contents, CommitteeFixture}; -use sui_types::{ - messages_checkpoint::{VerifiedCheckpoint, VerifiedCheckpointContents}, - storage::{ReadStore, SharedInMemoryStore, SingleCheckpointSharedInMemoryStore}, -}; -use tempfile::tempdir; - -use crate::{ - read_manifest, - reader::{ArchiveReader, ArchiveReaderMetrics}, - verify_archive_with_local_store, write_manifest, - writer::ArchiveWriter, - Manifest, -}; - -struct TestState { - archive_writer: ArchiveWriter, - archive_reader: ArchiveReader, - local_path: PathBuf, - remote_path: PathBuf, - local_store: Arc, - remote_store: Arc, - local_store_config: ObjectStoreConfig, - remote_store_config: ObjectStoreConfig, - committee: CommitteeFixture, -} - -fn temp_dir() -> std::path::PathBuf { - tempdir() - .expect("Failed to open temporary directory") - .into_path() -} - -async fn write_new_checkpoints_to_store( - test_state: &TestState, - store: SharedInMemoryStore, - num_checkpoints: usize, - prev_checkpoint: Option, -) -> Result> { - let (ordered_checkpoints, _contents, _sequence_number_to_digest, _checkpoints) = test_state - .committee - .make_empty_checkpoints(num_checkpoints, prev_checkpoint.clone()); - if prev_checkpoint.is_none() { - store.inner_mut().insert_genesis_state( - ordered_checkpoints.first().cloned().unwrap(), - empty_contents(), - test_state.committee.committee().to_owned(), - ); - } - for checkpoint in ordered_checkpoints.iter() { - store.inner_mut().insert_checkpoint(checkpoint); - } - Ok(ordered_checkpoints.last().cloned()) -} - -async fn setup_test_state(temp_dir: PathBuf) -> anyhow::Result { - let local_path = temp_dir.join("local_dir"); - let remote_path = temp_dir.join("remote_dir"); - let local_store_config = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(local_path.clone()), - ..Default::default() - }; - let remote_store_config = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(remote_path.clone()), - ..Default::default() - }; - let committee = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); - let archive_writer = ArchiveWriter::new( - local_store_config.clone(), - remote_store_config.clone(), - FileCompression::Zstd, - StorageFormat::Blob, - Duration::from_secs(10), - 20, - &Registry::default(), - ) - .await?; - let archive_reader_config = ArchiveReaderConfig { - remote_store_config: remote_store_config.clone(), - download_concurrency: NonZeroUsize::new(2).unwrap(), - use_for_pruning_watermark: false, - }; - let metrics = ArchiveReaderMetrics::new(&Registry::default()); - let archive_reader = ArchiveReader::new(archive_reader_config, &metrics)?; - let local_store = local_store_config.make()?; - let remote_store = remote_store_config.make()?; - Ok(TestState { - archive_writer, - archive_reader, - local_path, - remote_path, - local_store, - remote_store, - local_store_config, - remote_store_config, - committee, - }) -} - -async fn insert_checkpoints_and_verify_manifest( - test_state: &TestState, - test_store: SharedInMemoryStore, - prev_checkpoint: Option, -) -> Result> { - let mut prev_tail = None; - let mut prev_checkpoint = prev_checkpoint; - let mut num_verified_iterations = 0; - loop { - if test_state.remote_path.join("MANIFEST").exists() { - if let Ok(manifest) = read_manifest(test_state.remote_store.clone()).await { - for file in manifest.files().into_iter() { - let file_path = - path_to_filesystem(test_state.remote_path.clone(), &file.file_path())?; - assert!(file_path.exists()); - } - - if let Some(prev_tail) = prev_tail { - // Ensure checkpoint sequence number in manifest never moves back - assert!(manifest.next_checkpoint_seq_num() >= prev_tail); - if manifest.next_checkpoint_seq_num() > prev_tail { - num_verified_iterations += 1; - } - } - prev_tail = Some(manifest.next_checkpoint_seq_num()); - // Break out of the loop once we have ensured that we noticed MANIFEST - // got updated at least 5 times - if num_verified_iterations > 5 { - break; - } - } - } - tokio::time::sleep(Duration::from_secs(1)).await; - prev_checkpoint = - write_new_checkpoints_to_store(test_state, test_store.clone(), 1, prev_checkpoint) - .await?; - } - Ok(prev_checkpoint) -} - -#[tokio::test] -async fn test_archive_basic() -> Result<(), anyhow::Error> { - let test_store = SharedInMemoryStore::default(); - let test_state = setup_test_state(temp_dir()).await?; - let kill = test_state.archive_writer.start(test_store.clone()).await?; - insert_checkpoints_and_verify_manifest(&test_state, test_store, None).await?; - kill.send(())?; - Ok(()) -} - -#[tokio::test] -async fn test_archive_resumes() -> Result<(), anyhow::Error> { - let test_store = SharedInMemoryStore::default(); - let test_state = setup_test_state(temp_dir()).await?; - let kill = test_state.archive_writer.start(test_store.clone()).await?; - let prev_checkpoint = - insert_checkpoints_and_verify_manifest(&test_state, test_store.clone(), None).await?; - - // Kill the archive writer so we can restart it again - drop(kill); - let test_state = setup_test_state(temp_dir()).await?; - let kill = test_state.archive_writer.start(test_store.clone()).await?; - insert_checkpoints_and_verify_manifest(&test_state, test_store, prev_checkpoint).await?; - kill.send(())?; - Ok(()) -} - -#[tokio::test] -async fn test_manifest_serde() -> Result<()> { - let original_manifest = Manifest::new(0, 100); - let remote_store = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(temp_dir()), - ..Default::default() - } - .make()?; - write_manifest(original_manifest.clone(), remote_store.clone()).await?; - let downloaded_manifest = read_manifest(remote_store).await?; - assert_eq!(downloaded_manifest, original_manifest); - Ok(()) -} - -#[tokio::test] -async fn test_archive_reader_e2e() -> Result<(), anyhow::Error> { - let test_store = SharedInMemoryStore::default(); - let test_state = setup_test_state(temp_dir()).await?; - let kill = test_state.archive_writer.start(test_store.clone()).await?; - let mut latest_archived_checkpoint_seq_num = 0; - while latest_archived_checkpoint_seq_num < 10 { - insert_checkpoints_and_verify_manifest(&test_state, test_store.clone(), None).await?; - let new_latest_archived_checkpoint_seq_num = test_state - .archive_reader - .latest_available_checkpoint() - .await?; - ma::assert_ge!( - new_latest_archived_checkpoint_seq_num, - latest_archived_checkpoint_seq_num - ); - latest_archived_checkpoint_seq_num = new_latest_archived_checkpoint_seq_num; - tokio::time::sleep(Duration::from_secs(1)).await; - } - ma::assert_ge!(latest_archived_checkpoint_seq_num, 10); - let genesis_checkpoint = test_store - .get_checkpoint_by_sequence_number(0)? - .context("Missing genesis checkpoint")?; - let genesis_checkpoint_content = test_store - .get_full_checkpoint_contents_by_sequence_number(0)? - .context("Missing genesis checkpoint")?; - let read_store = SharedInMemoryStore::default(); - read_store.inner_mut().insert_genesis_state( - genesis_checkpoint, - VerifiedCheckpointContents::new_unchecked(genesis_checkpoint_content), - test_state.committee.committee().to_owned(), - ); - let tx_counter = Arc::new(AtomicU64::new(0)); - let checkpoint_counter = Arc::new(AtomicU64::new(0)); - test_state.archive_reader.sync_manifest_once().await?; - test_state - .archive_reader - .read( - read_store.clone(), - 0..(latest_archived_checkpoint_seq_num + 1), - tx_counter, - checkpoint_counter, - true, - ) - .await?; - ma::assert_ge!( - read_store - .get_highest_verified_checkpoint()? - .sequence_number, - latest_archived_checkpoint_seq_num - ); - ma::assert_ge!( - read_store.get_highest_synced_checkpoint()?.sequence_number, - latest_archived_checkpoint_seq_num - ); - kill.send(())?; - Ok(()) -} - -#[tokio::test] -async fn test_verify_archive_with_oneshot_store() -> Result<(), anyhow::Error> { - let test_store = SharedInMemoryStore::default(); - let test_state = setup_test_state(temp_dir()).await?; - let kill = test_state.archive_writer.start(test_store.clone()).await?; - let mut latest_archived_checkpoint_seq_num = 0; - while latest_archived_checkpoint_seq_num < 10 { - insert_checkpoints_and_verify_manifest(&test_state, test_store.clone(), None).await?; - let new_latest_archived_checkpoint_seq_num = test_state - .archive_reader - .latest_available_checkpoint() - .await?; - ma::assert_ge!( - new_latest_archived_checkpoint_seq_num, - latest_archived_checkpoint_seq_num - ); - latest_archived_checkpoint_seq_num = new_latest_archived_checkpoint_seq_num; - tokio::time::sleep(Duration::from_secs(1)).await; - } - ma::assert_ge!(latest_archived_checkpoint_seq_num, 10); - let genesis_checkpoint = test_store - .get_checkpoint_by_sequence_number(0)? - .context("Missing genesis checkpoint")?; - let genesis_checkpoint_content = test_store - .get_full_checkpoint_contents_by_sequence_number(0)? - .context("Missing genesis checkpoint")?; - let mut read_store = SingleCheckpointSharedInMemoryStore::default(); - read_store.insert_genesis_state( - genesis_checkpoint, - VerifiedCheckpointContents::new_unchecked(genesis_checkpoint_content), - test_state.committee.committee().to_owned(), - ); - - // Verification should pass - assert!( - verify_archive_with_local_store( - read_store, - test_state.remote_store_config.clone(), - 1, - false - ) - .await - .is_ok() - ); - kill.send(())?; - Ok(()) -} - -#[tokio::test] -async fn test_verify_archive_with_oneshot_store_bad_data() -> Result<(), anyhow::Error> { - let test_store = SharedInMemoryStore::default(); - let test_state = setup_test_state(temp_dir()).await?; - let kill = test_state.archive_writer.start(test_store.clone()).await?; - let mut latest_archived_checkpoint_seq_num = 0; - while latest_archived_checkpoint_seq_num < 10 { - insert_checkpoints_and_verify_manifest(&test_state, test_store.clone(), None).await?; - let new_latest_archived_checkpoint_seq_num = test_state - .archive_reader - .latest_available_checkpoint() - .await?; - ma::assert_ge!( - new_latest_archived_checkpoint_seq_num, - latest_archived_checkpoint_seq_num - ); - latest_archived_checkpoint_seq_num = new_latest_archived_checkpoint_seq_num; - tokio::time::sleep(Duration::from_secs(1)).await; - } - ma::assert_ge!(latest_archived_checkpoint_seq_num, 10); - - // Corrupt the .chk and .sum files in the archive - let dir = fs::read_dir(test_state.remote_path)?; - let mut num_files_corrupted = 0; - for file in dir { - let file = file?; - let file_metadata = file.metadata()?; - if file_metadata.is_dir() { - // epoch dir - let epoch_dir = fs::read_dir(file.path())?; - for epoch_file in epoch_dir { - let epoch_file = epoch_file?; - // epoch dir should only have checkpoint files and no dir - assert!(epoch_file.metadata()?.is_file()); - if epoch_file - .file_name() - .into_string() - .map_err(|_| anyhow!("Failed to read file name"))? - .ends_with(".chk") - { - let mut f = File::options().write(true).open(epoch_file.path())?; - f.write_all("hello_world".as_bytes())?; - num_files_corrupted += 1; - } - } - } - } - ma::assert_gt!(num_files_corrupted, 0); - let genesis_checkpoint = test_store - .get_checkpoint_by_sequence_number(0)? - .context("Missing genesis checkpoint")?; - let genesis_checkpoint_content = test_store - .get_full_checkpoint_contents_by_sequence_number(0)? - .context("Missing genesis checkpoint")?; - let mut read_store = SingleCheckpointSharedInMemoryStore::default(); - read_store.insert_genesis_state( - genesis_checkpoint, - VerifiedCheckpointContents::new_unchecked(genesis_checkpoint_content), - test_state.committee.committee().to_owned(), - ); - - // Verification should fail - assert!( - verify_archive_with_local_store( - read_store, - test_state.remote_store_config.clone(), - 1, - false - ) - .await - .is_err() - ); - kill.send(())?; - - Ok(()) -} diff --git a/crates/sui-archival/src/writer.rs b/crates/sui-archival/src/writer.rs deleted file mode 100644 index 72b750d621e..00000000000 --- a/crates/sui-archival/src/writer.rs +++ /dev/null @@ -1,511 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -#![allow(dead_code)] - -use std::{ - fs, - fs::{File, OpenOptions}, - io::{BufWriter, Seek, SeekFrom, Write}, - ops::Range, - path::{Path, PathBuf}, - sync::Arc, - thread::sleep, - time::Duration, -}; - -use anyhow::{anyhow, Context, Result}; -use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; -use object_store::DynObjectStore; -use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; -use sui_config::object_storage_config::ObjectStoreConfig; -use sui_storage::{ - blob::{Blob, BlobEncoding}, - compress, - object_store::util::{copy_file, path_to_filesystem}, - FileCompression, StorageFormat, -}; -use sui_types::{ - messages_checkpoint::{ - CertifiedCheckpointSummary as Checkpoint, CheckpointSequenceNumber, - FullCheckpointContents as CheckpointContents, - }, - storage::WriteStore, -}; -use tokio::{ - sync::{ - mpsc, - mpsc::{Receiver, Sender}, - }, - time::Instant, -}; -use tracing::{debug, info}; - -use crate::{ - create_file_metadata, read_manifest, write_manifest, CheckpointUpdates, FileMetadata, FileType, - Manifest, CHECKPOINT_FILE_MAGIC, CHECKPOINT_FILE_SUFFIX, EPOCH_DIR_PREFIX, MAGIC_BYTES, - SUMMARY_FILE_MAGIC, SUMMARY_FILE_SUFFIX, -}; - -pub struct ArchiveMetrics { - pub latest_checkpoint_archived: IntGauge, -} - -impl ArchiveMetrics { - pub fn new(registry: &Registry) -> Arc { - let this = Self { - latest_checkpoint_archived: register_int_gauge_with_registry!( - "latest_checkpoint_archived", - "Latest checkpoint to have archived to the remote store", - registry - ) - .unwrap(), - }; - Arc::new(this) - } -} - -/// CheckpointWriter writes checkpoints and summaries. It creates multiple *.chk -/// and *.sum files -struct CheckpointWriter { - root_dir_path: PathBuf, - epoch_num: u64, - checkpoint_range: Range, - wbuf: BufWriter, - summary_wbuf: BufWriter, - sender: Sender, - checkpoint_buf_offset: usize, - file_compression: FileCompression, - storage_format: StorageFormat, - manifest: Manifest, - last_commit_instant: Instant, - commit_duration: Duration, - commit_file_size: usize, -} - -impl CheckpointWriter { - fn new( - root_dir_path: PathBuf, - file_compression: FileCompression, - storage_format: StorageFormat, - sender: Sender, - manifest: Manifest, - commit_duration: Duration, - commit_file_size: usize, - ) -> Result { - let epoch_num = manifest.epoch_num(); - let checkpoint_sequence_num = manifest.next_checkpoint_seq_num(); - let epoch_dir = root_dir_path.join(format!("{}{epoch_num}", EPOCH_DIR_PREFIX)); - if epoch_dir.exists() { - fs::remove_dir_all(&epoch_dir)?; - } - fs::create_dir_all(&epoch_dir)?; - let checkpoint_file = Self::next_file( - &epoch_dir, - checkpoint_sequence_num, - CHECKPOINT_FILE_SUFFIX, - CHECKPOINT_FILE_MAGIC, - storage_format, - file_compression, - )?; - let summary_file = Self::next_file( - &epoch_dir, - checkpoint_sequence_num, - SUMMARY_FILE_SUFFIX, - SUMMARY_FILE_MAGIC, - storage_format, - file_compression, - )?; - Ok(CheckpointWriter { - root_dir_path, - epoch_num, - checkpoint_range: checkpoint_sequence_num..checkpoint_sequence_num, - wbuf: BufWriter::new(checkpoint_file), - summary_wbuf: BufWriter::new(summary_file), - checkpoint_buf_offset: 0, - sender, - file_compression, - storage_format, - manifest, - last_commit_instant: Instant::now(), - commit_duration, - commit_file_size, - }) - } - - pub fn write( - &mut self, - checkpoint_contents: CheckpointContents, - checkpoint_summary: Checkpoint, - ) -> Result<()> { - match self.storage_format { - StorageFormat::Blob => self.write_as_blob(checkpoint_contents, checkpoint_summary), - } - } - - pub fn write_as_blob( - &mut self, - checkpoint_contents: CheckpointContents, - checkpoint_summary: Checkpoint, - ) -> Result<()> { - assert_eq!( - checkpoint_summary.sequence_number, - self.checkpoint_range.end - ); - - if checkpoint_summary.epoch() - == self - .epoch_num - .checked_add(1) - .context("Epoch num overflow")? - { - self.cut()?; - self.update_to_next_epoch(); - if self.epoch_dir().exists() { - fs::remove_dir_all(self.epoch_dir())?; - } - fs::create_dir_all(self.epoch_dir())?; - self.reset()?; - } - - assert_eq!(checkpoint_summary.epoch, self.epoch_num); - - assert_eq!( - checkpoint_summary.content_digest, - *checkpoint_contents.checkpoint_contents().digest() - ); - - let contents_blob = Blob::encode(&checkpoint_contents, BlobEncoding::Bcs)?; - let blob_size = contents_blob.size(); - let cut_new_checkpoint_file = (self.checkpoint_buf_offset + blob_size) - > self.commit_file_size - || (self.last_commit_instant.elapsed() > self.commit_duration); - if cut_new_checkpoint_file { - self.cut()?; - self.reset()?; - } - - self.checkpoint_buf_offset += contents_blob.write(&mut self.wbuf)?; - - let summary_blob = Blob::encode(&checkpoint_summary, BlobEncoding::Bcs)?; - summary_blob.write(&mut self.summary_wbuf)?; - - self.checkpoint_range.end = self - .checkpoint_range - .end - .checked_add(1) - .context("Checkpoint sequence num overflow")?; - Ok(()) - } - fn finalize(&mut self) -> Result { - self.wbuf.flush()?; - self.wbuf.get_ref().sync_data()?; - let off = self.wbuf.get_ref().stream_position()?; - self.wbuf.get_ref().set_len(off)?; - let file_path = self.epoch_dir().join(format!( - "{}.{CHECKPOINT_FILE_SUFFIX}", - self.checkpoint_range.start - )); - self.compress(&file_path)?; - let file_metadata = create_file_metadata( - &file_path, - FileType::CheckpointContent, - self.epoch_num, - self.checkpoint_range.clone(), - )?; - Ok(file_metadata) - } - fn finalize_summary(&mut self) -> Result { - self.summary_wbuf.flush()?; - self.summary_wbuf.get_ref().sync_data()?; - let off = self.summary_wbuf.get_ref().stream_position()?; - self.summary_wbuf.get_ref().set_len(off)?; - let file_path = self.epoch_dir().join(format!( - "{}.{SUMMARY_FILE_SUFFIX}", - self.checkpoint_range.start - )); - self.compress(&file_path)?; - let file_metadata = create_file_metadata( - &file_path, - FileType::CheckpointSummary, - self.epoch_num, - self.checkpoint_range.clone(), - )?; - Ok(file_metadata) - } - fn cut(&mut self) -> Result<()> { - if !self.checkpoint_range.is_empty() { - let checkpoint_file_metadata = self.finalize()?; - let summary_file_metadata = self.finalize_summary()?; - let checkpoint_updates = CheckpointUpdates::new( - self.epoch_num, - self.checkpoint_range.end, - checkpoint_file_metadata, - summary_file_metadata, - &mut self.manifest, - ); - info!("Checkpoint file cut for: {:?}", checkpoint_updates); - self.sender.blocking_send(checkpoint_updates)?; - } - Ok(()) - } - fn compress(&self, source: &Path) -> Result<()> { - if self.file_compression == FileCompression::None { - return Ok(()); - } - let mut input = File::open(source)?; - let tmp_file_name = source.with_extension("tmp"); - let mut output = File::create(&tmp_file_name)?; - compress(&mut input, &mut output)?; - fs::rename(tmp_file_name, source)?; - Ok(()) - } - fn next_file( - dir_path: &Path, - checkpoint_sequence_num: u64, - suffix: &str, - magic_bytes: u32, - storage_format: StorageFormat, - file_compression: FileCompression, - ) -> Result { - let next_file_path = dir_path.join(format!("{checkpoint_sequence_num}.{suffix}")); - let mut f = File::create(next_file_path.clone())?; - let mut metab = [0u8; MAGIC_BYTES]; - BigEndian::write_u32(&mut metab, magic_bytes); - let n = f.write(&metab)?; - drop(f); - f = OpenOptions::new().append(true).open(next_file_path)?; - f.seek(SeekFrom::Start(n as u64))?; - f.write_u8(storage_format.into())?; - f.write_u8(file_compression.into())?; - Ok(f) - } - fn create_new_files(&mut self) -> Result<()> { - let f = Self::next_file( - &self.epoch_dir(), - self.checkpoint_range.start, - CHECKPOINT_FILE_SUFFIX, - CHECKPOINT_FILE_MAGIC, - self.storage_format, - self.file_compression, - )?; - self.checkpoint_buf_offset = MAGIC_BYTES; - self.wbuf = BufWriter::new(f); - let f = Self::next_file( - &self.epoch_dir(), - self.checkpoint_range.start, - SUMMARY_FILE_SUFFIX, - SUMMARY_FILE_MAGIC, - self.storage_format, - self.file_compression, - )?; - self.summary_wbuf = BufWriter::new(f); - Ok(()) - } - fn reset(&mut self) -> Result<()> { - self.reset_checkpoint_range(); - self.create_new_files()?; - self.reset_last_commit_ts(); - Ok(()) - } - fn reset_last_commit_ts(&mut self) { - self.last_commit_instant = Instant::now(); - } - fn reset_checkpoint_range(&mut self) { - self.checkpoint_range = self.checkpoint_range.end..self.checkpoint_range.end - } - fn epoch_dir(&self) -> PathBuf { - self.root_dir_path - .join(format!("{}{}", EPOCH_DIR_PREFIX, self.epoch_num)) - } - fn update_to_next_epoch(&mut self) { - self.epoch_num = self.epoch_num.checked_add(1).unwrap(); - } -} - -/// ArchiveWriter archives history by tailing checkpoints writing them to a -/// local staging dir and simultaneously uploading them to a remote object store -pub struct ArchiveWriter { - file_compression: FileCompression, - storage_format: StorageFormat, - local_staging_dir_root: PathBuf, - local_object_store: Arc, - remote_object_store: Arc, - commit_duration: Duration, - commit_file_size: usize, - archive_metrics: Arc, -} - -impl ArchiveWriter { - pub async fn new( - local_store_config: ObjectStoreConfig, - remote_store_config: ObjectStoreConfig, - file_compression: FileCompression, - storage_format: StorageFormat, - commit_duration: Duration, - commit_file_size: usize, - registry: &Registry, - ) -> Result { - Ok(ArchiveWriter { - file_compression, - storage_format, - remote_object_store: remote_store_config.make()?, - local_object_store: local_store_config.make()?, - local_staging_dir_root: local_store_config.directory.context("Missing local dir")?, - commit_duration, - commit_file_size, - archive_metrics: ArchiveMetrics::new(registry), - }) - } - - pub async fn start(&self, store: S) -> Result> - where - S: WriteStore + Send + Sync + 'static, - { - let remote_archive_is_empty = self - .remote_object_store - .list_with_delimiter(None) - .await - .expect("Failed to read remote archive dir") - .common_prefixes - .is_empty(); - let manifest = if remote_archive_is_empty { - // Start from genesis - Manifest::new(0, 0) - } else { - read_manifest(self.remote_object_store.clone()) - .await - .expect("Failed to read manifest") - }; - let start_checkpoint_sequence_number = manifest.next_checkpoint_seq_num(); - let (sender, receiver) = mpsc::channel::(100); - let checkpoint_writer = CheckpointWriter::new( - self.local_staging_dir_root.clone(), - self.file_compression, - self.storage_format, - sender, - manifest, - self.commit_duration, - self.commit_file_size, - ) - .expect("Failed to create checkpoint writer"); - let (kill_sender, kill_receiver) = tokio::sync::broadcast::channel::<()>(1); - tokio::spawn(Self::start_syncing_with_remote( - self.remote_object_store.clone(), - self.local_object_store.clone(), - self.local_staging_dir_root.clone(), - receiver, - kill_sender.subscribe(), - self.archive_metrics.clone(), - )); - tokio::task::spawn_blocking(move || { - Self::start_tailing_checkpoints( - start_checkpoint_sequence_number, - checkpoint_writer, - store, - kill_receiver, - ) - }); - Ok(kill_sender) - } - - fn start_tailing_checkpoints( - start_checkpoint_sequence_number: CheckpointSequenceNumber, - mut checkpoint_writer: CheckpointWriter, - store: S, - mut kill: tokio::sync::broadcast::Receiver<()>, - ) -> Result<()> - where - S: WriteStore + Send + Sync + 'static, - { - let mut checkpoint_sequence_number = start_checkpoint_sequence_number; - info!("Starting checkpoint tailing from sequence number: {checkpoint_sequence_number}"); - - while kill.try_recv().is_err() { - if let Some(checkpoint_summary) = store - .get_checkpoint_by_sequence_number(checkpoint_sequence_number) - .map_err(|_| anyhow!("Failed to read checkpoint summary from store"))? - { - if let Some(checkpoint_contents) = store - .get_full_checkpoint_contents(&checkpoint_summary.content_digest) - .map_err(|_| anyhow!("Failed to read checkpoint content from store"))? - { - checkpoint_writer - .write(checkpoint_contents, checkpoint_summary.into_inner())?; - checkpoint_sequence_number = checkpoint_sequence_number - .checked_add(1) - .context("checkpoint seq number overflow")?; - // There is more checkpoints to tail, so continue without sleeping - continue; - } - } - // Checkpoint with `checkpoint_sequence_number` is not available to read from - // store yet, sleep for sometime and then retry - sleep(Duration::from_secs(3)); - } - Ok(()) - } - - async fn start_syncing_with_remote( - remote_object_store: Arc, - local_object_store: Arc, - local_staging_root_dir: PathBuf, - mut update_receiver: Receiver, - mut kill: tokio::sync::broadcast::Receiver<()>, - metrics: Arc, - ) -> Result<()> { - loop { - tokio::select! { - _ = kill.recv() => break, - updates = update_receiver.recv() => { - if let Some(checkpoint_updates) = updates { - info!("Received checkpoint update: {:?}", checkpoint_updates); - let latest_checkpoint_seq_num = checkpoint_updates.manifest.next_checkpoint_seq_num(); - let summary_file_path = checkpoint_updates.summary_file_path(); - Self::sync_file_to_remote( - local_staging_root_dir.clone(), - summary_file_path, - local_object_store.clone(), - remote_object_store.clone() - ) - .await - .expect("Syncing checkpoint summary should not fail"); - - let content_file_path = checkpoint_updates.content_file_path(); - Self::sync_file_to_remote( - local_staging_root_dir.clone(), - content_file_path, - local_object_store.clone(), - remote_object_store.clone() - ) - .await - .expect("Syncing checkpoint content should not fail"); - - write_manifest( - checkpoint_updates.manifest, - remote_object_store.clone() - ) - .await - .expect("Updating manifest should not fail"); - metrics.latest_checkpoint_archived.set(latest_checkpoint_seq_num as i64) - } else { - info!("Terminating archive sync loop"); - break; - } - }, - } - } - Ok(()) - } - - async fn sync_file_to_remote( - dir: PathBuf, - path: object_store::path::Path, - from: Arc, - to: Arc, - ) -> Result<()> { - debug!("Syncing archive file to remote: {:?}", path); - copy_file(&path, &path, &from, &to).await?; - fs::remove_file(path_to_filesystem(dir, &path)?)?; - Ok(()) - } -} diff --git a/crates/sui-authority-aggregation/Cargo.toml b/crates/sui-authority-aggregation/Cargo.toml deleted file mode 100644 index 639b36909a0..00000000000 --- a/crates/sui-authority-aggregation/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "sui-authority-aggregation" -authors = ["Mysten Labs "] -license = "Apache-2.0" -version = "0.1.0" -edition = "2021" -publish = false - -[dependencies] -sui-types.workspace = true -mysten-metrics.workspace = true -tokio.workspace = true -tracing.workspace = true -futures.workspace = true diff --git a/crates/sui-authority-aggregation/src/lib.rs b/crates/sui-authority-aggregation/src/lib.rs deleted file mode 100644 index d2086ca733f..00000000000 --- a/crates/sui-authority-aggregation/src/lib.rs +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::{BTreeMap, BTreeSet}, - sync::Arc, - time::Duration, -}; - -use futures::{future::BoxFuture, stream::FuturesUnordered, Future, StreamExt}; -use mysten_metrics::monitored_future; -use sui_types::{ - base_types::ConciseableName, - committee::{CommitteeTrait, StakeUnit}, -}; -use tokio::time::timeout; -use tracing::instrument::Instrument; - -pub type AsyncResult<'a, T, E> = BoxFuture<'a, Result>; - -pub enum ReduceOutput { - Continue(S), - ContinueWithTimeout(S, Duration), - Failed(S), - Success(R), -} - -pub async fn quorum_map_then_reduce_with_timeout_and_prefs< - 'a, - C, - K, - Client: 'a, - S, - V, - R, - E, - FMap, - FReduce, ->( - committee: Arc, - authority_clients: Arc>>, - authority_preferences: Option<&BTreeSet>, - initial_state: S, - map_each_authority: FMap, - reduce_result: FReduce, - initial_timeout: Duration, -) -> Result< - ( - R, - FuturesUnordered)> + 'a>, - ), - S, -> -where - K: Ord + ConciseableName<'a> + Copy + 'a, - C: CommitteeTrait, - FMap: FnOnce(K, Arc) -> AsyncResult<'a, V, E> + Clone + 'a, - FReduce: Fn(S, K, StakeUnit, Result) -> BoxFuture<'a, ReduceOutput>, -{ - let authorities_shuffled = committee.shuffle_by_stake(authority_preferences, None); - - // First, execute in parallel for each authority FMap. - let mut responses: futures::stream::FuturesUnordered<_> = authorities_shuffled - .into_iter() - .map(|name| { - let client = authority_clients[&name].clone(); - let execute = map_each_authority.clone(); - let concise_name = name.concise_owned(); - monitored_future!(async move { - ( - name, - execute(name, client) - .instrument( - tracing::trace_span!("quorum_map_auth", authority =? concise_name), - ) - .await, - ) - }) - }) - .collect(); - - let mut current_timeout = initial_timeout; - let mut accumulated_state = initial_state; - // Then, as results become available fold them into the state using FReduce. - while let Ok(Some((authority_name, result))) = timeout(current_timeout, responses.next()).await - { - let authority_weight = committee.weight(&authority_name); - accumulated_state = - match reduce_result(accumulated_state, authority_name, authority_weight, result).await { - // In the first two cases we are told to continue the iteration. - ReduceOutput::Continue(state) => state, - ReduceOutput::ContinueWithTimeout(state, duration) => { - // Adjust the waiting timeout. - current_timeout = duration; - state - } - ReduceOutput::Failed(state) => { - return Err(state); - } - ReduceOutput::Success(result) => { - // The reducer tells us that we have the result needed. Just return it. - return Ok((result, responses)); - } - } - } - // If we have exhausted all authorities and still have not returned a result, - // return error with the accumulated state. - Err(accumulated_state) -} - -/// This function takes an initial state, than executes an asynchronous function -/// (FMap) for each authority, and folds the results as they become available -/// into the state using an async function (FReduce). -/// -/// FMap can do io, and returns a result V. An error there may not be fatal, and -/// could be consumed by the MReduce function to overall recover from it. This -/// is necessary to ensure byzantine authorities cannot interrupt the logic of -/// this function. -/// -/// FReduce returns a result to a ReduceOutput. If the result is Err the -/// function shortcuts and the Err is returned. An Ok ReduceOutput result can be -/// used to shortcut and return the resulting state (ReduceOutput::End), -/// continue the folding as new states arrive (ReduceOutput::Continue), -/// or continue with a timeout maximum waiting time -/// (ReduceOutput::ContinueWithTimeout). -/// -/// This function provides a flexible way to communicate with a quorum of -/// authorities, processing and processing their results into a safe overall -/// result, and also safely allowing operations to continue past the quorum to -/// ensure all authorities are up to date (up to a timeout). -pub async fn quorum_map_then_reduce_with_timeout< - 'a, - C, - K, - Client: 'a, - S: 'a, - V: 'a, - R: 'a, - E, - FMap, - FReduce, ->( - committee: Arc, - authority_clients: Arc>>, - // The initial state that will be used to fold in values from authorities. - initial_state: S, - // The async function used to apply to each authority. It takes an authority name, - // and authority client parameter and returns a Result. - map_each_authority: FMap, - // The async function that takes an accumulated state, and a new result for V from an - // authority and returns a result to a ReduceOutput state. - reduce_result: FReduce, - // The initial timeout applied to all - initial_timeout: Duration, -) -> Result< - ( - R, - FuturesUnordered)> + 'a>, - ), - S, -> -where - K: Ord + ConciseableName<'a> + Copy + 'a, - C: CommitteeTrait, - FMap: FnOnce(K, Arc) -> AsyncResult<'a, V, E> + Clone + 'a, - FReduce: Fn(S, K, StakeUnit, Result) -> BoxFuture<'a, ReduceOutput> + 'a, -{ - quorum_map_then_reduce_with_timeout_and_prefs( - committee, - authority_clients, - None, - initial_state, - map_each_authority, - reduce_result, - initial_timeout, - ) - .await -} diff --git a/crates/sui-aws-orchestrator/Cargo.toml b/crates/sui-aws-orchestrator/Cargo.toml deleted file mode 100644 index c9489e8c2ae..00000000000 --- a/crates/sui-aws-orchestrator/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "sui-aws-orchestrator" -version = "0.0.1" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -aws-sdk-ec2.workspace = true -aws-smithy-http.workspace = true -aws-smithy-runtime-api.workspace = true -russh.workspace = true -russh-keys.workspace = true -aws-config.workspace = true -color-eyre.workspace = true -clap.workspace = true -eyre.workspace = true -prettytable-rs.workspace = true -serde_json.workspace = true -futures.workspace = true -thiserror.workspace = true -reqwest.workspace = true -async-trait.workspace = true -crossterm.workspace = true -serde.workspace = true -tokio = { workspace = true, features = ["full"] } -prometheus-parse.workspace = true - -mysten-metrics.workspace = true -sui-config = { path = "../sui-config" } -narwhal-config.workspace = true -sui-types = { path = "../sui-types" } -sui-swarm-config = { path = "../sui-swarm-config" } - -[dev-dependencies] -tempfile = "3.6.0" - -[[bin]] -name = "sui-aws-orchestrator" -path = "src/main.rs" diff --git a/crates/sui-aws-orchestrator/README.md b/crates/sui-aws-orchestrator/README.md deleted file mode 100644 index 436c842e8ed..00000000000 --- a/crates/sui-aws-orchestrator/README.md +++ /dev/null @@ -1,157 +0,0 @@ -# Orchestrator - -The Orchestrator crate provides facilities for quickly deploying and benchmarking this codebase in a geo-distributed environment. Please note that it is not intended for production deployments or as an indicator of production engineering best practices. Its purpose is to facilitate research projects by allowing benchmarking of (variants of) the codebase and analyzing performance. - -This guide provides a step-by-step explanation of how to run geo-distributed benchmarks on [Amazon Web Services (AWS)](http://aws.amazon.com). - -## Step 1. Set up credentials - -To enable programmatic access to your cloud provider account from your local machine, you need to set up your cloud provider credentials. These credentials authorize your machine to create, delete, and edit instances programmatically on your account. - -### Setting up AWS credentials - -1. Find your ['access key id' and 'secret access key'](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds). -2. Create a file `~/.aws/credentials` with the following content: - -```text -[default] -aws_access_key_id = YOUR_ACCESS_KEY_ID -aws_secret_access_key = YOUR_SECRET_ACCESS_KEY -``` - -Do not specify any AWS region in that file, as the scripts need to handle multiple regions programmatically. - -### Setting up SSH credentials - -Running `ssh-keygen -t ed25519 -C "..."` would generate a new ssh key pair under the specified path, -e.g. private key at `~/.ssh/aws` and public key at `~/.ssh/aws.pub`. If the public key is not -at the corresponding private key path with `.pub` extension, then the public key path must be specified -for `ssh_public_key_file` in `settings.json`. - -## Step 2. Specify the testbed configuration - -Create a file called `settings.json` that contains all the configuration parameters for the testbed deployment. You can find a template at `./assets/settings-template.json`. Example content: - -```json -{ - "testbed_id": "alberto-0", - "cloud_provider": "aws", - "token_file": "/Users/alberto/.aws/credentials", - "ssh_private_key_file": "/Users/alberto/.ssh/aws", - "regions": [ - "us-east-1", - "us-west-2", - "ca-central-1", - "eu-central-1", - "ap-northeast-1", - "eu-west-1", - "eu-west-2", - "ap-south-1", - "ap-southeast-1", - "ap-southeast-2" - ], - "specs": "m5d.8xlarge", - "repository": { - "url": "https://github.com/MystenLabs/sui.git", - "commit": "main" - }, - "results_directory": "./results", - "logs_directory": "./logs" -} -``` - -The documentation of the `Settings` struct in `./src/settings.rs` provides detailed information about each `Settings` field. - -If you're working with a private GitHub repository, you can include a [private access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) in the repository URL. For example, if your access token is `[your_token]`, the repository URL should be formatted as follows: - -```json -"repository": { - "url": "http://[your_token]@github.com/mystenlabs/sui.git", - "commit": "main" -} -``` - -## Step 3. Create a testbed - -The `sui-aws-orchestrator` binary provides various functionalities for creating, starting, stopping, and destroying instances. You can use the following command to boot 2 instances per region (if the settings file specifies 10 regions, as shown in the example above, a total of 20 instances will be created): - -```bash -cargo run --bin sui-aws-orchestrator -- testbed deploy --instances 2 -``` - -To check the current status of the testbed instances, use the following command: - -```bash -cargo run --bin sui-aws-orchestrator testbed status -``` - -Instances listed with a green number are available and ready for use, while instances listed with a red number are stopped. - -Also keep in mind that there is nothing stopping you from running the `deploy` command multiple times if you find your self -needing more instances down the line. - -## Step 4. Choose protocol - -There is support to benchmark either Sui or Narwhal only. To choose which protocol to benchmark, you can set the `Protocol` & `BenchmarkType` field [here](https://github.com/MystenLabs/sui/blob/main/crates/sui-aws-orchestrator/src/main.rs#L33-L34) - -``` -// Sui -use protocol::sui::{SuiBenchmarkType, SuiProtocol}; -type Protocol = SuiProtocol; -type BenchmarkType = SuiBenchmarkType; -// Narwhal -use protocol::narwhal::{NarwhalBenchmarkType, NarwhalProtocol}; -type Protocol = NarwhalProtocol; -type BenchmarkType = NarwhalBenchmarkType; -``` - -## Step 5. Running benchmarks - -Running benchmarks involves installing the specified version of the codebase on the remote machines and running one validator and one load generator per instance. For example, the following command benchmarks a committee of 10 validators under a constant load of 200 tx/s for 3 minutes: - -```bash -cargo run --bin sui-aws-orchestrator -- benchmark --committee 10 fixed-load --loads 200 --duration 180 -``` - -In a network of 10 validators, each with a corresponding load generator, each load generator submits a fixed load of 20 tx/s. Performance measurements are collected by regularly scraping the Prometheus metrics exposed by the load generators. The `sui-aws-orchestrator` binary provides additional commands to run a specific number of load generators on separate machines. - -## Step 6. Monitoring - -The orchestrator provides facilities to monitor metrics on clients and nodes. The orchestrator deploys a [Prometheus](https://prometheus.io) instance and a [Grafana](https://grafana.com) instance on a dedicated remote machine. Grafana is then available on the address printed on stdout (e.g., `http://3.83.97.12:3000`) with the default username and password both set to `admin`. You can either create a [new dashboard](https://grafana.com/docs/grafana/latest/getting-started/build-first-dashboard/) or [import](https://grafana.com/docs/grafana/latest/dashboards/manage-dashboards/#import-a-dashboard) the example dashboards located in the `./assets` folder. - -## Destroy a testbed -After you have found yourself that you don't need the deployed testbed anymore you can simply run - -``` -cargo run --bin sui-aws-orchestrator -- testbed destroy -``` - -that will terminate all the deployed EC2 instances. Keep in mind that AWS is not immediately deleting the terminated instances - this could take a few hours - so in case you want to immediately deploy a new testbed it would be advised -to use a different `testbed_id` in the `settings.json` to avoid any later conflicts (see the FAQ section for more information). - -## FAQ - -### I am getting an error "Failed to read settings file '"crates/sui-aws-orchestrator/assets/settings.json"': No such file or directory" -To run the tool a `settings.json` file with the deployment configuration should be under the directory `crates/sui-aws-orchestrator/assets`. Also, please make sure -that you run the orchestrator from the top level repo folder, ex `/sui $ cargo run --bin sui-aws-orchestrator` - -### I am getting an error "IncorrectInstanceState" with message "The instance 'i-xxxxxxx' is not in a state from which it can be started."" when I try to run a benchmark -When a testbed is deployed the EC2 instances are tagged with the `testbed_id` as dictated in the `settings.json` file. When trying to run a benchmark the tool will try to list -all the EC2 instances on the dictated by the configuration regions. To successfully run the benchmark all the listed instances should be in status -`Running`. If there is any instance in different state , ex `Terminated` , then the above error will arise. Please pay attention that if you `destroy` a deployment -and then immediately `deploy` a new one under the same `testbed_id`, then it is possible to have a mix of instances with status `Running` and `Terminated`, as AWS does not immediately -delete the `Terminated` instances. That can eventually cause the above false positive error as well. It is advised in this case to use a different `testbed_id` to ensure that -there is no overlap between instances. - -### I am getting an error "Not enough instances: missing X instances" when running a benchmark -In the common case to successfully run a benchmark we need to have enough instances available to run -* the required validators -* the grafana dashboard -* the benchmarking clients - -for example when running the command `cargo run --bin sui-aws-orchestrator -- benchmark --committee 4 fixed-load --loads 500 --duration 500`, we'll need the following amount of instances available: -* `4 instances` to run the validators (since we set `--committee 4`) -* `1 instance` to run the grafana dashboard (by default only 1 is needed) -* no additional instances to run the benchmarking clients, as those will be co-deployed on the validator nodes - -so in total we must have deployed a testbed of at least `5 instances`. If we attempt to run with fewer, then the above error will be thrown. diff --git a/crates/sui-aws-orchestrator/src/client/mod.rs b/crates/sui-aws-orchestrator/src/client/mod.rs deleted file mode 100644 index ab685ce4a88..00000000000 --- a/crates/sui-aws-orchestrator/src/client/mod.rs +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - fmt::Display, - net::{Ipv4Addr, SocketAddr}, -}; - -use serde::{Deserialize, Serialize}; - -use super::error::CloudProviderResult; - -pub mod aws; - -/// Represents a cloud provider instance. -#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash)] -pub struct Instance { - /// The unique identifier of the instance. - pub id: String, - /// The region where the instance runs. - pub region: String, - /// The public ip address of the instance (accessible from anywhere). - pub main_ip: Ipv4Addr, - /// The list of tags associated with the instance. - pub tags: Vec, - /// The specs of the instance. - pub specs: String, - /// The current status of the instance. - pub status: String, -} - -impl Instance { - /// Return whether the instance is active and running. - pub fn is_active(&self) -> bool { - self.status.to_lowercase() == "running" - } - - /// Return whether the instance is inactive and not ready for use. - pub fn is_inactive(&self) -> bool { - !self.is_active() - } - - /// Return whether the instance is terminated and in the process of being - /// deleted. - pub fn is_terminated(&self) -> bool { - self.status.to_lowercase() == "terminated" - } - - /// Return the ssh address to connect to the instance. - pub fn ssh_address(&self) -> SocketAddr { - format!("{}:22", self.main_ip).parse().unwrap() - } - - #[cfg(test)] - pub fn new_for_test(id: String) -> Self { - Self { - id, - region: Default::default(), - main_ip: Ipv4Addr::new(127, 0, 0, 1), - tags: Default::default(), - specs: Default::default(), - status: Default::default(), - } - } -} - -#[async_trait::async_trait] -pub trait ServerProviderClient: Display { - /// The username used to connect to the instances. - const USERNAME: &'static str; - - /// List all existing instances (regardless of their status). - async fn list_instances(&self) -> CloudProviderResult>; - - /// Start the specified instances. - async fn start_instances<'a, I>(&self, instances: I) -> CloudProviderResult<()> - where - I: Iterator + Send; - - /// Halt/Stop the specified instances. We may still be billed for stopped - /// instances. - async fn stop_instances<'a, I>(&self, instance_ids: I) -> CloudProviderResult<()> - where - I: Iterator + Send; - - /// Create an instance in a specific region. - async fn create_instance(&self, region: S) -> CloudProviderResult - where - S: Into + Serialize + Send; - - /// Delete a specific instance. Calling this function ensures we are no - /// longer billed for the specified instance. - async fn delete_instance(&self, instance: Instance) -> CloudProviderResult<()>; - - /// Authorize the provided ssh public key to access machines. - async fn register_ssh_public_key(&self, public_key: String) -> CloudProviderResult<()>; - - /// Return provider-specific commands to setup the instance. - async fn instance_setup_commands(&self) -> CloudProviderResult>; -} - -#[cfg(test)] -pub mod test_client { - use std::{fmt::Display, sync::Mutex}; - - use serde::Serialize; - - use super::{Instance, ServerProviderClient}; - use crate::{error::CloudProviderResult, settings::Settings}; - - pub struct TestClient { - settings: Settings, - instances: Mutex>, - } - - impl TestClient { - pub fn new(settings: Settings) -> Self { - Self { - settings, - instances: Mutex::new(Vec::new()), - } - } - } - - impl Display for TestClient { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "TestClient") - } - } - - #[async_trait::async_trait] - impl ServerProviderClient for TestClient { - const USERNAME: &'static str = "root"; - - async fn list_instances(&self) -> CloudProviderResult> { - let guard = self.instances.lock().unwrap(); - Ok(guard.clone()) - } - - async fn start_instances<'a, I>(&self, instances: I) -> CloudProviderResult<()> - where - I: Iterator + Send, - { - let instance_ids: Vec<_> = instances.map(|x| x.id.clone()).collect(); - let mut guard = self.instances.lock().unwrap(); - for instance in guard.iter_mut().filter(|x| instance_ids.contains(&x.id)) { - instance.status = "running".into(); - } - Ok(()) - } - - async fn stop_instances<'a, I>(&self, instances: I) -> CloudProviderResult<()> - where - I: Iterator + Send, - { - let instance_ids: Vec<_> = instances.map(|x| x.id.clone()).collect(); - let mut guard = self.instances.lock().unwrap(); - for instance in guard.iter_mut().filter(|x| instance_ids.contains(&x.id)) { - instance.status = "stopped".into(); - } - Ok(()) - } - - async fn create_instance(&self, region: S) -> CloudProviderResult - where - S: Into + Serialize + Send, - { - let mut guard = self.instances.lock().unwrap(); - let id = guard.len(); - let instance = Instance { - id: id.to_string(), - region: region.into(), - main_ip: format!("0.0.0.{id}").parse().unwrap(), - tags: Vec::new(), - specs: self.settings.specs.clone(), - status: "running".into(), - }; - guard.push(instance.clone()); - Ok(instance) - } - - async fn delete_instance(&self, instance: Instance) -> CloudProviderResult<()> { - let mut guard = self.instances.lock().unwrap(); - guard.retain(|x| x.id != instance.id); - Ok(()) - } - - async fn register_ssh_public_key(&self, _public_key: String) -> CloudProviderResult<()> { - Ok(()) - } - - async fn instance_setup_commands(&self) -> CloudProviderResult> { - Ok(Vec::new()) - } - } -} diff --git a/crates/sui-aws-orchestrator/src/display.rs b/crates/sui-aws-orchestrator/src/display.rs deleted file mode 100644 index 4d8508ab3eb..00000000000 --- a/crates/sui-aws-orchestrator/src/display.rs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{fmt::Display, io::stdout}; - -use crossterm::{ - cursor::{RestorePosition, SavePosition}, - style::{Print, PrintStyledContent, Stylize}, - terminal::{Clear, ClearType}, -}; -use prettytable::format::{self}; - -pub fn header(message: S) { - crossterm::execute!( - stdout(), - PrintStyledContent(format!("\n{message}\n").green().bold()), - ) - .unwrap(); -} - -pub fn error(message: S) { - crossterm::execute!( - stdout(), - PrintStyledContent(format!("\n{message}\n").red().bold()), - ) - .unwrap(); -} - -pub fn warn(message: S) { - crossterm::execute!( - stdout(), - PrintStyledContent(format!("\n{message}\n").bold()), - ) - .unwrap(); -} - -pub fn config(name: N, value: V) { - crossterm::execute!( - stdout(), - PrintStyledContent(format!("{name}: ").bold()), - Print(format!("{value}\n")) - ) - .unwrap(); -} - -pub fn action(message: S) { - crossterm::execute!(stdout(), Print(format!("{message} ... ")), SavePosition).unwrap(); -} - -pub fn status(status: S) { - crossterm::execute!( - stdout(), - RestorePosition, - SavePosition, - Clear(ClearType::UntilNewLine), - Print(format!("[{status}]")) - ) - .unwrap(); -} - -pub fn done() { - crossterm::execute!( - stdout(), - RestorePosition, - Clear(ClearType::UntilNewLine), - Print(format!("[{}]\n", "Ok".green())) - ) - .unwrap(); -} - -pub fn newline() { - crossterm::execute!(stdout(), Print("\n")).unwrap(); -} - -/// Default style for tables printed to stdout. -pub fn default_table_format() -> format::TableFormat { - format::FormatBuilder::new() - .separators( - &[ - format::LinePosition::Top, - format::LinePosition::Bottom, - format::LinePosition::Title, - ], - format::LineSeparator::new('-', '-', '-', '-'), - ) - .padding(1, 1) - .build() -} - -#[cfg(test)] -mod test { - use std::time::Duration; - - use tokio::time::sleep; - - use super::{action, config, done, error, header, newline, warn}; - use crate::display::status; - - #[tokio::test] - #[ignore = "only used to manually check if prints work correctly"] - async fn display() { - header("This is a header"); - config("This is a config", 2); - action("Running a long function"); - for i in 0..5 { - sleep(Duration::from_secs(1)).await; - if i == 2 { - warn("This is a warning!"); - } - status(format!("{}/5", i + 1)); - } - done(); - error("This is an error!"); - warn("This is a warning!"); - newline(); - } -} diff --git a/crates/sui-aws-orchestrator/src/error.rs b/crates/sui-aws-orchestrator/src/error.rs deleted file mode 100644 index 33785274183..00000000000 --- a/crates/sui-aws-orchestrator/src/error.rs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::net::SocketAddr; - -use reqwest::Url; - -#[macro_export(local_inner_macros)] -macro_rules! ensure { - ($cond:expr, $e:expr) => { - if !($cond) { - return Err($e); - } - }; -} - -pub type SettingsResult = Result; - -#[derive(thiserror::Error, Debug)] -pub enum SettingsError { - #[error("Failed to read settings file '{file:?}': {message}")] - InvalidSettings { file: String, message: String }, - - #[error("Failed to read token file '{file:?}': {message}")] - InvalidTokenFile { file: String, message: String }, - - #[error("Failed to read ssh public key file '{file:?}': {message}")] - InvalidSshPublicKeyFile { file: String, message: String }, - - #[error("Malformed repository url: {0:?}")] - MalformedRepositoryUrl(Url), -} - -pub type CloudProviderResult = Result; - -#[derive(thiserror::Error, Debug)] -pub enum CloudProviderError { - #[error("Failed to send server request: {0}")] - RequestError(String), - - #[error("Unexpected response: {0}")] - UnexpectedResponse(String), - - #[error("Received error status code ({0}): {1}")] - FailureResponseCode(String, String), - - #[error("SSH key \"{0}\" not found")] - SshKeyNotFound(String), -} - -pub type SshResult = Result; - -#[derive(thiserror::Error, Debug)] -pub enum SshError { - #[error("Failed to load private key for {address}: {error}")] - PrivateKeyError { - address: SocketAddr, - error: russh_keys::Error, - }, - - #[error("Failed to create ssh session with {address}: {error}")] - SessionError { - address: SocketAddr, - error: russh::Error, - }, - - #[error("Failed to connect to instance {address}: {error}")] - ConnectionError { - address: SocketAddr, - error: russh::Error, - }, - - #[error("Remote execution on {address} returned exit code ({code}): {message}")] - NonZeroExitCode { - address: SocketAddr, - code: u32, - message: String, - }, -} - -pub type MonitorResult = Result; - -#[derive(thiserror::Error, Debug)] -pub enum MonitorError { - #[error(transparent)] - SshError(#[from] SshError), - - #[error("Failed to start Grafana: {0}")] - GrafanaError(String), -} - -pub type TestbedResult = Result; - -#[derive(thiserror::Error, Debug)] -pub enum TestbedError { - #[error(transparent)] - SettingsError(#[from] SettingsError), - - #[error(transparent)] - CloudProviderError(#[from] CloudProviderError), - - #[error(transparent)] - SshError(#[from] SshError), - - #[error("Not enough instances: missing {0} instances")] - InsufficientCapacity(usize), - - #[error(transparent)] - MonitorError(#[from] MonitorError), -} diff --git a/crates/sui-aws-orchestrator/src/main.rs b/crates/sui-aws-orchestrator/src/main.rs deleted file mode 100644 index 7f39e582073..00000000000 --- a/crates/sui-aws-orchestrator/src/main.rs +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{str::FromStr, time::Duration}; - -use benchmark::{BenchmarkParametersGenerator, LoadType}; -use clap::Parser; -use client::{aws::AwsClient, ServerProviderClient}; -use eyre::{Context, Result}; -use faults::FaultsType; -use measurement::MeasurementsCollection; -use orchestrator::Orchestrator; -use protocol::narwhal::{NarwhalBenchmarkType, NarwhalProtocol}; -use settings::{CloudProvider, Settings}; -use ssh::SshConnectionManager; -use testbed::Testbed; - -pub mod benchmark; -pub mod client; -pub mod display; -pub mod error; -pub mod faults; -pub mod logs; -pub mod measurement; -mod monitor; -pub mod orchestrator; -pub mod protocol; -pub mod settings; -pub mod ssh; -pub mod testbed; - -/// NOTE: Link these types to the correct protocol. Either Sui or Narwhal. -// use protocol::sui::{SuiBenchmarkType, SuiProtocol}; -// type Protocol = SuiProtocol; -// type BenchmarkType = SuiBenchmarkType; -type Protocol = NarwhalProtocol; -type BenchmarkType = NarwhalBenchmarkType; - -#[derive(Parser)] -#[command(author, version, about = "Testbed orchestrator", long_about = None)] -pub struct Opts { - /// The path to the settings file. This file contains basic information to - /// deploy testbeds and run benchmarks such as the url of the git repo, - /// the commit to deploy, etc. - #[clap( - long, - value_name = "FILE", - default_value = "crates/sui-aws-orchestrator/assets/settings.json", - global = true - )] - settings_path: String, - - /// The type of operation to run. - #[clap(subcommand)] - operation: Operation, -} - -#[derive(Parser)] -pub enum Operation { - /// Get or modify the status of the testbed. - Testbed { - #[clap(subcommand)] - action: TestbedAction, - }, - - /// Run a benchmark on the specified testbed. - Benchmark { - /// Percentage of shared vs owned objects; 0 means only owned objects - /// and 100 means only shared objects. - #[clap(long, default_value = "0", global = true)] - benchmark_type: String, - - /// The committee size to deploy. - #[clap(long, value_name = "INT")] - committee: usize, - - /// Number of faulty nodes. - #[clap(long, value_name = "INT", default_value = "0", global = true)] - faults: usize, - - /// Whether the faulty nodes recover. - #[clap(long, action, default_value = "false", global = true)] - crash_recovery: bool, - - /// The interval to crash nodes in seconds. - #[clap(long, value_parser = parse_duration, default_value = "60", global = true)] - crash_interval: Duration, - - /// The minimum duration of the benchmark in seconds. - #[clap(long, value_parser = parse_duration, default_value = "600", global = true)] - duration: Duration, - - /// The interval between measurements collection in seconds. - #[clap(long, value_parser = parse_duration, default_value = "15", global = true)] - scrape_interval: Duration, - - /// Whether to skip testbed updates before running benchmarks. - #[clap(long, action, default_value = "false", global = true)] - skip_testbed_update: bool, - - /// Whether to skip testbed configuration before running benchmarks. - #[clap(long, action, default_value = "false", global = true)] - skip_testbed_configuration: bool, - - /// Whether to download and analyze the client and node log files. - #[clap(long, action, default_value = "false", global = true)] - log_processing: bool, - - /// The number of instances running exclusively load generators. If set - /// to zero the orchestrator collocates one load generator with - /// each node. - #[clap(long, value_name = "INT", default_value = "0", global = true)] - dedicated_clients: usize, - - /// Whether to forgo a grafana and prometheus instance and leave the - /// testbed unmonitored. - #[clap(long, action, default_value = "false", global = true)] - skip_monitoring: bool, - - /// The timeout duration for ssh commands (in seconds). - #[clap(long, action, value_parser = parse_duration, default_value = "30", global = true)] - timeout: Duration, - - /// The number of times the orchestrator should retry an ssh command. - #[clap(long, value_name = "INT", default_value = "5", global = true)] - retries: usize, - - /// The load to submit to the system. - #[clap(subcommand)] - load_type: Load, - }, - - /// Print a summary of the specified measurements collection. - Summarize { - /// The path to the settings file. - #[clap(long, value_name = "FILE")] - path: String, - }, -} - -#[derive(Parser)] -#[clap(rename_all = "kebab-case")] -pub enum TestbedAction { - /// Display the testbed status. - Status, - - /// Deploy the specified number of instances in all regions specified by in - /// the setting file. - Deploy { - /// Number of instances to deploy. - #[clap(long)] - instances: usize, - - /// The region where to deploy the instances. If this parameter is not - /// specified, the command deploys the specified number of - /// instances in all regions listed in the setting file. - #[clap(long)] - region: Option, - }, - - /// Start at most the specified number of instances per region on an - /// existing testbed. - Start { - /// Number of instances to deploy. - #[clap(long, default_value = "200")] - instances: usize, - }, - - /// Stop an existing testbed (without destroying the instances). - Stop, - - /// Destroy the testbed and terminate all instances. - Destroy, -} - -#[derive(Parser)] -pub enum Load { - /// The fixed loads (in tx/s) to submit to the nodes. - FixedLoad { - /// A list of fixed load (tx/s). - #[clap( - long, - value_name = "INT", - num_args(1..), - value_delimiter = ',' - )] - loads: Vec, - }, - - /// Search for the maximum load that the system can sustainably handle. - Search { - /// The initial load (in tx/s) to test and use a baseline. - #[clap(long, value_name = "INT", default_value = "250")] - starting_load: usize, - /// The maximum number of iterations before converging on a breaking - /// point. - #[clap(long, value_name = "INT", default_value = "5")] - max_iterations: usize, - }, -} - -fn parse_duration(arg: &str) -> Result { - let seconds = arg.parse()?; - Ok(Duration::from_secs(seconds)) -} - -#[tokio::main] -async fn main() -> Result<()> { - color_eyre::install()?; - let opts: Opts = Opts::parse(); - - // Load the settings files. - let settings = Settings::load(&opts.settings_path).wrap_err("Failed to load settings")?; - - match &settings.cloud_provider { - CloudProvider::Aws => { - // Create the client for the cloud provider. - let client = AwsClient::new(settings.clone()).await; - - // Execute the command. - run(settings, client, opts).await - } - } -} - -async fn run(settings: Settings, client: C, opts: Opts) -> Result<()> { - // Create a new testbed. - let mut testbed = Testbed::new(settings.clone(), client) - .await - .wrap_err("Failed to create testbed")?; - - match opts.operation { - Operation::Testbed { action } => match action { - // Display the current status of the testbed. - TestbedAction::Status => testbed.status(), - - // Deploy the specified number of instances on the testbed. - TestbedAction::Deploy { instances, region } => testbed - .deploy(instances, region) - .await - .wrap_err("Failed to deploy testbed")?, - - // Start the specified number of instances on an existing testbed. - TestbedAction::Start { instances } => testbed - .start(instances) - .await - .wrap_err("Failed to start testbed")?, - - // Stop an existing testbed. - TestbedAction::Stop => testbed.stop().await.wrap_err("Failed to stop testbed")?, - - // Destroy the testbed and terminal all instances. - TestbedAction::Destroy => testbed - .destroy() - .await - .wrap_err("Failed to destroy testbed")?, - }, - - // Run benchmarks. - Operation::Benchmark { - benchmark_type, - committee, - faults, - crash_recovery, - crash_interval, - duration, - scrape_interval, - skip_testbed_update, - skip_testbed_configuration, - log_processing, - dedicated_clients, - skip_monitoring, - timeout, - retries, - load_type, - } => { - // Create a new orchestrator to instruct the testbed. - let username = testbed.username(); - let private_key_file = settings.ssh_private_key_file.clone(); - let ssh_manager = SshConnectionManager::new(username.into(), private_key_file) - .with_timeout(timeout) - .with_retries(retries); - - let instances = testbed.instances(); - - let setup_commands = testbed - .setup_commands() - .await - .wrap_err("Failed to load testbed setup commands")?; - - let protocol_commands = Protocol::new(&settings); - let benchmark_type = BenchmarkType::from_str(&benchmark_type)?; - - let load = match load_type { - Load::FixedLoad { loads } => { - let loads = if loads.is_empty() { vec![200] } else { loads }; - LoadType::Fixed(loads) - } - Load::Search { - starting_load, - max_iterations, - } => LoadType::Search { - starting_load, - max_iterations, - }, - }; - - let fault_type = if !crash_recovery || faults == 0 { - FaultsType::Permanent { faults } - } else { - FaultsType::CrashRecovery { - max_faults: faults, - interval: crash_interval, - } - }; - - let generator = BenchmarkParametersGenerator::new(committee, load) - .with_benchmark_type(benchmark_type) - .with_custom_duration(duration) - .with_faults(fault_type); - - Orchestrator::new( - settings, - instances, - setup_commands, - protocol_commands, - ssh_manager, - ) - .with_scrape_interval(scrape_interval) - .with_crash_interval(crash_interval) - .skip_testbed_updates(skip_testbed_update) - .skip_testbed_configuration(skip_testbed_configuration) - .with_log_processing(log_processing) - .with_dedicated_clients(dedicated_clients) - .skip_monitoring(skip_monitoring) - .run_benchmarks(generator) - .await - .wrap_err("Failed to run benchmarks")?; - } - - // Print a summary of the specified measurements collection. - Operation::Summarize { path } => { - MeasurementsCollection::::load(path)?.display_summary() - } - } - Ok(()) -} diff --git a/crates/sui-aws-orchestrator/src/orchestrator.rs b/crates/sui-aws-orchestrator/src/orchestrator.rs deleted file mode 100644 index 988e9c604f9..00000000000 --- a/crates/sui-aws-orchestrator/src/orchestrator.rs +++ /dev/null @@ -1,648 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::{HashMap, VecDeque}, - fs::{self}, - marker::PhantomData, - path::PathBuf, - time::Duration, -}; - -use tokio::time::{self, Instant}; - -use crate::{ - benchmark::{BenchmarkParameters, BenchmarkParametersGenerator, BenchmarkType}, - client::Instance, - display, ensure, - error::{TestbedError, TestbedResult}, - faults::CrashRecoverySchedule, - logs::LogsAnalyzer, - measurement::{Measurement, MeasurementsCollection}, - monitor::Monitor, - protocol::{ProtocolCommands, ProtocolMetrics}, - settings::Settings, - ssh::{CommandContext, CommandStatus, SshConnectionManager}, -}; - -/// An orchestrator to run benchmarks on a testbed. -pub struct Orchestrator { - /// The testbed's settings. - settings: Settings, - /// The state of the testbed (reflecting accurately the state of the - /// machines). - instances: Vec, - /// The type of the benchmark parameters. - benchmark_type: PhantomData, - /// Provider-specific commands to install on the instance. - instance_setup_commands: Vec, - /// Protocol-specific commands generator to generate the protocol - /// configuration files, boot clients and nodes, etc. - protocol_commands: P, - /// The interval between measurements collection. - scrape_interval: Duration, - /// The interval to crash nodes. - crash_interval: Duration, - /// Handle ssh connections to instances. - ssh_manager: SshConnectionManager, - /// Whether to skip testbed updates before running benchmarks. - skip_testbed_update: bool, - /// Whether to skip testbed configuration before running benchmarks. - skip_testbed_configuration: bool, - /// Whether to downloading and analyze the client and node log files. - log_processing: bool, - /// Number of instances running only load generators (not nodes). If this - /// value is set to zero, the orchestrator runs a load generate - /// collocated with each node. - dedicated_clients: usize, - /// Whether to forgo a grafana and prometheus instance and leave the testbed - /// unmonitored. - skip_monitoring: bool, -} - -impl Orchestrator { - /// The default interval between measurements collection. - const DEFAULT_SCRAPE_INTERVAL: Duration = Duration::from_secs(15); - /// The default interval to crash nodes. - const DEFAULT_CRASH_INTERVAL: Duration = Duration::from_secs(60); - - /// Make a new orchestrator. - pub fn new( - settings: Settings, - instances: Vec, - instance_setup_commands: Vec, - protocol_commands: P, - ssh_manager: SshConnectionManager, - ) -> Self { - Self { - settings, - instances, - benchmark_type: PhantomData, - instance_setup_commands, - protocol_commands, - ssh_manager, - scrape_interval: Self::DEFAULT_SCRAPE_INTERVAL, - crash_interval: Self::DEFAULT_CRASH_INTERVAL, - skip_testbed_update: false, - skip_testbed_configuration: false, - log_processing: false, - dedicated_clients: 0, - skip_monitoring: false, - } - } - - /// Set interval between measurements collection. - pub fn with_scrape_interval(mut self, scrape_interval: Duration) -> Self { - self.scrape_interval = scrape_interval; - self - } - - /// Set interval with which to crash nodes. - pub fn with_crash_interval(mut self, crash_interval: Duration) -> Self { - self.crash_interval = crash_interval; - self - } - - /// Set whether to skip testbed updates before running benchmarks. - pub fn skip_testbed_updates(mut self, skip_testbed_update: bool) -> Self { - self.skip_testbed_update = skip_testbed_update; - self - } - - /// Whether to skip testbed configuration before running benchmarks. - pub fn skip_testbed_configuration(mut self, skip_testbed_configuration: bool) -> Self { - self.skip_testbed_configuration = skip_testbed_configuration; - self - } - - /// Set whether to download and analyze the client and node log files. - pub fn with_log_processing(mut self, log_processing: bool) -> Self { - self.log_processing = log_processing; - self - } - - /// Set the number of instances running exclusively load generators. - pub fn with_dedicated_clients(mut self, dedicated_clients: usize) -> Self { - self.dedicated_clients = dedicated_clients; - self - } - - /// Set whether to boot grafana on the local machine to monitor the nodes. - pub fn skip_monitoring(mut self, skip_monitoring: bool) -> Self { - self.skip_monitoring = skip_monitoring; - self - } - - /// Select on which instances of the testbed to run the benchmarks. This - /// function returns two vector of instances; the first contains the - /// instances on which to run the load generators and the second - /// contains the instances on which to run the nodes. - pub fn select_instances( - &self, - parameters: &BenchmarkParameters, - ) -> TestbedResult<(Vec, Vec, Option)> { - // Ensure there are enough active instances. - let available_instances: Vec<_> = self.instances.iter().filter(|x| x.is_active()).collect(); - let minimum_instances = if self.skip_monitoring { - parameters.nodes + self.dedicated_clients - } else { - parameters.nodes + self.dedicated_clients + 1 - }; - ensure!( - available_instances.len() >= minimum_instances, - TestbedError::InsufficientCapacity(minimum_instances - available_instances.len()) - ); - - // Sort the instances by region. - let mut instances_by_regions = HashMap::new(); - for instance in available_instances { - instances_by_regions - .entry(&instance.region) - .or_insert_with(VecDeque::new) - .push_back(instance); - } - - // Select the instance to host the monitoring stack. - let mut monitoring_instance = None; - if !self.skip_monitoring { - for region in &self.settings.regions { - if let Some(regional_instances) = instances_by_regions.get_mut(region) { - if let Some(instance) = regional_instances.pop_front() { - monitoring_instance = Some(instance.clone()); - } - break; - } - } - } - - // Select the instances to host exclusively load generators. - let mut client_instances = Vec::new(); - for region in self.settings.regions.iter().cycle() { - if client_instances.len() == self.dedicated_clients { - break; - } - if let Some(regional_instances) = instances_by_regions.get_mut(region) { - if let Some(instance) = regional_instances.pop_front() { - client_instances.push(instance.clone()); - } - } - } - - // Select the instances to host the nodes. - let mut nodes_instances = Vec::new(); - for region in self.settings.regions.iter().cycle() { - if nodes_instances.len() == parameters.nodes { - break; - } - if let Some(regional_instances) = instances_by_regions.get_mut(region) { - if let Some(instance) = regional_instances.pop_front() { - nodes_instances.push(instance.clone()); - } - } - } - - // Spawn a load generate collocated with each node if there are no instances - // dedicated to excursively run load generators. - if client_instances.is_empty() { - client_instances = nodes_instances.clone(); - } - - Ok((client_instances, nodes_instances, monitoring_instance)) - } -} - -impl + ProtocolMetrics, T: BenchmarkType> Orchestrator { - /// Boot one node per instance. - async fn boot_nodes( - &self, - instances: Vec, - parameters: &BenchmarkParameters, - ) -> TestbedResult<()> { - // Run one node per instance. - let targets = self - .protocol_commands - .node_command(instances.clone(), parameters); - - let repo = self.settings.repository_name(); - let context = CommandContext::new() - .run_background("node".into()) - .with_log_file("~/node.log".into()) - .with_execute_from_path(repo.into()); - self.ssh_manager - .execute_per_instance(targets, context) - .await?; - - // Wait until all nodes are reachable. - let commands = self - .protocol_commands - .nodes_metrics_command(instances.clone()); - self.ssh_manager.wait_for_success(commands).await; - - Ok(()) - } - - /// Install the codebase and its dependencies on the testbed. - pub async fn install(&self) -> TestbedResult<()> { - display::action("Installing dependencies on all machines"); - - let working_dir = self.settings.working_dir.display(); - let url = &self.settings.repository.url; - let basic_commands = [ - "sudo apt-get update", - "sudo apt-get -y upgrade", - "sudo apt-get -y autoremove", - // Disable "pending kernel upgrade" message. - "sudo apt-get -y remove needrestart", - // The following dependencies: - // * build-essential: prevent the error: [error: linker `cc` not found]. - // * libssl-dev - Required to compile the orchestrator, todo remove this dependency - "sudo apt-get -y install build-essential libssl-dev", - // Install rust (non-interactive). - "curl --proto \"=https\" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y", - "echo \"source $HOME/.cargo/env\" | tee -a ~/.bashrc", - "source $HOME/.cargo/env", - "rustup default stable", - // Create the working directory. - &format!("mkdir -p {working_dir}"), - // Clone the repo. - &format!("(git clone {url} || true)"), - ]; - - let cloud_provider_specific_dependencies: Vec<_> = self - .instance_setup_commands - .iter() - .map(|x| x.as_str()) - .collect(); - - let protocol_dependencies = self.protocol_commands.protocol_dependencies(); - - let command = [ - &basic_commands[..], - &Monitor::dependencies()[..], - &cloud_provider_specific_dependencies[..], - &protocol_dependencies[..], - ] - .concat() - .join(" && "); - - let active = self.instances.iter().filter(|x| x.is_active()).cloned(); - let context = CommandContext::default(); - self.ssh_manager.execute(active, command, context).await?; - - display::done(); - Ok(()) - } - - /// Reload prometheus on all instances. - pub async fn start_monitoring(&self, parameters: &BenchmarkParameters) -> TestbedResult<()> { - let (clients, nodes, instance) = self.select_instances(parameters)?; - if let Some(instance) = instance { - display::action("Configuring monitoring instance"); - - let monitor = Monitor::new(instance, clients, nodes, self.ssh_manager.clone()); - monitor.start_prometheus(&self.protocol_commands).await?; - monitor.start_grafana().await?; - - display::done(); - display::config("Grafana address", monitor.grafana_address()); - display::newline(); - } - - Ok(()) - } - - /// Update all instances to use the version of the codebase specified in the - /// setting file. - pub async fn update(&self) -> TestbedResult<()> { - display::action("Updating all instances"); - - // Update all active instances. This requires compiling the codebase in release - // (which may take a long time) so we run the command in the background - // to avoid keeping alive many ssh connections for too long. - let commit = &self.settings.repository.commit; - let command = [ - "git fetch -f", - &format!("(git checkout -b {commit} {commit} || git checkout -f {commit})"), - "(git pull -f || true)", - "source $HOME/.cargo/env", - "cargo build --release", - ] - .join(" && "); - - let active = self.instances.iter().filter(|x| x.is_active()).cloned(); - - let id = "update"; - let repo_name = self.settings.repository_name(); - let context = CommandContext::new() - .run_background(id.into()) - .with_execute_from_path(repo_name.into()); - self.ssh_manager - .execute(active.clone(), command, context) - .await?; - - // Wait until the command finished running. - self.ssh_manager - .wait_for_command(active, id, CommandStatus::Terminated) - .await?; - - display::done(); - Ok(()) - } - - /// Configure the instances with the appropriate configuration files. - pub async fn configure(&self, parameters: &BenchmarkParameters) -> TestbedResult<()> { - display::action("Configuring instances"); - - // Select instances to configure. - let (clients, nodes, _) = self.select_instances(parameters)?; - - // Generate the genesis configuration file and the keystore allowing access to - // gas objects. - let command = self.protocol_commands.genesis_command(nodes.iter()); - let repo_name = self.settings.repository_name(); - let context = CommandContext::new().with_execute_from_path(repo_name.into()); - let all = clients.into_iter().chain(nodes); - self.ssh_manager.execute(all, command, context).await?; - - display::done(); - Ok(()) - } - - /// Cleanup all instances and optionally delete their log files. - pub async fn cleanup(&self, cleanup: bool) -> TestbedResult<()> { - display::action("Cleaning up testbed"); - - // Kill all tmux servers and delete the nodes dbs. Optionally clear logs. - let mut command = vec!["(tmux kill-server || true)".into()]; - for path in self.protocol_commands.db_directories() { - command.push(format!("(rm -rf {} || true)", path.display())); - } - if cleanup { - command.push("(rm -rf ~/*log* || true)".into()); - } - let command = command.join(" ; "); - - // Execute the deletion on all machines. - let active = self.instances.iter().filter(|x| x.is_active()).cloned(); - let context = CommandContext::default(); - self.ssh_manager.execute(active, command, context).await?; - - display::done(); - Ok(()) - } - - /// Deploy the nodes. - pub async fn run_nodes(&self, parameters: &BenchmarkParameters) -> TestbedResult<()> { - display::action("Deploying validators"); - - // Select the instances to run. - let (_, nodes, _) = self.select_instances(parameters)?; - - // Boot one node per instance. - self.boot_nodes(nodes, parameters).await?; - - display::done(); - Ok(()) - } - - /// Deploy the load generators. - pub async fn run_clients(&self, parameters: &BenchmarkParameters) -> TestbedResult<()> { - display::action("Setting up load generators"); - - // Select the instances to run. - let (clients, _, _) = self.select_instances(parameters)?; - - // Deploy the load generators. - let targets = self - .protocol_commands - .client_command(clients.clone(), parameters); - - let repo = self.settings.repository_name(); - let context = CommandContext::new() - .run_background("client".into()) - .with_log_file("~/client.log".into()) - .with_execute_from_path(repo.into()); - self.ssh_manager - .execute_per_instance(targets, context) - .await?; - - // Wait until all load generators are reachable. - let commands = self.protocol_commands.clients_metrics_command(clients); - self.ssh_manager.wait_for_success(commands).await; - - display::done(); - Ok(()) - } - - /// Collect metrics from the load generators. - pub async fn run( - &self, - parameters: &BenchmarkParameters, - ) -> TestbedResult> { - display::action(format!( - "Scraping metrics (at least {}s)", - parameters.duration.as_secs() - )); - - // Select the instances to run. - let (clients, nodes, _) = self.select_instances(parameters)?; - - // Regularly scrape the client - let mut metrics_commands = self.protocol_commands.clients_metrics_command(clients); - - // TODO: Remove this when narwhal client latency metrics are available. - // We will be getting latency metrics directly from narwhal nodes instead from - // the nw client - metrics_commands.append(&mut self.protocol_commands.nodes_metrics_command(nodes.clone())); - - let mut aggregator = MeasurementsCollection::new(&self.settings, parameters.clone()); - let mut metrics_interval = time::interval(self.scrape_interval); - metrics_interval.tick().await; // The first tick returns immediately. - - let faults_type = parameters.faults.clone(); - let mut faults_schedule = CrashRecoverySchedule::new(faults_type, nodes.clone()); - let mut faults_interval = time::interval(self.crash_interval); - faults_interval.tick().await; // The first tick returns immediately. - - let start = Instant::now(); - loop { - tokio::select! { - // Scrape metrics. - now = metrics_interval.tick() => { - let elapsed = now.duration_since(start).as_secs_f64().ceil() as u64; - display::status(format!("{elapsed}s")); - - let stdio = self - .ssh_manager - .execute_per_instance(metrics_commands.clone(), CommandContext::default()) - .await?; - for (i, (stdout, _stderr)) in stdio.iter().enumerate() { - let measurement = Measurement::from_prometheus::

    (stdout); - aggregator.add(i, measurement); - } - - if elapsed > parameters.duration .as_secs() { - break; - } - }, - - // Kill and recover nodes according to the input schedule. - _ = faults_interval.tick() => { - let action = faults_schedule.update(); - if !action.kill.is_empty() { - self.ssh_manager.kill(action.kill.clone(), "node").await?; - } - if !action.boot.is_empty() { - self.boot_nodes(action.boot.clone(), parameters).await?; - } - if !action.kill.is_empty() || !action.boot.is_empty() { - display::newline(); - display::config("Testbed update", action); - } - } - } - } - - let results_directory = &self.settings.results_dir; - let commit = &self.settings.repository.commit; - let path: PathBuf = [results_directory, &format!("results-{commit}").into()] - .iter() - .collect(); - fs::create_dir_all(&path).expect("Failed to create log directory"); - aggregator.save(path); - - display::done(); - Ok(aggregator) - } - - /// Download the log files from the nodes and clients. - pub async fn download_logs( - &self, - parameters: &BenchmarkParameters, - ) -> TestbedResult { - // Select the instances to run. - let (clients, nodes, _) = self.select_instances(parameters)?; - - // Create a log sub-directory for this run. - let commit = &self.settings.repository.commit; - let path: PathBuf = [ - &self.settings.logs_dir, - &format!("logs-{commit}").into(), - &format!("logs-{parameters:?}").into(), - ] - .iter() - .collect(); - fs::create_dir_all(&path).expect("Failed to create log directory"); - - // NOTE: Our ssh library does not seem to be able to transfers files in parallel - // reliably. - let mut log_parsers = Vec::new(); - - // Download the clients log files. - display::action("Downloading clients logs"); - for (i, instance) in clients.iter().enumerate() { - display::status(format!("{}/{}", i + 1, clients.len())); - - let connection = self.ssh_manager.connect(instance.ssh_address()).await?; - let client_log_content = connection.download("client.log").await?; - - let client_log_file = [path.clone(), format!("client-{i}.log").into()] - .iter() - .collect::(); - fs::write(&client_log_file, client_log_content.as_bytes()) - .expect("Cannot write log file"); - - let mut log_parser = LogsAnalyzer::default(); - log_parser.set_client_errors(&client_log_content); - log_parsers.push(log_parser) - } - display::done(); - - display::action("Downloading nodes logs"); - for (i, instance) in nodes.iter().enumerate() { - display::status(format!("{}/{}", i + 1, nodes.len())); - - let connection = self.ssh_manager.connect(instance.ssh_address()).await?; - let node_log_content = connection.download("node.log").await?; - - let node_log_file = [path.clone(), format!("node-{i}.log").into()] - .iter() - .collect::(); - fs::write(&node_log_file, node_log_content.as_bytes()).expect("Cannot write log file"); - - let mut log_parser = LogsAnalyzer::default(); - log_parser.set_node_errors(&node_log_content); - log_parsers.push(log_parser) - } - display::done(); - - Ok(LogsAnalyzer::aggregate(log_parsers)) - } - - /// Run all the benchmarks specified by the benchmark generator. - pub async fn run_benchmarks( - &mut self, - mut generator: BenchmarkParametersGenerator, - ) -> TestbedResult<()> { - display::header("Preparing testbed"); - display::config("Commit", format!("'{}'", &self.settings.repository.commit)); - display::newline(); - - // Cleanup the testbed (in case the previous run was not completed). - self.cleanup(true).await?; - - // Update the software on all instances. - if !self.skip_testbed_update { - self.install().await?; - self.update().await?; - } - - // Run all benchmarks. - let mut i = 1; - let mut latest_committee_size = 0; - while let Some(parameters) = generator.next() { - display::header(format!("Starting benchmark {i}")); - display::config("Benchmark type", ¶meters.benchmark_type); - display::config("Parameters", ¶meters); - display::newline(); - - // Cleanup the testbed (in case the previous run was not completed). - self.cleanup(true).await?; - // Start the instance monitoring tools. - self.start_monitoring(¶meters).await?; - - // Configure all instances (if needed). - if !self.skip_testbed_configuration && latest_committee_size != parameters.nodes { - self.configure(¶meters).await?; - latest_committee_size = parameters.nodes; - } - - // Deploy the validators. - self.run_nodes(¶meters).await?; - - // Deploy the load generators. - self.run_clients(¶meters).await?; - - // Wait for the benchmark to terminate. Then save the results and print a - // summary. - let aggregator = self.run(¶meters).await?; - aggregator.display_summary(); - generator.register_result(aggregator); - // drop(monitor); - - // Kill the nodes and clients (without deleting the log files). - self.cleanup(false).await?; - - // Download the log files. - if self.log_processing { - let error_counter = self.download_logs(¶meters).await?; - error_counter.print_summary(); - } - - i += 1; - } - - display::header("Benchmark completed"); - Ok(()) - } -} diff --git a/crates/sui-aws-orchestrator/src/protocol/mod.rs b/crates/sui-aws-orchestrator/src/protocol/mod.rs deleted file mode 100644 index d72c7d4df45..00000000000 --- a/crates/sui-aws-orchestrator/src/protocol/mod.rs +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::path::PathBuf; - -use crate::{ - benchmark::{BenchmarkParameters, BenchmarkType}, - client::Instance, -}; - -pub mod narwhal; -pub mod sui; - -/// The minimum interface that the protocol should implement to allow benchmarks -/// from the orchestrator. -pub trait ProtocolCommands { - /// The list of dependencies to install (e.g., through apt-get). - fn protocol_dependencies(&self) -> Vec<&'static str>; - - /// The directories of all databases (that should be erased before each - /// run). - fn db_directories(&self) -> Vec; - - /// The command to generate the genesis and all configuration files. This - /// command is run on each remote machine. - fn genesis_command<'a, I>(&self, instances: I) -> String - where - I: Iterator; - - /// The command to run a node. The function returns a vector of commands - /// along with the associated instance on which to run the command. - fn node_command( - &self, - instances: I, - parameters: &BenchmarkParameters, - ) -> Vec<(Instance, String)> - where - I: IntoIterator; - - fn monitor_command(&self, instances: I) -> Vec<(Instance, String)> - where - I: IntoIterator; - - /// The command to run a client. The function returns a vector of commands - /// along with the associated instance on which to run the command. - fn client_command( - &self, - instances: I, - parameters: &BenchmarkParameters, - ) -> Vec<(Instance, String)> - where - I: IntoIterator; -} - -/// The names of the minimum metrics exposed by the load generators that are -/// required to compute performance. -pub trait ProtocolMetrics { - /// The name of the metric reporting the total duration of the benchmark (in - /// seconds). - const BENCHMARK_DURATION: &'static str; - /// The name of the metric reporting the total number of finalized - /// transactions - const TOTAL_TRANSACTIONS: &'static str; - /// The name of the metric reporting the latency buckets. - const LATENCY_BUCKETS: &'static str; - /// The name of the metric reporting the sum of the end-to-end latency of - /// all finalized transactions. - const LATENCY_SUM: &'static str; - /// The name of the metric reporting the square of the sum of the end-to-end - /// latency of all finalized transactions. - const LATENCY_SQUARED_SUM: &'static str; - - /// The network path where the nodes expose prometheus metrics. - fn nodes_metrics_path(&self, instances: I) -> Vec<(Instance, String)> - where - I: IntoIterator; - /// The command to retrieve the metrics from the nodes. - fn nodes_metrics_command(&self, instances: I) -> Vec<(Instance, String)> - where - I: IntoIterator, - { - self.nodes_metrics_path(instances) - .into_iter() - .map(|(instance, path)| (instance, format!("curl {path}"))) - .collect() - } - - /// The network path where the clients expose prometheus metrics. - fn clients_metrics_path(&self, instances: I) -> Vec<(Instance, String)> - where - I: IntoIterator; - /// The command to retrieve the metrics from the clients. - fn clients_metrics_command(&self, instances: I) -> Vec<(Instance, String)> - where - I: IntoIterator, - { - self.clients_metrics_path(instances) - .into_iter() - .map(|(instance, path)| (instance, format!("curl {path}"))) - .collect() - } -} - -#[cfg(test)] -pub mod test_protocol_metrics { - use super::ProtocolMetrics; - use crate::client::Instance; - - pub struct TestProtocolMetrics; - - impl ProtocolMetrics for TestProtocolMetrics { - const BENCHMARK_DURATION: &'static str = "benchmark_duration"; - const TOTAL_TRANSACTIONS: &'static str = "latency_s_count"; - const LATENCY_BUCKETS: &'static str = "latency_s"; - const LATENCY_SUM: &'static str = "latency_s_sum"; - const LATENCY_SQUARED_SUM: &'static str = "latency_squared_s"; - - fn nodes_metrics_path(&self, instances: I) -> Vec<(Instance, String)> - where - I: IntoIterator, - { - instances - .into_iter() - .enumerate() - .map(|(i, instance)| (instance, format!("localhost:{}/metrics", 8000 + i as u16))) - .collect() - } - - fn clients_metrics_path(&self, instances: I) -> Vec<(Instance, String)> - where - I: IntoIterator, - { - instances - .into_iter() - .enumerate() - .map(|(i, instance)| (instance, format!("localhost:{}/metrics", 9000 + i as u16))) - .collect() - } - } -} diff --git a/crates/sui-aws-orchestrator/src/protocol/sui.rs b/crates/sui-aws-orchestrator/src/protocol/sui.rs deleted file mode 100644 index ea28120e41e..00000000000 --- a/crates/sui-aws-orchestrator/src/protocol/sui.rs +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - fmt::{Debug, Display}, - path::PathBuf, - str::FromStr, -}; - -use serde::{Deserialize, Serialize}; -use sui_swarm_config::genesis_config::GenesisConfig; -use sui_types::{base_types::SuiAddress, multiaddr::Multiaddr}; - -use super::{ProtocolCommands, ProtocolMetrics}; -use crate::{ - benchmark::{BenchmarkParameters, BenchmarkType}, - client::Instance, - settings::Settings, -}; - -#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct SuiBenchmarkType { - /// Percentage of shared vs owned objects; 0 means only owned objects and - /// 100 means only shared objects. - shared_objects_ratio: u16, -} - -impl Debug for SuiBenchmarkType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.shared_objects_ratio) - } -} - -impl Display for SuiBenchmarkType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}% shared objects", self.shared_objects_ratio) - } -} - -impl FromStr for SuiBenchmarkType { - type Err = std::num::ParseIntError; - - fn from_str(s: &str) -> Result { - Ok(Self { - shared_objects_ratio: s.parse::()?.min(100), - }) - } -} - -impl BenchmarkType for SuiBenchmarkType {} - -/// All configurations information to run a Sui client or validator. -pub struct SuiProtocol { - working_dir: PathBuf, -} - -impl ProtocolCommands for SuiProtocol { - fn protocol_dependencies(&self) -> Vec<&'static str> { - vec![ - // Install typical sui dependencies. - "sudo apt-get -y install curl git-all clang cmake gcc libssl-dev pkg-config libclang-dev", - // This dependency is missing from the Sui docs. - "sudo apt-get -y install libpq-dev", - ] - } - - fn db_directories(&self) -> Vec { - let authorities_db = [&self.working_dir, &sui_config::AUTHORITIES_DB_NAME.into()] - .iter() - .collect(); - let consensus_db = [&self.working_dir, &sui_config::CONSENSUS_DB_NAME.into()] - .iter() - .collect(); - vec![authorities_db, consensus_db] - } - - fn genesis_command<'a, I>(&self, instances: I) -> String - where - I: Iterator, - { - let working_dir = self.working_dir.display(); - let ips = instances - .map(|x| x.main_ip.to_string()) - .collect::>() - .join(" "); - let genesis = [ - "cargo run --release --bin sui --", - "genesis", - &format!("-f --working-dir {working_dir} --benchmark-ips {ips}"), - ] - .join(" "); - - [ - &format!("mkdir -p {working_dir}"), - "source $HOME/.cargo/env", - &genesis, - ] - .join(" && ") - } - - fn monitor_command(&self, _instances: I) -> Vec<(Instance, String)> - where - I: IntoIterator, - { - // instances - // .into_iter() - // .map(|i| { - // ( - // i, - // "tail -f --pid=$(pidof sui) -f /dev/null; tail -100 - // node.log".to_string(), ) - // }) - // .collect() - vec![] - } - - fn node_command( - &self, - instances: I, - _parameters: &BenchmarkParameters, - ) -> Vec<(Instance, String)> - where - I: IntoIterator, - { - let working_dir = self.working_dir.clone(); - let network_addresses = Self::resolve_network_addresses(instances); - - network_addresses - .into_iter() - .enumerate() - .map(|(i, (instance, network_address))| { - let validator_config = - sui_config::validator_config_file(network_address.clone(), i); - let config_path: PathBuf = working_dir.join(validator_config); - - let run = [ - "cargo run --release --bin sui-node --", - &format!( - "--config-path {} --listen-address {}", - config_path.display(), - network_address.with_zero_ip() - ), - ] - .join(" "); - let command = ["source $HOME/.cargo/env", &run].join(" && "); - - (instance, command) - }) - .collect() - } - - fn client_command( - &self, - instances: I, - parameters: &BenchmarkParameters, - ) -> Vec<(Instance, String)> - where - I: IntoIterator, - { - let genesis_path: PathBuf = [&self.working_dir, &sui_config::SUI_GENESIS_FILENAME.into()] - .iter() - .collect(); - let keystore_path: PathBuf = [ - &self.working_dir, - &sui_config::SUI_BENCHMARK_GENESIS_GAS_KEYSTORE_FILENAME.into(), - ] - .iter() - .collect(); - - let committee_size = parameters.nodes; - let clients: Vec<_> = instances.into_iter().collect(); - let load_share = parameters.load / clients.len(); - let shared_counter = parameters.benchmark_type.shared_objects_ratio; - let transfer_objects = 100 - shared_counter; - let metrics_port = Self::CLIENT_METRICS_PORT; - let gas_keys = GenesisConfig::benchmark_gas_keys(committee_size); - - clients - .into_iter() - .enumerate() - .map(|(i, instance)| { - let genesis = genesis_path.display(); - let keystore = keystore_path.display(); - let gas_key = &gas_keys[i % committee_size]; - let gas_address = SuiAddress::from(&gas_key.public()); - - let run = [ - "cargo run --release --bin stress --", - "--num-client-threads 24 --num-server-threads 1", - "--local false --num-transfer-accounts 2", - &format!("--genesis-blob-path {genesis} --keystore-path {keystore}",), - &format!("--primary-gas-owner-id {gas_address}"), - "bench", - &format!("--in-flight-ratio 30 --num-workers 24 --target-qps {load_share}"), - &format!( - "--shared-counter {shared_counter} --transfer-object {transfer_objects}" - ), - "--shared-counter-hotness-factor 50", - &format!("--client-metric-host 0.0.0.0 --client-metric-port {metrics_port}"), - ] - .join(" "); - let command = ["source $HOME/.cargo/env", &run].join(" && "); - - (instance, command) - }) - .collect() - } -} - -impl SuiProtocol { - const CLIENT_METRICS_PORT: u16 = GenesisConfig::BENCHMARKS_PORT_OFFSET + 2000; - - /// Make a new instance of the Sui protocol commands generator. - pub fn new(settings: &Settings) -> Self { - Self { - working_dir: [&settings.working_dir, &sui_config::SUI_CONFIG_DIR.into()] - .iter() - .collect(), - } - } - - /// Creates the network addresses in multi address format for the instances. - /// It returns the Instance and the corresponding address. - pub fn resolve_network_addresses( - instances: impl IntoIterator, - ) -> Vec<(Instance, Multiaddr)> { - let instances: Vec = instances.into_iter().collect(); - let ips: Vec<_> = instances.iter().map(|x| x.main_ip.to_string()).collect(); - let genesis_config = GenesisConfig::new_for_benchmarks(&ips); - let mut addresses = Vec::new(); - if let Some(validator_configs) = genesis_config.validator_config_info.as_ref() { - for (i, validator_info) in validator_configs.iter().enumerate() { - let address = &validator_info.network_address; - addresses.push((instances[i].clone(), address.clone())); - } - } - addresses - } -} - -impl ProtocolMetrics for SuiProtocol { - const BENCHMARK_DURATION: &'static str = "benchmark_duration"; - const TOTAL_TRANSACTIONS: &'static str = "latency_s_count"; - const LATENCY_BUCKETS: &'static str = "latency_s"; - const LATENCY_SUM: &'static str = "latency_s_sum"; - const LATENCY_SQUARED_SUM: &'static str = "latency_squared_s"; - - fn nodes_metrics_path(&self, instances: I) -> Vec<(Instance, String)> - where - I: IntoIterator, - { - let (ips, instances): (Vec<_>, Vec<_>) = instances - .into_iter() - .map(|x| (x.main_ip.to_string(), x)) - .unzip(); - - GenesisConfig::new_for_benchmarks(&ips) - .validator_config_info - .expect("No validator in genesis") - .iter() - .zip(instances) - .map(|(config, instance)| { - let path = format!( - "{}:{}{}", - instance.main_ip, - config.metrics_address.port(), - mysten_metrics::METRICS_ROUTE - ); - (instance, path) - }) - .collect() - } - - fn clients_metrics_path(&self, instances: I) -> Vec<(Instance, String)> - where - I: IntoIterator, - { - instances - .into_iter() - .map(|instance| { - let path = format!( - "{}:{}{}", - instance.main_ip, - Self::CLIENT_METRICS_PORT, - mysten_metrics::METRICS_ROUTE - ); - (instance, path) - }) - .collect() - } -} diff --git a/crates/sui-axelar-cgp/README.md b/crates/sui-axelar-cgp/README.md deleted file mode 100644 index ddc7837a222..00000000000 --- a/crates/sui-axelar-cgp/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Axelar cross-chain gateway protocol Sui implementation - - -## Design -TODO \ No newline at end of file diff --git a/crates/sui-axelar-cgp/move/Move.toml b/crates/sui-axelar-cgp/move/Move.toml deleted file mode 100644 index e56043bc1f1..00000000000 --- a/crates/sui-axelar-cgp/move/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "sui-axelar-cgp" -version = "0.0.1" - -[dependencies] -Sui = { local= "../../sui-framework/packages/sui-framework" } - -[addresses] -axelar = "0x0" -sui = "0x2" diff --git a/crates/sui-axelar-cgp/move/presets/package.json b/crates/sui-axelar-cgp/move/presets/package.json deleted file mode 100644 index 289195f7506..00000000000 --- a/crates/sui-axelar-cgp/move/presets/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "axelar-presets", - "version": "1.0.0", - "main": "index.js", - "author": "Damir Shamanaev ", - "license": "MIT", - "dependencies": { - "@mysten/bcs": "^0.5.0", - "ethers": "^5.7.1", - "secp256k1": "^4.0.3" - } -} diff --git a/crates/sui-benchmark/Cargo.toml b/crates/sui-benchmark/Cargo.toml deleted file mode 100644 index 3a4bdb69139..00000000000 --- a/crates/sui-benchmark/Cargo.toml +++ /dev/null @@ -1,59 +0,0 @@ -[package] -name = "sui-benchmark" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -async-trait.workspace = true -anyhow = { workspace = true, features = ["backtrace"] } -futures.workspace = true -serde.workspace = true -serde_json.workspace = true -itertools.workspace = true -tokio = { workspace = true, features = ["full"] } -strum.workspace = true -strum_macros.workspace = true -tracing.workspace = true -clap.workspace = true -prometheus.workspace = true -rand.workspace = true -indicatif.workspace = true -duration-str.workspace = true -hdrhistogram.workspace = true -comfy-table.workspace = true -bcs.workspace = true -tokio-util.workspace = true -sui-core.workspace = true -sui-config.workspace = true -sui-network.workspace = true -sui-storage.workspace = true -sui-types.workspace = true -sui-sdk.workspace = true -sui-keys.workspace = true -sui-json-rpc-types.workspace = true -sui-protocol-config.workspace = true -sui-test-transaction-builder.workspace = true -sui-swarm-config.workspace = true -telemetry-subscribers.workspace = true -roaring.workspace = true -regex.workspace = true -fastcrypto-zkp.workspace = true - -move-core-types.workspace = true -mysten-metrics.workspace = true -narwhal-node.workspace = true -test-cluster.workspace = true -sysinfo.workspace = true - -[target.'cfg(msim)'.dependencies] -sui-framework.workspace = true -sui-framework-snapshot.workspace = true -sui-macros.workspace = true -sui-simulator.workspace = true -typed-store.workspace = true - -[features] -benchmark = ["narwhal-node/benchmark"] diff --git a/crates/sui-benchmark/src/drivers/mod.rs b/crates/sui-benchmark/src/drivers/mod.rs deleted file mode 100644 index d8083b5b9cd..00000000000 --- a/crates/sui-benchmark/src/drivers/mod.rs +++ /dev/null @@ -1,419 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{fmt::Formatter, str::FromStr, time::Duration}; - -use duration_str::parse; - -pub mod bench_driver; -pub mod driver; -use comfy_table::{Cell, Color, ContentArrangement, Row, Table}; -use hdrhistogram::{serialization::Serializer, Histogram}; - -#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, Eq, PartialEq)] -pub enum Interval { - Count(u64), - Time(tokio::time::Duration), -} - -impl Interval { - pub fn is_unbounded(&self) -> bool { - matches!(self, Interval::Time(tokio::time::Duration::MAX)) - } -} - -impl FromStr for Interval { - type Err = String; - - fn from_str(s: &str) -> Result { - if let Ok(i) = s.parse() { - Ok(Interval::Count(i)) - } else if let Ok(d) = parse(s) { - Ok(Interval::Time(d)) - } else if "unbounded" == s { - Ok(Interval::Time(Duration::MAX)) - } else { - Err("Required integer number of cycles or time duration".to_string()) - } - } -} - -impl std::fmt::Display for Interval { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Interval::Count(count) => f.write_str(format!("{}", count).as_str()), - Interval::Time(d) => { - if *d == Duration::MAX { - f.write_str("unbounded") - } else { - f.write_str(format!("{}sec", d.as_secs()).as_str()) - } - } - } - } -} - -// wrapper which implements serde -#[allow(dead_code)] -#[derive(Debug)] -pub struct HistogramWrapper { - histogram: Histogram, -} - -impl Default for HistogramWrapper { - fn default() -> Self { - Self { - histogram: Histogram::new(0).unwrap(), - } - } -} - -impl serde::Serialize for HistogramWrapper { - fn serialize(&self, serializer: S) -> Result { - let mut vec = Vec::new(); - hdrhistogram::serialization::V2Serializer::new() - .serialize(&self.histogram, &mut vec) - .map_err(|e| serde::ser::Error::custom(e.to_string()))?; - serializer.serialize_bytes(&vec) - } -} - -impl<'de> serde::Deserialize<'de> for HistogramWrapper { - fn deserialize>(deserializer: D) -> Result { - let vec: Vec = serde::Deserialize::deserialize(deserializer)?; - let histogram: Histogram = hdrhistogram::serialization::Deserializer::new() - .deserialize(&mut &vec[..]) - .map_err(|e| serde::de::Error::custom(e.to_string()))?; - Ok(HistogramWrapper { histogram }) - } -} - -// Stores the final stress statisicts of the test run. -#[derive(serde::Serialize, serde::Deserialize)] -pub struct StressStats { - pub cpu_usage: HistogramWrapper, -} - -impl StressStats { - pub fn update(&mut self, sample_stat: &StressStats) { - self.cpu_usage - .histogram - .add(&sample_stat.cpu_usage.histogram) - .unwrap(); - } - - pub fn to_table(&self) -> Table { - let mut table = Table::new(); - table - .set_content_arrangement(ContentArrangement::Dynamic) - .set_width(200) - .set_header(vec!["metric", "p50", "p99"]); - - let mut row = Row::new(); - row.add_cell(Cell::new("cpu usage")); - row.add_cell(Cell::new(self.cpu_usage.histogram.value_at_quantile(0.5))); - row.add_cell(Cell::new(self.cpu_usage.histogram.value_at_quantile(0.99))); - table.add_row(row); - table - } -} - -/// Stores the final statistics of the test run. -#[derive(serde::Serialize, serde::Deserialize, Debug, Default)] -pub struct BenchmarkStats { - pub duration: Duration, - /// Number of transactions that ended in an error - pub num_error_txes: u64, - /// Number of transactions that were executed successfully - pub num_success_txes: u64, - /// Total number of commands in transactions that executed successfully - pub num_success_cmds: u64, - /// Total gas used - pub total_gas_used: u64, - pub latency_ms: HistogramWrapper, -} - -impl BenchmarkStats { - pub fn update(&mut self, duration: Duration, sample_stat: &BenchmarkStats) { - self.duration = duration; - self.num_error_txes += sample_stat.num_error_txes; - self.num_success_txes += sample_stat.num_success_txes; - self.num_success_cmds += sample_stat.num_success_cmds; - self.total_gas_used += sample_stat.total_gas_used; - self.latency_ms - .histogram - .add(&sample_stat.latency_ms.histogram) - .unwrap(); - } - pub fn to_table(&self) -> Table { - let mut table = Table::new(); - table - .set_content_arrangement(ContentArrangement::Dynamic) - .set_width(200) - .set_header(vec![ - "duration(s)", - "tps", - "cps", - "error%", - "latency (min)", - "latency (p50)", - "latency (p99)", - "gas used (MIST total)", - "gas used/hr (MIST approx.)", - ]); - let mut row = Row::new(); - row.add_cell(Cell::new(self.duration.as_secs())); - row.add_cell(Cell::new(self.num_success_txes / self.duration.as_secs())); - row.add_cell(Cell::new(self.num_success_cmds / self.duration.as_secs())); - row.add_cell(Cell::new( - (100 * self.num_error_txes) as f32 - / (self.num_error_txes + self.num_success_txes) as f32, - )); - row.add_cell(Cell::new(self.latency_ms.histogram.min())); - row.add_cell(Cell::new(self.latency_ms.histogram.value_at_quantile(0.5))); - row.add_cell(Cell::new(self.latency_ms.histogram.value_at_quantile(0.99))); - row.add_cell(Cell::new(format_num_with_separators( - self.total_gas_used, - 3, - ",", - ))); - row.add_cell(Cell::new(format_num_with_separators( - self.total_gas_used * 60 * 60 / self.duration.as_secs(), - 3, - ",", - ))); - table.add_row(row); - table - } -} - -/// A comparison between an old and a new benchmark. -/// All differences are reported in terms of measuring improvements -/// (negative) or regressions (positive). That is, if an old benchmark -/// is slower than a new benchmark, then the difference is negative. -/// Conversely, if an old benchmark is faster than a new benchmark, -/// then the difference is positive. -#[derive(Clone, Debug)] -pub struct Comparison { - pub name: String, - pub old_value: String, - pub new_value: String, - pub diff: i64, - pub diff_ratio: f64, - pub speedup: f64, -} - -pub struct BenchmarkCmp<'a> { - pub new: &'a BenchmarkStats, - pub old: &'a BenchmarkStats, -} - -impl BenchmarkCmp<'_> { - pub fn to_table(&self) -> Table { - let mut table = Table::new(); - table.set_header(vec!["name", "old", "new", "diff", "diff_ratio", "speedup"]); - for cmp in self.all_cmps() { - let diff_ratio = format!("{:.2}%", cmp.diff_ratio * 100f64); - let speedup = format!("{:.2}x", cmp.speedup); - let diff = format!("{:.2}", cmp.diff); - let mut row = Row::new(); - row.add_cell(Cell::new(cmp.name)); - row.add_cell(Cell::new(cmp.old_value)); - row.add_cell(Cell::new(cmp.new_value)); - if cmp.speedup >= 1.0 { - row.add_cell(Cell::new(diff).fg(Color::Green)); - row.add_cell(Cell::new(diff_ratio).fg(Color::Green)); - row.add_cell(Cell::new(speedup).fg(Color::Green)); - } else { - row.add_cell(Cell::new(diff).fg(Color::Red)); - row.add_cell(Cell::new(diff_ratio).fg(Color::Red)); - row.add_cell(Cell::new(speedup).fg(Color::Red)); - } - table.add_row(row); - } - table - } - pub fn all_cmps(&self) -> Vec { - vec![ - self.cmp_tps(), - self.cmp_error_rate(), - self.cmp_min_latency(), - self.cmp_p25_latency(), - self.cmp_p50_latency(), - self.cmp_p75_latency(), - self.cmp_p90_latency(), - self.cmp_p99_latency(), - self.cmp_p999_latency(), - self.cmp_max_latency(), - ] - } - pub fn cmp_tps(&self) -> Comparison { - let old_tps = self.old.num_success_txes / self.old.duration.as_secs(); - let new_tps = self.new.num_success_txes / self.new.duration.as_secs(); - let diff = new_tps as i64 - old_tps as i64; - let diff_ratio = diff as f64 / old_tps as f64; - let speedup = 1.0 + diff_ratio; - Comparison { - name: "tps".to_string(), - old_value: format!("{:.2}", old_tps), - new_value: format!("{:.2}", new_tps), - diff, - diff_ratio, - speedup, - } - } - pub fn cmp_error_rate(&self) -> Comparison { - let old_error_rate = - self.old.num_error_txes / (self.old.num_error_txes + self.old.num_success_txes); - let new_error_rate = - self.new.num_error_txes / (self.new.num_error_txes + self.new.num_success_txes); - let diff = new_error_rate as i64 - old_error_rate as i64; - let diff_ratio = diff as f64 / old_error_rate as f64; - let speedup = 1.0 / (1.0 + diff_ratio); - Comparison { - name: "error_rate".to_string(), - old_value: format!("{:.2}", old_error_rate), - new_value: format!("{:.2}", new_error_rate), - diff, - diff_ratio, - speedup, - } - } - pub fn cmp_min_latency(&self) -> Comparison { - let old = self.old.latency_ms.histogram.min() as i64; - let new = self.new.latency_ms.histogram.min() as i64; - let diff = new - old; - let diff_ratio = diff as f64 / old as f64; - let speedup = 1.0 / (1.0 + diff_ratio); - Comparison { - name: "min_latency".to_string(), - old_value: format!("{:.2}", old), - new_value: format!("{:.2}", new), - diff, - diff_ratio, - speedup, - } - } - pub fn cmp_p25_latency(&self) -> Comparison { - let old = self.old.latency_ms.histogram.value_at_quantile(0.25) as i64; - let new = self.new.latency_ms.histogram.value_at_quantile(0.25) as i64; - let diff = new - old; - let diff_ratio = diff as f64 / old as f64; - let speedup = 1.0 / (1.0 + diff_ratio); - Comparison { - name: "p25_latency".to_string(), - old_value: format!("{:.2}", old), - new_value: format!("{:.2}", new), - diff, - diff_ratio, - speedup, - } - } - pub fn cmp_p50_latency(&self) -> Comparison { - let old = self.old.latency_ms.histogram.value_at_quantile(0.5) as i64; - let new = self.new.latency_ms.histogram.value_at_quantile(0.5) as i64; - let diff = new - old; - let diff_ratio = diff as f64 / old as f64; - let speedup = 1.0 / (1.0 + diff_ratio); - Comparison { - name: "p50_latency".to_string(), - old_value: format!("{:.2}", old), - new_value: format!("{:.2}", new), - diff, - diff_ratio, - speedup, - } - } - pub fn cmp_p75_latency(&self) -> Comparison { - let old = self.old.latency_ms.histogram.value_at_quantile(0.75) as i64; - let new = self.new.latency_ms.histogram.value_at_quantile(0.75) as i64; - let diff = new - old; - let diff_ratio = diff as f64 / old as f64; - let speedup = 1.0 / (1.0 + diff_ratio); - Comparison { - name: "p75_latency".to_string(), - old_value: format!("{:.2}", old), - new_value: format!("{:.2}", new), - diff, - diff_ratio, - speedup, - } - } - pub fn cmp_p90_latency(&self) -> Comparison { - let old = self.old.latency_ms.histogram.value_at_quantile(0.9) as i64; - let new = self.new.latency_ms.histogram.value_at_quantile(0.9) as i64; - let diff = new - old; - let diff_ratio = diff as f64 / old as f64; - let speedup = 1.0 / (1.0 + diff_ratio); - Comparison { - name: "p90_latency".to_string(), - old_value: format!("{:.2}", old), - new_value: format!("{:.2}", new), - diff, - diff_ratio, - speedup, - } - } - pub fn cmp_p99_latency(&self) -> Comparison { - let old = self.old.latency_ms.histogram.value_at_quantile(0.99) as i64; - let new = self.new.latency_ms.histogram.value_at_quantile(0.99) as i64; - let diff = new - old; - let diff_ratio = diff as f64 / old as f64; - let speedup = 1.0 / (1.0 + diff_ratio); - Comparison { - name: "p99_latency".to_string(), - old_value: format!("{:.2}", old), - new_value: format!("{:.2}", new), - diff, - diff_ratio, - speedup, - } - } - pub fn cmp_p999_latency(&self) -> Comparison { - let old = self.old.latency_ms.histogram.value_at_quantile(0.999) as i64; - let new = self.new.latency_ms.histogram.value_at_quantile(0.999) as i64; - let diff = new - old; - let diff_ratio = diff as f64 / old as f64; - let speedup = 1.0 / (1.0 + diff_ratio); - Comparison { - name: "p999_latency".to_string(), - old_value: format!("{:.2}", old), - new_value: format!("{:.2}", new), - diff, - diff_ratio, - speedup, - } - } - pub fn cmp_max_latency(&self) -> Comparison { - let old = self.old.latency_ms.histogram.max() as i64; - let new = self.new.latency_ms.histogram.max() as i64; - let diff = new - old; - let diff_ratio = diff as f64 / old as f64; - let speedup = 1.0 / (1.0 + diff_ratio); - Comparison { - name: "max_latency".to_string(), - old_value: format!("{:.2}", old), - new_value: format!("{:.2}", new), - diff, - diff_ratio, - speedup, - } - } -} - -/// Convert an unsigned number into a string separated by `delim` every -/// `step_size` digits For example used to make 100000 more readable as 100,000 -fn format_num_with_separators + std::fmt::Display>( - x: T, - step_size: u8, - delim: &'static str, -) -> String { - x.to_string() - .as_bytes() - .rchunks(step_size as usize) - .rev() - .map(std::str::from_utf8) - .collect::, _>>() - .unwrap() - .join(delim) -} diff --git a/crates/sui-benchmark/src/lib.rs b/crates/sui-benchmark/src/lib.rs deleted file mode 100644 index 90c3f5a87b1..00000000000 --- a/crates/sui-benchmark/src/lib.rs +++ /dev/null @@ -1,908 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use std::{ - collections::BTreeMap, - sync::{Arc, Mutex}, - time::Duration, -}; - -use anyhow::bail; -use async_trait::async_trait; -use embedded_reconfig_observer::EmbeddedReconfigObserver; -use fullnode_reconfig_observer::FullNodeReconfigObserver; -use futures::{stream::FuturesUnordered, StreamExt}; -use mysten_metrics::GaugeGuard; -use prometheus::Registry; -use rand::Rng; -use roaring::RoaringBitmap; -use sui_config::genesis::Genesis; -use sui_core::{ - authority_aggregator::{AuthorityAggregator, AuthorityAggregatorBuilder}, - authority_client::{ - make_authority_clients_with_timeout_config, AuthorityAPI, NetworkAuthorityClient, - }, - quorum_driver::{ - QuorumDriver, QuorumDriverHandler, QuorumDriverHandlerBuilder, QuorumDriverMetrics, - }, -}; -use sui_json_rpc_types::{ - SuiObjectDataOptions, SuiObjectResponse, SuiObjectResponseQuery, SuiTransactionBlockEffects, - SuiTransactionBlockEffectsAPI, SuiTransactionBlockResponseOptions, -}; -use sui_network::{DEFAULT_CONNECT_TIMEOUT_SEC, DEFAULT_REQUEST_TIMEOUT_SEC}; -use sui_sdk::{SuiClient, SuiClientBuilder}; -use sui_types::{ - base_types::{AuthorityName, ConciseableName, ObjectID, ObjectRef, SequenceNumber, SuiAddress}, - committee::{Committee, CommitteeTrait, EpochId}, - crypto::{ - AggregateAuthenticator, AggregateAuthoritySignature, AuthorityQuorumSignInfo, - AuthoritySignature, AuthorityStrongQuorumSignInfo, - }, - effects::{CertifiedTransactionEffects, TransactionEffectsAPI, TransactionEvents}, - error::SuiError, - gas::GasCostSummary, - gas_coin::GasCoin, - message_envelope::Envelope, - object::{Object, Owner}, - programmable_transaction_builder::ProgrammableTransactionBuilder, - sui_system_state::{sui_system_state_summary::SuiSystemStateSummary, SuiSystemStateTrait}, - transaction::{Argument, CallArg, CertifiedTransaction, ObjectArg, Transaction}, -}; -use tokio::{ - task::JoinSet, - time::{sleep, timeout}, -}; -use tracing::{error, info}; - -pub mod bank; -pub mod benchmark_setup; -pub mod drivers; -pub mod embedded_reconfig_observer; -pub mod fullnode_reconfig_observer; -pub mod in_memory_wallet; -pub mod options; -pub mod system_state_observer; -pub mod util; -pub mod workloads; -use futures::FutureExt; -use sui_types::{ - messages_grpc::{HandleCertificateResponseV2, TransactionStatus}, - quorum_driver_types::{QuorumDriverError, QuorumDriverResponse}, -}; - -#[derive(Debug)] -/// A wrapper on execution results to accommodate different types of -/// responses from LocalValidatorAggregatorProxy and FullNodeProxy -#[allow(clippy::large_enum_variant)] -pub enum ExecutionEffects { - CertifiedTransactionEffects(CertifiedTransactionEffects, TransactionEvents), - SuiTransactionBlockEffects(SuiTransactionBlockEffects), -} - -impl ExecutionEffects { - pub fn mutated(&self) -> Vec<(ObjectRef, Owner)> { - match self { - ExecutionEffects::CertifiedTransactionEffects(certified_effects, ..) => { - certified_effects.data().mutated().to_vec() - } - ExecutionEffects::SuiTransactionBlockEffects(sui_tx_effects) => sui_tx_effects - .mutated() - .iter() - .map(|refe| (refe.reference.to_object_ref(), refe.owner)) - .collect(), - } - } - - pub fn created(&self) -> Vec<(ObjectRef, Owner)> { - match self { - ExecutionEffects::CertifiedTransactionEffects(certified_effects, ..) => { - certified_effects.data().created() - } - ExecutionEffects::SuiTransactionBlockEffects(sui_tx_effects) => sui_tx_effects - .created() - .iter() - .map(|refe| (refe.reference.to_object_ref(), refe.owner)) - .collect(), - } - } - - pub fn deleted(&self) -> Vec { - match self { - ExecutionEffects::CertifiedTransactionEffects(certified_effects, ..) => { - certified_effects.data().deleted().to_vec() - } - ExecutionEffects::SuiTransactionBlockEffects(sui_tx_effects) => sui_tx_effects - .deleted() - .iter() - .map(|refe| refe.to_object_ref()) - .collect(), - } - } - - pub fn quorum_sig(&self) -> Option<&AuthorityStrongQuorumSignInfo> { - match self { - ExecutionEffects::CertifiedTransactionEffects(certified_effects, ..) => { - Some(certified_effects.auth_sig()) - } - ExecutionEffects::SuiTransactionBlockEffects(_) => None, - } - } - - pub fn gas_object(&self) -> (ObjectRef, Owner) { - match self { - ExecutionEffects::CertifiedTransactionEffects(certified_effects, ..) => { - certified_effects.data().gas_object() - } - ExecutionEffects::SuiTransactionBlockEffects(sui_tx_effects) => { - let refe = &sui_tx_effects.gas_object(); - (refe.reference.to_object_ref(), refe.owner) - } - } - } - - pub fn sender(&self) -> SuiAddress { - match self.gas_object().1 { - Owner::AddressOwner(a) => a, - Owner::ObjectOwner(_) | Owner::Shared { .. } | Owner::Immutable => unreachable!(), /* owner of gas object is always an address */ - } - } - - pub fn is_ok(&self) -> bool { - match self { - ExecutionEffects::CertifiedTransactionEffects(certified_effects, ..) => { - certified_effects.data().status().is_ok() - } - ExecutionEffects::SuiTransactionBlockEffects(sui_tx_effects) => { - sui_tx_effects.status().is_ok() - } - } - } - - pub fn status(&self) -> String { - match self { - ExecutionEffects::CertifiedTransactionEffects(certified_effects, ..) => { - format!("{:#?}", certified_effects.data().status()) - } - ExecutionEffects::SuiTransactionBlockEffects(sui_tx_effects) => { - format!("{:#?}", sui_tx_effects.status()) - } - } - } - - pub fn gas_cost_summary(&self) -> GasCostSummary { - match self { - crate::ExecutionEffects::CertifiedTransactionEffects(a, _) => { - a.data().gas_cost_summary().clone() - } - crate::ExecutionEffects::SuiTransactionBlockEffects(b) => { - std::convert::Into::::into(b.gas_cost_summary().clone()) - } - } - } - - pub fn gas_used(&self) -> u64 { - self.gas_cost_summary().gas_used() - } - - pub fn net_gas_used(&self) -> i64 { - self.gas_cost_summary().net_gas_usage() - } - - pub fn print_gas_summary(&self) { - let gas_object = self.gas_object(); - let sender = self.sender(); - let status = self.status(); - let gas_cost_summary = self.gas_cost_summary(); - let gas_used = self.gas_used(); - let net_gas_used = self.net_gas_used(); - - info!( - "Summary:\n\ - Gas Object: {gas_object:?}\n\ - Sender: {sender:?}\n\ - status: {status}\n\ - Gas Cost Summary: {gas_cost_summary:#?}\n\ - Gas Used: {gas_used}\n\ - Net Gas Used: {net_gas_used}" - ); - } -} - -#[async_trait] -pub trait ValidatorProxy { - async fn get_object(&self, object_id: ObjectID) -> Result; - - async fn get_owned_objects( - &self, - account_address: SuiAddress, - ) -> Result, anyhow::Error>; - - async fn get_latest_system_state_object(&self) -> Result; - - async fn execute_transaction_block(&self, tx: Transaction) -> anyhow::Result; - - /// This function is similar to `execute_transaction` but does not check any - /// validator's signature. It should only be used for benchmarks. - async fn execute_bench_transaction(&self, tx: Transaction) -> anyhow::Result; - - fn clone_committee(&self) -> Arc; - - fn get_current_epoch(&self) -> EpochId; - - fn clone_new(&self) -> Box; - - async fn get_validators(&self) -> Result, anyhow::Error>; -} - -// TODO: Eventually remove this proxy because we shouldn't rely on validators to -// read objects. -pub struct LocalValidatorAggregatorProxy { - _qd_handler: QuorumDriverHandler, - // Stress client does not verify individual validator signatures since this is very expensive - qd: Arc>, - committee: Committee, - clients: BTreeMap, - requests: Mutex>, -} - -impl LocalValidatorAggregatorProxy { - pub async fn from_genesis( - genesis: &Genesis, - registry: &Registry, - reconfig_fullnode_rpc_url: Option<&str>, - ) -> Self { - let (aggregator, _) = AuthorityAggregatorBuilder::from_genesis(genesis) - .with_registry(registry) - .build() - .unwrap(); - - let committee = genesis.committee_with_network(); - let clients = make_authority_clients_with_timeout_config( - &committee, - DEFAULT_CONNECT_TIMEOUT_SEC, - DEFAULT_REQUEST_TIMEOUT_SEC, - ) - .unwrap(); - - Self::new_impl( - aggregator, - registry, - reconfig_fullnode_rpc_url, - clients, - committee.committee, - ) - .await - } - - async fn new_impl( - aggregator: AuthorityAggregator, - registry: &Registry, - reconfig_fullnode_rpc_url: Option<&str>, - clients: BTreeMap, - committee: Committee, - ) -> Self { - let quorum_driver_metrics = Arc::new(QuorumDriverMetrics::new(registry)); - let qd_handler = (if let Some(reconfig_fullnode_rpc_url) = reconfig_fullnode_rpc_url { - let qd_handler_builder = QuorumDriverHandlerBuilder::new( - Arc::new(aggregator.clone()), - quorum_driver_metrics, - ); - info!( - "Using FullNodeReconfigObserver: {:?}", - reconfig_fullnode_rpc_url - ); - let committee_store = aggregator.clone_committee_store(); - let reconfig_observer = Arc::new( - FullNodeReconfigObserver::new( - reconfig_fullnode_rpc_url, - committee_store, - aggregator.safe_client_metrics_base.clone(), - aggregator.metrics.clone(), - ) - .await, - ); - qd_handler_builder.with_reconfig_observer(reconfig_observer) - } else { - info!("Using EmbeddedReconfigObserver"); - let observer = EmbeddedReconfigObserver::new(); - // Get the latest committee from config observer - let new_agg = observer - .get_committee(Arc::new(aggregator)) - .await - .expect("Failed to get latest committee"); - let qd_handler_builder = - QuorumDriverHandlerBuilder::new(new_agg, quorum_driver_metrics); - qd_handler_builder.with_reconfig_observer(Arc::new(EmbeddedReconfigObserver::new())) - }) - .start(); - - let qd = qd_handler.clone_quorum_driver(); - Self { - _qd_handler: qd_handler, - qd, - clients, - committee, - requests: Mutex::new(JoinSet::new()), - } - } -} - -#[async_trait] -impl ValidatorProxy for LocalValidatorAggregatorProxy { - async fn get_object(&self, object_id: ObjectID) -> Result { - let auth_agg = self.qd.authority_aggregator().load(); - Ok(auth_agg - .get_latest_object_version_for_testing(object_id) - .await?) - } - - async fn get_owned_objects( - &self, - _account_address: SuiAddress, - ) -> Result, anyhow::Error> { - unimplemented!("Not available for local proxy"); - } - - async fn get_latest_system_state_object(&self) -> Result { - let auth_agg = self.qd.authority_aggregator().load(); - Ok(auth_agg - .get_latest_system_state_object_for_testing() - .await? - .into_sui_system_state_summary()) - } - - async fn execute_transaction_block(&self, tx: Transaction) -> anyhow::Result { - if std::env::var("BENCH_MODE").is_ok() { - return self.execute_bench_transaction(tx).await; - } - let tx_digest = *tx.digest(); - let mut retry_cnt = 0; - while retry_cnt < 3 { - let ticket = self.qd.submit_transaction(tx.clone()).await?; - // The ticket only times out when QuorumDriver exceeds the retry times - match ticket.await { - Ok(resp) => { - let QuorumDriverResponse { - effects_cert, - events, - } = resp; - return Ok(ExecutionEffects::CertifiedTransactionEffects( - effects_cert.into(), - events, - )); - } - Err(QuorumDriverError::NonRecoverableTransactionError { errors }) => { - bail!(QuorumDriverError::NonRecoverableTransactionError { errors }); - } - Err(err) => { - let delay = Duration::from_millis(rand::thread_rng().gen_range(100..1000)); - error!( - ?tx_digest, - retry_cnt, - "Transaction failed with err: {:?}. Sleeping for {:?} ...", - err, - delay, - ); - retry_cnt += 1; - sleep(delay).await; - } - } - } - bail!("Transaction {:?} failed for {retry_cnt} times", tx_digest); - } - - async fn execute_bench_transaction(&self, tx: Transaction) -> anyhow::Result { - // Store the epoch number; we read it from the votes and use it later to create - // the certificate. - let mut epoch = 0; - let auth_agg = self.qd.authority_aggregator().load(); - - // Send the transaction to all validators. - let tx_guard = GaugeGuard::acquire(&auth_agg.metrics.inflight_transactions); - let mut futures = FuturesUnordered::new(); - for (name, client) in self.clients.iter() { - let fut = client.handle_transaction(tx.clone()).map(|r| (r, *name)); - futures.push(fut); - } - auth_agg - .metrics - .inflight_transaction_requests - .add(futures.len() as i64); - - // TODO: This following aggregation will not work well at epoch boundary. - - // Listen to the replies from the first 2f+1 votes. - let mut total_stake = 0; - let mut votes = Vec::new(); - let mut certificate = None; - while let Some((response, name)) = futures.next().await { - auth_agg.metrics.inflight_transaction_requests.dec(); - match response { - Ok(response) => match response.status { - // If all goes well, the authority returns a vote. - TransactionStatus::Signed(signature) => { - epoch = signature.epoch; - total_stake += self.committee.weight(&signature.authority); - votes.push(signature); - } - // The transaction may be submitted again in case the certificate's submission - // failed. - TransactionStatus::Executed(cert, _effects, _) => { - tracing::warn!("Transaction already submitted: {tx:?}"); - if let Some(cert) = cert { - certificate = Some(CertifiedTransaction::new_from_data_and_sig( - tx.data().clone(), - cert, - )); - } - } - }, - // This typically happens when the validators are overloaded and the transaction is - // immediately rejected. - Err(e) => { - self.qd - .authority_aggregator() - .load() - .metrics - .process_tx_errors - .with_label_values(&[&name.concise().to_string(), e.as_ref()]) - .inc(); - tracing::warn!("Failed to submit transaction: {e}") - } - } - - if total_stake >= self.committee.quorum_threshold() { - break; - } - - if certificate.is_some() { - break; - } - } - - // Assemble a certificate from the validator's replies. - let certified_transaction: CertifiedTransaction = match certificate { - Some(x) => x, - None => { - let signatures: BTreeMap<_, _> = votes - .into_iter() - .map(|a| (a.authority, a.signature)) - .collect(); - let mut signers_map = RoaringBitmap::new(); - for pk in signatures.keys() { - signers_map.insert( - self.committee - .authority_index(pk) - .ok_or(SuiError::UnknownSigner { - signer: Some(pk.concise().to_string()), - index: None, - committee: Box::new(self.committee.clone()), - }) - .expect("Received signature from unknown validator"), - ); - } - let sigs: Vec = signatures.into_values().collect(); - - let quorum_signature = AuthorityQuorumSignInfo { - epoch, - // Note: This function simply aggregates signatures (it does not check that they - // are individually valid). - signature: AggregateAuthoritySignature::aggregate(&sigs) - .map_err(|e| SuiError::InvalidSignature { - error: e.to_string(), - }) - .expect("Validator returned invalid signature"), - signers_map, - }; - - Envelope::new_from_data_and_sig(tx.into_data(), quorum_signature) - } - }; - auth_agg - .metrics - .inflight_transaction_requests - .sub(futures.len() as i64); - drop(tx_guard); - - // Send the certificate to all validators. - let _cert_guard = GaugeGuard::acquire(&auth_agg.metrics.inflight_certificates); - let mut futures = FuturesUnordered::new(); - total_stake = 0; - let mut transaction_effects = None; - let mut transaction_events = None; - for (name, client) in self.clients.iter() { - let client = client.clone(); - let certificate = certified_transaction.clone(); - let name = *name; - futures.push(async move { - client - .handle_certificate_v2(certificate) - .map(move |r| (r, name)) - .await - }); - } - auth_agg - .metrics - .inflight_certificate_requests - .add(futures.len() as i64); - - // Wait for the replies from a quorum of validators. - while let Some((response, name)) = futures.next().await { - auth_agg.metrics.inflight_certificate_requests.dec(); - match response { - // If all goes well, the validators reply with signed effects. - Ok(HandleCertificateResponseV2 { - signed_effects, - events, - fastpath_input_objects: _, // unused field - }) => { - let author = signed_effects.auth_sig().authority; - transaction_effects = Some(signed_effects.data().clone()); - transaction_events = Some(events); - total_stake += self.committee.weight(&author); - } - - // This typically happens when the validators are overloaded and the certificate is - // immediately rejected. - Err(e) => { - auth_agg - .metrics - .process_cert_errors - .with_label_values(&[&name.concise().to_string(), e.as_ref()]) - .inc(); - tracing::warn!("Failed to submit certificate: {e}") - } - } - - if total_stake >= self.committee.quorum_threshold() { - break; - } - } - - // Abort if we failed to submit the certificate to enough validators. This - // typically happens when the validators are overloaded and the requests - // timed out. - if transaction_effects.is_none() || total_stake < self.committee.quorum_threshold() { - bail!("Failed to submit certificate to quorum of validators"); - } - - // Wait for 10 more seconds on remaining requests asynchronously. - const WAIT_TIMEOUT: Duration = Duration::from_secs(10); - { - let auth_agg = auth_agg.clone(); - let mut requests = self.requests.lock().unwrap(); - requests.spawn(async move { - let _ = timeout(WAIT_TIMEOUT, async { - while futures.next().await.is_some() { - auth_agg.metrics.inflight_certificate_requests.dec(); - } - }) - .await; - auth_agg - .metrics - .inflight_certificate_requests - .sub(futures.len() as i64); - }); - } - - // Package the certificate and effects to return. - let signed_material = certified_transaction.auth_sig().clone(); - let effects = ExecutionEffects::CertifiedTransactionEffects( - Envelope::new_from_data_and_sig(transaction_effects.unwrap(), signed_material), - transaction_events.unwrap(), - ); - Ok(effects) - } - - fn clone_committee(&self) -> Arc { - self.qd.clone_committee() - } - - fn get_current_epoch(&self) -> EpochId { - self.qd.current_epoch() - } - - fn clone_new(&self) -> Box { - let qdh = self._qd_handler.clone_new(); - let qd = qdh.clone_quorum_driver(); - Box::new(Self { - _qd_handler: qdh, - qd, - clients: self.clients.clone(), - committee: self.committee.clone(), - requests: Mutex::new(JoinSet::new()), - }) - } - - async fn get_validators(&self) -> Result, anyhow::Error> { - let system_state = self.get_latest_system_state_object().await?; - Ok(system_state - .active_validators - .iter() - .map(|v| v.sui_address) - .collect()) - } -} - -pub struct FullNodeProxy { - sui_client: SuiClient, - committee: Arc, -} - -impl FullNodeProxy { - pub async fn from_url(http_url: &str) -> Result { - // Each request times out after 60s (default value) - let sui_client = SuiClientBuilder::default() - .max_concurrent_requests(500_000) - .build(http_url) - .await?; - - let resp = sui_client.read_api().get_committee_info(None).await?; - let epoch = resp.epoch; - let committee_vec = resp.validators; - let committee_map = BTreeMap::from_iter(committee_vec.into_iter()); - let committee = - Committee::new_for_testing_with_normalized_voting_power(epoch, committee_map); - - Ok(Self { - sui_client, - committee: Arc::new(committee), - }) - } -} - -#[async_trait] -impl ValidatorProxy for FullNodeProxy { - async fn get_object(&self, object_id: ObjectID) -> Result { - let response = self - .sui_client - .read_api() - .get_object_with_options(object_id, SuiObjectDataOptions::bcs_lossless()) - .await?; - - if let Some(sui_object) = response.data { - sui_object.try_into() - } else if let Some(error) = response.error { - bail!("Error getting object {:?}: {}", object_id, error) - } else { - bail!("Object {:?} not found and no error provided", object_id) - } - } - - async fn get_owned_objects( - &self, - account_address: SuiAddress, - ) -> Result, anyhow::Error> { - let mut objects: Vec = Vec::new(); - let mut cursor = None; - loop { - let response = self - .sui_client - .read_api() - .get_owned_objects( - account_address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::bcs_lossless(), - )), - cursor, - None, - ) - .await?; - - objects.extend(response.data); - - if response.has_next_page { - cursor = response.next_cursor; - } else { - break; - } - } - - let mut values_objects = Vec::new(); - - for object in objects { - let o = object.data; - if let Some(o) = o { - let temp: Object = o.clone().try_into()?; - let gas_coin = GasCoin::try_from(&temp)?; - values_objects.push((gas_coin.value(), o.clone().try_into()?)); - } - } - - Ok(values_objects) - } - - async fn get_latest_system_state_object(&self) -> Result { - Ok(self - .sui_client - .governance_api() - .get_latest_sui_system_state() - .await?) - } - - async fn execute_transaction_block(&self, tx: Transaction) -> anyhow::Result { - let tx_digest = *tx.digest(); - let mut retry_cnt = 0; - while retry_cnt < 10 { - // Fullnode could time out after WAIT_FOR_FINALITY_TIMEOUT (30s) in - // TransactionOrchestrator SuiClient times out after 60s - match self - .sui_client - .quorum_driver_api() - .execute_transaction_block( - tx.clone(), - SuiTransactionBlockResponseOptions::new().with_effects(), - None, - ) - .await - { - Ok(resp) => { - let effects = ExecutionEffects::SuiTransactionBlockEffects( - resp.effects.expect("effects field should not be None"), - ); - return Ok(effects); - } - Err(err) => { - error!( - ?tx_digest, - retry_cnt, "Transaction failed with err: {:?}", err - ); - retry_cnt += 1; - } - } - } - bail!("Transaction {:?} failed for {retry_cnt} times", tx_digest); - } - - async fn execute_bench_transaction(&self, tx: Transaction) -> anyhow::Result { - self.execute_transaction_block(tx).await - } - - fn clone_committee(&self) -> Arc { - self.committee.clone() - } - - fn get_current_epoch(&self) -> EpochId { - self.committee.epoch - } - - fn clone_new(&self) -> Box { - Box::new(Self { - sui_client: self.sui_client.clone(), - committee: self.clone_committee(), - }) - } - - async fn get_validators(&self) -> Result, anyhow::Error> { - let validators = self - .sui_client - .governance_api() - .get_latest_sui_system_state() - .await? - .active_validators; - Ok(validators.into_iter().map(|v| v.sui_address).collect()) - } -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub enum BenchMoveCallArg { - Pure(Vec), - Shared((ObjectID, SequenceNumber, bool)), - ImmOrOwnedObject(ObjectRef), - ImmOrOwnedObjectVec(Vec), - SharedObjectVec(Vec<(ObjectID, SequenceNumber, bool)>), -} - -impl From for BenchMoveCallArg { - fn from(b: bool) -> Self { - // unwrap safe because every u8 value is BCS-serializable - BenchMoveCallArg::Pure(bcs::to_bytes(&b).unwrap()) - } -} - -impl From for BenchMoveCallArg { - fn from(n: u8) -> Self { - // unwrap safe because every u8 value is BCS-serializable - BenchMoveCallArg::Pure(bcs::to_bytes(&n).unwrap()) - } -} - -impl From for BenchMoveCallArg { - fn from(n: u16) -> Self { - // unwrap safe because every u16 value is BCS-serializable - BenchMoveCallArg::Pure(bcs::to_bytes(&n).unwrap()) - } -} - -impl From for BenchMoveCallArg { - fn from(n: u32) -> Self { - // unwrap safe because every u32 value is BCS-serializable - BenchMoveCallArg::Pure(bcs::to_bytes(&n).unwrap()) - } -} - -impl From for BenchMoveCallArg { - fn from(n: u64) -> Self { - // unwrap safe because every u64 value is BCS-serializable - BenchMoveCallArg::Pure(bcs::to_bytes(&n).unwrap()) - } -} - -impl From for BenchMoveCallArg { - fn from(n: u128) -> Self { - // unwrap safe because every u128 value is BCS-serializable - BenchMoveCallArg::Pure(bcs::to_bytes(&n).unwrap()) - } -} - -impl From<&Vec> for BenchMoveCallArg { - fn from(v: &Vec) -> Self { - // unwrap safe because every vec value is BCS-serializable - BenchMoveCallArg::Pure(bcs::to_bytes(v).unwrap()) - } -} - -impl From for BenchMoveCallArg { - fn from(obj: ObjectRef) -> Self { - BenchMoveCallArg::ImmOrOwnedObject(obj) - } -} - -impl From for BenchMoveCallArg { - fn from(ca: CallArg) -> Self { - match ca { - CallArg::Pure(p) => BenchMoveCallArg::Pure(p), - CallArg::Object(obj) => match obj { - ObjectArg::ImmOrOwnedObject(imo) => BenchMoveCallArg::ImmOrOwnedObject(imo), - ObjectArg::SharedObject { - id, - initial_shared_version, - mutable, - } => BenchMoveCallArg::Shared((id, initial_shared_version, mutable)), - ObjectArg::Receiving(_) => { - unimplemented!("Receiving is not supported for benchmarks") - } - }, - } - } -} - -/// Convert MoveCallArg to Vector of Argument for PT -pub fn convert_move_call_args( - args: &[BenchMoveCallArg], - pt_builder: &mut ProgrammableTransactionBuilder, -) -> Vec { - args.iter() - .map(|arg| match arg { - BenchMoveCallArg::Pure(bytes) => { - pt_builder.input(CallArg::Pure(bytes.clone())).unwrap() - } - BenchMoveCallArg::Shared((id, initial_shared_version, mutable)) => pt_builder - .input(CallArg::Object(ObjectArg::SharedObject { - id: *id, - initial_shared_version: *initial_shared_version, - mutable: *mutable, - })) - .unwrap(), - BenchMoveCallArg::ImmOrOwnedObject(obj_ref) => { - pt_builder.input((*obj_ref).into()).unwrap() - } - BenchMoveCallArg::ImmOrOwnedObjectVec(obj_refs) => pt_builder - .make_obj_vec(obj_refs.iter().map(|q| ObjectArg::ImmOrOwnedObject(*q))) - .unwrap(), - BenchMoveCallArg::SharedObjectVec(obj_refs) => pt_builder - .make_obj_vec( - obj_refs - .iter() - .map( - |(id, initial_shared_version, mutable)| ObjectArg::SharedObject { - id: *id, - initial_shared_version: *initial_shared_version, - mutable: *mutable, - }, - ), - ) - .unwrap(), - }) - .collect() -} diff --git a/crates/sui-benchmark/src/util.rs b/crates/sui-benchmark/src/util.rs deleted file mode 100644 index b69de0eecd4..00000000000 --- a/crates/sui-benchmark/src/util.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{path::PathBuf, sync::Arc}; - -use anyhow::Result; -use sui_keys::keystore::{AccountKeystore, FileBasedKeystore}; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ - base_types::{ObjectRef, SuiAddress}, - crypto::{AccountKeyPair, KeypairTraits, SuiKeyPair}, - object::Owner, - transaction::{Transaction, TransactionData, TEST_ONLY_GAS_UNIT_FOR_TRANSFER}, - utils::to_sender_signed_transaction, -}; - -use crate::{workloads::Gas, ValidatorProxy}; - -// This is the maximum gas we will transfer from primary coin into any gas coin -// for running the benchmark - -pub type UpdatedAndNewlyMintedGasCoins = Vec; - -pub fn get_ed25519_keypair_from_keystore( - keystore_path: PathBuf, - requested_address: &SuiAddress, -) -> Result { - let keystore = FileBasedKeystore::new(&keystore_path)?; - match keystore.get_key(requested_address) { - Ok(SuiKeyPair::Ed25519(kp)) => Ok(kp.copy()), - other => Err(anyhow::anyhow!("Invalid key type: {:?}", other)), - } -} - -pub fn make_pay_tx( - input_coins: Vec, - sender: SuiAddress, - addresses: Vec, - split_amounts: Vec, - gas: ObjectRef, - keypair: &AccountKeyPair, - gas_price: u64, -) -> Result { - let pay = TransactionData::new_pay( - sender, - input_coins, - addresses, - split_amounts, - gas, - TEST_ONLY_GAS_UNIT_FOR_TRANSFER * gas_price, - gas_price, - )?; - Ok(to_sender_signed_transaction(pay, keypair)) -} - -pub async fn publish_basics_package( - gas: ObjectRef, - proxy: Arc, - sender: SuiAddress, - keypair: &AccountKeyPair, - gas_price: u64, -) -> ObjectRef { - let transaction = TestTransactionBuilder::new(sender, gas, gas_price) - .publish_examples("basics") - .build_and_sign(keypair); - let effects = proxy.execute_transaction_block(transaction).await.unwrap(); - effects - .created() - .iter() - .find(|(_, owner)| matches!(owner, Owner::Immutable)) - .map(|(reference, _)| *reference) - .unwrap() -} diff --git a/crates/sui-benchmark/src/workloads/data/adversarial/Move.toml b/crates/sui-benchmark/src/workloads/data/adversarial/Move.toml deleted file mode 100644 index d3941ddd22e..00000000000 --- a/crates/sui-benchmark/src/workloads/data/adversarial/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "adversarial" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -adversarial = "0x0" -sui = "0000000000000000000000000000000000000000000000000000000000000002" diff --git a/crates/sui-benchmark/src/workloads/data/max_package/Move.toml b/crates/sui-benchmark/src/workloads/data/max_package/Move.toml deleted file mode 100644 index 40343e57c23..00000000000 --- a/crates/sui-benchmark/src/workloads/data/max_package/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "max_package" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -max_package = "0x0" -sui = "0000000000000000000000000000000000000000000000000000000000000002" diff --git a/crates/sui-benchmark/src/workloads/mod.rs b/crates/sui-benchmark/src/workloads/mod.rs deleted file mode 100644 index e478e3d2529..00000000000 --- a/crates/sui-benchmark/src/workloads/mod.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod adversarial; -pub mod batch_payment; -pub mod delegation; -pub mod payload; -pub mod shared_counter; -pub mod shared_object_deletion; -pub mod transfer_object; -pub mod workload; -pub mod workload_configuration; - -use std::sync::Arc; - -use sui_types::{ - base_types::{ObjectRef, SuiAddress}, - crypto::AccountKeyPair, -}; -use workload::*; - -use crate::{drivers::Interval, workloads::payload::Payload}; - -pub type GroupID = u32; - -#[derive(Debug, Clone)] -pub struct WorkloadParams { - pub group: GroupID, - pub target_qps: u64, - pub num_workers: u64, - pub max_ops: u64, - pub duration: Interval, -} - -#[derive(Debug)] -pub struct WorkloadBuilderInfo { - pub workload_params: WorkloadParams, - pub workload_builder: Box>, -} - -#[derive(Debug)] -pub struct WorkloadInfo { - pub workload_params: WorkloadParams, - pub workload: Box>, -} - -pub type Gas = (ObjectRef, SuiAddress, Arc); - -#[derive(Clone)] -pub struct GasCoinConfig { - // amount of SUI to transfer to this gas coin - pub amount: u64, - // recipient of this gas coin - pub address: SuiAddress, - // recipient account key pair (useful for signing txns) - pub keypair: Arc, -} diff --git a/crates/sui-benchmark/src/workloads/workload.rs b/crates/sui-benchmark/src/workloads/workload.rs deleted file mode 100644 index 92109ac67dd..00000000000 --- a/crates/sui-benchmark/src/workloads/workload.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::sync::Arc; - -use async_trait::async_trait; -use sui_types::gas_coin::MIST_PER_SUI; - -use crate::{ - system_state_observer::SystemStateObserver, - workloads::{payload::Payload, Gas, GasCoinConfig}, - ValidatorProxy, -}; - -// This is the maximum gas we will transfer from primary coin into any gas coin -// for running the benchmark -pub const MAX_GAS_FOR_TESTING: u64 = 1_000 * MIST_PER_SUI; - -// TODO: get this information from protocol config -// This is the maximum budget that can be set for a transaction. 50 SUI. -pub const MAX_BUDGET: u64 = 50 * MIST_PER_SUI; -// (COIN_BYTES_SIZE * STORAGE_PRICE * STORAGE_UNITS_PER_BYTE) -pub const STORAGE_COST_PER_COIN: u64 = 130 * 76 * 100; -// (COUNTER_BYTES_SIZE * STORAGE_PRICE * STORAGE_UNITS_PER_BYTE) -pub const STORAGE_COST_PER_COUNTER: u64 = 341 * 76 * 100; -/// Used to estimate the budget required for each transaction. -pub const ESTIMATED_COMPUTATION_COST: u64 = 1_000_000; - -#[async_trait] -pub trait WorkloadBuilder: Send + Sync + std::fmt::Debug { - async fn generate_coin_config_for_init(&self) -> Vec; - async fn generate_coin_config_for_payloads(&self) -> Vec; - async fn build(&self, init_gas: Vec, payload_gas: Vec) -> Box>; -} - -/// A Workload is used to generate multiple payloads during setup phase with -/// `make_test_payloads()` which are added to a local queue. We execute -/// transactions (the queue is drained based on the target qps i.e. for 100 tps, -/// the queue will be popped 100 times every second) with those payloads -/// and generate new payloads (which are enqueued back to the queue) with the -/// returned effects. The total number of payloads to generate depends on how -/// much transaction throughput we want and the maximum number of transactions -/// we want to have in flight. For instance, for a 100 target_qps and -/// in_flight_ratio of 5, a maximum of 500 transactions is expected to be in -/// flight and that many payloads are created. -#[async_trait] -pub trait Workload: Send + Sync + std::fmt::Debug { - async fn init( - &mut self, - proxy: Arc, - system_state_observer: Arc, - ); - async fn make_test_payloads( - &self, - proxy: Arc, - system_state_observer: Arc, - ) -> Vec>; -} diff --git a/crates/sui-benchmark/tests/data/deepbook_client/Move.toml b/crates/sui-benchmark/tests/data/deepbook_client/Move.toml deleted file mode 100644 index 7cb0166f141..00000000000 --- a/crates/sui-benchmark/tests/data/deepbook_client/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "deepbook_client" -version = "0.0.1" - -[dependencies] -DeepBook = { local = "../../../../sui-framework/packages/deepbook" } - -[addresses] -deepbook_client = "0x0" diff --git a/crates/sui-bridge/Cargo.toml b/crates/sui-bridge/Cargo.toml deleted file mode 100644 index c71e0c06ba8..00000000000 --- a/crates/sui-bridge/Cargo.toml +++ /dev/null @@ -1,62 +0,0 @@ -[package] -name = "sui-bridge" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -ethers = "2.0" -tokio = { workspace = true, features = ["full"] } -sui-types.workspace = true -sui-common.workspace = true -arc-swap.workspace = true -num_enum.workspace = true -move-core-types.workspace = true -url.workspace = true -futures.workspace = true -once_cell.workspace = true -telemetry-subscribers.workspace = true -prometheus.workspace = true -async-trait.workspace = true -typed-store-derive.workspace = true -rocksdb.workspace = true -typed-store.workspace = true -mysten-metrics.workspace = true -sui-sdk.workspace = true -sui-config.workspace = true -clap.workspace = true -tracing.workspace = true -git-version.workspace = true -const-str.workspace = true -bcs.workspace = true -sui-json-rpc-types.workspace = true -serde.workspace = true -serde_with.workspace = true -serde_json.workspace = true -eyre.workspace = true -tempfile.workspace = true -axum.workspace = true -anyhow.workspace = true -reqwest.workspace = true -fastcrypto.workspace = true -tap.workspace = true -rand.workspace = true -lru.workspace = true -shared-crypto.workspace = true -backoff = { version = "0.4.0", features = [ - "futures", -] } - -[dev-dependencies] -sui-types = { workspace = true, features = ["test-utils"] } -sui-json-rpc-types = { workspace = true, features = ["test-utils"] } -sui-config.workspace = true -sui-test-transaction-builder.workspace = true -test-cluster.workspace = true -hex-literal = "0.3.4" - -[[bin]] -name = "sui-bridge-cli" -path = "src/tools/cli.rs" diff --git a/crates/sui-bridge/abi/sui_bridge.json b/crates/sui-bridge/abi/sui_bridge.json deleted file mode 100644 index f9b0cea8343..00000000000 --- a/crates/sui-bridge/abi/sui_bridge.json +++ /dev/null @@ -1,644 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "previousAdmin", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "beacon", - "type": "address" - } - ], - "name": "BeaconUpgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint8", - "name": "sourceChainId", - "type": "uint8" - }, - { - "indexed": true, - "internalType": "uint64", - "name": "nonce", - "type": "uint64" - }, - { - "indexed": true, - "internalType": "uint8", - "name": "destinationChainId", - "type": "uint8" - }, - { - "indexed": false, - "internalType": "uint8", - "name": "tokenCode", - "type": "uint8" - }, - { - "indexed": false, - "internalType": "uint64", - "name": "suiAdjustedAmount", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "address", - "name": "sourceAddress", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "targetAddress", - "type": "bytes" - } - ], - "name": "TokensBridgedToSui", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "inputs": [], - "name": "BRIDGE_UPGRADE_STAKE_REQUIRED", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "FREEZING_STAKE_REQUIRED", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "TRANSFER_STAKE_REQUIRED", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "UNFREEZING_STAKE_REQUIRED", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "tokenId", - "type": "uint8" - }, - { - "internalType": "uint64", - "name": "originalAmount", - "type": "uint64" - }, - { - "internalType": "uint8", - "name": "ethDecimal", - "type": "uint8" - } - ], - "name": "adjustDecimalsForErc20", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "tokenId", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "originalAmount", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "ethDecimal", - "type": "uint8" - } - ], - "name": "adjustDecimalsForSuiToken", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "targetAddress", - "type": "bytes" - }, - { - "internalType": "uint8", - "name": "destinationChainId", - "type": "uint8" - } - ], - "name": "bridgeETHToSui", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "tokenId", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "targetAddress", - "type": "bytes" - }, - { - "internalType": "uint8", - "name": "destinationChainId", - "type": "uint8" - } - ], - "name": "bridgeToSui", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "chainId", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "committee", - "outputs": [ - { - "internalType": "contract IBridgeCommittee", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "signatures", - "type": "bytes[]" - }, - { - "components": [ - { - "internalType": "uint8", - "name": "messageType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "uint64", - "name": "nonce", - "type": "uint64" - }, - { - "internalType": "uint8", - "name": "chainID", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "payload", - "type": "bytes" - } - ], - "internalType": "struct Messages.Message", - "name": "message", - "type": "tuple" - } - ], - "name": "executeEmergencyOpWithSignatures", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "_supportedTokens", - "type": "address[]" - }, - { - "internalType": "address", - "name": "_committee", - "type": "address" - }, - { - "internalType": "address", - "name": "_vault", - "type": "address" - }, - { - "internalType": "address", - "name": "_weth9", - "type": "address" - }, - { - "internalType": "uint8", - "name": "_chainId", - "type": "uint8" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "name": "messageProcessed", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "name": "requiredApprovalStake", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "name": "supportedTokens", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "signatures", - "type": "bytes[]" - }, - { - "components": [ - { - "internalType": "uint8", - "name": "messageType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "uint64", - "name": "nonce", - "type": "uint64" - }, - { - "internalType": "uint8", - "name": "chainID", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "payload", - "type": "bytes" - } - ], - "internalType": "struct Messages.Message", - "name": "message", - "type": "tuple" - } - ], - "name": "transferTokensWithSignatures", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "signatures", - "type": "bytes[]" - }, - { - "components": [ - { - "internalType": "uint8", - "name": "messageType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "uint64", - "name": "nonce", - "type": "uint64" - }, - { - "internalType": "uint8", - "name": "chainID", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "payload", - "type": "bytes" - } - ], - "internalType": "struct Messages.Message", - "name": "message", - "type": "tuple" - } - ], - "name": "upgradeBridgeWithSignatures", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - } - ], - "name": "upgradeTo", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "vault", - "outputs": [ - { - "internalType": "contract IBridgeVault", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "weth9", - "outputs": [ - { - "internalType": "contract IWETH9", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/crates/sui-bridge/build.rs b/crates/sui-bridge/build.rs deleted file mode 100644 index 244572cd7b4..00000000000 --- a/crates/sui-bridge/build.rs +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - fs, - path::{Path, PathBuf}, - process::{exit, Command, ExitStatus}, -}; - -fn main() -> Result<(), ExitStatus> { - #[cfg(windows)] - { - eprintln!("bridge tests are not supported on Windows."); - return Ok(()); - } - - println!("cargo:rerun-if-changed=build.rs"); - let base = env!("CARGO_MANIFEST_DIR"); - let bridge_path = format!("{base}/../../bridge/evm"); - let bridge_lib_path = format!("{base}/../../bridge/evm/lib"); - let mut forge_path = "forge".to_owned(); - // Check if Forge is installed - let forge_installed = Command::new("which") - .arg("forge") - .output() - .map(|output| output.status.success()) - .unwrap_or(false); - if !forge_installed { - eprintln!("Installing forge"); - // Also print the path where foundryup is installed - let install_cmd = "curl -L https://foundry.paradigm.xyz | { cat; echo 'echo foundryup-path=\"$FOUNDRY_BIN_DIR/foundryup\"'; } | bash"; - - let output = Command::new("sh") - .arg("-c") - .arg(install_cmd) - .output() - .expect("Failed to install Forge"); - - // extract foundryup path - let output_str = String::from_utf8_lossy(&output.stdout); - let mut foundryup_path = None; - for line in output_str.lines() { - if line.starts_with("foundryup-path=") { - foundryup_path = Some(line.trim_start_matches("foundryup-path=")); - break; - } - } - if foundryup_path.is_none() { - eprintln!("Error installing forge: expect a foundry path in output"); - exit(1); - } - let foundryup_path = foundryup_path.unwrap(); - eprintln!("foundryup path: {foundryup_path}"); - // Run foundryup - let output = Command::new(foundryup_path) - .output() - .expect("Failed to run foundryup"); - - if !output.status.success() { - eprintln!("Error running foundryup: {:?}", output); - exit(1); - } - // Update forge path - let mut forge = PathBuf::from(foundryup_path); - forge.pop(); - forge.push("forge"); - forge_path = forge.to_str().unwrap().to_owned(); - } - - // check if should install dependencies - if should_install_dependencies(&bridge_lib_path) { - // Run Foundry CLI command to install dependencies - Command::new(forge_path) - .current_dir(bridge_path) - .arg("install") - .arg("https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable@v5.0.1") - .arg("https://github.com/foundry-rs/forge-std@v1.3.0") - .arg("https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades") - .arg("--no-git") - .arg("--no-commit") - .status() - .expect("Failed to execute Foundry CLI command"); - } - - Ok(()) -} - -fn should_install_dependencies(dir_path: &str) -> bool { - let dependencies = vec![ - "forge-std", - "openzeppelin-contracts-upgradeable", - "openzeppelin-foundry-upgrades", - ]; - let mut missing_dependencies = false; - for d in &dependencies { - let path = format!("{}/{}", dir_path, d); - let path = Path::new(&path); - if !path.exists() { - missing_dependencies = true; - break; - } - } - // found all dependencies, no need to install - if !missing_dependencies { - return false; - } - // if any dependencies are missing, recreate an empty directory and then - // reinstall - eprintln!( - "cargo:warning={:?} does not have all the dependnecies, re-creating", - dir_path - ); - if Path::new(&dir_path).exists() { - fs::remove_dir_all(dir_path).unwrap(); - } - fs::create_dir_all(dir_path).expect("Failed to create directory"); - true -} diff --git a/crates/sui-bridge/src/abi.rs b/crates/sui-bridge/src/abi.rs deleted file mode 100644 index edc60fe85eb..00000000000 --- a/crates/sui-bridge/src/abi.rs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use ethers::{ - abi::RawLog, - contract::{abigen, EthLogDecode}, - types::Address as EthAddress, -}; -use serde::{Deserialize, Serialize}; -use sui_types::base_types::SuiAddress; - -use crate::{ - error::{BridgeError, BridgeResult}, - types::{BridgeAction, BridgeChainId, EthLog, EthToSuiBridgeAction, TokenId}, -}; - -// TODO: write a macro to handle variants - -// TODO: Add other events -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum EthBridgeEvent { - EthSuiBridgeEvents(EthSuiBridgeEvents), -} - -abigen!( - EthSuiBridge, - "abi/sui_bridge.json", - event_derives(serde::Deserialize, serde::Serialize) -); - -impl EthBridgeEvent { - pub fn try_from_eth_log(log: &EthLog) -> Option { - let raw_log = RawLog { - topics: log.log.topics.clone(), - data: log.log.data.to_vec(), - }; - - if let Ok(decoded) = EthSuiBridgeEvents::decode_log(&raw_log) { - return Some(EthBridgeEvent::EthSuiBridgeEvents(decoded)); - } - - // TODO: try other variants - None - } -} - -impl EthBridgeEvent { - pub fn try_into_bridge_action( - self, - eth_tx_hash: ethers::types::H256, - eth_event_index: u16, - ) -> Option { - match self { - EthBridgeEvent::EthSuiBridgeEvents(event) => { - match event { - EthSuiBridgeEvents::TokensBridgedToSuiFilter(event) => { - let bridge_event = match EthToSuiTokenBridgeV1::try_from(&event) { - Ok(bridge_event) => bridge_event, - // This only happens when solidity code does not align with rust code. - // When this happens in production, there is a risk of stuck bridge - // transfers. We log error here. - // TODO: add metrics and alert - Err(e) => { - tracing::error!( - ?eth_tx_hash, - eth_event_index, - "Failed to convert TokensBridgedToSui log to EthToSuiTokenBridgeV1. This indicates incorrect parameters or a bug in the code: {:?}. Err: {:?}", - event, - e - ); - return None; - } - }; - - Some(BridgeAction::EthToSuiBridgeAction(EthToSuiBridgeAction { - eth_tx_hash, - eth_event_index, - eth_bridge_event: bridge_event, - })) - } - _ => None, - } - } - } - } -} - -// Sanity checked version of TokensBridgedToSuiFilter -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Hash)] -pub struct EthToSuiTokenBridgeV1 { - pub nonce: u64, - pub sui_chain_id: BridgeChainId, - pub eth_chain_id: BridgeChainId, - pub sui_address: SuiAddress, - pub eth_address: EthAddress, - pub token_id: TokenId, - pub amount: u64, -} - -impl TryFrom<&TokensBridgedToSuiFilter> for EthToSuiTokenBridgeV1 { - type Error = BridgeError; - fn try_from(event: &TokensBridgedToSuiFilter) -> BridgeResult { - Ok(Self { - nonce: event.nonce, - sui_chain_id: BridgeChainId::try_from(event.destination_chain_id)?, - eth_chain_id: BridgeChainId::try_from(event.source_chain_id)?, - sui_address: SuiAddress::from_bytes(event.target_address.as_ref())?, - eth_address: event.source_address, - token_id: TokenId::try_from(event.token_code)?, - amount: event.sui_adjusted_amount, - }) - } -} diff --git a/crates/sui-bridge/src/client/mod.rs b/crates/sui-bridge/src/client/mod.rs deleted file mode 100644 index 70bf7141d63..00000000000 --- a/crates/sui-bridge/src/client/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod bridge_authority_aggregator; -pub mod bridge_client; diff --git a/crates/sui-bridge/src/config.rs b/crates/sui-bridge/src/config.rs deleted file mode 100644 index 72a0637bd3f..00000000000 --- a/crates/sui-bridge/src/config.rs +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::{BTreeMap, HashSet}, - path::PathBuf, - str::FromStr, - sync::Arc, -}; - -use anyhow::anyhow; -use ethers::types::Address as EthAddress; -use fastcrypto::traits::EncodeDecodeBase64; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use sui_config::Config; -use sui_sdk::SuiClient as SuiSdkClient; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, - crypto::SuiKeyPair, - event::EventID, - object::Owner, - Identifier, -}; -use tracing::info; - -use crate::{ - crypto::BridgeAuthorityKeyPair, error::BridgeError, eth_client::EthClient, - sui_client::SuiClient, types::BridgeAction, -}; - -#[serde_as] -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct BridgeNodeConfig { - /// The port that the server listens on. - pub server_listen_port: u16, - /// The port that for metrics server. - pub metrics_port: u16, - /// Path of the file where bridge authority key (Secp256k1) is stored as - /// Base64 encoded `privkey`. - pub bridge_authority_key_path_base64_raw: PathBuf, - /// Rpc url for Sui fullnode, used for query stuff and submit transactions. - pub sui_rpc_url: String, - /// Rpc url for Eth fullnode, used for query stuff. - pub eth_rpc_url: String, - /// The eth contract addresses (hex). It must not be empty. It serves two - /// purpose: - /// 1. validator only signs bridge actions that are generated from these - /// contracts. - /// 2. for EthSyncer to watch for when `run_client` is true. - pub eth_addresses: Vec, - /// Path of the file where bridge client key (any SuiKeyPair) is stored as - /// Base64 encoded `flag || privkey`. If `run_client` is true, and this - /// is None, then use `bridge_authority_key_path_base64_raw` as client key. - #[serde(skip_serializing_if = "Option::is_none")] - pub bridge_client_key_path_base64_sui_key: Option, - /// Whether to run client. If true, `bridge_client_key_path_base64_sui_key`, - /// `bridge_client_gas_object` and `db_path` needs to be provided. - pub run_client: bool, - /// The gas object to use for paying for gas fees for the client. It needs - /// to be owned by the address associated with bridge client key. - #[serde(skip_serializing_if = "Option::is_none")] - pub bridge_client_gas_object: Option, - /// Path of the client storage. Required when `run_client` is true. - #[serde(skip_serializing_if = "Option::is_none")] - pub db_path: Option, - // TODO: this should be hardcoded and removed from config - /// The sui modules of bridge packages for client to watch for. Need to - /// contain at least one item when `run_client` is true. - pub sui_bridge_modules: Option>, - // TODO: we need to hardcode the starting blocks for eth networks for cold start. - /// Override the start block number for each eth address. Key must be in - /// `eth_addresses`. When set, EthSyncer will start from this block - /// number (inclusively) instead of the one in storage. - /// Key: eth address, Value: block number to start from - /// Note: This field should be rarely used. Only use it when you understand - /// how to follow up. - #[serde(skip_serializing_if = "Option::is_none")] - pub eth_bridge_contracts_start_block_override: Option>, - /// Override the last processed EventID for each bridge module. Key must be - /// in `sui_bridge_modules`. When set, SuiSyncer will start from this - /// cursor (exclusively) instead of the one in storage. Key: sui module, - /// Value: last processed EventID (tx_digest, event_seq). Note 1: This - /// field should be rarely used. Only use it when you understand how to - /// follow up. Note 2: the EventID needs to be valid, namely it must - /// exist and matches the filter. Otherwise, it will miss one event - /// because of fullnode Event query semantics. - #[serde(skip_serializing_if = "Option::is_none")] - pub sui_bridge_modules_last_processed_event_id_override: Option>, - /// A list of approved governance actions. Action in this list will be - /// signed when requested by client. - pub approved_governance_actions: Vec, -} - -impl Config for BridgeNodeConfig {} - -impl BridgeNodeConfig { - pub async fn validate( - &self, - ) -> anyhow::Result<(BridgeServerConfig, Option)> { - let bridge_authority_key = - read_bridge_authority_key(&self.bridge_authority_key_path_base64_raw)?; - - // TODO: verify it's part of bridge committee - let sui_client = Arc::new(SuiClient::::new(&self.sui_rpc_url).await?); - - // TODO(audit-blocking): verify Sui Chain ID matches bridge Chain ID - - if self.eth_addresses.is_empty() { - return Err(anyhow!("`eth_addresses` must contain at least one address")); - } - let eth_bridge_contracts = self - .eth_addresses - .iter() - .map(|addr| EthAddress::from_str(addr)) - .collect::, _>>()?; - let eth_client = Arc::new( - EthClient::::new( - &self.eth_rpc_url, - HashSet::from_iter(eth_bridge_contracts.iter().cloned()), - ) - .await?, - ); - // TODO(audit-blocking): verify Ethereum Chain ID matches bridge Chain ID - - // Validate approved actions that must be governace actions - for action in &self.approved_governance_actions { - if !action.is_governace_action() { - return Err(anyhow::anyhow!(format!( - "{:?}", - BridgeError::ActionIsNotGovernanceAction(action.clone()) - ))); - } - } - let approved_governance_actions = self.approved_governance_actions.clone(); - - let bridge_server_config = BridgeServerConfig { - key: bridge_authority_key, - metrics_port: self.metrics_port, - server_listen_port: self.server_listen_port, - sui_client: sui_client.clone(), - eth_client: eth_client.clone(), - approved_governance_actions, - }; - - if !self.run_client { - return Ok((bridge_server_config, None)); - } - // If client is enabled, prepare client config - let bridge_client_key = if self.bridge_client_key_path_base64_sui_key.is_none() { - let bridge_client_key = - read_bridge_authority_key(&self.bridge_authority_key_path_base64_raw)?; - Ok(SuiKeyPair::from(bridge_client_key)) - } else { - read_bridge_client_key(self.bridge_client_key_path_base64_sui_key.as_ref().unwrap()) - }?; - - let client_sui_address = SuiAddress::from(&bridge_client_key.public()); - info!("Bridge client sui address: {:?}", client_sui_address); - let gas_object_id = self.bridge_client_gas_object.ok_or(anyhow!( - "`bridge_client_gas_object` is required when `run_client` is true" - ))?; - let db_path = self - .db_path - .clone() - .ok_or(anyhow!("`db_path` is required when `run_client` is true"))?; - - let mut eth_bridge_contracts_start_block_override = BTreeMap::new(); - match &self.eth_bridge_contracts_start_block_override { - Some(overrides) => { - for (addr, block_number) in overrides { - let address = EthAddress::from_str(addr)?; - if eth_bridge_contracts.contains(&address) { - eth_bridge_contracts_start_block_override.insert(address, *block_number); - } else { - return Err(anyhow!( - "Override start block number for address {:?} is not in `eth_addresses`", - addr - )); - } - } - } - None => {} - } - - let sui_bridge_modules = match &self.sui_bridge_modules { - Some(modules) => { - if modules.is_empty() { - return Err(anyhow!( - "`sui_bridge_modules` is required when `run_client` is true" - )); - } - modules - .iter() - .map(|module| Identifier::from_str(module)) - .collect::, _>>() - .map_err(|e| anyhow!("Error parsing sui module: {:?}", e))? - } - None => { - return Err(anyhow!( - "`sui_bridge_modules` is required when `run_client` is true" - )); - } - }; - - let mut sui_bridge_modules_last_processed_event_id_override = BTreeMap::new(); - match &self.sui_bridge_modules_last_processed_event_id_override { - Some(overrides) => { - for (module, cursor) in overrides { - let module = Identifier::from_str(module)?; - if sui_bridge_modules.contains(&module) { - sui_bridge_modules_last_processed_event_id_override.insert(module, *cursor); - } else { - return Err(anyhow!( - "Override start tx digest for module {:?} is not in `sui_bridge_modules`", - module - )); - } - } - } - None => {} - } - - let (gas_coin, gas_object_ref, owner) = sui_client - .get_gas_data_panic_if_not_gas(gas_object_id) - .await; - if owner != Owner::AddressOwner(client_sui_address) { - return Err(anyhow!( - "Gas object {:?} is not owned by bridge client key's associated sui address {:?}, but {:?}", - gas_object_id, - client_sui_address, - owner - )); - } - info!( - "Starting bridge client with gas object {:?}, balance: {}", - gas_object_ref.0, - gas_coin.value() - ); - let bridge_client_config = BridgeClientConfig { - sui_address: client_sui_address, - key: bridge_client_key, - gas_object_ref, - metrics_port: self.metrics_port, - sui_client: sui_client.clone(), - eth_client: eth_client.clone(), - db_path, - eth_bridge_contracts, - sui_bridge_modules, - eth_bridge_contracts_start_block_override, - sui_bridge_modules_last_processed_event_id_override, - }; - - Ok((bridge_server_config, Some(bridge_client_config))) - } -} - -pub struct BridgeServerConfig { - pub key: BridgeAuthorityKeyPair, - pub server_listen_port: u16, - pub metrics_port: u16, - pub sui_client: Arc>, - pub eth_client: Arc>, - /// A list of approved governance actions. Action in this list will be - /// signed when requested by client. - pub approved_governance_actions: Vec, -} - -// TODO: add gas balance alert threshold -pub struct BridgeClientConfig { - pub sui_address: SuiAddress, - pub key: SuiKeyPair, - pub gas_object_ref: ObjectRef, - pub metrics_port: u16, - pub sui_client: Arc>, - pub eth_client: Arc>, - pub db_path: PathBuf, - pub eth_bridge_contracts: Vec, - pub sui_bridge_modules: Vec, - pub eth_bridge_contracts_start_block_override: BTreeMap, - pub sui_bridge_modules_last_processed_event_id_override: BTreeMap, -} - -/// Read Bridge Authority key (Secp256k1KeyPair) from a file. -/// BridgeAuthority key is stored as base64 encoded `privkey`. -pub fn read_bridge_authority_key(path: &PathBuf) -> Result { - if !path.exists() { - return Err(anyhow::anyhow!( - "Bridge authority key file not found at path: {:?}", - path - )); - } - let contents = std::fs::read_to_string(path)?; - - BridgeAuthorityKeyPair::decode_base64(contents.as_str().trim()) - .map_err(|e| anyhow!("Error decoding authority key: {:?}", e)) -} - -/// Read Bridge client key (any SuiKeyPair) from a file. -/// Read from file as Base64 encoded `flag || privkey`. -pub fn read_bridge_client_key(path: &PathBuf) -> Result { - if !path.exists() { - return Err(anyhow::anyhow!( - "Bridge client key file not found at path: {:?}", - path - )); - } - let contents = std::fs::read_to_string(path)?; - - SuiKeyPair::decode_base64(contents.as_str().trim()) - .map_err(|e| anyhow!("Error decoding authority key: {:?}", e)) -} diff --git a/crates/sui-bridge/src/crypto.rs b/crates/sui-bridge/src/crypto.rs deleted file mode 100644 index 0a8b46bb7f3..00000000000 --- a/crates/sui-bridge/src/crypto.rs +++ /dev/null @@ -1,390 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt::{Debug, Display, Formatter}; - -use ethers::{ - core::k256::{ecdsa::VerifyingKey, elliptic_curve::sec1::ToEncodedPoint}, - types::Address as EthAddress, -}; -use fastcrypto::{ - encoding::{Encoding, Hex}, - error::FastCryptoError, - hash::{HashFunction, Keccak256}, - secp256k1::{ - recoverable::Secp256k1RecoverableSignature, Secp256k1KeyPair, Secp256k1PublicKey, - Secp256k1PublicKeyAsBytes, - }, - traits::{KeyPair, RecoverableSigner, ToFromBytes, VerifyRecoverable}, -}; -use serde::{Deserialize, Serialize}; -use sui_types::{base_types::ConciseableName, message_envelope::VerifiedEnvelope}; -use tap::TapFallible; - -use crate::{ - error::{BridgeError, BridgeResult}, - types::{BridgeAction, BridgeCommittee, SignedBridgeAction, VerifiedSignedBridgeAction}, -}; -pub type BridgeAuthorityKeyPair = Secp256k1KeyPair; -pub type BridgeAuthorityPublicKey = Secp256k1PublicKey; -pub type BridgeAuthorityRecoverableSignature = Secp256k1RecoverableSignature; - -#[derive(Ord, PartialOrd, PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)] -pub struct BridgeAuthorityPublicKeyBytes(Secp256k1PublicKeyAsBytes); - -impl BridgeAuthorityPublicKeyBytes { - pub fn to_eth_address(&self) -> EthAddress { - // unwrap: the conversion should not fail - let pubkey = VerifyingKey::from_sec1_bytes(self.as_bytes()).unwrap(); - let affine: ðers::core::k256::AffinePoint = pubkey.as_ref(); - let encoded = affine.to_encoded_point(false); - let pubkey = &encoded.as_bytes()[1..]; - assert_eq!(pubkey.len(), 64, "raw public key must be 64 bytes"); - let hash = Keccak256::digest(pubkey).digest; - EthAddress::from_slice(&hash[12..]) - } -} - -impl From<&BridgeAuthorityPublicKey> for BridgeAuthorityPublicKeyBytes { - fn from(pk: &BridgeAuthorityPublicKey) -> Self { - Self(Secp256k1PublicKeyAsBytes::from(pk)) - } -} - -impl ToFromBytes for BridgeAuthorityPublicKeyBytes { - /// Parse an object from its byte representation - fn from_bytes(bytes: &[u8]) -> Result { - let pk = BridgeAuthorityPublicKey::from_bytes(bytes)?; - Ok(Self::from(&pk)) - } - - /// Borrow a byte slice representing the serialized form of this object - fn as_bytes(&self) -> &[u8] { - self.as_ref() - } -} - -pub struct ConciseBridgeAuthorityPublicKeyBytesRef<'a>(&'a BridgeAuthorityPublicKeyBytes); - -impl Debug for ConciseBridgeAuthorityPublicKeyBytesRef<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - let s = Hex::encode(self.0.0.0.get(0..4).ok_or(std::fmt::Error)?); - write!(f, "k#{}..", s) - } -} - -impl Display for ConciseBridgeAuthorityPublicKeyBytesRef<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - Debug::fmt(self, f) - } -} - -impl AsRef<[u8]> for BridgeAuthorityPublicKeyBytes { - fn as_ref(&self) -> &[u8] { - self.0.0.as_ref() - } -} - -impl<'a> ConciseableName<'a> for BridgeAuthorityPublicKeyBytes { - type ConciseTypeRef = ConciseBridgeAuthorityPublicKeyBytesRef<'a>; - type ConciseType = String; - - fn concise(&'a self) -> ConciseBridgeAuthorityPublicKeyBytesRef<'a> { - ConciseBridgeAuthorityPublicKeyBytesRef(self) - } - - fn concise_owned(&self) -> String { - format!("{:?}", ConciseBridgeAuthorityPublicKeyBytesRef(self)) - } -} - -// TODO: include epoch ID here to reduce race conditions? -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] -pub struct BridgeAuthoritySignInfo { - pub authority_pub_key: BridgeAuthorityPublicKey, - pub signature: BridgeAuthorityRecoverableSignature, -} - -impl BridgeAuthoritySignInfo { - pub fn new(msg: &BridgeAction, secret: &BridgeAuthorityKeyPair) -> Self { - let msg_bytes = msg.to_bytes(); - - Self { - authority_pub_key: secret.public().clone(), - signature: secret.sign_recoverable_with_hash::(&msg_bytes), - } - } - - pub fn verify(&self, msg: &BridgeAction, committee: &BridgeCommittee) -> BridgeResult<()> { - // 1. verify committee member is in the committee and not blocklisted - if !committee.is_active_member(&self.authority_pub_key_bytes()) { - return Err(BridgeError::InvalidBridgeAuthority( - self.authority_pub_key_bytes(), - )); - } - - // 2. verify signature - let msg_bytes = msg.to_bytes(); - - self.authority_pub_key - .verify_recoverable_with_hash::(&msg_bytes, &self.signature) - .map_err(|e| { - BridgeError::InvalidBridgeAuthoritySignature(( - self.authority_pub_key_bytes(), - e.to_string(), - )) - }) - } - - pub fn authority_pub_key_bytes(&self) -> BridgeAuthorityPublicKeyBytes { - BridgeAuthorityPublicKeyBytes::from(&self.authority_pub_key) - } -} - -/// Verifies a SignedBridgeAction (response from bridge authority to bridge -/// client) represents the right BridgeAction, and is signed by the right -/// authority. -pub fn verify_signed_bridge_action( - expected_action: &BridgeAction, - signed_action: SignedBridgeAction, - expected_signer: &BridgeAuthorityPublicKeyBytes, - committee: &BridgeCommittee, -) -> BridgeResult { - if signed_action.data() != expected_action { - return Err(BridgeError::MismatchedAction); - } - - let sig = signed_action.auth_sig(); - if &sig.authority_pub_key_bytes() != expected_signer { - return Err(BridgeError::MismatchedAuthoritySigner); - } - sig.verify(signed_action.data(), committee).tap_err(|e| { - tracing::error!( - "Failed to verify SignedBridgeEvent {:?}. Error {:?}", - signed_action, - e - ) - })?; - Ok(VerifiedEnvelope::new_from_verified(signed_action)) -} - -#[cfg(test)] -mod tests { - use std::{str::FromStr, sync::Arc}; - - use ethers::types::Address as EthAddress; - use fastcrypto::traits::{KeyPair, ToFromBytes}; - use prometheus::Registry; - use sui_types::{base_types::SuiAddress, crypto::get_key_pair, digests::TransactionDigest}; - - use super::*; - use crate::{ - events::EmittedSuiToEthTokenBridgeV1, - test_utils::{get_test_authority_and_key, get_test_sui_to_eth_bridge_action}, - types::{ - BridgeAction, BridgeAuthority, BridgeChainId, SignedBridgeAction, SuiToEthBridgeAction, - TokenId, - }, - }; - - #[test] - fn test_sign_and_verify_bridge_event_basic() -> anyhow::Result<()> { - telemetry_subscribers::init_for_testing(); - let registry = Registry::new(); - mysten_metrics::init_metrics(®istry); - - let (mut authority1, pubkey, secret) = get_test_authority_and_key(5000, 9999); - let pubkey_bytes = BridgeAuthorityPublicKeyBytes::from(&pubkey); - - let (authority2, pubkey2, _secret) = get_test_authority_and_key(5000, 9999); - let pubkey_bytes2 = BridgeAuthorityPublicKeyBytes::from(&pubkey2); - - let committee = BridgeCommittee::new(vec![authority1.clone(), authority2.clone()]).unwrap(); - - let action: BridgeAction = - get_test_sui_to_eth_bridge_action(None, Some(1), Some(1), Some(100)); - - let sig = BridgeAuthoritySignInfo::new(&action, &secret); - - let signed_action = SignedBridgeAction::new_from_data_and_sig(action.clone(), sig.clone()); - - // Verification should succeed - let _ = - verify_signed_bridge_action(&action, signed_action.clone(), &pubkey_bytes, &committee) - .unwrap(); - - // Verification should fail - mismatched signer - assert!(matches!( - verify_signed_bridge_action(&action, signed_action.clone(), &pubkey_bytes2, &committee) - .unwrap_err(), - BridgeError::MismatchedAuthoritySigner - )); - - let mismatched_action: BridgeAction = - get_test_sui_to_eth_bridge_action(None, Some(2), Some(3), Some(4)); - // Verification should fail - mismatched action - assert!(matches!( - verify_signed_bridge_action( - &mismatched_action, - signed_action.clone(), - &pubkey_bytes2, - &committee - ) - .unwrap_err(), - BridgeError::MismatchedAction, - )); - - // Signature is invalid (signed over different message), verification should - // fail - let action2: BridgeAction = - get_test_sui_to_eth_bridge_action(None, Some(3), Some(5), Some(77)); - - let invalid_sig = BridgeAuthoritySignInfo::new(&action2, &secret); - let signed_action = SignedBridgeAction::new_from_data_and_sig(action.clone(), invalid_sig); - let _ = verify_signed_bridge_action(&action, signed_action, &pubkey_bytes, &committee) - .unwrap_err(); - - // Signer is not in committee, verification should fail - let (_, kp2): (_, fastcrypto::secp256k1::Secp256k1KeyPair) = get_key_pair(); - let pubkey_bytes_2 = BridgeAuthorityPublicKeyBytes::from(kp2.public()); - let secret2 = Arc::pin(kp2); - let sig2 = BridgeAuthoritySignInfo::new(&action, &secret2); - let signed_action2 = SignedBridgeAction::new_from_data_and_sig(action.clone(), sig2); - let _ = verify_signed_bridge_action(&action, signed_action2, &pubkey_bytes_2, &committee) - .unwrap_err(); - - // Authority is blocklisted, verification should fail - authority1.is_blocklisted = true; - let committee = BridgeCommittee::new(vec![authority1, authority2]).unwrap(); - let signed_action = SignedBridgeAction::new_from_data_and_sig(action.clone(), sig); - let _ = verify_signed_bridge_action(&action, signed_action, &pubkey_bytes, &committee) - .unwrap_err(); - - Ok(()) - } - - #[test] - fn test_bridge_sig_verification_regression_test() { - telemetry_subscribers::init_for_testing(); - let registry = Registry::new(); - mysten_metrics::init_metrics(®istry); - - let public_key_bytes = - Hex::decode("02321ede33d2c2d7a8a152f275a1484edef2098f034121a602cb7d767d38680aa4") - .unwrap(); - let pubkey1 = BridgeAuthorityPublicKey::from_bytes(&public_key_bytes).unwrap(); - let authority1 = BridgeAuthority { - pubkey: pubkey1.clone(), - voting_power: 2500, - is_blocklisted: false, - base_url: "".into(), - }; - - let public_key_bytes = - Hex::decode("027f1178ff417fc9f5b8290bd8876f0a157a505a6c52db100a8492203ddd1d4279") - .unwrap(); - let pubkey2 = BridgeAuthorityPublicKey::from_bytes(&public_key_bytes).unwrap(); - let authority2 = BridgeAuthority { - pubkey: pubkey2.clone(), - voting_power: 2500, - is_blocklisted: false, - base_url: "".into(), - }; - - let public_key_bytes = - Hex::decode("026f311bcd1c2664c14277c7a80e4857c690626597064f89edc33b8f67b99c6bc0") - .unwrap(); - let pubkey3 = BridgeAuthorityPublicKey::from_bytes(&public_key_bytes).unwrap(); - let authority3 = BridgeAuthority { - pubkey: pubkey3.clone(), - voting_power: 2500, - is_blocklisted: false, - base_url: "".into(), - }; - - let public_key_bytes = - Hex::decode("03a57b85771aedeb6d31c808be9a6e73194e4b70e679608f2bca68bcc684773736") - .unwrap(); - let pubkey4 = BridgeAuthorityPublicKey::from_bytes(&public_key_bytes).unwrap(); - let authority4 = BridgeAuthority { - pubkey: pubkey4.clone(), - voting_power: 2500, - is_blocklisted: false, - base_url: "".into(), - }; - - let committee = BridgeCommittee::new(vec![ - authority1.clone(), - authority2.clone(), - authority3.clone(), - authority4.clone(), - ]) - .unwrap(); - - let action = BridgeAction::SuiToEthBridgeAction(SuiToEthBridgeAction { - sui_tx_digest: TransactionDigest::random(), - sui_tx_event_index: 0, - sui_bridge_event: EmittedSuiToEthTokenBridgeV1 { - nonce: 1, - sui_chain_id: BridgeChainId::SuiTestnet, - sui_address: SuiAddress::from_str( - "0x80ab1ee086210a3a37355300ca24672e81062fcdb5ced6618dab203f6a3b291c", - ) - .unwrap(), - eth_chain_id: BridgeChainId::EthSepolia, - eth_address: EthAddress::from_str("0xb18f79Fe671db47393315fFDB377Da4Ea1B7AF96") - .unwrap(), - token_id: TokenId::ETH, - amount: 100000u64, - }, - }); - let sig = BridgeAuthoritySignInfo { - authority_pub_key: pubkey1, - signature: BridgeAuthorityRecoverableSignature::from_bytes( - &Hex::decode("e1cf11b380855ff1d4a451ebc2fd68477cf701b7d4ec88da3082709fe95201a5061b4b60cf13815a80ba9dfead23e220506aa74c4a863ba045d95715b4cc6b6e00").unwrap(), - ).unwrap(), - }; - sig.verify(&action, &committee).unwrap(); - - let sig = BridgeAuthoritySignInfo { - authority_pub_key: pubkey4.clone(), - signature: BridgeAuthorityRecoverableSignature::from_bytes( - &Hex::decode("8ba9ec92c2d5a44ecc123182f689b901a93921fd35f581354fea20b25a0ded6d055b96a64bdda77dd5a62b93d29abe93640aa3c1a136348093cd7a2418c6bfa301").unwrap(), - ).unwrap(), - }; - sig.verify(&action, &committee).unwrap(); - - let sig = BridgeAuthoritySignInfo { - authority_pub_key: pubkey4, - signature: BridgeAuthorityRecoverableSignature::from_bytes( - // invalid sdig - &Hex::decode("8ba9ec92c2d5a44ecc123182f689b901a93921fd35f581354fea20b25a0ded6d055b96a64bdda77dd5a62b93d29abe93640aa3c1a136348093cd7a2418c6bfa302").unwrap(), - ).unwrap(), - }; - sig.verify(&action, &committee).unwrap_err(); - } - - #[test] - fn test_bridge_authority_public_key_bytes_to_eth_address() { - let pub_key_bytes = BridgeAuthorityPublicKeyBytes::from_bytes( - &Hex::decode("02321ede33d2c2d7a8a152f275a1484edef2098f034121a602cb7d767d38680aa4") - .unwrap(), - ) - .unwrap(); - let addr = "0x68b43fd906c0b8f024a18c56e06744f7c6157c65" - .parse::() - .unwrap(); - assert_eq!(pub_key_bytes.to_eth_address(), addr); - - // Example from: https://github.com/gakonst/ethers-rs/blob/master/ethers-core/src/utils/mod.rs#L1235 - let pub_key_bytes = BridgeAuthorityPublicKeyBytes::from_bytes( - &Hex::decode("0376698beebe8ee5c74d8cc50ab84ac301ee8f10af6f28d0ffd6adf4d6d3b9b762") - .unwrap(), - ) - .unwrap(); - let addr = "0Ac1dF02185025F65202660F8167210A80dD5086" - .parse::() - .unwrap(); - assert_eq!(pub_key_bytes.to_eth_address(), addr); - } -} diff --git a/crates/sui-bridge/src/error.rs b/crates/sui-bridge/src/error.rs deleted file mode 100644 index 7f1242f9c75..00000000000 --- a/crates/sui-bridge/src/error.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use crate::{crypto::BridgeAuthorityPublicKeyBytes, types::BridgeAction}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum BridgeError { - // The input is not an invalid transaction digest/hash - InvalidTxHash, - // The referenced transaction failed - OriginTxFailed, - // The referenced transction does not exist - TxNotFound, - // Tx is not yet finalized - TxNotFinalized, - // No recognized bridge event in specified transaction and event position - NoBridgeEventsInTxPosition, - // Found a bridge event but not in a recognized Eth bridge contract - BridgeEventInUnrecognizedEthContract, - // Found a bridge event but not in a recognized Sui bridge package - BridgeEventInUnrecognizedSuiPackage, - // Found BridgeEvent but not BridgeAction - BridgeEventNotActionable, - // Failure to serialize - BridgeSerializationError(String), - // Internal Bridge error - InternalError(String), - // Authority signature duplication - AuthoritySignatureDuplication(String), - // Too many errors when aggregating authority signatures - AuthoritySignatureAggregationTooManyError(String), - // Transient Ethereum provider error - TransientProviderError(String), - // Ethereum provider error - ProviderError(String), - // Invalid BridgeCommittee - InvalidBridgeCommittee(String), - // Invalid Bridge authority signature - InvalidBridgeAuthoritySignature((BridgeAuthorityPublicKeyBytes, String)), - // Entity is not in the Bridge committee or is blocklisted - InvalidBridgeAuthority(BridgeAuthorityPublicKeyBytes), - // Authority's base_url is invalid - InvalidAuthorityUrl(BridgeAuthorityPublicKeyBytes), - // Invalid Bridge Client request - InvalidBridgeClientRequest(String), - // Message is signed by mismatched authority - MismatchedAuthoritySigner, - // Signature is over a mismatched action - MismatchedAction, - // Action is not a governance action - ActionIsNotGovernanceAction(BridgeAction), - // Client requested an non-approved governace action - GovernanceActionIsNotApproved, - // Authority has invalid url - AuthoirtyUrlInvalid, - // Action is not token transfer - ActionIsNotTokenTransferAction, - // Sui transaction failure due to generic error - SuiTxFailureGeneric(String), - // Storage Error - StorageError(String), - // Rest API Error - RestAPIError(String), - // Uncategorized error - Generic(String), -} - -pub type BridgeResult = Result; diff --git a/crates/sui-bridge/src/events.rs b/crates/sui-bridge/src/events.rs deleted file mode 100644 index c21c3d52de1..00000000000 --- a/crates/sui-bridge/src/events.rs +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//! This file contains the definition of the SuiBridgeEvent enum, of -//! which each variant is an emitted Event struct defind in the Move -//! Bridge module. We rely on structures in this file to decode -//! the bcs content of the emitted events. - -use std::str::FromStr; - -use ethers::types::Address as EthAddress; -use fastcrypto::encoding::{Encoding, Hex}; -use move_core_types::language_storage::StructTag; -use once_cell::sync::OnceCell; -use serde::{Deserialize, Serialize}; -use sui_json_rpc_types::SuiEvent; -use sui_types::{base_types::SuiAddress, digests::TransactionDigest}; - -use crate::{ - error::{BridgeError, BridgeResult}, - sui_transaction_builder::get_bridge_package_id, - types::{BridgeAction, BridgeActionType, BridgeChainId, SuiToEthBridgeAction, TokenId}, -}; - -// This is the event structure defined and emitted in Move -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] -pub struct MoveTokenBridgeEvent { - pub message_type: u8, - pub seq_num: u64, - pub source_chain: u8, - pub sender_address: Vec, - pub target_chain: u8, - pub target_address: Vec, - pub token_type: u8, - pub amount: u64, -} - -// Sanitized version of MoveTokenBridgeEvent -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Hash)] -pub struct EmittedSuiToEthTokenBridgeV1 { - pub nonce: u64, - pub sui_chain_id: BridgeChainId, - pub eth_chain_id: BridgeChainId, - pub sui_address: SuiAddress, - pub eth_address: EthAddress, - pub token_id: TokenId, - pub amount: u64, -} - -impl TryFrom for EmittedSuiToEthTokenBridgeV1 { - type Error = BridgeError; - - fn try_from(event: MoveTokenBridgeEvent) -> BridgeResult { - if event.message_type != BridgeActionType::TokenTransfer as u8 { - return Err(BridgeError::Generic(format!( - "Failed to convert MoveTokenBridgeEvent to EmittedSuiToEthTokenBridgeV1. Expected message type {}, got {}", - BridgeActionType::TokenTransfer as u8, - event.message_type - ))); - } - let token_id = TokenId::try_from(event.token_type).map_err(|_e| { - BridgeError::Generic(format!( - "Failed to convert MoveTokenBridgeEvent to EmittedSuiToEthTokenBridgeV1. Failed to convert token type {} to TokenId", - event.token_type, - )) - })?; - - let sui_chain_id = BridgeChainId::try_from(event.source_chain).map_err(|_e| { - BridgeError::Generic(format!( - "Failed to convert MoveTokenBridgeEvent to EmittedSuiToEthTokenBridgeV1. Failed to convert source chain {} to BridgeChainId", - event.token_type, - )) - })?; - let eth_chain_id = BridgeChainId::try_from(event.target_chain).map_err(|_e| { - BridgeError::Generic(format!( - "Failed to convert MoveTokenBridgeEvent to EmittedSuiToEthTokenBridgeV1. Failed to convert target chain {} to BridgeChainId", - event.token_type, - )) - })?; - - match sui_chain_id { - BridgeChainId::SuiMainnet - | BridgeChainId::SuiTestnet - | BridgeChainId::SuiDevnet - | BridgeChainId::SuiLocalTest => {} - _ => { - return Err(BridgeError::Generic(format!( - "Failed to convert MoveTokenBridgeEvent to EmittedSuiToEthTokenBridgeV1. Invalid source chain {}", - event.source_chain - ))); - } - } - match eth_chain_id { - BridgeChainId::EthMainnet | BridgeChainId::EthSepolia | BridgeChainId::EthLocalTest => { - } - _ => { - return Err(BridgeError::Generic(format!( - "Failed to convert MoveTokenBridgeEvent to EmittedSuiToEthTokenBridgeV1. Invalid target chain {}", - event.target_chain - ))); - } - } - - let sui_address = SuiAddress::from_bytes(event.sender_address) - .map_err(|e| BridgeError::Generic(format!("Failed to convert MoveTokenBridgeEvent to EmittedSuiToEthTokenBridgeV1. Failed to convert sender_address to SuiAddress: {:?}", e)))?; - let eth_address = EthAddress::from_str(&Hex::encode(&event.target_address))?; - - Ok(Self { - nonce: event.seq_num, - sui_chain_id, - eth_chain_id, - sui_address, - eth_address, - token_id, - amount: event.amount, - }) - } -} - -// TODO: update this once we have bridge package on sui framework -pub fn get_bridge_event_struct_tag() -> &'static str { - static BRIDGE_EVENT_STRUCT_TAG: OnceCell = OnceCell::new(); - BRIDGE_EVENT_STRUCT_TAG.get_or_init(|| { - let bridge_package_id = *get_bridge_package_id(); - format!("0x{}::bridge::TokenBridgeEvent", bridge_package_id.to_hex()) - }) -} - -crate::declare_events!( - SuiToEthTokenBridgeV1(EmittedSuiToEthTokenBridgeV1) => (get_bridge_event_struct_tag(), MoveTokenBridgeEvent) - // Add new event types here. Format: EnumVariantName(Struct) => ("StructTagString", CorrespondingMoveStruct) -); - -#[macro_export] -macro_rules! declare_events { - ($($variant:ident($type:path) => ($event_tag:expr, $event_struct:path)),* $(,)?) => { - - #[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)] - pub enum SuiBridgeEvent { - $($variant($type),)* - } - - #[allow(non_upper_case_globals)] - $(pub(crate) static $variant: OnceCell = OnceCell::new();)* - - pub(crate) fn init_all_struct_tags() { - $($variant.get_or_init(|| { - StructTag::from_str($event_tag).unwrap() - });)* - } - - // Try to convert a SuiEvent into SuiBridgeEvent - impl SuiBridgeEvent { - pub fn try_from_sui_event(event: &SuiEvent) -> BridgeResult> { - init_all_struct_tags(); // Ensure all tags are initialized - - // Unwrap safe: we inited above - $( - if &event.type_ == $variant.get().unwrap() { - let event_struct: $event_struct = bcs::from_bytes(&event.bcs).map_err(|e| BridgeError::InternalError(format!("Failed to deserialize event to {}: {:?}", stringify!($event_struct), e)))?; - return Ok(Some(SuiBridgeEvent::$variant(event_struct.try_into()?))); - } - )* - Ok(None) - } - } - }; -} - -impl SuiBridgeEvent { - pub fn try_into_bridge_action( - self, - sui_tx_digest: TransactionDigest, - sui_tx_event_index: u16, - ) -> Option { - match self { - SuiBridgeEvent::SuiToEthTokenBridgeV1(event) => { - Some(BridgeAction::SuiToEthBridgeAction(SuiToEthBridgeAction { - sui_tx_digest, - sui_tx_event_index, - sui_bridge_event: event.clone(), - })) - } - } - } -} - -#[cfg(test)] -pub mod tests { - use std::str::FromStr; - - use ethers::types::Address as EthAddress; - use move_core_types::language_storage::StructTag; - use sui_json_rpc_types::SuiEvent; - use sui_types::{ - base_types::{ObjectID, SuiAddress}, - digests::TransactionDigest, - event::EventID, - Identifier, - }; - - use super::{get_bridge_event_struct_tag, EmittedSuiToEthTokenBridgeV1, MoveTokenBridgeEvent}; - use crate::types::{ - BridgeAction, BridgeActionType, BridgeChainId, SuiToEthBridgeAction, TokenId, - }; - - /// Returns a test SuiEvent and corresponding BridgeAction - pub fn get_test_sui_event_and_action(identifier: Identifier) -> (SuiEvent, BridgeAction) { - let sanitized_event = EmittedSuiToEthTokenBridgeV1 { - nonce: 1, - sui_chain_id: BridgeChainId::SuiTestnet, - sui_address: SuiAddress::random_for_testing_only(), - eth_chain_id: BridgeChainId::EthSepolia, - eth_address: EthAddress::random(), - token_id: TokenId::Sui, - amount: 100, - }; - let emitted_event = MoveTokenBridgeEvent { - message_type: BridgeActionType::TokenTransfer as u8, - seq_num: sanitized_event.nonce, - source_chain: sanitized_event.sui_chain_id as u8, - sender_address: sanitized_event.sui_address.to_vec(), - target_chain: sanitized_event.eth_chain_id as u8, - target_address: sanitized_event.eth_address.as_bytes().to_vec(), - token_type: sanitized_event.token_id as u8, - amount: sanitized_event.amount, - }; - - let tx_digest = TransactionDigest::random(); - let event_idx = 10u16; - let bridge_action = BridgeAction::SuiToEthBridgeAction(SuiToEthBridgeAction { - sui_tx_digest: tx_digest, - sui_tx_event_index: event_idx, - sui_bridge_event: sanitized_event.clone(), - }); - let event = SuiEvent { - // For this test to pass, match what is in events.rs - type_: StructTag::from_str(get_bridge_event_struct_tag()).unwrap(), - bcs: bcs::to_bytes(&emitted_event).unwrap(), - id: EventID { - tx_digest, - event_seq: event_idx as u64, - }, - - // The following fields do not matter as of writing, - // but if tests start to fail, it's worth checking these fields. - package_id: ObjectID::ZERO, - transaction_module: identifier.clone(), - sender: SuiAddress::random_for_testing_only(), - parsed_json: serde_json::json!({"test": "test"}), - timestamp_ms: None, - }; - (event, bridge_action) - } -} diff --git a/crates/sui-bridge/src/lib.rs b/crates/sui-bridge/src/lib.rs deleted file mode 100644 index 58266c4e9f8..00000000000 --- a/crates/sui-bridge/src/lib.rs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod abi; -pub mod action_executor; -pub mod client; -pub mod config; -pub mod crypto; -pub mod error; -pub mod eth_client; -pub mod eth_syncer; -pub mod events; -pub mod node; -pub mod orchestrator; -pub mod server; -pub mod storage; -pub mod sui_client; -pub mod sui_syncer; -pub mod sui_transaction_builder; -pub mod types; - -#[cfg(test)] -pub(crate) mod eth_mock_provider; - -#[cfg(test)] -pub(crate) mod sui_mock_client; - -#[cfg(test)] -pub(crate) mod test_utils; - -#[macro_export] -macro_rules! retry_with_max_elapsed_time { - ($func:expr, $max_elapsed_time:expr) => {{ - // The following delay sequence (in secs) will be used, applied with jitter - // 0.1, 0.2, 0.4, 0.8, 1.6, 3.2, 6.4, 12.8, 25.6, 30, 30, 30 ... - let backoff = backoff::ExponentialBackoff { - initial_interval: Duration::from_millis(100), - randomization_factor: 0.1, - multiplier: 2.0, - max_interval: Duration::from_secs(30), - max_elapsed_time: Some($max_elapsed_time), - ..Default::default() - }; - backoff::future::retry(backoff, || { - let fut = async { - let result = $func.await; - match result { - Ok(_) => { - return Ok(result); - } - Err(e) => { - // For simplicity we treat every error as transient so we can retry until - // max_elapsed_time - tracing::debug!("Retrying due to error: {:?}", e); - return Err(backoff::Error::transient(e)); - } - } - }; - std::boxed::Box::pin(fut) - }) - .await - }}; -} - -#[cfg(test)] -mod tests { - use std::time::Duration; - - use super::*; - - async fn example_func_ok() -> anyhow::Result<()> { - Ok(()) - } - - async fn example_func_err() -> anyhow::Result<()> { - Err(anyhow::anyhow!("")) - } - - #[tokio::test] - async fn test_retry_with_max_elapsed_time() { - // no retry is needed, should return immediately. We give it a very small - // max_elapsed_time and it should still finish in time. - let max_elapsed_time = Duration::from_millis(20); - retry_with_max_elapsed_time!(example_func_ok(), max_elapsed_time) - .unwrap() - .unwrap(); - - // now call a function that always errors and expect it to return before - // max_elapsed_time runs out - let max_elapsed_time = Duration::from_secs(4); - let instant = std::time::Instant::now(); - retry_with_max_elapsed_time!(example_func_err(), max_elapsed_time).unwrap_err(); - assert!(instant.elapsed() < max_elapsed_time); - } -} diff --git a/crates/sui-bridge/src/main.rs b/crates/sui-bridge/src/main.rs deleted file mode 100644 index c024fd83055..00000000000 --- a/crates/sui-bridge/src/main.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - net::{IpAddr, Ipv4Addr, SocketAddr}, - path::PathBuf, -}; - -use clap::Parser; -use mysten_metrics::start_prometheus_server; -use sui_bridge::{config::BridgeNodeConfig, node::run_bridge_node}; -use sui_config::Config; -use tracing::info; - -// TODO consolidate this with sui-node/src/main.rs, but where to put it? -const GIT_REVISION: &str = { - if let Some(revision) = option_env!("GIT_REVISION") { - revision - } else { - let version = git_version::git_version!( - args = ["--always", "--abbrev=12", "--dirty", "--exclude", "*"], - fallback = "" - ); - - if version.is_empty() { - panic!("unable to query git revision"); - } - version - } -}; -const VERSION: &str = const_str::concat!(env!("CARGO_PKG_VERSION"), "-", GIT_REVISION); - -#[derive(Parser)] -#[clap(rename_all = "kebab-case")] -#[clap(name = env!("CARGO_BIN_NAME"))] -#[clap(version = VERSION)] -struct Args { - #[clap(long)] - pub config_path: PathBuf, -} - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - let args = Args::parse(); - let config = BridgeNodeConfig::load(&args.config_path).unwrap(); - - // Init metrics server - let metrics_address = - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), config.metrics_port); - let registry_service = start_prometheus_server(metrics_address); - let prometheus_registry = registry_service.default_registry(); - mysten_metrics::init_metrics(&prometheus_registry); - info!("Metrics server started at port {}", config.metrics_port); - - // Init logging - let (_guard, _filter_handle) = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .with_prom_registry(&prometheus_registry) - .init(); - - run_bridge_node(config).await -} diff --git a/crates/sui-bridge/src/node.rs b/crates/sui-bridge/src/node.rs deleted file mode 100644 index f09778cc32b..00000000000 --- a/crates/sui-bridge/src/node.rs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::HashMap, - net::{IpAddr, Ipv4Addr, SocketAddr}, - sync::Arc, - time::Duration, -}; - -use tokio::task::JoinHandle; -use tracing::info; - -use crate::{ - action_executor::BridgeActionExecutor, - client::bridge_authority_aggregator::BridgeAuthorityAggregator, - config::{BridgeClientConfig, BridgeNodeConfig}, - eth_syncer::EthSyncer, - orchestrator::BridgeOrchestrator, - server::{handler::BridgeRequestHandler, run_server}, - storage::BridgeOrchestratorTables, - sui_syncer::SuiSyncer, -}; - -pub async fn run_bridge_node(config: BridgeNodeConfig) -> anyhow::Result<()> { - let (server_config, client_config) = config.validate().await?; - - // Start Client - let _handles = if let Some(client_config) = client_config { - start_client_components(client_config).await - } else { - Ok(vec![]) - }?; - - // Start Server - let socket_address = SocketAddr::new( - IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), - server_config.server_listen_port, - ); - run_server( - &socket_address, - BridgeRequestHandler::new( - server_config.key, - server_config.sui_client, - server_config.eth_client, - server_config.approved_governance_actions, - ), - ) - .await; - - Ok(()) -} - -// TODO: is there a way to clean up the overrides after it's stored in DB? -async fn start_client_components( - client_config: BridgeClientConfig, -) -> anyhow::Result>> { - let store: std::sync::Arc = - BridgeOrchestratorTables::new(&client_config.db_path.join("client")); - let stored_module_cursors = store - .get_sui_event_cursors(&client_config.sui_bridge_modules) - .map_err(|e| anyhow::anyhow!("Unable to get sui event cursors from storage: {e:?}"))?; - let mut sui_modules_to_watch = HashMap::new(); - for (module, cursor) in client_config - .sui_bridge_modules - .iter() - .zip(stored_module_cursors) - { - if client_config - .sui_bridge_modules_last_processed_event_id_override - .contains_key(module) - { - sui_modules_to_watch.insert( - module.clone(), - client_config.sui_bridge_modules_last_processed_event_id_override[module], - ); - info!( - "Overriding cursor for sui bridge module {} to {:?}. Stored cursor: {:?}", - module, - client_config.sui_bridge_modules_last_processed_event_id_override[module], - cursor - ); - } else if let Some(cursor) = cursor { - sui_modules_to_watch.insert(module.clone(), cursor); - } else { - return Err(anyhow::anyhow!( - "No cursor found for sui bridge module {} in storage or config override", - module - )); - } - } - - let stored_eth_cursors = store - .get_eth_event_cursors(&client_config.eth_bridge_contracts) - .map_err(|e| anyhow::anyhow!("Unable to get eth event cursors from storage: {e:?}"))?; - let mut eth_contracts_to_watch = HashMap::new(); - for (contract, cursor) in client_config - .eth_bridge_contracts - .iter() - .zip(stored_eth_cursors) - { - if client_config - .eth_bridge_contracts_start_block_override - .contains_key(contract) - { - eth_contracts_to_watch.insert( - *contract, - client_config.eth_bridge_contracts_start_block_override[contract], - ); - info!( - "Overriding cursor for eth bridge contract {} to {}. Stored cursor: {:?}", - contract, client_config.eth_bridge_contracts_start_block_override[contract], cursor - ); - } else if let Some(cursor) = cursor { - // +1: The stored value is the last block that was processed, so we start from - // the next block. - eth_contracts_to_watch.insert(*contract, cursor + 1); - } else { - return Err(anyhow::anyhow!( - "No cursor found for eth contract {} in storage or config override", - contract - )); - } - } - - let sui_client = client_config.sui_client.clone(); - - let mut all_handles = vec![]; - let (task_handles, eth_events_rx, _) = - EthSyncer::new(client_config.eth_client.clone(), eth_contracts_to_watch) - .run() - .await - .expect("Failed to start eth syncer"); - all_handles.extend(task_handles); - - let (task_handles, sui_events_rx) = - SuiSyncer::new(client_config.sui_client, sui_modules_to_watch) - .run(Duration::from_secs(2)) - .await - .expect("Failed to start sui syncer"); - all_handles.extend(task_handles); - - let committee = Arc::new( - sui_client - .get_bridge_committee() - .await - .expect("Failed to get committee"), - ); - let bridge_auth_agg = BridgeAuthorityAggregator::new(committee); - - let bridge_action_executor = BridgeActionExecutor::new( - sui_client.clone(), - Arc::new(bridge_auth_agg), - store.clone(), - client_config.key, - client_config.sui_address, - client_config.gas_object_ref.0, - ); - - let orchestrator = - BridgeOrchestrator::new(sui_client, sui_events_rx, eth_events_rx, store.clone()); - - all_handles.extend(orchestrator.run(bridge_action_executor)); - Ok(all_handles) -} diff --git a/crates/sui-bridge/src/orchestrator.rs b/crates/sui-bridge/src/orchestrator.rs deleted file mode 100644 index 4c8197e94bd..00000000000 --- a/crates/sui-bridge/src/orchestrator.rs +++ /dev/null @@ -1,422 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//! `BridgeOrchestrator` is the component that: -//! 1. monitors Sui and Ethereum events with the help of `SuiSyncer` and -//! `EthSyncer` -//! 2. updates WAL table and cursor tables -//! 2. hands actions to `BridgeExecutor` for execution - -use std::sync::Arc; - -use ethers::types::Address as EthAddress; -use mysten_metrics::spawn_logged_monitored_task; -use sui_json_rpc_types::SuiEvent; -use sui_types::Identifier; -use tokio::task::JoinHandle; -use tracing::{info, warn}; - -use crate::{ - abi::EthBridgeEvent, - action_executor::{ - submit_to_executor, BridgeActionExecutionWrapper, BridgeActionExecutorTrait, - }, - error::BridgeResult, - events::SuiBridgeEvent, - storage::BridgeOrchestratorTables, - sui_client::{SuiClient, SuiClientInner}, - types::EthLog, -}; - -pub struct BridgeOrchestrator { - _sui_client: Arc>, - sui_events_rx: mysten_metrics::metered_channel::Receiver<(Identifier, Vec)>, - eth_events_rx: mysten_metrics::metered_channel::Receiver<(EthAddress, u64, Vec)>, - store: Arc, -} - -impl BridgeOrchestrator -where - C: SuiClientInner + 'static, -{ - pub fn new( - sui_client: Arc>, - sui_events_rx: mysten_metrics::metered_channel::Receiver<(Identifier, Vec)>, - eth_events_rx: mysten_metrics::metered_channel::Receiver<(EthAddress, u64, Vec)>, - store: Arc, - ) -> Self { - Self { - _sui_client: sui_client, - sui_events_rx, - eth_events_rx, - store, - } - } - - pub fn run( - self, - bridge_action_executor: impl BridgeActionExecutorTrait, - ) -> Vec> { - tracing::info!("Starting BridgeOrchestrator"); - let mut task_handles = vec![]; - let store_clone = self.store.clone(); - - // Spawn BridgeActionExecutor - let (handles, executor_sender) = bridge_action_executor.run(); - task_handles.extend(handles); - let executor_sender_clone = executor_sender.clone(); - task_handles.push(spawn_logged_monitored_task!(Self::run_sui_watcher( - store_clone, - executor_sender_clone, - self.sui_events_rx, - ))); - let store_clone = self.store.clone(); - task_handles.push(spawn_logged_monitored_task!(Self::run_eth_watcher( - store_clone, - executor_sender, - self.eth_events_rx, - ))); - // TODO: spawn bridge committee change watcher task - task_handles - } - - async fn run_sui_watcher( - store: Arc, - executor_tx: mysten_metrics::metered_channel::Sender, - mut sui_events_rx: mysten_metrics::metered_channel::Receiver<(Identifier, Vec)>, - ) { - info!("Starting sui watcher task"); - while let Some((identifier, events)) = sui_events_rx.recv().await { - if events.is_empty() { - continue; - } - - // TODO: skip events that are already processed (in DB and on chain) - - let bridge_events = events - .iter() - .map(SuiBridgeEvent::try_from_sui_event) - .collect::>>() - .expect("Sui Event could not be deserialzed to SuiBridgeEvent"); - - let mut actions = vec![]; - for (sui_event, opt_bridge_event) in events.iter().zip(bridge_events) { - if opt_bridge_event.is_none() { - // TODO: we probably should not miss any events, warn for now. - warn!("Sui event not recognized: {:?}", sui_event); - continue; - } - // Unwrap safe: checked above - let bridge_event: SuiBridgeEvent = opt_bridge_event.unwrap(); - - if let Some(action) = bridge_event - .try_into_bridge_action(sui_event.id.tx_digest, sui_event.id.event_seq as u16) - { - actions.push(action); - } - // TODO: handle non Action events - } - - if !actions.is_empty() { - // Write action to pending WAL - store - .insert_pending_actions(&actions) - .expect("Store operation should not fail"); - for action in actions { - submit_to_executor(&executor_tx, action) - .await - .expect("Submit to executor should not fail"); - } - } - - // Unwrap safe: in the beginning of the loop we checked that events is not empty - let cursor = events.last().unwrap().id; - store - .update_sui_event_cursor(identifier, cursor) - .expect("Store operation should not fail"); - } - panic!("Sui event channel was closed"); - } - - async fn run_eth_watcher( - store: Arc, - executor_tx: mysten_metrics::metered_channel::Sender, - mut eth_events_rx: mysten_metrics::metered_channel::Receiver<( - ethers::types::Address, - u64, - Vec, - )>, - ) { - info!("Starting eth watcher task"); - while let Some((contract, end_block, logs)) = eth_events_rx.recv().await { - if logs.is_empty() { - store - .update_eth_event_cursor(contract, end_block) - .expect("Store operation should not fail"); - continue; - } - - // TODO: skip events that are not already processed (in DB and on chain) - let bridge_events = logs - .iter() - .map(EthBridgeEvent::try_from_eth_log) - .collect::>(); - - let mut actions = vec![]; - for (log, opt_bridge_event) in logs.iter().zip(bridge_events) { - if opt_bridge_event.is_none() { - // TODO: we probably should not miss any events, warn for now. - warn!("Eth event not recognized: {:?}", log); - continue; - } - // Unwrap safe: checked above - let bridge_event = opt_bridge_event.unwrap(); - - if let Some(action) = - bridge_event.try_into_bridge_action(log.tx_hash, log.log_index_in_tx) - { - actions.push(action); - } - // TODO: handle non Action events - } - if !actions.is_empty() { - // Write action to pending WAL - store - .insert_pending_actions(&actions) - .expect("Store operation should not fail"); - // Execution will remove the pending actions from DB when the action is - // completed. - for action in actions { - submit_to_executor(&executor_tx, action) - .await - .expect("Submit to executor should not fail"); - } - } - - store - .update_eth_event_cursor(contract, end_block) - .expect("Store operation should not fail"); - } - panic!("Eth event channel was closed"); - } -} - -#[cfg(test)] -mod tests { - use std::str::FromStr; - - use ethers::types::{Address as EthAddress, TxHash}; - use prometheus::Registry; - - use super::*; - use crate::{ - events::tests::get_test_sui_event_and_action, sui_mock_client::SuiMockClient, - test_utils::get_test_log_and_action, types::BridgeActionDigest, - }; - - #[tokio::test] - async fn test_sui_watcher_task() { - // Note: this test may fail beacuse of the following reasons: - // the SuiEvent's struct tag does not match the ones in events.rs - - let (sui_events_tx, sui_events_rx, _eth_events_tx, eth_events_rx, sui_client, store) = - setup(); - - let (executor, mut executor_requested_action_rx) = MockExecutor::new(); - // start orchestrator - let _handles = BridgeOrchestrator::new( - Arc::new(sui_client), - sui_events_rx, - eth_events_rx, - store.clone(), - ) - .run(executor); - - let identifier = Identifier::from_str("test_sui_watcher_task").unwrap(); - let (sui_event, bridge_action) = get_test_sui_event_and_action(identifier.clone()); - sui_events_tx - .send((identifier.clone(), vec![sui_event.clone()])) - .await - .unwrap(); - - let start = std::time::Instant::now(); - // Executor should have received the action - assert_eq!( - executor_requested_action_rx.recv().await.unwrap(), - bridge_action.digest() - ); - loop { - let actions = store.get_all_pending_actions().unwrap(); - if actions.is_empty() { - if start.elapsed().as_secs() > 5 { - panic!("Timed out waiting for action to be written to WAL"); - } - tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; - continue; - } - assert_eq!(actions.len(), 1); - let action = actions.get(&bridge_action.digest()).unwrap(); - assert_eq!(action, &bridge_action); - assert_eq!( - store.get_sui_event_cursors(&[identifier]).unwrap()[0].unwrap(), - sui_event.id, - ); - break; - } - } - - #[tokio::test] - async fn test_eth_watcher_task() { - // Note: this test may fail beacuse of the following reasons: - // 1. Log and BridgeAction returned from `get_test_log_and_action` are not in - // sync - // 2. Log returned from `get_test_log_and_action` is not parseable log (not - // abigen!, check abi.rs) - - let (_sui_events_tx, sui_events_rx, eth_events_tx, eth_events_rx, sui_client, store) = - setup(); - let (executor, mut executor_requested_action_rx) = MockExecutor::new(); - // start orchestrator - let _handles = BridgeOrchestrator::new( - Arc::new(sui_client), - sui_events_rx, - eth_events_rx, - store.clone(), - ) - .run(executor); - let address = EthAddress::random(); - let (log, bridge_action) = get_test_log_and_action(address, TxHash::random(), 10); - let log_index_in_tx = 10; - let log_block_num = log.block_number.unwrap().as_u64(); - let eth_log = EthLog { - log: log.clone(), - tx_hash: log.transaction_hash.unwrap(), - block_number: log_block_num, - log_index_in_tx, - }; - let end_block_num = log_block_num + 15; - - eth_events_tx - .send((address, end_block_num, vec![eth_log.clone()])) - .await - .unwrap(); - - // Executor should have received the action - assert_eq!( - executor_requested_action_rx.recv().await.unwrap(), - bridge_action.digest() - ); - let start = std::time::Instant::now(); - loop { - let actions = store.get_all_pending_actions().unwrap(); - if actions.is_empty() { - if start.elapsed().as_secs() > 5 { - panic!("Timed out waiting for action to be written to WAL"); - } - tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; - continue; - } - assert_eq!(actions.len(), 1); - let action = actions.get(&bridge_action.digest()).unwrap(); - assert_eq!(action, &bridge_action); - assert_eq!( - store.get_eth_event_cursors(&[address]).unwrap()[0].unwrap(), - end_block_num, - ); - break; - } - } - - #[allow(clippy::type_complexity)] - fn setup() -> ( - mysten_metrics::metered_channel::Sender<(Identifier, Vec)>, - mysten_metrics::metered_channel::Receiver<(Identifier, Vec)>, - mysten_metrics::metered_channel::Sender<(EthAddress, u64, Vec)>, - mysten_metrics::metered_channel::Receiver<(EthAddress, u64, Vec)>, - SuiClient, - Arc, - ) { - telemetry_subscribers::init_for_testing(); - let registry = Registry::new(); - mysten_metrics::init_metrics(®istry); - - // TODO: remove once we don't rely on env var to get package id - std::env::set_var("BRIDGE_PACKAGE_ID", "0x0b"); - - let temp_dir = tempfile::tempdir().unwrap(); - let store = BridgeOrchestratorTables::new(temp_dir.path()); - - let mock_client = SuiMockClient::default(); - let sui_client = SuiClient::new_for_testing(mock_client.clone()); - - let (eth_events_tx, eth_events_rx) = mysten_metrics::metered_channel::channel( - 100, - &mysten_metrics::get_metrics() - .unwrap() - .channels - .with_label_values(&["unit_test_eth_events_queue"]), - ); - - let (sui_events_tx, sui_events_rx) = mysten_metrics::metered_channel::channel( - 100, - &mysten_metrics::get_metrics() - .unwrap() - .channels - .with_label_values(&["unit_test_sui_events_queue"]), - ); - - ( - sui_events_tx, - sui_events_rx, - eth_events_tx, - eth_events_rx, - sui_client, - store, - ) - } - - /// A `BridgeActionExecutorTrait` implementation that only tracks the - /// submitted actions. - struct MockExecutor { - requested_transactions_tx: tokio::sync::broadcast::Sender, - } - - impl MockExecutor { - fn new() -> (Self, tokio::sync::broadcast::Receiver) { - let (tx, rx) = tokio::sync::broadcast::channel(100); - ( - Self { - requested_transactions_tx: tx, - }, - rx, - ) - } - } - - impl BridgeActionExecutorTrait for MockExecutor { - fn run( - self, - ) -> ( - Vec>, - mysten_metrics::metered_channel::Sender, - ) { - let (tx, mut rx) = - mysten_metrics::metered_channel::channel::( - 100, - &mysten_metrics::get_metrics() - .unwrap() - .channels - .with_label_values(&["unit_test_mock_executor"]), - ); - - let handles = tokio::spawn(async move { - while let Some(action) = rx.recv().await { - self.requested_transactions_tx - .send(action.0.digest()) - .unwrap(); - } - }); - (vec![handles], tx) - } - } -} diff --git a/crates/sui-bridge/src/server/mod.rs b/crates/sui-bridge/src/server/mod.rs deleted file mode 100644 index 5f1a388efa0..00000000000 --- a/crates/sui-bridge/src/server/mod.rs +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#![allow(clippy::inconsistent_digit_grouping)] - -use std::{net::SocketAddr, sync::Arc}; - -use axum::{ - extract::{Path, State}, - http::StatusCode, - routing::get, - Json, Router, -}; -use ethers::types::Address as EthAddress; -use fastcrypto::{ - encoding::{Encoding, Hex}, - traits::ToFromBytes, -}; - -use crate::{ - crypto::BridgeAuthorityPublicKeyBytes, - error::BridgeError, - server::handler::{BridgeRequestHandler, BridgeRequestHandlerTrait}, - types::{ - AssetPriceUpdateAction, BlocklistCommitteeAction, BlocklistType, BridgeAction, - BridgeChainId, EmergencyAction, EmergencyActionType, EvmContractUpgradeAction, - LimitUpdateAction, SignedBridgeAction, TokenId, - }, -}; - -pub mod governance_verifier; -pub mod handler; - -#[cfg(test)] -pub(crate) mod mock_handler; - -pub const APPLICATION_JSON: &str = "application/json"; - -// Important: the paths need to match the ones in bridge_client.rs -pub const ETH_TO_SUI_TX_PATH: &str = "/sign/bridge_tx/eth/sui/:tx_hash/:event_index"; -pub const SUI_TO_ETH_TX_PATH: &str = "/sign/bridge_tx/sui/eth/:tx_digest/:event_index"; -pub const COMMITTEE_BLOCKLIST_UPDATE_PATH: &str = - "/sign/update_committee_blocklist/:chain_id/:nonce/:type/:keys"; -pub const EMERGENCY_BUTTON_PATH: &str = "/sign/emergency_button/:chain_id/:nonce/:type"; -pub const LIMIT_UPDATE_PATH: &str = - "/sign/update_limit/:chain_id/:nonce/:sending_chain_id/:new_usd_limit"; -pub const ASSET_PRICE_UPDATE_PATH: &str = - "/sign/update_asset_price/:chain_id/:nonce/:token_id/:new_usd_price"; -pub const EVM_CONTRACT_UPGRADE_PATH_WITH_CALLDATA: &str = - "/sign/upgrade_evm_contract/:chain_id/:nonce/:proxy_address/:new_impl_address/:calldata"; -pub const EVM_CONTRACT_UPGRADE_PATH: &str = - "/sign/upgrade_evm_contract/:chain_id/:nonce/:proxy_address/:new_impl_address"; - -pub async fn run_server(socket_address: &SocketAddr, handler: BridgeRequestHandler) { - axum::Server::bind(socket_address) - .serve(make_router(Arc::new(handler)).into_make_service()) - .await - .unwrap(); -} - -pub(crate) fn make_router( - handler: Arc, -) -> Router { - Router::new() - .route("/", get(health_check)) - .route(ETH_TO_SUI_TX_PATH, get(handle_eth_tx_hash)) - .route(SUI_TO_ETH_TX_PATH, get(handle_sui_tx_digest)) - .route( - COMMITTEE_BLOCKLIST_UPDATE_PATH, - get(handle_update_committee_blocklist_action), - ) - .route(EMERGENCY_BUTTON_PATH, get(handle_emergecny_action)) - .route(LIMIT_UPDATE_PATH, get(handle_limit_update_action)) - .route( - ASSET_PRICE_UPDATE_PATH, - get(handle_asset_price_update_action), - ) - .route(EVM_CONTRACT_UPGRADE_PATH, get(handle_evm_contract_upgrade)) - .route( - EVM_CONTRACT_UPGRADE_PATH_WITH_CALLDATA, - get(handle_evm_contract_upgrade_with_calldata), - ) - .with_state(handler) -} - -impl axum::response::IntoResponse for BridgeError { - // TODO: distinguish client error. - fn into_response(self) -> axum::response::Response { - ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Something went wrong: {:?}", self), - ) - .into_response() - } -} - -impl From for BridgeError -where - E: Into, -{ - fn from(err: E) -> Self { - Self::Generic(err.into().to_string()) - } -} - -async fn health_check() -> StatusCode { - StatusCode::OK -} - -async fn handle_eth_tx_hash( - Path((tx_hash_hex, event_idx)): Path<(String, u16)>, - State(handler): State>, -) -> Result, BridgeError> { - let sig = handler.handle_eth_tx_hash(tx_hash_hex, event_idx).await?; - Ok(sig) -} - -async fn handle_sui_tx_digest( - Path((tx_digest_base58, event_idx)): Path<(String, u16)>, - State(handler): State>, -) -> Result, BridgeError> { - let sig: Json = handler - .handle_sui_tx_digest(tx_digest_base58, event_idx) - .await?; - Ok(sig) -} - -async fn handle_update_committee_blocklist_action( - Path((chain_id, nonce, blocklist_type, keys)): Path<(u8, u64, u8, String)>, - State(handler): State>, -) -> Result, BridgeError> { - let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| { - BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err)) - })?; - let blocklist_type = BlocklistType::try_from(blocklist_type).map_err(|err| { - BridgeError::InvalidBridgeClientRequest(format!("Invalid blocklist action type: {:?}", err)) - })?; - let blocklisted_members = keys - .split(',') - .map(|s| { - let bytes = Hex::decode(s).map_err(|e| anyhow::anyhow!("{:?}", e))?; - BridgeAuthorityPublicKeyBytes::from_bytes(&bytes) - .map_err(|e| anyhow::anyhow!("{:?}", e)) - }) - .collect::, _>>() - .map_err(|e| BridgeError::InvalidBridgeClientRequest(format!("{:?}", e)))?; - let action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction { - chain_id, - nonce, - blocklist_type, - blocklisted_members, - }); - - let sig: Json = handler.handle_governance_action(action).await?; - Ok(sig) -} - -async fn handle_emergecny_action( - Path((chain_id, nonce, action_type)): Path<(u8, u64, u8)>, - State(handler): State>, -) -> Result, BridgeError> { - let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| { - BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err)) - })?; - let action_type = EmergencyActionType::try_from(action_type).map_err(|err| { - BridgeError::InvalidBridgeClientRequest(format!("Invalid emergency action type: {:?}", err)) - })?; - let action = BridgeAction::EmergencyAction(EmergencyAction { - chain_id, - nonce, - action_type, - }); - let sig: Json = handler.handle_governance_action(action).await?; - Ok(sig) -} - -async fn handle_limit_update_action( - Path((chain_id, nonce, sending_chain_id, new_usd_limit)): Path<(u8, u64, u8, u64)>, - State(handler): State>, -) -> Result, BridgeError> { - let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| { - BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err)) - })?; - let sending_chain_id = BridgeChainId::try_from(sending_chain_id).map_err(|err| { - BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err)) - })?; - let action = BridgeAction::LimitUpdateAction(LimitUpdateAction { - chain_id, - nonce, - sending_chain_id, - new_usd_limit, - }); - let sig: Json = handler.handle_governance_action(action).await?; - Ok(sig) -} - -async fn handle_asset_price_update_action( - Path((chain_id, nonce, token_id, new_usd_price)): Path<(u8, u64, u8, u64)>, - State(handler): State>, -) -> Result, BridgeError> { - let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| { - BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err)) - })?; - let token_id = TokenId::try_from(token_id).map_err(|err| { - BridgeError::InvalidBridgeClientRequest(format!("Invalid token id: {:?}", err)) - })?; - let action = BridgeAction::AssetPriceUpdateAction(AssetPriceUpdateAction { - chain_id, - nonce, - token_id, - new_usd_price, - }); - let sig: Json = handler.handle_governance_action(action).await?; - Ok(sig) -} - -async fn handle_evm_contract_upgrade_with_calldata( - Path((chain_id, nonce, proxy_address, new_impl_address, calldata)): Path<( - u8, - u64, - EthAddress, - EthAddress, - String, - )>, - State(handler): State>, -) -> Result, BridgeError> { - let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| { - BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err)) - })?; - let call_data = Hex::decode(&calldata).map_err(|e| { - BridgeError::InvalidBridgeClientRequest(format!("Invalid call data: {:?}", e)) - })?; - let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { - chain_id, - nonce, - proxy_address, - new_impl_address, - call_data, - }); - let sig: Json = handler.handle_governance_action(action).await?; - Ok(sig) -} - -async fn handle_evm_contract_upgrade( - Path((chain_id, nonce, proxy_address, new_impl_address)): Path<( - u8, - u64, - EthAddress, - EthAddress, - )>, - State(handler): State>, -) -> Result, BridgeError> { - let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| { - BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err)) - })?; - let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { - chain_id, - nonce, - proxy_address, - new_impl_address, - call_data: vec![], - }); - let sig: Json = handler.handle_governance_action(action).await?; - Ok(sig) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - client::bridge_client::BridgeClient, server::mock_handler::BridgeRequestMockHandler, - test_utils::get_test_authorities_and_run_mock_bridge_server, types::BridgeCommittee, - }; - - #[tokio::test] - async fn test_bridge_server_handle_blocklist_update_action_path() { - let client = setup(); - - let pub_key_bytes = BridgeAuthorityPublicKeyBytes::from_bytes( - &Hex::decode("02321ede33d2c2d7a8a152f275a1484edef2098f034121a602cb7d767d38680aa4") - .unwrap(), - ) - .unwrap(); - let action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction { - nonce: 129, - chain_id: BridgeChainId::SuiLocalTest, - blocklist_type: BlocklistType::Blocklist, - blocklisted_members: vec![pub_key_bytes.clone()], - }); - client.request_sign_bridge_action(action).await.unwrap(); - } - - #[tokio::test] - async fn test_bridge_server_handle_emergency_action_path() { - let client = setup(); - - let action = BridgeAction::EmergencyAction(EmergencyAction { - nonce: 55, - chain_id: BridgeChainId::SuiLocalTest, - action_type: EmergencyActionType::Pause, - }); - client.request_sign_bridge_action(action).await.unwrap(); - } - - #[tokio::test] - async fn test_bridge_server_handle_limit_update_action_path() { - let client = setup(); - - let action = BridgeAction::LimitUpdateAction(LimitUpdateAction { - nonce: 15, - chain_id: BridgeChainId::SuiLocalTest, - sending_chain_id: BridgeChainId::EthLocalTest, - new_usd_limit: 1_000_000_0000, // $1M USD - }); - client.request_sign_bridge_action(action).await.unwrap(); - } - - #[tokio::test] - async fn test_bridge_server_handle_asset_price_update_action_path() { - let client = setup(); - - let action = BridgeAction::AssetPriceUpdateAction(AssetPriceUpdateAction { - nonce: 266, - chain_id: BridgeChainId::SuiLocalTest, - token_id: TokenId::BTC, - new_usd_price: 100_000_0000, // $100k USD - }); - client.request_sign_bridge_action(action).await.unwrap(); - } - - #[tokio::test] - async fn test_bridge_server_handle_evm_contract_upgrade_action_path() { - let client = setup(); - - let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { - nonce: 123, - chain_id: BridgeChainId::EthLocalTest, - proxy_address: EthAddress::repeat_byte(6), - new_impl_address: EthAddress::repeat_byte(9), - call_data: vec![], - }); - client.request_sign_bridge_action(action).await.unwrap(); - - let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { - nonce: 123, - chain_id: BridgeChainId::EthLocalTest, - proxy_address: EthAddress::repeat_byte(6), - new_impl_address: EthAddress::repeat_byte(9), - call_data: vec![12, 34, 56], - }); - client.request_sign_bridge_action(action).await.unwrap(); - } - - fn setup() -> BridgeClient { - let mock = BridgeRequestMockHandler::new(); - let (_handles, authorities, mut secrets) = - get_test_authorities_and_run_mock_bridge_server(vec![10000], vec![mock.clone()]); - mock.set_signer(secrets.swap_remove(0)); - let committee = BridgeCommittee::new(authorities).unwrap(); - let pub_key = committee.members().keys().next().unwrap(); - BridgeClient::new(pub_key.clone(), Arc::new(committee)).unwrap() - } -} diff --git a/crates/sui-bridge/src/storage.rs b/crates/sui-bridge/src/storage.rs deleted file mode 100644 index 94ed1c891b3..00000000000 --- a/crates/sui-bridge/src/storage.rs +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::HashMap, path::Path, sync::Arc}; - -use sui_types::{event::EventID, Identifier}; -use typed_store::{ - rocks::{DBMap, MetricConf}, - traits::{TableSummary, TypedStoreDebug}, - Map, -}; -use typed_store_derive::DBMapUtils; - -use crate::{ - error::{BridgeError, BridgeResult}, - types::{BridgeAction, BridgeActionDigest}, -}; - -#[derive(DBMapUtils)] -pub struct BridgeOrchestratorTables { - /// pending BridgeActions that orchestrator received but not yet executed - pub(crate) pending_actions: DBMap, - /// module identifier to the last processed EventID - pub(crate) sui_syncer_cursors: DBMap, - /// contract address to the last processed block - pub(crate) eth_syncer_cursors: DBMap, -} - -// TODO remove after wireup -#[allow(dead_code)] -impl BridgeOrchestratorTables { - pub fn new(path: &Path) -> Arc { - Arc::new(Self::open_tables_read_write( - path.to_path_buf(), - MetricConf::new("bridge"), - None, - None, - )) - } - - pub(crate) fn insert_pending_actions(&self, actions: &[BridgeAction]) -> BridgeResult<()> { - let mut batch = self.pending_actions.batch(); - batch - .insert_batch( - &self.pending_actions, - actions.iter().map(|a| (a.digest(), a)), - ) - .map_err(|e| { - BridgeError::StorageError(format!("Couldn't insert into pending_actions: {:?}", e)) - })?; - batch - .write() - .map_err(|e| BridgeError::StorageError(format!("Couldn't write batch: {:?}", e))) - } - - pub(crate) fn remove_pending_actions( - &self, - actions: &[BridgeActionDigest], - ) -> BridgeResult<()> { - let mut batch = self.pending_actions.batch(); - batch - .delete_batch(&self.pending_actions, actions) - .map_err(|e| { - BridgeError::StorageError(format!("Couldn't delete from pending_actions: {:?}", e)) - })?; - batch - .write() - .map_err(|e| BridgeError::StorageError(format!("Couldn't write batch: {:?}", e))) - } - - pub(crate) fn update_sui_event_cursor( - &self, - module: Identifier, - cursor: EventID, - ) -> BridgeResult<()> { - let mut batch = self.sui_syncer_cursors.batch(); - - batch - .insert_batch(&self.sui_syncer_cursors, [(module, cursor)]) - .map_err(|e| { - BridgeError::StorageError(format!( - "Coudln't insert into sui_syncer_cursors: {:?}", - e - )) - })?; - batch - .write() - .map_err(|e| BridgeError::StorageError(format!("Couldn't write batch: {:?}", e))) - } - - pub(crate) fn update_eth_event_cursor( - &self, - contract_address: ethers::types::Address, - cursor: u64, - ) -> BridgeResult<()> { - let mut batch = self.eth_syncer_cursors.batch(); - - batch - .insert_batch(&self.eth_syncer_cursors, [(contract_address, cursor)]) - .map_err(|e| { - BridgeError::StorageError(format!( - "Coudln't insert into eth_syncer_cursors: {:?}", - e - )) - })?; - batch - .write() - .map_err(|e| BridgeError::StorageError(format!("Couldn't write batch: {:?}", e))) - } - - pub fn get_all_pending_actions( - &self, - ) -> BridgeResult> { - Ok(self.pending_actions.unbounded_iter().collect()) - } - - pub fn get_sui_event_cursors( - &self, - identifiers: &[Identifier], - ) -> BridgeResult>> { - self.sui_syncer_cursors.multi_get(identifiers).map_err(|e| { - BridgeError::StorageError(format!("Couldn't get sui_syncer_cursors: {:?}", e)) - }) - } - - pub fn get_eth_event_cursors( - &self, - contract_addresses: &[ethers::types::Address], - ) -> BridgeResult>> { - self.eth_syncer_cursors - .multi_get(contract_addresses) - .map_err(|e| { - BridgeError::StorageError(format!("Couldn't get sui_syncer_cursors: {:?}", e)) - }) - } -} - -#[cfg(test)] -mod tests { - use std::str::FromStr; - - use sui_types::digests::TransactionDigest; - - use super::*; - use crate::test_utils::get_test_sui_to_eth_bridge_action; - - // async: existing runtime is required with typed-store - #[tokio::test] - async fn test_bridge_storage_basic() { - let temp_dir = tempfile::tempdir().unwrap(); - let store = BridgeOrchestratorTables::new(temp_dir.path()); - - let action1 = get_test_sui_to_eth_bridge_action(None, Some(0), Some(99), Some(10000)); - - let action2 = get_test_sui_to_eth_bridge_action(None, Some(2), Some(100), Some(10000)); - - // in the beginning it's empty - let actions = store.get_all_pending_actions().unwrap(); - assert!(actions.is_empty()); - - // remove non existing entry is ok - store.remove_pending_actions(&[action1.digest()]).unwrap(); - - store - .insert_pending_actions(&vec![action1.clone(), action2.clone()]) - .unwrap(); - - let actions = store.get_all_pending_actions().unwrap(); - assert_eq!( - actions, - HashMap::from_iter(vec![ - (action1.digest(), action1.clone()), - (action2.digest(), action2.clone()) - ]) - ); - - // insert an existing action is ok - store.insert_pending_actions(&[action1.clone()]).unwrap(); - let actions = store.get_all_pending_actions().unwrap(); - assert_eq!( - actions, - HashMap::from_iter(vec![ - (action1.digest(), action1.clone()), - (action2.digest(), action2.clone()) - ]) - ); - - // remove action 2 - store.remove_pending_actions(&[action2.digest()]).unwrap(); - let actions = store.get_all_pending_actions().unwrap(); - assert_eq!( - actions, - HashMap::from_iter(vec![(action1.digest(), action1.clone())]) - ); - - // remove action 1 - store.remove_pending_actions(&[action1.digest()]).unwrap(); - let actions = store.get_all_pending_actions().unwrap(); - assert!(actions.is_empty()); - - // update eth event cursor - let eth_contract_address = ethers::types::Address::random(); - let eth_block_num = 199999u64; - assert!( - store - .get_eth_event_cursors(&[eth_contract_address]) - .unwrap()[0] - .is_none() - ); - store - .update_eth_event_cursor(eth_contract_address, eth_block_num) - .unwrap(); - assert_eq!( - store - .get_eth_event_cursors(&[eth_contract_address]) - .unwrap()[0] - .unwrap(), - eth_block_num - ); - - // update sui event cursor - let sui_module = Identifier::from_str("test").unwrap(); - let sui_cursor = EventID { - tx_digest: TransactionDigest::random(), - event_seq: 1, - }; - assert!(store.get_sui_event_cursors(&[sui_module.clone()]).unwrap()[0].is_none()); - store - .update_sui_event_cursor(sui_module.clone(), sui_cursor) - .unwrap(); - assert_eq!( - store.get_sui_event_cursors(&[sui_module.clone()]).unwrap()[0].unwrap(), - sui_cursor - ); - } -} diff --git a/crates/sui-bridge/src/sui_client.rs b/crates/sui-bridge/src/sui_client.rs deleted file mode 100644 index 50bf2fadbfe..00000000000 --- a/crates/sui-bridge/src/sui_client.rs +++ /dev/null @@ -1,619 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// TODO remove when integrated -#![allow(unused)] - -use std::{ - str::{from_utf8, FromStr}, - time::Duration, -}; - -use anyhow::anyhow; -use async_trait::async_trait; -use axum::response::sse::Event; -use ethers::types::{Address, U256}; -use fastcrypto::traits::{KeyPair, ToFromBytes}; -use once_cell::sync::OnceCell; -use serde::{Deserialize, Serialize}; -use sui_json_rpc_types::{ - EventFilter, EventPage, Page, SuiData, SuiEvent, SuiObjectDataOptions, - SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, -}; -use sui_sdk::{SuiClient as SuiSdkClient, SuiClientBuilder}; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, - collection_types::LinkedTableNode, - crypto::get_key_pair, - digests::TransactionDigest, - dynamic_field::{DynamicFieldName, Field}, - error::{SuiObjectResponseError, UserInputError}, - event, - event::EventID, - gas_coin::GasCoin, - object::{Object, Owner}, - transaction::Transaction, - Identifier, TypeTag, -}; -use tap::TapFallible; -use tracing::{error, warn}; - -use crate::{ - crypto::BridgeAuthorityPublicKey, - error::{BridgeError, BridgeResult}, - events::SuiBridgeEvent, - retry_with_max_elapsed_time, - sui_transaction_builder::get_bridge_package_id, - types::{ - BridgeAction, BridgeActionStatus, BridgeAuthority, BridgeCommittee, - BridgeInnerDynamicField, BridgeRecordDyanmicField, MoveTypeBridgeCommittee, - MoveTypeBridgeInner, MoveTypeBridgeMessageKey, MoveTypeBridgeRecord, - MoveTypeCommitteeMember, - }, -}; - -// TODO: once we have bridge package on sui framework, we can hardcode the -// actual bridge dynamic field object id (not 0x9 or dynamic field wrapper) and -// update along with software upgrades. -// Or do we always retrieve from 0x9? We can figure this out before the first -// uggrade. -fn get_bridge_object_id() -> &'static ObjectID { - static BRIDGE_OBJ_ID: OnceCell = OnceCell::new(); - BRIDGE_OBJ_ID.get_or_init(|| { - let bridge_object_id = - std::env::var("BRIDGE_OBJECT_ID").expect("Expect BRIDGE_OBJECT_ID env var set"); - ObjectID::from_hex_literal(&bridge_object_id) - .expect("BRIDGE_OBJECT_ID must be a valid hex string") - }) -} - -// object id of BridgeRecord, this is wrapped in the bridge inner object. -// TODO: once we have bridge package on sui framework, we can hardcode the -// actual id. -fn get_bridge_record_id() -> &'static ObjectID { - static BRIDGE_RECORD_ID: OnceCell = OnceCell::new(); - BRIDGE_RECORD_ID.get_or_init(|| { - let bridge_record_id = - std::env::var("BRIDGE_RECORD_ID").expect("Expect BRIDGE_RECORD_ID env var set"); - ObjectID::from_hex_literal(&bridge_record_id) - .expect("BRIDGE_RECORD_ID must be a valid hex string") - }) -} - -pub struct SuiClient

    { - inner: P, -} - -impl SuiClient { - pub async fn new(rpc_url: &str) -> anyhow::Result { - let inner = SuiClientBuilder::default().build(rpc_url).await?; - let self_ = Self { inner }; - self_.describe().await?; - Ok(self_) - } -} - -impl

    SuiClient

    -where - P: SuiClientInner, -{ - pub fn new_for_testing(inner: P) -> Self { - Self { inner } - } - - // TODO assert chain identifier - async fn describe(&self) -> anyhow::Result<()> { - let chain_id = self.inner.get_chain_identifier().await?; - let block_number = self.inner.get_latest_checkpoint_sequence_number().await?; - tracing::info!( - "SuiClient is connected to chain {chain_id}, current block number: {block_number}" - ); - Ok(()) - } - - /// Query emitted Events that are defined in the given Move Module. - pub async fn query_events_by_module( - &self, - package: ObjectID, - module: Identifier, - // cursor is exclusive - cursor: EventID, - ) -> BridgeResult> { - let filter = EventFilter::MoveEventModule { - package, - module: module.clone(), - }; - let events = self.inner.query_events(filter.clone(), cursor).await?; - - // Safeguard check that all events are emitted from requested package and module - assert!( - events - .data - .iter() - .all(|event| event.type_.address.as_ref() == package.as_ref() - && event.type_.module == module) - ); - Ok(events) - } - - /// Returns BridgeAction from a Sui Transaction with transaction hash - /// and the event index. If event is declared in an unrecognized - /// package, return error. - pub async fn get_bridge_action_by_tx_digest_and_event_idx_maybe( - &self, - tx_digest: &TransactionDigest, - event_idx: u16, - ) -> BridgeResult { - let events = self.inner.get_events_by_tx_digest(*tx_digest).await?; - let event = events - .get(event_idx as usize) - .ok_or(BridgeError::NoBridgeEventsInTxPosition)?; - if event.type_.address.as_ref() != get_bridge_package_id().as_ref() { - return Err(BridgeError::BridgeEventInUnrecognizedSuiPackage); - } - let bridge_event = SuiBridgeEvent::try_from_sui_event(event)? - .ok_or(BridgeError::NoBridgeEventsInTxPosition)?; - - bridge_event - .try_into_bridge_action(*tx_digest, event_idx) - .ok_or(BridgeError::BridgeEventNotActionable) - } - - // TODO: expose this API to jsonrpc like system state query - pub async fn get_bridge_committee(&self) -> BridgeResult { - let move_type_bridge_committee = - self.inner.get_bridge_committee().await.map_err(|e| { - BridgeError::InternalError(format!("Can't get bridge committee: {e}")) - })?; - let mut authorities = vec![]; - // TODO: move this to MoveTypeBridgeCommittee - for member in move_type_bridge_committee.members.contents { - let MoveTypeCommitteeMember { - sui_address, - bridge_pubkey_bytes, - voting_power, - http_rest_url, - blocklisted, - } = member.value; - let pubkey = BridgeAuthorityPublicKey::from_bytes(&bridge_pubkey_bytes)?; - let base_url = from_utf8(&http_rest_url).unwrap_or_else(|e| { - warn!( - "Bridge authority address: {}, pubkey: {:?} has invalid http url: {:?}", - sui_address, bridge_pubkey_bytes, http_rest_url - ); - "" - }); - authorities.push(BridgeAuthority { - pubkey, - voting_power, - base_url: base_url.into(), - is_blocklisted: blocklisted, - }); - } - BridgeCommittee::new(authorities) - } - - pub async fn execute_transaction_block_with_effects( - &self, - tx: sui_types::transaction::Transaction, - ) -> BridgeResult { - self.inner.execute_transaction_block_with_effects(tx).await - } - - pub async fn get_token_transfer_action_onchain_status_until_success( - &self, - action: &BridgeAction, - ) -> BridgeActionStatus { - loop { - let Ok(Ok(status)) = retry_with_max_elapsed_time!( - self.inner.get_token_transfer_action_onchain_status(action), - Duration::from_secs(30) - ) else { - // TODO: add metrics and fire alert - error!("Failed to get action onchain status for: {:?}", action); - continue; - }; - return status; - } - } - - pub async fn get_gas_data_panic_if_not_gas( - &self, - gas_object_id: ObjectID, - ) -> (GasCoin, ObjectRef, Owner) { - self.inner - .get_gas_data_panic_if_not_gas(gas_object_id) - .await - } -} - -/// Use a trait to abstract over the SuiSDKClient and SuiMockClient for testing. -#[async_trait] -pub trait SuiClientInner: Send + Sync { - type Error: Into + Send + Sync + std::error::Error + 'static; - async fn query_events( - &self, - query: EventFilter, - cursor: EventID, - ) -> Result; - - async fn get_events_by_tx_digest( - &self, - tx_digest: TransactionDigest, - ) -> Result, Self::Error>; - - async fn get_chain_identifier(&self) -> Result; - - async fn get_latest_checkpoint_sequence_number(&self) -> Result; - - async fn get_bridge_committee(&self) -> Result; - - async fn execute_transaction_block_with_effects( - &self, - tx: Transaction, - ) -> Result; - - async fn get_token_transfer_action_onchain_status( - &self, - action: &BridgeAction, - ) -> Result; - - async fn get_gas_data_panic_if_not_gas( - &self, - gas_object_id: ObjectID, - ) -> (GasCoin, ObjectRef, Owner); -} - -#[async_trait] -impl SuiClientInner for SuiSdkClient { - type Error = sui_sdk::error::Error; - - async fn query_events( - &self, - query: EventFilter, - cursor: EventID, - ) -> Result { - self.event_api() - .query_events(query, Some(cursor), None, false) - .await - } - - async fn get_events_by_tx_digest( - &self, - tx_digest: TransactionDigest, - ) -> Result, Self::Error> { - self.event_api().get_events(tx_digest).await - } - - async fn get_chain_identifier(&self) -> Result { - self.read_api().get_chain_identifier().await - } - - async fn get_latest_checkpoint_sequence_number(&self) -> Result { - self.read_api() - .get_latest_checkpoint_sequence_number() - .await - } - - // TODO: Add a test for this - async fn get_bridge_committee(&self) -> Result { - let object_id = *get_bridge_object_id(); - let bcs_bytes = self.read_api().get_move_object_bcs(object_id).await?; - let bridge_dynamic_field: BridgeInnerDynamicField = bcs::from_bytes(&bcs_bytes)?; - Ok(bridge_dynamic_field.value.committee) - } - - async fn get_token_transfer_action_onchain_status( - &self, - action: &BridgeAction, - ) -> Result { - match &action { - BridgeAction::SuiToEthBridgeAction(_) | BridgeAction::EthToSuiBridgeAction(_) => (), - _ => return Err(BridgeError::ActionIsNotTokenTransferAction), - }; - let package_id = *get_bridge_package_id(); - let key = serde_json::json!( - { - // u64 is represented as string - "bridge_seq_num": action.seq_number().to_string(), - "message_type": action.action_type() as u8, - "source_chain": action.chain_id() as u8, - } - ); - let status_object_id = match self - .read_api() - .get_dynamic_field_object( - *get_bridge_record_id(), - DynamicFieldName { - type_: TypeTag::from_str(&format!( - "{:?}::message::BridgeMessageKey", - package_id - )) - .unwrap(), - value: key.clone(), - }, - ) - .await? - .into_object() - { - Ok(object) => object.object_id, - Err(SuiObjectResponseError::DynamicFieldNotFound { .. }) => { - return Ok(BridgeActionStatus::RecordNotFound); - } - other => { - return Err(BridgeError::Generic(format!( - "Can't get bridge action record dynamic field {:?}: {:?}", - key, other - ))); - } - }; - - // get_dynamic_field_object does not return bcs, so we have to issue anothe - // query - let bcs_bytes = self - .read_api() - .get_move_object_bcs(status_object_id) - .await?; - let status_object: BridgeRecordDyanmicField = bcs::from_bytes(&bcs_bytes)?; - - if status_object.value.value.claimed { - return Ok(BridgeActionStatus::Claimed); - } - - if status_object.value.value.verified_signatures.is_some() { - return Ok(BridgeActionStatus::Approved); - } - - return Ok(BridgeActionStatus::Pending); - } - - async fn execute_transaction_block_with_effects( - &self, - tx: Transaction, - ) -> Result { - match self.quorum_driver_api().execute_transaction_block( - tx, - SuiTransactionBlockResponseOptions::new().with_effects(), - Some(sui_types::quorum_driver_types::ExecuteTransactionRequestType::WaitForEffectsCert), - ).await { - Ok(response) => Ok(response), - Err(e) => return Err(BridgeError::SuiTxFailureGeneric(e.to_string())), - } - } - - async fn get_gas_data_panic_if_not_gas( - &self, - gas_object_id: ObjectID, - ) -> (GasCoin, ObjectRef, Owner) { - loop { - match self - .read_api() - .get_object_with_options( - gas_object_id, - SuiObjectDataOptions::default().with_owner().with_content(), - ) - .await - .map(|resp| resp.data) - { - Ok(Some(gas_obj)) => { - let owner = gas_obj.owner.expect("Owner is requested"); - let gas_coin = GasCoin::try_from(&gas_obj) - .unwrap_or_else(|err| panic!("{} is not a gas coin: {err}", gas_object_id)); - return (gas_coin, gas_obj.object_ref(), owner); - } - other => { - warn!("Can't get gas object: {:?}: {:?}", gas_object_id, other); - tokio::time::sleep(Duration::from_secs(5)).await; - } - } - } - } -} - -#[cfg(test)] -mod tests { - use std::{collections::HashSet, str::FromStr}; - - use ethers::{ - abi::Token, - types::{ - Address as EthAddress, Block, BlockNumber, Filter, FilterBlockOption, Log, - ValueOrArray, U64, - }, - }; - use move_core_types::account_address::AccountAddress; - use prometheus::Registry; - use test_cluster::TestClusterBuilder; - - use super::*; - use crate::{ - events::{ - init_all_struct_tags, EmittedSuiToEthTokenBridgeV1, MoveTokenBridgeEvent, - SuiToEthTokenBridgeV1, - }, - sui_mock_client::SuiMockClient, - test_utils::{ - bridge_token, get_test_sui_to_eth_bridge_action, mint_tokens, publish_bridge_package, - transfer_treasury_cap, - }, - types::{BridgeActionType, BridgeChainId, SuiToEthBridgeAction, TokenId}, - }; - - #[tokio::test] - async fn get_bridge_action_by_tx_digest_and_event_idx_maybe() { - // Note: for random events generated in this test, we only care about - // tx_digest and event_seq, so it's ok that package and module does - // not match the query parameters. - telemetry_subscribers::init_for_testing(); - let mock_client = SuiMockClient::default(); - let sui_client = SuiClient::new_for_testing(mock_client.clone()); - let tx_digest = TransactionDigest::random(); - - // Ensure all struct tags are inited - init_all_struct_tags(); - - let sanitized_event_1 = EmittedSuiToEthTokenBridgeV1 { - nonce: 1, - sui_chain_id: BridgeChainId::SuiTestnet, - sui_address: SuiAddress::random_for_testing_only(), - eth_chain_id: BridgeChainId::EthSepolia, - eth_address: Address::random(), - token_id: TokenId::Sui, - amount: 100, - }; - let emitted_event_1 = MoveTokenBridgeEvent { - message_type: BridgeActionType::TokenTransfer as u8, - seq_num: sanitized_event_1.nonce, - source_chain: sanitized_event_1.sui_chain_id as u8, - sender_address: sanitized_event_1.sui_address.to_vec(), - target_chain: sanitized_event_1.eth_chain_id as u8, - target_address: sanitized_event_1.eth_address.as_bytes().to_vec(), - token_type: sanitized_event_1.token_id as u8, - amount: sanitized_event_1.amount, - }; - - // TODO: remove once we don't rely on env var to get package id - std::env::set_var("BRIDGE_PACKAGE_ID", "0x0b"); - - let mut sui_event_1 = SuiEvent::random_for_testing(); - sui_event_1.type_ = SuiToEthTokenBridgeV1.get().unwrap().clone(); - sui_event_1.bcs = bcs::to_bytes(&emitted_event_1).unwrap(); - - #[derive(Serialize, Deserialize)] - struct RandomStruct {}; - - let event_2: RandomStruct = RandomStruct {}; - // undeclared struct tag - let mut sui_event_2 = SuiEvent::random_for_testing(); - sui_event_2.type_ = SuiToEthTokenBridgeV1.get().unwrap().clone(); - sui_event_2.type_.module = Identifier::from_str("unrecognized_module").unwrap(); - sui_event_2.bcs = bcs::to_bytes(&event_2).unwrap(); - - // Event 3 is defined in non-bridge package - let mut sui_event_3 = sui_event_1.clone(); - sui_event_3.type_.address = AccountAddress::random(); - - mock_client.add_events_by_tx_digest( - tx_digest, - vec![ - sui_event_1.clone(), - sui_event_2.clone(), - sui_event_1.clone(), - sui_event_3.clone(), - ], - ); - let mut expected_action_1 = BridgeAction::SuiToEthBridgeAction(SuiToEthBridgeAction { - sui_tx_digest: tx_digest, - sui_tx_event_index: 0, - sui_bridge_event: sanitized_event_1.clone(), - }); - assert_eq!( - sui_client - .get_bridge_action_by_tx_digest_and_event_idx_maybe(&tx_digest, 0) - .await - .unwrap(), - expected_action_1, - ); - let mut expected_action_2 = BridgeAction::SuiToEthBridgeAction(SuiToEthBridgeAction { - sui_tx_digest: tx_digest, - sui_tx_event_index: 2, - sui_bridge_event: sanitized_event_1.clone(), - }); - assert_eq!( - sui_client - .get_bridge_action_by_tx_digest_and_event_idx_maybe(&tx_digest, 2) - .await - .unwrap(), - expected_action_2, - ); - assert!(matches!( - sui_client - .get_bridge_action_by_tx_digest_and_event_idx_maybe(&tx_digest, 1) - .await - .unwrap_err(), - BridgeError::NoBridgeEventsInTxPosition - ),); - assert!(matches!( - sui_client - .get_bridge_action_by_tx_digest_and_event_idx_maybe(&tx_digest, 3) - .await - .unwrap_err(), - BridgeError::BridgeEventInUnrecognizedSuiPackage - ),); - assert!(matches!( - sui_client - .get_bridge_action_by_tx_digest_and_event_idx_maybe(&tx_digest, 4) - .await - .unwrap_err(), - BridgeError::NoBridgeEventsInTxPosition - ),); - - // if the StructTag matches with unparsable bcs, it returns an error - sui_event_2.type_ = SuiToEthTokenBridgeV1.get().unwrap().clone(); - mock_client.add_events_by_tx_digest(tx_digest, vec![sui_event_2]); - sui_client - .get_bridge_action_by_tx_digest_and_event_idx_maybe(&tx_digest, 2) - .await - .unwrap_err(); - } - - #[tokio::test] - async fn test_get_action_onchain_status_for_sui_to_eth_transfer() { - let mut test_cluster = TestClusterBuilder::new().build().await; - let context = &mut test_cluster.wallet; - let sender = context.active_address().unwrap(); - - let treasury_caps = publish_bridge_package(context).await; - let sui_client = SuiClient::new(&test_cluster.fullnode_handle.rpc_url) - .await - .unwrap(); - - let action = get_test_sui_to_eth_bridge_action(None, None, None, None); - - let status = sui_client - .inner - .get_token_transfer_action_onchain_status(&action) - .await - .unwrap(); - assert_eq!(status, BridgeActionStatus::RecordNotFound); - - // mint 1000 USDC - let amount = 1_000_000_000u64; - let (treasury_cap_obj_ref, usdc_coin_obj_ref) = mint_tokens( - context, - treasury_caps[&TokenId::USDC], - amount, - TokenId::USDC, - ) - .await; - - transfer_treasury_cap(context, treasury_cap_obj_ref, TokenId::USDC).await; - - let recv_address = EthAddress::random(); - let bridge_event = - bridge_token(context, recv_address, usdc_coin_obj_ref, TokenId::USDC).await; - assert_eq!(bridge_event.nonce, 0); - assert_eq!(bridge_event.sui_chain_id, BridgeChainId::SuiLocalTest); - assert_eq!(bridge_event.eth_chain_id, BridgeChainId::EthLocalTest); - assert_eq!(bridge_event.eth_address, recv_address); - assert_eq!(bridge_event.sui_address, sender); - assert_eq!(bridge_event.token_id, TokenId::USDC); - assert_eq!(bridge_event.amount, amount); - - let status = sui_client - .inner - .get_token_transfer_action_onchain_status(&action) - .await - .unwrap(); - assert_eq!(status, BridgeActionStatus::Pending); - - // TODO: run bridge committee and approve the action, then assert status - // is Approved - } - - #[tokio::test] - async fn test_get_action_onchain_status_for_eth_to_sui_transfer() { - // TODO: init an eth -> sui transfer, run bridge committee, approve the - // action, then assert status is Approved/Claimed - } -} diff --git a/crates/sui-bridge/src/sui_mock_client.rs b/crates/sui-bridge/src/sui_mock_client.rs deleted file mode 100644 index ade88b4c490..00000000000 --- a/crates/sui-bridge/src/sui_mock_client.rs +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//! A mock implementation of Sui JSON-RPC client. - -use std::{ - collections::{HashMap, VecDeque}, - sync::{Arc, Mutex}, -}; - -use async_trait::async_trait; -use sui_json_rpc_types::{EventFilter, EventPage, SuiEvent, SuiTransactionBlockResponse}; -use sui_types::{ - base_types::{ObjectID, ObjectRef}, - digests::TransactionDigest, - event::EventID, - gas_coin::GasCoin, - object::Owner, - transaction::Transaction, - Identifier, -}; - -use crate::{ - error::{BridgeError, BridgeResult}, - sui_client::SuiClientInner, - types::{BridgeAction, BridgeActionDigest, BridgeActionStatus, MoveTypeBridgeCommittee}, -}; - -/// Mock client used in test environments. -#[allow(clippy::type_complexity)] -#[derive(Clone, Debug)] -pub struct SuiMockClient { - // the top two fields do not change during tests so we don't need them to be Arc> - chain_identifier: String, - latest_checkpoint_sequence_number: u64, - events: Arc>>, - past_event_query_params: Arc>>, - events_by_tx_digest: - Arc, sui_sdk::error::Error>>>>, - transaction_responses: - Arc>>>, - wildcard_transaction_response: Arc>>>, - get_object_info: Arc>>, - onchain_status: Arc>>, - - requested_transactions_tx: tokio::sync::broadcast::Sender, -} - -impl SuiMockClient { - pub fn default() -> Self { - Self { - chain_identifier: "".to_string(), - latest_checkpoint_sequence_number: 0, - events: Default::default(), - past_event_query_params: Default::default(), - events_by_tx_digest: Default::default(), - transaction_responses: Default::default(), - wildcard_transaction_response: Default::default(), - get_object_info: Default::default(), - onchain_status: Default::default(), - requested_transactions_tx: tokio::sync::broadcast::channel(10000).0, - } - } - - pub fn add_event_response( - &self, - package: ObjectID, - module: Identifier, - cursor: EventID, - events: EventPage, - ) { - self.events - .lock() - .unwrap() - .insert((package, module, cursor), events); - } - - pub fn add_events_by_tx_digest(&self, tx_digest: TransactionDigest, events: Vec) { - self.events_by_tx_digest - .lock() - .unwrap() - .insert(tx_digest, Ok(events)); - } - - pub fn add_events_by_tx_digest_error(&self, tx_digest: TransactionDigest) { - self.events_by_tx_digest.lock().unwrap().insert( - tx_digest, - Err(sui_sdk::error::Error::DataError("".to_string())), - ); - } - - pub fn add_transaction_response( - &self, - tx_digest: TransactionDigest, - response: BridgeResult, - ) { - self.transaction_responses - .lock() - .unwrap() - .insert(tx_digest, response); - } - - pub fn set_action_onchain_status(&self, action: &BridgeAction, status: BridgeActionStatus) { - self.onchain_status - .lock() - .unwrap() - .insert(action.digest(), status); - } - - pub fn set_wildcard_transaction_response( - &self, - response: BridgeResult, - ) { - *self.wildcard_transaction_response.lock().unwrap() = Some(response); - } - - pub fn add_gas_object_info(&self, gas_coin: GasCoin, object_ref: ObjectRef, owner: Owner) { - self.get_object_info - .lock() - .unwrap() - .insert(object_ref.0, (gas_coin, object_ref, owner)); - } - - pub fn subscribe_to_requested_transactions( - &self, - ) -> tokio::sync::broadcast::Receiver { - self.requested_transactions_tx.subscribe() - } -} - -#[async_trait] -impl SuiClientInner for SuiMockClient { - type Error = sui_sdk::error::Error; - - // Unwraps in this function: We assume the responses are pre-populated - // by the test before calling into this function. - async fn query_events( - &self, - query: EventFilter, - cursor: EventID, - ) -> Result { - let events = self.events.lock().unwrap(); - match query { - EventFilter::MoveEventModule { package, module } => { - self.past_event_query_params.lock().unwrap().push_back(( - package, - module.clone(), - cursor, - )); - Ok(events - .get(&(package, module.clone(), cursor)) - .cloned() - .unwrap_or_else(|| { - panic!( - "No preset events found for package: {:?}, module: {:?}, cursor: {:?}", - package, module, cursor - ) - })) - } - _ => unimplemented!(), - } - } - - async fn get_events_by_tx_digest( - &self, - tx_digest: TransactionDigest, - ) -> Result, Self::Error> { - let events = self.events_by_tx_digest.lock().unwrap(); - - match events - .get(&tx_digest) - .unwrap_or_else(|| panic!("No preset events found for tx_digest: {:?}", tx_digest)) - { - Ok(events) => Ok(events.clone()), - // sui_sdk::error::Error is not Clone - Err(_) => Err(sui_sdk::error::Error::DataError("".to_string())), - } - } - - async fn get_chain_identifier(&self) -> Result { - Ok(self.chain_identifier.clone()) - } - - async fn get_latest_checkpoint_sequence_number(&self) -> Result { - Ok(self.latest_checkpoint_sequence_number) - } - - async fn get_bridge_committee(&self) -> Result { - unimplemented!() - } - - async fn get_token_transfer_action_onchain_status( - &self, - action: &BridgeAction, - ) -> Result { - Ok(self - .onchain_status - .lock() - .unwrap() - .get(&action.digest()) - .cloned() - .unwrap_or(BridgeActionStatus::Pending)) - } - - async fn execute_transaction_block_with_effects( - &self, - tx: Transaction, - ) -> Result { - self.requested_transactions_tx.send(*tx.digest()).unwrap(); - match self.transaction_responses.lock().unwrap().get(tx.digest()) { - Some(response) => response.clone(), - None => self - .wildcard_transaction_response - .lock() - .unwrap() - .clone() - .unwrap_or_else(|| panic!("No preset transaction response found for tx: {:?}", tx)), - } - } - - async fn get_gas_data_panic_if_not_gas( - &self, - gas_object_id: ObjectID, - ) -> (GasCoin, ObjectRef, Owner) { - self.get_object_info - .lock() - .unwrap() - .get(&gas_object_id) - .cloned() - .unwrap_or_else(|| { - panic!( - "No preset gas object info found for gas_object_id: {:?}", - gas_object_id - ) - }) - } -} diff --git a/crates/sui-bridge/src/sui_syncer.rs b/crates/sui-bridge/src/sui_syncer.rs deleted file mode 100644 index 3f03ef751dc..00000000000 --- a/crates/sui-bridge/src/sui_syncer.rs +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//! The SuiSyncer module is responsible for synchronizing Events emitted on Sui -//! blockchain from concerned bridge packages. - -use std::{collections::HashMap, sync::Arc}; - -use mysten_metrics::spawn_logged_monitored_task; -use sui_json_rpc_types::SuiEvent; -use sui_types::{event::EventID, Identifier}; -use tokio::{ - task::JoinHandle, - time::{self, Duration}, -}; - -use crate::{ - error::BridgeResult, - retry_with_max_elapsed_time, - sui_client::{SuiClient, SuiClientInner}, - sui_transaction_builder::get_bridge_package_id, -}; - -// TODO: use the right package id -// const PACKAGE_ID: ObjectID = SUI_SYSTEM_PACKAGE_ID; -const SUI_EVENTS_CHANNEL_SIZE: usize = 1000; - -/// Map from contract address to their start cursor (exclusive) -pub type SuiTargetModules = HashMap; - -pub struct SuiSyncer { - sui_client: Arc>, - // The last transaction that the syncer has fully processed. - // Syncer will resume post this transaction (i.e. exclusive), when it starts. - cursors: SuiTargetModules, -} - -impl SuiSyncer -where - C: SuiClientInner + 'static, -{ - pub fn new(sui_client: Arc>, cursors: SuiTargetModules) -> Self { - Self { - sui_client, - cursors, - } - } - - pub async fn run( - self, - query_interval: Duration, - ) -> BridgeResult<( - Vec>, - mysten_metrics::metered_channel::Receiver<(Identifier, Vec)>, - )> { - let (events_tx, events_rx) = mysten_metrics::metered_channel::channel( - SUI_EVENTS_CHANNEL_SIZE, - &mysten_metrics::get_metrics() - .unwrap() - .channels - .with_label_values(&["sui_events_queue"]), - ); - - let mut task_handles = vec![]; - for (module, cursor) in self.cursors { - let events_rx_clone = events_tx.clone(); - let sui_client_clone = self.sui_client.clone(); - task_handles.push(spawn_logged_monitored_task!( - Self::run_event_listening_task( - module, - cursor, - events_rx_clone, - sui_client_clone, - query_interval - ) - )); - } - Ok((task_handles, events_rx)) - } - - async fn run_event_listening_task( - // The module where interested events are defined. - // Moudle is always of bridge package 0x9. - module: Identifier, - mut cursor: EventID, - events_sender: mysten_metrics::metered_channel::Sender<(Identifier, Vec)>, - sui_client: Arc>, - query_interval: Duration, - ) { - tracing::info!(?module, ?cursor, "Starting sui events listening task"); - let mut interval = time::interval(query_interval); - interval.set_missed_tick_behavior(time::MissedTickBehavior::Skip); - loop { - interval.tick().await; - let Ok(Ok(events)) = retry_with_max_elapsed_time!( - sui_client.query_events_by_module(*get_bridge_package_id(), module.clone(), cursor), - Duration::from_secs(10) - ) else { - tracing::error!("Failed to query events from sui client after retry"); - continue; - }; - - let len = events.data.len(); - if len != 0 { - // Note: it's extremely critical to make sure the SuiEvents we send via this - // channel are complete per transaction level. Namely, we should - // never send a partial list of events for a transaction. - // Otherwise, we may end up missing events. See `sui_client. - // query_events_by_module` for how this is implemented. - events_sender - .send((module.clone(), events.data)) - .await - .expect("All Sui event channel receivers are closed"); - if let Some(next) = events.next_cursor { - cursor = next; - } - tracing::info!(?module, ?cursor, "Observed {len} new Sui events"); - } - } - } -} - -#[cfg(test)] -mod tests { - use prometheus::Registry; - use sui_json_rpc_types::EventPage; - use sui_types::{digests::TransactionDigest, event::EventID, Identifier}; - use tokio::time::timeout; - - use super::*; - use crate::{sui_client::SuiClient, sui_mock_client::SuiMockClient}; - - #[tokio::test] - async fn test_sui_syncer_basic() -> anyhow::Result<()> { - telemetry_subscribers::init_for_testing(); - let registry = Registry::new(); - mysten_metrics::init_metrics(®istry); - - let mock = SuiMockClient::default(); - let client = Arc::new(SuiClient::new_for_testing(mock.clone())); - let module_foo = Identifier::new("Foo").unwrap(); - let module_bar = Identifier::new("Bar").unwrap(); - let empty_events = EventPage::empty(); - let cursor = EventID { - tx_digest: TransactionDigest::random(), - event_seq: 0, - }; - add_event_response(&mock, module_foo.clone(), cursor, empty_events.clone()); - add_event_response(&mock, module_bar.clone(), cursor, empty_events.clone()); - - let target_modules = HashMap::from_iter(vec![ - (module_foo.clone(), cursor), - (module_bar.clone(), cursor), - ]); - let interval = Duration::from_millis(200); - let (_handles, mut events_rx) = SuiSyncer::new(client, target_modules) - .run(interval) - .await - .unwrap(); - - // Initially there are no events - assert_no_more_events(interval, &mut events_rx).await; - - // Module Foo has new events - let mut event_1: SuiEvent = SuiEvent::random_for_testing(); - let package_id = *get_bridge_package_id(); - event_1.type_.address = package_id.into(); - event_1.type_.module = module_foo.clone(); - let module_foo_events_1: sui_json_rpc_types::Page = EventPage { - data: vec![event_1.clone(), event_1.clone()], - next_cursor: Some(event_1.id), - has_next_page: false, - }; - add_event_response(&mock, module_foo.clone(), event_1.id, empty_events.clone()); - add_event_response( - &mock, - module_foo.clone(), - cursor, - module_foo_events_1.clone(), - ); - - let (identifier, received_events) = events_rx.recv().await.unwrap(); - assert_eq!(identifier, module_foo); - assert_eq!(received_events.len(), 2); - assert_eq!(received_events[0].id, event_1.id); - assert_eq!(received_events[1].id, event_1.id); - // No more - assert_no_more_events(interval, &mut events_rx).await; - - // Module Bar has new events - let mut event_2: SuiEvent = SuiEvent::random_for_testing(); - event_2.type_.address = package_id.into(); - event_2.type_.module = module_bar.clone(); - let module_bar_events_1 = EventPage { - data: vec![event_2.clone()], - next_cursor: Some(event_2.id), - has_next_page: false, - }; - add_event_response(&mock, module_bar.clone(), event_2.id, empty_events.clone()); - - add_event_response(&mock, module_bar.clone(), cursor, module_bar_events_1); - - let (identifier, received_events) = events_rx.recv().await.unwrap(); - assert_eq!(identifier, module_bar); - assert_eq!(received_events.len(), 1); - assert_eq!(received_events[0].id, event_2.id); - // No more - assert_no_more_events(interval, &mut events_rx).await; - - Ok(()) - } - - async fn assert_no_more_events( - interval: Duration, - events_rx: &mut mysten_metrics::metered_channel::Receiver<(Identifier, Vec)>, - ) { - match timeout(interval * 2, events_rx.recv()).await { - Err(_e) => (), - other => panic!("Should have timed out, but got: {:?}", other), - }; - } - - fn add_event_response( - mock: &SuiMockClient, - module: Identifier, - cursor: EventID, - events: EventPage, - ) { - mock.add_event_response( - *get_bridge_package_id(), - module.clone(), - cursor, - events.clone(), - ); - } -} diff --git a/crates/sui-bridge/src/sui_transaction_builder.rs b/crates/sui-bridge/src/sui_transaction_builder.rs deleted file mode 100644 index 1ca31002c6a..00000000000 --- a/crates/sui-bridge/src/sui_transaction_builder.rs +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::HashMap, str::FromStr}; - -use fastcrypto::traits::ToFromBytes; -use move_core_types::ident_str; -use once_cell::sync::OnceCell; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress}, - gas_coin::GAS, - programmable_transaction_builder::ProgrammableTransactionBuilder, - transaction::{ObjectArg, TransactionData}, - TypeTag, -}; - -use crate::{ - error::{BridgeError, BridgeResult}, - types::{BridgeAction, TokenId, VerifiedCertifiedBridgeAction}, -}; - -// TODO: once we have bridge package on sui framework, we can hardcode the -// actual package id. -pub fn get_bridge_package_id() -> &'static ObjectID { - static BRIDGE_PACKAGE_ID: OnceCell = OnceCell::new(); - BRIDGE_PACKAGE_ID.get_or_init(|| match std::env::var("BRIDGE_PACKAGE_ID") { - Ok(id) => { - ObjectID::from_hex_literal(&id).expect("BRIDGE_PACKAGE_ID must be a valid hex string") - } - Err(_) => ObjectID::from_hex_literal("0x9").unwrap(), - }) -} - -// TODO: this should be hardcoded once we have bridge package on sui framework. -pub fn get_root_bridge_object_arg() -> &'static ObjectArg { - static ROOT_BRIDGE_OBJ_ID: OnceCell = OnceCell::new(); - ROOT_BRIDGE_OBJ_ID.get_or_init(|| { - let bridge_object_id = std::env::var("ROOT_BRIDGE_OBJECT_ID") - .expect("Expect ROOT_BRIDGE_OBJECT_ID env var set"); - let object_id = ObjectID::from_hex_literal(&bridge_object_id) - .expect("ROOT_BRIDGE_OBJECT_ID must be a valid hex string"); - let initial_shared_version = std::env::var("ROOT_BRIDGE_OBJECT_INITIAL_SHARED_VERSION") - .expect("Expect ROOT_BRIDGE_OBJECT_INITIAL_SHARED_VERSION env var set") - .parse::() - .expect("ROOT_BRIDGE_OBJECT_INITIAL_SHARED_VERSION must be a valid u64"); - ObjectArg::SharedObject { - id: object_id, - initial_shared_version: SequenceNumber::from_u64(initial_shared_version), - mutable: true, - } - }) -} - -// TODO: how do we generalize this thing more? -pub fn get_sui_token_type_tag(token_id: TokenId) -> TypeTag { - static TYPE_TAGS: OnceCell> = OnceCell::new(); - let type_tags = TYPE_TAGS.get_or_init(|| { - let package_id = get_bridge_package_id(); - let mut type_tags = HashMap::new(); - type_tags.insert(TokenId::Sui, GAS::type_tag()); - type_tags.insert( - TokenId::BTC, - TypeTag::from_str(&format!("{:?}::btc::BTC", package_id)).unwrap(), - ); - type_tags.insert( - TokenId::ETH, - TypeTag::from_str(&format!("{:?}::eth::ETH", package_id)).unwrap(), - ); - type_tags.insert( - TokenId::USDC, - TypeTag::from_str(&format!("{:?}::usdc::USDC", package_id)).unwrap(), - ); - type_tags.insert( - TokenId::USDT, - TypeTag::from_str(&format!("{:?}::usdt::USDT", package_id)).unwrap(), - ); - type_tags - }); - type_tags.get(&token_id).unwrap().clone() -} - -// TODO: pass in gas price -pub fn build_transaction( - client_address: SuiAddress, - gas_object_ref: &ObjectRef, - action: VerifiedCertifiedBridgeAction, -) -> BridgeResult { - match action.data() { - BridgeAction::EthToSuiBridgeAction(_) => { - build_token_bridge_approve_transaction(client_address, gas_object_ref, action, true) - } - BridgeAction::SuiToEthBridgeAction(_) => { - build_token_bridge_approve_transaction(client_address, gas_object_ref, action, false) - } - BridgeAction::BlocklistCommitteeAction(_) => { - // TODO: handle this case - unimplemented!() - } - BridgeAction::EmergencyAction(_) => { - // TODO: handle this case - unimplemented!() - } - BridgeAction::LimitUpdateAction(_) => { - // TODO: handle this case - unimplemented!() - } - BridgeAction::AssetPriceUpdateAction(_) => { - // TODO: handle this case - unimplemented!() - } - BridgeAction::EvmContractUpgradeAction(_) => { - // TODO: handle this case - unimplemented!() - } - } -} - -// TODO: pass in gas price -fn build_token_bridge_approve_transaction( - client_address: SuiAddress, - gas_object_ref: &ObjectRef, - action: VerifiedCertifiedBridgeAction, - claim: bool, -) -> BridgeResult { - let (bridge_action, sigs) = action.into_inner().into_data_and_sig(); - let mut builder = ProgrammableTransactionBuilder::new(); - - let (source_chain, seq_num, sender, target_chain, target, token_type, amount) = - match bridge_action { - BridgeAction::SuiToEthBridgeAction(a) => { - let bridge_event = a.sui_bridge_event; - ( - bridge_event.sui_chain_id, - bridge_event.nonce, - bridge_event.sui_address.to_vec(), - bridge_event.eth_chain_id, - bridge_event.eth_address.to_fixed_bytes().to_vec(), - bridge_event.token_id, - bridge_event.amount, - ) - } - BridgeAction::EthToSuiBridgeAction(a) => { - let bridge_event = a.eth_bridge_event; - ( - bridge_event.eth_chain_id, - bridge_event.nonce, - bridge_event.eth_address.to_fixed_bytes().to_vec(), - bridge_event.sui_chain_id, - bridge_event.sui_address.to_vec(), - bridge_event.token_id, - bridge_event.amount, - ) - } - _ => unreachable!(), - }; - - let source_chain = builder.pure(source_chain as u8).unwrap(); - let seq_num = builder.pure(seq_num).unwrap(); - let sender = builder.pure(sender.clone()).map_err(|e| { - BridgeError::BridgeSerializationError(format!( - "Failed to serialize sender: {:?}. Err: {:?}", - sender, e - )) - })?; - let target_chain = builder.pure(target_chain as u8).unwrap(); - let target = builder.pure(target.clone()).map_err(|e| { - BridgeError::BridgeSerializationError(format!( - "Failed to serialize target: {:?}. Err: {:?}", - target, e - )) - })?; - let arg_token_type = builder.pure(token_type as u8).unwrap(); - let amount = builder.pure(amount).unwrap(); - - let arg_msg = builder.programmable_move_call( - *get_bridge_package_id(), - ident_str!("message").to_owned(), - ident_str!("create_token_bridge_message").to_owned(), - vec![], - vec![ - source_chain, - seq_num, - sender, - target_chain, - target, - arg_token_type, - amount, - ], - ); - - // Unwrap: this should not fail - let arg_bridge = builder.obj(*get_root_bridge_object_arg()).unwrap(); - - let mut sig_bytes = vec![]; - for (_, sig) in sigs.signatures { - sig_bytes.push(sig.as_bytes().to_vec()); - } - let arg_signatures = builder.pure(sig_bytes.clone()).map_err(|e| { - BridgeError::BridgeSerializationError(format!( - "Failed to serialize signatures: {:?}. Err: {:?}", - sig_bytes, e - )) - })?; - - builder.programmable_move_call( - *get_bridge_package_id(), - ident_str!("bridge").to_owned(), - ident_str!("approve_bridge_message").to_owned(), - vec![], - vec![arg_bridge, arg_msg, arg_signatures], - ); - - if claim { - builder.programmable_move_call( - *get_bridge_package_id(), - ident_str!("bridge").to_owned(), - ident_str!("claim_and_transfer_token").to_owned(), - vec![get_sui_token_type_tag(token_type)], - vec![arg_bridge, source_chain, seq_num], - ); - } - - let pt = builder.finish(); - - Ok(TransactionData::new_programmable( - client_address, - vec![*gas_object_ref], - pt, - 15_000_000, - // TODO: use reference gas price - 1500, - )) -} diff --git a/crates/sui-bridge/src/test_utils.rs b/crates/sui-bridge/src/test_utils.rs deleted file mode 100644 index 09abab7492a..00000000000 --- a/crates/sui-bridge/src/test_utils.rs +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::BTreeMap, - net::{IpAddr, Ipv4Addr, SocketAddr}, - path::PathBuf, -}; - -use ethers::{ - abi::{long_signature, ParamType}, - types::{ - Address as EthAddress, Block, BlockNumber, Filter, FilterBlockOption, Log, - TransactionReceipt, TxHash, ValueOrArray, U64, - }, -}; -use fastcrypto::{ - encoding::{Encoding, Hex}, - traits::KeyPair, -}; -use hex_literal::hex; -use sui_config::local_ip_utils; -use sui_json_rpc_types::ObjectChange; -use sui_sdk::wallet_context::WalletContext; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ - base_types::{ObjectRef, SuiAddress}, - crypto::get_key_pair, - digests::TransactionDigest, - object::Owner, - transaction::{CallArg, ObjectArg}, - SUI_FRAMEWORK_PACKAGE_ID, -}; -use tokio::task::JoinHandle; - -use crate::{ - abi::EthToSuiTokenBridgeV1, - crypto::{BridgeAuthorityKeyPair, BridgeAuthorityPublicKey, BridgeAuthoritySignInfo}, - eth_mock_provider::EthMockProvider, - events::{EmittedSuiToEthTokenBridgeV1, SuiBridgeEvent}, - server::mock_handler::{run_mock_server, BridgeRequestMockHandler}, - sui_transaction_builder::{ - get_bridge_package_id, get_root_bridge_object_arg, get_sui_token_type_tag, - }, - types::{ - BridgeAction, BridgeAuthority, BridgeChainId, BridgeInnerDynamicField, - EthToSuiBridgeAction, SignedBridgeAction, SuiToEthBridgeAction, TokenId, - }, -}; - -pub fn get_test_authority_and_key( - voting_power: u64, - port: u16, -) -> ( - BridgeAuthority, - BridgeAuthorityPublicKey, - BridgeAuthorityKeyPair, -) { - let (_, kp): (_, fastcrypto::secp256k1::Secp256k1KeyPair) = get_key_pair(); - let pubkey = kp.public().clone(); - let authority = BridgeAuthority { - pubkey: pubkey.clone(), - voting_power, - base_url: format!("http://127.0.0.1:{}", port), - is_blocklisted: false, - }; - - (authority, pubkey, kp) -} - -pub fn get_test_sui_to_eth_bridge_action( - sui_tx_digest: Option, - sui_tx_event_index: Option, - nonce: Option, - amount: Option, -) -> BridgeAction { - BridgeAction::SuiToEthBridgeAction(SuiToEthBridgeAction { - sui_tx_digest: sui_tx_digest.unwrap_or_else(TransactionDigest::random), - sui_tx_event_index: sui_tx_event_index.unwrap_or(0), - sui_bridge_event: EmittedSuiToEthTokenBridgeV1 { - nonce: nonce.unwrap_or_default(), - sui_chain_id: BridgeChainId::SuiLocalTest, - sui_address: SuiAddress::random_for_testing_only(), - eth_chain_id: BridgeChainId::EthLocalTest, - eth_address: EthAddress::random(), - token_id: TokenId::Sui, - amount: amount.unwrap_or(100_000), - }, - }) -} - -pub fn run_mock_bridge_server( - mock_handlers: Vec, -) -> (Vec>, Vec) { - let mut handles = vec![]; - let mut ports = vec![]; - for mock_handler in mock_handlers { - let localhost = local_ip_utils::localhost_for_testing(); - let port = local_ip_utils::get_available_port(&localhost); - // start server - let server_handle = run_mock_server( - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port), - mock_handler.clone(), - ); - ports.push(port); - handles.push(server_handle); - } - (handles, ports) -} - -pub fn get_test_authorities_and_run_mock_bridge_server( - voting_power: Vec, - mock_handlers: Vec, -) -> ( - Vec>, - Vec, - Vec, -) { - assert_eq!(voting_power.len(), mock_handlers.len()); - let (handles, ports) = run_mock_bridge_server(mock_handlers); - let mut authorites = vec![]; - let mut secrets = vec![]; - for (port, vp) in ports.iter().zip(voting_power) { - let (authority, _, secret) = get_test_authority_and_key(vp, *port); - authorites.push(authority); - secrets.push(secret); - } - - (handles, authorites, secrets) -} - -pub fn sign_action_with_key( - action: &BridgeAction, - secret: &BridgeAuthorityKeyPair, -) -> SignedBridgeAction { - let sig = BridgeAuthoritySignInfo::new(action, secret); - SignedBridgeAction::new_from_data_and_sig(action.clone(), sig) -} - -pub fn mock_last_finalized_block(mock_provider: &EthMockProvider, block_number: u64) { - let block = Block:: { - number: Some(U64::from(block_number)), - ..Default::default() - }; - mock_provider - .add_response("eth_getBlockByNumber", ("finalized", false), block) - .unwrap(); -} - -// Mocks eth_getLogs and eth_getTransactionReceipt for the given address and -// block range. The input log needs to have transaction_hash set. -pub fn mock_get_logs( - mock_provider: &EthMockProvider, - address: EthAddress, - from_block: u64, - to_block: u64, - logs: Vec, -) { - mock_provider.add_response::<[ethers::types::Filter; 1], Vec, Vec>( - "eth_getLogs", - [ - Filter { - block_option: FilterBlockOption::Range { - from_block: Some(BlockNumber::Number(U64::from(from_block))), - to_block: Some(BlockNumber::Number(U64::from(to_block))), - }, - address: Some(ValueOrArray::Value(address)), - topics: [None, None, None, None], - } - ], - logs.clone(), - ).unwrap(); - - for log in logs { - mock_provider - .add_response::<[TxHash; 1], TransactionReceipt, TransactionReceipt>( - "eth_getTransactionReceipt", - [log.transaction_hash.unwrap()], - TransactionReceipt { - block_number: log.block_number, - logs: vec![log], - ..Default::default() - }, - ) - .unwrap(); - } -} - -/// Returns a test Log and corresponding BridgeAction -// Refernece: https://github.com/rust-ethereum/ethabi/blob/master/ethabi/src/event.rs#L192 -pub fn get_test_log_and_action( - contract_address: EthAddress, - tx_hash: TxHash, - event_index: u16, -) -> (Log, BridgeAction) { - let token_code = 3u8; - let amount = 10000000u64; - let source_address = EthAddress::random(); - let sui_address: SuiAddress = SuiAddress::random_for_testing_only(); - let target_address = Hex::decode(&sui_address.to_string()).unwrap(); - // Note: must use `encode` rather than `encode_packged` - let encoded = ethers::abi::encode(&[ - // u8 is encoded as u256 in abi standard - ethers::abi::Token::Uint(ethers::types::U256::from(token_code)), - ethers::abi::Token::Uint(ethers::types::U256::from(amount)), - ethers::abi::Token::Address(source_address), - ethers::abi::Token::Bytes(target_address.clone()), - ]); - let log = Log { - address: contract_address, - topics: vec![ - long_signature( - "TokensBridgedToSui", - &[ - ParamType::Uint(8), - ParamType::Uint(64), - ParamType::Uint(8), - ParamType::Uint(8), - ParamType::Uint(64), - ParamType::Address, - ParamType::Bytes, - ], - ), - hex!("0000000000000000000000000000000000000000000000000000000000000001").into(), /* chain id: sui testnet */ - hex!("0000000000000000000000000000000000000000000000000000000000000010").into(), /* nonce: 16 */ - hex!("000000000000000000000000000000000000000000000000000000000000000b").into(), /* chain id: sepolia */ - ], - data: encoded.into(), - block_hash: Some(TxHash::random()), - block_number: Some(1.into()), - transaction_hash: Some(tx_hash), - log_index: Some(0.into()), - ..Default::default() - }; - let topic_1: [u8; 32] = log.topics[1].into(); - let topic_3: [u8; 32] = log.topics[3].into(); - - let bridge_action = BridgeAction::EthToSuiBridgeAction(EthToSuiBridgeAction { - eth_tx_hash: tx_hash, - eth_event_index: event_index, - eth_bridge_event: EthToSuiTokenBridgeV1 { - eth_chain_id: BridgeChainId::try_from(topic_1[topic_1.len() - 1]).unwrap(), - nonce: u64::from_be_bytes(log.topics[2].as_ref()[24..32].try_into().unwrap()), - sui_chain_id: BridgeChainId::try_from(topic_3[topic_3.len() - 1]).unwrap(), - token_id: TokenId::try_from(token_code).unwrap(), - amount, - sui_address, - eth_address: source_address, - }, - }); - (log, bridge_action) -} - -pub async fn publish_bridge_package(context: &WalletContext) -> BTreeMap { - let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); - let gas_price = context.get_reference_gas_price().await.unwrap(); - - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.extend(["..", "..", "examples", "move", "bridge"]); - - let txn = context.sign_transaction( - &TestTransactionBuilder::new(sender, gas_object, gas_price) - .publish(path) - .build(), - ); - let resp = context.execute_transaction_must_succeed(txn).await; - let object_changes = resp.object_changes.unwrap(); - let package_id = object_changes - .iter() - .find(|change| matches!(change, ObjectChange::Published { .. })) - .map(|change| change.object_id()) - .unwrap(); - - let mut treasury_caps = BTreeMap::new(); - object_changes.iter().for_each(|change| { - if let ObjectChange::Created { object_type, .. } = change { - let object_type_str = object_type.to_string(); - if object_type_str.contains("TreasuryCap") { - if object_type_str.contains("BTC") { - treasury_caps.insert(TokenId::BTC, change.object_ref()); - } else if object_type_str.contains("ETH") { - treasury_caps.insert(TokenId::ETH, change.object_ref()); - } else if object_type_str.contains("USDC") { - treasury_caps.insert(TokenId::USDC, change.object_ref()); - } else if object_type_str.contains("USDT") { - treasury_caps.insert(TokenId::USDT, change.object_ref()); - } - } - } - }); - - let root_bridge_object_ref = object_changes - .iter() - .find(|change| match change { - ObjectChange::Created { - object_type, owner, .. - } => { - object_type.to_string().contains("Bridge") && matches!(owner, Owner::Shared { .. }) - } - _ => false, - }) - .map(|change| change.object_ref()) - .unwrap(); - - let bridge_inner_object_ref = object_changes - .iter() - .find(|change| match change { - ObjectChange::Created { object_type, .. } => { - object_type.to_string().contains("BridgeInner") - } - _ => false, - }) - .map(|change| change.object_ref()) - .unwrap(); - - let client = context.get_client().await.unwrap(); - let bcs_bytes = client - .read_api() - .get_move_object_bcs(bridge_inner_object_ref.0) - .await - .unwrap(); - let bridge_inner_object: BridgeInnerDynamicField = bcs::from_bytes(&bcs_bytes).unwrap(); - let bridge_record_id = bridge_inner_object.value.bridge_records.id; - - // TODO: remove once we don't rely on env var to get package id - std::env::set_var("BRIDGE_PACKAGE_ID", package_id.to_string()); - std::env::set_var("BRIDGE_RECORD_ID", bridge_record_id.to_string()); - std::env::set_var( - "ROOT_BRIDGE_OBJECT_ID", - root_bridge_object_ref.0.to_string(), - ); - std::env::set_var( - "ROOT_BRIDGE_OBJECT_INITIAL_SHARED_VERSION", - u64::from(root_bridge_object_ref.1).to_string(), - ); - std::env::set_var("BRIDGE_OBJECT_ID", bridge_inner_object_ref.0.to_string()); - - treasury_caps -} - -pub async fn mint_tokens( - context: &mut WalletContext, - treasury_cap_ref: ObjectRef, - amount: u64, - token_id: TokenId, -) -> (ObjectRef, ObjectRef) { - let rgp = context.get_reference_gas_price().await.unwrap(); - let sender = context.active_address().unwrap(); - let gas_obj_ref = context.get_one_gas_object().await.unwrap().unwrap().1; - let tx = TestTransactionBuilder::new(sender, gas_obj_ref, rgp) - .move_call( - SUI_FRAMEWORK_PACKAGE_ID, - "coin", - "mint_and_transfer", - vec![ - CallArg::Object(ObjectArg::ImmOrOwnedObject(treasury_cap_ref)), - CallArg::Pure(bcs::to_bytes(&amount).unwrap()), - CallArg::Pure(sender.to_vec()), - ], - ) - .with_type_args(vec![get_sui_token_type_tag(token_id)]) - .build(); - let signed_tn = context.sign_transaction(&tx); - let resp = context.execute_transaction_must_succeed(signed_tn).await; - let object_changes = resp.object_changes.unwrap(); - - let treasury_cap_obj_ref = object_changes - .iter() - .find(|change| matches!(change, ObjectChange::Mutated { object_type, .. } if object_type.to_string().contains("TreasuryCap"))) - .map(|change| change.object_ref()) - .unwrap(); - - let minted_coin_obj_ref = object_changes - .iter() - .find(|change| matches!(change, ObjectChange::Created { .. })) - .map(|change| change.object_ref()) - .unwrap(); - - (treasury_cap_obj_ref, minted_coin_obj_ref) -} - -pub async fn transfer_treasury_cap( - context: &mut WalletContext, - treasury_cap_ref: ObjectRef, - token_id: TokenId, -) { - let rgp = context.get_reference_gas_price().await.unwrap(); - let sender = context.active_address().unwrap(); - let gas_object = context.get_one_gas_object().await.unwrap().unwrap().1; - let tx = TestTransactionBuilder::new(sender, gas_object, rgp) - .move_call( - *get_bridge_package_id(), - "bridge", - "add_treasury_cap", - vec![ - CallArg::Object(*get_root_bridge_object_arg()), - CallArg::Object(ObjectArg::ImmOrOwnedObject(treasury_cap_ref)), - ], - ) - .with_type_args(vec![get_sui_token_type_tag(token_id)]) - .build(); - let signed_tn = context.sign_transaction(&tx); - context.execute_transaction_must_succeed(signed_tn).await; -} - -pub async fn bridge_token( - context: &mut WalletContext, - recv_address: EthAddress, - token_ref: ObjectRef, - token_id: TokenId, -) -> EmittedSuiToEthTokenBridgeV1 { - let rgp = context.get_reference_gas_price().await.unwrap(); - let sender = context.active_address().unwrap(); - let gas_object = context.get_one_gas_object().await.unwrap().unwrap().1; - let tx = TestTransactionBuilder::new(sender, gas_object, rgp) - .move_call( - *get_bridge_package_id(), - "bridge", - "send_token", - vec![ - CallArg::Object(*get_root_bridge_object_arg()), - CallArg::Pure(bcs::to_bytes(&(BridgeChainId::EthLocalTest as u8)).unwrap()), - CallArg::Pure(bcs::to_bytes(&recv_address.as_bytes()).unwrap()), - CallArg::Object(ObjectArg::ImmOrOwnedObject(token_ref)), - ], - ) - .with_type_args(vec![get_sui_token_type_tag(token_id)]) - .build(); - let signed_tn = context.sign_transaction(&tx); - let resp = context.execute_transaction_must_succeed(signed_tn).await; - let events = resp.events.unwrap(); - let mut bridge_events = events - .data - .iter() - .filter_map(|event| SuiBridgeEvent::try_from_sui_event(event).unwrap()) - .collect::>(); - assert_eq!(bridge_events.len(), 1); - match bridge_events.remove(0) { - SuiBridgeEvent::SuiToEthTokenBridgeV1(event) => event, - } -} diff --git a/crates/sui-bridge/src/types.rs b/crates/sui-bridge/src/types.rs deleted file mode 100644 index cdc182d557d..00000000000 --- a/crates/sui-bridge/src/types.rs +++ /dev/null @@ -1,1325 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::{BTreeMap, BTreeSet}; - -pub use ethers::types::H256 as EthTransactionHash; -use ethers::types::{Address as EthAddress, Log, H256}; -use fastcrypto::hash::{HashFunction, Keccak256}; -use num_enum::TryFromPrimitive; -use rand::{seq::SliceRandom, Rng}; -use serde::{Deserialize, Serialize}; -use shared_crypto::intent::IntentScope; -use sui_types::{ - base_types::{SuiAddress, SUI_ADDRESS_LENGTH}, - collection_types::{Bag, LinkedTable, LinkedTableNode, VecMap}, - committee::{CommitteeTrait, EpochId, StakeUnit}, - digests::{Digest, TransactionDigest}, - dynamic_field::Field, - error::SuiResult, - message_envelope::{Envelope, Message, VerifiedEnvelope}, -}; - -use crate::{ - abi::EthToSuiTokenBridgeV1, - crypto::{ - BridgeAuthorityPublicKey, BridgeAuthorityPublicKeyBytes, - BridgeAuthorityRecoverableSignature, BridgeAuthoritySignInfo, - }, - error::{BridgeError, BridgeResult}, - events::EmittedSuiToEthTokenBridgeV1, -}; - -pub const BRIDGE_AUTHORITY_TOTAL_VOTING_POWER: u64 = 10000; - -pub const USD_MULTIPLIER: u64 = 10000; // decimal places = 4 - -pub type BridgeInnerDynamicField = Field; -pub type BridgeRecordDyanmicField = Field< - MoveTypeBridgeMessageKey, - LinkedTableNode, ->; - -#[derive(Debug, Eq, PartialEq, Clone)] -pub struct BridgeAuthority { - pub pubkey: BridgeAuthorityPublicKey, - pub voting_power: u64, - pub base_url: String, - pub is_blocklisted: bool, -} - -impl BridgeAuthority { - pub fn pubkey_bytes(&self) -> BridgeAuthorityPublicKeyBytes { - BridgeAuthorityPublicKeyBytes::from(&self.pubkey) - } -} - -// A static Bridge committee implementation -#[derive(Debug, Clone)] -pub struct BridgeCommittee { - members: BTreeMap, - total_blocklisted_stake: StakeUnit, -} - -impl BridgeCommittee { - pub fn new(members: Vec) -> BridgeResult { - let mut members_map = BTreeMap::new(); - let mut total_stake = 0; - let mut total_blocklisted_stake = 0; - for member in members { - let public_key = BridgeAuthorityPublicKeyBytes::from(&member.pubkey); - if members_map.contains_key(&public_key) { - return Err(BridgeError::InvalidBridgeCommittee( - "Duplicate BridgeAuthority Public key".into(), - )); - } - // TODO: should we disallow identical network addresses? - total_stake += member.voting_power; - if member.is_blocklisted { - total_blocklisted_stake += member.voting_power; - } - members_map.insert(public_key, member); - } - if total_stake != BRIDGE_AUTHORITY_TOTAL_VOTING_POWER { - return Err(BridgeError::InvalidBridgeCommittee( - "Total voting power does not equal to 10000".into(), - )); - } - Ok(Self { - members: members_map, - total_blocklisted_stake, - }) - } - - pub fn is_active_member(&self, member: &BridgeAuthorityPublicKeyBytes) -> bool { - self.members.contains_key(member) && !self.members.get(member).unwrap().is_blocklisted - } - - pub fn members(&self) -> &BTreeMap { - &self.members - } - - pub fn member(&self, member: &BridgeAuthorityPublicKeyBytes) -> Option<&BridgeAuthority> { - self.members.get(member) - } - - pub fn total_blocklisted_stake(&self) -> StakeUnit { - self.total_blocklisted_stake - } -} - -impl CommitteeTrait for BridgeCommittee { - // Note: - // 1. preference is not supported today. - // 2. blocklisted members are always excluded. - fn shuffle_by_stake_with_rng( - &self, - // preference is not supported today - _preferences: Option<&BTreeSet>, - // only attempt from these authorities. - restrict_to: Option<&BTreeSet>, - rng: &mut impl Rng, - ) -> Vec { - let candidates = self - .members - .iter() - .filter_map(|(name, a)| { - // Remove blocklisted members - if a.is_blocklisted { - return None; - } - // exclude non-allowlisted members - if let Some(restrict_to) = restrict_to { - match restrict_to.contains(name) { - true => Some((name.clone(), a.voting_power)), - false => None, - } - } else { - Some((name.clone(), a.voting_power)) - } - }) - .collect::>(); - - candidates - .choose_multiple_weighted(rng, candidates.len(), |(_, weight)| *weight as f64) - // Unwrap safe: it panics when the third parameter is larger than the size of the slice - .unwrap() - .map(|(name, _)| name) - .cloned() - .collect() - } - - fn weight(&self, author: &BridgeAuthorityPublicKeyBytes) -> StakeUnit { - self.members - .get(author) - .map(|a| a.voting_power) - .unwrap_or(0) - } -} - -#[derive(Copy, Clone, PartialEq, Eq)] -#[repr(u8)] -pub enum BridgeActionType { - TokenTransfer = 0, - UpdateCommitteeBlocklist = 1, - EmergencyButton = 2, - LimitUpdate = 3, - AssetPriceUpdate = 4, - EvmContractUpgrade = 5, -} - -pub const SUI_TX_DIGEST_LENGTH: usize = 32; -pub const ETH_TX_HASH_LENGTH: usize = 32; - -pub const BRIDGE_MESSAGE_PREFIX: &[u8] = b"SUI_BRIDGE_MESSAGE"; - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, TryFromPrimitive, Hash)] -#[repr(u8)] -pub enum BridgeChainId { - SuiMainnet = 0, - SuiTestnet = 1, - SuiDevnet = 2, - SuiLocalTest = 3, - - EthMainnet = 10, - EthSepolia = 11, - EthLocalTest = 12, -} - -#[derive( - Copy, - Clone, - Debug, - PartialEq, - Eq, - Serialize, - Deserialize, - TryFromPrimitive, - Hash, - Ord, - PartialOrd, -)] -#[repr(u8)] -pub enum TokenId { - Sui = 0, - BTC = 1, - ETH = 2, - USDC = 3, - USDT = 4, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum BridgeActionStatus { - RecordNotFound, - Pending, - Approved, - Claimed, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] -pub struct SuiToEthBridgeAction { - // Digest of the transaction where the event was emitted - pub sui_tx_digest: TransactionDigest, - // The index of the event in the transaction - pub sui_tx_event_index: u16, - pub sui_bridge_event: EmittedSuiToEthTokenBridgeV1, -} - -impl SuiToEthBridgeAction { - pub fn to_bytes(&self) -> Vec { - let mut bytes = Vec::new(); - let e = &self.sui_bridge_event; - // Add message type - bytes.push(BridgeActionType::TokenTransfer as u8); - // Add message version - bytes.push(TOKEN_TRANSFER_MESSAGE_VERSION); - // Add nonce - bytes.extend_from_slice(&e.nonce.to_be_bytes()); - // Add source chain id - bytes.push(e.sui_chain_id as u8); - - // Add source address length - bytes.push(SUI_ADDRESS_LENGTH as u8); - // Add source address - bytes.extend_from_slice(&e.sui_address.to_vec()); - // Add dest chain id - bytes.push(e.eth_chain_id as u8); - // Add dest address length - bytes.push(EthAddress::len_bytes() as u8); - // Add dest address - bytes.extend_from_slice(e.eth_address.as_bytes()); - - // Add token id - bytes.push(e.token_id as u8); - - // Add token amount - bytes.extend_from_slice(&e.amount.to_be_bytes()); - - bytes - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] -pub struct EthToSuiBridgeAction { - // Digest of the transaction where the event was emitted - pub eth_tx_hash: EthTransactionHash, - // The index of the event in the transaction - pub eth_event_index: u16, - pub eth_bridge_event: EthToSuiTokenBridgeV1, -} - -impl EthToSuiBridgeAction { - pub fn to_bytes(&self) -> Vec { - let mut bytes = Vec::new(); - let e = &self.eth_bridge_event; - // Add message type - bytes.push(BridgeActionType::TokenTransfer as u8); - // Add message version - bytes.push(TOKEN_TRANSFER_MESSAGE_VERSION); - // Add nonce - bytes.extend_from_slice(&e.nonce.to_be_bytes()); - // Add source chain id - bytes.push(e.eth_chain_id as u8); - - // Add source address length - bytes.push(EthAddress::len_bytes() as u8); - // Add source address - bytes.extend_from_slice(e.eth_address.as_bytes()); - // Add dest chain id - bytes.push(e.sui_chain_id as u8); - // Add dest address length - bytes.push(SUI_ADDRESS_LENGTH as u8); - // Add dest address - bytes.extend_from_slice(&e.sui_address.to_vec()); - - // Add token id - bytes.push(e.token_id as u8); - - // Add token amount - bytes.extend_from_slice(&e.amount.to_be_bytes()); - - bytes - } -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, TryFromPrimitive, Hash)] -#[repr(u8)] -pub enum BlocklistType { - Blocklist = 0, - Unblocklist = 1, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] -pub struct BlocklistCommitteeAction { - pub nonce: u64, - pub chain_id: BridgeChainId, - pub blocklist_type: BlocklistType, - pub blocklisted_members: Vec, -} - -impl BlocklistCommitteeAction { - pub fn to_bytes(&self) -> Vec { - let mut bytes = Vec::new(); - // Add message type - bytes.push(BridgeActionType::UpdateCommitteeBlocklist as u8); - // Add message version - bytes.push(COMMITTEE_BLOCKLIST_MESSAGE_VERSION); - // Add nonce - bytes.extend_from_slice(&self.nonce.to_be_bytes()); - // Add chain id - bytes.push(self.chain_id as u8); - // Add blocklist type - bytes.push(self.blocklist_type as u8); - // Add length of updated members. - // Unwrap: It should not overflow given what we have today. - bytes.push(u8::try_from(self.blocklisted_members.len()).unwrap()); - - // Add list of updated members - // Members are represented as pubkey dervied evm addresses (20 bytes) - let members_bytes = self - .blocklisted_members - .iter() - .map(|m| m.to_eth_address().to_fixed_bytes().to_vec()) - .collect::>(); - for members_bytes in members_bytes { - bytes.extend_from_slice(&members_bytes); - } - bytes - } -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, TryFromPrimitive, Hash)] -#[repr(u8)] -pub enum EmergencyActionType { - Pause = 0, - Unpause = 1, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] -pub struct EmergencyAction { - pub nonce: u64, - pub chain_id: BridgeChainId, - pub action_type: EmergencyActionType, -} - -impl EmergencyAction { - pub fn to_bytes(&self) -> Vec { - let mut bytes = Vec::new(); - // Add message type - bytes.push(BridgeActionType::EmergencyButton as u8); - // Add message version - bytes.push(EMERGENCY_BUTTON_MESSAGE_VERSION); - // Add nonce - bytes.extend_from_slice(&self.nonce.to_be_bytes()); - // Add chain id - bytes.push(self.chain_id as u8); - // Add action type - bytes.push(self.action_type as u8); - bytes - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] -pub struct LimitUpdateAction { - pub nonce: u64, - // The chain id that will receive this signed action. It's also the destination chain id - // for the limit update. For example, if chain_id is EthMainnet and sending_chain_id is - // SuiMainnet, it means we want to update the limit for the SuiMainnet to EthMainnet route. - pub chain_id: BridgeChainId, - // The sending chain id for the limit update. - pub sending_chain_id: BridgeChainId, - pub new_usd_limit: u64, -} - -impl LimitUpdateAction { - pub fn to_bytes(&self) -> Vec { - let mut bytes = Vec::new(); - // Add message type - bytes.push(BridgeActionType::LimitUpdate as u8); - // Add message version - bytes.push(LIMIT_UPDATE_MESSAGE_VERSION); - // Add nonce - bytes.extend_from_slice(&self.nonce.to_be_bytes()); - // Add chain id - bytes.push(self.chain_id as u8); - // Add sending chain id - bytes.push(self.sending_chain_id as u8); - // Add new usd limit - bytes.extend_from_slice(&self.new_usd_limit.to_be_bytes()); - bytes - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] -pub struct AssetPriceUpdateAction { - pub nonce: u64, - pub chain_id: BridgeChainId, - pub token_id: TokenId, - pub new_usd_price: u64, -} - -impl AssetPriceUpdateAction { - pub fn to_bytes(&self) -> Vec { - let mut bytes = Vec::new(); - // Add message type - bytes.push(BridgeActionType::AssetPriceUpdate as u8); - // Add message version - bytes.push(EMERGENCY_BUTTON_MESSAGE_VERSION); - // Add nonce - bytes.extend_from_slice(&self.nonce.to_be_bytes()); - // Add chain id - bytes.push(self.chain_id as u8); - // Add token id - bytes.push(self.token_id as u8); - // Add new usd limit - bytes.extend_from_slice(&self.new_usd_price.to_be_bytes()); - bytes - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] -pub struct EvmContractUpgradeAction { - pub nonce: u64, - pub chain_id: BridgeChainId, - pub proxy_address: EthAddress, - pub new_impl_address: EthAddress, - pub call_data: Vec, -} - -impl EvmContractUpgradeAction { - pub fn to_bytes(&self) -> Vec { - let mut bytes = Vec::new(); - // Add message type - bytes.push(BridgeActionType::EvmContractUpgrade as u8); - // Add message version - bytes.push(EVM_CONTRACT_UPGRADE_MESSAGE_VERSION); - // Add nonce - bytes.extend_from_slice(&self.nonce.to_be_bytes()); - // Add chain id - bytes.push(self.chain_id as u8); - // Add payload - let encoded = ethers::abi::encode(&[ - ethers::abi::Token::Address(self.proxy_address), - ethers::abi::Token::Address(self.new_impl_address), - ethers::abi::Token::Bytes(self.call_data.clone()), - ]); - bytes.extend_from_slice(&encoded); - bytes - } -} - -/// The type of actions Bridge Committee verify and sign off to execution. -/// Its relationship with BridgeEvent is similar to the relationship between -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] -pub enum BridgeAction { - /// Sui to Eth bridge action - SuiToEthBridgeAction(SuiToEthBridgeAction), - /// Eth to sui bridge action - EthToSuiBridgeAction(EthToSuiBridgeAction), - BlocklistCommitteeAction(BlocklistCommitteeAction), - EmergencyAction(EmergencyAction), - LimitUpdateAction(LimitUpdateAction), - AssetPriceUpdateAction(AssetPriceUpdateAction), - EvmContractUpgradeAction(EvmContractUpgradeAction), - // TODO: add other bridge actions such as blocklist & emergency button -} - -pub const TOKEN_TRANSFER_MESSAGE_VERSION: u8 = 1; -pub const COMMITTEE_BLOCKLIST_MESSAGE_VERSION: u8 = 1; -pub const EMERGENCY_BUTTON_MESSAGE_VERSION: u8 = 1; -pub const LIMIT_UPDATE_MESSAGE_VERSION: u8 = 1; -pub const ASSET_PRICE_UPDATE_MESSAGE_VERSION: u8 = 1; -pub const EVM_CONTRACT_UPGRADE_MESSAGE_VERSION: u8 = 1; - -impl BridgeAction { - /// Convert to message bytes that are verified in Move and Solidity - pub fn to_bytes(&self) -> Vec { - let mut bytes = Vec::new(); - // Add prefix - bytes.extend_from_slice(BRIDGE_MESSAGE_PREFIX); - match self { - BridgeAction::SuiToEthBridgeAction(a) => { - bytes.extend_from_slice(&a.to_bytes()); - } - BridgeAction::EthToSuiBridgeAction(a) => { - bytes.extend_from_slice(&a.to_bytes()); - } - BridgeAction::BlocklistCommitteeAction(a) => { - bytes.extend_from_slice(&a.to_bytes()); - } - BridgeAction::EmergencyAction(a) => { - bytes.extend_from_slice(&a.to_bytes()); - } - BridgeAction::LimitUpdateAction(a) => { - bytes.extend_from_slice(&a.to_bytes()); - } - BridgeAction::AssetPriceUpdateAction(a) => { - bytes.extend_from_slice(&a.to_bytes()); - } - BridgeAction::EvmContractUpgradeAction(a) => { - bytes.extend_from_slice(&a.to_bytes()); - } // TODO add formats for other events - } - bytes - } - - // Digest of BridgeAction (with Keccak256 hasher) - pub fn digest(&self) -> BridgeActionDigest { - let mut hasher = Keccak256::default(); - hasher.update(&self.to_bytes()); - BridgeActionDigest::new(hasher.finalize().into()) - } - - pub fn chain_id(&self) -> BridgeChainId { - match self { - BridgeAction::SuiToEthBridgeAction(a) => a.sui_bridge_event.sui_chain_id, - BridgeAction::EthToSuiBridgeAction(a) => a.eth_bridge_event.eth_chain_id, - BridgeAction::BlocklistCommitteeAction(a) => a.chain_id, - BridgeAction::EmergencyAction(a) => a.chain_id, - BridgeAction::LimitUpdateAction(a) => a.chain_id, - BridgeAction::AssetPriceUpdateAction(a) => a.chain_id, - BridgeAction::EvmContractUpgradeAction(a) => a.chain_id, - } - } - - pub fn is_governace_action(&self) -> bool { - match self.action_type() { - BridgeActionType::TokenTransfer => false, - BridgeActionType::UpdateCommitteeBlocklist => true, - BridgeActionType::EmergencyButton => true, - BridgeActionType::LimitUpdate => true, - BridgeActionType::AssetPriceUpdate => true, - BridgeActionType::EvmContractUpgrade => true, - } - } - - // Also called `message_type` - pub fn action_type(&self) -> BridgeActionType { - match self { - BridgeAction::SuiToEthBridgeAction(_) => BridgeActionType::TokenTransfer, - BridgeAction::EthToSuiBridgeAction(_) => BridgeActionType::TokenTransfer, - BridgeAction::BlocklistCommitteeAction(_) => BridgeActionType::UpdateCommitteeBlocklist, - BridgeAction::EmergencyAction(_) => BridgeActionType::EmergencyButton, - BridgeAction::LimitUpdateAction(_) => BridgeActionType::LimitUpdate, - BridgeAction::AssetPriceUpdateAction(_) => BridgeActionType::AssetPriceUpdate, - BridgeAction::EvmContractUpgradeAction(_) => BridgeActionType::EvmContractUpgrade, - } - } - - // Also called `nonce` - pub fn seq_number(&self) -> u64 { - match self { - BridgeAction::SuiToEthBridgeAction(a) => a.sui_bridge_event.nonce, - BridgeAction::EthToSuiBridgeAction(a) => a.eth_bridge_event.nonce, - BridgeAction::BlocklistCommitteeAction(a) => a.nonce, - BridgeAction::EmergencyAction(a) => a.nonce, - BridgeAction::LimitUpdateAction(a) => a.nonce, - BridgeAction::AssetPriceUpdateAction(a) => a.nonce, - BridgeAction::EvmContractUpgradeAction(a) => a.nonce, - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub struct BridgeActionDigest(Digest); - -impl BridgeActionDigest { - pub const fn new(digest: [u8; 32]) -> Self { - Self(Digest::new(digest)) - } -} - -#[derive(Debug, Clone)] -pub struct BridgeCommitteeValiditySignInfo { - pub signatures: BTreeMap, -} - -pub type SignedBridgeAction = Envelope; -pub type VerifiedSignedBridgeAction = VerifiedEnvelope; -pub type CertifiedBridgeAction = Envelope; -pub type VerifiedCertifiedBridgeAction = - VerifiedEnvelope; - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct BridgeEventDigest(Digest); - -impl BridgeEventDigest { - pub const fn new(digest: [u8; 32]) -> Self { - Self(Digest::new(digest)) - } -} - -impl Message for BridgeAction { - type DigestType = BridgeEventDigest; - - // this is not encoded in message today - const SCOPE: IntentScope = IntentScope::BridgeEventUnused; - - // this is not used today - fn digest(&self) -> Self::DigestType { - unreachable!("BridgeEventDigest is not used today") - } - - fn verify_user_input(&self) -> SuiResult { - Ok(()) - } - - fn verify_epoch(&self, _epoch: EpochId) -> SuiResult { - Ok(()) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EthLog { - pub block_number: u64, - pub tx_hash: H256, - pub log_index_in_tx: u16, - // TODO: pull necessary fields from `Log`. - pub log: Log, -} - -/////////////////////////// Move Types Start ////////////////////////// - -/// Rust version of the Move bridge::BridgeInner type. -#[derive(Debug, Serialize, Deserialize)] -pub struct MoveTypeBridgeInner { - pub bridge_version: u64, - pub chain_id: u8, - pub sequence_nums: VecMap, - pub committee: MoveTypeBridgeCommittee, - pub treasury: MoveTypeBridgeTreasury, - pub bridge_records: LinkedTable, - pub frozen: bool, -} - -/// Rust version of the Move treasury::BridgeTreasury type. -#[derive(Debug, Serialize, Deserialize)] -pub struct MoveTypeBridgeTreasury { - pub treasuries: Bag, -} - -/// Rust version of the Move committee::BridgeCommittee type. -#[derive(Debug, Serialize, Deserialize)] -pub struct MoveTypeBridgeCommittee { - pub members: VecMap, MoveTypeCommitteeMember>, - pub thresholds: VecMap, -} - -/// Rust version of the Move committee::CommitteeMember type. -#[derive(Debug, Serialize, Deserialize)] -pub struct MoveTypeCommitteeMember { - pub sui_address: SuiAddress, - pub bridge_pubkey_bytes: Vec, - pub voting_power: u64, - pub http_rest_url: Vec, - pub blocklisted: bool, -} - -/// Rust version of the Move message::BridgeMessageKey type. -#[derive(Debug, Serialize, Deserialize)] -pub struct MoveTypeBridgeMessageKey { - pub source_chain: u8, - pub message_type: u8, - pub bridge_seq_num: u64, -} - -/// Rust version of the Move message::BridgeMessage type. -#[derive(Debug, Serialize, Deserialize)] -pub struct MoveTypeBridgeMessage { - pub message_type: u8, - pub message_version: u8, - pub seq_num: u64, - pub source_chain: u8, - pub payload: Vec, -} - -/// Rust version of the Move message::BridgeMessage type. -#[derive(Debug, Serialize, Deserialize)] -pub struct MoveTypeBridgeRecord { - pub message: MoveTypeBridgeMessage, - pub verified_signatures: Option>>, - pub claimed: bool, -} - -/////////////////////////// Move Types End ////////////////////////// - -#[cfg(test)] -mod tests { - use std::{collections::HashSet, str::FromStr}; - - use ethers::{ - abi::ParamType, - types::{Address as EthAddress, TxHash}, - }; - use fastcrypto::{ - encoding::{Encoding, Hex}, - hash::HashFunction, - traits::{KeyPair, ToFromBytes}, - }; - use prometheus::Registry; - use sui_types::{ - base_types::{SuiAddress, TransactionDigest}, - crypto::get_key_pair, - }; - - use super::*; - use crate::{test_utils::get_test_authority_and_key, types::TokenId}; - - #[test] - fn test_bridge_message_encoding() -> anyhow::Result<()> { - telemetry_subscribers::init_for_testing(); - let registry = Registry::new(); - mysten_metrics::init_metrics(®istry); - let nonce = 54321u64; - let sui_tx_digest = TransactionDigest::random(); - let sui_chain_id = BridgeChainId::SuiTestnet; - let sui_tx_event_index = 1u16; - let eth_chain_id = BridgeChainId::EthSepolia; - let sui_address = SuiAddress::random_for_testing_only(); - let eth_address = EthAddress::random(); - let token_id = TokenId::USDC; - let amount = 1_000_000; - - let sui_bridge_event = EmittedSuiToEthTokenBridgeV1 { - nonce, - sui_chain_id, - eth_chain_id, - sui_address, - eth_address, - token_id, - amount, - }; - - let encoded_bytes = BridgeAction::SuiToEthBridgeAction(SuiToEthBridgeAction { - sui_tx_digest, - sui_tx_event_index, - sui_bridge_event, - }) - .to_bytes(); - - // Construct the expected bytes - let prefix_bytes = BRIDGE_MESSAGE_PREFIX.to_vec(); // len: 18 - let message_type = vec![BridgeActionType::TokenTransfer as u8]; // len: 1 - let message_version = vec![TOKEN_TRANSFER_MESSAGE_VERSION]; // len: 1 - let nonce_bytes = nonce.to_be_bytes().to_vec(); // len: 8 - let source_chain_id_bytes = vec![sui_chain_id as u8]; // len: 1 - - let sui_address_length_bytes = vec![SUI_ADDRESS_LENGTH as u8]; // len: 1 - let sui_address_bytes = sui_address.to_vec(); // len: 32 - let dest_chain_id_bytes = vec![eth_chain_id as u8]; // len: 1 - let eth_address_length_bytes = vec![EthAddress::len_bytes() as u8]; // len: 1 - let eth_address_bytes = eth_address.as_bytes().to_vec(); // len: 20 - - let token_id_bytes = vec![token_id as u8]; // len: 1 - let token_amount_bytes = amount.to_be_bytes().to_vec(); // len: 8 - - let mut combined_bytes = Vec::new(); - combined_bytes.extend_from_slice(&prefix_bytes); - combined_bytes.extend_from_slice(&message_type); - combined_bytes.extend_from_slice(&message_version); - combined_bytes.extend_from_slice(&nonce_bytes); - combined_bytes.extend_from_slice(&source_chain_id_bytes); - combined_bytes.extend_from_slice(&sui_address_length_bytes); - combined_bytes.extend_from_slice(&sui_address_bytes); - combined_bytes.extend_from_slice(&dest_chain_id_bytes); - combined_bytes.extend_from_slice(ð_address_length_bytes); - combined_bytes.extend_from_slice(ð_address_bytes); - combined_bytes.extend_from_slice(&token_id_bytes); - combined_bytes.extend_from_slice(&token_amount_bytes); - - assert_eq!(combined_bytes, encoded_bytes); - - // Assert fixed length - // TODO: for each action type add a test to assert the length - assert_eq!( - combined_bytes.len(), - 18 + 1 + 1 + 8 + 1 + 1 + 32 + 1 + 20 + 1 + 1 + 8 - ); - Ok(()) - } - - #[test] - fn test_bridge_message_encoding_regression_emitted_sui_to_eth_token_bridge_v1() - -> anyhow::Result<()> { - telemetry_subscribers::init_for_testing(); - let registry = Registry::new(); - mysten_metrics::init_metrics(®istry); - let sui_tx_digest = TransactionDigest::random(); - let sui_tx_event_index = 1u16; - - let nonce = 10u64; - let sui_chain_id = BridgeChainId::SuiTestnet; - let eth_chain_id = BridgeChainId::EthSepolia; - let sui_address = SuiAddress::from_str( - "0x0000000000000000000000000000000000000000000000000000000000000064", - ) - .unwrap(); - let eth_address = - EthAddress::from_str("0x00000000000000000000000000000000000000c8").unwrap(); - let token_id = TokenId::USDC; - let amount = 12345; - - let sui_bridge_event = EmittedSuiToEthTokenBridgeV1 { - nonce, - sui_chain_id, - eth_chain_id, - sui_address, - eth_address, - token_id, - amount, - }; - let encoded_bytes = BridgeAction::SuiToEthBridgeAction(SuiToEthBridgeAction { - sui_tx_digest, - sui_tx_event_index, - sui_bridge_event, - }) - .to_bytes(); - assert_eq!( - encoded_bytes, - Hex::decode("5355495f4252494447455f4d4553534147450001000000000000000a012000000000000000000000000000000000000000000000000000000000000000640b1400000000000000000000000000000000000000c8030000000000003039").unwrap(), - ); - - let hash = Keccak256::digest(encoded_bytes).digest; - assert_eq!( - hash.to_vec(), - Hex::decode("6ab34c52b6264cbc12fe8c3874f9b08f8481d2e81530d136386646dbe2f8baf4") - .unwrap(), - ); - Ok(()) - } - - #[test] - fn test_bridge_message_encoding_blocklist_update_v1() { - telemetry_subscribers::init_for_testing(); - let registry = Registry::new(); - mysten_metrics::init_metrics(®istry); - - let pub_key_bytes = BridgeAuthorityPublicKeyBytes::from_bytes( - &Hex::decode("02321ede33d2c2d7a8a152f275a1484edef2098f034121a602cb7d767d38680aa4") - .unwrap(), - ) - .unwrap(); - let blocklist_action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction { - nonce: 129, - chain_id: BridgeChainId::SuiLocalTest, - blocklist_type: BlocklistType::Blocklist, - blocklisted_members: vec![pub_key_bytes.clone()], - }); - let bytes = blocklist_action.to_bytes(); - // 5355495f4252494447455f4d455353414745: prefix - // 01: msg type - // 01: msg version - // 0000000000000081: nonce - // 03: chain id - // 00: blocklist type - // 01: length of updated members - // [ - // 68b43fd906c0b8f024a18c56e06744f7c6157c65 - // ]: blocklisted members abi-encoded - assert_eq!(bytes, Hex::decode("5355495f4252494447455f4d4553534147450101000000000000008103000168b43fd906c0b8f024a18c56e06744f7c6157c65").unwrap()); - - let pub_key_bytes_2 = BridgeAuthorityPublicKeyBytes::from_bytes( - &Hex::decode("027f1178ff417fc9f5b8290bd8876f0a157a505a6c52db100a8492203ddd1d4279") - .unwrap(), - ) - .unwrap(); - // its evem address: 0xacaef39832cb995c4e049437a3e2ec6a7bad1ab5 - let blocklist_action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction { - nonce: 68, - chain_id: BridgeChainId::SuiDevnet, - blocklist_type: BlocklistType::Unblocklist, - blocklisted_members: vec![pub_key_bytes.clone(), pub_key_bytes_2.clone()], - }); - let bytes = blocklist_action.to_bytes(); - // 5355495f4252494447455f4d455353414745: prefix - // 01: msg type - // 01: msg version - // 0000000000000044: nonce - // 02: chain id - // 01: blocklist type - // 02: length of updated members - // [ - // 68b43fd906c0b8f024a18c56e06744f7c6157c65 - // acaef39832cb995c4e049437a3e2ec6a7bad1ab5 - // ]: blocklisted members abi-encoded - assert_eq!(bytes, Hex::decode("5355495f4252494447455f4d4553534147450101000000000000004402010268b43fd906c0b8f024a18c56e06744f7c6157c65acaef39832cb995c4e049437a3e2ec6a7bad1ab5").unwrap()); - - let blocklist_action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction { - nonce: 49, - chain_id: BridgeChainId::EthLocalTest, - blocklist_type: BlocklistType::Blocklist, - blocklisted_members: vec![pub_key_bytes.clone()], - }); - let bytes = blocklist_action.to_bytes(); - // 5355495f4252494447455f4d455353414745: prefix - // 01: msg type - // 01: msg version - // 0000000000000031: nonce - // 0c: chain id - // 00: blocklist type - // 01: length of updated members - // [ - // 68b43fd906c0b8f024a18c56e06744f7c6157c65 - // ]: blocklisted members abi-encoded - assert_eq!(bytes, Hex::decode("5355495f4252494447455f4d455353414745010100000000000000310c000168b43fd906c0b8f024a18c56e06744f7c6157c65").unwrap()); - - let blocklist_action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction { - nonce: 94, - chain_id: BridgeChainId::EthSepolia, - blocklist_type: BlocklistType::Unblocklist, - blocklisted_members: vec![pub_key_bytes.clone(), pub_key_bytes_2.clone()], - }); - let bytes = blocklist_action.to_bytes(); - // 5355495f4252494447455f4d455353414745: prefix - // 01: msg type - // 01: msg version - // 000000000000005e: nonce - // 0b: chain id - // 01: blocklist type - // 02: length of updated members - // [ - // 00000000000000000000000068b43fd906c0b8f024a18c56e06744f7c6157c65 - // 000000000000000000000000acaef39832cb995c4e049437a3e2ec6a7bad1ab5 - // ]: blocklisted members abi-encoded - assert_eq!(bytes, Hex::decode("5355495f4252494447455f4d4553534147450101000000000000005e0b010268b43fd906c0b8f024a18c56e06744f7c6157c65acaef39832cb995c4e049437a3e2ec6a7bad1ab5").unwrap()); - } - - #[test] - fn test_emergency_action_encoding() { - let action = BridgeAction::EmergencyAction(EmergencyAction { - nonce: 55, - chain_id: BridgeChainId::SuiLocalTest, - action_type: EmergencyActionType::Pause, - }); - let bytes = action.to_bytes(); - // 5355495f4252494447455f4d455353414745: prefix - // 02: msg type - // 01: msg version - // 0000000000000037: nonce - // 03: chain id - // 00: action type - assert_eq!( - bytes, - Hex::decode("5355495f4252494447455f4d455353414745020100000000000000370300").unwrap() - ); - - let action = BridgeAction::EmergencyAction(EmergencyAction { - nonce: 56, - chain_id: BridgeChainId::EthSepolia, - action_type: EmergencyActionType::Unpause, - }); - let bytes = action.to_bytes(); - // 5355495f4252494447455f4d455353414745: prefix - // 02: msg type - // 01: msg version - // 0000000000000038: nonce - // 0b: chain id - // 01: action type - assert_eq!( - bytes, - Hex::decode("5355495f4252494447455f4d455353414745020100000000000000380b01").unwrap() - ); - } - - #[test] - fn test_limit_update_action_encoding() { - let action = BridgeAction::LimitUpdateAction(LimitUpdateAction { - nonce: 15, - chain_id: BridgeChainId::SuiLocalTest, - sending_chain_id: BridgeChainId::EthLocalTest, - new_usd_limit: 1_000_000 * USD_MULTIPLIER, // $1M USD - }); - let bytes = action.to_bytes(); - // 5355495f4252494447455f4d455353414745: prefix - // 03: msg type - // 01: msg version - // 000000000000000f: nonce - // 03: chain id - // 0c: sending chain id - // 00000002540be400: new usd limit - assert_eq!( - bytes, - Hex::decode( - "5355495f4252494447455f4d4553534147450301000000000000000f030c00000002540be400" - ) - .unwrap() - ); - } - - #[test] - fn test_asset_price_update_action_encoding() { - let action = BridgeAction::AssetPriceUpdateAction(AssetPriceUpdateAction { - nonce: 266, - chain_id: BridgeChainId::SuiLocalTest, - token_id: TokenId::BTC, - new_usd_price: 100_000 * USD_MULTIPLIER, // $100k USD - }); - let bytes = action.to_bytes(); - // 5355495f4252494447455f4d455353414745: prefix - // 04: msg type - // 01: msg version - // 000000000000010a: nonce - // 03: chain id - // 01: token id - // 000000003b9aca00: new usd price - assert_eq!( - bytes, - Hex::decode( - "5355495f4252494447455f4d4553534147450401000000000000010a0301000000003b9aca00" - ) - .unwrap() - ); - } - - #[test] - fn test_evm_contract_upgrade_action() { - // Calldata with only the function selector and no parameters: `function - // initializeV2()` - let function_signature = "initializeV2()"; - let selector = &Keccak256::digest(function_signature).digest[0..4]; - let call_data = selector.to_vec(); - assert_eq!(Hex::encode(call_data.clone()), "5cd8a76b"); - - let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { - nonce: 123, - chain_id: BridgeChainId::EthLocalTest, - proxy_address: EthAddress::repeat_byte(6), - new_impl_address: EthAddress::repeat_byte(9), - call_data, - }); - // 5355495f4252494447455f4d455353414745: prefix - // 05: msg type - // 01: msg version - // 000000000000007b: nonce - // 0c: chain id - // 0000000000000000000000000606060606060606060606060606060606060606: proxy - // address - // 0000000000000000000000000909090909090909090909090909090909090909: new impl - // address - // - // 0000000000000000000000000000000000000000000000000000000000000060 - // 0000000000000000000000000000000000000000000000000000000000000004 - // 5cd8a76b00000000000000000000000000000000000000000000000000000000: call data - assert_eq!( - Hex::encode(action.to_bytes().clone()), - "5355495f4252494447455f4d4553534147450501000000000000007b0c00000000000000000000000006060606060606060606060606060606060606060000000000000000000000000909090909090909090909090909090909090909000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000045cd8a76b00000000000000000000000000000000000000000000000000000000" - ); - - // Calldata with one parameter: `function newMockFunction(bool)` - let function_signature = "newMockFunction(bool)"; - let selector = &Keccak256::digest(function_signature).digest[0..4]; - let mut call_data = selector.to_vec(); - call_data.extend(ethers::abi::encode(&[ethers::abi::Token::Bool(true)])); - assert_eq!( - Hex::encode(call_data.clone()), - "417795ef0000000000000000000000000000000000000000000000000000000000000001" - ); - let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { - nonce: 123, - chain_id: BridgeChainId::EthLocalTest, - proxy_address: EthAddress::repeat_byte(6), - new_impl_address: EthAddress::repeat_byte(9), - call_data, - }); - // 5355495f4252494447455f4d455353414745: prefix - // 05: msg type - // 01: msg version - // 000000000000007b: nonce - // 0c: chain id - // 0000000000000000000000000606060606060606060606060606060606060606: proxy - // address - // 0000000000000000000000000909090909090909090909090909090909090909: new impl - // address - // - // 0000000000000000000000000000000000000000000000000000000000000060 - // 0000000000000000000000000000000000000000000000000000000000000024 - // 417795ef00000000000000000000000000000000000000000000000000000000 - // 0000000100000000000000000000000000000000000000000000000000000000: call data - assert_eq!( - Hex::encode(action.to_bytes().clone()), - "5355495f4252494447455f4d4553534147450501000000000000007b0c0000000000000000000000000606060606060606060606060606060606060606000000000000000000000000090909090909090909090909090909090909090900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000024417795ef000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000" - ); - - // Calldata with two parameters: `function newerMockFunction(bool, uint8)` - let function_signature = "newMockFunction(bool,uint8)"; - let selector = &Keccak256::digest(function_signature).digest[0..4]; - let mut call_data = selector.to_vec(); - call_data.extend(ethers::abi::encode(&[ - ethers::abi::Token::Bool(true), - ethers::abi::Token::Uint(42u8.into()), - ])); - assert_eq!( - Hex::encode(call_data.clone()), - "be8fc25d0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002a" - ); - let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { - nonce: 123, - chain_id: BridgeChainId::EthLocalTest, - proxy_address: EthAddress::repeat_byte(6), - new_impl_address: EthAddress::repeat_byte(9), - call_data, - }); - // 5355495f4252494447455f4d455353414745: prefix - // 05: msg type - // 01: msg version - // 000000000000007b: nonce - // 0c: chain id - // 0000000000000000000000000606060606060606060606060606060606060606: proxy - // address - // 0000000000000000000000000909090909090909090909090909090909090909: new impl - // address - // - // 0000000000000000000000000000000000000000000000000000000000000060 - // 0000000000000000000000000000000000000000000000000000000000000044 - // be8fc25d00000000000000000000000000000000000000000000000000000000 - // 0000000100000000000000000000000000000000000000000000000000000000 - // 0000002a00000000000000000000000000000000000000000000000000000000: call data - assert_eq!( - Hex::encode(action.to_bytes().clone()), - "5355495f4252494447455f4d4553534147450501000000000000007b0c0000000000000000000000000606060606060606060606060606060606060606000000000000000000000000090909090909090909090909090909090909090900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044be8fc25d0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000" - ); - - // Empty calldate - let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction { - nonce: 123, - chain_id: BridgeChainId::EthLocalTest, - proxy_address: EthAddress::repeat_byte(6), - new_impl_address: EthAddress::repeat_byte(9), - call_data: vec![], - }); - // 5355495f4252494447455f4d455353414745: prefix - // 05: msg type - // 01: msg version - // 000000000000007b: nonce - // 0c: chain id - // 0000000000000000000000000606060606060606060606060606060606060606: proxy - // address - // 0000000000000000000000000909090909090909090909090909090909090909: new impl - // address - // - // 0000000000000000000000000000000000000000000000000000000000000060 - // 0000000000000000000000000000000000000000000000000000000000000000: call data - let data = action.to_bytes(); - assert_eq!( - Hex::encode(data.clone()), - "5355495f4252494447455f4d4553534147450501000000000000007b0c0000000000000000000000000606060606060606060606060606060606060606000000000000000000000000090909090909090909090909090909090909090900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000" - ); - let types = vec![ParamType::Address, ParamType::Address, ParamType::Bytes]; - // Ensure that the call data (start from bytes 29) can be decoded - ethers::abi::decode(&types, &data[29..]).unwrap(); - } - - #[test] - fn test_bridge_message_encoding_regression_eth_to_sui_token_bridge_v1() -> anyhow::Result<()> { - telemetry_subscribers::init_for_testing(); - let registry = Registry::new(); - mysten_metrics::init_metrics(®istry); - let eth_tx_hash = TxHash::random(); - let eth_event_index = 1u16; - - let nonce = 10u64; - let sui_chain_id = BridgeChainId::SuiTestnet; - let eth_chain_id = BridgeChainId::EthSepolia; - let sui_address = SuiAddress::from_str( - "0x0000000000000000000000000000000000000000000000000000000000000064", - ) - .unwrap(); - let eth_address = - EthAddress::from_str("0x00000000000000000000000000000000000000c8").unwrap(); - let token_id = TokenId::USDC; - let amount = 12345; - - let eth_bridge_event = EthToSuiTokenBridgeV1 { - nonce, - sui_chain_id, - eth_chain_id, - sui_address, - eth_address, - token_id, - amount, - }; - let encoded_bytes = BridgeAction::EthToSuiBridgeAction(EthToSuiBridgeAction { - eth_tx_hash, - eth_event_index, - eth_bridge_event, - }) - .to_bytes(); - - assert_eq!( - encoded_bytes, - Hex::decode("5355495f4252494447455f4d4553534147450001000000000000000a0b1400000000000000000000000000000000000000c801200000000000000000000000000000000000000000000000000000000000000064030000000000003039").unwrap(), - ); - - let hash = Keccak256::digest(encoded_bytes).digest; - assert_eq!( - hash.to_vec(), - Hex::decode("b352508c301a37bb1b68a75dd0fc42b6f692b2650818631c8f8a4d4d3e5bef46") - .unwrap(), - ); - Ok(()) - } - - #[test] - fn test_bridge_committee_construction() -> anyhow::Result<()> { - let (mut authority, _, _) = get_test_authority_and_key(10000, 9999); - // This is ok - let _ = BridgeCommittee::new(vec![authority.clone()]).unwrap(); - - // This is not ok - total voting power != 10000 - authority.voting_power = 9999; - let _ = BridgeCommittee::new(vec![authority.clone()]).unwrap_err(); - - // This is not ok - total voting power != 10000 - authority.voting_power = 10001; - let _ = BridgeCommittee::new(vec![authority.clone()]).unwrap_err(); - - // This is ok - authority.voting_power = 5000; - let mut authority_2 = authority.clone(); - let (_, kp): (_, fastcrypto::secp256k1::Secp256k1KeyPair) = get_key_pair(); - let pubkey = kp.public().clone(); - authority_2.pubkey = pubkey.clone(); - let _ = BridgeCommittee::new(vec![authority.clone(), authority_2.clone()]).unwrap(); - - // This is not ok - duplicate pub key - authority_2.pubkey = authority.pubkey.clone(); - let _ = BridgeCommittee::new(vec![authority.clone(), authority.clone()]).unwrap_err(); - Ok(()) - } - - #[test] - fn test_bridge_committee_total_blocklisted_stake() -> anyhow::Result<()> { - let (mut authority1, _, _) = get_test_authority_and_key(10000, 9999); - assert_eq!( - BridgeCommittee::new(vec![authority1.clone()]) - .unwrap() - .total_blocklisted_stake(), - 0 - ); - authority1.voting_power = 6000; - - let (mut authority2, _, _) = get_test_authority_and_key(4000, 9999); - authority2.is_blocklisted = true; - assert_eq!( - BridgeCommittee::new(vec![authority1.clone(), authority2.clone()]) - .unwrap() - .total_blocklisted_stake(), - 4000 - ); - - authority1.voting_power = 7000; - authority2.voting_power = 2000; - let (mut authority3, _, _) = get_test_authority_and_key(1000, 9999); - authority3.is_blocklisted = true; - assert_eq!( - BridgeCommittee::new(vec![authority1, authority2, authority3]) - .unwrap() - .total_blocklisted_stake(), - 3000 - ); - - Ok(()) - } - - #[test] - fn test_bridge_committee_filter_blocklisted_authorities() -> anyhow::Result<()> { - // Note: today BridgeCommitte does not shuffle authorities - let (authority1, _, _) = get_test_authority_and_key(5000, 9999); - let (mut authority2, _, _) = get_test_authority_and_key(3000, 9999); - authority2.is_blocklisted = true; - let (authority3, _, _) = get_test_authority_and_key(2000, 9999); - let committee = BridgeCommittee::new(vec![ - authority1.clone(), - authority2.clone(), - authority3.clone(), - ]) - .unwrap(); - - // exclude authority2 - let result = committee - .shuffle_by_stake(None, None) - .into_iter() - .collect::>(); - assert_eq!( - HashSet::from_iter(vec![authority1.pubkey_bytes(), authority3.pubkey_bytes()]), - result - ); - - // exclude authority2 and authority3 - let result = committee - .shuffle_by_stake( - None, - Some( - &[authority1.pubkey_bytes(), authority2.pubkey_bytes()] - .iter() - .cloned() - .collect(), - ), - ) - .into_iter() - .collect::>(); - assert_eq!(HashSet::from_iter(vec![authority1.pubkey_bytes()]), result); - - Ok(()) - } -} diff --git a/crates/sui-cluster-test/Cargo.toml b/crates/sui-cluster-test/Cargo.toml deleted file mode 100644 index 04803e65b77..00000000000 --- a/crates/sui-cluster-test/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -[package] -name = "sui-cluster-test" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -futures.workspace = true -serde_json.workspace = true -tempfile.workspace = true -tokio = { workspace = true, features = ["full"] } -jsonrpsee.workspace = true -tracing.workspace = true -clap.workspace = true -reqwest.workspace = true -async-trait.workspace = true -anyhow = { workspace = true, features = ["backtrace"] } -uuid.workspace = true -prometheus.workspace = true -fastcrypto.workspace = true -shared-crypto.workspace = true -derivative.workspace = true -regex.workspace = true - -sui-indexer.workspace = true -sui-faucet.workspace = true -sui-graphql-rpc.workspace = true -sui-swarm.workspace = true -sui.workspace = true -sui-swarm-config.workspace = true -sui-json-rpc-types.workspace = true -sui-sdk.workspace = true -sui-keys.workspace = true -sui-types.workspace = true -sui-core.workspace = true -sui-json.workspace = true -sui-config.workspace = true -sui-test-transaction-builder.workspace = true -telemetry-subscribers.workspace = true - -test-cluster.workspace = true -move-core-types.workspace = true - -[features] -pg_integration = [] diff --git a/crates/sui-cluster-test/src/cluster.rs b/crates/sui-cluster-test/src/cluster.rs deleted file mode 100644 index c0dc44e5b41..00000000000 --- a/crates/sui-cluster-test/src/cluster.rs +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{net::SocketAddr, path::Path}; - -use async_trait::async_trait; -use sui_config::{Config, PersistedConfig, SUI_KEYSTORE_FILENAME, SUI_NETWORK_CONFIG}; -use sui_graphql_rpc::{ - config::ConnectionConfig, test_infra::cluster::start_graphql_server_with_fn_rpc, -}; -use sui_indexer::test_utils::{start_test_indexer, ReaderWriterConfig}; -use sui_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; -use sui_sdk::{ - sui_client_config::{SuiClientConfig, SuiEnv}, - wallet_context::WalletContext, -}; -use sui_swarm::memory::Swarm; -use sui_swarm_config::{genesis_config::GenesisConfig, network_config::NetworkConfig}; -use sui_types::{ - base_types::SuiAddress, - crypto::{get_key_pair, AccountKeyPair, KeypairTraits, SuiKeyPair}, -}; -use test_cluster::{TestCluster, TestClusterBuilder}; -use tracing::info; - -use super::config::{ClusterTestOpt, Env}; - -const DEVNET_FAUCET_ADDR: &str = "https://faucet.devnet.sui.io:443"; -const STAGING_FAUCET_ADDR: &str = "https://faucet.staging.sui.io:443"; -const CONTINUOUS_FAUCET_ADDR: &str = "https://faucet.ci.sui.io:443"; -const CONTINUOUS_NOMAD_FAUCET_ADDR: &str = "https://faucet.nomad.ci.sui.io:443"; -const TESTNET_FAUCET_ADDR: &str = "https://faucet.testnet.sui.io:443"; -const DEVNET_FULLNODE_ADDR: &str = "https://rpc.devnet.sui.io:443"; -const STAGING_FULLNODE_ADDR: &str = "https://fullnode.staging.sui.io:443"; -const CONTINUOUS_FULLNODE_ADDR: &str = "https://fullnode.ci.sui.io:443"; -const CONTINUOUS_NOMAD_FULLNODE_ADDR: &str = "https://fullnode.nomad.ci.sui.io:443"; -const TESTNET_FULLNODE_ADDR: &str = "https://fullnode.testnet.sui.io:443"; - -pub struct ClusterFactory; - -impl ClusterFactory { - pub async fn start( - options: &ClusterTestOpt, - ) -> Result, anyhow::Error> { - Ok(match &options.env { - Env::NewLocal => Box::new(LocalNewCluster::start(options).await?), - _ => Box::new(RemoteRunningCluster::start(options).await?), - }) - } -} - -/// Cluster Abstraction -#[async_trait] -pub trait Cluster { - async fn start(options: &ClusterTestOpt) -> Result - where - Self: Sized; - - fn fullnode_url(&self) -> &str; - fn user_key(&self) -> AccountKeyPair; - fn indexer_url(&self) -> &Option; - - /// Returns faucet url in a remote cluster. - fn remote_faucet_url(&self) -> Option<&str>; - - /// Returns faucet key in a local cluster. - fn local_faucet_key(&self) -> Option<&AccountKeyPair>; - - /// Place to put config for the wallet, and any locally running services. - fn config_directory(&self) -> &Path; -} - -/// Represents an up and running cluster deployed remotely. -pub struct RemoteRunningCluster { - fullnode_url: String, - faucet_url: String, - config_directory: tempfile::TempDir, -} - -#[async_trait] -impl Cluster for RemoteRunningCluster { - async fn start(options: &ClusterTestOpt) -> Result { - let (fullnode_url, faucet_url) = match options.env { - Env::Devnet => ( - String::from(DEVNET_FULLNODE_ADDR), - String::from(DEVNET_FAUCET_ADDR), - ), - Env::Staging => ( - String::from(STAGING_FULLNODE_ADDR), - String::from(STAGING_FAUCET_ADDR), - ), - Env::Ci => ( - String::from(CONTINUOUS_FULLNODE_ADDR), - String::from(CONTINUOUS_FAUCET_ADDR), - ), - Env::CiNomad => ( - String::from(CONTINUOUS_NOMAD_FULLNODE_ADDR), - String::from(CONTINUOUS_NOMAD_FAUCET_ADDR), - ), - Env::Testnet => ( - String::from(TESTNET_FULLNODE_ADDR), - String::from(TESTNET_FAUCET_ADDR), - ), - Env::CustomRemote => ( - options - .fullnode_address - .clone() - .expect("Expect 'fullnode_address' for Env::Custom"), - options - .faucet_address - .clone() - .expect("Expect 'faucet_address' for Env::Custom"), - ), - Env::NewLocal => unreachable!("NewLocal shouldn't use RemoteRunningCluster"), - }; - - // TODO: test connectivity before proceeding? - - Ok(Self { - fullnode_url, - faucet_url, - config_directory: tempfile::tempdir()?, - }) - } - - fn fullnode_url(&self) -> &str { - &self.fullnode_url - } - - fn indexer_url(&self) -> &Option { - &None - } - - fn user_key(&self) -> AccountKeyPair { - get_key_pair().1 - } - - fn remote_faucet_url(&self) -> Option<&str> { - Some(&self.faucet_url) - } - - fn local_faucet_key(&self) -> Option<&AccountKeyPair> { - None - } - - fn config_directory(&self) -> &Path { - self.config_directory.path() - } -} - -/// Represents a local Cluster which starts per cluster test run. -pub struct LocalNewCluster { - test_cluster: TestCluster, - fullnode_url: String, - indexer_url: Option, - faucet_key: AccountKeyPair, - config_directory: tempfile::TempDir, -} - -impl LocalNewCluster { - #[allow(unused)] - pub fn swarm(&self) -> &Swarm { - &self.test_cluster.swarm - } -} - -#[async_trait] -impl Cluster for LocalNewCluster { - async fn start(options: &ClusterTestOpt) -> Result { - // TODO: options should contain port instead of address - let fullnode_port = options.fullnode_address.as_ref().map(|addr| { - addr.parse::() - .expect("Unable to parse fullnode address") - .port() - }); - - let indexer_address = options.indexer_address.as_ref().map(|addr| { - addr.parse::() - .expect("Unable to parse indexer address") - }); - - let mut cluster_builder = TestClusterBuilder::new().enable_fullnode_events(); - - // Check if we already have a config directory that is passed - if let Some(config_dir) = options.config_dir.clone() { - assert!(options.epoch_duration_ms.is_none()); - // Load the config of the Sui authority. - let network_config_path = config_dir.join(SUI_NETWORK_CONFIG); - let network_config: NetworkConfig = PersistedConfig::read(&network_config_path) - .map_err(|err| { - err.context(format!( - "Cannot open Sui network config file at {:?}", - network_config_path - )) - })?; - - cluster_builder = cluster_builder.set_network_config(network_config); - cluster_builder = cluster_builder.with_config_dir(config_dir); - } else { - // Let the faucet account hold 1000 gas objects on genesis - let genesis_config = GenesisConfig::custom_genesis(1, 100); - // Custom genesis should be build here where we add the extra accounts - cluster_builder = cluster_builder.set_genesis_config(genesis_config); - - if let Some(epoch_duration_ms) = options.epoch_duration_ms { - cluster_builder = cluster_builder.with_epoch_duration_ms(epoch_duration_ms); - } - } - - if let Some(rpc_port) = fullnode_port { - cluster_builder = cluster_builder.with_fullnode_rpc_port(rpc_port); - } - - let mut test_cluster = cluster_builder.build().await; - - // Use the wealthy account for faucet - let faucet_key = test_cluster.swarm.config_mut().account_keys.swap_remove(0); - let faucet_address = SuiAddress::from(faucet_key.public()); - info!(?faucet_address, "faucet_address"); - - // This cluster has fullnode handle, safe to unwrap - let fullnode_url = test_cluster.fullnode_handle.rpc_url.clone(); - - if let (Some(pg_address), Some(indexer_address)) = - (options.pg_address.clone(), indexer_address) - { - // Start in writer mode - start_test_indexer( - Some(pg_address.clone()), - fullnode_url.clone(), - ReaderWriterConfig::writer_mode(None), - ) - .await; - - // Start in reader mode - start_test_indexer( - Some(pg_address), - fullnode_url.clone(), - ReaderWriterConfig::reader_mode(indexer_address.to_string()), - ) - .await; - } - - if let Some(graphql_address) = &options.graphql_address { - let graphql_address = graphql_address.parse::()?; - let graphql_connection_config = ConnectionConfig::new( - Some(graphql_address.port()), - Some(graphql_address.ip().to_string()), - options.pg_address.clone(), - None, - None, - None, - ); - - start_graphql_server_with_fn_rpc( - graphql_connection_config.clone(), - Some(fullnode_url.clone()), - // cancellation_token - None, - ) - .await; - } - - // Let nodes connect to one another - tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; - - // TODO: test connectivity before proceeding? - Ok(Self { - test_cluster, - fullnode_url, - faucet_key, - config_directory: tempfile::tempdir()?, - indexer_url: options.indexer_address.clone(), - }) - } - - fn fullnode_url(&self) -> &str { - &self.fullnode_url - } - - fn indexer_url(&self) -> &Option { - &self.indexer_url - } - - fn user_key(&self) -> AccountKeyPair { - get_key_pair().1 - } - - fn remote_faucet_url(&self) -> Option<&str> { - None - } - - fn local_faucet_key(&self) -> Option<&AccountKeyPair> { - Some(&self.faucet_key) - } - - fn config_directory(&self) -> &Path { - self.config_directory.path() - } -} - -// Make linter happy -#[async_trait] -impl Cluster for Box { - async fn start(_options: &ClusterTestOpt) -> Result { - unreachable!( - "If we already have a boxed Cluster trait object we wouldn't have to call this function" - ); - } - fn fullnode_url(&self) -> &str { - (**self).fullnode_url() - } - fn indexer_url(&self) -> &Option { - (**self).indexer_url() - } - - fn user_key(&self) -> AccountKeyPair { - (**self).user_key() - } - - fn remote_faucet_url(&self) -> Option<&str> { - (**self).remote_faucet_url() - } - - fn local_faucet_key(&self) -> Option<&AccountKeyPair> { - (**self).local_faucet_key() - } - - fn config_directory(&self) -> &Path { - (**self).config_directory() - } -} - -pub fn new_wallet_context_from_cluster( - cluster: &(dyn Cluster + Sync + Send), - key_pair: AccountKeyPair, -) -> WalletContext { - let config_dir = cluster.config_directory(); - let wallet_config_path = config_dir.join("client.yaml"); - let fullnode_url = cluster.fullnode_url(); - info!("Use RPC: {}", &fullnode_url); - let keystore_path = config_dir.join(SUI_KEYSTORE_FILENAME); - let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - let address: SuiAddress = key_pair.public().into(); - keystore - .add_key(None, SuiKeyPair::Ed25519(key_pair)) - .unwrap(); - SuiClientConfig { - keystore, - envs: vec![SuiEnv { - alias: "localnet".to_string(), - rpc: fullnode_url.into(), - ws: None, - }], - active_address: Some(address), - active_env: Some("localnet".to_string()), - } - .persisted(&wallet_config_path) - .save() - .unwrap(); - - info!( - "Initialize wallet from config path: {:?}", - wallet_config_path - ); - - WalletContext::new(&wallet_config_path, None, None).unwrap_or_else(|e| { - panic!( - "Failed to init wallet context from path {:?}, error: {e}", - wallet_config_path - ) - }) -} diff --git a/crates/sui-cluster-test/src/config.rs b/crates/sui-cluster-test/src/config.rs deleted file mode 100644 index b846a367b77..00000000000 --- a/crates/sui-cluster-test/src/config.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{fmt, path::PathBuf}; - -use clap::*; -use regex::Regex; - -#[derive(Parser, Clone, ValueEnum, Debug)] -pub enum Env { - Devnet, - Staging, - Ci, - CiNomad, - Testnet, - CustomRemote, - NewLocal, -} - -#[derive(derivative::Derivative, Parser)] -#[derivative(Debug)] -#[clap(name = "", rename_all = "kebab-case")] -pub struct ClusterTestOpt { - #[clap(value_enum)] - pub env: Env, - #[clap(long)] - pub faucet_address: Option, - #[clap(long)] - pub fullnode_address: Option, - #[clap(long)] - pub epoch_duration_ms: Option, - /// URL for the indexer RPC server - #[clap(long)] - pub indexer_address: Option, - /// URL for the Indexer Postgres DB - #[clap(long)] - #[derivative(Debug(format_with = "obfuscated_pg_address"))] - pub pg_address: Option, - #[clap(long)] - pub config_dir: Option, - /// URL for the indexer RPC server - #[clap(long)] - pub graphql_address: Option, -} - -fn obfuscated_pg_address(val: &Option, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match val { - None => write!(f, "None"), - Some(val) => { - write!( - f, - "{}", - Regex::new(r":.*@") - .unwrap() - .replace_all(val.as_str(), ":*****@") - ) - } - } -} - -impl ClusterTestOpt { - pub fn new_local() -> Self { - Self { - env: Env::NewLocal, - faucet_address: None, - fullnode_address: None, - epoch_duration_ms: None, - indexer_address: None, - pg_address: None, - config_dir: None, - graphql_address: None, - } - } -} diff --git a/crates/sui-cluster-test/src/lib.rs b/crates/sui-cluster-test/src/lib.rs deleted file mode 100644 index 6180a6b7f44..00000000000 --- a/crates/sui-cluster-test/src/lib.rs +++ /dev/null @@ -1,328 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use std::sync::Arc; - -use async_trait::async_trait; -use cluster::{Cluster, ClusterFactory}; -use config::ClusterTestOpt; -use futures::{stream::FuturesUnordered, StreamExt}; -use helper::ObjectChecker; -use jsonrpsee::{ - core::{client::ClientT, params::ArrayParams}, - http_client::HttpClientBuilder, -}; -use sui_faucet::CoinInfo; -use sui_json_rpc_types::{ - SuiExecutionStatus, SuiTransactionBlockEffectsAPI, SuiTransactionBlockResponse, - SuiTransactionBlockResponseOptions, TransactionBlockBytes, -}; -use sui_sdk::{wallet_context::WalletContext, SuiClient}; -use sui_test_transaction_builder::batch_make_transfer_transactions; -use sui_types::{ - base_types::{SuiAddress, TransactionDigest}, - gas_coin::GasCoin, - object::Owner, - quorum_driver_types::ExecuteTransactionRequestType, - sui_system_state::sui_system_state_summary::SuiSystemStateSummary, - transaction::{Transaction, TransactionData}, -}; -use test_case::{ - coin_index_test::CoinIndexTest, coin_merge_split_test::CoinMergeSplitTest, - fullnode_build_publish_transaction_test::FullNodeBuildPublishTransactionTest, - fullnode_execute_transaction_test::FullNodeExecuteTransactionTest, - native_transfer_test::NativeTransferTest, shared_object_test::SharedCounterTest, -}; -use tokio::time::{self, Duration}; -use tracing::{error, info}; -use wallet_client::WalletClient; - -use crate::faucet::{FaucetClient, FaucetClientFactory}; - -pub mod cluster; -pub mod config; -pub mod faucet; -pub mod helper; -pub mod test_case; -pub mod wallet_client; - -#[allow(unused)] -pub struct TestContext { - /// Cluster handle that allows access to various components in a cluster - cluster: Box, - /// Client that provides wallet context and fullnode access - client: WalletClient, - /// Facuet client that provides faucet access to a test - faucet: Arc, -} - -impl TestContext { - async fn get_sui_from_faucet(&self, minimum_coins: Option) -> Vec { - let addr = self.get_wallet_address(); - let faucet_response = self.faucet.request_sui_coins(addr).await; - - let coin_info = faucet_response - .transferred_gas_objects - .iter() - .map(|coin_info| coin_info.transfer_tx_digest) - .collect::>(); - self.let_fullnode_sync(coin_info, 5).await; - - let gas_coins = self - .check_owner_and_into_gas_coin(faucet_response.transferred_gas_objects, addr) - .await; - - let minimum_coins = minimum_coins.unwrap_or(1); - - if gas_coins.len() < minimum_coins { - panic!( - "Expect to get at least {minimum_coins} Sui Coins for address {addr}, but only got {}", - gas_coins.len() - ) - } - - gas_coins - } - - fn get_context(&self) -> &WalletClient { - &self.client - } - - fn get_fullnode_client(&self) -> &SuiClient { - self.client.get_fullnode_client() - } - - fn clone_fullnode_client(&self) -> SuiClient { - self.client.get_fullnode_client().clone() - } - - fn get_fullnode_rpc_url(&self) -> &str { - self.cluster.fullnode_url() - } - - fn get_wallet(&self) -> &WalletContext { - self.client.get_wallet() - } - - async fn get_latest_sui_system_state(&self) -> SuiSystemStateSummary { - self.client - .get_fullnode_client() - .governance_api() - .get_latest_sui_system_state() - .await - .unwrap() - } - - async fn get_reference_gas_price(&self) -> u64 { - self.client - .get_fullnode_client() - .governance_api() - .get_reference_gas_price() - .await - .unwrap() - } - - fn get_wallet_address(&self) -> SuiAddress { - self.client.get_wallet_address() - } - - /// See `make_transactions_with_wallet_context` for potential caveats - /// of this helper function. - pub async fn make_transactions(&self, max_txn_num: usize) -> Vec { - batch_make_transfer_transactions(self.get_wallet(), max_txn_num).await - } - - pub async fn build_transaction_remotely( - &self, - method: &str, - params: ArrayParams, - ) -> anyhow::Result { - let fn_rpc_url = self.get_fullnode_rpc_url(); - // TODO cache this? - let rpc_client = HttpClientBuilder::default().build(fn_rpc_url)?; - - TransactionBlockBytes::to_data(rpc_client.request(method, params).await?) - } - - async fn sign_and_execute( - &self, - txn_data: TransactionData, - desc: &str, - ) -> SuiTransactionBlockResponse { - let signature = self.get_context().sign(&txn_data, desc); - let resp = self - .get_fullnode_client() - .quorum_driver_api() - .execute_transaction_block( - Transaction::from_data(txn_data, vec![signature]), - SuiTransactionBlockResponseOptions::new() - .with_object_changes() - .with_balance_changes() - .with_effects() - .with_events(), - Some(ExecuteTransactionRequestType::WaitForLocalExecution), - ) - .await - .unwrap_or_else(|e| panic!("Failed to execute transaction for {}. {}", desc, e)); - assert!( - matches!( - resp.effects.as_ref().unwrap().status(), - SuiExecutionStatus::Success - ), - "Failed to execute transaction for {desc}: {:?}", - resp - ); - resp - } - - pub async fn setup(options: ClusterTestOpt) -> Result { - let cluster = ClusterFactory::start(&options).await?; - let wallet_client = WalletClient::new_from_cluster(&cluster).await; - let faucet = FaucetClientFactory::new_from_cluster(&cluster).await; - Ok(Self { - cluster, - client: wallet_client, - faucet, - }) - } - - // TODO: figure out a more efficient way to test a local cluster - // A potential way to do this is to subscribe to txns from fullnode - // when the feature is ready - pub async fn let_fullnode_sync(&self, digests: Vec, timeout_sec: u64) { - let mut futures = FuturesUnordered::new(); - for digest in digests.clone() { - let task = self.get_tx_with_retry_times(digest, 1); - futures.push(Box::pin(task)); - } - let mut sleep = Box::pin(time::sleep(Duration::from_secs(timeout_sec))); - - loop { - tokio::select! { - _ = &mut sleep => { - panic!("Fullnode does not know all of {:?} after {} secs.", digests, timeout_sec); - } - res = futures.next() => { - match res { - Some((true, _, _)) => {}, - Some((false, digest, retry_times)) => { - let task = self.get_tx_with_retry_times(digest, retry_times); - futures.push(Box::pin(task)); - }, - None => break, // all txns appear on fullnode, mission completed - } - } - } - } - } - - async fn get_tx_with_retry_times( - &self, - digest: TransactionDigest, - retry_times: u64, - ) -> (bool, TransactionDigest, u64) { - match self - .client - .get_fullnode_client() - .read_api() - .get_transaction_with_options(digest, SuiTransactionBlockResponseOptions::new()) - .await - { - Ok(_) => (true, digest, retry_times), - Err(_) => { - time::sleep(Duration::from_millis(300 * retry_times)).await; - (false, digest, retry_times + 1) - } - } - } - - async fn check_owner_and_into_gas_coin( - &self, - coin_info: Vec, - owner: SuiAddress, - ) -> Vec { - futures::future::join_all( - coin_info - .iter() - .map(|coin_info| { - ObjectChecker::new(coin_info.id) - .owner(Owner::AddressOwner(owner)) - .check_into_gas_coin(self.get_fullnode_client()) - }) - .collect::>(), - ) - .await - .into_iter() - .collect::>() - } -} - -pub struct TestCase<'a> { - test_case: Box, -} - -impl<'a> TestCase<'a> { - pub fn new(test_case: impl TestCaseImpl + 'a) -> Self { - TestCase { - test_case: (Box::new(test_case)), - } - } - - pub async fn run(self, ctx: &mut TestContext) -> bool { - let test_name = self.test_case.name(); - info!("Running test {}.", test_name); - - // TODO: unwind panic and fail gracefully? - - match self.test_case.run(ctx).await { - Ok(()) => { - info!("Test {test_name} succeeded."); - true - } - Err(e) => { - error!("Test {test_name} failed with error: {e}."); - false - } - } - } -} - -#[async_trait] -pub trait TestCaseImpl { - fn name(&self) -> &'static str; - fn description(&self) -> &'static str; - async fn run(&self, ctx: &mut TestContext) -> Result<(), anyhow::Error>; -} - -pub struct ClusterTest; - -impl ClusterTest { - pub async fn run(options: ClusterTestOpt) { - let mut ctx = TestContext::setup(options) - .await - .unwrap_or_else(|e| panic!("Failed to set up TestContext, e: {e}")); - - // TODO: collect tests from each test_case file instead. - let tests = vec![ - TestCase::new(NativeTransferTest {}), - TestCase::new(CoinMergeSplitTest {}), - TestCase::new(SharedCounterTest {}), - TestCase::new(FullNodeExecuteTransactionTest {}), - TestCase::new(FullNodeBuildPublishTransactionTest {}), - TestCase::new(CoinIndexTest {}), - ]; - - // TODO: improve the runner parallelism for efficiency - // For now we run tests serially - let mut success_cnt = 0; - let total_cnt = tests.len() as i32; - for t in tests { - let is_success = t.run(&mut ctx).await as i32; - success_cnt += is_success; - } - if success_cnt < total_cnt { - // If any test failed, panic to bubble up the signal - panic!("{success_cnt} of {total_cnt} tests passed."); - } - info!("{success_cnt} of {total_cnt} tests passed."); - } -} diff --git a/crates/sui-cluster-test/src/main.rs b/crates/sui-cluster-test/src/main.rs deleted file mode 100644 index 034e7574b77..00000000000 --- a/crates/sui-cluster-test/src/main.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use clap::*; -use sui_cluster_test::{config::ClusterTestOpt, ClusterTest}; - -#[tokio::main] -async fn main() { - let _guard = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .init(); - - let options = ClusterTestOpt::parse(); - - ClusterTest::run(options).await; -} diff --git a/crates/sui-cluster-test/src/wallet_client.rs b/crates/sui-cluster-test/src/wallet_client.rs deleted file mode 100644 index b15ea3717a9..00000000000 --- a/crates/sui-cluster-test/src/wallet_client.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use shared_crypto::intent::Intent; -use sui_keys::keystore::AccountKeystore; -use sui_sdk::{wallet_context::WalletContext, SuiClient, SuiClientBuilder}; -use sui_types::{ - base_types::SuiAddress, - crypto::{KeypairTraits, Signature}, - transaction::TransactionData, -}; -use tracing::{info, info_span, Instrument}; - -use super::Cluster; -use crate::cluster::new_wallet_context_from_cluster; - -pub struct WalletClient { - wallet_context: WalletContext, - address: SuiAddress, - fullnode_client: SuiClient, -} - -#[allow(clippy::borrowed_box)] -impl WalletClient { - pub async fn new_from_cluster(cluster: &(dyn Cluster + Sync + Send)) -> Self { - let key = cluster.user_key(); - let address: SuiAddress = key.public().into(); - let wallet_context = new_wallet_context_from_cluster(cluster, key) - .instrument(info_span!("init_wallet_context_for_test_user")); - - let rpc_url = String::from(cluster.fullnode_url()); - info!("Use fullnode rpc: {}", &rpc_url); - let fullnode_client = SuiClientBuilder::default().build(rpc_url).await.unwrap(); - - Self { - wallet_context: wallet_context.into_inner(), - address, - fullnode_client, - } - } - - pub fn get_wallet(&self) -> &WalletContext { - &self.wallet_context - } - - pub fn get_wallet_mut(&mut self) -> &mut WalletContext { - &mut self.wallet_context - } - - pub fn get_wallet_address(&self) -> SuiAddress { - self.address - } - - pub fn get_fullnode_client(&self) -> &SuiClient { - &self.fullnode_client - } - - pub fn sign(&self, txn_data: &TransactionData, desc: &str) -> Signature { - self.get_wallet() - .config - .keystore - .sign_secure(&self.address, txn_data, Intent::sui_transaction()) - .unwrap_or_else(|e| panic!("Failed to sign transaction for {}. {}", desc, e)) - } -} diff --git a/crates/sui-common/Cargo.toml b/crates/sui-common/Cargo.toml deleted file mode 100644 index 32d84e6f8bf..00000000000 --- a/crates/sui-common/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "sui-common" -authors = ["Mysten Labs "] -license = "Apache-2.0" -version = "0.1.0" -edition = "2021" -publish = false - -[dependencies] -sui-types.workspace = true -mysten-metrics.workspace = true -tokio.workspace = true -tracing.workspace = true -futures.workspace = true diff --git a/crates/sui-common/src/lib.rs b/crates/sui-common/src/lib.rs deleted file mode 100644 index 284d4b94752..00000000000 --- a/crates/sui-common/src/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod authority_aggregation; diff --git a/crates/sui-config/Cargo.toml b/crates/sui-config/Cargo.toml deleted file mode 100644 index d5e3a5ac859..00000000000 --- a/crates/sui-config/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = "sui-config" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anemo.workspace = true -anyhow = { workspace = true, features = ["backtrace"] } -bcs.workspace = true -csv.workspace = true -dirs.workspace = true -fastcrypto.workspace = true -once_cell.workspace = true -rand.workspace = true -serde = { workspace = true, features = ["derive", "rc"] } -serde_with.workspace = true -serde_yaml.workspace = true -tracing.workspace = true -prometheus.workspace = true -clap.workspace = true -object_store.workspace = true -reqwest.workspace = true - -narwhal-config.workspace = true -sui-keys.workspace = true -sui-protocol-config.workspace = true -sui-types.workspace = true - -[dev-dependencies] -insta.workspace = true -tempfile.workspace = true -sui-types = { workspace = true, features = ["test-utils"] } diff --git a/crates/sui-config/src/genesis.rs b/crates/sui-config/src/genesis.rs deleted file mode 100644 index f0a6b3eca75..00000000000 --- a/crates/sui-config/src/genesis.rs +++ /dev/null @@ -1,673 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{fs, path::Path}; - -use anyhow::{Context, Result}; -use fastcrypto::{ - encoding::{Base64, Encoding}, - hash::HashFunction, -}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use sui_types::{ - authenticator_state::{get_authenticator_state, AuthenticatorStateInner}, - base_types::{ObjectID, SuiAddress}, - clock::Clock, - committee::{Committee, CommitteeWithNetworkMetadata, EpochId, ProtocolVersion}, - crypto::DefaultHash, - deny_list::{get_coin_deny_list, PerTypeDenyList}, - effects::{TransactionEffects, TransactionEvents}, - error::SuiResult, - gas_coin::TOTAL_SUPPLY_MIST, - messages_checkpoint::{ - CertifiedCheckpointSummary, CheckpointContents, CheckpointSummary, VerifiedCheckpoint, - }, - object::Object, - storage::ObjectStore, - sui_system_state::{ - get_sui_system_state, get_sui_system_state_wrapper, SuiSystemState, SuiSystemStateTrait, - SuiSystemStateWrapper, SuiValidatorGenesis, - }, - transaction::Transaction, - SUI_RANDOMNESS_STATE_OBJECT_ID, -}; -use tracing::trace; - -#[derive(Clone, Debug)] -pub struct Genesis { - checkpoint: CertifiedCheckpointSummary, - checkpoint_contents: CheckpointContents, - transaction: Transaction, - effects: TransactionEffects, - events: TransactionEvents, - objects: Vec, -} - -#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug)] -pub struct UnsignedGenesis { - pub checkpoint: CheckpointSummary, - pub checkpoint_contents: CheckpointContents, - pub transaction: Transaction, - pub effects: TransactionEffects, - pub events: TransactionEvents, - pub objects: Vec, -} - -// Hand implement PartialEq in order to get around the fact that AuthSigs don't -// impl Eq -impl PartialEq for Genesis { - fn eq(&self, other: &Self) -> bool { - self.checkpoint.data() == other.checkpoint.data() - && { - let this = self.checkpoint.auth_sig(); - let other = other.checkpoint.auth_sig(); - - this.epoch == other.epoch - && this.signature.as_ref() == other.signature.as_ref() - && this.signers_map == other.signers_map - } - && self.checkpoint_contents == other.checkpoint_contents - && self.transaction == other.transaction - && self.effects == other.effects - && self.objects == other.objects - } -} - -impl Eq for Genesis {} - -impl Genesis { - pub fn new( - checkpoint: CertifiedCheckpointSummary, - checkpoint_contents: CheckpointContents, - transaction: Transaction, - effects: TransactionEffects, - events: TransactionEvents, - objects: Vec, - ) -> Self { - Self { - checkpoint, - checkpoint_contents, - transaction, - effects, - events, - objects, - } - } - - pub fn objects(&self) -> &[Object] { - &self.objects - } - - pub fn object(&self, id: ObjectID) -> Option { - self.objects.iter().find(|o| o.id() == id).cloned() - } - - pub fn transaction(&self) -> &Transaction { - &self.transaction - } - - pub fn effects(&self) -> &TransactionEffects { - &self.effects - } - pub fn events(&self) -> &TransactionEvents { - &self.events - } - - pub fn checkpoint(&self) -> VerifiedCheckpoint { - self.checkpoint - .clone() - .verify(&self.committee().unwrap()) - .unwrap() - } - - pub fn checkpoint_contents(&self) -> &CheckpointContents { - &self.checkpoint_contents - } - - pub fn epoch(&self) -> EpochId { - 0 - } - - pub fn validator_set_for_tooling(&self) -> Vec { - self.sui_system_object() - .into_genesis_version_for_tooling() - .validators - .active_validators - } - - pub fn committee_with_network(&self) -> CommitteeWithNetworkMetadata { - self.sui_system_object().get_current_epoch_committee() - } - - pub fn reference_gas_price(&self) -> u64 { - self.sui_system_object().reference_gas_price() - } - - // TODO: No need to return SuiResult. - pub fn committee(&self) -> SuiResult { - Ok(self.committee_with_network().committee) - } - - pub fn sui_system_wrapper_object(&self) -> SuiSystemStateWrapper { - get_sui_system_state_wrapper(&self.objects()) - .expect("Sui System State Wrapper object must always exist") - } - - pub fn sui_system_object(&self) -> SuiSystemState { - get_sui_system_state(&self.objects()).expect("Sui System State object must always exist") - } - - pub fn clock(&self) -> Clock { - let clock = self - .objects() - .iter() - .find(|o| o.id() == sui_types::SUI_CLOCK_OBJECT_ID) - .expect("Clock must always exist") - .data - .try_as_move() - .expect("Clock must be a Move object"); - bcs::from_bytes::(clock.contents()) - .expect("Clock object deserialization cannot fail") - } - - pub fn load>(path: P) -> Result { - let path = path.as_ref(); - trace!("Reading Genesis from {}", path.display()); - let bytes = fs::read(path) - .with_context(|| format!("Unable to load Genesis from {}", path.display()))?; - bcs::from_bytes(&bytes) - .with_context(|| format!("Unable to parse Genesis from {}", path.display())) - } - - pub fn save>(&self, path: P) -> Result<(), anyhow::Error> { - let path = path.as_ref(); - trace!("Writing Genesis to {}", path.display()); - let bytes = bcs::to_bytes(&self)?; - fs::write(path, bytes) - .with_context(|| format!("Unable to save Genesis to {}", path.display()))?; - Ok(()) - } - - pub fn to_bytes(&self) -> Vec { - bcs::to_bytes(self).expect("failed to serialize genesis") - } - - pub fn hash(&self) -> [u8; 32] { - use std::io::Write; - - let mut digest = DefaultHash::default(); - digest.write_all(&self.to_bytes()).unwrap(); - let hash = digest.finalize(); - hash.into() - } -} - -impl Serialize for Genesis { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - use serde::ser::Error; - - #[derive(Serialize)] - struct RawGenesis<'a> { - checkpoint: &'a CertifiedCheckpointSummary, - checkpoint_contents: &'a CheckpointContents, - transaction: &'a Transaction, - effects: &'a TransactionEffects, - events: &'a TransactionEvents, - objects: &'a [Object], - } - - let raw_genesis = RawGenesis { - checkpoint: &self.checkpoint, - checkpoint_contents: &self.checkpoint_contents, - transaction: &self.transaction, - effects: &self.effects, - events: &self.events, - objects: &self.objects, - }; - - let bytes = bcs::to_bytes(&raw_genesis).map_err(|e| Error::custom(e.to_string()))?; - - if serializer.is_human_readable() { - let s = Base64::encode(&bytes); - serializer.serialize_str(&s) - } else { - serializer.serialize_bytes(&bytes) - } - } -} - -impl<'de> Deserialize<'de> for Genesis { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - use serde::de::Error; - - #[derive(Deserialize)] - struct RawGenesis { - checkpoint: CertifiedCheckpointSummary, - checkpoint_contents: CheckpointContents, - transaction: Transaction, - effects: TransactionEffects, - events: TransactionEvents, - objects: Vec, - } - - let bytes = if deserializer.is_human_readable() { - let s = String::deserialize(deserializer)?; - Base64::decode(&s).map_err(|e| Error::custom(e.to_string()))? - } else { - let data: Vec = Vec::deserialize(deserializer)?; - data - }; - - let RawGenesis { - checkpoint, - checkpoint_contents, - transaction, - effects, - events, - objects, - } = bcs::from_bytes(&bytes).map_err(|e| Error::custom(e.to_string()))?; - - Ok(Genesis { - checkpoint, - checkpoint_contents, - transaction, - effects, - events, - objects, - }) - } -} - -impl UnsignedGenesis { - pub fn objects(&self) -> &[Object] { - &self.objects - } - - pub fn object(&self, id: ObjectID) -> Option { - self.objects.iter().find(|o| o.id() == id).cloned() - } - - pub fn transaction(&self) -> &Transaction { - &self.transaction - } - - pub fn effects(&self) -> &TransactionEffects { - &self.effects - } - pub fn events(&self) -> &TransactionEvents { - &self.events - } - - pub fn checkpoint(&self) -> &CheckpointSummary { - &self.checkpoint - } - - pub fn checkpoint_contents(&self) -> &CheckpointContents { - &self.checkpoint_contents - } - - pub fn epoch(&self) -> EpochId { - 0 - } - - pub fn sui_system_wrapper_object(&self) -> SuiSystemStateWrapper { - get_sui_system_state_wrapper(&self.objects()) - .expect("Sui System State Wrapper object must always exist") - } - - pub fn sui_system_object(&self) -> SuiSystemState { - get_sui_system_state(&self.objects()).expect("Sui System State object must always exist") - } - - pub fn authenticator_state_object(&self) -> Option { - get_authenticator_state(&self.objects()).expect("read from genesis cannot fail") - } - - pub fn has_randomness_state_object(&self) -> bool { - self.objects() - .get_object(&SUI_RANDOMNESS_STATE_OBJECT_ID) - .expect("read from genesis cannot fail") - .is_some() - } - - pub fn coin_deny_list_state(&self) -> Option { - get_coin_deny_list(&self.objects()) - } -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub struct GenesisChainParameters { - pub protocol_version: u64, - pub chain_start_timestamp_ms: u64, - pub epoch_duration_ms: u64, - - // Stake Subsidy parameters - pub stake_subsidy_start_epoch: u64, - pub stake_subsidy_initial_distribution_amount: u64, - pub stake_subsidy_period_length: u64, - pub stake_subsidy_decrease_rate: u16, - - // Validator committee parameters - pub max_validator_count: u64, - pub min_validator_joining_stake: u64, - pub validator_low_stake_threshold: u64, - pub validator_very_low_stake_threshold: u64, - pub validator_low_stake_grace_period: u64, -} - -/// Initial set of parameters for a chain. -#[derive(Serialize, Deserialize)] -pub struct GenesisCeremonyParameters { - #[serde(default = "GenesisCeremonyParameters::default_timestamp_ms")] - pub chain_start_timestamp_ms: u64, - - /// protocol version that the chain starts at. - #[serde(default = "ProtocolVersion::max")] - pub protocol_version: ProtocolVersion, - - #[serde(default = "GenesisCeremonyParameters::default_allow_insertion_of_extra_objects")] - pub allow_insertion_of_extra_objects: bool, - - /// The duration of an epoch, in milliseconds. - #[serde(default = "GenesisCeremonyParameters::default_epoch_duration_ms")] - pub epoch_duration_ms: u64, - - /// The starting epoch in which stake subsidies start being paid out. - #[serde(default)] - pub stake_subsidy_start_epoch: u64, - - /// The amount of stake subsidy to be drawn down per distribution. - /// This amount decays and decreases over time. - #[serde( - default = "GenesisCeremonyParameters::default_initial_stake_subsidy_distribution_amount" - )] - pub stake_subsidy_initial_distribution_amount: u64, - - /// Number of distributions to occur before the distribution amount decays. - #[serde(default = "GenesisCeremonyParameters::default_stake_subsidy_period_length")] - pub stake_subsidy_period_length: u64, - - /// The rate at which the distribution amount decays at the end of each - /// period. Expressed in basis points. - #[serde(default = "GenesisCeremonyParameters::default_stake_subsidy_decrease_rate")] - pub stake_subsidy_decrease_rate: u16, - // Most other parameters (e.g. initial gas schedule) should be derived from protocol_version. -} - -impl GenesisCeremonyParameters { - pub fn new() -> Self { - Self { - chain_start_timestamp_ms: Self::default_timestamp_ms(), - protocol_version: ProtocolVersion::MAX, - allow_insertion_of_extra_objects: true, - stake_subsidy_start_epoch: 0, - epoch_duration_ms: Self::default_epoch_duration_ms(), - stake_subsidy_initial_distribution_amount: - Self::default_initial_stake_subsidy_distribution_amount(), - stake_subsidy_period_length: Self::default_stake_subsidy_period_length(), - stake_subsidy_decrease_rate: Self::default_stake_subsidy_decrease_rate(), - } - } - - fn default_timestamp_ms() -> u64 { - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_millis() as u64 - } - - fn default_allow_insertion_of_extra_objects() -> bool { - true - } - - fn default_epoch_duration_ms() -> u64 { - // 24 hrs - 24 * 60 * 60 * 1000 - } - - fn default_initial_stake_subsidy_distribution_amount() -> u64 { - // 1M Sui - 1_000_000 * sui_types::gas_coin::MIST_PER_SUI - } - - fn default_stake_subsidy_period_length() -> u64 { - // 10 distributions or epochs - 10 - } - - fn default_stake_subsidy_decrease_rate() -> u16 { - // 10% in basis points - 1000 - } - - pub fn to_genesis_chain_parameters(&self) -> GenesisChainParameters { - GenesisChainParameters { - protocol_version: self.protocol_version.as_u64(), - stake_subsidy_start_epoch: self.stake_subsidy_start_epoch, - chain_start_timestamp_ms: self.chain_start_timestamp_ms, - epoch_duration_ms: self.epoch_duration_ms, - stake_subsidy_initial_distribution_amount: self - .stake_subsidy_initial_distribution_amount, - stake_subsidy_period_length: self.stake_subsidy_period_length, - stake_subsidy_decrease_rate: self.stake_subsidy_decrease_rate, - max_validator_count: sui_types::governance::MAX_VALIDATOR_COUNT, - min_validator_joining_stake: sui_types::governance::MIN_VALIDATOR_JOINING_STAKE_MIST, - validator_low_stake_threshold: - sui_types::governance::VALIDATOR_LOW_STAKE_THRESHOLD_MIST, - validator_very_low_stake_threshold: - sui_types::governance::VALIDATOR_VERY_LOW_STAKE_THRESHOLD_MIST, - validator_low_stake_grace_period: - sui_types::governance::VALIDATOR_LOW_STAKE_GRACE_PERIOD, - } - } -} - -impl Default for GenesisCeremonyParameters { - fn default() -> Self { - Self::new() - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub struct TokenDistributionSchedule { - pub stake_subsidy_fund_mist: u64, - pub allocations: Vec, -} - -impl TokenDistributionSchedule { - pub fn validate(&self) { - let mut total_mist = self.stake_subsidy_fund_mist; - - for allocation in &self.allocations { - total_mist += allocation.amount_mist; - } - - if total_mist != TOTAL_SUPPLY_MIST { - panic!( - "TokenDistributionSchedule adds up to {total_mist} and not expected {TOTAL_SUPPLY_MIST}" - ); - } - } - - pub fn check_all_stake_operations_are_for_valid_validators< - I: IntoIterator, - >( - &self, - validators: I, - ) { - use std::collections::HashMap; - - let mut validators: HashMap = - validators.into_iter().map(|a| (a, 0)).collect(); - - // Check that all allocations are for valid validators, while summing up all - // allocations for each validator - for allocation in &self.allocations { - if let Some(staked_with_validator) = &allocation.staked_with_validator { - *validators - .get_mut(staked_with_validator) - .expect("allocation must be staked with valid validator") += - allocation.amount_mist; - } - } - - // Check that all validators have sufficient stake allocated to ensure they meet - // the minimum stake threshold - let minimum_required_stake = sui_types::governance::VALIDATOR_LOW_STAKE_THRESHOLD_MIST; - for (validator, stake) in validators { - if stake < minimum_required_stake { - panic!( - "validator {validator} has '{stake}' stake and does not meet the minimum required stake threshold of '{minimum_required_stake}'" - ); - } - } - } - - pub fn new_for_validators_with_default_allocation>( - validators: I, - ) -> Self { - let mut supply = TOTAL_SUPPLY_MIST; - let default_allocation = sui_types::governance::VALIDATOR_LOW_STAKE_THRESHOLD_MIST; - - let allocations = validators - .into_iter() - .map(|a| { - supply -= default_allocation; - TokenAllocation { - recipient_address: a, - amount_mist: default_allocation, - staked_with_validator: Some(a), - } - }) - .collect(); - - let schedule = Self { - stake_subsidy_fund_mist: supply, - allocations, - }; - - schedule.validate(); - schedule - } - - /// Helper to read a TokenDistributionSchedule from a csv file. - /// - /// The file is encoded such that the final entry in the CSV file is used to - /// denote the allocation to the stake subsidy fund. It must be in the - /// following format: - /// `0x0000000000000000000000000000000000000000000000000000000000000000, - /// ,` - /// - /// All entries in a token distribution schedule must add up to 10B Sui. - pub fn from_csv(reader: R) -> Result { - let mut reader = csv::Reader::from_reader(reader); - let mut allocations: Vec = - reader.deserialize().collect::>()?; - assert_eq!( - TOTAL_SUPPLY_MIST, - allocations.iter().map(|a| a.amount_mist).sum::(), - "Token Distribution Schedule must add up to 10B Sui", - ); - let stake_subsidy_fund_allocation = allocations.pop().unwrap(); - assert_eq!( - SuiAddress::default(), - stake_subsidy_fund_allocation.recipient_address, - "Final allocation must be for stake subsidy fund", - ); - assert!( - stake_subsidy_fund_allocation - .staked_with_validator - .is_none(), - "Can't stake the stake subsidy fund", - ); - - let schedule = Self { - stake_subsidy_fund_mist: stake_subsidy_fund_allocation.amount_mist, - allocations, - }; - - schedule.validate(); - Ok(schedule) - } - - pub fn to_csv(&self, writer: W) -> Result<()> { - let mut writer = csv::Writer::from_writer(writer); - - for allocation in &self.allocations { - writer.serialize(allocation)?; - } - - writer.serialize(TokenAllocation { - recipient_address: SuiAddress::default(), - amount_mist: self.stake_subsidy_fund_mist, - staked_with_validator: None, - })?; - - Ok(()) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub struct TokenAllocation { - pub recipient_address: SuiAddress, - pub amount_mist: u64, - - /// Indicates if this allocation should be staked at genesis and with which - /// validator - pub staked_with_validator: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct TokenDistributionScheduleBuilder { - pool: u64, - allocations: Vec, -} - -impl TokenDistributionScheduleBuilder { - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - Self { - pool: TOTAL_SUPPLY_MIST, - allocations: vec![], - } - } - - pub fn default_allocation_for_validators>( - &mut self, - validators: I, - ) { - let default_allocation = sui_types::governance::VALIDATOR_LOW_STAKE_THRESHOLD_MIST; - - for validator in validators { - self.add_allocation(TokenAllocation { - recipient_address: validator, - amount_mist: default_allocation, - staked_with_validator: Some(validator), - }); - } - } - - pub fn add_allocation(&mut self, allocation: TokenAllocation) { - self.pool = self.pool.checked_sub(allocation.amount_mist).unwrap(); - self.allocations.push(allocation); - } - - pub fn build(&self) -> TokenDistributionSchedule { - let schedule = TokenDistributionSchedule { - stake_subsidy_fund_mist: self.pool, - allocations: self.allocations.clone(), - }; - - schedule.validate(); - schedule - } -} diff --git a/crates/sui-config/src/lib.rs b/crates/sui-config/src/lib.rs deleted file mode 100644 index df424e9ee39..00000000000 --- a/crates/sui-config/src/lib.rs +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - fs, - path::{Path, PathBuf}, -}; - -use anyhow::{Context, Result}; -use serde::{de::DeserializeOwned, Serialize}; -use tracing::trace; - -pub mod certificate_deny_config; -pub mod genesis; -pub mod local_ip_utils; -pub mod node; -pub mod node_config_metrics; -pub mod object_storage_config; -pub mod p2p; -pub mod transaction_deny_config; - -pub use node::{ConsensusConfig, NodeConfig}; -use sui_types::multiaddr::Multiaddr; - -const SUI_DIR: &str = ".sui"; -pub const SUI_CONFIG_DIR: &str = "sui_config"; -pub const SUI_NETWORK_CONFIG: &str = "network.yaml"; -pub const SUI_FULLNODE_CONFIG: &str = "fullnode.yaml"; -pub const SUI_CLIENT_CONFIG: &str = "client.yaml"; -pub const SUI_KEYSTORE_FILENAME: &str = "sui.keystore"; -pub const SUI_KEYSTORE_ALIASES_FILENAME: &str = "sui.aliases"; -pub const SUI_BENCHMARK_GENESIS_GAS_KEYSTORE_FILENAME: &str = "benchmark.keystore"; -pub const SUI_GENESIS_FILENAME: &str = "genesis.blob"; -pub const SUI_DEV_NET_URL: &str = "https://fullnode.devnet.sui.io:443"; - -pub const AUTHORITIES_DB_NAME: &str = "authorities_db"; -pub const CONSENSUS_DB_NAME: &str = "consensus_db"; -pub const FULL_NODE_DB_PATH: &str = "full_node_db"; - -pub fn sui_config_dir() -> Result { - match std::env::var_os("SUI_CONFIG_DIR") { - Some(config_env) => Ok(config_env.into()), - None => match dirs::home_dir() { - Some(v) => Ok(v.join(SUI_DIR).join(SUI_CONFIG_DIR)), - None => anyhow::bail!("Cannot obtain home directory path"), - }, - } - .and_then(|dir| { - if !dir.exists() { - fs::create_dir_all(dir.clone())?; - } - Ok(dir) - }) -} - -pub fn validator_config_file(address: Multiaddr, i: usize) -> String { - multiaddr_to_filename(address).unwrap_or(format!("validator-config-{}.yaml", i)) -} - -pub fn ssfn_config_file(address: Multiaddr, i: usize) -> String { - multiaddr_to_filename(address).unwrap_or(format!("ssfn-config-{}.yaml", i)) -} - -fn multiaddr_to_filename(address: Multiaddr) -> Option { - if let Some(hostname) = address.hostname() { - if let Some(port) = address.port() { - return Some(format!("{}-{}.yaml", hostname, port)); - } - } - None -} - -pub trait Config -where - Self: DeserializeOwned + Serialize, -{ - fn persisted(self, path: &Path) -> PersistedConfig { - PersistedConfig { - inner: self, - path: path.to_path_buf(), - } - } - - fn load>(path: P) -> Result { - let path = path.as_ref(); - trace!("Reading config from {}", path.display()); - let reader = fs::File::open(path) - .with_context(|| format!("Unable to load config from {}", path.display()))?; - Ok(serde_yaml::from_reader(reader)?) - } - - fn save>(&self, path: P) -> Result<(), anyhow::Error> { - let path = path.as_ref(); - trace!("Writing config to {}", path.display()); - let config = serde_yaml::to_string(&self)?; - fs::write(path, config) - .with_context(|| format!("Unable to save config to {}", path.display()))?; - Ok(()) - } -} - -pub struct PersistedConfig { - inner: C, - path: PathBuf, -} - -impl PersistedConfig -where - C: Config, -{ - pub fn read(path: &Path) -> Result { - Config::load(path) - } - - pub fn save(&self) -> Result<(), anyhow::Error> { - self.inner.save(&self.path) - } - - pub fn into_inner(self) -> C { - self.inner - } - - pub fn path(&self) -> &Path { - &self.path - } -} - -impl std::ops::Deref for PersistedConfig { - type Target = C; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl std::ops::DerefMut for PersistedConfig { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} diff --git a/crates/sui-config/src/node.rs b/crates/sui-config/src/node.rs deleted file mode 100644 index cf2ce247006..00000000000 --- a/crates/sui-config/src/node.rs +++ /dev/null @@ -1,1089 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use std::{ - collections::{BTreeMap, BTreeSet}, - net::SocketAddr, - num::NonZeroUsize, - path::{Path, PathBuf}, - sync::Arc, - time::Duration, - usize, -}; - -use anyhow::Result; -use narwhal_config::Parameters as ConsensusParameters; -use once_cell::sync::OnceCell; -use rand::rngs::OsRng; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use sui_keys::keypair_file::{read_authority_keypair_from_file, read_keypair_from_file}; -use sui_protocol_config::{Chain, SupportedProtocolVersions}; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, - committee::EpochId, - crypto::{ - get_key_pair_from_rng, AccountKeyPair, AuthorityKeyPair, AuthorityPublicKeyBytes, - KeypairTraits, NetworkKeyPair, SuiKeyPair, - }, - messages_checkpoint::CheckpointSequenceNumber, - multiaddr::Multiaddr, -}; -use tracing::info; - -use crate::{ - certificate_deny_config::CertificateDenyConfig, genesis, - object_storage_config::ObjectStoreConfig, p2p::P2pConfig, - transaction_deny_config::TransactionDenyConfig, Config, -}; - -// Default max number of concurrent requests served -pub const DEFAULT_GRPC_CONCURRENCY_LIMIT: usize = 20000000000; - -/// Default gas price of 100 Mist -pub const DEFAULT_VALIDATOR_GAS_PRICE: u64 = sui_types::transaction::DEFAULT_VALIDATOR_GAS_PRICE; - -/// Default commission rate of 2% -pub const DEFAULT_COMMISSION_RATE: u64 = 200; - -#[serde_as] -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct NodeConfig { - #[serde(default = "default_authority_key_pair")] - pub protocol_key_pair: AuthorityKeyPairWithPath, - #[serde(default = "default_key_pair")] - pub worker_key_pair: KeyPairWithPath, - #[serde(default = "default_key_pair")] - pub account_key_pair: KeyPairWithPath, - #[serde(default = "default_key_pair")] - pub network_key_pair: KeyPairWithPath, - - pub db_path: PathBuf, - #[serde(default = "default_grpc_address")] - pub network_address: Multiaddr, - #[serde(default = "default_json_rpc_address")] - pub json_rpc_address: SocketAddr, - - #[serde(default)] - pub enable_experimental_rest_api: bool, - - #[serde(default = "default_metrics_address")] - pub metrics_address: SocketAddr, - #[serde(default = "default_admin_interface_port")] - pub admin_interface_port: u16, - - #[serde(skip_serializing_if = "Option::is_none")] - pub consensus_config: Option, - - // TODO: Remove this as it's no longer used. - #[serde(default)] - pub enable_event_processing: bool, - - #[serde(default = "default_enable_index_processing")] - pub enable_index_processing: bool, - - // only alow websocket connections for jsonrpc traffic - #[serde(default)] - pub websocket_only: bool, - - #[serde(default)] - pub grpc_load_shed: Option, - - #[serde(default = "default_concurrency_limit")] - pub grpc_concurrency_limit: Option, - - #[serde(default)] - pub p2p_config: P2pConfig, - - pub genesis: Genesis, - - #[serde(default = "default_authority_store_pruning_config")] - pub authority_store_pruning_config: AuthorityStorePruningConfig, - - /// Size of the broadcast channel used for notifying other systems of end of - /// epoch. - /// - /// If unspecified, this will default to `128`. - #[serde(default = "default_end_of_epoch_broadcast_channel_capacity")] - pub end_of_epoch_broadcast_channel_capacity: usize, - - #[serde(default)] - pub checkpoint_executor_config: CheckpointExecutorConfig, - - #[serde(skip_serializing_if = "Option::is_none")] - pub metrics: Option, - - /// In a `sui-node` binary, this is set to - /// SupportedProtocolVersions::SYSTEM_DEFAULT in sui-node/src/main.rs. - /// It is present in the config so that it can be changed by tests in - /// order to test protocol upgrades. - #[serde(skip)] - pub supported_protocol_versions: Option, - - #[serde(default)] - pub db_checkpoint_config: DBCheckpointConfig, - - #[serde(default)] - pub indirect_objects_threshold: usize, - - #[serde(default)] - pub expensive_safety_check_config: ExpensiveSafetyCheckConfig, - - #[serde(skip_serializing_if = "Option::is_none")] - pub name_service_package_address: Option, - - #[serde(skip_serializing_if = "Option::is_none")] - pub name_service_registry_id: Option, - - #[serde(skip_serializing_if = "Option::is_none")] - pub name_service_reverse_registry_id: Option, - - #[serde(default)] - pub transaction_deny_config: TransactionDenyConfig, - - #[serde(default)] - pub certificate_deny_config: CertificateDenyConfig, - - #[serde(default)] - pub state_debug_dump_config: StateDebugDumpConfig, - - #[serde(default)] - pub state_archive_write_config: StateArchiveConfig, - - #[serde(default)] - pub state_archive_read_config: Vec, - - #[serde(default)] - pub state_snapshot_write_config: StateSnapshotConfig, - - #[serde(default)] - pub indexer_max_subscriptions: Option, - - #[serde(default = "default_transaction_kv_store_config")] - pub transaction_kv_store_read_config: TransactionKeyValueStoreReadConfig, - - #[serde(skip_serializing_if = "Option::is_none")] - pub transaction_kv_store_write_config: Option, - - #[serde(default = "default_jwk_fetch_interval_seconds")] - pub jwk_fetch_interval_seconds: u64, - - #[serde(default = "default_zklogin_oauth_providers")] - pub zklogin_oauth_providers: BTreeMap>, - - #[serde(default = "default_authority_overload_config")] - pub authority_overload_config: AuthorityOverloadConfig, - - #[serde(skip_serializing_if = "Option::is_none")] - pub run_with_range: Option, -} - -#[derive(Clone, Debug, Deserialize, Serialize, Default)] -#[serde(rename_all = "kebab-case")] -pub struct TransactionKeyValueStoreReadConfig { - pub base_url: String, -} - -fn default_jwk_fetch_interval_seconds() -> u64 { - 3600 -} - -pub fn default_zklogin_oauth_providers() -> BTreeMap> { - let mut map = BTreeMap::new(); - let experimental_providers = BTreeSet::from([ - "Google".to_string(), - "Facebook".to_string(), - "Twitch".to_string(), - "Kakao".to_string(), - "Apple".to_string(), - "Slack".to_string(), - ]); - let providers = BTreeSet::from([ - "Google".to_string(), - "Facebook".to_string(), - "Twitch".to_string(), - "Apple".to_string(), - ]); - map.insert(Chain::Mainnet, providers.clone()); - map.insert(Chain::Testnet, providers); - map.insert(Chain::Unknown, experimental_providers); - map -} - -fn default_transaction_kv_store_config() -> TransactionKeyValueStoreReadConfig { - TransactionKeyValueStoreReadConfig { - base_url: "https://transactions.sui.io/".to_string(), - } -} - -fn default_authority_store_pruning_config() -> AuthorityStorePruningConfig { - AuthorityStorePruningConfig::default() -} - -pub fn default_enable_index_processing() -> bool { - true -} - -fn default_grpc_address() -> Multiaddr { - "/ip4/0.0.0.0/tcp/8080".parse().unwrap() -} -fn default_authority_key_pair() -> AuthorityKeyPairWithPath { - AuthorityKeyPairWithPath::new(get_key_pair_from_rng::(&mut OsRng).1) -} - -fn default_key_pair() -> KeyPairWithPath { - KeyPairWithPath::new( - get_key_pair_from_rng::(&mut OsRng) - .1 - .into(), - ) -} - -fn default_metrics_address() -> SocketAddr { - use std::net::{IpAddr, Ipv4Addr}; - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9184) -} - -pub fn default_admin_interface_port() -> u16 { - 1337 -} - -pub fn default_json_rpc_address() -> SocketAddr { - use std::net::{IpAddr, Ipv4Addr}; - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9000) -} - -pub fn default_concurrency_limit() -> Option { - Some(DEFAULT_GRPC_CONCURRENCY_LIMIT) -} - -pub fn default_end_of_epoch_broadcast_channel_capacity() -> usize { - 128 -} - -pub fn bool_true() -> bool { - true -} - -impl Config for NodeConfig {} - -impl NodeConfig { - pub fn protocol_key_pair(&self) -> &AuthorityKeyPair { - self.protocol_key_pair.authority_keypair() - } - - pub fn worker_key_pair(&self) -> &NetworkKeyPair { - match self.worker_key_pair.keypair() { - SuiKeyPair::Ed25519(kp) => kp, - other => panic!( - "Invalid keypair type: {:?}, only Ed25519 is allowed for worker key", - other - ), - } - } - - pub fn network_key_pair(&self) -> &NetworkKeyPair { - match self.network_key_pair.keypair() { - SuiKeyPair::Ed25519(kp) => kp, - other => panic!( - "Invalid keypair type: {:?}, only Ed25519 is allowed for network key", - other - ), - } - } - - pub fn protocol_public_key(&self) -> AuthorityPublicKeyBytes { - self.protocol_key_pair().public().into() - } - - pub fn db_path(&self) -> PathBuf { - self.db_path.join("live") - } - - pub fn db_checkpoint_path(&self) -> PathBuf { - self.db_path.join("db_checkpoints") - } - - pub fn archive_path(&self) -> PathBuf { - self.db_path.join("archive") - } - - pub fn snapshot_path(&self) -> PathBuf { - self.db_path.join("snapshot") - } - - pub fn network_address(&self) -> &Multiaddr { - &self.network_address - } - - pub fn consensus_config(&self) -> Option<&ConsensusConfig> { - self.consensus_config.as_ref() - } - - pub fn genesis(&self) -> Result<&genesis::Genesis> { - self.genesis.genesis() - } - - pub fn sui_address(&self) -> SuiAddress { - (&self.account_key_pair.keypair().public()).into() - } - - pub fn archive_reader_config(&self) -> Vec { - self.state_archive_read_config - .iter() - .flat_map(|config| { - config - .object_store_config - .as_ref() - .map(|remote_store_config| ArchiveReaderConfig { - remote_store_config: remote_store_config.clone(), - download_concurrency: NonZeroUsize::new(config.concurrency) - .unwrap_or(NonZeroUsize::new(5).unwrap()), - use_for_pruning_watermark: config.use_for_pruning_watermark, - }) - }) - .collect() - } -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub enum ConsensusProtocol { - #[serde(rename = "narwhal")] - Narwhal, - #[serde(rename = "mysticeti")] - Mysticeti, -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct ConsensusConfig { - pub address: Multiaddr, - pub db_path: PathBuf, - - /// Optional alternative address preferentially used by a primary to talk to - /// its own worker. For example, this could be used to connect to - /// co-located workers over a private LAN address. - pub internal_worker_address: Option, - - /// Maximum number of pending transactions to submit to consensus, including - /// those in submission wait. - /// Assuming 10_000 txn tps * 10 sec consensus latency = 100_000 inflight - /// consensus txns, Default to 100_000. - pub max_pending_transactions: Option, - - /// When defined caps the calculated submission position to the - /// max_submit_position. Even if the is elected to submit from a higher - /// position than this, it will "reset" to the max_submit_position. - pub max_submit_position: Option, - - /// The submit delay step to consensus defined in milliseconds. When - /// provided it will override the current back off logic otherwise the - /// default backoff logic will be applied based on consensus latency - /// estimates. - pub submit_delay_step_override_millis: Option, - - pub narwhal_config: ConsensusParameters, - - /// The choice of consensus protocol to run. We default to Narwhal. - #[serde(skip)] - #[serde(default = "default_consensus_protocol")] - pub protocol: ConsensusProtocol, -} - -impl ConsensusConfig { - pub fn address(&self) -> &Multiaddr { - &self.address - } - - pub fn db_path(&self) -> &Path { - &self.db_path - } - - pub fn max_pending_transactions(&self) -> usize { - self.max_pending_transactions.unwrap_or(100_000) - } - - pub fn submit_delay_step_override(&self) -> Option { - self.submit_delay_step_override_millis - .map(Duration::from_millis) - } - - pub fn narwhal_config(&self) -> &ConsensusParameters { - &self.narwhal_config - } -} - -pub fn default_consensus_protocol() -> ConsensusProtocol { - ConsensusProtocol::Narwhal -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct CheckpointExecutorConfig { - /// Upper bound on the number of checkpoints that can be concurrently - /// executed - /// - /// If unspecified, this will default to `200` - #[serde(default = "default_checkpoint_execution_max_concurrency")] - pub checkpoint_execution_max_concurrency: usize, - - /// Number of seconds to wait for effects of a batch of transactions - /// before logging a warning. Note that we will continue to retry - /// indefinitely - /// - /// If unspecified, this will default to `10`. - #[serde(default = "default_local_execution_timeout_sec")] - pub local_execution_timeout_sec: u64, - - /// Optional directory used for data ingestion pipeline - /// When specified, each executed checkpoint will be saved in a local - /// directory for post processing - #[serde(default, skip_serializing_if = "Option::is_none")] - pub data_ingestion_dir: Option, -} - -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct ExpensiveSafetyCheckConfig { - /// If enabled, at epoch boundary, we will check that the storage - /// fund balance is always identical to the sum of the storage - /// rebate of all live objects, and that the total SUI in the network - /// remains the same. - #[serde(default)] - enable_epoch_sui_conservation_check: bool, - - /// If enabled, we will check that the total SUI in all input objects of a - /// tx (both the Move part and the storage rebate) matches the total SUI - /// in all output objects of the tx + gas fees - #[serde(default)] - enable_deep_per_tx_sui_conservation_check: bool, - - /// Disable epoch SUI conservation check even when we are running in debug - /// mode. - #[serde(default)] - force_disable_epoch_sui_conservation_check: bool, - - /// If enabled, at epoch boundary, we will check that the accumulated - /// live object state matches the end of epoch root state digest. - #[serde(default)] - enable_state_consistency_check: bool, - - /// Disable state consistency check even when we are running in debug mode. - #[serde(default)] - force_disable_state_consistency_check: bool, - - #[serde(default)] - enable_secondary_index_checks: bool, - // TODO: Add more expensive checks here -} - -impl ExpensiveSafetyCheckConfig { - pub fn new_enable_all() -> Self { - Self { - enable_epoch_sui_conservation_check: true, - enable_deep_per_tx_sui_conservation_check: true, - force_disable_epoch_sui_conservation_check: false, - enable_state_consistency_check: true, - force_disable_state_consistency_check: false, - enable_secondary_index_checks: false, // Disable by default for now - } - } - - pub fn new_disable_all() -> Self { - Self { - enable_epoch_sui_conservation_check: false, - enable_deep_per_tx_sui_conservation_check: false, - force_disable_epoch_sui_conservation_check: true, - enable_state_consistency_check: false, - force_disable_state_consistency_check: true, - enable_secondary_index_checks: false, - } - } - - pub fn force_disable_epoch_sui_conservation_check(&mut self) { - self.force_disable_epoch_sui_conservation_check = true; - } - - pub fn enable_epoch_sui_conservation_check(&self) -> bool { - (self.enable_epoch_sui_conservation_check || cfg!(debug_assertions)) - && !self.force_disable_epoch_sui_conservation_check - } - - pub fn force_disable_state_consistency_check(&mut self) { - self.force_disable_state_consistency_check = true; - } - - pub fn enable_state_consistency_check(&self) -> bool { - (self.enable_state_consistency_check || cfg!(debug_assertions)) - && !self.force_disable_state_consistency_check - } - - pub fn enable_deep_per_tx_sui_conservation_check(&self) -> bool { - self.enable_deep_per_tx_sui_conservation_check || cfg!(debug_assertions) - } - - pub fn enable_secondary_index_checks(&self) -> bool { - self.enable_secondary_index_checks - } -} - -fn default_checkpoint_execution_max_concurrency() -> usize { - 200 -} - -fn default_local_execution_timeout_sec() -> u64 { - 30 -} - -impl Default for CheckpointExecutorConfig { - fn default() -> Self { - Self { - checkpoint_execution_max_concurrency: default_checkpoint_execution_max_concurrency(), - local_execution_timeout_sec: default_local_execution_timeout_sec(), - data_ingestion_dir: None, - } - } -} - -#[derive(Debug, Clone, Copy, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct AuthorityStorePruningConfig { - /// number of the latest epoch dbs to retain - #[serde(default = "default_num_latest_epoch_dbs_to_retain")] - pub num_latest_epoch_dbs_to_retain: usize, - /// time interval used by the pruner to determine whether there are any - /// epoch DBs to remove - #[serde(default = "default_epoch_db_pruning_period_secs")] - pub epoch_db_pruning_period_secs: u64, - /// number of epochs to keep the latest version of objects for. - /// Note that a zero value corresponds to an aggressive pruner. - /// This mode is experimental and needs to be used with caution. - /// Use `u64::MAX` to disable the pruner for the objects. - #[serde(default)] - pub num_epochs_to_retain: u64, - /// pruner's runtime interval used for aggressive mode - #[serde(skip_serializing_if = "Option::is_none")] - pub pruning_run_delay_seconds: Option, - /// maximum number of checkpoints in the pruning batch. Can be adjusted to - /// increase performance - #[serde(default = "default_max_checkpoints_in_batch")] - pub max_checkpoints_in_batch: usize, - /// maximum number of transaction in the pruning batch - #[serde(default = "default_max_transactions_in_batch")] - pub max_transactions_in_batch: usize, - /// enables periodic background compaction for old SST files whose last - /// modified time is older than `periodic_compaction_threshold_days` - /// days. That ensures that all sst files eventually go through the - /// compaction process - #[serde(skip_serializing_if = "Option::is_none")] - pub periodic_compaction_threshold_days: Option, - /// number of epochs to keep the latest version of transactions and effects - /// for - #[serde(skip_serializing_if = "Option::is_none")] - pub num_epochs_to_retain_for_checkpoints: Option, - /// disables object tombstone pruning. We don't serialize it if it is the - /// default value, false. - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub killswitch_tombstone_pruning: bool, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub smooth: bool, -} - -fn default_num_latest_epoch_dbs_to_retain() -> usize { - 3 -} - -fn default_epoch_db_pruning_period_secs() -> u64 { - 3600 -} - -fn default_max_transactions_in_batch() -> usize { - 1000 -} - -fn default_max_checkpoints_in_batch() -> usize { - 10 -} - -impl Default for AuthorityStorePruningConfig { - fn default() -> Self { - Self { - num_latest_epoch_dbs_to_retain: default_num_latest_epoch_dbs_to_retain(), - epoch_db_pruning_period_secs: default_epoch_db_pruning_period_secs(), - num_epochs_to_retain: 0, - pruning_run_delay_seconds: if cfg!(msim) { Some(2) } else { None }, - max_checkpoints_in_batch: default_max_checkpoints_in_batch(), - max_transactions_in_batch: default_max_transactions_in_batch(), - periodic_compaction_threshold_days: None, - num_epochs_to_retain_for_checkpoints: if cfg!(msim) { Some(2) } else { None }, - killswitch_tombstone_pruning: false, - smooth: false, - } - } -} - -impl AuthorityStorePruningConfig { - pub fn set_num_epochs_to_retain_for_checkpoints(&mut self, num_epochs_to_retain: Option) { - self.num_epochs_to_retain_for_checkpoints = num_epochs_to_retain; - } - - pub fn num_epochs_to_retain_for_checkpoints(&self) -> Option { - self.num_epochs_to_retain_for_checkpoints - // if n less than 2, coerce to 2 and log - .map(|n| { - if n < 2 { - info!("num_epochs_to_retain_for_checkpoints must be at least 2, rounding up from {}", n); - 2 - } else { - n - } - }) - } - - pub fn set_killswitch_tombstone_pruning(&mut self, killswitch_tombstone_pruning: bool) { - self.killswitch_tombstone_pruning = killswitch_tombstone_pruning; - } -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct MetricsConfig { - #[serde(skip_serializing_if = "Option::is_none")] - pub push_interval_seconds: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub push_url: Option, -} - -#[derive(Default, Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct DBCheckpointConfig { - #[serde(default)] - pub perform_db_checkpoints_at_epoch_end: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub checkpoint_path: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub object_store_config: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub perform_index_db_checkpoints_at_epoch_end: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub prune_and_compact_before_upload: Option, -} - -#[derive(Debug, Clone)] -pub struct ArchiveReaderConfig { - pub remote_store_config: ObjectStoreConfig, - pub download_concurrency: NonZeroUsize, - pub use_for_pruning_watermark: bool, -} - -#[derive(Default, Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct StateArchiveConfig { - #[serde(skip_serializing_if = "Option::is_none")] - pub object_store_config: Option, - pub concurrency: usize, - pub use_for_pruning_watermark: bool, -} - -#[derive(Default, Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct StateSnapshotConfig { - #[serde(skip_serializing_if = "Option::is_none")] - pub object_store_config: Option, - pub concurrency: usize, -} - -#[derive(Default, Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct TransactionKeyValueStoreWriteConfig { - pub aws_access_key_id: String, - pub aws_secret_access_key: String, - pub aws_region: String, - pub table_name: String, - pub bucket_name: String, - pub concurrency: usize, -} - -/// Configuration for the threshold(s) at which we consider the system -/// to be overloaded. When one of the threshold is passed, the node may -/// stop processing new transactions and/or certificates until the congestion -/// resolves. -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct AuthorityOverloadConfig { - #[serde(default = "default_max_txn_age_in_queue")] - pub max_txn_age_in_queue: Duration, - - // The interval of checking overload signal. - #[serde(default = "default_overload_monitor_interval")] - pub overload_monitor_interval: Duration, - - // The execution queueing latency when entering load shedding mode. - #[serde(default = "default_execution_queue_latency_soft_limit")] - pub execution_queue_latency_soft_limit: Duration, - - // The execution queueing latency when entering aggressive load shedding mode. - #[serde(default = "default_execution_queue_latency_hard_limit")] - pub execution_queue_latency_hard_limit: Duration, - - // The maximum percentage of transactions to shed in load shedding mode. - #[serde(default = "default_max_load_shedding_percentage")] - pub max_load_shedding_percentage: u32, - - // When in aggressive load shedding mode, the minimum percentage of - // transactions to shed. - #[serde(default = "default_min_load_shedding_percentage_above_hard_limit")] - pub min_load_shedding_percentage_above_hard_limit: u32, - - // If transaction ready rate is below this rate, we consider the validator - // is well under used, and will not enter load shedding mode. - #[serde(default = "default_safe_transaction_ready_rate")] - pub safe_transaction_ready_rate: u32, - - // When set to true, transaction signing may be rejected when the validator - // is overloaded. - #[serde(default = "default_check_system_overload_at_signing")] - pub check_system_overload_at_signing: bool, - - // When set to true, transaction execution may be rejected when the validator - // is overloaded. - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub check_system_overload_at_execution: bool, - // TODO: Move other thresholds here as well, including `MAX_TM_QUEUE_LENGTH` - // and `MAX_PER_OBJECT_QUEUE_LENGTH`. -} - -fn default_max_txn_age_in_queue() -> Duration { - Duration::from_secs(1) -} - -fn default_overload_monitor_interval() -> Duration { - Duration::from_secs(10) -} - -fn default_execution_queue_latency_soft_limit() -> Duration { - Duration::from_secs(1) -} - -fn default_execution_queue_latency_hard_limit() -> Duration { - Duration::from_secs(10) -} - -fn default_max_load_shedding_percentage() -> u32 { - 95 -} - -fn default_min_load_shedding_percentage_above_hard_limit() -> u32 { - 50 -} - -fn default_safe_transaction_ready_rate() -> u32 { - 100 -} - -fn default_check_system_overload_at_signing() -> bool { - true -} - -impl Default for AuthorityOverloadConfig { - fn default() -> Self { - Self { - max_txn_age_in_queue: default_max_txn_age_in_queue(), - overload_monitor_interval: default_overload_monitor_interval(), - execution_queue_latency_soft_limit: default_execution_queue_latency_soft_limit(), - execution_queue_latency_hard_limit: default_execution_queue_latency_hard_limit(), - max_load_shedding_percentage: default_max_load_shedding_percentage(), - min_load_shedding_percentage_above_hard_limit: - default_min_load_shedding_percentage_above_hard_limit(), - safe_transaction_ready_rate: default_safe_transaction_ready_rate(), - check_system_overload_at_signing: true, - check_system_overload_at_execution: false, - } - } -} - -fn default_authority_overload_config() -> AuthorityOverloadConfig { - AuthorityOverloadConfig::default() -} - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)] -pub struct Genesis { - #[serde(flatten)] - location: GenesisLocation, - - #[serde(skip)] - genesis: once_cell::sync::OnceCell, -} - -impl Genesis { - pub fn new(genesis: genesis::Genesis) -> Self { - Self { - location: GenesisLocation::InPlace { genesis }, - genesis: Default::default(), - } - } - - pub fn new_from_file>(path: P) -> Self { - Self { - location: GenesisLocation::File { - genesis_file_location: path.into(), - }, - genesis: Default::default(), - } - } - - pub fn genesis(&self) -> Result<&genesis::Genesis> { - match &self.location { - GenesisLocation::InPlace { genesis } => Ok(genesis), - GenesisLocation::File { - genesis_file_location, - } => self - .genesis - .get_or_try_init(|| genesis::Genesis::load(genesis_file_location)), - } - } -} - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)] -#[serde(untagged)] -enum GenesisLocation { - InPlace { - genesis: genesis::Genesis, - }, - File { - #[serde(rename = "genesis-file-location")] - genesis_file_location: PathBuf, - }, -} - -/// Wrapper struct for SuiKeyPair that can be deserialized from a file path. -/// Used by network, worker, and account keypair. -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct KeyPairWithPath { - #[serde(flatten)] - location: KeyPairLocation, - - #[serde(skip)] - keypair: OnceCell>, -} - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)] -#[serde_as] -#[serde(untagged)] -enum KeyPairLocation { - InPlace { - #[serde_as(as = "Arc")] - value: Arc, - }, - File { - #[serde(rename = "path")] - path: PathBuf, - }, -} - -impl KeyPairWithPath { - pub fn new(kp: SuiKeyPair) -> Self { - let cell: OnceCell> = OnceCell::new(); - let arc_kp = Arc::new(kp); - // OK to unwrap panic because authority should not start without all keypairs - // loaded. - cell.set(arc_kp.clone()).expect("Failed to set keypair"); - Self { - location: KeyPairLocation::InPlace { value: arc_kp }, - keypair: cell, - } - } - - pub fn new_from_path(path: PathBuf) -> Self { - let cell: OnceCell> = OnceCell::new(); - // OK to unwrap panic because authority should not start without all keypairs - // loaded. - cell.set(Arc::new(read_keypair_from_file(&path).unwrap_or_else( - |e| panic!("Invalid keypair file at path {:?}: {e}", &path), - ))) - .expect("Failed to set keypair"); - Self { - location: KeyPairLocation::File { path }, - keypair: cell, - } - } - - pub fn keypair(&self) -> &SuiKeyPair { - self.keypair - .get_or_init(|| match &self.location { - KeyPairLocation::InPlace { value } => value.clone(), - KeyPairLocation::File { path } => { - // OK to unwrap panic because authority should not start without all keypairs - // loaded. - Arc::new( - read_keypair_from_file(path).unwrap_or_else(|e| { - panic!("Invalid keypair file at path {:?}: {e}", path) - }), - ) - } - }) - .as_ref() - } -} - -/// Wrapper struct for AuthorityKeyPair that can be deserialized from a file -/// path. -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct AuthorityKeyPairWithPath { - #[serde(flatten)] - location: AuthorityKeyPairLocation, - - #[serde(skip)] - keypair: OnceCell>, -} - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)] -#[serde_as] -#[serde(untagged)] -enum AuthorityKeyPairLocation { - InPlace { value: Arc }, - File { path: PathBuf }, -} - -impl AuthorityKeyPairWithPath { - pub fn new(kp: AuthorityKeyPair) -> Self { - let cell: OnceCell> = OnceCell::new(); - let arc_kp = Arc::new(kp); - // OK to unwrap panic because authority should not start without all keypairs - // loaded. - cell.set(arc_kp.clone()) - .expect("Failed to set authority keypair"); - Self { - location: AuthorityKeyPairLocation::InPlace { value: arc_kp }, - keypair: cell, - } - } - - pub fn new_from_path(path: PathBuf) -> Self { - let cell: OnceCell> = OnceCell::new(); - // OK to unwrap panic because authority should not start without all keypairs - // loaded. - cell.set(Arc::new( - read_authority_keypair_from_file(&path) - .unwrap_or_else(|_| panic!("Invalid authority keypair file at path {:?}", &path)), - )) - .expect("Failed to set authority keypair"); - Self { - location: AuthorityKeyPairLocation::File { path }, - keypair: cell, - } - } - - pub fn authority_keypair(&self) -> &AuthorityKeyPair { - self.keypair - .get_or_init(|| match &self.location { - AuthorityKeyPairLocation::InPlace { value } => value.clone(), - AuthorityKeyPairLocation::File { path } => { - // OK to unwrap panic because authority should not start without all keypairs - // loaded. - Arc::new( - read_authority_keypair_from_file(path).unwrap_or_else(|_| { - panic!("Invalid authority keypair file {:?}", &path) - }), - ) - } - }) - .as_ref() - } -} - -/// Configurations which determine how we dump state debug info. -/// Debug info is dumped when a node forks. -#[derive(Clone, Debug, Deserialize, Serialize, Default)] -#[serde(rename_all = "kebab-case")] -pub struct StateDebugDumpConfig { - #[serde(skip_serializing_if = "Option::is_none")] - pub dump_file_directory: Option, -} - -#[cfg(test)] -mod tests { - use std::path::PathBuf; - - use fastcrypto::traits::KeyPair; - use rand::{rngs::StdRng, SeedableRng}; - use sui_keys::keypair_file::{write_authority_keypair_to_file, write_keypair_to_file}; - use sui_types::crypto::{get_key_pair_from_rng, AuthorityKeyPair, NetworkKeyPair, SuiKeyPair}; - - use super::Genesis; - use crate::NodeConfig; - - #[test] - fn serialize_genesis_from_file() { - let g = Genesis::new_from_file("path/to/file"); - - let s = serde_yaml::to_string(&g).unwrap(); - assert_eq!("---\ngenesis-file-location: path/to/file\n", s); - let loaded_genesis: Genesis = serde_yaml::from_str(&s).unwrap(); - assert_eq!(g, loaded_genesis); - } - - #[test] - fn fullnode_template() { - const TEMPLATE: &str = include_str!("../data/fullnode-template.yaml"); - - let _template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap(); - } - - #[test] - fn load_key_pairs_to_node_config() { - let protocol_key_pair: AuthorityKeyPair = - get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1; - let worker_key_pair: NetworkKeyPair = - get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1; - let network_key_pair: NetworkKeyPair = - get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1; - - write_authority_keypair_to_file(&protocol_key_pair, PathBuf::from("protocol.key")).unwrap(); - write_keypair_to_file( - &SuiKeyPair::Ed25519(worker_key_pair.copy()), - PathBuf::from("worker.key"), - ) - .unwrap(); - write_keypair_to_file( - &SuiKeyPair::Ed25519(network_key_pair.copy()), - PathBuf::from("network.key"), - ) - .unwrap(); - - const TEMPLATE: &str = include_str!("../data/fullnode-template-with-path.yaml"); - let template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap(); - assert_eq!( - template.protocol_key_pair().public(), - protocol_key_pair.public() - ); - assert_eq!( - template.network_key_pair().public(), - network_key_pair.public() - ); - assert_eq!( - template.worker_key_pair().public(), - worker_key_pair.public() - ); - } -} - -// RunWithRange is used to specify the ending epoch/checkpoint to process. -// this is intended for use with disaster recovery debugging and verification -// workflows, never in normal operations -#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)] -pub enum RunWithRange { - Epoch(EpochId), - Checkpoint(CheckpointSequenceNumber), -} - -impl RunWithRange { - // is epoch_id > RunWithRange::Epoch - pub fn is_epoch_gt(&self, epoch_id: EpochId) -> bool { - matches!(self, RunWithRange::Epoch(e) if epoch_id > *e) - } - - pub fn matches_checkpoint(&self, seq_num: CheckpointSequenceNumber) -> bool { - matches!(self, RunWithRange::Checkpoint(seq) if *seq == seq_num) - } -} diff --git a/crates/sui-config/src/test_gateway.yml b/crates/sui-config/src/test_gateway.yml deleted file mode 100644 index 1e725f288ae..00000000000 --- a/crates/sui-config/src/test_gateway.yml +++ /dev/null @@ -1,251 +0,0 @@ - --- - epoch: 0 - validator_set: - - name: validator-9 - account-key: AD0iV/PbGVBoPExdB+4wfprZLoS9N4ltb00p1MNnlm71 - protocol-key: getJQ17IvK3nYcHAOLZ1PDeQt5dNcxGGkCooW9AYo0fUNEu1C3Uo264SZBiEqhqUD3QcR018SpZkYYEntPS/B/I8QGRJFBa55O1GSGGNscJ3rOOArqGKM4cOBaJUF2nH - worker-key: RXzQ+WNIIcodae0f1AaRVg3qvzbySW4EYBUVf68VdzA= - network-key: OD73hNLl2wBqBrmcxG00r77V7Kgdi2fu4YpnoEJDyPs= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/ny2-suival-1.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/ny2-suival-1.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/ny2-suival-1.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-14 - account-key: APxJHKslYpWYWmMIlpKfzBTj9K5I84diueoJ4sWHwjmS - protocol-key: hUY69ZxcvuOaoY9AoazvEAsum2bS/61LZU7d88h/baYO5rBXFod3UeYC+wr0J51qF6JUpOaNk/E2OIFSbI1GoLUxu0AxIfe23ph+BLD3CbttFMbpqZa7Zza6DOHpjyok - worker-key: IrjezuU/lXLkyXkAUvWbKBGPLH5GCrJqCRYKTVc9nao= - network-key: pu7Q7oXG6GiRfoEcR7azVoWUVQC10gY7MLi3xVoYa0g= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/mh1-suival-2.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/mh1-suival-2.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/mh1-suival-2.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-13 - account-key: AF7odQ5Mwj8PBN/7LYTqyB/gS1OywSBOcKuCS/+VNyLd - protocol-key: iBNb7x9vyRov6hR/y0671JJ3gYTGWjDtSO8BLZ0FjZQkkQ3peXhjQZnVUe7VO8CnGN630twyg6zfBwS8CL51rV0UbsEJ0ZOn/4uwR/rq8PwMdod+Wf84AkGhbrZ0AUh4 - worker-key: H2uJQcpeBVF/cn5VBR3re7HZugsooxv2TeGfoctO6GE= - network-key: tgVQjD8k8ymbIdWYhi8VxjMw9FInsfh8xLd+4xhOIOE= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/mh1-suival-1.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/mh1-suival-1.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/mh1-suival-1.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-17 - account-key: AO6lcah9+F9DfVBwE5+30kmi8pkw7nHPeolO0LNIJUQi - protocol-key: iJOovXaLrS4FvmlpMnkCk0oEY79HrBPLxY+21WhK2sKsaTsAgjL4KnyXVbrb7nTOAm0z6CkdzT+hMmMw1E7csmK8dV8VjKpgaR66oMxcGDM2Rbu0XhqIx7uH3DpwYezp - worker-key: jdsdCfcvGNs5XxGk+jwNbOF6caMnaWvCGKOp0b4QslI= - network-key: qqL4hLWUa7bitFYj0k1uosnmKEEslk/o8shtOOJriWY= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/ty6-suival-1.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/ty6-suival-1.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/ty6-suival-1.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-10 - account-key: AEM7kl/d6VlBG1IgY+lHdxzudYT6ZhtXiYBh3kCxLZCq - protocol-key: iic7mlIKCwVxaqej7btkXo045aJYw6hgqpHZT+n25aqICuYCkc0PUXzZ2qSGTrUgDkhcyLKUpMPXjNCPw7AV3M+B+dPuKf6BVVo4Enj4KJe5SnoNOYRE7Ll01K9KfbWU - worker-key: +Ukw2HM7IYXyIxp9F2ZbBZMAQpIMN24fhzArm41CJy0= - network-key: IXFQDgUFO6XD+eqnCHf4aAR2HVdqKKM/7l13nlFIk+w= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/ny2-suival-2.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/ny2-suival-2.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/ny2-suival-2.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-7 - account-key: ALO4VmUJME24oEDq0tzE7MRi+83HZE3UCuLTVPIE4ZQK - protocol-key: krpOBB6E7P0N4jsUHBGFPSHX0UPoS6uFR1I/kKND+em8+cgrujsm31oygHdrKhUeDjq4UWUtCyxLoCczGLO/F1VUooI/J3iqzjN1RvkG7CiFriuU0L9GF7/l64U01DwN - worker-key: knT4d0Du6/s0qQWtIeAHI25gRjTXHQe4g0SK56LGtLw= - network-key: ZtPhPziNESJSElsa2y7GZWkc97kKPMrJTq1UldpxUoU= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/dal2-suival-3.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/dal2-suival-3.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/dal2-suival-3.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-8 - account-key: AJN7LZADOBBRulSlRjE0HJs3YR8I3WPwg2ejh4HbDmIS - protocol-key: ky1saTSmEpWC/F4MKypOBzJaNaqxHk7gTWkhDnJP0NMZG0vniS+3YIGtg/MsHPQXAVJkmj/rq9AgGNN/xxmUXd7iB/6xnldUSRfHDberjd9lr6zlG+oEtj9nmpLNA/Wd - worker-key: feBqPOJotxyv+jWKWvYGWw6/ISzP2dms9jhiy4Nbj4Q= - network-key: yfVmqGTyP3tutFvvrvklhafUJUCTmik+6u6zBRV3Vb4= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/ny2-suival-0.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/ny2-suival-0.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/ny2-suival-0.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-4 - account-key: ACfae1xB9WlL4aSAEbIeTzHSK70s6pUFK4MWerGsas0i - protocol-key: lwDow31chV6Qb3bqcHN5EjFVRf6MVttV94z4d4y5srrEz/Ljax/6RV3rHR65OfU1ExK8K5bX1gZ6q8pZgVUTPjWrRt3G8P1aD8hw0gXFFYeE3Wx2+Y4P4r8H4LMcqriZ - worker-key: XpdNknObin/NdNWpBISwDdJxhSlyBVZ85Vn9AnVzxtY= - network-key: 7b8+yXq6rdRw7eToBWfCnYoDBPxDvTVeW6xyiK5u4HM= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/dal2-suival-0.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/dal2-suival-0.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/dal2-suival-0.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-18 - account-key: AE6+TGtd9SgOFPJh7sswMd8YDf7G080NeGYwzuIS3/zM - protocol-key: l/fjESkdgYtdwiEnTNEEltgjImpW5k5CIwnq3YHSAlXW2wATYAf+U0CwYHIbFelxC4XpuDZJTMUDp/B1q7lbMms/EuUmHvP59uz3ysNMERt0w+kDDIcdN45yPhJJOTwq - worker-key: Qn3hFtZnGKB5NKeLsjAzb0+N6Nar2UpLeiUYcOBAaAs= - network-key: y3wT8cSNLo+flMsvseffK5fJC72J12ZrT6Tjy6wzQkM= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/ty6-suival-2.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/ty6-suival-2.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/ty6-suival-2.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-2 - account-key: AGhrMVMiJ67VCxth8gWXNFOLnFuNkIMjV0GK3EFBfaio - protocol-key: pGmknQNryWXOmxfNJ1L2IpVplX0kcjMpeHAcuRbxv6rlJt1N+96RWegxtf38mLWQFt2b+S8diM25yMFn4ox2YzAHShhhISz8ZzB38WPScV3xXGG0F5KyPXk0sLM1/vjx - worker-key: qolNIcgY6rYX64P5O4oF9ugXl3hPi6yUyZlV1SPjt+M= - network-key: Qn8Zhwld5x22fE1GwIg6Hain9iVRi+iam1RDgp8mvhk= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/la2-suival-2.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/la2-suival-2.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/la2-suival-2.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-11 - account-key: AK6LecW3y0UyqzCHu3lUgffRyhGrxEQPjaHRxCilP6Rp - protocol-key: pVydcYoBSOHxVnw2mOg8YXJyqpDYP+ksefqghJwr3OChJNTa3A2NkDaCRKGcvRm6DPiaqBu8qBUSAfjWE4KHfQIllc7qkWYsRfKi0RYQ3zTFYSjal93Am/cAI1q6QX59 - worker-key: PqUDf04k2xNSqR0u2pmaU7L23hIt8gO6B3NoYPsR+RA= - network-key: x/0p4eV6ZQOyRGv9K9hiiaN7TvSfk2AvCttMAVpOoMk= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/ny2-suival-3.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/ny2-suival-3.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/ny2-suival-3.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-16 - account-key: AImuNvQVTUSNUQrsBSi7dzT+a+wVsSQM5fQMfdQ1CTZ0 - protocol-key: qBvUTaWiYjKIledSoTM8rwt4C7dqCVFuUPyQBNDOOSa109JlgUafHGEIeOHrrUlCEnAwTiXs+s2JlwmyegQzJp2ECnbz4JRPzFqbBhS7VDJ7UfydXbq4KDt12q8yb5v4 - worker-key: XFw5/sTtKHd47+vpj7uvt+FkAyOq1FnvGS/7be6suoA= - network-key: EEqhzNCQ6/nPfCW7jLMKQS2TGb2dY2CHAme8mlEZGKY= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/ty6-suival-0.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/ty6-suival-0.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/ty6-suival-0.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-15 - account-key: AFDDthZ/GakRrsI2QZJ8gQFEt+fJvKwpJJoYm+p/NW07 - protocol-key: q5U/HPqV6OsFbc5gzr+FPRfBGqyHqO683epGiQ535TOEYRkSi3wZFFUdDfWId7ORD5EIYWj7ZtA4C8uPrP3XsbIQogNizEyDu3CwytSwtcTa4/bIvc8HK/0KoDnPNOG2 - worker-key: ydUPJzWYwe3RdAUo5zMZvyAattOKn+wfxwdrQTRpxqA= - network-key: rU4e5yh97eNS5nCaa7EbbqnJVMcHehybdtBlIZjSHdU= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/mh1-suival-3.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/mh1-suival-3.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/mh1-suival-3.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-5 - account-key: ALaZN89Ud2dli3QScggR+9+2CqSkct2f7qMXQ1osFaBd - protocol-key: rA3xsZLdYP8f1Jhdy/qaAZJTZ1XGza6P167xhffC9qd/ThVdV0K/Pg0t9g5TpYHoEygnvMO8oPyJA2+zwbutgCTRaM1z573NN3mtbjK57R+S7aqwZiN2kI7aoymX9oHs - worker-key: EgpJ/Hdk6X+H8jXxurlwR1EiIlDkryVCQ4HMrk72INQ= - network-key: twXGi96O3XWKERXGzu1Y03Rl6uUr+1Tqx9kGuGV+Gew= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/dal2-suival-1.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/dal2-suival-1.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/dal2-suival-1.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-19 - account-key: AFhY6i8XnpRoImndz7kj+M6mjIpZz1248oyO5Ou/ajG8 - protocol-key: rewCDjFrQpvCurd4M6cl1/icgJsGKombV1OAd0iyskXN4WqXZiP/V7xy7fNZfciwD2k0nl8uQCaLEPXsO/zBL0ZGr2n274JYVm8j4gOekJcUpdAQ3LWPqDh3pRsxBVE+ - worker-key: 7J91jtn+//gCHUPIi8Std5hhSFLs9snJhPbnHPueudc= - network-key: 3PKKDx6y6CzV0+eK9G3WvH/queuZe3byCYIOTYIkyiQ= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/ty6-suival-3.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/ty6-suival-3.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/ty6-suival-3.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-12 - account-key: AAYmiOgJnOyXfMPEwP49TUUUTw4dlIA/8IXeKEv8M4RK - protocol-key: sfQG62p+A88facvLw+lXcDh6TtSaeaRa3D8dhMJpLWgJZ4NRl2JFSaUlYHWwP+zVGSdbyLGm72426wv5cKnVkHM8cxhNvpZRq370bYHTfTAb34WJ2mxHiqx5pChHJp4E - worker-key: UEtOxAHp/invOWPV8Uuls3/46iLdKFJIGEb2zhJIsNs= - network-key: ibWn5j/N9BqepJXTWioH47A2u//ASB3Xug50e7jmJ80= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/mh1-suival-0.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/mh1-suival-0.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/mh1-suival-0.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-3 - account-key: AIyUji/hvun9TdRLQXpN8UNgn3sIjSosETJWkPSwDzHr - protocol-key: tH2JgU9S5IFnC17arEV0dn2sRlZmgaHpOAVQvIJfvXAnZTOLDwHzepPbFpp3i9g+DzUyeKWSh06N7jILNze8jdhLeZ1fumbu07GgmpL2vdYR3Qbxg64DpsKLPMeNi3V1 - worker-key: NM/63ks+HTfHnPSRKU7Yh9I0c5qTm1ajr4akXpBR5V0= - network-key: 5VuCiFi9kAK7QlsZBuymT9xsIG/sPoFcmjHoGn/CPgs= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/la2-suival-3.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/la2-suival-3.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/la2-suival-3.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-1 - account-key: AG+M0+OIB31YRR/FQKdzt7aP4qUPBQSMyCWK+Da9Zmax - protocol-key: tlb8KVZRWWJZQ6TmpE+5ZL05Vb0TTnCMbJ+kWX5GtcnpaeRiFqlUKiYM5npZCCWyFx8f1VwW5gfg8OejVRlo+weJr50yphZdA53GkbJiOWxSY58DSNTQINB/lEdOAeJQ - worker-key: xplIPV8w5ahH8UaWChJcPrkSVZAGtKwMXCWdT8lSaPU= - network-key: pZdlHJfW9hxT415bG8kusy7m4TDfW0gkNMsx3MVs73o= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/la2-suival-1.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/la2-suival-1.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/la2-suival-1.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-6 - account-key: AGq4caYZr20U1EM7WkRo6CYVuKfjWmda1b5AGdgaSN2s - protocol-key: t/ueFnCtZPsfXozjLmRwefOht+pyelCaTgctHqOomF5gd0MuXdDSvOCAH3yWiaIVBskY54766sEG0antAeAtJHRwKXHGo99RR5nRRxUbekTvq7T05TTpQxW1pi4Cr/5O - worker-key: MM7hhssxwhocxsg8ZrEYXjMggQsrWaiQzCZpkwv7ya8= - network-key: q1+yp6neJ0VYGcRFDDfarMM6XN+CwiNVmqfc7IElUNY= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/dal2-suival-2.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/dal2-suival-2.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/dal2-suival-2.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - - name: validator-0 - account-key: APlYeKnmB0RcPB5cYaII7aAvjjAt19cVt3d9eJBCQwjX - protocol-key: uQWpdXdUDiw5/MSyB56qIUZoCOApbKzuXE9MkgjekQsn6PPSLEIydbr16TVKm8ifADeZUnFeIQ39VwT3LBveXXS8ncRoBddREyR/S19AXGWigynhjLi5hNGCfFO+FWHS - worker-key: 6zvKuVVIhIgczd4Gf3AhWzdJyINtK8yxoVLxlUw3kSU= - network-key: 2tgtZR/dK2E9rEfdenqmLKxjqjH0jJV7CcT4ywRA6uw= - stake: 1 - delegation: 0 - gas-price: 1 - network-address: /dns/la2-suival-0.testnet.sui.io/tcp/8080/http - narwhal-primary-address: /dns/la2-suival-0.testnet.sui.io/udp/8081 - narwhal-worker-address: /dns/la2-suival-0.testnet.sui.io/udp/8082 - narwhal-consensus-address: /ip4/127.0.0.1/tcp/8083/http - send_timeout: - secs: 30 - nanos: 0 - recv_timeout: - secs: 30 - nanos: 0 - buffer_size: 650000 - db_folder_path: /data/gateway_client_db diff --git a/crates/sui-core/Cargo.toml b/crates/sui-core/Cargo.toml deleted file mode 100644 index 6b4afd3644f..00000000000 --- a/crates/sui-core/Cargo.toml +++ /dev/null @@ -1,142 +0,0 @@ -[package] -name = "sui-core" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow = { workspace = true, features = ["backtrace"] } -arc-swap.workspace = true -async-trait.workspace = true -bcs.workspace = true -bytes.workspace = true -chrono.workspace = true -consensus-core.workspace = true -consensus-config.workspace = true -dashmap.workspace = true -diffy = { version = "0.3", default-features = false } -either.workspace = true -enum_dispatch.workspace = true -eyre.workspace = true -futures.workspace = true -im.workspace = true -indexmap.workspace = true -itertools.workspace = true -lru.workspace = true -mockall.workspace = true -num_cpus.workspace = true -object_store.workspace = true -once_cell.workspace = true -parking_lot.workspace = true -prometheus.workspace = true -rand.workspace = true -roaring.workspace = true -rocksdb.workspace = true -scopeguard.workspace = true -serde.workspace = true -serde_json.workspace = true -serde_with.workspace = true -signature.workspace = true -static_assertions.workspace = true -tap.workspace = true -tempfile.workspace = true -thiserror.workspace = true -tokio = { workspace = true, features = ["full", "tracing", "test-util"] } -tokio-retry.workspace = true -tokio-stream.workspace = true -tracing.workspace = true -twox-hash.workspace = true - -anemo.workspace = true -fastcrypto.workspace = true -fastcrypto-tbls.workspace = true -fastcrypto-zkp.workspace = true -move-binary-format.workspace = true -move-bytecode-utils.workspace = true -move-core-types.workspace = true -move-package.workspace = true -move-symbol-pool.workspace = true -mysten-common.workspace = true -mysten-network.workspace = true -telemetry-subscribers.workspace = true -typed-store-derive.workspace = true -typed-store.workspace = true - -mysten-metrics.workspace = true -narwhal-config.workspace = true -narwhal-crypto.workspace = true -narwhal-executor.workspace = true -narwhal-network.workspace = true -narwhal-node.workspace = true -narwhal-test-utils.workspace = true -narwhal-types.workspace = true -narwhal-worker.workspace = true -shared-crypto.workspace = true -sui-archival.workspace = true -sui-config.workspace = true -sui-authority-aggregation.workspace = true -sui-execution = { path = "../../sui-execution" } -sui-framework.workspace = true -sui-swarm-config.workspace = true -sui-genesis-builder.workspace = true -sui-json-rpc-types.workspace = true -sui-macros.workspace = true -sui-move-build.workspace = true -sui-network.workspace = true -sui-protocol-config.workspace = true -sui-transaction-checks.workspace = true -sui-simulator.workspace = true -sui-storage.workspace = true -sui-types.workspace = true -zeroize.workspace = true - -[dev-dependencies] -clap.workspace = true -criterion.workspace = true -expect-test.workspace = true -fs_extra.workspace = true -more-asserts.workspace = true -pretty_assertions.workspace = true -serde-reflection.workspace = true -serde_yaml.workspace = true -num-bigint = "0.4.4" - -test-cluster.workspace = true -move-symbol-pool.workspace = true - -sui-test-transaction-builder.workspace = true -sui-types = { workspace = true, features = ["test-utils"] } - -[target.'cfg(not(target_env = "msvc"))'.dev-dependencies] -pprof.workspace = true -test-fuzz.workspace = true - -sui-macros.workspace = true -sui-protocol-config.workspace = true - -# moka uses `quanta` by default for timing, which is not compatible with the simulator -[target.'cfg(msim)'.dependencies] -moka = { workspace = true, default-features = false, features = [ - "sync", - "atomic64", -] } -[target.'cfg(not(msim))'.dependencies] -moka = { workspace = true, features = ["sync"] } - -[[example]] -name = "generate-format" -path = "src/generate_format.rs" -test = false - -[[bench]] -name = "verified_cert_cache_bench" -harness = false - -[[bench]] -name = "batch_verification_bench" -harness = false - -[features] -test-utils = [] diff --git a/crates/sui-core/src/checkpoints/checkpoint_executor/metrics.rs b/crates/sui-core/src/checkpoints/checkpoint_executor/metrics.rs deleted file mode 100644 index f03330e3738..00000000000 --- a/crates/sui-core/src/checkpoints/checkpoint_executor/metrics.rs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::sync::Arc; - -use mysten_metrics::histogram::Histogram; -use prometheus::{ - register_int_counter_with_registry, register_int_gauge_with_registry, IntCounter, IntGauge, - Registry, -}; - -pub struct CheckpointExecutorMetrics { - pub checkpoint_exec_sync_tps: IntGauge, - pub last_executed_checkpoint: IntGauge, - pub last_executed_checkpoint_timestamp_ms: IntGauge, - pub checkpoint_exec_errors: IntCounter, - pub checkpoint_exec_epoch: IntGauge, - pub checkpoint_exec_inflight: IntGauge, - pub checkpoint_exec_latency_us: Histogram, - pub checkpoint_prepare_latency_us: Histogram, - pub checkpoint_transaction_count: Histogram, - pub checkpoint_contents_age_ms: Histogram, - pub last_executed_checkpoint_age_ms: Histogram, - pub accumulator_inconsistent_state: IntGauge, -} - -impl CheckpointExecutorMetrics { - pub fn new(registry: &Registry) -> Arc { - let this = Self { - checkpoint_exec_sync_tps: register_int_gauge_with_registry!( - "checkpoint_exec_sync_tps", - "Checkpoint sync estimated transactions per second", - registry - ) - .unwrap(), - last_executed_checkpoint: register_int_gauge_with_registry!( - "last_executed_checkpoint", - "Last executed checkpoint", - registry - ) - .unwrap(), - last_executed_checkpoint_timestamp_ms: register_int_gauge_with_registry!( - "last_executed_checkpoint_timestamp_ms", - "Last executed checkpoint timestamp ms", - registry - ) - .unwrap(), - checkpoint_exec_errors: register_int_counter_with_registry!( - "checkpoint_exec_errors", - "Checkpoint execution errors count", - registry - ) - .unwrap(), - checkpoint_exec_epoch: register_int_gauge_with_registry!( - "checkpoint_exec_epoch", - "Current epoch number in the checkpoint executor", - registry - ) - .unwrap(), - checkpoint_exec_inflight: register_int_gauge_with_registry!( - "checkpoint_exec_inflight", - "Current number of inflight checkpoints being executed", - registry - ) - .unwrap(), - checkpoint_exec_latency_us: Histogram::new_in_registry( - "checkpoint_exec_latency_us", - "Latency of executing a checkpoint from enqueue to all effects available, in microseconds", - registry, - ), - checkpoint_prepare_latency_us: Histogram::new_in_registry( - "checkpoint_prepare_latency_us", - "Latency of preparing a checkpoint to enqueue for execution, in microseconds", - registry, - ), - checkpoint_transaction_count: Histogram::new_in_registry( - "checkpoint_transaction_count", - "Number of transactions in the checkpoint", - registry, - ), - checkpoint_contents_age_ms: Histogram::new_in_registry( - "checkpoint_contents_age_ms", - "Age of checkpoints when they arrive for execution", - registry, - ), - last_executed_checkpoint_age_ms: Histogram::new_in_registry( - "last_executed_checkpoint_age_ms", - "Age of the last executed checkpoint", - registry - ), - accumulator_inconsistent_state: register_int_gauge_with_registry!( - "accumulator_inconsistent_state", - "1 if accumulated live object set differs from StateAccumulator root state hash for the previous epoch", - registry, - ) - .unwrap(), - }; - Arc::new(this) - } - - pub fn new_for_tests() -> Arc { - Self::new(&Registry::new()) - } -} diff --git a/crates/sui-core/src/checkpoints/checkpoint_executor/mod.rs b/crates/sui-core/src/checkpoints/checkpoint_executor/mod.rs deleted file mode 100644 index 1eb8f0a2407..00000000000 --- a/crates/sui-core/src/checkpoints/checkpoint_executor/mod.rs +++ /dev/null @@ -1,1221 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//! CheckpointExecutor is a Node component that executes all checkpoints for the -//! given epoch. It acts as a Consumer to StateSync -//! for newly synced checkpoints, taking these checkpoints and -//! scheduling and monitoring their execution. Its primary goal is to allow -//! for catching up to the current checkpoint sequence number of the network -//! as quickly as possible so that a newly joined, or recovering Node can -//! participate in a timely manner. To that end, CheckpointExecutor attempts -//! to saturate the CPU with executor tasks (one per checkpoint), each of which -//! handle scheduling and awaiting checkpoint transaction execution. -//! -//! CheckpointExecutor is made recoverable in the event of Node shutdown by way -//! of a watermark, highest_executed_checkpoint, which is guaranteed to be -//! updated sequentially in order, despite checkpoints themselves potentially -//! being executed nonsequentially and in parallel. CheckpointExecutor -//! parallelizes checkpoints of the same epoch as much as possible. -//! CheckpointExecutor enforces the invariant that if `run` returns -//! successfully, we have reached the end of epoch. This allows us to use it as -//! a signal for reconfig. - -use std::{ - collections::HashMap, - path::PathBuf, - sync::Arc, - time::{Duration, Instant}, -}; - -use futures::stream::FuturesOrdered; -use itertools::izip; -use mysten_metrics::{spawn_monitored_task, MonitoredFutureExt}; -use prometheus::Registry; -use sui_config::node::{CheckpointExecutorConfig, RunWithRange}; -use sui_macros::{fail_point, fail_point_async}; -use sui_types::{ - base_types::{ExecutionDigests, TransactionDigest, TransactionEffectsDigest}, - crypto::RandomnessRound, - effects::{TransactionEffects, TransactionEffectsAPI}, - error::SuiResult, - executable_transaction::VerifiedExecutableTransaction, - message_envelope::Message, - messages_checkpoint::{CheckpointSequenceNumber, VerifiedCheckpoint}, - transaction::{TransactionDataAPI, TransactionKind, VerifiedTransaction}, -}; -use tap::{TapFallible, TapOptional}; -use tokio::{ - sync::broadcast::{self, error::RecvError}, - task::JoinHandle, - time::timeout, -}; -use tokio_stream::StreamExt; -use tracing::{debug, error, info, instrument, trace, warn}; - -use self::metrics::CheckpointExecutorMetrics; -use crate::{ - authority::{authority_per_epoch_store::AuthorityPerEpochStore, AuthorityState}, - checkpoints::{ - checkpoint_executor::data_ingestion_handler::store_checkpoint_locally, CheckpointStore, - }, - execution_cache::ExecutionCacheRead, - state_accumulator::StateAccumulator, - transaction_manager::TransactionManager, -}; - -mod data_ingestion_handler; -mod metrics; -#[cfg(test)] -pub(crate) mod tests; - -type CheckpointExecutionBuffer = - FuturesOrdered)>>; - -/// The interval to log checkpoint progress, in # of checkpoints processed. -const CHECKPOINT_PROGRESS_LOG_COUNT_INTERVAL: u64 = 5000; - -const SCHEDULING_EVENT_FUTURE_TIMEOUT_MS: u64 = 2000; - -#[derive(PartialEq, Eq, Debug)] -pub enum StopReason { - EpochComplete, - RunWithRangeCondition, -} - -pub struct CheckpointExecutor { - mailbox: broadcast::Receiver, - // TODO: AuthorityState is only needed because we have to call - // deprecated_insert_finalized_transactions once that code is fully deprecated we can - // remove this - state: Arc, - checkpoint_store: Arc, - cache_reader: Arc, - tx_manager: Arc, - accumulator: Arc, - config: CheckpointExecutorConfig, - metrics: Arc, -} - -impl CheckpointExecutor { - pub fn new( - mailbox: broadcast::Receiver, - checkpoint_store: Arc, - state: Arc, - accumulator: Arc, - config: CheckpointExecutorConfig, - prometheus_registry: &Registry, - ) -> Self { - Self { - mailbox, - state: state.clone(), - checkpoint_store, - cache_reader: state.get_cache_reader().clone(), - tx_manager: state.transaction_manager().clone(), - accumulator, - config, - metrics: CheckpointExecutorMetrics::new(prometheus_registry), - } - } - - pub fn new_for_tests( - mailbox: broadcast::Receiver, - checkpoint_store: Arc, - state: Arc, - accumulator: Arc, - ) -> Self { - Self { - mailbox, - state: state.clone(), - checkpoint_store, - cache_reader: state.get_cache_reader().clone(), - tx_manager: state.transaction_manager().clone(), - accumulator, - config: Default::default(), - metrics: CheckpointExecutorMetrics::new_for_tests(), - } - } - - /// Ensure that all checkpoints in the current epoch will be executed. - /// We don't technically need &mut on self, but passing it to make sure only - /// one instance is running at one time. - pub async fn run_epoch( - &mut self, - epoch_store: Arc, - run_with_range: Option, - ) -> StopReason { - // check if we want to run this epoch based on RunWithRange condition value - // we want to be inclusive of the defined RunWithRangeEpoch::Epoch - // i.e Epoch(N) means we will execute epoch N and stop when reaching N+1 - if run_with_range.map_or(false, |rwr| rwr.is_epoch_gt(epoch_store.epoch())) { - info!( - "RunWithRange condition satisfied at {:?}, run_epoch={:?}", - run_with_range, - epoch_store.epoch() - ); - return StopReason::RunWithRangeCondition; - }; - - debug!( - "Checkpoint executor running for epoch {}", - epoch_store.epoch(), - ); - self.metrics - .checkpoint_exec_epoch - .set(epoch_store.epoch() as i64); - - // Decide the first checkpoint to schedule for execution. - // If we haven't executed anything in the past, we schedule checkpoint 0. - // Otherwise we schedule the one after highest executed. - let mut highest_executed = self - .checkpoint_store - .get_highest_executed_checkpoint() - .unwrap(); - - if let Some(highest_executed) = &highest_executed { - if epoch_store.epoch() == highest_executed.epoch() - && highest_executed.is_last_checkpoint_of_epoch() - { - // We can arrive at this point if we bump the highest_executed_checkpoint - // watermark, and then crash before completing reconfiguration. - info!(seq = ?highest_executed.sequence_number, "final checkpoint of epoch has already been executed"); - return StopReason::EpochComplete; - } - } - - let mut next_to_schedule = highest_executed - .as_ref() - .map(|c| c.sequence_number() + 1) - .unwrap_or_else(|| { - // TODO this invariant may no longer hold once we introduce snapshots - assert_eq!(epoch_store.epoch(), 0); - 0 - }); - let mut pending: CheckpointExecutionBuffer = FuturesOrdered::new(); - - let mut now_time = Instant::now(); - let mut now_transaction_num = highest_executed - .as_ref() - .map(|c| c.network_total_transactions) - .unwrap_or(0); - let scheduling_timeout = Duration::from_millis(SCHEDULING_EVENT_FUTURE_TIMEOUT_MS); - - loop { - // If we have executed the last checkpoint of the current epoch, stop. - // Note: when we arrive here with highest_executed == the final checkpoint of - // the epoch, we are in an edge case where highest_executed does not - // actually correspond to the watermark. The watermark is only - // bumped past the epoch final checkpoint after execution of the change - // epoch tx, and state accumulation. - if self - .check_epoch_last_checkpoint(epoch_store.clone(), &highest_executed) - .await - { - self.checkpoint_store - .prune_local_summaries() - .tap_err(|e| error!("Failed to prune local summaries: {}", e)) - .ok(); - - // be extra careful to ensure we don't have orphans - assert!( - pending.is_empty(), - "Pending checkpoint execution buffer should be empty after processing last checkpoint of epoch", - ); - fail_point_async!("crash"); - return StopReason::EpochComplete; - } - - self.schedule_synced_checkpoints( - &mut pending, - // next_to_schedule will be updated to the next checkpoint to schedule. - // This makes sure we don't re-schedule the same checkpoint multiple times. - &mut next_to_schedule, - epoch_store.clone(), - run_with_range, - ); - - self.metrics - .checkpoint_exec_inflight - .set(pending.len() as i64); - - tokio::select! { - // Check for completed workers and ratchet the highest_checkpoint_executed - // watermark accordingly. Note that given that checkpoints are guaranteed to - // be processed (added to FuturesOrdered) in seq_number order, using FuturesOrdered - // guarantees that we will also ratchet the watermarks in order. - Some(Ok((checkpoint, tx_digests))) = pending.next() => { - self.process_executed_checkpoint(&epoch_store, &checkpoint, &tx_digests).await; - highest_executed = Some(checkpoint.clone()); - - // Estimate TPS every 10k transactions or 30 sec - let elapsed = now_time.elapsed().as_millis(); - let current_transaction_num = highest_executed.as_ref().map(|c| c.network_total_transactions).unwrap_or(0); - if current_transaction_num - now_transaction_num > 10_000 || elapsed > 30_000{ - let tps = (1000.0 * (current_transaction_num - now_transaction_num) as f64 / elapsed as f64) as i32; - self.metrics.checkpoint_exec_sync_tps.set(tps as i64); - now_time = Instant::now(); - now_transaction_num = current_transaction_num; - } - // we want to be inclusive of checkpoints in RunWithRange::Checkpoint type - if run_with_range.map_or(false, |rwr| rwr.matches_checkpoint(checkpoint.sequence_number)) { - info!( - "RunWithRange condition satisfied after checkpoint sequence number {:?}", - checkpoint.sequence_number - ); - return StopReason::RunWithRangeCondition; - } - } - // Check for newly synced checkpoints from StateSync. - received = timeout(scheduling_timeout, self.mailbox.recv()) => match received { - Err(_elapsed) => { - warn!( - "Received no new synced checkpoints for {scheduling_timeout:?}. Next checkpoint to be scheduled: {next_to_schedule}", - ); - fail_point!("cp_exec_scheduling_timeout_reached"); - }, - Ok(Ok(checkpoint)) => { - debug!( - sequence_number = ?checkpoint.sequence_number, - "received checkpoint summary from state sync" - ); - checkpoint.report_checkpoint_age_ms(&self.metrics.checkpoint_contents_age_ms); - }, - // In this case, messages in the mailbox have been overwritten - // as a result of lagging too far behind. - Ok(Err(RecvError::Lagged(num_skipped))) => { - debug!( - "Checkpoint Execution Recv channel overflowed {:?} messages", - num_skipped, - ); - } - Ok(Err(RecvError::Closed)) => { - panic!("Checkpoint Execution Sender (StateSync) closed channel unexpectedly"); - } - } - } - } - } - - pub fn set_inconsistent_state(&self, is_inconsistent_state: bool) { - self.metrics - .accumulator_inconsistent_state - .set(is_inconsistent_state as i64); - } - - fn bump_highest_executed_checkpoint(&self, checkpoint: &VerifiedCheckpoint) { - // Ensure that we are not skipping checkpoints at any point - let seq = *checkpoint.sequence_number(); - debug!("Bumping highest_executed_checkpoint watermark to {seq:?}"); - if let Some(prev_highest) = self - .checkpoint_store - .get_highest_executed_checkpoint_seq_number() - .unwrap() - { - assert_eq!(prev_highest + 1, seq); - } else { - assert_eq!(seq, 0); - } - if seq % CHECKPOINT_PROGRESS_LOG_COUNT_INTERVAL == 0 { - info!("Finished syncing and executing checkpoint {}", seq); - } - - fail_point!("highest-executed-checkpoint"); - - // We store a fixed number of additional FullCheckpointContents after execution - // is complete for use in state sync. - const NUM_SAVED_FULL_CHECKPOINT_CONTENTS: u64 = 5_000; - if seq >= NUM_SAVED_FULL_CHECKPOINT_CONTENTS { - let prune_seq = seq - NUM_SAVED_FULL_CHECKPOINT_CONTENTS; - let prune_checkpoint = self - .checkpoint_store - .get_checkpoint_by_sequence_number(prune_seq) - .expect("Failed to fetch checkpoint") - .expect("Failed to retrieve earlier checkpoint by sequence number"); - self.checkpoint_store - .delete_full_checkpoint_contents(prune_seq) - .expect("Failed to delete full checkpoint contents"); - self.checkpoint_store - .delete_contents_digest_sequence_number_mapping(&prune_checkpoint.content_digest) - .expect("Failed to delete contents digest -> sequence number mapping"); - } - - self.checkpoint_store - .update_highest_executed_checkpoint(checkpoint) - .unwrap(); - self.metrics.last_executed_checkpoint.set(seq as i64); - - self.metrics - .last_executed_checkpoint_timestamp_ms - .set(checkpoint.timestamp_ms as i64); - checkpoint.report_checkpoint_age_ms(&self.metrics.last_executed_checkpoint_age_ms); - } - - /// Post processing and plumbing after we executed a checkpoint. This - /// function is guaranteed to be called in the order of checkpoint - /// sequence number. - #[instrument(level = "debug", skip_all)] - async fn process_executed_checkpoint( - &self, - epoch_store: &AuthorityPerEpochStore, - checkpoint: &VerifiedCheckpoint, - all_tx_digests: &[TransactionDigest], - ) { - // Commit all transaction effects to disk - let cache_commit = self.state.get_cache_commit(); - debug!(seq = ?checkpoint.sequence_number, "committing checkpoint transactions to disk"); - for digest in all_tx_digests { - cache_commit - .commit_transaction_outputs(epoch_store.epoch(), digest) - .await - .expect("commit_transaction_outputs cannot fail"); - } - - if !checkpoint.is_last_checkpoint_of_epoch() { - self.bump_highest_executed_checkpoint(checkpoint); - } - } - - #[instrument(level = "debug", skip_all)] - fn schedule_synced_checkpoints( - &self, - pending: &mut CheckpointExecutionBuffer, - next_to_schedule: &mut CheckpointSequenceNumber, - epoch_store: Arc, - run_with_range: Option, - ) { - let Some(latest_synced_checkpoint) = self - .checkpoint_store - .get_highest_synced_checkpoint() - .expect("Failed to read highest synced checkpoint") - else { - debug!("No checkpoints to schedule, highest synced checkpoint is None",); - return; - }; - - while *next_to_schedule <= *latest_synced_checkpoint.sequence_number() - && pending.len() < self.config.checkpoint_execution_max_concurrency - { - let checkpoint = self - .checkpoint_store - .get_checkpoint_by_sequence_number(*next_to_schedule) - .unwrap() - .unwrap_or_else(|| { - panic!( - "Checkpoint sequence number {:?} does not exist in checkpoint store", - *next_to_schedule - ) - }); - if checkpoint.epoch() > epoch_store.epoch() { - return; - } - match run_with_range { - Some(RunWithRange::Checkpoint(seq)) if *next_to_schedule > seq => { - debug!( - "RunWithRange Checkpoint {} is set, not scheduling checkpoint {}", - seq, *next_to_schedule - ); - return; - } - _ => { - self.schedule_checkpoint(checkpoint, pending, epoch_store.clone()); - *next_to_schedule += 1; - } - } - } - } - - #[instrument(level = "error", skip_all, fields(seq = ?checkpoint.sequence_number(), epoch = ?epoch_store.epoch()))] - fn schedule_checkpoint( - &self, - checkpoint: VerifiedCheckpoint, - pending: &mut CheckpointExecutionBuffer, - epoch_store: Arc, - ) { - debug!("Scheduling checkpoint for execution"); - - // Mismatch between node epoch and checkpoint epoch after startup - // crash recovery is invalid - let checkpoint_epoch = checkpoint.epoch(); - assert_eq!( - checkpoint_epoch, - epoch_store.epoch(), - "Epoch mismatch after startup recovery. checkpoint epoch: {:?}, node epoch: {:?}", - checkpoint_epoch, - epoch_store.epoch(), - ); - - let metrics = self.metrics.clone(); - let local_execution_timeout_sec = self.config.local_execution_timeout_sec; - let data_ingestion_dir = self.config.data_ingestion_dir.clone(); - let checkpoint_store = self.checkpoint_store.clone(); - let cache_reader = self.cache_reader.clone(); - let tx_manager = self.tx_manager.clone(); - let accumulator = self.accumulator.clone(); - let state = self.state.clone(); - - pending.push_back(spawn_monitored_task!(async move { - let epoch_store = epoch_store.clone(); - let tx_digests = loop { - match execute_checkpoint( - checkpoint.clone(), - &state, - cache_reader.as_ref(), - checkpoint_store.clone(), - epoch_store.clone(), - tx_manager.clone(), - accumulator.clone(), - local_execution_timeout_sec, - &metrics, - data_ingestion_dir.clone(), - ) - .await - { - Err(err) => { - error!( - "Error while executing checkpoint, will retry in 1s: {:?}", - err - ); - tokio::time::sleep(Duration::from_secs(1)).await; - metrics.checkpoint_exec_errors.inc(); - } - Ok(tx_digests) => break tx_digests, - } - }; - (checkpoint, tx_digests) - })); - } - - #[instrument(level = "info", skip_all)] - async fn execute_change_epoch_tx( - &self, - execution_digests: ExecutionDigests, - change_epoch_tx_digest: TransactionDigest, - change_epoch_tx: VerifiedExecutableTransaction, - epoch_store: Arc, - checkpoint: VerifiedCheckpoint, - ) { - let change_epoch_fx = self - .cache_reader - .get_effects(&execution_digests.effects) - .expect("Fetching effects for change_epoch tx cannot fail") - .expect("Change_epoch tx effects must exist"); - - if change_epoch_tx.contains_shared_object() { - epoch_store - .acquire_shared_locks_from_effects( - &change_epoch_tx, - &change_epoch_fx, - self.cache_reader.as_ref(), - ) - .await - .expect("Acquiring shared locks for change_epoch tx cannot fail"); - } - - self.tx_manager.enqueue_with_expected_effects_digest( - vec![(change_epoch_tx.clone(), execution_digests.effects)], - &epoch_store, - ); - handle_execution_effects( - &self.state, - vec![execution_digests], - vec![change_epoch_tx_digest], - checkpoint.clone(), - self.checkpoint_store.clone(), - self.cache_reader.as_ref(), - epoch_store.clone(), - self.tx_manager.clone(), - self.accumulator.clone(), - self.config.local_execution_timeout_sec, - self.config.data_ingestion_dir.clone(), - ) - .await; - } - - /// Check whether `checkpoint` is the last checkpoint of the current epoch. - /// If so, perform special case logic (execute change_epoch tx, - /// accumulate epoch, finalize transactions), then return true. - pub async fn check_epoch_last_checkpoint( - &self, - epoch_store: Arc, - checkpoint: &Option, - ) -> bool { - let cur_epoch = epoch_store.epoch(); - - if let Some(checkpoint) = checkpoint { - if checkpoint.epoch() == cur_epoch { - if let Some((change_epoch_execution_digests, change_epoch_tx)) = - extract_end_of_epoch_tx( - checkpoint, - self.cache_reader.as_ref(), - self.checkpoint_store.clone(), - epoch_store.clone(), - ) - { - let change_epoch_tx_digest = change_epoch_execution_digests.transaction; - - info!( - ended_epoch = cur_epoch, - last_checkpoint = checkpoint.sequence_number(), - "Reached end of epoch, executing change_epoch transaction", - ); - - self.execute_change_epoch_tx( - change_epoch_execution_digests, - change_epoch_tx_digest, - change_epoch_tx, - epoch_store.clone(), - checkpoint.clone(), - ) - .await; - - let cache_commit = self.state.get_cache_commit(); - cache_commit - .commit_transaction_outputs(cur_epoch, &change_epoch_tx_digest) - .await - .expect("commit_transaction_outputs cannot fail"); - - fail_point_async!("prune-and-compact"); - - // For finalizing the checkpoint, we need to pass in all checkpoint - // transaction effects, not just the change_epoch tx effects. However, - // we have already notify awaited all tx effects separately (once - // for change_epoch tx, and once for all other txes). Therefore this - // should be a fast operation - let all_tx_digests: Vec<_> = self - .checkpoint_store - .get_checkpoint_contents(&checkpoint.content_digest) - .expect("read cannot fail") - .expect("Checkpoint contents should exist") - .iter() - .map(|digests| digests.transaction) - .collect(); - - let effects = self - .cache_reader - .notify_read_executed_effects(&all_tx_digests) - .await - .expect("Failed to get executed effects for finalizing checkpoint"); - - finalize_checkpoint( - &self.state, - self.cache_reader.as_ref(), - self.checkpoint_store.clone(), - &all_tx_digests, - epoch_store.clone(), - checkpoint.clone(), - self.accumulator.clone(), - effects, - self.config.data_ingestion_dir.clone(), - ) - .await - .expect("Finalizing checkpoint cannot fail"); - - self.accumulator - .accumulate_epoch( - &cur_epoch, - *checkpoint.sequence_number(), - epoch_store.clone(), - ) - .in_monitored_scope("CheckpointExecutor::accumulate_epoch") - .await - .expect("Accumulating epoch cannot fail"); - - self.bump_highest_executed_checkpoint(checkpoint); - - return true; - } - } - } - false - } -} - -// Logs within the function are annotated with the checkpoint sequence number -// and epoch, from schedule_checkpoint(). -#[instrument(level = "debug", skip_all, fields(seq = ?checkpoint.sequence_number(), epoch = ?epoch_store.epoch()))] -async fn execute_checkpoint( - checkpoint: VerifiedCheckpoint, - state: &AuthorityState, - cache_reader: &dyn ExecutionCacheRead, - checkpoint_store: Arc, - epoch_store: Arc, - transaction_manager: Arc, - accumulator: Arc, - local_execution_timeout_sec: u64, - metrics: &Arc, - data_ingestion_dir: Option, -) -> SuiResult> { - debug!("Preparing checkpoint for execution",); - let prepare_start = Instant::now(); - - // this function must guarantee that all transactions in the checkpoint are - // executed before it returns. This invariant is enforced in two phases: - // - First, we filter out any already executed transactions from the checkpoint - // in get_unexecuted_transactions() - // - Second, we execute all remaining transactions. - - let (execution_digests, all_tx_digests, executable_txns, randomness_round) = - get_unexecuted_transactions( - checkpoint.clone(), - cache_reader, - checkpoint_store.clone(), - epoch_store.clone(), - ); - - let tx_count = execution_digests.len(); - debug!("Number of transactions in the checkpoint: {:?}", tx_count); - metrics.checkpoint_transaction_count.report(tx_count as u64); - - execute_transactions( - execution_digests, - all_tx_digests.clone(), - executable_txns, - state, - cache_reader, - checkpoint_store.clone(), - epoch_store.clone(), - transaction_manager, - accumulator, - local_execution_timeout_sec, - checkpoint, - metrics, - prepare_start, - data_ingestion_dir, - ) - .await?; - - // Once execution is complete, we know that any randomness contained in this - // checkpoint has been successfully included in a checkpoint certified by - // quorum of validators. - if let Some(round) = randomness_round { - // RandomnessManager is only present on validators. - if let Some(randomness_reporter) = epoch_store.randomness_reporter() { - debug!( - ?round, - "notifying RandomnessReporter that randomness update was executed in checkpoint" - ); - randomness_reporter.notify_randomness_in_checkpoint(round)?; - } - } - - Ok(all_tx_digests) -} - -#[instrument(level = "error", skip_all, fields(seq = ?checkpoint.sequence_number(), epoch = ?epoch_store.epoch()))] -async fn handle_execution_effects( - state: &AuthorityState, - execution_digests: Vec, - all_tx_digests: Vec, - checkpoint: VerifiedCheckpoint, - checkpoint_store: Arc, - cache_reader: &dyn ExecutionCacheRead, - epoch_store: Arc, - transaction_manager: Arc, - accumulator: Arc, - local_execution_timeout_sec: u64, - data_ingestion_dir: Option, -) { - // Once synced_txns have been awaited, all txns should have effects committed. - let mut periods = 1; - let log_timeout_sec = Duration::from_secs(local_execution_timeout_sec); - // Whether the checkpoint is next to execute and blocking additional executions. - let mut blocking_execution = false; - loop { - let effects_future = cache_reader.notify_read_executed_effects(&all_tx_digests); - - match timeout(log_timeout_sec, effects_future).await { - Err(_elapsed) => { - // Reading this value every timeout should be ok. - let highest_seq = checkpoint_store - .get_highest_executed_checkpoint_seq_number() - .unwrap() - .unwrap_or_default(); - if checkpoint.sequence_number <= highest_seq { - error!( - "Re-executing checkpoint {} after higher checkpoint {} has executed!", - checkpoint.sequence_number, highest_seq - ); - continue; - } - if checkpoint.sequence_number > highest_seq + 1 { - trace!( - "Checkpoint {} is still executing. Highest executed = {}", - checkpoint.sequence_number, - highest_seq - ); - continue; - } - if !blocking_execution { - trace!( - "Checkpoint {} is next to execute.", - checkpoint.sequence_number - ); - blocking_execution = true; - continue; - } - - // Only log details when the checkpoint is next to execute, but has not finished - // execution within log_timeout_sec. - let missing_digests: Vec = cache_reader - .multi_get_executed_effects_digests(&all_tx_digests) - .expect("multi_get_executed_effects cannot fail") - .iter() - .zip(all_tx_digests.clone()) - .filter_map( - |(fx, digest)| { - if fx.is_none() { Some(digest) } else { None } - }, - ) - .collect(); - - if missing_digests.is_empty() { - // All effects just become available. - continue; - } - - warn!( - "Transaction effects for checkpoint tx digests {:?} not present within {:?}. ", - missing_digests, - log_timeout_sec * periods, - ); - - // Print out more information for the 1st pending transaction, which should have - // all of its input available. - let pending_digest = missing_digests.first().unwrap(); - if let Some(missing_input) = transaction_manager.get_missing_input(pending_digest) { - warn!( - "Transaction {pending_digest:?} has missing input objects {missing_input:?}", - ); - } - periods += 1; - } - Ok(Err(err)) => panic!("Failed to notify_read_executed_effects: {:?}", err), - Ok(Ok(effects)) => { - for (tx_digest, expected_digest, actual_effects) in - izip!(&all_tx_digests, &execution_digests, &effects) - { - let expected_effects_digest = &expected_digest.effects; - assert_not_forked( - &checkpoint, - tx_digest, - expected_effects_digest, - &actual_effects.digest(), - cache_reader, - ); - } - - // return Ok(effects); - - // if end of epoch checkpoint, we must finalize the checkpoint after executing - // the change epoch tx, which is done after all other checkpoint execution - if checkpoint.end_of_epoch_data.is_none() { - finalize_checkpoint( - state, - cache_reader, - checkpoint_store.clone(), - &all_tx_digests, - epoch_store.clone(), - checkpoint.clone(), - accumulator.clone(), - effects, - data_ingestion_dir, - ) - .await - .expect("Finalizing checkpoint cannot fail"); - } - return; - } - } - } -} - -fn assert_not_forked( - checkpoint: &VerifiedCheckpoint, - tx_digest: &TransactionDigest, - expected_digest: &TransactionEffectsDigest, - actual_effects_digest: &TransactionEffectsDigest, - cache_reader: &dyn ExecutionCacheRead, -) { - if *expected_digest != *actual_effects_digest { - let actual_effects = cache_reader - .get_executed_effects(tx_digest) - .expect("get_executed_effects cannot fail") - .expect("actual effects should exist"); - - // log observed effects (too big for panic message) and then panic. - error!( - ?checkpoint, - ?tx_digest, - ?expected_digest, - ?actual_effects, - "fork detected!" - ); - panic!( - "When executing checkpoint {}, transaction {} \ - is expected to have effects digest {}, but got {}!", - checkpoint.sequence_number(), - tx_digest, - expected_digest, - actual_effects_digest, - ); - } -} - -// Given a checkpoint, find the end of epoch transaction, if it exists -fn extract_end_of_epoch_tx( - checkpoint: &VerifiedCheckpoint, - cache_reader: &dyn ExecutionCacheRead, - checkpoint_store: Arc, - epoch_store: Arc, -) -> Option<(ExecutionDigests, VerifiedExecutableTransaction)> { - checkpoint.end_of_epoch_data.as_ref()?; - - // Last checkpoint must have the end of epoch transaction as the last - // transaction. - - let checkpoint_sequence = checkpoint.sequence_number(); - let execution_digests = checkpoint_store - .get_checkpoint_contents(&checkpoint.content_digest) - .expect("Failed to get checkpoint contents from store") - .unwrap_or_else(|| { - panic!( - "Checkpoint contents for digest {:?} does not exist", - checkpoint.content_digest - ) - }) - .into_inner(); - - let digests = execution_digests - .last() - .expect("Final checkpoint must have at least one transaction"); - - let change_epoch_tx = cache_reader - .get_transaction_block(&digests.transaction) - .expect("read cannot fail"); - - let change_epoch_tx = VerifiedExecutableTransaction::new_from_checkpoint( - (*change_epoch_tx.unwrap_or_else(|| - panic!( - "state-sync should have ensured that transaction with digest {:?} exists for checkpoint: {checkpoint:?}", - digests.transaction, - ) - )).clone(), - epoch_store.epoch(), - *checkpoint_sequence, - ); - - assert!( - change_epoch_tx - .data() - .intent_message() - .value - .is_end_of_epoch_tx() - ); - - Some((*digests, change_epoch_tx)) -} - -// Given a checkpoint, filter out any already executed transactions, then return -// the remaining execution digests, transaction digests, transactions to be -// executed, and randomness round (if any) included in the checkpoint. -#[allow(clippy::type_complexity)] -fn get_unexecuted_transactions( - checkpoint: VerifiedCheckpoint, - cache_reader: &dyn ExecutionCacheRead, - checkpoint_store: Arc, - epoch_store: Arc, -) -> ( - Vec, - Vec, - Vec<(VerifiedExecutableTransaction, TransactionEffectsDigest)>, - Option, -) { - let checkpoint_sequence = checkpoint.sequence_number(); - let full_contents = checkpoint_store - .get_full_checkpoint_contents_by_sequence_number(*checkpoint_sequence) - .expect("Failed to get checkpoint contents from store") - .tap_some(|_| { - debug!("loaded full checkpoint contents in bulk for sequence {checkpoint_sequence}") - }); - - let mut execution_digests = checkpoint_store - .get_checkpoint_contents(&checkpoint.content_digest) - .expect("Failed to get checkpoint contents from store") - .unwrap_or_else(|| { - panic!( - "Checkpoint contents for digest {:?} does not exist", - checkpoint.content_digest - ) - }) - .into_inner(); - - let full_contents_txns = full_contents.map(|c| { - c.into_iter() - .zip(execution_digests.iter()) - .map(|(txn, digests)| (digests.transaction, txn)) - .collect::>() - }); - - // Remove the change epoch transaction so that we can special case its - // execution. - checkpoint.end_of_epoch_data.as_ref().tap_some(|_| { - let change_epoch_tx_digest = execution_digests - .pop() - .expect("Final checkpoint must have at least one transaction") - .transaction; - - let change_epoch_tx = cache_reader - .get_transaction_block(&change_epoch_tx_digest) - .expect("read cannot fail") - .unwrap_or_else(|| - panic!( - "state-sync should have ensured that transaction with digest {change_epoch_tx_digest:?} exists for checkpoint: {}", - checkpoint.sequence_number() - ) - ); - assert!(change_epoch_tx.data().intent_message().value.is_end_of_epoch_tx()); - }); - - // Look for a randomness state update tx. It must be first if it exists, because - // all other transactions in a checkpoint that includes a randomness state - // update are causally dependent on it. - let randomness_round = if let Some(first_digest) = execution_digests.first() { - let maybe_randomness_tx = cache_reader.get_transaction_block(&first_digest.transaction) - .expect("read cannot fail") - .unwrap_or_else(|| - panic!( - "state-sync should have ensured that transaction with digest {first_digest:?} exists for checkpoint: {}", - checkpoint.sequence_number() - ) - ); - if let TransactionKind::RandomnessStateUpdate(rsu) = - maybe_randomness_tx.data().transaction_data().kind() - { - Some(rsu.randomness_round) - } else { - None - } - } else { - None - }; - - let all_tx_digests: Vec = - execution_digests.iter().map(|tx| tx.transaction).collect(); - - let executed_effects_digests = cache_reader - .multi_get_executed_effects_digests(&all_tx_digests) - .expect("failed to read executed_effects from store"); - - let (unexecuted_txns, expected_effects_digests): (Vec<_>, Vec<_>) = - izip!(execution_digests.iter(), executed_effects_digests.iter()) - .filter_map(|(digests, effects_digest)| match effects_digest { - None => Some((digests.transaction, digests.effects)), - Some(actual_effects_digest) => { - let tx_digest = &digests.transaction; - let effects_digest = &digests.effects; - trace!( - "Transaction with digest {:?} has already been executed", - tx_digest - ); - assert_not_forked( - &checkpoint, - tx_digest, - effects_digest, - actual_effects_digest, - cache_reader, - ); - None - } - }) - .unzip(); - - // read remaining unexecuted transactions from store - let executable_txns: Vec<_> = if let Some(full_contents_txns) = full_contents_txns { - unexecuted_txns - .into_iter() - .zip(expected_effects_digests) - .map(|(tx_digest, expected_effects_digest)| { - let tx = &full_contents_txns.get(&tx_digest).unwrap().transaction; - ( - VerifiedExecutableTransaction::new_from_checkpoint( - VerifiedTransaction::new_unchecked(tx.clone()), - epoch_store.epoch(), - *checkpoint_sequence, - ), - expected_effects_digest, - ) - }) - .collect() - } else { - cache_reader - .multi_get_transaction_blocks(&unexecuted_txns) - .expect("Failed to get checkpoint txes from store") - .into_iter() - .zip(expected_effects_digests) - .enumerate() - .map(|(i, (tx, expected_effects_digest))| { - let tx = tx.unwrap_or_else(|| - panic!( - "state-sync should have ensured that transaction with digest {:?} exists for checkpoint: {checkpoint:?}", - unexecuted_txns[i] - ) - ); - // change epoch tx is handled specially in check_epoch_last_checkpoint - assert!(!tx.data().intent_message().value.is_end_of_epoch_tx()); - ( - VerifiedExecutableTransaction::new_from_checkpoint( - Arc::try_unwrap(tx).unwrap_or_else(|tx| (*tx).clone()), - epoch_store.epoch(), - *checkpoint_sequence, - ), - expected_effects_digest - ) - }) - .collect() - }; - - ( - execution_digests, - all_tx_digests, - executable_txns, - randomness_round, - ) -} - -// Logs within the function are annotated with the checkpoint sequence number -// and epoch, from schedule_checkpoint(). -#[instrument(level = "debug", skip_all)] -async fn execute_transactions( - execution_digests: Vec, - all_tx_digests: Vec, - executable_txns: Vec<(VerifiedExecutableTransaction, TransactionEffectsDigest)>, - state: &AuthorityState, - cache_reader: &dyn ExecutionCacheRead, - checkpoint_store: Arc, - epoch_store: Arc, - transaction_manager: Arc, - accumulator: Arc, - local_execution_timeout_sec: u64, - checkpoint: VerifiedCheckpoint, - metrics: &Arc, - prepare_start: Instant, - data_ingestion_dir: Option, -) -> SuiResult { - let effects_digests: HashMap<_, _> = execution_digests - .iter() - .map(|digest| (digest.transaction, digest.effects)) - .collect(); - - let shared_effects_digests = executable_txns - .iter() - .filter(|(tx, _)| tx.contains_shared_object()) - .map(|(tx, _)| { - *effects_digests - .get(tx.digest()) - .expect("Transaction digest not found in effects_digests") - }) - .collect::>(); - - let digest_to_effects: HashMap = cache_reader - .multi_get_effects(&shared_effects_digests)? - .into_iter() - .zip(shared_effects_digests) - .map(|(fx, fx_digest)| { - if fx.is_none() { - panic!( - "Transaction effects for effects digest {:?} do not exist in effects table", - fx_digest - ); - } - let fx = fx.unwrap(); - (*fx.transaction_digest(), fx) - }) - .collect(); - - for (tx, _) in &executable_txns { - if tx.contains_shared_object() { - epoch_store - .acquire_shared_locks_from_effects( - tx, - digest_to_effects.get(tx.digest()).unwrap(), - cache_reader, - ) - .await?; - } - } - - let prepare_elapsed = prepare_start.elapsed(); - metrics - .checkpoint_prepare_latency_us - .report(prepare_elapsed.as_micros() as u64); - if checkpoint.sequence_number % CHECKPOINT_PROGRESS_LOG_COUNT_INTERVAL == 0 { - info!( - "Checkpoint preparation for execution took {:?}", - prepare_elapsed - ); - } - - let exec_start = Instant::now(); - transaction_manager.enqueue_with_expected_effects_digest(executable_txns.clone(), &epoch_store); - - handle_execution_effects( - state, - execution_digests, - all_tx_digests, - checkpoint.clone(), - checkpoint_store, - cache_reader, - epoch_store, - transaction_manager, - accumulator, - local_execution_timeout_sec, - data_ingestion_dir, - ) - .await; - - let exec_elapsed = exec_start.elapsed(); - metrics - .checkpoint_exec_latency_us - .report(exec_elapsed.as_micros() as u64); - if checkpoint.sequence_number % CHECKPOINT_PROGRESS_LOG_COUNT_INTERVAL == 0 { - info!("Checkpoint execution took {:?}", exec_elapsed); - } - - Ok(()) -} - -#[instrument(level = "debug", skip_all)] -async fn finalize_checkpoint( - state: &AuthorityState, - cache_reader: &dyn ExecutionCacheRead, - checkpoint_store: Arc, - tx_digests: &[TransactionDigest], - epoch_store: Arc, - checkpoint: VerifiedCheckpoint, - accumulator: Arc, - effects: Vec, - data_ingestion_dir: Option, -) -> SuiResult { - if epoch_store.per_epoch_finalized_txns_enabled() { - epoch_store.insert_finalized_transactions(tx_digests, checkpoint.sequence_number)?; - } - // TODO remove once we no longer need to support this table for read RPC - state - .get_checkpoint_cache() - .deprecated_insert_finalized_transactions( - tx_digests, - epoch_store.epoch(), - checkpoint.sequence_number, - )?; - - accumulator.accumulate_checkpoint(effects, checkpoint.sequence_number, epoch_store)?; - if let Some(path) = data_ingestion_dir { - store_checkpoint_locally( - path, - checkpoint, - cache_reader, - checkpoint_store, - tx_digests.to_vec(), - )?; - } - Ok(()) -} diff --git a/crates/sui-core/src/checkpoints/checkpoint_executor/tests.rs b/crates/sui-core/src/checkpoints/checkpoint_executor/tests.rs deleted file mode 100644 index 7c0d66c73c1..00000000000 --- a/crates/sui-core/src/checkpoints/checkpoint_executor/tests.rs +++ /dev/null @@ -1,491 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{sync::Arc, time::Duration}; - -use broadcast::{Receiver, Sender}; -use sui_config::node::ExpensiveSafetyCheckConfig; -use sui_protocol_config::SupportedProtocolVersions; -use sui_swarm_config::test_utils::{empty_contents, CommitteeFixture}; -use sui_types::{ - committee::ProtocolVersion, - gas::GasCostSummary, - messages_checkpoint::{ECMHLiveObjectSetDigest, EndOfEpochData, VerifiedCheckpoint}, - sui_system_state::epoch_start_sui_system_state::EpochStartSystemState, -}; -use tempfile::tempdir; -use tokio::{sync::broadcast, time::timeout}; -use typed_store::Map; - -use super::*; -use crate::{ - authority::{ - epoch_start_configuration::EpochStartConfiguration, - test_authority_builder::TestAuthorityBuilder, AuthorityState, - }, - checkpoints::CheckpointStore, - state_accumulator::{AccumulatorStore, StateAccumulator}, -}; - -/// Test checkpoint executor happy path, test that checkpoint executor correctly -/// picks up where it left off in the event of a mid-epoch node crash. -#[tokio::test] -pub async fn test_checkpoint_executor_crash_recovery() { - let buffer_size = num_cpus::get() * 2; - let tempdir = tempdir().unwrap(); - let checkpoint_store = CheckpointStore::new(tempdir.path()); - - let (state, mut executor, accumulator, checkpoint_sender, committee): ( - Arc, - CheckpointExecutor, - Arc, - Sender, - CommitteeFixture, - ) = init_executor_test(buffer_size, checkpoint_store.clone()).await; - - assert!( - checkpoint_store - .get_highest_executed_checkpoint_seq_number() - .unwrap() - .is_none() - ); - let checkpoints = sync_new_checkpoints( - &checkpoint_store, - &checkpoint_sender, - 2 * buffer_size, - None, - &committee, - ); - - let epoch_store = state.epoch_store_for_testing().clone(); - let executor_handle = - spawn_monitored_task!(async move { executor.run_epoch(epoch_store, None).await }); - tokio::time::sleep(Duration::from_secs(5)).await; - - // ensure we executed all synced checkpoints - let highest_executed = checkpoint_store - .get_highest_executed_checkpoint_seq_number() - .unwrap() - .expect("Expected highest executed to not be None"); - assert_eq!(highest_executed, 2 * (buffer_size as u64) - 1,); - - // Simulate node restart - executor_handle.abort(); - - // sync more checkpoints in the meantime - let _ = sync_new_checkpoints( - &checkpoint_store, - &checkpoint_sender, - 2 * buffer_size, - Some(checkpoints.last().cloned().unwrap()), - &committee, - ); - - // restart checkpoint executor and ensure that it picks - // up where it left off - let mut executor = CheckpointExecutor::new_for_tests( - checkpoint_sender.subscribe(), - checkpoint_store.clone(), - state.clone(), - accumulator.clone(), - ); - - let epoch_store = state.epoch_store_for_testing().clone(); - let executor_handle = - spawn_monitored_task!(async move { executor.run_epoch(epoch_store, None).await }); - tokio::time::sleep(Duration::from_secs(15)).await; - - let highest_executed = checkpoint_store - .get_highest_executed_checkpoint_seq_number() - .unwrap() - .expect("Expected highest executed to not be None"); - assert_eq!(highest_executed, 4 * (buffer_size as u64) - 1); - - executor_handle.abort(); -} - -/// Test that checkpoint execution correctly signals end of epoch after -/// receiving last checkpoint of epoch, then resumes executing cehckpoints -/// from the next epoch if called after reconfig -/// -/// TODO(william) disabling reconfig unit tests here for now until we can work -/// on correctly inserting transactions, especially the change_epoch tx. As it -/// stands, this is better tested in existing reconfig simtests -#[tokio::test] -#[ignore] -pub async fn test_checkpoint_executor_cross_epoch() { - let buffer_size = 10; - let num_to_sync_per_epoch = buffer_size * 2; - let tempdir = tempdir().unwrap(); - let checkpoint_store = CheckpointStore::new(tempdir.path()); - - let (authority_state, mut executor, accumulator, checkpoint_sender, first_committee): ( - Arc, - CheckpointExecutor, - Arc, - Sender, - CommitteeFixture, - ) = init_executor_test(buffer_size, checkpoint_store.clone()).await; - - let epoch_store = authority_state.epoch_store_for_testing(); - let epoch = epoch_store.epoch(); - assert_eq!(epoch, 0); - - assert!( - checkpoint_store - .get_highest_executed_checkpoint_seq_number() - .unwrap() - .is_none() - ); - - // sync 20 checkpoints - let cold_start_checkpoints = sync_new_checkpoints( - &checkpoint_store, - &checkpoint_sender, - num_to_sync_per_epoch, - None, - &first_committee, - ); - - // sync end of epoch checkpoint - let last_executed_checkpoint = cold_start_checkpoints.last().cloned().unwrap(); - let (end_of_epoch_0_checkpoint, second_committee) = sync_end_of_epoch_checkpoint( - authority_state.clone(), - &checkpoint_store, - &checkpoint_sender, - last_executed_checkpoint.clone(), - &first_committee, - ) - .await; - - // sync 20 more checkpoints - let next_epoch_checkpoints = sync_new_checkpoints( - &checkpoint_store, - &checkpoint_sender, - num_to_sync_per_epoch, - Some(end_of_epoch_0_checkpoint.clone()), - &second_committee, - ); - - authority_state - .get_checkpoint_store() - .epoch_last_checkpoint_map - .insert( - &end_of_epoch_0_checkpoint.epoch, - end_of_epoch_0_checkpoint.sequence_number(), - ) - .unwrap(); - authority_state - .get_checkpoint_store() - .certified_checkpoints - .insert( - end_of_epoch_0_checkpoint.sequence_number(), - end_of_epoch_0_checkpoint.serializable_ref(), - ) - .unwrap(); - // sync end of epoch checkpoint - let last_executed_checkpoint = next_epoch_checkpoints.last().cloned().unwrap(); - let (_end_of_epoch_1_checkpoint, _third_committee) = sync_end_of_epoch_checkpoint( - authority_state.clone(), - &checkpoint_store, - &checkpoint_sender, - last_executed_checkpoint.clone(), - &second_committee, - ) - .await; - - // Ensure root state hash for epoch does not exist before we close epoch - assert!( - authority_state - .get_execution_cache() - .get_root_state_accumulator_for_epoch(0) - .unwrap() - .is_none() - ); - - // Ensure executor reaches end of epoch in a timely manner - timeout(Duration::from_secs(5), async { - executor.run_epoch(epoch_store.clone(), None).await; - }) - .await - .unwrap(); - - // We should have synced up to epoch boundary - assert_eq!( - checkpoint_store - .get_highest_executed_checkpoint_seq_number() - .unwrap() - .unwrap(), - num_to_sync_per_epoch as u64, - ); - - let first_epoch = 0; - - // Ensure root state hash for epoch exists at end of epoch - authority_state - .get_execution_cache() - .get_root_state_accumulator_for_epoch(first_epoch) - .unwrap() - .expect("root state hash for epoch should exist"); - - let system_state = EpochStartSystemState::new_for_testing_with_epoch(1); - - let new_epoch_store = authority_state - .reconfigure( - &authority_state.epoch_store_for_testing(), - SupportedProtocolVersions::SYSTEM_DEFAULT, - second_committee.committee().clone(), - EpochStartConfiguration::new( - system_state, - Default::default(), - authority_state.get_object_store(), - None, - ) - .unwrap(), - &executor, - accumulator, - &ExpensiveSafetyCheckConfig::default(), - ) - .await - .unwrap(); - - // checkpoint execution should resume starting at checkpoints - // of next epoch - timeout(Duration::from_secs(5), async { - executor.run_epoch(new_epoch_store.clone(), None).await; - }) - .await - .unwrap(); - - assert_eq!( - checkpoint_store - .get_highest_executed_checkpoint_seq_number() - .unwrap() - .unwrap(), - 2 * num_to_sync_per_epoch as u64 + 1, - ); - - let second_epoch = 1; - assert!(second_epoch == new_epoch_store.epoch()); - - authority_state - .get_execution_cache() - .get_root_state_accumulator_for_epoch(second_epoch) - .unwrap() - .expect("root state hash for epoch should exist"); -} - -/// Test that if we crash at end of epoch / during reconfig, we recover on -/// startup by starting at the old epoch and immediately retrying reconfig -/// -/// TODO(william) disabling reconfig unit tests here for now until we can work -/// on correctly inserting transactions, especially the change_epoch tx. As it -/// stands, this is better tested in existing reconfig simtests -#[tokio::test] -#[ignore] -pub async fn test_reconfig_crash_recovery() { - let tempdir = tempdir().unwrap(); - let checkpoint_store = CheckpointStore::new(tempdir.path()); - - // new Node (syncing from checkpoint 0) - let (authority_state, mut executor, accumulator, checkpoint_sender, first_committee): ( - Arc, - CheckpointExecutor, - Arc, - Sender, - CommitteeFixture, - ) = init_executor_test( - 10, // StateSync -> Executor channel buffer size - checkpoint_store.clone(), - ) - .await; - - assert!( - checkpoint_store - .get_highest_executed_checkpoint_seq_number() - .unwrap() - .is_none() - ); - - // sync 1 checkpoint - let checkpoint = sync_new_checkpoints( - &checkpoint_store, - &checkpoint_sender, - 1, - None, - &first_committee, - ) - .pop() - .unwrap(); - - // sync end of epoch checkpoint - let (end_of_epoch_checkpoint, second_committee) = sync_end_of_epoch_checkpoint( - authority_state.clone(), - &checkpoint_store, - &checkpoint_sender, - checkpoint, - &first_committee, - ) - .await; - // sync 1 more checkpoint - let _next_epoch_checkpoints = sync_new_checkpoints( - &checkpoint_store, - &checkpoint_sender, - 1, - Some(end_of_epoch_checkpoint.clone()), - &second_committee, - ); - - timeout(Duration::from_secs(1), async { - executor - .run_epoch(authority_state.epoch_store_for_testing().clone(), None) - .await; - }) - .await - .unwrap(); - - // Check that we stopped execution at epoch boundary - assert_eq!( - checkpoint_store - .get_highest_executed_checkpoint_seq_number() - .unwrap() - .unwrap(), - *end_of_epoch_checkpoint.sequence_number(), - ); - - // Drop and re-istantiate checkpoint executor without performing reconfig. This - // is logically equivalent to reconfig crashing and the node restarting, in - // which case executor should be able to infer that, rather than beginning - // execution of the next epoch, we should immediately exit so that reconfig - // can be reattempted. - drop(executor); - let mut executor = CheckpointExecutor::new_for_tests( - checkpoint_sender.subscribe(), - checkpoint_store.clone(), - authority_state.clone(), - accumulator.clone(), - ); - - timeout(Duration::from_millis(200), async { - executor - .run_epoch(authority_state.epoch_store_for_testing().clone(), None) - .await; - }) - .await - .unwrap(); - - // Check that we have still not gone beyond epoch boundary - assert_eq!( - checkpoint_store - .get_highest_executed_checkpoint_seq_number() - .unwrap() - .unwrap(), - *end_of_epoch_checkpoint.sequence_number(), - ); -} - -async fn init_executor_test( - buffer_size: usize, - store: Arc, -) -> ( - Arc, - CheckpointExecutor, - Arc, - Sender, - CommitteeFixture, -) { - let network_config = - sui_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir().build(); - let state = TestAuthorityBuilder::new() - .with_network_config(&network_config) - .build() - .await; - - let (checkpoint_sender, _): (Sender, Receiver) = - broadcast::channel(buffer_size); - - let accumulator = StateAccumulator::new(state.get_execution_cache()); - let accumulator = Arc::new(accumulator); - - let executor = CheckpointExecutor::new_for_tests( - checkpoint_sender.subscribe(), - store.clone(), - state.clone(), - accumulator.clone(), - ); - ( - state, - executor, - accumulator, - checkpoint_sender, - CommitteeFixture::from_network_config(&network_config), - ) -} - -/// Creates and simulates syncing of a new checkpoint by StateSync, i.e. new -/// checkpoint is persisted, along with its contents, highest synced checkpoint -/// watermark is updated, and message is broadcasted notifying of the newly -/// synced checkpoint. Returns created checkpoints -fn sync_new_checkpoints( - checkpoint_store: &CheckpointStore, - sender: &Sender, - number_of_checkpoints: usize, - previous_checkpoint: Option, - committee: &CommitteeFixture, -) -> Vec { - let (ordered_checkpoints, _, _sequence_number_to_digest, _checkpoints) = - committee.make_empty_checkpoints(number_of_checkpoints, previous_checkpoint); - - for checkpoint in ordered_checkpoints.iter() { - sync_checkpoint(checkpoint, checkpoint_store, sender); - } - - ordered_checkpoints -} - -async fn sync_end_of_epoch_checkpoint( - authority_state: Arc, - checkpoint_store: &CheckpointStore, - sender: &Sender, - previous_checkpoint: VerifiedCheckpoint, - committee: &CommitteeFixture, -) -> (VerifiedCheckpoint, CommitteeFixture) { - let new_committee = - CommitteeFixture::generate(rand::rngs::OsRng, committee.committee().epoch + 1, 4); - let (_sequence_number, _digest, checkpoint) = committee.make_end_of_epoch_checkpoint( - previous_checkpoint, - Some(EndOfEpochData { - next_epoch_committee: new_committee.committee().voting_rights.clone(), - next_epoch_protocol_version: ProtocolVersion::MIN, - epoch_commitments: vec![ECMHLiveObjectSetDigest::default().into()], - }), - ); - authority_state - .create_and_execute_advance_epoch_tx( - &authority_state.epoch_store_for_testing().clone(), - &GasCostSummary::new(0, 0, 0, 0), - *checkpoint.sequence_number(), - 0, // epoch_start_timestamp_ms - ) - .await - .expect("Failed to create and execute advance epoch tx"); - sync_checkpoint(&checkpoint, checkpoint_store, sender); - (checkpoint, new_committee) -} - -fn sync_checkpoint( - checkpoint: &VerifiedCheckpoint, - checkpoint_store: &CheckpointStore, - sender: &Sender, -) { - checkpoint_store - .insert_verified_checkpoint(checkpoint) - .unwrap(); - checkpoint_store - .insert_checkpoint_contents(empty_contents().into_inner().into_checkpoint_contents()) - .unwrap(); - checkpoint_store - .update_highest_synced_checkpoint(checkpoint) - .unwrap(); - sender.send(checkpoint.clone()).unwrap(); -} diff --git a/crates/sui-core/src/checkpoints/metrics.rs b/crates/sui-core/src/checkpoints/metrics.rs deleted file mode 100644 index a3a167c3ef3..00000000000 --- a/crates/sui-core/src/checkpoints/metrics.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::sync::Arc; - -use mysten_metrics::histogram::Histogram; -use prometheus::{ - register_int_counter_vec_with_registry, register_int_counter_with_registry, - register_int_gauge_vec_with_registry, register_int_gauge_with_registry, IntCounter, - IntCounterVec, IntGauge, IntGaugeVec, Registry, -}; - -pub struct CheckpointMetrics { - pub last_certified_checkpoint: IntGauge, - pub last_constructed_checkpoint: IntGauge, - pub checkpoint_errors: IntCounter, - pub transactions_included_in_checkpoint: IntCounter, - pub checkpoint_roots_count: IntCounter, - pub checkpoint_participation: IntCounterVec, - pub last_received_checkpoint_signatures: IntGaugeVec, - pub last_sent_checkpoint_signature: IntGauge, - pub highest_accumulated_epoch: IntGauge, - pub checkpoint_creation_latency_ms: Histogram, - pub remote_checkpoint_forks: IntCounter, - pub split_brain_checkpoint_forks: IntCounter, - pub last_created_checkpoint_age_ms: Histogram, - pub last_certified_checkpoint_age_ms: Histogram, -} - -impl CheckpointMetrics { - pub fn new(registry: &Registry) -> Arc { - let this = Self { - last_certified_checkpoint: register_int_gauge_with_registry!( - "last_certified_checkpoint", - "Last certified checkpoint", - registry - ) - .unwrap(), - last_constructed_checkpoint: register_int_gauge_with_registry!( - "last_constructed_checkpoint", - "Last constructed checkpoint", - registry - ) - .unwrap(), - last_created_checkpoint_age_ms: Histogram::new_in_registry( - "last_created_checkpoint_age_ms", - "Age of the last created checkpoint", - registry, - ), - last_certified_checkpoint_age_ms: Histogram::new_in_registry( - "last_certified_checkpoint_age_ms", - "Age of the last certified checkpoint", - registry, - ), - checkpoint_errors: register_int_counter_with_registry!( - "checkpoint_errors", - "Checkpoints errors count", - registry - ) - .unwrap(), - transactions_included_in_checkpoint: register_int_counter_with_registry!( - "transactions_included_in_checkpoint", - "Transactions included in a checkpoint", - registry - ) - .unwrap(), - checkpoint_roots_count: register_int_counter_with_registry!( - "checkpoint_roots_count", - "Number of checkpoint roots received from consensus", - registry - ) - .unwrap(), - checkpoint_participation: register_int_counter_vec_with_registry!( - "checkpoint_participation", - "Participation in checkpoint certification by validator", - &["signer"], - registry - ) - .unwrap(), - last_received_checkpoint_signatures: register_int_gauge_vec_with_registry!( - "last_received_checkpoint_signatures", - "Last received checkpoint signatures by validator", - &["signer"], - registry - ) - .unwrap(), - last_sent_checkpoint_signature: register_int_gauge_with_registry!( - "last_sent_checkpoint_signature", - "Last checkpoint signature sent by myself", - registry - ) - .unwrap(), - highest_accumulated_epoch: register_int_gauge_with_registry!( - "highest_accumulated_epoch", - "Highest accumulated epoch", - registry - ) - .unwrap(), - checkpoint_creation_latency_ms: Histogram::new_in_registry( - "checkpoint_creation_latency_ms", - "Latency from consensus commit timstamp to local checkpoint creation in milliseconds", - registry, - ), - remote_checkpoint_forks: register_int_counter_with_registry!( - "remote_checkpoint_forks", - "Number of remote checkpoints that forked from local checkpoints", - registry - ) - .unwrap(), - split_brain_checkpoint_forks: register_int_counter_with_registry!( - "split_brain_checkpoint_forks", - "Number of checkpoints that have resulted in a split brain", - registry - ) - .unwrap(), - }; - Arc::new(this) - } - - pub fn new_for_tests() -> Arc { - Self::new(&Registry::new()) - } -} diff --git a/crates/sui-core/src/checkpoints/mod.rs b/crates/sui-core/src/checkpoints/mod.rs deleted file mode 100644 index 2e9874aa807..00000000000 --- a/crates/sui-core/src/checkpoints/mod.rs +++ /dev/null @@ -1,2324 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod causal_order; -pub mod checkpoint_executor; -mod checkpoint_output; -mod metrics; - -use std::{ - collections::{BTreeMap, HashMap, HashSet}, - fs::File, - io::Write, - path::Path, - sync::Arc, - time::Duration, -}; - -use chrono::Utc; -use diffy::create_patch; -use futures::{ - future::{select, Either}, - FutureExt, -}; -use itertools::Itertools; -use mysten_metrics::{monitored_scope, spawn_monitored_task, MonitoredFutureExt}; -use parking_lot::Mutex; -use rand::{rngs::OsRng, seq::SliceRandom}; -use serde::{Deserialize, Serialize}; -use sui_macros::fail_point; -use sui_network::default_mysten_network_config; -use sui_protocol_config::ProtocolVersion; -use sui_types::{ - base_types::{AuthorityName, ConciseableName, EpochId, TransactionDigest}, - committee::StakeUnit, - crypto::AuthorityStrongQuorumSignInfo, - digests::{CheckpointContentsDigest, CheckpointDigest}, - effects::{TransactionEffects, TransactionEffectsAPI}, - error::SuiResult, - gas::GasCostSummary, - message_envelope::Message, - messages_checkpoint::{ - CertifiedCheckpointSummary, CheckpointContents, CheckpointRequestV2, CheckpointResponseV2, - CheckpointSequenceNumber, CheckpointSignatureMessage, CheckpointSummary, - CheckpointSummaryResponse, CheckpointTimestamp, EndOfEpochData, FullCheckpointContents, - SignedCheckpointSummary, TrustedCheckpoint, VerifiedCheckpoint, VerifiedCheckpointContents, - }, - messages_consensus::ConsensusTransactionKey, - signature::GenericSignature, - sui_system_state::{ - epoch_start_sui_system_state::EpochStartSystemStateTrait, SuiSystemState, - SuiSystemStateTrait, - }, - transaction::{TransactionDataAPI, TransactionKey, TransactionKind}, -}; -use tokio::{ - sync::{watch, Notify}, - time::timeout, -}; -use tracing::{debug, error, info, instrument, warn}; -use typed_store::{ - rocks::{DBMap, MetricConf}, - traits::{TableSummary, TypedStoreDebug}, - Map, TypedStoreError, -}; -use typed_store_derive::DBMapUtils; - -pub use crate::checkpoints::{ - checkpoint_output::{ - LogCheckpointOutput, SendCheckpointToStateSync, SubmitCheckpointToConsensus, - }, - metrics::CheckpointMetrics, -}; -use crate::{ - authority::{ - authority_per_epoch_store::AuthorityPerEpochStore, AuthorityState, EffectsNotifyRead, - }, - authority_client::{make_network_authority_clients_with_network_config, AuthorityAPI}, - checkpoints::{ - causal_order::CausalOrder, - checkpoint_output::{CertifiedCheckpointOutput, CheckpointOutput}, - }, - consensus_handler::SequencedConsensusTransactionKey, - stake_aggregator::{InsertResult, MultiStakeAggregator}, - state_accumulator::StateAccumulator, -}; - -pub type CheckpointHeight = u64; - -pub struct EpochStats { - pub checkpoint_count: u64, - pub transaction_count: u64, - pub total_gas_reward: u64, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PendingCheckpointInfo { - pub timestamp_ms: CheckpointTimestamp, - pub last_of_epoch: bool, - pub checkpoint_height: CheckpointHeight, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PendingCheckpoint { - pub roots: Vec, - pub details: PendingCheckpointInfo, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum PendingCheckpointV2 { - // This is an enum for future upgradability, though at the moment there is only one variant. - V2(PendingCheckpointV2Contents), -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PendingCheckpointV2Contents { - pub roots: Vec, - pub details: PendingCheckpointInfo, -} - -impl PendingCheckpointV2 { - pub fn as_v2(&self) -> &PendingCheckpointV2Contents { - match self { - PendingCheckpointV2::V2(contents) => contents, - } - } - - pub fn into_v2(self) -> PendingCheckpointV2Contents { - match self { - PendingCheckpointV2::V2(contents) => contents, - } - } - - pub fn expect_v1(self) -> PendingCheckpoint { - let v2 = self.into_v2(); - PendingCheckpoint { - roots: v2 - .roots - .into_iter() - .map(|root| *root.unwrap_digest()) - .collect(), - details: v2.details, - } - } - - pub fn roots(&self) -> &Vec { - &self.as_v2().roots - } - - pub fn details(&self) -> &PendingCheckpointInfo { - &self.as_v2().details - } - - pub fn height(&self) -> CheckpointHeight { - self.details().checkpoint_height - } -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct BuilderCheckpointSummary { - pub summary: CheckpointSummary, - // Height at which this checkpoint summary was built. None for genesis checkpoint - pub checkpoint_height: Option, - pub position_in_commit: usize, -} - -#[derive(DBMapUtils)] -pub struct CheckpointStore { - /// Maps checkpoint contents digest to checkpoint contents - pub(crate) checkpoint_content: DBMap, - - /// Maps checkpoint contents digest to checkpoint sequence number - pub(crate) checkpoint_sequence_by_contents_digest: - DBMap, - - /// Stores entire checkpoint contents from state sync, indexed by sequence - /// number, for efficient reads of full checkpoints. Entries from this - /// table are deleted after state accumulation has completed. - full_checkpoint_content: DBMap, - - /// Stores certified checkpoints - pub(crate) certified_checkpoints: DBMap, - /// Map from checkpoint digest to certified checkpoint - pub(crate) checkpoint_by_digest: DBMap, - - /// Store locally computed checkpoint summaries so that we can detect forks - /// and log useful information. Can be pruned as soon as we verify that - /// we are in agreement with the latest certified checkpoint. - pub(crate) locally_computed_checkpoints: DBMap, - - /// A map from epoch ID to the sequence number of the last checkpoint in - /// that epoch. - epoch_last_checkpoint_map: DBMap, - - /// Watermarks used to determine the highest verified, fully synced, and - /// fully executed checkpoints - pub(crate) watermarks: DBMap, -} - -impl CheckpointStore { - pub fn new(path: &Path) -> Arc { - Arc::new(Self::open_tables_read_write( - path.to_path_buf(), - MetricConf::new("checkpoint"), - None, - None, - )) - } - - pub fn open_readonly(path: &Path) -> CheckpointStoreReadOnly { - Self::get_read_only_handle( - path.to_path_buf(), - None, - None, - MetricConf::new("checkpoint_readonly"), - ) - } - - #[instrument(level = "info", skip_all)] - pub fn insert_genesis_checkpoint( - &self, - checkpoint: VerifiedCheckpoint, - contents: CheckpointContents, - epoch_store: &AuthorityPerEpochStore, - ) { - assert_eq!( - checkpoint.epoch(), - 0, - "can't call insert_genesis_checkpoint with a checkpoint not in epoch 0" - ); - assert_eq!( - *checkpoint.sequence_number(), - 0, - "can't call insert_genesis_checkpoint with a checkpoint that doesn't have a sequence number of 0" - ); - - // Only insert the genesis checkpoint if the DB is empty and doesn't have it - // already - if self - .get_checkpoint_by_digest(checkpoint.digest()) - .unwrap() - .is_none() - { - if epoch_store.epoch() == checkpoint.epoch { - epoch_store - .put_genesis_checkpoint_in_builder(checkpoint.data(), &contents) - .unwrap(); - } else { - debug!( - validator_epoch =% epoch_store.epoch(), - genesis_epoch =% checkpoint.epoch(), - "Not inserting checkpoint builder data for genesis checkpoint", - ); - } - self.insert_checkpoint_contents(contents).unwrap(); - self.insert_verified_checkpoint(&checkpoint).unwrap(); - self.update_highest_synced_checkpoint(&checkpoint).unwrap(); - } - } - - pub fn get_checkpoint_by_digest( - &self, - digest: &CheckpointDigest, - ) -> Result, TypedStoreError> { - self.checkpoint_by_digest - .get(digest) - .map(|maybe_checkpoint| maybe_checkpoint.map(|c| c.into())) - } - - pub fn get_checkpoint_by_sequence_number( - &self, - sequence_number: CheckpointSequenceNumber, - ) -> Result, TypedStoreError> { - self.certified_checkpoints - .get(&sequence_number) - .map(|maybe_checkpoint| maybe_checkpoint.map(|c| c.into())) - } - - pub fn get_locally_computed_checkpoint( - &self, - sequence_number: CheckpointSequenceNumber, - ) -> Result, TypedStoreError> { - self.locally_computed_checkpoints.get(&sequence_number) - } - - pub fn get_sequence_number_by_contents_digest( - &self, - digest: &CheckpointContentsDigest, - ) -> Result, TypedStoreError> { - self.checkpoint_sequence_by_contents_digest.get(digest) - } - - pub fn delete_contents_digest_sequence_number_mapping( - &self, - digest: &CheckpointContentsDigest, - ) -> Result<(), TypedStoreError> { - self.checkpoint_sequence_by_contents_digest.remove(digest) - } - - pub fn get_latest_certified_checkpoint(&self) -> Option { - self.certified_checkpoints - .unbounded_iter() - .skip_to_last() - .next() - .map(|(_, v)| v.into()) - } - - pub fn get_latest_locally_computed_checkpoint(&self) -> Option { - self.locally_computed_checkpoints - .unbounded_iter() - .skip_to_last() - .next() - .map(|(_, v)| v) - } - - pub fn multi_get_checkpoint_by_sequence_number( - &self, - sequence_numbers: &[CheckpointSequenceNumber], - ) -> Result>, TypedStoreError> { - let checkpoints = self - .certified_checkpoints - .multi_get(sequence_numbers)? - .into_iter() - .map(|maybe_checkpoint| maybe_checkpoint.map(|c| c.into())) - .collect(); - - Ok(checkpoints) - } - - pub fn multi_get_checkpoint_content( - &self, - contents_digest: &[CheckpointContentsDigest], - ) -> Result>, TypedStoreError> { - self.checkpoint_content.multi_get(contents_digest) - } - - pub fn get_highest_verified_checkpoint( - &self, - ) -> Result, TypedStoreError> { - let highest_verified = if let Some(highest_verified) = - self.watermarks.get(&CheckpointWatermark::HighestVerified)? - { - highest_verified - } else { - return Ok(None); - }; - self.get_checkpoint_by_digest(&highest_verified.1) - } - - pub fn get_highest_synced_checkpoint( - &self, - ) -> Result, TypedStoreError> { - let highest_synced = if let Some(highest_synced) = - self.watermarks.get(&CheckpointWatermark::HighestSynced)? - { - highest_synced - } else { - return Ok(None); - }; - self.get_checkpoint_by_digest(&highest_synced.1) - } - - pub fn get_highest_executed_checkpoint_seq_number( - &self, - ) -> Result, TypedStoreError> { - if let Some(highest_executed) = - self.watermarks.get(&CheckpointWatermark::HighestExecuted)? - { - Ok(Some(highest_executed.0)) - } else { - Ok(None) - } - } - - pub fn get_highest_executed_checkpoint( - &self, - ) -> Result, TypedStoreError> { - let highest_executed = if let Some(highest_executed) = - self.watermarks.get(&CheckpointWatermark::HighestExecuted)? - { - highest_executed - } else { - return Ok(None); - }; - self.get_checkpoint_by_digest(&highest_executed.1) - } - - pub fn get_highest_pruned_checkpoint_seq_number( - &self, - ) -> Result { - Ok(self - .watermarks - .get(&CheckpointWatermark::HighestPruned)? - .unwrap_or_default() - .0) - } - - pub fn get_checkpoint_contents( - &self, - digest: &CheckpointContentsDigest, - ) -> Result, TypedStoreError> { - self.checkpoint_content.get(digest) - } - - pub fn get_full_checkpoint_contents_by_sequence_number( - &self, - seq: CheckpointSequenceNumber, - ) -> Result, TypedStoreError> { - self.full_checkpoint_content.get(&seq) - } - - fn prune_local_summaries(&self) -> SuiResult { - if let Some((last_local_summary, _)) = self - .locally_computed_checkpoints - .unbounded_iter() - .skip_to_last() - .next() - { - let mut batch = self.locally_computed_checkpoints.batch(); - batch.schedule_delete_range( - &self.locally_computed_checkpoints, - &0, - &last_local_summary, - )?; - batch.write()?; - info!("Pruned local summaries up to {:?}", last_local_summary); - } - Ok(()) - } - - fn check_for_checkpoint_fork( - &self, - local_checkpoint: &CheckpointSummary, - verified_checkpoint: &VerifiedCheckpoint, - ) { - if local_checkpoint != verified_checkpoint.data() { - let verified_contents = self - .get_checkpoint_contents(&verified_checkpoint.content_digest) - .map(|opt_contents| { - opt_contents - .map(|contents| format!("{:?}", contents)) - .unwrap_or_else(|| { - format!( - "Verified checkpoint contents not found, digest: {:?}", - verified_checkpoint.content_digest, - ) - }) - }) - .map_err(|e| { - format!( - "Failed to get verified checkpoint contents, digest: {:?} error: {:?}", - verified_checkpoint.content_digest, e - ) - }) - .unwrap_or_else(|err_msg| err_msg); - - let local_contents = self - .get_checkpoint_contents(&local_checkpoint.content_digest) - .map(|opt_contents| { - opt_contents - .map(|contents| format!("{:?}", contents)) - .unwrap_or_else(|| { - format!( - "Local checkpoint contents not found, digest: {:?}", - local_checkpoint.content_digest - ) - }) - }) - .map_err(|e| { - format!( - "Failed to get local checkpoint contents, digest: {:?} error: {:?}", - local_checkpoint.content_digest, e - ) - }) - .unwrap_or_else(|err_msg| err_msg); - - // checkpoint contents may be too large for panic message. - error!( - verified_checkpoint = ?verified_checkpoint.data(), - ?verified_contents, - ?local_checkpoint, - ?local_contents, - "Local checkpoint fork detected!", - ); - panic!( - "Local checkpoint fork detected for sequence number: {}", - local_checkpoint.sequence_number() - ); - } - } - - // Called by consensus (ConsensusAggregator). - // Different from `insert_verified_checkpoint`, it does not touch - // the highest_verified_checkpoint watermark such that state sync - // will have a chance to process this checkpoint and perform some - // state-sync only things. - pub fn insert_certified_checkpoint( - &self, - checkpoint: &VerifiedCheckpoint, - ) -> Result<(), TypedStoreError> { - debug!( - checkpoint_seq = checkpoint.sequence_number(), - "Inserting certified checkpoint", - ); - let mut batch = self.certified_checkpoints.batch(); - batch - .insert_batch( - &self.certified_checkpoints, - [(checkpoint.sequence_number(), checkpoint.serializable_ref())], - )? - .insert_batch( - &self.checkpoint_by_digest, - [(checkpoint.digest(), checkpoint.serializable_ref())], - )?; - if checkpoint.next_epoch_committee().is_some() { - batch.insert_batch( - &self.epoch_last_checkpoint_map, - [(&checkpoint.epoch(), checkpoint.sequence_number())], - )?; - } - batch.write()?; - - if let Some(local_checkpoint) = self - .locally_computed_checkpoints - .get(checkpoint.sequence_number())? - { - self.check_for_checkpoint_fork(&local_checkpoint, checkpoint); - } - - Ok(()) - } - - // Called by state sync, apart from inserting the checkpoint and updating - // related tables, it also bumps the highest_verified_checkpoint watermark. - #[instrument(level = "debug", skip_all)] - pub fn insert_verified_checkpoint( - &self, - checkpoint: &VerifiedCheckpoint, - ) -> Result<(), TypedStoreError> { - self.insert_certified_checkpoint(checkpoint)?; - self.update_highest_verified_checkpoint(checkpoint) - } - - pub fn update_highest_verified_checkpoint( - &self, - checkpoint: &VerifiedCheckpoint, - ) -> Result<(), TypedStoreError> { - if Some(*checkpoint.sequence_number()) - > self - .get_highest_verified_checkpoint()? - .map(|x| *x.sequence_number()) - { - debug!( - checkpoint_seq = checkpoint.sequence_number(), - "Updating highest verified checkpoint", - ); - self.watermarks.insert( - &CheckpointWatermark::HighestVerified, - &(*checkpoint.sequence_number(), *checkpoint.digest()), - )?; - } - - Ok(()) - } - - pub fn update_highest_synced_checkpoint( - &self, - checkpoint: &VerifiedCheckpoint, - ) -> Result<(), TypedStoreError> { - debug!( - checkpoint_seq = checkpoint.sequence_number(), - "Updating highest synced checkpoint", - ); - self.watermarks.insert( - &CheckpointWatermark::HighestSynced, - &(*checkpoint.sequence_number(), *checkpoint.digest()), - ) - } - - pub fn update_highest_executed_checkpoint( - &self, - checkpoint: &VerifiedCheckpoint, - ) -> Result<(), TypedStoreError> { - if let Some(seq_number) = self.get_highest_executed_checkpoint_seq_number()? { - if seq_number >= *checkpoint.sequence_number() { - return Ok(()); - } - assert_eq!( - seq_number + 1, - *checkpoint.sequence_number(), - "Cannot update highest executed checkpoint to {} when current highest executed checkpoint is {}", - checkpoint.sequence_number(), - seq_number - ); - } - debug!( - checkpoint_seq = checkpoint.sequence_number(), - "Updating highest executed checkpoint", - ); - self.watermarks.insert( - &CheckpointWatermark::HighestExecuted, - &(*checkpoint.sequence_number(), *checkpoint.digest()), - ) - } - - pub fn update_highest_pruned_checkpoint( - &self, - checkpoint: &VerifiedCheckpoint, - ) -> Result<(), TypedStoreError> { - self.watermarks.insert( - &CheckpointWatermark::HighestPruned, - &(*checkpoint.sequence_number(), *checkpoint.digest()), - ) - } - - /// Sets highest executed checkpoint to any value. - /// - /// WARNING: This method is very subtle and can corrupt the database if used - /// incorrectly. It should only be used in one-off cases or tests after - /// fully understanding the risk. - pub fn set_highest_executed_checkpoint_subtle( - &self, - checkpoint: &VerifiedCheckpoint, - ) -> Result<(), TypedStoreError> { - self.watermarks.insert( - &CheckpointWatermark::HighestExecuted, - &(*checkpoint.sequence_number(), *checkpoint.digest()), - ) - } - - pub fn insert_checkpoint_contents( - &self, - contents: CheckpointContents, - ) -> Result<(), TypedStoreError> { - debug!( - checkpoint_seq = ?contents.digest(), - "Inserting checkpoint contents", - ); - self.checkpoint_content.insert(contents.digest(), &contents) - } - - pub fn insert_verified_checkpoint_contents( - &self, - checkpoint: &VerifiedCheckpoint, - full_contents: VerifiedCheckpointContents, - ) -> Result<(), TypedStoreError> { - let mut batch = self.full_checkpoint_content.batch(); - batch.insert_batch( - &self.checkpoint_sequence_by_contents_digest, - [(&checkpoint.content_digest, checkpoint.sequence_number())], - )?; - let full_contents = full_contents.into_inner(); - batch.insert_batch( - &self.full_checkpoint_content, - [(checkpoint.sequence_number(), &full_contents)], - )?; - - let contents = full_contents.into_checkpoint_contents(); - assert_eq!(&checkpoint.content_digest, contents.digest()); - - batch.insert_batch(&self.checkpoint_content, [(contents.digest(), &contents)])?; - - batch.write() - } - - pub fn delete_full_checkpoint_contents( - &self, - seq: CheckpointSequenceNumber, - ) -> Result<(), TypedStoreError> { - self.full_checkpoint_content.remove(&seq) - } - - pub fn get_epoch_last_checkpoint( - &self, - epoch_id: EpochId, - ) -> SuiResult> { - let seq = self.epoch_last_checkpoint_map.get(&epoch_id)?; - let checkpoint = match seq { - Some(seq) => self.get_checkpoint_by_sequence_number(seq)?, - None => None, - }; - Ok(checkpoint) - } - - pub fn insert_epoch_last_checkpoint( - &self, - epoch_id: EpochId, - checkpoint: &VerifiedCheckpoint, - ) -> SuiResult { - self.epoch_last_checkpoint_map - .insert(&epoch_id, checkpoint.sequence_number())?; - Ok(()) - } - - /// Given the epoch ID, and the last checkpoint of the epoch, derive a few - /// statistics of the epoch. - pub fn get_epoch_stats( - &self, - epoch: EpochId, - last_checkpoint: &CheckpointSummary, - ) -> Option { - let (first_checkpoint, prev_epoch_network_transactions) = if epoch == 0 { - (0, 0) - } else if let Ok(Some(checkpoint)) = self.get_epoch_last_checkpoint(epoch - 1) { - ( - checkpoint.sequence_number + 1, - checkpoint.network_total_transactions, - ) - } else { - return None; - }; - Some(EpochStats { - checkpoint_count: last_checkpoint.sequence_number - first_checkpoint + 1, - transaction_count: last_checkpoint.network_total_transactions - - prev_epoch_network_transactions, - total_gas_reward: last_checkpoint - .epoch_rolling_gas_cost_summary - .computation_cost, - }) - } - - pub fn checkpoint_db(&self, path: &Path) -> SuiResult { - // This checkpoints the entire db and not one column family - self.checkpoint_content - .checkpoint_db(path) - .map_err(Into::into) - } - - pub fn delete_highest_executed_checkpoint_test_only(&self) -> Result<(), TypedStoreError> { - let mut wb = self.watermarks.batch(); - wb.delete_batch( - &self.watermarks, - std::iter::once(CheckpointWatermark::HighestExecuted), - )?; - wb.write()?; - Ok(()) - } - - pub fn reset_db_for_execution_since_genesis(&self) -> SuiResult { - self.delete_highest_executed_checkpoint_test_only()?; - self.watermarks.rocksdb.flush()?; - Ok(()) - } -} - -#[derive(Copy, Clone, Debug, Serialize, Deserialize)] -pub enum CheckpointWatermark { - HighestVerified, - HighestSynced, - HighestExecuted, - HighestPruned, -} - -pub struct CheckpointBuilder { - state: Arc, - tables: Arc, - epoch_store: Arc, - notify: Arc, - notify_aggregator: Arc, - effects_store: Arc, - accumulator: Arc, - output: Box, - exit: watch::Receiver<()>, - metrics: Arc, - max_transactions_per_checkpoint: usize, - max_checkpoint_size_bytes: usize, -} - -pub struct CheckpointAggregator { - tables: Arc, - epoch_store: Arc, - notify: Arc, - exit: watch::Receiver<()>, - current: Option, - output: Box, - state: Arc, - metrics: Arc, -} - -// This holds information to aggregate signatures for one checkpoint -pub struct CheckpointSignatureAggregator { - next_index: u64, - summary: CheckpointSummary, - digest: CheckpointDigest, - /// Aggregates voting stake for each signed checkpoint proposal by authority - signatures_by_digest: MultiStakeAggregator, - tables: Arc, - state: Arc, - metrics: Arc, -} - -impl CheckpointBuilder { - fn new( - state: Arc, - tables: Arc, - epoch_store: Arc, - notify: Arc, - effects_store: Arc, - accumulator: Arc, - output: Box, - exit: watch::Receiver<()>, - notify_aggregator: Arc, - metrics: Arc, - max_transactions_per_checkpoint: usize, - max_checkpoint_size_bytes: usize, - ) -> Self { - Self { - state, - tables, - epoch_store, - notify, - effects_store, - accumulator, - output, - exit, - notify_aggregator, - metrics, - max_transactions_per_checkpoint, - max_checkpoint_size_bytes, - } - } - - async fn run(mut self) { - info!("Starting CheckpointBuilder"); - 'main: loop { - // Check whether an exit signal has been received, if so we break the loop. - // This gives us a chance to exit, in case checkpoint making keeps failing. - match self.exit.has_changed() { - Ok(true) | Err(_) => { - break; - } - Ok(false) => (), - }; - let mut last = self - .epoch_store - .last_built_checkpoint_commit_height() - .expect("epoch should not have ended"); - for (height, pending) in self - .epoch_store - .get_pending_checkpoints(last) - .expect("unexpected epoch store error") - { - last = Some(height); - debug!( - checkpoint_commit_height = height, - "Making checkpoint at commit height" - ); - if let Err(e) = self.make_checkpoint(height, pending).await { - error!("Error while making checkpoint, will retry in 1s: {:?}", e); - tokio::time::sleep(Duration::from_secs(1)).await; - self.metrics.checkpoint_errors.inc(); - continue 'main; - } - } - debug!("Waiting for more checkpoints from consensus after processing {last:?}"); - match select(self.exit.changed().boxed(), self.notify.notified().boxed()).await { - Either::Left(_) => { - // break loop on exit signal - break; - } - Either::Right(_) => {} - } - } - info!("Shutting down CheckpointBuilder"); - } - - #[instrument(level = "debug", skip_all, fields(?height))] - async fn make_checkpoint( - &self, - height: CheckpointHeight, - pending: PendingCheckpointV2, - ) -> anyhow::Result<()> { - let pending = pending.into_v2(); - self.metrics - .checkpoint_roots_count - .inc_by(pending.roots.len() as u64); - - let root_digests = self - .epoch_store - .notify_read_executed_digests(&pending.roots) - .in_monitored_scope("CheckpointNotifyDigests") - .await?; - let root_effects = self - .effects_store - .notify_read_executed_effects(root_digests) - .in_monitored_scope("CheckpointNotifyRead") - .await?; - - let _scope = monitored_scope("CheckpointBuilder"); - let unsorted = self.complete_checkpoint_effects(root_effects)?; - let sorted = { - let _scope = monitored_scope("CheckpointBuilder::causal_sort"); - CausalOrder::causal_sort(unsorted) - }; - let new_checkpoint = self.create_checkpoints(sorted, pending.details).await?; - self.write_checkpoints(height, new_checkpoint).await?; - Ok(()) - } - - #[instrument(level = "debug", skip_all)] - async fn write_checkpoints( - &self, - height: CheckpointHeight, - new_checkpoint: Vec<(CheckpointSummary, CheckpointContents)>, - ) -> SuiResult { - let _scope = monitored_scope("CheckpointBuilder::write_checkpoints"); - let mut batch = self.tables.checkpoint_content.batch(); - for (summary, contents) in &new_checkpoint { - debug!( - checkpoint_commit_height = height, - checkpoint_seq = summary.sequence_number, - contents_digest = ?contents.digest(), - "writing checkpoint", - ); - self.output - .checkpoint_created(summary, contents, &self.epoch_store) - .await?; - - self.metrics - .transactions_included_in_checkpoint - .inc_by(contents.size() as u64); - let sequence_number = summary.sequence_number; - self.metrics - .last_constructed_checkpoint - .set(sequence_number as i64); - - batch.insert_batch( - &self.tables.checkpoint_content, - [(contents.digest(), contents)], - )?; - - batch.insert_batch( - &self.tables.locally_computed_checkpoints, - [(sequence_number, summary)], - )?; - } - batch.write()?; - - for (local_checkpoint, _) in &new_checkpoint { - if let Some(certified_checkpoint) = self - .tables - .certified_checkpoints - .get(local_checkpoint.sequence_number())? - { - self.tables - .check_for_checkpoint_fork(local_checkpoint, &certified_checkpoint.into()); - } - } - - self.notify_aggregator.notify_one(); - self.epoch_store - .process_pending_checkpoint(height, new_checkpoint)?; - Ok(()) - } - - #[allow(clippy::type_complexity)] - fn split_checkpoint_chunks( - &self, - effects_and_transaction_sizes: Vec<(TransactionEffects, usize)>, - signatures: Vec>, - ) -> anyhow::Result)>>> { - let _guard = monitored_scope("CheckpointBuilder::split_checkpoint_chunks"); - let mut chunks = Vec::new(); - let mut chunk = Vec::new(); - let mut chunk_size: usize = 0; - for ((effects, transaction_size), signatures) in effects_and_transaction_sizes - .into_iter() - .zip(signatures.into_iter()) - { - // Roll over to a new chunk after either max count or max size is reached. - // The size calculation here is intended to estimate the size of the - // FullCheckpointContents struct. If this code is modified, that struct - // should also be updated accordingly. - let size = transaction_size - + bcs::serialized_size(&effects)? - + bcs::serialized_size(&signatures)?; - if chunk.len() == self.max_transactions_per_checkpoint - || (chunk_size + size) > self.max_checkpoint_size_bytes - { - if chunk.is_empty() { - // Always allow at least one tx in a checkpoint. - warn!( - "Size of single transaction ({size}) exceeds max checkpoint size ({}); allowing excessively large checkpoint to go through.", - self.max_checkpoint_size_bytes - ); - } else { - chunks.push(chunk); - chunk = Vec::new(); - chunk_size = 0; - } - } - - chunk.push((effects, signatures)); - chunk_size += size; - } - - if !chunk.is_empty() || chunks.is_empty() { - // We intentionally create an empty checkpoint if there is no content provided - // to make a 'heartbeat' checkpoint. - // Important: if some conditions are added here later, we need to make sure we - // always have at least one chunk if last_pending_of_epoch is set - chunks.push(chunk); - // Note: empty checkpoints are ok - they shouldn't happen at all on - // a network with even modest load. Even if they do - // happen, it is still useful as it allows fullnodes to - // distinguish between "no transactions have happened" and "i am not - // receiving new checkpoints". - } - Ok(chunks) - } - - #[instrument(level = "debug", skip_all)] - async fn create_checkpoints( - &self, - all_effects: Vec, - details: PendingCheckpointInfo, - ) -> anyhow::Result> { - let _scope = monitored_scope("CheckpointBuilder::create_checkpoints"); - let total = all_effects.len(); - let mut last_checkpoint = self.epoch_store.last_built_checkpoint_summary()?; - if last_checkpoint.is_none() { - let epoch = self.epoch_store.epoch(); - if epoch > 0 { - let previous_epoch = epoch - 1; - let last_verified = self.tables.get_epoch_last_checkpoint(previous_epoch)?; - last_checkpoint = last_verified.map(VerifiedCheckpoint::into_summary_and_sequence); - if let Some((ref seq, _)) = last_checkpoint { - debug!( - "No checkpoints in builder DB, taking checkpoint from previous epoch with sequence {seq}" - ); - } else { - // This is some serious bug with when CheckpointBuilder started so surfacing it - // via panic - panic!("Can not find last checkpoint for previous epoch {previous_epoch}"); - } - } - } - let last_checkpoint_seq = last_checkpoint.as_ref().map(|(seq, _)| *seq); - info!( - next_checkpoint_seq = last_checkpoint_seq.unwrap_or_default() + 1, - checkpoint_timestamp = details.timestamp_ms, - "Creating checkpoint(s) for {} transactions", - all_effects.len(), - ); - - let all_digests: Vec<_> = all_effects - .iter() - .map(|effect| *effect.transaction_digest()) - .collect(); - let transactions_and_sizes = self - .state - .get_cache_reader() - .get_transactions_and_serialized_sizes(&all_digests)?; - let mut all_effects_and_transaction_sizes = Vec::with_capacity(all_effects.len()); - let mut transactions = Vec::with_capacity(all_effects.len()); - let mut transaction_keys = Vec::with_capacity(all_effects.len()); - { - let _guard = monitored_scope("CheckpointBuilder::wait_for_transactions_sequenced"); - debug!( - ?last_checkpoint_seq, - "Waiting for {:?} certificates to appear in consensus", - all_effects_and_transaction_sizes.len() - ); - - for (effects, transaction_and_size) in all_effects - .into_iter() - .zip(transactions_and_sizes.into_iter()) - { - let (transaction, size) = transaction_and_size - .unwrap_or_else(|| panic!("Could not find executed transaction {:?}", effects)); - // ConsensusCommitPrologue and AuthenticatorStateUpdate are guaranteed to be - // processed before we reach here - if !matches!( - transaction.inner().transaction_data().kind(), - TransactionKind::ConsensusCommitPrologue(_) - | TransactionKind::ConsensusCommitPrologueV2(_) - | TransactionKind::AuthenticatorStateUpdate(_) - | TransactionKind::RandomnessStateUpdate(_) - ) { - transaction_keys.push(SequencedConsensusTransactionKey::External( - ConsensusTransactionKey::Certificate(*effects.transaction_digest()), - )); - } - transactions.push(transaction); - all_effects_and_transaction_sizes.push((effects, size)); - } - - self.epoch_store - .consensus_messages_processed_notify(transaction_keys) - .await?; - } - - let signatures = self - .epoch_store - .user_signatures_for_checkpoint(&transactions, &all_digests)?; - debug!( - ?last_checkpoint_seq, - "Received {} checkpoint user signatures from consensus", - signatures.len() - ); - - let chunks = self.split_checkpoint_chunks(all_effects_and_transaction_sizes, signatures)?; - let chunks_count = chunks.len(); - - let mut checkpoints = Vec::with_capacity(chunks_count); - debug!( - ?last_checkpoint_seq, - "Creating {} checkpoints with {} transactions", chunks_count, total, - ); - - let epoch = self.epoch_store.epoch(); - for (index, transactions) in chunks.into_iter().enumerate() { - let first_checkpoint_of_epoch = index == 0 - && last_checkpoint - .as_ref() - .map(|(_, c)| c.epoch != epoch) - .unwrap_or(true); - if first_checkpoint_of_epoch { - self.epoch_store - .record_epoch_first_checkpoint_creation_time_metric(); - } - let last_checkpoint_of_epoch = details.last_of_epoch && index == chunks_count - 1; - - let sequence_number = last_checkpoint - .as_ref() - .map(|(_, c)| c.sequence_number + 1) - .unwrap_or_default(); - let timestamp_ms = details.timestamp_ms; - if let Some((_, last_checkpoint)) = &last_checkpoint { - if last_checkpoint.timestamp_ms > timestamp_ms { - error!( - "Unexpected decrease of checkpoint timestamp, sequence: {}, previous: {}, current: {}", - sequence_number, last_checkpoint.timestamp_ms, timestamp_ms - ); - } - } - - let (mut effects, mut signatures): (Vec<_>, Vec<_>) = transactions.into_iter().unzip(); - let epoch_rolling_gas_cost_summary = - self.get_epoch_total_gas_cost(last_checkpoint.as_ref().map(|(_, c)| c), &effects); - - let end_of_epoch_data = if last_checkpoint_of_epoch { - let system_state_obj = self - .augment_epoch_last_checkpoint( - &epoch_rolling_gas_cost_summary, - timestamp_ms, - &mut effects, - &mut signatures, - sequence_number, - ) - .await?; - - let committee = system_state_obj.get_current_epoch_committee().committee; - - // This must happen after the call to augment_epoch_last_checkpoint, - // otherwise we will not capture the change_epoch tx - self.accumulator.accumulate_checkpoint( - effects.clone(), - sequence_number, - self.epoch_store.clone(), - )?; - - let root_state_digest = self - .accumulator - .digest_epoch(&epoch, sequence_number, self.epoch_store.clone()) - .in_monitored_scope("CheckpointBuilder::digest_epoch") - .await?; - self.metrics.highest_accumulated_epoch.set(epoch as i64); - info!("Epoch {epoch} root state hash digest: {root_state_digest:?}"); - - let epoch_commitments = if self - .epoch_store - .protocol_config() - .check_commit_root_state_digest_supported() - { - vec![root_state_digest.into()] - } else { - vec![] - }; - - Some(EndOfEpochData { - next_epoch_committee: committee.voting_rights, - next_epoch_protocol_version: ProtocolVersion::new( - system_state_obj.protocol_version(), - ), - epoch_commitments, - }) - } else { - None - }; - - let contents = CheckpointContents::new_with_digests_and_signatures( - effects.iter().map(TransactionEffects::execution_digests), - signatures, - ); - - let num_txns = contents.size() as u64; - - let network_total_transactions = last_checkpoint - .as_ref() - .map(|(_, c)| c.network_total_transactions + num_txns) - .unwrap_or(num_txns); - - let previous_digest = last_checkpoint.as_ref().map(|(_, c)| c.digest()); - let summary = CheckpointSummary::new( - epoch, - sequence_number, - network_total_transactions, - &contents, - previous_digest, - epoch_rolling_gas_cost_summary, - end_of_epoch_data, - timestamp_ms, - ); - summary.report_checkpoint_age_ms(&self.metrics.last_created_checkpoint_age_ms); - if last_checkpoint_of_epoch { - info!( - checkpoint_seq = sequence_number, - "creating last checkpoint of epoch {}", epoch - ); - if let Some(stats) = self.tables.get_epoch_stats(epoch, &summary) { - self.epoch_store - .report_epoch_metrics_at_last_checkpoint(stats); - } - } - last_checkpoint = Some((sequence_number, summary.clone())); - checkpoints.push((summary, contents)); - } - - Ok(checkpoints) - } - - fn get_epoch_total_gas_cost( - &self, - last_checkpoint: Option<&CheckpointSummary>, - cur_checkpoint_effects: &[TransactionEffects], - ) -> GasCostSummary { - let (previous_epoch, previous_gas_costs) = last_checkpoint - .map(|c| (c.epoch, c.epoch_rolling_gas_cost_summary.clone())) - .unwrap_or_default(); - let current_gas_costs = GasCostSummary::new_from_txn_effects(cur_checkpoint_effects.iter()); - if previous_epoch == self.epoch_store.epoch() { - // sum only when we are within the same epoch - GasCostSummary::new( - previous_gas_costs.computation_cost + current_gas_costs.computation_cost, - previous_gas_costs.storage_cost + current_gas_costs.storage_cost, - previous_gas_costs.storage_rebate + current_gas_costs.storage_rebate, - previous_gas_costs.non_refundable_storage_fee - + current_gas_costs.non_refundable_storage_fee, - ) - } else { - current_gas_costs - } - } - - #[instrument(level = "error", skip_all)] - async fn augment_epoch_last_checkpoint( - &self, - epoch_total_gas_cost: &GasCostSummary, - epoch_start_timestamp_ms: CheckpointTimestamp, - checkpoint_effects: &mut Vec, - signatures: &mut Vec>, - checkpoint: CheckpointSequenceNumber, - // TODO: Check whether we must use anyhow::Result or can we use SuiResult. - ) -> anyhow::Result { - let (system_state, effects) = self - .state - .create_and_execute_advance_epoch_tx( - &self.epoch_store, - epoch_total_gas_cost, - checkpoint, - epoch_start_timestamp_ms, - ) - .await?; - checkpoint_effects.push(effects); - signatures.push(vec![]); - Ok(system_state) - } - - /// For the given roots return complete list of effects to include in - /// checkpoint This list includes the roots and all their dependencies, - /// which are not part of checkpoint already - #[instrument(level = "debug", skip_all)] - fn complete_checkpoint_effects( - &self, - mut roots: Vec, - ) -> SuiResult> { - let _scope = monitored_scope("CheckpointBuilder::complete_checkpoint_effects"); - let mut results = vec![]; - let mut seen = HashSet::new(); - loop { - let mut pending = HashSet::new(); - - let transactions_included = self - .epoch_store - .builder_included_transactions_in_checkpoint( - roots.iter().map(|e| e.transaction_digest()), - )?; - - for (effect, tx_included) in roots.into_iter().zip(transactions_included.into_iter()) { - let digest = effect.transaction_digest(); - // Unnecessary to read effects of a dependency if the effect is already - // processed. - seen.insert(*digest); - - // Skip roots already included in checkpoints or roots from previous epochs - if tx_included || effect.executed_epoch() < self.epoch_store.epoch() { - continue; - } - - let existing_effects = self - .epoch_store - .effects_signatures_exists(effect.dependencies().iter())?; - - for (dependency, effects_signature_exists) in - effect.dependencies().iter().zip(existing_effects.iter()) - { - // Skip here if dependency not executed in the current epoch. - // Note that the existence of an effects signature in the - // epoch store for the given digest indicates that the transaction - // was locally executed in the current epoch - if !effects_signature_exists { - continue; - } - if seen.insert(*dependency) { - pending.insert(*dependency); - } - } - results.push(effect); - } - if pending.is_empty() { - break; - } - let pending = pending.into_iter().collect::>(); - let effects = self.effects_store.multi_get_executed_effects(&pending)?; - let effects = effects - .into_iter() - .zip(pending) - .map(|(opt, digest)| match opt { - Some(x) => x, - None => panic!( - "Can not find effect for transaction {:?}, however transaction that depend on it was already executed", - digest - ), - }) - .collect::>(); - roots = effects; - } - Ok(results) - } -} - -impl CheckpointAggregator { - fn new( - tables: Arc, - epoch_store: Arc, - notify: Arc, - exit: watch::Receiver<()>, - output: Box, - state: Arc, - metrics: Arc, - ) -> Self { - let current = None; - Self { - tables, - epoch_store, - notify, - exit, - current, - output, - state, - metrics, - } - } - - async fn run(mut self) { - info!("Starting CheckpointAggregator"); - loop { - if let Err(e) = self.run_and_notify().await { - error!( - "Error while aggregating checkpoint, will retry in 1s: {:?}", - e - ); - self.metrics.checkpoint_errors.inc(); - tokio::time::sleep(Duration::from_secs(1)).await; - continue; - } - - match select( - self.exit.changed().boxed(), - timeout(Duration::from_secs(1), self.notify.notified()).boxed(), - ) - .await - { - Either::Left(_) => { - // return on exit signal - info!("Shutting down CheckpointAggregator"); - return; - } - Either::Right(_) => {} - } - } - } - - async fn run_and_notify(&mut self) -> SuiResult { - let summaries = self.run_inner()?; - for summary in summaries { - self.output.certified_checkpoint_created(&summary).await?; - } - Ok(()) - } - - fn run_inner(&mut self) -> SuiResult> { - let _scope = monitored_scope("CheckpointAggregator"); - let mut result = vec![]; - 'outer: loop { - let next_to_certify = self.next_checkpoint_to_certify(); - let current = if let Some(current) = &mut self.current { - // It's possible that the checkpoint was already certified by - // the rest of the network and we've already received the - // certified checkpoint via StateSync. In this case, we reset - // the current signature aggregator to the next checkpoint to - // be certified - if current.summary.sequence_number < next_to_certify { - self.current = None; - continue; - } - current - } else { - let Some(summary) = self - .epoch_store - .get_built_checkpoint_summary(next_to_certify)? - else { - return Ok(result); - }; - self.current = Some(CheckpointSignatureAggregator { - next_index: 0, - digest: summary.digest(), - summary, - signatures_by_digest: MultiStakeAggregator::new( - self.epoch_store.committee().clone(), - ), - tables: self.tables.clone(), - state: self.state.clone(), - metrics: self.metrics.clone(), - }); - self.current.as_mut().unwrap() - }; - - let epoch_tables = self - .epoch_store - .tables() - .expect("should not run past end of epoch"); - let iter = epoch_tables.get_pending_checkpoint_signatures_iter( - current.summary.sequence_number, - current.next_index, - )?; - for ((seq, index), data) in iter { - if seq != current.summary.sequence_number { - debug!( - checkpoint_seq =? current.summary.sequence_number, - "Not enough checkpoint signatures", - ); - // No more signatures (yet) for this checkpoint - return Ok(result); - } - debug!( - checkpoint_seq = current.summary.sequence_number, - "Processing signature for checkpoint (digest: {:?}) from {:?}", - current.summary.digest(), - data.summary.auth_sig().authority.concise() - ); - self.metrics - .checkpoint_participation - .with_label_values(&[&format!( - "{:?}", - data.summary.auth_sig().authority.concise() - )]) - .inc(); - if let Ok(auth_signature) = current.try_aggregate(data) { - let summary = VerifiedCheckpoint::new_unchecked( - CertifiedCheckpointSummary::new_from_data_and_sig( - current.summary.clone(), - auth_signature, - ), - ); - - self.tables.insert_certified_checkpoint(&summary)?; - self.metrics - .last_certified_checkpoint - .set(current.summary.sequence_number as i64); - current - .summary - .report_checkpoint_age_ms(&self.metrics.last_certified_checkpoint_age_ms); - result.push(summary.into_inner()); - self.current = None; - continue 'outer; - } else { - current.next_index = index + 1; - } - } - break; - } - Ok(result) - } - - fn next_checkpoint_to_certify(&self) -> CheckpointSequenceNumber { - self.tables - .certified_checkpoints - .unbounded_iter() - .skip_to_last() - .next() - .map(|(seq, _)| seq + 1) - .unwrap_or_default() - } -} - -impl CheckpointSignatureAggregator { - #[allow(clippy::result_unit_err)] - pub fn try_aggregate( - &mut self, - data: CheckpointSignatureMessage, - ) -> Result { - let their_digest = *data.summary.digest(); - let (_, signature) = data.summary.into_data_and_sig(); - let author = signature.authority; - let envelope = - SignedCheckpointSummary::new_from_data_and_sig(self.summary.clone(), signature); - match self.signatures_by_digest.insert(their_digest, envelope) { - InsertResult::Failed { error } => { - warn!( - checkpoint_seq = self.summary.sequence_number, - "Failed to aggregate new signature from validator {:?}: {:?}", - author.concise(), - error - ); - self.check_for_split_brain(); - Err(()) - } - InsertResult::QuorumReached(cert) => { - // It is not guaranteed that signature.authority == narwhal_cert.author, but we - // do verify the signature so we know that the author signed the - // message at some point. - if their_digest != self.digest { - self.metrics.remote_checkpoint_forks.inc(); - warn!( - checkpoint_seq = self.summary.sequence_number, - "Validator {:?} has mismatching checkpoint digest {}, we have digest {}", - author.concise(), - their_digest, - self.digest - ); - return Err(()); - } - Ok(cert) - } - InsertResult::NotEnoughVotes { - bad_votes: _, - bad_authorities: _, - } => { - self.check_for_split_brain(); - Err(()) - } - } - } - - /// Check if there is a split brain condition in checkpoint signature - /// aggregation, defined as any state wherein it is no longer possible - /// to achieve quorum on a checkpoint proposal, irrespective of the - /// outcome of any outstanding votes. - fn check_for_split_brain(&self) { - debug!( - checkpoint_seq = self.summary.sequence_number, - "Checking for split brain condition" - ); - if self.signatures_by_digest.quorum_unreachable() { - // TODO: at this point we should immediately halt processing - // of new transaction certificates to avoid building on top of - // forked output - // self.halt_all_execution(); - - let digests_by_stake_messages = self - .signatures_by_digest - .get_all_unique_values() - .into_iter() - .sorted_by_key(|(_, (_, stake))| -(*stake as i64)) - .map(|(digest, (_authorities, total_stake))| { - format!("{:?} (total stake: {})", digest, total_stake) - }) - .collect::>(); - error!( - checkpoint_seq = self.summary.sequence_number, - "Split brain detected in checkpoint signature aggregation! Remaining stake: {:?}, Digests by stake: {:?}", - self.signatures_by_digest.uncommitted_stake(), - digests_by_stake_messages, - ); - self.metrics.split_brain_checkpoint_forks.inc(); - - let all_unique_values = self.signatures_by_digest.get_all_unique_values(); - let local_summary = self.summary.clone(); - let state = self.state.clone(); - let tables = self.tables.clone(); - - tokio::spawn(async move { - diagnose_split_brain(all_unique_values, local_summary, state, tables).await; - }); - } - } -} - -/// Create data dump containing relevant data for diagnosing cause of the -/// split brain by querying one disagreeing validator for full checkpoint -/// contents. To minimize peer chatter, we only query one validator at random -/// from each disagreeing faction, as all honest validators that participated in -/// this round may inevitably run the same process. -async fn diagnose_split_brain( - all_unique_values: BTreeMap, StakeUnit)>, - local_summary: CheckpointSummary, - state: Arc, - tables: Arc, -) { - debug!( - checkpoint_seq = local_summary.sequence_number, - "Running split brain diagnostics..." - ); - let time = Utc::now(); - // collect one random disagreeing validator per differing digest - let digest_to_validator = all_unique_values - .iter() - .filter_map(|(digest, (validators, _))| { - if *digest != local_summary.digest() { - let random_validator = validators.choose(&mut OsRng).unwrap(); - Some((*digest, *random_validator)) - } else { - None - } - }) - .collect::>(); - if digest_to_validator.is_empty() { - panic!( - "Given split brain condition, there should be at \ - least one validator that disagrees with local signature" - ); - } - - let epoch_store = state.load_epoch_store_one_call_per_task(); - let committee = epoch_store - .epoch_start_state() - .get_sui_committee_with_network_metadata(); - let network_config = default_mysten_network_config(); - let network_clients = - make_network_authority_clients_with_network_config(&committee, &network_config) - .expect("Failed to make authority clients from committee {committee}"); - - // Query all disagreeing validators - let response_futures = digest_to_validator - .values() - .cloned() - .map(|validator| { - let client = network_clients - .get(&validator) - .expect("Failed to get network client"); - let request = CheckpointRequestV2 { - sequence_number: Some(local_summary.sequence_number), - request_content: true, - certified: false, - }; - client.handle_checkpoint_v2(request) - }) - .collect::>(); - - let digest_name_pair = digest_to_validator.iter(); - let response_data = futures::future::join_all(response_futures) - .await - .into_iter() - .zip(digest_name_pair) - .filter_map(|(response, (digest, name))| match response { - Ok(response) => match response { - CheckpointResponseV2 { - checkpoint: Some(CheckpointSummaryResponse::Pending(summary)), - contents: Some(contents), - } => Some((*name, *digest, summary, contents)), - CheckpointResponseV2 { - checkpoint: Some(CheckpointSummaryResponse::Certified(_)), - contents: _, - } => { - panic!("Expected pending checkpoint, but got certified checkpoint"); - } - CheckpointResponseV2 { - checkpoint: None, - contents: _, - } => { - error!( - "Summary for checkpoint {:?} not found on validator {:?}", - local_summary.sequence_number, name - ); - None - } - CheckpointResponseV2 { - checkpoint: _, - contents: None, - } => { - error!( - "Contents for checkpoint {:?} not found on validator {:?}", - local_summary.sequence_number, name - ); - None - } - }, - Err(e) => { - error!( - "Failed to get checkpoint contents from validator for fork diagnostics: {:?}", - e - ); - None - } - }) - .collect::>(); - - let local_checkpoint_contents = tables - .get_checkpoint_contents(&local_summary.content_digest) - .unwrap_or_else(|_| { - panic!( - "Could not find checkpoint contents for digest {:?}", - local_summary.digest() - ) - }) - .unwrap_or_else(|| { - panic!( - "Could not find local full checkpoint contents for checkpoint {:?}, digest {:?}", - local_summary.sequence_number, - local_summary.digest() - ) - }); - let local_contents_text = format!("{local_checkpoint_contents:?}"); - - let local_summary_text = format!("{local_summary:?}"); - let local_validator = state.name.concise(); - let diff_patches = response_data - .iter() - .map(|(name, other_digest, other_summary, contents)| { - let other_contents_text = format!("{contents:?}"); - let other_summary_text = format!("{other_summary:?}"); - let (local_transactions, local_effects): (Vec<_>, Vec<_>) = local_checkpoint_contents - .enumerate_transactions(&local_summary) - .map(|(_, exec_digest)| (exec_digest.transaction, exec_digest.effects)) - .unzip(); - let (other_transactions, other_effects): (Vec<_>, Vec<_>) = contents - .enumerate_transactions(other_summary) - .map(|(_, exec_digest)| (exec_digest.transaction, exec_digest.effects)) - .unzip(); - let summary_patch = create_patch(&local_summary_text, &other_summary_text); - let contents_patch = create_patch(&local_contents_text, &other_contents_text); - let local_transactions_text = format!("{local_transactions:#?}"); - let other_transactions_text = format!("{other_transactions:#?}"); - let transactions_patch = - create_patch(&local_transactions_text, &other_transactions_text); - let local_effects_text = format!("{local_effects:#?}"); - let other_effects_text = format!("{other_effects:#?}"); - let effects_patch = create_patch(&local_effects_text, &other_effects_text); - let seq_number = local_summary.sequence_number; - let local_digest = local_summary.digest(); - let other_validator = name.concise(); - format!( - "Checkpoint: {seq_number:?}\n\ - Local validator (original): {local_validator:?}, digest: {local_digest:?}\n\ - Other validator (modified): {other_validator:?}, digest: {other_digest:?}\n\n\ - Summary Diff: \n{summary_patch}\n\n\ - Contents Diff: \n{contents_patch}\n\n\ - Transactions Diff: \n{transactions_patch}\n\n\ - Effects Diff: \n{effects_patch}", - ) - }) - .collect::>() - .join("\n\n\n"); - - let header = format!( - "Checkpoint Fork Dump - Authority {local_validator:?}: \n\ - Datetime: {time}", - ); - let fork_logs_text = format!("{header}\n\n{diff_patches}\n\n"); - let path = tempfile::tempdir() - .expect("Failed to create tempdir") - .into_path() - .join(Path::new("checkpoint_fork_dump.txt")); - let mut file = File::create(path).unwrap(); - write!(file, "{}", fork_logs_text).unwrap(); - debug!("{}", fork_logs_text); - - fail_point!("split_brain_reached"); -} - -pub trait CheckpointServiceNotify { - fn notify_checkpoint_signature( - &self, - epoch_store: &AuthorityPerEpochStore, - info: &CheckpointSignatureMessage, - ) -> SuiResult; - - fn notify_checkpoint(&self) -> SuiResult; -} - -/// This is a service used to communicate with other pieces of sui(for ex. -/// authority) -pub struct CheckpointService { - tables: Arc, - notify_builder: Arc, - notify_aggregator: Arc, - last_signature_index: Mutex, - metrics: Arc, -} - -impl CheckpointService { - pub fn spawn( - state: Arc, - checkpoint_store: Arc, - epoch_store: Arc, - effects_store: Arc, - accumulator: Arc, - checkpoint_output: Box, - certified_checkpoint_output: Box, - metrics: Arc, - max_transactions_per_checkpoint: usize, - max_checkpoint_size_bytes: usize, - ) -> (Arc, watch::Sender<()> /* The exit sender */) { - info!( - "Starting checkpoint service with {max_transactions_per_checkpoint} max_transactions_per_checkpoint and {max_checkpoint_size_bytes} max_checkpoint_size_bytes" - ); - let notify_builder = Arc::new(Notify::new()); - let notify_aggregator = Arc::new(Notify::new()); - - let (exit_snd, exit_rcv) = watch::channel(()); - - let builder = CheckpointBuilder::new( - state.clone(), - checkpoint_store.clone(), - epoch_store.clone(), - notify_builder.clone(), - effects_store, - accumulator, - checkpoint_output, - exit_rcv.clone(), - notify_aggregator.clone(), - metrics.clone(), - max_transactions_per_checkpoint, - max_checkpoint_size_bytes, - ); - - spawn_monitored_task!(builder.run()); - - let aggregator = CheckpointAggregator::new( - checkpoint_store.clone(), - epoch_store.clone(), - notify_aggregator.clone(), - exit_rcv, - certified_checkpoint_output, - state.clone(), - metrics.clone(), - ); - - spawn_monitored_task!(aggregator.run()); - - let last_signature_index = epoch_store - .get_last_checkpoint_signature_index() - .expect("should not cross end of epoch"); - let last_signature_index = Mutex::new(last_signature_index); - - let service = Arc::new(Self { - tables: checkpoint_store, - notify_builder, - notify_aggregator, - last_signature_index, - metrics, - }); - (service, exit_snd) - } - - #[cfg(test)] - fn write_and_notify_checkpoint_for_testing( - &self, - epoch_store: &AuthorityPerEpochStore, - checkpoint: PendingCheckpointV2, - ) -> SuiResult { - let mut batch = epoch_store.db_batch_for_test(); - epoch_store.write_pending_checkpoint(&mut batch, &checkpoint)?; - batch.write()?; - self.notify_checkpoint()?; - Ok(()) - } -} - -impl CheckpointServiceNotify for CheckpointService { - fn notify_checkpoint_signature( - &self, - epoch_store: &AuthorityPerEpochStore, - info: &CheckpointSignatureMessage, - ) -> SuiResult { - let sequence = info.summary.sequence_number; - let signer = info.summary.auth_sig().authority.concise(); - if let Some(last_certified) = self - .tables - .certified_checkpoints - .keys() - .skip_to_last() - .next() - .transpose()? - { - if sequence <= last_certified { - debug!( - checkpoint_seq = sequence, - "Ignore checkpoint signature from {} - already certified", signer, - ); - return Ok(()); - } - } - debug!( - checkpoint_seq = sequence, - "Received checkpoint signature, digest {} from {}", - info.summary.digest(), - signer, - ); - self.metrics - .last_received_checkpoint_signatures - .with_label_values(&[&signer.to_string()]) - .set(sequence as i64); - // While it can be tempting to make last_signature_index into AtomicU64, this - // won't work We need to make sure we write to `pending_signatures` and - // trigger `notify_aggregator` without race conditions - let mut index = self.last_signature_index.lock(); - *index += 1; - epoch_store.insert_checkpoint_signature(sequence, *index, info)?; - self.notify_aggregator.notify_one(); - Ok(()) - } - - fn notify_checkpoint(&self) -> SuiResult { - self.notify_builder.notify_one(); - Ok(()) - } -} - -// test helper -pub struct CheckpointServiceNoop {} -impl CheckpointServiceNotify for CheckpointServiceNoop { - fn notify_checkpoint_signature( - &self, - _: &AuthorityPerEpochStore, - _: &CheckpointSignatureMessage, - ) -> SuiResult { - Ok(()) - } - - fn notify_checkpoint(&self) -> SuiResult { - Ok(()) - } -} - -impl PendingCheckpoint { - pub fn height(&self) -> CheckpointHeight { - self.details.checkpoint_height - } -} - -impl PendingCheckpointV2 {} - -impl From for PendingCheckpointV2 { - fn from(value: PendingCheckpoint) -> Self { - PendingCheckpointV2::V2(PendingCheckpointV2Contents { - roots: value - .roots - .into_iter() - .map(TransactionKey::Digest) - .collect(), - details: value.details, - }) - } -} - -#[cfg(test)] -mod tests { - use std::{ - collections::{BTreeMap, HashMap}, - ops::Deref, - }; - - use async_trait::async_trait; - use shared_crypto::intent::{Intent, IntentScope}; - use sui_macros::sim_test; - use sui_types::{ - base_types::{ObjectID, SequenceNumber, TransactionEffectsDigest}, - crypto::{AuthoritySignInfo, Signature}, - effects::TransactionEffects, - messages_checkpoint::SignedCheckpointSummary, - move_package::MovePackage, - object, - transaction::{GenesisObject, VerifiedTransaction}, - }; - use tokio::sync::mpsc; - - use super::*; - use crate::authority::test_authority_builder::TestAuthorityBuilder; - - #[sim_test] - pub async fn checkpoint_builder_test() { - telemetry_subscribers::init_for_testing(); - let state = TestAuthorityBuilder::new().build().await; - - let dummy_tx = VerifiedTransaction::new_genesis_transaction(vec![]); - let dummy_tx_with_data = - VerifiedTransaction::new_genesis_transaction(vec![GenesisObject::RawObject { - data: object::Data::Package( - MovePackage::new( - ObjectID::random(), - SequenceNumber::new(), - BTreeMap::from([(format!("{:0>40000}", "1"), Vec::new())]), - 100_000, - // no modules so empty type_origin_table as no types are defined in this - // package - Vec::new(), - // no modules so empty linkage_table as no dependencies of this package - // exist - BTreeMap::new(), - ) - .unwrap(), - ), - owner: object::Owner::Immutable, - }]); - for i in 0..15 { - state - .database_for_testing() - .perpetual_tables - .transactions - .insert(&d(i), dummy_tx.serializable_ref()) - .unwrap(); - } - for i in 15..20 { - state - .database_for_testing() - .perpetual_tables - .transactions - .insert(&d(i), dummy_tx_with_data.serializable_ref()) - .unwrap(); - } - - let mut store = HashMap::::new(); - commit_cert_for_test( - &mut store, - state.clone(), - d(1), - vec![d(2), d(3)], - GasCostSummary::new(11, 12, 11, 1), - ); - commit_cert_for_test( - &mut store, - state.clone(), - d(2), - vec![d(3), d(4)], - GasCostSummary::new(21, 22, 21, 1), - ); - commit_cert_for_test( - &mut store, - state.clone(), - d(3), - vec![], - GasCostSummary::new(31, 32, 31, 1), - ); - commit_cert_for_test( - &mut store, - state.clone(), - d(4), - vec![], - GasCostSummary::new(41, 42, 41, 1), - ); - for i in [10, 11, 12, 13] { - commit_cert_for_test( - &mut store, - state.clone(), - d(i), - vec![], - GasCostSummary::new(41, 42, 41, 1), - ); - } - for i in [15, 16, 17] { - commit_cert_for_test( - &mut store, - state.clone(), - d(i), - vec![], - GasCostSummary::new(51, 52, 51, 1), - ); - } - let all_digests: Vec<_> = store.keys().copied().collect(); - for digest in all_digests { - let signature = Signature::Ed25519SuiSignature(Default::default()).into(); - state - .epoch_store_for_testing() - .test_insert_user_signature(digest, vec![signature]); - } - - let (output, mut result) = mpsc::channel::<(CheckpointContents, CheckpointSummary)>(10); - let (certified_output, mut certified_result) = - mpsc::channel::(10); - let store = Arc::new(store); - - let ckpt_dir = tempfile::tempdir().unwrap(); - let checkpoint_store = CheckpointStore::new(ckpt_dir.path()); - - let accumulator = StateAccumulator::new(state.get_accumulator_store().clone()); - - let epoch_store = state.epoch_store_for_testing(); - let (checkpoint_service, _exit) = CheckpointService::spawn( - state.clone(), - checkpoint_store, - epoch_store.clone(), - store, - Arc::new(accumulator), - Box::new(output), - Box::new(certified_output), - CheckpointMetrics::new_for_tests(), - 3, - 100_000, - ); - - checkpoint_service - .write_and_notify_checkpoint_for_testing(&epoch_store, p(0, vec![4])) - .unwrap(); - // Verify that sending same digests at same height is noop - checkpoint_service - .write_and_notify_checkpoint_for_testing(&epoch_store, p(0, vec![4])) - .unwrap(); - checkpoint_service - .write_and_notify_checkpoint_for_testing(&epoch_store, p(1, vec![1, 3])) - .unwrap(); - checkpoint_service - .write_and_notify_checkpoint_for_testing(&epoch_store, p(2, vec![10, 11, 12, 13])) - .unwrap(); - checkpoint_service - .write_and_notify_checkpoint_for_testing(&epoch_store, p(3, vec![15, 16, 17])) - .unwrap(); - - let (c1c, c1s) = result.recv().await.unwrap(); - let (c2c, c2s) = result.recv().await.unwrap(); - - let c1t = c1c.iter().map(|d| d.transaction).collect::>(); - let c2t = c2c.iter().map(|d| d.transaction).collect::>(); - assert_eq!(c1t, vec![d(4)]); - assert_eq!(c1s.previous_digest, None); - assert_eq!(c1s.sequence_number, 0); - assert_eq!( - c1s.epoch_rolling_gas_cost_summary, - GasCostSummary::new(41, 42, 41, 1) - ); - - assert_eq!(c2t, vec![d(3), d(2), d(1)]); - assert_eq!(c2s.previous_digest, Some(c1s.digest())); - assert_eq!(c2s.sequence_number, 1); - assert_eq!( - c2s.epoch_rolling_gas_cost_summary, - GasCostSummary::new(104, 108, 104, 4) - ); - - // Pending at index 2 had 4 transactions, and we configured 3 transactions max. - // Verify that we split into 2 checkpoints. - let (c3c, c3s) = result.recv().await.unwrap(); - let c3t = c3c.iter().map(|d| d.transaction).collect::>(); - let (c4c, c4s) = result.recv().await.unwrap(); - let c4t = c4c.iter().map(|d| d.transaction).collect::>(); - assert_eq!(c3s.sequence_number, 2); - assert_eq!(c3s.previous_digest, Some(c2s.digest())); - assert_eq!(c4s.sequence_number, 3); - assert_eq!(c4s.previous_digest, Some(c3s.digest())); - assert_eq!(c3t, vec![d(10), d(11), d(12)]); - assert_eq!(c4t, vec![d(13)]); - - // Pending at index 3 had 3 transactions of 40K size, and we configured 100K - // max. Verify that we split into 2 checkpoints. - let (c5c, c5s) = result.recv().await.unwrap(); - let c5t = c5c.iter().map(|d| d.transaction).collect::>(); - let (c6c, c6s) = result.recv().await.unwrap(); - let c6t = c6c.iter().map(|d| d.transaction).collect::>(); - assert_eq!(c5s.sequence_number, 4); - assert_eq!(c5s.previous_digest, Some(c4s.digest())); - assert_eq!(c6s.sequence_number, 5); - assert_eq!(c6s.previous_digest, Some(c5s.digest())); - assert_eq!(c5t, vec![d(15), d(16)]); - assert_eq!(c6t, vec![d(17)]); - - let c1ss = SignedCheckpointSummary::new(c1s.epoch, c1s, state.secret.deref(), state.name); - let c2ss = SignedCheckpointSummary::new(c2s.epoch, c2s, state.secret.deref(), state.name); - - checkpoint_service - .notify_checkpoint_signature( - &epoch_store, - &CheckpointSignatureMessage { summary: c2ss }, - ) - .unwrap(); - checkpoint_service - .notify_checkpoint_signature( - &epoch_store, - &CheckpointSignatureMessage { summary: c1ss }, - ) - .unwrap(); - - let c1sc = certified_result.recv().await.unwrap(); - let c2sc = certified_result.recv().await.unwrap(); - assert_eq!(c1sc.sequence_number, 0); - assert_eq!(c2sc.sequence_number, 1); - } - - #[async_trait] - impl EffectsNotifyRead for HashMap { - async fn notify_read_executed_effects( - &self, - digests: Vec, - ) -> SuiResult> { - Ok(digests - .into_iter() - .map(|d| self.get(&d).expect("effects not found").clone()) - .collect()) - } - - async fn notify_read_executed_effects_digests( - &self, - digests: Vec, - ) -> SuiResult> { - Ok(digests - .into_iter() - .map(|d| { - self.get(&d) - .map(|fx| fx.digest()) - .expect("effects not found") - }) - .collect()) - } - - fn multi_get_executed_effects( - &self, - digests: &[TransactionDigest], - ) -> SuiResult>> { - Ok(digests.iter().map(|d| self.get(d).cloned()).collect()) - } - } - - #[async_trait::async_trait] - impl CheckpointOutput for mpsc::Sender<(CheckpointContents, CheckpointSummary)> { - async fn checkpoint_created( - &self, - summary: &CheckpointSummary, - contents: &CheckpointContents, - _epoch_store: &Arc, - ) -> SuiResult { - self.try_send((contents.clone(), summary.clone())).unwrap(); - Ok(()) - } - } - - #[async_trait::async_trait] - impl CertifiedCheckpointOutput for mpsc::Sender { - async fn certified_checkpoint_created( - &self, - summary: &CertifiedCheckpointSummary, - ) -> SuiResult { - self.try_send(summary.clone()).unwrap(); - Ok(()) - } - } - - fn p(i: u64, t: Vec) -> PendingCheckpointV2 { - PendingCheckpointV2::V2(PendingCheckpointV2Contents { - roots: t - .into_iter() - .map(|t| TransactionKey::Digest(d(t))) - .collect(), - details: PendingCheckpointInfo { - timestamp_ms: 0, - last_of_epoch: false, - checkpoint_height: i, - }, - }) - } - - fn d(i: u8) -> TransactionDigest { - let mut bytes: [u8; 32] = Default::default(); - bytes[0] = i; - TransactionDigest::new(bytes) - } - - fn e( - transaction_digest: TransactionDigest, - dependencies: Vec, - gas_used: GasCostSummary, - ) -> TransactionEffects { - let mut effects = TransactionEffects::default(); - *effects.transaction_digest_mut_for_testing() = transaction_digest; - *effects.dependencies_mut_for_testing() = dependencies; - *effects.gas_cost_summary_mut_for_testing() = gas_used; - effects - } - - fn commit_cert_for_test( - store: &mut HashMap, - state: Arc, - digest: TransactionDigest, - dependencies: Vec, - gas_used: GasCostSummary, - ) { - let epoch_store = state.epoch_store_for_testing(); - let effects = e(digest, dependencies, gas_used); - store.insert(digest, effects.clone()); - epoch_store - .insert_tx_cert_and_effects_signature( - &TransactionKey::Digest(digest), - &digest, - None, - Some(&AuthoritySignInfo::new( - epoch_store.epoch(), - &effects, - Intent::sui_app(IntentScope::TransactionEffects), - state.name, - &*state.secret, - )), - ) - .expect("Inserting cert fx and sigs should not fail"); - } -} diff --git a/crates/sui-core/src/consensus_manager/mod.rs b/crates/sui-core/src/consensus_manager/mod.rs deleted file mode 100644 index afb293abf4b..00000000000 --- a/crates/sui-core/src/consensus_manager/mod.rs +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use std::{path::PathBuf, sync::Arc, time::Instant}; - -use async_trait::async_trait; -use enum_dispatch::enum_dispatch; -use fastcrypto::traits::KeyPair as _; -use mysten_metrics::RegistryService; -use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; -use sui_config::{ConsensusConfig, NodeConfig}; -use sui_protocol_config::ProtocolVersion; -use sui_types::committee::EpochId; -use tokio::sync::{Mutex, MutexGuard}; - -use crate::{ - authority::authority_per_epoch_store::AuthorityPerEpochStore, - consensus_handler::ConsensusHandlerInitializer, - consensus_manager::{ - mysticeti_manager::MysticetiManager, - narwhal_manager::{NarwhalConfiguration, NarwhalManager}, - }, - consensus_validator::SuiTxValidator, - mysticeti_adapter::LazyMysticetiClient, -}; - -pub mod mysticeti_manager; -pub mod narwhal_manager; - -#[derive(PartialEq)] -pub(crate) enum Running { - True(EpochId, ProtocolVersion), - False, -} - -/// An enum to easily differentiate between the chosen consensus engine -#[enum_dispatch] -pub enum ConsensusManager { - Narwhal(NarwhalManager), - Mysticeti(MysticetiManager), -} - -#[async_trait] -#[enum_dispatch(ConsensusManager)] -pub trait ConsensusManagerTrait { - async fn start( - &self, - config: &NodeConfig, - epoch_store: Arc, - consensus_handler_initializer: ConsensusHandlerInitializer, - tx_validator: SuiTxValidator, - ); - - async fn shutdown(&self); - - async fn is_running(&self) -> bool; - - fn get_storage_base_path(&self) -> PathBuf; -} - -impl ConsensusManager { - /// Create a new narwhal manager and wrap it around the Manager enum - pub fn new_narwhal( - config: &NodeConfig, - consensus_config: &ConsensusConfig, - registry_service: &RegistryService, - ) -> Self { - let narwhal_config = NarwhalConfiguration { - primary_keypair: config.protocol_key_pair().copy(), - network_keypair: config.network_key_pair().copy(), - worker_ids_and_keypairs: vec![(0, config.worker_key_pair().copy())], - storage_base_path: consensus_config.db_path().to_path_buf(), - parameters: consensus_config.narwhal_config().to_owned(), - registry_service: registry_service.clone(), - }; - - let metrics = ConsensusManagerMetrics::new(®istry_service.default_registry()); - - Self::Narwhal(NarwhalManager::new(narwhal_config, metrics)) - } - - pub fn new_mysticeti( - config: &NodeConfig, - consensus_config: &ConsensusConfig, - registry_service: &RegistryService, - client: Arc, - ) -> Self { - let metrics = ConsensusManagerMetrics::new(®istry_service.default_registry()); - - Self::Mysticeti(MysticetiManager::new( - config.worker_key_pair().copy(), - config.network_key_pair().copy(), - consensus_config.db_path().to_path_buf(), - metrics, - registry_service.clone(), - client, - )) - } -} - -pub struct ConsensusManagerMetrics { - start_latency: IntGauge, - shutdown_latency: IntGauge, - start_primary_retries: IntGauge, - start_worker_retries: IntGauge, -} - -impl ConsensusManagerMetrics { - pub fn new(registry: &Registry) -> Self { - Self { - start_latency: register_int_gauge_with_registry!( - "consensus_manager_start_latency", - "The latency of starting up consensus nodes", - registry, - ) - .unwrap(), - shutdown_latency: register_int_gauge_with_registry!( - "consensus_manager_shutdown_latency", - "The latency of shutting down consensus nodes", - registry, - ) - .unwrap(), - start_primary_retries: register_int_gauge_with_registry!( - "narwhal_manager_start_primary_retries", - "The number of retries took to start narwhal primary node", - registry - ) - .unwrap(), - start_worker_retries: register_int_gauge_with_registry!( - "narwhal_manager_start_worker_retries", - "The number of retries took to start narwhal worker node", - registry - ) - .unwrap(), - } - } -} - -pub(crate) struct RunningLockGuard<'a> { - state_guard: MutexGuard<'a, Running>, - metrics: &'a ConsensusManagerMetrics, - epoch: Option, - protocol_version: Option, - start: Instant, -} - -impl<'a> RunningLockGuard<'a> { - pub(crate) async fn acquire_start( - metrics: &'a ConsensusManagerMetrics, - running_mutex: &'a Mutex, - epoch: EpochId, - version: ProtocolVersion, - ) -> Option> { - let running = running_mutex.lock().await; - if let Running::True(epoch, version) = *running { - tracing::warn!( - "Consensus is already Running for epoch {epoch:?} & protocol version {version:?} - shutdown first before starting", - ); - return None; - } - - tracing::info!("Starting up consensus for epoch {epoch:?} & protocol version {version:?}"); - - Some(RunningLockGuard { - state_guard: running, - metrics, - start: Instant::now(), - epoch: Some(epoch), - protocol_version: Some(version), - }) - } - - pub(crate) async fn acquire_shutdown( - metrics: &'a ConsensusManagerMetrics, - running_mutex: &'a Mutex, - ) -> Option> { - let running = running_mutex.lock().await; - if let Running::True(epoch, version) = *running { - tracing::info!( - "Shutting down consensus for epoch {epoch:?} & protocol version {version:?}" - ); - } else { - tracing::warn!("Consensus shutdown was called but Narwhal node is not running"); - return None; - } - - Some(RunningLockGuard { - state_guard: running, - metrics, - start: Instant::now(), - epoch: None, - protocol_version: None, - }) - } -} - -impl Drop for RunningLockGuard<'_> { - fn drop(&mut self) { - match *self.state_guard { - // consensus was running and now will have to be marked as shutdown - Running::True(epoch, version) => { - tracing::info!( - "Consensus shutdown for epoch {epoch:?} & protocol version {version:?} is complete - took {} seconds", - self.start.elapsed().as_secs_f64() - ); - - self.metrics - .shutdown_latency - .set(self.start.elapsed().as_secs_f64() as i64); - - *self.state_guard = Running::False; - } - // consensus was not running and now will be marked as started - Running::False => { - tracing::info!( - "Starting up consensus for epoch {} & protocol version {:?} is complete - took {} seconds", - self.epoch.unwrap(), - self.protocol_version.unwrap(), - self.start.elapsed().as_secs_f64() - ); - - self.metrics - .start_latency - .set(self.start.elapsed().as_secs_f64() as i64); - - *self.state_guard = - Running::True(self.epoch.unwrap(), self.protocol_version.unwrap()); - } - } - } -} diff --git a/crates/sui-core/src/consensus_types/mod.rs b/crates/sui-core/src/consensus_types/mod.rs deleted file mode 100644 index 1bb7add7abc..00000000000 --- a/crates/sui-core/src/consensus_types/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub(crate) mod committee_api; -pub(crate) mod consensus_output_api; - -/// An unique integer ID for a validator used by consensus. -/// In Narwhal, this is the inner value of the `AuthorityIdentifier` type. -/// In Mysticeti, this is used the same way as the AuthorityIndex type there. -pub type AuthorityIndex = u32; diff --git a/crates/sui-core/src/epoch/mod.rs b/crates/sui-core/src/epoch/mod.rs deleted file mode 100644 index 5a8961ca226..00000000000 --- a/crates/sui-core/src/epoch/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod committee_store; -pub mod data_removal; -pub mod epoch_metrics; -pub mod randomness; -pub mod reconfiguration; diff --git a/crates/sui-core/src/lib.rs b/crates/sui-core/src/lib.rs deleted file mode 100644 index 213df582e6d..00000000000 --- a/crates/sui-core/src/lib.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2021, Facebook, Inc. and its affiliates -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -extern crate core; - -pub mod authority; -pub mod authority_aggregator; -pub mod authority_client; -pub mod authority_server; -pub mod checkpoints; -pub mod consensus_adapter; -pub mod consensus_handler; -pub mod consensus_manager; -pub mod consensus_throughput_calculator; -pub(crate) mod consensus_types; -pub mod consensus_validator; -pub mod db_checkpoint_handler; -pub mod epoch; -pub mod execution_cache; -mod execution_driver; -pub mod metrics; -pub mod module_cache_metrics; -pub mod mysticeti_adapter; -pub mod overload_monitor; -pub(crate) mod post_consensus_tx_reorder; -pub mod quorum_driver; -pub mod safe_client; -mod scoring_decision; -mod stake_aggregator; -pub mod state_accumulator; -pub mod storage; -pub mod streamer; -pub mod subscription_handler; -#[cfg(any(test, feature = "test-utils"))] -pub mod test_utils; -mod transaction_input_loader; -mod transaction_manager; -pub mod transaction_orchestrator; -mod transaction_outputs; -pub mod verify_indexes; - -#[cfg(test)] -#[path = "unit_tests/move_package_publish_tests.rs"] -mod move_package_publish_tests; -#[cfg(test)] -#[path = "unit_tests/move_package_tests.rs"] -mod move_package_tests; -#[cfg(test)] -#[path = "unit_tests/move_package_upgrade_tests.rs"] -mod move_package_upgrade_tests; -#[cfg(test)] -#[path = "unit_tests/pay_sui_tests.rs"] -mod pay_sui_tests; -#[cfg(test)] -#[path = "unit_tests/shared_object_deletion_tests.rs"] -mod shared_object_deletion_tests; -pub mod test_authority_clients; -#[cfg(test)] -#[path = "unit_tests/transfer_to_object_tests.rs"] -mod transfer_to_object_tests; -#[cfg(test)] -#[path = "unit_tests/type_param_tests.rs"] -mod type_param_tests; - -pub mod signature_verifier; - -pub mod runtime; -mod transaction_signing_filter; diff --git a/crates/sui-core/src/metrics.rs b/crates/sui-core/src/metrics.rs deleted file mode 100644 index 47bc61b0036..00000000000 --- a/crates/sui-core/src/metrics.rs +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::VecDeque, - default::Default, - sync::atomic::{AtomicU64, Ordering}, -}; - -use parking_lot::Mutex; -use tokio::time::{Duration, Instant}; - -pub struct LatencyObserver { - data: Mutex, - latency_ms: AtomicU64, -} - -#[derive(Default)] -struct LatencyObserverInner { - points: VecDeque, - sum: Duration, -} - -impl LatencyObserver { - pub fn new() -> Self { - Self { - data: Mutex::new(LatencyObserverInner::default()), - latency_ms: AtomicU64::new(u64::MAX), - } - } - - pub fn report(&self, latency: Duration) { - const MAX_SAMPLES: usize = 64; - let mut data = self.data.lock(); - data.points.push_back(latency); - data.sum += latency; - if data.points.len() >= MAX_SAMPLES { - let pop = data.points.pop_front().expect("data vector is not empty"); - data.sum -= pop; // This does not overflow because of how running sum is calculated - } - let latency = data.sum.as_millis() as u64 / data.points.len() as u64; - self.latency_ms.store(latency, Ordering::Relaxed); - } - - pub fn latency(&self) -> Option { - let latency = self.latency_ms.load(Ordering::Relaxed); - if latency == u64::MAX { - // Not initialized yet (0 data points) - None - } else { - Some(Duration::from_millis(latency)) - } - } -} - -impl Default for LatencyObserver { - fn default() -> Self { - Self::new() - } -} - -/// RateTracker tracks events in a rolling window, and calculates the rate of -/// events. Internally, the tracker divides the tracking window into multiple -/// BIN_DURATION, and counts events in each BIN_DURATION in a fixed sized -/// buffer. -pub struct RateTracker { - // Counts the number of events by bins. Each bin is BIN_DURATION long within window_duration. - // The size of the buffer = window_duration / BIN_DURATION. - event_buffer: Vec, - window_duration: Duration, - total_bins: usize, - - // We use the event time and the tracker start time to calculate the bin that a event - // belongs to. - // event_global_bin_index = (event_time - start_time) / BIN_DURATION. - // event_index_in_buffer = event_global_bin_index % buffer_size. - start_time: Instant, - - // Last updated global bin index. This tracks the end of the rolling window. - global_bin_index: u64, -} - -const BIN_DURATION: Duration = Duration::from_millis(100); - -impl RateTracker { - /// Create a new RateTracker to track event rate (events/seconds) in - /// `window_duration`. - pub fn new(window_duration: Duration) -> Self { - assert!(window_duration > BIN_DURATION); - let total_bins = (window_duration.as_millis() / BIN_DURATION.as_millis()) as usize; - RateTracker { - event_buffer: vec![0; total_bins], - window_duration, - total_bins, - start_time: Instant::now(), - global_bin_index: 0, - } - } - - /// Records an event at time `now`. - pub fn record_at_time(&mut self, now: Instant) { - self.update_window(now); - let current_bin_index = self.get_bin_index(now) as usize; - if current_bin_index + self.total_bins <= self.global_bin_index as usize { - // The bin associated with `now` has passed the rolling window. - return; - } - - self.event_buffer[current_bin_index % self.total_bins] += 1; - } - - /// Records an event at current time. - pub fn record(&mut self) { - self.record_at_time(Instant::now()); - } - - /// Returns the rate of events. - pub fn rate(&mut self) -> f64 { - let now = Instant::now(); - self.update_window(now); - self.event_buffer.iter().sum::() as f64 / self.window_duration.as_secs_f64() - } - - // Given a time `now`, returns the bin index since `start_time`. - fn get_bin_index(&self, now: Instant) -> u64 { - (now.duration_since(self.start_time).as_millis() / BIN_DURATION.as_millis()) as u64 - } - - // Updates the rolling window to accommodate the time of interests, `now`. That - // is, remove any event counts happened prior to (`now` - - // `window_duration`). - fn update_window(&mut self, now: Instant) { - let current_bin_index = self.get_bin_index(now); - if self.global_bin_index >= current_bin_index { - // The rolling doesn't move. - return; - } - - for bin_index in (self.global_bin_index + 1)..=current_bin_index { - // Time has elapsed from global_bin_index to current_bin_index. Clear all the - // buffer counter associated with them. - let index_in_buffer = bin_index as usize % self.total_bins; - self.event_buffer[index_in_buffer] = 0; - } - self.global_bin_index = current_bin_index; - } -} - -#[cfg(test)] -mod tests { - use rand::{rngs::StdRng, Rng, SeedableRng}; - use tokio::time::advance; - - use super::*; - - #[tokio::test(flavor = "current_thread", start_paused = true)] - pub async fn test_rate_tracker_basic() { - // 1 sec rolling window. - let mut tracker = RateTracker::new(Duration::from_secs(1)); - assert_eq!(tracker.rate(), 0.0); - tracker.record(); - tracker.record(); - tracker.record(); - assert_eq!(tracker.rate(), 3.0); - - advance(Duration::from_millis(200)).await; - tracker.record(); - tracker.record(); - tracker.record(); - assert_eq!(tracker.rate(), 6.0); - - advance(Duration::from_millis(800)).await; - assert_eq!(tracker.rate(), 3.0); - - advance(Duration::from_millis(200)).await; - assert_eq!(tracker.rate(), 0.0); - } - - // Tests rate calculation using different window duration. - #[tokio::test(flavor = "current_thread", start_paused = true)] - pub async fn test_rate_tracker_window() { - let seed = [0; 32]; - let mut rng = StdRng::from_seed(seed); - let random_windows: Vec = (0..10).map(|_| rng.gen_range(1..=60)).collect(); - for window in random_windows { - let mut tracker = RateTracker::new(Duration::from_secs(window)); - for _ in 0..23 { - tracker.record(); - } - assert_eq!(tracker.rate(), 23.0 / window as f64); - advance(Duration::from_secs(window)).await; - assert_eq!(tracker.rate(), 0.0); - } - } - - // Tests rate calculation when window moves continuously. - #[tokio::test(flavor = "current_thread", start_paused = true)] - pub async fn test_rate_tracker_rolling_window() { - let mut tracker = RateTracker::new(Duration::from_secs(1)); - // Generate event every 100ms. - for i in 0..10 { - tracker.record(); - assert_eq!(tracker.rate(), (i + 1) as f64); - advance(Duration::from_millis(100)).await; - } - - // Generate event every 50ms. - for i in 0..10 { - tracker.record(); - advance(Duration::from_millis(50)).await; - tracker.record(); - assert_eq!(tracker.rate(), 11.0 + i as f64); - advance(Duration::from_millis(50)).await; - } - - // Rate gradually returns to 0. - for i in 0..10 { - assert_eq!(tracker.rate(), 20.0 - (i as f64 + 1.0) * 2.0); - advance(Duration::from_millis(100)).await; - } - assert_eq!(tracker.rate(), 0.0); - } - - // Tests that events happened prior to tracking window shouldn't affect the - // rate. - #[tokio::test(flavor = "current_thread", start_paused = true)] - pub async fn test_rate_tracker_outside_of_window() { - let mut tracker = RateTracker::new(Duration::from_secs(1)); - advance(Duration::from_secs(60)).await; - tracker.record(); - tracker.record(); - tracker.record(); - assert_eq!(tracker.rate(), 3.0); - tracker.record_at_time(Instant::now() - Duration::from_millis(1100)); - tracker.record_at_time(Instant::now() - Duration::from_millis(1100)); - tracker.record_at_time(Instant::now() - Duration::from_millis(1100)); - assert_eq!(tracker.rate(), 3.0); - } -} diff --git a/crates/sui-core/src/quorum_driver/metrics.rs b/crates/sui-core/src/quorum_driver/metrics.rs deleted file mode 100644 index dc3a9cd46c2..00000000000 --- a/crates/sui-core/src/quorum_driver/metrics.rs +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2021, Facebook, Inc. and its affiliates -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use mysten_metrics::histogram::Histogram; -use prometheus::{ - register_histogram_vec_with_registry, register_int_counter_vec_with_registry, - register_int_counter_with_registry, register_int_gauge_with_registry, HistogramVec, IntCounter, - IntCounterVec, IntGauge, Registry, -}; - -const FINALITY_LATENCY_SEC_BUCKETS: &[f64] = &[ - 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, - 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, - 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, - 7.0, 7.5, 8.0, 8.5, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, - 25.0, -]; - -#[derive(Clone)] -pub struct QuorumDriverMetrics { - pub(crate) total_requests: IntCounter, - pub(crate) total_enqueued: IntCounter, - pub(crate) total_ok_responses: IntCounter, - pub(crate) total_err_responses: IntCounterVec, - pub(crate) attempt_times_ok_response: Histogram, - - // TODO: add histogram of attempt that tx succeeds - pub(crate) current_requests_in_flight: IntGauge, - - pub(crate) total_err_process_tx_responses_with_nonzero_conflicting_transactions: IntCounter, - pub(crate) total_attempts_retrying_conflicting_transaction: IntCounter, - pub(crate) total_successful_attempts_retrying_conflicting_transaction: IntCounter, - pub(crate) total_times_conflicting_transaction_already_finalized_when_retrying: IntCounter, - pub(crate) total_retryable_overload_errors: IntCounter, - pub(crate) transaction_retry_count: Histogram, - pub(crate) current_transactions_in_retry: IntGauge, - - pub(crate) settlement_finality_latency: HistogramVec, -} - -impl QuorumDriverMetrics { - pub fn new(registry: &Registry) -> Self { - Self { - total_requests: register_int_counter_with_registry!( - "quorum_driver_total_requests", - "Total number of requests received", - registry, - ) - .unwrap(), - total_enqueued: register_int_counter_with_registry!( - "quorum_driver_total_enqueued", - "Total number of requests enqueued", - registry, - ) - .unwrap(), - total_ok_responses: register_int_counter_with_registry!( - "quorum_driver_total_ok_responses", - "Total number of requests processed with Ok responses", - registry, - ) - .unwrap(), - total_err_responses: register_int_counter_vec_with_registry!( - "quorum_driver_total_err_responses", - "Total number of requests returned with Err responses, grouped by error type", - &["error"], - registry, - ) - .unwrap(), - attempt_times_ok_response: Histogram::new_in_registry( - "quorum_driver_attempt_times_ok_response", - "Total attempt times of ok response", - registry, - ), - current_requests_in_flight: register_int_gauge_with_registry!( - "current_requests_in_flight", - "Current number of requests being processed in QuorumDriver", - registry, - ) - .unwrap(), - total_err_process_tx_responses_with_nonzero_conflicting_transactions: register_int_counter_with_registry!( - "quorum_driver_total_err_process_tx_responses_with_nonzero_conflicting_transactions", - "Total number of err process_tx responses with non empty conflicting transactions", - registry, - ) - .unwrap(), - total_attempts_retrying_conflicting_transaction: register_int_counter_with_registry!( - "quorum_driver_total_attempts_trying_conflicting_transaction", - "Total number of attempts to retry a conflicting transaction", - registry, - ) - .unwrap(), - total_successful_attempts_retrying_conflicting_transaction: register_int_counter_with_registry!( - "quorum_driver_total_successful_attempts_trying_conflicting_transaction", - "Total number of successful attempts to retry a conflicting transaction", - registry, - ) - .unwrap(), - total_times_conflicting_transaction_already_finalized_when_retrying: register_int_counter_with_registry!( - "quorum_driver_total_times_conflicting_transaction_already_finalized_when_retrying", - "Total number of times the conflicting transaction is already finalized when retrying", - registry, - ) - .unwrap(), - total_retryable_overload_errors: register_int_counter_with_registry!( - "quorum_driver_total_retryable_overload_errors", - "Total number of transactions experiencing retryable overload error", - registry, - ) - .unwrap(), - transaction_retry_count: Histogram::new_in_registry( - "quorum_driver_transaction_retry_count", - "Histogram of transaction retry count", - registry, - ), - current_transactions_in_retry: register_int_gauge_with_registry!( - "current_transactions_in_retry", - "Current number of transactions in retry loop in QuorumDriver", - registry, - ) - .unwrap(), - settlement_finality_latency: register_histogram_vec_with_registry!( - "quorum_driver_settlement_finality_latency", - "Settlement finality latency observed from quorum driver", - &["tx_type"], - FINALITY_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - } - } - - pub fn new_for_tests() -> Self { - let registry = Registry::new(); - Self::new(®istry) - } -} diff --git a/crates/sui-core/src/quorum_driver/mod.rs b/crates/sui-core/src/quorum_driver/mod.rs deleted file mode 100644 index e07ebd4eac0..00000000000 --- a/crates/sui-core/src/quorum_driver/mod.rs +++ /dev/null @@ -1,945 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod metrics; -pub use metrics::*; - -pub mod reconfig_observer; - -use std::{ - collections::{BTreeMap, BTreeSet}, - fmt::{Debug, Formatter, Write}, - sync::Arc, - time::Duration, -}; - -use arc_swap::ArcSwap; -use mysten_common::sync::notify_read::{NotifyRead, Registration}; -use mysten_metrics::{ - spawn_monitored_task, GaugeGuard, TX_TYPE_SHARED_OBJ_TX, TX_TYPE_SINGLE_WRITER_TX, -}; -use sui_types::{ - base_types::{AuthorityName, ObjectRef, TransactionDigest}, - committee::{Committee, EpochId, StakeUnit}, - error::{SuiError, SuiResult}, - messages_safe_client::PlainTransactionInfoResponse, - quorum_driver_types::{ - QuorumDriverEffectsQueueResult, QuorumDriverError, QuorumDriverResponse, QuorumDriverResult, - }, - transaction::{CertifiedTransaction, Transaction}, -}; -use tap::TapFallible; -use tokio::{ - sync::{ - mpsc::{self, Receiver, Sender}, - Semaphore, - }, - task::JoinHandle, - time::{sleep_until, Instant}, -}; -use tracing::{debug, error, info, warn, Instrument}; - -use self::reconfig_observer::ReconfigObserver; -use crate::{ - authority_aggregator::{ - AggregatorProcessCertificateError, AggregatorProcessTransactionError, AuthorityAggregator, - ProcessTransactionResult, - }, - authority_client::AuthorityAPI, -}; - -#[cfg(test)] -mod tests; - -const TASK_QUEUE_SIZE: usize = 2000; -const EFFECTS_QUEUE_SIZE: usize = 10000; -const TX_MAX_RETRY_TIMES: u32 = 10; - -#[derive(Clone)] -pub struct QuorumDriverTask { - pub transaction: Transaction, - pub tx_cert: Option, - pub retry_times: u32, - pub next_retry_after: Instant, -} - -impl Debug for QuorumDriverTask { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let mut writer = String::new(); - write!(writer, "tx_digest={:?} ", self.transaction.digest())?; - write!(writer, "has_tx_cert={} ", self.tx_cert.is_some())?; - write!(writer, "retry_times={} ", self.retry_times)?; - write!(writer, "next_retry_after={:?} ", self.next_retry_after)?; - write!(f, "{}", writer) - } -} - -pub struct QuorumDriver { - validators: ArcSwap>, - task_sender: Sender, - effects_subscribe_sender: tokio::sync::broadcast::Sender, - notifier: Arc>, - metrics: Arc, - max_retry_times: u32, -} - -impl QuorumDriver { - pub(crate) fn new( - validators: ArcSwap>, - task_sender: Sender, - effects_subscribe_sender: tokio::sync::broadcast::Sender, - notifier: Arc>, - metrics: Arc, - max_retry_times: u32, - ) -> Self { - Self { - validators, - task_sender, - effects_subscribe_sender, - notifier, - metrics, - max_retry_times, - } - } - - pub fn authority_aggregator(&self) -> &ArcSwap> { - &self.validators - } - - pub fn clone_committee(&self) -> Arc { - self.validators.load().committee.clone() - } - - pub fn current_epoch(&self) -> EpochId { - self.validators.load().committee.epoch - } - - async fn enqueue_task(&self, task: QuorumDriverTask) -> SuiResult<()> { - self.task_sender - .send(task.clone()) - .await - .tap_err(|e| debug!(?task, "Failed to enqueue task: {:?}", e)) - .tap_ok(|_| { - debug!(?task, "Enqueued task."); - self.metrics.current_requests_in_flight.inc(); - self.metrics.total_enqueued.inc(); - if task.retry_times == 1 { - self.metrics.current_transactions_in_retry.inc(); - } - }) - .map_err(|e| SuiError::QuorumDriverCommunicationError { - error: e.to_string(), - }) - } - - /// Enqueue the task again if it hasn't maxed out the total retry attempts. - /// If it has, notify failure. - async fn enqueue_again_maybe( - &self, - transaction: Transaction, - tx_cert: Option, - old_retry_times: u32, - ) -> SuiResult<()> { - if old_retry_times >= self.max_retry_times { - // max out the retry times, notify failure - info!(tx_digest=?transaction.digest(), "Failed to reach finality after attempting for {} times", old_retry_times+1); - self.notify( - &transaction, - &Err( - QuorumDriverError::FailedWithTransientErrorAfterMaximumAttempts { - total_attempts: old_retry_times + 1, - }, - ), - old_retry_times + 1, - ); - return Ok(()); - } - self.backoff_and_enqueue(transaction, tx_cert, old_retry_times) - .await - } - - /// Performs exponential backoff and enqueue the `transaction` to the - /// execution queue. - async fn backoff_and_enqueue( - &self, - transaction: Transaction, - tx_cert: Option, - old_retry_times: u32, - ) -> SuiResult<()> { - let next_retry_after = - Instant::now() + Duration::from_millis(200 * u64::pow(2, old_retry_times)); - sleep_until(next_retry_after).await; - - let tx_cert = match tx_cert { - // TxCert is only valid when its epoch matches current epoch. - // Note, it's impossible that TxCert's epoch is larger than current epoch - // because the TxCert will be considered invalid and cannot reach here. - Some(tx_cert) if tx_cert.epoch() == self.current_epoch() => Some(tx_cert), - _other => None, - }; - - self.enqueue_task(QuorumDriverTask { - transaction, - tx_cert, - retry_times: old_retry_times + 1, - next_retry_after, - }) - .await - } - - pub fn notify( - &self, - transaction: &Transaction, - response: &QuorumDriverResult, - total_attempts: u32, - ) { - let tx_digest = transaction.digest(); - let effects_queue_result = match &response { - Ok(resp) => { - self.metrics.total_ok_responses.inc(); - self.metrics - .attempt_times_ok_response - .report(total_attempts as u64); - Ok((transaction.clone(), resp.clone())) - } - Err(err) => { - self.metrics - .total_err_responses - .with_label_values(&[err.as_ref()]) - .inc(); - Err((*tx_digest, err.clone())) - } - }; - if total_attempts > 1 { - self.metrics.current_transactions_in_retry.dec(); - } - // On fullnode we expect the send to always succeed because - // TransactionOrchestrator should be subscribing to this queue all the - // time. However the if QuorumDriver is used elsewhere log may be noisy. - if let Err(err) = self.effects_subscribe_sender.send(effects_queue_result) { - warn!(?tx_digest, "No subscriber found for effects: {}", err); - } - debug!(?tx_digest, "notify QuorumDriver task result"); - self.notifier.notify(tx_digest, response); - } -} - -impl QuorumDriver -where - A: AuthorityAPI + Send + Sync + 'static + Clone, -{ - pub async fn submit_transaction( - &self, - transaction: Transaction, - ) -> SuiResult> { - let tx_digest = transaction.digest(); - debug!(?tx_digest, "Received transaction execution request."); - self.metrics.total_requests.inc(); - - let ticket = self.notifier.register_one(tx_digest); - self.enqueue_task(QuorumDriverTask { - transaction, - tx_cert: None, - retry_times: 0, - next_retry_after: Instant::now(), - }) - .await?; - Ok(ticket) - } - - // Used when the it is called in a component holding the notifier, and a ticket - // is already obtained prior to calling this function, for instance, - // TransactionOrchestrator - pub async fn submit_transaction_no_ticket(&self, transaction: Transaction) -> SuiResult<()> { - let tx_digest = transaction.digest(); - debug!( - ?tx_digest, - "Received transaction execution request, no ticket." - ); - self.metrics.total_requests.inc(); - - self.enqueue_task(QuorumDriverTask { - transaction, - tx_cert: None, - retry_times: 0, - next_retry_after: Instant::now(), - }) - .await - } - - pub(crate) async fn process_transaction( - &self, - transaction: Transaction, - ) -> Result> { - let auth_agg = self.validators.load(); - let _tx_guard = GaugeGuard::acquire(&auth_agg.metrics.inflight_transactions); - let tx_digest = *transaction.digest(); - let result = auth_agg - .process_transaction(transaction) - .instrument(tracing::debug_span!("aggregator_process_tx", ?tx_digest)) - .await; - - self.process_transaction_result(result, tx_digest).await - } - - async fn process_transaction_result( - &self, - result: Result, - tx_digest: TransactionDigest, - ) -> Result> { - match result { - Ok(resp) => Ok(resp), - Err(AggregatorProcessTransactionError::RetryableConflictingTransaction { - conflicting_tx_digest_to_retry, - errors, - conflicting_tx_digests, - }) => { - self.metrics - .total_err_process_tx_responses_with_nonzero_conflicting_transactions - .inc(); - debug!( - ?tx_digest, - "Observed {} conflicting transactions: {:?}", - conflicting_tx_digests.len(), - conflicting_tx_digests - ); - - if let Some(conflicting_tx_digest) = conflicting_tx_digest_to_retry { - self.process_conflicting_tx( - tx_digest, - conflicting_tx_digest, - conflicting_tx_digests, - ) - .await - } else { - // If no retryable conflicting transaction was returned that means we have >= - // 2f+1 good stake for the original transaction + retryable - // stake. Will continue to retry the original transaction. - debug!( - ?errors, - "Observed Tx {tx_digest:} is still in retryable state. Conflicting Txes: {conflicting_tx_digests:?}", - ); - Err(None) - } - } - - Err(AggregatorProcessTransactionError::FatalConflictingTransaction { - errors, - conflicting_tx_digests, - }) => { - debug!( - ?errors, - "Observed Tx {tx_digest:} double spend attempted. Conflicting Txes: {conflicting_tx_digests:?}", - ); - Err(Some(QuorumDriverError::ObjectsDoubleUsed { - conflicting_txes: conflicting_tx_digests, - retried_tx: None, - retried_tx_success: None, - })) - } - - Err(AggregatorProcessTransactionError::FatalTransaction { errors }) => { - debug!(?tx_digest, ?errors, "Nonretryable transaction error"); - Err(Some(QuorumDriverError::NonRecoverableTransactionError { - errors, - })) - } - - Err(AggregatorProcessTransactionError::SystemOverload { - overloaded_stake, - errors, - }) => { - debug!(?tx_digest, ?errors, "System overload"); - Err(Some(QuorumDriverError::SystemOverload { - overloaded_stake, - errors, - })) - } - - Err(AggregatorProcessTransactionError::SystemOverloadRetryAfter { - overload_stake, - errors, - retry_after_secs, - }) => { - self.metrics.total_retryable_overload_errors.inc(); - debug!(?tx_digest, ?errors, "System overload and retry"); - Err(Some(QuorumDriverError::SystemOverloadRetryAfter { - overload_stake, - errors, - retry_after_secs, - })) - } - - Err(AggregatorProcessTransactionError::RetryableTransaction { errors }) => { - debug!(?tx_digest, ?errors, "Retryable transaction error"); - Err(None) - } - - Err( - AggregatorProcessTransactionError::TxAlreadyFinalizedWithDifferentUserSignatures, - ) => { - debug!( - ?tx_digest, - "Transaction is already finalized with different user signatures" - ); - Err(Some( - QuorumDriverError::TxAlreadyFinalizedWithDifferentUserSignatures, - )) - } - } - } - - async fn process_conflicting_tx( - &self, - tx_digest: TransactionDigest, - conflicting_tx_digest: TransactionDigest, - conflicting_tx_digests: BTreeMap< - TransactionDigest, - (Vec<(AuthorityName, ObjectRef)>, StakeUnit), - >, - ) -> Result> { - // Safe to unwrap because tx_digest_to_retry is generated from - // conflicting_tx_digests - // in ProcessTransactionState::conflicting_tx_digest_with_most_stake() - let (validators, _) = conflicting_tx_digests.get(&conflicting_tx_digest).unwrap(); - let attempt_result = self - .attempt_conflicting_transaction( - &conflicting_tx_digest, - &tx_digest, - validators.iter().map(|(pub_key, _)| *pub_key).collect(), - ) - .await; - self.metrics - .total_attempts_retrying_conflicting_transaction - .inc(); - - match attempt_result { - Err(err) => { - debug!( - ?tx_digest, - ?conflicting_tx_digest, - "Encountered error while attempting conflicting transaction: {:?}", - err - ); - Err(Some(QuorumDriverError::ObjectsDoubleUsed { - conflicting_txes: conflicting_tx_digests, - retried_tx: None, - retried_tx_success: None, - })) - } - Ok(success) => { - debug!( - ?tx_digest, - ?conflicting_tx_digest, - "Retried conflicting transaction. Success: {}", - success - ); - if success { - self.metrics - .total_successful_attempts_retrying_conflicting_transaction - .inc(); - } - Err(Some(QuorumDriverError::ObjectsDoubleUsed { - conflicting_txes: conflicting_tx_digests, - retried_tx: Some(conflicting_tx_digest), - retried_tx_success: Some(success), - })) - } - } - } - - pub(crate) async fn process_certificate( - &self, - certificate: CertifiedTransaction, - ) -> Result> { - let auth_agg = self.validators.load(); - let _cert_guard = GaugeGuard::acquire(&auth_agg.metrics.inflight_certificates); - let tx_digest = *certificate.digest(); - let (effects, events) = auth_agg - .process_certificate(certificate.clone()) - .instrument(tracing::debug_span!("aggregator_process_cert", ?tx_digest)) - .await - .map_err(|agg_err| match agg_err { - AggregatorProcessCertificateError::FatalExecuteCertificate { - non_retryable_errors, - } => { - // Normally a certificate shouldn't have fatal errors. - error!( - ?tx_digest, - ?non_retryable_errors, - "[WATCHOUT] Unexpected Fatal error for certificate" - ); - Some(QuorumDriverError::NonRecoverableTransactionError { - errors: non_retryable_errors, - }) - } - AggregatorProcessCertificateError::RetryableExecuteCertificate { - retryable_errors, - } => { - debug!(?retryable_errors, "Retryable certificate"); - None - } - })?; - let response = QuorumDriverResponse { - effects_cert: effects, - events, - }; - - Ok(response) - } - - pub async fn update_validators(&self, new_validators: Arc>) { - info!( - "Quorum Driver updating AuthorityAggregator with committee {}", - new_validators.committee - ); - self.validators.store(new_validators); - } - - /// Returns Some(true) if the conflicting transaction is executed - /// successfully (or already executed), or Some(false) if it did not. - async fn attempt_conflicting_transaction( - &self, - tx_digest: &TransactionDigest, - original_tx_digest: &TransactionDigest, - validators: BTreeSet, - ) -> SuiResult { - let response = self - .validators - .load() - .handle_transaction_info_request_from_some_validators( - tx_digest, - &validators, - Some(Duration::from_secs(10)), - ) - .await?; - - // If we are able to get a certificate right away, we use it and execute the - // cert; otherwise, we have to re-form a cert and execute it. - let transaction = match response { - PlainTransactionInfoResponse::ExecutedWithCert(cert, _, _) => { - self.metrics - .total_times_conflicting_transaction_already_finalized_when_retrying - .inc(); - // We still want to ask validators to execute this certificate in case this - // certificate is not known to the rest of them (e.g. when - // *this* validator is bad). - let result = self - .validators - .load() - .process_certificate(cert) - .await - .tap_ok(|_resp| { - debug!( - ?tx_digest, - ?original_tx_digest, - "Retry conflicting transaction certificate succeeded." - ); - }) - .tap_err(|err| { - debug!( - ?tx_digest, - ?original_tx_digest, - "Retry conflicting transaction certificate got an error: {:?}", - err - ); - }); - // We only try it once. - return Ok(result.is_ok()); - } - PlainTransactionInfoResponse::Signed(signed) => { - signed.verify_committee_sigs_only(&self.clone_committee())?; - signed.into_unsigned() - } - PlainTransactionInfoResponse::ExecutedWithoutCert(transaction, _, _) => transaction, - }; - // Now ask validators to execute this transaction. - let result = self - .validators - .load() - .execute_transaction_block(&transaction) - .await - .tap_ok(|_resp| { - debug!( - ?tx_digest, - ?original_tx_digest, - "Retry conflicting transaction succeeded." - ); - }) - .tap_err(|err| { - debug!( - ?tx_digest, - ?original_tx_digest, - "Retry conflicting transaction got an error: {:?}", - err - ); - }); - // We only try it once - Ok(result.is_ok()) - } -} - -pub struct QuorumDriverHandler { - quorum_driver: Arc>, - effects_subscriber: tokio::sync::broadcast::Receiver, - quorum_driver_metrics: Arc, - reconfig_observer: Arc + Sync + Send>, - _processor_handle: JoinHandle<()>, -} - -impl QuorumDriverHandler -where - A: AuthorityAPI + Send + Sync + 'static + Clone, -{ - pub(crate) fn new( - validators: Arc>, - notifier: Arc>, - reconfig_observer: Arc + Sync + Send>, - metrics: Arc, - max_retry_times: u32, - ) -> Self { - let (task_tx, task_rx) = mpsc::channel::(TASK_QUEUE_SIZE); - let (subscriber_tx, subscriber_rx) = - tokio::sync::broadcast::channel::<_>(EFFECTS_QUEUE_SIZE); - let quorum_driver = Arc::new(QuorumDriver::new( - ArcSwap::from(validators), - task_tx, - subscriber_tx, - notifier, - metrics.clone(), - max_retry_times, - )); - let metrics_clone = metrics.clone(); - let processor_handle = { - let quorum_driver_clone = quorum_driver.clone(); - spawn_monitored_task!(Self::task_queue_processor( - quorum_driver_clone, - task_rx, - metrics_clone - )) - }; - let reconfig_observer_clone = reconfig_observer.clone(); - { - let quorum_driver_clone = quorum_driver.clone(); - spawn_monitored_task!({ - async move { - let mut reconfig_observer_clone = reconfig_observer_clone.clone_boxed(); - reconfig_observer_clone.run(quorum_driver_clone).await; - } - }); - }; - Self { - quorum_driver, - effects_subscriber: subscriber_rx, - quorum_driver_metrics: metrics, - reconfig_observer, - _processor_handle: processor_handle, - } - } - - // Used when the it is called in a component holding the notifier, and a ticket - // is already obtained prior to calling this function, for instance, - // TransactionOrchestrator - pub async fn submit_transaction_no_ticket(&self, transaction: Transaction) -> SuiResult<()> { - self.quorum_driver - .submit_transaction_no_ticket(transaction) - .await - } - - pub async fn submit_transaction( - &self, - transaction: Transaction, - ) -> SuiResult> { - self.quorum_driver.submit_transaction(transaction).await - } - - /// Create a new `QuorumDriverHandler` based on the same - /// AuthorityAggregator. Note: the new `QuorumDriverHandler` will have a - /// new `ArcSwap` that is NOT tied to the original - /// one. So if there are multiple QuorumDriver(Handler) then all of them - /// need to do reconfigs on their own. - pub fn clone_new(&self) -> Self { - let (task_sender, task_rx) = mpsc::channel::(TASK_QUEUE_SIZE); - let (effects_subscribe_sender, subscriber_rx) = - tokio::sync::broadcast::channel::<_>(EFFECTS_QUEUE_SIZE); - let validators = ArcSwap::new(self.quorum_driver.authority_aggregator().load_full()); - let quorum_driver = Arc::new(QuorumDriver { - validators, - task_sender, - effects_subscribe_sender, - notifier: Arc::new(NotifyRead::new()), - metrics: self.quorum_driver_metrics.clone(), - max_retry_times: self.quorum_driver.max_retry_times, - }); - let metrics = self.quorum_driver_metrics.clone(); - let processor_handle = { - let quorum_driver_copy = quorum_driver.clone(); - spawn_monitored_task!(Self::task_queue_processor( - quorum_driver_copy, - task_rx, - metrics, - )) - }; - { - let quorum_driver_copy = quorum_driver.clone(); - let reconfig_observer = self.reconfig_observer.clone(); - spawn_monitored_task!({ - async move { - let mut reconfig_observer_clone = reconfig_observer.clone_boxed(); - reconfig_observer_clone.run(quorum_driver_copy).await; - } - }) - }; - - Self { - quorum_driver, - effects_subscriber: subscriber_rx, - quorum_driver_metrics: self.quorum_driver_metrics.clone(), - reconfig_observer: self.reconfig_observer.clone(), - _processor_handle: processor_handle, - } - } - - pub fn clone_quorum_driver(&self) -> Arc> { - self.quorum_driver.clone() - } - - pub fn subscribe_to_effects( - &self, - ) -> tokio::sync::broadcast::Receiver { - self.effects_subscriber.resubscribe() - } - - pub fn authority_aggregator(&self) -> &ArcSwap> { - self.quorum_driver.authority_aggregator() - } - - pub fn current_epoch(&self) -> EpochId { - self.quorum_driver.current_epoch() - } - - /// Process a QuorumDriverTask. - /// The function has no return value - the corresponding actions of task - /// result are performed in this call. - async fn process_task(quorum_driver: Arc>, task: QuorumDriverTask) { - debug!(?task, "Quorum Driver processing task"); - let QuorumDriverTask { - transaction, - tx_cert, - retry_times: old_retry_times, - .. - } = task; - let tx_digest = *transaction.digest(); - let is_single_writer_tx = !transaction.contains_shared_object(); - - quorum_driver - .metrics - .transaction_retry_count - .report(old_retry_times as u64 + 1); - - let timer = Instant::now(); - let tx_cert = match tx_cert { - None => match quorum_driver.process_transaction(transaction.clone()).await { - Ok(ProcessTransactionResult::Certified(tx_cert)) => { - debug!(?tx_digest, "Transaction processing succeeded"); - tx_cert - } - Ok(ProcessTransactionResult::Executed(effects_cert, events)) => { - debug!( - ?tx_digest, - "Transaction processing succeeded with effects directly" - ); - let response = QuorumDriverResponse { - effects_cert, - events, - }; - quorum_driver.notify(&transaction, &Ok(response), old_retry_times + 1); - return; - } - Err(err) => { - Self::handle_error( - quorum_driver, - transaction, - err, - None, - old_retry_times, - "get tx cert", - ); - return; - } - }, - Some(tx_cert) => tx_cert, - }; - - let response = match quorum_driver.process_certificate(tx_cert.clone()).await { - Ok(response) => { - debug!(?tx_digest, "Certificate processing succeeded"); - response - } - // Note: non retryable failure when processing a cert - // should be very rare. - Err(err) => { - Self::handle_error( - quorum_driver, - transaction, - err, - Some(tx_cert), - old_retry_times, - "get effects cert", - ); - return; - } - }; - let settlement_finality_latency = timer.elapsed().as_secs_f64(); - quorum_driver - .metrics - .settlement_finality_latency - .with_label_values(&[if is_single_writer_tx { - TX_TYPE_SINGLE_WRITER_TX - } else { - TX_TYPE_SHARED_OBJ_TX - }]) - .observe(settlement_finality_latency); - if settlement_finality_latency >= 8.0 || settlement_finality_latency <= 0.1 { - debug!( - ?tx_digest, - "Settlement finality latency is out of expected range: {}", - settlement_finality_latency - ); - } - - quorum_driver.notify(&transaction, &Ok(response), old_retry_times + 1); - } - - fn handle_error( - quorum_driver: Arc>, - transaction: Transaction, - err: Option, - tx_cert: Option, - old_retry_times: u32, - action: &'static str, - ) { - let tx_digest = *transaction.digest(); - match err { - None => { - debug!(?tx_digest, "Failed to {action} - Retrying"); - spawn_monitored_task!(quorum_driver.enqueue_again_maybe( - transaction.clone(), - tx_cert, - old_retry_times - )); - } - Some(QuorumDriverError::SystemOverloadRetryAfter { .. }) => { - // Special case for SystemOverloadRetryAfter error. In this case, due to that - // objects are already locked inside validators, we need to - // perform continuous retry and ignore `max_retry_times`. - // TODO: the txn can potentially be retried unlimited times, therefore, we need - // to bound the number of on going transactions in a quorum - // driver. When the limit is reached, the quorum driver should - // reject any new transaction requests. - debug!(?tx_digest, "Failed to {action} - Retrying"); - spawn_monitored_task!(quorum_driver.backoff_and_enqueue( - transaction.clone(), - tx_cert, - old_retry_times - )); - } - Some(qd_error) => { - debug!(?tx_digest, "Failed to {action}: {}", qd_error); - // non-retryable failure, this task reaches terminal state for now, notify - // waiter. - quorum_driver.notify(&transaction, &Err(qd_error), old_retry_times + 1); - } - } - } - - async fn task_queue_processor( - quorum_driver: Arc>, - mut task_receiver: Receiver, - metrics: Arc, - ) { - let limit = Arc::new(Semaphore::new(TASK_QUEUE_SIZE)); - while let Some(task) = task_receiver.recv().await { - // hold semaphore permit until task completes. unwrap ok because we never close - // the semaphore in this context. - let limit = limit.clone(); - let permit = limit.acquire_owned().await.unwrap(); - - // TODO check reconfig process here - - debug!(?task, "Dequeued task"); - if Instant::now() - .checked_duration_since(task.next_retry_after) - .is_none() - { - // Not ready for next attempt yet, re-enqueue - let _ = quorum_driver.enqueue_task(task).await; - continue; - } - metrics.current_requests_in_flight.dec(); - let qd = quorum_driver.clone(); - spawn_monitored_task!(async move { - let _guard = permit; - QuorumDriverHandler::process_task(qd, task).await - }); - } - } -} - -pub struct QuorumDriverHandlerBuilder { - validators: Arc>, - metrics: Arc, - notifier: Option>>, - reconfig_observer: Option + Sync + Send>>, - max_retry_times: u32, -} - -impl QuorumDriverHandlerBuilder -where - A: AuthorityAPI + Send + Sync + 'static + Clone, -{ - pub fn new(validators: Arc>, metrics: Arc) -> Self { - Self { - validators, - metrics, - notifier: None, - reconfig_observer: None, - max_retry_times: TX_MAX_RETRY_TIMES, - } - } - - pub(crate) fn with_notifier( - mut self, - notifier: Arc>, - ) -> Self { - self.notifier = Some(notifier); - self - } - - pub fn with_reconfig_observer( - mut self, - reconfig_observer: Arc + Sync + Send>, - ) -> Self { - self.reconfig_observer = Some(reconfig_observer); - self - } - - /// Used in tests when smaller number of retries is desired - pub fn with_max_retry_times(mut self, max_retry_times: u32) -> Self { - self.max_retry_times = max_retry_times; - self - } - - pub fn start(self) -> QuorumDriverHandler { - QuorumDriverHandler::new( - self.validators, - self.notifier.unwrap_or_else(|| { - Arc::new(NotifyRead::::new()) - }), - self.reconfig_observer - .expect("Reconfig observer is missing"), - self.metrics, - self.max_retry_times, - ) - } -} diff --git a/crates/sui-core/src/quorum_driver/tests.rs b/crates/sui-core/src/quorum_driver/tests.rs deleted file mode 100644 index c59edb9d205..00000000000 --- a/crates/sui-core/src/quorum_driver/tests.rs +++ /dev/null @@ -1,525 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{sync::Arc, time::Duration}; - -use mysten_common::sync::notify_read::{NotifyRead, Registration}; -use sui_types::{ - base_types::{SuiAddress, TransactionDigest}, - crypto::{deterministic_random_account_key, get_key_pair, AccountKeyPair}, - effects::TransactionEffectsAPI, - object::{generate_test_gas_objects, Object}, - quorum_driver_types::{QuorumDriverError, QuorumDriverResponse, QuorumDriverResult}, - transaction::Transaction, -}; -use tokio::time::timeout; - -use crate::{ - quorum_driver::{ - reconfig_observer::DummyReconfigObserver, AuthorityAggregator, QuorumDriverHandlerBuilder, - QuorumDriverMetrics, - }, - test_authority_clients::{LocalAuthorityClient, LocalAuthorityClientFaultConfig}, - test_utils::{init_local_authorities, make_transfer_sui_transaction}, -}; - -async fn setup() -> (AuthorityAggregator, Transaction) { - let (sender, keypair): (_, AccountKeyPair) = get_key_pair(); - let gas_object = Object::with_owner_for_testing(sender); - let (aggregator, authorities, genesis, _) = - init_local_authorities(4, vec![gas_object.clone()]).await; - let rgp = authorities - .first() - .unwrap() - .reference_gas_price_for_testing() - .unwrap(); - let gas_object = genesis - .objects() - .iter() - .find(|o| o.id() == gas_object.id()) - .unwrap(); - - let tx = make_tx(gas_object, sender, &keypair, rgp); - (aggregator, tx) -} - -fn make_tx( - gas: &Object, - sender: SuiAddress, - keypair: &AccountKeyPair, - gas_price: u64, -) -> Transaction { - make_transfer_sui_transaction( - gas.compute_object_reference(), - SuiAddress::random_for_testing_only(), - None, - sender, - keypair, - gas_price, - ) -} - -#[tokio::test] -async fn test_quorum_driver_submit_transaction() { - let (aggregator, tx) = setup().await; - let digest = *tx.digest(); - - let quorum_driver_handler = Arc::new( - QuorumDriverHandlerBuilder::new( - Arc::new(aggregator), - Arc::new(QuorumDriverMetrics::new_for_tests()), - ) - .with_reconfig_observer(Arc::new(DummyReconfigObserver {})) - .start(), - ); - // Test submit_transaction - let qd_clone = quorum_driver_handler.clone(); - let handle = tokio::task::spawn(async move { - let (tx, QuorumDriverResponse { effects_cert, .. }) = qd_clone - .subscribe_to_effects() - .recv() - .await - .unwrap() - .unwrap(); - assert_eq!(tx.digest(), &digest); - assert_eq!(*effects_cert.data().transaction_digest(), digest); - }); - let ticket = quorum_driver_handler.submit_transaction(tx).await.unwrap(); - verify_ticket_response(ticket, &digest).await; - - handle.await.unwrap(); -} - -#[tokio::test] -async fn test_quorum_driver_submit_transaction_no_ticket() { - let (aggregator, tx) = setup().await; - let digest = *tx.digest(); - - let quorum_driver_handler = Arc::new( - QuorumDriverHandlerBuilder::new( - Arc::new(aggregator), - Arc::new(QuorumDriverMetrics::new_for_tests()), - ) - .with_reconfig_observer(Arc::new(DummyReconfigObserver {})) - .start(), - ); - let qd_clone = quorum_driver_handler.clone(); - let handle = tokio::task::spawn(async move { - let (tx, QuorumDriverResponse { effects_cert, .. }) = qd_clone - .subscribe_to_effects() - .recv() - .await - .unwrap() - .unwrap(); - assert_eq!(tx.digest(), &digest); - assert_eq!(*effects_cert.data().transaction_digest(), digest); - }); - quorum_driver_handler - .submit_transaction_no_ticket(tx) - .await - .unwrap(); - handle.await.unwrap(); -} - -async fn verify_ticket_response<'a>( - ticket: Registration<'a, TransactionDigest, QuorumDriverResult>, - tx_digest: &TransactionDigest, -) { - let QuorumDriverResponse { effects_cert, .. } = ticket.await.unwrap(); - assert_eq!(effects_cert.data().transaction_digest(), tx_digest); -} - -#[tokio::test] -async fn test_quorum_driver_with_given_notify_read() { - let (aggregator, tx) = setup().await; - let digest = *tx.digest(); - let notifier = Arc::new(NotifyRead::new()); - - let quorum_driver_handler = Arc::new( - QuorumDriverHandlerBuilder::new( - Arc::new(aggregator), - Arc::new(QuorumDriverMetrics::new_for_tests()), - ) - .with_notifier(notifier.clone()) - .with_reconfig_observer(Arc::new(DummyReconfigObserver {})) - .start(), - ); - - let qd_clone = quorum_driver_handler.clone(); - let handle = tokio::task::spawn(async move { - let (tx, QuorumDriverResponse { effects_cert, .. }) = qd_clone - .subscribe_to_effects() - .recv() - .await - .unwrap() - .unwrap(); - assert_eq!(tx.digest(), &digest); - assert_eq!(*effects_cert.data().transaction_digest(), digest); - }); - let ticket1 = notifier.register_one(&digest); - let ticket2 = quorum_driver_handler.submit_transaction(tx).await.unwrap(); - verify_ticket_response(ticket1, &digest).await; - verify_ticket_response(ticket2, &digest).await; - - handle.await.unwrap(); -} - -// TODO: add other cases for mismatched validator/client epoch -#[tokio::test] -async fn test_quorum_driver_update_validators_and_max_retry_times() { - telemetry_subscribers::init_for_testing(); - let (mut aggregator, tx) = setup().await; - let arc_aggregator = Arc::new(aggregator.clone()); - - let quorum_driver_handler = Arc::new( - QuorumDriverHandlerBuilder::new( - arc_aggregator.clone(), - Arc::new(QuorumDriverMetrics::new_for_tests()), - ) - .with_reconfig_observer(Arc::new(DummyReconfigObserver {})) - .with_max_retry_times(3) - .start(), - ); - - let quorum_driver = quorum_driver_handler.clone_quorum_driver(); - let quorum_driver_clone = quorum_driver.clone(); - let handle = tokio::task::spawn(async move { - // Wait till the epoch/committee is updated. - tokio::time::sleep(Duration::from_secs(3)).await; - - // This now will fail due to server/client epoch mismatch: - // server's epoch is 0 but client's is 10 - // This error should not happen in practice for benign validators and a working - // client - let ticket = quorum_driver.submit_transaction(tx).await.unwrap(); - // We have a timeout here to make the test fail fast if fails - match tokio::time::timeout(Duration::from_secs(20), ticket).await { - Ok(Err(QuorumDriverError::FailedWithTransientErrorAfterMaximumAttempts { - total_attempts, - })) => assert_eq!(total_attempts, 4), - _ => panic!( - "The transaction should err on SafeClient epoch check mismatch, be retried 3 times and raise QuorumDriverError::FailedWithTransientErrorAfterMaximumAttempts error" - ), - }; - }); - - // Update authority aggregator with a new epoch number, and let quorum driver - // know. - let mut committee = aggregator.clone_inner_committee_test_only(); - committee.epoch = 10; - aggregator.committee = Arc::new(committee); - quorum_driver_clone - .update_validators(Arc::new(aggregator)) - .await; - assert_eq!( - quorum_driver_handler.clone_quorum_driver().current_epoch(), - 10 - ); - - handle.await.unwrap(); -} - -#[tokio::test] -async fn test_quorum_driver_object_locked() -> Result<(), anyhow::Error> { - let gas_objects = generate_test_gas_objects(); - let (sender, keypair): (SuiAddress, AccountKeyPair) = deterministic_random_account_key(); - - let (aggregator, authorities, genesis, _) = - init_local_authorities(4, gas_objects.clone()).await; - let rgp = authorities - .first() - .unwrap() - .reference_gas_price_for_testing() - .unwrap(); - - let mut gas_objects = gas_objects - .into_iter() - .map(|o| { - genesis - .objects() - .iter() - .find(|go| go.id() == o.id()) - .unwrap() - .to_owned() - }) - .collect::>(); - - let aggregator = Arc::new(aggregator); - - let quorum_driver_handler = Arc::new( - QuorumDriverHandlerBuilder::new( - aggregator.clone(), - Arc::new(QuorumDriverMetrics::new_for_tests()), - ) - .with_reconfig_observer(Arc::new(DummyReconfigObserver {})) - .start(), - ); - - let quorum_driver = quorum_driver_handler.clone_quorum_driver(); - - let gas = gas_objects.pop().unwrap(); - let tx = make_tx(&gas, sender, &keypair, rgp); - let names: Vec<_> = aggregator.authority_clients.keys().clone().collect(); - assert_eq!(names.len(), 4); - let client0 = aggregator.clone_client_test_only(names[0]); - let client1 = aggregator.clone_client_test_only(names[1]); - let client2 = aggregator.clone_client_test_only(names[2]); - - println!("Case 0 - two validators lock the object with the same tx"); - assert!(client0.handle_transaction(tx.clone()).await.is_ok()); - assert!(client1.handle_transaction(tx.clone()).await.is_ok()); - - let tx2 = make_tx(&gas, sender, &keypair, rgp); - let res = quorum_driver.submit_transaction(tx2).await.unwrap().await; - - // Aggregator waits for all responses when it sees a conflicting tx and because - // there are not enough retryable errors to push the original tx or the most - // staked conflicting tx >= 2f+1 stake. Neither transaction can be retried - // due to client double spend and this is a fatal error. - if let Err(QuorumDriverError::ObjectsDoubleUsed { - conflicting_txes, - retried_tx, - retried_tx_success, - }) = res - { - assert_eq!(retried_tx, None); - assert_eq!(retried_tx_success, None); - assert_eq!(conflicting_txes.len(), 1); - assert_eq!(conflicting_txes.iter().next().unwrap().0, tx.digest()); - } else { - panic!( - "expect Err(QuorumDriverError::ObjectsDoubleUsed) but got {:?}", - res - ); - } - - println!("Case 1 - three validators lock the object with the same tx"); - let gas = gas_objects.pop().unwrap(); - let tx = make_tx(&gas, sender, &keypair, rgp); - - assert!(client0.handle_transaction(tx.clone()).await.is_ok()); - assert!(client1.handle_transaction(tx.clone()).await.is_ok()); - assert!(client2.handle_transaction(tx.clone()).await.is_ok()); - - let tx2 = make_tx(&gas, sender, &keypair, rgp); - - let res = quorum_driver.submit_transaction(tx2).await.unwrap().await; - // Aggregator gets three bad responses, and tries tx, which should succeed. - if let Err(QuorumDriverError::ObjectsDoubleUsed { - conflicting_txes, - retried_tx, - retried_tx_success, - }) = res - { - assert_eq!(retried_tx, Some(*tx.digest())); - assert_eq!(retried_tx_success, Some(true)); - assert_eq!(conflicting_txes.len(), 1); - assert_eq!(conflicting_txes.iter().next().unwrap().0, tx.digest()); - } else { - panic!( - "expect Err(QuorumDriverError::ObjectsDoubleUsed) but got {:?}", - res - ) - } - - println!("Case 2 - one validator locks the object"); - let gas = gas_objects.pop().unwrap(); - let tx = make_tx(&gas, sender, &keypair, rgp); - assert!(client0.handle_transaction(tx.clone()).await.is_ok()); - - let tx2 = make_tx(&gas, sender, &keypair, rgp); - let tx2_digest = *tx2.digest(); - - let res = quorum_driver - .submit_transaction(tx2) - .await - .unwrap() - .await - .unwrap(); - - // Aggregator gets three good responses and execution succeeds. - let QuorumDriverResponse { effects_cert, .. } = res; - assert_eq!(*effects_cert.transaction_digest(), tx2_digest); - - println!( - "Case 3 - object is locked by 2 txes with weight 2 and 1 respectivefully. Then try to execute the third txn" - ); - let gas = gas_objects.pop().unwrap(); - let tx = make_tx(&gas, sender, &keypair, rgp); - let tx2 = make_tx(&gas, sender, &keypair, rgp); - - assert!(client0.handle_transaction(tx.clone()).await.is_ok()); - assert!(client1.handle_transaction(tx.clone()).await.is_ok()); - assert!(client2.handle_transaction(tx2.clone()).await.is_ok()); - - let tx3 = make_tx(&gas, sender, &keypair, rgp); - - let res = quorum_driver.submit_transaction(tx3).await.unwrap().await; - - if let Err(QuorumDriverError::ObjectsDoubleUsed { - conflicting_txes, - retried_tx, - retried_tx_success, - }) = res - { - assert_eq!(retried_tx, None); - assert_eq!(retried_tx_success, None); - assert_eq!(conflicting_txes.len(), 2); - let tx_stake = conflicting_txes.get(tx.digest()).unwrap().1; - assert!(tx_stake == 2500 || tx_stake == 5000); - assert_eq!(conflicting_txes.get(tx2.digest()).unwrap().1, 2500); - } else { - panic!( - "expect Err(QuorumDriverError::ObjectsDoubleUsed) but got {:?}", - res - ) - } - - println!( - "Case 4 - object is locked by 2 txes with weight 2 and 1, try to execute the lighter stake tx" - ); - let gas = gas_objects.pop().unwrap(); - let tx = make_tx(&gas, sender, &keypair, rgp); - let tx2 = make_tx(&gas, sender, &keypair, rgp); - assert!(client0.handle_transaction(tx.clone()).await.is_ok()); - assert!(client1.handle_transaction(tx.clone()).await.is_ok()); - assert!(client2.handle_transaction(tx2.clone()).await.is_ok()); - let res = quorum_driver.submit_transaction(tx2).await.unwrap().await; - - if let Err(QuorumDriverError::ObjectsDoubleUsed { - conflicting_txes, - retried_tx, - retried_tx_success, - }) = res - { - assert_eq!(retried_tx, None); - assert_eq!(retried_tx_success, None); - assert_eq!(conflicting_txes.len(), 1); - assert_eq!(conflicting_txes.get(tx.digest()).unwrap().1, 5000); - } else { - panic!( - "expect Err(QuorumDriverError::ObjectsDoubleUsed) but got {:?}", - res - ) - } - - println!( - "Case 5 - object is locked by 2 txes with weight 2 and 1, try to execute the heavier stake tx" - ); - let gas = gas_objects.pop().unwrap(); - let tx = make_tx(&gas, sender, &keypair, rgp); - let tx_digest = *tx.digest(); - let tx2 = make_tx(&gas, sender, &keypair, rgp); - - assert!(client0.handle_transaction(tx.clone()).await.is_ok()); - assert!(client1.handle_transaction(tx.clone()).await.is_ok()); - assert!(client2.handle_transaction(tx2).await.is_ok()); - - let res = quorum_driver - .submit_transaction(tx) - .await - .unwrap() - .await - .unwrap(); - - let QuorumDriverResponse { effects_cert, .. } = res; - assert_eq!(*effects_cert.transaction_digest(), tx_digest); - - println!("Case 6 - three validators lock the object, by different txes"); - let gas = gas_objects.pop().unwrap(); - let tx = make_tx(&gas, sender, &keypair, rgp); - let tx2 = make_tx(&gas, sender, &keypair, rgp); - let tx3 = make_tx(&gas, sender, &keypair, rgp); - assert!(client0.handle_transaction(tx.clone()).await.is_ok()); - assert!(client1.handle_transaction(tx2.clone()).await.is_ok()); - assert!(client2.handle_transaction(tx3.clone()).await.is_ok()); - - let tx4 = make_tx(&gas, sender, &keypair, rgp); - let res = quorum_driver - .submit_transaction(tx4.clone()) - .await - .unwrap() - .await; - - if let Err(QuorumDriverError::ObjectsDoubleUsed { - conflicting_txes, - retried_tx, - retried_tx_success, - }) = res - { - assert_eq!(retried_tx, None); - assert_eq!(retried_tx_success, None); - assert!(conflicting_txes.len() == 3 || conflicting_txes.len() == 2); - assert!( - conflicting_txes - .iter() - .all(|(digest, (_objs, stake))| (*stake == 2500) - && (digest == tx.digest() || digest == tx2.digest() || digest == tx3.digest())) - ); - } else { - panic!( - "expect Err(QuorumDriverError::ObjectsDoubleUsed) but got {:?}", - res - ) - } - - Ok(()) -} - -// Tests that quorum driver can continuously retry txn with -// SystemOverloadedRetryAfter error. -#[tokio::test(flavor = "current_thread", start_paused = true)] -async fn test_quorum_driver_handling_overload_and_retry() { - telemetry_subscribers::init_for_testing(); - - // Setup - let (sender, keypair): (_, AccountKeyPair) = get_key_pair(); - let gas_object = Object::with_owner_for_testing(sender); - let (mut aggregator, authorities, genesis, _) = - init_local_authorities(4, vec![gas_object.clone()]).await; - - // Make local authority client to always return SystemOverloadedRetryAfter - // error. - let fault_config = LocalAuthorityClientFaultConfig { - overload_retry_after_handle_transaction: true, - ..Default::default() - }; - let mut clients = aggregator.clone_inner_clients_test_only(); - for client in &mut clients.values_mut() { - client.authority_client_mut().fault_config = fault_config; - } - let clients = clients.into_iter().map(|(k, v)| (k, Arc::new(v))).collect(); - aggregator.authority_clients = Arc::new(clients); - - // Create a transaction for the test. - let rgp = authorities - .first() - .unwrap() - .reference_gas_price_for_testing() - .unwrap(); - let gas_object = genesis - .objects() - .iter() - .find(|o| o.id() == gas_object.id()) - .unwrap(); - let tx = make_tx(gas_object, sender, &keypair, rgp); - - // Create a quorum driver with max_retry_times = 0. - let arc_aggregator = Arc::new(aggregator.clone()); - let quorum_driver_handler = Arc::new( - QuorumDriverHandlerBuilder::new( - arc_aggregator.clone(), - Arc::new(QuorumDriverMetrics::new_for_tests()), - ) - .with_reconfig_observer(Arc::new(DummyReconfigObserver {})) - .with_max_retry_times(0) - .start(), - ); - - // Submit the transaction, and check that it shouldn't return. - let ticket = quorum_driver_handler.submit_transaction(tx).await.unwrap(); - match timeout(Duration::from_secs(300), ticket).await { - Ok(result) => panic!("Process transaction should timeout! {:?}", result), - Err(_) => eprintln!("Waiting for txn timed out! This is desired behavior."), - } -} diff --git a/crates/sui-core/src/storage.rs b/crates/sui-core/src/storage.rs deleted file mode 100644 index e866091cbb8..00000000000 --- a/crates/sui-core/src/storage.rs +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::sync::Arc; - -use parking_lot::Mutex; -use sui_types::{ - base_types::TransactionDigest, - committee::{Committee, EpochId}, - digests::TransactionEventsDigest, - effects::{TransactionEffects, TransactionEvents}, - error::SuiError, - messages_checkpoint::{ - CheckpointContentsDigest, CheckpointDigest, CheckpointSequenceNumber, EndOfEpochData, - FullCheckpointContents, VerifiedCheckpoint, VerifiedCheckpointContents, - }, - object::Object, - storage::{error::Error as StorageError, ObjectKey, ObjectStore, ReadStore, WriteStore}, - transaction::VerifiedTransaction, -}; - -use crate::{ - checkpoints::CheckpointStore, - epoch::committee_store::CommitteeStore, - execution_cache::{ExecutionCacheRead, StateSyncAPI}, -}; - -#[derive(Clone)] -pub struct RocksDbStore { - // Note: All three of these Arcs point to the same object, - // but we need to store them separately to satisfy the trait bounds. - execution_cache: Arc, - object_store: Arc, - state_sync_store: Arc, - - committee_store: Arc, - checkpoint_store: Arc, - // in memory checkpoint watermark sequence numbers - highest_verified_checkpoint: Arc>>, - highest_synced_checkpoint: Arc>>, -} - -impl RocksDbStore { - pub fn new( - execution_cache: Arc, - committee_store: Arc, - checkpoint_store: Arc, - ) -> Self { - Self { - execution_cache: execution_cache.clone(), - object_store: execution_cache.clone(), - state_sync_store: execution_cache.clone(), - committee_store, - checkpoint_store, - highest_verified_checkpoint: Arc::new(Mutex::new(None)), - highest_synced_checkpoint: Arc::new(Mutex::new(None)), - } - } - - pub fn get_objects(&self, object_keys: &[ObjectKey]) -> Result>, SuiError> { - self.execution_cache.multi_get_objects_by_key(object_keys) - } - - pub fn get_last_executed_checkpoint(&self) -> Result, SuiError> { - Ok(self.checkpoint_store.get_highest_executed_checkpoint()?) - } -} - -impl ReadStore for RocksDbStore { - fn get_checkpoint_by_digest( - &self, - digest: &CheckpointDigest, - ) -> Result, StorageError> { - self.checkpoint_store - .get_checkpoint_by_digest(digest) - .map_err(Into::into) - } - - fn get_checkpoint_by_sequence_number( - &self, - sequence_number: CheckpointSequenceNumber, - ) -> Result, StorageError> { - self.checkpoint_store - .get_checkpoint_by_sequence_number(sequence_number) - .map_err(Into::into) - } - - fn get_highest_verified_checkpoint(&self) -> Result { - self.checkpoint_store - .get_highest_verified_checkpoint() - .map(|maybe_checkpoint| { - maybe_checkpoint - .expect("storage should have been initialized with genesis checkpoint") - }) - .map_err(Into::into) - } - - fn get_highest_synced_checkpoint(&self) -> Result { - self.checkpoint_store - .get_highest_synced_checkpoint() - .map(|maybe_checkpoint| { - maybe_checkpoint - .expect("storage should have been initialized with genesis checkpoint") - }) - .map_err(Into::into) - } - - fn get_lowest_available_checkpoint(&self) -> Result { - self.checkpoint_store - .get_highest_pruned_checkpoint_seq_number() - .map(|seq| seq + 1) - .map_err(Into::into) - } - - fn get_full_checkpoint_contents_by_sequence_number( - &self, - sequence_number: CheckpointSequenceNumber, - ) -> Result, StorageError> { - self.checkpoint_store - .get_full_checkpoint_contents_by_sequence_number(sequence_number) - .map_err(Into::into) - } - - fn get_full_checkpoint_contents( - &self, - digest: &CheckpointContentsDigest, - ) -> Result, StorageError> { - // First look to see if we saved the complete contents already. - if let Some(seq_num) = self - .checkpoint_store - .get_sequence_number_by_contents_digest(digest) - .map_err(sui_types::storage::error::Error::custom)? - { - let contents = self - .checkpoint_store - .get_full_checkpoint_contents_by_sequence_number(seq_num) - .map_err(sui_types::storage::error::Error::custom)?; - if contents.is_some() { - return Ok(contents); - } - } - - // Otherwise gather it from the individual components. - // Note we can't insert the constructed contents into `full_checkpoint_content`, - // because it needs to be inserted along with - // `checkpoint_sequence_by_contents_digest` and `checkpoint_content`. - // However at this point it's likely we don't know the corresponding - // sequence number yet. - self.checkpoint_store - .get_checkpoint_contents(digest) - .map_err(sui_types::storage::error::Error::custom)? - .map(|contents| { - let mut transactions = Vec::with_capacity(contents.size()); - for tx in contents.iter() { - if let (Some(t), Some(e)) = ( - self.get_transaction(&tx.transaction)?, - self.execution_cache - .get_effects(&tx.effects) - .map_err(sui_types::storage::error::Error::custom)?, - ) { - transactions.push(sui_types::base_types::ExecutionData::new( - (*t).clone().into_inner(), - e, - )) - } else { - return Result::< - Option, - sui_types::storage::error::Error, - >::Ok(None); - } - } - Ok(Some( - FullCheckpointContents::from_contents_and_execution_data( - contents, - transactions.into_iter(), - ), - )) - }) - .transpose() - .map(|contents| contents.flatten()) - .map_err(sui_types::storage::error::Error::custom) - } - - fn get_committee( - &self, - epoch: EpochId, - ) -> Result>, sui_types::storage::error::Error> { - Ok(self.committee_store.get_committee(&epoch).unwrap()) - } - - fn get_transaction( - &self, - digest: &TransactionDigest, - ) -> Result>, StorageError> { - self.execution_cache - .get_transaction_block(digest) - .map_err(StorageError::custom) - } - - fn get_transaction_effects( - &self, - digest: &TransactionDigest, - ) -> Result, StorageError> { - self.execution_cache - .get_executed_effects(digest) - .map_err(StorageError::custom) - } - - fn get_events( - &self, - digest: &TransactionEventsDigest, - ) -> Result, StorageError> { - self.execution_cache - .get_events(digest) - .map_err(StorageError::custom) - } - - fn get_latest_checkpoint(&self) -> sui_types::storage::error::Result { - self.checkpoint_store - .get_latest_certified_checkpoint() - .ok_or_else(|| { - sui_types::storage::error::Error::missing("unable to get latest checkpoint") - }) - } - - fn get_checkpoint_contents_by_digest( - &self, - digest: &CheckpointContentsDigest, - ) -> sui_types::storage::error::Result> - { - self.checkpoint_store - .get_checkpoint_contents(digest) - .map_err(sui_types::storage::error::Error::custom) - } - - fn get_checkpoint_contents_by_sequence_number( - &self, - _sequence_number: CheckpointSequenceNumber, - ) -> sui_types::storage::error::Result> - { - todo!() - } -} - -impl ObjectStore for RocksDbStore { - fn get_object( - &self, - object_id: &sui_types::base_types::ObjectID, - ) -> sui_types::storage::error::Result> { - self.object_store.get_object(object_id) - } - - fn get_object_by_key( - &self, - object_id: &sui_types::base_types::ObjectID, - version: sui_types::base_types::VersionNumber, - ) -> sui_types::storage::error::Result> { - self.object_store.get_object_by_key(object_id, version) - } -} - -impl WriteStore for RocksDbStore { - fn insert_checkpoint( - &self, - checkpoint: &VerifiedCheckpoint, - ) -> Result<(), sui_types::storage::error::Error> { - if let Some(EndOfEpochData { - next_epoch_committee, - .. - }) = checkpoint.end_of_epoch_data.as_ref() - { - let next_committee = next_epoch_committee.iter().cloned().collect(); - let committee = - Committee::new(checkpoint.epoch().checked_add(1).unwrap(), next_committee); - self.insert_committee(committee)?; - } - - self.checkpoint_store - .insert_verified_checkpoint(checkpoint) - .map_err(Into::into) - } - - fn update_highest_synced_checkpoint( - &self, - checkpoint: &VerifiedCheckpoint, - ) -> Result<(), sui_types::storage::error::Error> { - let mut locked = self.highest_synced_checkpoint.lock(); - if locked.is_some() && locked.unwrap() >= checkpoint.sequence_number { - return Ok(()); - } - self.checkpoint_store - .update_highest_synced_checkpoint(checkpoint) - .map_err(sui_types::storage::error::Error::custom)?; - *locked = Some(checkpoint.sequence_number); - Ok(()) - } - - fn update_highest_verified_checkpoint( - &self, - checkpoint: &VerifiedCheckpoint, - ) -> Result<(), sui_types::storage::error::Error> { - let mut locked = self.highest_verified_checkpoint.lock(); - if locked.is_some() && locked.unwrap() >= checkpoint.sequence_number { - return Ok(()); - } - self.checkpoint_store - .update_highest_verified_checkpoint(checkpoint) - .map_err(sui_types::storage::error::Error::custom)?; - *locked = Some(checkpoint.sequence_number); - Ok(()) - } - - fn insert_checkpoint_contents( - &self, - checkpoint: &VerifiedCheckpoint, - contents: VerifiedCheckpointContents, - ) -> Result<(), sui_types::storage::error::Error> { - self.state_sync_store - .multi_insert_transaction_and_effects(contents.transactions()) - .map_err(sui_types::storage::error::Error::custom)?; - self.checkpoint_store - .insert_verified_checkpoint_contents(checkpoint, contents) - .map_err(Into::into) - } - - fn insert_committee( - &self, - new_committee: Committee, - ) -> Result<(), sui_types::storage::error::Error> { - self.committee_store - .insert_new_committee(&new_committee) - .unwrap(); - Ok(()) - } -} diff --git a/crates/sui-core/src/test_utils.rs b/crates/sui-core/src/test_utils.rs deleted file mode 100644 index 47c8d6f00be..00000000000 --- a/crates/sui-core/src/test_utils.rs +++ /dev/null @@ -1,472 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::{BTreeMap, HashMap}, - path::PathBuf, - sync::Arc, - time::Duration, -}; - -use fastcrypto::{hash::MultisetHash, traits::KeyPair}; -use futures::future::join_all; -use move_core_types::{account_address::AccountAddress, ident_str}; -use prometheus::Registry; -use shared_crypto::intent::{Intent, IntentScope}; -use sui_config::{genesis::Genesis, local_ip_utils, node::AuthorityOverloadConfig}; -use sui_framework::BuiltInFramework; -use sui_genesis_builder::validator_info::ValidatorInfo; -use sui_macros::nondeterministic; -use sui_move_build::{BuildConfig, CompiledPackage, SuiPackageHooks}; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ - base_types::{ - random_object_ref, AuthorityName, ExecutionDigests, ObjectID, ObjectRef, SuiAddress, - TransactionDigest, - }, - committee::Committee, - crypto::{ - generate_proof_of_possession, get_key_pair, AccountKeyPair, AuthorityKeyPair, - AuthorityPublicKeyBytes, AuthoritySignInfo, AuthoritySignature, NetworkKeyPair, Signer, - SuiKeyPair, - }, - effects::{SignedTransactionEffects, TestEffectsBuilder}, - error::SuiError, - message_envelope::Message, - object::Object, - transaction::{ - CallArg, CertifiedTransaction, ObjectArg, SignedTransaction, Transaction, TransactionData, - TEST_ONLY_GAS_UNIT_FOR_TRANSFER, - }, - utils::{create_fake_transaction, to_sender_signed_transaction}, -}; -use tokio::time::timeout; -use tracing::{info, warn}; - -use crate::{ - authority::{test_authority_builder::TestAuthorityBuilder, AuthorityState}, - authority_aggregator::{AuthorityAggregator, TimeoutConfig}, - epoch::committee_store::CommitteeStore, - state_accumulator::StateAccumulator, - test_authority_clients::LocalAuthorityClient, -}; - -const WAIT_FOR_TX_TIMEOUT: Duration = Duration::from_secs(15); - -pub async fn send_and_confirm_transaction( - authority: &AuthorityState, - fullnode: Option<&AuthorityState>, - transaction: Transaction, -) -> Result<(CertifiedTransaction, SignedTransactionEffects), SuiError> { - // Make the initial request - let epoch_store = authority.load_epoch_store_one_call_per_task(); - let transaction = epoch_store.verify_transaction(transaction)?; - let response = authority - .handle_transaction(&epoch_store, transaction.clone()) - .await?; - let vote = response.status.into_signed_for_testing(); - - // Collect signatures from a quorum of authorities - let committee = authority.clone_committee_for_testing(); - let certificate = - CertifiedTransaction::new(transaction.into_message(), vec![vote.clone()], &committee) - .unwrap() - .verify_authenticated(&committee, &Default::default()) - .unwrap(); - - // Submit the confirmation. *Now* execution actually happens, and it should fail - // when we try to look up our dummy module. we unfortunately don't get a - // very descriptive error message, but we can at least see that something went - // wrong inside the VM - // - // We also check the incremental effects of the transaction on the live object - // set against StateAccumulator for testing and regression detection - let state_acc = StateAccumulator::new(authority.get_execution_cache().clone()); - let include_wrapped_tombstone = !authority - .epoch_store_for_testing() - .protocol_config() - .simplified_unwrap_then_delete(); - let mut state = state_acc.accumulate_live_object_set(include_wrapped_tombstone); - let (result, _execution_error_opt) = authority.try_execute_for_test(&certificate).await?; - let state_after = state_acc.accumulate_live_object_set(include_wrapped_tombstone); - let effects_acc = state_acc.accumulate_effects( - vec![result.inner().data().clone()], - epoch_store.protocol_config(), - ); - state.union(&effects_acc); - - assert_eq!(state_after.digest(), state.digest()); - - if let Some(fullnode) = fullnode { - fullnode.try_execute_for_test(&certificate).await?; - } - Ok((certificate.into_inner(), result.into_inner())) -} - -// note: clippy is confused about this being dead - it appears to only be used -// in cfg(test), but adding #[cfg(test)] causes other targets to fail -#[allow(dead_code)] -pub(crate) fn init_state_parameters_from_rng(rng: &mut R) -> (Genesis, AuthorityKeyPair) -where - R: rand::CryptoRng + rand::RngCore, -{ - let dir = nondeterministic!(tempfile::TempDir::new().unwrap()); - let network_config = sui_swarm_config::network_config_builder::ConfigBuilder::new(&dir) - .rng(rng) - .build(); - let genesis = network_config.genesis; - let authority_key = network_config.validator_configs[0] - .protocol_key_pair() - .copy(); - - (genesis, authority_key) -} - -pub async fn wait_for_tx(digest: TransactionDigest, state: Arc) { - match timeout( - WAIT_FOR_TX_TIMEOUT, - state - .get_cache_reader() - .notify_read_executed_effects(&[digest]), - ) - .await - { - Ok(_) => info!(?digest, "digest found"), - Err(e) => { - warn!(?digest, "digest not found!"); - panic!("timed out waiting for effects of digest! {e}"); - } - } -} - -pub async fn wait_for_all_txes(digests: Vec, state: Arc) { - match timeout( - WAIT_FOR_TX_TIMEOUT, - state - .get_cache_reader() - .notify_read_executed_effects(&digests), - ) - .await - { - Ok(_) => info!(?digests, "all digests found"), - Err(e) => { - warn!(?digests, "some digests not found!"); - panic!("timed out waiting for effects of digests! {e}"); - } - } -} - -pub fn create_fake_cert_and_effect_digest<'a>( - signers: impl Iterator< - Item = ( - &'a AuthorityName, - &'a (dyn Signer + Send + Sync), - ), - >, - committee: &Committee, -) -> (ExecutionDigests, CertifiedTransaction) { - let transaction = create_fake_transaction(); - let cert = CertifiedTransaction::new( - transaction.data().clone(), - signers - .map(|(name, signer)| { - AuthoritySignInfo::new( - committee.epoch, - transaction.data(), - Intent::sui_app(IntentScope::SenderSignedTransaction), - *name, - signer, - ) - }) - .collect(), - committee, - ) - .unwrap(); - let effects = TestEffectsBuilder::new(transaction.data()).build(); - ( - ExecutionDigests::new(*transaction.digest(), effects.digest()), - cert, - ) -} - -pub fn compile_basics_package() -> CompiledPackage { - compile_example_package("../../sui_programmability/examples/basics") -} - -pub fn compile_managed_coin_package() -> CompiledPackage { - compile_example_package("../../crates/sui-core/src/unit_tests/data/managed_coin") -} - -pub fn compile_example_package(relative_path: &str) -> CompiledPackage { - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.push(relative_path); - - BuildConfig::new_for_testing().build(path).unwrap() -} - -async fn init_genesis( - committee_size: usize, - mut genesis_objects: Vec, -) -> ( - Genesis, - Vec<(AuthorityPublicKeyBytes, AuthorityKeyPair)>, - ObjectID, -) { - // add object_basics package object to genesis - let modules: Vec<_> = compile_basics_package().get_modules().cloned().collect(); - let genesis_move_packages: Vec<_> = BuiltInFramework::genesis_move_packages().collect(); - let pkg = Object::new_package( - &modules, - TransactionDigest::genesis_marker(), - ProtocolConfig::get_for_max_version_UNSAFE().max_move_package_size(), - &genesis_move_packages, - ) - .unwrap(); - let pkg_id = pkg.id(); - genesis_objects.push(pkg); - - let mut builder = sui_genesis_builder::Builder::new().add_objects(genesis_objects); - let mut key_pairs = Vec::new(); - for i in 0..committee_size { - let key_pair: AuthorityKeyPair = get_key_pair().1; - let authority_name = key_pair.public().into(); - let worker_key_pair: NetworkKeyPair = get_key_pair().1; - let worker_name = worker_key_pair.public().clone(); - let account_key_pair: SuiKeyPair = get_key_pair::().1.into(); - let network_key_pair: NetworkKeyPair = get_key_pair().1; - let validator_info = ValidatorInfo { - name: format!("validator-{i}"), - protocol_key: authority_name, - worker_key: worker_name, - account_address: SuiAddress::from(&account_key_pair.public()), - network_key: network_key_pair.public().clone(), - gas_price: 1, - commission_rate: 0, - network_address: local_ip_utils::new_local_tcp_address_for_testing(), - p2p_address: local_ip_utils::new_local_udp_address_for_testing(), - narwhal_primary_address: local_ip_utils::new_local_udp_address_for_testing(), - narwhal_worker_address: local_ip_utils::new_local_udp_address_for_testing(), - description: String::new(), - image_url: String::new(), - project_url: String::new(), - }; - let pop = generate_proof_of_possession(&key_pair, (&account_key_pair.public()).into()); - builder = builder.add_validator(validator_info, pop); - key_pairs.push((authority_name, key_pair)); - } - for (_, key) in &key_pairs { - builder = builder.add_validator_signature(key); - } - let genesis = builder.build(); - (genesis, key_pairs, pkg_id) -} - -pub async fn init_local_authorities( - committee_size: usize, - genesis_objects: Vec, -) -> ( - AuthorityAggregator, - Vec>, - Genesis, - ObjectID, -) { - let (genesis, key_pairs, framework) = init_genesis(committee_size, genesis_objects).await; - let authorities = join_all(key_pairs.iter().map(|(_, key_pair)| { - TestAuthorityBuilder::new() - .with_genesis_and_keypair(&genesis, key_pair) - .build() - })) - .await; - let aggregator = init_local_authorities_with_genesis(&genesis, authorities.clone()).await; - (aggregator, authorities, genesis, framework) -} - -pub async fn init_local_authorities_with_overload_thresholds( - committee_size: usize, - genesis_objects: Vec, - overload_thresholds: AuthorityOverloadConfig, -) -> ( - AuthorityAggregator, - Vec>, - Genesis, - ObjectID, -) { - let (genesis, key_pairs, framework) = init_genesis(committee_size, genesis_objects).await; - let authorities = join_all(key_pairs.iter().map(|(_, key_pair)| { - TestAuthorityBuilder::new() - .with_genesis_and_keypair(&genesis, key_pair) - .with_authority_overload_config(overload_thresholds.clone()) - .build() - })) - .await; - let aggregator = init_local_authorities_with_genesis(&genesis, authorities.clone()).await; - (aggregator, authorities, genesis, framework) -} - -pub async fn init_local_authorities_with_genesis( - genesis: &Genesis, - authorities: Vec>, -) -> AuthorityAggregator { - telemetry_subscribers::init_for_testing(); - let committee = genesis.committee().unwrap(); - - let mut clients = BTreeMap::new(); - for state in authorities { - let name = state.name; - let client = LocalAuthorityClient::new_from_authority(state); - clients.insert(name, client); - } - let timeouts = TimeoutConfig { - pre_quorum_timeout: Duration::from_secs(5), - post_quorum_timeout: Duration::from_secs(5), - serial_authority_request_interval: Duration::from_secs(1), - }; - let committee_store = Arc::new(CommitteeStore::new_for_testing(&committee)); - AuthorityAggregator::new_with_timeouts( - committee, - committee_store, - clients, - &Registry::new(), - Arc::new(HashMap::new()), - timeouts, - ) -} - -pub fn make_transfer_sui_transaction( - gas_object: ObjectRef, - recipient: SuiAddress, - amount: Option, - sender: SuiAddress, - keypair: &AccountKeyPair, - gas_price: u64, -) -> Transaction { - let data = TransactionData::new_transfer_sui( - recipient, - sender, - amount, - gas_object, - gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, - gas_price, - ); - to_sender_signed_transaction(data, keypair) -} - -pub fn make_pay_sui_transaction( - gas_object: ObjectRef, - coins: Vec, - recipients: Vec, - amounts: Vec, - sender: SuiAddress, - keypair: &AccountKeyPair, - gas_price: u64, - gas_budget: u64, -) -> Transaction { - let data = TransactionData::new_pay_sui( - sender, coins, recipients, amounts, gas_object, gas_budget, gas_price, - ) - .unwrap(); - to_sender_signed_transaction(data, keypair) -} - -pub fn make_transfer_object_transaction( - object_ref: ObjectRef, - gas_object: ObjectRef, - sender: SuiAddress, - keypair: &AccountKeyPair, - recipient: SuiAddress, - gas_price: u64, -) -> Transaction { - let data = TransactionData::new_transfer( - recipient, - object_ref, - sender, - gas_object, - gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER * 10, - gas_price, - ); - to_sender_signed_transaction(data, keypair) -} - -pub fn make_transfer_object_move_transaction( - src: SuiAddress, - keypair: &AccountKeyPair, - dest: SuiAddress, - object_ref: ObjectRef, - framework_obj_id: ObjectID, - gas_object_ref: ObjectRef, - gas_budget_in_units: u64, - gas_price: u64, -) -> Transaction { - let args = vec![ - CallArg::Object(ObjectArg::ImmOrOwnedObject(object_ref)), - CallArg::Pure(bcs::to_bytes(&AccountAddress::from(dest)).unwrap()), - ]; - - to_sender_signed_transaction( - TransactionData::new_move_call( - src, - framework_obj_id, - ident_str!("object_basics").to_owned(), - ident_str!("transfer").to_owned(), - Vec::new(), - gas_object_ref, - args, - gas_budget_in_units * gas_price, - gas_price, - ) - .unwrap(), - keypair, - ) -} - -/// Make a dummy tx that uses random object refs. -pub fn make_dummy_tx( - receiver: SuiAddress, - sender: SuiAddress, - sender_sec: &AccountKeyPair, -) -> Transaction { - Transaction::from_data_and_signer( - TransactionData::new_transfer( - receiver, - random_object_ref(), - sender, - random_object_ref(), - TEST_ONLY_GAS_UNIT_FOR_TRANSFER * 10, - 10, - ), - vec![sender_sec], - ) -} - -/// Make a cert using an arbitrarily large committee. -pub fn make_cert_with_large_committee( - committee: &Committee, - key_pairs: &[AuthorityKeyPair], - transaction: &Transaction, -) -> CertifiedTransaction { - // assumes equal weighting. - let len = committee.voting_rights.len(); - assert_eq!(len, key_pairs.len()); - let count = (len * 2 + 2) / 3; - - let sigs: Vec<_> = key_pairs - .iter() - .take(count) - .map(|key_pair| { - SignedTransaction::new( - committee.epoch(), - transaction.clone().into_data(), - key_pair, - AuthorityPublicKeyBytes::from(key_pair.public()), - ) - .auth_sig() - .clone() - }) - .collect(); - - let cert = CertifiedTransaction::new(transaction.clone().into_data(), sigs, committee).unwrap(); - cert.verify_signatures_authenticated(committee, &Default::default()) - .unwrap(); - cert -} diff --git a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest/sources/main.move b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest/sources/main.move deleted file mode 100644 index 923954f53ff..00000000000 --- a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest/sources/main.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module main::main { - public entry fun main() {} -} diff --git a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/sources/main.move b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/sources/main.move deleted file mode 100644 index 923954f53ff..00000000000 --- a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/sources/main.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module main::main { - public entry fun main() {} -} diff --git a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/sources/main.move b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/sources/main.move deleted file mode 100644 index 923954f53ff..00000000000 --- a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/sources/main.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module main::main { - public entry fun main() {} -} diff --git a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/sources/main.move b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/sources/main.move deleted file mode 100644 index 923954f53ff..00000000000 --- a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/sources/main.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module main::main { - public entry fun main() {} -} diff --git a/crates/sui-core/src/unit_tests/data/depends_on_basics/Move.toml b/crates/sui-core/src/unit_tests/data/depends_on_basics/Move.toml deleted file mode 100644 index 6cc128bb0d2..00000000000 --- a/crates/sui-core/src/unit_tests/data/depends_on_basics/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "DependsOnBasics" -version = "0.0.0" - -[dependencies] -Examples = { local = "../object_basics" } -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -depends = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/depends_on_basics/sources/depends_on_basics.move b/crates/sui-core/src/unit_tests/data/depends_on_basics/sources/depends_on_basics.move deleted file mode 100644 index ae1aedc87ef..00000000000 --- a/crates/sui-core/src/unit_tests/data/depends_on_basics/sources/depends_on_basics.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Test depending on another unpublished package, which is published -/// along with your own. -module depends::depends_on_basics { - use examples::object_basics; - use sui::tx_context::TxContext; - - public entry fun delegate(ctx: &mut TxContext) { - object_basics::share(ctx); - } -} diff --git a/crates/sui-core/src/unit_tests/data/entry_point_types/Move.lock b/crates/sui-core/src/unit_tests/data/entry_point_types/Move.lock deleted file mode 100644 index c4c4dba5fa4..00000000000 --- a/crates/sui-core/src/unit_tests/data/entry_point_types/Move.lock +++ /dev/null @@ -1,22 +0,0 @@ -# @generated by Move, please check-in and do not edit manually. - -[move] -version = 0 -manifest_digest = "767739C9147CAC379CE17A273955EE03EF28351CE7D26C3C286A02AAA14FB302" -deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082" - -dependencies = [ - { name = "Sui" }, -] - -[[move.package]] -name = "MoveStdlib" -source = { local = "../../../../../sui-framework/packages/move-stdlib" } - -[[move.package]] -name = "Sui" -source = { local = "../../../../../sui-framework/packages/sui-framework" } - -dependencies = [ - { name = "MoveStdlib" }, -] diff --git a/crates/sui-core/src/unit_tests/data/entry_point_types/Move.toml b/crates/sui-core/src/unit_tests/data/entry_point_types/Move.toml deleted file mode 100644 index 2df0f22bc28..00000000000 --- a/crates/sui-core/src/unit_tests/data/entry_point_types/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "entry_point_types" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -entry_point_types = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/entry_point_vector/Move.lock b/crates/sui-core/src/unit_tests/data/entry_point_vector/Move.lock deleted file mode 100644 index 6bb00e75241..00000000000 --- a/crates/sui-core/src/unit_tests/data/entry_point_vector/Move.lock +++ /dev/null @@ -1,22 +0,0 @@ -# @generated by Move, please check-in and do not edit manually. - -[move] -version = 0 -manifest_digest = "5EDC4495EB1E648D2099207F79D616639179085FA517FC2CE705753805534B04" -deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082" - -dependencies = [ - { name = "Sui" }, -] - -[[move.package]] -name = "MoveStdlib" -source = { local = "../../../../../sui-framework/packages/move-stdlib" } - -[[move.package]] -name = "Sui" -source = { local = "../../../../../sui-framework/packages/sui-framework" } - -dependencies = [ - { name = "MoveStdlib" }, -] diff --git a/crates/sui-core/src/unit_tests/data/entry_point_vector/Move.toml b/crates/sui-core/src/unit_tests/data/entry_point_vector/Move.toml deleted file mode 100644 index fd0624134ad..00000000000 --- a/crates/sui-core/src/unit_tests/data/entry_point_vector/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "entry_point_vector" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -entry_point_vector = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/generate_move_lock_file/Move.toml b/crates/sui-core/src/unit_tests/data/generate_move_lock_file/Move.toml deleted file mode 100644 index 3ddac81086d..00000000000 --- a/crates/sui-core/src/unit_tests/data/generate_move_lock_file/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "GenerateMoveLockFile" -version = "0.0.0" - -[dependencies] -Examples = { local = "../object_basics" } -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -depends = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/generate_move_lock_file/sources/depends_on_basics.move b/crates/sui-core/src/unit_tests/data/generate_move_lock_file/sources/depends_on_basics.move deleted file mode 100644 index 87b6921fecb..00000000000 --- a/crates/sui-core/src/unit_tests/data/generate_move_lock_file/sources/depends_on_basics.move +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Create a dependency on a package to test Move.lock generation. -module depends::depends_on_basics { - use examples::object_basics; - use sui::tx_context::TxContext; - - public entry fun delegate(ctx: &mut TxContext) { - object_basics::share(ctx); - } -} diff --git a/crates/sui-core/src/unit_tests/data/managed_coin/Move.toml b/crates/sui-core/src/unit_tests/data/managed_coin/Move.toml deleted file mode 100644 index dec194717b6..00000000000 --- a/crates/sui-core/src/unit_tests/data/managed_coin/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "FungibleTokens" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -fungible_tokens = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/managed_coin/sources/managed.move b/crates/sui-core/src/unit_tests/data/managed_coin/sources/managed.move deleted file mode 100644 index 4659577ceec..00000000000 --- a/crates/sui-core/src/unit_tests/data/managed_coin/sources/managed.move +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// A module to test coin index. -module fungible_tokens::managed { - use std::option; - use sui::coin::{Self, Coin, TreasuryCap}; - use sui::transfer; - use sui::object::{Self, UID}; - use sui::table_vec::{Self, TableVec}; - use sui::tx_context::{Self, TxContext}; - - struct PublicRedEnvelope has key, store { - id: UID, - coins: TableVec>, - } - - /// Name of the coin. By convention, this type has the same name as its parent module - /// and has no fields. The full type of the coin defined by this module will be `COIN`. - struct MANAGED has drop {} - - /// Register the managed currency to acquire its `TreasuryCap`. Because - /// this is a module initializer, it ensures the currency only gets - /// registered once. - fun init(witness: MANAGED, ctx: &mut TxContext) { - // Get a treasury cap for the coin and give it to the transaction sender - let (treasury_cap, metadata) = coin::create_currency(witness, 2, b"MANAGED", b"", b"", option::none(), ctx); - transfer::public_freeze_object(metadata); - transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); - - let red_envelopes = PublicRedEnvelope { id: object::new(ctx), coins: table_vec::empty(ctx) }; - transfer::share_object(red_envelopes) - } - - public entry fun mint( - treasury_cap: &mut TreasuryCap, amount: u64, recipient: address, ctx: &mut TxContext - ) { - coin::mint_and_transfer(treasury_cap, amount, recipient, ctx) - } - - public entry fun mint_multi( - treasury_cap: &mut TreasuryCap, amount: u64, num: u64, recipient: address, ctx: &mut TxContext - ) { - let i = 0; - while (i < num) { - coin::mint_and_transfer(treasury_cap, amount, recipient, ctx); - i = i + 1; - } - } - - public entry fun add_to_envelope( - red_envelopes: &mut PublicRedEnvelope, coin: Coin, - ) { - table_vec::push_back(&mut red_envelopes.coins, coin) - } - - public entry fun take_from_envelope( - red_envelopes: &mut PublicRedEnvelope, ctx: &mut TxContext - ) { - let coin = table_vec::pop_back(&mut red_envelopes.coins); - transfer::public_transfer(coin, tx_context::sender(ctx)) - } - - public entry fun take_from_envelope_and_burn( - treasury_cap: &mut TreasuryCap, - red_envelopes: &mut PublicRedEnvelope, - ) { - let coin = table_vec::pop_back(&mut red_envelopes.coins); - coin::burn(treasury_cap, coin); - } - - public entry fun burn(treasury_cap: &mut TreasuryCap, coin: Coin) { - coin::burn(treasury_cap, coin); - } -} diff --git a/crates/sui-core/src/unit_tests/data/move_package/A/sources/a.move b/crates/sui-core/src/unit_tests/data/move_package/A/sources/a.move deleted file mode 100644 index 6109094ac90..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_package/A/sources/a.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module a::a { - public fun a(): u64 { - b::b::b() - } -} diff --git a/crates/sui-core/src/unit_tests/data/move_package/B/sources/b.move b/crates/sui-core/src/unit_tests/data/move_package/B/sources/b.move deleted file mode 100644 index 007060afd1e..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_package/B/sources/b.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::b { - public fun b(): u64 { - c::c::c() - } -} diff --git a/crates/sui-core/src/unit_tests/data/move_package/Bv2/sources/b.move b/crates/sui-core/src/unit_tests/data/move_package/Bv2/sources/b.move deleted file mode 100644 index 007060afd1e..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_package/Bv2/sources/b.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::b { - public fun b(): u64 { - c::c::c() - } -} diff --git a/crates/sui-core/src/unit_tests/data/move_package/Cv1/sources/c.move b/crates/sui-core/src/unit_tests/data/move_package/Cv1/sources/c.move deleted file mode 100644 index 7e5ede6c68a..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_package/Cv1/sources/c.move +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module c::c { - struct C { - x: u64 - } - - public fun c(): u64 { - 42 - } -} diff --git a/crates/sui-core/src/unit_tests/data/move_package/Cv2/sources/c.move b/crates/sui-core/src/unit_tests/data/move_package/Cv2/sources/c.move deleted file mode 100644 index 7a4fdd2dae9..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_package/Cv2/sources/c.move +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module c::c { - struct C { - x: u64 - } - - struct D { - x: u64, - y: u64, - } - - public fun c(): u64 { - 43 - } -} diff --git a/crates/sui-core/src/unit_tests/data/move_random/Move.toml b/crates/sui-core/src/unit_tests/data/move_random/Move.toml deleted file mode 100644 index ae27152bbd3..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_random/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "Examples" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -examples = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade/sources/base.move deleted file mode 100644 index c5f21e157d6..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade/sources/base.move +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - - struct A { - f1: bool, - f2: T - } - - // new struct is fine - struct B { - f2: bool, - f1: T, - } - - friend base_addr::friend_module; - - // new function is fine - public fun return_1(): u64 { 1 } - - public fun return_0(): u64 { abort 42 } - - public fun plus_1(x: u64): u64 { x + 1 } - - public(friend) fun friend_fun(x: u64): u64 { x } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } - - entry fun entry_fun() { } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade/sources/friend_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade/sources/friend_module.move deleted file mode 100644 index b9e83eed8f8..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade/sources/friend_module.move +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::friend_module { - - struct A { - field1: u64, - field2: T - } - - public fun friend_call(): u64 { base_addr::base::friend_fun(1) } - - public fun return_0(): u64 { 0 } - - public fun plus_1(x: u64): u64 { x + 1 } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/sources/base.move deleted file mode 100644 index 227d48a9f10..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/sources/base.move +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - - struct A { - f1: bool, - f2: T - } - - // new struct is fine - struct B { - f2: bool, - f1: T, - } - - friend base_addr::friend_module; - - // new function is fine - public fun return_1(): u64 { 1 } - - public fun return_0(): u64 { 0 } - - public fun plus_1(x: u64): u64 { x + 1 } - - public(friend) fun friend_fun(x: u64): u64 { x } - - // This is invalid since I just changed the code - fun non_public_fun(y: bool): u64 { if (y) 0 else 2 } - - entry fun entry_fun() { } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/sources/friend_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/sources/friend_module.move deleted file mode 100644 index b9e83eed8f8..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/additive_upgrade_invalid/sources/friend_module.move +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::friend_module { - - struct A { - field1: u64, - field2: T - } - - public fun friend_call(): u64 { base_addr::base::friend_fun(1) } - - public fun return_0(): u64 { 0 } - - public fun plus_1(x: u64): u64 { x + 1 } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/base/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/base/sources/base.move deleted file mode 100644 index 0f6404540be..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/base/sources/base.move +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - - struct A { - f1: bool, - f2: T - } - - friend base_addr::friend_module; - - public fun return_0(): u64 { abort 42 } - - public fun plus_1(x: u64): u64 { x + 1 } - - public(friend) fun friend_fun(x: u64): u64 { x } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } - - entry fun entry_fun() { } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/base/sources/friend_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/base/sources/friend_module.move deleted file mode 100644 index b9e83eed8f8..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/base/sources/friend_module.move +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::friend_module { - - struct A { - field1: u64, - field2: T - } - - public fun friend_call(): u64 { base_addr::base::friend_fun(1) } - - public fun return_0(): u64 { 0 } - - public fun plus_1(x: u64): u64 { x + 1 } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/base_as_dep/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/base_as_dep/sources/base.move deleted file mode 100644 index ac3043d787a..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/base_as_dep/sources/base.move +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - - struct A { - f1: bool, - f2: T - } - - friend base_addr::friend_module; - - public fun return_0(): u64 { 0 } - - public fun plus_1(x: u64): u64 { x + 1 } - - public(friend) fun friend_fun(x: u64): u64 { x } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } - - entry fun entry_fun() { } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/base_as_dep/sources/friend_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/base_as_dep/sources/friend_module.move deleted file mode 100644 index b9e83eed8f8..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/base_as_dep/sources/friend_module.move +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::friend_module { - - struct A { - field1: u64, - field2: T - } - - public fun friend_call(): u64 { base_addr::base::friend_fun(1) } - - public fun return_0(): u64 { 0 } - - public fun plus_1(x: u64): u64 { x + 1 } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/compatibility_invalid/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/compatibility_invalid/sources/base.move deleted file mode 100644 index 2fd8f3f00f2..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/compatibility_invalid/sources/base.move +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - - struct A { - f1: bool, - f2: T - } - - friend base_addr::friend_module; - - public fun return_0(): u64 { 0 } - - public fun plus_1(x: u64, y: u64): u64 { x + y } - - public(friend) fun friend_fun(x: u64): u64 { x } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } - - entry fun entry_fun() { } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/compatibility_invalid/sources/friend_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/compatibility_invalid/sources/friend_module.move deleted file mode 100644 index b9e83eed8f8..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/compatibility_invalid/sources/friend_module.move +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::friend_module { - - struct A { - field1: u64, - field2: T - } - - public fun friend_call(): u64 { base_addr::base::friend_fun(1) } - - public fun return_0(): u64 { 0 } - - public fun plus_1(x: u64): u64 { x + 1 } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_dep/sources/my_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_dep/sources/my_module.move deleted file mode 100644 index 443dc4ce4fa..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_dep/sources/my_module.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module a::my_module { - use dep_on_upgrading_package::my_module; - - public fun call_return_0(): u64 { my_module::call_return_0() } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package/sources/my_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package/sources/my_module.move deleted file mode 100644 index 331b0f3fde0..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package/sources/my_module.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module dep_on_upgrading_package::my_module { - use base_addr::base; - - public fun call_return_0(): u64 { base::return_0() } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_transitive/sources/my_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_transitive/sources/my_module.move deleted file mode 100644 index c7464cb6fcc..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_transitive/sources/my_module.move +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module dep_on_upgrading_package_transitive::my_module { - use base_addr::base; - use dep_on_upgrading_package::my_module; - - public fun call_return_0(): u64 { my_module::call_return_0() + base::return_0() } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_upgradeable/sources/my_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_upgradeable/sources/my_module.move deleted file mode 100644 index 331b0f3fde0..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_on_upgrading_package_upgradeable/sources/my_module.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module dep_on_upgrading_package::my_module { - use base_addr::base; - - public fun call_return_0(): u64 { base::return_0() } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/Move.toml b/crates/sui-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/Move.toml deleted file mode 100644 index e17102d9366..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "package_upgrade_base" -version = "0.0.1" - -[addresses] -base_addr = "0x0" - -[dependencies] -Sui = { local = "../../../../../../sui-framework/packages/sui-framework" } diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/sources/base.move deleted file mode 100644 index 0f6404540be..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/sources/base.move +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - - struct A { - f1: bool, - f2: T - } - - friend base_addr::friend_module; - - public fun return_0(): u64 { abort 42 } - - public fun plus_1(x: u64): u64 { x + 1 } - - public(friend) fun friend_fun(x: u64): u64 { x } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } - - entry fun entry_fun() { } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/sources/friend_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/sources/friend_module.move deleted file mode 100644 index b9e83eed8f8..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/dep_only_upgrade/sources/friend_module.move +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::friend_module { - - struct A { - field1: u64, - field2: T - } - - public fun friend_call(): u64 { base_addr::base::friend_fun(1) } - - public fun return_0(): u64 { 0 } - - public fun plus_1(x: u64): u64 { x + 1 } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/makes_another_object/Move.toml b/crates/sui-core/src/unit_tests/data/move_upgrade/makes_another_object/Move.toml deleted file mode 100644 index d9f51c8345b..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/makes_another_object/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "makes_another_object" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../../sui-framework/packages/sui-framework" } - -[addresses] -base_addr = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/makes_another_object/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/makes_another_object/sources/base.move deleted file mode 100644 index db56bf6ff82..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/makes_another_object/sources/base.move +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer; - use sui::event; - - struct A { - f1: bool, - f2: T - } - - struct B has key { - id: UID, - x: u64, - } - - struct BModEvent has copy, drop { - old: u64, - new: u64, - } - - struct C has key { - id: UID, - x: u64, - } - - struct CModEvent has copy, drop { - old: u64, - new: u64, - } - - friend base_addr::friend_module; - - public fun return_0(): u64 { abort 42 } - - public fun plus_1(x: u64): u64 { x + 1 } - - public(friend) fun friend_fun(x: u64): u64 { x } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } - - entry fun makes_b(ctx: &mut TxContext) { - transfer::transfer( - B { id: object::new(ctx), x: 42 }, - tx_context::sender(ctx), - ) - } - - entry fun destroys_b(b: B) { - let B { id, x: _ } = b; - object::delete(id); - } - - entry fun modifies_b(b: B, ctx: &mut TxContext) { - event::emit(BModEvent{ old: b.x, new: 7 }); - b.x = 7; - transfer::transfer(b, tx_context::sender(ctx)) - } - - entry fun makes_c(ctx: &mut TxContext) { - transfer::transfer( - C { id: object::new(ctx), x: 42 }, - tx_context::sender(ctx), - ) - } - - entry fun modifies_c(c: C, ctx: &mut TxContext) { - event::emit(CModEvent{ old: c.x, new: 7 }); - c.x = 7; - transfer::transfer(c, tx_context::sender(ctx)) - } - - -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/makes_another_object/sources/friend_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/makes_another_object/sources/friend_module.move deleted file mode 100644 index b9e83eed8f8..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/makes_another_object/sources/friend_module.move +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::friend_module { - - struct A { - field1: u64, - field2: T - } - - public fun friend_call(): u64 { base_addr::base::friend_fun(1) } - - public fun return_0(): u64 { 0 } - - public fun plus_1(x: u64): u64 { x + 1 } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/makes_new_object/Move.toml b/crates/sui-core/src/unit_tests/data/move_upgrade/makes_new_object/Move.toml deleted file mode 100644 index 93216ad9ce8..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/makes_new_object/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "makes_new_object" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../../sui-framework/packages/sui-framework" } - -[addresses] -base_addr = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/makes_new_object/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/makes_new_object/sources/base.move deleted file mode 100644 index 8989a2a6a2f..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/makes_new_object/sources/base.move +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer; - use sui::event; - - struct A { - f1: bool, - f2: T - } - - struct B has key { - id: UID, - x: u64, - } - - struct BModEvent has copy, drop { - old: u64, - new: u64, - } - - friend base_addr::friend_module; - - public fun return_0(): u64 { abort 42 } - - public fun plus_1(x: u64): u64 { x + 1 } - - public(friend) fun friend_fun(x: u64): u64 { x } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } - - entry fun makes_b(ctx: &mut TxContext) { - transfer::transfer( - B { id: object::new(ctx), x: 42 }, - tx_context::sender(ctx), - ) - } - - entry fun destroys_b(b: B) { - let B { id, x: _ } = b; - object::delete(id); - } - - entry fun modifies_b(b: B, ctx: &mut TxContext) { - event::emit(BModEvent{ old: b.x, new: 7 }); - b.x = 7; - transfer::transfer(b, tx_context::sender(ctx)) - } - -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/makes_new_object/sources/friend_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/makes_new_object/sources/friend_module.move deleted file mode 100644 index b9e83eed8f8..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/makes_new_object/sources/friend_module.move +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::friend_module { - - struct A { - field1: u64, - field2: T - } - - public fun friend_call(): u64 { base_addr::base::friend_fun(1) } - - public fun return_0(): u64 { 0 } - - public fun plus_1(x: u64): u64 { x + 1 } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v1/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v1/sources/base.move deleted file mode 100644 index e8a1e64ca57..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v1/sources/base.move +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - - struct A { - f1: bool, - f2: T - } - - public fun return_0(): u64 { abort 42 } - - public fun plus_1(x: u64): u64 { x + 1 } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } - - entry fun entry_fun() { } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v1/sources/other_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v1/sources/other_module.move deleted file mode 100644 index 20211f316d0..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v1/sources/other_module.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::other_module { - struct X {} -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v2/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v2/sources/base.move deleted file mode 100644 index e8a1e64ca57..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v2/sources/base.move +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - - struct A { - f1: bool, - f2: T - } - - public fun return_0(): u64 { abort 42 } - - public fun plus_1(x: u64): u64 { x + 1 } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } - - entry fun entry_fun() { } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v2/sources/other_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v2/sources/other_module.move deleted file mode 100644 index b13184b84f3..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v2/sources/other_module.move +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::other_module { -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v2_module_removed/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v2_module_removed/sources/base.move deleted file mode 100644 index e8a1e64ca57..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/missing_type_v2_module_removed/sources/base.move +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - - struct A { - f1: bool, - f2: T - } - - public fun return_0(): u64 { abort 42 } - - public fun plus_1(x: u64): u64 { x + 1 } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } - - entry fun entry_fun() { } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/new_object/Move.toml b/crates/sui-core/src/unit_tests/data/move_upgrade/new_object/Move.toml deleted file mode 100644 index d4061410269..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/new_object/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "new_object" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../../sui-framework/packages/sui-framework" } - -[addresses] -base_addr = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/new_object/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/new_object/sources/base.move deleted file mode 100644 index c88d82faa7d..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/new_object/sources/base.move +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - use sui::object::UID; - - struct A { - f1: bool, - f2: T - } - - struct B has key { - id: UID, - x: u64, - } - - friend base_addr::friend_module; - - - public fun return_0(): u64 { abort 42 } - - public fun plus_1(x: u64): u64 { x + 1 } - - public(friend) fun friend_fun(x: u64): u64 { x } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/new_object/sources/friend_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/new_object/sources/friend_module.move deleted file mode 100644 index b9e83eed8f8..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/new_object/sources/friend_module.move +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::friend_module { - - struct A { - field1: u64, - field2: T - } - - public fun friend_call(): u64 { base_addr::base::friend_fun(1) } - - public fun return_0(): u64 { 0 } - - public fun plus_1(x: u64): u64 { x + 1 } - - fun non_public_fun(y: bool): u64 { if (y) 0 else 1 } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/Move.toml b/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/Move.toml deleted file mode 100644 index 159470bfaea..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "object_cross_module_ref" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../../sui-framework/packages/sui-framework" } - -[addresses] -base_addr = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/sources/base.move deleted file mode 100644 index 8adf7c9f675..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/sources/base.move +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer; - use base_addr::friend_module::{Self, X}; - - struct A has store, drop { - v: u16, - } - - struct B has key { - id: UID, - field1: u32, - field2: A, - } - - struct C has key { - id: UID, - field1: u64, - field2: X, - } - - entry fun make_objs(ctx: &mut TxContext) { - let field2 = A { v: 128 }; - transfer::transfer( - B { id: object::new(ctx), field1: 256, field2 }, - tx_context::sender(ctx), - ); - let field2 = friend_module::make_x(true); - transfer::transfer( - C { id: object::new(ctx), field1: 0, field2 }, - tx_context::sender(ctx), - ); - } - - entry fun destroy_objs(b: B, c: C) { - let B { id, field1: _, field2: _ } = b; - object::delete(id); - let C { id, field1: _, field2: _ } = c; - object::delete(id); - } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/sources/friend_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/sources/friend_module.move deleted file mode 100644 index 61917bc99d0..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref/sources/friend_module.move +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::friend_module { - - struct X has store, drop { - v: bool, - } - - struct Y has store, drop { - v: u64, - } - - public fun make_x(v: bool): X { - X { v } - } - - public fun make_y(v: u64): Y { - Y { v } - } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/Move.toml b/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/Move.toml deleted file mode 100644 index cb29df2a7f4..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "object_cross_module_ref1" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../../sui-framework/packages/sui-framework" } - -[addresses] -base_addr = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/sources/base.move deleted file mode 100644 index 749b6ed9b70..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/sources/base.move +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer; - use base_addr::friend_module::{Self, X, Z}; - - struct A has store, drop { - v: u16, - } - - struct B has key { - id: UID, - field1: u32, - field2: A, - } - - struct C has key { - id: UID, - field1: u64, - field2: X, - } - - struct D has key { - id: UID, - field1: u64, - field2: A, - } - - struct E has key { - id: UID, - field1: u64, - field2: X, - } - - struct F has key { - id: UID, - field1: u64, - field2: Z, - } - - entry fun make_objs(ctx: &mut TxContext) { - let field2 = A { v: 128 }; - transfer::transfer( - B { id: object::new(ctx), field1: 256, field2 }, - tx_context::sender(ctx), - ); - let field2 = friend_module::make_x(true); - transfer::transfer( - C { id: object::new(ctx), field1: 0, field2 }, - tx_context::sender(ctx), - ); - } - - entry fun make_objs_v2(ctx: &mut TxContext) { - let field2 = A { v: 128 }; - transfer::transfer( - D { id: object::new(ctx), field1: 256, field2 }, - tx_context::sender(ctx), - ); - let field2 = friend_module::make_x(true); - transfer::transfer( - E { id: object::new(ctx), field1: 0, field2 }, - tx_context::sender(ctx), - ); - let field2 = friend_module::make_z(true); - transfer::transfer( - F { id: object::new(ctx), field1: 0, field2 }, - tx_context::sender(ctx), - ); - } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/sources/friend_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/sources/friend_module.move deleted file mode 100644 index f53c064ec00..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref1/sources/friend_module.move +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::friend_module { - - struct X has store, drop { - v: bool, - } - - struct Y has store, drop { - v: u64, - } - - struct Z has store, drop { - x: X, - } - - public fun make_x(v: bool): X { - X { v } - } - - public fun make_y(v: u64): Y { - Y { v } - } - - public fun make_z(v: bool): Z { - let x = X { v }; - Z { x } - } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/Move.toml b/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/Move.toml deleted file mode 100644 index 72325786e8b..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "object_cross_module_ref2" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../../sui-framework/packages/sui-framework" } - -[addresses] -base_addr = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/sources/base.move deleted file mode 100644 index 8825b97b26c..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/sources/base.move +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer; - use base_addr::friend_module::{Self, X, Y, Z}; - - struct A has store, drop { - v: u16, - } - - struct B has key { - id: UID, - field1: u32, - field2: A, - } - - struct C has key { - id: UID, - field1: u64, - field2: X, - } - - struct D has key { - id: UID, - field1: u64, - field2: A, - } - - struct E has key { - id: UID, - field1: u64, - field2: X, - } - - struct F has key { - id: UID, - field1: u64, - field2: Z, - } - - struct G has key { - id: UID, - field1: bool, - field2: Y, - } - - entry fun make_objs(ctx: &mut TxContext) { - let field2 = A { v: 128 }; - transfer::transfer( - B { id: object::new(ctx), field1: 256, field2 }, - tx_context::sender(ctx), - ); - let field2 = friend_module::make_x(true); - transfer::transfer( - C { id: object::new(ctx), field1: 0, field2 }, - tx_context::sender(ctx), - ); - } - - entry fun make_objs_v2(ctx: &mut TxContext) { - let field2 = A { v: 128 }; - transfer::transfer( - D { id: object::new(ctx), field1: 256, field2 }, - tx_context::sender(ctx), - ); - let field2 = friend_module::make_x(true); - transfer::transfer( - E { id: object::new(ctx), field1: 0, field2 }, - tx_context::sender(ctx), - ); - let field2 = friend_module::make_z(true); - transfer::transfer( - F { id: object::new(ctx), field1: 0, field2 }, - tx_context::sender(ctx), - ); - } - - entry fun make_objs_v3(ctx: &mut TxContext) { - let field2 = friend_module::make_y(100000000); - transfer::transfer( - G { id: object::new(ctx), field1: false, field2 }, - tx_context::sender(ctx), - ); - } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/sources/friend_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/sources/friend_module.move deleted file mode 100644 index f53c064ec00..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/object_cross_module_ref2/sources/friend_module.move +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::friend_module { - - struct X has store, drop { - v: bool, - } - - struct Y has store, drop { - v: u64, - } - - struct Z has store, drop { - x: X, - } - - public fun make_x(v: bool): X { - X { v } - } - - public fun make_y(v: u64): Y { - Y { v } - } - - public fun make_z(v: bool): Z { - let x = X { v }; - Z { x } - } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/base.move deleted file mode 100644 index fd80a7868fa..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/base.move +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - - struct A { - f1: bool, - f2: T - } - - // Add a struct - struct B { - f1: bool, - f2: T - } - - friend base_addr::friend_module; - - public fun return_0(): u64 { 0 } - - public fun plus_1(x: u64): u64 { x + 1 } - - // We currently cannot change a friend function as the loader will yell at us. - public(friend) fun friend_fun(x: u64): u64 { x } - - // Change this private function - fun non_public_fun(y: bool, g: u64): u64 { if (y) 0 else g } - - // Note that this is fine since the entry function is private - entry fun entry_fun(x: u64): u64 { x } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/friend_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/friend_module.move deleted file mode 100644 index e9a7a4a4597..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/friend_module.move +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::friend_module { - - struct A { - field1: u64, - field2: T - } - - public fun friend_call(): u64 { base_addr::base::friend_fun(1) } - - public fun return_0(): u64 { 0 } - - fun non_public_fun(y: u64): u64 { y } - - // Reorder the functions - public fun plus_1(x: u64): u64 { x + 1 } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/new_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/new_module.move deleted file mode 100644 index d404dce80b2..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/stage1_basic_compatibility_valid/sources/new_module.move +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::new_module { - public fun this_is_a_new_module() { } - - public fun i_can_call_funs_in_other_modules_that_already_existed(): u64 { - base_addr::friend_module::friend_call() - } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/Move.toml b/crates/sui-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/Move.toml deleted file mode 100644 index 33c8390317e..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "stage2_basic_compatibility_valid" -version = "0.0.3" - -[dependencies] -Sui = { local = "../../../../../../sui-framework/packages/sui-framework" } - -[addresses] -base_addr = "0x0" -sui = "0x2" diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/base.move b/crates/sui-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/base.move deleted file mode 100644 index a021837f79e..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/base.move +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::base { - - struct A { - f1: bool, - f2: T - } - - // Add a struct - struct B { - f1: bool, - f2: T - } - - friend base_addr::friend_module; - - public fun return_0(): u64 { 0 } - - public fun plus_1(x: u64): u64 { x + 1 } - - // We currently cannot change a friend function as the loader will yell at us. - public(friend) fun friend_fun(x: u64): u64 { x } - - // Change this private function - fun non_public_fun(y: bool, g: u64): u64 { if (y) 0 else g } - - entry fun entry_fun() { } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/friend_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/friend_module.move deleted file mode 100644 index e9a7a4a4597..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/friend_module.move +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::friend_module { - - struct A { - field1: u64, - field2: T - } - - public fun friend_call(): u64 { base_addr::base::friend_fun(1) } - - public fun return_0(): u64 { 0 } - - fun non_public_fun(y: u64): u64 { y } - - // Reorder the functions - public fun plus_1(x: u64): u64 { x + 1 } -} diff --git a/crates/sui-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/new_module.move b/crates/sui-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/new_module.move deleted file mode 100644 index 54ae7a0eff5..00000000000 --- a/crates/sui-core/src/unit_tests/data/move_upgrade/stage2_basic_compatibility_valid/sources/new_module.move +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base_addr::new_module { - - struct MyObject has key, store { - id: sui::object::UID, - data: u64 - } - - public fun this_is_a_new_module() { } - - public fun i_can_call_funs_in_other_modules_that_already_existed(): u64 { - base_addr::friend_module::friend_call() - } -} diff --git a/crates/sui-core/src/unit_tests/data/object_basics/Move.toml b/crates/sui-core/src/unit_tests/data/object_basics/Move.toml deleted file mode 100644 index ae27152bbd3..00000000000 --- a/crates/sui-core/src/unit_tests/data/object_basics/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "Examples" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -examples = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/object_basics/sources/object_basics.move b/crates/sui-core/src/unit_tests/data/object_basics/sources/object_basics.move deleted file mode 100644 index bf8dcbf0eb5..00000000000 --- a/crates/sui-core/src/unit_tests/data/object_basics/sources/object_basics.move +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Test CTURD object basics (create, transfer, update, read, delete) -module examples::object_basics { - use sui::clock::Clock; - use sui::authenticator_state::AuthenticatorState; - use sui::random::Random; - use sui::dynamic_object_field as ofield; - use sui::event; - use sui::object::{Self, UID, ID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer; - - struct Object has key, store { - id: UID, - value: u64, - } - - struct Wrapper has key { - id: UID, - o: Object - } - - struct NewValueEvent has copy, drop { - new_value: u64 - } - - public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { - transfer::public_transfer( - Object { id: object::new(ctx), value }, - recipient - ) - } - - public entry fun share(ctx: &mut TxContext) { - transfer::public_share_object(Object { id: object::new(ctx), value: 0 }) - } - - public entry fun transfer(o: Object, recipient: address) { - transfer::public_transfer(o, recipient) - } - - public entry fun freeze_object(o: Object) { - transfer::public_freeze_object(o) - } - - public entry fun set_value(o: &mut Object, value: u64) { - o.value = value; - } - - // test that reading o2 and updating o1 works - public entry fun update(o1: &mut Object, o2: &Object) { - o1.value = o2.value; - // emit an event so the world can see the new value - event::emit(NewValueEvent { new_value: o2.value }) - } - - public entry fun delete(o: Object) { - let Object { id, value: _ } = o; - object::delete(id); - } - - public entry fun wrap(o: Object, ctx: &mut TxContext) { - transfer::transfer(wrap_object(o, ctx), tx_context::sender(ctx)) - } - - public entry fun unwrap(w: Wrapper, ctx: &mut TxContext) { - let Wrapper { id, o } = w; - object::delete(id); - transfer::public_transfer(o, tx_context::sender(ctx)) - } - - public fun wrap_object(o: Object, ctx: &mut TxContext): Wrapper { - Wrapper { id: object::new(ctx), o } - } - - public entry fun add_ofield(o: &mut Object, v: Object) { - ofield::add(&mut o.id, true, v); - } - - public entry fun remove_ofield(o: &mut Object, ctx: &mut TxContext) { - transfer::public_transfer( - ofield::remove(&mut o.id, true), - tx_context::sender(ctx), - ); - } - - fun borrow_value_mut(o: &mut Object): &mut u64 { - &mut o.value - } - - fun borrow_value(o: &Object): &u64 { - &o.value - } - - fun get_value(o: &Object): u64 { - o.value - } - - fun get_contents(o: &Object): (ID, u64) { - (object::id(o), o.value) - } - - public entry fun add_field(o: &mut Object, v: Object) { - sui::dynamic_field::add(&mut o.id, true, v); - } - - public entry fun remove_field(o: &mut Object, ctx: &mut TxContext) { - transfer::public_transfer( - sui::dynamic_field::remove(&mut o.id, true), - tx_context::sender(ctx), - ); - } - - struct Name has copy, drop, store { - name_str: std::string::String - } - - public entry fun add_field_with_struct_name(o: &mut Object, v: Object) { - sui::dynamic_field::add(&mut o.id, Name {name_str: std::string::utf8(b"Test Name")}, v); - } - - public entry fun add_ofield_with_struct_name(o: &mut Object, v: Object) { - ofield::add(&mut o.id, Name {name_str: std::string::utf8(b"Test Name")}, v); - } - - public entry fun add_field_with_bytearray_name(o: &mut Object, v: Object) { - sui::dynamic_field::add(&mut o.id,b"Test Name", v); - } - - public entry fun add_ofield_with_bytearray_name(o: &mut Object, v: Object) { - ofield::add(&mut o.id,b"Test Name", v); - } - - public entry fun add_field_with_address_name(o: &mut Object, v: Object, ctx: &mut TxContext) { - sui::dynamic_field::add(&mut o.id,tx_context::sender(ctx), v); - } - - public entry fun add_ofield_with_address_name(o: &mut Object, v: Object, ctx: &mut TxContext) { - ofield::add(&mut o.id,tx_context::sender(ctx), v); - } - - public entry fun generic_test() {} - - public entry fun use_clock(_clock: &Clock) {} - - public entry fun use_auth_state(_auth_state: &AuthenticatorState) {} - - public entry fun use_random(_random: &Random) {} -} diff --git a/crates/sui-core/src/unit_tests/data/object_no_id/Move.toml b/crates/sui-core/src/unit_tests/data/object_no_id/Move.toml deleted file mode 100644 index c11e8bd198a..00000000000 --- a/crates/sui-core/src/unit_tests/data/object_no_id/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "object_no_id" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -object_no_id = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/object_no_id/sources/test_only_object_no_id.move b/crates/sui-core/src/unit_tests/data/object_no_id/sources/test_only_object_no_id.move deleted file mode 100644 index 11ef647eda4..00000000000 --- a/crates/sui-core/src/unit_tests/data/object_no_id/sources/test_only_object_no_id.move +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module object_no_id::test_only_object_no_id { - #[test_only] - struct NotObject has key {f: u64} - - #[test] - fun bad_share() { - sui::transfer::share_object(NotObject{f: 42}); - } -} diff --git a/crates/sui-core/src/unit_tests/data/object_owner/Move.toml b/crates/sui-core/src/unit_tests/data/object_owner/Move.toml deleted file mode 100644 index 0cfec510f37..00000000000 --- a/crates/sui-core/src/unit_tests/data/object_owner/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "object_owner" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -object_owner = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/object_wrapping/Move.toml b/crates/sui-core/src/unit_tests/data/object_wrapping/Move.toml deleted file mode 100644 index 2f74263d412..00000000000 --- a/crates/sui-core/src/unit_tests/data/object_wrapping/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "object_wrapping" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -object_wrapping = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/package_deny/a/sources/a.move b/crates/sui-core/src/unit_tests/data/package_deny/a/sources/a.move deleted file mode 100644 index cd1af58d33e..00000000000 --- a/crates/sui-core/src/unit_tests/data/package_deny/a/sources/a.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module a::a { - public entry fun a() { - b::b::b() - } -} diff --git a/crates/sui-core/src/unit_tests/data/package_deny/b/sources/b.move b/crates/sui-core/src/unit_tests/data/package_deny/b/sources/b.move deleted file mode 100644 index 48713cc9450..00000000000 --- a/crates/sui-core/src/unit_tests/data/package_deny/b/sources/b.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::b { - public entry fun b() { - c::c::c() - } -} diff --git a/crates/sui-core/src/unit_tests/data/package_deny/c/sources/c.move b/crates/sui-core/src/unit_tests/data/package_deny/c/sources/c.move deleted file mode 100644 index fdb66dfd149..00000000000 --- a/crates/sui-core/src/unit_tests/data/package_deny/c/sources/c.move +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module c::c { - struct C { - x: u64 - } - - public entry fun c() {} -} diff --git a/crates/sui-core/src/unit_tests/data/publish_with_event/Move.toml b/crates/sui-core/src/unit_tests/data/publish_with_event/Move.toml deleted file mode 100644 index ae27152bbd3..00000000000 --- a/crates/sui-core/src/unit_tests/data/publish_with_event/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "Examples" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -examples = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/publish_with_event/sources/publish.move b/crates/sui-core/src/unit_tests/data/publish_with_event/sources/publish.move deleted file mode 100644 index b94d40bb2d6..00000000000 --- a/crates/sui-core/src/unit_tests/data/publish_with_event/sources/publish.move +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module examples::publish_with_event { - use std::ascii::{Self, String}; - - use sui::event; - use sui::tx_context::TxContext; - - struct PublishEvent has copy, drop { - foo: String - } - - fun init(_ctx: &mut TxContext) { - event::emit(PublishEvent { foo: ascii::string(b"bar") }) - } -} diff --git a/crates/sui-core/src/unit_tests/data/shared_object_deletion/Move.toml b/crates/sui-core/src/unit_tests/data/shared_object_deletion/Move.toml deleted file mode 100644 index 049d974c2b0..00000000000 --- a/crates/sui-core/src/unit_tests/data/shared_object_deletion/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "shared_object_deletion" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -shared_object_deletion = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/transitive_dependencies/a/sources/a.move b/crates/sui-core/src/unit_tests/data/transitive_dependencies/a/sources/a.move deleted file mode 100644 index 6109094ac90..00000000000 --- a/crates/sui-core/src/unit_tests/data/transitive_dependencies/a/sources/a.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module a::a { - public fun a(): u64 { - b::b::b() - } -} diff --git a/crates/sui-core/src/unit_tests/data/transitive_dependencies/b/sources/b.move b/crates/sui-core/src/unit_tests/data/transitive_dependencies/b/sources/b.move deleted file mode 100644 index 007060afd1e..00000000000 --- a/crates/sui-core/src/unit_tests/data/transitive_dependencies/b/sources/b.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::b { - public fun b(): u64 { - c::c::c() - } -} diff --git a/crates/sui-core/src/unit_tests/data/transitive_dependencies/c/sources/c.move b/crates/sui-core/src/unit_tests/data/transitive_dependencies/c/sources/c.move deleted file mode 100644 index 7e5ede6c68a..00000000000 --- a/crates/sui-core/src/unit_tests/data/transitive_dependencies/c/sources/c.move +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module c::c { - struct C { - x: u64 - } - - public fun c(): u64 { - 42 - } -} diff --git a/crates/sui-core/src/unit_tests/data/transitive_dependencies/root/Move.toml b/crates/sui-core/src/unit_tests/data/transitive_dependencies/root/Move.toml deleted file mode 100644 index c424f510269..00000000000 --- a/crates/sui-core/src/unit_tests/data/transitive_dependencies/root/Move.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "Examples" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../../sui-framework/packages/sui-framework" } -A = { local = "../a" } diff --git a/crates/sui-core/src/unit_tests/data/transitive_dependencies/root/sources/trusted_coin.move b/crates/sui-core/src/unit_tests/data/transitive_dependencies/root/sources/trusted_coin.move deleted file mode 100644 index d20fb46abea..00000000000 --- a/crates/sui-core/src/unit_tests/data/transitive_dependencies/root/sources/trusted_coin.move +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Example coin with a trusted owner responsible for minting/burning (e.g., a stablecoin) -module examples::trusted_coin { - use std::option; - use sui::coin::{Self, TreasuryCap}; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; - - /// Name of the coin - struct TRUSTED_COIN has drop {} - - /// Register the trusted currency to acquire its `TreasuryCap`. Because - /// this is a module initializer, it ensures the currency only gets - /// registered once. - fun init(witness: TRUSTED_COIN, ctx: &mut TxContext) { - // Get a treasury cap for the coin and give it to the transaction - // sender - let (treasury_cap, metadata) = coin::create_currency(witness, 2, b"TRUSTED", b"", b"", option::none(), ctx); - transfer::public_freeze_object(metadata); - transfer::public_transfer(treasury_cap, tx_context::sender(ctx)) - } - - public entry fun mint(treasury_cap: &mut TreasuryCap, ctx: &mut TxContext) { - let coin = coin::mint(treasury_cap, a::a::a(), ctx); - transfer::public_transfer(coin, tx_context::sender(ctx)); - } - - public entry fun transfer(treasury_cap: TreasuryCap, recipient: address) { - transfer::public_transfer(treasury_cap, recipient); - } - - #[test_only] - /// Wrapper of module initializer for testing - public fun test_init(ctx: &mut TxContext) { - init(TRUSTED_COIN {}, ctx) - } -} diff --git a/crates/sui-core/src/unit_tests/data/tto/Move.toml b/crates/sui-core/src/unit_tests/data/tto/Move.toml deleted file mode 100644 index 162ee2126f4..00000000000 --- a/crates/sui-core/src/unit_tests/data/tto/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "tto" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -tto = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/tto/sources/tto1.move b/crates/sui-core/src/unit_tests/data/tto/sources/tto1.move deleted file mode 100644 index 6e13ba61851..00000000000 --- a/crates/sui-core/src/unit_tests/data/tto/sources/tto1.move +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module tto::M1 { - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer::{Self, Receiving}; - use sui::dynamic_object_field; - - struct A has key, store { - id: UID, - } - - struct B has key, store { - id: UID, - } - - struct C has key { - id: UID, - wrapped: B, - } - - public fun start(ctx: &mut TxContext) { - let a = A { id: object::new(ctx) }; - let a_address = object::id_address(&a); - let b = B { id: object::new(ctx) }; - let c = A { id: object::new(ctx) }; - let d = A { id: object::new(ctx) }; - let e = A { id: object::new(ctx) }; - dynamic_object_field::add(&mut d.id, 0, e); - - transfer::public_transfer(a, tx_context::sender(ctx)); - transfer::public_transfer(b, a_address); - transfer::freeze_object(c); - transfer::share_object(d); - } - - public entry fun receiver(parent: &mut A, x: Receiving) { - let b = transfer::receive(&mut parent.id, x); - transfer::public_transfer(b, @tto); - } - - public entry fun send_back(parent: &mut A, x: Receiving) { - let b = transfer::receive(&mut parent.id, x); - let parent_address = object::id_address(parent); - transfer::public_transfer(b, parent_address); - } - - public entry fun deleter(parent: &mut A, x: Receiving) { - let B { id } = transfer::receive(&mut parent.id, x); - object::delete(id); - } - - public entry fun wrapper(parent: &mut A, x: Receiving, ctx: &mut TxContext) { - let b = transfer::receive(&mut parent.id, x); - let c = C { id: object::new(ctx), wrapped: b }; - transfer::transfer(c, @tto); - } - - public fun call_immut_ref(_parent: &mut A, _x: &Receiving) { } - public fun call_mut_ref(_parent: &mut A, _x: &mut Receiving) { } -} diff --git a/crates/sui-core/src/unit_tests/data/type_params/Move.toml b/crates/sui-core/src/unit_tests/data/type_params/Move.toml deleted file mode 100644 index 9602a3e38b5..00000000000 --- a/crates/sui-core/src/unit_tests/data/type_params/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "type_params" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -type_params = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/type_params/sources/m1.move b/crates/sui-core/src/unit_tests/data/type_params/sources/m1.move deleted file mode 100644 index 5dfee8c4fa0..00000000000 --- a/crates/sui-core/src/unit_tests/data/type_params/sources/m1.move +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module type_params::m1 { - use sui::object::{Self, UID}; - use sui::tx_context::TxContext; - use sui::transfer; - use type_params::m2; - - struct Object has key, store { - id: UID, - value: u64, - } - - struct GenObject has key, store { - id: UID, - o: T, - } - - public entry fun create_and_transfer(value: u64, recipient: address, ctx: &mut TxContext) { - transfer::public_transfer( - Object { id: object::new(ctx), value }, - recipient - ) - } - - public entry fun create_and_transfer_gen(value: u64, recipient: address, ctx: &mut TxContext) { - let another = m2::create(value, ctx); - transfer::public_transfer( - GenObject { id: object::new(ctx), o: another }, - recipient - ) - } - - public entry fun transfer_object(o: T, recipient: address) { - transfer::public_transfer(o, recipient); - } - - -} diff --git a/crates/sui-core/src/unit_tests/data/type_params_extra/Move.toml b/crates/sui-core/src/unit_tests/data/type_params_extra/Move.toml deleted file mode 100644 index 1b0306e8336..00000000000 --- a/crates/sui-core/src/unit_tests/data/type_params_extra/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "type_params_extra" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } - -[addresses] -type_params = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/type_params_extra/sources/m1.move b/crates/sui-core/src/unit_tests/data/type_params_extra/sources/m1.move deleted file mode 100644 index c26603d3e60..00000000000 --- a/crates/sui-core/src/unit_tests/data/type_params_extra/sources/m1.move +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module type_params::m1 { - use sui::transfer; - - public entry fun transfer_object(o: T, recipient: address) { - transfer::public_transfer(o, recipient); - } - - -} diff --git a/crates/sui-core/src/unit_tests/pay_sui_tests.rs b/crates/sui-core/src/unit_tests/pay_sui_tests.rs deleted file mode 100644 index d0b4b6534b2..00000000000 --- a/crates/sui-core/src/unit_tests/pay_sui_tests.rs +++ /dev/null @@ -1,475 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::HashMap, sync::Arc}; - -use futures::future::join_all; -use sui_types::{ - base_types::{dbg_addr, ObjectID, ObjectRef, SuiAddress}, - crypto::{get_key_pair, AccountKeyPair}, - effects::{SignedTransactionEffects, TransactionEffectsAPI}, - error::{SuiError, UserInputError}, - execution_status::{ExecutionFailureStatus, ExecutionStatus}, - gas_coin::GasCoin, - object::Object, - programmable_transaction_builder::ProgrammableTransactionBuilder, - transaction::TransactionData, - utils::to_sender_signed_transaction, -}; - -use crate::authority::{ - authority_tests::{init_state_with_committee, send_and_confirm_transaction}, - test_authority_builder::TestAuthorityBuilder, - AuthorityState, -}; - -#[tokio::test] -async fn test_pay_sui_failure_empty_recipients() { - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let coin_id = ObjectID::random(); - let coin1 = Object::with_id_owner_gas_for_testing(coin_id, sender, 2000000); - - // an empty set of programmable transaction commands will still charge gas - let res = execute_pay_sui(vec![coin1], vec![], vec![], sender, sender_key, 2000000).await; - - let effects = res.txn_result.unwrap().into_data(); - assert_eq!(effects.status(), &ExecutionStatus::Success); - assert_eq!(effects.mutated().len(), 1); - assert_eq!(effects.mutated()[0].0.0, coin_id); - assert!(effects.deleted().is_empty()); - assert!(effects.created().is_empty()); -} - -#[tokio::test] -async fn test_pay_sui_failure_insufficient_gas_balance_one_input_coin() { - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let coin1 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 2000); - let recipient1 = dbg_addr(1); - let recipient2 = dbg_addr(2); - - let res = execute_pay_sui( - vec![coin1], - vec![recipient1, recipient2], - vec![100, 100], - sender, - sender_key, - 2200000, - ) - .await; - - assert_eq!( - UserInputError::try_from(res.txn_result.unwrap_err()).unwrap(), - UserInputError::GasBalanceTooLow { - gas_balance: 2000, - needed_gas_amount: 2200000, - } - ); -} - -#[tokio::test] -async fn test_pay_sui_failure_insufficient_total_balance_one_input_coin() { - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let coin1 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 500100); - let recipient1 = dbg_addr(1); - let recipient2 = dbg_addr(2); - - let res = execute_pay_sui( - vec![coin1], - vec![recipient1, recipient2], - vec![100, 100], - sender, - sender_key, - 500000, - ) - .await; - - assert_eq!( - res.txn_result.as_ref().unwrap().status(), - &ExecutionStatus::Failure { - error: ExecutionFailureStatus::InsufficientCoinBalance, - command: Some(0) // SplitCoins is the first command in the implementation of pay - }, - ); -} - -#[tokio::test] -async fn test_pay_sui_failure_insufficient_gas_balance_multiple_input_coins() { - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let coin1 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 800); - let coin2 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 700); - let recipient1 = dbg_addr(1); - let recipient2 = dbg_addr(2); - - let res = execute_pay_sui( - vec![coin1, coin2], - vec![recipient1, recipient2], - vec![100, 100], - sender, - sender_key, - 2000000, - ) - .await; - - assert_eq!( - UserInputError::try_from(res.txn_result.unwrap_err()).unwrap(), - UserInputError::GasBalanceTooLow { - gas_balance: 1500, - needed_gas_amount: 2000000, - } - ); -} - -#[tokio::test] -async fn test_pay_sui_failure_insufficient_total_balance_multiple_input_coins() { - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let coin1 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 204000); - let coin2 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 303000); - let recipient1 = dbg_addr(1); - let recipient2 = dbg_addr(2); - - let res = execute_pay_sui( - vec![coin1, coin2], - vec![recipient1, recipient2], - vec![4000, 4000], - sender, - sender_key, - 500000, - ) - .await; - assert_eq!( - res.txn_result.as_ref().unwrap().status(), - &ExecutionStatus::Failure { - error: ExecutionFailureStatus::InsufficientCoinBalance, - command: Some(0) // SplitCoins is the first command in the implementation of pay - }, - ); -} - -#[tokio::test] -async fn test_pay_sui_success_one_input_coin() -> anyhow::Result<()> { - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let object_id = ObjectID::random(); - let coin_amount = 50000000; - let coin_obj = Object::with_id_owner_gas_for_testing(object_id, sender, 50000000); - let recipient1 = dbg_addr(1); - let recipient2 = dbg_addr(2); - let recipient3 = dbg_addr(3); - let recipient_amount_map: HashMap<_, u64> = - HashMap::from([(recipient1, 100), (recipient2, 200), (recipient3, 300)]); - let res = execute_pay_sui( - vec![coin_obj], - vec![recipient1, recipient2, recipient3], - vec![100, 200, 300], - sender, - sender_key, - coin_amount - 300 - 200 - 100, - ) - .await; - - let effects = res.txn_result.unwrap().into_data(); - assert_eq!(*effects.status(), ExecutionStatus::Success); - // make sure each recipient receives the specified amount - assert_eq!(effects.created().len(), 3); - let created_obj_id1 = effects.created()[0].0.0; - let created_obj_id2 = effects.created()[1].0.0; - let created_obj_id3 = effects.created()[2].0.0; - let created_obj1 = res - .authority_state - .get_object(&created_obj_id1) - .await - .unwrap() - .unwrap(); - let created_obj2 = res - .authority_state - .get_object(&created_obj_id2) - .await - .unwrap() - .unwrap(); - let created_obj3 = res - .authority_state - .get_object(&created_obj_id3) - .await - .unwrap() - .unwrap(); - - let addr1 = effects.created()[0].1.get_owner_address()?; - let addr2 = effects.created()[1].1.get_owner_address()?; - let addr3 = effects.created()[2].1.get_owner_address()?; - let coin_val1 = *recipient_amount_map - .get(&addr1) - .ok_or(SuiError::InvalidAddress)?; - let coin_val2 = *recipient_amount_map - .get(&addr2) - .ok_or(SuiError::InvalidAddress)?; - let coin_val3 = *recipient_amount_map - .get(&addr3) - .ok_or(SuiError::InvalidAddress)?; - assert_eq!(GasCoin::try_from(&created_obj1)?.value(), coin_val1); - assert_eq!(GasCoin::try_from(&created_obj2)?.value(), coin_val2); - assert_eq!(GasCoin::try_from(&created_obj3)?.value(), coin_val3); - - // make sure the first object still belongs to the sender, - // the value is equal to all residual values after amounts transferred and gas - // payment. - assert_eq!(effects.mutated()[0].0.0, object_id); - assert_eq!(effects.mutated()[0].1, sender); - let gas_used = effects.gas_cost_summary().net_gas_usage() as u64; - let gas_object = res.authority_state.get_object(&object_id).await?.unwrap(); - assert_eq!( - GasCoin::try_from(&gas_object)?.value(), - coin_amount - 100 - 200 - 300 - gas_used, - ); - - Ok(()) -} - -#[tokio::test] -async fn test_pay_sui_success_multiple_input_coins() -> anyhow::Result<()> { - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let object_id1 = ObjectID::random(); - let object_id2 = ObjectID::random(); - let object_id3 = ObjectID::random(); - let coin_obj1 = Object::with_id_owner_gas_for_testing(object_id1, sender, 5000000); - let coin_obj2 = Object::with_id_owner_gas_for_testing(object_id2, sender, 1000); - let coin_obj3 = Object::with_id_owner_gas_for_testing(object_id3, sender, 1000); - let recipient1 = dbg_addr(1); - let recipient2 = dbg_addr(2); - - let res = execute_pay_sui( - vec![coin_obj1, coin_obj2, coin_obj3], - vec![recipient1, recipient2], - vec![500, 1500], - sender, - sender_key, - 5000000, - ) - .await; - let recipient_amount_map: HashMap<_, u64> = - HashMap::from([(recipient1, 500), (recipient2, 1500)]); - let effects = res.txn_result.unwrap().into_data(); - assert_eq!(*effects.status(), ExecutionStatus::Success); - - // make sure each recipient receives the specified amount - assert_eq!(effects.created().len(), 2); - let created_obj_id1 = effects.created()[0].0.0; - let created_obj_id2 = effects.created()[1].0.0; - let created_obj1 = res - .authority_state - .get_object(&created_obj_id1) - .await - .unwrap() - .unwrap(); - let created_obj2 = res - .authority_state - .get_object(&created_obj_id2) - .await - .unwrap() - .unwrap(); - let addr1 = effects.created()[0].1.get_owner_address()?; - let addr2 = effects.created()[1].1.get_owner_address()?; - let coin_val1 = *recipient_amount_map - .get(&addr1) - .ok_or(SuiError::InvalidAddress)?; - let coin_val2 = *recipient_amount_map - .get(&addr2) - .ok_or(SuiError::InvalidAddress)?; - assert_eq!(GasCoin::try_from(&created_obj1)?.value(), coin_val1); - assert_eq!(GasCoin::try_from(&created_obj2)?.value(), coin_val2); - // make sure the first input coin still belongs to the sender, - // the value is equal to all residual values after amounts transferred and gas - // payment. - assert_eq!(effects.mutated()[0].0.0, object_id1); - assert_eq!(effects.mutated()[0].1, sender); - let gas_used = effects.gas_cost_summary().net_gas_usage() as u64; - let gas_object = res.authority_state.get_object(&object_id1).await?.unwrap(); - assert_eq!( - GasCoin::try_from(&gas_object)?.value(), - 5002000 - 500 - 1500 - gas_used, - ); - - // make sure the second and third input coins are deleted - let deleted_ids: Vec = effects.deleted().iter().map(|d| d.0).collect(); - assert!(deleted_ids.contains(&object_id2)); - assert!(deleted_ids.contains(&object_id3)); - Ok(()) -} - -#[tokio::test] -async fn test_pay_all_sui_failure_insufficient_gas_one_input_coin() { - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let coin1 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 1800); - let recipient = dbg_addr(2); - - let res = execute_pay_all_sui(vec![&coin1], recipient, sender, sender_key, 2000000).await; - - assert_eq!( - UserInputError::try_from(res.txn_result.unwrap_err()).unwrap(), - UserInputError::GasBalanceTooLow { - gas_balance: 1800, - needed_gas_amount: 2000000, - } - ); -} - -#[tokio::test] -async fn test_pay_all_sui_failure_insufficient_gas_budget_multiple_input_coins() { - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let coin1 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 1000); - let coin2 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 1000); - let recipient = dbg_addr(2); - let res = - execute_pay_all_sui(vec![&coin1, &coin2], recipient, sender, sender_key, 2500000).await; - - assert_eq!( - UserInputError::try_from(res.txn_result.unwrap_err()).unwrap(), - UserInputError::GasBalanceTooLow { - gas_balance: 2000, - needed_gas_amount: 2500000, - } - ); -} - -#[tokio::test] -async fn test_pay_all_sui_success_one_input_coin() -> anyhow::Result<()> { - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let object_id = ObjectID::random(); - let coin_obj = Object::with_id_owner_gas_for_testing(object_id, sender, 3000000); - let recipient = dbg_addr(2); - let res = execute_pay_all_sui(vec![&coin_obj], recipient, sender, sender_key, 2000000).await; - - let effects = res.txn_result.unwrap().into_data(); - assert_eq!(*effects.status(), ExecutionStatus::Success); - - // make sure the first object now belongs to the recipient, - // the value is equal to all residual values after gas payment. - let obj_ref = &effects.mutated()[0].0; - assert_eq!(obj_ref.0, object_id); - assert_eq!(effects.mutated()[0].1, recipient); - - let gas_used = effects.gas_cost_summary().gas_used(); - let gas_object = res.authority_state.get_object(&object_id).await?.unwrap(); - assert_eq!(GasCoin::try_from(&gas_object)?.value(), 3000000 - gas_used,); - Ok(()) -} - -#[tokio::test] -async fn test_pay_all_sui_success_multiple_input_coins() -> anyhow::Result<()> { - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let object_id1 = ObjectID::random(); - let coin_obj1 = Object::with_id_owner_gas_for_testing(object_id1, sender, 3000000); - let coin_obj2 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 1000); - let coin_obj3 = Object::with_id_owner_gas_for_testing(ObjectID::random(), sender, 1000); - let recipient = dbg_addr(2); - let res = execute_pay_all_sui( - vec![&coin_obj1, &coin_obj2, &coin_obj3], - recipient, - sender, - sender_key, - 3000000, - ) - .await; - - let effects = res.txn_result.unwrap().into_data(); - assert_eq!(*effects.status(), ExecutionStatus::Success); - - // make sure the first object now belongs to the recipient, - // the value is equal to all residual values after gas payment. - let obj_ref = &effects.mutated()[0].0; - assert_eq!(obj_ref.0, object_id1); - assert_eq!(effects.mutated()[0].1, recipient); - - let gas_used = effects.gas_cost_summary().gas_used(); - let gas_object = res.authority_state.get_object(&object_id1).await?.unwrap(); - assert_eq!(GasCoin::try_from(&gas_object)?.value(), 3002000 - gas_used,); - Ok(()) -} - -struct PaySuiTransactionBlockExecutionResult { - pub authority_state: Arc, - pub txn_result: Result, -} - -async fn execute_pay_sui( - input_coin_objects: Vec, - recipients: Vec, - amounts: Vec, - sender: SuiAddress, - sender_key: AccountKeyPair, - gas_budget: u64, -) -> PaySuiTransactionBlockExecutionResult { - let authority_state = TestAuthorityBuilder::new().build().await; - - let input_coin_refs: Vec = input_coin_objects - .iter() - .map(|coin_obj| coin_obj.compute_object_reference()) - .collect(); - let handles: Vec<_> = input_coin_objects - .into_iter() - .map(|obj| authority_state.insert_genesis_object(obj)) - .collect(); - join_all(handles).await; - let rgp = authority_state.reference_gas_price_for_testing().unwrap(); - - let mut builder = ProgrammableTransactionBuilder::new(); - builder.pay_sui(recipients, amounts).unwrap(); - let pt = builder.finish(); - let data = TransactionData::new_programmable(sender, input_coin_refs, pt, gas_budget, rgp); - let tx = to_sender_signed_transaction(data, &sender_key); - let txn_result = send_and_confirm_transaction(&authority_state, tx) - .await - .map(|(_, effects)| effects); - - PaySuiTransactionBlockExecutionResult { - authority_state, - txn_result, - } -} - -async fn execute_pay_all_sui( - input_coin_objects: Vec<&Object>, - recipient: SuiAddress, - sender: SuiAddress, - sender_key: AccountKeyPair, - gas_budget: u64, -) -> PaySuiTransactionBlockExecutionResult { - let dir = tempfile::TempDir::new().unwrap(); - let network_config = sui_swarm_config::network_config_builder::ConfigBuilder::new(&dir) - .with_reference_gas_price(700) - .with_objects( - input_coin_objects - .clone() - .into_iter() - .map(ToOwned::to_owned), - ) - .build(); - let genesis = network_config.genesis; - let keypair = network_config.validator_configs[0].protocol_key_pair(); - - let authority_state = init_state_with_committee(&genesis, keypair).await; - let rgp = authority_state.reference_gas_price_for_testing().unwrap(); - - let mut input_coins = Vec::new(); - for coin in input_coin_objects { - let id = coin.id(); - let object_ref = genesis - .objects() - .iter() - .find(|o| o.id() == id) - .unwrap() - .compute_object_reference(); - input_coins.push(object_ref); - } - - let mut builder = ProgrammableTransactionBuilder::new(); - builder.pay_all_sui(recipient); - let pt = builder.finish(); - let data = TransactionData::new_programmable(sender, input_coins, pt, gas_budget, rgp); - let tx = to_sender_signed_transaction(data, &sender_key); - let txn_result = send_and_confirm_transaction(&authority_state, tx) - .await - .map(|(_, effects)| effects); - PaySuiTransactionBlockExecutionResult { - authority_state, - txn_result, - } -} diff --git a/crates/sui-core/src/unit_tests/transaction_tests.rs b/crates/sui-core/src/unit_tests/transaction_tests.rs deleted file mode 100644 index cc92f2fc403..00000000000 --- a/crates/sui-core/src/unit_tests/transaction_tests.rs +++ /dev/null @@ -1,1254 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::ops::Deref; - -use fastcrypto::{ed25519::Ed25519KeyPair, traits::KeyPair}; -use fastcrypto_zkp::bn254::zk_login::{parse_jwks, OIDCProvider, ZkLoginInputs}; -use mysten_network::Multiaddr; -use rand::{rngs::StdRng, SeedableRng}; -use shared_crypto::intent::{Intent, IntentMessage}; -use sui_macros::sim_test; -use sui_types::{ - authenticator_state::ActiveJwk, - base_types::dbg_addr, - crypto::{get_key_pair, AccountKeyPair, Signature, SuiKeyPair}, - error::{SuiError, UserInputError}, - multisig::{MultiSig, MultiSigPublicKey}, - signature::GenericSignature, - transaction::{ - AuthenticatorStateUpdate, GenesisTransaction, TransactionDataAPI, TransactionExpiration, - TransactionKind, - }, - utils::{load_test_vectors, to_sender_signed_transaction}, - zk_login_authenticator::ZkLoginAuthenticator, - zk_login_util::DEFAULT_JWK_BYTES, -}; - -macro_rules! assert_matches { - ($expression:expr, $pattern:pat $(if $guard: expr)?) => { - match $expression { - $pattern $(if $guard)? => {} - ref e => panic!( - "assertion failed: `(left == right)` \ - (left: `{:?}`, right: `{:?}`)", - e, - stringify!($pattern $(if $guard)?) - ), - } - }; -} - -use fastcrypto::traits::AggregateAuthenticator; -use sui_types::programmable_transaction_builder::ProgrammableTransactionBuilder; - -use super::*; -pub use crate::authority::authority_test_utils::init_state_with_ids; -use crate::{ - authority_client::{AuthorityAPI, NetworkAuthorityClient}, - authority_server::{AuthorityServer, AuthorityServerHandle}, - stake_aggregator::{InsertResult, StakeAggregator}, -}; - -#[sim_test] -async fn test_handle_transfer_transaction_bad_signature() { - do_transaction_test( - 1, - |_| {}, - |mut_tx| { - let (_unknown_address, unknown_key): (_, AccountKeyPair) = get_key_pair(); - let data = mut_tx.data_mut_for_testing(); - *data.tx_signatures_mut_for_testing() = - vec![Signature::new_secure(data.intent_message(), &unknown_key).into()]; - }, - |err| { - assert_matches!(err, SuiError::SignerSignatureAbsent { .. }); - }, - ) - .await; -} - -#[sim_test] -async fn test_handle_transfer_transaction_no_signature() { - do_transaction_test( - 1, - |_| {}, - |tx| { - *tx.data_mut_for_testing().tx_signatures_mut_for_testing() = vec![]; - }, - |err| { - assert_matches!( - err, - SuiError::SignerSignatureNumberMismatch { - expected: 1, - actual: 0 - } - ); - }, - ) - .await; -} - -#[sim_test] -async fn test_handle_transfer_transaction_extra_signature() { - do_transaction_test( - 1, - |_| {}, - |tx| { - let sigs = tx.data_mut_for_testing().tx_signatures_mut_for_testing(); - sigs.push(sigs[0].clone()); - }, - |err| { - assert_matches!( - err, - SuiError::SignerSignatureNumberMismatch { - expected: 1, - actual: 2 - } - ); - }, - ) - .await; -} - -// TODO: verify that these cases are not exploitable via consensus input -#[sim_test] -async fn test_empty_sender_signed_data() { - do_transaction_test( - 0, - |_| {}, - |tx| { - let data = tx.data_mut_for_testing(); - data.inner_vec_mut_for_testing().clear(); - }, - |err| { - assert_matches!( - err, - SuiError::UserInputError { - error: UserInputError::Unsupported { .. } - } - ); - }, - ) - .await; -} - -#[sim_test] -async fn test_multiple_sender_signed_data() { - do_transaction_test( - 0, - |_| {}, - |tx| { - let data = tx.data_mut_for_testing(); - let tx_vec = data.inner_vec_mut_for_testing(); - assert_eq!(tx_vec.len(), 1); - let mut new = tx_vec[0].clone(); - // make sure second message has unique digest - *new.intent_message.value.expiration_mut_for_testing() = - TransactionExpiration::Epoch(123); - tx_vec.push(new); - }, - |err| { - assert_matches!( - err, - SuiError::UserInputError { - error: UserInputError::Unsupported { .. } - } - ); - }, - ) - .await; -} - -#[sim_test] -async fn test_duplicate_sender_signed_data() { - do_transaction_test( - 0, - |_| {}, - |tx| { - let data = tx.data_mut_for_testing(); - let tx_vec = data.inner_vec_mut_for_testing(); - assert_eq!(tx_vec.len(), 1); - let new = tx_vec[0].clone(); - tx_vec.push(new); - }, - |err| { - assert_matches!( - err, - SuiError::UserInputError { - error: UserInputError::Unsupported { .. } - } - ); - }, - ) - .await; -} - -#[sim_test] -async fn test_empty_gas_data() { - do_transaction_test_skip_cert_checks( - 0, - |tx| { - tx.gas_data_mut().payment = vec![]; - }, - |_| {}, - |err| { - assert_matches!( - err, - SuiError::UserInputError { - error: UserInputError::MissingGasPayment - } - ); - }, - ) - .await; -} - -#[sim_test] -async fn test_duplicate_gas_data() { - do_transaction_test_skip_cert_checks( - 0, - |tx| { - let gas_data = tx.gas_data_mut(); - let new_gas = gas_data.payment[0]; - gas_data.payment.push(new_gas); - }, - |_| {}, - |err| { - assert_matches!( - err, - SuiError::UserInputError { - error: UserInputError::MutableObjectUsedMoreThanOnce { .. } - } - ); - }, - ) - .await; -} - -#[sim_test] -async fn test_gas_wrong_owner_matches_sender() { - do_transaction_test( - 1, - |tx| { - let gas_data = tx.gas_data_mut(); - let (new_addr, _): (_, AccountKeyPair) = get_key_pair(); - gas_data.owner = new_addr; - *tx.sender_mut_for_testing() = new_addr; - }, - |_| {}, - |err| { - assert_matches!(err, SuiError::SignerSignatureAbsent { .. }); - }, - ) - .await; -} - -#[sim_test] -async fn test_gas_wrong_owner() { - do_transaction_test( - 1, - |tx| { - let gas_data = tx.gas_data_mut(); - let (new_addr, _): (_, AccountKeyPair) = get_key_pair(); - gas_data.owner = new_addr; - }, - |_| {}, - |err| { - assert_matches!( - err, - SuiError::SignerSignatureNumberMismatch { - expected: 2, - actual: 1 - } - ); - }, - ) - .await; -} - -#[sim_test] -async fn test_user_sends_system_transaction() { - do_transaction_test_skip_cert_checks( - 0, - |tx| { - *tx.kind_mut() = TransactionKind::Genesis(GenesisTransaction { objects: vec![] }); - }, - |_| {}, - |err| { - assert_matches!( - err, - SuiError::UserInputError { - error: UserInputError::Unsupported { .. } - } - ); - }, - ) - .await; -} - -pub fn init_transfer_transaction( - pre_sign_mutations: impl FnOnce(&mut TransactionData), - sender: SuiAddress, - secret: &AccountKeyPair, - recipient: SuiAddress, - object_ref: ObjectRef, - gas_object_ref: ObjectRef, - gas_budget: u64, - gas_price: u64, -) -> Transaction { - let mut data = TransactionData::new_transfer( - recipient, - object_ref, - sender, - gas_object_ref, - gas_budget, - gas_price, - ); - pre_sign_mutations(&mut data); - to_sender_signed_transaction(data, secret) -} - -async fn do_transaction_test_skip_cert_checks( - expected_sig_errors: u64, - pre_sign_mutations: impl FnOnce(&mut TransactionData), - post_sign_mutations: impl FnOnce(&mut Transaction), - err_check: impl Fn(&SuiError), -) { - do_transaction_test_impl( - expected_sig_errors, - false, - pre_sign_mutations, - post_sign_mutations, - err_check, - ) - .await -} - -async fn do_transaction_test( - expected_sig_errors: u64, - pre_sign_mutations: impl FnOnce(&mut TransactionData), - post_sign_mutations: impl FnOnce(&mut Transaction), - err_check: impl Fn(&SuiError), -) { - do_transaction_test_impl( - expected_sig_errors, - true, - pre_sign_mutations, - post_sign_mutations, - err_check, - ) - .await -} - -async fn do_transaction_test_impl( - _expected_sig_errors: u64, - check_forged_cert: bool, - pre_sign_mutations: impl FnOnce(&mut TransactionData), - post_sign_mutations: impl FnOnce(&mut Transaction), - err_check: impl Fn(&SuiError), -) { - telemetry_subscribers::init_for_testing(); - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let recipient = dbg_addr(2); - let object_id = ObjectID::random(); - let gas_object_id = ObjectID::random(); - let authority_state = - init_state_with_ids(vec![(sender, object_id), (sender, gas_object_id)]).await; - let rgp = authority_state.reference_gas_price_for_testing().unwrap(); - let object = authority_state - .get_object(&object_id) - .await - .unwrap() - .unwrap(); - let gas_object = authority_state - .get_object(&gas_object_id) - .await - .unwrap() - .unwrap(); - - let mut transfer_transaction = init_transfer_transaction( - pre_sign_mutations, - sender, - &sender_key, - recipient, - object.compute_object_reference(), - gas_object.compute_object_reference(), - rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, - rgp, - ); - - let consensus_address = "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(); - - let server = AuthorityServer::new_for_test( - "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(), - authority_state.clone(), - consensus_address, - ); - - let server_handle = server.spawn_for_test().await.unwrap(); - - let client = NetworkAuthorityClient::connect(server_handle.address()) - .await - .unwrap(); - - post_sign_mutations(&mut transfer_transaction); - - let err = client - .handle_transaction(transfer_transaction.clone()) - .await - .unwrap_err(); - err_check(&err); - - check_locks(authority_state.clone(), vec![object_id]).await; - - // now verify that the same transaction is rejected if a false certificate is - // somehow formed and sent - if check_forged_cert { - let epoch_store = authority_state.epoch_store_for_testing(); - let signed_transaction = VerifiedSignedTransaction::new( - epoch_store.epoch(), - VerifiedTransaction::new_unchecked(transfer_transaction), - authority_state.name, - &*authority_state.secret, - ); - let mut agg = StakeAggregator::new(epoch_store.committee().clone()); - - let InsertResult::QuorumReached(cert_sig) = agg.insert(signed_transaction.clone().into()) - else { - panic!("quorum expected"); - }; - - let plain_tx = signed_transaction.into_inner(); - - let ct = CertifiedTransaction::new_from_data_and_sig(plain_tx.into_data(), cert_sig); - - let err = client.handle_certificate_v2(ct.clone()).await.unwrap_err(); - err_check(&err); - epoch_store.clear_signature_cache(); - let err = client.handle_certificate_v2(ct.clone()).await.unwrap_err(); - err_check(&err); - } -} - -#[sim_test] -async fn test_zklogin_transfer_with_bad_ephemeral_sig() { - do_zklogin_transaction_test( - 1, - |_| {}, - |tx| { - let data = tx.data_mut_for_testing(); - let intent_message = data.intent_message().clone(); - let sigs = data.tx_signatures_mut_for_testing(); - let GenericSignature::ZkLoginAuthenticator(zklogin) = sigs.get_mut(0).unwrap() else { - panic!(); - }; - - let (_unknown_address, unknown_key): (_, AccountKeyPair) = get_key_pair(); - let sig = Signature::new_secure(&intent_message, &unknown_key); - *zklogin.user_signature_mut_for_testing() = sig; - }, - ) - .await; -} -#[sim_test] -async fn test_zklogin_transfer_with_large_address_seed() { - telemetry_subscribers::init_for_testing(); - let (object_ids, gas_object_ids, authority_state, _epoch_store, _, _, _server, client) = - setup_zklogin_network(|_| {}).await; - - let ephemeral_key = Ed25519KeyPair::generate(&mut StdRng::from_seed([3; 32])); - - let large_address_seed = - num_bigint::BigInt::from_bytes_be(num_bigint::Sign::Plus, &[1; 33]).to_string(); - let zklogin = ZkLoginInputs::from_json("{\"proofPoints\":{\"a\":[\"7351610957585487046328875967050889651854514987235893782501043846344306437586\",\"15901581830174345085102528605366245320934422564305327249129736514949843983391\",\"1\"],\"b\":[[\"8511334686125322419369086121569737536249817670014553268281989325333085952301\",\"4879445774811020644521006463993914729416121646921376735430388611804034116132\"],[\"17435652898871739253945717312312680537810513841582909477368887889905134847157\",\"14885460127400879557124294989610467103783286587437961743305395373299049315863\"],[\"1\",\"0\"]],\"c\":[\"18935582624804960299209074901817240117999581542763303721451852621662183299378\",\"5367019427921492326304024952457820199970536888356564030410757345854117465786\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", &large_address_seed).unwrap(); - let sender = SuiAddress::generate(StdRng::from_seed([3; 32])); - let recipient = dbg_addr(2); - - let tx = init_zklogin_transfer( - &authority_state, - object_ids[2], - gas_object_ids[2], - recipient, - sender, - |_| {}, - &ephemeral_key, - &zklogin, - ) - .await; - - assert!(client.handle_transaction(tx).await.is_err()); -} - -#[sim_test] -async fn zklogin_test_cached_proof_wrong_key() { - telemetry_subscribers::init_for_testing(); - let ( - mut object_ids, - gas_object_ids, - authority_state, - _epoch_store, - transfer_transaction, - metrics, - _server, - client, - ) = setup_zklogin_network(|_| {}).await; - - let res = client.handle_transaction(transfer_transaction).await; - assert!(res.is_ok()); - - // assert_eq!( - // epoch_store - // .signature_verifier - // .metrics - // .zklogin_inputs_cache_misses - // .get(), - // 1 - // ); - - let (skp, _eph_pk, zklogin) = - &load_test_vectors("../sui-types/src/unit_tests/zklogin_test_vectors.json")[1]; - let ephemeral_key = match skp { - SuiKeyPair::Ed25519(kp) => kp, - _ => panic!(), - }; - let sender = SuiAddress::try_from_unpadded(zklogin).unwrap(); - let recipient = dbg_addr(2); - - let mut transfer_transaction2 = init_zklogin_transfer( - &authority_state, - object_ids[2], - gas_object_ids[2], - recipient, - sender, - |_| {}, - ephemeral_key, - zklogin, - ) - .await; - - let intent_message = transfer_transaction2.data().intent_message().clone(); - match &mut transfer_transaction2 - .data_mut_for_testing() - .tx_signatures_mut_for_testing()[0] - { - GenericSignature::ZkLoginAuthenticator(zklogin) => { - let (_unknown_address, unknown_key): (_, AccountKeyPair) = get_key_pair(); - // replace the signature with a bogus one - *zklogin.user_signature_mut_for_testing() = - Signature::new_secure(&intent_message, &unknown_key); - } - _ => panic!(), - } - - // This tx should fail, but passes because we skip the ephemeral sig check when - // hitting the zklogin check! - assert!( - client - .handle_transaction(transfer_transaction2) - .await - .is_err() - ); - - // TODO: re-enable when cache is re-enabled. - // assert_eq!( - // epoch_store - // .signature_verifier - // .metrics - // .zklogin_inputs_cache_hits - // .get(), - // 1 - // ); - - assert_eq!(metrics.signature_errors.get(), 1); - - object_ids.remove(0); // first object was successfully locked. - check_locks(authority_state, object_ids).await; -} - -async fn do_zklogin_transaction_test( - expected_sig_errors: u64, - pre_sign_mutations: impl FnOnce(&mut TransactionData), - post_sign_mutations: impl FnOnce(&mut Transaction), -) { - let ( - object_ids, - _gas_object_id, - authority_state, - _epoch_store, - mut transfer_transaction, - metrics, - _server, - client, - ) = setup_zklogin_network(pre_sign_mutations).await; - - post_sign_mutations(&mut transfer_transaction); - - assert!( - client - .handle_transaction(transfer_transaction) - .await - .is_err() - ); - - // TODO: re-enable when cache is re-enabled. - // assert_eq!( - // epoch_store - // .signature_verifier - // .metrics - // .zklogin_inputs_cache_misses - // .get(), - // 1 - // ); - - assert_eq!(metrics.signature_errors.get(), expected_sig_errors); - - check_locks(authority_state, object_ids).await; -} - -async fn check_locks(authority_state: Arc, object_ids: Vec) { - for object_id in object_ids { - let object = authority_state - .get_object(&object_id) - .await - .unwrap() - .unwrap(); - assert!( - authority_state - .get_transaction_lock( - &object.compute_object_reference(), - &authority_state.epoch_store_for_testing() - ) - .await - .unwrap() - .is_none() - ); - } -} - -async fn setup_zklogin_network( - pre_sign_mutations: impl FnOnce(&mut TransactionData), -) -> ( - Vec, // objects - Vec, // gas objects - Arc, - Guard>, - sui_types::message_envelope::Envelope, - Arc, - AuthorityServerHandle, - NetworkAuthorityClient, -) { - let (skp, _eph_pk, zklogin) = - &load_test_vectors("../sui-types/src/unit_tests/zklogin_test_vectors.json")[1]; - let ephemeral_key = match skp { - SuiKeyPair::Ed25519(kp) => kp, - _ => panic!(), - }; - let sender = SuiAddress::try_from_unpadded(zklogin).unwrap(); - - let recipient = dbg_addr(2); - let objects: Vec<_> = (0..10).map(|_| (sender, ObjectID::random())).collect(); - let gas_objects: Vec<_> = (0..10).map(|_| (sender, ObjectID::random())).collect(); - let object_ids: Vec<_> = objects.iter().map(|(_, id)| *id).collect(); - let gas_object_ids: Vec<_> = gas_objects.iter().map(|(_, id)| *id).collect(); - - let authority_state = - init_state_with_ids(objects.into_iter().chain(gas_objects).collect::>()).await; - - let object_id = object_ids[0]; - let gas_object_id = gas_object_ids[0]; - let jwks = parse_jwks(DEFAULT_JWK_BYTES, &OIDCProvider::Twitch).unwrap(); - let epoch_store = authority_state.epoch_store_for_testing(); - epoch_store.update_authenticator_state(&AuthenticatorStateUpdate { - epoch: 0, - round: 0, - new_active_jwks: jwks - .into_iter() - .map(|(jwk_id, jwk)| ActiveJwk { - jwk_id, - jwk, - epoch: 0, - }) - .collect(), - authenticator_obj_initial_shared_version: 1.into(), - }); - - let transfer_transaction = init_zklogin_transfer( - &authority_state, - object_id, - gas_object_id, - recipient, - sender, - pre_sign_mutations, - ephemeral_key, - zklogin, - ) - .await; - - let consensus_address = "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(); - - let server = AuthorityServer::new_for_test( - "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(), - authority_state.clone(), - consensus_address, - ); - let metrics = server.metrics.clone(); - - let server_handle = server.spawn_for_test().await.unwrap(); - - let client = NetworkAuthorityClient::connect(server_handle.address()) - .await - .unwrap(); - ( - object_ids, - gas_object_ids, - authority_state, - epoch_store, - transfer_transaction, - metrics, - server_handle, - client, - ) -} - -async fn init_zklogin_transfer( - authority_state: &Arc, - object_id: ObjectID, - gas_object_id: ObjectID, - recipient: SuiAddress, - sender: SuiAddress, - pre_sign_mutations: impl FnOnce(&mut TransactionData), - ephemeral_key: &Ed25519KeyPair, - zklogin: &ZkLoginInputs, -) -> sui_types::message_envelope::Envelope { - let rgp = authority_state.reference_gas_price_for_testing().unwrap(); - let object = authority_state - .get_object(&object_id) - .await - .unwrap() - .unwrap(); - let gas_object = authority_state - .get_object(&gas_object_id) - .await - .unwrap() - .unwrap(); - let object_ref = object.compute_object_reference(); - let gas_object_ref = gas_object.compute_object_reference(); - let gas_budget = rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER; - let mut data = TransactionData::new_transfer( - recipient, - object_ref, - sender, - gas_object_ref, - gas_budget, - rgp, - ); - pre_sign_mutations(&mut data); - let mut tx = to_sender_signed_transaction(data, ephemeral_key); - let GenericSignature::Signature(signature) = - tx.data_mut_for_testing().tx_signatures_mut_for_testing()[0].clone() - else { - panic!(); - }; - let authenticator = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( - zklogin.clone(), - 2, - signature, - )); - tx.data_mut_for_testing().tx_signatures_mut_for_testing()[0] = authenticator; - tx -} - -#[tokio::test] -async fn zklogin_txn_fail_if_missing_jwk() { - telemetry_subscribers::init_for_testing(); - - // Initialize an authorty state with some objects under a zklogin address. - let (skp, _eph_pk, zklogin) = - &load_test_vectors("../sui-types/src/unit_tests/zklogin_test_vectors.json")[1]; - let ephemeral_key = match skp { - SuiKeyPair::Ed25519(kp) => kp, - _ => panic!(), - }; - let sender = SuiAddress::try_from_unpadded(zklogin).unwrap(); - let recipient = dbg_addr(2); - let objects: Vec<_> = (0..10).map(|_| (sender, ObjectID::random())).collect(); - let gas_objects: Vec<_> = (0..10).map(|_| (sender, ObjectID::random())).collect(); - let object_ids: Vec<_> = objects.iter().map(|(_, id)| *id).collect(); - let gas_object_ids: Vec<_> = gas_objects.iter().map(|(_, id)| *id).collect(); - let authority_state = - init_state_with_ids(objects.into_iter().chain(gas_objects).collect::>()).await; - - // Initialize an authenticator state with a Google JWK. - let jwks = parse_jwks(DEFAULT_JWK_BYTES, &OIDCProvider::Google).unwrap(); - let epoch_store = authority_state.epoch_store_for_testing(); - epoch_store.update_authenticator_state(&AuthenticatorStateUpdate { - epoch: 0, - round: 0, - new_active_jwks: jwks - .into_iter() - .map(|(jwk_id, jwk)| ActiveJwk { - jwk_id, - jwk, - epoch: 0, - }) - .collect(), - authenticator_obj_initial_shared_version: 1.into(), - }); - - // Case 1: Submit a transaction with zklogin signature derived from a Twitch JWT - // should fail. - let txn1 = init_zklogin_transfer( - &authority_state, - object_ids[2], - gas_object_ids[2], - recipient, - sender, - |_| {}, - ephemeral_key, - zklogin, - ) - .await; - execute_transaction_assert_err(authority_state.clone(), txn1.clone(), object_ids.clone()).await; - - // Initialize an authenticator state with Twitch's kid as "nosuckkey". - pub const BAD_JWK_BYTES: &[u8] = r#"{"keys":[{"alg":"RS256","e":"AQAB","kid":"nosuchkey","kty":"RSA","n":"6lq9MQ-q6hcxr7kOUp-tHlHtdcDsVLwVIw13iXUCvuDOeCi0VSuxCCUY6UmMjy53dX00ih2E4Y4UvlrmmurK0eG26b-HMNNAvCGsVXHU3RcRhVoHDaOwHwU72j7bpHn9XbP3Q3jebX6KIfNbei2MiR0Wyb8RZHE-aZhRYO8_-k9G2GycTpvc-2GBsP8VHLUKKfAs2B6sW3q3ymU6M0L-cFXkZ9fHkn9ejs-sqZPhMJxtBPBxoUIUQFTgv4VXTSv914f_YkNw-EjuwbgwXMvpyr06EyfImxHoxsZkFYB-qBYHtaMxTnFsZBr6fn8Ha2JqT1hoP7Z5r5wxDu3GQhKkHw","use":"sig"}]}"#.as_bytes(); - let jwks = parse_jwks(BAD_JWK_BYTES, &OIDCProvider::Twitch).unwrap(); - epoch_store.update_authenticator_state(&AuthenticatorStateUpdate { - epoch: 0, - round: 0, - new_active_jwks: jwks - .into_iter() - .map(|(jwk_id, jwk)| ActiveJwk { - jwk_id, - jwk, - epoch: 0, - }) - .collect(), - authenticator_obj_initial_shared_version: 1.into(), - }); - - // Case 2: Submit a transaction with zklogin signature derived from a Twitch JWT - // with kid "1" should fail. - execute_transaction_assert_err(authority_state, txn1, object_ids).await; -} - -#[tokio::test] -async fn zk_multisig_test() { - telemetry_subscribers::init_for_testing(); - - // User generate a multisig account with no zklogin signer. - let keys = sui_types::utils::keys(); - let pk1 = keys[0].public(); - let pk2 = keys[1].public(); - let pk3 = keys[2].public(); - let multisig_pk = MultiSigPublicKey::new( - vec![pk1.clone(), pk2.clone(), pk3.clone()], - vec![1, 1, 1], - 2, - ) - .unwrap(); - let victim_addr = SuiAddress::from(&multisig_pk); - - let recipient = dbg_addr(2); - let object_id = ObjectID::random(); - let gas_object_id = ObjectID::random(); - let authority_state = - init_state_with_ids(vec![(victim_addr, object_id), (victim_addr, gas_object_id)]).await; - - let jwks = parse_jwks(DEFAULT_JWK_BYTES, &OIDCProvider::Twitch).unwrap(); - let epoch_store = authority_state.epoch_store_for_testing(); - epoch_store.update_authenticator_state(&AuthenticatorStateUpdate { - epoch: 0, - round: 0, - new_active_jwks: jwks - .into_iter() - .map(|(jwk_id, jwk)| ActiveJwk { - jwk_id, - jwk, - epoch: 0, - }) - .collect(), - authenticator_obj_initial_shared_version: 1.into(), - }); - - let rgp = authority_state.reference_gas_price_for_testing().unwrap(); - let object = authority_state - .get_object(&object_id) - .await - .unwrap() - .unwrap(); - let gas_object = authority_state - .get_object(&gas_object_id) - .await - .unwrap() - .unwrap(); - - let data = TransactionData::new_transfer( - recipient, - object.compute_object_reference(), - victim_addr, - gas_object.compute_object_reference(), - rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, - rgp, - ); - - // Step 1. construct 2 zklogin signatures - let test_vectors = - &load_test_vectors("../sui-types/src/unit_tests/zklogin_test_vectors.json")[1..]; - let mut zklogin_sigs = vec![]; - for (kp, _pk_zklogin, inputs) in test_vectors { - let intent_message = IntentMessage::new(Intent::sui_transaction(), data.clone()); - let eph_sig = Signature::new_secure(&intent_message, kp); - let zklogin_sig = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( - inputs.clone(), - 2, - eph_sig, - )); - zklogin_sigs.push(zklogin_sig); - } - - // Step 2. Construct the fake multisig with the zklogin signatures. - let multisig = MultiSig::insecure_new( - vec![ - zklogin_sigs[0].clone().to_compressed().unwrap(), - zklogin_sigs[1].clone().to_compressed().unwrap(), - ], // zklogin sigs - 3, - multisig_pk, - ); - let generic_sig = GenericSignature::MultiSig(multisig); - let transfer_transaction = Transaction::from_generic_sig_data(data, vec![generic_sig]); - - execute_transaction_assert_err(authority_state, transfer_transaction, vec![object_id]).await; -} - -async fn execute_transaction_assert_err( - authority_state: Arc, - txn: Transaction, - object_ids: Vec, -) { - let consensus_address = "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(); - - let server = AuthorityServer::new_for_test( - "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(), - authority_state.clone(), - consensus_address, - ); - - let server_handle = server.spawn_for_test().await.unwrap(); - - let client = NetworkAuthorityClient::connect(server_handle.address()) - .await - .unwrap(); - - let err = client.handle_transaction(txn.clone()).await; - - assert!(dbg!(err).is_err()); - - check_locks(authority_state.clone(), object_ids).await; -} - -#[tokio::test] -async fn test_oversized_txn() { - telemetry_subscribers::init_for_testing(); - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let recipient = dbg_addr(2); - let object_id = ObjectID::random(); - let authority_state = init_state_with_ids(vec![(sender, object_id)]).await; - let max_txn_size = authority_state - .epoch_store_for_testing() - .protocol_config() - .max_tx_size_bytes() as usize; - let object = authority_state - .get_object(&object_id) - .await - .unwrap() - .unwrap(); - let obj_ref = object.compute_object_reference(); - - // Construct an oversized txn. - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - // Put a lot of commands in the txn so it's large. - for _ in 0..(1024 * 16) { - builder.transfer_object(recipient, obj_ref).unwrap(); - } - builder.finish() - }; - - let txn_data = TransactionData::new_programmable(sender, vec![obj_ref], pt, 0, 0); - - let txn = to_sender_signed_transaction(txn_data, &sender_key); - let tx_size = bcs::serialized_size(&txn).unwrap(); - - // Making sure the txn is larger than the max txn size. - assert!(tx_size > max_txn_size); - - let consensus_address = "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(); - - let server = AuthorityServer::new_for_test( - "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(), - authority_state.clone(), - consensus_address, - ); - - let server_handle = server.spawn_for_test().await.unwrap(); - - let client = NetworkAuthorityClient::connect(server_handle.address()) - .await - .unwrap(); - - let res = client.handle_transaction(txn).await; - // The txn should be rejected due to its size. - assert!( - res.err() - .unwrap() - .to_string() - .contains("serialized transaction size exceeded maximum") - ); -} - -#[tokio::test] -async fn test_very_large_certificate() { - telemetry_subscribers::init_for_testing(); - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let recipient = dbg_addr(2); - let object_id = ObjectID::random(); - let gas_object_id = ObjectID::random(); - let authority_state = - init_state_with_ids(vec![(sender, object_id), (sender, gas_object_id)]).await; - let rgp = authority_state.reference_gas_price_for_testing().unwrap(); - let object = authority_state - .get_object(&object_id) - .await - .unwrap() - .unwrap(); - let gas_object = authority_state - .get_object(&gas_object_id) - .await - .unwrap() - .unwrap(); - - let transfer_transaction = init_transfer_transaction( - |_| {}, - sender, - &sender_key, - recipient, - object.compute_object_reference(), - gas_object.compute_object_reference(), - rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, - rgp, - ); - - let consensus_address = "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(); - - let server = AuthorityServer::new_for_test( - "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(), - authority_state.clone(), - consensus_address, - ); - - let server_handle = server.spawn_for_test().await.unwrap(); - - let client = NetworkAuthorityClient::connect(server_handle.address()) - .await - .unwrap(); - - let auth_sig = client - .handle_transaction(transfer_transaction.clone()) - .await - .unwrap() - .status - .into_signed_for_testing(); - - let signatures: BTreeMap<_, _> = vec![auth_sig] - .into_iter() - .map(|a| (a.authority, a.signature)) - .collect(); - - // Insert a lot into the bitmap so the cert is very large, while the txn inside - // is reasonably sized. - let mut signers_map = roaring::bitmap::RoaringBitmap::new(); - signers_map.insert_range(0..52108864); - let sigs: Vec = signatures.into_values().collect(); - - let quorum_signature = sui_types::crypto::AuthorityQuorumSignInfo { - epoch: 0, - signature: sui_types::crypto::AggregateAuthoritySignature::aggregate(&sigs) - .map_err(|e| SuiError::InvalidSignature { - error: e.to_string(), - }) - .expect("Validator returned invalid signature"), - signers_map, - }; - let cert = sui_types::message_envelope::Envelope::new_from_data_and_sig( - transfer_transaction.into_data(), - quorum_signature, - ); - - let res = client.handle_certificate_v2(cert).await; - assert!(res.is_err()); - let err = res.err().unwrap(); - // The resulting error should be a RpcError with a message length too large. - assert!( - matches!(err, SuiError::RpcError(..)) - && err.to_string().contains("message length too large") - ); -} - -#[tokio::test] -async fn test_handle_certificate_errors() { - telemetry_subscribers::init_for_testing(); - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let recipient = dbg_addr(2); - let object_id = ObjectID::random(); - let gas_object_id = ObjectID::random(); - let authority_state = - init_state_with_ids(vec![(sender, object_id), (sender, gas_object_id)]).await; - let rgp = authority_state.reference_gas_price_for_testing().unwrap(); - let object = authority_state - .get_object(&object_id) - .await - .unwrap() - .unwrap(); - let gas_object = authority_state - .get_object(&gas_object_id) - .await - .unwrap() - .unwrap(); - - let transfer_transaction = init_transfer_transaction( - |_| {}, - sender, - &sender_key, - recipient, - object.compute_object_reference(), - gas_object.compute_object_reference(), - rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, - rgp, - ); - - let consensus_address: Multiaddr = "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(); - - let server = AuthorityServer::new_for_test( - "/ip4/127.0.0.1/tcp/0/http".parse().unwrap(), - authority_state.clone(), - consensus_address.clone(), - ); - - let server_handle = server.spawn_for_test().await.unwrap(); - - let client = NetworkAuthorityClient::connect(server_handle.address()) - .await - .unwrap(); - - // Test handle certificate from the wrong epoch - let epoch_store = authority_state.epoch_store_for_testing(); - let next_epoch = epoch_store.epoch() + 1; - let signed_transaction = VerifiedSignedTransaction::new( - next_epoch, - VerifiedTransaction::new_unchecked(transfer_transaction.clone()), - authority_state.name, - &*authority_state.secret, - ); - - let mut committee_1 = epoch_store.committee().deref().clone(); - committee_1.epoch = next_epoch; - let ct = CertifiedTransaction::new( - transfer_transaction.data().clone(), - vec![signed_transaction.auth_sig().clone()], - &committee_1, - ) - .unwrap(); - - let err = client.handle_certificate_v2(ct.clone()).await.unwrap_err(); - assert_matches!( - err, - SuiError::WrongEpoch { - expected_epoch: 0, - actual_epoch: 1 - } - ); - - // Test handle certificate with invalid user input - let signed_transaction = VerifiedSignedTransaction::new( - epoch_store.epoch(), - VerifiedTransaction::new_unchecked(transfer_transaction.clone()), - authority_state.name, - &*authority_state.secret, - ); - - let mut empty_tx = transfer_transaction.clone(); - let data = empty_tx.data_mut_for_testing(); - data.inner_vec_mut_for_testing().clear(); - - let committee = epoch_store.committee().deref().clone(); - let ct = CertifiedTransaction::new( - data.clone(), - vec![signed_transaction.auth_sig().clone()], - &committee, - ) - .unwrap(); - - let err = client.handle_certificate_v2(ct.clone()).await.unwrap_err(); - - assert_matches!( - err, - SuiError::UserInputError { - error: UserInputError::Unsupported(message) - } if message == "SenderSignedData must contain exactly one transaction" - ); - - let tx = VerifiedTransaction::new_consensus_commit_prologue(0, 0, 42); - let ct = CertifiedTransaction::new( - tx.data().clone(), - vec![signed_transaction.auth_sig().clone()], - &committee, - ) - .unwrap(); - - let err = client.handle_certificate_v2(ct.clone()).await.unwrap_err(); - - assert_matches!( - err, - SuiError::UserInputError { - error: UserInputError::Unsupported(message) - } if message == "SenderSignedData must not contain system transaction" - ); - - let mut invalid_sig_count_tx = transfer_transaction.clone(); - let data = invalid_sig_count_tx.data_mut_for_testing(); - data.tx_signatures_mut_for_testing().clear(); - let ct = CertifiedTransaction::new( - data.clone(), - vec![signed_transaction.auth_sig().clone()], - &committee, - ) - .unwrap(); - let err = client.handle_certificate_v2(ct.clone()).await.unwrap_err(); - - assert_matches!( - err, - SuiError::SignerSignatureNumberMismatch { - expected: 1, - actual: 0 - } - ); - - let mut absent_sig_tx = transfer_transaction.clone(); - let (_unknown_address, unknown_key): (_, AccountKeyPair) = get_key_pair(); - let data = absent_sig_tx.data_mut_for_testing(); - *data.tx_signatures_mut_for_testing() = - vec![Signature::new_secure(data.intent_message(), &unknown_key).into()]; - let ct = CertifiedTransaction::new( - data.clone(), - vec![signed_transaction.auth_sig().clone()], - &committee, - ) - .unwrap(); - - let err = client.handle_certificate_v2(ct.clone()).await.unwrap_err(); - - assert_matches!(err, SuiError::SignerSignatureAbsent { .. }); -} diff --git a/crates/sui-core/src/unit_tests/transfer_to_object_tests.rs b/crates/sui-core/src/unit_tests/transfer_to_object_tests.rs deleted file mode 100644 index 2806be49577..00000000000 --- a/crates/sui-core/src/unit_tests/transfer_to_object_tests.rs +++ /dev/null @@ -1,1784 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::HashSet, sync::Arc}; - -use move_core_types::ident_str; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress}, - crypto::{get_key_pair, AccountKeyPair}, - digests::ObjectDigest, - effects::{TransactionEffects, TransactionEffectsAPI}, - error::{SuiError, UserInputError}, - execution_status::{ExecutionFailureStatus, ExecutionStatus}, - object::{Object, Owner}, - programmable_transaction_builder::ProgrammableTransactionBuilder, - transaction::{ - CallArg, ObjectArg, ProgrammableTransaction, VerifiedCertificate, - TEST_ONLY_GAS_UNIT_FOR_PUBLISH, - }, -}; - -use crate::{ - authority::{ - authority_test_utils::{certify_transaction, send_consensus}, - authority_tests::{ - build_programmable_transaction, execute_programmable_transaction, - execute_programmable_transaction_with_shared, - }, - move_integration_tests::build_and_publish_test_package_with_upgrade_cap, - test_authority_builder::TestAuthorityBuilder, - AuthorityState, - }, - move_call, -}; - -// The primary use for these tests is to make sure the generated effect sets -// match what we expect when receiving an object, and if we then perform -// different types of operations on the received object (e.g., deleting, -// wrapping, unwrapping, adding as a dynamic field, etc.) and various -// combinations of that. Some of these tests also check and validate locking -// behavior around receiving object arguments as well. - -// Run the test twice -- once with aggressive pruning enabled, and the other -// with it not enabled. -macro_rules! transfer_test_runner { - (gas_objects: $num:expr, $expr:expr) => { - let runner = TestRunner::new_with_objects("tto", $num, false).await; - #[allow(clippy::redundant_closure_call)] - $expr(runner).await; - let runner = TestRunner::new_with_objects("tto", $num, true).await; - #[allow(clippy::redundant_closure_call)] - $expr(runner).await; - }; - ($expr:expr) => { - let runner = TestRunner::new("tto", false).await; - #[allow(clippy::redundant_closure_call)] - $expr(runner).await; - let runner = TestRunner::new("tto", true).await; - #[allow(clippy::redundant_closure_call)] - $expr(runner).await; - }; -} - -struct TestRunner { - pub sender: SuiAddress, - pub sender_key: AccountKeyPair, - pub gas_object_ids: Vec, - pub authority_state: Arc, - pub package: ObjectRef, - pub upgrade_cap: ObjectRef, - pub rgp: u64, - pub aggressive_pruning_enabled: bool, -} - -impl TestRunner { - pub async fn new_with_objects( - base_package_name: &str, - num: usize, - aggressive_pruning_enabled: bool, - ) -> Self { - telemetry_subscribers::init_for_testing(); - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - - let authority_state = TestAuthorityBuilder::new().build().await; - let rgp = authority_state.reference_gas_price_for_testing().unwrap(); - let mut gas_object_ids = vec![]; - for _ in 0..num { - let gas_object_id = ObjectID::random(); - let gas_object = Object::with_id_owner_for_testing(gas_object_id, sender); - authority_state.insert_genesis_object(gas_object).await; - gas_object_ids.push(gas_object_id); - } - - let (package, upgrade_cap) = build_and_publish_test_package_with_upgrade_cap( - &authority_state, - &sender, - &sender_key, - &gas_object_ids[0], - base_package_name, - // with_unpublished_deps - false, - ) - .await; - - Self { - sender, - sender_key, - gas_object_ids, - authority_state, - package, - upgrade_cap, - rgp, - aggressive_pruning_enabled, - } - } - - pub async fn new(base_package_name: &str, aggressive_pruning_enabled: bool) -> Self { - Self::new_with_objects(base_package_name, 1, aggressive_pruning_enabled).await - } - - pub async fn signing_error(&mut self, pt: ProgrammableTransaction) -> SuiError { - execute_programmable_transaction( - &self.authority_state, - &self.gas_object_ids[0], - &self.sender, - &self.sender_key, - pt, - self.rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, - ) - .await - .map(|_| ()) - .unwrap_err() - } - - pub async fn run_with_gas_object( - &mut self, - pt: ProgrammableTransaction, - idx: usize, - ) -> TransactionEffects { - let effects = execute_programmable_transaction( - &self.authority_state, - &self.gas_object_ids[idx], - &self.sender, - &self.sender_key, - pt, - self.rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, - ) - .await - .unwrap(); - - if self.aggressive_pruning_enabled { - self.authority_state - .database_for_testing() - .prune_objects_immediately_for_testing(vec![effects.clone()]) - .await - .unwrap(); - } - - if let Some(updated_cap) = effects - .mutated() - .into_iter() - .find_map(|(cap, _)| (cap.0 == self.upgrade_cap.0).then_some(cap)) - { - self.upgrade_cap = updated_cap; - } - - effects - } - - pub async fn run_with_gas_object_shared( - &mut self, - pt: ProgrammableTransaction, - idx: usize, - ) -> TransactionEffects { - let effects = execute_programmable_transaction_with_shared( - &self.authority_state, - &self.gas_object_ids[idx], - &self.sender, - &self.sender_key, - pt, - self.rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, - ) - .await - .unwrap(); - - if self.aggressive_pruning_enabled { - self.authority_state - .database_for_testing() - .prune_objects_immediately_for_testing(vec![effects.clone()]) - .await - .unwrap(); - } - - if let Some(updated_cap) = effects - .mutated() - .into_iter() - .find_map(|(cap, _)| (cap.0 == self.upgrade_cap.0).then_some(cap)) - { - self.upgrade_cap = updated_cap; - } - - effects - } - - pub async fn run(&mut self, pt: ProgrammableTransaction) -> TransactionEffects { - self.run_with_gas_object(pt, 0).await - } - - pub async fn lock_and_verify_transaction( - &mut self, - pt: ProgrammableTransaction, - account_id: usize, - ) -> VerifiedCertificate { - let transaction = build_programmable_transaction( - &self.authority_state, - &self.gas_object_ids[account_id], - &self.sender, - &self.sender_key, - pt, - TEST_ONLY_GAS_UNIT_FOR_PUBLISH, - ) - .await - .unwrap(); - certify_transaction(&self.authority_state, transaction) - .await - .unwrap() - } - - pub async fn execute_certificate( - &mut self, - ct: VerifiedCertificate, - shared: bool, - ) -> TransactionEffects { - let epoch_store = self.authority_state.load_epoch_store_one_call_per_task(); - if shared { - send_consensus(&self.authority_state, &ct).await; - } - // Call `execute_certificate` instead of - // `execute_certificate_with_execution_error` to make sure we go through TM - let effects = self - .authority_state - .execute_certificate(&ct, &epoch_store) - .await - .unwrap() - .inner() - .clone() - .into_data(); - - if self.aggressive_pruning_enabled { - self.authority_state - .database_for_testing() - .prune_objects_immediately_for_testing(vec![effects.clone()]) - .await - .unwrap(); - } - effects - } -} - -fn get_parent_and_child( - created: Vec<(ObjectRef, Owner)>, -) -> ((ObjectRef, Owner), (ObjectRef, Owner)) { - // make sure there is an object with an `AddressOwner` who matches the object ID - // of another object. - let created_addrs: HashSet<_> = created.iter().map(|((i, _, _), _)| i).collect(); - let (child, parent_id) = created - .iter() - .find_map(|child @ (_, owner)| match owner { - Owner::AddressOwner(j) if created_addrs.contains(&ObjectID::from(*j)) => { - Some((child, (*j).into())) - } - _ => None, - }) - .unwrap(); - let parent = *created - .iter() - .find(|((id, _, _), _)| *id == parent_id) - .unwrap(); - (parent, *child) -} - -#[tokio::test] -async fn test_tto_transfer() { - transfer_test_runner! { |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M1::start() - }; - builder.finish() - }) - .await; - - let (parent, child) = get_parent_and_child(effects.created()); - let transfer_digest = effects.transaction_digest(); - - // No receive the sent object - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M1::receiver(parent, child) - }; - builder.finish() - }) - .await; - - assert!(effects.status().is_ok()); - assert!(effects.created().is_empty()); - assert!(effects.unwrapped().is_empty()); - assert!(effects.deleted().is_empty()); - assert!(effects.unwrapped_then_deleted().is_empty()); - assert!(effects.wrapped().is_empty()); - assert!(effects.dependencies().contains(transfer_digest)); - - for (obj_ref, owner) in effects.mutated().iter() { - if obj_ref.0 == child.0 .0 { - // Child should be sent to 0x0 - assert_eq!(owner, &Owner::AddressOwner(SuiAddress::ZERO)); - // It's version should be bumped as well - assert!(obj_ref.1 > child.0 .1); - } - if obj_ref.0 == parent.0 .0 { - // owner of the parent stays the same - assert_eq!(owner, &parent.1); - // parent version is also bumped - assert!(obj_ref.1 > parent.0 .1); - } - } - } - } -} - -#[tokio::test] -async fn test_tto_intersection_input_and_receiving_objects() { - transfer_test_runner! { |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M1::start() - }; - builder.finish() - }) - .await; - - let (parent, child) = get_parent_and_child(effects.created()); - let parent_receiving_arg = CallArg::Object(ObjectArg::Receiving(parent.0)); - let child_receiving_arg = CallArg::Object(ObjectArg::Receiving(child.0)); - - // Duplicate object reference between receiving and input object arguments. - let SuiError::UserInputError { error } = runner - .signing_error({ - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M1::receiver(parent, child) - }; - let mut built = builder.finish(); - built.inputs.push(parent_receiving_arg); - built - }) - .await else { - panic!("expected signing error"); - }; - assert!(matches!(error, UserInputError::DuplicateObjectRefInput)); - - // Duplicate object reference in receiving object arguments. - let SuiError::UserInputError { error } = runner - .signing_error({ - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M1::receiver(parent, child) - }; - let mut built = builder.finish(); - built.inputs.push(child_receiving_arg); - built - }) - .await else { - panic!("expected signing error"); - }; - assert!(matches!(error, UserInputError::DuplicateObjectRefInput)); - } - } -} - -#[tokio::test] -async fn test_tto_invalid_receiving_arguments() { - transfer_test_runner! { |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M1::start() - }; - builder.finish() - }) - .await; - - let (parent, child) = get_parent_and_child(effects.created()); - let package_object_ref = runner.package; - let shared = *effects - .created() - .iter() - .find(|(_, owner)| matches!(owner, Owner::Shared { .. })) - .unwrap(); - let immutable = *effects - .created() - .iter() - .find(|(_, owner)| matches!(owner, Owner::Immutable)) - .unwrap(); - let object_owned = *effects - .created() - .iter() - .find(|(_, owner)| matches!(owner, Owner::ObjectOwner(_))) - .unwrap(); - - #[allow(clippy::type_complexity)] - let mutations: Vec<( - Box ObjectRef>, - Box bool>, - )> = vec![ - ( - Box::new(|x: ObjectRef| (x.0, SequenceNumber::MAX, x.2)), - Box::new(|err| matches!(err, UserInputError::InvalidSequenceNumber)), - ), - ( - Box::new(|x: ObjectRef| (ObjectID::ZERO, x.1, x.2)), - Box::new(|err| matches!(err, UserInputError::ObjectNotFound { .. })), - ), - ( - Box::new(|x: ObjectRef| (x.0, x.1.next(), x.2)), - Box::new(|err| { - matches!( - err, - UserInputError::ObjectVersionUnavailableForConsumption { .. } - ) - }), - ), - ( - Box::new(|x: ObjectRef| (x.0, x.1.one_before().unwrap(), x.2)), - Box::new(|err| { - matches!( - err, - UserInputError::ObjectVersionUnavailableForConsumption { .. } - ) - }), - ), - ( - Box::new(|_: ObjectRef| package_object_ref), - Box::new(|err| matches!(err, UserInputError::MovePackageAsObject { .. })), - ), - ( - Box::new(|x: ObjectRef| (x.0, x.1, ObjectDigest::random())), - Box::new(|err| matches!(err, UserInputError::InvalidObjectDigest { .. })), - ), - ( - Box::new(|_: ObjectRef| shared.0), - Box::new(|err| matches!(err, UserInputError::NotSharedObjectError)), - ), - ( - Box::new(|_: ObjectRef| object_owned.0), - Box::new(|err| matches!(err, UserInputError::InvalidChildObjectArgument { .. })), - ), - ( - Box::new(|_: ObjectRef| immutable.0), - Box::new(|err| matches!(err, UserInputError::MutableParameterExpected { .. })), - ), - ]; - - for (i, (mutate, expect)) in mutations.into_iter().enumerate() { - let SuiError::UserInputError { error } = runner.signing_error({ - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(mutate(child.0))).unwrap(); - move_call! { - builder, - (runner.package.0)::M1::receiver(parent, child) - }; - builder.finish() - }) - .await else { - panic!("failed on iteration {}", i); - }; - assert!( - expect(error), - "failed to match expected error on iteration {}", - i - ); - } - } - } -} - -#[tokio::test] -async fn test_tto_unused_receiver() { - transfer_test_runner! { |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M1::start() - }; - builder.finish() - }) - .await; - - let (parent, child) = get_parent_and_child(effects.created()); - - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - builder.finish() - }) - .await; - - assert!(effects.status().is_ok()); - assert!(effects.created().is_empty()); - assert!(effects.unwrapped().is_empty()); - assert!(effects.deleted().is_empty()); - assert!(effects.unwrapped_then_deleted().is_empty()); - assert!(effects.wrapped().is_empty()); - - // If the receiving argument is not used it should not be modified! - assert!(!effects - .modified_at_versions() - .iter() - .any(|(i, _)| i == &child.0 .0)); - // Since the parent was not used but it was an input object, it should be modified - assert!(effects - .modified_at_versions() - .iter() - .any(|(i, _)| i == &parent.0 .0)); - - // Make sure parent exists in mutated, and the version is bumped. - for (obj_ref, owner) in effects.mutated().iter() { - if obj_ref.0 == parent.0 .0 { - // owner of the parent stays the same - assert_eq!(owner, &parent.1); - // parent version is also bumped - assert!(obj_ref.1 > parent.0 .1); - } - } - } - } -} - -#[tokio::test] -async fn test_tto_pass_receiving_by_refs() { - transfer_test_runner! { |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M1::start() - }; - builder.finish() - }) - .await; - - let (parent, child) = get_parent_and_child(effects.created()); - - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M1::call_immut_ref(parent, child) - }; - move_call! { - builder, - (runner.package.0)::M1::call_mut_ref(parent, child) - }; - builder.finish() - }) - .await; - - assert!(effects.status().is_ok()); - assert!(effects.created().is_empty()); - assert!(effects.unwrapped().is_empty()); - assert!(effects.deleted().is_empty()); - assert!(effects.unwrapped_then_deleted().is_empty()); - assert!(effects.wrapped().is_empty()); - - // If the receiving argument is not used it should not be modified! - assert!(!effects - .modified_at_versions() - .iter() - .any(|(i, _)| i == &child.0 .0)); - // Since the parent was not used but it was an input object, it should be modified - assert!(effects - .modified_at_versions() - .iter() - .any(|(i, _)| i == &parent.0 .0)); - - // Make sure parent exists in mutated, and the version is bumped. - for (obj_ref, owner) in effects.mutated().iter() { - if obj_ref.0 == parent.0 .0 { - // owner of the parent stays the same - assert_eq!(owner, &parent.1); - // parent version is also bumped - assert!(obj_ref.1 > parent.0 .1); - } - } - } - } -} - -#[tokio::test] -async fn test_tto_delete() { - transfer_test_runner! { |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M1::start() - }; - builder.finish() - }) - .await; - - let (parent, child) = get_parent_and_child(effects.created()); - - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M1::deleter(parent, child) - }; - builder.finish() - }) - .await; - - assert!(effects.status().is_ok()); - assert!(effects.created().is_empty()); - assert!(effects.unwrapped().is_empty()); - assert!(effects.unwrapped_then_deleted().is_empty()); - assert!(effects.wrapped().is_empty()); - // Deleted should be non-empty - assert_eq!(effects.deleted().len(), 1); - // Deleted should contain the child object - assert_eq!(effects.deleted()[0].0, child.0 .0); - - // Make sure parent exists in mutated, and the version is bumped. - for (obj_ref, owner) in effects.mutated().iter() { - if obj_ref.0 == parent.0 .0 { - // owner of the parent stays the same - assert_eq!(owner, &parent.1); - // parent version is also bumped - assert!(obj_ref.1 > parent.0 .1); - } - } - } - } -} - -#[tokio::test] -async fn test_tto_wrap() { - transfer_test_runner! { |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M1::start() - }; - builder.finish() - }) - .await; - - let (parent, child) = get_parent_and_child(effects.created()); - - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M1::wrapper(parent, child) - }; - builder.finish() - }) - .await; - - assert!(effects.status().is_ok()); - assert!(effects.unwrapped().is_empty()); - assert!(effects.unwrapped_then_deleted().is_empty()); - assert!(effects.deleted().is_empty()); - // We created an object since we wrapped this when we received the transaction - assert_eq!(effects.created().len(), 1); - // Wrapped should be non-empty - assert_eq!(effects.wrapped().len(), 1); - // Wrapped should contain the child object - assert_eq!(effects.wrapped()[0].0, child.0 .0); - - // Make sure parent exists in mutated, and the version is bumped. - for (obj_ref, owner) in effects.mutated().iter() { - if obj_ref.0 == parent.0 .0 { - // owner of the parent stays the same - assert_eq!(owner, &parent.1); - // parent version is also bumped - assert!(obj_ref.1 > parent.0 .1); - } - } - } - } -} - -#[tokio::test] -async fn test_tto_unwrap_transfer() { - transfer_test_runner! { |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M2::start() - }; - builder.finish() - }) - .await; - - let (parent, child) = get_parent_and_child(effects.created()); - - // No receive the sent object - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M2::unwrap_receiver(parent, child) - }; - builder.finish() - }) - .await; - - assert!(effects.status().is_ok()); - assert!(effects.created().is_empty()); - assert!(effects.unwrapped_then_deleted().is_empty()); - assert!(effects.wrapped().is_empty()); - - // Unwrapped should be size 1 - assert_eq!(effects.unwrapped().len(), 1); - // The now-unwrapped object should be sent to 0x0 - assert_eq!( - effects.unwrapped()[0].1, - Owner::AddressOwner(SuiAddress::ZERO) - ); - - // Receiving object ID is deleted - assert_eq!(effects.deleted().len(), 1); - // Deleted should contain the child object id - assert_eq!(effects.deleted()[0].0, child.0 .0); - - for (obj_ref, owner) in effects.mutated().iter() { - // child ref should not be mutated since it was deleted - assert_ne!(obj_ref.0, child.0 .0); - if obj_ref.0 == parent.0 .0 { - // owner of the parent stays the same - assert_eq!(owner, &parent.1); - // parent version is also bumped - assert!(obj_ref.1 > parent.0 .1); - } - } - } - } -} - -#[tokio::test] -async fn test_tto_unwrap_delete() { - transfer_test_runner! { |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M2::start() - }; - builder.finish() - }) - .await; - - let (parent, child) = get_parent_and_child(effects.created()); - - // No receive the sent object - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M2::unwrap_deleter(parent, child) - }; - builder.finish() - }) - .await; - - assert!(effects.status().is_ok()); - assert!(effects.created().is_empty()); - assert!(effects.unwrapped().is_empty()); - assert!(effects.wrapped().is_empty()); - - // The deleted should be of size 1, and should contain the child address - assert_eq!(effects.deleted().len(), 1); - assert_eq!(effects.deleted()[0].0, child.0 .0); - - // Unwrapped then deleted should be of size 1 since we deleted the inner object as well. - assert_eq!(effects.unwrapped_then_deleted().len(), 1); - - for (obj_ref, owner) in effects.mutated().iter() { - // child ref should not be mutated since it was deleted - assert_ne!(obj_ref.0, child.0 .0); - if obj_ref.0 == parent.0 .0 { - // owner of the parent stays the same - assert_eq!(owner, &parent.1); - // parent version is also bumped - assert!(obj_ref.1 > parent.0 .1); - } - } - } - } -} - -#[tokio::test] -async fn test_tto_unwrap_add_as_dynamic_field() { - transfer_test_runner! { |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M2::start() - }; - builder.finish() - }) - .await; - - let (parent, child) = get_parent_and_child(effects.created()); - - // No receive the sent object - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M2::unwrap_add_dyn(parent, child) - }; - builder.finish() - }) - .await; - - assert!(effects.status().is_ok()); - // Since it's placed as a dynamic field it will be rewrapped(). So `unwrapped` should be empty - assert!(effects.unwrapped().is_empty()); - // Similarly it was already wrapped, so even though we're wrapping with the dynamic field `wrapped` should be empty - assert!(effects.wrapped().is_empty()); - assert!(effects.unwrapped_then_deleted().is_empty()); - - assert_eq!(effects.created().len(), 1); - - // The deleted should be of size 1, and should contain the child address - assert_eq!(effects.deleted().len(), 1); - assert_eq!(effects.deleted()[0].0, child.0 .0); - - for (obj_ref, owner) in effects.mutated().iter() { - assert_ne!(obj_ref.0, child.0 .0); - if obj_ref.0 == parent.0 .0 { - // owner of the parent stays the same - assert_eq!(owner, &parent.1); - // parent version is also bumped - assert!(obj_ref.1 > parent.0 .1); - } - } - } - } -} - -// This tests that locks are not grabbed for receiving objects. -// This test does this by -// 1. Creating a parent object and child object -// 2. Creating a fake parent object -// 3. Create and sign a transaction `tx1` that tries to receive the child object -// using the fake parent. -// 4. Create and sign a transaction `tx2` that receives the child object using -// the valid parent object. -// 5. Execute `tx2` and verify that it can be executed successfully. -// 6. Execute `tx1` and verify that it can be executed, but will result in a -// Move abort. -// The order of steps 5 and 6 are swapped if `flipper` is `true`. -// The object is deleted instead of received if `should_delete` is `true`. -async fn verify_tto_not_locked( - flipper: bool, - should_delete: bool, - aggressive_pruning: bool, -) -> (TransactionEffects, TransactionEffects) { - let mut runner = TestRunner::new_with_objects("tto", 2, aggressive_pruning).await; - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M3::start() - }; - builder.finish() - }) - .await; - - let (parent, child) = get_parent_and_child(effects.created()); - let fake_parent = *effects - .created() - .iter() - .find(|(obj_ref, _)| obj_ref.0 != parent.0.0 && obj_ref.0 != child.0.0) - .unwrap(); - - // Now get a certificate for fake_parent/child1. This will lock input objects. - // NB: the receiving object is _not_ locked. - let cert_for_fake_parent = runner - .lock_and_verify_transaction( - { - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder - .obj(ObjectArg::ImmOrOwnedObject(fake_parent.0)) - .unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - if should_delete { - move_call!(builder, (runner.package.0)::M3::deleter(parent, child)); - } else { - move_call!(builder, (runner.package.0)::M3::receiver(parent, child)); - }; - builder.finish() - }, - 0, - ) - .await; - - // After the other (fake) transaction has been created and signed, sign and - // execute this transaction. This should have no issues because the - // receiving object is not locked by the signing of the transaction above. - let valid_cert = runner - .lock_and_verify_transaction( - { - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - if should_delete { - move_call!(builder, (runner.package.0)::M3::deleter(parent, child)); - } else { - move_call!(builder, (runner.package.0)::M3::receiver(parent, child)); - }; - builder.finish() - }, - 1, - ) - .await; - - // The order of the execution of these transactions is flipped depending on the - // value of flipper. However, the result should be the same in either case. - let (valid_effects, invalid_effects) = if flipper { - let invalid_effects = runner - .execute_certificate(cert_for_fake_parent, false) - .await; - let valid_effects = runner.execute_certificate(valid_cert, false).await; - (valid_effects, invalid_effects) - } else { - let valid_effects = runner.execute_certificate(valid_cert, false).await; - let invalid_effects = runner - .execute_certificate(cert_for_fake_parent, false) - .await; - (valid_effects, invalid_effects) - }; - - assert!(valid_effects.status().is_ok()); - assert!(invalid_effects.status().is_err()); - assert!(matches!( - invalid_effects.status(), - ExecutionStatus::Failure { - error: ExecutionFailureStatus::MoveAbort(_, _), - .. - } - )); - (valid_effects, invalid_effects) -} - -fn assert_effects_equivalent(ef1: &TransactionEffects, ef2: &TransactionEffects) { - assert_eq!(ef1.status(), ef2.status()); - assert_eq!(ef1.executed_epoch(), ef2.executed_epoch()); - assert_eq!(ef1.gas_cost_summary(), ef2.gas_cost_summary()); - assert_eq!( - ef1.modified_at_versions().len(), - ef2.modified_at_versions().len() - ); - assert_eq!(ef1.created().len(), ef2.created().len()); - assert_eq!(ef1.mutated().len(), ef2.mutated().len()); - assert_eq!(ef1.unwrapped().len(), ef2.unwrapped().len()); - assert_eq!(ef1.deleted().len(), ef2.deleted().len()); - assert_eq!( - ef1.unwrapped_then_deleted().len(), - ef2.unwrapped_then_deleted().len() - ); - assert_eq!(ef1.wrapped().len(), ef2.wrapped().len()); - assert_eq!(ef1.dependencies().len(), ef2.dependencies().len()); -} - -#[tokio::test] -async fn test_tto_not_locked() { - for aggressive_pruning_enabled in [true, false] { - // The transaction effects for the valid and invalid transactions should be the - // same regardless of the order in which they are run. - let (valid1, invalid1) = - verify_tto_not_locked(false, false, aggressive_pruning_enabled).await; - let (valid2, invalid2) = - verify_tto_not_locked(true, false, aggressive_pruning_enabled).await; - assert_effects_equivalent(&valid1, &valid2); - assert_effects_equivalent(&invalid1, &invalid2); - - // The same should hold if the object is deleted by an intervening transaction. - let (valid1, invalid1) = - verify_tto_not_locked(false, true, aggressive_pruning_enabled).await; - let (valid2, invalid2) = - verify_tto_not_locked(true, true, aggressive_pruning_enabled).await; - assert_effects_equivalent(&valid1, &valid2); - assert_effects_equivalent(&invalid1, &invalid2); - } -} - -#[tokio::test] -async fn test_tto_valid_dependencies() { - transfer_test_runner! {gas_objects: 3, |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M4::start1() - }; - builder.finish() - }) - .await; - let parent = effects.created()[0]; - - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M4::start2() - }; - builder.finish() - }) - .await; - let child = effects.created()[0]; - - // Use a different gas coin than for all the other transactions. This serves two purposes: - // 1. Makes sure that we are registering the dependency on the transaction that transferred the - // object solely because of the fact that we received it in this transaction. - // 2. Since the gas coin is fresh it will have a smaller version, so this will test that we - // properly compute and update the lamport version that we should use for the transaction. - let effects = runner - .run_with_gas_object( - { - let mut builder = ProgrammableTransactionBuilder::new(); - builder - .transfer_object(SuiAddress::from(parent.0 .0), child.0) - .unwrap(); - builder.finish() - }, - 1, - ) - .await; - - let child = *effects - .mutated() - .iter() - .find(|(o, _)| o.0 == child.0 .0) - .unwrap(); - let transfer_digest = effects.transaction_digest(); - - // No receive the sent object - let effects = runner - .run_with_gas_object( - { - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M4::receiver(parent, child) - }; - builder.finish() - }, - 2, - ) - .await; - - assert!(effects.status().is_ok()); - assert!(effects.created().is_empty()); - assert!(effects.unwrapped().is_empty()); - assert!(effects.deleted().is_empty()); - assert!(effects.unwrapped_then_deleted().is_empty()); - assert!(effects.wrapped().is_empty()); - assert!(effects.dependencies().contains(transfer_digest)); - - for (obj_ref, owner) in effects.mutated().iter() { - if obj_ref.0 == child.0 .0 { - // Child should be sent to 0x0 - assert_eq!(owner, &Owner::AddressOwner(SuiAddress::ZERO)); - // It's version should be bumped as well - assert!(obj_ref.1 > child.0 .1); - // The child should be the max version - assert_eq!(obj_ref.1.value(), child.0 .1.value() + 1); - } - if obj_ref.0 == parent.0 .0 { - // owner of the parent stays the same - assert_eq!(owner, &parent.1); - // parent version is also bumped - assert!(obj_ref.1 > parent.0 .1); - // The child should be the max version - assert_eq!(obj_ref.1.value(), child.0 .1.value() + 1); - } - } - } - } -} - -#[tokio::test] -async fn test_tto_valid_dependencies_delete_on_receive() { - transfer_test_runner! {gas_objects: 3, |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M4::start1() - }; - builder.finish() - }) - .await; - let parent = effects.created()[0]; - - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M4::start2() - }; - builder.finish() - }) - .await; - let child = effects.created()[0]; - - // Use a different gas coin than for all the other transactions. This serves two purposes: - // 1. Makes sure that we are registering the dependency on the transaction that transferred the - // object solely because of the fact that we received it in this transaction. - // 2. Since the gas coin is fresh it will have a smaller version, so this will test that we - // properly compute and update the lamport version that we should use for the transaction. - let effects = runner - .run_with_gas_object( - { - let mut builder = ProgrammableTransactionBuilder::new(); - builder - .transfer_object(SuiAddress::from(parent.0 .0), child.0) - .unwrap(); - builder.finish() - }, - 1, - ) - .await; - - let child = *effects - .mutated() - .iter() - .find(|(o, _)| o.0 == child.0 .0) - .unwrap(); - let transfer_digest = effects.transaction_digest(); - - // No receive and delete the sent object - let effects = runner - .run_with_gas_object( - { - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M4::deleter(parent, child) - }; - builder.finish() - }, - 2, - ) - .await; - - assert!(effects.status().is_ok()); - assert!(effects.created().is_empty()); - assert!(effects.unwrapped().is_empty()); - assert!(effects.unwrapped_then_deleted().is_empty()); - assert!(effects.wrapped().is_empty()); - // Deleted should be non-empty - assert_eq!(effects.deleted().len(), 1); - // Deleted should contain the child object - assert_eq!(effects.deleted()[0].0, child.0 .0); - assert!(effects.dependencies().contains(transfer_digest)); - - // Make sure parent exists in mutated, and the version is bumped and is equal to the child's - // version + 1 since the child has the highest version number in the transaction. - for (obj_ref, owner) in effects.mutated().iter() { - if obj_ref.0 == parent.0 .0 { - // owner of the parent stays the same - assert_eq!(owner, &parent.1); - // parent version is also bumped - assert!(obj_ref.1 > parent.0 .1); - assert_eq!(obj_ref.1.value(), child.0 .1.value() + 1); - } - } - } - } -} - -#[tokio::test] -async fn test_tto_dependencies_dont_receive() { - transfer_test_runner! {gas_objects: 3, |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M4::start1() - }; - builder.finish() - }) - .await; - let parent = effects.created()[0]; - - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M4::start2() - }; - builder.finish() - }) - .await; - let old_child = effects.created()[0]; - - // Use a different gas coin than for all the other transactions. This: - // 1. Makes sure that we are registering the dependency on the transaction that transferred the - // object solely because of the fact that we received it in this transaction. - // 2. Since the gas coin is fresh it will have a smaller version, so this will test that we - // properly compute and update the lamport version that we should use for the transaction. - let effects = runner - .run_with_gas_object( - { - let mut builder = ProgrammableTransactionBuilder::new(); - builder - .transfer_object(SuiAddress::from(parent.0 .0), old_child.0) - .unwrap(); - builder.finish() - }, - 1, - ) - .await; - - let child = *effects - .mutated() - .iter() - .find(|(o, _)| o.0 == old_child.0 .0) - .unwrap(); - let transfer_digest = effects.transaction_digest(); - - // ensure child version is greater than parent version, otherwise the check afterwards won't be - // checking the correct thing. - assert!(parent.0 .1.value() < child.0 .1.value()); - - // Now dont receive the sent object but include it in the arguments for the PTB. - let effects = runner - .run_with_gas_object( - { - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M4::nop(parent, child) - }; - builder.finish() - }, - 2, - ) - .await; - - assert!(effects.status().is_ok()); - assert!(effects.created().is_empty()); - assert!(effects.unwrapped().is_empty()); - assert!(effects.deleted().is_empty()); - assert!(effects.unwrapped_then_deleted().is_empty()); - assert!(effects.wrapped().is_empty()); - // Not received so dependency is not added. - assert!(!effects.dependencies().contains(transfer_digest)); - - for (obj_ref, owner) in effects.mutated().iter() { - assert_ne!(obj_ref.0, child.0 .0); - if obj_ref.0 == parent.0 .0 { - // owner of the parent stays the same - assert_eq!(owner, &parent.1); - // parent version is also bumped - assert!(obj_ref.1 > parent.0 .1); - // Parent version is the largest in this transaction - assert_eq!(obj_ref.1.value(), child.0 .1.value() + 1); - } - } - } - } -} - -#[tokio::test] -async fn test_tto_dependencies_dont_receive_but_abort() { - transfer_test_runner! {gas_objects: 3, |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M4::start1() - }; - builder.finish() - }) - .await; - let parent = effects.created()[0]; - - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M4::start2() - }; - builder.finish() - }) - .await; - let old_child = effects.created()[0]; - - // Use a different gas coin than for all the other transactions. This: - // 1. Makes sure that we are registering the dependency on the transaction that transferred the - // object solely because of the fact that we received it in this transaction. - // 2. Since the gas coin is fresh it will have a smaller version, so this will test that we - // properly compute and update the lamport version that we should use for the transaction. - let effects = runner - .run_with_gas_object( - { - let mut builder = ProgrammableTransactionBuilder::new(); - builder - .transfer_object(SuiAddress::from(parent.0 .0), old_child.0) - .unwrap(); - builder.finish() - }, - 1, - ) - .await; - - let child = *effects - .mutated() - .iter() - .find(|(o, _)| o.0 == old_child.0 .0) - .unwrap(); - let transfer_digest = effects.transaction_digest(); - - assert!(parent.0 .1.value() < child.0 .1.value()); - - let effects = runner - .run_with_gas_object( - { - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M4::aborter(parent, child) - }; - builder.finish() - }, - 2, - ) - .await; - - assert!(effects.status().is_err()); - assert!(effects.created().is_empty()); - assert!(effects.unwrapped().is_empty()); - assert!(effects.deleted().is_empty()); - assert!(effects.unwrapped_then_deleted().is_empty()); - assert!(effects.wrapped().is_empty()); - // Not received so dependency is not added. - assert!(!effects.dependencies().contains(transfer_digest)); - - for (obj_ref, owner) in effects.mutated().iter() { - assert_ne!(obj_ref.0, child.0 .0); - if obj_ref.0 == parent.0 .0 { - // owner of the parent stays the same - assert_eq!(owner, &parent.1); - // parent version is also bumped - assert!(obj_ref.1 > parent.0 .1); - // child version is the largest in this transaction, and even though it's not received - // it still contributes to the lamport version of the transaction. - assert_eq!(obj_ref.1.value(), child.0 .1.value() + 1); - } - } - } - } -} - -#[tokio::test] -async fn test_tto_dependencies_receive_and_abort() { - transfer_test_runner! {gas_objects: 3, |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M4::start1() - }; - builder.finish() - }) - .await; - let parent = effects.created()[0]; - - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M4::start2() - }; - builder.finish() - }) - .await; - let old_child = effects.created()[0]; - - // Use a different gas coin than for all the other transactions. This: - // 1. Makes sure that we are registering the dependency on the transaction that transferred the - // object solely because of the fact that we received it in this transaction. - // 2. Since the gas coin is fresh it will have a smaller version, so this will test that we - // properly compute and update the lamport version that we should use for the transaction. - let effects = runner - .run_with_gas_object( - { - let mut builder = ProgrammableTransactionBuilder::new(); - builder - .transfer_object(SuiAddress::from(parent.0 .0), old_child.0) - .unwrap(); - builder.finish() - }, - 1, - ) - .await; - - let child = *effects - .mutated() - .iter() - .find(|(o, _)| o.0 == old_child.0 .0) - .unwrap(); - let transfer_digest = effects.transaction_digest(); - - assert!(parent.0 .1.value() < child.0 .1.value()); - - let effects = runner - .run_with_gas_object( - { - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M4::receive_abort(parent, child) - }; - builder.finish() - }, - 2, - ) - .await; - - assert!(effects.status().is_err()); - assert!(effects.created().is_empty()); - assert!(effects.unwrapped().is_empty()); - assert!(effects.deleted().is_empty()); - assert!(effects.unwrapped_then_deleted().is_empty()); - assert!(effects.wrapped().is_empty()); - // Received but aborted -- dependency is still added. - assert!(effects.dependencies().contains(transfer_digest)); - - for (obj_ref, owner) in effects.mutated().iter() { - assert_ne!(obj_ref.0, child.0 .0); - if obj_ref.0 == parent.0 .0 { - // owner of the parent stays the same - assert_eq!(owner, &parent.1); - // parent version is also bumped - assert!(obj_ref.1 > parent.0 .1); - // Child version is the largest in this transaction even though it's not received - assert_eq!(obj_ref.1.value(), child.0 .1.value() + 1); - } - } - } - } -} - -#[tokio::test] -async fn test_tto_dependencies_receive_and_type_mismatch() { - transfer_test_runner! {gas_objects: 3, |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M4::start1() - }; - builder.finish() - }) - .await; - let parent = effects.created()[0]; - - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M4::start2() - }; - builder.finish() - }) - .await; - let old_child = effects.created()[0]; - - // Use a different gas coin than for all the other transactions. This: - // 1. Makes sure that we are registering the dependency on the transaction that transferred the - // object solely because of the fact that we received it in this transaction. - // 2. Since the gas coin is fresh it will have a smaller version, so this will test that we - // properly compute and update the lamport version that we should use for the transaction. - let effects = runner - .run_with_gas_object( - { - let mut builder = ProgrammableTransactionBuilder::new(); - builder - .transfer_object(SuiAddress::from(parent.0 .0), old_child.0) - .unwrap(); - builder.finish() - }, - 1, - ) - .await; - - let child = *effects - .mutated() - .iter() - .find(|(o, _)| o.0 == old_child.0 .0) - .unwrap(); - let transfer_digest = effects.transaction_digest(); - - assert!(parent.0 .1.value() < child.0 .1.value()); - - let effects = runner - .run_with_gas_object( - { - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M4::receive_type_mismatch(parent, child) - }; - builder.finish() - }, - 2, - ) - .await; - - assert!(effects.status().is_err()); - - // Type mismatch is an abort code of 2 from `receive_impl` - let is_type_mismatch_error = matches!( - effects.status().clone().unwrap_err().0, - ExecutionFailureStatus::MoveAbort(x, 2) if x.function_name == Some("receive_impl".to_string()) - ); - assert!(is_type_mismatch_error); - assert!(effects.created().is_empty()); - assert!(effects.unwrapped().is_empty()); - assert!(effects.deleted().is_empty()); - assert!(effects.unwrapped_then_deleted().is_empty()); - assert!(effects.wrapped().is_empty()); - // Received but there was a type mismatch -- dependency is still added. - assert!(effects.dependencies().contains(transfer_digest)); - - for (obj_ref, owner) in effects.mutated().iter() { - assert_ne!(obj_ref.0, child.0 .0); - if obj_ref.0 == parent.0 .0 { - // owner of the parent stays the same - assert_eq!(owner, &parent.1); - // parent version is also bumped - assert!(obj_ref.1 > parent.0 .1); - // Child version is the largest in this transaction even though it's not received - assert_eq!(obj_ref.1.value(), child.0 .1.value() + 1); - } - } - } - } -} - -#[tokio::test] -async fn receive_and_dof_interleave() { - transfer_test_runner! {gas_objects: 3, |mut runner: TestRunner| async move { - // step 1 & 2 - let effects = runner - .run_with_gas_object( - { - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M5::start() - }; - builder.finish() - }, - 0, - ) - .await; - - let shared = *effects - .created() - .iter() - .find(|(_, owner)| matches!(owner, Owner::Shared { .. })) - .unwrap(); - let owned = *effects - .created() - .iter() - .find(|(_, owner)| matches!(owner, Owner::AddressOwner(_))) - .unwrap(); - let Owner::Shared { initial_shared_version }= shared.1 else { unreachable!() }; - - let init_digest = effects.transaction_digest(); - - let cert = runner - .lock_and_verify_transaction( - { - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder - .obj(ObjectArg::SharedObject { - id: shared.0 .0, - initial_shared_version, - mutable: true, - }) - .unwrap(); - let child = builder.obj(ObjectArg::Receiving(owned.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M5::deleter(parent, child) - }; - builder.finish() - }, - 1, - ) - .await; - - let dof_effects = runner - .run_with_gas_object_shared( - { - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder - .obj(ObjectArg::SharedObject { - id: shared.0 .0, - initial_shared_version, - mutable: true, - }) - .unwrap(); - let child = builder.obj(ObjectArg::ImmOrOwnedObject(owned.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M5::add_dof(parent, child) - }; - builder.finish() - }, - 2, - ) - .await; - - assert!(dof_effects.status().is_ok()); - - let recv_effects = runner.execute_certificate(cert, true).await; - assert!(recv_effects.status().is_ok()); - // The recv_effects should not contain the dependency on the initial transaction since we - // didn't actually receive the object -- it was loaded via the dynamic field instead. - assert!(!recv_effects.dependencies().contains(init_digest)); - } - } -} - -#[tokio::test] -async fn test_have_deleted_owned_object() { - transfer_test_runner! { |mut runner: TestRunner| async move { - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - move_call! { - builder, - (runner.package.0)::M1::start() - }; - builder.finish() - }) - .await; - - let (parent, child) = get_parent_and_child(effects.created()); - - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M1::send_back(parent, child) - }; - builder.finish() - }) - .await; - - let (new_parent, new_child) = get_parent_and_child(effects.mutated()); - - let cache = runner.authority_state.get_cache_reader().clone(); - - assert!(cache.get_object(&new_child.0.0).unwrap().is_some()); - // Should not show as deleted for either versions - assert!(!cache.have_deleted_owned_object_at_version_or_after(&new_child.0.0, new_child.0.1, 0).unwrap()); - assert!(!cache.have_deleted_owned_object_at_version_or_after(&new_child.0.0, child.0.1, 0).unwrap()); - - let effects = runner - .run({ - let mut builder = ProgrammableTransactionBuilder::new(); - let parent = builder.obj(ObjectArg::ImmOrOwnedObject(new_parent.0)).unwrap(); - let child = builder.obj(ObjectArg::Receiving(new_child.0)).unwrap(); - move_call! { - builder, - (runner.package.0)::M1::deleter(parent, child) - }; - builder.finish() - }) - .await; - - let deleted_child = effects.deleted().into_iter().find(|(id, _, _)| *id == new_child.0 .0).unwrap(); - assert!(cache.get_object(&deleted_child.0).unwrap().is_none()); - assert!(cache.have_deleted_owned_object_at_version_or_after(&deleted_child.0, deleted_child.1, 0).unwrap()); - assert!(cache.have_deleted_owned_object_at_version_or_after(&deleted_child.0, new_child.0.1, 0).unwrap()); - assert!(cache.have_deleted_owned_object_at_version_or_after(&deleted_child.0, child.0.1, 0).unwrap()); - // Should not show as deleted for versions after this though - assert!(!cache.have_deleted_owned_object_at_version_or_after(&deleted_child.0, deleted_child.1.next(), 0).unwrap()); - // Should not show as deleted for other epochs outside of our current epoch too - assert!(!cache.have_deleted_owned_object_at_version_or_after(&deleted_child.0, deleted_child.1, 1).unwrap()); - } - } -} diff --git a/crates/sui-core/tests/README.md b/crates/sui-core/tests/README.md deleted file mode 100644 index 8d813a22b96..00000000000 --- a/crates/sui-core/tests/README.md +++ /dev/null @@ -1,66 +0,0 @@ -## What this test is about - -This repository checks the conformance of our code to a BCS-compatible manifest of our serialized data formats. - -It does this by running a manifest generator from the code (using serde-reflection) and checking the output has not changed. - -If it has in a legitimate fashion (e.g. we update one of our main types), all that's left to do is to re-run the generator and check in the change. - -Here are the references to the software above: -https://github.com/diem/bcs -https://github.com/novifinancial/serde-reflection - -## Examples - -In this example, we will update one of our core types (SuiError), and then update the manifest: - -``` -huitseeker@Garillots-MBP.localdomain➜~/tmp/sui(main)» git checkout main [7:40:40] -Already on 'main' -Your branch is up to date with 'origin/main'. -huitseeker@Garillots-MBP.localdomain➜~/tmp/sui(main)» ruplacer --subvert 'CertificateAuthorityReuse' 'CertificateAuthorityDuplicate' --go [8:42:33] -./sui_types/src/error.rs:103 - CertificateAuthorityReuse, -./sui_types/src/error.rs:103 + CertificateAuthorityDuplicate, - -./sui_types/src/messages.rs:610 - SuiError::CertificateAuthorityReuse -./sui_types/src/messages.rs:610 + SuiError::CertificateAuthorityDuplicate -./sui_types/src/messages.rs:638 - SuiError::CertificateAuthorityReuse -./sui_types/src/messages.rs:638 + SuiError::CertificateAuthorityDuplicate - -./sui_core/tests/staged/sui.yaml:390 - CertificateAuthorityReuse: UNIT -./sui_core/tests/staged/sui.yaml:390 + CertificateAuthorityDuplicate: UNIT - -Performed 4 replacements on 196 matching files -``` - -Now our code is modified in a way that will make the format test fail: let's update the manifest. - -``` -huitseeker@Garillots-MBP.localdomain➜~/tmp/sui(main✗)» cd sui_core [8:43:38] -huitseeker@Garillots-MBP.localdomain➜tmp/sui/sui_core(main✗)» cargo -q run --example generate-format -- print > tests/staged/sui.yaml -``` - - -Let's check that we pass the test again: -``` -huitseeker@Garillots-MBP.localdomain➜tmp/sui/sui_core(main✗)» cargo test format 2>&1 |tail -n 40 [8:47:22] - Finished test [unoptimized + debuginfo] target(s) in 0.35s - Running unittests (/Users/huitseeker/tmp/sui/target/debug/deps/sui_core-5796871991341984) - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 52 filtered out; finished in 0.00s - - Running tests/format.rs (/Users/huitseeker/tmp/sui/target/debug/deps/format-ecdfa91a67810be3) - -running 1 test - Finished dev [unoptimized + debuginfo] target(s) in 0.20s - Running `target/debug/examples/generate-format test` -test test_format ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.48s -huitseeker@Garillots-MBP.localdomain➜tmp/sui/sui_core(main✗)» git status -s [8:47:38] - M tests/staged/sui.yaml - M ../sui_types/src/error.rs - M ../sui_types/src/messages.rs - ``` \ No newline at end of file diff --git a/crates/sui-core/tests/staged/sui.yaml b/crates/sui-core/tests/staged/sui.yaml deleted file mode 100644 index 7a6153159bc..00000000000 --- a/crates/sui-core/tests/staged/sui.yaml +++ /dev/null @@ -1,1061 +0,0 @@ ---- -AccountAddress: - NEWTYPESTRUCT: - TUPLEARRAY: - CONTENT: U8 - SIZE: 32 -ActiveJwk: - STRUCT: - - jwk_id: - TYPENAME: JwkId - - jwk: - TYPENAME: JWK - - epoch: U64 -Argument: - ENUM: - 0: - GasCoin: UNIT - 1: - Input: - NEWTYPE: U16 - 2: - Result: - NEWTYPE: U16 - 3: - NestedResult: - TUPLE: - - U16 - - U16 -AuthenticatorStateExpire: - STRUCT: - - min_epoch: U64 - - authenticator_obj_initial_shared_version: - TYPENAME: SequenceNumber -AuthenticatorStateUpdate: - STRUCT: - - epoch: U64 - - round: U64 - - new_active_jwks: - SEQ: - TYPENAME: ActiveJwk - - authenticator_obj_initial_shared_version: - TYPENAME: SequenceNumber -AuthorityPublicKeyBytes: - NEWTYPESTRUCT: BYTES -CallArg: - ENUM: - 0: - Pure: - NEWTYPE: - SEQ: U8 - 1: - Object: - NEWTYPE: - TYPENAME: ObjectArg -ChangeEpoch: - STRUCT: - - epoch: U64 - - protocol_version: - TYPENAME: ProtocolVersion - - storage_charge: U64 - - computation_charge: U64 - - storage_rebate: U64 - - non_refundable_storage_fee: U64 - - epoch_start_timestamp_ms: U64 - - system_packages: - SEQ: - TUPLE: - - TYPENAME: SequenceNumber - - SEQ: - SEQ: U8 - - SEQ: - TYPENAME: ObjectID -CheckpointCommitment: - ENUM: - 0: - ECMHLiveObjectSetDigest: - NEWTYPE: - TYPENAME: ECMHLiveObjectSetDigest -CheckpointContents: - ENUM: - 0: - V1: - NEWTYPE: - TYPENAME: CheckpointContentsV1 -CheckpointContentsDigest: - NEWTYPESTRUCT: - TYPENAME: Digest -CheckpointContentsV1: - STRUCT: - - transactions: - SEQ: - TYPENAME: ExecutionDigests - - user_signatures: - SEQ: - SEQ: - TYPENAME: GenericSignature -CheckpointDigest: - NEWTYPESTRUCT: - TYPENAME: Digest -CheckpointSummary: - STRUCT: - - epoch: U64 - - sequence_number: U64 - - network_total_transactions: U64 - - content_digest: - TYPENAME: CheckpointContentsDigest - - previous_digest: - OPTION: - TYPENAME: CheckpointDigest - - epoch_rolling_gas_cost_summary: - TYPENAME: GasCostSummary - - timestamp_ms: U64 - - checkpoint_commitments: - SEQ: - TYPENAME: CheckpointCommitment - - end_of_epoch_data: - OPTION: - TYPENAME: EndOfEpochData - - version_specific_data: - SEQ: U8 -Command: - ENUM: - 0: - MoveCall: - NEWTYPE: - TYPENAME: ProgrammableMoveCall - 1: - TransferObjects: - TUPLE: - - SEQ: - TYPENAME: Argument - - TYPENAME: Argument - 2: - SplitCoins: - TUPLE: - - TYPENAME: Argument - - SEQ: - TYPENAME: Argument - 3: - MergeCoins: - TUPLE: - - TYPENAME: Argument - - SEQ: - TYPENAME: Argument - 4: - Publish: - TUPLE: - - SEQ: - SEQ: U8 - - SEQ: - TYPENAME: ObjectID - 5: - MakeMoveVec: - TUPLE: - - OPTION: - TYPENAME: TypeTag - - SEQ: - TYPENAME: Argument - 6: - Upgrade: - TUPLE: - - SEQ: - SEQ: U8 - - SEQ: - TYPENAME: ObjectID - - TYPENAME: ObjectID - - TYPENAME: Argument -CommandArgumentError: - ENUM: - 0: - TypeMismatch: UNIT - 1: - InvalidBCSBytes: UNIT - 2: - InvalidUsageOfPureArg: UNIT - 3: - InvalidArgumentToPrivateEntryFunction: UNIT - 4: - IndexOutOfBounds: - STRUCT: - - idx: U16 - 5: - SecondaryIndexOutOfBounds: - STRUCT: - - result_idx: U16 - - secondary_idx: U16 - 6: - InvalidResultArity: - STRUCT: - - result_idx: U16 - 7: - InvalidGasCoinUsage: UNIT - 8: - InvalidValueUsage: UNIT - 9: - InvalidObjectByValue: UNIT - 10: - InvalidObjectByMutRef: UNIT - 11: - SharedObjectOperationNotAllowed: UNIT -CompressedSignature: - ENUM: - 0: - Ed25519: - NEWTYPE: - TUPLEARRAY: - CONTENT: U8 - SIZE: 64 - 1: - Secp256k1: - NEWTYPE: - TUPLEARRAY: - CONTENT: U8 - SIZE: 64 - 2: - Secp256r1: - NEWTYPE: - TUPLEARRAY: - CONTENT: U8 - SIZE: 64 - 3: - ZkLogin: - NEWTYPE: - TYPENAME: ZkLoginAuthenticatorAsBytes -ConsensusCommitDigest: - NEWTYPESTRUCT: - TYPENAME: Digest -ConsensusCommitPrologue: - STRUCT: - - epoch: U64 - - round: U64 - - commit_timestamp_ms: U64 -ConsensusCommitPrologueV2: - STRUCT: - - epoch: U64 - - round: U64 - - commit_timestamp_ms: U64 - - consensus_commit_digest: - TYPENAME: ConsensusCommitDigest -Data: - ENUM: - 0: - Move: - NEWTYPE: - TYPENAME: MoveObject - 1: - Package: - NEWTYPE: - TYPENAME: MovePackage -DeleteKind: - ENUM: - 0: - Normal: UNIT - 1: - UnwrapThenDelete: UNIT - 2: - Wrap: UNIT -Digest: - NEWTYPESTRUCT: BYTES -ECMHLiveObjectSetDigest: - STRUCT: - - digest: - TYPENAME: Digest -EffectsAuxDataDigest: - NEWTYPESTRUCT: - TYPENAME: Digest -EffectsObjectChange: - STRUCT: - - input_state: - TYPENAME: ObjectIn - - output_state: - TYPENAME: ObjectOut - - id_operation: - TYPENAME: IDOperation -EmptySignInfo: - STRUCT: [] -EndOfEpochData: - STRUCT: - - nextEpochCommittee: - SEQ: - TUPLE: - - TYPENAME: AuthorityPublicKeyBytes - - U64 - - nextEpochProtocolVersion: - TYPENAME: ProtocolVersion - - epochCommitments: - SEQ: - TYPENAME: CheckpointCommitment -EndOfEpochTransactionKind: - ENUM: - 0: - ChangeEpoch: - NEWTYPE: - TYPENAME: ChangeEpoch - 1: - AuthenticatorStateCreate: UNIT - 2: - AuthenticatorStateExpire: - NEWTYPE: - TYPENAME: AuthenticatorStateExpire - 3: - RandomnessStateCreate: UNIT - 4: - DenyListStateCreate: UNIT -Envelope: - STRUCT: - - data: - TYPENAME: SenderSignedData - - auth_signature: - TYPENAME: EmptySignInfo -ExecutionData: - STRUCT: - - transaction: - TYPENAME: Envelope - - effects: - TYPENAME: TransactionEffects -ExecutionDigests: - STRUCT: - - transaction: - TYPENAME: TransactionDigest - - effects: - TYPENAME: TransactionEffectsDigest -ExecutionFailureStatus: - ENUM: - 0: - InsufficientGas: UNIT - 1: - InvalidGasObject: UNIT - 2: - InvariantViolation: UNIT - 3: - FeatureNotYetSupported: UNIT - 4: - MoveObjectTooBig: - STRUCT: - - object_size: U64 - - max_object_size: U64 - 5: - MovePackageTooBig: - STRUCT: - - object_size: U64 - - max_object_size: U64 - 6: - CircularObjectOwnership: - STRUCT: - - object: - TYPENAME: ObjectID - 7: - InsufficientCoinBalance: UNIT - 8: - CoinBalanceOverflow: UNIT - 9: - PublishErrorNonZeroAddress: UNIT - 10: - SuiMoveVerificationError: UNIT - 11: - MovePrimitiveRuntimeError: - NEWTYPE: - TYPENAME: MoveLocationOpt - 12: - MoveAbort: - TUPLE: - - TYPENAME: MoveLocation - - U64 - 13: - VMVerificationOrDeserializationError: UNIT - 14: - VMInvariantViolation: UNIT - 15: - FunctionNotFound: UNIT - 16: - ArityMismatch: UNIT - 17: - TypeArityMismatch: UNIT - 18: - NonEntryFunctionInvoked: UNIT - 19: - CommandArgumentError: - STRUCT: - - arg_idx: U16 - - kind: - TYPENAME: CommandArgumentError - 20: - TypeArgumentError: - STRUCT: - - argument_idx: U16 - - kind: - TYPENAME: TypeArgumentError - 21: - UnusedValueWithoutDrop: - STRUCT: - - result_idx: U16 - - secondary_idx: U16 - 22: - InvalidPublicFunctionReturnType: - STRUCT: - - idx: U16 - 23: - InvalidTransferObject: UNIT - 24: - EffectsTooLarge: - STRUCT: - - current_size: U64 - - max_size: U64 - 25: - PublishUpgradeMissingDependency: UNIT - 26: - PublishUpgradeDependencyDowngrade: UNIT - 27: - PackageUpgradeError: - STRUCT: - - upgrade_error: - TYPENAME: PackageUpgradeError - 28: - WrittenObjectsTooLarge: - STRUCT: - - current_size: U64 - - max_size: U64 - 29: - CertificateDenied: UNIT - 30: - SuiMoveVerificationTimedout: UNIT - 31: - SharedObjectOperationNotAllowed: UNIT - 32: - InputObjectDeleted: UNIT -ExecutionStatus: - ENUM: - 0: - Success: UNIT - 1: - Failure: - STRUCT: - - error: - TYPENAME: ExecutionFailureStatus - - command: - OPTION: U64 -FullCheckpointContents: - STRUCT: - - transactions: - SEQ: - TYPENAME: ExecutionData - - user_signatures: - SEQ: - SEQ: - TYPENAME: GenericSignature -GasCostSummary: - STRUCT: - - computationCost: U64 - - storageCost: U64 - - storageRebate: U64 - - nonRefundableStorageFee: U64 -GasData: - STRUCT: - - payment: - SEQ: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - owner: - TYPENAME: SuiAddress - - price: U64 - - budget: U64 -GenericSignature: - NEWTYPESTRUCT: - SEQ: U8 -GenesisObject: - ENUM: - 0: - RawObject: - STRUCT: - - data: - TYPENAME: Data - - owner: - TYPENAME: Owner -GenesisTransaction: - STRUCT: - - objects: - SEQ: - TYPENAME: GenesisObject -IDOperation: - ENUM: - 0: - None: UNIT - 1: - Created: UNIT - 2: - Deleted: UNIT -Identifier: - NEWTYPESTRUCT: STR -Intent: - STRUCT: - - scope: U8 - - version: U8 - - app_id: U8 -IntentMessage: - STRUCT: - - intent: - TYPENAME: Intent - - value: - TYPENAME: TransactionData -JWK: - STRUCT: - - kty: STR - - e: STR - - n: STR - - alg: STR -JwkId: - STRUCT: - - iss: STR - - kid: STR -ModuleId: - STRUCT: - - address: - TYPENAME: AccountAddress - - name: - TYPENAME: Identifier -MoveLocation: - STRUCT: - - module: - TYPENAME: ModuleId - - function: U16 - - instruction: U16 - - function_name: - OPTION: STR -MoveLocationOpt: - NEWTYPESTRUCT: - OPTION: - TYPENAME: MoveLocation -MoveObject: - STRUCT: - - type_: - TYPENAME: MoveObjectType - - has_public_transfer: BOOL - - version: - TYPENAME: SequenceNumber - - contents: BYTES -MoveObjectType: - NEWTYPESTRUCT: - TYPENAME: MoveObjectType_ -MoveObjectType_: - ENUM: - 0: - Other: - NEWTYPE: - TYPENAME: StructTag - 1: - GasCoin: UNIT - 2: - StakedSui: UNIT - 3: - Coin: - NEWTYPE: - TYPENAME: TypeTag -MovePackage: - STRUCT: - - id: - TYPENAME: ObjectID - - version: - TYPENAME: SequenceNumber - - module_map: - MAP: - KEY: STR - VALUE: BYTES - - type_origin_table: - SEQ: - TYPENAME: TypeOrigin - - linkage_table: - MAP: - KEY: - TYPENAME: ObjectID - VALUE: - TYPENAME: UpgradeInfo -MultiSig: - STRUCT: - - sigs: - SEQ: - TYPENAME: CompressedSignature - - bitmap: U16 - - multisig_pk: - TYPENAME: MultiSigPublicKey -MultiSigPublicKey: - STRUCT: - - pk_map: - SEQ: - TUPLE: - - TYPENAME: PublicKey - - U8 - - threshold: U16 -ObjectArg: - ENUM: - 0: - ImmOrOwnedObject: - NEWTYPE: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - 1: - SharedObject: - STRUCT: - - id: - TYPENAME: ObjectID - - initial_shared_version: - TYPENAME: SequenceNumber - - mutable: BOOL - 2: - Receiving: - NEWTYPE: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest -ObjectDigest: - NEWTYPESTRUCT: - TYPENAME: Digest -ObjectID: - NEWTYPESTRUCT: - TYPENAME: AccountAddress -ObjectIn: - ENUM: - 0: - NotExist: UNIT - 1: - Exist: - NEWTYPE: - TUPLE: - - TUPLE: - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - TYPENAME: Owner -ObjectInfoRequestKind: - ENUM: - 0: - LatestObjectInfo: UNIT - 1: - PastObjectInfoDebug: - NEWTYPE: - TYPENAME: SequenceNumber -ObjectOut: - ENUM: - 0: - NotExist: UNIT - 1: - ObjectWrite: - NEWTYPE: - TUPLE: - - TYPENAME: ObjectDigest - - TYPENAME: Owner - 2: - PackageWrite: - NEWTYPE: - TUPLE: - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest -Owner: - ENUM: - 0: - AddressOwner: - NEWTYPE: - TYPENAME: SuiAddress - 1: - ObjectOwner: - NEWTYPE: - TYPENAME: SuiAddress - 2: - Shared: - STRUCT: - - initial_shared_version: - TYPENAME: SequenceNumber - 3: - Immutable: UNIT -PackageUpgradeError: - ENUM: - 0: - UnableToFetchPackage: - STRUCT: - - package_id: - TYPENAME: ObjectID - 1: - NotAPackage: - STRUCT: - - object_id: - TYPENAME: ObjectID - 2: - IncompatibleUpgrade: UNIT - 3: - DigestDoesNotMatch: - STRUCT: - - digest: - SEQ: U8 - 4: - UnknownUpgradePolicy: - STRUCT: - - policy: U8 - 5: - PackageIDDoesNotMatch: - STRUCT: - - package_id: - TYPENAME: ObjectID - - ticket_id: - TYPENAME: ObjectID -ProgrammableMoveCall: - STRUCT: - - package: - TYPENAME: ObjectID - - module: - TYPENAME: Identifier - - function: - TYPENAME: Identifier - - type_arguments: - SEQ: - TYPENAME: TypeTag - - arguments: - SEQ: - TYPENAME: Argument -ProgrammableTransaction: - STRUCT: - - inputs: - SEQ: - TYPENAME: CallArg - - commands: - SEQ: - TYPENAME: Command -ProtocolVersion: - NEWTYPESTRUCT: U64 -PublicKey: - ENUM: - 0: - Ed25519: - NEWTYPE: - TUPLEARRAY: - CONTENT: U8 - SIZE: 32 - 1: - Secp256k1: - NEWTYPE: - TUPLEARRAY: - CONTENT: U8 - SIZE: 33 - 2: - Secp256r1: - NEWTYPE: - TUPLEARRAY: - CONTENT: U8 - SIZE: 33 - 3: - ZkLogin: - NEWTYPE: - TYPENAME: ZkLoginPublicIdentifier -RandomnessRound: - NEWTYPESTRUCT: U64 -RandomnessStateUpdate: - STRUCT: - - epoch: U64 - - randomness_round: - TYPENAME: RandomnessRound - - random_bytes: - SEQ: U8 - - randomness_obj_initial_shared_version: - TYPENAME: SequenceNumber -SenderSignedData: - NEWTYPESTRUCT: - SEQ: - TYPENAME: SenderSignedTransaction -SenderSignedTransaction: - STRUCT: - - intent_message: - TYPENAME: IntentMessage - - tx_signatures: - SEQ: - TYPENAME: GenericSignature -SequenceNumber: - NEWTYPESTRUCT: U64 -StructTag: - STRUCT: - - address: - TYPENAME: AccountAddress - - module: - TYPENAME: Identifier - - name: - TYPENAME: Identifier - - type_args: - SEQ: - TYPENAME: TypeTag -SuiAddress: - NEWTYPESTRUCT: - TUPLEARRAY: - CONTENT: U8 - SIZE: 32 -TransactionData: - ENUM: - 0: - V1: - NEWTYPE: - TYPENAME: TransactionDataV1 -TransactionDataV1: - STRUCT: - - kind: - TYPENAME: TransactionKind - - sender: - TYPENAME: SuiAddress - - gas_data: - TYPENAME: GasData - - expiration: - TYPENAME: TransactionExpiration -TransactionDigest: - NEWTYPESTRUCT: - TYPENAME: Digest -TransactionEffects: - ENUM: - 0: - V1: - NEWTYPE: - TYPENAME: TransactionEffectsV1 - 1: - V2: - NEWTYPE: - TYPENAME: TransactionEffectsV2 -TransactionEffectsDigest: - NEWTYPESTRUCT: - TYPENAME: Digest -TransactionEffectsV1: - STRUCT: - - status: - TYPENAME: ExecutionStatus - - executed_epoch: U64 - - gas_used: - TYPENAME: GasCostSummary - - modified_at_versions: - SEQ: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - shared_objects: - SEQ: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - transaction_digest: - TYPENAME: TransactionDigest - - created: - SEQ: - TUPLE: - - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - TYPENAME: Owner - - mutated: - SEQ: - TUPLE: - - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - TYPENAME: Owner - - unwrapped: - SEQ: - TUPLE: - - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - TYPENAME: Owner - - deleted: - SEQ: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - unwrapped_then_deleted: - SEQ: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - wrapped: - SEQ: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - gas_object: - TUPLE: - - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - - TYPENAME: Owner - - events_digest: - OPTION: - TYPENAME: TransactionEventsDigest - - dependencies: - SEQ: - TYPENAME: TransactionDigest -TransactionEffectsV2: - STRUCT: - - status: - TYPENAME: ExecutionStatus - - executed_epoch: U64 - - gas_used: - TYPENAME: GasCostSummary - - transaction_digest: - TYPENAME: TransactionDigest - - gas_object_index: - OPTION: U32 - - events_digest: - OPTION: - TYPENAME: TransactionEventsDigest - - dependencies: - SEQ: - TYPENAME: TransactionDigest - - lamport_version: - TYPENAME: SequenceNumber - - changed_objects: - SEQ: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: EffectsObjectChange - - unchanged_shared_objects: - SEQ: - TUPLE: - - TYPENAME: ObjectID - - TYPENAME: UnchangedSharedKind - - aux_data_digest: - OPTION: - TYPENAME: EffectsAuxDataDigest -TransactionEventsDigest: - NEWTYPESTRUCT: - TYPENAME: Digest -TransactionExpiration: - ENUM: - 0: - None: UNIT - 1: - Epoch: - NEWTYPE: U64 -TransactionKind: - ENUM: - 0: - ProgrammableTransaction: - NEWTYPE: - TYPENAME: ProgrammableTransaction - 1: - ChangeEpoch: - NEWTYPE: - TYPENAME: ChangeEpoch - 2: - Genesis: - NEWTYPE: - TYPENAME: GenesisTransaction - 3: - ConsensusCommitPrologue: - NEWTYPE: - TYPENAME: ConsensusCommitPrologue - 4: - AuthenticatorStateUpdate: - NEWTYPE: - TYPENAME: AuthenticatorStateUpdate - 5: - EndOfEpochTransaction: - NEWTYPE: - SEQ: - TYPENAME: EndOfEpochTransactionKind - 6: - RandomnessStateUpdate: - NEWTYPE: - TYPENAME: RandomnessStateUpdate - 7: - ConsensusCommitPrologueV2: - NEWTYPE: - TYPENAME: ConsensusCommitPrologueV2 -TypeArgumentError: - ENUM: - 0: - TypeNotFound: UNIT - 1: - ConstraintNotSatisfied: UNIT -TypeOrigin: - STRUCT: - - module_name: STR - - struct_name: STR - - package: - TYPENAME: ObjectID -TypeTag: - ENUM: - 0: - bool: UNIT - 1: - u8: UNIT - 2: - u64: UNIT - 3: - u128: UNIT - 4: - address: UNIT - 5: - signer: UNIT - 6: - vector: - NEWTYPE: - TYPENAME: TypeTag - 7: - struct: - NEWTYPE: - TYPENAME: StructTag - 8: - u16: UNIT - 9: - u32: UNIT - 10: - u256: UNIT -TypedStoreError: - ENUM: - 0: - RocksDBError: - NEWTYPE: STR - 1: - SerializationError: - NEWTYPE: STR - 2: - UnregisteredColumn: - NEWTYPE: STR - 3: - CrossDBBatch: UNIT - 4: - MetricsReporting: UNIT - 5: - RetryableTransactionError: UNIT -UnchangedSharedKind: - ENUM: - 0: - ReadOnlyRoot: - NEWTYPE: - TUPLE: - - TYPENAME: SequenceNumber - - TYPENAME: ObjectDigest - 1: - MutateDeleted: - NEWTYPE: - TYPENAME: SequenceNumber - 2: - ReadDeleted: - NEWTYPE: - TYPENAME: SequenceNumber -UpgradeInfo: - STRUCT: - - upgraded_id: - TYPENAME: ObjectID - - upgraded_version: - TYPENAME: SequenceNumber -ZkLoginAuthenticatorAsBytes: - NEWTYPESTRUCT: - SEQ: U8 -ZkLoginPublicIdentifier: - NEWTYPESTRUCT: - SEQ: U8 - diff --git a/crates/sui-cost/Cargo.toml b/crates/sui-cost/Cargo.toml deleted file mode 100644 index e41938790d3..00000000000 --- a/crates/sui-cost/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "sui-cost" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -sui-types.workspace = true -anyhow.workspace = true -tokio = { workspace = true, features = ["full"] } -serde.workspace = true -strum.workspace = true -strum_macros.workspace = true -bcs.workspace = true - -[dev-dependencies] -insta.workspace = true -test-cluster.workspace = true -sui-config.workspace = true -sui-swarm-config.workspace = true -sui-test-transaction-builder.workspace = true -sui-move-build.workspace = true -move-cli.workspace = true -move-disassembler.workspace = true -sui-json-rpc-types.workspace = true diff --git a/crates/sui-cost/tests/data/dummy_modules_publish/Move.toml b/crates/sui-cost/tests/data/dummy_modules_publish/Move.toml deleted file mode 100644 index 1a80243f9c9..00000000000 --- a/crates/sui-cost/tests/data/dummy_modules_publish/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "Examples" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../sui-framework/packages/sui-framework" } - -[addresses] -examples = "0x0" diff --git a/crates/sui-cost/tests/data/dummy_modules_publish/sources/trusted_coin.move b/crates/sui-cost/tests/data/dummy_modules_publish/sources/trusted_coin.move deleted file mode 100644 index 01833ab7367..00000000000 --- a/crates/sui-cost/tests/data/dummy_modules_publish/sources/trusted_coin.move +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Example coin with a trusted owner responsible for minting/burning (e.g., a stablecoin) -module examples::trusted_coin { - use std::option; - use sui::coin::{Self, TreasuryCap}; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; - - /// Name of the coin - struct TRUSTED_COIN has drop {} - - /// Register the trusted currency to acquire its `TreasuryCap`. Because - /// this is a module initializer, it ensures the currency only gets - /// registered once. - fun init(witness: TRUSTED_COIN, ctx: &mut TxContext) { - // Get a treasury cap for the coin and give it to the transaction - // sender - let (treasury_cap, metadata) = coin::create_currency(witness, 2, b"TRUSTED", b"", b"", option::none(), ctx); - transfer::public_freeze_object(metadata); - transfer::public_transfer(treasury_cap, tx_context::sender(ctx)) - } - - public entry fun mint(treasury_cap: &mut TreasuryCap, amount: u64, ctx: &mut TxContext) { - let coin = coin::mint(treasury_cap, amount, ctx); - transfer::public_transfer(coin, tx_context::sender(ctx)); - } -} diff --git a/crates/sui-cost/troubleshooting.md b/crates/sui-cost/troubleshooting.md deleted file mode 100644 index 9066550f8f7..00000000000 --- a/crates/sui-cost/troubleshooting.md +++ /dev/null @@ -1,13 +0,0 @@ -# Troubleshooting - -## Sui Framework change - -If Sui framework code got updated, the expectations need to be changed. Follow these steps: - -```bash -# required; can be omitted if cargo-insta is installed -$ cargo install cargo-insta - -# run in ./sui-cost -$ cargo insta test --review -``` diff --git a/crates/sui-data-ingestion-core/Cargo.toml b/crates/sui-data-ingestion-core/Cargo.toml deleted file mode 100644 index 18a1d7d66aa..00000000000 --- a/crates/sui-data-ingestion-core/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "sui-data-ingestion-core" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" -version = "0.1.0" - -[dependencies] -anyhow.workspace = true -async-trait.workspace = true -backoff.workspace = true -futures.workspace = true -mysten-metrics.workspace = true -notify.workspace = true -serde.workspace = true -serde_json.workspace = true -object_store.workspace = true -prometheus.workspace = true -telemetry-subscribers.workspace = true -tokio = { workspace = true, features = ["full"] } -tracing.workspace = true -sui-storage.workspace = true -sui-types.workspace = true -url.workspace = true -tempfile.workspace = true -tap.workspace = true - -[dev-dependencies] -rand.workspace = true -sui-types = { workspace = true, features = ["test-utils"] } diff --git a/crates/sui-data-ingestion-core/src/executor.rs b/crates/sui-data-ingestion-core/src/executor.rs deleted file mode 100644 index c75a27b44ed..00000000000 --- a/crates/sui-data-ingestion-core/src/executor.rs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{path::PathBuf, pin::Pin}; - -use anyhow::Result; -use futures::Future; -use mysten_metrics::spawn_monitored_task; -use prometheus::Registry; -use sui_types::{ - full_checkpoint_content::CheckpointData, messages_checkpoint::CheckpointSequenceNumber, -}; -use tokio::sync::{mpsc, oneshot}; - -use crate::{ - progress_store::{ExecutorProgress, ProgressStore, ProgressStoreWrapper, ShimProgressStore}, - reader::CheckpointReader, - worker_pool::WorkerPool, - DataIngestionMetrics, ReaderOptions, Worker, -}; - -pub const MAX_CHECKPOINTS_IN_PROGRESS: usize = 10000; - -pub struct IndexerExecutor

    { - pools: Vec + Send>>>, - pool_senders: Vec>, - progress_store: ProgressStoreWrapper

    , - pool_progress_sender: mpsc::Sender<(String, CheckpointSequenceNumber)>, - pool_progress_receiver: mpsc::Receiver<(String, CheckpointSequenceNumber)>, - metrics: DataIngestionMetrics, -} - -impl IndexerExecutor

    { - pub fn new(progress_store: P, number_of_jobs: usize, metrics: DataIngestionMetrics) -> Self { - let (pool_progress_sender, pool_progress_receiver) = - mpsc::channel(number_of_jobs * MAX_CHECKPOINTS_IN_PROGRESS); - Self { - pools: vec![], - pool_senders: vec![], - progress_store: ProgressStoreWrapper::new(progress_store), - pool_progress_sender, - pool_progress_receiver, - metrics, - } - } - - /// Registers new worker pool in executor - pub async fn register(&mut self, pool: WorkerPool) -> Result<()> { - let checkpoint_number = self.progress_store.load(pool.task_name.clone()).await?; - let (sender, receiver) = mpsc::channel(MAX_CHECKPOINTS_IN_PROGRESS); - self.pools.push(Box::pin(pool.run( - checkpoint_number, - receiver, - self.pool_progress_sender.clone(), - ))); - self.pool_senders.push(sender); - Ok(()) - } - - /// Main executor loop - pub async fn run( - mut self, - path: PathBuf, - remote_store_url: Option, - remote_store_options: Vec<(String, String)>, - reader_options: ReaderOptions, - mut exit_receiver: oneshot::Receiver<()>, - ) -> Result { - let mut reader_checkpoint_number = self.progress_store.min_watermark()?; - let (checkpoint_reader, mut checkpoint_recv, gc_sender, _exit_sender) = - CheckpointReader::initialize( - path, - reader_checkpoint_number, - remote_store_url, - remote_store_options, - reader_options, - ); - spawn_monitored_task!(checkpoint_reader.run()); - - for pool in std::mem::take(&mut self.pools) { - spawn_monitored_task!(pool); - } - loop { - tokio::select! { - _ = &mut exit_receiver => break, - Some((task_name, sequence_number)) = self.pool_progress_receiver.recv() => { - self.progress_store.save(task_name.clone(), sequence_number).await?; - let seq_number = self.progress_store.min_watermark()?; - if seq_number > reader_checkpoint_number { - gc_sender.send(seq_number).await?; - reader_checkpoint_number = seq_number; - } - self.metrics.data_ingestion_checkpoint.with_label_values(&[&task_name]).set(sequence_number as i64); - } - Some(checkpoint) = checkpoint_recv.recv() => { - for sender in &self.pool_senders { - sender.send(checkpoint.clone()).await?; - } - } - } - } - Ok(self.progress_store.stats()) - } -} - -pub async fn setup_single_workflow( - worker: W, - remote_store_url: String, - initial_checkpoint_number: CheckpointSequenceNumber, - concurrency: usize, - reader_options: Option, -) -> Result<( - impl Future>, - oneshot::Sender<()>, -)> { - let (exit_sender, exit_receiver) = oneshot::channel(); - let metrics = DataIngestionMetrics::new(&Registry::new()); - let progress_store = ShimProgressStore(initial_checkpoint_number); - let mut executor = IndexerExecutor::new(progress_store, 1, metrics); - let worker_pool = WorkerPool::new(worker, "workflow".to_string(), concurrency); - executor.register(worker_pool).await?; - Ok(( - executor.run( - tempfile::tempdir()?.into_path(), - Some(remote_store_url), - vec![], - reader_options.unwrap_or_default(), - exit_receiver, - ), - exit_sender, - )) -} diff --git a/crates/sui-data-ingestion-core/src/lib.rs b/crates/sui-data-ingestion-core/src/lib.rs deleted file mode 100644 index 0cf5ec288cd..00000000000 --- a/crates/sui-data-ingestion-core/src/lib.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod executor; -mod metrics; -mod progress_store; -mod reader; -#[cfg(test)] -mod tests; -mod util; -mod worker_pool; - -use anyhow::Result; -use async_trait::async_trait; -pub use executor::{setup_single_workflow, IndexerExecutor, MAX_CHECKPOINTS_IN_PROGRESS}; -pub use metrics::DataIngestionMetrics; -pub use progress_store::{FileProgressStore, ProgressStore}; -pub use reader::ReaderOptions; -use sui_types::{ - full_checkpoint_content::CheckpointData, messages_checkpoint::CheckpointSequenceNumber, -}; -pub use util::create_remote_store_client; -pub use worker_pool::WorkerPool; - -#[async_trait] -pub trait Worker: Send + Sync { - async fn process_checkpoint(&self, checkpoint: CheckpointData) -> Result<()>; - /// Optional method. Allows controlling when workflow progress is updated in - /// the progress store. For instance, some pipelines may benefit from - /// aggregating checkpoints, thus skipping the saving of updates for - /// intermediate checkpoints. The default implementation is to update - /// the progress store for every processed checkpoint. - async fn save_progress( - &self, - sequence_number: CheckpointSequenceNumber, - ) -> Option { - Some(sequence_number) - } -} diff --git a/crates/sui-data-ingestion-core/src/metrics.rs b/crates/sui-data-ingestion-core/src/metrics.rs deleted file mode 100644 index 2433efc44b2..00000000000 --- a/crates/sui-data-ingestion-core/src/metrics.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use prometheus::{register_int_gauge_vec_with_registry, IntGaugeVec, Registry}; - -#[derive(Clone)] -pub struct DataIngestionMetrics { - pub data_ingestion_checkpoint: IntGaugeVec, -} - -impl DataIngestionMetrics { - pub fn new(registry: &Registry) -> Self { - Self { - data_ingestion_checkpoint: register_int_gauge_vec_with_registry!( - "data_ingestion_checkpoint", - "Number of uploaded checkpoints.", - &["task"], - registry, - ) - .unwrap(), - } - } -} diff --git a/crates/sui-data-ingestion-core/src/progress_store/mod.rs b/crates/sui-data-ingestion-core/src/progress_store/mod.rs deleted file mode 100644 index 0f3a9e86b52..00000000000 --- a/crates/sui-data-ingestion-core/src/progress_store/mod.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::HashMap; - -use anyhow::Result; -use async_trait::async_trait; -use sui_types::messages_checkpoint::CheckpointSequenceNumber; -mod file; -pub use file::FileProgressStore; - -pub type ExecutorProgress = HashMap; - -#[async_trait] -pub trait ProgressStore: Send { - async fn load(&mut self, task_name: String) -> Result; - async fn save( - &mut self, - task_name: String, - checkpoint_number: CheckpointSequenceNumber, - ) -> Result<()>; -} - -pub struct ProgressStoreWrapper

    { - progress_store: P, - pending_state: ExecutorProgress, -} - -#[async_trait] -impl ProgressStore for ProgressStoreWrapper

    { - async fn load(&mut self, task_name: String) -> Result { - let watermark = self.progress_store.load(task_name.clone()).await?; - self.pending_state.insert(task_name, watermark); - Ok(watermark) - } - - async fn save( - &mut self, - task_name: String, - checkpoint_number: CheckpointSequenceNumber, - ) -> Result<()> { - self.progress_store - .save(task_name.clone(), checkpoint_number) - .await?; - self.pending_state.insert(task_name, checkpoint_number); - Ok(()) - } -} - -impl ProgressStoreWrapper

    { - pub fn new(progress_store: P) -> Self { - Self { - progress_store, - pending_state: HashMap::new(), - } - } - - pub fn min_watermark(&self) -> Result { - self.pending_state - .values() - .min() - .cloned() - .ok_or_else(|| anyhow::anyhow!("pools can't be empty")) - } - - pub fn stats(&self) -> ExecutorProgress { - self.pending_state.clone() - } -} - -pub struct ShimProgressStore(pub u64); - -#[async_trait] -impl ProgressStore for ShimProgressStore { - async fn load(&mut self, _: String) -> Result { - Ok(self.0) - } - async fn save(&mut self, _: String, _: CheckpointSequenceNumber) -> Result<()> { - Ok(()) - } -} diff --git a/crates/sui-data-ingestion-core/src/reader.rs b/crates/sui-data-ingestion-core/src/reader.rs deleted file mode 100644 index bcdde67fb1e..00000000000 --- a/crates/sui-data-ingestion-core/src/reader.rs +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ffi::OsString, fs, path::PathBuf, time::Duration}; - -use anyhow::Result; -use backoff::backoff::Backoff; -use futures::StreamExt; -use mysten_metrics::spawn_monitored_task; -use notify::{RecursiveMode, Watcher}; -use object_store::{path::Path, ObjectStore}; -use sui_storage::blob::Blob; -use sui_types::{ - full_checkpoint_content::CheckpointData, messages_checkpoint::CheckpointSequenceNumber, -}; -use tap::pipe::Pipe; -use tokio::{ - sync::{mpsc, mpsc::error::TryRecvError, oneshot}, - time::timeout, -}; -use tracing::{debug, error, info}; - -use crate::{create_remote_store_client, executor::MAX_CHECKPOINTS_IN_PROGRESS}; - -/// Implements a checkpoint reader that monitors a local directory. -/// Designed for setups where the indexer daemon is colocated with FN. -/// This implementation is push-based and utilizes the inotify API. -pub struct CheckpointReader { - path: PathBuf, - remote_store_url: Option, - remote_store_options: Vec<(String, String)>, - current_checkpoint_number: CheckpointSequenceNumber, - last_pruned_watermark: CheckpointSequenceNumber, - checkpoint_sender: mpsc::Sender, - processed_receiver: mpsc::Receiver, - remote_fetcher_receiver: Option>>, - exit_receiver: oneshot::Receiver<()>, - options: ReaderOptions, -} - -#[derive(Clone)] -pub struct ReaderOptions { - pub tick_interal_ms: u64, - pub timeout_secs: u64, - pub batch_size: usize, -} - -impl Default for ReaderOptions { - fn default() -> Self { - Self { - tick_interal_ms: 100, - timeout_secs: 5, - batch_size: 100, - } - } -} - -impl CheckpointReader { - /// Represents a single iteration of the reader. - /// Reads files in a local directory, validates them, and forwards - /// `CheckpointData` to the executor. - async fn read_local_files(&self) -> Result> { - let mut files = vec![]; - for entry in fs::read_dir(self.path.clone())? { - let entry = entry?; - let filename = entry.file_name(); - if let Some(sequence_number) = Self::checkpoint_number_from_file_path(&filename) { - if sequence_number >= self.current_checkpoint_number { - files.push((sequence_number, entry.path())); - } - } - } - files.sort(); - debug!("unprocessed local files {:?}", files); - let mut checkpoints = vec![]; - for (_, filename) in files.iter().take(MAX_CHECKPOINTS_IN_PROGRESS) { - let checkpoint = Blob::from_bytes::(&fs::read(filename)?)?; - checkpoints.push(checkpoint); - } - Ok(checkpoints) - } - - fn exceeds_capacity(&self, checkpoint_number: CheckpointSequenceNumber) -> bool { - (MAX_CHECKPOINTS_IN_PROGRESS as u64 + self.last_pruned_watermark) <= checkpoint_number - } - - async fn remote_fetch_checkpoint_internal( - store: &dyn ObjectStore, - checkpoint_number: CheckpointSequenceNumber, - ) -> Result { - let path = Path::from(format!("{}.chk", checkpoint_number)); - let response = store.get(&path).await?; - let bytes = response.bytes().await?; - Blob::from_bytes::(&bytes) - } - - async fn remote_fetch_checkpoint( - store: &dyn ObjectStore, - checkpoint_number: CheckpointSequenceNumber, - ) -> Result { - let mut backoff = backoff::ExponentialBackoff::default(); - backoff.max_elapsed_time = Some(Duration::from_secs(60)); - backoff.initial_interval = Duration::from_millis(100); - backoff.current_interval = backoff.initial_interval; - backoff.multiplier = 1.0; - loop { - match Self::remote_fetch_checkpoint_internal(store, checkpoint_number).await { - Ok(data) => return Ok(data), - Err(err) if err.to_string().contains("404") => match backoff.next_backoff() { - Some(duration) => tokio::time::sleep(duration).await, - None => return Err(err), - }, - Err(err) => return Err(err), - } - } - } - - fn start_remote_fetcher(&mut self) -> mpsc::Receiver> { - let batch_size = self.options.batch_size; - let start_checkpoint = self.current_checkpoint_number; - let (sender, receiver) = mpsc::channel(batch_size); - let url = self - .remote_store_url - .clone() - .expect("remote store url must be set"); - let store = create_remote_store_client( - url, - self.remote_store_options.clone(), - self.options.timeout_secs, - ) - .expect("failed to create remote store client"); - - spawn_monitored_task!(async move { - let mut checkpoint_stream = (start_checkpoint..u64::MAX) - .map(|checkpoint_number| Self::remote_fetch_checkpoint(&store, checkpoint_number)) - .pipe(futures::stream::iter) - .buffered(batch_size); - - while let Some(checkpoint) = checkpoint_stream.next().await { - if sender.send(checkpoint).await.is_err() { - info!("remote reader dropped"); - break; - } - } - }); - receiver - } - - fn remote_fetch(&mut self) -> Vec { - let mut checkpoints = vec![]; - if self.remote_fetcher_receiver.is_none() { - self.remote_fetcher_receiver = Some(self.start_remote_fetcher()); - } - while !self.exceeds_capacity(self.current_checkpoint_number + checkpoints.len() as u64) { - match self.remote_fetcher_receiver.as_mut().unwrap().try_recv() { - Ok(Ok(checkpoint)) => checkpoints.push(checkpoint), - Ok(Err(err)) => { - error!("remote reader transient error {:?}", err); - self.remote_fetcher_receiver = None; - break; - } - Err(TryRecvError::Disconnected) => { - error!("remote reader channel disconnect error"); - self.remote_fetcher_receiver = None; - break; - } - Err(TryRecvError::Empty) => break, - } - } - checkpoints - } - - async fn sync(&mut self) -> Result<()> { - let backoff = backoff::ExponentialBackoff::default(); - let mut checkpoints = backoff::future::retry(backoff, || async { - self.read_local_files() - .await - .map_err(backoff::Error::transient) - }) - .await?; - - if self.remote_store_url.is_some() - && (checkpoints.is_empty() - || checkpoints[0].checkpoint_summary.sequence_number - > self.current_checkpoint_number) - { - checkpoints = self.remote_fetch(); - } else { - // cancel remote fetcher execution because local reader has made progress - self.remote_fetcher_receiver = None; - } - - info!( - "Local reader. Current checkpoint number: {}, pruning watermark: {}, unprocessed checkpoints: {:?}", - self.current_checkpoint_number, - self.last_pruned_watermark, - checkpoints.len(), - ); - for checkpoint in checkpoints { - assert_eq!( - checkpoint.checkpoint_summary.sequence_number, - self.current_checkpoint_number - ); - if self.exceeds_capacity(checkpoint.checkpoint_summary.sequence_number) { - break; - } - self.checkpoint_sender.send(checkpoint).await?; - self.current_checkpoint_number += 1; - } - Ok(()) - } - - /// Cleans the local directory by removing all processed checkpoint files. - fn gc_processed_files(&mut self, watermark: CheckpointSequenceNumber) -> Result<()> { - info!("cleaning processed files, watermark is {}", watermark); - self.last_pruned_watermark = watermark; - for entry in fs::read_dir(self.path.clone())? { - let entry = entry?; - let filename = entry.file_name(); - if let Some(sequence_number) = Self::checkpoint_number_from_file_path(&filename) { - if sequence_number < watermark { - fs::remove_file(entry.path())?; - } - } - } - Ok(()) - } - - fn checkpoint_number_from_file_path(file_name: &OsString) -> Option { - file_name - .to_str() - .and_then(|s| s.rfind('.').map(|pos| &s[..pos])) - .and_then(|s| s.parse().ok()) - } - - pub fn initialize( - path: PathBuf, - starting_checkpoint_number: CheckpointSequenceNumber, - remote_store_url: Option, - remote_store_options: Vec<(String, String)>, - options: ReaderOptions, - ) -> ( - Self, - mpsc::Receiver, - mpsc::Sender, - oneshot::Sender<()>, - ) { - let (checkpoint_sender, checkpoint_recv) = mpsc::channel(MAX_CHECKPOINTS_IN_PROGRESS); - let (processed_sender, processed_receiver) = mpsc::channel(MAX_CHECKPOINTS_IN_PROGRESS); - let (exit_sender, exit_receiver) = oneshot::channel(); - let reader = Self { - path, - remote_store_url, - remote_store_options, - current_checkpoint_number: starting_checkpoint_number, - last_pruned_watermark: starting_checkpoint_number, - checkpoint_sender, - processed_receiver, - remote_fetcher_receiver: None, - options, - exit_receiver, - }; - (reader, checkpoint_recv, processed_sender, exit_sender) - } - - pub async fn run(mut self) -> Result<()> { - let (inotify_sender, mut inotify_recv) = mpsc::channel(1); - std::fs::create_dir_all(self.path.clone()).expect("failed to create a directory"); - let mut watcher = notify::recommended_watcher(move |res| { - if let Err(err) = res { - eprintln!("watch error: {:?}", err); - } - inotify_sender - .blocking_send(()) - .expect("Failed to send inotify update"); - }) - .expect("Failed to init inotify"); - - watcher - .watch(&self.path, RecursiveMode::NonRecursive) - .expect("Inotify watcher failed"); - - loop { - tokio::select! { - _ = &mut self.exit_receiver => break, - Some(gc_checkpoint_number) = self.processed_receiver.recv() => { - self.gc_processed_files(gc_checkpoint_number).expect("Failed to clean the directory"); - } - Ok(Some(_)) | Err(_) = timeout(Duration::from_millis(self.options.tick_interal_ms), inotify_recv.recv()) => { - self.sync().await.expect("Failed to read checkpoint files"); - } - } - } - Ok(()) - } -} diff --git a/crates/sui-data-ingestion-core/src/tests.rs b/crates/sui-data-ingestion-core/src/tests.rs deleted file mode 100644 index 1037a430c36..00000000000 --- a/crates/sui-data-ingestion-core/src/tests.rs +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{path::PathBuf, time::Duration}; - -use anyhow::Result; -use async_trait::async_trait; -use prometheus::Registry; -use rand::{prelude::StdRng, SeedableRng}; -use sui_storage::blob::{Blob, BlobEncoding}; -use sui_types::{ - crypto::KeypairTraits, - full_checkpoint_content::CheckpointData, - gas::GasCostSummary, - messages_checkpoint::{ - CertifiedCheckpointSummary, CheckpointContents, CheckpointSequenceNumber, - CheckpointSummary, SignedCheckpointSummary, - }, - utils::make_committee_key, -}; -use tempfile::NamedTempFile; -use tokio::sync::oneshot; - -use crate::{ - progress_store::ExecutorProgress, DataIngestionMetrics, FileProgressStore, IndexerExecutor, - ReaderOptions, Worker, WorkerPool, -}; - -async fn add_worker_pool( - indexer: &mut IndexerExecutor, - worker: W, - concurrency: usize, -) -> Result<()> { - let worker_pool = WorkerPool::new(worker, "test".to_string(), concurrency); - indexer.register(worker_pool).await?; - Ok(()) -} - -async fn run( - indexer: IndexerExecutor, - path: Option, - duration: Option, -) -> Result { - let options = ReaderOptions { - tick_interal_ms: 10, - batch_size: 1, - ..Default::default() - }; - let (sender, recv) = oneshot::channel(); - match duration { - None => { - indexer - .run(path.unwrap_or_else(temp_dir), None, vec![], options, recv) - .await - } - Some(duration) => { - let handle = tokio::task::spawn(async move { - indexer - .run(path.unwrap_or_else(temp_dir), None, vec![], options, recv) - .await - }); - tokio::time::sleep(duration).await; - drop(sender); - handle.await? - } - } -} - -struct ExecutorBundle { - executor: IndexerExecutor, - _progress_file: NamedTempFile, -} - -#[derive(Clone)] -struct TestWorker; - -#[async_trait] -impl Worker for TestWorker { - async fn process_checkpoint(&self, _checkpoint: CheckpointData) -> Result<()> { - Ok(()) - } -} - -#[tokio::test] -async fn empty_pools() { - let bundle = create_executor_bundle(); - let result = run(bundle.executor, None, None).await; - assert!(result.is_err()); - if let Err(err) = result { - assert!(err.to_string().contains("pools can't be empty")); - } -} - -#[tokio::test] -async fn basic_flow() { - let mut bundle = create_executor_bundle(); - add_worker_pool(&mut bundle.executor, TestWorker, 5) - .await - .unwrap(); - let path = temp_dir(); - for checkpoint_number in 0..20 { - let bytes = mock_checkpoint_data_bytes(checkpoint_number); - std::fs::write(path.join(format!("{}.chk", checkpoint_number)), bytes).unwrap(); - } - let result = run(bundle.executor, Some(path), Some(Duration::from_secs(1))).await; - assert!(result.is_ok()); - assert_eq!(result.unwrap().get("test"), Some(&20)); -} - -fn temp_dir() -> std::path::PathBuf { - tempfile::tempdir() - .expect("Failed to open temporary directory") - .into_path() -} - -fn create_executor_bundle() -> ExecutorBundle { - let progress_file = NamedTempFile::new().unwrap(); - let path = progress_file.path().to_path_buf(); - std::fs::write(path.clone(), "{}").unwrap(); - let progress_store = FileProgressStore::new(path); - let executor = IndexerExecutor::new( - progress_store, - 1, - DataIngestionMetrics::new(&Registry::new()), - ); - ExecutorBundle { - executor, - _progress_file: progress_file, - } -} - -const RNG_SEED: [u8; 32] = [ - 21, 23, 199, 200, 234, 250, 252, 178, 94, 15, 202, 178, 62, 186, 88, 137, 233, 192, 130, 157, - 179, 179, 65, 9, 31, 249, 221, 123, 225, 112, 199, 247, -]; - -fn mock_checkpoint_data_bytes(seq_number: CheckpointSequenceNumber) -> Vec { - let mut rng = StdRng::from_seed(RNG_SEED); - let (keys, committee) = make_committee_key(&mut rng); - let contents = CheckpointContents::new_with_digests_only_for_tests(vec![]); - let summary = CheckpointSummary::new( - 0, - seq_number, - 0, - &contents, - None, - GasCostSummary::default(), - None, - 0, - ); - - let sign_infos: Vec<_> = keys - .iter() - .map(|k| { - let name = k.public().into(); - SignedCheckpointSummary::sign(committee.epoch, &summary, k, name) - }) - .collect(); - - let checkpoint_data = CheckpointData { - checkpoint_summary: CertifiedCheckpointSummary::new(summary, sign_infos, &committee) - .unwrap(), - checkpoint_contents: contents, - transactions: vec![], - }; - Blob::encode(&checkpoint_data, BlobEncoding::Bcs) - .unwrap() - .to_bytes() -} diff --git a/crates/sui-data-ingestion-core/src/util.rs b/crates/sui-data-ingestion-core/src/util.rs deleted file mode 100644 index a37a7c4450f..00000000000 --- a/crates/sui-data-ingestion-core/src/util.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{str::FromStr, time::Duration}; - -use anyhow::Result; -use object_store::{ - aws::AmazonS3ConfigKey, gcp::GoogleConfigKey, ClientOptions, ObjectStore, RetryConfig, -}; -use url::Url; - -pub fn create_remote_store_client( - url: String, - remote_store_options: Vec<(String, String)>, - timeout_secs: u64, -) -> Result> { - let retry_config = RetryConfig { - max_retries: 0, - retry_timeout: Duration::from_secs(timeout_secs + 1), - ..Default::default() - }; - let client_options = ClientOptions::new().with_timeout(Duration::from_secs(timeout_secs)); - if remote_store_options.is_empty() { - let http_store = object_store::http::HttpBuilder::new() - .with_url(url) - .with_client_options(client_options) - .with_retry(retry_config) - .build()?; - Ok(Box::new(http_store)) - } else if Url::parse(&url)?.scheme() == "gs" { - let url = Url::parse(&url)?; - let mut builder = object_store::gcp::GoogleCloudStorageBuilder::new() - .with_url(url.as_str()) - .with_retry(retry_config) - .with_client_options(client_options); - for (key, value) in remote_store_options { - builder = builder.with_config(GoogleConfigKey::from_str(&key)?, value); - } - Ok(Box::new(builder.build()?)) - } else { - let url = Url::parse(&url)?; - let mut builder = object_store::aws::AmazonS3Builder::new() - .with_url(url.as_str()) - .with_retry(retry_config) - .with_client_options(client_options); - for (key, value) in remote_store_options { - builder = builder.with_config(AmazonS3ConfigKey::from_str(&key)?, value); - } - Ok(Box::new(builder.build()?)) - } -} diff --git a/crates/sui-data-ingestion/Cargo.toml b/crates/sui-data-ingestion/Cargo.toml deleted file mode 100644 index 94bf693b0df..00000000000 --- a/crates/sui-data-ingestion/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -[package] -name = "sui-data-ingestion" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" -version = "0.1.0" - -[dependencies] -anyhow.workspace = true -async-trait.workspace = true -aws-config.workspace = true -aws-sdk-dynamodb.workspace = true -aws-sdk-s3.workspace = true -backoff.workspace = true -base64-url.workspace = true -bcs.workspace = true -byteorder.workspace = true -bytes.workspace = true -futures.workspace = true -mysten-metrics.workspace = true -notify.workspace = true -object_store.workspace = true -serde.workspace = true -serde_json.workspace = true -serde_yaml.workspace = true -prometheus.workspace = true -telemetry-subscribers.workspace = true -tokio = { workspace = true, features = ["full"] } -tracing.workspace = true -sui-archival.workspace = true -sui-storage.workspace = true -sui-data-ingestion-core.workspace = true -sui-types.workspace = true -url.workspace = true - -[dev-dependencies] -rand.workspace = true -tempfile.workspace = true -sui-types = { workspace = true, features = ["test-utils"] } diff --git a/crates/sui-data-ingestion/src/lib.rs b/crates/sui-data-ingestion/src/lib.rs deleted file mode 100644 index f5a53324ac8..00000000000 --- a/crates/sui-data-ingestion/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod progress_store; -mod workers; - -pub use progress_store::DynamoDBProgressStore; -pub use workers::{ - ArchivalConfig, ArchivalWorker, BlobTaskConfig, BlobWorker, KVStoreTaskConfig, KVStoreWorker, -}; diff --git a/crates/sui-data-ingestion/src/main.rs b/crates/sui-data-ingestion/src/main.rs deleted file mode 100644 index c909708a23b..00000000000 --- a/crates/sui-data-ingestion/src/main.rs +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{env, path::PathBuf}; - -use anyhow::Result; -use prometheus::Registry; -use serde::{Deserialize, Serialize}; -use sui_data_ingestion::{ - ArchivalConfig, ArchivalWorker, BlobTaskConfig, BlobWorker, DynamoDBProgressStore, - KVStoreTaskConfig, KVStoreWorker, -}; -use sui_data_ingestion_core::{DataIngestionMetrics, IndexerExecutor, ReaderOptions, WorkerPool}; -use tokio::{signal, sync::oneshot}; - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "lowercase")] -enum Task { - Archival(ArchivalConfig), - Blob(BlobTaskConfig), - KV(KVStoreTaskConfig), -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -struct TaskConfig { - #[serde(flatten)] - task: Task, - name: String, - concurrency: usize, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "lowercase")] -struct ProgressStoreConfig { - pub aws_access_key_id: String, - pub aws_secret_access_key: String, - pub aws_region: String, - pub table_name: String, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -struct IndexerConfig { - path: PathBuf, - tasks: Vec, - progress_store: ProgressStoreConfig, - #[serde(skip_serializing_if = "Option::is_none")] - remote_store_url: Option, - #[serde(skip_serializing_if = "Vec::is_empty", default)] - remote_store_options: Vec<(String, String)>, - #[serde(default = "default_remote_read_batch_size")] - remote_read_batch_size: usize, - #[serde(default = "default_metrics_host")] - metrics_host: String, - #[serde(default = "default_metrics_port")] - metrics_port: u16, -} - -fn default_metrics_host() -> String { - "127.0.0.1".to_string() -} - -fn default_metrics_port() -> u16 { - 8081 -} - -fn default_remote_read_batch_size() -> usize { - 100 -} - -fn setup_env(exit_sender: oneshot::Sender<()>) { - let default_hook = std::panic::take_hook(); - - std::panic::set_hook(Box::new(move |panic| { - default_hook(panic); - std::process::exit(12); - })); - - tokio::spawn(async { - signal::ctrl_c() - .await - .expect("Failed to install Ctrl+C handler"); - exit_sender - .send(()) - .expect("Failed to gracefully process shutdown"); - }); -} - -#[tokio::main] -async fn main() -> Result<()> { - let (exit_sender, exit_receiver) = oneshot::channel(); - setup_env(exit_sender); - - let args: Vec = env::args().collect(); - assert_eq!(args.len(), 2, "configuration yaml file is required"); - let config: IndexerConfig = serde_yaml::from_str(&std::fs::read_to_string(&args[1])?)?; - - // setup metrics - let _guard = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .init(); - let registry_service = mysten_metrics::start_prometheus_server( - format!("{}:{}", config.metrics_host, config.metrics_port).parse()?, - ); - let registry: Registry = registry_service.default_registry(); - mysten_metrics::init_metrics(®istry); - let metrics = DataIngestionMetrics::new(®istry); - - let progress_store = DynamoDBProgressStore::new( - &config.progress_store.aws_access_key_id, - &config.progress_store.aws_secret_access_key, - config.progress_store.aws_region, - config.progress_store.table_name, - ) - .await; - let mut executor = IndexerExecutor::new(progress_store, config.tasks.len(), metrics); - for task_config in config.tasks { - match task_config.task { - Task::Archival(archival_config) => { - let worker_pool = WorkerPool::new( - ArchivalWorker::new(archival_config).await?, - task_config.name, - task_config.concurrency, - ); - executor.register(worker_pool).await?; - } - Task::Blob(blob_config) => { - let worker_pool = WorkerPool::new( - BlobWorker::new(blob_config), - task_config.name, - task_config.concurrency, - ); - executor.register(worker_pool).await?; - } - Task::KV(kv_config) => { - let worker_pool = WorkerPool::new( - KVStoreWorker::new(kv_config).await, - task_config.name, - task_config.concurrency, - ); - executor.register(worker_pool).await?; - } - }; - } - let reader_options = ReaderOptions { - batch_size: config.remote_read_batch_size, - ..Default::default() - }; - executor - .run( - config.path, - config.remote_store_url, - config.remote_store_options, - reader_options, - exit_receiver, - ) - .await?; - Ok(()) -} diff --git a/crates/sui-data-ingestion/src/workers/blob.rs b/crates/sui-data-ingestion/src/workers/blob.rs deleted file mode 100644 index 7c097a36133..00000000000 --- a/crates/sui-data-ingestion/src/workers/blob.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use anyhow::Result; -use async_trait::async_trait; -use bytes::Bytes; -use object_store::{path::Path, ObjectStore}; -use serde::{Deserialize, Serialize}; -use sui_data_ingestion_core::{create_remote_store_client, Worker}; -use sui_storage::blob::{Blob, BlobEncoding}; -use sui_types::full_checkpoint_content::CheckpointData; - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct BlobTaskConfig { - pub url: String, - pub remote_store_options: Vec<(String, String)>, -} - -pub struct BlobWorker { - remote_store: Box, -} - -impl BlobWorker { - pub fn new(config: BlobTaskConfig) -> Self { - Self { - remote_store: create_remote_store_client(config.url, config.remote_store_options, 10) - .expect("failed to create remote store client"), - } - } -} - -#[async_trait] -impl Worker for BlobWorker { - async fn process_checkpoint(&self, checkpoint: CheckpointData) -> Result<()> { - let bytes = Blob::encode(&checkpoint, BlobEncoding::Bcs)?.to_bytes(); - let location = Path::from(format!( - "{}.chk", - checkpoint.checkpoint_summary.sequence_number - )); - self.remote_store.put(&location, Bytes::from(bytes)).await?; - Ok(()) - } -} diff --git a/crates/sui-data-ingestion/src/workers/mod.rs b/crates/sui-data-ingestion/src/workers/mod.rs deleted file mode 100644 index a2ad63a5275..00000000000 --- a/crates/sui-data-ingestion/src/workers/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod archival; -mod blob; -mod kv_store; -pub use archival::{ArchivalConfig, ArchivalWorker}; -pub use blob::{BlobTaskConfig, BlobWorker}; -pub use kv_store::{KVStoreTaskConfig, KVStoreWorker}; diff --git a/crates/sui-e2e-tests/Cargo.toml b/crates/sui-e2e-tests/Cargo.toml deleted file mode 100644 index 73693d65540..00000000000 --- a/crates/sui-e2e-tests/Cargo.toml +++ /dev/null @@ -1,60 +0,0 @@ -[package] -name = "sui-e2e-tests" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" -version = "0.1.0" - -[dependencies] - -[dev-dependencies] -tempfile.workspace = true -futures.workspace = true -prometheus.workspace = true -fs_extra.workspace = true -indexmap.workspace = true -insta.workspace = true -jsonrpsee.workspace = true -test-cluster.workspace = true -rand.workspace = true -expect-test.workspace = true -tokio.workspace = true -tracing.workspace = true -assert_cmd.workspace = true -serde.workspace = true -bcs.workspace = true -anyhow.workspace = true -async-trait.workspace = true -clap.workspace = true -serde_json.workspace = true - -move-binary-format.workspace = true -move-package.workspace = true -telemetry-subscribers.workspace = true -fastcrypto.workspace = true -fastcrypto-zkp.workspace = true -move-core-types.workspace = true - -sui-core.workspace = true -sui-framework.workspace = true -sui-json-rpc.workspace = true -sui-json-rpc-api.workspace = true -sui-node.workspace = true -sui-macros.workspace = true -sui-simulator.workspace = true -sui-storage.workspace = true -mysten-metrics.workspace = true -sui-tool.workspace = true -sui-protocol-config.workspace = true -sui-types.workspace = true -sui-move-build.workspace = true -sui-swarm-config.workspace = true -sui-swarm.workspace = true -sui-test-transaction-builder.workspace = true -sui-config.workspace = true -sui-json-rpc-types.workspace = true -sui.workspace = true -sui-sdk.workspace = true -sui-keys.workspace = true -shared-crypto.workspace = true diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/add_key_ability/Move.toml b/crates/sui-e2e-tests/tests/framework_upgrades/add_key_ability/Move.toml deleted file mode 100644 index 874fc2e73dd..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/add_key_ability/Move.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "SuiExtraAddKeyAbility" -version = "0.0.1" - -[dependencies] -SuiSystem = { local = "../../../../sui-framework/packages/sui-system" } -Sui = { local = "../../../../sui-framework/packages/sui-framework" } -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -sui_system = "0x3" diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/add_key_ability/sources/modules.move b/crates/sui-e2e-tests/tests/framework_upgrades/add_key_ability/sources/modules.move deleted file mode 100644 index 1f64d46c059..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/add_key_ability/sources/modules.move +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::msim_extra_1 { - use sui::object::UID; - use sui::tx_context::TxContext; - - struct Type has drop { - x: u64, - } - - struct Obj has key { - id: UID, - } - - struct AlmostObj has key { - id: UID, - } - - public fun canary(): u64 { - private_function(42) - } - - entry fun mint(_ctx: &mut TxContext) {} - - entry fun entry_fun() {} - - fun private_function(x: u64): u64 { - private_function_2(x) + 1 - } - - fun private_function_2(x: u64): u64 { x } - fun private_function_3(_x: u64) {} - - public fun generic(_t: T) {} -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/add_struct_ability/Move.toml b/crates/sui-e2e-tests/tests/framework_upgrades/add_struct_ability/Move.toml deleted file mode 100644 index 1bf3abfc2d7..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/add_struct_ability/Move.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "SuiExtraAddStructAbility" -version = "0.0.1" - -[dependencies] -SuiSystem = { local = "../../../../sui-framework/packages/sui-system" } -Sui = { local = "../../../../sui-framework/packages/sui-framework" } -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -sui_system = "0x3" diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/add_struct_ability/sources/modules.move b/crates/sui-e2e-tests/tests/framework_upgrades/add_struct_ability/sources/modules.move deleted file mode 100644 index 749cb3cf89c..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/add_struct_ability/sources/modules.move +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::msim_extra_1 { - use sui::object::{Self, UID}; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; - - struct Type has drop, copy { - x: u64, - } - - struct Obj has key, store { - id: UID, - } - - struct AlmostObj { - id: UID, - } - - struct Wrapper has key { - id: UID, - obj: Obj, - } - - public fun canary(): u64 { - private_function(42) - } - - entry fun mint(ctx: &mut TxContext) { - transfer::transfer( - Obj { id: object::new(ctx) }, - tx_context::sender(ctx), - ) - } - - entry fun wrap(obj: Obj, ctx: &mut TxContext) { - transfer::transfer( - Wrapper { id: object::new(ctx), obj }, - tx_context::sender(ctx), - ) - } - - entry fun entry_fun() {} - - fun private_function(x: u64): u64 { - private_function_2(x) + 1 - } - - fun private_function_2(x: u64): u64 { x } - fun private_function_3(_x: u64) {} - - public fun generic(_t: T) {} -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/base/Move.toml b/crates/sui-e2e-tests/tests/framework_upgrades/base/Move.toml deleted file mode 100644 index 80e1531719a..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/base/Move.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "SuiExtraBase" -version = "0.0.1" - -[dependencies] -SuiSystem = { local = "../../../../sui-framework/packages/sui-system" } -Sui = { local = "../../../../sui-framework/packages/sui-framework" } -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -sui_system = "0x3" diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/base/sources/modules.move b/crates/sui-e2e-tests/tests/framework_upgrades/base/sources/modules.move deleted file mode 100644 index 685865d9bf9..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/base/sources/modules.move +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::msim_extra_1 { - use sui::object::{Self, UID}; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; - - struct Type has drop { - x: u64, - } - - struct Obj has key { - id: UID, - } - - struct AlmostObj { - id: UID, - } - - public fun canary(): u64 { - private_function(41) - } - - entry fun mint(ctx: &mut TxContext) { - transfer::transfer( - Obj { id: object::new(ctx) }, - tx_context::sender(ctx), - ) - } - - entry fun entry_fun() {} - - fun private_function(x: u64): u64 { - private_function_2(x) + 1 - } - - fun private_function_2(x: u64): u64 { x } - fun private_function_3(_x: u64) {} - - public fun generic(_t: T) {} -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/change_entry_function_signature/Move.toml b/crates/sui-e2e-tests/tests/framework_upgrades/change_entry_function_signature/Move.toml deleted file mode 100644 index ad099807e1b..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/change_entry_function_signature/Move.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "SuiExtraChangeEntryFunctionSignature" -version = "0.0.1" - -[dependencies] -SuiSystem = { local = "../../../../sui-framework/packages/sui-system" } -Sui = { local = "../../../../sui-framework/packages/sui-framework" } -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -sui_system = "0x3" diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/change_entry_function_signature/sources/modules.move b/crates/sui-e2e-tests/tests/framework_upgrades/change_entry_function_signature/sources/modules.move deleted file mode 100644 index 04e61ddd52d..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/change_entry_function_signature/sources/modules.move +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::msim_extra_1 { - use sui::object::UID; - use sui::tx_context::TxContext; - - struct Type has drop { - x: u64, - } - - struct Obj has key { - id: UID, - } - - struct AlmostObj { - id: UID, - } - - public fun canary(): u64 { - private_function(47) - } - - entry fun mint(_ctx: &mut TxContext) {} - - entry fun entry_fun(_x: u64) {} - - fun private_function(x: u64): u64 { - private_function_2(x) + 1 - } - - fun private_function_2(x: u64): u64 { x } - fun private_function_3(_x: u64) {} - - public fun generic(_t: T) {} -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/change_public_function_signature/Move.toml b/crates/sui-e2e-tests/tests/framework_upgrades/change_public_function_signature/Move.toml deleted file mode 100644 index 20038f221f3..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/change_public_function_signature/Move.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "SuiExtraChangePublicFunctionSignature" -version = "0.0.1" - -[dependencies] -SuiSystem = { local = "../../../../sui-framework/packages/sui-system" } -Sui = { local = "../../../../sui-framework/packages/sui-framework" } -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -sui_system = "0x3" diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/change_public_function_signature/sources/modules.move b/crates/sui-e2e-tests/tests/framework_upgrades/change_public_function_signature/sources/modules.move deleted file mode 100644 index 1ab194ea371..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/change_public_function_signature/sources/modules.move +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::msim_extra_1 { - use sui::object::UID; - use sui::tx_context::TxContext; - - struct Type has drop { - x: u64, - } - - struct Obj has key { - id: UID, - } - - struct AlmostObj { - id: UID, - } - - public fun canary(): u64 { - private_function(46) - } - - entry fun mint(_ctx: &mut TxContext) {} - - entry fun entry_fun() {} - - fun private_function(x: u64): u64 { - x + 1 - } - - fun private_function_2(x: u64): u64 { x } - fun private_function_3(_x: u64) {} - - public fun generic(_t: T, _x: u64) {} -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/change_struct_ability/Move.toml b/crates/sui-e2e-tests/tests/framework_upgrades/change_struct_ability/Move.toml deleted file mode 100644 index dc7a7e099e8..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/change_struct_ability/Move.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "SuiExtraChangeStructAbility" -version = "0.0.1" - -[dependencies] -SuiSystem = { local = "../../../../sui-framework/packages/sui-system" } -Sui = { local = "../../../../sui-framework/packages/sui-framework" } -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -sui_system = "0x3" diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/change_struct_ability/sources/modules.move b/crates/sui-e2e-tests/tests/framework_upgrades/change_struct_ability/sources/modules.move deleted file mode 100644 index 50c7e80f293..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/change_struct_ability/sources/modules.move +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::msim_extra_1 { - use sui::object::UID; - use sui::tx_context::TxContext; - - struct Type { - x: u64, - } - - struct Obj has key { - id: UID, - } - - struct AlmostObj { - id: UID, - } - - public fun canary(): u64 { - private_function(44) - } - - entry fun mint(_ctx: &mut TxContext) {} - - entry fun entry_fun() {} - - fun private_function(x: u64): u64 { - x + 1 - } - - fun private_function_2(x: u64): u64 { x } - fun private_function_3(_x: u64) {} - - public fun generic(_t: T) {} -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/change_struct_layout/Move.toml b/crates/sui-e2e-tests/tests/framework_upgrades/change_struct_layout/Move.toml deleted file mode 100644 index 70e72c3bc10..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/change_struct_layout/Move.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "SuiExtraChangeStructLayout" -version = "0.0.1" - -[dependencies] -SuiSystem = { local = "../../../../sui-framework/packages/sui-system" } -Sui = { local = "../../../../sui-framework/packages/sui-framework" } -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -sui_system = "0x3" diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/change_struct_layout/sources/modules.move b/crates/sui-e2e-tests/tests/framework_upgrades/change_struct_layout/sources/modules.move deleted file mode 100644 index 87b49f6cf63..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/change_struct_layout/sources/modules.move +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::msim_extra_1 { - use sui::object::UID; - use sui::tx_context::TxContext; - - struct Type has drop { - x: u64, - y: u64, - } - - struct Obj has key { - id: UID, - } - - struct AlmostObj { - id: UID, - } - - public fun canary(): u64 { - private_function(43) - } - - entry fun mint(_ctx: &mut TxContext) {} - - entry fun entry_fun() {} - - fun private_function(x: u64): u64 { - x + 1 - } - - fun private_function_2(x: u64): u64 { x } - fun private_function_3(_x: u64) {} - - public fun generic(_t: T) {} -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/change_type_constraint/Move.toml b/crates/sui-e2e-tests/tests/framework_upgrades/change_type_constraint/Move.toml deleted file mode 100644 index 8d3b016bc80..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/change_type_constraint/Move.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "SuiExtraChangeTypeConstraint" -version = "0.0.1" - -[dependencies] -SuiSystem = { local = "../../../../sui-framework/packages/sui-system" } -Sui = { local = "../../../../sui-framework/packages/sui-framework" } -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -sui_system = "0x3" diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/change_type_constraint/sources/modules.move b/crates/sui-e2e-tests/tests/framework_upgrades/change_type_constraint/sources/modules.move deleted file mode 100644 index 4fbcfa4f086..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/change_type_constraint/sources/modules.move +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::msim_extra_1 { - use sui::object::UID; - use sui::tx_context::TxContext; - - struct Type has drop { - x: u64, - } - - struct Obj has key { - id: UID, - } - - struct AlmostObj { - id: UID, - } - - public fun canary(): u64 { - private_function(45) - } - - entry fun mint(_ctx: &mut TxContext) {} - - entry fun entry_fun() {} - - fun private_function(x: u64): u64 { - x + 1 - } - - fun private_function_2(x: u64): u64 { x } - fun private_function_3(_x: u64) {} - - public fun generic(_t: T) {} -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/compatible/Move.toml b/crates/sui-e2e-tests/tests/framework_upgrades/compatible/Move.toml deleted file mode 100644 index 158b0be4e95..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/compatible/Move.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "SuiExtraCompatible" -version = "0.0.1" - -[dependencies] -SuiSystem = { local = "../../../../sui-framework/packages/sui-system" } -Sui = { local = "../../../../sui-framework/packages/sui-framework" } -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -sui_system = "0x3" diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/compatible/sources/modules.move b/crates/sui-e2e-tests/tests/framework_upgrades/compatible/sources/modules.move deleted file mode 100644 index 47da47306a0..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/compatible/sources/modules.move +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::msim_extra_1 { - use sui::object::UID; - use sui::tx_context::TxContext; - - struct Type has drop { - x: u64 - } - - struct Obj has key { - id: UID, - } - - struct AlmostObj { - id: UID, - } - - struct NewType { - t: Type, - } - - public fun canary(): u64 { - private_function(20, 21) - } - - entry fun mint(_ctx: &mut TxContext) {} - - public entry fun entry_fun() {} - - /// Bit of a confusing function name, but we're testing that a - /// once private function can be made public. - public fun private_function(x: u64, y: u64): u64 { - x + y + 2 - } - - // Removing this function - // fun private_function_2(x: u64): u64 { x } - - entry fun private_function_3(_x: u64) {} - - public fun generic(_t: T) {} -} - -module sui_system::msim_extra_2 { - public fun bar(): u64 { - 43 - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/extra_package/Move.toml b/crates/sui-e2e-tests/tests/framework_upgrades/extra_package/Move.toml deleted file mode 100644 index 7751940f62b..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/extra_package/Move.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "SuiExtra" -version = "0.0.1" - -[dependencies] -SuiSystem = { local = "../../../../sui-framework/packages/sui-system" } -Sui = { local = "../../../../sui-framework/packages/sui-framework" } -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -sui_extra = "0x42" diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/extra_package/sources/modules.move b/crates/sui-e2e-tests/tests/framework_upgrades/extra_package/sources/modules.move deleted file mode 100644 index 438ee4596b5..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/extra_package/sources/modules.move +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_extra::msim_extra_1 { - use sui::object::{Self, UID}; - use sui::transfer; - use sui::tx_context::TxContext; - - struct S has key { id: UID } - - fun init(ctx: &mut TxContext) { - transfer::share_object(S { - id: object::new(ctx) - }) - } - - public fun canary(): u64 { - 43 - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/Move.toml b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/Move.toml deleted file mode 100644 index c4aeece9ecd..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "MockSuiSystemBase" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } -MoveStdlib = { local = "../../../../../sui-framework/packages/move-stdlib" } - -[addresses] -sui_system = "0x3" diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/README.txt b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/README.txt deleted file mode 100644 index 04f2b82034f..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/README.txt +++ /dev/null @@ -1,9 +0,0 @@ -This directory contains a mock version of the 0x3 package (sui-system). -The idea is to introduce a minimum version of the sui-system that we can use to start Sui. -We can then use this mock version as the base package to test various things such as sui system state upgrades. -This allows us to decouple from the complicated code in the original sui-system under sui-framework. -We only need to update code here and in other mock versions when the core protocol changes. This includes: -1. The genesis creation function interface -2. advance_epoch and advance_epoch_safe_mode interface -3. Any new system function call to the sui-system package required by protocol. -4. Any new information needed at epoch start. diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/genesis.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/genesis.move deleted file mode 100644 index bf640c93d4d..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/genesis.move +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::genesis { - use std::vector; - use sui::balance::{Self, Balance}; - use sui::object::UID; - use sui::sui::SUI; - use sui::tx_context::{Self, TxContext}; - use std::option::Option; - - use sui_system::sui_system; - use sui_system::validator; - - struct GenesisValidatorMetadata has drop, copy { - name: vector, - description: vector, - image_url: vector, - project_url: vector, - - sui_address: address, - - gas_price: u64, - commission_rate: u64, - - protocol_public_key: vector, - proof_of_possession: vector, - - network_public_key: vector, - worker_public_key: vector, - - network_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - } - - struct GenesisChainParameters has drop, copy { - protocol_version: u64, - chain_start_timestamp_ms: u64, - epoch_duration_ms: u64, - - stake_subsidy_start_epoch: u64, - stake_subsidy_initial_distribution_amount: u64, - stake_subsidy_period_length: u64, - stake_subsidy_decrease_rate: u16, - - max_validator_count: u64, - min_validator_joining_stake: u64, - validator_low_stake_threshold: u64, - validator_very_low_stake_threshold: u64, - validator_low_stake_grace_period: u64, - } - - struct TokenDistributionSchedule has drop { - stake_subsidy_fund_mist: u64, - allocations: vector, - } - - struct TokenAllocation has drop { - recipient_address: address, - amount_mist: u64, - staked_with_validator: Option

    , - } - - fun create( - sui_system_state_id: UID, - sui_supply: Balance, - genesis_chain_parameters: GenesisChainParameters, - genesis_validators: vector, - _token_distribution_schedule: TokenDistributionSchedule, - ctx: &mut TxContext, - ) { - assert!(tx_context::epoch(ctx) == 0, 0); - - let validators = vector::empty(); - let count = vector::length(&genesis_validators); - let i = 0; - while (i < count) { - let GenesisValidatorMetadata { - name: _, - description: _, - image_url: _, - project_url: _, - sui_address, - gas_price: _, - commission_rate: _, - protocol_public_key, - proof_of_possession: _, - network_public_key, - worker_public_key, - network_address, - p2p_address, - primary_address, - worker_address, - } = *vector::borrow(&genesis_validators, i); - - let validator = validator::new( - sui_address, - protocol_public_key, - network_public_key, - worker_public_key, - network_address, - p2p_address, - primary_address, - worker_address, - balance::split(&mut sui_supply, 2500), - ctx - ); - - vector::push_back(&mut validators, validator); - - i = i + 1; - }; - - sui_system::create( - sui_system_state_id, - validators, - sui_supply, // storage_fund - genesis_chain_parameters.protocol_version, - genesis_chain_parameters.chain_start_timestamp_ms, - genesis_chain_parameters.epoch_duration_ms, - ctx, - ); - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/sui_system.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/sui_system.move deleted file mode 100644 index ef3bf9e2904..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/sui_system.move +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::sui_system { - use sui::balance::Balance; - use sui::object::UID; - use sui::sui::SUI; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; - use sui::dynamic_field; - - use sui_system::validator::Validator; - use sui_system::sui_system_state_inner::SuiSystemStateInner; - use sui_system::sui_system_state_inner; - - friend sui_system::genesis; - - struct SuiSystemState has key { - id: UID, - version: u64, - } - - public(friend) fun create( - id: UID, - validators: vector, - storage_fund: Balance, - protocol_version: u64, - epoch_start_timestamp_ms: u64, - epoch_duration_ms: u64, - ctx: &mut TxContext, - ) { - let system_state = sui_system_state_inner::create( - validators, - storage_fund, - protocol_version, - epoch_start_timestamp_ms, - epoch_duration_ms, - ctx, - ); - let version = sui_system_state_inner::genesis_system_state_version(); - let self = SuiSystemState { - id, - version, - }; - dynamic_field::add(&mut self.id, version, system_state); - transfer::share_object(self); - } - - fun advance_epoch( - storage_reward: Balance, - computation_reward: Balance, - wrapper: &mut SuiSystemState, - new_epoch: u64, - next_protocol_version: u64, - storage_rebate: u64, - _non_refundable_storage_fee: u64, - _storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested - // into storage fund, in basis point. - _reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. - epoch_start_timestamp_ms: u64, // Timestamp of the epoch start - ctx: &mut TxContext, - ) : Balance { - let self = load_system_state_mut(wrapper); - assert!(tx_context::sender(ctx) == @0x0, 0); - let storage_rebate = sui_system_state_inner::advance_epoch( - self, - new_epoch, - next_protocol_version, - storage_reward, - computation_reward, - storage_rebate, - epoch_start_timestamp_ms, - ); - - storage_rebate - } - - fun load_system_state_mut(self: &mut SuiSystemState): &mut SuiSystemStateInner { - load_inner_maybe_upgrade(self) - } - - fun load_inner_maybe_upgrade(self: &mut SuiSystemState): &mut SuiSystemStateInner { - let version = self.version; - // TODO: This is where we check the version and perform upgrade if necessary. - - let inner: &mut SuiSystemStateInner = dynamic_field::borrow_mut(&mut self.id, version); - assert!(sui_system_state_inner::system_state_version(inner) == version, 0); - inner - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/sui_system_state_inner.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/sui_system_state_inner.move deleted file mode 100644 index 3b39ea3502f..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/sui_system_state_inner.move +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::sui_system_state_inner { - use sui::balance::{Self, Balance}; - use sui::sui::SUI; - use sui::tx_context::TxContext; - use sui::bag::{Self, Bag}; - use sui::table::{Self, Table}; - use sui::object::ID; - - use sui_system::validator::Validator; - use sui_system::validator_wrapper::ValidatorWrapper; - use sui_system::validator_wrapper; - use sui_system::validator; - use sui::object; - - friend sui_system::sui_system; - - const SYSTEM_STATE_VERSION_V1: u64 = 18446744073709551605; // u64::MAX - 10 - - struct SystemParameters has store { - epoch_duration_ms: u64, - extra_fields: Bag, - } - - struct ValidatorSet has store { - active_validators: vector, - inactive_validators: Table, - extra_fields: Bag, - } - - struct SuiSystemStateInner has store { - epoch: u64, - protocol_version: u64, - system_state_version: u64, - validators: ValidatorSet, - storage_fund: Balance, - parameters: SystemParameters, - reference_gas_price: u64, - safe_mode: bool, - epoch_start_timestamp_ms: u64, - extra_fields: Bag, - } - - public(friend) fun create( - validators: vector, - storage_fund: Balance, - protocol_version: u64, - epoch_start_timestamp_ms: u64, - epoch_duration_ms: u64, - ctx: &mut TxContext, - ): SuiSystemStateInner { - let validators = new_validator_set(validators, ctx); - let system_state = SuiSystemStateInner { - epoch: 0, - protocol_version, - system_state_version: genesis_system_state_version(), - validators, - storage_fund, - parameters: SystemParameters { - epoch_duration_ms, - extra_fields: bag::new(ctx), - }, - reference_gas_price: 1, - safe_mode: false, - epoch_start_timestamp_ms, - extra_fields: bag::new(ctx), - }; - // Add a dummy inactive validator so that we could test validator upgrade through wrapper latter. - add_dummy_inactive_validator_for_testing(&mut system_state, ctx); - system_state - } - - public(friend) fun advance_epoch( - self: &mut SuiSystemStateInner, - new_epoch: u64, - next_protocol_version: u64, - storage_reward: Balance, - computation_reward: Balance, - storage_rebate_amount: u64, - epoch_start_timestamp_ms: u64, - ) : Balance { - self.epoch_start_timestamp_ms = epoch_start_timestamp_ms; - self.epoch = self.epoch + 1; - assert!(new_epoch == self.epoch, 0); - self.safe_mode = false; - self.protocol_version = next_protocol_version; - - balance::join(&mut self.storage_fund, computation_reward); - balance::join(&mut self.storage_fund, storage_reward); - let storage_rebate = balance::split(&mut self.storage_fund, storage_rebate_amount); - storage_rebate - } - - public(friend) fun protocol_version(self: &SuiSystemStateInner): u64 { self.protocol_version } - public(friend) fun system_state_version(self: &SuiSystemStateInner): u64 { self.system_state_version } - public(friend) fun genesis_system_state_version(): u64 { - SYSTEM_STATE_VERSION_V1 - } - - public(friend) fun add_dummy_inactive_validator_for_testing(self: &mut SuiSystemStateInner, ctx: &mut TxContext) { - // Add a new entry to the inactive validator table for upgrade testing. - let dummy_inactive_validator = validator_wrapper::create_v1( - validator::new_dummy_inactive_validator(ctx), - ctx, - ); - table::add(&mut self.validators.inactive_validators, object::id_from_address(@0x0), dummy_inactive_validator); - } - - fun new_validator_set(init_active_validators: vector, ctx: &mut TxContext): ValidatorSet { - ValidatorSet { - active_validators: init_active_validators, - inactive_validators: table::new(ctx), - extra_fields: bag::new(ctx), - } - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/validator.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/validator.move deleted file mode 100644 index d7df822a08a..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/validator.move +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::validator { - use std::ascii; - - use sui::tx_context::TxContext; - use std::string::{Self, String}; - use sui::bag::{Self, Bag}; - use sui::balance::{Self, Balance}; - use sui::sui::SUI; - - friend sui_system::genesis; - friend sui_system::sui_system_state_inner; - friend sui_system::validator_wrapper; - - struct ValidatorMetadata has store { - sui_address: address, - protocol_pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - net_address: String, - p2p_address: String, - primary_address: String, - worker_address: String, - extra_fields: Bag, - } - - struct Validator has store { - metadata: ValidatorMetadata, - voting_power: u64, - stake: Balance, - extra_fields: Bag, - } - - public(friend) fun new( - sui_address: address, - protocol_pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - net_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - init_stake: Balance, - ctx: &mut TxContext - ): Validator { - let metadata = ValidatorMetadata { - sui_address, - protocol_pubkey_bytes, - network_pubkey_bytes, - worker_pubkey_bytes, - net_address: string::from_ascii(ascii::string(net_address)), - p2p_address: string::from_ascii(ascii::string(p2p_address)), - primary_address: string::from_ascii(ascii::string(primary_address)), - worker_address: string::from_ascii(ascii::string(worker_address)), - extra_fields: bag::new(ctx), - }; - - Validator { - metadata, - voting_power: balance::value(&init_stake), - stake: init_stake, - extra_fields: bag::new(ctx), - } - } - - public(friend) fun new_dummy_inactive_validator( - ctx: &mut TxContext - ): Validator { - let metadata = ValidatorMetadata { - sui_address: @0x0, - protocol_pubkey_bytes: vector[], - network_pubkey_bytes: vector[], - worker_pubkey_bytes: vector[], - net_address: string::utf8(vector[]), - p2p_address: string::utf8(vector[]), - primary_address: string::utf8(vector[]), - worker_address: string::utf8(vector[]), - extra_fields: bag::new(ctx), - }; - - Validator { - metadata, - voting_power: 0, - stake: balance::zero(), - extra_fields: bag::new(ctx), - } - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/validator_wrapper.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/validator_wrapper.move deleted file mode 100644 index be79baee76f..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/base/sources/validator_wrapper.move +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::validator_wrapper { - use sui::versioned::Versioned; - use sui::versioned; - use sui::tx_context::TxContext; - use sui_system::validator::Validator; - - friend sui_system::sui_system_state_inner; - - const VALIDATOR_VERSION_V1: u64 = 18446744073709551605; // u64::MAX - 10 - - const EInvalidVersion: u64 = 0; - - struct ValidatorWrapper has store { - inner: Versioned - } - - // Validator corresponds to version 1. - public(friend) fun create_v1(validator: Validator, ctx: &mut TxContext): ValidatorWrapper { - ValidatorWrapper { - inner: versioned::create(VALIDATOR_VERSION_V1, validator, ctx) - } - } - - /// This function should always return the latest supported version. - /// If the inner version is old, we upgrade it lazily in-place. - public(friend) fun load_validator_maybe_upgrade(self: &mut ValidatorWrapper): &mut Validator { - upgrade_to_latest(self); - versioned::load_value_mut(&mut self.inner) - } - - /// Destroy the wrapper and retrieve the inner validator object. - public(friend) fun destroy(self: ValidatorWrapper): Validator { - upgrade_to_latest(&mut self); - let ValidatorWrapper { inner } = self; - versioned::destroy(inner) - } - - fun upgrade_to_latest(self: &mut ValidatorWrapper) { - let version = version(self); - // TODO: When new versions are added, we need to explicitly upgrade here. - assert!(version == VALIDATOR_VERSION_V1, EInvalidVersion); - } - - fun version(self: &ValidatorWrapper): u64 { - versioned::version(&self.inner) - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/Move.toml b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/Move.toml deleted file mode 100644 index 3e0caa622b8..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "SuiSystemDeepUpgrade" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } -MoveStdlib = { local = "../../../../../sui-framework/packages/move-stdlib" } - -[addresses] -sui_system = "0x3" diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/genesis.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/genesis.move deleted file mode 100644 index bf640c93d4d..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/genesis.move +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::genesis { - use std::vector; - use sui::balance::{Self, Balance}; - use sui::object::UID; - use sui::sui::SUI; - use sui::tx_context::{Self, TxContext}; - use std::option::Option; - - use sui_system::sui_system; - use sui_system::validator; - - struct GenesisValidatorMetadata has drop, copy { - name: vector, - description: vector, - image_url: vector, - project_url: vector, - - sui_address: address, - - gas_price: u64, - commission_rate: u64, - - protocol_public_key: vector, - proof_of_possession: vector, - - network_public_key: vector, - worker_public_key: vector, - - network_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - } - - struct GenesisChainParameters has drop, copy { - protocol_version: u64, - chain_start_timestamp_ms: u64, - epoch_duration_ms: u64, - - stake_subsidy_start_epoch: u64, - stake_subsidy_initial_distribution_amount: u64, - stake_subsidy_period_length: u64, - stake_subsidy_decrease_rate: u16, - - max_validator_count: u64, - min_validator_joining_stake: u64, - validator_low_stake_threshold: u64, - validator_very_low_stake_threshold: u64, - validator_low_stake_grace_period: u64, - } - - struct TokenDistributionSchedule has drop { - stake_subsidy_fund_mist: u64, - allocations: vector, - } - - struct TokenAllocation has drop { - recipient_address: address, - amount_mist: u64, - staked_with_validator: Option
    , - } - - fun create( - sui_system_state_id: UID, - sui_supply: Balance, - genesis_chain_parameters: GenesisChainParameters, - genesis_validators: vector, - _token_distribution_schedule: TokenDistributionSchedule, - ctx: &mut TxContext, - ) { - assert!(tx_context::epoch(ctx) == 0, 0); - - let validators = vector::empty(); - let count = vector::length(&genesis_validators); - let i = 0; - while (i < count) { - let GenesisValidatorMetadata { - name: _, - description: _, - image_url: _, - project_url: _, - sui_address, - gas_price: _, - commission_rate: _, - protocol_public_key, - proof_of_possession: _, - network_public_key, - worker_public_key, - network_address, - p2p_address, - primary_address, - worker_address, - } = *vector::borrow(&genesis_validators, i); - - let validator = validator::new( - sui_address, - protocol_public_key, - network_public_key, - worker_public_key, - network_address, - p2p_address, - primary_address, - worker_address, - balance::split(&mut sui_supply, 2500), - ctx - ); - - vector::push_back(&mut validators, validator); - - i = i + 1; - }; - - sui_system::create( - sui_system_state_id, - validators, - sui_supply, // storage_fund - genesis_chain_parameters.protocol_version, - genesis_chain_parameters.chain_start_timestamp_ms, - genesis_chain_parameters.epoch_duration_ms, - ctx, - ); - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/sui_system.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/sui_system.move deleted file mode 100644 index a26bd4eb03a..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/sui_system.move +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::sui_system { - use sui::balance::Balance; - use sui::object::UID; - use sui::sui::SUI; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; - use sui::dynamic_field; - - use sui_system::validator::Validator; - use sui_system::sui_system_state_inner::{Self, SuiSystemStateInnerV2, SuiSystemStateInner}; - - friend sui_system::genesis; - - struct SuiSystemState has key { - id: UID, - version: u64, - } - - public(friend) fun create( - id: UID, - validators: vector, - storage_fund: Balance, - protocol_version: u64, - epoch_start_timestamp_ms: u64, - epoch_duration_ms: u64, - ctx: &mut TxContext, - ) { - let system_state = sui_system_state_inner::create( - validators, - storage_fund, - protocol_version, - epoch_start_timestamp_ms, - epoch_duration_ms, - ctx, - ); - let version = sui_system_state_inner::genesis_system_state_version(); - let self = SuiSystemState { - id, - version, - }; - dynamic_field::add(&mut self.id, version, system_state); - transfer::share_object(self); - } - - fun advance_epoch( - storage_reward: Balance, - computation_reward: Balance, - wrapper: &mut SuiSystemState, - new_epoch: u64, - next_protocol_version: u64, - storage_rebate: u64, - _non_refundable_storage_fee: u64, - _storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested - // into storage fund, in basis point. - _reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. - epoch_start_timestamp_ms: u64, // Timestamp of the epoch start - ctx: &mut TxContext, - ) : Balance { - let self = load_system_state_mut(wrapper); - assert!(tx_context::sender(ctx) == @0x0, 0); - let storage_rebate = sui_system_state_inner::advance_epoch( - self, - new_epoch, - next_protocol_version, - storage_reward, - computation_reward, - storage_rebate, - epoch_start_timestamp_ms, - ); - - storage_rebate - } - - fun load_system_state_mut(self: &mut SuiSystemState): &mut SuiSystemStateInnerV2 { - load_inner_maybe_upgrade(self) - } - - fun load_inner_maybe_upgrade(self: &mut SuiSystemState): &mut SuiSystemStateInnerV2 { - let version = self.version; - if (version == sui_system_state_inner::genesis_system_state_version()) { - let inner: SuiSystemStateInner = dynamic_field::remove(&mut self.id, version); - let new_inner = sui_system_state_inner::v1_to_v2(inner); - version = sui_system_state_inner::system_state_version(&new_inner); - dynamic_field::add(&mut self.id, version, new_inner); - self.version = version; - }; - - let inner: &mut SuiSystemStateInnerV2 = dynamic_field::borrow_mut(&mut self.id, version); - assert!(sui_system_state_inner::system_state_version(inner) == version, 0); - inner - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/sui_system_state_inner.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/sui_system_state_inner.move deleted file mode 100644 index cb99c612686..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/sui_system_state_inner.move +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::sui_system_state_inner { - use std::vector; - - use sui::balance::{Self, Balance}; - use sui::sui::SUI; - use sui::tx_context::TxContext; - use sui::bag::{Self, Bag}; - use sui::table::{Self, Table}; - use sui::object::ID; - - use sui_system::validator::{Validator, ValidatorV2}; - use sui_system::validator_wrapper::ValidatorWrapper; - use sui_system::validator_wrapper; - use sui::object; - use sui_system::validator; - - friend sui_system::sui_system; - - const SYSTEM_STATE_VERSION_V1: u64 = 18446744073709551605; // u64::MAX - 10 - // Not using MAX - 9 since it's already used in the shallow upgrade test. - const SYSTEM_STATE_VERSION_V2: u64 = 18446744073709551607; // u64::MAX - 8 - - struct SystemParameters has store { - epoch_duration_ms: u64, - extra_fields: Bag, - } - - struct ValidatorSet has store { - active_validators: vector, - inactive_validators: Table, - extra_fields: Bag, - } - - struct ValidatorSetV2 has store { - active_validators: vector, - inactive_validators: Table, - extra_fields: Bag, - } - - struct SuiSystemStateInner has store { - epoch: u64, - protocol_version: u64, - system_state_version: u64, - validators: ValidatorSet, - storage_fund: Balance, - parameters: SystemParameters, - reference_gas_price: u64, - safe_mode: bool, - epoch_start_timestamp_ms: u64, - extra_fields: Bag, - } - - struct SuiSystemStateInnerV2 has store { - new_dummy_field: u64, - epoch: u64, - protocol_version: u64, - system_state_version: u64, - validators: ValidatorSetV2, - storage_fund: Balance, - parameters: SystemParameters, - reference_gas_price: u64, - safe_mode: bool, - epoch_start_timestamp_ms: u64, - extra_fields: Bag, - } - - public(friend) fun create( - validators: vector, - storage_fund: Balance, - protocol_version: u64, - epoch_start_timestamp_ms: u64, - epoch_duration_ms: u64, - ctx: &mut TxContext, - ): SuiSystemStateInner { - let validators = new_validator_set(validators, ctx); - let system_state = SuiSystemStateInner { - epoch: 0, - protocol_version, - system_state_version: genesis_system_state_version(), - validators, - storage_fund, - parameters: SystemParameters { - epoch_duration_ms, - extra_fields: bag::new(ctx), - }, - reference_gas_price: 1, - safe_mode: false, - epoch_start_timestamp_ms, - extra_fields: bag::new(ctx), - }; - system_state - } - - public(friend) fun advance_epoch( - self: &mut SuiSystemStateInnerV2, - new_epoch: u64, - next_protocol_version: u64, - storage_reward: Balance, - computation_reward: Balance, - storage_rebate_amount: u64, - epoch_start_timestamp_ms: u64, - ) : Balance { - touch_dummy_inactive_validator(self); - - self.epoch_start_timestamp_ms = epoch_start_timestamp_ms; - self.epoch = self.epoch + 1; - assert!(new_epoch == self.epoch, 0); - self.safe_mode = false; - self.protocol_version = next_protocol_version; - - balance::join(&mut self.storage_fund, computation_reward); - balance::join(&mut self.storage_fund, storage_reward); - let storage_rebate = balance::split(&mut self.storage_fund, storage_rebate_amount); - storage_rebate - } - - public(friend) fun protocol_version(self: &SuiSystemStateInnerV2): u64 { self.protocol_version } - public(friend) fun system_state_version(self: &SuiSystemStateInnerV2): u64 { self.system_state_version } - public(friend) fun genesis_system_state_version(): u64 { - SYSTEM_STATE_VERSION_V1 - } - - fun new_validator_set(init_active_validators: vector, ctx: &mut TxContext): ValidatorSet { - ValidatorSet { - active_validators: init_active_validators, - inactive_validators: table::new(ctx), - extra_fields: bag::new(ctx), - } - } - - public(friend) fun v1_to_v2(v1: SuiSystemStateInner): SuiSystemStateInnerV2 { - let SuiSystemStateInner { - epoch, - protocol_version, - system_state_version: old_system_state_version, - validators, - storage_fund, - parameters, - reference_gas_price, - safe_mode, - epoch_start_timestamp_ms, - extra_fields, - } = v1; - let new_validator_set = validator_set_v1_to_v2(validators); - assert!(old_system_state_version == SYSTEM_STATE_VERSION_V1, 0); - SuiSystemStateInnerV2 { - new_dummy_field: 100, - epoch, - protocol_version, - system_state_version: SYSTEM_STATE_VERSION_V2, - validators: new_validator_set, - storage_fund, - parameters, - reference_gas_price, - safe_mode, - epoch_start_timestamp_ms, - extra_fields, - } - } - - /// Load the dummy inactive validator added in the base version, trigger it to be upgraded. - fun touch_dummy_inactive_validator(self: &mut SuiSystemStateInnerV2) { - let validator_wrapper = table::borrow_mut(&mut self.validators.inactive_validators, object::id_from_address(@0x0)); - let _ = validator_wrapper::load_validator_maybe_upgrade(validator_wrapper); - } - - fun validator_set_v1_to_v2(v1: ValidatorSet): ValidatorSetV2 { - let ValidatorSet { - active_validators, - inactive_validators, - extra_fields, - } = v1; - let new_active_validators = vector[]; - while (!vector::is_empty(&active_validators)) { - let validator = vector::pop_back(&mut active_validators); - let validator = validator::v1_to_v2(validator); - vector::push_back(&mut new_active_validators, validator); - }; - vector::destroy_empty(active_validators); - vector::reverse(&mut new_active_validators); - ValidatorSetV2 { - active_validators: new_active_validators, - inactive_validators, - extra_fields, - } - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/validator.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/validator.move deleted file mode 100644 index a881cdefc3f..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/validator.move +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::validator { - use std::ascii; - - use sui::tx_context::TxContext; - use std::string::{Self, String}; - use sui::bag::{Self, Bag}; - use sui::balance::{Self, Balance}; - use sui::sui::SUI; - - friend sui_system::genesis; - friend sui_system::sui_system_state_inner; - friend sui_system::validator_wrapper; - - struct ValidatorMetadata has store { - sui_address: address, - protocol_pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - net_address: String, - p2p_address: String, - primary_address: String, - worker_address: String, - extra_fields: Bag, - } - - struct Validator has store { - metadata: ValidatorMetadata, - voting_power: u64, - stake: Balance, - extra_fields: Bag, - } - - struct ValidatorV2 has store { - new_dummy_field: u64, - metadata: ValidatorMetadata, - voting_power: u64, - stake: Balance, - extra_fields: Bag, - } - - public(friend) fun new( - sui_address: address, - protocol_pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - net_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - init_stake: Balance, - ctx: &mut TxContext - ): Validator { - let metadata = ValidatorMetadata { - sui_address, - protocol_pubkey_bytes, - network_pubkey_bytes, - worker_pubkey_bytes, - net_address: string::from_ascii(ascii::string(net_address)), - p2p_address: string::from_ascii(ascii::string(p2p_address)), - primary_address: string::from_ascii(ascii::string(primary_address)), - worker_address: string::from_ascii(ascii::string(worker_address)), - extra_fields: bag::new(ctx), - }; - - Validator { - metadata, - voting_power: balance::value(&init_stake), - stake: init_stake, - extra_fields: bag::new(ctx), - } - } - - public(friend) fun v1_to_v2(v1: Validator): ValidatorV2 { - let Validator { - metadata, - voting_power, - stake, - extra_fields, - } = v1; - ValidatorV2 { - new_dummy_field: 100, - metadata, - voting_power, - stake, - extra_fields, - } - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/validator_wrapper.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/validator_wrapper.move deleted file mode 100644 index e57b6f00845..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/deep_upgrade/sources/validator_wrapper.move +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::validator_wrapper { - use sui::versioned::Versioned; - use sui::versioned; - use sui::tx_context::TxContext; - use sui_system::validator::{Validator, ValidatorV2}; - use sui_system::validator; - - friend sui_system::sui_system; - friend sui_system::sui_system_state_inner; - - const VALIDATOR_VERSION_V1: u64 = 18446744073709551605; // u64::MAX - 10 - const VALIDATOR_VERSION_V3: u64 = 18446744073709551607; // u64::MAX - 8 - - const EInvalidVersion: u64 = 0; - - struct ValidatorWrapper has store { - inner: Versioned - } - - // Validator corresponds to version 1. - public(friend) fun create_v1(validator: Validator, ctx: &mut TxContext): ValidatorWrapper { - ValidatorWrapper { - inner: versioned::create(VALIDATOR_VERSION_V1, validator, ctx) - } - } - - /// This function should always return the latest supported version. - /// If the inner version is old, we upgrade it lazily in-place. - public(friend) fun load_validator_maybe_upgrade(self: &mut ValidatorWrapper): &mut ValidatorV2 { - upgrade_to_latest(self); - versioned::load_value_mut(&mut self.inner) - } - - /// Destroy the wrapper and retrieve the inner validator object. - public(friend) fun destroy(self: ValidatorWrapper): ValidatorV2 { - upgrade_to_latest(&mut self); - let ValidatorWrapper { inner } = self; - versioned::destroy(inner) - } - - fun upgrade_to_latest(self: &mut ValidatorWrapper) { - let version = version(self); - if (version == VALIDATOR_VERSION_V1) { - let (v1, cap) = versioned::remove_value_for_upgrade(&mut self.inner); - let v3 = validator::v1_to_v2(v1); - versioned::upgrade(&mut self.inner, VALIDATOR_VERSION_V3, v3, cap); - }; - assert!(version(self) == VALIDATOR_VERSION_V3, EInvalidVersion); - } - - fun version(self: &ValidatorWrapper): u64 { - versioned::version(&self.inner) - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/Move.toml b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/Move.toml deleted file mode 100644 index d0a073c1f8d..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "MockSuiSystemSafeMode" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } -MoveStdlib = { local = "../../../../../sui-framework/packages/move-stdlib" } - -[addresses] -sui_system = "0x3" diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/genesis.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/genesis.move deleted file mode 100644 index bf640c93d4d..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/genesis.move +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::genesis { - use std::vector; - use sui::balance::{Self, Balance}; - use sui::object::UID; - use sui::sui::SUI; - use sui::tx_context::{Self, TxContext}; - use std::option::Option; - - use sui_system::sui_system; - use sui_system::validator; - - struct GenesisValidatorMetadata has drop, copy { - name: vector, - description: vector, - image_url: vector, - project_url: vector, - - sui_address: address, - - gas_price: u64, - commission_rate: u64, - - protocol_public_key: vector, - proof_of_possession: vector, - - network_public_key: vector, - worker_public_key: vector, - - network_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - } - - struct GenesisChainParameters has drop, copy { - protocol_version: u64, - chain_start_timestamp_ms: u64, - epoch_duration_ms: u64, - - stake_subsidy_start_epoch: u64, - stake_subsidy_initial_distribution_amount: u64, - stake_subsidy_period_length: u64, - stake_subsidy_decrease_rate: u16, - - max_validator_count: u64, - min_validator_joining_stake: u64, - validator_low_stake_threshold: u64, - validator_very_low_stake_threshold: u64, - validator_low_stake_grace_period: u64, - } - - struct TokenDistributionSchedule has drop { - stake_subsidy_fund_mist: u64, - allocations: vector, - } - - struct TokenAllocation has drop { - recipient_address: address, - amount_mist: u64, - staked_with_validator: Option
    , - } - - fun create( - sui_system_state_id: UID, - sui_supply: Balance, - genesis_chain_parameters: GenesisChainParameters, - genesis_validators: vector, - _token_distribution_schedule: TokenDistributionSchedule, - ctx: &mut TxContext, - ) { - assert!(tx_context::epoch(ctx) == 0, 0); - - let validators = vector::empty(); - let count = vector::length(&genesis_validators); - let i = 0; - while (i < count) { - let GenesisValidatorMetadata { - name: _, - description: _, - image_url: _, - project_url: _, - sui_address, - gas_price: _, - commission_rate: _, - protocol_public_key, - proof_of_possession: _, - network_public_key, - worker_public_key, - network_address, - p2p_address, - primary_address, - worker_address, - } = *vector::borrow(&genesis_validators, i); - - let validator = validator::new( - sui_address, - protocol_public_key, - network_public_key, - worker_public_key, - network_address, - p2p_address, - primary_address, - worker_address, - balance::split(&mut sui_supply, 2500), - ctx - ); - - vector::push_back(&mut validators, validator); - - i = i + 1; - }; - - sui_system::create( - sui_system_state_id, - validators, - sui_supply, // storage_fund - genesis_chain_parameters.protocol_version, - genesis_chain_parameters.chain_start_timestamp_ms, - genesis_chain_parameters.epoch_duration_ms, - ctx, - ); - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/sui_system.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/sui_system.move deleted file mode 100644 index 4c7662d80fc..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/sui_system.move +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::sui_system { - use sui::balance::Balance; - use sui::object::UID; - use sui::sui::SUI; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; - use sui::dynamic_field; - - use sui_system::validator::Validator; - use sui_system::sui_system_state_inner::SuiSystemStateInner; - use sui_system::sui_system_state_inner; - - friend sui_system::genesis; - - struct SuiSystemState has key { - id: UID, - version: u64, - } - - public(friend) fun create( - id: UID, - validators: vector, - storage_fund: Balance, - protocol_version: u64, - epoch_start_timestamp_ms: u64, - epoch_duration_ms: u64, - ctx: &mut TxContext, - ) { - let system_state = sui_system_state_inner::create( - validators, - storage_fund, - protocol_version, - epoch_start_timestamp_ms, - epoch_duration_ms, - ctx, - ); - let version = sui_system_state_inner::genesis_system_state_version(); - let self = SuiSystemState { - id, - version, - }; - dynamic_field::add(&mut self.id, version, system_state); - transfer::share_object(self); - } - - fun advance_epoch( - storage_reward: Balance, - computation_reward: Balance, - wrapper: &mut SuiSystemState, - _new_epoch: u64, - _next_protocol_version: u64, - storage_rebate: u64, - _non_refundable_storage_fee: u64, - _storage_fund_reinvest_rate: u64, - _reward_slashing_rate: u64, - _epoch_start_timestamp_ms: u64, - ctx: &mut TxContext, - ) : Balance { - let self = load_system_state_mut(wrapper); - assert!(tx_context::sender(ctx) == @0x1, 0); // aborts here - sui_system_state_inner::advance_epoch( - self, - storage_reward, - computation_reward, - storage_rebate, - ) - } - - fun load_system_state_mut(self: &mut SuiSystemState): &mut SuiSystemStateInner { - let version = self.version; - dynamic_field::borrow_mut(&mut self.id, version) - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/sui_system_state_inner.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/sui_system_state_inner.move deleted file mode 100644 index 3e9bcad4a7b..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/sui_system_state_inner.move +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::sui_system_state_inner { - use sui::balance::{Self, Balance}; - use sui::sui::SUI; - use sui::tx_context::TxContext; - use sui::bag::{Self, Bag}; - use sui::table::{Self, Table}; - use sui::object::ID; - - use sui_system::validator::Validator; - use sui_system::validator_wrapper::ValidatorWrapper; - - friend sui_system::sui_system; - - const SYSTEM_STATE_VERSION_V1: u64 = 18446744073709551605; // u64::MAX - 10 - - struct SystemParameters has store { - epoch_duration_ms: u64, - extra_fields: Bag, - } - - struct ValidatorSet has store { - active_validators: vector, - inactive_validators: Table, - extra_fields: Bag, - } - - struct SuiSystemStateInner has store { - epoch: u64, - protocol_version: u64, - system_state_version: u64, - validators: ValidatorSet, - storage_fund: Balance, - parameters: SystemParameters, - reference_gas_price: u64, - safe_mode: bool, - epoch_start_timestamp_ms: u64, - extra_fields: Bag, - } - - public(friend) fun create( - validators: vector, - storage_fund: Balance, - protocol_version: u64, - epoch_start_timestamp_ms: u64, - epoch_duration_ms: u64, - ctx: &mut TxContext, - ): SuiSystemStateInner { - let system_state = SuiSystemStateInner { - epoch: 0, - protocol_version, - system_state_version: genesis_system_state_version(), - validators: ValidatorSet { - active_validators: validators, - inactive_validators: table::new(ctx), - extra_fields: bag::new(ctx), - }, - storage_fund, - parameters: SystemParameters { - epoch_duration_ms, - extra_fields: bag::new(ctx), - }, - reference_gas_price: 1, - safe_mode: false, - epoch_start_timestamp_ms, - extra_fields: bag::new(ctx), - }; - system_state - } - - public(friend) fun advance_epoch( - self: &mut SuiSystemStateInner, - storage_reward: Balance, - computation_reward: Balance, - storage_rebate_amount: u64, - ) : Balance { - balance::join(&mut self.storage_fund, computation_reward); - balance::join(&mut self.storage_fund, storage_reward); - let storage_rebate = balance::split(&mut self.storage_fund, storage_rebate_amount); - storage_rebate - } - - public(friend) fun genesis_system_state_version(): u64 { - SYSTEM_STATE_VERSION_V1 - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/validator.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/validator.move deleted file mode 100644 index d52ca818f80..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/validator.move +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::validator { - use std::ascii; - - use sui::tx_context::TxContext; - use std::string::{Self, String}; - use sui::bag::{Self, Bag}; - use sui::balance::{Self, Balance}; - use sui::sui::SUI; - - friend sui_system::genesis; - friend sui_system::sui_system_state_inner; - friend sui_system::validator_wrapper; - - struct ValidatorMetadata has store { - sui_address: address, - protocol_pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - net_address: String, - p2p_address: String, - primary_address: String, - worker_address: String, - extra_fields: Bag, - } - - struct Validator has store { - metadata: ValidatorMetadata, - voting_power: u64, - stake: Balance, - extra_fields: Bag, - } - - public(friend) fun new( - sui_address: address, - protocol_pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - net_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - init_stake: Balance, - ctx: &mut TxContext - ): Validator { - let metadata = ValidatorMetadata { - sui_address, - protocol_pubkey_bytes, - network_pubkey_bytes, - worker_pubkey_bytes, - net_address: string::from_ascii(ascii::string(net_address)), - p2p_address: string::from_ascii(ascii::string(p2p_address)), - primary_address: string::from_ascii(ascii::string(primary_address)), - worker_address: string::from_ascii(ascii::string(worker_address)), - extra_fields: bag::new(ctx), - }; - - Validator { - metadata, - voting_power: balance::value(&init_stake), - stake: init_stake, - extra_fields: bag::new(ctx), - } - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/validator_wrapper.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/validator_wrapper.move deleted file mode 100644 index 544048f6ca8..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/safe_mode/sources/validator_wrapper.move +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::validator_wrapper { - use sui::versioned::Versioned; - - friend sui_system::sui_system_state_inner; - - struct ValidatorWrapper has store { - inner: Versioned - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/Move.toml b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/Move.toml deleted file mode 100644 index fe9b71b6c24..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "SuiSystemShallowUpgrade" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../../sui-framework/packages/sui-framework" } -MoveStdlib = { local = "../../../../../sui-framework/packages/move-stdlib" } - -[addresses] -sui_system = "0x3" diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/genesis.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/genesis.move deleted file mode 100644 index bf640c93d4d..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/genesis.move +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::genesis { - use std::vector; - use sui::balance::{Self, Balance}; - use sui::object::UID; - use sui::sui::SUI; - use sui::tx_context::{Self, TxContext}; - use std::option::Option; - - use sui_system::sui_system; - use sui_system::validator; - - struct GenesisValidatorMetadata has drop, copy { - name: vector, - description: vector, - image_url: vector, - project_url: vector, - - sui_address: address, - - gas_price: u64, - commission_rate: u64, - - protocol_public_key: vector, - proof_of_possession: vector, - - network_public_key: vector, - worker_public_key: vector, - - network_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - } - - struct GenesisChainParameters has drop, copy { - protocol_version: u64, - chain_start_timestamp_ms: u64, - epoch_duration_ms: u64, - - stake_subsidy_start_epoch: u64, - stake_subsidy_initial_distribution_amount: u64, - stake_subsidy_period_length: u64, - stake_subsidy_decrease_rate: u16, - - max_validator_count: u64, - min_validator_joining_stake: u64, - validator_low_stake_threshold: u64, - validator_very_low_stake_threshold: u64, - validator_low_stake_grace_period: u64, - } - - struct TokenDistributionSchedule has drop { - stake_subsidy_fund_mist: u64, - allocations: vector, - } - - struct TokenAllocation has drop { - recipient_address: address, - amount_mist: u64, - staked_with_validator: Option
    , - } - - fun create( - sui_system_state_id: UID, - sui_supply: Balance, - genesis_chain_parameters: GenesisChainParameters, - genesis_validators: vector, - _token_distribution_schedule: TokenDistributionSchedule, - ctx: &mut TxContext, - ) { - assert!(tx_context::epoch(ctx) == 0, 0); - - let validators = vector::empty(); - let count = vector::length(&genesis_validators); - let i = 0; - while (i < count) { - let GenesisValidatorMetadata { - name: _, - description: _, - image_url: _, - project_url: _, - sui_address, - gas_price: _, - commission_rate: _, - protocol_public_key, - proof_of_possession: _, - network_public_key, - worker_public_key, - network_address, - p2p_address, - primary_address, - worker_address, - } = *vector::borrow(&genesis_validators, i); - - let validator = validator::new( - sui_address, - protocol_public_key, - network_public_key, - worker_public_key, - network_address, - p2p_address, - primary_address, - worker_address, - balance::split(&mut sui_supply, 2500), - ctx - ); - - vector::push_back(&mut validators, validator); - - i = i + 1; - }; - - sui_system::create( - sui_system_state_id, - validators, - sui_supply, // storage_fund - genesis_chain_parameters.protocol_version, - genesis_chain_parameters.chain_start_timestamp_ms, - genesis_chain_parameters.epoch_duration_ms, - ctx, - ); - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/sui_system.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/sui_system.move deleted file mode 100644 index ab61237102d..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/sui_system.move +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::sui_system { - use sui::balance::Balance; - use sui::object::UID; - use sui::sui::SUI; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; - use sui::dynamic_field; - - use sui_system::validator::Validator; - use sui_system::sui_system_state_inner::{Self, SuiSystemStateInner, SuiSystemStateInnerV2}; - - friend sui_system::genesis; - - struct SuiSystemState has key { - id: UID, - version: u64, - } - - public(friend) fun create( - id: UID, - validators: vector, - storage_fund: Balance, - protocol_version: u64, - epoch_start_timestamp_ms: u64, - epoch_duration_ms: u64, - ctx: &mut TxContext, - ) { - let system_state = sui_system_state_inner::create( - validators, - storage_fund, - protocol_version, - epoch_start_timestamp_ms, - epoch_duration_ms, - ctx, - ); - let version = sui_system_state_inner::genesis_system_state_version(); - let self = SuiSystemState { - id, - version, - }; - dynamic_field::add(&mut self.id, version, system_state); - transfer::share_object(self); - } - - fun advance_epoch( - storage_reward: Balance, - computation_reward: Balance, - wrapper: &mut SuiSystemState, - new_epoch: u64, - next_protocol_version: u64, - storage_rebate: u64, - _non_refundable_storage_fee: u64, - _storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested - // into storage fund, in basis point. - _reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. - epoch_start_timestamp_ms: u64, // Timestamp of the epoch start - ctx: &mut TxContext, - ) : Balance { - let self = load_system_state_mut(wrapper); - assert!(tx_context::sender(ctx) == @0x0, 0); - let storage_rebate = sui_system_state_inner::advance_epoch( - self, - new_epoch, - next_protocol_version, - storage_reward, - computation_reward, - storage_rebate, - epoch_start_timestamp_ms, - ); - - storage_rebate - } - - fun load_system_state_mut(self: &mut SuiSystemState): &mut SuiSystemStateInnerV2 { - load_inner_maybe_upgrade(self) - } - - fun load_inner_maybe_upgrade(self: &mut SuiSystemState): &mut SuiSystemStateInnerV2 { - let version = self.version; - if (version == sui_system_state_inner::genesis_system_state_version()) { - let inner: SuiSystemStateInner = dynamic_field::remove(&mut self.id, version); - let new_inner = sui_system_state_inner::v1_to_v2(inner); - version = sui_system_state_inner::system_state_version(&new_inner); - dynamic_field::add(&mut self.id, version, new_inner); - self.version = version; - }; - - let inner: &mut SuiSystemStateInnerV2 = dynamic_field::borrow_mut(&mut self.id, version); - assert!(sui_system_state_inner::system_state_version(inner) == version, 0); - inner - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/sui_system_state_inner.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/sui_system_state_inner.move deleted file mode 100644 index 2675588b0a2..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/sui_system_state_inner.move +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::sui_system_state_inner { - use sui::balance::{Self, Balance}; - use sui::sui::SUI; - use sui::tx_context::TxContext; - use sui::bag::{Self, Bag}; - use sui::table::{Self, Table}; - use sui::object::ID; - - use sui_system::validator::Validator; - use sui_system::validator_wrapper::ValidatorWrapper; - - friend sui_system::sui_system; - - const SYSTEM_STATE_VERSION_V1: u64 = 18446744073709551605; // u64::MAX - 10 - const SYSTEM_STATE_VERSION_V2: u64 = 18446744073709551606; // u64::MAX - 9 - - struct SystemParameters has store { - epoch_duration_ms: u64, - extra_fields: Bag, - } - - struct ValidatorSet has store { - active_validators: vector, - inactive_validators: Table, - extra_fields: Bag, - } - - struct SuiSystemStateInner has store { - epoch: u64, - protocol_version: u64, - system_state_version: u64, - validators: ValidatorSet, - storage_fund: Balance, - parameters: SystemParameters, - reference_gas_price: u64, - safe_mode: bool, - epoch_start_timestamp_ms: u64, - extra_fields: Bag, - } - - struct SuiSystemStateInnerV2 has store { - new_dummy_field: u64, - epoch: u64, - protocol_version: u64, - system_state_version: u64, - validators: ValidatorSet, - storage_fund: Balance, - parameters: SystemParameters, - reference_gas_price: u64, - safe_mode: bool, - epoch_start_timestamp_ms: u64, - extra_fields: Bag, - } - - public(friend) fun create( - validators: vector, - storage_fund: Balance, - protocol_version: u64, - epoch_start_timestamp_ms: u64, - epoch_duration_ms: u64, - ctx: &mut TxContext, - ): SuiSystemStateInner { - let validators = new_validator_set(validators, ctx); - let system_state = SuiSystemStateInner { - epoch: 0, - protocol_version, - system_state_version: genesis_system_state_version(), - validators, - storage_fund, - parameters: SystemParameters { - epoch_duration_ms, - extra_fields: bag::new(ctx), - }, - reference_gas_price: 1, - safe_mode: false, - epoch_start_timestamp_ms, - extra_fields: bag::new(ctx), - }; - system_state - } - - public(friend) fun advance_epoch( - self: &mut SuiSystemStateInnerV2, - new_epoch: u64, - next_protocol_version: u64, - storage_reward: Balance, - computation_reward: Balance, - storage_rebate_amount: u64, - epoch_start_timestamp_ms: u64, - ) : Balance { - self.epoch_start_timestamp_ms = epoch_start_timestamp_ms; - self.epoch = self.epoch + 1; - assert!(new_epoch == self.epoch, 0); - self.safe_mode = false; - self.protocol_version = next_protocol_version; - - balance::join(&mut self.storage_fund, computation_reward); - balance::join(&mut self.storage_fund, storage_reward); - let storage_rebate = balance::split(&mut self.storage_fund, storage_rebate_amount); - storage_rebate - } - - public(friend) fun protocol_version(self: &SuiSystemStateInnerV2): u64 { self.protocol_version } - public(friend) fun system_state_version(self: &SuiSystemStateInnerV2): u64 { self.system_state_version } - public(friend) fun genesis_system_state_version(): u64 { - SYSTEM_STATE_VERSION_V1 - } - - fun new_validator_set(init_active_validators: vector, ctx: &mut TxContext): ValidatorSet { - ValidatorSet { - active_validators: init_active_validators, - inactive_validators: table::new(ctx), - extra_fields: bag::new(ctx), - } - } - - public(friend) fun v1_to_v2(v1: SuiSystemStateInner): SuiSystemStateInnerV2 { - let SuiSystemStateInner { - epoch, - protocol_version, - system_state_version: old_system_state_version, - validators, - storage_fund, - parameters, - reference_gas_price, - safe_mode, - epoch_start_timestamp_ms, - extra_fields, - } = v1; - assert!(old_system_state_version == SYSTEM_STATE_VERSION_V1, 0); - SuiSystemStateInnerV2 { - new_dummy_field: 100, - epoch, - protocol_version, - system_state_version: SYSTEM_STATE_VERSION_V2, - validators, - storage_fund, - parameters, - reference_gas_price, - safe_mode, - epoch_start_timestamp_ms, - extra_fields, - } - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/validator.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/validator.move deleted file mode 100644 index d52ca818f80..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/validator.move +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::validator { - use std::ascii; - - use sui::tx_context::TxContext; - use std::string::{Self, String}; - use sui::bag::{Self, Bag}; - use sui::balance::{Self, Balance}; - use sui::sui::SUI; - - friend sui_system::genesis; - friend sui_system::sui_system_state_inner; - friend sui_system::validator_wrapper; - - struct ValidatorMetadata has store { - sui_address: address, - protocol_pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - net_address: String, - p2p_address: String, - primary_address: String, - worker_address: String, - extra_fields: Bag, - } - - struct Validator has store { - metadata: ValidatorMetadata, - voting_power: u64, - stake: Balance, - extra_fields: Bag, - } - - public(friend) fun new( - sui_address: address, - protocol_pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - net_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - init_stake: Balance, - ctx: &mut TxContext - ): Validator { - let metadata = ValidatorMetadata { - sui_address, - protocol_pubkey_bytes, - network_pubkey_bytes, - worker_pubkey_bytes, - net_address: string::from_ascii(ascii::string(net_address)), - p2p_address: string::from_ascii(ascii::string(p2p_address)), - primary_address: string::from_ascii(ascii::string(primary_address)), - worker_address: string::from_ascii(ascii::string(worker_address)), - extra_fields: bag::new(ctx), - }; - - Validator { - metadata, - voting_power: balance::value(&init_stake), - stake: init_stake, - extra_fields: bag::new(ctx), - } - } -} diff --git a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/validator_wrapper.move b/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/validator_wrapper.move deleted file mode 100644 index 3dea3ac9750..00000000000 --- a/crates/sui-e2e-tests/tests/framework_upgrades/mock_sui_systems/shallow_upgrade/sources/validator_wrapper.move +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::validator_wrapper { - use sui::versioned::Versioned; - use sui::versioned; - use sui::tx_context::TxContext; - use sui_system::validator::Validator; - - friend sui_system::sui_system; - friend sui_system::sui_system_state_inner; - - const EInvalidVersion: u64 = 0; - - struct ValidatorWrapper has store { - inner: Versioned - } - - // Validator corresponds to version 1. - public(friend) fun create_v1(validator: Validator, ctx: &mut TxContext): ValidatorWrapper { - ValidatorWrapper { - inner: versioned::create(1, validator, ctx) - } - } - - /// This function should always return the latest supported version. - /// If the inner version is old, we upgrade it lazily in-place. - public(friend) fun load_validator_maybe_upgrade(self: &mut ValidatorWrapper): &mut Validator { - upgrade_to_latest(self); - versioned::load_value_mut(&mut self.inner) - } - - /// Destroy the wrapper and retrieve the inner validator object. - public(friend) fun destroy(self: ValidatorWrapper): Validator { - upgrade_to_latest(&mut self); - let ValidatorWrapper { inner } = self; - versioned::destroy(inner) - } - - fun upgrade_to_latest(self: &mut ValidatorWrapper) { - let version = version(self); - // TODO: When new versions are added, we need to explicitly upgrade here. - assert!(version == 1, EInvalidVersion); - } - - fun version(self: &ValidatorWrapper): u64 { - versioned::version(&self.inner) - } -} diff --git a/crates/sui-e2e-tests/tests/move_test_code/Move.toml b/crates/sui-e2e-tests/tests/move_test_code/Move.toml deleted file mode 100644 index ed02bdd787c..00000000000 --- a/crates/sui-e2e-tests/tests/move_test_code/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "move_test_code" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../sui-framework/packages/sui-framework" } - -[addresses] -move_test_code = "0x0" diff --git a/crates/sui-e2e-tests/tests/move_test_code/sources/regulated_coin.move b/crates/sui-e2e-tests/tests/move_test_code/sources/regulated_coin.move deleted file mode 100644 index fcb09c5529b..00000000000 --- a/crates/sui-e2e-tests/tests/move_test_code/sources/regulated_coin.move +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module move_test_code::regulated_coin { - use std::option; - use sui::coin; - use sui::object::UID; - use sui::transfer; - use sui::tx_context; - use sui::tx_context::TxContext; - - struct REGULATED_COIN has drop {} - - struct Wallet has key { - id: UID, - } - - fun init(otw: REGULATED_COIN, ctx: &mut TxContext) { - let (treasury_cap, deny_cap, metadata) = coin::create_regulated_currency( - otw, - 9, - b"RC", - b"REGULATED_COIN", - b"A new regulated coin", - option::none(), - ctx - ); - transfer::public_transfer(deny_cap, tx_context::sender(ctx)); - transfer::public_freeze_object(treasury_cap); - transfer::public_freeze_object(metadata); - } -} diff --git a/crates/sui-e2e-tests/tests/move_test_code/sources/tto1.move b/crates/sui-e2e-tests/tests/move_test_code/sources/tto1.move deleted file mode 100644 index a001fe10a06..00000000000 --- a/crates/sui-e2e-tests/tests/move_test_code/sources/tto1.move +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module move_test_code::tto { - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer::{Self, Receiving}; - - struct A has key, store { - id: UID, - } - - struct B has key, store { - id: UID, - } - - public fun start(ctx: &mut TxContext) { - let a = A { id: object::new(ctx) }; - let a_address = object::id_address(&a); - let b = B { id: object::new(ctx) }; - let c = B { id: object::new(ctx) }; - transfer::share_object(c); - transfer::public_transfer(a, tx_context::sender(ctx)); - transfer::public_transfer(b, a_address); - } - - public entry fun receiver(parent: &mut A, x: Receiving) { - let b = transfer::receive(&mut parent.id, x); - // transfer back to the parent so we can reuse - transfer::public_transfer(b, object::id_address(parent)); - } - - public entry fun deleter(parent: &mut A, x: Receiving) { - let B { id } = transfer::receive(&mut parent.id, x); - object::delete(id); - } -} diff --git a/crates/sui-e2e-tests/tests/multisig_tests.rs b/crates/sui-e2e-tests/tests/multisig_tests.rs deleted file mode 100644 index 0f7ed9c7c77..00000000000 --- a/crates/sui-e2e-tests/tests/multisig_tests.rs +++ /dev/null @@ -1,818 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use fastcrypto::traits::EncodeDecodeBase64; -use shared_crypto::intent::{Intent, IntentMessage}; -use sui_core::authority_client::AuthorityAPI; -use sui_macros::sim_test; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ - base_types::SuiAddress, - crypto::{ - get_key_pair, CompressedSignature, PublicKey, Signature, SuiKeyPair, - ZkLoginAuthenticatorAsBytes, ZkLoginPublicIdentifier, - }, - error::{SuiError, SuiResult}, - multisig::{MultiSig, MultiSigPublicKey}, - multisig_legacy::MultiSigPublicKeyLegacy, - signature::GenericSignature, - transaction::Transaction, - utils::{keys, load_test_vectors, make_upgraded_multisig_tx}, - zk_login_authenticator::ZkLoginAuthenticator, -}; -use test_cluster::{TestCluster, TestClusterBuilder}; -async fn do_upgraded_multisig_test() -> SuiResult { - let test_cluster = TestClusterBuilder::new().build().await; - let tx = make_upgraded_multisig_tx(); - - test_cluster - .authority_aggregator() - .authority_clients - .values() - .next() - .unwrap() - .authority_client() - .handle_transaction(tx) - .await - .map(|_| ()) -} - -#[sim_test] -async fn test_upgraded_multisig_feature_deny() { - use sui_protocol_config::ProtocolConfig; - - let _guard = ProtocolConfig::apply_overrides_for_testing(|_, mut config| { - config.set_upgraded_multisig_for_testing(false); - config - }); - - let err = do_upgraded_multisig_test().await.unwrap_err(); - - assert!(matches!(err, SuiError::UnsupportedFeatureError { .. })); -} - -#[sim_test] -async fn test_upgraded_multisig_feature_allow() { - use sui_protocol_config::ProtocolConfig; - - let _guard = ProtocolConfig::apply_overrides_for_testing(|_, mut config| { - config.set_upgraded_multisig_for_testing(true); - config - }); - - let res = do_upgraded_multisig_test().await; - - // we didn't make a real transaction with a valid object, but we verify that we - // pass the feature gate. - assert!(matches!(res.unwrap_err(), SuiError::UserInputError { .. })); -} - -#[sim_test] -async fn test_multisig_e2e() { - let test_cluster = TestClusterBuilder::new().build().await; - let context = &test_cluster.wallet; - let rgp = test_cluster.get_reference_gas_price().await; - - let keys = keys(); - let pk0 = keys[0].public(); // ed25519 - let pk1 = keys[1].public(); // secp256k1 - let pk2 = keys[2].public(); // secp256r1 - - let multisig_pk = MultiSigPublicKey::insecure_new( - vec![(pk0.clone(), 1), (pk1.clone(), 1), (pk2.clone(), 1)], - 2, - ); - let multisig_addr = SuiAddress::from(&multisig_pk); - - // fund wallet and get a gas object to use later. - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) - .await; - - // 1. sign with key 0 and 1 executes successfully. - let tx1 = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build_and_sign_multisig(multisig_pk.clone(), &[&keys[0], &keys[1]], 0b011); - let res = context.execute_transaction_must_succeed(tx1).await; - assert!(res.status_ok().unwrap()); - - // 2. sign with key 1 and 2 executes successfully. - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) - .await; - let tx2 = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build_and_sign_multisig(multisig_pk.clone(), &[&keys[1], &keys[2]], 0b110); - let res = context.execute_transaction_must_succeed(tx2).await; - assert!(res.status_ok().unwrap()); - - // 3. signature 2 and 1 swapped fails to execute. - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) - .await; - let tx3 = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build_and_sign_multisig(multisig_pk.clone(), &[&keys[2], &keys[1]], 0b110); - let res = context.execute_transaction_may_fail(tx3).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Invalid sig for pk=AQIOF81ZOeRrGWZBlozXWZELold+J/pz/eOHbbm+xbzrKw==") - ); - - // 4. sign with key 0 only is below threshold, fails to execute. - let tx4 = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build_and_sign_multisig(multisig_pk.clone(), &[&keys[0]], 0b001); - let res = context.execute_transaction_may_fail(tx4).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Insufficient weight=1 threshold=2") - ); - - // 5. multisig with no single sig fails to execute. - let tx5 = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build_and_sign_multisig(multisig_pk.clone(), &[], 0b001); - let res = context.execute_transaction_may_fail(tx5).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Invalid value was given to the function") - ); - - // 6. multisig two dup sigs fails to execute. - let tx6 = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build_and_sign_multisig(multisig_pk.clone(), &[&keys[0], &keys[0]], 0b011); - let res = context.execute_transaction_may_fail(tx6).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Invalid ed25519 pk bytes") - ); - - // 7. mismatch pks in sig with multisig address fails to execute. - let kp3: SuiKeyPair = SuiKeyPair::Secp256r1(get_key_pair().1); - let pk3 = kp3.public(); - let wrong_multisig_pk = MultiSigPublicKey::new( - vec![pk0.clone(), pk1.clone(), pk3.clone()], - vec![1, 1, 1], - 2, - ) - .unwrap(); - let wrong_sender = SuiAddress::from(&wrong_multisig_pk); - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), wrong_sender) - .await; - let tx7 = TestTransactionBuilder::new(wrong_sender, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build_and_sign_multisig(wrong_multisig_pk.clone(), &[&keys[0], &keys[2]], 0b101); - let res = context.execute_transaction_may_fail(tx7).await; - assert!( - res.unwrap_err() - .to_string() - .contains(format!("Invalid sig for pk={}", pk3.encode_base64()).as_str()) - ); -} - -#[sim_test] -async fn test_multisig_with_zklogin_scenerios() { - let test_cluster = TestClusterBuilder::new() - .with_epoch_duration_ms(15000) - .with_default_jwks() - .build() - .await; - - test_cluster.wait_for_epoch(Some(1)).await; - - let rgp = test_cluster.get_reference_gas_price().await; - let context = &test_cluster.wallet; - - let keys = keys(); - let pk0 = keys[0].public(); // ed25519 - let pk1 = keys[1].public(); // secp256k1 - let pk2 = keys[2].public(); // secp256r1 - - // construct a multisig address with 4 pks (ed25519, secp256k1, secp256r1, - // zklogin) with threshold = 1. - let (eph_kp, _eph_pk, zklogin_inputs) = - &load_test_vectors("../sui-types/src/unit_tests/zklogin_test_vectors.json")[1]; - let (eph_kp_1, _, _) = - &load_test_vectors("../sui-types/src/unit_tests/zklogin_test_vectors.json")[2]; - let zklogin_pk = PublicKey::ZkLogin( - ZkLoginPublicIdentifier::new(zklogin_inputs.get_iss(), zklogin_inputs.get_address_seed()) - .unwrap(), - ); - let multisig_pk = MultiSigPublicKey::new( - vec![pk0.clone(), pk1.clone(), pk2.clone(), zklogin_pk.clone()], - vec![1, 1, 1, 1], - 1, - ) - .unwrap(); - - // fund the multisig address. - let multisig_addr = SuiAddress::from(&multisig_pk); - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) - .await; - let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let wrong_intent_msg = IntentMessage::new(Intent::personal_message(), tx_data.clone()); - - // 1. a multisig with a bad ed25519 sig fails to execute. - let wrong_sig: GenericSignature = Signature::new_secure(&wrong_intent_msg, &keys[0]).into(); - let multisig = GenericSignature::MultiSig( - MultiSig::combine(vec![wrong_sig], multisig_pk.clone()).unwrap(), - ); - let tx_1 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_1).await; - assert!( - res.unwrap_err() - .to_string() - .contains(format!("Invalid sig for pk={}", pk0.encode_base64()).as_str()) - ); - - // 2. a multisig with a bad secp256k1 sig fails to execute. - let wrong_sig_2: GenericSignature = Signature::new_secure(&wrong_intent_msg, &keys[1]).into(); - let multisig = GenericSignature::MultiSig( - MultiSig::combine(vec![wrong_sig_2], multisig_pk.clone()).unwrap(), - ); - let tx_2 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_2).await; - assert!( - res.unwrap_err() - .to_string() - .contains(format!("Invalid sig for pk={}", pk1.encode_base64()).as_str()) - ); - - // 3. a multisig with a bad secp256r1 sig fails to execute. - let wrong_sig_3: GenericSignature = Signature::new_secure(&wrong_intent_msg, &keys[2]).into(); - let multisig = GenericSignature::MultiSig( - MultiSig::combine(vec![wrong_sig_3], multisig_pk.clone()).unwrap(), - ); - let tx_3 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_3).await; - assert!( - res.unwrap_err() - .to_string() - .contains(format!("Invalid sig for pk={}", pk2.encode_base64()).as_str()) - ); - - // 4. a multisig with a bad ephemeral sig inside zklogin sig fails to execute. - let wrong_eph_sig = Signature::new_secure(&wrong_intent_msg, eph_kp); - let wrong_zklogin_sig = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( - zklogin_inputs.clone(), - 2, - wrong_eph_sig, - )); - let multisig = GenericSignature::MultiSig( - MultiSig::combine(vec![wrong_zklogin_sig], multisig_pk.clone()).unwrap(), - ); - let tx_4 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_4).await; - let pk3 = PublicKey::ZkLogin( - ZkLoginPublicIdentifier::new(zklogin_inputs.get_iss(), zklogin_inputs.get_address_seed()) - .unwrap(), - ); - assert!( - res.unwrap_err() - .to_string() - .contains(format!("Invalid sig for pk={}", pk3.encode_base64()).as_str()) - ); - - // 5. a multisig with a mismatch ephermeal sig and zklogin inputs fails to - // execute. - let eph_sig = Signature::new_secure(&intent_msg, eph_kp_1); - let zklogin_sig_mismatch = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( - zklogin_inputs.clone(), - 2, - eph_sig, - )); - let multisig = GenericSignature::MultiSig( - MultiSig::combine(vec![zklogin_sig_mismatch], multisig_pk.clone()).unwrap(), - ); - let tx_5 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_5).await; - assert!( - res.unwrap_err() - .to_string() - .contains(format!("Invalid sig for pk={}", pk3.encode_base64()).as_str()) - ); - - // 6. a multisig with an inconsistent max_epoch with zk proof itself fails to - // execute. - let eph_sig = Signature::new_secure(&intent_msg, eph_kp); - let zklogin_sig_wrong_zklogin_inputs = GenericSignature::ZkLoginAuthenticator( - ZkLoginAuthenticator::new(zklogin_inputs.clone(), 1, eph_sig), /* max_epoch set to 1 - * instead of 2 */ - ); - let multisig = GenericSignature::MultiSig( - MultiSig::combine(vec![zklogin_sig_wrong_zklogin_inputs], multisig_pk.clone()).unwrap(), - ); - let tx_7 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_7).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Groth16 proof verify failed") - ); - - // 7. a multisig with the wrong sender fails to execute. - let wrong_multisig_addr = SuiAddress::from( - &MultiSigPublicKey::new( - vec![pk0.clone(), pk1.clone(), pk2.clone()], - vec![1, 1, 1], - 1, - ) - .unwrap(), - ); - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), wrong_multisig_addr) - .await; - let tx_data = TestTransactionBuilder::new(wrong_multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let sig_4: GenericSignature = ZkLoginAuthenticator::new( - zklogin_inputs.clone(), - 2, - Signature::new_secure(&intent_msg, eph_kp), - ) - .into(); - let multisig = - GenericSignature::MultiSig(MultiSig::combine(vec![sig_4], multisig_pk.clone()).unwrap()); - let tx_8 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_8).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Required Signature from") - ); - - // 8. a multisig with zklogin sig of invalid compact signature bytes fails to - // execute. - let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( - vec![CompressedSignature::ZkLogin(ZkLoginAuthenticatorAsBytes( - vec![0], - ))], - 0b1000, - multisig_pk.clone(), - )); - let tx_7 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_7).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Invalid zklogin authenticator bytes") - ); - - // assert positive case for all 4 participanting parties. - // 1a. good ed25519 sig used in multisig executes successfully. - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) - .await; - let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let sig_0: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); - let multisig = - GenericSignature::MultiSig(MultiSig::combine(vec![sig_0], multisig_pk.clone()).unwrap()); - let tx_8 = Transaction::from_generic_sig_data(tx_data, vec![multisig]); - let _ = context.execute_transaction_must_succeed(tx_8).await; - - // 2a. good secp256k1 sig used in multisig executes successfully. - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) - .await; - let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let sig_1: GenericSignature = Signature::new_secure(&intent_msg, &keys[1]).into(); - let multisig = - GenericSignature::MultiSig(MultiSig::combine(vec![sig_1], multisig_pk.clone()).unwrap()); - let tx_9 = Transaction::from_generic_sig_data(tx_data, vec![multisig]); - let _ = context.execute_transaction_must_succeed(tx_9).await; - - // 3a. good secp256r1 sig used in multisig executes successfully. - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) - .await; - let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let sig_2: GenericSignature = Signature::new_secure(&intent_msg, &keys[2]).into(); - let multisig = - GenericSignature::MultiSig(MultiSig::combine(vec![sig_2], multisig_pk.clone()).unwrap()); - let tx_9 = Transaction::from_generic_sig_data(tx_data, vec![multisig]); - let _ = context.execute_transaction_must_succeed(tx_9).await; - - // 4b. good zklogin sig used in multisig executes successfully. - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) - .await; - let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let sig_4: GenericSignature = ZkLoginAuthenticator::new( - zklogin_inputs.clone(), - 2, - Signature::new_secure(&intent_msg, eph_kp), - ) - .into(); - let multisig = - GenericSignature::MultiSig(MultiSig::combine(vec![sig_4], multisig_pk.clone()).unwrap()); - let tx_10 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let _ = context.execute_transaction_must_succeed(tx_10).await; - - // 4c. good zklogin sig AND good ed25519 combined used in multisig executes - // successfully. - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) - .await; - let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); - let sig_1: GenericSignature = ZkLoginAuthenticator::new( - zklogin_inputs.clone(), - 2, - Signature::new_secure(&intent_msg, eph_kp), - ) - .into(); - let multisig = GenericSignature::MultiSig( - MultiSig::combine(vec![sig, sig_1], multisig_pk.clone()).unwrap(), - ); - let tx_11 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let _ = context.execute_transaction_must_succeed(tx_11).await; - - // 9. wrong bitmap fails to execute. - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) - .await; - let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); - let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( - vec![sig.to_compressed().unwrap()], - 0b0010, - multisig_pk.clone(), - )); - let tx_11 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_11).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Invalid ed25519 pk bytes") - ); - - // 10. invalid bitmap b10000 when the max bitmap for 4 pks is b1111, fails to - // execute. - let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( - vec![sig.clone().to_compressed().unwrap()], - 1 << 4, - multisig_pk.clone(), - )); - let tx_10 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_10).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Invalid public keys index") - ); - - // 11. malformed multisig pk where threshold = 0, fails to execute. - let bad_multisig_pk = MultiSigPublicKey::insecure_new( - vec![(pk0.clone(), 1), (pk1.clone(), 1), (pk2.clone(), 1)], - 0, - ); - let bad_multisig_addr = SuiAddress::from(&bad_multisig_pk); - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), bad_multisig_addr) - .await; - let tx_data = TestTransactionBuilder::new(bad_multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); - let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( - vec![sig.to_compressed().unwrap()], - 0b001, - bad_multisig_pk.clone(), - )); - let tx_11 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_11).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Invalid value was given to the function") - ); - - // 12. malformed multisig a pk has weight = 0, fails to execute. - let bad_multisig_pk_2 = MultiSigPublicKey::insecure_new( - vec![(pk0.clone(), 1), (pk1.clone(), 1), (pk2.clone(), 0)], - 1, - ); - let bad_multisig_addr_2 = SuiAddress::from(&bad_multisig_pk_2); - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), bad_multisig_addr_2) - .await; - let tx_data = TestTransactionBuilder::new(bad_multisig_addr_2, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); - let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( - vec![sig.to_compressed().unwrap()], - 2, - bad_multisig_pk, - )); - let tx_14 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_14).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Invalid value was given to the function") - ); - - // 13. pass in 2 sigs when only 1 pk in multisig_pk, fails to execute. - let small_multisig_pk = MultiSigPublicKey::insecure_new(vec![(pk0.clone(), 1)], 1); - let bad_multisig_addr_3 = SuiAddress::from(&small_multisig_pk); - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), bad_multisig_addr_3) - .await; - let tx_data = TestTransactionBuilder::new(bad_multisig_addr_3, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); - let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( - vec![sig.to_compressed().unwrap(), sig.to_compressed().unwrap()], - 0b1, - small_multisig_pk, - )); - let tx_13 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_13).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Invalid value was given to the function") - ); - - // 14. pass a multisig where there is dup pk in multisig_pk, fails to execute. - let multisig_pk_with_dup = - MultiSigPublicKey::insecure_new(vec![(pk0.clone(), 1), (pk0.clone(), 1)], 1); - let bad_multisig_addr_4 = SuiAddress::from(&multisig_pk_with_dup); - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), bad_multisig_addr_4) - .await; - let tx_data = TestTransactionBuilder::new(bad_multisig_addr_4, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); - let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( - vec![sig.to_compressed().unwrap()], - 0b01, - multisig_pk_with_dup, - )); - let tx_14 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_14).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Invalid value was given to the function") - ); - - // 15. a sig with 11 pks fails to execute. - let multisig_pk_11 = MultiSigPublicKey::insecure_new(vec![(pk0.clone(), 1); 11], 1); - let bad_multisig_addr_11 = SuiAddress::from(&multisig_pk_11); - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), bad_multisig_addr_11) - .await; - let tx_data = TestTransactionBuilder::new(bad_multisig_addr_11, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); - let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( - vec![sig.to_compressed().unwrap()], - 0b00000000001, - multisig_pk_11, - )); - let tx_15 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_15).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Invalid value was given to the function") - ); - - // 16. total weight of all pks < threshold fails to execute. - let multisig_pk_12 = - MultiSigPublicKey::insecure_new(vec![(pk0.clone(), 1), (pk0.clone(), 1)], 3); - let bad_multisig_addr = SuiAddress::from(&multisig_pk_12); - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), bad_multisig_addr) - .await; - let tx_data = TestTransactionBuilder::new(bad_multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); - let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( - vec![sig.to_compressed().unwrap()], - 0b00000000001, - multisig_pk_12, - )); - let tx_16 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_16).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Invalid value was given to the function") - ); - - // 17. multisig with empty pk map fails to execute. - let bad_multisig_empty_pk = MultiSigPublicKey::insecure_new(vec![], 1); - let bad_multisig_addr = SuiAddress::from(&bad_multisig_empty_pk); - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), bad_multisig_addr) - .await; - let tx_data = TestTransactionBuilder::new(bad_multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let sig: GenericSignature = Signature::new_secure(&intent_msg, &keys[0]).into(); - let multisig = GenericSignature::MultiSig(MultiSig::insecure_new( - vec![sig.to_compressed().unwrap()], - 0b01, - bad_multisig_empty_pk, - )); - let tx_17 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_17).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Invalid value was given to the function") - ); -} - -#[sim_test] -async fn test_expired_epoch_zklogin_in_multisig() { - let test_cluster = TestClusterBuilder::new() - .with_epoch_duration_ms(10000) - .with_default_jwks() - .build() - .await; - test_cluster.wait_for_epoch(Some(3)).await; - let tx = construct_simple_zklogin_multisig_tx(&test_cluster).await; - let res = test_cluster.wallet.execute_transaction_may_fail(tx).await; - assert!( - res.unwrap_err() - .to_string() - .contains("ZKLogin expired at epoch 2") - ); -} - -#[sim_test] -async fn test_random_zklogin_in_multisig() { - let test_vectors = - &load_test_vectors("../sui-types/src/unit_tests/zklogin_test_vectors.json")[1..11]; - let test_cluster = TestClusterBuilder::new().with_default_jwks().build().await; - test_cluster.wait_for_authenticator_state_update().await; - let rgp = test_cluster.get_reference_gas_price().await; - let context = &test_cluster.wallet; - - // create a multisig with 10 zklogin pks. - let pks = test_vectors.iter().map(|(_, pk, _)| pk.clone()).collect(); - let multisig_pk = MultiSigPublicKey::new(pks, vec![1; 10], 10).unwrap(); - let multisig_addr = SuiAddress::from(&multisig_pk); - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) - .await; - let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let mut zklogin_sigs = vec![]; - for (kp, _pk, inputs) in test_vectors { - let eph_sig = Signature::new_secure(&intent_msg, kp); - let zklogin_sig = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( - inputs.clone(), - 2, - eph_sig, - )); - zklogin_sigs.push(zklogin_sig); - } - let short_multisig = GenericSignature::MultiSig( - MultiSig::combine(zklogin_sigs[..9].to_vec(), multisig_pk.clone()).unwrap(), - ); - let bad_tx = Transaction::from_generic_sig_data(tx_data.clone(), vec![short_multisig]); - let res = context.execute_transaction_may_fail(bad_tx).await; - assert!( - res.unwrap_err() - .to_string() - .contains("Insufficient weight=9 threshold=10") - ); - - let multisig = GenericSignature::MultiSig( - MultiSig::combine(zklogin_sigs.clone(), multisig_pk.clone()).unwrap(), - ); - let tx = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let _ = context.execute_transaction_must_succeed(tx).await; -} -#[sim_test] -async fn test_multisig_legacy_works() { - let test_cluster = TestClusterBuilder::new().build().await; - let rgp = test_cluster.get_reference_gas_price().await; - - let keys = keys(); - let pk1 = keys[0].public(); - let pk2 = keys[1].public(); - let pk3 = keys[2].public(); - - let multisig_pk_legacy = MultiSigPublicKeyLegacy::new( - vec![pk1.clone(), pk2.clone(), pk3.clone()], - vec![1, 1, 1], - 2, - ) - .unwrap(); - let multisig_pk = MultiSigPublicKey::new( - vec![pk1.clone(), pk2.clone(), pk3.clone()], - vec![1, 1, 1], - 2, - ) - .unwrap(); - let multisig_addr = SuiAddress::from(&multisig_pk); - let context = &test_cluster.wallet; - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) - .await; - let transfer_from_multisig = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(Some(1000000), SuiAddress::ZERO) - .build_and_sign_multisig_legacy(multisig_pk_legacy, &[&keys[0], &keys[1]]); - - context - .execute_transaction_must_succeed(transfer_from_multisig) - .await; -} - -#[sim_test] -async fn test_zklogin_inside_multisig_feature_deny() { - use sui_protocol_config::ProtocolConfig; - - // if feature disabled, fails to execute. - let _guard = ProtocolConfig::apply_overrides_for_testing(|_, mut config| { - config.set_accept_zklogin_in_multisig_for_testing(false); - config - }); - let test_cluster = TestClusterBuilder::new().with_default_jwks().build().await; - test_cluster.wait_for_authenticator_state_update().await; - let tx = construct_simple_zklogin_multisig_tx(&test_cluster).await; - let res = test_cluster.wallet.execute_transaction_may_fail(tx).await; - assert!( - res.unwrap_err() - .to_string() - .contains("zkLogin sig not supported inside multisig") - ); -} - -async fn construct_simple_zklogin_multisig_tx(test_cluster: &TestCluster) -> Transaction { - // construct a multisig address with 1 zklogin pk with threshold = 1. - let (eph_kp, _eph_pk, zklogin_inputs) = - &load_test_vectors("../sui-types/src/unit_tests/zklogin_test_vectors.json")[1]; - let zklogin_pk = PublicKey::ZkLogin( - ZkLoginPublicIdentifier::new(zklogin_inputs.get_iss(), zklogin_inputs.get_address_seed()) - .unwrap(), - ); - let multisig_pk = MultiSigPublicKey::insecure_new(vec![(zklogin_pk.clone(), 1)], 1); - let rgp = test_cluster.get_reference_gas_price().await; - - let multisig_addr = SuiAddress::from(&multisig_pk); - let gas = test_cluster - .fund_address_and_return_gas(rgp, Some(20000000000), multisig_addr) - .await; - let tx_data = TestTransactionBuilder::new(multisig_addr, gas, rgp) - .transfer_sui(None, SuiAddress::ZERO) - .build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data.clone()); - let sig_4: GenericSignature = ZkLoginAuthenticator::new( - zklogin_inputs.clone(), - 2, - Signature::new_secure(&intent_msg, eph_kp), - ) - .into(); - let multisig = - GenericSignature::MultiSig(MultiSig::combine(vec![sig_4], multisig_pk.clone()).unwrap()); - Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]) -} diff --git a/crates/sui-e2e-tests/tests/snapshot_tests.rs b/crates/sui-e2e-tests/tests/snapshot_tests.rs deleted file mode 100644 index d6ef43f15cf..00000000000 --- a/crates/sui-e2e-tests/tests/snapshot_tests.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use clap::Parser; -use insta::assert_json_snapshot; -use sui::sui_commands::SuiCommand; -use sui_macros::sim_test; -use sui_sdk::wallet_context::WalletContext; -use test_cluster::TestClusterBuilder; - -// special constants for substitution in commands -const ME: &str = "{ME}"; - -async fn run_one( - test: Vec<&str>, - context: &mut WalletContext, -) -> Result, anyhow::Error> { - let mut test_output = Vec::new(); - let active_addr = context.active_address()?.to_string(); - for cli_cmd in test { - let mut cli_cmd_vec = cli_cmd.split(' ').collect::>(); - for word in cli_cmd_vec.iter_mut() { - if *word == ME { - *word = &active_addr - } - } - test_output.push(serde_json::Value::String(cli_cmd.to_string())); - let c = SuiCommand::try_parse_from(cli_cmd_vec)?; - match c { - SuiCommand::Client { cmd, .. } => { - if let Some(client_cmd) = cmd { - match client_cmd.execute(context).await { - Ok(output) => { - if let Some(block_response) = output.tx_block_response() { - test_output.push(serde_json::to_value(block_response)?); - } else if let Some(objects_response) = output.objects_response() { - test_output.push(serde_json::to_value(objects_response)?) - } - } - Err(e) => test_output.push(serde_json::Value::String(e.to_string())), - } - } - } - SuiCommand::Move { - package_path: _, - build_config: _, - cmd: _, - } => unimplemented!("Supporting Move publish and upgrade commands"), - _ => panic!("Command {:?} not supported by RPC snapshot tests", cli_cmd), - } - } - Ok(test_output) -} - -#[ignore] -#[sim_test] -async fn basic_read_cmd_snapshot_tests() -> Result<(), anyhow::Error> { - let mut test_cluster = TestClusterBuilder::new().build().await; - let context = &mut test_cluster.wallet; - - let cmds = vec![ - "sui client objects {ME}", // valid addr - "sui client objects 0x0000000000000000000000000000000000000000000000000000000000000000", /* empty addr */ - "sui client object 0x5", // valid object - "sui client object 0x5 --bcs", // valid object BCS - // Simtest object IDs are not stable so these object IDs may or may not exist currently -- - // commenting them out for now. - // "sui client object 0x3b5121a0603ef7ab4cb57827fceca17db3338ef2cd76126cc1523b681df27cee", - // // valid object "sui client object - // 0x3b5121a0603ef7ab4cb57827fceca17db3338ef2cd76126cc1523b681df27cee --bcs", // valid - // object BCS - "sui client object 0x0000000000000000000000000000000000000000000000000000000000000000", /* non-existent object */ - "sui client tx-block Duwr9uSk9ZvAndEa8oDHunx345i6oyrp3e78MYHVAbYdv", // valid tx digest - "sui client tx-block EgMTHQygMi6SRsBqrPHAEKZCNrpShXurCp9rcb9qbSg8", /* non-existent tx - * digest */ - ]; - assert_json_snapshot!(run_one(cmds, context).await?); - Ok(()) -} diff --git a/crates/sui-e2e-tests/tests/transfer_to_object_tests.rs b/crates/sui-e2e-tests/tests/transfer_to_object_tests.rs deleted file mode 100644 index b3f83652f9e..00000000000 --- a/crates/sui-e2e-tests/tests/transfer_to_object_tests.rs +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::HashSet, path::PathBuf}; - -use sui_core::authority_client::AuthorityAPI; -use sui_macros::*; -use sui_test_transaction_builder::publish_package; -use sui_types::{ - base_types::{ObjectID, ObjectRef}, - effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, - error::SuiError, - object::Owner, - transaction::{CallArg, ObjectArg, Transaction}, -}; -use test_cluster::{TestCluster, TestClusterBuilder}; - -#[sim_test] -async fn receive_object_feature_deny() { - use sui_protocol_config::ProtocolConfig; - - let _guard = ProtocolConfig::apply_overrides_for_testing(|_, mut config| { - config.set_receive_object_for_testing(false); - config - }); - - let env = TestEnvironment::new().await; - let (parent, child) = env.start().await; - let arguments = vec![ - CallArg::Object(ObjectArg::ImmOrOwnedObject(parent)), - CallArg::Object(ObjectArg::Receiving(child)), - ]; - let txn = env.create_move_call("receiver", arguments).await; - let err = env - .test_cluster - .authority_aggregator() - .authority_clients - .values() - .next() - .unwrap() - .authority_client() - .handle_transaction(txn) - .await - .map(|_| ()) - .unwrap_err(); - - assert!(matches!(err, SuiError::UnsupportedFeatureError { .. })); -} - -#[sim_test] -async fn receive_of_object() { - let env = TestEnvironment::new().await; - let (parent, child) = env.start().await; - env.receive(parent, child).await.unwrap(); -} - -#[sim_test] -async fn receive_of_object_with_reconfiguration() { - let env = TestEnvironment::new().await; - let (parent, child) = env.start().await; - env.receive(parent, child).await.unwrap(); - env.test_cluster.trigger_reconfiguration().await; -} - -#[sim_test] -async fn receive_of_object_with_reconfiguration_receive_after_reconfig() { - let env = TestEnvironment::new().await; - let (parent, child) = env.start().await; - let (new_parent, new_child) = env.receive(parent, child).await.unwrap(); - env.test_cluster.trigger_reconfiguration().await; - assert!(env.receive(new_parent, new_child).await.is_ok()); -} - -#[sim_test] -async fn receive_of_object_with_reconfiguration_receive_of_old_child_after_reconfig() { - let env = TestEnvironment::new().await; - let (parent, child) = env.start().await; - let (new_parent, _) = env.receive(parent, child).await.unwrap(); - env.test_cluster.trigger_reconfiguration().await; - assert!(env.receive(new_parent, child).await.is_err()); -} - -#[sim_test] -async fn receive_of_object_with_reconfiguration_receive_of_old_parent_after_reconfig() { - let env = TestEnvironment::new().await; - let (parent, child) = env.start().await; - let (_, new_child) = env.receive(parent, child).await.unwrap(); - env.test_cluster.trigger_reconfiguration().await; - assert!(env.receive(parent, new_child).await.is_err()); -} - -#[sim_test] -async fn receive_of_object_with_reconfiguration_receive_of_old_parent_and_child_after_reconfig() { - let env = TestEnvironment::new().await; - let (parent, child) = env.start().await; - env.receive(parent, child).await.unwrap(); - env.test_cluster.trigger_reconfiguration().await; - assert!(env.receive(parent, child).await.is_err()); -} - -#[sim_test] -async fn receive_of_object_with_reconfiguration_receive_after_reconfig_with_invalid_child() { - let env = TestEnvironment::new().await; - let (parent, child) = env.start().await; - let (new_parent, new_child) = env.receive(parent, child).await.unwrap(); - env.test_cluster.trigger_reconfiguration().await; - assert!(env.receive(new_child, new_parent).await.is_err()); -} - -#[sim_test] -async fn delete_of_object_with_reconfiguration_receive_of_old_parent_and_child_after_reconfig() { - let env = TestEnvironment::new().await; - let (parent, child) = env.start().await; - env.delete(parent, child).await; - env.test_cluster.trigger_reconfiguration().await; - assert!(env.receive(parent, child).await.is_err()); -} - -#[sim_test] -async fn delete_of_object_with_reconfiguration_receive_of_new_parent_and_old_child_after_reconfig() -{ - let env = TestEnvironment::new().await; - let (parent, child) = env.start().await; - let new_parent = env.delete(parent, child).await; - env.test_cluster.trigger_reconfiguration().await; - assert!(env.receive(new_parent, child).await.is_err()); -} - -fn get_parent_and_child(created: Vec<(ObjectRef, Owner)>) -> (ObjectRef, ObjectRef) { - // make sure there is an object with an `AddressOwner` who matches the object ID - // of another object. - let created_addrs: HashSet<_> = created.iter().map(|((i, _, _), _)| i).collect(); - let (child, parent_id) = created - .iter() - .find_map(|child @ (_, owner)| match owner { - Owner::AddressOwner(j) if created_addrs.contains(&ObjectID::from(*j)) => { - Some((child, (*j).into())) - } - _ => None, - }) - .unwrap(); - let parent = created - .iter() - .find(|((id, _, _), _)| *id == parent_id) - .unwrap(); - (parent.0, child.0) -} - -struct TestEnvironment { - pub test_cluster: TestCluster, - move_package: ObjectID, -} - -impl TestEnvironment { - async fn new() -> Self { - let test_cluster = TestClusterBuilder::new().build().await; - - let move_package = publish_move_package(&test_cluster).await.0; - - Self { - test_cluster, - move_package, - } - } - - async fn create_move_call( - &self, - function: &'static str, - arguments: Vec, - ) -> Transaction { - let transaction = self - .test_cluster - .test_transaction_builder() - .await - .move_call(self.move_package, "tto", function, arguments) - .build(); - self.test_cluster.wallet.sign_transaction(&transaction) - } - - async fn move_call( - &self, - function: &'static str, - arguments: Vec, - ) -> anyhow::Result<(TransactionEffects, TransactionEvents)> { - let transaction = self.create_move_call(function, arguments).await; - self.test_cluster - .execute_transaction_return_raw_effects(transaction) - .await - } - - async fn start(&self) -> (ObjectRef, ObjectRef) { - let (fx, _) = self.move_call("start", vec![]).await.unwrap(); - assert!(fx.status().is_ok()); - - get_parent_and_child(fx.created()) - } - - async fn receive( - &self, - parent: ObjectRef, - child: ObjectRef, - ) -> anyhow::Result<(ObjectRef, ObjectRef)> { - let arguments = vec![ - CallArg::Object(ObjectArg::ImmOrOwnedObject(parent)), - CallArg::Object(ObjectArg::Receiving(child)), - ]; - let fx = self.move_call("receiver", arguments).await?; - assert!(fx.0.status().is_ok()); - let new_child_ref = - fx.0.mutated_excluding_gas() - .iter() - .find_map( - |(oref, _)| { - if oref.0 == child.0 { Some(*oref) } else { None } - }, - ) - .unwrap(); - let new_parent_ref = - fx.0.mutated_excluding_gas() - .iter() - .find_map(|(oref, _)| { - if oref.0 == parent.0 { - Some(*oref) - } else { - None - } - }) - .unwrap(); - Ok((new_parent_ref, new_child_ref)) - } - - async fn delete(&self, parent: ObjectRef, child: ObjectRef) -> ObjectRef { - let arguments = vec![ - CallArg::Object(ObjectArg::ImmOrOwnedObject(parent)), - CallArg::Object(ObjectArg::Receiving(child)), - ]; - let fx = self.move_call("deleter", arguments).await.unwrap(); - assert!(fx.0.status().is_ok()); - fx.0.mutated_excluding_gas() - .iter() - .find_map(|(oref, _)| { - if oref.0 == parent.0 { - Some(*oref) - } else { - None - } - }) - .unwrap() - } -} - -async fn publish_move_package(test_cluster: &TestCluster) -> ObjectRef { - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.push("tests/move_test_code"); - publish_package(&test_cluster.wallet, path).await -} diff --git a/crates/sui-enum-compat-util/Cargo.toml b/crates/sui-enum-compat-util/Cargo.toml deleted file mode 100644 index 8666fbd54d5..00000000000 --- a/crates/sui-enum-compat-util/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "sui-enum-compat-util" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -serde_yaml.workspace = true diff --git a/crates/sui-enum-compat-util/src/lib.rs b/crates/sui-enum-compat-util/src/lib.rs deleted file mode 100644 index 6c7c4dc06ab..00000000000 --- a/crates/sui-enum-compat-util/src/lib.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{io::Write, path::PathBuf}; - -pub trait EnumOrderMap { - fn order_to_variant_map() -> std::collections::BTreeMap; -} - -pub fn check_enum_compat_order(snapshot_file: PathBuf) { - let new_map = T::order_to_variant_map(); - - if let Err(err) = std::fs::read_to_string(snapshot_file.clone()) { - if err.kind() == std::io::ErrorKind::NotFound { - // Create the file if not exists - let mut file = std::fs::File::create(snapshot_file).unwrap(); - let content: String = serde_yaml::to_string(&new_map).unwrap(); - - write!(file, "{}", content).unwrap(); - return; - } - panic!("Error reading file: {:?}: err {:?}", snapshot_file, err); - } - - let existing_map: std::collections::BTreeMap = - serde_yaml::from_str(&std::fs::read_to_string(snapshot_file.clone()).unwrap()).unwrap(); - - // Check that the new map includes the existing map in order - for (pos, val) in existing_map { - match new_map.get(&pos) { - None => { - panic!( - "Enum variant {} has been removed. Not allowed: enum must be backward compatible.", - val - ); - } - Some(new_val) if new_val == &val => continue, - Some(new_val) => { - panic!( - "Enum variant {val} has been swapped with {new_val} at position {pos}. Not allowed: enum must be backward compatible." - ); - } - } - } - - // Update the file - let mut file = std::fs::File::create(snapshot_file).unwrap(); - let content: String = serde_yaml::to_string(&new_map).unwrap(); - - write!(file, "{}", content).unwrap(); -} diff --git a/crates/sui-faucet/Cargo.toml b/crates/sui-faucet/Cargo.toml deleted file mode 100644 index 7f2cb4d76ad..00000000000 --- a/crates/sui-faucet/Cargo.toml +++ /dev/null @@ -1,50 +0,0 @@ -[package] -name = "sui-faucet" -version.workspace = true -edition = "2021" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false - -[dependencies] -anyhow.workspace = true -async-trait.workspace = true -axum.workspace = true -clap.workspace = true -thiserror.workspace = true -tokio = { workspace = true, features = ["full"] } -tracing.workspace = true -serde.workspace = true -tower.workspace = true -tower-http.workspace = true -http.workspace = true -futures.workspace = true -uuid.workspace = true -prometheus.workspace = true -scopeguard.workspace = true -tap.workspace = true -ttl_cache.workspace = true -eyre.workspace = true -rocksdb.workspace = true -tempfile.workspace = true -parking_lot.workspace = true - -sui.workspace = true -sui-json-rpc-types.workspace = true -sui-types.workspace = true -sui-config.workspace = true -sui-keys.workspace = true -sui-sdk.workspace = true -mysten-metrics.workspace = true -telemetry-subscribers.workspace = true -typed-store.workspace = true -typed-store-derive.workspace = true -shared-crypto.workspace = true -async-recursion.workspace = true - -[dev-dependencies] -test-cluster.workspace = true - -[[bin]] -name = "sui-faucet" -path = "src/main.rs" diff --git a/crates/sui-faucet/src/errors.rs b/crates/sui-faucet/src/errors.rs deleted file mode 100644 index 1538a5b7be9..00000000000 --- a/crates/sui-faucet/src/errors.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use thiserror::Error; - -#[derive(Error, Debug, PartialEq, Eq)] -pub enum FaucetError { - #[error("Faucet cannot read objects from fullnode: {0}")] - FullnodeReadingError(String), - - #[error("Failed to parse transaction response {0}")] - ParseTransactionResponseError(String), - - #[error( - "Gas coin `{0}` does not have sufficient balance and has been removed from gas coin pool" - )] - GasCoinWithInsufficientBalance(String), - - #[error("Faucet does not have enough balance")] - InsuffientBalance, - - #[error("Gas coin `{0}` is not valid and has been removed from gas coin pool")] - InvalidGasCoin(String), - - #[error("Timed out waiting for a coin from the gas coin pool")] - NoGasCoinAvailable, - - #[error("Wallet Error: `{0}`")] - Wallet(String), - - #[error("Coin Transfer Failed `{0}`")] - Transfer(String), - - #[error("Too many coins in the batch queue. Please try again later.")] - BatchSendQueueFull, - - #[error("Request consumer queue closed.")] - ChannelClosed, - - #[error("Coin amounts sent are incorrect:`{0}`")] - CoinAmountTransferredIncorrect(String), - - #[error("Internal error: {0}")] - Internal(String), -} - -impl FaucetError { - pub(crate) fn internal(e: impl ToString) -> Self { - FaucetError::Internal(e.to_string()) - } -} diff --git a/crates/sui-faucet/src/faucet/mod.rs b/crates/sui-faucet/src/faucet/mod.rs deleted file mode 100644 index b93ac4546fe..00000000000 --- a/crates/sui-faucet/src/faucet/mod.rs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use async_trait::async_trait; -use serde::{Deserialize, Serialize}; -use sui_types::base_types::{ObjectID, SuiAddress, TransactionDigest}; -use uuid::Uuid; - -use crate::FaucetError; - -mod simple_faucet; -mod write_ahead_log; -use std::{net::Ipv4Addr, path::PathBuf}; - -use clap::Parser; - -pub use self::simple_faucet::SimpleFaucet; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct FaucetReceipt { - pub sent: Vec, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct BatchFaucetReceipt { - pub task: String, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct CoinInfo { - pub amount: u64, - pub id: ObjectID, - pub transfer_tx_digest: TransactionDigest, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct BatchSendStatus { - pub status: BatchSendStatusType, - pub transferred_gas_objects: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] -#[serde(rename_all = "UPPERCASE")] -pub enum BatchSendStatusType { - INPROGRESS, - SUCCEEDED, - DISCARDED, -} - -#[async_trait] -pub trait Faucet { - /// Send `Coin` of the specified amount to the recipient - async fn send( - &self, - id: Uuid, - recipient: SuiAddress, - amounts: &[u64], - ) -> Result; - - /// Send `Coin` of the specified amount to the recipient in a batch - /// request - async fn batch_send( - &self, - id: Uuid, - recipient: SuiAddress, - amounts: &[u64], - ) -> Result; - - /// Get the status of a batch_send request - async fn get_batch_send_status(&self, task_id: Uuid) -> Result; -} - -pub const DEFAULT_AMOUNT: u64 = 1_000_000_000; -pub const DEFAULT_NUM_OF_COINS: usize = 1; - -#[derive(Parser, Clone)] -#[clap( - name = "Sui Faucet", - about = "Faucet for requesting test tokens on Sui", - rename_all = "kebab-case" -)] -pub struct FaucetConfig { - #[clap(long, default_value_t = 5003)] - pub port: u16, - - #[clap(long, default_value = "127.0.0.1")] - pub host_ip: Ipv4Addr, - - #[clap(long, default_value_t = DEFAULT_AMOUNT)] - pub amount: u64, - - #[clap(long, default_value_t = DEFAULT_NUM_OF_COINS)] - pub num_coins: usize, - - #[clap(long, default_value_t = 10)] - pub request_buffer_size: usize, - - #[clap(long, default_value_t = 10)] - pub max_request_per_second: u64, - - #[clap(long, default_value_t = 60)] - pub wallet_client_timeout_secs: u64, - - #[clap(long)] - pub write_ahead_log: PathBuf, - - #[clap(long, default_value_t = 300)] - pub wal_retry_interval: u64, - - #[clap(long, default_value_t = 10000)] - pub max_request_queue_length: u64, - - #[clap(long, default_value_t = 500)] - pub batch_request_size: u64, - - #[clap(long, default_value_t = 300)] - pub ttl_expiration: u64, - - #[clap(long, action = clap::ArgAction::Set, default_value_t = false)] - pub batch_enabled: bool, -} - -impl Default for FaucetConfig { - fn default() -> Self { - Self { - port: 5003, - host_ip: Ipv4Addr::new(127, 0, 0, 1), - amount: 1_000_000_000, - num_coins: 1, - request_buffer_size: 10, - max_request_per_second: 10, - wallet_client_timeout_secs: 60, - write_ahead_log: Default::default(), - wal_retry_interval: 300, - max_request_queue_length: 10000, - batch_request_size: 500, - ttl_expiration: 300, - batch_enabled: false, - } - } -} diff --git a/crates/sui-faucet/src/lib.rs b/crates/sui-faucet/src/lib.rs deleted file mode 100644 index 8d3697fbce1..00000000000 --- a/crates/sui-faucet/src/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod errors; -mod faucet; -mod metrics; -mod requests; -mod responses; - -pub mod metrics_layer; -pub use errors::FaucetError; -pub use faucet::*; -pub use metrics_layer::*; -pub use requests::*; -pub use responses::*; diff --git a/crates/sui-faucet/src/main.rs b/crates/sui-faucet/src/main.rs deleted file mode 100644 index 1acb75623f7..00000000000 --- a/crates/sui-faucet/src/main.rs +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - borrow::Cow, - env, - net::{IpAddr, SocketAddr}, - sync::Arc, - time::Duration, -}; - -use axum::{ - error_handling::HandleErrorLayer, - extract::Path, - http::StatusCode, - response::IntoResponse, - routing::{get, post}, - BoxError, Extension, Json, Router, -}; -use clap::Parser; -use http::Method; -use mysten_metrics::spawn_monitored_task; -use sui_config::{sui_config_dir, SUI_CLIENT_CONFIG}; -use sui_faucet::{ - BatchFaucetResponse, BatchStatusFaucetResponse, Faucet, FaucetConfig, FaucetError, - FaucetRequest, FaucetResponse, RequestMetricsLayer, SimpleFaucet, -}; -use sui_sdk::wallet_context::WalletContext; -use tower::{limit::RateLimitLayer, ServiceBuilder}; -use tower_http::cors::{Any, CorsLayer}; -use tracing::{info, warn}; -use uuid::Uuid; - -const CONCURRENCY_LIMIT: usize = 30; - -struct AppState> { - faucet: F, - config: FaucetConfig, -} - -const PROM_PORT_ADDR: &str = "0.0.0.0:9184"; - -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - // initialize tracing - let _guard = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .init(); - - let max_concurrency = match env::var("MAX_CONCURRENCY") { - Ok(val) => val.parse::().unwrap(), - _ => CONCURRENCY_LIMIT, - }; - info!("Max concurrency: {max_concurrency}."); - - let config: FaucetConfig = FaucetConfig::parse(); - let FaucetConfig { - port, - host_ip, - request_buffer_size, - max_request_per_second, - wallet_client_timeout_secs, - ref write_ahead_log, - wal_retry_interval, - .. - } = config; - - let context = create_wallet_context(wallet_client_timeout_secs)?; - - let prom_binding = PROM_PORT_ADDR.parse().unwrap(); - info!("Starting Prometheus HTTP endpoint at {}", prom_binding); - let registry_service = mysten_metrics::start_prometheus_server(prom_binding); - let prometheus_registry = registry_service.default_registry(); - let app_state = Arc::new(AppState { - faucet: SimpleFaucet::new( - context, - &prometheus_registry, - write_ahead_log, - config.clone(), - ) - .await - .unwrap(), - config, - }); - - // TODO: restrict access if needed - let cors = CorsLayer::new() - .allow_methods(vec![Method::GET, Method::POST]) - .allow_headers(Any) - .allow_origin(Any); - - let app = Router::new() - .route("/", get(health)) - .route("/gas", post(request_gas)) - .route("/v1/gas", post(batch_request_gas)) - .route("/v1/status/:task_id", get(request_status)) - .layer( - ServiceBuilder::new() - .layer(HandleErrorLayer::new(handle_error)) - .layer(RequestMetricsLayer::new(&prometheus_registry)) - .layer(cors) - .load_shed() - .buffer(request_buffer_size) - .layer(RateLimitLayer::new( - max_request_per_second, - Duration::from_secs(1), - )) - .concurrency_limit(max_concurrency) - .layer(Extension(app_state.clone())) - .into_inner(), - ); - - spawn_monitored_task!(async move { - info!("Starting task to clear WAL."); - loop { - // Every config.wal_retry_interval (Default: 300 seconds) we try to clear the - // wal coins - tokio::time::sleep(Duration::from_secs(wal_retry_interval)).await; - app_state.faucet.retry_wal_coins().await.unwrap(); - } - }); - - let addr = SocketAddr::new(IpAddr::V4(host_ip), port); - info!("listening on {}", addr); - axum::Server::bind(&addr) - .serve(app.into_make_service()) - .await?; - Ok(()) -} - -/// basic handler that responds with a static string -async fn health() -> &'static str { - "OK" -} - -/// handler for batch_request_gas requests -async fn batch_request_gas( - Extension(state): Extension>, - Json(payload): Json, -) -> impl IntoResponse { - let id = Uuid::new_v4(); - // ID for traceability - info!(uuid = ?id, "Got new gas request."); - - let FaucetRequest::FixedAmountRequest(request) = payload else { - return ( - StatusCode::BAD_REQUEST, - Json(BatchFaucetResponse::from(FaucetError::Internal( - "Input Error.".to_string(), - ))), - ); - }; - - if state.config.batch_enabled { - let result = spawn_monitored_task!(async move { - state - .faucet - .batch_send( - id, - request.recipient, - &vec![state.config.amount; state.config.num_coins], - ) - .await - }) - .await - .unwrap(); - - match result { - Ok(v) => { - info!(uuid =?id, "Request is successfully served"); - (StatusCode::ACCEPTED, Json(BatchFaucetResponse::from(v))) - } - Err(v) => { - warn!(uuid =?id, "Failed to request gas: {:?}", v); - ( - StatusCode::INTERNAL_SERVER_ERROR, - Json(BatchFaucetResponse::from(v)), - ) - } - } - } else { - // TODO (jian): remove this feature gate when batch has proven to be baked long - // enough - info!(uuid = ?id, "Falling back to v1 implementation"); - let result = spawn_monitored_task!(async move { - state - .faucet - .send( - id, - request.recipient, - &vec![state.config.amount; state.config.num_coins], - ) - .await - }) - .await - .unwrap(); - - match result { - Ok(_) => { - info!(uuid =?id, "Request is successfully served"); - (StatusCode::ACCEPTED, Json(BatchFaucetResponse::from(id))) - } - Err(v) => { - warn!(uuid =?id, "Failed to request gas: {:?}", v); - ( - StatusCode::INTERNAL_SERVER_ERROR, - Json(BatchFaucetResponse::from(v)), - ) - } - } - } -} - -/// handler for batch_get_status requests -async fn request_status( - Extension(state): Extension>, - Path(id): Path, -) -> impl IntoResponse { - match Uuid::parse_str(&id) { - Ok(task_id) => { - let result = state.faucet.get_batch_send_status(task_id).await; - match result { - Ok(v) => ( - StatusCode::CREATED, - Json(BatchStatusFaucetResponse::from(v)), - ), - Err(v) => ( - StatusCode::INTERNAL_SERVER_ERROR, - Json(BatchStatusFaucetResponse::from(v)), - ), - } - } - Err(e) => ( - StatusCode::INTERNAL_SERVER_ERROR, - Json(BatchStatusFaucetResponse::from(FaucetError::Internal( - e.to_string(), - ))), - ), - } -} - -/// handler for all the request_gas requests -async fn request_gas( - Extension(state): Extension>, - Json(payload): Json, -) -> impl IntoResponse { - // ID for traceability - let id = Uuid::new_v4(); - info!(uuid = ?id, "Got new gas request."); - let result = match payload { - FaucetRequest::FixedAmountRequest(requests) => { - // We spawn a tokio task for this such that connection drop will not interrupt - // it and impact the recycling of coins - spawn_monitored_task!(async move { - state - .faucet - .send( - id, - requests.recipient, - &vec![state.config.amount; state.config.num_coins], - ) - .await - }) - .await - .unwrap() - } - _ => { - return ( - StatusCode::BAD_REQUEST, - Json(FaucetResponse::from(FaucetError::Internal( - "Input Error.".to_string(), - ))), - ); - } - }; - match result { - Ok(v) => { - info!(uuid =?id, "Request is successfully served"); - (StatusCode::CREATED, Json(FaucetResponse::from(v))) - } - Err(v) => { - warn!(uuid =?id, "Failed to request gas: {:?}", v); - ( - StatusCode::INTERNAL_SERVER_ERROR, - Json(FaucetResponse::from(v)), - ) - } - } -} - -fn create_wallet_context(timeout_secs: u64) -> Result { - let wallet_conf = sui_config_dir()?.join(SUI_CLIENT_CONFIG); - info!("Initialize wallet from config path: {:?}", wallet_conf); - WalletContext::new( - &wallet_conf, - Some(Duration::from_secs(timeout_secs)), - Some(1000), - ) -} - -async fn handle_error(error: BoxError) -> impl IntoResponse { - if error.is::() { - return ( - StatusCode::SERVICE_UNAVAILABLE, - Cow::from("service is overloaded, please try again later"), - ); - } - - ( - StatusCode::INTERNAL_SERVER_ERROR, - Cow::from(format!("Unhandled internal error: {}", error)), - ) -} diff --git a/crates/sui-faucet/src/metrics.rs b/crates/sui-faucet/src/metrics.rs deleted file mode 100644 index e67bbc334cd..00000000000 --- a/crates/sui-faucet/src/metrics.rs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2021, Facebook, Inc. and its affiliates -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use prometheus::{ - register_histogram_with_registry, register_int_counter_with_registry, - register_int_gauge_with_registry, Histogram, IntCounter, IntGauge, Registry, -}; - -/// Prometheus metrics which can be displayed in Grafana, queried and alerted on - -/// Metrics relevant to the requests coming into the service -#[derive(Clone, Debug)] -pub struct RequestMetrics { - pub(crate) total_requests_received: IntCounter, - pub(crate) total_requests_succeeded: IntCounter, - pub(crate) total_requests_shed: IntCounter, - pub(crate) total_requests_failed: IntCounter, - pub(crate) total_requests_disconnected: IntCounter, - pub(crate) current_requests_in_flight: IntGauge, - pub(crate) process_latency: Histogram, -} - -/// Metrics relevant to the running of the service -#[derive(Clone, Debug)] -pub struct FaucetMetrics { - pub(crate) current_executions_in_flight: IntGauge, - pub(crate) total_available_coins: IntGauge, - pub(crate) total_discarded_coins: IntGauge, - pub(crate) total_coin_requests_succeeded: IntGauge, -} - -const LATENCY_SEC_BUCKETS: &[f64] = &[ - 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1., 2.5, 5., 10., 20., 30., 60., 90., -]; - -impl RequestMetrics { - pub fn new(registry: &Registry) -> Self { - Self { - total_requests_received: register_int_counter_with_registry!( - "total_requests_received", - "Total number of requests received in Faucet", - registry, - ) - .unwrap(), - total_requests_succeeded: register_int_counter_with_registry!( - "total_requests_succeeded", - "Total number of requests processed successfully in Faucet", - registry, - ) - .unwrap(), - total_requests_shed: register_int_counter_with_registry!( - "total_requests_shed", - "Total number of requests that were dropped because the service was saturated", - registry, - ) - .unwrap(), - total_requests_failed: register_int_counter_with_registry!( - "total_requests_failed", - "Total number of requests that started but failed with an uncaught error", - registry, - ) - .unwrap(), - total_requests_disconnected: register_int_counter_with_registry!( - "total_requests_disconnected", - "Total number of requests where the client disconnected before the service \ - returned a response", - registry, - ) - .unwrap(), - current_requests_in_flight: register_int_gauge_with_registry!( - "current_requests_in_flight", - "Current number of requests being processed in Faucet", - registry, - ) - .unwrap(), - process_latency: register_histogram_with_registry!( - "process_latency", - "Latency of processing a Faucet request", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - } - } -} - -impl FaucetMetrics { - pub fn new(registry: &Registry) -> Self { - Self { - current_executions_in_flight: register_int_gauge_with_registry!( - "current_executions_in_flight", - "Current number of transactions being executed in Faucet", - registry, - ) - .unwrap(), - total_available_coins: register_int_gauge_with_registry!( - "total_available_coins", - "Total number of available coins in queue", - registry, - ) - .unwrap(), - total_discarded_coins: register_int_gauge_with_registry!( - "total_discarded_coins", - "Total number of discarded coins", - registry, - ) - .unwrap(), - total_coin_requests_succeeded: register_int_gauge_with_registry!( - "total_coin_requests_succeeded", - "Total number of requests processed successfully in Faucet (both batch and non_batched)", - registry, - ) - .unwrap(), - } - } -} diff --git a/crates/sui-framework-snapshot/Cargo.toml b/crates/sui-framework-snapshot/Cargo.toml deleted file mode 100644 index 311b886a7da..00000000000 --- a/crates/sui-framework-snapshot/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "sui-framework-snapshot" -version = "0.1.0" -edition = "2021" -authors = ["Mysten Labs "] -description = "Tool to create a bytecode snapshot of the current sui-framework" -license = "Apache-2.0" -publish = false - -[dependencies] -anyhow.workspace = true -bcs.workspace = true -serde.workspace = true -serde_json.workspace = true -git-version.workspace = true - -sui-framework.workspace = true -sui-protocol-config.workspace = true -sui-types.workspace = true - -[dev-dependencies] -tokio = { workspace = true, features = ["full"] } diff --git a/crates/sui-framework-snapshot/README.txt b/crates/sui-framework-snapshot/README.txt deleted file mode 100644 index 615b51572ad..00000000000 --- a/crates/sui-framework-snapshot/README.txt +++ /dev/null @@ -1,7 +0,0 @@ -Whenever we release a new binary that has a new protocol version to a network, we should go to the tip of that network's branch, and run this command: -``` -cargo run --bin sui-framework-snapshot -``` -And the commit the changes to `main` branch to record it. -It's important to ensure that each protocol version should correspond to a unique snapshot among all networks, -i.e. for the same protocol version, testnet and mainnet should contain identical framework bytecode. diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000002 b/crates/sui-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000002 deleted file mode 100644 index 515fc6ae1bb..00000000000 Binary files a/crates/sui-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000002 and /dev/null differ diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000003 b/crates/sui-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000003 deleted file mode 100644 index 01217292a30..00000000000 Binary files a/crates/sui-framework-snapshot/bytecode_snapshot/42/0x0000000000000000000000000000000000000000000000000000000000000003 and /dev/null differ diff --git a/crates/sui-framework-snapshot/bytecode_snapshot/42/0x000000000000000000000000000000000000000000000000000000000000dee9 b/crates/sui-framework-snapshot/bytecode_snapshot/42/0x000000000000000000000000000000000000000000000000000000000000dee9 deleted file mode 100644 index 546217a09f8..00000000000 Binary files a/crates/sui-framework-snapshot/bytecode_snapshot/42/0x000000000000000000000000000000000000000000000000000000000000dee9 and /dev/null differ diff --git a/crates/sui-framework-snapshot/src/lib.rs b/crates/sui-framework-snapshot/src/lib.rs deleted file mode 100644 index eafb5436a4c..00000000000 --- a/crates/sui-framework-snapshot/src/lib.rs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::BTreeMap, fs, io::Read, path::PathBuf}; - -use serde::{Deserialize, Serialize}; -use sui_framework::SystemPackage; -use sui_types::{ - base_types::ObjectID, DEEPBOOK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID, - SUI_SYSTEM_PACKAGE_ID, -}; - -pub type SnapshotManifest = BTreeMap; - -#[derive(Serialize, Deserialize)] -pub struct SingleSnapshot { - /// Git revision that this snapshot is taken on. - git_revision: String, - /// List of file names (also identical to object ID) of the bytecode package - /// files. - package_ids: Vec, -} - -impl SingleSnapshot { - pub fn git_revision(&self) -> &str { - &self.git_revision - } - pub fn package_ids(&self) -> &[ObjectID] { - &self.package_ids - } -} - -const SYSTEM_PACKAGE_PUBLISH_ORDER: &[ObjectID] = &[ - MOVE_STDLIB_PACKAGE_ID, - SUI_FRAMEWORK_PACKAGE_ID, - SUI_SYSTEM_PACKAGE_ID, - DEEPBOOK_PACKAGE_ID, -]; - -pub fn load_bytecode_snapshot_manifest() -> SnapshotManifest { - let Ok(bytes) = fs::read(manifest_path()) else { - return SnapshotManifest::default(); - }; - serde_json::from_slice::(&bytes) - .expect("Could not deserialize SnapshotManifest") -} - -pub fn update_bytecode_snapshot_manifest(git_revision: &str, version: u64, files: Vec) { - let mut snapshot = load_bytecode_snapshot_manifest(); - - snapshot.insert( - version, - SingleSnapshot { - git_revision: git_revision.to_string(), - package_ids: files, - }, - ); - - let json = - serde_json::to_string_pretty(&snapshot).expect("Could not serialize SnapshotManifest"); - fs::write(manifest_path(), json).expect("Could not update manifest file"); -} - -pub fn load_bytecode_snapshot(protocol_version: u64) -> anyhow::Result> { - let mut snapshot_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - snapshot_path.extend(["bytecode_snapshot", protocol_version.to_string().as_str()]); - let mut snapshots: BTreeMap = fs::read_dir(&snapshot_path)? - .flatten() - .map(|entry| { - let file_name = entry.file_name().to_str().unwrap().to_string(); - let mut file = fs::File::open(snapshot_path.clone().join(file_name))?; - let mut buffer = Vec::new(); - file.read_to_end(&mut buffer)?; - let package: SystemPackage = bcs::from_bytes(&buffer)?; - Ok((*package.id(), package)) - }) - .collect::>()?; - - // system packages need to be restored in a specific order - assert!(snapshots.len() <= SYSTEM_PACKAGE_PUBLISH_ORDER.len()); - let mut snapshot_objects = Vec::new(); - for package_id in SYSTEM_PACKAGE_PUBLISH_ORDER { - if let Some(object) = snapshots.remove(package_id) { - snapshot_objects.push(object); - } - } - Ok(snapshot_objects) -} - -fn manifest_path() -> PathBuf { - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("manifest.json") -} diff --git a/crates/sui-framework-snapshot/src/main.rs b/crates/sui-framework-snapshot/src/main.rs deleted file mode 100644 index 2bfe287ebac..00000000000 --- a/crates/sui-framework-snapshot/src/main.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{env, fs, path::PathBuf}; - -use sui_framework::{BuiltInFramework, SystemPackage}; -use sui_framework_snapshot::update_bytecode_snapshot_manifest; -use sui_protocol_config::ProtocolVersion; - -const GIT_REVISION: &str = { - if let Some(revision) = option_env!("GIT_REVISION") { - revision - } else { - let version = git_version::git_version!( - args = ["--always", "--dirty", "--exclude", "*"], - fallback = "" - ); - - if version.is_empty() { - panic!("unable to query git revision"); - } - version - } -}; - -fn main() { - // Always generate snapshot for the latest version. - let version = ProtocolVersion::MAX.as_u64(); - let mut files = vec![]; - for package in BuiltInFramework::iter_system_packages() { - write_package_to_file(version, package); - files.push(*package.id()); - } - update_bytecode_snapshot_manifest(GIT_REVISION, version, files); -} - -fn write_package_to_file(version: u64, package: &SystemPackage) { - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.extend(["bytecode_snapshot", version.to_string().as_str()]); - fs::create_dir_all(&path) - .or_else(|e| match e.kind() { - std::io::ErrorKind::AlreadyExists => Ok(()), - _ => Err(e), - }) - .expect("Unable to create snapshot directory"); - let bytes = bcs::to_bytes(package).expect("Deserialization cannot fail"); - fs::write(path.join(package.id().to_string()), bytes).expect("Unable to write data to file"); -} diff --git a/crates/sui-framework-tests/Cargo.toml b/crates/sui-framework-tests/Cargo.toml deleted file mode 100644 index 81802124a7d..00000000000 --- a/crates/sui-framework-tests/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "sui-framework-tests" -version = "0.1.0" -edition = "2021" -authors = ["Mysten Labs "] -description = "Runs Move tests for sui-framework" -license = "Apache-2.0" -publish = false - -[dev-dependencies] -prometheus.workspace = true - -sui-framework.workspace = true -sui-move = { workspace = true, features = ["unit_test"] } -sui-move-build.workspace = true -sui-protocol-config.workspace = true -sui-types.workspace = true - -move-bytecode-verifier = { path = "../../external-crates/move/crates/move-bytecode-verifier" } -sui-adapter = { path = "../../sui-execution/latest/sui-adapter", package = "sui-adapter-latest" } -sui-verifier = { path = "../../sui-execution/latest/sui-verifier", package = "sui-verifier-latest" } - -move-cli.workspace = true -move-package.workspace = true -move-unit-test.workspace = true - -[dependencies] diff --git a/crates/sui-framework-tests/src/lib.rs b/crates/sui-framework-tests/src/lib.rs deleted file mode 100644 index d41a90db7c6..00000000000 --- a/crates/sui-framework-tests/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[cfg(test)] -mod unit_tests; - -#[cfg(test)] -mod metered_verifier; diff --git a/crates/sui-framework/CONTRIBUTING.md b/crates/sui-framework/CONTRIBUTING.md deleted file mode 100644 index 0435035cfb1..00000000000 --- a/crates/sui-framework/CONTRIBUTING.md +++ /dev/null @@ -1,16 +0,0 @@ -This file contains useful information and troubleshooting advice for those wishing to contribute to `sui-framework` crate. - -## Framework Move source code changes - -If changes need to be made to the framework's Move code, additional actions need to be taken to ensure that the system builds and runs correctly. In particular, one needs to make sure that the framework snapshot tests are up-to-date and that any new native functions are correctly handled by the [Move Prover](https://github.com/move-language/move/tree/main/language/move-prover). - -### Snapshot tests update - -Run the following commands in Sui's [root directory](../../) and accept the changes, if any (if you do not have `cargo-insta` command installed, please run the `cargo install cargo-insta` command first): - -``` bash -cargo insta test -p sui-cost --review -cargo insta test -p sui-config --review -``` - -Please use your best judgment to decide if the changes between old and new versions of the snapshots look "reasonable" (e.g., a minor change in gas costs). When in doubt, please reach out to a member of Sui core team. diff --git a/crates/sui-framework/Cargo.toml b/crates/sui-framework/Cargo.toml deleted file mode 100644 index 23fc1069ac7..00000000000 --- a/crates/sui-framework/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "sui-framework" -version = "0.1.0" -edition = "2021" -authors = ["Mysten Labs "] -description = "Move framework for sui platform" -license = "Apache-2.0" -publish = false - -[dependencies] -bcs.workspace = true -serde.workspace = true -once_cell.workspace = true -tracing.workspace = true - -sui-types.workspace = true - -move-binary-format.workspace = true -move-core-types.workspace = true - -[build-dependencies] -anyhow.workspace = true -bcs.workspace = true -regex.workspace = true - -sui-move-build.workspace = true - -move-binary-format.workspace = true -move-compiler.workspace = true -move-package.workspace = true diff --git a/crates/sui-framework/README.md b/crates/sui-framework/README.md deleted file mode 100644 index 63a013a2912..00000000000 --- a/crates/sui-framework/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# To add a new native Move function - -1. Add a new `./sui-framework/{name}.move` file or find an appropriate `.move`. -2. Add the signature of the function you are adding in `{name}.move`. -3. Add the rust implementation of the function under `./sui-framework/src/natives` with name `{name}.rs`. -4. Link the move interface with the native function in [all_natives](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/src/natives/mod.rs#L23) -5. Write some tests in `{name}_tests.move` and pass `run_framework_move_unit_tests`. -6. Optionally, update the mock move VM value in [gas_tests.rs](https://github.com/MystenLabs/sui/blob/276356e168047cdfce71814cb14403f4653a3656/crates/sui-core/src/unit_tests/gas_tests.rs) since the sui-framework package will increase the gas metering. -7. Optionally, run `cargo insta test` and `cargo insta review` since the sui-framework build will change the empty genesis config. - -Note: The gas metering for native functions is currently a WIP; use a dummy value for now and please open an issue with `move` label. diff --git a/crates/sui-framework/build.rs b/crates/sui-framework/build.rs deleted file mode 100644 index 1398baddd81..00000000000 --- a/crates/sui-framework/build.rs +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::BTreeMap, - env, fs, - path::{Path, PathBuf}, -}; - -use anyhow::Result; -use move_binary_format::CompiledModule; -use move_compiler::editions::Edition; -use move_package::{BuildConfig as MoveBuildConfig, LintFlag}; -use sui_move_build::{BuildConfig, SuiPackageHooks}; - -const DOCS_DIR: &str = "docs"; - -/// Save revision info to environment variable -fn main() { - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let packages_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("packages"); - - let deepbook_path = packages_path.join("deepbook"); - let sui_system_path = packages_path.join("sui-system"); - let sui_framework_path = packages_path.join("sui-framework"); - let stardust_path = packages_path.join("stardust"); - let timelock_path = packages_path.join("timelock"); - let deepbook_path_clone = deepbook_path.clone(); - let sui_system_path_clone = sui_system_path.clone(); - let sui_framework_path_clone = sui_framework_path.clone(); - let stardust_path_clone = stardust_path.clone(); - let timelock_path_clone = timelock_path.clone(); - let move_stdlib_path = packages_path.join("move-stdlib"); - - build_packages( - deepbook_path_clone, - sui_system_path_clone, - sui_framework_path_clone, - stardust_path_clone, - timelock_path_clone, - out_dir, - ); - - println!("cargo:rerun-if-changed=build.rs"); - println!( - "cargo:rerun-if-changed={}", - deepbook_path.join("Move.toml").display() - ); - println!( - "cargo:rerun-if-changed={}", - deepbook_path.join("sources").display() - ); - println!( - "cargo:rerun-if-changed={}", - sui_system_path.join("Move.toml").display() - ); - println!( - "cargo:rerun-if-changed={}", - sui_system_path.join("sources").display() - ); - println!( - "cargo:rerun-if-changed={}", - sui_framework_path.join("Move.toml").display() - ); - println!( - "cargo:rerun-if-changed={}", - sui_framework_path.join("sources").display() - ); - println!( - "cargo:rerun-if-changed={}", - move_stdlib_path.join("Move.toml").display() - ); - println!( - "cargo:rerun-if-changed={}", - move_stdlib_path.join("sources").display() - ); - println!( - "cargo:rerun-if-changed={}", - stardust_path.join("Move.toml").display() - ); - println!( - "cargo:rerun-if-changed={}", - stardust_path.join("sources").display() - ); - println!( - "cargo:rerun-if-changed={}", - timelock_path.join("Move.toml").display() - ); - println!( - "cargo:rerun-if-changed={}", - timelock_path.join("sources").display() - ); -} - -fn build_packages( - deepbook_path: PathBuf, - sui_system_path: PathBuf, - sui_framework_path: PathBuf, - stardust_path: PathBuf, - timelock_path: PathBuf, - out_dir: PathBuf, -) { - let config = MoveBuildConfig { - generate_docs: true, - warnings_are_errors: true, - install_dir: Some(PathBuf::from(".")), - lint_flag: LintFlag::LEVEL_NONE, - default_edition: Some(Edition::E2024_BETA), - ..Default::default() - }; - debug_assert!(!config.test_mode); - build_packages_with_move_config( - deepbook_path.clone(), - sui_system_path.clone(), - sui_framework_path.clone(), - stardust_path.clone(), - timelock_path.clone(), - out_dir.clone(), - "deepbook", - "sui-system", - "sui-framework", - "move-stdlib", - "stardust", - "timelock", - config, - true, - ); - let config = MoveBuildConfig { - generate_docs: true, - test_mode: true, - warnings_are_errors: true, - install_dir: Some(PathBuf::from(".")), - lint_flag: LintFlag::LEVEL_NONE, - default_edition: Some(Edition::E2024_BETA), - ..Default::default() - }; - build_packages_with_move_config( - deepbook_path, - sui_system_path, - sui_framework_path, - stardust_path, - timelock_path, - out_dir, - "deepbook-test", - "sui-system-test", - "sui-framework-test", - "move-stdlib-test", - "stardust-test", - "timelock-test", - config, - false, - ); -} - -fn build_packages_with_move_config( - deepbook_path: PathBuf, - sui_system_path: PathBuf, - sui_framework_path: PathBuf, - stardust_path: PathBuf, - timelock_path: PathBuf, - out_dir: PathBuf, - deepbook_dir: &str, - system_dir: &str, - framework_dir: &str, - stdlib_dir: &str, - stardust_dir: &str, - timelock_dir: &str, - config: MoveBuildConfig, - write_docs: bool, -) { - let framework_pkg = BuildConfig { - config: config.clone(), - run_bytecode_verifier: true, - print_diags_to_stderr: false, - } - .build(sui_framework_path) - .unwrap(); - let system_pkg = BuildConfig { - config: config.clone(), - run_bytecode_verifier: true, - print_diags_to_stderr: false, - } - .build(sui_system_path) - .unwrap(); - let deepbook_pkg = BuildConfig { - config: config.clone(), - run_bytecode_verifier: true, - print_diags_to_stderr: false, - } - .build(deepbook_path) - .unwrap(); - let stardust_pkg = BuildConfig { - config: config.clone(), - run_bytecode_verifier: true, - print_diags_to_stderr: false, - } - .build(stardust_path) - .unwrap(); - let timelock_pkg = BuildConfig { - config, - run_bytecode_verifier: true, - print_diags_to_stderr: false, - } - .build(timelock_path) - .unwrap(); - - let sui_system = system_pkg.get_sui_system_modules(); - let sui_framework = framework_pkg.get_sui_framework_modules(); - let deepbook = deepbook_pkg.get_deepbook_modules(); - let move_stdlib = framework_pkg.get_stdlib_modules(); - let stardust = stardust_pkg.get_stardust_modules(); - let timelock = timelock_pkg.get_timelock_modules(); - - serialize_modules_to_file(sui_system, &out_dir.join(system_dir)).unwrap(); - serialize_modules_to_file(sui_framework, &out_dir.join(framework_dir)).unwrap(); - serialize_modules_to_file(deepbook, &out_dir.join(deepbook_dir)).unwrap(); - serialize_modules_to_file(move_stdlib, &out_dir.join(stdlib_dir)).unwrap(); - serialize_modules_to_file(stardust, &out_dir.join(stardust_dir)).unwrap(); - serialize_modules_to_file(timelock, &out_dir.join(timelock_dir)).unwrap(); - // write out generated docs - if write_docs { - // Remove the old docs directory -- in case there was a module that was deleted - // (could happen during development). - if Path::new(DOCS_DIR).exists() { - std::fs::remove_dir_all(DOCS_DIR).unwrap(); - } - let mut files_to_write = BTreeMap::new(); - relocate_docs( - deepbook_dir, - &deepbook_pkg.package.compiled_docs.unwrap(), - &mut files_to_write, - ); - relocate_docs( - system_dir, - &system_pkg.package.compiled_docs.unwrap(), - &mut files_to_write, - ); - relocate_docs( - framework_dir, - &framework_pkg.package.compiled_docs.unwrap(), - &mut files_to_write, - ); - relocate_docs( - stardust_dir, - &stardust_pkg.package.compiled_docs.unwrap(), - &mut files_to_write, - ); - relocate_docs( - timelock_dir, - &timelock_pkg.package.compiled_docs.unwrap(), - &mut files_to_write, - ); - for (fname, doc) in files_to_write { - let mut dst_path = PathBuf::from(DOCS_DIR); - dst_path.push(fname); - fs::create_dir_all(dst_path.parent().unwrap()).unwrap(); - fs::write(dst_path, doc).unwrap(); - } - } -} - -/// Post process the generated docs so that they are in a format that can be -/// consumed by docusaurus. -/// * Flatten out the tree-like structure of the docs directory that we generate -/// for a package into a flat list of packages; -/// * Deduplicate packages (since multiple packages could share dependencies); -/// and -/// * Write out the package docs in a flat directory structure. -fn relocate_docs(prefix: &str, files: &[(String, String)], output: &mut BTreeMap) { - // Turn on multi-line mode so that `.` matches newlines, consume from the start - // of the file to beginning of the heading, then capture the heading and - // replace with the yaml tag for docusaurus. E.g., ``` - // - - // - - // -# Module `0x2::display` - // - - // +--- - // +title: Module `0x2::display` - // +--- - //``` - let re = regex::Regex::new(r"(?s).*\n#\s+(.*?)\n").unwrap(); - for (file_name, file_content) in files { - let path = PathBuf::from(file_name); - let top_level = path.components().count() == 1; - let file_name = if top_level { - let mut new_path = PathBuf::from(prefix); - new_path.push(file_name); - new_path.to_string_lossy().to_string() - } else { - let mut new_path = PathBuf::new(); - new_path.push(path.components().skip(1).collect::()); - new_path.to_string_lossy().to_string() - }; - output.entry(file_name).or_insert_with(|| { - re.replace_all( - &file_content - .replace("../../dependencies/", "../") - .replace("dependencies/", "../"), - "---\ntitle: $1\n---\n", - ) - .to_string() - }); - } -} - -fn serialize_modules_to_file<'a>( - modules: impl Iterator, - file: &Path, -) -> Result<()> { - let mut serialized_modules = Vec::new(); - for module in modules { - let mut buf = Vec::new(); - module.serialize(&mut buf)?; - serialized_modules.push(buf); - } - assert!( - !serialized_modules.is_empty(), - "Failed to find system or framework or stdlib modules" - ); - - let binary = bcs::to_bytes(&serialized_modules)?; - - fs::write(file, binary)?; - - Ok(()) -} diff --git a/crates/sui-framework/docs/deepbook/clob.md b/crates/sui-framework/docs/deepbook/clob.md deleted file mode 100644 index a555ee20872..00000000000 --- a/crates/sui-framework/docs/deepbook/clob.md +++ /dev/null @@ -1,2535 +0,0 @@ ---- -title: Module `0xdee9::clob` ---- - - - -- [Struct `PoolCreated`](#0xdee9_clob_PoolCreated) -- [Struct `OrderPlacedV2`](#0xdee9_clob_OrderPlacedV2) -- [Struct `OrderCanceled`](#0xdee9_clob_OrderCanceled) -- [Struct `OrderFilledV2`](#0xdee9_clob_OrderFilledV2) -- [Struct `Order`](#0xdee9_clob_Order) -- [Struct `TickLevel`](#0xdee9_clob_TickLevel) -- [Resource `Pool`](#0xdee9_clob_Pool) -- [Struct `OrderPlaced`](#0xdee9_clob_OrderPlaced) -- [Struct `OrderFilled`](#0xdee9_clob_OrderFilled) -- [Constants](#@Constants_0) -- [Function `destroy_empty_level`](#0xdee9_clob_destroy_empty_level) -- [Function `create_account`](#0xdee9_clob_create_account) -- [Function `create_pool`](#0xdee9_clob_create_pool) -- [Function `deposit_base`](#0xdee9_clob_deposit_base) -- [Function `deposit_quote`](#0xdee9_clob_deposit_quote) -- [Function `withdraw_base`](#0xdee9_clob_withdraw_base) -- [Function `withdraw_quote`](#0xdee9_clob_withdraw_quote) -- [Function `swap_exact_base_for_quote`](#0xdee9_clob_swap_exact_base_for_quote) -- [Function `swap_exact_quote_for_base`](#0xdee9_clob_swap_exact_quote_for_base) -- [Function `match_bid_with_quote_quantity`](#0xdee9_clob_match_bid_with_quote_quantity) -- [Function `match_bid`](#0xdee9_clob_match_bid) -- [Function `match_ask`](#0xdee9_clob_match_ask) -- [Function `place_market_order`](#0xdee9_clob_place_market_order) -- [Function `inject_limit_order`](#0xdee9_clob_inject_limit_order) -- [Function `place_limit_order`](#0xdee9_clob_place_limit_order) -- [Function `order_is_bid`](#0xdee9_clob_order_is_bid) -- [Function `emit_order_canceled`](#0xdee9_clob_emit_order_canceled) -- [Function `emit_order_filled`](#0xdee9_clob_emit_order_filled) -- [Function `cancel_order`](#0xdee9_clob_cancel_order) -- [Function `remove_order`](#0xdee9_clob_remove_order) -- [Function `cancel_all_orders`](#0xdee9_clob_cancel_all_orders) -- [Function `batch_cancel_order`](#0xdee9_clob_batch_cancel_order) -- [Function `list_open_orders`](#0xdee9_clob_list_open_orders) -- [Function `account_balance`](#0xdee9_clob_account_balance) -- [Function `get_market_price`](#0xdee9_clob_get_market_price) -- [Function `get_level2_book_status_bid_side`](#0xdee9_clob_get_level2_book_status_bid_side) -- [Function `get_level2_book_status_ask_side`](#0xdee9_clob_get_level2_book_status_ask_side) -- [Function `get_level2_book_status`](#0xdee9_clob_get_level2_book_status) -- [Function `get_order_status`](#0xdee9_clob_get_order_status) - - -
    use 0x1::option;
    -use 0x1::type_name;
    -use 0x2::balance;
    -use 0x2::clock;
    -use 0x2::coin;
    -use 0x2::event;
    -use 0x2::linked_table;
    -use 0x2::object;
    -use 0x2::sui;
    -use 0x2::table;
    -use 0x2::tx_context;
    -use 0xdee9::critbit;
    -use 0xdee9::custodian;
    -use 0xdee9::math;
    -
    - - - - - -## Struct `PoolCreated` - -Emitted when a new pool is created - - -
    struct PoolCreated has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -pool_id: object::ID -
    -
    - object ID of the newly created pool -
    -
    -base_asset: type_name::TypeName -
    -
    - -
    -
    -quote_asset: type_name::TypeName -
    -
    - -
    -
    -taker_fee_rate: u64 -
    -
    - -
    -
    -maker_rebate_rate: u64 -
    -
    - -
    -
    -tick_size: u64 -
    -
    - -
    -
    -lot_size: u64 -
    -
    - -
    -
    - - -
    - - - -## Struct `OrderPlacedV2` - -Emitted when a maker order is injected into the order book. - - -
    struct OrderPlacedV2<BaseAsset, QuoteAsset> has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -pool_id: object::ID -
    -
    - object ID of the pool the order was placed on -
    -
    -order_id: u64 -
    -
    - ID of the order within the pool -
    -
    -is_bid: bool -
    -
    - -
    -
    -owner: object::ID -
    -
    - object ID of the AccountCap that placed the order -
    -
    -base_asset_quantity_placed: u64 -
    -
    - -
    -
    -price: u64 -
    -
    - -
    -
    -expire_timestamp: u64 -
    -
    - -
    -
    - - -
    - - - -## Struct `OrderCanceled` - -Emitted when a maker order is canceled. - - -
    struct OrderCanceled<BaseAsset, QuoteAsset> has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -pool_id: object::ID -
    -
    - object ID of the pool the order was placed on -
    -
    -order_id: u64 -
    -
    - ID of the order within the pool -
    -
    -is_bid: bool -
    -
    - -
    -
    -owner: object::ID -
    -
    - object ID of the AccountCap that placed the order -
    -
    -base_asset_quantity_canceled: u64 -
    -
    - -
    -
    -price: u64 -
    -
    - -
    -
    - - -
    - - - -## Struct `OrderFilledV2` - -Emitted only when a maker order is filled. - - -
    struct OrderFilledV2<BaseAsset, QuoteAsset> has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -pool_id: object::ID -
    -
    - object ID of the pool the order was placed on -
    -
    -order_id: u64 -
    -
    - ID of the order within the pool -
    -
    -is_bid: bool -
    -
    - -
    -
    -owner: object::ID -
    -
    - object ID of the AccountCap that placed the order -
    -
    -total_quantity: u64 -
    -
    - -
    -
    -base_asset_quantity_filled: u64 -
    -
    - -
    -
    -base_asset_quantity_remaining: u64 -
    -
    - -
    -
    -price: u64 -
    -
    - -
    -
    -taker_commission: u64 -
    -
    - -
    -
    -maker_rebates: u64 -
    -
    - -
    -
    - - -
    - - - -## Struct `Order` - - - -
    struct Order has drop, store
    -
    - - - -
    -Fields - - -
    -
    -order_id: u64 -
    -
    - -
    -
    -price: u64 -
    -
    - -
    -
    -quantity: u64 -
    -
    - -
    -
    -is_bid: bool -
    -
    - -
    -
    -owner: object::ID -
    -
    - -
    -
    -expire_timestamp: u64 -
    -
    - -
    -
    - - -
    - - - -## Struct `TickLevel` - - - -
    struct TickLevel has store
    -
    - - - -
    -Fields - - -
    -
    -price: u64 -
    -
    - -
    -
    -open_orders: linked_table::LinkedTable<u64, clob::Order> -
    -
    - -
    -
    - - -
    - - - -## Resource `Pool` - - - -
    struct Pool<BaseAsset, QuoteAsset> has key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -bids: critbit::CritbitTree<clob::TickLevel> -
    -
    - -
    -
    -asks: critbit::CritbitTree<clob::TickLevel> -
    -
    - -
    -
    -next_bid_order_id: u64 -
    -
    - -
    -
    -next_ask_order_id: u64 -
    -
    - -
    -
    -usr_open_orders: table::Table<object::ID, linked_table::LinkedTable<u64, u64>> -
    -
    - -
    -
    -taker_fee_rate: u64 -
    -
    - -
    -
    -maker_rebate_rate: u64 -
    -
    - -
    -
    -tick_size: u64 -
    -
    - -
    -
    -lot_size: u64 -
    -
    - -
    -
    -base_custodian: custodian::Custodian<BaseAsset> -
    -
    - -
    -
    -quote_custodian: custodian::Custodian<QuoteAsset> -
    -
    - -
    -
    -creation_fee: balance::Balance<sui::SUI> -
    -
    - -
    -
    -base_asset_trading_fees: balance::Balance<BaseAsset> -
    -
    - -
    -
    -quote_asset_trading_fees: balance::Balance<QuoteAsset> -
    -
    - -
    -
    - - -
    - - - -## Struct `OrderPlaced` - -Deprecated since v1.0.0, use OrderPlacedV2 instead. - - -
    struct OrderPlaced<BaseAsset, QuoteAsset> has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -pool_id: object::ID -
    -
    - object ID of the pool the order was placed on -
    -
    -order_id: u64 -
    -
    - ID of the order within the pool -
    -
    -is_bid: bool -
    -
    - -
    -
    -owner: object::ID -
    -
    - object ID of the AccountCap that placed the order -
    -
    -base_asset_quantity_placed: u64 -
    -
    - -
    -
    -price: u64 -
    -
    - -
    -
    - - -
    - - - -## Struct `OrderFilled` - -Deprecated since v1.0.0, use OrderFilledV2 instead. - - -
    struct OrderFilled<BaseAsset, QuoteAsset> has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -pool_id: object::ID -
    -
    - object ID of the pool the order was placed on -
    -
    -order_id: u64 -
    -
    - ID of the order within the pool -
    -
    -is_bid: bool -
    -
    - -
    -
    -owner: object::ID -
    -
    - object ID of the AccountCap that placed the order -
    -
    -total_quantity: u64 -
    -
    - -
    -
    -base_asset_quantity_filled: u64 -
    -
    - -
    -
    -base_asset_quantity_remaining: u64 -
    -
    - -
    -
    -price: u64 -
    -
    - -
    -
    - - -
    - - - -## Constants - - - - - - -
    const FLOAT_SCALING: u64 = 1000000000;
    -
    - - - - - - - -
    const DEPRECATED: u64 = 0;
    -
    - - - - - - - -
    const EInsufficientBaseCoin: u64 = 7;
    -
    - - - - - - - -
    const EInsufficientQuoteCoin: u64 = 8;
    -
    - - - - - - - -
    const EInvalidExpireTimestamp: u64 = 19;
    -
    - - - - - - - -
    const EInvalidOrderId: u64 = 3;
    -
    - - - - - - - -
    const EInvalidPrice: u64 = 5;
    -
    - - - - - - - -
    const EInvalidQuantity: u64 = 6;
    -
    - - - - - - - -
    const EInvalidRestriction: u64 = 14;
    -
    - - - - - - - -
    const EInvalidTickPrice: u64 = 11;
    -
    - - - - - - - -
    const EInvalidUser: u64 = 12;
    -
    - - - - - - - -
    const EOrderCannotBeFullyFilled: u64 = 9;
    -
    - - - - - - - -
    const EOrderCannotBeFullyPassive: u64 = 10;
    -
    - - - - - - - -
    const EUnauthorizedCancel: u64 = 4;
    -
    - - - - - - - -
    const FILL_OR_KILL: u8 = 2;
    -
    - - - - - - - -
    const IMMEDIATE_OR_CANCEL: u8 = 1;
    -
    - - - - - - - -
    const MAX_PRICE: u64 = 9223372036854775808;
    -
    - - - - - - - -
    const MIN_ASK_ORDER_ID: u64 = 9223372036854775808;
    -
    - - - - - - - -
    const MIN_PRICE: u64 = 0;
    -
    - - - - - - - -
    const NO_RESTRICTION: u8 = 0;
    -
    - - - - - - - -
    const POST_OR_ABORT: u8 = 3;
    -
    - - - - - -## Function `destroy_empty_level` - - - -
    fun destroy_empty_level(level: clob::TickLevel)
    -
    - - - -
    -Implementation - - -
    fun destroy_empty_level(level: TickLevel) {
    -    let TickLevel {
    -        price: _,
    -        open_orders: orders,
    -    } = level;
    -
    -    linked_table::destroy_empty(orders);
    -}
    -
    - - - -
    - - - -## Function `create_account` - - - -
    public fun create_account(_ctx: &mut tx_context::TxContext): custodian::AccountCap
    -
    - - - -
    -Implementation - - -
    public fun create_account(_ctx: &mut TxContext): AccountCap {
    -    abort DEPRECATED
    -}
    -
    - - - -
    - - - -## Function `create_pool` - - - -
    public fun create_pool<BaseAsset, QuoteAsset>(_tick_size: u64, _lot_size: u64, _creation_fee: coin::Coin<sui::SUI>, _ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public fun create_pool<BaseAsset, QuoteAsset>(
    -    _tick_size: u64,
    -    _lot_size: u64,
    -    _creation_fee: Coin<SUI>,
    -    _ctx: &mut TxContext,
    -) {
    -    abort DEPRECATED
    -}
    -
    - - - -
    - - - -## Function `deposit_base` - - - -
    public fun deposit_base<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, coin: coin::Coin<BaseAsset>, account_cap: &custodian::AccountCap)
    -
    - - - -
    -Implementation - - -
    public fun deposit_base<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    coin: Coin<BaseAsset>,
    -    account_cap: &AccountCap
    -) {
    -    assert!(coin::value(&coin) != 0, EInsufficientBaseCoin);
    -    custodian::increase_user_available_balance(
    -        &mut pool.base_custodian,
    -        object::id(account_cap),
    -        coin::into_balance(coin)
    -    )
    -}
    -
    - - - -
    - - - -## Function `deposit_quote` - - - -
    public fun deposit_quote<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, coin: coin::Coin<QuoteAsset>, account_cap: &custodian::AccountCap)
    -
    - - - -
    -Implementation - - -
    public fun deposit_quote<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    coin: Coin<QuoteAsset>,
    -    account_cap: &AccountCap
    -) {
    -    assert!(coin::value(&coin) != 0, EInsufficientQuoteCoin);
    -    custodian::increase_user_available_balance(
    -        &mut pool.quote_custodian,
    -        object::id(account_cap),
    -        coin::into_balance(coin)
    -    )
    -}
    -
    - - - -
    - - - -## Function `withdraw_base` - - - -
    public fun withdraw_base<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, quantity: u64, account_cap: &custodian::AccountCap, ctx: &mut tx_context::TxContext): coin::Coin<BaseAsset>
    -
    - - - -
    -Implementation - - -
    public fun withdraw_base<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    quantity: u64,
    -    account_cap: &AccountCap,
    -    ctx: &mut TxContext
    -): Coin<BaseAsset> {
    -    assert!(quantity > 0, EInvalidQuantity);
    -    custodian::withdraw_asset(&mut pool.base_custodian, quantity, account_cap, ctx)
    -}
    -
    - - - -
    - - - -## Function `withdraw_quote` - - - -
    public fun withdraw_quote<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, quantity: u64, account_cap: &custodian::AccountCap, ctx: &mut tx_context::TxContext): coin::Coin<QuoteAsset>
    -
    - - - -
    -Implementation - - -
    public fun withdraw_quote<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    quantity: u64,
    -    account_cap: &AccountCap,
    -    ctx: &mut TxContext
    -): Coin<QuoteAsset> {
    -    assert!(quantity > 0, EInvalidQuantity);
    -    custodian::withdraw_asset(&mut pool.quote_custodian, quantity, account_cap, ctx)
    -}
    -
    - - - -
    - - - -## Function `swap_exact_base_for_quote` - - - -
    public fun swap_exact_base_for_quote<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, quantity: u64, base_coin: coin::Coin<BaseAsset>, quote_coin: coin::Coin<QuoteAsset>, clock: &clock::Clock, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, u64)
    -
    - - - -
    -Implementation - - -
    public fun swap_exact_base_for_quote<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    quantity: u64,
    -    base_coin: Coin<BaseAsset>,
    -    quote_coin: Coin<QuoteAsset>,
    -    clock: &Clock,
    -    ctx: &mut TxContext,
    -): (Coin<BaseAsset>, Coin<QuoteAsset>, u64) {
    -    assert!(quantity > 0, EInvalidQuantity);
    -    assert!(coin::value(&base_coin) >= quantity, EInsufficientBaseCoin);
    -    let original_val = coin::value("e_coin);
    -    let (ret_base_coin, ret_quote_coin) = place_market_order(
    -        pool,
    -        quantity,
    -        false,
    -        base_coin,
    -        quote_coin,
    -        clock,
    -        ctx
    -    );
    -    let ret_val = coin::value(&ret_quote_coin);
    -    (ret_base_coin, ret_quote_coin, ret_val - original_val)
    -}
    -
    - - - -
    - - - -## Function `swap_exact_quote_for_base` - - - -
    public fun swap_exact_quote_for_base<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, quantity: u64, clock: &clock::Clock, quote_coin: coin::Coin<QuoteAsset>, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>, u64)
    -
    - - - -
    -Implementation - - -
    public fun swap_exact_quote_for_base<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    quantity: u64,
    -    clock: &Clock,
    -    quote_coin: Coin<QuoteAsset>,
    -    ctx: &mut TxContext,
    -): (Coin<BaseAsset>, Coin<QuoteAsset>, u64) {
    -    assert!(quantity > 0, EInvalidQuantity);
    -    assert!(coin::value("e_coin) >= quantity, EInsufficientQuoteCoin);
    -    let (base_asset_balance, quote_asset_balance) = match_bid_with_quote_quantity(
    -        pool,
    -        quantity,
    -        MAX_PRICE,
    -        clock::timestamp_ms(clock),
    -        coin::into_balance(quote_coin)
    -    );
    -    let val = balance::value(&base_asset_balance);
    -    (coin::from_balance(base_asset_balance, ctx), coin::from_balance(quote_asset_balance, ctx), val)
    -}
    -
    - - - -
    - - - -## Function `match_bid_with_quote_quantity` - - - -
    fun match_bid_with_quote_quantity<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, quantity: u64, price_limit: u64, current_timestamp: u64, quote_balance: balance::Balance<QuoteAsset>): (balance::Balance<BaseAsset>, balance::Balance<QuoteAsset>)
    -
    - - - -
    -Implementation - - -
    fun match_bid_with_quote_quantity<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    quantity: u64,
    -    price_limit: u64,
    -    current_timestamp: u64,
    -    quote_balance: Balance<QuoteAsset>,
    -): (Balance<BaseAsset>, Balance<QuoteAsset>) {
    -    // Base balance received by taker, taking into account of taker commission.
    -    // Need to individually keep track of the remaining base quantity to be filled to avoid infinite loop.
    -    let pool_id = *object::uid_as_inner(&pool.id);
    -    let mut taker_quote_quantity_remaining = quantity;
    -    let mut base_balance_filled = balance::zero<BaseAsset>();
    -    let mut quote_balance_left = quote_balance;
    -    let all_open_orders = &mut pool.asks;
    -    if (critbit::is_empty(all_open_orders)) {
    -        return (base_balance_filled, quote_balance_left)
    -    };
    -    let (mut tick_price, mut tick_index) = min_leaf(all_open_orders);
    -    let mut terminate_loop = false;
    -
    -    while (!is_empty<TickLevel>(all_open_orders) && tick_price <= price_limit) {
    -        let tick_level = borrow_mut_leaf_by_index(all_open_orders, tick_index);
    -        let mut order_id = *option::borrow(linked_table::front(&tick_level.open_orders));
    -
    -        while (!linked_table::is_empty(&tick_level.open_orders)) {
    -            let maker_order = linked_table::borrow(&tick_level.open_orders, order_id);
    -            let mut maker_base_quantity = maker_order.quantity;
    -            let mut skip_order = false;
    -
    -            if (maker_order.expire_timestamp <= current_timestamp) {
    -                skip_order = true;
    -                custodian::unlock_balance(&mut pool.base_custodian, maker_order.owner, maker_order.quantity);
    -                emit_order_canceled<BaseAsset, QuoteAsset>(pool_id, maker_order);
    -            } else {
    -                // Calculate how much quote asset (maker_quote_quantity) is required, including the commission, to fill the maker order.
    -                let maker_quote_quantity_without_commission = clob_math::mul(
    -                    maker_base_quantity,
    -                    maker_order.price
    -                );
    -                let (is_round_down, mut taker_commission)  = clob_math::unsafe_mul_round(
    -                    maker_quote_quantity_without_commission,
    -                    pool.taker_fee_rate
    -                );
    -                if (is_round_down)  taker_commission = taker_commission + 1;
    -
    -                let maker_quote_quantity = maker_quote_quantity_without_commission + taker_commission;
    -
    -                // Total base quantity filled.
    -                let mut filled_base_quantity: u64;
    -                // Total quote quantity filled, excluding commission and rebate.
    -                let mut filled_quote_quantity: u64;
    -                // Total quote quantity paid by taker.
    -                // filled_quote_quantity_without_commission * (FLOAT_SCALING + taker_fee_rate) = filled_quote_quantity
    -                let mut filled_quote_quantity_without_commission: u64;
    -                if (taker_quote_quantity_remaining > maker_quote_quantity) {
    -                    filled_quote_quantity = maker_quote_quantity;
    -                    filled_quote_quantity_without_commission = maker_quote_quantity_without_commission;
    -                    filled_base_quantity = maker_base_quantity;
    -                } else {
    -                    terminate_loop = true;
    -                    // if not enough quote quantity to pay for taker commission, then no quantity will be filled
    -                    filled_quote_quantity_without_commission = clob_math::unsafe_div(
    -                        taker_quote_quantity_remaining,
    -                        FLOAT_SCALING + pool.taker_fee_rate
    -                    );
    -                    // filled_base_quantity = 0 is permitted since filled_quote_quantity_without_commission can be 0
    -                    filled_base_quantity = clob_math::unsafe_div(
    -                        filled_quote_quantity_without_commission,
    -                        maker_order.price
    -                    );
    -                    let filled_base_lot = filled_base_quantity / pool.lot_size;
    -                    filled_base_quantity = filled_base_lot * pool.lot_size;
    -                    // filled_quote_quantity_without_commission = 0 is permitted here since filled_base_quantity could be 0
    -                    filled_quote_quantity_without_commission = clob_math::unsafe_mul(
    -                        filled_base_quantity,
    -                        maker_order.price
    -                    );
    -                    // if taker_commission = 0 due to underflow, round it up to 1
    -                    let (round_down, mut taker_commission) = clob_math::unsafe_mul_round(
    -                        filled_quote_quantity_without_commission,
    -                        pool.taker_fee_rate
    -                    );
    -                    if (round_down) {
    -                        taker_commission = taker_commission + 1;
    -                    };
    -                    filled_quote_quantity = filled_quote_quantity_without_commission + taker_commission;
    -                };
    -                // if maker_rebate = 0 due to underflow, maker will not receive a rebate
    -                let maker_rebate = clob_math::unsafe_mul(
    -                    filled_quote_quantity_without_commission,
    -                    pool.maker_rebate_rate
    -                );
    -                maker_base_quantity = maker_base_quantity - filled_base_quantity;
    -
    -                // maker in ask side, decrease maker's locked base asset, increase maker's available quote asset
    -                taker_quote_quantity_remaining = taker_quote_quantity_remaining - filled_quote_quantity;
    -                let locked_base_balance = custodian::decrease_user_locked_balance<BaseAsset>(
    -                    &mut pool.base_custodian,
    -                    maker_order.owner,
    -                    filled_base_quantity
    -                );
    -
    -                let mut quote_balance_filled = balance::split(
    -                    &mut quote_balance_left,
    -                    filled_quote_quantity,
    -                );
    -                // Send quote asset including rebate to maker.
    -                custodian::increase_user_available_balance<QuoteAsset>(
    -                    &mut pool.quote_custodian,
    -                    maker_order.owner,
    -                    balance::split(
    -                        &mut quote_balance_filled,
    -                        maker_rebate + filled_quote_quantity_without_commission,
    -                    ),
    -                );
    -                // Send remaining of commission - rebate to the protocol.
    -                // commission - rebate = filled_quote_quantity_without_commission - filled_quote_quantity - maker_rebate
    -                balance::join(&mut pool.quote_asset_trading_fees, quote_balance_filled);
    -                balance::join(&mut base_balance_filled, locked_base_balance);
    -
    -                emit_order_filled<BaseAsset, QuoteAsset>(
    -                    *object::uid_as_inner(&pool.id),
    -                    maker_order,
    -                    filled_base_quantity,
    -                    // taker_commission = filled_quote_quantity - filled_quote_quantity_without_commission
    -                    // This guarantees that the subtraction will not underflow
    -                    filled_quote_quantity - filled_quote_quantity_without_commission,
    -                    maker_rebate
    -                )
    -            };
    -
    -            if (skip_order || maker_base_quantity == 0) {
    -                // Remove the maker order.
    -                let old_order_id = order_id;
    -                let maybe_order_id = linked_table::next(&tick_level.open_orders, order_id);
    -                if (!option::is_none(maybe_order_id)) {
    -                    order_id = *option::borrow(maybe_order_id);
    -                };
    -                let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, maker_order.owner);
    -                linked_table::remove(usr_open_order_ids, old_order_id);
    -                linked_table::remove(&mut tick_level.open_orders, old_order_id);
    -            } else {
    -                // Update the maker order.
    -                let maker_order_mut = linked_table::borrow_mut(
    -                    &mut tick_level.open_orders,
    -                    order_id);
    -                maker_order_mut.quantity = maker_base_quantity;
    -            };
    -            if (terminate_loop) {
    -                break
    -            };
    -        };
    -        if (linked_table::is_empty(&tick_level.open_orders)) {
    -            (tick_price, _) = next_leaf(all_open_orders, tick_price);
    -            destroy_empty_level(remove_leaf_by_index(all_open_orders, tick_index));
    -            (_, tick_index) = find_leaf(all_open_orders, tick_price);
    -        };
    -        if (terminate_loop) {
    -            break
    -        };
    -    };
    -    return (base_balance_filled, quote_balance_left)
    -}
    -
    - - - -
    - - - -## Function `match_bid` - - - -
    fun match_bid<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, quantity: u64, price_limit: u64, current_timestamp: u64, quote_balance: balance::Balance<QuoteAsset>): (balance::Balance<BaseAsset>, balance::Balance<QuoteAsset>)
    -
    - - - -
    -Implementation - - -
    fun match_bid<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    quantity: u64,
    -    price_limit: u64,
    -    current_timestamp: u64,
    -    quote_balance: Balance<QuoteAsset>,
    -): (Balance<BaseAsset>, Balance<QuoteAsset>) {
    -    let pool_id = *object::uid_as_inner(&pool.id);
    -    // Base balance received by taker.
    -    // Need to individually keep track of the remaining base quantity to be filled to avoid infinite loop.
    -    let mut taker_base_quantity_remaining = quantity;
    -    let mut base_balance_filled = balance::zero<BaseAsset>();
    -    let mut quote_balance_left = quote_balance;
    -    let all_open_orders = &mut pool.asks;
    -    if (critbit::is_empty(all_open_orders)) {
    -        return (base_balance_filled, quote_balance_left)
    -    };
    -    let (mut tick_price, mut tick_index) = min_leaf(all_open_orders);
    -
    -    while (!is_empty<TickLevel>(all_open_orders) && tick_price <= price_limit) {
    -        let tick_level = borrow_mut_leaf_by_index(all_open_orders, tick_index);
    -        let mut order_id = *option::borrow(linked_table::front(&tick_level.open_orders));
    -
    -        while (!linked_table::is_empty(&tick_level.open_orders)) {
    -            let maker_order = linked_table::borrow(&tick_level.open_orders, order_id);
    -            let mut maker_base_quantity = maker_order.quantity;
    -            let mut skip_order = false;
    -
    -            if (maker_order.expire_timestamp <= current_timestamp) {
    -                skip_order = true;
    -                custodian::unlock_balance(&mut pool.base_custodian, maker_order.owner, maker_order.quantity);
    -                emit_order_canceled<BaseAsset, QuoteAsset>(pool_id, maker_order);
    -            } else {
    -                let filled_base_quantity =
    -                    if (taker_base_quantity_remaining > maker_base_quantity) { maker_base_quantity }
    -                    else { taker_base_quantity_remaining };
    -
    -                let filled_quote_quantity = clob_math::mul(filled_base_quantity, maker_order.price);
    -
    -                // if maker_rebate = 0 due to underflow, maker will not receive a rebate
    -                let maker_rebate = clob_math::unsafe_mul(filled_quote_quantity, pool.maker_rebate_rate);
    -                // if taker_commission = 0 due to underflow, round it up to 1
    -                let (is_round_down, mut taker_commission) = clob_math::unsafe_mul_round(
    -                    filled_quote_quantity,
    -                    pool.taker_fee_rate
    -                );
    -                if (is_round_down) taker_commission = taker_commission + 1;
    -
    -                maker_base_quantity = maker_base_quantity - filled_base_quantity;
    -
    -                // maker in ask side, decrease maker's locked base asset, increase maker's available quote asset
    -                taker_base_quantity_remaining = taker_base_quantity_remaining - filled_base_quantity;
    -                let locked_base_balance = custodian::decrease_user_locked_balance<BaseAsset>(
    -                    &mut pool.base_custodian,
    -                    maker_order.owner,
    -                    filled_base_quantity
    -                );
    -                let mut taker_commission_balance = balance::split(
    -                    &mut quote_balance_left,
    -                    taker_commission,
    -                );
    -                custodian::increase_user_available_balance<QuoteAsset>(
    -                    &mut pool.quote_custodian,
    -                    maker_order.owner,
    -                    balance::split(
    -                        &mut taker_commission_balance,
    -                        maker_rebate,
    -                    ),
    -                );
    -                balance::join(&mut pool.quote_asset_trading_fees, taker_commission_balance);
    -                balance::join(&mut base_balance_filled, locked_base_balance);
    -
    -                custodian::increase_user_available_balance<QuoteAsset>(
    -                    &mut pool.quote_custodian,
    -                    maker_order.owner,
    -                    balance::split(
    -                        &mut quote_balance_left,
    -                        filled_quote_quantity,
    -                    ),
    -                );
    -
    -                emit_order_filled<BaseAsset, QuoteAsset>(
    -                    *object::uid_as_inner(&pool.id),
    -                    maker_order,
    -                    filled_base_quantity,
    -                    taker_commission,
    -                    maker_rebate
    -                );
    -            };
    -
    -            if (skip_order || maker_base_quantity == 0) {
    -                // Remove the maker order.
    -                let old_order_id = order_id;
    -                let maybe_order_id = linked_table::next(&tick_level.open_orders, order_id);
    -                if (!option::is_none(maybe_order_id)) {
    -                    order_id = *option::borrow(maybe_order_id);
    -                };
    -                let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, maker_order.owner);
    -                linked_table::remove(usr_open_order_ids, old_order_id);
    -                linked_table::remove(&mut tick_level.open_orders, old_order_id);
    -            } else {
    -                // Update the maker order.
    -                let maker_order_mut = linked_table::borrow_mut(
    -                    &mut tick_level.open_orders,
    -                    order_id);
    -                maker_order_mut.quantity = maker_base_quantity;
    -            };
    -            if (taker_base_quantity_remaining == 0) {
    -                break
    -            };
    -        };
    -        if (linked_table::is_empty(&tick_level.open_orders)) {
    -            (tick_price, _) = next_leaf(all_open_orders, tick_price);
    -            destroy_empty_level(remove_leaf_by_index(all_open_orders, tick_index));
    -            (_, tick_index) = find_leaf(all_open_orders, tick_price);
    -        };
    -        if (taker_base_quantity_remaining == 0) {
    -            break
    -        };
    -    };
    -    return (base_balance_filled, quote_balance_left)
    -}
    -
    - - - -
    - - - -## Function `match_ask` - - - -
    fun match_ask<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, price_limit: u64, current_timestamp: u64, base_balance: balance::Balance<BaseAsset>): (balance::Balance<BaseAsset>, balance::Balance<QuoteAsset>)
    -
    - - - -
    -Implementation - - -
    fun match_ask<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    price_limit: u64,
    -    current_timestamp: u64,
    -    base_balance: Balance<BaseAsset>,
    -): (Balance<BaseAsset>, Balance<QuoteAsset>) {
    -    let pool_id = *object::uid_as_inner(&pool.id);
    -    let mut base_balance_left = base_balance;
    -    // Base balance received by taker, taking into account of taker commission.
    -    let mut quote_balance_filled = balance::zero<QuoteAsset>();
    -    let all_open_orders = &mut pool.bids;
    -    if (critbit::is_empty(all_open_orders)) {
    -        return (base_balance_left, quote_balance_filled)
    -    };
    -    let (mut tick_price, mut tick_index) = max_leaf(all_open_orders);
    -    while (!is_empty<TickLevel>(all_open_orders) && tick_price >= price_limit) {
    -        let tick_level = borrow_mut_leaf_by_index(all_open_orders, tick_index);
    -        let mut order_id = *option::borrow(linked_table::front(&tick_level.open_orders));
    -        while (!linked_table::is_empty(&tick_level.open_orders)) {
    -            let maker_order = linked_table::borrow(&tick_level.open_orders, order_id);
    -            let mut maker_base_quantity = maker_order.quantity;
    -            let mut skip_order = false;
    -
    -            if (maker_order.expire_timestamp <= current_timestamp) {
    -                skip_order = true;
    -                let maker_quote_quantity = clob_math::mul(maker_order.quantity, maker_order.price);
    -                custodian::unlock_balance(&mut pool.quote_custodian, maker_order.owner, maker_quote_quantity);
    -                emit_order_canceled<BaseAsset, QuoteAsset>(pool_id, maker_order);
    -            } else {
    -                let taker_base_quantity_remaining = balance::value(&base_balance_left);
    -                let filled_base_quantity =
    -                    if (taker_base_quantity_remaining >= maker_base_quantity) { maker_base_quantity }
    -                    else { taker_base_quantity_remaining };
    -
    -                let filled_quote_quantity = clob_math::mul(filled_base_quantity, maker_order.price);
    -
    -                // if maker_rebate = 0 due to underflow, maker will not receive a rebate
    -                let maker_rebate = clob_math::unsafe_mul(filled_quote_quantity, pool.maker_rebate_rate);
    -                // if taker_commission = 0 due to underflow, round it up to 1
    -                let (is_round_down, mut taker_commission) = clob_math::unsafe_mul_round(
    -                    filled_quote_quantity,
    -                    pool.taker_fee_rate
    -                );
    -                if (is_round_down) taker_commission = taker_commission + 1;
    -
    -                maker_base_quantity = maker_base_quantity - filled_base_quantity;
    -                // maker in bid side, decrease maker's locked quote asset, increase maker's available base asset
    -                let mut locked_quote_balance = custodian::decrease_user_locked_balance<QuoteAsset>(
    -                    &mut pool.quote_custodian,
    -                    maker_order.owner,
    -                    filled_quote_quantity
    -                );
    -                let mut taker_commission_balance = balance::split(
    -                    &mut locked_quote_balance,
    -                    taker_commission,
    -                );
    -                custodian::increase_user_available_balance<QuoteAsset>(
    -                    &mut pool.quote_custodian,
    -                    maker_order.owner,
    -                    balance::split(
    -                        &mut taker_commission_balance,
    -                        maker_rebate,
    -                    ),
    -                );
    -                balance::join(&mut pool.quote_asset_trading_fees, taker_commission_balance);
    -                balance::join(&mut quote_balance_filled, locked_quote_balance);
    -
    -                custodian::increase_user_available_balance<BaseAsset>(
    -                    &mut pool.base_custodian,
    -                    maker_order.owner,
    -                    balance::split(
    -                        &mut base_balance_left,
    -                        filled_base_quantity,
    -                    ),
    -                );
    -
    -                emit_order_filled<BaseAsset, QuoteAsset>(
    -                    *object::uid_as_inner(&pool.id),
    -                    maker_order,
    -                    filled_base_quantity,
    -                    taker_commission,
    -                    maker_rebate
    -                );
    -            };
    -
    -            if (skip_order || maker_base_quantity == 0) {
    -                // Remove the maker order.
    -                let old_order_id = order_id;
    -                let maybe_order_id = linked_table::next(&tick_level.open_orders, order_id);
    -                if (!option::is_none(maybe_order_id)) {
    -                    order_id = *option::borrow(maybe_order_id);
    -                };
    -                let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, maker_order.owner);
    -                linked_table::remove(usr_open_order_ids, old_order_id);
    -                linked_table::remove(&mut tick_level.open_orders, old_order_id);
    -            } else {
    -                // Update the maker order.
    -                let maker_order_mut = linked_table::borrow_mut(
    -                    &mut tick_level.open_orders,
    -                    order_id);
    -                maker_order_mut.quantity = maker_base_quantity;
    -            };
    -            if (balance::value(&base_balance_left) == 0) {
    -                break
    -            };
    -        };
    -        if (linked_table::is_empty(&tick_level.open_orders)) {
    -            (tick_price, _) = previous_leaf(all_open_orders, tick_price);
    -            destroy_empty_level(remove_leaf_by_index(all_open_orders, tick_index));
    -            (_, tick_index) = find_leaf(all_open_orders, tick_price);
    -        };
    -        if (balance::value(&base_balance_left) == 0) {
    -            break
    -        };
    -    };
    -    return (base_balance_left, quote_balance_filled)
    -}
    -
    - - - -
    - - - -## Function `place_market_order` - -Place a market order to the order book. - - -
    public fun place_market_order<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, quantity: u64, is_bid: bool, base_coin: coin::Coin<BaseAsset>, quote_coin: coin::Coin<QuoteAsset>, clock: &clock::Clock, ctx: &mut tx_context::TxContext): (coin::Coin<BaseAsset>, coin::Coin<QuoteAsset>)
    -
    - - - -
    -Implementation - - -
    public fun place_market_order<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    quantity: u64,
    -    is_bid: bool,
    -    mut base_coin: Coin<BaseAsset>,
    -    mut quote_coin: Coin<QuoteAsset>,
    -    clock: &Clock,
    -    ctx: &mut TxContext,
    -): (Coin<BaseAsset>, Coin<QuoteAsset>) {
    -    // If market bid order, match against the open ask orders. Otherwise, match against the open bid orders.
    -    // Take market bid order for example.
    -    // We first retrieve the PriceLevel with the lowest price by calling min_leaf on the asks Critbit Tree.
    -    // We then match the market order by iterating through open orders on that price level in ascending order of the order id.
    -    // Open orders that are being filled are removed from the order book.
    -    // We stop the iteration untill all quantities are filled.
    -    // If the total quantity of open orders at the lowest price level is not large enough to fully fill the market order,
    -    // we move on to the next price level by calling next_leaf on the asks Critbit Tree and repeat the same procedure.
    -    // Continue iterating over the price levels in ascending order until the market order is completely filled.
    -    // If ther market order cannot be completely filled even after consuming all the open ask orders,
    -    // the unfilled quantity will be cancelled.
    -    // Market ask order follows similar procedure.
    -    // The difference is that market ask order is matched against the open bid orders.
    -    // We start with the bid PriceLeve with the highest price by calling max_leaf on the bids Critbit Tree.
    -    // The inner loop for iterating over the open orders in ascending orders of order id is the same as above.
    -    // Then iterate over the price levels in descending order until the market order is completely filled.
    -    assert!(quantity % pool.lot_size == 0, EInvalidQuantity);
    -    assert!(quantity != 0, EInvalidQuantity);
    -    if (is_bid) {
    -        let (base_balance_filled, quote_balance_left) = match_bid(
    -            pool,
    -            quantity,
    -            MAX_PRICE,
    -            clock::timestamp_ms(clock),
    -            coin::into_balance(quote_coin),
    -        );
    -        join(
    -            &mut base_coin,
    -            coin::from_balance(base_balance_filled, ctx),
    -        );
    -        quote_coin = coin::from_balance(quote_balance_left, ctx);
    -    } else {
    -        assert!(quantity <= coin::value(&base_coin), EInsufficientBaseCoin);
    -        let (base_balance_left, quote_balance_filled) = match_ask(
    -            pool,
    -            MIN_PRICE,
    -            clock::timestamp_ms(clock),
    -            coin::into_balance(base_coin),
    -        );
    -        base_coin = coin::from_balance(base_balance_left, ctx);
    -        join(
    -            &mut quote_coin,
    -            coin::from_balance(quote_balance_filled, ctx),
    -        );
    -    };
    -    (base_coin, quote_coin)
    -}
    -
    - - - -
    - - - -## Function `inject_limit_order` - -Injects a maker order to the order book. -Returns the order id. - - -
    fun inject_limit_order<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, price: u64, quantity: u64, is_bid: bool, expire_timestamp: u64, account_cap: &custodian::AccountCap, ctx: &mut tx_context::TxContext): u64
    -
    - - - -
    -Implementation - - -
    fun inject_limit_order<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    price: u64,
    -    quantity: u64,
    -    is_bid: bool,
    -    expire_timestamp: u64,
    -    account_cap: &AccountCap,
    -    ctx: &mut TxContext
    -): u64 {
    -    let user = object::id(account_cap);
    -    let order_id: u64;
    -    let open_orders: &mut CritbitTree<TickLevel>;
    -    if (is_bid) {
    -        let quote_quantity = clob_math::mul(quantity, price);
    -        custodian::lock_balance<QuoteAsset>(&mut pool.quote_custodian, account_cap, quote_quantity);
    -        order_id = pool.next_bid_order_id;
    -        pool.next_bid_order_id = pool.next_bid_order_id + 1;
    -        open_orders = &mut pool.bids;
    -    } else {
    -        custodian::lock_balance<BaseAsset>(&mut pool.base_custodian, account_cap, quantity);
    -        order_id = pool.next_ask_order_id;
    -        pool.next_ask_order_id = pool.next_ask_order_id + 1;
    -        open_orders = &mut pool.asks;
    -    };
    -    let order = Order {
    -        order_id,
    -        price,
    -        quantity,
    -        is_bid,
    -        owner: user,
    -        expire_timestamp,
    -    };
    -    let (tick_exists, mut tick_index) = find_leaf(open_orders, price);
    -    if (!tick_exists) {
    -        tick_index = insert_leaf(
    -            open_orders,
    -            price,
    -            TickLevel {
    -                price,
    -                open_orders: linked_table::new(ctx),
    -            });
    -    };
    -
    -    let tick_level = borrow_mut_leaf_by_index(open_orders, tick_index);
    -    linked_table::push_back(&mut tick_level.open_orders, order_id, order);
    -    event::emit(OrderPlacedV2<BaseAsset, QuoteAsset> {
    -        pool_id: *object::uid_as_inner(&pool.id),
    -        order_id,
    -        is_bid,
    -        owner: user,
    -        base_asset_quantity_placed: quantity,
    -        price,
    -        expire_timestamp
    -    });
    -    if (!contains(&pool.usr_open_orders, user)) {
    -        add(&mut pool.usr_open_orders, user, linked_table::new(ctx));
    -    };
    -    linked_table::push_back(borrow_mut(&mut pool.usr_open_orders, user), order_id, price);
    -
    -    return order_id
    -}
    -
    - - - -
    - - - -## Function `place_limit_order` - -Place a limit order to the order book. -Returns (base quantity filled, quote quantity filled, whether a maker order is being placed, order id of the maker order). -When the limit order is not successfully placed, we return false to indicate that and also returns a meaningless order_id 0. -When the limit order is successfully placed, we return true to indicate that and also the corresponding order_id. -So please check that boolean value first before using the order id. - - -
    public fun place_limit_order<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, price: u64, quantity: u64, is_bid: bool, expire_timestamp: u64, restriction: u8, clock: &clock::Clock, account_cap: &custodian::AccountCap, ctx: &mut tx_context::TxContext): (u64, u64, bool, u64)
    -
    - - - -
    -Implementation - - -
    public fun place_limit_order<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    price: u64,
    -    quantity: u64,
    -    is_bid: bool,
    -    expire_timestamp: u64, // Expiration timestamp in ms in absolute value inclusive.
    -    restriction: u8,
    -    clock: &Clock,
    -    account_cap: &AccountCap,
    -    ctx: &mut TxContext
    -): (u64, u64, bool, u64) {
    -    // If limit bid order, check whether the price is lower than the lowest ask order by checking the min_leaf of asks Critbit Tree.
    -    // If so, assign the sequence id of the order to be next_bid_order_id and increment next_bid_order_id by 1.
    -    // Inject the new order to the bids Critbit Tree according to the price and order id.
    -    // Otherwise, find the price level from the asks Critbit Tree that is no greater than the input price.
    -    // Match the bid order against the asks Critbit Tree in the same way as a market order but up until the price level found in the previous step.
    -    // If the bid order is not completely filled, inject the remaining quantity to the bids Critbit Tree according to the input price and order id.
    -    // If limit ask order, vice versa.
    -    assert!(quantity > 0, EInvalidQuantity);
    -    assert!(price > 0, EInvalidPrice);
    -    assert!(price % pool.tick_size == 0, EInvalidPrice);
    -    assert!(quantity % pool.lot_size == 0, EInvalidQuantity);
    -    assert!(expire_timestamp > clock::timestamp_ms(clock), EInvalidExpireTimestamp);
    -    let user = object::id(account_cap);
    -    let base_quantity_filled;
    -    let quote_quantity_filled;
    -
    -    if (is_bid) {
    -        let quote_quantity_original = custodian::account_available_balance<QuoteAsset>(
    -            &pool.quote_custodian,
    -            user,
    -        );
    -        let quote_balance = custodian::decrease_user_available_balance<QuoteAsset>(
    -            &mut pool.quote_custodian,
    -            account_cap,
    -            quote_quantity_original,
    -        );
    -        let (base_balance_filled, quote_balance_left) = match_bid(
    -            pool,
    -            quantity,
    -            price,
    -            clock::timestamp_ms(clock),
    -            quote_balance,
    -        );
    -        base_quantity_filled = balance::value(&base_balance_filled);
    -        quote_quantity_filled = quote_quantity_original - balance::value("e_balance_left);
    -
    -        custodian::increase_user_available_balance<BaseAsset>(
    -            &mut pool.base_custodian,
    -            user,
    -            base_balance_filled,
    -        );
    -        custodian::increase_user_available_balance<QuoteAsset>(
    -            &mut pool.quote_custodian,
    -            user,
    -            quote_balance_left,
    -        );
    -    } else {
    -        let base_balance = custodian::decrease_user_available_balance<BaseAsset>(
    -            &mut pool.base_custodian,
    -            account_cap,
    -            quantity,
    -        );
    -        let (base_balance_left, quote_balance_filled) = match_ask(
    -            pool,
    -            price,
    -            clock::timestamp_ms(clock),
    -            base_balance,
    -        );
    -
    -        base_quantity_filled = quantity - balance::value(&base_balance_left);
    -        quote_quantity_filled = balance::value("e_balance_filled);
    -
    -        custodian::increase_user_available_balance<BaseAsset>(
    -            &mut pool.base_custodian,
    -            user,
    -            base_balance_left,
    -        );
    -        custodian::increase_user_available_balance<QuoteAsset>(
    -            &mut pool.quote_custodian,
    -            user,
    -            quote_balance_filled,
    -        );
    -    };
    -
    -    let order_id;
    -    if (restriction == IMMEDIATE_OR_CANCEL) {
    -        return (base_quantity_filled, quote_quantity_filled, false, 0)
    -    };
    -    if (restriction == FILL_OR_KILL) {
    -        assert!(base_quantity_filled == quantity, EOrderCannotBeFullyFilled);
    -        return (base_quantity_filled, quote_quantity_filled, false, 0)
    -    };
    -    if (restriction == POST_OR_ABORT) {
    -        assert!(base_quantity_filled == 0, EOrderCannotBeFullyPassive);
    -        order_id = inject_limit_order(pool, price, quantity, is_bid, expire_timestamp, account_cap, ctx);
    -        return (base_quantity_filled, quote_quantity_filled, true, order_id)
    -    } else {
    -        assert!(restriction == NO_RESTRICTION, EInvalidRestriction);
    -        if (quantity > base_quantity_filled) {
    -            order_id = inject_limit_order(
    -                pool,
    -                price,
    -                quantity - base_quantity_filled,
    -                is_bid,
    -                expire_timestamp,
    -                account_cap,
    -                ctx
    -            );
    -            return (base_quantity_filled, quote_quantity_filled, true, order_id)
    -        };
    -        return (base_quantity_filled, quote_quantity_filled, false, 0)
    -    }
    -}
    -
    - - - -
    - - - -## Function `order_is_bid` - - - -
    fun order_is_bid(order_id: u64): bool
    -
    - - - -
    -Implementation - - -
    fun order_is_bid(order_id: u64): bool {
    -    return order_id < MIN_ASK_ORDER_ID
    -}
    -
    - - - -
    - - - -## Function `emit_order_canceled` - - - -
    fun emit_order_canceled<BaseAsset, QuoteAsset>(pool_id: object::ID, order: &clob::Order)
    -
    - - - -
    -Implementation - - -
    fun emit_order_canceled<BaseAsset, QuoteAsset>(
    -    pool_id: ID,
    -    order: &Order
    -) {
    -    event::emit(OrderCanceled<BaseAsset, QuoteAsset> {
    -        pool_id,
    -        order_id: order.order_id,
    -        is_bid: order.is_bid,
    -        owner: order.owner,
    -        base_asset_quantity_canceled: order.quantity,
    -        price: order.price
    -    })
    -}
    -
    - - - -
    - - - -## Function `emit_order_filled` - - - -
    fun emit_order_filled<BaseAsset, QuoteAsset>(pool_id: object::ID, order: &clob::Order, base_asset_quantity_filled: u64, taker_commission: u64, maker_rebates: u64)
    -
    - - - -
    -Implementation - - -
    fun emit_order_filled<BaseAsset, QuoteAsset>(
    -    pool_id: ID,
    -    order: &Order,
    -    base_asset_quantity_filled: u64,
    -    taker_commission: u64,
    -    maker_rebates: u64
    -) {
    -    event::emit(OrderFilledV2<BaseAsset, QuoteAsset> {
    -        pool_id,
    -        order_id: order.order_id,
    -        is_bid: order.is_bid,
    -        owner: order.owner,
    -        total_quantity: order.quantity,
    -        base_asset_quantity_filled,
    -        // order.quantity = base_asset_quantity_filled + base_asset_quantity_remaining
    -        // This guarantees that the subtraction will not underflow
    -        base_asset_quantity_remaining: order.quantity - base_asset_quantity_filled,
    -        price: order.price,
    -        taker_commission,
    -        maker_rebates
    -    })
    -}
    -
    - - - -
    - - - -## Function `cancel_order` - -Cancel and opening order. -Abort if order_id is invalid or if the order is not submitted by the transaction sender. - - -
    public fun cancel_order<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, order_id: u64, account_cap: &custodian::AccountCap)
    -
    - - - -
    -Implementation - - -
    public fun cancel_order<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    order_id: u64,
    -    account_cap: &AccountCap
    -) {
    -    // First check the highest bit of the order id to see whether it's bid or ask.
    -    // Then retrieve the price using the order id.
    -    // Using the price to retrieve the corresponding PriceLevel from the bids / asks Critbit Tree.
    -    // Retrieve and remove the order from open orders of the PriceLevel.
    -    let user = object::id(account_cap);
    -    assert!(contains(&pool.usr_open_orders, user), EInvalidUser);
    -    let usr_open_orders = borrow_mut(&mut pool.usr_open_orders, user);
    -    assert!(linked_table::contains(usr_open_orders, order_id), EInvalidOrderId);
    -    let tick_price = *linked_table::borrow(usr_open_orders, order_id);
    -    let is_bid = order_is_bid(order_id);
    -    let (tick_exists, tick_index) = find_leaf(
    -        if (is_bid) { &pool.bids } else { &pool.asks },
    -        tick_price);
    -    assert!(tick_exists, EInvalidOrderId);
    -    let order = remove_order(
    -        if (is_bid) { &mut pool.bids } else { &mut pool.asks },
    -        usr_open_orders,
    -        tick_index,
    -        order_id,
    -        user
    -    );
    -    if (is_bid) {
    -        let balance_locked = clob_math::mul(order.quantity, order.price);
    -        custodian::unlock_balance(&mut pool.quote_custodian, user, balance_locked);
    -    } else {
    -        custodian::unlock_balance(&mut pool.base_custodian, user, order.quantity);
    -    };
    -    emit_order_canceled<BaseAsset, QuoteAsset>(*object::uid_as_inner(&pool.id), &order);
    -}
    -
    - - - -
    - - - -## Function `remove_order` - - - -
    fun remove_order(open_orders: &mut critbit::CritbitTree<clob::TickLevel>, usr_open_orders: &mut linked_table::LinkedTable<u64, u64>, tick_index: u64, order_id: u64, user: object::ID): clob::Order
    -
    - - - -
    -Implementation - - -
    fun remove_order(
    -    open_orders: &mut CritbitTree<TickLevel>,
    -    usr_open_orders: &mut LinkedTable<u64, u64>,
    -    tick_index: u64,
    -    order_id: u64,
    -    user: ID,
    -): Order {
    -    linked_table::remove(usr_open_orders, order_id);
    -    let tick_level = borrow_leaf_by_index(open_orders, tick_index);
    -    assert!(linked_table::contains(&tick_level.open_orders, order_id), EInvalidOrderId);
    -    let mut_tick_level = borrow_mut_leaf_by_index(open_orders, tick_index);
    -    let order = linked_table::remove(&mut mut_tick_level.open_orders, order_id);
    -    assert!(order.owner == user, EUnauthorizedCancel);
    -    if (linked_table::is_empty(&mut_tick_level.open_orders)) {
    -        destroy_empty_level(remove_leaf_by_index(open_orders, tick_index));
    -    };
    -    order
    -}
    -
    - - - -
    - - - -## Function `cancel_all_orders` - - - -
    public fun cancel_all_orders<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian::AccountCap)
    -
    - - - -
    -Implementation - - -
    public fun cancel_all_orders<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    account_cap: &AccountCap
    -) {
    -    let pool_id = *object::uid_as_inner(&pool.id);
    -    let user = object::id(account_cap);
    -    assert!(contains(&pool.usr_open_orders, user), EInvalidUser);
    -    let usr_open_order_ids = table::borrow_mut(&mut pool.usr_open_orders, user);
    -    while (!linked_table::is_empty(usr_open_order_ids)) {
    -        let order_id = *option::borrow(linked_table::back(usr_open_order_ids));
    -        let order_price = *linked_table::borrow(usr_open_order_ids, order_id);
    -        let is_bid = order_is_bid(order_id);
    -        let open_orders =
    -            if (is_bid) { &mut pool.bids }
    -            else { &mut pool.asks };
    -        let (_, tick_index) = critbit::find_leaf(open_orders, order_price);
    -        let order = remove_order(
    -            open_orders,
    -            usr_open_order_ids,
    -            tick_index,
    -            order_id,
    -            user
    -        );
    -        if (is_bid) {
    -            let balance_locked = clob_math::mul(order.quantity, order.price);
    -            custodian::unlock_balance(&mut pool.quote_custodian, user, balance_locked);
    -        } else {
    -            custodian::unlock_balance(&mut pool.base_custodian, user, order.quantity);
    -        };
    -        emit_order_canceled<BaseAsset, QuoteAsset>(pool_id, &order);
    -    };
    -}
    -
    - - - -
    - - - -## Function `batch_cancel_order` - -Batch cancel limit orders to save gas cost. -Abort if any of the order_ids are not submitted by the sender. -Skip any order_id that is invalid. -Note that this function can reduce gas cost even further if caller has multiple orders at the same price level, -and if orders with the same price are grouped together in the vector. -For example, if we have the following order_id to price mapping, {0: 100., 1: 200., 2: 100., 3: 200.}. -Grouping order_ids like [0, 2, 1, 3] would make it the most gas efficient. - - -
    public fun batch_cancel_order<BaseAsset, QuoteAsset>(pool: &mut clob::Pool<BaseAsset, QuoteAsset>, order_ids: vector<u64>, account_cap: &custodian::AccountCap)
    -
    - - - -
    -Implementation - - -
    public fun batch_cancel_order<BaseAsset, QuoteAsset>(
    -    pool: &mut Pool<BaseAsset, QuoteAsset>,
    -    order_ids: vector<u64>,
    -    account_cap: &AccountCap
    -) {
    -    let pool_id = *object::uid_as_inner(&pool.id);
    -    // First group the order ids according to price level,
    -    // so that we don't have to retrieve the PriceLevel multiple times if there are orders at the same price level.
    -    // Iterate over each price level, retrieve the corresponding PriceLevel.
    -    // Iterate over the order ids that need to be canceled at that price level,
    -    // retrieve and remove the order from open orders of the PriceLevel.
    -    let user = object::id(account_cap);
    -    assert!(contains(&pool.usr_open_orders, user), 0);
    -    let mut tick_index: u64 = 0;
    -    let mut tick_price: u64 = 0;
    -    let n_order = vector::length(&order_ids);
    -    let mut i_order = 0;
    -    let usr_open_orders = borrow_mut(&mut pool.usr_open_orders, user);
    -    while (i_order < n_order) {
    -        let order_id = *vector::borrow(&order_ids, i_order);
    -        assert!(linked_table::contains(usr_open_orders, order_id), EInvalidOrderId);
    -        let new_tick_price = *linked_table::borrow(usr_open_orders, order_id);
    -        let is_bid = order_is_bid(order_id);
    -        if (new_tick_price != tick_price) {
    -            tick_price = new_tick_price;
    -            let (tick_exists, new_tick_index) = find_leaf(
    -                if (is_bid) { &pool.bids } else { &pool.asks },
    -                tick_price
    -            );
    -            assert!(tick_exists, EInvalidTickPrice);
    -            tick_index = new_tick_index;
    -        };
    -        let order = remove_order(
    -            if (is_bid) { &mut pool.bids } else { &mut pool.asks },
    -            usr_open_orders,
    -            tick_index,
    -            order_id,
    -            user
    -        );
    -        if (is_bid) {
    -            let balance_locked = clob_math::mul(order.quantity, order.price);
    -            custodian::unlock_balance(&mut pool.quote_custodian, user, balance_locked);
    -        } else {
    -            custodian::unlock_balance(&mut pool.base_custodian, user, order.quantity);
    -        };
    -        emit_order_canceled<BaseAsset, QuoteAsset>(pool_id, &order);
    -        i_order = i_order + 1;
    -    }
    -}
    -
    - - - -
    - - - -## Function `list_open_orders` - - - -
    public fun list_open_orders<BaseAsset, QuoteAsset>(pool: &clob::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian::AccountCap): vector<clob::Order>
    -
    - - - -
    -Implementation - - -
    public fun list_open_orders<BaseAsset, QuoteAsset>(
    -    pool: &Pool<BaseAsset, QuoteAsset>,
    -    account_cap: &AccountCap
    -): vector<Order> {
    -    let user = object::id(account_cap);
    -    let usr_open_order_ids = table::borrow(&pool.usr_open_orders, user);
    -    let mut open_orders = vector::empty<Order>();
    -    let mut order_id = linked_table::front(usr_open_order_ids);
    -    while (!option::is_none(order_id)) {
    -        let order_price = *linked_table::borrow(usr_open_order_ids, *option::borrow(order_id));
    -        let tick_level =
    -            if (order_is_bid(*option::borrow(order_id))) borrow_leaf_by_key(&pool.bids, order_price)
    -            else borrow_leaf_by_key(&pool.asks, order_price);
    -        let order = linked_table::borrow(&tick_level.open_orders, *option::borrow(order_id));
    -        vector::push_back(&mut open_orders, Order {
    -            order_id: order.order_id,
    -            price: order.price,
    -            quantity: order.quantity,
    -            is_bid: order.is_bid,
    -            owner: order.owner,
    -            expire_timestamp: order.expire_timestamp
    -        });
    -        order_id = linked_table::next(usr_open_order_ids, *option::borrow(order_id));
    -    };
    -    open_orders
    -}
    -
    - - - -
    - - - -## Function `account_balance` - -query user balance inside custodian - - -
    public fun account_balance<BaseAsset, QuoteAsset>(pool: &clob::Pool<BaseAsset, QuoteAsset>, account_cap: &custodian::AccountCap): (u64, u64, u64, u64)
    -
    - - - -
    -Implementation - - -
    public fun account_balance<BaseAsset, QuoteAsset>(
    -    pool: &Pool<BaseAsset, QuoteAsset>,
    -    account_cap: &AccountCap
    -): (u64, u64, u64, u64) {
    -    let user = object::id(account_cap);
    -    let (base_avail, base_locked) = custodian::account_balance(&pool.base_custodian, user);
    -    let (quote_avail, quote_locked) = custodian::account_balance(&pool.quote_custodian, user);
    -    (base_avail, base_locked, quote_avail, quote_locked)
    -}
    -
    - - - -
    - - - -## Function `get_market_price` - -Query the market price of order book -returns (best_bid_price, best_ask_price) - - -
    public fun get_market_price<BaseAsset, QuoteAsset>(pool: &clob::Pool<BaseAsset, QuoteAsset>): (u64, u64)
    -
    - - - -
    -Implementation - - -
    public fun get_market_price<BaseAsset, QuoteAsset>(
    -    pool: &Pool<BaseAsset, QuoteAsset>
    -): (u64, u64){
    -    let (bid_price, _) = critbit::max_leaf(&pool.bids);
    -    let (ask_price, _) = critbit::min_leaf(&pool.asks);
    -    return (bid_price, ask_price)
    -}
    -
    - - - -
    - - - -## Function `get_level2_book_status_bid_side` - -Enter a price range and return the level2 order depth of all valid prices within this price range in bid side -returns two vectors of u64 -The previous is a list of all valid prices -The latter is the corresponding depth list - - -
    public fun get_level2_book_status_bid_side<BaseAsset, QuoteAsset>(pool: &clob::Pool<BaseAsset, QuoteAsset>, price_low: u64, price_high: u64, clock: &clock::Clock): (vector<u64>, vector<u64>)
    -
    - - - -
    -Implementation - - -
    public fun get_level2_book_status_bid_side<BaseAsset, QuoteAsset>(
    -    pool: &Pool<BaseAsset, QuoteAsset>,
    -    mut price_low: u64,
    -    mut price_high: u64,
    -    clock: &Clock
    -): (vector<u64>, vector<u64>) {
    -    let (price_low_, _) = critbit::min_leaf(&pool.bids);
    -    if (price_low < price_low_) price_low = price_low_;
    -    let (price_high_, _) = critbit::max_leaf(&pool.bids);
    -    if (price_high > price_high_) price_high = price_high_;
    -    price_low = critbit::find_closest_key(&pool.bids, price_low);
    -    price_high = critbit::find_closest_key(&pool.bids, price_high);
    -    let mut price_vec = vector::empty<u64>();
    -    let mut depth_vec = vector::empty<u64>();
    -    if (price_low == 0) { return (price_vec, depth_vec) };
    -    while (price_low <= price_high) {
    -        let depth = get_level2_book_status(
    -            &pool.bids,
    -            price_low,
    -            clock::timestamp_ms(clock)
    -        );
    -        vector::push_back(&mut price_vec, price_low);
    -        vector::push_back(&mut depth_vec, depth);
    -        let (next_price, _) = critbit::next_leaf(&pool.bids, price_low);
    -        if (next_price == 0) { break }
    -        else { price_low = next_price };
    -    };
    -    (price_vec, depth_vec)
    -}
    -
    - - - -
    - - - -## Function `get_level2_book_status_ask_side` - -Enter a price range and return the level2 order depth of all valid prices within this price range in ask side -returns two vectors of u64 -The previous is a list of all valid prices -The latter is the corresponding depth list - - -
    public fun get_level2_book_status_ask_side<BaseAsset, QuoteAsset>(pool: &clob::Pool<BaseAsset, QuoteAsset>, price_low: u64, price_high: u64, clock: &clock::Clock): (vector<u64>, vector<u64>)
    -
    - - - -
    -Implementation - - -
    public fun get_level2_book_status_ask_side<BaseAsset, QuoteAsset>(
    -    pool: &Pool<BaseAsset, QuoteAsset>,
    -    mut price_low: u64,
    -    mut price_high: u64,
    -    clock: &Clock
    -): (vector<u64>, vector<u64>) {
    -    let (price_low_, _) = critbit::min_leaf(&pool.asks);
    -    if (price_low < price_low_) price_low = price_low_;
    -    let (price_high_, _) = critbit::max_leaf(&pool.asks);
    -    if (price_high > price_high_) price_high = price_high_;
    -    price_low = critbit::find_closest_key(&pool.asks, price_low);
    -    price_high = critbit::find_closest_key(&pool.asks, price_high);
    -    let mut price_vec = vector::empty<u64>();
    -    let mut depth_vec = vector::empty<u64>();
    -    if (price_low == 0) { return (price_vec, depth_vec) };
    -    while (price_low <= price_high) {
    -        let depth = get_level2_book_status(
    -            &pool.asks,
    -            price_low,
    -            clock::timestamp_ms(clock)
    -        );
    -        vector::push_back(&mut price_vec, price_low);
    -        vector::push_back(&mut depth_vec, depth);
    -        let (next_price, _) = critbit::next_leaf(&pool.asks, price_low);
    -        if (next_price == 0) { break }
    -        else { price_low = next_price };
    -    };
    -    (price_vec, depth_vec)
    -}
    -
    - - - -
    - - - -## Function `get_level2_book_status` - -internal func to retrive single depth of a tick price - - -
    fun get_level2_book_status(open_orders: &critbit::CritbitTree<clob::TickLevel>, price: u64, time_stamp: u64): u64
    -
    - - - -
    -Implementation - - -
    fun get_level2_book_status(
    -    open_orders: &CritbitTree<TickLevel>,
    -    price: u64,
    -    time_stamp: u64
    -): u64 {
    -    let tick_level = critbit::borrow_leaf_by_key(open_orders, price);
    -    let tick_open_orders = &tick_level.open_orders;
    -    let mut depth = 0;
    -    let mut order_id = linked_table::front(tick_open_orders);
    -    let mut order: &Order;
    -    while (!option::is_none(order_id)) {
    -        order = linked_table::borrow(tick_open_orders, *option::borrow(order_id));
    -        if (order.expire_timestamp > time_stamp) depth = depth + order.quantity;
    -        order_id = linked_table::next(tick_open_orders, *option::borrow(order_id));
    -    };
    -    depth
    -}
    -
    - - - -
    - - - -## Function `get_order_status` - - - -
    public fun get_order_status<BaseAsset, QuoteAsset>(pool: &clob::Pool<BaseAsset, QuoteAsset>, order_id: u64, account_cap: &custodian::AccountCap): &clob::Order
    -
    - - - -
    -Implementation - - -
    public fun get_order_status<BaseAsset, QuoteAsset>(
    -    pool: &Pool<BaseAsset, QuoteAsset>,
    -    order_id: u64,
    -    account_cap: &AccountCap
    -): &Order {
    -    let user = object::id(account_cap);
    -    assert!(table::contains(&pool.usr_open_orders, user), EInvalidUser);
    -    let usr_open_order_ids = table::borrow(&pool.usr_open_orders, user);
    -    assert!(linked_table::contains(usr_open_order_ids, order_id), EInvalidOrderId);
    -    let order_price = *linked_table::borrow(usr_open_order_ids, order_id);
    -    let open_orders =
    -        if (order_id < MIN_ASK_ORDER_ID) { &pool.bids }
    -        else { &pool.asks };
    -    let tick_level = critbit::borrow_leaf_by_key(open_orders, order_price);
    -    let tick_open_orders = &tick_level.open_orders;
    -    let order = linked_table::borrow(tick_open_orders, order_id);
    -    order
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/deepbook/custodian.md b/crates/sui-framework/docs/deepbook/custodian.md deleted file mode 100644 index 998024d9f82..00000000000 --- a/crates/sui-framework/docs/deepbook/custodian.md +++ /dev/null @@ -1,504 +0,0 @@ ---- -title: Module `0xdee9::custodian` ---- - - - -- [Struct `Account`](#0xdee9_custodian_Account) -- [Resource `AccountCap`](#0xdee9_custodian_AccountCap) -- [Resource `Custodian`](#0xdee9_custodian_Custodian) -- [Function `mint_account_cap`](#0xdee9_custodian_mint_account_cap) -- [Function `account_balance`](#0xdee9_custodian_account_balance) -- [Function `new`](#0xdee9_custodian_new) -- [Function `withdraw_asset`](#0xdee9_custodian_withdraw_asset) -- [Function `increase_user_available_balance`](#0xdee9_custodian_increase_user_available_balance) -- [Function `decrease_user_available_balance`](#0xdee9_custodian_decrease_user_available_balance) -- [Function `increase_user_locked_balance`](#0xdee9_custodian_increase_user_locked_balance) -- [Function `decrease_user_locked_balance`](#0xdee9_custodian_decrease_user_locked_balance) -- [Function `lock_balance`](#0xdee9_custodian_lock_balance) -- [Function `unlock_balance`](#0xdee9_custodian_unlock_balance) -- [Function `account_available_balance`](#0xdee9_custodian_account_available_balance) -- [Function `account_locked_balance`](#0xdee9_custodian_account_locked_balance) -- [Function `borrow_mut_account_balance`](#0xdee9_custodian_borrow_mut_account_balance) - - -
    use 0x2::balance;
    -use 0x2::coin;
    -use 0x2::object;
    -use 0x2::table;
    -use 0x2::tx_context;
    -
    - - - - - -## Struct `Account` - - - -
    struct Account<T> has store
    -
    - - - -
    -Fields - - -
    -
    -available_balance: balance::Balance<T> -
    -
    - -
    -
    -locked_balance: balance::Balance<T> -
    -
    - -
    -
    - - -
    - - - -## Resource `AccountCap` - - - -
    struct AccountCap has store, key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    - - -
    - - - -## Resource `Custodian` - - - -
    struct Custodian<T> has store, key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -account_balances: table::Table<object::ID, custodian::Account<T>> -
    -
    - Map from an AccountCap object ID to an Account object -
    -
    - - -
    - - - -## Function `mint_account_cap` - -Create an AccountCap that can be used across all DeepBook pool - - -
    public fun mint_account_cap(ctx: &mut tx_context::TxContext): custodian::AccountCap
    -
    - - - -
    -Implementation - - -
    public fun mint_account_cap(ctx: &mut TxContext): AccountCap {
    -    AccountCap { id: object::new(ctx) }
    -}
    -
    - - - -
    - - - -## Function `account_balance` - - - -
    public(friend) fun account_balance<Asset>(custodian: &custodian::Custodian<Asset>, user: object::ID): (u64, u64)
    -
    - - - -
    -Implementation - - -
    public(package) fun account_balance<Asset>(
    -    custodian: &Custodian<Asset>,
    -    user: ID
    -): (u64, u64) {
    -    // if custodian account is not created yet, directly return (0, 0) rather than abort
    -    if (!table::contains(&custodian.account_balances, user)) {
    -        return (0, 0)
    -    };
    -    let account_balances = table::borrow(&custodian.account_balances, user);
    -    let avail_balance = balance::value(&account_balances.available_balance);
    -    let locked_balance = balance::value(&account_balances.locked_balance);
    -    (avail_balance, locked_balance)
    -}
    -
    - - - -
    - - - -## Function `new` - - - -
    public(friend) fun new<T>(ctx: &mut tx_context::TxContext): custodian::Custodian<T>
    -
    - - - -
    -Implementation - - -
    public(package) fun new<T>(ctx: &mut TxContext): Custodian<T> {
    -    Custodian<T> {
    -        id: object::new(ctx),
    -        account_balances: table::new(ctx),
    -    }
    -}
    -
    - - - -
    - - - -## Function `withdraw_asset` - - - -
    public(friend) fun withdraw_asset<Asset>(custodian: &mut custodian::Custodian<Asset>, quantity: u64, account_cap: &custodian::AccountCap, ctx: &mut tx_context::TxContext): coin::Coin<Asset>
    -
    - - - -
    -Implementation - - -
    public(package) fun withdraw_asset<Asset>(
    -    custodian: &mut Custodian<Asset>,
    -    quantity: u64,
    -    account_cap: &AccountCap,
    -    ctx: &mut TxContext
    -): Coin<Asset> {
    -    coin::from_balance(decrease_user_available_balance<Asset>(custodian, account_cap, quantity), ctx)
    -}
    -
    - - - -
    - - - -## Function `increase_user_available_balance` - - - -
    public(friend) fun increase_user_available_balance<T>(custodian: &mut custodian::Custodian<T>, user: object::ID, quantity: balance::Balance<T>)
    -
    - - - -
    -Implementation - - -
    public(package) fun increase_user_available_balance<T>(
    -    custodian: &mut Custodian<T>,
    -    user: ID,
    -    quantity: Balance<T>,
    -) {
    -    let account = borrow_mut_account_balance<T>(custodian, user);
    -    balance::join(&mut account.available_balance, quantity);
    -}
    -
    - - - -
    - - - -## Function `decrease_user_available_balance` - - - -
    public(friend) fun decrease_user_available_balance<T>(custodian: &mut custodian::Custodian<T>, account_cap: &custodian::AccountCap, quantity: u64): balance::Balance<T>
    -
    - - - -
    -Implementation - - -
    public(package) fun decrease_user_available_balance<T>(
    -    custodian: &mut Custodian<T>,
    -    account_cap: &AccountCap,
    -    quantity: u64,
    -): Balance<T> {
    -    let account = borrow_mut_account_balance<T>(custodian, object::uid_to_inner(&account_cap.id));
    -    balance::split(&mut account.available_balance, quantity)
    -}
    -
    - - - -
    - - - -## Function `increase_user_locked_balance` - - - -
    public(friend) fun increase_user_locked_balance<T>(custodian: &mut custodian::Custodian<T>, account_cap: &custodian::AccountCap, quantity: balance::Balance<T>)
    -
    - - - -
    -Implementation - - -
    public(package) fun increase_user_locked_balance<T>(
    -    custodian: &mut Custodian<T>,
    -    account_cap: &AccountCap,
    -    quantity: Balance<T>,
    -) {
    -    let account = borrow_mut_account_balance<T>(custodian, object::uid_to_inner(&account_cap.id));
    -    balance::join(&mut account.locked_balance, quantity);
    -}
    -
    - - - -
    - - - -## Function `decrease_user_locked_balance` - - - -
    public(friend) fun decrease_user_locked_balance<T>(custodian: &mut custodian::Custodian<T>, user: object::ID, quantity: u64): balance::Balance<T>
    -
    - - - -
    -Implementation - - -
    public(package) fun decrease_user_locked_balance<T>(
    -    custodian: &mut Custodian<T>,
    -    user: ID,
    -    quantity: u64,
    -): Balance<T> {
    -    let account = borrow_mut_account_balance<T>(custodian, user);
    -    split(&mut account.locked_balance, quantity)
    -}
    -
    - - - -
    - - - -## Function `lock_balance` - -Move quantity from the unlocked balance of user to the locked balance of user - - -
    public(friend) fun lock_balance<T>(custodian: &mut custodian::Custodian<T>, account_cap: &custodian::AccountCap, quantity: u64)
    -
    - - - -
    -Implementation - - -
    public(package) fun lock_balance<T>(
    -    custodian: &mut Custodian<T>,
    -    account_cap: &AccountCap,
    -    quantity: u64,
    -) {
    -    let to_lock = decrease_user_available_balance(custodian, account_cap, quantity);
    -    increase_user_locked_balance(custodian, account_cap, to_lock);
    -}
    -
    - - - -
    - - - -## Function `unlock_balance` - -Move quantity from the locked balance of user to the unlocked balacne of user - - -
    public(friend) fun unlock_balance<T>(custodian: &mut custodian::Custodian<T>, user: object::ID, quantity: u64)
    -
    - - - -
    -Implementation - - -
    public(package) fun unlock_balance<T>(
    -    custodian: &mut Custodian<T>,
    -    user: ID,
    -    quantity: u64,
    -) {
    -    let locked_balance = decrease_user_locked_balance<T>(custodian, user, quantity);
    -    increase_user_available_balance<T>(custodian, user, locked_balance)
    -}
    -
    - - - -
    - - - -## Function `account_available_balance` - - - -
    public(friend) fun account_available_balance<T>(custodian: &custodian::Custodian<T>, user: object::ID): u64
    -
    - - - -
    -Implementation - - -
    public(package) fun account_available_balance<T>(
    -    custodian: &Custodian<T>,
    -    user: ID,
    -): u64 {
    -    balance::value(&table::borrow(&custodian.account_balances, user).available_balance)
    -}
    -
    - - - -
    - - - -## Function `account_locked_balance` - - - -
    public(friend) fun account_locked_balance<T>(custodian: &custodian::Custodian<T>, user: object::ID): u64
    -
    - - - -
    -Implementation - - -
    public(package) fun account_locked_balance<T>(
    -    custodian: &Custodian<T>,
    -    user: ID,
    -): u64 {
    -    balance::value(&table::borrow(&custodian.account_balances, user).locked_balance)
    -}
    -
    - - - -
    - - - -## Function `borrow_mut_account_balance` - - - -
    fun borrow_mut_account_balance<T>(custodian: &mut custodian::Custodian<T>, user: object::ID): &mut custodian::Account<T>
    -
    - - - -
    -Implementation - - -
    fun borrow_mut_account_balance<T>(
    -    custodian: &mut Custodian<T>,
    -    user: ID,
    -): &mut Account<T> {
    -    if (!table::contains(&custodian.account_balances, user)) {
    -        table::add(
    -            &mut custodian.account_balances,
    -            user,
    -            Account { available_balance: balance::zero(), locked_balance: balance::zero() }
    -        );
    -    };
    -    table::borrow_mut(&mut custodian.account_balances, user)
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/move-stdlib/address.md b/crates/sui-framework/docs/move-stdlib/address.md deleted file mode 100644 index 58d41960149..00000000000 --- a/crates/sui-framework/docs/move-stdlib/address.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Module `0x1::address` ---- - -Provides a way to get address length since it's a -platform-specific parameter. - - -- [Function `length`](#0x1_address_length) - - -
    - - - - - -## Function `length` - -Should be converted to a native function. -Current implementation only works for Sui. - - -
    public fun length(): u64
    -
    - - - -
    -Implementation - - -
    public fun length(): u64 {
    -    32
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/stardust/alias_output.md b/crates/sui-framework/docs/stardust/alias_output.md deleted file mode 100644 index 896f7c7eeaa..00000000000 --- a/crates/sui-framework/docs/stardust/alias_output.md +++ /dev/null @@ -1,197 +0,0 @@ ---- -title: Module `0x107a::alias_output` ---- - - - -- [Resource `AliasOutput`](#0x107a_alias_output_AliasOutput) -- [Constants](#@Constants_0) -- [Function `extract_assets`](#0x107a_alias_output_extract_assets) -- [Function `receive`](#0x107a_alias_output_receive) -- [Function `attach_alias`](#0x107a_alias_output_attach_alias) -- [Function `load_alias`](#0x107a_alias_output_load_alias) - - -
    use 0x107a::alias;
    -use 0x2::bag;
    -use 0x2::balance;
    -use 0x2::dynamic_object_field;
    -use 0x2::object;
    -use 0x2::sui;
    -use 0x2::transfer;
    -
    - - - - - -## Resource `AliasOutput` - -Owned Object controlled by the Governor Address. - - -
    struct AliasOutput has key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - This is a "random" UID, not the AliasID from Stardust. -
    -
    -iota: balance::Balance<sui::SUI> -
    -
    - The amount of IOTA coins held by the output. -
    -
    -native_tokens: bag::Bag -
    -
    - The Bag holds native tokens, key-ed by the stringified type of the asset. - Example: key: "0xabcded::soon::SOON", value: Balance<0xabcded::soon::SOON>. -
    -
    - - -
    - - - -## Constants - - - - -The Alias dynamic object field name. - - -
    const ALIAS_NAME: vector<u8> = [97, 108, 105, 97, 115];
    -
    - - - - - -## Function `extract_assets` - -The function extracts assets from a legacy AliasOutput. -- returns the IOTA Balance, -- the native tokens Bag, -- and the Alias object that persists the AliasID=ObjectID from Stardust. - - -
    public fun extract_assets(output: alias_output::AliasOutput): (balance::Balance<sui::SUI>, bag::Bag, alias::Alias)
    -
    - - - -
    -Implementation - - -
    public fun extract_assets(mut output: AliasOutput): (Balance<SUI>, Bag, Alias) {
    -    // Load the related alias object.
    -    let alias = load_alias(&mut output);
    -
    -    // Unpack the output into its basic part.
    -    let AliasOutput {
    -        id,
    -        iota,
    -        native_tokens
    -    } = output;
    -
    -    // Delete the output.
    -    object::delete(id);
    -
    -    (iota, native_tokens, alias)
    -}
    -
    - - - -
    - - - -## Function `receive` - -Utility function to receive an AliasOutput object in other Stardust modules. -Other modules in the Stardust package can call this function to receive an AliasOutput object (nft). - - -
    public(friend) fun receive(parent: &mut object::UID, output: transfer::Receiving<alias_output::AliasOutput>): alias_output::AliasOutput
    -
    - - - -
    -Implementation - - -
    public(package) fun receive(parent: &mut UID, output: Receiving<AliasOutput>) : AliasOutput {
    -    transfer::receive(parent, output)
    -}
    -
    - - - -
    - - - -## Function `attach_alias` - -Utility function to attach an Alias to an AliasOutput. - - -
    public fun attach_alias(output: &mut alias_output::AliasOutput, alias: alias::Alias)
    -
    - - - -
    -Implementation - - -
    public fun attach_alias(output: &mut AliasOutput, alias: Alias) {
    -    dynamic_object_field::add(&mut output.id, ALIAS_NAME, alias)
    -}
    -
    - - - -
    - - - -## Function `load_alias` - -Loads the Alias object from the dynamic object field. - - -
    fun load_alias(output: &mut alias_output::AliasOutput): alias::Alias
    -
    - - - -
    -Implementation - - -
    fun load_alias(output: &mut AliasOutput): Alias {
    -    dynamic_object_field::remove(&mut output.id, ALIAS_NAME)
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/stardust/basic_output.md b/crates/sui-framework/docs/stardust/basic_output.md deleted file mode 100644 index 793e029c122..00000000000 --- a/crates/sui-framework/docs/stardust/basic_output.md +++ /dev/null @@ -1,198 +0,0 @@ ---- -title: Module `0x107a::basic_output` ---- - - - -- [Resource `BasicOutput`](#0x107a_basic_output_BasicOutput) -- [Function `extract_assets`](#0x107a_basic_output_extract_assets) -- [Function `receive`](#0x107a_basic_output_receive) - - -
    use 0x107a::expiration_unlock_condition;
    -use 0x107a::storage_deposit_return_unlock_condition;
    -use 0x107a::timelock_unlock_condition;
    -use 0x1::option;
    -use 0x2::bag;
    -use 0x2::balance;
    -use 0x2::object;
    -use 0x2::sui;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -
    - - - - - -## Resource `BasicOutput` - -A basic output that has unlock conditions/features. -- basic outputs with expiration unlock condition must be a shared object, since that's the only -way to handle the two possible addresses that can unlock the output. -- notice that there is no store ability and there is no custom transfer function: -- you can call extract_assets, -- or you can call receive in other models to receive a BasicOutput. - - -
    struct BasicOutput has key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - Hash of the outputId that was migrated. -
    -
    -iota: balance::Balance<sui::SUI> -
    -
    - The amount of IOTA coins held by the output. -
    -
    -native_tokens: bag::Bag -
    -
    - The Bag holds native tokens, key-ed by the stringified type of the asset. - Example: key: "0xabcded::soon::SOON", value: Balance<0xabcded::soon::SOON>. -
    -
    -storage_deposit_return_uc: option::Option<storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition> -
    -
    - The storage deposit return unlock condition. -
    -
    -timelock_uc: option::Option<timelock_unlock_condition::TimelockUnlockCondition> -
    -
    - The timelock unlock condition. -
    -
    -expiration_uc: option::Option<expiration_unlock_condition::ExpirationUnlockCondition> -
    -
    - The expiration unlock condition. -
    -
    -metadata: option::Option<vector<u8>> -
    -
    - The metadata feature. -
    -
    -tag: option::Option<vector<u8>> -
    -
    - The tag feature. -
    -
    -sender: option::Option<address> -
    -
    - The sender feature. -
    -
    - - -
    - - - -## Function `extract_assets` - -Extract the assets stored inside the output, respecting the unlock conditions. -- The object will be deleted. -- The StorageDepositReturnUnlockCondition will return the deposit. -- Remaining assets (IOTA coins and native tokens) will be returned. - - -
    public fun extract_assets(output: basic_output::BasicOutput, ctx: &mut tx_context::TxContext): (balance::Balance<sui::SUI>, bag::Bag)
    -
    - - - -
    -Implementation - - -
    public fun extract_assets(output: BasicOutput, ctx: &mut TxContext) : (Balance<SUI>, Bag) {
    -    // Unpack the output into its basic part.
    -    let BasicOutput {
    -        id,
    -        iota: mut iota,
    -        native_tokens,
    -        storage_deposit_return_uc: mut storage_deposit_return_uc,
    -        timelock_uc: mut timelock_uc,
    -        expiration_uc: mut expiration_uc,
    -        sender: _,
    -        metadata: _,
    -        tag: _
    -    } = output;
    -
    -    // If the output has a timelock unlock condition, then we need to check if the timelock_uc has expired.
    -    if (timelock_uc.is_some()) {
    -        timelock_uc.extract().unlock(ctx);
    -    };
    -
    -    // If the output has an expiration unlock condition, then we need to check who can unlock the output.
    -    if (expiration_uc.is_some()) {
    -        expiration_uc.extract().unlock(ctx);
    -    };
    -
    -    // If the output has an storage deposit return unlock condition, then we need to return the deposit.
    -    if (storage_deposit_return_uc.is_some()) {
    -        storage_deposit_return_uc.extract().unlock(&mut iota, ctx);
    -    };
    -
    -    // Destroy the unlock conditions.
    -    option::destroy_none(timelock_uc);
    -    option::destroy_none(expiration_uc);
    -    option::destroy_none(storage_deposit_return_uc);
    -
    -    // Delete the output.
    -    object::delete(id);
    -
    -    return (iota, native_tokens)
    -}
    -
    - - - -
    - - - -## Function `receive` - -Utility function to receive a basic output in other stardust modules. -Since BasicOutput only has key, it can not be received via public_receive. -The private receiver must be implemented in its defining module (here). -Other modules in the Stardust package can call this function to receive a basic output (alias, NFT). - - -
    public(friend) fun receive(parent: &mut object::UID, output: transfer::Receiving<basic_output::BasicOutput>): basic_output::BasicOutput
    -
    - - - -
    -Implementation - - -
    public(package) fun receive(parent: &mut UID, output: Receiving<BasicOutput>) : BasicOutput {
    -    transfer::receive(parent, output)
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/stardust/nft_output.md b/crates/sui-framework/docs/stardust/nft_output.md deleted file mode 100644 index 4eaa1b03d87..00000000000 --- a/crates/sui-framework/docs/stardust/nft_output.md +++ /dev/null @@ -1,239 +0,0 @@ ---- -title: Module `0x107a::nft_output` ---- - - - -- [Resource `NftOutput`](#0x107a_nft_output_NftOutput) -- [Constants](#@Constants_0) -- [Function `extract_assets`](#0x107a_nft_output_extract_assets) -- [Function `load_nft`](#0x107a_nft_output_load_nft) -- [Function `attach_nft`](#0x107a_nft_output_attach_nft) -- [Function `receive`](#0x107a_nft_output_receive) - - -
    use 0x107a::expiration_unlock_condition;
    -use 0x107a::nft;
    -use 0x107a::storage_deposit_return_unlock_condition;
    -use 0x107a::timelock_unlock_condition;
    -use 0x1::option;
    -use 0x2::bag;
    -use 0x2::balance;
    -use 0x2::dynamic_object_field;
    -use 0x2::object;
    -use 0x2::sui;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -
    - - - - - -## Resource `NftOutput` - -The Stardust NFT output representation. - - -
    struct NftOutput has key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - This is a "random" UID, not the NFTID from Stardust. -
    -
    -iota: balance::Balance<sui::SUI> -
    -
    - The amount of IOTA tokens held by the output. -
    -
    -native_tokens: bag::Bag -
    -
    - The Bag holds native tokens, key-ed by the stringified type of the asset. - Example: key: "0xabcded::soon::SOON", value: Balance<0xabcded::soon::SOON>. -
    -
    -storage_deposit_return_uc: option::Option<storage_deposit_return_unlock_condition::StorageDepositReturnUnlockCondition> -
    -
    - The storage deposit return unlock condition. -
    -
    -timelock_uc: option::Option<timelock_unlock_condition::TimelockUnlockCondition> -
    -
    - The timelock unlock condition. -
    -
    -expiration_uc: option::Option<expiration_unlock_condition::ExpirationUnlockCondition> -
    -
    - The expiration unlock condition. -
    -
    - - -
    - - - -## Constants - - - - -The NFT dynamic field name. - - -
    const NFT_NAME: vector<u8> = [110, 102, 116];
    -
    - - - - - -## Function `extract_assets` - -The function extracts assets from a legacy NFT output. - - -
    public fun extract_assets(output: nft_output::NftOutput, ctx: &mut tx_context::TxContext): (balance::Balance<sui::SUI>, bag::Bag, nft::Nft)
    -
    - - - -
    -Implementation - - -
    public fun extract_assets(mut output: NftOutput, ctx: &mut TxContext): (Balance<SUI>, Bag, Nft) {
    -    // Load the related Nft object.
    -    let nft = load_nft(&mut output);
    -
    -    // Unpuck the output.
    -    let NftOutput {
    -        id,
    -        iota: mut iota,
    -        native_tokens,
    -        storage_deposit_return_uc: mut storage_deposit_return_uc,
    -        timelock_uc: mut timelock_uc,
    -        expiration_uc: mut expiration_uc
    -    } = output;
    -
    -    // If the output has a timelock unlock condition, then we need to check if the timelock_uc has expired.
    -    if (timelock_uc.is_some()) {
    -        timelock_uc.extract().unlock(ctx);
    -    };
    -
    -    // If the output has an expiration unlock condition, then we need to check who can unlock the output.
    -    if (expiration_uc.is_some()) {
    -        expiration_uc.extract().unlock(ctx);
    -    };
    -
    -    // If the output has a storage deposit return unlock condition, then we need to return the deposit.
    -    if (storage_deposit_return_uc.is_some()) {
    -        storage_deposit_return_uc.extract().unlock(&mut iota, ctx);
    -    };
    -
    -    // Destroy the output.
    -    option::destroy_none(timelock_uc);
    -    option::destroy_none(expiration_uc);
    -    option::destroy_none(storage_deposit_return_uc);
    -
    -    object::delete(id);
    -
    -    return (iota, native_tokens, nft)
    -}
    -
    - - - -
    - - - -## Function `load_nft` - -Loads the related Nft object. - - -
    fun load_nft(output: &mut nft_output::NftOutput): nft::Nft
    -
    - - - -
    -Implementation - - -
    fun load_nft(output: &mut NftOutput): Nft {
    -    dynamic_object_field::remove(&mut output.id, NFT_NAME)
    -}
    -
    - - - -
    - - - -## Function `attach_nft` - -Utility function to attach an Alias to an AliasOutput. - - -
    public fun attach_nft(output: &mut nft_output::NftOutput, nft: nft::Nft)
    -
    - - - -
    -Implementation - - -
    public fun attach_nft(output: &mut NftOutput, nft: Nft) {
    -    dynamic_object_field::add(&mut output.id, NFT_NAME, nft)
    -}
    -
    - - - -
    - - - -## Function `receive` - -Utility function to receive an NftOutput in other Stardust modules. -Other modules in the stardust package can call this function to receive an NftOutput (alias). - - -
    public(friend) fun receive(parent: &mut object::UID, nft: transfer::Receiving<nft_output::NftOutput>): nft_output::NftOutput
    -
    - - - -
    -Implementation - - -
    public(package) fun receive(parent: &mut UID, nft: Receiving<NftOutput>) : NftOutput {
    -    transfer::receive(parent, nft)
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/stardust/utilities.md b/crates/sui-framework/docs/stardust/utilities.md deleted file mode 100644 index 9d2256b6d5d..00000000000 --- a/crates/sui-framework/docs/stardust/utilities.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -title: Module `0x107a::utilities` ---- - - - -- [Constants](#@Constants_0) -- [Function `extract_and_send_to`](#0x107a_utilities_extract_and_send_to) -- [Function `extract`](#0x107a_utilities_extract) -- [Function `extract_`](#0x107a_utilities_extract_) - - -
    use 0x1::ascii;
    -use 0x1::type_name;
    -use 0x2::bag;
    -use 0x2::balance;
    -use 0x2::coin;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -
    - - - - - -## Constants - - - - -Returned when trying to extract a Balance<T> from a Bag and the balance is zero. - - -
    const EZeroNativeTokenBalance: u64 = 0;
    -
    - - - - - -## Function `extract_and_send_to` - -Extract a Balance<T> from a Bag, create a Coin out of it and send it to the address. -NOTE: We return the Bag by value so the function can be called repeatedly in a PTB. - - -
    public fun extract_and_send_to<T>(bag: bag::Bag, to: address, ctx: &mut tx_context::TxContext): bag::Bag
    -
    - - - -
    -Implementation - - -
    public fun extract_and_send_to<T>(mut bag: Bag, to: address, ctx: &mut TxContext): Bag {
    -    let coin = coin::from_balance(extract_<T>(&mut bag), ctx);
    -    transfer::public_transfer(coin, to);
    -    bag
    -}
    -
    - - - -
    - - - -## Function `extract` - -Extract a Balance<T> from a Bag and return it. Caller can decide what to do with it. -NOTE: We return the Bag by value so the function can be called repeatedly in a PTB. - - -
    public fun extract<T>(bag: bag::Bag): (bag::Bag, balance::Balance<T>)
    -
    - - - -
    -Implementation - - -
    public fun extract<T>(mut bag: Bag): (Bag, Balance<T>) {
    -    let balance = extract_<T>(&mut bag);
    -    (bag, balance)
    -}
    -
    - - - -
    - - - -## Function `extract_` - -Get a Balance<T> from a Bag. -Aborts if the balance is zero or if there is no balance for the type T. - - -
    fun extract_<T>(bag: &mut bag::Bag): balance::Balance<T>
    -
    - - - -
    -Implementation - - -
    fun extract_<T>(bag: &mut Bag): Balance<T> {
    -    let key = type_name::get<T>().into_string();
    -
    -    // This call aborts if the key doesn't exist.
    -    let balance : Balance<T> = bag.remove(key);
    -
    -    assert!(balance.value() != 0, EZeroNativeTokenBalance);
    -
    -    balance
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/address.md b/crates/sui-framework/docs/sui-framework/address.md deleted file mode 100644 index 88786f39d2a..00000000000 --- a/crates/sui-framework/docs/sui-framework/address.md +++ /dev/null @@ -1,323 +0,0 @@ ---- -title: Module `0x2::address` ---- - - - -- [Constants](#@Constants_0) -- [Function `to_u256`](#0x2_address_to_u256) -- [Function `from_u256`](#0x2_address_from_u256) -- [Function `from_bytes`](#0x2_address_from_bytes) -- [Function `to_bytes`](#0x2_address_to_bytes) -- [Function `to_ascii_string`](#0x2_address_to_ascii_string) -- [Function `to_string`](#0x2_address_to_string) -- [Function `from_ascii_bytes`](#0x2_address_from_ascii_bytes) -- [Function `hex_char_value`](#0x2_address_hex_char_value) -- [Function `length`](#0x2_address_length) -- [Function `max`](#0x2_address_max) - - -
    use 0x1::ascii;
    -use 0x1::bcs;
    -use 0x1::string;
    -use 0x2::hex;
    -
    - - - - - -## Constants - - - - -Error from from_bytes when it is supplied too many or too few bytes. - - -
    const EAddressParseError: u64 = 0;
    -
    - - - - - -The length of an address, in bytes - - -
    const LENGTH: u64 = 32;
    -
    - - - - - - - -
    const MAX: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
    -
    - - - - - -## Function `to_u256` - -Convert a into a u256 by interpreting a as the bytes of a big-endian integer -(e.g., to_u256(0x1) == 1) - - -
    public fun to_u256(a: address): u256
    -
    - - - -
    -Implementation - - -
    public native fun to_u256(a: address): u256;
    -
    - - - -
    - - - -## Function `from_u256` - -Convert n into an address by encoding it as a big-endian integer (e.g., from_u256(1) = @0x1) -Aborts if n > MAX_ADDRESS - - -
    public fun from_u256(n: u256): address
    -
    - - - -
    -Implementation - - -
    public native fun from_u256(n: u256): address;
    -
    - - - -
    - - - -## Function `from_bytes` - -Convert bytes into an address. -Aborts with EAddressParseError if the length of bytes is not 32 - - -
    public fun from_bytes(bytes: vector<u8>): address
    -
    - - - -
    -Implementation - - -
    public native fun from_bytes(bytes: vector<u8>): address;
    -
    - - - -
    - - - -## Function `to_bytes` - -Convert a into BCS-encoded bytes. - - -
    public fun to_bytes(a: address): vector<u8>
    -
    - - - -
    -Implementation - - -
    public fun to_bytes(a: address): vector<u8> {
    -    bcs::to_bytes(&a)
    -}
    -
    - - - -
    - - - -## Function `to_ascii_string` - -Convert a to a hex-encoded ASCII string - - -
    public fun to_ascii_string(a: address): ascii::String
    -
    - - - -
    -Implementation - - -
    public fun to_ascii_string(a: address): ascii::String {
    -    hex::encode(to_bytes(a)).to_ascii_string()
    -}
    -
    - - - -
    - - - -## Function `to_string` - -Convert a to a hex-encoded string - - -
    public fun to_string(a: address): string::String
    -
    - - - -
    -Implementation - - -
    public fun to_string(a: address): string::String {
    -    to_ascii_string(a).to_string()
    -}
    -
    - - - -
    - - - -## Function `from_ascii_bytes` - -Converts an ASCII string to an address, taking the numerical value for each character. The -string must be Base16 encoded, and thus exactly 64 characters long. -For example, the string "00000000000000000000000000000000000000000000000000000000DEADB33F" -will be converted to the address @0xDEADB33F. -Aborts with EAddressParseError if the length of s is not 64, -or if an invalid character is encountered. - - -
    public fun from_ascii_bytes(bytes: &vector<u8>): address
    -
    - - - -
    -Implementation - - -
    public fun from_ascii_bytes(bytes: &vector<u8>): address {
    -    assert!(bytes.length() == 64, EAddressParseError);
    -    let mut hex_bytes = vector[];
    -    let mut i = 0;
    -    while (i < 64) {
    -        let hi = hex_char_value(bytes[i]);
    -        let lo = hex_char_value(bytes[i+1]);
    -        hex_bytes.push_back((hi << 4) | lo);
    -        i = i + 2;
    -    };
    -    from_bytes(hex_bytes)
    -}
    -
    - - - -
    - - - -## Function `hex_char_value` - - - -
    fun hex_char_value(c: u8): u8
    -
    - - - -
    -Implementation - - -
    fun hex_char_value(c: u8): u8 {
    -    if (c >= 48 && c <= 57) c - 48 // 0-9
    -    else if (c >= 65 && c <= 70) c - 55 // A-F
    -    else if (c >= 97 && c <= 102) c - 87 // a-f
    -    else abort EAddressParseError
    -}
    -
    - - - -
    - - - -## Function `length` - -Length of a Sui address in bytes - - -
    public fun length(): u64
    -
    - - - -
    -Implementation - - -
    public fun length(): u64 {
    -    LENGTH
    -}
    -
    - - - -
    - - - -## Function `max` - -Largest possible address - - -
    public fun max(): u256
    -
    - - - -
    -Implementation - - -
    public fun max(): u256 {
    -    MAX
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/authenticator_state.md b/crates/sui-framework/docs/sui-framework/authenticator_state.md deleted file mode 100644 index 2db0c6ad475..00000000000 --- a/crates/sui-framework/docs/sui-framework/authenticator_state.md +++ /dev/null @@ -1,807 +0,0 @@ ---- -title: Module `0x2::authenticator_state` ---- - - - -- [Resource `AuthenticatorState`](#0x2_authenticator_state_AuthenticatorState) -- [Struct `AuthenticatorStateInner`](#0x2_authenticator_state_AuthenticatorStateInner) -- [Struct `JWK`](#0x2_authenticator_state_JWK) -- [Struct `JwkId`](#0x2_authenticator_state_JwkId) -- [Struct `ActiveJwk`](#0x2_authenticator_state_ActiveJwk) -- [Constants](#@Constants_0) -- [Function `active_jwk_equal`](#0x2_authenticator_state_active_jwk_equal) -- [Function `jwk_equal`](#0x2_authenticator_state_jwk_equal) -- [Function `jwk_id_equal`](#0x2_authenticator_state_jwk_id_equal) -- [Function `string_bytes_lt`](#0x2_authenticator_state_string_bytes_lt) -- [Function `jwk_lt`](#0x2_authenticator_state_jwk_lt) -- [Function `create`](#0x2_authenticator_state_create) -- [Function `load_inner_mut`](#0x2_authenticator_state_load_inner_mut) -- [Function `load_inner`](#0x2_authenticator_state_load_inner) -- [Function `check_sorted`](#0x2_authenticator_state_check_sorted) -- [Function `update_authenticator_state`](#0x2_authenticator_state_update_authenticator_state) -- [Function `deduplicate`](#0x2_authenticator_state_deduplicate) -- [Function `expire_jwks`](#0x2_authenticator_state_expire_jwks) -- [Function `get_active_jwks`](#0x2_authenticator_state_get_active_jwks) - - -
    use 0x1::option;
    -use 0x1::string;
    -use 0x2::dynamic_field;
    -use 0x2::math;
    -use 0x2::object;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -
    - - - - - -## Resource `AuthenticatorState` - -Singleton shared object which stores the global authenticator state. -The actual state is stored in a dynamic field of type AuthenticatorStateInner to support -future versions of the authenticator state. - - -
    struct AuthenticatorState has key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -version: u64 -
    -
    - -
    -
    - - -
    - - - -## Struct `AuthenticatorStateInner` - - - -
    struct AuthenticatorStateInner has store
    -
    - - - -
    -Fields - - -
    -
    -version: u64 -
    -
    - -
    -
    -active_jwks: vector<authenticator_state::ActiveJwk> -
    -
    - List of currently active JWKs. -
    -
    - - -
    - - - -## Struct `JWK` - -Must match the JWK struct in fastcrypto-zkp - - -
    struct JWK has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -kty: string::String -
    -
    - -
    -
    -e: string::String -
    -
    - -
    -
    -n: string::String -
    -
    - -
    -
    -alg: string::String -
    -
    - -
    -
    - - -
    - - - -## Struct `JwkId` - -Must match the JwkId struct in fastcrypto-zkp - - -
    struct JwkId has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -iss: string::String -
    -
    - -
    -
    -kid: string::String -
    -
    - -
    -
    - - -
    - - - -## Struct `ActiveJwk` - - - -
    struct ActiveJwk has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -jwk_id: authenticator_state::JwkId -
    -
    - -
    -
    -jwk: authenticator_state::JWK -
    -
    - -
    -
    -epoch: u64 -
    -
    - -
    -
    - - -
    - - - -## Constants - - - - -Sender is not @0x0 the system address. - - -
    const ENotSystemAddress: u64 = 0;
    -
    - - - - - - - -
    const CurrentVersion: u64 = 1;
    -
    - - - - - - - -
    const EJwksNotSorted: u64 = 2;
    -
    - - - - - - - -
    const EWrongInnerVersion: u64 = 1;
    -
    - - - - - -## Function `active_jwk_equal` - - - -
    fun active_jwk_equal(a: &authenticator_state::ActiveJwk, b: &authenticator_state::ActiveJwk): bool
    -
    - - - -
    -Implementation - - -
    fun active_jwk_equal(a: &ActiveJwk, b: &ActiveJwk): bool {
    -    // note: epoch is ignored
    -    jwk_equal(&a.jwk, &b.jwk) && jwk_id_equal(&a.jwk_id, &b.jwk_id)
    -}
    -
    - - - -
    - - - -## Function `jwk_equal` - - - -
    fun jwk_equal(a: &authenticator_state::JWK, b: &authenticator_state::JWK): bool
    -
    - - - -
    -Implementation - - -
    fun jwk_equal(a: &JWK, b: &JWK): bool {
    -    (&a.kty == &b.kty) &&
    -       (&a.e == &b.e) &&
    -       (&a.n == &b.n) &&
    -       (&a.alg == &b.alg)
    -}
    -
    - - - -
    - - - -## Function `jwk_id_equal` - - - -
    fun jwk_id_equal(a: &authenticator_state::JwkId, b: &authenticator_state::JwkId): bool
    -
    - - - -
    -Implementation - - -
    fun jwk_id_equal(a: &JwkId, b: &JwkId): bool {
    -    (&a.iss == &b.iss) && (&a.kid == &b.kid)
    -}
    -
    - - - -
    - - - -## Function `string_bytes_lt` - - - -
    fun string_bytes_lt(a: &string::String, b: &string::String): bool
    -
    - - - -
    -Implementation - - -
    fun string_bytes_lt(a: &String, b: &String): bool {
    -    let a_bytes = a.bytes();
    -    let b_bytes = b.bytes();
    -
    -    if (a_bytes.length() < b_bytes.length()) {
    -        true
    -    } else if (a_bytes.length() > b_bytes.length()) {
    -        false
    -    } else {
    -        let mut i = 0;
    -        while (i < a_bytes.length()) {
    -            let a_byte = a_bytes[i];
    -            let b_byte = b_bytes[i];
    -            if (a_byte < b_byte) {
    -                return true
    -            } else if (a_byte > b_byte) {
    -                return false
    -            };
    -            i = i + 1;
    -        };
    -        // all bytes are equal
    -        false
    -    }
    -}
    -
    - - - -
    - - - -## Function `jwk_lt` - - - -
    fun jwk_lt(a: &authenticator_state::ActiveJwk, b: &authenticator_state::ActiveJwk): bool
    -
    - - - -
    -Implementation - - -
    fun jwk_lt(a: &ActiveJwk, b: &ActiveJwk): bool {
    -    // note: epoch is ignored
    -    if (&a.jwk_id.iss != &b.jwk_id.iss) {
    -        return string_bytes_lt(&a.jwk_id.iss, &b.jwk_id.iss)
    -    };
    -    if (&a.jwk_id.kid != &b.jwk_id.kid) {
    -        return string_bytes_lt(&a.jwk_id.kid, &b.jwk_id.kid)
    -    };
    -    if (&a.jwk.kty != &b.jwk.kty) {
    -        return string_bytes_lt(&a.jwk.kty, &b.jwk.kty)
    -    };
    -    if (&a.jwk.e != &b.jwk.e) {
    -        return string_bytes_lt(&a.jwk.e, &b.jwk.e)
    -    };
    -    if (&a.jwk.n != &b.jwk.n) {
    -        return string_bytes_lt(&a.jwk.n, &b.jwk.n)
    -    };
    -    string_bytes_lt(&a.jwk.alg, &b.jwk.alg)
    -}
    -
    - - - -
    - - - -## Function `create` - -Create and share the AuthenticatorState object. This function is call exactly once, when -the authenticator state object is first created. -Can only be called by genesis or change_epoch transactions. - - -
    fun create(ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    fun create(ctx: &TxContext) {
    -    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    -
    -    let version = CurrentVersion;
    -
    -    let inner = AuthenticatorStateInner {
    -        version,
    -        active_jwks: vector[],
    -    };
    -
    -    let mut self = AuthenticatorState {
    -        id: object::authenticator_state(),
    -        version,
    -    };
    -
    -    dynamic_field::add(&mut self.id, version, inner);
    -    transfer::share_object(self);
    -}
    -
    - - - -
    - - - -## Function `load_inner_mut` - - - -
    fun load_inner_mut(self: &mut authenticator_state::AuthenticatorState): &mut authenticator_state::AuthenticatorStateInner
    -
    - - - -
    -Implementation - - -
    fun load_inner_mut(
    -    self: &mut AuthenticatorState,
    -): &mut AuthenticatorStateInner {
    -    let version = self.version;
    -
    -    // replace this with a lazy update function when we add a new version of the inner object.
    -    assert!(version == CurrentVersion, EWrongInnerVersion);
    -
    -    let inner: &mut AuthenticatorStateInner = dynamic_field::borrow_mut(&mut self.id, self.version);
    -
    -    assert!(inner.version == version, EWrongInnerVersion);
    -    inner
    -}
    -
    - - - -
    - - - -## Function `load_inner` - - - -
    fun load_inner(self: &authenticator_state::AuthenticatorState): &authenticator_state::AuthenticatorStateInner
    -
    - - - -
    -Implementation - - -
    fun load_inner(
    -    self: &AuthenticatorState,
    -): &AuthenticatorStateInner {
    -    let version = self.version;
    -
    -    // replace this with a lazy update function when we add a new version of the inner object.
    -    assert!(version == CurrentVersion, EWrongInnerVersion);
    -
    -    let inner: &AuthenticatorStateInner = dynamic_field::borrow(&self.id, self.version);
    -
    -    assert!(inner.version == version, EWrongInnerVersion);
    -    inner
    -}
    -
    - - - -
    - - - -## Function `check_sorted` - - - -
    fun check_sorted(new_active_jwks: &vector<authenticator_state::ActiveJwk>)
    -
    - - - -
    -Implementation - - -
    fun check_sorted(new_active_jwks: &vector<ActiveJwk>) {
    -    let mut i = 0;
    -    while (i < new_active_jwks.length() - 1) {
    -        let a = &new_active_jwks[i];
    -        let b = &new_active_jwks[i + 1];
    -        assert!(jwk_lt(a, b), EJwksNotSorted);
    -        i = i + 1;
    -    };
    -}
    -
    - - - -
    - - - -## Function `update_authenticator_state` - -Record a new set of active_jwks. Called when executing the AuthenticatorStateUpdate system -transaction. The new input vector must be sorted and must not contain duplicates. -If a new JWK is already present, but with a previous epoch, then the epoch is updated to -indicate that the JWK has been validated in the current epoch and should not be expired. - - -
    fun update_authenticator_state(self: &mut authenticator_state::AuthenticatorState, new_active_jwks: vector<authenticator_state::ActiveJwk>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    fun update_authenticator_state(
    -    self: &mut AuthenticatorState,
    -    new_active_jwks: vector<ActiveJwk>,
    -    ctx: &TxContext,
    -) {
    -    // Validator will make a special system call with sender set as 0x0.
    -    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    -
    -    check_sorted(&new_active_jwks);
    -    let new_active_jwks = deduplicate(new_active_jwks);
    -
    -    let inner = self.load_inner_mut();
    -
    -    let mut res = vector[];
    -    let mut i = 0;
    -    let mut j = 0;
    -    let active_jwks_len = inner.active_jwks.length();
    -    let new_active_jwks_len = new_active_jwks.length();
    -
    -    while (i < active_jwks_len && j < new_active_jwks_len) {
    -        let old_jwk = &inner.active_jwks[i];
    -        let new_jwk = &new_active_jwks[j];
    -
    -        // when they are equal, push only one, but use the max epoch of the two
    -        if (active_jwk_equal(old_jwk, new_jwk)) {
    -            let mut jwk = *old_jwk;
    -            jwk.epoch = math::max(old_jwk.epoch, new_jwk.epoch);
    -            res.push_back(jwk);
    -            i = i + 1;
    -            j = j + 1;
    -        } else if (jwk_id_equal(&old_jwk.jwk_id, &new_jwk.jwk_id)) {
    -            // if only jwk_id is equal, then the key has changed. Providers should not send
    -            // JWKs like this, but if they do, we must ignore the new JWK to avoid having a
    -            // liveness / forking issues
    -            res.push_back(*old_jwk);
    -            i = i + 1;
    -            j = j + 1;
    -        } else if (jwk_lt(old_jwk, new_jwk)) {
    -            res.push_back(*old_jwk);
    -            i = i + 1;
    -        } else {
    -            res.push_back(*new_jwk);
    -            j = j + 1;
    -        }
    -    };
    -
    -    while (i < active_jwks_len) {
    -        res.push_back(inner.active_jwks[i]);
    -        i = i + 1;
    -    };
    -    while (j < new_active_jwks_len) {
    -        res.push_back(new_active_jwks[j]);
    -        j = j + 1;
    -    };
    -
    -    inner.active_jwks = res;
    -}
    -
    - - - -
    - - - -## Function `deduplicate` - - - -
    fun deduplicate(jwks: vector<authenticator_state::ActiveJwk>): vector<authenticator_state::ActiveJwk>
    -
    - - - -
    -Implementation - - -
    fun deduplicate(jwks: vector<ActiveJwk>): vector<ActiveJwk> {
    -    let mut res = vector[];
    -    let mut i = 0;
    -    let mut prev: Option<JwkId> = option::none();
    -    while (i < jwks.length()) {
    -        let jwk = &jwks[i];
    -        if (prev.is_none()) {
    -            prev.fill(jwk.jwk_id);
    -        } else if (jwk_id_equal(prev.borrow(), &jwk.jwk_id)) {
    -            // skip duplicate jwks in input
    -            i = i + 1;
    -            continue
    -        } else {
    -            *prev.borrow_mut() = jwk.jwk_id;
    -        };
    -        res.push_back(*jwk);
    -        i = i + 1;
    -    };
    -    res
    -}
    -
    - - - -
    - - - -## Function `expire_jwks` - - - -
    fun expire_jwks(self: &mut authenticator_state::AuthenticatorState, min_epoch: u64, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    fun expire_jwks(
    -    self: &mut AuthenticatorState,
    -    // any jwk below this epoch is not retained
    -    min_epoch: u64,
    -    ctx: &TxContext) {
    -    // This will only be called by sui_system::advance_epoch
    -    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    -
    -    let inner = load_inner_mut(self);
    -
    -    let len = inner.active_jwks.length();
    -
    -    // first we count how many jwks from each issuer are above the min_epoch
    -    // and store the counts in a vector that parallels the (sorted) active_jwks vector
    -    let mut issuer_max_epochs = vector[];
    -    let mut i = 0;
    -    let mut prev_issuer: Option<String> = option::none();
    -
    -    while (i < len) {
    -        let cur = &inner.active_jwks[i];
    -        let cur_iss = &cur.jwk_id.iss;
    -        if (prev_issuer.is_none()) {
    -            prev_issuer.fill(*cur_iss);
    -            issuer_max_epochs.push_back(cur.epoch);
    -        } else {
    -            if (cur_iss == prev_issuer.borrow()) {
    -                let back = issuer_max_epochs.length() - 1;
    -                let prev_max_epoch = &mut issuer_max_epochs[back];
    -                *prev_max_epoch = math::max(*prev_max_epoch, cur.epoch);
    -            } else {
    -                *prev_issuer.borrow_mut() = *cur_iss;
    -                issuer_max_epochs.push_back(cur.epoch);
    -            }
    -        };
    -        i = i + 1;
    -    };
    -
    -    // Now, filter out any JWKs that are below the min_epoch, unless that issuer has no
    -    // JWKs >= the min_epoch, in which case we keep all of them.
    -    let mut new_active_jwks: vector<ActiveJwk> = vector[];
    -    let mut prev_issuer: Option<String> = option::none();
    -    let mut i = 0;
    -    let mut j = 0;
    -    while (i < len) {
    -        let jwk = &inner.active_jwks[i];
    -        let cur_iss = &jwk.jwk_id.iss;
    -
    -        if (prev_issuer.is_none()) {
    -            prev_issuer.fill(*cur_iss);
    -        } else if (cur_iss != prev_issuer.borrow()) {
    -            *prev_issuer.borrow_mut() = *cur_iss;
    -            j = j + 1;
    -        };
    -
    -        let max_epoch_for_iss = &issuer_max_epochs[j];
    -
    -        // TODO: if the iss for this jwk has *no* jwks that meet the minimum epoch,
    -        // then expire nothing.
    -        if (*max_epoch_for_iss < min_epoch || jwk.epoch >= min_epoch) {
    -            new_active_jwks.push_back(*jwk);
    -        };
    -        i = i + 1;
    -    };
    -    inner.active_jwks = new_active_jwks;
    -}
    -
    - - - -
    - - - -## Function `get_active_jwks` - -Get the current active_jwks. Called when the node starts up in order to load the current -JWK state from the chain. - - -
    fun get_active_jwks(self: &authenticator_state::AuthenticatorState, ctx: &tx_context::TxContext): vector<authenticator_state::ActiveJwk>
    -
    - - - -
    -Implementation - - -
    fun get_active_jwks(
    -    self: &AuthenticatorState,
    -    ctx: &TxContext,
    -): vector<ActiveJwk> {
    -    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    -    self.load_inner().active_jwks
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/bag.md b/crates/sui-framework/docs/sui-framework/bag.md deleted file mode 100644 index c97071bcc9f..00000000000 --- a/crates/sui-framework/docs/sui-framework/bag.md +++ /dev/null @@ -1,367 +0,0 @@ ---- -title: Module `0x2::bag` ---- - -A bag is a heterogeneous map-like collection. The collection is similar to sui::table in that -its keys and values are not stored within the Bag value, but instead are stored using Sui's -object system. The Bag struct acts only as a handle into the object system to retrieve those -keys and values. -Note that this means that Bag values with exactly the same key-value mapping will not be -equal, with ==, at runtime. For example -``` -let bag1 = bag::new(); -let bag2 = bag::new(); -bag::add(&mut bag1, 0, false); -bag::add(&mut bag1, 1, true); -bag::add(&mut bag2, 0, false); -bag::add(&mut bag2, 1, true); -// bag1 does not equal bag2, despite having the same entries -assert!(&bag1 != &bag2, 0); -``` -At it's core, sui::bag is a wrapper around UID that allows for access to -sui::dynamic_field while preventing accidentally stranding field values. A UID can be -deleted, even if it has dynamic fields associated with it, but a bag, on the other hand, must be -empty to be destroyed. - - -- [Resource `Bag`](#0x2_bag_Bag) -- [Constants](#@Constants_0) -- [Function `new`](#0x2_bag_new) -- [Function `add`](#0x2_bag_add) -- [Function `borrow`](#0x2_bag_borrow) -- [Function `borrow_mut`](#0x2_bag_borrow_mut) -- [Function `remove`](#0x2_bag_remove) -- [Function `contains`](#0x2_bag_contains) -- [Function `contains_with_type`](#0x2_bag_contains_with_type) -- [Function `length`](#0x2_bag_length) -- [Function `is_empty`](#0x2_bag_is_empty) -- [Function `destroy_empty`](#0x2_bag_destroy_empty) - - -
    use 0x2::dynamic_field;
    -use 0x2::object;
    -use 0x2::tx_context;
    -
    - - - - - -## Resource `Bag` - - - -
    struct Bag has store, key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - the ID of this bag -
    -
    -size: u64 -
    -
    - the number of key-value pairs in the bag -
    -
    - - -
    - - - -## Constants - - - - - - -
    const EBagNotEmpty: u64 = 0;
    -
    - - - - - -## Function `new` - -Creates a new, empty bag - - -
    public fun new(ctx: &mut tx_context::TxContext): bag::Bag
    -
    - - - -
    -Implementation - - -
    public fun new(ctx: &mut TxContext): Bag {
    -    Bag {
    -        id: object::new(ctx),
    -        size: 0,
    -    }
    -}
    -
    - - - -
    - - - -## Function `add` - -Adds a key-value pair to the bag bag: &mut Bag -Aborts with sui::dynamic_field::EFieldAlreadyExists if the bag already has an entry with -that key k: K. - - -
    public fun add<K: copy, drop, store, V: store>(bag: &mut bag::Bag, k: K, v: V)
    -
    - - - -
    -Implementation - - -
    public fun add<K: copy + drop + store, V: store>(bag: &mut Bag, k: K, v: V) {
    -    field::add(&mut bag.id, k, v);
    -    bag.size = bag.size + 1;
    -}
    -
    - - - -
    - - - -## Function `borrow` - -Immutable borrows the value associated with the key in the bag bag: &Bag. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the bag does not have an entry with -that key k: K. -Aborts with sui::dynamic_field::EFieldTypeMismatch if the bag has an entry for the key, but -the value does not have the specified type. - - -
    public fun borrow<K: copy, drop, store, V: store>(bag: &bag::Bag, k: K): &V
    -
    - - - -
    -Implementation - - -
    public fun borrow<K: copy + drop + store, V: store>(bag: &Bag, k: K): &V {
    -    field::borrow(&bag.id, k)
    -}
    -
    - - - -
    - - - -## Function `borrow_mut` - -Mutably borrows the value associated with the key in the bag bag: &mut Bag. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the bag does not have an entry with -that key k: K. -Aborts with sui::dynamic_field::EFieldTypeMismatch if the bag has an entry for the key, but -the value does not have the specified type. - - -
    public fun borrow_mut<K: copy, drop, store, V: store>(bag: &mut bag::Bag, k: K): &mut V
    -
    - - - -
    -Implementation - - -
    public fun borrow_mut<K: copy + drop + store, V: store>(bag: &mut Bag, k: K): &mut V {
    -    field::borrow_mut(&mut bag.id, k)
    -}
    -
    - - - -
    - - - -## Function `remove` - -Mutably borrows the key-value pair in the bag bag: &mut Bag and returns the value. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the bag does not have an entry with -that key k: K. -Aborts with sui::dynamic_field::EFieldTypeMismatch if the bag has an entry for the key, but -the value does not have the specified type. - - -
    public fun remove<K: copy, drop, store, V: store>(bag: &mut bag::Bag, k: K): V
    -
    - - - -
    -Implementation - - -
    public fun remove<K: copy + drop + store, V: store>(bag: &mut Bag, k: K): V {
    -    let v = field::remove(&mut bag.id, k);
    -    bag.size = bag.size - 1;
    -    v
    -}
    -
    - - - -
    - - - -## Function `contains` - -Returns true iff there is an value associated with the key k: K in the bag bag: &Bag - - -
    public fun contains<K: copy, drop, store>(bag: &bag::Bag, k: K): bool
    -
    - - - -
    -Implementation - - -
    public fun contains<K: copy + drop + store>(bag: &Bag, k: K): bool {
    -    field::exists_<K>(&bag.id, k)
    -}
    -
    - - - -
    - - - -## Function `contains_with_type` - -Returns true iff there is an value associated with the key k: K in the bag bag: &Bag -with an assigned value of type V - - -
    public fun contains_with_type<K: copy, drop, store, V: store>(bag: &bag::Bag, k: K): bool
    -
    - - - -
    -Implementation - - -
    public fun contains_with_type<K: copy + drop + store, V: store>(bag: &Bag, k: K): bool {
    -    field::exists_with_type<K, V>(&bag.id, k)
    -}
    -
    - - - -
    - - - -## Function `length` - -Returns the size of the bag, the number of key-value pairs - - -
    public fun length(bag: &bag::Bag): u64
    -
    - - - -
    -Implementation - - -
    public fun length(bag: &Bag): u64 {
    -    bag.size
    -}
    -
    - - - -
    - - - -## Function `is_empty` - -Returns true iff the bag is empty (if length returns 0) - - -
    public fun is_empty(bag: &bag::Bag): bool
    -
    - - - -
    -Implementation - - -
    public fun is_empty(bag: &Bag): bool {
    -    bag.size == 0
    -}
    -
    - - - -
    - - - -## Function `destroy_empty` - -Destroys an empty bag -Aborts with EBagNotEmpty if the bag still contains values - - -
    public fun destroy_empty(bag: bag::Bag)
    -
    - - - -
    -Implementation - - -
    public fun destroy_empty(bag: Bag) {
    -    let Bag { id, size } = bag;
    -    assert!(size == 0, EBagNotEmpty);
    -    id.delete()
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/balance.md b/crates/sui-framework/docs/sui-framework/balance.md deleted file mode 100644 index 44fe728ec4f..00000000000 --- a/crates/sui-framework/docs/sui-framework/balance.md +++ /dev/null @@ -1,477 +0,0 @@ ---- -title: Module `0x2::balance` ---- - -A storable handler for Balances in general. Is used in the Coin -module to allow balance operations and can be used to implement -custom coins with Supply and Balances. - - -- [Struct `Supply`](#0x2_balance_Supply) -- [Struct `Balance`](#0x2_balance_Balance) -- [Constants](#@Constants_0) -- [Function `value`](#0x2_balance_value) -- [Function `supply_value`](#0x2_balance_supply_value) -- [Function `create_supply`](#0x2_balance_create_supply) -- [Function `increase_supply`](#0x2_balance_increase_supply) -- [Function `decrease_supply`](#0x2_balance_decrease_supply) -- [Function `zero`](#0x2_balance_zero) -- [Function `join`](#0x2_balance_join) -- [Function `split`](#0x2_balance_split) -- [Function `withdraw_all`](#0x2_balance_withdraw_all) -- [Function `destroy_zero`](#0x2_balance_destroy_zero) -- [Function `create_staking_rewards`](#0x2_balance_create_staking_rewards) -- [Function `destroy_storage_rebates`](#0x2_balance_destroy_storage_rebates) -- [Function `destroy_supply`](#0x2_balance_destroy_supply) - - -
    use 0x2::tx_context;
    -
    - - - - - -## Struct `Supply` - -A Supply of T. Used for minting and burning. -Wrapped into a TreasuryCap in the Coin module. - - -
    struct Supply<T> has store
    -
    - - - -
    -Fields - - -
    -
    -value: u64 -
    -
    - -
    -
    - - -
    - - - -## Struct `Balance` - -Storable balance - an inner struct of a Coin type. -Can be used to store coins which don't need the key ability. - - -
    struct Balance<T> has store
    -
    - - - -
    -Fields - - -
    -
    -value: u64 -
    -
    - -
    -
    - - -
    - - - -## Constants - - - - -Sender is not @0x0 the system address. - - -
    const ENotSystemAddress: u64 = 3;
    -
    - - - - - -For when trying to destroy a non-zero balance. - - -
    const ENonZero: u64 = 0;
    -
    - - - - - -For when trying to withdraw more than there is. - - -
    const ENotEnough: u64 = 2;
    -
    - - - - - -For when an overflow is happening on Supply operations. - - -
    const EOverflow: u64 = 1;
    -
    - - - - - -## Function `value` - -Get the amount stored in a Balance. - - -
    public fun value<T>(self: &balance::Balance<T>): u64
    -
    - - - -
    -Implementation - - -
    public fun value<T>(self: &Balance<T>): u64 {
    -    self.value
    -}
    -
    - - - -
    - - - -## Function `supply_value` - -Get the Supply value. - - -
    public fun supply_value<T>(supply: &balance::Supply<T>): u64
    -
    - - - -
    -Implementation - - -
    public fun supply_value<T>(supply: &Supply<T>): u64 {
    -    supply.value
    -}
    -
    - - - -
    - - - -## Function `create_supply` - -Create a new supply for type T. - - -
    public fun create_supply<T: drop>(_: T): balance::Supply<T>
    -
    - - - -
    -Implementation - - -
    public fun create_supply<T: drop>(_: T): Supply<T> {
    -    Supply { value: 0 }
    -}
    -
    - - - -
    - - - -## Function `increase_supply` - -Increase supply by value and create a new Balance<T> with this value. - - -
    public fun increase_supply<T>(self: &mut balance::Supply<T>, value: u64): balance::Balance<T>
    -
    - - - -
    -Implementation - - -
    public fun increase_supply<T>(self: &mut Supply<T>, value: u64): Balance<T> {
    -    assert!(value < (18446744073709551615u64 - self.value), EOverflow);
    -    self.value = self.value + value;
    -    Balance { value }
    -}
    -
    - - - -
    - - - -## Function `decrease_supply` - -Burn a Balance and decrease Supply. - - -
    public fun decrease_supply<T>(self: &mut balance::Supply<T>, balance: balance::Balance<T>): u64
    -
    - - - -
    -Implementation - - -
    public fun decrease_supply<T>(self: &mut Supply<T>, balance: Balance<T>): u64 {
    -    let Balance { value } = balance;
    -    assert!(self.value >= value, EOverflow);
    -    self.value = self.value - value;
    -    value
    -}
    -
    - - - -
    - - - -## Function `zero` - -Create a zero Balance for type T. - - -
    public fun zero<T>(): balance::Balance<T>
    -
    - - - -
    -Implementation - - -
    public fun zero<T>(): Balance<T> {
    -    Balance { value: 0 }
    -}
    -
    - - - -
    - - - -## Function `join` - -Join two balances together. - - -
    public fun join<T>(self: &mut balance::Balance<T>, balance: balance::Balance<T>): u64
    -
    - - - -
    -Implementation - - -
    public fun join<T>(self: &mut Balance<T>, balance: Balance<T>): u64 {
    -    let Balance { value } = balance;
    -    self.value = self.value + value;
    -    self.value
    -}
    -
    - - - -
    - - - -## Function `split` - -Split a Balance and take a sub balance from it. - - -
    public fun split<T>(self: &mut balance::Balance<T>, value: u64): balance::Balance<T>
    -
    - - - -
    -Implementation - - -
    public fun split<T>(self: &mut Balance<T>, value: u64): Balance<T> {
    -    assert!(self.value >= value, ENotEnough);
    -    self.value = self.value - value;
    -    Balance { value }
    -}
    -
    - - - -
    - - - -## Function `withdraw_all` - -Withdraw all balance. After this the remaining balance must be 0. - - -
    public fun withdraw_all<T>(self: &mut balance::Balance<T>): balance::Balance<T>
    -
    - - - -
    -Implementation - - -
    public fun withdraw_all<T>(self: &mut Balance<T>): Balance<T> {
    -    let value = self.value;
    -    split(self, value)
    -}
    -
    - - - -
    - - - -## Function `destroy_zero` - -Destroy a zero Balance. - - -
    public fun destroy_zero<T>(balance: balance::Balance<T>)
    -
    - - - -
    -Implementation - - -
    public fun destroy_zero<T>(balance: Balance<T>) {
    -    assert!(balance.value == 0, ENonZero);
    -    let Balance { value: _ } = balance;
    -}
    -
    - - - -
    - - - -## Function `create_staking_rewards` - -CAUTION: this function creates a Balance without increasing the supply. -It should only be called by the epoch change system txn to create staking rewards, -and nowhere else. - - -
    fun create_staking_rewards<T>(value: u64, ctx: &tx_context::TxContext): balance::Balance<T>
    -
    - - - -
    -Implementation - - -
    fun create_staking_rewards<T>(value: u64, ctx: &TxContext): Balance<T> {
    -    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    -    Balance { value }
    -}
    -
    - - - -
    - - - -## Function `destroy_storage_rebates` - -CAUTION: this function destroys a Balance without decreasing the supply. -It should only be called by the epoch change system txn to destroy storage rebates, -and nowhere else. - - -
    fun destroy_storage_rebates<T>(self: balance::Balance<T>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    fun destroy_storage_rebates<T>(self: Balance<T>, ctx: &TxContext) {
    -    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    -    let Balance { value: _ } = self;
    -}
    -
    - - - -
    - - - -## Function `destroy_supply` - -Destroy a Supply preventing any further minting and burning. - - -
    public(friend) fun destroy_supply<T>(self: balance::Supply<T>): u64
    -
    - - - -
    -Implementation - - -
    public(package) fun destroy_supply<T>(self: Supply<T>): u64 {
    -    let Supply { value } = self;
    -    value
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/clock.md b/crates/sui-framework/docs/sui-framework/clock.md deleted file mode 100644 index f8e50611232..00000000000 --- a/crates/sui-framework/docs/sui-framework/clock.md +++ /dev/null @@ -1,171 +0,0 @@ ---- -title: Module `0x2::clock` ---- - -APIs for accessing time from move calls, via the Clock: a unique -shared object that is created at 0x6 during genesis. - - -- [Resource `Clock`](#0x2_clock_Clock) -- [Constants](#@Constants_0) -- [Function `timestamp_ms`](#0x2_clock_timestamp_ms) -- [Function `create`](#0x2_clock_create) -- [Function `consensus_commit_prologue`](#0x2_clock_consensus_commit_prologue) - - -
    use 0x2::object;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -
    - - - - - -## Resource `Clock` - -Singleton shared object that exposes time to Move calls. This -object is found at address 0x6, and can only be read (accessed -via an immutable reference) by entry functions. - -Entry Functions that attempt to accept Clock by mutable -reference or value will fail to verify, and honest validators -will not sign or execute transactions that use Clock as an -input parameter, unless it is passed by immutable reference. - - -
    struct Clock has key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -timestamp_ms: u64 -
    -
    - The clock's timestamp, which is set automatically by a - system transaction every time consensus commits a - schedule, or by sui::clock::increment_for_testing during - testing. -
    -
    - - -
    - - - -## Constants - - - - -Sender is not @0x0 the system address. - - -
    const ENotSystemAddress: u64 = 0;
    -
    - - - - - -## Function `timestamp_ms` - -The clock's current timestamp as a running total of -milliseconds since an arbitrary point in the past. - - -
    public fun timestamp_ms(clock: &clock::Clock): u64
    -
    - - - -
    -Implementation - - -
    public fun timestamp_ms(clock: &Clock): u64 {
    -    clock.timestamp_ms
    -}
    -
    - - - -
    - - - -## Function `create` - -Create and share the singleton Clock -- this function is -called exactly once, during genesis. - - -
    fun create(ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    fun create(ctx: &TxContext) {
    -    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    -
    -    transfer::share_object(Clock {
    -        id: object::clock(),
    -        // Initialised to zero, but set to a real timestamp by a
    -        // system transaction before it can be witnessed by a move
    -        // call.
    -        timestamp_ms: 0,
    -    })
    -}
    -
    - - - -
    - - - -## Function `consensus_commit_prologue` - - - -
    fun consensus_commit_prologue(clock: &mut clock::Clock, timestamp_ms: u64, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    fun consensus_commit_prologue(
    -    clock: &mut Clock,
    -    timestamp_ms: u64,
    -    ctx: &TxContext,
    -) {
    -    // Validator will make a special system call with sender set as 0x0.
    -    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    -
    -    clock.timestamp_ms = timestamp_ms
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/coin.md b/crates/sui-framework/docs/sui-framework/coin.md deleted file mode 100644 index 1fabe772e11..00000000000 --- a/crates/sui-framework/docs/sui-framework/coin.md +++ /dev/null @@ -1,1354 +0,0 @@ ---- -title: Module `0x2::coin` ---- - -Defines the Coin type - platform wide representation of fungible -tokens and coins. Coin can be described as a secure wrapper around -Balance type. - - -- [Resource `Coin`](#0x2_coin_Coin) -- [Resource `CoinMetadata`](#0x2_coin_CoinMetadata) -- [Resource `RegulatedCoinMetadata`](#0x2_coin_RegulatedCoinMetadata) -- [Resource `TreasuryCap`](#0x2_coin_TreasuryCap) -- [Resource `DenyCap`](#0x2_coin_DenyCap) -- [Struct `CurrencyCreated`](#0x2_coin_CurrencyCreated) -- [Constants](#@Constants_0) -- [Function `total_supply`](#0x2_coin_total_supply) -- [Function `treasury_into_supply`](#0x2_coin_treasury_into_supply) -- [Function `supply_immut`](#0x2_coin_supply_immut) -- [Function `supply_mut`](#0x2_coin_supply_mut) -- [Function `value`](#0x2_coin_value) -- [Function `balance`](#0x2_coin_balance) -- [Function `balance_mut`](#0x2_coin_balance_mut) -- [Function `from_balance`](#0x2_coin_from_balance) -- [Function `into_balance`](#0x2_coin_into_balance) -- [Function `take`](#0x2_coin_take) -- [Function `put`](#0x2_coin_put) -- [Function `join`](#0x2_coin_join) -- [Function `split`](#0x2_coin_split) -- [Function `divide_into_n`](#0x2_coin_divide_into_n) -- [Function `zero`](#0x2_coin_zero) -- [Function `destroy_zero`](#0x2_coin_destroy_zero) -- [Function `create_currency`](#0x2_coin_create_currency) -- [Function `create_regulated_currency`](#0x2_coin_create_regulated_currency) -- [Function `mint`](#0x2_coin_mint) -- [Function `mint_balance`](#0x2_coin_mint_balance) -- [Function `burn`](#0x2_coin_burn) -- [Function `deny_list_add`](#0x2_coin_deny_list_add) -- [Function `deny_list_remove`](#0x2_coin_deny_list_remove) -- [Function `deny_list_contains`](#0x2_coin_deny_list_contains) -- [Function `mint_and_transfer`](#0x2_coin_mint_and_transfer) -- [Function `update_name`](#0x2_coin_update_name) -- [Function `update_symbol`](#0x2_coin_update_symbol) -- [Function `update_description`](#0x2_coin_update_description) -- [Function `update_icon_url`](#0x2_coin_update_icon_url) -- [Function `get_decimals`](#0x2_coin_get_decimals) -- [Function `get_name`](#0x2_coin_get_name) -- [Function `get_symbol`](#0x2_coin_get_symbol) -- [Function `get_description`](#0x2_coin_get_description) -- [Function `get_icon_url`](#0x2_coin_get_icon_url) -- [Function `supply`](#0x2_coin_supply) - - -
    use 0x1::ascii;
    -use 0x1::option;
    -use 0x1::string;
    -use 0x1::type_name;
    -use 0x2::balance;
    -use 0x2::deny_list;
    -use 0x2::object;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -use 0x2::types;
    -use 0x2::url;
    -
    - - - - - -## Resource `Coin` - -A coin of type T worth value. Transferable and storable - - -
    struct Coin<T> has store, key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -balance: balance::Balance<T> -
    -
    - -
    -
    - - -
    - - - -## Resource `CoinMetadata` - -Each Coin type T created through create_currency function will have a -unique instance of CoinMetadata that stores the metadata for this coin type. - - -
    struct CoinMetadata<T> has store, key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -decimals: u8 -
    -
    - Number of decimal places the coin uses. - A coin with value N and decimals D should be shown as N / 10^D - E.g., a coin with value 7002 and decimals 3 should be displayed as 7.002 - This is metadata for display usage only. -
    -
    -name: string::String -
    -
    - Name for the token -
    -
    -symbol: ascii::String -
    -
    - Symbol for the token -
    -
    -description: string::String -
    -
    - Description of the token -
    -
    -icon_url: option::Option<url::Url> -
    -
    - URL for the token logo -
    -
    - - -
    - - - -## Resource `RegulatedCoinMetadata` - -Similar to CoinMetadata, but created only for regulated coins that use the DenyList. -This object is always immutable. - - -
    struct RegulatedCoinMetadata<T> has key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -coin_metadata_object: object::ID -
    -
    - The ID of the coin's CoinMetadata object. -
    -
    -deny_cap_object: object::ID -
    -
    - The ID of the coin's DenyCap object. -
    -
    - - -
    - - - -## Resource `TreasuryCap` - -Capability allowing the bearer to mint and burn -coins of type T. Transferable - - -
    struct TreasuryCap<T> has store, key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -total_supply: balance::Supply<T> -
    -
    - -
    -
    - - -
    - - - -## Resource `DenyCap` - -Capability allowing the bearer to freeze addresses, preventing those addresses from -interacting with the coin as an input to a transaction. - - -
    struct DenyCap<T> has store, key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    - - -
    - - - -## Struct `CurrencyCreated` - - - -
    struct CurrencyCreated<T> has copy, drop
    -
    - - - -
    -Fields - - -
    -
    -decimals: u8 -
    -
    - -
    -
    - - -
    - - - -## Constants - - - - -Trying to split a coin more times than its balance allows. - - -
    const ENotEnough: u64 = 2;
    -
    - - - - - -The index into the deny list vector for the sui::coin::Coin type. - - -
    const DENY_LIST_COIN_INDEX: u64 = 0;
    -
    - - - - - -A type passed to create_supply is not a one-time witness. - - -
    const EBadWitness: u64 = 0;
    -
    - - - - - -Invalid arguments are passed to a function. - - -
    const EInvalidArg: u64 = 1;
    -
    - - - - - -## Function `total_supply` - -Return the total number of T's in circulation. - - -
    public fun total_supply<T>(cap: &coin::TreasuryCap<T>): u64
    -
    - - - -
    -Implementation - - -
    public fun total_supply<T>(cap: &TreasuryCap<T>): u64 {
    -    balance::supply_value(&cap.total_supply)
    -}
    -
    - - - -
    - - - -## Function `treasury_into_supply` - -Unwrap TreasuryCap getting the Supply. - -Operation is irreversible. Supply cannot be converted into a TreasuryCap due -to different security guarantees (TreasuryCap can be created only once for a type) - - -
    public fun treasury_into_supply<T>(treasury: coin::TreasuryCap<T>): balance::Supply<T>
    -
    - - - -
    -Implementation - - -
    public fun treasury_into_supply<T>(treasury: TreasuryCap<T>): Supply<T> {
    -    let TreasuryCap { id, total_supply } = treasury;
    -    id.delete();
    -    total_supply
    -}
    -
    - - - -
    - - - -## Function `supply_immut` - -Get immutable reference to the treasury's Supply. - - -
    public fun supply_immut<T>(treasury: &coin::TreasuryCap<T>): &balance::Supply<T>
    -
    - - - -
    -Implementation - - -
    public fun supply_immut<T>(treasury: &TreasuryCap<T>): &Supply<T> {
    -    &treasury.total_supply
    -}
    -
    - - - -
    - - - -## Function `supply_mut` - -Get mutable reference to the treasury's Supply. - - -
    public fun supply_mut<T>(treasury: &mut coin::TreasuryCap<T>): &mut balance::Supply<T>
    -
    - - - -
    -Implementation - - -
    public fun supply_mut<T>(treasury: &mut TreasuryCap<T>): &mut Supply<T> {
    -    &mut treasury.total_supply
    -}
    -
    - - - -
    - - - -## Function `value` - -Public getter for the coin's value - - -
    public fun value<T>(self: &coin::Coin<T>): u64
    -
    - - - -
    -Implementation - - -
    public fun value<T>(self: &Coin<T>): u64 {
    -    self.balance.value()
    -}
    -
    - - - -
    - - - -## Function `balance` - -Get immutable reference to the balance of a coin. - - -
    public fun balance<T>(coin: &coin::Coin<T>): &balance::Balance<T>
    -
    - - - -
    -Implementation - - -
    public fun balance<T>(coin: &Coin<T>): &Balance<T> {
    -    &coin.balance
    -}
    -
    - - - -
    - - - -## Function `balance_mut` - -Get a mutable reference to the balance of a coin. - - -
    public fun balance_mut<T>(coin: &mut coin::Coin<T>): &mut balance::Balance<T>
    -
    - - - -
    -Implementation - - -
    public fun balance_mut<T>(coin: &mut Coin<T>): &mut Balance<T> {
    -    &mut coin.balance
    -}
    -
    - - - -
    - - - -## Function `from_balance` - -Wrap a balance into a Coin to make it transferable. - - -
    public fun from_balance<T>(balance: balance::Balance<T>, ctx: &mut tx_context::TxContext): coin::Coin<T>
    -
    - - - -
    -Implementation - - -
    public fun from_balance<T>(balance: Balance<T>, ctx: &mut TxContext): Coin<T> {
    -    Coin { id: object::new(ctx), balance }
    -}
    -
    - - - -
    - - - -## Function `into_balance` - -Destruct a Coin wrapper and keep the balance. - - -
    public fun into_balance<T>(coin: coin::Coin<T>): balance::Balance<T>
    -
    - - - -
    -Implementation - - -
    public fun into_balance<T>(coin: Coin<T>): Balance<T> {
    -    let Coin { id, balance } = coin;
    -    id.delete();
    -    balance
    -}
    -
    - - - -
    - - - -## Function `take` - -Take a Coin worth of value from Balance. -Aborts if value > balance.value - - -
    public fun take<T>(balance: &mut balance::Balance<T>, value: u64, ctx: &mut tx_context::TxContext): coin::Coin<T>
    -
    - - - -
    -Implementation - - -
    public fun take<T>(
    -    balance: &mut Balance<T>, value: u64, ctx: &mut TxContext,
    -): Coin<T> {
    -    Coin {
    -        id: object::new(ctx),
    -        balance: balance.split(value)
    -    }
    -}
    -
    - - - -
    - - - -## Function `put` - -Put a Coin<T> to the Balance<T>. - - -
    public fun put<T>(balance: &mut balance::Balance<T>, coin: coin::Coin<T>)
    -
    - - - -
    -Implementation - - -
    public fun put<T>(balance: &mut Balance<T>, coin: Coin<T>) {
    -    balance.join(into_balance(coin));
    -}
    -
    - - - -
    - - - -## Function `join` - -Consume the coin c and add its value to self. -Aborts if c.value + self.value > U64_MAX - - -
    public entry fun join<T>(self: &mut coin::Coin<T>, c: coin::Coin<T>)
    -
    - - - -
    -Implementation - - -
    public entry fun join<T>(self: &mut Coin<T>, c: Coin<T>) {
    -    let Coin { id, balance } = c;
    -    id.delete();
    -    self.balance.join(balance);
    -}
    -
    - - - -
    - - - -## Function `split` - -Split coin self to two coins, one with balance split_amount, -and the remaining balance is left is self. - - -
    public fun split<T>(self: &mut coin::Coin<T>, split_amount: u64, ctx: &mut tx_context::TxContext): coin::Coin<T>
    -
    - - - -
    -Implementation - - -
    public fun split<T>(
    -    self: &mut Coin<T>, split_amount: u64, ctx: &mut TxContext
    -): Coin<T> {
    -    take(&mut self.balance, split_amount, ctx)
    -}
    -
    - - - -
    - - - -## Function `divide_into_n` - -Split coin self into n - 1 coins with equal balances. The remainder is left in -self. Return newly created coins. - - -
    public fun divide_into_n<T>(self: &mut coin::Coin<T>, n: u64, ctx: &mut tx_context::TxContext): vector<coin::Coin<T>>
    -
    - - - -
    -Implementation - - -
    public fun divide_into_n<T>(
    -    self: &mut Coin<T>, n: u64, ctx: &mut TxContext
    -): vector<Coin<T>> {
    -    assert!(n > 0, EInvalidArg);
    -    assert!(n <= value(self), ENotEnough);
    -
    -    let mut vec = vector[];
    -    let mut i = 0;
    -    let split_amount = value(self) / n;
    -    while (i < n - 1) {
    -        vec.push_back(self.split(split_amount, ctx));
    -        i = i + 1;
    -    };
    -    vec
    -}
    -
    - - - -
    - - - -## Function `zero` - -Make any Coin with a zero value. Useful for placeholding -bids/payments or preemptively making empty balances. - - -
    public fun zero<T>(ctx: &mut tx_context::TxContext): coin::Coin<T>
    -
    - - - -
    -Implementation - - -
    public fun zero<T>(ctx: &mut TxContext): Coin<T> {
    -    Coin { id: object::new(ctx), balance: balance::zero() }
    -}
    -
    - - - -
    - - - -## Function `destroy_zero` - -Destroy a coin with value zero - - -
    public fun destroy_zero<T>(c: coin::Coin<T>)
    -
    - - - -
    -Implementation - - -
    public fun destroy_zero<T>(c: Coin<T>) {
    -    let Coin { id, balance } = c;
    -    id.delete();
    -    balance.destroy_zero()
    -}
    -
    - - - -
    - - - -## Function `create_currency` - -Create a new currency type T as and return the TreasuryCap for -T to the caller. Can only be called with a one-time-witness -type, ensuring that there's only one TreasuryCap per T. - - -
    public fun create_currency<T: drop>(witness: T, decimals: u8, symbol: vector<u8>, name: vector<u8>, description: vector<u8>, icon_url: option::Option<url::Url>, ctx: &mut tx_context::TxContext): (coin::TreasuryCap<T>, coin::CoinMetadata<T>)
    -
    - - - -
    -Implementation - - -
    public fun create_currency<T: drop>(
    -    witness: T,
    -    decimals: u8,
    -    symbol: vector<u8>,
    -    name: vector<u8>,
    -    description: vector<u8>,
    -    icon_url: Option<Url>,
    -    ctx: &mut TxContext
    -): (TreasuryCap<T>, CoinMetadata<T>) {
    -    // Make sure there's only one instance of the type T
    -    assert!(sui::types::is_one_time_witness(&witness), EBadWitness);
    -
    -    (
    -        TreasuryCap {
    -            id: object::new(ctx),
    -            total_supply: balance::create_supply(witness)
    -        },
    -        CoinMetadata {
    -            id: object::new(ctx),
    -            decimals,
    -            name: string::utf8(name),
    -            symbol: ascii::string(symbol),
    -            description: string::utf8(description),
    -            icon_url
    -        }
    -    )
    -}
    -
    - - - -
    - - - -## Function `create_regulated_currency` - -This creates a new currency, via create_currency, but with an extra capability that -allows for specific addresses to have their coins frozen. Those addresses cannot interact -with the coin as input objects. - - -
    public fun create_regulated_currency<T: drop>(witness: T, decimals: u8, symbol: vector<u8>, name: vector<u8>, description: vector<u8>, icon_url: option::Option<url::Url>, ctx: &mut tx_context::TxContext): (coin::TreasuryCap<T>, coin::DenyCap<T>, coin::CoinMetadata<T>)
    -
    - - - -
    -Implementation - - -
    public fun create_regulated_currency<T: drop>(
    -    witness: T,
    -    decimals: u8,
    -    symbol: vector<u8>,
    -    name: vector<u8>,
    -    description: vector<u8>,
    -    icon_url: Option<Url>,
    -    ctx: &mut TxContext
    -): (TreasuryCap<T>, DenyCap<T>, CoinMetadata<T>) {
    -    let (treasury_cap, metadata) = create_currency(
    -        witness,
    -        decimals,
    -        symbol,
    -        name,
    -        description,
    -        icon_url,
    -        ctx
    -    );
    -    let deny_cap = DenyCap {
    -        id: object::new(ctx),
    -    };
    -    transfer::freeze_object(RegulatedCoinMetadata<T> {
    -        id: object::new(ctx),
    -        coin_metadata_object: object::id(&metadata),
    -        deny_cap_object: object::id(&deny_cap),
    -    });
    -    (treasury_cap, deny_cap, metadata)
    -}
    -
    - - - -
    - - - -## Function `mint` - -Create a coin worth value and increase the total supply -in cap accordingly. - - -
    public fun mint<T>(cap: &mut coin::TreasuryCap<T>, value: u64, ctx: &mut tx_context::TxContext): coin::Coin<T>
    -
    - - - -
    -Implementation - - -
    public fun mint<T>(
    -    cap: &mut TreasuryCap<T>, value: u64, ctx: &mut TxContext,
    -): Coin<T> {
    -    Coin {
    -        id: object::new(ctx),
    -        balance: cap.total_supply.increase_supply(value)
    -    }
    -}
    -
    - - - -
    - - - -## Function `mint_balance` - -Mint some amount of T as a Balance and increase the total -supply in cap accordingly. -Aborts if value + cap.total_supply >= U64_MAX - - -
    public fun mint_balance<T>(cap: &mut coin::TreasuryCap<T>, value: u64): balance::Balance<T>
    -
    - - - -
    -Implementation - - -
    public fun mint_balance<T>(
    -    cap: &mut TreasuryCap<T>, value: u64
    -): Balance<T> {
    -    cap.total_supply.increase_supply(value)
    -}
    -
    - - - -
    - - - -## Function `burn` - -Destroy the coin c and decrease the total supply in cap -accordingly. - - -
    public entry fun burn<T>(cap: &mut coin::TreasuryCap<T>, c: coin::Coin<T>): u64
    -
    - - - -
    -Implementation - - -
    public entry fun burn<T>(cap: &mut TreasuryCap<T>, c: Coin<T>): u64 {
    -    let Coin { id, balance } = c;
    -    id.delete();
    -    cap.total_supply.decrease_supply(balance)
    -}
    -
    - - - -
    - - - -## Function `deny_list_add` - -Adds the given address to the deny list, preventing it -from interacting with the specified coin type as an input to a transaction. - - -
    public fun deny_list_add<T>(deny_list: &mut deny_list::DenyList, _deny_cap: &mut coin::DenyCap<T>, addr: address, _ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public fun deny_list_add<T>(
    -   deny_list: &mut DenyList,
    -   _deny_cap: &mut DenyCap<T>,
    -   addr: address,
    -   _ctx: &mut TxContext
    -) {
    -    let `type` =
    -        type_name::into_string(type_name::get_with_original_ids<T>()).into_bytes();
    -    deny_list::add(
    -        deny_list,
    -        DENY_LIST_COIN_INDEX,
    -        `type`,
    -        addr,
    -    )
    -}
    -
    - - - -
    - - - -## Function `deny_list_remove` - -Removes an address from the deny list. -Aborts with ENotFrozen if the address is not already in the list. - - -
    public fun deny_list_remove<T>(deny_list: &mut deny_list::DenyList, _deny_cap: &mut coin::DenyCap<T>, addr: address, _ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public fun deny_list_remove<T>(
    -   deny_list: &mut DenyList,
    -   _deny_cap: &mut DenyCap<T>,
    -   addr: address,
    -   _ctx: &mut TxContext
    -) {
    -    let `type` =
    -        type_name::into_string(type_name::get_with_original_ids<T>()).into_bytes();
    -    deny_list::remove(
    -        deny_list,
    -        DENY_LIST_COIN_INDEX,
    -        `type`,
    -        addr,
    -    )
    -}
    -
    - - - -
    - - - -## Function `deny_list_contains` - -Returns true iff the given address is denied for the given coin type. It will -return false if given a non-coin type. - - -
    public fun deny_list_contains<T>(freezer: &deny_list::DenyList, addr: address): bool
    -
    - - - -
    -Implementation - - -
    public fun deny_list_contains<T>(
    -   freezer: &DenyList,
    -   addr: address,
    -): bool {
    -    let name = type_name::get_with_original_ids<T>();
    -    if (type_name::is_primitive(&name)) return false;
    -
    -    let `type` = type_name::into_string(name).into_bytes();
    -    freezer.contains(DENY_LIST_COIN_INDEX, `type`, addr)
    -}
    -
    - - - -
    - - - -## Function `mint_and_transfer` - -Mint amount of Coin and send it to recipient. Invokes mint(). - - -
    public entry fun mint_and_transfer<T>(c: &mut coin::TreasuryCap<T>, amount: u64, recipient: address, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun mint_and_transfer<T>(
    -    c: &mut TreasuryCap<T>, amount: u64, recipient: address, ctx: &mut TxContext
    -) {
    -    transfer::public_transfer(mint(c, amount, ctx), recipient)
    -}
    -
    - - - -
    - - - -## Function `update_name` - -Update name of the coin in CoinMetadata - - -
    public entry fun update_name<T>(_treasury: &coin::TreasuryCap<T>, metadata: &mut coin::CoinMetadata<T>, name: string::String)
    -
    - - - -
    -Implementation - - -
    public entry fun update_name<T>(
    -    _treasury: &TreasuryCap<T>, metadata: &mut CoinMetadata<T>, name: string::String
    -) {
    -    metadata.name = name;
    -}
    -
    - - - -
    - - - -## Function `update_symbol` - -Update the symbol of the coin in CoinMetadata - - -
    public entry fun update_symbol<T>(_treasury: &coin::TreasuryCap<T>, metadata: &mut coin::CoinMetadata<T>, symbol: ascii::String)
    -
    - - - -
    -Implementation - - -
    public entry fun update_symbol<T>(
    -    _treasury: &TreasuryCap<T>, metadata: &mut CoinMetadata<T>, symbol: ascii::String
    -) {
    -    metadata.symbol = symbol;
    -}
    -
    - - - -
    - - - -## Function `update_description` - -Update the description of the coin in CoinMetadata - - -
    public entry fun update_description<T>(_treasury: &coin::TreasuryCap<T>, metadata: &mut coin::CoinMetadata<T>, description: string::String)
    -
    - - - -
    -Implementation - - -
    public entry fun update_description<T>(
    -    _treasury: &TreasuryCap<T>, metadata: &mut CoinMetadata<T>, description: string::String
    -) {
    -    metadata.description = description;
    -}
    -
    - - - -
    - - - -## Function `update_icon_url` - -Update the url of the coin in CoinMetadata - - -
    public entry fun update_icon_url<T>(_treasury: &coin::TreasuryCap<T>, metadata: &mut coin::CoinMetadata<T>, url: ascii::String)
    -
    - - - -
    -Implementation - - -
    public entry fun update_icon_url<T>(
    -    _treasury: &TreasuryCap<T>, metadata: &mut CoinMetadata<T>, url: ascii::String
    -) {
    -    metadata.icon_url = option::some(url::new_unsafe(url));
    -}
    -
    - - - -
    - - - -## Function `get_decimals` - - - -
    public fun get_decimals<T>(metadata: &coin::CoinMetadata<T>): u8
    -
    - - - -
    -Implementation - - -
    public fun get_decimals<T>(metadata: &CoinMetadata<T>): u8 {
    -    metadata.decimals
    -}
    -
    - - - -
    - - - -## Function `get_name` - - - -
    public fun get_name<T>(metadata: &coin::CoinMetadata<T>): string::String
    -
    - - - -
    -Implementation - - -
    public fun get_name<T>(metadata: &CoinMetadata<T>): string::String {
    -    metadata.name
    -}
    -
    - - - -
    - - - -## Function `get_symbol` - - - -
    public fun get_symbol<T>(metadata: &coin::CoinMetadata<T>): ascii::String
    -
    - - - -
    -Implementation - - -
    public fun get_symbol<T>(metadata: &CoinMetadata<T>): ascii::String {
    -    metadata.symbol
    -}
    -
    - - - -
    - - - -## Function `get_description` - - - -
    public fun get_description<T>(metadata: &coin::CoinMetadata<T>): string::String
    -
    - - - -
    -Implementation - - -
    public fun get_description<T>(metadata: &CoinMetadata<T>): string::String {
    -    metadata.description
    -}
    -
    - - - -
    - - - -## Function `get_icon_url` - - - -
    public fun get_icon_url<T>(metadata: &coin::CoinMetadata<T>): option::Option<url::Url>
    -
    - - - -
    -Implementation - - -
    public fun get_icon_url<T>(metadata: &CoinMetadata<T>): Option<Url> {
    -    metadata.icon_url
    -}
    -
    - - - -
    - - - -## Function `supply` - - - -
    public fun supply<T>(treasury: &mut coin::TreasuryCap<T>): &balance::Supply<T>
    -
    - - - -
    -Implementation - - -
    public fun supply<T>(treasury: &mut TreasuryCap<T>): &Supply<T> {
    -    &treasury.total_supply
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/deny_list.md b/crates/sui-framework/docs/sui-framework/deny_list.md deleted file mode 100644 index 5c8cb7378c6..00000000000 --- a/crates/sui-framework/docs/sui-framework/deny_list.md +++ /dev/null @@ -1,411 +0,0 @@ ---- -title: Module `0x2::deny_list` ---- - -Defines the DenyList type. The DenyList shared object is used to restrict access to -instances of certain core types from being used as inputs by specified addresses in the deny -list. - - -- [Resource `DenyList`](#0x2_deny_list_DenyList) -- [Resource `PerTypeList`](#0x2_deny_list_PerTypeList) -- [Constants](#@Constants_0) -- [Function `add`](#0x2_deny_list_add) -- [Function `per_type_list_add`](#0x2_deny_list_per_type_list_add) -- [Function `remove`](#0x2_deny_list_remove) -- [Function `per_type_list_remove`](#0x2_deny_list_per_type_list_remove) -- [Function `contains`](#0x2_deny_list_contains) -- [Function `per_type_list_contains`](#0x2_deny_list_per_type_list_contains) -- [Function `create`](#0x2_deny_list_create) -- [Function `per_type_list`](#0x2_deny_list_per_type_list) - - -
    use 0x2::bag;
    -use 0x2::object;
    -use 0x2::table;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -use 0x2::vec_set;
    -
    - - - - - -## Resource `DenyList` - -A shared object that stores the addresses that are blocked for a given core type. - - -
    struct DenyList has key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -lists: bag::Bag -
    -
    - The individual deny lists. -
    -
    - - -
    - - - -## Resource `PerTypeList` - -Stores the addresses that are denied for a given core type. - - -
    struct PerTypeList has store, key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -denied_count: table::Table<address, u64> -
    -
    - Number of object types that have been banned for a given address. - Used to quickly skip checks for most addresses. -
    -
    -denied_addresses: table::Table<vector<u8>, vec_set::VecSet<address>> -
    -
    - Set of addresses that are banned for a given type. - For example with sui::coin::Coin: If addresses A and B are banned from using - "0...0123::my_coin::MY_COIN", this will be "0...0123::my_coin::MY_COIN" -> {A, B}. -
    -
    - - -
    - - - -## Constants - - - - -Trying to create a deny list object when not called by the system address. - - -
    const ENotSystemAddress: u64 = 0;
    -
    - - - - - -The index into the deny list vector for the sui::coin::Coin type. - - -
    const COIN_INDEX: u64 = 0;
    -
    - - - - - -The specified address to be removed is not already in the deny list. - - -
    const ENotDenied: u64 = 1;
    -
    - - - - - -## Function `add` - -Adds the given address to the deny list of the specified type, preventing it -from interacting with instances of that type as an input to a transaction. For coins, -the type specified is the type of the coin, not the coin type itself. For example, -"00...0123::my_coin::MY_COIN" would be the type, not "00...02::coin::Coin". - - -
    public(friend) fun add(deny_list: &mut deny_list::DenyList, per_type_index: u64, type: vector<u8>, addr: address)
    -
    - - - -
    -Implementation - - -
    public(package) fun add(
    -    deny_list: &mut DenyList,
    -    per_type_index: u64,
    -    `type`: vector<u8>,
    -    addr: address,
    -) {
    -    let bag_entry: &mut PerTypeList = &mut deny_list.lists[per_type_index];
    -    bag_entry.per_type_list_add(`type`, addr)
    -}
    -
    - - - -
    - - - -## Function `per_type_list_add` - - - -
    fun per_type_list_add(list: &mut deny_list::PerTypeList, type: vector<u8>, addr: address)
    -
    - - - -
    -Implementation - - -
    fun per_type_list_add(
    -    list: &mut PerTypeList,
    -    `type`: vector<u8>,
    -    addr: address,
    -) {
    -    if (!list.denied_addresses.contains(`type`)) {
    -        list.denied_addresses.add(`type`, vec_set::empty());
    -    };
    -    let denied_addresses = &mut list.denied_addresses[`type`];
    -    let already_denied = denied_addresses.contains(&addr);
    -    if (already_denied) return;
    -
    -    denied_addresses.insert(addr);
    -    if (!list.denied_count.contains(addr)) {
    -        list.denied_count.add(addr, 0);
    -    };
    -    let denied_count = &mut list.denied_count[addr];
    -    *denied_count = *denied_count + 1;
    -}
    -
    - - - -
    - - - -## Function `remove` - -Removes a previously denied address from the list. -Aborts with ENotDenied if the address is not on the list. - - -
    public(friend) fun remove(deny_list: &mut deny_list::DenyList, per_type_index: u64, type: vector<u8>, addr: address)
    -
    - - - -
    -Implementation - - -
    public(package) fun remove(
    -    deny_list: &mut DenyList,
    -    per_type_index: u64,
    -    `type`: vector<u8>,
    -    addr: address,
    -) {
    -    per_type_list_remove(&mut deny_list.lists[per_type_index], `type`, addr)
    -}
    -
    - - - -
    - - - -## Function `per_type_list_remove` - - - -
    fun per_type_list_remove(list: &mut deny_list::PerTypeList, type: vector<u8>, addr: address)
    -
    - - - -
    -Implementation - - -
    fun per_type_list_remove(
    -    list: &mut PerTypeList,
    -    `type`: vector<u8>,
    -    addr: address,
    -) {
    -    let denied_addresses = &mut list.denied_addresses[`type`];
    -    assert!(denied_addresses.contains(&addr), ENotDenied);
    -    denied_addresses.remove(&addr);
    -    let denied_count = &mut list.denied_count[addr];
    -    *denied_count = *denied_count - 1;
    -    if (*denied_count == 0) {
    -        list.denied_count.remove(addr);
    -    }
    -}
    -
    - - - -
    - - - -## Function `contains` - -Returns true iff the given address is denied for the given type. - - -
    public(friend) fun contains(deny_list: &deny_list::DenyList, per_type_index: u64, type: vector<u8>, addr: address): bool
    -
    - - - -
    -Implementation - - -
    public(package) fun contains(
    -    deny_list: &DenyList,
    -    per_type_index: u64,
    -    `type`: vector<u8>,
    -    addr: address,
    -): bool {
    -    per_type_list_contains(&deny_list.lists[per_type_index], `type`, addr)
    -}
    -
    - - - -
    - - - -## Function `per_type_list_contains` - - - -
    fun per_type_list_contains(list: &deny_list::PerTypeList, type: vector<u8>, addr: address): bool
    -
    - - - -
    -Implementation - - -
    fun per_type_list_contains(
    -    list: &PerTypeList,
    -    `type`: vector<u8>,
    -    addr: address,
    -): bool {
    -    if (!list.denied_count.contains(addr)) return false;
    -
    -    let denied_count = &list.denied_count[addr];
    -    if (*denied_count == 0) return false;
    -
    -    if (!list.denied_addresses.contains(`type`)) return false;
    -
    -    let denied_addresses = &list.denied_addresses[`type`];
    -    denied_addresses.contains(&addr)
    -}
    -
    - - - -
    - - - -## Function `create` - -Creation of the deny list object is restricted to the system address -via a system transaction. - - -
    fun create(ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    fun create(ctx: &mut TxContext) {
    -    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    -
    -    let mut lists = bag::new(ctx);
    -    lists.add(COIN_INDEX, per_type_list(ctx));
    -    let deny_list_object = DenyList {
    -        id: object::sui_deny_list_object_id(),
    -        lists,
    -    };
    -    transfer::share_object(deny_list_object);
    -}
    -
    - - - -
    - - - -## Function `per_type_list` - - - -
    fun per_type_list(ctx: &mut tx_context::TxContext): deny_list::PerTypeList
    -
    - - - -
    -Implementation - - -
    fun per_type_list(ctx: &mut TxContext): PerTypeList {
    -    PerTypeList {
    -        id: object::new(ctx),
    -        denied_count: table::new(ctx),
    -        denied_addresses: table::new(ctx),
    -    }
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/dynamic_field.md b/crates/sui-framework/docs/sui-framework/dynamic_field.md deleted file mode 100644 index 2693ef914fc..00000000000 --- a/crates/sui-framework/docs/sui-framework/dynamic_field.md +++ /dev/null @@ -1,593 +0,0 @@ ---- -title: Module `0x2::dynamic_field` ---- - -In addition to the fields declared in its type definition, a Sui object can have dynamic fields -that can be added after the object has been constructed. Unlike ordinary field names -(which are always statically declared identifiers) a dynamic field name can be any value with -the copy, drop, and store abilities, e.g. an integer, a boolean, or a string. -This gives Sui programmers the flexibility to extend objects on-the-fly, and it also serves as a -building block for core collection types - - -- [Resource `Field`](#0x2_dynamic_field_Field) -- [Constants](#@Constants_0) -- [Function `add`](#0x2_dynamic_field_add) -- [Function `borrow`](#0x2_dynamic_field_borrow) -- [Function `borrow_mut`](#0x2_dynamic_field_borrow_mut) -- [Function `remove`](#0x2_dynamic_field_remove) -- [Function `exists_`](#0x2_dynamic_field_exists_) -- [Function `remove_if_exists`](#0x2_dynamic_field_remove_if_exists) -- [Function `exists_with_type`](#0x2_dynamic_field_exists_with_type) -- [Function `field_info`](#0x2_dynamic_field_field_info) -- [Function `field_info_mut`](#0x2_dynamic_field_field_info_mut) -- [Function `hash_type_and_key`](#0x2_dynamic_field_hash_type_and_key) -- [Function `add_child_object`](#0x2_dynamic_field_add_child_object) -- [Function `borrow_child_object`](#0x2_dynamic_field_borrow_child_object) -- [Function `borrow_child_object_mut`](#0x2_dynamic_field_borrow_child_object_mut) -- [Function `remove_child_object`](#0x2_dynamic_field_remove_child_object) -- [Function `has_child_object`](#0x2_dynamic_field_has_child_object) -- [Function `has_child_object_with_ty`](#0x2_dynamic_field_has_child_object_with_ty) - - -
    use 0x1::option;
    -use 0x2::object;
    -
    - - - - - -## Resource `Field` - -Internal object used for storing the field and value - - -
    struct Field<Name: copy, drop, store, Value: store> has key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - Determined by the hash of the object ID, the field name value and it's type, - i.e. hash(parent.id || name || Name) -
    -
    -name: Name -
    -
    - The value for the name of this field -
    -
    -value: Value -
    -
    - The value bound to this field -
    -
    - - -
    - - - -## Constants - - - - -Failed to serialize the field's name - - -
    const EBCSSerializationFailure: u64 = 3;
    -
    - - - - - -The object added as a dynamic field was previously a shared object - - -
    const ESharedObjectOperationNotSupported: u64 = 4;
    -
    - - - - - -The object already has a dynamic field with this name (with the value and type specified) - - -
    const EFieldAlreadyExists: u64 = 0;
    -
    - - - - - -Cannot load dynamic field. -The object does not have a dynamic field with this name (with the value and type specified) - - -
    const EFieldDoesNotExist: u64 = 1;
    -
    - - - - - -The object has a field with that name, but the value type does not match - - -
    const EFieldTypeMismatch: u64 = 2;
    -
    - - - - - -## Function `add` - -Adds a dynamic field to the object object: &mut UID at field specified by name: Name. -Aborts with EFieldAlreadyExists if the object already has that field with that name. - - -
    public fun add<Name: copy, drop, store, Value: store>(object: &mut object::UID, name: Name, value: Value)
    -
    - - - -
    -Implementation - - -
    public fun add<Name: copy + drop + store, Value: store>(
    -    // we use &mut UID in several spots for access control
    -    object: &mut UID,
    -    name: Name,
    -    value: Value,
    -) {
    -    let object_addr = object.to_address();
    -    let hash = hash_type_and_key(object_addr, name);
    -    assert!(!has_child_object(object_addr, hash), EFieldAlreadyExists);
    -    let field = Field {
    -        id: object::new_uid_from_hash(hash),
    -        name,
    -        value,
    -    };
    -    add_child_object(object_addr, field)
    -}
    -
    - - - -
    - - - -## Function `borrow` - -Immutably borrows the objects dynamic field with the name specified by name: Name. -Aborts with EFieldDoesNotExist if the object does not have a field with that name. -Aborts with EFieldTypeMismatch if the field exists, but the value does not have the specified -type. - - -
    public fun borrow<Name: copy, drop, store, Value: store>(object: &object::UID, name: Name): &Value
    -
    - - - -
    -Implementation - - -
    public fun borrow<Name: copy + drop + store, Value: store>(
    -    object: &UID,
    -    name: Name,
    -): &Value {
    -    let object_addr = object.to_address();
    -    let hash = hash_type_and_key(object_addr, name);
    -    let field = borrow_child_object<Field<Name, Value>>(object, hash);
    -    &field.value
    -}
    -
    - - - -
    - - - -## Function `borrow_mut` - -Mutably borrows the objects dynamic field with the name specified by name: Name. -Aborts with EFieldDoesNotExist if the object does not have a field with that name. -Aborts with EFieldTypeMismatch if the field exists, but the value does not have the specified -type. - - -
    public fun borrow_mut<Name: copy, drop, store, Value: store>(object: &mut object::UID, name: Name): &mut Value
    -
    - - - -
    -Implementation - - -
    public fun borrow_mut<Name: copy + drop + store, Value: store>(
    -    object: &mut UID,
    -    name: Name,
    -): &mut Value {
    -    let object_addr = object.to_address();
    -    let hash = hash_type_and_key(object_addr, name);
    -    let field = borrow_child_object_mut<Field<Name, Value>>(object, hash);
    -    &mut field.value
    -}
    -
    - - - -
    - - - -## Function `remove` - -Removes the objects dynamic field with the name specified by name: Name and returns the -bound value. -Aborts with EFieldDoesNotExist if the object does not have a field with that name. -Aborts with EFieldTypeMismatch if the field exists, but the value does not have the specified -type. - - -
    public fun remove<Name: copy, drop, store, Value: store>(object: &mut object::UID, name: Name): Value
    -
    - - - -
    -Implementation - - -
    public fun remove<Name: copy + drop + store, Value: store>(
    -    object: &mut UID,
    -    name: Name,
    -): Value {
    -    let object_addr = object.to_address();
    -    let hash = hash_type_and_key(object_addr, name);
    -    let Field { id, name: _, value } = remove_child_object<Field<Name, Value>>(object_addr, hash);
    -    id.delete();
    -    value
    -}
    -
    - - - -
    - - - -## Function `exists_` - -Returns true if and only if the object has a dynamic field with the name specified by -name: Name but without specifying the Value type - - -
    public fun exists_<Name: copy, drop, store>(object: &object::UID, name: Name): bool
    -
    - - - -
    -Implementation - - -
    public fun exists_<Name: copy + drop + store>(
    -    object: &UID,
    -    name: Name,
    -): bool {
    -    let object_addr = object.to_address();
    -    let hash = hash_type_and_key(object_addr, name);
    -    has_child_object(object_addr, hash)
    -}
    -
    - - - -
    - - - -## Function `remove_if_exists` - -Removes the dynamic field if it exists. Returns the some(Value) if it exists or none otherwise. - - -
    public fun remove_if_exists<Name: copy, drop, store, Value: store>(object: &mut object::UID, name: Name): option::Option<Value>
    -
    - - - -
    -Implementation - - -
    public fun remove_if_exists<Name: copy + drop + store, Value: store>(
    -    object: &mut UID,
    -    name: Name
    -): Option<Value> {
    -    if (exists_<Name>(object, name)) {
    -        option::some(remove(object, name))
    -    } else {
    -        option::none()
    -    }
    -}
    -
    - - - -
    - - - -## Function `exists_with_type` - -Returns true if and only if the object has a dynamic field with the name specified by -name: Name with an assigned value of type Value. - - -
    public fun exists_with_type<Name: copy, drop, store, Value: store>(object: &object::UID, name: Name): bool
    -
    - - - -
    -Implementation - - -
    public fun exists_with_type<Name: copy + drop + store, Value: store>(
    -    object: &UID,
    -    name: Name,
    -): bool {
    -    let object_addr = object.to_address();
    -    let hash = hash_type_and_key(object_addr, name);
    -    has_child_object_with_ty<Field<Name, Value>>(object_addr, hash)
    -}
    -
    - - - -
    - - - -## Function `field_info` - - - -
    public(friend) fun field_info<Name: copy, drop, store>(object: &object::UID, name: Name): (&object::UID, address)
    -
    - - - -
    -Implementation - - -
    public(package) fun field_info<Name: copy + drop + store>(
    -    object: &UID,
    -    name: Name,
    -): (&UID, address) {
    -    let object_addr = object.to_address();
    -    let hash = hash_type_and_key(object_addr, name);
    -    let Field { id, name: _, value } = borrow_child_object<Field<Name, ID>>(object, hash);
    -    (id, value.to_address())
    -}
    -
    - - - -
    - - - -## Function `field_info_mut` - - - -
    public(friend) fun field_info_mut<Name: copy, drop, store>(object: &mut object::UID, name: Name): (&mut object::UID, address)
    -
    - - - -
    -Implementation - - -
    public(package) fun field_info_mut<Name: copy + drop + store>(
    -    object: &mut UID,
    -    name: Name,
    -): (&mut UID, address) {
    -    let object_addr = object.to_address();
    -    let hash = hash_type_and_key(object_addr, name);
    -    let Field { id, name: _, value } = borrow_child_object_mut<Field<Name, ID>>(object, hash);
    -    (id, value.to_address())
    -}
    -
    - - - -
    - - - -## Function `hash_type_and_key` - -May abort with EBCSSerializationFailure. - - -
    public(friend) fun hash_type_and_key<K: copy, drop, store>(parent: address, k: K): address
    -
    - - - -
    -Implementation - - -
    public(package) native fun hash_type_and_key<K: copy + drop + store>(parent: address, k: K): address;
    -
    - - - -
    - - - -## Function `add_child_object` - - - -
    public(friend) fun add_child_object<Child: key>(parent: address, child: Child)
    -
    - - - -
    -Implementation - - -
    public(package) native fun add_child_object<Child: key>(parent: address, child: Child);
    -
    - - - -
    - - - -## Function `borrow_child_object` - -throws EFieldDoesNotExist if a child does not exist with that ID -or throws EFieldTypeMismatch if the type does not match, -and may also abort with EBCSSerializationFailure -we need two versions to return a reference or a mutable reference - - -
    public(friend) fun borrow_child_object<Child: key>(object: &object::UID, id: address): &Child
    -
    - - - -
    -Implementation - - -
    public(package) native fun borrow_child_object<Child: key>(object: &UID, id: address): &Child;
    -
    - - - -
    - - - -## Function `borrow_child_object_mut` - - - -
    public(friend) fun borrow_child_object_mut<Child: key>(object: &mut object::UID, id: address): &mut Child
    -
    - - - -
    -Implementation - - -
    public(package) native fun borrow_child_object_mut<Child: key>(object: &mut UID, id: address): &mut Child;
    -
    - - - -
    - - - -## Function `remove_child_object` - -throws EFieldDoesNotExist if a child does not exist with that ID -or throws EFieldTypeMismatch if the type does not match, -and may also abort with EBCSSerializationFailure. - - -
    public(friend) fun remove_child_object<Child: key>(parent: address, id: address): Child
    -
    - - - -
    -Implementation - - -
    public(package) native fun remove_child_object<Child: key>(parent: address, id: address): Child;
    -
    - - - -
    - - - -## Function `has_child_object` - - - -
    public(friend) fun has_child_object(parent: address, id: address): bool
    -
    - - - -
    -Implementation - - -
    public(package) native fun has_child_object(parent: address, id: address): bool;
    -
    - - - -
    - - - -## Function `has_child_object_with_ty` - - - -
    public(friend) fun has_child_object_with_ty<Child: key>(parent: address, id: address): bool
    -
    - - - -
    -Implementation - - -
    public(package) native fun has_child_object_with_ty<Child: key>(parent: address, id: address): bool;
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/dynamic_object_field.md b/crates/sui-framework/docs/sui-framework/dynamic_object_field.md deleted file mode 100644 index 6884726aac4..00000000000 --- a/crates/sui-framework/docs/sui-framework/dynamic_object_field.md +++ /dev/null @@ -1,284 +0,0 @@ ---- -title: Module `0x2::dynamic_object_field` ---- - -Similar to sui::dynamic_field, this module allows for the access of dynamic fields. But -unlike, sui::dynamic_field the values bound to these dynamic fields _must_ be objects -themselves. This allows for the objects to still exist within in storage, which may be important -for external tools. The difference is otherwise not observable from within Move. - - -- [Struct `Wrapper`](#0x2_dynamic_object_field_Wrapper) -- [Function `add`](#0x2_dynamic_object_field_add) -- [Function `borrow`](#0x2_dynamic_object_field_borrow) -- [Function `borrow_mut`](#0x2_dynamic_object_field_borrow_mut) -- [Function `remove`](#0x2_dynamic_object_field_remove) -- [Function `exists_`](#0x2_dynamic_object_field_exists_) -- [Function `exists_with_type`](#0x2_dynamic_object_field_exists_with_type) -- [Function `id`](#0x2_dynamic_object_field_id) - - -
    use 0x1::option;
    -use 0x2::dynamic_field;
    -use 0x2::object;
    -
    - - - - - -## Struct `Wrapper` - - - -
    struct Wrapper<Name> has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -name: Name -
    -
    - -
    -
    - - -
    - - - -## Function `add` - -Adds a dynamic object field to the object object: &mut UID at field specified by name: Name. -Aborts with EFieldAlreadyExists if the object already has that field with that name. - - -
    public fun add<Name: copy, drop, store, Value: store, key>(object: &mut object::UID, name: Name, value: Value)
    -
    - - - -
    -Implementation - - -
    public fun add<Name: copy + drop + store, Value: key + store>(
    -    // we use &mut UID in several spots for access control
    -    object: &mut UID,
    -    name: Name,
    -    value: Value,
    -) {
    -    let key = Wrapper { name };
    -    let id = object::id(&value);
    -    field::add(object, key, id);
    -    let (field, _) = field::field_info<Wrapper<Name>>(object, key);
    -    add_child_object(field.to_address(), value);
    -}
    -
    - - - -
    - - - -## Function `borrow` - -Immutably borrows the objects dynamic object field with the name specified by name: Name. -Aborts with EFieldDoesNotExist if the object does not have a field with that name. -Aborts with EFieldTypeMismatch if the field exists, but the value object does not have the -specified type. - - -
    public fun borrow<Name: copy, drop, store, Value: store, key>(object: &object::UID, name: Name): &Value
    -
    - - - -
    -Implementation - - -
    public fun borrow<Name: copy + drop + store, Value: key + store>(
    -    object: &UID,
    -    name: Name,
    -): &Value {
    -    let key = Wrapper { name };
    -    let (field, value_id) = field::field_info<Wrapper<Name>>(object, key);
    -    borrow_child_object<Value>(field, value_id)
    -}
    -
    - - - -
    - - - -## Function `borrow_mut` - -Mutably borrows the objects dynamic object field with the name specified by name: Name. -Aborts with EFieldDoesNotExist if the object does not have a field with that name. -Aborts with EFieldTypeMismatch if the field exists, but the value object does not have the -specified type. - - -
    public fun borrow_mut<Name: copy, drop, store, Value: store, key>(object: &mut object::UID, name: Name): &mut Value
    -
    - - - -
    -Implementation - - -
    public fun borrow_mut<Name: copy + drop + store, Value: key + store>(
    -    object: &mut UID,
    -    name: Name,
    -): &mut Value {
    -    let key = Wrapper { name };
    -    let (field, value_id) = field::field_info_mut<Wrapper<Name>>(object, key);
    -    borrow_child_object_mut<Value>(field, value_id)
    -}
    -
    - - - -
    - - - -## Function `remove` - -Removes the objects dynamic object field with the name specified by name: Name and returns -the bound object. -Aborts with EFieldDoesNotExist if the object does not have a field with that name. -Aborts with EFieldTypeMismatch if the field exists, but the value object does not have the -specified type. - - -
    public fun remove<Name: copy, drop, store, Value: store, key>(object: &mut object::UID, name: Name): Value
    -
    - - - -
    -Implementation - - -
    public fun remove<Name: copy + drop + store, Value: key + store>(
    -    object: &mut UID,
    -    name: Name,
    -): Value {
    -    let key = Wrapper { name };
    -    let (field, value_id) = field::field_info<Wrapper<Name>>(object, key);
    -    let value = remove_child_object<Value>(field.to_address(), value_id);
    -    field::remove<Wrapper<Name>, ID>(object, key);
    -    value
    -}
    -
    - - - -
    - - - -## Function `exists_` - -Returns true if and only if the object has a dynamic object field with the name specified by -name: Name. - - -
    public fun exists_<Name: copy, drop, store>(object: &object::UID, name: Name): bool
    -
    - - - -
    -Implementation - - -
    public fun exists_<Name: copy + drop + store>(
    -    object: &UID,
    -    name: Name,
    -): bool {
    -    let key = Wrapper { name };
    -    field::exists_with_type<Wrapper<Name>, ID>(object, key)
    -}
    -
    - - - -
    - - - -## Function `exists_with_type` - -Returns true if and only if the object has a dynamic field with the name specified by -name: Name with an assigned value of type Value. - - -
    public fun exists_with_type<Name: copy, drop, store, Value: store, key>(object: &object::UID, name: Name): bool
    -
    - - - -
    -Implementation - - -
    public fun exists_with_type<Name: copy + drop + store, Value: key + store>(
    -    object: &UID,
    -    name: Name,
    -): bool {
    -    let key = Wrapper { name };
    -    if (!field::exists_with_type<Wrapper<Name>, ID>(object, key)) return false;
    -    let (field, value_id) = field::field_info<Wrapper<Name>>(object, key);
    -    field::has_child_object_with_ty<Value>(field.to_address(), value_id)
    -}
    -
    - - - -
    - - - -## Function `id` - -Returns the ID of the object associated with the dynamic object field -Returns none otherwise - - -
    public fun id<Name: copy, drop, store>(object: &object::UID, name: Name): option::Option<object::ID>
    -
    - - - -
    -Implementation - - -
    public fun id<Name: copy + drop + store>(
    -    object: &UID,
    -    name: Name,
    -): Option<ID> {
    -    let key = Wrapper { name };
    -    if (!field::exists_with_type<Wrapper<Name>, ID>(object, key)) return option::none();
    -    let (_field, value_addr) = field::field_info<Wrapper<Name>>(object, key);
    -    option::some(value_addr.to_id())
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/event.md b/crates/sui-framework/docs/sui-framework/event.md deleted file mode 100644 index c300ed5aac6..00000000000 --- a/crates/sui-framework/docs/sui-framework/event.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Module `0x2::event` ---- - -Events module. Defines the sui::event::emit function which -creates and sends a custom MoveEvent as a part of the effects -certificate of the transaction. - -Every MoveEvent has the following properties: -- sender -- type signature (T) -- event data (the value of T) -- timestamp (local to a node) -- transaction digest - -Example: -``` -module my::marketplace { -use sui::event; -/* ... */ -struct ItemPurchased has copy, drop { -item_id: ID, buyer: address -} -entry fun buy(/* .... */) { -/* ... */ -event::emit(ItemPurchased { item_id: ..., buyer: .... }) -} -} -``` - - -- [Function `emit`](#0x2_event_emit) - - -
    - - - - - -## Function `emit` - -Emit a custom Move event, sending the data offchain. - -Used for creating custom indexes and tracking onchain -activity in a way that suits a specific application the most. - -The type T is the main way to index the event, and can contain -phantom parameters, eg emit(MyEvent<phantom T>). - - -
    public fun emit<T: copy, drop>(event: T)
    -
    - - - -
    -Implementation - - -
    public native fun emit<T: copy + drop>(event: T);
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/hex.md b/crates/sui-framework/docs/sui-framework/hex.md deleted file mode 100644 index 1c17b6ff9bc..00000000000 --- a/crates/sui-framework/docs/sui-framework/hex.md +++ /dev/null @@ -1,150 +0,0 @@ ---- -title: Module `0x2::hex` ---- - -HEX (Base16) encoding utility. - - -- [Constants](#@Constants_0) -- [Function `encode`](#0x2_hex_encode) -- [Function `decode`](#0x2_hex_decode) -- [Function `decode_byte`](#0x2_hex_decode_byte) - - -
    use 0x1::vector;
    -
    - - - - - -## Constants - - - - - - -
    const EInvalidHexLength: u64 = 0;
    -
    - - - - - - - -
    const ENotValidHexCharacter: u64 = 1;
    -
    - - - - - -Vector of Base16 values from 00 to FF - - -
    const HEX: vector<vector<u8>> = [ByteArray([48, 48]), ByteArray([48, 49]), ByteArray([48, 50]), ByteArray([48, 51]), ByteArray([48, 52]), ByteArray([48, 53]), ByteArray([48, 54]), ByteArray([48, 55]), ByteArray([48, 56]), ByteArray([48, 57]), ByteArray([48, 97]), ByteArray([48, 98]), ByteArray([48, 99]), ByteArray([48, 100]), ByteArray([48, 101]), ByteArray([48, 102]), ByteArray([49, 48]), ByteArray([49, 49]), ByteArray([49, 50]), ByteArray([49, 51]), ByteArray([49, 52]), ByteArray([49, 53]), ByteArray([49, 54]), ByteArray([49, 55]), ByteArray([49, 56]), ByteArray([49, 57]), ByteArray([49, 97]), ByteArray([49, 98]), ByteArray([49, 99]), ByteArray([49, 100]), ByteArray([49, 101]), ByteArray([49, 102]), ByteArray([50, 48]), ByteArray([50, 49]), ByteArray([50, 50]), ByteArray([50, 51]), ByteArray([50, 52]), ByteArray([50, 53]), ByteArray([50, 54]), ByteArray([50, 55]), ByteArray([50, 56]), ByteArray([50, 57]), ByteArray([50, 97]), ByteArray([50, 98]), ByteArray([50, 99]), ByteArray([50, 100]), ByteArray([50, 101]), ByteArray([50, 102]), ByteArray([51, 48]), ByteArray([51, 49]), ByteArray([51, 50]), ByteArray([51, 51]), ByteArray([51, 52]), ByteArray([51, 53]), ByteArray([51, 54]), ByteArray([51, 55]), ByteArray([51, 56]), ByteArray([51, 57]), ByteArray([51, 97]), ByteArray([51, 98]), ByteArray([51, 99]), ByteArray([51, 100]), ByteArray([51, 101]), ByteArray([51, 102]), ByteArray([52, 48]), ByteArray([52, 49]), ByteArray([52, 50]), ByteArray([52, 51]), ByteArray([52, 52]), ByteArray([52, 53]), ByteArray([52, 54]), ByteArray([52, 55]), ByteArray([52, 56]), ByteArray([52, 57]), ByteArray([52, 97]), ByteArray([52, 98]), ByteArray([52, 99]), ByteArray([52, 100]), ByteArray([52, 101]), ByteArray([52, 102]), ByteArray([53, 48]), ByteArray([53, 49]), ByteArray([53, 50]), ByteArray([53, 51]), ByteArray([53, 52]), ByteArray([53, 53]), ByteArray([53, 54]), ByteArray([53, 55]), ByteArray([53, 56]), ByteArray([53, 57]), ByteArray([53, 97]), ByteArray([53, 98]), ByteArray([53, 99]), ByteArray([53, 100]), ByteArray([53, 101]), ByteArray([53, 102]), ByteArray([54, 48]), ByteArray([54, 49]), ByteArray([54, 50]), ByteArray([54, 51]), ByteArray([54, 52]), ByteArray([54, 53]), ByteArray([54, 54]), ByteArray([54, 55]), ByteArray([54, 56]), ByteArray([54, 57]), ByteArray([54, 97]), ByteArray([54, 98]), ByteArray([54, 99]), ByteArray([54, 100]), ByteArray([54, 101]), ByteArray([54, 102]), ByteArray([55, 48]), ByteArray([55, 49]), ByteArray([55, 50]), ByteArray([55, 51]), ByteArray([55, 52]), ByteArray([55, 53]), ByteArray([55, 54]), ByteArray([55, 55]), ByteArray([55, 56]), ByteArray([55, 57]), ByteArray([55, 97]), ByteArray([55, 98]), ByteArray([55, 99]), ByteArray([55, 100]), ByteArray([55, 101]), ByteArray([55, 102]), ByteArray([56, 48]), ByteArray([56, 49]), ByteArray([56, 50]), ByteArray([56, 51]), ByteArray([56, 52]), ByteArray([56, 53]), ByteArray([56, 54]), ByteArray([56, 55]), ByteArray([56, 56]), ByteArray([56, 57]), ByteArray([56, 97]), ByteArray([56, 98]), ByteArray([56, 99]), ByteArray([56, 100]), ByteArray([56, 101]), ByteArray([56, 102]), ByteArray([57, 48]), ByteArray([57, 49]), ByteArray([57, 50]), ByteArray([57, 51]), ByteArray([57, 52]), ByteArray([57, 53]), ByteArray([57, 54]), ByteArray([57, 55]), ByteArray([57, 56]), ByteArray([57, 57]), ByteArray([57, 97]), ByteArray([57, 98]), ByteArray([57, 99]), ByteArray([57, 100]), ByteArray([57, 101]), ByteArray([57, 102]), ByteArray([97, 48]), ByteArray([97, 49]), ByteArray([97, 50]), ByteArray([97, 51]), ByteArray([97, 52]), ByteArray([97, 53]), ByteArray([97, 54]), ByteArray([97, 55]), ByteArray([97, 56]), ByteArray([97, 57]), ByteArray([97, 97]), ByteArray([97, 98]), ByteArray([97, 99]), ByteArray([97, 100]), ByteArray([97, 101]), ByteArray([97, 102]), ByteArray([98, 48]), ByteArray([98, 49]), ByteArray([98, 50]), ByteArray([98, 51]), ByteArray([98, 52]), ByteArray([98, 53]), ByteArray([98, 54]), ByteArray([98, 55]), ByteArray([98, 56]), ByteArray([98, 57]), ByteArray([98, 97]), ByteArray([98, 98]), ByteArray([98, 99]), ByteArray([98, 100]), ByteArray([98, 101]), ByteArray([98, 102]), ByteArray([99, 48]), ByteArray([99, 49]), ByteArray([99, 50]), ByteArray([99, 51]), ByteArray([99, 52]), ByteArray([99, 53]), ByteArray([99, 54]), ByteArray([99, 55]), ByteArray([99, 56]), ByteArray([99, 57]), ByteArray([99, 97]), ByteArray([99, 98]), ByteArray([99, 99]), ByteArray([99, 100]), ByteArray([99, 101]), ByteArray([99, 102]), ByteArray([100, 48]), ByteArray([100, 49]), ByteArray([100, 50]), ByteArray([100, 51]), ByteArray([100, 52]), ByteArray([100, 53]), ByteArray([100, 54]), ByteArray([100, 55]), ByteArray([100, 56]), ByteArray([100, 57]), ByteArray([100, 97]), ByteArray([100, 98]), ByteArray([100, 99]), ByteArray([100, 100]), ByteArray([100, 101]), ByteArray([100, 102]), ByteArray([101, 48]), ByteArray([101, 49]), ByteArray([101, 50]), ByteArray([101, 51]), ByteArray([101, 52]), ByteArray([101, 53]), ByteArray([101, 54]), ByteArray([101, 55]), ByteArray([101, 56]), ByteArray([101, 57]), ByteArray([101, 97]), ByteArray([101, 98]), ByteArray([101, 99]), ByteArray([101, 100]), ByteArray([101, 101]), ByteArray([101, 102]), ByteArray([102, 48]), ByteArray([102, 49]), ByteArray([102, 50]), ByteArray([102, 51]), ByteArray([102, 52]), ByteArray([102, 53]), ByteArray([102, 54]), ByteArray([102, 55]), ByteArray([102, 56]), ByteArray([102, 57]), ByteArray([102, 97]), ByteArray([102, 98]), ByteArray([102, 99]), ByteArray([102, 100]), ByteArray([102, 101]), ByteArray([102, 102])];
    -
    - - - - - -## Function `encode` - -Encode bytes in lowercase hex - - -
    public fun encode(bytes: vector<u8>): vector<u8>
    -
    - - - -
    -Implementation - - -
    public fun encode(bytes: vector<u8>): vector<u8> {
    -    let (mut i, mut r, l) = (0, vector[], bytes.length());
    -    let hex_vector = HEX;
    -    while (i < l) {
    -        r.append(hex_vector[bytes[i] as u64]);
    -        i = i + 1;
    -    };
    -    r
    -}
    -
    - - - -
    - - - -## Function `decode` - -Decode hex into bytes -Takes a hex string (no 0x prefix) (e.g. b"0f3a") -Returns vector of bytes that represents the hex string (e.g. x"0f3a") -Hex string can be case insensitive (e.g. b"0F3A" and b"0f3a" both return x"0f3a") -Aborts if the hex string does not have an even number of characters (as each hex character is 2 characters long) -Aborts if the hex string contains non-valid hex characters (valid characters are 0 - 9, a - f, A - F) - - -
    public fun decode(hex: vector<u8>): vector<u8>
    -
    - - - -
    -Implementation - - -
    public fun decode(hex: vector<u8>): vector<u8> {
    -    let (mut i, mut r, l) = (0, vector[], hex.length());
    -    assert!(l % 2 == 0, EInvalidHexLength);
    -    while (i < l) {
    -        let decimal = decode_byte(hex[i]) * 16 + decode_byte(hex[i + 1]);
    -        r.push_back(decimal);
    -        i = i + 2;
    -    };
    -    r
    -}
    -
    - - - -
    - - - -## Function `decode_byte` - - - -
    fun decode_byte(hex: u8): u8
    -
    - - - -
    -Implementation - - -
    fun decode_byte(hex: u8): u8 {
    -    if (/* 0 .. 9 */ 48 <= hex && hex < 58) {
    -        hex - 48
    -    } else if (/* A .. F */ 65 <= hex && hex < 71) {
    -        10 + hex - 65
    -    } else if (/* a .. f */ 97 <= hex && hex < 103) {
    -        10 + hex - 97
    -    } else {
    -        abort ENotValidHexCharacter
    -    }
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/hmac.md b/crates/sui-framework/docs/sui-framework/hmac.md deleted file mode 100644 index 3d1ae716c84..00000000000 --- a/crates/sui-framework/docs/sui-framework/hmac.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Module `0x2::hmac` ---- - - - -- [Function `hmac_sha3_256`](#0x2_hmac_hmac_sha3_256) - - -
    - - - - - -## Function `hmac_sha3_256` - -@param key: HMAC key, arbitrary bytes. -@param msg: message to sign, arbitrary bytes. -Returns the 32 bytes digest of HMAC-SHA3-256(key, msg). - - -
    public fun hmac_sha3_256(key: &vector<u8>, msg: &vector<u8>): vector<u8>
    -
    - - - -
    -Implementation - - -
    public native fun hmac_sha3_256(key: &vector<u8>, msg: &vector<u8>): vector<u8>;
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/linked_table.md b/crates/sui-framework/docs/sui-framework/linked_table.md deleted file mode 100644 index 4577908849a..00000000000 --- a/crates/sui-framework/docs/sui-framework/linked_table.md +++ /dev/null @@ -1,648 +0,0 @@ ---- -title: Module `0x2::linked_table` ---- - -Similar to sui::table but the values are linked together, allowing for ordered insertion and -removal - - -- [Resource `LinkedTable`](#0x2_linked_table_LinkedTable) -- [Struct `Node`](#0x2_linked_table_Node) -- [Constants](#@Constants_0) -- [Function `new`](#0x2_linked_table_new) -- [Function `front`](#0x2_linked_table_front) -- [Function `back`](#0x2_linked_table_back) -- [Function `push_front`](#0x2_linked_table_push_front) -- [Function `push_back`](#0x2_linked_table_push_back) -- [Function `borrow`](#0x2_linked_table_borrow) -- [Function `borrow_mut`](#0x2_linked_table_borrow_mut) -- [Function `prev`](#0x2_linked_table_prev) -- [Function `next`](#0x2_linked_table_next) -- [Function `remove`](#0x2_linked_table_remove) -- [Function `pop_front`](#0x2_linked_table_pop_front) -- [Function `pop_back`](#0x2_linked_table_pop_back) -- [Function `contains`](#0x2_linked_table_contains) -- [Function `length`](#0x2_linked_table_length) -- [Function `is_empty`](#0x2_linked_table_is_empty) -- [Function `destroy_empty`](#0x2_linked_table_destroy_empty) -- [Function `drop`](#0x2_linked_table_drop) - - -
    use 0x1::option;
    -use 0x2::dynamic_field;
    -use 0x2::object;
    -use 0x2::tx_context;
    -
    - - - - - -## Resource `LinkedTable` - - - -
    struct LinkedTable<K: copy, drop, store, V: store> has store, key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - the ID of this table -
    -
    -size: u64 -
    -
    - the number of key-value pairs in the table -
    -
    -head: option::Option<K> -
    -
    - the front of the table, i.e. the key of the first entry -
    -
    -tail: option::Option<K> -
    -
    - the back of the table, i.e. the key of the last entry -
    -
    - - -
    - - - -## Struct `Node` - - - -
    struct Node<K: copy, drop, store, V: store> has store
    -
    - - - -
    -Fields - - -
    -
    -prev: option::Option<K> -
    -
    - the previous key -
    -
    -next: option::Option<K> -
    -
    - the next key -
    -
    -value: V -
    -
    - the value being stored -
    -
    - - -
    - - - -## Constants - - - - - - -
    const ETableNotEmpty: u64 = 0;
    -
    - - - - - - - -
    const ETableIsEmpty: u64 = 1;
    -
    - - - - - -## Function `new` - -Creates a new, empty table - - -
    public fun new<K: copy, drop, store, V: store>(ctx: &mut tx_context::TxContext): linked_table::LinkedTable<K, V>
    -
    - - - -
    -Implementation - - -
    public fun new<K: copy + drop + store, V: store>(ctx: &mut TxContext): LinkedTable<K, V> {
    -    LinkedTable {
    -        id: object::new(ctx),
    -        size: 0,
    -        head: option::none(),
    -        tail: option::none(),
    -    }
    -}
    -
    - - - -
    - - - -## Function `front` - -Returns the key for the first element in the table, or None if the table is empty - - -
    public fun front<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>): &option::Option<K>
    -
    - - - -
    -Implementation - - -
    public fun front<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>): &Option<K> {
    -    &table.head
    -}
    -
    - - - -
    - - - -## Function `back` - -Returns the key for the last element in the table, or None if the table is empty - - -
    public fun back<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>): &option::Option<K>
    -
    - - - -
    -Implementation - - -
    public fun back<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>): &Option<K> {
    -    &table.tail
    -}
    -
    - - - -
    - - - -## Function `push_front` - -Inserts a key-value pair at the front of the table, i.e. the newly inserted pair will be -the first element in the table -Aborts with sui::dynamic_field::EFieldAlreadyExists if the table already has an entry with -that key k: K. - - -
    public fun push_front<K: copy, drop, store, V: store>(table: &mut linked_table::LinkedTable<K, V>, k: K, value: V)
    -
    - - - -
    -Implementation - - -
    public fun push_front<K: copy + drop + store, V: store>(
    -    table: &mut LinkedTable<K, V>,
    -    k: K,
    -    value: V,
    -) {
    -    let old_head = table.head.swap_or_fill(k);
    -    if (table.tail.is_none()) table.tail.fill(k);
    -    let prev = option::none();
    -    let next = if (old_head.is_some()) {
    -        let old_head_k = old_head.destroy_some();
    -        field::borrow_mut<K, Node<K, V>>(&mut table.id, old_head_k).prev = option::some(k);
    -        option::some(old_head_k)
    -    } else {
    -        option::none()
    -    };
    -    field::add(&mut table.id, k, Node { prev, next, value });
    -    table.size = table.size + 1;
    -}
    -
    - - - -
    - - - -## Function `push_back` - -Inserts a key-value pair at the back of the table, i.e. the newly inserted pair will be -the last element in the table -Aborts with sui::dynamic_field::EFieldAlreadyExists if the table already has an entry with -that key k: K. - - -
    public fun push_back<K: copy, drop, store, V: store>(table: &mut linked_table::LinkedTable<K, V>, k: K, value: V)
    -
    - - - -
    -Implementation - - -
    public fun push_back<K: copy + drop + store, V: store>(
    -    table: &mut LinkedTable<K, V>,
    -    k: K,
    -    value: V,
    -) {
    -    if (table.head.is_none()) table.head.fill(k);
    -    let old_tail = table.tail.swap_or_fill(k);
    -    let prev = if (old_tail.is_some()) {
    -        let old_tail_k = old_tail.destroy_some();
    -        field::borrow_mut<K, Node<K, V>>(&mut table.id, old_tail_k).next = option::some(k);
    -        option::some(old_tail_k)
    -    } else {
    -        option::none()
    -    };
    -    let next = option::none();
    -    field::add(&mut table.id, k, Node { prev, next, value });
    -    table.size = table.size + 1;
    -}
    -
    - - - -
    - - - -## Function `borrow` - -Immutable borrows the value associated with the key in the table table: &LinkedTable<K, V>. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the table does not have an entry with -that key k: K. - - -
    public fun borrow<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>, k: K): &V
    -
    - - - -
    -Implementation - - -
    public fun borrow<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>, k: K): &V {
    -    &field::borrow<K, Node<K, V>>(&table.id, k).value
    -}
    -
    - - - -
    - - - -## Function `borrow_mut` - -Mutably borrows the value associated with the key in the table table: &mut LinkedTable<K, V>. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the table does not have an entry with -that key k: K. - - -
    public fun borrow_mut<K: copy, drop, store, V: store>(table: &mut linked_table::LinkedTable<K, V>, k: K): &mut V
    -
    - - - -
    -Implementation - - -
    public fun borrow_mut<K: copy + drop + store, V: store>(
    -    table: &mut LinkedTable<K, V>,
    -    k: K,
    -): &mut V {
    -    &mut field::borrow_mut<K, Node<K, V>>(&mut table.id, k).value
    -}
    -
    - - - -
    - - - -## Function `prev` - -Borrows the key for the previous entry of the specified key k: K in the table -table: &LinkedTable<K, V>. Returns None if the entry does not have a predecessor. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the table does not have an entry with -that key k: K - - -
    public fun prev<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>, k: K): &option::Option<K>
    -
    - - - -
    -Implementation - - -
    public fun prev<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>, k: K): &Option<K> {
    -    &field::borrow<K, Node<K, V>>(&table.id, k).prev
    -}
    -
    - - - -
    - - - -## Function `next` - -Borrows the key for the next entry of the specified key k: K in the table -table: &LinkedTable<K, V>. Returns None if the entry does not have a predecessor. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the table does not have an entry with -that key k: K - - -
    public fun next<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>, k: K): &option::Option<K>
    -
    - - - -
    -Implementation - - -
    public fun next<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>, k: K): &Option<K> {
    -    &field::borrow<K, Node<K, V>>(&table.id, k).next
    -}
    -
    - - - -
    - - - -## Function `remove` - -Removes the key-value pair in the table table: &mut LinkedTable<K, V> and returns the value. -This splices the element out of the ordering. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the table does not have an entry with -that key k: K. Note: this is also what happens when the table is empty. - - -
    public fun remove<K: copy, drop, store, V: store>(table: &mut linked_table::LinkedTable<K, V>, k: K): V
    -
    - - - -
    -Implementation - - -
    public fun remove<K: copy + drop + store, V: store>(table: &mut LinkedTable<K, V>, k: K): V {
    -    let Node<K, V> { prev, next, value } = field::remove(&mut table.id, k);
    -    table.size = table.size - 1;
    -    if (prev.is_some()) {
    -        field::borrow_mut<K, Node<K, V>>(&mut table.id, *prev.borrow()).next = next
    -    };
    -    if (next.is_some()) {
    -        field::borrow_mut<K, Node<K, V>>(&mut table.id, *next.borrow()).prev = prev
    -    };
    -    if (table.head.borrow() == &k) table.head = next;
    -    if (table.tail.borrow() == &k) table.tail = prev;
    -    value
    -}
    -
    - - - -
    - - - -## Function `pop_front` - -Removes the front of the table table: &mut LinkedTable<K, V> and returns the value. -Aborts with ETableIsEmpty if the table is empty - - -
    public fun pop_front<K: copy, drop, store, V: store>(table: &mut linked_table::LinkedTable<K, V>): (K, V)
    -
    - - - -
    -Implementation - - -
    public fun pop_front<K: copy + drop + store, V: store>(table: &mut LinkedTable<K, V>): (K, V) {
    -    assert!(table.head.is_some(), ETableIsEmpty);
    -    let head = *table.head.borrow();
    -    (head, table.remove(head))
    -}
    -
    - - - -
    - - - -## Function `pop_back` - -Removes the back of the table table: &mut LinkedTable<K, V> and returns the value. -Aborts with ETableIsEmpty if the table is empty - - -
    public fun pop_back<K: copy, drop, store, V: store>(table: &mut linked_table::LinkedTable<K, V>): (K, V)
    -
    - - - -
    -Implementation - - -
    public fun pop_back<K: copy + drop + store, V: store>(table: &mut LinkedTable<K, V>): (K, V) {
    -    assert!(table.tail.is_some(), ETableIsEmpty);
    -    let tail = *table.tail.borrow();
    -    (tail, table.remove(tail))
    -}
    -
    - - - -
    - - - -## Function `contains` - -Returns true iff there is a value associated with the key k: K in table -table: &LinkedTable<K, V> - - -
    public fun contains<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>, k: K): bool
    -
    - - - -
    -Implementation - - -
    public fun contains<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>, k: K): bool {
    -    field::exists_with_type<K, Node<K, V>>(&table.id, k)
    -}
    -
    - - - -
    - - - -## Function `length` - -Returns the size of the table, the number of key-value pairs - - -
    public fun length<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>): u64
    -
    - - - -
    -Implementation - - -
    public fun length<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>): u64 {
    -    table.size
    -}
    -
    - - - -
    - - - -## Function `is_empty` - -Returns true iff the table is empty (if length returns 0) - - -
    public fun is_empty<K: copy, drop, store, V: store>(table: &linked_table::LinkedTable<K, V>): bool
    -
    - - - -
    -Implementation - - -
    public fun is_empty<K: copy + drop + store, V: store>(table: &LinkedTable<K, V>): bool {
    -    table.size == 0
    -}
    -
    - - - -
    - - - -## Function `destroy_empty` - -Destroys an empty table -Aborts with ETableNotEmpty if the table still contains values - - -
    public fun destroy_empty<K: copy, drop, store, V: store>(table: linked_table::LinkedTable<K, V>)
    -
    - - - -
    -Implementation - - -
    public fun destroy_empty<K: copy + drop + store, V: store>(table: LinkedTable<K, V>) {
    -    let LinkedTable { id, size, head: _, tail: _ } = table;
    -    assert!(size == 0, ETableNotEmpty);
    -    id.delete()
    -}
    -
    - - - -
    - - - -## Function `drop` - -Drop a possibly non-empty table. -Usable only if the value type V has the drop ability - - -
    public fun drop<K: copy, drop, store, V: drop, store>(table: linked_table::LinkedTable<K, V>)
    -
    - - - -
    -Implementation - - -
    public fun drop<K: copy + drop + store, V: drop + store>(table: LinkedTable<K, V>) {
    -    let LinkedTable { id, size: _, head: _, tail: _ } = table;
    -    id.delete()
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/object.md b/crates/sui-framework/docs/sui-framework/object.md deleted file mode 100644 index 7bebc36eef2..00000000000 --- a/crates/sui-framework/docs/sui-framework/object.md +++ /dev/null @@ -1,764 +0,0 @@ ---- -title: Module `0x2::object` ---- - -Sui object identifiers - - -- [Struct `ID`](#0x2_object_ID) -- [Struct `UID`](#0x2_object_UID) -- [Constants](#@Constants_0) -- [Function `id_to_bytes`](#0x2_object_id_to_bytes) -- [Function `id_to_address`](#0x2_object_id_to_address) -- [Function `id_from_bytes`](#0x2_object_id_from_bytes) -- [Function `id_from_address`](#0x2_object_id_from_address) -- [Function `sui_system_state`](#0x2_object_sui_system_state) -- [Function `clock`](#0x2_object_clock) -- [Function `authenticator_state`](#0x2_object_authenticator_state) -- [Function `randomness_state`](#0x2_object_randomness_state) -- [Function `sui_deny_list_object_id`](#0x2_object_sui_deny_list_object_id) -- [Function `uid_as_inner`](#0x2_object_uid_as_inner) -- [Function `uid_to_inner`](#0x2_object_uid_to_inner) -- [Function `uid_to_bytes`](#0x2_object_uid_to_bytes) -- [Function `uid_to_address`](#0x2_object_uid_to_address) -- [Function `new`](#0x2_object_new) -- [Function `delete`](#0x2_object_delete) -- [Function `id`](#0x2_object_id) -- [Function `borrow_id`](#0x2_object_borrow_id) -- [Function `id_bytes`](#0x2_object_id_bytes) -- [Function `id_address`](#0x2_object_id_address) -- [Function `borrow_uid`](#0x2_object_borrow_uid) -- [Function `new_uid_from_hash`](#0x2_object_new_uid_from_hash) -- [Function `delete_impl`](#0x2_object_delete_impl) -- [Function `record_new_uid`](#0x2_object_record_new_uid) - - -
    use 0x1::bcs;
    -use 0x2::address;
    -use 0x2::tx_context;
    -
    - - - - - -## Struct `ID` - -An object ID. This is used to reference Sui Objects. -This is *not* guaranteed to be globally unique--anyone can create an ID from a UID or -from an object, and ID's can be freely copied and dropped. -Here, the values are not globally unique because there can be multiple values of type ID -with the same underlying bytes. For example, object::id(&obj) can be called as many times -as you want for a given obj, and each ID value will be identical. - - -
    struct ID has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -bytes: address -
    -
    - -
    -
    - - -
    - - - -## Struct `UID` - -Globally unique IDs that define an object's ID in storage. Any Sui Object, that is a struct -with the key ability, must have id: UID as its first field. -These are globally unique in the sense that no two values of type UID are ever equal, in -other words for any two values id1: UID and id2: UID, id1 != id2. -This is a privileged type that can only be derived from a TxContext. -UID doesn't have the drop ability, so deleting a UID requires a call to delete. - - -
    struct UID has store
    -
    - - - -
    -Fields - - -
    -
    -id: object::ID -
    -
    - -
    -
    - - -
    - - - -## Constants - - - - -Sender is not @0x0 the system address. - - -
    const ENotSystemAddress: u64 = 0;
    -
    - - - - - -The hardcoded ID for the singleton AuthenticatorState Object. - - -
    const SUI_AUTHENTICATOR_STATE_ID: address = 7;
    -
    - - - - - -The hardcoded ID for the singleton Clock Object. - - -
    const SUI_CLOCK_OBJECT_ID: address = 6;
    -
    - - - - - -The hardcoded ID for the singleton DenyList. - - -
    const SUI_DENY_LIST_OBJECT_ID: address = 403;
    -
    - - - - - -The hardcoded ID for the singleton Random Object. - - -
    const SUI_RANDOM_ID: address = 8;
    -
    - - - - - -The hardcoded ID for the singleton Sui System State Object. - - -
    const SUI_SYSTEM_STATE_OBJECT_ID: address = 5;
    -
    - - - - - -## Function `id_to_bytes` - -Get the raw bytes of a ID - - -
    public fun id_to_bytes(id: &object::ID): vector<u8>
    -
    - - - -
    -Implementation - - -
    public fun id_to_bytes(id: &ID): vector<u8> {
    -    bcs::to_bytes(&id.bytes)
    -}
    -
    - - - -
    - - - -## Function `id_to_address` - -Get the inner bytes of id as an address. - - -
    public fun id_to_address(id: &object::ID): address
    -
    - - - -
    -Implementation - - -
    public fun id_to_address(id: &ID): address {
    -    id.bytes
    -}
    -
    - - - -
    - - - -## Function `id_from_bytes` - -Make an ID from raw bytes. - - -
    public fun id_from_bytes(bytes: vector<u8>): object::ID
    -
    - - - -
    -Implementation - - -
    public fun id_from_bytes(bytes: vector<u8>): ID {
    -    address::from_bytes(bytes).to_id()
    -}
    -
    - - - -
    - - - -## Function `id_from_address` - -Make an ID from an address. - - -
    public fun id_from_address(bytes: address): object::ID
    -
    - - - -
    -Implementation - - -
    public fun id_from_address(bytes: address): ID {
    -    ID { bytes }
    -}
    -
    - - - -
    - - - -## Function `sui_system_state` - -Create the UID for the singleton SuiSystemState object. -This should only be called once from sui_system. - - -
    fun sui_system_state(ctx: &tx_context::TxContext): object::UID
    -
    - - - -
    -Implementation - - -
    fun sui_system_state(ctx: &TxContext): UID {
    -    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    -    UID {
    -        id: ID { bytes: SUI_SYSTEM_STATE_OBJECT_ID },
    -    }
    -}
    -
    - - - -
    - - - -## Function `clock` - -Create the UID for the singleton Clock object. -This should only be called once from clock. - - -
    public(friend) fun clock(): object::UID
    -
    - - - -
    -Implementation - - -
    public(package) fun clock(): UID {
    -    UID {
    -        id: ID { bytes: SUI_CLOCK_OBJECT_ID }
    -    }
    -}
    -
    - - - -
    - - - -## Function `authenticator_state` - -Create the UID for the singleton AuthenticatorState object. -This should only be called once from authenticator_state. - - -
    public(friend) fun authenticator_state(): object::UID
    -
    - - - -
    -Implementation - - -
    public(package) fun authenticator_state(): UID {
    -    UID {
    -        id: ID { bytes: SUI_AUTHENTICATOR_STATE_ID }
    -    }
    -}
    -
    - - - -
    - - - -## Function `randomness_state` - -Create the UID for the singleton Random object. -This should only be called once from random. - - -
    public(friend) fun randomness_state(): object::UID
    -
    - - - -
    -Implementation - - -
    public(package) fun randomness_state(): UID {
    -    UID {
    -        id: ID { bytes: SUI_RANDOM_ID }
    -    }
    -}
    -
    - - - -
    - - - -## Function `sui_deny_list_object_id` - -Create the UID for the singleton DenyList object. -This should only be called once from deny_list. - - -
    public(friend) fun sui_deny_list_object_id(): object::UID
    -
    - - - -
    -Implementation - - -
    public(package) fun sui_deny_list_object_id(): UID {
    -    UID {
    -        id: ID { bytes: SUI_DENY_LIST_OBJECT_ID }
    -    }
    -}
    -
    - - - -
    - - - -## Function `uid_as_inner` - -Get the inner ID of uid - - -
    public fun uid_as_inner(uid: &object::UID): &object::ID
    -
    - - - -
    -Implementation - - -
    public fun uid_as_inner(uid: &UID): &ID {
    -    &uid.id
    -}
    -
    - - - -
    - - - -## Function `uid_to_inner` - -Get the raw bytes of a uid's inner ID - - -
    public fun uid_to_inner(uid: &object::UID): object::ID
    -
    - - - -
    -Implementation - - -
    public fun uid_to_inner(uid: &UID): ID {
    -    uid.id
    -}
    -
    - - - -
    - - - -## Function `uid_to_bytes` - -Get the raw bytes of a UID - - -
    public fun uid_to_bytes(uid: &object::UID): vector<u8>
    -
    - - - -
    -Implementation - - -
    public fun uid_to_bytes(uid: &UID): vector<u8> {
    -    bcs::to_bytes(&uid.id.bytes)
    -}
    -
    - - - -
    - - - -## Function `uid_to_address` - -Get the inner bytes of id as an address. - - -
    public fun uid_to_address(uid: &object::UID): address
    -
    - - - -
    -Implementation - - -
    public fun uid_to_address(uid: &UID): address {
    -    uid.id.bytes
    -}
    -
    - - - -
    - - - -## Function `new` - -Create a new object. Returns the UID that must be stored in a Sui object. -This is the only way to create UIDs. - - -
    public fun new(ctx: &mut tx_context::TxContext): object::UID
    -
    - - - -
    -Implementation - - -
    public fun new(ctx: &mut TxContext): UID {
    -    UID {
    -        id: ID { bytes: ctx.fresh_object_address() },
    -    }
    -}
    -
    - - - -
    - - - -## Function `delete` - -Delete the object and it's UID. This is the only way to eliminate a UID. - - -
    public fun delete(id: object::UID)
    -
    - - - -
    -Implementation - - -
    public fun delete(id: UID) {
    -    let UID { id: ID { bytes } } = id;
    -    delete_impl(bytes)
    -}
    -
    - - - -
    - - - -## Function `id` - -Get the underlying ID of obj - - -
    public fun id<T: key>(obj: &T): object::ID
    -
    - - - -
    -Implementation - - -
    public fun id<T: key>(obj: &T): ID {
    -    borrow_uid(obj).id
    -}
    -
    - - - -
    - - - -## Function `borrow_id` - -Borrow the underlying ID of obj - - -
    public fun borrow_id<T: key>(obj: &T): &object::ID
    -
    - - - -
    -Implementation - - -
    public fun borrow_id<T: key>(obj: &T): &ID {
    -    &borrow_uid(obj).id
    -}
    -
    - - - -
    - - - -## Function `id_bytes` - -Get the raw bytes for the underlying ID of obj - - -
    public fun id_bytes<T: key>(obj: &T): vector<u8>
    -
    - - - -
    -Implementation - - -
    public fun id_bytes<T: key>(obj: &T): vector<u8> {
    -    bcs::to_bytes(&borrow_uid(obj).id)
    -}
    -
    - - - -
    - - - -## Function `id_address` - -Get the inner bytes for the underlying ID of obj - - -
    public fun id_address<T: key>(obj: &T): address
    -
    - - - -
    -Implementation - - -
    public fun id_address<T: key>(obj: &T): address {
    -    borrow_uid(obj).id.bytes
    -}
    -
    - - - -
    - - - -## Function `borrow_uid` - -Get the UID for obj. -Safe because Sui has an extra bytecode verifier pass that forces every struct with -the key ability to have a distinguished UID field. -Cannot be made public as the access to UID for a given object must be privileged, and -restrictable in the object's module. - - -
    fun borrow_uid<T: key>(obj: &T): &object::UID
    -
    - - - -
    -Implementation - - -
    native fun borrow_uid<T: key>(obj: &T): &UID;
    -
    - - - -
    - - - -## Function `new_uid_from_hash` - -Generate a new UID specifically used for creating a UID from a hash - - -
    public(friend) fun new_uid_from_hash(bytes: address): object::UID
    -
    - - - -
    -Implementation - - -
    public(package) fun new_uid_from_hash(bytes: address): UID {
    -    record_new_uid(bytes);
    -    UID { id: ID { bytes } }
    -}
    -
    - - - -
    - - - -## Function `delete_impl` - - - -
    fun delete_impl(id: address)
    -
    - - - -
    -Implementation - - -
    native fun delete_impl(id: address);
    -
    - - - -
    - - - -## Function `record_new_uid` - - - -
    fun record_new_uid(id: address)
    -
    - - - -
    -Implementation - - -
    native fun record_new_uid(id: address);
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/pay.md b/crates/sui-framework/docs/sui-framework/pay.md deleted file mode 100644 index 05b26f34526..00000000000 --- a/crates/sui-framework/docs/sui-framework/pay.md +++ /dev/null @@ -1,273 +0,0 @@ ---- -title: Module `0x2::pay` ---- - -This module provides handy functionality for wallets and sui::Coin management. - - -- [Constants](#@Constants_0) -- [Function `keep`](#0x2_pay_keep) -- [Function `split`](#0x2_pay_split) -- [Function `split_vec`](#0x2_pay_split_vec) -- [Function `split_and_transfer`](#0x2_pay_split_and_transfer) -- [Function `divide_and_keep`](#0x2_pay_divide_and_keep) -- [Function `join`](#0x2_pay_join) -- [Function `join_vec`](#0x2_pay_join_vec) -- [Function `join_vec_and_transfer`](#0x2_pay_join_vec_and_transfer) - - -
    use 0x2::coin;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -
    - - - - - -## Constants - - - - -For when empty vector is supplied into join function. - - -
    const ENoCoins: u64 = 0;
    -
    - - - - - -## Function `keep` - -Transfer c to the sender of the current transaction - - -
    public fun keep<T>(c: coin::Coin<T>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public fun keep<T>(c: Coin<T>, ctx: &TxContext) {
    -    transfer::public_transfer(c, ctx.sender())
    -}
    -
    - - - -
    - - - -## Function `split` - -Split coin self to two coins, one with balance split_amount, -and the remaining balance is left is self. - - -
    public entry fun split<T>(coin: &mut coin::Coin<T>, split_amount: u64, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun split<T>(
    -    coin: &mut Coin<T>, split_amount: u64, ctx: &mut TxContext
    -) {
    -    keep(coin.split(split_amount, ctx), ctx)
    -}
    -
    - - - -
    - - - -## Function `split_vec` - -Split coin self into multiple coins, each with balance specified -in split_amounts. Remaining balance is left in self. - - -
    public entry fun split_vec<T>(self: &mut coin::Coin<T>, split_amounts: vector<u64>, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun split_vec<T>(
    -    self: &mut Coin<T>, split_amounts: vector<u64>, ctx: &mut TxContext
    -) {
    -    let (mut i, len) = (0, split_amounts.length());
    -    while (i < len) {
    -        split(self, split_amounts[i], ctx);
    -        i = i + 1;
    -    };
    -}
    -
    - - - -
    - - - -## Function `split_and_transfer` - -Send amount units of c to recipient -Aborts with EVALUE if amount is greater than or equal to amount - - -
    public entry fun split_and_transfer<T>(c: &mut coin::Coin<T>, amount: u64, recipient: address, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun split_and_transfer<T>(
    -    c: &mut Coin<T>, amount: u64, recipient: address, ctx: &mut TxContext
    -) {
    -    transfer::public_transfer(c.split(amount, ctx), recipient)
    -}
    -
    - - - -
    - - - -## Function `divide_and_keep` - -Divide coin self into n - 1 coins with equal balances. If the balance is -not evenly divisible by n, the remainder is left in self. - - -
    public entry fun divide_and_keep<T>(self: &mut coin::Coin<T>, n: u64, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun divide_and_keep<T>(
    -    self: &mut Coin<T>, n: u64, ctx: &mut TxContext
    -) {
    -    let mut vec: vector<Coin<T>> = self.divide_into_n(n, ctx);
    -    let (mut i, len) = (0, vec.length());
    -    while (i < len) {
    -        transfer::public_transfer(vec.pop_back(), ctx.sender());
    -        i = i + 1;
    -    };
    -    vec.destroy_empty();
    -}
    -
    - - - -
    - - - -## Function `join` - -Join coin into self. Re-exports coin::join function. -Deprecated: you should call coin.join(other) directly. - - -
    public entry fun join<T>(self: &mut coin::Coin<T>, coin: coin::Coin<T>)
    -
    - - - -
    -Implementation - - -
    public entry fun join<T>(self: &mut Coin<T>, coin: Coin<T>) {
    -    self.join(coin)
    -}
    -
    - - - -
    - - - -## Function `join_vec` - -Join everything in coins with self - - -
    public entry fun join_vec<T>(self: &mut coin::Coin<T>, coins: vector<coin::Coin<T>>)
    -
    - - - -
    -Implementation - - -
    public entry fun join_vec<T>(self: &mut Coin<T>, mut coins: vector<Coin<T>>) {
    -    let (mut i, len) = (0, coins.length());
    -    while (i < len) {
    -        let coin = coins.pop_back();
    -        self.join(coin);
    -        i = i + 1
    -    };
    -    // safe because we've drained the vector
    -    coins.destroy_empty()
    -}
    -
    - - - -
    - - - -## Function `join_vec_and_transfer` - -Join a vector of Coin into a single object and transfer it to receiver. - - -
    public entry fun join_vec_and_transfer<T>(coins: vector<coin::Coin<T>>, receiver: address)
    -
    - - - -
    -Implementation - - -
    public entry fun join_vec_and_transfer<T>(mut coins: vector<Coin<T>>, receiver: address) {
    -    assert!(coins.length() > 0, ENoCoins);
    -
    -    let mut self = coins.pop_back();
    -    join_vec(&mut self, coins);
    -    transfer::public_transfer(self, receiver)
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/priority_queue.md b/crates/sui-framework/docs/sui-framework/priority_queue.md deleted file mode 100644 index 7fd5a94dae7..00000000000 --- a/crates/sui-framework/docs/sui-framework/priority_queue.md +++ /dev/null @@ -1,368 +0,0 @@ ---- -title: Module `0x2::priority_queue` ---- - -Priority queue implemented using a max heap. - - -- [Struct `PriorityQueue`](#0x2_priority_queue_PriorityQueue) -- [Struct `Entry`](#0x2_priority_queue_Entry) -- [Constants](#@Constants_0) -- [Function `new`](#0x2_priority_queue_new) -- [Function `pop_max`](#0x2_priority_queue_pop_max) -- [Function `insert`](#0x2_priority_queue_insert) -- [Function `new_entry`](#0x2_priority_queue_new_entry) -- [Function `create_entries`](#0x2_priority_queue_create_entries) -- [Function `restore_heap_recursive`](#0x2_priority_queue_restore_heap_recursive) -- [Function `max_heapify_recursive`](#0x2_priority_queue_max_heapify_recursive) -- [Function `priorities`](#0x2_priority_queue_priorities) - - -
    use 0x1::vector;
    -
    - - - - - -## Struct `PriorityQueue` - -Struct representing a priority queue. The entries vector represents a max -heap structure, where entries[0] is the root, entries[1] and entries[2] are the -left child and right child of the root, etc. More generally, the children of -entries[i] are at at i * 2 + 1 and i * 2 + 2. The max heap should have the invariant -that the parent node's priority is always higher than its child nodes' priorities. - - -
    struct PriorityQueue<T: drop> has drop, store
    -
    - - - -
    -Fields - - -
    -
    -entries: vector<priority_queue::Entry<T>> -
    -
    - -
    -
    - - -
    - - - -## Struct `Entry` - - - -
    struct Entry<T: drop> has drop, store
    -
    - - - -
    -Fields - - -
    -
    -priority: u64 -
    -
    - -
    -
    -value: T -
    -
    - -
    -
    - - -
    - - - -## Constants - - - - -For when heap is empty and there's no data to pop. - - -
    const EPopFromEmptyHeap: u64 = 0;
    -
    - - - - - -## Function `new` - -Create a new priority queue from the input entry vectors. - - -
    public fun new<T: drop>(entries: vector<priority_queue::Entry<T>>): priority_queue::PriorityQueue<T>
    -
    - - - -
    -Implementation - - -
    public fun new<T: drop>(mut entries: vector<Entry<T>>) : PriorityQueue<T> {
    -    let len = entries.length();
    -    let mut i = len / 2;
    -    // Max heapify from the first node that is a parent (node at len / 2).
    -    while (i > 0) {
    -        i = i - 1;
    -        max_heapify_recursive(&mut entries, len, i);
    -    };
    -    PriorityQueue { entries }
    -}
    -
    - - - -
    - - - -## Function `pop_max` - -Pop the entry with the highest priority value. - - -
    public fun pop_max<T: drop>(pq: &mut priority_queue::PriorityQueue<T>): (u64, T)
    -
    - - - -
    -Implementation - - -
    public fun pop_max<T: drop>(pq: &mut PriorityQueue<T>) : (u64, T) {
    -    let len = pq.entries.length();
    -    assert!(len > 0, EPopFromEmptyHeap);
    -    // Swap the max element with the last element in the entries and remove the max element.
    -    let Entry { priority, value } = pq.entries.swap_remove(0);
    -    // Now the max heap property has been violated at the root node, but nowhere else
    -    // so we call max heapify on the root node.
    -    max_heapify_recursive(&mut pq.entries, len - 1, 0);
    -    (priority, value)
    -}
    -
    - - - -
    - - - -## Function `insert` - -Insert a new entry into the queue. - - -
    public fun insert<T: drop>(pq: &mut priority_queue::PriorityQueue<T>, priority: u64, value: T)
    -
    - - - -
    -Implementation - - -
    public fun insert<T: drop>(pq: &mut PriorityQueue<T>, priority: u64, value: T) {
    -    pq.entries.push_back(Entry { priority, value});
    -    let index = pq.entries.length() - 1;
    -    restore_heap_recursive(&mut pq.entries, index);
    -}
    -
    - - - -
    - - - -## Function `new_entry` - - - -
    public fun new_entry<T: drop>(priority: u64, value: T): priority_queue::Entry<T>
    -
    - - - -
    -Implementation - - -
    public fun new_entry<T: drop>(priority: u64, value: T): Entry<T> {
    -    Entry { priority, value }
    -}
    -
    - - - -
    - - - -## Function `create_entries` - - - -
    public fun create_entries<T: drop>(p: vector<u64>, v: vector<T>): vector<priority_queue::Entry<T>>
    -
    - - - -
    -Implementation - - -
    public fun create_entries<T: drop>(mut p: vector<u64>, mut v: vector<T>): vector<Entry<T>> {
    -    let len = p.length();
    -    assert!(v.length() == len, 0);
    -    let mut res = vector[];
    -    let mut i = 0;
    -    while (i < len) {
    -        let priority = p.remove(0);
    -        let value = v.remove(0);
    -        res.push_back(Entry { priority, value });
    -        i = i + 1;
    -    };
    -    res
    -}
    -
    - - - -
    - - - -## Function `restore_heap_recursive` - - - -
    fun restore_heap_recursive<T: drop>(v: &mut vector<priority_queue::Entry<T>>, i: u64)
    -
    - - - -
    -Implementation - - -
    fun restore_heap_recursive<T: drop>(v: &mut vector<Entry<T>>, i: u64) {
    -    if (i == 0) {
    -        return
    -    };
    -    let parent = (i - 1) / 2;
    -
    -    // If new elem is greater than its parent, swap them and recursively
    -    // do the restoration upwards.
    -    if (*&v[i].priority > *&v[parent].priority) {
    -        v.swap(i, parent);
    -        restore_heap_recursive(v, parent);
    -    }
    -}
    -
    - - - -
    - - - -## Function `max_heapify_recursive` - -Max heapify the subtree whose root is at index i. That means after this function -finishes, the subtree should have the property that the parent node has higher priority -than both child nodes. -This function assumes that all the other nodes in the subtree (nodes other than the root) -do satisfy the max heap property. - - -
    fun max_heapify_recursive<T: drop>(v: &mut vector<priority_queue::Entry<T>>, len: u64, i: u64)
    -
    - - - -
    -Implementation - - -
    fun max_heapify_recursive<T: drop>(v: &mut vector<Entry<T>>, len: u64, i: u64) {
    -    if (len == 0) {
    -        return
    -    };
    -    assert!(i < len, 1);
    -    let left = i * 2 + 1;
    -    let right = left + 1;
    -    let mut max = i;
    -    // Find the node with highest priority among node `i` and its two children.
    -    if (left < len && *&v[left].priority > *&v[max].priority) {
    -        max = left;
    -    };
    -    if (right < len && *&v[right].priority > *&v[max].priority) {
    -        max = right;
    -    };
    -    // If the parent node (node `i`) doesn't have the highest priority, we swap the parent with the
    -    // max priority node.
    -    if (max != i) {
    -        v.swap(max, i);
    -        // After the swap, we have restored the property at node `i` but now the max heap property
    -        // may be violated at node `max` since this node now has a new value. So we need to now
    -        // max heapify the subtree rooted at node `max`.
    -        max_heapify_recursive(v, len, max);
    -    }
    -}
    -
    - - - -
    - - - -## Function `priorities` - - - -
    public fun priorities<T: drop>(pq: &priority_queue::PriorityQueue<T>): vector<u64>
    -
    - - - -
    -Implementation - - -
    public fun priorities<T: drop>(pq: &PriorityQueue<T>): vector<u64> {
    -    let mut res = vector[];
    -    let mut i = 0;
    -    while (i < pq.entries.length()) {
    -        res.push_back(pq.entries[i].priority);
    -        i = i +1;
    -    };
    -    res
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/random.md b/crates/sui-framework/docs/sui-framework/random.md deleted file mode 100644 index cc43cef4904..00000000000 --- a/crates/sui-framework/docs/sui-framework/random.md +++ /dev/null @@ -1,927 +0,0 @@ ---- -title: Module `0x2::random` ---- - -This module provides functionality for generating secure randomness. - - -- [Resource `Random`](#0x2_random_Random) -- [Struct `RandomInner`](#0x2_random_RandomInner) -- [Struct `RandomGenerator`](#0x2_random_RandomGenerator) -- [Constants](#@Constants_0) -- [Function `create`](#0x2_random_create) -- [Function `load_inner_mut`](#0x2_random_load_inner_mut) -- [Function `load_inner`](#0x2_random_load_inner) -- [Function `update_randomness_state`](#0x2_random_update_randomness_state) -- [Function `new_generator`](#0x2_random_new_generator) -- [Function `derive_next_block`](#0x2_random_derive_next_block) -- [Function `fill_buffer`](#0x2_random_fill_buffer) -- [Function `generate_bytes`](#0x2_random_generate_bytes) -- [Function `u256_from_bytes`](#0x2_random_u256_from_bytes) -- [Function `generate_u256`](#0x2_random_generate_u256) -- [Function `generate_u128`](#0x2_random_generate_u128) -- [Function `generate_u64`](#0x2_random_generate_u64) -- [Function `generate_u32`](#0x2_random_generate_u32) -- [Function `generate_u16`](#0x2_random_generate_u16) -- [Function `generate_u8`](#0x2_random_generate_u8) -- [Function `generate_bool`](#0x2_random_generate_bool) -- [Function `u128_in_range`](#0x2_random_u128_in_range) -- [Function `generate_u128_in_range`](#0x2_random_generate_u128_in_range) -- [Function `generate_u64_in_range`](#0x2_random_generate_u64_in_range) -- [Function `generate_u32_in_range`](#0x2_random_generate_u32_in_range) -- [Function `generate_u16_in_range`](#0x2_random_generate_u16_in_range) -- [Function `generate_u8_in_range`](#0x2_random_generate_u8_in_range) -- [Function `shuffle`](#0x2_random_shuffle) - - -
    use 0x1::bcs;
    -use 0x1::vector;
    -use 0x2::address;
    -use 0x2::hmac;
    -use 0x2::object;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -use 0x2::versioned;
    -
    - - - - - -## Resource `Random` - -Singleton shared object which stores the global randomness state. -The actual state is stored in a versioned inner field. - - -
    struct Random has key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -inner: versioned::Versioned -
    -
    - -
    -
    - - -
    - - - -## Struct `RandomInner` - - - -
    struct RandomInner has store
    -
    - - - -
    -Fields - - -
    -
    -version: u64 -
    -
    - -
    -
    -epoch: u64 -
    -
    - -
    -
    -randomness_round: u64 -
    -
    - -
    -
    -random_bytes: vector<u8> -
    -
    - -
    -
    - - -
    - - - -## Struct `RandomGenerator` - -Unique randomness generator, derived from the global randomness. - - -
    struct RandomGenerator has drop
    -
    - - - -
    -Fields - - -
    -
    -seed: vector<u8> -
    -
    - -
    -
    -counter: u16 -
    -
    - -
    -
    -buffer: vector<u8> -
    -
    - -
    -
    - - -
    - - - -## Constants - - - - - - -
    const ENotSystemAddress: u64 = 0;
    -
    - - - - - - - -
    const EWrongInnerVersion: u64 = 1;
    -
    - - - - - - - -
    const CURRENT_VERSION: u64 = 1;
    -
    - - - - - - - -
    const EInvalidLength: u64 = 4;
    -
    - - - - - - - -
    const EInvalidRandomnessUpdate: u64 = 2;
    -
    - - - - - - - -
    const EInvalidRange: u64 = 3;
    -
    - - - - - - - -
    const RAND_OUTPUT_LEN: u16 = 32;
    -
    - - - - - - - -
    const U16_MAX: u64 = 65535;
    -
    - - - - - -## Function `create` - -Create and share the Random object. This function is called exactly once, when -the Random object is first created. -Can only be called by genesis or change_epoch transactions. - - -
    fun create(ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    fun create(ctx: &mut TxContext) {
    -    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    -
    -    let version = CURRENT_VERSION;
    -
    -    let inner = RandomInner {
    -        version,
    -        epoch: ctx.epoch(),
    -        randomness_round: 0,
    -        random_bytes: vector[],
    -    };
    -
    -    let self = Random {
    -        id: object::randomness_state(),
    -        inner: versioned::create(version, inner, ctx),
    -    };
    -    transfer::share_object(self);
    -}
    -
    - - - -
    - - - -## Function `load_inner_mut` - - - -
    fun load_inner_mut(self: &mut random::Random): &mut random::RandomInner
    -
    - - - -
    -Implementation - - -
    fun load_inner_mut(
    -    self: &mut Random,
    -): &mut RandomInner {
    -    let version = versioned::version(&self.inner);
    -
    -    // Replace this with a lazy update function when we add a new version of the inner object.
    -    assert!(version == CURRENT_VERSION, EWrongInnerVersion);
    -    let inner: &mut RandomInner = versioned::load_value_mut(&mut self.inner);
    -    assert!(inner.version == version, EWrongInnerVersion);
    -    inner
    -}
    -
    - - - -
    - - - -## Function `load_inner` - - - -
    fun load_inner(self: &random::Random): &random::RandomInner
    -
    - - - -
    -Implementation - - -
    fun load_inner(
    -    self: &Random,
    -): &RandomInner {
    -    let version = versioned::version(&self.inner);
    -
    -    // Replace this with a lazy update function when we add a new version of the inner object.
    -    assert!(version == CURRENT_VERSION, EWrongInnerVersion);
    -    let inner: &RandomInner = versioned::load_value(&self.inner);
    -    assert!(inner.version == version, EWrongInnerVersion);
    -    inner
    -}
    -
    - - - -
    - - - -## Function `update_randomness_state` - -Record new randomness. Called when executing the RandomnessStateUpdate system -transaction. - - -
    fun update_randomness_state(self: &mut random::Random, new_round: u64, new_bytes: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    fun update_randomness_state(
    -    self: &mut Random,
    -    new_round: u64,
    -    new_bytes: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    // Validator will make a special system call with sender set as 0x0.
    -    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    -
    -    // Randomness should only be incremented.
    -    let epoch = ctx.epoch();
    -    let inner = self.load_inner_mut();
    -    if (inner.randomness_round == 0 && inner.epoch == 0 && inner.random_bytes.is_empty()) {
    -        // First update should be for round zero.
    -        assert!(new_round == 0, EInvalidRandomnessUpdate);
    -    } else {
    -        // Subsequent updates should either increase epoch or increment randomness_round.
    -        // Note that epoch may increase by more than 1 if an epoch is completed without
    -        // randomness ever being generated in that epoch.
    -        assert!(
    -            (epoch > inner.epoch && new_round == 0) ||
    -                (new_round == inner.randomness_round + 1),
    -            EInvalidRandomnessUpdate
    -        );
    -    };
    -
    -    inner.epoch = ctx.epoch();
    -    inner.randomness_round = new_round;
    -    inner.random_bytes = new_bytes;
    -}
    -
    - - - -
    - - - -## Function `new_generator` - -Create a generator. Can be used to derive up to MAX_U16 * 32 random bytes. - - -
    public fun new_generator(r: &random::Random, ctx: &mut tx_context::TxContext): random::RandomGenerator
    -
    - - - -
    -Implementation - - -
    public fun new_generator(r: &Random, ctx: &mut TxContext): RandomGenerator {
    -    let inner = load_inner(r);
    -    let seed = hmac_sha3_256(
    -        &inner.random_bytes,
    -        &ctx.fresh_object_address().to_bytes()
    -    );
    -    RandomGenerator { seed, counter: 0, buffer: vector[] }
    -}
    -
    - - - -
    - - - -## Function `derive_next_block` - - - -
    fun derive_next_block(g: &mut random::RandomGenerator): vector<u8>
    -
    - - - -
    -Implementation - - -
    fun derive_next_block(g: &mut RandomGenerator): vector<u8> {
    -    g.counter = g.counter + 1;
    -    hmac_sha3_256(&g.seed, &bcs::to_bytes(&g.counter))
    -}
    -
    - - - -
    - - - -## Function `fill_buffer` - - - -
    fun fill_buffer(g: &mut random::RandomGenerator)
    -
    - - - -
    -Implementation - - -
    fun fill_buffer(g: &mut RandomGenerator) {
    -    let next_block = derive_next_block(g);
    -    vector::append(&mut g.buffer, next_block);
    -}
    -
    - - - -
    - - - -## Function `generate_bytes` - -Generate n random bytes. - - -
    public fun generate_bytes(g: &mut random::RandomGenerator, num_of_bytes: u16): vector<u8>
    -
    - - - -
    -Implementation - - -
    public fun generate_bytes(g: &mut RandomGenerator, num_of_bytes: u16): vector<u8> {
    -    let mut result = vector[];
    -    // Append RAND_OUTPUT_LEN size buffers directly without going through the generator's buffer.
    -    let mut num_of_blocks = num_of_bytes / RAND_OUTPUT_LEN;
    -    while (num_of_blocks > 0) {
    -        vector::append(&mut result, derive_next_block(g));
    -        num_of_blocks = num_of_blocks - 1;
    -    };
    -    // Fill the generator's buffer if needed.
    -    let num_of_bytes = num_of_bytes as u64;
    -    if (vector::length(&g.buffer) < (num_of_bytes - vector::length(&result))) {
    -        fill_buffer(g);
    -    };
    -    // Take remaining bytes from the generator's buffer.
    -    while (vector::length(&result) < num_of_bytes) {
    -        vector::push_back(&mut result, vector::pop_back(&mut g.buffer));
    -    };
    -    result
    -}
    -
    - - - -
    - - - -## Function `u256_from_bytes` - - - -
    fun u256_from_bytes(g: &mut random::RandomGenerator, num_of_bytes: u8): u256
    -
    - - - -
    -Implementation - - -
    fun u256_from_bytes(g: &mut RandomGenerator, num_of_bytes: u8): u256 {
    -    if (vector::length(&g.buffer) < num_of_bytes as u64) {
    -        fill_buffer(g);
    -    };
    -    let mut result: u256 = 0;
    -    let mut i = 0;
    -    while (i < num_of_bytes) {
    -        let byte = vector::pop_back(&mut g.buffer);
    -        result = (result << 8) + (byte as u256);
    -        i = i + 1;
    -    };
    -    result
    -}
    -
    - - - -
    - - - -## Function `generate_u256` - -Generate a u256. - - -
    public fun generate_u256(g: &mut random::RandomGenerator): u256
    -
    - - - -
    -Implementation - - -
    public fun generate_u256(g: &mut RandomGenerator): u256 {
    -    u256_from_bytes(g, 32)
    -}
    -
    - - - -
    - - - -## Function `generate_u128` - -Generate a u128. - - -
    public fun generate_u128(g: &mut random::RandomGenerator): u128
    -
    - - - -
    -Implementation - - -
    public fun generate_u128(g: &mut RandomGenerator): u128 {
    -    u256_from_bytes(g, 16) as u128
    -}
    -
    - - - -
    - - - -## Function `generate_u64` - -Generate a u64. - - -
    public fun generate_u64(g: &mut random::RandomGenerator): u64
    -
    - - - -
    -Implementation - - -
    public fun generate_u64(g: &mut RandomGenerator): u64 {
    -    u256_from_bytes(g, 8) as u64
    -}
    -
    - - - -
    - - - -## Function `generate_u32` - -Generate a u32. - - -
    public fun generate_u32(g: &mut random::RandomGenerator): u32
    -
    - - - -
    -Implementation - - -
    public fun generate_u32(g: &mut RandomGenerator): u32 {
    -    u256_from_bytes(g, 4) as u32
    -}
    -
    - - - -
    - - - -## Function `generate_u16` - -Generate a u16. - - -
    public fun generate_u16(g: &mut random::RandomGenerator): u16
    -
    - - - -
    -Implementation - - -
    public fun generate_u16(g: &mut RandomGenerator): u16 {
    -    u256_from_bytes(g, 2) as u16
    -}
    -
    - - - -
    - - - -## Function `generate_u8` - -Generate a u8. - - -
    public fun generate_u8(g: &mut random::RandomGenerator): u8
    -
    - - - -
    -Implementation - - -
    public fun generate_u8(g: &mut RandomGenerator): u8 {
    -    u256_from_bytes(g, 1) as u8
    -}
    -
    - - - -
    - - - -## Function `generate_bool` - -Generate a boolean. - - -
    public fun generate_bool(g: &mut random::RandomGenerator): bool
    -
    - - - -
    -Implementation - - -
    public fun generate_bool(g: &mut RandomGenerator): bool {
    -    (u256_from_bytes(g, 1) & 1) == 1
    -}
    -
    - - - -
    - - - -## Function `u128_in_range` - - - -
    fun u128_in_range(g: &mut random::RandomGenerator, min: u128, max: u128, num_of_bytes: u8): u128
    -
    - - - -
    -Implementation - - -
    fun u128_in_range(g: &mut RandomGenerator, min: u128, max: u128, num_of_bytes: u8): u128 {
    -    assert!(min <= max, EInvalidRange);
    -    if (min == max) {
    -        return min
    -    };
    -    // Pick a random number in [0, max - min] by generating a random number that is larger than max-min, and taking
    -    // the modulo of the random number by the range size. Then add the min to the result to get a number in
    -    // [min, max].
    -    let range_size = (max - min) as u256 + 1;
    -    let rand = u256_from_bytes(g, num_of_bytes);
    -    min + (rand % range_size as u128)
    -}
    -
    - - - -
    - - - -## Function `generate_u128_in_range` - -Generate a random u128 in [min, max] (with a bias of 2^{-64}). - - -
    public fun generate_u128_in_range(g: &mut random::RandomGenerator, min: u128, max: u128): u128
    -
    - - - -
    -Implementation - - -
    public fun generate_u128_in_range(g: &mut RandomGenerator, min: u128, max: u128): u128 {
    -    u128_in_range(g, min, max, 24)
    -}
    -
    - - - -
    - - - -## Function `generate_u64_in_range` - - - -
    public fun generate_u64_in_range(g: &mut random::RandomGenerator, min: u64, max: u64): u64
    -
    - - - -
    -Implementation - - -
    public fun generate_u64_in_range(g: &mut RandomGenerator, min: u64, max: u64): u64 {
    -    u128_in_range(g, min as u128, max as u128, 16) as u64
    -}
    -
    - - - -
    - - - -## Function `generate_u32_in_range` - -Generate a random u32 in [min, max] (with a bias of 2^{-64}). - - -
    public fun generate_u32_in_range(g: &mut random::RandomGenerator, min: u32, max: u32): u32
    -
    - - - -
    -Implementation - - -
    public fun generate_u32_in_range(g: &mut RandomGenerator, min: u32, max: u32): u32 {
    -    u128_in_range(g, min as u128, max as u128, 12) as u32
    -}
    -
    - - - -
    - - - -## Function `generate_u16_in_range` - -Generate a random u16 in [min, max] (with a bias of 2^{-64}). - - -
    public fun generate_u16_in_range(g: &mut random::RandomGenerator, min: u16, max: u16): u16
    -
    - - - -
    -Implementation - - -
    public fun generate_u16_in_range(g: &mut RandomGenerator, min: u16, max: u16): u16 {
    -    u128_in_range(g, min as u128, max as u128, 10) as u16
    -}
    -
    - - - -
    - - - -## Function `generate_u8_in_range` - -Generate a random u8 in [min, max] (with a bias of 2^{-64}). - - -
    public fun generate_u8_in_range(g: &mut random::RandomGenerator, min: u8, max: u8): u8
    -
    - - - -
    -Implementation - - -
    public fun generate_u8_in_range(g: &mut RandomGenerator, min: u8, max: u8): u8 {
    -    u128_in_range(g, min as u128, max as u128, 9) as u8
    -}
    -
    - - - -
    - - - -## Function `shuffle` - -Shuffle a vector using the random generator (Fisher–Yates/Knuth shuffle). - - -
    public fun shuffle<T>(g: &mut random::RandomGenerator, v: &mut vector<T>)
    -
    - - - -
    -Implementation - - -
    public fun shuffle<T>(g: &mut RandomGenerator, v: &mut vector<T>) {
    -    let n = vector::length(v);
    -    if (n == 0) {
    -        return
    -    };
    -    assert!(n <= U16_MAX, EInvalidLength);
    -    let n = n as u16;
    -    let mut i: u16 = 0;
    -    let end = n - 1;
    -    while (i < end) {
    -        let j = generate_u16_in_range(g, i, end);
    -        vector::swap(v, i as u64, j as u64);
    -        i = i + 1;
    -    };
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/sui.md b/crates/sui-framework/docs/sui-framework/sui.md deleted file mode 100644 index a9da6ac8df2..00000000000 --- a/crates/sui-framework/docs/sui-framework/sui.md +++ /dev/null @@ -1,173 +0,0 @@ ---- -title: Module `0x2::sui` ---- - -Coin is the token used to pay for gas in Sui. -It has 9 decimals, and the smallest unit (10^-9) is called "mist". - - -- [Struct `SUI`](#0x2_sui_SUI) -- [Constants](#@Constants_0) -- [Function `new`](#0x2_sui_new) -- [Function `transfer`](#0x2_sui_transfer) - - -
    use 0x1::option;
    -use 0x2::balance;
    -use 0x2::coin;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -use 0x2::url;
    -
    - - - - - -## Struct `SUI` - -Name of the coin - - -
    struct SUI has drop
    -
    - - - -
    -Fields - - -
    -
    -dummy_field: bool -
    -
    - -
    -
    - - -
    - - - -## Constants - - - - -Sender is not @0x0 the system address. - - -
    const ENotSystemAddress: u64 = 1;
    -
    - - - - - - - -
    const EAlreadyMinted: u64 = 0;
    -
    - - - - - -The amount of Mist per Sui token based on the fact that mist is -10^-9 of a Sui token - - -
    const MIST_PER_SUI: u64 = 1000000000;
    -
    - - - - - -The total supply of Sui denominated in Mist (10 Billion * 10^9) - - -
    const TOTAL_SUPPLY_MIST: u64 = 10000000000000000000;
    -
    - - - - - -The total supply of Sui denominated in whole Sui tokens (10 Billion) - - -
    const TOTAL_SUPPLY_SUI: u64 = 10000000000;
    -
    - - - - - -## Function `new` - -Register the SUI Coin to acquire its Supply. -This should be called only once during genesis creation. - - -
    fun new(ctx: &mut tx_context::TxContext): balance::Balance<sui::SUI>
    -
    - - - -
    -Implementation - - -
    fun new(ctx: &mut TxContext): Balance<SUI> {
    -    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    -    assert!(ctx.epoch() == 0, EAlreadyMinted);
    -
    -    let (treasury, metadata) = coin::create_currency(
    -        SUI {},
    -        9,
    -        b"SUI",
    -        b"Sui",
    -        // TODO: add appropriate description and logo url
    -        b"",
    -        option::none(),
    -        ctx
    -    );
    -    transfer::public_freeze_object(metadata);
    -    let mut supply = treasury.treasury_into_supply();
    -    let total_sui = supply.increase_supply(TOTAL_SUPPLY_MIST);
    -    supply.destroy_supply();
    -    total_sui
    -}
    -
    - - - -
    - - - -## Function `transfer` - - - -
    public entry fun transfer(c: coin::Coin<sui::SUI>, recipient: address)
    -
    - - - -
    -Implementation - - -
    public entry fun transfer(c: coin::Coin<SUI>, recipient: address) {
    -    transfer::public_transfer(c, recipient)
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/table.md b/crates/sui-framework/docs/sui-framework/table.md deleted file mode 100644 index 54cc80f1021..00000000000 --- a/crates/sui-framework/docs/sui-framework/table.md +++ /dev/null @@ -1,357 +0,0 @@ ---- -title: Module `0x2::table` ---- - -A table is a map-like collection. But unlike a traditional collection, it's keys and values are -not stored within the Table value, but instead are stored using Sui's object system. The -Table struct acts only as a handle into the object system to retrieve those keys and values. -Note that this means that Table values with exactly the same key-value mapping will not be -equal, with ==, at runtime. For example -``` -let table1 = table::new(); -let table2 = table::new(); -table::add(&mut table1, 0, false); -table::add(&mut table1, 1, true); -table::add(&mut table2, 0, false); -table::add(&mut table2, 1, true); -// table1 does not equal table2, despite having the same entries -assert!(&table1 != &table2, 0); -``` - - -- [Resource `Table`](#0x2_table_Table) -- [Constants](#@Constants_0) -- [Function `new`](#0x2_table_new) -- [Function `add`](#0x2_table_add) -- [Function `borrow`](#0x2_table_borrow) -- [Function `borrow_mut`](#0x2_table_borrow_mut) -- [Function `remove`](#0x2_table_remove) -- [Function `contains`](#0x2_table_contains) -- [Function `length`](#0x2_table_length) -- [Function `is_empty`](#0x2_table_is_empty) -- [Function `destroy_empty`](#0x2_table_destroy_empty) -- [Function `drop`](#0x2_table_drop) - - -
    use 0x2::dynamic_field;
    -use 0x2::object;
    -use 0x2::tx_context;
    -
    - - - - - -## Resource `Table` - - - -
    struct Table<K: copy, drop, store, V: store> has store, key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - the ID of this table -
    -
    -size: u64 -
    -
    - the number of key-value pairs in the table -
    -
    - - -
    - - - -## Constants - - - - - - -
    const ETableNotEmpty: u64 = 0;
    -
    - - - - - -## Function `new` - -Creates a new, empty table - - -
    public fun new<K: copy, drop, store, V: store>(ctx: &mut tx_context::TxContext): table::Table<K, V>
    -
    - - - -
    -Implementation - - -
    public fun new<K: copy + drop + store, V: store>(ctx: &mut TxContext): Table<K, V> {
    -    Table {
    -        id: object::new(ctx),
    -        size: 0,
    -    }
    -}
    -
    - - - -
    - - - -## Function `add` - -Adds a key-value pair to the table table: &mut Table<K, V> -Aborts with sui::dynamic_field::EFieldAlreadyExists if the table already has an entry with -that key k: K. - - -
    public fun add<K: copy, drop, store, V: store>(table: &mut table::Table<K, V>, k: K, v: V)
    -
    - - - -
    -Implementation - - -
    public fun add<K: copy + drop + store, V: store>(table: &mut Table<K, V>, k: K, v: V) {
    -    field::add(&mut table.id, k, v);
    -    table.size = table.size + 1;
    -}
    -
    - - - -
    - - - -## Function `borrow` - -Immutable borrows the value associated with the key in the table table: &Table<K, V>. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the table does not have an entry with -that key k: K. - - -
    public fun borrow<K: copy, drop, store, V: store>(table: &table::Table<K, V>, k: K): &V
    -
    - - - -
    -Implementation - - -
    public fun borrow<K: copy + drop + store, V: store>(table: &Table<K, V>, k: K): &V {
    -    field::borrow(&table.id, k)
    -}
    -
    - - - -
    - - - -## Function `borrow_mut` - -Mutably borrows the value associated with the key in the table table: &mut Table<K, V>. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the table does not have an entry with -that key k: K. - - -
    public fun borrow_mut<K: copy, drop, store, V: store>(table: &mut table::Table<K, V>, k: K): &mut V
    -
    - - - -
    -Implementation - - -
    public fun borrow_mut<K: copy + drop + store, V: store>(table: &mut Table<K, V>, k: K): &mut V {
    -    field::borrow_mut(&mut table.id, k)
    -}
    -
    - - - -
    - - - -## Function `remove` - -Removes the key-value pair in the table table: &mut Table<K, V> and returns the value. -Aborts with sui::dynamic_field::EFieldDoesNotExist if the table does not have an entry with -that key k: K. - - -
    public fun remove<K: copy, drop, store, V: store>(table: &mut table::Table<K, V>, k: K): V
    -
    - - - -
    -Implementation - - -
    public fun remove<K: copy + drop + store, V: store>(table: &mut Table<K, V>, k: K): V {
    -    let v = field::remove(&mut table.id, k);
    -    table.size = table.size - 1;
    -    v
    -}
    -
    - - - -
    - - - -## Function `contains` - -Returns true iff there is a value associated with the key k: K in table table: &Table<K, V> - - -
    public fun contains<K: copy, drop, store, V: store>(table: &table::Table<K, V>, k: K): bool
    -
    - - - -
    -Implementation - - -
    public fun contains<K: copy + drop + store, V: store>(table: &Table<K, V>, k: K): bool {
    -    field::exists_with_type<K, V>(&table.id, k)
    -}
    -
    - - - -
    - - - -## Function `length` - -Returns the size of the table, the number of key-value pairs - - -
    public fun length<K: copy, drop, store, V: store>(table: &table::Table<K, V>): u64
    -
    - - - -
    -Implementation - - -
    public fun length<K: copy + drop + store, V: store>(table: &Table<K, V>): u64 {
    -    table.size
    -}
    -
    - - - -
    - - - -## Function `is_empty` - -Returns true iff the table is empty (if length returns 0) - - -
    public fun is_empty<K: copy, drop, store, V: store>(table: &table::Table<K, V>): bool
    -
    - - - -
    -Implementation - - -
    public fun is_empty<K: copy + drop + store, V: store>(table: &Table<K, V>): bool {
    -    table.size == 0
    -}
    -
    - - - -
    - - - -## Function `destroy_empty` - -Destroys an empty table -Aborts with ETableNotEmpty if the table still contains values - - -
    public fun destroy_empty<K: copy, drop, store, V: store>(table: table::Table<K, V>)
    -
    - - - -
    -Implementation - - -
    public fun destroy_empty<K: copy + drop + store, V: store>(table: Table<K, V>) {
    -    let Table { id, size } = table;
    -    assert!(size == 0, ETableNotEmpty);
    -    id.delete()
    -}
    -
    - - - -
    - - - -## Function `drop` - -Drop a possibly non-empty table. -Usable only if the value type V has the drop ability - - -
    public fun drop<K: copy, drop, store, V: drop, store>(table: table::Table<K, V>)
    -
    - - - -
    -Implementation - - -
    public fun drop<K: copy + drop + store, V: drop + store>(table: Table<K, V>) {
    -    let Table { id, size: _ } = table;
    -    id.delete()
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/table_vec.md b/crates/sui-framework/docs/sui-framework/table_vec.md deleted file mode 100644 index ec9aeb03fd8..00000000000 --- a/crates/sui-framework/docs/sui-framework/table_vec.md +++ /dev/null @@ -1,407 +0,0 @@ ---- -title: Module `0x2::table_vec` ---- - -A basic scalable vector library implemented using Table. - - -- [Struct `TableVec`](#0x2_table_vec_TableVec) -- [Constants](#@Constants_0) -- [Function `empty`](#0x2_table_vec_empty) -- [Function `singleton`](#0x2_table_vec_singleton) -- [Function `length`](#0x2_table_vec_length) -- [Function `is_empty`](#0x2_table_vec_is_empty) -- [Function `borrow`](#0x2_table_vec_borrow) -- [Function `push_back`](#0x2_table_vec_push_back) -- [Function `borrow_mut`](#0x2_table_vec_borrow_mut) -- [Function `pop_back`](#0x2_table_vec_pop_back) -- [Function `destroy_empty`](#0x2_table_vec_destroy_empty) -- [Function `drop`](#0x2_table_vec_drop) -- [Function `swap`](#0x2_table_vec_swap) -- [Function `swap_remove`](#0x2_table_vec_swap_remove) - - -
    use 0x2::table;
    -use 0x2::tx_context;
    -
    - - - - - -## Struct `TableVec` - - - -
    struct TableVec<Element: store> has store
    -
    - - - -
    -Fields - - -
    -
    -contents: table::Table<u64, Element> -
    -
    - The contents of the table vector. -
    -
    - - -
    - - - -## Constants - - - - - - -
    const EIndexOutOfBound: u64 = 0;
    -
    - - - - - - - -
    const ETableNonEmpty: u64 = 1;
    -
    - - - - - -## Function `empty` - -Create an empty TableVec. - - -
    public fun empty<Element: store>(ctx: &mut tx_context::TxContext): table_vec::TableVec<Element>
    -
    - - - -
    -Implementation - - -
    public fun empty<Element: store>(ctx: &mut TxContext): TableVec<Element> {
    -    TableVec {
    -        contents: table::new(ctx)
    -    }
    -}
    -
    - - - -
    - - - -## Function `singleton` - -Return a TableVec of size one containing element e. - - -
    public fun singleton<Element: store>(e: Element, ctx: &mut tx_context::TxContext): table_vec::TableVec<Element>
    -
    - - - -
    -Implementation - - -
    public fun singleton<Element: store>(e: Element, ctx: &mut TxContext): TableVec<Element> {
    -    let mut t = empty(ctx);
    -    t.push_back(e);
    -    t
    -}
    -
    - - - -
    - - - -## Function `length` - -Return the length of the TableVec. - - -
    public fun length<Element: store>(t: &table_vec::TableVec<Element>): u64
    -
    - - - -
    -Implementation - - -
    public fun length<Element: store>(t: &TableVec<Element>): u64 {
    -    t.contents.length()
    -}
    -
    - - - -
    - - - -## Function `is_empty` - -Return if the TableVec is empty or not. - - -
    public fun is_empty<Element: store>(t: &table_vec::TableVec<Element>): bool
    -
    - - - -
    -Implementation - - -
    public fun is_empty<Element: store>(t: &TableVec<Element>): bool {
    -    t.length() == 0
    -}
    -
    - - - -
    - - - -## Function `borrow` - -Acquire an immutable reference to the ith element of the TableVec t. -Aborts if i is out of bounds. - - -
    public fun borrow<Element: store>(t: &table_vec::TableVec<Element>, i: u64): &Element
    -
    - - - -
    -Implementation - - -
    public fun borrow<Element: store>(t: &TableVec<Element>, i: u64): &Element {
    -    assert!(t.length() > i, EIndexOutOfBound);
    -    &t.contents[i]
    -}
    -
    - - - -
    - - - -## Function `push_back` - -Add element e to the end of the TableVec t. - - -
    public fun push_back<Element: store>(t: &mut table_vec::TableVec<Element>, e: Element)
    -
    - - - -
    -Implementation - - -
    public fun push_back<Element: store>(t: &mut TableVec<Element>, e: Element) {
    -    let key = t.length();
    -    t.contents.add(key, e);
    -}
    -
    - - - -
    - - - -## Function `borrow_mut` - -Return a mutable reference to the ith element in the TableVec t. -Aborts if i is out of bounds. - - -
    public fun borrow_mut<Element: store>(t: &mut table_vec::TableVec<Element>, i: u64): &mut Element
    -
    - - - -
    -Implementation - - -
    public fun borrow_mut<Element: store>(t: &mut TableVec<Element>, i: u64): &mut Element {
    -    assert!(t.length() > i, EIndexOutOfBound);
    -    &mut t.contents[i]
    -}
    -
    - - - -
    - - - -## Function `pop_back` - -Pop an element from the end of TableVec t. -Aborts if t is empty. - - -
    public fun pop_back<Element: store>(t: &mut table_vec::TableVec<Element>): Element
    -
    - - - -
    -Implementation - - -
    public fun pop_back<Element: store>(t: &mut TableVec<Element>): Element {
    -    let length = length(t);
    -    assert!(length > 0, EIndexOutOfBound);
    -    t.contents.remove(length - 1)
    -}
    -
    - - - -
    - - - -## Function `destroy_empty` - -Destroy the TableVec t. -Aborts if t is not empty. - - -
    public fun destroy_empty<Element: store>(t: table_vec::TableVec<Element>)
    -
    - - - -
    -Implementation - - -
    public fun destroy_empty<Element: store>(t: TableVec<Element>) {
    -    assert!(length(&t) == 0, ETableNonEmpty);
    -    let TableVec { contents } = t;
    -    contents.destroy_empty();
    -}
    -
    - - - -
    - - - -## Function `drop` - -Drop a possibly non-empty TableVec t. -Usable only if the value type Element has the drop ability - - -
    public fun drop<Element: drop, store>(t: table_vec::TableVec<Element>)
    -
    - - - -
    -Implementation - - -
    public fun drop<Element: drop + store>(t: TableVec<Element>) {
    -    let TableVec { contents } = t;
    -    contents.drop()
    -}
    -
    - - - -
    - - - -## Function `swap` - -Swaps the elements at the ith and jth indices in the TableVec t. -Aborts if i or j is out of bounds. - - -
    public fun swap<Element: store>(t: &mut table_vec::TableVec<Element>, i: u64, j: u64)
    -
    - - - -
    -Implementation - - -
    public fun swap<Element: store>(t: &mut TableVec<Element>, i: u64, j: u64) {
    -    assert!(t.length() > i, EIndexOutOfBound);
    -    assert!(t.length() > j, EIndexOutOfBound);
    -    if (i == j) { return };
    -    let element_i = t.contents.remove(i);
    -    let element_j = t.contents.remove(j);
    -    t.contents.add(j, element_i);
    -    t.contents.add(i, element_j);
    -}
    -
    - - - -
    - - - -## Function `swap_remove` - -Swap the ith element of the TableVec t with the last element and then pop the TableVec. -This is O(1), but does not preserve ordering of elements in the TableVec. -Aborts if i is out of bounds. - - -
    public fun swap_remove<Element: store>(t: &mut table_vec::TableVec<Element>, i: u64): Element
    -
    - - - -
    -Implementation - - -
    public fun swap_remove<Element: store>(t: &mut TableVec<Element>, i: u64): Element {
    -    assert!(t.length() > i, EIndexOutOfBound);
    -    let last_idx = t.length() - 1;
    -    t.swap(i, last_idx);
    -    t.pop_back()
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/transfer.md b/crates/sui-framework/docs/sui-framework/transfer.md deleted file mode 100644 index e9d0f36b35c..00000000000 --- a/crates/sui-framework/docs/sui-framework/transfer.md +++ /dev/null @@ -1,479 +0,0 @@ ---- -title: Module `0x2::transfer` ---- - - - -- [Struct `Receiving`](#0x2_transfer_Receiving) -- [Constants](#@Constants_0) -- [Function `transfer`](#0x2_transfer_transfer) -- [Function `public_transfer`](#0x2_transfer_public_transfer) -- [Function `freeze_object`](#0x2_transfer_freeze_object) -- [Function `public_freeze_object`](#0x2_transfer_public_freeze_object) -- [Function `share_object`](#0x2_transfer_share_object) -- [Function `public_share_object`](#0x2_transfer_public_share_object) -- [Function `receive`](#0x2_transfer_receive) -- [Function `public_receive`](#0x2_transfer_public_receive) -- [Function `receiving_object_id`](#0x2_transfer_receiving_object_id) -- [Function `freeze_object_impl`](#0x2_transfer_freeze_object_impl) -- [Function `share_object_impl`](#0x2_transfer_share_object_impl) -- [Function `transfer_impl`](#0x2_transfer_transfer_impl) -- [Function `receive_impl`](#0x2_transfer_receive_impl) - - -
    use 0x2::object;
    -
    - - - - - -## Struct `Receiving` - -This represents the ability to receive an object of type T. -This type is ephemeral per-transaction and cannot be stored on-chain. -This does not represent the obligation to receive the object that it -references, but simply the ability to receive the object with object ID -id at version version if you can prove mutable access to the parent -object during the transaction. -Internals of this struct are opaque outside this module. - - -
    struct Receiving<T: key> has drop
    -
    - - - -
    -Fields - - -
    -
    -id: object::ID -
    -
    - -
    -
    -version: u64 -
    -
    - -
    -
    - - -
    - - - -## Constants - - - - -Serialization of the object failed. - - -
    const EBCSSerializationFailure: u64 = 1;
    -
    - - - - - -The object being received is not of the expected type. - - -
    const EReceivingObjectTypeMismatch: u64 = 2;
    -
    - - - - - -Shared an object that was previously created. Shared objects must currently -be constructed in the transaction they are created. - - -
    const ESharedNonNewObject: u64 = 0;
    -
    - - - - - -Shared object operations such as wrapping, freezing, and converting to owned are not allowed. - - -
    const ESharedObjectOperationNotSupported: u64 = 4;
    -
    - - - - - -Represents both the case where the object does not exist and the case where the object is not -able to be accessed through the parent that is passed-in. - - -
    const EUnableToReceiveObject: u64 = 3;
    -
    - - - - - -## Function `transfer` - -Transfer ownership of obj to recipient. obj must have the key attribute, -which (in turn) ensures that obj has a globally unique ID. Note that if the recipient -address represents an object ID, the obj sent will be inaccessible after the transfer -(though they will be retrievable at a future date once new features are added). -This function has custom rules performed by the Sui Move bytecode verifier that ensures -that T is an object defined in the module where transfer is invoked. Use -public_transfer to transfer an object with store outside of its module. - - -
    public fun transfer<T: key>(obj: T, recipient: address)
    -
    - - - -
    -Implementation - - -
    public fun transfer<T: key>(obj: T, recipient: address) {
    -    transfer_impl(obj, recipient)
    -}
    -
    - - - -
    - - - -## Function `public_transfer` - -Transfer ownership of obj to recipient. obj must have the key attribute, -which (in turn) ensures that obj has a globally unique ID. Note that if the recipient -address represents an object ID, the obj sent will be inaccessible after the transfer -(though they will be retrievable at a future date once new features are added). -The object must have store to be transferred outside of its module. - - -
    public fun public_transfer<T: store, key>(obj: T, recipient: address)
    -
    - - - -
    -Implementation - - -
    public fun public_transfer<T: key + store>(obj: T, recipient: address) {
    -    transfer_impl(obj, recipient)
    -}
    -
    - - - -
    - - - -## Function `freeze_object` - -Freeze obj. After freezing obj becomes immutable and can no longer be transferred or -mutated. -This function has custom rules performed by the Sui Move bytecode verifier that ensures -that T is an object defined in the module where freeze_object is invoked. Use -public_freeze_object to freeze an object with store outside of its module. - - -
    public fun freeze_object<T: key>(obj: T)
    -
    - - - -
    -Implementation - - -
    public fun freeze_object<T: key>(obj: T) {
    -    freeze_object_impl(obj)
    -}
    -
    - - - -
    - - - -## Function `public_freeze_object` - -Freeze obj. After freezing obj becomes immutable and can no longer be transferred or -mutated. -The object must have store to be frozen outside of its module. - - -
    public fun public_freeze_object<T: store, key>(obj: T)
    -
    - - - -
    -Implementation - - -
    public fun public_freeze_object<T: key + store>(obj: T) {
    -    freeze_object_impl(obj)
    -}
    -
    - - - -
    - - - -## Function `share_object` - -Turn the given object into a mutable shared object that everyone can access and mutate. -This is irreversible, i.e. once an object is shared, it will stay shared forever. -Aborts with ESharedNonNewObject of the object being shared was not created in this -transaction. This restriction may be relaxed in the future. -This function has custom rules performed by the Sui Move bytecode verifier that ensures -that T is an object defined in the module where share_object is invoked. Use -public_share_object to share an object with store outside of its module. - - -
    public fun share_object<T: key>(obj: T)
    -
    - - - -
    -Implementation - - -
    public fun share_object<T: key>(obj: T) {
    -    share_object_impl(obj)
    -}
    -
    - - - -
    - - - -## Function `public_share_object` - -Turn the given object into a mutable shared object that everyone can access and mutate. -This is irreversible, i.e. once an object is shared, it will stay shared forever. -Aborts with ESharedNonNewObject of the object being shared was not created in this -transaction. This restriction may be relaxed in the future. -The object must have store to be shared outside of its module. - - -
    public fun public_share_object<T: store, key>(obj: T)
    -
    - - - -
    -Implementation - - -
    public fun public_share_object<T: key + store>(obj: T) {
    -    share_object_impl(obj)
    -}
    -
    - - - -
    - - - -## Function `receive` - -Given mutable (i.e., locked) access to the parent and a Receiving argument -referencing an object of type T owned by parent use the to_receive -argument to receive and return the referenced owned object of type T. -This function has custom rules performed by the Sui Move bytecode verifier that ensures -that T is an object defined in the module where receive is invoked. Use -public_receive to receivne an object with store outside of its module. - - -
    public fun receive<T: key>(parent: &mut object::UID, to_receive: transfer::Receiving<T>): T
    -
    - - - -
    -Implementation - - -
    public fun receive<T: key>(parent: &mut UID, to_receive: Receiving<T>): T {
    -    let Receiving {
    -        id,
    -        version,
    -    } = to_receive;
    -    receive_impl(parent.to_address(), id, version)
    -}
    -
    - - - -
    - - - -## Function `public_receive` - -Given mutable (i.e., locked) access to the parent and a Receiving argument -referencing an object of type T owned by parent use the to_receive -argument to receive and return the referenced owned object of type T. -The object must have store to be received outside of its defining module. - - -
    public fun public_receive<T: store, key>(parent: &mut object::UID, to_receive: transfer::Receiving<T>): T
    -
    - - - -
    -Implementation - - -
    public fun public_receive<T: key + store>(parent: &mut UID, to_receive: Receiving<T>): T {
    -    let Receiving {
    -        id,
    -        version,
    -    } = to_receive;
    -    receive_impl(parent.to_address(), id, version)
    -}
    -
    - - - -
    - - - -## Function `receiving_object_id` - -Return the object ID that the given Receiving argument references. - - -
    public fun receiving_object_id<T: key>(receiving: &transfer::Receiving<T>): object::ID
    -
    - - - -
    -Implementation - - -
    public fun receiving_object_id<T: key>(receiving: &Receiving<T>): ID {
    -    receiving.id
    -}
    -
    - - - -
    - - - -## Function `freeze_object_impl` - - - -
    public(friend) fun freeze_object_impl<T: key>(obj: T)
    -
    - - - -
    -Implementation - - -
    public(package) native fun freeze_object_impl<T: key>(obj: T);
    -
    - - - -
    - - - -## Function `share_object_impl` - - - -
    public(friend) fun share_object_impl<T: key>(obj: T)
    -
    - - - -
    -Implementation - - -
    public(package) native fun share_object_impl<T: key>(obj: T);
    -
    - - - -
    - - - -## Function `transfer_impl` - - - -
    public(friend) fun transfer_impl<T: key>(obj: T, recipient: address)
    -
    - - - -
    -Implementation - - -
    public(package) native fun transfer_impl<T: key>(obj: T, recipient: address);
    -
    - - - -
    - - - -## Function `receive_impl` - - - -
    fun receive_impl<T: key>(parent: address, to_receive: object::ID, version: u64): T
    -
    - - - -
    -Implementation - - -
    native fun receive_impl<T: key>(parent: address, to_receive: ID, version: u64): T;
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/tx_context.md b/crates/sui-framework/docs/sui-framework/tx_context.md deleted file mode 100644 index 45715763894..00000000000 --- a/crates/sui-framework/docs/sui-framework/tx_context.md +++ /dev/null @@ -1,255 +0,0 @@ ---- -title: Module `0x2::tx_context` ---- - - - -- [Struct `TxContext`](#0x2_tx_context_TxContext) -- [Function `sender`](#0x2_tx_context_sender) -- [Function `digest`](#0x2_tx_context_digest) -- [Function `epoch`](#0x2_tx_context_epoch) -- [Function `epoch_timestamp_ms`](#0x2_tx_context_epoch_timestamp_ms) -- [Function `fresh_object_address`](#0x2_tx_context_fresh_object_address) -- [Function `ids_created`](#0x2_tx_context_ids_created) -- [Function `derive_id`](#0x2_tx_context_derive_id) - - -
    - - - - - -## Struct `TxContext` - -Information about the transaction currently being executed. -This cannot be constructed by a transaction--it is a privileged object created by -the VM and passed in to the entrypoint of the transaction as &mut TxContext. - - -
    struct TxContext has drop
    -
    - - - -
    -Fields - - -
    -
    -sender: address -
    -
    - The address of the user that signed the current transaction -
    -
    -tx_hash: vector<u8> -
    -
    - Hash of the current transaction -
    -
    -epoch: u64 -
    -
    - The current epoch number -
    -
    -epoch_timestamp_ms: u64 -
    -
    - Timestamp that the epoch started at -
    -
    -ids_created: u64 -
    -
    - Counter recording the number of fresh id's created while executing - this transaction. Always 0 at the start of a transaction -
    -
    - - -
    - - - -## Function `sender` - -Return the address of the user that signed the current -transaction - - -
    public fun sender(self: &tx_context::TxContext): address
    -
    - - - -
    -Implementation - - -
    public fun sender(self: &TxContext): address {
    -    self.sender
    -}
    -
    - - - -
    - - - -## Function `digest` - -Return the transaction digest (hash of transaction inputs). -Please do not use as a source of randomness. - - -
    public fun digest(self: &tx_context::TxContext): &vector<u8>
    -
    - - - -
    -Implementation - - -
    public fun digest(self: &TxContext): &vector<u8> {
    -    &self.tx_hash
    -}
    -
    - - - -
    - - - -## Function `epoch` - -Return the current epoch - - -
    public fun epoch(self: &tx_context::TxContext): u64
    -
    - - - -
    -Implementation - - -
    public fun epoch(self: &TxContext): u64 {
    -    self.epoch
    -}
    -
    - - - -
    - - - -## Function `epoch_timestamp_ms` - -Return the epoch start time as a unix timestamp in milliseconds. - - -
    public fun epoch_timestamp_ms(self: &tx_context::TxContext): u64
    -
    - - - -
    -Implementation - - -
    public fun epoch_timestamp_ms(self: &TxContext): u64 {
    -   self.epoch_timestamp_ms
    -}
    -
    - - - -
    - - - -## Function `fresh_object_address` - -Create an address that has not been used. As it is an object address, it will never -occur as the address for a user. -In other words, the generated address is a globally unique object ID. - - -
    public fun fresh_object_address(ctx: &mut tx_context::TxContext): address
    -
    - - - -
    -Implementation - - -
    public fun fresh_object_address(ctx: &mut TxContext): address {
    -    let ids_created = ctx.ids_created;
    -    let id = derive_id(*&ctx.tx_hash, ids_created);
    -    ctx.ids_created = ids_created + 1;
    -    id
    -}
    -
    - - - -
    - - - -## Function `ids_created` - -Return the number of id's created by the current transaction. -Hidden for now, but may expose later - - -
    fun ids_created(self: &tx_context::TxContext): u64
    -
    - - - -
    -Implementation - - -
    fun ids_created(self: &TxContext): u64 {
    -    self.ids_created
    -}
    -
    - - - -
    - - - -## Function `derive_id` - -Native function for deriving an ID via hash(tx_hash || ids_created) - - -
    fun derive_id(tx_hash: vector<u8>, ids_created: u64): address
    -
    - - - -
    -Implementation - - -
    native fun derive_id(tx_hash: vector<u8>, ids_created: u64): address;
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/types.md b/crates/sui-framework/docs/sui-framework/types.md deleted file mode 100644 index a9087b587ba..00000000000 --- a/crates/sui-framework/docs/sui-framework/types.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Module `0x2::types` ---- - -Sui types helpers and utilities - - -- [Function `is_one_time_witness`](#0x2_types_is_one_time_witness) - - -
    - - - - - -## Function `is_one_time_witness` - -Tests if the argument type is a one-time witness, that is a type with only one instantiation -across the entire code base. - - -
    public fun is_one_time_witness<T: drop>(_: &T): bool
    -
    - - - -
    -Implementation - - -
    public native fun is_one_time_witness<T: drop>(_: &T): bool;
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/url.md b/crates/sui-framework/docs/sui-framework/url.md deleted file mode 100644 index e0e22042192..00000000000 --- a/crates/sui-framework/docs/sui-framework/url.md +++ /dev/null @@ -1,148 +0,0 @@ ---- -title: Module `0x2::url` ---- - -URL: standard Uniform Resource Locator string - - -- [Struct `Url`](#0x2_url_Url) -- [Function `new_unsafe`](#0x2_url_new_unsafe) -- [Function `new_unsafe_from_bytes`](#0x2_url_new_unsafe_from_bytes) -- [Function `inner_url`](#0x2_url_inner_url) -- [Function `update`](#0x2_url_update) - - -
    use 0x1::ascii;
    -
    - - - - - -## Struct `Url` - -Standard Uniform Resource Locator (URL) string. - - -
    struct Url has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -url: ascii::String -
    -
    - -
    -
    - - -
    - - - -## Function `new_unsafe` - -Create a Url, with no validation - - -
    public fun new_unsafe(url: ascii::String): url::Url
    -
    - - - -
    -Implementation - - -
    public fun new_unsafe(url: String): Url {
    -    Url { url }
    -}
    -
    - - - -
    - - - -## Function `new_unsafe_from_bytes` - -Create a Url with no validation from bytes -Note: this will abort if bytes is not valid ASCII - - -
    public fun new_unsafe_from_bytes(bytes: vector<u8>): url::Url
    -
    - - - -
    -Implementation - - -
    public fun new_unsafe_from_bytes(bytes: vector<u8>): Url {
    -    let url = bytes.to_ascii_string();
    -    Url { url }
    -}
    -
    - - - -
    - - - -## Function `inner_url` - -Get inner URL - - -
    public fun inner_url(self: &url::Url): ascii::String
    -
    - - - -
    -Implementation - - -
    public fun inner_url(self: &Url): String{
    -    self.url
    -}
    -
    - - - -
    - - - -## Function `update` - -Update the inner URL - - -
    public fun update(self: &mut url::Url, url: ascii::String)
    -
    - - - -
    -Implementation - - -
    public fun update(self: &mut Url, url: String) {
    -    self.url = url;
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/vec_map.md b/crates/sui-framework/docs/sui-framework/vec_map.md deleted file mode 100644 index caae189e8ad..00000000000 --- a/crates/sui-framework/docs/sui-framework/vec_map.md +++ /dev/null @@ -1,673 +0,0 @@ ---- -title: Module `0x2::vec_map` ---- - - - -- [Struct `VecMap`](#0x2_vec_map_VecMap) -- [Struct `Entry`](#0x2_vec_map_Entry) -- [Constants](#@Constants_0) -- [Function `empty`](#0x2_vec_map_empty) -- [Function `insert`](#0x2_vec_map_insert) -- [Function `remove`](#0x2_vec_map_remove) -- [Function `pop`](#0x2_vec_map_pop) -- [Function `get_mut`](#0x2_vec_map_get_mut) -- [Function `get`](#0x2_vec_map_get) -- [Function `try_get`](#0x2_vec_map_try_get) -- [Function `contains`](#0x2_vec_map_contains) -- [Function `size`](#0x2_vec_map_size) -- [Function `is_empty`](#0x2_vec_map_is_empty) -- [Function `destroy_empty`](#0x2_vec_map_destroy_empty) -- [Function `into_keys_values`](#0x2_vec_map_into_keys_values) -- [Function `keys`](#0x2_vec_map_keys) -- [Function `get_idx_opt`](#0x2_vec_map_get_idx_opt) -- [Function `get_idx`](#0x2_vec_map_get_idx) -- [Function `get_entry_by_idx`](#0x2_vec_map_get_entry_by_idx) -- [Function `get_entry_by_idx_mut`](#0x2_vec_map_get_entry_by_idx_mut) -- [Function `remove_entry_by_idx`](#0x2_vec_map_remove_entry_by_idx) - - -
    use 0x1::option;
    -use 0x1::vector;
    -
    - - - - - -## Struct `VecMap` - -A map data structure backed by a vector. The map is guaranteed not to contain duplicate keys, but entries -are *not* sorted by key--entries are included in insertion order. -All operations are O(N) in the size of the map--the intention of this data structure is only to provide -the convenience of programming against a map API. -Large maps should use handwritten parent/child relationships instead. -Maps that need sorted iteration rather than insertion order iteration should also be handwritten. - - -
    struct VecMap<K: copy, V> has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -contents: vector<vec_map::Entry<K, V>> -
    -
    - -
    -
    - - -
    - - - -## Struct `Entry` - -An entry in the map - - -
    struct Entry<K: copy, V> has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -key: K -
    -
    - -
    -
    -value: V -
    -
    - -
    -
    - - -
    - - - -## Constants - - - - -This key already exists in the map - - -
    const EKeyAlreadyExists: u64 = 0;
    -
    - - - - - -This key does not exist in the map - - -
    const EKeyDoesNotExist: u64 = 1;
    -
    - - - - - -Trying to access an element of the map at an invalid index - - -
    const EIndexOutOfBounds: u64 = 3;
    -
    - - - - - -Trying to pop from a map that is empty - - -
    const EMapEmpty: u64 = 4;
    -
    - - - - - -Trying to destroy a map that is not empty - - -
    const EMapNotEmpty: u64 = 2;
    -
    - - - - - -## Function `empty` - -Create an empty VecMap - - -
    public fun empty<K: copy, V>(): vec_map::VecMap<K, V>
    -
    - - - -
    -Implementation - - -
    public fun empty<K: copy, V>(): VecMap<K,V> {
    -    VecMap { contents: vector[] }
    -}
    -
    - - - -
    - - - -## Function `insert` - -Insert the entry key |-> value into self. -Aborts if key is already bound in self. - - -
    public fun insert<K: copy, V>(self: &mut vec_map::VecMap<K, V>, key: K, value: V)
    -
    - - - -
    -Implementation - - -
    public fun insert<K: copy, V>(self: &mut VecMap<K,V>, key: K, value: V) {
    -    assert!(!self.contains(&key), EKeyAlreadyExists);
    -    self.contents.push_back(Entry { key, value })
    -}
    -
    - - - -
    - - - -## Function `remove` - -Remove the entry key |-> value from self. Aborts if key is not bound in self. - - -
    public fun remove<K: copy, V>(self: &mut vec_map::VecMap<K, V>, key: &K): (K, V)
    -
    - - - -
    -Implementation - - -
    public fun remove<K: copy, V>(self: &mut VecMap<K,V>, key: &K): (K, V) {
    -    let idx = self.get_idx(key);
    -    let Entry { key, value } = self.contents.remove(idx);
    -    (key, value)
    -}
    -
    - - - -
    - - - -## Function `pop` - -Pop the most recently inserted entry from the map. Aborts if the map is empty. - - -
    public fun pop<K: copy, V>(self: &mut vec_map::VecMap<K, V>): (K, V)
    -
    - - - -
    -Implementation - - -
    public fun pop<K: copy, V>(self: &mut VecMap<K,V>): (K, V) {
    -    assert!(!self.contents.is_empty(), EMapEmpty);
    -    let Entry { key, value } = self.contents.pop_back();
    -    (key, value)
    -}
    -
    - - - -
    - - - -## Function `get_mut` - -Get a mutable reference to the value bound to key in self. -Aborts if key is not bound in self. - - -
    public fun get_mut<K: copy, V>(self: &mut vec_map::VecMap<K, V>, key: &K): &mut V
    -
    - - - -
    -Implementation - - -
    public fun get_mut<K: copy, V>(self: &mut VecMap<K,V>, key: &K): &mut V {
    -    let idx = self.get_idx(key);
    -    let entry = &mut self.contents[idx];
    -    &mut entry.value
    -}
    -
    - - - -
    - - - -## Function `get` - -Get a reference to the value bound to key in self. -Aborts if key is not bound in self. - - -
    public fun get<K: copy, V>(self: &vec_map::VecMap<K, V>, key: &K): &V
    -
    - - - -
    -Implementation - - -
    public fun get<K: copy, V>(self: &VecMap<K,V>, key: &K): &V {
    -    let idx = self.get_idx(key);
    -    let entry = &self.contents[idx];
    -    &entry.value
    -}
    -
    - - - -
    - - - -## Function `try_get` - -Safely try borrow a value bound to key in self. -Return Some(V) if the value exists, None otherwise. -Only works for a "copyable" value as references cannot be stored in vector. - - -
    public fun try_get<K: copy, V: copy>(self: &vec_map::VecMap<K, V>, key: &K): option::Option<V>
    -
    - - - -
    -Implementation - - -
    public fun try_get<K: copy, V: copy>(self: &VecMap<K,V>, key: &K): Option<V> {
    -    if (self.contains(key)) {
    -        option::some(*get(self, key))
    -    } else {
    -        option::none()
    -    }
    -}
    -
    - - - -
    - - - -## Function `contains` - -Return true if self contains an entry for key, false otherwise - - -
    public fun contains<K: copy, V>(self: &vec_map::VecMap<K, V>, key: &K): bool
    -
    - - - -
    -Implementation - - -
    public fun contains<K: copy, V>(self: &VecMap<K, V>, key: &K): bool {
    -    get_idx_opt(self, key).is_some()
    -}
    -
    - - - -
    - - - -## Function `size` - -Return the number of entries in self - - -
    public fun size<K: copy, V>(self: &vec_map::VecMap<K, V>): u64
    -
    - - - -
    -Implementation - - -
    public fun size<K: copy, V>(self: &VecMap<K,V>): u64 {
    -    self.contents.length()
    -}
    -
    - - - -
    - - - -## Function `is_empty` - -Return true if self has 0 elements, false otherwise - - -
    public fun is_empty<K: copy, V>(self: &vec_map::VecMap<K, V>): bool
    -
    - - - -
    -Implementation - - -
    public fun is_empty<K: copy, V>(self: &VecMap<K,V>): bool {
    -    self.size() == 0
    -}
    -
    - - - -
    - - - -## Function `destroy_empty` - -Destroy an empty map. Aborts if self is not empty - - -
    public fun destroy_empty<K: copy, V>(self: vec_map::VecMap<K, V>)
    -
    - - - -
    -Implementation - - -
    public fun destroy_empty<K: copy, V>(self: VecMap<K, V>) {
    -    let VecMap { contents } = self;
    -    assert!(contents.is_empty(), EMapNotEmpty);
    -    contents.destroy_empty()
    -}
    -
    - - - -
    - - - -## Function `into_keys_values` - -Unpack self into vectors of its keys and values. -The output keys and values are stored in insertion order, *not* sorted by key. - - -
    public fun into_keys_values<K: copy, V>(self: vec_map::VecMap<K, V>): (vector<K>, vector<V>)
    -
    - - - -
    -Implementation - - -
    public fun into_keys_values<K: copy, V>(self: VecMap<K, V>): (vector<K>, vector<V>) {
    -    let VecMap { mut contents } = self;
    -    // reverse the vector so the output keys and values will appear in insertion order
    -    contents.reverse();
    -    let mut i = 0;
    -    let n = contents.length();
    -    let mut keys = vector[];
    -    let mut values = vector[];
    -    while (i < n) {
    -        let Entry { key, value } = contents.pop_back();
    -        keys.push_back(key);
    -        values.push_back(value);
    -        i = i + 1;
    -    };
    -    contents.destroy_empty();
    -    (keys, values)
    -}
    -
    - - - -
    - - - -## Function `keys` - -Returns a list of keys in the map. -Do not assume any particular ordering. - - -
    public fun keys<K: copy, V>(self: &vec_map::VecMap<K, V>): vector<K>
    -
    - - - -
    -Implementation - - -
    public fun keys<K: copy, V>(self: &VecMap<K, V>): vector<K> {
    -    let mut i = 0;
    -    let n = self.contents.length();
    -    let mut keys = vector[];
    -    while (i < n) {
    -        let entry = self.contents.borrow(i);
    -        keys.push_back(entry.key);
    -        i = i + 1;
    -    };
    -    keys
    -}
    -
    - - - -
    - - - -## Function `get_idx_opt` - -Find the index of key in self. Return None if key is not in self. -Note that map entries are stored in insertion order, *not* sorted by key. - - -
    public fun get_idx_opt<K: copy, V>(self: &vec_map::VecMap<K, V>, key: &K): option::Option<u64>
    -
    - - - -
    -Implementation - - -
    public fun get_idx_opt<K: copy, V>(self: &VecMap<K,V>, key: &K): Option<u64> {
    -    let mut i = 0;
    -    let n = size(self);
    -    while (i < n) {
    -        if (&self.contents[i].key == key) {
    -            return option::some(i)
    -        };
    -        i = i + 1;
    -    };
    -    option::none()
    -}
    -
    - - - -
    - - - -## Function `get_idx` - -Find the index of key in self. Aborts if key is not in self. -Note that map entries are stored in insertion order, *not* sorted by key. - - -
    public fun get_idx<K: copy, V>(self: &vec_map::VecMap<K, V>, key: &K): u64
    -
    - - - -
    -Implementation - - -
    public fun get_idx<K: copy, V>(self: &VecMap<K,V>, key: &K): u64 {
    -    let idx_opt = self.get_idx_opt(key);
    -    assert!(idx_opt.is_some(), EKeyDoesNotExist);
    -    idx_opt.destroy_some()
    -}
    -
    - - - -
    - - - -## Function `get_entry_by_idx` - -Return a reference to the idxth entry of self. This gives direct access into the backing array of the map--use with caution. -Note that map entries are stored in insertion order, *not* sorted by key. -Aborts if idx is greater than or equal to size(self) - - -
    public fun get_entry_by_idx<K: copy, V>(self: &vec_map::VecMap<K, V>, idx: u64): (&K, &V)
    -
    - - - -
    -Implementation - - -
    public fun get_entry_by_idx<K: copy, V>(self: &VecMap<K, V>, idx: u64): (&K, &V) {
    -    assert!(idx < size(self), EIndexOutOfBounds);
    -    let entry = &self.contents[idx];
    -    (&entry.key, &entry.value)
    -}
    -
    - - - -
    - - - -## Function `get_entry_by_idx_mut` - -Return a mutable reference to the idxth entry of self. This gives direct access into the backing array of the map--use with caution. -Note that map entries are stored in insertion order, *not* sorted by key. -Aborts if idx is greater than or equal to size(self) - - -
    public fun get_entry_by_idx_mut<K: copy, V>(self: &mut vec_map::VecMap<K, V>, idx: u64): (&K, &mut V)
    -
    - - - -
    -Implementation - - -
    public fun get_entry_by_idx_mut<K: copy, V>(self: &mut VecMap<K, V>, idx: u64): (&K, &mut V) {
    -    assert!(idx < size(self), EIndexOutOfBounds);
    -    let entry = &mut self.contents[idx];
    -    (&entry.key, &mut entry.value)
    -}
    -
    - - - -
    - - - -## Function `remove_entry_by_idx` - -Remove the entry at index idx from self. -Aborts if idx is greater than or equal to size(self) - - -
    public fun remove_entry_by_idx<K: copy, V>(self: &mut vec_map::VecMap<K, V>, idx: u64): (K, V)
    -
    - - - -
    -Implementation - - -
    public fun remove_entry_by_idx<K: copy, V>(self: &mut VecMap<K, V>, idx: u64): (K, V) {
    -    assert!(idx < size(self), EIndexOutOfBounds);
    -    let Entry { key, value } = self.contents.remove(idx);
    -    (key, value)
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/vec_set.md b/crates/sui-framework/docs/sui-framework/vec_set.md deleted file mode 100644 index 3186e0dd928..00000000000 --- a/crates/sui-framework/docs/sui-framework/vec_set.md +++ /dev/null @@ -1,377 +0,0 @@ ---- -title: Module `0x2::vec_set` ---- - - - -- [Struct `VecSet`](#0x2_vec_set_VecSet) -- [Constants](#@Constants_0) -- [Function `empty`](#0x2_vec_set_empty) -- [Function `singleton`](#0x2_vec_set_singleton) -- [Function `insert`](#0x2_vec_set_insert) -- [Function `remove`](#0x2_vec_set_remove) -- [Function `contains`](#0x2_vec_set_contains) -- [Function `size`](#0x2_vec_set_size) -- [Function `is_empty`](#0x2_vec_set_is_empty) -- [Function `into_keys`](#0x2_vec_set_into_keys) -- [Function `keys`](#0x2_vec_set_keys) -- [Function `get_idx_opt`](#0x2_vec_set_get_idx_opt) -- [Function `get_idx`](#0x2_vec_set_get_idx) - - -
    use 0x1::option;
    -use 0x1::vector;
    -
    - - - - - -## Struct `VecSet` - -A set data structure backed by a vector. The set is guaranteed not to -contain duplicate keys. All operations are O(N) in the size of the set -- the intention of this data structure is only to provide the convenience -of programming against a set API. Sets that need sorted iteration rather -than insertion order iteration should be handwritten. - - -
    struct VecSet<K: copy, drop> has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -contents: vector<K> -
    -
    - -
    -
    - - -
    - - - -## Constants - - - - -This key already exists in the map - - -
    const EKeyAlreadyExists: u64 = 0;
    -
    - - - - - -This key does not exist in the map - - -
    const EKeyDoesNotExist: u64 = 1;
    -
    - - - - - -## Function `empty` - -Create an empty VecSet - - -
    public fun empty<K: copy, drop>(): vec_set::VecSet<K>
    -
    - - - -
    -Implementation - - -
    public fun empty<K: copy + drop>(): VecSet<K> {
    -    VecSet { contents: vector[] }
    -}
    -
    - - - -
    - - - -## Function `singleton` - -Create a singleton VecSet that only contains one element. - - -
    public fun singleton<K: copy, drop>(key: K): vec_set::VecSet<K>
    -
    - - - -
    -Implementation - - -
    public fun singleton<K: copy + drop>(key: K): VecSet<K> {
    -    VecSet { contents: vector[key] }
    -}
    -
    - - - -
    - - - -## Function `insert` - -Insert a key into self. -Aborts if key is already present in self. - - -
    public fun insert<K: copy, drop>(self: &mut vec_set::VecSet<K>, key: K)
    -
    - - - -
    -Implementation - - -
    public fun insert<K: copy + drop>(self: &mut VecSet<K>, key: K) {
    -    assert!(!self.contains(&key), EKeyAlreadyExists);
    -    self.contents.push_back(key)
    -}
    -
    - - - -
    - - - -## Function `remove` - -Remove the entry key from self. Aborts if key is not present in self. - - -
    public fun remove<K: copy, drop>(self: &mut vec_set::VecSet<K>, key: &K)
    -
    - - - -
    -Implementation - - -
    public fun remove<K: copy + drop>(self: &mut VecSet<K>, key: &K) {
    -    let idx = get_idx(self, key);
    -    self.contents.remove(idx);
    -}
    -
    - - - -
    - - - -## Function `contains` - -Return true if self contains an entry for key, false otherwise - - -
    public fun contains<K: copy, drop>(self: &vec_set::VecSet<K>, key: &K): bool
    -
    - - - -
    -Implementation - - -
    public fun contains<K: copy + drop>(self: &VecSet<K>, key: &K): bool {
    -    get_idx_opt(self, key).is_some()
    -}
    -
    - - - -
    - - - -## Function `size` - -Return the number of entries in self - - -
    public fun size<K: copy, drop>(self: &vec_set::VecSet<K>): u64
    -
    - - - -
    -Implementation - - -
    public fun size<K: copy + drop>(self: &VecSet<K>): u64 {
    -    self.contents.length()
    -}
    -
    - - - -
    - - - -## Function `is_empty` - -Return true if self has 0 elements, false otherwise - - -
    public fun is_empty<K: copy, drop>(self: &vec_set::VecSet<K>): bool
    -
    - - - -
    -Implementation - - -
    public fun is_empty<K: copy + drop>(self: &VecSet<K>): bool {
    -    size(self) == 0
    -}
    -
    - - - -
    - - - -## Function `into_keys` - -Unpack self into vectors of keys. -The output keys are stored in insertion order, *not* sorted. - - -
    public fun into_keys<K: copy, drop>(self: vec_set::VecSet<K>): vector<K>
    -
    - - - -
    -Implementation - - -
    public fun into_keys<K: copy + drop>(self: VecSet<K>): vector<K> {
    -    let VecSet { contents } = self;
    -    contents
    -}
    -
    - - - -
    - - - -## Function `keys` - -Borrow the contents of the VecSet to access content by index -without unpacking. The contents are stored in insertion order, -*not* sorted. - - -
    public fun keys<K: copy, drop>(self: &vec_set::VecSet<K>): &vector<K>
    -
    - - - -
    -Implementation - - -
    public fun keys<K: copy + drop>(self: &VecSet<K>): &vector<K> {
    -    &self.contents
    -}
    -
    - - - -
    - - - -## Function `get_idx_opt` - -Find the index of key in self. Return None if key is not in self. -Note that keys are stored in insertion order, *not* sorted. - - -
    fun get_idx_opt<K: copy, drop>(self: &vec_set::VecSet<K>, key: &K): option::Option<u64>
    -
    - - - -
    -Implementation - - -
    fun get_idx_opt<K: copy + drop>(self: &VecSet<K>, key: &K): Option<u64> {
    -    let mut i = 0;
    -    let n = size(self);
    -    while (i < n) {
    -        if (&self.contents[i] == key) {
    -            return option::some(i)
    -        };
    -        i = i + 1;
    -    };
    -    option::none()
    -}
    -
    - - - -
    - - - -## Function `get_idx` - -Find the index of key in self. Aborts if key is not in self. -Note that map entries are stored in insertion order, *not* sorted. - - -
    fun get_idx<K: copy, drop>(self: &vec_set::VecSet<K>, key: &K): u64
    -
    - - - -
    -Implementation - - -
    fun get_idx<K: copy + drop>(self: &VecSet<K>, key: &K): u64 {
    -    let idx_opt = get_idx_opt(self, key);
    -    assert!(idx_opt.is_some(), EKeyDoesNotExist);
    -    idx_opt.destroy_some()
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-framework/versioned.md b/crates/sui-framework/docs/sui-framework/versioned.md deleted file mode 100644 index 8ff537cc794..00000000000 --- a/crates/sui-framework/docs/sui-framework/versioned.md +++ /dev/null @@ -1,309 +0,0 @@ ---- -title: Module `0x2::versioned` ---- - - - -- [Resource `Versioned`](#0x2_versioned_Versioned) -- [Struct `VersionChangeCap`](#0x2_versioned_VersionChangeCap) -- [Constants](#@Constants_0) -- [Function `create`](#0x2_versioned_create) -- [Function `version`](#0x2_versioned_version) -- [Function `load_value`](#0x2_versioned_load_value) -- [Function `load_value_mut`](#0x2_versioned_load_value_mut) -- [Function `remove_value_for_upgrade`](#0x2_versioned_remove_value_for_upgrade) -- [Function `upgrade`](#0x2_versioned_upgrade) -- [Function `destroy`](#0x2_versioned_destroy) - - -
    use 0x2::dynamic_field;
    -use 0x2::object;
    -use 0x2::tx_context;
    -
    - - - - - -## Resource `Versioned` - -A wrapper type that supports versioning of the inner type. -The inner type is a dynamic field of the Versioned object, and is keyed using version. -User of this type could load the inner object using corresponding type based on the version. -You can also upgrade the inner object to a new type version. -If you want to support lazy upgrade of the inner type, one caveat is that all APIs would have -to use mutable reference even if it's a read-only API. - - -
    struct Versioned has store, key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -version: u64 -
    -
    - -
    -
    - - -
    - - - -## Struct `VersionChangeCap` - -Represents a hot potato object generated when we take out the dynamic field. -This is to make sure that we always put a new value back. - - -
    struct VersionChangeCap
    -
    - - - -
    -Fields - - -
    -
    -versioned_id: object::ID -
    -
    - -
    -
    -old_version: u64 -
    -
    - -
    -
    - - -
    - - - -## Constants - - - - -Failed to upgrade the inner object due to invalid capability or new version. - - -
    const EInvalidUpgrade: u64 = 0;
    -
    - - - - - -## Function `create` - -Create a new Versioned object that contains a initial value of type T with an initial version. - - -
    public fun create<T: store>(init_version: u64, init_value: T, ctx: &mut tx_context::TxContext): versioned::Versioned
    -
    - - - -
    -Implementation - - -
    public fun create<T: store>(init_version: u64, init_value: T, ctx: &mut TxContext): Versioned {
    -    let mut self = Versioned {
    -        id: object::new(ctx),
    -        version: init_version,
    -    };
    -    dynamic_field::add(&mut self.id, init_version, init_value);
    -    self
    -}
    -
    - - - -
    - - - -## Function `version` - -Get the current version of the inner type. - - -
    public fun version(self: &versioned::Versioned): u64
    -
    - - - -
    -Implementation - - -
    public fun version(self: &Versioned): u64 {
    -    self.version
    -}
    -
    - - - -
    - - - -## Function `load_value` - -Load the inner value based on the current version. Caller specifies an expected type T. -If the type mismatch, the load will fail. - - -
    public fun load_value<T: store>(self: &versioned::Versioned): &T
    -
    - - - -
    -Implementation - - -
    public fun load_value<T: store>(self: &Versioned): &T {
    -    dynamic_field::borrow(&self.id, self.version)
    -}
    -
    - - - -
    - - - -## Function `load_value_mut` - -Similar to load_value, but return a mutable reference. - - -
    public fun load_value_mut<T: store>(self: &mut versioned::Versioned): &mut T
    -
    - - - -
    -Implementation - - -
    public fun load_value_mut<T: store>(self: &mut Versioned): &mut T {
    -    dynamic_field::borrow_mut(&mut self.id, self.version)
    -}
    -
    - - - -
    - - - -## Function `remove_value_for_upgrade` - -Take the inner object out for upgrade. To ensure we always upgrade properly, a capability object is returned -and must be used when we upgrade. - - -
    public fun remove_value_for_upgrade<T: store>(self: &mut versioned::Versioned): (T, versioned::VersionChangeCap)
    -
    - - - -
    -Implementation - - -
    public fun remove_value_for_upgrade<T: store>(self: &mut Versioned): (T, VersionChangeCap) {
    -    (
    -        dynamic_field::remove(&mut self.id, self.version),
    -        VersionChangeCap {
    -            versioned_id: object::id(self),
    -            old_version: self.version,
    -        }
    -    )
    -}
    -
    - - - -
    - - - -## Function `upgrade` - -Upgrade the inner object with a new version and new value. Must use the capability returned -by calling remove_value_for_upgrade. - - -
    public fun upgrade<T: store>(self: &mut versioned::Versioned, new_version: u64, new_value: T, cap: versioned::VersionChangeCap)
    -
    - - - -
    -Implementation - - -
    public fun upgrade<T: store>(self: &mut Versioned, new_version: u64, new_value: T, cap: VersionChangeCap) {
    -    let VersionChangeCap { versioned_id, old_version } = cap;
    -    assert!(versioned_id == object::id(self), EInvalidUpgrade);
    -    assert!(old_version < new_version, EInvalidUpgrade);
    -    dynamic_field::add(&mut self.id, new_version, new_value);
    -    self.version = new_version;
    -}
    -
    - - - -
    - - - -## Function `destroy` - -Destroy this Versioned container, and return the inner object. - - -
    public fun destroy<T: store>(self: versioned::Versioned): T
    -
    - - - -
    -Implementation - - -
    public fun destroy<T: store>(self: Versioned): T {
    -    let Versioned { mut id, version } = self;
    -    let ret = dynamic_field::remove(&mut id, version);
    -    id.delete();
    -    ret
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-system/genesis.md b/crates/sui-framework/docs/sui-system/genesis.md deleted file mode 100644 index d519c1ce0d5..00000000000 --- a/crates/sui-framework/docs/sui-system/genesis.md +++ /dev/null @@ -1,563 +0,0 @@ ---- -title: Module `0x3::genesis` ---- - - - -- [Struct `GenesisValidatorMetadata`](#0x3_genesis_GenesisValidatorMetadata) -- [Struct `GenesisChainParameters`](#0x3_genesis_GenesisChainParameters) -- [Struct `TokenDistributionSchedule`](#0x3_genesis_TokenDistributionSchedule) -- [Struct `TokenAllocation`](#0x3_genesis_TokenAllocation) -- [Constants](#@Constants_0) -- [Function `create`](#0x3_genesis_create) -- [Function `allocate_tokens`](#0x3_genesis_allocate_tokens) -- [Function `activate_validators`](#0x3_genesis_activate_validators) - - -
    use 0x1::option;
    -use 0x1::vector;
    -use 0x2::balance;
    -use 0x2::coin;
    -use 0x2::object;
    -use 0x2::sui;
    -use 0x2::tx_context;
    -use 0x3::stake_subsidy;
    -use 0x3::sui_system;
    -use 0x3::sui_system_state_inner;
    -use 0x3::validator;
    -use 0x3::validator_set;
    -
    - - - - - -## Struct `GenesisValidatorMetadata` - - - -
    struct GenesisValidatorMetadata has copy, drop
    -
    - - - -
    -Fields - - -
    -
    -name: vector<u8> -
    -
    - -
    -
    -description: vector<u8> -
    -
    - -
    -
    -image_url: vector<u8> -
    -
    - -
    -
    -project_url: vector<u8> -
    -
    - -
    -
    -sui_address: address -
    -
    - -
    -
    -gas_price: u64 -
    -
    - -
    -
    -commission_rate: u64 -
    -
    - -
    -
    -protocol_public_key: vector<u8> -
    -
    - -
    -
    -proof_of_possession: vector<u8> -
    -
    - -
    -
    -network_public_key: vector<u8> -
    -
    - -
    -
    -worker_public_key: vector<u8> -
    -
    - -
    -
    -network_address: vector<u8> -
    -
    - -
    -
    -p2p_address: vector<u8> -
    -
    - -
    -
    -primary_address: vector<u8> -
    -
    - -
    -
    -worker_address: vector<u8> -
    -
    - -
    -
    - - -
    - - - -## Struct `GenesisChainParameters` - - - -
    struct GenesisChainParameters has copy, drop
    -
    - - - -
    -Fields - - -
    -
    -protocol_version: u64 -
    -
    - -
    -
    -chain_start_timestamp_ms: u64 -
    -
    - -
    -
    -epoch_duration_ms: u64 -
    -
    - -
    -
    -stake_subsidy_start_epoch: u64 -
    -
    - -
    -
    -stake_subsidy_initial_distribution_amount: u64 -
    -
    - -
    -
    -stake_subsidy_period_length: u64 -
    -
    - -
    -
    -stake_subsidy_decrease_rate: u16 -
    -
    - -
    -
    -max_validator_count: u64 -
    -
    - -
    -
    -min_validator_joining_stake: u64 -
    -
    - -
    -
    -validator_low_stake_threshold: u64 -
    -
    - -
    -
    -validator_very_low_stake_threshold: u64 -
    -
    - -
    -
    -validator_low_stake_grace_period: u64 -
    -
    - -
    -
    - - -
    - - - -## Struct `TokenDistributionSchedule` - - - -
    struct TokenDistributionSchedule
    -
    - - - -
    -Fields - - -
    -
    -stake_subsidy_fund_mist: u64 -
    -
    - -
    -
    -allocations: vector<genesis::TokenAllocation> -
    -
    - -
    -
    - - -
    - - - -## Struct `TokenAllocation` - - - -
    struct TokenAllocation
    -
    - - - -
    -Fields - - -
    -
    -recipient_address: address -
    -
    - -
    -
    -amount_mist: u64 -
    -
    - -
    -
    -staked_with_validator: option::Option<address> -
    -
    - Indicates if this allocation should be staked at genesis and with which validator -
    -
    - - -
    - - - -## Constants - - - - -The create function was called with duplicate validators. - - -
    const EDuplicateValidator: u64 = 1;
    -
    - - - - - -The create function was called at a non-genesis epoch. - - -
    const ENotCalledAtGenesis: u64 = 0;
    -
    - - - - - -## Function `create` - -This function will be explicitly called once at genesis. -It will create a singleton SuiSystemState object, which contains -all the information we need in the system. - - -
    fun create(sui_system_state_id: object::UID, sui_supply: balance::Balance<sui::SUI>, genesis_chain_parameters: genesis::GenesisChainParameters, genesis_validators: vector<genesis::GenesisValidatorMetadata>, token_distribution_schedule: genesis::TokenDistributionSchedule, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    fun create(
    -    sui_system_state_id: UID,
    -    mut sui_supply: Balance<SUI>,
    -    genesis_chain_parameters: GenesisChainParameters,
    -    genesis_validators: vector<GenesisValidatorMetadata>,
    -    token_distribution_schedule: TokenDistributionSchedule,
    -    ctx: &mut TxContext,
    -) {
    -    // Ensure this is only called at genesis
    -    assert!(ctx.epoch() == 0, ENotCalledAtGenesis);
    -
    -    let TokenDistributionSchedule {
    -        stake_subsidy_fund_mist,
    -        allocations,
    -    } = token_distribution_schedule;
    -
    -    let subsidy_fund = sui_supply.split(stake_subsidy_fund_mist);
    -    let storage_fund = balance::zero();
    -
    -    // Create all the `Validator` structs
    -    let mut validators = vector[];
    -    let count = genesis_validators.length();
    -    let mut i = 0;
    -    while (i < count) {
    -        let GenesisValidatorMetadata {
    -            name,
    -            description,
    -            image_url,
    -            project_url,
    -            sui_address,
    -            gas_price,
    -            commission_rate,
    -            protocol_public_key,
    -            proof_of_possession,
    -            network_public_key,
    -            worker_public_key,
    -            network_address,
    -            p2p_address,
    -            primary_address,
    -            worker_address,
    -        } = genesis_validators[i];
    -
    -        let validator = validator::new(
    -            sui_address,
    -            protocol_public_key,
    -            network_public_key,
    -            worker_public_key,
    -            proof_of_possession,
    -            name,
    -            description,
    -            image_url,
    -            project_url,
    -            network_address,
    -            p2p_address,
    -            primary_address,
    -            worker_address,
    -            gas_price,
    -            commission_rate,
    -            ctx
    -        );
    -
    -        // Ensure that each validator is unique
    -        assert!(
    -            !validator_set::is_duplicate_validator(&validators, &validator),
    -            EDuplicateValidator,
    -        );
    -
    -        validators.push_back(validator);
    -
    -        i = i + 1;
    -    };
    -
    -    // Allocate tokens and staking operations
    -    allocate_tokens(
    -        sui_supply,
    -        allocations,
    -        &mut validators,
    -        ctx
    -    );
    -
    -    // Activate all validators
    -    activate_validators(&mut validators);
    -
    -    let system_parameters = sui_system_state_inner::create_system_parameters(
    -        genesis_chain_parameters.epoch_duration_ms,
    -        genesis_chain_parameters.stake_subsidy_start_epoch,
    -
    -        // Validator committee parameters
    -        genesis_chain_parameters.max_validator_count,
    -        genesis_chain_parameters.min_validator_joining_stake,
    -        genesis_chain_parameters.validator_low_stake_threshold,
    -        genesis_chain_parameters.validator_very_low_stake_threshold,
    -        genesis_chain_parameters.validator_low_stake_grace_period,
    -
    -        ctx,
    -    );
    -
    -    let stake_subsidy = stake_subsidy::create(
    -        subsidy_fund,
    -        genesis_chain_parameters.stake_subsidy_initial_distribution_amount,
    -        genesis_chain_parameters.stake_subsidy_period_length,
    -        genesis_chain_parameters.stake_subsidy_decrease_rate,
    -        ctx,
    -    );
    -
    -    sui_system::create(
    -        sui_system_state_id,
    -        validators,
    -        storage_fund,
    -        genesis_chain_parameters.protocol_version,
    -        genesis_chain_parameters.chain_start_timestamp_ms,
    -        system_parameters,
    -        stake_subsidy,
    -        ctx,
    -    );
    -}
    -
    - - - -
    - - - -## Function `allocate_tokens` - - - -
    fun allocate_tokens(sui_supply: balance::Balance<sui::SUI>, allocations: vector<genesis::TokenAllocation>, validators: &mut vector<validator::Validator>, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    fun allocate_tokens(
    -    mut sui_supply: Balance<SUI>,
    -    mut allocations: vector<TokenAllocation>,
    -    validators: &mut vector<Validator>,
    -    ctx: &mut TxContext,
    -) {
    -
    -    while (!allocations.is_empty()) {
    -        let TokenAllocation {
    -            recipient_address,
    -            amount_mist,
    -            staked_with_validator,
    -        } = allocations.pop_back();
    -
    -        let allocation_balance = sui_supply.split(amount_mist);
    -
    -        if (staked_with_validator.is_some()) {
    -            let validator_address = staked_with_validator.destroy_some();
    -            let validator = validator_set::get_validator_mut(validators, validator_address);
    -            validator.request_add_stake_at_genesis(
    -                allocation_balance,
    -                recipient_address,
    -                ctx
    -            );
    -        } else {
    -            sui::transfer(
    -                allocation_balance.into_coin(ctx),
    -                recipient_address,
    -            );
    -        };
    -    };
    -    allocations.destroy_empty();
    -
    -    // Provided allocations must fully allocate the sui_supply and there
    -    // should be none left at this point.
    -    sui_supply.destroy_zero();
    -}
    -
    - - - -
    - - - -## Function `activate_validators` - - - -
    fun activate_validators(validators: &mut vector<validator::Validator>)
    -
    - - - -
    -Implementation - - -
    fun activate_validators(validators: &mut vector<Validator>) {
    -    // Activate all genesis validators
    -    let count = validators.length();
    -    let mut i = 0;
    -    while (i < count) {
    -        let validator = &mut validators[i];
    -        validator.activate(0);
    -
    -        i = i + 1;
    -    };
    -
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-system/stake_subsidy.md b/crates/sui-framework/docs/sui-system/stake_subsidy.md deleted file mode 100644 index 948b47786b7..00000000000 --- a/crates/sui-framework/docs/sui-system/stake_subsidy.md +++ /dev/null @@ -1,213 +0,0 @@ ---- -title: Module `0x3::stake_subsidy` ---- - - - -- [Struct `StakeSubsidy`](#0x3_stake_subsidy_StakeSubsidy) -- [Constants](#@Constants_0) -- [Function `create`](#0x3_stake_subsidy_create) -- [Function `advance_epoch`](#0x3_stake_subsidy_advance_epoch) -- [Function `current_epoch_subsidy_amount`](#0x3_stake_subsidy_current_epoch_subsidy_amount) - - -
    use 0x2::bag;
    -use 0x2::balance;
    -use 0x2::math;
    -use 0x2::sui;
    -use 0x2::tx_context;
    -
    - - - - - -## Struct `StakeSubsidy` - - - -
    struct StakeSubsidy has store
    -
    - - - -
    -Fields - - -
    -
    -balance: balance::Balance<sui::SUI> -
    -
    - Balance of SUI set aside for stake subsidies that will be drawn down over time. -
    -
    -distribution_counter: u64 -
    -
    - Count of the number of times stake subsidies have been distributed. -
    -
    -current_distribution_amount: u64 -
    -
    - The amount of stake subsidy to be drawn down per distribution. - This amount decays and decreases over time. -
    -
    -stake_subsidy_period_length: u64 -
    -
    - Number of distributions to occur before the distribution amount decays. -
    -
    -stake_subsidy_decrease_rate: u16 -
    -
    - The rate at which the distribution amount decays at the end of each - period. Expressed in basis points. -
    -
    -extra_fields: bag::Bag -
    -
    - Any extra fields that's not defined statically. -
    -
    - - -
    - - - -## Constants - - - - - - -
    const BASIS_POINT_DENOMINATOR: u128 = 10000;
    -
    - - - - - - - -
    const ESubsidyDecreaseRateTooLarge: u64 = 0;
    -
    - - - - - -## Function `create` - - - -
    public(friend) fun create(balance: balance::Balance<sui::SUI>, initial_distribution_amount: u64, stake_subsidy_period_length: u64, stake_subsidy_decrease_rate: u16, ctx: &mut tx_context::TxContext): stake_subsidy::StakeSubsidy
    -
    - - - -
    -Implementation - - -
    public(package) fun create(
    -    balance: Balance<SUI>,
    -    initial_distribution_amount: u64,
    -    stake_subsidy_period_length: u64,
    -    stake_subsidy_decrease_rate: u16,
    -    ctx: &mut TxContext,
    -): StakeSubsidy {
    -    // Rate can't be higher than 100%.
    -    assert!(
    -        stake_subsidy_decrease_rate <= BASIS_POINT_DENOMINATOR as u16,
    -        ESubsidyDecreaseRateTooLarge,
    -    );
    -
    -    StakeSubsidy {
    -        balance,
    -        distribution_counter: 0,
    -        current_distribution_amount: initial_distribution_amount,
    -        stake_subsidy_period_length,
    -        stake_subsidy_decrease_rate,
    -        extra_fields: bag::new(ctx),
    -    }
    -}
    -
    - - - -
    - - - -## Function `advance_epoch` - -Advance the epoch counter and draw down the subsidy for the epoch. - - -
    public(friend) fun advance_epoch(self: &mut stake_subsidy::StakeSubsidy): balance::Balance<sui::SUI>
    -
    - - - -
    -Implementation - - -
    public(package) fun advance_epoch(self: &mut StakeSubsidy): Balance<SUI> {
    -    // Take the minimum of the reward amount and the remaining balance in
    -    // order to ensure we don't overdraft the remaining stake subsidy
    -    // balance
    -    let to_withdraw = math::min(self.current_distribution_amount, self.balance.value());
    -
    -    // Drawn down the subsidy for this epoch.
    -    let stake_subsidy = self.balance.split(to_withdraw);
    -
    -    self.distribution_counter = self.distribution_counter + 1;
    -
    -    // Decrease the subsidy amount only when the current period ends.
    -    if (self.distribution_counter % self.stake_subsidy_period_length == 0) {
    -        let decrease_amount = self.current_distribution_amount as u128
    -            * (self.stake_subsidy_decrease_rate as u128) / BASIS_POINT_DENOMINATOR;
    -        self.current_distribution_amount = self.current_distribution_amount - (decrease_amount as u64)
    -    };
    -
    -    stake_subsidy
    -}
    -
    - - - -
    - - - -## Function `current_epoch_subsidy_amount` - -Returns the amount of stake subsidy to be added at the end of the current epoch. - - -
    public fun current_epoch_subsidy_amount(self: &stake_subsidy::StakeSubsidy): u64
    -
    - - - -
    -Implementation - - -
    public fun current_epoch_subsidy_amount(self: &StakeSubsidy): u64 {
    -    math::min(self.current_distribution_amount, self.balance.value())
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-system/staking_pool.md b/crates/sui-framework/docs/sui-system/staking_pool.md deleted file mode 100644 index eceed22bdd1..00000000000 --- a/crates/sui-framework/docs/sui-system/staking_pool.md +++ /dev/null @@ -1,1412 +0,0 @@ ---- -title: Module `0x3::staking_pool` ---- - - - -- [Resource `StakingPool`](#0x3_staking_pool_StakingPool) -- [Struct `PoolTokenExchangeRate`](#0x3_staking_pool_PoolTokenExchangeRate) -- [Resource `StakedSui`](#0x3_staking_pool_StakedSui) -- [Constants](#@Constants_0) -- [Function `new`](#0x3_staking_pool_new) -- [Function `request_add_stake`](#0x3_staking_pool_request_add_stake) -- [Function `request_withdraw_stake`](#0x3_staking_pool_request_withdraw_stake) -- [Function `withdraw_from_principal`](#0x3_staking_pool_withdraw_from_principal) -- [Function `unwrap_staked_sui`](#0x3_staking_pool_unwrap_staked_sui) -- [Function `deposit_rewards`](#0x3_staking_pool_deposit_rewards) -- [Function `process_pending_stakes_and_withdraws`](#0x3_staking_pool_process_pending_stakes_and_withdraws) -- [Function `process_pending_stake_withdraw`](#0x3_staking_pool_process_pending_stake_withdraw) -- [Function `process_pending_stake`](#0x3_staking_pool_process_pending_stake) -- [Function `withdraw_rewards`](#0x3_staking_pool_withdraw_rewards) -- [Function `activate_staking_pool`](#0x3_staking_pool_activate_staking_pool) -- [Function `deactivate_staking_pool`](#0x3_staking_pool_deactivate_staking_pool) -- [Function `sui_balance`](#0x3_staking_pool_sui_balance) -- [Function `pool_id`](#0x3_staking_pool_pool_id) -- [Function `staked_sui_amount`](#0x3_staking_pool_staked_sui_amount) -- [Function `stake_activation_epoch`](#0x3_staking_pool_stake_activation_epoch) -- [Function `is_preactive`](#0x3_staking_pool_is_preactive) -- [Function `is_inactive`](#0x3_staking_pool_is_inactive) -- [Function `split`](#0x3_staking_pool_split) -- [Function `split_staked_sui`](#0x3_staking_pool_split_staked_sui) -- [Function `join_staked_sui`](#0x3_staking_pool_join_staked_sui) -- [Function `is_equal_staking_metadata`](#0x3_staking_pool_is_equal_staking_metadata) -- [Function `pool_token_exchange_rate_at_epoch`](#0x3_staking_pool_pool_token_exchange_rate_at_epoch) -- [Function `pending_stake_amount`](#0x3_staking_pool_pending_stake_amount) -- [Function `pending_stake_withdraw_amount`](#0x3_staking_pool_pending_stake_withdraw_amount) -- [Function `exchange_rates`](#0x3_staking_pool_exchange_rates) -- [Function `sui_amount`](#0x3_staking_pool_sui_amount) -- [Function `pool_token_amount`](#0x3_staking_pool_pool_token_amount) -- [Function `is_preactive_at_epoch`](#0x3_staking_pool_is_preactive_at_epoch) -- [Function `get_sui_amount`](#0x3_staking_pool_get_sui_amount) -- [Function `get_token_amount`](#0x3_staking_pool_get_token_amount) -- [Function `initial_exchange_rate`](#0x3_staking_pool_initial_exchange_rate) -- [Function `check_balance_invariants`](#0x3_staking_pool_check_balance_invariants) - - -
    use 0x1::option;
    -use 0x2::bag;
    -use 0x2::balance;
    -use 0x2::math;
    -use 0x2::object;
    -use 0x2::sui;
    -use 0x2::table;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -
    - - - - - -## Resource `StakingPool` - -A staking pool embedded in each validator struct in the system state object. - - -
    struct StakingPool has store, key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -activation_epoch: option::Option<u64> -
    -
    - The epoch at which this pool became active. - The value is None if the pool is pre-active and Some(<epoch_number>) if active or inactive. -
    -
    -deactivation_epoch: option::Option<u64> -
    -
    - The epoch at which this staking pool ceased to be active. None = {pre-active, active}, - Some(<epoch_number>) if in-active, and it was de-activated at epoch <epoch_number>. -
    -
    -sui_balance: u64 -
    -
    - The total number of SUI tokens in this pool, including the SUI in the rewards_pool, as well as in all the principal - in the StakedSui object, updated at epoch boundaries. -
    -
    -rewards_pool: balance::Balance<sui::SUI> -
    -
    - The epoch stake rewards will be added here at the end of each epoch. -
    -
    -pool_token_balance: u64 -
    -
    - Total number of pool tokens issued by the pool. -
    -
    -exchange_rates: table::Table<u64, staking_pool::PoolTokenExchangeRate> -
    -
    - Exchange rate history of previous epochs. Key is the epoch number. - The entries start from the activation_epoch of this pool and contains exchange rates at the beginning of each epoch, - i.e., right after the rewards for the previous epoch have been deposited into the pool. -
    -
    -pending_stake: u64 -
    -
    - Pending stake amount for this epoch, emptied at epoch boundaries. -
    -
    -pending_total_sui_withdraw: u64 -
    -
    - Pending stake withdrawn during the current epoch, emptied at epoch boundaries. - This includes both the principal and rewards SUI withdrawn. -
    -
    -pending_pool_token_withdraw: u64 -
    -
    - Pending pool token withdrawn during the current epoch, emptied at epoch boundaries. -
    -
    -extra_fields: bag::Bag -
    -
    - Any extra fields that's not defined statically. -
    -
    - - -
    - - - -## Struct `PoolTokenExchangeRate` - -Struct representing the exchange rate of the stake pool token to SUI. - - -
    struct PoolTokenExchangeRate has copy, drop, store
    -
    - - - -
    -Fields - - -
    -
    -sui_amount: u64 -
    -
    - -
    -
    -pool_token_amount: u64 -
    -
    - -
    -
    - - -
    - - - -## Resource `StakedSui` - -A self-custodial object holding the staked SUI tokens. - - -
    struct StakedSui has store, key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -pool_id: object::ID -
    -
    - ID of the staking pool we are staking with. -
    -
    -stake_activation_epoch: u64 -
    -
    - The epoch at which the stake becomes active. -
    -
    -principal: balance::Balance<sui::SUI> -
    -
    - The staked SUI tokens. -
    -
    - - -
    - - - -## Constants - - - - - - -
    const EActivationOfInactivePool: u64 = 16;
    -
    - - - - - - - -
    const EDeactivationOfInactivePool: u64 = 11;
    -
    - - - - - - - -
    const EDelegationOfZeroSui: u64 = 17;
    -
    - - - - - - - -
    const EDelegationToInactivePool: u64 = 10;
    -
    - - - - - - - -
    const EDestroyNonzeroBalance: u64 = 5;
    -
    - - - - - - - -
    const EIncompatibleStakedSui: u64 = 12;
    -
    - - - - - - - -
    const EInsufficientPoolTokenBalance: u64 = 0;
    -
    - - - - - - - -
    const EInsufficientRewardsPoolBalance: u64 = 4;
    -
    - - - - - - - -
    const EInsufficientSuiTokenBalance: u64 = 3;
    -
    - - - - - - - -
    const EPendingDelegationDoesNotExist: u64 = 8;
    -
    - - - - - - - -
    const EPoolAlreadyActive: u64 = 14;
    -
    - - - - - - - -
    const EPoolNotPreactive: u64 = 15;
    -
    - - - - - - - -
    const EStakedSuiBelowThreshold: u64 = 18;
    -
    - - - - - - - -
    const ETokenBalancesDoNotMatchExchangeRate: u64 = 9;
    -
    - - - - - - - -
    const ETokenTimeLockIsSome: u64 = 6;
    -
    - - - - - - - -
    const EWithdrawAmountCannotBeZero: u64 = 2;
    -
    - - - - - - - -
    const EWithdrawalInSameEpoch: u64 = 13;
    -
    - - - - - - - -
    const EWrongDelegation: u64 = 7;
    -
    - - - - - - - -
    const EWrongPool: u64 = 1;
    -
    - - - - - -StakedSui objects cannot be split to below this amount. - - -
    const MIN_STAKING_THRESHOLD: u64 = 1000000000;
    -
    - - - - - -## Function `new` - -Create a new, empty staking pool. - - -
    public(friend) fun new(ctx: &mut tx_context::TxContext): staking_pool::StakingPool
    -
    - - - -
    -Implementation - - -
    public(package) fun new(ctx: &mut TxContext) : StakingPool {
    -    let exchange_rates = table::new(ctx);
    -    StakingPool {
    -        id: object::new(ctx),
    -        activation_epoch: option::none(),
    -        deactivation_epoch: option::none(),
    -        sui_balance: 0,
    -        rewards_pool: balance::zero(),
    -        pool_token_balance: 0,
    -        exchange_rates,
    -        pending_stake: 0,
    -        pending_total_sui_withdraw: 0,
    -        pending_pool_token_withdraw: 0,
    -        extra_fields: bag::new(ctx),
    -    }
    -}
    -
    - - - -
    - - - -## Function `request_add_stake` - -Request to stake to a staking pool. The stake starts counting at the beginning of the next epoch, - - -
    public(friend) fun request_add_stake(pool: &mut staking_pool::StakingPool, stake: balance::Balance<sui::SUI>, stake_activation_epoch: u64, ctx: &mut tx_context::TxContext): staking_pool::StakedSui
    -
    - - - -
    -Implementation - - -
    public(package) fun request_add_stake(
    -    pool: &mut StakingPool,
    -    stake: Balance<SUI>,
    -    stake_activation_epoch: u64,
    -    ctx: &mut TxContext
    -) : StakedSui {
    -    let sui_amount = stake.value();
    -    assert!(!is_inactive(pool), EDelegationToInactivePool);
    -    assert!(sui_amount > 0, EDelegationOfZeroSui);
    -    let staked_sui = StakedSui {
    -        id: object::new(ctx),
    -        pool_id: object::id(pool),
    -        stake_activation_epoch,
    -        principal: stake,
    -    };
    -    pool.pending_stake = pool.pending_stake + sui_amount;
    -    staked_sui
    -}
    -
    - - - -
    - - - -## Function `request_withdraw_stake` - -Request to withdraw the given stake plus rewards from a staking pool. -Both the principal and corresponding rewards in SUI are withdrawn. -A proportional amount of pool token withdraw is recorded and processed at epoch change time. - - -
    public(friend) fun request_withdraw_stake(pool: &mut staking_pool::StakingPool, staked_sui: staking_pool::StakedSui, ctx: &tx_context::TxContext): balance::Balance<sui::SUI>
    -
    - - - -
    -Implementation - - -
    public(package) fun request_withdraw_stake(
    -    pool: &mut StakingPool,
    -    staked_sui: StakedSui,
    -    ctx: &TxContext
    -) : Balance<SUI> {
    -    let (pool_token_withdraw_amount, mut principal_withdraw) =
    -        withdraw_from_principal(pool, staked_sui);
    -    let principal_withdraw_amount = principal_withdraw.value();
    -
    -    let rewards_withdraw = withdraw_rewards(
    -        pool, principal_withdraw_amount, pool_token_withdraw_amount, ctx.epoch()
    -    );
    -    let total_sui_withdraw_amount = principal_withdraw_amount + rewards_withdraw.value();
    -
    -    pool.pending_total_sui_withdraw = pool.pending_total_sui_withdraw + total_sui_withdraw_amount;
    -    pool.pending_pool_token_withdraw = pool.pending_pool_token_withdraw + pool_token_withdraw_amount;
    -
    -    // If the pool is inactive, we immediately process the withdrawal.
    -    if (is_inactive(pool)) process_pending_stake_withdraw(pool);
    -
    -    // TODO: implement withdraw bonding period here.
    -    principal_withdraw.join(rewards_withdraw);
    -    principal_withdraw
    -}
    -
    - - - -
    - - - -## Function `withdraw_from_principal` - -Withdraw the principal SUI stored in the StakedSui object, and calculate the corresponding amount of pool -tokens using exchange rate at staking epoch. -Returns values are amount of pool tokens withdrawn and withdrawn principal portion of SUI. - - -
    public(friend) fun withdraw_from_principal(pool: &staking_pool::StakingPool, staked_sui: staking_pool::StakedSui): (u64, balance::Balance<sui::SUI>)
    -
    - - - -
    -Implementation - - -
    public(package) fun withdraw_from_principal(
    -    pool: &StakingPool,
    -    staked_sui: StakedSui,
    -) : (u64, Balance<SUI>) {
    -
    -    // Check that the stake information matches the pool.
    -    assert!(staked_sui.pool_id == object::id(pool), EWrongPool);
    -
    -    let exchange_rate_at_staking_epoch = pool_token_exchange_rate_at_epoch(pool, staked_sui.stake_activation_epoch);
    -    let principal_withdraw = unwrap_staked_sui(staked_sui);
    -    let pool_token_withdraw_amount = get_token_amount(
    -		&exchange_rate_at_staking_epoch,
    -		principal_withdraw.value()
    -	);
    -
    -    (
    -        pool_token_withdraw_amount,
    -        principal_withdraw,
    -    )
    -}
    -
    - - - -
    - - - -## Function `unwrap_staked_sui` - - - -
    fun unwrap_staked_sui(staked_sui: staking_pool::StakedSui): balance::Balance<sui::SUI>
    -
    - - - -
    -Implementation - - -
    fun unwrap_staked_sui(staked_sui: StakedSui): Balance<SUI> {
    -    let StakedSui {
    -        id,
    -        pool_id: _,
    -        stake_activation_epoch: _,
    -        principal,
    -    } = staked_sui;
    -    object::delete(id);
    -    principal
    -}
    -
    - - - -
    - - - -## Function `deposit_rewards` - -Called at epoch advancement times to add rewards (in SUI) to the staking pool. - - -
    public(friend) fun deposit_rewards(pool: &mut staking_pool::StakingPool, rewards: balance::Balance<sui::SUI>)
    -
    - - - -
    -Implementation - - -
    public(package) fun deposit_rewards(pool: &mut StakingPool, rewards: Balance<SUI>) {
    -    pool.sui_balance = pool.sui_balance + rewards.value();
    -    pool.rewards_pool.join(rewards);
    -}
    -
    - - - -
    - - - -## Function `process_pending_stakes_and_withdraws` - - - -
    public(friend) fun process_pending_stakes_and_withdraws(pool: &mut staking_pool::StakingPool, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun process_pending_stakes_and_withdraws(pool: &mut StakingPool, ctx: &TxContext) {
    -    let new_epoch = ctx.epoch() + 1;
    -    process_pending_stake_withdraw(pool);
    -    process_pending_stake(pool);
    -    pool.exchange_rates.add(
    -        new_epoch,
    -        PoolTokenExchangeRate { sui_amount: pool.sui_balance, pool_token_amount: pool.pool_token_balance },
    -    );
    -    check_balance_invariants(pool, new_epoch);
    -}
    -
    - - - -
    - - - -## Function `process_pending_stake_withdraw` - -Called at epoch boundaries to process pending stake withdraws requested during the epoch. -Also called immediately upon withdrawal if the pool is inactive. - - -
    fun process_pending_stake_withdraw(pool: &mut staking_pool::StakingPool)
    -
    - - - -
    -Implementation - - -
    fun process_pending_stake_withdraw(pool: &mut StakingPool) {
    -    pool.sui_balance = pool.sui_balance - pool.pending_total_sui_withdraw;
    -    pool.pool_token_balance = pool.pool_token_balance - pool.pending_pool_token_withdraw;
    -    pool.pending_total_sui_withdraw = 0;
    -    pool.pending_pool_token_withdraw = 0;
    -}
    -
    - - - -
    - - - -## Function `process_pending_stake` - -Called at epoch boundaries to process the pending stake. - - -
    public(friend) fun process_pending_stake(pool: &mut staking_pool::StakingPool)
    -
    - - - -
    -Implementation - - -
    public(package) fun process_pending_stake(pool: &mut StakingPool) {
    -    // Use the most up to date exchange rate with the rewards deposited and withdraws effectuated.
    -    let latest_exchange_rate =
    -        PoolTokenExchangeRate { sui_amount: pool.sui_balance, pool_token_amount: pool.pool_token_balance };
    -    pool.sui_balance = pool.sui_balance + pool.pending_stake;
    -    pool.pool_token_balance = get_token_amount(&latest_exchange_rate, pool.sui_balance);
    -    pool.pending_stake = 0;
    -}
    -
    - - - -
    - - - -## Function `withdraw_rewards` - -This function does the following: -1. Calculates the total amount of SUI (including principal and rewards) that the provided pool tokens represent -at the current exchange rate. -2. Using the above number and the given principal_withdraw_amount, calculates the rewards portion of the -stake we should withdraw. -3. Withdraws the rewards portion from the rewards pool at the current exchange rate. We only withdraw the rewards -portion because the principal portion was already taken out of the staker's self custodied StakedSui. - - -
    fun withdraw_rewards(pool: &mut staking_pool::StakingPool, principal_withdraw_amount: u64, pool_token_withdraw_amount: u64, epoch: u64): balance::Balance<sui::SUI>
    -
    - - - -
    -Implementation - - -
    fun withdraw_rewards(
    -    pool: &mut StakingPool,
    -    principal_withdraw_amount: u64,
    -    pool_token_withdraw_amount: u64,
    -    epoch: u64,
    -) : Balance<SUI> {
    -    let exchange_rate = pool_token_exchange_rate_at_epoch(pool, epoch);
    -    let total_sui_withdraw_amount = get_sui_amount(&exchange_rate, pool_token_withdraw_amount);
    -    let mut reward_withdraw_amount =
    -        if (total_sui_withdraw_amount >= principal_withdraw_amount)
    -            total_sui_withdraw_amount - principal_withdraw_amount
    -        else 0;
    -    // This may happen when we are withdrawing everything from the pool and
    -    // the rewards pool balance may be less than reward_withdraw_amount.
    -    // TODO: FIGURE OUT EXACTLY WHY THIS CAN HAPPEN.
    -    reward_withdraw_amount = math::min(reward_withdraw_amount, pool.rewards_pool.value());
    -    pool.rewards_pool.split(reward_withdraw_amount)
    -}
    -
    - - - -
    - - - -## Function `activate_staking_pool` - -Called by validator module to activate a staking pool. - - -
    public(friend) fun activate_staking_pool(pool: &mut staking_pool::StakingPool, activation_epoch: u64)
    -
    - - - -
    -Implementation - - -
    public(package) fun activate_staking_pool(pool: &mut StakingPool, activation_epoch: u64) {
    -    // Add the initial exchange rate to the table.
    -    pool.exchange_rates.add(
    -        activation_epoch,
    -        initial_exchange_rate()
    -    );
    -    // Check that the pool is preactive and not inactive.
    -    assert!(is_preactive(pool), EPoolAlreadyActive);
    -    assert!(!is_inactive(pool), EActivationOfInactivePool);
    -    // Fill in the active epoch.
    -    pool.activation_epoch.fill(activation_epoch);
    -}
    -
    - - - -
    - - - -## Function `deactivate_staking_pool` - -Deactivate a staking pool by setting the deactivation_epoch. After -this pool deactivation, the pool stops earning rewards. Only stake -withdraws can be made to the pool. - - -
    public(friend) fun deactivate_staking_pool(pool: &mut staking_pool::StakingPool, deactivation_epoch: u64)
    -
    - - - -
    -Implementation - - -
    public(package) fun deactivate_staking_pool(pool: &mut StakingPool, deactivation_epoch: u64) {
    -    // We can't deactivate an already deactivated pool.
    -    assert!(!is_inactive(pool), EDeactivationOfInactivePool);
    -    pool.deactivation_epoch = option::some(deactivation_epoch);
    -}
    -
    - - - -
    - - - -## Function `sui_balance` - - - -
    public fun sui_balance(pool: &staking_pool::StakingPool): u64
    -
    - - - -
    -Implementation - - -
    public fun sui_balance(pool: &StakingPool): u64 { pool.sui_balance }
    -
    - - - -
    - - - -## Function `pool_id` - - - -
    public fun pool_id(staked_sui: &staking_pool::StakedSui): object::ID
    -
    - - - -
    -Implementation - - -
    public fun pool_id(staked_sui: &StakedSui): ID { staked_sui.pool_id }
    -
    - - - -
    - - - -## Function `staked_sui_amount` - - - -
    public fun staked_sui_amount(staked_sui: &staking_pool::StakedSui): u64
    -
    - - - -
    -Implementation - - -
    public fun staked_sui_amount(staked_sui: &StakedSui): u64 { staked_sui.principal.value() }
    -
    - - - -
    - - - -## Function `stake_activation_epoch` - - - -
    public fun stake_activation_epoch(staked_sui: &staking_pool::StakedSui): u64
    -
    - - - -
    -Implementation - - -
    public fun stake_activation_epoch(staked_sui: &StakedSui): u64 {
    -    staked_sui.stake_activation_epoch
    -}
    -
    - - - -
    - - - -## Function `is_preactive` - -Returns true if the input staking pool is preactive. - - -
    public fun is_preactive(pool: &staking_pool::StakingPool): bool
    -
    - - - -
    -Implementation - - -
    public fun is_preactive(pool: &StakingPool): bool{
    -    pool.activation_epoch.is_none()
    -}
    -
    - - - -
    - - - -## Function `is_inactive` - -Returns true if the input staking pool is inactive. - - -
    public fun is_inactive(pool: &staking_pool::StakingPool): bool
    -
    - - - -
    -Implementation - - -
    public fun is_inactive(pool: &StakingPool): bool {
    -    pool.deactivation_epoch.is_some()
    -}
    -
    - - - -
    - - - -## Function `split` - -Split StakedSui self to two parts, one with principal split_amount, -and the remaining principal is left in self. -All the other parameters of the StakedSui like stake_activation_epoch or pool_id remain the same. - - -
    public fun split(self: &mut staking_pool::StakedSui, split_amount: u64, ctx: &mut tx_context::TxContext): staking_pool::StakedSui
    -
    - - - -
    -Implementation - - -
    public fun split(self: &mut StakedSui, split_amount: u64, ctx: &mut TxContext): StakedSui {
    -    let original_amount = self.principal.value();
    -    assert!(split_amount <= original_amount, EInsufficientSuiTokenBalance);
    -    let remaining_amount = original_amount - split_amount;
    -    // Both resulting parts should have at least MIN_STAKING_THRESHOLD.
    -    assert!(remaining_amount >= MIN_STAKING_THRESHOLD, EStakedSuiBelowThreshold);
    -    assert!(split_amount >= MIN_STAKING_THRESHOLD, EStakedSuiBelowThreshold);
    -    StakedSui {
    -        id: object::new(ctx),
    -        pool_id: self.pool_id,
    -        stake_activation_epoch: self.stake_activation_epoch,
    -        principal: self.principal.split(split_amount),
    -    }
    -}
    -
    - - - -
    - - - -## Function `split_staked_sui` - -Split the given StakedSui to the two parts, one with principal split_amount, -transfer the newly split part to the sender address. - - -
    public entry fun split_staked_sui(stake: &mut staking_pool::StakedSui, split_amount: u64, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun split_staked_sui(stake: &mut StakedSui, split_amount: u64, ctx: &mut TxContext) {
    -    transfer::transfer(split(stake, split_amount, ctx), ctx.sender());
    -}
    -
    - - - -
    - - - -## Function `join_staked_sui` - -Consume the staked sui other and add its value to self. -Aborts if some of the staking parameters are incompatible (pool id, stake activation epoch, etc.) - - -
    public entry fun join_staked_sui(self: &mut staking_pool::StakedSui, other: staking_pool::StakedSui)
    -
    - - - -
    -Implementation - - -
    public entry fun join_staked_sui(self: &mut StakedSui, other: StakedSui) {
    -    assert!(is_equal_staking_metadata(self, &other), EIncompatibleStakedSui);
    -    let StakedSui {
    -        id,
    -        pool_id: _,
    -        stake_activation_epoch: _,
    -        principal,
    -    } = other;
    -
    -    id.delete();
    -    self.principal.join(principal);
    -}
    -
    - - - -
    - - - -## Function `is_equal_staking_metadata` - -Returns true if all the staking parameters of the staked sui except the principal are identical - - -
    public fun is_equal_staking_metadata(self: &staking_pool::StakedSui, other: &staking_pool::StakedSui): bool
    -
    - - - -
    -Implementation - - -
    public fun is_equal_staking_metadata(self: &StakedSui, other: &StakedSui): bool {
    -    (self.pool_id == other.pool_id) &&
    -    (self.stake_activation_epoch == other.stake_activation_epoch)
    -}
    -
    - - - -
    - - - -## Function `pool_token_exchange_rate_at_epoch` - - - -
    public fun pool_token_exchange_rate_at_epoch(pool: &staking_pool::StakingPool, epoch: u64): staking_pool::PoolTokenExchangeRate
    -
    - - - -
    -Implementation - - -
    public fun pool_token_exchange_rate_at_epoch(pool: &StakingPool, epoch: u64): PoolTokenExchangeRate {
    -    // If the pool is preactive then the exchange rate is always 1:1.
    -    if (is_preactive_at_epoch(pool, epoch)) {
    -        return initial_exchange_rate()
    -    };
    -    let clamped_epoch = pool.deactivation_epoch.get_with_default(epoch);
    -    let mut epoch = math::min(clamped_epoch, epoch);
    -    let activation_epoch = *pool.activation_epoch.borrow();
    -
    -    // Find the latest epoch that's earlier than the given epoch with an entry in the table
    -    while (epoch >= activation_epoch) {
    -        if (pool.exchange_rates.contains(epoch)) {
    -            return pool.exchange_rates[epoch]
    -        };
    -        epoch = epoch - 1;
    -    };
    -    // This line really should be unreachable. Do we want an assert false here?
    -    initial_exchange_rate()
    -}
    -
    - - - -
    - - - -## Function `pending_stake_amount` - -Returns the total value of the pending staking requests for this staking pool. - - -
    public fun pending_stake_amount(staking_pool: &staking_pool::StakingPool): u64
    -
    - - - -
    -Implementation - - -
    public fun pending_stake_amount(staking_pool: &StakingPool): u64 {
    -    staking_pool.pending_stake
    -}
    -
    - - - -
    - - - -## Function `pending_stake_withdraw_amount` - -Returns the total withdrawal from the staking pool this epoch. - - -
    public fun pending_stake_withdraw_amount(staking_pool: &staking_pool::StakingPool): u64
    -
    - - - -
    -Implementation - - -
    public fun pending_stake_withdraw_amount(staking_pool: &StakingPool): u64 {
    -    staking_pool.pending_total_sui_withdraw
    -}
    -
    - - - -
    - - - -## Function `exchange_rates` - - - -
    public(friend) fun exchange_rates(pool: &staking_pool::StakingPool): &table::Table<u64, staking_pool::PoolTokenExchangeRate>
    -
    - - - -
    -Implementation - - -
    public(package) fun exchange_rates(pool: &StakingPool): &Table<u64, PoolTokenExchangeRate> {
    -    &pool.exchange_rates
    -}
    -
    - - - -
    - - - -## Function `sui_amount` - - - -
    public fun sui_amount(exchange_rate: &staking_pool::PoolTokenExchangeRate): u64
    -
    - - - -
    -Implementation - - -
    public fun sui_amount(exchange_rate: &PoolTokenExchangeRate): u64 {
    -    exchange_rate.sui_amount
    -}
    -
    - - - -
    - - - -## Function `pool_token_amount` - - - -
    public fun pool_token_amount(exchange_rate: &staking_pool::PoolTokenExchangeRate): u64
    -
    - - - -
    -Implementation - - -
    public fun pool_token_amount(exchange_rate: &PoolTokenExchangeRate): u64 {
    -    exchange_rate.pool_token_amount
    -}
    -
    - - - -
    - - - -## Function `is_preactive_at_epoch` - -Returns true if the provided staking pool is preactive at the provided epoch. - - -
    fun is_preactive_at_epoch(pool: &staking_pool::StakingPool, epoch: u64): bool
    -
    - - - -
    -Implementation - - -
    fun is_preactive_at_epoch(pool: &StakingPool, epoch: u64): bool{
    -    // Either the pool is currently preactive or the pool's starting epoch is later than the provided epoch.
    -    is_preactive(pool) || (*pool.activation_epoch.borrow() > epoch)
    -}
    -
    - - - -
    - - - -## Function `get_sui_amount` - - - -
    fun get_sui_amount(exchange_rate: &staking_pool::PoolTokenExchangeRate, token_amount: u64): u64
    -
    - - - -
    -Implementation - - -
    fun get_sui_amount(exchange_rate: &PoolTokenExchangeRate, token_amount: u64): u64 {
    -    // When either amount is 0, that means we have no stakes with this pool.
    -    // The other amount might be non-zero when there's dust left in the pool.
    -    if (exchange_rate.sui_amount == 0 || exchange_rate.pool_token_amount == 0) {
    -        return token_amount
    -    };
    -    let res = exchange_rate.sui_amount as u128
    -            * (token_amount as u128)
    -            / (exchange_rate.pool_token_amount as u128);
    -    res as u64
    -}
    -
    - - - -
    - - - -## Function `get_token_amount` - - - -
    fun get_token_amount(exchange_rate: &staking_pool::PoolTokenExchangeRate, sui_amount: u64): u64
    -
    - - - -
    -Implementation - - -
    fun get_token_amount(exchange_rate: &PoolTokenExchangeRate, sui_amount: u64): u64 {
    -    // When either amount is 0, that means we have no stakes with this pool.
    -    // The other amount might be non-zero when there's dust left in the pool.
    -    if (exchange_rate.sui_amount == 0 || exchange_rate.pool_token_amount == 0) {
    -        return sui_amount
    -    };
    -    let res = exchange_rate.pool_token_amount as u128
    -            * (sui_amount as u128)
    -            / (exchange_rate.sui_amount as u128);
    -    res as u64
    -}
    -
    - - - -
    - - - -## Function `initial_exchange_rate` - - - -
    fun initial_exchange_rate(): staking_pool::PoolTokenExchangeRate
    -
    - - - -
    -Implementation - - -
    fun initial_exchange_rate(): PoolTokenExchangeRate {
    -    PoolTokenExchangeRate { sui_amount: 0, pool_token_amount: 0 }
    -}
    -
    - - - -
    - - - -## Function `check_balance_invariants` - - - -
    fun check_balance_invariants(pool: &staking_pool::StakingPool, epoch: u64)
    -
    - - - -
    -Implementation - - -
    fun check_balance_invariants(pool: &StakingPool, epoch: u64) {
    -    let exchange_rate = pool_token_exchange_rate_at_epoch(pool, epoch);
    -    // check that the pool token balance and sui balance ratio matches the exchange rate stored.
    -    let expected = get_token_amount(&exchange_rate, pool.sui_balance);
    -    let actual = pool.pool_token_balance;
    -    assert!(expected == actual, ETokenBalancesDoNotMatchExchangeRate)
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-system/storage_fund.md b/crates/sui-framework/docs/sui-system/storage_fund.md deleted file mode 100644 index f8f05bf62f6..00000000000 --- a/crates/sui-framework/docs/sui-system/storage_fund.md +++ /dev/null @@ -1,187 +0,0 @@ ---- -title: Module `0x3::storage_fund` ---- - - - -- [Struct `StorageFund`](#0x3_storage_fund_StorageFund) -- [Function `new`](#0x3_storage_fund_new) -- [Function `advance_epoch`](#0x3_storage_fund_advance_epoch) -- [Function `total_object_storage_rebates`](#0x3_storage_fund_total_object_storage_rebates) -- [Function `total_balance`](#0x3_storage_fund_total_balance) - - -
    use 0x2::balance;
    -use 0x2::sui;
    -
    - - - - - -## Struct `StorageFund` - -Struct representing the storage fund, containing two Balances: -- total_object_storage_rebates has the invariant that it's the sum of storage_rebate of -all objects currently stored on-chain. To maintain this invariant, the only inflow of this -balance is storage charges collected from transactions, and the only outflow is storage rebates -of transactions, including both the portion refunded to the transaction senders as well as -the non-refundable portion taken out and put into non_refundable_balance. -- non_refundable_balance contains any remaining inflow of the storage fund that should not -be taken out of the fund. - - -
    struct StorageFund has store
    -
    - - - -
    -Fields - - -
    -
    -total_object_storage_rebates: balance::Balance<sui::SUI> -
    -
    - -
    -
    -non_refundable_balance: balance::Balance<sui::SUI> -
    -
    - -
    -
    - - -
    - - - -## Function `new` - -Called by sui_system at genesis time. - - -
    public(friend) fun new(initial_fund: balance::Balance<sui::SUI>): storage_fund::StorageFund
    -
    - - - -
    -Implementation - - -
    public(package) fun new(initial_fund: Balance<SUI>) : StorageFund {
    -    StorageFund {
    -        // At the beginning there's no object in the storage yet
    -        total_object_storage_rebates: balance::zero(),
    -        non_refundable_balance: initial_fund,
    -    }
    -}
    -
    - - - -
    - - - -## Function `advance_epoch` - -Called by sui_system at epoch change times to process the inflows and outflows of storage fund. - - -
    public(friend) fun advance_epoch(self: &mut storage_fund::StorageFund, storage_charges: balance::Balance<sui::SUI>, storage_fund_reinvestment: balance::Balance<sui::SUI>, leftover_staking_rewards: balance::Balance<sui::SUI>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64): balance::Balance<sui::SUI>
    -
    - - - -
    -Implementation - - -
    public(package) fun advance_epoch(
    -    self: &mut StorageFund,
    -    storage_charges: Balance<SUI>,
    -    storage_fund_reinvestment: Balance<SUI>,
    -    leftover_staking_rewards: Balance<SUI>,
    -    storage_rebate_amount: u64,
    -    non_refundable_storage_fee_amount: u64,
    -) : Balance<SUI> {
    -    // Both the reinvestment and leftover rewards are not to be refunded so they go to the non-refundable balance.
    -    self.non_refundable_balance.join(storage_fund_reinvestment);
    -    self.non_refundable_balance.join(leftover_staking_rewards);
    -
    -    // The storage charges for the epoch come from the storage rebate of the new objects created
    -    // and the new storage rebates of the objects modified during the epoch so we put the charges
    -    // into `total_object_storage_rebates`.
    -    self.total_object_storage_rebates.join(storage_charges);
    -
    -    // Split out the non-refundable portion of the storage rebate and put it into the non-refundable balance.
    -    let non_refundable_storage_fee = self.total_object_storage_rebates.split(non_refundable_storage_fee_amount);
    -    self.non_refundable_balance.join(non_refundable_storage_fee);
    -
    -    // `storage_rebates` include the already refunded rebates of deleted objects and old rebates of modified objects and
    -    // should be taken out of the `total_object_storage_rebates`.
    -    let storage_rebate = self.total_object_storage_rebates.split(storage_rebate_amount);
    -
    -    // The storage rebate has already been returned to individual transaction senders' gas coins
    -    // so we return the balance to be burnt at the very end of epoch change.
    -    storage_rebate
    -}
    -
    - - - -
    - - - -## Function `total_object_storage_rebates` - - - -
    public fun total_object_storage_rebates(self: &storage_fund::StorageFund): u64
    -
    - - - -
    -Implementation - - -
    public fun total_object_storage_rebates(self: &StorageFund): u64 {
    -    self.total_object_storage_rebates.value()
    -}
    -
    - - - -
    - - - -## Function `total_balance` - - - -
    public fun total_balance(self: &storage_fund::StorageFund): u64
    -
    - - - -
    -Implementation - - -
    public fun total_balance(self: &StorageFund): u64 {
    -    self.total_object_storage_rebates.value() + self.non_refundable_balance.value()
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-system/sui_system.md b/crates/sui-framework/docs/sui-system/sui_system.md deleted file mode 100644 index cd17b3e160a..00000000000 --- a/crates/sui-framework/docs/sui-system/sui_system.md +++ /dev/null @@ -1,1492 +0,0 @@ ---- -title: Module `0x3::sui_system` ---- - -Sui System State Type Upgrade Guide -SuiSystemState is a thin wrapper around SuiSystemStateInner that provides a versioned interface. -The SuiSystemState object has a fixed ID 0x5, and the SuiSystemStateInner object is stored as a dynamic field. -There are a few different ways to upgrade the SuiSystemStateInner type: - -The simplest and one that doesn't involve a real upgrade is to just add dynamic fields to the extra_fields field -of SuiSystemStateInner or any of its sub type. This is useful when we are in a rush, or making a small change, -or still experimenting a new field. - -To properly upgrade the SuiSystemStateInner type, we need to ship a new framework that does the following: -1. Define a new SuiSystemStateInnertype (e.g. SuiSystemStateInnerV2). -2. Define a data migration function that migrates the old SuiSystemStateInner to the new one (i.e. SuiSystemStateInnerV2). -3. Replace all uses of SuiSystemStateInner with SuiSystemStateInnerV2 in both sui_system.move and sui_system_state_inner.move, -with the exception of the sui_system_state_inner::create function, which should always return the genesis type. -4. Inside load_inner_maybe_upgrade function, check the current version in the wrapper, and if it's not the latest version, -call the data migration function to upgrade the inner object. Make sure to also update the version in the wrapper. -A detailed example can be found in sui/tests/framework_upgrades/mock_sui_systems/shallow_upgrade. -Along with the Move change, we also need to update the Rust code to support the new type. This includes: -1. Define a new SuiSystemStateInner struct type that matches the new Move type, and implement the SuiSystemStateTrait. -2. Update the SuiSystemState struct to include the new version as a new enum variant. -3. Update the get_sui_system_state function to handle the new version. -To test that the upgrade will be successful, we need to modify sui_system_state_production_upgrade_test test in -protocol_version_tests and trigger a real upgrade using the new framework. We will need to keep this directory as old version, -put the new framework in a new directory, and run the test to exercise the upgrade. - -To upgrade Validator type, besides everything above, we also need to: -1. Define a new Validator type (e.g. ValidatorV2). -2. Define a data migration function that migrates the old Validator to the new one (i.e. ValidatorV2). -3. Replace all uses of Validator with ValidatorV2 except the genesis creation function. -4. In validator_wrapper::upgrade_to_latest, check the current version in the wrapper, and if it's not the latest version, -call the data migration function to upgrade it. -In Rust, we also need to add a new case in get_validator_from_table. -Note that it is possible to upgrade SuiSystemStateInner without upgrading Validator, but not the other way around. -And when we only upgrade SuiSystemStateInner, the version of Validator in the wrapper will not be updated, and hence may become -inconsistent with the version of SuiSystemStateInner. This is fine as long as we don't use the Validator version to determine -the SuiSystemStateInner version, or vice versa. - - -- [Resource `SuiSystemState`](#0x3_sui_system_SuiSystemState) -- [Constants](#@Constants_0) -- [Function `create`](#0x3_sui_system_create) -- [Function `request_add_validator_candidate`](#0x3_sui_system_request_add_validator_candidate) -- [Function `request_remove_validator_candidate`](#0x3_sui_system_request_remove_validator_candidate) -- [Function `request_add_validator`](#0x3_sui_system_request_add_validator) -- [Function `request_remove_validator`](#0x3_sui_system_request_remove_validator) -- [Function `request_set_gas_price`](#0x3_sui_system_request_set_gas_price) -- [Function `set_candidate_validator_gas_price`](#0x3_sui_system_set_candidate_validator_gas_price) -- [Function `request_set_commission_rate`](#0x3_sui_system_request_set_commission_rate) -- [Function `set_candidate_validator_commission_rate`](#0x3_sui_system_set_candidate_validator_commission_rate) -- [Function `request_add_stake`](#0x3_sui_system_request_add_stake) -- [Function `request_add_stake_non_entry`](#0x3_sui_system_request_add_stake_non_entry) -- [Function `request_add_stake_mul_coin`](#0x3_sui_system_request_add_stake_mul_coin) -- [Function `request_withdraw_stake`](#0x3_sui_system_request_withdraw_stake) -- [Function `request_withdraw_stake_non_entry`](#0x3_sui_system_request_withdraw_stake_non_entry) -- [Function `report_validator`](#0x3_sui_system_report_validator) -- [Function `undo_report_validator`](#0x3_sui_system_undo_report_validator) -- [Function `rotate_operation_cap`](#0x3_sui_system_rotate_operation_cap) -- [Function `update_validator_name`](#0x3_sui_system_update_validator_name) -- [Function `update_validator_description`](#0x3_sui_system_update_validator_description) -- [Function `update_validator_image_url`](#0x3_sui_system_update_validator_image_url) -- [Function `update_validator_project_url`](#0x3_sui_system_update_validator_project_url) -- [Function `update_validator_next_epoch_network_address`](#0x3_sui_system_update_validator_next_epoch_network_address) -- [Function `update_candidate_validator_network_address`](#0x3_sui_system_update_candidate_validator_network_address) -- [Function `update_validator_next_epoch_p2p_address`](#0x3_sui_system_update_validator_next_epoch_p2p_address) -- [Function `update_candidate_validator_p2p_address`](#0x3_sui_system_update_candidate_validator_p2p_address) -- [Function `update_validator_next_epoch_primary_address`](#0x3_sui_system_update_validator_next_epoch_primary_address) -- [Function `update_candidate_validator_primary_address`](#0x3_sui_system_update_candidate_validator_primary_address) -- [Function `update_validator_next_epoch_worker_address`](#0x3_sui_system_update_validator_next_epoch_worker_address) -- [Function `update_candidate_validator_worker_address`](#0x3_sui_system_update_candidate_validator_worker_address) -- [Function `update_validator_next_epoch_protocol_pubkey`](#0x3_sui_system_update_validator_next_epoch_protocol_pubkey) -- [Function `update_candidate_validator_protocol_pubkey`](#0x3_sui_system_update_candidate_validator_protocol_pubkey) -- [Function `update_validator_next_epoch_worker_pubkey`](#0x3_sui_system_update_validator_next_epoch_worker_pubkey) -- [Function `update_candidate_validator_worker_pubkey`](#0x3_sui_system_update_candidate_validator_worker_pubkey) -- [Function `update_validator_next_epoch_network_pubkey`](#0x3_sui_system_update_validator_next_epoch_network_pubkey) -- [Function `update_candidate_validator_network_pubkey`](#0x3_sui_system_update_candidate_validator_network_pubkey) -- [Function `pool_exchange_rates`](#0x3_sui_system_pool_exchange_rates) -- [Function `active_validator_addresses`](#0x3_sui_system_active_validator_addresses) -- [Function `advance_epoch`](#0x3_sui_system_advance_epoch) -- [Function `load_system_state`](#0x3_sui_system_load_system_state) -- [Function `load_system_state_mut`](#0x3_sui_system_load_system_state_mut) -- [Function `load_inner_maybe_upgrade`](#0x3_sui_system_load_inner_maybe_upgrade) - - -
    use 0x1::option;
    -use 0x2::balance;
    -use 0x2::coin;
    -use 0x2::dynamic_field;
    -use 0x2::object;
    -use 0x2::sui;
    -use 0x2::table;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -use 0x3::stake_subsidy;
    -use 0x3::staking_pool;
    -use 0x3::sui_system_state_inner;
    -use 0x3::validator;
    -use 0x3::validator_cap;
    -
    - - - - - -## Resource `SuiSystemState` - - - -
    struct SuiSystemState has key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -version: u64 -
    -
    - -
    -
    - - -
    - - - -## Constants - - - - - - -
    const ENotSystemAddress: u64 = 0;
    -
    - - - - - - - -
    const EWrongInnerVersion: u64 = 1;
    -
    - - - - - -## Function `create` - -Create a new SuiSystemState object and make it shared. -This function will be called only once in genesis. - - -
    public(friend) fun create(id: object::UID, validators: vector<validator::Validator>, storage_fund: balance::Balance<sui::SUI>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: sui_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun create(
    -    id: UID,
    -    validators: vector<Validator>,
    -    storage_fund: Balance<SUI>,
    -    protocol_version: u64,
    -    epoch_start_timestamp_ms: u64,
    -    parameters: SystemParameters,
    -    stake_subsidy: StakeSubsidy,
    -    ctx: &mut TxContext,
    -) {
    -    let system_state = sui_system_state_inner::create(
    -        validators,
    -        storage_fund,
    -        protocol_version,
    -        epoch_start_timestamp_ms,
    -        parameters,
    -        stake_subsidy,
    -        ctx,
    -    );
    -    let version = sui_system_state_inner::genesis_system_state_version();
    -    let mut self = SuiSystemState {
    -        id,
    -        version,
    -    };
    -    dynamic_field::add(&mut self.id, version, system_state);
    -    transfer::share_object(self);
    -}
    -
    - - - -
    - - - -## Function `request_add_validator_candidate` - -Can be called by anyone who wishes to become a validator candidate and starts accuring delegated -stakes in their staking pool. Once they have at least MIN_VALIDATOR_JOINING_STAKE amount of stake they -can call request_add_validator to officially become an active validator at the next epoch. -Aborts if the caller is already a pending or active validator, or a validator candidate. -Note: proof_of_possession MUST be a valid signature using sui_address and protocol_pubkey_bytes. -To produce a valid PoP, run [fn test_proof_of_possession]. - - -
    public entry fun request_add_validator_candidate(wrapper: &mut sui_system::SuiSystemState, pubkey_bytes: vector<u8>, network_pubkey_bytes: vector<u8>, worker_pubkey_bytes: vector<u8>, proof_of_possession: vector<u8>, name: vector<u8>, description: vector<u8>, image_url: vector<u8>, project_url: vector<u8>, net_address: vector<u8>, p2p_address: vector<u8>, primary_address: vector<u8>, worker_address: vector<u8>, gas_price: u64, commission_rate: u64, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun request_add_validator_candidate(
    -    wrapper: &mut SuiSystemState,
    -    pubkey_bytes: vector<u8>,
    -    network_pubkey_bytes: vector<u8>,
    -    worker_pubkey_bytes: vector<u8>,
    -    proof_of_possession: vector<u8>,
    -    name: vector<u8>,
    -    description: vector<u8>,
    -    image_url: vector<u8>,
    -    project_url: vector<u8>,
    -    net_address: vector<u8>,
    -    p2p_address: vector<u8>,
    -    primary_address: vector<u8>,
    -    worker_address: vector<u8>,
    -    gas_price: u64,
    -    commission_rate: u64,
    -    ctx: &mut TxContext,
    -) {
    -    let self = load_system_state_mut(wrapper);
    -    self.request_add_validator_candidate(
    -        pubkey_bytes,
    -        network_pubkey_bytes,
    -        worker_pubkey_bytes,
    -        proof_of_possession,
    -        name,
    -        description,
    -        image_url,
    -        project_url,
    -        net_address,
    -        p2p_address,
    -        primary_address,
    -        worker_address,
    -        gas_price,
    -        commission_rate,
    -        ctx,
    -    )
    -}
    -
    - - - -
    - - - -## Function `request_remove_validator_candidate` - -Called by a validator candidate to remove themselves from the candidacy. After this call -their staking pool becomes deactivate. - - -
    public entry fun request_remove_validator_candidate(wrapper: &mut sui_system::SuiSystemState, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun request_remove_validator_candidate(
    -    wrapper: &mut SuiSystemState,
    -    ctx: &mut TxContext,
    -) {
    -    let self = load_system_state_mut(wrapper);
    -    self.request_remove_validator_candidate(ctx)
    -}
    -
    - - - -
    - - - -## Function `request_add_validator` - -Called by a validator candidate to add themselves to the active validator set beginning next epoch. -Aborts if the validator is a duplicate with one of the pending or active validators, or if the amount of -stake the validator has doesn't meet the min threshold, or if the number of new validators for the next -epoch has already reached the maximum. - - -
    public entry fun request_add_validator(wrapper: &mut sui_system::SuiSystemState, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun request_add_validator(
    -    wrapper: &mut SuiSystemState,
    -    ctx: &mut TxContext,
    -) {
    -    let self = load_system_state_mut(wrapper);
    -    self.request_add_validator(ctx)
    -}
    -
    - - - -
    - - - -## Function `request_remove_validator` - -A validator can call this function to request a removal in the next epoch. -We use the sender of ctx to look up the validator -(i.e. sender must match the sui_address in the validator). -At the end of the epoch, the validator object will be returned to the sui_address -of the validator. - - -
    public entry fun request_remove_validator(wrapper: &mut sui_system::SuiSystemState, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun request_remove_validator(
    -    wrapper: &mut SuiSystemState,
    -    ctx: &mut TxContext,
    -) {
    -    let self = load_system_state_mut(wrapper);
    -    self.request_remove_validator(ctx)
    -}
    -
    - - - -
    - - - -## Function `request_set_gas_price` - -A validator can call this entry function to submit a new gas price quote, to be -used for the reference gas price calculation at the end of the epoch. - - -
    public entry fun request_set_gas_price(wrapper: &mut sui_system::SuiSystemState, cap: &validator_cap::UnverifiedValidatorOperationCap, new_gas_price: u64)
    -
    - - - -
    -Implementation - - -
    public entry fun request_set_gas_price(
    -    wrapper: &mut SuiSystemState,
    -    cap: &UnverifiedValidatorOperationCap,
    -    new_gas_price: u64,
    -) {
    -    let self = load_system_state_mut(wrapper);
    -    self.request_set_gas_price(cap, new_gas_price)
    -}
    -
    - - - -
    - - - -## Function `set_candidate_validator_gas_price` - -This entry function is used to set new gas price for candidate validators - - -
    public entry fun set_candidate_validator_gas_price(wrapper: &mut sui_system::SuiSystemState, cap: &validator_cap::UnverifiedValidatorOperationCap, new_gas_price: u64)
    -
    - - - -
    -Implementation - - -
    public entry fun set_candidate_validator_gas_price(
    -    wrapper: &mut SuiSystemState,
    -    cap: &UnverifiedValidatorOperationCap,
    -    new_gas_price: u64,
    -) {
    -    let self = load_system_state_mut(wrapper);
    -    self.set_candidate_validator_gas_price(cap, new_gas_price)
    -}
    -
    - - - -
    - - - -## Function `request_set_commission_rate` - -A validator can call this entry function to set a new commission rate, updated at the end of -the epoch. - - -
    public entry fun request_set_commission_rate(wrapper: &mut sui_system::SuiSystemState, new_commission_rate: u64, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun request_set_commission_rate(
    -    wrapper: &mut SuiSystemState,
    -    new_commission_rate: u64,
    -    ctx: &mut TxContext,
    -) {
    -    let self = load_system_state_mut(wrapper);
    -    self.request_set_commission_rate(new_commission_rate, ctx)
    -}
    -
    - - - -
    - - - -## Function `set_candidate_validator_commission_rate` - -This entry function is used to set new commission rate for candidate validators - - -
    public entry fun set_candidate_validator_commission_rate(wrapper: &mut sui_system::SuiSystemState, new_commission_rate: u64, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun set_candidate_validator_commission_rate(
    -    wrapper: &mut SuiSystemState,
    -    new_commission_rate: u64,
    -    ctx: &mut TxContext,
    -) {
    -    let self = load_system_state_mut(wrapper);
    -    self.set_candidate_validator_commission_rate(new_commission_rate, ctx)
    -}
    -
    - - - -
    - - - -## Function `request_add_stake` - -Add stake to a validator's staking pool. - - -
    public entry fun request_add_stake(wrapper: &mut sui_system::SuiSystemState, stake: coin::Coin<sui::SUI>, validator_address: address, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun request_add_stake(
    -    wrapper: &mut SuiSystemState,
    -    stake: Coin<SUI>,
    -    validator_address: address,
    -    ctx: &mut TxContext,
    -) {
    -    let staked_sui = request_add_stake_non_entry(wrapper, stake, validator_address, ctx);
    -    transfer::public_transfer(staked_sui, ctx.sender());
    -}
    -
    - - - -
    - - - -## Function `request_add_stake_non_entry` - -The non-entry version of request_add_stake, which returns the staked SUI instead of transferring it to the sender. - - -
    public fun request_add_stake_non_entry(wrapper: &mut sui_system::SuiSystemState, stake: coin::Coin<sui::SUI>, validator_address: address, ctx: &mut tx_context::TxContext): staking_pool::StakedSui
    -
    - - - -
    -Implementation - - -
    public fun request_add_stake_non_entry(
    -    wrapper: &mut SuiSystemState,
    -    stake: Coin<SUI>,
    -    validator_address: address,
    -    ctx: &mut TxContext,
    -): StakedSui {
    -    let self = load_system_state_mut(wrapper);
    -    self.request_add_stake(stake, validator_address, ctx)
    -}
    -
    - - - -
    - - - -## Function `request_add_stake_mul_coin` - -Add stake to a validator's staking pool using multiple coins. - - -
    public entry fun request_add_stake_mul_coin(wrapper: &mut sui_system::SuiSystemState, stakes: vector<coin::Coin<sui::SUI>>, stake_amount: option::Option<u64>, validator_address: address, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun request_add_stake_mul_coin(
    -    wrapper: &mut SuiSystemState,
    -    stakes: vector<Coin<SUI>>,
    -    stake_amount: option::Option<u64>,
    -    validator_address: address,
    -    ctx: &mut TxContext,
    -) {
    -    let self = load_system_state_mut(wrapper);
    -    let staked_sui = self.request_add_stake_mul_coin(stakes, stake_amount, validator_address, ctx);
    -    transfer::public_transfer(staked_sui, ctx.sender());
    -}
    -
    - - - -
    - - - -## Function `request_withdraw_stake` - -Withdraw stake from a validator's staking pool. - - -
    public entry fun request_withdraw_stake(wrapper: &mut sui_system::SuiSystemState, staked_sui: staking_pool::StakedSui, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun request_withdraw_stake(
    -    wrapper: &mut SuiSystemState,
    -    staked_sui: StakedSui,
    -    ctx: &mut TxContext,
    -) {
    -    let withdrawn_stake = request_withdraw_stake_non_entry(wrapper, staked_sui, ctx);
    -    transfer::public_transfer(withdrawn_stake.into_coin(ctx), ctx.sender());
    -}
    -
    - - - -
    - - - -## Function `request_withdraw_stake_non_entry` - -Non-entry version of request_withdraw_stake that returns the withdrawn SUI instead of transferring it to the sender. - - -
    public fun request_withdraw_stake_non_entry(wrapper: &mut sui_system::SuiSystemState, staked_sui: staking_pool::StakedSui, ctx: &mut tx_context::TxContext): balance::Balance<sui::SUI>
    -
    - - - -
    -Implementation - - -
    public fun request_withdraw_stake_non_entry(
    -    wrapper: &mut SuiSystemState,
    -    staked_sui: StakedSui,
    -    ctx: &mut TxContext,
    -) : Balance<SUI> {
    -    let self = load_system_state_mut(wrapper);
    -    self.request_withdraw_stake(staked_sui, ctx)
    -}
    -
    - - - -
    - - - -## Function `report_validator` - -Report a validator as a bad or non-performant actor in the system. -Succeeds if all the following are satisfied: -1. both the reporter in cap and the input reportee_addr are active validators. -2. reporter and reportee not the same address. -3. the cap object is still valid. -This function is idempotent. - - -
    public entry fun report_validator(wrapper: &mut sui_system::SuiSystemState, cap: &validator_cap::UnverifiedValidatorOperationCap, reportee_addr: address)
    -
    - - - -
    -Implementation - - -
    public entry fun report_validator(
    -    wrapper: &mut SuiSystemState,
    -    cap: &UnverifiedValidatorOperationCap,
    -    reportee_addr: address,
    -) {
    -    let self = load_system_state_mut(wrapper);
    -    self.report_validator(cap, reportee_addr)
    -}
    -
    - - - -
    - - - -## Function `undo_report_validator` - -Undo a report_validator action. Aborts if -1. the reportee is not a currently active validator or -2. the sender has not previously reported the reportee_addr, or -3. the cap is not valid - - -
    public entry fun undo_report_validator(wrapper: &mut sui_system::SuiSystemState, cap: &validator_cap::UnverifiedValidatorOperationCap, reportee_addr: address)
    -
    - - - -
    -Implementation - - -
    public entry fun undo_report_validator(
    -    wrapper: &mut SuiSystemState,
    -    cap: &UnverifiedValidatorOperationCap,
    -    reportee_addr: address,
    -) {
    -    let self = load_system_state_mut(wrapper);
    -    self.undo_report_validator(cap, reportee_addr)
    -}
    -
    - - - -
    - - - -## Function `rotate_operation_cap` - -Create a new UnverifiedValidatorOperationCap, transfer it to the -validator and registers it. The original object is thus revoked. - - -
    public entry fun rotate_operation_cap(self: &mut sui_system::SuiSystemState, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun rotate_operation_cap(
    -    self: &mut SuiSystemState,
    -    ctx: &mut TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.rotate_operation_cap(ctx)
    -}
    -
    - - - -
    - - - -## Function `update_validator_name` - -Update a validator's name. - - -
    public entry fun update_validator_name(self: &mut sui_system::SuiSystemState, name: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_validator_name(
    -    self: &mut SuiSystemState,
    -    name: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_validator_name(name, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_validator_description` - -Update a validator's description - - -
    public entry fun update_validator_description(self: &mut sui_system::SuiSystemState, description: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_validator_description(
    -    self: &mut SuiSystemState,
    -    description: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_validator_description(description, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_validator_image_url` - -Update a validator's image url - - -
    public entry fun update_validator_image_url(self: &mut sui_system::SuiSystemState, image_url: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_validator_image_url(
    -    self: &mut SuiSystemState,
    -    image_url: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_validator_image_url(image_url, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_validator_project_url` - -Update a validator's project url - - -
    public entry fun update_validator_project_url(self: &mut sui_system::SuiSystemState, project_url: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_validator_project_url(
    -    self: &mut SuiSystemState,
    -    project_url: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_validator_project_url(project_url, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_validator_next_epoch_network_address` - -Update a validator's network address. -The change will only take effects starting from the next epoch. - - -
    public entry fun update_validator_next_epoch_network_address(self: &mut sui_system::SuiSystemState, network_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_validator_next_epoch_network_address(
    -    self: &mut SuiSystemState,
    -    network_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_validator_next_epoch_network_address(network_address, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_candidate_validator_network_address` - -Update candidate validator's network address. - - -
    public entry fun update_candidate_validator_network_address(self: &mut sui_system::SuiSystemState, network_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_candidate_validator_network_address(
    -    self: &mut SuiSystemState,
    -    network_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_candidate_validator_network_address(network_address, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_validator_next_epoch_p2p_address` - -Update a validator's p2p address. -The change will only take effects starting from the next epoch. - - -
    public entry fun update_validator_next_epoch_p2p_address(self: &mut sui_system::SuiSystemState, p2p_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_validator_next_epoch_p2p_address(
    -    self: &mut SuiSystemState,
    -    p2p_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_validator_next_epoch_p2p_address(p2p_address, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_candidate_validator_p2p_address` - -Update candidate validator's p2p address. - - -
    public entry fun update_candidate_validator_p2p_address(self: &mut sui_system::SuiSystemState, p2p_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_candidate_validator_p2p_address(
    -    self: &mut SuiSystemState,
    -    p2p_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_candidate_validator_p2p_address(p2p_address, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_validator_next_epoch_primary_address` - -Update a validator's narwhal primary address. -The change will only take effects starting from the next epoch. - - -
    public entry fun update_validator_next_epoch_primary_address(self: &mut sui_system::SuiSystemState, primary_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_validator_next_epoch_primary_address(
    -    self: &mut SuiSystemState,
    -    primary_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_validator_next_epoch_primary_address(primary_address, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_candidate_validator_primary_address` - -Update candidate validator's narwhal primary address. - - -
    public entry fun update_candidate_validator_primary_address(self: &mut sui_system::SuiSystemState, primary_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_candidate_validator_primary_address(
    -    self: &mut SuiSystemState,
    -    primary_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_candidate_validator_primary_address(primary_address, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_validator_next_epoch_worker_address` - -Update a validator's narwhal worker address. -The change will only take effects starting from the next epoch. - - -
    public entry fun update_validator_next_epoch_worker_address(self: &mut sui_system::SuiSystemState, worker_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_validator_next_epoch_worker_address(
    -    self: &mut SuiSystemState,
    -    worker_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_validator_next_epoch_worker_address(worker_address, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_candidate_validator_worker_address` - -Update candidate validator's narwhal worker address. - - -
    public entry fun update_candidate_validator_worker_address(self: &mut sui_system::SuiSystemState, worker_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_candidate_validator_worker_address(
    -    self: &mut SuiSystemState,
    -    worker_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_candidate_validator_worker_address(worker_address, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_validator_next_epoch_protocol_pubkey` - -Update a validator's public key of protocol key and proof of possession. -The change will only take effects starting from the next epoch. - - -
    public entry fun update_validator_next_epoch_protocol_pubkey(self: &mut sui_system::SuiSystemState, protocol_pubkey: vector<u8>, proof_of_possession: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_validator_next_epoch_protocol_pubkey(
    -    self: &mut SuiSystemState,
    -    protocol_pubkey: vector<u8>,
    -    proof_of_possession: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_validator_next_epoch_protocol_pubkey(protocol_pubkey, proof_of_possession, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_candidate_validator_protocol_pubkey` - -Update candidate validator's public key of protocol key and proof of possession. - - -
    public entry fun update_candidate_validator_protocol_pubkey(self: &mut sui_system::SuiSystemState, protocol_pubkey: vector<u8>, proof_of_possession: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_candidate_validator_protocol_pubkey(
    -    self: &mut SuiSystemState,
    -    protocol_pubkey: vector<u8>,
    -    proof_of_possession: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_candidate_validator_protocol_pubkey(protocol_pubkey, proof_of_possession, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_validator_next_epoch_worker_pubkey` - -Update a validator's public key of worker key. -The change will only take effects starting from the next epoch. - - -
    public entry fun update_validator_next_epoch_worker_pubkey(self: &mut sui_system::SuiSystemState, worker_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_validator_next_epoch_worker_pubkey(
    -    self: &mut SuiSystemState,
    -    worker_pubkey: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_validator_next_epoch_worker_pubkey(worker_pubkey, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_candidate_validator_worker_pubkey` - -Update candidate validator's public key of worker key. - - -
    public entry fun update_candidate_validator_worker_pubkey(self: &mut sui_system::SuiSystemState, worker_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_candidate_validator_worker_pubkey(
    -    self: &mut SuiSystemState,
    -    worker_pubkey: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_candidate_validator_worker_pubkey(worker_pubkey, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_validator_next_epoch_network_pubkey` - -Update a validator's public key of network key. -The change will only take effects starting from the next epoch. - - -
    public entry fun update_validator_next_epoch_network_pubkey(self: &mut sui_system::SuiSystemState, network_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_validator_next_epoch_network_pubkey(
    -    self: &mut SuiSystemState,
    -    network_pubkey: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_validator_next_epoch_network_pubkey(network_pubkey, ctx)
    -}
    -
    - - - -
    - - - -## Function `update_candidate_validator_network_pubkey` - -Update candidate validator's public key of network key. - - -
    public entry fun update_candidate_validator_network_pubkey(self: &mut sui_system::SuiSystemState, network_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun update_candidate_validator_network_pubkey(
    -    self: &mut SuiSystemState,
    -    network_pubkey: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let self = load_system_state_mut(self);
    -    self.update_candidate_validator_network_pubkey(network_pubkey, ctx)
    -}
    -
    - - - -
    - - - -## Function `pool_exchange_rates` - -Getter of the pool token exchange rate of a staking pool. Works for both active and inactive pools. - - -
    public fun pool_exchange_rates(wrapper: &mut sui_system::SuiSystemState, pool_id: &object::ID): &table::Table<u64, staking_pool::PoolTokenExchangeRate>
    -
    - - - -
    -Implementation - - -
    public fun pool_exchange_rates(
    -    wrapper: &mut SuiSystemState,
    -    pool_id: &ID
    -): &Table<u64, PoolTokenExchangeRate>  {
    -    let self = load_system_state_mut(wrapper);
    -    self.pool_exchange_rates(pool_id)
    -}
    -
    - - - -
    - - - -## Function `active_validator_addresses` - -Getter returning addresses of the currently active validators. - - -
    public fun active_validator_addresses(wrapper: &mut sui_system::SuiSystemState): vector<address>
    -
    - - - -
    -Implementation - - -
    public fun active_validator_addresses(wrapper: &mut SuiSystemState): vector<address> {
    -    let self = load_system_state(wrapper);
    -    self.active_validator_addresses()
    -}
    -
    - - - -
    - - - -## Function `advance_epoch` - -This function should be called at the end of an epoch, and advances the system to the next epoch. -It does the following things: -1. Add storage charge to the storage fund. -2. Burn the storage rebates from the storage fund. These are already refunded to transaction sender's -gas coins. -3. Distribute computation charge to validator stake. -4. Update all validators. - - -
    fun advance_epoch(storage_reward: balance::Balance<sui::SUI>, computation_reward: balance::Balance<sui::SUI>, wrapper: &mut sui_system::SuiSystemState, new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<sui::SUI>
    -
    - - - -
    -Implementation - - -
    fun advance_epoch(
    -    storage_reward: Balance<SUI>,
    -    computation_reward: Balance<SUI>,
    -    wrapper: &mut SuiSystemState,
    -    new_epoch: u64,
    -    next_protocol_version: u64,
    -    storage_rebate: u64,
    -    non_refundable_storage_fee: u64,
    -    storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested
    -                                     // into storage fund, in basis point.
    -    reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps.
    -    epoch_start_timestamp_ms: u64, // Timestamp of the epoch start
    -    ctx: &mut TxContext,
    -) : Balance<SUI> {
    -    let self = load_system_state_mut(wrapper);
    -    // Validator will make a special system call with sender set as 0x0.
    -    assert!(ctx.sender() == @0x0, ENotSystemAddress);
    -    let storage_rebate = self.advance_epoch(
    -        new_epoch,
    -        next_protocol_version,
    -        storage_reward,
    -        computation_reward,
    -        storage_rebate,
    -        non_refundable_storage_fee,
    -        storage_fund_reinvest_rate,
    -        reward_slashing_rate,
    -        epoch_start_timestamp_ms,
    -        ctx,
    -    );
    -
    -    storage_rebate
    -}
    -
    - - - -
    - - - -## Function `load_system_state` - - - -
    fun load_system_state(self: &mut sui_system::SuiSystemState): &sui_system_state_inner::SuiSystemStateInnerV2
    -
    - - - -
    -Implementation - - -
    fun load_system_state(self: &mut SuiSystemState): &SuiSystemStateInnerV2 {
    -    load_inner_maybe_upgrade(self)
    -}
    -
    - - - -
    - - - -## Function `load_system_state_mut` - - - -
    fun load_system_state_mut(self: &mut sui_system::SuiSystemState): &mut sui_system_state_inner::SuiSystemStateInnerV2
    -
    - - - -
    -Implementation - - -
    fun load_system_state_mut(self: &mut SuiSystemState): &mut SuiSystemStateInnerV2 {
    -    load_inner_maybe_upgrade(self)
    -}
    -
    - - - -
    - - - -## Function `load_inner_maybe_upgrade` - - - -
    fun load_inner_maybe_upgrade(self: &mut sui_system::SuiSystemState): &mut sui_system_state_inner::SuiSystemStateInnerV2
    -
    - - - -
    -Implementation - - -
    fun load_inner_maybe_upgrade(self: &mut SuiSystemState): &mut SuiSystemStateInnerV2 {
    -    if (self.version == 1) {
    -      let v1: SuiSystemStateInner = dynamic_field::remove(&mut self.id, self.version);
    -      let v2 = v1.v1_to_v2();
    -      self.version = 2;
    -      dynamic_field::add(&mut self.id, self.version, v2);
    -    };
    -
    -    let inner: &mut SuiSystemStateInnerV2 = dynamic_field::borrow_mut(
    -        &mut self.id,
    -        self.version
    -    );
    -    assert!(inner.system_state_version() == self.version, EWrongInnerVersion);
    -    inner
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/sui-system/sui_system_state_inner.md b/crates/sui-framework/docs/sui-system/sui_system_state_inner.md deleted file mode 100644 index 100edbd3a78..00000000000 --- a/crates/sui-framework/docs/sui-system/sui_system_state_inner.md +++ /dev/null @@ -1,2597 +0,0 @@ ---- -title: Module `0x3::sui_system_state_inner` ---- - - - -- [Struct `SystemParameters`](#0x3_sui_system_state_inner_SystemParameters) -- [Struct `SystemParametersV2`](#0x3_sui_system_state_inner_SystemParametersV2) -- [Struct `SuiSystemStateInner`](#0x3_sui_system_state_inner_SuiSystemStateInner) -- [Struct `SuiSystemStateInnerV2`](#0x3_sui_system_state_inner_SuiSystemStateInnerV2) -- [Struct `SystemEpochInfoEvent`](#0x3_sui_system_state_inner_SystemEpochInfoEvent) -- [Constants](#@Constants_0) -- [Function `create`](#0x3_sui_system_state_inner_create) -- [Function `create_system_parameters`](#0x3_sui_system_state_inner_create_system_parameters) -- [Function `v1_to_v2`](#0x3_sui_system_state_inner_v1_to_v2) -- [Function `request_add_validator_candidate`](#0x3_sui_system_state_inner_request_add_validator_candidate) -- [Function `request_remove_validator_candidate`](#0x3_sui_system_state_inner_request_remove_validator_candidate) -- [Function `request_add_validator`](#0x3_sui_system_state_inner_request_add_validator) -- [Function `request_remove_validator`](#0x3_sui_system_state_inner_request_remove_validator) -- [Function `request_set_gas_price`](#0x3_sui_system_state_inner_request_set_gas_price) -- [Function `set_candidate_validator_gas_price`](#0x3_sui_system_state_inner_set_candidate_validator_gas_price) -- [Function `request_set_commission_rate`](#0x3_sui_system_state_inner_request_set_commission_rate) -- [Function `set_candidate_validator_commission_rate`](#0x3_sui_system_state_inner_set_candidate_validator_commission_rate) -- [Function `request_add_stake`](#0x3_sui_system_state_inner_request_add_stake) -- [Function `request_add_stake_mul_coin`](#0x3_sui_system_state_inner_request_add_stake_mul_coin) -- [Function `request_withdraw_stake`](#0x3_sui_system_state_inner_request_withdraw_stake) -- [Function `report_validator`](#0x3_sui_system_state_inner_report_validator) -- [Function `undo_report_validator`](#0x3_sui_system_state_inner_undo_report_validator) -- [Function `report_validator_impl`](#0x3_sui_system_state_inner_report_validator_impl) -- [Function `undo_report_validator_impl`](#0x3_sui_system_state_inner_undo_report_validator_impl) -- [Function `rotate_operation_cap`](#0x3_sui_system_state_inner_rotate_operation_cap) -- [Function `update_validator_name`](#0x3_sui_system_state_inner_update_validator_name) -- [Function `update_validator_description`](#0x3_sui_system_state_inner_update_validator_description) -- [Function `update_validator_image_url`](#0x3_sui_system_state_inner_update_validator_image_url) -- [Function `update_validator_project_url`](#0x3_sui_system_state_inner_update_validator_project_url) -- [Function `update_validator_next_epoch_network_address`](#0x3_sui_system_state_inner_update_validator_next_epoch_network_address) -- [Function `update_candidate_validator_network_address`](#0x3_sui_system_state_inner_update_candidate_validator_network_address) -- [Function `update_validator_next_epoch_p2p_address`](#0x3_sui_system_state_inner_update_validator_next_epoch_p2p_address) -- [Function `update_candidate_validator_p2p_address`](#0x3_sui_system_state_inner_update_candidate_validator_p2p_address) -- [Function `update_validator_next_epoch_primary_address`](#0x3_sui_system_state_inner_update_validator_next_epoch_primary_address) -- [Function `update_candidate_validator_primary_address`](#0x3_sui_system_state_inner_update_candidate_validator_primary_address) -- [Function `update_validator_next_epoch_worker_address`](#0x3_sui_system_state_inner_update_validator_next_epoch_worker_address) -- [Function `update_candidate_validator_worker_address`](#0x3_sui_system_state_inner_update_candidate_validator_worker_address) -- [Function `update_validator_next_epoch_protocol_pubkey`](#0x3_sui_system_state_inner_update_validator_next_epoch_protocol_pubkey) -- [Function `update_candidate_validator_protocol_pubkey`](#0x3_sui_system_state_inner_update_candidate_validator_protocol_pubkey) -- [Function `update_validator_next_epoch_worker_pubkey`](#0x3_sui_system_state_inner_update_validator_next_epoch_worker_pubkey) -- [Function `update_candidate_validator_worker_pubkey`](#0x3_sui_system_state_inner_update_candidate_validator_worker_pubkey) -- [Function `update_validator_next_epoch_network_pubkey`](#0x3_sui_system_state_inner_update_validator_next_epoch_network_pubkey) -- [Function `update_candidate_validator_network_pubkey`](#0x3_sui_system_state_inner_update_candidate_validator_network_pubkey) -- [Function `advance_epoch`](#0x3_sui_system_state_inner_advance_epoch) -- [Function `epoch`](#0x3_sui_system_state_inner_epoch) -- [Function `protocol_version`](#0x3_sui_system_state_inner_protocol_version) -- [Function `system_state_version`](#0x3_sui_system_state_inner_system_state_version) -- [Function `genesis_system_state_version`](#0x3_sui_system_state_inner_genesis_system_state_version) -- [Function `epoch_start_timestamp_ms`](#0x3_sui_system_state_inner_epoch_start_timestamp_ms) -- [Function `validator_stake_amount`](#0x3_sui_system_state_inner_validator_stake_amount) -- [Function `validator_staking_pool_id`](#0x3_sui_system_state_inner_validator_staking_pool_id) -- [Function `validator_staking_pool_mappings`](#0x3_sui_system_state_inner_validator_staking_pool_mappings) -- [Function `get_reporters_of`](#0x3_sui_system_state_inner_get_reporters_of) -- [Function `get_storage_fund_total_balance`](#0x3_sui_system_state_inner_get_storage_fund_total_balance) -- [Function `get_storage_fund_object_rebates`](#0x3_sui_system_state_inner_get_storage_fund_object_rebates) -- [Function `pool_exchange_rates`](#0x3_sui_system_state_inner_pool_exchange_rates) -- [Function `active_validator_addresses`](#0x3_sui_system_state_inner_active_validator_addresses) -- [Function `extract_coin_balance`](#0x3_sui_system_state_inner_extract_coin_balance) - - -
    use 0x1::option;
    -use 0x2::bag;
    -use 0x2::balance;
    -use 0x2::coin;
    -use 0x2::event;
    -use 0x2::object;
    -use 0x2::pay;
    -use 0x2::sui;
    -use 0x2::table;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -use 0x2::vec_map;
    -use 0x2::vec_set;
    -use 0x3::stake_subsidy;
    -use 0x3::staking_pool;
    -use 0x3::storage_fund;
    -use 0x3::validator;
    -use 0x3::validator_cap;
    -use 0x3::validator_set;
    -
    - - - - - -## Struct `SystemParameters` - -A list of system config parameters. - - -
    struct SystemParameters has store
    -
    - - - -
    -Fields - - -
    -
    -epoch_duration_ms: u64 -
    -
    - The duration of an epoch, in milliseconds. -
    -
    -stake_subsidy_start_epoch: u64 -
    -
    - The starting epoch in which stake subsidies start being paid out -
    -
    -max_validator_count: u64 -
    -
    - Maximum number of active validators at any moment. - We do not allow the number of validators in any epoch to go above this. -
    -
    -min_validator_joining_stake: u64 -
    -
    - Lower-bound on the amount of stake required to become a validator. -
    -
    -validator_low_stake_threshold: u64 -
    -
    - Validators with stake amount below validator_low_stake_threshold are considered to - have low stake and will be escorted out of the validator set after being below this - threshold for more than validator_low_stake_grace_period number of epochs. -
    -
    -validator_very_low_stake_threshold: u64 -
    -
    - Validators with stake below validator_very_low_stake_threshold will be removed - immediately at epoch change, no grace period. -
    -
    -validator_low_stake_grace_period: u64 -
    -
    - A validator can have stake below validator_low_stake_threshold - for this many epochs before being kicked out. -
    -
    -extra_fields: bag::Bag -
    -
    - Any extra fields that's not defined statically. -
    -
    - - -
    - - - -## Struct `SystemParametersV2` - -Added min_validator_count. - - -
    struct SystemParametersV2 has store
    -
    - - - -
    -Fields - - -
    -
    -epoch_duration_ms: u64 -
    -
    - The duration of an epoch, in milliseconds. -
    -
    -stake_subsidy_start_epoch: u64 -
    -
    - The starting epoch in which stake subsidies start being paid out -
    -
    -min_validator_count: u64 -
    -
    - Minimum number of active validators at any moment. -
    -
    -max_validator_count: u64 -
    -
    - Maximum number of active validators at any moment. - We do not allow the number of validators in any epoch to go above this. -
    -
    -min_validator_joining_stake: u64 -
    -
    - Lower-bound on the amount of stake required to become a validator. -
    -
    -validator_low_stake_threshold: u64 -
    -
    - Validators with stake amount below validator_low_stake_threshold are considered to - have low stake and will be escorted out of the validator set after being below this - threshold for more than validator_low_stake_grace_period number of epochs. -
    -
    -validator_very_low_stake_threshold: u64 -
    -
    - Validators with stake below validator_very_low_stake_threshold will be removed - immediately at epoch change, no grace period. -
    -
    -validator_low_stake_grace_period: u64 -
    -
    - A validator can have stake below validator_low_stake_threshold - for this many epochs before being kicked out. -
    -
    -extra_fields: bag::Bag -
    -
    - Any extra fields that's not defined statically. -
    -
    - - -
    - - - -## Struct `SuiSystemStateInner` - -The top-level object containing all information of the Sui system. - - -
    struct SuiSystemStateInner has store
    -
    - - - -
    -Fields - - -
    -
    -epoch: u64 -
    -
    - The current epoch ID, starting from 0. -
    -
    -protocol_version: u64 -
    -
    - The current protocol version, starting from 1. -
    -
    -system_state_version: u64 -
    -
    - The current version of the system state data structure type. - This is always the same as SuiSystemState.version. Keeping a copy here so that - we know what version it is by inspecting SuiSystemStateInner as well. -
    -
    -validators: validator_set::ValidatorSet -
    -
    - Contains all information about the validators. -
    -
    -storage_fund: storage_fund::StorageFund -
    -
    - The storage fund. -
    -
    -parameters: sui_system_state_inner::SystemParameters -
    -
    - A list of system config parameters. -
    -
    -reference_gas_price: u64 -
    -
    - The reference gas price for the current epoch. -
    -
    -validator_report_records: vec_map::VecMap<address, vec_set::VecSet<address>> -
    -
    - A map storing the records of validator reporting each other. - There is an entry in the map for each validator that has been reported - at least once. The entry VecSet contains all the validators that reported - them. If a validator has never been reported they don't have an entry in this map. - This map persists across epoch: a peer continues being in a reported state until the - reporter doesn't explicitly remove their report. - Note that in case we want to support validator address change in future, - the reports should be based on validator ids -
    -
    -stake_subsidy: stake_subsidy::StakeSubsidy -
    -
    - Schedule of stake subsidies given out each epoch. -
    -
    -safe_mode: bool -
    -
    - Whether the system is running in a downgraded safe mode due to a non-recoverable bug. - This is set whenever we failed to execute advance_epoch, and ended up executing advance_epoch_safe_mode. - It can be reset once we are able to successfully execute advance_epoch. - The rest of the fields starting with safe_mode_ are accmulated during safe mode - when advance_epoch_safe_mode is executed. They will eventually be processed once we - are out of safe mode. -
    -
    -safe_mode_storage_rewards: balance::Balance<sui::SUI> -
    -
    - -
    -
    -safe_mode_computation_rewards: balance::Balance<sui::SUI> -
    -
    - -
    -
    -safe_mode_storage_rebates: u64 -
    -
    - -
    -
    -safe_mode_non_refundable_storage_fee: u64 -
    -
    - -
    -
    -epoch_start_timestamp_ms: u64 -
    -
    - Unix timestamp of the current epoch start -
    -
    -extra_fields: bag::Bag -
    -
    - Any extra fields that's not defined statically. -
    -
    - - -
    - - - -## Struct `SuiSystemStateInnerV2` - -Uses SystemParametersV2 as the parameters. - - -
    struct SuiSystemStateInnerV2 has store
    -
    - - - -
    -Fields - - -
    -
    -epoch: u64 -
    -
    - The current epoch ID, starting from 0. -
    -
    -protocol_version: u64 -
    -
    - The current protocol version, starting from 1. -
    -
    -system_state_version: u64 -
    -
    - The current version of the system state data structure type. - This is always the same as SuiSystemState.version. Keeping a copy here so that - we know what version it is by inspecting SuiSystemStateInner as well. -
    -
    -validators: validator_set::ValidatorSet -
    -
    - Contains all information about the validators. -
    -
    -storage_fund: storage_fund::StorageFund -
    -
    - The storage fund. -
    -
    -parameters: sui_system_state_inner::SystemParametersV2 -
    -
    - A list of system config parameters. -
    -
    -reference_gas_price: u64 -
    -
    - The reference gas price for the current epoch. -
    -
    -validator_report_records: vec_map::VecMap<address, vec_set::VecSet<address>> -
    -
    - A map storing the records of validator reporting each other. - There is an entry in the map for each validator that has been reported - at least once. The entry VecSet contains all the validators that reported - them. If a validator has never been reported they don't have an entry in this map. - This map persists across epoch: a peer continues being in a reported state until the - reporter doesn't explicitly remove their report. - Note that in case we want to support validator address change in future, - the reports should be based on validator ids -
    -
    -stake_subsidy: stake_subsidy::StakeSubsidy -
    -
    - Schedule of stake subsidies given out each epoch. -
    -
    -safe_mode: bool -
    -
    - Whether the system is running in a downgraded safe mode due to a non-recoverable bug. - This is set whenever we failed to execute advance_epoch, and ended up executing advance_epoch_safe_mode. - It can be reset once we are able to successfully execute advance_epoch. - The rest of the fields starting with safe_mode_ are accmulated during safe mode - when advance_epoch_safe_mode is executed. They will eventually be processed once we - are out of safe mode. -
    -
    -safe_mode_storage_rewards: balance::Balance<sui::SUI> -
    -
    - -
    -
    -safe_mode_computation_rewards: balance::Balance<sui::SUI> -
    -
    - -
    -
    -safe_mode_storage_rebates: u64 -
    -
    - -
    -
    -safe_mode_non_refundable_storage_fee: u64 -
    -
    - -
    -
    -epoch_start_timestamp_ms: u64 -
    -
    - Unix timestamp of the current epoch start -
    -
    -extra_fields: bag::Bag -
    -
    - Any extra fields that's not defined statically. -
    -
    - - -
    - - - -## Struct `SystemEpochInfoEvent` - -Event containing system-level epoch information, emitted during -the epoch advancement transaction. - - -
    struct SystemEpochInfoEvent has copy, drop
    -
    - - - -
    -Fields - - -
    -
    -epoch: u64 -
    -
    - -
    -
    -protocol_version: u64 -
    -
    - -
    -
    -reference_gas_price: u64 -
    -
    - -
    -
    -total_stake: u64 -
    -
    - -
    -
    -storage_fund_reinvestment: u64 -
    -
    - -
    -
    -storage_charge: u64 -
    -
    - -
    -
    -storage_rebate: u64 -
    -
    - -
    -
    -storage_fund_balance: u64 -
    -
    - -
    -
    -stake_subsidy_amount: u64 -
    -
    - -
    -
    -total_gas_fees: u64 -
    -
    - -
    -
    -total_stake_rewards_distributed: u64 -
    -
    - -
    -
    -leftover_storage_fund_inflow: u64 -
    -
    - -
    -
    - - -
    - - - -## Constants - - - - - - -
    const ENotSystemAddress: u64 = 2;
    -
    - - - - - - - -
    const ACTIVE_OR_PENDING_VALIDATOR: u8 = 2;
    -
    - - - - - - - -
    const ACTIVE_VALIDATOR_ONLY: u8 = 1;
    -
    - - - - - - - -
    const ANY_VALIDATOR: u8 = 3;
    -
    - - - - - - - -
    const BASIS_POINT_DENOMINATOR: u128 = 10000;
    -
    - - - - - - - -
    const EAdvancedToWrongEpoch: u64 = 8;
    -
    - - - - - - - -
    const EBpsTooLarge: u64 = 5;
    -
    - - - - - - - -
    const ECannotReportOneself: u64 = 3;
    -
    - - - - - - - -
    const ELimitExceeded: u64 = 1;
    -
    - - - - - - - -
    const ENotValidator: u64 = 0;
    -
    - - - - - - - -
    const EReportRecordNotFound: u64 = 4;
    -
    - - - - - - - -
    const ESafeModeGasNotProcessed: u64 = 7;
    -
    - - - - - - - -
    const EStakeWithdrawBeforeActivation: u64 = 6;
    -
    - - - - - - - -
    const SYSTEM_STATE_VERSION_V1: u64 = 1;
    -
    - - - - - -## Function `create` - -Create a new SuiSystemState object and make it shared. -This function will be called only once in genesis. - - -
    public(friend) fun create(validators: vector<validator::Validator>, initial_storage_fund: balance::Balance<sui::SUI>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: sui_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext): sui_system_state_inner::SuiSystemStateInner
    -
    - - - -
    -Implementation - - -
    public(package) fun create(
    -    validators: vector<Validator>,
    -    initial_storage_fund: Balance<SUI>,
    -    protocol_version: u64,
    -    epoch_start_timestamp_ms: u64,
    -    parameters: SystemParameters,
    -    stake_subsidy: StakeSubsidy,
    -    ctx: &mut TxContext,
    -): SuiSystemStateInner {
    -    let validators = validator_set::new(validators, ctx);
    -    let reference_gas_price = validators.derive_reference_gas_price();
    -    // This type is fixed as it's created at genesis. It should not be updated during type upgrade.
    -    let system_state = SuiSystemStateInner {
    -        epoch: 0,
    -        protocol_version,
    -        system_state_version: genesis_system_state_version(),
    -        validators,
    -        storage_fund: storage_fund::new(initial_storage_fund),
    -        parameters,
    -        reference_gas_price,
    -        validator_report_records: vec_map::empty(),
    -        stake_subsidy,
    -        safe_mode: false,
    -        safe_mode_storage_rewards: balance::zero(),
    -        safe_mode_computation_rewards: balance::zero(),
    -        safe_mode_storage_rebates: 0,
    -        safe_mode_non_refundable_storage_fee: 0,
    -        epoch_start_timestamp_ms,
    -        extra_fields: bag::new(ctx),
    -    };
    -    system_state
    -}
    -
    - - - -
    - - - -## Function `create_system_parameters` - - - -
    public(friend) fun create_system_parameters(epoch_duration_ms: u64, stake_subsidy_start_epoch: u64, max_validator_count: u64, min_validator_joining_stake: u64, validator_low_stake_threshold: u64, validator_very_low_stake_threshold: u64, validator_low_stake_grace_period: u64, ctx: &mut tx_context::TxContext): sui_system_state_inner::SystemParameters
    -
    - - - -
    -Implementation - - -
    public(package) fun create_system_parameters(
    -    epoch_duration_ms: u64,
    -    stake_subsidy_start_epoch: u64,
    -
    -    // Validator committee parameters
    -    max_validator_count: u64,
    -    min_validator_joining_stake: u64,
    -    validator_low_stake_threshold: u64,
    -    validator_very_low_stake_threshold: u64,
    -    validator_low_stake_grace_period: u64,
    -    ctx: &mut TxContext,
    -): SystemParameters {
    -    SystemParameters {
    -        epoch_duration_ms,
    -        stake_subsidy_start_epoch,
    -        max_validator_count,
    -        min_validator_joining_stake,
    -        validator_low_stake_threshold,
    -        validator_very_low_stake_threshold,
    -        validator_low_stake_grace_period,
    -        extra_fields: bag::new(ctx),
    -    }
    -}
    -
    - - - -
    - - - -## Function `v1_to_v2` - - - -
    public(friend) fun v1_to_v2(self: sui_system_state_inner::SuiSystemStateInner): sui_system_state_inner::SuiSystemStateInnerV2
    -
    - - - -
    -Implementation - - -
    public(package) fun v1_to_v2(self: SuiSystemStateInner): SuiSystemStateInnerV2 {
    -    let SuiSystemStateInner {
    -        epoch,
    -        protocol_version,
    -        system_state_version: _,
    -        validators,
    -        storage_fund,
    -        parameters,
    -        reference_gas_price,
    -        validator_report_records,
    -        stake_subsidy,
    -        safe_mode,
    -        safe_mode_storage_rewards,
    -        safe_mode_computation_rewards,
    -        safe_mode_storage_rebates,
    -        safe_mode_non_refundable_storage_fee,
    -        epoch_start_timestamp_ms,
    -        extra_fields: state_extra_fields,
    -    } = self;
    -    let SystemParameters {
    -        epoch_duration_ms,
    -        stake_subsidy_start_epoch,
    -        max_validator_count,
    -        min_validator_joining_stake,
    -        validator_low_stake_threshold,
    -        validator_very_low_stake_threshold,
    -        validator_low_stake_grace_period,
    -        extra_fields: param_extra_fields,
    -    } = parameters;
    -    SuiSystemStateInnerV2 {
    -        epoch,
    -        protocol_version,
    -        system_state_version: 2,
    -        validators,
    -        storage_fund,
    -        parameters: SystemParametersV2 {
    -            epoch_duration_ms,
    -            stake_subsidy_start_epoch,
    -            min_validator_count: 4,
    -            max_validator_count,
    -            min_validator_joining_stake,
    -            validator_low_stake_threshold,
    -            validator_very_low_stake_threshold,
    -            validator_low_stake_grace_period,
    -            extra_fields: param_extra_fields,
    -        },
    -        reference_gas_price,
    -        validator_report_records,
    -        stake_subsidy,
    -        safe_mode,
    -        safe_mode_storage_rewards,
    -        safe_mode_computation_rewards,
    -        safe_mode_storage_rebates,
    -        safe_mode_non_refundable_storage_fee,
    -        epoch_start_timestamp_ms,
    -        extra_fields: state_extra_fields
    -    }
    -}
    -
    - - - -
    - - - -## Function `request_add_validator_candidate` - -Can be called by anyone who wishes to become a validator candidate and starts accuring delegated -stakes in their staking pool. Once they have at least MIN_VALIDATOR_JOINING_STAKE amount of stake they -can call request_add_validator to officially become an active validator at the next epoch. -Aborts if the caller is already a pending or active validator, or a validator candidate. -Note: proof_of_possession MUST be a valid signature using sui_address and protocol_pubkey_bytes. -To produce a valid PoP, run [fn test_proof_of_possession]. - - -
    public(friend) fun request_add_validator_candidate(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, pubkey_bytes: vector<u8>, network_pubkey_bytes: vector<u8>, worker_pubkey_bytes: vector<u8>, proof_of_possession: vector<u8>, name: vector<u8>, description: vector<u8>, image_url: vector<u8>, project_url: vector<u8>, net_address: vector<u8>, p2p_address: vector<u8>, primary_address: vector<u8>, worker_address: vector<u8>, gas_price: u64, commission_rate: u64, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun request_add_validator_candidate(
    -    self: &mut SuiSystemStateInnerV2,
    -    pubkey_bytes: vector<u8>,
    -    network_pubkey_bytes: vector<u8>,
    -    worker_pubkey_bytes: vector<u8>,
    -    proof_of_possession: vector<u8>,
    -    name: vector<u8>,
    -    description: vector<u8>,
    -    image_url: vector<u8>,
    -    project_url: vector<u8>,
    -    net_address: vector<u8>,
    -    p2p_address: vector<u8>,
    -    primary_address: vector<u8>,
    -    worker_address: vector<u8>,
    -    gas_price: u64,
    -    commission_rate: u64,
    -    ctx: &mut TxContext,
    -) {
    -    let validator = validator::new(
    -        ctx.sender(),
    -        pubkey_bytes,
    -        network_pubkey_bytes,
    -        worker_pubkey_bytes,
    -        proof_of_possession,
    -        name,
    -        description,
    -        image_url,
    -        project_url,
    -        net_address,
    -        p2p_address,
    -        primary_address,
    -        worker_address,
    -        gas_price,
    -        commission_rate,
    -        ctx
    -    );
    -
    -    self.validators.request_add_validator_candidate(validator, ctx);
    -}
    -
    - - - -
    - - - -## Function `request_remove_validator_candidate` - -Called by a validator candidate to remove themselves from the candidacy. After this call -their staking pool becomes deactivate. - - -
    public(friend) fun request_remove_validator_candidate(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun request_remove_validator_candidate(
    -    self: &mut SuiSystemStateInnerV2,
    -    ctx: &mut TxContext,
    -) {
    -    self.validators.request_remove_validator_candidate(ctx);
    -}
    -
    - - - -
    - - - -## Function `request_add_validator` - -Called by a validator candidate to add themselves to the active validator set beginning next epoch. -Aborts if the validator is a duplicate with one of the pending or active validators, or if the amount of -stake the validator has doesn't meet the min threshold, or if the number of new validators for the next -epoch has already reached the maximum. - - -
    public(friend) fun request_add_validator(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun request_add_validator(
    -    self: &mut SuiSystemStateInnerV2,
    -    ctx: &TxContext,
    -) {
    -    assert!(
    -        self.validators.next_epoch_validator_count() < self.parameters.max_validator_count,
    -        ELimitExceeded,
    -    );
    -
    -    self.validators.request_add_validator(self.parameters.min_validator_joining_stake, ctx);
    -}
    -
    - - - -
    - - - -## Function `request_remove_validator` - -A validator can call this function to request a removal in the next epoch. -We use the sender of ctx to look up the validator -(i.e. sender must match the sui_address in the validator). -At the end of the epoch, the validator object will be returned to the sui_address -of the validator. - - -
    public(friend) fun request_remove_validator(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun request_remove_validator(
    -    self: &mut SuiSystemStateInnerV2,
    -    ctx: &TxContext,
    -) {
    -    // Only check min validator condition if the current number of validators satisfy the constraint.
    -    // This is so that if we somehow already are in a state where we have less than min validators, it no longer matters
    -    // and is ok to stay so. This is useful for a test setup.
    -    if (self.validators.active_validators().length() >= self.parameters.min_validator_count) {
    -        assert!(
    -            self.validators.next_epoch_validator_count() > self.parameters.min_validator_count,
    -            ELimitExceeded,
    -        );
    -    };
    -
    -    self.validators.request_remove_validator(ctx)
    -}
    -
    - - - -
    - - - -## Function `request_set_gas_price` - -A validator can call this function to submit a new gas price quote, to be -used for the reference gas price calculation at the end of the epoch. - - -
    public(friend) fun request_set_gas_price(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, cap: &validator_cap::UnverifiedValidatorOperationCap, new_gas_price: u64)
    -
    - - - -
    -Implementation - - -
    public(package) fun request_set_gas_price(
    -    self: &mut SuiSystemStateInnerV2,
    -    cap: &UnverifiedValidatorOperationCap,
    -    new_gas_price: u64,
    -) {
    -    // Verify the represented address is an active or pending validator, and the capability is still valid.
    -    let verified_cap = self.validators.verify_cap(cap, ACTIVE_OR_PENDING_VALIDATOR);
    -    let validator = self.validators.get_validator_mut_with_verified_cap(&verified_cap, false /* include_candidate */);
    -
    -    validator.request_set_gas_price(verified_cap, new_gas_price);
    -}
    -
    - - - -
    - - - -## Function `set_candidate_validator_gas_price` - -This function is used to set new gas price for candidate validators - - -
    public(friend) fun set_candidate_validator_gas_price(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, cap: &validator_cap::UnverifiedValidatorOperationCap, new_gas_price: u64)
    -
    - - - -
    -Implementation - - -
    public(package) fun set_candidate_validator_gas_price(
    -    self: &mut SuiSystemStateInnerV2,
    -    cap: &UnverifiedValidatorOperationCap,
    -    new_gas_price: u64,
    -) {
    -    // Verify the represented address is an active or pending validator, and the capability is still valid.
    -    let verified_cap = self.validators.verify_cap(cap, ANY_VALIDATOR);
    -    let candidate = self.validators.get_validator_mut_with_verified_cap(&verified_cap, true /* include_candidate */);
    -    candidate.set_candidate_gas_price(verified_cap, new_gas_price)
    -}
    -
    - - - -
    - - - -## Function `request_set_commission_rate` - -A validator can call this function to set a new commission rate, updated at the end of -the epoch. - - -
    public(friend) fun request_set_commission_rate(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, new_commission_rate: u64, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun request_set_commission_rate(
    -    self: &mut SuiSystemStateInnerV2,
    -    new_commission_rate: u64,
    -    ctx: &TxContext,
    -) {
    -    self.validators.request_set_commission_rate(
    -        new_commission_rate,
    -        ctx
    -    )
    -}
    -
    - - - -
    - - - -## Function `set_candidate_validator_commission_rate` - -This function is used to set new commission rate for candidate validators - - -
    public(friend) fun set_candidate_validator_commission_rate(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, new_commission_rate: u64, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun set_candidate_validator_commission_rate(
    -    self: &mut SuiSystemStateInnerV2,
    -    new_commission_rate: u64,
    -    ctx: &TxContext,
    -) {
    -    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    -    candidate.set_candidate_commission_rate(new_commission_rate)
    -}
    -
    - - - -
    - - - -## Function `request_add_stake` - -Add stake to a validator's staking pool. - - -
    public(friend) fun request_add_stake(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, stake: coin::Coin<sui::SUI>, validator_address: address, ctx: &mut tx_context::TxContext): staking_pool::StakedSui
    -
    - - - -
    -Implementation - - -
    public(package) fun request_add_stake(
    -    self: &mut SuiSystemStateInnerV2,
    -    stake: Coin<SUI>,
    -    validator_address: address,
    -    ctx: &mut TxContext,
    -) : StakedSui {
    -    self.validators.request_add_stake(
    -        validator_address,
    -        stake.into_balance(),
    -        ctx,
    -    )
    -}
    -
    - - - -
    - - - -## Function `request_add_stake_mul_coin` - -Add stake to a validator's staking pool using multiple coins. - - -
    public(friend) fun request_add_stake_mul_coin(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, stakes: vector<coin::Coin<sui::SUI>>, stake_amount: option::Option<u64>, validator_address: address, ctx: &mut tx_context::TxContext): staking_pool::StakedSui
    -
    - - - -
    -Implementation - - -
    public(package) fun request_add_stake_mul_coin(
    -    self: &mut SuiSystemStateInnerV2,
    -    stakes: vector<Coin<SUI>>,
    -    stake_amount: option::Option<u64>,
    -    validator_address: address,
    -    ctx: &mut TxContext,
    -) : StakedSui {
    -    let balance = extract_coin_balance(stakes, stake_amount, ctx);
    -    self.validators.request_add_stake(validator_address, balance, ctx)
    -}
    -
    - - - -
    - - - -## Function `request_withdraw_stake` - -Withdraw some portion of a stake from a validator's staking pool. - - -
    public(friend) fun request_withdraw_stake(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, staked_sui: staking_pool::StakedSui, ctx: &tx_context::TxContext): balance::Balance<sui::SUI>
    -
    - - - -
    -Implementation - - -
    public(package) fun request_withdraw_stake(
    -    self: &mut SuiSystemStateInnerV2,
    -    staked_sui: StakedSui,
    -    ctx: &TxContext,
    -) : Balance<SUI> {
    -    assert!(
    -        stake_activation_epoch(&staked_sui) <= ctx.epoch(),
    -        EStakeWithdrawBeforeActivation
    -    );
    -    self.validators.request_withdraw_stake(staked_sui, ctx)
    -}
    -
    - - - -
    - - - -## Function `report_validator` - -Report a validator as a bad or non-performant actor in the system. -Succeeds if all the following are satisfied: -1. both the reporter in cap and the input reportee_addr are active validators. -2. reporter and reportee not the same address. -3. the cap object is still valid. -This function is idempotent. - - -
    public(friend) fun report_validator(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, cap: &validator_cap::UnverifiedValidatorOperationCap, reportee_addr: address)
    -
    - - - -
    -Implementation - - -
    public(package) fun report_validator(
    -    self: &mut SuiSystemStateInnerV2,
    -    cap: &UnverifiedValidatorOperationCap,
    -    reportee_addr: address,
    -) {
    -    // Reportee needs to be an active validator
    -    assert!(self.validators.is_active_validator_by_sui_address(reportee_addr), ENotValidator);
    -    // Verify the represented reporter address is an active validator, and the capability is still valid.
    -    let verified_cap = self.validators.verify_cap(cap, ACTIVE_VALIDATOR_ONLY);
    -    report_validator_impl(verified_cap, reportee_addr, &mut self.validator_report_records);
    -}
    -
    - - - -
    - - - -## Function `undo_report_validator` - -Undo a report_validator action. Aborts if -1. the reportee is not a currently active validator or -2. the sender has not previously reported the reportee_addr, or -3. the cap is not valid - - -
    public(friend) fun undo_report_validator(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, cap: &validator_cap::UnverifiedValidatorOperationCap, reportee_addr: address)
    -
    - - - -
    -Implementation - - -
    public(package) fun undo_report_validator(
    -    self: &mut SuiSystemStateInnerV2,
    -    cap: &UnverifiedValidatorOperationCap,
    -    reportee_addr: address,
    -) {
    -    let verified_cap = self.validators.verify_cap(cap, ACTIVE_VALIDATOR_ONLY);
    -    undo_report_validator_impl(verified_cap, reportee_addr, &mut self.validator_report_records);
    -}
    -
    - - - -
    - - - -## Function `report_validator_impl` - - - -
    fun report_validator_impl(verified_cap: validator_cap::ValidatorOperationCap, reportee_addr: address, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>)
    -
    - - - -
    -Implementation - - -
    fun report_validator_impl(
    -    verified_cap: ValidatorOperationCap,
    -    reportee_addr: address,
    -    validator_report_records: &mut VecMap<address, VecSet<address>>,
    -) {
    -    let reporter_address = *verified_cap.verified_operation_cap_address();
    -    assert!(reporter_address != reportee_addr, ECannotReportOneself);
    -    if (!validator_report_records.contains(&reportee_addr)) {
    -        validator_report_records.insert(reportee_addr, vec_set::singleton(reporter_address));
    -    } else {
    -        let reporters = validator_report_records.get_mut(&reportee_addr);
    -        if (!reporters.contains(&reporter_address)) {
    -            reporters.insert(reporter_address);
    -        }
    -    }
    -}
    -
    - - - -
    - - - -## Function `undo_report_validator_impl` - - - -
    fun undo_report_validator_impl(verified_cap: validator_cap::ValidatorOperationCap, reportee_addr: address, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>)
    -
    - - - -
    -Implementation - - -
    fun undo_report_validator_impl(
    -    verified_cap: ValidatorOperationCap,
    -    reportee_addr: address,
    -    validator_report_records: &mut VecMap<address, VecSet<address>>,
    -) {
    -    assert!(validator_report_records.contains(&reportee_addr), EReportRecordNotFound);
    -    let reporters = validator_report_records.get_mut(&reportee_addr);
    -
    -    let reporter_addr = *verified_cap.verified_operation_cap_address();
    -    assert!(reporters.contains(&reporter_addr), EReportRecordNotFound);
    -
    -    reporters.remove(&reporter_addr);
    -    if (reporters.is_empty()) {
    -        validator_report_records.remove(&reportee_addr);
    -    }
    -}
    -
    - - - -
    - - - -## Function `rotate_operation_cap` - -Create a new UnverifiedValidatorOperationCap, transfer it to the -validator and registers it. The original object is thus revoked. - - -
    public(friend) fun rotate_operation_cap(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun rotate_operation_cap(
    -    self: &mut SuiSystemStateInnerV2,
    -    ctx: &mut TxContext,
    -) {
    -    let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    -    validator.new_unverified_validator_operation_cap_and_transfer(ctx);
    -}
    -
    - - - -
    - - - -## Function `update_validator_name` - -Update a validator's name. - - -
    public(friend) fun update_validator_name(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, name: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_validator_name(
    -    self: &mut SuiSystemStateInnerV2,
    -    name: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    -
    -    validator.update_name(name);
    -}
    -
    - - - -
    - - - -## Function `update_validator_description` - -Update a validator's description - - -
    public(friend) fun update_validator_description(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, description: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_validator_description(
    -    self: &mut SuiSystemStateInnerV2,
    -    description: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    -    validator.update_description(description);
    -}
    -
    - - - -
    - - - -## Function `update_validator_image_url` - -Update a validator's image url - - -
    public(friend) fun update_validator_image_url(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, image_url: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_validator_image_url(
    -    self: &mut SuiSystemStateInnerV2,
    -    image_url: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    -    validator.update_image_url(image_url);
    -}
    -
    - - - -
    - - - -## Function `update_validator_project_url` - -Update a validator's project url - - -
    public(friend) fun update_validator_project_url(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, project_url: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_validator_project_url(
    -    self: &mut SuiSystemStateInnerV2,
    -    project_url: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    -    validator.update_project_url(project_url);
    -}
    -
    - - - -
    - - - -## Function `update_validator_next_epoch_network_address` - -Update a validator's network address. -The change will only take effects starting from the next epoch. - - -
    public(friend) fun update_validator_next_epoch_network_address(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, network_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_validator_next_epoch_network_address(
    -    self: &mut SuiSystemStateInnerV2,
    -    network_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let validator = self.validators.get_validator_mut_with_ctx(ctx);
    -    validator.update_next_epoch_network_address(network_address);
    -    let validator :&Validator = validator; // Force immutability for the following call
    -    self.validators.assert_no_pending_or_active_duplicates(validator);
    -}
    -
    - - - -
    - - - -## Function `update_candidate_validator_network_address` - -Update candidate validator's network address. - - -
    public(friend) fun update_candidate_validator_network_address(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, network_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_candidate_validator_network_address(
    -    self: &mut SuiSystemStateInnerV2,
    -    network_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    -    candidate.update_candidate_network_address(network_address);
    -}
    -
    - - - -
    - - - -## Function `update_validator_next_epoch_p2p_address` - -Update a validator's p2p address. -The change will only take effects starting from the next epoch. - - -
    public(friend) fun update_validator_next_epoch_p2p_address(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, p2p_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_validator_next_epoch_p2p_address(
    -    self: &mut SuiSystemStateInnerV2,
    -    p2p_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let validator = self.validators.get_validator_mut_with_ctx(ctx);
    -    validator.update_next_epoch_p2p_address(p2p_address);
    -    let validator :&Validator = validator; // Force immutability for the following call
    -    self.validators.assert_no_pending_or_active_duplicates(validator);
    -}
    -
    - - - -
    - - - -## Function `update_candidate_validator_p2p_address` - -Update candidate validator's p2p address. - - -
    public(friend) fun update_candidate_validator_p2p_address(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, p2p_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_candidate_validator_p2p_address(
    -    self: &mut SuiSystemStateInnerV2,
    -    p2p_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    -    candidate.update_candidate_p2p_address(p2p_address);
    -}
    -
    - - - -
    - - - -## Function `update_validator_next_epoch_primary_address` - -Update a validator's narwhal primary address. -The change will only take effects starting from the next epoch. - - -
    public(friend) fun update_validator_next_epoch_primary_address(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, primary_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_validator_next_epoch_primary_address(
    -    self: &mut SuiSystemStateInnerV2,
    -    primary_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let validator = self.validators.get_validator_mut_with_ctx(ctx);
    -    validator.update_next_epoch_primary_address(primary_address);
    -}
    -
    - - - -
    - - - -## Function `update_candidate_validator_primary_address` - -Update candidate validator's narwhal primary address. - - -
    public(friend) fun update_candidate_validator_primary_address(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, primary_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_candidate_validator_primary_address(
    -    self: &mut SuiSystemStateInnerV2,
    -    primary_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    -    candidate.update_candidate_primary_address(primary_address);
    -}
    -
    - - - -
    - - - -## Function `update_validator_next_epoch_worker_address` - -Update a validator's narwhal worker address. -The change will only take effects starting from the next epoch. - - -
    public(friend) fun update_validator_next_epoch_worker_address(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, worker_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_validator_next_epoch_worker_address(
    -    self: &mut SuiSystemStateInnerV2,
    -    worker_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let validator = self.validators.get_validator_mut_with_ctx(ctx);
    -    validator.update_next_epoch_worker_address(worker_address);
    -}
    -
    - - - -
    - - - -## Function `update_candidate_validator_worker_address` - -Update candidate validator's narwhal worker address. - - -
    public(friend) fun update_candidate_validator_worker_address(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, worker_address: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_candidate_validator_worker_address(
    -    self: &mut SuiSystemStateInnerV2,
    -    worker_address: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    -    candidate.update_candidate_worker_address(worker_address);
    -}
    -
    - - - -
    - - - -## Function `update_validator_next_epoch_protocol_pubkey` - -Update a validator's public key of protocol key and proof of possession. -The change will only take effects starting from the next epoch. - - -
    public(friend) fun update_validator_next_epoch_protocol_pubkey(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, protocol_pubkey: vector<u8>, proof_of_possession: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_validator_next_epoch_protocol_pubkey(
    -    self: &mut SuiSystemStateInnerV2,
    -    protocol_pubkey: vector<u8>,
    -    proof_of_possession: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let validator = self.validators.get_validator_mut_with_ctx(ctx);
    -    validator.update_next_epoch_protocol_pubkey(protocol_pubkey, proof_of_possession);
    -    let validator :&Validator = validator; // Force immutability for the following call
    -    self.validators.assert_no_pending_or_active_duplicates(validator);
    -}
    -
    - - - -
    - - - -## Function `update_candidate_validator_protocol_pubkey` - -Update candidate validator's public key of protocol key and proof of possession. - - -
    public(friend) fun update_candidate_validator_protocol_pubkey(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, protocol_pubkey: vector<u8>, proof_of_possession: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_candidate_validator_protocol_pubkey(
    -    self: &mut SuiSystemStateInnerV2,
    -    protocol_pubkey: vector<u8>,
    -    proof_of_possession: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    -    candidate.update_candidate_protocol_pubkey(protocol_pubkey, proof_of_possession);
    -}
    -
    - - - -
    - - - -## Function `update_validator_next_epoch_worker_pubkey` - -Update a validator's public key of worker key. -The change will only take effects starting from the next epoch. - - -
    public(friend) fun update_validator_next_epoch_worker_pubkey(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, worker_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_validator_next_epoch_worker_pubkey(
    -    self: &mut SuiSystemStateInnerV2,
    -    worker_pubkey: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let validator = self.validators.get_validator_mut_with_ctx(ctx);
    -    validator.update_next_epoch_worker_pubkey(worker_pubkey);
    -    let validator :&Validator = validator; // Force immutability for the following call
    -    self.validators.assert_no_pending_or_active_duplicates(validator);
    -}
    -
    - - - -
    - - - -## Function `update_candidate_validator_worker_pubkey` - -Update candidate validator's public key of worker key. - - -
    public(friend) fun update_candidate_validator_worker_pubkey(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, worker_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_candidate_validator_worker_pubkey(
    -    self: &mut SuiSystemStateInnerV2,
    -    worker_pubkey: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    -    candidate.update_candidate_worker_pubkey(worker_pubkey);
    -}
    -
    - - - -
    - - - -## Function `update_validator_next_epoch_network_pubkey` - -Update a validator's public key of network key. -The change will only take effects starting from the next epoch. - - -
    public(friend) fun update_validator_next_epoch_network_pubkey(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, network_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_validator_next_epoch_network_pubkey(
    -    self: &mut SuiSystemStateInnerV2,
    -    network_pubkey: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let validator = self.validators.get_validator_mut_with_ctx(ctx);
    -    validator.update_next_epoch_network_pubkey(network_pubkey);
    -    let validator :&Validator = validator; // Force immutability for the following call
    -    self.validators.assert_no_pending_or_active_duplicates(validator);
    -}
    -
    - - - -
    - - - -## Function `update_candidate_validator_network_pubkey` - -Update candidate validator's public key of network key. - - -
    public(friend) fun update_candidate_validator_network_pubkey(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, network_pubkey: vector<u8>, ctx: &tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public(package) fun update_candidate_validator_network_pubkey(
    -    self: &mut SuiSystemStateInnerV2,
    -    network_pubkey: vector<u8>,
    -    ctx: &TxContext,
    -) {
    -    let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx);
    -    candidate.update_candidate_network_pubkey(network_pubkey);
    -}
    -
    - - - -
    - - - -## Function `advance_epoch` - -This function should be called at the end of an epoch, and advances the system to the next epoch. -It does the following things: -1. Add storage charge to the storage fund. -2. Burn the storage rebates from the storage fund. These are already refunded to transaction sender's -gas coins. -3. Distribute computation charge to validator stake. -4. Update all validators. - - -
    public(friend) fun advance_epoch(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, storage_reward: balance::Balance<sui::SUI>, computation_reward: balance::Balance<sui::SUI>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<sui::SUI>
    -
    - - - -
    -Implementation - - -
    public(package) fun advance_epoch(
    -    self: &mut SuiSystemStateInnerV2,
    -    new_epoch: u64,
    -    next_protocol_version: u64,
    -    mut storage_reward: Balance<SUI>,
    -    mut computation_reward: Balance<SUI>,
    -    mut storage_rebate_amount: u64,
    -    mut non_refundable_storage_fee_amount: u64,
    -    storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested
    -                                     // into storage fund, in basis point.
    -    reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps.
    -    epoch_start_timestamp_ms: u64, // Timestamp of the epoch start
    -    ctx: &mut TxContext,
    -) : Balance<SUI> {
    -    let prev_epoch_start_timestamp = self.epoch_start_timestamp_ms;
    -    self.epoch_start_timestamp_ms = epoch_start_timestamp_ms;
    -
    -    let bps_denominator_u64 = BASIS_POINT_DENOMINATOR as u64;
    -    // Rates can't be higher than 100%.
    -    assert!(
    -        storage_fund_reinvest_rate <= bps_denominator_u64
    -        && reward_slashing_rate <= bps_denominator_u64,
    -        EBpsTooLarge,
    -    );
    -
    -    // TODO: remove this in later upgrade.
    -    if (self.parameters.stake_subsidy_start_epoch > 0) {
    -        self.parameters.stake_subsidy_start_epoch = 20;
    -    };
    -
    -    // Accumulate the gas summary during safe_mode before processing any rewards:
    -    let safe_mode_storage_rewards = self.safe_mode_storage_rewards.withdraw_all();
    -    storage_reward.join(safe_mode_storage_rewards);
    -    let safe_mode_computation_rewards = self.safe_mode_computation_rewards.withdraw_all();
    -    computation_reward.join(safe_mode_computation_rewards);
    -    storage_rebate_amount = storage_rebate_amount + self.safe_mode_storage_rebates;
    -    self.safe_mode_storage_rebates = 0;
    -    non_refundable_storage_fee_amount = non_refundable_storage_fee_amount + self.safe_mode_non_refundable_storage_fee;
    -    self.safe_mode_non_refundable_storage_fee = 0;
    -
    -    let total_validators_stake = self.validators.total_stake();
    -    let storage_fund_balance = self.storage_fund.total_balance();
    -    let total_stake = storage_fund_balance + total_validators_stake;
    -
    -    let storage_charge = storage_reward.value();
    -    let computation_charge = computation_reward.value();
    -
    -    // Include stake subsidy in the rewards given out to validators and stakers.
    -    // Delay distributing any stake subsidies until after `stake_subsidy_start_epoch`.
    -    // And if this epoch is shorter than the regular epoch duration, don't distribute any stake subsidy.
    -    let stake_subsidy =
    -        if (ctx.epoch() >= self.parameters.stake_subsidy_start_epoch  &&
    -            epoch_start_timestamp_ms >= prev_epoch_start_timestamp + self.parameters.epoch_duration_ms)
    -        {
    -            self.stake_subsidy.advance_epoch()
    -        } else {
    -            balance::zero()
    -        };
    -
    -    let stake_subsidy_amount = stake_subsidy.value();
    -    computation_reward.join(stake_subsidy);
    -
    -    let total_stake_u128 = total_stake as u128;
    -    let computation_charge_u128 = computation_charge as u128;
    -
    -    let storage_fund_reward_amount = storage_fund_balance as u128 * computation_charge_u128 / total_stake_u128;
    -    let mut storage_fund_reward = computation_reward.split(storage_fund_reward_amount as u64);
    -    let storage_fund_reinvestment_amount =
    -        storage_fund_reward_amount * (storage_fund_reinvest_rate as u128) / BASIS_POINT_DENOMINATOR;
    -    let storage_fund_reinvestment = storage_fund_reward.split(
    -        storage_fund_reinvestment_amount as u64,
    -    );
    -
    -    self.epoch = self.epoch + 1;
    -    // Sanity check to make sure we are advancing to the right epoch.
    -    assert!(new_epoch == self.epoch, EAdvancedToWrongEpoch);
    -
    -    let computation_reward_amount_before_distribution = computation_reward.value();
    -    let storage_fund_reward_amount_before_distribution = storage_fund_reward.value();
    -
    -    self.validators.advance_epoch(
    -        &mut computation_reward,
    -        &mut storage_fund_reward,
    -        &mut self.validator_report_records,
    -        reward_slashing_rate,
    -        self.parameters.validator_low_stake_threshold,
    -        self.parameters.validator_very_low_stake_threshold,
    -        self.parameters.validator_low_stake_grace_period,
    -        ctx,
    -    );
    -
    -    let new_total_stake = self.validators.total_stake();
    -
    -    let computation_reward_amount_after_distribution = computation_reward.value();
    -    let storage_fund_reward_amount_after_distribution = storage_fund_reward.value();
    -    let computation_reward_distributed = computation_reward_amount_before_distribution - computation_reward_amount_after_distribution;
    -    let storage_fund_reward_distributed = storage_fund_reward_amount_before_distribution - storage_fund_reward_amount_after_distribution;
    -
    -    self.protocol_version = next_protocol_version;
    -
    -    // Derive the reference gas price for the new epoch
    -    self.reference_gas_price = self.validators.derive_reference_gas_price();
    -    // Because of precision issues with integer divisions, we expect that there will be some
    -    // remaining balance in `storage_fund_reward` and `computation_reward`.
    -    // All of these go to the storage fund.
    -    let mut leftover_staking_rewards = storage_fund_reward;
    -    leftover_staking_rewards.join(computation_reward);
    -    let leftover_storage_fund_inflow = leftover_staking_rewards.value();
    -
    -    let refunded_storage_rebate =
    -        self.storage_fund.advance_epoch(
    -            storage_reward,
    -            storage_fund_reinvestment,
    -            leftover_staking_rewards,
    -            storage_rebate_amount,
    -            non_refundable_storage_fee_amount,
    -        );
    -
    -    event::emit(
    -        SystemEpochInfoEvent {
    -            epoch: self.epoch,
    -            protocol_version: self.protocol_version,
    -            reference_gas_price: self.reference_gas_price,
    -            total_stake: new_total_stake,
    -            storage_charge,
    -            storage_fund_reinvestment: storage_fund_reinvestment_amount as u64,
    -            storage_rebate: storage_rebate_amount,
    -            storage_fund_balance: self.storage_fund.total_balance(),
    -            stake_subsidy_amount,
    -            total_gas_fees: computation_charge,
    -            total_stake_rewards_distributed: computation_reward_distributed + storage_fund_reward_distributed,
    -            leftover_storage_fund_inflow,
    -        }
    -    );
    -    self.safe_mode = false;
    -    // Double check that the gas from safe mode has been processed.
    -    assert!(self.safe_mode_storage_rebates == 0
    -        && self.safe_mode_storage_rewards.value() == 0
    -        && self.safe_mode_computation_rewards.value() == 0, ESafeModeGasNotProcessed);
    -
    -    // Return the storage rebate split from storage fund that's already refunded to the transaction senders.
    -    // This will be burnt at the last step of epoch change programmable transaction.
    -    refunded_storage_rebate
    -}
    -
    - - - -
    - - - -## Function `epoch` - -Return the current epoch number. Useful for applications that need a coarse-grained concept of time, -since epochs are ever-increasing and epoch changes are intended to happen every 24 hours. - - -
    public(friend) fun epoch(self: &sui_system_state_inner::SuiSystemStateInnerV2): u64
    -
    - - - -
    -Implementation - - -
    public(package) fun epoch(self: &SuiSystemStateInnerV2): u64 {
    -    self.epoch
    -}
    -
    - - - -
    - - - -## Function `protocol_version` - - - -
    public(friend) fun protocol_version(self: &sui_system_state_inner::SuiSystemStateInnerV2): u64
    -
    - - - -
    -Implementation - - -
    public(package) fun protocol_version(self: &SuiSystemStateInnerV2): u64 {
    -    self.protocol_version
    -}
    -
    - - - -
    - - - -## Function `system_state_version` - - - -
    public(friend) fun system_state_version(self: &sui_system_state_inner::SuiSystemStateInnerV2): u64
    -
    - - - -
    -Implementation - - -
    public(package) fun system_state_version(self: &SuiSystemStateInnerV2): u64 {
    -    self.system_state_version
    -}
    -
    - - - -
    - - - -## Function `genesis_system_state_version` - -This function always return the genesis system state version, which is used to create the system state in genesis. -It should never change for a given network. - - -
    public(friend) fun genesis_system_state_version(): u64
    -
    - - - -
    -Implementation - - -
    public(package) fun genesis_system_state_version(): u64 {
    -    SYSTEM_STATE_VERSION_V1
    -}
    -
    - - - -
    - - - -## Function `epoch_start_timestamp_ms` - -Returns unix timestamp of the start of current epoch - - -
    public(friend) fun epoch_start_timestamp_ms(self: &sui_system_state_inner::SuiSystemStateInnerV2): u64
    -
    - - - -
    -Implementation - - -
    public(package) fun epoch_start_timestamp_ms(self: &SuiSystemStateInnerV2): u64 {
    -    self.epoch_start_timestamp_ms
    -}
    -
    - - - -
    - - - -## Function `validator_stake_amount` - -Returns the total amount staked with validator_addr. -Aborts if validator_addr is not an active validator. - - -
    public(friend) fun validator_stake_amount(self: &sui_system_state_inner::SuiSystemStateInnerV2, validator_addr: address): u64
    -
    - - - -
    -Implementation - - -
    public(package) fun validator_stake_amount(self: &SuiSystemStateInnerV2, validator_addr: address): u64 {
    -    self.validators.validator_total_stake_amount(validator_addr)
    -}
    -
    - - - -
    - - - -## Function `validator_staking_pool_id` - -Returns the staking pool id of a given validator. -Aborts if validator_addr is not an active validator. - - -
    public(friend) fun validator_staking_pool_id(self: &sui_system_state_inner::SuiSystemStateInnerV2, validator_addr: address): object::ID
    -
    - - - -
    -Implementation - - -
    public(package) fun validator_staking_pool_id(self: &SuiSystemStateInnerV2, validator_addr: address): ID {
    -
    -    self.validators.validator_staking_pool_id(validator_addr)
    -}
    -
    - - - -
    - - - -## Function `validator_staking_pool_mappings` - -Returns reference to the staking pool mappings that map pool ids to active validator addresses - - -
    public(friend) fun validator_staking_pool_mappings(self: &sui_system_state_inner::SuiSystemStateInnerV2): &table::Table<object::ID, address>
    -
    - - - -
    -Implementation - - -
    public(package) fun validator_staking_pool_mappings(self: &SuiSystemStateInnerV2): &Table<ID, address> {
    -
    -    self.validators.staking_pool_mappings()
    -}
    -
    - - - -
    - - - -## Function `get_reporters_of` - -Returns all the validators who are currently reporting addr - - -
    public(friend) fun get_reporters_of(self: &sui_system_state_inner::SuiSystemStateInnerV2, addr: address): vec_set::VecSet<address>
    -
    - - - -
    -Implementation - - -
    public(package) fun get_reporters_of(self: &SuiSystemStateInnerV2, addr: address): VecSet<address> {
    -
    -    if (self.validator_report_records.contains(&addr)) {
    -        self.validator_report_records[&addr]
    -    } else {
    -        vec_set::empty()
    -    }
    -}
    -
    - - - -
    - - - -## Function `get_storage_fund_total_balance` - - - -
    public(friend) fun get_storage_fund_total_balance(self: &sui_system_state_inner::SuiSystemStateInnerV2): u64
    -
    - - - -
    -Implementation - - -
    public(package) fun get_storage_fund_total_balance(self: &SuiSystemStateInnerV2): u64 {
    -    self.storage_fund.total_balance()
    -}
    -
    - - - -
    - - - -## Function `get_storage_fund_object_rebates` - - - -
    public(friend) fun get_storage_fund_object_rebates(self: &sui_system_state_inner::SuiSystemStateInnerV2): u64
    -
    - - - -
    -Implementation - - -
    public(package) fun get_storage_fund_object_rebates(self: &SuiSystemStateInnerV2): u64 {
    -    self.storage_fund.total_object_storage_rebates()
    -}
    -
    - - - -
    - - - -## Function `pool_exchange_rates` - - - -
    public(friend) fun pool_exchange_rates(self: &mut sui_system_state_inner::SuiSystemStateInnerV2, pool_id: &object::ID): &table::Table<u64, staking_pool::PoolTokenExchangeRate>
    -
    - - - -
    -Implementation - - -
    public(package) fun pool_exchange_rates(
    -    self: &mut SuiSystemStateInnerV2,
    -    pool_id: &ID
    -): &Table<u64, PoolTokenExchangeRate>  {
    -    let validators = &mut self.validators;
    -    validators.pool_exchange_rates(pool_id)
    -}
    -
    - - - -
    - - - -## Function `active_validator_addresses` - - - -
    public(friend) fun active_validator_addresses(self: &sui_system_state_inner::SuiSystemStateInnerV2): vector<address>
    -
    - - - -
    -Implementation - - -
    public(package) fun active_validator_addresses(self: &SuiSystemStateInnerV2): vector<address> {
    -    let validator_set = &self.validators;
    -    validator_set.active_validator_addresses()
    -}
    -
    - - - -
    - - - -## Function `extract_coin_balance` - -Extract required Balance from vector of Coin, transfer the remainder back to sender. - - -
    fun extract_coin_balance(coins: vector<coin::Coin<sui::SUI>>, amount: option::Option<u64>, ctx: &mut tx_context::TxContext): balance::Balance<sui::SUI>
    -
    - - - -
    -Implementation - - -
    fun extract_coin_balance(mut coins: vector<Coin<SUI>>, amount: option::Option<u64>, ctx: &mut TxContext): Balance<SUI> {
    -    let mut merged_coin = coins.pop_back();
    -    merged_coin.join_vec(coins);
    -
    -    let mut total_balance = merged_coin.into_balance();
    -    // return the full amount if amount is not specified
    -    if (amount.is_some()) {
    -        let amount = amount.destroy_some();
    -        let balance = total_balance.split(amount);
    -        // transfer back the remainder if non zero.
    -        if (total_balance.value() > 0) {
    -            transfer::public_transfer(total_balance.into_coin(ctx), ctx.sender());
    -        } else {
    -            total_balance.destroy_zero();
    -        };
    -        balance
    -    } else {
    -        total_balance
    -    }
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/timelock/timelock.md b/crates/sui-framework/docs/timelock/timelock.md deleted file mode 100644 index bd284b6026a..00000000000 --- a/crates/sui-framework/docs/timelock/timelock.md +++ /dev/null @@ -1,380 +0,0 @@ ---- -title: Module `0x10cf::timelock` ---- - -A timelock implementation. - - -- [Resource `TimeLock`](#0x10cf_timelock_TimeLock) -- [Constants](#@Constants_0) -- [Function `lock`](#0x10cf_timelock_lock) -- [Function `unlock`](#0x10cf_timelock_unlock) -- [Function `expiration_timestamp_ms`](#0x10cf_timelock_expiration_timestamp_ms) -- [Function `is_locked`](#0x10cf_timelock_is_locked) -- [Function `remaining_time`](#0x10cf_timelock_remaining_time) -- [Function `locked`](#0x10cf_timelock_locked) -- [Function `locked_mut`](#0x10cf_timelock_locked_mut) -- [Function `pack`](#0x10cf_timelock_pack) -- [Function `unpack`](#0x10cf_timelock_unpack) -- [Function `transfer`](#0x10cf_timelock_transfer) - - -
    use 0x2::object;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -
    - - - - - -## Resource `TimeLock` - -TimeLock struct that holds a locked object. - - -
    struct TimeLock<T: store> has key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -locked: T -
    -
    - The locked object. -
    -
    -expiration_timestamp_ms: u64 -
    -
    - This is the epoch time stamp of when the lock expires. -
    -
    - - -
    - - - -## Constants - - - - -Error code for when the expire timestamp of the lock is in the past. - - -
    const EExpireEpochIsPast: u64 = 0;
    -
    - - - - - -Error code for when the lock has not expired yet. - - -
    const ENotExpiredYet: u64 = 1;
    -
    - - - - - -## Function `lock` - -Function to lock an object till a unix timestamp in milliseconds. - - -
    public fun lock<T: store>(locked: T, expiration_timestamp_ms: u64, ctx: &mut tx_context::TxContext): timelock::TimeLock<T>
    -
    - - - -
    -Implementation - - -
    public fun lock<T: store>(locked: T, expiration_timestamp_ms: u64, ctx: &mut TxContext): TimeLock<T> {
    -    // Get the epoch timestamp.
    -    let epoch_timestamp_ms = ctx.epoch_timestamp_ms();
    -
    -    // Check that `expiration_timestamp_ms` is valid.
    -    assert!(expiration_timestamp_ms > epoch_timestamp_ms, EExpireEpochIsPast);
    -
    -    // Create a timelock.
    -    pack(locked, expiration_timestamp_ms, ctx)
    -}
    -
    - - - -
    - - - -## Function `unlock` - -Function to unlock the object from a TimeLock. - - -
    public fun unlock<T: store>(self: timelock::TimeLock<T>, ctx: &mut tx_context::TxContext): T
    -
    - - - -
    -Implementation - - -
    public fun unlock<T: store>(self: TimeLock<T>, ctx: &mut TxContext): T {
    -    // Unpack the timelock.
    -    let (locked, expiration_timestamp_ms) = unpack(self);
    -
    -    // Check if the lock has expired.
    -    assert!(expiration_timestamp_ms <= ctx.epoch_timestamp_ms(), ENotExpiredYet);
    -
    -    locked
    -}
    -
    - - - -
    - - - -## Function `expiration_timestamp_ms` - -Function to get the expiration timestamp of a TimeLock. - - -
    public fun expiration_timestamp_ms<T: store>(self: &timelock::TimeLock<T>): u64
    -
    - - - -
    -Implementation - - -
    public fun expiration_timestamp_ms<T: store>(self: &TimeLock<T>): u64 {
    -    self.expiration_timestamp_ms
    -}
    -
    - - - -
    - - - -## Function `is_locked` - -Function to check if a TimeLock is locked. - - -
    public fun is_locked<T: store>(self: &timelock::TimeLock<T>, ctx: &mut tx_context::TxContext): bool
    -
    - - - -
    -Implementation - - -
    public fun is_locked<T: store>(self: &TimeLock<T>, ctx: &mut TxContext): bool {
    -    self.remaining_time(ctx) > 0
    -}
    -
    - - - -
    - - - -## Function `remaining_time` - -Function to get the remaining time of a TimeLock. -Returns 0 if the lock has expired. - - -
    public fun remaining_time<T: store>(self: &timelock::TimeLock<T>, ctx: &mut tx_context::TxContext): u64
    -
    - - - -
    -Implementation - - -
    public fun remaining_time<T: store>(self: &TimeLock<T>, ctx: &mut TxContext): u64 {
    -    // Get the epoch timestamp.
    -    let current_timestamp_ms = ctx.epoch_timestamp_ms();
    -
    -    // Check if the lock has expired.
    -    if (self.expiration_timestamp_ms < current_timestamp_ms) {
    -        return 0
    -    };
    -
    -    // Calculate the remaining time.
    -    self.expiration_timestamp_ms - current_timestamp_ms
    -}
    -
    - - - -
    - - - -## Function `locked` - -Function to get the locked object of a TimeLock. - - -
    public fun locked<T: store>(self: &timelock::TimeLock<T>): &T
    -
    - - - -
    -Implementation - - -
    public fun locked<T: store>(self: &TimeLock<T>): &T {
    -    &self.locked
    -}
    -
    - - - -
    - - - -## Function `locked_mut` - -Function to get a mutable reference to the locked object of a TimeLock. - - -
    public(friend) fun locked_mut<T: store>(self: &mut timelock::TimeLock<T>): &mut T
    -
    - - - -
    -Implementation - - -
    public(package) fun locked_mut<T: store>(self: &mut TimeLock<T>): &mut T {
    -    &mut self.locked
    -}
    -
    - - - -
    - - - -## Function `pack` - -An utility function to pack a TimeLock. - - -
    public(friend) fun pack<T: store>(locked: T, expiration_timestamp_ms: u64, ctx: &mut tx_context::TxContext): timelock::TimeLock<T>
    -
    - - - -
    -Implementation - - -
    public(package) fun pack<T: store>(locked: T, expiration_timestamp_ms: u64, ctx: &mut TxContext): TimeLock<T> {
    -    // Create a timelock.
    -    TimeLock {
    -        id: object::new(ctx),
    -        locked,
    -        expiration_timestamp_ms
    -    }
    -}
    -
    - - - -
    - - - -## Function `unpack` - -An utility function to unpack a TimeLock. - - -
    public(friend) fun unpack<T: store>(lock: timelock::TimeLock<T>): (T, u64)
    -
    - - - -
    -Implementation - - -
    public(package) fun unpack<T: store>(lock: TimeLock<T>): (T, u64) {
    -    // Unpack the timelock.
    -    let TimeLock {
    -        id,
    -        locked,
    -        expiration_timestamp_ms
    -    } = lock;
    -
    -    // Delete the timelock.
    -    object::delete(id);
    -
    -    (locked, expiration_timestamp_ms)
    -}
    -
    - - - -
    - - - -## Function `transfer` - -An utility function to transfer a TimeLock. - - -
    public(friend) fun transfer<T: store>(lock: timelock::TimeLock<T>, recipient: address)
    -
    - - - -
    -Implementation - - -
    public(package) fun transfer<T: store>(lock: TimeLock<T>, recipient: address) {
    -    transfer::transfer(lock, recipient);
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/timelock/timelocked_balance.md b/crates/sui-framework/docs/timelock/timelocked_balance.md deleted file mode 100644 index e966e6db596..00000000000 --- a/crates/sui-framework/docs/timelock/timelocked_balance.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -title: Module `0x10cf::timelocked_balance` ---- - -Utility functions for time-locked balance. - - -- [Constants](#@Constants_0) -- [Function `join`](#0x10cf_timelocked_balance_join) -- [Function `join_vec`](#0x10cf_timelocked_balance_join_vec) -- [Function `split`](#0x10cf_timelocked_balance_split) - - -
    use 0x10cf::timelock;
    -use 0x2::balance;
    -use 0x2::tx_context;
    -
    - - - - - -## Constants - - - - -For when trying to join two timelocks with different expiration time. - - -
    const EDifferentExpirationTime: u64 = 0;
    -
    - - - - - -## Function `join` - -Join two TimeLock<Balance<T>> together. - - -
    public fun join<T>(self: &mut timelock::TimeLock<balance::Balance<T>>, other: timelock::TimeLock<balance::Balance<T>>)
    -
    - - - -
    -Implementation - - -
    public fun join<T>(self: &mut TimeLock<Balance<T>>, other: TimeLock<Balance<T>>) {
    -    // Check the preconditions.
    -    assert!(self.expiration_timestamp_ms() == other.expiration_timestamp_ms(), EDifferentExpirationTime);
    -
    -    // Unpack the time-locked balance.
    -    let (value, _) = timelock::unpack(other);
    -
    -    // Join the balances.
    -    self.locked_mut().join(value);
    -}
    -
    - - - -
    - - - -## Function `join_vec` - -Join everything in others with self. - - -
    public fun join_vec<T>(self: &mut timelock::TimeLock<balance::Balance<T>>, others: vector<timelock::TimeLock<balance::Balance<T>>>)
    -
    - - - -
    -Implementation - - -
    public fun join_vec<T>(self: &mut TimeLock<Balance<T>>, mut others: vector<TimeLock<Balance<T>>>) {
    -    // Create useful variables.
    -    let (mut i, len) = (0, others.length());
    -
    -    // Join all the balances.
    -    while (i < len) {
    -        let other = others.pop_back();
    -        Self::join(self, other);
    -        i = i + 1
    -    };
    -
    -    // Destroy the empty vector.
    -    vector::destroy_empty(others)
    -}
    -
    - - - -
    - - - -## Function `split` - -Split a TimeLock<Balance<T>> and take a sub balance from it. - - -
    public fun split<T>(self: &mut timelock::TimeLock<balance::Balance<T>>, value: u64, ctx: &mut tx_context::TxContext): timelock::TimeLock<balance::Balance<T>>
    -
    - - - -
    -Implementation - - -
    public fun split<T>(self: &mut TimeLock<Balance<T>>, value: u64, ctx: &mut TxContext): TimeLock<Balance<T>> {
    -    // Split the locked balance.
    -    let value = self.locked_mut().split(value);
    -
    -    // Pack the splitted balance into a timelock.
    -    timelock::pack(value, self.expiration_timestamp_ms(), ctx)
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/timelock/timelocked_staked_sui.md b/crates/sui-framework/docs/timelock/timelocked_staked_sui.md deleted file mode 100644 index a7f71a74744..00000000000 --- a/crates/sui-framework/docs/timelock/timelocked_staked_sui.md +++ /dev/null @@ -1,390 +0,0 @@ ---- -title: Module `0x10cf::timelocked_staked_sui` ---- - - - -- [Resource `TimelockedStakedSui`](#0x10cf_timelocked_staked_sui_TimelockedStakedSui) -- [Constants](#@Constants_0) -- [Function `create`](#0x10cf_timelocked_staked_sui_create) -- [Function `pool_id`](#0x10cf_timelocked_staked_sui_pool_id) -- [Function `staked_sui_amount`](#0x10cf_timelocked_staked_sui_staked_sui_amount) -- [Function `stake_activation_epoch`](#0x10cf_timelocked_staked_sui_stake_activation_epoch) -- [Function `expiration_timestamp_ms`](#0x10cf_timelocked_staked_sui_expiration_timestamp_ms) -- [Function `split`](#0x10cf_timelocked_staked_sui_split) -- [Function `split_staked_sui`](#0x10cf_timelocked_staked_sui_split_staked_sui) -- [Function `join_staked_sui`](#0x10cf_timelocked_staked_sui_join_staked_sui) -- [Function `is_equal_staking_metadata`](#0x10cf_timelocked_staked_sui_is_equal_staking_metadata) -- [Function `unpack`](#0x10cf_timelocked_staked_sui_unpack) -- [Function `transfer`](#0x10cf_timelocked_staked_sui_transfer) - - -
    use 0x2::object;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -use 0x3::staking_pool;
    -
    - - - - - -## Resource `TimelockedStakedSui` - -A self-custodial object holding the timelocked staked SUI tokens. - - -
    struct TimelockedStakedSui has key
    -
    - - - -
    -Fields - - -
    -
    -id: object::UID -
    -
    - -
    -
    -staked_sui: staking_pool::StakedSui -
    -
    - A self-custodial object holding the staked SUI tokens. -
    -
    -expiration_timestamp_ms: u64 -
    -
    - This is the epoch time stamp of when the lock expires. -
    -
    - - -
    - - - -## Constants - - - - - - -
    const EIncompatibleTimelockedStakedSui: u64 = 0;
    -
    - - - - - -## Function `create` - -Create a new instance of TimelockedStakedSui. - - -
    public(friend) fun create(staked_sui: staking_pool::StakedSui, expiration_timestamp_ms: u64, ctx: &mut tx_context::TxContext): timelocked_staked_sui::TimelockedStakedSui
    -
    - - - -
    -Implementation - - -
    public(package) fun create(
    -    staked_sui: StakedSui,
    -    expiration_timestamp_ms: u64,
    -    ctx: &mut TxContext
    -): TimelockedStakedSui {
    -    TimelockedStakedSui {
    -        id: object::new(ctx),
    -        staked_sui,
    -        expiration_timestamp_ms
    -    }
    -}
    -
    - - - -
    - - - -## Function `pool_id` - -Function to get the pool id of a TimelockedStakedSui. - - -
    public fun pool_id(self: &timelocked_staked_sui::TimelockedStakedSui): object::ID
    -
    - - - -
    -Implementation - - -
    public fun pool_id(self: &TimelockedStakedSui): ID { self.staked_sui.pool_id() }
    -
    - - - -
    - - - -## Function `staked_sui_amount` - -Function to get the staked sui amount of a TimelockedStakedSui. - - -
    public fun staked_sui_amount(self: &timelocked_staked_sui::TimelockedStakedSui): u64
    -
    - - - -
    -Implementation - - -
    public fun staked_sui_amount(self: &TimelockedStakedSui): u64 { self.staked_sui.staked_sui_amount() }
    -
    - - - -
    - - - -## Function `stake_activation_epoch` - -Function to get the stake activation epoch of a TimelockedStakedSui. - - -
    public fun stake_activation_epoch(self: &timelocked_staked_sui::TimelockedStakedSui): u64
    -
    - - - -
    -Implementation - - -
    public fun stake_activation_epoch(self: &TimelockedStakedSui): u64 {
    -    self.staked_sui.stake_activation_epoch()
    -}
    -
    - - - -
    - - - -## Function `expiration_timestamp_ms` - -Function to get the expiration timestamp of a TimelockedStakedSui. - - -
    public fun expiration_timestamp_ms(self: &timelocked_staked_sui::TimelockedStakedSui): u64
    -
    - - - -
    -Implementation - - -
    public fun expiration_timestamp_ms(self: &TimelockedStakedSui): u64 {
    -    self.expiration_timestamp_ms
    -}
    -
    - - - -
    - - - -## Function `split` - -Split TimelockedStakedSui into two parts, one with principal split_amount, -and the remaining principal is left in self. -All the other parameters of the TimelockedStakedSui like stake_activation_epoch or pool_id remain the same. - - -
    public fun split(self: &mut timelocked_staked_sui::TimelockedStakedSui, split_amount: u64, ctx: &mut tx_context::TxContext): timelocked_staked_sui::TimelockedStakedSui
    -
    - - - -
    -Implementation - - -
    public fun split(self: &mut TimelockedStakedSui, split_amount: u64, ctx: &mut TxContext): TimelockedStakedSui {
    -    let splitted_stake = self.staked_sui.split(split_amount, ctx);
    -
    -    TimelockedStakedSui {
    -        id: object::new(ctx),
    -        staked_sui: splitted_stake,
    -        expiration_timestamp_ms: self.expiration_timestamp_ms,
    -    }
    -}
    -
    - - - -
    - - - -## Function `split_staked_sui` - -Split the given TimelockedStakedSui to the two parts, one with principal split_amount, -transfer the newly split part to the sender address. - - -
    public entry fun split_staked_sui(stake: &mut timelocked_staked_sui::TimelockedStakedSui, split_amount: u64, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun split_staked_sui(stake: &mut TimelockedStakedSui, split_amount: u64, ctx: &mut TxContext) {
    -    transfer::transfer(split(stake, split_amount, ctx), ctx.sender());
    -}
    -
    - - - -
    - - - -## Function `join_staked_sui` - -Consume the staked sui other and add its value to self. -Aborts if some of the staking parameters are incompatible (pool id, stake activation epoch, etc.) - - -
    public entry fun join_staked_sui(self: &mut timelocked_staked_sui::TimelockedStakedSui, other: timelocked_staked_sui::TimelockedStakedSui)
    -
    - - - -
    -Implementation - - -
    public entry fun join_staked_sui(self: &mut TimelockedStakedSui, other: TimelockedStakedSui) {
    -    assert!(self.is_equal_staking_metadata(&other), EIncompatibleTimelockedStakedSui);
    -
    -    let TimelockedStakedSui {
    -        id,
    -        staked_sui,
    -        expiration_timestamp_ms: _,
    -    } = other;
    -
    -    id.delete();
    -
    -    self.staked_sui.join(staked_sui);
    -}
    -
    - - - -
    - - - -## Function `is_equal_staking_metadata` - -Returns true if all the staking parameters of the staked sui except the principal are identical - - -
    public fun is_equal_staking_metadata(self: &timelocked_staked_sui::TimelockedStakedSui, other: &timelocked_staked_sui::TimelockedStakedSui): bool
    -
    - - - -
    -Implementation - - -
    public fun is_equal_staking_metadata(self: &TimelockedStakedSui, other: &TimelockedStakedSui): bool {
    -    self.staked_sui.is_equal_staking_metadata(&other.staked_sui) &&
    -    (self.expiration_timestamp_ms == other.expiration_timestamp_ms)
    -}
    -
    - - - -
    - - - -## Function `unpack` - -An utility function to destroy a TimelockedStakedSui. - - -
    public(friend) fun unpack(self: timelocked_staked_sui::TimelockedStakedSui): (staking_pool::StakedSui, u64)
    -
    - - - -
    -Implementation - - -
    public(package) fun unpack(self: TimelockedStakedSui): (StakedSui, u64) {
    -    let TimelockedStakedSui {
    -        id,
    -        staked_sui,
    -        expiration_timestamp_ms,
    -    } = self;
    -
    -    object::delete(id);
    -
    -    (staked_sui, expiration_timestamp_ms)
    -}
    -
    - - - -
    - - - -## Function `transfer` - -An utility function to transfer a TimelockedStakedSui. - - -
    public(friend) fun transfer(stake: timelocked_staked_sui::TimelockedStakedSui, recipient: address)
    -
    - - - -
    -Implementation - - -
    public(package) fun transfer(stake: TimelockedStakedSui, recipient: address) {
    -    transfer::transfer(stake, recipient);
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/docs/timelock/timelocked_staking.md b/crates/sui-framework/docs/timelock/timelocked_staking.md deleted file mode 100644 index a3bbbdc3849..00000000000 --- a/crates/sui-framework/docs/timelock/timelocked_staking.md +++ /dev/null @@ -1,311 +0,0 @@ ---- -title: Module `0x10cf::timelocked_staking` ---- - - - -- [Constants](#@Constants_0) -- [Function `request_add_stake`](#0x10cf_timelocked_staking_request_add_stake) -- [Function `request_add_stake_non_entry`](#0x10cf_timelocked_staking_request_add_stake_non_entry) -- [Function `request_add_stake_mul_bal`](#0x10cf_timelocked_staking_request_add_stake_mul_bal) -- [Function `request_add_stake_mul_bal_non_entry`](#0x10cf_timelocked_staking_request_add_stake_mul_bal_non_entry) -- [Function `request_withdraw_stake`](#0x10cf_timelocked_staking_request_withdraw_stake) -- [Function `request_withdraw_stake_non_entry`](#0x10cf_timelocked_staking_request_withdraw_stake_non_entry) - - -
    use 0x10cf::timelock;
    -use 0x10cf::timelocked_staked_sui;
    -use 0x2::balance;
    -use 0x2::coin;
    -use 0x2::sui;
    -use 0x2::transfer;
    -use 0x2::tx_context;
    -use 0x3::staking_pool;
    -use 0x3::sui_system;
    -
    - - - - - -## Constants - - - - -For when trying to stake an expired time-locked balance. - - -
    const ETimeLockShouldNotBeExpired: u64 = 0;
    -
    - - - - - -## Function `request_add_stake` - -Add a time-locked stake to a validator's staking pool. - - -
    public entry fun request_add_stake(sui_system: &mut sui_system::SuiSystemState, timelocked_balance: timelock::TimeLock<balance::Balance<sui::SUI>>, validator_address: address, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun request_add_stake(
    -    sui_system: &mut SuiSystemState,
    -    timelocked_balance: TimeLock<Balance<SUI>>,
    -    validator_address: address,
    -    ctx: &mut TxContext,
    -) {
    -    // Stake the time-locked balance.
    -    let timelocked_staked_sui = request_add_stake_non_entry(sui_system, timelocked_balance, validator_address, ctx);
    -
    -    // Transfer the receipt to the sender.
    -    timelocked_staked_sui::transfer(timelocked_staked_sui, ctx.sender());
    -}
    -
    - - - -
    - - - -## Function `request_add_stake_non_entry` - -The non-entry version of request_add_stake, which returns the time-locked staked SUI instead of transferring it to the sender. - - -
    public fun request_add_stake_non_entry(sui_system: &mut sui_system::SuiSystemState, timelocked_balance: timelock::TimeLock<balance::Balance<sui::SUI>>, validator_address: address, ctx: &mut tx_context::TxContext): timelocked_staked_sui::TimelockedStakedSui
    -
    - - - -
    -Implementation - - -
    public fun request_add_stake_non_entry(
    -    sui_system: &mut SuiSystemState,
    -    timelocked_balance: TimeLock<Balance<SUI>>,
    -    validator_address: address,
    -    ctx: &mut TxContext,
    -) : TimelockedStakedSui {
    -    // Check the preconditions.
    -    assert!(timelocked_balance.is_locked(ctx), ETimeLockShouldNotBeExpired);
    -
    -    // Unpack the time-locked balance.
    -    let (balance, expiration_timestamp_ms) = timelock::unpack(timelocked_balance);
    -
    -    // Stake the time-locked balance.
    -    let staked_sui = sui_system.request_add_stake_non_entry(
    -        balance.into_coin(ctx),
    -        validator_address,
    -        ctx,
    -    );
    -
    -    // Create and return a receipt.
    -    timelocked_staked_sui::create(
    -        staked_sui,
    -        expiration_timestamp_ms,
    -        ctx
    -    )
    -}
    -
    - - - -
    - - - -## Function `request_add_stake_mul_bal` - -Add a time-locked stake to a validator's staking pool using multiple time-locked balances. - - -
    public entry fun request_add_stake_mul_bal(sui_system: &mut sui_system::SuiSystemState, timelocked_balances: vector<timelock::TimeLock<balance::Balance<sui::SUI>>>, validator_address: address, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun request_add_stake_mul_bal(
    -    sui_system: &mut SuiSystemState,
    -    timelocked_balances: vector<TimeLock<Balance<SUI>>>,
    -    validator_address: address,
    -    ctx: &mut TxContext,
    -) {
    -    // Stake the time-locked balances.
    -    let mut receipts = request_add_stake_mul_bal_non_entry(sui_system, timelocked_balances, validator_address, ctx);
    -
    -    // Create useful variables.
    -    let (mut i, len) = (0, receipts.length());
    -
    -    // Send all the receipts to the sender.
    -    while (i < len) {
    -        // Take a receipt.
    -        let receipt = receipts.pop_back();
    -
    -        // Transfer the receipt to the sender.
    -        timelocked_staked_sui::transfer(receipt, ctx.sender());
    -
    -        i = i + 1
    -    };
    -
    -    // Destroy the empty vector.
    -    vector::destroy_empty(receipts)
    -}
    -
    - - - -
    - - - -## Function `request_add_stake_mul_bal_non_entry` - -The non-entry version of request_add_stake_mul_bal, -which returns a list of the time-locked staked SUIs instead of transferring them to the sender. - - -
    public fun request_add_stake_mul_bal_non_entry(sui_system: &mut sui_system::SuiSystemState, timelocked_balances: vector<timelock::TimeLock<balance::Balance<sui::SUI>>>, validator_address: address, ctx: &mut tx_context::TxContext): vector<timelocked_staked_sui::TimelockedStakedSui>
    -
    - - - -
    -Implementation - - -
    public fun request_add_stake_mul_bal_non_entry(
    -    sui_system: &mut SuiSystemState,
    -    mut timelocked_balances: vector<TimeLock<Balance<SUI>>>,
    -    validator_address: address,
    -    ctx: &mut TxContext,
    -) : vector<TimelockedStakedSui> {
    -    // Create a vector to store the results.
    -    let mut result = vector[];
    -
    -    // Create useful variables.
    -    let (mut i, len) = (0, timelocked_balances.length());
    -
    -    // Stake all the time-locked balances.
    -    while (i < len) {
    -        // Take a time-locked balance.
    -        let timelocked_balance = timelocked_balances.pop_back();
    -
    -        // Stake the time-locked balance.
    -        let timelocked_staked_sui = request_add_stake_non_entry(sui_system, timelocked_balance, validator_address, ctx);
    -
    -        // Store the created receipt.
    -        result.push_back(timelocked_staked_sui);
    -
    -        i = i + 1
    -    };
    -
    -    // Destroy the empty vector.
    -    vector::destroy_empty(timelocked_balances);
    -
    -    result
    -}
    -
    - - - -
    - - - -## Function `request_withdraw_stake` - -Withdraw a time-locked stake from a validator's staking pool. - - -
    public entry fun request_withdraw_stake(sui_system: &mut sui_system::SuiSystemState, timelocked_staked_sui: timelocked_staked_sui::TimelockedStakedSui, ctx: &mut tx_context::TxContext)
    -
    - - - -
    -Implementation - - -
    public entry fun request_withdraw_stake(
    -    sui_system: &mut SuiSystemState,
    -    timelocked_staked_sui: TimelockedStakedSui,
    -    ctx: &mut TxContext,
    -) {
    -    // Withdraw the time-locked balance.
    -    let (timelocked_balance, reward) = request_withdraw_stake_non_entry(sui_system, timelocked_staked_sui, ctx);
    -
    -    // Transfer the withdrawn time-locked balance to the sender.
    -    timelock::transfer(timelocked_balance, ctx.sender());
    -
    -    // Send coins only if the reward is not zero.
    -    if (reward.value() > 0) {
    -        transfer::public_transfer(reward.into_coin(ctx), ctx.sender());
    -    }
    -    else {
    -        balance::destroy_zero(reward);
    -    }
    -}
    -
    - - - -
    - - - -## Function `request_withdraw_stake_non_entry` - -Non-entry version of request_withdraw_stake that returns the withdrawn time-locked SUI and reward -instead of transferring it to the sender. - - -
    public fun request_withdraw_stake_non_entry(sui_system: &mut sui_system::SuiSystemState, timelocked_staked_sui: timelocked_staked_sui::TimelockedStakedSui, ctx: &mut tx_context::TxContext): (timelock::TimeLock<balance::Balance<sui::SUI>>, balance::Balance<sui::SUI>)
    -
    - - - -
    -Implementation - - -
    public fun request_withdraw_stake_non_entry(
    -    sui_system: &mut SuiSystemState,
    -    timelocked_staked_sui: TimelockedStakedSui,
    -    ctx: &mut TxContext,
    -) : (TimeLock<Balance<SUI>>, Balance<SUI>) {
    -    // Unpack the `TimelockedStakedSui` instance.
    -    let (staked_sui, expiration_timestamp_ms) = timelocked_staked_sui.unpack();
    -
    -    // Store the original stake amount.
    -    let principal = staked_sui.staked_sui_amount();
    -
    -    // Withdraw the balance.
    -    let mut withdraw_stake = sui_system.request_withdraw_stake_non_entry(staked_sui, ctx);
    -
    -    // The sui_system withdraw functions return a balance that consists of the original staked amount plus the reward amount;
    -    // In here, it splits the original staked balance to timelock it again.
    -    let principal = withdraw_stake.split(principal);
    -
    -    // Pack and return a time-locked balance, and the reward.
    -    (timelock::pack(principal, expiration_timestamp_ms, ctx), withdraw_stake)
    -}
    -
    - - - -
    diff --git a/crates/sui-framework/packages/deepbook/Move.lock b/crates/sui-framework/packages/deepbook/Move.lock deleted file mode 100644 index 40c594faa0e..00000000000 --- a/crates/sui-framework/packages/deepbook/Move.lock +++ /dev/null @@ -1,28 +0,0 @@ -# @generated by Move, please check-in and do not edit manually. - -[move] -version = 1 -manifest_digest = "E7FF1D7441FA0105B981EE018AEF168A18B22984DEABBF2F111AA6FBB3C3CB81" -deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600" - -dependencies = [ - { name = "MoveStdlib" }, - { name = "Sui" }, -] - -[[move.package]] -name = "MoveStdlib" -source = { local = "../move-stdlib" } - -[[move.package]] -name = "Sui" -source = { local = "../sui-framework" } - -dependencies = [ - { name = "MoveStdlib" }, -] - -[move.toolchain-version] -compiler-version = "1.22.0" -edition = "legacy" -flavor = "sui" diff --git a/crates/sui-framework/packages/deepbook/Move.toml b/crates/sui-framework/packages/deepbook/Move.toml deleted file mode 100644 index 4dea063cf40..00000000000 --- a/crates/sui-framework/packages/deepbook/Move.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "DeepBook" -version = "0.0.1" -published-at = "0xdee9" -edition = "2024.beta" - -[dependencies] -MoveStdlib = { local = "../move-stdlib" } -Sui = { local = "../sui-framework" } - -[addresses] -deepbook = "0xdee9" diff --git a/crates/sui-framework/packages/deepbook/README.md b/crates/sui-framework/packages/deepbook/README.md deleted file mode 100644 index 0d9bf440013..00000000000 --- a/crates/sui-framework/packages/deepbook/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# DeepBook - -DeepBook is a decentralized central limit order book (CLOB) built for the Sui ecosystem. DeepBook provides a one-stop shop for trading digital assets, with a technical design built for Sui’s architecture. DeepBook leverages Sui’s performance and delivers a low latency and high throughput execution engine to spread liquidity across the DeFi ecosystem. - -Designed as permissionless and released as open source, DeepBook will accelerate the development of financial and other apps on Sui. It will give builders an efficient and shared ready-built financial layer for trading fungible assets. \ No newline at end of file diff --git a/crates/sui-framework/packages/deepbook/sources/math.move b/crates/sui-framework/packages/deepbook/sources/math.move deleted file mode 100644 index de7ab51bcbe..00000000000 --- a/crates/sui-framework/packages/deepbook/sources/math.move +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module deepbook::math { - /// scaling setting for float - const FLOAT_SCALING: u64 = 1_000_000_000; - const FLOAT_SCALING_U128: u128 = 1_000_000_000; - - /* friend deepbook::clob; */ - /* friend deepbook::clob_v2; */ - /* friend deepbook::critbit; */ - - // <<<<<<<<<<<<<<<<<<<<<<<< Error codes <<<<<<<<<<<<<<<<<<<<<<<< - const EUnderflow: u64 = 1; - // <<<<<<<<<<<<<<<<<<<<<<<< Error codes <<<<<<<<<<<<<<<<<<<<<<<< - - // multiply two floating numbers - public(package) fun unsafe_mul(x: u64, y: u64): u64 { - let (_, result) = unsafe_mul_round(x, y); - result - } - - // multiply two floating numbers - // also returns whether the result is rounded down - public(package) fun unsafe_mul_round(x: u64, y: u64): (bool, u64) { - let x = x as u128; - let y = y as u128; - let mut is_round_down = true; - if ((x * y) % FLOAT_SCALING_U128 == 0) is_round_down = false; - (is_round_down, (x * y / FLOAT_SCALING_U128) as u64) - } - - // multiply two floating numbers and assert the result is non zero - // Note that this function will still round down - public fun mul(x: u64, y: u64): u64 { - let (_, result) = unsafe_mul_round(x, y); - assert!(result > 0, EUnderflow); - result - } - - // multiply two floating numbers and assert the result is non zero - // also returns whether the result is rounded down - public fun mul_round(x: u64, y: u64): (bool, u64) { - let (is_round_down, result) = unsafe_mul_round(x, y); - assert!(result > 0, EUnderflow); - (is_round_down, result) - } - - // divide two floating numbers - public(package) fun unsafe_div(x: u64, y: u64): u64 { - let (_, result) = unsafe_div_round(x, y); - result - } - - // divide two floating numbers - // also returns whether the result is rounded down - public(package) fun unsafe_div_round(x: u64, y: u64): (bool, u64) { - let x = x as u128; - let y = y as u128; - let mut is_round_down = true; - if ((x * (FLOAT_SCALING as u128) % y) == 0) is_round_down = false; - (is_round_down, (x * (FLOAT_SCALING as u128) / y) as u64) - } - - // divide two floating numbers and assert the result is non zero - // also returns whether the result is rounded down - public fun div_round(x: u64, y: u64): (bool, u64) { - let (is_round_down, result) = unsafe_div_round(x, y); - assert!(result > 0, EUnderflow); - (is_round_down, result) - } - - public(package) fun count_leading_zeros(mut x: u128): u8 { - if (x == 0) { - 128 - } else { - let mut n: u8 = 0; - if (x & 0xFFFFFFFFFFFFFFFF0000000000000000 == 0) { - // x's higher 64 is all zero, shift the lower part over - x = x << 64; - n = n + 64; - }; - if (x & 0xFFFFFFFF000000000000000000000000 == 0) { - // x's higher 32 is all zero, shift the lower part over - x = x << 32; - n = n + 32; - }; - if (x & 0xFFFF0000000000000000000000000000 == 0) { - // x's higher 16 is all zero, shift the lower part over - x = x << 16; - n = n + 16; - }; - if (x & 0xFF000000000000000000000000000000 == 0) { - // x's higher 8 is all zero, shift the lower part over - x = x << 8; - n = n + 8; - }; - if (x & 0xF0000000000000000000000000000000 == 0) { - // x's higher 4 is all zero, shift the lower part over - x = x << 4; - n = n + 4; - }; - if (x & 0xC0000000000000000000000000000000 == 0) { - // x's higher 2 is all zero, shift the lower part over - x = x << 2; - n = n + 2; - }; - if (x & 0x80000000000000000000000000000000 == 0) { - n = n + 1; - }; - - n - } - } - - #[test_only] use sui::test_utils::assert_eq; - - #[test_only] - fun pow(mut base: u128, mut exponent: u8): u128 { - let mut res: u128 = 1; - while (exponent >= 1) { - if (exponent % 2 == 0) { - base = base * base; - exponent = exponent / 2; - } else { - res = res * base; - exponent = exponent - 1; - } - }; - res - } - - #[test] - fun test_count_leading_zeros() { - let mut i: u8 = 0; - while (i <= 127) { - assert_eq(count_leading_zeros(pow(2, i) as u128), 128 - i - 1); - i = i + 1; - }; - - while (i <= 127) { - assert_eq(count_leading_zeros(pow(2, i) as u128 + 1), 128 - i - 1); - i = i + 1; - }; - assert_eq(count_leading_zeros(0), 128); - } - - #[test] - fun test_mul() { - assert_eq(unsafe_mul(1_000_000_000, 1), 1); - assert_eq(unsafe_mul(9_999_999_999, 1), 9); - assert_eq(unsafe_mul(9_000_000_000, 1), 9); - } - - #[test] - #[expected_failure(abort_code = EUnderflow)] - fun test_mul_underflow() { - mul(999_999_999, 1); - } - - #[test] - #[expected_failure(abort_code = EUnderflow)] - fun test_mul_round_check_underflow() { - mul_round(999_999_999, 1); - } - - #[test] - fun test_mul_round() { - let (mut is_round, mut result) = unsafe_mul_round(1_000_000_000, 1); - assert_eq(is_round, false); - assert_eq(result, 1); - (is_round, result) = unsafe_mul_round(9_999_999_999, 1); - assert_eq(is_round, true); - assert_eq(result, 9); - (is_round, result) = mul_round(9_999_999_999, 1); - assert_eq(is_round, true); - assert_eq(result, 9); - } - - #[test] - fun test_div() { - let (mut is_round, mut result) = unsafe_div_round(1, 1_000_000_000); - assert_eq(is_round, false); - assert_eq(result, 1); - (is_round, result) = unsafe_div_round(1, 9_999_999_999); - assert_eq(is_round, true); - assert_eq(result, 0); - (is_round, result) = unsafe_div_round(1, 999_999_999); - assert_eq(is_round, true); - assert_eq(result, 1); - } - - #[test] - fun test_div_round() { - let (mut is_round, mut result) = unsafe_div_round(1, 1_000_000_000); - assert_eq(is_round, false); - assert_eq(result, 1); - (is_round, result) = unsafe_div_round(1, 9_999_999_999); - assert_eq(is_round, true); - assert_eq(result, 0); - (is_round, result) = unsafe_div_round(1, 999_999_999); - assert_eq(is_round, true); - assert_eq(result, 1); - (is_round, result) = div_round(1, 999_999_999); - assert_eq(is_round, true); - assert_eq(result, 1); - } - - #[test] - #[expected_failure(abort_code = EUnderflow)] - fun test_div_round_check_underflow() { - div_round(1, 1_000_000_001); - } -} diff --git a/crates/sui-framework/packages/move-stdlib/Move.lock b/crates/sui-framework/packages/move-stdlib/Move.lock deleted file mode 100644 index d75b1f6eb48..00000000000 --- a/crates/sui-framework/packages/move-stdlib/Move.lock +++ /dev/null @@ -1,11 +0,0 @@ -# @generated by Move, please check-in and do not edit manually. - -[move] -version = 1 -manifest_digest = "774F1883683AAACD2512A2B6C01188350E10E5A035E065A8CF110CE44A564509" -deps_digest = "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855" - -[move.toolchain-version] -compiler-version = "1.22.0" -edition = "legacy" -flavor = "sui" diff --git a/crates/sui-framework/packages/move-stdlib/sources/address.move b/crates/sui-framework/packages/move-stdlib/sources/address.move deleted file mode 100644 index ec1416b4473..00000000000 --- a/crates/sui-framework/packages/move-stdlib/sources/address.move +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Provides a way to get address length since it's a -/// platform-specific parameter. -module std::address { - /// Should be converted to a native function. - /// Current implementation only works for Sui. - public fun length(): u64 { - 32 - } -} diff --git a/crates/sui-framework/packages/move-stdlib/sources/ascii.move b/crates/sui-framework/packages/move-stdlib/sources/ascii.move deleted file mode 100644 index d037e74b4cb..00000000000 --- a/crates/sui-framework/packages/move-stdlib/sources/ascii.move +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// The `ASCII` module defines basic string and char newtypes in Move that verify -/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. -module std::ascii { - use std::option::{Self, Option}; - - // Allows calling `.to_string()` to convert an `ascii::String` into as `string::String` - public use fun std::string::from_ascii as String.to_string; - - /// An invalid ASCII character was encountered when creating an ASCII string. - const EINVALID_ASCII_CHARACTER: u64 = 0x10000; - - /// The `String` struct holds a vector of bytes that all represent - /// valid ASCII characters. Note that these ASCII characters may not all - /// be printable. To determine if a `String` contains only "printable" - /// characters you should use the `all_characters_printable` predicate - /// defined in this module. - public struct String has copy, drop, store { - bytes: vector, - } - - /// An ASCII character. - public struct Char has copy, drop, store { - byte: u8, - } - - /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. - public fun char(byte: u8): Char { - assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); - Char { byte } - } - - /// Convert a vector of bytes `bytes` into an `String`. Aborts if - /// `bytes` contains non-ASCII characters. - public fun string(bytes: vector): String { - let x = try_string(bytes); - assert!(x.is_some(), EINVALID_ASCII_CHARACTER); - x.destroy_some() - } - - /// Convert a vector of bytes `bytes` into an `String`. Returns - /// `Some()` if the `bytes` contains all valid ASCII - /// characters. Otherwise returns `None`. - public fun try_string(bytes: vector): Option { - let len = bytes.length(); - let mut i = 0; - while (i < len) { - let possible_byte = bytes[i]; - if (!is_valid_char(possible_byte)) return option::none(); - i = i + 1; - }; - option::some(String { bytes }) - } - - /// Returns `true` if all characters in `string` are printable characters - /// Returns `false` otherwise. Not all `String`s are printable strings. - public fun all_characters_printable(string: &String): bool { - let len = string.bytes.length(); - let mut i = 0; - while (i < len) { - let byte = string.bytes[i]; - if (!is_printable_char(byte)) return false; - i = i + 1; - }; - true - } - - public fun push_char(string: &mut String, char: Char) { - string.bytes.push_back(char.byte); - } - - public fun pop_char(string: &mut String): Char { - Char { byte: string.bytes.pop_back() } - } - - public fun length(string: &String): u64 { - string.as_bytes().length() - } - - /// Get the inner bytes of the `string` as a reference - public fun as_bytes(string: &String): &vector { - &string.bytes - } - - /// Unpack the `string` to get its backing bytes - public fun into_bytes(string: String): vector { - let String { bytes } = string; - bytes - } - - /// Unpack the `char` into its underlying byte. - public fun byte(char: Char): u8 { - let Char { byte } = char; - byte - } - - /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. - public fun is_valid_char(b: u8): bool { - b <= 0x7F - } - - /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. - public fun is_printable_char(byte: u8): bool { - byte >= 0x20 && // Disallow metacharacters - byte <= 0x7E // Don't allow DEL metacharacter - } -} diff --git a/crates/sui-framework/packages/move-stdlib/sources/bcs.move b/crates/sui-framework/packages/move-stdlib/sources/bcs.move deleted file mode 100644 index 8e07273cf1e..00000000000 --- a/crates/sui-framework/packages/move-stdlib/sources/bcs.move +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Utility for converting a Move value to its binary representation in BCS (Binary Canonical -/// Serialization). BCS is the binary encoding for Move resources and other non-module values -/// published on-chain. See https://github.com/diem/bcs#binary-canonical-serialization-bcs for more -/// details on BCS. -module std::bcs { - /// Return the binary representation of `v` in BCS (Binary Canonical Serialization) format - native public fun to_bytes(v: &MoveValue): vector; -} diff --git a/crates/sui-framework/packages/move-stdlib/sources/hash.move b/crates/sui-framework/packages/move-stdlib/sources/hash.move deleted file mode 100644 index ed84f18a9a7..00000000000 --- a/crates/sui-framework/packages/move-stdlib/sources/hash.move +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Module which defines SHA hashes for byte vectors. -/// -/// The functions in this module are natively declared both in the Move runtime -/// as in the Move prover's prelude. -module std::hash { - native public fun sha2_256(data: vector): vector; - native public fun sha3_256(data: vector): vector; -} diff --git a/crates/sui-framework/packages/move-stdlib/sources/string.move b/crates/sui-framework/packages/move-stdlib/sources/string.move deleted file mode 100644 index ac6adb0e4a4..00000000000 --- a/crates/sui-framework/packages/move-stdlib/sources/string.move +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// The `string` module defines the `String` type which represents UTF8 encoded strings. -module std::string { - use std::ascii; - use std::option::{Self, Option}; - - /// An invalid UTF8 encoding. - const EINVALID_UTF8: u64 = 1; - - /// Index out of range. - const EINVALID_INDEX: u64 = 2; - - /// A `String` holds a sequence of bytes which is guaranteed to be in utf8 format. - public struct String has copy, drop, store { - bytes: vector, - } - - /// Creates a new string from a sequence of bytes. Aborts if the bytes do not represent valid utf8. - public fun utf8(bytes: vector): String { - assert!(internal_check_utf8(&bytes), EINVALID_UTF8); - String { bytes } - } - - /// Convert an ASCII string to a UTF8 string - public fun from_ascii(s: ascii::String): String { - String { bytes: ascii::into_bytes(s) } - } - - /// Convert an UTF8 string to an ASCII string. - /// Aborts if `s` is not valid ASCII - public fun to_ascii(s: String): ascii::String { - let String { bytes } = s; - ascii::string(bytes) - } - - /// Tries to create a new string from a sequence of bytes. - public fun try_utf8(bytes: vector): Option { - if (internal_check_utf8(&bytes)) { - option::some(String { bytes }) - } else { - option::none() - } - } - - /// Returns a reference to the underlying byte vector. - public fun bytes(s: &String): &vector { - &s.bytes - } - - /// Checks whether this string is empty. - public fun is_empty(s: &String): bool { - s.bytes.is_empty() - } - - /// Returns the length of this string, in bytes. - public fun length(s: &String): u64 { - s.bytes.length() - } - - /// Appends a string. - public fun append(s: &mut String, r: String) { - s.bytes.append(r.bytes) - } - - /// Appends bytes which must be in valid utf8 format. - public fun append_utf8(s: &mut String, bytes: vector) { - s.append(utf8(bytes)) - } - - /// Insert the other string at the byte index in given string. The index must be at a valid utf8 char - /// boundary. - public fun insert(s: &mut String, at: u64, o: String) { - let bytes = &s.bytes; - assert!(at <= bytes.length() && internal_is_char_boundary(bytes, at), EINVALID_INDEX); - let l = s.length(); - let mut front = s.sub_string(0, at); - let end = s.sub_string(at, l); - front.append(o); - front.append(end); - *s = front; - } - - /// Returns a sub-string using the given byte indices, where `i` is the first byte position and `j` is the start - /// of the first byte not included (or the length of the string). The indices must be at valid utf8 char boundaries, - /// guaranteeing that the result is valid utf8. - public fun sub_string(s: &String, i: u64, j: u64): String { - let bytes = &s.bytes; - let l = bytes.length(); - assert!( - j <= l && i <= j && internal_is_char_boundary(bytes, i) && internal_is_char_boundary(bytes, j), - EINVALID_INDEX - ); - String{bytes: internal_sub_string(bytes, i, j)} - } - - /// Computes the index of the first occurrence of a string. Returns `length(s)` if no occurrence found. - public fun index_of(s: &String, r: &String): u64 { - internal_index_of(&s.bytes, &r.bytes) - } - - // Native API - - native fun internal_check_utf8(v: &vector): bool; - native fun internal_is_char_boundary(v: &vector, i: u64): bool; - native fun internal_sub_string(v: &vector, i: u64, j: u64): vector; - native fun internal_index_of(v: &vector, r: &vector): u64; -} diff --git a/crates/sui-framework/packages/move-stdlib/tests/hash_tests.move b/crates/sui-framework/packages/move-stdlib/tests/hash_tests.move deleted file mode 100644 index 3cb1b303df8..00000000000 --- a/crates/sui-framework/packages/move-stdlib/tests/hash_tests.move +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[test_only] -module std::hash_tests { - use std::hash; - - #[test] - fun sha2_256_expected_hash() { - let input = x"616263"; - let expected_output = x"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; - assert!(hash::sha2_256(input) == expected_output, 0); - } - - #[test] - fun sha3_256_expected_hash() { - let input = x"616263"; - let expected_output = x"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"; - assert!(hash::sha3_256(input) == expected_output, 0); - } -} diff --git a/crates/sui-framework/packages/stardust/Move.lock b/crates/sui-framework/packages/stardust/Move.lock deleted file mode 100644 index 1281a6d529e..00000000000 --- a/crates/sui-framework/packages/stardust/Move.lock +++ /dev/null @@ -1,28 +0,0 @@ -# @generated by Move, please check-in and do not edit manually. - -[move] -version = 0 -manifest_digest = "6C1F0F55CC88971254EA38AAC647E0C39D902AAF2D67AC59A332B50B8EDDE68E" -deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600" - -dependencies = [ - { name = "MoveStdlib" }, - { name = "Sui" }, -] - -[[move.package]] -name = "MoveStdlib" -source = { local = "../move-stdlib" } - -[[move.package]] -name = "Sui" -source = { local = "../sui-framework" } - -dependencies = [ - { name = "MoveStdlib" }, -] - -[move.toolchain-version] -compiler-version = "1.22.0" -edition = "legacy" -flavor = "sui" diff --git a/crates/sui-framework/packages/stardust/Move.toml b/crates/sui-framework/packages/stardust/Move.toml deleted file mode 100644 index 1edd71c2948..00000000000 --- a/crates/sui-framework/packages/stardust/Move.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "Stardust" -version = "0.0.1" -published-at = "0x107a" -edition = "2024.beta" - -[dependencies] -MoveStdlib = { local = "../move-stdlib" } -Sui = { local = "../sui-framework" } - -[addresses] -stardust = "0x107a" diff --git a/crates/sui-framework/packages/sui-framework/Move.lock b/crates/sui-framework/packages/sui-framework/Move.lock deleted file mode 100644 index e38ac909eb1..00000000000 --- a/crates/sui-framework/packages/sui-framework/Move.lock +++ /dev/null @@ -1,19 +0,0 @@ -# @generated by Move, please check-in and do not edit manually. - -[move] -version = 1 -manifest_digest = "ED5DEFBBF556EE89312E639A53F21DE24320F9B13C2087D3BFE2989D5B2B5DAF" -deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082" - -dependencies = [ - { name = "MoveStdlib" }, -] - -[[move.package]] -name = "MoveStdlib" -source = { local = "../move-stdlib" } - -[move.toolchain-version] -compiler-version = "1.22.0" -edition = "legacy" -flavor = "sui" diff --git a/crates/sui-framework/packages/sui-framework/Move.toml b/crates/sui-framework/packages/sui-framework/Move.toml deleted file mode 100644 index 4484ab644fb..00000000000 --- a/crates/sui-framework/packages/sui-framework/Move.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "Sui" -version = "0.0.1" -published-at = "0x2" -edition = "2024.beta" - -[dependencies] -MoveStdlib = { local = "../move-stdlib" } - -[addresses] -sui = "0x2" diff --git a/crates/sui-framework/packages/sui-framework/sources/address.move b/crates/sui-framework/packages/sui-framework/sources/address.move deleted file mode 100644 index 129908910df..00000000000 --- a/crates/sui-framework/packages/sui-framework/sources/address.move +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[defines_primitive(address)] -module sui::address { - use sui::hex; - use std::ascii; - use std::bcs; - use std::string; - - /// Allows calling `.to_id()` on an address to get its `ID`. - public use fun sui::object::id_from_address as address.to_id; - - /// The length of an address, in bytes - const LENGTH: u64 = 32; - - // The largest integer that can be represented with 32 bytes: 2^(8*32) - 1 - const MAX: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935; - - #[allow(unused_const)] - /// Error from `from_bytes` when it is supplied too many or too few bytes. - const EAddressParseError: u64 = 0; - - /// Convert `a` into a u256 by interpreting `a` as the bytes of a big-endian integer - /// (e.g., `to_u256(0x1) == 1`) - public native fun to_u256(a: address): u256; - - /// Convert `n` into an address by encoding it as a big-endian integer (e.g., `from_u256(1) = @0x1`) - /// Aborts if `n` > `MAX_ADDRESS` - public native fun from_u256(n: u256): address; - - /// Convert `bytes` into an address. - /// Aborts with `EAddressParseError` if the length of `bytes` is not 32 - public native fun from_bytes(bytes: vector): address; - - /// Convert `a` into BCS-encoded bytes. - public fun to_bytes(a: address): vector { - bcs::to_bytes(&a) - } - - /// Convert `a` to a hex-encoded ASCII string - public fun to_ascii_string(a: address): ascii::String { - hex::encode(to_bytes(a)).to_ascii_string() - } - - /// Convert `a` to a hex-encoded string - public fun to_string(a: address): string::String { - to_ascii_string(a).to_string() - } - - /// Converts an ASCII string to an address, taking the numerical value for each character. The - /// string must be Base16 encoded, and thus exactly 64 characters long. - /// For example, the string "00000000000000000000000000000000000000000000000000000000DEADB33F" - /// will be converted to the address @0xDEADB33F. - /// Aborts with `EAddressParseError` if the length of `s` is not 64, - /// or if an invalid character is encountered. - public fun from_ascii_bytes(bytes: &vector): address { - assert!(bytes.length() == 64, EAddressParseError); - let mut hex_bytes = vector[]; - let mut i = 0; - while (i < 64) { - let hi = hex_char_value(bytes[i]); - let lo = hex_char_value(bytes[i+1]); - hex_bytes.push_back((hi << 4) | lo); - i = i + 2; - }; - from_bytes(hex_bytes) - } - - fun hex_char_value(c: u8): u8 { - if (c >= 48 && c <= 57) c - 48 // 0-9 - else if (c >= 65 && c <= 70) c - 55 // A-F - else if (c >= 97 && c <= 102) c - 87 // a-f - else abort EAddressParseError - } - - /// Length of a Sui address in bytes - public fun length(): u64 { - LENGTH - } - - /// Largest possible address - public fun max(): u256 { - MAX - } -} diff --git a/crates/sui-framework/packages/sui-framework/sources/bcs.move b/crates/sui-framework/packages/sui-framework/sources/bcs.move deleted file mode 100644 index ff99c7790c7..00000000000 --- a/crates/sui-framework/packages/sui-framework/sources/bcs.move +++ /dev/null @@ -1,460 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// This module implements BCS (de)serialization in Move. -/// Full specification can be found here: https://github.com/diem/bcs -/// -/// Short summary (for Move-supported types): -/// -/// - address - sequence of X bytes -/// - bool - byte with 0 or 1 -/// - u8 - a single u8 byte -/// - u64 / u128 / u256 - LE bytes -/// - vector - ULEB128 length + LEN elements -/// - option - first byte bool: None (0) or Some (1), then value -/// -/// Usage example: -/// ``` -/// /// This function reads u8 and u64 value from the input -/// /// and returns the rest of the bytes. -/// fun deserialize(bytes: vector): (u8, u64, vector) { -/// use sui::bcs::{Self, BCS}; -/// -/// let prepared: BCS = bcs::new(bytes); -/// let (u8_value, u64_value) = ( -/// prepared.peel_u8(), -/// prepared.peel_u64() -/// ); -/// -/// // unpack bcs struct -/// let leftovers = prepared.into_remainder_bytes(); -/// -/// (u8_value, u64_value, leftovers) -/// } -/// ``` -module sui::bcs { - use sui::address; - use std::bcs; - - /// For when bytes length is less than required for deserialization. - const EOutOfRange: u64 = 0; - /// For when the boolean value different than `0` or `1`. - const ENotBool: u64 = 1; - /// For when ULEB byte is out of range (or not found). - const ELenOutOfRange: u64 = 2; - - /// A helper struct that saves resources on operations. For better - /// vector performance, it stores reversed bytes of the BCS and - /// enables use of `vector::pop_back`. - public struct BCS has store, copy, drop { - bytes: vector - } - - /// Get BCS serialized bytes for any value. - /// Re-exports stdlib `bcs::to_bytes`. - public fun to_bytes(value: &T): vector { - bcs::to_bytes(value) - } - - /// Creates a new instance of BCS wrapper that holds inversed - /// bytes for better performance. - public fun new(mut bytes: vector): BCS { - bytes.reverse(); - BCS { bytes } - } - - /// Unpack the `BCS` struct returning the leftover bytes. - /// Useful for passing the data further after partial deserialization. - public fun into_remainder_bytes(bcs: BCS): vector { - let BCS { mut bytes } = bcs; - bytes.reverse(); - bytes - } - - /// Read address from the bcs-serialized bytes. - public fun peel_address(bcs: &mut BCS): address { - assert!(bcs.bytes.length() >= address::length(), EOutOfRange); - let (mut addr_bytes, mut i) = (vector[], 0); - while (i < address::length()) { - addr_bytes.push_back(bcs.bytes.pop_back()); - i = i + 1; - }; - address::from_bytes(addr_bytes) - } - - /// Read a `bool` value from bcs-serialized bytes. - public fun peel_bool(bcs: &mut BCS): bool { - let value = bcs.peel_u8(); - if (value == 0) { - false - } else if (value == 1) { - true - } else { - abort ENotBool - } - } - - /// Read `u8` value from bcs-serialized bytes. - public fun peel_u8(bcs: &mut BCS): u8 { - assert!(bcs.bytes.length() >= 1, EOutOfRange); - bcs.bytes.pop_back() - } - - /// Read `u64` value from bcs-serialized bytes. - public fun peel_u64(bcs: &mut BCS): u64 { - assert!(bcs.bytes.length() >= 8, EOutOfRange); - - let (mut value, mut i) = (0u64, 0u8); - while (i < 64) { - let byte = bcs.bytes.pop_back() as u64; - value = value + (byte << i); - i = i + 8; - }; - - value - } - - /// Read `u128` value from bcs-serialized bytes. - public fun peel_u128(bcs: &mut BCS): u128 { - assert!(bcs.bytes.length() >= 16, EOutOfRange); - - let (mut value, mut i) = (0u128, 0u8); - while (i < 128) { - let byte = bcs.bytes.pop_back() as u128; - value = value + (byte << i); - i = i + 8; - }; - - value - } - - /// Read `u256` value from bcs-serialized bytes. - public fun peel_u256(bcs: &mut BCS): u256 { - assert!(bcs.bytes.length() >= 32, EOutOfRange); - - let (mut value, mut i) = (0u256, 0u16); - while (i < 256) { - let byte = bcs.bytes.pop_back() as u256; - value = value + (byte << (i as u8)); - i = i + 8; - }; - - value - } - - // === Vector === - - /// Read ULEB bytes expecting a vector length. Result should - /// then be used to perform `peel_*` operation LEN times. - /// - /// In BCS `vector` length is implemented with ULEB128; - /// See more here: https://en.wikipedia.org/wiki/LEB128 - public fun peel_vec_length(bcs: &mut BCS): u64 { - let (mut total, mut shift, mut len) = (0u64, 0, 0); - while (true) { - assert!(len <= 4, ELenOutOfRange); - let byte = bcs.bytes.pop_back() as u64; - len = len + 1; - total = total | ((byte & 0x7f) << shift); - if ((byte & 0x80) == 0) { - break - }; - shift = shift + 7; - }; - total - } - - /// Peel a vector of `address` from serialized bytes. - public fun peel_vec_address(bcs: &mut BCS): vector
    { - let (len, mut i, mut res) = (bcs.peel_vec_length(), 0, vector[]); - while (i < len) { - res.push_back(bcs.peel_address()); - i = i + 1; - }; - res - } - - /// Peel a vector of `address` from serialized bytes. - public fun peel_vec_bool(bcs: &mut BCS): vector { - let (len, mut i, mut res) = (bcs.peel_vec_length(), 0, vector[]); - while (i < len) { - res.push_back(bcs.peel_bool()); - i = i + 1; - }; - res - } - - /// Peel a vector of `u8` (eg string) from serialized bytes. - public fun peel_vec_u8(bcs: &mut BCS): vector { - let (len, mut i, mut res) = (bcs.peel_vec_length(), 0, vector[]); - while (i < len) { - res.push_back(bcs.peel_u8()); - i = i + 1; - }; - res - } - - /// Peel a `vector>` (eg vec of string) from serialized bytes. - public fun peel_vec_vec_u8(bcs: &mut BCS): vector> { - let (len, mut i, mut res) = (bcs.peel_vec_length(), 0, vector[]); - while (i < len) { - res.push_back(bcs.peel_vec_u8()); - i = i + 1; - }; - res - } - - /// Peel a vector of `u64` from serialized bytes. - public fun peel_vec_u64(bcs: &mut BCS): vector { - let (len, mut i, mut res) = (bcs.peel_vec_length(), 0, vector[]); - while (i < len) { - res.push_back(bcs.peel_u64()); - i = i + 1; - }; - res - } - - /// Peel a vector of `u128` from serialized bytes. - public fun peel_vec_u128(bcs: &mut BCS): vector { - let (len, mut i, mut res) = (bcs.peel_vec_length(), 0, vector[]); - while (i < len) { - res.push_back(bcs.peel_u128()); - i = i + 1; - }; - res - } - - // === Option === - - /// Peel `Option
    ` from serialized bytes. - public fun peel_option_address(bcs: &mut BCS): Option
    { - if (bcs.peel_bool()) { - option::some(bcs.peel_address()) - } else { - option::none() - } - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_bool(bcs: &mut BCS): Option { - if (bcs.peel_bool()) { - option::some(bcs.peel_bool()) - } else { - option::none() - } - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u8(bcs: &mut BCS): Option { - if (bcs.peel_bool()) { - option::some(bcs.peel_u8()) - } else { - option::none() - } - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u64(bcs: &mut BCS): Option { - if (bcs.peel_bool()) { - option::some(bcs.peel_u64()) - } else { - option::none() - } - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u128(bcs: &mut BCS): Option { - if (bcs.peel_bool()) { - option::some(bcs.peel_u128()) - } else { - option::none() - } - } - - // === Tests === - - #[test_only] - public struct Info has drop { a: bool, b: u8, c: u64, d: u128, k: vector, s: address } - - #[test] - #[expected_failure(abort_code = ELenOutOfRange)] - fun test_uleb_len_fail() { - let value = vector[0xff, 0xff, 0xff, 0xff, 0xff]; - let mut bytes = new(to_bytes(&value)); - let _fail = bytes.peel_vec_length(); - abort 2 // TODO: make this test fail - } - - #[test] - #[expected_failure(abort_code = ENotBool)] - fun test_bool_fail() { - let mut bytes = new(to_bytes(&10u8)); - let _fail = bytes.peel_bool(); - } - - #[test] - fun test_option() { - { - let value = option::some(true); - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_option_bool(), 0); - }; - - { - let value = option::some(10u8); - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_option_u8(), 0); - }; - - { - let value = option::some(10000u64); - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_option_u64(), 0); - }; - - { - let value = option::some(10000999999u128); - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_option_u128(), 0); - }; - - { - let value = option::some(@0xC0FFEE); - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_option_address(), 0); - }; - - { - let value: Option = option::none(); - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_option_bool(), 0); - }; - } - - #[test] - fun test_bcs() { - { - let value = @0xC0FFEE; - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_address(), 0); - }; - - { // boolean: true - let value = true; - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_bool(), 0); - }; - - { // boolean: false - let value = false; - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_bool(), 0); - }; - - { // u8 - let value = 100u8; - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_u8(), 0); - }; - - { // u64 (4 bytes) - let value = 1000100u64; - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_u64(), 0); - }; - - { // u64 (8 bytes) - let value = 100000000000000u64; - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_u64(), 0); - }; - - { // u128 (16 bytes) - let value = 100000000000000000000000000u128; - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_u128(), 0); - }; - - { // vector length - let value = vector[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; - let mut bytes = new(to_bytes(&value)); - assert!(value.length() == bytes.peel_vec_length(), 0); - }; - - { // vector length (more data) - let value = vector[ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - ]; - - let mut bytes = new(to_bytes(&value)); - assert!(value.length() == bytes.peel_vec_length(), 0); - }; - - { // full deserialization test (ordering) - let info = Info { a: true, b: 100, c: 9999, d: 112333, k: vector[true, false, true, false], s: @0xAAAAAAAAAAA }; - let mut bytes = new(to_bytes(&info)); - - assert!(info.a == bytes.peel_bool(), 0); - assert!(info.b == bytes.peel_u8(), 0); - assert!(info.c == bytes.peel_u64(), 0); - assert!(info.d == bytes.peel_u128(), 0); - - let len = bytes.peel_vec_length(); - - assert!(info.k.length() == len, 0); - - let mut i = 0; - while (i < info.k.length()) { - assert!(info.k[i] == bytes.peel_bool(), 0); - i = i + 1; - }; - - assert!(info.s == bytes.peel_address(), 0); - }; - - { // read vector of bytes directly - let value = vector[ - vector[1,2,3,4,5], - vector[1,2,3,4,5], - vector[1,2,3,4,5] - ]; - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_vec_vec_u8(), 0); - }; - - { // read vector of bytes directly - let value = vector[1,2,3,4,5]; - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_vec_u8(), 0); - }; - - { // read vector of bytes directly - let value = vector[1,2,3,4,5]; - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_vec_u64(), 0); - }; - - { // read vector of bytes directly - let value = vector[1,2,3,4,5]; - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_vec_u128(), 0); - }; - - { // read vector of bytes directly - let value = vector[true, false, true, false]; - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_vec_bool(), 0); - }; - - { // read vector of address directly - let value = vector[@0x0, @0x1, @0x2, @0x3]; - let mut bytes = new(to_bytes(&value)); - assert!(value == bytes.peel_vec_address(), 0); - }; - } -} diff --git a/crates/sui-framework/packages/sui-framework/sources/clock.move b/crates/sui-framework/packages/sui-framework/sources/clock.move deleted file mode 100644 index 72e661e5ba4..00000000000 --- a/crates/sui-framework/packages/sui-framework/sources/clock.move +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// APIs for accessing time from move calls, via the `Clock`: a unique -/// shared object that is created at 0x6 during genesis. -module sui::clock { - - /// Sender is not @0x0 the system address. - const ENotSystemAddress: u64 = 0; - - /// Singleton shared object that exposes time to Move calls. This - /// object is found at address 0x6, and can only be read (accessed - /// via an immutable reference) by entry functions. - /// - /// Entry Functions that attempt to accept `Clock` by mutable - /// reference or value will fail to verify, and honest validators - /// will not sign or execute transactions that use `Clock` as an - /// input parameter, unless it is passed by immutable reference. - public struct Clock has key { - id: UID, - /// The clock's timestamp, which is set automatically by a - /// system transaction every time consensus commits a - /// schedule, or by `sui::clock::increment_for_testing` during - /// testing. - timestamp_ms: u64, - } - - /// The `clock`'s current timestamp as a running total of - /// milliseconds since an arbitrary point in the past. - public fun timestamp_ms(clock: &Clock): u64 { - clock.timestamp_ms - } - - #[allow(unused_function)] - /// Create and share the singleton Clock -- this function is - /// called exactly once, during genesis. - fun create(ctx: &TxContext) { - assert!(ctx.sender() == @0x0, ENotSystemAddress); - - transfer::share_object(Clock { - id: object::clock(), - // Initialised to zero, but set to a real timestamp by a - // system transaction before it can be witnessed by a move - // call. - timestamp_ms: 0, - }) - } - - #[allow(unused_function)] - fun consensus_commit_prologue( - clock: &mut Clock, - timestamp_ms: u64, - ctx: &TxContext, - ) { - // Validator will make a special system call with sender set as 0x0. - assert!(ctx.sender() == @0x0, ENotSystemAddress); - - clock.timestamp_ms = timestamp_ms - } - - #[test_only] - /// Expose the functionality of `create()` (usually only done during - /// genesis) for tests that want to create a Clock. - public fun create_for_testing(ctx: &mut TxContext): Clock { - Clock { - id: object::new(ctx), - timestamp_ms: 0, - } - } - - #[test_only] - /// For transactional tests (if a Clock is used as a shared object). - public fun share_for_testing(clock: Clock) { - transfer::share_object(clock) - } - - #[test_only] - public fun increment_for_testing(clock: &mut Clock, tick: u64) { - clock.timestamp_ms = clock.timestamp_ms + tick; - } - - #[test_only] - public fun set_for_testing(clock: &mut Clock, timestamp_ms: u64) { - assert!(timestamp_ms >= clock.timestamp_ms, 0); - clock.timestamp_ms = timestamp_ms; - } - - #[test_only] - public fun destroy_for_testing(clock: Clock) { - let Clock { id, timestamp_ms: _ } = clock; - id.delete(); - } -} diff --git a/crates/sui-framework/packages/sui-framework/sources/coin.move b/crates/sui-framework/packages/sui-framework/sources/coin.move deleted file mode 100644 index 89829325346..00000000000 --- a/crates/sui-framework/packages/sui-framework/sources/coin.move +++ /dev/null @@ -1,448 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Defines the `Coin` type - platform wide representation of fungible -/// tokens and coins. `Coin` can be described as a secure wrapper around -/// `Balance` type. -module sui::coin { - use std::string; - use std::ascii; - use sui::balance::{Self, Balance, Supply}; - use sui::url::{Self, Url}; - use sui::deny_list::{Self, DenyList}; - use std::type_name; - - // Allows calling `.split_vec(amounts, ctx)` on `coin` - public use fun sui::pay::split_vec as Coin.split_vec; - - // Allows calling `.join_vec(coins)` on `coin` - public use fun sui::pay::join_vec as Coin.join_vec; - - // Allows calling `.split_and_transfer(amount, recipient, ctx)` on `coin` - public use fun sui::pay::split_and_transfer as Coin.split_and_transfer; - - // Allows calling `.divide_and_keep(n, ctx)` on `coin` - public use fun sui::pay::divide_and_keep as Coin.divide_and_keep; - - /// A type passed to create_supply is not a one-time witness. - const EBadWitness: u64 = 0; - /// Invalid arguments are passed to a function. - const EInvalidArg: u64 = 1; - /// Trying to split a coin more times than its balance allows. - const ENotEnough: u64 = 2; - - /// A coin of type `T` worth `value`. Transferable and storable - public struct Coin has key, store { - id: UID, - balance: Balance - } - - /// Each Coin type T created through `create_currency` function will have a - /// unique instance of CoinMetadata that stores the metadata for this coin type. - public struct CoinMetadata has key, store { - id: UID, - /// Number of decimal places the coin uses. - /// A coin with `value ` N and `decimals` D should be shown as N / 10^D - /// E.g., a coin with `value` 7002 and decimals 3 should be displayed as 7.002 - /// This is metadata for display usage only. - decimals: u8, - /// Name for the token - name: string::String, - /// Symbol for the token - symbol: ascii::String, - /// Description of the token - description: string::String, - /// URL for the token logo - icon_url: Option - } - - /// Similar to CoinMetadata, but created only for regulated coins that use the DenyList. - /// This object is always immutable. - public struct RegulatedCoinMetadata has key { - id: UID, - /// The ID of the coin's CoinMetadata object. - coin_metadata_object: ID, - /// The ID of the coin's DenyCap object. - deny_cap_object: ID, - } - - /// Capability allowing the bearer to mint and burn - /// coins of type `T`. Transferable - public struct TreasuryCap has key, store { - id: UID, - total_supply: Supply - } - - /// Capability allowing the bearer to freeze addresses, preventing those addresses from - /// interacting with the coin as an input to a transaction. - public struct DenyCap has key, store { - id: UID, - } - - // === Supply <-> TreasuryCap morphing and accessors === - - /// Return the total number of `T`'s in circulation. - public fun total_supply(cap: &TreasuryCap): u64 { - balance::supply_value(&cap.total_supply) - } - - /// Unwrap `TreasuryCap` getting the `Supply`. - /// - /// Operation is irreversible. Supply cannot be converted into a `TreasuryCap` due - /// to different security guarantees (TreasuryCap can be created only once for a type) - public fun treasury_into_supply(treasury: TreasuryCap): Supply { - let TreasuryCap { id, total_supply } = treasury; - id.delete(); - total_supply - } - - /// Get immutable reference to the treasury's `Supply`. - public fun supply_immut(treasury: &TreasuryCap): &Supply { - &treasury.total_supply - } - - /// Get mutable reference to the treasury's `Supply`. - public fun supply_mut(treasury: &mut TreasuryCap): &mut Supply { - &mut treasury.total_supply - } - - // === Balance <-> Coin accessors and type morphing === - - /// Public getter for the coin's value - public fun value(self: &Coin): u64 { - self.balance.value() - } - - /// Get immutable reference to the balance of a coin. - public fun balance(coin: &Coin): &Balance { - &coin.balance - } - - /// Get a mutable reference to the balance of a coin. - public fun balance_mut(coin: &mut Coin): &mut Balance { - &mut coin.balance - } - - /// Wrap a balance into a Coin to make it transferable. - public fun from_balance(balance: Balance, ctx: &mut TxContext): Coin { - Coin { id: object::new(ctx), balance } - } - - /// Destruct a Coin wrapper and keep the balance. - public fun into_balance(coin: Coin): Balance { - let Coin { id, balance } = coin; - id.delete(); - balance - } - - /// Take a `Coin` worth of `value` from `Balance`. - /// Aborts if `value > balance.value` - public fun take( - balance: &mut Balance, value: u64, ctx: &mut TxContext, - ): Coin { - Coin { - id: object::new(ctx), - balance: balance.split(value) - } - } - - /// Put a `Coin` to the `Balance`. - public fun put(balance: &mut Balance, coin: Coin) { - balance.join(into_balance(coin)); - } - - // === Base Coin functionality === - - /// Consume the coin `c` and add its value to `self`. - /// Aborts if `c.value + self.value > U64_MAX` - public entry fun join(self: &mut Coin, c: Coin) { - let Coin { id, balance } = c; - id.delete(); - self.balance.join(balance); - } - - /// Split coin `self` to two coins, one with balance `split_amount`, - /// and the remaining balance is left is `self`. - public fun split( - self: &mut Coin, split_amount: u64, ctx: &mut TxContext - ): Coin { - take(&mut self.balance, split_amount, ctx) - } - - /// Split coin `self` into `n - 1` coins with equal balances. The remainder is left in - /// `self`. Return newly created coins. - public fun divide_into_n( - self: &mut Coin, n: u64, ctx: &mut TxContext - ): vector> { - assert!(n > 0, EInvalidArg); - assert!(n <= value(self), ENotEnough); - - let mut vec = vector[]; - let mut i = 0; - let split_amount = value(self) / n; - while (i < n - 1) { - vec.push_back(self.split(split_amount, ctx)); - i = i + 1; - }; - vec - } - - /// Make any Coin with a zero value. Useful for placeholding - /// bids/payments or preemptively making empty balances. - public fun zero(ctx: &mut TxContext): Coin { - Coin { id: object::new(ctx), balance: balance::zero() } - } - - /// Destroy a coin with value zero - public fun destroy_zero(c: Coin) { - let Coin { id, balance } = c; - id.delete(); - balance.destroy_zero() - } - - // === Registering new coin types and managing the coin supply === - - /// Create a new currency type `T` as and return the `TreasuryCap` for - /// `T` to the caller. Can only be called with a `one-time-witness` - /// type, ensuring that there's only one `TreasuryCap` per `T`. - public fun create_currency( - witness: T, - decimals: u8, - symbol: vector, - name: vector, - description: vector, - icon_url: Option, - ctx: &mut TxContext - ): (TreasuryCap, CoinMetadata) { - // Make sure there's only one instance of the type T - assert!(sui::types::is_one_time_witness(&witness), EBadWitness); - - ( - TreasuryCap { - id: object::new(ctx), - total_supply: balance::create_supply(witness) - }, - CoinMetadata { - id: object::new(ctx), - decimals, - name: string::utf8(name), - symbol: ascii::string(symbol), - description: string::utf8(description), - icon_url - } - ) - } - - /// This creates a new currency, via `create_currency`, but with an extra capability that - /// allows for specific addresses to have their coins frozen. Those addresses cannot interact - /// with the coin as input objects. - public fun create_regulated_currency( - witness: T, - decimals: u8, - symbol: vector, - name: vector, - description: vector, - icon_url: Option, - ctx: &mut TxContext - ): (TreasuryCap, DenyCap, CoinMetadata) { - let (treasury_cap, metadata) = create_currency( - witness, - decimals, - symbol, - name, - description, - icon_url, - ctx - ); - let deny_cap = DenyCap { - id: object::new(ctx), - }; - transfer::freeze_object(RegulatedCoinMetadata { - id: object::new(ctx), - coin_metadata_object: object::id(&metadata), - deny_cap_object: object::id(&deny_cap), - }); - (treasury_cap, deny_cap, metadata) - } - - /// Create a coin worth `value` and increase the total supply - /// in `cap` accordingly. - public fun mint( - cap: &mut TreasuryCap, value: u64, ctx: &mut TxContext, - ): Coin { - Coin { - id: object::new(ctx), - balance: cap.total_supply.increase_supply(value) - } - } - - /// Mint some amount of T as a `Balance` and increase the total - /// supply in `cap` accordingly. - /// Aborts if `value` + `cap.total_supply` >= U64_MAX - public fun mint_balance( - cap: &mut TreasuryCap, value: u64 - ): Balance { - cap.total_supply.increase_supply(value) - } - - /// Destroy the coin `c` and decrease the total supply in `cap` - /// accordingly. - public entry fun burn(cap: &mut TreasuryCap, c: Coin): u64 { - let Coin { id, balance } = c; - id.delete(); - cap.total_supply.decrease_supply(balance) - } - - /// The index into the deny list vector for the `sui::coin::Coin` type. - const DENY_LIST_COIN_INDEX: u64 = 0; // TODO public(package) const - - /// Adds the given address to the deny list, preventing it - /// from interacting with the specified coin type as an input to a transaction. - public fun deny_list_add( - deny_list: &mut DenyList, - _deny_cap: &mut DenyCap, - addr: address, - _ctx: &mut TxContext - ) { - let `type` = - type_name::into_string(type_name::get_with_original_ids()).into_bytes(); - deny_list::add( - deny_list, - DENY_LIST_COIN_INDEX, - `type`, - addr, - ) - } - - /// Removes an address from the deny list. - /// Aborts with `ENotFrozen` if the address is not already in the list. - public fun deny_list_remove( - deny_list: &mut DenyList, - _deny_cap: &mut DenyCap, - addr: address, - _ctx: &mut TxContext - ) { - let `type` = - type_name::into_string(type_name::get_with_original_ids()).into_bytes(); - deny_list::remove( - deny_list, - DENY_LIST_COIN_INDEX, - `type`, - addr, - ) - } - - /// Returns true iff the given address is denied for the given coin type. It will - /// return false if given a non-coin type. - public fun deny_list_contains( - freezer: &DenyList, - addr: address, - ): bool { - let name = type_name::get_with_original_ids(); - if (type_name::is_primitive(&name)) return false; - - let `type` = type_name::into_string(name).into_bytes(); - freezer.contains(DENY_LIST_COIN_INDEX, `type`, addr) - } - - // === Entrypoints === - - /// Mint `amount` of `Coin` and send it to `recipient`. Invokes `mint()`. - public entry fun mint_and_transfer( - c: &mut TreasuryCap, amount: u64, recipient: address, ctx: &mut TxContext - ) { - transfer::public_transfer(mint(c, amount, ctx), recipient) - } - - // === Update coin metadata === - - /// Update name of the coin in `CoinMetadata` - public entry fun update_name( - _treasury: &TreasuryCap, metadata: &mut CoinMetadata, name: string::String - ) { - metadata.name = name; - } - - /// Update the symbol of the coin in `CoinMetadata` - public entry fun update_symbol( - _treasury: &TreasuryCap, metadata: &mut CoinMetadata, symbol: ascii::String - ) { - metadata.symbol = symbol; - } - - /// Update the description of the coin in `CoinMetadata` - public entry fun update_description( - _treasury: &TreasuryCap, metadata: &mut CoinMetadata, description: string::String - ) { - metadata.description = description; - } - - /// Update the url of the coin in `CoinMetadata` - public entry fun update_icon_url( - _treasury: &TreasuryCap, metadata: &mut CoinMetadata, url: ascii::String - ) { - metadata.icon_url = option::some(url::new_unsafe(url)); - } - - // === Get coin metadata fields for on-chain consumption === - - public fun get_decimals(metadata: &CoinMetadata): u8 { - metadata.decimals - } - - public fun get_name(metadata: &CoinMetadata): string::String { - metadata.name - } - - public fun get_symbol(metadata: &CoinMetadata): ascii::String { - metadata.symbol - } - - public fun get_description(metadata: &CoinMetadata): string::String { - metadata.description - } - - public fun get_icon_url(metadata: &CoinMetadata): Option { - metadata.icon_url - } - - // === Test-only code === - - #[test_only] - /// Mint coins of any type for (obviously!) testing purposes only - public fun mint_for_testing(value: u64, ctx: &mut TxContext): Coin { - Coin { id: object::new(ctx), balance: balance::create_for_testing(value) } - } - - #[test_only] - /// Burn coins of any type for testing purposes only - public fun burn_for_testing(coin: Coin): u64 { - let Coin { id, balance } = coin; - id.delete(); - balance.destroy_for_testing() - } - - #[test_only] - /// Create a `TreasuryCap` for any `Coin` for testing purposes. - public fun create_treasury_cap_for_testing( - ctx: &mut TxContext - ): TreasuryCap { - TreasuryCap { - id: object::new(ctx), - total_supply: balance::create_supply_for_testing() - } - } - - // === Deprecated code === - - // oops, wanted treasury: &TreasuryCap - public fun supply(treasury: &mut TreasuryCap): &Supply { - &treasury.total_supply - } - - // deprecated as we have CoinMetadata now - #[allow(unused_field)] - public struct CurrencyCreated has copy, drop { - decimals: u8 - } -} diff --git a/crates/sui-framework/packages/sui-framework/sources/crypto/hash.move b/crates/sui-framework/packages/sui-framework/sources/crypto/hash.move deleted file mode 100644 index 4b2e9d6bc0e..00000000000 --- a/crates/sui-framework/packages/sui-framework/sources/crypto/hash.move +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Module which defines hash functions. Note that Sha-256 and Sha3-256 is available in the std::hash module in the -/// standard library. -module sui::hash { - /// @param data: Arbitrary binary data to hash - /// Hash the input bytes using Blake2b-256 and returns 32 bytes. - native public fun blake2b256(data: &vector): vector; - - /// @param data: Arbitrary binary data to hash - /// Hash the input bytes using keccak256 and returns 32 bytes. - native public fun keccak256(data: &vector): vector; -} diff --git a/crates/sui-framework/packages/sui-framework/sources/display.move b/crates/sui-framework/packages/sui-framework/sources/display.move deleted file mode 100644 index 38f460e890f..00000000000 --- a/crates/sui-framework/packages/sui-framework/sources/display.move +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Defines a Display struct which defines the way an Object -/// should be displayed. The intention is to keep data as independent -/// from its display as possible, protecting the development process -/// and keeping it separate from the ecosystem agreements. -/// -/// Each of the fields of the Display object should allow for pattern -/// substitution and filling-in the pieces using the data from the object T. -/// -/// More entry functions might be added in the future depending on the use cases. -module sui::display { - use sui::package::Publisher; - use sui::vec_map::{Self, VecMap}; - use sui::event; - use std::string::String; - - /// For when T does not belong to the package `Publisher`. - const ENotOwner: u64 = 0; - - /// For when vectors passed into one of the multiple insert functions - /// don't match in their lengths. - const EVecLengthMismatch: u64 = 1; - - /// The Display object. Defines the way a T instance should be - /// displayed. Display object can only be created and modified with - /// a PublisherCap, making sure that the rules are set by the owner - /// of the type. - /// - /// Each of the display properties should support patterns outside - /// of the system, making it simpler to customize Display based - /// on the property values of an Object. - /// ``` - /// // Example of a display object - /// Display<0x...::capy::Capy> { - /// fields: - /// - /// - /// - /// - /// } - /// ``` - /// - /// Uses only String type due to external-facing nature of the object, - /// the property names have a priority over their types. - public struct Display has key, store { - id: UID, - /// Contains fields for display. Currently supported - /// fields are: name, link, image and description. - fields: VecMap, - /// Version that can only be updated manually by the Publisher. - version: u16 - } - - /// Event: emitted when a new Display object has been created for type T. - /// Type signature of the event corresponds to the type while id serves for - /// the discovery. - /// - /// Since Sui RPC supports querying events by type, finding a Display for the T - /// would be as simple as looking for the first event with `Display`. - public struct DisplayCreated has copy, drop { - id: ID - } - - /// Version of Display got updated - - public struct VersionUpdated has copy, drop { - id: ID, - version: u16, - fields: VecMap, - } - - // === Initializer Methods === - - /// Create an empty Display object. It can either be shared empty or filled - /// with data right away via cheaper `set_owned` method. - public fun new(pub: &Publisher, ctx: &mut TxContext): Display { - assert!(is_authorized(pub), ENotOwner); - create_internal(ctx) - } - - /// Create a new Display object with a set of fields. - public fun new_with_fields( - pub: &Publisher, fields: vector, values: vector, ctx: &mut TxContext - ): Display { - let len = fields.length(); - assert!(len == values.length(), EVecLengthMismatch); - - let mut i = 0; - let mut display = new(pub, ctx); - while (i < len) { - display.add_internal(fields[i], values[i]); - i = i + 1; - }; - - display - } - - // === Entry functions: Create === - - #[allow(lint(self_transfer))] - /// Create a new empty Display object and keep it. - entry public fun create_and_keep(pub: &Publisher, ctx: &mut TxContext) { - transfer::public_transfer(new(pub, ctx), ctx.sender()) - } - - /// Manually bump the version and emit an event with the updated version's contents. - entry public fun update_version( - display: &mut Display - ) { - display.version = display.version + 1; - event::emit(VersionUpdated { - version: display.version, - fields: *&display.fields, - id: display.id.to_inner(), - }) - } - - // === Entry functions: Add/Modify fields === - - /// Sets a custom `name` field with the `value`. - entry public fun add(self: &mut Display, name: String, value: String) { - self.add_internal(name, value) - } - - /// Sets multiple `fields` with `values`. - entry public fun add_multiple( - self: &mut Display, fields: vector, values: vector - ) { - let len = fields.length(); - assert!(len == values.length(), EVecLengthMismatch); - - let mut i = 0; - while (i < len) { - self.add_internal(fields[i], values[i]); - i = i + 1; - }; - } - - /// Change the value of the field. - /// TODO (long run): version changes; - entry public fun edit(self: &mut Display, name: String, value: String) { - let (_, _) = self.fields.remove(&name); - self.add_internal(name, value) - } - - /// Remove the key from the Display. - entry public fun remove(self: &mut Display, name: String) { - self.fields.remove(&name); - } - - // === Access fields === - - /// Authorization check; can be performed externally to implement protection rules for Display. - public fun is_authorized(pub: &Publisher): bool { - pub.from_package() - } - - /// Read the `version` field. - public fun version(d: &Display): u16 { - d.version - } - - /// Read the `fields` field. - public fun fields(d: &Display): &VecMap { - &d.fields - } - - // === Private functions === - - /// Internal function to create a new `Display`. - fun create_internal(ctx: &mut TxContext): Display { - let uid = object::new(ctx); - - event::emit(DisplayCreated { - id: uid.to_inner() - }); - - Display { - id: uid, - fields: vec_map::empty(), - version: 0, - } - } - - /// Private method for inserting fields without security checks. - fun add_internal(display: &mut Display, name: String, value: String) { - display.fields.insert(name, value) - } -} - -#[test_only] -module sui::display_tests { - use sui::test_scenario as test; - use std::string::String; - use sui::package; - use sui::display; - - #[allow(unused_field)] - /// An example object. - /// Purely for visibility. - public struct Capy has key { - id: UID, - name: String - } - - /// Test witness type to create a Publisher object. - public struct CAPY has drop {} - - #[test] - fun capy_init() { - let mut test = test::begin(@0x2); - let pub = package::test_claim(CAPY {}, test::ctx(&mut test)); - - // create a new display object - let mut display = display::new(&pub, test::ctx(&mut test)); - - display.add(b"name".to_string(), b"Capy {name}".to_string()); - display.add(b"link".to_string(), b"https://capy.art/capy/{id}".to_string()); - display.add(b"image".to_string(), b"https://api.capy.art/capy/{id}/svg".to_string()); - display.add(b"description".to_string(), b"A Lovely Capy".to_string()); - - pub.burn_publisher(); - transfer::public_transfer(display, @0x2); - test.end(); - } -} diff --git a/crates/sui-framework/packages/sui-framework/sources/math.move b/crates/sui-framework/packages/sui-framework/sources/math.move deleted file mode 100644 index 9f91ff736b4..00000000000 --- a/crates/sui-framework/packages/sui-framework/sources/math.move +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Basic math for nicer programmability -module sui::math { - - /// Return the larger of `x` and `y` - public fun max(x: u64, y: u64): u64 { - if (x > y) { - x - } else { - y - } - } - - /// Return the smaller of `x` and `y` - public fun min(x: u64, y: u64): u64 { - if (x < y) { - x - } else { - y - } - } - - /// Return the absolute value of x - y - public fun diff(x: u64, y: u64): u64 { - if (x > y) { - x - y - } else { - y - x - } - } - - /// Return the value of a base raised to a power - public fun pow(mut base: u64, mut exponent: u8): u64 { - let mut res = 1; - while (exponent >= 1) { - if (exponent % 2 == 0) { - base = base * base; - exponent = exponent / 2; - } else { - res = res * base; - exponent = exponent - 1; - } - }; - - res - } - - /// Get a nearest lower integer Square Root for `x`. Given that this - /// function can only operate with integers, it is impossible - /// to get perfect (or precise) integer square root for some numbers. - /// - /// Example: - /// ``` - /// math::sqrt(9) => 3 - /// math::sqrt(8) => 2 // the nearest lower square root is 4; - /// ``` - /// - /// In integer math, one of the possible ways to get results with more - /// precision is to use higher values or temporarily multiply the - /// value by some bigger number. Ideally if this is a square of 10 or 100. - /// - /// Example: - /// ``` - /// math::sqrt(8) => 2; - /// math::sqrt(8 * 10000) => 282; - /// // now we can use this value as if it was 2.82; - /// // but to get the actual result, this value needs - /// // to be divided by 100 (because sqrt(10000)). - /// - /// - /// math::sqrt(8 * 1000000) => 2828; // same as above, 2828 / 1000 (2.828) - /// ``` - public fun sqrt(x: u64): u64 { - let mut bit = 1u128 << 64; - let mut res = 0u128; - let mut x = x as u128; - - while (bit != 0) { - if (x >= res + bit) { - x = x - (res + bit); - res = (res >> 1) + bit; - } else { - res = res >> 1; - }; - bit = bit >> 2; - }; - - res as u64 - } - - /// Similar to math::sqrt, but for u128 numbers. Get a nearest lower integer Square Root for `x`. Given that this - /// function can only operate with integers, it is impossible - /// to get perfect (or precise) integer square root for some numbers. - /// - /// Example: - /// ``` - /// math::sqrt_u128(9) => 3 - /// math::sqrt_u128(8) => 2 // the nearest lower square root is 4; - /// ``` - /// - /// In integer math, one of the possible ways to get results with more - /// precision is to use higher values or temporarily multiply the - /// value by some bigger number. Ideally if this is a square of 10 or 100. - /// - /// Example: - /// ``` - /// math::sqrt_u128(8) => 2; - /// math::sqrt_u128(8 * 10000) => 282; - /// // now we can use this value as if it was 2.82; - /// // but to get the actual result, this value needs - /// // to be divided by 100 (because sqrt_u128(10000)). - /// - /// - /// math::sqrt_u128(8 * 1000000) => 2828; // same as above, 2828 / 1000 (2.828) - /// ``` - public fun sqrt_u128(x: u128): u128 { - let mut bit = 1u256 << 128; - let mut res = 0u256; - let mut x = x as u256; - - while (bit != 0) { - if (x >= res + bit) { - x = x - (res + bit); - res = (res >> 1) + bit; - } else { - res = res >> 1; - }; - bit = bit >> 2; - }; - - res as u128 - } - - /// Calculate x / y, but round up the result. - public fun divide_and_round_up(x: u64, y: u64): u64 { - if (x % y == 0) { - x / y - } else { - x / y + 1 - } - } -} diff --git a/crates/sui-framework/packages/sui-framework/sources/object.move b/crates/sui-framework/packages/sui-framework/sources/object.move deleted file mode 100644 index 95ebd4522e7..00000000000 --- a/crates/sui-framework/packages/sui-framework/sources/object.move +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Sui object identifiers -module sui::object { - use std::bcs; - use sui::address; - - /* friend sui::clock; */ - /* friend sui::coin; */ - /* friend sui::dynamic_field; */ - /* friend sui::dynamic_object_field; */ - /* friend sui::transfer; */ - /* friend sui::authenticator_state; */ - /* friend sui::random; */ - /* friend sui::deny_list; */ - - /// Allows calling `.to_address` on an `ID` to get an `address`. - public use fun id_to_address as ID.to_address; - - /// Allows calling `.to_bytes` on an `ID` to get a `vector`. - public use fun id_to_bytes as ID.to_bytes; - - /// Allows calling `.as_inner` on a `UID` to get an `&ID`. - public use fun uid_as_inner as UID.as_inner; - - /// Allows calling `.to_inner` on a `UID` to get an `ID`. - public use fun uid_to_inner as UID.to_inner; - - /// Allows calling `.to_address` on a `UID` to get an `address`. - public use fun uid_to_address as UID.to_address; - - /// Allows calling `.to_bytes` on a `UID` to get a `vector`. - public use fun uid_to_bytes as UID.to_bytes; - - /* #[test_only] */ - /* friend sui::test_scenario; */ - - /// The hardcoded ID for the singleton Sui System State Object. - const SUI_SYSTEM_STATE_OBJECT_ID: address = @0x5; - - /// The hardcoded ID for the singleton Clock Object. - const SUI_CLOCK_OBJECT_ID: address = @0x6; - - /// The hardcoded ID for the singleton AuthenticatorState Object. - const SUI_AUTHENTICATOR_STATE_ID: address = @0x7; - - /// The hardcoded ID for the singleton Random Object. - const SUI_RANDOM_ID: address = @0x8; - - /// The hardcoded ID for the singleton DenyList. - const SUI_DENY_LIST_OBJECT_ID: address = @0x403; - - /// Sender is not @0x0 the system address. - const ENotSystemAddress: u64 = 0; - - /// An object ID. This is used to reference Sui Objects. - /// This is *not* guaranteed to be globally unique--anyone can create an `ID` from a `UID` or - /// from an object, and ID's can be freely copied and dropped. - /// Here, the values are not globally unique because there can be multiple values of type `ID` - /// with the same underlying bytes. For example, `object::id(&obj)` can be called as many times - /// as you want for a given `obj`, and each `ID` value will be identical. - public struct ID has copy, drop, store { - // We use `address` instead of `vector` here because `address` has a more - // compact serialization. `address` is serialized as a BCS fixed-length sequence, - // which saves us the length prefix we would pay for if this were `vector`. - // See https://github.com/diem/bcs#fixed-and-variable-length-sequences. - bytes: address - } - - /// Globally unique IDs that define an object's ID in storage. Any Sui Object, that is a struct - /// with the `key` ability, must have `id: UID` as its first field. - /// These are globally unique in the sense that no two values of type `UID` are ever equal, in - /// other words for any two values `id1: UID` and `id2: UID`, `id1` != `id2`. - /// This is a privileged type that can only be derived from a `TxContext`. - /// `UID` doesn't have the `drop` ability, so deleting a `UID` requires a call to `delete`. - public struct UID has store { - id: ID, - } - - // === id === - - /// Get the raw bytes of a `ID` - public fun id_to_bytes(id: &ID): vector { - bcs::to_bytes(&id.bytes) - } - - /// Get the inner bytes of `id` as an address. - public fun id_to_address(id: &ID): address { - id.bytes - } - - /// Make an `ID` from raw bytes. - public fun id_from_bytes(bytes: vector): ID { - address::from_bytes(bytes).to_id() - } - - /// Make an `ID` from an address. - public fun id_from_address(bytes: address): ID { - ID { bytes } - } - - // === uid === - - #[allow(unused_function)] - /// Create the `UID` for the singleton `SuiSystemState` object. - /// This should only be called once from `sui_system`. - fun sui_system_state(ctx: &TxContext): UID { - assert!(ctx.sender() == @0x0, ENotSystemAddress); - UID { - id: ID { bytes: SUI_SYSTEM_STATE_OBJECT_ID }, - } - } - - /// Create the `UID` for the singleton `Clock` object. - /// This should only be called once from `clock`. - public(package) fun clock(): UID { - UID { - id: ID { bytes: SUI_CLOCK_OBJECT_ID } - } - } - - /// Create the `UID` for the singleton `AuthenticatorState` object. - /// This should only be called once from `authenticator_state`. - public(package) fun authenticator_state(): UID { - UID { - id: ID { bytes: SUI_AUTHENTICATOR_STATE_ID } - } - } - - /// Create the `UID` for the singleton `Random` object. - /// This should only be called once from `random`. - public(package) fun randomness_state(): UID { - UID { - id: ID { bytes: SUI_RANDOM_ID } - } - } - - /// Create the `UID` for the singleton `DenyList` object. - /// This should only be called once from `deny_list`. - public(package) fun sui_deny_list_object_id(): UID { - UID { - id: ID { bytes: SUI_DENY_LIST_OBJECT_ID } - } - } - - /// Get the inner `ID` of `uid` - public fun uid_as_inner(uid: &UID): &ID { - &uid.id - } - - /// Get the raw bytes of a `uid`'s inner `ID` - public fun uid_to_inner(uid: &UID): ID { - uid.id - } - - /// Get the raw bytes of a `UID` - public fun uid_to_bytes(uid: &UID): vector { - bcs::to_bytes(&uid.id.bytes) - } - - /// Get the inner bytes of `id` as an address. - public fun uid_to_address(uid: &UID): address { - uid.id.bytes - } - - // === any object === - - /// Create a new object. Returns the `UID` that must be stored in a Sui object. - /// This is the only way to create `UID`s. - public fun new(ctx: &mut TxContext): UID { - UID { - id: ID { bytes: ctx.fresh_object_address() }, - } - } - - /// Delete the object and it's `UID`. This is the only way to eliminate a `UID`. - // This exists to inform Sui of object deletions. When an object - // gets unpacked, the programmer will have to do something with its - // `UID`. The implementation of this function emits a deleted - // system event so Sui knows to process the object deletion - public fun delete(id: UID) { - let UID { id: ID { bytes } } = id; - delete_impl(bytes) - } - - /// Get the underlying `ID` of `obj` - public fun id(obj: &T): ID { - borrow_uid(obj).id - } - - /// Borrow the underlying `ID` of `obj` - public fun borrow_id(obj: &T): &ID { - &borrow_uid(obj).id - } - - /// Get the raw bytes for the underlying `ID` of `obj` - public fun id_bytes(obj: &T): vector { - bcs::to_bytes(&borrow_uid(obj).id) - } - - /// Get the inner bytes for the underlying `ID` of `obj` - public fun id_address(obj: &T): address { - borrow_uid(obj).id.bytes - } - - /// Get the `UID` for `obj`. - /// Safe because Sui has an extra bytecode verifier pass that forces every struct with - /// the `key` ability to have a distinguished `UID` field. - /// Cannot be made public as the access to `UID` for a given object must be privileged, and - /// restrictable in the object's module. - native fun borrow_uid(obj: &T): &UID; - - /// Generate a new UID specifically used for creating a UID from a hash - public(package) fun new_uid_from_hash(bytes: address): UID { - record_new_uid(bytes); - UID { id: ID { bytes } } - } - - // === internal functions === - - // helper for delete - native fun delete_impl(id: address); - - // marks newly created UIDs from hash - native fun record_new_uid(id: address); - - #[test_only] - /// Return the most recent created object ID. - public fun last_created(ctx: &TxContext): ID { - ID { bytes: ctx.last_created_object_id() } - } - -} diff --git a/crates/sui-framework/packages/sui-framework/sources/package.move b/crates/sui-framework/packages/sui-framework/sources/package.move deleted file mode 100644 index 706e94e8a3a..00000000000 --- a/crates/sui-framework/packages/sui-framework/sources/package.move +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Functions for operating on Move packages from within Move: -/// - Creating proof-of-publish objects from one-time witnesses -/// - Administering package upgrades through upgrade policies. -module sui::package { - use std::ascii::String; - use std::type_name; - use sui::types; - - /// Tried to create a `Publisher` using a type that isn't a - /// one-time witness. - const ENotOneTimeWitness: u64 = 0; - /// Tried to set a less restrictive policy than currently in place. - const ETooPermissive: u64 = 1; - /// This `UpgradeCap` has already authorized a pending upgrade. - const EAlreadyAuthorized: u64 = 2; - /// This `UpgradeCap` has not authorized an upgrade. - const ENotAuthorized: u64 = 3; - /// Trying to commit an upgrade to the wrong `UpgradeCap`. - const EWrongUpgradeCap: u64 = 4; - - /// Update any part of the package (function implementations, add new - /// functions or types, change dependencies) - const COMPATIBLE: u8 = 0; - /// Add new functions or types, or change dependencies, existing - /// functions can't change. - const ADDITIVE: u8 = 128; - /// Only be able to change dependencies. - const DEP_ONLY: u8 = 192; - - /// This type can only be created in the transaction that - /// generates a module, by consuming its one-time witness, so it - /// can be used to identify the address that published the package - /// a type originated from. - public struct Publisher has key, store { - id: UID, - package: String, - module_name: String, - } - - /// Capability controlling the ability to upgrade a package. - public struct UpgradeCap has key, store { - id: UID, - /// (Mutable) ID of the package that can be upgraded. - package: ID, - /// (Mutable) The number of upgrades that have been applied - /// successively to the original package. Initially 0. - version: u64, - /// What kind of upgrades are allowed. - policy: u8, - } - - /// Permission to perform a particular upgrade (for a fixed version of - /// the package, bytecode to upgrade with and transitive dependencies to - /// depend against). - /// - /// An `UpgradeCap` can only issue one ticket at a time, to prevent races - /// between concurrent updates or a change in its upgrade policy after - /// issuing a ticket, so the ticket is a "Hot Potato" to preserve forward - /// progress. - public struct UpgradeTicket { - /// (Immutable) ID of the `UpgradeCap` this originated from. - cap: ID, - /// (Immutable) ID of the package that can be upgraded. - package: ID, - /// (Immutable) The policy regarding what kind of upgrade this ticket - /// permits. - policy: u8, - /// (Immutable) SHA256 digest of the bytecode and transitive - /// dependencies that will be used in the upgrade. - digest: vector, - } - - /// Issued as a result of a successful upgrade, containing the - /// information to be used to update the `UpgradeCap`. This is a "Hot - /// Potato" to ensure that it is used to update its `UpgradeCap` before - /// the end of the transaction that performed the upgrade. - public struct UpgradeReceipt { - /// (Immutable) ID of the `UpgradeCap` this originated from. - cap: ID, - /// (Immutable) ID of the package after it was upgraded. - package: ID, - } - - /// Claim a Publisher object. - /// Requires a One-Time-Witness to prove ownership. Due to this - /// constraint there can be only one Publisher object per module - /// but multiple per package (!). - public fun claim(otw: OTW, ctx: &mut TxContext): Publisher { - assert!(types::is_one_time_witness(&otw), ENotOneTimeWitness); - - let tyname = type_name::get_with_original_ids(); - - Publisher { - id: object::new(ctx), - package: tyname.get_address(), - module_name: tyname.get_module(), - } - } - - #[allow(lint(self_transfer))] - /// Claim a Publisher object and send it to transaction sender. - /// Since this function can only be called in the module initializer, - /// the sender is the publisher. - public fun claim_and_keep(otw: OTW, ctx: &mut TxContext) { - sui::transfer::public_transfer(claim(otw, ctx), ctx.sender()) - } - - /// Destroy a Publisher object effectively removing all privileges - /// associated with it. - public fun burn_publisher(self: Publisher) { - let Publisher { id, package: _, module_name: _ } = self; - id.delete(); - } - - /// Check whether type belongs to the same package as the publisher object. - public fun from_package(self: &Publisher): bool { - type_name::get_with_original_ids().get_address() == self.package - } - - /// Check whether a type belongs to the same module as the publisher object. - public fun from_module(self: &Publisher): bool { - let tyname = type_name::get_with_original_ids(); - - (tyname.get_address() == self.package) && (tyname.get_module() == self.module_name) - } - - /// Read the name of the module. - public fun published_module(self: &Publisher): &String { - &self.module_name - } - - /// Read the package address string. - public fun published_package(self: &Publisher): &String { - &self.package - } - - /// The ID of the package that this cap authorizes upgrades for. - /// Can be `0x0` if the cap cannot currently authorize an upgrade - /// because there is already a pending upgrade in the transaction. - /// Otherwise guaranteed to be the latest version of any given - /// package. - public fun upgrade_package(cap: &UpgradeCap): ID { - cap.package - } - - /// The most recent version of the package, increments by one for each - /// successfully applied upgrade. - public fun version(cap: &UpgradeCap): u64 { - cap.version - } - - /// The most permissive kind of upgrade currently supported by this - /// `cap`. - public fun upgrade_policy(cap: &UpgradeCap): u8 { - cap.policy - } - - /// The package that this ticket is authorized to upgrade - public fun ticket_package(ticket: &UpgradeTicket): ID { - ticket.package - } - - /// The kind of upgrade that this ticket authorizes. - public fun ticket_policy(ticket: &UpgradeTicket): u8 { - ticket.policy - } - - /// ID of the `UpgradeCap` that this `receipt` should be used to - /// update. - public fun receipt_cap(receipt: &UpgradeReceipt): ID { - receipt.cap - } - - /// ID of the package that was upgraded to: the latest version of - /// the package, as of the upgrade represented by this `receipt`. - public fun receipt_package(receipt: &UpgradeReceipt): ID { - receipt.package - } - - /// A hash of the package contents for the new version of the - /// package. This ticket only authorizes an upgrade to a package - /// that matches this digest. A package's contents are identified - /// by two things: - /// - /// - modules: [[u8]] a list of the package's module contents - /// - deps: [[u8; 32]] a list of 32 byte ObjectIDs of the - /// package's transitive dependencies - /// - /// A package's digest is calculated as: - /// - /// sha3_256(sort(modules ++ deps)) - public fun ticket_digest(ticket: &UpgradeTicket): &vector { - &ticket.digest - } - - /// Expose the constants representing various upgrade policies - public fun compatible_policy(): u8 { COMPATIBLE } - public fun additive_policy(): u8 { ADDITIVE } - public fun dep_only_policy(): u8 { DEP_ONLY } - - /// Restrict upgrades through this upgrade `cap` to just add code, or - /// change dependencies. - public entry fun only_additive_upgrades(cap: &mut UpgradeCap) { - cap.restrict(ADDITIVE) - } - - /// Restrict upgrades through this upgrade `cap` to just change - /// dependencies. - public entry fun only_dep_upgrades(cap: &mut UpgradeCap) { - cap.restrict(DEP_ONLY) - } - - /// Discard the `UpgradeCap` to make a package immutable. - public entry fun make_immutable(cap: UpgradeCap) { - let UpgradeCap { id, package: _, version: _, policy: _ } = cap; - id.delete(); - } - - /// Issue a ticket authorizing an upgrade to a particular new bytecode - /// (identified by its digest). A ticket will only be issued if one has - /// not already been issued, and if the `policy` requested is at least as - /// restrictive as the policy set out by the `cap`. - /// - /// The `digest` supplied and the `policy` will both be checked by - /// validators when running the upgrade. I.e. the bytecode supplied in - /// the upgrade must have a matching digest, and the changes relative to - /// the parent package must be compatible with the policy in the ticket - /// for the upgrade to succeed. - public fun authorize_upgrade( - cap: &mut UpgradeCap, - policy: u8, - digest: vector - ): UpgradeTicket { - let id_zero = @0x0.to_id(); - assert!(cap.package != id_zero, EAlreadyAuthorized); - assert!(policy >= cap.policy, ETooPermissive); - - let package = cap.package; - cap.package = id_zero; - - UpgradeTicket { - cap: object::id(cap), - package, - policy, - digest, - } - } - - /// Consume an `UpgradeReceipt` to update its `UpgradeCap`, finalizing - /// the upgrade. - public fun commit_upgrade( - cap: &mut UpgradeCap, - receipt: UpgradeReceipt, - ) { - let UpgradeReceipt { cap: cap_id, package } = receipt; - - assert!(object::id(cap) == cap_id, EWrongUpgradeCap); - assert!(cap.package.to_address() == @0x0, ENotAuthorized); - - cap.package = package; - cap.version = cap.version + 1; - } - - #[test_only] - /// Test-only function to claim a Publisher object bypassing OTW check. - public fun test_claim(_: OTW, ctx: &mut TxContext): Publisher { - let tyname = type_name::get_with_original_ids(); - - Publisher { - id: object::new(ctx), - package: tyname.get_address(), - module_name: tyname.get_module(), - } - } - - #[test_only] - /// Test-only function to simulate publishing a package at address - /// `ID`, to create an `UpgradeCap`. - public fun test_publish(package: ID, ctx: &mut TxContext): UpgradeCap { - UpgradeCap { - id: object::new(ctx), - package, - version: 1, - policy: COMPATIBLE, - } - } - - #[test_only] - /// Test-only function that takes the role of the actual `Upgrade` - /// command, converting the ticket for the pending upgrade to a - /// receipt for a completed upgrade. - public fun test_upgrade(ticket: UpgradeTicket): UpgradeReceipt { - let UpgradeTicket { cap, package, policy: _, digest: _ } = ticket; - - // Generate a fake package ID for the upgraded package by - // hashing the existing package and cap ID. - let mut data = cap.to_bytes(); - data.append(package.to_bytes()); - let package = object::id_from_bytes(sui::hash::blake2b256(&data)); - - UpgradeReceipt { - cap, package - } - } - - fun restrict(cap: &mut UpgradeCap, policy: u8) { - assert!(cap.policy <= policy, ETooPermissive); - cap.policy = policy; - } -} diff --git a/crates/sui-framework/packages/sui-framework/sources/prover.move b/crates/sui-framework/packages/sui-framework/sources/prover.move deleted file mode 100644 index e52feb48264..00000000000 --- a/crates/sui-framework/packages/sui-framework/sources/prover.move +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui::prover { -} diff --git a/crates/sui-framework/packages/sui-framework/sources/random.move b/crates/sui-framework/packages/sui-framework/sources/random.move deleted file mode 100644 index 5d2c4fa5d7a..00000000000 --- a/crates/sui-framework/packages/sui-framework/sources/random.move +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// This module provides functionality for generating secure randomness. -module sui::random { - use std::bcs; - use sui::hmac::hmac_sha3_256; - use sui::versioned::{Self, Versioned}; - - // Sender is not @0x0 the system address. - const ENotSystemAddress: u64 = 0; - const EWrongInnerVersion: u64 = 1; - const EInvalidRandomnessUpdate: u64 = 2; - const EInvalidRange: u64 = 3; - const EInvalidLength: u64 = 4; - - const CURRENT_VERSION: u64 = 1; - const RAND_OUTPUT_LEN: u16 = 32; - const U16_MAX: u64 = 0xFFFF; - - /// Singleton shared object which stores the global randomness state. - /// The actual state is stored in a versioned inner field. - public struct Random has key { - id: UID, - // The inner object must never be accessed outside this module as it could be used for accessing global - // randomness via deserialization of RandomInner. - inner: Versioned, - } - - public struct RandomInner has store { - version: u64, - epoch: u64, - randomness_round: u64, - random_bytes: vector, - } - - #[allow(unused_function)] - /// Create and share the Random object. This function is called exactly once, when - /// the Random object is first created. - /// Can only be called by genesis or change_epoch transactions. - fun create(ctx: &mut TxContext) { - assert!(ctx.sender() == @0x0, ENotSystemAddress); - - let version = CURRENT_VERSION; - - let inner = RandomInner { - version, - epoch: ctx.epoch(), - randomness_round: 0, - random_bytes: vector[], - }; - - let self = Random { - id: object::randomness_state(), - inner: versioned::create(version, inner, ctx), - }; - transfer::share_object(self); - } - - #[test_only] - public fun create_for_testing(ctx: &mut TxContext) { - create(ctx); - } - - fun load_inner_mut( - self: &mut Random, - ): &mut RandomInner { - let version = versioned::version(&self.inner); - - // Replace this with a lazy update function when we add a new version of the inner object. - assert!(version == CURRENT_VERSION, EWrongInnerVersion); - let inner: &mut RandomInner = versioned::load_value_mut(&mut self.inner); - assert!(inner.version == version, EWrongInnerVersion); - inner - } - - fun load_inner( - self: &Random, - ): &RandomInner { - let version = versioned::version(&self.inner); - - // Replace this with a lazy update function when we add a new version of the inner object. - assert!(version == CURRENT_VERSION, EWrongInnerVersion); - let inner: &RandomInner = versioned::load_value(&self.inner); - assert!(inner.version == version, EWrongInnerVersion); - inner - } - - #[allow(unused_function)] - /// Record new randomness. Called when executing the RandomnessStateUpdate system - /// transaction. - fun update_randomness_state( - self: &mut Random, - new_round: u64, - new_bytes: vector, - ctx: &TxContext, - ) { - // Validator will make a special system call with sender set as 0x0. - assert!(ctx.sender() == @0x0, ENotSystemAddress); - - // Randomness should only be incremented. - let epoch = ctx.epoch(); - let inner = self.load_inner_mut(); - if (inner.randomness_round == 0 && inner.epoch == 0 && inner.random_bytes.is_empty()) { - // First update should be for round zero. - assert!(new_round == 0, EInvalidRandomnessUpdate); - } else { - // Subsequent updates should either increase epoch or increment randomness_round. - // Note that epoch may increase by more than 1 if an epoch is completed without - // randomness ever being generated in that epoch. - assert!( - (epoch > inner.epoch && new_round == 0) || - (new_round == inner.randomness_round + 1), - EInvalidRandomnessUpdate - ); - }; - - inner.epoch = ctx.epoch(); - inner.randomness_round = new_round; - inner.random_bytes = new_bytes; - } - - #[test_only] - public fun update_randomness_state_for_testing( - self: &mut Random, - new_round: u64, - new_bytes: vector, - ctx: &TxContext, - ) { - self.update_randomness_state(new_round, new_bytes, ctx); - } - - - /// Unique randomness generator, derived from the global randomness. - public struct RandomGenerator has drop { - seed: vector, - counter: u16, - buffer: vector, - } - - /// Create a generator. Can be used to derive up to MAX_U16 * 32 random bytes. - public fun new_generator(r: &Random, ctx: &mut TxContext): RandomGenerator { - let inner = load_inner(r); - let seed = hmac_sha3_256( - &inner.random_bytes, - &ctx.fresh_object_address().to_bytes() - ); - RandomGenerator { seed, counter: 0, buffer: vector[] } - } - - // Get the next block of random bytes. - fun derive_next_block(g: &mut RandomGenerator): vector { - g.counter = g.counter + 1; - hmac_sha3_256(&g.seed, &bcs::to_bytes(&g.counter)) - } - - // Fill the generator's buffer with 32 random bytes. - fun fill_buffer(g: &mut RandomGenerator) { - let next_block = derive_next_block(g); - vector::append(&mut g.buffer, next_block); - } - - /// Generate n random bytes. - public fun generate_bytes(g: &mut RandomGenerator, num_of_bytes: u16): vector { - let mut result = vector[]; - // Append RAND_OUTPUT_LEN size buffers directly without going through the generator's buffer. - let mut num_of_blocks = num_of_bytes / RAND_OUTPUT_LEN; - while (num_of_blocks > 0) { - vector::append(&mut result, derive_next_block(g)); - num_of_blocks = num_of_blocks - 1; - }; - // Fill the generator's buffer if needed. - let num_of_bytes = num_of_bytes as u64; - if (vector::length(&g.buffer) < (num_of_bytes - vector::length(&result))) { - fill_buffer(g); - }; - // Take remaining bytes from the generator's buffer. - while (vector::length(&result) < num_of_bytes) { - vector::push_back(&mut result, vector::pop_back(&mut g.buffer)); - }; - result - } - - // Helper function that extracts the given number of bytes from the random generator and returns it as u256. - // Assumes that the caller has already checked that num_of_bytes is valid. - // TODO: Replace with a macro when we have support for it. - fun u256_from_bytes(g: &mut RandomGenerator, num_of_bytes: u8): u256 { - if (vector::length(&g.buffer) < num_of_bytes as u64) { - fill_buffer(g); - }; - let mut result: u256 = 0; - let mut i = 0; - while (i < num_of_bytes) { - let byte = vector::pop_back(&mut g.buffer); - result = (result << 8) + (byte as u256); - i = i + 1; - }; - result - } - - /// Generate a u256. - public fun generate_u256(g: &mut RandomGenerator): u256 { - u256_from_bytes(g, 32) - } - - /// Generate a u128. - public fun generate_u128(g: &mut RandomGenerator): u128 { - u256_from_bytes(g, 16) as u128 - } - - /// Generate a u64. - public fun generate_u64(g: &mut RandomGenerator): u64 { - u256_from_bytes(g, 8) as u64 - } - - /// Generate a u32. - public fun generate_u32(g: &mut RandomGenerator): u32 { - u256_from_bytes(g, 4) as u32 - } - - /// Generate a u16. - public fun generate_u16(g: &mut RandomGenerator): u16 { - u256_from_bytes(g, 2) as u16 - } - - /// Generate a u8. - public fun generate_u8(g: &mut RandomGenerator): u8 { - u256_from_bytes(g, 1) as u8 - } - - /// Generate a boolean. - public fun generate_bool(g: &mut RandomGenerator): bool { - (u256_from_bytes(g, 1) & 1) == 1 - } - - // Helper function to generate a random u128 in [min, max] using a random number with num_of_bytes bytes. - // Assumes that the caller verified the inputs, and uses num_of_bytes to control the bias (e.g., 8 bytes larger - // than the actual type used by the caller function to limit the bias by 2^{-64}). - // TODO: Replace with a macro when we have support for it. - fun u128_in_range(g: &mut RandomGenerator, min: u128, max: u128, num_of_bytes: u8): u128 { - assert!(min <= max, EInvalidRange); - if (min == max) { - return min - }; - // Pick a random number in [0, max - min] by generating a random number that is larger than max-min, and taking - // the modulo of the random number by the range size. Then add the min to the result to get a number in - // [min, max]. - let range_size = (max - min) as u256 + 1; - let rand = u256_from_bytes(g, num_of_bytes); - min + (rand % range_size as u128) - } - - /// Generate a random u128 in [min, max] (with a bias of 2^{-64}). - public fun generate_u128_in_range(g: &mut RandomGenerator, min: u128, max: u128): u128 { - u128_in_range(g, min, max, 24) - } - - //// Generate a random u64 in [min, max] (with a bias of 2^{-64}). - public fun generate_u64_in_range(g: &mut RandomGenerator, min: u64, max: u64): u64 { - u128_in_range(g, min as u128, max as u128, 16) as u64 - } - - /// Generate a random u32 in [min, max] (with a bias of 2^{-64}). - public fun generate_u32_in_range(g: &mut RandomGenerator, min: u32, max: u32): u32 { - u128_in_range(g, min as u128, max as u128, 12) as u32 - } - - /// Generate a random u16 in [min, max] (with a bias of 2^{-64}). - public fun generate_u16_in_range(g: &mut RandomGenerator, min: u16, max: u16): u16 { - u128_in_range(g, min as u128, max as u128, 10) as u16 - } - - /// Generate a random u8 in [min, max] (with a bias of 2^{-64}). - public fun generate_u8_in_range(g: &mut RandomGenerator, min: u8, max: u8): u8 { - u128_in_range(g, min as u128, max as u128, 9) as u8 - } - - /// Shuffle a vector using the random generator (Fisher–Yates/Knuth shuffle). - public fun shuffle(g: &mut RandomGenerator, v: &mut vector) { - let n = vector::length(v); - if (n == 0) { - return - }; - assert!(n <= U16_MAX, EInvalidLength); - let n = n as u16; - let mut i: u16 = 0; - let end = n - 1; - while (i < end) { - let j = generate_u16_in_range(g, i, end); - vector::swap(v, i as u64, j as u64); - i = i + 1; - }; - } - - #[test_only] - public fun generator_seed(r: &RandomGenerator): &vector { - &r.seed - } - - #[test_only] - public fun generator_counter(r: &RandomGenerator): u16 { - r.counter - } - - #[test_only] - public fun generator_buffer(r: &RandomGenerator): &vector { - &r.buffer - } -} diff --git a/crates/sui-framework/packages/sui-framework/sources/sui.move b/crates/sui-framework/packages/sui-framework/sources/sui.move deleted file mode 100644 index 90c7daab59c..00000000000 --- a/crates/sui-framework/packages/sui-framework/sources/sui.move +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Coin is the token used to pay for gas in Sui. -/// It has 9 decimals, and the smallest unit (10^-9) is called "mist". -module sui::sui { - use sui::balance::Balance; - use sui::coin; - - const EAlreadyMinted: u64 = 0; - /// Sender is not @0x0 the system address. - const ENotSystemAddress: u64 = 1; - - #[allow(unused_const)] - /// The amount of Mist per Sui token based on the fact that mist is - /// 10^-9 of a Sui token - const MIST_PER_SUI: u64 = 1_000_000_000; - - #[allow(unused_const)] - /// The total supply of Sui denominated in whole Sui tokens (10 Billion) - const TOTAL_SUPPLY_SUI: u64 = 10_000_000_000; - - /// The total supply of Sui denominated in Mist (10 Billion * 10^9) - const TOTAL_SUPPLY_MIST: u64 = 10_000_000_000_000_000_000; - - /// Name of the coin - public struct SUI has drop {} - - #[allow(unused_function)] - /// Register the `SUI` Coin to acquire its `Supply`. - /// This should be called only once during genesis creation. - fun new(ctx: &mut TxContext): Balance { - assert!(ctx.sender() == @0x0, ENotSystemAddress); - assert!(ctx.epoch() == 0, EAlreadyMinted); - - let (treasury, metadata) = coin::create_currency( - SUI {}, - 9, - b"SUI", - b"Sui", - // TODO: add appropriate description and logo url - b"", - option::none(), - ctx - ); - transfer::public_freeze_object(metadata); - let mut supply = treasury.treasury_into_supply(); - let total_sui = supply.increase_supply(TOTAL_SUPPLY_MIST); - supply.destroy_supply(); - total_sui - } - - public entry fun transfer(c: coin::Coin, recipient: address) { - transfer::public_transfer(c, recipient) - } -} diff --git a/crates/sui-framework/packages/sui-framework/sources/transfer.move b/crates/sui-framework/packages/sui-framework/sources/transfer.move deleted file mode 100644 index 6843fb9897d..00000000000 --- a/crates/sui-framework/packages/sui-framework/sources/transfer.move +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[allow(unused_const)] -module sui::transfer { - - - /* #[test_only] */ - /* friend sui::test_scenario; */ - - /// This represents the ability to `receive` an object of type `T`. - /// This type is ephemeral per-transaction and cannot be stored on-chain. - /// This does not represent the obligation to receive the object that it - /// references, but simply the ability to receive the object with object ID - /// `id` at version `version` if you can prove mutable access to the parent - /// object during the transaction. - /// Internals of this struct are opaque outside this module. - public struct Receiving has drop { - id: ID, - version: u64, - } - - /// Shared an object that was previously created. Shared objects must currently - /// be constructed in the transaction they are created. - const ESharedNonNewObject: u64 = 0; - - #[allow(unused_const)] - /// Serialization of the object failed. - const EBCSSerializationFailure: u64 = 1; - - #[allow(unused_const)] - /// The object being received is not of the expected type. - const EReceivingObjectTypeMismatch: u64 = 2; - - #[allow(unused_const)] - /// Represents both the case where the object does not exist and the case where the object is not - /// able to be accessed through the parent that is passed-in. - const EUnableToReceiveObject: u64 = 3; - - #[allow(unused_const)] - /// Shared object operations such as wrapping, freezing, and converting to owned are not allowed. - const ESharedObjectOperationNotSupported: u64 = 4; - - - /// Transfer ownership of `obj` to `recipient`. `obj` must have the `key` attribute, - /// which (in turn) ensures that `obj` has a globally unique ID. Note that if the recipient - /// address represents an object ID, the `obj` sent will be inaccessible after the transfer - /// (though they will be retrievable at a future date once new features are added). - /// This function has custom rules performed by the Sui Move bytecode verifier that ensures - /// that `T` is an object defined in the module where `transfer` is invoked. Use - /// `public_transfer` to transfer an object with `store` outside of its module. - public fun transfer(obj: T, recipient: address) { - transfer_impl(obj, recipient) - } - - /// Transfer ownership of `obj` to `recipient`. `obj` must have the `key` attribute, - /// which (in turn) ensures that `obj` has a globally unique ID. Note that if the recipient - /// address represents an object ID, the `obj` sent will be inaccessible after the transfer - /// (though they will be retrievable at a future date once new features are added). - /// The object must have `store` to be transferred outside of its module. - public fun public_transfer(obj: T, recipient: address) { - transfer_impl(obj, recipient) - } - - /// Freeze `obj`. After freezing `obj` becomes immutable and can no longer be transferred or - /// mutated. - /// This function has custom rules performed by the Sui Move bytecode verifier that ensures - /// that `T` is an object defined in the module where `freeze_object` is invoked. Use - /// `public_freeze_object` to freeze an object with `store` outside of its module. - public fun freeze_object(obj: T) { - freeze_object_impl(obj) - } - - /// Freeze `obj`. After freezing `obj` becomes immutable and can no longer be transferred or - /// mutated. - /// The object must have `store` to be frozen outside of its module. - public fun public_freeze_object(obj: T) { - freeze_object_impl(obj) - } - - /// Turn the given object into a mutable shared object that everyone can access and mutate. - /// This is irreversible, i.e. once an object is shared, it will stay shared forever. - /// Aborts with `ESharedNonNewObject` of the object being shared was not created in this - /// transaction. This restriction may be relaxed in the future. - /// This function has custom rules performed by the Sui Move bytecode verifier that ensures - /// that `T` is an object defined in the module where `share_object` is invoked. Use - /// `public_share_object` to share an object with `store` outside of its module. - public fun share_object(obj: T) { - share_object_impl(obj) - } - - /// Turn the given object into a mutable shared object that everyone can access and mutate. - /// This is irreversible, i.e. once an object is shared, it will stay shared forever. - /// Aborts with `ESharedNonNewObject` of the object being shared was not created in this - /// transaction. This restriction may be relaxed in the future. - /// The object must have `store` to be shared outside of its module. - public fun public_share_object(obj: T) { - share_object_impl(obj) - } - - /// Given mutable (i.e., locked) access to the `parent` and a `Receiving` argument - /// referencing an object of type `T` owned by `parent` use the `to_receive` - /// argument to receive and return the referenced owned object of type `T`. - /// This function has custom rules performed by the Sui Move bytecode verifier that ensures - /// that `T` is an object defined in the module where `receive` is invoked. Use - /// `public_receive` to receivne an object with `store` outside of its module. - public fun receive(parent: &mut UID, to_receive: Receiving): T { - let Receiving { - id, - version, - } = to_receive; - receive_impl(parent.to_address(), id, version) - } - - /// Given mutable (i.e., locked) access to the `parent` and a `Receiving` argument - /// referencing an object of type `T` owned by `parent` use the `to_receive` - /// argument to receive and return the referenced owned object of type `T`. - /// The object must have `store` to be received outside of its defining module. - public fun public_receive(parent: &mut UID, to_receive: Receiving): T { - let Receiving { - id, - version, - } = to_receive; - receive_impl(parent.to_address(), id, version) - } - - /// Return the object ID that the given `Receiving` argument references. - public fun receiving_object_id(receiving: &Receiving): ID { - receiving.id - } - - public(package) native fun freeze_object_impl(obj: T); - - public(package) native fun share_object_impl(obj: T); - - public(package) native fun transfer_impl(obj: T, recipient: address); - - native fun receive_impl(parent: address, to_receive: ID, version: u64): T; -} diff --git a/crates/sui-framework/packages/sui-framework/sources/types.move b/crates/sui-framework/packages/sui-framework/sources/types.move deleted file mode 100644 index 64a68a82434..00000000000 --- a/crates/sui-framework/packages/sui-framework/sources/types.move +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Sui types helpers and utilities -module sui::types { - // === one-time witness === - - /// Tests if the argument type is a one-time witness, that is a type with only one instantiation - /// across the entire code base. - public native fun is_one_time_witness(_: &T): bool; -} diff --git a/crates/sui-framework/packages/sui-framework/tests/balance_tests.move b/crates/sui-framework/packages/sui-framework/tests/balance_tests.move deleted file mode 100644 index 9479ad26bda..00000000000 --- a/crates/sui-framework/packages/sui-framework/tests/balance_tests.move +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[test_only] -module sui::coin_balance_tests { - use sui::test_scenario; - use sui::pay; - use sui::coin; - use sui::balance; - use sui::sui::SUI; - - #[test] - fun type_morphing() { - let mut scenario = test_scenario::begin(@0x1); - - let balance = balance::zero(); - let coin = balance.into_coin(scenario.ctx()); - let balance = coin.into_balance(); - - balance.destroy_zero(); - - let mut coin = coin::mint_for_testing(100, scenario.ctx()); - let balance_mut = coin::balance_mut(&mut coin); - let sub_balance = balance_mut.split(50); - - assert!(sub_balance.value() == 50, 0); - assert!(coin.value() == 50, 0); - - let mut balance = coin.into_balance(); - balance.join(sub_balance); - - assert!(balance.value() == 100, 0); - - let coin = balance.into_coin(scenario.ctx()); - pay::keep(coin, scenario.ctx()); - scenario.end(); - } -} diff --git a/crates/sui-framework/packages/sui-framework/tests/crypto/hash_tests.move b/crates/sui-framework/packages/sui-framework/tests/crypto/hash_tests.move deleted file mode 100644 index bd4e554f97b..00000000000 --- a/crates/sui-framework/packages/sui-framework/tests/crypto/hash_tests.move +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[test_only] -module sui::hash_tests { - use sui::hash; - - #[test] - fun test_keccak256_hash() { - let msg = b"hello world!"; - let hashed_msg_bytes = x"57caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd6"; - let hashed_msg = hash::keccak256(&msg); - assert!(hashed_msg == hashed_msg_bytes, 0); - - let empty_msg = b""; - let _ = hash::keccak256(&empty_msg); - let long_msg = b"57caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd6"; - let _ = hash::keccak256(&long_msg); - } - - #[test] - fun test_blake2b256_hash() { - let msg = b"hello world!"; - let hashed_msg_bytes = x"4fccfb4d98d069558aa93e9565f997d81c33b080364efd586e77a433ddffc5e2"; - let hashed_msg = hash::blake2b256(&msg); - assert!(hashed_msg == hashed_msg_bytes, 0); - - let empty_msg = b""; - let _ = hash::blake2b256(&empty_msg); - let long_msg = b"57caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd657caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd6"; - let _ = hash::blake2b256(&long_msg); - } - -} \ No newline at end of file diff --git a/crates/sui-framework/packages/sui-framework/tests/prover_tests.move b/crates/sui-framework/packages/sui-framework/tests/prover_tests.move deleted file mode 100644 index 1c45ebe68eb..00000000000 --- a/crates/sui-framework/packages/sui-framework/tests/prover_tests.move +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[test_only] -module sui::prover_tests { - - public struct Obj has key, store { - id: UID - } - - // ==================================================================== - // Object ownership - // ==================================================================== - - public fun simple_transfer(o: Obj, recipient: address) { - sui::transfer::public_transfer(o, recipient); - } - - public fun simple_share(o: Obj) { - sui::transfer::public_share_object(o) - } - - public fun simple_freeze(o: Obj) { - sui::transfer::public_freeze_object(o) - } - - public fun simple_delete(o: Obj) { - let Obj { id } = o; - id.delete(); - } - - // ==================================================================== - // Dynamic fields - // ==================================================================== - - public fun simple_field_add(o: &mut Obj, n1: u64, v1: u8, n2: u8, v2: u64) { - sui::dynamic_field::add(&mut o.id, n1, v1); - sui::dynamic_field::add(&mut o.id, n2, v2); - } - - public fun simple_field_remove(o: &mut Obj, n1: u64, n2: u8) { - sui::dynamic_field::remove(&mut o.id, n1); - sui::dynamic_field::remove(&mut o.id, n2); - } -} diff --git a/crates/sui-framework/packages/sui-framework/tests/verifier_tests.move b/crates/sui-framework/packages/sui-framework/tests/verifier_tests.move deleted file mode 100644 index f5e103b7f35..00000000000 --- a/crates/sui-framework/packages/sui-framework/tests/verifier_tests.move +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[test_only] -/// Tests if normally illegal (in terms of Sui bytecode verification) code is allowed in tests. -module sui::verifier_tests { - public struct VERIFIER_TESTS has drop {} - - fun init(otw: VERIFIER_TESTS, _: &mut sui::tx_context::TxContext) { - assert!(sui::types::is_one_time_witness(&otw), 0); - } - - #[test] - fun test_init() { - use sui::test_scenario; - let admin = @0xBABE; - - let mut scenario = test_scenario::begin(admin); - let otw = VERIFIER_TESTS{}; - init(otw, scenario.ctx()); - scenario.end(); - } - - fun is_otw(witness: VERIFIER_TESTS): bool { - sui::types::is_one_time_witness(&witness) - } - - #[test] - fun test_otw() { - // we should be able to construct otw in test code - let otw = VERIFIER_TESTS{}; - assert!(is_otw(otw), 0); - } - -} diff --git a/crates/sui-framework/packages/sui-system/Move.lock b/crates/sui-framework/packages/sui-system/Move.lock deleted file mode 100644 index af204d00c79..00000000000 --- a/crates/sui-framework/packages/sui-system/Move.lock +++ /dev/null @@ -1,28 +0,0 @@ -# @generated by Move, please check-in and do not edit manually. - -[move] -version = 1 -manifest_digest = "68AEB9354EE1D616F6D2293EC721FE3D7E810FEC4FE34197676ECFA3DA72CAE3" -deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600" - -dependencies = [ - { name = "MoveStdlib" }, - { name = "Sui" }, -] - -[[move.package]] -name = "MoveStdlib" -source = { local = "../move-stdlib" } - -[[move.package]] -name = "Sui" -source = { local = "../sui-framework" } - -dependencies = [ - { name = "MoveStdlib" }, -] - -[move.toolchain-version] -compiler-version = "1.22.0" -edition = "legacy" -flavor = "sui" diff --git a/crates/sui-framework/packages/sui-system/Move.toml b/crates/sui-framework/packages/sui-system/Move.toml deleted file mode 100644 index 98e9236ff9b..00000000000 --- a/crates/sui-framework/packages/sui-system/Move.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "SuiSystem" -version = "0.0.1" -published-at = "0x3" -edition = "2024.beta" - -[dependencies] -MoveStdlib = { local = "../move-stdlib" } -Sui = { local = "../sui-framework" } - -[addresses] -sui_system = "0x3" diff --git a/crates/sui-framework/packages/sui-system/sources/genesis.move b/crates/sui-framework/packages/sui-system/sources/genesis.move deleted file mode 100644 index 39f1945142b..00000000000 --- a/crates/sui-framework/packages/sui-system/sources/genesis.move +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::genesis { - - use sui::balance::{Self, Balance}; - use sui::sui::{Self, SUI}; - use sui_system::sui_system; - use sui_system::validator::{Self, Validator}; - use sui_system::validator_set; - use sui_system::sui_system_state_inner; - use sui_system::stake_subsidy; - - public struct GenesisValidatorMetadata has drop, copy { - name: vector, - description: vector, - image_url: vector, - project_url: vector, - - sui_address: address, - - gas_price: u64, - commission_rate: u64, - - protocol_public_key: vector, - proof_of_possession: vector, - - network_public_key: vector, - worker_public_key: vector, - - network_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - } - - public struct GenesisChainParameters has drop, copy { - protocol_version: u64, - chain_start_timestamp_ms: u64, - epoch_duration_ms: u64, - - // Stake Subsidy parameters - stake_subsidy_start_epoch: u64, - stake_subsidy_initial_distribution_amount: u64, - stake_subsidy_period_length: u64, - stake_subsidy_decrease_rate: u16, - - // Validator committee parameters - max_validator_count: u64, - min_validator_joining_stake: u64, - validator_low_stake_threshold: u64, - validator_very_low_stake_threshold: u64, - validator_low_stake_grace_period: u64, - } - - public struct TokenDistributionSchedule { - stake_subsidy_fund_mist: u64, - allocations: vector, - } - - public struct TokenAllocation { - recipient_address: address, - amount_mist: u64, - - /// Indicates if this allocation should be staked at genesis and with which validator - staked_with_validator: Option
    , - } - - // Error codes - /// The `create` function was called at a non-genesis epoch. - const ENotCalledAtGenesis: u64 = 0; - /// The `create` function was called with duplicate validators. - const EDuplicateValidator: u64 = 1; - - #[allow(unused_function)] - /// This function will be explicitly called once at genesis. - /// It will create a singleton SuiSystemState object, which contains - /// all the information we need in the system. - fun create( - sui_system_state_id: UID, - mut sui_supply: Balance, - genesis_chain_parameters: GenesisChainParameters, - genesis_validators: vector, - token_distribution_schedule: TokenDistributionSchedule, - ctx: &mut TxContext, - ) { - // Ensure this is only called at genesis - assert!(ctx.epoch() == 0, ENotCalledAtGenesis); - - let TokenDistributionSchedule { - stake_subsidy_fund_mist, - allocations, - } = token_distribution_schedule; - - let subsidy_fund = sui_supply.split(stake_subsidy_fund_mist); - let storage_fund = balance::zero(); - - // Create all the `Validator` structs - let mut validators = vector[]; - let count = genesis_validators.length(); - let mut i = 0; - while (i < count) { - let GenesisValidatorMetadata { - name, - description, - image_url, - project_url, - sui_address, - gas_price, - commission_rate, - protocol_public_key, - proof_of_possession, - network_public_key, - worker_public_key, - network_address, - p2p_address, - primary_address, - worker_address, - } = genesis_validators[i]; - - let validator = validator::new( - sui_address, - protocol_public_key, - network_public_key, - worker_public_key, - proof_of_possession, - name, - description, - image_url, - project_url, - network_address, - p2p_address, - primary_address, - worker_address, - gas_price, - commission_rate, - ctx - ); - - // Ensure that each validator is unique - assert!( - !validator_set::is_duplicate_validator(&validators, &validator), - EDuplicateValidator, - ); - - validators.push_back(validator); - - i = i + 1; - }; - - // Allocate tokens and staking operations - allocate_tokens( - sui_supply, - allocations, - &mut validators, - ctx - ); - - // Activate all validators - activate_validators(&mut validators); - - let system_parameters = sui_system_state_inner::create_system_parameters( - genesis_chain_parameters.epoch_duration_ms, - genesis_chain_parameters.stake_subsidy_start_epoch, - - // Validator committee parameters - genesis_chain_parameters.max_validator_count, - genesis_chain_parameters.min_validator_joining_stake, - genesis_chain_parameters.validator_low_stake_threshold, - genesis_chain_parameters.validator_very_low_stake_threshold, - genesis_chain_parameters.validator_low_stake_grace_period, - - ctx, - ); - - let stake_subsidy = stake_subsidy::create( - subsidy_fund, - genesis_chain_parameters.stake_subsidy_initial_distribution_amount, - genesis_chain_parameters.stake_subsidy_period_length, - genesis_chain_parameters.stake_subsidy_decrease_rate, - ctx, - ); - - sui_system::create( - sui_system_state_id, - validators, - storage_fund, - genesis_chain_parameters.protocol_version, - genesis_chain_parameters.chain_start_timestamp_ms, - system_parameters, - stake_subsidy, - ctx, - ); - } - - fun allocate_tokens( - mut sui_supply: Balance, - mut allocations: vector, - validators: &mut vector, - ctx: &mut TxContext, - ) { - - while (!allocations.is_empty()) { - let TokenAllocation { - recipient_address, - amount_mist, - staked_with_validator, - } = allocations.pop_back(); - - let allocation_balance = sui_supply.split(amount_mist); - - if (staked_with_validator.is_some()) { - let validator_address = staked_with_validator.destroy_some(); - let validator = validator_set::get_validator_mut(validators, validator_address); - validator.request_add_stake_at_genesis( - allocation_balance, - recipient_address, - ctx - ); - } else { - sui::transfer( - allocation_balance.into_coin(ctx), - recipient_address, - ); - }; - }; - allocations.destroy_empty(); - - // Provided allocations must fully allocate the sui_supply and there - // should be none left at this point. - sui_supply.destroy_zero(); - } - - fun activate_validators(validators: &mut vector) { - // Activate all genesis validators - let count = validators.length(); - let mut i = 0; - while (i < count) { - let validator = &mut validators[i]; - validator.activate(0); - - i = i + 1; - }; - - } -} diff --git a/crates/sui-framework/packages/sui-system/sources/staking_pool.move b/crates/sui-framework/packages/sui-system/sources/staking_pool.move deleted file mode 100644 index f040b69721a..00000000000 --- a/crates/sui-framework/packages/sui-system/sources/staking_pool.move +++ /dev/null @@ -1,472 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[allow(unused_const)] -module sui_system::staking_pool { - use sui::balance::{Self, Balance}; - use sui::sui::SUI; - use sui::math; - use sui::table::{Self, Table}; - use sui::bag::Bag; - use sui::bag; - - /* friend sui_system::validator; */ - /* friend sui_system::validator_set; */ - - /// StakedSui objects cannot be split to below this amount. - const MIN_STAKING_THRESHOLD: u64 = 1_000_000_000; // 1 SUI - - const EInsufficientPoolTokenBalance: u64 = 0; - const EWrongPool: u64 = 1; - const EWithdrawAmountCannotBeZero: u64 = 2; - const EInsufficientSuiTokenBalance: u64 = 3; - const EInsufficientRewardsPoolBalance: u64 = 4; - const EDestroyNonzeroBalance: u64 = 5; - const ETokenTimeLockIsSome: u64 = 6; - const EWrongDelegation: u64 = 7; - const EPendingDelegationDoesNotExist: u64 = 8; - const ETokenBalancesDoNotMatchExchangeRate: u64 = 9; - const EDelegationToInactivePool: u64 = 10; - const EDeactivationOfInactivePool: u64 = 11; - const EIncompatibleStakedSui: u64 = 12; - const EWithdrawalInSameEpoch: u64 = 13; - const EPoolAlreadyActive: u64 = 14; - const EPoolNotPreactive: u64 = 15; - const EActivationOfInactivePool: u64 = 16; - const EDelegationOfZeroSui: u64 = 17; - const EStakedSuiBelowThreshold: u64 = 18; - - /// A staking pool embedded in each validator struct in the system state object. - public struct StakingPool has key, store { - id: UID, - /// The epoch at which this pool became active. - /// The value is `None` if the pool is pre-active and `Some()` if active or inactive. - activation_epoch: Option, - /// The epoch at which this staking pool ceased to be active. `None` = {pre-active, active}, - /// `Some()` if in-active, and it was de-activated at epoch ``. - deactivation_epoch: Option, - /// The total number of SUI tokens in this pool, including the SUI in the rewards_pool, as well as in all the principal - /// in the `StakedSui` object, updated at epoch boundaries. - sui_balance: u64, - /// The epoch stake rewards will be added here at the end of each epoch. - rewards_pool: Balance, - /// Total number of pool tokens issued by the pool. - pool_token_balance: u64, - /// Exchange rate history of previous epochs. Key is the epoch number. - /// The entries start from the `activation_epoch` of this pool and contains exchange rates at the beginning of each epoch, - /// i.e., right after the rewards for the previous epoch have been deposited into the pool. - exchange_rates: Table, - /// Pending stake amount for this epoch, emptied at epoch boundaries. - pending_stake: u64, - /// Pending stake withdrawn during the current epoch, emptied at epoch boundaries. - /// This includes both the principal and rewards SUI withdrawn. - pending_total_sui_withdraw: u64, - /// Pending pool token withdrawn during the current epoch, emptied at epoch boundaries. - pending_pool_token_withdraw: u64, - /// Any extra fields that's not defined statically. - extra_fields: Bag, - } - - /// Struct representing the exchange rate of the stake pool token to SUI. - public struct PoolTokenExchangeRate has store, copy, drop { - sui_amount: u64, - pool_token_amount: u64, - } - - /// A self-custodial object holding the staked SUI tokens. - public struct StakedSui has key, store { - id: UID, - /// ID of the staking pool we are staking with. - pool_id: ID, - /// The epoch at which the stake becomes active. - stake_activation_epoch: u64, - /// The staked SUI tokens. - principal: Balance, - } - - // ==== initializer ==== - - /// Create a new, empty staking pool. - public(package) fun new(ctx: &mut TxContext) : StakingPool { - let exchange_rates = table::new(ctx); - StakingPool { - id: object::new(ctx), - activation_epoch: option::none(), - deactivation_epoch: option::none(), - sui_balance: 0, - rewards_pool: balance::zero(), - pool_token_balance: 0, - exchange_rates, - pending_stake: 0, - pending_total_sui_withdraw: 0, - pending_pool_token_withdraw: 0, - extra_fields: bag::new(ctx), - } - } - - // ==== stake requests ==== - - /// Request to stake to a staking pool. The stake starts counting at the beginning of the next epoch, - public(package) fun request_add_stake( - pool: &mut StakingPool, - stake: Balance, - stake_activation_epoch: u64, - ctx: &mut TxContext - ) : StakedSui { - let sui_amount = stake.value(); - assert!(!is_inactive(pool), EDelegationToInactivePool); - assert!(sui_amount > 0, EDelegationOfZeroSui); - let staked_sui = StakedSui { - id: object::new(ctx), - pool_id: object::id(pool), - stake_activation_epoch, - principal: stake, - }; - pool.pending_stake = pool.pending_stake + sui_amount; - staked_sui - } - - /// Request to withdraw the given stake plus rewards from a staking pool. - /// Both the principal and corresponding rewards in SUI are withdrawn. - /// A proportional amount of pool token withdraw is recorded and processed at epoch change time. - public(package) fun request_withdraw_stake( - pool: &mut StakingPool, - staked_sui: StakedSui, - ctx: &TxContext - ) : Balance { - let (pool_token_withdraw_amount, mut principal_withdraw) = - withdraw_from_principal(pool, staked_sui); - let principal_withdraw_amount = principal_withdraw.value(); - - let rewards_withdraw = withdraw_rewards( - pool, principal_withdraw_amount, pool_token_withdraw_amount, ctx.epoch() - ); - let total_sui_withdraw_amount = principal_withdraw_amount + rewards_withdraw.value(); - - pool.pending_total_sui_withdraw = pool.pending_total_sui_withdraw + total_sui_withdraw_amount; - pool.pending_pool_token_withdraw = pool.pending_pool_token_withdraw + pool_token_withdraw_amount; - - // If the pool is inactive, we immediately process the withdrawal. - if (is_inactive(pool)) process_pending_stake_withdraw(pool); - - // TODO: implement withdraw bonding period here. - principal_withdraw.join(rewards_withdraw); - principal_withdraw - } - - /// Withdraw the principal SUI stored in the StakedSui object, and calculate the corresponding amount of pool - /// tokens using exchange rate at staking epoch. - /// Returns values are amount of pool tokens withdrawn and withdrawn principal portion of SUI. - public(package) fun withdraw_from_principal( - pool: &StakingPool, - staked_sui: StakedSui, - ) : (u64, Balance) { - - // Check that the stake information matches the pool. - assert!(staked_sui.pool_id == object::id(pool), EWrongPool); - - let exchange_rate_at_staking_epoch = pool_token_exchange_rate_at_epoch(pool, staked_sui.stake_activation_epoch); - let principal_withdraw = unwrap_staked_sui(staked_sui); - let pool_token_withdraw_amount = get_token_amount( - &exchange_rate_at_staking_epoch, - principal_withdraw.value() - ); - - ( - pool_token_withdraw_amount, - principal_withdraw, - ) - } - - fun unwrap_staked_sui(staked_sui: StakedSui): Balance { - let StakedSui { - id, - pool_id: _, - stake_activation_epoch: _, - principal, - } = staked_sui; - object::delete(id); - principal - } - - /// Allows calling `.into_balance()` on `StakedSui` to invoke `unwrap_staked_sui` - public use fun unwrap_staked_sui as StakedSui.into_balance; - - // ==== functions called at epoch boundaries === - - /// Called at epoch advancement times to add rewards (in SUI) to the staking pool. - public(package) fun deposit_rewards(pool: &mut StakingPool, rewards: Balance) { - pool.sui_balance = pool.sui_balance + rewards.value(); - pool.rewards_pool.join(rewards); - } - - public(package) fun process_pending_stakes_and_withdraws(pool: &mut StakingPool, ctx: &TxContext) { - let new_epoch = ctx.epoch() + 1; - process_pending_stake_withdraw(pool); - process_pending_stake(pool); - pool.exchange_rates.add( - new_epoch, - PoolTokenExchangeRate { sui_amount: pool.sui_balance, pool_token_amount: pool.pool_token_balance }, - ); - check_balance_invariants(pool, new_epoch); - } - - /// Called at epoch boundaries to process pending stake withdraws requested during the epoch. - /// Also called immediately upon withdrawal if the pool is inactive. - fun process_pending_stake_withdraw(pool: &mut StakingPool) { - pool.sui_balance = pool.sui_balance - pool.pending_total_sui_withdraw; - pool.pool_token_balance = pool.pool_token_balance - pool.pending_pool_token_withdraw; - pool.pending_total_sui_withdraw = 0; - pool.pending_pool_token_withdraw = 0; - } - - /// Called at epoch boundaries to process the pending stake. - public(package) fun process_pending_stake(pool: &mut StakingPool) { - // Use the most up to date exchange rate with the rewards deposited and withdraws effectuated. - let latest_exchange_rate = - PoolTokenExchangeRate { sui_amount: pool.sui_balance, pool_token_amount: pool.pool_token_balance }; - pool.sui_balance = pool.sui_balance + pool.pending_stake; - pool.pool_token_balance = get_token_amount(&latest_exchange_rate, pool.sui_balance); - pool.pending_stake = 0; - } - - /// This function does the following: - /// 1. Calculates the total amount of SUI (including principal and rewards) that the provided pool tokens represent - /// at the current exchange rate. - /// 2. Using the above number and the given `principal_withdraw_amount`, calculates the rewards portion of the - /// stake we should withdraw. - /// 3. Withdraws the rewards portion from the rewards pool at the current exchange rate. We only withdraw the rewards - /// portion because the principal portion was already taken out of the staker's self custodied StakedSui. - fun withdraw_rewards( - pool: &mut StakingPool, - principal_withdraw_amount: u64, - pool_token_withdraw_amount: u64, - epoch: u64, - ) : Balance { - let exchange_rate = pool_token_exchange_rate_at_epoch(pool, epoch); - let total_sui_withdraw_amount = get_sui_amount(&exchange_rate, pool_token_withdraw_amount); - let mut reward_withdraw_amount = - if (total_sui_withdraw_amount >= principal_withdraw_amount) - total_sui_withdraw_amount - principal_withdraw_amount - else 0; - // This may happen when we are withdrawing everything from the pool and - // the rewards pool balance may be less than reward_withdraw_amount. - // TODO: FIGURE OUT EXACTLY WHY THIS CAN HAPPEN. - reward_withdraw_amount = math::min(reward_withdraw_amount, pool.rewards_pool.value()); - pool.rewards_pool.split(reward_withdraw_amount) - } - - // ==== preactive pool related ==== - - /// Called by `validator` module to activate a staking pool. - public(package) fun activate_staking_pool(pool: &mut StakingPool, activation_epoch: u64) { - // Add the initial exchange rate to the table. - pool.exchange_rates.add( - activation_epoch, - initial_exchange_rate() - ); - // Check that the pool is preactive and not inactive. - assert!(is_preactive(pool), EPoolAlreadyActive); - assert!(!is_inactive(pool), EActivationOfInactivePool); - // Fill in the active epoch. - pool.activation_epoch.fill(activation_epoch); - } - - // ==== inactive pool related ==== - - /// Deactivate a staking pool by setting the `deactivation_epoch`. After - /// this pool deactivation, the pool stops earning rewards. Only stake - /// withdraws can be made to the pool. - public(package) fun deactivate_staking_pool(pool: &mut StakingPool, deactivation_epoch: u64) { - // We can't deactivate an already deactivated pool. - assert!(!is_inactive(pool), EDeactivationOfInactivePool); - pool.deactivation_epoch = option::some(deactivation_epoch); - } - - // ==== getters and misc utility functions ==== - - public fun sui_balance(pool: &StakingPool): u64 { pool.sui_balance } - - public fun pool_id(staked_sui: &StakedSui): ID { staked_sui.pool_id } - - public fun staked_sui_amount(staked_sui: &StakedSui): u64 { staked_sui.principal.value() } - - /// Allows calling `.amount()` on `StakedSui` to invoke `staked_sui_amount` - public use fun staked_sui_amount as StakedSui.amount; - - public fun stake_activation_epoch(staked_sui: &StakedSui): u64 { - staked_sui.stake_activation_epoch - } - - /// Returns true if the input staking pool is preactive. - public fun is_preactive(pool: &StakingPool): bool{ - pool.activation_epoch.is_none() - } - - /// Returns true if the input staking pool is inactive. - public fun is_inactive(pool: &StakingPool): bool { - pool.deactivation_epoch.is_some() - } - - /// Split StakedSui `self` to two parts, one with principal `split_amount`, - /// and the remaining principal is left in `self`. - /// All the other parameters of the StakedSui like `stake_activation_epoch` or `pool_id` remain the same. - public fun split(self: &mut StakedSui, split_amount: u64, ctx: &mut TxContext): StakedSui { - let original_amount = self.principal.value(); - assert!(split_amount <= original_amount, EInsufficientSuiTokenBalance); - let remaining_amount = original_amount - split_amount; - // Both resulting parts should have at least MIN_STAKING_THRESHOLD. - assert!(remaining_amount >= MIN_STAKING_THRESHOLD, EStakedSuiBelowThreshold); - assert!(split_amount >= MIN_STAKING_THRESHOLD, EStakedSuiBelowThreshold); - StakedSui { - id: object::new(ctx), - pool_id: self.pool_id, - stake_activation_epoch: self.stake_activation_epoch, - principal: self.principal.split(split_amount), - } - } - - /// Split the given StakedSui to the two parts, one with principal `split_amount`, - /// transfer the newly split part to the sender address. - public entry fun split_staked_sui(stake: &mut StakedSui, split_amount: u64, ctx: &mut TxContext) { - transfer::transfer(split(stake, split_amount, ctx), ctx.sender()); - } - - /// Allows calling `.split_to_sender()` on `StakedSui` to invoke `split_staked_sui` - public use fun split_staked_sui as StakedSui.split_to_sender; - - /// Consume the staked sui `other` and add its value to `self`. - /// Aborts if some of the staking parameters are incompatible (pool id, stake activation epoch, etc.) - public entry fun join_staked_sui(self: &mut StakedSui, other: StakedSui) { - assert!(is_equal_staking_metadata(self, &other), EIncompatibleStakedSui); - let StakedSui { - id, - pool_id: _, - stake_activation_epoch: _, - principal, - } = other; - - id.delete(); - self.principal.join(principal); - } - - /// Allows calling `.join()` on `StakedSui` to invoke `join_staked_sui` - public use fun join_staked_sui as StakedSui.join; - - /// Returns true if all the staking parameters of the staked sui except the principal are identical - public fun is_equal_staking_metadata(self: &StakedSui, other: &StakedSui): bool { - (self.pool_id == other.pool_id) && - (self.stake_activation_epoch == other.stake_activation_epoch) - } - - public fun pool_token_exchange_rate_at_epoch(pool: &StakingPool, epoch: u64): PoolTokenExchangeRate { - // If the pool is preactive then the exchange rate is always 1:1. - if (is_preactive_at_epoch(pool, epoch)) { - return initial_exchange_rate() - }; - let clamped_epoch = pool.deactivation_epoch.get_with_default(epoch); - let mut epoch = math::min(clamped_epoch, epoch); - let activation_epoch = *pool.activation_epoch.borrow(); - - // Find the latest epoch that's earlier than the given epoch with an entry in the table - while (epoch >= activation_epoch) { - if (pool.exchange_rates.contains(epoch)) { - return pool.exchange_rates[epoch] - }; - epoch = epoch - 1; - }; - // This line really should be unreachable. Do we want an assert false here? - initial_exchange_rate() - } - - /// Returns the total value of the pending staking requests for this staking pool. - public fun pending_stake_amount(staking_pool: &StakingPool): u64 { - staking_pool.pending_stake - } - - /// Returns the total withdrawal from the staking pool this epoch. - public fun pending_stake_withdraw_amount(staking_pool: &StakingPool): u64 { - staking_pool.pending_total_sui_withdraw - } - - public(package) fun exchange_rates(pool: &StakingPool): &Table { - &pool.exchange_rates - } - - public fun sui_amount(exchange_rate: &PoolTokenExchangeRate): u64 { - exchange_rate.sui_amount - } - - public fun pool_token_amount(exchange_rate: &PoolTokenExchangeRate): u64 { - exchange_rate.pool_token_amount - } - - /// Returns true if the provided staking pool is preactive at the provided epoch. - fun is_preactive_at_epoch(pool: &StakingPool, epoch: u64): bool{ - // Either the pool is currently preactive or the pool's starting epoch is later than the provided epoch. - is_preactive(pool) || (*pool.activation_epoch.borrow() > epoch) - } - - fun get_sui_amount(exchange_rate: &PoolTokenExchangeRate, token_amount: u64): u64 { - // When either amount is 0, that means we have no stakes with this pool. - // The other amount might be non-zero when there's dust left in the pool. - if (exchange_rate.sui_amount == 0 || exchange_rate.pool_token_amount == 0) { - return token_amount - }; - let res = exchange_rate.sui_amount as u128 - * (token_amount as u128) - / (exchange_rate.pool_token_amount as u128); - res as u64 - } - - fun get_token_amount(exchange_rate: &PoolTokenExchangeRate, sui_amount: u64): u64 { - // When either amount is 0, that means we have no stakes with this pool. - // The other amount might be non-zero when there's dust left in the pool. - if (exchange_rate.sui_amount == 0 || exchange_rate.pool_token_amount == 0) { - return sui_amount - }; - let res = exchange_rate.pool_token_amount as u128 - * (sui_amount as u128) - / (exchange_rate.sui_amount as u128); - res as u64 - } - - fun initial_exchange_rate(): PoolTokenExchangeRate { - PoolTokenExchangeRate { sui_amount: 0, pool_token_amount: 0 } - } - - fun check_balance_invariants(pool: &StakingPool, epoch: u64) { - let exchange_rate = pool_token_exchange_rate_at_epoch(pool, epoch); - // check that the pool token balance and sui balance ratio matches the exchange rate stored. - let expected = get_token_amount(&exchange_rate, pool.sui_balance); - let actual = pool.pool_token_balance; - assert!(expected == actual, ETokenBalancesDoNotMatchExchangeRate) - } - - // ==== test-related functions ==== - - // Given the `staked_sui` receipt calculate the current rewards (in terms of SUI) for it. - #[test_only] - public fun calculate_rewards( - pool: &StakingPool, - staked_sui: &StakedSui, - current_epoch: u64, - ): u64 { - let staked_amount = staked_sui_amount(staked_sui); - let pool_token_withdraw_amount = { - let exchange_rate_at_staking_epoch = pool_token_exchange_rate_at_epoch(pool, staked_sui.stake_activation_epoch); - get_token_amount(&exchange_rate_at_staking_epoch, staked_amount) - }; - - let new_epoch_exchange_rate = pool_token_exchange_rate_at_epoch(pool, current_epoch); - let total_sui_withdraw_amount = get_sui_amount(&new_epoch_exchange_rate, pool_token_withdraw_amount); - - let mut reward_withdraw_amount = - if (total_sui_withdraw_amount >= staked_amount) - total_sui_withdraw_amount - staked_amount - else 0; - reward_withdraw_amount = math::min(reward_withdraw_amount, pool.rewards_pool.value()); - - staked_amount + reward_withdraw_amount - } -} diff --git a/crates/sui-framework/packages/sui-system/sources/sui_system.move b/crates/sui-framework/packages/sui-system/sources/sui_system.move deleted file mode 100644 index 1159391857d..00000000000 --- a/crates/sui-framework/packages/sui-system/sources/sui_system.move +++ /dev/null @@ -1,772 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Sui System State Type Upgrade Guide -/// `SuiSystemState` is a thin wrapper around `SuiSystemStateInner` that provides a versioned interface. -/// The `SuiSystemState` object has a fixed ID 0x5, and the `SuiSystemStateInner` object is stored as a dynamic field. -/// There are a few different ways to upgrade the `SuiSystemStateInner` type: -/// -/// The simplest and one that doesn't involve a real upgrade is to just add dynamic fields to the `extra_fields` field -/// of `SuiSystemStateInner` or any of its sub type. This is useful when we are in a rush, or making a small change, -/// or still experimenting a new field. -/// -/// To properly upgrade the `SuiSystemStateInner` type, we need to ship a new framework that does the following: -/// 1. Define a new `SuiSystemStateInner`type (e.g. `SuiSystemStateInnerV2`). -/// 2. Define a data migration function that migrates the old `SuiSystemStateInner` to the new one (i.e. SuiSystemStateInnerV2). -/// 3. Replace all uses of `SuiSystemStateInner` with `SuiSystemStateInnerV2` in both sui_system.move and sui_system_state_inner.move, -/// with the exception of the `sui_system_state_inner::create` function, which should always return the genesis type. -/// 4. Inside `load_inner_maybe_upgrade` function, check the current version in the wrapper, and if it's not the latest version, -/// call the data migration function to upgrade the inner object. Make sure to also update the version in the wrapper. -/// A detailed example can be found in sui/tests/framework_upgrades/mock_sui_systems/shallow_upgrade. -/// Along with the Move change, we also need to update the Rust code to support the new type. This includes: -/// 1. Define a new `SuiSystemStateInner` struct type that matches the new Move type, and implement the SuiSystemStateTrait. -/// 2. Update the `SuiSystemState` struct to include the new version as a new enum variant. -/// 3. Update the `get_sui_system_state` function to handle the new version. -/// To test that the upgrade will be successful, we need to modify `sui_system_state_production_upgrade_test` test in -/// protocol_version_tests and trigger a real upgrade using the new framework. We will need to keep this directory as old version, -/// put the new framework in a new directory, and run the test to exercise the upgrade. -/// -/// To upgrade Validator type, besides everything above, we also need to: -/// 1. Define a new Validator type (e.g. ValidatorV2). -/// 2. Define a data migration function that migrates the old Validator to the new one (i.e. ValidatorV2). -/// 3. Replace all uses of Validator with ValidatorV2 except the genesis creation function. -/// 4. In validator_wrapper::upgrade_to_latest, check the current version in the wrapper, and if it's not the latest version, -/// call the data migration function to upgrade it. -/// In Rust, we also need to add a new case in `get_validator_from_table`. -/// Note that it is possible to upgrade SuiSystemStateInner without upgrading Validator, but not the other way around. -/// And when we only upgrade SuiSystemStateInner, the version of Validator in the wrapper will not be updated, and hence may become -/// inconsistent with the version of SuiSystemStateInner. This is fine as long as we don't use the Validator version to determine -/// the SuiSystemStateInner version, or vice versa. - -module sui_system::sui_system { - use sui::balance::Balance; - - use sui::coin::Coin; - use sui_system::staking_pool::StakedSui; - use sui::sui::SUI; - use sui::table::Table; - use sui_system::validator::Validator; - use sui_system::validator_cap::UnverifiedValidatorOperationCap; - use sui_system::sui_system_state_inner::{Self, SystemParameters, SuiSystemStateInner, SuiSystemStateInnerV2}; - use sui_system::stake_subsidy::StakeSubsidy; - use sui_system::staking_pool::PoolTokenExchangeRate; - use sui::dynamic_field; - - #[test_only] use sui::balance; - #[test_only] use sui_system::validator_set::ValidatorSet; - #[test_only] use sui::vec_set::VecSet; - - /* friend sui_system::genesis; */ - - /* #[test_only] */ - /* friend sui_system::governance_test_utils; */ - /* #[test_only] */ - /* friend sui_system::sui_system_tests; */ - - public struct SuiSystemState has key { - id: UID, - version: u64, - } - - const ENotSystemAddress: u64 = 0; - const EWrongInnerVersion: u64 = 1; - - // ==== functions that can only be called by genesis ==== - - /// Create a new SuiSystemState object and make it shared. - /// This function will be called only once in genesis. - public(package) fun create( - id: UID, - validators: vector, - storage_fund: Balance, - protocol_version: u64, - epoch_start_timestamp_ms: u64, - parameters: SystemParameters, - stake_subsidy: StakeSubsidy, - ctx: &mut TxContext, - ) { - let system_state = sui_system_state_inner::create( - validators, - storage_fund, - protocol_version, - epoch_start_timestamp_ms, - parameters, - stake_subsidy, - ctx, - ); - let version = sui_system_state_inner::genesis_system_state_version(); - let mut self = SuiSystemState { - id, - version, - }; - dynamic_field::add(&mut self.id, version, system_state); - transfer::share_object(self); - } - - // ==== entry functions ==== - - /// Can be called by anyone who wishes to become a validator candidate and starts accuring delegated - /// stakes in their staking pool. Once they have at least `MIN_VALIDATOR_JOINING_STAKE` amount of stake they - /// can call `request_add_validator` to officially become an active validator at the next epoch. - /// Aborts if the caller is already a pending or active validator, or a validator candidate. - /// Note: `proof_of_possession` MUST be a valid signature using sui_address and protocol_pubkey_bytes. - /// To produce a valid PoP, run [fn test_proof_of_possession]. - public entry fun request_add_validator_candidate( - wrapper: &mut SuiSystemState, - pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - proof_of_possession: vector, - name: vector, - description: vector, - image_url: vector, - project_url: vector, - net_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - gas_price: u64, - commission_rate: u64, - ctx: &mut TxContext, - ) { - let self = load_system_state_mut(wrapper); - self.request_add_validator_candidate( - pubkey_bytes, - network_pubkey_bytes, - worker_pubkey_bytes, - proof_of_possession, - name, - description, - image_url, - project_url, - net_address, - p2p_address, - primary_address, - worker_address, - gas_price, - commission_rate, - ctx, - ) - } - - /// Called by a validator candidate to remove themselves from the candidacy. After this call - /// their staking pool becomes deactivate. - public entry fun request_remove_validator_candidate( - wrapper: &mut SuiSystemState, - ctx: &mut TxContext, - ) { - let self = load_system_state_mut(wrapper); - self.request_remove_validator_candidate(ctx) - } - - /// Called by a validator candidate to add themselves to the active validator set beginning next epoch. - /// Aborts if the validator is a duplicate with one of the pending or active validators, or if the amount of - /// stake the validator has doesn't meet the min threshold, or if the number of new validators for the next - /// epoch has already reached the maximum. - public entry fun request_add_validator( - wrapper: &mut SuiSystemState, - ctx: &mut TxContext, - ) { - let self = load_system_state_mut(wrapper); - self.request_add_validator(ctx) - } - - /// A validator can call this function to request a removal in the next epoch. - /// We use the sender of `ctx` to look up the validator - /// (i.e. sender must match the sui_address in the validator). - /// At the end of the epoch, the `validator` object will be returned to the sui_address - /// of the validator. - public entry fun request_remove_validator( - wrapper: &mut SuiSystemState, - ctx: &mut TxContext, - ) { - let self = load_system_state_mut(wrapper); - self.request_remove_validator(ctx) - } - - /// A validator can call this entry function to submit a new gas price quote, to be - /// used for the reference gas price calculation at the end of the epoch. - public entry fun request_set_gas_price( - wrapper: &mut SuiSystemState, - cap: &UnverifiedValidatorOperationCap, - new_gas_price: u64, - ) { - let self = load_system_state_mut(wrapper); - self.request_set_gas_price(cap, new_gas_price) - } - - /// This entry function is used to set new gas price for candidate validators - public entry fun set_candidate_validator_gas_price( - wrapper: &mut SuiSystemState, - cap: &UnverifiedValidatorOperationCap, - new_gas_price: u64, - ) { - let self = load_system_state_mut(wrapper); - self.set_candidate_validator_gas_price(cap, new_gas_price) - } - - /// A validator can call this entry function to set a new commission rate, updated at the end of - /// the epoch. - public entry fun request_set_commission_rate( - wrapper: &mut SuiSystemState, - new_commission_rate: u64, - ctx: &mut TxContext, - ) { - let self = load_system_state_mut(wrapper); - self.request_set_commission_rate(new_commission_rate, ctx) - } - - /// This entry function is used to set new commission rate for candidate validators - public entry fun set_candidate_validator_commission_rate( - wrapper: &mut SuiSystemState, - new_commission_rate: u64, - ctx: &mut TxContext, - ) { - let self = load_system_state_mut(wrapper); - self.set_candidate_validator_commission_rate(new_commission_rate, ctx) - } - - /// Add stake to a validator's staking pool. - public entry fun request_add_stake( - wrapper: &mut SuiSystemState, - stake: Coin, - validator_address: address, - ctx: &mut TxContext, - ) { - let staked_sui = request_add_stake_non_entry(wrapper, stake, validator_address, ctx); - transfer::public_transfer(staked_sui, ctx.sender()); - } - - /// The non-entry version of `request_add_stake`, which returns the staked SUI instead of transferring it to the sender. - public fun request_add_stake_non_entry( - wrapper: &mut SuiSystemState, - stake: Coin, - validator_address: address, - ctx: &mut TxContext, - ): StakedSui { - let self = load_system_state_mut(wrapper); - self.request_add_stake(stake, validator_address, ctx) - } - - /// Add stake to a validator's staking pool using multiple coins. - public entry fun request_add_stake_mul_coin( - wrapper: &mut SuiSystemState, - stakes: vector>, - stake_amount: option::Option, - validator_address: address, - ctx: &mut TxContext, - ) { - let self = load_system_state_mut(wrapper); - let staked_sui = self.request_add_stake_mul_coin(stakes, stake_amount, validator_address, ctx); - transfer::public_transfer(staked_sui, ctx.sender()); - } - - /// Withdraw stake from a validator's staking pool. - public entry fun request_withdraw_stake( - wrapper: &mut SuiSystemState, - staked_sui: StakedSui, - ctx: &mut TxContext, - ) { - let withdrawn_stake = request_withdraw_stake_non_entry(wrapper, staked_sui, ctx); - transfer::public_transfer(withdrawn_stake.into_coin(ctx), ctx.sender()); - } - - /// Non-entry version of `request_withdraw_stake` that returns the withdrawn SUI instead of transferring it to the sender. - public fun request_withdraw_stake_non_entry( - wrapper: &mut SuiSystemState, - staked_sui: StakedSui, - ctx: &mut TxContext, - ) : Balance { - let self = load_system_state_mut(wrapper); - self.request_withdraw_stake(staked_sui, ctx) - } - - /// Report a validator as a bad or non-performant actor in the system. - /// Succeeds if all the following are satisfied: - /// 1. both the reporter in `cap` and the input `reportee_addr` are active validators. - /// 2. reporter and reportee not the same address. - /// 3. the cap object is still valid. - /// This function is idempotent. - public entry fun report_validator( - wrapper: &mut SuiSystemState, - cap: &UnverifiedValidatorOperationCap, - reportee_addr: address, - ) { - let self = load_system_state_mut(wrapper); - self.report_validator(cap, reportee_addr) - } - - - /// Undo a `report_validator` action. Aborts if - /// 1. the reportee is not a currently active validator or - /// 2. the sender has not previously reported the `reportee_addr`, or - /// 3. the cap is not valid - public entry fun undo_report_validator( - wrapper: &mut SuiSystemState, - cap: &UnverifiedValidatorOperationCap, - reportee_addr: address, - ) { - let self = load_system_state_mut(wrapper); - self.undo_report_validator(cap, reportee_addr) - } - - // ==== validator metadata management functions ==== - - /// Create a new `UnverifiedValidatorOperationCap`, transfer it to the - /// validator and registers it. The original object is thus revoked. - public entry fun rotate_operation_cap( - self: &mut SuiSystemState, - ctx: &mut TxContext, - ) { - let self = load_system_state_mut(self); - self.rotate_operation_cap(ctx) - } - - /// Update a validator's name. - public entry fun update_validator_name( - self: &mut SuiSystemState, - name: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_validator_name(name, ctx) - } - - /// Update a validator's description - public entry fun update_validator_description( - self: &mut SuiSystemState, - description: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_validator_description(description, ctx) - } - - /// Update a validator's image url - public entry fun update_validator_image_url( - self: &mut SuiSystemState, - image_url: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_validator_image_url(image_url, ctx) - } - - /// Update a validator's project url - public entry fun update_validator_project_url( - self: &mut SuiSystemState, - project_url: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_validator_project_url(project_url, ctx) - } - - /// Update a validator's network address. - /// The change will only take effects starting from the next epoch. - public entry fun update_validator_next_epoch_network_address( - self: &mut SuiSystemState, - network_address: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_validator_next_epoch_network_address(network_address, ctx) - } - - /// Update candidate validator's network address. - public entry fun update_candidate_validator_network_address( - self: &mut SuiSystemState, - network_address: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_candidate_validator_network_address(network_address, ctx) - } - - /// Update a validator's p2p address. - /// The change will only take effects starting from the next epoch. - public entry fun update_validator_next_epoch_p2p_address( - self: &mut SuiSystemState, - p2p_address: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_validator_next_epoch_p2p_address(p2p_address, ctx) - } - - /// Update candidate validator's p2p address. - public entry fun update_candidate_validator_p2p_address( - self: &mut SuiSystemState, - p2p_address: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_candidate_validator_p2p_address(p2p_address, ctx) - } - - /// Update a validator's narwhal primary address. - /// The change will only take effects starting from the next epoch. - public entry fun update_validator_next_epoch_primary_address( - self: &mut SuiSystemState, - primary_address: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_validator_next_epoch_primary_address(primary_address, ctx) - } - - /// Update candidate validator's narwhal primary address. - public entry fun update_candidate_validator_primary_address( - self: &mut SuiSystemState, - primary_address: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_candidate_validator_primary_address(primary_address, ctx) - } - - /// Update a validator's narwhal worker address. - /// The change will only take effects starting from the next epoch. - public entry fun update_validator_next_epoch_worker_address( - self: &mut SuiSystemState, - worker_address: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_validator_next_epoch_worker_address(worker_address, ctx) - } - - /// Update candidate validator's narwhal worker address. - public entry fun update_candidate_validator_worker_address( - self: &mut SuiSystemState, - worker_address: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_candidate_validator_worker_address(worker_address, ctx) - } - - /// Update a validator's public key of protocol key and proof of possession. - /// The change will only take effects starting from the next epoch. - public entry fun update_validator_next_epoch_protocol_pubkey( - self: &mut SuiSystemState, - protocol_pubkey: vector, - proof_of_possession: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_validator_next_epoch_protocol_pubkey(protocol_pubkey, proof_of_possession, ctx) - } - - /// Update candidate validator's public key of protocol key and proof of possession. - public entry fun update_candidate_validator_protocol_pubkey( - self: &mut SuiSystemState, - protocol_pubkey: vector, - proof_of_possession: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_candidate_validator_protocol_pubkey(protocol_pubkey, proof_of_possession, ctx) - } - - /// Update a validator's public key of worker key. - /// The change will only take effects starting from the next epoch. - public entry fun update_validator_next_epoch_worker_pubkey( - self: &mut SuiSystemState, - worker_pubkey: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_validator_next_epoch_worker_pubkey(worker_pubkey, ctx) - } - - /// Update candidate validator's public key of worker key. - public entry fun update_candidate_validator_worker_pubkey( - self: &mut SuiSystemState, - worker_pubkey: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_candidate_validator_worker_pubkey(worker_pubkey, ctx) - } - - /// Update a validator's public key of network key. - /// The change will only take effects starting from the next epoch. - public entry fun update_validator_next_epoch_network_pubkey( - self: &mut SuiSystemState, - network_pubkey: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_validator_next_epoch_network_pubkey(network_pubkey, ctx) - } - - /// Update candidate validator's public key of network key. - public entry fun update_candidate_validator_network_pubkey( - self: &mut SuiSystemState, - network_pubkey: vector, - ctx: &TxContext, - ) { - let self = load_system_state_mut(self); - self.update_candidate_validator_network_pubkey(network_pubkey, ctx) - } - - /// Getter of the pool token exchange rate of a staking pool. Works for both active and inactive pools. - public fun pool_exchange_rates( - wrapper: &mut SuiSystemState, - pool_id: &ID - ): &Table { - let self = load_system_state_mut(wrapper); - self.pool_exchange_rates(pool_id) - } - - /// Getter returning addresses of the currently active validators. - public fun active_validator_addresses(wrapper: &mut SuiSystemState): vector
    { - let self = load_system_state(wrapper); - self.active_validator_addresses() - } - - #[allow(unused_function)] - /// This function should be called at the end of an epoch, and advances the system to the next epoch. - /// It does the following things: - /// 1. Add storage charge to the storage fund. - /// 2. Burn the storage rebates from the storage fund. These are already refunded to transaction sender's - /// gas coins. - /// 3. Distribute computation charge to validator stake. - /// 4. Update all validators. - fun advance_epoch( - storage_reward: Balance, - computation_reward: Balance, - wrapper: &mut SuiSystemState, - new_epoch: u64, - next_protocol_version: u64, - storage_rebate: u64, - non_refundable_storage_fee: u64, - storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested - // into storage fund, in basis point. - reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. - epoch_start_timestamp_ms: u64, // Timestamp of the epoch start - ctx: &mut TxContext, - ) : Balance { - let self = load_system_state_mut(wrapper); - // Validator will make a special system call with sender set as 0x0. - assert!(ctx.sender() == @0x0, ENotSystemAddress); - let storage_rebate = self.advance_epoch( - new_epoch, - next_protocol_version, - storage_reward, - computation_reward, - storage_rebate, - non_refundable_storage_fee, - storage_fund_reinvest_rate, - reward_slashing_rate, - epoch_start_timestamp_ms, - ctx, - ); - - storage_rebate - } - - fun load_system_state(self: &mut SuiSystemState): &SuiSystemStateInnerV2 { - load_inner_maybe_upgrade(self) - } - - fun load_system_state_mut(self: &mut SuiSystemState): &mut SuiSystemStateInnerV2 { - load_inner_maybe_upgrade(self) - } - - fun load_inner_maybe_upgrade(self: &mut SuiSystemState): &mut SuiSystemStateInnerV2 { - if (self.version == 1) { - let v1: SuiSystemStateInner = dynamic_field::remove(&mut self.id, self.version); - let v2 = v1.v1_to_v2(); - self.version = 2; - dynamic_field::add(&mut self.id, self.version, v2); - }; - - let inner: &mut SuiSystemStateInnerV2 = dynamic_field::borrow_mut( - &mut self.id, - self.version - ); - assert!(inner.system_state_version() == self.version, EWrongInnerVersion); - inner - } - - #[test_only] - /// Return the current epoch number. Useful for applications that need a coarse-grained concept of time, - /// since epochs are ever-increasing and epoch changes are intended to happen every 24 hours. - public fun epoch(wrapper: &mut SuiSystemState): u64 { - let self = load_system_state(wrapper); - self.epoch() - } - - #[test_only] - /// Returns unix timestamp of the start of current epoch - public fun epoch_start_timestamp_ms(wrapper: &mut SuiSystemState): u64 { - let self = load_system_state(wrapper); - self.epoch_start_timestamp_ms() - } - - #[test_only] - /// Returns the total amount staked with `validator_addr`. - /// Aborts if `validator_addr` is not an active validator. - public fun validator_stake_amount(wrapper: &mut SuiSystemState, validator_addr: address): u64 { - let self = load_system_state(wrapper); - self.validator_stake_amount(validator_addr) - } - - #[test_only] - /// Returns the staking pool id of a given validator. - /// Aborts if `validator_addr` is not an active validator. - public fun validator_staking_pool_id(wrapper: &mut SuiSystemState, validator_addr: address): ID { - let self = load_system_state(wrapper); - self.validator_staking_pool_id(validator_addr) - } - - #[test_only] - /// Returns reference to the staking pool mappings that map pool ids to active validator addresses - public fun validator_staking_pool_mappings(wrapper: &mut SuiSystemState): &Table { - let self = load_system_state(wrapper); - self.validator_staking_pool_mappings() - } - - #[test_only] - /// Returns all the validators who are currently reporting `addr` - public fun get_reporters_of(wrapper: &mut SuiSystemState, addr: address): VecSet
    { - let self = load_system_state(wrapper); - self.get_reporters_of(addr) - } - - #[test_only] - /// Return the current validator set - public fun validators(wrapper: &mut SuiSystemState): &ValidatorSet { - let self = load_system_state(wrapper); - self.validators() - } - - #[test_only] - /// Return the currently active validator by address - public fun active_validator_by_address(self: &mut SuiSystemState, validator_address: address): &Validator { - validators(self).get_active_validator_ref(validator_address) - } - - #[test_only] - /// Return the currently pending validator by address - public fun pending_validator_by_address(self: &mut SuiSystemState, validator_address: address): &Validator { - validators(self).get_pending_validator_ref(validator_address) - } - - #[test_only] - /// Return the currently candidate validator by address - public fun candidate_validator_by_address(self: &mut SuiSystemState, validator_address: address): &Validator { - validators(self).get_candidate_validator_ref(validator_address) - } - - #[test_only] - public fun set_epoch_for_testing(wrapper: &mut SuiSystemState, epoch_num: u64) { - let self = load_system_state_mut(wrapper); - self.set_epoch_for_testing(epoch_num) - } - - #[test_only] - public fun request_add_validator_for_testing( - wrapper: &mut SuiSystemState, - min_joining_stake_for_testing: u64, - ctx: &TxContext, - ) { - let self = load_system_state_mut(wrapper); - self.request_add_validator_for_testing(min_joining_stake_for_testing, ctx) - } - - #[test_only] - public fun get_storage_fund_total_balance(wrapper: &mut SuiSystemState): u64 { - let self = load_system_state(wrapper); - self.get_storage_fund_total_balance() - } - - #[test_only] - public fun get_storage_fund_object_rebates(wrapper: &mut SuiSystemState): u64 { - let self = load_system_state(wrapper); - self.get_storage_fund_object_rebates() - } - - #[test_only] - public fun get_stake_subsidy_distribution_counter(wrapper: &mut SuiSystemState): u64 { - let self = load_system_state(wrapper); - self.get_stake_subsidy_distribution_counter() - } - - // CAUTION: THIS CODE IS ONLY FOR TESTING AND THIS MACRO MUST NEVER EVER BE REMOVED. Creates a - // candidate validator - bypassing the proof of possession check and other metadata validation - // in the process. - #[test_only] - public entry fun request_add_validator_candidate_for_testing( - wrapper: &mut SuiSystemState, - pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - proof_of_possession: vector, - name: vector, - description: vector, - image_url: vector, - project_url: vector, - net_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - gas_price: u64, - commission_rate: u64, - ctx: &mut TxContext, - ) { - let self = load_system_state_mut(wrapper); - self.request_add_validator_candidate_for_testing( - pubkey_bytes, - network_pubkey_bytes, - worker_pubkey_bytes, - proof_of_possession, - name, - description, - image_url, - project_url, - net_address, - p2p_address, - primary_address, - worker_address, - gas_price, - commission_rate, - ctx - ) - } - - // CAUTION: THIS CODE IS ONLY FOR TESTING AND THIS MACRO MUST NEVER EVER BE REMOVED. - #[test_only] - public(package) fun advance_epoch_for_testing( - wrapper: &mut SuiSystemState, - new_epoch: u64, - next_protocol_version: u64, - storage_charge: u64, - computation_charge: u64, - storage_rebate: u64, - non_refundable_storage_fee: u64, - storage_fund_reinvest_rate: u64, - reward_slashing_rate: u64, - epoch_start_timestamp_ms: u64, - ctx: &mut TxContext, - ): Balance { - let storage_reward = balance::create_for_testing(storage_charge); - let computation_reward = balance::create_for_testing(computation_charge); - let storage_rebate = advance_epoch( - storage_reward, - computation_reward, - wrapper, - new_epoch, - next_protocol_version, - storage_rebate, - non_refundable_storage_fee, - storage_fund_reinvest_rate, - reward_slashing_rate, - epoch_start_timestamp_ms, - ctx, - ); - storage_rebate - } -} diff --git a/crates/sui-framework/packages/sui-system/sources/sui_system_state_inner.move b/crates/sui-framework/packages/sui-system/sources/sui_system_state_inner.move deleted file mode 100644 index c0178590635..00000000000 --- a/crates/sui-framework/packages/sui-system/sources/sui_system_state_inner.move +++ /dev/null @@ -1,1154 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::sui_system_state_inner { - use sui::balance::{Self, Balance}; - use sui::coin::Coin; - use sui_system::staking_pool::{stake_activation_epoch, StakedSui}; - use sui::sui::SUI; - use sui_system::validator::{Self, Validator}; - use sui_system::validator_set::{Self, ValidatorSet}; - use sui_system::validator_cap::{UnverifiedValidatorOperationCap, ValidatorOperationCap}; - use sui_system::stake_subsidy::StakeSubsidy; - use sui_system::storage_fund::{Self, StorageFund}; - use sui_system::staking_pool::PoolTokenExchangeRate; - use sui::vec_map::{Self, VecMap}; - use sui::vec_set::{Self, VecSet}; - use sui::event; - use sui::table::Table; - use sui::bag::Bag; - use sui::bag; - - /* friend sui_system::genesis; */ - /* friend sui_system::sui_system; */ - - /* #[test_only] */ - /* friend sui_system::governance_test_utils; */ - - // same as in validator_set - const ACTIVE_VALIDATOR_ONLY: u8 = 1; - const ACTIVE_OR_PENDING_VALIDATOR: u8 = 2; - const ANY_VALIDATOR: u8 = 3; - - const SYSTEM_STATE_VERSION_V1: u64 = 1; - - /// A list of system config parameters. - public struct SystemParameters has store { - /// The duration of an epoch, in milliseconds. - epoch_duration_ms: u64, - - /// The starting epoch in which stake subsidies start being paid out - stake_subsidy_start_epoch: u64, - - /// Maximum number of active validators at any moment. - /// We do not allow the number of validators in any epoch to go above this. - max_validator_count: u64, - - /// Lower-bound on the amount of stake required to become a validator. - min_validator_joining_stake: u64, - - /// Validators with stake amount below `validator_low_stake_threshold` are considered to - /// have low stake and will be escorted out of the validator set after being below this - /// threshold for more than `validator_low_stake_grace_period` number of epochs. - validator_low_stake_threshold: u64, - - /// Validators with stake below `validator_very_low_stake_threshold` will be removed - /// immediately at epoch change, no grace period. - validator_very_low_stake_threshold: u64, - - /// A validator can have stake below `validator_low_stake_threshold` - /// for this many epochs before being kicked out. - validator_low_stake_grace_period: u64, - - /// Any extra fields that's not defined statically. - extra_fields: Bag, - } - - /// Added min_validator_count. - public struct SystemParametersV2 has store { - /// The duration of an epoch, in milliseconds. - epoch_duration_ms: u64, - - /// The starting epoch in which stake subsidies start being paid out - stake_subsidy_start_epoch: u64, - - /// Minimum number of active validators at any moment. - min_validator_count: u64, - - /// Maximum number of active validators at any moment. - /// We do not allow the number of validators in any epoch to go above this. - max_validator_count: u64, - - /// Lower-bound on the amount of stake required to become a validator. - min_validator_joining_stake: u64, - - /// Validators with stake amount below `validator_low_stake_threshold` are considered to - /// have low stake and will be escorted out of the validator set after being below this - /// threshold for more than `validator_low_stake_grace_period` number of epochs. - validator_low_stake_threshold: u64, - - /// Validators with stake below `validator_very_low_stake_threshold` will be removed - /// immediately at epoch change, no grace period. - validator_very_low_stake_threshold: u64, - - /// A validator can have stake below `validator_low_stake_threshold` - /// for this many epochs before being kicked out. - validator_low_stake_grace_period: u64, - - /// Any extra fields that's not defined statically. - extra_fields: Bag, - } - - /// The top-level object containing all information of the Sui system. - public struct SuiSystemStateInner has store { - /// The current epoch ID, starting from 0. - epoch: u64, - /// The current protocol version, starting from 1. - protocol_version: u64, - /// The current version of the system state data structure type. - /// This is always the same as SuiSystemState.version. Keeping a copy here so that - /// we know what version it is by inspecting SuiSystemStateInner as well. - system_state_version: u64, - /// Contains all information about the validators. - validators: ValidatorSet, - /// The storage fund. - storage_fund: StorageFund, - /// A list of system config parameters. - parameters: SystemParameters, - /// The reference gas price for the current epoch. - reference_gas_price: u64, - /// A map storing the records of validator reporting each other. - /// There is an entry in the map for each validator that has been reported - /// at least once. The entry VecSet contains all the validators that reported - /// them. If a validator has never been reported they don't have an entry in this map. - /// This map persists across epoch: a peer continues being in a reported state until the - /// reporter doesn't explicitly remove their report. - /// Note that in case we want to support validator address change in future, - /// the reports should be based on validator ids - validator_report_records: VecMap>, - /// Schedule of stake subsidies given out each epoch. - stake_subsidy: StakeSubsidy, - - /// Whether the system is running in a downgraded safe mode due to a non-recoverable bug. - /// This is set whenever we failed to execute advance_epoch, and ended up executing advance_epoch_safe_mode. - /// It can be reset once we are able to successfully execute advance_epoch. - /// The rest of the fields starting with `safe_mode_` are accmulated during safe mode - /// when advance_epoch_safe_mode is executed. They will eventually be processed once we - /// are out of safe mode. - safe_mode: bool, - safe_mode_storage_rewards: Balance, - safe_mode_computation_rewards: Balance, - safe_mode_storage_rebates: u64, - safe_mode_non_refundable_storage_fee: u64, - - /// Unix timestamp of the current epoch start - epoch_start_timestamp_ms: u64, - /// Any extra fields that's not defined statically. - extra_fields: Bag, - } - - /// Uses SystemParametersV2 as the parameters. - public struct SuiSystemStateInnerV2 has store { - /// The current epoch ID, starting from 0. - epoch: u64, - /// The current protocol version, starting from 1. - protocol_version: u64, - /// The current version of the system state data structure type. - /// This is always the same as SuiSystemState.version. Keeping a copy here so that - /// we know what version it is by inspecting SuiSystemStateInner as well. - system_state_version: u64, - /// Contains all information about the validators. - validators: ValidatorSet, - /// The storage fund. - storage_fund: StorageFund, - /// A list of system config parameters. - parameters: SystemParametersV2, - /// The reference gas price for the current epoch. - reference_gas_price: u64, - /// A map storing the records of validator reporting each other. - /// There is an entry in the map for each validator that has been reported - /// at least once. The entry VecSet contains all the validators that reported - /// them. If a validator has never been reported they don't have an entry in this map. - /// This map persists across epoch: a peer continues being in a reported state until the - /// reporter doesn't explicitly remove their report. - /// Note that in case we want to support validator address change in future, - /// the reports should be based on validator ids - validator_report_records: VecMap>, - /// Schedule of stake subsidies given out each epoch. - stake_subsidy: StakeSubsidy, - - /// Whether the system is running in a downgraded safe mode due to a non-recoverable bug. - /// This is set whenever we failed to execute advance_epoch, and ended up executing advance_epoch_safe_mode. - /// It can be reset once we are able to successfully execute advance_epoch. - /// The rest of the fields starting with `safe_mode_` are accmulated during safe mode - /// when advance_epoch_safe_mode is executed. They will eventually be processed once we - /// are out of safe mode. - safe_mode: bool, - safe_mode_storage_rewards: Balance, - safe_mode_computation_rewards: Balance, - safe_mode_storage_rebates: u64, - safe_mode_non_refundable_storage_fee: u64, - - /// Unix timestamp of the current epoch start - epoch_start_timestamp_ms: u64, - /// Any extra fields that's not defined statically. - extra_fields: Bag, - } - - /// Event containing system-level epoch information, emitted during - /// the epoch advancement transaction. - public struct SystemEpochInfoEvent has copy, drop { - epoch: u64, - protocol_version: u64, - reference_gas_price: u64, - total_stake: u64, - storage_fund_reinvestment: u64, - storage_charge: u64, - storage_rebate: u64, - storage_fund_balance: u64, - stake_subsidy_amount: u64, - total_gas_fees: u64, - total_stake_rewards_distributed: u64, - leftover_storage_fund_inflow: u64, - } - - // Errors - const ENotValidator: u64 = 0; - const ELimitExceeded: u64 = 1; - #[allow(unused_const)] - const ENotSystemAddress: u64 = 2; - const ECannotReportOneself: u64 = 3; - const EReportRecordNotFound: u64 = 4; - const EBpsTooLarge: u64 = 5; - const EStakeWithdrawBeforeActivation: u64 = 6; - const ESafeModeGasNotProcessed: u64 = 7; - const EAdvancedToWrongEpoch: u64 = 8; - - const BASIS_POINT_DENOMINATOR: u128 = 10000; - - // ==== functions that can only be called by genesis ==== - - /// Create a new SuiSystemState object and make it shared. - /// This function will be called only once in genesis. - public(package) fun create( - validators: vector, - initial_storage_fund: Balance, - protocol_version: u64, - epoch_start_timestamp_ms: u64, - parameters: SystemParameters, - stake_subsidy: StakeSubsidy, - ctx: &mut TxContext, - ): SuiSystemStateInner { - let validators = validator_set::new(validators, ctx); - let reference_gas_price = validators.derive_reference_gas_price(); - // This type is fixed as it's created at genesis. It should not be updated during type upgrade. - let system_state = SuiSystemStateInner { - epoch: 0, - protocol_version, - system_state_version: genesis_system_state_version(), - validators, - storage_fund: storage_fund::new(initial_storage_fund), - parameters, - reference_gas_price, - validator_report_records: vec_map::empty(), - stake_subsidy, - safe_mode: false, - safe_mode_storage_rewards: balance::zero(), - safe_mode_computation_rewards: balance::zero(), - safe_mode_storage_rebates: 0, - safe_mode_non_refundable_storage_fee: 0, - epoch_start_timestamp_ms, - extra_fields: bag::new(ctx), - }; - system_state - } - - public(package) fun create_system_parameters( - epoch_duration_ms: u64, - stake_subsidy_start_epoch: u64, - - // Validator committee parameters - max_validator_count: u64, - min_validator_joining_stake: u64, - validator_low_stake_threshold: u64, - validator_very_low_stake_threshold: u64, - validator_low_stake_grace_period: u64, - ctx: &mut TxContext, - ): SystemParameters { - SystemParameters { - epoch_duration_ms, - stake_subsidy_start_epoch, - max_validator_count, - min_validator_joining_stake, - validator_low_stake_threshold, - validator_very_low_stake_threshold, - validator_low_stake_grace_period, - extra_fields: bag::new(ctx), - } - } - - public(package) fun v1_to_v2(self: SuiSystemStateInner): SuiSystemStateInnerV2 { - let SuiSystemStateInner { - epoch, - protocol_version, - system_state_version: _, - validators, - storage_fund, - parameters, - reference_gas_price, - validator_report_records, - stake_subsidy, - safe_mode, - safe_mode_storage_rewards, - safe_mode_computation_rewards, - safe_mode_storage_rebates, - safe_mode_non_refundable_storage_fee, - epoch_start_timestamp_ms, - extra_fields: state_extra_fields, - } = self; - let SystemParameters { - epoch_duration_ms, - stake_subsidy_start_epoch, - max_validator_count, - min_validator_joining_stake, - validator_low_stake_threshold, - validator_very_low_stake_threshold, - validator_low_stake_grace_period, - extra_fields: param_extra_fields, - } = parameters; - SuiSystemStateInnerV2 { - epoch, - protocol_version, - system_state_version: 2, - validators, - storage_fund, - parameters: SystemParametersV2 { - epoch_duration_ms, - stake_subsidy_start_epoch, - min_validator_count: 4, - max_validator_count, - min_validator_joining_stake, - validator_low_stake_threshold, - validator_very_low_stake_threshold, - validator_low_stake_grace_period, - extra_fields: param_extra_fields, - }, - reference_gas_price, - validator_report_records, - stake_subsidy, - safe_mode, - safe_mode_storage_rewards, - safe_mode_computation_rewards, - safe_mode_storage_rebates, - safe_mode_non_refundable_storage_fee, - epoch_start_timestamp_ms, - extra_fields: state_extra_fields - } - } - - // ==== public(friend) functions ==== - - /// Can be called by anyone who wishes to become a validator candidate and starts accuring delegated - /// stakes in their staking pool. Once they have at least `MIN_VALIDATOR_JOINING_STAKE` amount of stake they - /// can call `request_add_validator` to officially become an active validator at the next epoch. - /// Aborts if the caller is already a pending or active validator, or a validator candidate. - /// Note: `proof_of_possession` MUST be a valid signature using sui_address and protocol_pubkey_bytes. - /// To produce a valid PoP, run [fn test_proof_of_possession]. - public(package) fun request_add_validator_candidate( - self: &mut SuiSystemStateInnerV2, - pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - proof_of_possession: vector, - name: vector, - description: vector, - image_url: vector, - project_url: vector, - net_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - gas_price: u64, - commission_rate: u64, - ctx: &mut TxContext, - ) { - let validator = validator::new( - ctx.sender(), - pubkey_bytes, - network_pubkey_bytes, - worker_pubkey_bytes, - proof_of_possession, - name, - description, - image_url, - project_url, - net_address, - p2p_address, - primary_address, - worker_address, - gas_price, - commission_rate, - ctx - ); - - self.validators.request_add_validator_candidate(validator, ctx); - } - - /// Called by a validator candidate to remove themselves from the candidacy. After this call - /// their staking pool becomes deactivate. - public(package) fun request_remove_validator_candidate( - self: &mut SuiSystemStateInnerV2, - ctx: &mut TxContext, - ) { - self.validators.request_remove_validator_candidate(ctx); - } - - /// Called by a validator candidate to add themselves to the active validator set beginning next epoch. - /// Aborts if the validator is a duplicate with one of the pending or active validators, or if the amount of - /// stake the validator has doesn't meet the min threshold, or if the number of new validators for the next - /// epoch has already reached the maximum. - public(package) fun request_add_validator( - self: &mut SuiSystemStateInnerV2, - ctx: &TxContext, - ) { - assert!( - self.validators.next_epoch_validator_count() < self.parameters.max_validator_count, - ELimitExceeded, - ); - - self.validators.request_add_validator(self.parameters.min_validator_joining_stake, ctx); - } - - /// A validator can call this function to request a removal in the next epoch. - /// We use the sender of `ctx` to look up the validator - /// (i.e. sender must match the sui_address in the validator). - /// At the end of the epoch, the `validator` object will be returned to the sui_address - /// of the validator. - public(package) fun request_remove_validator( - self: &mut SuiSystemStateInnerV2, - ctx: &TxContext, - ) { - // Only check min validator condition if the current number of validators satisfy the constraint. - // This is so that if we somehow already are in a state where we have less than min validators, it no longer matters - // and is ok to stay so. This is useful for a test setup. - if (self.validators.active_validators().length() >= self.parameters.min_validator_count) { - assert!( - self.validators.next_epoch_validator_count() > self.parameters.min_validator_count, - ELimitExceeded, - ); - }; - - self.validators.request_remove_validator(ctx) - } - - /// A validator can call this function to submit a new gas price quote, to be - /// used for the reference gas price calculation at the end of the epoch. - public(package) fun request_set_gas_price( - self: &mut SuiSystemStateInnerV2, - cap: &UnverifiedValidatorOperationCap, - new_gas_price: u64, - ) { - // Verify the represented address is an active or pending validator, and the capability is still valid. - let verified_cap = self.validators.verify_cap(cap, ACTIVE_OR_PENDING_VALIDATOR); - let validator = self.validators.get_validator_mut_with_verified_cap(&verified_cap, false /* include_candidate */); - - validator.request_set_gas_price(verified_cap, new_gas_price); - } - - /// This function is used to set new gas price for candidate validators - public(package) fun set_candidate_validator_gas_price( - self: &mut SuiSystemStateInnerV2, - cap: &UnverifiedValidatorOperationCap, - new_gas_price: u64, - ) { - // Verify the represented address is an active or pending validator, and the capability is still valid. - let verified_cap = self.validators.verify_cap(cap, ANY_VALIDATOR); - let candidate = self.validators.get_validator_mut_with_verified_cap(&verified_cap, true /* include_candidate */); - candidate.set_candidate_gas_price(verified_cap, new_gas_price) - } - - /// A validator can call this function to set a new commission rate, updated at the end of - /// the epoch. - public(package) fun request_set_commission_rate( - self: &mut SuiSystemStateInnerV2, - new_commission_rate: u64, - ctx: &TxContext, - ) { - self.validators.request_set_commission_rate( - new_commission_rate, - ctx - ) - } - - /// This function is used to set new commission rate for candidate validators - public(package) fun set_candidate_validator_commission_rate( - self: &mut SuiSystemStateInnerV2, - new_commission_rate: u64, - ctx: &TxContext, - ) { - let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); - candidate.set_candidate_commission_rate(new_commission_rate) - } - - /// Add stake to a validator's staking pool. - public(package) fun request_add_stake( - self: &mut SuiSystemStateInnerV2, - stake: Coin, - validator_address: address, - ctx: &mut TxContext, - ) : StakedSui { - self.validators.request_add_stake( - validator_address, - stake.into_balance(), - ctx, - ) - } - - /// Add stake to a validator's staking pool using multiple coins. - public(package) fun request_add_stake_mul_coin( - self: &mut SuiSystemStateInnerV2, - stakes: vector>, - stake_amount: option::Option, - validator_address: address, - ctx: &mut TxContext, - ) : StakedSui { - let balance = extract_coin_balance(stakes, stake_amount, ctx); - self.validators.request_add_stake(validator_address, balance, ctx) - } - - /// Withdraw some portion of a stake from a validator's staking pool. - public(package) fun request_withdraw_stake( - self: &mut SuiSystemStateInnerV2, - staked_sui: StakedSui, - ctx: &TxContext, - ) : Balance { - assert!( - stake_activation_epoch(&staked_sui) <= ctx.epoch(), - EStakeWithdrawBeforeActivation - ); - self.validators.request_withdraw_stake(staked_sui, ctx) - } - - /// Report a validator as a bad or non-performant actor in the system. - /// Succeeds if all the following are satisfied: - /// 1. both the reporter in `cap` and the input `reportee_addr` are active validators. - /// 2. reporter and reportee not the same address. - /// 3. the cap object is still valid. - /// This function is idempotent. - public(package) fun report_validator( - self: &mut SuiSystemStateInnerV2, - cap: &UnverifiedValidatorOperationCap, - reportee_addr: address, - ) { - // Reportee needs to be an active validator - assert!(self.validators.is_active_validator_by_sui_address(reportee_addr), ENotValidator); - // Verify the represented reporter address is an active validator, and the capability is still valid. - let verified_cap = self.validators.verify_cap(cap, ACTIVE_VALIDATOR_ONLY); - report_validator_impl(verified_cap, reportee_addr, &mut self.validator_report_records); - } - - - /// Undo a `report_validator` action. Aborts if - /// 1. the reportee is not a currently active validator or - /// 2. the sender has not previously reported the `reportee_addr`, or - /// 3. the cap is not valid - public(package) fun undo_report_validator( - self: &mut SuiSystemStateInnerV2, - cap: &UnverifiedValidatorOperationCap, - reportee_addr: address, - ) { - let verified_cap = self.validators.verify_cap(cap, ACTIVE_VALIDATOR_ONLY); - undo_report_validator_impl(verified_cap, reportee_addr, &mut self.validator_report_records); - } - - fun report_validator_impl( - verified_cap: ValidatorOperationCap, - reportee_addr: address, - validator_report_records: &mut VecMap>, - ) { - let reporter_address = *verified_cap.verified_operation_cap_address(); - assert!(reporter_address != reportee_addr, ECannotReportOneself); - if (!validator_report_records.contains(&reportee_addr)) { - validator_report_records.insert(reportee_addr, vec_set::singleton(reporter_address)); - } else { - let reporters = validator_report_records.get_mut(&reportee_addr); - if (!reporters.contains(&reporter_address)) { - reporters.insert(reporter_address); - } - } - } - - fun undo_report_validator_impl( - verified_cap: ValidatorOperationCap, - reportee_addr: address, - validator_report_records: &mut VecMap>, - ) { - assert!(validator_report_records.contains(&reportee_addr), EReportRecordNotFound); - let reporters = validator_report_records.get_mut(&reportee_addr); - - let reporter_addr = *verified_cap.verified_operation_cap_address(); - assert!(reporters.contains(&reporter_addr), EReportRecordNotFound); - - reporters.remove(&reporter_addr); - if (reporters.is_empty()) { - validator_report_records.remove(&reportee_addr); - } - } - - // ==== validator metadata management functions ==== - - /// Create a new `UnverifiedValidatorOperationCap`, transfer it to the - /// validator and registers it. The original object is thus revoked. - public(package) fun rotate_operation_cap( - self: &mut SuiSystemStateInnerV2, - ctx: &mut TxContext, - ) { - let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); - validator.new_unverified_validator_operation_cap_and_transfer(ctx); - } - - /// Update a validator's name. - public(package) fun update_validator_name( - self: &mut SuiSystemStateInnerV2, - name: vector, - ctx: &TxContext, - ) { - let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); - - validator.update_name(name); - } - - /// Update a validator's description - public(package) fun update_validator_description( - self: &mut SuiSystemStateInnerV2, - description: vector, - ctx: &TxContext, - ) { - let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); - validator.update_description(description); - } - - /// Update a validator's image url - public(package) fun update_validator_image_url( - self: &mut SuiSystemStateInnerV2, - image_url: vector, - ctx: &TxContext, - ) { - let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); - validator.update_image_url(image_url); - } - - /// Update a validator's project url - public(package) fun update_validator_project_url( - self: &mut SuiSystemStateInnerV2, - project_url: vector, - ctx: &TxContext, - ) { - let validator = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); - validator.update_project_url(project_url); - } - - /// Update a validator's network address. - /// The change will only take effects starting from the next epoch. - public(package) fun update_validator_next_epoch_network_address( - self: &mut SuiSystemStateInnerV2, - network_address: vector, - ctx: &TxContext, - ) { - let validator = self.validators.get_validator_mut_with_ctx(ctx); - validator.update_next_epoch_network_address(network_address); - let validator :&Validator = validator; // Force immutability for the following call - self.validators.assert_no_pending_or_active_duplicates(validator); - } - - /// Update candidate validator's network address. - public(package) fun update_candidate_validator_network_address( - self: &mut SuiSystemStateInnerV2, - network_address: vector, - ctx: &TxContext, - ) { - let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); - candidate.update_candidate_network_address(network_address); - } - - /// Update a validator's p2p address. - /// The change will only take effects starting from the next epoch. - public(package) fun update_validator_next_epoch_p2p_address( - self: &mut SuiSystemStateInnerV2, - p2p_address: vector, - ctx: &TxContext, - ) { - let validator = self.validators.get_validator_mut_with_ctx(ctx); - validator.update_next_epoch_p2p_address(p2p_address); - let validator :&Validator = validator; // Force immutability for the following call - self.validators.assert_no_pending_or_active_duplicates(validator); - } - - /// Update candidate validator's p2p address. - public(package) fun update_candidate_validator_p2p_address( - self: &mut SuiSystemStateInnerV2, - p2p_address: vector, - ctx: &TxContext, - ) { - let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); - candidate.update_candidate_p2p_address(p2p_address); - } - - /// Update a validator's narwhal primary address. - /// The change will only take effects starting from the next epoch. - public(package) fun update_validator_next_epoch_primary_address( - self: &mut SuiSystemStateInnerV2, - primary_address: vector, - ctx: &TxContext, - ) { - let validator = self.validators.get_validator_mut_with_ctx(ctx); - validator.update_next_epoch_primary_address(primary_address); - } - - /// Update candidate validator's narwhal primary address. - public(package) fun update_candidate_validator_primary_address( - self: &mut SuiSystemStateInnerV2, - primary_address: vector, - ctx: &TxContext, - ) { - let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); - candidate.update_candidate_primary_address(primary_address); - } - - /// Update a validator's narwhal worker address. - /// The change will only take effects starting from the next epoch. - public(package) fun update_validator_next_epoch_worker_address( - self: &mut SuiSystemStateInnerV2, - worker_address: vector, - ctx: &TxContext, - ) { - let validator = self.validators.get_validator_mut_with_ctx(ctx); - validator.update_next_epoch_worker_address(worker_address); - } - - /// Update candidate validator's narwhal worker address. - public(package) fun update_candidate_validator_worker_address( - self: &mut SuiSystemStateInnerV2, - worker_address: vector, - ctx: &TxContext, - ) { - let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); - candidate.update_candidate_worker_address(worker_address); - } - - /// Update a validator's public key of protocol key and proof of possession. - /// The change will only take effects starting from the next epoch. - public(package) fun update_validator_next_epoch_protocol_pubkey( - self: &mut SuiSystemStateInnerV2, - protocol_pubkey: vector, - proof_of_possession: vector, - ctx: &TxContext, - ) { - let validator = self.validators.get_validator_mut_with_ctx(ctx); - validator.update_next_epoch_protocol_pubkey(protocol_pubkey, proof_of_possession); - let validator :&Validator = validator; // Force immutability for the following call - self.validators.assert_no_pending_or_active_duplicates(validator); - } - - /// Update candidate validator's public key of protocol key and proof of possession. - public(package) fun update_candidate_validator_protocol_pubkey( - self: &mut SuiSystemStateInnerV2, - protocol_pubkey: vector, - proof_of_possession: vector, - ctx: &TxContext, - ) { - let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); - candidate.update_candidate_protocol_pubkey(protocol_pubkey, proof_of_possession); - } - - /// Update a validator's public key of worker key. - /// The change will only take effects starting from the next epoch. - public(package) fun update_validator_next_epoch_worker_pubkey( - self: &mut SuiSystemStateInnerV2, - worker_pubkey: vector, - ctx: &TxContext, - ) { - let validator = self.validators.get_validator_mut_with_ctx(ctx); - validator.update_next_epoch_worker_pubkey(worker_pubkey); - let validator :&Validator = validator; // Force immutability for the following call - self.validators.assert_no_pending_or_active_duplicates(validator); - } - - /// Update candidate validator's public key of worker key. - public(package) fun update_candidate_validator_worker_pubkey( - self: &mut SuiSystemStateInnerV2, - worker_pubkey: vector, - ctx: &TxContext, - ) { - let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); - candidate.update_candidate_worker_pubkey(worker_pubkey); - } - - /// Update a validator's public key of network key. - /// The change will only take effects starting from the next epoch. - public(package) fun update_validator_next_epoch_network_pubkey( - self: &mut SuiSystemStateInnerV2, - network_pubkey: vector, - ctx: &TxContext, - ) { - let validator = self.validators.get_validator_mut_with_ctx(ctx); - validator.update_next_epoch_network_pubkey(network_pubkey); - let validator :&Validator = validator; // Force immutability for the following call - self.validators.assert_no_pending_or_active_duplicates(validator); - } - - /// Update candidate validator's public key of network key. - public(package) fun update_candidate_validator_network_pubkey( - self: &mut SuiSystemStateInnerV2, - network_pubkey: vector, - ctx: &TxContext, - ) { - let candidate = self.validators.get_validator_mut_with_ctx_including_candidates(ctx); - candidate.update_candidate_network_pubkey(network_pubkey); - } - - /// This function should be called at the end of an epoch, and advances the system to the next epoch. - /// It does the following things: - /// 1. Add storage charge to the storage fund. - /// 2. Burn the storage rebates from the storage fund. These are already refunded to transaction sender's - /// gas coins. - /// 3. Distribute computation charge to validator stake. - /// 4. Update all validators. - public(package) fun advance_epoch( - self: &mut SuiSystemStateInnerV2, - new_epoch: u64, - next_protocol_version: u64, - mut storage_reward: Balance, - mut computation_reward: Balance, - mut storage_rebate_amount: u64, - mut non_refundable_storage_fee_amount: u64, - storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested - // into storage fund, in basis point. - reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. - epoch_start_timestamp_ms: u64, // Timestamp of the epoch start - ctx: &mut TxContext, - ) : Balance { - let prev_epoch_start_timestamp = self.epoch_start_timestamp_ms; - self.epoch_start_timestamp_ms = epoch_start_timestamp_ms; - - let bps_denominator_u64 = BASIS_POINT_DENOMINATOR as u64; - // Rates can't be higher than 100%. - assert!( - storage_fund_reinvest_rate <= bps_denominator_u64 - && reward_slashing_rate <= bps_denominator_u64, - EBpsTooLarge, - ); - - // TODO: remove this in later upgrade. - if (self.parameters.stake_subsidy_start_epoch > 0) { - self.parameters.stake_subsidy_start_epoch = 20; - }; - - // Accumulate the gas summary during safe_mode before processing any rewards: - let safe_mode_storage_rewards = self.safe_mode_storage_rewards.withdraw_all(); - storage_reward.join(safe_mode_storage_rewards); - let safe_mode_computation_rewards = self.safe_mode_computation_rewards.withdraw_all(); - computation_reward.join(safe_mode_computation_rewards); - storage_rebate_amount = storage_rebate_amount + self.safe_mode_storage_rebates; - self.safe_mode_storage_rebates = 0; - non_refundable_storage_fee_amount = non_refundable_storage_fee_amount + self.safe_mode_non_refundable_storage_fee; - self.safe_mode_non_refundable_storage_fee = 0; - - let total_validators_stake = self.validators.total_stake(); - let storage_fund_balance = self.storage_fund.total_balance(); - let total_stake = storage_fund_balance + total_validators_stake; - - let storage_charge = storage_reward.value(); - let computation_charge = computation_reward.value(); - - // Include stake subsidy in the rewards given out to validators and stakers. - // Delay distributing any stake subsidies until after `stake_subsidy_start_epoch`. - // And if this epoch is shorter than the regular epoch duration, don't distribute any stake subsidy. - let stake_subsidy = - if (ctx.epoch() >= self.parameters.stake_subsidy_start_epoch && - epoch_start_timestamp_ms >= prev_epoch_start_timestamp + self.parameters.epoch_duration_ms) - { - self.stake_subsidy.advance_epoch() - } else { - balance::zero() - }; - - let stake_subsidy_amount = stake_subsidy.value(); - computation_reward.join(stake_subsidy); - - let total_stake_u128 = total_stake as u128; - let computation_charge_u128 = computation_charge as u128; - - let storage_fund_reward_amount = storage_fund_balance as u128 * computation_charge_u128 / total_stake_u128; - let mut storage_fund_reward = computation_reward.split(storage_fund_reward_amount as u64); - let storage_fund_reinvestment_amount = - storage_fund_reward_amount * (storage_fund_reinvest_rate as u128) / BASIS_POINT_DENOMINATOR; - let storage_fund_reinvestment = storage_fund_reward.split( - storage_fund_reinvestment_amount as u64, - ); - - self.epoch = self.epoch + 1; - // Sanity check to make sure we are advancing to the right epoch. - assert!(new_epoch == self.epoch, EAdvancedToWrongEpoch); - - let computation_reward_amount_before_distribution = computation_reward.value(); - let storage_fund_reward_amount_before_distribution = storage_fund_reward.value(); - - self.validators.advance_epoch( - &mut computation_reward, - &mut storage_fund_reward, - &mut self.validator_report_records, - reward_slashing_rate, - self.parameters.validator_low_stake_threshold, - self.parameters.validator_very_low_stake_threshold, - self.parameters.validator_low_stake_grace_period, - ctx, - ); - - let new_total_stake = self.validators.total_stake(); - - let computation_reward_amount_after_distribution = computation_reward.value(); - let storage_fund_reward_amount_after_distribution = storage_fund_reward.value(); - let computation_reward_distributed = computation_reward_amount_before_distribution - computation_reward_amount_after_distribution; - let storage_fund_reward_distributed = storage_fund_reward_amount_before_distribution - storage_fund_reward_amount_after_distribution; - - self.protocol_version = next_protocol_version; - - // Derive the reference gas price for the new epoch - self.reference_gas_price = self.validators.derive_reference_gas_price(); - // Because of precision issues with integer divisions, we expect that there will be some - // remaining balance in `storage_fund_reward` and `computation_reward`. - // All of these go to the storage fund. - let mut leftover_staking_rewards = storage_fund_reward; - leftover_staking_rewards.join(computation_reward); - let leftover_storage_fund_inflow = leftover_staking_rewards.value(); - - let refunded_storage_rebate = - self.storage_fund.advance_epoch( - storage_reward, - storage_fund_reinvestment, - leftover_staking_rewards, - storage_rebate_amount, - non_refundable_storage_fee_amount, - ); - - event::emit( - SystemEpochInfoEvent { - epoch: self.epoch, - protocol_version: self.protocol_version, - reference_gas_price: self.reference_gas_price, - total_stake: new_total_stake, - storage_charge, - storage_fund_reinvestment: storage_fund_reinvestment_amount as u64, - storage_rebate: storage_rebate_amount, - storage_fund_balance: self.storage_fund.total_balance(), - stake_subsidy_amount, - total_gas_fees: computation_charge, - total_stake_rewards_distributed: computation_reward_distributed + storage_fund_reward_distributed, - leftover_storage_fund_inflow, - } - ); - self.safe_mode = false; - // Double check that the gas from safe mode has been processed. - assert!(self.safe_mode_storage_rebates == 0 - && self.safe_mode_storage_rewards.value() == 0 - && self.safe_mode_computation_rewards.value() == 0, ESafeModeGasNotProcessed); - - // Return the storage rebate split from storage fund that's already refunded to the transaction senders. - // This will be burnt at the last step of epoch change programmable transaction. - refunded_storage_rebate - } - - /// Return the current epoch number. Useful for applications that need a coarse-grained concept of time, - /// since epochs are ever-increasing and epoch changes are intended to happen every 24 hours. - public(package) fun epoch(self: &SuiSystemStateInnerV2): u64 { - self.epoch - } - - public(package) fun protocol_version(self: &SuiSystemStateInnerV2): u64 { - self.protocol_version - } - - public(package) fun system_state_version(self: &SuiSystemStateInnerV2): u64 { - self.system_state_version - } - - /// This function always return the genesis system state version, which is used to create the system state in genesis. - /// It should never change for a given network. - public(package) fun genesis_system_state_version(): u64 { - SYSTEM_STATE_VERSION_V1 - } - - /// Returns unix timestamp of the start of current epoch - public(package) fun epoch_start_timestamp_ms(self: &SuiSystemStateInnerV2): u64 { - self.epoch_start_timestamp_ms - } - - /// Returns the total amount staked with `validator_addr`. - /// Aborts if `validator_addr` is not an active validator. - public(package) fun validator_stake_amount(self: &SuiSystemStateInnerV2, validator_addr: address): u64 { - self.validators.validator_total_stake_amount(validator_addr) - } - - /// Returns the staking pool id of a given validator. - /// Aborts if `validator_addr` is not an active validator. - public(package) fun validator_staking_pool_id(self: &SuiSystemStateInnerV2, validator_addr: address): ID { - - self.validators.validator_staking_pool_id(validator_addr) - } - - /// Returns reference to the staking pool mappings that map pool ids to active validator addresses - public(package) fun validator_staking_pool_mappings(self: &SuiSystemStateInnerV2): &Table { - - self.validators.staking_pool_mappings() - } - - /// Returns all the validators who are currently reporting `addr` - public(package) fun get_reporters_of(self: &SuiSystemStateInnerV2, addr: address): VecSet
    { - - if (self.validator_report_records.contains(&addr)) { - self.validator_report_records[&addr] - } else { - vec_set::empty() - } - } - - public(package) fun get_storage_fund_total_balance(self: &SuiSystemStateInnerV2): u64 { - self.storage_fund.total_balance() - } - - public(package) fun get_storage_fund_object_rebates(self: &SuiSystemStateInnerV2): u64 { - self.storage_fund.total_object_storage_rebates() - } - - public(package) fun pool_exchange_rates( - self: &mut SuiSystemStateInnerV2, - pool_id: &ID - ): &Table { - let validators = &mut self.validators; - validators.pool_exchange_rates(pool_id) - } - - public(package) fun active_validator_addresses(self: &SuiSystemStateInnerV2): vector
    { - let validator_set = &self.validators; - validator_set.active_validator_addresses() - } - - #[allow(lint(self_transfer))] - /// Extract required Balance from vector of Coin, transfer the remainder back to sender. - fun extract_coin_balance(mut coins: vector>, amount: option::Option, ctx: &mut TxContext): Balance { - let mut merged_coin = coins.pop_back(); - merged_coin.join_vec(coins); - - let mut total_balance = merged_coin.into_balance(); - // return the full amount if amount is not specified - if (amount.is_some()) { - let amount = amount.destroy_some(); - let balance = total_balance.split(amount); - // transfer back the remainder if non zero. - if (total_balance.value() > 0) { - transfer::public_transfer(total_balance.into_coin(ctx), ctx.sender()); - } else { - total_balance.destroy_zero(); - }; - balance - } else { - total_balance - } - } - - #[test_only] - /// Return the current validator set - public(package) fun validators(self: &SuiSystemStateInnerV2): &ValidatorSet { - &self.validators - } - - #[test_only] - /// Return the currently active validator by address - public(package) fun active_validator_by_address(self: &SuiSystemStateInnerV2, validator_address: address): &Validator { - self.validators().get_active_validator_ref(validator_address) - } - - #[test_only] - /// Return the currently pending validator by address - public(package) fun pending_validator_by_address(self: &SuiSystemStateInnerV2, validator_address: address): &Validator { - self.validators().get_pending_validator_ref(validator_address) - } - - #[test_only] - /// Return the currently candidate validator by address - public(package) fun candidate_validator_by_address(self: &SuiSystemStateInnerV2, validator_address: address): &Validator { - validators(self).get_candidate_validator_ref(validator_address) - } - - #[test_only] - public(package) fun get_stake_subsidy_distribution_counter(self: &SuiSystemStateInnerV2): u64 { - self.stake_subsidy.get_distribution_counter() - } - - #[test_only] - public(package) fun set_epoch_for_testing(self: &mut SuiSystemStateInnerV2, epoch_num: u64) { - self.epoch = epoch_num - } - - #[test_only] - public(package) fun request_add_validator_for_testing( - self: &mut SuiSystemStateInnerV2, - min_joining_stake_for_testing: u64, - ctx: &TxContext, - ) { - assert!( - self.validators.next_epoch_validator_count() < self.parameters.max_validator_count, - ELimitExceeded, - ); - - self.validators.request_add_validator(min_joining_stake_for_testing, ctx); - } - - // CAUTION: THIS CODE IS ONLY FOR TESTING AND THIS MACRO MUST NEVER EVER BE REMOVED. Creates a - // candidate validator - bypassing the proof of possession check and other metadata validation - // in the process. - #[test_only] - public(package) fun request_add_validator_candidate_for_testing( - self: &mut SuiSystemStateInnerV2, - pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - proof_of_possession: vector, - name: vector, - description: vector, - image_url: vector, - project_url: vector, - net_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - gas_price: u64, - commission_rate: u64, - ctx: &mut TxContext, - ) { - let validator = validator::new_for_testing( - ctx.sender(), - pubkey_bytes, - network_pubkey_bytes, - worker_pubkey_bytes, - proof_of_possession, - name, - description, - image_url, - project_url, - net_address, - p2p_address, - primary_address, - worker_address, - option::none(), - gas_price, - commission_rate, - false, // not an initial validator active at genesis - ctx - ); - - self.validators.request_add_validator_candidate(validator, ctx); - } - -} diff --git a/crates/sui-framework/packages/sui-system/sources/validator.move b/crates/sui-framework/packages/sui-system/sources/validator.move deleted file mode 100644 index 714fb4b4ce7..00000000000 --- a/crates/sui-framework/packages/sui-system/sources/validator.move +++ /dev/null @@ -1,956 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[allow(unused_const)] -module sui_system::validator { - use std::bcs; - - use sui::balance::Balance; - use sui::sui::SUI; - use sui_system::validator_cap::{Self, ValidatorOperationCap}; - use sui_system::staking_pool::{Self, PoolTokenExchangeRate, StakedSui, StakingPool}; - use std::string::String; - use sui::url::Url; - use sui::url; - use sui::event; - use sui::bag::Bag; - use sui::bag; - /* friend sui_system::genesis; */ - /* friend sui_system::sui_system_state_inner; */ - /* friend sui_system::validator_wrapper; */ - /* friend sui_system::validator_set; */ - /* friend sui_system::voting_power; */ - - /* #[test_only] */ - /* friend sui_system::validator_tests; */ - /* #[test_only] */ - /* friend sui_system::validator_set_tests; */ - /* #[test_only] */ - /* friend sui_system::sui_system_tests; */ - /* #[test_only] */ - /* friend sui_system::governance_test_utils; */ - - /// Invalid proof_of_possession field in ValidatorMetadata - const EInvalidProofOfPossession: u64 = 0; - - /// Invalid pubkey_bytes field in ValidatorMetadata - const EMetadataInvalidPubkey: u64 = 1; - - /// Invalid network_pubkey_bytes field in ValidatorMetadata - const EMetadataInvalidNetPubkey: u64 = 2; - - /// Invalid worker_pubkey_bytes field in ValidatorMetadata - const EMetadataInvalidWorkerPubkey: u64 = 3; - - /// Invalid net_address field in ValidatorMetadata - const EMetadataInvalidNetAddr: u64 = 4; - - /// Invalid p2p_address field in ValidatorMetadata - const EMetadataInvalidP2pAddr: u64 = 5; - - /// Invalid primary_address field in ValidatorMetadata - const EMetadataInvalidPrimaryAddr: u64 = 6; - - /// Invalidworker_address field in ValidatorMetadata - const EMetadataInvalidWorkerAddr: u64 = 7; - - /// Commission rate set by the validator is higher than the threshold - const ECommissionRateTooHigh: u64 = 8; - - /// Validator Metadata is too long - const EValidatorMetadataExceedingLengthLimit: u64 = 9; - - /// Intended validator is not a candidate one. - const ENotValidatorCandidate: u64 = 10; - - /// Stake amount is invalid or wrong. - const EInvalidStakeAmount: u64 = 11; - - /// Function called during non-genesis times. - const ECalledDuringNonGenesis: u64 = 12; - - /// New Capability is not created by the validator itself - const ENewCapNotCreatedByValidatorItself: u64 = 100; - - /// Capability code is not valid - const EInvalidCap: u64 = 101; - - /// Validator trying to set gas price higher than threshold. - const EGasPriceHigherThanThreshold: u64 = 102; - - // TODO: potentially move this value to onchain config. - const MAX_COMMISSION_RATE: u64 = 2_000; // Max rate is 20%, which is 2000 base points - - const MAX_VALIDATOR_METADATA_LENGTH: u64 = 256; - - // TODO: Move this to onchain config when we have a good way to do it. - /// Max gas price a validator can set is 100K MIST. - const MAX_VALIDATOR_GAS_PRICE: u64 = 100_000; - - public struct ValidatorMetadata has store { - /// The Sui Address of the validator. This is the sender that created the Validator object, - /// and also the address to send validator/coins to during withdraws. - sui_address: address, - /// The public key bytes corresponding to the private key that the validator - /// holds to sign transactions. For now, this is the same as AuthorityName. - protocol_pubkey_bytes: vector, - /// The public key bytes corresponding to the private key that the validator - /// uses to establish TLS connections - network_pubkey_bytes: vector, - /// The public key bytes correstponding to the Narwhal Worker - worker_pubkey_bytes: vector, - /// This is a proof that the validator has ownership of the private key - proof_of_possession: vector, - /// A unique human-readable name of this validator. - name: String, - description: String, - image_url: Url, - project_url: Url, - /// The network address of the validator (could also contain extra info such as port, DNS and etc.). - net_address: String, - /// The address of the validator used for p2p activities such as state sync (could also contain extra info such as port, DNS and etc.). - p2p_address: String, - /// The address of the narwhal primary - primary_address: String, - /// The address of the narwhal worker - worker_address: String, - - /// "next_epoch" metadata only takes effects in the next epoch. - /// If none, current value will stay unchanged. - next_epoch_protocol_pubkey_bytes: Option>, - next_epoch_proof_of_possession: Option>, - next_epoch_network_pubkey_bytes: Option>, - next_epoch_worker_pubkey_bytes: Option>, - next_epoch_net_address: Option, - next_epoch_p2p_address: Option, - next_epoch_primary_address: Option, - next_epoch_worker_address: Option, - - /// Any extra fields that's not defined statically. - extra_fields: Bag, - } - - public struct Validator has store { - /// Summary of the validator. - metadata: ValidatorMetadata, - /// The voting power of this validator, which might be different from its - /// stake amount. - voting_power: u64, - /// The ID of this validator's current valid `UnverifiedValidatorOperationCap` - operation_cap_id: ID, - /// Gas price quote, updated only at end of epoch. - gas_price: u64, - /// Staking pool for this validator. - staking_pool: StakingPool, - /// Commission rate of the validator, in basis point. - commission_rate: u64, - /// Total amount of stake that would be active in the next epoch. - next_epoch_stake: u64, - /// This validator's gas price quote for the next epoch. - next_epoch_gas_price: u64, - /// The commission rate of the validator starting the next epoch, in basis point. - next_epoch_commission_rate: u64, - /// Any extra fields that's not defined statically. - extra_fields: Bag, - } - - /// Event emitted when a new stake request is received. - public struct StakingRequestEvent has copy, drop { - pool_id: ID, - validator_address: address, - staker_address: address, - epoch: u64, - amount: u64, - } - - /// Event emitted when a new unstake request is received. - public struct UnstakingRequestEvent has copy, drop { - pool_id: ID, - validator_address: address, - staker_address: address, - stake_activation_epoch: u64, - unstaking_epoch: u64, - principal_amount: u64, - reward_amount: u64, - } - - public(package) fun new_metadata( - sui_address: address, - protocol_pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - proof_of_possession: vector, - name: String, - description: String, - image_url: Url, - project_url: Url, - net_address: String, - p2p_address: String, - primary_address: String, - worker_address: String, - extra_fields: Bag, - ): ValidatorMetadata { - let metadata = ValidatorMetadata { - sui_address, - protocol_pubkey_bytes, - network_pubkey_bytes, - worker_pubkey_bytes, - proof_of_possession, - name, - description, - image_url, - project_url, - net_address, - p2p_address, - primary_address, - worker_address, - next_epoch_protocol_pubkey_bytes: option::none(), - next_epoch_network_pubkey_bytes: option::none(), - next_epoch_worker_pubkey_bytes: option::none(), - next_epoch_proof_of_possession: option::none(), - next_epoch_net_address: option::none(), - next_epoch_p2p_address: option::none(), - next_epoch_primary_address: option::none(), - next_epoch_worker_address: option::none(), - extra_fields, - }; - metadata - } - - public(package) fun new( - sui_address: address, - protocol_pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - proof_of_possession: vector, - name: vector, - description: vector, - image_url: vector, - project_url: vector, - net_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - gas_price: u64, - commission_rate: u64, - ctx: &mut TxContext - ): Validator { - assert!( - net_address.length() <= MAX_VALIDATOR_METADATA_LENGTH - && p2p_address.length() <= MAX_VALIDATOR_METADATA_LENGTH - && primary_address.length() <= MAX_VALIDATOR_METADATA_LENGTH - && worker_address.length() <= MAX_VALIDATOR_METADATA_LENGTH - && name.length() <= MAX_VALIDATOR_METADATA_LENGTH - && description.length() <= MAX_VALIDATOR_METADATA_LENGTH - && image_url.length() <= MAX_VALIDATOR_METADATA_LENGTH - && project_url.length() <= MAX_VALIDATOR_METADATA_LENGTH, - EValidatorMetadataExceedingLengthLimit - ); - assert!(commission_rate <= MAX_COMMISSION_RATE, ECommissionRateTooHigh); - assert!(gas_price < MAX_VALIDATOR_GAS_PRICE, EGasPriceHigherThanThreshold); - - let metadata = new_metadata( - sui_address, - protocol_pubkey_bytes, - network_pubkey_bytes, - worker_pubkey_bytes, - proof_of_possession, - name.to_ascii_string().to_string(), - description.to_ascii_string().to_string(), - url::new_unsafe_from_bytes(image_url), - url::new_unsafe_from_bytes(project_url), - net_address.to_ascii_string().to_string(), - p2p_address.to_ascii_string().to_string(), - primary_address.to_ascii_string().to_string(), - worker_address.to_ascii_string().to_string(), - bag::new(ctx), - ); - - // Checks that the keys & addresses & PoP are valid. - validate_metadata(&metadata); - - new_from_metadata( - metadata, - gas_price, - commission_rate, - ctx - ) - } - - /// Deactivate this validator's staking pool - public(package) fun deactivate(self: &mut Validator, deactivation_epoch: u64) { - self.staking_pool.deactivate_staking_pool(deactivation_epoch) - } - - public(package) fun activate(self: &mut Validator, activation_epoch: u64) { - self.staking_pool.activate_staking_pool(activation_epoch); - } - - /// Process pending stake and pending withdraws, and update the gas price. - public(package) fun adjust_stake_and_gas_price(self: &mut Validator) { - self.gas_price = self.next_epoch_gas_price; - self.commission_rate = self.next_epoch_commission_rate; - } - - /// Request to add stake to the validator's staking pool, processed at the end of the epoch. - public(package) fun request_add_stake( - self: &mut Validator, - stake: Balance, - staker_address: address, - ctx: &mut TxContext, - ) : StakedSui { - let stake_amount = stake.value(); - assert!(stake_amount > 0, EInvalidStakeAmount); - let stake_epoch = ctx.epoch() + 1; - let staked_sui = self.staking_pool.request_add_stake(stake, stake_epoch, ctx); - // Process stake right away if staking pool is preactive. - if (self.staking_pool.is_preactive()) { - self.staking_pool.process_pending_stake(); - }; - self.next_epoch_stake = self.next_epoch_stake + stake_amount; - event::emit( - StakingRequestEvent { - pool_id: staking_pool_id(self), - validator_address: self.metadata.sui_address, - staker_address, - epoch: ctx.epoch(), - amount: stake_amount, - } - ); - staked_sui - } - - /// Request to add stake to the validator's staking pool at genesis - public(package) fun request_add_stake_at_genesis( - self: &mut Validator, - stake: Balance, - staker_address: address, - ctx: &mut TxContext, - ) { - assert!(ctx.epoch() == 0, ECalledDuringNonGenesis); - let stake_amount = stake.value(); - assert!(stake_amount > 0, EInvalidStakeAmount); - - let staked_sui = self.staking_pool.request_add_stake( - stake, - 0, // epoch 0 -- genesis - ctx - ); - - transfer::public_transfer(staked_sui, staker_address); - - // Process stake right away - self.staking_pool.process_pending_stake(); - self.next_epoch_stake = self.next_epoch_stake + stake_amount; - } - - /// Request to withdraw stake from the validator's staking pool, processed at the end of the epoch. - public(package) fun request_withdraw_stake( - self: &mut Validator, - staked_sui: StakedSui, - ctx: &TxContext, - ) : Balance { - let principal_amount = staked_sui.staked_sui_amount(); - let stake_activation_epoch = staked_sui.stake_activation_epoch(); - let withdrawn_stake = self.staking_pool.request_withdraw_stake(staked_sui, ctx); - let withdraw_amount = withdrawn_stake.value(); - let reward_amount = withdraw_amount - principal_amount; - self.next_epoch_stake = self.next_epoch_stake - withdraw_amount; - event::emit( - UnstakingRequestEvent { - pool_id: staking_pool_id(self), - validator_address: self.metadata.sui_address, - staker_address: ctx.sender(), - stake_activation_epoch, - unstaking_epoch: ctx.epoch(), - principal_amount, - reward_amount, - } - ); - withdrawn_stake - } - - /// Request to set new gas price for the next epoch. - /// Need to present a `ValidatorOperationCap`. - public(package) fun request_set_gas_price( - self: &mut Validator, - verified_cap: ValidatorOperationCap, - new_price: u64, - ) { - assert!(new_price < MAX_VALIDATOR_GAS_PRICE, EGasPriceHigherThanThreshold); - let validator_address = *verified_cap.verified_operation_cap_address(); - assert!(validator_address == self.metadata.sui_address, EInvalidCap); - self.next_epoch_gas_price = new_price; - } - - /// Set new gas price for the candidate validator. - public(package) fun set_candidate_gas_price( - self: &mut Validator, - verified_cap: ValidatorOperationCap, - new_price: u64 - ) { - assert!(is_preactive(self), ENotValidatorCandidate); - assert!(new_price < MAX_VALIDATOR_GAS_PRICE, EGasPriceHigherThanThreshold); - let validator_address = *verified_cap.verified_operation_cap_address(); - assert!(validator_address == self.metadata.sui_address, EInvalidCap); - self.next_epoch_gas_price = new_price; - self.gas_price = new_price; - } - - /// Request to set new commission rate for the next epoch. - public(package) fun request_set_commission_rate(self: &mut Validator, new_commission_rate: u64) { - assert!(new_commission_rate <= MAX_COMMISSION_RATE, ECommissionRateTooHigh); - self.next_epoch_commission_rate = new_commission_rate; - } - - /// Set new commission rate for the candidate validator. - public(package) fun set_candidate_commission_rate(self: &mut Validator, new_commission_rate: u64) { - assert!(is_preactive(self), ENotValidatorCandidate); - assert!(new_commission_rate <= MAX_COMMISSION_RATE, ECommissionRateTooHigh); - self.commission_rate = new_commission_rate; - } - - /// Deposit stakes rewards into the validator's staking pool, called at the end of the epoch. - public(package) fun deposit_stake_rewards(self: &mut Validator, reward: Balance) { - self.next_epoch_stake = self.next_epoch_stake + reward.value(); - self.staking_pool.deposit_rewards(reward); - } - - /// Process pending stakes and withdraws, called at the end of the epoch. - public(package) fun process_pending_stakes_and_withdraws(self: &mut Validator, ctx: &TxContext) { - self.staking_pool.process_pending_stakes_and_withdraws(ctx); - assert!(stake_amount(self) == self.next_epoch_stake, EInvalidStakeAmount); - } - - /// Returns true if the validator is preactive. - public fun is_preactive(self: &Validator): bool { - self.staking_pool.is_preactive() - } - - public fun metadata(self: &Validator): &ValidatorMetadata { - &self.metadata - } - - public fun sui_address(self: &Validator): address { - self.metadata.sui_address - } - - public fun name(self: &Validator): &String { - &self.metadata.name - } - - public fun description(self: &Validator): &String { - &self.metadata.description - } - - public fun image_url(self: &Validator): &Url { - &self.metadata.image_url - } - - public fun project_url(self: &Validator): &Url { - &self.metadata.project_url - } - - public fun network_address(self: &Validator): &String { - &self.metadata.net_address - } - - public fun p2p_address(self: &Validator): &String { - &self.metadata.p2p_address - } - - public fun primary_address(self: &Validator): &String { - &self.metadata.primary_address - } - - public fun worker_address(self: &Validator): &String { - &self.metadata.worker_address - } - - public fun protocol_pubkey_bytes(self: &Validator): &vector { - &self.metadata.protocol_pubkey_bytes - } - - public fun proof_of_possession(self: &Validator): &vector { - &self.metadata.proof_of_possession - } - - public fun network_pubkey_bytes(self: &Validator): &vector { - &self.metadata.network_pubkey_bytes - } - - public fun worker_pubkey_bytes(self: &Validator): &vector { - &self.metadata.worker_pubkey_bytes - } - - public fun next_epoch_network_address(self: &Validator): &Option { - &self.metadata.next_epoch_net_address - } - - public fun next_epoch_p2p_address(self: &Validator): &Option { - &self.metadata.next_epoch_p2p_address - } - - public fun next_epoch_primary_address(self: &Validator): &Option { - &self.metadata.next_epoch_primary_address - } - - public fun next_epoch_worker_address(self: &Validator): &Option { - &self.metadata.next_epoch_worker_address - } - - public fun next_epoch_protocol_pubkey_bytes(self: &Validator): &Option> { - &self.metadata.next_epoch_protocol_pubkey_bytes - } - - public fun next_epoch_proof_of_possession(self: &Validator): &Option> { - &self.metadata.next_epoch_proof_of_possession - } - - public fun next_epoch_network_pubkey_bytes(self: &Validator): &Option> { - &self.metadata.next_epoch_network_pubkey_bytes - } - - public fun next_epoch_worker_pubkey_bytes(self: &Validator): &Option> { - &self.metadata.next_epoch_worker_pubkey_bytes - } - - public fun operation_cap_id(self: &Validator): &ID { - &self.operation_cap_id - } - - public fun next_epoch_gas_price(self: &Validator): u64 { - self.next_epoch_gas_price - } - - // TODO: this and `delegate_amount` and `total_stake` all seem to return the same value? - // two of the functions can probably be removed. - public fun total_stake_amount(self: &Validator): u64 { - self.staking_pool.sui_balance() - } - - public fun stake_amount(self: &Validator): u64 { - self.staking_pool.sui_balance() - } - - /// Return the total amount staked with this validator - public fun total_stake(self: &Validator): u64 { - stake_amount(self) - } - - /// Return the voting power of this validator. - public fun voting_power(self: &Validator): u64 { - self.voting_power - } - - /// Set the voting power of this validator, called only from validator_set. - public(package) fun set_voting_power(self: &mut Validator, new_voting_power: u64) { - self.voting_power = new_voting_power; - } - - public fun pending_stake_amount(self: &Validator): u64 { - self.staking_pool.pending_stake_amount() - } - - public fun pending_stake_withdraw_amount(self: &Validator): u64 { - self.staking_pool.pending_stake_withdraw_amount() - } - - public fun gas_price(self: &Validator): u64 { - self.gas_price - } - - public fun commission_rate(self: &Validator): u64 { - self.commission_rate - } - - public fun pool_token_exchange_rate_at_epoch(self: &Validator, epoch: u64): PoolTokenExchangeRate { - self.staking_pool.pool_token_exchange_rate_at_epoch(epoch) - } - - public fun staking_pool_id(self: &Validator): ID { - object::id(&self.staking_pool) - } - - // MUSTFIX: We need to check this when updating metadata as well. - public fun is_duplicate(self: &Validator, other: &Validator): bool { - self.metadata.sui_address == other.metadata.sui_address - || self.metadata.name == other.metadata.name - || self.metadata.net_address == other.metadata.net_address - || self.metadata.p2p_address == other.metadata.p2p_address - || self.metadata.protocol_pubkey_bytes == other.metadata.protocol_pubkey_bytes - || self.metadata.network_pubkey_bytes == other.metadata.network_pubkey_bytes - || self.metadata.network_pubkey_bytes == other.metadata.worker_pubkey_bytes - || self.metadata.worker_pubkey_bytes == other.metadata.worker_pubkey_bytes - || self.metadata.worker_pubkey_bytes == other.metadata.network_pubkey_bytes - // All next epoch parameters. - || is_equal_some(&self.metadata.next_epoch_net_address, &other.metadata.next_epoch_net_address) - || is_equal_some(&self.metadata.next_epoch_p2p_address, &other.metadata.next_epoch_p2p_address) - || is_equal_some(&self.metadata.next_epoch_protocol_pubkey_bytes, &other.metadata.next_epoch_protocol_pubkey_bytes) - || is_equal_some(&self.metadata.next_epoch_network_pubkey_bytes, &other.metadata.next_epoch_network_pubkey_bytes) - || is_equal_some(&self.metadata.next_epoch_network_pubkey_bytes, &other.metadata.next_epoch_worker_pubkey_bytes) - || is_equal_some(&self.metadata.next_epoch_worker_pubkey_bytes, &other.metadata.next_epoch_worker_pubkey_bytes) - || is_equal_some(&self.metadata.next_epoch_worker_pubkey_bytes, &other.metadata.next_epoch_network_pubkey_bytes) - // My next epoch parameters with other current epoch parameters. - || is_equal_some_and_value(&self.metadata.next_epoch_net_address, &other.metadata.net_address) - || is_equal_some_and_value(&self.metadata.next_epoch_p2p_address, &other.metadata.p2p_address) - || is_equal_some_and_value(&self.metadata.next_epoch_protocol_pubkey_bytes, &other.metadata.protocol_pubkey_bytes) - || is_equal_some_and_value(&self.metadata.next_epoch_network_pubkey_bytes, &other.metadata.network_pubkey_bytes) - || is_equal_some_and_value(&self.metadata.next_epoch_network_pubkey_bytes, &other.metadata.worker_pubkey_bytes) - || is_equal_some_and_value(&self.metadata.next_epoch_worker_pubkey_bytes, &other.metadata.worker_pubkey_bytes) - || is_equal_some_and_value(&self.metadata.next_epoch_worker_pubkey_bytes, &other.metadata.network_pubkey_bytes) - // Other next epoch parameters with my current epoch parameters. - || is_equal_some_and_value(&other.metadata.next_epoch_net_address, &self.metadata.net_address) - || is_equal_some_and_value(&other.metadata.next_epoch_p2p_address, &self.metadata.p2p_address) - || is_equal_some_and_value(&other.metadata.next_epoch_protocol_pubkey_bytes, &self.metadata.protocol_pubkey_bytes) - || is_equal_some_and_value(&other.metadata.next_epoch_network_pubkey_bytes, &self.metadata.network_pubkey_bytes) - || is_equal_some_and_value(&other.metadata.next_epoch_network_pubkey_bytes, &self.metadata.worker_pubkey_bytes) - || is_equal_some_and_value(&other.metadata.next_epoch_worker_pubkey_bytes, &self.metadata.worker_pubkey_bytes) - || is_equal_some_and_value(&other.metadata.next_epoch_worker_pubkey_bytes, &self.metadata.network_pubkey_bytes) - } - - fun is_equal_some_and_value(a: &Option, b: &T): bool { - if (a.is_none()) { - false - } else { - a.borrow() == b - } - } - - fun is_equal_some(a: &Option, b: &Option): bool { - if (a.is_none() || b.is_none()) { - false - } else { - a.borrow() == b.borrow() - } - } - - // ==== Validator Metadata Management Functions ==== - - /// Create a new `UnverifiedValidatorOperationCap`, transfer to the validator, - /// and registers it, thus revoking the previous cap's permission. - public(package) fun new_unverified_validator_operation_cap_and_transfer(self: &mut Validator, ctx: &mut TxContext) { - let address = ctx.sender(); - assert!(address == self.metadata.sui_address, ENewCapNotCreatedByValidatorItself); - let new_id = validator_cap::new_unverified_validator_operation_cap_and_transfer(address, ctx); - self.operation_cap_id = new_id; - } - - /// Update name of the validator. - public(package) fun update_name(self: &mut Validator, name: vector) { - assert!( - name.length() <= MAX_VALIDATOR_METADATA_LENGTH, - EValidatorMetadataExceedingLengthLimit - ); - self.metadata.name = name.to_ascii_string().to_string(); - } - - /// Update description of the validator. - public(package) fun update_description(self: &mut Validator, description: vector) { - assert!( - description.length() <= MAX_VALIDATOR_METADATA_LENGTH, - EValidatorMetadataExceedingLengthLimit - ); - self.metadata.description = description.to_ascii_string().to_string(); - } - - /// Update image url of the validator. - public(package) fun update_image_url(self: &mut Validator, image_url: vector) { - assert!( - image_url.length() <= MAX_VALIDATOR_METADATA_LENGTH, - EValidatorMetadataExceedingLengthLimit - ); - self.metadata.image_url = url::new_unsafe_from_bytes(image_url); - } - - /// Update project url of the validator. - public(package) fun update_project_url(self: &mut Validator, project_url: vector) { - assert!( - project_url.length() <= MAX_VALIDATOR_METADATA_LENGTH, - EValidatorMetadataExceedingLengthLimit - ); - self.metadata.project_url = url::new_unsafe_from_bytes(project_url); - } - - /// Update network address of this validator, taking effects from next epoch - public(package) fun update_next_epoch_network_address(self: &mut Validator, net_address: vector) { - assert!( - net_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, - EValidatorMetadataExceedingLengthLimit - ); - let net_address = net_address.to_ascii_string().to_string(); - self.metadata.next_epoch_net_address = option::some(net_address); - validate_metadata(&self.metadata); - } - - /// Update network address of this candidate validator - public(package) fun update_candidate_network_address(self: &mut Validator, net_address: vector) { - assert!(is_preactive(self), ENotValidatorCandidate); - assert!( - net_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, - EValidatorMetadataExceedingLengthLimit - ); - let net_address = net_address.to_ascii_string().to_string(); - self.metadata.net_address = net_address; - validate_metadata(&self.metadata); - } - - /// Update p2p address of this validator, taking effects from next epoch - public(package) fun update_next_epoch_p2p_address(self: &mut Validator, p2p_address: vector) { - assert!( - p2p_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, - EValidatorMetadataExceedingLengthLimit - ); - let p2p_address = p2p_address.to_ascii_string().to_string(); - self.metadata.next_epoch_p2p_address = option::some(p2p_address); - validate_metadata(&self.metadata); - } - - /// Update p2p address of this candidate validator - public(package) fun update_candidate_p2p_address(self: &mut Validator, p2p_address: vector) { - assert!(is_preactive(self), ENotValidatorCandidate); - assert!( - p2p_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, - EValidatorMetadataExceedingLengthLimit - ); - let p2p_address = p2p_address.to_ascii_string().to_string(); - self.metadata.p2p_address = p2p_address; - validate_metadata(&self.metadata); - } - - /// Update primary address of this validator, taking effects from next epoch - public(package) fun update_next_epoch_primary_address(self: &mut Validator, primary_address: vector) { - assert!( - primary_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, - EValidatorMetadataExceedingLengthLimit - ); - let primary_address = primary_address.to_ascii_string().to_string(); - self.metadata.next_epoch_primary_address = option::some(primary_address); - validate_metadata(&self.metadata); - } - - /// Update primary address of this candidate validator - public(package) fun update_candidate_primary_address(self: &mut Validator, primary_address: vector) { - assert!(is_preactive(self), ENotValidatorCandidate); - assert!( - primary_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, - EValidatorMetadataExceedingLengthLimit - ); - let primary_address = primary_address.to_ascii_string().to_string(); - self.metadata.primary_address = primary_address; - validate_metadata(&self.metadata); - } - - /// Update worker address of this validator, taking effects from next epoch - public(package) fun update_next_epoch_worker_address(self: &mut Validator, worker_address: vector) { - assert!( - worker_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, - EValidatorMetadataExceedingLengthLimit - ); - let worker_address = worker_address.to_ascii_string().to_string(); - self.metadata.next_epoch_worker_address = option::some(worker_address); - validate_metadata(&self.metadata); - } - - /// Update worker address of this candidate validator - public(package) fun update_candidate_worker_address(self: &mut Validator, worker_address: vector) { - assert!(is_preactive(self), ENotValidatorCandidate); - assert!( - worker_address.length() <= MAX_VALIDATOR_METADATA_LENGTH, - EValidatorMetadataExceedingLengthLimit - ); - let worker_address = worker_address.to_ascii_string().to_string(); - self.metadata.worker_address = worker_address; - validate_metadata(&self.metadata); - } - - /// Update protocol public key of this validator, taking effects from next epoch - public(package) fun update_next_epoch_protocol_pubkey(self: &mut Validator, protocol_pubkey: vector, proof_of_possession: vector) { - self.metadata.next_epoch_protocol_pubkey_bytes = option::some(protocol_pubkey); - self.metadata.next_epoch_proof_of_possession = option::some(proof_of_possession); - validate_metadata(&self.metadata); - } - - /// Update protocol public key of this candidate validator - public(package) fun update_candidate_protocol_pubkey(self: &mut Validator, protocol_pubkey: vector, proof_of_possession: vector) { - assert!(is_preactive(self), ENotValidatorCandidate); - self.metadata.protocol_pubkey_bytes = protocol_pubkey; - self.metadata.proof_of_possession = proof_of_possession; - validate_metadata(&self.metadata); - } - - /// Update network public key of this validator, taking effects from next epoch - public(package) fun update_next_epoch_network_pubkey(self: &mut Validator, network_pubkey: vector) { - self.metadata.next_epoch_network_pubkey_bytes = option::some(network_pubkey); - validate_metadata(&self.metadata); - } - - /// Update network public key of this candidate validator - public(package) fun update_candidate_network_pubkey(self: &mut Validator, network_pubkey: vector) { - assert!(is_preactive(self), ENotValidatorCandidate); - self.metadata.network_pubkey_bytes = network_pubkey; - validate_metadata(&self.metadata); - } - - /// Update Narwhal worker public key of this validator, taking effects from next epoch - public(package) fun update_next_epoch_worker_pubkey(self: &mut Validator, worker_pubkey: vector) { - self.metadata.next_epoch_worker_pubkey_bytes = option::some(worker_pubkey); - validate_metadata(&self.metadata); - } - - /// Update Narwhal worker public key of this candidate validator - public(package) fun update_candidate_worker_pubkey(self: &mut Validator, worker_pubkey: vector) { - assert!(is_preactive(self), ENotValidatorCandidate); - self.metadata.worker_pubkey_bytes = worker_pubkey; - validate_metadata(&self.metadata); - } - - /// Effectutate all staged next epoch metadata for this validator. - /// NOTE: this function SHOULD ONLY be called by validator_set when - /// advancing an epoch. - public(package) fun effectuate_staged_metadata(self: &mut Validator) { - if (next_epoch_network_address(self).is_some()) { - self.metadata.net_address = self.metadata.next_epoch_net_address.extract(); - self.metadata.next_epoch_net_address = option::none(); - }; - - if (next_epoch_p2p_address(self).is_some()) { - self.metadata.p2p_address = self.metadata.next_epoch_p2p_address.extract(); - self.metadata.next_epoch_p2p_address = option::none(); - }; - - if (next_epoch_primary_address(self).is_some()) { - self.metadata.primary_address = self.metadata.next_epoch_primary_address.extract(); - self.metadata.next_epoch_primary_address = option::none(); - }; - - if (next_epoch_worker_address(self).is_some()) { - self.metadata.worker_address = self.metadata.next_epoch_worker_address.extract(); - self.metadata.next_epoch_worker_address = option::none(); - }; - - if (next_epoch_protocol_pubkey_bytes(self).is_some()) { - self.metadata.protocol_pubkey_bytes = self.metadata.next_epoch_protocol_pubkey_bytes.extract(); - self.metadata.next_epoch_protocol_pubkey_bytes = option::none(); - self.metadata.proof_of_possession = self.metadata.next_epoch_proof_of_possession.extract(); - self.metadata.next_epoch_proof_of_possession = option::none(); - }; - - if (next_epoch_network_pubkey_bytes(self).is_some()) { - self.metadata.network_pubkey_bytes = self.metadata.next_epoch_network_pubkey_bytes.extract(); - self.metadata.next_epoch_network_pubkey_bytes = option::none(); - }; - - if (next_epoch_worker_pubkey_bytes(self).is_some()) { - self.metadata.worker_pubkey_bytes = self.metadata.next_epoch_worker_pubkey_bytes.extract(); - self.metadata.next_epoch_worker_pubkey_bytes = option::none(); - }; - } - - /// Aborts if validator metadata is valid - public fun validate_metadata(metadata: &ValidatorMetadata) { - validate_metadata_bcs(bcs::to_bytes(metadata)); - } - - public native fun validate_metadata_bcs(metadata: vector); - - public(package) fun get_staking_pool_ref(self: &Validator) : &StakingPool { - &self.staking_pool - } - - - /// Create a new validator from the given `ValidatorMetadata`, called by both `new` and `new_for_testing`. - fun new_from_metadata( - metadata: ValidatorMetadata, - gas_price: u64, - commission_rate: u64, - ctx: &mut TxContext - ): Validator { - let sui_address = metadata.sui_address; - - let staking_pool = staking_pool::new(ctx); - - let operation_cap_id = validator_cap::new_unverified_validator_operation_cap_and_transfer(sui_address, ctx); - Validator { - metadata, - // Initialize the voting power to be 0. - // At the epoch change where this validator is actually added to the - // active validator set, the voting power will be updated accordingly. - voting_power: 0, - operation_cap_id, - gas_price, - staking_pool, - commission_rate, - next_epoch_stake: 0, - next_epoch_gas_price: gas_price, - next_epoch_commission_rate: commission_rate, - extra_fields: bag::new(ctx), - } - } - - // CAUTION: THIS CODE IS ONLY FOR TESTING AND THIS MACRO MUST NEVER EVER BE REMOVED. - // Creates a validator - bypassing the proof of possession check and other metadata - // validation in the process. - // Note: `proof_of_possession` MUST be a valid signature using sui_address and - // protocol_pubkey_bytes. To produce a valid PoP, run [fn test_proof_of_possession]. - #[test_only] - public(package) fun new_for_testing( - sui_address: address, - protocol_pubkey_bytes: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - proof_of_possession: vector, - name: vector, - description: vector, - image_url: vector, - project_url: vector, - net_address: vector, - p2p_address: vector, - primary_address: vector, - worker_address: vector, - mut initial_stake_option: Option>, - gas_price: u64, - commission_rate: u64, - is_active_at_genesis: bool, - ctx: &mut TxContext - ): Validator { - let mut validator = new_from_metadata( - new_metadata( - sui_address, - protocol_pubkey_bytes, - network_pubkey_bytes, - worker_pubkey_bytes, - proof_of_possession, - name.to_ascii_string().to_string(), - description.to_ascii_string().to_string(), - url::new_unsafe_from_bytes(image_url), - url::new_unsafe_from_bytes(project_url), - net_address.to_ascii_string().to_string(), - p2p_address.to_ascii_string().to_string(), - primary_address.to_ascii_string().to_string(), - worker_address.to_ascii_string().to_string(), - bag::new(ctx), - ), - gas_price, - commission_rate, - ctx - ); - - // Add the validator's starting stake to the staking pool if there exists one. - if (initial_stake_option.is_some()) { - request_add_stake_at_genesis( - &mut validator, - initial_stake_option.extract(), - sui_address, // give the stake to the validator - ctx - ); - }; - initial_stake_option.destroy_none(); - - if (is_active_at_genesis) { - activate(&mut validator, 0); - }; - - validator - } -} diff --git a/crates/sui-framework/packages/sui-system/sources/validator_wrapper.move b/crates/sui-framework/packages/sui-system/sources/validator_wrapper.move deleted file mode 100644 index 14eaecc05d6..00000000000 --- a/crates/sui-framework/packages/sui-system/sources/validator_wrapper.move +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui_system::validator_wrapper { - use sui::versioned::Versioned; - use sui_system::validator::Validator; - use sui::versioned; - - /* friend sui_system::validator_set; */ - - const EInvalidVersion: u64 = 0; - - public struct ValidatorWrapper has store { - inner: Versioned - } - - // Validator corresponds to version 1. - public(package) fun create_v1(validator: Validator, ctx: &mut TxContext): ValidatorWrapper { - ValidatorWrapper { - inner: versioned::create(1, validator, ctx) - } - } - - /// This function should always return the latest supported version. - /// If the inner version is old, we upgrade it lazily in-place. - public(package) fun load_validator_maybe_upgrade(self: &mut ValidatorWrapper): &mut Validator { - upgrade_to_latest(self); - versioned::load_value_mut(&mut self.inner) - } - - /// Destroy the wrapper and retrieve the inner validator object. - public(package) fun destroy(self: ValidatorWrapper): Validator { - upgrade_to_latest(&self); - let ValidatorWrapper { inner } = self; - versioned::destroy(inner) - } - - #[test_only] - /// Load the inner validator with assumed type. This should be used for testing only. - public(package) fun get_inner_validator_ref(self: &ValidatorWrapper): &Validator { - versioned::load_value(&self.inner) - } - - fun upgrade_to_latest(self: &ValidatorWrapper) { - let version = version(self); - // TODO: When new versions are added, we need to explicitly upgrade here. - assert!(version == 1, EInvalidVersion); - } - - fun version(self: &ValidatorWrapper): u64 { - versioned::version(&self.inner) - } -} diff --git a/crates/sui-framework/packages/sui-system/tests/delegation_tests.move b/crates/sui-framework/packages/sui-system/tests/delegation_tests.move deleted file mode 100644 index c12ca1624fd..00000000000 --- a/crates/sui-framework/packages/sui-system/tests/delegation_tests.move +++ /dev/null @@ -1,563 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[test_only] -module sui_system::stake_tests { - use sui::coin; - use sui::test_scenario; - use sui_system::sui_system::SuiSystemState; - use sui_system::staking_pool::{Self, StakedSui, PoolTokenExchangeRate}; - use sui::test_utils::assert_eq; - use sui_system::validator_set; - use sui::test_utils; - use sui::table::Table; - - use sui_system::governance_test_utils::{ - add_validator, - add_validator_candidate, - advance_epoch, - advance_epoch_with_reward_amounts, - assert_validator_total_stake_amounts, - create_validator_for_testing, - create_sui_system_state_for_testing, - stake_with, - remove_validator, - remove_validator_candidate, - total_sui_balance, - unstake, - }; - - const VALIDATOR_ADDR_1: address = @0x1; - const VALIDATOR_ADDR_2: address = @0x2; - - const STAKER_ADDR_1: address = @0x42; - const STAKER_ADDR_2: address = @0x43; - const STAKER_ADDR_3: address = @0x44; - - const NEW_VALIDATOR_ADDR: address = @0x1a4623343cd42be47d67314fce0ad042f3c82685544bc91d8c11d24e74ba7357; - // Generated with seed [0;32] - const NEW_VALIDATOR_PUBKEY: vector = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; - // Generated using [fn test_proof_of_possession] - const NEW_VALIDATOR_POP: vector = x"8b93fc1b33379e2796d361c4056f0f04ad5aea7f4a8c02eaac57340ff09b6dc158eb1945eece103319167f420daf0cb3"; - - const MIST_PER_SUI: u64 = 1_000_000_000; - - #[test] - fun test_split_join_staked_sui() { - // All this is just to generate a dummy StakedSui object to split and join later - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); - let scenario = &mut scenario_val; - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, scenario); - - scenario.next_tx(STAKER_ADDR_1); - { - let mut staked_sui = scenario.take_from_sender(); - let ctx = scenario.ctx(); - staked_sui.split_to_sender(20 * MIST_PER_SUI, ctx); - scenario.return_to_sender(staked_sui); - }; - - // Verify the correctness of the split and send the join txn - scenario.next_tx(STAKER_ADDR_1); - { - let staked_sui_ids = scenario.ids_for_sender(); - assert!(staked_sui_ids.length() == 2, 101); // staked sui split to 2 coins - - let mut part1 = scenario.take_from_sender_by_id(staked_sui_ids[0]); - let part2 = scenario.take_from_sender_by_id(staked_sui_ids[1]); - - let amount1 = part1.amount(); - let amount2 = part2.amount(); - assert!(amount1 == 20 * MIST_PER_SUI || amount1 == 40 * MIST_PER_SUI, 102); - assert!(amount2 == 20 * MIST_PER_SUI || amount2 == 40 * MIST_PER_SUI, 103); - assert!(amount1 + amount2 == 60 * MIST_PER_SUI, 104); - - part1.join(part2); - assert!(part1.amount() == 60 * MIST_PER_SUI, 105); - scenario.return_to_sender(part1); - }; - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = staking_pool::EIncompatibleStakedSui)] - fun test_join_different_epochs() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); - let scenario = &mut scenario_val; - // Create two instances of staked sui w/ different epoch activations - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, scenario); - advance_epoch(scenario); - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, scenario); - - // Verify that these cannot be merged - scenario.next_tx(STAKER_ADDR_1); - { - let staked_sui_ids = scenario.ids_for_sender(); - let mut part1 = scenario.take_from_sender_by_id(staked_sui_ids[0]); - let part2 = scenario.take_from_sender_by_id(staked_sui_ids[1]); - - part1.join(part2); - - scenario.return_to_sender(part1); - }; - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = staking_pool::EStakedSuiBelowThreshold)] - fun test_split_below_threshold() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); - let scenario = &mut scenario_val; - // Stake 2 SUI - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 2, scenario); - - scenario.next_tx(STAKER_ADDR_1); - { - let mut staked_sui = scenario.take_from_sender(); - let ctx = scenario.ctx(); - // The remaining amount after splitting is below the threshold so this should fail. - staked_sui.split_to_sender(1 * MIST_PER_SUI + 1, ctx); - scenario.return_to_sender(staked_sui); - }; - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = staking_pool::EStakedSuiBelowThreshold)] - fun test_split_nonentry_below_threshold() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); - let scenario = &mut scenario_val; - // Stake 2 SUI - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 2, scenario); - - scenario.next_tx(STAKER_ADDR_1); - { - let mut staked_sui = scenario.take_from_sender(); - let ctx = scenario.ctx(); - // The remaining amount after splitting is below the threshold so this should fail. - let stake = staked_sui.split(1 * MIST_PER_SUI + 1, ctx); - test_utils::destroy(stake); - scenario.return_to_sender(staked_sui); - }; - scenario_val.end(); - } - - #[test] - fun test_add_remove_stake_flow() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - scenario.next_tx(STAKER_ADDR_1); - { - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - let ctx = scenario.ctx(); - - // Create a stake to VALIDATOR_ADDR_1. - system_state_mut_ref.request_add_stake( - coin::mint_for_testing(60 * MIST_PER_SUI, ctx), VALIDATOR_ADDR_1, ctx - ); - - assert!(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1) == 100 * MIST_PER_SUI, 101); - assert!(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2) == 100 * MIST_PER_SUI, 102); - - test_scenario::return_shared(system_state); - }; - - advance_epoch(scenario); - - scenario.next_tx(STAKER_ADDR_1); - { - - let staked_sui = scenario.take_from_sender(); - assert!(staked_sui.amount() == 60 * MIST_PER_SUI, 105); - - - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - assert!(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1) == 160 * MIST_PER_SUI, 103); - assert!(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2) == 100 * MIST_PER_SUI, 104); - - let ctx = scenario.ctx(); - - // Unstake from VALIDATOR_ADDR_1 - system_state_mut_ref.request_withdraw_stake(staked_sui, ctx); - - assert!(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1) == 160 * MIST_PER_SUI, 107); - test_scenario::return_shared(system_state); - }; - - advance_epoch(scenario); - - scenario.next_tx(STAKER_ADDR_1); - { - let mut system_state = scenario.take_shared(); - assert!(system_state.validator_stake_amount(VALIDATOR_ADDR_1) == 100 * MIST_PER_SUI, 107); - test_scenario::return_shared(system_state); - }; - scenario_val.end(); - } - - #[test] - fun test_remove_stake_post_active_flow_no_rewards() { - test_remove_stake_post_active_flow(false) - } - - #[test] - fun test_remove_stake_post_active_flow_with_rewards() { - test_remove_stake_post_active_flow(true) - } - - fun test_remove_stake_post_active_flow(should_distribute_rewards: bool) { - set_up_sui_system_state_with_storage_fund(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, scenario); - - advance_epoch(scenario); - - assert_validator_total_stake_amounts( - vector[VALIDATOR_ADDR_1, VALIDATOR_ADDR_2], - vector[200 * MIST_PER_SUI, 100 * MIST_PER_SUI], - scenario - ); - - if (should_distribute_rewards) { - // Each validator pool gets 30 MIST and each validator gets an additional 10 MIST. - advance_epoch_with_reward_amounts(0, 80, scenario); - } else { - advance_epoch(scenario); - }; - - remove_validator(VALIDATOR_ADDR_1, scenario); - - advance_epoch(scenario); - - let reward_amt = if (should_distribute_rewards) 15 * MIST_PER_SUI else 0; - let validator_reward_amt = if (should_distribute_rewards) 10 * MIST_PER_SUI else 0; - - // Make sure stake withdrawal happens - scenario.next_tx(STAKER_ADDR_1); - { - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - assert!(!system_state_mut_ref.validators().is_active_validator_by_sui_address(VALIDATOR_ADDR_1), 0); - - let staked_sui = scenario.take_from_sender(); - assert_eq(staked_sui.amount(), 100 * MIST_PER_SUI); - - // Unstake from VALIDATOR_ADDR_1 - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), 0); - let ctx = scenario.ctx(); - system_state_mut_ref.request_withdraw_stake(staked_sui, ctx); - - // Make sure they have all of their stake. - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), 100 * MIST_PER_SUI + reward_amt); - - test_scenario::return_shared(system_state); - }; - - // Validator unstakes now. - assert_eq(total_sui_balance(VALIDATOR_ADDR_1, scenario), 0); - unstake(VALIDATOR_ADDR_1, 0, scenario); - if (should_distribute_rewards) unstake(VALIDATOR_ADDR_1, 0, scenario); - - // Make sure have all of their stake. NB there is no epoch change. This is immediate. - assert_eq(total_sui_balance(VALIDATOR_ADDR_1, scenario), 100 * MIST_PER_SUI + reward_amt + validator_reward_amt); - - scenario_val.end(); - } - - #[test] - fun test_earns_rewards_at_last_epoch() { - set_up_sui_system_state_with_storage_fund(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, scenario); - - advance_epoch(scenario); - - remove_validator(VALIDATOR_ADDR_1, scenario); - - // Add some rewards after the validator requests to leave. Since the validator is still active - // this epoch, they should get the rewards from this epoch. - advance_epoch_with_reward_amounts(0, 80, scenario); - - // Each validator pool gets 30 MIST and validators shares the 20 MIST from the storage fund - // so validator gets another 10 MIST. - let reward_amt = 15 * MIST_PER_SUI; - let validator_reward_amt = 10 * MIST_PER_SUI; - - // Make sure stake withdrawal happens - scenario.next_tx(STAKER_ADDR_1); - { - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - let staked_sui = scenario.take_from_sender(); - assert_eq(staked_sui.amount(), 100 * MIST_PER_SUI); - - // Unstake from VALIDATOR_ADDR_1 - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), 0); - let ctx = scenario.ctx(); - system_state_mut_ref.request_withdraw_stake(staked_sui, ctx); - - // Make sure they have all of their stake. - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), 100 * MIST_PER_SUI + reward_amt); - - test_scenario::return_shared(system_state); - }; - - // Validator unstakes now. - assert_eq(total_sui_balance(VALIDATOR_ADDR_1, scenario), 0); - unstake(VALIDATOR_ADDR_1, 0, scenario); - unstake(VALIDATOR_ADDR_1, 0, scenario); - - // Make sure have all of their stake. NB there is no epoch change. This is immediate. - assert_eq(total_sui_balance(VALIDATOR_ADDR_1, scenario), 100 * MIST_PER_SUI + reward_amt + validator_reward_amt); - - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = validator_set::ENotAValidator)] - fun test_add_stake_post_active_flow() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, scenario); - - advance_epoch(scenario); - - remove_validator(VALIDATOR_ADDR_1, scenario); - - advance_epoch(scenario); - - // Make sure the validator is no longer active. - scenario.next_tx(STAKER_ADDR_1); - { - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - assert!(!system_state_mut_ref.validators().is_active_validator_by_sui_address(VALIDATOR_ADDR_1), 0); - - test_scenario::return_shared(system_state); - }; - - // Now try and stake to the old validator/staking pool. This should fail! - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, scenario); - - scenario_val.end(); - } - - #[test] - fun test_add_preactive_remove_preactive() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - add_validator_candidate(NEW_VALIDATOR_ADDR, b"name5", b"/ip4/127.0.0.1/udp/85", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); - - // Delegate 100 MIST to the preactive validator - stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); - - // Advance epoch twice with some rewards - advance_epoch_with_reward_amounts(0, 400, scenario); - advance_epoch_with_reward_amounts(0, 900, scenario); - - // Unstake from the preactive validator. There should be no rewards earned. - unstake(STAKER_ADDR_1, 0, scenario); - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), 100 * MIST_PER_SUI); - - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = validator_set::ENotAValidator)] - fun test_add_preactive_remove_pending_failure() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - add_validator_candidate(NEW_VALIDATOR_ADDR, b"name4", b"/ip4/127.0.0.1/udp/84", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); - - add_validator(NEW_VALIDATOR_ADDR, scenario); - - // Delegate 100 SUI to the pending validator. This should fail because pending active validators don't accept - // new stakes or withdraws. - stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); - - scenario_val.end(); - } - - #[test] - fun test_add_preactive_remove_active() { - set_up_sui_system_state_with_storage_fund(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - add_validator_candidate(NEW_VALIDATOR_ADDR, b"name3", b"/ip4/127.0.0.1/udp/83", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); - - // Delegate 100 SUI to the preactive validator - stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); - advance_epoch_with_reward_amounts(0, 300, scenario); - // At this point we got the following distribution of stake: - // V1: 250, V2: 250, storage fund: 100 - - stake_with(STAKER_ADDR_2, NEW_VALIDATOR_ADDR, 50, scenario); - stake_with(STAKER_ADDR_3, NEW_VALIDATOR_ADDR, 100, scenario); - - // Now the preactive becomes active - add_validator(NEW_VALIDATOR_ADDR, scenario); - advance_epoch(scenario); - - // At this point we got the following distribution of stake: - // V1: 250, V2: 250, V3: 250, storage fund: 100 - - advance_epoch_with_reward_amounts(0, 85, scenario); - - // staker 1 and 3 unstake from the validator and earns about 2/5 * (85 - 10) * 1/3 = 10 SUI each. - // Although they stake in different epochs, they earn the same rewards as long as they unstake - // in the same epoch because the validator was preactive when they staked. - // So they will both get slightly more than 110 SUI in total balance. - unstake(STAKER_ADDR_1, 0, scenario); - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), 110002000000); - unstake(STAKER_ADDR_3, 0, scenario); - assert_eq(total_sui_balance(STAKER_ADDR_3, scenario), 110002000000); - - advance_epoch_with_reward_amounts(0, 85, scenario); - unstake(STAKER_ADDR_2, 0, scenario); - // staker 2 earns about 5 SUI from the previous epoch and 24-ish from this one - // so in total she has about 50 + 5 + 24 = 79 SUI. - assert_eq(total_sui_balance(STAKER_ADDR_2, scenario), 78862939078); - - scenario_val.end(); - } - - #[test] - fun test_add_preactive_remove_post_active() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - add_validator_candidate(NEW_VALIDATOR_ADDR, b"name1", b"/ip4/127.0.0.1/udp/81", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); - - // Delegate 100 SUI to the preactive validator - stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); - - // Now the preactive becomes active - add_validator(NEW_VALIDATOR_ADDR, scenario); - advance_epoch(scenario); - - // staker 1 earns a bit greater than 30 SUI here. A bit greater because the new validator's voting power - // is slightly greater than 1/3 of the total voting power. - advance_epoch_with_reward_amounts(0, 90, scenario); - - // And now the validator leaves the validator set. - remove_validator(NEW_VALIDATOR_ADDR, scenario); - - advance_epoch(scenario); - - unstake(STAKER_ADDR_1, 0, scenario); - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), 130006000000); - - scenario_val.end(); - } - - #[test] - fun test_add_preactive_candidate_drop_out() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - add_validator_candidate(NEW_VALIDATOR_ADDR, b"name2", b"/ip4/127.0.0.1/udp/82", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); - - // Delegate 100 MIST to the preactive validator - stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); - - // Advance epoch and give out some rewards. The candidate should get nothing, of course. - advance_epoch_with_reward_amounts(0, 800, scenario); - - // Now the candidate leaves. - remove_validator_candidate(NEW_VALIDATOR_ADDR, scenario); - - // Advance epoch a few times. - advance_epoch(scenario); - advance_epoch(scenario); - advance_epoch(scenario); - - // Unstake now and the staker should get no rewards. - unstake(STAKER_ADDR_1, 0, scenario); - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), 100 * MIST_PER_SUI); - - scenario_val.end(); - } - - #[test] - fun test_staking_pool_exchange_rate_getter() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - stake_with(@0x42, @0x2, 100, scenario); // stakes 100 SUI with 0x2 - scenario.next_tx(@0x42); - let staked_sui = scenario.take_from_address(@0x42); - let pool_id = staked_sui.pool_id(); - test_scenario::return_to_address(@0x42, staked_sui); - advance_epoch(scenario); // advances epoch to effectuate the stake - // Each staking pool gets 10 SUI of rewards. - advance_epoch_with_reward_amounts(0, 20, scenario); - let mut system_state = scenario.take_shared(); - let rates = system_state.pool_exchange_rates(&pool_id); - assert_eq(rates.length(), 3); - assert_exchange_rate_eq(rates, 0, 0, 0); // no tokens at epoch 0 - assert_exchange_rate_eq(rates, 1, 200, 200); // 200 SUI of self + delegate stake at epoch 1 - assert_exchange_rate_eq(rates, 2, 210, 200); // 10 SUI of rewards at epoch 2 - test_scenario::return_shared(system_state); - scenario_val.end(); - } - - fun assert_exchange_rate_eq( - rates: &Table, epoch: u64, sui_amount: u64, pool_token_amount: u64 - ) { - let rate = &rates[epoch]; - assert_eq(rate.sui_amount(), sui_amount * MIST_PER_SUI); - assert_eq(rate.pool_token_amount(), pool_token_amount * MIST_PER_SUI); - } - - fun set_up_sui_system_state() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - let ctx = scenario.ctx(); - - let validators = vector[ - create_validator_for_testing(VALIDATOR_ADDR_1, 100, ctx), - create_validator_for_testing(VALIDATOR_ADDR_2, 100, ctx) - ]; - create_sui_system_state_for_testing(validators, 0, 0, ctx); - scenario_val.end(); - } - - fun set_up_sui_system_state_with_storage_fund() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - let ctx = scenario.ctx(); - - let validators = vector[ - create_validator_for_testing(VALIDATOR_ADDR_1, 100, ctx), - create_validator_for_testing(VALIDATOR_ADDR_2, 100, ctx) - ]; - create_sui_system_state_for_testing(validators, 300, 100, ctx); - scenario_val.end(); - } -} diff --git a/crates/sui-framework/packages/sui-system/tests/governance_test_utils.move b/crates/sui-framework/packages/sui-system/tests/governance_test_utils.move deleted file mode 100644 index 895bde41f77..00000000000 --- a/crates/sui-framework/packages/sui-system/tests/governance_test_utils.move +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[test_only] -module sui_system::governance_test_utils { - use sui::address; - use sui::balance; - use sui::sui::SUI; - use sui::coin::{Self, Coin}; - use sui_system::staking_pool::{StakedSui, StakingPool}; - use sui::test_utils::assert_eq; - use sui_system::validator::{Self, Validator}; - use sui_system::sui_system::{Self, SuiSystemState}; - use sui_system::sui_system_state_inner; - use sui_system::stake_subsidy; - use sui::test_scenario::{Self, Scenario}; - use sui::test_utils; - use sui::balance::Balance; - - const MIST_PER_SUI: u64 = 1_000_000_000; - - public fun create_validator_for_testing( - addr: address, init_stake_amount_in_sui: u64, ctx: &mut TxContext - ): Validator { - let validator = validator::new_for_testing( - addr, - x"AA", - x"BB", - x"CC", - x"DD", - b"ValidatorName", - b"description", - b"image_url", - b"project_url", - b"/ip4/127.0.0.1/tcp/80", - b"/ip4/127.0.0.1/udp/80", - b"/ip4/127.0.0.1/udp/80", - b"/ip4/127.0.0.1/udp/80", - option::some(balance::create_for_testing(init_stake_amount_in_sui * MIST_PER_SUI)), - 1, - 0, - true, - ctx - ); - validator - } - - /// Create a validator set with the given stake amounts - public fun create_validators_with_stakes(stakes: vector, ctx: &mut TxContext): vector { - let mut i = 0; - let mut validators = vector[]; - while (i < stakes.length()) { - let validator = create_validator_for_testing(address::from_u256(i as u256), stakes[i], ctx); - validators.push_back(validator); - i = i + 1 - }; - validators - } - - public fun create_sui_system_state_for_testing( - validators: vector, sui_supply_amount: u64, storage_fund_amount: u64, ctx: &mut TxContext - ) { - let system_parameters = sui_system_state_inner::create_system_parameters( - 42, // epoch_duration_ms, doesn't matter what number we put here - 0, // stake_subsidy_start_epoch - - 150, // max_validator_count - 1, // min_validator_joining_stake - 1, // validator_low_stake_threshold - 0, // validator_very_low_stake_threshold - 7, // validator_low_stake_grace_period - ctx, - ); - - let stake_subsidy = stake_subsidy::create( - balance::create_for_testing(sui_supply_amount * MIST_PER_SUI), // sui_supply - 0, // stake subsidy initial distribution amount - 10, // stake_subsidy_period_length - 0, // stake_subsidy_decrease_rate - ctx, - ); - - sui_system::create( - object::new(ctx), // it doesn't matter what ID sui system state has in tests - validators, - balance::create_for_testing(storage_fund_amount * MIST_PER_SUI), // storage_fund - 1, // protocol version - 0, // chain_start_timestamp_ms - system_parameters, - stake_subsidy, - ctx, - ) - } - - public fun set_up_sui_system_state(mut addrs: vector
    ) { - let mut scenario = test_scenario::begin(@0x0); - let ctx = scenario.ctx(); - let mut validators = vector[]; - - while (!addrs.is_empty()) { - validators.push_back( - create_validator_for_testing(addrs.pop_back(), 100, ctx) - ); - }; - - create_sui_system_state_for_testing(validators, 1000, 0, ctx); - scenario.end(); - } - - public fun advance_epoch(scenario: &mut Scenario) { - advance_epoch_with_reward_amounts(0, 0, scenario); - } - - public fun advance_epoch_with_reward_amounts_return_rebate( - storage_charge: u64, computation_charge: u64, stoarge_rebate: u64, non_refundable_storage_rebate: u64, scenario: &mut Scenario, - ): Balance { - scenario.next_tx(@0x0); - let new_epoch = scenario.ctx().epoch() + 1; - let mut system_state = scenario.take_shared(); - - let ctx = scenario.ctx(); - - let storage_rebate = system_state.advance_epoch_for_testing( - new_epoch, 1, storage_charge, computation_charge, stoarge_rebate, non_refundable_storage_rebate, 0, 0, 0, ctx, - ); - test_scenario::return_shared(system_state); - scenario.next_epoch(@0x0); - storage_rebate - } - - public fun advance_epoch_with_reward_amounts( - storage_charge: u64, computation_charge: u64, scenario: &mut Scenario - ) { - let storage_rebate = advance_epoch_with_reward_amounts_return_rebate(storage_charge * MIST_PER_SUI, computation_charge * MIST_PER_SUI, 0, 0, scenario); - test_utils::destroy(storage_rebate) - } - - public fun advance_epoch_with_reward_amounts_and_slashing_rates( - storage_charge: u64, - computation_charge: u64, - reward_slashing_rate: u64, - scenario: &mut Scenario - ) { - scenario.next_tx(@0x0); - let new_epoch = scenario.ctx().epoch() + 1; - let mut system_state = scenario.take_shared(); - - let ctx = scenario.ctx(); - - let storage_rebate = system_state.advance_epoch_for_testing( - new_epoch, 1, storage_charge * MIST_PER_SUI, computation_charge * MIST_PER_SUI, 0, 0, 0, reward_slashing_rate, 0, ctx - ); - test_utils::destroy(storage_rebate); - test_scenario::return_shared(system_state); - scenario.next_epoch(@0x0); - } - - public fun stake_with( - staker: address, validator: address, amount: u64, scenario: &mut Scenario - ) { - scenario.next_tx(staker); - let mut system_state = scenario.take_shared(); - - let ctx = scenario.ctx(); - - system_state.request_add_stake(coin::mint_for_testing(amount * MIST_PER_SUI, ctx), validator, ctx); - test_scenario::return_shared(system_state); - } - - public fun unstake( - staker: address, staked_sui_idx: u64, scenario: &mut Scenario - ) { - scenario.next_tx(staker); - let stake_sui_ids = scenario.ids_for_sender(); - let staked_sui = scenario.take_from_sender_by_id(stake_sui_ids[staked_sui_idx]); - let mut system_state = scenario.take_shared(); - - let ctx = scenario.ctx(); - system_state.request_withdraw_stake(staked_sui, ctx); - test_scenario::return_shared(system_state); - } - - public fun add_validator_full_flow(validator: address, name: vector, net_addr: vector, init_stake_amount: u64, pubkey: vector, pop: vector, scenario: &mut Scenario) { - scenario.next_tx(validator); - let mut system_state = scenario.take_shared(); - let ctx = scenario.ctx(); - - system_state.request_add_validator_candidate( - pubkey, - vector[171, 2, 39, 3, 139, 105, 166, 171, 153, 151, 102, 197, 151, 186, 140, 116, 114, 90, 213, 225, 20, 167, 60, 69, 203, 12, 180, 198, 9, 217, 117, 38], - vector[171, 3, 39, 3, 139, 105, 166, 171, 153, 151, 102, 197, 151, 186, 140, 116, 114, 90, 213, 225, 20, 167, 60, 69, 203, 12, 180, 198, 9, 217, 117, 38], - pop, - name, - b"description", - b"image_url", - b"project_url", - net_addr, - net_addr, - net_addr, - net_addr, - 1, - 0, - ctx - ); - system_state.request_add_stake(coin::mint_for_testing(init_stake_amount * MIST_PER_SUI, ctx), validator, ctx); - system_state.request_add_validator_for_testing(0, ctx); - test_scenario::return_shared(system_state); - } - - public fun add_validator_candidate(validator: address, name: vector, net_addr: vector, pubkey: vector, pop: vector, scenario: &mut Scenario) { - scenario.next_tx(validator); - let mut system_state = scenario.take_shared(); - let ctx = scenario.ctx(); - - system_state.request_add_validator_candidate( - pubkey, - vector[171, 2, 39, 3, 139, 105, 166, 171, 153, 151, 102, 197, 151, 186, 140, 116, 114, 90, 213, 225, 20, 167, 60, 69, 203, 12, 180, 198, 9, 217, 117, 38], - vector[171, 3, 39, 3, 139, 105, 166, 171, 153, 151, 102, 197, 151, 186, 140, 116, 114, 90, 213, 225, 20, 167, 60, 69, 203, 12, 180, 198, 9, 217, 117, 38], - pop, - name, - b"description", - b"image_url", - b"project_url", - net_addr, - net_addr, - net_addr, - net_addr, - 1, - 0, - ctx - ); - test_scenario::return_shared(system_state); - } - - public fun remove_validator_candidate(validator: address, scenario: &mut Scenario) { - scenario.next_tx(validator); - let mut system_state = scenario.take_shared(); - let ctx = scenario.ctx(); - - system_state.request_remove_validator_candidate(ctx); - test_scenario::return_shared(system_state); - } - - public fun add_validator(validator: address, scenario: &mut Scenario) { - scenario.next_tx(validator); - let mut system_state = scenario.take_shared(); - let ctx = scenario.ctx(); - - system_state.request_add_validator_for_testing(0, ctx); - test_scenario::return_shared(system_state); - } - - public fun remove_validator(validator: address, scenario: &mut Scenario) { - scenario.next_tx(validator); - let mut system_state = scenario.take_shared(); - - let ctx = scenario.ctx(); - - system_state.request_remove_validator(ctx); - test_scenario::return_shared(system_state); - } - - public fun assert_validator_self_stake_amounts(validator_addrs: vector
    , stake_amounts: vector, scenario: &mut Scenario) { - let mut i = 0; - while (i < validator_addrs.length()) { - let validator_addr = validator_addrs[i]; - let amount = stake_amounts[i]; - - scenario.next_tx(validator_addr); - let mut system_state = scenario.take_shared(); - let stake_plus_rewards = stake_plus_current_rewards_for_validator(validator_addr, &mut system_state, scenario); - assert_eq(stake_plus_rewards, amount); - test_scenario::return_shared(system_state); - i = i + 1; - }; - } - - public fun assert_validator_total_stake_amounts(validator_addrs: vector
    , stake_amounts: vector, scenario: &mut Scenario) { - let mut i = 0; - while (i < validator_addrs.length()) { - let validator_addr = validator_addrs[i]; - let amount = stake_amounts[i]; - - scenario.next_tx(validator_addr); - let mut system_state = scenario.take_shared(); - let validator_amount = system_state.validator_stake_amount(validator_addr); - assert!(validator_amount == amount, validator_amount); - test_scenario::return_shared(system_state); - i = i + 1; - }; - } - - public fun assert_validator_non_self_stake_amounts(validator_addrs: vector
    , stake_amounts: vector, scenario: &mut Scenario) { - let mut i = 0; - while (i < validator_addrs.length()) { - let validator_addr = validator_addrs[i]; - let amount = stake_amounts[i]; - scenario.next_tx(validator_addr); - let mut system_state = scenario.take_shared(); - let non_self_stake_amount = system_state.validator_stake_amount(validator_addr) - stake_plus_current_rewards_for_validator(validator_addr, &mut system_state, scenario); - assert_eq(non_self_stake_amount, amount); - test_scenario::return_shared(system_state); - i = i + 1; - }; - } - - /// Return the rewards for the validator at `addr` in terms of SUI. - public fun stake_plus_current_rewards_for_validator(addr: address, system_state: &mut SuiSystemState, scenario: &mut Scenario): u64 { - let validator_ref = system_state.validators().get_active_validator_ref(addr); - let amount = stake_plus_current_rewards(addr, validator_ref.get_staking_pool_ref(), scenario); - amount - } - - public fun stake_plus_current_rewards(addr: address, staking_pool: &StakingPool, scenario: &mut Scenario): u64 { - let mut sum = 0; - scenario.next_tx(addr); - let mut stake_ids = scenario.ids_for_sender(); - let current_epoch = scenario.ctx().epoch(); - - while (!stake_ids.is_empty()) { - let staked_sui_id = stake_ids.pop_back(); - let staked_sui = scenario.take_from_sender_by_id(staked_sui_id); - sum = sum + staking_pool.calculate_rewards(&staked_sui, current_epoch); - scenario.return_to_sender(staked_sui); - }; - sum - } - - public fun total_sui_balance(addr: address, scenario: &mut Scenario): u64 { - let mut sum = 0; - scenario.next_tx(addr); - let coin_ids = scenario.ids_for_sender>(); - let mut i = 0; - while (i < coin_ids.length()) { - let coin = scenario.take_from_sender_by_id>(coin_ids[i]); - sum = sum + coin.value(); - scenario.return_to_sender(coin); - i = i + 1; - }; - sum - } -} diff --git a/crates/sui-framework/packages/sui-system/tests/rewards_distribution_tests.move b/crates/sui-framework/packages/sui-system/tests/rewards_distribution_tests.move deleted file mode 100644 index 8d821356e14..00000000000 --- a/crates/sui-framework/packages/sui-system/tests/rewards_distribution_tests.move +++ /dev/null @@ -1,494 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[test_only] -module sui_system::rewards_distribution_tests { - use sui::test_scenario::{Self, Scenario}; - use sui_system::sui_system::SuiSystemState; - use sui_system::validator_cap::UnverifiedValidatorOperationCap; - use sui_system::governance_test_utils::{ - advance_epoch, - advance_epoch_with_reward_amounts, - advance_epoch_with_reward_amounts_and_slashing_rates, - assert_validator_total_stake_amounts, - assert_validator_non_self_stake_amounts, - assert_validator_self_stake_amounts, - create_validator_for_testing, - create_sui_system_state_for_testing, - stake_with, - total_sui_balance, unstake - }; - use sui::test_utils::assert_eq; - use sui::address; - - const VALIDATOR_ADDR_1: address = @0x1; - const VALIDATOR_ADDR_2: address = @0x2; - const VALIDATOR_ADDR_3: address = @0x3; - const VALIDATOR_ADDR_4: address = @0x4; - - const STAKER_ADDR_1: address = @0x42; - const STAKER_ADDR_2: address = @0x43; - const STAKER_ADDR_3: address = @0x44; - const STAKER_ADDR_4: address = @0x45; - - const MIST_PER_SUI: u64 = 1_000_000_000; - - #[test] - fun test_validator_rewards() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - // need to advance epoch so validator's staking starts counting - advance_epoch(scenario); - - advance_epoch_with_reward_amounts(0, 100, scenario); - assert_validator_total_stake_amounts( - validator_addrs(), - vector[125 * MIST_PER_SUI, 225 * MIST_PER_SUI, 325 * MIST_PER_SUI, 425 * MIST_PER_SUI], - scenario - ); - - stake_with(VALIDATOR_ADDR_2, VALIDATOR_ADDR_2, 720, scenario); - - advance_epoch(scenario); - advance_epoch_with_reward_amounts(0, 100, scenario); - // Even though validator 2 has a lot more stake now, it should not get more rewards because - // the voting power is capped at 10%. - assert_validator_total_stake_amounts( - validator_addrs(), - vector[150 * MIST_PER_SUI, 970 * MIST_PER_SUI, 350 * MIST_PER_SUI, 450 * MIST_PER_SUI], - scenario - ); - scenario_val.end(); - } - - #[test] - fun test_stake_subsidy() { - set_up_sui_system_state_with_big_amounts(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - // need to advance epoch so validator's staking starts counting - advance_epoch(scenario); - - advance_epoch_with_reward_amounts(0, 100, scenario); - assert_validator_total_stake_amounts(validator_addrs(), vector[100_000_025 * MIST_PER_SUI, 200_000_025 * MIST_PER_SUI, 300_000_025 * MIST_PER_SUI, 400_000_025 * MIST_PER_SUI], scenario); - scenario_val.end(); - } - - #[test] - fun test_stake_rewards() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 200, scenario); - stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_2, 100, scenario); - advance_epoch(scenario); - - assert_validator_total_stake_amounts(validator_addrs(), vector[300 * MIST_PER_SUI, 300 * MIST_PER_SUI, 300 * MIST_PER_SUI, 400 * MIST_PER_SUI], scenario); - assert_validator_self_stake_amounts(validator_addrs(), vector[100 * MIST_PER_SUI, 200 * MIST_PER_SUI, 300 * MIST_PER_SUI, 400 * MIST_PER_SUI], scenario); - - // Each pool gets 30 SUI. - advance_epoch_with_reward_amounts(0, 120, scenario); - assert_validator_self_stake_amounts(validator_addrs(), vector[110 * MIST_PER_SUI, 220 * MIST_PER_SUI, 330 * MIST_PER_SUI, 430 * MIST_PER_SUI], scenario); - unstake(STAKER_ADDR_1, 0, scenario); - stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_1, 600, scenario); - // Each pool gets 30 SUI. - advance_epoch_with_reward_amounts(0, 120, scenario); - // staker 1 receives only 20 SUI of rewards, not 40 since we are using pre-epoch exchange rate. - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), 220 * MIST_PER_SUI); - assert_validator_self_stake_amounts(validator_addrs(), vector[140 * MIST_PER_SUI, 240 * MIST_PER_SUI, 360 * MIST_PER_SUI, 460 * MIST_PER_SUI], scenario); - unstake(STAKER_ADDR_2, 0, scenario); - assert_eq(total_sui_balance(STAKER_ADDR_2, scenario), 120 * MIST_PER_SUI); // 20 SUI of rewards received - - advance_epoch_with_reward_amounts(0, 40, scenario); - - unstake(STAKER_ADDR_2, 0, scenario); // unstake 600 principal SUI - // additional 600 SUI of principal and 46 SUI of rewards withdrawn to Coin - // For this stake, the staking exchange rate is 100 : 140 and the unstaking - // exchange rate is 528 : 750 -ish so the total sui withdraw will be: - // (600 * 100 / 140) * 750 / 528 = ~608. Together with the 120 SUI we already have, - // that would be about 728 SUI. - // TODO: Come up with better numbers and clean it up! - assert_eq(total_sui_balance(STAKER_ADDR_2, scenario), 728108108107); - scenario_val.end(); - } - - #[test] - fun test_stake_tiny_rewards() { - set_up_sui_system_state_with_big_amounts(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - // stake a large amount - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 200000000, scenario); - - advance_epoch(scenario); - - advance_epoch_with_reward_amounts(0, 150000, scenario); - - // stake a small amount - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 10, scenario); - advance_epoch_with_reward_amounts(0, 130, scenario); - - // unstake the stakes - unstake(STAKER_ADDR_1, 1, scenario); - - // and advance epoch should succeed - advance_epoch_with_reward_amounts(0, 150, scenario); - scenario_val.end(); - } - - #[test] - fun test_validator_commission() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, scenario); - stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_2, 100, scenario); - advance_epoch(scenario); - // V1: 200, V2: 300, V3: 300, V4: 400 - - set_commission_rate_and_advance_epoch(VALIDATOR_ADDR_2, 2000, scenario); // 50% commission - advance_epoch_with_reward_amounts(0, 120, scenario); - // V1: 230, V2: 330, V3: 330, V4: 430 - // 2 SUI, or 20 % of staker_2's rewards, goes to validator_2 - assert_validator_non_self_stake_amounts(validator_addrs(), vector[115 * MIST_PER_SUI, 108 * MIST_PER_SUI, 0, 0], scenario); - assert_validator_self_stake_amounts(validator_addrs(), vector[115 * MIST_PER_SUI, 222 * MIST_PER_SUI, 330 * MIST_PER_SUI, 430 * MIST_PER_SUI], scenario); - - set_commission_rate_and_advance_epoch(VALIDATOR_ADDR_1, 1000, scenario); // 10% commission - - advance_epoch_with_reward_amounts(0, 240, scenario); - assert_validator_total_stake_amounts(validator_addrs(), vector[290 * MIST_PER_SUI, 390 * MIST_PER_SUI, 390 * MIST_PER_SUI, 490 * MIST_PER_SUI], scenario); - - // Staker 1 rewards in the recent distribution is 0.9 x 30 = 27 SUI - // Validator 1 rewards in the recent distribution is 60 - 27 = 33 SUI - - // Staker 2 amounts for 0.8 * 60 * (108 / 330) + 108 = 123.709 SUI - // Validator 2 amounts for 390 - 123.709 = 266.291 SUI - assert_validator_non_self_stake_amounts(validator_addrs(), vector[142 * MIST_PER_SUI, 123709090909, 0, 0], scenario); - assert_validator_self_stake_amounts(validator_addrs(), vector[148 * MIST_PER_SUI, 266290909091, 390 * MIST_PER_SUI, 490 * MIST_PER_SUI], scenario); - - scenario_val.end(); - } - - #[test] - fun test_rewards_slashing() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - advance_epoch(scenario); - - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, scenario); - stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_2, 100, scenario); - - advance_epoch(scenario); - - // validator_2 is reported by 3 other validators, so 75% of total stake. - report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_2, scenario); - report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_2, scenario); - report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_2, scenario); - - // validator_1 is reported by only 1 other validator, which is 25% of total stake. - report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_1, scenario); - - // 3600 SUI of total rewards, 50% threshold and 10% reward slashing. - // So validator_2 is the only one whose rewards should get slashed. - advance_epoch_with_reward_amounts_and_slashing_rates( - 0, 3600, 1000, scenario - ); - - // Without reward slashing, the validator's stakes should be [100+450, 200+600, 300+900, 400+900] - // after the last epoch advancement. - // Since 60 SUI, or 10% of validator_2's rewards (600) are slashed, she only has 800 - 60 = 740 now. - // There are in total 90 SUI of rewards slashed (60 from the validator, and 30 from her staker) - // so the unslashed validators each get their share of additional rewards, which is 30. - assert_validator_self_stake_amounts(validator_addrs(), vector[565 * MIST_PER_SUI, 740 * MIST_PER_SUI, 1230 * MIST_PER_SUI, 1330 * MIST_PER_SUI], scenario); - - // Unstake so we can check the stake rewards as well. - unstake(STAKER_ADDR_1, 0, scenario); - unstake(STAKER_ADDR_2, 0, scenario); - - // Same analysis as above. Delegator 1 has 3 additional SUI, and 10% of staker 2's rewards are slashed. - assert!(total_sui_balance(STAKER_ADDR_1, scenario) == 565 * MIST_PER_SUI, 0); - assert!(total_sui_balance(STAKER_ADDR_2, scenario) == 370 * MIST_PER_SUI, 0); - scenario_val.end(); - } - - #[test] - fun test_entire_rewards_slashing() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - advance_epoch(scenario); - - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, scenario); - stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_2, 100, scenario); - - advance_epoch(scenario); - - // validator_2 is reported by 3 other validators, so 75% of total stake. - report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_2, scenario); - report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_2, scenario); - report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_2, scenario); - - - // 3600 SUI of total rewards, 100% reward slashing. - // So validator_2 is the only one whose rewards should get slashed. - advance_epoch_with_reward_amounts_and_slashing_rates( - 0, 3600, 10_000, scenario - ); - - // Without reward slashing, the validator's stakes should be [100+450, 200+600, 300+900, 400+900] - // after the last epoch advancement. - // The entire rewards of validator 2's staking pool are slashed, which is 900 SUI. - // so the unslashed validators each get their share of additional rewards, which is 300. - assert_validator_self_stake_amounts(validator_addrs(), vector[(550 + 150) * MIST_PER_SUI, 200 * MIST_PER_SUI, (1200 + 300) * MIST_PER_SUI, (1300 + 300) * MIST_PER_SUI], scenario); - - // Unstake so we can check the stake rewards as well. - unstake(STAKER_ADDR_1, 0, scenario); - unstake(STAKER_ADDR_2, 0, scenario); - - // Same analysis as above. Staker 1 has 150 additional SUI, and since all of staker 2's rewards are slashed she only gets back her principal. - assert!(total_sui_balance(STAKER_ADDR_1, scenario) == (550 + 150) * MIST_PER_SUI, 0); - assert!(total_sui_balance(STAKER_ADDR_2, scenario) == 100 * MIST_PER_SUI, 0); - scenario_val.end(); - } - - #[test] - fun test_rewards_slashing_with_storage_fund() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - // Put 300 SUI into the storage fund. - advance_epoch_with_reward_amounts(300, 0, scenario); - - // Add a few stakes. - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_3, 100, scenario); - stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_4, 100, scenario); - advance_epoch(scenario); - - // validator_4 is reported by 3 other validators, so 75% of total stake. - report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_4, scenario); - report_validator(VALIDATOR_ADDR_2, VALIDATOR_ADDR_4, scenario); - report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_4, scenario); - - // 1000 SUI of storage rewards, 1500 SUI of computation rewards, 50% slashing threshold - // and 20% slashing rate - advance_epoch_with_reward_amounts_and_slashing_rates( - 1000, 1500, 2000, scenario - ); - - // Each unslashed validator staking pool gets 300 SUI of computation rewards + 75 SUI of storage fund rewards + - // 20 SUI (1/3) of validator 4's slashed computation reward and 5 SUI (1/3) of validator 4's slashed - // storage fund reward, so in total it gets 400 SUI of rewards. - // Validator 3 has a delegator with her so she gets 320 * 3/4 + 75 + 5 = 320 SUI of rewards. - // Validator 4's should get 300 * 4/5 * (1 - 20%) = 192 in computation rewards and 75 * (1 - 20%) = 60 in storage rewards. - assert_validator_self_stake_amounts(validator_addrs(), vector[500 * MIST_PER_SUI, 600 * MIST_PER_SUI, 620 * MIST_PER_SUI, 652 * MIST_PER_SUI], scenario); - - // Unstake so we can check the stake rewards as well. - unstake(STAKER_ADDR_1, 0, scenario); - unstake(STAKER_ADDR_2, 0, scenario); - - // Staker 1 gets 320 * 1/4 = 80 SUI of rewards. - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), (100 + 80) * MIST_PER_SUI); - // Staker 2 gets 300 * 1/5 * (1 - 20%) = 48 SUI of rewards. - assert_eq(total_sui_balance(STAKER_ADDR_2, scenario), (100 + 48) * MIST_PER_SUI); - - scenario_val.end(); - } - - #[test] - fun test_everyone_slashed() { - // This test is to make sure that if everyone is slashed, our protocol works as expected without aborting - // and all rewards go to the storage fund. - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_4, scenario); - report_validator(VALIDATOR_ADDR_2, VALIDATOR_ADDR_4, scenario); - report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_4, scenario); - report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_3, scenario); - report_validator(VALIDATOR_ADDR_2, VALIDATOR_ADDR_3, scenario); - report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_3, scenario); - report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_2, scenario); - report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_2, scenario); - report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_2, scenario); - report_validator(VALIDATOR_ADDR_2, VALIDATOR_ADDR_1, scenario); - report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_1, scenario); - report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_1, scenario); - - advance_epoch_with_reward_amounts_and_slashing_rates( - 1000, 3000, 10_000, scenario - ); - - // All validators should have 0 rewards added so their stake stays the same. - assert_validator_self_stake_amounts(validator_addrs(), vector[100 * MIST_PER_SUI, 200 * MIST_PER_SUI, 300 * MIST_PER_SUI, 400 * MIST_PER_SUI], scenario); - - scenario.next_tx(@0x0); - // Storage fund balance should increase by 4000 SUI. - let mut system_state = scenario.take_shared(); - assert_eq(system_state.get_storage_fund_total_balance(), 4000 * MIST_PER_SUI); - - // The entire 1000 SUI of storage rewards should go to the object rebate portion of the storage fund. - assert_eq(system_state.get_storage_fund_object_rebates(), 1000 * MIST_PER_SUI); - - test_scenario::return_shared(system_state); - scenario_val.end(); - } - - #[test] - fun test_mul_rewards_withdraws_at_same_epoch() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 220, scenario); - - advance_epoch_with_reward_amounts(0, 40, scenario); - - stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_1, 480, scenario); - - // Staker 1 gets 2/3 * 1/4 * 120 = 20 SUI here. - advance_epoch_with_reward_amounts(0, 120, scenario); - - stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 130, scenario); - stake_with(STAKER_ADDR_3, VALIDATOR_ADDR_1, 390, scenario); - - // Staker 1 gets 20 SUI here and staker 2 gets 40 SUI here. - advance_epoch_with_reward_amounts(0, 280, scenario); - stake_with(STAKER_ADDR_3, VALIDATOR_ADDR_1, 280, scenario); - stake_with(STAKER_ADDR_4, VALIDATOR_ADDR_1, 1400, scenario); - - // Staker 1 gets 30 SUI, staker 2 gets 40 SUI and staker 3 gets 30 SUI. - advance_epoch_with_reward_amounts(0, 440, scenario); - - scenario.next_tx(@0x0); - let mut system_state = scenario.take_shared(); - // Check that we have the right amount of SUI in the staking pool. - assert_eq(system_state.validator_stake_amount(VALIDATOR_ADDR_1), 140 * 23 * MIST_PER_SUI); - test_scenario::return_shared(system_state); - - // Withdraw all stakes at once. - unstake(STAKER_ADDR_1, 0, scenario); - unstake(STAKER_ADDR_1, 0, scenario); - unstake(STAKER_ADDR_2, 0, scenario); - unstake(STAKER_ADDR_3, 0, scenario); - unstake(STAKER_ADDR_3, 0, scenario); - unstake(STAKER_ADDR_4, 0, scenario); - - // staker 1's first stake was active for 3 epochs so got 20 * 3 = 60 SUI of rewards - // and her second stake was active for only one epoch and got 10 SUI of rewards. - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), (220 + 130 + 20 * 3 + 10) * MIST_PER_SUI); - // staker 2's stake was active for 2 epochs so got 40 * 2 = 80 SUI of rewards - assert_eq(total_sui_balance(STAKER_ADDR_2, scenario), (480 + 40 * 2) * MIST_PER_SUI); - // staker 3's first stake was active for 1 epoch and got 30 SUI of rewards - // and her second stake didn't get any rewards. - assert_eq(total_sui_balance(STAKER_ADDR_3, scenario), (390 + 280 + 30) * MIST_PER_SUI); - // staker 4 joined and left in an epoch where no rewards were earned so she got no rewards. - assert_eq(total_sui_balance(STAKER_ADDR_4, scenario), 1400 * MIST_PER_SUI); - - advance_epoch_with_reward_amounts(0, 0, scenario); - - scenario.next_tx(@0x0); - let mut system_state = scenario.take_shared(); - // Since all the stakes are gone the pool is empty except for the validator's original stake. - assert_eq(system_state.validator_stake_amount(VALIDATOR_ADDR_1), 140 * MIST_PER_SUI); - test_scenario::return_shared(system_state); - scenario_val.end(); - } - - #[test] - fun test_uncapped_rewards() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - - let ctx = scenario.ctx(); - let mut validators = vector[]; - - let num_validators = 20; - let mut i = 0; - // Create a set of 20 validators, each with 481 + i * 2 SUI of stake. - // The stake total sums up to be 481 + 483 + ... + 517 + 519 = 1000 SUI. - while (i < num_validators) { - let validator = create_validator_for_testing(address::from_u256(i as u256), (481 + i * 2), ctx); - validators.push_back(validator); - i = i + 1; - }; - - create_sui_system_state_for_testing(validators, 0, 0, ctx); - // Each validator's stake gets doubled. - advance_epoch_with_reward_amounts(0, 10000, scenario); - - let mut i = 0; - scenario.next_tx(@0x0); - // Check that each validator has the correct amount of SUI in their stake pool. - let mut system_state = scenario.take_shared(); - while (i < num_validators) { - let addr = address::from_u256(i as u256); - assert_eq(system_state.validator_stake_amount(addr), (962 + i * 4) * MIST_PER_SUI); - i = i + 1; - }; - test_scenario::return_shared(system_state); - scenario_val.end(); - } - - fun set_up_sui_system_state() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - let ctx = scenario.ctx(); - - let validators = vector[ - create_validator_for_testing(VALIDATOR_ADDR_1, 100, ctx), - create_validator_for_testing(VALIDATOR_ADDR_2, 200, ctx), - create_validator_for_testing(VALIDATOR_ADDR_3, 300, ctx), - create_validator_for_testing(VALIDATOR_ADDR_4, 400, ctx), - ]; - create_sui_system_state_for_testing(validators, 1000, 0, ctx); - scenario_val.end(); - } - - fun set_up_sui_system_state_with_big_amounts() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - let ctx = scenario.ctx(); - - let validators = vector[ - create_validator_for_testing(VALIDATOR_ADDR_1, 100000000, ctx), - create_validator_for_testing(VALIDATOR_ADDR_2, 200000000, ctx), - create_validator_for_testing(VALIDATOR_ADDR_3, 300000000, ctx), - create_validator_for_testing(VALIDATOR_ADDR_4, 400000000, ctx), - ]; - create_sui_system_state_for_testing(validators, 1000000000, 0, ctx); - scenario_val.end(); - } - - fun validator_addrs() : vector
    { - vector[VALIDATOR_ADDR_1, VALIDATOR_ADDR_2, VALIDATOR_ADDR_3, VALIDATOR_ADDR_4] - } - - fun set_commission_rate_and_advance_epoch(addr: address, commission_rate: u64, scenario: &mut Scenario) { - scenario.next_tx(addr); - let mut system_state = scenario.take_shared(); - let ctx = scenario.ctx(); - system_state.request_set_commission_rate(commission_rate, ctx); - test_scenario::return_shared(system_state); - advance_epoch(scenario); - } - - fun report_validator(reporter: address, reportee: address, scenario: &mut Scenario) { - scenario.next_tx(reporter); - let mut system_state = scenario.take_shared(); - let cap = scenario.take_from_sender(); - system_state.report_validator(&cap, reportee); - scenario.return_to_sender(cap); - test_scenario::return_shared(system_state); - } -} diff --git a/crates/sui-framework/packages/sui-system/tests/sui_system_tests.move b/crates/sui-framework/packages/sui-system/tests/sui_system_tests.move deleted file mode 100644 index 0debd1b9556..00000000000 --- a/crates/sui-framework/packages/sui-system/tests/sui_system_tests.move +++ /dev/null @@ -1,1005 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// This file contains tests testing functionalities in `sui_system` that are not -// already tested by the other more themed tests such as `stake_tests` or -// `rewards_distribution_tests`. - -#[test_only] -module sui_system::sui_system_tests { - use sui::test_scenario::{Self, Scenario}; - use sui::sui::SUI; - use sui_system::governance_test_utils::{add_validator_full_flow, advance_epoch, remove_validator, set_up_sui_system_state, create_sui_system_state_for_testing}; - use sui_system::sui_system::SuiSystemState; - use sui_system::sui_system_state_inner; - use sui_system::validator::{Self, Validator}; - use sui_system::validator_set; - use sui_system::validator_cap::UnverifiedValidatorOperationCap; - use sui::balance; - use sui::test_utils::{assert_eq, destroy}; - use sui::url; - - #[test] - fun test_report_validator() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - - set_up_sui_system_state(vector[@0x1, @0x2, @0x3]); - - report_helper(@0x1, @0x2, false, scenario); - assert!(get_reporters_of(@0x2, scenario) == vector[@0x1], 0); - report_helper(@0x3, @0x2, false, scenario); - assert!(get_reporters_of(@0x2, scenario) == vector[@0x1, @0x3], 0); - - // Report again and result should stay the same. - report_helper(@0x1, @0x2, false, scenario); - assert!(get_reporters_of(@0x2, scenario) == vector[@0x1, @0x3], 0); - - // Undo the report. - report_helper(@0x3, @0x2, true, scenario); - assert!(get_reporters_of(@0x2, scenario) == vector[@0x1], 0); - - advance_epoch(scenario); - - // After an epoch ends, report records are still present. - assert!(get_reporters_of(@0x2, scenario) == vector[@0x1], 0); - - report_helper(@0x2, @0x1, false, scenario); - assert!(get_reporters_of(@0x1, scenario) == vector[@0x2], 0); - - - report_helper(@0x3, @0x2, false, scenario); - assert!(get_reporters_of(@0x2, scenario) == vector[@0x1, @0x3], 0); - - // After 0x3 leaves, its reports are gone - remove_validator(@0x3, scenario); - advance_epoch(scenario); - assert!(get_reporters_of(@0x2, scenario) == vector[@0x1], 0); - - // After 0x1 leaves, both its reports and the reports on its name are gone - remove_validator(@0x1, scenario); - advance_epoch(scenario); - assert!(get_reporters_of(@0x1, scenario).is_empty(), 0); - assert!(get_reporters_of(@0x2, scenario).is_empty(), 0); - scenario_val.end(); - } - - #[test] - fun test_validator_ops_by_stakee_ok() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - set_up_sui_system_state(vector[@0x1, @0x2]); - - // @0x1 transfers the cap object to stakee. - let stakee_address = @0xbeef; - scenario.next_tx(@0x1); - let cap = scenario.take_from_sender(); - transfer::public_transfer(cap, stakee_address); - - // With the cap object in hand, stakee could report validators on behalf of @0x1. - report_helper(stakee_address, @0x2, false, scenario); - assert!(get_reporters_of(@0x2, scenario) == vector[@0x1], 0); - - // stakee could also undo report. - report_helper(stakee_address, @0x2, true, scenario); - assert!(get_reporters_of(@0x2, scenario).is_empty(), 0); - - scenario.next_tx(stakee_address); - let cap = scenario.take_from_sender(); - let new_stakee_address = @0xcafe; - transfer::public_transfer(cap, new_stakee_address); - - // New stakee could report validators on behalf of @0x1. - report_helper(new_stakee_address, @0x2, false, scenario); - assert!(get_reporters_of(@0x2, scenario) == vector[@0x1], 0); - - // New stakee could also set reference gas price on behalf of @0x1. - set_gas_price_helper(new_stakee_address, 666, scenario); - - // Add a pending validator - let new_validator_addr = @0x1a4623343cd42be47d67314fce0ad042f3c82685544bc91d8c11d24e74ba7357; - scenario.next_tx(new_validator_addr); - let pubkey = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; - let pop = x"8b93fc1b33379e2796d361c4056f0f04ad5aea7f4a8c02eaac57340ff09b6dc158eb1945eece103319167f420daf0cb3"; - add_validator_full_flow(new_validator_addr, b"name1", b"/ip4/127.0.0.1/udp/81", 100, pubkey, pop, scenario); - - scenario.next_tx(new_validator_addr); - // Pending validator could set reference price as well - set_gas_price_helper(new_validator_addr, 777, scenario); - - scenario.next_tx(new_stakee_address); - let mut system_state = scenario.take_shared(); - let validator = system_state.active_validator_by_address(@0x1); - assert!(validator.next_epoch_gas_price() == 666, 0); - let pending_validator = system_state.pending_validator_by_address(new_validator_addr); - assert!(pending_validator.next_epoch_gas_price() == 777, 0); - test_scenario::return_shared(system_state); - - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = ::sui_system::validator_set::EInvalidCap)] - fun test_report_validator_by_stakee_revoked() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - set_up_sui_system_state(vector[@0x1, @0x2]); - - // @0x1 transfers the cap object to stakee. - let stakee_address = @0xbeef; - scenario.next_tx(@0x1); - let cap = scenario.take_from_sender(); - transfer::public_transfer(cap, stakee_address); - - report_helper(stakee_address, @0x2, false, scenario); - assert!(get_reporters_of(@0x2, scenario) == vector[@0x1], 0); - - // @0x1 revokes stakee's permission by creating a new - // operation cap object. - rotate_operation_cap(@0x1, scenario); - - // stakee no longer has permission to report validators, here it aborts. - report_helper(stakee_address, @0x2, true, scenario); - - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = ::sui_system::validator_set::EInvalidCap)] - fun test_set_reference_gas_price_by_stakee_revoked() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - set_up_sui_system_state(vector[@0x1, @0x2]); - - // @0x1 transfers the cap object to stakee. - let stakee_address = @0xbeef; - scenario.next_tx(@0x1); - let cap = scenario.take_from_sender(); - transfer::public_transfer(cap, stakee_address); - - // With the cap object in hand, stakee could report validators on behalf of @0x1. - set_gas_price_helper(stakee_address, 888, scenario); - - scenario.next_tx(stakee_address); - let mut system_state = scenario.take_shared(); - let validator = system_state.active_validator_by_address(@0x1); - assert!(validator.next_epoch_gas_price() == 888, 0); - test_scenario::return_shared(system_state); - - // @0x1 revokes stakee's permssion by creating a new - // operation cap object. - rotate_operation_cap(@0x1, scenario); - - // stakee no longer has permission to report validators, here it aborts. - set_gas_price_helper(stakee_address, 888, scenario); - - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = validator::EGasPriceHigherThanThreshold)] - fun test_set_gas_price_failure() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - set_up_sui_system_state(vector[@0x1, @0x2]); - - // Fails here since the gas price is too high. - set_gas_price_helper(@0x1, 100_001, scenario); - - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = validator::ECommissionRateTooHigh)] - fun test_set_commission_rate_failure() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - set_up_sui_system_state(vector[@0x1, @0x2]); - - scenario.next_tx(@0x2); - let mut system_state = scenario.take_shared(); - - // Fails here since the commission rate is too high. - system_state.request_set_commission_rate(2001, scenario.ctx()); - test_scenario::return_shared(system_state); - - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = sui_system_state_inner::ENotValidator)] - fun test_report_non_validator_failure() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - - set_up_sui_system_state(vector[@0x1, @0x2, @0x3]); - report_helper(@0x1, @0x42, false, scenario); - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = sui_system_state_inner::ECannotReportOneself)] - fun test_report_self_failure() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - - set_up_sui_system_state(vector[@0x1, @0x2, @0x3]); - report_helper(@0x1, @0x1, false, scenario); - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = sui_system_state_inner::EReportRecordNotFound)] - fun test_undo_report_failure() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - - set_up_sui_system_state(vector[@0x1, @0x2, @0x3]); - report_helper(@0x2, @0x1, true, scenario); - scenario_val.end(); - } - - #[test] - fun test_staking_pool_mappings() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - - set_up_sui_system_state(vector[@0x1, @0x2, @0x3, @0x4]); - scenario.next_tx(@0x1); - let mut system_state = scenario.take_shared(); - let pool_id_1 = system_state.validator_staking_pool_id(@0x1); - let pool_id_2 = system_state.validator_staking_pool_id(@0x2); - let pool_id_3 = system_state.validator_staking_pool_id(@0x3); - let pool_id_4 = system_state.validator_staking_pool_id(@0x4); - let mut pool_mappings = system_state.validator_staking_pool_mappings(); - assert_eq(pool_mappings.length(), 4); - assert_eq(pool_mappings[pool_id_1], @0x1); - assert_eq(pool_mappings[pool_id_2], @0x2); - assert_eq(pool_mappings[pool_id_3], @0x3); - assert_eq(pool_mappings[pool_id_4], @0x4); - test_scenario::return_shared(system_state); - - let new_validator_addr = @0xaf76afe6f866d8426d2be85d6ef0b11f871a251d043b2f11e15563bf418f5a5a; - scenario.next_tx(new_validator_addr); - // Seed [0; 32] - let pubkey = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; - // Generated with [fn test_proof_of_possession] - let pop = x"b01cc86f421beca7ab4cfca87c0799c4d038c199dd399fbec1924d4d4367866dba9e84d514710b91feb65316e4ceef43"; - - // Add a validator - add_validator_full_flow(new_validator_addr, b"name2", b"/ip4/127.0.0.1/udp/82", 100, pubkey, pop, scenario); - advance_epoch(scenario); - - scenario.next_tx(@0x1); - let mut system_state = scenario.take_shared(); - let pool_id_5 = system_state.validator_staking_pool_id(new_validator_addr); - pool_mappings = system_state.validator_staking_pool_mappings(); - // Check that the previous mappings didn't change as well. - assert_eq(pool_mappings.length(), 5); - assert_eq(pool_mappings[pool_id_1], @0x1); - assert_eq(pool_mappings[pool_id_2], @0x2); - assert_eq(pool_mappings[pool_id_3], @0x3); - assert_eq(pool_mappings[pool_id_4], @0x4); - assert_eq(pool_mappings[pool_id_5], new_validator_addr); - test_scenario::return_shared(system_state); - - // Remove one of the original validators. - remove_validator(@0x1, scenario); - advance_epoch(scenario); - - scenario.next_tx(@0x1); - let mut system_state = scenario.take_shared(); - pool_mappings = system_state.validator_staking_pool_mappings(); - // Check that the previous mappings didn't change as well. - assert_eq(pool_mappings.length(), 4); - assert_eq(pool_mappings.contains(pool_id_1), false); - assert_eq(pool_mappings[pool_id_2], @0x2); - assert_eq(pool_mappings[pool_id_3], @0x3); - assert_eq(pool_mappings[pool_id_4], @0x4); - assert_eq(pool_mappings[pool_id_5], new_validator_addr); - test_scenario::return_shared(system_state); - - scenario_val.end(); - } - - fun report_helper(sender: address, reported: address, is_undo: bool, scenario: &mut Scenario) { - scenario.next_tx(sender); - - let mut system_state = scenario.take_shared(); - let cap = scenario.take_from_sender(); - if (is_undo) { - system_state.undo_report_validator(&cap, reported); - } else { - system_state.report_validator(&cap, reported); - }; - scenario.return_to_sender(cap); - test_scenario::return_shared(system_state); - } - - fun set_gas_price_helper( - sender: address, - new_gas_price: u64, - scenario: &mut Scenario, - ) { - scenario.next_tx(sender); - let cap = scenario.take_from_sender(); - let mut system_state = scenario.take_shared(); - system_state.request_set_gas_price(&cap, new_gas_price); - scenario.return_to_sender(cap); - test_scenario::return_shared(system_state); - } - - - fun rotate_operation_cap(sender: address, scenario: &mut Scenario) { - scenario.next_tx(sender); - let mut system_state = scenario.take_shared(); - let ctx = scenario.ctx(); - system_state.rotate_operation_cap(ctx); - test_scenario::return_shared(system_state); - } - - fun get_reporters_of(addr: address, scenario: &mut Scenario): vector
    { - scenario.next_tx(addr); - let mut system_state = scenario.take_shared(); - let res = system_state.get_reporters_of(addr).into_keys(); - test_scenario::return_shared(system_state); - res - } - - fun update_candidate( - scenario: &mut Scenario, - system_state: &mut SuiSystemState, - name: vector, - protocol_pub_key: vector, - pop: vector, - network_address: vector, - p2p_address: vector, - commission_rate: u64, - gas_price: u64, - ) { - let ctx = scenario.ctx(); - system_state.update_validator_name(name, ctx); - system_state.update_validator_description(b"new_desc", ctx); - system_state.update_validator_image_url(b"new_image_url", ctx); - system_state.update_validator_project_url(b"new_project_url", ctx); - system_state.update_candidate_validator_network_address(network_address, ctx); - system_state.update_candidate_validator_p2p_address(p2p_address, ctx); - system_state.update_candidate_validator_primary_address(b"/ip4/127.0.0.1/udp/80", ctx); - system_state.update_candidate_validator_worker_address(b"/ip4/127.0.0.1/udp/80", ctx); - system_state.update_candidate_validator_protocol_pubkey( - protocol_pub_key, - pop, - ctx - ); - system_state.update_candidate_validator_worker_pubkey(vector[68, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], ctx); - system_state.update_candidate_validator_network_pubkey(vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], ctx); - - system_state.set_candidate_validator_commission_rate(commission_rate, ctx); - let cap = scenario.take_from_sender(); - system_state.set_candidate_validator_gas_price(&cap, gas_price); - scenario.return_to_sender(cap); - } - - - fun verify_candidate( - validator: &Validator, - name: vector, - protocol_pub_key: vector, - pop: vector, - network_address: vector, - p2p_address: vector, - commission_rate: u64, - gas_price: u64, - - ) { - verify_current_epoch_metadata( - validator, - name, - protocol_pub_key, - pop, - b"/ip4/127.0.0.1/udp/80", - b"/ip4/127.0.0.1/udp/80", - network_address, - p2p_address, - vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], - vector[68, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], - ); - assert!(validator.commission_rate() == commission_rate, 0); - assert!(validator.gas_price() == gas_price, 0); - - } - - // Note: `pop` MUST be a valid signature using sui_address and protocol_pubkey_bytes. - // To produce a valid PoP, run [fn test_proof_of_possession]. - fun update_metadata( - scenario: &mut Scenario, - system_state: &mut SuiSystemState, - name: vector, - protocol_pub_key: vector, - pop: vector, - network_address: vector, - p2p_address: vector, - network_pubkey: vector, - worker_pubkey: vector, - ) { - let ctx = scenario.ctx(); - system_state.update_validator_name(name, ctx); - system_state.update_validator_description(b"new_desc", ctx); - system_state.update_validator_image_url(b"new_image_url", ctx); - system_state.update_validator_project_url(b"new_project_url", ctx); - system_state.update_validator_next_epoch_network_address(network_address, ctx); - system_state.update_validator_next_epoch_p2p_address(p2p_address, ctx); - system_state.update_validator_next_epoch_primary_address(b"/ip4/168.168.168.168/udp/80", ctx); - system_state.update_validator_next_epoch_worker_address(b"/ip4/168.168.168.168/udp/80", ctx); - system_state.update_validator_next_epoch_protocol_pubkey( - protocol_pub_key, - pop, - ctx - ); - system_state.update_validator_next_epoch_network_pubkey(network_pubkey, ctx); - system_state.update_validator_next_epoch_worker_pubkey(worker_pubkey, ctx); - } - - fun verify_metadata( - validator: &Validator, - name: vector, - protocol_pub_key: vector, - pop: vector, - network_address: vector, - p2p_address: vector, - network_pubkey: vector, - worker_pubkey: vector, - new_protocol_pub_key: vector, - new_pop: vector, - new_network_address: vector, - new_p2p_address: vector, - new_network_pubkey: vector, - new_worker_pubkey: vector, - ) { - // Current epoch - verify_current_epoch_metadata( - validator, - name, - protocol_pub_key, - pop, - b"/ip4/127.0.0.1/udp/80", - b"/ip4/127.0.0.1/udp/80", - network_address, - p2p_address, - network_pubkey, - worker_pubkey, - ); - - // Next epoch - assert!(validator.next_epoch_network_address() == &option::some(new_network_address.to_string()), 0); - assert!(validator.next_epoch_p2p_address() == &option::some(new_p2p_address.to_string()), 0); - assert!(validator.next_epoch_primary_address() == &option::some(b"/ip4/168.168.168.168/udp/80".to_string()), 0); - assert!(validator.next_epoch_worker_address() == &option::some(b"/ip4/168.168.168.168/udp/80".to_string()), 0); - assert!( - validator.next_epoch_protocol_pubkey_bytes() == &option::some(new_protocol_pub_key), - 0 - ); - assert!( - validator.next_epoch_proof_of_possession() == &option::some(new_pop), - 0 - ); - assert!( - validator.next_epoch_worker_pubkey_bytes() == &option::some(new_worker_pubkey), - 0 - ); - assert!( - validator.next_epoch_network_pubkey_bytes() == &option::some(new_network_pubkey), - 0 - ); - } - - fun verify_current_epoch_metadata( - validator: &Validator, - name: vector, - protocol_pub_key: vector, - pop: vector, - primary_address: vector, - worker_address: vector, - network_address: vector, - p2p_address: vector, - network_pubkey_bytes: vector, - worker_pubkey_bytes: vector, - ) { - // Current epoch - assert!(validator.name() == &name.to_string(), 0); - assert!(validator.description() == &b"new_desc".to_string(), 0); - assert!(validator.image_url() == &url::new_unsafe_from_bytes(b"new_image_url"), 0); - assert!(validator.project_url() == &url::new_unsafe_from_bytes(b"new_project_url"), 0); - assert!(validator.network_address() == &network_address.to_string(), 0); - assert!(validator.p2p_address() == &p2p_address.to_string(), 0); - assert!(validator.primary_address() == &primary_address.to_string(), 0); - assert!(validator.worker_address() == &worker_address.to_string(), 0); - assert!(validator.protocol_pubkey_bytes() == &protocol_pub_key, 0); - assert!(validator.proof_of_possession() == &pop, 0); - assert!(validator.worker_pubkey_bytes() == &worker_pubkey_bytes, 0); - assert!(validator.network_pubkey_bytes() == &network_pubkey_bytes, 0); - } - - - fun verify_metadata_after_advancing_epoch( - validator: &Validator, - name: vector, - protocol_pub_key: vector, - pop: vector, - network_address: vector, - p2p_address: vector, - network_pubkey: vector, - worker_pubkey: vector, - ) { - // Current epoch - verify_current_epoch_metadata( - validator, - name, - protocol_pub_key, - pop, - b"/ip4/168.168.168.168/udp/80", - b"/ip4/168.168.168.168/udp/80", - network_address, - p2p_address, - network_pubkey, - worker_pubkey, - ); - - // Next epoch - assert!(validator.next_epoch_network_address().is_none(), 0); - assert!(validator.next_epoch_p2p_address().is_none(), 0); - assert!(validator.next_epoch_primary_address().is_none(), 0); - assert!(validator.next_epoch_worker_address().is_none(), 0); - assert!(validator.next_epoch_protocol_pubkey_bytes().is_none(), 0); - assert!(validator.next_epoch_proof_of_possession().is_none(), 0); - assert!(validator.next_epoch_worker_pubkey_bytes().is_none(), 0); - assert!(validator.next_epoch_network_pubkey_bytes().is_none(), 0); - } - - #[test] - fun test_active_validator_update_metadata() { - let validator_addr = @0xaf76afe6f866d8426d2be85d6ef0b11f871a251d043b2f11e15563bf418f5a5a; - // pubkey generated with protocol key on seed [0; 32] - let pubkey = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; - // pop generated using the protocol key and address with [fn test_proof_of_possession] - let pop = x"b01cc86f421beca7ab4cfca87c0799c4d038c199dd399fbec1924d4d4367866dba9e84d514710b91feb65316e4ceef43"; - - // pubkey generated with protocol key on seed [1; 32] - let pubkey1 = x"96d19c53f1bee2158c3fcfb5bb2f06d3a8237667529d2d8f0fbb22fe5c3b3e64748420b4103674490476d98530d063271222d2a59b0f7932909cc455a30f00c69380e6885375e94243f7468e9563aad29330aca7ab431927540e9508888f0e1c"; - let pop1 = x"a8a0bcaf04e13565914eb22fa9f27a76f297db04446860ee2b923d10224cedb130b30783fb60b12556e7fc50e5b57a86"; - - let new_validator_addr = @0x8e3446145b0c7768839d71840df389ffa3b9742d0baaff326a3d453b595f87d7; - // pubkey generated with protocol key on seed [2; 32] - let new_pubkey = x"adf2e2350fe9a58f3fa50777499f20331c4550ab70f6a4fb25a58c61b50b5366107b5c06332e71bb47aa99ce2d5c07fe0dab04b8af71589f0f292c50382eba6ad4c90acb010ab9db7412988b2aba1018aaf840b1390a8b2bee3fde35b4ab7fdf"; - let new_pop = x"926fdb08b2b46d802e3642044f215dcb049e6c17a376a272ffd7dba32739bb995370966698ab235ee172fbd974985cfe"; - - // pubkey generated with protocol key on seed [3; 32] - let new_pubkey1 = x"91b8de031e0b60861c655c8168596d98b065d57f26f287f8c810590b06a636eff13c4055983e95b2f60a4d6ba5484fa4176923d1f7807cc0b222ddf6179c1db099dba0433f098aae82542b3fd27b411d64a0a35aad01b2c07ac67f7d0a1d2c11"; - let new_pop1 = x"b61913eb4dc7ea1d92f174e1a3c6cad3f49ae8de40b13b69046ce072d8d778bfe87e734349c7394fd1543fff0cb6e2d0"; - - let mut scenario_val = test_scenario::begin(validator_addr); - let scenario = &mut scenario_val; - - // Set up SuiSystemState with an active validator - let mut validators = vector[]; - let ctx = scenario.ctx(); - let validator = validator::new_for_testing( - validator_addr, - pubkey, - vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], - vector[68, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], - pop, - b"ValidatorName", - b"description", - b"image_url", - b"project_url", - b"/ip4/127.0.0.1/tcp/80", - b"/ip4/127.0.0.1/udp/80", - b"/ip4/127.0.0.1/udp/80", - b"/ip4/127.0.0.1/udp/80", - option::some(balance::create_for_testing(100_000_000_000)), - 1, - 0, - true, - ctx - ); - validators.push_back(validator); - create_sui_system_state_for_testing(validators, 1000, 0, ctx); - - scenario.next_tx(validator_addr); - - let mut system_state = scenario.take_shared(); - - // Test active validator metadata changes - scenario.next_tx(validator_addr); - { - update_metadata( - scenario, - &mut system_state, - b"validator_new_name", - pubkey1, - pop1, - b"/ip4/42.42.42.42/tcp/80", - b"/ip4/43.43.43.43/udp/80", - vector[148, 117, 212, 171, 44, 104, 167, 11, 177, 100, 4, 55, 17, 235, 117, 45, 117, 84, 159, 49, 14, 159, 239, 246, 237, 21, 83, 166, 112, 53, 62, 199], - vector[215, 64, 85, 185, 231, 116, 69, 151, 97, 79, 4, 183, 20, 70, 84, 51, 211, 162, 115, 221, 73, 241, 240, 171, 192, 25, 232, 106, 175, 162, 176, 43], - ); - }; - - scenario.next_tx(validator_addr); - let validator = system_state.active_validator_by_address(validator_addr); - verify_metadata( - validator, - b"validator_new_name", - pubkey, - pop, - b"/ip4/127.0.0.1/tcp/80", - b"/ip4/127.0.0.1/udp/80", - vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], - vector[68, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], - pubkey1, - pop1, - b"/ip4/42.42.42.42/tcp/80", - b"/ip4/43.43.43.43/udp/80", - vector[148, 117, 212, 171, 44, 104, 167, 11, 177, 100, 4, 55, 17, 235, 117, 45, 117, 84, 159, 49, 14, 159, 239, 246, 237, 21, 83, 166, 112, 53, 62, 199], - vector[215, 64, 85, 185, 231, 116, 69, 151, 97, 79, 4, 183, 20, 70, 84, 51, 211, 162, 115, 221, 73, 241, 240, 171, 192, 25, 232, 106, 175, 162, 176, 43], - ); - - test_scenario::return_shared(system_state); - scenario_val.end(); - - // Test pending validator metadata changes - let mut scenario_val = test_scenario::begin(new_validator_addr); - let scenario = &mut scenario_val; - let mut system_state = scenario.take_shared(); - scenario.next_tx(new_validator_addr); - { - let ctx = scenario.ctx(); - system_state.request_add_validator_candidate( - new_pubkey, - vector[33, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], - vector[69, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], - new_pop, - b"ValidatorName2", - b"description2", - b"image_url2", - b"project_url2", - b"/ip4/127.0.0.2/tcp/80", - b"/ip4/127.0.0.2/udp/80", - b"/ip4/127.0.0.1/udp/80", - b"/ip4/127.0.0.1/udp/80", - 1, - 0, - ctx, - ); - system_state.request_add_validator_for_testing(0, ctx); - }; - - scenario.next_tx(new_validator_addr); - { - update_metadata( - scenario, - &mut system_state, - b"new_validator_new_name", - new_pubkey1, - new_pop1, - b"/ip4/66.66.66.66/tcp/80", - b"/ip4/77.77.77.77/udp/80", - vector[215, 65, 85, 185, 231, 116, 69, 151, 97, 79, 4, 183, 20, 70, 84, 51, 211, 162, 115, 221, 73, 241, 240, 171, 192, 25, 232, 106, 175, 162, 176, 43], - vector[149, 117, 212, 171, 44, 104, 167, 11, 177, 100, 4, 55, 17, 235, 117, 45, 117, 84, 159, 49, 14, 159, 239, 246, 237, 21, 83, 166, 112, 53, 62, 199], - ); - }; - - scenario.next_tx(new_validator_addr); - let validator = system_state.pending_validator_by_address(new_validator_addr); - verify_metadata( - validator, - b"new_validator_new_name", - new_pubkey, - new_pop, - b"/ip4/127.0.0.2/tcp/80", - b"/ip4/127.0.0.2/udp/80", - vector[33, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], - vector[69, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], - new_pubkey1, - new_pop1, - b"/ip4/66.66.66.66/tcp/80", - b"/ip4/77.77.77.77/udp/80", - vector[215, 65, 85, 185, 231, 116, 69, 151, 97, 79, 4, 183, 20, 70, 84, 51, 211, 162, 115, 221, 73, 241, 240, 171, 192, 25, 232, 106, 175, 162, 176, 43], - vector[149, 117, 212, 171, 44, 104, 167, 11, 177, 100, 4, 55, 17, 235, 117, 45, 117, 84, 159, 49, 14, 159, 239, 246, 237, 21, 83, 166, 112, 53, 62, 199], - ); - - test_scenario::return_shared(system_state); - - // Advance epoch to effectuate the metadata changes. - scenario.next_tx(new_validator_addr); - advance_epoch(scenario); - - // Now both validators are active, verify their metadata. - scenario.next_tx(new_validator_addr); - let mut system_state = scenario.take_shared(); - let validator = system_state.active_validator_by_address(validator_addr); - verify_metadata_after_advancing_epoch( - validator, - b"validator_new_name", - pubkey1, - pop1, - b"/ip4/42.42.42.42/tcp/80", - b"/ip4/43.43.43.43/udp/80", - vector[148, 117, 212, 171, 44, 104, 167, 11, 177, 100, 4, 55, 17, 235, 117, 45, 117, 84, 159, 49, 14, 159, 239, 246, 237, 21, 83, 166, 112, 53, 62, 199], - vector[215, 64, 85, 185, 231, 116, 69, 151, 97, 79, 4, 183, 20, 70, 84, 51, 211, 162, 115, 221, 73, 241, 240, 171, 192, 25, 232, 106, 175, 162, 176, 43], - ); - - let validator = system_state.active_validator_by_address(new_validator_addr); - verify_metadata_after_advancing_epoch( - validator, - b"new_validator_new_name", - new_pubkey1, - new_pop1, - b"/ip4/66.66.66.66/tcp/80", - b"/ip4/77.77.77.77/udp/80", - vector[215, 65, 85, 185, 231, 116, 69, 151, 97, 79, 4, 183, 20, 70, 84, 51, 211, 162, 115, 221, 73, 241, 240, 171, 192, 25, 232, 106, 175, 162, 176, 43], - vector[149, 117, 212, 171, 44, 104, 167, 11, 177, 100, 4, 55, 17, 235, 117, 45, 117, 84, 159, 49, 14, 159, 239, 246, 237, 21, 83, 166, 112, 53, 62, 199], - ); - - test_scenario::return_shared(system_state); - scenario_val.end(); - } - - - #[test] - fun test_validator_candidate_update() { - let validator_addr = @0xaf76afe6f866d8426d2be85d6ef0b11f871a251d043b2f11e15563bf418f5a5a; - // pubkey generated with protocol key on seed [0; 32] - let pubkey = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; - // pop generated using the protocol key and address with [fn test_proof_of_possession] - let pop = x"b01cc86f421beca7ab4cfca87c0799c4d038c199dd399fbec1924d4d4367866dba9e84d514710b91feb65316e4ceef43"; - - // pubkey generated with protocol key on seed [1; 32] - let pubkey1 = x"96d19c53f1bee2158c3fcfb5bb2f06d3a8237667529d2d8f0fbb22fe5c3b3e64748420b4103674490476d98530d063271222d2a59b0f7932909cc455a30f00c69380e6885375e94243f7468e9563aad29330aca7ab431927540e9508888f0e1c"; - let pop1 = x"a8a0bcaf04e13565914eb22fa9f27a76f297db04446860ee2b923d10224cedb130b30783fb60b12556e7fc50e5b57a86"; - - let mut scenario_val = test_scenario::begin(validator_addr); - let scenario = &mut scenario_val; - - set_up_sui_system_state(vector[@0x1, @0x2, @0x3]); - scenario.next_tx(validator_addr); - let mut system_state = scenario.take_shared(); - scenario.next_tx(validator_addr); - { - system_state.request_add_validator_candidate_for_testing( - pubkey, - vector[215, 64, 85, 185, 231, 116, 69, 151, 97, 79, 4, 183, 20, 70, 84, 51, 211, 162, 115, 221, 73, 241, 240, 171, 192, 25, 232, 106, 175, 162, 176, 43], - vector[148, 117, 212, 171, 44, 104, 167, 11, 177, 100, 4, 55, 17, 235, 117, 45, 117, 84, 159, 49, 14, 159, 239, 246, 237, 21, 83, 166, 112, 53, 62, 199], - pop, - b"ValidatorName2", - b"description2", - b"image_url2", - b"project_url2", - b"/ip4/127.0.0.2/tcp/80", - b"/ip4/127.0.0.2/udp/80", - b"/ip4/168.168.168.168/udp/80", - b"/ip4/168.168.168.168/udp/80", - 1, - 0, - scenario.ctx(), - ); - }; - - scenario.next_tx(validator_addr); - update_candidate( - scenario, - &mut system_state, - b"validator_new_name", - pubkey1, - pop1, - b"/ip4/42.42.42.42/tcp/80", - b"/ip4/43.43.43.43/udp/80", - 42, - 7, - ); - - scenario.next_tx(validator_addr); - - let validator = system_state.candidate_validator_by_address(validator_addr); - verify_candidate( - validator, - b"validator_new_name", - pubkey1, - pop1, - b"/ip4/42.42.42.42/tcp/80", - b"/ip4/43.43.43.43/udp/80", - 42, - 7, - ); - - - - test_scenario::return_shared(system_state); - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = validator::EMetadataInvalidWorkerPubkey)] - fun test_add_validator_candidate_failure_invalid_metadata() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - - // Generated using [fn test_proof_of_possession] - let new_validator_addr = @0x8e3446145b0c7768839d71840df389ffa3b9742d0baaff326a3d453b595f87d7; - let pubkey = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; - let pop = x"83809369ce6572be211512d85621a075ee6a8da57fbb2d867d05e6a395e71f10e4e957796944d68a051381eb91720fba"; - - set_up_sui_system_state(vector[@0x1, @0x2, @0x3]); - scenario.next_tx(new_validator_addr); - let mut system_state = scenario.take_shared(); - system_state.request_add_validator_candidate( - pubkey, - vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], - vector[42], // invalid - pop, - b"ValidatorName2", - b"description2", - b"image_url2", - b"project_url2", - b"/ip4/127.0.0.2/tcp/80", - b"/ip4/127.0.0.2/udp/80", - b"/ip4/127.0.0.1/udp/80", - b"/ip4/127.0.0.1/udp/80", - 1, - 0, - scenario.ctx(), - ); - test_scenario::return_shared(system_state); - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = validator_set::EAlreadyValidatorCandidate)] - fun test_add_validator_candidate_failure_double_register() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - let new_validator_addr = @0x8e3446145b0c7768839d71840df389ffa3b9742d0baaff326a3d453b595f87d7; - let pubkey = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; - let pop = x"83809369ce6572be211512d85621a075ee6a8da57fbb2d867d05e6a395e71f10e4e957796944d68a051381eb91720fba"; - - set_up_sui_system_state(vector[@0x1, @0x2, @0x3]); - scenario.next_tx(new_validator_addr); - let mut system_state = scenario.take_shared(); - system_state.request_add_validator_candidate( - pubkey, - vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], - vector[68, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], - pop, - b"ValidatorName2", - b"description2", - b"image_url2", - b"project_url2", - b"/ip4/127.0.0.2/tcp/80", - b"/ip4/127.0.0.2/udp/80", - b"/ip4/127.0.0.1/udp/80", - b"/ip4/127.0.0.1/udp/80", - 1, - 0, - scenario.ctx(), - ); - - // Add the same address as candidate again, should fail this time. - system_state.request_add_validator_candidate( - pubkey, - vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], - vector[68, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], - pop, - b"ValidatorName2", - b"description2", - b"image_url2", - b"project_url2", - b"/ip4/127.0.0.2/tcp/80", - b"/ip4/127.0.0.2/udp/80", - b"/ip4/127.0.0.1/udp/80", - b"/ip4/127.0.0.1/udp/80", - 1, - 0, - scenario.ctx(), - ); - test_scenario::return_shared(system_state); - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = validator_set::EDuplicateValidator)] - fun test_add_validator_candidate_failure_duplicate_with_active() { - let validator_addr = @0xaf76afe6f866d8426d2be85d6ef0b11f871a251d043b2f11e15563bf418f5a5a; - // Seed [0; 32] - let pubkey = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; - let pop = x"b01cc86f421beca7ab4cfca87c0799c4d038c199dd399fbec1924d4d4367866dba9e84d514710b91feb65316e4ceef43"; - - let new_addr = @0x1a4623343cd42be47d67314fce0ad042f3c82685544bc91d8c11d24e74ba7357; - // Seed [1; 32] - let new_pubkey = x"96d19c53f1bee2158c3fcfb5bb2f06d3a8237667529d2d8f0fbb22fe5c3b3e64748420b4103674490476d98530d063271222d2a59b0f7932909cc455a30f00c69380e6885375e94243f7468e9563aad29330aca7ab431927540e9508888f0e1c"; - let new_pop = x"932336c35a8c393019c63eb0f7d385dd4e0bd131f04b54cf45aa9544f14dca4dab53bd70ffcb8e0b34656e4388309720"; - - let mut scenario_val = test_scenario::begin(validator_addr); - let scenario = &mut scenario_val; - - // Set up SuiSystemState with an active validator - let ctx = scenario.ctx(); - let validator = validator::new_for_testing( - validator_addr, - pubkey, - vector[32, 219, 38, 23, 242, 109, 116, 235, 225, 192, 219, 45, 40, 124, 162, 25, 33, 68, 52, 41, 123, 9, 98, 11, 184, 150, 214, 62, 60, 210, 121, 62], - vector[68, 55, 206, 25, 199, 14, 169, 53, 68, 92, 142, 136, 174, 149, 54, 215, 101, 63, 249, 206, 197, 98, 233, 80, 60, 12, 183, 32, 216, 88, 103, 25], - pop, - b"ValidatorName", - b"description", - b"image_url", - b"project_url", - b"/ip4/127.0.0.1/tcp/80", - b"/ip4/127.0.0.1/udp/80", - b"/ip4/127.0.0.1/udp/80", - b"/ip4/127.0.0.1/udp/80", - option::some(balance::create_for_testing(100_000_000_000)), - 1, - 0, - true, - ctx - ); - create_sui_system_state_for_testing(vector[validator], 1000, 0, ctx); - - scenario.next_tx(new_addr); - - let mut system_state = scenario.take_shared(); - - // Add a candidate with the same name. Fails due to duplicating with an already active validator. - system_state.request_add_validator_candidate( - new_pubkey, - vector[115, 220, 238, 151, 134, 159, 173, 41, 80, 2, 66, 196, 61, 17, 191, 76, 103, 39, 246, 127, 171, 85, 19, 235, 210, 106, 97, 97, 116, 48, 244, 191], - vector[149, 128, 161, 13, 11, 183, 96, 45, 89, 20, 188, 205, 26, 127, 147, 254, 184, 229, 184, 102, 64, 170, 104, 29, 191, 171, 91, 99, 58, 178, 41, 156], - new_pop, - // same name - b"ValidatorName", - b"description2", - b"image_url2", - b"project_url2", - b"/ip4/127.0.0.2/tcp/80", - b"/ip4/127.0.0.2/udp/80", - b"/ip4/127.0.0.1/udp/80", - b"/ip4/127.0.0.1/udp/80", - 1, - 0, - scenario.ctx(), - ); - test_scenario::return_shared(system_state); - scenario_val.end(); - } - - #[test] - fun test_skip_stake_subsidy() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - // Epoch duration is set to be 42 here. - set_up_sui_system_state(vector[@0x1, @0x2]); - - // If the epoch length is less than 42 then the stake subsidy distribution counter should not be incremented. Otherwise it should. - advance_epoch_and_check_distribution_counter(scenario, 42, true); - advance_epoch_and_check_distribution_counter(scenario, 32, false); - advance_epoch_and_check_distribution_counter(scenario, 52, true); - scenario_val.end(); - } - - fun advance_epoch_and_check_distribution_counter(scenario: &mut Scenario, epoch_length: u64, should_increment_counter: bool) { - scenario.next_tx(@0x0); - let new_epoch = scenario.ctx().epoch() + 1; - let mut system_state = scenario.take_shared(); - let prev_epoch_time = system_state.epoch_start_timestamp_ms(); - let prev_counter = system_state.get_stake_subsidy_distribution_counter(); - - let rebate = system_state.advance_epoch_for_testing( - new_epoch, 1, 0, 0, 0, 0, 0, 0, prev_epoch_time + epoch_length, scenario.ctx() - ); - destroy(rebate); - assert_eq(system_state.get_stake_subsidy_distribution_counter(), prev_counter + (if (should_increment_counter) 1 else 0)); - test_scenario::return_shared(system_state); - scenario.next_epoch(@0x0); - } -} diff --git a/crates/sui-framework/packages/timelock/Move.lock b/crates/sui-framework/packages/timelock/Move.lock deleted file mode 100644 index 289128a4b5d..00000000000 --- a/crates/sui-framework/packages/timelock/Move.lock +++ /dev/null @@ -1,37 +0,0 @@ -# @generated by Move, please check-in and do not edit manually. - -[move] -version = 1 -manifest_digest = "F7B0657885F7F095E7ED4AC0F6A8772A191E3257D870D1C8A0DD84BFD1BE32E8" -deps_digest = "060AD7E57DFB13104F21BE5F5C3759D03F0553FC3229247D9A7A6B45F50D03A3" -dependencies = [ - { name = "MoveStdlib" }, - { name = "Sui" }, - { name = "SuiSystem" }, -] - -[[move.package]] -name = "MoveStdlib" -source = { local = "../move-stdlib" } - -[[move.package]] -name = "Sui" -source = { local = "../sui-framework" } - -dependencies = [ - { name = "MoveStdlib" }, -] - -[[move.package]] -name = "SuiSystem" -source = { local = "../sui-system" } - -dependencies = [ - { name = "MoveStdlib" }, - { name = "Sui" }, -] - -[move.toolchain-version] -compiler-version = "1.22.0" -edition = "legacy" -flavor = "sui" diff --git a/crates/sui-framework/packages/timelock/Move.toml b/crates/sui-framework/packages/timelock/Move.toml deleted file mode 100644 index 3448e14064c..00000000000 --- a/crates/sui-framework/packages/timelock/Move.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "TimeLock" -version = "0.0.1" -published-at = "0x10cf" -edition = "2024.beta" - -[dependencies] -MoveStdlib = { local = "../move-stdlib" } -Sui = { local = "../sui-framework" } -SuiSystem = { local = "../sui-system" } - -[addresses] -timelock = "0x10cf" diff --git a/crates/sui-framework/packages/timelock/sources/timelock.move b/crates/sui-framework/packages/timelock/sources/timelock.move deleted file mode 100644 index f8839860ef3..00000000000 --- a/crates/sui-framework/packages/timelock/sources/timelock.move +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -/// A timelock implementation. -module timelock::timelock { - /// Error code for when the expire timestamp of the lock is in the past. - const EExpireEpochIsPast: u64 = 0; - - /// Error code for when the lock has not expired yet. - const ENotExpiredYet: u64 = 1; - - /// `TimeLock` struct that holds a locked object. - public struct TimeLock has key { - id: UID, - /// The locked object. - locked: T, - /// This is the epoch time stamp of when the lock expires. - expiration_timestamp_ms: u64, - } - - /// Function to lock an object till a unix timestamp in milliseconds. - public fun lock(locked: T, expiration_timestamp_ms: u64, ctx: &mut TxContext): TimeLock { - // Get the epoch timestamp. - let epoch_timestamp_ms = ctx.epoch_timestamp_ms(); - - // Check that `expiration_timestamp_ms` is valid. - assert!(expiration_timestamp_ms > epoch_timestamp_ms, EExpireEpochIsPast); - - // Create a timelock. - pack(locked, expiration_timestamp_ms, ctx) - } - - /// Function to unlock the object from a `TimeLock`. - public fun unlock(self: TimeLock, ctx: &mut TxContext): T { - // Unpack the timelock. - let (locked, expiration_timestamp_ms) = unpack(self); - - // Check if the lock has expired. - assert!(expiration_timestamp_ms <= ctx.epoch_timestamp_ms(), ENotExpiredYet); - - locked - } - - /// Function to get the expiration timestamp of a `TimeLock`. - public fun expiration_timestamp_ms(self: &TimeLock): u64 { - self.expiration_timestamp_ms - } - - /// Function to check if a `TimeLock` is locked. - public fun is_locked(self: &TimeLock, ctx: &mut TxContext): bool { - self.remaining_time(ctx) > 0 - } - - /// Function to get the remaining time of a `TimeLock`. - /// Returns 0 if the lock has expired. - public fun remaining_time(self: &TimeLock, ctx: &mut TxContext): u64 { - // Get the epoch timestamp. - let current_timestamp_ms = ctx.epoch_timestamp_ms(); - - // Check if the lock has expired. - if (self.expiration_timestamp_ms < current_timestamp_ms) { - return 0 - }; - - // Calculate the remaining time. - self.expiration_timestamp_ms - current_timestamp_ms - } - - /// Function to get the locked object of a `TimeLock`. - public fun locked(self: &TimeLock): &T { - &self.locked - } - - /// Function to get a mutable reference to the locked object of a `TimeLock`. - public(package) fun locked_mut(self: &mut TimeLock): &mut T { - &mut self.locked - } - - /// An utility function to pack a `TimeLock`. - public(package) fun pack(locked: T, expiration_timestamp_ms: u64, ctx: &mut TxContext): TimeLock { - // Create a timelock. - TimeLock { - id: object::new(ctx), - locked, - expiration_timestamp_ms - } - } - - /// An utility function to unpack a `TimeLock`. - public(package) fun unpack(lock: TimeLock): (T, u64) { - // Unpack the timelock. - let TimeLock { - id, - locked, - expiration_timestamp_ms - } = lock; - - // Delete the timelock. - object::delete(id); - - (locked, expiration_timestamp_ms) - } - - /// An utility function to transfer a `TimeLock`. - public(package) fun transfer(lock: TimeLock, recipient: address) { - transfer::transfer(lock, recipient); - } -} diff --git a/crates/sui-framework/packages/timelock/sources/timelocked_staked_sui.move b/crates/sui-framework/packages/timelock/sources/timelocked_staked_sui.move deleted file mode 100644 index 4ce419fcfe6..00000000000 --- a/crates/sui-framework/packages/timelock/sources/timelocked_staked_sui.move +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -module timelock::timelocked_staked_sui { - - use sui_system::staking_pool::StakedSui; - - const EIncompatibleTimelockedStakedSui: u64 = 0; - - /// A self-custodial object holding the timelocked staked SUI tokens. - public struct TimelockedStakedSui has key { - id: UID, - /// A self-custodial object holding the staked SUI tokens. - staked_sui: StakedSui, - /// This is the epoch time stamp of when the lock expires. - expiration_timestamp_ms: u64, - } - - /// Create a new instance of `TimelockedStakedSui`. - public(package) fun create( - staked_sui: StakedSui, - expiration_timestamp_ms: u64, - ctx: &mut TxContext - ): TimelockedStakedSui { - TimelockedStakedSui { - id: object::new(ctx), - staked_sui, - expiration_timestamp_ms - } - } - - /// Function to get the pool id of a `TimelockedStakedSui`. - public fun pool_id(self: &TimelockedStakedSui): ID { self.staked_sui.pool_id() } - - /// Function to get the staked sui amount of a `TimelockedStakedSui`. - public fun staked_sui_amount(self: &TimelockedStakedSui): u64 { self.staked_sui.staked_sui_amount() } - - /// Allows calling `.amount()` on `TimelockedStakedSui` to invoke `staked_sui_amount` - public use fun staked_sui_amount as TimelockedStakedSui.amount; - - /// Function to get the stake activation epoch of a `TimelockedStakedSui`. - public fun stake_activation_epoch(self: &TimelockedStakedSui): u64 { - self.staked_sui.stake_activation_epoch() - } - - /// Function to get the expiration timestamp of a `TimelockedStakedSui`. - public fun expiration_timestamp_ms(self: &TimelockedStakedSui): u64 { - self.expiration_timestamp_ms - } - - /// Split `TimelockedStakedSui` into two parts, one with principal `split_amount`, - /// and the remaining principal is left in `self`. - /// All the other parameters of the `TimelockedStakedSui` like `stake_activation_epoch` or `pool_id` remain the same. - public fun split(self: &mut TimelockedStakedSui, split_amount: u64, ctx: &mut TxContext): TimelockedStakedSui { - let splitted_stake = self.staked_sui.split(split_amount, ctx); - - TimelockedStakedSui { - id: object::new(ctx), - staked_sui: splitted_stake, - expiration_timestamp_ms: self.expiration_timestamp_ms, - } - } - - /// Split the given `TimelockedStakedSui` to the two parts, one with principal `split_amount`, - /// transfer the newly split part to the sender address. - public entry fun split_staked_sui(stake: &mut TimelockedStakedSui, split_amount: u64, ctx: &mut TxContext) { - transfer::transfer(split(stake, split_amount, ctx), ctx.sender()); - } - - /// Allows calling `.split_to_sender()` on `TimelockedStakedSui` to invoke `split_staked_sui` - public use fun split_staked_sui as TimelockedStakedSui.split_to_sender; - - /// Consume the staked sui `other` and add its value to `self`. - /// Aborts if some of the staking parameters are incompatible (pool id, stake activation epoch, etc.) - public entry fun join_staked_sui(self: &mut TimelockedStakedSui, other: TimelockedStakedSui) { - assert!(self.is_equal_staking_metadata(&other), EIncompatibleTimelockedStakedSui); - - let TimelockedStakedSui { - id, - staked_sui, - expiration_timestamp_ms: _, - } = other; - - id.delete(); - - self.staked_sui.join(staked_sui); - } - - /// Allows calling `.join()` on `TimelockedStakedSui` to invoke `join_staked_sui` - public use fun join_staked_sui as TimelockedStakedSui.join; - - /// Returns true if all the staking parameters of the staked sui except the principal are identical - public fun is_equal_staking_metadata(self: &TimelockedStakedSui, other: &TimelockedStakedSui): bool { - self.staked_sui.is_equal_staking_metadata(&other.staked_sui) && - (self.expiration_timestamp_ms == other.expiration_timestamp_ms) - } - - /// An utility function to destroy a `TimelockedStakedSui`. - public(package) fun unpack(self: TimelockedStakedSui): (StakedSui, u64) { - let TimelockedStakedSui { - id, - staked_sui, - expiration_timestamp_ms, - } = self; - - object::delete(id); - - (staked_sui, expiration_timestamp_ms) - } - - /// An utility function to transfer a `TimelockedStakedSui`. - public(package) fun transfer(stake: TimelockedStakedSui, recipient: address) { - transfer::transfer(stake, recipient); - } -} diff --git a/crates/sui-framework/packages/timelock/sources/timelocked_staking.move b/crates/sui-framework/packages/timelock/sources/timelocked_staking.move deleted file mode 100644 index df6774f43fe..00000000000 --- a/crates/sui-framework/packages/timelock/sources/timelocked_staking.move +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -module timelock::timelocked_staking { - - use sui::balance::{Self, Balance}; - use sui::sui::SUI; - - use sui_system::sui_system::{SuiSystemState}; - - use timelock::timelock::{Self, TimeLock}; - use timelock::timelocked_staked_sui::{Self, TimelockedStakedSui}; - - /// For when trying to stake an expired time-locked balance. - const ETimeLockShouldNotBeExpired: u64 = 0; - - /// Add a time-locked stake to a validator's staking pool. - public entry fun request_add_stake( - sui_system: &mut SuiSystemState, - timelocked_balance: TimeLock>, - validator_address: address, - ctx: &mut TxContext, - ) { - // Stake the time-locked balance. - let timelocked_staked_sui = request_add_stake_non_entry(sui_system, timelocked_balance, validator_address, ctx); - - // Transfer the receipt to the sender. - timelocked_staked_sui::transfer(timelocked_staked_sui, ctx.sender()); - } - - /// The non-entry version of `request_add_stake`, which returns the time-locked staked SUI instead of transferring it to the sender. - public fun request_add_stake_non_entry( - sui_system: &mut SuiSystemState, - timelocked_balance: TimeLock>, - validator_address: address, - ctx: &mut TxContext, - ) : TimelockedStakedSui { - // Check the preconditions. - assert!(timelocked_balance.is_locked(ctx), ETimeLockShouldNotBeExpired); - - // Unpack the time-locked balance. - let (balance, expiration_timestamp_ms) = timelock::unpack(timelocked_balance); - - // Stake the time-locked balance. - let staked_sui = sui_system.request_add_stake_non_entry( - balance.into_coin(ctx), - validator_address, - ctx, - ); - - // Create and return a receipt. - timelocked_staked_sui::create( - staked_sui, - expiration_timestamp_ms, - ctx - ) - } - - /// Add a time-locked stake to a validator's staking pool using multiple time-locked balances. - public entry fun request_add_stake_mul_bal( - sui_system: &mut SuiSystemState, - timelocked_balances: vector>>, - validator_address: address, - ctx: &mut TxContext, - ) { - // Stake the time-locked balances. - let mut receipts = request_add_stake_mul_bal_non_entry(sui_system, timelocked_balances, validator_address, ctx); - - // Create useful variables. - let (mut i, len) = (0, receipts.length()); - - // Send all the receipts to the sender. - while (i < len) { - // Take a receipt. - let receipt = receipts.pop_back(); - - // Transfer the receipt to the sender. - timelocked_staked_sui::transfer(receipt, ctx.sender()); - - i = i + 1 - }; - - // Destroy the empty vector. - vector::destroy_empty(receipts) - } - - /// The non-entry version of `request_add_stake_mul_bal`, - /// which returns a list of the time-locked staked SUIs instead of transferring them to the sender. - public fun request_add_stake_mul_bal_non_entry( - sui_system: &mut SuiSystemState, - mut timelocked_balances: vector>>, - validator_address: address, - ctx: &mut TxContext, - ) : vector { - // Create a vector to store the results. - let mut result = vector[]; - - // Create useful variables. - let (mut i, len) = (0, timelocked_balances.length()); - - // Stake all the time-locked balances. - while (i < len) { - // Take a time-locked balance. - let timelocked_balance = timelocked_balances.pop_back(); - - // Stake the time-locked balance. - let timelocked_staked_sui = request_add_stake_non_entry(sui_system, timelocked_balance, validator_address, ctx); - - // Store the created receipt. - result.push_back(timelocked_staked_sui); - - i = i + 1 - }; - - // Destroy the empty vector. - vector::destroy_empty(timelocked_balances); - - result - } - - /// Withdraw a time-locked stake from a validator's staking pool. - public entry fun request_withdraw_stake( - sui_system: &mut SuiSystemState, - timelocked_staked_sui: TimelockedStakedSui, - ctx: &mut TxContext, - ) { - // Withdraw the time-locked balance. - let (timelocked_balance, reward) = request_withdraw_stake_non_entry(sui_system, timelocked_staked_sui, ctx); - - // Transfer the withdrawn time-locked balance to the sender. - timelock::transfer(timelocked_balance, ctx.sender()); - - // Send coins only if the reward is not zero. - if (reward.value() > 0) { - transfer::public_transfer(reward.into_coin(ctx), ctx.sender()); - } - else { - balance::destroy_zero(reward); - } - } - - /// Non-entry version of `request_withdraw_stake` that returns the withdrawn time-locked SUI and reward - /// instead of transferring it to the sender. - public fun request_withdraw_stake_non_entry( - sui_system: &mut SuiSystemState, - timelocked_staked_sui: TimelockedStakedSui, - ctx: &mut TxContext, - ) : (TimeLock>, Balance) { - // Unpack the `TimelockedStakedSui` instance. - let (staked_sui, expiration_timestamp_ms) = timelocked_staked_sui.unpack(); - - // Store the original stake amount. - let principal = staked_sui.staked_sui_amount(); - - // Withdraw the balance. - let mut withdraw_stake = sui_system.request_withdraw_stake_non_entry(staked_sui, ctx); - - // The sui_system withdraw functions return a balance that consists of the original staked amount plus the reward amount; - // In here, it splits the original staked balance to timelock it again. - let principal = withdraw_stake.split(principal); - - // Pack and return a time-locked balance, and the reward. - (timelock::pack(principal, expiration_timestamp_ms, ctx), withdraw_stake) - } -} diff --git a/crates/sui-framework/packages/timelock/tests/timelock_tests.move b/crates/sui-framework/packages/timelock/tests/timelock_tests.move deleted file mode 100644 index f46e26b7a36..00000000000 --- a/crates/sui-framework/packages/timelock/tests/timelock_tests.move +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -#[test_only] -module timelock::timelock_tests { - - use sui::balance; - use sui::sui::SUI; - use sui::test_scenario; - - use timelock::timelock; - - #[test] - fun test_lock_unlock_flow() { - // Set up a test environment. - let sender = @0xA; - let mut scenario = test_scenario::begin(sender); - - // Minting some IOTA. - let iota = balance::create_for_testing(10); - - // Lock the IOTA balance. - let timelock = timelock::lock(iota, 100, scenario.ctx()); - - // Check the locked IOTA. - assert!(timelock.locked().value() == 10, 0); - - // Check if the timelock is locked. - assert!(timelock.is_locked(scenario.ctx()), 1); - assert!(timelock.remaining_time(scenario.ctx()) == 100, 2); - - // Increment epoch timestamp. - scenario.ctx().increment_epoch_timestamp(10); - - // Check if the timelock is still locked. - assert!(timelock.is_locked(scenario.ctx()), 3); - assert!(timelock.remaining_time(scenario.ctx()) == 90, 4); - - // Increment epoch timestamp again. - scenario.ctx().increment_epoch_timestamp(90); - - // Check if the timelock is unlocked. - assert!(!timelock.is_locked(scenario.ctx()), 5); - assert!(timelock.remaining_time(scenario.ctx()) == 0, 6); - - // Unlock the IOTA balance. - let balance = timelock::unlock(timelock, scenario.ctx()); - - // Check the unlocked IOTA balance. - assert!(balance.value() == 10, 7); - - // Cleanup. - balance::destroy_for_testing(balance); - - scenario.end(); - } - - #[test] - #[expected_failure(abort_code = timelock::EExpireEpochIsPast)] - fun test_expiration_time_is_passed() { - // Set up a test environment. - let sender = @0xA; - let mut scenario = test_scenario::begin(sender); - - // Increment epoch timestamp. - scenario.ctx().increment_epoch_timestamp(100); - - // Minting some IOTA. - let iota = balance::create_for_testing(10); - - // Lock the IOTA balance with a wrong expiration time. - let timelock = timelock::lock(iota, 10, scenario.ctx()); - - // Cleanup. - let (balance, _) = timelock::unpack(timelock); - - balance::destroy_for_testing(balance); - - scenario.end(); - } - - #[test] - #[expected_failure(abort_code = timelock::ENotExpiredYet)] - fun test_unlock_not_expired_object() { - // Set up a test environment. - let sender = @0xA; - let mut scenario = test_scenario::begin(sender); - - // Minting some IOTA. - let iota = balance::create_for_testing(10); - - // Lock the IOTA balance. - let timelock = timelock::lock(iota, 100, scenario.ctx()); - - // Increment epoch timestamp. - scenario.ctx().increment_epoch_timestamp(10); - - // Unlock the IOTA balance which is not expired. - let balance = timelock::unlock(timelock, scenario.ctx()); - - // Cleanup. - balance::destroy_for_testing(balance); - - scenario.end(); - } -} diff --git a/crates/sui-framework/packages/timelock/tests/timelocked_balance_tests.move b/crates/sui-framework/packages/timelock/tests/timelocked_balance_tests.move deleted file mode 100644 index ff2b39dc350..00000000000 --- a/crates/sui-framework/packages/timelock/tests/timelocked_balance_tests.move +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -#[test_only] -module timelock::timelocked_balance_tests { - - use sui::balance; - use sui::sui::SUI; - use sui::test_scenario; - - use timelock::timelock; - use timelock::timelocked_balance; - - #[test] - fun test_join_timelocked_balances() { - // Set up a test environment. - let sender = @0xA; - let mut scenario = test_scenario::begin(sender); - - // Minting some IOTA. - let iota1 = balance::create_for_testing(10); - let iota2 = balance::create_for_testing(15); - - // Lock the IOTA balances. - let mut timelock1 = timelock::lock(iota1, 100, scenario.ctx()); - let timelock2 = timelock::lock(iota2, 100, scenario.ctx()); - - // Join the timelocks. - timelocked_balance::join(&mut timelock1, timelock2); - - // Check the joined timelock. - assert!(timelock1.expiration_timestamp_ms() == 100, 1); - assert!(timelock1.locked().value() == 25, 2); - - // Cleanup. - let (balance, _) = timelock::unpack(timelock1); - - balance::destroy_for_testing(balance); - - scenario.end(); - } - - #[test] - #[expected_failure(abort_code = timelocked_balance::EDifferentExpirationTime)] - fun test_join_timelocked_balances_with_different_exp_time() { - // Set up a test environment. - let sender = @0xA; - let mut scenario = test_scenario::begin(sender); - - // Minting some IOTA. - let iota1 = balance::create_for_testing(10); - let iota2 = balance::create_for_testing(15); - - // Lock the IOTA balances. - let mut timelock1 = timelock::lock(iota1, 100, scenario.ctx()); - let timelock2 = timelock::lock(iota2, 200, scenario.ctx()); - - // Join the timelocks. - timelocked_balance::join(&mut timelock1, timelock2); - - // Cleanup. - let (balance, _) = timelock::unpack(timelock1); - - balance::destroy_for_testing(balance); - - scenario.end(); - } - - #[test] - fun test_join_vec_timelocked_balances() { - // Set up a test environment. - let sender = @0xA; - let mut scenario = test_scenario::begin(sender); - - // Minting some IOTA. - let iota1 = balance::create_for_testing(10); - let iota2 = balance::create_for_testing(15); - let iota3 = balance::create_for_testing(20); - let iota4 = balance::create_for_testing(25); - - // Lock the IOTA balances. - let mut timelock1 = timelock::lock(iota1, 100, scenario.ctx()); - - let mut others = vector[]; - - others.push_back(timelock::lock(iota2, 100, scenario.ctx())); - others.push_back(timelock::lock(iota3, 100, scenario.ctx())); - others.push_back(timelock::lock(iota4, 100, scenario.ctx())); - - // Join the timelocks. - timelocked_balance::join_vec(&mut timelock1, others); - - // Check the joined timelock. - assert!(timelock1.expiration_timestamp_ms() == 100, 1); - assert!(timelock1.locked().value() == 70, 2); - - // Cleanup. - let (balance, _) = timelock::unpack(timelock1); - - balance::destroy_for_testing(balance); - - scenario.end(); - } - - #[test] - fun test_join_empty_vec_timelocked_balances() { - // Set up a test environment. - let sender = @0xA; - let mut scenario = test_scenario::begin(sender); - - // Minting some IOTA. - let iota = balance::create_for_testing(10); - - // Lock the IOTA balance. - let mut timelock = timelock::lock(iota, 100, scenario.ctx()); - let others = vector[]; - - // Join the timelocks. - timelocked_balance::join_vec(&mut timelock, others); - - // Check the joined timelock. - assert!(timelock.expiration_timestamp_ms() == 100, 1); - assert!(timelock.locked().value() == 10, 2); - - // Cleanup. - let (balance, _) = timelock::unpack(timelock); - - balance::destroy_for_testing(balance); - - scenario.end(); - } - - #[test] - #[expected_failure(abort_code = timelocked_balance::EDifferentExpirationTime)] - fun test_join_vec_timelocked_balances_with_different_exp_time() { - // Set up a test environment. - let sender = @0xA; - let mut scenario = test_scenario::begin(sender); - - // Minting some IOTA. - let iota1 = balance::create_for_testing(10); - let iota2 = balance::create_for_testing(15); - let iota3 = balance::create_for_testing(20); - let iota4 = balance::create_for_testing(25); - - // Lock the IOTA balances. - let mut timelock1 = timelock::lock(iota1, 100, scenario.ctx()); - - let mut others = vector[]; - - others.push_back(timelock::lock(iota2, 100, scenario.ctx())); - others.push_back(timelock::lock(iota3, 200, scenario.ctx())); - others.push_back(timelock::lock(iota4, 100, scenario.ctx())); - - // Join the timelocks. - timelocked_balance::join_vec(&mut timelock1, others); - - // Cleanup. - let (balance, _) = timelock::unpack(timelock1); - - balance::destroy_for_testing(balance); - - scenario.end(); - } - - #[test] - fun test_split_timelocked_balances() { - // Set up a test environment. - let sender = @0xA; - let mut scenario = test_scenario::begin(sender); - - // Minting some IOTA. - let iota = balance::create_for_testing(10); - - // Lock the IOTA balance. - let mut original = timelock::lock(iota, 100, scenario.ctx()); - - // Split the timelock. - let splitted = timelocked_balance::split(&mut original, 3, scenario.ctx()); - - // Check the original timelock. - assert!(original.expiration_timestamp_ms() == 100, 1); - assert!(original.locked().value() == 7, 2); - - // Check the splitted timelock. - assert!(splitted.expiration_timestamp_ms() == 100, 3); - assert!(splitted.locked().value() == 3, 4); - - // Cleanup. - let (balance, _) = timelock::unpack(original); - balance::destroy_for_testing(balance); - - let (balance, _) = timelock::unpack(splitted); - balance::destroy_for_testing(balance); - - scenario.end(); - } - - #[test] - fun test_split_zero_value_from_timelocked_balances() { - // Set up a test environment. - let sender = @0xA; - let mut scenario = test_scenario::begin(sender); - - // Minting some IOTA. - let iota = balance::create_for_testing(10); - - // Lock the IOTA balance. - let mut original = timelock::lock(iota, 100, scenario.ctx()); - - // Split the timelock. - let splitted = timelocked_balance::split(&mut original, 0, scenario.ctx()); - - // Check the original timelock. - assert!(original.expiration_timestamp_ms() == 100, 1); - assert!(original.locked().value() == 10, 2); - - // Check the splitted timelock. - assert!(splitted.expiration_timestamp_ms() == 100, 3); - assert!(splitted.locked().value() == 0, 4); - - // Cleanup. - let (balance, _) = timelock::unpack(original); - balance::destroy_for_testing(balance); - - let (balance, _) = timelock::unpack(splitted); - balance::destroy_for_testing(balance); - - scenario.end(); - } - - #[test] - fun test_split_same_value_from_timelocked_balances() { - // Set up a test environment. - let sender = @0xA; - let mut scenario = test_scenario::begin(sender); - - // Minting some IOTA. - let iota = balance::create_for_testing(10); - - // Lock the IOTA balance. - let mut original = timelock::lock(iota, 100, scenario.ctx()); - - // Split the timelock. - let splitted = timelocked_balance::split(&mut original, 10, scenario.ctx()); - - // Check the original timelock. - assert!(original.expiration_timestamp_ms() == 100, 0); - assert!(original.locked().value() == 0, 1); - - // Check the splitted timelock. - assert!(splitted.expiration_timestamp_ms() == 100, 2); - assert!(splitted.locked().value() == 10, 3); - - // Cleanup. - let (balance, _) = timelock::unpack(original); - balance::destroy_for_testing(balance); - - let (balance, _) = timelock::unpack(splitted); - balance::destroy_for_testing(balance); - - scenario.end(); - } - - #[test] - #[expected_failure(abort_code = balance::ENotEnough)] - fun test_split_bigger_value_from_timelocked_balances() { - // Set up a test environment. - let sender = @0xA; - let mut scenario = test_scenario::begin(sender); - - // Minting some IOTA. - let iota = balance::create_for_testing(10); - - // Lock the IOTA balance. - let mut original = timelock::lock(iota, 100, scenario.ctx()); - - // Split the timelock. - let splitted = timelocked_balance::split(&mut original, 11, scenario.ctx()); - - // Cleanup. - let (balance, _) = timelock::unpack(original); - balance::destroy_for_testing(balance); - - let (balance, _) = timelock::unpack(splitted); - balance::destroy_for_testing(balance); - - scenario.end(); - } -} diff --git a/crates/sui-framework/packages/timelock/tests/timelocked_delegation_tests.move b/crates/sui-framework/packages/timelock/tests/timelocked_delegation_tests.move deleted file mode 100644 index c505e3ea49b..00000000000 --- a/crates/sui-framework/packages/timelock/tests/timelocked_delegation_tests.move +++ /dev/null @@ -1,821 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -#[test_only] -module timelock::timelocked_stake_tests { - use sui::balance; - use sui::balance::Balance; - use sui::coin::Coin; - use sui::sui::SUI; - use sui::table::Table; - use sui::test_scenario::{Self, Scenario}; - use sui::test_utils::assert_eq; - use sui::test_utils; - - use sui_system::sui_system::SuiSystemState; - use sui_system::staking_pool::{Self, PoolTokenExchangeRate}; - use sui_system::validator_set::{Self, ValidatorSet}; - use sui_system::governance_test_utils::{ - add_validator, - add_validator_candidate, - advance_epoch, - advance_epoch_with_reward_amounts, - assert_validator_total_stake_amounts, - create_validator_for_testing, - create_sui_system_state_for_testing, - remove_validator, - remove_validator_candidate, - total_sui_balance, - unstake, - }; - - use timelock::timelock::{Self, TimeLock}; - use timelock::timelocked_staked_sui::{Self, TimelockedStakedSui}; - use timelock::timelocked_staking; - - const VALIDATOR_ADDR_1: address = @0x1; - const VALIDATOR_ADDR_2: address = @0x2; - - const STAKER_ADDR_1: address = @0x42; - const STAKER_ADDR_2: address = @0x43; - const STAKER_ADDR_3: address = @0x44; - - const NEW_VALIDATOR_ADDR: address = @0x1a4623343cd42be47d67314fce0ad042f3c82685544bc91d8c11d24e74ba7357; - // Generated with seed [0;32] - const NEW_VALIDATOR_PUBKEY: vector = x"99f25ef61f8032b914636460982c5cc6f134ef1ddae76657f2cbfec1ebfc8d097374080df6fcf0dcb8bc4b0d8e0af5d80ebbff2b4c599f54f42d6312dfc314276078c1cc347ebbbec5198be258513f386b930d02c2749a803e2330955ebd1a10"; - // Generated using [fn test_proof_of_possession] - const NEW_VALIDATOR_POP: vector = x"8b93fc1b33379e2796d361c4056f0f04ad5aea7f4a8c02eaac57340ff09b6dc158eb1945eece103319167f420daf0cb3"; - - const MIST_PER_SUI: u64 = 1_000_000_000; - - #[test] - fun test_split_join_staked_sui() { - // All this is just to generate a dummy StakedSui object to split and join later - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); - let scenario = &mut scenario_val; - stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 10, scenario); - - scenario.next_tx(STAKER_ADDR_1); - { - let mut staked_sui = scenario.take_from_sender(); - let ctx = scenario.ctx(); - staked_sui.split_to_sender(20 * MIST_PER_SUI, ctx); - scenario.return_to_sender(staked_sui); - }; - - // Verify the correctness of the split and send the join txn - scenario.next_tx(STAKER_ADDR_1); - { - let staked_sui_ids = scenario.ids_for_sender(); - assert!(staked_sui_ids.length() == 2, 101); // staked sui split to 2 coins - - let mut part1 = scenario.take_from_sender_by_id(staked_sui_ids[0]); - let part2 = scenario.take_from_sender_by_id(staked_sui_ids[1]); - - let amount1 = part1.amount(); - let amount2 = part2.amount(); - assert!(amount1 == 20 * MIST_PER_SUI || amount1 == 40 * MIST_PER_SUI, 102); - assert!(amount2 == 20 * MIST_PER_SUI || amount2 == 40 * MIST_PER_SUI, 103); - assert!(amount1 + amount2 == 60 * MIST_PER_SUI, 104); - - part1.join(part2); - assert!(part1.amount() == 60 * MIST_PER_SUI, 105); - scenario.return_to_sender(part1); - }; - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = timelocked_staked_sui::EIncompatibleTimelockedStakedSui)] - fun test_join_different_epochs() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); - let scenario = &mut scenario_val; - // Create two instances of staked sui w/ different epoch activations - stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 10, scenario); - advance_epoch(scenario); - stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 10, scenario); - - // Verify that these cannot be merged - scenario.next_tx(STAKER_ADDR_1); - { - let staked_sui_ids = scenario.ids_for_sender(); - let mut part1 = scenario.take_from_sender_by_id(staked_sui_ids[0]); - let part2 = scenario.take_from_sender_by_id(staked_sui_ids[1]); - - part1.join(part2); - - scenario.return_to_sender(part1); - }; - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = timelocked_staked_sui::EIncompatibleTimelockedStakedSui)] - fun test_join_different_timestamps() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); - let scenario = &mut scenario_val; - // Create two instances of staked sui w/ different epoch activations - stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 10, scenario); - advance_epoch(scenario); - stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 20, scenario); - - // Verify that these cannot be merged - scenario.next_tx(STAKER_ADDR_1); - { - let staked_sui_ids = scenario.ids_for_sender(); - let mut part1 = scenario.take_from_sender_by_id(staked_sui_ids[0]); - let part2 = scenario.take_from_sender_by_id(staked_sui_ids[1]); - - part1.join(part2); - - scenario.return_to_sender(part1); - }; - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = staking_pool::EStakedSuiBelowThreshold)] - fun test_split_below_threshold() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); - let scenario = &mut scenario_val; - // Stake 2 SUI - stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 2, 10, scenario); - - scenario.next_tx(STAKER_ADDR_1); - { - let mut staked_sui = scenario.take_from_sender(); - let ctx = scenario.ctx(); - // The remaining amount after splitting is below the threshold so this should fail. - staked_sui.split_to_sender(1 * MIST_PER_SUI + 1, ctx); - scenario.return_to_sender(staked_sui); - }; - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = staking_pool::EStakedSuiBelowThreshold)] - fun test_split_nonentry_below_threshold() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(STAKER_ADDR_1); - let scenario = &mut scenario_val; - // Stake 2 SUI - stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 2, 10, scenario); - - scenario.next_tx(STAKER_ADDR_1); - { - let mut staked_sui = scenario.take_from_sender(); - let ctx = scenario.ctx(); - // The remaining amount after splitting is below the threshold so this should fail. - let stake = staked_sui.split(1 * MIST_PER_SUI + 1, ctx); - test_utils::destroy(stake); - scenario.return_to_sender(staked_sui); - }; - scenario_val.end(); - } - - #[test] - fun test_add_remove_stake_flow() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - scenario.next_tx(STAKER_ADDR_1); - { - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - let ctx = scenario.ctx(); - - // Create a stake to VALIDATOR_ADDR_1. - timelocked_staking::request_add_stake( - system_state_mut_ref, - timelock::lock(balance::create_for_testing(60 * MIST_PER_SUI), 10, ctx), - VALIDATOR_ADDR_1, - ctx - ); - - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 100 * MIST_PER_SUI); - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2), 100 * MIST_PER_SUI); - - test_scenario::return_shared(system_state); - }; - - advance_epoch(scenario); - - scenario.next_tx(STAKER_ADDR_1); - { - let staked_sui = scenario.take_from_sender(); - assert_eq(staked_sui.amount(), 60 * MIST_PER_SUI); - - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 160 * MIST_PER_SUI); - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2), 100 * MIST_PER_SUI); - - let ctx = scenario.ctx(); - - // Unstake from VALIDATOR_ADDR_1 - timelocked_staking::request_withdraw_stake(system_state_mut_ref, staked_sui, ctx); - - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 160 * MIST_PER_SUI); - test_scenario::return_shared(system_state); - }; - - advance_epoch(scenario); - - scenario.next_tx(STAKER_ADDR_1); - { - let mut system_state = scenario.take_shared(); - assert_eq(system_state.validator_stake_amount(VALIDATOR_ADDR_1), 100 * MIST_PER_SUI); - test_scenario::return_shared(system_state); - }; - scenario_val.end(); - } - - #[test] - fun test_add_remove_stake_mul_bal_flow() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - scenario.next_tx(STAKER_ADDR_1); - { - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - let ctx = scenario.ctx(); - - let mut balances = vector[]; - - balances.push_back(timelock::lock(balance::create_for_testing(30 * MIST_PER_SUI), 10, ctx)); - balances.push_back(timelock::lock(balance::create_for_testing(60 * MIST_PER_SUI), 20, ctx)); - - // Create a stake to VALIDATOR_ADDR_1. - timelocked_staking::request_add_stake_mul_bal( - system_state_mut_ref, - balances, - VALIDATOR_ADDR_1, - ctx - ); - - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 100 * MIST_PER_SUI); - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2), 100 * MIST_PER_SUI); - - test_scenario::return_shared(system_state); - }; - - advance_epoch(scenario); - - scenario.next_tx(STAKER_ADDR_1); - { - let stake_sui_ids = scenario.ids_for_sender(); - - let staked_sui1 = scenario.take_from_sender_by_id(stake_sui_ids[0]); - assert_eq(staked_sui1.amount(), 30 * MIST_PER_SUI); - let staked_sui2 = scenario.take_from_sender_by_id(stake_sui_ids[1]); - assert_eq(staked_sui2.amount(), 60 * MIST_PER_SUI); - - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 190 * MIST_PER_SUI); - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2), 100 * MIST_PER_SUI); - - let ctx = scenario.ctx(); - - // First unstake from VALIDATOR_ADDR_1 - timelocked_staking::request_withdraw_stake(system_state_mut_ref, staked_sui1, ctx); - - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 190 * MIST_PER_SUI); - - scenario.return_to_sender(staked_sui2); - test_scenario::return_shared(system_state); - }; - - advance_epoch(scenario); - - scenario.next_tx(STAKER_ADDR_1); - { - let staked_sui = scenario.take_from_sender(); - assert_eq(staked_sui.amount(), 60 * MIST_PER_SUI); - - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 160 * MIST_PER_SUI); - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2), 100 * MIST_PER_SUI); - - let ctx = scenario.ctx(); - - // Second unstake from VALIDATOR_ADDR_1 - timelocked_staking::request_withdraw_stake(system_state_mut_ref, staked_sui, ctx); - - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 160 * MIST_PER_SUI); - test_scenario::return_shared(system_state); - }; - - advance_epoch(scenario); - - scenario.next_tx(STAKER_ADDR_1); - { - assert_eq(scenario.has_most_recent_for_sender(), false); - - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_1), 100 * MIST_PER_SUI); - assert_eq(system_state_mut_ref.validator_stake_amount(VALIDATOR_ADDR_2), 100 * MIST_PER_SUI); - - test_scenario::return_shared(system_state); - }; - - scenario_val.end(); - } - - #[test] - fun test_remove_stake_post_active_flow_no_rewards() { - set_up_sui_system_state_with_storage_fund(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, 10, scenario); - - advance_epoch(scenario); - - assert_validator_total_stake_amounts( - vector[VALIDATOR_ADDR_1, VALIDATOR_ADDR_2], - vector[200 * MIST_PER_SUI, 100 * MIST_PER_SUI], - scenario - ); - - advance_epoch(scenario); - - remove_validator(VALIDATOR_ADDR_1, scenario); - - advance_epoch(scenario); - - // Make sure stake withdrawal happens - scenario.next_tx(STAKER_ADDR_1); - { - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - assert!(!is_active_validator_by_sui_address(system_state_mut_ref.validators(), VALIDATOR_ADDR_1), 0); - - let staked_sui = scenario.take_from_sender(); - assert_eq(staked_sui.amount(), 100 * MIST_PER_SUI); - - // Unstake from VALIDATOR_ADDR_1 - assert!(!has_sui_coins(STAKER_ADDR_1, scenario), 1); - let ctx = scenario.ctx(); - timelocked_staking::request_withdraw_stake(system_state_mut_ref, staked_sui, ctx); - - // Make sure they have all of their stake. - assert_eq(total_timelocked_sui_balance(STAKER_ADDR_1, scenario), 100 * MIST_PER_SUI); - assert!(!has_sui_coins(STAKER_ADDR_1, scenario), 2); - - test_scenario::return_shared(system_state); - }; - - // Validator unstakes now. - assert!(!has_sui_coins(VALIDATOR_ADDR_1, scenario), 3); - unstake(VALIDATOR_ADDR_1, 0, scenario); - - // Make sure have all of their stake. NB there is no epoch change. This is immediate. - assert_eq(total_sui_balance(VALIDATOR_ADDR_1, scenario), 100 * MIST_PER_SUI); - - scenario_val.end(); - } - - #[test] - fun test_remove_stake_post_active_flow_with_rewards() { - set_up_sui_system_state_with_storage_fund(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, 10, scenario); - - advance_epoch(scenario); - - assert_validator_total_stake_amounts( - vector[VALIDATOR_ADDR_1, VALIDATOR_ADDR_2], - vector[200 * MIST_PER_SUI, 100 * MIST_PER_SUI], - scenario - ); - - // Each validator pool gets 30 MIST and each validator gets an additional 10 MIST. - advance_epoch_with_reward_amounts(0, 80, scenario); - - remove_validator(VALIDATOR_ADDR_1, scenario); - - advance_epoch(scenario); - - let reward_amt = 15 * MIST_PER_SUI; - let validator_reward_amt = 10 * MIST_PER_SUI; - - // Make sure stake withdrawal happens - scenario.next_tx(STAKER_ADDR_1); - { - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - assert!(!is_active_validator_by_sui_address(system_state_mut_ref.validators(), VALIDATOR_ADDR_1), 0); - - let staked_sui = scenario.take_from_sender(); - assert_eq(staked_sui.amount(), 100 * MIST_PER_SUI); - - // Unstake from VALIDATOR_ADDR_1 - assert!(!has_sui_coins(STAKER_ADDR_1, scenario), 1); - let ctx = scenario.ctx(); - timelocked_staking::request_withdraw_stake(system_state_mut_ref, staked_sui, ctx); - - // Make sure they have all of their stake. - assert_eq(total_timelocked_sui_balance(STAKER_ADDR_1, scenario), 100 * MIST_PER_SUI); - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), reward_amt); - - test_scenario::return_shared(system_state); - }; - - // Validator unstakes now. - assert!(!has_sui_coins(VALIDATOR_ADDR_1, scenario), 2); - unstake(VALIDATOR_ADDR_1, 0, scenario); - unstake(VALIDATOR_ADDR_1, 0, scenario); - - // Make sure have all of their stake. NB there is no epoch change. This is immediate. - assert_eq(total_sui_balance(VALIDATOR_ADDR_1, scenario), 100 * MIST_PER_SUI + reward_amt + validator_reward_amt); - - scenario_val.end(); - } - - #[test] - fun test_earns_rewards_at_last_epoch() { - set_up_sui_system_state_with_storage_fund(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, 10, scenario); - - advance_epoch(scenario); - - remove_validator(VALIDATOR_ADDR_1, scenario); - - // Add some rewards after the validator requests to leave. Since the validator is still active - // this epoch, they should get the rewards from this epoch. - advance_epoch_with_reward_amounts(0, 80, scenario); - - // Each validator pool gets 30 MIST and validators shares the 20 MIST from the storage fund - // so validator gets another 10 MIST. - let reward_amt = 15 * MIST_PER_SUI; - let validator_reward_amt = 10 * MIST_PER_SUI; - - // Make sure stake withdrawal happens - scenario.next_tx(STAKER_ADDR_1); - { - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - let staked_sui = scenario.take_from_sender(); - assert_eq(staked_sui.amount(), 100 * MIST_PER_SUI); - - // Unstake from VALIDATOR_ADDR_1 - assert!(!has_timelocked_sui_balance(STAKER_ADDR_1, scenario), 0); - assert!(!has_sui_coins(STAKER_ADDR_1, scenario), 1); - let ctx = scenario.ctx(); - timelocked_staking::request_withdraw_stake(system_state_mut_ref, staked_sui, ctx); - - // Make sure they have all of their stake. - assert_eq(total_timelocked_sui_balance(STAKER_ADDR_1, scenario), 100 * MIST_PER_SUI); - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), reward_amt); - - test_scenario::return_shared(system_state); - }; - - // Validator unstakes now. - assert!(!has_sui_coins(VALIDATOR_ADDR_1, scenario), 2); - unstake(VALIDATOR_ADDR_1, 0, scenario); - unstake(VALIDATOR_ADDR_1, 0, scenario); - - // Make sure have all of their stake. NB there is no epoch change. This is immediate. - assert_eq(total_sui_balance(VALIDATOR_ADDR_1, scenario), 100 * MIST_PER_SUI + reward_amt + validator_reward_amt); - - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = validator_set::ENotAValidator)] - fun test_add_stake_post_active_flow() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, 10, scenario); - - advance_epoch(scenario); - - remove_validator(VALIDATOR_ADDR_1, scenario); - - advance_epoch(scenario); - - // Make sure the validator is no longer active. - scenario.next_tx(STAKER_ADDR_1); - { - let mut system_state = scenario.take_shared(); - let system_state_mut_ref = &mut system_state; - - assert!(!is_active_validator_by_sui_address(system_state_mut_ref.validators(), VALIDATOR_ADDR_1), 0); - - test_scenario::return_shared(system_state); - }; - - // Now try and stake to the old validator/staking pool. This should fail! - stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 60, 10, scenario); - - scenario_val.end(); - } - - #[test] - fun test_add_preactive_remove_preactive() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - add_validator_candidate(NEW_VALIDATOR_ADDR, b"name5", b"/ip4/127.0.0.1/udp/85", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); - - // Delegate 100 MIST to the preactive validator - stake_timelocked_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, 10, scenario); - - // Advance epoch twice with some rewards - advance_epoch_with_reward_amounts(0, 400, scenario); - advance_epoch_with_reward_amounts(0, 900, scenario); - - // Unstake from the preactive validator. There should be no rewards earned. - unstake_timelocked(STAKER_ADDR_1, 0, scenario); - assert!(!has_sui_coins(STAKER_ADDR_1, scenario), 0); - assert_eq(total_timelocked_sui_balance(STAKER_ADDR_1, scenario), 100 * MIST_PER_SUI); - - scenario_val.end(); - } - - #[test] - #[expected_failure(abort_code = validator_set::ENotAValidator)] - fun test_add_preactive_remove_pending_failure() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - add_validator_candidate(NEW_VALIDATOR_ADDR, b"name4", b"/ip4/127.0.0.1/udp/84", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); - - add_validator(NEW_VALIDATOR_ADDR, scenario); - - // Delegate 100 SUI to the pending validator. This should fail because pending active validators don't accept - // new stakes or withdraws. - stake_timelocked_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, 10, scenario); - - scenario_val.end(); - } - - #[test] - fun test_add_preactive_remove_active() { - set_up_sui_system_state_with_storage_fund(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - add_validator_candidate(NEW_VALIDATOR_ADDR, b"name3", b"/ip4/127.0.0.1/udp/83", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); - - // Delegate 100 SUI to the preactive validator - stake_timelocked_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, 10, scenario); - advance_epoch_with_reward_amounts(0, 300, scenario); - // At this point we got the following distribution of stake: - // V1: 250, V2: 250, storage fund: 100 - - stake_timelocked_with(STAKER_ADDR_2, NEW_VALIDATOR_ADDR, 50, 10, scenario); - stake_timelocked_with(STAKER_ADDR_3, NEW_VALIDATOR_ADDR, 100, 10, scenario); - - // Now the preactive becomes active - add_validator(NEW_VALIDATOR_ADDR, scenario); - advance_epoch(scenario); - - // At this point we got the following distribution of stake: - // V1: 250, V2: 250, V3: 250, storage fund: 100 - - advance_epoch_with_reward_amounts(0, 85, scenario); - - // staker 1 and 3 unstake from the validator and earns about 2/5 * (85 - 10) * 1/3 = 10 SUI each. - // Although they stake in different epochs, they earn the same rewards as long as they unstake - // in the same epoch because the validator was preactive when they staked. - // So they will both get slightly more than 110 SUI in total balance. - unstake_timelocked(STAKER_ADDR_1, 0, scenario); - assert_eq(total_timelocked_sui_balance(STAKER_ADDR_1, scenario), 100 * MIST_PER_SUI); - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), 10_002_000_000); - - unstake_timelocked(STAKER_ADDR_3, 0, scenario); - assert_eq(total_timelocked_sui_balance(STAKER_ADDR_3, scenario), 100 * MIST_PER_SUI); - assert_eq(total_sui_balance(STAKER_ADDR_3, scenario), 10_002_000_000); - - advance_epoch_with_reward_amounts(0, 85, scenario); - - unstake_timelocked(STAKER_ADDR_2, 0, scenario); - // staker 2 earns about 5 SUI from the previous epoch and 24-ish from this one - // so in total she has about 50 + 5 + 24 = 79 SUI. - assert_eq(total_timelocked_sui_balance(STAKER_ADDR_2, scenario), 50 * MIST_PER_SUI); - assert_eq(total_sui_balance(STAKER_ADDR_2, scenario), 28_862_939_078); - - scenario_val.end(); - } - - #[test] - fun test_add_preactive_remove_post_active() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - add_validator_candidate(NEW_VALIDATOR_ADDR, b"name1", b"/ip4/127.0.0.1/udp/81", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); - - // Delegate 100 SUI to the preactive validator - stake_timelocked_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, 10, scenario); - - // Now the preactive becomes active - add_validator(NEW_VALIDATOR_ADDR, scenario); - advance_epoch(scenario); - - // staker 1 earns a bit greater than 30 SUI here. A bit greater because the new validator's voting power - // is slightly greater than 1/3 of the total voting power. - advance_epoch_with_reward_amounts(0, 90, scenario); - - // And now the validator leaves the validator set. - remove_validator(NEW_VALIDATOR_ADDR, scenario); - - advance_epoch(scenario); - - unstake_timelocked(STAKER_ADDR_1, 0, scenario); - assert_eq(total_timelocked_sui_balance(STAKER_ADDR_1, scenario), 100 * MIST_PER_SUI); - assert_eq(total_sui_balance(STAKER_ADDR_1, scenario), 30_006_000_000); - - scenario_val.end(); - } - - #[test] - fun test_add_preactive_candidate_drop_out() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); - let scenario = &mut scenario_val; - - add_validator_candidate(NEW_VALIDATOR_ADDR, b"name2", b"/ip4/127.0.0.1/udp/82", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario); - - // Delegate 100 MIST to the preactive validator - stake_timelocked_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, 10, scenario); - - // Advance epoch and give out some rewards. The candidate should get nothing, of course. - advance_epoch_with_reward_amounts(0, 800, scenario); - - // Now the candidate leaves. - remove_validator_candidate(NEW_VALIDATOR_ADDR, scenario); - - // Advance epoch a few times. - advance_epoch(scenario); - advance_epoch(scenario); - advance_epoch(scenario); - - // Unstake now and the staker should get no rewards. - unstake_timelocked(STAKER_ADDR_1, 0, scenario); - assert_eq(total_timelocked_sui_balance(STAKER_ADDR_1, scenario), 100 * MIST_PER_SUI); - assert!(!has_sui_coins(STAKER_ADDR_1, scenario), 0); - - scenario_val.end(); - } - - #[test] - fun test_staking_pool_exchange_rate_getter() { - set_up_sui_system_state(); - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - stake_timelocked_with(@0x42, @0x2, 100, 10, scenario); // stakes 100 SUI with 0x2 - scenario.next_tx(@0x42); - let staked_sui = scenario.take_from_address(@0x42); - let pool_id = staked_sui.pool_id(); - test_scenario::return_to_address(@0x42, staked_sui); - advance_epoch(scenario); // advances epoch to effectuate the stake - // Each staking pool gets 10 SUI of rewards. - advance_epoch_with_reward_amounts(0, 20, scenario); - let mut system_state = scenario.take_shared(); - let rates = system_state.pool_exchange_rates(&pool_id); - assert_eq(rates.length(), 3); - assert_exchange_rate_eq(rates, 0, 0, 0); // no tokens at epoch 0 - assert_exchange_rate_eq(rates, 1, 200, 200); // 200 SUI of self + delegate stake at epoch 1 - assert_exchange_rate_eq(rates, 2, 210, 200); // 10 SUI of rewards at epoch 2 - test_scenario::return_shared(system_state); - scenario_val.end(); - } - - fun assert_exchange_rate_eq( - rates: &Table, epoch: u64, sui_amount: u64, pool_token_amount: u64 - ) { - let rate = &rates[epoch]; - assert_eq(rate.sui_amount(), sui_amount * MIST_PER_SUI); - assert_eq(rate.pool_token_amount(), pool_token_amount * MIST_PER_SUI); - } - - fun set_up_sui_system_state() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - let ctx = scenario.ctx(); - - let validators = vector[ - create_validator_for_testing(VALIDATOR_ADDR_1, 100, ctx), - create_validator_for_testing(VALIDATOR_ADDR_2, 100, ctx) - ]; - create_sui_system_state_for_testing(validators, 0, 0, ctx); - scenario_val.end(); - } - - fun set_up_sui_system_state_with_storage_fund() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - let ctx = scenario.ctx(); - - let validators = vector[ - create_validator_for_testing(VALIDATOR_ADDR_1, 100, ctx), - create_validator_for_testing(VALIDATOR_ADDR_2, 100, ctx) - ]; - create_sui_system_state_for_testing(validators, 300, 100, ctx); - scenario_val.end(); - } - - fun stake_timelocked_with( - staker: address, - validator: address, - amount: u64, - expiration_timestamp_ms: u64, - scenario: &mut Scenario - ) { - scenario.next_tx(staker); - let mut system_state = scenario.take_shared(); - - let ctx = scenario.ctx(); - - timelocked_staking::request_add_stake( - &mut system_state, - timelock::lock(balance::create_for_testing(amount * MIST_PER_SUI), expiration_timestamp_ms, ctx), - validator, - ctx); - test_scenario::return_shared(system_state); - } - - fun unstake_timelocked( - staker: address, staked_sui_idx: u64, scenario: &mut Scenario - ) { - scenario.next_tx(staker); - let stake_sui_ids = scenario.ids_for_sender(); - let staked_sui = scenario.take_from_sender_by_id(stake_sui_ids[staked_sui_idx]); - let mut system_state = scenario.take_shared(); - - let ctx = scenario.ctx(); - timelocked_staking::request_withdraw_stake(&mut system_state, staked_sui, ctx); - test_scenario::return_shared(system_state); - } - - - fun total_timelocked_sui_balance(addr: address, scenario: &mut Scenario): u64 { - let mut sum = 0; - scenario.next_tx(addr); - let lock_ids = scenario.ids_for_sender>>(); - let mut i = 0; - while (i < lock_ids.length()) { - let coin = scenario.take_from_sender_by_id>>(lock_ids[i]); - sum = sum + coin.locked().value(); - scenario.return_to_sender(coin); - i = i + 1; - }; - sum - } - - fun has_timelocked_sui_balance(addr: address, scenario: &mut Scenario): bool { - scenario.next_tx(addr); - scenario.has_most_recent_for_sender>>() - } - - fun has_sui_coins(addr: address, scenario: &mut Scenario): bool { - scenario.next_tx(addr); - scenario.has_most_recent_for_sender>() - } - - fun is_active_validator_by_sui_address(set: &ValidatorSet, validator_address: address): bool { - let validators = set.active_validators(); - let length = validators.length(); - let mut i = 0; - while (i < length) { - let v = &validators[i]; - if (v.sui_address() == validator_address) { - return true - }; - i = i + 1; - }; - false - } - -} diff --git a/crates/sui-framework/src/lib.rs b/crates/sui-framework/src/lib.rs deleted file mode 100644 index 0babc0838c3..00000000000 --- a/crates/sui-framework/src/lib.rs +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt::Formatter; - -use move_binary_format::{ - binary_config::BinaryConfig, - compatibility::Compatibility, - file_format::{Ability, AbilitySet}, - CompiledModule, -}; -use move_core_types::gas_algebra::InternalGas; -use once_cell::sync::Lazy; -use serde::{Deserialize, Serialize}; -use sui_types::{ - base_types::{ObjectID, ObjectRef}, - digests::TransactionDigest, - move_package::MovePackage, - object::{Object, OBJECT_START_VERSION}, - storage::ObjectStore, - DEEPBOOK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID, STARDUST_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID, - SUI_SYSTEM_PACKAGE_ID, TIMELOCK_PACKAGE_ID, -}; -use tracing::error; - -/// Represents a system package in the framework, that's built from the source -/// code inside sui-framework. -#[derive(Clone, Serialize, PartialEq, Eq, Deserialize)] -pub struct SystemPackage { - pub id: ObjectID, - pub bytes: Vec>, - pub dependencies: Vec, -} - -impl SystemPackage { - pub fn new(id: ObjectID, raw_bytes: &'static [u8], dependencies: &[ObjectID]) -> Self { - let bytes: Vec> = bcs::from_bytes(raw_bytes).unwrap(); - Self { - id, - bytes, - dependencies: dependencies.to_vec(), - } - } - - pub fn id(&self) -> &ObjectID { - &self.id - } - - pub fn bytes(&self) -> &[Vec] { - &self.bytes - } - - pub fn dependencies(&self) -> &[ObjectID] { - &self.dependencies - } - - pub fn modules(&self) -> Vec { - self.bytes - .iter() - .map(|b| CompiledModule::deserialize_with_defaults(b).unwrap()) - .collect() - } - - pub fn genesis_move_package(&self) -> MovePackage { - MovePackage::new_system( - OBJECT_START_VERSION, - &self.modules(), - self.dependencies.iter().copied(), - ) - } - - pub fn genesis_object(&self) -> Object { - Object::new_system_package( - &self.modules(), - OBJECT_START_VERSION, - self.dependencies.to_vec(), - TransactionDigest::genesis_marker(), - ) - } -} - -impl std::fmt::Debug for SystemPackage { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - writeln!(f, "Object ID: {:?}", self.id)?; - writeln!(f, "Size: {}", self.bytes.len())?; - writeln!(f, "Dependencies: {:?}", self.dependencies)?; - Ok(()) - } -} - -macro_rules! define_system_packages { - ([$(($id:expr, $path:expr, $deps:expr)),* $(,)?]) => {{ - static PACKAGES: Lazy> = Lazy::new(|| { - vec![ - $(SystemPackage::new( - $id, - include_bytes!(concat!(env!("OUT_DIR"), "/", $path)), - &$deps, - )),* - ] - }); - Lazy::force(&PACKAGES) - }} -} - -pub struct BuiltInFramework; -impl BuiltInFramework { - /// Dedicated method to iterate on `stardust` packages. - // TODO: integrate to iter_system_packages when we make a new - // system-framework-snapshot with the associated protocol bump:wq - pub fn iter_stardust_packages() -> impl Iterator { - define_system_packages!([ - ( - STARDUST_PACKAGE_ID, - "stardust", - [MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID] - ), - ( - TIMELOCK_PACKAGE_ID, - "timelock", - [ - MOVE_STDLIB_PACKAGE_ID, - SUI_FRAMEWORK_PACKAGE_ID, - SUI_SYSTEM_PACKAGE_ID - ] - ) - ]) - .iter() - } - - pub fn iter_system_packages() -> impl Iterator { - // All system packages in the current build should be registered here, and this - // is the only place we need to worry about if any of them changes. - // TODO: Is it possible to derive dependencies from the bytecode instead of - // manually specifying them? - define_system_packages!([ - (MOVE_STDLIB_PACKAGE_ID, "move-stdlib", []), - ( - SUI_FRAMEWORK_PACKAGE_ID, - "sui-framework", - [MOVE_STDLIB_PACKAGE_ID] - ), - ( - SUI_SYSTEM_PACKAGE_ID, - "sui-system", - [MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID] - ), - ( - DEEPBOOK_PACKAGE_ID, - "deepbook", - [MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID] - ) - ]) - .iter() - } - - pub fn all_package_ids() -> Vec { - Self::iter_system_packages().map(|p| p.id).collect() - } - - pub fn get_package_by_id(id: &ObjectID) -> &'static SystemPackage { - Self::iter_system_packages().find(|s| &s.id == id).unwrap() - } - - pub fn genesis_move_packages() -> impl Iterator { - Self::iter_system_packages().map(|package| package.genesis_move_package()) - } - - pub fn genesis_objects() -> impl Iterator { - Self::iter_system_packages().map(|package| package.genesis_object()) - } -} - -pub const DEFAULT_FRAMEWORK_PATH: &str = env!("CARGO_MANIFEST_DIR"); - -pub fn legacy_test_cost() -> InternalGas { - InternalGas::new(0) -} - -/// Check whether the framework defined by `modules` is compatible with the -/// framework that is already on-chain (i.e. stored in `object_store`) at `id`. -/// -/// - Returns `None` if the current package at `id` cannot be loaded, or the -/// compatibility check fails (This is grounds not to upgrade). -/// - Panics if the object at `id` can be loaded but is not a package -- this is -/// an invariant violation. -/// - Returns the digest of the current framework (and version) if it is -/// equivalent to the new framework (indicates support for a protocol upgrade -/// without a framework upgrade). -/// - Returns the digest of the new framework (and version) if it is compatible -/// (indicates support for a protocol upgrade with a framework upgrade). -pub async fn compare_system_package( - object_store: &S, - id: &ObjectID, - modules: &[CompiledModule], - dependencies: Vec, - binary_config: &BinaryConfig, -) -> Option { - let cur_object = match object_store.get_object(id) { - Ok(Some(cur_object)) => cur_object, - - Ok(None) => { - // creating a new framework package--nothing to check - return Some( - Object::new_system_package( - modules, - // note: execution_engine assumes any system package with version - // OBJECT_START_VERSION is freshly created rather than - // upgraded - OBJECT_START_VERSION, - dependencies, - // Genesis is fine here, we only use it to calculate an object ref that we can - // use for all validators to commit to the same bytes in - // the update - TransactionDigest::genesis_marker(), - ) - .compute_object_reference(), - ); - } - - Err(e) => { - error!("Error loading framework object at {id}: {e:?}"); - return None; - } - }; - - let cur_ref = cur_object.compute_object_reference(); - let cur_pkg = cur_object - .data - .try_as_package() - .expect("Framework not package"); - - let mut new_object = Object::new_system_package( - modules, - // Start at the same version as the current package, and increment if compatibility is - // successful - cur_object.version(), - dependencies, - cur_object.previous_transaction, - ); - - if cur_ref == new_object.compute_object_reference() { - return Some(cur_ref); - } - - let compatibility = Compatibility { - check_struct_and_pub_function_linking: true, - check_struct_layout: true, - check_friend_linking: false, - // Checking `entry` linkage is required because system packages are updated in-place, and a - // transaction that was rolled back to make way for reconfiguration should still be runnable - // after a reconfiguration that upgraded the framework. - // - // A transaction that calls a system function that was previously `entry` and is now private - // will fail because its entrypoint became no longer callable. A transaction that calls a - // system function that was previously `public entry` and is now just `public` could also - // fail if one of its mutable inputs was being used in another private `entry` function. - check_private_entry_linking: true, - disallowed_new_abilities: AbilitySet::singleton(Ability::Key), - disallow_change_struct_type_params: true, - }; - - let new_pkg = new_object - .data - .try_as_package_mut() - .expect("Created as package"); - - let cur_normalized = match cur_pkg.normalize(binary_config) { - Ok(v) => v, - Err(e) => { - error!("Could not normalize existing package: {e:?}"); - return None; - } - }; - let mut new_normalized = new_pkg.normalize(binary_config).ok()?; - - for (name, cur_module) in cur_normalized { - let Some(new_module) = new_normalized.remove(&name) else { - return None; - }; - - if let Err(e) = compatibility.check(&cur_module, &new_module) { - error!("Compatibility check failed, for new version of {id}::{name}: {e:?}"); - return None; - } - } - - new_pkg.increment_version(); - Some(new_object.compute_object_reference()) -} diff --git a/crates/sui-genesis-builder/Cargo.toml b/crates/sui-genesis-builder/Cargo.toml deleted file mode 100644 index 47c657a0b5a..00000000000 --- a/crates/sui-genesis-builder/Cargo.toml +++ /dev/null @@ -1,60 +0,0 @@ -[package] -name = "sui-genesis-builder" -version = "0.0.0" -authors = ["IOTA Stiftung"] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -bcs.workspace = true -camino.workspace = true -fastcrypto.workspace = true -hex.workspace = true -move-binary-format.workspace = true -move-core-types.workspace = true -move-package.workspace = true -move-vm-runtime-v2 = { path = "../../external-crates/move/move-execution/v2/crates/move-vm-runtime" } -rand.workspace = true -rand_regex.workspace = true -regex.workspace = true -serde.workspace = true -serde_json.workspace = true -serde_with.workspace = true -serde_yaml.workspace = true -tempfile.workspace = true -thiserror.workspace = true -tracing.workspace = true -prometheus.workspace = true - -bigdecimal = "0.4.3" -fs_extra = "1.3.0" -iota-sdk = { version = "1.1.4", default-features = false, features = ["irc_27", "irc_30", "std"] } -num-rational = "0.4" -packable = { version = "0.8.3", default-features = false, features = ["io"] } -rand_pcg = "0.3.1" -rand_seeder = "0.2.3" - -schemars.workspace = true -shared-crypto.workspace = true -sui-config.workspace = true -sui-execution.workspace = true -sui-adapter-v2 = { path = "../../sui-execution/v2/sui-adapter/" } -sui-framework.workspace = true -sui-framework-snapshot.workspace = true -sui-move-build.workspace = true -sui-move-natives-v2 = { path = "../../sui-execution/v2/sui-move-natives" } -sui-protocol-config.workspace = true -sui-types.workspace = true -[target.'cfg(msim)'.dependencies] -sui-simulator.workspace = true - -[dev-dependencies] -insta.workspace = true -tempfile.workspace = true -sui-types = { workspace = true, features = ["test-utils"] } - -[[example]] -name = "parse_full_snapshot" -path = "examples/parse_full_snapshot.rs" diff --git a/crates/sui-genesis-builder/src/lib.rs b/crates/sui-genesis-builder/src/lib.rs deleted file mode 100644 index 9e10177f122..00000000000 --- a/crates/sui-genesis-builder/src/lib.rs +++ /dev/null @@ -1,1215 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::{BTreeMap, HashSet}, - fs, - path::Path, - sync::Arc, -}; - -use anyhow::{bail, Context}; -use camino::Utf8Path; -use fastcrypto::{hash::HashFunction, traits::KeyPair}; -use move_binary_format::CompiledModule; -use move_core_types::ident_str; -use shared_crypto::intent::{Intent, IntentMessage, IntentScope}; -use sui_config::genesis::{ - Genesis, GenesisCeremonyParameters, GenesisChainParameters, TokenDistributionSchedule, - UnsignedGenesis, -}; -use sui_execution::{self, Executor}; -use sui_framework::{BuiltInFramework, SystemPackage}; -use sui_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; -use sui_types::{ - base_types::{ - ExecutionDigests, ObjectID, SequenceNumber, SuiAddress, TransactionDigest, TxContext, - }, - committee::Committee, - crypto::{ - AuthorityKeyPair, AuthorityPublicKeyBytes, AuthoritySignInfo, AuthoritySignInfoTrait, - AuthoritySignature, DefaultHash, SuiAuthoritySignature, - }, - deny_list::{DENY_LIST_CREATE_FUNC, DENY_LIST_MODULE}, - digests::ChainIdentifier, - effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, - epoch_data::EpochData, - gas::SuiGasStatus, - gas_coin::GasCoin, - governance::StakedSui, - in_memory_storage::InMemoryStorage, - inner_temporary_store::InnerTemporaryStore, - message_envelope::Message, - messages_checkpoint::{CertifiedCheckpointSummary, CheckpointContents, CheckpointSummary}, - metrics::LimitsMetrics, - object::{Object, Owner}, - programmable_transaction_builder::ProgrammableTransactionBuilder, - sui_system_state::{get_sui_system_state, SuiSystemState, SuiSystemStateTrait}, - transaction::{ - CallArg, CheckedInputObjects, Command, InputObjectKind, ObjectReadResult, Transaction, - }, - SUI_FRAMEWORK_ADDRESS, SUI_SYSTEM_ADDRESS, -}; -use tracing::trace; -use validator_info::{GenesisValidatorInfo, GenesisValidatorMetadata, ValidatorInfo}; - -pub mod stardust; -pub mod validator_info; - -const GENESIS_BUILDER_COMMITTEE_DIR: &str = "committee"; -const GENESIS_BUILDER_PARAMETERS_FILE: &str = "parameters"; -const GENESIS_BUILDER_TOKEN_DISTRIBUTION_SCHEDULE_FILE: &str = "token-distribution-schedule"; -const GENESIS_BUILDER_SIGNATURE_DIR: &str = "signatures"; -const GENESIS_BUILDER_UNSIGNED_GENESIS_FILE: &str = "unsigned-genesis"; - -pub struct Builder { - parameters: GenesisCeremonyParameters, - token_distribution_schedule: Option, - objects: BTreeMap, - validators: BTreeMap, - // Validator signatures over checkpoint - signatures: BTreeMap, - built_genesis: Option, -} - -impl Default for Builder { - fn default() -> Self { - Self::new() - } -} - -impl Builder { - pub fn new() -> Self { - Self { - parameters: Default::default(), - token_distribution_schedule: None, - objects: Default::default(), - validators: Default::default(), - signatures: Default::default(), - built_genesis: None, - } - } - - pub fn with_parameters(mut self, parameters: GenesisCeremonyParameters) -> Self { - self.parameters = parameters; - self - } - - pub fn with_token_distribution_schedule( - mut self, - token_distribution_schedule: TokenDistributionSchedule, - ) -> Self { - self.token_distribution_schedule = Some(token_distribution_schedule); - self - } - - pub fn with_protocol_version(mut self, v: ProtocolVersion) -> Self { - self.parameters.protocol_version = v; - self - } - - pub fn add_object(mut self, object: Object) -> Self { - self.objects.insert(object.id(), object); - self - } - - pub fn add_objects(mut self, objects: Vec) -> Self { - for object in objects { - self.objects.insert(object.id(), object); - } - self - } - - pub fn add_validator( - mut self, - validator: ValidatorInfo, - proof_of_possession: AuthoritySignature, - ) -> Self { - self.validators.insert( - validator.protocol_key(), - GenesisValidatorInfo { - info: validator, - proof_of_possession, - }, - ); - self - } - - pub fn validators(&self) -> &BTreeMap { - &self.validators - } - - pub fn add_validator_signature(mut self, keypair: &AuthorityKeyPair) -> Self { - let UnsignedGenesis { checkpoint, .. } = self.build_unsigned_genesis_checkpoint(); - - let name = keypair.public().into(); - assert!( - self.validators.contains_key(&name), - "provided keypair does not correspond to a validator in the validator set" - ); - let checkpoint_signature = { - let intent_msg = IntentMessage::new( - Intent::sui_app(IntentScope::CheckpointSummary), - checkpoint.clone(), - ); - let signature = AuthoritySignature::new_secure(&intent_msg, &checkpoint.epoch, keypair); - AuthoritySignInfo { - epoch: checkpoint.epoch, - authority: name, - signature, - } - }; - - self.signatures.insert(name, checkpoint_signature); - - self - } - - pub fn unsigned_genesis_checkpoint(&self) -> Option { - self.built_genesis.clone() - } - - pub fn build_unsigned_genesis_checkpoint(&mut self) -> UnsignedGenesis { - if let Some(built_genesis) = &self.built_genesis { - return built_genesis.clone(); - } - - // Verify that all input data is valid - self.validate().unwrap(); - - let objects = self.objects.clone().into_values().collect::>(); - let validators = self.validators.clone().into_values().collect::>(); - - let token_distribution_schedule = - if let Some(token_distribution_schedule) = &self.token_distribution_schedule { - token_distribution_schedule.clone() - } else { - TokenDistributionSchedule::new_for_validators_with_default_allocation( - validators.iter().map(|v| v.info.sui_address()), - ) - }; - - self.built_genesis = Some(build_unsigned_genesis_data( - &self.parameters, - &token_distribution_schedule, - &validators, - &objects, - )); - - self.token_distribution_schedule = Some(token_distribution_schedule); - - self.built_genesis.clone().unwrap() - } - - fn committee(objects: &[Object]) -> Committee { - let sui_system_object = - get_sui_system_state(&objects).expect("Sui System State object must always exist"); - sui_system_object.get_current_epoch_committee().committee - } - - pub fn protocol_version(&self) -> ProtocolVersion { - self.parameters.protocol_version - } - - pub fn build(mut self) -> Genesis { - let UnsignedGenesis { - checkpoint, - checkpoint_contents, - transaction, - effects, - events, - objects, - } = self.build_unsigned_genesis_checkpoint(); - - let committee = Self::committee(&objects); - - let checkpoint = { - let signatures = self.signatures.clone().into_values().collect(); - - CertifiedCheckpointSummary::new(checkpoint, signatures, &committee).unwrap() - }; - - let genesis = Genesis::new( - checkpoint, - checkpoint_contents, - transaction, - effects, - events, - objects, - ); - - // Verify that all on-chain state was properly created - self.validate().unwrap(); - - genesis - } - - /// Validates the entire state of the build, no matter what the internal - /// state is (input collection phase or output phase) - pub fn validate(&self) -> anyhow::Result<(), anyhow::Error> { - self.validate_inputs()?; - self.validate_output(); - Ok(()) - } - - /// Runs through validation checks on the input values present in the - /// builder - fn validate_inputs(&self) -> anyhow::Result<(), anyhow::Error> { - if !self.parameters.allow_insertion_of_extra_objects && !self.objects.is_empty() { - bail!("extra objects are disallowed"); - } - - for validator in self.validators.values() { - validator.validate().with_context(|| { - format!( - "metadata for validator {} is invalid", - validator.info.name() - ) - })?; - } - - if let Some(token_distribution_schedule) = &self.token_distribution_schedule { - token_distribution_schedule.validate(); - token_distribution_schedule.check_all_stake_operations_are_for_valid_validators( - self.validators.values().map(|v| v.info.sui_address()), - ); - } - - Ok(()) - } - - /// Runs through validation checks on the generated output (the initial - /// chain state) based on the input values present in the builder - fn validate_output(&self) { - // If genesis hasn't been built yet, just early return as there is nothing to - // validate yet - let Some(unsigned_genesis) = self.unsigned_genesis_checkpoint() else { - return; - }; - - let GenesisChainParameters { - protocol_version, - chain_start_timestamp_ms, - epoch_duration_ms, - stake_subsidy_start_epoch, - stake_subsidy_initial_distribution_amount, - stake_subsidy_period_length, - stake_subsidy_decrease_rate, - max_validator_count, - min_validator_joining_stake, - validator_low_stake_threshold, - validator_very_low_stake_threshold, - validator_low_stake_grace_period, - } = self.parameters.to_genesis_chain_parameters(); - - // In non-testing code, genesis type must always be V1. - let system_state = match unsigned_genesis.sui_system_object() { - SuiSystemState::V1(inner) => inner, - SuiSystemState::V2(_) => unreachable!(), - #[cfg(msim)] - _ => { - // Types other than V1 used in simtests do not need to be validated. - return; - } - }; - - let protocol_config = get_genesis_protocol_config(ProtocolVersion::new(protocol_version)); - - if protocol_config.create_authenticator_state_in_genesis() { - let authenticator_state = unsigned_genesis.authenticator_state_object().unwrap(); - assert!(authenticator_state.active_jwks.is_empty()); - } else { - assert!(unsigned_genesis.authenticator_state_object().is_none()); - } - assert_eq!( - protocol_config.random_beacon(), - unsigned_genesis.has_randomness_state_object() - ); - - assert_eq!( - protocol_config.enable_coin_deny_list(), - unsigned_genesis.coin_deny_list_state().is_some(), - ); - - assert_eq!( - self.validators.len(), - system_state.validators.active_validators.len() - ); - let mut address_to_pool_id = BTreeMap::new(); - for (validator, onchain_validator) in self - .validators - .values() - .zip(system_state.validators.active_validators.iter()) - { - let metadata = onchain_validator.verified_metadata(); - - // Validators should not have duplicate addresses so the result of insertion - // should be None. - assert!( - address_to_pool_id - .insert(metadata.sui_address, onchain_validator.staking_pool.id) - .is_none() - ); - assert_eq!(validator.info.sui_address(), metadata.sui_address); - assert_eq!(validator.info.protocol_key(), metadata.sui_pubkey_bytes()); - assert_eq!(validator.info.network_key, metadata.network_pubkey); - assert_eq!(validator.info.worker_key, metadata.worker_pubkey); - assert_eq!( - validator.proof_of_possession.as_ref().to_vec(), - metadata.proof_of_possession_bytes - ); - assert_eq!(validator.info.name(), &metadata.name); - assert_eq!(validator.info.description, metadata.description); - assert_eq!(validator.info.image_url, metadata.image_url); - assert_eq!(validator.info.project_url, metadata.project_url); - assert_eq!(validator.info.network_address(), &metadata.net_address); - assert_eq!(validator.info.p2p_address, metadata.p2p_address); - assert_eq!( - validator.info.narwhal_primary_address, - metadata.primary_address - ); - assert_eq!( - validator.info.narwhal_worker_address, - metadata.worker_address - ); - - assert_eq!(validator.info.gas_price, onchain_validator.gas_price); - assert_eq!( - validator.info.commission_rate, - onchain_validator.commission_rate - ); - } - - assert_eq!(system_state.epoch, 0); - assert_eq!(system_state.protocol_version, protocol_version); - assert_eq!(system_state.storage_fund.non_refundable_balance.value(), 0); - assert_eq!( - system_state - .storage_fund - .total_object_storage_rebates - .value(), - 0 - ); - - assert_eq!(system_state.parameters.epoch_duration_ms, epoch_duration_ms); - assert_eq!( - system_state.parameters.stake_subsidy_start_epoch, - stake_subsidy_start_epoch, - ); - assert_eq!( - system_state.parameters.max_validator_count, - max_validator_count, - ); - assert_eq!( - system_state.parameters.min_validator_joining_stake, - min_validator_joining_stake, - ); - assert_eq!( - system_state.parameters.validator_low_stake_threshold, - validator_low_stake_threshold, - ); - assert_eq!( - system_state.parameters.validator_very_low_stake_threshold, - validator_very_low_stake_threshold, - ); - assert_eq!( - system_state.parameters.validator_low_stake_grace_period, - validator_low_stake_grace_period, - ); - - assert_eq!(system_state.stake_subsidy.distribution_counter, 0); - assert_eq!( - system_state.stake_subsidy.current_distribution_amount, - stake_subsidy_initial_distribution_amount, - ); - assert_eq!( - system_state.stake_subsidy.stake_subsidy_period_length, - stake_subsidy_period_length, - ); - assert_eq!( - system_state.stake_subsidy.stake_subsidy_decrease_rate, - stake_subsidy_decrease_rate, - ); - - assert!(!system_state.safe_mode); - assert_eq!( - system_state.epoch_start_timestamp_ms, - chain_start_timestamp_ms, - ); - assert_eq!(system_state.validators.pending_removals.len(), 0); - assert_eq!( - system_state - .validators - .pending_active_validators - .contents - .size, - 0 - ); - assert_eq!(system_state.validators.inactive_validators.size, 0); - assert_eq!(system_state.validators.validator_candidates.size, 0); - - // Check distribution is correct - let token_distribution_schedule = self.token_distribution_schedule.clone().unwrap(); - assert_eq!( - system_state.stake_subsidy.balance.value(), - token_distribution_schedule.stake_subsidy_fund_mist - ); - - let mut gas_objects: BTreeMap = unsigned_genesis - .objects() - .iter() - .filter_map(|o| GasCoin::try_from(o).ok().map(|g| (o.id(), (o, g)))) - .collect(); - let mut staked_sui_objects: BTreeMap = unsigned_genesis - .objects() - .iter() - .filter_map(|o| StakedSui::try_from(o).ok().map(|s| (o.id(), (o, s)))) - .collect(); - - for allocation in token_distribution_schedule.allocations { - if let Some(staked_with_validator) = allocation.staked_with_validator { - let staking_pool_id = *address_to_pool_id - .get(&staked_with_validator) - .expect("staking pool should exist"); - let staked_sui_object_id = staked_sui_objects - .iter() - .find(|(_k, (o, s))| { - let Owner::AddressOwner(owner) = &o.owner else { - panic!("gas object owner must be address owner"); - }; - *owner == allocation.recipient_address - && s.principal() == allocation.amount_mist - && s.pool_id() == staking_pool_id - }) - .map(|(k, _)| *k) - .expect("all allocations should be present"); - let staked_sui_object = staked_sui_objects.remove(&staked_sui_object_id).unwrap(); - assert_eq!( - staked_sui_object.0.owner, - Owner::AddressOwner(allocation.recipient_address) - ); - assert_eq!(staked_sui_object.1.principal(), allocation.amount_mist); - assert_eq!(staked_sui_object.1.pool_id(), staking_pool_id); - assert_eq!(staked_sui_object.1.activation_epoch(), 0); - } else { - let gas_object_id = gas_objects - .iter() - .find(|(_k, (o, g))| { - if let Owner::AddressOwner(owner) = &o.owner { - *owner == allocation.recipient_address - && g.value() == allocation.amount_mist - } else { - false - } - }) - .map(|(k, _)| *k) - .expect("all allocations should be present"); - let gas_object = gas_objects.remove(&gas_object_id).unwrap(); - assert_eq!( - gas_object.0.owner, - Owner::AddressOwner(allocation.recipient_address) - ); - assert_eq!(gas_object.1.value(), allocation.amount_mist,); - } - } - - // All Gas and staked objects should be accounted for - if !self.parameters.allow_insertion_of_extra_objects { - assert!(gas_objects.is_empty()); - assert!(staked_sui_objects.is_empty()); - } - - let committee = system_state.get_current_epoch_committee().committee; - for signature in self.signatures.values() { - if self.validators.get(&signature.authority).is_none() { - panic!("found signature for unknown validator: {:#?}", signature); - } - - signature - .verify_secure( - unsigned_genesis.checkpoint(), - Intent::sui_app(IntentScope::CheckpointSummary), - &committee, - ) - .expect("signature should be valid"); - } - } - - pub fn load>(path: P) -> anyhow::Result { - let path = path.as_ref(); - let path: &Utf8Path = path.try_into()?; - trace!("Reading Genesis Builder from {}", path); - - if !path.is_dir() { - bail!("path must be a directory"); - } - - // Load parameters - let parameters_file = path.join(GENESIS_BUILDER_PARAMETERS_FILE); - let parameters = serde_yaml::from_slice( - &fs::read(parameters_file).context("unable to read genesis parameters file")?, - ) - .context("unable to deserialize genesis parameters")?; - - let token_distribution_schedule_file = - path.join(GENESIS_BUILDER_TOKEN_DISTRIBUTION_SCHEDULE_FILE); - let token_distribution_schedule = if token_distribution_schedule_file.exists() { - Some(TokenDistributionSchedule::from_csv(fs::File::open( - token_distribution_schedule_file, - )?)?) - } else { - None - }; - - // Load validator infos - let mut committee = BTreeMap::new(); - for entry in path.join(GENESIS_BUILDER_COMMITTEE_DIR).read_dir_utf8()? { - let entry = entry?; - if entry.file_name().starts_with('.') { - continue; - } - - let path = entry.path(); - let validator_info_bytes = fs::read(path)?; - let validator_info: GenesisValidatorInfo = - serde_yaml::from_slice(&validator_info_bytes) - .with_context(|| format!("unable to load validator info for {path}"))?; - committee.insert(validator_info.info.protocol_key(), validator_info); - } - - // Load Signatures - let mut signatures = BTreeMap::new(); - for entry in path.join(GENESIS_BUILDER_SIGNATURE_DIR).read_dir_utf8()? { - let entry = entry?; - if entry.file_name().starts_with('.') { - continue; - } - - let path = entry.path(); - let signature_bytes = fs::read(path)?; - let sigs: AuthoritySignInfo = bcs::from_bytes(&signature_bytes) - .with_context(|| format!("unable to load validator signatrue for {path}"))?; - signatures.insert(sigs.authority, sigs); - } - - let mut builder = Self { - parameters, - token_distribution_schedule, - objects: Default::default(), - validators: committee, - signatures, - built_genesis: None, // Leave this as none, will build and compare below - }; - - let unsigned_genesis_file = path.join(GENESIS_BUILDER_UNSIGNED_GENESIS_FILE); - if unsigned_genesis_file.exists() { - let unsigned_genesis_bytes = fs::read(unsigned_genesis_file)?; - let loaded_genesis: UnsignedGenesis = bcs::from_bytes(&unsigned_genesis_bytes)?; - - // If we have a built genesis, then we must have a token_distribution_schedule - // present as well. - assert!( - builder.token_distribution_schedule.is_some(), - "If a built genesis is present, then there must also be a token-distribution-schedule present" - ); - - // Verify loaded genesis matches one build from the constituent parts - let built = builder.build_unsigned_genesis_checkpoint(); - loaded_genesis.checkpoint_contents.digest(); // cache digest before compare - assert_eq!( - built, loaded_genesis, - "loaded genesis does not match built genesis" - ); - - // Just to double check that its set after building above - assert!(builder.unsigned_genesis_checkpoint().is_some()); - } - - Ok(builder) - } - - pub fn save>(self, path: P) -> anyhow::Result<(), anyhow::Error> { - let path = path.as_ref(); - trace!("Writing Genesis Builder to {}", path.display()); - - fs::create_dir_all(path)?; - - // Write parameters - let parameters_file = path.join(GENESIS_BUILDER_PARAMETERS_FILE); - fs::write(parameters_file, serde_yaml::to_string(&self.parameters)?)?; - - if let Some(token_distribution_schedule) = &self.token_distribution_schedule { - token_distribution_schedule.to_csv(fs::File::create( - path.join(GENESIS_BUILDER_TOKEN_DISTRIBUTION_SCHEDULE_FILE), - )?)?; - } - - // Write Signatures - let signature_dir = path.join(GENESIS_BUILDER_SIGNATURE_DIR); - std::fs::create_dir_all(&signature_dir)?; - for (pubkey, sigs) in self.signatures { - let sig_bytes = bcs::to_bytes(&sigs)?; - let name = self.validators.get(&pubkey).unwrap().info.name(); - fs::write(signature_dir.join(name), sig_bytes)?; - } - - // Write validator infos - let committee_dir = path.join(GENESIS_BUILDER_COMMITTEE_DIR); - fs::create_dir_all(&committee_dir)?; - - for (_pubkey, validator) in self.validators { - let validator_info_bytes = serde_yaml::to_string(&validator)?; - fs::write( - committee_dir.join(validator.info.name()), - validator_info_bytes, - )?; - } - - if let Some(genesis) = &self.built_genesis { - let genesis_bytes = bcs::to_bytes(&genesis)?; - fs::write( - path.join(GENESIS_BUILDER_UNSIGNED_GENESIS_FILE), - genesis_bytes, - )?; - } - - Ok(()) - } -} - -// Create a Genesis Txn Context to be used when generating genesis objects by -// hashing all of the inputs into genesis ans using that as our "Txn Digest". -// This is done to ensure that coin objects created between chains are unique -fn create_genesis_context( - epoch_data: &EpochData, - genesis_chain_parameters: &GenesisChainParameters, - genesis_validators: &[GenesisValidatorMetadata], - token_distribution_schedule: &TokenDistributionSchedule, - system_packages: &[SystemPackage], -) -> TxContext { - let mut hasher = DefaultHash::default(); - hasher.update(b"sui-genesis"); - hasher.update(&bcs::to_bytes(genesis_chain_parameters).unwrap()); - hasher.update(&bcs::to_bytes(genesis_validators).unwrap()); - hasher.update(&bcs::to_bytes(token_distribution_schedule).unwrap()); - for system_package in system_packages { - hasher.update(&bcs::to_bytes(system_package.bytes()).unwrap()); - } - - let hash = hasher.finalize(); - let genesis_transaction_digest = TransactionDigest::new(hash.into()); - - TxContext::new( - &SuiAddress::default(), - &genesis_transaction_digest, - epoch_data, - ) -} - -fn get_genesis_protocol_config(version: ProtocolVersion) -> ProtocolConfig { - // We have a circular dependency here. Protocol config depends on chain ID, - // which depends on genesis checkpoint (digest), which depends on genesis - // transaction, which depends on protocol config. - // - // ChainIdentifier::default().chain() which can be overridden by the - // SUI_PROTOCOL_CONFIG_CHAIN_OVERRIDE if necessary - ProtocolConfig::get_for_version(version, ChainIdentifier::default().chain()) -} - -fn build_unsigned_genesis_data( - parameters: &GenesisCeremonyParameters, - token_distribution_schedule: &TokenDistributionSchedule, - validators: &[GenesisValidatorInfo], - objects: &[Object], -) -> UnsignedGenesis { - if !parameters.allow_insertion_of_extra_objects && !objects.is_empty() { - panic!( - "insertion of extra objects at genesis time is prohibited due to 'allow_insertion_of_extra_objects' parameter" - ); - } - - let genesis_chain_parameters = parameters.to_genesis_chain_parameters(); - let genesis_validators = validators - .iter() - .cloned() - .map(GenesisValidatorMetadata::from) - .collect::>(); - - token_distribution_schedule.validate(); - token_distribution_schedule.check_all_stake_operations_are_for_valid_validators( - genesis_validators.iter().map(|v| v.sui_address), - ); - - let epoch_data = EpochData::new_genesis(genesis_chain_parameters.chain_start_timestamp_ms); - - // Get the correct system packages for our protocol version. If we cannot find - // the snapshot that means that we must be at the latest version and we - // should use the latest version of the framework. - let system_packages = - sui_framework_snapshot::load_bytecode_snapshot(parameters.protocol_version.as_u64()) - .unwrap_or_else(|_| BuiltInFramework::iter_system_packages().cloned().collect()); - - let mut genesis_ctx = create_genesis_context( - &epoch_data, - &genesis_chain_parameters, - &genesis_validators, - token_distribution_schedule, - &system_packages, - ); - - // Use a throwaway metrics registry for genesis transaction execution. - let registry = prometheus::Registry::new(); - let metrics = Arc::new(LimitsMetrics::new(®istry)); - - let objects = create_genesis_objects( - &mut genesis_ctx, - objects, - &genesis_validators, - &genesis_chain_parameters, - token_distribution_schedule, - system_packages, - metrics.clone(), - ); - - let protocol_config = get_genesis_protocol_config(parameters.protocol_version); - - let (genesis_transaction, genesis_effects, genesis_events, objects) = - create_genesis_transaction(objects, &protocol_config, metrics, &epoch_data); - let (checkpoint, checkpoint_contents) = - create_genesis_checkpoint(parameters, &genesis_transaction, &genesis_effects); - - UnsignedGenesis { - checkpoint, - checkpoint_contents, - transaction: genesis_transaction, - effects: genesis_effects, - events: genesis_events, - objects, - } -} - -fn create_genesis_checkpoint( - parameters: &GenesisCeremonyParameters, - transaction: &Transaction, - effects: &TransactionEffects, -) -> (CheckpointSummary, CheckpointContents) { - let execution_digests = ExecutionDigests { - transaction: *transaction.digest(), - effects: effects.digest(), - }; - let contents = - CheckpointContents::new_with_digests_and_signatures([execution_digests], vec![vec![]]); - let checkpoint = CheckpointSummary { - epoch: 0, - sequence_number: 0, - network_total_transactions: contents.size().try_into().unwrap(), - content_digest: *contents.digest(), - previous_digest: None, - epoch_rolling_gas_cost_summary: Default::default(), - end_of_epoch_data: None, - timestamp_ms: parameters.chain_start_timestamp_ms, - version_specific_data: Vec::new(), - checkpoint_commitments: Default::default(), - }; - - (checkpoint, contents) -} - -fn create_genesis_transaction( - objects: Vec, - protocol_config: &ProtocolConfig, - metrics: Arc, - epoch_data: &EpochData, -) -> ( - Transaction, - TransactionEffects, - TransactionEvents, - Vec, -) { - let genesis_transaction = { - let genesis_objects = objects - .into_iter() - .map(|mut object| { - if let Some(o) = object.data.try_as_move_mut() { - o.decrement_version_to(SequenceNumber::MIN); - } - - if let Owner::Shared { - initial_shared_version, - } = &mut object.owner - { - *initial_shared_version = SequenceNumber::MIN; - } - - let object = object.into_inner(); - sui_types::transaction::GenesisObject::RawObject { - data: object.data, - owner: object.owner, - } - }) - .collect(); - - sui_types::transaction::VerifiedTransaction::new_genesis_transaction(genesis_objects) - .into_inner() - }; - - let genesis_digest = *genesis_transaction.digest(); - // execute txn to effects - let (effects, events, objects) = { - let silent = true; - - let executor = sui_execution::executor(protocol_config, silent, None) - .expect("Creating an executor should not fail here"); - - let expensive_checks = false; - let certificate_deny_set = HashSet::new(); - let transaction_data = &genesis_transaction.data().intent_message().value; - let (kind, signer, _) = transaction_data.execution_parts(); - let input_objects = CheckedInputObjects::new_for_genesis(vec![]); - let (inner_temp_store, _, effects, _execution_error) = executor - .execute_transaction_to_effects( - &InMemoryStorage::new(Vec::new()), - protocol_config, - metrics, - expensive_checks, - &certificate_deny_set, - &epoch_data.epoch_id(), - epoch_data.epoch_start_timestamp(), - input_objects, - vec![], - SuiGasStatus::new_unmetered(), - kind, - signer, - genesis_digest, - ); - assert!(inner_temp_store.input_objects.is_empty()); - assert!(inner_temp_store.mutable_inputs.is_empty()); - assert!(effects.mutated().is_empty()); - assert!(effects.unwrapped().is_empty()); - assert!(effects.deleted().is_empty()); - assert!(effects.wrapped().is_empty()); - assert!(effects.unwrapped_then_deleted().is_empty()); - - let objects = inner_temp_store.written.into_values().collect(); - (effects, inner_temp_store.events, objects) - }; - - (genesis_transaction, effects, events, objects) -} - -fn create_genesis_objects( - genesis_ctx: &mut TxContext, - input_objects: &[Object], - validators: &[GenesisValidatorMetadata], - parameters: &GenesisChainParameters, - token_distribution_schedule: &TokenDistributionSchedule, - system_packages: Vec, - metrics: Arc, -) -> Vec { - let mut store = InMemoryStorage::new(Vec::new()); - // We don't know the chain ID here since we haven't yet created the genesis - // checkpoint. However since we know there are no chain specific protool - // config options in genesis, we use Chain::Unknown here. - let protocol_config = ProtocolConfig::get_for_version( - ProtocolVersion::new(parameters.protocol_version), - Chain::Unknown, - ); - - let silent = true; - let executor = sui_execution::executor(&protocol_config, silent, None) - .expect("Creating an executor should not fail here"); - - for system_package in system_packages.into_iter() { - process_package( - &mut store, - executor.as_ref(), - genesis_ctx, - &system_package.modules(), - system_package.dependencies().to_vec(), - &protocol_config, - metrics.clone(), - ) - .unwrap(); - } - - { - for object in input_objects { - store.insert_object(object.to_owned()); - } - } - - generate_genesis_system_object( - &mut store, - executor.as_ref(), - validators, - genesis_ctx, - parameters, - token_distribution_schedule, - metrics, - ) - .unwrap(); - - store.into_inner().into_values().collect() -} - -pub(crate) fn process_package( - store: &mut InMemoryStorage, - executor: &dyn Executor, - ctx: &mut TxContext, - modules: &[CompiledModule], - dependencies: Vec, - protocol_config: &ProtocolConfig, - metrics: Arc, -) -> anyhow::Result<()> { - let dependency_objects = store.get_objects(&dependencies); - // When publishing genesis packages, since the std framework packages all have - // non-zero addresses, [`Transaction::input_objects_in_compiled_modules`] will - // consider them as dependencies even though they are not. Hence - // input_objects contain objects that don't exist on-chain because they are - // yet to be published. - #[cfg(debug_assertions)] - { - use move_core_types::account_address::AccountAddress; - let to_be_published_addresses: HashSet<_> = modules - .iter() - .map(|module| *module.self_id().address()) - .collect(); - assert!( - // An object either exists on-chain, or is one of the packages to be published. - dependencies - .iter() - .zip(dependency_objects.iter()) - .all(|(dependency, obj_opt)| obj_opt.is_some() - || to_be_published_addresses.contains(&AccountAddress::from(*dependency))) - ); - } - let loaded_dependencies: Vec<_> = dependencies - .iter() - .zip(dependency_objects) - .filter_map(|(dependency, object)| { - Some(ObjectReadResult::new( - InputObjectKind::MovePackage(*dependency), - object?.clone().into(), - )) - }) - .collect(); - - let module_bytes = modules - .iter() - .map(|m| { - let mut buf = vec![]; - m.serialize(&mut buf).unwrap(); - buf - }) - .collect(); - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - // executing in Genesis mode does not create an `UpgradeCap`. - builder.command(Command::Publish(module_bytes, dependencies)); - builder.finish() - }; - let InnerTemporaryStore { written, .. } = executor.update_genesis_state( - &*store, - protocol_config, - metrics, - ctx, - CheckedInputObjects::new_for_genesis(loaded_dependencies), - pt, - )?; - - store.finish(written); - - Ok(()) -} - -pub fn generate_genesis_system_object( - store: &mut InMemoryStorage, - executor: &dyn Executor, - genesis_validators: &[GenesisValidatorMetadata], - genesis_ctx: &mut TxContext, - genesis_chain_parameters: &GenesisChainParameters, - token_distribution_schedule: &TokenDistributionSchedule, - metrics: Arc, -) -> anyhow::Result<()> { - let protocol_config = ProtocolConfig::get_for_version( - ProtocolVersion::new(genesis_chain_parameters.protocol_version), - ChainIdentifier::default().chain(), - ); - - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - // Step 1: Create the SuiSystemState UID - let sui_system_state_uid = builder.programmable_move_call( - SUI_FRAMEWORK_ADDRESS.into(), - ident_str!("object").to_owned(), - ident_str!("sui_system_state").to_owned(), - vec![], - vec![], - ); - - // Step 2: Create and share the Clock. - builder.move_call( - SUI_FRAMEWORK_ADDRESS.into(), - ident_str!("clock").to_owned(), - ident_str!("create").to_owned(), - vec![], - vec![], - )?; - - // Step 3: Create ProtocolConfig-controlled system objects, unless disabled - // (which only happens in tests). - if protocol_config.create_authenticator_state_in_genesis() { - builder.move_call( - SUI_FRAMEWORK_ADDRESS.into(), - ident_str!("authenticator_state").to_owned(), - ident_str!("create").to_owned(), - vec![], - vec![], - )?; - } - if protocol_config.random_beacon() { - builder.move_call( - SUI_FRAMEWORK_ADDRESS.into(), - ident_str!("random").to_owned(), - ident_str!("create").to_owned(), - vec![], - vec![], - )?; - } - if protocol_config.enable_coin_deny_list() { - builder.move_call( - SUI_FRAMEWORK_ADDRESS.into(), - DENY_LIST_MODULE.to_owned(), - DENY_LIST_CREATE_FUNC.to_owned(), - vec![], - vec![], - )?; - } - - // Step 4: Mint the supply of SUI. - let sui_supply = builder.programmable_move_call( - SUI_FRAMEWORK_ADDRESS.into(), - ident_str!("sui").to_owned(), - ident_str!("new").to_owned(), - vec![], - vec![], - ); - - // Step 5: Run genesis. - // The first argument is the system state uid we got from step 1 and the second - // one is the SUI supply we got from step 3. - let mut arguments = vec![sui_system_state_uid, sui_supply]; - let mut call_arg_arguments = vec![ - CallArg::Pure(bcs::to_bytes(&genesis_chain_parameters).unwrap()), - CallArg::Pure(bcs::to_bytes(&genesis_validators).unwrap()), - CallArg::Pure(bcs::to_bytes(&token_distribution_schedule).unwrap()), - ] - .into_iter() - .map(|a| builder.input(a)) - .collect::>()?; - arguments.append(&mut call_arg_arguments); - builder.programmable_move_call( - SUI_SYSTEM_ADDRESS.into(), - ident_str!("genesis").to_owned(), - ident_str!("create").to_owned(), - vec![], - arguments, - ); - builder.finish() - }; - - let InnerTemporaryStore { mut written, .. } = executor.update_genesis_state( - &*store, - &protocol_config, - metrics, - genesis_ctx, - CheckedInputObjects::new_for_genesis(vec![]), - pt, - )?; - - // update the value of the clock to match the chain start time - { - let object = written.get_mut(&sui_types::SUI_CLOCK_OBJECT_ID).unwrap(); - object - .data - .try_as_move_mut() - .unwrap() - .set_clock_timestamp_ms_unsafe(genesis_chain_parameters.chain_start_timestamp_ms); - } - - store.finish(written); - - Ok(()) -} - -#[cfg(test)] -mod test { - use fastcrypto::traits::KeyPair; - use sui_config::{ - genesis::*, - local_ip_utils, - node::{DEFAULT_COMMISSION_RATE, DEFAULT_VALIDATOR_GAS_PRICE}, - }; - use sui_types::{ - base_types::SuiAddress, - crypto::{ - generate_proof_of_possession, get_key_pair_from_rng, AccountKeyPair, AuthorityKeyPair, - NetworkKeyPair, - }, - }; - - use crate::{validator_info::ValidatorInfo, Builder}; - - #[test] - fn allocation_csv() { - let schedule = TokenDistributionSchedule::new_for_validators_with_default_allocation([ - SuiAddress::random_for_testing_only(), - SuiAddress::random_for_testing_only(), - ]); - let mut output = Vec::new(); - - schedule.to_csv(&mut output).unwrap(); - - let parsed_schedule = TokenDistributionSchedule::from_csv(output.as_slice()).unwrap(); - - assert_eq!(schedule, parsed_schedule); - - std::io::Write::write_all(&mut std::io::stdout(), &output).unwrap(); - } - - #[test] - #[cfg_attr(msim, ignore)] - fn ceremony() { - let dir = tempfile::TempDir::new().unwrap(); - - let key: AuthorityKeyPair = get_key_pair_from_rng(&mut rand::rngs::OsRng).1; - let worker_key: NetworkKeyPair = get_key_pair_from_rng(&mut rand::rngs::OsRng).1; - let account_key: AccountKeyPair = get_key_pair_from_rng(&mut rand::rngs::OsRng).1; - let network_key: NetworkKeyPair = get_key_pair_from_rng(&mut rand::rngs::OsRng).1; - let validator = ValidatorInfo { - name: "0".into(), - protocol_key: key.public().into(), - worker_key: worker_key.public().clone(), - account_address: SuiAddress::from(account_key.public()), - network_key: network_key.public().clone(), - gas_price: DEFAULT_VALIDATOR_GAS_PRICE, - commission_rate: DEFAULT_COMMISSION_RATE, - network_address: local_ip_utils::new_local_tcp_address_for_testing(), - p2p_address: local_ip_utils::new_local_udp_address_for_testing(), - narwhal_primary_address: local_ip_utils::new_local_udp_address_for_testing(), - narwhal_worker_address: local_ip_utils::new_local_udp_address_for_testing(), - description: String::new(), - image_url: String::new(), - project_url: String::new(), - }; - let pop = generate_proof_of_possession(&key, account_key.public().into()); - let mut builder = Builder::new().add_validator(validator, pop); - - let genesis = builder.build_unsigned_genesis_checkpoint(); - for object in genesis.objects() { - println!("ObjectID: {} Type: {:?}", object.id(), object.type_()); - } - builder.save(dir.path()).unwrap(); - Builder::load(dir.path()).unwrap(); - } -} diff --git a/crates/sui-genesis-builder/src/stardust/error.rs b/crates/sui-genesis-builder/src/stardust/error.rs deleted file mode 100644 index 3e5739f063d..00000000000 --- a/crates/sui-genesis-builder/src/stardust/error.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -//! Error types pertaining to deserializing Stardust snapshots -use std::convert::Infallible; - -use iota_sdk::types::block::output::FoundryId; -use packable::error::UnknownTagError; -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum StardustError { - #[error("unsupported snapshot version: expected {0}, got {1}")] - UnsupportedSnapshotVersion(u8, u8), - #[error("invalid snapshot kind: {0}")] - InvalidSnapshotKind(u8), - #[error("block error: {0}")] - BlockError(#[from] iota_sdk::types::block::Error), - #[error("{0}")] - UnknownTag(#[from] UnknownTagError), - #[error( - "cannot convert `FoundryOutput` with `FoundryId` {foundry_id} to `NativeTokenPackageData`: {err}" - )] - FoundryConversionError { - foundry_id: FoundryId, - err: anyhow::Error, - }, - #[error("framework packages path not found")] - FrameworkPackagesPathNotFound, - #[error( - "failed to derive valid move identifier from symbol `{symbol}`, invalid identifier: `{identifier}`" - )] - InvalidMoveIdentifierDerived { symbol: String, identifier: String }, - #[error("melting tokens must not be greater than minted tokens")] - MeltingTokensMustNotBeGreaterThanMintedTokens, - #[error("circulating supply must not be greater than maximum supply")] - CirculatingSupplyMustNotBeGreaterThanMaximumSupply, -} - -impl From for StardustError { - fn from(_: Infallible) -> Self { - unreachable!() - } -} diff --git a/crates/sui-genesis-builder/src/stardust/migration/executor.rs b/crates/sui-genesis-builder/src/stardust/migration/executor.rs deleted file mode 100644 index cdc86ca1c5f..00000000000 --- a/crates/sui-genesis-builder/src/stardust/migration/executor.rs +++ /dev/null @@ -1,811 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::{BTreeSet, HashMap}, - sync::Arc, -}; - -use anyhow::Result; -use iota_sdk::types::block::output::{ - AliasOutput, BasicOutput, FoundryOutput, NativeTokens, NftOutput, OutputId, TokenId, -}; -use move_core_types::{ident_str, language_storage::StructTag}; -use move_vm_runtime_v2::move_vm::MoveVM; -use sui_adapter_v2::{ - adapter::new_move_vm, gas_charger::GasCharger, programmable_transactions, - temporary_store::TemporaryStore, -}; -use sui_framework::BuiltInFramework; -use sui_move_build::CompiledPackage; -use sui_move_natives_v2::all_natives; -use sui_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; -use sui_types::{ - balance::Balance, - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress, TxContext}, - collection_types::Bag, - dynamic_field::Field, - execution_mode, - id::UID, - in_memory_storage::InMemoryStorage, - inner_temporary_store::InnerTemporaryStore, - metrics::LimitsMetrics, - move_package::{MovePackage, TypeOrigin, UpgradeCap}, - object::Object, - programmable_transaction_builder::ProgrammableTransactionBuilder, - transaction::{ - Argument, CheckedInputObjects, Command, InputObjectKind, InputObjects, ObjectArg, - ObjectReadResult, ProgrammableTransaction, - }, - TypeTag, STARDUST_ADDRESS, STARDUST_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID, -}; - -use crate::{ - process_package, - stardust::{ - migration::{ - create_migration_context, package_module_bytes, - verification::created_objects::CreatedObjects, PACKAGE_DEPS, - }, - types::{ - foundry::create_foundry_gas_coin, snapshot::OutputHeader, stardust_to_sui_address, - stardust_to_sui_address_owner, timelock, token_scheme::SimpleTokenSchemeU64, Nft, - }, - }, -}; - -/// Creates the objects that map to the stardust UTXO ledger. -/// -/// Internally uses an unmetered Move VM. -pub(super) struct Executor { - protocol_config: ProtocolConfig, - tx_context: TxContext, - /// Stores all the migration objects. - store: InMemoryStorage, - /// Caches the system packages and init objects. Useful for evicting - /// them from the store before creating the snapshot. - system_packages_and_objects: BTreeSet, - move_vm: Arc, - metrics: Arc, - /// Map the stardust token id [`TokenId`] to the on-chain info of the - /// published foundry objects. - native_tokens: HashMap, -} - -impl Executor { - /// Setup the execution environment backed by an in-memory store that holds - /// all the system packages. - pub(super) fn new(protocol_version: ProtocolVersion) -> Result { - let mut tx_context = create_migration_context(); - // Use a throwaway metrics registry for transaction execution. - let metrics = Arc::new(LimitsMetrics::new(&prometheus::Registry::new())); - let mut store = InMemoryStorage::new(Vec::new()); - // We don't know the chain ID here since we haven't yet created the genesis - // checkpoint. However since we know there are no chain specific - // protocol config options in genesis, we use Chain::Unknown here. - let protocol_config = ProtocolConfig::get_for_version(protocol_version, Chain::Unknown); - // Get the correct system packages for our protocol version. If we cannot find - // the snapshot that means that we must be at the latest version and we - // should use the latest version of the framework. - let mut system_packages = - sui_framework_snapshot::load_bytecode_snapshot(protocol_version.as_u64()) - .unwrap_or_else(|_| BuiltInFramework::iter_system_packages().cloned().collect()); - // TODO: Remove when we have bumped the protocol to include the stardust - // packages into the system packages. - // - // See also: https://github.com/iotaledger/kinesis/pull/149 - system_packages.extend(BuiltInFramework::iter_stardust_packages().cloned()); - - let silent = true; - let executor = sui_execution::executor(&protocol_config, silent, None) - .expect("Creating an executor should not fail here"); - for system_package in system_packages.into_iter() { - process_package( - &mut store, - executor.as_ref(), - &mut tx_context, - &system_package.modules(), - system_package.dependencies().to_vec(), - &protocol_config, - metrics.clone(), - )?; - } - let move_vm = Arc::new(new_move_vm(all_natives(silent), &protocol_config, None)?); - - let system_packages_and_objects = store.objects().keys().copied().collect(); - Ok(Self { - protocol_config, - tx_context, - store, - system_packages_and_objects, - move_vm, - metrics, - native_tokens: Default::default(), - }) - } - - pub fn store(&self) -> &InMemoryStorage { - &self.store - } - - pub(crate) fn native_tokens(&self) -> &HashMap { - &self.native_tokens - } - - /// The migration objects. - /// - /// The system packages and underlying `init` objects - /// are filtered out because they will be generated - /// in the genesis process. - pub(super) fn into_objects(self) -> Vec { - self.store - .into_inner() - .into_values() - .filter(|object| !self.system_packages_and_objects.contains(&object.id())) - .collect() - } - - /// Load input objects from the store to be used as checked - /// input while executing a transaction - pub(crate) fn load_input_objects( - &self, - object_refs: impl IntoIterator + 'static, - ) -> impl Iterator + '_ { - object_refs.into_iter().filter_map(|object_ref| { - Some(ObjectReadResult::new( - InputObjectKind::ImmOrOwnedMoveObject(object_ref), - self.store.get_object(&object_ref.0)?.clone().into(), - )) - }) - } - - /// Load packages from the store to be used as checked - /// input while executing a transaction - pub(crate) fn load_packages( - &self, - object_ids: impl IntoIterator + 'static, - ) -> impl Iterator + '_ { - object_ids.into_iter().filter_map(|object_id| { - Some(ObjectReadResult::new( - InputObjectKind::MovePackage(object_id), - self.store.get_object(&object_id)?.clone().into(), - )) - }) - } - - fn checked_system_packages(&self) -> CheckedInputObjects { - CheckedInputObjects::new_for_genesis(self.load_packages(PACKAGE_DEPS).collect()) - } - - pub(crate) fn execute_pt_unmetered( - &mut self, - input_objects: CheckedInputObjects, - pt: ProgrammableTransaction, - ) -> Result { - let input_objects = input_objects.into_inner(); - let mut temporary_store = TemporaryStore::new( - &self.store, - input_objects, - vec![], - self.tx_context.digest(), - &self.protocol_config, - ); - let mut gas_charger = GasCharger::new_unmetered(self.tx_context.digest()); - programmable_transactions::execution::execute::( - &self.protocol_config, - self.metrics.clone(), - &self.move_vm, - &mut temporary_store, - &mut self.tx_context, - &mut gas_charger, - pt, - )?; - temporary_store.update_object_version_and_prev_tx(); - Ok(temporary_store.into_inner()) - } - - /// Process the foundry outputs as follows: - /// - /// * Publish the generated packages using a tailored unmetered executor. - /// * For each native token, map the [`TokenId`] to the [`ObjectID`] of the - /// coin that holds its total supply. - /// * Update the inner store with the created objects. - pub(super) fn create_foundries<'a>( - &mut self, - foundries: impl IntoIterator, - ) -> Result> { - let mut res = Vec::new(); - for (header, foundry, pkg) in foundries { - let mut created_objects = CreatedObjects::default(); - let modules = package_module_bytes(&pkg)?; - let deps = self.checked_system_packages(); - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - let upgrade_cap = builder.command(Command::Publish(modules, PACKAGE_DEPS.into())); - // We make a dummy transfer because the `UpgradeCap` does - // not have the drop ability. - // - // We ignore it in the genesis, to render the package immutable. - builder.transfer_arg(Default::default(), upgrade_cap); - builder.finish() - }; - let InnerTemporaryStore { written, .. } = self.execute_pt_unmetered(deps, pt)?; - // Get on-chain info - let mut minted_coin_id = None::; - let mut foundry_package = None::<&MovePackage>; - for object in written.values() { - if object.is_coin() { - minted_coin_id = Some(object.id()); - created_objects.set_minted_coin(object.id())?; - } else if object.type_().map_or(false, |t| t.is_coin_metadata()) { - created_objects.set_coin_metadata(object.id())? - } else if object.type_().map_or(false, |t| { - t.address() == STARDUST_ADDRESS - && t.module().as_str() == "capped_coin" - && t.name().as_str() == "MaxSupplyPolicy" - }) { - created_objects.set_max_supply_policy(object.id())? - } else if object.is_package() { - foundry_package = Some( - object - .data - .try_as_package() - .expect("already verified this is a package"), - ); - created_objects.set_package(object.id())?; - } - } - let (minted_coin_id, foundry_package) = ( - minted_coin_id.expect("a coin must have been minted"), - foundry_package.expect("there should be a published package"), - ); - self.native_tokens.insert( - foundry.token_id(), - FoundryLedgerData::new( - minted_coin_id, - foundry_package, - SimpleTokenSchemeU64::try_from(foundry.token_scheme().as_simple())?, - ), - ); - - // Create the foundry gas coin object. - let gas_coin = create_foundry_gas_coin( - &header.output_id(), - foundry, - &self.tx_context, - foundry_package.version(), - &self.protocol_config, - )?; - created_objects.set_coin(gas_coin.id())?; - self.store.insert_object(gas_coin); - - self.store.finish( - written - .into_iter() - // We ignore the [`UpgradeCap`] objects. - .filter(|(_, object)| object.struct_tag() != Some(UpgradeCap::type_())) - .collect(), - ); - res.push((header.output_id(), created_objects)); - } - Ok(res) - } - - pub(super) fn create_alias_objects( - &mut self, - header: &OutputHeader, - alias: &AliasOutput, - ) -> Result { - let mut created_objects = CreatedObjects::default(); - - // Take the Alias ID set in the output or, if its zeroized, compute it from the - // Output ID. - let alias_id = ObjectID::new(*alias.alias_id().or_from_output_id(&header.output_id())); - let move_alias = crate::stardust::types::Alias::try_from_stardust(alias_id, alias)?; - - // TODO: We should ensure that no circular ownership exists. - let alias_output_owner = stardust_to_sui_address_owner(alias.governor_address())?; - - let package_deps = InputObjects::new(self.load_packages(PACKAGE_DEPS).collect()); - let version = package_deps.lamport_timestamp(&[]); - - let move_alias_object = move_alias.to_genesis_object( - alias_output_owner, - &self.protocol_config, - &self.tx_context, - version, - )?; - let move_alias_object_ref = move_alias_object.compute_object_reference(); - - self.store.insert_object(move_alias_object); - - let (bag, version, fields) = self.create_bag_with_pt(alias.native_tokens())?; - created_objects.set_native_tokens(fields)?; - - let move_alias_output = crate::stardust::types::AliasOutput::try_from_stardust( - self.tx_context.fresh_id(), - alias, - bag, - )?; - - // The bag will be wrapped into the alias output object, so - // by equating their versions we emulate a ptb. - let move_alias_output_object = move_alias_output.to_genesis_object( - alias_output_owner, - &self.protocol_config, - &self.tx_context, - version, - )?; - let move_alias_output_object_ref = move_alias_output_object.compute_object_reference(); - - created_objects.set_output(move_alias_output_object.id())?; - self.store.insert_object(move_alias_output_object); - - // Attach the Alias to the Alias Output as a dynamic object field via the - // attach_alias convenience method. - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - - let alias_output_arg = - builder.obj(ObjectArg::ImmOrOwnedObject(move_alias_output_object_ref))?; - let alias_arg = builder.obj(ObjectArg::ImmOrOwnedObject(move_alias_object_ref))?; - - builder.programmable_move_call( - STARDUST_PACKAGE_ID, - ident_str!("alias_output").into(), - ident_str!("attach_alias").into(), - vec![], - vec![alias_output_arg, alias_arg], - ); - - builder.finish() - }; - - let input_objects = CheckedInputObjects::new_for_genesis( - self.load_input_objects([move_alias_object_ref, move_alias_output_object_ref]) - .chain(self.load_packages(PACKAGE_DEPS)) - .collect(), - ); - - let InnerTemporaryStore { written, .. } = self.execute_pt_unmetered(input_objects, pt)?; - self.store.finish(written); - - Ok(created_objects) - } - - /// Create a [`Bag`] of balances of native tokens executing a programmable - /// transaction block. - pub(crate) fn create_bag_with_pt( - &mut self, - native_tokens: &NativeTokens, - ) -> Result<(Bag, SequenceNumber, Vec)> { - let mut object_deps = Vec::with_capacity(native_tokens.len()); - let mut foundry_package_deps = Vec::with_capacity(native_tokens.len()); - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - let bag = pt::bag_new(&mut builder); - for token in native_tokens.iter() { - let Some(foundry_ledger_data) = self.native_tokens.get_mut(token.token_id()) else { - anyhow::bail!("foundry for native token has not been published"); - }; - - let Some(foundry_coin) = self.store.get_object(&foundry_ledger_data.minted_coin_id) - else { - anyhow::bail!("foundry coin should exist"); - }; - let object_ref = foundry_coin.compute_object_reference(); - - object_deps.push(object_ref); - foundry_package_deps.push(foundry_ledger_data.package_id); - - let token_type = foundry_ledger_data.canonical_coin_type(); - - let adjusted_amount = foundry_ledger_data - .token_scheme_u64 - .adjust_tokens(token.amount()); - - foundry_ledger_data.minted_value = foundry_ledger_data - .minted_value - .checked_sub(adjusted_amount) - .ok_or_else(|| anyhow::anyhow!("underflow splitting native token balance"))?; - - let balance = pt::coin_balance_split( - &mut builder, - object_ref, - token_type.parse()?, - adjusted_amount, - )?; - pt::bag_add(&mut builder, bag, balance, token_type)?; - } - - // The `Bag` object does not have the `drop` ability so we have to use it - // in the transaction block. Therefore we transfer it to the `0x0` address. - // - // Nevertheless, we only store the contents of the object, and thus the - // ownership metadata are irrelevant to us. This is a dummy transfer - // then to satisfy the VM. - builder.transfer_arg(Default::default(), bag); - builder.finish() - }; - let checked_input_objects = CheckedInputObjects::new_for_genesis( - self.load_packages(PACKAGE_DEPS) - .chain(self.load_packages(foundry_package_deps)) - .chain(self.load_input_objects(object_deps)) - .collect(), - ); - let InnerTemporaryStore { - mut written, - input_objects, - .. - } = self.execute_pt_unmetered(checked_input_objects, pt)?; - let bag_object = written - .iter() - // We filter out the dynamic-field objects that are owned by the bag - // and we should be left with only the bag - .find_map(|(id, object)| { - (!input_objects.contains_key(id) && !object.is_child_object()).then_some(id) - }) - .copied() - .and_then(|id| written.remove(&id)) - .ok_or_else(|| anyhow::anyhow!("the bag should have been created"))?; - written.remove(&bag_object.id()); - let field_ids = written - .iter() - .filter_map(|(id, object)| object.to_rust::>().map(|_| *id)) - .collect(); - // Save the modified coins - self.store.finish(written); - // Return bag - let bag = bcs::from_bytes( - bag_object - .data - .try_as_move() - .expect("this should be a move object") - .contents(), - ) - .expect("this should be a valid Bag Move object"); - Ok((bag, bag_object.version(), field_ids)) - } - - /// Create [`Coin`] objects representing native tokens in the ledger. - fn create_native_token_coins( - &mut self, - native_tokens: &NativeTokens, - owner: SuiAddress, - ) -> Result> { - let mut object_deps = Vec::with_capacity(native_tokens.len()); - let mut foundry_package_deps = Vec::with_capacity(native_tokens.len()); - let mut foundry_coins = Vec::with_capacity(native_tokens.len()); - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - for token in native_tokens.iter() { - let Some(foundry_ledger_data) = self.native_tokens.get_mut(token.token_id()) else { - anyhow::bail!("foundry for native token has not been published"); - }; - - let Some(foundry_coin) = self.store.get_object(&foundry_ledger_data.minted_coin_id) - else { - anyhow::bail!("foundry coin should exist"); - }; - let object_ref = foundry_coin.compute_object_reference(); - foundry_coins.push(foundry_coin.id()); - - object_deps.push(object_ref); - foundry_package_deps.push(foundry_ledger_data.package_id); - - // Pay using that object - let adjusted_amount = foundry_ledger_data - .token_scheme_u64 - .adjust_tokens(token.amount()); - - foundry_ledger_data.minted_value = foundry_ledger_data - .minted_value - .checked_sub(adjusted_amount) - .ok_or_else(|| anyhow::anyhow!("underflow splitting native token balance"))?; - - builder.pay(vec![object_ref], vec![owner], vec![adjusted_amount])?; - } - - builder.finish() - }; - let checked_input_objects = CheckedInputObjects::new_for_genesis( - self.load_packages(PACKAGE_DEPS) - .chain(self.load_packages(foundry_package_deps)) - .chain(self.load_input_objects(object_deps)) - .collect(), - ); - // Execute - let InnerTemporaryStore { written, .. } = - self.execute_pt_unmetered(checked_input_objects, pt)?; - - let coin_ids = written - .keys() - // Linear search is ok due to the expected very small size of - // `foundry_coins` - .filter(|id| !foundry_coins.contains(id)) - .copied() - .collect(); - - // Save the modified coin - self.store.finish(written); - Ok(coin_ids) - } - - /// This implements the control flow in - /// crates/sui-framework/packages/stardust/basic_migration_graph.svg - pub(super) fn create_basic_objects( - &mut self, - header: &OutputHeader, - basic_output: &BasicOutput, - ) -> Result { - let mut data = - crate::stardust::types::output::BasicOutput::new(header.clone(), basic_output)?; - let owner: SuiAddress = basic_output.address().to_string().parse()?; - let mut created_objects = CreatedObjects::default(); - - // The minimum version of the manually created objects - let package_deps = InputObjects::new(self.load_packages(PACKAGE_DEPS).collect()); - let mut version = package_deps.lamport_timestamp(&[]); - let object = if data.is_simple_coin() { - if !basic_output.native_tokens().is_empty() { - let coins = self.create_native_token_coins(basic_output.native_tokens(), owner)?; - created_objects.set_native_tokens(coins)?; - } - let coin = data.into_genesis_coin_object( - owner, - &self.protocol_config, - &self.tx_context, - version, - )?; - created_objects.set_coin(coin.id())?; - coin - } else { - if !basic_output.native_tokens().is_empty() { - let fields; - // The bag will be wrapped into the basic output object, so - // by equating their versions we emulate a ptb. - (data.native_tokens, version, fields) = - self.create_bag_with_pt(basic_output.native_tokens())?; - created_objects.set_native_tokens(fields)?; - } else { - // Overwrite the default 0 UID of `Bag::default()`, since we won't - // be creating a new bag in this code path. - data.native_tokens.id = UID::new(self.tx_context.fresh_id()); - } - let object = - data.to_genesis_object(owner, &self.protocol_config, &self.tx_context, version)?; - created_objects.set_output(object.id())?; - object - }; - - self.store.insert_object(object); - Ok(created_objects) - } - - /// Creates [`TimeLock>`] objects which represent vested - /// rewards that were created during the stardust upgrade on IOTA - /// mainnet. - pub(super) fn create_timelock_object( - &mut self, - output_id: OutputId, - basic_output: &BasicOutput, - target_milestone_timestamp: u32, - ) -> Result { - let mut created_objects = CreatedObjects::default(); - - let owner: SuiAddress = basic_output.address().to_string().parse()?; - - let package_deps = InputObjects::new(self.load_packages(PACKAGE_DEPS).collect()); - let version = package_deps.lamport_timestamp(&[]); - - let timelock = - timelock::try_from_stardust(output_id, basic_output, target_milestone_timestamp)?; - - let object = timelock::to_genesis_object( - timelock, - owner, - &self.protocol_config, - &self.tx_context, - version, - )?; - - created_objects.set_output(object.id())?; - - self.store.insert_object(object); - Ok(created_objects) - } - - pub(super) fn create_nft_objects( - &mut self, - header: &OutputHeader, - nft: &NftOutput, - ) -> Result { - let mut created_objects = CreatedObjects::default(); - - // Take the Nft ID set in the output or, if its zeroized, compute it from the - // Output ID. - let nft_id = ObjectID::new(*nft.nft_id().or_from_output_id(&header.output_id())); - let move_nft = Nft::try_from_stardust(nft_id, nft)?; - - // TODO: We should ensure that no circular ownership exists. - let nft_output_owner_address = stardust_to_sui_address(nft.address())?; - let nft_output_owner = stardust_to_sui_address_owner(nft.address())?; - - let package_deps = InputObjects::new(self.load_packages(PACKAGE_DEPS).collect()); - let version = package_deps.lamport_timestamp(&[]); - let move_nft_object = move_nft.to_genesis_object( - nft_output_owner, - &self.protocol_config, - &self.tx_context, - version, - )?; - - let move_nft_object_ref = move_nft_object.compute_object_reference(); - self.store.insert_object(move_nft_object); - - let (bag, version, fields) = self.create_bag_with_pt(nft.native_tokens())?; - created_objects.set_native_tokens(fields)?; - let move_nft_output = crate::stardust::types::NftOutput::try_from_stardust( - self.tx_context.fresh_id(), - nft, - bag, - )?; - - // The bag will be wrapped into the nft output object, so - // by equating their versions we emulate a ptb. - let move_nft_output_object = move_nft_output.to_genesis_object( - nft_output_owner_address, - &self.protocol_config, - &self.tx_context, - version, - )?; - let move_nft_output_object_ref = move_nft_output_object.compute_object_reference(); - created_objects.set_output(move_nft_output_object.id())?; - self.store.insert_object(move_nft_output_object); - - // Attach the Nft to the Nft Output as a dynamic object field via the attach_nft - // convenience method. - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - - let nft_output_arg = - builder.obj(ObjectArg::ImmOrOwnedObject(move_nft_output_object_ref))?; - let nft_arg = builder.obj(ObjectArg::ImmOrOwnedObject(move_nft_object_ref))?; - builder.programmable_move_call( - STARDUST_PACKAGE_ID, - ident_str!("nft_output").into(), - ident_str!("attach_nft").into(), - vec![], - vec![nft_output_arg, nft_arg], - ); - - builder.finish() - }; - - let input_objects = CheckedInputObjects::new_for_genesis( - self.load_input_objects([move_nft_object_ref, move_nft_output_object_ref]) - .chain(self.load_packages(PACKAGE_DEPS)) - .collect(), - ); - - let InnerTemporaryStore { written, .. } = self.execute_pt_unmetered(input_objects, pt)?; - self.store.finish(written); - - Ok(created_objects) - } -} - -#[cfg(test)] -impl Executor { - /// Set the [`TxContext`] of the [`Executor`]. - pub(crate) fn with_tx_context(mut self, tx_context: TxContext) -> Self { - self.tx_context = tx_context; - self - } - - /// Set the [`InMemoryStorage`] of the [`Executor`]. - pub(crate) fn with_store(mut self, store: InMemoryStorage) -> Self { - self.store = store; - self - } -} - -mod pt { - use super::*; - use crate::stardust::migration::NATIVE_TOKEN_BAG_KEY_TYPE; - - pub fn coin_balance_split( - builder: &mut ProgrammableTransactionBuilder, - foundry_coin_ref: ObjectRef, - token_type_tag: TypeTag, - amount: u64, - ) -> Result { - let foundry_coin_ref = builder.obj(ObjectArg::ImmOrOwnedObject(foundry_coin_ref))?; - let amount = builder.pure(amount)?; - let coin = builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, - ident_str!("coin").into(), - ident_str!("split").into(), - vec![token_type_tag.clone()], - vec![foundry_coin_ref, amount], - ); - Ok(builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, - ident_str!("coin").into(), - ident_str!("into_balance").into(), - vec![token_type_tag], - vec![coin], - )) - } - - pub fn bag_add( - builder: &mut ProgrammableTransactionBuilder, - bag: Argument, - balance: Argument, - token_type: String, - ) -> Result<()> { - let key_type: StructTag = NATIVE_TOKEN_BAG_KEY_TYPE.parse()?; - let value_type = Balance::type_(token_type.parse::()?); - let token_name = builder.pure(token_type)?; - builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, - ident_str!("bag").into(), - ident_str!("add").into(), - vec![key_type.into(), value_type.into()], - vec![bag, token_name, balance], - ); - Ok(()) - } - - pub fn bag_new(builder: &mut ProgrammableTransactionBuilder) -> Argument { - builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, - ident_str!("bag").into(), - ident_str!("new").into(), - vec![], - vec![], - ) - } -} - -/// On-chain data about the objects created while -/// publishing foundry packages -pub(crate) struct FoundryLedgerData { - pub(crate) minted_coin_id: ObjectID, - pub(crate) coin_type_origin: TypeOrigin, - pub(crate) package_id: ObjectID, - pub(crate) token_scheme_u64: SimpleTokenSchemeU64, - pub(crate) minted_value: u64, -} - -impl FoundryLedgerData { - /// Store the minted coin `ObjectID` and derive data from the foundry - /// package. - /// - /// # Panic - /// - /// Panics if the package does not contain any [`TypeOrigin`]. - fn new( - minted_coin_id: ObjectID, - foundry_package: &MovePackage, - token_scheme_u64: SimpleTokenSchemeU64, - ) -> Self { - Self { - minted_coin_id, - // There must be only one type created in the foundry package. - coin_type_origin: foundry_package.type_origin_table()[0].clone(), - package_id: foundry_package.id(), - minted_value: token_scheme_u64.circulating_supply(), - token_scheme_u64, - } - } - - pub(crate) fn canonical_coin_type(&self) -> String { - format!( - "{}::{}::{}", - self.coin_type_origin.package, - self.coin_type_origin.module_name, - self.coin_type_origin.struct_name - ) - } -} diff --git a/crates/sui-genesis-builder/src/stardust/migration/mod.rs b/crates/sui-genesis-builder/src/stardust/migration/mod.rs deleted file mode 100644 index e9876456db1..00000000000 --- a/crates/sui-genesis-builder/src/stardust/migration/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -mod executor; -#[allow(clippy::module_inception)] -mod migration; -#[cfg(test)] -mod tests; -pub mod verification; - -pub use migration::*; diff --git a/crates/sui-genesis-builder/src/stardust/migration/tests/alias.rs b/crates/sui-genesis-builder/src/stardust/migration/tests/alias.rs deleted file mode 100644 index 32e2fe3202c..00000000000 --- a/crates/sui-genesis-builder/src/stardust/migration/tests/alias.rs +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use std::str::FromStr; - -use iota_sdk::{ - types::block::{ - address::{Address, Ed25519Address}, - output::{ - feature::{Irc30Metadata, IssuerFeature, MetadataFeature, SenderFeature}, - unlock_condition::{ - AddressUnlockCondition, GovernorAddressUnlockCondition, - StateControllerAddressUnlockCondition, - }, - AliasId, AliasOutput as StardustAlias, AliasOutputBuilder, Feature, NativeToken, NftId, - NftOutputBuilder, SimpleTokenScheme, - }, - }, - U256, -}; -use move_core_types::ident_str; -use sui_types::{ - base_types::ObjectID, - dynamic_field::{derive_dynamic_field_id, DynamicFieldInfo}, - id::UID, - object::{Object, Owner}, - TypeTag, -}; - -use super::ExpectedAssets; -use crate::stardust::{ - migration::tests::{ - create_foundry, extract_native_token_from_bag, object_migration_with_object_owner, - random_output_header, run_migration, - }, - types::{ - snapshot::OutputHeader, stardust_to_sui_address, Alias, AliasOutput, - ALIAS_DYNAMIC_OBJECT_FIELD_KEY, ALIAS_DYNAMIC_OBJECT_FIELD_KEY_TYPE, - ALIAS_OUTPUT_MODULE_NAME, NFT_OUTPUT_MODULE_NAME, - }, -}; - -fn migrate_alias( - header: OutputHeader, - stardust_alias: StardustAlias, -) -> anyhow::Result<(ObjectID, Alias, AliasOutput, Object, Object)> { - let output_id = header.output_id(); - let alias_id: AliasId = stardust_alias - .alias_id() - .or_from_output_id(&output_id) - .to_owned(); - - let (executor, objects_map) = run_migration([(header, stardust_alias.into())])?; - - // Ensure the migrated objects exist under the expected identifiers. - let alias_object_id = ObjectID::new(*alias_id); - let created_objects = objects_map - .get(&output_id) - .expect("alias output should have created objects"); - - let alias_object = executor - .store() - .objects() - .values() - .find(|obj| obj.id() == alias_object_id) - .expect("alias object should be present in the migrated snapshot"); - assert_eq!(alias_object.struct_tag().unwrap(), Alias::tag()); - - let alias_output_object = executor - .store() - .get_object(created_objects.output().unwrap()) - .unwrap(); - assert_eq!( - alias_output_object.struct_tag().unwrap(), - AliasOutput::tag() - ); - - // Version is set to 1 when the alias is created based on the computed lamport - // timestamp. When the alias is attached to the alias output, the version - // should be incremented. - assert!( - alias_object.version().value() > 1, - "alias object version should have been incremented" - ); - assert!( - alias_output_object.version().value() > 1, - "alias output object version should have been incremented" - ); - - let alias_output: AliasOutput = - bcs::from_bytes(alias_output_object.data.try_as_move().unwrap().contents()).unwrap(); - let alias: Alias = - bcs::from_bytes(alias_object.data.try_as_move().unwrap().contents()).unwrap(); - - Ok(( - alias_object_id, - alias, - alias_output, - alias_object.clone(), - alias_output_object.clone(), - )) -} - -/// Test that the migrated alias objects in the snapshot contain the expected -/// data. -#[test] -fn alias_migration_with_full_features() { - let alias_id = AliasId::new(rand::random()); - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let header = random_output_header(); - - let stardust_alias = AliasOutputBuilder::new_with_amount(1_000_000, alias_id) - .add_unlock_condition(StateControllerAddressUnlockCondition::new(random_address)) - .add_unlock_condition(GovernorAddressUnlockCondition::new(random_address)) - .with_state_metadata([0xff; 1]) - .with_features(vec![ - Feature::Metadata(MetadataFeature::new([0xdd; 1]).unwrap()), - Feature::Sender(SenderFeature::new(random_address)), - ]) - .with_immutable_features(vec![ - Feature::Metadata(MetadataFeature::new([0xaa; 1]).unwrap()), - Feature::Issuer(IssuerFeature::new(random_address)), - ]) - .with_state_index(3) - .finish() - .unwrap(); - - let (alias_object_id, alias, alias_output, alias_object, alias_output_object) = - migrate_alias(header, stardust_alias.clone()).unwrap(); - let expected_alias = Alias::try_from_stardust(alias_object_id, &stardust_alias).unwrap(); - - // The bag is tested separately. - assert_eq!(stardust_alias.amount(), alias_output.iota.value()); - // The ID is newly generated, so we don't know the exact value, but it should - // not be zero. - assert_ne!(alias_output.id, UID::new(ObjectID::ZERO)); - assert_ne!( - alias_output.id, - UID::new(ObjectID::new( - stardust_alias.alias_id().as_slice().try_into().unwrap() - )) - ); - - assert_eq!(expected_alias, alias); - - // The Alias Object should be in a dynamic object field. - let alias_owner = derive_dynamic_field_id( - alias_output_object.id(), - &TypeTag::from(DynamicFieldInfo::dynamic_object_field_wrapper( - // The key type of the dynamic object field. - TypeTag::from_str(ALIAS_DYNAMIC_OBJECT_FIELD_KEY_TYPE).unwrap(), - )), - &bcs::to_bytes(ALIAS_DYNAMIC_OBJECT_FIELD_KEY).unwrap(), - ) - .unwrap(); - assert_eq!(alias_object.owner, Owner::ObjectOwner(alias_owner.into())); - - let alias_output_owner = - Owner::AddressOwner(stardust_to_sui_address(stardust_alias.governor_address()).unwrap()); - assert_eq!(alias_output_object.owner, alias_output_owner); -} - -/// Test that an Alias with a zeroed ID is migrated to an Alias Object with its -/// UID set to the hashed Output ID. -#[test] -fn alias_migration_with_zeroed_id() { - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let header = random_output_header(); - - let stardust_alias = AliasOutputBuilder::new_with_amount(1_000_000, AliasId::null()) - .add_unlock_condition(StateControllerAddressUnlockCondition::new(random_address)) - .add_unlock_condition(GovernorAddressUnlockCondition::new(random_address)) - .finish() - .unwrap(); - - // If this function does not panic, then the created aliases - // were found at the correct non-zeroed Alias ID. - migrate_alias(header, stardust_alias).unwrap(); -} - -/// Test that an Alias owned by another Alias can be received by the owning -/// object. -/// -/// The PTB sends the extracted assets to the null address since they must be -/// used in the transaction. -#[test] -fn alias_migration_with_alias_owner() { - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - - let alias1_header = random_output_header(); - let stardust_alias1 = - AliasOutputBuilder::new_with_amount(1_000_000, AliasId::new(rand::random())) - .add_unlock_condition(StateControllerAddressUnlockCondition::new(random_address)) - .add_unlock_condition(GovernorAddressUnlockCondition::new(random_address)) - .finish() - .unwrap(); - - let alias2_header = random_output_header(); - // stardust_alias1 is the owner of stardust_alias2. - let stardust_alias2 = - AliasOutputBuilder::new_with_amount(2_000_000, AliasId::new(rand::random())) - .add_unlock_condition(StateControllerAddressUnlockCondition::new(Address::from( - *stardust_alias1.alias_id(), - ))) - .add_unlock_condition(GovernorAddressUnlockCondition::new(Address::from( - *stardust_alias1.alias_id(), - ))) - .finish() - .unwrap(); - - object_migration_with_object_owner( - alias1_header.output_id(), - alias2_header.output_id(), - [ - (alias1_header.clone(), stardust_alias1.into()), - (alias2_header.clone(), stardust_alias2.into()), - ], - ALIAS_OUTPUT_MODULE_NAME, - ALIAS_OUTPUT_MODULE_NAME, - ident_str!("unlock_alias_address_owned_alias"), - ) - .unwrap(); -} - -/// Test that an Alias owned by an NFT can be received by the owning object. -#[test] -fn alias_migration_with_nft_owner() { - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - - let nft_header = random_output_header(); - let nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::new(rand::random())) - .add_unlock_condition(AddressUnlockCondition::new(random_address)) - .finish() - .unwrap(); - - let alias_header = random_output_header(); - // nft is the owner (governor) of alias. - let alias = AliasOutputBuilder::new_with_amount(2_000_000, AliasId::new(rand::random())) - .add_unlock_condition(StateControllerAddressUnlockCondition::new( - Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()), - )) - .add_unlock_condition(GovernorAddressUnlockCondition::new(Address::from( - *nft.nft_id(), - ))) - .finish() - .unwrap(); - - object_migration_with_object_owner( - nft_header.output_id(), - alias_header.output_id(), - [ - (nft_header.clone(), nft.into()), - (alias_header.clone(), alias.into()), - ], - NFT_OUTPUT_MODULE_NAME, - ALIAS_OUTPUT_MODULE_NAME, - ident_str!("unlock_nft_address_owned_alias"), - ) - .unwrap(); -} - -/// Test that an Alias that owns Native Tokens can extract those tokens from the -/// contained bag. -#[test] -fn alias_migration_with_native_tokens() { - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let (foundry_header, foundry_output) = create_foundry( - 0, - SimpleTokenScheme::new(U256::from(100_000), U256::from(0), U256::from(100_000_000)) - .unwrap(), - Irc30Metadata::new("Rustcoin\u{245}", "Rust''\n\tCöin", 0) - .with_description("The description of Rustcöin.\n Nice!"), - AliasId::null(), - ) - .unwrap(); - let native_token = NativeToken::new(foundry_output.id().into(), 100).unwrap(); - - let alias_header = random_output_header(); - let alias = AliasOutputBuilder::new_with_amount(1_000_000, AliasId::new(rand::random())) - .add_unlock_condition(StateControllerAddressUnlockCondition::new(random_address)) - .add_unlock_condition(GovernorAddressUnlockCondition::new(random_address)) - .add_native_token(native_token) - .finish() - .unwrap(); - - extract_native_token_from_bag( - alias_header.output_id(), - [ - (alias_header.clone(), alias.into()), - (foundry_header, foundry_output.into()), - ], - ALIAS_OUTPUT_MODULE_NAME, - native_token, - ExpectedAssets::BalanceBagObject, - ) - .unwrap(); -} diff --git a/crates/sui-genesis-builder/src/stardust/migration/tests/basic.rs b/crates/sui-genesis-builder/src/stardust/migration/tests/basic.rs deleted file mode 100644 index 08e91b6e57a..00000000000 --- a/crates/sui-genesis-builder/src/stardust/migration/tests/basic.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use iota_sdk::types::block::{ - address::Ed25519Address, - output::{ - feature::Irc30Metadata, unlock_condition::AddressUnlockCondition, AliasId, - BasicOutputBuilder, NativeToken, SimpleTokenScheme, - }, -}; - -use crate::stardust::migration::{ - tests::{create_foundry, random_output_header}, - Migration, -}; - -#[test] -fn basic_simple_coin_migration_with_native_token() { - let (foundry_header, foundry_output) = create_foundry( - 0, - SimpleTokenScheme::new(100_000, 0, 100_000_000).unwrap(), - Irc30Metadata::new("Rustcoin", "Rust", 0), - AliasId::null(), - ) - .unwrap(); - let native_token = NativeToken::new(foundry_output.id().into(), 100).unwrap(); - - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let header = random_output_header(); - - let stardust_basic = BasicOutputBuilder::new_with_amount(1_000_000) - .add_unlock_condition(AddressUnlockCondition::new(random_address)) - .add_native_token(native_token) - .finish() - .unwrap(); - - let outputs = [ - (foundry_header, foundry_output.into()), - (header, stardust_basic.into()), - ]; - let mut migration = Migration::new(1).unwrap(); - migration.run_migration(outputs).unwrap(); -} diff --git a/crates/sui-genesis-builder/src/stardust/migration/tests/executor.rs b/crates/sui-genesis-builder/src/stardust/migration/tests/executor.rs deleted file mode 100644 index f8f89c43227..00000000000 --- a/crates/sui-genesis-builder/src/stardust/migration/tests/executor.rs +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use iota_sdk::types::block::{ - address::AliasAddress, - output::{ - unlock_condition::ImmutableAliasAddressUnlockCondition, AliasId, FoundryOutputBuilder, - NativeToken, NativeTokens, SimpleTokenScheme, UnlockCondition, - }, -}; -use sui_protocol_config::ProtocolVersion; -use sui_types::{ - balance::Balance, - dynamic_field::{derive_dynamic_field_id, Field}, - object::Owner, -}; - -use crate::stardust::{ - migration::{ - executor::Executor, migration::NATIVE_TOKEN_BAG_KEY_TYPE, tests::random_output_header, - }, - native_token::{ - package_builder, - package_data::{NativeTokenModuleData, NativeTokenPackageData}, - }, -}; - -#[test] -fn create_bag_with_pt() { - // Mock the foundry - let owner = AliasAddress::new(AliasId::new([0; AliasId::LENGTH])); - let supply = 1_000_000; - let token_scheme = SimpleTokenScheme::new(supply, 0, supply).unwrap(); - let header = random_output_header(); - let foundry = FoundryOutputBuilder::new_with_amount(1000, 1, token_scheme.into()) - .with_unlock_conditions([UnlockCondition::from( - ImmutableAliasAddressUnlockCondition::new(owner), - )]) - .finish_with_params(supply) - .unwrap(); - let foundry_id = foundry.id(); - let foundry_package_data = NativeTokenPackageData::new( - "wat", - NativeTokenModuleData::new( - foundry_id, "wat", "WAT", 0, "WAT", supply, supply, "wat", "wat", None, owner, - ), - ); - let foundry_package = package_builder::build_and_compile(foundry_package_data).unwrap(); - - // Execution - let mut executor = Executor::new(ProtocolVersion::MAX).unwrap(); - let object_count = executor.store().objects().len(); - executor - .create_foundries([(&header, &foundry, foundry_package)]) - .unwrap(); - // Foundry package publication creates five objects - // - // * The package - // * Coin metadata - // * MaxSupplyPolicy - // * The total supply coin - // * The foundry gas coin - assert_eq!(executor.store().objects().len() - object_count, 5); - assert!(executor.native_tokens().get(&foundry_id.into()).is_some()); - let initial_supply_coin_object = executor - .store() - .objects() - .values() - .find(|object| object.is_coin() && !object.is_gas_coin()) - .expect("there should be only a single coin: the total supply of native tokens"); - let coin_type_tag = initial_supply_coin_object.coin_type_maybe().unwrap(); - let initial_supply_coin_data = initial_supply_coin_object.as_coin_maybe().unwrap(); - - // Mock the native token - let token_amount = 10_000; - let native_token = NativeToken::new(foundry_id.into(), token_amount).unwrap(); - - // Create the bag - let (bag, _, _) = executor - .create_bag_with_pt(&NativeTokens::from_vec(vec![native_token]).unwrap()) - .unwrap(); - assert!(executor.store().get_object(bag.id.object_id()).is_none()); - - // Verify the mutation of the foundry coin with the total supply - let mutated_supply_coin = executor - .store() - .get_object(initial_supply_coin_data.id()) - .unwrap() - .as_coin_maybe() - .unwrap(); - assert_eq!(mutated_supply_coin.value(), supply - token_amount); - - // Get the dynamic fields (df) - let tokens = executor - .store() - .objects() - .values() - .filter(|object| object.is_child_object()) - .collect::>(); - assert_eq!(tokens.len(), 1); - assert_eq!( - tokens[0].owner, - Owner::ObjectOwner((*bag.id.object_id()).into()) - ); - let token_as_df = tokens[0].to_rust::>().unwrap(); - // Verify name - let expected_name = coin_type_tag.to_canonical_string(true); - assert_eq!(token_as_df.name, expected_name); - // Verify value - let expected_balance = Balance::new(token_amount); - assert_eq!(token_as_df.value, expected_balance); - // Verify df id - let expected_id = derive_dynamic_field_id( - *bag.id.object_id(), - &NATIVE_TOKEN_BAG_KEY_TYPE.parse().unwrap(), - &bcs::to_bytes(&expected_name).unwrap(), - ) - .unwrap(); - assert_eq!(*token_as_df.id.object_id(), expected_id); -} diff --git a/crates/sui-genesis-builder/src/stardust/migration/tests/foundry.rs b/crates/sui-genesis-builder/src/stardust/migration/tests/foundry.rs deleted file mode 100644 index 9e82c15b2a5..00000000000 --- a/crates/sui-genesis-builder/src/stardust/migration/tests/foundry.rs +++ /dev/null @@ -1,391 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use anyhow::{anyhow, Result}; -use iota_sdk::{ - types::block::output::{ - feature::Irc30Metadata, AliasId, FoundryOutput, Output, SimpleTokenScheme, - }, - Url, U256, -}; -use move_core_types::language_storage::TypeTag; -use sui_protocol_config::ProtocolConfigValue::u64; -use sui_types::{ - balance::Balance, - base_types::{MoveObjectType, ObjectID, SuiAddress}, - coin::CoinMetadata, - gas_coin::GAS, - object::Object, -}; - -use crate::stardust::{ - migration::tests::{create_foundry, run_migration}, - types::{ - capped_coin::MaxSupplyPolicy, snapshot::OutputHeader, stardust_to_sui_address, - stardust_to_sui_address_owner, - }, -}; - -type PackageObject = Object; -type CoinObject = Object; -type MintedCoinObject = Object; -type CoinMetadataObject = Object; -type MaxSupplyPolicyObject = Object; - -fn migrate_foundry( - header: OutputHeader, - foundry: FoundryOutput, -) -> Result<( - PackageObject, - CoinObject, - MintedCoinObject, - CoinMetadataObject, - MaxSupplyPolicyObject, -)> { - let output_id = header.output_id(); - - let (executor, objects_map) = run_migration([(header, Output::Foundry(foundry))])?; - - let created_objects_ids = objects_map - .get(&output_id) - .ok_or(anyhow!("missing created objects"))?; - - let created_objects = executor.into_objects(); - - assert_eq!(created_objects.len(), 5); - - let package_id = *created_objects_ids.package()?; - let coin_id = *created_objects_ids.coin()?; - let minted_coin_id = *created_objects_ids.minted_coin()?; - let coin_metadata_id = *created_objects_ids.coin_metadata()?; - let max_supply_policy_id = *created_objects_ids.max_supply_policy()?; - - let package_object = created_objects - .iter() - .find(|object| object.id() == package_id) - .ok_or(anyhow!("missing package object"))?; - let coin_object = created_objects - .iter() - .find(|object| object.id() == coin_id) - .ok_or(anyhow!("missing coin object"))?; - let minted_coin_object = created_objects - .iter() - .find(|object| object.id() == minted_coin_id) - .ok_or(anyhow!("missing minted coin object"))?; - let coin_metadata_object = created_objects - .iter() - .find(|object| object.id() == coin_metadata_id) - .ok_or(anyhow!("missing coin metadata object"))?; - let max_supply_policy_object = created_objects - .iter() - .find(|object| object.id() == max_supply_policy_id) - .ok_or(anyhow!("missing max supply policy object"))?; - - Ok(( - package_object.clone(), - coin_object.clone(), - minted_coin_object.clone(), - coin_metadata_object.clone(), - max_supply_policy_object.clone(), - )) -} - -#[test] -fn foundry_with_simple_metadata() -> Result<()> { - let alias_id = AliasId::new(rand::random()); - let (header, foundry) = create_foundry( - 1_000_000, - SimpleTokenScheme::new(U256::from(100_000), U256::from(0), U256::from(100_000_000)) - .unwrap(), - Irc30Metadata::new("Dogecoin", "DOGE", 0), - alias_id, - ) - .unwrap(); - - let ( - package_object, - coin_object, - minted_coin_object, - coin_metadata_object, - max_supply_policy_object, - ) = migrate_foundry(header, foundry)?; - - // Check the package object. - let type_origin_table = package_object - .data - .try_as_package() - .expect("should be a package object") - .type_origin_table(); - assert_eq!(type_origin_table.len(), 1); - let coin_type_origin = type_origin_table[0].clone(); - assert_eq!(coin_type_origin.module_name, "doge"); - assert_eq!(coin_type_origin.struct_name, "DOGE"); - - // Check the coin object. - let coin = coin_object - .as_coin_maybe() - .expect("should be a coin object"); - assert_eq!( - coin_object.owner.get_owner_address().unwrap().to_string(), - alias_id.to_string() - ); - assert_eq!(coin.balance, Balance::new(1_000_000)); - - // Check the minted coin object. - let minted_coin = minted_coin_object - .as_coin_maybe() - .expect("should be a coin object"); - assert_eq!(minted_coin_object.owner, SuiAddress::ZERO); - assert_eq!(minted_coin.balance, Balance::new(100_000)); - - // Check the coin metadata object. - let coin_metadata = coin_metadata_object - .data - .try_as_move() - .expect("should be a move object"); - - let coin_metadata = CoinMetadata::from_bcs_bytes(coin_metadata.contents()).unwrap(); - assert_eq!(coin_metadata.decimals, 0); - assert_eq!(coin_metadata.name, "Dogecoin"); - assert_eq!(coin_metadata.symbol, "doge"); - assert_eq!(coin_metadata.description, ""); - assert!(coin_metadata.icon_url.is_none()); - - // Check the max supply policy object. - let max_supply_policy = max_supply_policy_object - .to_rust::() - .unwrap(); - - assert_eq!( - max_supply_policy_object.owner, - stardust_to_sui_address_owner(alias_id).unwrap() - ); - assert_eq!(max_supply_policy.maximum_supply, 100_000_000); - - let max_supply_policy_object = max_supply_policy_object.data.try_as_move().unwrap(); - let max_supply_policy_object_type = max_supply_policy_object.type_(); - assert_eq!( - max_supply_policy_object_type.module().as_str(), - "capped_coin" - ); - assert_eq!( - max_supply_policy_object_type.name().as_str(), - "MaxSupplyPolicy" - ); - - let max_supply_policy_object_type_params = - max_supply_policy_object_type.clone().into_type_params(); - assert_eq!(max_supply_policy_object_type_params.len(), 1); - let TypeTag::Struct(type_tag) = &max_supply_policy_object_type_params[0] else { - panic!("unexpected type tag") - }; - assert_eq!(type_tag.module.as_str(), "doge"); - assert_eq!(type_tag.name.as_str(), "DOGE"); - assert_eq!(type_tag.type_params.len(), 0); - assert!(max_supply_policy_object.has_public_transfer()); - - Ok(()) -} - -/// Tests the migration of a foundry output with a metadata -/// containing non-ascii characters, overflowing circulating and maximum -/// supplies - basically not the usual cases. -#[test] -fn foundry_with_special_metadata() -> Result<()> { - let alias_id = AliasId::new(rand::random()); - let (header, foundry) = create_foundry( - 1_000_000, - SimpleTokenScheme::new(U256::from(u64::MAX), U256::from(0), U256::MAX).unwrap(), - Irc30Metadata::new("Dogecoin", "DOGE❤", 123) - .with_description("Much wow") - .with_url(Url::parse("https://dogecoin.com").unwrap()) - .with_logo_url(Url::parse("https://dogecoin.com/logo.png").unwrap()) - .with_logo("0x54654"), - alias_id, - ) - .unwrap(); - - let ( - package_object, - coin_object, - minted_coin_object, - coin_metadata_object, - max_supply_policy_object, - ) = migrate_foundry(header, foundry)?; - - // Check the package object. - let type_origin_table = package_object - .data - .try_as_package() - .expect("should be a package object") - .type_origin_table(); - assert_eq!(type_origin_table.len(), 1); - let coin_type_origin = type_origin_table[0].clone(); - assert_eq!(coin_type_origin.module_name, "doge"); - assert_eq!(coin_type_origin.struct_name, "DOGE"); - - // Check the coin object. - let coin = coin_object - .as_coin_maybe() - .expect("should be a coin object"); - assert_eq!( - coin_object.owner.get_owner_address().unwrap().to_string(), - alias_id.to_string() - ); - assert_eq!(coin.balance, Balance::new(1_000_000)); - - // Check the minted coin object. - let minted_coin = minted_coin_object - .as_coin_maybe() - .expect("should be a coin object"); - assert_eq!(minted_coin_object.owner, SuiAddress::ZERO); - assert_eq!(minted_coin.balance, Balance::new(u64::MAX - 1)); - - // Check the coin metadata object. - let coin_metadata = coin_metadata_object - .data - .try_as_move() - .expect("should be a move object"); - - let coin_metadata = CoinMetadata::from_bcs_bytes(coin_metadata.contents()).unwrap(); - assert_eq!(coin_metadata.decimals, 123); - assert_eq!(coin_metadata.name, "Dogecoin"); - assert_eq!(coin_metadata.symbol, "doge"); - assert_eq!(coin_metadata.description, "Much wow"); - assert_eq!( - coin_metadata.icon_url.unwrap().to_string(), - "https://dogecoin.com/logo.png" - ); - - // Check the max supply policy object. - let max_supply_policy = max_supply_policy_object - .to_rust::() - .unwrap(); - - assert_eq!( - max_supply_policy_object.owner, - stardust_to_sui_address_owner(alias_id).unwrap() - ); - assert_eq!(max_supply_policy.maximum_supply, u64::MAX - 1); - - let max_supply_policy_object = max_supply_policy_object.data.try_as_move().unwrap(); - let max_supply_policy_object_type = max_supply_policy_object.type_(); - assert_eq!( - max_supply_policy_object_type.module().as_str(), - "capped_coin" - ); - assert_eq!( - max_supply_policy_object_type.name().as_str(), - "MaxSupplyPolicy" - ); - - let max_supply_policy_object_type_params = - max_supply_policy_object_type.clone().into_type_params(); - assert_eq!(max_supply_policy_object_type_params.len(), 1); - let TypeTag::Struct(type_tag) = &max_supply_policy_object_type_params[0] else { - panic!("unexpected type tag") - }; - assert_eq!(type_tag.module.as_str(), "doge"); - assert_eq!(type_tag.name.as_str(), "DOGE"); - assert_eq!(type_tag.type_params.len(), 0); - assert!(max_supply_policy_object.has_public_transfer()); - - Ok(()) -} - -#[test] -fn coin_ownership() -> Result<()> { - let alias_id = AliasId::new(rand::random()); - let (header, foundry) = create_foundry( - 1_000_000, - SimpleTokenScheme::new(U256::from(100_000), U256::from(0), U256::from(100_000_000)) - .unwrap(), - Irc30Metadata::new("Dogecoin", "DOGE", 0), - alias_id, - ) - .unwrap(); - - let ( - _package_object, - coin_object, - minted_coin_object, - _coin_metadata_object, - max_supply_policy_object, - ) = migrate_foundry(header, foundry)?; - - // Check the owner of the coin object. - assert_eq!( - coin_object.owner.get_owner_address().unwrap().to_string(), - alias_id.to_string() - ); - - // Check the owner of the minted coin object. - assert_eq!(minted_coin_object.owner, SuiAddress::ZERO); - - // Check the owner of the max supply policy object. - assert_eq!( - max_supply_policy_object.owner, - stardust_to_sui_address_owner(alias_id).unwrap() - ); - - Ok(()) -} - -#[test] -fn create_gas_coin() { - let (foundry_header, foundry_output) = create_foundry( - 1_000_000, - SimpleTokenScheme::new(U256::from(100_000), U256::from(0), U256::from(100_000_000)) - .unwrap(), - Irc30Metadata::new("Rustcoin", "Rust", 0), - AliasId::null(), - ) - .unwrap(); - - let output_id = foundry_header.output_id(); - let alias_address = *foundry_output.alias_address(); - - let (executor, _) = run_migration([(foundry_header, foundry_output.into())]).unwrap(); - let objects = executor.into_objects(); - - // Foundry package publication creates five objects - // - // * The package - // * Coin metadata - // * MaxSupplyPolicy - // * The total supply coin - // * The foundry gas coin - assert_eq!(objects.len(), 5); - - // Extract the package object. - let package_object = objects - .iter() - .find(|object| object.is_package()) - .expect("there should be only a single gas coin"); - - // Extract the gas coin object. - let gas_coin_object = objects - .iter() - .find(|object| object.is_gas_coin()) - .expect("there should be only a single gas coin"); - - // Downcast the gas coin object to get the coin. - let coin = gas_coin_object.as_coin_maybe().unwrap(); - - // Check if the gas coin id is the same as the output id. - assert_eq!(gas_coin_object.id(), ObjectID::new(output_id.hash())); - - // Check if the owner of the gas coin is the package object. - assert_eq!( - gas_coin_object.owner.get_owner_address().unwrap(), - stardust_to_sui_address(alias_address).unwrap() - ); - - assert_eq!( - *gas_coin_object.type_().unwrap(), - MoveObjectType::gas_coin() - ); - assert_eq!(gas_coin_object.coin_type_maybe().unwrap(), GAS::type_tag()); - assert_eq!(coin.value(), 1_000_000); - assert_eq!(package_object.version(), gas_coin_object.version()); -} diff --git a/crates/sui-genesis-builder/src/stardust/migration/tests/mod.rs b/crates/sui-genesis-builder/src/stardust/migration/tests/mod.rs deleted file mode 100644 index 2526428081a..00000000000 --- a/crates/sui-genesis-builder/src/stardust/migration/tests/mod.rs +++ /dev/null @@ -1,505 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::HashMap, str::FromStr}; - -use anyhow::{anyhow, bail, ensure}; -use iota_sdk::types::block::{ - address::AliasAddress, - output::{ - feature::{Irc30Metadata, MetadataFeature}, - unlock_condition::ImmutableAliasAddressUnlockCondition, - AliasId, Feature, FoundryOutput, FoundryOutputBuilder, NativeToken, Output, OutputId, - SimpleTokenScheme, TokenId, TokenScheme, - }, -}; -use move_binary_format::errors::VMError; -use move_core_types::{ident_str, identifier::IdentStr, vm_status::StatusCode}; -use sui_types::{ - balance::Balance, - base_types::{SuiAddress, TxContext}, - coin::Coin, - digests::TransactionDigest, - epoch_data::EpochData, - gas_coin::GAS, - in_memory_storage::InMemoryStorage, - inner_temporary_store::InnerTemporaryStore, - programmable_transaction_builder::ProgrammableTransactionBuilder, - transaction::{Argument, CheckedInputObjects, ObjectArg}, - TypeTag, STARDUST_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID, -}; - -use super::MIGRATION_PROTOCOL_VERSION; -use crate::stardust::{ - migration::{ - executor::Executor, - migration::{Migration, NATIVE_TOKEN_BAG_KEY_TYPE, PACKAGE_DEPS}, - verification::created_objects::CreatedObjects, - }, - types::snapshot::OutputHeader, -}; - -mod alias; -mod basic; -mod executor; -mod foundry; -mod nft; - -fn random_output_header() -> OutputHeader { - OutputHeader::new_testing( - rand::random(), - rand::random(), - rand::random(), - rand::random(), - ) -} - -fn run_migration( - outputs: impl IntoIterator, -) -> anyhow::Result<(Executor, HashMap)> { - let mut migration = Migration::new(1)?; - migration.run_migration(outputs)?; - Ok(migration.into_parts()) -} - -fn create_foundry( - iota_amount: u64, - token_scheme: SimpleTokenScheme, - irc_30_metadata: Irc30Metadata, - alias_id: AliasId, -) -> anyhow::Result<(OutputHeader, FoundryOutput)> { - let builder = - FoundryOutputBuilder::new_with_amount(iota_amount, 1, TokenScheme::Simple(token_scheme)) - .add_unlock_condition(ImmutableAliasAddressUnlockCondition::new( - AliasAddress::new(alias_id), - )) - .add_immutable_feature(Feature::Metadata( - MetadataFeature::new(irc_30_metadata).unwrap(), - )); - let foundry_output = builder.finish()?; - - Ok((random_output_header(), foundry_output)) -} - -/// Test that an Object owned by another Object (not to be confused with -/// Owner::ObjectOwner) can be received by the owning object. This means aliases -/// owned by aliases, aliases owned by NFTs, etc. -/// -/// The PTB sends the extracted assets to the null address since they must be -/// used in the transaction. -fn object_migration_with_object_owner( - output_id_owner: OutputId, - output_id_owned: OutputId, - outputs: impl IntoIterator, - output_owner_module_name: &IdentStr, - output_owned_module_name: &IdentStr, - unlock_condition_function: &IdentStr, -) -> anyhow::Result<()> { - let (mut executor, objects_map) = run_migration(outputs)?; - - // Find the corresponding objects to the migrated outputs. - let owner_created_objects = objects_map - .get(&output_id_owner) - .expect("owner output should have created objects"); - let owned_created_objects = objects_map - .get(&output_id_owned) - .expect("owned output should have created objects"); - - let owner_output_object_ref = executor - .store() - .get_object(owner_created_objects.output()?) - .ok_or_else(|| anyhow!("missing owner-created output"))? - .compute_object_reference(); - let owned_output_object_ref = executor - .store() - .get_object(owned_created_objects.output()?) - .ok_or_else(|| anyhow!("missing owned created output"))? - .compute_object_reference(); - - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - let owner_arg = builder.obj(ObjectArg::ImmOrOwnedObject(owner_output_object_ref))?; - - let extracted_assets = builder.programmable_move_call( - STARDUST_PACKAGE_ID, - output_owner_module_name.into(), - ident_str!("extract_assets").into(), - vec![], - vec![owner_arg], - ); - - let Argument::Result(result_idx) = extracted_assets else { - bail!("expected Argument::Result"); - }; - let balance_arg = Argument::NestedResult(result_idx, 0); - let bag_arg = Argument::NestedResult(result_idx, 1); - let owned_arg = Argument::NestedResult(result_idx, 2); - - let receiving_owned_arg = builder.obj(ObjectArg::Receiving(owned_output_object_ref))?; - let received_owned_output = builder.programmable_move_call( - STARDUST_PACKAGE_ID, - ident_str!("address_unlock_condition").into(), - unlock_condition_function.into(), - vec![], - vec![owned_arg, receiving_owned_arg], - ); - - let coin_arg = builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, - ident_str!("coin").into(), - ident_str!("from_balance").into(), - vec![TypeTag::from_str(&format!( - "{SUI_FRAMEWORK_PACKAGE_ID}::sui::SUI" - ))?], - vec![balance_arg], - ); - - // Destroying the bag only works if it's empty, hence asserting that it is in - // fact empty. - builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, - ident_str!("bag").into(), - ident_str!("destroy_empty").into(), - vec![], - vec![bag_arg], - ); - - // Transfer the coin to the zero address since we have to move it somewhere. - builder.transfer_arg(SuiAddress::default(), coin_arg); - - // We have to use extracted object as we cannot transfer it (since it lacks the - // `store` ability), so we extract its assets. - let extracted_assets = builder.programmable_move_call( - STARDUST_PACKAGE_ID, - output_owned_module_name.into(), - ident_str!("extract_assets").into(), - vec![], - vec![received_owned_output], - ); - let Argument::Result(result_idx) = extracted_assets else { - bail!("expected Argument::Result"); - }; - let balance_arg = Argument::NestedResult(result_idx, 0); - let bag_arg = Argument::NestedResult(result_idx, 1); - let inner_owned_arg = Argument::NestedResult(result_idx, 2); - - let coin_arg = builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, - ident_str!("coin").into(), - ident_str!("from_balance").into(), - vec![TypeTag::from_str(&format!( - "{SUI_FRAMEWORK_PACKAGE_ID}::sui::SUI" - ))?], - vec![balance_arg], - ); - - // Destroying the bag only works if it's empty, hence asserting that it is in - // fact empty. - builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, - ident_str!("bag").into(), - ident_str!("destroy_empty").into(), - vec![], - vec![bag_arg], - ); - - // Transfer the coin to the zero address since we have to move it somewhere. - builder.transfer_arg(SuiAddress::default(), coin_arg); - - // We have successfully extracted the owned objects which is what we want to - // test. Transfer to the zero address so the PTB doesn't fail. - builder.transfer_arg(SuiAddress::default(), owned_arg); - builder.transfer_arg(SuiAddress::default(), inner_owned_arg); - - builder.finish() - }; - - let input_objects = CheckedInputObjects::new_for_genesis( - executor - .load_input_objects([owner_output_object_ref]) - .chain(executor.load_packages(PACKAGE_DEPS)) - .collect(), - ); - executor.execute_pt_unmetered(input_objects, pt)?; - Ok(()) -} - -/// Test that an Output that owns Native Tokens can extract those tokens from -/// the contained bag. -fn extract_native_token_from_bag( - output_id: OutputId, - outputs: impl IntoIterator, - module_name: &IdentStr, - native_token: NativeToken, - expected_assets: ExpectedAssets, -) -> anyhow::Result<()> { - let native_token_id: &TokenId = native_token.token_id(); - - let (mut executor, objects_map) = run_migration(outputs)?; - - // Find the corresponding objects to the migrated output. - let output_created_objects = objects_map - .get(&output_id) - .expect("output should have created objects"); - - let output_object_ref = executor - .store() - .get_object(output_created_objects.output()?) - .ok_or_else(|| anyhow!("missing output-created output"))? - .compute_object_reference(); - - // Recreate the key under which the tokens are stored in the bag. - let foundry_ledger_data = executor - .native_tokens() - .get(native_token_id) - .ok_or_else(|| anyhow!("missing native token {native_token_id}"))?; - let token_type = foundry_ledger_data.canonical_coin_type(); - let token_type_tag = token_type.parse::()?; - - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - let inner_object_arg = builder.obj(ObjectArg::ImmOrOwnedObject(output_object_ref))?; - - let extracted_assets = builder.programmable_move_call( - STARDUST_PACKAGE_ID, - module_name.into(), - ident_str!("extract_assets").into(), - vec![], - vec![inner_object_arg], - ); - - let Argument::Result(result_idx) = extracted_assets else { - bail!("expected Argument::Result"); - }; - let balance_arg = Argument::NestedResult(result_idx, 0); - let bag_arg = Argument::NestedResult(result_idx, 1); - if matches!(expected_assets, ExpectedAssets::BalanceBagObject) { - // This is the inner object, i.e. the Alias extracted from an Alias Output - // or NFT extracted from an NFT Output. - let inner_arg = Argument::NestedResult(result_idx, 2); - builder.transfer_arg(SuiAddress::default(), inner_arg); - } - - let coin_arg = builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, - ident_str!("coin").into(), - ident_str!("from_balance").into(), - vec![GAS::type_tag()], - vec![balance_arg], - ); - - builder.transfer_arg(SuiAddress::default(), coin_arg); - - let token_type_arg = builder.pure(token_type.clone())?; - let balance_arg = builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, - ident_str!("bag").into(), - ident_str!("remove").into(), - vec![ - NATIVE_TOKEN_BAG_KEY_TYPE - .parse() - .expect("should be a valid type tag"), - Balance::type_(token_type_tag.clone()).into(), - ], - vec![bag_arg, token_type_arg], - ); - - let coin_arg = builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, - ident_str!("coin").into(), - ident_str!("from_balance").into(), - vec![token_type_tag.clone()], - vec![balance_arg], - ); - - // Destroying the bag only works if it's empty, hence asserting that it is in - // fact empty. - builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, - ident_str!("bag").into(), - ident_str!("destroy_empty").into(), - vec![], - vec![bag_arg], - ); - - builder.transfer_arg(SuiAddress::default(), coin_arg); - - builder.finish() - }; - - let input_objects = CheckedInputObjects::new_for_genesis( - executor - .load_input_objects([output_object_ref]) - .chain(executor.load_packages(PACKAGE_DEPS)) - .collect(), - ); - let InnerTemporaryStore { written, .. } = executor.execute_pt_unmetered(input_objects, pt)?; - - let coin_token_struct_tag = Coin::type_(token_type_tag); - let coin_token = written - .values() - .find(|obj| { - obj.struct_tag() - .map(|tag| tag == coin_token_struct_tag) - .unwrap_or(false) - }) - .ok_or_else(|| anyhow!("missing coin object")) - .and_then(|obj| { - obj.as_coin_maybe() - .ok_or_else(|| anyhow!("object is not a coin")) - })?; - - ensure!( - coin_token.balance.value() == native_token.amount().as_u64(), - "coin token balance does not match original native token amount" - ); - Ok(()) -} - -enum UnlockObjectTestResult { - /// The test should succeed. - Success, - /// The test should fail with the given sub_status. - Failure(u64), -} - -impl UnlockObjectTestResult { - /// A copy of `EWrongSender` in the expiration unlock condition smart - /// contract. - pub(crate) const ERROR_WRONG_SENDER_FAILURE: Self = Self::Failure(0); - /// A copy of `ETimelockNotExpired` in the timelock unlock condition smart - /// contract. - pub(crate) const ERROR_TIMELOCK_NOT_EXPIRED_FAILURE: Self = Self::Failure(0); -} - -enum ExpectedAssets { - // TODO: Remove lint exception once the variant is used - #[allow(dead_code)] - BalanceBag, - BalanceBagObject, -} - -fn unlock_object_test( - output_id: OutputId, - outputs: impl IntoIterator, - sender: &SuiAddress, - module_name: &IdentStr, - epoch_start_timestamp_ms: u64, - expected_test_result: UnlockObjectTestResult, - expected_assets: ExpectedAssets, -) -> anyhow::Result<()> { - let (migration_executor, objects_map) = run_migration(outputs)?; - - // Recreate the TxContext and Executor so we can set a timestamp greater than 0. - let tx_context = TxContext::new( - sender, - &TransactionDigest::new(rand::random()), - &EpochData::new(0, epoch_start_timestamp_ms, Default::default()), - ); - let store = InMemoryStorage::new( - // Cloning all objects in the store includes the system packages we need for executing - // tests. - migration_executor - .store() - .objects() - .values() - .cloned() - .collect(), - ); - let mut executor = Executor::new(MIGRATION_PROTOCOL_VERSION.into()) - .unwrap() - .with_tx_context(tx_context) - .with_store(store); - - // Find the corresponding objects to the migrated output. - let output_created_objects = objects_map - .get(&output_id) - .expect("output should have created objects"); - - let output_object_ref = executor - .store() - .get_object(output_created_objects.output().unwrap()) - .unwrap() - .compute_object_reference(); - - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - let inner_object_arg = builder - .obj(ObjectArg::ImmOrOwnedObject(output_object_ref)) - .unwrap(); - - let extracted_assets = builder.programmable_move_call( - STARDUST_PACKAGE_ID, - module_name.into(), - ident_str!("extract_assets").into(), - vec![], - vec![inner_object_arg], - ); - - let Argument::Result(result_idx) = extracted_assets else { - bail!("expected Argument::Result"); - }; - let balance_arg = Argument::NestedResult(result_idx, 0); - let bag_arg = Argument::NestedResult(result_idx, 1); - - let coin_arg = builder.programmable_move_call( - SUI_FRAMEWORK_PACKAGE_ID, - ident_str!("coin").into(), - ident_str!("from_balance").into(), - vec![TypeTag::from_str(&format!("{SUI_FRAMEWORK_PACKAGE_ID}::sui::SUI")).unwrap()], - vec![balance_arg], - ); - - // Transfer the assets to the zero address since we have to move them somewhere - // in the test. - builder.transfer_arg(SuiAddress::ZERO, coin_arg); - builder.transfer_arg(SuiAddress::ZERO, bag_arg); - - if matches!(expected_assets, ExpectedAssets::BalanceBagObject) { - let object_arg = Argument::NestedResult(result_idx, 2); - builder.transfer_arg(SuiAddress::ZERO, object_arg); - } - - builder.finish() - }; - - let input_objects = CheckedInputObjects::new_for_genesis( - executor - .load_input_objects([output_object_ref]) - .chain(executor.load_packages(PACKAGE_DEPS)) - .collect(), - ); - let result = executor.execute_pt_unmetered(input_objects, pt); - - match (result, expected_test_result) { - (Ok(_), UnlockObjectTestResult::Success) => Ok(()), - (Ok(_), UnlockObjectTestResult::Failure(_)) => { - bail!("expected test failure, but test suceeded") - } - (Err(err), UnlockObjectTestResult::Success) => { - bail!("expected test success, but test failed: {err}") - } - (Err(err), UnlockObjectTestResult::Failure(expected_sub_status)) => { - for cause in err.chain() { - match cause.downcast_ref::() { - Some(vm_error) => { - ensure!(vm_error.major_status() == StatusCode::ABORTED); - let actual_sub_status = vm_error - .sub_status() - .expect("sub_status should be set for aborts"); - ensure!( - actual_sub_status == expected_sub_status, - "actual vm sub_status {actual_sub_status} did not match expected sub_status {expected_sub_status}" - ); - // Finish test successfully. - return Ok(()); - } - None => continue, - } - } - bail!( - "expected test failure, but failed to find expected VMError in error chain, got: {err}" - ); - } - } -} diff --git a/crates/sui-genesis-builder/src/stardust/migration/tests/nft.rs b/crates/sui-genesis-builder/src/stardust/migration/tests/nft.rs deleted file mode 100644 index 9eed0df3a47..00000000000 --- a/crates/sui-genesis-builder/src/stardust/migration/tests/nft.rs +++ /dev/null @@ -1,701 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::{BTreeMap, BTreeSet}, - str::FromStr, -}; - -use anyhow::anyhow; -use iota_sdk::{ - types::block::{ - address::{AliasAddress, Ed25519Address, Hrp, NftAddress, ToBech32Ext}, - output::{ - feature::{ - Attribute, Irc30Metadata, IssuerFeature, MetadataFeature, SenderFeature, TagFeature, - }, - unlock_condition::{ - AddressUnlockCondition, ExpirationUnlockCondition, GovernorAddressUnlockCondition, - StateControllerAddressUnlockCondition, StorageDepositReturnUnlockCondition, - TimelockUnlockCondition, - }, - AliasId, AliasOutputBuilder, Feature, NativeToken, NftId, NftOutput as StardustNft, - NftOutputBuilder, SimpleTokenScheme, - }, - }, - U256, -}; -use move_core_types::ident_str; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, - collection_types::VecMap, - dynamic_field::{derive_dynamic_field_id, DynamicFieldInfo}, - id::UID, - object::{Object, Owner}, - TypeTag, -}; - -use super::{unlock_object_test, ExpectedAssets, UnlockObjectTestResult}; -use crate::stardust::{ - migration::tests::{ - create_foundry, extract_native_token_from_bag, object_migration_with_object_owner, - random_output_header, run_migration, - }, - types::{ - snapshot::OutputHeader, stardust_to_sui_address, FixedPoint32, Irc27Metadata, Nft, - NftOutput, ALIAS_OUTPUT_MODULE_NAME, NFT_DYNAMIC_OBJECT_FIELD_KEY, - NFT_DYNAMIC_OBJECT_FIELD_KEY_TYPE, NFT_OUTPUT_MODULE_NAME, - }, -}; - -fn migrate_nft( - header: OutputHeader, - stardust_nft: StardustNft, -) -> anyhow::Result<(ObjectID, Nft, NftOutput, Object, Object)> { - let output_id = header.output_id(); - let nft_id: NftId = stardust_nft - .nft_id() - .or_from_output_id(&output_id) - .to_owned(); - - let (executor, objects_map) = run_migration([(header, stardust_nft.into())])?; - - // Ensure the migrated objects exist under the expected identifiers. - let nft_object_id = ObjectID::new(*nft_id); - let created_objects = objects_map - .get(&output_id) - .ok_or_else(|| anyhow!("nft output should have created objects"))?; - - let nft_object = executor - .store() - .objects() - .values() - .find(|obj| obj.id() == nft_object_id) - .ok_or_else(|| anyhow!("nft object should be present in the migrated snapshot"))?; - assert_eq!( - nft_object - .struct_tag() - .ok_or_else(|| anyhow!("missing struct tag on nft object"))?, - Nft::tag() - ); - - let nft_output_object = executor - .store() - .get_object(created_objects.output()?) - .ok_or_else(|| anyhow!("missing nft output"))?; - assert_eq!( - nft_output_object - .struct_tag() - .ok_or_else(|| anyhow!("missing struct tag on output nft object"))?, - NftOutput::tag() - ); - - // Version is set to 1 when the nft is created based on the computed lamport - // timestamp. When the nft is attached to the nft output, the version should - // be incremented. - assert!( - nft_object.version().value() > 1, - "nft object version should have been incremented" - ); - assert!( - nft_output_object.version().value() > 1, - "nft output object version should have been incremented" - ); - - let nft_output: NftOutput = bcs::from_bytes( - nft_output_object - .data - .try_as_move() - .ok_or_else(|| anyhow!("nft output is not a move object"))? - .contents(), - )?; - let nft: Nft = bcs::from_bytes( - nft_object - .data - .try_as_move() - .ok_or_else(|| anyhow!("nft is not a move object"))? - .contents(), - )?; - - Ok(( - nft_object_id, - nft, - nft_output, - nft_object.clone(), - nft_output_object.clone(), - )) -} - -/// Test that the migrated nft objects in the snapshot contain the expected -/// data. -#[test] -fn nft_migration_with_full_features() { - let nft_id = NftId::new(rand::random()); - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let header = random_output_header(); - - let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, nft_id) - .add_unlock_condition(AddressUnlockCondition::new(random_address)) - .with_features(vec![ - Feature::Metadata(MetadataFeature::new([0xdd; 1]).unwrap()), - Feature::Sender(SenderFeature::new(random_address)), - Feature::Tag(TagFeature::new(b"tag").unwrap()), - ]) - .with_immutable_features(vec![ - Feature::Metadata(MetadataFeature::new([0xaa; 1]).unwrap()), - Feature::Issuer(IssuerFeature::new(random_address)), - ]) - .finish() - .unwrap(); - - let (nft_object_id, nft, nft_output, nft_object, nft_output_object) = - migrate_nft(header, stardust_nft.clone()).unwrap(); - let expected_nft = Nft::try_from_stardust(nft_object_id, &stardust_nft).unwrap(); - - // The bag is tested separately. - assert_eq!(stardust_nft.amount(), nft_output.iota.value()); - // The ID is newly generated, so we don't know the exact value, but it should - // not be zero. - assert_ne!(nft_output.id, UID::new(ObjectID::ZERO)); - assert_ne!( - nft_output.id, - UID::new(ObjectID::new( - stardust_nft.nft_id().as_slice().try_into().unwrap() - )) - ); - - assert!(nft_output.storage_deposit_return.is_none()); - assert!(nft_output.expiration.is_none()); - assert!(nft_output.timelock.is_none()); - - assert_eq!(expected_nft, nft); - - // The NFT Object should be in a dynamic object field. - let nft_owner = derive_dynamic_field_id( - nft_output_object.id(), - &TypeTag::from(DynamicFieldInfo::dynamic_object_field_wrapper( - TypeTag::from_str(NFT_DYNAMIC_OBJECT_FIELD_KEY_TYPE).unwrap(), - )), - &bcs::to_bytes(NFT_DYNAMIC_OBJECT_FIELD_KEY).unwrap(), - ) - .unwrap(); - assert_eq!(nft_object.owner, Owner::ObjectOwner(nft_owner.into())); - - let nft_output_owner = - Owner::AddressOwner(stardust_to_sui_address(stardust_nft.address()).unwrap()); - assert_eq!(nft_output_object.owner, nft_output_owner); -} - -/// Test that an Nft with a zeroed ID is migrated to an Nft Object with its UID -/// set to the hashed Output ID. -#[test] -fn nft_migration_with_zeroed_id() { - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let header = random_output_header(); - - let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) - .add_unlock_condition(AddressUnlockCondition::new(random_address)) - .finish() - .unwrap(); - - // If this function does not panic, then the created NFTs - // were found at the correct non-zeroed Nft ID. - migrate_nft(header, stardust_nft).unwrap(); -} - -#[test] -fn nft_migration_with_alias_owner() { - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - - let alias_header = random_output_header(); - let alias = AliasOutputBuilder::new_with_amount(2_000_000, AliasId::new(rand::random())) - .add_unlock_condition(StateControllerAddressUnlockCondition::new(random_address)) - .add_unlock_condition(GovernorAddressUnlockCondition::new(random_address)) - .finish() - .unwrap(); - - let nft_header = random_output_header(); - // alias is the owner of nft. - let nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::new(rand::random())) - .add_unlock_condition(AddressUnlockCondition::new(AliasAddress::from( - *alias.alias_id(), - ))) - .finish() - .unwrap(); - - object_migration_with_object_owner( - alias_header.output_id(), - nft_header.output_id(), - [ - (nft_header.clone(), nft.into()), - (alias_header.clone(), alias.into()), - ], - ALIAS_OUTPUT_MODULE_NAME, - NFT_OUTPUT_MODULE_NAME, - ident_str!("unlock_alias_address_owned_nft"), - ) - .unwrap(); -} - -#[test] -fn nft_migration_with_nft_owner() { - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - - let nft1_header = random_output_header(); - let nft1 = NftOutputBuilder::new_with_amount(1_000_000, NftId::new(rand::random())) - .add_unlock_condition(AddressUnlockCondition::new(random_address)) - .finish() - .unwrap(); - - let nft2_header = random_output_header(); - // nft1 is the owner of nft2. - let nft2 = NftOutputBuilder::new_with_amount(1_000_000, NftId::new(rand::random())) - .add_unlock_condition(AddressUnlockCondition::new(NftAddress::from( - *nft1.nft_id(), - ))) - .finish() - .unwrap(); - - object_migration_with_object_owner( - nft1_header.output_id(), - nft2_header.output_id(), - [ - (nft1_header.clone(), nft1.into()), - (nft2_header.clone(), nft2.into()), - ], - NFT_OUTPUT_MODULE_NAME, - NFT_OUTPUT_MODULE_NAME, - ident_str!("unlock_nft_address_owned_nft"), - ) - .unwrap(); -} - -/// Test that an NFT that owns Native Tokens can extract those tokens from the -/// contained bag. -#[test] -fn nft_migration_with_native_tokens() { - let (foundry_header, foundry_output) = create_foundry( - 0, - SimpleTokenScheme::new(U256::from(100_000), U256::from(0), U256::from(100_000)).unwrap(), - Irc30Metadata::new("Rustcoin", "Rust", 0), - AliasId::null(), - ) - .unwrap(); - let native_token = NativeToken::new(foundry_output.id().into(), 100_000).unwrap(); - - let nft_header = random_output_header(); - let nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::new(rand::random())) - .add_unlock_condition(AddressUnlockCondition::new(Ed25519Address::from( - rand::random::<[u8; Ed25519Address::LENGTH]>(), - ))) - .add_native_token(native_token) - .finish() - .unwrap(); - - extract_native_token_from_bag( - nft_header.output_id(), - [ - (nft_header.clone(), nft.into()), - (foundry_header, foundry_output.into()), - ], - NFT_OUTPUT_MODULE_NAME, - native_token, - ExpectedAssets::BalanceBagObject, - ) - .unwrap(); -} - -#[test] -fn nft_migration_with_valid_irc27_metadata() { - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let random_address2 = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let header = random_output_header(); - - let hrp = Hrp::from_str_unchecked("atoi"); - let mut attributes = BTreeSet::new(); - attributes.insert(Attribute::new("planet", "earth")); - attributes.insert(Attribute::new("languages", vec!["english", "rust"])); - - let mut royalties = BTreeMap::new(); - royalties.insert(random_address.to_bech32(hrp), 10.0); - royalties.insert(random_address2.to_bech32(hrp), 5.0); - - let metadata = iota_sdk::types::block::output::feature::Irc27Metadata::new( - "image/png", - "https://nft.org/nft.png".parse().unwrap(), - "NFT", - ) - .with_issuer_name("issuer_name") - .with_collection_name("collection_name") - .with_royalties(royalties) - .with_description("description") - .with_attributes(attributes); - - let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::new(rand::random())) - .add_unlock_condition(AddressUnlockCondition::new(random_address)) - .with_immutable_features(vec![ - Feature::Metadata( - MetadataFeature::new(serde_json::to_vec(&metadata).unwrap()).unwrap(), - ), - Feature::Issuer(IssuerFeature::new(random_address)), - ]) - .finish() - .unwrap(); - - let (_, nft, _, _, _) = migrate_nft(header, stardust_nft.clone()).unwrap(); - - let immutable_metadata = nft.immutable_metadata; - assert_eq!(&immutable_metadata.media_type, metadata.media_type()); - assert_eq!(immutable_metadata.uri.url, metadata.uri().to_string()); - assert_eq!(&immutable_metadata.name, metadata.name()); - assert_eq!(&immutable_metadata.issuer_name, metadata.issuer_name()); - assert_eq!( - &immutable_metadata.collection_name, - metadata.collection_name() - ); - assert_eq!(&immutable_metadata.description, metadata.description()); - - let migrated_royalties = immutable_metadata - .royalties - .contents - .into_iter() - .map(|entry| (entry.key, entry.value)) - .collect::>(); - let converted_royalties = metadata - .royalties() - .iter() - .map(|entry| { - ( - SuiAddress::from_bytes(entry.0.as_ed25519().as_slice()).unwrap(), - FixedPoint32::try_from(*entry.1).unwrap(), - ) - }) - .collect::>(); - - assert_eq!(migrated_royalties, converted_royalties); - - let migrated_attributes = immutable_metadata - .attributes - .contents - .into_iter() - .map(|entry| (entry.key, entry.value)) - .collect::>(); - - let converted_attributes = metadata - .attributes() - .iter() - .map(|entry| (entry.trait_type().to_owned(), entry.value().to_string())) - .collect::>(); - - assert_eq!(migrated_attributes, converted_attributes); -} - -#[test] -fn nft_migration_with_invalid_irc27_metadata() { - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let header = random_output_header(); - - let metadata = iota_sdk::types::block::output::feature::Irc27Metadata::new( - "image/png", - "https://nft.org/nft.png".parse().unwrap(), - "NFT", - ); - - let mut metadata = serde_json::to_value(&metadata).unwrap(); - // Make the IRC-27 Metadata invalid by changing the type of the `uri` key. - metadata - .as_object_mut() - .unwrap() - .insert("uri".to_owned(), serde_json::Value::Bool(false)); - let metadata_content = serde_json::to_vec(&metadata).unwrap(); - - let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) - .add_unlock_condition(AddressUnlockCondition::new(random_address)) - .with_immutable_features(vec![ - Feature::Metadata(MetadataFeature::new(metadata_content).unwrap()), - Feature::Issuer(IssuerFeature::new(random_address)), - ]) - .finish() - .unwrap(); - - let (_, nft, _, _, _) = migrate_nft(header, stardust_nft.clone()).unwrap(); - - let mut immutable_metadata = nft.immutable_metadata; - let mut non_standard_fields = VecMap { contents: vec![] }; - std::mem::swap( - &mut immutable_metadata.non_standard_fields, - &mut non_standard_fields, - ); - - let non_standard_fields = non_standard_fields - .contents - .into_iter() - .map(|entry| (entry.key, entry.value)) - .collect::>(); - - let converted_metadata = metadata - .as_object() - .unwrap() - .iter() - .map(|entry| (entry.0.to_owned(), entry.1.to_string())) - .collect::>(); - - // Since the metadata is valid JSON, we expect the fields of the object to be in - // the non_standard_fields. - assert_eq!(non_standard_fields, converted_metadata); - - // Since we removed non_standard_fields, the other fields of immutable_metadata - // should be the defaults. - assert_eq!(immutable_metadata, Irc27Metadata::default()); -} - -#[test] -fn nft_migration_with_non_json_metadata() { - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let header = random_output_header(); - - let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) - .add_unlock_condition(AddressUnlockCondition::new(random_address)) - .with_immutable_features(vec![ - Feature::Metadata(MetadataFeature::new([0xde, 0xca, 0xde]).unwrap()), - Feature::Issuer(IssuerFeature::new(random_address)), - ]) - .finish() - .unwrap(); - - let (_, nft, _, _, _) = migrate_nft(header, stardust_nft.clone()).unwrap(); - - let mut immutable_metadata = nft.immutable_metadata; - let mut non_standard_fields = VecMap { contents: vec![] }; - std::mem::swap( - &mut immutable_metadata.non_standard_fields, - &mut non_standard_fields, - ); - - assert_eq!(non_standard_fields.contents.len(), 1); - let data = non_standard_fields - .contents - .into_iter() - .find_map(|entry| { - if entry.key == "data" { - Some(entry.value) - } else { - None - } - }) - .unwrap(); - - assert_eq!(data, "decade"); - - // Since we removed non_standard_fields, the other fields of immutable_metadata - // should be the defaults. - assert_eq!(immutable_metadata, Irc27Metadata::default()); -} - -#[test] -fn nft_migration_without_metadata() { - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let header = random_output_header(); - - let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) - .add_unlock_condition(AddressUnlockCondition::new(random_address)) - .with_immutable_features(vec![Feature::Issuer(IssuerFeature::new(random_address))]) - .finish() - .unwrap(); - - let (_, nft, _, _, _) = migrate_nft(header, stardust_nft.clone()).unwrap(); - let immutable_metadata = nft.immutable_metadata; - - assert_eq!(immutable_metadata.non_standard_fields.contents.len(), 0); - - // Since we removed non_standard_fields, the other fields of immutable_metadata - // should be the defaults. - assert_eq!(immutable_metadata, Irc27Metadata::default()); -} - -#[test] -fn nft_migration_with_timelock_unlocked() { - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let header = random_output_header(); - - // The epoch timestamp that the executor will use for the test. - let epoch_start_timestamp_ms = 100_000; - - let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) - .add_unlock_condition(AddressUnlockCondition::new(random_address)) - .add_unlock_condition( - TimelockUnlockCondition::new(epoch_start_timestamp_ms / 1000).unwrap(), - ) - .finish() - .unwrap(); - - unlock_object_test( - header.output_id(), - [(header, stardust_nft.into())], - // Sender is not important for this test. - &SuiAddress::ZERO, - NFT_OUTPUT_MODULE_NAME, - epoch_start_timestamp_ms as u64, - UnlockObjectTestResult::Success, - ExpectedAssets::BalanceBagObject, - ) - .unwrap(); -} - -#[test] -fn nft_migration_with_timelock_still_locked() { - let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let header = random_output_header(); - - // The epoch timestamp that the executor will use for the test. - let epoch_start_timestamp_ms = 100_000; - - let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) - .add_unlock_condition(AddressUnlockCondition::new(random_address)) - .add_unlock_condition( - TimelockUnlockCondition::new((epoch_start_timestamp_ms / 1000) + 1).unwrap(), - ) - .finish() - .unwrap(); - - unlock_object_test( - header.output_id(), - [(header, stardust_nft.into())], - // Sender is not important for this test. - &SuiAddress::ZERO, - NFT_OUTPUT_MODULE_NAME, - epoch_start_timestamp_ms as u64, - UnlockObjectTestResult::ERROR_TIMELOCK_NOT_EXPIRED_FAILURE, - ExpectedAssets::BalanceBagObject, - ) - .unwrap(); -} - -/// Test that an NFT with an expired Expiration Unlock Condition can/cannot be -/// unlocked, depending on the TX sender. -#[test] -fn nft_migration_with_expired_unlock_condition() { - let owner = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let return_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let sui_owner_address = stardust_to_sui_address(owner).unwrap(); - let sui_return_address = stardust_to_sui_address(return_address).unwrap(); - let header = random_output_header(); - - // The epoch timestamp that the executor will use for the test. - let epoch_start_timestamp_ms = 100_000; - - // Expiration Timestamp is exactly at the epoch start timestamp -> object is - // expired -> return address can unlock. - let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) - .add_unlock_condition(AddressUnlockCondition::new(owner)) - .add_unlock_condition( - ExpirationUnlockCondition::new(return_address, epoch_start_timestamp_ms / 1000) - .unwrap(), - ) - .finish() - .unwrap(); - - // Owner Address CANNOT unlock. - unlock_object_test( - header.output_id(), - [(header.clone(), stardust_nft.clone().into())], - &sui_owner_address, - NFT_OUTPUT_MODULE_NAME, - epoch_start_timestamp_ms as u64, - UnlockObjectTestResult::ERROR_WRONG_SENDER_FAILURE, - ExpectedAssets::BalanceBagObject, - ) - .unwrap(); - - // Return Address CAN unlock. - unlock_object_test( - header.output_id(), - [(header, stardust_nft.into())], - &sui_return_address, - NFT_OUTPUT_MODULE_NAME, - epoch_start_timestamp_ms as u64, - UnlockObjectTestResult::Success, - ExpectedAssets::BalanceBagObject, - ) - .unwrap(); -} - -/// Test that an NFT with an unexpired Expiration Unlock Condition can/cannot be -/// unlocked, depending on the TX sender. -#[test] -fn nft_migration_with_unexpired_unlock_condition() { - let owner = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let return_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let sui_owner_address = stardust_to_sui_address(owner).unwrap(); - let sui_return_address = stardust_to_sui_address(return_address).unwrap(); - let header = random_output_header(); - - // The epoch timestamp that the executor will use for the test. - let epoch_start_timestamp_ms = 100_000; - - // Expiration Timestamp is after the epoch start timestamp -> object is not - // expired -> owner address can unlock. - let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) - .add_unlock_condition(AddressUnlockCondition::new(owner)) - .add_unlock_condition( - ExpirationUnlockCondition::new(return_address, (epoch_start_timestamp_ms / 1000) + 1) - .unwrap(), - ) - .finish() - .unwrap(); - - // Return Address CANNOT unlock. - unlock_object_test( - header.output_id(), - [(header.clone(), stardust_nft.clone().into())], - &sui_return_address, - NFT_OUTPUT_MODULE_NAME, - epoch_start_timestamp_ms as u64, - UnlockObjectTestResult::ERROR_WRONG_SENDER_FAILURE, - ExpectedAssets::BalanceBagObject, - ) - .unwrap(); - - // Owner Address CAN unlock. - unlock_object_test( - header.output_id(), - [(header, stardust_nft.into())], - &sui_owner_address, - NFT_OUTPUT_MODULE_NAME, - epoch_start_timestamp_ms as u64, - UnlockObjectTestResult::Success, - ExpectedAssets::BalanceBagObject, - ) - .unwrap(); -} - -/// Test that an NFT with a Storage Deposit Return Unlock Condition can be -/// unlocked. -#[test] -fn nft_migration_with_storage_deposit_return_unlock_condition() { - let owner = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let return_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); - let header = random_output_header(); - - let stardust_nft = NftOutputBuilder::new_with_amount(1_000_000, NftId::null()) - .add_unlock_condition(AddressUnlockCondition::new(owner)) - .add_unlock_condition( - StorageDepositReturnUnlockCondition::new(return_address, 1_000, 1_000_000_000).unwrap(), - ) - .finish() - .unwrap(); - - // Simply test that the unlock with the SDRUC succeeds. - unlock_object_test( - header.output_id(), - [(header.clone(), stardust_nft.clone().into())], - // Sender is not important for this test. - &SuiAddress::ZERO, - NFT_OUTPUT_MODULE_NAME, - // Epoch start time is not important for this test. - 0, - UnlockObjectTestResult::Success, - ExpectedAssets::BalanceBagObject, - ) - .unwrap(); -} diff --git a/crates/sui-genesis-builder/src/stardust/migration/verification/alias.rs b/crates/sui-genesis-builder/src/stardust/migration/verification/alias.rs deleted file mode 100644 index ec1dd446b83..00000000000 --- a/crates/sui-genesis-builder/src/stardust/migration/verification/alias.rs +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::HashMap; - -use anyhow::{anyhow, bail, ensure}; -use iota_sdk::types::block::output as stardust; -use sui_types::{ - balance::Balance, - base_types::{ObjectID, SuiAddress}, - dynamic_field::{derive_dynamic_field_id, DynamicFieldInfo, Field}, - in_memory_storage::InMemoryStorage, - object::Owner, - TypeTag, -}; - -use super::util::verify_parent; -use crate::stardust::{ - migration::{ - executor::FoundryLedgerData, - verification::{ - created_objects::CreatedObjects, - util::{ - verify_address_owner, verify_issuer_feature, verify_metadata_feature, - verify_native_tokens, verify_sender_feature, - }, - }, - }, - types::{ - Alias, AliasOutput, ALIAS_DYNAMIC_OBJECT_FIELD_KEY, ALIAS_DYNAMIC_OBJECT_FIELD_KEY_TYPE, - }, -}; - -pub(super) fn verify_alias_output( - output_id: stardust::OutputId, - output: &stardust::AliasOutput, - created_objects: &CreatedObjects, - foundry_data: &HashMap, - storage: &InMemoryStorage, -) -> anyhow::Result<()> { - let alias_id = ObjectID::new(*output.alias_id_non_null(&output_id)); - - let created_output_obj = created_objects.output().and_then(|id| { - storage - .get_object(id) - .ok_or_else(|| anyhow!("missing alias output object")) - })?; - - let created_alias_obj = storage - .get_object(&alias_id) - .ok_or_else(|| anyhow!("missing alias object"))?; - - // Alias Output Owner - verify_address_owner( - output.governor_address(), - created_output_obj, - "alias output", - )?; - - // Alias Owner - let expected_alias_owner = Owner::ObjectOwner( - derive_dynamic_field_id( - created_output_obj.id(), - &DynamicFieldInfo::dynamic_object_field_wrapper( - ALIAS_DYNAMIC_OBJECT_FIELD_KEY_TYPE.parse::()?, - ) - .into(), - &bcs::to_bytes(ALIAS_DYNAMIC_OBJECT_FIELD_KEY)?, - )? - .into(), - ); - - ensure!( - created_alias_obj.owner == expected_alias_owner, - "alias owner mismatch: found {}, expected {}", - created_alias_obj.owner, - expected_alias_owner - ); - - let created_alias = created_alias_obj - .to_rust::() - .ok_or_else(|| anyhow!("invalid alias object"))?; - - let created_output = created_output_obj - .to_rust::() - .ok_or_else(|| anyhow!("invalid alias output object"))?; - - // Amount - ensure!( - created_output.iota.value() == output.amount(), - "amount mismatch: found {}, expected {}", - created_output.iota.value(), - output.amount() - ); - - // Native Tokens - verify_native_tokens::>( - output.native_tokens(), - foundry_data, - created_output.native_tokens, - created_objects.native_tokens().ok(), - storage, - )?; - - // Legacy State Controller - let expected_state_controller = output - .state_controller_address() - .to_string() - .parse::()?; - ensure!( - created_alias.legacy_state_controller == expected_state_controller, - "legacy state controller mismatch: found {}, expected {}", - created_alias.legacy_state_controller, - expected_state_controller - ); - - // State Index - ensure!( - created_alias.state_index == output.state_index(), - "state index mismatch: found {}, expected {}", - created_alias.state_index, - output.state_index() - ); - - // State Metadata - if output.state_metadata().is_empty() { - ensure!( - created_alias.state_metadata.is_none(), - "unexpected state metadata found" - ); - } else { - let Some(state_metadata) = created_alias.state_metadata.as_ref() else { - bail!("missing state metadata") - }; - - ensure!( - state_metadata.as_slice() == output.state_metadata(), - "state metadata mismatch: found {:?}, expected {:?}", - state_metadata, - output.state_metadata() - ); - } - - // Sender Feature - verify_sender_feature(output.features().sender(), created_alias.sender)?; - - // Metadata Feature - verify_metadata_feature( - output.features().metadata(), - created_alias.metadata.as_ref(), - )?; - - // Immutable Issuer Feature - verify_issuer_feature( - output.immutable_features().issuer(), - created_alias.immutable_issuer, - )?; - - // Immutable Metadata Feature - verify_metadata_feature( - output.immutable_features().metadata(), - created_alias.immutable_metadata.as_ref(), - )?; - - verify_parent(output.governor_address(), storage)?; - - ensure!(created_objects.coin().is_err(), "unexpected coin found"); - - ensure!( - created_objects.coin_metadata().is_err(), - "unexpected coin metadata found" - ); - - ensure!( - created_objects.minted_coin().is_err(), - "unexpected minted coin found" - ); - - ensure!( - created_objects.max_supply_policy().is_err(), - "unexpected max supply policy found" - ); - - ensure!( - created_objects.package().is_err(), - "unexpected package found" - ); - - Ok(()) -} diff --git a/crates/sui-genesis-builder/src/stardust/migration/verification/basic.rs b/crates/sui-genesis-builder/src/stardust/migration/verification/basic.rs deleted file mode 100644 index 85cbc80a262..00000000000 --- a/crates/sui-genesis-builder/src/stardust/migration/verification/basic.rs +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::HashMap; - -use anyhow::{anyhow, ensure, Result}; -use iota_sdk::types::block::output::{BasicOutput, OutputId, TokenId}; -use sui_types::{ - balance::Balance, coin::Coin, dynamic_field::Field, in_memory_storage::InMemoryStorage, - timelock::timelock::TimeLock, TypeTag, -}; - -use crate::stardust::{ - migration::{ - executor::FoundryLedgerData, - verification::{ - created_objects::CreatedObjects, - util::{ - verify_address_owner, verify_coin, verify_expiration_unlock_condition, - verify_metadata_feature, verify_native_tokens, verify_parent, - verify_sender_feature, verify_storage_deposit_unlock_condition, verify_tag_feature, - verify_timelock_unlock_condition, - }, - }, - }, - types::timelock::is_timelocked_vested_reward, -}; - -pub(super) fn verify_basic_output( - output_id: OutputId, - output: &BasicOutput, - created_objects: &CreatedObjects, - foundry_data: &HashMap, - target_milestone_timestamp: u32, - storage: &InMemoryStorage, -) -> Result<()> { - // If this is a timelocked vested reward, a `Timelock` is created. - if is_timelocked_vested_reward(output_id, output, target_milestone_timestamp) { - let created_timelock = created_objects - .output() - .and_then(|id| { - storage - .get_object(id) - .ok_or_else(|| anyhow!("missing timelock object")) - })? - .to_rust::>() - .ok_or_else(|| anyhow!("invalid timelock object"))?; - - // Locked timestamp - ensure!( - created_timelock.expiration_timestamp_ms == target_milestone_timestamp as u64, - "timelock timestamp mismatch: found {}, expected {}", - created_timelock.expiration_timestamp_ms, - target_milestone_timestamp - ); - - // Amount - ensure!( - created_timelock.locked.value() == output.amount(), - "locked amount mismatch: found {}, expected {}", - created_timelock.locked.value(), - output.amount() - ); - - return Ok(()); - } - - // If the output has multiple unlock conditions, then a genesis object should - // have been created. - if output.unlock_conditions().len() > 1 { - ensure!(created_objects.coin().is_err(), "unexpected coin created"); - - let created_output_obj = created_objects.output().and_then(|id| { - storage - .get_object(id) - .ok_or_else(|| anyhow!("missing basic output object")) - })?; - let created_output = created_output_obj - .to_rust::() - .ok_or_else(|| anyhow!("invalid basic output object"))?; - - // Owner - verify_address_owner(output.address(), created_output_obj, "basic output")?; - - // Amount - ensure!( - created_output.iota.value() == output.amount(), - "amount mismatch: found {}, expected {}", - created_output.iota.value(), - output.amount() - ); - - // Native Tokens - verify_native_tokens::>( - output.native_tokens(), - foundry_data, - created_output.native_tokens, - created_objects.native_tokens().ok(), - storage, - )?; - - // Storage Deposit Return Unlock Condition - verify_storage_deposit_unlock_condition( - output.unlock_conditions().storage_deposit_return(), - created_output.storage_deposit_return.as_ref(), - )?; - - // Timelock Unlock Condition - verify_timelock_unlock_condition( - output.unlock_conditions().timelock(), - created_output.timelock.as_ref(), - )?; - - // Expiration Unlock Condition - verify_expiration_unlock_condition( - output.unlock_conditions().expiration(), - created_output.expiration.as_ref(), - output.address(), - )?; - - // Metadata Feature - verify_metadata_feature( - output.features().metadata(), - created_output.metadata.as_ref(), - )?; - - // Tag Feature - verify_tag_feature(output.features().tag(), created_output.tag.as_ref())?; - - // Sender Feature - verify_sender_feature(output.features().sender(), created_output.sender)?; - - // Otherwise the output contains only an address unlock condition and only a - // coin and possibly native tokens should have been created. - } else { - ensure!( - created_objects.output().is_err(), - "unexpected output object created for simple deposit" - ); - - // Coin value and owner - verify_coin(output.amount(), output.address(), created_objects, storage)?; - - // Native Tokens - verify_native_tokens::<(TypeTag, Coin)>( - output.native_tokens(), - foundry_data, - None, - created_objects.native_tokens().ok(), - storage, - )?; - } - - verify_parent(output.address(), storage)?; - - ensure!( - created_objects.coin_metadata().is_err(), - "unexpected coin metadata found" - ); - - ensure!( - created_objects.minted_coin().is_err(), - "unexpected minted coin found" - ); - - ensure!( - created_objects.max_supply_policy().is_err(), - "unexpected max supply policy found" - ); - - ensure!( - created_objects.package().is_err(), - "unexpected package found" - ); - - Ok(()) -} diff --git a/crates/sui-genesis-builder/src/stardust/migration/verification/foundry.rs b/crates/sui-genesis-builder/src/stardust/migration/verification/foundry.rs deleted file mode 100644 index 5b1dedfdd77..00000000000 --- a/crates/sui-genesis-builder/src/stardust/migration/verification/foundry.rs +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::HashMap; - -use anyhow::{anyhow, ensure, Result}; -use iota_sdk::types::block::output::{FoundryOutput, TokenId}; -use move_core_types::language_storage::ModuleId; -use sui_types::{ - base_types::SuiAddress, coin::CoinMetadata, in_memory_storage::InMemoryStorage, object::Owner, - Identifier, -}; - -use crate::stardust::{ - migration::{ - executor::FoundryLedgerData, - verification::{ - util::{ - truncate_to_max_allowed_u64_supply, verify_address_owner, verify_coin, - verify_parent, - }, - CreatedObjects, - }, - }, - native_token::package_data::NativeTokenPackageData, - types::{capped_coin::MaxSupplyPolicy, token_scheme::SimpleTokenSchemeU64}, -}; - -pub(super) fn verify_foundry_output( - output: &FoundryOutput, - created_objects: &CreatedObjects, - foundry_data: &HashMap, - storage: &InMemoryStorage, -) -> Result<()> { - let foundry_data = foundry_data - .get(&output.token_id()) - .ok_or_else(|| anyhow!("missing foundry data"))?; - - let alias_address = output - .unlock_conditions() - .immutable_alias_address() - .expect("foundry outputs always have an immutable alias address") - .address(); - - // Coin value and owner - verify_coin(output.amount(), alias_address, created_objects, storage)?; - - // Minted coin value - let minted_coin_id = created_objects.minted_coin()?; - let minted_coin_obj = storage - .get_object(minted_coin_id) - .ok_or_else(|| anyhow!("missing coin"))?; - let minted_coin = minted_coin_obj - .as_coin_maybe() - .ok_or_else(|| anyhow!("expected a coin"))?; - - // Minted coins are transferred to `0x0` - let expected_owner = Owner::AddressOwner(SuiAddress::default()); - ensure!( - minted_coin_obj.owner == expected_owner, - "minted coin owner mismatch: found {}, expected {}", - minted_coin_obj.owner, - expected_owner - ); - - ensure!( - foundry_data.minted_coin_id == *minted_coin_id, - "coin ID mismatch: found {}, expected {}", - foundry_data.minted_coin_id, - minted_coin_id - ); - - ensure!( - minted_coin.value() == foundry_data.minted_value, - "minted coin amount mismatch: found {}, expected {}", - minted_coin.value(), - foundry_data.minted_value - ); - - // Package - let package_id = created_objects.package()?; - let created_package = storage - .get_object(package_id) - .ok_or_else(|| anyhow!("missing package"))? - .data - .try_as_package() - .ok_or_else(|| anyhow!("expected a package"))?; - - ensure!( - foundry_data.package_id == *package_id, - "foundry data package ID mismatch: found {}, expected {}", - foundry_data.package_id, - package_id - ); - - let expected_package_data = NativeTokenPackageData::try_from(output)?; - - let module_id = ModuleId::new( - created_package.id().into(), - Identifier::new(expected_package_data.module().module_name.as_ref())?, - ); - - ensure!( - created_package.get_module(&module_id).is_some(), - "package did not create expected module `{}`", - expected_package_data.module().module_name - ); - - let type_origin_map = created_package.type_origin_map(); - - ensure!( - type_origin_map.contains_key(&( - expected_package_data.module().module_name.clone(), - expected_package_data.module().otw_name.clone() - )), - "package did not create expected OTW type `{}` within module `{}`", - expected_package_data.module().otw_name, - expected_package_data.module().module_name, - ); - ensure!( - foundry_data.coin_type_origin.module_name == expected_package_data.module().module_name, - "foundry data module name mismatch: found {}, expected {}", - foundry_data.coin_type_origin.module_name, - expected_package_data.module().module_name - ); - ensure!( - foundry_data.coin_type_origin.struct_name == expected_package_data.module().otw_name, - "foundry data OTW struct name mismatch: found {}, expected {}", - foundry_data.coin_type_origin.struct_name, - expected_package_data.module().otw_name - ); - - // Adjusted Token Scheme - let expected_token_scheme_u64 = - SimpleTokenSchemeU64::try_from(output.token_scheme().as_simple())?; - ensure!( - expected_token_scheme_u64 == foundry_data.token_scheme_u64, - "foundry data token scheme mismatch: found {:?}, expected: {:?}", - foundry_data.token_scheme_u64, - expected_token_scheme_u64 - ); - - // Coin Metadata - let minted_coin = created_objects - .coin_metadata() - .and_then(|id| { - storage - .get_object(id) - .ok_or_else(|| anyhow!("missing coin metadata")) - })? - .to_rust::() - .ok_or_else(|| anyhow!("expected a coin metadata"))?; - - ensure!( - minted_coin.decimals == expected_package_data.module().decimals, - "coin decimals mismatch: expected {}, found {}", - expected_package_data.module().decimals, - minted_coin.decimals - ); - ensure!( - minted_coin.name == expected_package_data.module().coin_name, - "coin name mismatch: expected {}, found {}", - expected_package_data.module().coin_name, - minted_coin.name - ); - ensure!( - minted_coin.symbol == expected_package_data.module().symbol, - "coin symbol mismatch: expected {}, found {}", - expected_package_data.module().symbol, - minted_coin.symbol - ); - ensure!( - minted_coin.description == expected_package_data.module().coin_description, - "coin description mismatch: expected {}, found {}", - expected_package_data.module().coin_description, - minted_coin.description - ); - ensure!( - minted_coin.icon_url - == expected_package_data - .module() - .icon_url - .as_ref() - .map(|u| u.to_string()), - "coin icon url mismatch: expected {:?}, found {:?}", - expected_package_data.module().icon_url, - minted_coin.icon_url - ); - - // Maximum Supply - let max_supply_policy_obj = created_objects.max_supply_policy().and_then(|id| { - storage - .get_object(id) - .ok_or_else(|| anyhow!("missing max supply policy")) - })?; - let max_supply_policy = max_supply_policy_obj - .to_rust::() - .ok_or_else(|| anyhow!("expected a max supply policy"))?; - - ensure!( - max_supply_policy.maximum_supply == expected_package_data.module().maximum_supply, - "maximum supply mismatch: expected {}, found {}", - expected_package_data.module().maximum_supply, - max_supply_policy.maximum_supply - ); - let circulating_supply = - truncate_to_max_allowed_u64_supply(output.token_scheme().as_simple().circulating_supply()); - ensure!( - max_supply_policy.treasury_cap.total_supply.value == circulating_supply, - "treasury total supply mismatch: found {}, expected {}", - max_supply_policy.treasury_cap.total_supply.value, - circulating_supply - ); - - // Alias Address Unlock Condition - verify_address_owner(alias_address, max_supply_policy_obj, "max supply policy")?; - - verify_parent(alias_address, storage)?; - - ensure!( - created_objects.output().is_err(), - "unexpected output object found" - ); - - Ok(()) -} diff --git a/crates/sui-genesis-builder/src/stardust/migration/verification/mod.rs b/crates/sui-genesis-builder/src/stardust/migration/verification/mod.rs deleted file mode 100644 index f79f82add3d..00000000000 --- a/crates/sui-genesis-builder/src/stardust/migration/verification/mod.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -//! The [`verification`] module contains the validation logic to make sure that -//! the stardust outputs are correctly converted to the move objects. - -use std::collections::HashMap; - -use anyhow::anyhow; -use iota_sdk::types::block::output::{Output, OutputId, TokenId}; -use sui_types::in_memory_storage::InMemoryStorage; - -use self::created_objects::CreatedObjects; -use crate::stardust::{migration::executor::FoundryLedgerData, types::snapshot::OutputHeader}; - -pub mod alias; -pub mod basic; -pub mod created_objects; -pub mod foundry; -pub mod nft; -mod util; - -pub(crate) fn verify_outputs<'a>( - outputs: impl IntoIterator, - output_objects_map: &HashMap, - foundry_data: &HashMap, - target_milestone_timestamp: u32, - storage: &InMemoryStorage, -) -> anyhow::Result<()> { - for (header, output) in outputs { - let created_objects = output_objects_map - .get(&header.output_id()) - .ok_or_else(|| anyhow!("missing created objects for output {}", header.output_id()))?; - verify_output( - header, - output, - created_objects, - foundry_data, - target_milestone_timestamp, - storage, - )?; - } - Ok(()) -} - -fn verify_output( - header: &OutputHeader, - output: &Output, - created_objects: &CreatedObjects, - foundry_data: &HashMap, - target_milestone_timestamp: u32, - storage: &InMemoryStorage, -) -> anyhow::Result<()> { - match output { - Output::Alias(output) => alias::verify_alias_output( - header.output_id(), - output, - created_objects, - foundry_data, - storage, - ), - Output::Basic(output) => basic::verify_basic_output( - header.output_id(), - output, - created_objects, - foundry_data, - target_milestone_timestamp, - storage, - ), - Output::Foundry(output) => { - foundry::verify_foundry_output(output, created_objects, foundry_data, storage) - } - Output::Nft(output) => nft::verify_nft_output( - header.output_id(), - output, - created_objects, - foundry_data, - storage, - ), - // Treasury outputs aren't used since Stardust, so no need to verify anything here. - Output::Treasury(_) => return Ok(()), - } - .map_err(|e| anyhow!("error verifying output {}: {}", header.output_id(), e)) -} diff --git a/crates/sui-genesis-builder/src/stardust/migration/verification/nft.rs b/crates/sui-genesis-builder/src/stardust/migration/verification/nft.rs deleted file mode 100644 index 0ae0f8d016b..00000000000 --- a/crates/sui-genesis-builder/src/stardust/migration/verification/nft.rs +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::HashMap; - -use anyhow::{anyhow, ensure}; -use iota_sdk::types::block::output::{NftOutput, OutputId, TokenId}; -use sui_types::{ - balance::Balance, - base_types::ObjectID, - dynamic_field::{derive_dynamic_field_id, DynamicFieldInfo, Field}, - in_memory_storage::InMemoryStorage, - object::Owner, - TypeTag, -}; - -use crate::stardust::{ - migration::{ - executor::FoundryLedgerData, - verification::{ - created_objects::CreatedObjects, - util::{ - verify_address_owner, verify_expiration_unlock_condition, verify_issuer_feature, - verify_metadata_feature, verify_native_tokens, verify_parent, - verify_sender_feature, verify_storage_deposit_unlock_condition, verify_tag_feature, - verify_timelock_unlock_condition, - }, - }, - }, - types::{NFT_DYNAMIC_OBJECT_FIELD_KEY, NFT_DYNAMIC_OBJECT_FIELD_KEY_TYPE}, -}; - -pub(super) fn verify_nft_output( - output_id: OutputId, - output: &NftOutput, - created_objects: &CreatedObjects, - foundry_data: &HashMap, - storage: &InMemoryStorage, -) -> anyhow::Result<()> { - let created_output_obj = created_objects.output().and_then(|id| { - storage - .get_object(id) - .ok_or_else(|| anyhow!("missing nft output object for {output_id}")) - })?; - let created_output = created_output_obj - .to_rust::() - .ok_or_else(|| anyhow!("invalid nft output object for {output_id}"))?; - - let created_nft_obj = storage - .get_object(&ObjectID::new(*output.nft_id_non_null(&output_id))) - .ok_or_else(|| anyhow!("missing nft object for {output_id}"))?; - let created_nft = created_nft_obj - .to_rust::() - .ok_or_else(|| anyhow!("invalid nft object for {output_id}"))?; - - // Output Owner - // If there is an expiration unlock condition, the NFT is shared. - if output.unlock_conditions().expiration().is_some() { - ensure!( - matches!(created_output_obj.owner, Owner::Shared { .. }), - "nft output owner mismatch: found {:?}, expected Shared", - created_output_obj.owner, - ); - } else { - verify_address_owner(output.address(), created_output_obj, "nft output")?; - } - - // NFT Owner - let expected_nft_owner = Owner::ObjectOwner( - derive_dynamic_field_id( - created_output_obj.id(), - &DynamicFieldInfo::dynamic_object_field_wrapper( - NFT_DYNAMIC_OBJECT_FIELD_KEY_TYPE.parse::()?, - ) - .into(), - &bcs::to_bytes(NFT_DYNAMIC_OBJECT_FIELD_KEY)?, - )? - .into(), - ); - - ensure!( - created_nft_obj.owner == expected_nft_owner, - "nft owner mismatch: found {}, expected {}", - created_nft_obj.owner, - expected_nft_owner - ); - - // Amount - ensure!( - created_output.iota.value() == output.amount(), - "amount mismatch: found {}, expected {}", - created_output.iota.value(), - output.amount() - ); - - // Native Tokens - verify_native_tokens::>( - output.native_tokens(), - foundry_data, - created_output.native_tokens, - created_objects.native_tokens().ok(), - storage, - )?; - - // Storage Deposit Return Unlock Condition - verify_storage_deposit_unlock_condition( - output.unlock_conditions().storage_deposit_return(), - created_output.storage_deposit_return.as_ref(), - )?; - - // Timelock Unlock Condition - verify_timelock_unlock_condition( - output.unlock_conditions().timelock(), - created_output.timelock.as_ref(), - )?; - - // Expiration Unlock Condition - verify_expiration_unlock_condition( - output.unlock_conditions().expiration(), - created_output.expiration.as_ref(), - output.address(), - )?; - - // Metadata Feature - verify_metadata_feature(output.features().metadata(), created_nft.metadata.as_ref())?; - - // Tag Feature - verify_tag_feature(output.features().tag(), created_nft.tag.as_ref())?; - - // Sender Feature - verify_sender_feature(output.features().sender(), created_nft.legacy_sender)?; - - // Issuer Feature - verify_issuer_feature( - output.immutable_features().issuer(), - created_nft.immutable_issuer, - )?; - - // Immutable Metadata Feature - ensure!( - crate::stardust::types::Nft::convert_immutable_metadata(output)? - == created_nft.immutable_metadata, - "metadata mismatch: found {:x?}, expected {:x?}", - crate::stardust::types::Nft::convert_immutable_metadata(output)?, - created_nft.immutable_metadata - ); - - verify_parent(output.address(), storage)?; - - ensure!(created_objects.coin().is_err(), "unexpected coin found"); - - ensure!( - created_objects.coin_metadata().is_err(), - "unexpected coin metadata found" - ); - - ensure!( - created_objects.minted_coin().is_err(), - "unexpected minted coin found" - ); - - ensure!( - created_objects.max_supply_policy().is_err(), - "unexpected max supply policy found" - ); - - ensure!( - created_objects.package().is_err(), - "unexpected package found" - ); - - Ok(()) -} diff --git a/crates/sui-genesis-builder/src/stardust/migration/verification/util.rs b/crates/sui-genesis-builder/src/stardust/migration/verification/util.rs deleted file mode 100644 index 06ef4210077..00000000000 --- a/crates/sui-genesis-builder/src/stardust/migration/verification/util.rs +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::HashMap; - -use anyhow::{anyhow, bail, ensure, Result}; -use iota_sdk::{ - types::block::{ - address::Address, - output::{self as sdk_output, NativeTokens, TokenId}, - }, - U256, -}; -use sui_types::{ - balance::Balance, - base_types::{ObjectID, SuiAddress}, - coin::Coin, - collection_types::Bag, - dynamic_field::Field, - in_memory_storage::InMemoryStorage, - object::Object, - TypeTag, -}; - -use crate::stardust::{ - migration::{executor::FoundryLedgerData, verification::CreatedObjects}, - types::{ - output as migration_output, stardust_to_sui_address, stardust_to_sui_address_owner, - token_scheme::MAX_ALLOWED_U64_SUPPLY, Alias, Nft, - }, -}; - -pub(super) fn verify_native_tokens( - native_tokens: &NativeTokens, - foundry_data: &HashMap, - native_tokens_bag: impl Into>, - created_native_tokens: Option<&[ObjectID]>, - storage: &InMemoryStorage, -) -> Result<()> { - // Token types should be unique as the token ID is guaranteed unique within - // NativeTokens - let created_native_tokens = created_native_tokens - .map(|object_ids| { - object_ids - .iter() - .map(|id| { - let obj = storage - .get_object(id) - .ok_or_else(|| anyhow!("missing native token field for {id}"))?; - NtKind::from_object(obj).map(|nt| (nt.token_type(), nt.value())) - }) - .collect::, _>>() - }) - .unwrap_or(Ok(HashMap::new()))?; - - ensure!( - created_native_tokens.len() == native_tokens.len(), - "native token count mismatch: found {}, expected: {}", - created_native_tokens.len(), - native_tokens.len(), - ); - - if let Some(native_tokens_bag) = native_tokens_bag.into() { - ensure!( - native_tokens_bag.size == native_tokens.len() as u64, - "native tokens bag length mismatch: found {}, expected {}", - native_tokens_bag.size, - native_tokens.len() - ); - } - - for native_token in native_tokens.iter() { - let foundry_data = foundry_data - .get(native_token.token_id()) - .ok_or_else(|| anyhow!("missing foundry data for token {}", native_token.token_id()))?; - - let expected_token_type = foundry_data.canonical_coin_type(); - // The token amounts are scaled so that the total circulating supply does not - // exceed `u64::MAX` - let reduced_amount = foundry_data - .token_scheme_u64 - .adjust_tokens(native_token.amount()); - - if let Some(created_value) = created_native_tokens.get(&expected_token_type) { - ensure!( - *created_value == reduced_amount, - "created token amount mismatch: found {created_value}, expected {reduced_amount}" - ); - } else { - bail!( - "native token object was not created for token: {}", - native_token.token_id() - ); - } - } - - Ok(()) -} - -pub(super) fn verify_storage_deposit_unlock_condition( - original: Option<&sdk_output::unlock_condition::StorageDepositReturnUnlockCondition>, - created: Option<&migration_output::StorageDepositReturnUnlockCondition>, -) -> Result<()> { - // Storage Deposit Return Unlock Condition - if let Some(sdruc) = original { - let sui_return_address = stardust_to_sui_address(sdruc.return_address())?; - if let Some(obj_sdruc) = created { - ensure!( - obj_sdruc.return_address == sui_return_address, - "storage deposit return address mismatch: found {}, expected {}", - obj_sdruc.return_address, - sui_return_address - ); - ensure!( - obj_sdruc.return_amount == sdruc.amount(), - "storage deposit return amount mismatch: found {}, expected {}", - obj_sdruc.return_amount, - sdruc.amount() - ); - } else { - bail!("missing storage deposit return on object"); - } - } else { - ensure!( - created.is_none(), - "erroneous storage deposit return on object" - ); - } - Ok(()) -} - -pub(super) fn verify_timelock_unlock_condition( - original: Option<&sdk_output::unlock_condition::TimelockUnlockCondition>, - created: Option<&migration_output::TimelockUnlockCondition>, -) -> Result<()> { - // Timelock Unlock Condition - if let Some(timelock) = original { - if let Some(obj_timelock) = created { - ensure!( - obj_timelock.unix_time == timelock.timestamp(), - "timelock timestamp mismatch: found {}, expected {}", - obj_timelock.unix_time, - timelock.timestamp() - ); - } else { - bail!("missing timelock on object"); - } - } else { - ensure!(created.is_none(), "erroneous timelock on object"); - } - Ok(()) -} - -pub(super) fn verify_expiration_unlock_condition( - original: Option<&sdk_output::unlock_condition::ExpirationUnlockCondition>, - created: Option<&migration_output::ExpirationUnlockCondition>, - address: &Address, -) -> Result<()> { - // Expiration Unlock Condition - if let Some(expiration) = original { - if let Some(obj_expiration) = created { - let sui_address = stardust_to_sui_address(address)?; - let sui_return_address = stardust_to_sui_address(expiration.return_address())?; - ensure!( - obj_expiration.owner == sui_address, - "expiration owner mismatch: found {}, expected {}", - obj_expiration.owner, - sui_address - ); - ensure!( - obj_expiration.return_address == sui_return_address, - "expiration return address mismatch: found {}, expected {}", - obj_expiration.return_address, - sui_return_address - ); - ensure!( - obj_expiration.unix_time == expiration.timestamp(), - "expiration timestamp mismatch: found {}, expected {}", - obj_expiration.unix_time, - expiration.timestamp() - ); - } else { - bail!("missing expiration on object"); - } - } else { - ensure!(created.is_none(), "erroneous expiration on object"); - } - Ok(()) -} - -pub(super) fn verify_metadata_feature( - original: Option<&sdk_output::feature::MetadataFeature>, - created: Option<&Vec>, -) -> Result<()> { - if let Some(metadata) = original { - if let Some(obj_metadata) = created { - ensure!( - obj_metadata.as_slice() == metadata.data(), - "metadata mismatch: found {:x?}, expected {:x?}", - obj_metadata.as_slice(), - metadata.data() - ); - } else { - bail!("missing metadata on object"); - } - } else { - ensure!(created.is_none(), "erroneous metadata on object"); - } - Ok(()) -} - -pub(super) fn verify_tag_feature( - original: Option<&sdk_output::feature::TagFeature>, - created: Option<&Vec>, -) -> Result<()> { - if let Some(tag) = original { - if let Some(obj_tag) = created { - ensure!( - obj_tag.as_slice() == tag.tag(), - "tag mismatch: found {:x?}, expected {:x?}", - obj_tag.as_slice(), - tag.tag() - ); - } else { - bail!("missing tag on object"); - } - } else { - ensure!(created.is_none(), "erroneous tag on object"); - } - Ok(()) -} - -pub(super) fn verify_sender_feature( - original: Option<&sdk_output::feature::SenderFeature>, - created: Option, -) -> Result<()> { - if let Some(sender) = original { - let sui_sender_address = stardust_to_sui_address(sender.address())?; - if let Some(obj_sender) = created { - ensure!( - obj_sender == sui_sender_address, - "sender mismatch: found {}, expected {}", - obj_sender, - sui_sender_address - ); - } else { - bail!("missing sender on object"); - } - } else { - ensure!(created.is_none(), "erroneous sender on object"); - } - Ok(()) -} - -pub(super) fn verify_issuer_feature( - original: Option<&sdk_output::feature::IssuerFeature>, - created: Option, -) -> Result<()> { - if let Some(issuer) = original { - let sui_issuer_address = stardust_to_sui_address(issuer.address())?; - if let Some(obj_issuer) = created { - ensure!( - obj_issuer == sui_issuer_address, - "issuer mismatch: found {}, expected {}", - obj_issuer, - sui_issuer_address - ); - } else { - bail!("missing issuer on object"); - } - } else { - ensure!(created.is_none(), "erroneous issuer on object"); - } - Ok(()) -} - -pub(super) fn verify_address_owner( - owning_address: &Address, - obj: &Object, - name: &str, -) -> Result<()> { - let expected_owner = stardust_to_sui_address_owner(owning_address)?; - ensure!( - obj.owner == expected_owner, - "{name} owner mismatch: found {}, expected {}", - obj.owner, - expected_owner - ); - Ok(()) -} - -// Checks whether an object exists for this address and whether it is the -// expected alias or nft object. We do not expect an object for Ed25519 -// addresses. -pub(super) fn verify_parent(address: &Address, storage: &InMemoryStorage) -> Result<()> { - let object_id = ObjectID::from(stardust_to_sui_address(address)?); - let parent = storage.get_object(&object_id); - match address { - Address::Alias(address) => { - if let Some(parent_obj) = parent { - parent_obj - .to_rust::() - .ok_or_else(|| anyhow!("invalid alias object for {address}"))?; - } - } - Address::Nft(address) => { - if let Some(parent_obj) = parent { - parent_obj - .to_rust::() - .ok_or_else(|| anyhow!("invalid nft object for {address}"))?; - } - } - Address::Ed25519(address) => { - ensure!( - parent.is_none(), - "unexpected parent found for ed25519 address {address}", - ); - } - } - Ok(()) -} - -pub(super) fn verify_coin( - output_amount: u64, - owning_address: &Address, - created_objects: &CreatedObjects, - storage: &InMemoryStorage, -) -> Result<()> { - let created_coin_obj = created_objects.coin().and_then(|id| { - storage - .get_object(id) - .ok_or_else(|| anyhow!("missing coin")) - })?; - let created_coin = created_coin_obj - .as_coin_maybe() - .ok_or_else(|| anyhow!("expected a coin"))?; - - ensure!( - created_coin.value() == output_amount, - "coin amount mismatch: found {}, expected {}", - created_coin.value(), - output_amount - ); - - verify_address_owner(owning_address, created_coin_obj, "coin") -} - -pub(super) trait NativeTokenKind { - fn token_type(&self) -> String; - - fn value(&self) -> u64; - - fn from_object(obj: &Object) -> Result - where - Self: Sized; -} - -impl NativeTokenKind for (TypeTag, Coin) { - fn token_type(&self) -> String { - self.0.to_canonical_string(true) - } - - fn value(&self) -> u64 { - self.1.value() - } - - fn from_object(obj: &Object) -> Result { - obj.coin_type_maybe() - .zip(obj.as_coin_maybe()) - .ok_or_else(|| anyhow!("expected a native token coin, found {:?}", obj.type_())) - } -} - -impl NativeTokenKind for Field { - fn token_type(&self) -> String { - self.name.clone() - } - - fn value(&self) -> u64 { - self.value.value() - } - - fn from_object(obj: &Object) -> Result { - obj.to_rust::>() - .ok_or_else(|| anyhow!("expected a native token field, found {:?}", obj.type_())) - } -} - -pub fn truncate_to_max_allowed_u64_supply(value: U256) -> u64 { - if value > U256::from(MAX_ALLOWED_U64_SUPPLY) { - MAX_ALLOWED_U64_SUPPLY - } else { - value.as_u64() - } -} diff --git a/crates/sui-genesis-builder/src/stardust/mod.rs b/crates/sui-genesis-builder/src/stardust/mod.rs deleted file mode 100644 index 617b442df70..00000000000 --- a/crates/sui-genesis-builder/src/stardust/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -//! The [`stardust`] module incorporates all the logic necessary for -//! parsing Stardust UTXOs from a full-snapshot file, and converting -//! them to the appropriate genesis objects. - -pub mod error; -pub mod migration; -pub mod native_token; -pub mod parse; -pub mod types; diff --git a/crates/sui-genesis-builder/src/stardust/native_token/mod.rs b/crates/sui-genesis-builder/src/stardust/native_token/mod.rs deleted file mode 100644 index 8addf637863..00000000000 --- a/crates/sui-genesis-builder/src/stardust/native_token/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -//! The [`native_token`] module incorporates all the logic necessary for -//! building Stardust native token modules and packages. - -pub mod package_builder; -pub mod package_data; diff --git a/crates/sui-genesis-builder/src/stardust/native_token/package_template/Move.toml b/crates/sui-genesis-builder/src/stardust/native_token/package_template/Move.toml deleted file mode 100644 index 16c58aad0db..00000000000 --- a/crates/sui-genesis-builder/src/stardust/native_token/package_template/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "$PACKAGE_NAME" -version = "0.0.1" -edition = "2024.beta" - -[dependencies] -MoveStdlib = { local = "$FRAMEWORK_PACKAGES_PATH/move-stdlib" } -Sui = { local = "$FRAMEWORK_PACKAGES_PATH/sui-framework" } -Stardust = { local = "$FRAMEWORK_PACKAGES_PATH/stardust" } diff --git a/crates/sui-genesis-builder/src/stardust/types/address.rs b/crates/sui-genesis-builder/src/stardust/types/address.rs deleted file mode 100644 index ef985cac139..00000000000 --- a/crates/sui-genesis-builder/src/stardust/types/address.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use iota_sdk::types::block::address::Address; -use sui_types::{base_types::SuiAddress, object::Owner}; - -/// Converts a ["Stardust" `Address`](Address) to a [`SuiAddress`]. -/// -/// This is intended as the only conversion function to go from Stardust to Sui -/// addresses, so there is only one place to potentially update it if we decide -/// to change it later. -pub fn stardust_to_sui_address(stardust_address: impl Into
    ) -> anyhow::Result { - stardust_address.into().to_string().parse() -} - -/// Converts a ["Stardust" `Address`](Address) to a [`SuiAddress`] and then -/// wraps it into an [`Owner`] which is either address- or object-owned -/// depending on the stardust address. -pub fn stardust_to_sui_address_owner( - stardust_address: impl Into
    , -) -> anyhow::Result { - stardust_to_sui_address(stardust_address.into()).map(Owner::AddressOwner) -} diff --git a/crates/sui-genesis-builder/src/stardust/types/alias.rs b/crates/sui-genesis-builder/src/stardust/types/alias.rs deleted file mode 100644 index 9255cb17e98..00000000000 --- a/crates/sui-genesis-builder/src/stardust/types/alias.rs +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use iota_sdk::types::block::output::AliasOutput as StardustAlias; -use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ - balance::Balance, - base_types::{ObjectID, SequenceNumber, SuiAddress, TxContext}, - collection_types::Bag, - id::UID, - object::{Data, MoveObject, Object, Owner}, - STARDUST_PACKAGE_ID, -}; - -use super::stardust_to_sui_address; - -pub const ALIAS_MODULE_NAME: &IdentStr = ident_str!("alias"); -pub const ALIAS_OUTPUT_MODULE_NAME: &IdentStr = ident_str!("alias_output"); -pub const ALIAS_OUTPUT_STRUCT_NAME: &IdentStr = ident_str!("AliasOutput"); -pub const ALIAS_STRUCT_NAME: &IdentStr = ident_str!("Alias"); -pub const ALIAS_DYNAMIC_OBJECT_FIELD_KEY: &[u8] = b"alias"; -pub const ALIAS_DYNAMIC_OBJECT_FIELD_KEY_TYPE: &str = "vector"; - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct Alias { - /// The ID of the Alias = hash of the Output ID that created the Alias - /// Output in Stardust. This is the AliasID from Stardust. - pub id: UID, - - /// The last State Controller address assigned before the migration. - pub legacy_state_controller: SuiAddress, - /// A counter increased by 1 every time the alias was state transitioned. - pub state_index: u32, - /// State metadata that can be used to store additional information. - pub state_metadata: Option>, - - /// The sender feature. - pub sender: Option, - /// The metadata feature. - pub metadata: Option>, - - /// The immutable issuer feature. - pub immutable_issuer: Option, - /// The immutable metadata feature. - pub immutable_metadata: Option>, -} - -impl Alias { - pub fn tag() -> StructTag { - StructTag { - address: STARDUST_PACKAGE_ID.into(), - module: ALIAS_MODULE_NAME.to_owned(), - name: ALIAS_STRUCT_NAME.to_owned(), - type_params: Vec::new(), - } - } - - /// Creates the Move-based Alias model from a Stardust-based Alias Output. - pub fn try_from_stardust( - alias_id: ObjectID, - alias: &StardustAlias, - ) -> Result { - if alias_id.as_ref() == [0; 32] { - anyhow::bail!("alias_id must be non-zeroed"); - } - - let state_metadata: Option> = if alias.state_metadata().is_empty() { - None - } else { - Some(alias.state_metadata().to_vec()) - }; - let sender: Option = alias - .features() - .sender() - .map(|sender_feat| stardust_to_sui_address(sender_feat.address())) - .transpose()?; - let metadata: Option> = alias - .features() - .metadata() - .map(|metadata_feat| metadata_feat.data().to_vec()); - let immutable_issuer: Option = alias - .immutable_features() - .issuer() - .map(|issuer_feat| stardust_to_sui_address(issuer_feat.address())) - .transpose()?; - let immutable_metadata: Option> = alias - .immutable_features() - .metadata() - .map(|metadata_feat| metadata_feat.data().to_vec()); - - Ok(Alias { - id: UID::new(alias_id), - legacy_state_controller: stardust_to_sui_address(alias.state_controller_address())?, - state_index: alias.state_index(), - state_metadata, - sender, - metadata, - immutable_issuer, - immutable_metadata, - }) - } - - pub fn to_genesis_object( - &self, - owner: Owner, - protocol_config: &ProtocolConfig, - tx_context: &TxContext, - version: SequenceNumber, - ) -> anyhow::Result { - // Construct the Alias object. - let move_alias_object = unsafe { - // Safety: we know from the definition of `Alias` in the stardust package - // that it has public transfer (`store` ability is present). - MoveObject::new_from_execution( - Self::tag().into(), - true, - version, - bcs::to_bytes(&self)?, - protocol_config, - )? - }; - - let move_alias_object = Object::new_from_genesis( - Data::Move(move_alias_object), - // We will later overwrite the owner we set here since this object will be added - // as a dynamic field on the alias output object. - owner, - tx_context.digest(), - ); - - Ok(move_alias_object) - } -} - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct AliasOutput { - /// This is a "random" UID, not the AliasID from Stardust. - pub id: UID, - - /// The amount of IOTA coins held by the output. - pub iota: Balance, - /// The `Bag` holds native tokens, key-ed by the stringified type of the - /// asset. Example: key: "0xabcded::soon::SOON", value: - /// Balance<0xabcded::soon::SOON>. - pub native_tokens: Bag, -} - -impl AliasOutput { - pub fn tag() -> StructTag { - StructTag { - address: STARDUST_PACKAGE_ID.into(), - module: ALIAS_OUTPUT_MODULE_NAME.to_owned(), - name: ALIAS_OUTPUT_STRUCT_NAME.to_owned(), - type_params: Vec::new(), - } - } - - /// Creates the Move-based Alias Output model from a Stardust-based Alias - /// Output. - pub fn try_from_stardust( - object_id: ObjectID, - alias: &StardustAlias, - native_tokens: Bag, - ) -> Result { - Ok(AliasOutput { - id: UID::new(object_id), - iota: Balance::new(alias.amount()), - native_tokens, - }) - } - - pub fn to_genesis_object( - &self, - owner: Owner, - protocol_config: &ProtocolConfig, - tx_context: &TxContext, - version: SequenceNumber, - ) -> anyhow::Result { - // Construct the Alias Output object. - let move_alias_output_object = unsafe { - // Safety: we know from the definition of `AliasOutput` in the stardust package - // that it does not have public transfer (`store` ability is absent). - MoveObject::new_from_execution( - AliasOutput::tag().into(), - false, - version, - bcs::to_bytes(&self)?, - protocol_config, - )? - }; - - let move_alias_output_object = Object::new_from_genesis( - Data::Move(move_alias_output_object), - owner, - tx_context.digest(), - ); - - Ok(move_alias_output_object) - } -} diff --git a/crates/sui-genesis-builder/src/stardust/types/foundry.rs b/crates/sui-genesis-builder/src/stardust/types/foundry.rs deleted file mode 100644 index 898a97d06eb..00000000000 --- a/crates/sui-genesis-builder/src/stardust/types/foundry.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use iota_sdk::types::block::output::{FoundryOutput, OutputId}; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ - base_types::{ObjectID, SequenceNumber, TxContext}, - id::UID, - object::Object, -}; - -use crate::{stardust, stardust::types::stardust_to_sui_address}; - -pub(crate) fn create_foundry_gas_coin( - output_id: &OutputId, - foundry: &FoundryOutput, - tx_context: &TxContext, - version: SequenceNumber, - protocol_config: &ProtocolConfig, -) -> anyhow::Result { - stardust::types::output::create_gas_coin( - UID::new(ObjectID::new(output_id.hash())), - stardust_to_sui_address(*foundry.alias_address())?, - foundry.amount(), - tx_context, - version, - protocol_config, - ) -} diff --git a/crates/sui-genesis-builder/src/stardust/types/mod.rs b/crates/sui-genesis-builder/src/stardust/types/mod.rs deleted file mode 100644 index 5d944e43112..00000000000 --- a/crates/sui-genesis-builder/src/stardust/types/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -pub mod address; -pub mod alias; -pub mod capped_coin; -pub mod foundry; -pub mod nft; -pub mod output; -pub mod snapshot; -pub mod timelock; -pub mod token_scheme; - -pub use address::*; -pub use alias::*; -pub use nft::*; diff --git a/crates/sui-genesis-builder/src/stardust/types/nft.rs b/crates/sui-genesis-builder/src/stardust/types/nft.rs deleted file mode 100644 index 80d0995df6d..00000000000 --- a/crates/sui-genesis-builder/src/stardust/types/nft.rs +++ /dev/null @@ -1,466 +0,0 @@ -use anyhow::anyhow; -use iota_sdk::types::block::output::{ - feature::Irc27Metadata as StardustIrc27, NftOutput as StardustNft, -}; -use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; -use num_rational::Ratio; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ - balance::Balance, - base_types::{ObjectID, SequenceNumber, SuiAddress, TxContext}, - collection_types::{Bag, Entry, VecMap}, - id::UID, - object::{Data, MoveObject, Object, Owner}, - STARDUST_PACKAGE_ID, -}; - -use super::{ - output::{ - ExpirationUnlockCondition, StorageDepositReturnUnlockCondition, TimelockUnlockCondition, - }, - stardust_to_sui_address, -}; - -pub const IRC27_MODULE_NAME: &IdentStr = ident_str!("irc27"); -pub const NFT_MODULE_NAME: &IdentStr = ident_str!("nft"); -pub const NFT_OUTPUT_MODULE_NAME: &IdentStr = ident_str!("nft_output"); -pub const NFT_OUTPUT_STRUCT_NAME: &IdentStr = ident_str!("NftOutput"); -pub const NFT_STRUCT_NAME: &IdentStr = ident_str!("Nft"); -pub const IRC27_STRUCT_NAME: &IdentStr = ident_str!("Irc27Metadata"); -pub const NFT_DYNAMIC_OBJECT_FIELD_KEY: &[u8] = b"nft"; -pub const NFT_DYNAMIC_OBJECT_FIELD_KEY_TYPE: &str = "vector"; - -/// Rust version of the Move std::fixed_point32::FixedPoint32 type. -#[derive(Debug, Default, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct FixedPoint32 { - pub value: u64, -} - -impl FixedPoint32 { - /// Create a fixed-point value from a rational number specified by its - /// numerator and denominator. Imported from Move std lib. - /// This will panic if the denominator is zero. It will also - /// abort if the numerator is nonzero and the ratio is not in the range - /// 2^-32 .. 2^32-1. When specifying decimal fractions, be careful about - /// rounding errors: if you round to display N digits after the decimal - /// point, you can use a denominator of 10^N to avoid numbers where the - /// very small imprecision in the binary representation could change the - /// rounding, e.g., 0.0125 will round down to 0.012 instead of up to 0.013. - fn create_from_rational(numerator: u64, denominator: u64) -> Self { - // If the denominator is zero, this will abort. - // Scale the numerator to have 64 fractional bits and the denominator - // to have 32 fractional bits, so that the quotient will have 32 - // fractional bits. - let scaled_numerator = (numerator as u128) << 64; - let scaled_denominator = (denominator as u128) << 32; - assert!(scaled_denominator != 0); - let quotient = scaled_numerator / scaled_denominator; - assert!(quotient != 0 || numerator == 0); - // Return the quotient as a fixed-point number. We first need to check whether - // the cast can succeed. - assert!(quotient <= u64::MAX as u128); - FixedPoint32 { - value: quotient as u64, - } - } -} - -impl TryFrom for FixedPoint32 { - type Error = anyhow::Error; - fn try_from(value: f64) -> Result { - let value = Ratio::from_float(value).ok_or(anyhow!("Missing attribute"))?; - let numerator = value.numer().clone().try_into()?; - let denominator = value.denom().clone().try_into()?; - Ok(FixedPoint32::create_from_rational(numerator, denominator)) - } -} - -/// Rust version of the Move sui::url::Url type. -#[derive(Debug, Default, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct Url { - /// The underlying URL as a string. - /// - /// # SAFETY - /// - /// Note that this String is UTF-8 encoded while the URL type in Move is - /// ascii-encoded. Setting this field requires ensuring that the string - /// consists of only ASCII characters. - pub(crate) url: String, -} - -impl TryFrom for Url { - type Error = anyhow::Error; - - /// Creates a new `Url` ensuring that it only consists of ascii characters. - fn try_from(url: String) -> Result { - if !url.is_ascii() { - anyhow::bail!("url `{url}` does not consist of only ascii characters") - } - Ok(Url { url }) - } -} - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct Irc27Metadata { - /// Version of the metadata standard. - pub version: String, - - /// The media type (MIME) of the asset. - /// - /// ## Examples - /// - Image files: `image/jpeg`, `image/png`, `image/gif`, etc. - /// - Video files: `video/x-msvideo` (avi), `video/mp4`, `video/mpeg`, etc. - /// - Audio files: `audio/mpeg`, `audio/wav`, etc. - /// - 3D Assets: `model/obj`, `model/u3d`, etc. - /// - Documents: `application/pdf`, `text/plain`, etc. - pub media_type: String, - - /// URL pointing to the NFT file location. - pub uri: Url, - - /// Alphanumeric text string defining the human identifiable name for the - /// NFT. - pub name: String, - - /// The human-readable collection name of the NFT. - pub collection_name: Option, - - /// Royalty payment addresses mapped to the payout percentage. - /// Contains a hash of the 32 bytes parsed from the BECH32 encoded IOTA - /// address in the metadata, it is a legacy address. Royalties are not - /// supported by the protocol and needed to be processed by an integrator. - pub royalties: VecMap, - - /// The human-readable name of the NFT creator. - pub issuer_name: Option, - - /// The human-readable description of the NFT. - pub description: Option, - - /// Additional attributes which follow [OpenSea Metadata standards](https://docs.opensea.io/docs/metadata-standards). - pub attributes: VecMap, - - /// Legacy non-standard metadata fields. - pub non_standard_fields: VecMap, -} - -impl TryFrom for Irc27Metadata { - type Error = anyhow::Error; - fn try_from(irc27: StardustIrc27) -> Result { - Ok(Self { - version: irc27.version().to_string(), - media_type: irc27.media_type().to_string(), - // We are converting a `Url` to an ASCII string here (as the URL type in move is based - // on ASCII strings). The `ToString` implementation of the `Url` ensures - // only ascii characters are returned and this conversion is therefore safe - // to do. - uri: Url::try_from(irc27.uri().to_string()) - .expect("url should only contain ascii characters"), - name: irc27.name().to_string(), - collection_name: irc27.collection_name().clone(), - royalties: VecMap { - contents: irc27 - .royalties() - .iter() - .map(|(addr, value)| { - Ok(Entry { - key: stardust_to_sui_address(addr.inner())?, - value: FixedPoint32::try_from(*value)?, - }) - }) - .collect::>, Self::Error>>()?, - }, - issuer_name: irc27.issuer_name().clone(), - description: irc27.description().clone(), - attributes: VecMap { - contents: irc27 - .attributes() - .iter() - .map(|attribute| Entry { - key: attribute.trait_type().to_string(), - value: attribute.value().to_string(), - }) - .collect(), - }, - non_standard_fields: VecMap { - contents: Vec::new(), - }, - }) - } -} - -impl Default for Irc27Metadata { - fn default() -> Self { - // The currently supported version per . - let version = "v1.0".to_owned(); - // Matches the media type of the URI below. - let media_type = "image/png".to_owned(); - // A placeholder for NFTs without metadata from which we can extract a URI. - let uri = Url::try_from( - iota_sdk::Url::parse("https://opensea.io/static/images/placeholder.png") - .expect("should be a valid url") - .to_string(), - ) - .expect("url should only contain ascii characters"); - let name = "NFT".to_owned(); - - Self { - version, - media_type, - uri, - name, - collection_name: Default::default(), - royalties: VecMap { - contents: Vec::new(), - }, - issuer_name: Default::default(), - description: Default::default(), - attributes: VecMap { - contents: Vec::new(), - }, - non_standard_fields: VecMap { - contents: Vec::new(), - }, - } - } -} - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct Nft { - /// The ID of the Nft = hash of the Output ID that created the Nft Output in - /// Stardust. This is the NftID from Stardust. - pub id: UID, - - /// The sender feature holds the last sender address assigned before the - /// migration and is not supported by the protocol after it. - pub legacy_sender: Option, - /// The metadata feature. - pub metadata: Option>, - /// The tag feature. - pub tag: Option>, - - /// The immutable issuer feature. - pub immutable_issuer: Option, - /// The immutable metadata feature. - pub immutable_metadata: Irc27Metadata, -} - -impl Nft { - pub fn tag() -> StructTag { - StructTag { - address: STARDUST_PACKAGE_ID.into(), - module: NFT_MODULE_NAME.to_owned(), - name: NFT_STRUCT_NAME.to_owned(), - type_params: Vec::new(), - } - } - - /// Creates the Move-based Nft model from a Stardust-based Nft Output. - pub fn try_from_stardust(nft_id: ObjectID, nft: &StardustNft) -> Result { - if nft_id.as_ref() == [0; 32] { - anyhow::bail!("nft_id must be non-zeroed"); - } - - let legacy_sender: Option = nft - .features() - .sender() - .map(|sender_feat| stardust_to_sui_address(sender_feat.address())) - .transpose()?; - let metadata: Option> = nft - .features() - .metadata() - .map(|metadata_feat| metadata_feat.data().to_vec()); - let tag: Option> = nft.features().tag().map(|tag_feat| tag_feat.tag().to_vec()); - let immutable_issuer: Option = nft - .immutable_features() - .issuer() - .map(|issuer_feat| stardust_to_sui_address(issuer_feat.address())) - .transpose()?; - let irc27: Irc27Metadata = Self::convert_immutable_metadata(nft)?; - - Ok(Nft { - id: UID::new(nft_id), - legacy_sender, - metadata, - tag, - immutable_issuer, - immutable_metadata: irc27, - }) - } - - /// Converts the immutable metadata of the NFT into an [`Irc27Metadata`]. - /// - /// - If the metadata does not exist returns the default `Irc27Metadata`. - /// - If the metadata can be parsed into [`StardustIrc27`] returns that - /// converted into `Irc27Metadata`. - /// - If the metadata can be parsed into a JSON object returns the default - /// `Irc27Metadata` with `non_standard_fields` set to the fields of the - /// object. - /// - Otherwise, returns the default `Irc27Metadata` with - /// `non_standard_fields` containing a `data` key with the hex-encoded - /// metadata (without `0x` prefix). - /// - /// Note that the metadata feature of the NFT cannot be present _and_ empty - /// per the protocol rules: . - pub(crate) fn convert_immutable_metadata(nft: &StardustNft) -> anyhow::Result { - let Some(metadata) = nft.immutable_features().metadata() else { - return Ok(Irc27Metadata::default()); - }; - - if let Ok(parsed_irc27_metadata) = serde_json::from_slice::(metadata.data()) - { - return Irc27Metadata::try_from(parsed_irc27_metadata); - } - - if let Ok(serde_json::Value::Object(json_object)) = - serde_json::from_slice::(metadata.data()) - { - let mut irc_metadata = Irc27Metadata::default(); - - for (key, value) in json_object.into_iter() { - irc_metadata.non_standard_fields.contents.push(Entry { - key, - value: value.to_string(), - }) - } - - return Ok(irc_metadata); - } - - let mut irc_metadata = Irc27Metadata::default(); - let hex_encoded_metadata = hex::encode(metadata.data()); - irc_metadata.non_standard_fields.contents.push(Entry { - key: "data".to_owned(), - value: hex_encoded_metadata, - }); - Ok(irc_metadata) - } - - pub fn to_genesis_object( - &self, - owner: Owner, - protocol_config: &ProtocolConfig, - tx_context: &TxContext, - version: SequenceNumber, - ) -> anyhow::Result { - // Construct the Nft object. - let move_nft_object = unsafe { - // Safety: we know from the definition of `Nft` in the stardust package - // that it has public transfer (`store` ability is present). - MoveObject::new_from_execution( - Self::tag().into(), - true, - version, - bcs::to_bytes(&self)?, - protocol_config, - )? - }; - - let move_nft_object = Object::new_from_genesis( - Data::Move(move_nft_object), - // We will later overwrite the owner we set here since this object will be added - // as a dynamic field on the nft output object. - owner, - tx_context.digest(), - ); - - Ok(move_nft_object) - } -} - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct NftOutput { - /// This is a "random" UID, not the NftID from Stardust. - pub id: UID, - - /// The amount of IOTA coins held by the output. - pub iota: Balance, - /// The `Bag` holds native tokens, key-ed by the stringified type of the - /// asset. Example: key: "0xabcded::soon::SOON", value: - /// Balance<0xabcded::soon::SOON>. - pub native_tokens: Bag, - - /// The storage deposit return unlock condition. - pub storage_deposit_return: Option, - /// The timelock unlock condition. - pub timelock: Option, - /// The expiration unlock condition. - pub expiration: Option, -} - -impl NftOutput { - pub fn tag() -> StructTag { - StructTag { - address: STARDUST_PACKAGE_ID.into(), - module: NFT_OUTPUT_MODULE_NAME.to_owned(), - name: NFT_OUTPUT_STRUCT_NAME.to_owned(), - type_params: Vec::new(), - } - } - - /// Creates the Move-based Nft Output model from a Stardust-based Nft - /// Output. - pub fn try_from_stardust( - object_id: ObjectID, - nft: &StardustNft, - native_tokens: Bag, - ) -> Result { - let unlock_conditions = nft.unlock_conditions(); - Ok(NftOutput { - id: UID::new(object_id), - iota: Balance::new(nft.amount()), - native_tokens, - storage_deposit_return: unlock_conditions - .storage_deposit_return() - .map(|unlock| unlock.try_into()) - .transpose()?, - timelock: unlock_conditions.timelock().map(|unlock| unlock.into()), - expiration: unlock_conditions - .expiration() - .map(|expiration| ExpirationUnlockCondition::new(nft.address(), expiration)) - .transpose()?, - }) - } - - pub fn to_genesis_object( - &self, - owner: SuiAddress, - protocol_config: &ProtocolConfig, - tx_context: &TxContext, - version: SequenceNumber, - ) -> anyhow::Result { - // Construct the Nft Output object. - let move_nft_output_object = unsafe { - // Safety: we know from the definition of `NftOutput` in the stardust package - // that it does not have public transfer (`store` ability is absent). - MoveObject::new_from_execution( - NftOutput::tag().into(), - false, - version, - bcs::to_bytes(&self)?, - protocol_config, - )? - }; - - let owner = if self.expiration.is_some() { - Owner::Shared { - initial_shared_version: version, - } - } else { - Owner::AddressOwner(owner) - }; - - let move_nft_output_object = Object::new_from_genesis( - Data::Move(move_nft_output_object), - owner, - tx_context.digest(), - ); - - Ok(move_nft_output_object) - } -} diff --git a/crates/sui-genesis-builder/src/stardust/types/timelock.rs b/crates/sui-genesis-builder/src/stardust/types/timelock.rs deleted file mode 100644 index 871a0227775..00000000000 --- a/crates/sui-genesis-builder/src/stardust/types/timelock.rs +++ /dev/null @@ -1,391 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use iota_sdk::types::block::output::{BasicOutput, OutputId}; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ - balance::Balance, - base_types::{MoveObjectType, ObjectID, SequenceNumber, SuiAddress, TxContext}, - id::UID, - object::{Data, MoveObject, Object, Owner}, - timelock::timelock::TimeLock, -}; - -/// All basic outputs whose IDs start with this prefix represent vested rewards -/// that were created during the stardust upgrade on IOTA mainnet. -const VESTED_REWARD_ID_PREFIX: &str = "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb18"; - -#[derive(Debug, thiserror::Error)] -pub enum VestedRewardError { - #[error("failed to create genesis move object, owner: {owner}, timelock: {timelock:#?}")] - ObjectCreation { - owner: SuiAddress, - timelock: TimeLock, - source: sui_types::error::ExecutionError, - }, - #[error("a vested reward must not contain native tokens")] - NativeTokensNotSupported, - #[error("a basic output is not a vested reward")] - NotVestedReward, - #[error("a vested reward must have two unlock conditions")] - UnlockConditionsNumberMismatch, - #[error("only timelocked vested rewards can be migrated as `TimeLock>`")] - UnlockedVestedReward, -} - -/// Checks if an output is a timelocked vested reward. -pub fn is_timelocked_vested_reward( - output_id: OutputId, - basic_output: &BasicOutput, - target_milestone_timestamp_sec: u32, -) -> bool { - is_vested_reward(output_id, basic_output) - && basic_output - .unlock_conditions() - .is_time_locked(target_milestone_timestamp_sec) -} - -/// Checks if an output is a vested reward, if it has a specific ID prefix, -/// and if it contains a timelock unlock condition. -fn is_vested_reward(output_id: OutputId, basic_output: &BasicOutput) -> bool { - let has_vesting_prefix = output_id.to_string().starts_with(VESTED_REWARD_ID_PREFIX); - - has_vesting_prefix && basic_output.unlock_conditions().timelock().is_some() -} - -/// Creates a `TimeLock>` from a Stardust-based Basic Output -/// that represents a vested reward. -pub fn try_from_stardust( - output_id: OutputId, - basic_output: &BasicOutput, - target_milestone_timestamp_sec: u32, -) -> Result, VestedRewardError> { - if !is_vested_reward(output_id, basic_output) { - return Err(VestedRewardError::NotVestedReward); - } - - if !basic_output - .unlock_conditions() - .is_time_locked(target_milestone_timestamp_sec) - { - return Err(VestedRewardError::UnlockedVestedReward); - } - - if basic_output.unlock_conditions().len() != 2 { - return Err(VestedRewardError::UnlockConditionsNumberMismatch); - } - - if basic_output.native_tokens().len() > 0 { - return Err(VestedRewardError::NativeTokensNotSupported); - } - - let id = UID::new(ObjectID::new(output_id.hash())); - let locked = Balance::new(basic_output.amount()); - - // We already checked the existence of the timelock unlock condition at this - // point. - let timelock_uc = basic_output - .unlock_conditions() - .timelock() - .expect("a vested reward should contain a timelock unlock condition"); - let expiration_timestamp_ms = Into::::into(timelock_uc.timestamp()) * 1000; - - Ok(sui_types::timelock::timelock::TimeLock::new( - id, - locked, - expiration_timestamp_ms, - )) -} - -/// Creates a genesis object from a time-locked balance. -pub fn to_genesis_object( - timelock: TimeLock, - owner: SuiAddress, - protocol_config: &ProtocolConfig, - tx_context: &TxContext, - version: SequenceNumber, -) -> Result { - let move_object = unsafe { - // Safety: we know from the definition of `TimeLock` in the timelock package - // that it is not publicly transferable (`store` ability is absent). - MoveObject::new_from_execution( - MoveObjectType::timelocked_sui_balance(), - false, - version, - timelock.to_bcs_bytes(), - protocol_config, - ) - .map_err(|source| VestedRewardError::ObjectCreation { - owner, - timelock, - source, - })? - }; - - Ok(Object::new_from_genesis( - Data::Move(move_object), - Owner::AddressOwner(owner), - tx_context.digest(), - )) -} - -#[cfg(test)] -mod tests { - use std::str::FromStr; - - use iota_sdk::types::block::{ - address::Ed25519Address, - output::{ - unlock_condition::{ - AddressUnlockCondition, StorageDepositReturnUnlockCondition, - TimelockUnlockCondition, - }, - BasicOutput, BasicOutputBuilder, NativeToken, OutputId, TokenId, - }, - }; - - use crate::stardust::types::timelock::{self, VestedRewardError}; - - fn vested_reward_output(amount: u64, expiration_time_sec: u32) -> BasicOutput { - BasicOutputBuilder::new_with_amount(amount) - .add_unlock_condition(AddressUnlockCondition::new( - Ed25519Address::from_str( - "0xebe40a263480190dcd7939447ee01aefa73d6f3cc33c90ef7bf905abf8728655", - ) - .unwrap(), - )) - .add_unlock_condition(TimelockUnlockCondition::new(expiration_time_sec).unwrap()) - .finish() - .unwrap() - } - - #[test] - fn is_timelocked_vested_reward_all_correct() { - let output_id = OutputId::from_str( - "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", - ) - .unwrap(); - let output = vested_reward_output(10, 1000); - - assert!(timelock::is_timelocked_vested_reward( - output_id, &output, 100 - )); - } - - #[test] - fn is_timelocked_vested_reward_min_id() { - let output_id = OutputId::from_str( - "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1800000000", - ) - .unwrap(); - let output = vested_reward_output(10, 1000); - - assert!(timelock::is_timelocked_vested_reward( - output_id, &output, 100 - )); - } - - #[test] - fn is_timelocked_vested_reward_max_id() { - let output_id = OutputId::from_str( - "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb18ffffffff", - ) - .unwrap(); - let output = vested_reward_output(10, 1000); - - assert!(timelock::is_timelocked_vested_reward( - output_id, &output, 100 - )); - } - - #[test] - fn is_timelocked_vested_reward_incorrect_id() { - let output_id = OutputId::from_str( - "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1712345678", - ) - .unwrap(); - let output = vested_reward_output(10, 1000); - - assert!(!timelock::is_timelocked_vested_reward( - output_id, &output, 100 - )); - } - - #[test] - fn is_timelocked_vested_reward_no_timelock_unlock_condition() { - let output_id = OutputId::from_str( - "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", - ) - .unwrap(); - let output = BasicOutputBuilder::new_with_amount(10) - .add_unlock_condition(AddressUnlockCondition::new( - Ed25519Address::from_str( - "0xebe40a263480190dcd7939447ee01aefa73d6f3cc33c90ef7bf905abf8728655", - ) - .unwrap(), - )) - .finish() - .unwrap(); - - assert!(!timelock::is_timelocked_vested_reward( - output_id, &output, 100 - )); - } - - #[test] - fn is_timelocked_vested_reward_bigger_milestone_time() { - let output_id = OutputId::from_str( - "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", - ) - .unwrap(); - let output = vested_reward_output(10, 100); - - assert!(!timelock::is_timelocked_vested_reward( - output_id, &output, 1000 - )); - } - - #[test] - fn is_timelocked_vested_reward_same_milestone_time() { - let output_id = OutputId::from_str( - "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", - ) - .unwrap(); - let output = vested_reward_output(10, 1000); - - assert!(!timelock::is_timelocked_vested_reward( - output_id, &output, 1000 - )); - } - - #[test] - fn timelock_from_stardust_all_correct() { - let output_id = OutputId::from_str( - "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", - ) - .unwrap(); - let output = vested_reward_output(10, 1000); - - let timelock = timelock::try_from_stardust(output_id, &output, 100).unwrap(); - - assert!(timelock.locked().value() == 10); - assert!(timelock.expiration_timestamp_ms() == 1_000_000); - } - - #[test] - fn timelock_from_stardust_with_expired_output() { - let output_id = OutputId::from_str( - "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", - ) - .unwrap(); - let output = vested_reward_output(10, 1000); - - let err = timelock::try_from_stardust(output_id, &output, 1000).unwrap_err(); - - assert!(matches!(err, VestedRewardError::UnlockedVestedReward)); - } - - #[test] - fn timelock_from_stardust_with_incorrect_id() { - let output_id = OutputId::from_str( - "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1712345678", - ) - .unwrap(); - let output = vested_reward_output(10, 1000); - - let err = timelock::try_from_stardust(output_id, &output, 100).unwrap_err(); - - assert!(matches!(err, VestedRewardError::NotVestedReward)); - } - - #[test] - fn timelock_from_stardust_without_timelock_unlock_condition() { - let output_id = OutputId::from_str( - "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", - ) - .unwrap(); - let output = BasicOutputBuilder::new_with_amount(10) - .add_unlock_condition(AddressUnlockCondition::new( - Ed25519Address::from_str( - "0xebe40a263480190dcd7939447ee01aefa73d6f3cc33c90ef7bf905abf8728655", - ) - .unwrap(), - )) - .add_unlock_condition( - StorageDepositReturnUnlockCondition::new( - Ed25519Address::from_str( - "0xebe40a263480190dcd7939447ee01aefa73d6f3cc33c90ef7bf905abf8728655", - ) - .unwrap(), - 100, - 100, - ) - .unwrap(), - ) - .finish() - .unwrap(); - - let err = timelock::try_from_stardust(output_id, &output, 1000).unwrap_err(); - - assert!(matches!(err, VestedRewardError::NotVestedReward)); - } - - #[test] - fn timelock_from_stardust_extra_unlock_condition() { - let output_id = OutputId::from_str( - "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", - ) - .unwrap(); - let output = BasicOutputBuilder::new_with_amount(10) - .add_unlock_condition(AddressUnlockCondition::new( - Ed25519Address::from_str( - "0xebe40a263480190dcd7939447ee01aefa73d6f3cc33c90ef7bf905abf8728655", - ) - .unwrap(), - )) - .add_unlock_condition(TimelockUnlockCondition::new(1000).unwrap()) - .add_unlock_condition( - StorageDepositReturnUnlockCondition::new( - Ed25519Address::from_str( - "0xebe40a263480190dcd7939447ee01aefa73d6f3cc33c90ef7bf905abf8728655", - ) - .unwrap(), - 100, - 100, - ) - .unwrap(), - ) - .finish() - .unwrap(); - - let err = timelock::try_from_stardust(output_id, &output, 100).unwrap_err(); - - assert!(matches!( - err, - VestedRewardError::UnlockConditionsNumberMismatch - )); - } - - #[test] - fn timelock_from_stardust_with_native_tokens() { - let output_id = OutputId::from_str( - "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb1812345678", - ) - .unwrap(); - let output = BasicOutputBuilder::new_with_amount(10) - .add_unlock_condition(AddressUnlockCondition::new( - Ed25519Address::from_str( - "0xebe40a263480190dcd7939447ee01aefa73d6f3cc33c90ef7bf905abf8728655", - ) - .unwrap(), - )) - .add_unlock_condition(TimelockUnlockCondition::new(1000).unwrap()) - .add_native_token(NativeToken::new(TokenId::null(), 1).unwrap()) - .finish() - .unwrap(); - - let err = timelock::try_from_stardust(output_id, &output, 100).unwrap_err(); - - assert!(matches!(err, VestedRewardError::NativeTokensNotSupported)); - } -} diff --git a/crates/sui-graphql-e2e-tests/Cargo.toml b/crates/sui-graphql-e2e-tests/Cargo.toml deleted file mode 100644 index fb8642a2a40..00000000000 --- a/crates/sui-graphql-e2e-tests/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "sui-graphql-e2e-tests" -version = "0.1.0" -authors = ["Mysten Labs "] -description = "End to end tests for Sui GraphQL" -license = "Apache-2.0" -publish = false -edition = "2021" - -[dev-dependencies] -datatest-stable.workspace = true -sui-graphql-rpc.workspace = true -sui-transactional-test-runner.workspace = true -tokio.workspace = true - -[[test]] -name = "tests" -harness = false - -[dependencies] - -[features] -default = ["pg_backend"] -pg_integration = [] -pg_backend = [] - -[target.'cfg(msim)'.dependencies] -msim.workspace = true diff --git a/crates/sui-graphql-e2e-tests/README.md b/crates/sui-graphql-e2e-tests/README.md deleted file mode 100644 index 5da2d1cb984..00000000000 --- a/crates/sui-graphql-e2e-tests/README.md +++ /dev/null @@ -1,64 +0,0 @@ -End-to-end tests for GraphQL service, built on top of the transactional test -runner. - -# Local Set-up - -These tests require a running instance of the `postgres` service, with a -database set-up. The instructions below assume that `postgres` has been -installed using `brew`: - -1. See the instructions in the Sui Indexer [README](../sui-indexer/README.md) - for pre-requisites and starting the Postgres service. - -2. When postgres is initially installed, it creates a role for your current - user. We need to use that role to create the role that will access the - database: - -```sh -$ ME=$(whoami) -$ psql "postgres://$ME:$ME@localhost:5432/postgres" \ - -c "CREATE ROLE postgres WITH SUPERUSER LOGIN PASSWORD 'postgrespw';" -``` - -3. Then, create the database that the tests expect, using the `postgres` user - and increase the max connections since many tests might run in parallel. - -```sh -$ psql "postgres://postgres:postgrespw@localhost:5432/postgres" \ - -c "CREATE DATABASE sui_indexer_v2;" -c "ALTER SYSTEM SET max_connections = 500;" -``` - -4. Finally, restart the `postgres` server so the max connections change takes - effect. - -Mac -```sh -brew services restart postgresql@15 - -``` - -Linux -```sh -/etc/init.d/postgresql restart -``` - -# Running Locally - -When running the tests locally, they must be run with the `pg_integration` -feature enabled: - -```sh -$ cargo nextest run --features pg_integration -``` - -# Snapshot Stability - -Tests are pinned to an existing protocol version that has already been used on a -production network. The protocol version controls the protocol config and also -the version of the framework that gets used by tests. By using a version that -has already been used in a production setting, we are guaranteeing that it will -not be changed by later modifications to the protocol or framework (this would -be a bug). - -When adding a new test, **remember to set the `--protocol-version`** for that -test to ensure stability. diff --git a/crates/sui-graphql-e2e-tests/src/lib.rs b/crates/sui-graphql-e2e-tests/src/lib.rs deleted file mode 100644 index 07fe81c224d..00000000000 --- a/crates/sui-graphql-e2e-tests/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#![forbid(unsafe_code)] - -// Empty src/lib.rs to get rusty-tags working. diff --git a/crates/sui-graphql-e2e-tests/tests/call/dynamic_fields.move b/crates/sui-graphql-e2e-tests/tests/call/dynamic_fields.move deleted file mode 100644 index a7d3fd9beb5..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/call/dynamic_fields.move +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// Create some dynamic fields on an object, and then try to query them. -// There should be 1 dynamic object field (MoveObject) and 3 dynamic fields. -// When the object is wrapped, we expect that making the query through Object will return null. -// But it should still be visible through the Owner type. -// This test also demonstrates why we need separate dynamicField and dynamicObjectField APIs. -// It is possible for a dynamic field and a dynamic object field to share the same name lookup. - -//# init --protocol-version 39 --addresses Test=0x0 --accounts A --simulator - -//# publish -module Test::m { - use sui::dynamic_field as field; - use sui::dynamic_object_field as ofield; - - public struct Wrapper has key { - id: object::UID, - o: Parent - } - - public struct Parent has key, store { - id: object::UID, - } - - public struct Child has key, store { - id: object::UID, - } - - public entry fun create_obj(ctx: &mut TxContext){ - let id = object::new(ctx); - sui::transfer::public_transfer(Parent { id }, ctx.sender()) - } - - public entry fun add_df(obj: &mut Parent) { - let id = &mut obj.id; - field::add(id, 0, 0); - field::add, u64>(id, b"", 1); - field::add(id, false, 2); - } - - public entry fun add_dof(parent: &mut Parent, ctx: &mut TxContext) { - let child = Child { id: object::new(ctx) }; - ofield::add(&mut parent.id, 0, child); - } - - public entry fun wrap(parent: Parent, ctx: &mut TxContext) { - let wrapper = Wrapper { id: object::new(ctx), o: parent }; - sui::transfer::transfer(wrapper, ctx.sender()) - } -} - -//# run Test::m::create_obj --sender A - -//# run Test::m::add_df --sender A --args object(2,0) - -//# run Test::m::add_dof --sender A --args object(2,0) - -//# create-checkpoint - -//# run-graphql -{ - object(address: "@{obj_2_0}") { - dynamicFields { - nodes { - name { - type { - repr - } - data - bcs - } - value { - ... on MoveObject { - __typename - } - ... on MoveValue { - __typename - } - } - } - } - } -} - -//# run Test::m::wrap --sender A --args object(2,0) - -//# create-checkpoint - -//# run-graphql -{ - object(address: "@{obj_2_0}") { - dynamicFields { - nodes { - name { - type { - repr - } - data - bcs - } - value { - ... on MoveObject { - __typename - } - ... on MoveValue { - __typename - } - } - } - } - } -} - -//# run-graphql -{ - owner(address: "@{obj_2_0}") { - dynamicFields { - nodes { - name { - type { - repr - } - data - bcs - } - value { - ... on MoveObject { - __typename - } - ... on MoveValue { - bcs - data - __typename - } - } - } - } - } -} - -//# run-graphql -{ - owner(address: "@{obj_2_0}") { - dynamicField(name: {type: "u64", bcs: "AAAAAAAAAAA="}) { - name { - type { - repr - } - data - bcs - } - value { - ... on MoveValue { - __typename - bcs - data - } - } - } - } -} - -//# run-graphql -{ - owner(address: "@{obj_2_0}") { - dynamicObjectField(name: {type: "u64", bcs: "AAAAAAAAAAA="}) { - value { - ... on MoveObject { - __typename - } - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/call/simple.exp b/crates/sui-graphql-e2e-tests/tests/call/simple.exp deleted file mode 100644 index ffa4c70705e..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/call/simple.exp +++ /dev/null @@ -1,271 +0,0 @@ -processed 25 tasks - -init: -validator_0: object(0,0) - -task 1 'publish'. lines 6-25: -created: object(1,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 5570800, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'run'. lines 27-27: -created: object(2,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 2302800, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'run'. lines 29-29: -created: object(3,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 2302800, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 4 'view-object'. lines 31-31: -Owner: Account Address ( validator_0 ) -Version: 1 -Contents: sui_system::validator_cap::UnverifiedValidatorOperationCap {id: sui::object::UID {id: sui::object::ID {bytes: fake(0,0)}}, authorizer_validator_address: validator_0} - -task 5 'view-object'. lines 33-33: -Owner: Account Address ( A ) -Version: 3 -Contents: Test::M1::Object {id: sui::object::UID {id: sui::object::ID {bytes: fake(2,0)}}, value: 0u64} - -task 6 'view-object'. lines 35-35: -Owner: Account Address ( validator_0 ) -Version: 4 -Contents: Test::M1::Object {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,0)}}, value: 0u64} - -task 7 'create-checkpoint'. lines 37-37: -Checkpoint created: 4 - -task 8 'view-checkpoint'. lines 39-39: -CheckpointSummary { epoch: 0, seq: 4, content_digest: D3oWLCcqoa1D15gxzvMaDemNNY8YYVspAkYkcmtQKWRt, - epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 3000000, storage_cost: 10176400, storage_rebate: 1956240, non_refundable_storage_fee: 19760 }} - -task 9 'advance-epoch'. lines 41-41: -Epoch advanced: 5 - -task 10 'view-checkpoint'. lines 43-43: -CheckpointSummary { epoch: 5, seq: 10, content_digest: C61cKCJWb9sw7ntgsD6WSAXioh4ogmbNMty8v4oxsjhB, - epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 0, storage_cost: 0, storage_rebate: 0, non_refundable_storage_fee: 0 }} - -task 11 'run-graphql'. lines 45-50: -Response: { - "data": { - "checkpoint": { - "sequenceNumber": 10 - } - } -} - -task 12 'create-checkpoint'. lines 52-52: -Checkpoint created: 11 - -task 13 'view-checkpoint'. lines 54-54: -CheckpointSummary { epoch: 6, seq: 11, content_digest: D3oWLCcqoa1D15gxzvMaDemNNY8YYVspAkYkcmtQKWRt, - epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 0, storage_cost: 0, storage_rebate: 0, non_refundable_storage_fee: 0 }} - -task 14 'run-graphql'. lines 56-61: -Response: { - "data": { - "checkpoint": { - "sequenceNumber": 11 - } - } -} - -task 15 'run-graphql'. lines 63-68: -Headers: { - "content-type": "application/json", - "content-length": "157", - "x-sui-rpc-version": "2024.2.0-testing-no-sha", - "access-control-allow-origin": "*", - "vary": "origin", - "vary": "access-control-request-method", - "vary": "access-control-request-headers", -} -Service version: 2024.2.0-testing-no-sha -Response: { - "data": { - "checkpoint": { - "sequenceNumber": 11 - } - }, - "extensions": { - "usage": { - "inputNodes": 2, - "outputNodes": 2, - "depth": 2, - "variables": 0, - "fragments": 0, - "queryPayload": 41 - } - } -} - -task 16 'view-checkpoint'. lines 70-70: -CheckpointSummary { epoch: 6, seq: 11, content_digest: D3oWLCcqoa1D15gxzvMaDemNNY8YYVspAkYkcmtQKWRt, - epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 0, storage_cost: 0, storage_rebate: 0, non_refundable_storage_fee: 0 }} - -task 17 'advance-epoch'. lines 72-75: -Epoch advanced: 6 - -task 18 'run-graphql'. lines 77-92: -Response: { - "data": { - "address": { - "objects": { - "edges": [ - { - "node": { - "address": "0x127ebc904fc866d4677fca7f7b428bff5b88527c305434c882e712945bbeb630", - "digest": "Cmx2Tcf2RoMqnxriyZFSccHtHk7jA4HVKRKykrNMtKpW", - "owner": { - "__typename": "AddressOwner" - } - } - } - ] - } - } - } -} - -task 19 'run-graphql'. lines 94-149: -Response: { - "data": { - "address": { - "objects": { - "edges": [] - } - }, - "second": { - "objects": { - "edges": [ - { - "node": { - "address": "0x127ebc904fc866d4677fca7f7b428bff5b88527c305434c882e712945bbeb630", - "digest": "Cmx2Tcf2RoMqnxriyZFSccHtHk7jA4HVKRKykrNMtKpW", - "owner": { - "__typename": "AddressOwner" - } - } - } - ] - } - }, - "val_objs": { - "objects": { - "edges": [ - { - "node": { - "address": "0x00ca13a0bf70f8768696ebd40a05bafb132e05f020f4186a17ba90e6737abaca", - "digest": "9R3vvuwUS4Zk1joFrUCAg6azt9kfBGVJgpH5MoEVfu8y", - "owner": { - "__typename": "AddressOwner" - } - } - }, - { - "node": { - "address": "0x76fb11d049dd7b1328f2cfb196f1cb18d444d20c9c5ca59c832e5a15ac80594c", - "digest": "uaafRXthffyBnsd17L6D8wWQtaYrsbyJ9U4fRsu4tJW", - "owner": { - "__typename": "AddressOwner" - } - } - }, - { - "node": { - "address": "0xa75755ab1ad9cc5a1f9e0745d770d7eeb724d30fca9a96d4dc881e2e57aa8c66", - "digest": "AycePHSxuYVtwTaK9xG38Bjb7T1237mEC4U1WUDy1WFW", - "owner": { - "__typename": "AddressOwner" - } - } - }, - { - "node": { - "address": "0xaf12bf78851720ffb7583032490b150ab1c37e430628d91d7e84dbdbc93c17e3", - "digest": "7vsLSSY4ZntwJSkTfB54MGDxbw8RGQtUQjtNX64PDeo1", - "owner": { - "__typename": "AddressOwner" - } - } - }, - { - "node": { - "address": "0xc68bdb786bf1563aaf02ca2ed63d7f7d83c71ff277dde05fbdd962030c6e180f", - "digest": "CvbTB1bRP3ngTtwkE2YSfFaSNWkpUV5YgE3ikqwaiMJa", - "owner": { - "__typename": "AddressOwner" - } - } - }, - { - "node": { - "address": "0xe03a1feb19afc2c173044f6d778432c74c567604e0dcc759ae06680453f460d4", - "digest": "FbF9oAL5jJTFkxUkPSEPyUDDbWEhuFzzem353cRGgCG3", - "owner": { - "__typename": "AddressOwner" - } - } - } - ] - } - }, - "object": { - "version": 3, - "owner": { - "__typename": "AddressOwner", - "owner": { - "address": "0x0000000000000000000000000000000000000000000000000000000000000042" - } - } - } - } -} - -task 20 'run-graphql'. lines 151-167: -Response: { - "data": { - "epoch": { - "validatorSet": { - "activeValidators": { - "nodes": [ - { - "address": { - "address": "0xa7b032703878aa74c3126935789fd1d4d7e111d5911b09247d6963061c312b5a" - } - } - ] - } - } - }, - "address": { - "address": "0xa7b032703878aa74c3126935789fd1d4d7e111d5911b09247d6963061c312b5a" - } - } -} - -task 21 'run-graphql'. lines 169-175: -Response: { - "data": { - "epoch": { - "referenceGasPrice": "234" - } - } -} - -task 22 'run'. lines 177-177: -created: object(22,0) -mutated: object(0,1) -gas summary: computation_cost: 999000, storage_cost: 2302800, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 23 'run'. lines 179-179: -created: object(23,0) -mutated: object(0,1) -gas summary: computation_cost: 1000000, storage_cost: 2302800, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 24 'run'. lines 181-181: -created: object(24,0) -mutated: object(0,1) -gas summary: computation_cost: 235000, storage_cost: 2302800, storage_rebate: 978120, non_refundable_storage_fee: 9880 diff --git a/crates/sui-graphql-e2e-tests/tests/call/simple.move b/crates/sui-graphql-e2e-tests/tests/call/simple.move deleted file mode 100644 index 54cde9d9bd8..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/call/simple.move +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --protocol-version 39 --addresses Test=0x0 A=0x42 --simulator --custom-validator-account --reference-gas-price 234 --default-gas-price 1000 - -//# publish -module Test::M1 { - use sui::coin::Coin; - - public struct Object has key, store { - id: UID, - value: u64, - } - - fun foo(_p1: u64, value1: T, _value2: &Coin, _p2: u64): T { - value1 - } - - public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { - transfer::public_transfer( - Object { id: object::new(ctx), value }, - recipient - ) - } -} - -//# run Test::M1::create --args 0 @A --gas-price 1000 - -//# run Test::M1::create --args 0 @validator_0 - -//# view-object 0,0 - -//# view-object 2,0 - -//# view-object 3,0 - -//# create-checkpoint 4 - -//# view-checkpoint - -//# advance-epoch 6 - -//# view-checkpoint - -//# run-graphql -{ - checkpoint { - sequenceNumber - } -} - -//# create-checkpoint - -//# view-checkpoint - -//# run-graphql -{ - checkpoint { - sequenceNumber - } -} - -//# run-graphql --show-usage --show-headers --show-service-version -{ - checkpoint { - sequenceNumber - } -} - -//# view-checkpoint - -//# advance-epoch - -// Demonstrates using variables -// If the variable ends in _opt, this is the optional variant - -//# run-graphql -{ - address(address: "@{A}") { - objects { - edges { - node { - address - digest - owner { - __typename - } - } - } - } - } -} - -//# run-graphql -{ - address(address: "@{Test}") { - objects { - edges { - node { - address - digest - owner { - __typename - } - } - } - } - } - second: address(address: "@{A}") { - objects { - edges { - node { - address - digest - owner { - __typename - } - } - } - } - } - - val_objs: address(address: "@{validator_0}") { - objects { - edges { - node { - address - digest - owner { - __typename - } - } - } - } - } - - object(address: "@{obj_2_0}") { - version - owner { - __typename - ... on AddressOwner { - owner { - address - } - } - } - } - -} - -//# run-graphql -{ - epoch { - validatorSet { - activeValidators { - nodes { - address { - address - } - } - } - } - } - address(address: "@{validator_0}") { - address - } -} - -//# run-graphql -# Since we set it at the init, it should be the same as 234 -{ - epoch { - referenceGasPrice - } -} - -//# run Test::M1::create --args 0 @A --gas-price 999 - -//# run Test::M1::create --args 0 @A --gas-price 1000 - -//# run Test::M1::create --args 0 @A --gas-price 235 diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/checkpoints/transaction_blocks.move b/crates/sui-graphql-e2e-tests/tests/consistency/checkpoints/transaction_blocks.move deleted file mode 100644 index 588eee59e78..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/consistency/checkpoints/transaction_blocks.move +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// checkpoint | transactions from A -// -----------+-------------------- -// 0 | 0 -// 1 | 4 -// 2 | 3 -// 3 | 2 - -//# init --protocol-version 39 --addresses Test=0x0 --accounts A B --simulator - -//# publish -module Test::M1 { - public struct Object has key, store { - id: UID, - value: u64, - } - - public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { - transfer::public_transfer( - Object { id: object::new(ctx), value }, - recipient - ) - } -} - -//# run Test::M1::create --args 0 @A --sender A - -//# run Test::M1::create --args 0 @A --sender A - -//# run Test::M1::create --args 0 @A --sender A - -//# run Test::M1::create --args 0 @A --sender A - -//# create-checkpoint - -//# run Test::M1::create --args 0 @A --sender A - -//# run Test::M1::create --args 0 @A --sender A - -//# run Test::M1::create --args 0 @A --sender A - -//# create-checkpoint - -//# run Test::M1::create --args 0 @A --sender A - -//# run Test::M1::create --args 0 @A --sender A - -//# create-checkpoint - -//# run-graphql -# Each transaction block's sender's last object resolves to the same last object at the latest -# state -{ - checkpoints { - nodes { - sequenceNumber - transactionBlocks(filter: { signAddress: "@{A}"}) { - edges { - cursor - node { - digest - sender { - objects(last: 1) { - edges { - cursor - } - } - } - } - } - } - } - } -} - -//# run-graphql -# Similarly, resolving the checkpoint's epoch will return the epoch the checkpoint belongs in, but -# the nested checkpoints connection will behave as if it was made on the top-level. -{ - checkpoints { - nodes { - sequenceNumber - epoch { - epochId - checkpoints { - nodes { - sequenceNumber - } - } - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dynamic_fields.move b/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dynamic_fields.move deleted file mode 100644 index fbf87eaadbe..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/consistency/dynamic_fields/dynamic_fields.move +++ /dev/null @@ -1,528 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// chkpt1: create parent and child @ version 2 -// chkpt1: add dof to parent @ version 3 -// chkpt2: PTB(mutate dof, add df1, 2, 3) - parent and dof @ version 4 -// chkpt3: add df4, 5, 6 parent @ version 5, child @ version 4 -// chkpt4: remove df1, df2, df3 parent @ version 6, child @ version 4 - -//# init --protocol-version 39 --addresses Test=0x0 --accounts A --simulator - -//# publish -module Test::M1 { - use sui::dynamic_object_field as ofield; - use sui::dynamic_field as field; - use std::string::{String, utf8}; - - public struct Parent has key, store { - id: UID, - } - - public struct Child has key, store { - id: UID, - count: u64, - } - - public entry fun parent(recipient: address, ctx: &mut TxContext) { - transfer::public_transfer( - Parent { id: object::new(ctx) }, - recipient - ) - } - - public entry fun child(recipient: address, ctx: &mut TxContext) { - transfer::public_transfer( - Child { id: object::new(ctx), count: 0 }, - recipient - ) - } - - public fun add_child(parent: &mut Parent, child: Child, name: u64) { - ofield::add(&mut parent.id, name, child); - } - - public fun mutate_child(child: &mut Child) { - child.count = child.count + 1; - } - - public fun mutate_child_via_parent(parent: &mut Parent, name: u64) { - mutate_child(ofield::borrow_mut(&mut parent.id, name)) - } - - public fun reclaim_child(parent: &mut Parent, name: u64): Child { - ofield::remove(&mut parent.id, name) - } - - public fun delete_child(parent: &mut Parent, name: u64) { - let Child { id, count: _ } = reclaim_child(parent, name); - object::delete(id); - } - - public entry fun add_df(obj: &mut Parent) { - let id = &mut obj.id; - field::add(id, utf8(b"df1"), utf8(b"df1")); - field::add(id, utf8(b"df2"), utf8(b"df2")); - field::add(id, utf8(b"df3"), utf8(b"df3")); - } - - public entry fun remove_df(obj: &mut Parent) { - let id = &mut obj.id; - field::remove(id, utf8(b"df1")); - field::remove(id, utf8(b"df2")); - field::remove(id, utf8(b"df3")); - } - - public entry fun add_more_df(obj: &mut Parent) { - let id = &mut obj.id; - field::add(id, utf8(b"df4"), utf8(b"df4")); - field::add(id, utf8(b"df5"), utf8(b"df5")); - field::add(id, utf8(b"df6"), utf8(b"df6")); - } -} - -//# programmable --sender A --inputs @A 42 -//> 0: Test::M1::parent(Input(0)); -//> 1: Test::M1::child(Input(0)); - -//# view-object 2,1 - -//# view-object 2,0 - -//# programmable --sender A --inputs object(2,1) object(2,0) 420 -//> Test::M1::add_child(Input(0), Input(1), Input(2)); -//> Test::M1::mutate_child_via_parent(Input(0), Input(2)); - -//# view-object 2,1 - -//# view-object 2,0 - -//# create-checkpoint - -//# run-graphql -fragment DynamicFieldSelect on DynamicField { - name { - bcs - type { - repr - } - } - value { - ... on MoveObject { - contents { - json - } - } - ... on MoveValue { - json - } - } -} - -fragment DynamicFieldsSelect on DynamicFieldConnection { - edges { - cursor - node { - ...DynamicFieldSelect - } - } -} - -{ - parent_version_2_no_dof: object(address: "@{obj_2_1}", version: 2) { - address - dynamicFields { - ...DynamicFieldsSelect - } - } - parent_version_3_has_dof: object(address: "@{obj_2_1}", version: 3) { - dynamicFields { - ...DynamicFieldsSelect - } - } - child_version_2_no_parent: object(address: "@{obj_2_0}", version: 2) { - address - owner { - ... on Parent { - parent { - address - } - } - } - } - # Note that the value object's parent is the field object, not the parent object that we may - # expect - child_version_3_has_parent: object(address: "@{obj_2_0}", version: 3) { - owner { - ... on Parent { - parent { - address - } - } - } - } -} - -//# programmable --sender A --inputs object(2,1) 420 -//> Test::M1::mutate_child_via_parent(Input(0), Input(1)); -//> Test::M1::add_df(Input(0)); - -//# view-object 2,1 - -//# view-object 2,0 - -//# create-checkpoint - -//# run-graphql --cursors @{obj_5_0,1} @{obj_5_0,2} -fragment DynamicFieldSelect on DynamicField { - name { - bcs - type { - repr - } - } - value { - ... on MoveObject { - contents { - json - } - } - ... on MoveValue { - json - } - } -} - -fragment DynamicFieldsSelect on DynamicFieldConnection { - edges { - cursor - node { - ...DynamicFieldSelect - } - } -} - -{ - parent_version_4_show_dof_and_dfs: object(address: "@{obj_2_1}", version: 4) { - dynamicFields { - ...DynamicFieldsSelect - } - } - parent_version_3_only_dof: object(address: "@{obj_2_1}", version: 3) { - dynamicFields { - ...DynamicFieldsSelect - } - } - use_dof_version_3_cursor_at_parent_version_4: object(address: "@{obj_2_1}", version: 4) { - dynamicFields(after: "@{cursor_0}") { - ...DynamicFieldsSelect - } - } - use_dof_version_4_cursor_at_parent_version_4: object(address: "@{obj_2_1}", version: 4) { - dynamicFields(after: "@{cursor_1}") { - ...DynamicFieldsSelect - } - } - use_dof_version_3_cursor_at_parent_version_3: object(address: "@{obj_2_1}", version: 3) { - dynamicFields(after: "@{cursor_0}") { - ...DynamicFieldsSelect - } - } - use_dof_version_4_cursor_at_version_3: object(address: "@{obj_2_1}", version: 3) { - dynamicFields(after: "@{cursor_1}") { - ...DynamicFieldsSelect - } - } -} - -//# run-graphql -fragment DynamicFieldSelect on DynamicField { - name { - bcs - type { - repr - } - } - value { - ... on MoveObject { - contents { - json - } - } - ... on MoveValue { - json - } - } -} - -{ - parent_version_3: object(address: "@{obj_2_1}", version: 3) { - dynamicObjectField(name: {type: "u64", bcs: "pAEAAAAAAAA="}) { - ...DynamicFieldSelect - } - dfNotAvailableYet: dynamicField(name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="}) { - ...DynamicFieldSelect - } - } - parent_version_4: object(address: "@{obj_2_1}", version: 4) { - dynamicObjectField(name: {type: "u64", bcs: "pAEAAAAAAAA="}) { - ...DynamicFieldSelect - } - dfAddedHere: dynamicField(name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="}) { - ...DynamicFieldSelect - } - } -} - - -//# programmable --sender A --inputs object(2,1) -//> Test::M1::add_more_df(Input(0)); - -//# view-object 2,1 - -//# view-object 2,0 - -//# create-checkpoint - -//# run-graphql --cursors @{obj_5_0,2} @{obj_5_0,3} -fragment DynamicFieldSelect on DynamicField { - name { - bcs - type { - repr - } - } - value { - ... on MoveObject { - contents { - json - } - } - ... on MoveValue { - json - } - } -} - -fragment DynamicFieldsSelect on DynamicFieldConnection { - edges { - cursor - node { - ...DynamicFieldSelect - } - } -} - -{ - parent_version_4_has_4_children: object(address: "@{obj_2_1}", version: 4) { - dynamicFields { - ...DynamicFieldsSelect - } - } - parent_version_4_paginated_on_dof_consistent: object(address: "@{obj_2_1}", version: 4) { - dynamicFields(after: "@{cursor_0}") { - ...DynamicFieldsSelect - } - } - parent_version_5_has_7_children: object(address: "@{obj_2_1}", version: 5) { - dynamicFields { - ...DynamicFieldsSelect - } - } - parent_version_5_paginated_on_dof_consistent: object(address: "@{obj_2_1}", version: 5) { - dynamicFields(after: "@{cursor_1}") { - ...DynamicFieldsSelect - } - } -} - -//# programmable --sender A --inputs object(2,1) 420 -//> Test::M1::remove_df(Input(0)); - -//# view-object 2,1 - -//# view-object 2,0 - -//# create-checkpoint - -//# run-graphql --cursors @{obj_5_0,2} @{obj_5_0,4} -fragment DynamicFieldSelect on DynamicField { - name { - bcs - type { - repr - } - } - value { - ... on MoveObject { - contents { - json - } - } - ... on MoveValue { - json - } - } -} - -fragment DynamicFieldsSelect on DynamicFieldConnection { - edges { - cursor - node { - ...DynamicFieldSelect - } - } -} - -{ - parent_version_4_has_df1_2_3: object(address: "@{obj_2_1}", version: 4) { - dynamicFields { - ...DynamicFieldsSelect - } - } - parent_version_4_paginated_on_dof_consistent: object(address: "@{obj_2_1}", version: 4) { - dynamicFields(after: "@{cursor_0}") { - ...DynamicFieldsSelect - } - } - parent_version_6_no_df_1_2_3: object(address: "@{obj_2_1}", version: 6) { - dynamicFields { - ...DynamicFieldsSelect - } - } - parent_version_6_paginated_no_df_1_2_3: object(address: "@{obj_2_1}", version: 6) { - dynamicFields(after: "@{cursor_1}") { - ...DynamicFieldsSelect - } - } -} - -//# run-graphql -fragment DynamicFieldSelect on DynamicField { - name { - bcs - type { - repr - } - } - value { - ... on MoveObject { - contents { - json - } - } - ... on MoveValue { - json - } - } -} - -{ - parent_version_4: object(address: "@{obj_2_1}", version: 4) { - dfAtParentVersion4: dynamicField(name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="}) { - ...DynamicFieldSelect - } - } - parent_version_6: object(address: "@{obj_2_1}", version: 6) { - dfAtParentVersion6: dynamicField(name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="}) { - ...DynamicFieldSelect - } - } -} - -//# advance-clock --duration-ns 1 - -//# create-checkpoint - -//# advance-clock --duration-ns 1 - -//# create-checkpoint - -//# force-object-snapshot-catchup --start-cp 0 --end-cp 5 - -//# create-checkpoint - -//# run-graphql --cursors @{obj_5_0,2} @{obj_5_0,4} -fragment DynamicFieldSelect on DynamicField { - name { - bcs - type { - repr - } - } - value { - ... on MoveObject { - contents { - json - } - } - ... on MoveValue { - json - } - } -} - -fragment DynamicFieldsSelect on DynamicFieldConnection { - edges { - cursor - node { - ...DynamicFieldSelect - } - } -} - -{ - parent_version_4_outside_consistent_range: object(address: "@{obj_2_1}", version: 4) { - dynamicFields { - ...DynamicFieldsSelect - } - } - parent_version_4_paginated_outside_consistent_range: object(address: "@{obj_2_1}", version: 4) { - dynamicFields(after: "@{cursor_0}") { - ...DynamicFieldsSelect - } - } - parent_version_6_no_df_1_2_3: object(address: "@{obj_2_1}", version: 6) { - dynamicFields { - ...DynamicFieldsSelect - } - } - parent_version_6_paginated_no_df_1_2_3: object(address: "@{obj_2_1}", version: 6) { - dynamicFields(after: "@{cursor_1}") { - ...DynamicFieldsSelect - } - } -} - -//# run-graphql -fragment DynamicFieldSelect on DynamicField { - name { - bcs - type { - repr - } - } - value { - ... on MoveObject { - contents { - json - } - } - ... on MoveValue { - json - } - } -} - -{ - parent_version_4: object(address: "@{obj_2_1}", version: 4) { - dfAtParentVersion4_outside_range: dynamicField(name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="}) { - ...DynamicFieldSelect - } - } - parent_version_6: object(address: "@{obj_2_1}", version: 6) { - dfAtParentVersion6: dynamicField(name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="}) { - ...DynamicFieldSelect - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/epochs/transaction_blocks.move b/crates/sui-graphql-e2e-tests/tests/consistency/epochs/transaction_blocks.move deleted file mode 100644 index 3077a041104..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/consistency/epochs/transaction_blocks.move +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// tx | func | checkpoint | epoch -// ---+----------------+------------+------- -// 0 | | 0 | 0 -// 1 | make_immutable | 1 | 0 -// 2 | create | 2 | 0 -// 3 | epoch | 3 | 0 -// 4 | create | 4 | 1 -// 5 | create | 5 | 1 -// 6 | create | 6 | 1 -// 7 | epoch | 7 | 1 -// 8 | create | 8 | 2 -// 9 | create | 9 | 2 -// 10 | create | 10 | 2 -// 11 | epoch | 11 | 2 -// 12 | epoch | 12 | 3 - -//# init --protocol-version 39 --addresses Test=0x0 --accounts A B --simulator - -//# publish -module Test::M1 { - public struct Object has key, store { - id: UID, - value: u64, - } - - public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { - transfer::public_transfer( - Object { id: object::new(ctx), value }, - recipient - ) - } -} - -//# create-checkpoint - -//# run Test::M1::create --args 0 @A --sender A - -//# create-checkpoint - -//# advance-epoch - -//# run-graphql -{ - checkpoint { - sequenceNumber - } - epoch { - epochId - transactionBlocks { - edges { - cursor - node { - digest - } - } - } - } -} - -//# run Test::M1::create --args 0 @A --sender A - -//# create-checkpoint - -//# run Test::M1::create --args 0 @A --sender A - -//# create-checkpoint - -//# run Test::M1::create --args 0 @A --sender A - -//# create-checkpoint - -//# advance-epoch - -//# run Test::M1::create --args 0 @A --sender A - -//# create-checkpoint - -//# run Test::M1::create --args 0 @A --sender A - -//# create-checkpoint - -//# run Test::M1::create --args 0 @A --sender A - -//# create-checkpoint - -//# advance-epoch - -//# advance-epoch - -//# run-graphql --cursors {"t":3,"tc":3,"c":4} {"t":7,"tc":7,"c":8} {"t":11,"tc":11,"c":12} -# View transactions before the last transaction in each epoch, from the perspective of the first -# checkpoint in the next epoch. -{ - checkpoint { - sequenceNumber - } - epoch_0_txs: epoch(id: 0) { - epochId - transactionBlocks { - edges { - cursor - node { - digest - } - } - } - } - txs_epoch_0: transactionBlocks(before: "@{cursor_0}") { - edges { - cursor - node { - digest - } - } - } - epoch_1_txs: epoch(id: 1) { - epochId - transactionBlocks { - edges { - cursor - node { - digest - } - } - } - } - txs_epoch_1: transactionBlocks(before: "@{cursor_1}") { - edges { - cursor - node { - digest - } - } - } - epoch_2_txs: epoch(id: 2) { - epochId - transactionBlocks { - edges { - cursor - node { - digest - } - } - } - } - txs_epoch_2: transactionBlocks(before: "@{cursor_2}") { - edges { - cursor - node { - digest - } - } - } -} - -//# run-graphql --cursors {"t":0,"tc":0,"c":7} {"t":4,"tc":4,"c":11} {"t":8,"tc":8,"c":12} -# View transactions after the first transaction in each epoch, from the perspective of the last -# checkpoint in the next epoch. -{ - checkpoint { - sequenceNumber - } - epoch_0: epoch(id: 0) { - epochId - transactionBlocks(after: "@{cursor_0}") { - edges { - cursor - node { - digest - } - } - } - } - epoch_1: epoch(id: 1) { - epochId - transactionBlocks(after: "@{cursor_1}") { - edges { - cursor - node { - digest - } - } - } - } - epoch_2: epoch(id: 2) { - epochId - transactionBlocks(after: "@{cursor_2}") { - edges { - cursor - node { - digest - } - } - } - } -} - -//# run-graphql --cursors {"t":1,"tc":1,"c":2} {"t":5,"tc":5,"c":6} {"t":9,"tc":9,"c":10} -# View transactions after the second transaction in each epoch, from the perspective of a checkpoint -# around the middle of each epoch. -{ - checkpoint { - sequenceNumber - } - epoch_0: epoch(id: 0) { - epochId - transactionBlocks(after: "@{cursor_0}") { - edges { - cursor - node { - digest - } - } - } - } - epoch_1: epoch(id: 1) { - epochId - transactionBlocks(after: "@{cursor_1}") { - edges { - cursor - node { - digest - } - } - } - } - epoch_2: epoch(id: 2) { - epochId - transactionBlocks(after: "@{cursor_2}") { - edges { - cursor - node { - digest - } - } - } - } -} - -//# run-graphql --cursors {"t":5,"tc":5,"c":6} -# Verify that with a cursor, we are locked into a view as if we were at the checkpoint stored in -# the cursor. Compare against `without_cursor`, which should show the latest state at the actual -# latest checkpoint. There should only be 1 transaction block in the `with_cursor` query, but -# multiple in the second -{ - checkpoint { - sequenceNumber - } - with_cursor: transactionBlocks(after: "@{cursor_0}", filter: {signAddress: "@{A}"}) { - edges { - cursor - node { - digest - sender { - objects { - edges { - cursor - } - } - } - } - } - } - without_cursor: transactionBlocks(filter: {signAddress: "@{A}"}) { - edges { - cursor - node { - digest - sender { - objects { - edges { - cursor - } - } - } - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/staked_sui.exp b/crates/sui-graphql-e2e-tests/tests/consistency/staked_sui.exp deleted file mode 100644 index faca460362c..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/consistency/staked_sui.exp +++ /dev/null @@ -1,151 +0,0 @@ -processed 15 tasks - -init: -C: object(0,0) - -task 1 'run-graphql'. lines 6-18: -Response: { - "data": { - "address": { - "stakedSuis": { - "edges": [] - } - } - } -} - -task 2 'programmable'. lines 20-22: -created: object(2,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'run'. lines 24-24: -events: Event { package_id: sui_system, transaction_module: Identifier("sui_system"), sender: C, type_: StructTag { address: sui_system, module: Identifier("validator"), name: Identifier("StakingRequestEvent"), type_params: [] }, contents: [138, 42, 97, 253, 61, 22, 31, 106, 213, 157, 60, 241, 33, 156, 159, 193, 184, 127, 83, 194, 143, 198, 11, 54, 121, 139, 166, 151, 113, 26, 5, 97, 218, 131, 22, 109, 1, 175, 215, 221, 207, 138, 245, 248, 68, 244, 90, 170, 83, 244, 133, 72, 229, 17, 124, 35, 245, 162, 151, 140, 253, 66, 34, 68, 252, 204, 154, 66, 27, 187, 19, 193, 166, 106, 26, 169, 143, 10, 215, 80, 41, 237, 233, 72, 87, 119, 156, 105, 21, 180, 79, 148, 6, 139, 146, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 11, 84, 2, 0, 0, 0] } -created: object(3,0), object(3,1) -mutated: 0x0000000000000000000000000000000000000000000000000000000000000005, object(0,0) -deleted: object(_), object(2,0) -gas summary: computation_cost: 1000000, storage_cost: 15078400, storage_rebate: 1956240, non_refundable_storage_fee: 19760 - -task 4 'create-checkpoint'. lines 26-26: -Checkpoint created: 1 - -task 5 'advance-epoch'. lines 28-28: -Epoch advanced: 0 - -task 6 'programmable'. lines 30-32: -created: object(6,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 7 'run'. lines 34-34: -events: Event { package_id: sui_system, transaction_module: Identifier("sui_system"), sender: C, type_: StructTag { address: sui_system, module: Identifier("validator"), name: Identifier("StakingRequestEvent"), type_params: [] }, contents: [138, 42, 97, 253, 61, 22, 31, 106, 213, 157, 60, 241, 33, 156, 159, 193, 184, 127, 83, 194, 143, 198, 11, 54, 121, 139, 166, 151, 113, 26, 5, 97, 218, 131, 22, 109, 1, 175, 215, 221, 207, 138, 245, 248, 68, 244, 90, 170, 83, 244, 133, 72, 229, 17, 124, 35, 245, 162, 151, 140, 253, 66, 34, 68, 252, 204, 154, 66, 27, 187, 19, 193, 166, 106, 26, 169, 143, 10, 215, 80, 41, 237, 233, 72, 87, 119, 156, 105, 21, 180, 79, 148, 6, 139, 146, 30, 1, 0, 0, 0, 0, 0, 0, 0, 0, 228, 11, 84, 2, 0, 0, 0] } -created: object(7,0) -mutated: 0x0000000000000000000000000000000000000000000000000000000000000005, object(0,0), object(3,0) -deleted: object(6,0) -gas summary: computation_cost: 1000000, storage_cost: 15078400, storage_rebate: 14626656, non_refundable_storage_fee: 147744 - -task 8 'create-checkpoint'. lines 36-36: -Checkpoint created: 3 - -task 9 'advance-epoch'. lines 38-38: -Epoch advanced: 1 - -task 10 'view-object'. lines 40-40: -Owner: Account Address ( C ) -Version: 3 -Contents: sui_system::staking_pool::StakedSui {id: sui::object::UID {id: sui::object::ID {bytes: fake(3,1)}}, pool_id: sui::object::ID {bytes: _}, stake_activation_epoch: 1u64, principal: sui::balance::Balance {value: 10000000000u64}} - -task 11 'view-object'. lines 42-42: -Owner: Account Address ( C ) -Version: 5 -Contents: sui_system::staking_pool::StakedSui {id: sui::object::UID {id: sui::object::ID {bytes: fake(7,0)}}, pool_id: sui::object::ID {bytes: _}, stake_activation_epoch: 2u64, principal: sui::balance::Balance {value: 10000000000u64}} - -task 12 'run-graphql'. lines 44-56: -Response: { - "data": { - "address": { - "stakedSuis": { - "edges": [ - { - "cursor": "IAk4XNJ325CV4kql8g6oWLdlvSCovGah0C/Ucs4Gg2ayBAAAAAAAAAA=", - "node": { - "principal": "10000000000" - } - }, - { - "cursor": "IBX0DS9yEyPNAQauq4aH+cupD1Spyw3GeIxMiAUZU0iSBAAAAAAAAAA=", - "node": { - "principal": "10000000000" - } - } - ] - } - } - } -} - -task 13 'run-graphql'. lines 58-102: -Response: { - "data": { - "no_coins_after_obj_3_1_chkpt_1": { - "stakedSuis": { - "edges": [] - } - }, - "no_coins_before_obj_3_1_chkpt_1": { - "stakedSuis": { - "edges": [] - } - }, - "no_coins_after_obj_7_0_chkpt_1": { - "stakedSuis": { - "edges": [] - } - }, - "no_coins_before_obj_7_0_chkpt_1": { - "stakedSuis": { - "edges": [] - } - } - } -} - -task 14 'run-graphql'. lines 104-147: -Response: { - "data": { - "coins_after_obj_3_1_chkpt_3": { - "stakedSuis": { - "edges": [] - } - }, - "coins_before_obj_3_1_chkpt_3": { - "stakedSuis": { - "edges": [ - { - "cursor": "IAk4XNJ325CV4kql8g6oWLdlvSCovGah0C/Ucs4Gg2ayAwAAAAAAAAA=", - "node": { - "principal": "10000000000" - } - } - ] - } - }, - "coins_after_obj_7_0_chkpt_3": { - "stakedSuis": { - "edges": [ - { - "cursor": "IBX0DS9yEyPNAQauq4aH+cupD1Spyw3GeIxMiAUZU0iSAwAAAAAAAAA=", - "node": { - "principal": "10000000000" - } - } - ] - } - }, - "coins_before_obj_7_0_chkpt_3": { - "stakedSuis": { - "edges": [] - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/consistency/staked_sui.move b/crates/sui-graphql-e2e-tests/tests/consistency/staked_sui.move deleted file mode 100644 index 1666658706a..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/consistency/staked_sui.move +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --protocol-version 39 --simulator --accounts C - -//# run-graphql -{ - address(address: "@{C}") { - stakedSuis { - edges { - cursor - node { - principal - } - } - } - } -} - -//# programmable --sender C --inputs 10000000000 @C -//> SplitCoins(Gas, [Input(0)]); -//> TransferObjects([Result(0)], Input(1)) - -//# run 0x3::sui_system::request_add_stake --args object(0x5) object(2,0) @validator_0 --sender C - -//# create-checkpoint - -//# advance-epoch - -//# programmable --sender C --inputs 10000000000 @C -//> SplitCoins(Gas, [Input(0)]); -//> TransferObjects([Result(0)], Input(1)) - -//# run 0x3::sui_system::request_add_stake --args object(0x5) object(6,0) @validator_0 --sender C - -//# create-checkpoint - -//# advance-epoch - -//# view-object 3,1 - -//# view-object 7,0 - -//# run-graphql -{ - address(address: "@{C}") { - stakedSuis { - edges { - cursor - node { - principal - } - } - } - } -} - -//# run-graphql --cursors @{obj_3_1,1} @{obj_7_0,1} -# Even though there is a stake created after the initial one, the cursor locks the upper bound to -# checkpoint 1 - at that point in time, we did not have any additional stakes. -{ - no_coins_after_obj_3_1_chkpt_1: address(address: "@{C}") { - stakedSuis(after: "@{cursor_0}") { - edges { - cursor - node { - principal - } - } - } - } - no_coins_before_obj_3_1_chkpt_1: address(address: "@{C}") { - stakedSuis(before: "@{cursor_0}") { - edges { - cursor - node { - principal - } - } - } - } - no_coins_after_obj_7_0_chkpt_1: address(address: "@{C}") { - stakedSuis(after: "@{cursor_0}") { - edges { - cursor - node { - principal - } - } - } - } - no_coins_before_obj_7_0_chkpt_1: address(address: "@{C}") { - stakedSuis(before: "@{cursor_0}") { - edges { - cursor - node { - principal - } - } - } - } -} - -//# run-graphql --cursors @{obj_3_1,3} @{obj_7_0,3} -# The second stake was created at checkpoint 3, and thus will be visible. -{ - coins_after_obj_3_1_chkpt_3: address(address: "@{C}") { - stakedSuis(after: "@{cursor_0}") { - edges { - cursor - node { - principal - } - } - } - } - coins_before_obj_3_1_chkpt_3: address(address: "@{C}") { - stakedSuis(before: "@{cursor_0}") { - edges { - cursor - node { - principal - } - } - } - } - coins_after_obj_7_0_chkpt_3: address(address: "@{C}") { - stakedSuis(after: "@{cursor_1}") { - edges { - cursor - node { - principal - } - } - } - } - coins_before_obj_7_0_chkpt_3: address(address: "@{C}") { - stakedSuis(before: "@{cursor_1}") { - edges { - cursor - node { - principal - } - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/epoch/epoch.exp b/crates/sui-graphql-e2e-tests/tests/epoch/epoch.exp deleted file mode 100644 index 630bdbda47c..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/epoch/epoch.exp +++ /dev/null @@ -1,82 +0,0 @@ -processed 11 tasks - -init: -C: object(0,0) - -task 1 'create-checkpoint'. lines 8-8: -Checkpoint created: 1 - -task 2 'advance-epoch'. lines 10-10: -Epoch advanced: 0 - -task 3 'programmable'. lines 12-14: -created: object(3,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 4 'run'. lines 16-18: -events: Event { package_id: sui_system, transaction_module: Identifier("sui_system"), sender: C, type_: StructTag { address: sui_system, module: Identifier("validator"), name: Identifier("StakingRequestEvent"), type_params: [] }, contents: [138, 42, 97, 253, 61, 22, 31, 106, 213, 157, 60, 241, 33, 156, 159, 193, 184, 127, 83, 194, 143, 198, 11, 54, 121, 139, 166, 151, 113, 26, 5, 97, 218, 131, 22, 109, 1, 175, 215, 221, 207, 138, 245, 248, 68, 244, 90, 170, 83, 244, 133, 72, 229, 17, 124, 35, 245, 162, 151, 140, 253, 66, 34, 68, 252, 204, 154, 66, 27, 187, 19, 193, 166, 106, 26, 169, 143, 10, 215, 80, 41, 237, 233, 72, 87, 119, 156, 105, 21, 180, 79, 148, 6, 139, 146, 30, 1, 0, 0, 0, 0, 0, 0, 0, 0, 228, 11, 84, 2, 0, 0, 0] } -created: object(4,0) -mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000005, object(0,0) -deleted: object(3,0) -gas summary: computation_cost: 1000000, storage_cost: 15078400, storage_rebate: 1956240, non_refundable_storage_fee: 19760 - -task 5 'create-checkpoint'. lines 19-19: -Checkpoint created: 3 - -task 6 'advance-epoch'. lines 21-23: -Epoch advanced: 1 - -task 7 'programmable'. lines 24-28: -created: object(7,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 8 'create-checkpoint'. lines 29-29: -Checkpoint created: 5 - -task 9 'advance-epoch'. lines 31-32: -Epoch advanced: 2 - -task 10 'run-graphql'. lines 33-62: -Response: { - "data": { - "epoch": { - "validatorSet": { - "totalStake": "20000010002000000", - "activeValidators": { - "nodes": [ - { - "name": "validator-0" - } - ] - }, - "validatorCandidatesSize": 0, - "inactivePoolsId": "0x8713eb91a5cf17ed1c0d8e008aa785666469e7ab693ef8761efa1ee3ebbe3ab9" - }, - "totalGasFees": "1000000", - "totalStakeRewards": "1000000", - "totalStakeSubsidies": "0", - "fundSize": "15098160", - "fundInflow": "1976000", - "fundOutflow": "978120", - "netInflow": "997880", - "transactionBlocks": { - "nodes": [ - { - "kind": { - "__typename": "ProgrammableTransactionBlock" - }, - "digest": "74v5nnByFFTd2kePFY4X2skrHsRojfdnb96562Yr3hWM" - }, - { - "kind": { - "__typename": "EndOfEpochTransaction" - }, - "digest": "5NBZfJP5y3yrNaBesbtkatNSHoYCghaK6uCNP1uf8c2w" - } - ] - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/epoch/system_state.exp b/crates/sui-graphql-e2e-tests/tests/epoch/system_state.exp deleted file mode 100644 index 096c67048ab..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/epoch/system_state.exp +++ /dev/null @@ -1,139 +0,0 @@ -processed 23 tasks - -init: -C: object(0,0), validator_0: object(0,1) - -task 1 'create-checkpoint'. lines 10-10: -Checkpoint created: 1 - -task 2 'advance-epoch'. lines 12-12: -Epoch advanced: 0 - -task 3 'programmable'. lines 14-16: -created: object(3,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 4 'run'. lines 18-18: -events: Event { package_id: sui_system, transaction_module: Identifier("sui_system"), sender: C, type_: StructTag { address: sui_system, module: Identifier("validator"), name: Identifier("StakingRequestEvent"), type_params: [] }, contents: [236, 3, 28, 119, 89, 112, 37, 120, 90, 31, 66, 230, 116, 106, 58, 235, 215, 29, 65, 204, 9, 76, 95, 163, 254, 107, 4, 55, 88, 155, 108, 41, 218, 131, 22, 109, 1, 175, 215, 221, 207, 138, 245, 248, 68, 244, 90, 170, 83, 244, 133, 72, 229, 17, 124, 35, 245, 162, 151, 140, 253, 66, 34, 68, 252, 204, 154, 66, 27, 187, 19, 193, 166, 106, 26, 169, 143, 10, 215, 80, 41, 237, 233, 72, 87, 119, 156, 105, 21, 180, 79, 148, 6, 139, 146, 30, 1, 0, 0, 0, 0, 0, 0, 0, 0, 228, 11, 84, 2, 0, 0, 0] } -created: object(4,0) -mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000005, object(0,0) -deleted: object(3,0) -gas summary: computation_cost: 1000000, storage_cost: 15078400, storage_rebate: 1956240, non_refundable_storage_fee: 19760 - -task 5 'create-checkpoint'. lines 20-20: -Checkpoint created: 3 - -task 6 'advance-epoch'. lines 22-22: -Epoch advanced: 1 - -task 7 'create-checkpoint'. lines 24-24: -Checkpoint created: 5 - -task 8 'advance-epoch'. lines 26-26: -Epoch advanced: 2 - -task 9 'programmable'. lines 28-30: -created: object(9,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 10 'create-checkpoint'. lines 32-32: -Checkpoint created: 7 - -task 11 'advance-epoch'. lines 34-34: -Epoch advanced: 3 - -task 12 'run'. lines 36-36: -events: Event { package_id: sui_system, transaction_module: Identifier("sui_system"), sender: C, type_: StructTag { address: sui_system, module: Identifier("validator"), name: Identifier("UnstakingRequestEvent"), type_params: [] }, contents: [236, 3, 28, 119, 89, 112, 37, 120, 90, 31, 66, 230, 116, 106, 58, 235, 215, 29, 65, 204, 9, 76, 95, 163, 254, 107, 4, 55, 88, 155, 108, 41, 218, 131, 22, 109, 1, 175, 215, 221, 207, 138, 245, 248, 68, 244, 90, 170, 83, 244, 133, 72, 229, 17, 124, 35, 245, 162, 151, 140, 253, 66, 34, 68, 252, 204, 154, 66, 27, 187, 19, 193, 166, 106, 26, 169, 143, 10, 215, 80, 41, 237, 233, 72, 87, 119, 156, 105, 21, 180, 79, 148, 6, 139, 146, 30, 2, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 228, 11, 84, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] } -created: object(12,0) -mutated: object(_), 0x0000000000000000000000000000000000000000000000000000000000000005, object(0,0) -deleted: object(4,0) -gas summary: computation_cost: 1000000, storage_cost: 14774400, storage_rebate: 14927616, non_refundable_storage_fee: 150784 - -task 13 'create-checkpoint'. lines 38-38: -Checkpoint created: 9 - -task 14 'advance-epoch'. lines 40-40: -Epoch advanced: 4 - -task 15 'programmable'. lines 42-44: -created: object(15,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 16 'create-checkpoint'. lines 46-46: -Checkpoint created: 11 - -task 17 'advance-epoch'. lines 48-48: -Epoch advanced: 5 - -task 18 'run-graphql'. lines 50-60: -Response: { - "data": { - "epoch": { - "epochId": 4, - "systemStateVersion": 2, - "storageFund": { - "totalObjectStorageRebates": "15762400", - "nonRefundableBalance": "180424" - } - } - } -} - -task 19 'run-graphql'. lines 62-72: -Response: { - "data": { - "epoch": { - "epochId": 3, - "systemStateVersion": 2, - "storageFund": { - "totalObjectStorageRebates": "16066400", - "nonRefundableBalance": "29640" - } - } - } -} - -task 20 'run-graphql'. lines 74-84: -Response: { - "data": { - "epoch": { - "epochId": 2, - "systemStateVersion": 2, - "storageFund": { - "totalObjectStorageRebates": "15078400", - "nonRefundableBalance": "19760" - } - } - } -} - -task 21 'run-graphql'. lines 86-96: -Response: { - "data": { - "epoch": { - "epochId": 1, - "systemStateVersion": 2, - "storageFund": { - "totalObjectStorageRebates": "15078400", - "nonRefundableBalance": "19760" - } - } - } -} - -task 22 'run-graphql'. lines 98-108: -Response: { - "data": { - "epoch": { - "epochId": 4, - "systemStateVersion": 2, - "storageFund": { - "totalObjectStorageRebates": "15762400", - "nonRefundableBalance": "180424" - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/event_connection/pagination.move b/crates/sui-graphql-e2e-tests/tests/event_connection/pagination.move deleted file mode 100644 index 3a8d17d023e..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/event_connection/pagination.move +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --protocol-version 39 --addresses Test=0x0 --accounts A --simulator - -//# publish -module Test::M1 { - use sui::event; - - public struct EventA has copy, drop { - new_value: u64 - } - - public entry fun emit_1(value: u64) { - event::emit(EventA { new_value: value }) - } - - public entry fun emit_2(value: u64) { - event::emit(EventA { new_value: value }); - event::emit(EventA { new_value: value + 1}) - } -} - -//# run Test::M1::emit_1 --sender A --args 0 - -//# run Test::M1::emit_2 --sender A --args 1 - -//# create-checkpoint - -//# run-graphql -{ - events(filter: {sender: "@{A}"}) { - pageInfo { - hasPreviousPage - hasNextPage - } - edges { - cursor - node { - sendingModule { - name - } - type { - repr - } - sender { - address - } - json - bcs - } - } - } -} - -//# run-graphql --cursors {"tx":2,"e":0,"c":1} -{ - events(first: 2 after: "@{cursor_0}", filter: {sender: "@{A}"}) { - pageInfo { - hasPreviousPage - hasNextPage - } - edges { - cursor - node { - sendingModule { - name - } - type { - repr - } - sender { - address - } - json - bcs - } - } - } -} - -//# run-graphql --cursors {"tx":3,"e":1,"c":1} -{ - events(last: 2 before: "@{cursor_0}", filter: {sender: "@{A}"}) { - pageInfo { - hasPreviousPage - hasNextPage - } - edges { - cursor - node { - sendingModule { - name - } - type { - repr - } - sender { - address - } - json - bcs - } - } - } -} - -//# run-graphql -{ - events(last: 2) { - pageInfo { - hasPreviousPage - hasNextPage - } - edges { - cursor - node { - sendingModule { - name - } - type { - repr - } - sender { - address - } - json - bcs - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/objects/coin.move b/crates/sui-graphql-e2e-tests/tests/objects/coin.move deleted file mode 100644 index ac314736816..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/objects/coin.move +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --protocol-version 39 --addresses P0=0x0 --accounts A --simulator - -//# publish --sender A -module P0::fake { - use sui::coin; - - public struct FAKE has drop {} - - fun init(witness: FAKE, ctx: &mut TxContext){ - let (mut treasury_cap, metadata) = coin::create_currency( - witness, - 2, - b"FAKE", - b"", - b"", - option::none(), - ctx, - ); - - let c1 = coin::mint(&mut treasury_cap, 1, ctx); - let c2 = coin::mint(&mut treasury_cap, 2, ctx); - let c3 = coin::mint(&mut treasury_cap, 3, ctx); - - transfer::public_freeze_object(metadata); - transfer::public_transfer(treasury_cap, tx_context::sender(ctx)); - transfer::public_transfer(c1, tx_context::sender(ctx)); - transfer::public_transfer(c2, tx_context::sender(ctx)); - transfer::public_transfer(c3, tx_context::sender(ctx)); - } -} - -//# create-checkpoint - -//# run-graphql -fragment C on Coin { - coinBalance - contents { type { repr } } -} - -{ - suiCoins: coins { - edges { - cursor - node { ...C } - } - } - - fakeCoins: coins(type: "@{P0}::fake::FAKE") { - edges { - cursor - node { ...C } - } - } - - address(address: "@{A}") { - coins { - edges { - cursor - node { ...C } - } - } - - allBalances: balances { - edges { - cursor - node { - coinType { repr } - coinObjectCount - totalBalance - } - } - } - - firstBalance: balances(first: 1) { - edges { cursor } - } - - lastBalance: balances(last: 1) { - edges { cursor } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/objects/data.move b/crates/sui-graphql-e2e-tests/tests/objects/data.move deleted file mode 100644 index efad2e60874..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/objects/data.move +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --protocol-version 39 --addresses P0=0x0 --accounts A --simulator - -//# publish -module P0::m { - use std::ascii::{Self, String as ASCII}; - use std::string::{Self, String as UTF8}; - - public struct Foo has key, store { - id: UID, - f0: ID, - f1: bool, - f2: u8, - f3: u64, - f4: UTF8, - f5: ASCII, - f6: vector
    , - f7: Option, - } - - public struct Bar has key { - id: UID, - } - - public fun foo(ctx: &mut TxContext): Foo { - let id = object::new(ctx); - let f0 = object::uid_to_inner(&id); - let f1 = true; - let f2 = 42; - let f3 = 43; - let f4 = string::utf8(b"hello"); - let f5 = ascii::string(b"world"); - let f6 = vector[object::uid_to_address(&id)]; - let f7 = option::some(44); - Foo { id, f0, f1, f2, f3, f4, f5, f6, f7 } - } -} - -//# programmable --inputs @A -//> 0: P0::m::foo(); -//> TransferObjects([Result(0)], Input(0)) - -//# create-checkpoint - -//# run-graphql -{ - transactionBlocks(last: 1) { - nodes { - effects { - objectChanges { - nodes { - outputState { - asMoveObject { - contents { - type { repr } - data - json - } - } - } - } - } - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/objects/display.exp b/crates/sui-graphql-e2e-tests/tests/objects/display.exp deleted file mode 100644 index e6cc9ddcd27..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/objects/display.exp +++ /dev/null @@ -1,216 +0,0 @@ -processed 17 tasks - -init: -A: object(0,0) - -task 1 'publish'. lines 6-130: -events: Event { package_id: Test, transaction_module: Identifier("boars"), sender: A, type_: StructTag { address: sui, module: Identifier("display"), name: Identifier("DisplayCreated"), type_params: [Struct(StructTag { address: Test, module: Identifier("boars"), name: Identifier("Boar"), type_params: [] })] }, contents: [157, 80, 190, 33, 119, 59, 45, 238, 34, 126, 254, 191, 25, 36, 11, 95, 217, 30, 133, 175, 214, 221, 149, 84, 133, 67, 247, 141, 240, 193, 184, 229] } -created: object(1,0), object(1,1), object(1,2) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 21470000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 2 'create-checkpoint'. lines 132-132: -Checkpoint created: 1 - -task 3 'view-checkpoint'. lines 134-134: -CheckpointSummary { epoch: 0, seq: 1, content_digest: AvP8uds3916DQnCtsoGY4BBH3Bj8VzaMsVzVTv2LURFb, - epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 1000000, storage_cost: 21470000, storage_rebate: 0, non_refundable_storage_fee: 0 }} - -task 4 'run'. lines 136-136: -created: object(4,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 3556800, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 5 'run'. lines 138-138: -events: Event { package_id: Test, transaction_module: Identifier("boars"), sender: A, type_: StructTag { address: sui, module: Identifier("display"), name: Identifier("VersionUpdated"), type_params: [Struct(StructTag { address: Test, module: Identifier("boars"), name: Identifier("Boar"), type_params: [] })] }, contents: [157, 80, 190, 33, 119, 59, 45, 238, 34, 126, 254, 191, 25, 36, 11, 95, 217, 30, 133, 175, 214, 221, 149, 84, 133, 67, 247, 141, 240, 193, 184, 229, 1, 0, 3, 7, 118, 101, 99, 116, 111, 114, 115, 5, 123, 118, 101, 99, 125, 3, 105, 100, 100, 5, 123, 105, 100, 100, 125, 5, 110, 97, 109, 101, 101, 7, 123, 110, 97, 109, 101, 101, 125] } -mutated: object(0,0), object(1,1) -gas summary: computation_cost: 1000000, storage_cost: 2941200, storage_rebate: 2625876, non_refundable_storage_fee: 26524 - -task 6 'create-checkpoint'. lines 140-140: -Checkpoint created: 2 - -task 7 'view-checkpoint'. lines 142-142: -CheckpointSummary { epoch: 0, seq: 2, content_digest: EMEK1Xy5EePdb6taLpJJWCgNbrvDHTSS3UzY59KrSx1F, - epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 3000000, storage_cost: 27968000, storage_rebate: 3603996, non_refundable_storage_fee: 36404 }} - -task 8 'run-graphql'. lines 144-157: -Response: { - "data": { - "address": { - "objects": { - "nodes": [ - { - "display": [ - { - "key": "vectors", - "value": null, - "error": "Vector of name vec is not supported as a Display value" - }, - { - "key": "idd", - "value": null, - "error": "Field 'idd' not found" - }, - { - "key": "namee", - "value": null, - "error": "Field 'namee' not found" - } - ] - } - ] - } - } - } -} - -task 9 'run'. lines 159-159: -events: Event { package_id: Test, transaction_module: Identifier("boars"), sender: A, type_: StructTag { address: sui, module: Identifier("display"), name: Identifier("VersionUpdated"), type_params: [Struct(StructTag { address: Test, module: Identifier("boars"), name: Identifier("Boar"), type_params: [] })] }, contents: [157, 80, 190, 33, 119, 59, 45, 238, 34, 126, 254, 191, 25, 36, 11, 95, 217, 30, 133, 175, 214, 221, 149, 84, 133, 67, 247, 141, 240, 193, 184, 229, 2, 0, 4, 7, 118, 101, 99, 116, 111, 114, 115, 5, 123, 118, 101, 99, 125, 3, 105, 100, 100, 5, 123, 105, 100, 100, 125, 5, 110, 97, 109, 101, 101, 7, 123, 110, 97, 109, 101, 101, 125, 4, 110, 117, 109, 115, 6, 123, 110, 117, 109, 115, 125] } -mutated: object(0,0), object(1,1) -gas summary: computation_cost: 1000000, storage_cost: 3032400, storage_rebate: 2911788, non_refundable_storage_fee: 29412 - -task 10 'create-checkpoint'. lines 161-161: -Checkpoint created: 3 - -task 11 'view-checkpoint'. lines 163-163: -CheckpointSummary { epoch: 0, seq: 3, content_digest: 3WgfPMSDoyWjhDnFLqkwUqT6fk7Rq3WnJqB8zPH9Ju7X, - epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 4000000, storage_cost: 31000400, storage_rebate: 6515784, non_refundable_storage_fee: 65816 }} - -task 12 'run-graphql'. lines 165-178: -Response: { - "data": { - "address": { - "objects": { - "nodes": [ - { - "display": [ - { - "key": "vectors", - "value": null, - "error": "Vector of name vec is not supported as a Display value" - }, - { - "key": "idd", - "value": null, - "error": "Field 'idd' not found" - }, - { - "key": "namee", - "value": null, - "error": "Field 'namee' not found" - }, - { - "key": "nums", - "value": "420", - "error": null - } - ] - } - ] - } - } - } -} - -task 13 'run'. lines 180-180: -events: Event { package_id: Test, transaction_module: Identifier("boars"), sender: A, type_: StructTag { address: sui, module: Identifier("display"), name: Identifier("VersionUpdated"), type_params: [Struct(StructTag { address: Test, module: Identifier("boars"), name: Identifier("Boar"), type_params: [] })] }, contents: [157, 80, 190, 33, 119, 59, 45, 238, 34, 126, 254, 191, 25, 36, 11, 95, 217, 30, 133, 175, 214, 221, 149, 84, 133, 67, 247, 141, 240, 193, 184, 229, 3, 0, 15, 7, 118, 101, 99, 116, 111, 114, 115, 5, 123, 118, 101, 99, 125, 3, 105, 100, 100, 5, 123, 105, 100, 100, 125, 5, 110, 97, 109, 101, 101, 7, 123, 110, 97, 109, 101, 101, 125, 4, 110, 117, 109, 115, 6, 123, 110, 117, 109, 115, 125, 5, 98, 111, 111, 108, 115, 7, 123, 98, 111, 111, 108, 115, 125, 5, 98, 117, 121, 101, 114, 7, 123, 98, 117, 121, 101, 114, 125, 4, 110, 97, 109, 101, 6, 123, 110, 97, 109, 101, 125, 7, 99, 114, 101, 97, 116, 111, 114, 9, 123, 99, 114, 101, 97, 116, 111, 114, 125, 5, 112, 114, 105, 99, 101, 7, 123, 112, 114, 105, 99, 101, 125, 11, 112, 114, 111, 106, 101, 99, 116, 95, 117, 114, 108, 58, 85, 110, 105, 113, 117, 101, 32, 66, 111, 97, 114, 32, 102, 114, 111, 109, 32, 116, 104, 101, 32, 66, 111, 97, 114, 115, 32, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 32, 119, 105, 116, 104, 32, 123, 110, 97, 109, 101, 125, 32, 97, 110, 100, 32, 123, 105, 100, 125, 8, 98, 97, 115, 101, 95, 117, 114, 108, 32, 104, 116, 116, 112, 115, 58, 47, 47, 103, 101, 116, 45, 97, 45, 98, 111, 97, 114, 46, 99, 111, 109, 47, 123, 105, 109, 103, 95, 117, 114, 108, 125, 11, 110, 111, 95, 116, 101, 109, 112, 108, 97, 116, 101, 23, 104, 116, 116, 112, 115, 58, 47, 47, 103, 101, 116, 45, 97, 45, 98, 111, 97, 114, 46, 99, 111, 109, 47, 3, 97, 103, 101, 21, 123, 109, 101, 116, 97, 100, 97, 116, 97, 46, 110, 101, 115, 116, 101, 100, 46, 97, 103, 101, 125, 8, 102, 117, 108, 108, 95, 117, 114, 108, 10, 123, 102, 117, 108, 108, 95, 117, 114, 108, 125, 13, 101, 115, 99, 97, 112, 101, 95, 115, 121, 110, 116, 97, 120, 8, 92, 123, 110, 97, 109, 101, 92, 125] } -mutated: object(0,0), object(1,1) -gas summary: computation_cost: 1000000, storage_cost: 5236400, storage_rebate: 3002076, non_refundable_storage_fee: 30324 - -task 14 'create-checkpoint'. lines 182-182: -Checkpoint created: 4 - -task 15 'view-checkpoint'. lines 184-184: -CheckpointSummary { epoch: 0, seq: 4, content_digest: Edca7Q6cQmwQkpJTAojfrLh4tjkM9Zvxkbz2imBnUQbK, - epoch_rolling_gas_cost_summary: GasCostSummary { computation_cost: 5000000, storage_cost: 36236800, storage_rebate: 9517860, non_refundable_storage_fee: 96140 }} - -task 16 'run-graphql'. lines 186-199: -Response: { - "data": { - "address": { - "objects": { - "nodes": [ - { - "display": [ - { - "key": "vectors", - "value": null, - "error": "Vector of name vec is not supported as a Display value" - }, - { - "key": "idd", - "value": null, - "error": "Field 'idd' not found" - }, - { - "key": "namee", - "value": null, - "error": "Field 'namee' not found" - }, - { - "key": "nums", - "value": "420", - "error": null - }, - { - "key": "bools", - "value": "true", - "error": null - }, - { - "key": "buyer", - "value": "0xfccc9a421bbb13c1a66a1aa98f0ad75029ede94857779c6915b44f94068b921e", - "error": null - }, - { - "key": "name", - "value": "First Boar", - "error": null - }, - { - "key": "creator", - "value": "Will", - "error": null - }, - { - "key": "price", - "value": "", - "error": null - }, - { - "key": "project_url", - "value": "Unique Boar from the Boars collection with First Boar and 0x8191fe2b7da69708e88717dddab3af8544a09aa17dcfb2889be64569e68559c7", - "error": null - }, - { - "key": "base_url", - "value": "https://get-a-boar.com/first.png", - "error": null - }, - { - "key": "no_template", - "value": "https://get-a-boar.com/", - "error": null - }, - { - "key": "age", - "value": "10", - "error": null - }, - { - "key": "full_url", - "value": "https://get-a-boar.fullurl.com/", - "error": null - }, - { - "key": "escape_syntax", - "value": "{name}", - "error": null - } - ] - } - ] - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/objects/display.move b/crates/sui-graphql-e2e-tests/tests/objects/display.move deleted file mode 100644 index 2e1d29f0cdd..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/objects/display.move +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --protocol-version 39 --addresses Test=0x0 --accounts A --simulator - -//# publish --sender A -module Test::boars { - use sui::package; - use sui::url::{Self, Url}; - use sui::display; - use std::string::{utf8, String}; - - /// For when a witness type passed is not an OTW. - const ENotOneTimeWitness: u64 = 0; - - /// An OTW to use when creating a Publisher - public struct BOARS has drop {} - - public struct Boar has key, store { - id: UID, - img_url: String, - name: String, - description: String, - creator: Option, - price: Option, - metadata: NestedMetadata, - full_url: Url, - nums: u64, - bools: bool, - buyer: address, - vec: vector, - } - - public struct Metadata has store { - age: u64, - } - - public struct NestedMetadata has store { - nested: Metadata - } - - fun init(otw: BOARS, ctx: &mut TxContext) { - let pub = package::claim(otw, ctx); - let display = display::new(&pub, ctx); - - transfer::public_transfer(display, ctx.sender()); - transfer::public_transfer(pub, ctx.sender()); - } - - - public entry fun update_display_faulty(display_obj: &mut display::Display) { - display::add_multiple(display_obj, vector[ - utf8(b"vectors"), - utf8(b"idd"), - utf8(b"namee"), - ], vector[ - utf8(b"{vec}"), - utf8(b"{idd}"), - utf8(b"{namee}"), - ]); - display::update_version(display_obj) - } - - public entry fun single_add(display_obj: &mut display::Display) { - display::add(display_obj, utf8(b"nums"), utf8(b"{nums}")); - display::update_version(display_obj) - } - - public entry fun multi_add(display_obj: &mut display::Display) { - display::add_multiple(display_obj, vector[ - utf8(b"bools"), - utf8(b"buyer"), - utf8(b"name"), - utf8(b"creator"), - utf8(b"price"), - utf8(b"project_url"), - utf8(b"base_url"), - utf8(b"no_template"), - utf8(b"age"), - utf8(b"full_url"), - utf8(b"escape_syntax"), - ], vector[ - // test bool - utf8(b"{bools}"), - // test address - utf8(b"{buyer}"), - // test string - utf8(b"{name}"), - // test optional string w/ Some value - utf8(b"{creator}"), - // test optional string w/ None value - utf8(b"{price}"), - // test multiple fields and UID - utf8(b"Unique Boar from the Boars collection with {name} and {id}"), - utf8(b"https://get-a-boar.com/{img_url}"), - // test no template value - utf8(b"https://get-a-boar.com/"), - // test nested struct - utf8(b"{metadata.nested.age}"), - // test Url type - utf8(b"{full_url}"), - // test escape syntax - utf8(b"\\{name\\}"), - ]); - - display::update_version(display_obj); - } - - public entry fun create_bear(ctx: &mut TxContext) { - let boar = Boar { - id: object::new(ctx), - img_url: utf8(b"first.png"), - name: utf8(b"First Boar"), - description: utf8(b"First Boar from the Boars collection!"), - creator: option::some(utf8(b"Will")), - price: option::none(), - metadata: NestedMetadata { - nested: Metadata { - age: 10, - }, - }, - full_url: url::new_unsafe_from_bytes(b"https://get-a-boar.fullurl.com/"), - nums: 420, - bools: true, - buyer: ctx.sender(), - vec: vector[1, 2, 3], - }; - transfer::transfer(boar, ctx.sender()) - } -} - -//# create-checkpoint - -//# view-checkpoint - -//# run Test::boars::create_bear --sender A - -//# run Test::boars::update_display_faulty --sender A --args object(1,1) - -//# create-checkpoint - -//# view-checkpoint - -//# run-graphql -{ - address(address: "@{A}") { - objects(filter: {type: "@{Test}::boars::Boar"}) { - nodes { - display { - key - value - error - } - } - } - } -} - -//# run Test::boars::single_add --sender A --args object(1,1) - -//# create-checkpoint - -//# view-checkpoint - -//# run-graphql -{ - address(address: "@{A}") { - objects(filter: {type: "@{Test}::boars::Boar"}) { - nodes { - display { - key - value - error - } - } - } - } -} - -//# run Test::boars::multi_add --sender A --args object(1,1) - -//# create-checkpoint - -//# view-checkpoint - -//# run-graphql -{ - address(address: "@{A}") { - objects(filter: {type: "@{Test}::boars::Boar"}) { - nodes { - display { - key - value - error - } - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/objects/pagination.move b/crates/sui-graphql-e2e-tests/tests/objects/pagination.move deleted file mode 100644 index f0b3fc0fa4d..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/objects/pagination.move +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --protocol-version 39 --addresses Test=0x0 A=0x42 --simulator - -//# publish -module Test::M1 { - public struct Object has key, store { - id: UID, - value: u64, - } - - public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { - transfer::public_transfer( - Object { id: object::new(ctx), value }, - recipient - ) - } -} - -//# run Test::M1::create --args 0 @A - -//# run Test::M1::create --args 1 @A - -//# run Test::M1::create --args 2 @A - -//# run Test::M1::create --args 3 @A - -//# run Test::M1::create --args 4 @A - -//# create-checkpoint - -//# run-graphql -{ - # select all objects owned by A - address(address: "@{A}") { - objects { - edges { - cursor - } - } - } -} - -//# run-graphql -{ - # select the first 2 objects owned by A - address(address: "@{A}") { - objects(first: 2) { - edges { - cursor - } - } - } -} - -//# run-graphql --cursors @{obj_5_0} -{ - address(address: "@{A}") { - # select the 2nd and 3rd objects - # note that order does not correspond - # to order in which objects were created - objects(first: 2 after: "@{cursor_0}") { - edges { - cursor - } - } - } -} - -//# run-graphql --cursors @{obj_4_0} -{ - address(address: "@{A}") { - # select 4th and last object - objects(first: 2 after: "@{cursor_0}") { - edges { - cursor - } - } - } -} - -//# run-graphql --cursors @{obj_3_0} -{ - address(address: "@{A}") { - # select 3rd and 4th object - objects(last: 2 before: "@{cursor_0}") { - edges { - cursor - } - } - } -} - -//# run-graphql -{ - address(address: "@{A}") { - objects(last: 2) { - edges { - cursor - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/objects/staked_sui.exp b/crates/sui-graphql-e2e-tests/tests/objects/staked_sui.exp deleted file mode 100644 index b788e1f3ef1..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/objects/staked_sui.exp +++ /dev/null @@ -1,102 +0,0 @@ -processed 7 tasks - -init: -C: object(0,0) - -task 1 'run-graphql'. lines 6-31: -Response: { - "data": { - "objects": { - "edges": [ - { - "cursor": "IJWZW/OSvG5lfNwrD5Efh60SfOWYpPQ2klpOeswsoIDnAAAAAAAAAAA=", - "node": { - "asMoveObject": { - "asStakedSui": { - "principal": "20000000000000000" - } - } - } - } - ] - }, - "address": { - "stakedSuis": { - "edges": [] - } - } - } -} - -task 2 'programmable'. lines 33-35: -created: object(2,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 1976000, storage_rebate: 0, non_refundable_storage_fee: 0 - -task 3 'run'. lines 37-37: -events: Event { package_id: sui_system, transaction_module: Identifier("sui_system"), sender: C, type_: StructTag { address: sui_system, module: Identifier("validator"), name: Identifier("StakingRequestEvent"), type_params: [] }, contents: [138, 42, 97, 253, 61, 22, 31, 106, 213, 157, 60, 241, 33, 156, 159, 193, 184, 127, 83, 194, 143, 198, 11, 54, 121, 139, 166, 151, 113, 26, 5, 97, 218, 131, 22, 109, 1, 175, 215, 221, 207, 138, 245, 248, 68, 244, 90, 170, 83, 244, 133, 72, 229, 17, 124, 35, 245, 162, 151, 140, 253, 66, 34, 68, 252, 204, 154, 66, 27, 187, 19, 193, 166, 106, 26, 169, 143, 10, 215, 80, 41, 237, 233, 72, 87, 119, 156, 105, 21, 180, 79, 148, 6, 139, 146, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 11, 84, 2, 0, 0, 0] } -created: object(3,0), object(3,1) -mutated: 0x0000000000000000000000000000000000000000000000000000000000000005, object(0,0) -deleted: object(_), object(2,0) -gas summary: computation_cost: 1000000, storage_cost: 15078400, storage_rebate: 1956240, non_refundable_storage_fee: 19760 - -task 4 'create-checkpoint'. lines 39-39: -Checkpoint created: 1 - -task 5 'advance-epoch'. lines 41-41: -Epoch advanced: 0 - -task 6 'run-graphql'. lines 43-69: -Response: { - "data": { - "objects": { - "edges": [ - { - "cursor": "IBX0DS9yEyPNAQauq4aH+cupD1Spyw3GeIxMiAUZU0iSAgAAAAAAAAA=", - "node": { - "asMoveObject": { - "asStakedSui": { - "principal": "10000000000", - "poolId": "0x8a2a61fd3d161f6ad59d3cf1219c9fc1b87f53c28fc60b36798ba697711a0561" - } - } - } - }, - { - "cursor": "IJWZW/OSvG5lfNwrD5Efh60SfOWYpPQ2klpOeswsoIDnAgAAAAAAAAA=", - "node": { - "asMoveObject": { - "asStakedSui": { - "principal": "20000000000000000", - "poolId": "0x8a2a61fd3d161f6ad59d3cf1219c9fc1b87f53c28fc60b36798ba697711a0561" - } - } - } - }, - { - "cursor": "IM4xOAHc44iKtPoj6VC+X2JPItu/LKLvVeSyLZAGWA+/AgAAAAAAAAA=", - "node": { - "asMoveObject": { - "asStakedSui": { - "principal": "40000", - "poolId": "0x8a2a61fd3d161f6ad59d3cf1219c9fc1b87f53c28fc60b36798ba697711a0561" - } - } - } - } - ] - }, - "address": { - "stakedSuis": { - "edges": [ - { - "cursor": "IBX0DS9yEyPNAQauq4aH+cupD1Spyw3GeIxMiAUZU0iSAgAAAAAAAAA=", - "node": { - "principal": "10000000000" - } - } - ] - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/objects/staked_sui.move b/crates/sui-graphql-e2e-tests/tests/objects/staked_sui.move deleted file mode 100644 index 0892e2912d4..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/objects/staked_sui.move +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --protocol-version 39 --simulator --accounts C - -//# run-graphql -{ # init --protocol-version 39ial query yields only the validator's stake - objects(filter: { type: "0x3::staking_pool::StakedSui" }) { - edges { - cursor - node { - asMoveObject { - asStakedSui { - principal - } - } - } - } - } - - address(address: "@{C}") { - stakedSuis { - edges { - cursor - node { - principal - } - } - } - } -} - -//# programmable --sender C --inputs 10000000000 @C -//> SplitCoins(Gas, [Input(0)]); -//> TransferObjects([Result(0)], Input(1)) - -//# run 0x3::sui_system::request_add_stake --args object(0x5) object(2,0) @validator_0 --sender C - -//# create-checkpoint - -//# advance-epoch - -//# run-graphql -{ # This query should pick up the recently Staked SUI as well. - objects(filter: { type: "0x3::staking_pool::StakedSui" }) { - edges { - cursor - node { - asMoveObject { - asStakedSui { - principal - poolId - } - } - } - } - } - - address(address: "@{C}") { - stakedSuis { - edges { - cursor - node { - principal - } - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/packages/modules.move b/crates/sui-graphql-e2e-tests/tests/packages/modules.move deleted file mode 100644 index e7d95a4fb04..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/packages/modules.move +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --protocol-version 39 --addresses pkg=0x0 --simulator - -//# publish - -module pkg::m { - use sui::coin::{Self, Coin}; - use sui::sui::SUI; - - public fun foo(x: u64, c: &Coin): u64 { - coin::value(c) + x - } - - public fun bar(c: &Coin): u64 { - foo(42, c) * foo(43, c) - } -} - -module pkg::n { - public fun baz(): u32 { - 44 - } -} - -module pkg::o { - public fun qux(): u32 { - 45 - } -} - -//# create-checkpoint - -//# run-graphql - -fragment Modules on Object { - address - asMovePackage { - module(name: "m") { - name - package { address } - - fileFormatVersion - bytes - disassembly - } - } -} - -{ - transactionBlocks(last: 1) { - nodes { - effects { - objectChanges { - nodes { - outputState { - ...Modules - } - } - } - } - } - } -} - -//# run-graphql --cursors {"n":"m","c":1} {"n":"o","c":1} -fragment NodeNames on MoveModuleConnection { - edges { - cursor - node { name } - } - pageInfo { hasNextPage hasPreviousPage } -} - -fragment Modules on Object { - address - asMovePackage { - # Tests to make sure `after` and `before` correctly limit the - # upper and lower bounds on the range of modules, and - # correctly detect the existence of predecessor or successor - # pages. - - all: modules { ...NodeNames } - after: modules(after: "@{cursor_0}") { ...NodeNames } - before: modules(before: "@{cursor_1}") { ...NodeNames } - } -} - -{ - transactionBlocks(last: 1) { - nodes { - effects { - objectChanges { - nodes { - outputState { - ...Modules - } - } - } - } - } - } -} - -//# run-graphql --cursors {"n":"m","c":1} {"n":"o","c":1} -fragment NodeNames on MoveModuleConnection { - edges { - cursor - node { name } - } - pageInfo { hasNextPage hasPreviousPage } -} - -fragment Modules on Object { - address - asMovePackage { - # Tests to make sure `first` and `last` correctly limit the - # number of modules returned and correctly detect the - # existence of predecessor or successor pages. - - prefix: modules(after: "@{cursor_0}", first: 1) { ...NodeNames } - prefixAll: modules(after: "@{cursor_0}", first: 2) { ...NodeNames } - prefixExcess: modules(after: "@{cursor_0}", first: 20) { ...NodeNames } - - suffix: modules(before: "@{cursor_1}", last: 1) { ...NodeNames } - suffixAll: modules(before: "@{cursor_1}", last: 2) { ...NodeNames } - suffixExcess: modules(before: "@{cursor_1}", last: 20) { ...NodeNames } - } -} - -{ - transactionBlocks(last: 1) { - nodes { - effects { - objectChanges { - nodes { - outputState { - ...Modules - } - } - } - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/packages/structs.move b/crates/sui-graphql-e2e-tests/tests/packages/structs.move deleted file mode 100644 index fd14b1075a9..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/packages/structs.move +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --protocol-version 39 --addresses P0=0x0 P1=0x0 --accounts A --simulator - -//# run-graphql - -# Tests on existing system types -{ - object(address: "0x2") { - asMovePackage { - # Look-up a type that has generics, including phantoms. - coin: module(name: "coin") { - struct(name: "Coin") { - name - abilities - typeParameters { - constraints - isPhantom - } - fields { - name - type { - repr - signature - } - } - } - } - - tx_context: module(name: "tx_context") { - struct(name: "TxContext") { - name - abilities - typeParameters { - constraints - isPhantom - } - fields { - name - type { - repr - signature - } - } - } - } - } - } -} - -//# publish --upgradeable --sender A - -module P0::m { - public struct S has copy, drop { x: u64 } -} - -//# create-checkpoint - -//# run-graphql - -# Check the contents of P0::m::S that was just published, this acts as -# a reference for when we run the same transaction against the -# upgraded package. -fragment Structs on Object { - address - asMovePackage { - module(name: "m") { - struct(name: "S") { - name - abilities - typeParameters { - constraints - isPhantom - } - fields { - name - type { - repr - signature - } - } - } - } - } -} - -{ - transactionBlocks(last: 1) { - nodes { - effects { - objectChanges { - nodes { - outputState { - ...Structs - } - } - } - } - } - } -} - -//# upgrade --package P0 --upgrade-capability 2,1 --sender A - -module P1::m { - public struct S has copy, drop { x: u64 } - public struct T { y: u64, s: S, u: U } - public struct V { t: T } -} - -//# create-checkpoint - -//# run-graphql - -# Run a similar query as above again, but on the upgraded package, to -# see the IDs of types as they appear in the new package -- they will -# all be the runtime ID. -fragment FullStruct on MoveStruct { - module { package { address } } - name - abilities - typeParameters { - constraints - isPhantom - } - fields { - name - type { - repr - signature - } - } -} - -fragment Structs on Object { - address - asMovePackage { - module(name: "m") { - s: struct(name: "S") { ...FullStruct } - t: struct(name: "T") { ...FullStruct } - - # V is a special type that exists to show the - # representations of S and T, so we don't need to query as - # many fields for it. - v: struct(name: "V") { - name - fields { - name - type { repr } - } - } - } - } -} - -{ - transactionBlocks(last: 1) { - nodes { - effects { - objectChanges { - nodes { - outputState { - ...Structs - } - } - } - } - } - } -} - -//# run-graphql - -# But we can still confirm that we can roundtrip the `T` public struct from -# its own module, but cannot reach `T` from `S`'s defining module. - -fragment ReachT on MoveStruct { - module { struct(name: "T") { name } } -} - -fragment Structs on Object { - asMovePackage { - module(name: "m") { - # S should not be able to reach T from its own module - s: struct(name: "S") { ...ReachT } - - # But T should - t: struct(name: "T") { ...ReachT } - } - } -} - -{ - transactionBlocks(last: 1) { - nodes { - effects { - objectChanges { - nodes { - outputState { - ...Structs - } - } - } - } - } - } -} - - -//# run-graphql --cursors {"n":"Coin","c":2} {"n":"TreasuryCap","c":2} -{ - object(address: "0x2") { - asMovePackage { - module(name: "coin") { - # Get all the types defined in coin - all: structs { - nodes { - name - fields { - name - type { repr } - } - } - pageInfo { hasNextPage hasPreviousPage } - } - - # After: Coin is the first type and `after` is an - # exclusive lower bound, so this query should indicate - # there is a previous page, and not include `Coin` in - # the output. - after: structs(after: "@{cursor_0}") { - edges { - cursor - node { name } - } - pageInfo { hasNextPage hasPreviousPage } - } - - # Before: Similar to `after` but at the end of the range. - before: structs(before: "@{cursor_1}") { - edges { - cursor - node { name } - } - pageInfo { hasNextPage hasPreviousPage } - } - } - } - } -} - -//# run-graphql --cursors {"n":"Coin","c":2} {"n":"TreasuryCap","c":2} -fragment NodeNames on MoveStructConnection { - edges { - cursor - node { name } - } - pageInfo { hasNextPage hasPreviousPage } -} - -{ - object(address: "0x2") { - asMovePackage { - module(name: "coin") { - # Limit the number of elements in the page using - # `first` and skip elements using `after`. - prefix: structs(after: "@{cursor_0}", first: 2) { - ...NodeNames - } - - # Limit has no effect because it matches the total - # number of entries in the page. - prefixAll: structs(after: "@{cursor_0}", first: 3) { - ...NodeNames - } - - # Limit also has no effect, because it exceeds the - # total number of entries in the page. - prefixExcess: structs(after: "@{cursor_0}", first: 20) { - ...NodeNames - } - - # Remaining tests are similar to after/first but with - # before/last. - suffix: structs(before: "@{cursor_1}", last: 2) { - ...NodeNames - } - - suffixAll: structs(before: "@{cursor_1}", last: 3) { - ...NodeNames - } - - suffixExcess: structs(before: "@{cursor_1}", last: 20) { - ...NodeNames - } - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/packages/types.move b/crates/sui-graphql-e2e-tests/tests/packages/types.move deleted file mode 100644 index b837e3e4b12..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/packages/types.move +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --protocol-version 39 --addresses P0=0x0 --simulator - -//# run-graphql -# Happy path -- valid type, get everything - -{ - type(type: "0x2::priority_queue::PriorityQueue<0x2::coin::Coin<0x2::sui::SUI>>") { - repr - signature - layout - } -} - -//# run-graphql -# Happy path -- primitive type - -{ - type(type: "u64") { - repr - signature - layout - } -} - -//# run-graphql -# Happy path -- primitive type with generic parameter - -{ - type(type: "vector") { - repr - signature - layout - } -} - -//# run-graphql -# Unhappy path -- bad type tag (failed to parse) - -{ - type(type: "not_a_type") { - repr - signature - layout - } -} - -//# run-graphql -# Semi-happy path -- the input looks like a type, but that type -# doesn't exist. Depending on which fields you ask for, this request -# may still succeed. - -{ - type(type: "0x42::not::Here") { - repr - signature - } -} - -//# run-graphql -# Unhappy side of semi-happy path -- asking for a layout for a type -# that doesn't exist won't work. -# -# TODO: This currently produces an INTERNAL_SERVER_ERROR, but should -# produce a user error. This because, like other parts of our -# codebase, we don't have enough differentiation in error types for -# MoveType to signal an error in layout calculation and the GraphQL -# field implementations to know that it is a user error or an internal -# error. - -{ - type(type: "0x42::not::Here") { - layout - } -} - -//# run-graphql -# Querying abilities for concrete types - -{ - token: type(type: "0x2::token::Token<0x2::sui::SUI>") { - abilities - } - - coin: type(type: "0x2::coin::Coin<0x2::sui::SUI>") { - abilities - } - - balance: type(type: "0x2::balance::Balance<0x2::sui::SUI>") { - abilities - } - - coin_vector: type(type: "vector<0x2::coin::Coin<0x2::sui::SUI>>") { - abilities - } - - prim_vector: type(type: "vector") { - abilities - } -} - -//# run-graphql -# Unhappy path, type arguments too deep. - -{ - type(type: """ - vector - >>>> - >>>> - >>>> - >>>> - """) { - abilities - } -} - -//# publish -module P0::m { - public struct S0 { - xs: vector>>> - >>>> - } - - public struct S1 { - xss: S0>>>>>>> - >>>>>>>> - } -} - -//# create-checkpoint - -//# run-graphql - -# Unhappy path, value nesting too deep. - -{ - type(type: "@{P0}::m::S1") { - layout - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/tests.rs b/crates/sui-graphql-e2e-tests/tests/tests.rs deleted file mode 100644 index 69b549209fd..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/tests.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#![allow(unused_imports)] -#![allow(unused_variables)] -use std::{path::Path, sync::Arc}; - -use sui_transactional_test_runner::{ - run_test_impl, - test_adapter::{SuiTestAdapter, PRE_COMPILED}, -}; -pub const TEST_DIR: &str = "tests"; - -datatest_stable::harness!(run_test, TEST_DIR, r".*\.(mvir|move)$"); - -#[cfg_attr(not(msim), tokio::main)] -#[cfg_attr(msim, msim::main)] -async fn run_test(path: &Path) -> Result<(), Box> { - if cfg!(feature = "pg_integration") { - run_test_impl::(path, Some(Arc::new(PRE_COMPILED.clone()))).await?; - } - Ok(()) -} diff --git a/crates/sui-graphql-e2e-tests/tests/transactions/random.move b/crates/sui-graphql-e2e-tests/tests/transactions/random.move deleted file mode 100644 index 2dfbc286199..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/transactions/random.move +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --protocol-version 39 --simulator - -//# create-checkpoint - -//# advance-epoch --create-random-state - -//# run-graphql -# Make sure the randomness state was created on the epoch boundary -{ - epoch { - protocolConfigs { - protocolVersion - randomBeacon: featureFlag(key: "random_beacon") { value } - } - } - - object(address: "0x8") { - address - version - asMoveObject { - contents { - type { repr } - json - } - } - } - - transactionBlocks(last: 1) { - nodes { - kind { - __typename - ... on EndOfEpochTransaction { - transactions { - edges { - cursor - node { __typename } - } - } - } - } - } - } -} - - -//# set-random-state --randomness-round 0 --random-bytes SGVsbG8gU3Vp --randomness-initial-version 2 -# Set the contents of the randomness object - -//# create-checkpoint - -//# run-graphql -{ - transactionBlocks(last: 1) { - nodes { - kind { - __typename - ... on RandomnessStateUpdateTransaction { - epoch { epochId } - randomnessRound - randomBytes - randomnessObjInitialSharedVersion - } - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/transactions/shared.move b/crates/sui-graphql-e2e-tests/tests/transactions/shared.move deleted file mode 100644 index 78b2fb8942b..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/transactions/shared.move +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# init --protocol-version 39 --addresses P0=0x0 --simulator - -//# publish -module P0::m { - public struct Foo has key { - id: UID, - x: u64, - } - - fun init(ctx: &mut TxContext) { - transfer::share_object(Foo { - id: object::new(ctx), - x: 0, - }) - } - - public fun get(f: &Foo): u64 { f.x } - public fun inc(f: &mut Foo) { f.x = f.x + 1 } -} - -//# programmable --inputs immshared(1,0) -//> 0: P0::m::get(Input(0)) - -//# programmable --inputs object(1,0) -//> 0: P0::m::inc(Input(0)) - -//# programmable --inputs object(1,0) -//> 0: P0::m::get(Input(0)); -//> P0::m::inc(Input(0)) - -//# create-checkpoint - -//# run-graphql -{ - transactionBlocks(last: 3) { - nodes { - kind { - __typename - ... on ProgrammableTransactionBlock { - transactions { - nodes { - ... on MoveCallTransaction { - package - module - functionName - } - } - } - } - } - effects { - status - unchangedSharedObjects { - nodes { - __typename - ... on SharedObjectRead { - address - version - digest - object { - asMoveObject { - contents { - type { - repr - } - json - } - } - } - } - ... on SharedObjectDelete { - address - version - mutable - } - } - } - } - } - } -} diff --git a/crates/sui-graphql-e2e-tests/tests/validator/validator.move b/crates/sui-graphql-e2e-tests/tests/validator/validator.move deleted file mode 100644 index 92be888e9fe..00000000000 --- a/crates/sui-graphql-e2e-tests/tests/validator/validator.move +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// Test the change of APY with heavy transactions - -//# init --protocol-version 39 --simulator --accounts A --addresses P0=0x0 - -//# advance-epoch - -//# create-checkpoint - -//# publish --sender A --gas-budget 9999999999 -module P0::m { - public struct Big has key, store { - id: UID, - weight: vector, - } - - fun weight(): vector { - let mut i = 0; - let mut v = vector[]; - while (i < 248 * 1024) { - vector::push_back(&mut v, 42); - i = i + 1; - }; - v - } - - public entry fun new(ctx: &mut TxContext){ - let id = object::new(ctx); - let w = weight(); - sui::transfer::public_transfer( - Big { id, weight: w }, - ctx.sender() - ) - } -} - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# create-checkpoint - -//# advance-epoch - -//# run-graphql -{ - epoch(id: 1) { - validatorSet { - activeValidators { - nodes { - apy - name - } - } - } - } -} - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# run P0::m::new --sender A - -//# create-checkpoint - -//# advance-epoch - -// check the epoch metrics - -//# run-graphql -{ - epoch(id: 2) { - validatorSet { - activeValidators { - nodes { - apy - name - reportRecords { - nodes { - address - } - } - } - } - } - } -} diff --git a/crates/sui-graphql-rpc-client/Cargo.toml b/crates/sui-graphql-rpc-client/Cargo.toml deleted file mode 100644 index 929101d0a90..00000000000 --- a/crates/sui-graphql-rpc-client/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "sui-graphql-rpc-client" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -async-graphql = {workspace = true, features = ["dataloader", "apollo_tracing", "tracing", "opentelemetry"] } -axum.workspace = true -hyper.workspace = true -reqwest.workspace = true -serde_json.workspace = true -sui-graphql-rpc-headers.workspace = true -thiserror.workspace = true diff --git a/crates/sui-graphql-rpc-client/src/lib.rs b/crates/sui-graphql-rpc-client/src/lib.rs deleted file mode 100644 index d1615bb8a91..00000000000 --- a/crates/sui-graphql-rpc-client/src/lib.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_graphql::Value; -use hyper::header::ToStrError; -use serde_json::Number; - -pub mod response; -pub mod simple_client; - -#[derive(Debug, thiserror::Error)] -pub enum ClientError { - #[error("Service version header not found")] - ServiceVersionHeaderNotFound, - #[error("Service version header value invalid string: {error}")] - ServiceVersionHeaderValueInvalidString { error: ToStrError }, - #[error("Invalid usage number for {usage_name}: {usage_number}")] - InvalidUsageNumber { - usage_name: String, - usage_number: Number, - }, - #[error("Invalid usage field for {usage_name}: {usage_value}")] - InvalidUsageValue { - usage_name: String, - usage_value: Value, - }, - #[error("{item_type} at pos {idx} must not be empty")] - InvalidEmptyItem { item_type: String, idx: usize }, - #[error( - "Invalid variable name: `{var_name}`. Variable names must be non-empty and start with a letter or underscore, and may only contain letters, digits, and underscores." - )] - InvalidVariableName { var_name: String }, - - #[error( - "Conflicting type definitions for variable {var_name}: {var_type_prev} vs {var_type_curr}" - )] - VariableDefinitionConflict { - var_name: String, - var_type_prev: String, - var_type_curr: String, - }, - #[error("Conflicting values for variable {var_name}: {var_val_prev} vs {var_val_curr}")] - VariableValueConflict { - var_name: String, - var_val_prev: serde_json::Value, - var_val_curr: serde_json::Value, - }, - #[error(transparent)] - InnerClientError(#[from] reqwest::Error), -} diff --git a/crates/sui-graphql-rpc-client/src/response.rs b/crates/sui-graphql-rpc-client/src/response.rs deleted file mode 100644 index a3f9605b9cf..00000000000 --- a/crates/sui-graphql-rpc-client/src/response.rs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::BTreeMap, net::SocketAddr}; - -use async_graphql::{Response, ServerError, Value}; -use axum::http::HeaderName; -use hyper::HeaderMap; -use reqwest::Response as ReqwestResponse; -use serde_json::json; -use sui_graphql_rpc_headers::VERSION_HEADER; - -use super::ClientError; - -#[derive(Debug)] -pub struct GraphqlResponse { - headers: HeaderMap, - remote_address: Option, - http_version: hyper::Version, - status: hyper::StatusCode, - full_response: Response, -} - -impl GraphqlResponse { - pub async fn from_resp(resp: ReqwestResponse) -> Result { - let headers = resp.headers().clone(); - let remote_address = resp.remote_addr(); - let http_version = resp.version(); - let status = resp.status(); - let full_response: Response = resp.json().await.map_err(ClientError::InnerClientError)?; - - Ok(Self { - headers, - remote_address, - http_version, - status, - full_response, - }) - } - - pub fn graphql_version(&self) -> Result { - Ok(self - .headers - .get(&VERSION_HEADER) - .ok_or(ClientError::ServiceVersionHeaderNotFound)? - .to_str() - .map_err(|e| ClientError::ServiceVersionHeaderValueInvalidString { error: e })? - .to_string()) - } - - pub fn response_body(&self) -> &Response { - &self.full_response - } - - pub fn response_body_json(&self) -> serde_json::Value { - json!(self.full_response) - } - - pub fn response_body_json_pretty(&self) -> String { - serde_json::to_string_pretty(&self.full_response).unwrap() - } - - pub fn http_status(&self) -> hyper::StatusCode { - self.status - } - - pub fn http_version(&self) -> hyper::Version { - self.http_version - } - - pub fn http_headers(&self) -> HeaderMap { - self.headers.clone() - } - - /// Returns the HTTP headers without the `Date` header. - /// The `Date` header is removed because it is not deterministic. - pub fn http_headers_without_date(&self) -> HeaderMap { - let mut headers = self.http_headers().clone(); - headers.remove(HeaderName::from_static("date")); - headers - } - - pub fn remote_address(&self) -> Option { - self.remote_address - } - - pub fn errors(&self) -> Vec { - self.full_response.errors.clone() - } - - pub fn usage(&self) -> Result>, ClientError> { - Ok(match self.full_response.extensions.get("usage").cloned() { - Some(Value::Object(obj)) => Some( - obj.into_iter() - .map(|(k, v)| match v { - Value::Number(n) => { - n.as_u64().ok_or(ClientError::InvalidUsageNumber { - usage_name: k.to_string(), - usage_number: n, - }) - } - .map(|q| (k.to_string(), q)), - _ => Err(ClientError::InvalidUsageValue { - usage_name: k.to_string(), - usage_value: v, - }), - }) - .collect::, ClientError>>()?, - ), - _ => None, - }) - } -} diff --git a/crates/sui-graphql-rpc-headers/Cargo.toml b/crates/sui-graphql-rpc-headers/Cargo.toml deleted file mode 100644 index f24c6c5dd27..00000000000 --- a/crates/sui-graphql-rpc-headers/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "sui-graphql-rpc-headers" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -axum.workspace = true diff --git a/crates/sui-graphql-rpc-headers/src/lib.rs b/crates/sui-graphql-rpc-headers/src/lib.rs deleted file mode 100644 index f24429aad92..00000000000 --- a/crates/sui-graphql-rpc-headers/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use axum::http::HeaderName; - -pub static VERSION_HEADER: HeaderName = HeaderName::from_static("x-sui-rpc-version"); -pub static LIMITS_HEADER: HeaderName = HeaderName::from_static("x-sui-rpc-show-usage"); diff --git a/crates/sui-graphql-rpc/Cargo.toml b/crates/sui-graphql-rpc/Cargo.toml deleted file mode 100644 index a3c942daab6..00000000000 --- a/crates/sui-graphql-rpc/Cargo.toml +++ /dev/null @@ -1,92 +0,0 @@ -[package] -name = "sui-graphql-rpc" -version = "2024.2.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - - -[dependencies] -anyhow.workspace = true -async-graphql = {workspace = true, features = ["dataloader", "apollo_tracing", "tracing", "opentelemetry"] } -async-graphql-axum.workspace = true -async-graphql-value.workspace = true -async-trait.workspace = true -axum.workspace = true -chrono.workspace = true -clap.workspace = true -const-str.workspace = true -diesel.workspace = true -either.workspace = true -fastcrypto = { workspace = true, features = ["copy_key"] } -fastcrypto-zkp.workspace = true -futures.workspace = true -git-version.workspace = true -hex.workspace = true -http.workspace = true -hyper.workspace = true -lru.workspace = true -move-binary-format.workspace = true -move-disassembler.workspace = true -move-ir-types.workspace = true -markdown-gen.workspace = true -mysten-metrics.workspace = true -mysten-network.workspace = true -move-core-types.workspace = true -once_cell.workspace = true -prometheus.workspace = true -rand.workspace = true # todo: cleanup test only deps -regex.workspace = true -reqwest.workspace = true -serial_test.workspace = true -serde.workspace = true -serde_json.workspace = true -serde_with.workspace = true -serde_yaml.workspace = true -shared-crypto.workspace = true -similar.workspace = true -sui-sdk.workspace = true -sui-types.workspace = true -tap.workspace = true -telemetry-subscribers.workspace = true -tracing.workspace = true -tokio = { workspace = true, features = ["rt-multi-thread"] } -tokio-util = { workspace = true, features = ["rt"] } -toml.workspace = true -tower.workspace = true -tower-http.workspace = true -thiserror.workspace = true -uuid.workspace = true -im.workspace = true - -sui-graphql-rpc-headers.workspace = true -sui-graphql-rpc-client.workspace = true - - -# TODO: put these behind feature flag to prevent leakage -# Used for dummy data -bcs.workspace = true -simulacrum.workspace = true # todo: cleanup test only deps -sui-json-rpc.workspace = true -sui-json-rpc-types.workspace = true -sui-indexer.workspace = true -sui-rest-api.workspace = true -sui-swarm-config.workspace = true -test-cluster.workspace = true -sui-protocol-config.workspace = true -move-bytecode-utils.workspace = true -sui-package-resolver.workspace = true - -[dev-dependencies] -expect-test.workspace = true -hyper.workspace = true -insta.workspace = true -serde_json.workspace = true -sui-framework.workspace = true -tower.workspace = true - -[features] -default = ["pg_backend"] -pg_integration = [] -pg_backend = [] diff --git a/crates/sui-graphql-rpc/README.md b/crates/sui-graphql-rpc/README.md deleted file mode 100644 index 44cdbe22ec8..00000000000 --- a/crates/sui-graphql-rpc/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# sui-graphql-rpc - -## Dev setup -Note that we use compilation flags to determine the backend for Diesel. If you're using VS Code, make sure to update settings.json with the appropriate features - there should at least be a "pg_backend" (or other backend.) -``` -"rust-analyzer.cargo.features": ["pg_backend"] -``` -Consequently, you'll also need to specify the backend when running cargo commands: -```cargo run --features "pg_backend" --bin sui-graphql-rpc start-server --db-url ``` - -The order is important: -1. --features "pg_backend": This part tells Cargo to enable the pg_backend feature. -2. --bin sui-graphql-rpc: This specifies which binary to run. -3. start-server --db-url: These are arguments to the binary. - -## Spinning up locally - -### Setting up local db - -The graphql service is backed by a db based on the db schema in [sui-indexer](../sui-indexer/src/schema.rs). To spin up a local db, follow the instructions at [sui-indexer](../sui-indexer/README.md) until "Running standalone indexer". - -If you have not created a db yet, you can do so as follows: -```sh -psql -U postgres -CREATE DATABASE sui_indexer_v2; -``` - -You should be able to refer to the db url now: -`psql postgres://postgres:postgrespw@localhost:5432/sui_indexer_v2` - -With the new db, run the following commands (also under `sui/crates/sui-indexer`): - -```sh -diesel setup --database-url="" --migration-dir=migrations -diesel migration run --database-url="" --migration-dir=migrations -``` - -### Launching the server -See [src/commands.rs](src/commands.rs) for all CLI options. - -Example `.toml` config: -```toml -[limits] -max-query-depth = 15 -max-query-nodes = 500 -max-output-nodes = 100000 -max-query-payload-size = 5000 -max-db-query-cost = 20000 -default-page-size = 5 -max-page-size = 10 -request-timeout-ms = 15000 -max-type-argument-depth = 16 -max-type-argument-width = 32 -max-type-nodes = 256 -max-move-value-depth = 128 - -[background-tasks] -watermark-update-ms=500 -``` - -This will build sui-graphql-rpc and start an IDE: -``` -cargo run --bin sui-graphql-rpc start-server [--rpc-url] [--db-url] [--port] [--host] [--config] -``` - -### Launching the server w/ indexer -For local dev, it might be useful to spin up an indexer as well. Instructions are at [Running standalone indexer](../sui-indexer/README.md#running-standalone-indexer). - -## Compatibility with json-rpc - -`cargo run --bin sui-test-validator -- --with-indexer --pg-port 5432 --pg-db-name sui_indexer_v2 --graphql-host 127.0.0.1 --graphql-port 9125` - -`pnpm --filter @mysten/graphql-transport test:e2e` diff --git a/crates/sui-graphql-rpc/examples/coin_metadata/coin_metadata.graphql b/crates/sui-graphql-rpc/examples/coin_metadata/coin_metadata.graphql deleted file mode 100644 index 03ff1ed5c5c..00000000000 --- a/crates/sui-graphql-rpc/examples/coin_metadata/coin_metadata.graphql +++ /dev/null @@ -1,11 +0,0 @@ -query CoinMetadata { - coinMetadata(coinType: "0x2::sui::SUI") { - decimals - name - symbol - description - iconUrl - supply - hasPublicTransfer - } -} diff --git a/crates/sui-graphql-rpc/examples/name_service/name_service.graphql b/crates/sui-graphql-rpc/examples/name_service/name_service.graphql deleted file mode 100644 index b0a4d0a6f9a..00000000000 --- a/crates/sui-graphql-rpc/examples/name_service/name_service.graphql +++ /dev/null @@ -1,18 +0,0 @@ -{ - resolveSuinsAddress(domain: "example.sui") { - address - } - address( - address: "0x0b86be5d779fac217b41d484b8040ad5145dc9ba0cba099d083c6cbda50d983e" - ) { - address - balance(type: "0x2::sui::SUI") { - coinType { - repr - } - coinObjectCount - totalBalance - } - defaultSuinsName - } -} diff --git a/crates/sui-graphql-rpc/examples/object_connection/filter_on_type.graphql b/crates/sui-graphql-rpc/examples/object_connection/filter_on_type.graphql deleted file mode 100644 index 5d338f134d8..00000000000 --- a/crates/sui-graphql-rpc/examples/object_connection/filter_on_type.graphql +++ /dev/null @@ -1,15 +0,0 @@ -{ - objects(filter: {type: "0x3::staking_pool::StakedSui"}) { - edges { - node { - asMoveObject { - contents { - type { - repr - } - } - } - } - } - } -} diff --git a/crates/sui-graphql-rpc/examples/sui_system_state_summary/sui_system_state_summary.graphql b/crates/sui-graphql-rpc/examples/sui_system_state_summary/sui_system_state_summary.graphql deleted file mode 100644 index c023fc3ca51..00000000000 --- a/crates/sui-graphql-rpc/examples/sui_system_state_summary/sui_system_state_summary.graphql +++ /dev/null @@ -1,37 +0,0 @@ -# Get the latest sui system state data -{ - epoch { - storageFund { - totalObjectStorageRebates - nonRefundableBalance - } - safeMode { - enabled - gasSummary { - computationCost - storageCost - storageRebate - nonRefundableStorageFee - } - } - systemStateVersion - systemParameters { - durationMs - stakeSubsidyStartEpoch - minValidatorCount - maxValidatorCount - minValidatorJoiningStake - validatorLowStakeThreshold - validatorVeryLowStakeThreshold - validatorLowStakeGracePeriod - } - systemStakeSubsidy { - balance - distributionCounter - currentDistributionAmount - periodLength - decreaseRate - - } - } -} diff --git a/crates/sui-graphql-rpc/src/commands.rs b/crates/sui-graphql-rpc/src/commands.rs deleted file mode 100644 index 8eac2903a0d..00000000000 --- a/crates/sui-graphql-rpc/src/commands.rs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::path::PathBuf; - -use clap::*; - -#[derive(Parser)] -#[clap( - name = "sui-graphql-rpc", - about = "Sui GraphQL RPC", - rename_all = "kebab-case", - author, - version -)] -pub enum Command { - GenerateDocsExamples, - GenerateSchema { - /// Path to output GraphQL schema to, in SDL format. - #[clap(short, long)] - file: Option, - }, - GenerateExamples { - /// Path to output examples docs. - #[clap(short, long)] - file: Option, - }, - StartServer { - /// The title to display at the top of the page - #[clap(short, long)] - ide_title: Option, - /// DB URL for data fetching - #[clap(short, long)] - db_url: Option, - /// Port to bind the server to - #[clap(short, long)] - port: Option, - /// Host to bind the server to - #[clap(long)] - host: Option, - /// Port to bind the prom server to - #[clap(long)] - prom_port: Option, - /// Host to bind the prom server to - #[clap(long)] - prom_host: Option, - - /// Path to TOML file containing configuration for service. - #[clap(short, long)] - config: Option, - - /// RPC url to the Node for tx execution - #[clap(long)] - node_rpc_url: Option, - }, -} diff --git a/crates/sui-graphql-rpc/src/config.rs b/crates/sui-graphql-rpc/src/config.rs deleted file mode 100644 index 190dd32e947..00000000000 --- a/crates/sui-graphql-rpc/src/config.rs +++ /dev/null @@ -1,638 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::BTreeSet, fmt::Display, time::Duration}; - -use async_graphql::*; -use fastcrypto_zkp::bn254::zk_login_api::ZkLoginEnv; -use serde::{Deserialize, Serialize}; -use sui_json_rpc::name_service::NameServiceConfig; - -use crate::{functional_group::FunctionalGroup, types::big_int::BigInt}; - -// TODO: calculate proper cost limits - -/// These values are set to support TS SDK shim layer queries for json-rpc -/// compatibility. -const MAX_QUERY_NODES: u32 = 300; -const MAX_QUERY_PAYLOAD_SIZE: u32 = 5_000; - -const MAX_QUERY_DEPTH: u32 = 20; -const MAX_OUTPUT_NODES: u64 = 100_000; // Maximum number of output nodes allowed in the response -const MAX_DB_QUERY_COST: u64 = 20_000; // Max DB query cost (normally f64) truncated -const DEFAULT_PAGE_SIZE: u64 = 20; // Default number of elements allowed on a page of a connection -const MAX_PAGE_SIZE: u64 = 50; // Maximum number of elements allowed on a page of a connection - -/// The following limits reflect the max values set in the ProtocolConfig. -const MAX_TYPE_ARGUMENT_DEPTH: u32 = 16; -const MAX_TYPE_ARGUMENT_WIDTH: u32 = 32; -const MAX_TYPE_NODES: u32 = 256; -const MAX_MOVE_VALUE_DEPTH: u32 = 128; - -pub(crate) const DEFAULT_REQUEST_TIMEOUT_MS: u64 = 40_000; - -const DEFAULT_IDE_TITLE: &str = "Sui GraphQL IDE"; - -pub(crate) const RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD: Duration = Duration::from_millis(10_000); -pub(crate) const MAX_CONCURRENT_REQUESTS: usize = 1_000; - -// Default values for the server connection configuration. -pub(crate) const DEFAULT_SERVER_CONNECTION_PORT: u16 = 8000; -pub(crate) const DEFAULT_SERVER_CONNECTION_HOST: &str = "127.0.0.1"; -pub(crate) const DEFAULT_SERVER_DB_URL: &str = - "postgres://postgres:postgrespw@localhost:5432/sui_indexer"; -pub(crate) const DEFAULT_SERVER_DB_POOL_SIZE: u32 = 3; -pub(crate) const DEFAULT_SERVER_PROM_HOST: &str = "0.0.0.0"; -pub(crate) const DEFAULT_SERVER_PROM_PORT: u16 = 9184; -pub(crate) const DEFAULT_WATERMARK_UPDATE_MS: u64 = 500; - -/// The combination of all configurations for the GraphQL service. -#[derive(Serialize, Clone, Deserialize, Debug, Default)] -pub struct ServerConfig { - #[serde(default)] - pub service: ServiceConfig, - #[serde(default)] - pub connection: ConnectionConfig, - #[serde(default)] - pub internal_features: InternalFeatureConfig, - #[serde(default)] - pub tx_exec_full_node: TxExecFullNodeConfig, - #[serde(default)] - pub ide: Ide, -} - -/// Configuration for connections for the RPC, passed in as command-line -/// arguments. This configures specific connections between this service and -/// other services, and might differ from instance to instance of the GraphQL -/// service. -#[derive(Serialize, Clone, Deserialize, Debug, Eq, PartialEq)] -pub struct ConnectionConfig { - /// Port to bind the server to - pub(crate) port: u16, - /// Host to bind the server to - pub(crate) host: String, - pub(crate) db_url: String, - pub(crate) db_pool_size: u32, - pub(crate) prom_url: String, - pub(crate) prom_port: u16, -} - -/// Configuration on features supported by the GraphQL service, passed in a -/// TOML-based file. These configurations are shared across fleets of the -/// service, i.e. all testnet services will have the same `ServiceConfig`. -#[derive(Serialize, Clone, Deserialize, Debug, Eq, PartialEq, Default)] -#[serde(rename_all = "kebab-case")] -pub struct ServiceConfig { - #[serde(default)] - pub(crate) limits: Limits, - - #[serde(default)] - pub(crate) disabled_features: BTreeSet, - - #[serde(default)] - pub(crate) experiments: Experiments, - - #[serde(default)] - pub(crate) name_service: NameServiceConfig, - - #[serde(default)] - pub(crate) background_tasks: BackgroundTasksConfig, - - #[serde(default)] - pub(crate) zklogin: ZkLoginConfig, -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Copy)] -#[serde(rename_all = "kebab-case")] -pub struct Limits { - #[serde(default)] - pub max_query_depth: u32, - #[serde(default)] - pub max_query_nodes: u32, - #[serde(default)] - pub max_output_nodes: u64, - #[serde(default)] - pub max_query_payload_size: u32, - #[serde(default)] - pub max_db_query_cost: u64, - #[serde(default)] - pub default_page_size: u64, - #[serde(default)] - pub max_page_size: u64, - #[serde(default)] - pub request_timeout_ms: u64, - #[serde(default)] - pub max_type_argument_depth: u32, - #[serde(default)] - pub max_type_argument_width: u32, - #[serde(default)] - pub max_type_nodes: u32, - #[serde(default)] - pub max_move_value_depth: u32, -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Copy)] -#[serde(rename_all = "kebab-case")] -pub struct BackgroundTasksConfig { - #[serde(default)] - pub watermark_update_ms: u64, -} - -/// The Version of the service. `year.month` represents the major release. -/// New `patch` versions represent backwards compatible fixes for their major -/// release. The `full` version is `year.month.patch-sha`. -#[derive(Copy, Clone, Debug)] -pub struct Version { - /// The year of this release. - pub year: &'static str, - /// The month of this release. - pub month: &'static str, - /// The patch is a positive number incremented for every compatible release - /// on top of the major.month release. - pub patch: &'static str, - /// The commit sha for this release. - pub sha: &'static str, - /// The full version string. - /// Note that this extra field is used only for the uptime_metric function - /// which requries a &'static str. - pub full: &'static str, -} - -impl Version { - /// Use for testing when you need the Version obj and a year.month &str - pub fn for_testing() -> Self { - Self { - year: env!("CARGO_PKG_VERSION_MAJOR"), - month: env!("CARGO_PKG_VERSION_MINOR"), - patch: env!("CARGO_PKG_VERSION_PATCH"), - sha: "testing-no-sha", - // note that this full field is needed for metrics but not for testing - full: const_str::concat!( - env!("CARGO_PKG_VERSION_MAJOR"), - ".", - env!("CARGO_PKG_VERSION_MINOR"), - ".", - env!("CARGO_PKG_VERSION_PATCH"), - "-testing-no-sha" - ), - } - } -} - -impl Display for Version { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.full) - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] -#[serde(rename_all = "kebab-case")] -pub struct Ide { - #[serde(default)] - pub(crate) ide_title: String, -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Default)] -#[serde(rename_all = "kebab-case")] -pub struct Experiments { - // Add experimental flags here, to provide access to them through-out the GraphQL - // implementation. - #[cfg(test)] - test_flag: bool, -} - -#[derive(Serialize, Clone, Deserialize, Debug, Eq, PartialEq)] -pub struct InternalFeatureConfig { - #[serde(default)] - pub(crate) query_limits_checker: bool, - #[serde(default)] - pub(crate) feature_gate: bool, - #[serde(default)] - pub(crate) logger: bool, - #[serde(default)] - pub(crate) query_timeout: bool, - #[serde(default)] - pub(crate) metrics: bool, - #[serde(default)] - pub(crate) tracing: bool, - #[serde(default)] - pub(crate) apollo_tracing: bool, - #[serde(default)] - pub(crate) open_telemetry: bool, -} - -#[derive(Serialize, Clone, Deserialize, Debug, Eq, PartialEq, Default)] -pub struct TxExecFullNodeConfig { - #[serde(default)] - pub(crate) node_rpc_url: Option, -} - -#[derive(Serialize, Clone, Deserialize, Debug, Eq, PartialEq, Default)] -#[serde(rename_all = "kebab-case")] -pub struct ZkLoginConfig { - pub env: ZkLoginEnv, -} - -/// The enabled features and service limits configured by the server. -#[Object] -impl ServiceConfig { - /// Check whether `feature` is enabled on this GraphQL service. - async fn is_enabled(&self, feature: FunctionalGroup) -> bool { - !self.disabled_features.contains(&feature) - } - - /// List of all features that are enabled on this GraphQL service. - async fn enabled_features(&self) -> Vec { - FunctionalGroup::all() - .iter() - .filter(|g| !self.disabled_features.contains(g)) - .copied() - .collect() - } - - /// The maximum depth a GraphQL query can be to be accepted by this service. - pub async fn max_query_depth(&self) -> u32 { - self.limits.max_query_depth - } - - /// The maximum number of nodes (field names) the service will accept in a - /// single query. - pub async fn max_query_nodes(&self) -> u32 { - self.limits.max_query_nodes - } - - /// The maximum number of output nodes in a GraphQL response. - /// - /// Non-connection nodes have a count of 1, while connection nodes are - /// counted as the specified 'first' or 'last' number of items, or the - /// default_page_size as set by the server if those arguments are not - /// set. - /// - /// Counts accumulate multiplicatively down the query tree. For example, if - /// a query starts with a connection of first: 10 and has a field to a - /// connection with last: 20, the count at the second level would be 200 - /// nodes. This is then summed to the count of 10 nodes at the first - /// level, for a total of 210 nodes. - pub async fn max_output_nodes(&self) -> u64 { - self.limits.max_output_nodes - } - - /// Maximum estimated cost of a database query used to serve a GraphQL - /// request. This is measured in the same units that the database uses - /// in EXPLAIN queries. - async fn max_db_query_cost(&self) -> BigInt { - BigInt::from(self.limits.max_db_query_cost) - } - - /// Default number of elements allowed on a single page of a connection. - async fn default_page_size(&self) -> u64 { - self.limits.default_page_size - } - - /// Maximum number of elements allowed on a single page of a connection. - async fn max_page_size(&self) -> u64 { - self.limits.max_page_size - } - - /// Maximum time in milliseconds that will be spent to serve one request. - async fn request_timeout_ms(&self) -> u64 { - self.limits.request_timeout_ms - } - - /// Maximum length of a query payload string. - async fn max_query_payload_size(&self) -> u32 { - self.limits.max_query_payload_size - } - - /// Maximum nesting allowed in type arguments in Move Types resolved by this - /// service. - async fn max_type_argument_depth(&self) -> u32 { - self.limits.max_type_argument_depth - } - - /// Maximum number of type arguments passed into a generic instantiation of - /// a Move Type resolved by this service. - async fn max_type_argument_width(&self) -> u32 { - self.limits.max_type_argument_width - } - - /// Maximum number of structs that need to be processed when calculating the - /// layout of a single Move Type. - async fn max_type_nodes(&self) -> u32 { - self.limits.max_type_nodes - } - - /// Maximum nesting allowed in struct fields when calculating the layout of - /// a single Move Type. - async fn max_move_value_depth(&self) -> u32 { - self.limits.max_move_value_depth - } -} - -impl TxExecFullNodeConfig { - pub fn new(node_rpc_url: Option) -> Self { - Self { node_rpc_url } - } -} - -impl ConnectionConfig { - pub fn new( - port: Option, - host: Option, - db_url: Option, - db_pool_size: Option, - prom_url: Option, - prom_port: Option, - ) -> Self { - let default = Self::default(); - Self { - port: port.unwrap_or(default.port), - host: host.unwrap_or(default.host), - db_url: db_url.unwrap_or(default.db_url), - db_pool_size: db_pool_size.unwrap_or(default.db_pool_size), - prom_url: prom_url.unwrap_or(default.prom_url), - prom_port: prom_port.unwrap_or(default.prom_port), - } - } - - pub fn ci_integration_test_cfg() -> Self { - Self { - db_url: DEFAULT_SERVER_DB_URL.to_string(), - ..Default::default() - } - } - - pub fn ci_integration_test_cfg_with_db_name( - db_name: String, - port: u16, - prom_port: u16, - ) -> Self { - Self { - db_url: format!("postgres://postgres:postgrespw@localhost:5432/{}", db_name), - port, - prom_port, - ..Default::default() - } - } - - pub fn db_name(&self) -> String { - self.db_url.split('/').last().unwrap().to_string() - } - - pub fn db_url(&self) -> String { - self.db_url.clone() - } - - pub fn db_pool_size(&self) -> u32 { - self.db_pool_size - } - - pub fn server_address(&self) -> String { - format!("{}:{}", self.host, self.port) - } -} - -impl ServiceConfig { - pub fn read(contents: &str) -> Result { - toml::de::from_str::(contents) - } - - pub fn test_defaults() -> Self { - Self { - background_tasks: BackgroundTasksConfig::test_defaults(), - zklogin: ZkLoginConfig { - env: ZkLoginEnv::Test, - }, - ..Default::default() - } - } -} - -impl Limits { - /// Extract limits for the package resolver. - pub fn package_resolver_limits(&self) -> sui_package_resolver::Limits { - sui_package_resolver::Limits { - max_type_argument_depth: self.max_type_argument_depth as usize, - max_type_argument_width: self.max_type_argument_width as usize, - max_type_nodes: self.max_type_nodes as usize, - max_move_value_depth: self.max_move_value_depth as usize, - } - } -} - -impl Ide { - pub fn new(ide_title: Option) -> Self { - Self { - ide_title: ide_title.unwrap_or_else(|| DEFAULT_IDE_TITLE.to_string()), - } - } -} - -impl BackgroundTasksConfig { - pub fn test_defaults() -> Self { - Self { - watermark_update_ms: 100, // Set to 100ms for testing - } - } -} - -impl Default for Ide { - fn default() -> Self { - Self { - ide_title: DEFAULT_IDE_TITLE.to_string(), - } - } -} - -impl Default for ConnectionConfig { - fn default() -> Self { - Self { - port: DEFAULT_SERVER_CONNECTION_PORT, - host: DEFAULT_SERVER_CONNECTION_HOST.to_string(), - db_url: DEFAULT_SERVER_DB_URL.to_string(), - db_pool_size: DEFAULT_SERVER_DB_POOL_SIZE, - prom_url: DEFAULT_SERVER_PROM_HOST.to_string(), - prom_port: DEFAULT_SERVER_PROM_PORT, - } - } -} - -impl Default for Limits { - fn default() -> Self { - Self { - max_query_depth: MAX_QUERY_DEPTH, - max_query_nodes: MAX_QUERY_NODES, - max_output_nodes: MAX_OUTPUT_NODES, - max_query_payload_size: MAX_QUERY_PAYLOAD_SIZE, - max_db_query_cost: MAX_DB_QUERY_COST, - default_page_size: DEFAULT_PAGE_SIZE, - max_page_size: MAX_PAGE_SIZE, - request_timeout_ms: DEFAULT_REQUEST_TIMEOUT_MS, - max_type_argument_depth: MAX_TYPE_ARGUMENT_DEPTH, - max_type_argument_width: MAX_TYPE_ARGUMENT_WIDTH, - max_type_nodes: MAX_TYPE_NODES, - max_move_value_depth: MAX_MOVE_VALUE_DEPTH, - } - } -} - -impl Default for InternalFeatureConfig { - fn default() -> Self { - Self { - query_limits_checker: true, - feature_gate: true, - logger: true, - query_timeout: true, - metrics: true, - tracing: false, - apollo_tracing: false, - open_telemetry: false, - } - } -} - -impl Default for BackgroundTasksConfig { - fn default() -> Self { - Self { - watermark_update_ms: DEFAULT_WATERMARK_UPDATE_MS, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_read_empty_service_config() { - let actual = ServiceConfig::read("").unwrap(); - let expect = ServiceConfig::default(); - assert_eq!(actual, expect); - } - - #[test] - fn test_read_limits_in_service_config() { - let actual = ServiceConfig::read( - r#" [limits] - max-query-depth = 100 - max-query-nodes = 300 - max-output-nodes = 200000 - max-query-payload-size = 2000 - max-db-query-cost = 50 - default-page-size = 20 - max-page-size = 50 - request-timeout-ms = 27000 - max-type-argument-depth = 32 - max-type-argument-width = 64 - max-type-nodes = 128 - max-move-value-depth = 256 - "#, - ) - .unwrap(); - - let expect = ServiceConfig { - limits: Limits { - max_query_depth: 100, - max_query_nodes: 300, - max_output_nodes: 200000, - max_query_payload_size: 2000, - max_db_query_cost: 50, - default_page_size: 20, - max_page_size: 50, - request_timeout_ms: 27_000, - max_type_argument_depth: 32, - max_type_argument_width: 64, - max_type_nodes: 128, - max_move_value_depth: 256, - }, - ..Default::default() - }; - - assert_eq!(actual, expect) - } - - #[test] - fn test_read_enabled_features_in_service_config() { - let actual = ServiceConfig::read( - r#" disabled-features = [ - "coins", - "name-service", - ] - "#, - ) - .unwrap(); - - use FunctionalGroup as G; - let expect = ServiceConfig { - disabled_features: BTreeSet::from([G::Coins, G::NameService]), - ..Default::default() - }; - - assert_eq!(actual, expect) - } - - #[test] - fn test_read_experiments_in_service_config() { - let actual = ServiceConfig::read( - r#" [experiments] - test-flag = true - "#, - ) - .unwrap(); - - let expect = ServiceConfig { - experiments: Experiments { test_flag: true }, - ..Default::default() - }; - - assert_eq!(actual, expect) - } - - #[test] - fn test_read_everything_in_service_config() { - let actual = ServiceConfig::read( - r#" disabled-features = ["analytics"] - - [limits] - max-query-depth = 42 - max-query-nodes = 320 - max-output-nodes = 200000 - max-query-payload-size = 200 - max-db-query-cost = 20 - default-page-size = 10 - max-page-size = 20 - request-timeout-ms = 30000 - max-type-argument-depth = 32 - max-type-argument-width = 64 - max-type-nodes = 128 - max-move-value-depth = 256 - - [experiments] - test-flag = true - "#, - ) - .unwrap(); - - let expect = ServiceConfig { - limits: Limits { - max_query_depth: 42, - max_query_nodes: 320, - max_output_nodes: 200000, - max_query_payload_size: 200, - max_db_query_cost: 20, - default_page_size: 10, - max_page_size: 20, - request_timeout_ms: 30_000, - max_type_argument_depth: 32, - max_type_argument_width: 64, - max_type_nodes: 128, - max_move_value_depth: 256, - }, - disabled_features: BTreeSet::from([FunctionalGroup::Analytics]), - experiments: Experiments { test_flag: true }, - ..Default::default() - }; - - assert_eq!(actual, expect); - } -} diff --git a/crates/sui-graphql-rpc/src/context_data/db_data_provider.rs b/crates/sui-graphql-rpc/src/context_data/db_data_provider.rs deleted file mode 100644 index 258a2ffa6a8..00000000000 --- a/crates/sui-graphql-rpc/src/context_data/db_data_provider.rs +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::BTreeMap, time::Duration}; - -use sui_indexer::{ - apis::GovernanceReadApi, db::PgConnectionPoolConfig, indexer_reader::IndexerReader, -}; -use sui_json_rpc_types::Stake as RpcStakedSui; -use sui_types::{ - base_types::SuiAddress as NativeSuiAddress, - governance::StakedSui as NativeStakedSui, - sui_system_state::sui_system_state_summary::{ - SuiSystemStateSummary as NativeSuiSystemStateSummary, SuiValidatorSummary, - }, -}; - -use crate::{ - config::{DEFAULT_REQUEST_TIMEOUT_MS, DEFAULT_SERVER_DB_POOL_SIZE}, - error::Error, - types::{address::Address, sui_address::SuiAddress, validator::Validator}, -}; - -pub(crate) struct PgManager { - pub inner: IndexerReader, -} - -impl PgManager { - pub(crate) fn new(inner: IndexerReader) -> Self { - Self { inner } - } - - /// Create a new underlying reader, which is used by this type as well as - /// other data providers. - pub(crate) fn reader(db_url: impl Into) -> Result { - Self::reader_with_config( - db_url, - DEFAULT_SERVER_DB_POOL_SIZE, - DEFAULT_REQUEST_TIMEOUT_MS, - ) - } - - pub(crate) fn reader_with_config( - db_url: impl Into, - pool_size: u32, - timeout_ms: u64, - ) -> Result { - let mut config = PgConnectionPoolConfig::default(); - config.set_pool_size(pool_size); - config.set_statement_timeout(Duration::from_millis(timeout_ms)); - IndexerReader::new_with_config(db_url, config) - .map_err(|e| Error::Internal(format!("Failed to create reader: {e}"))) - } -} - -/// Implement methods to be used by graphql resolvers -impl PgManager { - /// Retrieve the validator APYs - pub(crate) async fn fetch_validator_apys( - &self, - address: &NativeSuiAddress, - ) -> Result, Error> { - let governance_api = GovernanceReadApi::new(self.inner.clone()); - - governance_api - .get_validator_apy(address) - .await - .map_err(|e| Error::Internal(format!("{e}"))) - } - - /// If no epoch was requested or if the epoch requested is in progress, - /// returns the latest sui system state. - pub(crate) async fn fetch_sui_system_state( - &self, - epoch_id: Option, - ) -> Result { - let latest_sui_system_state = self - .inner - .spawn_blocking(move |this| this.get_latest_sui_system_state()) - .await?; - - if epoch_id.is_some_and(|id| id == latest_sui_system_state.epoch) { - Ok(latest_sui_system_state) - } else { - Ok(self - .inner - .spawn_blocking(move |this| this.get_epoch_sui_system_state(epoch_id)) - .await?) - } - } - - /// Make a request to the RPC for its representations of the staked sui we - /// parsed out of the object. Used to implement fields that are - /// implemented in JSON-RPC but not GraphQL (yet). - pub(crate) async fn fetch_rpc_staked_sui( - &self, - stake: NativeStakedSui, - ) -> Result { - let governance_api = GovernanceReadApi::new(self.inner.clone()); - - let mut delegated_stakes = governance_api - .get_delegated_stakes(vec![stake]) - .await - .map_err(|e| Error::Internal(format!("Error fetching delegated stake. {e}")))?; - - let Some(mut delegated_stake) = delegated_stakes.pop() else { - return Err(Error::Internal( - "Error fetching delegated stake. No pools returned.".to_string(), - )); - }; - - let Some(stake) = delegated_stake.stakes.pop() else { - return Err(Error::Internal( - "Error fetching delegated stake. No stake in pool.".to_string(), - )); - }; - - Ok(stake) - } -} - -/// `checkpoint_viewed_at` represents the checkpoint sequence number at which -/// the set of `SuiValidatorSummary` was queried for. Each `Validator` will -/// inherit this checkpoint, so that when viewing the `Validator`'s state, it -/// will be as if it was read at the same checkpoint. -pub(crate) fn convert_to_validators( - validators: Vec, - system_state: Option, - checkpoint_viewed_at: u64, -) -> Vec { - let (at_risk, reports) = if let Some(NativeSuiSystemStateSummary { - at_risk_validators, - validator_report_records, - .. - }) = system_state - { - ( - BTreeMap::from_iter(at_risk_validators), - BTreeMap::from_iter(validator_report_records), - ) - } else { - Default::default() - }; - - validators - .into_iter() - .map(|validator_summary| { - let at_risk = at_risk.get(&validator_summary.sui_address).copied(); - let report_records = reports.get(&validator_summary.sui_address).map(|addrs| { - addrs - .iter() - .cloned() - .map(|a| Address { - address: SuiAddress::from(a), - checkpoint_viewed_at: Some(checkpoint_viewed_at), - }) - .collect() - }); - - Validator { - validator_summary, - at_risk, - report_records, - checkpoint_viewed_at, - } - }) - .collect() -} diff --git a/crates/sui-graphql-rpc/src/context_data/mod.rs b/crates/sui-graphql-rpc/src/context_data/mod.rs deleted file mode 100644 index 03076719288..00000000000 --- a/crates/sui-graphql-rpc/src/context_data/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub(crate) mod db_data_provider; -pub(crate) mod package_cache; diff --git a/crates/sui-graphql-rpc/src/error.rs b/crates/sui-graphql-rpc/src/error.rs deleted file mode 100644 index a4166d2b7b6..00000000000 --- a/crates/sui-graphql-rpc/src/error.rs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_graphql::{ErrorExtensionValues, ErrorExtensions, Pos, Response, ServerError}; -use async_graphql_axum::GraphQLResponse; -use sui_indexer::errors::IndexerError; -use sui_json_rpc::name_service::NameServiceError; - -/// Error codes for the `extensions.code` field of a GraphQL error that -/// originates from outside GraphQL. -/// `` -pub(crate) mod code { - pub const BAD_REQUEST: &str = "BAD_REQUEST"; - pub const BAD_USER_INPUT: &str = "BAD_USER_INPUT"; - pub const INTERNAL_SERVER_ERROR: &str = "INTERNAL_SERVER_ERROR"; - pub const REQUEST_TIMEOUT: &str = "REQUEST_TIMEOUT"; - pub const UNKNOWN: &str = "UNKNOWN"; -} - -/// Create a GraphQL Response containing an Error. -/// -/// Most errors produced by the service will automatically be wrapped in a -/// `GraphQLResponse`, because they will originate from within the GraphQL -/// implementation. This function is intended for errors that originated from -/// outside of GraphQL (such as in middleware), but that need to be ingested by -/// GraphQL clients. -pub(crate) fn graphql_error_response(code: &str, message: impl Into) -> GraphQLResponse { - let error = graphql_error(code, message); - Response::from_errors(error.into()).into() -} - -/// Create a generic GraphQL Server Error. -/// -/// This error has no path, source, or locations, just a message and an error -/// code. -pub(crate) fn graphql_error(code: &str, message: impl Into) -> ServerError { - let mut ext = ErrorExtensionValues::default(); - ext.set("code", code); - - ServerError { - message: message.into(), - source: None, - locations: vec![], - path: vec![], - extensions: Some(ext), - } -} - -pub(crate) fn graphql_error_at_pos( - code: &str, - message: impl Into, - pos: Pos, -) -> ServerError { - let mut ext = ErrorExtensionValues::default(); - ext.set("code", code); - - ServerError { - message: message.into(), - source: None, - locations: vec![pos], - path: vec![], - extensions: Some(ext), - } -} - -#[derive(Clone, Debug, thiserror::Error)] -pub enum Error { - #[error("Unsupported protocol version requested. Min supported: {0}, max supported: {1}")] - ProtocolVersionUnsupported(u64, u64), - #[error(transparent)] - NameService(#[from] NameServiceError), - #[error("'first' and 'last' must not be used together")] - CursorNoFirstLast, - #[error("Connection's page size of {0} exceeds max of {1}")] - PageTooLarge(u64, u64), - // Catch-all for client-fault errors - #[error("{0}")] - Client(String), - #[error("Internal error occurred while processing request: {0}")] - Internal(String), -} - -impl ErrorExtensions for Error { - fn extend(&self) -> async_graphql::Error { - async_graphql::Error::new(format!("{}", self)).extend_with(|_err, e| match self { - Error::NameService(_) - | Error::CursorNoFirstLast - | Error::PageTooLarge(_, _) - | Error::ProtocolVersionUnsupported(_, _) - | Error::Client(_) => { - e.set("code", code::BAD_USER_INPUT); - } - Error::Internal(_) => { - e.set("code", code::INTERNAL_SERVER_ERROR); - } - }) - } -} - -impl From for Error { - fn from(e: IndexerError) -> Self { - Error::Internal(e.to_string()) - } -} diff --git a/crates/sui-graphql-rpc/src/examples.rs b/crates/sui-graphql-rpc/src/examples.rs deleted file mode 100644 index e33b8babd9d..00000000000 --- a/crates/sui-graphql-rpc/src/examples.rs +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - io::{BufWriter, Read}, - path::PathBuf, -}; - -use anyhow::anyhow; -use markdown_gen::markdown::{AsMarkdown, Markdown}; - -#[derive(Debug)] -pub struct ExampleQuery { - pub name: String, - pub contents: String, - pub path: PathBuf, -} - -#[derive(Debug)] -pub struct ExampleQueryGroup { - pub name: String, - pub queries: Vec, - pub _path: PathBuf, -} - -const QUERY_EXT: &str = "graphql"; - -fn regularize_string(s: &str) -> String { - // Replace underscore with space and make every word first letter uppercase - s.replace('_', " ") - .split_whitespace() - .map(|word| { - let mut chars = word.chars(); - match chars.next() { - None => String::new(), - Some(f) => f.to_uppercase().chain(chars).collect(), - } - }) - .collect::>() - .join(" ") -} - -pub fn load_examples() -> anyhow::Result> { - let mut buf: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - buf.push("examples"); - - let mut groups = vec![]; - for entry in std::fs::read_dir(buf).map_err(|e| anyhow::anyhow!(e))? { - let entry = entry.map_err(|e| anyhow::anyhow!(e))?; - let path = entry.path(); - let group_name = path - .file_stem() - .ok_or(anyhow::anyhow!("File stem cannot be read"))? - .to_str() - .ok_or(anyhow::anyhow!("File stem cannot be read"))? - .to_string(); - - let mut group = ExampleQueryGroup { - name: group_name.clone(), - queries: vec![], - _path: path.clone(), - }; - - for file in std::fs::read_dir(path).map_err(|e| anyhow::anyhow!(e))? { - assert!(file.is_ok()); - let file = file.map_err(|e| anyhow::anyhow!(e))?; - assert!(file.path().extension().is_some()); - let ext = file - .path() - .extension() - .ok_or(anyhow!("File extension cannot be read"))? - .to_str() - .ok_or(anyhow!("File extension cannot be read to string"))? - .to_string(); - assert_eq!(ext, QUERY_EXT, "wrong file extension for example"); - - let file_path = file.path(); - let query_name = file_path - .file_stem() - .ok_or(anyhow!("File stem cannot be read"))? - .to_str() - .ok_or(anyhow!("File extension cannot be read to string"))? - .to_string(); - - let mut contents = String::new(); - let mut fp = std::fs::File::open(file_path.clone()).map_err(|e| anyhow!(e))?; - fp.read_to_string(&mut contents).map_err(|e| anyhow!(e))?; - group.queries.push(ExampleQuery { - name: query_name, - contents, - path: file_path, - }); - } - group.queries.sort_by(|x, y| x.name.cmp(&y.name)); - - groups.push(group); - } - - groups.sort_by(|x, y| x.name.cmp(&y.name)); - Ok(groups) -} - -/// This generates a markdown page with all the examples, to be used in the docs -/// site -pub fn generate_examples_for_docs() -> anyhow::Result { - let groups = load_examples()?; - - let mut output = BufWriter::new(Vec::new()); - let mut md = Markdown::new(&mut output); - md.write( - r#"--- -title: Examples -description: Query examples for working with the Sui GraphQL RPC. ---- -"#, - )?; - md.write("This page showcases a number of queries to interact with the network. These examples can also be found in the [repository](https://github.com/MystenLabs/sui/tree/main/crates/sui-graphql-rpc/examples). You can use the [interactive online IDE](https://mainnet.sui.io/rpc/graphql) to run these examples.")?; - for group in groups.iter() { - let group_name = regularize_string(&group.name); - md.write(group_name.heading(2)) - .map_err(|e| anyhow::anyhow!(e))?; - for query in group.queries.iter() { - let name = regularize_string(&query.name); - md.write(name.heading(3)).map_err(|e| anyhow::anyhow!(e))?; - let query = query.contents.lines().collect::>().join("\n"); - let content = format!("```graphql\n{}\n```", query); - md.write(content.as_str()).map_err(|e| anyhow::anyhow!(e))?; - } - } - let bytes = output.into_inner().map_err(|e| anyhow::anyhow!(e))?; - Ok(String::from_utf8(bytes) - .map_err(|e| anyhow::anyhow!(e))? - .replace('\\', "")) -} - -pub fn generate_markdown() -> anyhow::Result { - let groups = load_examples()?; - - let mut output = BufWriter::new(Vec::new()); - let mut md = Markdown::new(&mut output); - - md.write("Sui GraphQL Examples".heading(1)) - .map_err(|e| anyhow!(e))?; - - // TODO: reduce multiple loops - // Generate the table of contents - for (id, group) in groups.iter().enumerate() { - let group_name = regularize_string(&group.name); - let group_name_toc = format!("[{}](#{})", group_name, id); - md.write(group_name_toc.heading(3)) - .map_err(|e| anyhow!(e))?; - - for (inner, query) in group.queries.iter().enumerate() { - let inner_id = inner + 0xFFFF * id; - let inner_name = regularize_string(&query.name); - let inner_name_toc = format!("  [{}](#{})", inner_name, inner_id); - md.write(inner_name_toc.heading(4)) - .map_err(|e| anyhow!(e))?; - } - } - - for (id, group) in groups.iter().enumerate() { - let group_name = regularize_string(&group.name); - - let id_tag = format!("", id); - md.write(id_tag.heading(2)) - .map_err(|e| anyhow::anyhow!(e))?; - md.write(group_name.heading(2)) - .map_err(|e| anyhow::anyhow!(e))?; - for (inner, query) in group.queries.iter().enumerate() { - let inner_id = inner + 0xFFFF * id; - let name = regularize_string(&query.name); - - let id_tag = format!("", inner_id); - md.write(id_tag.heading(3)) - .map_err(|e| anyhow::anyhow!(e))?; - md.write(name.heading(3)).map_err(|e| anyhow::anyhow!(e))?; - - // Extract all lines that start with `#` and use them as headers - let mut headers = vec![]; - let mut query_start = 0; - for (idx, line) in query.contents.lines().enumerate() { - let line = line.trim(); - if line.starts_with('#') { - headers.push(line.trim_start_matches('#')); - } else if line.starts_with('{') { - query_start = idx; - break; - } - } - - // Remove headers from query - let query = query - .contents - .lines() - .skip(query_start) - .collect::>() - .join("\n"); - - let content = format!("
    {}
    ", query); - for header in headers { - md.write(header.heading(4)) - .map_err(|e| anyhow::anyhow!(e))?; - } - md.write(content.quote()).map_err(|e| anyhow::anyhow!(e))?; - } - } - let bytes = output.into_inner().map_err(|e| anyhow::anyhow!(e))?; - Ok(String::from_utf8(bytes) - .map_err(|e| anyhow::anyhow!(e))? - .replace('\\', "")) -} - -#[test] -fn test_generate_markdown() { - use std::fs::File; - - use similar::*; - - let mut buf: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - buf.push("docs"); - buf.push("examples.md"); - let mut out_file: File = File::open(buf).expect("Could not open examples.md"); - - // Read the current content of `out_file` - let mut current_content = String::new(); - out_file - .read_to_string(&mut current_content) - .expect("Could not read examples.md"); - let new_content: String = generate_markdown().expect("Generating examples markdown failed"); - - if current_content != new_content { - let mut res = vec![]; - let diff = TextDiff::from_lines(¤t_content, &new_content); - for change in diff.iter_all_changes() { - let sign = match change.tag() { - ChangeTag::Delete => "---", - ChangeTag::Insert => "+++", - ChangeTag::Equal => " ", - }; - res.push(format!("{}{}", sign, change)); - } - panic!( - "Doc examples have changed. Please run `sui-graphql-rpc generate-examples` to update the docs. Diff: {}", - res.join("") - ); - } -} diff --git a/crates/sui-graphql-rpc/src/extensions/logger.rs b/crates/sui-graphql-rpc/src/extensions/logger.rs deleted file mode 100644 index 6105a64cc54..00000000000 --- a/crates/sui-graphql-rpc/src/extensions/logger.rs +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{fmt::Write, net::SocketAddr, sync::Arc}; - -use async_graphql::{ - extensions::{ - Extension, ExtensionContext, ExtensionFactory, NextExecute, NextParseQuery, NextResolve, - NextValidation, ResolveInfo, - }, - parser::types::{ExecutableDocument, OperationType, Selection}, - PathSegment, Response, ServerError, ServerResult, ValidationResult, Variables, -}; -use async_graphql_value::ConstValue; -use tracing::{debug, error, info, warn}; -use uuid::Uuid; - -use crate::{error::code, metrics::Metrics}; - -#[derive(Clone, Debug)] -pub struct LoggerConfig { - pub log_request_query: bool, - pub log_response: bool, - pub log_complexity: bool, -} - -impl Default for LoggerConfig { - fn default() -> Self { - Self { - log_request_query: false, - log_response: true, - log_complexity: true, - } - } -} - -#[derive(Clone, Debug, Default)] -pub struct Logger { - config: LoggerConfig, -} - -impl ExtensionFactory for Logger { - fn create(&self) -> Arc { - Arc::new(LoggerExtension { - config: self.config.clone(), - }) - } -} - -struct LoggerExtension { - config: LoggerConfig, -} - -#[async_trait::async_trait] -impl Extension for LoggerExtension { - // This hook is used to get the top level node name for recording in the metrics - // which top level nodes are being called. - async fn resolve( - &self, - ctx: &ExtensionContext<'_>, - info: ResolveInfo<'_>, - next: NextResolve<'_>, - ) -> ServerResult> { - if info.path_node.parent.is_none() { - ctx.data_unchecked::() - .request_metrics - .num_queries_top_level - .with_label_values(&[info.name]) - .inc(); - } - next.run(ctx, info).await - } - - async fn parse_query( - &self, - ctx: &ExtensionContext<'_>, - query: &str, - variables: &Variables, - next: NextParseQuery<'_>, - ) -> ServerResult { - let document = next.run(ctx, query, variables).await?; - let is_schema = document - .operations - .iter() - .filter(|(_, operation)| operation.node.ty == OperationType::Query) - .any(|(_, operation)| operation.node.selection_set.node.items.iter().any(|selection| matches!(&selection.node, Selection::Field(field) if field.node.name.node == "__schema"))); - let query_id: &Uuid = ctx.data_unchecked(); - let session_id: &SocketAddr = ctx.data_unchecked(); - if !is_schema && self.config.log_request_query { - info!( - %query_id, - %session_id, - "[Query] {}", - ctx.stringify_execute_doc(&document, variables) - ); - } - Ok(document) - } - - async fn validation( - &self, - ctx: &ExtensionContext<'_>, - next: NextValidation<'_>, - ) -> Result> { - let res = next.run(ctx).await?; - let query_id: &Uuid = ctx.data_unchecked(); - let session_id: &SocketAddr = ctx.data_unchecked(); - if self.config.log_complexity { - info!( - %query_id, - %session_id, - complexity = res.complexity, - depth = res.depth, - "[Validation]", - ); - } - Ok(res) - } - - async fn execute( - &self, - ctx: &ExtensionContext<'_>, - operation_name: Option<&str>, - next: NextExecute<'_>, - ) -> Response { - let resp = next.run(ctx, operation_name).await; - let query_id: &Uuid = ctx.data_unchecked(); - let session_id: &SocketAddr = ctx.data_unchecked(); - if resp.is_err() { - for err in &resp.errors { - let error_code = &err.extensions.as_ref().and_then(|x| x.get("code")); - if !err.path.is_empty() { - let mut path = String::new(); - for (idx, s) in err.path.iter().enumerate() { - if idx > 0 { - path.push('.'); - } - match s { - PathSegment::Index(idx) => { - let _ = write!(&mut path, "{}", idx); - } - PathSegment::Field(name) => { - let _ = write!(&mut path, "{}", name); - } - } - } - - if let Some(async_graphql_value::ConstValue::String(error_code)) = error_code { - if error_code.as_str() == code::INTERNAL_SERVER_ERROR { - error!( - %query_id, - %session_id, - error_code, - "[Response] path={} message={}", - path, - err.message, - ); - } else { - info!( - %query_id, - %session_id, - error_code, - "[Response] path={} message={}", - path, - err.message, - ); - } - } else { - warn!( - %query_id, - %session_id, - error_code = code::UNKNOWN, - "[Response] path={} message={}", - path, - err.message, - ); - } - } else { - let error_code = if let Some(error_code) = error_code { - error_code.to_string() - } else { - code::UNKNOWN.to_string() - }; - info!( - %query_id, - %session_id, - error_code, - "[Response] message={}", err.message - ) - } - } - } else if self.config.log_response { - match operation_name { - Some("IntrospectionQuery") => { - debug!( - %query_id, - %session_id, - "[Schema] {}", resp.data - ); - } - _ => info!( - %query_id, - %session_id, - "[Response] {}", resp.data - ), - } - } - resp - } -} diff --git a/crates/sui-graphql-rpc/src/extensions/mod.rs b/crates/sui-graphql-rpc/src/extensions/mod.rs deleted file mode 100644 index 9c282b5ae95..00000000000 --- a/crates/sui-graphql-rpc/src/extensions/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub(crate) mod feature_gate; -pub(crate) mod logger; -pub mod query_limits_checker; -pub(crate) mod timeout; diff --git a/crates/sui-graphql-rpc/src/lib.rs b/crates/sui-graphql-rpc/src/lib.rs deleted file mode 100644 index baea0d2ce2c..00000000000 --- a/crates/sui-graphql-rpc/src/lib.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub use sui_graphql_rpc_client as client; -pub mod commands; -pub mod config; -pub(crate) mod consistency; -pub mod context_data; -pub(crate) mod data; -mod error; -pub mod examples; -pub mod extensions; -pub(crate) mod functional_group; -mod metrics; -mod mutation; -pub(crate) mod raw_query; -pub mod server; -pub mod test_infra; -mod types; diff --git a/crates/sui-graphql-rpc/src/main.rs b/crates/sui-graphql-rpc/src/main.rs deleted file mode 100644 index 9f5b415f61f..00000000000 --- a/crates/sui-graphql-rpc/src/main.rs +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{fs, path::PathBuf}; - -use clap::Parser; -use sui_graphql_rpc::{ - commands::Command, - config::{ConnectionConfig, Ide, ServerConfig, ServiceConfig, TxExecFullNodeConfig, Version}, - server::{builder::export_schema, graphiql_server::start_graphiql_server}, -}; -use tokio_util::{sync::CancellationToken, task::TaskTracker}; - -// WARNING!!! -// -// Do not move or use similar logic to generate git revision information outside -// of a binary entry point (e.g. main.rs). Placing the below logic into a -// library can result in unnecessary builds. -const GIT_REVISION: &str = { - if let Some(revision) = option_env!("GIT_REVISION") { - revision - } else { - git_version::git_version!( - args = ["--always", "--abbrev=40", "--dirty", "--exclude", "*"], - fallback = "DIRTY" - ) - } -}; - -// VERSION mimics what other sui binaries use for the same const -static VERSION: Version = Version { - year: env!("CARGO_PKG_VERSION_MAJOR"), - month: env!("CARGO_PKG_VERSION_MINOR"), - patch: env!("CARGO_PKG_VERSION_PATCH"), - sha: GIT_REVISION, - full: const_str::concat!( - env!("CARGO_PKG_VERSION_MAJOR"), - ".", - env!("CARGO_PKG_VERSION_MINOR"), - ".", - env!("CARGO_PKG_VERSION_PATCH"), - "-", - GIT_REVISION - ), -}; - -#[tokio::main] -async fn main() { - let cmd: Command = Command::parse(); - match cmd { - Command::GenerateDocsExamples => { - let mut buf: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - // we are looking to put examples content in - // sui/docs/content/references/sui-graphql/examples.mdx - let filename = "docs/content/references/sui-graphql/examples.mdx"; - buf.pop(); - buf.pop(); - buf.push(filename); - let content = sui_graphql_rpc::examples::generate_examples_for_docs() - .expect("Generating examples markdown file for docs failed"); - std::fs::write(buf, content).expect("Writing examples markdown failed"); - println!("Generated the docs example.mdx file and copied it to {filename}."); - } - Command::GenerateSchema { file } => { - let out = export_schema(); - if let Some(file) = file { - println!("Write schema to file: {:?}", file); - std::fs::write(file, &out).unwrap(); - } else { - println!("{}", &out); - } - } - Command::GenerateExamples { file } => { - let new_content: String = sui_graphql_rpc::examples::generate_markdown() - .expect("Generating examples markdown failed"); - let mut buf: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - buf.push("docs"); - buf.push("examples.md"); - let file = file.unwrap_or(buf); - - std::fs::write(file.clone(), new_content).expect("Writing examples markdown failed"); - println!("Written examples to file: {:?}", file); - } - Command::StartServer { - ide_title, - db_url, - port, - host, - config, - node_rpc_url, - prom_host, - prom_port, - } => { - let connection = ConnectionConfig::new(port, host, db_url, None, prom_host, prom_port); - let service_config = service_config(config); - let _guard = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .init(); - let tracker = TaskTracker::new(); - let cancellation_token = CancellationToken::new(); - - println!("Starting server..."); - let server_config = ServerConfig { - connection, - service: service_config, - ide: Ide::new(ide_title), - tx_exec_full_node: TxExecFullNodeConfig::new(node_rpc_url), - ..ServerConfig::default() - }; - - let cancellation_token_clone = cancellation_token.clone(); - let graphql_service_handle = tracker.spawn(async move { - start_graphiql_server(&server_config, &VERSION, cancellation_token_clone) - .await - .unwrap(); - }); - - // Wait for shutdown signal - tokio::select! { - result = graphql_service_handle => { - if let Err(e) = result { - println!("GraphQL service crashed or exited with error: {:?}", e); - } - } - _ = tokio::signal::ctrl_c() => { - println!("Ctrl+C signal received."); - }, - } - - println!("Shutting down..."); - - // Send shutdown signal to application - cancellation_token.cancel(); - tracker.close(); - tracker.wait().await; - } - } -} - -fn service_config(path: Option) -> ServiceConfig { - let Some(path) = path else { - return ServiceConfig::default(); - }; - - let contents = fs::read_to_string(path).expect("Reading configuration"); - ServiceConfig::read(&contents).expect("Deserializing configuration") -} diff --git a/crates/sui-graphql-rpc/src/metrics.rs b/crates/sui-graphql-rpc/src/metrics.rs deleted file mode 100644 index 86ca3c8a814..00000000000 --- a/crates/sui-graphql-rpc/src/metrics.rs +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{sync::Arc, time::Duration}; - -use async_graphql::{PathSegment, ServerError}; -use prometheus::{ - register_gauge_with_registry, register_histogram_vec_with_registry, - register_histogram_with_registry, register_int_counter_vec_with_registry, - register_int_counter_with_registry, Gauge, Histogram, HistogramVec, IntCounter, IntCounterVec, - Registry, -}; - -use crate::error::code; - -// TODO: finetune buckets as we learn more about the distribution of queries -const LATENCY_SEC_BUCKETS: &[f64] = &[ - 0.001, 0.005, 0.01, 0.05, 0.1, 0.25, 0.5, 1., 2.5, 5., 10., 20., 30., 60., 90., -]; -const DB_LATENCY_SEC_BUCKETS: &[f64] = &[ - 0.001, 0.005, 0.01, 0.02, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 2.0, 3.0, - 5.0, 10.0, 20.0, 40.0, 60.0, 80.0, 100.0, 200.0, -]; -const INPUT_NODES_BUCKETS: &[f64] = &[ - 1., 2., 4., 8., 12., 16., 24., 32., 48., 64., 96., 128., 256., 512., 1024., -]; -const OUTPUT_NODES_BUCKETS: &[f64] = &[ - 100., 200., 400., 800., 1200., 1600., 2400., 3200., 4800., 6400., 9600., 12800., 25600., - 51200., 102400., -]; -const QUERY_DEPTH_BUCKETS: &[f64] = &[ - 1., 2., 4., 8., 12., 16., 24., 32., 48., 64., 96., 128., 256., 512., 1024., -]; -const QUERY_PAYLOAD_SIZE_BUCKETS: &[f64] = &[ - 10., 20., 50., 100., 200., 400., 800., 1200., 1600., 2400., 3200., 4800., 6400., 9600., 12800., - 25600., 51200., 102400., -]; -const DB_QUERY_COST_BUCKETS: &[f64] = &[ - 1., 2., 4., 8., 12., 16., 24., 32., 48., 64., 96., 128., 256., 512., 1024., -]; - -#[derive(Clone)] -pub(crate) struct Metrics { - pub db_metrics: Arc, - pub request_metrics: Arc, -} - -#[derive(Clone)] -pub(crate) struct DBMetrics { - /// The number of fetches grouped by result (success or error) - pub db_fetches: IntCounterVec, - /// The fetch latency grouped by result (success or error) - pub db_fetch_latency: HistogramVec, - // TODO make this work, blocked by pg.rs (unclear if to use log function or smth else) - pub _db_query_cost: Histogram, - // TODO determine if we want this metric, and implement it - pub _db_fetch_batch_size: HistogramVec, -} - -#[derive(Clone)] -pub(crate) struct RequestMetrics { - /// The number of nodes for the input query that passed the query limits - /// check - pub input_nodes: Histogram, - /// The number of nodes in the result - pub output_nodes: Histogram, - /// The query depth - pub query_depth: Histogram, - /// The size (in bytes) of the payload that is higher than the maximum - pub query_payload_too_large_size: Histogram, - /// The size (in bytes) of the payload - pub query_payload_size: Histogram, - /// The time it takes to validate the query - pub query_validation_latency: Histogram, - /// The time it takes for the GraphQL service to execute the request - pub query_latency: Histogram, - /// Number of errors by path and type. - pub num_errors: IntCounterVec, - /// Number of queries - pub num_queries: IntCounter, - /// Number of queries by top level path - pub num_queries_top_level: IntCounterVec, - /// Total inflight requests - pub inflight_requests: Gauge, -} - -impl Metrics { - pub(crate) fn new(registry: &Registry) -> Self { - let db_metrics = DBMetrics::new(registry); - let request_metrics = RequestMetrics::new(registry); - - Self { - db_metrics: Arc::new(db_metrics), - request_metrics: Arc::new(request_metrics), - } - } - - /// Updates the DB related metrics (latency, error, success) - pub(crate) fn observe_db_data(&self, time: Duration, succeeded: bool) { - let label = if succeeded { "success" } else { "error" }; - self.db_metrics.db_fetches.with_label_values(&[label]).inc(); - self.db_metrics - .db_fetch_latency - .with_label_values(&[label]) - .observe(time.as_secs_f64()); - } - - /// The total time needed for handling the query - pub(crate) fn query_latency(&self, time: Duration) { - self.request_metrics - .query_latency - .observe(time.as_secs_f64()); - } - - /// The time needed for validating the query - pub(crate) fn query_validation_latency(&self, time: Duration) { - self.request_metrics - .query_validation_latency - .observe(time.as_secs_f64()); - } - - /// Increment the total number of queries by one - pub(crate) fn inc_num_queries(&self) { - self.request_metrics.num_queries.inc(); - } - - /// Use this function to increment the number of errors per path and per - /// error type. The error type is detected automatically from the passed - /// errors. - pub(crate) fn inc_errors(&self, errors: &[ServerError]) { - for err in errors { - if let Some(ext) = &err.extensions { - if let Some(async_graphql_value::ConstValue::String(val)) = ext.get("code") { - self.request_metrics - .num_errors - .with_label_values(&[query_label_for_error(&err.path).as_str(), val]) - .inc(); - } - } else { - self.request_metrics - .num_errors - .with_label_values(&[query_label_for_error(&err.path).as_str(), code::UNKNOWN]) - .inc(); - } - } - } -} - -impl DBMetrics { - pub(crate) fn new(registry: &Registry) -> Self { - Self { - db_fetches: register_int_counter_vec_with_registry!( - "db_fetches", - "The number of fetches grouped by result (success or error)", - &["type"], - registry - ) - .unwrap(), - db_fetch_latency: register_histogram_vec_with_registry!( - "db_fetch_latency", - "The fetch latency grouped by result (success or error)", - &["type"], - DB_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - _db_query_cost: register_histogram_with_registry!( - "db_query_cost", - "Cost of a DB query", - DB_QUERY_COST_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - _db_fetch_batch_size: register_histogram_vec_with_registry!( - "db_fetch_batch_size", - "Number of ids fetched per batch", - &["type"], - registry, - ) - .unwrap(), - } - } -} - -impl RequestMetrics { - pub(crate) fn new(registry: &Registry) -> Self { - Self { - input_nodes: register_histogram_with_registry!( - "input_nodes", - "Number of input nodes in the query", - INPUT_NODES_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - output_nodes: register_histogram_with_registry!( - "output_nodes", - "Number of output nodes in the response", - OUTPUT_NODES_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - query_depth: register_histogram_with_registry!( - "query_depth", - "Depth of the query", - QUERY_DEPTH_BUCKETS.to_vec(), - registry - ) - .unwrap(), - query_payload_too_large_size: register_histogram_with_registry!( - "query_payload_too_large_size", - "Query payload size (bytes), that was rejected due to being larger than maximum", - QUERY_PAYLOAD_SIZE_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - query_payload_size: register_histogram_with_registry!( - "query_payload_size", - "Size of the query payload string", - QUERY_PAYLOAD_SIZE_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - query_validation_latency: register_histogram_with_registry!( - "query_validation_latency", - "The time to validate the query", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - query_latency: register_histogram_with_registry!( - "query_latency", - "The time needed to resolve and get the result for the request", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - num_errors: register_int_counter_vec_with_registry!( - "num_errors", - "Number of errors by path and error type", - &["path", "type"], - registry, - ) - .unwrap(), - num_queries: register_int_counter_with_registry!( - "num_queries", - "Total number of queries", - registry - ) - .unwrap(), - num_queries_top_level: register_int_counter_vec_with_registry!( - "num_queries_top_level", - "Number of queries for each top level node", - &["path"], - registry - ) - .unwrap(), - inflight_requests: register_gauge_with_registry!( - "inflight_requests", - "Number of queries that are being resolved at a moment in time", - registry - ) - .unwrap(), - } - } -} - -/// When an error occurs, GraphQL returns a vector of PathSegments, -/// that we can use to retrieve the last node which contains the error. -pub(crate) fn query_label_for_error(query: &[PathSegment]) -> String { - let fields: Vec<_> = query - .iter() - .filter_map(|s| { - if let PathSegment::Field(name) = s { - Some(name) - } else { - None - } - }) - .collect(); - - match &fields[..] { - [] => "".to_string(), - [seg] => seg.to_string(), - [fst, .., lst] => format!("{fst}..{lst}"), - } -} diff --git a/crates/sui-graphql-rpc/src/server/builder.rs b/crates/sui-graphql-rpc/src/server/builder.rs deleted file mode 100644 index cf7aa092009..00000000000 --- a/crates/sui-graphql-rpc/src/server/builder.rs +++ /dev/null @@ -1,961 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - any::Any, - convert::Infallible, - net::{SocketAddr, TcpStream}, - sync::{ - atomic::{AtomicU64, Ordering::Relaxed}, - Arc, - }, - time::Instant, -}; - -use async_graphql::{ - dataloader::DataLoader, - extensions::{ApolloTracing, ExtensionFactory, Tracing}, - EmptySubscription, Schema, SchemaBuilder, ServerError, -}; -use async_graphql_axum::{GraphQLRequest, GraphQLResponse}; -use axum::{ - extract::{connect_info::IntoMakeServiceWithConnectInfo, ConnectInfo, FromRef, State}, - headers::Header, - http::{HeaderMap, StatusCode}, - middleware::{self}, - response::IntoResponse, - routing::{post, MethodRouter, Route}, - Router, -}; -use http::{HeaderValue, Method, Request}; -use hyper::{server::conn::AddrIncoming as HyperAddrIncoming, Body, Server as HyperServer}; -use mysten_metrics::spawn_monitored_task; -use mysten_network::callback::{CallbackLayer, MakeCallbackHandler, ResponseHandler}; -use sui_graphql_rpc_headers::{LIMITS_HEADER, VERSION_HEADER}; -use sui_package_resolver::{PackageStoreWithLruCache, Resolver}; -use sui_sdk::SuiClientBuilder; -use tokio::{join, sync::OnceCell}; -use tokio_util::sync::CancellationToken; -use tower::{Layer, Service}; -use tower_http::cors::{AllowOrigin, CorsLayer}; -use tracing::{error, info, warn}; -use uuid::Uuid; - -use crate::{ - config::{ - ConnectionConfig, ServerConfig, ServiceConfig, Version, MAX_CONCURRENT_REQUESTS, - RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD, - }, - consistency::CheckpointViewedAt, - context_data::{db_data_provider::PgManager, package_cache::DbPackageStore}, - data::Db, - error::Error, - extensions::{ - feature_gate::FeatureGate, - logger::Logger, - query_limits_checker::{QueryLimitsChecker, ShowUsage}, - timeout::Timeout, - }, - metrics::Metrics, - mutation::Mutation, - server::version::{check_version_middleware, set_version_middleware}, - types::{ - checkpoint::Checkpoint, - move_object::IMoveObject, - object::IObject, - owner::IOwner, - query::{Query, SuiGraphQLSchema}, - }, -}; - -pub(crate) struct Server { - pub server: HyperServer>, - /// The following fields are internally used for background tasks - checkpoint_watermark: CheckpointWatermark, - state: AppState, - db_reader: Db, -} - -impl Server { - /// Start the GraphQL service and any background tasks it is dependent on. - /// When a cancellation signal is received, the method waits for all - /// tasks to complete before returning. - pub async fn run(self) -> Result<(), Error> { - get_or_init_server_start_time().await; - - // A handle that spawns a background task to periodically update the - // `CheckpointViewedAt`, which is the u64 high watermark of checkpoints - // that the service is guaranteed to produce a consistent result for. - let watermark_task = { - let metrics = self.state.metrics.clone(); - let sleep_ms = self.state.service.background_tasks.watermark_update_ms; - let cancellation_token = self.state.cancellation_token.clone(); - info!("Starting watermark update task"); - spawn_monitored_task!(async move { - update_watermark( - &self.db_reader, - self.checkpoint_watermark, - metrics, - tokio::time::Duration::from_millis(sleep_ms), - cancellation_token, - ) - .await; - }) - }; - - let server_task = { - info!("Starting graphql service"); - let cancellation_token = self.state.cancellation_token.clone(); - spawn_monitored_task!(async move { - self.server - .with_graceful_shutdown(async { - cancellation_token.cancelled().await; - info!("Shutdown signal received, terminating graphql service"); - }) - .await - .map_err(|e| Error::Internal(format!("Server run failed: {}", e))) - }) - }; - - // Wait for both tasks to complete. This ensures that the service doesn't fully - // shut down until both the background task and the server have - // completed their shutdown processes. - let _ = join!(watermark_task, server_task); - - Ok(()) - } -} - -pub(crate) struct ServerBuilder { - state: AppState, - schema: SchemaBuilder, - router: Option, - db_reader: Option, -} - -#[derive(Clone)] -pub(crate) struct AppState { - connection: ConnectionConfig, - service: ServiceConfig, - metrics: Metrics, - cancellation_token: CancellationToken, - pub version: Version, -} - -/// The high checkpoint watermark stamped on each GraphQL request. This is used -/// to ensure cross-query consistency. -#[derive(Clone)] -pub(crate) struct CheckpointWatermark(pub Arc); - -impl AppState { - pub(crate) fn new( - connection: ConnectionConfig, - service: ServiceConfig, - metrics: Metrics, - cancellation_token: CancellationToken, - version: Version, - ) -> Self { - Self { - connection, - service, - metrics, - cancellation_token, - version, - } - } -} - -impl FromRef for ConnectionConfig { - fn from_ref(app_state: &AppState) -> ConnectionConfig { - app_state.connection.clone() - } -} - -impl FromRef for Metrics { - fn from_ref(app_state: &AppState) -> Metrics { - app_state.metrics.clone() - } -} - -impl ServerBuilder { - pub fn new(state: AppState) -> Self { - Self { - state, - schema: schema_builder(), - router: None, - db_reader: None, - } - } - - pub fn address(&self) -> String { - format!( - "{}:{}", - self.state.connection.host, self.state.connection.port - ) - } - - pub fn context_data(mut self, context_data: impl Any + Send + Sync) -> Self { - self.schema = self.schema.data(context_data); - self - } - - pub fn extension(mut self, extension: impl ExtensionFactory) -> Self { - self.schema = self.schema.extension(extension); - self - } - - fn build_schema(self) -> Schema { - self.schema.finish() - } - - /// Prepares the components of the server to be run. Finalizes the graphql - /// schema, and expects the `Db` and `Router` to have been initialized. - fn build_components( - self, - ) -> ( - String, - Schema, - Db, - Router, - ) { - let address = self.address(); - let ServerBuilder { - schema, - db_reader, - router, - .. - } = self; - ( - address, - schema.finish(), - db_reader.expect("DB reader not initialized"), - router.expect("Router not initialized"), - ) - } - - fn init_router(&mut self) { - if self.router.is_none() { - let router: Router = Router::new() - .route("/", post(graphql_handler)) - .route("/graphql", post(graphql_handler)) - .route("/health", axum::routing::get(health_checks)) - .with_state(self.state.clone()) - .route_layer(middleware::from_fn_with_state( - self.state.version, - set_version_middleware, - )) - .route_layer(middleware::from_fn_with_state( - self.state.version, - check_version_middleware, - )) - .route_layer(CallbackLayer::new(MetricsMakeCallbackHandler { - metrics: self.state.metrics.clone(), - })); - self.router = Some(router); - } - } - - pub fn route(mut self, path: &str, method_handler: MethodRouter) -> Self { - self.init_router(); - self.router = self.router.map(|router| router.route(path, method_handler)); - self - } - - pub fn layer(mut self, layer: L) -> Self - where - L: Layer + Clone + Send + 'static, - L::Service: Service> + Clone + Send + 'static, - >>::Response: IntoResponse + 'static, - >>::Error: Into + 'static, - >>::Future: Send + 'static, - { - self.init_router(); - self.router = self.router.map(|router| router.layer(layer)); - self - } - - fn cors() -> Result { - let acl = match std::env::var("ACCESS_CONTROL_ALLOW_ORIGIN") { - Ok(value) => { - let allow_hosts = value - .split(',') - .map(HeaderValue::from_str) - .collect::, _>>() - .map_err(|_| { - Error::Internal( - "Cannot resolve access control origin env variable".to_string(), - ) - })?; - AllowOrigin::list(allow_hosts) - } - _ => AllowOrigin::any(), - }; - info!("Access control allow origin set to: {acl:?}"); - - let cors = CorsLayer::new() - // Allow `POST` when accessing the resource - .allow_methods([Method::POST]) - // Allow requests from any origin - .allow_origin(acl) - .allow_headers([ - hyper::header::CONTENT_TYPE, - VERSION_HEADER.clone(), - LIMITS_HEADER.clone(), - ]); - Ok(cors) - } - - /// Consumes the `ServerBuilder` to create a `Server` that can be run. - pub fn build(self) -> Result { - let state = self.state.clone(); - let (address, schema, db_reader, router) = self.build_components(); - - // Initialize the checkpoint watermark for the background task to update. - let checkpoint_watermark = CheckpointWatermark(Arc::new(AtomicU64::new(0))); - - let app = router - .layer(axum::extract::Extension(schema)) - .layer(axum::extract::Extension(checkpoint_watermark.clone())) - .layer(Self::cors()?); - - Ok(Server { - server: axum::Server::bind( - &address - .parse() - .map_err(|_| Error::Internal(format!("Failed to parse address {}", address)))?, - ) - .serve(app.into_make_service_with_connect_info::()), - checkpoint_watermark, - state, - db_reader, - }) - } - - /// Instantiate a `ServerBuilder` from a `ServerConfig`, typically called - /// when building the graphql service for production usage. - pub async fn from_config( - config: &ServerConfig, - version: &Version, - cancellation_token: CancellationToken, - ) -> Result { - // PROMETHEUS - let prom_addr: SocketAddr = format!( - "{}:{}", - config.connection.prom_url, config.connection.prom_port - ) - .parse() - .map_err(|_| { - Error::Internal(format!( - "Failed to parse url {}, port {} into socket address", - config.connection.prom_url, config.connection.prom_port - )) - })?; - - let registry_service = mysten_metrics::start_prometheus_server(prom_addr); - info!("Starting Prometheus HTTP endpoint at {}", prom_addr); - let registry = registry_service.default_registry(); - registry - .register(mysten_metrics::uptime_metric( - "graphql", - version.full, - "unknown", - )) - .unwrap(); - - // METRICS - let metrics = Metrics::new(®istry); - let state = AppState::new( - config.connection.clone(), - config.service.clone(), - metrics.clone(), - cancellation_token, - *version, - ); - let mut builder = ServerBuilder::new(state); - - let name_service_config = config.service.name_service.clone(); - let zklogin_config = config.service.zklogin.clone(); - let reader = PgManager::reader_with_config( - config.connection.db_url.clone(), - config.connection.db_pool_size, - // Bound each statement in a request with the overall request timeout, to bound DB - // utilisation (in the worst case we will use 2x the request timeout time in DB wall - // time). - config.service.limits.request_timeout_ms, - ) - .map_err(|e| Error::Internal(format!("Failed to create pg connection pool: {}", e)))?; - - // DB - let db = Db::new(reader.clone(), config.service.limits, metrics.clone()); - let pg_conn_pool = PgManager::new(reader.clone()); - let package_store = DbPackageStore(reader.clone()); - let package_cache = PackageStoreWithLruCache::new(package_store); - builder.db_reader = Some(db.clone()); - - // SDK for talking to fullnode. Used for executing transactions only - // TODO: fail fast if no url, once we enable mutations fully - let sui_sdk_client = if let Some(url) = &config.tx_exec_full_node.node_rpc_url { - Some( - SuiClientBuilder::default() - .request_timeout(RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD) - .max_concurrent_requests(MAX_CONCURRENT_REQUESTS) - .build(url) - .await - .map_err(|e| Error::Internal(format!("Failed to create SuiClient: {}", e)))?, - ) - } else { - warn!( - "No fullnode url found in config. `dryRunTransactionBlock` and `executeTransactionBlock` will not work" - ); - None - }; - - builder = builder - .context_data(config.service.clone()) - .context_data(DataLoader::new(db.clone(), tokio::spawn)) - .context_data(db) - .context_data(pg_conn_pool) - .context_data(Resolver::new_with_limits( - package_cache, - config.service.limits.package_resolver_limits(), - )) - .context_data(sui_sdk_client) - .context_data(name_service_config) - .context_data(zklogin_config) - .context_data(metrics.clone()) - .context_data(config.clone()); - - if config.internal_features.feature_gate { - builder = builder.extension(FeatureGate); - } - if config.internal_features.logger { - builder = builder.extension(Logger::default()); - } - if config.internal_features.query_limits_checker { - builder = builder.extension(QueryLimitsChecker::default()); - } - if config.internal_features.query_timeout { - builder = builder.extension(Timeout); - } - if config.internal_features.tracing { - builder = builder.extension(Tracing); - } - if config.internal_features.apollo_tracing { - builder = builder.extension(ApolloTracing); - } - - // TODO: uncomment once impl - // if config.internal_features.open_telemetry { } - - Ok(builder) - } -} - -fn schema_builder() -> SchemaBuilder { - async_graphql::Schema::build(Query, Mutation, EmptySubscription) - .register_output_type::() - .register_output_type::() - .register_output_type::() -} - -/// Return the string representation of the schema used by this server. -pub fn export_schema() -> String { - schema_builder().finish().sdl() -} - -/// Entry point for graphql requests. Each request is stamped with a unique ID, -/// a `ShowUsage` flag if set in the request headers, and the high checkpoint -/// watermark as set by the background task. -async fn graphql_handler( - ConnectInfo(addr): ConnectInfo, - schema: axum::Extension, - watermark: axum::Extension, - headers: HeaderMap, - req: GraphQLRequest, -) -> (axum::http::Extensions, GraphQLResponse) { - let mut req = req.into_inner(); - req.data.insert(Uuid::new_v4()); - if headers.contains_key(ShowUsage::name()) { - req.data.insert(ShowUsage) - } - // Capture the IP address of the client - // Note: if a load balancer is used it must be configured to forward the client - // IP address - req.data.insert(addr); - - let checkpoint_viewed_at = watermark.0.0.load(Relaxed); - - // This wrapping is done to delineate the watermark from potentially other u64 - // types. - req.data.insert(CheckpointViewedAt(checkpoint_viewed_at)); - - let result = schema.execute(req).await; - - // If there are errors, insert them as an extention so that the Metrics callback - // handler can pull it out later. - let mut extensions = axum::http::Extensions::new(); - if result.is_err() { - extensions.insert(GraphqlErrors(std::sync::Arc::new(result.errors.clone()))); - }; - (extensions, result.into()) -} - -#[derive(Clone)] -struct MetricsMakeCallbackHandler { - metrics: Metrics, -} - -impl MakeCallbackHandler for MetricsMakeCallbackHandler { - type Handler = MetricsCallbackHandler; - - fn make_handler(&self, _request: &http::request::Parts) -> Self::Handler { - let start = Instant::now(); - let metrics = self.metrics.clone(); - - metrics.request_metrics.inflight_requests.inc(); - metrics.inc_num_queries(); - - MetricsCallbackHandler { metrics, start } - } -} - -struct MetricsCallbackHandler { - metrics: Metrics, - start: Instant, -} - -impl ResponseHandler for MetricsCallbackHandler { - fn on_response(self, response: &http::response::Parts) { - if let Some(errors) = response.extensions.get::() { - self.metrics.inc_errors(&errors.0); - } - } - - fn on_error(self, _error: &E) { - // Do nothing if the whole service errored - // - // in Axum this isn't possible since all services are required to have - // an error type of Infallible - } -} - -impl Drop for MetricsCallbackHandler { - fn drop(&mut self) { - self.metrics.query_latency(self.start.elapsed()); - self.metrics.request_metrics.inflight_requests.dec(); - } -} - -#[derive(Debug, Clone)] -struct GraphqlErrors(std::sync::Arc>); - -/// Connect via a TCPStream to the DB to check if it is alive -async fn health_checks(State(connection): State) -> StatusCode { - let Ok(url) = reqwest::Url::parse(connection.db_url.as_str()) else { - return StatusCode::INTERNAL_SERVER_ERROR; - }; - - let Some(host) = url.host_str() else { - return StatusCode::INTERNAL_SERVER_ERROR; - }; - - let tcp_url = if let Some(port) = url.port() { - format!("{host}:{port}") - } else { - host.to_string() - }; - - if TcpStream::connect(tcp_url).is_err() { - StatusCode::INTERNAL_SERVER_ERROR - } else { - StatusCode::OK - } -} - -// One server per proc, so this is okay -async fn get_or_init_server_start_time() -> &'static Instant { - static ONCE: OnceCell = OnceCell::const_new(); - ONCE.get_or_init(|| async move { Instant::now() }).await -} - -/// Starts an infinite loop that periodically updates the `checkpoint_viewed_at` -/// high watermark. -pub(crate) async fn update_watermark( - db: &Db, - checkpoint_viewed_at: CheckpointWatermark, - metrics: Metrics, - sleep_ms: tokio::time::Duration, - cancellation_token: CancellationToken, -) { - loop { - tokio::select! { - _ = cancellation_token.cancelled() => { - info!("Shutdown signal received, terminating watermark update task"); - return; - }, - _ = tokio::time::sleep(sleep_ms) => { - let new_checkpoint_viewed_at = - match Checkpoint::query_latest_checkpoint_sequence_number(db).await { - Ok(checkpoint) => Some(checkpoint), - Err(e) => { - error!("{}", e); - metrics.inc_errors(&[ServerError::new(e.to_string(), None)]); - None - } - }; - - if let Some(checkpoint) = new_checkpoint_viewed_at { - checkpoint_viewed_at.0.store(checkpoint, Relaxed); - } - } - } - } -} - -pub mod tests { - use std::{sync::Arc, time::Duration}; - - use async_graphql::{ - extensions::{Extension, ExtensionContext, NextExecute}, - Response, - }; - use uuid::Uuid; - - use super::*; - use crate::{ - config::{ConnectionConfig, Limits, ServiceConfig, Version}, - context_data::db_data_provider::PgManager, - extensions::{query_limits_checker::QueryLimitsChecker, timeout::Timeout}, - }; - - /// Prepares a schema for tests dealing with extensions. Returns a - /// `ServerBuilder` that can be further extended with `context_data` and - /// `extension` for testing. - fn prep_schema( - connection_config: Option, - service_config: Option, - ) -> ServerBuilder { - let connection_config = - connection_config.unwrap_or_else(ConnectionConfig::ci_integration_test_cfg); - let service_config = service_config.unwrap_or_default(); - - let db_url: String = connection_config.db_url.clone(); - let reader = PgManager::reader(db_url).expect("Failed to create pg connection pool"); - let version = Version::for_testing(); - let metrics = metrics(); - let db = Db::new(reader.clone(), service_config.limits, metrics.clone()); - let pg_conn_pool = PgManager::new(reader); - let cancellation_token = CancellationToken::new(); - let watermark = CheckpointViewedAt(1); - let state = AppState::new( - connection_config.clone(), - service_config.clone(), - metrics.clone(), - cancellation_token.clone(), - version, - ); - ServerBuilder::new(state) - .context_data(db) - .context_data(pg_conn_pool) - .context_data(service_config) - .context_data(query_id()) - .context_data(ip_address()) - .context_data(watermark) - .context_data(metrics) - } - - fn metrics() -> Metrics { - let binding_address: SocketAddr = "0.0.0.0:9185".parse().unwrap(); - let registry = mysten_metrics::start_prometheus_server(binding_address).default_registry(); - Metrics::new(®istry) - } - - fn ip_address() -> SocketAddr { - let binding_address: SocketAddr = "0.0.0.0:51515".parse().unwrap(); - binding_address - } - - fn query_id() -> Uuid { - Uuid::new_v4() - } - - pub async fn test_timeout_impl() { - struct TimedExecuteExt { - pub min_req_delay: Duration, - } - - impl ExtensionFactory for TimedExecuteExt { - fn create(&self) -> Arc { - Arc::new(TimedExecuteExt { - min_req_delay: self.min_req_delay, - }) - } - } - - #[async_trait::async_trait] - impl Extension for TimedExecuteExt { - async fn execute( - &self, - ctx: &ExtensionContext<'_>, - operation_name: Option<&str>, - next: NextExecute<'_>, - ) -> Response { - tokio::time::sleep(self.min_req_delay).await; - next.run(ctx, operation_name).await - } - } - - async fn test_timeout(delay: Duration, timeout: Duration) -> Response { - let mut cfg = ServiceConfig::default(); - cfg.limits.request_timeout_ms = timeout.as_millis() as u64; - - let schema = prep_schema(None, Some(cfg)) - .extension(Timeout) - .extension(TimedExecuteExt { - min_req_delay: delay, - }) - .build_schema(); - - schema.execute("{ chainIdentifier }").await - } - - let timeout = Duration::from_millis(1000); - let delay = Duration::from_millis(100); - - test_timeout(delay, timeout) - .await - .into_result() - .expect("Should complete successfully"); - - // Should timeout - let errs: Vec<_> = test_timeout(delay, delay) - .await - .into_result() - .unwrap_err() - .into_iter() - .map(|e| e.message) - .collect(); - let exp = format!("Request timed out. Limit: {}s", delay.as_secs_f32()); - assert_eq!(errs, vec![exp]); - } - - pub async fn test_query_depth_limit_impl() { - async fn exec_query_depth_limit(depth: u32, query: &str) -> Response { - let service_config = ServiceConfig { - limits: Limits { - max_query_depth: depth, - ..Default::default() - }, - ..Default::default() - }; - - let schema = prep_schema(None, Some(service_config)) - .extension(QueryLimitsChecker::default()) - .build_schema(); - schema.execute(query).await - } - - exec_query_depth_limit(1, "{ chainIdentifier }") - .await - .into_result() - .expect("Should complete successfully"); - - exec_query_depth_limit( - 5, - "{ chainIdentifier protocolConfig { configs { value key }} }", - ) - .await - .into_result() - .expect("Should complete successfully"); - - // Should fail - let errs: Vec<_> = exec_query_depth_limit(0, "{ chainIdentifier }") - .await - .into_result() - .unwrap_err() - .into_iter() - .map(|e| e.message) - .collect(); - - assert_eq!( - errs, - vec!["Query has too many levels of nesting 1. The maximum allowed is 0".to_string()] - ); - let errs: Vec<_> = exec_query_depth_limit( - 2, - "{ chainIdentifier protocolConfig { configs { value key }} }", - ) - .await - .into_result() - .unwrap_err() - .into_iter() - .map(|e| e.message) - .collect(); - assert_eq!( - errs, - vec!["Query has too many levels of nesting 3. The maximum allowed is 2".to_string()] - ); - } - - pub async fn test_query_node_limit_impl() { - async fn exec_query_node_limit(nodes: u32, query: &str) -> Response { - let service_config = ServiceConfig { - limits: Limits { - max_query_nodes: nodes, - ..Default::default() - }, - ..Default::default() - }; - - let schema = prep_schema(None, Some(service_config)) - .extension(QueryLimitsChecker::default()) - .build_schema(); - schema.execute(query).await - } - - exec_query_node_limit(1, "{ chainIdentifier }") - .await - .into_result() - .expect("Should complete successfully"); - - exec_query_node_limit( - 5, - "{ chainIdentifier protocolConfig { configs { value key }} }", - ) - .await - .into_result() - .expect("Should complete successfully"); - - // Should fail - let err: Vec<_> = exec_query_node_limit(0, "{ chainIdentifier }") - .await - .into_result() - .unwrap_err() - .into_iter() - .map(|e| e.message) - .collect(); - assert_eq!( - err, - vec!["Query has too many nodes 1. The maximum allowed is 0".to_string()] - ); - - let err: Vec<_> = exec_query_node_limit( - 4, - "{ chainIdentifier protocolConfig { configs { value key }} }", - ) - .await - .into_result() - .unwrap_err() - .into_iter() - .map(|e| e.message) - .collect(); - assert_eq!( - err, - vec!["Query has too many nodes 5. The maximum allowed is 4".to_string()] - ); - } - - pub async fn test_query_default_page_limit_impl() { - let service_config = ServiceConfig { - limits: Limits { - default_page_size: 1, - ..Default::default() - }, - ..Default::default() - }; - let schema = prep_schema(None, Some(service_config)).build_schema(); - - let resp = schema - .execute("{ checkpoints { nodes { sequenceNumber } } }") - .await; - let data = resp.data.clone().into_json().unwrap(); - let checkpoints = data - .get("checkpoints") - .unwrap() - .get("nodes") - .unwrap() - .as_array() - .unwrap(); - assert_eq!( - checkpoints.len(), - 1, - "Checkpoints should have exactly one element" - ); - - let resp = schema - .execute("{ checkpoints(first: 2) { nodes { sequenceNumber } } }") - .await; - let data = resp.data.clone().into_json().unwrap(); - let checkpoints = data - .get("checkpoints") - .unwrap() - .get("nodes") - .unwrap() - .as_array() - .unwrap(); - assert_eq!( - checkpoints.len(), - 2, - "Checkpoints should return two elements" - ); - } - - pub async fn test_query_max_page_limit_impl() { - let schema = prep_schema(None, None).build_schema(); - - schema - .execute("{ objects(first: 1) { nodes { version } } }") - .await - .into_result() - .expect("Should complete successfully"); - - // Should fail - let err: Vec<_> = schema - .execute("{ objects(first: 51) { nodes { version } } }") - .await - .into_result() - .unwrap_err() - .into_iter() - .map(|e| e.message) - .collect(); - assert_eq!( - err, - vec!["Connection's page size of 51 exceeds max of 50".to_string()] - ); - } - - pub async fn test_query_complexity_metrics_impl() { - let server_builder = prep_schema(None, None); - let metrics = server_builder.state.metrics.clone(); - let schema = server_builder - .extension(QueryLimitsChecker::default()) // QueryLimitsChecker is where we actually set the metrics - .build_schema(); - - schema - .execute("{ chainIdentifier }") - .await - .into_result() - .expect("Should complete successfully"); - - let req_metrics = metrics.request_metrics; - assert_eq!(req_metrics.input_nodes.get_sample_count(), 1); - assert_eq!(req_metrics.output_nodes.get_sample_count(), 1); - assert_eq!(req_metrics.query_depth.get_sample_count(), 1); - assert_eq!(req_metrics.input_nodes.get_sample_sum(), 1.); - assert_eq!(req_metrics.output_nodes.get_sample_sum(), 1.); - assert_eq!(req_metrics.query_depth.get_sample_sum(), 1.); - - schema - .execute("{ chainIdentifier protocolConfig { configs { value key }} }") - .await - .into_result() - .expect("Should complete successfully"); - - assert_eq!(req_metrics.input_nodes.get_sample_count(), 2); - assert_eq!(req_metrics.output_nodes.get_sample_count(), 2); - assert_eq!(req_metrics.query_depth.get_sample_count(), 2); - assert_eq!(req_metrics.input_nodes.get_sample_sum(), 2. + 4.); - assert_eq!(req_metrics.output_nodes.get_sample_sum(), 2. + 4.); - assert_eq!(req_metrics.query_depth.get_sample_sum(), 1. + 3.); - } -} diff --git a/crates/sui-graphql-rpc/src/server/mod.rs b/crates/sui-graphql-rpc/src/server/mod.rs deleted file mode 100644 index 374fbda9a57..00000000000 --- a/crates/sui-graphql-rpc/src/server/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod graphiql_server; - -pub mod builder; -pub mod version; diff --git a/crates/sui-graphql-rpc/src/test_infra/cluster.rs b/crates/sui-graphql-rpc/src/test_infra/cluster.rs deleted file mode 100644 index 1f0ff07ccd6..00000000000 --- a/crates/sui-graphql-rpc/src/test_infra/cluster.rs +++ /dev/null @@ -1,358 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{net::SocketAddr, sync::Arc, time::Duration}; - -use sui_graphql_rpc_client::simple_client::SimpleClient; -pub use sui_indexer::handlers::objects_snapshot_processor::SnapshotLagConfig; -use sui_indexer::{ - errors::IndexerError, - store::{indexer_store::IndexerStore, PgIndexerStore}, - test_utils::{ - force_delete_database, start_test_indexer, start_test_indexer_impl, ReaderWriterConfig, - }, -}; -use sui_swarm_config::genesis_config::{AccountConfig, DEFAULT_GAS_AMOUNT}; -use sui_types::storage::ReadStore; -use test_cluster::{TestCluster, TestClusterBuilder}; -use tokio::task::JoinHandle; -use tokio_util::sync::CancellationToken; - -use crate::{ - config::{ConnectionConfig, ServerConfig, ServiceConfig, Version}, - server::graphiql_server::start_graphiql_server, -}; - -const VALIDATOR_COUNT: usize = 7; -const EPOCH_DURATION_MS: u64 = 15000; - -const ACCOUNT_NUM: usize = 20; -const GAS_OBJECT_COUNT: usize = 3; - -pub const DEFAULT_INTERNAL_DATA_SOURCE_PORT: u16 = 3000; - -pub struct ExecutorCluster { - pub executor_server_handle: JoinHandle<()>, - pub indexer_store: PgIndexerStore, - pub indexer_join_handle: JoinHandle>, - pub graphql_server_join_handle: JoinHandle<()>, - pub graphql_client: SimpleClient, - pub snapshot_config: SnapshotLagConfig, - pub graphql_connection_config: ConnectionConfig, - pub cancellation_token: CancellationToken, -} - -pub struct Cluster { - pub validator_fullnode_handle: TestCluster, - pub indexer_store: PgIndexerStore, - pub indexer_join_handle: JoinHandle>, - pub graphql_server_join_handle: JoinHandle<()>, - pub graphql_client: SimpleClient, -} - -/// Starts a validator, fullnode, indexer, and graphql service for testing. -pub async fn start_cluster( - graphql_connection_config: ConnectionConfig, - internal_data_source_rpc_port: Option, -) -> Cluster { - let db_url = graphql_connection_config.db_url.clone(); - // Starts validator+fullnode - let val_fn = start_validator_with_fullnode(internal_data_source_rpc_port).await; - - // Starts indexer - let (pg_store, pg_handle) = start_test_indexer( - Some(db_url), - val_fn.rpc_url().to_string(), - ReaderWriterConfig::writer_mode(None), - ) - .await; - - // Starts graphql server - let fn_rpc_url = val_fn.rpc_url().to_string(); - let graphql_server_handle = start_graphql_server_with_fn_rpc( - graphql_connection_config.clone(), - Some(fn_rpc_url), - // cancellation_token - None, - ) - .await; - - let server_url = format!( - "http://{}:{}/", - graphql_connection_config.host, graphql_connection_config.port - ); - - // Starts graphql client - let client = SimpleClient::new(server_url); - wait_for_graphql_server(&client).await; - - Cluster { - validator_fullnode_handle: val_fn, - indexer_store: pg_store, - indexer_join_handle: pg_handle, - graphql_server_join_handle: graphql_server_handle, - graphql_client: client, - } -} - -/// Takes in a simulated instantiation of a Sui blockchain and builds a cluster -/// around it. This cluster is typically used in e2e tests to emulate and test -/// behaviors. -pub async fn serve_executor( - graphql_connection_config: ConnectionConfig, - internal_data_source_rpc_port: u16, - executor: Arc, - snapshot_config: Option, -) -> ExecutorCluster { - let db_url = graphql_connection_config.db_url.clone(); - let cancellation_token = CancellationToken::new(); - - let executor_server_url: SocketAddr = format!("127.0.0.1:{}", internal_data_source_rpc_port) - .parse() - .unwrap(); - - let executor_server_handle = tokio::spawn(async move { - let chain_id = (*executor - .get_checkpoint_by_sequence_number(0) - .unwrap() - .unwrap() - .digest()) - .into(); - - sui_rest_api::RestService::new_without_version(executor, chain_id) - .start_service(executor_server_url, Some("/rest".to_owned())) - .await; - }); - - let (pg_store, pg_handle) = start_test_indexer_impl( - Some(db_url), - format!("http://{}", executor_server_url), - ReaderWriterConfig::writer_mode(snapshot_config.clone()), - Some(graphql_connection_config.db_name()), - ) - .await; - - // Starts graphql server - let graphql_server_handle = start_graphql_server( - graphql_connection_config.clone(), - cancellation_token.clone(), - ) - .await; - - let server_url = format!( - "http://{}:{}/", - graphql_connection_config.host, graphql_connection_config.port - ); - - // Starts graphql client - let client = SimpleClient::new(server_url); - wait_for_graphql_server(&client).await; - - ExecutorCluster { - executor_server_handle, - indexer_store: pg_store, - indexer_join_handle: pg_handle, - graphql_server_join_handle: graphql_server_handle, - graphql_client: client, - snapshot_config: snapshot_config.unwrap_or_default(), - graphql_connection_config, - cancellation_token, - } -} - -pub async fn start_graphql_server( - graphql_connection_config: ConnectionConfig, - cancellation_token: CancellationToken, -) -> JoinHandle<()> { - start_graphql_server_with_fn_rpc(graphql_connection_config, None, Some(cancellation_token)) - .await -} - -pub async fn start_graphql_server_with_fn_rpc( - graphql_connection_config: ConnectionConfig, - fn_rpc_url: Option, - cancellation_token: Option, -) -> JoinHandle<()> { - let cancellation_token = cancellation_token.unwrap_or_default(); - let mut server_config = ServerConfig { - connection: graphql_connection_config, - service: ServiceConfig::test_defaults(), - ..ServerConfig::default() - }; - if let Some(fn_rpc_url) = fn_rpc_url { - server_config.tx_exec_full_node.node_rpc_url = Some(fn_rpc_url); - }; - - // Starts graphql server - tokio::spawn(async move { - start_graphiql_server(&server_config, &Version::for_testing(), cancellation_token) - .await - .unwrap(); - }) -} - -async fn start_validator_with_fullnode(internal_data_source_rpc_port: Option) -> TestCluster { - let mut test_cluster_builder = TestClusterBuilder::new() - .with_num_validators(VALIDATOR_COUNT) - .with_epoch_duration_ms(EPOCH_DURATION_MS) - .with_accounts(vec![ - AccountConfig { - address: None, - gas_amounts: vec![DEFAULT_GAS_AMOUNT; GAS_OBJECT_COUNT], - }; - ACCOUNT_NUM - ]); - - if let Some(internal_data_source_rpc_port) = internal_data_source_rpc_port { - test_cluster_builder = - test_cluster_builder.with_fullnode_rpc_port(internal_data_source_rpc_port); - }; - test_cluster_builder.build().await -} - -/// Repeatedly ping the GraphQL server for 10s, until it responds -async fn wait_for_graphql_server(client: &SimpleClient) { - tokio::time::timeout(Duration::from_secs(10), async { - while client.ping().await.is_err() { - tokio::time::sleep(Duration::from_millis(500)).await; - } - }) - .await - .expect("Timeout waiting for graphql server to start"); -} - -/// Ping the GraphQL server until its background task has updated the checkpoint -/// watermark to the desired checkpoint. -async fn wait_for_graphql_checkpoint_catchup( - client: &SimpleClient, - checkpoint: u64, - base_timeout: Duration, -) { - let query = r#" - { - availableRange { - last { - sequenceNumber - } - } - }"#; - - let timeout = base_timeout.mul_f64(checkpoint.max(1) as f64); - - tokio::time::timeout(timeout, async { - loop { - let resp = client - .execute_to_graphql(query.to_string(), false, vec![], vec![]) - .await - .unwrap() - .response_body_json(); - - let current_checkpoint = resp["data"]["availableRange"]["last"].get("sequenceNumber"); - - // Indexer has not picked up any checkpoints yet - let Some(current_checkpoint) = current_checkpoint else { - tokio::time::sleep(Duration::from_secs(1)).await; - continue; - }; - - // Indexer has picked up a checkpoint, but it's not the one we're waiting for - let current_checkpoint = current_checkpoint.as_u64().unwrap(); - if current_checkpoint < checkpoint { - tokio::time::sleep(Duration::from_secs(1)).await; - } else { - break; - } - } - }) - .await - .expect("Timeout waiting for graphql to catchup to checkpoint"); -} - -impl Cluster { - /// Waits for the indexer to index up to the given checkpoint, then waits - /// for the graphql service's background task to update the checkpoint - /// watermark to the given checkpoint. - pub async fn wait_for_checkpoint_catchup(&self, checkpoint: u64, base_timeout: Duration) { - wait_for_graphql_checkpoint_catchup(&self.graphql_client, checkpoint, base_timeout).await - } -} - -impl ExecutorCluster { - /// Waits for the indexer to index up to the given checkpoint, then waits - /// for the graphql service's background task to update the checkpoint - /// watermark to the given checkpoint. - pub async fn wait_for_checkpoint_catchup(&self, checkpoint: u64, base_timeout: Duration) { - wait_for_graphql_checkpoint_catchup(&self.graphql_client, checkpoint, base_timeout).await - } - - /// The ObjectsSnapshotProcessor is a long-running task that periodically - /// takes a snapshot of the objects table. This leads to flakiness in - /// tests, so we wait until the objects_snapshot has reached the - /// expected state. - pub async fn wait_for_objects_snapshot_catchup(&self, base_timeout: Duration) { - let mut latest_snapshot_cp = 0; - - let latest_cp = self - .indexer_store - .get_latest_tx_checkpoint_sequence_number() - .await - .unwrap() - .unwrap(); - - tokio::time::timeout(base_timeout, async { - while latest_cp > latest_snapshot_cp + self.snapshot_config.snapshot_max_lag as u64 { - tokio::time::sleep(Duration::from_secs(1)).await; - latest_snapshot_cp = self - .indexer_store - .get_latest_object_snapshot_checkpoint_sequence_number() - .await - .unwrap() - .unwrap_or_default(); - } - }) - .await - .unwrap_or_else(|_| panic!("Timeout waiting for indexer to update objects snapshot - latest_cp: {}, latest_snapshot_cp: {}", - latest_cp, latest_snapshot_cp)); - } - - /// Deletes the database created for the test and sends a cancellation - /// signal to the graphql service. When this function is awaited on, the - /// callsite will wait for the graphql service to terminate its - /// background task and then itself. - pub async fn cleanup_resources(self) { - self.cancellation_token.cancel(); - let db_url = self.graphql_connection_config.db_url.clone(); - force_delete_database(db_url).await; - } - - pub async fn force_objects_snapshot_catchup(&self, start_cp: u64, end_cp: u64) { - self.indexer_store - .persist_object_snapshot(start_cp, end_cp) - .await - .unwrap(); - - let mut latest_snapshot_cp = self - .indexer_store - .get_latest_object_snapshot_checkpoint_sequence_number() - .await - .unwrap() - .unwrap_or_default(); - - tokio::time::timeout(Duration::from_secs(60), async { - while latest_snapshot_cp < end_cp - 1 { - tokio::time::sleep(Duration::from_secs(1)).await; - latest_snapshot_cp = self - .indexer_store - .get_latest_object_snapshot_checkpoint_sequence_number() - .await - .unwrap() - .unwrap_or_default(); - } - }) - .await - .unwrap_or_else(|_| panic!("Timeout waiting for indexer to update objects snapshot - latest_snapshot_cp: {}, end_cp: {}", - latest_snapshot_cp, end_cp)); - - tokio::time::sleep(Duration::from_secs(5)).await; - } -} diff --git a/crates/sui-graphql-rpc/src/test_infra/mod.rs b/crates/sui-graphql-rpc/src/test_infra/mod.rs deleted file mode 100644 index 853cfe14c9f..00000000000 --- a/crates/sui-graphql-rpc/src/test_infra/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod cluster; diff --git a/crates/sui-graphql-rpc/src/types/address.rs b/crates/sui-graphql-rpc/src/types/address.rs deleted file mode 100644 index 9d5f79a34f3..00000000000 --- a/crates/sui-graphql-rpc/src/types/address.rs +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_graphql::{connection::Connection, *}; - -use super::{ - balance::{self, Balance}, - coin::Coin, - cursor::Page, - move_object::MoveObject, - object::{self, ObjectFilter}, - owner::OwnerImpl, - stake::StakedSui, - sui_address::SuiAddress, - suins_registration::{DomainFormat, SuinsRegistration}, - transaction_block::{self, TransactionBlock, TransactionBlockFilter}, - type_filter::ExactTypeFilter, -}; - -#[derive(Clone, Debug, PartialEq, Eq, Copy)] -pub(crate) struct Address { - pub address: SuiAddress, - /// The checkpoint sequence number at which this was viewed at, or None if - /// the data was requested at the latest checkpoint. - pub checkpoint_viewed_at: Option, -} - -/// The possible relationship types for a transaction block: sign, sent, -/// received, or paid. -#[derive(Enum, Copy, Clone, Eq, PartialEq)] -pub(crate) enum AddressTransactionBlockRelationship { - /// Transactions this address has signed either as a sender or as a sponsor. - Sign, - /// Transactions that sent objects to this address. - Recv, -} - -/// The 32-byte address that is an account address (corresponding to a public -/// key). -#[Object] -impl Address { - pub(crate) async fn address(&self) -> SuiAddress { - OwnerImpl::from(self).address().await - } - - /// Objects owned by this address, optionally `filter`-ed. - pub(crate) async fn objects( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - filter: Option, - ) -> Result> { - OwnerImpl::from(self) - .objects(ctx, first, after, last, before, filter) - .await - } - - /// Total balance of all coins with marker type owned by this address. If - /// type is not supplied, it defaults to `0x2::sui::SUI`. - pub(crate) async fn balance( - &self, - ctx: &Context<'_>, - type_: Option, - ) -> Result> { - OwnerImpl::from(self).balance(ctx, type_).await - } - - /// The balances of all coin types owned by this address. - pub(crate) async fn balances( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(self) - .balances(ctx, first, after, last, before) - .await - } - - /// The coin objects for this address. - /// - /// `type` is a filter on the coin's type parameter, defaulting to - /// `0x2::sui::SUI`. - pub(crate) async fn coins( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - type_: Option, - ) -> Result> { - OwnerImpl::from(self) - .coins(ctx, first, after, last, before, type_) - .await - } - - /// The `0x3::staking_pool::StakedSui` objects owned by this address. - pub(crate) async fn staked_suis( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(self) - .staked_suis(ctx, first, after, last, before) - .await - } - - /// The domain explicitly configured as the default domain pointing to this - /// address. - pub(crate) async fn default_suins_name( - &self, - ctx: &Context<'_>, - format: Option, - ) -> Result> { - OwnerImpl::from(self).default_suins_name(ctx, format).await - } - - /// The SuinsRegistration NFTs owned by this address. These grant the owner - /// the capability to manage the associated domain. - pub(crate) async fn suins_registrations( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(self) - .suins_registrations(ctx, first, after, last, before) - .await - } - - /// Similar behavior to the `transactionBlocks` in Query but supporting the - /// additional `AddressTransactionBlockRelationship` filter, which - /// defaults to `SIGN`. - async fn transaction_blocks( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - relation: Option, - filter: Option, - ) -> Result> { - use AddressTransactionBlockRelationship as R; - let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - - let Some(filter) = filter.unwrap_or_default().intersect(match relation { - // Relationship defaults to "signer" if none is supplied. - Some(R::Sign) | None => TransactionBlockFilter { - sign_address: Some(self.address), - ..Default::default() - }, - - Some(R::Recv) => TransactionBlockFilter { - recv_address: Some(self.address), - ..Default::default() - }, - }) else { - return Ok(Connection::new(false, false)); - }; - - TransactionBlock::paginate( - ctx.data_unchecked(), - page, - filter, - self.checkpoint_viewed_at, - ) - .await - .extend() - } -} - -impl From<&Address> for OwnerImpl { - fn from(address: &Address) -> Self { - OwnerImpl { - address: address.address, - checkpoint_viewed_at: address.checkpoint_viewed_at, - } - } -} diff --git a/crates/sui-graphql-rpc/src/types/balance.rs b/crates/sui-graphql-rpc/src/types/balance.rs deleted file mode 100644 index 588601c1b55..00000000000 --- a/crates/sui-graphql-rpc/src/types/balance.rs +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::str::FromStr; - -use async_graphql::{ - connection::{Connection, CursorType, Edge}, - *, -}; -use diesel::{ - sql_types::{BigInt as SqlBigInt, Nullable, Text}, - OptionalExtension, QueryableByName, -}; -use serde::{Deserialize, Serialize}; -use sui_indexer::types::OwnerType; -use sui_types::{parse_sui_type_tag, TypeTag}; - -use super::{ - big_int::BigInt, - cursor::{self, Page, RawPaginated, Target}, - move_type::MoveType, - sui_address::SuiAddress, -}; -use crate::{ - consistency::{consistent_range, Checkpointed}, - data::{Db, DbConnection, QueryExecutor}, - error::Error, - filter, query, - raw_query::RawQuery, -}; - -/// The total balance for a particular coin type. -#[derive(Clone, Debug, SimpleObject)] -pub(crate) struct Balance { - /// Coin type for the balance, such as 0x2::sui::SUI - pub(crate) coin_type: MoveType, - /// How many coins of this type constitute the balance - pub(crate) coin_object_count: Option, - /// Total balance across all coin objects of the coin type - pub(crate) total_balance: Option, -} - -/// Representation of a row of balance information from the DB. We read the -/// balance as a `String` to deal with the large (bigger than 2^63 - 1) -/// balances. -#[derive(QueryableByName)] -pub struct StoredBalance { - #[diesel(sql_type = Nullable)] - pub balance: Option, - #[diesel(sql_type = Nullable)] - pub count: Option, - #[diesel(sql_type = Text)] - pub coin_type: String, -} - -pub(crate) type Cursor = cursor::JsonCursor; - -/// The inner struct for the `Balance`'s cursor. The `coin_type` is used as the -/// cursor, while the `checkpoint_viewed_at` sets the consistent upper bound for -/// the cursor. -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)] -pub(crate) struct BalanceCursor { - #[serde(rename = "t")] - coin_type: String, - /// The checkpoint sequence number this was viewed at. - #[serde(rename = "c")] - checkpoint_viewed_at: u64, -} - -impl Balance { - /// Query for the balance of coins owned by `address`, of coins with type - /// `coin_type`. Note that `coin_type` is the type of - /// `0x2::coin::Coin`'s type parameter, not the full type of the coin - /// object. - pub(crate) async fn query( - db: &Db, - address: SuiAddress, - coin_type: TypeTag, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - let stored: Option = db - .execute_repeatable(move |conn| { - let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { - return Ok::<_, diesel::result::Error>(None); - }; - - conn.result(move || { - balance_query(address, Some(coin_type.clone()), lhs as i64, rhs as i64) - .into_boxed() - }) - .optional() - }) - .await?; - - stored.map(Balance::try_from).transpose() - } - - /// Query the database for a `page` of coin balances. Each balance - /// represents the total balance for a particular coin type, owned by - /// `address`. - pub(crate) async fn paginate( - db: &Db, - page: Page, - address: SuiAddress, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - // If cursors are provided, defer to the `checkpoint_viewed_at` in the cursor if - // they are consistent. Otherwise, use the value from the parameter, or - // set to None. This is so that paginated queries are consistent with - // the previous query that created the cursor. - let cursor_viewed_at = page.validate_cursor_consistency()?; - let checkpoint_viewed_at: Option = cursor_viewed_at.or(checkpoint_viewed_at); - - let response = db - .execute_repeatable(move |conn| { - let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { - return Ok::<_, diesel::result::Error>(None); - }; - - let result = page.paginate_raw_query::( - conn, - rhs, - balance_query(address, None, lhs as i64, rhs as i64), - )?; - - Ok(Some((result, rhs))) - }) - .await?; - - let Some(((prev, next, results), checkpoint_viewed_at)) = response else { - return Err(Error::Client( - "Requested data is outside the available range".to_string(), - )); - }; - - let mut conn = Connection::new(prev, next); - - for stored in results { - let cursor = stored.cursor(checkpoint_viewed_at).encode_cursor(); - let balance = Balance::try_from(stored)?; - conn.edges.push(Edge::new(cursor, balance)); - } - - Ok(conn) - } -} - -impl RawPaginated for StoredBalance { - fn filter_ge(cursor: &Cursor, query: RawQuery) -> RawQuery { - filter!(query, "coin_type >= {}", cursor.coin_type.clone()) - } - - fn filter_le(cursor: &Cursor, query: RawQuery) -> RawQuery { - filter!(query, "coin_type <= {}", cursor.coin_type.clone()) - } - - fn order(asc: bool, query: RawQuery) -> RawQuery { - if asc { - return query.order_by("coin_type ASC"); - } - query.order_by("coin_type DESC") - } -} - -impl Target for StoredBalance { - fn cursor(&self, checkpoint_viewed_at: u64) -> Cursor { - Cursor::new(BalanceCursor { - coin_type: self.coin_type.clone(), - checkpoint_viewed_at, - }) - } -} - -impl Checkpointed for Cursor { - fn checkpoint_viewed_at(&self) -> u64 { - self.checkpoint_viewed_at - } -} - -impl TryFrom for Balance { - type Error = Error; - - fn try_from(s: StoredBalance) -> Result { - let StoredBalance { - balance, - count, - coin_type, - } = s; - let total_balance = balance - .map(|b| BigInt::from_str(&b)) - .transpose() - .map_err(|_| Error::Internal("Failed to read balance.".to_string()))?; - - let coin_object_count = count.map(|c| c as u64); - - let coin_type = MoveType::new( - parse_sui_type_tag(&coin_type) - .map_err(|e| Error::Internal(format!("Failed to parse coin type: {e}")))?, - ); - - Ok(Balance { - coin_type, - coin_object_count, - total_balance, - }) - } -} - -/// Query the database for a `page` of coin balances. Each balance represents -/// the total balance for a particular coin type, owned by `address`. This -/// function is meant to be called within a thunk and returns a RawQuery that -/// can be converted into a BoxedSqlQuery with `.into_boxed()`. -fn balance_query(address: SuiAddress, coin_type: Option, lhs: i64, rhs: i64) -> RawQuery { - // Construct the filtered inner query - apply the same filtering criteria to - // both objects_snapshot and objects_history tables. - let mut snapshot_objs = query!("SELECT * FROM objects_snapshot"); - snapshot_objs = filter(snapshot_objs, address, coin_type.clone()); - - // Additionally filter objects_history table for results between the available - // range, or checkpoint_viewed_at, if provided. - let mut history_objs = query!("SELECT * FROM objects_history"); - history_objs = filter(history_objs, address, coin_type.clone()); - history_objs = filter!( - history_objs, - format!(r#"checkpoint_sequence_number BETWEEN {} AND {}"#, lhs, rhs) - ); - - // Combine the two queries, and select the most recent version of each object. - let candidates = query!( - r#"SELECT DISTINCT ON (object_id) * FROM (({}) UNION ALL ({})) o"#, - snapshot_objs, - history_objs - ) - .order_by("object_id") - .order_by("object_version DESC"); - - // Objects that fulfill the filtering criteria may not be the most recent - // version available. Left join the candidates table on newer to filter out - // any objects that have a newer version. - let mut newer = query!("SELECT object_id, object_version FROM objects_history"); - newer = filter!( - newer, - format!(r#"checkpoint_sequence_number BETWEEN {} AND {}"#, lhs, rhs) - ); - let final_ = query!( - r#"SELECT - CAST(SUM(coin_balance) AS TEXT) as balance, - COUNT(*) as count, - coin_type - FROM ({}) candidates - LEFT JOIN ({}) newer - ON ( - candidates.object_id = newer.object_id - AND candidates.object_version < newer.object_version - )"#, - candidates, - newer - ); - - // Additionally for balance's query, group coins by coin_type. - filter!(final_, "newer.object_version IS NULL").group_by("coin_type") -} - -/// Applies the filtering criteria for balances to the input `RawQuery` and -/// returns a new `RawQuery`. -fn filter(mut query: RawQuery, owner: SuiAddress, coin_type: Option) -> RawQuery { - query = filter!(query, "coin_type IS NOT NULL"); - - query = filter!( - query, - format!( - "owner_id = '\\x{}'::bytea AND owner_type = {}", - hex::encode(owner.into_vec()), - OwnerType::Address as i16 - ) - ); - - if let Some(coin_type) = coin_type { - query = filter!( - query, - "coin_type = {}", - coin_type.to_canonical_display(/* with_prefix */ true) - ); - }; - - query -} diff --git a/crates/sui-graphql-rpc/src/types/coin.rs b/crates/sui-graphql-rpc/src/types/coin.rs deleted file mode 100644 index 6fd7a49a82a..00000000000 --- a/crates/sui-graphql-rpc/src/types/coin.rs +++ /dev/null @@ -1,430 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_graphql::{ - connection::{Connection, CursorType, Edge}, - *, -}; -use sui_indexer::{models::objects::StoredHistoryObject, types::OwnerType}; -use sui_types::{coin::Coin as NativeCoin, TypeTag}; - -use super::{ - balance::{self, Balance}, - base64::Base64, - big_int::BigInt, - cursor::{Page, Target}, - display::DisplayEntry, - dynamic_field::{DynamicField, DynamicFieldName}, - move_object::{MoveObject, MoveObjectImpl}, - move_value::MoveValue, - object::{self, Object, ObjectFilter, ObjectImpl, ObjectOwner, ObjectStatus}, - owner::OwnerImpl, - stake::StakedSui, - sui_address::SuiAddress, - suins_registration::{DomainFormat, SuinsRegistration}, - transaction_block::{self, TransactionBlock, TransactionBlockFilter}, - type_filter::ExactTypeFilter, -}; -use crate::{ - consistency::{build_objects_query, consistent_range, View}, - data::{Db, QueryExecutor}, - error::Error, - filter, - raw_query::RawQuery, -}; - -#[derive(Clone)] -pub(crate) struct Coin { - /// Representation of this Coin as a generic Move Object. - pub super_: MoveObject, - - /// The deserialized representation of the Move Object's contents, as a - /// `0x2::coin::Coin`. - pub native: NativeCoin, -} - -pub(crate) enum CoinDowncastError { - NotACoin, - Bcs(bcs::Error), -} - -/// Some 0x2::coin::Coin Move object. -#[Object] -impl Coin { - pub(crate) async fn address(&self) -> SuiAddress { - OwnerImpl::from(&self.super_.super_).address().await - } - - /// Objects owned by this object, optionally `filter`-ed. - pub(crate) async fn objects( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - filter: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .objects(ctx, first, after, last, before, filter) - .await - } - - /// Total balance of all coins with marker type owned by this object. If - /// type is not supplied, it defaults to `0x2::sui::SUI`. - pub(crate) async fn balance( - &self, - ctx: &Context<'_>, - type_: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .balance(ctx, type_) - .await - } - - /// The balances of all coin types owned by this object. - pub(crate) async fn balances( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .balances(ctx, first, after, last, before) - .await - } - - /// The coin objects for this object. - /// - /// `type` is a filter on the coin's type parameter, defaulting to - /// `0x2::sui::SUI`. - pub(crate) async fn coins( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - type_: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .coins(ctx, first, after, last, before, type_) - .await - } - - /// The `0x3::staking_pool::StakedSui` objects owned by this object. - pub(crate) async fn staked_suis( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .staked_suis(ctx, first, after, last, before) - .await - } - - /// The domain explicitly configured as the default domain pointing to this - /// object. - pub(crate) async fn default_suins_name( - &self, - ctx: &Context<'_>, - format: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .default_suins_name(ctx, format) - .await - } - - /// The SuinsRegistration NFTs owned by this object. These grant the owner - /// the capability to manage the associated domain. - pub(crate) async fn suins_registrations( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .suins_registrations(ctx, first, after, last, before) - .await - } - - pub(crate) async fn version(&self) -> u64 { - ObjectImpl(&self.super_.super_).version().await - } - - /// The current status of the object as read from the off-chain store. The - /// possible states are: NOT_INDEXED, the object is loaded from - /// serialized data, such as the contents of a genesis or system package - /// upgrade transaction. LIVE, the version returned is the most recent for - /// the object, and it is not deleted or wrapped at that version. - /// HISTORICAL, the object was referenced at a specific version or - /// checkpoint, so is fetched from historical tables and may not be the - /// latest version of the object. WRAPPED_OR_DELETED, the object is deleted - /// or wrapped and only partial information can be loaded." - pub(crate) async fn status(&self) -> ObjectStatus { - ObjectImpl(&self.super_.super_).status().await - } - - /// 32-byte hash that identifies the object's contents, encoded as a Base58 - /// string. - pub(crate) async fn digest(&self) -> Option { - ObjectImpl(&self.super_.super_).digest().await - } - - /// The owner type of this object: Immutable, Shared, Parent, Address - pub(crate) async fn owner(&self, ctx: &Context<'_>) -> Option { - ObjectImpl(&self.super_.super_).owner(ctx).await - } - - /// The transaction block that created this version of the object. - pub(crate) async fn previous_transaction_block( - &self, - ctx: &Context<'_>, - ) -> Result> { - ObjectImpl(&self.super_.super_) - .previous_transaction_block(ctx) - .await - } - - /// The amount of SUI we would rebate if this object gets deleted or - /// mutated. This number is recalculated based on the present storage - /// gas price. - pub(crate) async fn storage_rebate(&self) -> Option { - ObjectImpl(&self.super_.super_).storage_rebate().await - } - - /// The transaction blocks that sent objects to this object. - pub(crate) async fn received_transaction_blocks( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - filter: Option, - ) -> Result> { - ObjectImpl(&self.super_.super_) - .received_transaction_blocks(ctx, first, after, last, before, filter) - .await - } - - /// The Base64-encoded BCS serialization of the object's content. - pub(crate) async fn bcs(&self) -> Result> { - ObjectImpl(&self.super_.super_).bcs().await - } - - /// Displays the contents of the Move object in a JSON string and through - /// GraphQL types. Also provides the flat representation of the type - /// signature, and the BCS of the corresponding data. - pub(crate) async fn contents(&self) -> Option { - MoveObjectImpl(&self.super_).contents().await - } - - /// Determines whether a transaction can transfer this object, using the - /// TransferObjects transaction command or - /// `sui::transfer::public_transfer`, both of which require the object to - /// have the `key` and `store` abilities. - pub(crate) async fn has_public_transfer(&self, ctx: &Context<'_>) -> Result { - MoveObjectImpl(&self.super_).has_public_transfer(ctx).await - } - - /// The set of named templates defined on-chain for the type of this object, - /// to be handled off-chain. The server substitutes data from the object - /// into these templates to generate a display string per template. - pub(crate) async fn display(&self, ctx: &Context<'_>) -> Result>> { - ObjectImpl(&self.super_.super_).display(ctx).await - } - - /// Access a dynamic field on an object using its name. Names are arbitrary - /// Move values whose type have `copy`, `drop`, and `store`, and are - /// specified using their type, and their BCS contents, Base64 encoded. - /// - /// Dynamic fields on wrapped objects can be accessed by using the same API - /// under the Owner type. - pub(crate) async fn dynamic_field( - &self, - ctx: &Context<'_>, - name: DynamicFieldName, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .dynamic_field(ctx, name, Some(self.super_.super_.version_impl())) - .await - } - - /// Access a dynamic object field on an object using its name. Names are - /// arbitrary Move values whose type have `copy`, `drop`, and `store`, - /// and are specified using their type, and their BCS contents, Base64 - /// encoded. The value of a dynamic object field can also be accessed - /// off-chain directly via its address (e.g. using `Query.object`). - /// - /// Dynamic fields on wrapped objects can be accessed by using the same API - /// under the Owner type. - pub(crate) async fn dynamic_object_field( - &self, - ctx: &Context<'_>, - name: DynamicFieldName, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .dynamic_object_field(ctx, name, Some(self.super_.super_.version_impl())) - .await - } - - /// The dynamic fields and dynamic object fields on an object. - /// - /// Dynamic fields on wrapped objects can be accessed by using the same API - /// under the Owner type. - pub(crate) async fn dynamic_fields( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .dynamic_fields( - ctx, - first, - after, - last, - before, - Some(self.super_.super_.version_impl()), - ) - .await - } - - /// Balance of this coin object. - async fn coin_balance(&self) -> Option { - Some(BigInt::from(self.native.balance.value())) - } -} - -impl Coin { - /// Query the database for a `page` of coins. The page uses the bytes of an - /// Object ID as the cursor, and can optionally be filtered by an owner. - pub(crate) async fn paginate( - db: &Db, - page: Page, - coin_type: TypeTag, - owner: Option, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - // If cursors are provided, defer to the `checkpoint_viewed_at` in the cursor if - // they are consistent. Otherwise, use the value from the parameter, or - // set to None. This is so that paginated queries are consistent with - // the previous query that created the cursor. - let cursor_viewed_at = page.validate_cursor_consistency()?; - let checkpoint_viewed_at: Option = cursor_viewed_at.or(checkpoint_viewed_at); - - let response = db - .execute_repeatable(move |conn| { - let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { - return Ok::<_, diesel::result::Error>(None); - }; - - let result = page.paginate_raw_query::( - conn, - rhs, - coins_query(coin_type, owner, lhs as i64, rhs as i64, &page), - )?; - - Ok(Some((result, rhs))) - }) - .await?; - - let Some(((prev, next, results), checkpoint_viewed_at)) = response else { - return Err(Error::Client( - "Requested data is outside the available range".to_string(), - )); - }; - - let mut conn: Connection = Connection::new(prev, next); - - for stored in results { - // To maintain consistency, the returned cursor should have the same upper-bound - // as the checkpoint found on the cursor. - let cursor = stored.cursor(checkpoint_viewed_at).encode_cursor(); - let object = - Object::try_from_stored_history_object(stored, Some(checkpoint_viewed_at))?; - - let move_ = MoveObject::try_from(&object).map_err(|_| { - Error::Internal(format!( - "Failed to deserialize as Move object: {}", - object.address - )) - })?; - - let coin = Coin::try_from(&move_).map_err(|_| { - Error::Internal(format!("Faild to deserialize as Coin: {}", object.address)) - })?; - - conn.edges.push(Edge::new(cursor, coin)); - } - - Ok(conn) - } -} - -impl TryFrom<&MoveObject> for Coin { - type Error = CoinDowncastError; - - fn try_from(move_object: &MoveObject) -> Result { - if !move_object.native.is_coin() { - return Err(CoinDowncastError::NotACoin); - } - - Ok(Self { - super_: move_object.clone(), - native: bcs::from_bytes(move_object.native.contents()) - .map_err(CoinDowncastError::Bcs)?, - }) - } -} - -/// Constructs a raw query to fetch objects from the database. Since there are -/// no point lookups for the coin query, objects are filtered out if they -/// satisfy the criteria but have a later version in the same checkpoint. -fn coins_query( - coin_type: TypeTag, - owner: Option, - lhs: i64, - rhs: i64, - page: &Page, -) -> RawQuery { - build_objects_query( - View::Consistent, - lhs, - rhs, - page, - move |query| apply_filter(query, &coin_type, owner), - move |newer| newer, - ) -} - -fn apply_filter(mut query: RawQuery, coin_type: &TypeTag, owner: Option) -> RawQuery { - if let Some(owner) = owner { - query = filter!( - query, - format!( - "owner_id = '\\x{}'::bytea AND owner_type = {}", - hex::encode(owner.into_vec()), - OwnerType::Address as i16 - ) - ); - } - - query = filter!( - query, - "coin_type IS NOT NULL AND coin_type = {}", - coin_type.to_canonical_display(/* with_prefix */ true) - ); - - query -} diff --git a/crates/sui-graphql-rpc/src/types/display.rs b/crates/sui-graphql-rpc/src/types/display.rs deleted file mode 100644 index ca1c52142ca..00000000000 --- a/crates/sui-graphql-rpc/src/types/display.rs +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_graphql::*; -use diesel::{ExpressionMethods, OptionalExtension, QueryDsl}; -use move_core_types::annotated_value::{MoveStruct, MoveValue}; -use sui_indexer::{models::display::StoredDisplay, schema::display}; -use sui_json_rpc_types::SuiMoveValue; -use sui_types::TypeTag; - -use crate::{ - data::{Db, DbConnection, QueryExecutor}, - error::Error, -}; - -pub(crate) struct Display { - pub stored: StoredDisplay, -} - -/// The set of named templates defined on-chain for the type of this object, -/// to be handled off-chain. The server substitutes data from the object -/// into these templates to generate a display string per template. -#[derive(Debug, SimpleObject)] -pub(crate) struct DisplayEntry { - /// The identifier for a particular template string of the Display object. - pub key: String, - /// The template string for the key with placeholder values substituted. - pub value: Option, - /// An error string describing why the template could not be rendered. - pub error: Option, -} - -#[derive(thiserror::Error, Debug)] -pub(crate) enum DisplayRenderError { - #[error("Display template value cannot be empty")] - TemplateValueEmpty, - #[error("Display template value of {0} exceeds maximum depth of {1}")] - ExceedsLookupDepth(usize, u64), - #[error("Vector of name {0} is not supported as a Display value")] - Vector(String), - #[error("Field '{0}' not found")] - FieldNotFound(String), - #[error("Unexpected MoveValue")] - UnexpectedMoveValue, -} - -impl Display { - /// Query for a `Display` object by the type that it is displaying - pub(crate) async fn query(db: &Db, type_: TypeTag) -> Result, Error> { - let stored: Option = db - .execute(move |conn| { - conn.first(move || { - use display::dsl; - dsl::display.filter( - dsl::object_type.eq(type_.to_canonical_string(/* with_prefix */ true)), - ) - }) - .optional() - }) - .await?; - - Ok(stored.map(|stored| Display { stored })) - } - - /// Render the fields defined by this `Display` from the contents of - /// `struct_`. - pub(crate) fn render(&self, struct_: &MoveStruct) -> Result, Error> { - let event = self - .stored - .to_display_update_event() - .map_err(|e| Error::Internal(e.to_string()))?; - - let mut rendered = vec![]; - for entry in event.fields.contents { - rendered.push(match parse_template(&entry.value, struct_) { - Ok(v) => DisplayEntry::create_value(entry.key, v), - Err(e) => DisplayEntry::create_error(entry.key, e.to_string()), - }); - } - - Ok(rendered) - } -} - -impl DisplayEntry { - pub(crate) fn create_value(key: String, value: String) -> Self { - Self { - key, - value: Some(value), - error: None, - } - } - - pub(crate) fn create_error(key: String, error: String) -> Self { - Self { - key, - value: None, - error: Some(error), - } - } -} - -/// Handles the PART of the grammar, defined as: -/// PART ::= '{' CHAIN '}' -/// | '\{' | '\}' -/// | [:utf8:] -/// Defers resolution down to the IDENT to get_value_from_move_struct, -/// and substitutes the result into the PART template. -fn parse_template(template: &str, move_struct: &MoveStruct) -> Result { - let mut output = template.to_string(); - let mut var_name = String::new(); - let mut in_braces = false; - let mut escaped = false; - - for ch in template.chars() { - match ch { - '\\' => { - escaped = true; - continue; - } - '{' if !escaped => { - in_braces = true; - var_name.clear(); - } - '}' if !escaped => { - in_braces = false; - let value = get_value_from_move_struct(move_struct, &var_name)?; - output = output.replace(&format!("{{{}}}", var_name), &value.to_string()); - } - _ if !escaped => { - if in_braces { - var_name.push(ch); - } - } - _ => {} - } - escaped = false; - } - - Ok(output.replace('\\', "")) -} - -/// Handles the CHAIN and IDENT of the grammar, defined as: -/// CHAIN ::= IDENT | CHAIN '.' IDENT -/// IDENT ::= /* Move identifier */ -pub(crate) fn get_value_from_move_struct( - move_struct: &MoveStruct, - var_name: &str, -) -> Result { - let parts: Vec<&str> = var_name.split('.').collect(); - if parts.is_empty() { - return Err(DisplayRenderError::TemplateValueEmpty); - } - // todo: 10 is a carry-over from the sui-json-rpc implementation - // we should introduce this as a new limit on the config - if parts.len() > 10 { - return Err(DisplayRenderError::ExceedsLookupDepth(parts.len(), 10)); - } - - // update this as we iterate through the parts - let start_value = &MoveValue::Struct(move_struct.clone()); - - let result = parts - .iter() - .try_fold(start_value, |current_value, part| match current_value { - MoveValue::Struct(s) => s - .fields - .iter() - .find_map(|(id, value)| { - if id.as_str() == *part { - Some(value) - } else { - None - } - }) - .ok_or_else(|| DisplayRenderError::FieldNotFound(part.to_string())), - _ => Err(DisplayRenderError::UnexpectedMoveValue), - })?; - - // TODO: move off dependency on SuiMoveValue - let sui_move_value: SuiMoveValue = result.clone().into(); - - match sui_move_value { - SuiMoveValue::Option(move_option) => match move_option.as_ref() { - Some(move_value) => Ok(move_value.to_string()), - None => Ok("".to_string()), - }, - SuiMoveValue::Vector(_) => Err(DisplayRenderError::Vector(var_name.to_string())), - _ => Ok(sui_move_value.to_string()), - } -} diff --git a/crates/sui-graphql-rpc/src/types/dynamic_field.rs b/crates/sui-graphql-rpc/src/types/dynamic_field.rs deleted file mode 100644 index 99c45fdb3d6..00000000000 --- a/crates/sui-graphql-rpc/src/types/dynamic_field.rs +++ /dev/null @@ -1,381 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_graphql::{ - connection::{Connection, CursorType, Edge}, - *, -}; -use move_core_types::annotated_value::{self as A, MoveStruct}; -use sui_indexer::{models::objects::StoredHistoryObject, types::OwnerType}; -use sui_package_resolver::Resolver; -use sui_types::dynamic_field::{derive_dynamic_field_id, DynamicFieldInfo, DynamicFieldType}; - -use super::{ - base64::Base64, - cursor::{Page, Target}, - move_object::MoveObject, - move_value::MoveValue, - object::{self, deserialize_move_struct, Object, ObjectKind, ObjectLookupKey}, - sui_address::SuiAddress, - type_filter::ExactTypeFilter, -}; -use crate::{ - consistency::{build_objects_query, consistent_range, View}, - context_data::package_cache::PackageCache, - data::{Db, QueryExecutor}, - error::Error, - filter, - raw_query::RawQuery, -}; - -pub(crate) struct DynamicField { - pub super_: MoveObject, - pub df_object_id: SuiAddress, - pub df_kind: DynamicFieldType, -} - -#[derive(Union)] -pub(crate) enum DynamicFieldValue { - MoveObject(MoveObject), // DynamicObject - MoveValue(MoveValue), // DynamicField -} - -#[derive(InputObject)] // used as input object -pub(crate) struct DynamicFieldName { - /// The string type of the DynamicField's 'name' field. - /// A string representation of a Move primitive like 'u64', or a struct type - /// like '0x2::kiosk::Listing' - pub type_: ExactTypeFilter, - /// The Base64 encoded bcs serialization of the DynamicField's 'name' field. - pub bcs: Base64, -} - -/// Dynamic fields are heterogeneous fields that can be added or removed at -/// runtime, and can have arbitrary user-assigned names. There are two sub-types -/// of dynamic fields: -/// -/// 1) Dynamic Fields can store any value that has the `store` ability, however -/// an object stored in this kind of field will be considered wrapped and -/// will not be accessible directly via its ID by external tools (explorers, -/// wallets, etc) accessing storage. -/// 2) Dynamic Object Fields values must be Sui objects (have the `key` and -/// `store` abilities, and id: UID as the first field), but will still be -/// directly accessible off-chain via their object ID after being attached. -#[Object] -impl DynamicField { - /// The string type, data, and serialized value of the DynamicField's 'name' - /// field. This field is used to uniquely identify a child of the parent - /// object. - async fn name(&self, ctx: &Context<'_>) -> Result> { - let resolver: &Resolver = ctx - .data() - .map_err(|_| Error::Internal("Unable to fetch Package Cache.".to_string())) - .extend()?; - - let (struct_tag, move_struct) = deserialize_move_struct(&self.super_.native, resolver) - .await - .extend()?; - - // Get TypeTag of the DynamicField name from StructTag of the MoveStruct - let type_tag = DynamicFieldInfo::try_extract_field_name(&struct_tag, &self.df_kind) - .map_err(|e| Error::Internal(e.to_string())) - .extend()?; - - let name_move_value = extract_field_from_move_struct(move_struct, "name").extend()?; - - let undecorated = if self.df_kind == DynamicFieldType::DynamicObject { - let inner_name_move_value = match name_move_value { - A::MoveValue::Struct(inner_struct) => { - extract_field_from_move_struct(inner_struct, "name") - } - _ => Err(Error::Internal("Expected a wrapper struct".to_string())), - } - .extend()?; - inner_name_move_value.undecorate() - } else { - name_move_value.undecorate() - }; - - let bcs = bcs::to_bytes(&undecorated) - .map_err(|e| Error::Internal(format!("Failed to serialize object: {e}"))) - .extend()?; - - Ok(Some(MoveValue::new(type_tag, Base64::from(bcs)))) - } - - /// The actual data stored in the dynamic field. - /// The returned dynamic field is an object if its return type is - /// MoveObject, in which case it is also accessible off-chain via its - /// address. - async fn value(&self, ctx: &Context<'_>) -> Result> { - if self.df_kind == DynamicFieldType::DynamicObject { - // If `df_kind` is a DynamicObject, the object we are currently on is the field - // object, and we must resolve one more level down to the value - // object. Becuase we only have checkpoint-level granularity, we may - // end up reading a later version of the value object. Thus, we use - // the version of the field object to bound the value object at the - // correct version. - let obj = MoveObject::query( - ctx.data_unchecked(), - self.df_object_id, - ObjectLookupKey::LatestAtParentVersion { - version: self.super_.super_.version_impl(), - checkpoint_viewed_at: self.super_.super_.checkpoint_viewed_at, - }, - ) - .await - .extend()?; - Ok(obj.map(DynamicFieldValue::MoveObject)) - } else { - let resolver: &Resolver = ctx - .data() - .map_err(|_| Error::Internal("Unable to fetch Package Cache.".to_string())) - .extend()?; - - let (struct_tag, move_struct) = deserialize_move_struct(&self.super_.native, resolver) - .await - .extend()?; - - // Get TypeTag of the DynamicField value from StructTag of the MoveStruct - let type_tag = DynamicFieldInfo::try_extract_field_value(&struct_tag) - .map_err(|e| Error::Internal(e.to_string())) - .extend()?; - - let value_move_value = extract_field_from_move_struct(move_struct, "value").extend()?; - - let undecorated = value_move_value.undecorate(); - let bcs = bcs::to_bytes(&undecorated) - .map_err(|e| Error::Internal(format!("Failed to serialize object: {e}"))) - .extend()?; - - Ok(Some(DynamicFieldValue::MoveValue(MoveValue::new( - type_tag, - Base64::from(bcs), - )))) - } - } -} - -impl DynamicField { - /// Fetch a single dynamic field entry from the `db`, on `parent` object, - /// with field name `name`, and kind `kind` (dynamic field or dynamic - /// object field). The dynamic field is bound by the `parent_version` if - /// provided - the fetched field will be the latest version at or before - /// the provided version. If `parent_version` is not provided, the latest - /// version of the field is returned as bounded by the - /// `checkpoint_viewed_at` parameter. - pub(crate) async fn query( - db: &Db, - parent: SuiAddress, - parent_version: Option, - name: DynamicFieldName, - kind: DynamicFieldType, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - let type_ = match kind { - DynamicFieldType::DynamicField => name.type_.0, - DynamicFieldType::DynamicObject => { - DynamicFieldInfo::dynamic_object_field_wrapper(name.type_.0).into() - } - }; - - let field_id = derive_dynamic_field_id(parent, &type_, &name.bcs.0) - .map_err(|e| Error::Internal(format!("Failed to derive dynamic field id: {e}")))?; - - use ObjectLookupKey as K; - let key = match (parent_version, checkpoint_viewed_at) { - (None, None) => K::Latest, - (None, Some(checkpoint_viewed_at)) => K::LatestAt(checkpoint_viewed_at), - (Some(version), checkpoint_viewed_at) => K::LatestAtParentVersion { - version, - checkpoint_viewed_at, - }, - }; - - let super_ = MoveObject::query(db, SuiAddress::from(field_id), key).await?; - - super_.map(Self::try_from).transpose() - } - - /// Query the `db` for a `page` of dynamic fields attached to object with ID - /// `parent`. The returned dynamic fields are bound by the - /// `parent_version` if provided - each field will be the latest version - /// at or before the provided version. If `parent_version` is not provided, - /// the latest version of each field is returned as bounded by the - /// `checkpoint_viewed-at` parameter.` - pub(crate) async fn paginate( - db: &Db, - page: Page, - parent: SuiAddress, - parent_version: Option, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - // If cursors are provided, defer to the `checkpoint_viewed_at` in the cursor if - // they are consistent. Otherwise, use the value from the parameter, or - // set to None. This is so that paginated queries are consistent with - // the previous query that created the cursor. - let cursor_viewed_at = page.validate_cursor_consistency()?; - let checkpoint_viewed_at: Option = cursor_viewed_at.or(checkpoint_viewed_at); - - let Some(((prev, next, results), checkpoint_viewed_at)) = db - .execute_repeatable(move |conn| { - let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { - return Ok::<_, diesel::result::Error>(None); - }; - - let result = page.paginate_raw_query::( - conn, - rhs, - dynamic_fields_query(parent, parent_version, lhs as i64, rhs as i64, &page), - )?; - - Ok(Some((result, rhs))) - }) - .await? - else { - return Err(Error::Client( - "Requested data is outside the available range".to_string(), - )); - }; - - let mut conn: Connection = Connection::new(prev, next); - - for stored in results { - // To maintain consistency, the returned cursor should have the same upper-bound - // as the checkpoint found on the cursor. - let cursor = stored.cursor(checkpoint_viewed_at).encode_cursor(); - - let object = - Object::try_from_stored_history_object(stored, Some(checkpoint_viewed_at))?; - - let move_ = MoveObject::try_from(&object).map_err(|_| { - Error::Internal(format!( - "Failed to deserialize as Move object: {}", - object.address - )) - })?; - - let dynamic_field = DynamicField::try_from(move_)?; - - conn.edges.push(Edge::new(cursor, dynamic_field)); - } - - Ok(conn) - } -} - -impl TryFrom for DynamicField { - type Error = Error; - - fn try_from(stored: MoveObject) -> Result { - let super_ = &stored.super_; - - let (df_object_id, df_kind) = match &super_.kind { - ObjectKind::Live(_, stored) => stored - .df_object_id - .as_ref() - .map(|id| (id, stored.df_kind)) - .ok_or_else(|| Error::Internal("Object is not a dynamic field.".to_string()))?, - ObjectKind::Historical(_, stored) => stored - .df_object_id - .as_ref() - .map(|id| (id, stored.df_kind)) - .ok_or_else(|| Error::Internal("Object is not a dynamic field.".to_string()))?, - _ => { - return Err(Error::Internal( - "A WrappedOrDeleted object cannot be converted into a DynamicField." - .to_string(), - )); - } - }; - - let df_object_id = SuiAddress::from_bytes(df_object_id).map_err(|e| { - Error::Internal(format!("Failed to deserialize dynamic field ID: {e}.")) - })?; - - let df_kind = match df_kind { - Some(0) => DynamicFieldType::DynamicField, - Some(1) => DynamicFieldType::DynamicObject, - Some(k) => { - return Err(Error::Internal(format!( - "Unrecognized dynamic field kind: {k}." - ))); - } - None => return Err(Error::Internal("No dynamic field kind.".to_string())), - }; - - Ok(DynamicField { - super_: stored, - df_object_id, - df_kind, - }) - } -} - -pub fn extract_field_from_move_struct( - move_struct: MoveStruct, - field_name: &str, -) -> Result { - move_struct - .fields - .into_iter() - .find_map(|(id, value)| { - if id.to_string() == field_name { - Some(value) - } else { - None - } - }) - .ok_or_else(|| Error::Internal(format!("Field '{}' not found", field_name))) -} - -/// Builds the `RawQuery` for fetching dynamic fields attached to a parent -/// object. If `parent_version` is null, the latest version of each field within -/// the given checkpoint range [`lhs`, `rhs`] is returned, conditioned on the -/// fact that there is not a more recent version of the field. -/// -/// If `parent_version` is provided, it is used to bound both the `candidates` -/// and `newer` objects subqueries. This is because the dynamic fields of a -/// parent at version v are dynamic fields owned by the parent whose versions -/// are <= v. Unlike object ownership, where owned and owner objects -/// can have arbitrary `object_version`s, dynamic fields on a parent cannot have -/// a version greater than its parent. -fn dynamic_fields_query( - parent: SuiAddress, - parent_version: Option, - lhs: i64, - rhs: i64, - page: &Page, -) -> RawQuery { - build_objects_query( - View::Consistent, - lhs, - rhs, - page, - move |query| apply_filter(query, parent, parent_version), - move |newer| { - if let Some(parent_version) = parent_version { - filter!(newer, format!("object_version <= {}", parent_version)) - } else { - newer - } - }, - ) -} - -fn apply_filter(query: RawQuery, parent: SuiAddress, parent_version: Option) -> RawQuery { - let query = filter!( - query, - format!( - "owner_id = '\\x{}'::bytea AND owner_type = {} AND df_kind IS NOT NULL", - hex::encode(parent.into_vec()), - OwnerType::Object as i16 - ) - ); - - if let Some(version) = parent_version { - filter!(query, format!("object_version <= {}", version)) - } else { - query - } -} diff --git a/crates/sui-graphql-rpc/src/types/epoch.rs b/crates/sui-graphql-rpc/src/types/epoch.rs deleted file mode 100644 index 18987cf0e5d..00000000000 --- a/crates/sui-graphql-rpc/src/types/epoch.rs +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::{BTreeMap, BTreeSet, HashMap}; - -use async_graphql::{ - connection::Connection, - dataloader::{DataLoader, Loader}, - *, -}; -use diesel::{ExpressionMethods, OptionalExtension, QueryDsl, SelectableHelper}; -use fastcrypto::encoding::{Base58, Encoding}; -use sui_indexer::{models::epoch::QueryableEpochInfo, schema::epochs}; -use sui_types::messages_checkpoint::CheckpointCommitment as EpochCommitment; - -use super::{ - big_int::BigInt, - checkpoint::{self, Checkpoint, CheckpointId}, - cursor::Page, - date_time::DateTime, - protocol_config::ProtocolConfigs, - system_state_summary::SystemStateSummary, - transaction_block::{self, TransactionBlock, TransactionBlockFilter}, - validator_set::ValidatorSet, -}; -use crate::{ - context_data::db_data_provider::{convert_to_validators, PgManager}, - data::{Db, DbConnection, QueryExecutor}, - error::Error, -}; - -#[derive(Clone)] -pub(crate) struct Epoch { - pub stored: QueryableEpochInfo, - pub checkpoint_viewed_at: Option, -} - -/// DataLoader key for fetching an `Epoch` by its ID, optionally constrained by -/// a consistency cursor. -#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)] -struct EpochKey { - pub epoch_id: u64, - pub checkpoint_viewed_at: Option, -} - -/// Operation of the Sui network is temporally partitioned into non-overlapping -/// epochs, and the network aims to keep epochs roughly the same duration as -/// each other. During a particular epoch the following data is fixed: -/// -/// - the protocol version -/// - the reference gas price -/// - the set of participating validators -#[Object] -impl Epoch { - /// The epoch's id as a sequence number that starts at 0 and is incremented - /// by one at every epoch change. - async fn epoch_id(&self) -> u64 { - self.stored.epoch as u64 - } - - /// The minimum gas price that a quorum of validators are guaranteed to sign - /// a transaction for. - async fn reference_gas_price(&self) -> Option { - Some(BigInt::from(self.stored.reference_gas_price as u64)) - } - - /// Validator related properties, including the active validators. - async fn validator_set(&self, ctx: &Context<'_>) -> Result> { - let system_state = ctx - .data_unchecked::() - .fetch_sui_system_state(Some(self.stored.epoch as u64)) - .await?; - - let checkpoint_viewed_at = match self.checkpoint_viewed_at { - Some(value) => Ok(value), - None => Checkpoint::query_latest_checkpoint_sequence_number(ctx.data_unchecked()).await, - }?; - - let active_validators = - convert_to_validators(system_state.active_validators, None, checkpoint_viewed_at); - let validator_set = ValidatorSet { - total_stake: Some(BigInt::from(self.stored.total_stake)), - active_validators: Some(active_validators), - pending_removals: Some(system_state.pending_removals), - pending_active_validators_id: Some(system_state.pending_active_validators_id.into()), - pending_active_validators_size: Some(system_state.pending_active_validators_size), - staking_pool_mappings_id: Some(system_state.staking_pool_mappings_id.into()), - staking_pool_mappings_size: Some(system_state.staking_pool_mappings_size), - inactive_pools_id: Some(system_state.inactive_pools_id.into()), - inactive_pools_size: Some(system_state.inactive_pools_size), - validator_candidates_id: Some(system_state.validator_candidates_id.into()), - validator_candidates_size: Some(system_state.validator_candidates_size), - checkpoint_viewed_at, - }; - Ok(Some(validator_set)) - } - - /// The epoch's starting timestamp. - async fn start_timestamp(&self) -> Result { - DateTime::from_ms(self.stored.epoch_start_timestamp) - } - - /// The epoch's ending timestamp. - async fn end_timestamp(&self) -> Result, Error> { - self.stored - .epoch_end_timestamp - .map(DateTime::from_ms) - .transpose() - } - - /// The total number of checkpoints in this epoch. - async fn total_checkpoints(&self, ctx: &Context<'_>) -> Result> { - let last = match self.stored.last_checkpoint_id { - Some(last) => last as u64, - None => Checkpoint::query(ctx, CheckpointId::default(), None) - .await - .extend()? - .map_or(self.stored.first_checkpoint_id as u64, |c| { - c.sequence_number_impl() - }), - }; - Ok(Some(BigInt::from( - last - self.stored.first_checkpoint_id as u64, - ))) - } - - /// The total number of transaction blocks in this epoch. - async fn total_transactions(&self) -> Result> { - // TODO: this currently returns None for the current epoch. Fix this. - Ok(self.stored.epoch_total_transactions.map(|v| v as u64)) - } - - /// The total amount of gas fees (in MIST) that were paid in this epoch. - async fn total_gas_fees(&self) -> Option { - self.stored.total_gas_fees.map(BigInt::from) - } - - /// The total MIST rewarded as stake. - async fn total_stake_rewards(&self) -> Option { - self.stored - .total_stake_rewards_distributed - .map(BigInt::from) - } - - /// The amount added to total gas fees to make up the total stake rewards. - async fn total_stake_subsidies(&self) -> Option { - self.stored.stake_subsidy_amount.map(BigInt::from) - } - - /// The storage fund available in this epoch. - /// This fund is used to redistribute storage fees from past transactions - /// to future validators. - async fn fund_size(&self) -> Option { - Some(BigInt::from(self.stored.storage_fund_balance)) - } - - /// The difference between the fund inflow and outflow, representing - /// the net amount of storage fees accumulated in this epoch. - async fn net_inflow(&self) -> Option { - if let (Some(fund_inflow), Some(fund_outflow)) = - (self.stored.storage_charge, self.stored.storage_rebate) - { - Some(BigInt::from(fund_inflow - fund_outflow)) - } else { - None - } - } - - /// The storage fees paid for transactions executed during the epoch. - async fn fund_inflow(&self) -> Option { - self.stored.storage_charge.map(BigInt::from) - } - - /// The storage fee rebates paid to users who deleted the data associated - /// with past transactions. - async fn fund_outflow(&self) -> Option { - self.stored.storage_rebate.map(BigInt::from) - } - - /// The epoch's corresponding protocol configuration, including the feature - /// flags and the configuration options. - async fn protocol_configs(&self, ctx: &Context<'_>) -> Result { - ProtocolConfigs::query(ctx.data_unchecked(), Some(self.protocol_version())) - .await - .extend() - } - - #[graphql(flatten)] - async fn system_state_summary(&self, ctx: &Context<'_>) -> Result { - let state = ctx - .data_unchecked::() - .fetch_sui_system_state(Some(self.stored.epoch as u64)) - .await?; - Ok(SystemStateSummary { native: state }) - } - - /// A commitment by the committee at the end of epoch on the contents of the - /// live object set at that time. This can be used to verify state - /// snapshots. - async fn live_object_set_digest(&self) -> Result> { - let Some(commitments) = self.stored.epoch_commitments.as_ref() else { - return Ok(None); - }; - let commitments: Vec = bcs::from_bytes(commitments).map_err(|e| { - Error::Internal(format!("Error deserializing commitments: {e}")).extend() - })?; - - let digest = commitments.into_iter().next().map(|commitment| { - let EpochCommitment::ECMHLiveObjectSetDigest(digest) = commitment; - Base58::encode(digest.digest.into_inner()) - }); - - Ok(digest) - } - - /// The epoch's corresponding checkpoints. - async fn checkpoints( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - let epoch = self.stored.epoch as u64; - Checkpoint::paginate( - ctx.data_unchecked(), - page, - Some(epoch), - self.checkpoint_viewed_at, - ) - .await - .extend() - } - - /// The epoch's corresponding transaction blocks. - async fn transaction_blocks( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - filter: Option, - ) -> Result> { - let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - - #[allow(clippy::unnecessary_lazy_evaluations)] // rust-lang/rust-clippy#9422 - let Some(filter) = filter - .unwrap_or_default() - .intersect(TransactionBlockFilter { - after_checkpoint: (self.stored.first_checkpoint_id > 0) - .then(|| self.stored.first_checkpoint_id as u64 - 1), - before_checkpoint: self.stored.last_checkpoint_id.map(|id| id as u64 + 1), - ..Default::default() - }) - else { - return Ok(Connection::new(false, false)); - }; - - TransactionBlock::paginate( - ctx.data_unchecked(), - page, - filter, - self.checkpoint_viewed_at, - ) - .await - .extend() - } -} - -impl Epoch { - /// The epoch's protocol version. - pub(crate) fn protocol_version(&self) -> u64 { - self.stored.protocol_version as u64 - } - - /// Look up an `Epoch` in the database, optionally filtered by its Epoch ID. - /// If no ID is supplied, defaults to fetching the latest epoch. - pub(crate) async fn query( - ctx: &Context<'_>, - filter: Option, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - if let Some(epoch_id) = filter { - let dl: &DataLoader = ctx.data_unchecked(); - dl.load_one(EpochKey { - epoch_id, - checkpoint_viewed_at, - }) - .await - } else { - Self::query_latest_at(ctx.data_unchecked(), checkpoint_viewed_at).await - } - } - - /// Look up the latest `Epoch` from the database, optionally filtered by a - /// consistency cursor (querying for a consistency cursor in the past - /// looks for the latest epoch as of that cursor). - pub(crate) async fn query_latest_at( - db: &Db, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - use epochs::dsl; - - let (stored, checkpoint_viewed_at): (Option, u64) = db - .execute_repeatable(move |conn| { - let checkpoint_viewed_at = match checkpoint_viewed_at { - Some(value) => Ok(value), - None => Checkpoint::available_range(conn).map(|(_, rhs)| rhs), - }?; - - let stored = conn - .first(move || { - let mut query = dsl::epochs - .select(QueryableEpochInfo::as_select()) - .order_by(dsl::epoch.desc()) - .into_boxed(); - - // Bound the query on `checkpoint_viewed_at` by filtering for the epoch - // whose `first_checkpoint_id <= checkpoint_viewed_at`, selecting the epoch - // with the largest `first_checkpoint_id` among the filtered set. - query = query - .filter(dsl::first_checkpoint_id.le(checkpoint_viewed_at as i64)) - .order_by(dsl::first_checkpoint_id.desc()); - - query - }) - .optional()?; - - Ok::<_, diesel::result::Error>((stored, checkpoint_viewed_at)) - }) - .await - .map_err(|e| Error::Internal(format!("Failed to fetch epoch: {e}")))?; - - Ok(stored.map(|stored| Epoch { - stored, - checkpoint_viewed_at: Some(checkpoint_viewed_at), - })) - } -} - -#[async_trait::async_trait] -impl Loader for Db { - type Value = Epoch; - type Error = Error; - - async fn load(&self, keys: &[EpochKey]) -> Result, Error> { - use epochs::dsl; - - let epoch_ids: BTreeSet<_> = keys.iter().map(|key| key.epoch_id as i64).collect(); - let epochs: Vec = self - .execute_repeatable(move |conn| { - conn.results(move || { - dsl::epochs - .select(QueryableEpochInfo::as_select()) - .filter(dsl::epoch.eq_any(epoch_ids.iter().cloned())) - }) - }) - .await - .map_err(|e| Error::Internal(format!("Failed to fetch epochs: {e}")))?; - - let epoch_id_to_stored: BTreeMap<_, _> = epochs - .into_iter() - .map(|stored| (stored.epoch as u64, stored)) - .collect(); - - Ok(keys - .iter() - .filter_map(|key| { - let stored = epoch_id_to_stored.get(&key.epoch_id).cloned()?; - let epoch = Epoch { - stored, - checkpoint_viewed_at: key.checkpoint_viewed_at, - }; - - // We filter by checkpoint viewed at in memory because it should be quite rare - // that this query actually filters something (only in edge - // cases), and not trying to encode it in the SQL query makes - // the query much simpler and therefore easier for - // the DB to plan. - let start = epoch.stored.first_checkpoint_id as u64; - if matches!(key.checkpoint_viewed_at, Some(cp) if cp < start) { - None - } else { - Some((*key, epoch)) - } - }) - .collect()) - } -} diff --git a/crates/sui-graphql-rpc/src/types/event.rs b/crates/sui-graphql-rpc/src/types/event.rs deleted file mode 100644 index ced04864069..00000000000 --- a/crates/sui-graphql-rpc/src/types/event.rs +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::str::FromStr; - -use async_graphql::{ - connection::{Connection, CursorType, Edge}, - *, -}; -use diesel::{BoolExpressionMethods, ExpressionMethods, NullableExpressionMethods, QueryDsl}; -use serde::{Deserialize, Serialize}; -use sui_indexer::{ - models::{events::StoredEvent, transactions::StoredTransaction}, - schema::{events, transactions, tx_senders}, -}; -use sui_types::{ - base_types::{ObjectID, SuiAddress as NativeSuiAddress}, - event::Event as NativeEvent, - parse_sui_struct_tag, Identifier, -}; - -use super::{ - address::Address, - base64::Base64, - checkpoint::Checkpoint, - cursor::{self, Page, Paginated, Target}, - date_time::DateTime, - digest::Digest, - move_module::MoveModule, - move_value::MoveValue, - sui_address::SuiAddress, - type_filter::{ModuleFilter, TypeFilter}, -}; -use crate::{ - consistency::Checkpointed, - data::{self, Db, QueryExecutor}, - error::Error, -}; - -/// A Sui node emits one of the following events: -/// Move event -/// Publish event -/// Transfer object event -/// Delete object event -/// New object event -/// Epoch change event -#[derive(Clone, Debug)] -pub(crate) struct Event { - pub stored: Option, - pub native: NativeEvent, - /// The checkpoint sequence number this was viewed at. - pub checkpoint_viewed_at: u64, -} - -/// Contents of an Event's cursor. -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] -pub(crate) struct EventKey { - /// Transaction Sequence Number - tx: u64, - - /// Event Sequence Number - e: u64, - - /// The checkpoint sequence number this was viewed at. - #[serde(rename = "c")] - checkpoint_viewed_at: u64, -} - -pub(crate) type Cursor = cursor::JsonCursor; -type Query = data::Query; - -#[derive(InputObject, Clone, Default)] -pub(crate) struct EventFilter { - pub sender: Option, - pub transaction_digest: Option, - // Enhancement (post-MVP) - // after_checkpoint - // before_checkpoint - /// Events emitted by a particular module. An event is emitted by a - /// particular module if some function in the module is called by a - /// PTB and emits an event. - /// - /// Modules can be filtered by their package, or package::module. - pub emitting_module: Option, - - /// This field is used to specify the type of event emitted. - /// - /// Events can be filtered by their type's package, package::module, - /// or their fully qualified type name. - /// - /// Generic types can be queried by either the generic type name, e.g. - /// `0x2::coin::Coin`, or by the full type name, such as - /// `0x2::coin::Coin<0x2::sui::SUI>`. - pub event_type: Option, - // Enhancement (post-MVP) - // pub start_time - // pub end_time - - // Enhancement (post-MVP) - // pub any - // pub all - // pub not -} - -#[Object] -impl Event { - /// The Move module containing some function that when called by - /// a programmable transaction block (PTB) emitted this event. - /// For example, if a PTB invokes A::m1::foo, which internally - /// calls A::m2::emit_event to emit an event, - /// the sending module would be A::m1. - async fn sending_module(&self, ctx: &Context<'_>) -> Result> { - MoveModule::query( - ctx.data_unchecked(), - self.native.package_id.into(), - &self.native.transaction_module.to_string(), - self.checkpoint_viewed_at, - ) - .await - .extend() - } - - /// Address of the sender of the event - async fn sender(&self) -> Result> { - if self.native.sender == NativeSuiAddress::ZERO { - return Ok(None); - } - - Ok(Some(Address { - address: self.native.sender.into(), - checkpoint_viewed_at: Some(self.checkpoint_viewed_at), - })) - } - - /// UTC timestamp in milliseconds since epoch (1/1/1970) - async fn timestamp(&self) -> Result, Error> { - if let Some(stored) = &self.stored { - Ok(Some(DateTime::from_ms(stored.timestamp_ms)?)) - } else { - Ok(None) - } - } - - #[graphql(flatten)] - async fn move_value(&self) -> Result { - Ok(MoveValue::new( - self.native.type_.clone().into(), - Base64::from(self.native.contents.clone()), - )) - } -} - -impl Event { - /// Query the database for a `page` of events. The Page uses the - /// transaction, event, and checkpoint sequence numbers as the cursor to - /// determine the correct page of results. The query can optionally be - /// further `filter`-ed by the `EventFilter`. - /// - /// The `checkpoint_viewed_at` parameter is an Option representing the - /// checkpoint_sequence_number at which this page was queried for, or `None` - /// if the data was requested at the latest checkpoint. Each entity - /// returned in the connection will inherit this checkpoint, so that - /// when viewing that entity's state, it will be from the reference of this - /// checkpoint_viewed_at parameter. - /// - /// If the `Page` is set, then this function will defer to the - /// `checkpoint_viewed_at` in the cursor if they are consistent. - pub(crate) async fn paginate( - db: &Db, - page: Page, - filter: EventFilter, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - let cursor_viewed_at = page.validate_cursor_consistency()?; - let checkpoint_viewed_at: Option = cursor_viewed_at.or(checkpoint_viewed_at); - - let ((prev, next, results), checkpoint_viewed_at) = db - .execute_repeatable(move |conn| { - let checkpoint_viewed_at = match checkpoint_viewed_at { - Some(value) => Ok(value), - None => Checkpoint::available_range(conn).map(|(_, rhs)| rhs), - }?; - - let result = page.paginate_query::( - conn, - checkpoint_viewed_at, - move || { - let mut query = events::dsl::events.into_boxed(); - - // Bound events by the provided `checkpoint_viewed_at`. From EXPLAIN - // ANALYZE, using the checkpoint sequence number directly instead of - // translating into a transaction sequence number bound is more efficient. - query = query.filter( - events::dsl::checkpoint_sequence_number.le(checkpoint_viewed_at as i64), - ); - - // The transactions table doesn't have an index on the senders column, so - // use `tx_senders`. - if let Some(sender) = &filter.sender { - query = query.filter( - events::dsl::tx_sequence_number.eq_any( - tx_senders::dsl::tx_senders - .select(tx_senders::dsl::tx_sequence_number) - .filter(tx_senders::dsl::sender.eq(sender.into_vec())), - ), - ) - } - - if let Some(digest) = &filter.transaction_digest { - // Since the event filter takes in a single tx_digest, we know that - // there will only be one corresponding transaction. We can use - // single_value() to tell the query planner that we expect only one - // instead of a range of values, which will subsequently speed up query - // execution time. - query = query.filter( - events::dsl::tx_sequence_number.nullable().eq( - transactions::dsl::transactions - .select(transactions::dsl::tx_sequence_number) - .filter( - transactions::dsl::transaction_digest - .eq(digest.to_vec()), - ) - .single_value(), - ), - ) - } - - if let Some(module) = &filter.emitting_module { - query = module.apply(query, events::dsl::package, events::dsl::module); - } - - if let Some(type_) = &filter.event_type { - query = type_.apply(query, events::dsl::event_type); - } - - query - }, - )?; - - Ok::<_, diesel::result::Error>((result, checkpoint_viewed_at)) - }) - .await?; - - let mut conn = Connection::new(prev, next); - - // Defer to the provided checkpoint_viewed_at, but if it is not provided, use - // the current available range. This sets a consistent upper bound for - // the nested queries. - for stored in results { - let cursor = stored.cursor(checkpoint_viewed_at).encode_cursor(); - conn.edges.push(Edge::new( - cursor, - Event::try_from_stored_event(stored, checkpoint_viewed_at)?, - )); - } - - Ok(conn) - } - - pub(crate) fn try_from_stored_transaction( - stored_tx: &StoredTransaction, - idx: usize, - checkpoint_viewed_at: u64, - ) -> Result { - let Some(Some(serialized_event)) = stored_tx.events.get(idx) else { - return Err(Error::Internal(format!( - "Could not find event with event_sequence_number {} at transaction {}", - idx, stored_tx.tx_sequence_number - ))); - }; - - let native_event: NativeEvent = bcs::from_bytes(serialized_event).map_err(|_| { - Error::Internal(format!( - "Failed to deserialize event with {} at transaction {}", - idx, stored_tx.tx_sequence_number - )) - })?; - - let stored_event = StoredEvent { - tx_sequence_number: stored_tx.tx_sequence_number, - event_sequence_number: idx as i64, - transaction_digest: stored_tx.transaction_digest.clone(), - checkpoint_sequence_number: stored_tx.checkpoint_sequence_number, - senders: vec![Some(native_event.sender.to_vec())], - package: native_event.package_id.to_vec(), - module: native_event.transaction_module.to_string(), - event_type: native_event - .type_ - .to_canonical_string(/* with_prefix */ true), - bcs: native_event.contents.clone(), - timestamp_ms: stored_tx.timestamp_ms, - }; - - Ok(Self { - stored: Some(stored_event), - native: native_event, - checkpoint_viewed_at, - }) - } - - fn try_from_stored_event( - stored: StoredEvent, - checkpoint_viewed_at: u64, - ) -> Result { - let Some(Some(sender_bytes)) = stored.senders.first() else { - return Err(Error::Internal("No senders found for event".to_string())); - }; - let sender = NativeSuiAddress::from_bytes(sender_bytes) - .map_err(|e| Error::Internal(e.to_string()))?; - - let package_id = - ObjectID::from_bytes(&stored.package).map_err(|e| Error::Internal(e.to_string()))?; - let type_ = - parse_sui_struct_tag(&stored.event_type).map_err(|e| Error::Internal(e.to_string()))?; - let transaction_module = - Identifier::from_str(&stored.module).map_err(|e| Error::Internal(e.to_string()))?; - let contents = stored.bcs.clone(); - Ok(Event { - stored: Some(stored), - native: NativeEvent { - sender, - package_id, - transaction_module, - type_, - contents, - }, - checkpoint_viewed_at, - }) - } -} - -impl Paginated for StoredEvent { - type Source = events::table; - - fn filter_ge(cursor: &Cursor, query: Query) -> Query { - use events::dsl::{event_sequence_number as event, tx_sequence_number as tx}; - query.filter( - tx.gt(cursor.tx as i64) - .or(tx.eq(cursor.tx as i64).and(event.ge(cursor.e as i64))), - ) - } - - fn filter_le(cursor: &Cursor, query: Query) -> Query { - use events::dsl::{event_sequence_number as event, tx_sequence_number as tx}; - query.filter( - tx.lt(cursor.tx as i64) - .or(tx.eq(cursor.tx as i64).and(event.le(cursor.e as i64))), - ) - } - - fn order(asc: bool, query: Query) -> Query { - use events::dsl; - if asc { - query - .order_by(dsl::tx_sequence_number.asc()) - .then_order_by(dsl::event_sequence_number.asc()) - } else { - query - .order_by(dsl::tx_sequence_number.desc()) - .then_order_by(dsl::event_sequence_number.desc()) - } - } -} - -impl Target for StoredEvent { - fn cursor(&self, checkpoint_viewed_at: u64) -> Cursor { - Cursor::new(EventKey { - tx: self.tx_sequence_number as u64, - e: self.event_sequence_number as u64, - checkpoint_viewed_at, - }) - } -} - -impl Checkpointed for Cursor { - fn checkpoint_viewed_at(&self) -> u64 { - self.checkpoint_viewed_at - } -} diff --git a/crates/sui-graphql-rpc/src/types/gas.rs b/crates/sui-graphql-rpc/src/types/gas.rs deleted file mode 100644 index 8a1ce250117..00000000000 --- a/crates/sui-graphql-rpc/src/types/gas.rs +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_graphql::{connection::Connection, *}; -use sui_types::{ - effects::{TransactionEffects as NativeTransactionEffects, TransactionEffectsAPI}, - gas::GasCostSummary as NativeGasCostSummary, - transaction::GasData, -}; - -use super::{ - address::Address, - big_int::BigInt, - cursor::Page, - object::{self, ObjectFilter, ObjectKey, ObjectLookupKey}, - sui_address::SuiAddress, -}; -use crate::types::object::Object; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct GasInput { - pub owner: SuiAddress, - pub price: u64, - pub budget: u64, - pub payment_obj_keys: Vec, - /// The checkpoint sequence number at which this was viewed at, or None if - /// the data was requested at the latest checkpoint. - pub checkpoint_viewed_at: Option, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub(crate) struct GasCostSummary { - pub computation_cost: u64, - pub storage_cost: u64, - pub storage_rebate: u64, - pub non_refundable_storage_fee: u64, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub(crate) struct GasEffects { - pub summary: GasCostSummary, - pub object_id: SuiAddress, - pub object_version: u64, - /// The checkpoint sequence number this was viewed at. - pub checkpoint_viewed_at: u64, -} - -/// Configuration for this transaction's gas price and the coins used to pay for -/// gas. -#[Object] -impl GasInput { - /// Address of the owner of the gas object(s) used - async fn gas_sponsor(&self) -> Option
    { - Some(Address { - address: self.owner, - checkpoint_viewed_at: self.checkpoint_viewed_at, - }) - } - - /// Objects used to pay for a transaction's execution and storage - async fn gas_payment( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - // A possible user error during dry run or execution would be to supply a gas - // payment that is not a Move object (i.e a package). Even though the - // transaction would fail to run, this service will still attempt to - // present execution results. If the return type of this field - // is a `MoveObject`, then GraphQL will fail on the top-level with an internal - // error. Instead, we return an `Object` here, so that the rest of the - // `TransactionBlock` will still be viewable. - let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - - let filter = ObjectFilter { - object_keys: Some(self.payment_obj_keys.clone()), - ..Default::default() - }; - - Object::paginate( - ctx.data_unchecked(), - page, - filter, - self.checkpoint_viewed_at, - ) - .await - .extend() - } - - /// An unsigned integer specifying the number of native tokens per gas unit - /// this transaction will pay (in MIST). - async fn gas_price(&self) -> Option { - Some(BigInt::from(self.price)) - } - - /// The maximum number of gas units that can be expended by executing this - /// transaction - async fn gas_budget(&self) -> Option { - Some(BigInt::from(self.budget)) - } -} - -/// Breakdown of gas costs in effects. -#[Object] -impl GasCostSummary { - /// Gas paid for executing this transaction (in MIST). - async fn computation_cost(&self) -> Option { - Some(BigInt::from(self.computation_cost)) - } - - /// Gas paid for the data stored on-chain by this transaction (in MIST). - async fn storage_cost(&self) -> Option { - Some(BigInt::from(self.storage_cost)) - } - - /// Part of storage cost that can be reclaimed by cleaning up data created - /// by this transaction (when objects are deleted or an object is - /// modified, which is treated as a deletion followed by a creation) (in - /// MIST). - async fn storage_rebate(&self) -> Option { - Some(BigInt::from(self.storage_rebate)) - } - - /// Part of storage cost that is not reclaimed when data created by this - /// transaction is cleaned up (in MIST). - async fn non_refundable_storage_fee(&self) -> Option { - Some(BigInt::from(self.non_refundable_storage_fee)) - } -} - -/// Effects related to gas (costs incurred and the identity of the smashed gas -/// object returned). -#[Object] -impl GasEffects { - async fn gas_object(&self, ctx: &Context<'_>) -> Result> { - Object::query( - ctx.data_unchecked(), - self.object_id, - ObjectLookupKey::VersionAt { - version: self.object_version, - checkpoint_viewed_at: Some(self.checkpoint_viewed_at), - }, - ) - .await - .extend() - } - - async fn gas_summary(&self) -> Option<&GasCostSummary> { - Some(&self.summary) - } -} - -impl GasEffects { - /// `checkpoint_viewed_at` represents the checkpoint sequence number at - /// which this `GasEffects` was queried for, or `None` if the data was - /// requested at the latest checkpoint. This is stored on `GasEffects` - /// so that when viewing that entity's state, it will be as if it was - /// read at the same checkpoint. - pub(crate) fn from(effects: &NativeTransactionEffects, checkpoint_viewed_at: u64) -> Self { - let ((id, version, _digest), _owner) = effects.gas_object(); - Self { - summary: GasCostSummary::from(effects.gas_cost_summary()), - object_id: SuiAddress::from(id), - object_version: version.value(), - checkpoint_viewed_at, - } - } -} - -impl GasInput { - /// `checkpoint_viewed_at` represents the checkpoint sequence number at - /// which this `GasInput` was queried for, or `None` if the data was - /// requested at the latest checkpoint. This is stored on `GasInput` so - /// that when viewing that entity's state, it will be as if it was read - /// at the same checkpoint. - pub(crate) fn from(s: &GasData, checkpoint_viewed_at: Option) -> Self { - Self { - owner: s.owner.into(), - price: s.price, - budget: s.budget, - payment_obj_keys: s - .payment - .iter() - .map(|o| ObjectKey { - object_id: o.0.into(), - version: o.1.value(), - }) - .collect(), - checkpoint_viewed_at, - } - } -} - -impl From<&NativeGasCostSummary> for GasCostSummary { - fn from(gcs: &NativeGasCostSummary) -> Self { - Self { - computation_cost: gcs.computation_cost, - storage_cost: gcs.storage_cost, - storage_rebate: gcs.storage_rebate, - non_refundable_storage_fee: gcs.non_refundable_storage_fee, - } - } -} diff --git a/crates/sui-graphql-rpc/src/types/mod.rs b/crates/sui-graphql-rpc/src/types/mod.rs deleted file mode 100644 index f59d7910810..00000000000 --- a/crates/sui-graphql-rpc/src/types/mod.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub(crate) mod address; -pub(crate) mod available_range; -pub(crate) mod balance; -pub(crate) mod balance_change; -pub(crate) mod base64; -pub(crate) mod big_int; -pub(crate) mod chain_identifier; -pub(crate) mod checkpoint; -pub(crate) mod coin; -pub(crate) mod coin_metadata; -pub(crate) mod cursor; -pub(crate) mod date_time; -pub(crate) mod digest; -pub(crate) mod display; -pub(crate) mod dry_run_result; -pub(crate) mod dynamic_field; -pub(crate) mod epoch; -pub(crate) mod event; -pub(crate) mod execution_result; -pub(crate) mod gas; -pub(crate) mod intersect; -pub(crate) mod json; -pub(crate) mod move_function; -pub(crate) mod move_module; -pub(crate) mod move_object; -pub(crate) mod move_package; -pub(crate) mod move_struct; -pub(crate) mod move_type; -pub(crate) mod move_value; -pub(crate) mod object; -pub(crate) mod object_change; -pub(crate) mod object_read; -pub(crate) mod open_move_type; -pub(crate) mod owner; -pub(crate) mod protocol_config; -pub(crate) mod query; -pub(crate) mod safe_mode; -pub(crate) mod stake; -pub(crate) mod stake_subsidy; -pub(crate) mod storage_fund; -pub(crate) mod string_input; -pub(crate) mod sui_address; -pub(crate) mod suins_registration; -pub(crate) mod system_parameters; -pub(crate) mod system_state_summary; -pub(crate) mod transaction_block; -pub(crate) mod transaction_block_effects; -pub(crate) mod transaction_block_kind; -pub(crate) mod transaction_metadata; -pub(crate) mod type_filter; -pub(crate) mod unchanged_shared_object; -pub(crate) mod validator; -pub(crate) mod validator_credentials; -pub(crate) mod validator_set; -pub(crate) mod zklogin_verify_signature; diff --git a/crates/sui-graphql-rpc/src/types/move_package.rs b/crates/sui-graphql-rpc/src/types/move_package.rs deleted file mode 100644 index 616d7be953f..00000000000 --- a/crates/sui-graphql-rpc/src/types/move_package.rs +++ /dev/null @@ -1,474 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_graphql::{ - connection::{Connection, CursorType, Edge}, - *, -}; -use sui_package_resolver::{error::Error as PackageCacheError, Package as ParsedMovePackage}; -use sui_types::{move_package::MovePackage as NativeMovePackage, object::Data}; - -use super::{ - balance::{self, Balance}, - base64::Base64, - big_int::BigInt, - coin::Coin, - cursor::{JsonCursor, Page}, - move_module::MoveModule, - move_object::MoveObject, - object::{self, Object, ObjectFilter, ObjectImpl, ObjectLookupKey, ObjectOwner, ObjectStatus}, - owner::OwnerImpl, - stake::StakedSui, - sui_address::SuiAddress, - suins_registration::{DomainFormat, SuinsRegistration}, - transaction_block::{self, TransactionBlock, TransactionBlockFilter}, - type_filter::ExactTypeFilter, -}; -use crate::{ - consistency::ConsistentNamedCursor, data::Db, error::Error, types::checkpoint::Checkpoint, -}; - -#[derive(Clone)] -pub(crate) struct MovePackage { - /// Representation of this Move Object as a generic Object. - pub super_: Object, - - /// Move-object-specific data, extracted from the native representation at - /// `graphql_object.native_object.data`. - pub native: NativeMovePackage, - - /// The checkpoint sequence number this package was viewed at. - pub checkpoint_viewed_at: u64, -} - -/// Information used by a package to link to a specific version of its -/// dependency. -#[derive(SimpleObject)] -struct Linkage { - /// The ID on-chain of the first version of the dependency. - original_id: SuiAddress, - - /// The ID on-chain of the version of the dependency that this package - /// depends on. - upgraded_id: SuiAddress, - - /// The version of the dependency that this package depends on. - version: u64, -} - -/// Information about which previous versions of a package introduced its types. -#[derive(SimpleObject)] -struct TypeOrigin { - /// Module defining the type. - module: String, - - /// Name of the struct. - #[graphql(name = "struct")] - struct_: String, - - /// The storage ID of the package that first defined this type. - defining_id: SuiAddress, -} - -pub(crate) struct MovePackageDowncastError; - -pub(crate) type CModule = JsonCursor; - -/// A MovePackage is a kind of Move object that represents code that has been -/// published on chain. It exposes information about its modules, type -/// definitions, functions, and dependencies. -#[Object] -impl MovePackage { - pub(crate) async fn address(&self) -> SuiAddress { - OwnerImpl::from(&self.super_).address().await - } - - /// Objects owned by this package, optionally `filter`-ed. - /// - /// Note that objects owned by a package are inaccessible, because packages - /// are immutable and cannot be owned by an address. - pub(crate) async fn objects( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - filter: Option, - ) -> Result> { - OwnerImpl::from(&self.super_) - .objects(ctx, first, after, last, before, filter) - .await - } - - /// Total balance of all coins with marker type owned by this package. If - /// type is not supplied, it defaults to `0x2::sui::SUI`. - /// - /// Note that coins owned by a package are inaccessible, because packages - /// are immutable and cannot be owned by an address. - pub(crate) async fn balance( - &self, - ctx: &Context<'_>, - type_: Option, - ) -> Result> { - OwnerImpl::from(&self.super_).balance(ctx, type_).await - } - - /// The balances of all coin types owned by this package. - /// - /// Note that coins owned by a package are inaccessible, because packages - /// are immutable and cannot be owned by an address. - pub(crate) async fn balances( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(&self.super_) - .balances(ctx, first, after, last, before) - .await - } - - /// The coin objects owned by this package. - /// - /// `type` is a filter on the coin's type parameter, defaulting to - /// `0x2::sui::SUI`. - /// - /// Note that coins owned by a package are inaccessible, because packages - /// are immutable and cannot be owned by an address. - pub(crate) async fn coins( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - type_: Option, - ) -> Result> { - OwnerImpl::from(&self.super_) - .coins(ctx, first, after, last, before, type_) - .await - } - - /// The `0x3::staking_pool::StakedSui` objects owned by this package. - /// - /// Note that objects owned by a package are inaccessible, because packages - /// are immutable and cannot be owned by an address. - pub(crate) async fn staked_suis( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(&self.super_) - .staked_suis(ctx, first, after, last, before) - .await - } - - /// The domain explicitly configured as the default domain pointing to this - /// object. - pub(crate) async fn default_suins_name( - &self, - ctx: &Context<'_>, - format: Option, - ) -> Result> { - OwnerImpl::from(&self.super_) - .default_suins_name(ctx, format) - .await - } - - /// The SuinsRegistration NFTs owned by this package. These grant the owner - /// the capability to manage the associated domain. - /// - /// Note that objects owned by a package are inaccessible, because packages - /// are immutable and cannot be owned by an address. - pub(crate) async fn suins_registrations( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(&self.super_) - .suins_registrations(ctx, first, after, last, before) - .await - } - - pub(crate) async fn version(&self) -> u64 { - ObjectImpl(&self.super_).version().await - } - - /// The current status of the object as read from the off-chain store. The - /// possible states are: NOT_INDEXED, the object is loaded from - /// serialized data, such as the contents of a genesis or system package - /// upgrade transaction. LIVE, the version returned is the most recent for - /// the object, and it is not deleted or wrapped at that version. - /// HISTORICAL, the object was referenced at a specific version or - /// checkpoint, so is fetched from historical tables and may not be the - /// latest version of the object. WRAPPED_OR_DELETED, the object is deleted - /// or wrapped and only partial information can be loaded." - pub(crate) async fn status(&self) -> ObjectStatus { - ObjectImpl(&self.super_).status().await - } - - /// 32-byte hash that identifies the package's contents, encoded as a Base58 - /// string. - pub(crate) async fn digest(&self) -> Option { - ObjectImpl(&self.super_).digest().await - } - - /// The owner type of this object: Immutable, Shared, Parent, Address - /// Packages are always Immutable. - pub(crate) async fn owner(&self, ctx: &Context<'_>) -> Option { - ObjectImpl(&self.super_).owner(ctx).await - } - - /// The transaction block that published or upgraded this package. - pub(crate) async fn previous_transaction_block( - &self, - ctx: &Context<'_>, - ) -> Result> { - ObjectImpl(&self.super_) - .previous_transaction_block(ctx) - .await - } - - /// The amount of SUI we would rebate if this object gets deleted or - /// mutated. This number is recalculated based on the present storage - /// gas price. - /// - /// Note that packages cannot be deleted or mutated, so this number is - /// provided purely for reference. - pub(crate) async fn storage_rebate(&self) -> Option { - ObjectImpl(&self.super_).storage_rebate().await - } - - /// The transaction blocks that sent objects to this package. - /// - /// Note that objects that have been sent to a package become inaccessible. - pub(crate) async fn received_transaction_blocks( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - filter: Option, - ) -> Result> { - ObjectImpl(&self.super_) - .received_transaction_blocks(ctx, first, after, last, before, filter) - .await - } - - /// The Base64-encoded BCS serialization of the package's content. - pub(crate) async fn bcs(&self) -> Result> { - ObjectImpl(&self.super_).bcs().await - } - - /// A representation of the module called `name` in this package, including - /// the structs and functions it defines. - async fn module(&self, name: String) -> Result> { - self.module_impl(&name).extend() - } - - /// Paginate through the MoveModules defined in this package. - pub async fn modules( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result>> { - use std::ops::Bound as B; - - let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - let cursor_viewed_at = page.validate_cursor_consistency()?; - let checkpoint_viewed_at = cursor_viewed_at.unwrap_or(self.checkpoint_viewed_at); - - let parsed = self.parsed_package()?; - let module_range = parsed.modules().range::(( - page.after().map_or(B::Unbounded, |a| B::Excluded(&a.name)), - page.before().map_or(B::Unbounded, |b| B::Excluded(&b.name)), - )); - - let mut connection = Connection::new(false, false); - let modules = if page.is_from_front() { - module_range.take(page.limit()).collect() - } else { - let mut ms: Vec<_> = module_range.rev().take(page.limit()).collect(); - ms.reverse(); - ms - }; - - connection.has_previous_page = modules.first().is_some_and(|(fst, _)| { - parsed - .modules() - .range::((B::Unbounded, B::Excluded(*fst))) - .next() - .is_some() - }); - - connection.has_next_page = modules.last().is_some_and(|(lst, _)| { - parsed - .modules() - .range::((B::Excluded(*lst), B::Unbounded)) - .next() - .is_some() - }); - - for (name, parsed) in modules { - let Some(native) = self.native.serialized_module_map().get(name) else { - return Err(Error::Internal(format!( - "Module '{name}' exists in PackageCache but not in serialized map.", - )) - .extend()); - }; - - let cursor = JsonCursor::new(ConsistentNamedCursor { - name: name.clone(), - c: checkpoint_viewed_at, - }) - .encode_cursor(); - connection.edges.push(Edge::new( - cursor, - MoveModule { - storage_id: self.super_.address, - native: native.clone(), - parsed: parsed.clone(), - checkpoint_viewed_at, - }, - )) - } - - if connection.edges.is_empty() { - Ok(None) - } else { - Ok(Some(connection)) - } - } - - /// The transitive dependencies of this package. - async fn linkage(&self) -> Option> { - let linkage = self - .native - .linkage_table() - .iter() - .map(|(&runtime_id, upgrade_info)| Linkage { - original_id: runtime_id.into(), - upgraded_id: upgrade_info.upgraded_id.into(), - version: upgrade_info.upgraded_version.value(), - }) - .collect(); - - Some(linkage) - } - - /// The (previous) versions of this package that introduced its types. - async fn type_origins(&self) -> Option> { - let type_origins = self - .native - .type_origin_table() - .iter() - .map(|origin| TypeOrigin { - module: origin.module_name.clone(), - struct_: origin.struct_name.clone(), - defining_id: origin.package.into(), - }) - .collect(); - - Some(type_origins) - } - - /// BCS representation of the package's modules. Modules appear as a - /// sequence of pairs (module name, followed by module bytes), in - /// alphabetic order by module name. - async fn module_bcs(&self) -> Result> { - let bcs = bcs::to_bytes(self.native.serialized_module_map()) - .map_err(|_| { - Error::Internal(format!("Failed to serialize package {}", self.native.id())) - }) - .extend()?; - - Ok(Some(bcs.into())) - } -} - -impl MovePackage { - fn parsed_package(&self) -> Result { - // TODO: Leverage the package cache (attempt to read from it, and if that - // doesn't succeed, write back the parsed Package to the cache as well.) - let Some(native) = self.super_.native_impl() else { - return Err(Error::Internal( - "No native representation of package to parse.".to_string(), - )); - }; - - ParsedMovePackage::read(native) - .map_err(|e| Error::Internal(format!("Error reading package: {e}"))) - } - - pub(crate) fn module_impl(&self, name: &str) -> Result, Error> { - use PackageCacheError as E; - match ( - self.native.serialized_module_map().get(name), - self.parsed_package()?.module(name), - ) { - (Some(native), Ok(parsed)) => Ok(Some(MoveModule { - storage_id: self.super_.address, - native: native.clone(), - parsed: parsed.clone(), - checkpoint_viewed_at: self.checkpoint_viewed_at, - })), - - (None, _) | (_, Err(E::ModuleNotFound(_, _))) => Ok(None), - (_, Err(e)) => Err(Error::Internal(format!( - "Unexpected error fetching module: {e}" - ))), - } - } - - pub(crate) async fn query( - db: &Db, - address: SuiAddress, - key: ObjectLookupKey, - ) -> Result, Error> { - let Some(object) = Object::query(db, address, key).await? else { - return Ok(None); - }; - - let checkpoint_viewed_at = match object.checkpoint_viewed_at { - Some(value) => Ok(value), - None => Checkpoint::query_latest_checkpoint_sequence_number(db).await, - }?; - - Ok(Some( - MovePackage::try_from(&object, checkpoint_viewed_at) - .map_err(|_| Error::Internal(format!("{address} is not a package")))?, - )) - } - - pub(crate) fn try_from( - object: &Object, - checkpoint_viewed_at: u64, - ) -> Result { - let Some(native) = object.native_impl() else { - return Err(MovePackageDowncastError); - }; - - if let Data::Package(move_package) = &native.data { - Ok(Self { - super_: object.clone(), - native: move_package.clone(), - checkpoint_viewed_at, - }) - } else { - Err(MovePackageDowncastError) - } - } -} diff --git a/crates/sui-graphql-rpc/src/types/object.rs b/crates/sui-graphql-rpc/src/types/object.rs deleted file mode 100644 index c8573c6c0c5..00000000000 --- a/crates/sui-graphql-rpc/src/types/object.rs +++ /dev/null @@ -1,1561 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::BTreeMap, fmt::Write}; - -use async_graphql::{ - connection::{Connection, CursorType, Edge}, - *, -}; -use diesel::{CombineDsl, ExpressionMethods, OptionalExtension, QueryDsl}; -use move_core_types::{ - annotated_value::{MoveStruct, MoveTypeLayout}, - language_storage::StructTag, -}; -use serde::{Deserialize, Serialize}; -use sui_indexer::{ - models::objects::{StoredDeletedHistoryObject, StoredHistoryObject, StoredObject}, - schema::{objects, objects_history, objects_snapshot}, - types::{ObjectStatus as NativeObjectStatus, OwnerType}, -}; -use sui_package_resolver::Resolver; -use sui_types::{ - object::{ - bounded_visitor::BoundedVisitor, MoveObject as NativeMoveObject, Object as NativeObject, - Owner as NativeOwner, - }, - TypeTag, -}; - -use super::{ - balance::{self, Balance}, - big_int::BigInt, - checkpoint::Checkpoint, - coin::Coin, - coin_metadata::CoinMetadata, - cursor::{self, Page, Paginated, RawPaginated, Target}, - digest::Digest, - display::{Display, DisplayEntry}, - dynamic_field::{DynamicField, DynamicFieldName}, - move_object::MoveObject, - move_package::MovePackage, - owner::{Owner, OwnerImpl}, - stake::StakedSui, - sui_address::SuiAddress, - suins_registration::{DomainFormat, SuinsRegistration}, - transaction_block, - transaction_block::{TransactionBlock, TransactionBlockFilter}, - type_filter::{ExactTypeFilter, TypeFilter}, -}; -use crate::{ - consistency::{build_objects_query, consistent_range, Checkpointed, View}, - context_data::package_cache::PackageCache, - data::{self, Db, DbConnection, QueryExecutor}, - error::Error, - filter, or_filter, - raw_query::RawQuery, - types::{base64::Base64, intersect}, -}; - -#[derive(Clone, Debug)] -pub(crate) struct Object { - pub address: SuiAddress, - pub kind: ObjectKind, - /// The checkpoint sequence number at which this was viewed at, or None if - /// the data was requested at the latest checkpoint. - pub checkpoint_viewed_at: Option, -} - -/// Type to implement GraphQL fields that are shared by all Objects. -pub(crate) struct ObjectImpl<'o>(pub &'o Object); - -#[derive(Clone, Debug)] -pub(crate) enum ObjectKind { - /// An object loaded from serialized data, such as the contents of a - /// transaction. - NotIndexed(NativeObject), - /// An object fetched from the live objects table. - Live(NativeObject, StoredObject), - /// An object fetched from the snapshot or historical objects table. - Historical(NativeObject, StoredHistoryObject), - /// The object is wrapped or deleted and only partial information can be - /// loaded from the indexer. - WrappedOrDeleted(StoredDeletedHistoryObject), -} - -#[derive(Enum, Copy, Clone, Eq, PartialEq, Debug)] -#[graphql(name = "ObjectKind")] -pub enum ObjectStatus { - /// The object is loaded from serialized data, such as the contents of a - /// transaction. - NotIndexed, - /// The object is currently live and is not deleted or wrapped. - Live, - /// The object is referenced at some version, and thus is fetched from the - /// snapshot or historical objects table. - Historical, - /// The object is deleted or wrapped and only partial information can be - /// loaded from the indexer. - WrappedOrDeleted, -} - -#[derive(Clone, Debug, PartialEq, Eq, InputObject)] -pub(crate) struct ObjectRef { - /// ID of the object. - pub address: SuiAddress, - /// Version or sequence number of the object. - pub version: u64, - /// Digest of the object. - pub digest: Digest, -} - -/// Constrains the set of objects returned. All filters are optional, and the -/// resulting set of objects are ones whose -/// -/// - Type matches the `type` filter, -/// - AND, whose owner matches the `owner` filter, -/// - AND, whose ID is in `objectIds` OR whose ID and version is in -/// `objectKeys`. -#[derive(InputObject, Default, Debug, Clone, Eq, PartialEq)] -pub(crate) struct ObjectFilter { - /// This field is used to specify the type of objects that should be - /// included in the query results. - /// - /// Objects can be filtered by their type's package, package::module, or - /// their fully qualified type name. - /// - /// Generic types can be queried by either the generic type name, e.g. - /// `0x2::coin::Coin`, or by the full type name, such as - /// `0x2::coin::Coin<0x2::sui::SUI>`. - pub type_: Option, - - /// Filter for live objects by their current owners. - pub owner: Option, - - /// Filter for live objects by their IDs. - pub object_ids: Option>, - - /// Filter for live or potentially historical objects by their ID and - /// version. - pub object_keys: Option>, -} - -#[derive(InputObject, Debug, Clone, Eq, PartialEq)] -pub(crate) struct ObjectKey { - pub object_id: SuiAddress, - pub version: u64, -} - -/// The object's owner type: Immutable, Shared, Parent, or Address. -#[derive(Union, Clone)] -pub enum ObjectOwner { - Immutable(Immutable), - Shared(Shared), - Parent(Parent), - Address(AddressOwner), -} - -/// An immutable object is an object that can't be mutated, transferred, or -/// deleted. Immutable objects have no owner, so anyone can use them. -#[derive(SimpleObject, Clone)] -pub struct Immutable { - #[graphql(name = "_")] - dummy: Option, -} - -/// A shared object is an object that is shared using the -/// 0x2::transfer::share_object function. Unlike owned objects, once an object -/// is shared, it stays mutable and is accessible by anyone. -#[derive(SimpleObject, Clone)] -pub struct Shared { - initial_shared_version: u64, -} - -/// If the object's owner is a Parent, this object is part of a dynamic field -/// (it is the value of the dynamic field, or the intermediate Field object -/// itself). Also note that if the owner is a parent, then it's guaranteed to be -/// an object. -#[derive(SimpleObject, Clone)] -pub struct Parent { - parent: Option, -} - -/// An address-owned object is owned by a specific 32-byte address that is -/// either an account address (derived from a particular signature scheme) or -/// an object ID. An address-owned object is accessible only to its owner and no -/// others. -#[derive(SimpleObject, Clone)] -pub struct AddressOwner { - owner: Option, -} - -pub(crate) enum ObjectLookupKey { - Latest, - LatestAt(u64), - VersionAt { - version: u64, - /// The checkpoint sequence number at which this was viewed at, or None - /// if the data was requested at the latest checkpoint. - checkpoint_viewed_at: Option, - }, - LatestAtParentVersion { - /// The parent version to be used as the upper bound for the query. Look - /// for the latest version of a child object that is less than - /// or equal to this upper bound. - version: u64, - /// The checkpoint sequence number at which this was viewed at, or None - /// if the data was requested at the latest checkpoint. - checkpoint_viewed_at: Option, - }, -} - -pub(crate) type Cursor = cursor::BcsCursor; -type Query = data::Query; - -/// The inner struct for the `Object`'s cursor. The `object_id` is used as the -/// cursor, while the `checkpoint_viewed_at` sets the consistent upper bound for -/// the cursor. -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)] -pub(crate) struct HistoricalObjectCursor { - #[serde(rename = "o")] - object_id: Vec, - /// The checkpoint sequence number this was viewed at. - #[serde(rename = "c")] - checkpoint_viewed_at: u64, -} - -/// Interface implemented by on-chain values that are addressable by an ID (also -/// referred to as its address). This includes Move objects and packages. -#[derive(Interface)] -#[graphql( - name = "IObject", - field(name = "version", ty = "u64"), - field( - name = "status", - ty = "ObjectStatus", - desc = "The current status of the object as read from the off-chain store. The possible \ - states are: NOT_INDEXED, the object is loaded from serialized data, such as the \ - contents of a genesis or system package upgrade transaction. LIVE, the version \ - returned is the most recent for the object, and it is not deleted or wrapped at \ - that version. HISTORICAL, the object was referenced at a specific version or \ - checkpoint, so is fetched from historical tables and may not be the latest version \ - of the object. WRAPPED_OR_DELETED, the object is deleted or wrapped and only \ - partial information can be loaded." - ), - field( - name = "digest", - ty = "Option", - desc = "32-byte hash that identifies the object's current contents, encoded as a Base58 \ - string." - ), - field( - name = "owner", - ty = "Option", - desc = "The owner type of this object: Immutable, Shared, Parent, Address\n\ - Immutable and Shared Objects do not have owners." - ), - field( - name = "previous_transaction_block", - ty = "Option", - desc = "The transaction block that created this version of the object." - ), - field(name = "storage_rebate", ty = "Option", desc = "",), - field( - name = "received_transaction_blocks", - arg(name = "first", ty = "Option"), - arg(name = "after", ty = "Option"), - arg(name = "last", ty = "Option"), - arg(name = "before", ty = "Option"), - arg(name = "filter", ty = "Option"), - ty = "Connection", - desc = "The transaction blocks that sent objects to this object." - ), - field( - name = "bcs", - ty = "Option", - desc = "The Base64-encoded BCS serialization of the object's content." - ) -)] -pub(crate) enum IObject { - Object(Object), - MovePackage(MovePackage), - MoveObject(MoveObject), - Coin(Coin), - CoinMetadata(CoinMetadata), - StakedSui(StakedSui), - SuinsRegistration(SuinsRegistration), -} - -/// An object in Sui is a package (set of Move bytecode modules) or object -/// (typed data structure with fields) with additional metadata detailing its -/// id, version, transaction digest, owner field indicating how this object can -/// be accessed. -#[Object] -impl Object { - pub(crate) async fn address(&self) -> SuiAddress { - OwnerImpl::from(self).address().await - } - - /// Objects owned by this object, optionally `filter`-ed. - pub(crate) async fn objects( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - filter: Option, - ) -> Result> { - OwnerImpl::from(self) - .objects(ctx, first, after, last, before, filter) - .await - } - - /// Total balance of all coins with marker type owned by this object. If - /// type is not supplied, it defaults to `0x2::sui::SUI`. - pub(crate) async fn balance( - &self, - ctx: &Context<'_>, - type_: Option, - ) -> Result> { - OwnerImpl::from(self).balance(ctx, type_).await - } - - /// The balances of all coin types owned by this object. - pub(crate) async fn balances( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(self) - .balances(ctx, first, after, last, before) - .await - } - - /// The coin objects for this object. - /// - /// `type` is a filter on the coin's type parameter, defaulting to - /// `0x2::sui::SUI`. - pub(crate) async fn coins( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - type_: Option, - ) -> Result> { - OwnerImpl::from(self) - .coins(ctx, first, after, last, before, type_) - .await - } - - /// The `0x3::staking_pool::StakedSui` objects owned by this object. - pub(crate) async fn staked_suis( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(self) - .staked_suis(ctx, first, after, last, before) - .await - } - - /// The domain explicitly configured as the default domain pointing to this - /// object. - pub(crate) async fn default_suins_name( - &self, - ctx: &Context<'_>, - format: Option, - ) -> Result> { - OwnerImpl::from(self).default_suins_name(ctx, format).await - } - - /// The SuinsRegistration NFTs owned by this object. These grant the owner - /// the capability to manage the associated domain. - pub(crate) async fn suins_registrations( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(self) - .suins_registrations(ctx, first, after, last, before) - .await - } - - pub(crate) async fn version(&self) -> u64 { - ObjectImpl(self).version().await - } - - /// The current status of the object as read from the off-chain store. The - /// possible states are: NOT_INDEXED, the object is loaded from - /// serialized data, such as the contents of a genesis or system package - /// upgrade transaction. LIVE, the version returned is the most recent for - /// the object, and it is not deleted or wrapped at that version. - /// HISTORICAL, the object was referenced at a specific version or - /// checkpoint, so is fetched from historical tables and may not be the - /// latest version of the object. WRAPPED_OR_DELETED, the object is deleted - /// or wrapped and only partial information can be loaded." - pub(crate) async fn status(&self) -> ObjectStatus { - ObjectImpl(self).status().await - } - - /// 32-byte hash that identifies the object's current contents, encoded as a - /// Base58 string. - pub(crate) async fn digest(&self) -> Option { - ObjectImpl(self).digest().await - } - - /// The owner type of this object: Immutable, Shared, Parent, Address - /// Immutable and Shared Objects do not have owners. - pub(crate) async fn owner(&self, ctx: &Context<'_>) -> Option { - ObjectImpl(self).owner(ctx).await - } - - /// The transaction block that created this version of the object. - pub(crate) async fn previous_transaction_block( - &self, - ctx: &Context<'_>, - ) -> Result> { - ObjectImpl(self).previous_transaction_block(ctx).await - } - - /// The amount of SUI we would rebate if this object gets deleted or - /// mutated. This number is recalculated based on the present storage - /// gas price. - pub(crate) async fn storage_rebate(&self) -> Option { - ObjectImpl(self).storage_rebate().await - } - - /// The transaction blocks that sent objects to this object. - pub(crate) async fn received_transaction_blocks( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - filter: Option, - ) -> Result> { - ObjectImpl(self) - .received_transaction_blocks(ctx, first, after, last, before, filter) - .await - } - - /// The Base64-encoded BCS serialization of the object's content. - pub(crate) async fn bcs(&self) -> Result> { - ObjectImpl(self).bcs().await - } - - /// The set of named templates defined on-chain for the type of this object, - /// to be handled off-chain. The server substitutes data from the object - /// into these templates to generate a display string per template. - async fn display(&self, ctx: &Context<'_>) -> Result>> { - ObjectImpl(self).display(ctx).await - } - - /// Access a dynamic field on an object using its name. Names are arbitrary - /// Move values whose type have `copy`, `drop`, and `store`, and are - /// specified using their type, and their BCS contents, Base64 encoded. - /// - /// Dynamic fields on wrapped objects can be accessed by using the same API - /// under the Owner type. - async fn dynamic_field( - &self, - ctx: &Context<'_>, - name: DynamicFieldName, - ) -> Result> { - OwnerImpl::from(self) - .dynamic_field(ctx, name, Some(self.version_impl())) - .await - } - - /// Access a dynamic object field on an object using its name. Names are - /// arbitrary Move values whose type have `copy`, `drop`, and `store`, - /// and are specified using their type, and their BCS contents, Base64 - /// encoded. The value of a dynamic object field can also be accessed - /// off-chain directly via its address (e.g. using `Query.object`). - /// - /// Dynamic fields on wrapped objects can be accessed by using the same API - /// under the Owner type. - async fn dynamic_object_field( - &self, - ctx: &Context<'_>, - name: DynamicFieldName, - ) -> Result> { - OwnerImpl::from(self) - .dynamic_object_field(ctx, name, Some(self.version_impl())) - .await - } - - /// The dynamic fields and dynamic object fields on an object. - /// - /// Dynamic fields on wrapped objects can be accessed by using the same API - /// under the Owner type. - async fn dynamic_fields( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(self) - .dynamic_fields(ctx, first, after, last, before, Some(self.version_impl())) - .await - } - - /// Attempts to convert the object into a MoveObject - async fn as_move_object(&self) -> Option { - MoveObject::try_from(self).ok() - } - - /// Attempts to convert the object into a MovePackage - async fn as_move_package(&self, ctx: &Context<'_>) -> Option { - let Some(checkpoint_viewed_at) = match self.checkpoint_viewed_at { - Some(value) => Ok(value), - None => Checkpoint::query_latest_checkpoint_sequence_number(ctx.data_unchecked()).await, - } - .ok() else { - return None; - }; - - MovePackage::try_from(self, checkpoint_viewed_at).ok() - } -} - -impl ObjectImpl<'_> { - pub(crate) async fn version(&self) -> u64 { - self.0.version_impl() - } - - pub(crate) async fn status(&self) -> ObjectStatus { - ObjectStatus::from(&self.0.kind) - } - - pub(crate) async fn digest(&self) -> Option { - self.0 - .native_impl() - .map(|native| native.digest().base58_encode()) - } - - pub(crate) async fn owner(&self, ctx: &Context<'_>) -> Option { - use NativeOwner as O; - - let Some(native) = self.0.native_impl() else { - return None; - }; - - match native.owner { - O::AddressOwner(address) => { - let address = SuiAddress::from(address); - Some(ObjectOwner::Address(AddressOwner { - owner: Some(Owner { - address, - checkpoint_viewed_at: self.0.checkpoint_viewed_at, - }), - })) - } - O::Immutable => Some(ObjectOwner::Immutable(Immutable { dummy: None })), - O::ObjectOwner(address) => { - let parent = Object::query( - ctx.data_unchecked(), - address.into(), - ObjectLookupKey::Latest, - ) - .await - .ok() - .flatten(); - - Some(ObjectOwner::Parent(Parent { parent })) - } - O::Shared { - initial_shared_version, - } => Some(ObjectOwner::Shared(Shared { - initial_shared_version: initial_shared_version.value(), - })), - } - } - - pub(crate) async fn previous_transaction_block( - &self, - ctx: &Context<'_>, - ) -> Result> { - let Some(native) = self.0.native_impl() else { - return Ok(None); - }; - let digest = native.previous_transaction; - - TransactionBlock::query( - ctx.data_unchecked(), - digest.into(), - self.0.checkpoint_viewed_at, - ) - .await - .extend() - } - - pub(crate) async fn storage_rebate(&self) -> Option { - self.0 - .native_impl() - .map(|native| BigInt::from(native.storage_rebate)) - } - - pub(crate) async fn received_transaction_blocks( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - filter: Option, - ) -> Result> { - let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - - let Some(filter) = filter - .unwrap_or_default() - .intersect(TransactionBlockFilter { - recv_address: Some(self.0.address), - ..Default::default() - }) - else { - return Ok(Connection::new(false, false)); - }; - - TransactionBlock::paginate( - ctx.data_unchecked(), - page, - filter, - self.0.checkpoint_viewed_at, - ) - .await - .extend() - } - - pub(crate) async fn bcs(&self) -> Result> { - use ObjectKind as K; - Ok(match &self.0.kind { - K::WrappedOrDeleted(_) => None, - K::Live(_, stored) => Some(Base64::from(&stored.serialized_object)), - - // WrappedOrDeleted objects are also read from the historical objects table, and they do - // not have a serialized object, so the column is also nullable for stored historical - // objects. - K::Historical(_, stored) => stored.serialized_object.as_ref().map(Base64::from), - - K::NotIndexed(native) => { - let bytes = bcs::to_bytes(native) - .map_err(|e| { - Error::Internal(format!( - "Failed to serialize object at {}: {e}", - self.0.address - )) - }) - .extend()?; - Some(Base64::from(&bytes)) - } - }) - } - - /// `display` is part of the `IMoveObject` interface, but is implemented on - /// `ObjectImpl` to allow for a convenience function on `Object`. - pub(crate) async fn display(&self, ctx: &Context<'_>) -> Result>> { - let Some(native) = self.0.native_impl() else { - return Ok(None); - }; - - let move_object = native - .data - .try_as_move() - .ok_or_else(|| Error::Internal("Failed to convert object into MoveObject".to_string())) - .extend()?; - - let (struct_tag, move_struct) = deserialize_move_struct(move_object, ctx.data_unchecked()) - .await - .extend()?; - - let Some(display) = Display::query(ctx.data_unchecked(), struct_tag.into()) - .await - .extend()? - else { - return Ok(None); - }; - - Ok(Some(display.render(&move_struct).extend()?)) - } -} - -impl Object { - /// Construct a GraphQL object from a native object, without its stored - /// (indexed) counterpart. - /// - /// `checkpoint_viewed_at` represents the checkpoint sequence number at - /// which this `Object` was constructed in, or `None` if the data was - /// requested at the latest checkpoint. This is stored on `Object` so - /// that when viewing that entity's state, it will be as if it was - /// read at the same checkpoint. - pub(crate) fn from_native( - address: SuiAddress, - native: NativeObject, - checkpoint_viewed_at: Option, - ) -> Object { - Object { - address, - kind: ObjectKind::NotIndexed(native), - checkpoint_viewed_at, - } - } - - pub(crate) fn native_impl(&self) -> Option<&NativeObject> { - use ObjectKind as K; - - match &self.kind { - K::Live(native, _) | K::NotIndexed(native) | K::Historical(native, _) => Some(native), - K::WrappedOrDeleted(_) => None, - } - } - - pub(crate) fn version_impl(&self) -> u64 { - use ObjectKind as K; - - match &self.kind { - K::Live(native, _) | K::NotIndexed(native) | K::Historical(native, _) => { - native.version().value() - } - K::WrappedOrDeleted(stored) => stored.object_version as u64, - } - } - - /// Query the database for a `page` of objects, optionally `filter`-ed. - /// - /// `checkpoint_viewed_at` represents the checkpoint sequence number at - /// which this page was queried for, or `None` if the data was requested - /// at the latest checkpoint. Each entity returned in the connection - /// will inherit this checkpoint, so that when viewing that entity's - /// state, it will be as if it was read at the same checkpoint. - pub(crate) async fn paginate( - db: &Db, - page: Page, - filter: ObjectFilter, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - Self::paginate_subtype(db, page, filter, checkpoint_viewed_at, Ok).await - } - - /// Query the database for a `page` of some sub-type of Object. The page - /// uses the bytes of an Object ID and the checkpoint when the query was - /// made as the cursor, and can optionally be further `filter`-ed. The - /// subtype is created using the `downcast` function, which is allowed - /// to fail, if the downcast has failed. - /// - /// `checkpoint_viewed_at` represents the checkpoint sequence number at - /// which this page was queried for, or `None` if the data was requested - /// at the latest checkpoint. Each entity returned in the connection - /// will inherit this checkpoint, so that when viewing that entity's - /// state, it will be as if it was read at the same checkpoint. - /// - /// If a `Page` is also provided, then this function will defer to - /// the `checkpoint_viewed_at` in the cursors. Otherwise, use the value - /// from the parameter, or set to None. This is so that paginated - /// queries are consistent with the previous query that created the - /// cursor. - pub(crate) async fn paginate_subtype( - db: &Db, - page: Page, - filter: ObjectFilter, - checkpoint_viewed_at: Option, - downcast: impl Fn(Object) -> Result, - ) -> Result, Error> { - // If cursors are provided, defer to the `checkpoint_viewed_at` in the cursor if - // they are consistent. Otherwise, use the value from the parameter, or - // set to None. This is so that paginated queries are consistent with - // the previous query that created the cursor. - let cursor_viewed_at = page.validate_cursor_consistency()?; - let checkpoint_viewed_at: Option = cursor_viewed_at.or(checkpoint_viewed_at); - - let response = db - .execute_repeatable(move |conn| { - let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { - return Ok::<_, diesel::result::Error>(None); - }; - - let result = page.paginate_raw_query::( - conn, - rhs, - objects_query(&filter, lhs as i64, rhs as i64, &page), - )?; - - Ok(Some((result, rhs))) - }) - .await?; - - let Some(((prev, next, results), checkpoint_viewed_at)) = response else { - return Err(Error::Client( - "Requested data is outside the available range".to_string(), - )); - }; - - let mut conn: Connection = Connection::new(prev, next); - - for stored in results { - // To maintain consistency, the returned cursor should have the same upper-bound - // as the checkpoint found on the cursor. - let cursor = stored.cursor(checkpoint_viewed_at).encode_cursor(); - let object = - Object::try_from_stored_history_object(stored, Some(checkpoint_viewed_at))?; - conn.edges.push(Edge::new(cursor, downcast(object)?)); - } - - Ok(conn) - } - - /// Query for the object at a specific version, at the checkpoint_viewed_at - /// if given, else against the latest checkpoint. - /// - /// `checkpoint_viewed_at` represents the checkpoint sequence number at - /// which this `Object` was queried in, or `None` if the data was - /// requested at the latest checkpoint. This is stored on `Object` so - /// that when viewing that entity's state, it will be as if it was read at - /// the same checkpoint. - async fn query_at_version( - db: &Db, - address: SuiAddress, - version: u64, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - use objects_history::dsl as history; - use objects_snapshot::dsl as snapshot; - - let version = version as i64; - - let stored_objs: Option> = db - .execute_repeatable(move |conn| { - let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { - return Ok::<_, diesel::result::Error>(None); - }; - - conn.results(move || { - // If an object was created or mutated in a checkpoint outside the current - // available range, and never touched again, it will not show up in the - // objects_history table. Thus, we always need to check the objects_snapshot - // table as well. - let snapshot_query = snapshot::objects_snapshot - .filter(snapshot::object_id.eq(address.into_vec())) - .filter(snapshot::object_version.eq(version)); - - let historical_query = history::objects_history - .filter(history::object_id.eq(address.into_vec())) - .filter(history::object_version.eq(version)) - .filter(history::checkpoint_sequence_number.between(lhs as i64, rhs as i64)) - .order_by(history::object_version.desc()) - .limit(1); - - snapshot_query.union(historical_query) - }) - .optional() // Return optional to match the state when checkpoint_viewed_at is out of range - }) - .await?; - - let Some(stored_objs) = stored_objs else { - return Ok(None); - }; - - // Select the max by key after the union query, because Diesel currently does - // not support order_by on union - stored_objs - .into_iter() - .max_by_key(|o| o.object_version) - .map(|obj| Self::try_from_stored_history_object(obj, checkpoint_viewed_at)) - .transpose() - } - - /// Query for the latest version of an object bounded by the provided - /// `parent_version`. - /// - /// `checkpoint_viewed_at` represents the checkpoint sequence number at - /// which this `Object` was queried in, or `None` if the data was - /// requested at the latest checkpoint. This is stored on `Object` so - /// that when viewing that entity's state, it will be as if it was read at - /// the same checkpoint. - async fn query_latest_at_version( - db: &Db, - address: SuiAddress, - parent_version: u64, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - use objects_history::dsl as history; - use objects_snapshot::dsl as snapshot; - - let version = parent_version as i64; - - let stored_objs: Option> = db - .execute_repeatable(move |conn| { - let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { - return Ok::<_, diesel::result::Error>(None); - }; - - conn.results(move || { - // If an object was created or mutated in a checkpoint outside the current - // available range, and never touched again, it will not show up in the - // objects_history table. Thus, we always need to check the objects_snapshot - // table as well. - let snapshot_query = snapshot::objects_snapshot - .filter(snapshot::object_id.eq(address.into_vec())) - .filter(snapshot::object_version.le(version)); - - let historical_query = history::objects_history - .filter(history::object_id.eq(address.into_vec())) - .filter(history::object_version.le(version)) - .filter(history::checkpoint_sequence_number.between(lhs as i64, rhs as i64)) - .order_by(history::object_version.desc()) - .limit(1); - - snapshot_query.union(historical_query) - }) - .optional() // Return optional to match the state when checkpoint_viewed_at is out of range - }) - .await?; - - let Some(stored_objs) = stored_objs else { - return Ok(None); - }; - - // Select the max by key after the union query, because Diesel currently does - // not support order_by on union - stored_objs - .into_iter() - .max_by_key(|o| o.object_version) - .map(|obj| Self::try_from_stored_history_object(obj, checkpoint_viewed_at)) - .transpose() - } - - /// Query for the object at the latest version at the checkpoint sequence - /// number if given, else the latest version of the object against the - /// latest checkpoint. - async fn query_latest_at_checkpoint( - db: &Db, - address: SuiAddress, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - use objects_history::dsl as history; - use objects_snapshot::dsl as snapshot; - - let stored_objs: Option> = db - .execute_repeatable(move |conn| { - let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { - return Ok::<_, diesel::result::Error>(None); - }; - - conn.results(move || { - // If an object was created or mutated in a checkpoint outside the current - // available range, and never touched again, it will not show up in the - // objects_history table. Thus, we always need to check the objects_snapshot - // table as well. - let snapshot_query = snapshot::objects_snapshot - .filter(snapshot::object_id.eq(address.into_vec())); - - let historical_query = history::objects_history - .filter(history::object_id.eq(address.into_vec())) - .filter(history::checkpoint_sequence_number.between(lhs as i64, rhs as i64)) - .order_by(history::object_version.desc()) - .limit(1); - - snapshot_query.union(historical_query) - }) - .optional() // Return optional to match the state when checkpoint_viewed_at is out of range - }) - .await?; - - let Some(stored_objs) = stored_objs else { - return Ok(None); - }; - - // Select the max by key after the union query, because Diesel currently does - // not support order_by on union - stored_objs - .into_iter() - .max_by_key(|o| o.object_version) - .map(|obj| Self::try_from_stored_history_object(obj, checkpoint_viewed_at)) - .transpose() - } - - pub(crate) async fn query( - db: &Db, - address: SuiAddress, - key: ObjectLookupKey, - ) -> Result, Error> { - match key { - ObjectLookupKey::Latest => Self::query_latest_at_checkpoint(db, address, None).await, - ObjectLookupKey::LatestAt(checkpoint_sequence_number) => { - Self::query_latest_at_checkpoint(db, address, Some(checkpoint_sequence_number)) - .await - } - ObjectLookupKey::VersionAt { - version, - checkpoint_viewed_at, - } => Self::query_at_version(db, address, version, checkpoint_viewed_at).await, - ObjectLookupKey::LatestAtParentVersion { - version, - checkpoint_viewed_at, - } => Self::query_latest_at_version(db, address, version, checkpoint_viewed_at).await, - } - .map_err(|e| Error::Internal(format!("Failed to fetch object: {e}"))) - } - - /// Query for a singleton object identified by its type. Note: the object is - /// assumed to be a singleton (we either find at least one object with - /// this type and then return it, or return nothing). - pub(crate) async fn query_singleton(db: &Db, type_: TypeTag) -> Result, Error> { - use objects::dsl; - - let stored_obj: Option = db - .execute(move |conn| { - conn.first(move || { - dsl::objects.filter( - dsl::object_type.eq(type_.to_canonical_string(/* with_prefix */ true)), - ) - }) - .optional() - }) - .await - .map_err(|e| Error::Internal(format!("Failed to fetch singleton: {e}")))?; - - stored_obj - .map(|obj| Object::try_from_stored_object(obj, None)) - .transpose() - } - - /// `checkpoint_viewed_at` represents the checkpoint sequence number at - /// which this `Object` was constructed in, or `None` if the data was - /// requested at the latest checkpoint. This is stored on `Object` so - /// that when viewing that entity's state, it will be as if it was read at - /// the same checkpoint. - pub(crate) fn try_from_stored_object( - stored_object: StoredObject, - checkpoint_viewed_at: Option, - ) -> Result { - let address = addr(&stored_object.object_id)?; - let native_object = bcs::from_bytes(&stored_object.serialized_object) - .map_err(|_| Error::Internal(format!("Failed to deserialize object {address}")))?; - - Ok(Self { - address, - kind: ObjectKind::Live(native_object, stored_object), - checkpoint_viewed_at, - }) - } - - /// `checkpoint_viewed_at` represents the checkpoint sequence number at - /// which this `Object` was constructed in, or `None` if the data was - /// requested at the latest checkpoint. This is stored on `Object` so - /// that when viewing that entity's state, it will be as if it was read at - /// the same checkpoint. - pub(crate) fn try_from_stored_history_object( - history_object: StoredHistoryObject, - checkpoint_viewed_at: Option, - ) -> Result { - let address = addr(&history_object.object_id)?; - - let object_status = - NativeObjectStatus::try_from(history_object.object_status).map_err(|_| { - Error::Internal(format!( - "Unknown object status {} for object {} at version {}", - history_object.object_status, address, history_object.object_version - )) - })?; - - match object_status { - NativeObjectStatus::Active => { - let Some(serialized_object) = &history_object.serialized_object else { - return Err(Error::Internal(format!( - "Live object {} at version {} cannot have missing serialized_object field", - address, history_object.object_version - ))); - }; - - let native_object = bcs::from_bytes(serialized_object).map_err(|_| { - Error::Internal(format!("Failed to deserialize object {address}")) - })?; - - Ok(Self { - address, - kind: ObjectKind::Historical(native_object, history_object), - checkpoint_viewed_at, - }) - } - NativeObjectStatus::WrappedOrDeleted => Ok(Self { - address, - kind: ObjectKind::WrappedOrDeleted(StoredDeletedHistoryObject { - object_id: history_object.object_id, - object_version: history_object.object_version, - object_status: history_object.object_status, - checkpoint_sequence_number: history_object.checkpoint_sequence_number, - }), - checkpoint_viewed_at, - }), - } - } -} - -impl ObjectFilter { - /// Try to create a filter whose results are the intersection of objects in - /// `self`'s results and objects in `other`'s results. This may not be - /// possible if the resulting filter is inconsistent in some way (e.g. a - /// filter that requires one field to be two different values - /// simultaneously). - pub(crate) fn intersect(self, other: ObjectFilter) -> Option { - macro_rules! intersect { - ($field:ident, $body:expr) => { - intersect::field(self.$field, other.$field, $body) - }; - } - - // Treat `object_ids` and `object_keys` as a single filter on IDs, and - // optionally versions, and compute the intersection of that. - let keys = intersect::field(self.keys(), other.keys(), |k, l| { - let mut combined = BTreeMap::new(); - - for (id, v) in k { - if let Some(w) = l.get(&id).copied() { - combined.insert(id, intersect::field(v, w, intersect::by_eq)?); - } - } - - // If the intersection is empty, it means, there were some ID or Key filters in - // both `self` and `other`, but they don't overlap, so the final - // result is inconsistent. - (!combined.is_empty()).then_some(combined) - })?; - - // Extract the ID and Key filters back out. At this point, we know that if there - // were ID/Key filters in both `self` and `other`, then they intersected - // to form a consistent set of constraints, so it is safe to interpret - // the lack of any ID/Key filters respectively as a lack of that kind of - // constraint, rather than a constraint on the empty set. - - let object_ids = { - let partition: Vec<_> = keys - .iter() - .flatten() - .filter_map(|(id, v)| v.is_none().then_some(*id)) - .collect(); - - (!partition.is_empty()).then_some(partition) - }; - - let object_keys = { - let partition: Vec<_> = keys - .iter() - .flatten() - .filter_map(|(id, v)| { - Some(ObjectKey { - object_id: *id, - version: (*v)?, - }) - }) - .collect(); - - (!partition.is_empty()).then_some(partition) - }; - - Some(Self { - type_: intersect!(type_, TypeFilter::intersect)?, - owner: intersect!(owner, intersect::by_eq)?, - object_ids, - object_keys, - }) - } - - /// Extract the Object ID and Key filters into one combined map from Object - /// IDs in this filter, to the versions they should have (or None if the - /// filter mentions the ID but no version for it). - fn keys(&self) -> Option>> { - if self.object_keys.is_none() && self.object_ids.is_none() { - return None; - } - - Some(BTreeMap::from_iter( - self.object_keys - .iter() - .flatten() - .map(|key| (key.object_id, Some(key.version))) - // Chain ID filters after Key filters so if there is overlap, we overwrite the key - // filter with the ID filter. - .chain(self.object_ids.iter().flatten().map(|id| (*id, None))), - )) - } - - /// Applies ObjectFilter to the input `RawQuery` and returns a new - /// `RawQuery`. - pub(crate) fn apply(&self, mut query: RawQuery) -> RawQuery { - // Start by applying the filters on IDs and/or keys because they are combined as - // a disjunction, while the remaining queries are conjunctions. - if let Some(object_ids) = &self.object_ids { - // Maximally strict - match a vec of 0 elements - if object_ids.is_empty() { - query = or_filter!(query, "1=0"); - } else { - let mut inner = String::new(); - let mut prefix = "object_id IN ("; - for id in object_ids { - // SAFETY: Writing to a `String` cannot fail. - write!( - &mut inner, - "{prefix}'\\x{}'::bytea", - hex::encode(id.into_vec()) - ) - .unwrap(); - prefix = ","; - } - inner.push(')'); - query = or_filter!(query, inner); - } - } - - if let Some(object_keys) = &self.object_keys { - // Maximally strict - match a vec of 0 elements - if object_keys.is_empty() { - query = or_filter!(query, "1=0"); - } else { - let mut inner = String::new(); - let mut prefix = "("; - for ObjectKey { object_id, version } in object_keys { - // SAFETY: Writing to a `String` cannot fail. - write!( - &mut inner, - "{prefix}(object_id = '\\x{}'::bytea AND object_version = {})", - hex::encode(object_id.into_vec()), - version - ) - .unwrap(); - prefix = " OR "; - } - inner.push(')'); - query = or_filter!(query, inner); - } - } - - if let Some(owner) = self.owner { - query = filter!( - query, - format!( - "owner_id = '\\x{}'::bytea AND owner_type = {}", - hex::encode(owner.into_vec()), - OwnerType::Address as i16 - ) - ); - } - - if let Some(type_) = &self.type_ { - return type_.apply_raw(query, "object_type"); - } - - query - } - - pub(crate) fn has_filters(&self) -> bool { - self != &Default::default() - } -} - -impl HistoricalObjectCursor { - pub(crate) fn new(object_id: Vec, checkpoint_viewed_at: u64) -> Self { - Self { - object_id, - checkpoint_viewed_at, - } - } -} - -impl Checkpointed for Cursor { - fn checkpoint_viewed_at(&self) -> u64 { - self.checkpoint_viewed_at - } -} - -impl Paginated for StoredObject { - type Source = objects::table; - - fn filter_ge(cursor: &Cursor, query: Query) -> Query { - query.filter(objects::dsl::object_id.ge(cursor.object_id.clone())) - } - - fn filter_le(cursor: &Cursor, query: Query) -> Query { - query.filter(objects::dsl::object_id.le(cursor.object_id.clone())) - } - - fn order(asc: bool, query: Query) -> Query { - use objects::dsl; - if asc { - query.order_by(dsl::object_id.asc()) - } else { - query.order_by(dsl::object_id.desc()) - } - } -} - -impl Target for StoredObject { - fn cursor(&self, checkpoint_viewed_at: u64) -> Cursor { - Cursor::new(HistoricalObjectCursor::new( - self.object_id.clone(), - checkpoint_viewed_at, - )) - } -} - -impl RawPaginated for StoredHistoryObject { - fn filter_ge(cursor: &Cursor, query: RawQuery) -> RawQuery { - filter!( - query, - format!( - "candidates.object_id >= '\\x{}'::bytea", - hex::encode(cursor.object_id.clone()) - ) - ) - } - - fn filter_le(cursor: &Cursor, query: RawQuery) -> RawQuery { - filter!( - query, - format!( - "candidates.object_id <= '\\x{}'::bytea", - hex::encode(cursor.object_id.clone()) - ) - ) - } - - fn order(asc: bool, query: RawQuery) -> RawQuery { - if asc { - query.order_by("candidates.object_id ASC") - } else { - query.order_by("candidates.object_id DESC") - } - } -} - -impl Target for StoredHistoryObject { - fn cursor(&self, checkpoint_viewed_at: u64) -> Cursor { - Cursor::new(HistoricalObjectCursor::new( - self.object_id.clone(), - checkpoint_viewed_at, - )) - } -} - -impl From<&ObjectKind> for ObjectStatus { - fn from(kind: &ObjectKind) -> Self { - match kind { - ObjectKind::NotIndexed(_) => ObjectStatus::NotIndexed, - ObjectKind::Live(_, _) => ObjectStatus::Live, - ObjectKind::Historical(_, _) => ObjectStatus::Historical, - ObjectKind::WrappedOrDeleted(_) => ObjectStatus::WrappedOrDeleted, - } - } -} - -impl From<&Object> for OwnerImpl { - fn from(object: &Object) -> Self { - OwnerImpl { - address: object.address, - checkpoint_viewed_at: object.checkpoint_viewed_at, - } - } -} - -/// Parse a `SuiAddress` from its stored representation. Failure is an internal -/// error: the database should never contain a malformed address (containing the -/// wrong number of bytes). -fn addr(bytes: impl AsRef<[u8]>) -> Result { - SuiAddress::from_bytes(bytes.as_ref()).map_err(|e| { - let bytes = bytes.as_ref().to_vec(); - Error::Internal(format!("Error deserializing address: {bytes:?}: {e}")) - }) -} - -pub(crate) async fn deserialize_move_struct( - move_object: &NativeMoveObject, - resolver: &Resolver, -) -> Result<(StructTag, MoveStruct), Error> { - let struct_tag = StructTag::from(move_object.type_().clone()); - let contents = move_object.contents(); - let move_type_layout = resolver - .type_layout(TypeTag::from(struct_tag.clone())) - .await - .map_err(|e| { - Error::Internal(format!( - "Error fetching layout for type {}: {e}", - struct_tag.to_canonical_string(/* with_prefix */ true) - )) - })?; - - let MoveTypeLayout::Struct(layout) = move_type_layout else { - return Err(Error::Internal("Object is not a move struct".to_string())); - }; - - // TODO (annotated-visitor): Use custom visitors for extracting a dynamic field, - // and for creating a GraphQL MoveValue directly (not via an annotated - // visitor). - let move_struct = BoundedVisitor::deserialize_struct(contents, &layout).map_err(|e| { - Error::Internal(format!( - "Error deserializing move struct for type {}: {e}", - struct_tag.to_canonical_string(/* with_prefix */ true) - )) - })?; - - Ok((struct_tag, move_struct)) -} - -/// Constructs a raw query to fetch objects from the database. Objects are -/// filtered out if they satisfy the criteria but have a later version in the -/// same checkpoint. If object keys are provided, or no filters are specified at -/// all, then this final condition is not applied. -fn objects_query(filter: &ObjectFilter, lhs: i64, rhs: i64, page: &Page) -> RawQuery -where -{ - let view = if filter.object_keys.is_some() || !filter.has_filters() { - View::Historical - } else { - View::Consistent - }; - - build_objects_query( - view, - lhs, - rhs, - page, - move |query| filter.apply(query), - move |newer| newer, - ) -} - -#[cfg(test)] -mod tests { - use std::str::FromStr; - - use super::*; - - #[test] - fn test_owner_filter_intersection() { - let f0 = ObjectFilter { - owner: Some(SuiAddress::from_str("0x1").unwrap()), - ..Default::default() - }; - - let f1 = ObjectFilter { - owner: Some(SuiAddress::from_str("0x2").unwrap()), - ..Default::default() - }; - - assert_eq!(f0.clone().intersect(f0.clone()), Some(f0.clone())); - assert_eq!(f0.clone().intersect(f1.clone()), None); - } - - #[test] - fn test_key_filter_intersection() { - let i1 = SuiAddress::from_str("0x1").unwrap(); - let i2 = SuiAddress::from_str("0x2").unwrap(); - let i3 = SuiAddress::from_str("0x3").unwrap(); - let i4 = SuiAddress::from_str("0x4").unwrap(); - - let f0 = ObjectFilter { - object_ids: Some(vec![i1, i3]), - object_keys: Some(vec![ - ObjectKey { - object_id: i2, - version: 1, - }, - ObjectKey { - object_id: i4, - version: 2, - }, - ]), - ..Default::default() - }; - - let f1 = ObjectFilter { - object_ids: Some(vec![i1, i2]), - object_keys: Some(vec![ObjectKey { - object_id: i4, - version: 2, - }]), - ..Default::default() - }; - - let f2 = ObjectFilter { - object_ids: Some(vec![i1, i3]), - ..Default::default() - }; - - let f3 = ObjectFilter { - object_keys: Some(vec![ - ObjectKey { - object_id: i2, - version: 2, - }, - ObjectKey { - object_id: i4, - version: 2, - }, - ]), - ..Default::default() - }; - - assert_eq!( - f0.clone().intersect(f1.clone()), - Some(ObjectFilter { - object_ids: Some(vec![i1]), - object_keys: Some(vec![ - ObjectKey { - object_id: i2, - version: 1 - }, - ObjectKey { - object_id: i4, - version: 2 - }, - ]), - ..Default::default() - }) - ); - - assert_eq!( - f1.clone().intersect(f2.clone()), - Some(ObjectFilter { - object_ids: Some(vec![i1]), - ..Default::default() - }) - ); - - assert_eq!( - f1.clone().intersect(f3.clone()), - Some(ObjectFilter { - object_keys: Some(vec![ - ObjectKey { - object_id: i2, - version: 2 - }, - ObjectKey { - object_id: i4, - version: 2 - }, - ]), - ..Default::default() - }) - ); - - // i2 got a conflicting version assignment - assert_eq!(f0.clone().intersect(f3.clone()), None); - - // No overlap between these two. - assert_eq!(f2.clone().intersect(f3.clone()), None); - } -} diff --git a/crates/sui-graphql-rpc/src/types/object_change.rs b/crates/sui-graphql-rpc/src/types/object_change.rs deleted file mode 100644 index 8056edf7eba..00000000000 --- a/crates/sui-graphql-rpc/src/types/object_change.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_graphql::*; -use sui_types::effects::{IDOperation, ObjectChange as NativeObjectChange}; - -use super::{ - object::{Object, ObjectLookupKey}, - sui_address::SuiAddress, -}; - -pub(crate) struct ObjectChange { - pub native: NativeObjectChange, - /// The checkpoint sequence number this was viewed at. - pub checkpoint_viewed_at: u64, -} - -/// Effect on an individual Object (keyed by its ID). -#[Object] -impl ObjectChange { - /// The address of the object that has changed. - async fn address(&self) -> SuiAddress { - self.native.id.into() - } - - /// The contents of the object immediately before the transaction. - async fn input_state(&self, ctx: &Context<'_>) -> Result> { - let Some(version) = self.native.input_version else { - return Ok(None); - }; - - Object::query( - ctx.data_unchecked(), - self.native.id.into(), - ObjectLookupKey::VersionAt { - version: version.value(), - checkpoint_viewed_at: Some(self.checkpoint_viewed_at), - }, - ) - .await - .extend() - } - - /// The contents of the object immediately after the transaction. - async fn output_state(&self, ctx: &Context<'_>) -> Result> { - let Some(version) = self.native.output_version else { - return Ok(None); - }; - - Object::query( - ctx.data_unchecked(), - self.native.id.into(), - ObjectLookupKey::VersionAt { - version: version.value(), - checkpoint_viewed_at: Some(self.checkpoint_viewed_at), - }, - ) - .await - .extend() - } - - /// Whether the ID was created in this transaction. - async fn id_created(&self) -> Option { - Some(self.native.id_operation == IDOperation::Created) - } - - /// Whether the ID was deleted in this transaction. - async fn id_deleted(&self) -> Option { - Some(self.native.id_operation == IDOperation::Deleted) - } -} diff --git a/crates/sui-graphql-rpc/src/types/query.rs b/crates/sui-graphql-rpc/src/types/query.rs deleted file mode 100644 index a1ccb34c6ce..00000000000 --- a/crates/sui-graphql-rpc/src/types/query.rs +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::str::FromStr; - -use async_graphql::{connection::Connection, *}; -use fastcrypto::encoding::{Base64, Encoding}; -use move_core_types::account_address::AccountAddress; -use serde::de::DeserializeOwned; -use sui_json_rpc_types::DevInspectArgs; -use sui_sdk::SuiClient; -use sui_types::{ - gas_coin::GAS, - transaction::{TransactionData, TransactionDataAPI, TransactionKind}, - TypeTag, -}; - -use super::{ - address::Address, - available_range::AvailableRange, - chain_identifier::ChainIdentifier, - checkpoint::{self, Checkpoint, CheckpointId}, - coin::Coin, - coin_metadata::CoinMetadata, - cursor::Page, - digest::Digest, - dry_run_result::DryRunResult, - epoch::Epoch, - event::{self, Event, EventFilter}, - move_type::MoveType, - object::{self, Object, ObjectFilter, ObjectLookupKey}, - owner::Owner, - protocol_config::ProtocolConfigs, - sui_address::SuiAddress, - suins_registration::{Domain, NameService}, - transaction_block::{self, TransactionBlock, TransactionBlockFilter}, - transaction_metadata::TransactionMetadata, - type_filter::ExactTypeFilter, -}; -use crate::{ - config::ServiceConfig, - consistency::{consistent_range, CheckpointViewedAt}, - data::{Db, QueryExecutor}, - error::Error, - mutation::Mutation, - types::{ - base64::Base64 as GraphQLBase64, - zklogin_verify_signature::{ - verify_zklogin_signature, ZkLoginIntentScope, ZkLoginVerifyResult, - }, - }, -}; - -pub(crate) struct Query; -pub(crate) type SuiGraphQLSchema = async_graphql::Schema; - -#[Object] -impl Query { - /// First four bytes of the network's genesis checkpoint digest (uniquely - /// identifies the network). - async fn chain_identifier(&self, ctx: &Context<'_>) -> Result { - Ok(ChainIdentifier::query(ctx.data_unchecked()) - .await - .extend()? - .to_string()) - } - - /// Range of checkpoints that the RPC has data available for (for data - /// that can be tied to a particular checkpoint). - async fn available_range(&self, ctx: &Context<'_>) -> Result { - let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; - let result = ctx - .data_unchecked::() - .execute(move |conn| consistent_range(conn, Some(checkpoint_viewed_at))) - .await - .extend()?; - - match result { - Some((first, last)) => Ok(AvailableRange { first, last }), - None => Err(Error::Internal( - "Checkpoint watermark outside of available range from database".to_string(), - ) - .extend()), - } - } - - /// Configuration for this RPC service - async fn service_config(&self, ctx: &Context<'_>) -> Result { - ctx.data() - .map_err(|_| Error::Internal("Unable to fetch service configuration.".to_string())) - .cloned() - .extend() - } - - /// Simulate running a transaction to inspect its effects without - /// committing to them on-chain. - /// - /// `txBytes` either a `TransactionData` struct or a `TransactionKind` - /// struct, BCS-encoded and then Base64-encoded. The expected - /// type is controlled by the presence or absence of `txMeta`: If - /// present, `txBytes` is assumed to be a `TransactionKind`, if - /// absent, then `TransactionData`. - /// - /// `txMeta` the data that is missing from a `TransactionKind` to make - /// a `TransactionData` (sender address and gas information). All - /// its fields are nullable. - /// - /// `skipChecks` optional flag to disable the usual verification - /// checks that prevent access to objects that are owned by - /// addresses other than the sender, and calling non-public, - /// non-entry functions, and some other checks. Defaults to false. - async fn dry_run_transaction_block( - &self, - ctx: &Context<'_>, - tx_bytes: String, - tx_meta: Option, - skip_checks: Option, - ) -> Result { - let skip_checks = skip_checks.unwrap_or(false); - - let sui_sdk_client: &Option = ctx - .data() - .map_err(|_| Error::Internal("Unable to fetch Sui SDK client".to_string())) - .extend()?; - let sui_sdk_client = sui_sdk_client - .as_ref() - .ok_or_else(|| Error::Internal("Sui SDK client not initialized".to_string())) - .extend()?; - - let (sender_address, tx_kind, gas_price, gas_sponsor, gas_budget, gas_objects) = - if let Some(TransactionMetadata { - sender, - gas_price, - gas_objects, - gas_budget, - gas_sponsor, - }) = tx_meta - { - // This implies `TransactionKind` - let tx_kind = deserialize_tx_data::(&tx_bytes)?; - - // Default is 0x0 - let sender_address = sender.unwrap_or_else(|| AccountAddress::ZERO.into()).into(); - - let gas_sponsor = gas_sponsor.map(|addr| addr.into()); - - let gas_objects = gas_objects.map(|objs| { - objs.into_iter() - .map(|obj| (obj.address.into(), obj.version.into(), obj.digest.into())) - .collect() - }); - - ( - sender_address, - tx_kind, - gas_price.map(|p| p.into()), - gas_sponsor, - gas_budget.map(|b| b.into()), - gas_objects, - ) - } else { - // This implies `TransactionData` - let tx_data = deserialize_tx_data::(&tx_bytes)?; - - ( - tx_data.sender(), - tx_data.clone().into_kind(), - Some(tx_data.gas_price().into()), - Some(tx_data.gas_owner()), - Some(tx_data.gas_budget().into()), - Some(tx_data.gas().to_vec()), - ) - }; - - let dev_inspect_args = DevInspectArgs { - gas_sponsor, - gas_budget, - gas_objects, - show_raw_txn_data_and_effects: Some(true), - skip_checks: Some(skip_checks), - }; - - let res = sui_sdk_client - .read_api() - .dev_inspect_transaction_block( - sender_address, - tx_kind, - gas_price, - None, - Some(dev_inspect_args), - ) - .await?; - - DryRunResult::try_from(res).extend() - } - - async fn owner(&self, ctx: &Context<'_>, address: SuiAddress) -> Result> { - let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; - - Ok(Some(Owner { - address, - checkpoint_viewed_at: Some(checkpoint_viewed_at), - })) - } - - /// The object corresponding to the given address at the (optionally) given - /// version. When no version is given, the latest version is returned. - async fn object( - &self, - ctx: &Context<'_>, - address: SuiAddress, - version: Option, - ) -> Result> { - let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; - - match version { - Some(version) => Object::query( - ctx.data_unchecked(), - address, - ObjectLookupKey::VersionAt { - version, - checkpoint_viewed_at: Some(checkpoint_viewed_at), - }, - ) - .await - .extend(), - None => Object::query( - ctx.data_unchecked(), - address, - ObjectLookupKey::LatestAt(checkpoint_viewed_at), - ) - .await - .extend(), - } - } - - /// Look-up an Account by its SuiAddress. - async fn address(&self, ctx: &Context<'_>, address: SuiAddress) -> Result> { - let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; - - Ok(Some(Address { - address, - checkpoint_viewed_at: Some(checkpoint_viewed_at), - })) - } - - /// Fetch a structured representation of a concrete type, including its - /// layout information. Fails if the type is malformed. - async fn type_(&self, type_: String) -> Result { - Ok(MoveType::new( - TypeTag::from_str(&type_) - .map_err(|e| Error::Client(format!("Bad type: {e}"))) - .extend()?, - )) - } - - /// Fetch epoch information by ID (defaults to the latest epoch). - async fn epoch(&self, ctx: &Context<'_>, id: Option) -> Result> { - let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; - - Epoch::query(ctx, id, Some(checkpoint_viewed_at)) - .await - .extend() - } - - /// Fetch checkpoint information by sequence number or digest (defaults to - /// the latest available checkpoint). - async fn checkpoint( - &self, - ctx: &Context<'_>, - id: Option, - ) -> Result> { - let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; - - Checkpoint::query(ctx, id.unwrap_or_default(), Some(checkpoint_viewed_at)) - .await - .extend() - } - - /// Fetch a transaction block by its transaction digest. - async fn transaction_block( - &self, - ctx: &Context<'_>, - digest: Digest, - ) -> Result> { - let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; - - TransactionBlock::query(ctx.data_unchecked(), digest, Some(checkpoint_viewed_at)) - .await - .extend() - } - - /// The coin objects that exist in the network. - /// - /// The type field is a string of the inner type of the coin by which to - /// filter (e.g. `0x2::sui::SUI`). If no type is provided, it will - /// default to `0x2::sui::SUI`. - async fn coins( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - type_: Option, - ) -> Result> { - let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; - - let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - let coin = type_.map_or_else(GAS::type_tag, |t| t.0); - Coin::paginate( - ctx.data_unchecked(), - page, - coin, - // owner - None, - Some(checkpoint_viewed_at), - ) - .await - .extend() - } - - /// The checkpoints that exist in the network. - async fn checkpoints( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; - - let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - Checkpoint::paginate( - ctx.data_unchecked(), - page, - // epoch - None, - Some(checkpoint_viewed_at), - ) - .await - .extend() - } - - /// The transaction blocks that exist in the network. - async fn transaction_blocks( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - filter: Option, - ) -> Result> { - let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; - - let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - TransactionBlock::paginate( - ctx.data_unchecked(), - page, - filter.unwrap_or_default(), - Some(checkpoint_viewed_at), - ) - .await - .extend() - } - - /// The events that exist in the network. - async fn events( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - filter: Option, - ) -> Result> { - let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; - - let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - Event::paginate( - ctx.data_unchecked(), - page, - filter.unwrap_or_default(), - Some(checkpoint_viewed_at), - ) - .await - .extend() - } - - /// The objects that exist in the network. - async fn objects( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - filter: Option, - ) -> Result> { - let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; - - let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - Object::paginate( - ctx.data_unchecked(), - page, - filter.unwrap_or_default(), - Some(checkpoint_viewed_at), - ) - .await - .extend() - } - - /// Fetch the protocol config by protocol version (defaults to the latest - /// protocol version known to the GraphQL service). - async fn protocol_config( - &self, - ctx: &Context<'_>, - protocol_version: Option, - ) -> Result { - ProtocolConfigs::query(ctx.data_unchecked(), protocol_version) - .await - .extend() - } - - /// Resolves a SuiNS `domain` name to an address, if it has been bound. - async fn resolve_suins_address( - &self, - ctx: &Context<'_>, - domain: Domain, - ) -> Result> { - let CheckpointViewedAt(checkpoint_viewed_at) = *ctx.data()?; - Ok( - NameService::resolve_to_record(ctx, &domain, Some(checkpoint_viewed_at)) - .await - .extend()? - .and_then(|r| r.target_address) - .map(|a| Address { - address: a.into(), - checkpoint_viewed_at: Some(checkpoint_viewed_at), - }), - ) - } - - /// The coin metadata associated with the given coin type. - async fn coin_metadata( - &self, - ctx: &Context<'_>, - coin_type: ExactTypeFilter, - ) -> Result> { - CoinMetadata::query(ctx.data_unchecked(), coin_type.0) - .await - .extend() - } - - /// Verify a zkLogin signature based on the provided transaction or personal - /// message based on current epoch, chain id, and latest JWKs fetched - /// on-chain. If the signature is valid, the function returns a - /// `ZkLoginVerifyResult` with success as true and an empty list of - /// errors. If the signature is invalid, the function returns - /// a `ZkLoginVerifyResult` with success as false with a list of errors. - /// - /// - `bytes` is either the personal message in raw bytes or transaction - /// data bytes in BCS-encoded and then Base64-encoded. - /// - `signature` is a serialized zkLogin signature that is Base64-encoded. - /// - `intentScope` is an enum that specifies the intent scope to be used to - /// parse bytes. - /// - `author` is the address of the signer of the transaction or personal - /// msg. - async fn verify_zklogin_signature( - &self, - ctx: &Context<'_>, - bytes: GraphQLBase64, - signature: GraphQLBase64, - intent_scope: ZkLoginIntentScope, - author: SuiAddress, - ) -> Result { - verify_zklogin_signature(ctx, bytes, signature, intent_scope, author) - .await - .extend() - } -} - -fn deserialize_tx_data(tx_bytes: &str) -> Result -where - T: DeserializeOwned, -{ - bcs::from_bytes( - &Base64::decode(tx_bytes) - .map_err(|e| { - Error::Client(format!( - "Unable to deserialize transaction bytes from Base64: {e}" - )) - }) - .extend()?, - ) - .map_err(|e| { - Error::Client(format!( - "Unable to deserialize transaction bytes as BCS: {e}" - )) - }) - .extend() -} diff --git a/crates/sui-graphql-rpc/src/types/sui_address.rs b/crates/sui-graphql-rpc/src/types/sui_address.rs deleted file mode 100644 index e70f9bd70ac..00000000000 --- a/crates/sui-graphql-rpc/src/types/sui_address.rs +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::str::FromStr; - -use async_graphql::*; -use move_core_types::account_address::AccountAddress; -use serde::{Deserialize, Serialize}; -use sui_types::base_types::{ObjectID, SuiAddress as NativeSuiAddress}; -use thiserror::Error; - -const SUI_ADDRESS_LENGTH: usize = 32; - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Copy)] -pub(crate) struct SuiAddress([u8; SUI_ADDRESS_LENGTH]); - -#[derive(Error, Debug, Eq, PartialEq)] -pub(crate) enum FromStrError { - #[error("Invalid SuiAddress. Missing 0x prefix.")] - NoPrefix, - - #[error( - "Expected SuiAddress string with between 1 and {} digits ({} bytes), received {0}", - SUI_ADDRESS_LENGTH * 2, - SUI_ADDRESS_LENGTH, - )] - WrongLength(usize), - - #[error("Invalid character {0:?} at position {1}")] - BadHex(char, usize), -} - -#[derive(Error, Debug, Eq, PartialEq)] -pub(crate) enum FromVecError { - #[error("Expected SuiAddress with {} bytes, received {0}", SUI_ADDRESS_LENGTH)] - WrongLength(usize), -} - -impl SuiAddress { - pub fn from_array(arr: [u8; SUI_ADDRESS_LENGTH]) -> Self { - SuiAddress(arr) - } - - pub fn into_vec(self) -> Vec { - self.0.to_vec() - } - - pub fn as_slice(&self) -> &[u8] { - &self.0 - } - - pub fn from_bytes>(bytes: T) -> Result { - <[u8; SUI_ADDRESS_LENGTH]>::try_from(bytes.as_ref()) - .map_err(|_| FromVecError::WrongLength(bytes.as_ref().len())) - .map(SuiAddress) - } -} - -#[Scalar(use_type_description = true)] -impl ScalarType for SuiAddress { - fn parse(value: Value) -> InputValueResult { - let Value::String(s) = value else { - return Err(InputValueError::expected_type(value)); - }; - - Ok(SuiAddress::from_str(&s)?) - } - - fn to_value(&self) -> Value { - Value::String(format!("0x{}", hex::encode(self.0))) - } -} - -impl Description for SuiAddress { - fn description() -> &'static str { - "String containing 32B hex-encoded address, with a leading \"0x\". Leading zeroes can be \ - omitted on input but will always appear in outputs (SuiAddress in output is guaranteed \ - to be 66 characters long)." - } -} - -impl TryFrom> for SuiAddress { - type Error = FromVecError; - - fn try_from(bytes: Vec) -> Result { - Self::from_bytes(bytes) - } -} - -impl From for SuiAddress { - fn from(value: AccountAddress) -> Self { - SuiAddress(value.into_bytes()) - } -} - -impl From for AccountAddress { - fn from(value: SuiAddress) -> Self { - AccountAddress::new(value.0) - } -} - -impl From for SuiAddress { - fn from(value: ObjectID) -> Self { - SuiAddress(value.into_bytes()) - } -} - -impl From for ObjectID { - fn from(value: SuiAddress) -> Self { - ObjectID::new(value.0) - } -} - -impl From for SuiAddress { - fn from(value: NativeSuiAddress) -> Self { - SuiAddress(value.to_inner()) - } -} - -impl From for NativeSuiAddress { - fn from(value: SuiAddress) -> Self { - AccountAddress::from(value).into() - } -} - -impl FromStr for SuiAddress { - type Err = FromStrError; - - fn from_str(s: &str) -> Result { - let Some(s) = s.strip_prefix("0x") else { - return Err(FromStrError::NoPrefix); - }; - - if s.is_empty() || s.len() > SUI_ADDRESS_LENGTH * 2 { - return Err(FromStrError::WrongLength(s.len())); - } - - let mut arr = [0u8; SUI_ADDRESS_LENGTH]; - hex::decode_to_slice( - // Left pad with `0`-s up to SUI_ADDRESS_LENGTH * 2 characters long. - format!("{:0>width$}", s, width = SUI_ADDRESS_LENGTH * 2), - &mut arr[..], - ) - .map_err(|e| match e { - hex::FromHexError::InvalidHexCharacter { c, index } => { - FromStrError::BadHex(c, index + 2) - } - hex::FromHexError::OddLength => unreachable!("SAFETY: Prevented by padding"), - hex::FromHexError::InvalidStringLength => { - unreachable!("SAFETY: Prevented by bounds check") - } - })?; - - Ok(SuiAddress(arr)) - } -} - -impl std::fmt::Display for SuiAddress { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(&format!("0x{}", hex::encode(self.0))) - } -} - -#[cfg(test)] -mod tests { - use async_graphql::Value; - - use super::*; - - const STR_ADDRESS: &str = "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; - const ARR_ADDRESS: [u8; SUI_ADDRESS_LENGTH] = [ - 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, - 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, - ]; - const SUI_ADDRESS: SuiAddress = SuiAddress(ARR_ADDRESS); - - #[test] - fn test_parse_valid_suiaddress() { - let parsed = SuiAddress::from_str(STR_ADDRESS).unwrap(); - assert_eq!(parsed.0, ARR_ADDRESS); - } - - #[test] - fn test_to_value() { - let value = ScalarType::to_value(&SUI_ADDRESS); - assert_eq!(value, Value::String(STR_ADDRESS.to_string())); - } - - #[test] - fn test_from_array() { - let addr = SuiAddress::from_array(ARR_ADDRESS); - assert_eq!(addr, SUI_ADDRESS); - } - - #[test] - fn test_as_slice() { - assert_eq!(SUI_ADDRESS.as_slice(), &ARR_ADDRESS); - } - - #[test] - fn test_round_trip() { - let value = ScalarType::to_value(&SUI_ADDRESS); - let parsed_back = ScalarType::parse(value).unwrap(); - assert_eq!(SUI_ADDRESS, parsed_back); - } - - #[test] - fn test_parse_no_prefix() { - let err = SuiAddress::from_str(&STR_ADDRESS[2..]).unwrap_err(); - assert_eq!(FromStrError::NoPrefix, err); - } - - #[test] - fn test_parse_invalid_prefix() { - let input = "1x".to_string() + &STR_ADDRESS[2..]; - let err = SuiAddress::from_str(&input).unwrap_err(); - assert_eq!(FromStrError::NoPrefix, err) - } - - #[test] - fn test_parse_invalid_length() { - let input = STR_ADDRESS.to_string() + "0123"; - let err = SuiAddress::from_str(&input).unwrap_err(); - assert_eq!(FromStrError::WrongLength(68), err) - } - - #[test] - fn test_parse_invalid_characters() { - let input = "0xg".to_string() + &STR_ADDRESS[3..]; - let err = SuiAddress::from_str(&input).unwrap_err(); - assert_eq!(FromStrError::BadHex('g', 2), err); - } - - #[test] - fn test_unicode_gibberish() { - let parsed = SuiAddress::from_str("aAௗ0㌀0"); - assert!(parsed.is_err()); - } - - #[test] - fn bad_scalar_type() { - let input = Value::Number(0x42.into()); - let parsed = ::parse(input); - assert!(parsed.is_err()); - } -} diff --git a/crates/sui-graphql-rpc/src/types/suins_registration.rs b/crates/sui-graphql-rpc/src/types/suins_registration.rs deleted file mode 100644 index c4f7e093c3b..00000000000 --- a/crates/sui-graphql-rpc/src/types/suins_registration.rs +++ /dev/null @@ -1,635 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::str::FromStr; - -use async_graphql::{connection::Connection, *}; -use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; -use serde::{Deserialize, Serialize}; -use sui_indexer::models::objects::StoredHistoryObject; -use sui_json_rpc::name_service::{ - Domain as NativeDomain, NameRecord, NameServiceConfig, NameServiceError, -}; -use sui_types::{base_types::SuiAddress as NativeSuiAddress, dynamic_field::Field, id::UID}; - -use super::{ - balance::{self, Balance}, - base64::Base64, - big_int::BigInt, - checkpoint::Checkpoint, - coin::Coin, - cursor::Page, - display::DisplayEntry, - dynamic_field::{DynamicField, DynamicFieldName}, - move_object::{MoveObject, MoveObjectImpl}, - move_value::MoveValue, - object::{self, Object, ObjectFilter, ObjectImpl, ObjectLookupKey, ObjectOwner, ObjectStatus}, - owner::OwnerImpl, - stake::StakedSui, - string_input::impl_string_input, - sui_address::SuiAddress, - transaction_block::{self, TransactionBlock, TransactionBlockFilter}, - type_filter::ExactTypeFilter, -}; -use crate::{ - consistency::{build_objects_query, consistent_range, View}, - data::{Db, DbConnection, QueryExecutor}, - error::Error, -}; - -const MOD_REGISTRATION: &IdentStr = ident_str!("suins_registration"); -const TYP_REGISTRATION: &IdentStr = ident_str!("SuinsRegistration"); - -/// Represents the "core" of the name service (e.g. the on-chain registry and -/// reverse registry). It doesn't contain any fields because we look them up -/// based on the `NameServiceConfig`. -pub(crate) struct NameService; - -/// Wrap SuiNS Domain type to expose as a string scalar in GraphQL. -#[derive(Debug)] -pub(crate) struct Domain(NativeDomain); - -#[derive(Enum, Copy, Clone, Eq, PartialEq)] -#[graphql(remote = "sui_json_rpc::name_service::DomainFormat")] -pub enum DomainFormat { - At, - Dot, -} - -#[derive(Clone, Serialize, Deserialize)] -pub(crate) struct NativeSuinsRegistration { - pub id: UID, - pub domain: NativeDomain, - pub domain_name: String, - pub expiration_timestamp_ms: u64, - pub image_url: String, -} - -#[derive(Clone)] -pub(crate) struct SuinsRegistration { - /// Representation of this SuinsRegistration as a generic Move object. - pub super_: MoveObject, - - /// The deserialized representation of the Move object's contents. - pub native: NativeSuinsRegistration, -} - -/// Represents the results of a query for a domain's `NameRecord` and its -/// parent's `NameRecord`. The `expiration_timestamp_ms` on the name records are -/// compared to the checkpoint's timestamp to check that the domain is not -/// expired. -pub(crate) struct DomainExpiration { - /// The domain's `NameRecord`. - pub name_record: Option, - /// The parent's `NameRecord`, populated only if the domain is a subdomain. - pub parent_name_record: Option, - /// The timestamp of the checkpoint at which the query was made. This is - /// used to check if the `expiration_timestamp_ms` on the name records - /// are expired. - pub checkpoint_timestamp_ms: u64, -} - -pub(crate) enum SuinsRegistrationDowncastError { - NotASuinsRegistration, - Bcs(bcs::Error), -} - -#[Object] -impl SuinsRegistration { - pub(crate) async fn address(&self) -> SuiAddress { - OwnerImpl::from(&self.super_.super_).address().await - } - - /// Objects owned by this object, optionally `filter`-ed. - pub(crate) async fn objects( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - filter: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .objects(ctx, first, after, last, before, filter) - .await - } - - /// Total balance of all coins with marker type owned by this object. If - /// type is not supplied, it defaults to `0x2::sui::SUI`. - pub(crate) async fn balance( - &self, - ctx: &Context<'_>, - type_: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .balance(ctx, type_) - .await - } - - /// The balances of all coin types owned by this object. - pub(crate) async fn balances( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .balances(ctx, first, after, last, before) - .await - } - - /// The coin objects for this object. - /// - /// `type` is a filter on the coin's type parameter, defaulting to - /// `0x2::sui::SUI`. - pub(crate) async fn coins( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - type_: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .coins(ctx, first, after, last, before, type_) - .await - } - - /// The `0x3::staking_pool::StakedSui` objects owned by this object. - pub(crate) async fn staked_suis( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .staked_suis(ctx, first, after, last, before) - .await - } - - /// The domain explicitly configured as the default domain pointing to this - /// object. - pub(crate) async fn default_suins_name( - &self, - ctx: &Context<'_>, - format: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .default_suins_name(ctx, format) - .await - } - - /// The SuinsRegistration NFTs owned by this object. These grant the owner - /// the capability to manage the associated domain. - pub(crate) async fn suins_registrations( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .suins_registrations(ctx, first, after, last, before) - .await - } - - pub(crate) async fn version(&self) -> u64 { - ObjectImpl(&self.super_.super_).version().await - } - - /// The current status of the object as read from the off-chain store. The - /// possible states are: NOT_INDEXED, the object is loaded from - /// serialized data, such as the contents of a genesis or system package - /// upgrade transaction. LIVE, the version returned is the most recent for - /// the object, and it is not deleted or wrapped at that version. - /// HISTORICAL, the object was referenced at a specific version or - /// checkpoint, so is fetched from historical tables and may not be the - /// latest version of the object. WRAPPED_OR_DELETED, the object is deleted - /// or wrapped and only partial information can be loaded." - pub(crate) async fn status(&self) -> ObjectStatus { - ObjectImpl(&self.super_.super_).status().await - } - - /// 32-byte hash that identifies the object's contents, encoded as a Base58 - /// string. - pub(crate) async fn digest(&self) -> Option { - ObjectImpl(&self.super_.super_).digest().await - } - - /// The owner type of this object: Immutable, Shared, Parent, Address - pub(crate) async fn owner(&self, ctx: &Context<'_>) -> Option { - ObjectImpl(&self.super_.super_).owner(ctx).await - } - - /// The transaction block that created this version of the object. - pub(crate) async fn previous_transaction_block( - &self, - ctx: &Context<'_>, - ) -> Result> { - ObjectImpl(&self.super_.super_) - .previous_transaction_block(ctx) - .await - } - - /// The amount of SUI we would rebate if this object gets deleted or - /// mutated. This number is recalculated based on the present storage - /// gas price. - pub(crate) async fn storage_rebate(&self) -> Option { - ObjectImpl(&self.super_.super_).storage_rebate().await - } - - /// The transaction blocks that sent objects to this object. - pub(crate) async fn received_transaction_blocks( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - filter: Option, - ) -> Result> { - ObjectImpl(&self.super_.super_) - .received_transaction_blocks(ctx, first, after, last, before, filter) - .await - } - - /// The Base64-encoded BCS serialization of the object's content. - pub(crate) async fn bcs(&self) -> Result> { - ObjectImpl(&self.super_.super_).bcs().await - } - - /// Displays the contents of the Move object in a JSON string and through - /// GraphQL types. Also provides the flat representation of the type - /// signature, and the BCS of the corresponding data. - pub(crate) async fn contents(&self) -> Option { - MoveObjectImpl(&self.super_).contents().await - } - - /// Determines whether a transaction can transfer this object, using the - /// TransferObjects transaction command or - /// `sui::transfer::public_transfer`, both of which require the object to - /// have the `key` and `store` abilities. - pub(crate) async fn has_public_transfer(&self, ctx: &Context<'_>) -> Result { - MoveObjectImpl(&self.super_).has_public_transfer(ctx).await - } - - /// The set of named templates defined on-chain for the type of this object, - /// to be handled off-chain. The server substitutes data from the object - /// into these templates to generate a display string per template. - pub(crate) async fn display(&self, ctx: &Context<'_>) -> Result>> { - ObjectImpl(&self.super_.super_).display(ctx).await - } - - /// Access a dynamic field on an object using its name. Names are arbitrary - /// Move values whose type have `copy`, `drop`, and `store`, and are - /// specified using their type, and their BCS contents, Base64 encoded. - /// - /// Dynamic fields on wrapped objects can be accessed by using the same API - /// under the Owner type. - pub(crate) async fn dynamic_field( - &self, - ctx: &Context<'_>, - name: DynamicFieldName, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .dynamic_field(ctx, name, Some(self.super_.super_.version_impl())) - .await - } - - /// Access a dynamic object field on an object using its name. Names are - /// arbitrary Move values whose type have `copy`, `drop`, and `store`, - /// and are specified using their type, and their BCS contents, Base64 - /// encoded. The value of a dynamic object field can also be accessed - /// off-chain directly via its address (e.g. using `Query.object`). - /// - /// Dynamic fields on wrapped objects can be accessed by using the same API - /// under the Owner type. - pub(crate) async fn dynamic_object_field( - &self, - ctx: &Context<'_>, - name: DynamicFieldName, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .dynamic_object_field(ctx, name, Some(self.super_.super_.version_impl())) - .await - } - - /// The dynamic fields and dynamic object fields on an object. - /// - /// Dynamic fields on wrapped objects can be accessed by using the same API - /// under the Owner type. - pub(crate) async fn dynamic_fields( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - OwnerImpl::from(&self.super_.super_) - .dynamic_fields( - ctx, - first, - after, - last, - before, - Some(self.super_.super_.version_impl()), - ) - .await - } - - /// Domain name of the SuinsRegistration object - async fn domain(&self) -> &str { - &self.native.domain_name - } -} - -impl NameService { - /// Lookup the SuiNS NameRecord for the given `domain` name. `config` - /// specifies where to find the domain name registry, and its type. - /// - /// `checkpoint_viewed_at` represents the checkpoint sequence number at - /// which this was queried for, or `None` if the data was requested at - /// the latest checkpoint. - /// - /// The `NameRecord` is returned only if it has not expired as of the - /// `checkpoint_viewed_at` or latest checkpoint's timestamp. - /// - /// For leaf domains, the `NameRecord` is returned only if its parent is - /// valid and not expired. - pub(crate) async fn resolve_to_record( - ctx: &Context<'_>, - domain: &Domain, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - // Query for the domain's NameRecord and parent NameRecord if applicable. The - // checkpoint's timestamp is also fetched. These values are used to - // determine if the domain is expired. - let Some(domain_expiration) = - Self::query_domain_expiration(ctx, domain, checkpoint_viewed_at).await? - else { - return Ok(None); - }; - - // Get the name_record from the query. If we didn't find it, we return as it - // means that the requested name is not registered. - let Some(name_record) = domain_expiration.name_record else { - return Ok(None); - }; - - // If name record is SLD, or Node subdomain, we can check the expiration and - // return the record if not expired. - if !name_record.is_leaf_record() { - return if !name_record.is_node_expired(domain_expiration.checkpoint_timestamp_ms) { - Ok(Some(name_record)) - } else { - Err(Error::NameService(NameServiceError::NameExpired)) - }; - } - - // If we cannot find the parent, then the name is expired. - let Some(parent_name_record) = domain_expiration.parent_name_record else { - return Err(Error::NameService(NameServiceError::NameExpired)); - }; - - // If the parent is valid for this leaf, and not expired, then we can return the - // name record. Otherwise, the name is expired. - if parent_name_record.is_valid_leaf_parent(&name_record) - && !parent_name_record.is_node_expired(domain_expiration.checkpoint_timestamp_ms) - { - Ok(Some(name_record)) - } else { - Err(Error::NameService(NameServiceError::NameExpired)) - } - } - - /// Lookup the SuiNS Domain for the given `address`. `config` specifies - /// where to find the domain name registry, and its type. - /// - /// `checkpoint_viewed_at` represents the checkpoint sequence number at - /// which this was queried for, or `None` if the data was requested at - /// the latest checkpoint. - pub(crate) async fn reverse_resolve_to_name( - ctx: &Context<'_>, - address: SuiAddress, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - let config = ctx.data_unchecked::(); - - let reverse_record_id = config.reverse_record_field_id(address.as_slice()); - - let Some(object) = MoveObject::query( - ctx.data_unchecked(), - reverse_record_id.into(), - match checkpoint_viewed_at { - Some(checkpoint_viewed_at) => ObjectLookupKey::LatestAt(checkpoint_viewed_at), - None => ObjectLookupKey::Latest, - }, - ) - .await? - else { - return Ok(None); - }; - - let field: Field = object - .native - .to_rust() - .ok_or_else(|| Error::Internal("Malformed Suins Domain".to_string()))?; - - let domain = Domain(field.value); - - // We attempt to resolve the domain to a record, and if it fails, we return - // None. That way we can validate that the name has not expired and is - // still valid. - let Some(_) = Self::resolve_to_record(ctx, &domain, checkpoint_viewed_at).await? else { - return Ok(None); - }; - - Ok(Some(domain.0)) - } - - /// Query for a domain's NameRecord, its parent's NameRecord if supplied, - /// and the timestamp of the checkpoint bound. - async fn query_domain_expiration( - ctx: &Context<'_>, - domain: &Domain, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - let config = ctx.data_unchecked::(); - let db: &crate::data::pg::PgExecutor = ctx.data_unchecked::(); - // Construct the list of `object_id`s to look up. The first element is the - // domain's `NameRecord`. If the domain is a subdomain, there will be a - // second element for the parent's `NameRecord`. - let mut object_ids = vec![SuiAddress::from(config.record_field_id(&domain.0))]; - if domain.0.is_subdomain() { - object_ids.push(SuiAddress::from(config.record_field_id(&domain.0.parent()))); - } - - // Create a page with a bound of `object_ids` length to fetch the relevant - // `NameRecord`s. - let page: Page = Page::from_params( - ctx.data_unchecked(), - Some(object_ids.len() as u64), - None, - None, - None, - ) - .map_err(|_| { - Error::Internal("Page size of 2 is incompatible with configured limits".to_string()) - })?; - - // prepare the filter for the query. - let filter = ObjectFilter { - object_ids: Some(object_ids.clone()), - ..Default::default() - }; - - let response = db - .execute_repeatable(move |conn| { - let Some((lhs, rhs)) = consistent_range(conn, checkpoint_viewed_at)? else { - return Ok::<_, diesel::result::Error>(None); - }; - - let timestamp_ms = Checkpoint::query_timestamp(conn, rhs)?; - - let sql = build_objects_query( - View::Consistent, - lhs as i64, - rhs as i64, - &page, - move |query| filter.apply(query), - move |newer| newer, - ); - - let objects: Vec = - conn.results(move || sql.clone().into_boxed())?; - - Ok(Some((timestamp_ms, objects))) - }) - .await?; - - let Some((checkpoint_timestamp_ms, results)) = response else { - return Err(Error::Client( - "Requested data is outside the available range".to_string(), - )); - }; - - let mut domain_expiration = DomainExpiration { - parent_name_record: None, - name_record: None, - checkpoint_timestamp_ms, - }; - - // Max size of results is 2. We loop through them, convert to objects, and then - // parse name_record. We then assign it to the correct field on - // `domain_expiration` based on the address. - for result in results { - let object = Object::try_from_stored_history_object(result, None)?; - let move_object = MoveObject::try_from(&object).map_err(|_| { - Error::Internal(format!( - "Expected {0} to be a NameRecord, but it's not a Move Object.", - object.address - )) - })?; - - let record = NameRecord::try_from(move_object.native)?; - - if object.address == object_ids[0] { - domain_expiration.name_record = Some(record); - } else if Some(&object.address) == object_ids.get(1) { - domain_expiration.parent_name_record = Some(record); - } - } - - Ok(Some(domain_expiration)) - } -} - -impl SuinsRegistration { - /// Query the database for a `page` of SuiNS registrations. The page uses - /// the same cursor type as is used for `Object`, and is further - /// filtered to a particular `owner`. `config` specifies where to find - /// the domain name registry and its type. - /// - /// `checkpoint_viewed_at` represents the checkpoint sequence number at - /// which this page was queried for, or `None` if the data was requested - /// at the latest checkpoint. Each entity returned in the connection - /// will inherit this checkpoint, so that when viewing that entity's - /// state, it will be as if it was read at the same checkpoint. - pub(crate) async fn paginate( - db: &Db, - config: &NameServiceConfig, - page: Page, - owner: SuiAddress, - checkpoint_viewed_at: Option, - ) -> Result, Error> { - let type_ = SuinsRegistration::type_(config.package_address.into()); - - let filter = ObjectFilter { - type_: Some(type_.clone().into()), - owner: Some(owner), - ..Default::default() - }; - - Object::paginate_subtype(db, page, filter, checkpoint_viewed_at, |object| { - let address = object.address; - let move_object = MoveObject::try_from(&object).map_err(|_| { - Error::Internal(format!( - "Expected {address} to be a SuinsRegistration, but it's not a Move Object.", - )) - })?; - - SuinsRegistration::try_from(&move_object, &type_).map_err(|_| { - Error::Internal(format!( - "Expected {address} to be a SuinsRegistration, but it is not." - )) - }) - }) - .await - } - - /// Return the type representing a `SuinsRegistration` on chain. This can - /// change from chain to chain (mainnet, testnet, devnet etc). - pub(crate) fn type_(package: SuiAddress) -> StructTag { - StructTag { - address: package.into(), - module: MOD_REGISTRATION.to_owned(), - name: TYP_REGISTRATION.to_owned(), - type_params: vec![], - } - } - - // Because the type of the SuinsRegistration object is not constant, - // we need to take it in as a param. - pub(crate) fn try_from( - move_object: &MoveObject, - tag: &StructTag, - ) -> Result { - if !move_object.native.is_type(tag) { - return Err(SuinsRegistrationDowncastError::NotASuinsRegistration); - } - - Ok(Self { - super_: move_object.clone(), - native: bcs::from_bytes(move_object.native.contents()) - .map_err(SuinsRegistrationDowncastError::Bcs)?, - }) - } -} - -impl_string_input!(Domain); - -impl FromStr for Domain { - type Err = ::Err; - - fn from_str(s: &str) -> Result { - Ok(Domain(NativeDomain::from_str(s)?)) - } -} diff --git a/crates/sui-graphql-rpc/src/types/transaction_block_kind/genesis.rs b/crates/sui-graphql-rpc/src/types/transaction_block_kind/genesis.rs deleted file mode 100644 index 1cb8f881305..00000000000 --- a/crates/sui-graphql-rpc/src/types/transaction_block_kind/genesis.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_graphql::{ - connection::{Connection, CursorType, Edge}, - *, -}; -use sui_types::{ - digests::TransactionDigest, - object::Object as NativeObject, - transaction::{GenesisObject, GenesisTransaction as NativeGenesisTransaction}, -}; - -use crate::{ - consistency::ConsistentIndexCursor, - types::{ - cursor::{JsonCursor, Page}, - object::Object, - sui_address::SuiAddress, - }, -}; - -#[derive(Clone, PartialEq, Eq)] -pub(crate) struct GenesisTransaction { - pub native: NativeGenesisTransaction, - /// The checkpoint sequence number this was viewed at. - pub checkpoint_viewed_at: u64, -} - -pub(crate) type CObject = JsonCursor; - -/// System transaction that initializes the network and writes the initial set -/// of objects on-chain. -#[Object] -impl GenesisTransaction { - /// Objects to be created during genesis. - async fn objects( - &self, - ctx: &Context<'_>, - first: Option, - after: Option, - last: Option, - before: Option, - ) -> Result> { - let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - - let mut connection = Connection::new(false, false); - let Some((prev, next, _, cs)) = - page.paginate_consistent_indices(self.native.objects.len(), self.checkpoint_viewed_at)? - else { - return Ok(connection); - }; - - connection.has_previous_page = prev; - connection.has_next_page = next; - - for c in cs { - let GenesisObject::RawObject { data, owner } = self.native.objects[c.ix].clone(); - let native = - NativeObject::new_from_genesis(data, owner, TransactionDigest::genesis_marker()); - - let object = Object::from_native(SuiAddress::from(native.id()), native, Some(c.c)); - connection.edges.push(Edge::new(c.encode_cursor(), object)); - } - - Ok(connection) - } -} diff --git a/crates/sui-graphql-rpc/src/types/transaction_block_kind/mod.rs b/crates/sui-graphql-rpc/src/types/transaction_block_kind/mod.rs deleted file mode 100644 index e2e64f8de45..00000000000 --- a/crates/sui-graphql-rpc/src/types/transaction_block_kind/mod.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_graphql::*; -use sui_types::transaction::TransactionKind as NativeTransactionKind; - -use self::{ - consensus_commit_prologue::ConsensusCommitPrologueTransaction, - end_of_epoch::ChangeEpochTransaction, genesis::GenesisTransaction, - randomness_state_update::RandomnessStateUpdateTransaction, -}; -use crate::types::transaction_block_kind::{ - authenticator_state_update::AuthenticatorStateUpdateTransaction, - end_of_epoch::EndOfEpochTransaction, programmable::ProgrammableTransactionBlock, -}; - -pub(crate) mod authenticator_state_update; -pub(crate) mod consensus_commit_prologue; -pub(crate) mod end_of_epoch; -pub(crate) mod genesis; -pub(crate) mod programmable; -pub(crate) mod randomness_state_update; - -/// The kind of transaction block, either a programmable transaction or a system -/// transaction. -#[derive(Union, PartialEq, Clone, Eq)] -pub(crate) enum TransactionBlockKind { - ConsensusCommitPrologue(ConsensusCommitPrologueTransaction), - Genesis(GenesisTransaction), - ChangeEpoch(ChangeEpochTransaction), - Programmable(ProgrammableTransactionBlock), - AuthenticatorState(AuthenticatorStateUpdateTransaction), - Randomness(RandomnessStateUpdateTransaction), - EndOfEpoch(EndOfEpochTransaction), -} - -impl TransactionBlockKind { - pub(crate) fn from(kind: NativeTransactionKind, checkpoint_viewed_at: u64) -> Self { - use NativeTransactionKind as K; - use TransactionBlockKind as T; - - match kind { - K::ProgrammableTransaction(pt) => T::Programmable(ProgrammableTransactionBlock { - native: pt, - checkpoint_viewed_at, - }), - K::ChangeEpoch(ce) => T::ChangeEpoch(ChangeEpochTransaction { - native: ce, - checkpoint_viewed_at, - }), - K::Genesis(g) => T::Genesis(GenesisTransaction { - native: g, - checkpoint_viewed_at, - }), - K::ConsensusCommitPrologue(ccp) => T::ConsensusCommitPrologue( - ConsensusCommitPrologueTransaction::from_v1(ccp, checkpoint_viewed_at), - ), - K::ConsensusCommitPrologueV2(ccp) => T::ConsensusCommitPrologue( - ConsensusCommitPrologueTransaction::from_v2(ccp, checkpoint_viewed_at), - ), - K::AuthenticatorStateUpdate(asu) => { - T::AuthenticatorState(AuthenticatorStateUpdateTransaction { - native: asu, - checkpoint_viewed_at, - }) - } - K::EndOfEpochTransaction(eoe) => T::EndOfEpoch(EndOfEpochTransaction { - native: eoe, - checkpoint_viewed_at, - }), - K::RandomnessStateUpdate(rsu) => T::Randomness(RandomnessStateUpdateTransaction { - native: rsu, - checkpoint_viewed_at, - }), - } - } -} diff --git a/crates/sui-graphql-rpc/src/types/validator.rs b/crates/sui-graphql-rpc/src/types/validator.rs deleted file mode 100644 index 6b6df91cb63..00000000000 --- a/crates/sui-graphql-rpc/src/types/validator.rs +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_graphql::{ - connection::{Connection, CursorType, Edge}, - *, -}; -use sui_types::sui_system_state::sui_system_state_summary::SuiValidatorSummary as NativeSuiValidatorSummary; - -use super::{ - address::Address, base64::Base64, big_int::BigInt, move_object::MoveObject, - object::ObjectLookupKey, sui_address::SuiAddress, validator_credentials::ValidatorCredentials, -}; -use crate::{ - consistency::ConsistentIndexCursor, - context_data::db_data_provider::PgManager, - types::cursor::{JsonCursor, Page}, -}; - -#[derive(Clone, Debug)] -pub(crate) struct Validator { - pub validator_summary: NativeSuiValidatorSummary, - pub at_risk: Option, - pub report_records: Option>, - /// The checkpoint sequence number at which this was viewed at. - pub checkpoint_viewed_at: u64, -} - -type CAddr = JsonCursor; - -#[Object] -impl Validator { - /// The validator's address. - async fn address(&self) -> Address { - Address { - address: SuiAddress::from(self.validator_summary.sui_address), - checkpoint_viewed_at: Some(self.checkpoint_viewed_at), - } - } - - /// Validator's set of credentials such as public keys, network addresses - /// and others. - async fn credentials(&self) -> Option { - let v = &self.validator_summary; - let credentials = ValidatorCredentials { - protocol_pub_key: Some(Base64::from(v.protocol_pubkey_bytes.clone())), - network_pub_key: Some(Base64::from(v.network_pubkey_bytes.clone())), - worker_pub_key: Some(Base64::from(v.worker_pubkey_bytes.clone())), - proof_of_possession: Some(Base64::from(v.proof_of_possession_bytes.clone())), - net_address: Some(v.net_address.clone()), - p2p_address: Some(v.p2p_address.clone()), - primary_address: Some(v.primary_address.clone()), - worker_address: Some(v.worker_address.clone()), - }; - Some(credentials) - } - - /// Validator's set of credentials for the next epoch. - async fn next_epoch_credentials(&self) -> Option { - let v = &self.validator_summary; - let credentials = ValidatorCredentials { - protocol_pub_key: v - .next_epoch_protocol_pubkey_bytes - .as_ref() - .map(Base64::from), - network_pub_key: v.next_epoch_network_pubkey_bytes.as_ref().map(Base64::from), - worker_pub_key: v.next_epoch_worker_pubkey_bytes.as_ref().map(Base64::from), - proof_of_possession: v.next_epoch_proof_of_possession.as_ref().map(Base64::from), - net_address: v.next_epoch_net_address.clone(), - p2p_address: v.next_epoch_p2p_address.clone(), - primary_address: v.next_epoch_primary_address.clone(), - worker_address: v.next_epoch_worker_address.clone(), - }; - Some(credentials) - } - - /// Validator's name. - async fn name(&self) -> Option { - Some(self.validator_summary.name.clone()) - } - - /// Validator's description. - async fn description(&self) -> Option { - Some(self.validator_summary.description.clone()) - } - - /// Validator's url containing their custom image. - async fn image_url(&self) -> Option { - Some(self.validator_summary.image_url.clone()) - } - - /// Validator's homepage URL. - async fn project_url(&self) -> Option { - Some(self.validator_summary.project_url.clone()) - } - - /// The validator's current valid `Cap` object. Validators can delegate - /// the operation ability to another address. The address holding this `Cap` - /// object can then update the reference gas price and tallying rule on - /// behalf of the validator. - async fn operation_cap(&self, ctx: &Context<'_>) -> Result> { - MoveObject::query( - ctx.data_unchecked(), - self.operation_cap_id(), - ObjectLookupKey::LatestAt(self.checkpoint_viewed_at), - ) - .await - .extend() - } - - /// The validator's current staking pool object, used to track the amount of - /// stake and to compound staking rewards. - async fn staking_pool(&self, ctx: &Context<'_>) -> Result> { - MoveObject::query( - ctx.data_unchecked(), - self.staking_pool_id(), - ObjectLookupKey::LatestAt(self.checkpoint_viewed_at), - ) - .await - .extend() - } - - /// The validator's current exchange object. The exchange rate is used to - /// determine the amount of SUI tokens that each past SUI staker can - /// withdraw in the future. - async fn exchange_rates(&self, ctx: &Context<'_>) -> Result> { - MoveObject::query( - ctx.data_unchecked(), - self.exchange_rates_id(), - ObjectLookupKey::LatestAt(self.checkpoint_viewed_at), - ) - .await - .extend() - } - - /// Number of exchange rates in the table. - async fn exchange_rates_size(&self) -> Option { - Some(self.validator_summary.exchange_rates_size) - } - - /// The epoch at which this pool became active. - async fn staking_pool_activation_epoch(&self) -> Option { - self.validator_summary.staking_pool_activation_epoch - } - - /// The total number of SUI tokens in this pool. - async fn staking_pool_sui_balance(&self) -> Option { - Some(BigInt::from( - self.validator_summary.staking_pool_sui_balance, - )) - } - - /// The epoch stake rewards will be added here at the end of each epoch. - async fn rewards_pool(&self) -> Option { - Some(BigInt::from(self.validator_summary.rewards_pool)) - } - - /// Total number of pool tokens issued by the pool. - async fn pool_token_balance(&self) -> Option { - Some(BigInt::from(self.validator_summary.pool_token_balance)) - } - - /// Pending stake amount for this epoch. - async fn pending_stake(&self) -> Option { - Some(BigInt::from(self.validator_summary.pending_stake)) - } - - /// Pending stake withdrawn during the current epoch, emptied at epoch - /// boundaries. - async fn pending_total_sui_withdraw(&self) -> Option { - Some(BigInt::from( - self.validator_summary.pending_total_sui_withdraw, - )) - } - - /// Pending pool token withdrawn during the current epoch, emptied at epoch - /// boundaries. - async fn pending_pool_token_withdraw(&self) -> Option { - Some(BigInt::from( - self.validator_summary.pending_pool_token_withdraw, - )) - } - - /// The voting power of this validator in basis points (e.g., 100 = 1% - /// voting power). - async fn voting_power(&self) -> Option { - Some(self.validator_summary.voting_power) - } - - // TODO async fn stake_units(&self) -> Option{} - - /// The reference gas price for this epoch. - async fn gas_price(&self) -> Option { - Some(BigInt::from(self.validator_summary.gas_price)) - } - - /// The fee charged by the validator for staking services. - async fn commission_rate(&self) -> Option { - Some(self.validator_summary.commission_rate) - } - - /// The total number of SUI tokens in this pool plus - /// the pending stake amount for this epoch. - async fn next_epoch_stake(&self) -> Option { - Some(BigInt::from(self.validator_summary.next_epoch_stake)) - } - - /// The validator's gas price quote for the next epoch. - async fn next_epoch_gas_price(&self) -> Option { - Some(BigInt::from(self.validator_summary.next_epoch_gas_price)) - } - - /// The proposed next epoch fee for the validator's staking services. - async fn next_epoch_commission_rate(&self) -> Option { - Some(self.validator_summary.next_epoch_commission_rate) - } - - /// The number of epochs for which this validator has been below the - /// low stake threshold. - async fn at_risk(&self) -> Option { - self.at_risk - } - - /// The addresses of other validators this validator has reported. - async fn report_records( - &self, - ctx: &Context<'_>, - first: Option, - before: Option, - last: Option, - after: Option, - ) -> Result> { - let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?; - - let mut connection = Connection::new(false, false); - let Some(addresses) = &self.report_records else { - return Ok(connection); - }; - - let Some((prev, next, _, cs)) = - page.paginate_consistent_indices(addresses.len(), self.checkpoint_viewed_at)? - else { - return Ok(connection); - }; - - connection.has_previous_page = prev; - connection.has_next_page = next; - - for c in cs { - connection.edges.push(Edge::new( - c.encode_cursor(), - Address { - address: addresses[c.ix].address, - checkpoint_viewed_at: Some(c.c), - }, - )); - } - - Ok(connection) - } - - /// The APY of this validator in basis points. - /// To get the APY in percentage, divide by 100. - async fn apy(&self, ctx: &Context<'_>) -> Result, Error> { - Ok(ctx - .data_unchecked::() - .fetch_validator_apys(&self.validator_summary.sui_address) - .await? - .map(|x| (x * 10000.0) as u64)) - } -} - -impl Validator { - pub fn operation_cap_id(&self) -> SuiAddress { - SuiAddress::from_array(**self.validator_summary.operation_cap_id) - } - pub fn staking_pool_id(&self) -> SuiAddress { - SuiAddress::from_array(**self.validator_summary.staking_pool_id) - } - pub fn exchange_rates_id(&self) -> SuiAddress { - SuiAddress::from_array(**self.validator_summary.exchange_rates_id) - } -} diff --git a/crates/sui-graphql-rpc/tests/snapshot_tests.rs b/crates/sui-graphql-rpc/tests/snapshot_tests.rs deleted file mode 100644 index c1c2abc1332..00000000000 --- a/crates/sui-graphql-rpc/tests/snapshot_tests.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{fs::write, path::PathBuf}; - -use insta::assert_snapshot; -use sui_graphql_rpc::server::builder::export_schema; - -#[test] -fn test_schema_sdl_export() { - let sdl = export_schema(); - - // update the current schema file - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.extend(["schema", "current_progress_schema.graphql"]); - write(path, &sdl).unwrap(); - - assert_snapshot!(sdl); -} diff --git a/crates/sui-indexer/Cargo.toml b/crates/sui-indexer/Cargo.toml deleted file mode 100644 index 7aeb6e84589..00000000000 --- a/crates/sui-indexer/Cargo.toml +++ /dev/null @@ -1,70 +0,0 @@ -[package] -name = "sui-indexer" -version.workspace = true -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -async-trait.workspace = true -axum.workspace = true -backoff.workspace = true -bcs.workspace = true -chrono.workspace = true -serde_with.workspace = true -clap.workspace = true -tap.workspace = true -diesel.workspace = true -diesel-derive-enum.workspace = true -futures.workspace = true -itertools.workspace = true -jsonrpsee.workspace = true -prometheus.workspace = true -serde.workspace = true -serde_json.workspace = true -rayon.workspace = true -regex.workspace = true -thiserror.workspace = true -tracing.workspace = true -tokio = { workspace = true, features = ["full"] } -url.workspace = true - -fastcrypto = { workspace = true, features = ["copy_key"] } -mysten-metrics.workspace = true -sui-json.workspace = true -sui-json-rpc.workspace = true -sui-json-rpc-api.workspace = true -sui-json-rpc-types.workspace = true -sui-open-rpc.workspace = true -sui-sdk.workspace = true -sui-types.workspace = true -sui-package-resolver.workspace = true -sui-protocol-config.workspace = true -telemetry-subscribers.workspace = true -sui-rest-api.workspace = true -sui-transaction-builder.workspace = true - -move-core-types.workspace = true -move-bytecode-utils.workspace = true -move-binary-format.workspace = true - -diesel_migrations.workspace = true -cached.workspace = true - -[features] -pg_integration = [] - -[dev-dependencies] -sui-keys.workspace = true -sui-move-build.workspace = true -sui-test-transaction-builder.workspace = true -test-cluster.workspace = true -ntest.workspace = true -criterion.workspace = true -simulacrum.workspace = true - -[[bin]] -name = "sui-indexer" -path = "src/main.rs" diff --git a/crates/sui-indexer/README.md b/crates/sui-indexer/README.md deleted file mode 100644 index 618f7771a94..00000000000 --- a/crates/sui-indexer/README.md +++ /dev/null @@ -1,61 +0,0 @@ -Sui indexer is an off-fullnode service to serve data from Sui protocol, including both data directly generated from chain and derivative data. - -## Architecture -![enhanced_FN](https://user-images.githubusercontent.com/106119108/221022505-a1d873c6-60e2-45f1-b2aa-e50192c4dfbb.png) - -## Steps to run locally -### Prerequisites -- install local [Postgres server](https://www.postgresql.org/download/). You can also `brew install postgresql@15` and then add the following to your `~/.zshrc` or `~/.zprofile`, etc: -```sh -export LDFLAGS="-L/opt/homebrew/opt/postgresql@15/lib" -export CPPFLAGS="-I/opt/homebrew/opt/postgresql@15/include" -export PATH="/opt/homebrew/opt/postgresql@15/bin:$PATH" -``` -- make sure you have libpq installed: `brew install libpq`, and in your profile, add `export PATH="/opt/homebrew/opt/libpq/bin:$PATH"`. If this doesn't work, try `brew link --force libpq`. - -- install Diesel CLI with `cargo install diesel_cli --no-default-features --features postgres`, refer to [Diesel Getting Started guide](https://diesel.rs/guides/getting-started) for more details -- [optional but handy] Postgres client like [Postico](https://eggerapps.at/postico2/), for local check, query execution etc. - -### Start the Postgres Service - -Postgres must run as a service in the background for other tools to communicate with. If it was installed using homebrew, it can be started as a service with: - -``` sh -brew services start postgresql@version -``` - -### Local Development(Recommended) - -Use [sui-test-validator](../../crates/sui-test-validator/README.md) - -### Running standalone indexer -1. DB setup, under `sui/crates/sui-indexer` run: -```sh -# an example DATABASE_URL is "postgres://postgres:postgres@localhost/gegao" -diesel setup --database-url="" -diesel database reset --database-url="" -``` -Note that you'll need an existing database for the above to work. Replace `gegao` with the name of the database created. - -2. Checkout to your target branch - -For example, if you want to be on the DevNet branch -```sh -git fetch upstream devnet && git reset --hard upstream/devnet -``` -3. Start indexer binary, under `sui/crates/sui-indexer` run: -- run indexer as a writer, which pulls data from fullnode and writes data to DB -```sh -# Change the RPC_CLIENT_URL to http://0.0.0.0:9000 to run indexer against local validator & fullnode -cargo run --bin sui-indexer -- --db-url "" --rpc-client-url "https://fullnode.devnet.sui.io:443" --fullnode-sync-worker --reset-db -``` -- run indexer as a reader, which is a JSON RPC server with the [interface](https://docs.sui.io/sui-api-ref#suix_getallbalances) -``` -cargo run --bin sui-indexer -- --db-url "" --rpc-client-url "https://fullnode.devnet.sui.io:443" --rpc-server-worker -``` -More flags info can be found in this [file](https://github.com/MystenLabs/sui/blob/main/crates/sui-indexer/src/lib.rs#L83-L123). -### DB reset -Run this command under `sui/crates/sui-indexer`, which will wipe DB; In case of schema changes in `.sql` files, this will also update corresponding `schema.rs` file. -```sh -diesel database reset --database-url="" -``` diff --git a/crates/sui-indexer/migrations/2023-08-19-044020_events/up.sql b/crates/sui-indexer/migrations/2023-08-19-044020_events/up.sql deleted file mode 100644 index 567a687c39a..00000000000 --- a/crates/sui-indexer/migrations/2023-08-19-044020_events/up.sql +++ /dev/null @@ -1,24 +0,0 @@ -CREATE TABLE events -( - tx_sequence_number BIGINT NOT NULL, - event_sequence_number BIGINT NOT NULL, - transaction_digest bytea NOT NULL, - checkpoint_sequence_number bigint NOT NULL, - -- array of SuiAddress in bytes. All signers of the transaction. - senders bytea[] NOT NULL, - -- bytes of the entry package ID - package bytea NOT NULL, - -- entry module name - module text NOT NULL, - -- StructTag in Display format - event_type text NOT NULL, - timestamp_ms BIGINT NOT NULL, - -- bcs of the Event contents (Event.contents) - bcs BYTEA NOT NULL, - PRIMARY KEY(tx_sequence_number, event_sequence_number) -); - -CREATE INDEX events_package ON events (package, tx_sequence_number, event_sequence_number); -CREATE INDEX events_package_module ON events (package, module, tx_sequence_number, event_sequence_number); -CREATE INDEX events_event_type ON events (event_type text_pattern_ops, tx_sequence_number, event_sequence_number); -CREATE INDEX events_checkpoint_sequence_number ON events (checkpoint_sequence_number); diff --git a/crates/sui-indexer/migrations/2023-08-19-044023_objects/up.sql b/crates/sui-indexer/migrations/2023-08-19-044023_objects/up.sql deleted file mode 100644 index 38a0697d24b..00000000000 --- a/crates/sui-indexer/migrations/2023-08-19-044023_objects/up.sql +++ /dev/null @@ -1,89 +0,0 @@ -CREATE TABLE objects ( - object_id bytea PRIMARY KEY, - object_version bigint NOT NULL, - object_digest bytea NOT NULL, - checkpoint_sequence_number bigint NOT NULL, - -- Immutable/Address/Object/Shared, see types.rs - owner_type smallint NOT NULL, - -- bytes of SuiAddress/ObjectID of the owner ID. - -- Non-null for objects with an owner: Addresso or Objects - owner_id bytea, - -- Object type - object_type text, - -- bcs serialized Object - serialized_object bytea NOT NULL, - -- Non-null when the object is a coin. - -- e.g. `0x2::sui::SUI` - coin_type text, - -- Non-null when the object is a coin. - coin_balance bigint, - -- DynamicField/DynamicObject, see types.rs - -- Non-null when the object is a dynamic field - df_kind smallint, - -- bcs serialized DynamicFieldName - -- Non-null when the object is a dynamic field - df_name bytea, - -- object_type in DynamicFieldInfo. - df_object_type text, - -- object_id in DynamicFieldInfo. - df_object_id bytea -); - --- OwnerType: 1: Address, 2: Object, see types.rs -CREATE INDEX objects_owner ON objects (owner_type, owner_id) WHERE owner_type BETWEEN 1 AND 2 AND owner_id IS NOT NULL; -CREATE INDEX objects_coin ON objects (owner_id, coin_type) WHERE coin_type IS NOT NULL AND owner_type = 1; -CREATE INDEX objects_checkpoint_sequence_number ON objects (checkpoint_sequence_number); -CREATE INDEX objects_type ON objects (object_type); - --- similar to objects table, except that --- 1. the primary key to store multiple object versions and partitions by checkpoint_sequence_number --- 2. allow null values in some columns for deleted / wrapped objects --- 3. object_status to mark the status of the object, which is either Active or WrappedOrDeleted -CREATE TABLE objects_history ( - object_id bytea NOT NULL, - object_version bigint NOT NULL, - object_status smallint NOT NULL, - object_digest bytea, - checkpoint_sequence_number bigint NOT NULL, - owner_type smallint, - owner_id bytea, - object_type text, - serialized_object bytea, - coin_type text, - coin_balance bigint, - df_kind smallint, - df_name bytea, - df_object_type text, - df_object_id bytea, - CONSTRAINT objects_history_pk PRIMARY KEY (checkpoint_sequence_number, object_id, object_version) -) PARTITION BY RANGE (checkpoint_sequence_number); -CREATE INDEX objects_history_owner ON objects_history (checkpoint_sequence_number, owner_type, owner_id) WHERE owner_type BETWEEN 1 AND 2 AND owner_id IS NOT NULL; -CREATE INDEX objects_history_coin ON objects_history (checkpoint_sequence_number, owner_id, coin_type) WHERE coin_type IS NOT NULL AND owner_type = 1; -CREATE INDEX objects_history_type ON objects_history (checkpoint_sequence_number, object_type); --- init with first partition of the history table -CREATE TABLE objects_history_partition_0 PARTITION OF objects_history FOR VALUES FROM (0) TO (MAXVALUE); - --- snapshot table by folding objects_history table until certain checkpoint, --- effectively the snapshot of objects at the same checkpoint, --- except that it also includes deleted or wrapped objects with the corresponding object_status. -CREATE TABLE objects_snapshot ( - object_id bytea PRIMARY KEY, - object_version bigint NOT NULL, - object_status smallint NOT NULL, - object_digest bytea, - checkpoint_sequence_number bigint NOT NULL, - owner_type smallint, - owner_id bytea, - object_type text, - serialized_object bytea, - coin_type text, - coin_balance bigint, - df_kind smallint, - df_name bytea, - df_object_type text, - df_object_id bytea -); -CREATE INDEX objects_snapshot_checkpoint_sequence_number ON objects_snapshot (checkpoint_sequence_number); -CREATE INDEX objects_snapshot_owner ON objects_snapshot (owner_type, owner_id, object_id) WHERE owner_type BETWEEN 1 AND 2 AND owner_id IS NOT NULL; -CREATE INDEX objects_snapshot_coin ON objects_snapshot (owner_id, coin_type, object_id) WHERE coin_type IS NOT NULL AND owner_type = 1; -CREATE INDEX objects_snapshot_type ON objects_snapshot (object_type, object_id); diff --git a/crates/sui-indexer/migrations/2023-10-06-204335_tx_recipients/up.sql b/crates/sui-indexer/migrations/2023-10-06-204335_tx_recipients/up.sql deleted file mode 100644 index a338d3e6e02..00000000000 --- a/crates/sui-indexer/migrations/2023-10-06-204335_tx_recipients/up.sql +++ /dev/null @@ -1,8 +0,0 @@ --- Your SQL goes here -CREATE TABLE tx_recipients ( - tx_sequence_number BIGINT NOT NULL, - -- SuiAddress in bytes. - recipient BYTEA NOT NULL, - PRIMARY KEY(recipient, tx_sequence_number) -); -CREATE INDEX tx_recipients_tx_sequence_number_index ON tx_recipients (tx_sequence_number ASC); diff --git a/crates/sui-indexer/migrations/2023-10-06-204340_tx_senders/up.sql b/crates/sui-indexer/migrations/2023-10-06-204340_tx_senders/up.sql deleted file mode 100644 index d47d57bc351..00000000000 --- a/crates/sui-indexer/migrations/2023-10-06-204340_tx_senders/up.sql +++ /dev/null @@ -1,8 +0,0 @@ --- Your SQL goes here -CREATE TABLE tx_senders ( - tx_sequence_number BIGINT NOT NULL, - -- SuiAddress in bytes. - sender BYTEA NOT NULL, - PRIMARY KEY(sender, tx_sequence_number) -); -CREATE INDEX tx_senders_tx_sequence_number_index ON tx_senders (tx_sequence_number ASC); diff --git a/crates/sui-indexer/src/apis/coin_api.rs b/crates/sui-indexer/src/apis/coin_api.rs deleted file mode 100644 index e5204eb89c7..00000000000 --- a/crates/sui-indexer/src/apis/coin_api.rs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_trait::async_trait; -use jsonrpsee::{core::RpcResult, RpcModule}; -use sui_json_rpc::{ - coin_api::{parse_to_struct_tag, parse_to_type_tag}, - SuiRpcModule, -}; -use sui_json_rpc_api::{cap_page_limit, CoinReadApiServer}; -use sui_json_rpc_types::{Balance, CoinPage, Page, SuiCoinMetadata}; -use sui_open_rpc::Module; -use sui_types::{ - balance::Supply, - base_types::{ObjectID, SuiAddress}, - gas_coin::{GAS, TOTAL_SUPPLY_MIST}, -}; - -use crate::indexer_reader::IndexerReader; - -pub(crate) struct CoinReadApi { - inner: IndexerReader, -} - -impl CoinReadApi { - pub fn new(inner: IndexerReader) -> Self { - Self { inner } - } -} - -#[async_trait] -impl CoinReadApiServer for CoinReadApi { - async fn get_coins( - &self, - owner: SuiAddress, - coin_type: Option, - cursor: Option, - limit: Option, - ) -> RpcResult { - let limit = cap_page_limit(limit); - if limit == 0 { - return Ok(CoinPage::empty()); - } - - // Normalize coin type tag and default to Gas - let coin_type = - parse_to_type_tag(coin_type)?.to_canonical_string(/* with_prefix */ true); - - let cursor = match cursor { - Some(c) => c, - // If cursor is not specified, we need to start from the beginning of the coin type, - // which is the minimal possible ObjectID. - None => ObjectID::ZERO, - }; - let mut results = self - .inner - .get_owned_coins_in_blocking_task(owner, Some(coin_type), cursor, limit + 1) - .await?; - - let has_next_page = results.len() > limit; - results.truncate(limit); - let next_cursor = results.last().map(|o| o.coin_object_id); - Ok(Page { - data: results, - next_cursor, - has_next_page, - }) - } - - async fn get_all_coins( - &self, - owner: SuiAddress, - cursor: Option, - limit: Option, - ) -> RpcResult { - let limit = cap_page_limit(limit); - if limit == 0 { - return Ok(CoinPage::empty()); - } - - let cursor = match cursor { - Some(c) => c, - // If cursor is not specified, we need to start from the beginning of the coin type, - // which is the minimal possible ObjectID. - None => ObjectID::ZERO, - }; - let mut results = self - .inner - .get_owned_coins_in_blocking_task(owner, None, cursor, limit + 1) - .await?; - - let has_next_page = results.len() > limit; - results.truncate(limit); - let next_cursor = results.last().map(|o| o.coin_object_id); - Ok(Page { - data: results, - next_cursor, - has_next_page, - }) - } - - async fn get_balance( - &self, - owner: SuiAddress, - coin_type: Option, - ) -> RpcResult { - // Normalize coin type tag and default to Gas - let coin_type = - parse_to_type_tag(coin_type)?.to_canonical_string(/* with_prefix */ true); - - let mut results = self - .inner - .get_coin_balances_in_blocking_task(owner, Some(coin_type.clone())) - .await?; - if results.is_empty() { - return Ok(Balance::zero(coin_type)); - } - Ok(results.swap_remove(0)) - } - - async fn get_all_balances(&self, owner: SuiAddress) -> RpcResult> { - self.inner - .get_coin_balances_in_blocking_task(owner, None) - .await - .map_err(Into::into) - } - - async fn get_coin_metadata(&self, coin_type: String) -> RpcResult> { - let coin_struct = parse_to_struct_tag(&coin_type)?; - self.inner - .get_coin_metadata_in_blocking_task(coin_struct) - .await - .map_err(Into::into) - } - - async fn get_total_supply(&self, coin_type: String) -> RpcResult { - let coin_struct = parse_to_struct_tag(&coin_type)?; - if GAS::is_gas(&coin_struct) { - Ok(Supply { - value: TOTAL_SUPPLY_MIST, - }) - } else { - self.inner - .get_total_supply_in_blocking_task(coin_struct) - .await - .map_err(Into::into) - } - } -} - -impl SuiRpcModule for CoinReadApi { - fn rpc(self) -> RpcModule { - self.into_rpc() - } - - fn rpc_doc_module() -> Module { - sui_json_rpc_api::CoinReadApiOpenRpc::module_doc() - } -} diff --git a/crates/sui-indexer/src/apis/governance_api.rs b/crates/sui-indexer/src/apis/governance_api.rs deleted file mode 100644 index ace8fb5d973..00000000000 --- a/crates/sui-indexer/src/apis/governance_api.rs +++ /dev/null @@ -1,464 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use async_trait::async_trait; -use cached::{proc_macro::cached, SizedCache}; -use jsonrpsee::{core::RpcResult, RpcModule}; -use sui_json_rpc::{governance_api::ValidatorExchangeRates, SuiRpcModule}; -use sui_json_rpc_api::GovernanceReadApiServer; -use sui_json_rpc_types::{ - DelegatedStake, DelegatedTimelockedStake, EpochInfo, StakeStatus, SuiCommittee, - SuiObjectDataFilter, ValidatorApys, -}; -use sui_open_rpc::Module; -use sui_types::{ - base_types::{MoveObjectType, ObjectID, SuiAddress}, - committee::EpochId, - governance::StakedSui, - sui_serde::BigInt, - sui_system_state::{sui_system_state_summary::SuiSystemStateSummary, PoolTokenExchangeRate}, - timelock::timelocked_staked_sui::TimelockedStakedSui, -}; - -use crate::{errors::IndexerError, indexer_reader::IndexerReader}; - -/// Maximum amount of staked objects for querying. -const MAX_QUERY_STAKED_OBJECTS: usize = 1000; - -#[derive(Clone)] -pub struct GovernanceReadApi { - inner: IndexerReader, -} - -impl GovernanceReadApi { - pub fn new(inner: IndexerReader) -> Self { - Self { inner } - } - - /// Get a validator's APY by its address - pub async fn get_validator_apy( - &self, - address: &SuiAddress, - ) -> Result, IndexerError> { - let apys = validators_apys_map(self.get_validators_apy().await?); - Ok(apys.get(address).copied()) - } - - async fn get_validators_apy(&self) -> Result { - let system_state_summary: SuiSystemStateSummary = - self.get_latest_sui_system_state().await?; - let epoch = system_state_summary.epoch; - let stake_subsidy_start_epoch = system_state_summary.stake_subsidy_start_epoch; - - let exchange_rate_table = exchange_rates(self, system_state_summary).await?; - - let apys = sui_json_rpc::governance_api::calculate_apys( - stake_subsidy_start_epoch, - exchange_rate_table, - ); - - Ok(ValidatorApys { apys, epoch }) - } - - pub async fn get_epoch_info(&self, epoch: Option) -> Result { - match self - .inner - .spawn_blocking(move |this| this.get_epoch_info(epoch)) - .await - { - Ok(Some(epoch_info)) => Ok(epoch_info), - Ok(None) => Err(IndexerError::InvalidArgumentError(format!( - "Missing epoch {epoch:?}" - ))), - Err(e) => Err(e), - } - } - - async fn get_latest_sui_system_state(&self) -> Result { - self.inner - .spawn_blocking(|this| this.get_latest_sui_system_state()) - .await - } - - async fn get_stakes_by_ids( - &self, - ids: Vec, - ) -> Result, IndexerError> { - let mut stakes = vec![]; - for stored_object in self.inner.multi_get_objects_in_blocking_task(ids).await? { - let object = sui_types::object::Object::try_from(stored_object)?; - let stake_object = StakedSui::try_from(&object)?; - stakes.push(stake_object); - } - - self.get_delegated_stakes(stakes).await - } - - async fn get_staked_by_owner( - &self, - owner: SuiAddress, - ) -> Result, IndexerError> { - let mut stakes = vec![]; - for stored_object in self - .inner - .get_owned_objects_in_blocking_task( - owner, - Some(SuiObjectDataFilter::StructType( - MoveObjectType::staked_sui().into(), - )), - None, - MAX_QUERY_STAKED_OBJECTS, - ) - .await? - { - let object = sui_types::object::Object::try_from(stored_object)?; - let stake_object = StakedSui::try_from(&object)?; - stakes.push(stake_object); - } - - self.get_delegated_stakes(stakes).await - } - - async fn get_timelocked_staked_by_owner( - &self, - owner: SuiAddress, - ) -> Result, IndexerError> { - let mut stakes = vec![]; - for stored_object in self - .inner - .get_owned_objects_in_blocking_task( - owner, - Some(SuiObjectDataFilter::StructType( - MoveObjectType::timelocked_staked_sui().into(), - )), - None, - MAX_QUERY_STAKED_OBJECTS, - ) - .await? - { - let object = sui_types::object::Object::try_from(stored_object)?; - let stake_object = TimelockedStakedSui::try_from(&object)?; - stakes.push(stake_object); - } - - self.get_delegated_timelocked_stakes(stakes).await - } - - pub async fn get_delegated_stakes( - &self, - stakes: Vec, - ) -> Result, IndexerError> { - let pools = stakes - .into_iter() - .fold(BTreeMap::<_, Vec<_>>::new(), |mut pools, stake| { - pools.entry(stake.pool_id()).or_default().push(stake); - pools - }); - - let system_state_summary = self.get_latest_sui_system_state().await?; - let epoch = system_state_summary.epoch; - - let rates = exchange_rates(self, system_state_summary) - .await? - .into_iter() - .map(|rates| (rates.pool_id, rates)) - .collect::>(); - - let mut delegated_stakes = vec![]; - for (pool_id, stakes) in pools { - // Rate table and rate can be null when the pool is not active - let rate_table = rates.get(&pool_id).ok_or_else(|| { - IndexerError::InvalidArgumentError( - "Cannot find rates for staking pool {pool_id}".to_string(), - ) - })?; - let current_rate = rate_table.rates.first().map(|(_, rate)| rate); - - let mut delegations = vec![]; - for stake in stakes { - let status = stake_status( - epoch, - stake.activation_epoch(), - stake.principal(), - rate_table, - current_rate, - ); - - delegations.push(sui_json_rpc_types::Stake { - staked_sui_id: stake.id(), - // TODO: this might change when we implement warm up period. - stake_request_epoch: stake.activation_epoch().saturating_sub(1), - stake_active_epoch: stake.activation_epoch(), - principal: stake.principal(), - status, - }) - } - delegated_stakes.push(DelegatedStake { - validator_address: rate_table.address, - staking_pool: pool_id, - stakes: delegations, - }) - } - Ok(delegated_stakes) - } - - pub async fn get_delegated_timelocked_stakes( - &self, - stakes: Vec, - ) -> Result, IndexerError> { - let pools = stakes - .into_iter() - .fold(BTreeMap::<_, Vec<_>>::new(), |mut pools, stake| { - pools.entry(stake.pool_id()).or_default().push(stake); - pools - }); - - let system_state_summary = self.get_latest_sui_system_state().await?; - let epoch = system_state_summary.epoch; - - let rates = exchange_rates(self, system_state_summary) - .await? - .into_iter() - .map(|rates| (rates.pool_id, rates)) - .collect::>(); - - let mut delegated_stakes = vec![]; - for (pool_id, stakes) in pools { - // Rate table and rate can be null when the pool is not active - let rate_table = rates.get(&pool_id).ok_or_else(|| { - IndexerError::InvalidArgumentError( - "Cannot find rates for staking pool {pool_id}".to_string(), - ) - })?; - let current_rate = rate_table.rates.first().map(|(_, rate)| rate); - - let mut delegations = vec![]; - for stake in stakes { - let status = stake_status( - epoch, - stake.activation_epoch(), - stake.principal(), - rate_table, - current_rate, - ); - - delegations.push(sui_json_rpc_types::TimelockedStake { - timelocked_staked_sui_id: stake.id(), - // TODO: this might change when we implement warm up period. - stake_request_epoch: stake.activation_epoch().saturating_sub(1), - stake_active_epoch: stake.activation_epoch(), - principal: stake.principal(), - status, - expiration_timestamp_ms: stake.expiration_timestamp_ms(), - }) - } - delegated_stakes.push(DelegatedTimelockedStake { - validator_address: rate_table.address, - staking_pool: pool_id, - stakes: delegations, - }) - } - Ok(delegated_stakes) - } -} - -fn stake_status( - epoch: u64, - activation_epoch: u64, - principal: u64, - rate_table: &ValidatorExchangeRates, - current_rate: Option<&PoolTokenExchangeRate>, -) -> StakeStatus { - if epoch >= activation_epoch { - let estimated_reward = if let Some(current_rate) = current_rate { - let stake_rate = rate_table - .rates - .iter() - .find_map(|(epoch, rate)| (*epoch == activation_epoch).then(|| rate.clone())) - .unwrap_or_default(); - let estimated_reward = - ((stake_rate.rate() / current_rate.rate()) - 1.0) * principal as f64; - std::cmp::max(0, estimated_reward.round() as u64) - } else { - 0 - }; - StakeStatus::Active { estimated_reward } - } else { - StakeStatus::Pending - } -} - -/// Cached exchange rates for validators for the given epoch, the cache size is -/// 1, it will be cleared when the epoch changes. rates are in descending order -/// by epoch. -#[cached( - type = "SizedCache>", - create = "{ SizedCache::with_size(1) }", - convert = "{ system_state_summary.epoch }", - result = true -)] -async fn exchange_rates( - state: &GovernanceReadApi, - system_state_summary: SuiSystemStateSummary, -) -> Result, IndexerError> { - // Get validator rate tables - let mut tables = vec![]; - - for validator in system_state_summary.active_validators { - tables.push(( - validator.sui_address, - validator.staking_pool_id, - validator.exchange_rates_id, - validator.exchange_rates_size, - true, - )); - } - - // Get inactive validator rate tables - for df in state - .inner - .get_dynamic_fields_in_blocking_task( - system_state_summary.inactive_pools_id, - None, - system_state_summary.inactive_pools_size as usize, - ) - .await? - { - let pool_id: sui_types::id::ID = bcs::from_bytes(&df.bcs_name).map_err(|e| { - sui_types::error::SuiError::ObjectDeserializationError { - error: e.to_string(), - } - })?; - let inactive_pools_id = system_state_summary.inactive_pools_id; - let validator = state - .inner - .spawn_blocking(move |this| { - sui_types::sui_system_state::get_validator_from_table( - &this, - inactive_pools_id, - &pool_id, - ) - }) - .await?; - tables.push(( - validator.sui_address, - validator.staking_pool_id, - validator.exchange_rates_id, - validator.exchange_rates_size, - false, - )); - } - - let mut exchange_rates = vec![]; - // Get exchange rates for each validator - for (address, pool_id, exchange_rates_id, exchange_rates_size, active) in tables { - let mut rates = vec![]; - for df in state - .inner - .get_dynamic_fields_raw_in_blocking_task( - exchange_rates_id, - None, - exchange_rates_size as usize, - ) - .await? - { - let dynamic_field = df - .to_dynamic_field::() - .ok_or_else(|| sui_types::error::SuiError::ObjectDeserializationError { - error: "dynamic field malformed".to_owned(), - })?; - - rates.push((dynamic_field.name, dynamic_field.value)); - } - - rates.sort_by(|(a, _), (b, _)| a.cmp(b).reverse()); - - exchange_rates.push(ValidatorExchangeRates { - address, - pool_id, - active, - rates, - }); - } - Ok(exchange_rates) -} - -/// Cache a map representing the validators' APYs for this epoch -#[cached( - type = "SizedCache>", - create = "{ SizedCache::with_size(1) }", - convert = " {apys.epoch} " -)] -fn validators_apys_map(apys: ValidatorApys) -> BTreeMap { - BTreeMap::from_iter(apys.apys.iter().map(|x| (x.address, x.apy))) -} - -#[async_trait] -impl GovernanceReadApiServer for GovernanceReadApi { - async fn get_stakes_by_ids( - &self, - staked_sui_ids: Vec, - ) -> RpcResult> { - self.get_stakes_by_ids(staked_sui_ids) - .await - .map_err(Into::into) - } - - async fn get_stakes(&self, owner: SuiAddress) -> RpcResult> { - self.get_staked_by_owner(owner).await.map_err(Into::into) - } - - async fn get_timelocked_stakes_by_ids( - &self, - timelocked_staked_sui_ids: Vec, - ) -> RpcResult> { - self.get_timelocked_stakes_by_ids(timelocked_staked_sui_ids) - .await - .map_err(Into::into) - } - - async fn get_timelocked_stakes( - &self, - owner: SuiAddress, - ) -> RpcResult> { - self.get_timelocked_staked_by_owner(owner) - .await - .map_err(Into::into) - } - - async fn get_committee_info(&self, epoch: Option>) -> RpcResult { - let epoch = self.get_epoch_info(epoch.as_deref().copied()).await?; - Ok(epoch.committee().map_err(IndexerError::from)?.into()) - } - - async fn get_latest_sui_system_state(&self) -> RpcResult { - self.get_latest_sui_system_state().await.map_err(Into::into) - } - - async fn get_reference_gas_price(&self) -> RpcResult> { - let epoch = self.get_epoch_info(None).await?; - Ok(BigInt::from(epoch.reference_gas_price.ok_or_else( - || { - IndexerError::PersistentStorageDataCorruptionError( - "missing latest reference gas price".to_owned(), - ) - }, - )?)) - } - - async fn get_validators_apy(&self) -> RpcResult { - Ok(self.get_validators_apy().await?) - } -} - -impl SuiRpcModule for GovernanceReadApi { - fn rpc(self) -> RpcModule { - self.into_rpc() - } - - fn rpc_doc_module() -> Module { - sui_json_rpc_api::GovernanceReadApiOpenRpc::module_doc() - } -} diff --git a/crates/sui-indexer/src/apis/indexer_api.rs b/crates/sui-indexer/src/apis/indexer_api.rs deleted file mode 100644 index 21ef0ff379a..00000000000 --- a/crates/sui-indexer/src/apis/indexer_api.rs +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_trait::async_trait; -use jsonrpsee::{ - core::RpcResult, - types::{SubscriptionEmptyError, SubscriptionResult}, - RpcModule, SubscriptionSink, -}; -use sui_json_rpc::{ - name_service::{Domain, NameRecord, NameServiceConfig}, - SuiRpcModule, -}; -use sui_json_rpc_api::{cap_page_limit, IndexerApiServer}; -use sui_json_rpc_types::{ - DynamicFieldPage, EventFilter, EventPage, ObjectsPage, Page, SuiObjectResponse, - SuiObjectResponseQuery, SuiTransactionBlockResponseQuery, TransactionBlocksPage, - TransactionFilter, -}; -use sui_open_rpc::Module; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, - digests::TransactionDigest, - dynamic_field::{DynamicFieldName, Field}, - error::SuiObjectResponseError, - event::EventID, - object::ObjectRead, - TypeTag, -}; - -use crate::{indexer_reader::IndexerReader, IndexerError}; - -pub(crate) struct IndexerApi { - inner: IndexerReader, - name_service_config: NameServiceConfig, -} - -impl IndexerApi { - pub fn new(inner: IndexerReader) -> Self { - Self { - inner, - // TODO allow configuring for other networks - name_service_config: Default::default(), - } - } - - async fn get_owned_objects_internal( - &self, - address: SuiAddress, - query: Option, - cursor: Option, - limit: usize, - ) -> RpcResult { - let SuiObjectResponseQuery { filter, options } = query.unwrap_or_default(); - let options = options.unwrap_or_default(); - let objects = self - .inner - .get_owned_objects_in_blocking_task(address, filter, cursor, limit + 1) - .await?; - let mut objects = self - .inner - .spawn_blocking(move |this| { - objects - .into_iter() - .map(|object| object.try_into_object_read(&this)) - .collect::, _>>() - }) - .await?; - let has_next_page = objects.len() > limit; - objects.truncate(limit); - - let next_cursor = objects.last().map(|o_read| o_read.object_id()); - let mut parallel_tasks = vec![]; - for o in objects { - let inner_clone = self.inner.clone(); - let options = options.clone(); - parallel_tasks.push(tokio::task::spawn(async move { - match o { - ObjectRead::NotExists(id) => Ok(SuiObjectResponse::new_with_error( - SuiObjectResponseError::NotExists { object_id: id }, - )), - ObjectRead::Exists(object_ref, o, layout) => { - if options.show_display { - match inner_clone.get_display_fields(&o, &layout).await { - Ok(rendered_fields) => Ok(SuiObjectResponse::new_with_data( - (object_ref, o, layout, options, Some(rendered_fields)) - .try_into()?, - )), - Err(e) => Ok(SuiObjectResponse::new( - Some((object_ref, o, layout, options, None).try_into()?), - Some(SuiObjectResponseError::DisplayError { - error: e.to_string(), - }), - )), - } - } else { - Ok(SuiObjectResponse::new_with_data( - (object_ref, o, layout, options, None).try_into()?, - )) - } - } - ObjectRead::Deleted((object_id, version, digest)) => Ok( - SuiObjectResponse::new_with_error(SuiObjectResponseError::Deleted { - object_id, - version, - digest, - }), - ), - } - })); - } - let data = futures::future::join_all(parallel_tasks) - .await - .into_iter() - .collect::, _>>() - .map_err(|e: tokio::task::JoinError| anyhow::anyhow!(e))? - .into_iter() - .collect::, anyhow::Error>>()?; - - Ok(Page { - data, - next_cursor, - has_next_page, - }) - } -} - -#[async_trait] -impl IndexerApiServer for IndexerApi { - async fn get_owned_objects( - &self, - address: SuiAddress, - query: Option, - cursor: Option, - limit: Option, - ) -> RpcResult { - let limit = cap_page_limit(limit); - if limit == 0 { - return Ok(ObjectsPage::empty()); - } - self.get_owned_objects_internal(address, query, cursor, limit) - .await - } - - async fn query_transaction_blocks( - &self, - query: SuiTransactionBlockResponseQuery, - cursor: Option, - limit: Option, - descending_order: Option, - ) -> RpcResult { - let limit = cap_page_limit(limit); - if limit == 0 { - return Ok(TransactionBlocksPage::empty()); - } - let mut results = self - .inner - .query_transaction_blocks_in_blocking_task( - query.filter, - query.options.unwrap_or_default(), - cursor, - limit + 1, - descending_order.unwrap_or(false), - ) - .await - .map_err(|e: IndexerError| anyhow::anyhow!(e))?; - - let has_next_page = results.len() > limit; - results.truncate(limit); - let next_cursor = results.last().map(|o| o.digest); - Ok(Page { - data: results, - next_cursor, - has_next_page, - }) - } - - async fn query_events( - &self, - query: EventFilter, - // exclusive cursor if `Some`, otherwise start from the beginning - cursor: Option, - limit: Option, - descending_order: Option, - ) -> RpcResult { - let limit = cap_page_limit(limit); - if limit == 0 { - return Ok(EventPage::empty()); - } - let descending_order = descending_order.unwrap_or(false); - let mut results = self - .inner - .query_events_in_blocking_task(query, cursor, limit + 1, descending_order) - .await?; - - let has_next_page = results.len() > limit; - results.truncate(limit); - let next_cursor = results.last().map(|o| o.id); - Ok(Page { - data: results, - next_cursor, - has_next_page, - }) - } - - async fn get_dynamic_fields( - &self, - parent_object_id: ObjectID, - cursor: Option, - limit: Option, - ) -> RpcResult { - let limit = cap_page_limit(limit); - if limit == 0 { - return Ok(DynamicFieldPage::empty()); - } - let mut results = self - .inner - .get_dynamic_fields_in_blocking_task(parent_object_id, cursor, limit + 1) - .await?; - - let has_next_page = results.len() > limit; - results.truncate(limit); - let next_cursor = results.last().map(|o| o.object_id); - Ok(Page { - data: results, - next_cursor, - has_next_page, - }) - } - - async fn get_dynamic_field_object( - &self, - parent_object_id: ObjectID, - name: DynamicFieldName, - ) -> RpcResult { - let name_bcs_value = self - .inner - .bcs_name_from_dynamic_field_name_in_blocking_task(&name) - .await?; - - // Try as Dynamic Field - let id = sui_types::dynamic_field::derive_dynamic_field_id( - parent_object_id, - &name.type_, - &name_bcs_value, - ) - .expect("deriving dynamic field id can't fail"); - - let options = sui_json_rpc_types::SuiObjectDataOptions::full_content(); - match self.inner.get_object_read_in_blocking_task(id).await? { - sui_types::object::ObjectRead::NotExists(_) - | sui_types::object::ObjectRead::Deleted(_) => {} - sui_types::object::ObjectRead::Exists(object_ref, o, layout) => { - return Ok(SuiObjectResponse::new_with_data( - (object_ref, o, layout, options, None).try_into()?, - )); - } - } - - // Try as Dynamic Field Object - let dynamic_object_field_struct = - sui_types::dynamic_field::DynamicFieldInfo::dynamic_object_field_wrapper(name.type_); - let dynamic_object_field_type = TypeTag::Struct(Box::new(dynamic_object_field_struct)); - let dynamic_object_field_id = sui_types::dynamic_field::derive_dynamic_field_id( - parent_object_id, - &dynamic_object_field_type, - &name_bcs_value, - ) - .expect("deriving dynamic field id can't fail"); - match self - .inner - .get_object_read_in_blocking_task(dynamic_object_field_id) - .await? - { - sui_types::object::ObjectRead::NotExists(_) - | sui_types::object::ObjectRead::Deleted(_) => {} - sui_types::object::ObjectRead::Exists(object_ref, o, layout) => { - return Ok(SuiObjectResponse::new_with_data( - (object_ref, o, layout, options, None).try_into()?, - )); - } - } - - Ok(SuiObjectResponse::new_with_error( - sui_types::error::SuiObjectResponseError::DynamicFieldNotFound { parent_object_id }, - )) - } - - fn subscribe_event(&self, _sink: SubscriptionSink, _filter: EventFilter) -> SubscriptionResult { - Err(SubscriptionEmptyError) - } - - fn subscribe_transaction( - &self, - _sink: SubscriptionSink, - _filter: TransactionFilter, - ) -> SubscriptionResult { - Err(SubscriptionEmptyError) - } - - async fn resolve_name_service_address(&self, name: String) -> RpcResult> { - // TODO(manos): Implement new logic. - let domain = name - .parse::() - .map_err(IndexerError::NameServiceError)?; - - let record_id = self.name_service_config.record_field_id(&domain); - - let field_record_object = match self.inner.get_object_in_blocking_task(record_id).await? { - Some(o) => o, - None => return Ok(None), - }; - - let record = NameRecord::try_from(field_record_object) - .map_err(|e| IndexerError::PersistentStorageDataCorruptionError(e.to_string()))?; - - Ok(record.target_address) - } - - async fn resolve_name_service_names( - &self, - address: SuiAddress, - _cursor: Option, - _limit: Option, - ) -> RpcResult> { - let reverse_record_id = self - .name_service_config - .reverse_record_field_id(address.as_ref()); - - let field_reverse_record_object = match self - .inner - .get_object_in_blocking_task(reverse_record_id) - .await? - { - Some(o) => o, - None => { - return Ok(Page { - data: vec![], - next_cursor: None, - has_next_page: false, - }); - } - }; - - let domain = field_reverse_record_object - .to_rust::>() - .ok_or_else(|| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "Malformed Object {reverse_record_id}" - )) - })? - .value; - - Ok(Page { - data: vec![domain.to_string()], - next_cursor: None, - has_next_page: false, - }) - } -} - -impl SuiRpcModule for IndexerApi { - fn rpc(self) -> RpcModule { - self.into_rpc() - } - - fn rpc_doc_module() -> Module { - sui_json_rpc_api::IndexerApiOpenRpc::module_doc() - } -} diff --git a/crates/sui-indexer/src/apis/mod.rs b/crates/sui-indexer/src/apis/mod.rs deleted file mode 100644 index d458dadf72e..00000000000 --- a/crates/sui-indexer/src/apis/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub(crate) use coin_api::CoinReadApi; -pub(crate) use extended_api::ExtendedApi; -pub use governance_api::GovernanceReadApi; -pub(crate) use indexer_api::IndexerApi; -pub(crate) use move_utils::MoveUtilsApi; -pub(crate) use read_api::ReadApi; -pub(crate) use transaction_builder_api::TransactionBuilderApi; -pub(crate) use write_api::WriteApi; - -mod coin_api; -mod extended_api; -mod governance_api; -mod indexer_api; -mod move_utils; -mod read_api; -mod transaction_builder_api; -mod write_api; diff --git a/crates/sui-indexer/src/apis/move_utils.rs b/crates/sui-indexer/src/apis/move_utils.rs deleted file mode 100644 index 93f0c848e82..00000000000 --- a/crates/sui-indexer/src/apis/move_utils.rs +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use async_trait::async_trait; -use jsonrpsee::{core::RpcResult, RpcModule}; -use move_binary_format::binary_config::BinaryConfig; -use sui_json_rpc::{error::SuiRpcInputError, SuiRpcModule}; -use sui_json_rpc_api::MoveUtilsServer; -use sui_json_rpc_types::{ - MoveFunctionArgType, ObjectValueKind, SuiMoveNormalizedFunction, SuiMoveNormalizedModule, - SuiMoveNormalizedStruct, SuiMoveNormalizedType, -}; -use sui_open_rpc::Module; -use sui_types::{base_types::ObjectID, move_package::normalize_modules}; - -use crate::indexer_reader::IndexerReader; - -pub struct MoveUtilsApi { - inner: IndexerReader, -} - -impl MoveUtilsApi { - pub fn new(inner: IndexerReader) -> Self { - Self { inner } - } -} - -#[async_trait] -impl MoveUtilsServer for MoveUtilsApi { - async fn get_normalized_move_modules_by_package( - &self, - package_id: ObjectID, - ) -> RpcResult> { - let package = self - .inner - .get_package_in_blocking_task(package_id) - .await - .map_err(|e| SuiRpcInputError::GenericNotFound(e.to_string()))? - .ok_or_else(|| { - SuiRpcInputError::GenericNotFound(format!( - "Package object does not exist with ID {package_id}", - )) - })?; - let binary_config = BinaryConfig::with_extraneous_bytes_check(false); - let modules = - // we are on the read path - it's OK to use VERSION_MAX of the supported Move - // binary format - normalize_modules( - package.serialized_module_map().values(), - &binary_config, - ) - .map_err(|e| SuiRpcInputError::GenericInvalid(e.to_string()))?; - Ok(modules - .into_iter() - .map(|(name, module)| (name, module.into())) - .collect::>()) - } - - async fn get_normalized_move_module( - &self, - package: ObjectID, - module_name: String, - ) -> RpcResult { - let mut modules = self.get_normalized_move_modules_by_package(package).await?; - let module = modules.remove(&module_name).ok_or_else(|| { - SuiRpcInputError::GenericNotFound(format!( - "No module was found with name {module_name}", - )) - })?; - Ok(module) - } - - async fn get_normalized_move_struct( - &self, - package: ObjectID, - module_name: String, - struct_name: String, - ) -> RpcResult { - let mut module = self - .get_normalized_move_module(package, module_name) - .await?; - module - .structs - .remove(&struct_name) - .ok_or_else(|| { - SuiRpcInputError::GenericNotFound(format!( - "No struct was found with struct name {struct_name}" - )) - }) - .map_err(Into::into) - } - - async fn get_normalized_move_function( - &self, - package: ObjectID, - module_name: String, - function_name: String, - ) -> RpcResult { - let mut module = self - .get_normalized_move_module(package, module_name) - .await?; - module - .exposed_functions - .remove(&function_name) - .ok_or_else(|| { - SuiRpcInputError::GenericNotFound(format!( - "No function was found with function name {function_name}", - )) - }) - .map_err(Into::into) - } - - async fn get_move_function_arg_types( - &self, - package: ObjectID, - module: String, - function: String, - ) -> RpcResult> { - let function = self - .get_normalized_move_function(package, module, function) - .await?; - let args = function - .parameters - .iter() - .map(|p| match p { - SuiMoveNormalizedType::Struct { .. } => { - MoveFunctionArgType::Object(ObjectValueKind::ByValue) - } - SuiMoveNormalizedType::Vector(_) => { - MoveFunctionArgType::Object(ObjectValueKind::ByValue) - } - SuiMoveNormalizedType::Reference(_) => { - MoveFunctionArgType::Object(ObjectValueKind::ByImmutableReference) - } - SuiMoveNormalizedType::MutableReference(_) => { - MoveFunctionArgType::Object(ObjectValueKind::ByMutableReference) - } - _ => MoveFunctionArgType::Pure, - }) - .collect::>(); - Ok(args) - } -} - -impl SuiRpcModule for MoveUtilsApi { - fn rpc(self) -> RpcModule { - self.into_rpc() - } - - fn rpc_doc_module() -> Module { - sui_json_rpc_api::MoveUtilsOpenRpc::module_doc() - } -} diff --git a/crates/sui-indexer/src/apis/read_api.rs b/crates/sui-indexer/src/apis/read_api.rs deleted file mode 100644 index b2b5478a955..00000000000 --- a/crates/sui-indexer/src/apis/read_api.rs +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_trait::async_trait; -use jsonrpsee::{core::RpcResult, RpcModule}; -use sui_json_rpc::{error::SuiRpcInputError, SuiRpcModule}; -use sui_json_rpc_api::{ReadApiServer, QUERY_MAX_RESULT_LIMIT}; -use sui_json_rpc_types::{ - Checkpoint, CheckpointId, CheckpointPage, ProtocolConfigResponse, SuiEvent, - SuiGetPastObjectRequest, SuiLoadedChildObjectsResponse, SuiObjectDataOptions, - SuiObjectResponse, SuiPastObjectResponse, SuiTransactionBlockResponse, - SuiTransactionBlockResponseOptions, -}; -use sui_open_rpc::Module; -use sui_protocol_config::{ProtocolConfig, ProtocolVersion}; -use sui_types::{ - base_types::{ObjectID, SequenceNumber}, - digests::{ChainIdentifier, TransactionDigest}, - error::SuiObjectResponseError, - object::ObjectRead, - sui_serde::BigInt, -}; - -use crate::{errors::IndexerError, indexer_reader::IndexerReader}; - -#[derive(Clone)] -pub(crate) struct ReadApi { - inner: IndexerReader, -} - -impl ReadApi { - pub fn new(inner: IndexerReader) -> Self { - Self { inner } - } - - async fn get_checkpoint(&self, id: CheckpointId) -> Result { - match self - .inner - .spawn_blocking(move |this| this.get_checkpoint(id)) - .await - { - Ok(Some(epoch_info)) => Ok(epoch_info), - Ok(None) => Err(IndexerError::InvalidArgumentError(format!( - "Checkpoint {id:?} not found" - ))), - Err(e) => Err(e), - } - } - - async fn get_latest_checkpoint(&self) -> Result { - self.inner - .spawn_blocking(|this| this.get_latest_checkpoint()) - .await - } - - async fn get_chain_identifier(&self) -> RpcResult { - let genesis_checkpoint = self.get_checkpoint(CheckpointId::SequenceNumber(0)).await?; - Ok(ChainIdentifier::from(genesis_checkpoint.digest)) - } -} - -#[async_trait] -impl ReadApiServer for ReadApi { - async fn get_object( - &self, - object_id: ObjectID, - options: Option, - ) -> RpcResult { - let options = options.unwrap_or_default(); - let object_read = self - .inner - .get_object_read_in_blocking_task(object_id) - .await?; - - match object_read { - ObjectRead::NotExists(id) => Ok(SuiObjectResponse::new_with_error( - SuiObjectResponseError::NotExists { object_id: id }, - )), - ObjectRead::Exists(object_ref, o, layout) => { - let mut display_fields = None; - if options.show_display { - match self.inner.get_display_fields(&o, &layout).await { - Ok(rendered_fields) => display_fields = Some(rendered_fields), - Err(e) => { - return Ok(SuiObjectResponse::new( - Some((object_ref, o, layout, options, None).try_into()?), - Some(SuiObjectResponseError::DisplayError { - error: e.to_string(), - }), - )); - } - } - } - Ok(SuiObjectResponse::new_with_data( - (object_ref, o, layout, options, display_fields).try_into()?, - )) - } - ObjectRead::Deleted((object_id, version, digest)) => Ok( - SuiObjectResponse::new_with_error(SuiObjectResponseError::Deleted { - object_id, - version, - digest, - }), - ), - } - } - - // For ease of implementation we just forward to the single object query, - // although in the future we may want to improve the performance by having a - // more naitive multi_get functionality - async fn multi_get_objects( - &self, - object_ids: Vec, - options: Option, - ) -> RpcResult> { - if object_ids.len() > *QUERY_MAX_RESULT_LIMIT { - return Err( - SuiRpcInputError::SizeLimitExceeded(QUERY_MAX_RESULT_LIMIT.to_string()).into(), - ); - } - - let mut futures = vec![]; - for object_id in object_ids { - futures.push(self.get_object(object_id, options.clone())); - } - - futures::future::join_all(futures) - .await - .into_iter() - .collect::, _>>() - } - - async fn get_total_transaction_blocks(&self) -> RpcResult> { - let checkpoint = self.get_latest_checkpoint().await?; - Ok(BigInt::from(checkpoint.network_total_transactions)) - } - - async fn get_transaction_block( - &self, - digest: TransactionDigest, - options: Option, - ) -> RpcResult { - let mut txn = self - .multi_get_transaction_blocks(vec![digest], options) - .await?; - - let txn = txn.pop().ok_or_else(|| { - IndexerError::InvalidArgumentError(format!("Transaction {digest} not found")) - })?; - - Ok(txn) - } - - async fn multi_get_transaction_blocks( - &self, - digests: Vec, - options: Option, - ) -> RpcResult> { - let num_digests = digests.len(); - if num_digests > *QUERY_MAX_RESULT_LIMIT { - Err(SuiRpcInputError::SizeLimitExceeded( - QUERY_MAX_RESULT_LIMIT.to_string(), - ))? - } - - let options = options.unwrap_or_default(); - let txns = self - .inner - .multi_get_transaction_block_response_in_blocking_task(digests, options) - .await?; - - Ok(txns) - } - - async fn try_get_past_object( - &self, - _object_id: ObjectID, - _version: SequenceNumber, - _options: Option, - ) -> RpcResult { - Err(jsonrpsee::types::error::CallError::Custom( - jsonrpsee::types::error::ErrorCode::MethodNotFound.into(), - ) - .into()) - } - - async fn try_multi_get_past_objects( - &self, - _past_objects: Vec, - _options: Option, - ) -> RpcResult> { - Err(jsonrpsee::types::error::CallError::Custom( - jsonrpsee::types::error::ErrorCode::MethodNotFound.into(), - ) - .into()) - } - - async fn get_latest_checkpoint_sequence_number(&self) -> RpcResult> { - let checkpoint = self.get_latest_checkpoint().await?; - Ok(BigInt::from(checkpoint.sequence_number)) - } - - async fn get_checkpoint(&self, id: CheckpointId) -> RpcResult { - self.get_checkpoint(id).await.map_err(Into::into) - } - - async fn get_checkpoints( - &self, - cursor: Option>, - limit: Option, - descending_order: bool, - ) -> RpcResult { - let cursor = cursor.map(BigInt::into_inner); - let limit = sui_json_rpc_api::validate_limit( - limit, - sui_json_rpc_api::QUERY_MAX_RESULT_LIMIT_CHECKPOINTS, - ) - .map_err(SuiRpcInputError::from)?; - - let mut checkpoints = self - .inner - .spawn_blocking(move |this| this.get_checkpoints(cursor, limit + 1, descending_order)) - .await?; - - let has_next_page = checkpoints.len() > limit; - checkpoints.truncate(limit); - - let next_cursor = checkpoints.last().map(|d| d.sequence_number.into()); - - Ok(CheckpointPage { - data: checkpoints, - next_cursor, - has_next_page, - }) - } - - async fn get_checkpoints_deprecated_limit( - &self, - cursor: Option>, - limit: Option>, - descending_order: bool, - ) -> RpcResult { - self.get_checkpoints( - cursor, - limit.map(|l| l.into_inner() as usize), - descending_order, - ) - .await - } - - async fn get_events(&self, transaction_digest: TransactionDigest) -> RpcResult> { - self.inner - .get_transaction_events_in_blocking_task(transaction_digest) - .await - .map_err(Into::into) - } - - async fn get_loaded_child_objects( - &self, - _digest: TransactionDigest, - ) -> RpcResult { - Err(jsonrpsee::types::error::CallError::Custom( - jsonrpsee::types::error::ErrorCode::MethodNotFound.into(), - ) - .into()) - } - - async fn get_protocol_config( - &self, - version: Option>, - ) -> RpcResult { - let chain = self.get_chain_identifier().await?.chain(); - let version = if let Some(version) = version { - (*version).into() - } else { - let latest_epoch = self - .inner - .spawn_blocking(|this| this.get_latest_epoch_info_from_db()) - .await?; - (latest_epoch.protocol_version as u64).into() - }; - - ProtocolConfig::get_for_version_if_supported(version, chain) - .ok_or(SuiRpcInputError::ProtocolVersionUnsupported( - ProtocolVersion::MIN.as_u64(), - ProtocolVersion::MAX.as_u64(), - )) - .map_err(Into::into) - .map(ProtocolConfigResponse::from) - } - - async fn get_chain_identifier(&self) -> RpcResult { - self.get_chain_identifier().await.map(|id| id.to_string()) - } -} - -impl SuiRpcModule for ReadApi { - fn rpc(self) -> RpcModule { - self.into_rpc() - } - - fn rpc_doc_module() -> Module { - sui_json_rpc_api::ReadApiOpenRpc::module_doc() - } -} diff --git a/crates/sui-indexer/src/apis/transaction_builder_api.rs b/crates/sui-indexer/src/apis/transaction_builder_api.rs deleted file mode 100644 index d49c50d0f78..00000000000 --- a/crates/sui-indexer/src/apis/transaction_builder_api.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_trait::async_trait; -use move_core_types::language_storage::StructTag; -use sui_json_rpc::transaction_builder_api::TransactionBuilderApi as SuiTransactionBuilderApi; -use sui_json_rpc_types::{SuiObjectDataFilter, SuiObjectDataOptions, SuiObjectResponse}; -use sui_transaction_builder::DataReader; -use sui_types::{ - base_types::{ObjectID, ObjectInfo, SuiAddress}, - object::Object, -}; - -use super::governance_api::GovernanceReadApi; -use crate::indexer_reader::IndexerReader; - -pub(crate) struct TransactionBuilderApi { - inner: IndexerReader, -} - -impl TransactionBuilderApi { - #[allow(clippy::new_ret_no_self)] - pub fn new(inner: IndexerReader) -> SuiTransactionBuilderApi { - SuiTransactionBuilderApi::new_with_data_reader(std::sync::Arc::new(Self { inner })) - } -} - -#[async_trait] -impl DataReader for TransactionBuilderApi { - async fn get_owned_objects( - &self, - address: SuiAddress, - object_type: StructTag, - ) -> Result, anyhow::Error> { - let stored_objects = self - .inner - .get_owned_objects_in_blocking_task( - address, - Some(SuiObjectDataFilter::StructType(object_type)), - None, - 50, // Limit the number of objects returned to 50 - ) - .await?; - - stored_objects - .into_iter() - .map(|object| { - let object = Object::try_from(object)?; - let object_ref = object.compute_object_reference(); - let info = ObjectInfo::new(&object_ref, &object); - Ok(info) - }) - .collect::, _>>() - } - - async fn get_object_with_options( - &self, - object_id: ObjectID, - options: SuiObjectDataOptions, - ) -> Result { - let result = self - .inner - .get_object_read_in_blocking_task(object_id) - .await?; - Ok((result, options).try_into()?) - } - - async fn get_reference_gas_price(&self) -> Result { - let epoch_info = GovernanceReadApi::new(self.inner.clone()) - .get_epoch_info(None) - .await?; - Ok(epoch_info - .reference_gas_price - .ok_or_else(|| anyhow::anyhow!("missing latest reference_gas_price"))?) - } -} diff --git a/crates/sui-indexer/src/apis/write_api.rs b/crates/sui-indexer/src/apis/write_api.rs deleted file mode 100644 index 5750c25644b..00000000000 --- a/crates/sui-indexer/src/apis/write_api.rs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_trait::async_trait; -use fastcrypto::encoding::Base64; -use jsonrpsee::{core::RpcResult, http_client::HttpClient, RpcModule}; -use sui_json_rpc::SuiRpcModule; -use sui_json_rpc_api::{WriteApiClient, WriteApiServer}; -use sui_json_rpc_types::{ - DevInspectArgs, DevInspectResults, DryRunTransactionBlockResponse, SuiTransactionBlockResponse, - SuiTransactionBlockResponseOptions, -}; -use sui_open_rpc::Module; -use sui_types::{ - base_types::SuiAddress, quorum_driver_types::ExecuteTransactionRequestType, sui_serde::BigInt, -}; - -use crate::types::SuiTransactionBlockResponseWithOptions; - -pub(crate) struct WriteApi { - fullnode: HttpClient, -} - -impl WriteApi { - pub fn new(fullnode_client: HttpClient) -> Self { - Self { - fullnode: fullnode_client, - } - } -} - -#[async_trait] -impl WriteApiServer for WriteApi { - async fn execute_transaction_block( - &self, - tx_bytes: Base64, - signatures: Vec, - options: Option, - request_type: Option, - ) -> RpcResult { - let sui_transaction_response = self - .fullnode - .execute_transaction_block(tx_bytes, signatures, options.clone(), request_type) - .await?; - Ok(SuiTransactionBlockResponseWithOptions { - response: sui_transaction_response, - options: options.unwrap_or_default(), - } - .into()) - } - - async fn dev_inspect_transaction_block( - &self, - sender_address: SuiAddress, - tx_bytes: Base64, - gas_price: Option>, - epoch: Option>, - additional_args: Option, - ) -> RpcResult { - self.fullnode - .dev_inspect_transaction_block( - sender_address, - tx_bytes, - gas_price, - epoch, - additional_args, - ) - .await - } - - async fn dry_run_transaction_block( - &self, - tx_bytes: Base64, - ) -> RpcResult { - self.fullnode.dry_run_transaction_block(tx_bytes).await - } -} - -impl SuiRpcModule for WriteApi { - fn rpc(self) -> RpcModule { - self.into_rpc() - } - - fn rpc_doc_module() -> Module { - sui_json_rpc_api::WriteApiOpenRpc::module_doc() - } -} diff --git a/crates/sui-indexer/src/errors.rs b/crates/sui-indexer/src/errors.rs deleted file mode 100644 index 35e7badb271..00000000000 --- a/crates/sui-indexer/src/errors.rs +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use fastcrypto::error::FastCryptoError; -use jsonrpsee::{core::Error as RpcError, types::error::CallError}; -use sui_json_rpc::name_service::NameServiceError; -use sui_types::{ - base_types::ObjectIDParseError, - error::{SuiError, SuiObjectResponseError, UserInputError}, -}; -use thiserror::Error; - -#[derive(Debug, Error)] -pub struct DataDownloadError { - pub error: IndexerError, - pub next_checkpoint_sequence_number: u64, -} - -impl std::fmt::Display for DataDownloadError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "next_checkpoint_seq: {}, error: {}", - self.next_checkpoint_sequence_number, self.error - ) - } -} - -#[derive(Debug, Error)] -pub enum IndexerError { - #[error("Indexer failed to convert timestamp to NaiveDateTime with error: `{0}`")] - DateTimeParsingError(String), - - #[error("Indexer failed to deserialize event from events table with error: `{0}`")] - EventDeserializationError(String), - - #[error( - "Fullnode returns unexpected responses, which may block indexers from proceeding, with error: `{0}`" - )] - UnexpectedFullnodeResponseError(String), - - #[error("Indexer failed to transform data with error: `{0}`")] - DataTransformationError(String), - - #[error("Indexer failed to read fullnode with error: `{0}`")] - FullNodeReadingError(String), - - #[error("Indexer failed to convert structs to diesel Insertable with error: `{0}`")] - InsertableParsingError(String), - - #[error("Indexer failed to build JsonRpcServer with error: `{0}`")] - JsonRpcServerError(#[from] sui_json_rpc::error::Error), - - #[error("Indexer failed to find object mutations, which should never happen.")] - ObjectMutationNotAvailable, - - #[error("Indexer failed to build PG connection pool with error: `{0}`")] - PgConnectionPoolInitError(String), - - #[error("Indexer failed to get a pool connection from PG connection pool with error: `{0}`")] - PgPoolConnectionError(String), - - #[error("Indexer failed to read PostgresDB with error: `{0}`")] - PostgresReadError(String), - - #[error("Indexer failed to reset PostgresDB with error: `{0}`")] - PostgresResetError(String), - - #[error("Indexer failed to commit changes to PostgresDB with error: `{0}`")] - PostgresWriteError(String), - - #[error(transparent)] - PostgresError(#[from] diesel::result::Error), - - #[error("Indexer failed to initialize fullnode Http client with error: `{0}`")] - HttpClientInitError(String), - - #[error("Indexer failed to serialize/deserialize with error: `{0}`")] - SerdeError(String), - - #[error("Indexer error related to dynamic field: `{0}`")] - DynamicFieldError(String), - - #[error("Indexer does not support the feature with error: `{0}`")] - NotSupportedError(String), - - #[error("Indexer read corrupted/incompatible data from persistent storage: `{0}`")] - PersistentStorageDataCorruptionError(String), - - #[error("Indexer generic error: `{0}`")] - GenericError(String), - - #[error("Indexer failed to resolve object to move struct with error: `{0}`")] - ResolveMoveStructError(String), - - #[error(transparent)] - UncategorizedError(#[from] anyhow::Error), - - #[error(transparent)] - ObjectIdParseError(#[from] ObjectIDParseError), - - #[error("Invalid transaction digest with error: `{0}`")] - InvalidTransactionDigestError(String), - - #[error(transparent)] - SuiError(#[from] SuiError), - - #[error(transparent)] - BcsError(#[from] bcs::Error), - - #[error("Invalid argument with error: `{0}`")] - InvalidArgumentError(String), - - #[error(transparent)] - UserInputError(#[from] UserInputError), - - #[error("Indexer failed to resolve module with error: `{0}`")] - ModuleResolutionError(String), - - #[error(transparent)] - ObjectResponseError(#[from] SuiObjectResponseError), - - #[error(transparent)] - FastCryptoError(#[from] FastCryptoError), - - #[error("`{0}`: `{1}`")] - ErrorWithContext(String, Box), - - #[error("Indexer failed to send item to channel with error: `{0}`")] - MpscChannelError(String), - - #[error(transparent)] - NameServiceError(#[from] NameServiceError), -} - -pub trait Context { - fn context(self, context: &str) -> Result; -} - -impl Context for Result { - fn context(self, context: &str) -> Result { - self.map_err(|e| IndexerError::ErrorWithContext(context.to_string(), Box::new(e))) - } -} - -impl From for RpcError { - fn from(e: IndexerError) -> Self { - RpcError::Call(CallError::Failed(e.into())) - } -} - -impl From for IndexerError { - fn from(value: tokio::task::JoinError) -> Self { - IndexerError::UncategorizedError(anyhow::Error::from(value)) - } -} diff --git a/crates/sui-indexer/src/framework/builder.rs b/crates/sui-indexer/src/framework/builder.rs deleted file mode 100644 index 26ecc31ed5f..00000000000 --- a/crates/sui-indexer/src/framework/builder.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use sui_types::messages_checkpoint::CheckpointSequenceNumber; - -use super::{fetcher::CheckpointFetcher, Handler}; -use crate::metrics::IndexerMetrics; - -pub struct IndexerBuilder { - rest_url: Option, - handlers: Vec>, - last_downloaded_checkpoint: Option, - checkpoint_buffer_size: usize, - metrics: IndexerMetrics, -} - -impl IndexerBuilder { - const DEFAULT_CHECKPOINT_BUFFER_SIZE: usize = 1000; - - #[allow(clippy::new_without_default)] - pub fn new(metrics: IndexerMetrics) -> Self { - Self { - rest_url: None, - handlers: Vec::new(), - last_downloaded_checkpoint: None, - checkpoint_buffer_size: Self::DEFAULT_CHECKPOINT_BUFFER_SIZE, - metrics, - } - } - - pub fn rest_url>(mut self, rest_url: T) -> Self { - self.rest_url = Some(rest_url.into()); - self - } - - pub fn handler(mut self, handler: T) -> Self { - self.handlers.push(Box::new(handler)); - self - } - - pub fn last_downloaded_checkpoint( - mut self, - last_downloaded_checkpoint: Option, - ) -> Self { - self.last_downloaded_checkpoint = last_downloaded_checkpoint; - self - } - - pub fn checkpoint_buffer_size(mut self, checkpoint_buffer_size: usize) -> Self { - self.checkpoint_buffer_size = checkpoint_buffer_size; - self - } - - pub async fn run(self) { - let (downloaded_checkpoint_data_sender, downloaded_checkpoint_data_receiver) = - mysten_metrics::metered_channel::channel( - self.checkpoint_buffer_size, - &mysten_metrics::get_metrics() - .unwrap() - .channels - .with_label_values(&["checkpoint_tx_downloading"]), - ); - - // experimental rest api route is found at `/rest` on the same interface as the - // jsonrpc service - let rest_api_url = format!("{}/rest", self.rest_url.unwrap()); - let fetcher = CheckpointFetcher::new( - sui_rest_api::Client::new(rest_api_url), - self.last_downloaded_checkpoint, - downloaded_checkpoint_data_sender, - self.metrics.clone(), - ); - mysten_metrics::spawn_monitored_task!(fetcher.run()); - - assert!(!self.handlers.is_empty()); - - super::runner::run( - mysten_metrics::metered_channel::ReceiverStream::new( - downloaded_checkpoint_data_receiver, - ), - self.handlers, - self.metrics.clone(), - ) - .await; - } -} diff --git a/crates/sui-indexer/src/framework/mod.rs b/crates/sui-indexer/src/framework/mod.rs deleted file mode 100644 index 0df81bdcdd5..00000000000 --- a/crates/sui-indexer/src/framework/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod builder; -pub mod interface; - -// TODO remove the pub(crater) once indexer.rs is renamed to lib.rs -pub(crate) mod fetcher; -pub(crate) mod runner; - -pub use builder::IndexerBuilder; -pub use interface::Handler; diff --git a/crates/sui-indexer/src/handlers/checkpoint_handler.rs b/crates/sui-indexer/src/handlers/checkpoint_handler.rs deleted file mode 100644 index b8b30e9ac9a..00000000000 --- a/crates/sui-indexer/src/handlers/checkpoint_handler.rs +++ /dev/null @@ -1,890 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::{hash_map::Entry, BTreeMap, HashMap, HashSet}, - sync::{Arc, Mutex}, -}; - -use async_trait::async_trait; -use itertools::Itertools; -use move_core_types::{ - annotated_value::{MoveStructLayout, MoveTypeLayout}, - language_storage::{StructTag, TypeTag}, -}; -use mysten_metrics::{get_metrics, spawn_monitored_task}; -use sui_json_rpc_types::SuiMoveValue; -use sui_package_resolver::{PackageStore, Resolver}; -use sui_rest_api::{CheckpointData, CheckpointTransaction}; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber}, - dynamic_field::{DynamicFieldInfo, DynamicFieldName, DynamicFieldType}, - effects::{TransactionEffects, TransactionEffectsAPI}, - event::SystemEpochInfoEvent, - messages_checkpoint::{CertifiedCheckpointSummary, CheckpointContents}, - object::{Object, Owner}, - sui_system_state::{ - get_sui_system_state, sui_system_state_summary::SuiSystemStateSummary, SuiSystemStateTrait, - }, - transaction::TransactionDataAPI, -}; -use tap::tap::TapFallible; -use tokio::sync::watch; -use tracing::{error, info, warn}; - -use super::{ - tx_processor::{EpochEndIndexingObjectStore, TxChangesProcessor}, - CheckpointDataToCommit, EpochToCommit, TransactionObjectChangesToCommit, -}; -use crate::{ - db::PgConnectionPool, - errors::IndexerError, - framework::interface::Handler, - handlers::{committer::start_tx_checkpoint_commit_task, tx_processor::IndexingPackageBuffer}, - metrics::IndexerMetrics, - models::display::StoredDisplay, - store::{ - module_resolver::{IndexerStorePackageModuleResolver, InterimPackageResolver}, - IndexerStore, PgIndexerStore, - }, - types::{ - IndexedCheckpoint, IndexedDeletedObject, IndexedEpochInfo, IndexedEvent, IndexedObject, - IndexedPackage, IndexedTransaction, IndexerResult, TransactionKind, TxIndex, - }, -}; - -const CHECKPOINT_QUEUE_SIZE: usize = 100; - -pub async fn new_handlers( - state: S, - metrics: IndexerMetrics, -) -> Result, IndexerError> -where - S: IndexerStore + Clone + Sync + Send + 'static, -{ - let checkpoint_queue_size = std::env::var("CHECKPOINT_QUEUE_SIZE") - .unwrap_or(CHECKPOINT_QUEUE_SIZE.to_string()) - .parse::() - .unwrap(); - let global_metrics = get_metrics().unwrap(); - let (indexed_checkpoint_sender, indexed_checkpoint_receiver) = - mysten_metrics::metered_channel::channel( - checkpoint_queue_size, - &global_metrics - .channels - .with_label_values(&["checkpoint_indexing"]), - ); - - let state_clone = state.clone(); - let metrics_clone = metrics.clone(); - let (tx, package_tx) = watch::channel(None); - spawn_monitored_task!(start_tx_checkpoint_commit_task( - state_clone, - metrics_clone, - indexed_checkpoint_receiver, - tx, - )); - - let checkpoint_handler = CheckpointHandler { - state, - metrics, - indexed_checkpoint_sender, - package_buffer: IndexingPackageBuffer::start(package_tx), - }; - - Ok(checkpoint_handler) -} - -pub struct CheckpointHandler { - state: S, - metrics: IndexerMetrics, - indexed_checkpoint_sender: mysten_metrics::metered_channel::Sender, - // buffers for packages that are being indexed but not committed to DB, - // they will be periodically GCed to avoid OOM. - package_buffer: Arc>, -} - -#[async_trait] -impl Handler for CheckpointHandler -where - S: IndexerStore + Clone + Sync + Send + 'static, -{ - fn name(&self) -> &str { - "checkpoint-handler" - } - async fn process_checkpoints(&mut self, checkpoints: &[CheckpointData]) -> anyhow::Result<()> { - if checkpoints.is_empty() { - return Ok(()); - } - // Safe to unwrap, checked emptiness above - let first_checkpoint_seq = checkpoints - .first() - .unwrap() - .checkpoint_summary - .sequence_number(); - let last_checkpoint_seq = checkpoints - .last() - .unwrap() - .checkpoint_summary - .sequence_number(); - info!( - first = first_checkpoint_seq, - last = last_checkpoint_seq, - "Checkpoints received by CheckpointHandler" - ); - - let indexing_timer = self.metrics.checkpoint_index_latency.start_timer(); - // It's important to index packages first to populate ModuleResolver - let packages = Self::index_packages(checkpoints, &self.metrics); - let package_objects = Self::get_package_objects(checkpoints); - - let pg_blocking_cp = self.pg_blocking_cp()?; - let module_package_db_resolver = IndexerStorePackageModuleResolver::new(pg_blocking_cp); - let in_mem_package_resolver = InterimPackageResolver::new( - module_package_db_resolver, - self.package_buffer.clone(), - &package_objects, - self.metrics.clone(), - ); - let package_resolver = Arc::new(Resolver::new(in_mem_package_resolver)); - - let mut packages_per_checkpoint: HashMap<_, Vec<_>> = HashMap::new(); - for package in packages { - packages_per_checkpoint - .entry(package.checkpoint_sequence_number) - .or_default() - .push(package); - } - let mut tasks = vec![]; - let state_clone = Arc::new(self.state.clone()); - let metrics_clone = Arc::new(self.metrics.clone()); - for checkpoint in checkpoints { - let packages = packages_per_checkpoint - .remove(checkpoint.checkpoint_summary.sequence_number()) - .unwrap_or_default(); - tasks.push(tokio::task::spawn(Self::index_one_checkpoint( - state_clone.clone(), - checkpoint.clone(), - metrics_clone.clone(), - packages, - package_resolver.clone(), - ))); - } - let checkpoint_data_to_commit = futures::future::join_all(tasks) - .await - .into_iter() - .collect::, _>>() - .tap_err(|e| { - error!( - "Failed to join all checkpoint indexing tasks with error: {}", - e.to_string() - ); - })? - .into_iter() - .collect::, _>>() - .tap_err(|e| { - error!("Failed to index checkpoints with error: {}", e.to_string()); - })?; - let elapsed = indexing_timer.stop_and_record(); - - info!( - first = first_checkpoint_seq, - last = last_checkpoint_seq, - elapsed, - "Checkpoints indexing finished, about to sending to commit handler" - ); - - // NOTE: when the channel is full, checkpoint_sender_guard will wait until the - // channel has space. Checkpoints are sent sequentially to stick to the - // order of checkpoint sequence numbers. - for checkpoint_data in checkpoint_data_to_commit { - let checkpoint_seq = checkpoint_data.checkpoint.sequence_number; - self.indexed_checkpoint_sender - .send(checkpoint_data) - .await - .tap_ok(|_| info!(checkpoint_seq, "Checkpoint sent to commit handler")) - .unwrap_or_else(|e| { - panic!( - "checkpoint channel send should not fail, but got error: {:?}", - e - ) - }); - } - Ok(()) - } -} - -impl CheckpointHandler -where - S: IndexerStore + Clone + Sync + Send + 'static, -{ - async fn index_epoch( - state: Arc, - data: &CheckpointData, - ) -> Result, IndexerError> { - let checkpoint_object_store = EpochEndIndexingObjectStore::new(data); - - let CheckpointData { - transactions, - checkpoint_summary, - checkpoint_contents: _, - } = data; - - // Genesis epoch - if *checkpoint_summary.sequence_number() == 0 { - info!("Processing genesis epoch"); - let system_state: SuiSystemStateSummary = - get_sui_system_state(&checkpoint_object_store)?.into_sui_system_state_summary(); - return Ok(Some(EpochToCommit { - last_epoch: None, - new_epoch: IndexedEpochInfo::from_new_system_state_summary( - system_state, - 0, // first_checkpoint_id - None, - ), - })); - } - - // If not end of epoch, return - if checkpoint_summary.end_of_epoch_data.is_none() { - return Ok(None); - } - - let system_state: SuiSystemStateSummary = - get_sui_system_state(&checkpoint_object_store)?.into_sui_system_state_summary(); - - let epoch_event = transactions - .iter() - .flat_map(|t| t.events.as_ref().map(|e| &e.data)) - .flatten() - .find(|ev| ev.is_system_epoch_info_event()) - .unwrap_or_else(|| { - panic!( - "Can't find SystemEpochInfoEvent in epoch end checkpoint {}", - checkpoint_summary.sequence_number() - ) - }); - - let event = bcs::from_bytes::(&epoch_event.contents)?; - - // Now we just entered epoch X, we want to calculate the diff between - // TotalTransactionsByEndOfEpoch(X-1) and TotalTransactionsByEndOfEpoch(X-2) - let network_tx_count_prev_epoch = match system_state.epoch { - // If first epoch change, this number is 0 - 1 => Ok(0), - _ => { - let last_epoch = system_state.epoch - 2; - state - .get_network_total_transactions_by_end_of_epoch(last_epoch) - .await - } - }?; - - Ok(Some(EpochToCommit { - last_epoch: Some(IndexedEpochInfo::from_end_of_epoch_data( - &system_state, - checkpoint_summary, - &event, - network_tx_count_prev_epoch, - )), - new_epoch: IndexedEpochInfo::from_new_system_state_summary( - system_state, - checkpoint_summary.sequence_number + 1, // first_checkpoint_id - Some(&event), - ), - })) - } - - async fn index_one_checkpoint( - state: Arc, - data: CheckpointData, - metrics: Arc, - packages: Vec, - package_resolver: Arc>, - ) -> Result { - let checkpoint_seq = data.checkpoint_summary.sequence_number; - info!(checkpoint_seq, "Indexing checkpoint data blob"); - - // Index epoch - let epoch = Self::index_epoch(state, &data).await?; - - // Index Objects - let object_changes: TransactionObjectChangesToCommit = - Self::index_objects(data.clone(), &metrics, package_resolver.clone()).await?; - let object_history_changes: TransactionObjectChangesToCommit = - Self::index_objects_history(data.clone(), package_resolver.clone()).await?; - - let (checkpoint, db_transactions, db_events, db_indices, db_displays) = { - let CheckpointData { - transactions, - checkpoint_summary, - checkpoint_contents, - } = data; - - let (db_transactions, db_events, db_indices, db_displays) = Self::index_transactions( - transactions, - &checkpoint_summary, - &checkpoint_contents, - &metrics, - ) - .await?; - - let successful_tx_num: u64 = db_transactions.iter().map(|t| t.successful_tx_num).sum(); - ( - IndexedCheckpoint::from_sui_checkpoint( - &checkpoint_summary, - &checkpoint_contents, - successful_tx_num as usize, - ), - db_transactions, - db_events, - db_indices, - db_displays, - ) - }; - info!(checkpoint_seq, "Indexed one checkpoint."); - Ok(CheckpointDataToCommit { - checkpoint, - transactions: db_transactions, - events: db_events, - tx_indices: db_indices, - display_updates: db_displays, - object_changes, - object_history_changes, - packages, - epoch, - }) - } - - async fn index_transactions( - transactions: Vec, - checkpoint_summary: &CertifiedCheckpointSummary, - checkpoint_contents: &CheckpointContents, - metrics: &IndexerMetrics, - ) -> IndexerResult<( - Vec, - Vec, - Vec, - BTreeMap, - )> { - let checkpoint_seq = checkpoint_summary.sequence_number(); - - let mut tx_seq_num_iter = checkpoint_contents - .enumerate_transactions(checkpoint_summary) - .map(|(seq, execution_digest)| (execution_digest.transaction, seq)); - - if checkpoint_contents.size() != transactions.len() { - return Err(IndexerError::FullNodeReadingError(format!( - "CheckpointContents has different size {} compared to Transactions {} for checkpoint {}", - checkpoint_contents.size(), - transactions.len(), - checkpoint_seq - ))); - } - - let mut db_transactions = Vec::new(); - let mut db_events = Vec::new(); - let mut db_displays = BTreeMap::new(); - let mut db_indices = Vec::new(); - - for tx in transactions { - let CheckpointTransaction { - transaction: sender_signed_data, - effects: fx, - events, - input_objects, - output_objects, - } = tx; - // Unwrap safe - we checked they have equal length above - let (tx_digest, tx_sequence_number) = tx_seq_num_iter.next().unwrap(); - if tx_digest != *sender_signed_data.digest() { - return Err(IndexerError::FullNodeReadingError(format!( - "Transactions has different ordering from CheckpointContents, for checkpoint {}, Mismatch found at {} v.s. {}", - checkpoint_seq, - tx_digest, - sender_signed_data.digest() - ))); - } - let tx = sender_signed_data.transaction_data(); - let events = events - .as_ref() - .map(|events| events.data.clone()) - .unwrap_or_default(); - - let transaction_kind = if tx.is_system_tx() { - TransactionKind::SystemTransaction - } else { - TransactionKind::ProgrammableTransaction - }; - - db_events.extend(events.iter().enumerate().map(|(idx, event)| { - IndexedEvent::from_event( - tx_sequence_number, - idx as u64, - *checkpoint_seq, - tx_digest, - event, - checkpoint_summary.timestamp_ms, - ) - })); - - db_displays.extend( - events - .iter() - .flat_map(StoredDisplay::try_from_event) - .map(|display| (display.object_type.clone(), display)), - ); - - let objects = input_objects - .iter() - .chain(output_objects.iter()) - .collect::>(); - - let (balance_change, object_changes) = - TxChangesProcessor::new(&objects, metrics.clone()) - .get_changes(tx, &fx, &tx_digest) - .await?; - - let db_txn = IndexedTransaction { - tx_sequence_number, - tx_digest, - checkpoint_sequence_number: *checkpoint_summary.sequence_number(), - timestamp_ms: checkpoint_summary.timestamp_ms, - sender_signed_data: sender_signed_data.data().clone(), - effects: fx.clone(), - object_changes, - balance_change, - events, - transaction_kind, - successful_tx_num: if fx.status().is_ok() { - tx.kind().tx_count() as u64 - } else { - 0 - }, - }; - - db_transactions.push(db_txn); - - // Input Objects - let input_objects = tx - .input_objects() - .expect("committed txns have been validated") - .into_iter() - .map(|obj_kind| obj_kind.object_id()) - .collect::>(); - - // Changed Objects - let changed_objects = fx - .all_changed_objects() - .into_iter() - .map(|(object_ref, _owner, _write_kind)| object_ref.0) - .collect::>(); - - // Payers - let payers = vec![tx.gas_owner()]; - - // Senders - let senders = vec![tx.sender()]; - - // Recipients - let recipients = fx - .all_changed_objects() - .into_iter() - .filter_map(|(_object_ref, owner, _write_kind)| match owner { - Owner::AddressOwner(address) => Some(address), - _ => None, - }) - .unique() - .collect::>(); - - // Move Calls - let move_calls = tx - .move_calls() - .iter() - .map(|(p, m, f)| (*<&ObjectID>::clone(p), m.to_string(), f.to_string())) - .collect(); - - db_indices.push(TxIndex { - tx_sequence_number, - transaction_digest: tx_digest, - checkpoint_sequence_number: *checkpoint_seq, - input_objects, - changed_objects, - senders, - payers, - recipients, - move_calls, - }); - } - Ok((db_transactions, db_events, db_indices, db_displays)) - } - - async fn index_objects( - data: CheckpointData, - metrics: &IndexerMetrics, - package_resolver: Arc>, - ) -> Result { - let _timer = metrics.indexing_objects_latency.start_timer(); - let checkpoint_seq = data.checkpoint_summary.sequence_number; - let deleted_objects = data - .transactions - .iter() - .flat_map(|tx| get_deleted_objects(&tx.effects)) - .collect::>(); - let deleted_object_ids = deleted_objects - .iter() - .map(|o| (o.0, o.1)) - .collect::>(); - let indexed_deleted_objects = deleted_objects - .into_iter() - .map(|o| IndexedDeletedObject { - object_id: o.0, - object_version: o.1.value(), - checkpoint_sequence_number: checkpoint_seq, - }) - .collect(); - - let (latest_objects, intermediate_versions) = get_latest_objects(data.output_objects()); - - let live_objects: Vec = data - .transactions - .iter() - .flat_map(|tx| { - let CheckpointTransaction { - transaction: tx, - effects: fx, - .. - } = tx; - fx.all_changed_objects() - .into_iter() - .filter_map(|(oref, _owner, _kind)| { - // We don't care about objects that are deleted or updated more than once - if intermediate_versions.contains(&(oref.0, oref.1)) - || deleted_object_ids.contains(&(oref.0, oref.1)) - { - return None; - } - let object = latest_objects.get(&(oref.0)).unwrap_or_else(|| { - panic!( - "object {:?} not found in CheckpointData (tx_digest: {})", - oref.0, - tx.digest() - ) - }); - assert_eq!(oref.1, object.version()); - Some(object.clone()) - }) - .collect::>() - }) - .collect(); - - let move_struct_layout_map = - get_move_struct_layout_map(&live_objects, package_resolver).await?; - let changed_objects = live_objects - .into_iter() - .map(|o| { - let df_info = - try_create_dynamic_field_info(&o, &move_struct_layout_map, &latest_objects); - df_info.map(|info| IndexedObject::from_object(checkpoint_seq, o, info)) - }) - .collect::, _>>()?; - Ok(TransactionObjectChangesToCommit { - changed_objects, - deleted_objects: indexed_deleted_objects, - }) - } - - // similar to index_objects, but objects_history keeps all versions of objects - async fn index_objects_history( - data: CheckpointData, - package_resolver: Arc>, - ) -> Result { - let checkpoint_seq = data.checkpoint_summary.sequence_number; - let deleted_objects = data - .transactions - .iter() - .flat_map(|tx| get_deleted_objects(&tx.effects)) - .collect::>(); - let indexed_deleted_objects: Vec = deleted_objects - .into_iter() - .map(|o| IndexedDeletedObject { - object_id: o.0, - object_version: o.1.value(), - checkpoint_sequence_number: checkpoint_seq, - }) - .collect(); - - let (latest_objects, _) = get_latest_objects(data.output_objects()); - let history_object_map = data - .output_objects() - .into_iter() - .map(|o| ((o.id(), o.version()), o.clone())) - .collect::>(); - - let history_objects: Vec = data - .transactions - .iter() - .flat_map(|tx| { - let CheckpointTransaction { - transaction: tx, - effects: fx, - .. - } = tx; - fx.all_changed_objects() - .into_iter() - .map(|(oref, _owner, _kind)| { - let history_object = history_object_map.get(&(oref.0, oref.1)).unwrap_or_else(|| { - panic!( - "object {:?} version {:?} not found in CheckpointData (tx_digest: {})", - oref.0, - oref.1, - tx.digest() - ) - }); - assert_eq!(oref.2, history_object.digest()); - history_object.clone() - }) - .collect::>() - }) - .collect(); - - let move_struct_layout_map = - get_move_struct_layout_map(&history_objects, package_resolver).await?; - let changed_objects = history_objects - .into_iter() - .map(|o| { - let df_info = - try_create_dynamic_field_info(&o, &move_struct_layout_map, &latest_objects); - df_info.map(|info| IndexedObject::from_object(checkpoint_seq, o, info)) - }) - .collect::, _>>()?; - - Ok(TransactionObjectChangesToCommit { - changed_objects, - deleted_objects: indexed_deleted_objects, - }) - } - - fn index_packages( - checkpoint_data: &[CheckpointData], - metrics: &IndexerMetrics, - ) -> Vec { - let _timer = metrics.indexing_packages_latency.start_timer(); - checkpoint_data - .iter() - .flat_map(|data| { - let checkpoint_sequence_number = data.checkpoint_summary.sequence_number; - data.output_objects() - .iter() - .filter_map(|o| { - if let sui_types::object::Data::Package(p) = &o.data { - Some(IndexedPackage { - package_id: o.id(), - move_package: p.clone(), - checkpoint_sequence_number, - }) - } else { - None - } - }) - .collect::>() - }) - .collect() - } - - fn get_package_objects(checkpoint_data: &[CheckpointData]) -> Vec<(IndexedPackage, Object)> { - checkpoint_data - .iter() - .flat_map(|data| { - let checkpoint_sequence_number = data.checkpoint_summary.sequence_number; - data.output_objects() - .iter() - .filter_map(|o| { - if let sui_types::object::Data::Package(p) = &o.data { - let indexed_pkg = IndexedPackage { - package_id: o.id(), - move_package: p.clone(), - checkpoint_sequence_number, - }; - Some((indexed_pkg, (**o).clone())) - } else { - None - } - }) - .collect::>() - }) - .collect() - } - - fn pg_blocking_cp(&self) -> Result { - let state_as_any = self.state.as_any(); - if let Some(pg_state) = state_as_any.downcast_ref::() { - return Ok(pg_state.blocking_cp()); - } - Err(IndexerError::UncategorizedError(anyhow::anyhow!( - "Failed to downcast state to PgIndexerStore" - ))) - } -} - -async fn get_move_struct_layout_map( - objects: &[Object], - package_resolver: Arc>, -) -> Result, IndexerError> { - let struct_tags = objects - .iter() - .filter_map(|o| { - let move_object = o.data.try_as_move().cloned(); - move_object.map(|move_object| { - let struct_tag: StructTag = move_object.type_().clone().into(); - struct_tag - }) - }) - .collect::>(); - let struct_tags = struct_tags.into_iter().unique().collect::>(); - info!( - "Resolving Move struct layouts for struct tags of size {}.", - struct_tags.len() - ); - let move_struct_layout_futures = struct_tags - .into_iter() - .map(|struct_tag| { - let package_resolver_clone = package_resolver.clone(); - async move { - let move_type_layout = package_resolver_clone - .type_layout(TypeTag::Struct(Box::new(struct_tag.clone()))) - .await - .map_err(|e| { - IndexerError::DynamicFieldError(format!( - "Fail to resolve struct layout for {:?} with {:?}.", - struct_tag, e - )) - })?; - let move_struct_layout = match move_type_layout { - MoveTypeLayout::Struct(s) => Ok(s), - _ => Err(IndexerError::ResolveMoveStructError( - "MoveTypeLayout is not Struct".to_string(), - )), - }?; - Ok::< - ( - move_core_types::language_storage::StructTag, - move_core_types::annotated_value::MoveStructLayout, - ), - IndexerError, - >((struct_tag, move_struct_layout)) - } - }) - .collect::>(); - let move_struct_layout_map = futures::future::try_join_all(move_struct_layout_futures) - .await? - .into_iter() - .collect::>(); - Ok(move_struct_layout_map) -} - -pub fn get_deleted_objects(effects: &TransactionEffects) -> Vec { - let deleted = effects.deleted().into_iter(); - let wrapped = effects.wrapped().into_iter(); - let unwrapped_then_deleted = effects.unwrapped_then_deleted().into_iter(); - deleted - .chain(wrapped) - .chain(unwrapped_then_deleted) - .collect::>() -} - -pub fn get_latest_objects( - objects: Vec<&Object>, -) -> ( - HashMap, - HashSet<(ObjectID, SequenceNumber)>, -) { - let mut latest_objects = HashMap::new(); - let mut discarded_versions = HashSet::new(); - for object in objects { - match latest_objects.entry(object.id()) { - Entry::Vacant(e) => { - e.insert(object.clone()); - } - Entry::Occupied(mut e) => { - if object.version() > e.get().version() { - discarded_versions.insert((e.get().id(), e.get().version())); - e.insert(object.clone()); - } - } - } - } - (latest_objects, discarded_versions) -} - -fn try_create_dynamic_field_info( - o: &Object, - struct_tag_to_move_struct_layout: &HashMap, - latest_objects: &HashMap, -) -> IndexerResult> { - // Skip if not a move object - let Some(move_object) = o.data.try_as_move().cloned() else { - return Ok(None); - }; - - if !move_object.type_().is_dynamic_field() { - return Ok(None); - } - - let struct_tag: StructTag = move_object.type_().clone().into(); - let move_struct_layout = struct_tag_to_move_struct_layout - .get(&struct_tag) - .cloned() - .ok_or_else(|| { - IndexerError::DynamicFieldError(format!( - "Cannot find struct layout in mapfor {:?}.", - struct_tag - )) - })?; - let move_struct = move_object.to_move_struct(&move_struct_layout)?; - let (name_value, type_, object_id) = - DynamicFieldInfo::parse_move_object(&move_struct).tap_err(|e| warn!("{e}"))?; - let name_type = move_object.type_().try_extract_field_name(&type_)?; - let bcs_name = bcs::to_bytes(&name_value.clone().undecorate()).map_err(|e| { - IndexerError::SerdeError(format!( - "Failed to serialize dynamic field name {:?}: {e}", - name_value - )) - })?; - let name = DynamicFieldName { - type_: name_type, - value: SuiMoveValue::from(name_value).to_json_value(), - }; - Ok(Some(match type_ { - DynamicFieldType::DynamicObject => { - let object = latest_objects - .get(&object_id) - .ok_or(IndexerError::UncategorizedError(anyhow::anyhow!( - "Failed to find object_id {:?} when trying to create dynamic field info", - object_id - )))?; - let version = object.version(); - let digest = object.digest(); - let object_type = object.data.type_().unwrap().clone(); - DynamicFieldInfo { - name, - bcs_name, - type_, - object_type: object_type.to_canonical_string(/* with_prefix */ true), - object_id, - version, - digest, - } - } - DynamicFieldType::DynamicField => DynamicFieldInfo { - name, - bcs_name, - type_, - object_type: move_object.into_type().into_type_params()[1] - .to_canonical_string(/* with_prefix */ true), - object_id: o.id(), - version: o.version(), - digest: o.digest(), - }, - })) -} diff --git a/crates/sui-indexer/src/handlers/mod.rs b/crates/sui-indexer/src/handlers/mod.rs deleted file mode 100644 index 587a13f22bb..00000000000 --- a/crates/sui-indexer/src/handlers/mod.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use crate::{ - models::display::StoredDisplay, - types::{ - IndexedCheckpoint, IndexedDeletedObject, IndexedEpochInfo, IndexedEvent, IndexedObject, - IndexedPackage, IndexedTransaction, TxIndex, - }, -}; - -pub mod checkpoint_handler; -pub mod committer; -pub mod objects_snapshot_processor; -pub mod tx_processor; - -#[derive(Debug)] -pub struct CheckpointDataToCommit { - pub checkpoint: IndexedCheckpoint, - pub transactions: Vec, - pub events: Vec, - pub tx_indices: Vec, - pub display_updates: BTreeMap, - pub object_changes: TransactionObjectChangesToCommit, - pub object_history_changes: TransactionObjectChangesToCommit, - pub packages: Vec, - pub epoch: Option, -} - -#[derive(Clone, Debug)] -pub struct TransactionObjectChangesToCommit { - pub changed_objects: Vec, - pub deleted_objects: Vec, -} - -#[derive(Clone, Debug)] -pub struct EpochToCommit { - pub last_epoch: Option, - pub new_epoch: IndexedEpochInfo, -} diff --git a/crates/sui-indexer/src/indexer.rs b/crates/sui-indexer/src/indexer.rs deleted file mode 100644 index 35a3ca79ef2..00000000000 --- a/crates/sui-indexer/src/indexer.rs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::env; - -use anyhow::Result; -use mysten_metrics::spawn_monitored_task; -use prometheus::Registry; -use tracing::info; - -use crate::{ - build_json_rpc_server, - errors::IndexerError, - framework::fetcher::CheckpointFetcher, - handlers::{ - checkpoint_handler::new_handlers, - objects_snapshot_processor::{ObjectsSnapshotProcessor, SnapshotLagConfig}, - }, - indexer_reader::IndexerReader, - metrics::IndexerMetrics, - store::IndexerStore, - IndexerConfig, -}; - -const DOWNLOAD_QUEUE_SIZE: usize = 200; - -pub struct Indexer; - -impl Indexer { - pub async fn start_writer( - config: &IndexerConfig, - store: S, - metrics: IndexerMetrics, - ) -> Result<(), IndexerError> { - let snapshot_config = SnapshotLagConfig::default(); - Indexer::start_writer_with_config(config, store, metrics, snapshot_config).await - } - - pub async fn start_writer_with_config( - config: &IndexerConfig, - store: S, - metrics: IndexerMetrics, - snapshot_config: SnapshotLagConfig, - ) -> Result<(), IndexerError> { - info!( - "Sui Indexer Writer (version {:?}) started...", - env!("CARGO_PKG_VERSION") - ); - - // None will be returned when checkpoints table is empty. - let last_seq_from_db = store - .get_latest_tx_checkpoint_sequence_number() - .await - .expect("Failed to get latest tx checkpoint sequence number from DB"); - let download_queue_size = env::var("DOWNLOAD_QUEUE_SIZE") - .unwrap_or_else(|_| DOWNLOAD_QUEUE_SIZE.to_string()) - .parse::() - .expect("Invalid DOWNLOAD_QUEUE_SIZE"); - let (downloaded_checkpoint_data_sender, downloaded_checkpoint_data_receiver) = - mysten_metrics::metered_channel::channel( - download_queue_size, - &mysten_metrics::get_metrics() - .unwrap() - .channels - .with_label_values(&["checkpoint_tx_downloading"]), - ); - - let rest_api_url = format!("{}/rest", config.rpc_client_url); - let rest_client = sui_rest_api::Client::new(&rest_api_url); - let fetcher = CheckpointFetcher::new( - rest_client.clone(), - last_seq_from_db, - downloaded_checkpoint_data_sender, - metrics.clone(), - ); - spawn_monitored_task!(fetcher.run()); - - let objects_snapshot_processor = ObjectsSnapshotProcessor::new_with_config( - store.clone(), - metrics.clone(), - snapshot_config, - ); - spawn_monitored_task!(objects_snapshot_processor.start()); - - let checkpoint_handler = new_handlers(store, metrics.clone()).await?; - crate::framework::runner::run( - mysten_metrics::metered_channel::ReceiverStream::new( - downloaded_checkpoint_data_receiver, - ), - vec![Box::new(checkpoint_handler)], - metrics, - ) - .await; - - Ok(()) - } - - pub async fn start_reader( - config: &IndexerConfig, - registry: &Registry, - db_url: String, - ) -> Result<(), IndexerError> { - info!( - "Sui Indexer Reader (version {:?}) started...", - env!("CARGO_PKG_VERSION") - ); - let indexer_reader = IndexerReader::new(db_url)?; - let handle = build_json_rpc_server(registry, indexer_reader, config, None) - .await - .expect("Json rpc server should not run into errors upon start."); - tokio::spawn(async move { handle.stopped().await }) - .await - .expect("Rpc server task failed"); - - Ok(()) - } -} diff --git a/crates/sui-indexer/src/lib.rs b/crates/sui-indexer/src/lib.rs deleted file mode 100644 index 0510939629a..00000000000 --- a/crates/sui-indexer/src/lib.rs +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -#![recursion_limit = "256"] - -use std::net::SocketAddr; - -use anyhow::{anyhow, Result}; -use clap::Parser; -use errors::IndexerError; -use jsonrpsee::http_client::{HeaderMap, HeaderValue, HttpClient, HttpClientBuilder}; -use metrics::IndexerMetrics; -use prometheus::Registry; -use sui_json_rpc::{JsonRpcServerBuilder, ServerHandle, ServerType}; -use sui_json_rpc_api::CLIENT_SDK_TYPE_HEADER; -use tokio::runtime::Handle; -use tracing::warn; -use url::Url; - -use crate::{ - apis::{ - CoinReadApi, ExtendedApi, GovernanceReadApi, IndexerApi, MoveUtilsApi, ReadApi, - TransactionBuilderApi, WriteApi, - }, - indexer_reader::IndexerReader, -}; - -pub mod apis; -pub mod db; -pub mod errors; -pub mod framework; -pub mod handlers; -pub mod indexer; -pub mod indexer_reader; -pub mod metrics; -pub mod models; -pub mod schema; -pub mod store; -pub mod test_utils; -pub mod types; - -#[derive(Parser, Clone, Debug)] -#[clap( - name = "Sui indexer", - about = "An off-fullnode service serving data from Sui protocol", - rename_all = "kebab-case" -)] -pub struct IndexerConfig { - #[clap(long)] - pub db_url: Option, - #[clap(long)] - pub db_user_name: Option, - #[clap(long)] - pub db_password: Option, - #[clap(long)] - pub db_host: Option, - #[clap(long)] - pub db_port: Option, - #[clap(long)] - pub db_name: Option, - #[clap(long, default_value = "http://0.0.0.0:9000", global = true)] - pub rpc_client_url: String, - #[clap(long, default_value = "0.0.0.0", global = true)] - pub client_metric_host: String, - #[clap(long, default_value = "9184", global = true)] - pub client_metric_port: u16, - #[clap(long, default_value = "0.0.0.0", global = true)] - pub rpc_server_url: String, - #[clap(long, default_value = "9000", global = true)] - pub rpc_server_port: u16, - #[clap(long)] - pub reset_db: bool, - #[clap(long)] - pub fullnode_sync_worker: bool, - #[clap(long)] - pub rpc_server_worker: bool, -} - -impl IndexerConfig { - /// returns connection url without the db name - pub fn base_connection_url(&self) -> Result { - let url_str = self.get_db_url()?; - let url = Url::parse(&url_str).expect("Failed to parse URL"); - Ok(format!( - "{}://{}:{}@{}:{}/", - url.scheme(), - url.username(), - url.password().unwrap_or_default(), - url.host_str().unwrap_or_default(), - url.port().unwrap_or_default() - )) - } - - pub fn get_db_url(&self) -> Result { - match ( - &self.db_url, - &self.db_user_name, - &self.db_password, - &self.db_host, - &self.db_port, - &self.db_name, - ) { - (Some(db_url), _, _, _, _, _) => Ok(db_url.clone()), - ( - None, - Some(db_user_name), - Some(db_password), - Some(db_host), - Some(db_port), - Some(db_name), - ) => Ok(format!( - "postgres://{}:{}@{}:{}/{}", - db_user_name, db_password, db_host, db_port, db_name - )), - _ => Err(anyhow!( - "Invalid db connection config, either db_url or (db_user_name, db_password, db_host, db_port, db_name) must be provided" - )), - } - } -} - -impl Default for IndexerConfig { - fn default() -> Self { - Self { - db_url: Some("postgres://postgres:postgres@localhost:5432/sui_indexer".to_string()), - db_user_name: None, - db_password: None, - db_host: None, - db_port: None, - db_name: None, - rpc_client_url: "http://127.0.0.1:9000".to_string(), - client_metric_host: "0.0.0.0".to_string(), - client_metric_port: 9184, - rpc_server_url: "0.0.0.0".to_string(), - rpc_server_port: 9000, - reset_db: false, - fullnode_sync_worker: true, - rpc_server_worker: true, - } - } -} - -pub async fn build_json_rpc_server( - prometheus_registry: &Registry, - reader: IndexerReader, - config: &IndexerConfig, - custom_runtime: Option, -) -> Result { - let mut builder = JsonRpcServerBuilder::new(env!("CARGO_PKG_VERSION"), prometheus_registry); - let http_client = crate::get_http_client(config.rpc_client_url.as_str())?; - - builder.register_module(WriteApi::new(http_client.clone()))?; - builder.register_module(IndexerApi::new(reader.clone()))?; - builder.register_module(TransactionBuilderApi::new(reader.clone()))?; - builder.register_module(MoveUtilsApi::new(reader.clone()))?; - builder.register_module(GovernanceReadApi::new(reader.clone()))?; - builder.register_module(ReadApi::new(reader.clone()))?; - builder.register_module(CoinReadApi::new(reader.clone()))?; - builder.register_module(ExtendedApi::new(reader.clone()))?; - - let default_socket_addr: SocketAddr = SocketAddr::new( - // unwrap() here is safe b/c the address is a static config. - config.rpc_server_url.as_str().parse().unwrap(), - config.rpc_server_port, - ); - Ok(builder - .start(default_socket_addr, custom_runtime, Some(ServerType::Http)) - .await?) -} - -fn get_http_client(rpc_client_url: &str) -> Result { - let mut headers = HeaderMap::new(); - headers.insert(CLIENT_SDK_TYPE_HEADER, HeaderValue::from_static("indexer")); - - HttpClientBuilder::default() - .max_request_body_size(2 << 30) - .max_concurrent_requests(usize::MAX) - .set_headers(headers.clone()) - .build(rpc_client_url) - .map_err(|e| { - warn!("Failed to get new Http client with error: {:?}", e); - IndexerError::HttpClientInitError(format!( - "Failed to initialize fullnode RPC client with error: {:?}", - e - )) - }) -} diff --git a/crates/sui-indexer/src/main.rs b/crates/sui-indexer/src/main.rs deleted file mode 100644 index e633436639b..00000000000 --- a/crates/sui-indexer/src/main.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use clap::Parser; -use sui_indexer::{ - db::{get_pg_pool_connection, new_pg_connection_pool, reset_database}, - errors::IndexerError, - indexer::Indexer, - metrics::{start_prometheus_server, IndexerMetrics}, - store::PgIndexerStore, - IndexerConfig, -}; -use tracing::{error, info}; - -#[tokio::main] -async fn main() -> Result<(), IndexerError> { - // NOTE: this is to print out tracing like info, warn & error. - let _guard = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .init(); - - let indexer_config = IndexerConfig::parse(); - info!("Parsed indexer config: {:#?}", indexer_config); - - let db_url = indexer_config.get_db_url().map_err(|e| { - IndexerError::PgPoolConnectionError(format!( - "Failed parsing database url with error {:?}", - e - )) - })?; - let blocking_cp = new_pg_connection_pool(&db_url, None).map_err(|e| { - error!( - "Failed creating Postgres connection pool with error {:?}", - e - ); - e - })?; - if indexer_config.reset_db { - let mut conn = get_pg_pool_connection(&blocking_cp).map_err(|e| { - error!( - "Failed getting Postgres connection from connection pool with error {:?}", - e - ); - e - })?; - reset_database(&mut conn, /* drop_all */ true).map_err(|e| { - let db_err_msg = format!( - "Failed resetting database with url: {:?} and error: {:?}", - db_url, e - ); - error!("{}", db_err_msg); - IndexerError::PostgresResetError(db_err_msg) - })?; - } - - let (_registry_service, registry) = start_prometheus_server( - // NOTE: this parses the input host addr and port number for socket addr, - // so unwrap() is safe here. - format!( - "{}:{}", - indexer_config.client_metric_host, indexer_config.client_metric_port - ) - .parse() - .unwrap(), - indexer_config.rpc_client_url.as_str(), - )?; - let indexer_metrics = IndexerMetrics::new(®istry); - mysten_metrics::init_metrics(®istry); - - let report_cp = blocking_cp.clone(); - let report_metrics = indexer_metrics.clone(); - tokio::spawn(async move { - loop { - let cp_state = report_cp.state(); - info!( - "DB connection pool size: {}, with idle conn: {}.", - cp_state.connections, cp_state.idle_connections - ); - report_metrics - .db_conn_pool_size - .set(cp_state.connections as i64); - report_metrics - .idle_db_conn - .set(cp_state.idle_connections as i64); - tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; - } - }); - - if indexer_config.fullnode_sync_worker { - let store = PgIndexerStore::new(blocking_cp, indexer_metrics.clone()); - return Indexer::start_writer(&indexer_config, store, indexer_metrics).await; - } else if indexer_config.rpc_server_worker { - return Indexer::start_reader(&indexer_config, ®istry, db_url).await; - } - Ok(()) -} diff --git a/crates/sui-indexer/src/metrics.rs b/crates/sui-indexer/src/metrics.rs deleted file mode 100644 index a14975a3053..00000000000 --- a/crates/sui-indexer/src/metrics.rs +++ /dev/null @@ -1,670 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::HashMap, net::SocketAddr}; - -use axum::{extract::Extension, http::StatusCode, routing::get, Router}; -use mysten_metrics::RegistryService; -use prometheus::{ - register_histogram_with_registry, register_int_counter_with_registry, - register_int_gauge_with_registry, Histogram, IntCounter, IntGauge, Registry, TextEncoder, -}; -use regex::Regex; -use tracing::{info, warn}; - -const METRICS_ROUTE: &str = "/metrics"; - -pub fn start_prometheus_server( - addr: SocketAddr, - fn_url: &str, -) -> Result<(RegistryService, Registry), anyhow::Error> { - let converted_fn_url = convert_url(fn_url); - if converted_fn_url.is_none() { - warn!( - "Failed to convert full node url {} to a shorter version", - fn_url - ); - } - let fn_url_str = converted_fn_url.unwrap_or_else(|| "unknown_url".to_string()); - - let labels = HashMap::from([("indexer_fullnode".to_string(), fn_url_str)]); - info!("Starting prometheus server with labels: {:?}", labels); - let registry = Registry::new_custom(Some("indexer".to_string()), Some(labels))?; - let registry_service = RegistryService::new(registry.clone()); - - let app = Router::new() - .route(METRICS_ROUTE, get(metrics)) - .layer(Extension(registry_service.clone())); - - tokio::spawn(async move { - axum::Server::bind(&addr) - .serve(app.into_make_service()) - .await - .unwrap(); - }); - Ok((registry_service, registry)) -} - -async fn metrics(Extension(registry_service): Extension) -> (StatusCode, String) { - let metrics_families = registry_service.gather_all(); - match TextEncoder.encode_to_string(&metrics_families) { - Ok(metrics) => (StatusCode::OK, metrics), - Err(error) => ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("unable to encode metrics: {error}"), - ), - } -} - -fn convert_url(url_str: &str) -> Option { - // NOTE: unwrap here is safe because the regex is a constant. - let re = Regex::new(r"https?://([a-z0-9-]+\.[a-z0-9-]+\.[a-z]+)").unwrap(); - let captures = re.captures(url_str)?; - - captures.get(1).map(|m| m.as_str().to_string()) -} - -/// Prometheus metrics for sui-indexer. -// buckets defined in seconds -const LATENCY_SEC_BUCKETS: &[f64] = &[ - 0.001, 0.005, 0.01, 0.02, 0.05, 0.1, 0.25, 0.5, 1.0, 2.0, 3.0, 5.0, 10.0, 20.0, 40.0, 60.0, - 80.0, 100.0, 200.0, -]; - -const DB_COMMIT_LATENCY_SEC_BUCKETS: &[f64] = &[ - 0.001, 0.005, 0.01, 0.02, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 2.0, 3.0, - 5.0, 10.0, 20.0, 40.0, 60.0, 80.0, 100.0, 200.0, -]; - -#[derive(Clone)] -pub struct IndexerMetrics { - pub total_checkpoint_received: IntCounter, - pub total_tx_checkpoint_committed: IntCounter, - pub total_object_checkpoint_committed: IntCounter, - pub total_transaction_committed: IntCounter, - pub total_object_change_committed: IntCounter, - pub total_transaction_chunk_committed: IntCounter, - pub total_object_change_chunk_committed: IntCounter, - pub total_epoch_committed: IntCounter, - pub latest_fullnode_checkpoint_sequence_number: IntGauge, - pub latest_tx_checkpoint_sequence_number: IntGauge, - pub latest_indexer_object_checkpoint_sequence_number: IntGauge, - pub latest_object_snapshot_sequence_number: IntGauge, - // checkpoint E2E latency is: - // fullnode_download_latency + checkpoint_index_latency + db_commit_latency - pub checkpoint_download_bytes_size: IntGauge, - pub fullnode_checkpoint_data_download_latency: Histogram, - pub fullnode_checkpoint_wait_and_download_latency: Histogram, - pub fullnode_transaction_download_latency: Histogram, - pub fullnode_object_download_latency: Histogram, - pub checkpoint_index_latency: Histogram, - pub indexing_batch_size: IntGauge, - pub indexing_tx_object_changes_latency: Histogram, - pub indexing_objects_latency: Histogram, - pub indexing_get_object_in_mem_hit: IntCounter, - pub indexing_get_object_db_hit: IntCounter, - pub indexing_module_resolver_in_mem_hit: IntCounter, - pub indexing_package_resolver_in_mem_hit: IntCounter, - pub indexing_packages_latency: Histogram, - pub checkpoint_objects_index_latency: Histogram, - pub checkpoint_db_commit_latency: Histogram, - pub checkpoint_db_commit_latency_step_1: Histogram, - pub checkpoint_db_commit_latency_transactions: Histogram, - pub checkpoint_db_commit_latency_transactions_chunks: Histogram, - pub checkpoint_db_commit_latency_transactions_chunks_transformation: Histogram, - pub checkpoint_db_commit_latency_objects: Histogram, - pub checkpoint_db_commit_latency_objects_history: Histogram, - pub checkpoint_db_commit_latency_objects_chunks: Histogram, - pub checkpoint_db_commit_latency_objects_history_chunks: Histogram, - pub checkpoint_db_commit_latency_events: Histogram, - pub checkpoint_db_commit_latency_events_chunks: Histogram, - pub checkpoint_db_commit_latency_packages: Histogram, - pub checkpoint_db_commit_latency_tx_indices: Histogram, - pub checkpoint_db_commit_latency_tx_indices_chunks: Histogram, - pub checkpoint_db_commit_latency_checkpoints: Histogram, - pub checkpoint_db_commit_latency_epoch: Histogram, - pub advance_epoch_latency: Histogram, - pub update_object_snapshot_latency: Histogram, - pub tokio_blocking_task_wait_latency: Histogram, - // average latency of committing 1000 transactions. - // 1000 is not necessarily the batch size, it's to roughly map average tx commit latency to - // [0.1, 1] seconds, which is well covered by DB_COMMIT_LATENCY_SEC_BUCKETS. - pub thousand_transaction_avg_db_commit_latency: Histogram, - pub object_db_commit_latency: Histogram, - pub object_mutation_db_commit_latency: Histogram, - pub object_deletion_db_commit_latency: Histogram, - pub epoch_db_commit_latency: Histogram, - // latency of event websocket subscription - pub subscription_process_latency: Histogram, - pub transaction_per_checkpoint: Histogram, - // FN RPC latencies on the read path - // read.rs - pub get_transaction_block_latency: Histogram, - pub multi_get_transaction_blocks_latency: Histogram, - pub get_object_latency: Histogram, - pub multi_get_objects_latency: Histogram, - pub try_get_past_object_latency: Histogram, - pub try_multi_get_past_objects_latency: Histogram, - pub get_checkpoint_latency: Histogram, - pub get_checkpoints_latency: Histogram, - pub get_events_latency: Histogram, - pub get_loaded_child_objects_latency: Histogram, - pub get_total_transaction_blocks_latency: Histogram, - pub get_latest_checkpoint_sequence_number_latency: Histogram, - // indexer.rs - pub get_owned_objects_latency: Histogram, - pub query_transaction_blocks_latency: Histogram, - pub query_events_latency: Histogram, - pub get_dynamic_fields_latency: Histogram, - pub get_dynamic_field_object_latency: Histogram, - pub get_protocol_config_latency: Histogram, - // indexer state metrics - pub db_conn_pool_size: IntGauge, - pub idle_db_conn: IntGauge, - - pub address_processor_failure: IntCounter, - pub checkpoint_metrics_processor_failure: IntCounter, -} - -impl IndexerMetrics { - pub fn new(registry: &Registry) -> Self { - Self { - total_checkpoint_received: register_int_counter_with_registry!( - "total_checkpoint_received", - "Total number of checkpoint received", - registry, - ) - .unwrap(), - total_tx_checkpoint_committed: register_int_counter_with_registry!( - "total_checkpoint_committed", - "Total number of checkpoint committed", - registry, - ) - .unwrap(), - total_object_checkpoint_committed: register_int_counter_with_registry!( - "total_object_checkpoint_committed", - "Total number of object checkpoint committed", - registry, - ) - .unwrap(), - total_transaction_committed: register_int_counter_with_registry!( - "total_transaction_committed", - "Total number of transaction committed", - registry, - ) - .unwrap(), - total_object_change_committed: register_int_counter_with_registry!( - "total_object_change_committed", - "Total number of object change committed", - registry, - ) - .unwrap(), - total_transaction_chunk_committed: register_int_counter_with_registry!( - "total_transaction_chunk_commited", - "Total number of transaction chunk committed", - registry, - ) - .unwrap(), - total_object_change_chunk_committed: register_int_counter_with_registry!( - "total_object_change_chunk_committed", - "Total number of object change chunk committed", - registry, - ) - .unwrap(), - total_epoch_committed: register_int_counter_with_registry!( - "total_epoch_committed", - "Total number of epoch committed", - registry, - ) - .unwrap(), - latest_fullnode_checkpoint_sequence_number: register_int_gauge_with_registry!( - "latest_fullnode_checkpoint_sequence_number", - "Latest checkpoint sequence number from the Full Node", - registry, - ) - .unwrap(), - latest_tx_checkpoint_sequence_number: register_int_gauge_with_registry!( - "latest_indexer_checkpoint_sequence_number", - "Latest checkpoint sequence number from the Indexer", - registry, - ) - .unwrap(), - latest_indexer_object_checkpoint_sequence_number: register_int_gauge_with_registry!( - "latest_indexer_object_checkpoint_sequence_number", - "Latest object checkpoint sequence number from the Indexer", - registry, - ) - .unwrap(), - latest_object_snapshot_sequence_number: register_int_gauge_with_registry!( - "latest_object_snapshot_sequence_number", - "Latest object snapshot sequence number from the Indexer", - registry, - ).unwrap(), - checkpoint_download_bytes_size: register_int_gauge_with_registry!( - "checkpoint_download_bytes_size", - "Size of the downloaded checkpoint in bytes", - registry, - ).unwrap(), - fullnode_checkpoint_data_download_latency: register_histogram_with_registry!( - "fullnode_checkpoint_data_download_latency", - "Time spent in downloading checkpoint and transation for a new checkpoint from the Full Node", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - fullnode_checkpoint_wait_and_download_latency: register_histogram_with_registry!( - "fullnode_checkpoint_wait_and_download_latency", - "Time spent in waiting for a new checkpoint from the Full Node", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - - fullnode_transaction_download_latency: register_histogram_with_registry!( - "fullnode_transaction_download_latency", - "Time spent in waiting for a new transaction from the Full Node", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - fullnode_object_download_latency: register_histogram_with_registry!( - "fullnode_object_download_latency", - "Time spent in waiting for a new epoch from the Full Node", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - checkpoint_index_latency: register_histogram_with_registry!( - "checkpoint_index_latency", - "Time spent in indexing a checkpoint", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - indexing_batch_size: register_int_gauge_with_registry!( - "indexing_batch_size", - "Size of the indexing batch", - registry, - ).unwrap(), - indexing_tx_object_changes_latency: register_histogram_with_registry!( - "indexing_tx_object_changes_latency", - "Time spent in indexing object changes for a transaction", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - indexing_objects_latency: register_histogram_with_registry!( - "indexing_objects_latency", - "Time spent in indexing objects", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - indexing_packages_latency: register_histogram_with_registry!( - "indexing_packages_latency", - "Time spent in indexing packages", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - indexing_get_object_in_mem_hit: register_int_counter_with_registry!( - "indexing_get_object_in_mem_hit", - "Total number get object hit in mem", - registry, - ) - .unwrap(), - indexing_get_object_db_hit: register_int_counter_with_registry!( - "indexing_get_object_db_hit", - "Total number get object hit in db", - registry, - ) - .unwrap(), - indexing_module_resolver_in_mem_hit: register_int_counter_with_registry!( - "indexing_module_resolver_in_mem_hit", - "Total number module resolver hit in mem", - registry, - ) - .unwrap(), - indexing_package_resolver_in_mem_hit: register_int_counter_with_registry!( - "indexing_package_resolver_in_mem_hit", - "Total number package resolver hit in mem", - registry, - ) - .unwrap(), - checkpoint_objects_index_latency: register_histogram_with_registry!( - "checkpoint_object_index_latency", - "Time spent in indexing a checkpoint objects", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - checkpoint_db_commit_latency: register_histogram_with_registry!( - "checkpoint_db_commit_latency", - "Time spent commiting a checkpoint to the db", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - - checkpoint_db_commit_latency_step_1: register_histogram_with_registry!( - "checkpoint_db_commit_latency_step_1", - "Time spent commiting a checkpoint to the db, step 1", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - checkpoint_db_commit_latency_transactions: register_histogram_with_registry!( - "checkpoint_db_commit_latency_transactions", - "Time spent commiting transactions", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - checkpoint_db_commit_latency_transactions_chunks: register_histogram_with_registry!( - "checkpoint_db_commit_latency_transactions_chunks", - "Time spent commiting transactions chunks", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - checkpoint_db_commit_latency_transactions_chunks_transformation: register_histogram_with_registry!( - "checkpoint_db_commit_latency_transactions_transaformation", - "Time spent in transactions chunks transformation prior to commit", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - checkpoint_db_commit_latency_objects: register_histogram_with_registry!( - "checkpoint_db_commit_latency_objects", - "Time spent commiting objects", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - checkpoint_db_commit_latency_objects_history: register_histogram_with_registry!( - "checkpoint_db_commit_latency_objects_history", - "Time spent commiting objects history", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ).unwrap(), - checkpoint_db_commit_latency_objects_chunks: register_histogram_with_registry!( - "checkpoint_db_commit_latency_objects_chunks", - "Time spent commiting objects chunks", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - checkpoint_db_commit_latency_objects_history_chunks: register_histogram_with_registry!( - "checkpoint_db_commit_latency_objects_history_chunks", - "Time spent commiting objects history chunks", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ).unwrap(), - checkpoint_db_commit_latency_events: register_histogram_with_registry!( - "checkpoint_db_commit_latency_events", - "Time spent commiting events", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - checkpoint_db_commit_latency_events_chunks: register_histogram_with_registry!( - "checkpoint_db_commit_latency_events_chunks", - "Time spent commiting events chunks", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - - checkpoint_db_commit_latency_packages: register_histogram_with_registry!( - "checkpoint_db_commit_latency_packages", - "Time spent commiting packages", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - checkpoint_db_commit_latency_tx_indices: register_histogram_with_registry!( - "checkpoint_db_commit_latency_tx_indices", - "Time spent commiting tx indices", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - checkpoint_db_commit_latency_tx_indices_chunks: register_histogram_with_registry!( - "checkpoint_db_commit_latency_tx_indices_chunks", - "Time spent commiting tx_indices chunks", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - checkpoint_db_commit_latency_checkpoints: register_histogram_with_registry!( - "checkpoint_db_commit_latency_checkpoints", - "Time spent commiting checkpoints", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - checkpoint_db_commit_latency_epoch: register_histogram_with_registry!( - "checkpoint_db_commit_latency_epochs", - "Time spent commiting epochs", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - advance_epoch_latency: register_histogram_with_registry!( - "advance_epoch_latency", - "Time spent in advancing epoch", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ).unwrap(), - update_object_snapshot_latency: register_histogram_with_registry!( - "update_object_snapshot_latency", - "Time spent in updating object snapshot", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ).unwrap(), - tokio_blocking_task_wait_latency: register_histogram_with_registry!( - "tokio_blocking_task_wait_latency", - "Time spent to wait for tokio blocking task pool", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ).unwrap(), - thousand_transaction_avg_db_commit_latency: register_histogram_with_registry!( - "transaction_db_commit_latency", - "Average time spent commiting 1000 transactions to the db", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - object_db_commit_latency: register_histogram_with_registry!( - "object_db_commit_latency", - "Time spent commiting a object to the db", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - object_mutation_db_commit_latency: register_histogram_with_registry!( - "object_mutation_db_commit_latency", - "Time spent commiting a object mutation to the db", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - object_deletion_db_commit_latency: register_histogram_with_registry!( - "object_deletion_db_commit_latency", - "Time spent commiting a object deletion to the db", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - epoch_db_commit_latency: register_histogram_with_registry!( - "epoch_db_commit_latency", - "Time spent commiting a epoch to the db", - DB_COMMIT_LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - subscription_process_latency: register_histogram_with_registry!( - "subscription_process_latency", - "Time spent in process Websocket subscription", - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - transaction_per_checkpoint: register_histogram_with_registry!( - "transaction_per_checkpoint", - "Number of transactions per checkpoint", - vec![1.0, 2.0, 5.0, 10.0, 20.0, 50.0, 100.0, 200.0, 500.0, 1000.0, 2000.0, 5000.0], - registry, - ) - .unwrap(), - get_transaction_block_latency: register_histogram_with_registry!( - "get_transaction_block_latency", - "Time spent in get_transaction_block on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - multi_get_transaction_blocks_latency: register_histogram_with_registry!( - "multi_get_transaction_blocks_latency", - "Time spent in multi_get_transaction_blocks on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - get_object_latency: register_histogram_with_registry!( - "get_object_latency", - "Time spent in get_object on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - multi_get_objects_latency: register_histogram_with_registry!( - "multi_get_objects_latency", - "Time spent in multi_get_objects on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - try_get_past_object_latency: register_histogram_with_registry!( - "try_get_past_object_latency", - "Time spent in try_get_past_object on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - try_multi_get_past_objects_latency: register_histogram_with_registry!( - "try_multi_get_past_objects_latency", - "Time spent in try_multi_get_past_objects on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - get_checkpoint_latency: register_histogram_with_registry!( - "get_checkpoint_latency", - "Time spent in get_checkpoint on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - get_checkpoints_latency: register_histogram_with_registry!( - "get_checkpoints_latency", - "Time spent in get_checkpoints on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - get_events_latency: register_histogram_with_registry!( - "get_events_latency", - "Time spent in get_events on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - get_total_transaction_blocks_latency: register_histogram_with_registry!( - "get_total_transaction_blocks_latency", - "Time spent in get_total_transaction_blocks on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - get_latest_checkpoint_sequence_number_latency: register_histogram_with_registry!( - "get_latest_checkpoint_sequence_number_latency", - "Time spent in get_latest_checkpoint_sequence_number on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - get_owned_objects_latency: register_histogram_with_registry!( - "get_owned_objects_latency", - "Time spent in get_owned_objects on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - query_transaction_blocks_latency: register_histogram_with_registry!( - "query_transaction_blocks_latency", - "Time spent in query_transaction_blocks on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - query_events_latency: register_histogram_with_registry!( - "query_events_latency", - "Time spent in query_events on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - get_dynamic_fields_latency: register_histogram_with_registry!( - "get_dynamic_fields_latency", - "Time spent in get_dynamic_fields on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - get_dynamic_field_object_latency: register_histogram_with_registry!( - "get_dynamic_field_object_latency", - "Time spent in get_dynamic_field_object on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - get_loaded_child_objects_latency: register_histogram_with_registry!( - "get_loaded_child_objects_latency", - "Time spent in get_loaded_child_objects_latency on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - get_protocol_config_latency: register_histogram_with_registry!( - "get_protocol_config_latency", - "Time spent in get_protocol_config_latency on the fullnode behind.", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - db_conn_pool_size: register_int_gauge_with_registry!( - "db_conn_pool_size", - "Size of the database connection pool", - registry - ).unwrap(), - idle_db_conn: register_int_gauge_with_registry!( - "idle_db_conn", - "Number of idle database connections", - registry - ).unwrap(), - address_processor_failure: register_int_counter_with_registry!( - "address_processor_failure", - "Total number of address processor failure", - registry, - ) - .unwrap(), - checkpoint_metrics_processor_failure: register_int_counter_with_registry!( - "checkpoint_metrics_processor_failure", - "Total number of checkpoint metrics processor failure", - registry, - ) - .unwrap(), - } - } -} diff --git a/crates/sui-indexer/src/models/checkpoints.rs b/crates/sui-indexer/src/models/checkpoints.rs deleted file mode 100644 index e6801f5f064..00000000000 --- a/crates/sui-indexer/src/models/checkpoints.rs +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use diesel::prelude::*; -use sui_json_rpc_types::Checkpoint as RpcCheckpoint; -use sui_types::{base_types::TransactionDigest, digests::CheckpointDigest, gas::GasCostSummary}; - -use crate::{errors::IndexerError, schema::checkpoints, types::IndexedCheckpoint}; - -#[derive(Queryable, Insertable, Debug, Clone, Default)] -#[diesel(table_name = checkpoints)] -pub struct StoredCheckpoint { - pub sequence_number: i64, - pub checkpoint_digest: Vec, - pub epoch: i64, - pub network_total_transactions: i64, - pub previous_checkpoint_digest: Option>, - pub end_of_epoch: bool, - pub tx_digests: Vec>>, - pub timestamp_ms: i64, - pub total_gas_cost: i64, - pub computation_cost: i64, - pub storage_cost: i64, - pub storage_rebate: i64, - pub non_refundable_storage_fee: i64, - pub checkpoint_commitments: Vec, - pub validator_signature: Vec, - pub end_of_epoch_data: Option>, -} - -impl From<&IndexedCheckpoint> for StoredCheckpoint { - fn from(c: &IndexedCheckpoint) -> Self { - Self { - sequence_number: c.sequence_number as i64, - checkpoint_digest: c.checkpoint_digest.into_inner().to_vec(), - epoch: c.epoch as i64, - tx_digests: c - .tx_digests - .iter() - .map(|tx| Some(tx.into_inner().to_vec())) - .collect(), - network_total_transactions: c.network_total_transactions as i64, - previous_checkpoint_digest: c - .previous_checkpoint_digest - .as_ref() - .map(|d| (*d).into_inner().to_vec()), - timestamp_ms: c.timestamp_ms as i64, - total_gas_cost: c.total_gas_cost, - computation_cost: c.computation_cost as i64, - storage_cost: c.storage_cost as i64, - storage_rebate: c.storage_rebate as i64, - non_refundable_storage_fee: c.non_refundable_storage_fee as i64, - checkpoint_commitments: bcs::to_bytes(&c.checkpoint_commitments).unwrap(), - validator_signature: bcs::to_bytes(&c.validator_signature).unwrap(), - end_of_epoch_data: c - .end_of_epoch_data - .as_ref() - .map(|d| bcs::to_bytes(d).unwrap()), - end_of_epoch: c.end_of_epoch_data.is_some(), - } - } -} - -impl TryFrom for RpcCheckpoint { - type Error = IndexerError; - fn try_from(checkpoint: StoredCheckpoint) -> Result { - let parsed_digest = CheckpointDigest::try_from(checkpoint.checkpoint_digest.clone()) - .map_err(|e| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "Failed to decode checkpoint digest: {:?} with err: {:?}", - checkpoint.checkpoint_digest, e - )) - })?; - - let parsed_previous_digest: Option = checkpoint - .previous_checkpoint_digest - .map(|digest| { - CheckpointDigest::try_from(digest.clone()).map_err(|e| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "Failed to decode previous checkpoint digest: {:?} with err: {:?}", - digest, e - )) - }) - }) - .transpose()?; - - let transactions: Vec = checkpoint - .tx_digests - .into_iter() - .map(|tx_digest| match tx_digest { - None => Err(IndexerError::PersistentStorageDataCorruptionError( - "tx_digests should not contain null elements".to_string(), - )), - Some(tx_digest) => TransactionDigest::try_from(tx_digest.as_slice()).map_err(|e| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "Failed to decode transaction digest: {:?} with err: {:?}", - tx_digest, e - )) - }), - }) - .collect::, IndexerError>>()?; - - let validator_signature = - bcs::from_bytes(&checkpoint.validator_signature).map_err(|e| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "Failed to decode validator signature: {:?} with err: {:?}", - checkpoint.validator_signature, e - )) - })?; - - let checkpoint_commitments = - bcs::from_bytes(&checkpoint.checkpoint_commitments).map_err(|e| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "Failed to decode checkpoint commitments: {:?} with err: {:?}", - checkpoint.checkpoint_commitments, e - )) - })?; - - let end_of_epoch_data = checkpoint - .end_of_epoch_data - .map(|data| { - bcs::from_bytes(&data).map_err(|e| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "Failed to decode end of epoch data: {:?} with err: {:?}", - data, e - )) - }) - }) - .transpose()?; - - Ok(RpcCheckpoint { - epoch: checkpoint.epoch as u64, - sequence_number: checkpoint.sequence_number as u64, - digest: parsed_digest, - previous_digest: parsed_previous_digest, - end_of_epoch_data, - epoch_rolling_gas_cost_summary: GasCostSummary { - computation_cost: checkpoint.computation_cost as u64, - storage_cost: checkpoint.storage_cost as u64, - storage_rebate: checkpoint.storage_rebate as u64, - non_refundable_storage_fee: checkpoint.non_refundable_storage_fee as u64, - }, - network_total_transactions: checkpoint.network_total_transactions as u64, - timestamp_ms: checkpoint.timestamp_ms as u64, - transactions, - validator_signature, - checkpoint_commitments, - }) - } -} diff --git a/crates/sui-indexer/src/models/display.rs b/crates/sui-indexer/src/models/display.rs deleted file mode 100644 index 1c860f75f33..00000000000 --- a/crates/sui-indexer/src/models/display.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use diesel::prelude::*; -use sui_types::display::DisplayVersionUpdatedEvent; - -use crate::schema::display; - -#[derive(Queryable, Insertable, Debug, Clone)] -#[diesel(table_name = display)] -pub struct StoredDisplay { - pub object_type: String, - pub id: Vec, - pub version: i16, - pub bcs: Vec, -} - -impl StoredDisplay { - pub fn try_from_event(event: &sui_types::event::Event) -> Option { - let (ty, display_event) = DisplayVersionUpdatedEvent::try_from_event(event)?; - - Some(Self { - object_type: ty.to_canonical_string(/* with_prefix */ true), - id: display_event.id.bytes.to_vec(), - version: display_event.version as i16, - bcs: event.contents.clone(), - }) - } - - pub fn to_display_update_event(&self) -> Result { - bcs::from_bytes(&self.bcs) - } -} diff --git a/crates/sui-indexer/src/models/epoch.rs b/crates/sui-indexer/src/models/epoch.rs deleted file mode 100644 index 6b12557dc66..00000000000 --- a/crates/sui-indexer/src/models/epoch.rs +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use diesel::{Insertable, Queryable, Selectable}; -use sui_json_rpc_types::{EndOfEpochInfo, EpochInfo}; -use sui_types::sui_system_state::sui_system_state_summary::SuiSystemStateSummary; - -use crate::{errors::IndexerError, schema::epochs, types::IndexedEpochInfo}; - -#[derive(Queryable, Insertable, Debug, Clone, Default)] -#[diesel(table_name = epochs)] -pub struct StoredEpochInfo { - pub epoch: i64, - pub first_checkpoint_id: i64, - pub epoch_start_timestamp: i64, - pub reference_gas_price: i64, - pub protocol_version: i64, - pub total_stake: i64, - pub storage_fund_balance: i64, - pub system_state: Vec, - pub epoch_total_transactions: Option, - pub last_checkpoint_id: Option, - pub epoch_end_timestamp: Option, - pub storage_fund_reinvestment: Option, - pub storage_charge: Option, - pub storage_rebate: Option, - pub stake_subsidy_amount: Option, - pub total_gas_fees: Option, - pub total_stake_rewards_distributed: Option, - pub leftover_storage_fund_inflow: Option, - pub epoch_commitments: Option>, -} - -#[derive(Queryable, Selectable, Clone)] -#[diesel(table_name = epochs)] -pub struct QueryableEpochInfo { - pub epoch: i64, - pub first_checkpoint_id: i64, - pub epoch_start_timestamp: i64, - pub reference_gas_price: i64, - pub protocol_version: i64, - pub total_stake: i64, - pub storage_fund_balance: i64, - pub epoch_total_transactions: Option, - pub last_checkpoint_id: Option, - pub epoch_end_timestamp: Option, - pub storage_fund_reinvestment: Option, - pub storage_charge: Option, - pub storage_rebate: Option, - pub stake_subsidy_amount: Option, - pub total_gas_fees: Option, - pub total_stake_rewards_distributed: Option, - pub leftover_storage_fund_inflow: Option, - pub epoch_commitments: Option>, -} - -#[derive(Queryable)] -pub struct QueryableEpochSystemState { - pub epoch: i64, - pub system_state: Vec, -} - -impl StoredEpochInfo { - pub fn from_epoch_beginning_info(e: &IndexedEpochInfo) -> Self { - Self { - epoch: e.epoch as i64, - first_checkpoint_id: e.first_checkpoint_id as i64, - epoch_start_timestamp: e.epoch_start_timestamp as i64, - reference_gas_price: e.reference_gas_price as i64, - protocol_version: e.protocol_version as i64, - total_stake: e.total_stake as i64, - storage_fund_balance: e.storage_fund_balance as i64, - ..Default::default() - } - } - - pub fn from_epoch_end_info(e: &IndexedEpochInfo) -> Self { - Self { - epoch: e.epoch as i64, - system_state: e.system_state.clone(), - epoch_total_transactions: e.epoch_total_transactions.map(|v| v as i64), - last_checkpoint_id: e.last_checkpoint_id.map(|v| v as i64), - epoch_end_timestamp: e.epoch_end_timestamp.map(|v| v as i64), - storage_fund_reinvestment: e.storage_fund_reinvestment.map(|v| v as i64), - storage_charge: e.storage_charge.map(|v| v as i64), - storage_rebate: e.storage_rebate.map(|v| v as i64), - stake_subsidy_amount: e.stake_subsidy_amount.map(|v| v as i64), - total_gas_fees: e.total_gas_fees.map(|v| v as i64), - total_stake_rewards_distributed: e.total_stake_rewards_distributed.map(|v| v as i64), - leftover_storage_fund_inflow: e.leftover_storage_fund_inflow.map(|v| v as i64), - epoch_commitments: e - .epoch_commitments - .as_ref() - .map(|v| bcs::to_bytes(&v).unwrap()), - - // For the following fields: - // we don't update these columns when persisting EndOfEpoch data. - // However if the data is partial, diesel would interpret them - // as Null and hence cause errors. - first_checkpoint_id: 0, - epoch_start_timestamp: 0, - reference_gas_price: 0, - protocol_version: 0, - total_stake: 0, - storage_fund_balance: 0, - } - } -} - -impl From<&StoredEpochInfo> for Option { - fn from(info: &StoredEpochInfo) -> Option { - Some(EndOfEpochInfo { - reference_gas_price: (info.reference_gas_price as u64), - protocol_version: (info.protocol_version as u64), - last_checkpoint_id: info.last_checkpoint_id.map(|v| v as u64)?, - total_stake: info.total_stake as u64, - storage_fund_balance: info.storage_fund_balance as u64, - epoch_end_timestamp: info.epoch_end_timestamp.map(|v| v as u64)?, - storage_fund_reinvestment: info.storage_fund_reinvestment.map(|v| v as u64)?, - storage_charge: info.storage_charge.map(|v| v as u64)?, - storage_rebate: info.storage_rebate.map(|v| v as u64)?, - stake_subsidy_amount: info.stake_subsidy_amount.map(|v| v as u64)?, - total_gas_fees: info.total_gas_fees.map(|v| v as u64)?, - total_stake_rewards_distributed: info - .total_stake_rewards_distributed - .map(|v| v as u64)?, - leftover_storage_fund_inflow: info.leftover_storage_fund_inflow.map(|v| v as u64)?, - }) - } -} - -impl TryFrom for EpochInfo { - type Error = IndexerError; - - fn try_from(value: StoredEpochInfo) -> Result { - let epoch = value.epoch as u64; - let end_of_epoch_info = (&value).into(); - let system_state: Option = bcs::from_bytes(&value.system_state) - .map_err(|_| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "Failed to deserialize `system_state` for epoch {epoch}", - )) - }) - .ok(); - Ok(EpochInfo { - epoch: value.epoch as u64, - validators: system_state - .map(|s| s.active_validators) - .unwrap_or_default(), - epoch_total_transactions: value.epoch_total_transactions.unwrap_or(0) as u64, - first_checkpoint_id: value.first_checkpoint_id as u64, - epoch_start_timestamp: value.epoch_start_timestamp as u64, - end_of_epoch_info, - reference_gas_price: Some(value.reference_gas_price as u64), - }) - } -} diff --git a/crates/sui-indexer/src/models/events.rs b/crates/sui-indexer/src/models/events.rs deleted file mode 100644 index 85c901d5af8..00000000000 --- a/crates/sui-indexer/src/models/events.rs +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::str::FromStr; - -use diesel::prelude::*; -use move_bytecode_utils::module_cache::GetModule; -use move_core_types::identifier::Identifier; -use sui_json_rpc_types::{SuiEvent, SuiMoveStruct}; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, - digests::TransactionDigest, - event::EventID, - object::{bounded_visitor::BoundedVisitor, MoveObject}, - parse_sui_struct_tag, -}; - -use crate::{errors::IndexerError, schema::events, types::IndexedEvent}; - -#[derive(Queryable, QueryableByName, Insertable, Debug, Clone)] -#[diesel(table_name = events)] -pub struct StoredEvent { - #[diesel(sql_type = diesel::sql_types::BigInt)] - pub tx_sequence_number: i64, - - #[diesel(sql_type = diesel::sql_types::BigInt)] - pub event_sequence_number: i64, - - #[diesel(sql_type = diesel::sql_types::Bytea)] - pub transaction_digest: Vec, - - #[diesel(sql_type = diesel::sql_types::BigInt)] - pub checkpoint_sequence_number: i64, - - #[diesel(sql_type = diesel::sql_types::Array>)] - pub senders: Vec>>, - - #[diesel(sql_type = diesel::sql_types::Bytea)] - pub package: Vec, - - #[diesel(sql_type = diesel::sql_types::Text)] - pub module: String, - - #[diesel(sql_type = diesel::sql_types::Text)] - pub event_type: String, - - #[diesel(sql_type = diesel::sql_types::BigInt)] - pub timestamp_ms: i64, - - #[diesel(sql_type = diesel::sql_types::Bytea)] - pub bcs: Vec, -} - -impl From for StoredEvent { - fn from(event: IndexedEvent) -> Self { - Self { - tx_sequence_number: event.tx_sequence_number as i64, - event_sequence_number: event.event_sequence_number as i64, - transaction_digest: event.transaction_digest.into_inner().to_vec(), - checkpoint_sequence_number: event.checkpoint_sequence_number as i64, - senders: event - .senders - .into_iter() - .map(|sender| Some(sender.to_vec())) - .collect(), - package: event.package.to_vec(), - module: event.module.clone(), - event_type: event.event_type.clone(), - bcs: event.bcs.clone(), - timestamp_ms: event.timestamp_ms as i64, - } - } -} - -impl StoredEvent { - pub fn try_into_sui_event( - self, - module_cache: &impl GetModule, - ) -> Result { - let package_id = ObjectID::from_bytes(self.package.clone()).map_err(|_e| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "Failed to parse event package ID: {:?}", - self.package - )) - })?; - // Note: SuiEvent only has one sender today, so we always use the first one. - let sender = self.senders.first().ok_or_else(|| { - IndexerError::PersistentStorageDataCorruptionError( - "Event senders should contain at least one address".to_string(), - ) - })?; - let sender = match sender { - Some(s) => SuiAddress::from_bytes(s).map_err(|_e| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "Failed to parse event sender address: {:?}", - sender - )) - })?, - None => { - return Err(IndexerError::PersistentStorageDataCorruptionError( - "Event senders element should not be null".to_string(), - )); - } - }; - - let type_ = parse_sui_struct_tag(&self.event_type)?; - - let layout = MoveObject::get_layout_from_struct_tag(type_.clone(), module_cache)?; - let move_object = BoundedVisitor::deserialize_struct(&self.bcs, &layout) - .map_err(|e| IndexerError::SerdeError(e.to_string()))?; - let parsed_json = SuiMoveStruct::from(move_object).to_json_value(); - let tx_digest = - TransactionDigest::try_from(self.transaction_digest.as_slice()).map_err(|e| { - IndexerError::SerdeError(format!( - "Failed to parse transaction digest: {:?}, error: {}", - self.transaction_digest, e - )) - })?; - Ok(SuiEvent { - id: EventID { - tx_digest, - event_seq: self.event_sequence_number as u64, - }, - package_id, - transaction_module: Identifier::from_str(&self.module)?, - sender, - type_, - bcs: self.bcs, - parsed_json, - timestamp_ms: Some(self.timestamp_ms as u64), - }) - } -} - -#[cfg(test)] -mod tests { - use move_core_types::{account_address::AccountAddress, language_storage::StructTag}; - use sui_types::event::Event; - - use super::*; - - #[test] - fn test_canonical_string_of_event_type() { - let tx_digest = TransactionDigest::default(); - let event = Event { - package_id: ObjectID::random(), - transaction_module: Identifier::new("test").unwrap(), - sender: AccountAddress::random().into(), - type_: StructTag { - address: AccountAddress::TWO, - module: Identifier::new("test").unwrap(), - name: Identifier::new("test").unwrap(), - type_params: vec![], - }, - contents: vec![], - }; - - let indexed_event = IndexedEvent::from_event(1, 1, 1, tx_digest, &event, 100); - - let stored_event = StoredEvent::from(indexed_event); - - assert_eq!( - stored_event.event_type, - "0x0000000000000000000000000000000000000000000000000000000000000002::test::test" - ); - } -} diff --git a/crates/sui-indexer/src/models/mod.rs b/crates/sui-indexer/src/models/mod.rs deleted file mode 100644 index 3b8233ec450..00000000000 --- a/crates/sui-indexer/src/models/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod checkpoints; -pub mod display; -pub mod epoch; -pub mod events; -pub mod objects; -pub mod packages; -pub mod transactions; -pub mod tx_indices; diff --git a/crates/sui-indexer/src/models/objects.rs b/crates/sui-indexer/src/models/objects.rs deleted file mode 100644 index 78cbfe5138b..00000000000 --- a/crates/sui-indexer/src/models/objects.rs +++ /dev/null @@ -1,511 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::HashMap; - -use diesel::prelude::*; -use move_bytecode_utils::module_cache::GetModule; -use serde::de::DeserializeOwned; -use sui_json_rpc::coin_api::parse_to_struct_tag; -use sui_json_rpc_types::{Balance, Coin as SuiCoin}; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber}, - digests::ObjectDigest, - dynamic_field::{DynamicFieldInfo, DynamicFieldName, DynamicFieldType, Field}, - object::{Object, ObjectRead}, -}; - -use crate::{ - errors::IndexerError, - schema::{objects, objects_history}, - types::{IndexedDeletedObject, IndexedObject, ObjectStatus}, -}; - -#[derive(Queryable)] -pub struct DynamicFieldColumn { - pub object_id: Vec, - pub object_version: i64, - pub object_digest: Vec, - pub df_kind: Option, - pub df_name: Option>, - pub df_object_type: Option, - pub df_object_id: Option>, -} - -#[derive(Queryable)] -pub struct ObjectRefColumn { - pub object_id: Vec, - pub object_version: i64, - pub object_digest: Vec, -} - -// NOTE: please add updating statement like below in pg_indexer_store.rs, -// if new columns are added here: -// objects::epoch.eq(excluded(objects::epoch)) -#[derive(Queryable, Insertable, Debug, Identifiable, Clone, QueryableByName)] -#[diesel(table_name = objects, primary_key(object_id))] -pub struct StoredObject { - pub object_id: Vec, - pub object_version: i64, - pub object_digest: Vec, - pub checkpoint_sequence_number: i64, - pub owner_type: i16, - pub owner_id: Option>, - /// The type of this object. This will be None if the object is a Package - pub object_type: Option, - pub serialized_object: Vec, - pub coin_type: Option, - // TODO deal with overflow - pub coin_balance: Option, - pub df_kind: Option, - pub df_name: Option>, - pub df_object_type: Option, - pub df_object_id: Option>, -} - -#[derive(Queryable, Insertable, Debug, Identifiable, Clone, QueryableByName)] -#[diesel(table_name = objects_history, primary_key(object_id, object_version, checkpoint_sequence_number))] -pub struct StoredHistoryObject { - pub object_id: Vec, - pub object_version: i64, - pub object_status: i16, - pub object_digest: Option>, - pub checkpoint_sequence_number: i64, - pub owner_type: Option, - pub owner_id: Option>, - pub object_type: Option, - pub serialized_object: Option>, - pub coin_type: Option, - pub coin_balance: Option, - pub df_kind: Option, - pub df_name: Option>, - pub df_object_type: Option, - pub df_object_id: Option>, -} - -impl From for StoredHistoryObject { - fn from(o: StoredObject) -> Self { - Self { - object_id: o.object_id, - object_version: o.object_version, - object_status: ObjectStatus::Active as i16, - object_digest: Some(o.object_digest), - checkpoint_sequence_number: o.checkpoint_sequence_number, - owner_type: Some(o.owner_type), - owner_id: o.owner_id, - object_type: o.object_type, - serialized_object: Some(o.serialized_object), - coin_type: o.coin_type, - coin_balance: o.coin_balance, - df_kind: o.df_kind, - df_name: o.df_name, - df_object_type: o.df_object_type, - df_object_id: o.df_object_id, - } - } -} - -#[derive(Queryable, Insertable, Debug, Identifiable, Clone, QueryableByName)] -#[diesel(table_name = objects, primary_key(object_id))] -pub struct StoredDeletedObject { - pub object_id: Vec, - pub object_version: i64, - pub checkpoint_sequence_number: i64, -} - -impl From for StoredDeletedObject { - fn from(o: IndexedDeletedObject) -> Self { - Self { - object_id: o.object_id.to_vec(), - object_version: o.object_version as i64, - checkpoint_sequence_number: o.checkpoint_sequence_number as i64, - } - } -} - -#[derive(Queryable, Insertable, Debug, Identifiable, Clone, QueryableByName)] -#[diesel(table_name = objects_history, primary_key(object_id, object_version, checkpoint_sequence_number))] -pub struct StoredDeletedHistoryObject { - pub object_id: Vec, - pub object_version: i64, - pub object_status: i16, - pub checkpoint_sequence_number: i64, -} - -impl From for StoredDeletedHistoryObject { - fn from(o: StoredDeletedObject) -> Self { - Self { - object_id: o.object_id, - object_version: o.object_version, - object_status: ObjectStatus::WrappedOrDeleted as i16, - checkpoint_sequence_number: o.checkpoint_sequence_number, - } - } -} - -impl From for StoredObject { - fn from(o: IndexedObject) -> Self { - Self { - object_id: o.object_id.to_vec(), - object_version: o.object_version as i64, - object_digest: o.object_digest.into_inner().to_vec(), - checkpoint_sequence_number: o.checkpoint_sequence_number as i64, - owner_type: o.owner_type as i16, - owner_id: o.owner_id.map(|id| id.to_vec()), - object_type: o - .object - .type_() - .map(|t| t.to_canonical_string(/* with_prefix */ true)), - serialized_object: bcs::to_bytes(&o.object).unwrap(), - coin_type: o.coin_type, - coin_balance: o.coin_balance.map(|b| b as i64), - df_kind: o.df_info.as_ref().map(|k| match k.type_ { - DynamicFieldType::DynamicField => 0, - DynamicFieldType::DynamicObject => 1, - }), - df_name: o.df_info.as_ref().map(|n| bcs::to_bytes(&n.name).unwrap()), - df_object_type: o.df_info.as_ref().map(|v| v.object_type.clone()), - df_object_id: o.df_info.as_ref().map(|v| v.object_id.to_vec()), - } - } -} - -impl TryFrom for Object { - type Error = IndexerError; - - fn try_from(o: StoredObject) -> Result { - bcs::from_bytes(&o.serialized_object).map_err(|e| { - IndexerError::SerdeError(format!( - "Failed to deserialize object: {:?}, error: {}", - o.object_id, e - )) - }) - } -} - -impl StoredObject { - pub fn try_into_object_read( - self, - module_cache: &impl GetModule, - ) -> Result { - let oref = self.get_object_ref()?; - let object: sui_types::object::Object = self.try_into()?; - let layout = object.get_layout(module_cache)?; - Ok(ObjectRead::Exists(oref, object, layout)) - } - - pub fn try_into_expectant_dynamic_field_info( - self, - module_cache: &impl GetModule, - ) -> Result { - match self.try_into_dynamic_field_info(module_cache).transpose() { - Some(Ok(info)) => Ok(info), - Some(Err(e)) => Err(e), - None => Err(IndexerError::PersistentStorageDataCorruptionError( - "Dynamic field object has incompatible dynamic field type: empty df_kind".into(), - )), - } - } - - pub fn try_into_dynamic_field_info( - self, - module_cache: &impl GetModule, - ) -> Result, IndexerError> { - if self.df_kind.is_none() { - return Ok(None); - } - - // Past this point, if there is any unexpected field, it's a data corruption - // error - let object_id = ObjectID::from_bytes(&self.object_id).map_err(|_| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "Can't convert {:?} to object_id", - self.object_id - )) - })?; - let object_digest = ObjectDigest::try_from(self.object_digest.as_slice()).map_err(|e| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "object {} has incompatible object digest. Error: {e}", - object_id - )) - })?; - let df_object_id = if let Some(df_object_id) = self.df_object_id { - ObjectID::from_bytes(df_object_id).map_err(|e| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "object {} has incompatible dynamic field type: df_object_id. Error: {e}", - object_id - )) - }) - } else { - return Err(IndexerError::PersistentStorageDataCorruptionError(format!( - "object {} has incompatible dynamic field type: empty df_object_id", - object_id - ))); - }?; - let type_ = match self.df_kind { - Some(0) => DynamicFieldType::DynamicField, - Some(1) => DynamicFieldType::DynamicObject, - _ => { - return Err(IndexerError::PersistentStorageDataCorruptionError(format!( - "object {} has incompatible dynamic field type: empty df_kind", - object_id - ))); - } - }; - let name = if let Some(field_name) = self.df_name { - let name: DynamicFieldName = bcs::from_bytes(&field_name).map_err(|e| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "object {} has incompatible dynamic field type: df_name. Error: {e}", - object_id - )) - })?; - name - } else { - return Err(IndexerError::PersistentStorageDataCorruptionError(format!( - "object {} has incompatible dynamic field type: empty df_name", - object_id - ))); - }; - let layout = move_bytecode_utils::layout::TypeLayoutBuilder::build_with_types( - &name.type_, - module_cache, - )?; - let sui_json_value = sui_json::SuiJsonValue::new(name.value.clone())?; - let bcs_name = sui_json_value.to_bcs_bytes(&layout)?; - let object_type = - self.df_object_type - .ok_or(IndexerError::PersistentStorageDataCorruptionError(format!( - "object {} has incompatible dynamic field type: empty df_object_type", - object_id - )))?; - Ok(Some(DynamicFieldInfo { - version: SequenceNumber::from_u64(self.object_version as u64), - digest: object_digest, - type_, - name, - bcs_name, - object_type, - object_id: df_object_id, - })) - } - - pub fn get_object_ref(&self) -> Result { - let object_id = ObjectID::from_bytes(self.object_id.clone()).map_err(|_| { - IndexerError::SerdeError(format!("Can't convert {:?} to object_id", self.object_id)) - })?; - let object_digest = - ObjectDigest::try_from(self.object_digest.as_slice()).map_err(|_| { - IndexerError::SerdeError(format!( - "Can't convert {:?} to object_digest", - self.object_digest - )) - })?; - Ok(( - object_id, - (self.object_version as u64).into(), - object_digest, - )) - } - - pub fn to_dynamic_field(&self) -> Option> - where - K: DeserializeOwned, - V: DeserializeOwned, - { - let object: Object = bcs::from_bytes(&self.serialized_object).ok()?; - - let object = object.data.try_as_move()?; - let ty = object.type_(); - - if !ty.is_dynamic_field() { - return None; - } - - bcs::from_bytes(object.contents()).ok() - } -} - -impl TryFrom for SuiCoin { - type Error = IndexerError; - - fn try_from(o: StoredObject) -> Result { - let object: Object = o.clone().try_into()?; - let (coin_object_id, version, digest) = o.get_object_ref()?; - let coin_type_canonical = - o.coin_type - .ok_or(IndexerError::PersistentStorageDataCorruptionError(format!( - "Object {} is supposed to be a coin but has an empty coin_type column", - coin_object_id, - )))?; - let coin_type = parse_to_struct_tag(coin_type_canonical.as_str()) - .map_err(|_| { - IndexerError::PersistentStorageDataCorruptionError(format!( - "The type of object {} cannot be parsed as a struct tag", - coin_object_id, - )) - })? - .to_string(); - let balance = o - .coin_balance - .ok_or(IndexerError::PersistentStorageDataCorruptionError(format!( - "Object {} is supposed to be a coin but has an empy coin_balance column", - coin_object_id, - )))?; - Ok(SuiCoin { - coin_type, - coin_object_id, - version, - digest, - balance: balance as u64, - previous_transaction: object.previous_transaction, - }) - } -} - -#[derive(QueryableByName)] -pub struct CoinBalance { - #[diesel(sql_type = diesel::sql_types::Text)] - pub coin_type: String, - #[diesel(sql_type = diesel::sql_types::BigInt)] - pub coin_num: i64, - #[diesel(sql_type = diesel::sql_types::BigInt)] - pub coin_balance: i64, -} - -impl TryFrom for Balance { - type Error = IndexerError; - - fn try_from(c: CoinBalance) -> Result { - let coin_type = parse_to_struct_tag(c.coin_type.as_str()) - .map_err(|_| { - IndexerError::PersistentStorageDataCorruptionError( - "The type of coin balance cannot be parsed as a struct tag".to_string(), - ) - })? - .to_string(); - Ok(Self { - coin_type, - coin_object_count: c.coin_num as usize, - // TODO: deal with overflow - total_balance: c.coin_balance as u128, - locked_balance: HashMap::default(), - }) - } -} - -#[cfg(test)] -mod tests { - use move_core_types::{account_address::AccountAddress, language_storage::StructTag}; - use sui_types::{ - coin::Coin, - digests::TransactionDigest, - gas_coin::{GasCoin, GAS}, - object::{Data, MoveObject, ObjectInner, Owner}, - Identifier, TypeTag, - }; - - use super::*; - - #[test] - fn test_canonical_string_of_object_type_for_coin() { - let test_obj = Object::new_gas_for_testing(); - let indexed_obj = IndexedObject::from_object(1, test_obj, None); - - let stored_obj = StoredObject::from(indexed_obj); - - match stored_obj.object_type { - Some(t) => { - assert_eq!( - t, - "0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" - ); - } - None => { - panic!("object_type should not be none"); - } - } - } - - #[test] - fn test_convert_stored_obj_to_sui_coin() { - let test_obj = Object::new_gas_for_testing(); - let indexed_obj = IndexedObject::from_object(1, test_obj, None); - - let stored_obj = StoredObject::from(indexed_obj); - - let sui_coin = SuiCoin::try_from(stored_obj).unwrap(); - assert_eq!(sui_coin.coin_type, "0x2::sui::SUI"); - } - - #[test] - fn test_output_format_coin_balance() { - let test_obj = Object::new_gas_for_testing(); - let indexed_obj = IndexedObject::from_object(1, test_obj, None); - - let stored_obj = StoredObject::from(indexed_obj); - let test_balance = CoinBalance { - coin_type: stored_obj.coin_type.unwrap(), - coin_num: 1, - coin_balance: 100, - }; - let balance = Balance::try_from(test_balance).unwrap(); - assert_eq!(balance.coin_type, "0x2::sui::SUI"); - } - - #[test] - fn test_vec_of_coin_sui_conversion() { - // 0xe7::vec_coin::VecCoin>> - let vec_coins_type = TypeTag::Vector(Box::new( - Coin::type_(TypeTag::Struct(Box::new(GAS::type_()))).into(), - )); - let object_type = StructTag { - address: AccountAddress::from_hex_literal("0xe7").unwrap(), - module: Identifier::new("vec_coin").unwrap(), - name: Identifier::new("VecCoin").unwrap(), - type_params: vec![vec_coins_type], - }; - - let id = ObjectID::ZERO; - let gas = 10; - - let contents = bcs::to_bytes(&vec![GasCoin::new(id, gas)]).unwrap(); - let data = Data::Move( - unsafe { - MoveObject::new_from_execution_with_limit( - object_type.into(), - true, - 1.into(), - contents, - 256, - ) - } - .unwrap(), - ); - - let owner = AccountAddress::from_hex_literal("0x1").unwrap(); - - let object = ObjectInner { - owner: Owner::AddressOwner(owner.into()), - data, - previous_transaction: TransactionDigest::genesis_marker(), - storage_rebate: 0, - } - .into(); - - let indexed_obj = IndexedObject::from_object(1, object, None); - - let stored_obj = StoredObject::from(indexed_obj); - - match stored_obj.object_type { - Some(t) => { - assert_eq!( - t, - "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin>>" - ); - } - None => { - panic!("object_type should not be none"); - } - } - } -} diff --git a/crates/sui-indexer/src/schema.patch b/crates/sui-indexer/src/schema.patch deleted file mode 100644 index 0caee130c40..00000000000 --- a/crates/sui-indexer/src/schema.patch +++ /dev/null @@ -1,7 +0,0 @@ -diff --git a/crates/sui-indexer/src/schema.rs b/crates/sui-indexer/src/schema.rs ---- a/crates/sui-indexer/src/schema.rs -+++ b/crates/sui-indexer/src/schema.rs -@@ -1 +1,3 @@ -+// Copyright (c) Mysten Labs, Inc. -+// SPDX-License-Identifier: Apache-2.0 - // @generated automatically by Diesel CLI. diff --git a/crates/sui-indexer/src/schema.rs b/crates/sui-indexer/src/schema.rs deleted file mode 100644 index eea28c74d88..00000000000 --- a/crates/sui-indexer/src/schema.rs +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -// @generated automatically by Diesel CLI. - -diesel::table! { - checkpoints (sequence_number) { - sequence_number -> Int8, - checkpoint_digest -> Bytea, - epoch -> Int8, - network_total_transactions -> Int8, - previous_checkpoint_digest -> Nullable, - end_of_epoch -> Bool, - tx_digests -> Array>, - timestamp_ms -> Int8, - total_gas_cost -> Int8, - computation_cost -> Int8, - storage_cost -> Int8, - storage_rebate -> Int8, - non_refundable_storage_fee -> Int8, - checkpoint_commitments -> Bytea, - validator_signature -> Bytea, - end_of_epoch_data -> Nullable, - } -} - -diesel::table! { - display (object_type) { - object_type -> Text, - id -> Bytea, - version -> Int2, - bcs -> Bytea, - } -} - -diesel::table! { - epochs (epoch) { - epoch -> Int8, - first_checkpoint_id -> Int8, - epoch_start_timestamp -> Int8, - reference_gas_price -> Int8, - protocol_version -> Int8, - total_stake -> Int8, - storage_fund_balance -> Int8, - system_state -> Bytea, - epoch_total_transactions -> Nullable, - last_checkpoint_id -> Nullable, - epoch_end_timestamp -> Nullable, - storage_fund_reinvestment -> Nullable, - storage_charge -> Nullable, - storage_rebate -> Nullable, - stake_subsidy_amount -> Nullable, - total_gas_fees -> Nullable, - total_stake_rewards_distributed -> Nullable, - leftover_storage_fund_inflow -> Nullable, - epoch_commitments -> Nullable, - } -} - -diesel::table! { - events (tx_sequence_number, event_sequence_number) { - tx_sequence_number -> Int8, - event_sequence_number -> Int8, - transaction_digest -> Bytea, - checkpoint_sequence_number -> Int8, - senders -> Array>, - package -> Bytea, - module -> Text, - event_type -> Text, - timestamp_ms -> Int8, - bcs -> Bytea, - } -} - -diesel::table! { - objects (object_id) { - object_id -> Bytea, - object_version -> Int8, - object_digest -> Bytea, - checkpoint_sequence_number -> Int8, - owner_type -> Int2, - owner_id -> Nullable, - object_type -> Nullable, - serialized_object -> Bytea, - coin_type -> Nullable, - coin_balance -> Nullable, - df_kind -> Nullable, - df_name -> Nullable, - df_object_type -> Nullable, - df_object_id -> Nullable, - } -} - -diesel::table! { - objects_history (checkpoint_sequence_number, object_id, object_version) { - object_id -> Bytea, - object_version -> Int8, - object_status -> Int2, - object_digest -> Nullable, - checkpoint_sequence_number -> Int8, - owner_type -> Nullable, - owner_id -> Nullable, - object_type -> Nullable, - serialized_object -> Nullable, - coin_type -> Nullable, - coin_balance -> Nullable, - df_kind -> Nullable, - df_name -> Nullable, - df_object_type -> Nullable, - df_object_id -> Nullable, - } -} - -diesel::table! { - objects_history_partition_0 (checkpoint_sequence_number, object_id, object_version) { - object_id -> Bytea, - object_version -> Int8, - object_status -> Int2, - object_digest -> Nullable, - checkpoint_sequence_number -> Int8, - owner_type -> Nullable, - owner_id -> Nullable, - object_type -> Nullable, - serialized_object -> Nullable, - coin_type -> Nullable, - coin_balance -> Nullable, - df_kind -> Nullable, - df_name -> Nullable, - df_object_type -> Nullable, - df_object_id -> Nullable, - } -} - -diesel::table! { - objects_snapshot (object_id) { - object_id -> Bytea, - object_version -> Int8, - object_status -> Int2, - object_digest -> Nullable, - checkpoint_sequence_number -> Int8, - owner_type -> Nullable, - owner_id -> Nullable, - object_type -> Nullable, - serialized_object -> Nullable, - coin_type -> Nullable, - coin_balance -> Nullable, - df_kind -> Nullable, - df_name -> Nullable, - df_object_type -> Nullable, - df_object_id -> Nullable, - } -} - -diesel::table! { - packages (package_id) { - package_id -> Bytea, - move_package -> Bytea, - } -} - -diesel::table! { - transactions (tx_sequence_number, checkpoint_sequence_number) { - tx_sequence_number -> Int8, - transaction_digest -> Bytea, - raw_transaction -> Bytea, - raw_effects -> Bytea, - checkpoint_sequence_number -> Int8, - timestamp_ms -> Int8, - object_changes -> Array>, - balance_changes -> Array>, - events -> Array>, - transaction_kind -> Int2, - success_command_count -> Int2, - } -} - -diesel::table! { - transactions_partition_0 (tx_sequence_number, checkpoint_sequence_number) { - tx_sequence_number -> Int8, - transaction_digest -> Bytea, - raw_transaction -> Bytea, - raw_effects -> Bytea, - checkpoint_sequence_number -> Int8, - timestamp_ms -> Int8, - object_changes -> Array>, - balance_changes -> Array>, - events -> Array>, - transaction_kind -> Int2, - success_command_count -> Int2, - } -} - -diesel::table! { - tx_calls (package, tx_sequence_number) { - tx_sequence_number -> Int8, - package -> Bytea, - module -> Text, - func -> Text, - } -} - -diesel::table! { - tx_changed_objects (object_id, tx_sequence_number) { - tx_sequence_number -> Int8, - object_id -> Bytea, - } -} - -diesel::table! { - tx_input_objects (object_id, tx_sequence_number) { - tx_sequence_number -> Int8, - object_id -> Bytea, - } -} - -diesel::table! { - tx_recipients (recipient, tx_sequence_number) { - tx_sequence_number -> Int8, - recipient -> Bytea, - } -} - -diesel::table! { - tx_senders (sender, tx_sequence_number) { - tx_sequence_number -> Int8, - sender -> Bytea, - } -} - -diesel::allow_tables_to_appear_in_same_query!( - checkpoints, - display, - epochs, - events, - objects, - objects_history, - objects_history_partition_0, - objects_snapshot, - packages, - transactions, - transactions_partition_0, - tx_calls, - tx_changed_objects, - tx_input_objects, - tx_recipients, - tx_senders, -); diff --git a/crates/sui-indexer/src/store/mod.rs b/crates/sui-indexer/src/store/mod.rs deleted file mode 100644 index 87bceff8d8a..00000000000 --- a/crates/sui-indexer/src/store/mod.rs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub(crate) use indexer_store::*; -pub use pg_indexer_store::PgIndexerStore; - -pub mod indexer_store; -pub mod module_resolver; -mod pg_indexer_store; -mod pg_partition_manager; -mod query; - -pub(crate) mod diesel_macro { - macro_rules! read_only_blocking { - ($pool:expr, $query:expr) => {{ - let mut pg_pool_conn = crate::db::get_pg_pool_connection($pool)?; - pg_pool_conn - .build_transaction() - .read_only() - .run($query) - .map_err(|e| IndexerError::PostgresReadError(e.to_string())) - }}; - } - - macro_rules! transactional_blocking_with_retry { - ($pool:expr, $query:expr, $max_elapsed:expr) => {{ - let mut backoff = backoff::ExponentialBackoff::default(); - backoff.max_elapsed_time = Some($max_elapsed); - - let result = match backoff::retry(backoff, || { - let mut pg_pool_conn = crate::db::get_pg_pool_connection($pool).map_err(|e| { - backoff::Error::Transient { - err: IndexerError::PostgresWriteError(e.to_string()), - retry_after: None, - } - })?; - pg_pool_conn - .build_transaction() - .read_write() - .run($query) - .map_err(|e| { - tracing::error!("Error with persisting data into DB: {:?}", e); - backoff::Error::Transient { - err: IndexerError::PostgresWriteError(e.to_string()), - retry_after: None, - } - }) - }) { - Ok(v) => Ok(v), - Err(backoff::Error::Transient { err, .. }) => Err(err), - Err(backoff::Error::Permanent(err)) => Err(err), - }; - - result - }}; - } - - pub(crate) use read_only_blocking; - pub(crate) use transactional_blocking_with_retry; -} diff --git a/crates/sui-indexer/src/store/query.rs b/crates/sui-indexer/src/store/query.rs deleted file mode 100644 index 8b5c3c2441b..00000000000 --- a/crates/sui-indexer/src/store/query.rs +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use sui_json_rpc_types::SuiObjectDataFilter; -use sui_types::base_types::ObjectID; - -pub trait DBFilter { - fn to_objects_history_sql(&self, cursor: Option, limit: usize, columns: Vec<&str>) - -> String; - fn to_latest_objects_sql(&self, cursor: Option, limit: usize, columns: Vec<&str>) -> String; -} - -impl DBFilter for SuiObjectDataFilter { - fn to_objects_history_sql( - &self, - cursor: Option, - limit: usize, - columns: Vec<&str>, - ) -> String { - let inner_clauses = to_clauses(self); - let inner_clauses = if let Some(inner_clauses) = inner_clauses { - format!("\n AND {inner_clauses}") - } else { - "".to_string() - }; - let outer_clauses = to_outer_clauses(self); - let outer_clauses = if let Some(outer_clauses) = outer_clauses { - format!("\nAND {outer_clauses}") - } else { - "".to_string() - }; - let cursor = if let Some(cursor) = cursor { - format!("\n AND o.object_id > '{cursor}'") - } else { - "".to_string() - }; - - let columns = columns - .iter() - .map(|c| format!("t1.{c}")) - .collect::>() - .join(", "); - // NOTE: order by checkpoint DESC so that whenever a row from checkpoint is - // available, we will pick that over the one from fast-path, which has - // checkpoint of -1. - format!( - "SELECT {columns} -FROM (SELECT DISTINCT ON (o.object_id) * - FROM objects_history o - WHERE o.checkpoint <= $1{cursor}{inner_clauses} - ORDER BY o.object_id, version, o.checkpoint DESC) AS t1 -WHERE t1.object_status NOT IN ('deleted', 'wrapped', 'unwrapped_then_deleted'){outer_clauses} -LIMIT {limit};" - ) - } - - fn to_latest_objects_sql( - &self, - cursor: Option, - limit: usize, - columns: Vec<&str>, - ) -> String { - let columns = columns - .iter() - .map(|c| format!("o.{c}")) - .collect::>() - .join(", "); - - let cursor = if let Some(cursor) = cursor { - format!(" AND o.object_id > '{cursor}'") - } else { - "".to_string() - }; - - let inner_clauses = to_latest_objects_clauses(self); - let inner_clauses = if let Some(inner_clauses) = inner_clauses { - format!(" AND {inner_clauses}") - } else { - "".to_string() - }; - - format!( - "SELECT {columns} -FROM objects o WHERE o.object_status NOT IN ('deleted', 'wrapped', 'unwrapped_then_deleted'){cursor}{inner_clauses} -LIMIT {limit};" - ) - } -} - -fn to_latest_objects_clauses(filter: &SuiObjectDataFilter) -> Option { - match filter { - SuiObjectDataFilter::AddressOwner(a) => Some(format!( - "(o.owner_type = 'address_owner' AND o.owner_address = '{a}')" - )), - _ => None, - } -} - -fn to_clauses(filter: &SuiObjectDataFilter) -> Option { - match filter { - SuiObjectDataFilter::MatchAll(sub_filters) => { - let sub_filters = sub_filters.iter().flat_map(to_clauses).collect::>(); - if sub_filters.is_empty() { - None - } else if sub_filters.len() == 1 { - Some(sub_filters[0].to_string()) - } else { - Some(format!("({})", sub_filters.join(" AND "))) - } - } - SuiObjectDataFilter::MatchAny(sub_filters) => { - let sub_filters = sub_filters.iter().flat_map(to_clauses).collect::>(); - if sub_filters.is_empty() { - // Any default to false - Some("FALSE".to_string()) - } else if sub_filters.len() == 1 { - Some(sub_filters[0].to_string()) - } else { - Some(format!("({})", sub_filters.join(" OR "))) - } - } - SuiObjectDataFilter::MatchNone(sub_filters) => { - let sub_filters = sub_filters.iter().flat_map(to_clauses).collect::>(); - if sub_filters.is_empty() { - None - } else { - Some(format!("NOT ({})", sub_filters.join(" OR "))) - } - } - SuiObjectDataFilter::Package(p) => { - Some(format!("o.object_type LIKE '{}::%'", p.to_hex_literal())) - } - SuiObjectDataFilter::MoveModule { package, module } => Some(format!( - "o.object_type LIKE '{}::{}::%'", - package.to_hex_literal(), - module - )), - SuiObjectDataFilter::StructType(s) => { - // If people do not provide type_params, we will match all type_params - // e.g. `0x2::coin::Coin` can match `0x2::coin::Coin<0x2::sui::SUI>` - if s.type_params.is_empty() { - Some(format!("o.object_type LIKE '{s}%'")) - } else { - Some(format!("o.object_type = '{s}'")) - } - } - SuiObjectDataFilter::AddressOwner(a) => Some(format!( - "((o.owner_type = 'address_owner' AND o.owner_address = '{a}') OR (o.old_owner_type = 'address_owner' AND o.old_owner_address = '{a}'))" - )), - SuiObjectDataFilter::ObjectOwner(o) => Some(format!( - "((o.owner_type = 'object_owner' AND o.owner_address = '{o}') OR (o.old_owner_type = 'object_owner' AND o.old_owner_address = '{o}'))" - )), - SuiObjectDataFilter::ObjectId(id) => Some(format!("o.object_id = '{id}'")), - SuiObjectDataFilter::ObjectIds(ids) => { - if ids.is_empty() { - None - } else { - let ids = ids - .iter() - .map(|o| o.to_string()) - .collect::>() - .join(", "); - Some(format!("o.object_id IN '{ids}'")) - } - } - SuiObjectDataFilter::Version(v) => Some(format!("o.version = {v}")), - } -} - -fn to_outer_clauses(filter: &SuiObjectDataFilter) -> Option { - match filter { - SuiObjectDataFilter::MatchNone(sub_filters) => { - let sub_filters = sub_filters - .iter() - .flat_map(to_outer_clauses) - .collect::>(); - if sub_filters.is_empty() { - None - } else { - Some(format!("NOT ({})", sub_filters.join(" OR "))) - } - } - SuiObjectDataFilter::MatchAll(sub_filters) => { - let sub_filters = sub_filters - .iter() - .flat_map(to_outer_clauses) - .collect::>(); - if sub_filters.is_empty() { - None - } else if sub_filters.len() == 1 { - Some(sub_filters[0].to_string()) - } else { - Some(format!("({})", sub_filters.join(" AND "))) - } - } - SuiObjectDataFilter::MatchAny(sub_filters) => { - let sub_filters = sub_filters - .iter() - .flat_map(to_outer_clauses) - .collect::>(); - if sub_filters.is_empty() { - None - } else if sub_filters.len() == 1 { - Some(sub_filters[0].to_string()) - } else { - Some(format!("({})", sub_filters.join(" OR "))) - } - } - SuiObjectDataFilter::AddressOwner(a) => Some(format!("t1.owner_address = '{a}'")), - _ => None, - } -} - -#[cfg(test)] -mod test { - use std::str::FromStr; - - use move_core_types::ident_str; - use sui_json_rpc_types::SuiObjectDataFilter; - use sui_types::{ - base_types::{ObjectID, SuiAddress}, - parse_sui_struct_tag, - }; - - use crate::store::query::DBFilter; - - #[test] - fn test_address_filter() { - let address = SuiAddress::from_str( - "0x92dd4d9b0150c251661d821583ef078024ae9e9ee11063e216500861eec7f381", - ) - .unwrap(); - let filter = SuiObjectDataFilter::AddressOwner(address); - - let expected_sql = "SELECT t1.* -FROM (SELECT DISTINCT ON (o.object_id) * - FROM objects_history o - WHERE o.checkpoint <= $1 - AND ((o.owner_type = 'address_owner' AND o.owner_address = '0x92dd4d9b0150c251661d821583ef078024ae9e9ee11063e216500861eec7f381') OR (o.old_owner_type = 'address_owner' AND o.old_owner_address = '0x92dd4d9b0150c251661d821583ef078024ae9e9ee11063e216500861eec7f381')) - ORDER BY o.object_id, version, o.checkpoint DESC) AS t1 -WHERE t1.object_status NOT IN ('deleted', 'wrapped', 'unwrapped_then_deleted') -AND t1.owner_address = '0x92dd4d9b0150c251661d821583ef078024ae9e9ee11063e216500861eec7f381' -LIMIT 100;"; - assert_eq!( - expected_sql, - filter.to_objects_history_sql(None, 100, vec!["*"]) - ); - } - - #[test] - fn test_move_module_filter() { - let filter = SuiObjectDataFilter::MoveModule { - package: ObjectID::from_str( - "0x485d947e293f07e659127dc5196146b49cdf2efbe4b233f4d293fc56aff2aa17", - ) - .unwrap(), - module: ident_str!("test_module").into(), - }; - let expected_sql = "SELECT t1.* -FROM (SELECT DISTINCT ON (o.object_id) * - FROM objects_history o - WHERE o.checkpoint <= $1 - AND o.object_type LIKE '0x485d947e293f07e659127dc5196146b49cdf2efbe4b233f4d293fc56aff2aa17::test_module::%' - ORDER BY o.object_id, version, o.checkpoint DESC) AS t1 -WHERE t1.object_status NOT IN ('deleted', 'wrapped', 'unwrapped_then_deleted') -LIMIT 100;"; - assert_eq!( - expected_sql, - filter.to_objects_history_sql(None, 100, vec!["*"]) - ); - } - - #[test] - fn test_empty_all_filter() { - let filter = SuiObjectDataFilter::MatchAll(vec![]); - let expected_sql = "SELECT t1.* -FROM (SELECT DISTINCT ON (o.object_id) * - FROM objects_history o - WHERE o.checkpoint <= $1 - ORDER BY o.object_id, version, o.checkpoint DESC) AS t1 -WHERE t1.object_status NOT IN ('deleted', 'wrapped', 'unwrapped_then_deleted') -LIMIT 100;"; - assert_eq!( - expected_sql, - filter.to_objects_history_sql(None, 100, vec!["*"]) - ); - } - - #[test] - fn test_empty_any_filter() { - let filter = SuiObjectDataFilter::MatchAny(vec![]); - let expected_sql = "SELECT t1.* -FROM (SELECT DISTINCT ON (o.object_id) * - FROM objects_history o - WHERE o.checkpoint <= $1 - AND FALSE - ORDER BY o.object_id, version, o.checkpoint DESC) AS t1 -WHERE t1.object_status NOT IN ('deleted', 'wrapped', 'unwrapped_then_deleted') -LIMIT 100;"; - assert_eq!( - expected_sql, - filter.to_objects_history_sql(None, 100, vec!["*"]) - ); - } - - #[test] - fn test_all_filter() { - let filter = SuiObjectDataFilter::MatchAll(vec![ - SuiObjectDataFilter::ObjectId( - ObjectID::from_str( - "0xef9fb75a7b3d4cb5551ef0b08c83528b94d5f5cd8be28b1d08a87dbbf3731738", - ) - .unwrap(), - ), - SuiObjectDataFilter::StructType(parse_sui_struct_tag("0x2::test::Test").unwrap()), - ]); - - let expected_sql = "SELECT t1.* -FROM (SELECT DISTINCT ON (o.object_id) * - FROM objects_history o - WHERE o.checkpoint <= $1 - AND (o.object_id = '0xef9fb75a7b3d4cb5551ef0b08c83528b94d5f5cd8be28b1d08a87dbbf3731738' AND o.object_type LIKE '0x2::test::Test%') - ORDER BY o.object_id, version, o.checkpoint DESC) AS t1 -WHERE t1.object_status NOT IN ('deleted', 'wrapped', 'unwrapped_then_deleted') -LIMIT 100;"; - assert_eq!( - expected_sql, - filter.to_objects_history_sql(None, 100, vec!["*"]) - ); - } -} diff --git a/crates/sui-indexer/src/test_utils.rs b/crates/sui-indexer/src/test_utils.rs deleted file mode 100644 index dcc2df10424..00000000000 --- a/crates/sui-indexer/src/test_utils.rs +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{env, net::SocketAddr, time::Duration}; - -use diesel::connection::SimpleConnection; -use mysten_metrics::init_metrics; -use sui_json_rpc_types::SuiTransactionBlockResponse; -use tokio::task::JoinHandle; -use tracing::info; - -use crate::{ - db::{new_pg_connection_pool_with_config, reset_database, PgConnectionPoolConfig}, - errors::IndexerError, - handlers::objects_snapshot_processor::SnapshotLagConfig, - indexer::Indexer, - store::PgIndexerStore, - IndexerConfig, IndexerMetrics, -}; - -pub enum ReaderWriterConfig { - Reader { reader_mode_rpc_url: String }, - Writer { snapshot_config: SnapshotLagConfig }, -} - -impl ReaderWriterConfig { - pub fn reader_mode(reader_mode_rpc_url: String) -> Self { - Self::Reader { - reader_mode_rpc_url, - } - } - - pub fn writer_mode(snapshot_config: Option) -> Self { - Self::Writer { - snapshot_config: snapshot_config.unwrap_or_default(), - } - } -} - -pub async fn start_test_indexer( - db_url: Option, - rpc_url: String, - reader_writer_config: ReaderWriterConfig, -) -> (PgIndexerStore, JoinHandle>) { - start_test_indexer_impl(db_url, rpc_url, reader_writer_config, None).await -} - -pub async fn start_test_indexer_impl( - db_url: Option, - rpc_url: String, - reader_writer_config: ReaderWriterConfig, - new_database: Option, -) -> (PgIndexerStore, JoinHandle>) { - // Reduce the connection pool size to 10 for testing - // to prevent maxing out - info!("Setting DB_POOL_SIZE to 10"); - std::env::set_var("DB_POOL_SIZE", "10"); - - let db_url = db_url.unwrap_or_else(|| { - let pg_host = env::var("POSTGRES_HOST").unwrap_or_else(|_| "localhost".into()); - let pg_port = env::var("POSTGRES_PORT").unwrap_or_else(|_| "32770".into()); - let pw = env::var("POSTGRES_PASSWORD").unwrap_or_else(|_| "postgrespw".into()); - format!("postgres://postgres:{pw}@{pg_host}:{pg_port}") - }); - - // dynamically set ports instead of all to 9000 - let base_port = rpc_url - .chars() - .rev() - .take(4) - .collect::() - .chars() - .rev() - .collect::() - .parse::() - .unwrap(); - - // Set connection timeout for tests to 1 second - let mut pool_config = PgConnectionPoolConfig::default(); - pool_config.set_connection_timeout(Duration::from_secs(1)); - - // Default writer mode - let mut config = IndexerConfig { - db_url: Some(db_url.clone()), - rpc_client_url: rpc_url, - reset_db: true, - fullnode_sync_worker: true, - rpc_server_worker: false, - rpc_server_port: base_port + 1, - ..Default::default() - }; - - let registry = prometheus::Registry::default(); - - init_metrics(®istry); - - let indexer_metrics = IndexerMetrics::new(®istry); - - let mut parsed_url = config.get_db_url().unwrap(); - - if let Some(new_database) = new_database { - // Switch to default to create a new database - let (default_db_url, _) = replace_db_name(&parsed_url, "postgres"); - - // Open in default mode - let blocking_pool = - new_pg_connection_pool_with_config(&default_db_url, Some(5), pool_config).unwrap(); - let mut default_conn = blocking_pool.get().unwrap(); - - // Delete the old db if it exists - default_conn - .batch_execute(&format!("DROP DATABASE IF EXISTS {}", new_database)) - .unwrap(); - - // Create the new db - default_conn - .batch_execute(&format!("CREATE DATABASE {}", new_database)) - .unwrap(); - parsed_url = replace_db_name(&parsed_url, &new_database).0; - } - - let blocking_pool = - new_pg_connection_pool_with_config(&parsed_url, Some(5), pool_config).unwrap(); - let store = PgIndexerStore::new(blocking_pool.clone(), indexer_metrics.clone()); - - let handle = match reader_writer_config { - ReaderWriterConfig::Reader { - reader_mode_rpc_url, - } => { - let reader_mode_rpc_url = reader_mode_rpc_url - .parse::() - .expect("Unable to parse fullnode address"); - config.fullnode_sync_worker = false; - config.rpc_server_worker = true; - config.rpc_server_url = reader_mode_rpc_url.ip().to_string(); - config.rpc_server_port = reader_mode_rpc_url.port(); - tokio::spawn(async move { Indexer::start_reader(&config, ®istry, db_url).await }) - } - ReaderWriterConfig::Writer { snapshot_config } => { - if config.reset_db { - reset_database(&mut blocking_pool.get().unwrap(), true).unwrap(); - } - let store_clone = store.clone(); - - tokio::spawn(async move { - Indexer::start_writer_with_config( - &config, - store_clone, - indexer_metrics, - snapshot_config, - ) - .await - }) - } - }; - - (store, handle) -} - -fn replace_db_name(db_url: &str, new_db_name: &str) -> (String, String) { - let pos = db_url.rfind('/').expect("Unable to find / in db_url"); - let old_db_name = &db_url[pos + 1..]; - - ( - format!("{}/{}", &db_url[..pos], new_db_name), - old_db_name.to_string(), - ) -} - -pub async fn force_delete_database(db_url: String) { - // Replace the database name with the default `postgres`, which should be the - // last string after `/` This is necessary because you can't drop a database - // while being connected to it. Hence switch to the default `postgres` - // database to drop the active database. - let (default_db_url, db_name) = replace_db_name(&db_url, "postgres"); - // Set connection timeout for tests to 1 second - let mut pool_config = PgConnectionPoolConfig::default(); - pool_config.set_connection_timeout(Duration::from_secs(1)); - - let blocking_pool = - new_pg_connection_pool_with_config(&default_db_url, Some(5), pool_config).unwrap(); - blocking_pool - .get() - .unwrap() - .batch_execute(&format!("DROP DATABASE IF EXISTS {} WITH (FORCE)", db_name)) - .unwrap(); -} - -#[derive(Clone)] -pub struct SuiTransactionBlockResponseBuilder<'a> { - response: SuiTransactionBlockResponse, - full_response: &'a SuiTransactionBlockResponse, -} - -impl<'a> SuiTransactionBlockResponseBuilder<'a> { - pub fn new(full_response: &'a SuiTransactionBlockResponse) -> Self { - Self { - response: SuiTransactionBlockResponse::default(), - full_response, - } - } - - pub fn with_input(mut self) -> Self { - self.response = SuiTransactionBlockResponse { - transaction: self.full_response.transaction.clone(), - ..self.response - }; - self - } - - pub fn with_raw_input(mut self) -> Self { - self.response = SuiTransactionBlockResponse { - raw_transaction: self.full_response.raw_transaction.clone(), - ..self.response - }; - self - } - - pub fn with_effects(mut self) -> Self { - self.response = SuiTransactionBlockResponse { - effects: self.full_response.effects.clone(), - ..self.response - }; - self - } - - pub fn with_events(mut self) -> Self { - self.response = SuiTransactionBlockResponse { - events: self.full_response.events.clone(), - ..self.response - }; - self - } - - pub fn with_balance_changes(mut self) -> Self { - self.response = SuiTransactionBlockResponse { - balance_changes: self.full_response.balance_changes.clone(), - ..self.response - }; - self - } - - pub fn with_object_changes(mut self) -> Self { - self.response = SuiTransactionBlockResponse { - object_changes: self.full_response.object_changes.clone(), - ..self.response - }; - self - } - - pub fn with_input_and_changes(mut self) -> Self { - self.response = SuiTransactionBlockResponse { - transaction: self.full_response.transaction.clone(), - balance_changes: self.full_response.balance_changes.clone(), - object_changes: self.full_response.object_changes.clone(), - ..self.response - }; - self - } - - pub fn build(self) -> SuiTransactionBlockResponse { - SuiTransactionBlockResponse { - transaction: self.response.transaction, - raw_transaction: self.response.raw_transaction, - effects: self.response.effects, - events: self.response.events, - balance_changes: self.response.balance_changes, - object_changes: self.response.object_changes, - // Use full response for any fields that aren't showable - ..self.full_response.clone() - } - } -} diff --git a/crates/sui-indexer/src/types.rs b/crates/sui-indexer/src/types.rs deleted file mode 100644 index 089fb130ee8..00000000000 --- a/crates/sui-indexer/src/types.rs +++ /dev/null @@ -1,633 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use move_core_types::language_storage::StructTag; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use sui_json_rpc_types::{ - ObjectChange, SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, -}; -use sui_types::{ - base_types::{ObjectDigest, ObjectID, SequenceNumber, SuiAddress}, - crypto::AggregateAuthoritySignature, - digests::TransactionDigest, - dynamic_field::DynamicFieldInfo, - effects::TransactionEffects, - event::SystemEpochInfoEvent, - messages_checkpoint::{ - CertifiedCheckpointSummary, CheckpointCommitment, CheckpointDigest, EndOfEpochData, - }, - move_package::MovePackage, - object::{Object, Owner}, - sui_serde::SuiStructTag, - sui_system_state::sui_system_state_summary::SuiSystemStateSummary, - transaction::SenderSignedData, -}; - -use crate::errors::IndexerError; - -pub type IndexerResult = Result; - -#[derive(Debug)] -pub struct IndexedCheckpoint { - pub sequence_number: u64, - pub checkpoint_digest: CheckpointDigest, - pub epoch: u64, - pub tx_digests: Vec, - pub network_total_transactions: u64, - pub previous_checkpoint_digest: Option, - pub timestamp_ms: u64, - pub total_gas_cost: i64, // total gas cost could be negative - pub computation_cost: u64, - pub storage_cost: u64, - pub storage_rebate: u64, - pub non_refundable_storage_fee: u64, - pub checkpoint_commitments: Vec, - pub validator_signature: AggregateAuthoritySignature, - pub successful_tx_num: usize, - pub end_of_epoch_data: Option, - pub end_of_epoch: bool, -} - -impl IndexedCheckpoint { - pub fn from_sui_checkpoint( - checkpoint: &sui_types::messages_checkpoint::CertifiedCheckpointSummary, - contents: &sui_types::messages_checkpoint::CheckpointContents, - successful_tx_num: usize, - ) -> Self { - let total_gas_cost = checkpoint.epoch_rolling_gas_cost_summary.computation_cost as i64 - + checkpoint.epoch_rolling_gas_cost_summary.storage_cost as i64 - - checkpoint.epoch_rolling_gas_cost_summary.storage_rebate as i64; - let tx_digests = contents.iter().map(|t| t.transaction).collect::>(); - let auth_sig = &checkpoint.auth_sig().signature; - Self { - sequence_number: checkpoint.sequence_number, - checkpoint_digest: *checkpoint.digest(), - epoch: checkpoint.epoch, - tx_digests, - previous_checkpoint_digest: checkpoint.previous_digest, - end_of_epoch_data: checkpoint.end_of_epoch_data.clone(), - end_of_epoch: checkpoint.end_of_epoch_data.clone().is_some(), - total_gas_cost, - computation_cost: checkpoint.epoch_rolling_gas_cost_summary.computation_cost, - storage_cost: checkpoint.epoch_rolling_gas_cost_summary.storage_cost, - storage_rebate: checkpoint.epoch_rolling_gas_cost_summary.storage_rebate, - non_refundable_storage_fee: checkpoint - .epoch_rolling_gas_cost_summary - .non_refundable_storage_fee, - successful_tx_num, - network_total_transactions: checkpoint.network_total_transactions, - timestamp_ms: checkpoint.timestamp_ms, - validator_signature: auth_sig.clone(), - checkpoint_commitments: checkpoint.checkpoint_commitments.clone(), - } - } -} - -#[derive(Clone, Debug, Default)] -pub struct IndexedEpochInfo { - pub epoch: u64, - pub first_checkpoint_id: u64, - pub epoch_start_timestamp: u64, - pub reference_gas_price: u64, - pub protocol_version: u64, - pub total_stake: u64, - pub storage_fund_balance: u64, - pub system_state: Vec, - pub epoch_total_transactions: Option, - pub last_checkpoint_id: Option, - pub epoch_end_timestamp: Option, - pub storage_fund_reinvestment: Option, - pub storage_charge: Option, - pub storage_rebate: Option, - pub stake_subsidy_amount: Option, - pub total_gas_fees: Option, - pub total_stake_rewards_distributed: Option, - pub leftover_storage_fund_inflow: Option, - pub epoch_commitments: Option>, -} - -impl IndexedEpochInfo { - pub fn from_new_system_state_summary( - new_system_state_summary: SuiSystemStateSummary, - first_checkpoint_id: u64, - event: Option<&SystemEpochInfoEvent>, - ) -> IndexedEpochInfo { - Self { - epoch: new_system_state_summary.epoch, - first_checkpoint_id, - epoch_start_timestamp: new_system_state_summary.epoch_start_timestamp_ms, - reference_gas_price: new_system_state_summary.reference_gas_price, - protocol_version: new_system_state_summary.protocol_version, - // NOTE: total_stake and storage_fund_balance are about new epoch, - // although the event is generated at the end of the previous epoch, - // the event is optional b/c no such event for the first epoch. - total_stake: event.map(|e| e.total_stake).unwrap_or(0), - storage_fund_balance: event.map(|e| e.storage_fund_balance).unwrap_or(0), - system_state: bcs::to_bytes(&new_system_state_summary).unwrap(), - ..Default::default() - } - } - - pub fn from_end_of_epoch_data( - system_state_summary: &SuiSystemStateSummary, - last_checkpoint_summary: &CertifiedCheckpointSummary, - event: &SystemEpochInfoEvent, - network_total_tx_num_at_last_epoch_end: u64, - ) -> IndexedEpochInfo { - Self { - epoch: last_checkpoint_summary.epoch, - epoch_total_transactions: Some( - last_checkpoint_summary.network_total_transactions - - network_total_tx_num_at_last_epoch_end, - ), - last_checkpoint_id: Some(*last_checkpoint_summary.sequence_number()), - epoch_end_timestamp: Some(last_checkpoint_summary.timestamp_ms), - storage_fund_reinvestment: Some(event.storage_fund_reinvestment), - storage_charge: Some(event.storage_charge), - storage_rebate: Some(event.storage_rebate), - leftover_storage_fund_inflow: Some(event.leftover_storage_fund_inflow), - stake_subsidy_amount: Some(event.stake_subsidy_amount), - total_gas_fees: Some(event.total_gas_fees), - total_stake_rewards_distributed: Some(event.total_stake_rewards_distributed), - epoch_commitments: last_checkpoint_summary - .end_of_epoch_data - .as_ref() - .map(|e| e.epoch_commitments.clone()), - system_state: bcs::to_bytes(system_state_summary).unwrap(), - // The following felds will not and shall not be upserted - // into DB. We have them below to make compiler and diesel happy - first_checkpoint_id: 0, - epoch_start_timestamp: 0, - reference_gas_price: 0, - protocol_version: 0, - total_stake: 0, - storage_fund_balance: 0, - } - } -} - -#[derive(Debug, Clone)] -pub struct IndexedEvent { - pub tx_sequence_number: u64, - pub event_sequence_number: u64, - pub checkpoint_sequence_number: u64, - pub transaction_digest: TransactionDigest, - pub senders: Vec, - pub package: ObjectID, - pub module: String, - pub event_type: String, - pub bcs: Vec, - pub timestamp_ms: u64, -} - -impl IndexedEvent { - pub fn from_event( - tx_sequence_number: u64, - event_sequence_number: u64, - checkpoint_sequence_number: u64, - transaction_digest: TransactionDigest, - event: &sui_types::event::Event, - timestamp_ms: u64, - ) -> Self { - Self { - tx_sequence_number, - event_sequence_number, - checkpoint_sequence_number, - transaction_digest, - senders: vec![event.sender], - package: event.package_id, - module: event.transaction_module.to_string(), - event_type: event.type_.to_canonical_string(/* with_prefix */ true), - bcs: event.contents.clone(), - timestamp_ms, - } - } -} - -#[derive(Debug, Copy, Clone)] -pub enum OwnerType { - Immutable = 0, - Address = 1, - Object = 2, - Shared = 3, -} - -pub enum ObjectStatus { - Active = 0, - WrappedOrDeleted = 1, -} - -impl TryFrom for ObjectStatus { - type Error = IndexerError; - - fn try_from(value: i16) -> Result { - Ok(match value { - 0 => ObjectStatus::Active, - 1 => ObjectStatus::WrappedOrDeleted, - value => { - return Err(IndexerError::PersistentStorageDataCorruptionError(format!( - "{value} as ObjectStatus" - ))); - } - }) - } -} - -impl TryFrom for OwnerType { - type Error = IndexerError; - - fn try_from(value: i16) -> Result { - Ok(match value { - 0 => OwnerType::Immutable, - 1 => OwnerType::Address, - 2 => OwnerType::Object, - 3 => OwnerType::Shared, - value => { - return Err(IndexerError::PersistentStorageDataCorruptionError(format!( - "{value} as OwnerType" - ))); - } - }) - } -} - -// Returns owner_type, owner_address -pub fn owner_to_owner_info(owner: &Owner) -> (OwnerType, Option) { - match owner { - Owner::AddressOwner(address) => (OwnerType::Address, Some(*address)), - Owner::ObjectOwner(address) => (OwnerType::Object, Some(*address)), - Owner::Shared { .. } => (OwnerType::Shared, None), - Owner::Immutable => (OwnerType::Immutable, None), - } -} - -#[derive(Debug, Copy, Clone)] -pub enum DynamicFieldKind { - DynamicField = 0, - DynamicObject = 1, -} - -#[derive(Clone, Debug)] -pub struct IndexedObject { - pub object_id: ObjectID, - pub object_version: u64, - pub object_digest: ObjectDigest, - pub checkpoint_sequence_number: u64, - pub owner_type: OwnerType, - pub owner_id: Option, - pub object: Object, - pub coin_type: Option, - pub coin_balance: Option, - pub df_info: Option, -} - -impl IndexedObject { - pub fn from_object( - checkpoint_sequence_number: u64, - object: Object, - df_info: Option, - ) -> Self { - let (owner_type, owner_id) = owner_to_owner_info(&object.owner); - let coin_type = object - .coin_type_maybe() - .map(|t| t.to_canonical_string(/* with_prefix */ true)); - let coin_balance = if coin_type.is_some() { - Some(object.get_coin_value_unsafe()) - } else { - None - }; - - Self { - checkpoint_sequence_number, - object_id: object.id(), - object_version: object.version().value(), - object_digest: object.digest(), - owner_type, - owner_id, - object, - coin_type, - coin_balance, - df_info, - } - } -} - -#[derive(Clone, Debug)] -pub struct IndexedDeletedObject { - pub object_id: ObjectID, - pub object_version: u64, - pub checkpoint_sequence_number: u64, -} - -#[derive(Debug)] -pub struct IndexedPackage { - pub package_id: ObjectID, - pub move_package: MovePackage, - pub checkpoint_sequence_number: u64, -} - -#[derive(Debug, Clone)] -pub enum TransactionKind { - SystemTransaction = 0, - ProgrammableTransaction = 1, -} - -#[derive(Debug, Clone)] -pub struct IndexedTransaction { - pub tx_sequence_number: u64, - pub tx_digest: TransactionDigest, - pub sender_signed_data: SenderSignedData, - pub effects: TransactionEffects, - pub checkpoint_sequence_number: u64, - pub timestamp_ms: u64, - pub object_changes: Vec, - pub balance_change: Vec, - pub events: Vec, - pub transaction_kind: TransactionKind, - pub successful_tx_num: u64, -} - -#[derive(Debug, Clone)] -pub struct TxIndex { - pub tx_sequence_number: u64, - pub transaction_digest: TransactionDigest, - pub checkpoint_sequence_number: u64, - pub input_objects: Vec, - pub changed_objects: Vec, - pub payers: Vec, - pub senders: Vec, - pub recipients: Vec, - pub move_calls: Vec<(ObjectID, String, String)>, -} - -// ObjectChange is not bcs deserializable, IndexedObjectChange is. -#[serde_as] -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] -pub enum IndexedObjectChange { - Published { - package_id: ObjectID, - version: SequenceNumber, - digest: ObjectDigest, - modules: Vec, - }, - Transferred { - sender: SuiAddress, - recipient: Owner, - #[serde_as(as = "SuiStructTag")] - object_type: StructTag, - object_id: ObjectID, - version: SequenceNumber, - digest: ObjectDigest, - }, - /// Object mutated. - Mutated { - sender: SuiAddress, - owner: Owner, - #[serde_as(as = "SuiStructTag")] - object_type: StructTag, - object_id: ObjectID, - version: SequenceNumber, - previous_version: SequenceNumber, - digest: ObjectDigest, - }, - /// Delete object - Deleted { - sender: SuiAddress, - #[serde_as(as = "SuiStructTag")] - object_type: StructTag, - object_id: ObjectID, - version: SequenceNumber, - }, - /// Wrapped object - Wrapped { - sender: SuiAddress, - #[serde_as(as = "SuiStructTag")] - object_type: StructTag, - object_id: ObjectID, - version: SequenceNumber, - }, - /// New object creation - Created { - sender: SuiAddress, - owner: Owner, - #[serde_as(as = "SuiStructTag")] - object_type: StructTag, - object_id: ObjectID, - version: SequenceNumber, - digest: ObjectDigest, - }, -} - -impl From for IndexedObjectChange { - fn from(oc: ObjectChange) -> Self { - match oc { - ObjectChange::Published { - package_id, - version, - digest, - modules, - } => Self::Published { - package_id, - version, - digest, - modules, - }, - ObjectChange::Transferred { - sender, - recipient, - object_type, - object_id, - version, - digest, - } => Self::Transferred { - sender, - recipient, - object_type, - object_id, - version, - digest, - }, - ObjectChange::Mutated { - sender, - owner, - object_type, - object_id, - version, - previous_version, - digest, - } => Self::Mutated { - sender, - owner, - object_type, - object_id, - version, - previous_version, - digest, - }, - ObjectChange::Deleted { - sender, - object_type, - object_id, - version, - } => Self::Deleted { - sender, - object_type, - object_id, - version, - }, - ObjectChange::Wrapped { - sender, - object_type, - object_id, - version, - } => Self::Wrapped { - sender, - object_type, - object_id, - version, - }, - ObjectChange::Created { - sender, - owner, - object_type, - object_id, - version, - digest, - } => Self::Created { - sender, - owner, - object_type, - object_id, - version, - digest, - }, - } - } -} - -impl From for ObjectChange { - fn from(val: IndexedObjectChange) -> Self { - match val { - IndexedObjectChange::Published { - package_id, - version, - digest, - modules, - } => ObjectChange::Published { - package_id, - version, - digest, - modules, - }, - IndexedObjectChange::Transferred { - sender, - recipient, - object_type, - object_id, - version, - digest, - } => ObjectChange::Transferred { - sender, - recipient, - object_type, - object_id, - version, - digest, - }, - IndexedObjectChange::Mutated { - sender, - owner, - object_type, - object_id, - version, - previous_version, - digest, - } => ObjectChange::Mutated { - sender, - owner, - object_type, - object_id, - version, - previous_version, - digest, - }, - IndexedObjectChange::Deleted { - sender, - object_type, - object_id, - version, - } => ObjectChange::Deleted { - sender, - object_type, - object_id, - version, - }, - IndexedObjectChange::Wrapped { - sender, - object_type, - object_id, - version, - } => ObjectChange::Wrapped { - sender, - object_type, - object_id, - version, - }, - IndexedObjectChange::Created { - sender, - owner, - object_type, - object_id, - version, - digest, - } => ObjectChange::Created { - sender, - owner, - object_type, - object_id, - version, - digest, - }, - } - } -} - -// SuiTransactionBlockResponseWithOptions is only used on the reading path -pub struct SuiTransactionBlockResponseWithOptions { - pub response: SuiTransactionBlockResponse, - pub options: SuiTransactionBlockResponseOptions, -} - -impl From for SuiTransactionBlockResponse { - fn from(value: SuiTransactionBlockResponseWithOptions) -> Self { - let SuiTransactionBlockResponseWithOptions { response, options } = value; - - SuiTransactionBlockResponse { - digest: response.digest, - transaction: options.show_input.then_some(response.transaction).flatten(), - raw_transaction: options - .show_raw_input - .then_some(response.raw_transaction) - .unwrap_or_default(), - effects: options.show_effects.then_some(response.effects).flatten(), - events: options.show_events.then_some(response.events).flatten(), - object_changes: options - .show_object_changes - .then_some(response.object_changes) - .flatten(), - balance_changes: options - .show_balance_changes - .then_some(response.balance_changes) - .flatten(), - timestamp_ms: response.timestamp_ms, - confirmed_local_execution: response.confirmed_local_execution, - checkpoint: response.checkpoint, - errors: vec![], - raw_effects: options - .show_raw_effects - .then_some(response.raw_effects) - .unwrap_or_default(), - } - } -} diff --git a/crates/sui-json-rpc-api/Cargo.toml b/crates/sui-json-rpc-api/Cargo.toml deleted file mode 100644 index 0bdc9b2af1c..00000000000 --- a/crates/sui-json-rpc-api/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "sui-json-rpc-api" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -jsonrpsee.workspace = true -once_cell.workspace = true -prometheus.workspace = true -tap.workspace = true -tracing.workspace = true -fastcrypto.workspace = true -mysten-metrics.workspace = true -sui-json.workspace = true -sui-json-rpc-types.workspace = true -sui-open-rpc.workspace = true -sui-open-rpc-macros.workspace = true -sui-types.workspace = true - -# NOTE: It's important to keep the above dependency list short. -# This and the sui-sdk crate are widely used to develop on Sui and it's valuable -# to not have to pull in the entire sui repo for it. - -[dev-dependencies] diff --git a/crates/sui-json-rpc-api/src/coin.rs b/crates/sui-json-rpc-api/src/coin.rs deleted file mode 100644 index 72fbf565b7b..00000000000 --- a/crates/sui-json-rpc-api/src/coin.rs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -use sui_json_rpc_types::{Balance, CoinPage, SuiCoinMetadata}; -use sui_open_rpc_macros::open_rpc; -use sui_types::{ - balance::Supply, - base_types::{ObjectID, SuiAddress}, -}; - -#[open_rpc(namespace = "suix", tag = "Coin Query API")] -#[rpc(server, client, namespace = "suix")] -pub trait CoinReadApi { - /// Return all Coin<`coin_type`> objects owned by an address. - #[rustfmt::skip] - #[method(name = "getCoins")] - async fn get_coins( - &self, - /// the owner's Sui address - owner: SuiAddress, - /// optional type name for the coin (e.g., 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC), default to 0x2::sui::SUI if not specified. - coin_type: Option, - /// optional paging cursor - cursor: Option, - /// maximum number of items per page - limit: Option, - ) -> RpcResult; - - /// Return all Coin objects owned by an address. - #[rustfmt::skip] - #[method(name = "getAllCoins")] - async fn get_all_coins( - &self, - /// the owner's Sui address - owner: SuiAddress, - /// optional paging cursor - cursor: Option, - /// maximum number of items per page - limit: Option, - ) -> RpcResult; - - /// Return the total coin balance for one coin type, owned by the address owner. - #[rustfmt::skip] - #[method(name = "getBalance")] - async fn get_balance( - &self, - /// the owner's Sui address - owner: SuiAddress, - /// optional type names for the coin (e.g., 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC), default to 0x2::sui::SUI if not specified. - coin_type: Option, - ) -> RpcResult; - - /// Return the total coin balance for all coin type, owned by the address owner. - #[rustfmt::skip] - #[method(name = "getAllBalances")] - async fn get_all_balances( - &self, - /// the owner's Sui address - owner: SuiAddress, - ) -> RpcResult>; - - /// Return metadata(e.g., symbol, decimals) for a coin - #[rustfmt::skip] - #[method(name = "getCoinMetadata")] - async fn get_coin_metadata( - &self, - /// type name for the coin (e.g., 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC) - coin_type: String, - ) -> RpcResult>; - - /// Return total supply for a coin - #[rustfmt::skip] - #[method(name = "getTotalSupply")] - async fn get_total_supply( - &self, - /// type name for the coin (e.g., 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC) - coin_type: String, - ) -> RpcResult; -} diff --git a/crates/sui-json-rpc-api/src/governance.rs b/crates/sui-json-rpc-api/src/governance.rs deleted file mode 100644 index db75ef6e59d..00000000000 --- a/crates/sui-json-rpc-api/src/governance.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -use sui_json_rpc_types::{DelegatedStake, DelegatedTimelockedStake, SuiCommittee, ValidatorApys}; -use sui_open_rpc_macros::open_rpc; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, - sui_serde::BigInt, - sui_system_state::sui_system_state_summary::SuiSystemStateSummary, -}; - -#[open_rpc(namespace = "suix", tag = "Governance Read API")] -#[rpc(server, client, namespace = "suix")] -pub trait GovernanceReadApi { - /// Return one or more [DelegatedStake]. If a Stake was withdrawn its status - /// will be Unstaked. - #[method(name = "getStakesByIds")] - async fn get_stakes_by_ids( - &self, - staked_sui_ids: Vec, - ) -> RpcResult>; - - /// Return all [DelegatedStake]. - #[method(name = "getStakes")] - async fn get_stakes(&self, owner: SuiAddress) -> RpcResult>; - - /// Return one or more [DelegatedTimelockedStake]. If a Stake was withdrawn - /// its status will be Unstaked. - #[method(name = "getTimelockedStakesByIds")] - async fn get_timelocked_stakes_by_ids( - &self, - timelocked_staked_sui_ids: Vec, - ) -> RpcResult>; - - /// Return all [DelegatedTimelockedStake]. - #[method(name = "getTimelockedStakes")] - async fn get_timelocked_stakes( - &self, - owner: SuiAddress, - ) -> RpcResult>; - - /// Return the committee information for the asked `epoch`. - #[method(name = "getCommitteeInfo")] - async fn get_committee_info( - &self, - /// The epoch of interest. If None, default to the latest epoch - epoch: Option>, - ) -> RpcResult; - - /// Return the latest SUI system state object on-chain. - #[method(name = "getLatestSuiSystemState")] - async fn get_latest_sui_system_state(&self) -> RpcResult; - - /// Return the reference gas price for the network - #[method(name = "getReferenceGasPrice")] - async fn get_reference_gas_price(&self) -> RpcResult>; - - /// Return the validator APY - #[method(name = "getValidatorsApy")] - async fn get_validators_apy(&self) -> RpcResult; -} diff --git a/crates/sui-json-rpc-api/src/indexer.rs b/crates/sui-json-rpc-api/src/indexer.rs deleted file mode 100644 index d3301225c28..00000000000 --- a/crates/sui-json-rpc-api/src/indexer.rs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -use sui_json_rpc_types::{ - DynamicFieldPage, EventFilter, EventPage, ObjectsPage, Page, SuiEvent, SuiObjectResponse, - SuiObjectResponseQuery, SuiTransactionBlockEffects, SuiTransactionBlockResponseQuery, - TransactionBlocksPage, TransactionFilter, -}; -use sui_open_rpc_macros::open_rpc; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, - digests::TransactionDigest, - dynamic_field::DynamicFieldName, - event::EventID, -}; - -#[open_rpc(namespace = "suix", tag = "Extended API")] -#[rpc(server, client, namespace = "suix")] -pub trait IndexerApi { - /// Return the list of objects owned by an address. - /// Note that if the address owns more than `QUERY_MAX_RESULT_LIMIT` objects, - /// the pagination is not accurate, because previous page may have been updated when - /// the next page is fetched. - /// Please use suix_queryObjects if this is a concern. - #[rustfmt::skip] - #[method(name = "getOwnedObjects")] - async fn get_owned_objects( - &self, - /// the owner's Sui address - address: SuiAddress, - /// the objects query criteria. - query: Option, - /// An optional paging cursor. If provided, the query will start from the next item after the specified cursor. Default to start from the first item if not specified. - cursor: Option, - /// Max number of items returned per page, default to [QUERY_MAX_RESULT_LIMIT] if not specified. - limit: Option, - ) -> RpcResult; - - /// Return list of transactions for a specified query criteria. - #[rustfmt::skip] - #[method(name = "queryTransactionBlocks")] - async fn query_transaction_blocks( - &self, - /// the transaction query criteria. - query: SuiTransactionBlockResponseQuery, - /// An optional paging cursor. If provided, the query will start from the next item after the specified cursor. Default to start from the first item if not specified. - cursor: Option, - /// Maximum item returned per page, default to QUERY_MAX_RESULT_LIMIT if not specified. - limit: Option, - /// query result ordering, default to false (ascending order), oldest record first. - descending_order: Option, - ) -> RpcResult; - - /// Return list of events for a specified query criteria. - #[rustfmt::skip] - #[method(name = "queryEvents")] - async fn query_events( - &self, - /// The event query criteria. See [Event filter](https://docs.sui.io/build/event_api#event-filters) documentation for examples. - query: EventFilter, - /// optional paging cursor - cursor: Option, - /// maximum number of items per page, default to [QUERY_MAX_RESULT_LIMIT] if not specified. - limit: Option, - /// query result ordering, default to false (ascending order), oldest record first. - descending_order: Option, - ) -> RpcResult; - - /// Subscribe to a stream of Sui event - #[rustfmt::skip] - #[subscription(name = "subscribeEvent", item = SuiEvent)] - fn subscribe_event( - &self, - /// The filter criteria of the event stream. See [Event filter](https://docs.sui.io/build/event_api#event-filters) documentation for examples. - filter: EventFilter, - ); - - /// Subscribe to a stream of Sui transaction effects - #[subscription(name = "subscribeTransaction", item = SuiTransactionBlockEffects)] - fn subscribe_transaction(&self, filter: TransactionFilter); - - /// Return the list of dynamic field objects owned by an object. - #[rustfmt::skip] - #[method(name = "getDynamicFields")] - async fn get_dynamic_fields( - &self, - /// The ID of the parent object - parent_object_id: ObjectID, - /// An optional paging cursor. If provided, the query will start from the next item after the specified cursor. Default to start from the first item if not specified. - cursor: Option, - /// Maximum item returned per page, default to [QUERY_MAX_RESULT_LIMIT] if not specified. - limit: Option, - ) -> RpcResult; - - /// Return the dynamic field object information for a specified object - #[rustfmt::skip] - #[method(name = "getDynamicFieldObject")] - async fn get_dynamic_field_object( - &self, - /// The ID of the queried parent object - parent_object_id: ObjectID, - /// The Name of the dynamic field - name: DynamicFieldName, - ) -> RpcResult; - - /// Return the resolved address given resolver and name - #[rustfmt::skip] - #[method(name = "resolveNameServiceAddress")] - async fn resolve_name_service_address( - &self, - /// The name to resolve - name: String, - ) -> RpcResult>; - - /// Return the resolved names given address, - /// if multiple names are resolved, the first one is the primary name. - #[rustfmt::skip] - #[method(name = "resolveNameServiceNames")] - async fn resolve_name_service_names( - &self, - /// The address to resolve - address: SuiAddress, - cursor: Option, - limit: Option, - ) -> RpcResult>; -} diff --git a/crates/sui-json-rpc-api/src/lib.rs b/crates/sui-json-rpc-api/src/lib.rs deleted file mode 100644 index 7fc4cc294c0..00000000000 --- a/crates/sui-json-rpc-api/src/lib.rs +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use anyhow::anyhow; -pub use coin::{CoinReadApiClient, CoinReadApiOpenRpc, CoinReadApiServer}; -pub use extended::{ExtendedApiClient, ExtendedApiOpenRpc, ExtendedApiServer}; -pub use governance::{GovernanceReadApiClient, GovernanceReadApiOpenRpc, GovernanceReadApiServer}; -pub use indexer::{IndexerApiClient, IndexerApiOpenRpc, IndexerApiServer}; -pub use move_utils::{MoveUtilsClient, MoveUtilsOpenRpc, MoveUtilsServer}; -use mysten_metrics::histogram::Histogram; -use once_cell::sync::Lazy; -use prometheus::{register_int_counter_with_registry, IntCounter}; -pub use read::{ReadApiClient, ReadApiOpenRpc, ReadApiServer}; -use tap::TapFallible; -use tracing::warn; -pub use transaction_builder::{ - TransactionBuilderClient, TransactionBuilderOpenRpc, TransactionBuilderServer, -}; -pub use write::{WriteApiClient, WriteApiOpenRpc, WriteApiServer}; - -mod coin; -mod extended; -mod governance; -mod indexer; -mod move_utils; -mod read; -mod transaction_builder; -mod write; - -const RPC_QUERY_MAX_RESULT_LIMIT: &str = "RPC_QUERY_MAX_RESULT_LIMIT"; -const DEFAULT_RPC_QUERY_MAX_RESULT_LIMIT: usize = 50; - -pub static QUERY_MAX_RESULT_LIMIT: Lazy = Lazy::new(|| { - read_size_from_env(RPC_QUERY_MAX_RESULT_LIMIT).unwrap_or(DEFAULT_RPC_QUERY_MAX_RESULT_LIMIT) -}); - -// TODOD(chris): make this configurable -pub const QUERY_MAX_RESULT_LIMIT_CHECKPOINTS: usize = 100; - -pub fn cap_page_limit(limit: Option) -> usize { - let limit = limit.unwrap_or_default(); - if limit > *QUERY_MAX_RESULT_LIMIT || limit == 0 { - *QUERY_MAX_RESULT_LIMIT - } else { - limit - } -} - -pub fn validate_limit(limit: Option, max: usize) -> Result { - match limit { - Some(l) if l > max => Err(anyhow!("Page size limit {l} exceeds max limit {max}")), - Some(0) => Err(anyhow!("Page size limit cannot be smaller than 1")), - Some(l) => Ok(l), - None => Ok(max), - } -} - -#[derive(Clone)] -pub struct JsonRpcMetrics { - pub get_objects_limit: Histogram, - pub get_objects_result_size: Histogram, - pub get_objects_result_size_total: IntCounter, - pub get_tx_blocks_limit: Histogram, - pub get_tx_blocks_result_size: Histogram, - pub get_tx_blocks_result_size_total: IntCounter, - pub get_checkpoints_limit: Histogram, - pub get_checkpoints_result_size: Histogram, - pub get_checkpoints_result_size_total: IntCounter, - pub get_owned_objects_limit: Histogram, - pub get_owned_objects_result_size: Histogram, - pub get_owned_objects_result_size_total: IntCounter, - pub get_coins_limit: Histogram, - pub get_coins_result_size: Histogram, - pub get_coins_result_size_total: IntCounter, - pub get_dynamic_fields_limit: Histogram, - pub get_dynamic_fields_result_size: Histogram, - pub get_dynamic_fields_result_size_total: IntCounter, - pub query_tx_blocks_limit: Histogram, - pub query_tx_blocks_result_size: Histogram, - pub query_tx_blocks_result_size_total: IntCounter, - pub query_events_limit: Histogram, - pub query_events_result_size: Histogram, - pub query_events_result_size_total: IntCounter, - - pub get_stake_sui_result_size: Histogram, - pub get_stake_sui_result_size_total: IntCounter, - - pub get_stake_sui_latency: Histogram, - pub get_delegated_sui_latency: Histogram, - - pub orchestrator_latency_ms: Histogram, - pub post_orchestrator_latency_ms: Histogram, -} - -impl JsonRpcMetrics { - pub fn new(registry: &prometheus::Registry) -> Self { - Self { - get_objects_limit: Histogram::new_in_registry( - "json_rpc_get_objects_limit", - "The input limit for multi_get_objects, after applying the cap", - registry, - ), - get_objects_result_size: Histogram::new_in_registry( - "json_rpc_get_objects_result_size", - "The return size for multi_get_objects", - registry, - ), - get_objects_result_size_total: register_int_counter_with_registry!( - "json_rpc_get_objects_result_size_total", - "The total return size for multi_get_objects", - registry - ) - .unwrap(), - get_tx_blocks_limit: Histogram::new_in_registry( - "json_rpc_get_tx_blocks_limit", - "The input limit for get_tx_blocks, after applying the cap", - registry, - ), - get_tx_blocks_result_size: Histogram::new_in_registry( - "json_rpc_get_tx_blocks_result_size", - "The return size for get_tx_blocks", - registry, - ), - get_tx_blocks_result_size_total: register_int_counter_with_registry!( - "json_rpc_get_tx_blocks_result_size_total", - "The total return size for get_tx_blocks", - registry - ) - .unwrap(), - get_checkpoints_limit: Histogram::new_in_registry( - "json_rpc_get_checkpoints_limit", - "The input limit for get_checkpoints, after applying the cap", - registry, - ), - get_checkpoints_result_size: Histogram::new_in_registry( - "json_rpc_get_checkpoints_result_size", - "The return size for get_checkpoints", - registry, - ), - get_checkpoints_result_size_total: register_int_counter_with_registry!( - "json_rpc_get_checkpoints_result_size_total", - "The total return size for get_checkpoints", - registry - ) - .unwrap(), - get_owned_objects_limit: Histogram::new_in_registry( - "json_rpc_get_owned_objects_limit", - "The input limit for get_owned_objects, after applying the cap", - registry, - ), - get_owned_objects_result_size: Histogram::new_in_registry( - "json_rpc_get_owned_objects_result_size", - "The return size for get_owned_objects", - registry, - ), - get_owned_objects_result_size_total: register_int_counter_with_registry!( - "json_rpc_get_owned_objects_result_size_total", - "The total return size for get_owned_objects", - registry - ) - .unwrap(), - get_coins_limit: Histogram::new_in_registry( - "json_rpc_get_coins_limit", - "The input limit for get_coins, after applying the cap", - registry, - ), - get_coins_result_size: Histogram::new_in_registry( - "json_rpc_get_coins_result_size", - "The return size for get_coins", - registry, - ), - get_coins_result_size_total: register_int_counter_with_registry!( - "json_rpc_get_coins_result_size_total", - "The total return size for get_coins", - registry - ) - .unwrap(), - get_dynamic_fields_limit: Histogram::new_in_registry( - "json_rpc_get_dynamic_fields_limit", - "The input limit for get_dynamic_fields, after applying the cap", - registry, - ), - get_dynamic_fields_result_size: Histogram::new_in_registry( - "json_rpc_get_dynamic_fields_result_size", - "The return size for get_dynamic_fields", - registry, - ), - get_dynamic_fields_result_size_total: register_int_counter_with_registry!( - "json_rpc_get_dynamic_fields_result_size_total", - "The total return size for get_dynamic_fields", - registry - ) - .unwrap(), - query_tx_blocks_limit: Histogram::new_in_registry( - "json_rpc_query_tx_blocks_limit", - "The input limit for query_tx_blocks, after applying the cap", - registry, - ), - query_tx_blocks_result_size: Histogram::new_in_registry( - "json_rpc_query_tx_blocks_result_size", - "The return size for query_tx_blocks", - registry, - ), - query_tx_blocks_result_size_total: register_int_counter_with_registry!( - "json_rpc_query_tx_blocks_result_size_total", - "The total return size for query_tx_blocks", - registry - ) - .unwrap(), - query_events_limit: Histogram::new_in_registry( - "json_rpc_query_events_limit", - "The input limit for query_events, after applying the cap", - registry, - ), - query_events_result_size: Histogram::new_in_registry( - "json_rpc_query_events_result_size", - "The return size for query_events", - registry, - ), - query_events_result_size_total: register_int_counter_with_registry!( - "json_rpc_query_events_result_size_total", - "The total return size for query_events", - registry - ) - .unwrap(), - get_stake_sui_result_size: Histogram::new_in_registry( - "json_rpc_get_stake_sui_result_size", - "The return size for get_stake_sui", - registry, - ), - get_stake_sui_result_size_total: register_int_counter_with_registry!( - "json_rpc_get_stake_sui_result_size_total", - "The total return size for get_stake_sui", - registry - ) - .unwrap(), - get_stake_sui_latency: Histogram::new_in_registry( - "get_stake_sui_latency", - "The latency of get stake sui, in ms", - registry, - ), - get_delegated_sui_latency: Histogram::new_in_registry( - "get_delegated_sui_latency", - "The latency of get delegated sui, in ms", - registry, - ), - orchestrator_latency_ms: Histogram::new_in_registry( - "json_rpc_orchestrator_latency", - "The latency of submitting transaction via transaction orchestrator, in ms", - registry, - ), - post_orchestrator_latency_ms: Histogram::new_in_registry( - "json_rpc_post_orchestrator_latency", - "The latency of response processing after transaction orchestrator, in ms", - registry, - ), - } - } - - pub fn new_for_tests() -> Self { - let registry = prometheus::Registry::new(); - Self::new(®istry) - } -} - -pub fn read_size_from_env(var_name: &str) -> Option { - std::env::var(var_name) - .ok()? - .parse::() - .tap_err(|e| { - warn!( - "Env var {} does not contain valid usize integer: {}", - var_name, e - ) - }) - .ok() -} - -pub const CLIENT_SDK_TYPE_HEADER: &str = "client-sdk-type"; -/// The version number of the SDK itself. This can be different from the API -/// version. -pub const CLIENT_SDK_VERSION_HEADER: &str = "client-sdk-version"; -/// The RPC API version that the client is targeting. Different SDK versions may -/// target the same API version. -pub const CLIENT_TARGET_API_VERSION_HEADER: &str = "client-target-api-version"; - -pub const TRANSIENT_ERROR_CODE: i32 = -32050; -pub const TRANSACTION_EXECUTION_CLIENT_ERROR_CODE: i32 = -32002; diff --git a/crates/sui-json-rpc-api/src/move_utils.rs b/crates/sui-json-rpc-api/src/move_utils.rs deleted file mode 100644 index b0a79355b69..00000000000 --- a/crates/sui-json-rpc-api/src/move_utils.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -use sui_json_rpc_types::{ - MoveFunctionArgType, SuiMoveNormalizedFunction, SuiMoveNormalizedModule, - SuiMoveNormalizedStruct, -}; -use sui_open_rpc_macros::open_rpc; -use sui_types::base_types::ObjectID; - -#[open_rpc(namespace = "sui", tag = "Move Utils")] -#[rpc(server, client, namespace = "sui")] -pub trait MoveUtils { - /// Return the argument types of a Move function, - /// based on normalized Type. - #[method(name = "getMoveFunctionArgTypes")] - async fn get_move_function_arg_types( - &self, - package: ObjectID, - module: String, - function: String, - ) -> RpcResult>; - - /// Return structured representations of all modules in the given package - #[method(name = "getNormalizedMoveModulesByPackage")] - async fn get_normalized_move_modules_by_package( - &self, - package: ObjectID, - ) -> RpcResult>; - - /// Return a structured representation of Move module - #[method(name = "getNormalizedMoveModule")] - async fn get_normalized_move_module( - &self, - package: ObjectID, - module_name: String, - ) -> RpcResult; - - /// Return a structured representation of Move struct - #[method(name = "getNormalizedMoveStruct")] - async fn get_normalized_move_struct( - &self, - package: ObjectID, - module_name: String, - struct_name: String, - ) -> RpcResult; - - /// Return a structured representation of Move function - #[method(name = "getNormalizedMoveFunction")] - async fn get_normalized_move_function( - &self, - package: ObjectID, - module_name: String, - function_name: String, - ) -> RpcResult; -} diff --git a/crates/sui-json-rpc-api/src/transaction_builder.rs b/crates/sui-json-rpc-api/src/transaction_builder.rs deleted file mode 100644 index 7b0da4a36bf..00000000000 --- a/crates/sui-json-rpc-api/src/transaction_builder.rs +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use fastcrypto::encoding::Base64; -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -use sui_json::SuiJsonValue; -use sui_json_rpc_types::{ - RPCTransactionRequestParams, SuiTransactionBlockBuilderMode, SuiTypeTag, TransactionBlockBytes, -}; -use sui_open_rpc_macros::open_rpc; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, - sui_serde::BigInt, -}; - -#[open_rpc(namespace = "unsafe", tag = "Transaction Builder API")] -#[rpc(server, client, namespace = "unsafe")] -pub trait TransactionBuilder { - /// Create an unsigned transaction to transfer an object from one address to another. The object's type - /// must allow public transfers - #[rustfmt::skip] - #[method(name = "transferObject")] - async fn transfer_object( - &self, - /// the transaction signer's Sui address - signer: SuiAddress, - /// the ID of the object to be transferred - object_id: ObjectID, - /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided - gas: Option, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - /// the recipient's Sui address - recipient: SuiAddress, - ) -> RpcResult; - - /// Create an unsigned transaction to send SUI coin object to a Sui address. The SUI object is also used as the gas object. - #[rustfmt::skip] - #[method(name = "transferSui")] - async fn transfer_sui( - &self, - /// the transaction signer's Sui address - signer: SuiAddress, - /// the Sui coin object to be used in this transaction - sui_object_id: ObjectID, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - /// the recipient's Sui address - recipient: SuiAddress, - /// the amount to be split out and transferred - amount: Option>, - ) -> RpcResult; - - /// Send `Coin` to a list of addresses, where `T` can be any coin type, following a list of amounts, - /// The object specified in the `gas` field will be used to pay the gas fee for the transaction. - /// The gas object can not appear in `input_coins`. If the gas object is not specified, the RPC server - /// will auto-select one. - #[rustfmt::skip] - #[method(name = "pay")] - async fn pay( - &self, - /// the transaction signer's Sui address - signer: SuiAddress, - /// the Sui coins to be used in this transaction - input_coins: Vec, - /// the recipients' addresses, the length of this vector must be the same as amounts. - recipients: Vec, - /// the amounts to be transferred to recipients, following the same order - amounts: Vec>, - /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided - gas: Option, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - ) -> RpcResult; - - /// Send SUI coins to a list of addresses, following a list of amounts. - /// This is for SUI coin only and does not require a separate gas coin object. - /// Specifically, what pay_sui does are: - /// 1. debit each input_coin to create new coin following the order of - /// amounts and assign it to the corresponding recipient. - /// 2. accumulate all residual SUI from input coins left and deposit all SUI to the first - /// input coin, then use the first input coin as the gas coin object. - /// 3. the balance of the first input coin after tx is sum(input_coins) - sum(amounts) - actual_gas_cost - /// 4. all other input coints other than the first one are deleted. - #[rustfmt::skip] - #[method(name = "paySui")] - async fn pay_sui( - &self, - /// the transaction signer's Sui address - signer: SuiAddress, - /// the Sui coins to be used in this transaction, including the coin for gas payment. - input_coins: Vec, - /// the recipients' addresses, the length of this vector must be the same as amounts. - recipients: Vec, - /// the amounts to be transferred to recipients, following the same order - amounts: Vec>, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - ) -> RpcResult; - - /// Send all SUI coins to one recipient. - /// This is for SUI coin only and does not require a separate gas coin object. - /// Specifically, what pay_all_sui does are: - /// 1. accumulate all SUI from input coins and deposit all SUI to the first input coin - /// 2. transfer the updated first coin to the recipient and also use this first coin as gas coin object. - /// 3. the balance of the first input coin after tx is sum(input_coins) - actual_gas_cost. - /// 4. all other input coins other than the first are deleted. - #[rustfmt::skip] - #[method(name = "payAllSui")] - async fn pay_all_sui( - &self, - /// the transaction signer's Sui address - signer: SuiAddress, - /// the Sui coins to be used in this transaction, including the coin for gas payment. - input_coins: Vec, - /// the recipient address, - recipient: SuiAddress, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - ) -> RpcResult; - - /// Create an unsigned transaction to execute a Move call on the network, by calling the specified function in the module of a given package. - #[rustfmt::skip] - #[method(name = "moveCall")] - async fn move_call( - &self, - /// the transaction signer's Sui address - signer: SuiAddress, - /// the Move package ID, e.g. `0x2` - package_object_id: ObjectID, - /// the Move module name, e.g. `pay` - module: String, - /// the move function name, e.g. `split` - function: String, - /// the type arguments of the Move function - type_arguments: Vec, - /// the arguments to be passed into the Move function, in [SuiJson](https://docs.sui.io/build/sui-json) format - arguments: Vec, - /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided - gas: Option, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - /// Whether this is a Normal transaction or a Dev Inspect Transaction. Default to be `SuiTransactionBlockBuilderMode::Commit` when it's None. - execution_mode: Option, - ) -> RpcResult; - - /// Create an unsigned transaction to publish a Move package. - #[rustfmt::skip] - #[method(name = "publish")] - async fn publish( - &self, - /// the transaction signer's Sui address - sender: SuiAddress, - /// the compiled bytes of a Move package - compiled_modules: Vec, - /// a list of transitive dependency addresses that this set of modules depends on. - dependencies: Vec, - /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided - gas: Option, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - ) -> RpcResult; - - /// Create an unsigned transaction to split a coin object into multiple - /// coins. - #[rustfmt::skip] - #[method(name = "splitCoin")] - async fn split_coin( - &self, - /// the transaction signer's Sui address - signer: SuiAddress, - /// the coin object to be spilt - coin_object_id: ObjectID, - /// the amounts to split out from the coin - split_amounts: Vec>, - /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided - gas: Option, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - ) -> RpcResult; - - /// Create an unsigned transaction to split a coin object into multiple equal-size coins. - #[rustfmt::skip] - #[method(name = "splitCoinEqual")] - async fn split_coin_equal( - &self, - /// the transaction signer's Sui address - signer: SuiAddress, - /// the coin object to be spilt - coin_object_id: ObjectID, - /// the number of coins to split into - split_count: BigInt, - /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided - gas: Option, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - ) -> RpcResult; - - /// Create an unsigned transaction to merge multiple coins into one coin. - #[rustfmt::skip] - #[method(name = "mergeCoins")] - async fn merge_coin( - &self, - /// the transaction signer's Sui address - signer: SuiAddress, - /// the coin object to merge into, this coin will remain after the transaction - primary_coin: ObjectID, - /// the coin object to be merged, this coin will be destroyed, the balance will be added to `primary_coin` - coin_to_merge: ObjectID, - /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided - gas: Option, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - ) -> RpcResult; - - /// Create an unsigned batched transaction. - #[rustfmt::skip] - #[method(name = "batchTransaction")] - async fn batch_transaction( - &self, - /// the transaction signer's Sui address - signer: SuiAddress, - /// list of transaction request parameters - single_transaction_params: Vec, - /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided - gas: Option, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - /// Whether this is a regular transaction or a Dev Inspect Transaction - txn_builder_mode: Option, - ) -> RpcResult; - - /// Add stake to a validator's staking pool using multiple coins and amount. - #[rustfmt::skip] - #[method(name = "requestAddStake")] - async fn request_add_stake( - &self, - /// the transaction signer's Sui address - signer: SuiAddress, - /// Coin object to stake - coins: Vec, - /// stake amount - amount: Option>, - /// the validator's Sui address - validator: SuiAddress, - /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided - gas: Option, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - ) -> RpcResult; - - /// Withdraw stake from a validator's staking pool. - #[rustfmt::skip] - #[method(name = "requestWithdrawStake")] - async fn request_withdraw_stake( - &self, - /// the transaction signer's Sui address - signer: SuiAddress, - /// StakedSui object ID - staked_sui: ObjectID, - /// gas object to be used in this transaction, node will pick one from the signer's possession if not provided - gas: Option, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - ) -> RpcResult; - - /// Add timelocked stake to a validator's staking pool using multiple balances and amount. - #[rustfmt::skip] - #[method(name = "requestAddTimelockedStake")] - async fn request_add_timelocked_stake( - &self, - /// the transaction signer's Sui address - signer: SuiAddress, - /// TimeLock> object to stake - locked_balance: ObjectID, - /// the validator's Sui address - validator: SuiAddress, - /// gas object to be used in this transaction - gas: ObjectID, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - ) -> RpcResult; - - /// Withdraw timelocked stake from a validator's staking pool. - #[rustfmt::skip] - #[method(name = "requestWithdrawTimelockedStake")] - async fn request_withdraw_timelocked_stake( - &self, - /// the transaction signer's Sui address - signer: SuiAddress, - /// TimelockedStakedSui object ID - timelocked_staked_sui: ObjectID, - /// gas object to be used in this transaction - gas: ObjectID, - /// the gas budget, the transaction will fail if the gas cost exceed the budget - gas_budget: BigInt, - ) -> RpcResult; -} diff --git a/crates/sui-json-rpc-tests/Cargo.toml b/crates/sui-json-rpc-tests/Cargo.toml deleted file mode 100644 index 22a68345de8..00000000000 --- a/crates/sui-json-rpc-tests/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -[package] -name = "sui-json-rpc-tests" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] - -[dev-dependencies] -move-package.workspace = true -sui-config.workspace = true -sui-core.workspace = true -sui-keys.workspace = true -sui-move-build.workspace = true -sui-test-transaction-builder.workspace = true -sui-sdk.workspace = true -sui-macros.workspace = true -sui-simulator.workspace = true -sui-json.workspace = true -sui-json-rpc.workspace = true -sui-json-rpc-api.workspace = true -sui-json-rpc-types.workspace = true -sui-open-rpc.workspace = true -sui-open-rpc-macros.workspace = true -sui-protocol-config.workspace = true -sui-swarm-config.workspace = true -sui-types.workspace = true -test-cluster.workspace = true -telemetry-subscribers.workspace = true - -anyhow.workspace = true -async-trait.workspace = true -bcs.workspace = true -hyper.workspace = true -jsonrpsee.workspace = true -prometheus.workspace = true -rand.workspace = true -reqwest.workspace = true -tokio = { workspace = true, features = ["full"] } -tracing.workspace = true - diff --git a/crates/sui-json-rpc-tests/tests/data/dummy_modules_publish/Move.toml b/crates/sui-json-rpc-tests/tests/data/dummy_modules_publish/Move.toml deleted file mode 100644 index 1a80243f9c9..00000000000 --- a/crates/sui-json-rpc-tests/tests/data/dummy_modules_publish/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "Examples" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../sui-framework/packages/sui-framework" } - -[addresses] -examples = "0x0" diff --git a/crates/sui-json-rpc-tests/tests/data/dummy_modules_publish/sources/trusted_coin.move b/crates/sui-json-rpc-tests/tests/data/dummy_modules_publish/sources/trusted_coin.move deleted file mode 100644 index 5152db8cd4f..00000000000 --- a/crates/sui-json-rpc-tests/tests/data/dummy_modules_publish/sources/trusted_coin.move +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Example coin with a trusted owner responsible for minting/burning (e.g., a stablecoin) -module examples::trusted_coin { - use std::option; - use sui::coin::{Self, TreasuryCap}; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; - - /// Name of the coin - struct TRUSTED_COIN has drop {} - - /// Register the trusted currency to acquire its `TreasuryCap`. Because - /// this is a module initializer, it ensures the currency only gets - /// registered once. - fun init(witness: TRUSTED_COIN, ctx: &mut TxContext) { - // Get a treasury cap for the coin and give it to the transaction - // sender - let (treasury_cap, metadata) = coin::create_currency(witness, 2, b"TRUSTED", b"Trusted Coin", b"Trusted Coin for test", option::none(), ctx); - transfer::public_freeze_object(metadata); - transfer::public_transfer(treasury_cap, tx_context::sender(ctx)) - } - - public entry fun mint(treasury_cap: &mut TreasuryCap, amount: u64, ctx: &mut TxContext) { - let coin = coin::mint(treasury_cap, amount, ctx); - transfer::public_transfer(coin, tx_context::sender(ctx)); - } - - public entry fun transfer(treasury_cap: TreasuryCap, recipient: address) { - transfer::public_transfer(treasury_cap, recipient); - } - - #[test_only] - /// Wrapper of module initializer for testing - public fun test_init(ctx: &mut TxContext) { - init(TRUSTED_COIN {}, ctx) - } -} diff --git a/crates/sui-json-rpc-tests/tests/name_service_tests.rs b/crates/sui-json-rpc-tests/tests/name_service_tests.rs deleted file mode 100644 index 3f78667fbf8..00000000000 --- a/crates/sui-json-rpc-tests/tests/name_service_tests.rs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::str::FromStr; - -use sui_json_rpc::name_service::{self, Domain}; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, - collection_types::VecMap, -}; - -#[test] -fn test_parent_extraction() { - let mut name = Domain::from_str("leaf.node.test.sui").unwrap(); - - assert_eq!(name.parent().to_string(), "node.test.sui"); - - name = Domain::from_str("node.test.sui").unwrap(); - - assert_eq!(name.parent().to_string(), "test.sui"); -} - -#[test] -fn test_expirations() { - let system_time: u64 = 100; - - let mut name = name_service::NameRecord { - nft_id: sui_types::id::ID::new(ObjectID::random()), - data: VecMap { contents: vec![] }, - target_address: Some(SuiAddress::random_for_testing_only()), - expiration_timestamp_ms: system_time + 10, - }; - - assert!(!name.is_node_expired(system_time)); - - name.expiration_timestamp_ms = system_time - 10; - - assert!(name.is_node_expired(system_time)); -} - -#[test] -fn test_name_service_outputs() { - assert_eq!("@test".parse::().unwrap().to_string(), "test.sui"); - assert_eq!( - "test.sui".parse::().unwrap().to_string(), - "test.sui" - ); - assert_eq!( - "test@sld".parse::().unwrap().to_string(), - "test.sld.sui" - ); - assert_eq!( - "test.test@example".parse::().unwrap().to_string(), - "test.test.example.sui" - ); - assert_eq!( - "sui@sui".parse::().unwrap().to_string(), - "sui.sui.sui" - ); - - assert_eq!("@sui".parse::().unwrap().to_string(), "sui.sui"); - - assert_eq!( - "test*test@test".parse::().unwrap().to_string(), - "test.test.test.sui" - ); - assert_eq!( - "test.test.sui".parse::().unwrap().to_string(), - "test.test.sui" - ); - assert_eq!( - "test.test.test.sui".parse::().unwrap().to_string(), - "test.test.test.sui" - ); -} - -#[test] -fn test_different_wildcard() { - assert_eq!("test.sui".parse::(), "test*sui".parse::(),); - - assert_eq!("@test".parse::(), "test*sui".parse::(),); -} - -#[test] -fn test_invalid_inputs() { - assert!("*".parse::().is_err()); - assert!(".".parse::().is_err()); - assert!("@".parse::().is_err()); - assert!("@inner.sui".parse::().is_err()); - assert!("@inner*sui".parse::().is_err()); - assert!("test@".parse::().is_err()); - assert!("sui".parse::().is_err()); - assert!("test.test@example.sui".parse::().is_err()); - assert!("test@test@example".parse::().is_err()); -} - -#[test] -fn output_tests() { - let mut domain = "test.sui".parse::().unwrap(); - assert!(domain.format(name_service::DomainFormat::Dot) == "test.sui"); - assert!(domain.format(name_service::DomainFormat::At) == "@test"); - - domain = "test.test.sui".parse::().unwrap(); - assert!(domain.format(name_service::DomainFormat::Dot) == "test.test.sui"); - assert!(domain.format(name_service::DomainFormat::At) == "test@test"); - - domain = "test.test.test.sui".parse::().unwrap(); - assert!(domain.format(name_service::DomainFormat::Dot) == "test.test.test.sui"); - assert!(domain.format(name_service::DomainFormat::At) == "test.test@test"); - - domain = "test.test.test.test.sui".parse::().unwrap(); - assert!(domain.format(name_service::DomainFormat::Dot) == "test.test.test.test.sui"); - assert!(domain.format(name_service::DomainFormat::At) == "test.test.test@test"); -} diff --git a/crates/sui-json-rpc-tests/tests/subscription_tests.rs b/crates/sui-json-rpc-tests/tests/subscription_tests.rs deleted file mode 100644 index 9980946c0d6..00000000000 --- a/crates/sui-json-rpc-tests/tests/subscription_tests.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::time::Duration; - -use jsonrpsee::{ - core::client::{Subscription, SubscriptionClientT}, - rpc_params, -}; -use sui_core::test_utils::wait_for_tx; -use sui_json_rpc_types::{ - SuiTransactionBlockEffects, SuiTransactionBlockEffectsAPI, TransactionFilter, -}; -use sui_test_transaction_builder::{create_devnet_nft, publish_nfts_package}; -use test_cluster::TestClusterBuilder; -use tokio::time::timeout; - -#[tokio::test] -async fn test_subscribe_transaction() -> Result<(), anyhow::Error> { - let cluster = TestClusterBuilder::new().build().await; - - let address = &cluster.get_address_0(); - let wallet = cluster.wallet; - - let ws_client = cluster.fullnode_handle.ws_client().await; - - let package_id = publish_nfts_package(&wallet).await.0; - - let mut sub: Subscription = ws_client - .subscribe( - "suix_subscribeTransaction", - rpc_params![TransactionFilter::FromAddress(*address)], - "suix_unsubscribeTransaction", - ) - .await - .unwrap(); - - let (_, _, digest) = create_devnet_nft(&wallet, package_id).await; - wait_for_tx(digest, cluster.fullnode_handle.sui_node.state()).await; - - // Wait for streaming - let effects = match timeout(Duration::from_secs(5), sub.next()).await { - Ok(Some(Ok(tx))) => tx, - _ => panic!("Failed to get tx"), - }; - - assert_eq!(&digest, effects.transaction_digest()); - Ok(()) -} diff --git a/crates/sui-json-rpc-tests/tests/transaction_tests.rs b/crates/sui-json-rpc-tests/tests/transaction_tests.rs deleted file mode 100644 index 99c3a2594c0..00000000000 --- a/crates/sui-json-rpc-tests/tests/transaction_tests.rs +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use sui_json_rpc_api::{IndexerApiClient, TransactionBuilderClient, WriteApiClient}; -use sui_json_rpc_types::{ - SuiObjectDataOptions, SuiObjectResponseQuery, SuiTransactionBlockResponse, - SuiTransactionBlockResponseOptions, SuiTransactionBlockResponseQuery, TransactionBlockBytes, - TransactionFilter, -}; -use sui_macros::sim_test; -use sui_types::{ - quorum_driver_types::ExecuteTransactionRequestType, transaction::SenderSignedData, -}; -use test_cluster::TestClusterBuilder; - -#[sim_test] -async fn test_get_transaction_block() -> Result<(), anyhow::Error> { - let cluster = TestClusterBuilder::new().build().await; - let http_client = cluster.rpc_client(); - let address = cluster.get_address_0(); - - let objects = http_client - .get_owned_objects( - address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() - .with_type() - .with_owner() - .with_previous_transaction(), - )), - None, - None, - ) - .await? - .data; - let gas_id = objects.last().unwrap().object().unwrap().object_id; - - // Make some transactions - let mut tx_responses: Vec = Vec::new(); - for obj in &objects[..objects.len() - 1] { - let oref = obj.object().unwrap(); - let transaction_bytes: TransactionBlockBytes = http_client - .transfer_object( - address, - oref.object_id, - Some(gas_id), - 1_000_000.into(), - address, - ) - .await?; - let tx = cluster - .wallet - .sign_transaction(&transaction_bytes.to_data()?); - - let (tx_bytes, signatures) = tx.to_tx_bytes_and_signatures(); - - let response = http_client - .execute_transaction_block( - tx_bytes, - signatures, - Some(SuiTransactionBlockResponseOptions::new()), - Some(ExecuteTransactionRequestType::WaitForLocalExecution), - ) - .await?; - - tx_responses.push(response); - } - - // TODO(chris): re-enable after rewriting get_transactions_in_range_deprecated - // with query_transactions test get_transaction_batch - // let batch_responses: Vec = http_client - // .multi_get_transaction_blocks(tx, - // Some(SuiTransactionBlockResponseOptions::new())) .await?; - - // assert_eq!(5, batch_responses.len()); - - // for r in batch_responses.iter().skip(1) { - // assert!(tx_responses - // .iter() - // .any(|resp| matches!(resp, SuiTransactionBlockResponse {digest, ..} - // if *digest == r.digest))) } - - // // test get_transaction - // for tx_digest in tx { - // let response: SuiTransactionBlockResponse = http_client - // .get_transaction_block( - // tx_digest, - // Some(SuiTransactionBlockResponseOptions::new().with_raw_input()), - // ) - // .await?; - // assert!(tx_responses.iter().any( - // |resp| matches!(resp, SuiTransactionBlockResponse {digest, ..} if *digest == response.digest) - // )); - // let sender_signed_data: SenderSignedData = - // bcs::from_bytes(&response.raw_transaction).unwrap(); - // assert_eq!(sender_signed_data.digest(), tx_digest); - // } - - Ok(()) -} - -#[sim_test] -async fn test_get_raw_transaction() -> Result<(), anyhow::Error> { - let cluster = TestClusterBuilder::new().build().await; - let http_client = cluster.rpc_client(); - let address = cluster.get_address_0(); - - let objects = http_client - .get_owned_objects( - address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new(), - )), - None, - None, - ) - .await? - .data; - let object_to_transfer = objects.first().unwrap().object().unwrap().object_id; - - // Make a transfer transactions - let transaction_bytes: TransactionBlockBytes = http_client - .transfer_object(address, object_to_transfer, None, 1_000_000.into(), address) - .await?; - let tx = cluster - .wallet - .sign_transaction(&transaction_bytes.to_data()?); - let original_sender_signed_data = tx.data().clone(); - - let (tx_bytes, signatures) = tx.to_tx_bytes_and_signatures(); - - let response = http_client - .execute_transaction_block( - tx_bytes, - signatures, - Some(SuiTransactionBlockResponseOptions::new().with_raw_input()), - Some(ExecuteTransactionRequestType::WaitForLocalExecution), - ) - .await?; - - let decode_sender_signed_data: SenderSignedData = - bcs::from_bytes(&response.raw_transaction).unwrap(); - // verify that the raw transaction data returned by the response is the same - // as the original transaction data - assert_eq!(decode_sender_signed_data, original_sender_signed_data); - - Ok(()) -} - -#[sim_test] -async fn test_get_fullnode_transaction() -> Result<(), anyhow::Error> { - let cluster = TestClusterBuilder::new().build().await; - - let context = &cluster.wallet; - - let mut tx_responses: Vec = Vec::new(); - - let client = context.get_client().await.unwrap(); - - for address in cluster.get_addresses() { - let objects = client - .read_api() - .get_owned_objects( - address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() - .with_type() - .with_owner() - .with_previous_transaction(), - )), - None, - None, - ) - .await? - .data; - let gas_id = objects.last().unwrap().object().unwrap().object_id; - - // Make some transactions - for obj in &objects[..objects.len() - 1] { - let oref = obj.object().unwrap(); - let data = client - .transaction_builder() - .transfer_object(address, oref.object_id, Some(gas_id), 1_000_000, address) - .await?; - let tx = cluster.wallet.sign_transaction(&data); - - let response = client - .quorum_driver_api() - .execute_transaction_block( - tx, - SuiTransactionBlockResponseOptions::new(), - Some(ExecuteTransactionRequestType::WaitForLocalExecution), - ) - .await - .unwrap(); - - tx_responses.push(response); - } - } - - // test get_recent_transactions with smaller range - let query = SuiTransactionBlockResponseQuery { - options: Some(SuiTransactionBlockResponseOptions { - show_input: true, - show_effects: true, - show_events: true, - ..Default::default() - }), - ..Default::default() - }; - - let tx = client - .read_api() - .query_transaction_blocks(query, None, Some(3), true) - .await - .unwrap(); - assert_eq!(3, tx.data.len()); - assert!(tx.data[0].transaction.is_some()); - assert!(tx.data[0].effects.is_some()); - assert!(tx.data[0].events.is_some()); - assert!(tx.has_next_page); - - // test get all transactions paged - let first_page = client - .read_api() - .query_transaction_blocks( - SuiTransactionBlockResponseQuery::default(), - None, - Some(5), - false, - ) - .await - .unwrap(); - assert_eq!(5, first_page.data.len()); - assert!(first_page.has_next_page); - - let second_page = client - .read_api() - .query_transaction_blocks( - SuiTransactionBlockResponseQuery::default(), - first_page.next_cursor, - None, - false, - ) - .await - .unwrap(); - assert!(second_page.data.len() > 5); - assert!(!second_page.has_next_page); - - let mut all_txs_rev = first_page.data.clone(); - all_txs_rev.extend(second_page.data); - all_txs_rev.reverse(); - - // test get 10 latest transactions paged - let latest = client - .read_api() - .query_transaction_blocks( - SuiTransactionBlockResponseQuery::default(), - None, - Some(10), - true, - ) - .await - .unwrap(); - assert_eq!(10, latest.data.len()); - assert_eq!(Some(all_txs_rev[9].digest), latest.next_cursor); - assert_eq!(all_txs_rev[0..10], latest.data); - assert!(latest.has_next_page); - - // test get from address txs in ascending order - let address_txs_asc = client - .read_api() - .query_transaction_blocks( - SuiTransactionBlockResponseQuery::new_with_filter(TransactionFilter::FromAddress( - cluster.get_address_0(), - )), - None, - None, - false, - ) - .await - .unwrap(); - assert_eq!(4, address_txs_asc.data.len()); - - // test get from address txs in descending order - let address_txs_desc = client - .read_api() - .query_transaction_blocks( - SuiTransactionBlockResponseQuery::new_with_filter(TransactionFilter::FromAddress( - cluster.get_address_0(), - )), - None, - None, - true, - ) - .await - .unwrap(); - assert_eq!(4, address_txs_desc.data.len()); - - // test get from address txs in both ordering are the same. - let mut data_asc = address_txs_asc.data; - data_asc.reverse(); - assert_eq!(data_asc, address_txs_desc.data); - - // test get_recent_transactions - let tx = client - .read_api() - .query_transaction_blocks( - SuiTransactionBlockResponseQuery::default(), - None, - Some(20), - true, - ) - .await - .unwrap(); - assert_eq!(20, tx.data.len()); - - // test get_transaction - for tx_resp in tx.data { - let response: SuiTransactionBlockResponse = client - .read_api() - .get_transaction_with_options(tx_resp.digest, SuiTransactionBlockResponseOptions::new()) - .await - .unwrap(); - assert_eq!(tx_resp.digest, response.digest); - } - - Ok(()) -} diff --git a/crates/sui-json-rpc-types/Cargo.toml b/crates/sui-json-rpc-types/Cargo.toml deleted file mode 100644 index d43b3a7ac39..00000000000 --- a/crates/sui-json-rpc-types/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -name = "sui-json-rpc-types" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -fastcrypto.workspace = true -schemars.workspace = true -serde.workspace = true -serde_json.workspace = true -serde_with.workspace = true -colored.workspace = true -itertools.workspace = true -tracing.workspace = true -bcs.workspace = true -sui-protocol-config.workspace = true -sui-macros.workspace = true -sui-enum-compat-util.workspace = true -enum_dispatch.workspace = true -json_to_table.workspace = true -tabled.workspace = true - -move-binary-format.workspace = true -move-core-types.workspace = true -move-bytecode-utils.workspace = true - -mysten-metrics.workspace = true -sui-types.workspace = true -sui-json.workspace = true - -[dev-dependencies] -sui-types = { workspace = true, features = ["test-utils"] } - -[features] -test-utils = [] diff --git a/crates/sui-json-rpc-types/src/balance_changes.rs b/crates/sui-json-rpc-types/src/balance_changes.rs deleted file mode 100644 index 23c3c07e8b0..00000000000 --- a/crates/sui-json-rpc-types/src/balance_changes.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use std::fmt::{Display, Formatter, Result}; - -use move_core_types::language_storage::TypeTag; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_with::{serde_as, DisplayFromStr}; -use sui_types::{object::Owner, sui_serde::SuiTypeTag}; - -#[serde_as] -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] -#[serde(rename_all = "camelCase")] -pub struct BalanceChange { - /// Owner of the balance change - pub owner: Owner, - #[schemars(with = "String")] - #[serde_as(as = "SuiTypeTag")] - pub coin_type: TypeTag, - /// The amount indicate the balance value changes, - /// negative amount means spending coin value and positive means receiving - /// coin value. - #[schemars(with = "String")] - #[serde_as(as = "DisplayFromStr")] - pub amount: i128, -} - -impl Display for BalanceChange { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - write!( - f, - " ┌──\n │ Owner: {} \n │ CoinType: {} \n │ Amount: {}\n └──", - self.owner, self.coin_type, self.amount - ) - } -} diff --git a/crates/sui-json-rpc-types/src/displays/mod.rs b/crates/sui-json-rpc-types/src/displays/mod.rs deleted file mode 100644 index 1b5ad9e0e3d..00000000000 --- a/crates/sui-json-rpc-types/src/displays/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod transaction_displays; - -pub struct Pretty<'a, T>(pub &'a T); diff --git a/crates/sui-json-rpc-types/src/displays/transaction_displays.rs b/crates/sui-json-rpc-types/src/displays/transaction_displays.rs deleted file mode 100644 index 478a3de9072..00000000000 --- a/crates/sui-json-rpc-types/src/displays/transaction_displays.rs +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt::{Display, Formatter}; - -use sui_types::transaction::write_sep; -use tabled::{ - builder::Builder as TableBuilder, - settings::{style::HorizontalLine, Panel as TablePanel, Style as TableStyle}, -}; - -use crate::{ - displays::Pretty, SuiArgument, SuiCallArg, SuiCommand, SuiObjectArg, SuiProgrammableMoveCall, - SuiProgrammableTransactionBlock, -}; - -impl<'a> Display for Pretty<'a, SuiProgrammableTransactionBlock> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Pretty(ptb) = self; - let SuiProgrammableTransactionBlock { inputs, commands } = ptb; - if !inputs.is_empty() { - let mut builder = TableBuilder::default(); - for (i, input) in inputs.iter().enumerate() { - match input { - SuiCallArg::Pure(v) => { - let pure_arg = if let Some(t) = v.value_type() { - format!( - "{i:<3} Pure Arg: Type: {}, Value: {}", - t, - v.value().to_json_value() - ) - } else { - format!("{i:<3} Pure Arg: {}", v.value().to_json_value()) - }; - builder.push_record(vec![pure_arg]); - } - SuiCallArg::Object(SuiObjectArg::ImmOrOwnedObject { object_id, .. }) => { - builder.push_record(vec![format!( - "{i:<3} Imm/Owned Object ID: {}", - object_id - )]); - } - SuiCallArg::Object(SuiObjectArg::SharedObject { object_id, .. }) => { - builder.push_record(vec![format!( - "{i:<3} Shared Object ID: {}", - object_id - )]); - } - SuiCallArg::Object(SuiObjectArg::Receiving { object_id, .. }) => { - builder.push_record(vec![format!( - "{i:<3} Receiving Object ID: {}", - object_id - )]); - } - } - } - - let mut table = builder.build(); - table.with(TablePanel::header("Input Objects")); - table.with(TableStyle::rounded().horizontals([HorizontalLine::new( - 1, - TableStyle::modern().get_horizontal(), - )])); - write!(f, "\n{}", table)?; - } else { - write!(f, "\n No input objects for this transaction")?; - } - - if !commands.is_empty() { - let mut builder = TableBuilder::default(); - for (i, c) in commands.iter().enumerate() { - if i == commands.len() - 1 { - builder.push_record(vec![format!("{i:<2} {}", Pretty(c))]); - } else { - builder.push_record(vec![format!("{i:<2} {}\n", Pretty(c))]); - } - } - let mut table = builder.build(); - table.with(TablePanel::header("Commands")); - table.with(TableStyle::rounded().horizontals([HorizontalLine::new( - 1, - TableStyle::modern().get_horizontal(), - )])); - write!(f, "\n{}", table) - } else { - write!(f, "\n No commands for this transaction") - } - } -} - -impl<'a> Display for Pretty<'a, SuiCommand> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Pretty(command) = self; - match command { - SuiCommand::MakeMoveVec(ty_opt, elems) => { - write!(f, "MakeMoveVec:\n ┌")?; - if let Some(ty) = ty_opt { - write!(f, "\n │ Type Tag: {ty}")?; - } - write!(f, "\n │ Arguments:\n │ ")?; - write_sep(f, elems.iter().map(Pretty), "\n │ ")?; - write!(f, "\n └") - } - - SuiCommand::MoveCall(p) => write!(f, "{}", Pretty(&**p)), - - SuiCommand::MergeCoins(target, coins) => { - write!( - f, - "MergeCoins:\n ┌\n │ Target: {}\n │ Coins: \n │ ", - Pretty(target) - )?; - write_sep(f, coins.iter().map(Pretty), "\n │ ")?; - write!(f, "\n └") - } - - SuiCommand::SplitCoins(coin, amounts) => { - write!( - f, - "SplitCoins:\n ┌\n │ Coin: {}\n │ Amounts: \n │ ", - Pretty(coin) - )?; - write_sep(f, amounts.iter().map(Pretty), "\n │ ")?; - write!(f, "\n └") - } - - SuiCommand::Publish(deps) => { - write!(f, "Publish:\n ┌\n │ Dependencies: \n │ ")?; - write_sep(f, deps, "\n │ ")?; - write!(f, "\n └") - } - - SuiCommand::TransferObjects(objs, addr) => { - write!(f, "TransferObjects:\n ┌\n │ Arguments: \n │ ")?; - write_sep(f, objs.iter().map(Pretty), "\n │ ")?; - write!(f, "\n │ Address: {}\n └", Pretty(addr)) - } - - SuiCommand::Upgrade(deps, current_package_id, ticket) => { - write!(f, "Upgrade:\n ┌\n │ Dependencies: \n │ ")?; - write_sep(f, deps, "\n │ ")?; - write!(f, "\n │ Current Package ID: {current_package_id}")?; - write!(f, "\n │ Ticket: {}", Pretty(ticket))?; - write!(f, "\n └") - } - } - } -} - -impl<'a> Display for Pretty<'a, SuiProgrammableMoveCall> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Pretty(move_call) = self; - let SuiProgrammableMoveCall { - package, - module, - function, - type_arguments, - arguments, - } = move_call; - - write!( - f, - "MoveCall:\n ┌\n │ Function: {} \n │ Module: {}\n │ Package: {}", - function, module, package - )?; - - if !type_arguments.is_empty() { - write!(f, "\n │ Type Arguments: \n │ ")?; - write_sep(f, type_arguments, "\n │ ")?; - } - if !arguments.is_empty() { - write!(f, "\n │ Arguments: \n │ ")?; - write_sep(f, arguments.iter().map(Pretty), "\n │ ")?; - } - - write!(f, "\n └") - } -} - -impl<'a> Display for Pretty<'a, SuiArgument> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Pretty(argument) = self; - - let output = match argument { - SuiArgument::GasCoin => "GasCoin".to_string(), - SuiArgument::Input(i) => format!("Input {}", i), - SuiArgument::Result(i) => format!("Result {}", i), - SuiArgument::NestedResult(j, k) => format!("Nested Result {}: {}", j, k), - }; - write!(f, "{}", output) - } -} diff --git a/crates/sui-json-rpc-types/src/lib.rs b/crates/sui-json-rpc-types/src/lib.rs deleted file mode 100644 index f8469ed62c2..00000000000 --- a/crates/sui-json-rpc-types/src/lib.rs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub use balance_changes::*; -pub use object_changes::*; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -pub use sui_checkpoint::*; -pub use sui_coin::*; -pub use sui_event::*; -pub use sui_extended::*; -pub use sui_governance::*; -pub use sui_move::*; -pub use sui_object::*; -pub use sui_protocol::*; -pub use sui_transaction::*; -use sui_types::{base_types::ObjectID, dynamic_field::DynamicFieldInfo}; - -#[cfg(test)] -#[path = "unit_tests/rpc_types_tests.rs"] -mod rpc_types_tests; - -mod balance_changes; -mod displays; -mod object_changes; -mod sui_checkpoint; -mod sui_coin; -mod sui_event; -mod sui_extended; -mod sui_governance; -mod sui_move; -mod sui_object; -mod sui_protocol; -mod sui_transaction; - -pub type DynamicFieldPage = Page; -/// `next_cursor` points to the last item in the page; -/// Reading with `next_cursor` will start from the next item after `next_cursor` -/// if `next_cursor` is `Some`, otherwise it will start from the first item. -#[derive(Clone, Debug, JsonSchema, Serialize, Deserialize, PartialEq, Eq)] -#[serde(rename_all = "camelCase")] -pub struct Page { - pub data: Vec, - pub next_cursor: Option, - pub has_next_page: bool, -} - -impl Page { - pub fn empty() -> Self { - Self { - data: vec![], - next_cursor: None, - has_next_page: false, - } - } -} diff --git a/crates/sui-json-rpc-types/src/object_changes.rs b/crates/sui-json-rpc-types/src/object_changes.rs deleted file mode 100644 index 895e9c34fef..00000000000 --- a/crates/sui-json-rpc-types/src/object_changes.rs +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt::{Display, Formatter, Result}; - -use move_core_types::language_storage::StructTag; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use sui_types::{ - base_types::{ObjectDigest, ObjectID, ObjectRef, SequenceNumber, SuiAddress}, - object::Owner, - sui_serde::{SequenceNumber as AsSequenceNumber, SuiStructTag}, -}; - -/// ObjectChange are derived from the object mutations in the TransactionEffect -/// to provide richer object information. -#[serde_as] -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] -#[serde(rename_all = "camelCase", tag = "type")] -pub enum ObjectChange { - /// Module published - #[serde(rename_all = "camelCase")] - Published { - package_id: ObjectID, - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - version: SequenceNumber, - digest: ObjectDigest, - modules: Vec, - }, - /// Transfer objects to new address / wrap in another object - #[serde(rename_all = "camelCase")] - Transferred { - sender: SuiAddress, - recipient: Owner, - #[schemars(with = "String")] - #[serde_as(as = "SuiStructTag")] - object_type: StructTag, - object_id: ObjectID, - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - version: SequenceNumber, - digest: ObjectDigest, - }, - /// Object mutated. - #[serde(rename_all = "camelCase")] - Mutated { - sender: SuiAddress, - owner: Owner, - #[schemars(with = "String")] - #[serde_as(as = "SuiStructTag")] - object_type: StructTag, - object_id: ObjectID, - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - version: SequenceNumber, - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - previous_version: SequenceNumber, - digest: ObjectDigest, - }, - /// Delete object - #[serde(rename_all = "camelCase")] - Deleted { - sender: SuiAddress, - #[schemars(with = "String")] - #[serde_as(as = "SuiStructTag")] - object_type: StructTag, - object_id: ObjectID, - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - version: SequenceNumber, - }, - /// Wrapped object - #[serde(rename_all = "camelCase")] - Wrapped { - sender: SuiAddress, - #[schemars(with = "String")] - #[serde_as(as = "SuiStructTag")] - object_type: StructTag, - object_id: ObjectID, - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - version: SequenceNumber, - }, - /// New object creation - #[serde(rename_all = "camelCase")] - Created { - sender: SuiAddress, - owner: Owner, - #[schemars(with = "String")] - #[serde_as(as = "SuiStructTag")] - object_type: StructTag, - object_id: ObjectID, - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - version: SequenceNumber, - digest: ObjectDigest, - }, -} - -impl ObjectChange { - pub fn object_id(&self) -> ObjectID { - match self { - ObjectChange::Published { package_id, .. } => *package_id, - ObjectChange::Transferred { object_id, .. } - | ObjectChange::Mutated { object_id, .. } - | ObjectChange::Deleted { object_id, .. } - | ObjectChange::Wrapped { object_id, .. } - | ObjectChange::Created { object_id, .. } => *object_id, - } - } - - pub fn object_ref(&self) -> ObjectRef { - match self { - ObjectChange::Published { - package_id, - version, - digest, - .. - } => (*package_id, *version, *digest), - ObjectChange::Transferred { - object_id, - version, - digest, - .. - } - | ObjectChange::Mutated { - object_id, - version, - digest, - .. - } - | ObjectChange::Created { - object_id, - version, - digest, - .. - } => (*object_id, *version, *digest), - ObjectChange::Deleted { - object_id, version, .. - } => (*object_id, *version, ObjectDigest::OBJECT_DIGEST_DELETED), - ObjectChange::Wrapped { - object_id, version, .. - } => (*object_id, *version, ObjectDigest::OBJECT_DIGEST_WRAPPED), - } - } - - pub fn mask_for_test(&mut self, new_version: SequenceNumber, new_digest: ObjectDigest) { - match self { - ObjectChange::Published { - version, digest, .. - } - | ObjectChange::Transferred { - version, digest, .. - } - | ObjectChange::Mutated { - version, digest, .. - } - | ObjectChange::Created { - version, digest, .. - } => { - *version = new_version; - *digest = new_digest - } - ObjectChange::Deleted { version, .. } | ObjectChange::Wrapped { version, .. } => { - *version = new_version - } - } - } -} - -impl Display for ObjectChange { - fn fmt(&self, f: &mut Formatter) -> Result { - match self { - ObjectChange::Published { - package_id, - version, - digest, - modules, - } => { - write!( - f, - " ┌──\n │ PackageID: {} \n │ Version: {} \n │ Digest: {}\n │ Modules: {}\n └──", - package_id, - u64::from(*version), - digest, - modules.join(", ") - ) - } - ObjectChange::Transferred { - sender, - recipient, - object_type, - object_id, - version, - digest, - } => { - write!( - f, - " ┌──\n │ ObjectID: {}\n │ Sender: {} \n │ Recipient: {}\n │ ObjectType: {} \n │ Version: {}\n │ Digest: {}\n └──", - object_id, - sender, - recipient, - object_type, - u64::from(*version), - digest - ) - } - ObjectChange::Mutated { - sender, - owner, - object_type, - object_id, - version, - previous_version: _, - digest, - } => { - write!( - f, - " ┌──\n │ ObjectID: {}\n │ Sender: {} \n │ Owner: {}\n │ ObjectType: {} \n │ Version: {}\n │ Digest: {}\n └──", - object_id, - sender, - owner, - object_type, - u64::from(*version), - digest - ) - } - ObjectChange::Deleted { - sender, - object_type, - object_id, - version, - } => { - write!( - f, - " ┌──\n │ ObjectID: {}\n │ Sender: {} \n │ ObjectType: {} \n │ Version: {}\n └──", - object_id, - sender, - object_type, - u64::from(*version) - ) - } - ObjectChange::Wrapped { - sender, - object_type, - object_id, - version, - } => { - write!( - f, - " ┌──\n │ ObjectID: {}\n │ Sender: {} \n │ ObjectType: {} \n │ Version: {}\n └──", - object_id, - sender, - object_type, - u64::from(*version) - ) - } - ObjectChange::Created { - sender, - owner, - object_type, - object_id, - version, - digest, - } => { - write!( - f, - " ┌──\n │ ObjectID: {}\n │ Sender: {} \n │ Owner: {}\n │ ObjectType: {} \n │ Version: {}\n │ Digest: {}\n └──", - object_id, - sender, - owner, - object_type, - u64::from(*version), - digest - ) - } - } - } -} diff --git a/crates/sui-json-rpc-types/src/sui_checkpoint.rs b/crates/sui-json-rpc-types/src/sui_checkpoint.rs deleted file mode 100644 index 88f49f1984d..00000000000 --- a/crates/sui-json-rpc-types/src/sui_checkpoint.rs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use fastcrypto::encoding::Base64; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use sui_types::{ - base_types::TransactionDigest, - committee::EpochId, - crypto::AggregateAuthoritySignature, - digests::CheckpointDigest, - gas::GasCostSummary, - message_envelope::Message, - messages_checkpoint::{ - CheckpointCommitment, CheckpointContents, CheckpointSequenceNumber, CheckpointSummary, - CheckpointTimestamp, EndOfEpochData, - }, - sui_serde::BigInt, -}; - -use crate::Page; -pub type CheckpointPage = Page>; - -#[serde_as] -#[derive(Clone, Debug, JsonSchema, Serialize, Deserialize, PartialEq, Eq)] -#[serde(rename_all = "camelCase")] -pub struct Checkpoint { - /// Checkpoint's epoch ID - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub epoch: EpochId, - /// Checkpoint sequence number - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub sequence_number: CheckpointSequenceNumber, - /// Checkpoint digest - pub digest: CheckpointDigest, - /// Total number of transactions committed since genesis, including those in - /// this checkpoint. - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub network_total_transactions: u64, - /// Digest of the previous checkpoint - #[serde(skip_serializing_if = "Option::is_none")] - pub previous_digest: Option, - /// The running total gas costs of all transactions included in the current - /// epoch so far until this checkpoint. - pub epoch_rolling_gas_cost_summary: GasCostSummary, - /// Timestamp of the checkpoint - number of milliseconds from the Unix epoch - /// Checkpoint timestamps are monotonic, but not strongly monotonic - - /// subsequent checkpoints can have same timestamp if they originate - /// from the same underlining consensus commit - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub timestamp_ms: CheckpointTimestamp, - /// Present only on the final checkpoint of the epoch. - #[serde(skip_serializing_if = "Option::is_none")] - pub end_of_epoch_data: Option, - /// Transaction digests - pub transactions: Vec, - - /// Commitments to checkpoint state - pub checkpoint_commitments: Vec, - /// Validator Signature - #[schemars(with = "Base64")] - //#[serde_as(as = "Readable")] - pub validator_signature: AggregateAuthoritySignature, -} - -impl - From<( - CheckpointSummary, - CheckpointContents, - AggregateAuthoritySignature, - )> for Checkpoint -{ - fn from( - (summary, contents, signature): ( - CheckpointSummary, - CheckpointContents, - AggregateAuthoritySignature, - ), - ) -> Self { - let digest = summary.digest(); - let CheckpointSummary { - epoch, - sequence_number, - network_total_transactions, - previous_digest, - epoch_rolling_gas_cost_summary, - timestamp_ms, - end_of_epoch_data, - .. - } = summary; - - Checkpoint { - epoch, - sequence_number, - digest, - network_total_transactions, - previous_digest, - epoch_rolling_gas_cost_summary, - timestamp_ms, - end_of_epoch_data, - transactions: contents.iter().map(|digest| digest.transaction).collect(), - // TODO: populate commitment for rpc clients. Most likely, rpc clients don't need this - // info (if they need it, they need to get signed BCS data anyway in order to trust - // it). - checkpoint_commitments: Default::default(), - validator_signature: signature, - } - } -} - -#[serde_as] -#[derive(Clone, Copy, Debug, JsonSchema, Serialize, Deserialize)] -#[serde(untagged)] -pub enum CheckpointId { - SequenceNumber( - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - CheckpointSequenceNumber, - ), - Digest(CheckpointDigest), -} - -impl From for CheckpointId { - fn from(seq: CheckpointSequenceNumber) -> Self { - Self::SequenceNumber(seq) - } -} - -impl From for CheckpointId { - fn from(digest: CheckpointDigest) -> Self { - Self::Digest(digest) - } -} diff --git a/crates/sui-json-rpc-types/src/sui_coin.rs b/crates/sui-json-rpc-types/src/sui_coin.rs deleted file mode 100644 index 71b38b6b65d..00000000000 --- a/crates/sui-json-rpc-types/src/sui_coin.rs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::HashMap; - -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use sui_types::{ - base_types::{EpochId, ObjectDigest, ObjectID, ObjectRef, SequenceNumber, TransactionDigest}, - coin::CoinMetadata, - error::SuiError, - object::Object, - sui_serde::{BigInt, SequenceNumber as AsSequenceNumber}, -}; - -use crate::Page; - -pub type CoinPage = Page; - -#[serde_as] -#[derive(Serialize, Deserialize, Debug, JsonSchema, PartialEq, Eq, Clone)] -#[serde(rename_all = "camelCase")] -pub struct Balance { - pub coin_type: String, - pub coin_object_count: usize, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub total_balance: u128, - // TODO: This should be removed - #[schemars(with = "HashMap, BigInt>")] - #[serde_as(as = "HashMap, BigInt>")] - pub locked_balance: HashMap, -} - -impl Balance { - pub fn zero(coin_type: String) -> Self { - Self { - coin_type, - coin_object_count: 0, - total_balance: 0, - locked_balance: HashMap::new(), - } - } -} - -#[serde_as] -#[derive(Serialize, Deserialize, Debug, JsonSchema, PartialEq, Eq, Clone)] -#[serde(rename_all = "camelCase")] -pub struct Coin { - pub coin_type: String, - pub coin_object_id: ObjectID, - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - pub version: SequenceNumber, - pub digest: ObjectDigest, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub balance: u64, - pub previous_transaction: TransactionDigest, -} - -impl Coin { - pub fn object_ref(&self) -> ObjectRef { - (self.coin_object_id, self.version, self.digest) - } -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone, PartialEq, Eq)] -#[serde(rename_all = "camelCase")] -pub struct SuiCoinMetadata { - /// Number of decimal places the coin uses. - pub decimals: u8, - /// Name for the token - pub name: String, - /// Symbol for the token - pub symbol: String, - /// Description of the token - pub description: String, - /// URL for the token logo - pub icon_url: Option, - /// Object id for the CoinMetadata object - pub id: Option, -} - -impl TryFrom for SuiCoinMetadata { - type Error = SuiError; - fn try_from(object: Object) -> Result { - let metadata: CoinMetadata = object.try_into()?; - let CoinMetadata { - decimals, - name, - symbol, - description, - icon_url, - id, - } = metadata; - Ok(Self { - id: Some(*id.object_id()), - decimals, - name, - symbol, - description, - icon_url, - }) - } -} diff --git a/crates/sui-json-rpc-types/src/sui_event.rs b/crates/sui-json-rpc-types/src/sui_event.rs deleted file mode 100644 index aa24a939861..00000000000 --- a/crates/sui-json-rpc-types/src/sui_event.rs +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[cfg(any(feature = "test-utils", test))] -use std::str::FromStr; -use std::{fmt, fmt::Display}; - -use fastcrypto::encoding::{Base58, Base64}; -use json_to_table::json_to_table; -use move_core_types::{ - annotated_value::MoveStructLayout, identifier::Identifier, language_storage::StructTag, -}; -use mysten_metrics::monitored_scope; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_json::{json, Value}; -use serde_with::{serde_as, DisplayFromStr}; -use sui_types::{ - base_types::{ObjectID, SuiAddress, TransactionDigest}, - error::SuiResult, - event::{Event, EventEnvelope, EventID}, - sui_serde::{BigInt, SuiStructTag}, -}; -use tabled::settings::Style as TableStyle; - -use crate::{type_and_fields_from_move_struct, Page}; - -pub type EventPage = Page; - -#[serde_as] -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] -#[serde(rename = "Event", rename_all = "camelCase")] -pub struct SuiEvent { - /// Sequential event ID, ie (transaction seq number, event seq number). - /// 1) Serves as a unique event ID for each fullnode - /// 2) Also serves to sequence events for the purposes of pagination and - /// querying. A higher id is an event seen later by that fullnode. - /// This ID is the "cursor" for event querying. - pub id: EventID, - /// Move package where this event was emitted. - pub package_id: ObjectID, - #[schemars(with = "String")] - #[serde_as(as = "DisplayFromStr")] - /// Move module where this event was emitted. - pub transaction_module: Identifier, - /// Sender's Sui address. - pub sender: SuiAddress, - #[schemars(with = "String")] - #[serde_as(as = "SuiStructTag")] - /// Move event type. - pub type_: StructTag, - /// Parsed json value of the event - pub parsed_json: Value, - #[serde_as(as = "Base58")] - #[schemars(with = "Base58")] - /// Base 58 encoded bcs bytes of the move event - pub bcs: Vec, - /// UTC timestamp in milliseconds since epoch (1/1/1970) - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(with = "Option>")] - #[serde_as(as = "Option>")] - pub timestamp_ms: Option, -} - -impl From for SuiEvent { - fn from(ev: EventEnvelope) -> Self { - Self { - id: EventID { - tx_digest: ev.tx_digest, - event_seq: ev.event_num, - }, - package_id: ev.event.package_id, - transaction_module: ev.event.transaction_module, - sender: ev.event.sender, - type_: ev.event.type_, - parsed_json: ev.parsed_json, - bcs: ev.event.contents, - timestamp_ms: Some(ev.timestamp), - } - } -} - -impl From for Event { - fn from(val: SuiEvent) -> Self { - Event { - package_id: val.package_id, - transaction_module: val.transaction_module, - sender: val.sender, - type_: val.type_, - contents: val.bcs, - } - } -} - -impl SuiEvent { - pub fn try_from( - event: Event, - tx_digest: TransactionDigest, - event_seq: u64, - timestamp_ms: Option, - layout: MoveStructLayout, - ) -> SuiResult { - let Event { - package_id, - transaction_module, - sender, - type_, - contents, - } = event; - - let bcs = contents.to_vec(); - - let move_struct = Event::move_event_to_move_struct(&contents, layout)?; - let (type_, field) = type_and_fields_from_move_struct(&type_, move_struct); - - Ok(SuiEvent { - id: EventID { - tx_digest, - event_seq, - }, - package_id, - transaction_module, - sender, - type_, - parsed_json: field.to_json_value(), - bcs, - timestamp_ms, - }) - } -} - -impl Display for SuiEvent { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let parsed_json = &mut self.parsed_json.clone(); - bytes_array_to_base64(parsed_json); - let mut table = json_to_table(parsed_json); - let style = TableStyle::modern(); - table.collapse().with(style); - write!( - f, - " ┌──\n │ EventID: {}:{}\n │ PackageID: {}\n │ Transaction Module: {}\n │ Sender: {}\n │ EventType: {}\n", - self.id.tx_digest, - self.id.event_seq, - self.package_id, - self.transaction_module, - self.sender, - self.type_ - )?; - if let Some(ts) = self.timestamp_ms { - writeln!(f, " │ Timestamp: {}\n └──", ts)?; - } - writeln!(f, " │ ParsedJSON:")?; - let table_string = table.to_string(); - let table_rows = table_string.split_inclusive('\n'); - for r in table_rows { - write!(f, " │ {r}")?; - } - - write!(f, "\n └──") - } -} - -#[cfg(any(feature = "test-utils", test))] -impl SuiEvent { - pub fn random_for_testing() -> Self { - Self { - id: EventID { - tx_digest: TransactionDigest::random(), - event_seq: 0, - }, - package_id: ObjectID::random(), - transaction_module: Identifier::from_str("random_for_testing").unwrap(), - sender: SuiAddress::random_for_testing_only(), - type_: StructTag::from_str("0x6666::random_for_testing::RandomForTesting").unwrap(), - parsed_json: json!({}), - bcs: vec![], - timestamp_ms: None, - } - } -} - -/// Convert a json array of bytes to Base64 -fn bytes_array_to_base64(v: &mut Value) { - match v { - Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => (), - Value::Array(vals) => { - if let Some(vals) = vals.iter().map(try_into_byte).collect::>>() { - *v = json!(Base64::from_bytes(&vals).encoded()) - } else { - for val in vals { - bytes_array_to_base64(val) - } - } - } - Value::Object(map) => { - for val in map.values_mut() { - bytes_array_to_base64(val) - } - } - } -} - -/// Try to convert a json Value object into an u8. -fn try_into_byte(v: &Value) -> Option { - let num = v.as_u64()?; - (num <= 255).then_some(num as u8) -} - -#[serde_as] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub enum EventFilter { - /// Query by sender address. - Sender(SuiAddress), - /// Return events emitted by the given transaction. - Transaction( - /// digest of the transaction, as base-64 encoded string - TransactionDigest, - ), - /// Return events emitted in a specified Package. - Package(ObjectID), - /// Return events emitted in a specified Move module. - /// If the event is defined in Module A but emitted in a tx with Module B, - /// query `MoveModule` by module B returns the event. - /// Query `MoveEventModule` by module A returns the event too. - MoveModule { - /// the Move package ID - package: ObjectID, - /// the module name - #[schemars(with = "String")] - #[serde_as(as = "DisplayFromStr")] - module: Identifier, - }, - /// Return events with the given Move event struct name (struct tag). - /// For example, if the event is defined in `0xabcd::MyModule`, and named - /// `Foo`, then the struct tag is `0xabcd::MyModule::Foo`. - MoveEventType( - #[schemars(with = "String")] - #[serde_as(as = "SuiStructTag")] - StructTag, - ), - /// Return events with the given Move module name where the event struct is - /// defined. If the event is defined in Module A but emitted in a tx - /// with Module B, query `MoveEventModule` by module A returns the - /// event. Query `MoveModule` by module B returns the event too. - MoveEventModule { - /// the Move package ID - package: ObjectID, - /// the module name - #[schemars(with = "String")] - #[serde_as(as = "DisplayFromStr")] - module: Identifier, - }, - MoveEventField { - path: String, - value: Value, - }, - /// Return events emitted in [start_time, end_time] interval - #[serde(rename_all = "camelCase")] - TimeRange { - /// left endpoint of time interval, milliseconds since epoch, inclusive - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - start_time: u64, - /// right endpoint of time interval, milliseconds since epoch, exclusive - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - end_time: u64, - }, - - All(Vec), - Any(Vec), - And(Box, Box), - Or(Box, Box), -} - -impl EventFilter { - fn try_matches(&self, item: &SuiEvent) -> SuiResult { - Ok(match self { - EventFilter::MoveEventType(event_type) => &item.type_ == event_type, - EventFilter::MoveEventField { path, value } => { - matches!(item.parsed_json.pointer(path), Some(v) if v == value) - } - EventFilter::Sender(sender) => &item.sender == sender, - EventFilter::Package(object_id) => &item.package_id == object_id, - EventFilter::MoveModule { package, module } => { - &item.transaction_module == module && &item.package_id == package - } - EventFilter::All(filters) => filters.iter().all(|f| f.matches(item)), - EventFilter::Any(filters) => filters.iter().any(|f| f.matches(item)), - EventFilter::And(f1, f2) => { - EventFilter::All(vec![*(*f1).clone(), *(*f2).clone()]).matches(item) - } - EventFilter::Or(f1, f2) => { - EventFilter::Any(vec![*(*f1).clone(), *(*f2).clone()]).matches(item) - } - EventFilter::Transaction(digest) => digest == &item.id.tx_digest, - - EventFilter::TimeRange { - start_time, - end_time, - } => { - if let Some(timestamp) = &item.timestamp_ms { - start_time <= timestamp && end_time > timestamp - } else { - false - } - } - EventFilter::MoveEventModule { package, module } => { - &item.type_.module == module && &ObjectID::from(item.type_.address) == package - } - }) - } - - pub fn and(self, other_filter: EventFilter) -> Self { - Self::All(vec![self, other_filter]) - } - pub fn or(self, other_filter: EventFilter) -> Self { - Self::Any(vec![self, other_filter]) - } -} - -impl Filter for EventFilter { - fn matches(&self, item: &SuiEvent) -> bool { - let _scope = monitored_scope("EventFilter::matches"); - self.try_matches(item).unwrap_or_default() - } -} - -pub trait Filter { - fn matches(&self, item: &T) -> bool; -} diff --git a/crates/sui-json-rpc-types/src/sui_extended.rs b/crates/sui-json-rpc-types/src/sui_extended.rs deleted file mode 100644 index dd474455576..00000000000 --- a/crates/sui-json-rpc-types/src/sui_extended.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use fastcrypto::traits::ToFromBytes; -use move_core_types::identifier::Identifier; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_with::{serde_as, DisplayFromStr}; -use sui_types::{ - base_types::{AuthorityName, EpochId, ObjectID}, - committee::Committee, - messages_checkpoint::CheckpointSequenceNumber, - sui_serde::BigInt, - sui_system_state::sui_system_state_summary::SuiValidatorSummary, -}; - -use crate::Page; - -pub type EpochPage = Page>; - -#[serde_as] -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct EpochInfo { - /// epoch number - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub epoch: EpochId, - /// list of validators included in epoch - pub validators: Vec, - /// count of tx in epoch - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub epoch_total_transactions: u64, - /// first, last checkpoint sequence numbers - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub first_checkpoint_id: CheckpointSequenceNumber, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub epoch_start_timestamp: u64, - pub end_of_epoch_info: Option, - pub reference_gas_price: Option, -} - -impl EpochInfo { - pub fn committee(&self) -> Result { - let mut voting_rights = BTreeMap::new(); - for validator in &self.validators { - let name = AuthorityName::from_bytes(&validator.protocol_pubkey_bytes)?; - voting_rights.insert(name, validator.voting_power); - } - Ok(Committee::new(self.epoch, voting_rights)) - } -} - -#[serde_as] -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct EndOfEpochInfo { - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub last_checkpoint_id: CheckpointSequenceNumber, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub epoch_end_timestamp: u64, - /// existing fields from `SystemEpochInfo` - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub protocol_version: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub reference_gas_price: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub total_stake: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub storage_fund_reinvestment: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub storage_charge: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub storage_rebate: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub storage_fund_balance: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub stake_subsidy_amount: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub total_gas_fees: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub total_stake_rewards_distributed: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub leftover_storage_fund_inflow: u64, -} - -#[serde_as] -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct MoveFunctionName { - pub package: ObjectID, - #[schemars(with = "String")] - #[serde_as(as = "DisplayFromStr")] - pub module: Identifier, - #[schemars(with = "String")] - #[serde_as(as = "DisplayFromStr")] - pub function: Identifier, -} diff --git a/crates/sui-json-rpc-types/src/sui_governance.rs b/crates/sui-json-rpc-types/src/sui_governance.rs deleted file mode 100644 index eb05236a98c..00000000000 --- a/crates/sui-json-rpc-types/src/sui_governance.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use sui_types::{ - base_types::{AuthorityName, EpochId, ObjectID, SuiAddress}, - committee::{Committee, StakeUnit}, - sui_serde::BigInt, -}; - -/// RPC representation of the [Committee] type. -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] -#[serde(rename = "CommitteeInfo")] -pub struct SuiCommittee { - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub epoch: EpochId, - #[schemars(with = "Vec<(AuthorityName, BigInt)>")] - #[serde_as(as = "Vec<(_, BigInt)>")] - pub validators: Vec<(AuthorityName, StakeUnit)>, -} - -impl From for SuiCommittee { - fn from(committee: Committee) -> Self { - Self { - epoch: committee.epoch, - validators: committee.voting_rights, - } - } -} - -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct DelegatedStake { - /// Validator's Address. - pub validator_address: SuiAddress, - /// Staking pool object id. - pub staking_pool: ObjectID, - pub stakes: Vec, -} - -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct DelegatedTimelockedStake { - pub validator_address: SuiAddress, - pub staking_pool: ObjectID, - pub stakes: Vec, -} - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] -#[serde(tag = "status")] -pub enum StakeStatus { - Pending, - #[serde(rename_all = "camelCase")] - Active { - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - estimated_reward: u64, - }, - Unstaked, -} - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct Stake { - /// ID of the StakedSui receipt object. - pub staked_sui_id: ObjectID, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub stake_request_epoch: EpochId, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub stake_active_epoch: EpochId, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub principal: u64, - #[serde(flatten)] - pub status: StakeStatus, -} - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct TimelockedStake { - pub timelocked_staked_sui_id: ObjectID, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub stake_request_epoch: EpochId, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub stake_active_epoch: EpochId, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub principal: u64, - #[serde(flatten)] - pub status: StakeStatus, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub expiration_timestamp_ms: u64, -} - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] -pub struct ValidatorApys { - pub apys: Vec, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub epoch: EpochId, -} - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] -pub struct ValidatorApy { - pub address: SuiAddress, - pub apy: f64, -} diff --git a/crates/sui-json-rpc-types/src/sui_move.rs b/crates/sui-json-rpc-types/src/sui_move.rs deleted file mode 100644 index 263ebf5258b..00000000000 --- a/crates/sui-json-rpc-types/src/sui_move.rs +++ /dev/null @@ -1,554 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::BTreeMap, - fmt, - fmt::{Display, Formatter, Write}, -}; - -use colored::Colorize; -use itertools::Itertools; -use move_binary_format::{ - file_format::{Ability, AbilitySet, StructTypeParameter, Visibility}, - normalized::{ - Field as NormalizedField, Function as SuiNormalizedFunction, Module as NormalizedModule, - Struct as NormalizedStruct, Type as NormalizedType, - }, -}; -use move_core_types::{ - annotated_value::{MoveStruct, MoveValue}, - identifier::Identifier, - language_storage::StructTag, -}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_json::{json, Value}; -use serde_with::serde_as; -use sui_macros::EnumVariantOrder; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, - sui_serde::SuiStructTag, -}; -use tracing::warn; - -pub type SuiMoveTypeParameterIndex = u16; - -#[cfg(test)] -#[path = "unit_tests/sui_move_tests.rs"] -mod sui_move_tests; - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -pub enum SuiMoveAbility { - Copy, - Drop, - Store, - Key, -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -pub struct SuiMoveAbilitySet { - pub abilities: Vec, -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -pub enum SuiMoveVisibility { - Private, - Public, - Friend, -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct SuiMoveStructTypeParameter { - pub constraints: SuiMoveAbilitySet, - pub is_phantom: bool, -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -pub struct SuiMoveNormalizedField { - pub name: String, - #[serde(rename = "type")] - pub type_: SuiMoveNormalizedType, -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct SuiMoveNormalizedStruct { - pub abilities: SuiMoveAbilitySet, - pub type_parameters: Vec, - pub fields: Vec, -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -pub enum SuiMoveNormalizedType { - Bool, - U8, - U16, - U32, - U64, - U128, - U256, - Address, - Signer, - #[serde(rename_all = "camelCase")] - Struct { - address: String, - module: String, - name: String, - type_arguments: Vec, - }, - Vector(Box), - TypeParameter(SuiMoveTypeParameterIndex), - Reference(Box), - MutableReference(Box), -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct SuiMoveNormalizedFunction { - pub visibility: SuiMoveVisibility, - pub is_entry: bool, - pub type_parameters: Vec, - pub parameters: Vec, - pub return_: Vec, -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -pub struct SuiMoveModuleId { - address: String, - name: String, -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct SuiMoveNormalizedModule { - pub file_format_version: u32, - pub address: String, - pub name: String, - pub friends: Vec, - pub structs: BTreeMap, - pub exposed_functions: BTreeMap, -} - -impl PartialEq for SuiMoveNormalizedModule { - fn eq(&self, other: &Self) -> bool { - self.file_format_version == other.file_format_version - && self.address == other.address - && self.name == other.name - } -} - -impl From for SuiMoveNormalizedModule { - fn from(module: NormalizedModule) -> Self { - Self { - file_format_version: module.file_format_version, - address: module.address.to_hex_literal(), - name: module.name.to_string(), - friends: module - .friends - .into_iter() - .map(|module_id| SuiMoveModuleId { - address: module_id.address().to_hex_literal(), - name: module_id.name().to_string(), - }) - .collect::>(), - structs: module - .structs - .into_iter() - .map(|(name, struct_)| (name.to_string(), SuiMoveNormalizedStruct::from(struct_))) - .collect::>(), - exposed_functions: module - .functions - .into_iter() - .filter_map(|(name, function)| { - // TODO: Do we want to expose the private functions as well? - (function.is_entry || function.visibility != Visibility::Private) - .then(|| (name.to_string(), SuiMoveNormalizedFunction::from(function))) - }) - .collect::>(), - } - } -} - -impl From for SuiMoveNormalizedFunction { - fn from(function: SuiNormalizedFunction) -> Self { - Self { - visibility: match function.visibility { - Visibility::Private => SuiMoveVisibility::Private, - Visibility::Public => SuiMoveVisibility::Public, - Visibility::Friend => SuiMoveVisibility::Friend, - }, - is_entry: function.is_entry, - type_parameters: function - .type_parameters - .into_iter() - .map(|a| a.into()) - .collect::>(), - parameters: function - .parameters - .into_iter() - .map(SuiMoveNormalizedType::from) - .collect::>(), - return_: function - .return_ - .into_iter() - .map(SuiMoveNormalizedType::from) - .collect::>(), - } - } -} - -impl From for SuiMoveNormalizedStruct { - fn from(struct_: NormalizedStruct) -> Self { - Self { - abilities: struct_.abilities.into(), - type_parameters: struct_ - .type_parameters - .into_iter() - .map(SuiMoveStructTypeParameter::from) - .collect::>(), - fields: struct_ - .fields - .into_iter() - .map(SuiMoveNormalizedField::from) - .collect::>(), - } - } -} - -impl From for SuiMoveStructTypeParameter { - fn from(type_parameter: StructTypeParameter) -> Self { - Self { - constraints: type_parameter.constraints.into(), - is_phantom: type_parameter.is_phantom, - } - } -} - -impl From for SuiMoveNormalizedField { - fn from(normalized_field: NormalizedField) -> Self { - Self { - name: normalized_field.name.to_string(), - type_: SuiMoveNormalizedType::from(normalized_field.type_), - } - } -} - -impl From for SuiMoveNormalizedType { - fn from(type_: NormalizedType) -> Self { - match type_ { - NormalizedType::Bool => SuiMoveNormalizedType::Bool, - NormalizedType::U8 => SuiMoveNormalizedType::U8, - NormalizedType::U16 => SuiMoveNormalizedType::U16, - NormalizedType::U32 => SuiMoveNormalizedType::U32, - NormalizedType::U64 => SuiMoveNormalizedType::U64, - NormalizedType::U128 => SuiMoveNormalizedType::U128, - NormalizedType::U256 => SuiMoveNormalizedType::U256, - NormalizedType::Address => SuiMoveNormalizedType::Address, - NormalizedType::Signer => SuiMoveNormalizedType::Signer, - NormalizedType::Struct { - address, - module, - name, - type_arguments, - } => SuiMoveNormalizedType::Struct { - address: address.to_hex_literal(), - module: module.to_string(), - name: name.to_string(), - type_arguments: type_arguments - .into_iter() - .map(SuiMoveNormalizedType::from) - .collect::>(), - }, - NormalizedType::Vector(v) => { - SuiMoveNormalizedType::Vector(Box::new(SuiMoveNormalizedType::from(*v))) - } - NormalizedType::TypeParameter(t) => SuiMoveNormalizedType::TypeParameter(t), - NormalizedType::Reference(r) => { - SuiMoveNormalizedType::Reference(Box::new(SuiMoveNormalizedType::from(*r))) - } - NormalizedType::MutableReference(mr) => { - SuiMoveNormalizedType::MutableReference(Box::new(SuiMoveNormalizedType::from(*mr))) - } - } - } -} - -impl From for SuiMoveAbilitySet { - fn from(set: AbilitySet) -> SuiMoveAbilitySet { - Self { - abilities: set - .into_iter() - .map(|a| match a { - Ability::Copy => SuiMoveAbility::Copy, - Ability::Drop => SuiMoveAbility::Drop, - Ability::Key => SuiMoveAbility::Key, - Ability::Store => SuiMoveAbility::Store, - }) - .collect::>(), - } - } -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -pub enum ObjectValueKind { - ByImmutableReference, - ByMutableReference, - ByValue, -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -pub enum MoveFunctionArgType { - Pure, - Object(ObjectValueKind), -} - -#[serde_as] -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq, EnumVariantOrder)] -#[serde(untagged, rename = "MoveValue")] -pub enum SuiMoveValue { - // u64 and u128 are converted to String to avoid overflow - Number(u32), - Bool(bool), - Address(SuiAddress), - Vector(Vec), - String(String), - UID { id: ObjectID }, - Struct(SuiMoveStruct), - Option(Box>), -} - -impl SuiMoveValue { - /// Extract values from MoveValue without type information in json format - pub fn to_json_value(self) -> Value { - match self { - SuiMoveValue::Struct(move_struct) => move_struct.to_json_value(), - SuiMoveValue::Vector(values) => SuiMoveStruct::Runtime(values).to_json_value(), - SuiMoveValue::Number(v) => json!(v), - SuiMoveValue::Bool(v) => json!(v), - SuiMoveValue::Address(v) => json!(v), - SuiMoveValue::String(v) => json!(v), - SuiMoveValue::UID { id } => json!({ "id": id }), - SuiMoveValue::Option(v) => json!(v), - } - } -} - -impl Display for SuiMoveValue { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let mut writer = String::new(); - match self { - SuiMoveValue::Number(value) => write!(writer, "{}", value)?, - SuiMoveValue::Bool(value) => write!(writer, "{}", value)?, - SuiMoveValue::Address(value) => write!(writer, "{}", value)?, - SuiMoveValue::String(value) => write!(writer, "{}", value)?, - SuiMoveValue::UID { id } => write!(writer, "{id}")?, - SuiMoveValue::Struct(value) => write!(writer, "{}", value)?, - SuiMoveValue::Option(value) => write!(writer, "{:?}", value)?, - SuiMoveValue::Vector(vec) => { - write!( - writer, - "{}", - vec.iter().map(|value| format!("{value}")).join(",\n") - )?; - } - } - write!(f, "{}", writer.trim_end_matches('\n')) - } -} - -impl From for SuiMoveValue { - fn from(value: MoveValue) -> Self { - match value { - MoveValue::U8(value) => SuiMoveValue::Number(value.into()), - MoveValue::U16(value) => SuiMoveValue::Number(value.into()), - MoveValue::U32(value) => SuiMoveValue::Number(value), - MoveValue::U64(value) => SuiMoveValue::String(format!("{value}")), - MoveValue::U128(value) => SuiMoveValue::String(format!("{value}")), - MoveValue::U256(value) => SuiMoveValue::String(format!("{value}")), - MoveValue::Bool(value) => SuiMoveValue::Bool(value), - MoveValue::Vector(values) => { - SuiMoveValue::Vector(values.into_iter().map(|value| value.into()).collect()) - } - MoveValue::Struct(value) => { - // Best effort Sui core type conversion - let MoveStruct { type_, fields } = &value; - if let Some(value) = try_convert_type(type_, fields) { - return value; - } - SuiMoveValue::Struct(value.into()) - } - MoveValue::Signer(value) | MoveValue::Address(value) => { - SuiMoveValue::Address(SuiAddress::from(ObjectID::from(value))) - } - } - } -} - -fn to_bytearray(value: &[MoveValue]) -> Option> { - if value.iter().all(|value| matches!(value, MoveValue::U8(_))) { - let bytearray = value - .iter() - .flat_map(|value| { - if let MoveValue::U8(u8) = value { - Some(*u8) - } else { - None - } - }) - .collect::>(); - Some(bytearray) - } else { - None - } -} - -#[serde_as] -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq, EnumVariantOrder)] -#[serde(untagged, rename = "MoveStruct")] -pub enum SuiMoveStruct { - Runtime(Vec), - WithTypes { - #[schemars(with = "String")] - #[serde(rename = "type")] - #[serde_as(as = "SuiStructTag")] - type_: StructTag, - fields: BTreeMap, - }, - WithFields(BTreeMap), -} - -impl SuiMoveStruct { - /// Extract values from MoveStruct without type information in json format - pub fn to_json_value(self) -> Value { - // Unwrap MoveStructs - match self { - SuiMoveStruct::Runtime(values) => { - let values = values - .into_iter() - .map(|value| value.to_json_value()) - .collect::>(); - json!(values) - } - // We only care about values here, assuming struct type information is known at the - // client side. - SuiMoveStruct::WithTypes { type_: _, fields } | SuiMoveStruct::WithFields(fields) => { - let fields = fields - .into_iter() - .map(|(key, value)| (key, value.to_json_value())) - .collect::>(); - json!(fields) - } - } - } - - pub fn read_dynamic_field_value(&self, field_name: &str) -> Option { - match self { - SuiMoveStruct::WithFields(fields) => fields.get(field_name).cloned(), - SuiMoveStruct::WithTypes { type_: _, fields } => fields.get(field_name).cloned(), - _ => None, - } - } -} - -impl Display for SuiMoveStruct { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let mut writer = String::new(); - match self { - SuiMoveStruct::Runtime(_) => {} - SuiMoveStruct::WithFields(fields) => { - for (name, value) in fields { - writeln!(writer, "{}: {value}", name.bold().bright_black())?; - } - } - SuiMoveStruct::WithTypes { type_, fields } => { - writeln!(writer)?; - writeln!(writer, " {}: {type_}", "type".bold().bright_black())?; - for (name, value) in fields { - let value = format!("{}", value); - let value = if value.starts_with('\n') { - indent(&value, 2) - } else { - value - }; - writeln!(writer, " {}: {value}", name.bold().bright_black())?; - } - } - } - write!(f, "{}", writer.trim_end_matches('\n')) - } -} - -fn indent(d: &T, indent: usize) -> String { - d.to_string() - .lines() - .map(|line| format!("{:indent$}{}", "", line)) - .join("\n") -} - -fn try_convert_type(type_: &StructTag, fields: &[(Identifier, MoveValue)]) -> Option { - let struct_name = format!( - "0x{}::{}::{}", - type_.address.short_str_lossless(), - type_.module, - type_.name - ); - let mut values = fields - .iter() - .map(|(id, value)| (id.to_string(), value)) - .collect::>(); - match struct_name.as_str() { - "0x1::string::String" | "0x1::ascii::String" => { - if let Some(MoveValue::Vector(bytes)) = values.remove("bytes") { - return to_bytearray(bytes) - .and_then(|bytes| String::from_utf8(bytes).ok()) - .map(SuiMoveValue::String); - } - } - "0x2::url::Url" => { - return values.remove("url").cloned().map(SuiMoveValue::from); - } - "0x2::object::ID" => { - return values.remove("bytes").cloned().map(SuiMoveValue::from); - } - "0x2::object::UID" => { - let id = values.remove("id").cloned().map(SuiMoveValue::from); - if let Some(SuiMoveValue::Address(address)) = id { - return Some(SuiMoveValue::UID { - id: ObjectID::from(address), - }); - } - } - "0x2::balance::Balance" => { - return values.remove("value").cloned().map(SuiMoveValue::from); - } - "0x1::option::Option" => { - if let Some(MoveValue::Vector(values)) = values.remove("vec") { - return Some(SuiMoveValue::Option(Box::new( - // in Move option is modeled as vec of 1 element - values.first().cloned().map(SuiMoveValue::from), - ))); - } - } - _ => return None, - } - warn!( - fields =? fields, - "Failed to convert {struct_name} to SuiMoveValue" - ); - None -} - -impl From for SuiMoveStruct { - fn from(move_struct: MoveStruct) -> Self { - SuiMoveStruct::WithTypes { - type_: move_struct.type_, - fields: move_struct - .fields - .into_iter() - .map(|(id, value)| (id.into_string(), value.into())) - .collect(), - } - } -} diff --git a/crates/sui-json-rpc-types/src/sui_object.rs b/crates/sui-json-rpc-types/src/sui_object.rs deleted file mode 100644 index 0c9f6485dba..00000000000 --- a/crates/sui-json-rpc-types/src/sui_object.rs +++ /dev/null @@ -1,1259 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - cmp::Ordering, - collections::BTreeMap, - fmt, - fmt::{Display, Formatter, Write}, -}; - -use anyhow::anyhow; -use colored::Colorize; -use fastcrypto::encoding::Base64; -use move_bytecode_utils::module_cache::GetModule; -use move_core_types::{ - annotated_value::{MoveStruct, MoveStructLayout}, - identifier::Identifier, - language_storage::StructTag, -}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use serde_with::{serde_as, DisplayFromStr}; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ - base_types::{ - ObjectDigest, ObjectID, ObjectInfo, ObjectRef, ObjectType, SequenceNumber, SuiAddress, - TransactionDigest, - }, - error::{ExecutionError, SuiObjectResponseError, UserInputError, UserInputResult}, - gas_coin::GasCoin, - messages_checkpoint::CheckpointSequenceNumber, - move_package::{MovePackage, TypeOrigin, UpgradeInfo}, - object::{Data, MoveObject, Object, ObjectInner, ObjectRead, Owner}, - sui_serde::{BigInt, SequenceNumber as AsSequenceNumber, SuiStructTag}, -}; - -use crate::{Page, SuiMoveStruct, SuiMoveValue}; - -#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone, PartialEq, Eq)] -pub struct SuiObjectResponse { - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub error: Option, -} - -impl SuiObjectResponse { - pub fn new(data: Option, error: Option) -> Self { - Self { data, error } - } - - pub fn new_with_data(data: SuiObjectData) -> Self { - Self { - data: Some(data), - error: None, - } - } - - pub fn new_with_error(error: SuiObjectResponseError) -> Self { - Self { - data: None, - error: Some(error), - } - } -} - -impl Ord for SuiObjectResponse { - fn cmp(&self, other: &Self) -> Ordering { - match (&self.data, &other.data) { - (Some(data), Some(data_2)) => { - if data.object_id.cmp(&data_2.object_id).eq(&Ordering::Greater) { - return Ordering::Greater; - } else if data.object_id.cmp(&data_2.object_id).eq(&Ordering::Less) { - return Ordering::Less; - } - Ordering::Equal - } - // In this ordering those with data will come before SuiObjectResponses that are errors. - (Some(_), None) => Ordering::Less, - (None, Some(_)) => Ordering::Greater, - // SuiObjectResponses that are errors are just considered equal. - _ => Ordering::Equal, - } - } -} - -impl PartialOrd for SuiObjectResponse { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl SuiObjectResponse { - pub fn move_object_bcs(&self) -> Option<&Vec> { - match &self.data { - Some(SuiObjectData { - bcs: Some(SuiRawData::MoveObject(obj)), - .. - }) => Some(&obj.bcs_bytes), - _ => None, - } - } - - pub fn owner(&self) -> Option { - if let Some(data) = &self.data { - return data.owner; - } - None - } - - pub fn object_id(&self) -> Result { - match (&self.data, &self.error) { - (Some(obj_data), None) => Ok(obj_data.object_id), - (None, Some(SuiObjectResponseError::NotExists { object_id })) => Ok(*object_id), - ( - None, - Some(SuiObjectResponseError::Deleted { - object_id, - version: _, - digest: _, - }), - ) => Ok(*object_id), - _ => Err(anyhow!( - "Could not get object_id, something went wrong with SuiObjectResponse construction." - )), - } - } - - pub fn object_ref_if_exists(&self) -> Option { - match (&self.data, &self.error) { - (Some(obj_data), None) => Some(obj_data.object_ref()), - _ => None, - } - } -} - -impl TryFrom for ObjectInfo { - type Error = anyhow::Error; - - fn try_from(value: SuiObjectResponse) -> Result { - let SuiObjectData { - object_id, - version, - digest, - type_, - owner, - previous_transaction, - .. - } = value.into_object()?; - - Ok(ObjectInfo { - object_id, - version, - digest, - type_: type_.ok_or_else(|| anyhow!("Object type not found for object."))?, - owner: owner.ok_or_else(|| anyhow!("Owner not found for object."))?, - previous_transaction: previous_transaction - .ok_or_else(|| anyhow!("Transaction digest not found for object."))?, - }) - } -} - -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, Eq, PartialEq)] -pub struct DisplayFieldsResponse { - pub data: Option>, - pub error: Option, -} - -#[serde_as] -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, Eq, PartialEq)] -#[serde(rename_all = "camelCase", rename = "ObjectData")] -pub struct SuiObjectData { - pub object_id: ObjectID, - /// Object version. - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - pub version: SequenceNumber, - /// Base64 string representing the object digest - pub digest: ObjectDigest, - /// The type of the object. Default to be None unless - /// SuiObjectDataOptions.showType is set to true - #[schemars(with = "Option")] - #[serde_as(as = "Option")] - #[serde(rename = "type", skip_serializing_if = "Option::is_none")] - pub type_: Option, - // Default to be None because otherwise it will be repeated for the getOwnedObjects endpoint - /// The owner of this object. Default to be None unless - /// SuiObjectDataOptions.showOwner is set to true - #[serde(skip_serializing_if = "Option::is_none")] - pub owner: Option, - /// The digest of the transaction that created or last mutated this object. - /// Default to be None unless SuiObjectDataOptions. - /// showPreviousTransaction is set to true - #[serde(skip_serializing_if = "Option::is_none")] - pub previous_transaction: Option, - /// The amount of SUI we would rebate if this object gets deleted. - /// This number is re-calculated each time the object is mutated based on - /// the present storage gas price. - #[schemars(with = "Option>")] - #[serde_as(as = "Option>")] - #[serde(skip_serializing_if = "Option::is_none")] - pub storage_rebate: Option, - /// The Display metadata for frontend UI rendering, default to be None - /// unless SuiObjectDataOptions.showContent is set to true This can also - /// be None if the struct type does not have Display defined See more details in - #[serde(skip_serializing_if = "Option::is_none")] - pub display: Option, - /// Move object content or package content, default to be None unless - /// SuiObjectDataOptions.showContent is set to true - #[serde(skip_serializing_if = "Option::is_none")] - pub content: Option, - /// Move object content or package content in BCS, default to be None unless - /// SuiObjectDataOptions.showBcs is set to true - #[serde(skip_serializing_if = "Option::is_none")] - pub bcs: Option, -} - -impl SuiObjectData { - pub fn object_ref(&self) -> ObjectRef { - (self.object_id, self.version, self.digest) - } - - pub fn object_type(&self) -> anyhow::Result { - self.type_ - .as_ref() - .ok_or_else(|| anyhow!("type is missing for object {:?}", self.object_id)) - .cloned() - } - - pub fn is_gas_coin(&self) -> bool { - match self.type_.as_ref() { - Some(ObjectType::Struct(ty)) if ty.is_gas_coin() => true, - Some(_) => false, - None => false, - } - } -} - -impl Display for SuiObjectData { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let type_ = if let Some(type_) = &self.type_ { - type_.to_string() - } else { - "Unknown Type".into() - }; - let mut writer = String::new(); - writeln!( - writer, - "{}", - format!("----- {type_} ({}[{}]) -----", self.object_id, self.version).bold() - )?; - if let Some(owner) = self.owner { - writeln!(writer, "{}: {}", "Owner".bold().bright_black(), owner)?; - } - - writeln!( - writer, - "{}: {}", - "Version".bold().bright_black(), - self.version - )?; - if let Some(storage_rebate) = self.storage_rebate { - writeln!( - writer, - "{}: {}", - "Storage Rebate".bold().bright_black(), - storage_rebate - )?; - } - - if let Some(previous_transaction) = self.previous_transaction { - writeln!( - writer, - "{}: {:?}", - "Previous Transaction".bold().bright_black(), - previous_transaction - )?; - } - if let Some(content) = self.content.as_ref() { - writeln!(writer, "{}", "----- Data -----".bold())?; - write!(writer, "{}", content)?; - } - - write!(f, "{}", writer) - } -} - -impl TryFrom<&SuiObjectData> for GasCoin { - type Error = anyhow::Error; - fn try_from(object: &SuiObjectData) -> Result { - match &object - .content - .as_ref() - .ok_or_else(|| anyhow!("Expect object content to not be empty"))? - { - SuiParsedData::MoveObject(o) => { - if GasCoin::type_() == o.type_ { - return GasCoin::try_from(&o.fields); - } - } - SuiParsedData::Package(_) => {} - } - - Err(anyhow!( - "Gas object type is not a gas coin: {:?}", - object.type_ - )) - } -} - -impl TryFrom<&SuiMoveStruct> for GasCoin { - type Error = anyhow::Error; - fn try_from(move_struct: &SuiMoveStruct) -> Result { - match move_struct { - SuiMoveStruct::WithFields(fields) | SuiMoveStruct::WithTypes { type_: _, fields } => { - if let Some(SuiMoveValue::String(balance)) = fields.get("balance") { - if let Ok(balance) = balance.parse::() { - if let Some(SuiMoveValue::UID { id }) = fields.get("id") { - return Ok(GasCoin::new(*id, balance)); - } - } - } - } - _ => {} - } - Err(anyhow!("Struct is not a gas coin: {move_struct:?}")) - } -} - -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, Eq, PartialEq, Default)] -#[serde(rename_all = "camelCase", rename = "ObjectDataOptions", default)] -pub struct SuiObjectDataOptions { - /// Whether to show the type of the object. Default to be False - pub show_type: bool, - /// Whether to show the owner of the object. Default to be False - pub show_owner: bool, - /// Whether to show the previous transaction digest of the object. Default - /// to be False - pub show_previous_transaction: bool, - /// Whether to show the Display metadata of the object for frontend - /// rendering. Default to be False - pub show_display: bool, - /// Whether to show the content(i.e., package content or Move struct - /// content) of the object. Default to be False - pub show_content: bool, - /// Whether to show the content in BCS format. Default to be False - pub show_bcs: bool, - /// Whether to show the storage rebate of the object. Default to be False - pub show_storage_rebate: bool, -} - -impl SuiObjectDataOptions { - pub fn new() -> Self { - Self::default() - } - - /// return BCS data and all other metadata such as storage rebate - pub fn bcs_lossless() -> Self { - Self { - show_bcs: true, - show_type: true, - show_owner: true, - show_previous_transaction: true, - show_display: false, - show_content: false, - show_storage_rebate: true, - } - } - - /// return full content except bcs - pub fn full_content() -> Self { - Self { - show_bcs: false, - show_type: true, - show_owner: true, - show_previous_transaction: true, - show_display: false, - show_content: true, - show_storage_rebate: true, - } - } - - pub fn with_content(mut self) -> Self { - self.show_content = true; - self - } - - pub fn with_owner(mut self) -> Self { - self.show_owner = true; - self - } - - pub fn with_type(mut self) -> Self { - self.show_type = true; - self - } - - pub fn with_display(mut self) -> Self { - self.show_display = true; - self - } - - pub fn with_bcs(mut self) -> Self { - self.show_bcs = true; - self - } - - pub fn with_previous_transaction(mut self) -> Self { - self.show_previous_transaction = true; - self - } - - pub fn is_not_in_object_info(&self) -> bool { - self.show_bcs || self.show_content || self.show_display || self.show_storage_rebate - } -} - -impl TryFrom<(ObjectRead, SuiObjectDataOptions)> for SuiObjectResponse { - type Error = anyhow::Error; - - fn try_from( - (object_read, options): (ObjectRead, SuiObjectDataOptions), - ) -> Result { - match object_read { - ObjectRead::NotExists(id) => Ok(SuiObjectResponse::new_with_error( - SuiObjectResponseError::NotExists { object_id: id }, - )), - ObjectRead::Exists(object_ref, o, layout) => { - let data = (object_ref, o, layout, options).try_into()?; - Ok(SuiObjectResponse::new_with_data(data)) - } - ObjectRead::Deleted((object_id, version, digest)) => Ok( - SuiObjectResponse::new_with_error(SuiObjectResponseError::Deleted { - object_id, - version, - digest, - }), - ), - } - } -} - -impl TryFrom<(ObjectInfo, SuiObjectDataOptions)> for SuiObjectResponse { - type Error = anyhow::Error; - - fn try_from( - (object_info, options): (ObjectInfo, SuiObjectDataOptions), - ) -> Result { - let SuiObjectDataOptions { - show_type, - show_owner, - show_previous_transaction, - .. - } = options; - - Ok(Self::new_with_data(SuiObjectData { - object_id: object_info.object_id, - version: object_info.version, - digest: object_info.digest, - type_: show_type.then_some(object_info.type_), - owner: show_owner.then_some(object_info.owner), - previous_transaction: show_previous_transaction - .then_some(object_info.previous_transaction), - storage_rebate: None, - display: None, - content: None, - bcs: None, - })) - } -} - -impl - TryFrom<( - ObjectRef, - Object, - Option, - SuiObjectDataOptions, - )> for SuiObjectData -{ - type Error = anyhow::Error; - - fn try_from( - (object_ref, o, layout, options): ( - ObjectRef, - Object, - Option, - SuiObjectDataOptions, - ), - ) -> Result { - let SuiObjectDataOptions { - show_type, - show_owner, - show_previous_transaction, - show_content, - show_bcs, - show_storage_rebate, - .. - } = options; - - let (object_id, version, digest) = object_ref; - let type_ = if show_type { - Some(Into::::into(&o)) - } else { - None - }; - - let bcs: Option = if show_bcs { - let data = match o.data.clone() { - Data::Move(m) => { - let layout = layout.clone().ok_or_else(|| { - anyhow!("Layout is required to convert Move object to json") - })?; - SuiRawData::try_from_object(m, layout)? - } - Data::Package(p) => SuiRawData::try_from_package(p) - .map_err(|e| anyhow!("Error getting raw data from package: {e:#?}"))?, - }; - Some(data) - } else { - None - }; - - let o = o.into_inner(); - - let content: Option = if show_content { - let data = match o.data { - Data::Move(m) => { - let layout = layout.ok_or_else(|| { - anyhow!("Layout is required to convert Move object to json") - })?; - SuiParsedData::try_from_object(m, layout)? - } - Data::Package(p) => SuiParsedData::try_from_package(p)?, - }; - Some(data) - } else { - None - }; - - Ok(SuiObjectData { - object_id, - version, - digest, - type_, - owner: if show_owner { Some(o.owner) } else { None }, - storage_rebate: if show_storage_rebate { - Some(o.storage_rebate) - } else { - None - }, - previous_transaction: if show_previous_transaction { - Some(o.previous_transaction) - } else { - None - }, - content, - bcs, - display: None, - }) - } -} - -impl - TryFrom<( - ObjectRef, - Object, - Option, - SuiObjectDataOptions, - Option, - )> for SuiObjectData -{ - type Error = anyhow::Error; - - fn try_from( - (object_ref, o, layout, options, display_fields): ( - ObjectRef, - Object, - Option, - SuiObjectDataOptions, - Option, - ), - ) -> Result { - let show_display = options.show_display; - let mut data: SuiObjectData = (object_ref, o, layout, options).try_into()?; - if show_display { - data.display = display_fields; - } - Ok(data) - } -} - -impl SuiObjectResponse { - /// Returns a reference to the object if there is any, otherwise an Err if - /// the object does not exist or is deleted. - pub fn object(&self) -> Result<&SuiObjectData, SuiObjectResponseError> { - if let Some(data) = &self.data { - Ok(data) - } else if let Some(error) = &self.error { - Err(error.clone()) - } else { - // We really shouldn't reach this code block since either data, or error field - // should always be filled. - Err(SuiObjectResponseError::Unknown) - } - } - - /// Returns the object value if there is any, otherwise an Err if - /// the object does not exist or is deleted. - pub fn into_object(self) -> Result { - match self.object() { - Ok(data) => Ok(data.clone()), - Err(error) => Err(error), - } - } -} - -impl TryInto for SuiObjectData { - type Error = anyhow::Error; - - fn try_into(self) -> Result { - let protocol_config = ProtocolConfig::get_for_min_version(); - let data = match self.bcs { - Some(SuiRawData::MoveObject(o)) => Data::Move(unsafe { - MoveObject::new_from_execution( - o.type_().clone().into(), - o.has_public_transfer, - o.version, - o.bcs_bytes, - &protocol_config, - )? - }), - Some(SuiRawData::Package(p)) => Data::Package(MovePackage::new( - p.id, - self.version, - p.module_map, - protocol_config.max_move_package_size(), - p.type_origin_table, - p.linkage_table, - )?), - _ => Err(anyhow!( - "BCS data is required to convert SuiObjectData to Object" - ))?, - }; - Ok(ObjectInner { - data, - owner: self - .owner - .ok_or_else(|| anyhow!("Owner is required to convert SuiObjectData to Object"))?, - previous_transaction: self.previous_transaction.ok_or_else(|| { - anyhow!("previous_transaction is required to convert SuiObjectData to Object") - })?, - storage_rebate: self.storage_rebate.ok_or_else(|| { - anyhow!("storage_rebate is required to convert SuiObjectData to Object") - })?, - } - .into()) - } -} - -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, Eq, PartialEq, Ord, PartialOrd)] -#[serde(rename_all = "camelCase", rename = "ObjectRef")] -pub struct SuiObjectRef { - /// Hex code as string representing the object id - pub object_id: ObjectID, - /// Object version. - pub version: SequenceNumber, - /// Base64 string representing the object digest - pub digest: ObjectDigest, -} - -impl SuiObjectRef { - pub fn to_object_ref(&self) -> ObjectRef { - (self.object_id, self.version, self.digest) - } -} - -impl Display for SuiObjectRef { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!( - f, - "Object ID: {}, version: {}, digest: {}", - self.object_id, self.version, self.digest - ) - } -} - -impl From for SuiObjectRef { - fn from(oref: ObjectRef) -> Self { - Self { - object_id: oref.0, - version: oref.1, - digest: oref.2, - } - } -} - -pub trait SuiData: Sized { - type ObjectType; - type PackageType; - fn try_from_object(object: MoveObject, layout: MoveStructLayout) - -> Result; - fn try_from_package(package: MovePackage) -> Result; - fn try_as_move(&self) -> Option<&Self::ObjectType>; - fn try_into_move(self) -> Option; - fn try_as_package(&self) -> Option<&Self::PackageType>; - fn type_(&self) -> Option<&StructTag>; -} - -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)] -#[serde(tag = "dataType", rename_all = "camelCase", rename = "RawData")] -pub enum SuiRawData { - // Manually handle generic schema generation - MoveObject(SuiRawMoveObject), - Package(SuiRawMovePackage), -} - -impl SuiData for SuiRawData { - type ObjectType = SuiRawMoveObject; - type PackageType = SuiRawMovePackage; - - fn try_from_object(object: MoveObject, _: MoveStructLayout) -> Result { - Ok(Self::MoveObject(object.into())) - } - - fn try_from_package(package: MovePackage) -> Result { - Ok(Self::Package(package.into())) - } - - fn try_as_move(&self) -> Option<&Self::ObjectType> { - match self { - Self::MoveObject(o) => Some(o), - Self::Package(_) => None, - } - } - - fn try_into_move(self) -> Option { - match self { - Self::MoveObject(o) => Some(o), - Self::Package(_) => None, - } - } - - fn try_as_package(&self) -> Option<&Self::PackageType> { - match self { - Self::MoveObject(_) => None, - Self::Package(p) => Some(p), - } - } - - fn type_(&self) -> Option<&StructTag> { - match self { - Self::MoveObject(o) => Some(&o.type_), - Self::Package(_) => None, - } - } -} - -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)] -#[serde(tag = "dataType", rename_all = "camelCase", rename = "Data")] -pub enum SuiParsedData { - // Manually handle generic schema generation - MoveObject(SuiParsedMoveObject), - Package(SuiMovePackage), -} - -impl SuiData for SuiParsedData { - type ObjectType = SuiParsedMoveObject; - type PackageType = SuiMovePackage; - - fn try_from_object( - object: MoveObject, - layout: MoveStructLayout, - ) -> Result { - Ok(Self::MoveObject(SuiParsedMoveObject::try_from_layout( - object, layout, - )?)) - } - - fn try_from_package(package: MovePackage) -> Result { - Ok(Self::Package(SuiMovePackage { - disassembled: package.disassemble()?, - })) - } - - fn try_as_move(&self) -> Option<&Self::ObjectType> { - match self { - Self::MoveObject(o) => Some(o), - Self::Package(_) => None, - } - } - - fn try_into_move(self) -> Option { - match self { - Self::MoveObject(o) => Some(o), - Self::Package(_) => None, - } - } - - fn try_as_package(&self) -> Option<&Self::PackageType> { - match self { - Self::MoveObject(_) => None, - Self::Package(p) => Some(p), - } - } - - fn type_(&self) -> Option<&StructTag> { - match self { - Self::MoveObject(o) => Some(&o.type_), - Self::Package(_) => None, - } - } -} - -impl Display for SuiParsedData { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let mut writer = String::new(); - match self { - SuiParsedData::MoveObject(o) => { - writeln!(writer, "{}: {}", "type".bold().bright_black(), o.type_)?; - write!(writer, "{}", &o.fields)?; - } - SuiParsedData::Package(p) => { - write!( - writer, - "{}: {:?}", - "Modules".bold().bright_black(), - p.disassembled.keys() - )?; - } - } - write!(f, "{}", writer) - } -} - -impl SuiParsedData { - pub fn try_from_object_read(object_read: ObjectRead) -> Result { - match object_read { - ObjectRead::NotExists(id) => Err(anyhow::anyhow!("Object {} does not exist", id)), - ObjectRead::Exists(_object_ref, o, layout) => { - let data = match o.into_inner().data { - Data::Move(m) => { - let layout = layout.ok_or_else(|| { - anyhow!("Layout is required to convert Move object to json") - })?; - SuiParsedData::try_from_object(m, layout)? - } - Data::Package(p) => SuiParsedData::try_from_package(p)?, - }; - Ok(data) - } - ObjectRead::Deleted((object_id, version, digest)) => Err(anyhow::anyhow!( - "Object {} was deleted at version {} with digest {}", - object_id, - version, - digest - )), - } - } -} - -pub trait SuiMoveObject: Sized { - fn try_from_layout(object: MoveObject, layout: MoveStructLayout) - -> Result; - - fn try_from(o: MoveObject, resolver: &impl GetModule) -> Result { - let layout = o.get_layout(resolver)?; - Self::try_from_layout(o, layout) - } - - fn type_(&self) -> &StructTag; -} - -#[serde_as] -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)] -#[serde(rename = "MoveObject", rename_all = "camelCase")] -pub struct SuiParsedMoveObject { - #[serde(rename = "type")] - #[serde_as(as = "SuiStructTag")] - #[schemars(with = "String")] - pub type_: StructTag, - pub has_public_transfer: bool, - pub fields: SuiMoveStruct, -} - -impl SuiMoveObject for SuiParsedMoveObject { - fn try_from_layout( - object: MoveObject, - layout: MoveStructLayout, - ) -> Result { - let move_struct = object.to_move_struct(&layout)?.into(); - - Ok( - if let SuiMoveStruct::WithTypes { type_, fields } = move_struct { - SuiParsedMoveObject { - type_, - has_public_transfer: object.has_public_transfer(), - fields: SuiMoveStruct::WithFields(fields), - } - } else { - SuiParsedMoveObject { - type_: object.type_().clone().into(), - has_public_transfer: object.has_public_transfer(), - fields: move_struct, - } - }, - ) - } - - fn type_(&self) -> &StructTag { - &self.type_ - } -} - -impl SuiParsedMoveObject { - pub fn try_from_object_read(object_read: ObjectRead) -> Result { - let parsed_data = SuiParsedData::try_from_object_read(object_read)?; - match parsed_data { - SuiParsedData::MoveObject(o) => Ok(o), - SuiParsedData::Package(_) => Err(anyhow::anyhow!("Object is not a Move object")), - } - } - - pub fn read_dynamic_field_value(&self, field_name: &str) -> Option { - match &self.fields { - SuiMoveStruct::WithFields(fields) => fields.get(field_name).cloned(), - SuiMoveStruct::WithTypes { fields, .. } => fields.get(field_name).cloned(), - _ => None, - } - } -} - -pub fn type_and_fields_from_move_struct( - type_: &StructTag, - move_struct: MoveStruct, -) -> (StructTag, SuiMoveStruct) { - match move_struct.into() { - SuiMoveStruct::WithTypes { type_, fields } => (type_, SuiMoveStruct::WithFields(fields)), - fields => (type_.clone(), fields), - } -} - -#[serde_as] -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)] -#[serde(rename = "RawMoveObject", rename_all = "camelCase")] -pub struct SuiRawMoveObject { - #[schemars(with = "String")] - #[serde(rename = "type")] - #[serde_as(as = "SuiStructTag")] - pub type_: StructTag, - pub has_public_transfer: bool, - pub version: SequenceNumber, - #[serde_as(as = "Base64")] - #[schemars(with = "Base64")] - pub bcs_bytes: Vec, -} - -impl From for SuiRawMoveObject { - fn from(o: MoveObject) -> Self { - Self { - type_: o.type_().clone().into(), - has_public_transfer: o.has_public_transfer(), - version: o.version(), - bcs_bytes: o.into_contents(), - } - } -} - -impl SuiMoveObject for SuiRawMoveObject { - fn try_from_layout( - object: MoveObject, - _layout: MoveStructLayout, - ) -> Result { - Ok(Self { - type_: object.type_().clone().into(), - has_public_transfer: object.has_public_transfer(), - version: object.version(), - bcs_bytes: object.into_contents(), - }) - } - - fn type_(&self) -> &StructTag { - &self.type_ - } -} - -impl SuiRawMoveObject { - pub fn deserialize<'a, T: Deserialize<'a>>(&'a self) -> Result { - Ok(bcs::from_bytes(self.bcs_bytes.as_slice())?) - } -} - -#[serde_as] -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)] -#[serde(rename = "RawMovePackage", rename_all = "camelCase")] -pub struct SuiRawMovePackage { - pub id: ObjectID, - pub version: SequenceNumber, - #[schemars(with = "BTreeMap")] - #[serde_as(as = "BTreeMap<_, Base64>")] - pub module_map: BTreeMap>, - pub type_origin_table: Vec, - pub linkage_table: BTreeMap, -} - -impl From for SuiRawMovePackage { - fn from(p: MovePackage) -> Self { - Self { - id: p.id(), - version: p.version(), - module_map: p.serialized_module_map().clone(), - type_origin_table: p.type_origin_table().clone(), - linkage_table: p.linkage_table().clone(), - } - } -} - -impl SuiRawMovePackage { - pub fn to_move_package( - &self, - max_move_package_size: u64, - ) -> Result { - MovePackage::new( - self.id, - self.version, - self.module_map.clone(), - max_move_package_size, - self.type_origin_table.clone(), - self.linkage_table.clone(), - ) - } -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone, PartialEq, Eq)] -#[serde(tag = "status", content = "details", rename = "ObjectRead")] -pub enum SuiPastObjectResponse { - /// The object exists and is found with this version - VersionFound(SuiObjectData), - /// The object does not exist - ObjectNotExists(ObjectID), - /// The object is found to be deleted with this version - ObjectDeleted(SuiObjectRef), - /// The object exists but not found with this version - VersionNotFound(ObjectID, SequenceNumber), - /// The asked object version is higher than the latest - VersionTooHigh { - object_id: ObjectID, - asked_version: SequenceNumber, - latest_version: SequenceNumber, - }, -} - -impl SuiPastObjectResponse { - /// Returns a reference to the object if there is any, otherwise an Err - pub fn object(&self) -> UserInputResult<&SuiObjectData> { - match &self { - Self::ObjectDeleted(oref) => Err(UserInputError::ObjectDeleted { - object_ref: oref.to_object_ref(), - }), - Self::ObjectNotExists(id) => Err(UserInputError::ObjectNotFound { - object_id: *id, - version: None, - }), - Self::VersionFound(o) => Ok(o), - Self::VersionNotFound(id, seq_num) => Err(UserInputError::ObjectNotFound { - object_id: *id, - version: Some(*seq_num), - }), - Self::VersionTooHigh { - object_id, - asked_version, - latest_version, - } => Err(UserInputError::ObjectSequenceNumberTooHigh { - object_id: *object_id, - asked_version: *asked_version, - latest_version: *latest_version, - }), - } - } - - /// Returns the object value if there is any, otherwise an Err - pub fn into_object(self) -> UserInputResult { - match self { - Self::ObjectDeleted(oref) => Err(UserInputError::ObjectDeleted { - object_ref: oref.to_object_ref(), - }), - Self::ObjectNotExists(id) => Err(UserInputError::ObjectNotFound { - object_id: id, - version: None, - }), - Self::VersionFound(o) => Ok(o), - Self::VersionNotFound(object_id, version) => Err(UserInputError::ObjectNotFound { - object_id, - version: Some(version), - }), - Self::VersionTooHigh { - object_id, - asked_version, - latest_version, - } => Err(UserInputError::ObjectSequenceNumberTooHigh { - object_id, - asked_version, - latest_version, - }), - } - } -} - -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)] -#[serde(rename = "MovePackage", rename_all = "camelCase")] -pub struct SuiMovePackage { - pub disassembled: BTreeMap, -} - -pub type QueryObjectsPage = Page; -pub type ObjectsPage = Page; - -#[serde_as] -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Copy, Eq, PartialEq)] -#[serde(rename_all = "camelCase")] -pub struct CheckpointedObjectID { - pub object_id: ObjectID, - #[schemars(with = "Option>")] - #[serde_as(as = "Option>")] - #[serde(skip_serializing_if = "Option::is_none")] - pub at_checkpoint: Option, -} - -#[serde_as] -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, Eq, PartialEq)] -#[serde(rename = "GetPastObjectRequest", rename_all = "camelCase")] -pub struct SuiGetPastObjectRequest { - /// the ID of the queried object - pub object_id: ObjectID, - /// the version of the queried object. - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - pub version: SequenceNumber, -} - -#[serde_as] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub enum SuiObjectDataFilter { - MatchAll(Vec), - MatchAny(Vec), - MatchNone(Vec), - /// Query by type a specified Package. - Package(ObjectID), - /// Query by type a specified Move module. - MoveModule { - /// the Move package ID - package: ObjectID, - /// the module name - #[schemars(with = "String")] - #[serde_as(as = "DisplayFromStr")] - module: Identifier, - }, - /// Query by type - StructType( - #[schemars(with = "String")] - #[serde_as(as = "SuiStructTag")] - StructTag, - ), - AddressOwner(SuiAddress), - ObjectOwner(ObjectID), - ObjectId(ObjectID), - // allow querying for multiple object ids - ObjectIds(Vec), - Version( - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - u64, - ), -} - -impl SuiObjectDataFilter { - pub fn gas_coin() -> Self { - Self::StructType(GasCoin::type_()) - } - - pub fn and(self, other: Self) -> Self { - Self::MatchAll(vec![self, other]) - } - pub fn or(self, other: Self) -> Self { - Self::MatchAny(vec![self, other]) - } - pub fn not(self, other: Self) -> Self { - Self::MatchNone(vec![self, other]) - } - - pub fn matches(&self, object: &ObjectInfo) -> bool { - match self { - SuiObjectDataFilter::MatchAll(filters) => !filters.iter().any(|f| !f.matches(object)), - SuiObjectDataFilter::MatchAny(filters) => filters.iter().any(|f| f.matches(object)), - SuiObjectDataFilter::MatchNone(filters) => !filters.iter().any(|f| f.matches(object)), - SuiObjectDataFilter::StructType(s) => { - let obj_tag: StructTag = match &object.type_ { - ObjectType::Package => return false, - ObjectType::Struct(s) => s.clone().into(), - }; - // If people do not provide type_params, we will match all type_params - // e.g. `0x2::coin::Coin` can match `0x2::coin::Coin<0x2::sui::SUI>` - if !s.type_params.is_empty() && s.type_params != obj_tag.type_params { - false - } else { - obj_tag.address == s.address - && obj_tag.module == s.module - && obj_tag.name == s.name - } - } - SuiObjectDataFilter::MoveModule { package, module } => { - matches!(&object.type_, ObjectType::Struct(s) if &ObjectID::from(s.address()) == package - && s.module() == module.as_ident_str()) - } - SuiObjectDataFilter::Package(p) => { - matches!(&object.type_, ObjectType::Struct(s) if &ObjectID::from(s.address()) == p) - } - SuiObjectDataFilter::AddressOwner(a) => { - matches!(object.owner, Owner::AddressOwner(addr) if &addr == a) - } - SuiObjectDataFilter::ObjectOwner(o) => { - matches!(object.owner, Owner::ObjectOwner(addr) if addr == SuiAddress::from(*o)) - } - SuiObjectDataFilter::ObjectId(id) => &object.object_id == id, - SuiObjectDataFilter::ObjectIds(ids) => ids.contains(&object.object_id), - SuiObjectDataFilter::Version(v) => object.version.value() == *v, - } - } -} - -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, Default)] -#[serde(rename_all = "camelCase", rename = "ObjectResponseQuery", default)] -pub struct SuiObjectResponseQuery { - /// If None, no filter will be applied - pub filter: Option, - /// config which fields to include in the response, by default only digest - /// is included - pub options: Option, -} - -impl SuiObjectResponseQuery { - pub fn new(filter: Option, options: Option) -> Self { - Self { filter, options } - } - - pub fn new_with_filter(filter: SuiObjectDataFilter) -> Self { - Self { - filter: Some(filter), - options: None, - } - } - - pub fn new_with_options(options: SuiObjectDataOptions) -> Self { - Self { - filter: None, - options: Some(options), - } - } -} diff --git a/crates/sui-json-rpc-types/src/sui_protocol.rs b/crates/sui-json-rpc-types/src/sui_protocol.rs deleted file mode 100644 index 934d072f338..00000000000 --- a/crates/sui-json-rpc-types/src/sui_protocol.rs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_with::{serde_as, DisplayFromStr}; -use sui_protocol_config::{ProtocolConfig, ProtocolConfigValue, ProtocolVersion}; -use sui_types::sui_serde::{AsProtocolVersion, BigInt, Readable}; - -#[serde_as] -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, PartialEq)] -#[serde(rename_all = "camelCase", rename = "ProtocolConfigValue")] -pub enum SuiProtocolConfigValue { - U16( - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - u16, - ), - U32( - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - u32, - ), - U64( - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - u64, - ), - F64( - #[schemars(with = "String")] - #[serde_as(as = "DisplayFromStr")] - f64, - ), -} - -impl From for SuiProtocolConfigValue { - fn from(value: ProtocolConfigValue) -> Self { - match value { - ProtocolConfigValue::u16(y) => SuiProtocolConfigValue::U16(y), - ProtocolConfigValue::u32(y) => SuiProtocolConfigValue::U32(y), - ProtocolConfigValue::u64(x) => SuiProtocolConfigValue::U64(x), - ProtocolConfigValue::f64(z) => SuiProtocolConfigValue::F64(z), - } - } -} - -#[serde_as] -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, PartialEq)] -#[serde(rename_all = "camelCase", rename = "ProtocolConfig")] -pub struct ProtocolConfigResponse { - #[schemars(with = "AsProtocolVersion")] - #[serde_as(as = "Readable")] - pub min_supported_protocol_version: ProtocolVersion, - #[schemars(with = "AsProtocolVersion")] - #[serde_as(as = "Readable")] - pub max_supported_protocol_version: ProtocolVersion, - #[schemars(with = "AsProtocolVersion")] - #[serde_as(as = "Readable")] - pub protocol_version: ProtocolVersion, - pub feature_flags: BTreeMap, - pub attributes: BTreeMap>, -} - -impl From for ProtocolConfigResponse { - fn from(config: ProtocolConfig) -> Self { - ProtocolConfigResponse { - protocol_version: config.version, - attributes: config - .attr_map() - .into_iter() - .map(|(k, v)| (k, v.map(SuiProtocolConfigValue::from))) - .collect(), - min_supported_protocol_version: ProtocolVersion::MIN, - max_supported_protocol_version: ProtocolVersion::MAX, - feature_flags: config.feature_map(), - } - } -} diff --git a/crates/sui-json-rpc-types/src/sui_transaction.rs b/crates/sui-json-rpc-types/src/sui_transaction.rs deleted file mode 100644 index a90857e6b97..00000000000 --- a/crates/sui-json-rpc-types/src/sui_transaction.rs +++ /dev/null @@ -1,2240 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt::{self, Display, Formatter, Write}; - -use enum_dispatch::enum_dispatch; -use fastcrypto::encoding::Base64; -use move_binary_format::{access::ModuleAccess, binary_views::BinaryIndexedView, CompiledModule}; -use move_bytecode_utils::module_cache::GetModule; -use move_core_types::{ - annotated_value::MoveTypeLayout, - identifier::IdentStr, - language_storage::{ModuleId, StructTag, TypeTag}, -}; -use mysten_metrics::monitored_scope; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use sui_json::{primitive_type, SuiJsonValue}; -use sui_types::{ - authenticator_state::ActiveJwk, - base_types::{EpochId, ObjectID, ObjectRef, SequenceNumber, SuiAddress, TransactionDigest}, - crypto::SuiSignature, - digests::{ConsensusCommitDigest, ObjectDigest, TransactionEventsDigest}, - effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, - error::{ExecutionError, SuiError, SuiResult}, - execution_status::ExecutionStatus, - gas::GasCostSummary, - messages_checkpoint::CheckpointSequenceNumber, - object::{MoveObject, Owner}, - parse_sui_type_tag, - quorum_driver_types::ExecuteTransactionRequestType, - signature::GenericSignature, - storage::{DeleteKind, WriteKind}, - sui_serde::{BigInt, Readable, SequenceNumber as AsSequenceNumber, SuiTypeTag as AsSuiTypeTag}, - transaction::{ - Argument, CallArg, ChangeEpoch, Command, EndOfEpochTransactionKind, GenesisObject, - InputObjectKind, ObjectArg, ProgrammableMoveCall, ProgrammableTransaction, - SenderSignedData, TransactionData, TransactionDataAPI, TransactionKind, - VersionedProtocolMessage, - }, - type_resolver::LayoutResolver, - SUI_FRAMEWORK_ADDRESS, -}; -use tabled::{ - builder::Builder as TableBuilder, - settings::{style::HorizontalLine, Panel as TablePanel, Style as TableStyle}, -}; - -use crate::{ - balance_changes::BalanceChange, object_changes::ObjectChange, - sui_transaction::GenericSignature::Signature, Filter, Page, SuiEvent, SuiObjectRef, -}; - -// similar to EpochId of sui-types but BigInt -pub type SuiEpochId = BigInt; - -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, Default)] -#[serde( - rename_all = "camelCase", - rename = "TransactionBlockResponseQuery", - default -)] -pub struct SuiTransactionBlockResponseQuery { - /// If None, no filter will be applied - pub filter: Option, - /// config which fields to include in the response, by default only digest - /// is included - pub options: Option, -} - -impl SuiTransactionBlockResponseQuery { - pub fn new( - filter: Option, - options: Option, - ) -> Self { - Self { filter, options } - } - - pub fn new_with_filter(filter: TransactionFilter) -> Self { - Self { - filter: Some(filter), - options: None, - } - } -} - -pub type TransactionBlocksPage = Page; - -#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, Eq, PartialEq, Default)] -#[serde( - rename_all = "camelCase", - rename = "TransactionBlockResponseOptions", - default -)] -pub struct SuiTransactionBlockResponseOptions { - /// Whether to show transaction input data. Default to be False - pub show_input: bool, - /// Whether to show bcs-encoded transaction input data - pub show_raw_input: bool, - /// Whether to show transaction effects. Default to be False - pub show_effects: bool, - /// Whether to show transaction events. Default to be False - pub show_events: bool, - /// Whether to show object_changes. Default to be False - pub show_object_changes: bool, - /// Whether to show balance_changes. Default to be False - pub show_balance_changes: bool, - /// Whether to show raw transaction effects. Default to be False - pub show_raw_effects: bool, -} - -impl SuiTransactionBlockResponseOptions { - pub fn new() -> Self { - Self::default() - } - - pub fn full_content() -> Self { - Self { - show_effects: true, - show_input: true, - show_raw_input: true, - show_events: true, - show_object_changes: true, - show_balance_changes: true, - // This field is added for graphql execution. We keep it false here - // so current users of `full_content` will not get raw effects unexpectedly. - show_raw_effects: false, - } - } - - pub fn with_input(mut self) -> Self { - self.show_input = true; - self - } - - pub fn with_raw_input(mut self) -> Self { - self.show_raw_input = true; - self - } - - pub fn with_effects(mut self) -> Self { - self.show_effects = true; - self - } - - pub fn with_events(mut self) -> Self { - self.show_events = true; - self - } - - pub fn with_balance_changes(mut self) -> Self { - self.show_balance_changes = true; - self - } - - pub fn with_object_changes(mut self) -> Self { - self.show_object_changes = true; - self - } - - pub fn with_raw_effects(mut self) -> Self { - self.show_raw_effects = true; - self - } - - /// default to return `WaitForEffectsCert` unless some options require - /// local execution - pub fn default_execution_request_type(&self) -> ExecuteTransactionRequestType { - // if people want effects or events, they typically want to wait for local - // execution - if self.require_effects() { - ExecuteTransactionRequestType::WaitForLocalExecution - } else { - ExecuteTransactionRequestType::WaitForEffectsCert - } - } - - pub fn require_local_execution(&self) -> bool { - self.show_balance_changes || self.show_object_changes - } - - pub fn require_input(&self) -> bool { - self.show_input || self.show_raw_input || self.show_object_changes - } - - pub fn require_effects(&self) -> bool { - self.show_effects - || self.show_events - || self.show_balance_changes - || self.show_object_changes - || self.show_raw_effects - } - - pub fn only_digest(&self) -> bool { - self == &Self::default() - } -} - -#[serde_as] -#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone, Default)] -#[serde(rename_all = "camelCase", rename = "TransactionBlockResponse")] -pub struct SuiTransactionBlockResponse { - pub digest: TransactionDigest, - /// Transaction input data - #[serde(skip_serializing_if = "Option::is_none")] - pub transaction: Option, - /// BCS encoded [SenderSignedData] that includes input object references - /// returns empty array if `show_raw_transaction` is false - #[serde_as(as = "Base64")] - #[schemars(with = "Base64")] - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub raw_transaction: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub effects: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub events: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub object_changes: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - pub balance_changes: Option>, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[schemars(with = "Option>")] - #[serde_as(as = "Option>")] - pub timestamp_ms: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub confirmed_local_execution: Option, - /// The checkpoint number when this transaction was included and hence - /// finalized. This is only returned in the read api, not in the - /// transaction execution api. - #[schemars(with = "Option>")] - #[serde_as(as = "Option>")] - #[serde(skip_serializing_if = "Option::is_none")] - pub checkpoint: Option, - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub errors: Vec, - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub raw_effects: Vec, -} - -impl SuiTransactionBlockResponse { - pub fn new(digest: TransactionDigest) -> Self { - Self { - digest, - ..Default::default() - } - } - - pub fn status_ok(&self) -> Option { - self.effects.as_ref().map(|e| e.status().is_ok()) - } -} - -/// We are specifically ignoring events for now until events become more stable. -impl PartialEq for SuiTransactionBlockResponse { - fn eq(&self, other: &Self) -> bool { - self.transaction == other.transaction - && self.effects == other.effects - && self.timestamp_ms == other.timestamp_ms - && self.confirmed_local_execution == other.confirmed_local_execution - && self.checkpoint == other.checkpoint - } -} - -impl Display for SuiTransactionBlockResponse { - fn fmt(&self, writer: &mut Formatter<'_>) -> fmt::Result { - writeln!(writer, "Transaction Digest: {}", &self.digest)?; - - if let Some(t) = &self.transaction { - writeln!(writer, "{}", t)?; - } - - if let Some(e) = &self.effects { - writeln!(writer, "{}", e)?; - } - - if let Some(e) = &self.events { - writeln!(writer, "{}", e)?; - } - - if let Some(object_changes) = &self.object_changes { - let mut builder = TableBuilder::default(); - let ( - mut created, - mut deleted, - mut mutated, - mut published, - mut transferred, - mut wrapped, - ) = (vec![], vec![], vec![], vec![], vec![], vec![]); - - for obj in object_changes { - match obj { - ObjectChange::Created { .. } => created.push(obj), - ObjectChange::Deleted { .. } => deleted.push(obj), - ObjectChange::Mutated { .. } => mutated.push(obj), - ObjectChange::Published { .. } => published.push(obj), - ObjectChange::Transferred { .. } => transferred.push(obj), - ObjectChange::Wrapped { .. } => wrapped.push(obj), - }; - } - - write_obj_changes(created, "Created", &mut builder)?; - write_obj_changes(deleted, "Deleted", &mut builder)?; - write_obj_changes(mutated, "Mutated", &mut builder)?; - write_obj_changes(published, "Published", &mut builder)?; - write_obj_changes(transferred, "Transferred", &mut builder)?; - write_obj_changes(wrapped, "Wrapped", &mut builder)?; - - let mut table = builder.build(); - table.with(TablePanel::header("Object Changes")); - table.with(TableStyle::rounded().horizontals([HorizontalLine::new( - 1, - TableStyle::modern().get_horizontal(), - )])); - writeln!(writer, "{}", table)?; - } - - if let Some(balance_changes) = &self.balance_changes { - let mut builder = TableBuilder::default(); - for balance in balance_changes { - builder.push_record(vec![format!("{}", balance)]); - } - let mut table = builder.build(); - table.with(TablePanel::header("Balance Changes")); - table.with(TableStyle::rounded().horizontals([HorizontalLine::new( - 1, - TableStyle::modern().get_horizontal(), - )])); - writeln!(writer, "{}", table)?; - } - Ok(()) - } -} - -fn write_obj_changes( - values: Vec, - output_string: &str, - builder: &mut TableBuilder, -) -> std::fmt::Result { - if !values.is_empty() { - builder.push_record(vec![format!("{} Objects: ", output_string)]); - for obj in values { - builder.push_record(vec![format!("{}", obj)]); - } - } - Ok(()) -} - -pub fn get_new_package_obj_from_response( - response: &SuiTransactionBlockResponse, -) -> Option { - response.object_changes.as_ref().and_then(|changes| { - changes - .iter() - .find(|change| matches!(change, ObjectChange::Published { .. })) - .map(|change| change.object_ref()) - }) -} - -pub fn get_new_package_upgrade_cap_from_response( - response: &SuiTransactionBlockResponse, -) -> Option { - response.object_changes.as_ref().and_then(|changes| { - changes - .iter() - .find(|change| { - matches!(change, ObjectChange::Created { - owner: Owner::AddressOwner(_), - object_type: StructTag { - address: SUI_FRAMEWORK_ADDRESS, - module, - name, - .. - }, - .. - } if module.as_str() == "package" && name.as_str() == "UpgradeCap") - }) - .map(|change| change.object_ref()) - }) -} - -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -#[serde(rename = "TransactionBlockKind", tag = "kind")] -pub enum SuiTransactionBlockKind { - /// A system transaction that will update epoch information on-chain. - ChangeEpoch(SuiChangeEpoch), - /// A system transaction used for initializing the initial state of the - /// chain. - Genesis(SuiGenesisTransaction), - /// A system transaction marking the start of a series of transactions - /// scheduled as part of a checkpoint - ConsensusCommitPrologue(SuiConsensusCommitPrologue), - /// A series of transactions where the results of one transaction can be - /// used in future transactions - ProgrammableTransaction(SuiProgrammableTransactionBlock), - /// A transaction which updates global authenticator state - AuthenticatorStateUpdate(SuiAuthenticatorStateUpdate), - /// A transaction which updates global randomness state - RandomnessStateUpdate(SuiRandomnessStateUpdate), - /// The transaction which occurs only at the end of the epoch - EndOfEpochTransaction(SuiEndOfEpochTransaction), - ConsensusCommitPrologueV2(SuiConsensusCommitPrologueV2), - // .. more transaction types go here -} - -impl Display for SuiTransactionBlockKind { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let mut writer = String::new(); - match &self { - Self::ChangeEpoch(e) => { - writeln!(writer, "Transaction Kind: Epoch Change")?; - writeln!(writer, "New epoch ID: {}", e.epoch)?; - writeln!(writer, "Storage gas reward: {}", e.storage_charge)?; - writeln!(writer, "Computation gas reward: {}", e.computation_charge)?; - writeln!(writer, "Storage rebate: {}", e.storage_rebate)?; - writeln!(writer, "Timestamp: {}", e.epoch_start_timestamp_ms)?; - } - Self::Genesis(_) => { - writeln!(writer, "Transaction Kind: Genesis Transaction")?; - } - Self::ConsensusCommitPrologue(p) => { - writeln!(writer, "Transaction Kind: Consensus Commit Prologue")?; - writeln!( - writer, - "Epoch: {}, Round: {}, Timestamp: {}", - p.epoch, p.round, p.commit_timestamp_ms - )?; - } - Self::ConsensusCommitPrologueV2(p) => { - writeln!(writer, "Transaction Kind: Consensus Commit Prologue V2")?; - writeln!( - writer, - "Epoch: {}, Round: {}, Timestamp: {}, ConsensusCommitDigest: {}", - p.epoch, p.round, p.commit_timestamp_ms, p.consensus_commit_digest - )?; - } - Self::ProgrammableTransaction(p) => { - write!(writer, "Transaction Kind: Programmable")?; - write!(writer, "{}", crate::displays::Pretty(p))?; - } - Self::AuthenticatorStateUpdate(_) => { - writeln!(writer, "Transaction Kind: Authenticator State Update")?; - } - Self::RandomnessStateUpdate(_) => { - writeln!(writer, "Transaction Kind: Randomness State Update")?; - } - Self::EndOfEpochTransaction(_) => { - writeln!(writer, "Transaction Kind: End of Epoch Transaction")?; - } - } - write!(f, "{}", writer) - } -} - -impl SuiTransactionBlockKind { - fn try_from(tx: TransactionKind, module_cache: &impl GetModule) -> Result { - Ok(match tx { - TransactionKind::ChangeEpoch(e) => Self::ChangeEpoch(e.into()), - TransactionKind::Genesis(g) => Self::Genesis(SuiGenesisTransaction { - objects: g.objects.iter().map(GenesisObject::id).collect(), - }), - TransactionKind::ConsensusCommitPrologue(p) => { - Self::ConsensusCommitPrologue(SuiConsensusCommitPrologue { - epoch: p.epoch, - round: p.round, - commit_timestamp_ms: p.commit_timestamp_ms, - }) - } - TransactionKind::ConsensusCommitPrologueV2(p) => { - Self::ConsensusCommitPrologueV2(SuiConsensusCommitPrologueV2 { - epoch: p.epoch, - round: p.round, - commit_timestamp_ms: p.commit_timestamp_ms, - consensus_commit_digest: p.consensus_commit_digest, - }) - } - TransactionKind::ProgrammableTransaction(p) => Self::ProgrammableTransaction( - SuiProgrammableTransactionBlock::try_from(p, module_cache)?, - ), - TransactionKind::AuthenticatorStateUpdate(update) => { - Self::AuthenticatorStateUpdate(SuiAuthenticatorStateUpdate { - epoch: update.epoch, - round: update.round, - new_active_jwks: update - .new_active_jwks - .into_iter() - .map(SuiActiveJwk::from) - .collect(), - }) - } - TransactionKind::RandomnessStateUpdate(update) => { - Self::RandomnessStateUpdate(SuiRandomnessStateUpdate { - epoch: update.epoch, - randomness_round: update.randomness_round.0, - random_bytes: update.random_bytes, - }) - } - TransactionKind::EndOfEpochTransaction(end_of_epoch_tx) => { - Self::EndOfEpochTransaction(SuiEndOfEpochTransaction { - transactions: end_of_epoch_tx - .into_iter() - .map(|tx| match tx { - EndOfEpochTransactionKind::ChangeEpoch(e) => { - SuiEndOfEpochTransactionKind::ChangeEpoch(e.into()) - } - EndOfEpochTransactionKind::AuthenticatorStateCreate => { - SuiEndOfEpochTransactionKind::AuthenticatorStateCreate - } - EndOfEpochTransactionKind::AuthenticatorStateExpire(expire) => { - SuiEndOfEpochTransactionKind::AuthenticatorStateExpire( - SuiAuthenticatorStateExpire { - min_epoch: expire.min_epoch, - }, - ) - } - EndOfEpochTransactionKind::RandomnessStateCreate => { - SuiEndOfEpochTransactionKind::RandomnessStateCreate - } - EndOfEpochTransactionKind::DenyListStateCreate => { - SuiEndOfEpochTransactionKind::CoinDenyListStateCreate - } - }) - .collect(), - }) - } - }) - } - - pub fn transaction_count(&self) -> usize { - match self { - Self::ProgrammableTransaction(p) => p.commands.len(), - _ => 1, - } - } - - pub fn name(&self) -> &'static str { - match self { - Self::ChangeEpoch(_) => "ChangeEpoch", - Self::Genesis(_) => "Genesis", - Self::ConsensusCommitPrologue(_) => "ConsensusCommitPrologue", - Self::ConsensusCommitPrologueV2(_) => "ConsensusCommitPrologueV2", - Self::ProgrammableTransaction(_) => "ProgrammableTransaction", - Self::AuthenticatorStateUpdate(_) => "AuthenticatorStateUpdate", - Self::RandomnessStateUpdate(_) => "RandomnessStateUpdate", - Self::EndOfEpochTransaction(_) => "EndOfEpochTransaction", - } - } -} - -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub struct SuiChangeEpoch { - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub epoch: EpochId, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub storage_charge: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub computation_charge: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub storage_rebate: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub epoch_start_timestamp_ms: u64, -} - -impl From for SuiChangeEpoch { - fn from(e: ChangeEpoch) -> Self { - Self { - epoch: e.epoch, - storage_charge: e.storage_charge, - computation_charge: e.computation_charge, - storage_rebate: e.storage_rebate, - epoch_start_timestamp_ms: e.epoch_start_timestamp_ms, - } - } -} - -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, PartialEq, Eq)] -#[enum_dispatch(SuiTransactionBlockEffectsAPI)] -#[serde( - rename = "TransactionBlockEffects", - rename_all = "camelCase", - tag = "messageVersion" -)] -pub enum SuiTransactionBlockEffects { - V1(SuiTransactionBlockEffectsV1), -} - -#[enum_dispatch] -pub trait SuiTransactionBlockEffectsAPI { - fn status(&self) -> &SuiExecutionStatus; - fn into_status(self) -> SuiExecutionStatus; - fn shared_objects(&self) -> &[SuiObjectRef]; - fn created(&self) -> &[OwnedObjectRef]; - fn mutated(&self) -> &[OwnedObjectRef]; - fn unwrapped(&self) -> &[OwnedObjectRef]; - fn deleted(&self) -> &[SuiObjectRef]; - fn unwrapped_then_deleted(&self) -> &[SuiObjectRef]; - fn wrapped(&self) -> &[SuiObjectRef]; - fn gas_object(&self) -> &OwnedObjectRef; - fn events_digest(&self) -> Option<&TransactionEventsDigest>; - fn dependencies(&self) -> &[TransactionDigest]; - fn executed_epoch(&self) -> EpochId; - fn transaction_digest(&self) -> &TransactionDigest; - fn gas_cost_summary(&self) -> &GasCostSummary; - - /// Return an iterator of mutated objects, but excluding the gas object. - fn mutated_excluding_gas(&self) -> Vec; - fn modified_at_versions(&self) -> Vec<(ObjectID, SequenceNumber)>; - fn all_changed_objects(&self) -> Vec<(&OwnedObjectRef, WriteKind)>; - fn all_deleted_objects(&self) -> Vec<(&SuiObjectRef, DeleteKind)>; -} - -#[serde_as] -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] -#[serde( - rename = "TransactionBlockEffectsModifiedAtVersions", - rename_all = "camelCase" -)] -pub struct SuiTransactionBlockEffectsModifiedAtVersions { - object_id: ObjectID, - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - sequence_number: SequenceNumber, -} - -/// The response from processing a transaction or a certified transaction -#[serde_as] -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] -#[serde(rename = "TransactionBlockEffectsV1", rename_all = "camelCase")] -pub struct SuiTransactionBlockEffectsV1 { - /// The status of the execution - pub status: SuiExecutionStatus, - /// The epoch when this transaction was executed. - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub executed_epoch: EpochId, - pub gas_used: GasCostSummary, - /// The version that every modified (mutated or deleted) object had before - /// it was modified by this transaction. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub modified_at_versions: Vec, - /// The object references of the shared objects used in this transaction. - /// Empty if no shared objects were used. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub shared_objects: Vec, - /// The transaction digest - pub transaction_digest: TransactionDigest, - /// ObjectRef and owner of new objects created. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub created: Vec, - /// ObjectRef and owner of mutated objects, including gas object. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub mutated: Vec, - /// ObjectRef and owner of objects that are unwrapped in this transaction. - /// Unwrapped objects are objects that were wrapped into other objects in - /// the past, and just got extracted out. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub unwrapped: Vec, - /// Object Refs of objects now deleted (the old refs). - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub deleted: Vec, - /// Object refs of objects previously wrapped in other objects but now - /// deleted. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub unwrapped_then_deleted: Vec, - /// Object refs of objects now wrapped in other objects. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub wrapped: Vec, - /// The updated gas object reference. Have a dedicated field for convenient - /// access. It's also included in mutated. - pub gas_object: OwnedObjectRef, - /// The digest of the events emitted during execution, - /// can be None if the transaction does not emit any event. - #[serde(skip_serializing_if = "Option::is_none")] - pub events_digest: Option, - /// The set of transaction digests this transaction depends on. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub dependencies: Vec, -} - -impl SuiTransactionBlockEffectsAPI for SuiTransactionBlockEffectsV1 { - fn status(&self) -> &SuiExecutionStatus { - &self.status - } - fn into_status(self) -> SuiExecutionStatus { - self.status - } - fn shared_objects(&self) -> &[SuiObjectRef] { - &self.shared_objects - } - fn created(&self) -> &[OwnedObjectRef] { - &self.created - } - fn mutated(&self) -> &[OwnedObjectRef] { - &self.mutated - } - fn unwrapped(&self) -> &[OwnedObjectRef] { - &self.unwrapped - } - fn deleted(&self) -> &[SuiObjectRef] { - &self.deleted - } - fn unwrapped_then_deleted(&self) -> &[SuiObjectRef] { - &self.unwrapped_then_deleted - } - fn wrapped(&self) -> &[SuiObjectRef] { - &self.wrapped - } - fn gas_object(&self) -> &OwnedObjectRef { - &self.gas_object - } - fn events_digest(&self) -> Option<&TransactionEventsDigest> { - self.events_digest.as_ref() - } - fn dependencies(&self) -> &[TransactionDigest] { - &self.dependencies - } - - fn executed_epoch(&self) -> EpochId { - self.executed_epoch - } - - fn transaction_digest(&self) -> &TransactionDigest { - &self.transaction_digest - } - - fn gas_cost_summary(&self) -> &GasCostSummary { - &self.gas_used - } - - fn mutated_excluding_gas(&self) -> Vec { - self.mutated - .iter() - .filter(|o| *o != &self.gas_object) - .cloned() - .collect() - } - - fn modified_at_versions(&self) -> Vec<(ObjectID, SequenceNumber)> { - self.modified_at_versions - .iter() - .map(|v| (v.object_id, v.sequence_number)) - .collect::>() - } - - fn all_changed_objects(&self) -> Vec<(&OwnedObjectRef, WriteKind)> { - self.mutated - .iter() - .map(|owner_ref| (owner_ref, WriteKind::Mutate)) - .chain( - self.created - .iter() - .map(|owner_ref| (owner_ref, WriteKind::Create)), - ) - .chain( - self.unwrapped - .iter() - .map(|owner_ref| (owner_ref, WriteKind::Unwrap)), - ) - .collect() - } - - fn all_deleted_objects(&self) -> Vec<(&SuiObjectRef, DeleteKind)> { - self.deleted - .iter() - .map(|r| (r, DeleteKind::Normal)) - .chain( - self.unwrapped_then_deleted - .iter() - .map(|r| (r, DeleteKind::UnwrapThenDelete)), - ) - .chain(self.wrapped.iter().map(|r| (r, DeleteKind::Wrap))) - .collect() - } -} - -impl SuiTransactionBlockEffects { - #[cfg(any(feature = "test-utils", test))] - pub fn new_for_testing( - transaction_digest: TransactionDigest, - status: SuiExecutionStatus, - ) -> Self { - Self::V1(SuiTransactionBlockEffectsV1 { - transaction_digest, - status, - gas_object: OwnedObjectRef { - owner: Owner::AddressOwner(SuiAddress::random_for_testing_only()), - reference: sui_types::base_types::random_object_ref().into(), - }, - executed_epoch: 0, - modified_at_versions: vec![], - gas_used: GasCostSummary::default(), - shared_objects: vec![], - created: vec![], - mutated: vec![], - unwrapped: vec![], - deleted: vec![], - unwrapped_then_deleted: vec![], - wrapped: vec![], - events_digest: None, - dependencies: vec![], - }) - } -} - -impl TryFrom for SuiTransactionBlockEffects { - type Error = SuiError; - - fn try_from(effect: TransactionEffects) -> Result { - Ok(SuiTransactionBlockEffects::V1( - SuiTransactionBlockEffectsV1 { - status: effect.status().clone().into(), - executed_epoch: effect.executed_epoch(), - modified_at_versions: effect - .modified_at_versions() - .into_iter() - .map(|(object_id, sequence_number)| { - SuiTransactionBlockEffectsModifiedAtVersions { - object_id, - sequence_number, - } - }) - .collect(), - gas_used: effect.gas_cost_summary().clone(), - shared_objects: to_sui_object_ref( - effect - .input_shared_objects() - .into_iter() - .map(|kind| kind.object_ref()) - .collect(), - ), - transaction_digest: *effect.transaction_digest(), - created: to_owned_ref(effect.created()), - mutated: to_owned_ref(effect.mutated().to_vec()), - unwrapped: to_owned_ref(effect.unwrapped().to_vec()), - deleted: to_sui_object_ref(effect.deleted().to_vec()), - unwrapped_then_deleted: to_sui_object_ref(effect.unwrapped_then_deleted().to_vec()), - wrapped: to_sui_object_ref(effect.wrapped().to_vec()), - gas_object: OwnedObjectRef { - owner: effect.gas_object().1, - reference: effect.gas_object().0.into(), - }, - events_digest: effect.events_digest().copied(), - dependencies: effect.dependencies().to_vec(), - }, - )) - } -} - -fn owned_objref_string(obj: &OwnedObjectRef) -> String { - format!( - " ┌──\n │ ID: {} \n │ Owner: {} \n │ Version: {} \n │ Digest: {}\n └──", - obj.reference.object_id, - obj.owner, - u64::from(obj.reference.version), - obj.reference.digest - ) -} - -fn objref_string(obj: &SuiObjectRef) -> String { - format!( - " ┌──\n │ ID: {} \n │ Version: {} \n │ Digest: {}\n └──", - obj.object_id, - u64::from(obj.version), - obj.digest - ) -} - -impl Display for SuiTransactionBlockEffects { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let mut builder = TableBuilder::default(); - - builder.push_record(vec![format!("Digest: {}", self.transaction_digest())]); - builder.push_record(vec![format!("Status: {:?}", self.status())]); - builder.push_record(vec![format!("Executed Epoch: {}", self.executed_epoch())]); - - if !self.created().is_empty() { - builder.push_record(vec![format!("\nCreated Objects: ")]); - - for oref in self.created() { - builder.push_record(vec![owned_objref_string(oref)]); - } - } - - if !self.mutated().is_empty() { - builder.push_record(vec![format!("Mutated Objects: ")]); - for oref in self.mutated() { - builder.push_record(vec![owned_objref_string(oref)]); - } - } - - if !self.shared_objects().is_empty() { - builder.push_record(vec![format!("Shared Objects: ")]); - for oref in self.shared_objects() { - builder.push_record(vec![objref_string(oref)]); - } - } - - if !self.deleted().is_empty() { - builder.push_record(vec![format!("Deleted Objects: ")]); - - for oref in self.deleted() { - builder.push_record(vec![objref_string(oref)]); - } - } - - if !self.wrapped().is_empty() { - builder.push_record(vec![format!("Wrapped Objects: ")]); - - for oref in self.wrapped() { - builder.push_record(vec![objref_string(oref)]); - } - } - - if !self.unwrapped().is_empty() { - builder.push_record(vec![format!("Unwrapped Objects: ")]); - for oref in self.unwrapped() { - builder.push_record(vec![owned_objref_string(oref)]); - } - } - - builder.push_record(vec![format!( - "Gas Object: \n{}", - owned_objref_string(self.gas_object()) - )]); - - let gas_cost_summary = self.gas_cost_summary(); - builder.push_record(vec![format!( - "Gas Cost Summary:\n \ - Storage Cost: {} MIST\n \ - Computation Cost: {} MIST\n \ - Storage Rebate: {} MIST\n \ - Non-refundable Storage Fee: {} MIST", - gas_cost_summary.storage_cost, - gas_cost_summary.computation_cost, - gas_cost_summary.storage_rebate, - gas_cost_summary.non_refundable_storage_fee, - )]); - - let dependencies = self.dependencies(); - if !dependencies.is_empty() { - builder.push_record(vec![format!("\nTransaction Dependencies:")]); - for dependency in dependencies { - builder.push_record(vec![format!(" {}", dependency)]); - } - } - - let mut table = builder.build(); - table.with(TablePanel::header("Transaction Effects")); - table.with(TableStyle::rounded().horizontals([HorizontalLine::new( - 1, - TableStyle::modern().get_horizontal(), - )])); - write!(f, "{}", table) - } -} - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct DryRunTransactionBlockResponse { - pub effects: SuiTransactionBlockEffects, - pub events: SuiTransactionBlockEvents, - pub object_changes: Vec, - pub balance_changes: Vec, - pub input: SuiTransactionBlockData, -} - -#[derive(Eq, PartialEq, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] -#[serde(rename = "TransactionBlockEvents", transparent)] -pub struct SuiTransactionBlockEvents { - pub data: Vec, -} - -impl SuiTransactionBlockEvents { - pub fn try_from( - events: TransactionEvents, - tx_digest: TransactionDigest, - timestamp_ms: Option, - resolver: &mut dyn LayoutResolver, - ) -> SuiResult { - Ok(Self { - data: events - .data - .into_iter() - .enumerate() - .map(|(seq, event)| { - let layout = resolver.get_annotated_layout(&event.type_)?; - SuiEvent::try_from(event, tx_digest, seq as u64, timestamp_ms, layout) - }) - .collect::>()?, - }) - } - - // TODO: this is only called from the indexer. Remove this once indexer moves to - // its own resolver. - pub fn try_from_using_module_resolver( - events: TransactionEvents, - tx_digest: TransactionDigest, - timestamp_ms: Option, - resolver: &impl GetModule, - ) -> SuiResult { - Ok(Self { - data: events - .data - .into_iter() - .enumerate() - .map(|(seq, event)| { - let layout = - MoveObject::get_layout_from_struct_tag(event.type_.clone(), resolver)?; - SuiEvent::try_from(event, tx_digest, seq as u64, timestamp_ms, layout) - }) - .collect::>()?, - }) - } -} - -impl Display for SuiTransactionBlockEvents { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if self.data.is_empty() { - writeln!(f, "╭─────────────────────────────╮")?; - writeln!(f, "│ No transaction block events │")?; - writeln!(f, "╰─────────────────────────────╯") - } else { - let mut builder = TableBuilder::default(); - - for event in &self.data { - builder.push_record(vec![format!("{}", event)]); - } - - let mut table = builder.build(); - table.with(TablePanel::header("Transaction Block Events")); - table.with(TableStyle::rounded().horizontals([HorizontalLine::new( - 1, - TableStyle::modern().get_horizontal(), - )])); - write!(f, "{}", table) - } - } -} - -// TODO: this file might not be the best place for this struct. -/// Additional rguments supplied to dev inspect beyond what is allowed in -/// today's API. -#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)] -#[serde(rename = "DevInspectArgs", rename_all = "camelCase")] -pub struct DevInspectArgs { - /// The sponsor of the gas for the transaction, might be different from the - /// sender. - pub gas_sponsor: Option, - /// The gas budget for the transaction. - pub gas_budget: Option>, - /// The gas objects used to pay for the transaction. - pub gas_objects: Option>, - /// Whether to skip transaction checks for the transaction. - pub skip_checks: Option, - /// Whether to return the raw transaction data and effects. - pub show_raw_txn_data_and_effects: Option, -} - -/// The response from processing a dev inspect transaction -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] -#[serde(rename = "DevInspectResults", rename_all = "camelCase")] -pub struct DevInspectResults { - /// Summary of effects that likely would be generated if the transaction is - /// actually run. Note however, that not all dev-inspect transactions - /// are actually usable as transactions so it might not be possible - /// actually generate these effects from a normal transaction. - pub effects: SuiTransactionBlockEffects, - /// Events that likely would be generated if the transaction is actually - /// run. - pub events: SuiTransactionBlockEvents, - /// Execution results (including return values) from executing the - /// transactions - #[serde(skip_serializing_if = "Option::is_none")] - pub results: Option>, - /// Execution error from executing the transactions - #[serde(skip_serializing_if = "Option::is_none")] - pub error: Option, - /// The raw transaction data that was dev inspected. - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub raw_txn_data: Vec, - /// The raw effects of the transaction that was dev inspected. - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub raw_effects: Vec, -} - -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] -#[serde(rename = "SuiExecutionResult", rename_all = "camelCase")] -pub struct SuiExecutionResult { - /// The value of any arguments that were mutably borrowed. - /// Non-mut borrowed values are not included - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub mutable_reference_outputs: Vec<(/* argument */ SuiArgument, Vec, SuiTypeTag)>, - /// The return values from the transaction - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub return_values: Vec<(Vec, SuiTypeTag)>, -} - -type ExecutionResult = ( - // mutable_reference_outputs - Vec<(Argument, Vec, TypeTag)>, - // return_values - Vec<(Vec, TypeTag)>, -); - -impl DevInspectResults { - pub fn new( - effects: TransactionEffects, - events: TransactionEvents, - return_values: Result, ExecutionError>, - raw_txn_data: Vec, - raw_effects: Vec, - resolver: &mut dyn LayoutResolver, - ) -> SuiResult { - let tx_digest = *effects.transaction_digest(); - let mut error = None; - let mut results = None; - match return_values { - Err(e) => error = Some(e.to_string()), - Ok(srvs) => { - results = Some( - srvs.into_iter() - .map(|srv| { - let (mutable_reference_outputs, return_values) = srv; - let mutable_reference_outputs = mutable_reference_outputs - .into_iter() - .map(|(a, bytes, tag)| (a.into(), bytes, SuiTypeTag::from(tag))) - .collect(); - let return_values = return_values - .into_iter() - .map(|(bytes, tag)| (bytes, SuiTypeTag::from(tag))) - .collect(); - SuiExecutionResult { - mutable_reference_outputs, - return_values, - } - }) - .collect(), - ) - } - }; - Ok(Self { - effects: effects.try_into()?, - events: SuiTransactionBlockEvents::try_from(events, tx_digest, None, resolver)?, - results, - error, - raw_txn_data, - raw_effects, - }) - } -} - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub enum SuiTransactionBlockBuilderMode { - /// Regular Sui Transactions that are committed on chain - Commit, - /// Simulated transaction that allows calling any Move function with - /// arbitrary values. - DevInspect, -} - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] -#[serde(rename = "ExecutionStatus", rename_all = "camelCase", tag = "status")] -pub enum SuiExecutionStatus { - // Gas used in the success case. - Success, - // Gas used in the failed case, and the error. - Failure { error: String }, -} - -impl SuiExecutionStatus { - pub fn is_ok(&self) -> bool { - matches!(self, SuiExecutionStatus::Success { .. }) - } - pub fn is_err(&self) -> bool { - matches!(self, SuiExecutionStatus::Failure { .. }) - } -} - -impl From for SuiExecutionStatus { - fn from(status: ExecutionStatus) -> Self { - match status { - ExecutionStatus::Success => Self::Success, - ExecutionStatus::Failure { - error, - command: None, - } => Self::Failure { - error: format!("{error:?}"), - }, - ExecutionStatus::Failure { - error, - command: Some(idx), - } => Self::Failure { - error: format!("{error:?} in command {idx}"), - }, - } - } -} - -fn to_sui_object_ref(refs: Vec) -> Vec { - refs.into_iter().map(SuiObjectRef::from).collect() -} - -fn to_owned_ref(owned_refs: Vec<(ObjectRef, Owner)>) -> Vec { - owned_refs - .into_iter() - .map(|(oref, owner)| OwnedObjectRef { - owner, - reference: oref.into(), - }) - .collect() -} - -#[serde_as] -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, PartialEq, Eq)] -#[serde(rename = "GasData", rename_all = "camelCase")] -pub struct SuiGasData { - pub payment: Vec, - pub owner: SuiAddress, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub price: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub budget: u64, -} - -impl Display for SuiGasData { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - writeln!(f, "Gas Owner: {}", self.owner)?; - writeln!(f, "Gas Budget: {} MIST", self.budget)?; - writeln!(f, "Gas Price: {} MIST", self.price)?; - writeln!(f, "Gas Payment:")?; - for payment in &self.payment { - write!(f, "{} ", objref_string(payment))?; - } - writeln!(f) - } -} - -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, PartialEq, Eq)] -#[enum_dispatch(SuiTransactionBlockDataAPI)] -#[serde( - rename = "TransactionBlockData", - rename_all = "camelCase", - tag = "messageVersion" -)] -pub enum SuiTransactionBlockData { - V1(SuiTransactionBlockDataV1), -} - -#[enum_dispatch] -pub trait SuiTransactionBlockDataAPI { - fn transaction(&self) -> &SuiTransactionBlockKind; - fn sender(&self) -> &SuiAddress; - fn gas_data(&self) -> &SuiGasData; -} - -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, PartialEq, Eq)] -#[serde(rename = "TransactionBlockDataV1", rename_all = "camelCase")] -pub struct SuiTransactionBlockDataV1 { - pub transaction: SuiTransactionBlockKind, - pub sender: SuiAddress, - pub gas_data: SuiGasData, -} - -impl SuiTransactionBlockDataAPI for SuiTransactionBlockDataV1 { - fn transaction(&self) -> &SuiTransactionBlockKind { - &self.transaction - } - fn sender(&self) -> &SuiAddress { - &self.sender - } - fn gas_data(&self) -> &SuiGasData { - &self.gas_data - } -} - -impl SuiTransactionBlockData { - pub fn move_calls(&self) -> Vec<&SuiProgrammableMoveCall> { - match self { - Self::V1(data) => match &data.transaction { - SuiTransactionBlockKind::ProgrammableTransaction(pt) => pt - .commands - .iter() - .filter_map(|command| match command { - SuiCommand::MoveCall(c) => Some(&**c), - _ => None, - }) - .collect(), - _ => vec![], - }, - } - } -} - -impl Display for SuiTransactionBlockData { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - Self::V1(data) => { - writeln!(f, "Sender: {}", data.sender)?; - writeln!(f, "{}", self.gas_data())?; - writeln!(f, "{}", data.transaction) - } - } - } -} - -impl SuiTransactionBlockData { - pub fn try_from( - data: TransactionData, - module_cache: &impl GetModule, - ) -> Result { - let message_version = data - .message_version() - .expect("TransactionData defines message_version()"); - let sender = data.sender(); - let gas_data = SuiGasData { - payment: data - .gas() - .iter() - .map(|obj_ref| SuiObjectRef::from(*obj_ref)) - .collect(), - owner: data.gas_owner(), - price: data.gas_price(), - budget: data.gas_budget(), - }; - let transaction = SuiTransactionBlockKind::try_from(data.into_kind(), module_cache)?; - match message_version { - 1 => Ok(SuiTransactionBlockData::V1(SuiTransactionBlockDataV1 { - transaction, - sender, - gas_data, - })), - _ => Err(anyhow::anyhow!( - "Support for TransactionData version {} not implemented", - message_version - )), - } - } -} - -#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, PartialEq, Eq)] -#[serde(rename = "TransactionBlock", rename_all = "camelCase")] -pub struct SuiTransactionBlock { - pub data: SuiTransactionBlockData, - pub tx_signatures: Vec, -} - -impl SuiTransactionBlock { - pub fn try_from( - data: SenderSignedData, - module_cache: &impl GetModule, - ) -> Result { - Ok(Self { - data: SuiTransactionBlockData::try_from( - data.intent_message().value.clone(), - module_cache, - )?, - tx_signatures: data.tx_signatures().to_vec(), - }) - } -} - -impl Display for SuiTransactionBlock { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let mut builder = TableBuilder::default(); - - builder.push_record(vec![format!("{}", self.data)]); - builder.push_record(vec![format!("Signatures:")]); - for tx_sig in &self.tx_signatures { - builder.push_record(vec![format!( - " {}\n", - match tx_sig { - Signature(sig) => Base64::from_bytes(sig.signature_bytes()).encoded(), - _ => Base64::from_bytes(tx_sig.as_ref()).encoded(), /* the signatures for - * multisig and zklogin - * are not suited to be - * parsed out. they - * should be interpreted - * as a whole */ - } - )]); - } - - let mut table = builder.build(); - table.with(TablePanel::header("Transaction Data")); - table.with(TableStyle::rounded().horizontals([HorizontalLine::new( - 1, - TableStyle::modern().get_horizontal(), - )])); - write!(f, "{}", table) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub struct SuiGenesisTransaction { - pub objects: Vec, -} - -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub struct SuiConsensusCommitPrologue { - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub epoch: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub round: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub commit_timestamp_ms: u64, -} - -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub struct SuiConsensusCommitPrologueV2 { - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub epoch: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub round: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub commit_timestamp_ms: u64, - pub consensus_commit_digest: ConsensusCommitDigest, -} - -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub struct SuiAuthenticatorStateUpdate { - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub epoch: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub round: u64, - - pub new_active_jwks: Vec, -} - -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub struct SuiRandomnessStateUpdate { - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub epoch: u64, - - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub randomness_round: u64, - pub random_bytes: Vec, -} - -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub struct SuiEndOfEpochTransaction { - pub transactions: Vec, -} - -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub enum SuiEndOfEpochTransactionKind { - ChangeEpoch(SuiChangeEpoch), - AuthenticatorStateCreate, - AuthenticatorStateExpire(SuiAuthenticatorStateExpire), - RandomnessStateCreate, - CoinDenyListStateCreate, -} - -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub struct SuiAuthenticatorStateExpire { - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub min_epoch: u64, -} - -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub struct SuiActiveJwk { - pub jwk_id: SuiJwkId, - pub jwk: SuiJWK, - - #[schemars(with = "BigInt")] - #[serde_as(as = "BigInt")] - pub epoch: u64, -} - -impl From for SuiActiveJwk { - fn from(active_jwk: ActiveJwk) -> Self { - Self { - jwk_id: SuiJwkId { - iss: active_jwk.jwk_id.iss.clone(), - kid: active_jwk.jwk_id.kid.clone(), - }, - jwk: SuiJWK { - kty: active_jwk.jwk.kty.clone(), - e: active_jwk.jwk.e.clone(), - n: active_jwk.jwk.n.clone(), - alg: active_jwk.jwk.alg.clone(), - }, - epoch: active_jwk.epoch, - } - } -} - -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub struct SuiJwkId { - pub iss: String, - pub kid: String, -} - -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub struct SuiJWK { - pub kty: String, - pub e: String, - pub n: String, - pub alg: String, -} - -#[serde_as] -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, JsonSchema)] -#[serde(rename = "InputObjectKind")] -pub enum SuiInputObjectKind { - // A Move package, must be immutable. - MovePackage(ObjectID), - // A Move object, either immutable, or owned mutable. - ImmOrOwnedMoveObject(SuiObjectRef), - // A Move object that's shared and mutable. - SharedMoveObject { - id: ObjectID, - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - initial_shared_version: SequenceNumber, - #[serde(default = "default_shared_object_mutability")] - mutable: bool, - }, -} - -/// A series of commands where the results of one command can be used in future -/// commands -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub struct SuiProgrammableTransactionBlock { - /// Input objects or primitive values - pub inputs: Vec, - #[serde(rename = "transactions")] - /// The transactions to be executed sequentially. A failure in any - /// transaction will result in the failure of the entire programmable - /// transaction block. - pub commands: Vec, -} - -impl Display for SuiProgrammableTransactionBlock { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Self { inputs, commands } = self; - writeln!(f, "Inputs: {inputs:?}")?; - writeln!(f, "Commands: [")?; - for c in commands { - writeln!(f, " {c},")?; - } - writeln!(f, "]") - } -} - -impl SuiProgrammableTransactionBlock { - fn try_from( - value: ProgrammableTransaction, - module_cache: &impl GetModule, - ) -> Result { - let ProgrammableTransaction { inputs, commands } = value; - let input_types = Self::resolve_input_type(&inputs, &commands, module_cache); - Ok(SuiProgrammableTransactionBlock { - inputs: inputs - .into_iter() - .zip(input_types) - .map(|(arg, layout)| SuiCallArg::try_from(arg, layout.as_ref())) - .collect::>()?, - commands: commands.into_iter().map(SuiCommand::from).collect(), - }) - } - - fn resolve_input_type( - inputs: &Vec, - commands: &[Command], - module_cache: &impl GetModule, - ) -> Vec> { - let mut result_types = vec![None; inputs.len()]; - for command in commands.iter() { - match command { - Command::MoveCall(c) => { - let id = ModuleId::new(c.package.into(), c.module.clone()); - let Some(types) = - get_signature_types(id, c.function.as_ident_str(), module_cache) - else { - return result_types; - }; - for (arg, type_) in c.arguments.iter().zip(types) { - if let (&Argument::Input(i), Some(type_)) = (arg, type_) { - if let Some(x) = result_types.get_mut(i as usize) { - x.replace(type_); - } - } - } - } - Command::SplitCoins(_, amounts) => { - for arg in amounts { - if let &Argument::Input(i) = arg { - if let Some(x) = result_types.get_mut(i as usize) { - x.replace(MoveTypeLayout::U64); - } - } - } - } - Command::TransferObjects(_, Argument::Input(i)) => { - if let Some(x) = result_types.get_mut((*i) as usize) { - x.replace(MoveTypeLayout::Address); - } - } - _ => {} - } - } - result_types - } -} - -fn get_signature_types( - id: ModuleId, - function: &IdentStr, - module_cache: &impl GetModule, -) -> Option>> { - use std::borrow::Borrow; - if let Ok(Some(module)) = module_cache.get_module_by_id(&id) { - let module: &CompiledModule = module.borrow(); - let view = BinaryIndexedView::Module(module); - let func = module - .function_handles - .iter() - .find(|f| module.identifier_at(f.name) == function)?; - Some( - module - .signature_at(func.parameters) - .0 - .iter() - .map(|s| primitive_type(&view, &[], s).1) - .collect(), - ) - } else { - None - } -} - -/// A single transaction in a programmable transaction block. -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -#[serde(rename = "SuiTransaction")] -pub enum SuiCommand { - /// A call to either an entry or a public Move function - MoveCall(Box), - /// `(Vec, address)` - /// It sends n-objects to the specified address. These objects must have - /// store (public transfer) and either the previous owner must be an - /// address or the object must be newly created. - TransferObjects(Vec, SuiArgument), - /// `(&mut Coin, Vec)` -> `Vec>` - /// It splits off some amounts into a new coins with those amounts - SplitCoins(SuiArgument, Vec), - /// `(&mut Coin, Vec>)` - /// It merges n-coins into the first coin - MergeCoins(SuiArgument, Vec), - /// Publishes a Move package. It takes the package bytes and a list of the - /// package's transitive dependencies to link against on-chain. - Publish(Vec), - /// Upgrades a Move package - Upgrade(Vec, ObjectID, SuiArgument), - /// `forall T: Vec -> vector` - /// Given n-values of the same type, it constructs a vector. For non objects - /// or an empty vector, the type tag must be specified. - MakeMoveVec(Option, Vec), -} - -impl Display for SuiCommand { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Self::MoveCall(p) => { - write!(f, "MoveCall({p})") - } - Self::MakeMoveVec(ty_opt, elems) => { - write!(f, "MakeMoveVec(")?; - if let Some(ty) = ty_opt { - write!(f, "Some{ty}")?; - } else { - write!(f, "None")?; - } - write!(f, ",[")?; - write_sep(f, elems, ",")?; - write!(f, "])") - } - Self::TransferObjects(objs, addr) => { - write!(f, "TransferObjects([")?; - write_sep(f, objs, ",")?; - write!(f, "],{addr})") - } - Self::SplitCoins(coin, amounts) => { - write!(f, "SplitCoins({coin},")?; - write_sep(f, amounts, ",")?; - write!(f, ")") - } - Self::MergeCoins(target, coins) => { - write!(f, "MergeCoins({target},")?; - write_sep(f, coins, ",")?; - write!(f, ")") - } - Self::Publish(deps) => { - write!(f, "Publish(,")?; - write_sep(f, deps, ",")?; - write!(f, ")") - } - Self::Upgrade(deps, current_package_id, ticket) => { - write!(f, "Upgrade(, {ticket},")?; - write_sep(f, deps, ",")?; - write!(f, ", {current_package_id}")?; - write!(f, ")") - } - } - } -} - -impl From for SuiCommand { - fn from(value: Command) -> Self { - match value { - Command::MoveCall(m) => SuiCommand::MoveCall(Box::new((*m).into())), - Command::TransferObjects(args, arg) => SuiCommand::TransferObjects( - args.into_iter().map(SuiArgument::from).collect(), - arg.into(), - ), - Command::SplitCoins(arg, args) => SuiCommand::SplitCoins( - arg.into(), - args.into_iter().map(SuiArgument::from).collect(), - ), - Command::MergeCoins(arg, args) => SuiCommand::MergeCoins( - arg.into(), - args.into_iter().map(SuiArgument::from).collect(), - ), - Command::Publish(_modules, dep_ids) => SuiCommand::Publish(dep_ids), - Command::MakeMoveVec(tag_opt, args) => SuiCommand::MakeMoveVec( - tag_opt.map(|tag| tag.to_string()), - args.into_iter().map(SuiArgument::from).collect(), - ), - Command::Upgrade(_modules, dep_ids, current_package_id, ticket) => { - SuiCommand::Upgrade(dep_ids, current_package_id, SuiArgument::from(ticket)) - } - } - } -} - -/// An argument to a transaction in a programmable transaction block -#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub enum SuiArgument { - /// The gas coin. The gas coin can only be used by-ref, except for with - /// `TransferObjects`, which can use it by-value. - GasCoin, - /// One of the input objects or primitive values (from - /// `ProgrammableTransactionBlock` inputs) - Input(u16), - /// The result of another transaction (from `ProgrammableTransactionBlock` - /// transactions) - Result(u16), - /// Like a `Result` but it accesses a nested result. Currently, the only - /// usage of this is to access a value from a Move call with multiple - /// return values. - NestedResult(u16, u16), -} - -impl Display for SuiArgument { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Self::GasCoin => write!(f, "GasCoin"), - Self::Input(i) => write!(f, "Input({i})"), - Self::Result(i) => write!(f, "Result({i})"), - Self::NestedResult(i, j) => write!(f, "NestedResult({i},{j})"), - } - } -} - -impl From for SuiArgument { - fn from(value: Argument) -> Self { - match value { - Argument::GasCoin => Self::GasCoin, - Argument::Input(i) => Self::Input(i), - Argument::Result(i) => Self::Result(i), - Argument::NestedResult(i, j) => Self::NestedResult(i, j), - } - } -} - -/// The transaction for calling a Move function, either an entry function or a -/// public function (which cannot return references). -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -pub struct SuiProgrammableMoveCall { - /// The package containing the module and function. - pub package: ObjectID, - /// The specific module in the package containing the function. - pub module: String, - /// The function to be called. - pub function: String, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - /// The type arguments to the function. - pub type_arguments: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - /// The arguments to the function. - pub arguments: Vec, -} - -fn write_sep( - f: &mut Formatter<'_>, - items: impl IntoIterator, - sep: &str, -) -> std::fmt::Result { - let mut xs = items.into_iter().peekable(); - while let Some(x) = xs.next() { - write!(f, "{x}")?; - if xs.peek().is_some() { - write!(f, "{sep}")?; - } - } - Ok(()) -} - -impl Display for SuiProgrammableMoveCall { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Self { - package, - module, - function, - type_arguments, - arguments, - } = self; - write!(f, "{package}::{module}::{function}")?; - if !type_arguments.is_empty() { - write!(f, "<")?; - write_sep(f, type_arguments, ",")?; - write!(f, ">")?; - } - write!(f, "(")?; - write_sep(f, arguments, ",")?; - write!(f, ")") - } -} - -impl From for SuiProgrammableMoveCall { - fn from(value: ProgrammableMoveCall) -> Self { - let ProgrammableMoveCall { - package, - module, - function, - type_arguments, - arguments, - } = value; - Self { - package, - module: module.to_string(), - function: function.to_string(), - type_arguments: type_arguments.into_iter().map(|t| t.to_string()).collect(), - arguments: arguments.into_iter().map(SuiArgument::from).collect(), - } - } -} - -const fn default_shared_object_mutability() -> bool { - true -} - -impl From for SuiInputObjectKind { - fn from(input: InputObjectKind) -> Self { - match input { - InputObjectKind::MovePackage(id) => Self::MovePackage(id), - InputObjectKind::ImmOrOwnedMoveObject(oref) => Self::ImmOrOwnedMoveObject(oref.into()), - InputObjectKind::SharedMoveObject { - id, - initial_shared_version, - mutable, - } => Self::SharedMoveObject { - id, - initial_shared_version, - mutable, - }, - } - } -} - -#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone)] -#[serde(rename = "TypeTag", rename_all = "camelCase")] -pub struct SuiTypeTag(String); - -impl SuiTypeTag { - pub fn new(tag: String) -> Self { - Self(tag) - } -} - -impl TryInto for SuiTypeTag { - type Error = anyhow::Error; - fn try_into(self) -> Result { - parse_sui_type_tag(&self.0) - } -} - -impl From for SuiTypeTag { - fn from(tag: TypeTag) -> Self { - Self(format!("{}", tag)) - } -} - -#[derive(Serialize, Deserialize, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub enum RPCTransactionRequestParams { - TransferObjectRequestParams(TransferObjectParams), - MoveCallRequestParams(MoveCallParams), -} - -#[derive(Serialize, Deserialize, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct TransferObjectParams { - pub recipient: SuiAddress, - pub object_id: ObjectID, -} - -#[derive(Serialize, Deserialize, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct MoveCallParams { - pub package_object_id: ObjectID, - pub module: String, - pub function: String, - #[serde(default)] - pub type_arguments: Vec, - pub arguments: Vec, -} - -#[serde_as] -#[derive(Serialize, Deserialize, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct TransactionBlockBytes { - /// BCS serialized transaction data bytes without its type tag, as base-64 - /// encoded string. - pub tx_bytes: Base64, - /// the gas objects to be used - pub gas: Vec, - /// objects to be used in this transaction - pub input_objects: Vec, -} - -impl TransactionBlockBytes { - pub fn from_data(data: TransactionData) -> Result { - Ok(Self { - tx_bytes: Base64::from_bytes(bcs::to_bytes(&data)?.as_slice()), - gas: data - .gas() - .iter() - .map(|obj_ref| SuiObjectRef::from(*obj_ref)) - .collect(), - input_objects: data - .input_objects()? - .into_iter() - .map(SuiInputObjectKind::from) - .collect(), - }) - } - - pub fn to_data(self) -> Result { - bcs::from_bytes::(&self.tx_bytes.to_vec().map_err(|e| anyhow::anyhow!(e))?) - .map_err(|e| anyhow::anyhow!(e)) - } -} - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] -#[serde(rename = "OwnedObjectRef")] -pub struct OwnedObjectRef { - pub owner: Owner, - pub reference: SuiObjectRef, -} - -impl OwnedObjectRef { - pub fn object_id(&self) -> ObjectID { - self.reference.object_id - } - pub fn version(&self) -> SequenceNumber { - self.reference.version - } -} - -#[derive(Eq, PartialEq, Debug, Clone, Serialize, Deserialize, JsonSchema)] -#[serde(tag = "type", rename_all = "camelCase")] -pub enum SuiCallArg { - // Needs to become an Object Ref or Object ID, depending on object type - Object(SuiObjectArg), - // pure value, bcs encoded - Pure(SuiPureValue), -} - -impl SuiCallArg { - pub fn try_from( - value: CallArg, - layout: Option<&MoveTypeLayout>, - ) -> Result { - Ok(match value { - CallArg::Pure(p) => SuiCallArg::Pure(SuiPureValue { - value_type: layout.map(|l| l.into()), - value: SuiJsonValue::from_bcs_bytes(layout, &p)?, - }), - CallArg::Object(ObjectArg::ImmOrOwnedObject((id, version, digest))) => { - SuiCallArg::Object(SuiObjectArg::ImmOrOwnedObject { - object_id: id, - version, - digest, - }) - } - CallArg::Object(ObjectArg::SharedObject { - id, - initial_shared_version, - mutable, - }) => SuiCallArg::Object(SuiObjectArg::SharedObject { - object_id: id, - initial_shared_version, - mutable, - }), - CallArg::Object(ObjectArg::Receiving((object_id, version, digest))) => { - SuiCallArg::Object(SuiObjectArg::Receiving { - object_id, - version, - digest, - }) - } - }) - } - - pub fn pure(&self) -> Option<&SuiJsonValue> { - match self { - SuiCallArg::Pure(v) => Some(&v.value), - _ => None, - } - } - - pub fn object(&self) -> Option<&ObjectID> { - match self { - SuiCallArg::Object(SuiObjectArg::SharedObject { object_id, .. }) - | SuiCallArg::Object(SuiObjectArg::ImmOrOwnedObject { object_id, .. }) - | SuiCallArg::Object(SuiObjectArg::Receiving { object_id, .. }) => Some(object_id), - _ => None, - } - } -} - -#[serde_as] -#[derive(Eq, PartialEq, Debug, Clone, Serialize, Deserialize, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct SuiPureValue { - #[schemars(with = "Option")] - #[serde_as(as = "Option")] - value_type: Option, - value: SuiJsonValue, -} - -impl SuiPureValue { - pub fn value(&self) -> SuiJsonValue { - self.value.clone() - } - - pub fn value_type(&self) -> Option { - self.value_type.clone() - } -} - -#[serde_as] -#[derive(Eq, PartialEq, Debug, Clone, Serialize, Deserialize, JsonSchema)] -#[serde(tag = "objectType", rename_all = "camelCase")] -pub enum SuiObjectArg { - // A Move object, either immutable, or owned mutable. - #[serde(rename_all = "camelCase")] - ImmOrOwnedObject { - object_id: ObjectID, - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - version: SequenceNumber, - digest: ObjectDigest, - }, - // A Move object that's shared. - // SharedObject::mutable controls whether caller asks for a mutable reference to shared - // object. - #[serde(rename_all = "camelCase")] - SharedObject { - object_id: ObjectID, - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - initial_shared_version: SequenceNumber, - mutable: bool, - }, - // A reference to a Move object that's going to be received in the transaction. - #[serde(rename_all = "camelCase")] - Receiving { - object_id: ObjectID, - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - version: SequenceNumber, - digest: ObjectDigest, - }, -} - -#[serde_as] -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)] -#[serde(rename = "LoadedChildObject", rename_all = "camelCase")] -pub struct SuiLoadedChildObject { - object_id: ObjectID, - #[schemars(with = "AsSequenceNumber")] - #[serde_as(as = "AsSequenceNumber")] - sequence_number: SequenceNumber, -} - -impl SuiLoadedChildObject { - pub fn new(object_id: ObjectID, sequence_number: SequenceNumber) -> Self { - Self { - object_id, - sequence_number, - } - } - - pub fn object_id(&self) -> ObjectID { - self.object_id - } - - pub fn sequence_number(&self) -> SequenceNumber { - self.sequence_number - } -} - -#[serde_as] -#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone, Default)] -#[serde(rename_all = "camelCase", rename = "LoadedChildObjectsResponse")] -pub struct SuiLoadedChildObjectsResponse { - pub loaded_child_objects: Vec, -} - -#[derive(Clone)] -pub struct EffectsWithInput { - pub effects: SuiTransactionBlockEffects, - pub input: TransactionData, -} - -impl From for SuiTransactionBlockEffects { - fn from(e: EffectsWithInput) -> Self { - e.effects - } -} - -#[serde_as] -#[derive(Clone, Debug, JsonSchema, Serialize, Deserialize)] -pub enum TransactionFilter { - /// Query by checkpoint. - Checkpoint( - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - CheckpointSequenceNumber, - ), - /// Query by move function. - MoveFunction { - package: ObjectID, - module: Option, - function: Option, - }, - /// Query by input object. - InputObject(ObjectID), - /// Query by changed object, including created, mutated and unwrapped - /// objects. - ChangedObject(ObjectID), - /// Query by sender address. - FromAddress(SuiAddress), - /// Query by recipient address. - ToAddress(SuiAddress), - /// Query by sender and recipient address. - FromAndToAddress { from: SuiAddress, to: SuiAddress }, - /// Query txs that have a given address as sender or recipient. - FromOrToAddress { addr: SuiAddress }, - /// Query by transaction kind - TransactionKind(String), - /// Query transactions of any given kind in the input. - TransactionKindIn(Vec), -} - -impl Filter for TransactionFilter { - fn matches(&self, item: &EffectsWithInput) -> bool { - let _scope = monitored_scope("TransactionFilter::matches"); - match self { - TransactionFilter::InputObject(o) => { - let Ok(input_objects) = item.input.input_objects() else { - return false; - }; - input_objects.iter().any(|object| object.object_id() == *o) - } - TransactionFilter::ChangedObject(o) => item - .effects - .mutated() - .iter() - .any(|oref: &OwnedObjectRef| &oref.reference.object_id == o), - TransactionFilter::FromAddress(a) => &item.input.sender() == a, - TransactionFilter::ToAddress(a) => { - let mutated: &[OwnedObjectRef] = item.effects.mutated(); - mutated.iter().chain(item.effects.unwrapped().iter()).any(|oref: &OwnedObjectRef| { - matches!(oref.owner, Owner::AddressOwner(owner) if owner == *a) - }) - } - TransactionFilter::FromAndToAddress { from, to } => { - Self::FromAddress(*from).matches(item) && Self::ToAddress(*to).matches(item) - } - TransactionFilter::MoveFunction { - package, - module, - function, - } => item.input.move_calls().into_iter().any(|(p, m, f)| { - p == package - && (module.is_none() || matches!(module, Some(m2) if m2 == &m.to_string())) - && (function.is_none() || matches!(function, Some(f2) if f2 == &f.to_string())) - }), - TransactionFilter::TransactionKind(kind) => item.input.kind().to_string() == *kind, - TransactionFilter::TransactionKindIn(kinds) => { - kinds.contains(&item.input.kind().to_string()) - } - // these filters are not supported, rpc will reject these filters on subscription - TransactionFilter::Checkpoint(_) => false, - TransactionFilter::FromOrToAddress { addr: _ } => false, - } - } -} diff --git a/crates/sui-json-rpc-types/src/unit_tests/rpc_types_tests.rs b/crates/sui-json-rpc-types/src/unit_tests/rpc_types_tests.rs deleted file mode 100644 index a51264d72d6..00000000000 --- a/crates/sui-json-rpc-types/src/unit_tests/rpc_types_tests.rs +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::str::FromStr; - -use anyhow::anyhow; -use move_core_types::{ - annotated_value::{MoveStruct, MoveValue}, - ident_str, - identifier::Identifier, - language_storage::{StructTag, TypeTag}, -}; -use serde_json::json; -use sui_types::{ - base_types::{ObjectDigest, ObjectID, SequenceNumber, SuiAddress}, - gas_coin::GasCoin, - object::{MoveObject, Owner}, - parse_sui_struct_tag, MOVE_STDLIB_ADDRESS, SUI_FRAMEWORK_ADDRESS, -}; - -use crate::{ObjectChange, SuiMoveStruct, SuiMoveValue}; - -#[test] -fn test_move_value_to_sui_coin() { - let id = ObjectID::random(); - let value = 10000; - let coin = GasCoin::new(id, value); - - let move_object = MoveObject::new_gas_coin(SequenceNumber::new(), id, value); - let layout = GasCoin::layout(); - - let move_struct = move_object.to_move_struct(&layout).unwrap(); - let sui_struct = SuiMoveStruct::from(move_struct); - let gas_coin = GasCoin::try_from(&sui_struct).unwrap(); - assert_eq!(coin.value(), gas_coin.value()); - assert_eq!(coin.id(), gas_coin.id()); -} - -#[test] -fn test_move_value_to_string() { - let test_string = "Some test string"; - let bytes = test_string.as_bytes(); - let values = bytes - .iter() - .map(|u8| MoveValue::U8(*u8)) - .collect::>(); - - let move_value = MoveValue::Struct(MoveStruct { - type_: StructTag { - address: MOVE_STDLIB_ADDRESS, - module: ident_str!("string").to_owned(), - name: ident_str!("String").to_owned(), - type_params: vec![], - }, - fields: vec![(ident_str!("bytes").to_owned(), MoveValue::Vector(values))], - }); - - let sui_value = SuiMoveValue::from(move_value); - - assert!(matches!(sui_value, SuiMoveValue::String(s) if s == test_string)); -} - -#[test] -fn test_option() { - // bugfix for https://github.com/MystenLabs/sui/issues/4995 - let option = MoveValue::Struct(MoveStruct { - type_: StructTag { - address: MOVE_STDLIB_ADDRESS, - module: Identifier::from_str("option").unwrap(), - name: Identifier::from_str("Option").unwrap(), - type_params: vec![TypeTag::U8], - }, - fields: vec![( - Identifier::from_str("vec").unwrap(), - MoveValue::Vector(vec![MoveValue::U8(5)]), - )], - }); - let sui_value = SuiMoveValue::from(option); - assert!(matches!( - sui_value, - SuiMoveValue::Option(value) if *value == Some(SuiMoveValue::Number(5)) - )); -} - -#[test] -fn test_move_value_to_url() { - let test_url = "http://testing.com"; - let bytes = test_url.as_bytes(); - let values = bytes - .iter() - .map(|u8| MoveValue::U8(*u8)) - .collect::>(); - - let string_move_value = MoveValue::Struct(MoveStruct { - type_: StructTag { - address: MOVE_STDLIB_ADDRESS, - module: ident_str!("string").to_owned(), - name: ident_str!("String").to_owned(), - type_params: vec![], - }, - fields: vec![(ident_str!("bytes").to_owned(), MoveValue::Vector(values))], - }); - - let url_move_value = MoveValue::Struct(MoveStruct { - type_: StructTag { - address: SUI_FRAMEWORK_ADDRESS, - module: ident_str!("url").to_owned(), - name: ident_str!("Url").to_owned(), - type_params: vec![], - }, - fields: vec![(ident_str!("url").to_owned(), string_move_value)], - }); - - let sui_value = SuiMoveValue::from(url_move_value); - - assert!(matches!(sui_value, SuiMoveValue::String(s) if s == test_url)); -} - -#[test] -fn test_serde() { - let test_values = [ - SuiMoveValue::Number(u32::MAX), - SuiMoveValue::UID { - id: ObjectID::random(), - }, - SuiMoveValue::String("some test string".to_string()), - SuiMoveValue::Address(SuiAddress::random_for_testing_only()), - SuiMoveValue::Bool(true), - SuiMoveValue::Option(Box::new(None)), - SuiMoveValue::Vector(vec![ - SuiMoveValue::Number(1000000), - SuiMoveValue::Number(2000000), - SuiMoveValue::Number(3000000), - ]), - ]; - - for value in test_values { - let json = serde_json::to_string(&value).unwrap(); - let serde_value: SuiMoveValue = serde_json::from_str(&json) - .map_err(|e| anyhow!("Serde failed for [{:?}], Error msg : {}", value, e)) - .unwrap(); - assert_eq!( - value, serde_value, - "Error converting {:?} [{json}], got {:?}", - value, serde_value - ) - } -} - -#[test] -fn test_serde_bytearray() { - // ensure that we serialize byte arrays as number array - let test_values = MoveValue::Vector(vec![MoveValue::U8(1), MoveValue::U8(2), MoveValue::U8(3)]); - let sui_move_value = SuiMoveValue::from(test_values); - let json = serde_json::to_value(&sui_move_value).unwrap(); - assert_eq!(json, json!([1, 2, 3])); -} - -#[test] -fn test_serde_number() { - // ensure that we serialize byte arrays as number array - let test_values = MoveValue::U8(1); - let sui_move_value = SuiMoveValue::from(test_values); - let json = serde_json::to_value(&sui_move_value).unwrap(); - assert_eq!(json, json!(1)); - let test_values = MoveValue::U16(1); - let sui_move_value = SuiMoveValue::from(test_values); - let json = serde_json::to_value(&sui_move_value).unwrap(); - assert_eq!(json, json!(1)); - let test_values = MoveValue::U32(1); - let sui_move_value = SuiMoveValue::from(test_values); - let json = serde_json::to_value(&sui_move_value).unwrap(); - assert_eq!(json, json!(1)); -} - -#[test] -fn test_type_tag_struct_tag_devnet_inc_222() { - let offending_tags = [ - "0x1::address::MyType", - "0x1::vector::MyType", - "0x1::address::MyType<0x1::address::OtherType>", - "0x1::address::MyType<0x1::address::OtherType, 0x1::vector::VecTyper>", - "0x1::address::address<0x1::vector::address, 0x1::vector::vector>", - ]; - - for tag in offending_tags { - let oc = ObjectChange::Created { - sender: Default::default(), - owner: Owner::Immutable, - object_type: parse_sui_struct_tag(tag).unwrap(), - object_id: ObjectID::random(), - version: Default::default(), - digest: ObjectDigest::random(), - }; - - let serde_json = serde_json::to_string(&oc).unwrap(); - let deser: ObjectChange = serde_json::from_str(&serde_json).unwrap(); - assert_eq!(oc, deser); - } -} diff --git a/crates/sui-json-rpc-types/src/unit_tests/sui_move_tests.rs b/crates/sui-json-rpc-types/src/unit_tests/sui_move_tests.rs deleted file mode 100644 index 6d2baa10bc2..00000000000 --- a/crates/sui-json-rpc-types/src/unit_tests/sui_move_tests.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use sui_enum_compat_util::*; - -use crate::{SuiMoveStruct, SuiMoveValue}; - -#[test] -fn enforce_order_test() { - let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.extend(["tests", "staged", "sui_move_struct.yaml"]); - check_enum_compat_order::(path); - - let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.extend(["tests", "staged", "sui_move_value.yaml"]); - check_enum_compat_order::(path); -} diff --git a/crates/sui-json-rpc/Cargo.toml b/crates/sui-json-rpc/Cargo.toml deleted file mode 100644 index bdc4cfd9afc..00000000000 --- a/crates/sui-json-rpc/Cargo.toml +++ /dev/null @@ -1,58 +0,0 @@ -[package] -name = "sui-json-rpc" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -arc-swap.workspace = true -fastcrypto.workspace = true -jsonrpsee.workspace = true -hyper.workspace = true -itertools.workspace = true -indexmap.workspace = true -tower.workspace = true -axum.workspace = true -tower-http.workspace = true -move-binary-format.workspace = true -move-core-types.workspace = true -move-package.workspace = true -move-bytecode-utils.workspace = true -prometheus.workspace = true -anyhow.workspace = true -tracing.workspace = true -async-trait.workspace = true -serde.workspace = true -futures.workspace = true -tokio = { workspace = true, features = ["full"] } -signature.workspace = true -thiserror.workspace = true -bcs.workspace = true -eyre.workspace = true -once_cell.workspace = true -serde_json.workspace = true - -tap.workspace = true - -sui-core.workspace = true -sui-storage.workspace = true -sui-types.workspace = true -sui-json.workspace = true -sui-json-rpc-api.workspace = true -sui-open-rpc.workspace = true -sui-open-rpc-macros.workspace = true -sui-protocol-config.workspace = true -sui-json-rpc-types.workspace = true -sui-transaction-builder.workspace = true -mysten-metrics.workspace = true -shared-crypto.workspace = true -typed-store-error.workspace = true -cached.workspace = true - -[dev-dependencies] -mockall.workspace = true -expect-test.workspace = true -sui-types = { workspace = true, features = ["test-utils"] } -telemetry-subscribers.workspace = true diff --git a/crates/sui-json-rpc/src/balance_changes.rs b/crates/sui-json-rpc/src/balance_changes.rs deleted file mode 100644 index 51973d77bfa..00000000000 --- a/crates/sui-json-rpc/src/balance_changes.rs +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::{BTreeMap, HashMap, HashSet}, - ops::Neg, -}; - -use async_trait::async_trait; -use move_core_types::language_storage::TypeTag; -use sui_json_rpc_types::BalanceChange; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber}, - coin::Coin, - digests::ObjectDigest, - effects::{TransactionEffects, TransactionEffectsAPI}, - execution_status::ExecutionStatus, - gas_coin::GAS, - object::{Object, Owner}, - storage::WriteKind, - transaction::InputObjectKind, -}; -use tokio::sync::RwLock; - -pub async fn get_balance_changes_from_effect, E>( - object_provider: &P, - effects: &TransactionEffects, - input_objs: Vec, - mocked_coin: Option, -) -> Result, E> { - let (_, gas_owner) = effects.gas_object(); - - // Only charge gas when tx fails, skip all object parsing - if effects.status() != &ExecutionStatus::Success { - return Ok(vec![BalanceChange { - owner: gas_owner, - coin_type: GAS::type_tag(), - amount: effects.gas_cost_summary().net_gas_usage().neg() as i128, - }]); - } - - let all_mutated = effects - .all_changed_objects() - .into_iter() - .filter_map(|((id, version, digest), _, _)| { - if matches!(mocked_coin, Some(coin) if id == coin) { - return None; - } - Some((id, version, Some(digest))) - }) - .collect::>(); - - let input_objs_to_digest = input_objs - .iter() - .filter_map(|k| match k { - InputObjectKind::ImmOrOwnedMoveObject(o) => Some((o.0, o.2)), - InputObjectKind::MovePackage(_) | InputObjectKind::SharedMoveObject { .. } => None, - }) - .collect::>(); - let unwrapped_then_deleted = effects - .unwrapped_then_deleted() - .iter() - .map(|e| e.0) - .collect::>(); - get_balance_changes( - object_provider, - &effects - .modified_at_versions() - .into_iter() - .filter_map(|(id, version)| { - if matches!(mocked_coin, Some(coin) if id == coin) { - return None; - } - // We won't be able to get dynamic object from object provider today - if unwrapped_then_deleted.contains(&id) { - return None; - } - Some((id, version, input_objs_to_digest.get(&id).cloned())) - }) - .collect::>(), - &all_mutated, - ) - .await -} - -pub async fn get_balance_changes, E>( - object_provider: &P, - modified_at_version: &[(ObjectID, SequenceNumber, Option)], - all_mutated: &[(ObjectID, SequenceNumber, Option)], -) -> Result, E> { - // 1. subtract all input coins - let balances = fetch_coins(object_provider, modified_at_version) - .await? - .into_iter() - .fold( - BTreeMap::<_, i128>::new(), - |mut acc, (owner, type_, amount)| { - *acc.entry((owner, type_)).or_default() -= amount as i128; - acc - }, - ); - // 2. add all mutated coins - let balances = fetch_coins(object_provider, all_mutated) - .await? - .into_iter() - .fold(balances, |mut acc, (owner, type_, amount)| { - *acc.entry((owner, type_)).or_default() += amount as i128; - acc - }); - - Ok(balances - .into_iter() - .filter_map(|((owner, coin_type), amount)| { - if amount == 0 { - return None; - } - Some(BalanceChange { - owner, - coin_type, - amount, - }) - }) - .collect()) -} - -async fn fetch_coins, E>( - object_provider: &P, - objects: &[(ObjectID, SequenceNumber, Option)], -) -> Result, E> { - let mut all_mutated_coins = vec![]; - for (id, version, digest_opt) in objects { - // TODO: use multi get object - let o = object_provider.get_object(id, version).await?; - if let Some(type_) = o.type_() { - if type_.is_coin() { - if let Some(digest) = digest_opt { - // TODO: can we return Err here instead? - assert_eq!( - *digest, - o.digest(), - "Object digest mismatch--got bad data from object_provider?" - ) - } - let [coin_type]: [TypeTag; 1] = - type_.clone().into_type_params().try_into().unwrap(); - all_mutated_coins.push(( - o.owner, - coin_type, - // we know this is a coin, safe to unwrap - Coin::extract_balance_if_coin(&o).unwrap().unwrap(), - )) - } - } - } - Ok(all_mutated_coins) -} - -#[async_trait] -pub trait ObjectProvider { - type Error; - async fn get_object( - &self, - id: &ObjectID, - version: &SequenceNumber, - ) -> Result; - async fn find_object_lt_or_eq_version( - &self, - id: &ObjectID, - version: &SequenceNumber, - ) -> Result, Self::Error>; -} - -pub struct ObjectProviderCache

    { - object_cache: RwLock>, - last_version_cache: RwLock>, - provider: P, -} - -impl

    ObjectProviderCache

    { - pub fn new(provider: P) -> Self { - Self { - object_cache: Default::default(), - last_version_cache: Default::default(), - provider, - } - } - - pub fn new_with_cache( - provider: P, - written_objects: BTreeMap, - ) -> Self { - let mut object_cache = BTreeMap::new(); - let mut last_version_cache = BTreeMap::new(); - - for (object_id, (object_ref, object, _)) in written_objects { - let key = (object_id, object_ref.1); - object_cache.insert(key, object.clone()); - - match last_version_cache.get_mut(&key) { - Some(existing_seq_number) => { - if object_ref.1 > *existing_seq_number { - *existing_seq_number = object_ref.1 - } - } - None => { - last_version_cache.insert(key, object_ref.1); - } - } - } - - Self { - object_cache: RwLock::new(object_cache), - last_version_cache: RwLock::new(last_version_cache), - provider, - } - } -} - -#[async_trait] -impl ObjectProvider for ObjectProviderCache

    -where - P: ObjectProvider + Sync + Send, - E: Sync + Send, -{ - type Error = P::Error; - - async fn get_object( - &self, - id: &ObjectID, - version: &SequenceNumber, - ) -> Result { - if let Some(o) = self.object_cache.read().await.get(&(*id, *version)) { - return Ok(o.clone()); - } - let o = self.provider.get_object(id, version).await?; - self.object_cache - .write() - .await - .insert((*id, *version), o.clone()); - Ok(o) - } - - async fn find_object_lt_or_eq_version( - &self, - id: &ObjectID, - version: &SequenceNumber, - ) -> Result, Self::Error> { - if let Some(version) = self.last_version_cache.read().await.get(&(*id, *version)) { - return Ok(self.get_object(id, version).await.ok()); - } - if let Some(o) = self - .provider - .find_object_lt_or_eq_version(id, version) - .await? - { - self.object_cache - .write() - .await - .insert((*id, o.version()), o.clone()); - self.last_version_cache - .write() - .await - .insert((*id, *version), o.version()); - Ok(Some(o)) - } else { - Ok(None) - } - } -} diff --git a/crates/sui-json-rpc/src/coin_api.rs b/crates/sui-json-rpc/src/coin_api.rs deleted file mode 100644 index 68b02744e6e..00000000000 --- a/crates/sui-json-rpc/src/coin_api.rs +++ /dev/null @@ -1,1409 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::HashMap, sync::Arc}; - -use async_trait::async_trait; -use cached::{proc_macro::cached, SizedCache}; -use jsonrpsee::{core::RpcResult, RpcModule}; -#[cfg(test)] -use mockall::automock; -use move_core_types::language_storage::{StructTag, TypeTag}; -use mysten_metrics::spawn_monitored_task; -use sui_core::authority::AuthorityState; -use sui_json_rpc_api::{cap_page_limit, CoinReadApiOpenRpc, CoinReadApiServer, JsonRpcMetrics}; -use sui_json_rpc_types::{Balance, CoinPage, SuiCoinMetadata}; -use sui_open_rpc::Module; -use sui_storage::{indexes::TotalBalance, key_value_store::TransactionKeyValueStore}; -use sui_types::{ - balance::Supply, - base_types::{ObjectID, SuiAddress}, - coin::{CoinMetadata, TreasuryCap}, - effects::TransactionEffectsAPI, - gas_coin::{GAS, TOTAL_SUPPLY_MIST}, - object::Object, - parse_sui_struct_tag, -}; -use tap::TapFallible; -use tracing::{debug, info, instrument}; - -use crate::{ - authority_state::StateRead, - error::{Error, RpcInterimResult, SuiRpcInputError}, - with_tracing, SuiRpcModule, -}; - -pub fn parse_to_struct_tag(coin_type: &str) -> Result { - parse_sui_struct_tag(coin_type) - .map_err(|e| SuiRpcInputError::CannotParseSuiStructTag(format!("{e}"))) -} - -pub fn parse_to_type_tag(coin_type: Option) -> Result { - Ok(TypeTag::Struct(Box::new(match coin_type { - Some(c) => parse_to_struct_tag(&c)?, - None => GAS::type_(), - }))) -} - -pub struct CoinReadApi { - // Trait object w/ Box as we do not need to share this across multiple threads - internal: Box, -} - -impl CoinReadApi { - pub fn new( - state: Arc, - transaction_kv_store: Arc, - metrics: Arc, - ) -> Self { - Self { - internal: Box::new(CoinReadInternalImpl::new( - state, - transaction_kv_store, - metrics, - )), - } - } -} - -impl SuiRpcModule for CoinReadApi { - fn rpc(self) -> RpcModule { - self.into_rpc() - } - - fn rpc_doc_module() -> Module { - CoinReadApiOpenRpc::module_doc() - } -} - -#[async_trait] -impl CoinReadApiServer for CoinReadApi { - #[instrument(skip(self))] - async fn get_coins( - &self, - owner: SuiAddress, - coin_type: Option, - // exclusive cursor if `Some`, otherwise start from the beginning - cursor: Option, - limit: Option, - ) -> RpcResult { - with_tracing!(async move { - let coin_type_tag = parse_to_type_tag(coin_type)?; - - let cursor = match cursor { - Some(c) => (coin_type_tag.to_string(), c), - // If cursor is not specified, we need to start from the beginning of the coin type, - // which is the minimal possible ObjectID. - None => (coin_type_tag.to_string(), ObjectID::ZERO), - }; - - self.internal - .get_coins_iterator( - owner, cursor, limit, true, // only care about one type of coin - ) - .await - }) - } - - #[instrument(skip(self))] - async fn get_all_coins( - &self, - owner: SuiAddress, - // exclusive cursor if `Some`, otherwise start from the beginning - cursor: Option, - limit: Option, - ) -> RpcResult { - with_tracing!(async move { - let cursor = match cursor { - Some(object_id) => { - let obj = self.internal.get_object(&object_id).await?; - match obj { - Some(obj) => { - let coin_type = obj.coin_type_maybe(); - if coin_type.is_none() { - Err(SuiRpcInputError::GenericInvalid( - "cursor is not a coin".to_string(), - )) - } else { - Ok((coin_type.unwrap().to_string(), object_id)) - } - } - None => Err(SuiRpcInputError::GenericInvalid( - "cursor not found".to_string(), - )), - } - } - None => { - // If cursor is None, start from the beginning - Ok((String::from_utf8([0u8].to_vec()).unwrap(), ObjectID::ZERO)) - } - }?; - - let coins = self - .internal - .get_coins_iterator( - owner, cursor, limit, false, // return all types of coins - ) - .await?; - - Ok(coins) - }) - } - - #[instrument(skip(self))] - async fn get_balance( - &self, - owner: SuiAddress, - coin_type: Option, - ) -> RpcResult { - with_tracing!(async move { - let coin_type_tag = parse_to_type_tag(coin_type)?; - let balance = self - .internal - .get_balance(owner, coin_type_tag.clone()) - .await - .tap_err(|e| { - debug!(?owner, "Failed to get balance with error: {:?}", e); - })?; - Ok(Balance { - coin_type: coin_type_tag.to_string(), - coin_object_count: balance.num_coins as usize, - total_balance: balance.balance as u128, - // note: LockedCoin is deprecated - locked_balance: Default::default(), - }) - }) - } - - #[instrument(skip(self))] - async fn get_all_balances(&self, owner: SuiAddress) -> RpcResult> { - with_tracing!(async move { - let all_balance = self.internal.get_all_balance(owner).await.tap_err(|e| { - debug!(?owner, "Failed to get all balance with error: {:?}", e); - })?; - Ok(all_balance - .iter() - .map(|(coin_type, balance)| { - Balance { - coin_type: coin_type.to_string(), - coin_object_count: balance.num_coins as usize, - total_balance: balance.balance as u128, - // note: LockedCoin is deprecated - locked_balance: Default::default(), - } - }) - .collect()) - }) - } - - #[instrument(skip(self))] - async fn get_coin_metadata(&self, coin_type: String) -> RpcResult> { - with_tracing!(async move { - let coin_struct = parse_to_struct_tag(&coin_type)?; - let metadata_object = self - .internal - .find_package_object( - &coin_struct.address.into(), - CoinMetadata::type_(coin_struct), - ) - .await - .ok(); - Ok(metadata_object.and_then(|v: Object| v.try_into().ok())) - }) - } - - #[instrument(skip(self))] - async fn get_total_supply(&self, coin_type: String) -> RpcResult { - with_tracing!(async move { - let coin_struct = parse_to_struct_tag(&coin_type)?; - Ok(if GAS::is_gas(&coin_struct) { - Supply { - value: TOTAL_SUPPLY_MIST, - } - } else { - let treasury_cap_object = self - .internal - .find_package_object( - &coin_struct.address.into(), - TreasuryCap::type_(coin_struct), - ) - .await?; - let treasury_cap = TreasuryCap::from_bcs_bytes( - treasury_cap_object.data.try_as_move().unwrap().contents(), - ) - .map_err(Error::from)?; - treasury_cap.total_supply - }) - }) - } -} - -#[cached( - type = "SizedCache", - create = "{ SizedCache::with_size(10000) }", - convert = r#"{ format!("{}{}", package_id, object_struct_tag) }"#, - result = true -)] -async fn find_package_object_id( - state: Arc, - package_id: ObjectID, - object_struct_tag: StructTag, - kv_store: Arc, -) -> RpcInterimResult { - spawn_monitored_task!(async move { - let publish_txn_digest = state.find_publish_txn_digest(package_id)?; - - let (_, effect) = state - .get_executed_transaction_and_effects(publish_txn_digest, kv_store) - .await?; - - for ((id, _, _), _) in effect.created() { - if let Ok(object_read) = state.get_object_read(&id) { - if let Ok(object) = object_read.into_object() { - if matches!(object.type_(), Some(type_) if type_.is(&object_struct_tag)) { - return Ok(id); - } - } - } - } - Err(SuiRpcInputError::GenericNotFound(format!( - "Cannot find object [{}] from [{}] package event.", - object_struct_tag, package_id, - )) - .into()) - }) - .await? -} - -/// CoinReadInternal trait to capture logic of interactions with AuthorityState -/// and metrics This allows us to also mock internal implementation for testing -#[cfg_attr(test, automock)] -#[async_trait] -pub trait CoinReadInternal { - fn get_state(&self) -> Arc; - async fn get_object(&self, object_id: &ObjectID) -> RpcInterimResult>; - async fn get_balance( - &self, - owner: SuiAddress, - coin_type: TypeTag, - ) -> RpcInterimResult; - async fn get_all_balance( - &self, - owner: SuiAddress, - ) -> RpcInterimResult>>; - async fn find_package_object( - &self, - package_id: &ObjectID, - object_struct_tag: StructTag, - ) -> RpcInterimResult; - async fn get_coins_iterator( - &self, - owner: SuiAddress, - cursor: (String, ObjectID), - limit: Option, - one_coin_type_only: bool, - ) -> RpcInterimResult; -} - -pub struct CoinReadInternalImpl { - // Trait object w/ Arc as we have methods that require sharing this across multiple threads - state: Arc, - transaction_kv_store: Arc, - pub metrics: Arc, -} - -impl CoinReadInternalImpl { - pub fn new( - state: Arc, - transaction_kv_store: Arc, - metrics: Arc, - ) -> Self { - Self { - state, - transaction_kv_store, - metrics, - } - } -} - -#[async_trait] -impl CoinReadInternal for CoinReadInternalImpl { - fn get_state(&self) -> Arc { - self.state.clone() - } - - async fn get_object(&self, object_id: &ObjectID) -> RpcInterimResult> { - Ok(self.state.get_object(object_id).await?) - } - - async fn get_balance( - &self, - owner: SuiAddress, - coin_type: TypeTag, - ) -> RpcInterimResult { - Ok(self.state.get_balance(owner, coin_type).await?) - } - - async fn get_all_balance( - &self, - owner: SuiAddress, - ) -> RpcInterimResult>> { - Ok(self.state.get_all_balance(owner).await?) - } - - async fn find_package_object( - &self, - package_id: &ObjectID, - object_struct_tag: StructTag, - ) -> RpcInterimResult { - let state = self.get_state(); - let kv_store = self.transaction_kv_store.clone(); - let object_id = - find_package_object_id(state, *package_id, object_struct_tag, kv_store).await?; - Ok(self.state.get_object_read(&object_id)?.into_object()?) - } - - async fn get_coins_iterator( - &self, - owner: SuiAddress, - cursor: (String, ObjectID), - limit: Option, - one_coin_type_only: bool, - ) -> RpcInterimResult { - let limit = cap_page_limit(limit); - self.metrics.get_coins_limit.report(limit as u64); - let state = self.get_state(); - let mut data = spawn_monitored_task!(async move { - state.get_owned_coins(owner, cursor, limit + 1, one_coin_type_only) - }) - .await??; - - let has_next_page = data.len() > limit; - data.truncate(limit); - - self.metrics.get_coins_result_size.report(data.len() as u64); - self.metrics - .get_coins_result_size_total - .inc_by(data.len() as u64); - let next_cursor = data.last().map(|coin| coin.coin_object_id); - Ok(CoinPage { - data, - next_cursor, - has_next_page, - }) - } -} - -#[cfg(test)] -mod tests { - use expect_test::expect; - use jsonrpsee::types::ErrorObjectOwned; - use mockall::{mock, predicate}; - use move_core_types::{account_address::AccountAddress, language_storage::StructTag}; - use sui_json_rpc_types::Coin; - use sui_storage::{ - key_value_store::{ - KVStoreCheckpointData, KVStoreTransactionData, TransactionKeyValueStoreTrait, - }, - key_value_store_metrics::KeyValueStoreMetrics, - }; - use sui_types::{ - balance::Supply, - base_types::{ObjectID, SequenceNumber, SuiAddress}, - coin::TreasuryCap, - digests::{ObjectDigest, TransactionDigest, TransactionEventsDigest}, - effects::TransactionEffects, - error::{SuiError, SuiResult}, - gas_coin::GAS, - id::UID, - messages_checkpoint::{ - CheckpointContentsDigest, CheckpointDigest, CheckpointSequenceNumber, - }, - object::Object, - parse_sui_struct_tag, - utils::create_fake_transaction, - TypeTag, - }; - - use super::*; - use crate::authority_state::{MockStateRead, StateReadError}; - - mock! { - pub KeyValueStore {} - #[async_trait] - impl TransactionKeyValueStoreTrait for KeyValueStore { - async fn multi_get( - &self, - transactions: &[TransactionDigest], - effects: &[TransactionDigest], - events: &[TransactionEventsDigest], - ) -> SuiResult; - - async fn multi_get_checkpoints( - &self, - checkpoint_summaries: &[CheckpointSequenceNumber], - checkpoint_contents: &[CheckpointSequenceNumber], - checkpoint_summaries_by_digest: &[CheckpointDigest], - checkpoint_contents_by_digest: &[CheckpointContentsDigest], - ) -> SuiResult; - - async fn deprecated_get_transaction_checkpoint( - &self, - digest: TransactionDigest, - ) -> SuiResult>; - - async fn get_object(&self, object_id: ObjectID, version: SequenceNumber) -> SuiResult>; - - async fn multi_get_transaction_checkpoint( - &self, - digests: &[TransactionDigest], - ) -> SuiResult>>; - } - } - - impl CoinReadInternalImpl { - pub fn new_for_tests( - state: Arc, - kv_store: Option>, - ) -> Self { - let kv_store = kv_store.unwrap_or_else(|| Arc::new(MockKeyValueStore::new())); - let metrics = KeyValueStoreMetrics::new_for_tests(); - let transaction_kv_store = - Arc::new(TransactionKeyValueStore::new("rocksdb", metrics, kv_store)); - Self { - state, - transaction_kv_store, - metrics: Arc::new(JsonRpcMetrics::new_for_tests()), - } - } - } - - impl CoinReadApi { - pub fn new_for_tests( - state: Arc, - kv_store: Option>, - ) -> Self { - let kv_store = kv_store.unwrap_or_else(|| Arc::new(MockKeyValueStore::new())); - Self { - internal: Box::new(CoinReadInternalImpl::new_for_tests(state, Some(kv_store))), - } - } - } - - fn get_test_owner() -> SuiAddress { - AccountAddress::ONE.into() - } - - fn get_test_package_id() -> ObjectID { - ObjectID::from_hex_literal("0xf").unwrap() - } - - fn get_test_coin_type(package_id: ObjectID) -> String { - format!("{}::test_coin::TEST_COIN", package_id) - } - - fn get_test_coin_type_tag(coin_type: String) -> TypeTag { - TypeTag::Struct(Box::new(parse_sui_struct_tag(&coin_type).unwrap())) - } - - enum CoinType { - Gas, - Usdc, - } - - fn get_test_coin(id_hex_literal: Option<&str>, coin_type: CoinType) -> Coin { - let (arr, coin_type_string, balance, default_hex) = match coin_type { - CoinType::Gas => ([0; 32], GAS::type_().to_string(), 42, "0xA"), - CoinType::Usdc => ( - [1; 32], - "0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC".to_string(), - 24, - "0xB", - ), - }; - - let object_id = if let Some(literal) = id_hex_literal { - ObjectID::from_hex_literal(literal).unwrap() - } else { - ObjectID::from_hex_literal(default_hex).unwrap() - }; - - Coin { - coin_type: coin_type_string, - coin_object_id: object_id, - version: SequenceNumber::from_u64(1), - digest: ObjectDigest::from(arr), - balance, - previous_transaction: TransactionDigest::from(arr), - } - } - - fn get_test_treasury_cap_peripherals( - package_id: ObjectID, - ) -> (String, StructTag, StructTag, TreasuryCap, Object) { - let coin_name = get_test_coin_type(package_id); - let input_coin_struct = parse_sui_struct_tag(&coin_name).expect("should not fail"); - let treasury_cap_struct = TreasuryCap::type_(input_coin_struct.clone()); - let treasury_cap = TreasuryCap { - id: UID::new(get_test_package_id()), - total_supply: Supply { value: 420 }, - }; - let treasury_cap_object = - Object::treasury_cap_for_testing(input_coin_struct.clone(), treasury_cap.clone()); - ( - coin_name, - input_coin_struct, - treasury_cap_struct, - treasury_cap, - treasury_cap_object, - ) - } - - mod get_coins_tests { - use jsonrpsee::types::ErrorObjectOwned; - - use super::{super::*, *}; - - // Success scenarios - #[tokio::test] - async fn test_gas_coin_no_cursor() { - let owner = get_test_owner(); - let gas_coin = get_test_coin(None, CoinType::Gas); - let gas_coin_clone = gas_coin.clone(); - let mut mock_state = MockStateRead::new(); - mock_state - .expect_get_owned_coins() - .with( - predicate::eq(owner), - predicate::eq((GAS::type_().to_string(), ObjectID::ZERO)), - predicate::eq(51), - predicate::eq(true), - ) - .return_once(move |_, _, _, _| Ok(vec![gas_coin_clone])); - - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api.get_coins(owner, None, None, None).await; - assert!(response.is_ok()); - let result = response.unwrap(); - assert_eq!( - result, - CoinPage { - data: vec![gas_coin.clone()], - next_cursor: Some(gas_coin.coin_object_id), - has_next_page: false, - } - ); - } - - #[tokio::test] - async fn test_gas_coin_with_cursor() { - let owner = get_test_owner(); - let limit = 2; - let coins = vec![ - get_test_coin(Some("0xA"), CoinType::Gas), - get_test_coin(Some("0xAA"), CoinType::Gas), - get_test_coin(Some("0xAAA"), CoinType::Gas), - ]; - let coins_clone = coins.clone(); - let mut mock_state = MockStateRead::new(); - mock_state - .expect_get_owned_coins() - .with( - predicate::eq(owner), - predicate::eq((GAS::type_().to_string(), coins[0].coin_object_id)), - predicate::eq(limit + 1), - predicate::eq(true), - ) - .return_once(move |_, _, _, _| Ok(coins_clone)); - - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_coins(owner, None, Some(coins[0].coin_object_id), Some(limit)) - .await; - assert!(response.is_ok()); - let result = response.unwrap(); - assert_eq!( - result, - CoinPage { - data: coins[..limit].to_vec(), - next_cursor: Some(coins[limit - 1].coin_object_id), - has_next_page: true, - } - ); - } - - #[tokio::test] - async fn test_coin_no_cursor() { - let coin = get_test_coin(None, CoinType::Usdc); - let coin_clone = coin.clone(); - // Build request params - let owner = get_test_owner(); - let coin_type = coin.coin_type.clone(); - - let coin_type_tag = - TypeTag::Struct(Box::new(parse_sui_struct_tag(&coin.coin_type).unwrap())); - let mut mock_state = MockStateRead::new(); - mock_state - .expect_get_owned_coins() - .with( - predicate::eq(owner), - predicate::eq((coin_type_tag.to_string(), ObjectID::ZERO)), - predicate::eq(51), - predicate::eq(true), - ) - .return_once(move |_, _, _, _| Ok(vec![coin_clone])); - - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_coins(owner, Some(coin_type), None, None) - .await; - - assert!(response.is_ok()); - let result = response.unwrap(); - assert_eq!( - result, - CoinPage { - data: vec![coin.clone()], - next_cursor: Some(coin.coin_object_id), - has_next_page: false, - } - ); - } - - #[tokio::test] - async fn test_coin_with_cursor() { - let coins = vec![ - get_test_coin(Some("0xB"), CoinType::Usdc), - get_test_coin(Some("0xBB"), CoinType::Usdc), - get_test_coin(Some("0xBBB"), CoinType::Usdc), - ]; - let coins_clone = coins.clone(); - // Build request params - let owner = get_test_owner(); - let coin_type = coins[0].coin_type.clone(); - let cursor = coins[0].coin_object_id; - let limit = 2; - - let coin_type_tag = - TypeTag::Struct(Box::new(parse_sui_struct_tag(&coins[0].coin_type).unwrap())); - let mut mock_state = MockStateRead::new(); - mock_state - .expect_get_owned_coins() - .with( - predicate::eq(owner), - predicate::eq((coin_type_tag.to_string(), coins[0].coin_object_id)), - predicate::eq(limit + 1), - predicate::eq(true), - ) - .return_once(move |_, _, _, _| Ok(coins_clone)); - - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_coins(owner, Some(coin_type), Some(cursor), Some(limit)) - .await; - - assert!(response.is_ok()); - let result = response.unwrap(); - assert_eq!( - result, - CoinPage { - data: coins[..limit].to_vec(), - next_cursor: Some(coins[limit - 1].coin_object_id), - has_next_page: true, - } - ); - } - - // Expected error scenarios - #[tokio::test] - async fn test_invalid_coin_type() { - let owner = get_test_owner(); - let coin_type = "0x2::invalid::struct::tag"; - let mock_state = MockStateRead::new(); - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_coins(owner, Some(coin_type.to_string()), None, None) - .await; - - assert!(response.is_err()); - let error_result = response.unwrap_err(); - let error_object: ErrorObjectOwned = error_result.into(); - let expected = expect!["-32602"]; - expected.assert_eq(&error_object.code().to_string()); - let expected = expect![ - "Invalid struct type: 0x2::invalid::struct::tag. Got error: Expected end of token stream. Got: ::" - ]; - expected.assert_eq(error_object.message()); - } - - #[tokio::test] - async fn test_unrecognized_token() { - let owner = get_test_owner(); - let coin_type = "0x2::sui:🤵"; - let mock_state = MockStateRead::new(); - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_coins(owner, Some(coin_type.to_string()), None, None) - .await; - - assert!(response.is_err()); - let error_result = response.unwrap_err(); - let error_object: ErrorObjectOwned = error_result.into(); - let expected = expect!["-32602"]; - expected.assert_eq(&error_object.code().to_string()); - let expected = - expect!["Invalid struct type: 0x2::sui:🤵. Got error: unrecognized token: :🤵"]; - expected.assert_eq(error_object.message()); - } - - // Unexpected error scenarios - #[tokio::test] - async fn test_get_coins_iterator_index_store_not_available() { - let owner = get_test_owner(); - let coin_type = get_test_coin_type(get_test_package_id()); - let mut mock_state = MockStateRead::new(); - mock_state - .expect_get_owned_coins() - .returning(move |_, _, _, _| { - Err(StateReadError::Client( - SuiError::IndexStoreNotAvailable.into(), - )) - }); - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_coins(owner, Some(coin_type.to_string()), None, None) - .await; - - assert!(response.is_err()); - let error_result = response.unwrap_err(); - let error_object: ErrorObjectOwned = error_result.into(); - assert_eq!( - error_object.code(), - jsonrpsee::types::error::INVALID_PARAMS_CODE - ); - let expected = expect!["Index store not available on this Fullnode."]; - expected.assert_eq(error_object.message()); - } - - #[tokio::test] - async fn test_get_coins_iterator_typed_store_error() { - let owner = get_test_owner(); - let coin_type = get_test_coin_type(get_test_package_id()); - let mut mock_state = MockStateRead::new(); - mock_state - .expect_get_owned_coins() - .returning(move |_, _, _, _| { - Err(SuiError::Storage("mock rocksdb error".to_string()).into()) - }); - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_coins(owner, Some(coin_type.to_string()), None, None) - .await; - - assert!(response.is_err()); - let error_result = response.unwrap_err(); - let error_object: ErrorObjectOwned = error_result.into(); - assert_eq!( - error_object.code(), - jsonrpsee::types::error::INTERNAL_ERROR_CODE - ); - let expected = expect!["Storage error: mock rocksdb error"]; - expected.assert_eq(error_object.message()); - } - } - - mod get_all_coins_tests { - use sui_types::object::{MoveObject, Owner}; - - use super::{super::*, *}; - - // Success scenarios - #[tokio::test] - async fn test_no_cursor() { - let owner = get_test_owner(); - let gas_coin = get_test_coin(None, CoinType::Gas); - let gas_coin_clone = gas_coin.clone(); - let mut mock_state = MockStateRead::new(); - mock_state - .expect_get_owned_coins() - .with( - predicate::eq(owner), - predicate::eq((String::from_utf8([0u8].to_vec()).unwrap(), ObjectID::ZERO)), - predicate::eq(51), - predicate::eq(false), - ) - .return_once(move |_, _, _, _| Ok(vec![gas_coin_clone])); - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_all_coins(owner, None, Some(51)) - .await - .unwrap(); - assert_eq!(response.data.len(), 1); - assert_eq!(response.data[0], gas_coin); - } - - #[tokio::test] - async fn test_with_cursor() { - let owner = get_test_owner(); - let limit = 2; - let coins = vec![ - get_test_coin(Some("0xA"), CoinType::Gas), - get_test_coin(Some("0xAA"), CoinType::Gas), - get_test_coin(Some("0xAAA"), CoinType::Gas), - ]; - let coins_clone = coins.clone(); - let coin_move_object = MoveObject::new_gas_coin( - coins[0].version, - coins[0].coin_object_id, - coins[0].balance, - ); - let coin_object = Object::new_move( - coin_move_object, - Owner::Immutable, - coins[0].previous_transaction, - ); - let mut mock_state = MockStateRead::new(); - mock_state - .expect_get_object() - .return_once(move |_| Ok(Some(coin_object))); - mock_state - .expect_get_owned_coins() - .with( - predicate::eq(owner), - predicate::eq((coins[0].coin_type.clone(), coins[0].coin_object_id)), - predicate::eq(limit + 1), - predicate::eq(false), - ) - .return_once(move |_, _, _, _| Ok(coins_clone)); - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_all_coins(owner, Some(coins[0].coin_object_id), Some(limit)) - .await - .unwrap(); - assert_eq!(response.data.len(), limit); - assert_eq!(response.data, coins[..limit].to_vec()); - } - - // Expected error scenarios - #[tokio::test] - async fn test_object_is_not_coin() { - let owner = get_test_owner(); - let object_id = get_test_package_id(); - let (_, _, _, _, treasury_cap_object) = get_test_treasury_cap_peripherals(object_id); - let mut mock_state = MockStateRead::new(); - mock_state.expect_get_object().returning(move |obj_id| { - if obj_id == &object_id { - Ok(Some(treasury_cap_object.clone())) - } else { - panic!("should not be called with any other object id") - } - }); - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_all_coins(owner, Some(object_id), None) - .await; - - assert!(response.is_err()); - let error_result = response.unwrap_err(); - let error_object: ErrorObjectOwned = error_result.into(); - assert_eq!(error_object.code(), -32602); - let expected = expect!["-32602"]; - expected.assert_eq(&error_object.code().to_string()); - let expected = expect!["cursor is not a coin"]; - expected.assert_eq(error_object.message()); - } - - #[tokio::test] - async fn test_object_not_found() { - let owner = get_test_owner(); - let object_id = get_test_package_id(); - let mut mock_state = MockStateRead::new(); - mock_state.expect_get_object().returning(move |_| Ok(None)); - - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_all_coins(owner, Some(object_id), None) - .await; - - assert!(response.is_err()); - let error_result = response.unwrap_err(); - let error_object: ErrorObjectOwned = error_result.into(); - let expected = expect!["-32602"]; - expected.assert_eq(&error_object.code().to_string()); - let expected = expect!["cursor not found"]; - expected.assert_eq(error_object.message()); - } - } - - mod get_balance_tests { - use jsonrpsee::types::ErrorObjectOwned; - - use super::{super::*, *}; - // Success scenarios - #[tokio::test] - async fn test_gas_coin() { - let owner = get_test_owner(); - let gas_coin = get_test_coin(None, CoinType::Gas); - let gas_coin_clone = gas_coin.clone(); - let mut mock_state = MockStateRead::new(); - mock_state - .expect_get_balance() - .with( - predicate::eq(owner), - predicate::eq(get_test_coin_type_tag(gas_coin_clone.coin_type)), - ) - .return_once(move |_, _| { - Ok(TotalBalance { - balance: 7, - num_coins: 9, - }) - }); - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api.get_balance(owner, None).await; - - assert!(response.is_ok()); - let result = response.unwrap(); - assert_eq!( - result, - Balance { - coin_type: gas_coin.coin_type, - coin_object_count: 9, - total_balance: 7, - locked_balance: Default::default() - } - ); - } - - #[tokio::test] - async fn test_with_coin_type() { - let owner = get_test_owner(); - let coin = get_test_coin(None, CoinType::Usdc); - let coin_clone = coin.clone(); - let mut mock_state = MockStateRead::new(); - mock_state - .expect_get_balance() - .with( - predicate::eq(owner), - predicate::eq(get_test_coin_type_tag(coin_clone.coin_type)), - ) - .return_once(move |_, _| { - Ok(TotalBalance { - balance: 10, - num_coins: 11, - }) - }); - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_balance(owner, Some(coin.coin_type.clone())) - .await; - - assert!(response.is_ok()); - let result = response.unwrap(); - assert_eq!( - result, - Balance { - coin_type: coin.coin_type, - coin_object_count: 11, - total_balance: 10, - locked_balance: Default::default() - } - ); - } - - // Expected error scenarios - #[tokio::test] - async fn test_invalid_coin_type() { - let owner = get_test_owner(); - let coin_type = "0x2::invalid::struct::tag"; - let mock_state = MockStateRead::new(); - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_balance(owner, Some(coin_type.to_string())) - .await; - - assert!(response.is_err()); - let error_result = response.unwrap_err(); - let error_object: ErrorObjectOwned = error_result.into(); - let expected = expect!["-32602"]; - expected.assert_eq(&error_object.code().to_string()); - let expected = expect![ - "Invalid struct type: 0x2::invalid::struct::tag. Got error: Expected end of token stream. Got: ::" - ]; - expected.assert_eq(error_object.message()); - } - - // Unexpected error scenarios - #[tokio::test] - async fn test_get_balance_index_store_not_available() { - let owner = get_test_owner(); - let coin_type = get_test_coin_type(get_test_package_id()); - let mut mock_state = MockStateRead::new(); - mock_state.expect_get_balance().returning(move |_, _| { - Err(StateReadError::Client( - SuiError::IndexStoreNotAvailable.into(), - )) - }); - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_balance(owner, Some(coin_type.to_string())) - .await; - - assert!(response.is_err()); - let error_result = response.unwrap_err(); - let error_object: ErrorObjectOwned = error_result.into(); - assert_eq!( - error_object.code(), - jsonrpsee::types::error::INVALID_PARAMS_CODE - ); - let expected = expect!["Index store not available on this Fullnode."]; - expected.assert_eq(error_object.message()); - } - - #[tokio::test] - async fn test_get_balance_execution_error() { - // Validate that we handle and return an error message when we encounter an - // unexpected error - let owner = get_test_owner(); - let coin_type = get_test_coin_type(get_test_package_id()); - let mut mock_state = MockStateRead::new(); - mock_state.expect_get_balance().returning(move |_, _| { - Err(SuiError::ExecutionError("mock db error".to_string()).into()) - }); - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_balance(owner, Some(coin_type.to_string())) - .await; - - assert!(response.is_err()); - let error_result = response.unwrap_err(); - let error_object: ErrorObjectOwned = error_result.into(); - - assert_eq!( - error_object.code(), - jsonrpsee::types::error::INTERNAL_ERROR_CODE - ); - let expected = expect!["Error executing mock db error"]; - expected.assert_eq(error_object.message()); - } - } - - mod get_all_balances_tests { - use jsonrpsee::types::ErrorObjectOwned; - - use super::{super::*, *}; - - // Success scenarios - #[tokio::test] - async fn test_success_scenario() { - let owner = get_test_owner(); - let gas_coin = get_test_coin(None, CoinType::Gas); - let gas_coin_type_tag = get_test_coin_type_tag(gas_coin.coin_type.clone()); - let usdc_coin = get_test_coin(None, CoinType::Usdc); - let usdc_coin_type_tag = get_test_coin_type_tag(usdc_coin.coin_type.clone()); - let mut mock_state = MockStateRead::new(); - mock_state - .expect_get_all_balance() - .with(predicate::eq(owner)) - .return_once(move |_| { - let mut hash_map = HashMap::new(); - hash_map.insert( - gas_coin_type_tag, - TotalBalance { - balance: 7, - num_coins: 9, - }, - ); - hash_map.insert( - usdc_coin_type_tag, - TotalBalance { - balance: 10, - num_coins: 11, - }, - ); - Ok(Arc::new(hash_map)) - }); - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api.get_all_balances(owner).await; - - assert!(response.is_ok()); - let expected_result = vec![ - Balance { - coin_type: gas_coin.coin_type, - coin_object_count: 9, - total_balance: 7, - locked_balance: Default::default(), - }, - Balance { - coin_type: usdc_coin.coin_type, - coin_object_count: 11, - total_balance: 10, - locked_balance: Default::default(), - }, - ]; - // This is because the underlying result is a hashmap, so order is not - // guaranteed - let mut result = response.unwrap(); - for item in expected_result { - if let Some(pos) = result.iter().position(|i| *i == item) { - result.remove(pos); - } else { - panic!("{:?} not found in result", item); - } - } - assert!(result.is_empty()); - } - - // Unexpected error scenarios - #[tokio::test] - async fn test_index_store_not_available() { - let owner = get_test_owner(); - let mut mock_state = MockStateRead::new(); - mock_state.expect_get_all_balance().returning(move |_| { - Err(StateReadError::Client( - SuiError::IndexStoreNotAvailable.into(), - )) - }); - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api.get_all_balances(owner).await; - - assert!(response.is_err()); - let error_result = response.unwrap_err(); - let error_object: ErrorObjectOwned = error_result.into(); - assert_eq!( - error_object.code(), - jsonrpsee::types::error::INVALID_PARAMS_CODE - ); - let expected = expect!["Index store not available on this Fullnode."]; - expected.assert_eq(error_object.message()); - } - } - - mod get_coin_metadata_tests { - use mockall::predicate; - use sui_types::id::UID; - - use super::{super::*, *}; - - // Success scenarios - #[tokio::test] - async fn test_valid_coin_metadata_object() { - let package_id = get_test_package_id(); - let coin_name = get_test_coin_type(package_id); - let input_coin_struct = parse_sui_struct_tag(&coin_name).expect("should not fail"); - let coin_metadata_struct = CoinMetadata::type_(input_coin_struct.clone()); - let coin_metadata = CoinMetadata { - id: UID::new(get_test_package_id()), - decimals: 2, - name: "test_coin".to_string(), - symbol: "TEST".to_string(), - description: "test coin".to_string(), - icon_url: Some("unit.test.io".to_string()), - }; - let coin_metadata_object = - Object::coin_metadata_for_testing(input_coin_struct.clone(), coin_metadata); - let metadata = SuiCoinMetadata::try_from(coin_metadata_object.clone()).unwrap(); - let mut mock_internal = MockCoinReadInternal::new(); - // return TreasuryCap instead of CoinMetadata to set up test - mock_internal - .expect_find_package_object() - .with(predicate::always(), predicate::eq(coin_metadata_struct)) - .return_once(move |object_id, _| { - if object_id == &package_id { - Ok(coin_metadata_object) - } else { - panic!("should not be called with any other object id") - } - }); - - let coin_read_api = CoinReadApi { - internal: Box::new(mock_internal), - }; - - let response = coin_read_api.get_coin_metadata(coin_name.clone()).await; - assert!(response.is_ok()); - let result = response.unwrap().unwrap(); - assert_eq!(result, metadata); - } - - #[tokio::test] - async fn test_object_not_found() { - let transaction_digest = TransactionDigest::from([0; 32]); - let transaction_effects = TransactionEffects::default(); - - let mut mock_state = MockStateRead::new(); - mock_state - .expect_find_publish_txn_digest() - .return_once(move |_| Ok(transaction_digest)); - mock_state - .expect_get_executed_transaction_and_effects() - .return_once(move |_, _| Ok((create_fake_transaction(), transaction_effects))); - - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api - .get_coin_metadata("0x2::sui::SUI".to_string()) - .await; - - assert!(response.is_ok()); - let result = response.unwrap(); - assert_eq!(result, None); - } - - #[tokio::test] - async fn test_find_package_object_not_sui_coin_metadata() { - let package_id = get_test_package_id(); - let coin_name = get_test_coin_type(package_id); - let input_coin_struct = parse_sui_struct_tag(&coin_name).expect("should not fail"); - let coin_metadata_struct = CoinMetadata::type_(input_coin_struct.clone()); - let treasury_cap = TreasuryCap { - id: UID::new(get_test_package_id()), - total_supply: Supply { value: 420 }, - }; - let treasury_cap_object = - Object::treasury_cap_for_testing(input_coin_struct.clone(), treasury_cap); - let mut mock_internal = MockCoinReadInternal::new(); - // return TreasuryCap instead of CoinMetadata to set up test - mock_internal - .expect_find_package_object() - .with(predicate::always(), predicate::eq(coin_metadata_struct)) - .returning(move |object_id, _| { - if object_id == &package_id { - Ok(treasury_cap_object.clone()) - } else { - panic!("should not be called with any other object id") - } - }); - - let coin_read_api = CoinReadApi { - internal: Box::new(mock_internal), - }; - - let response = coin_read_api.get_coin_metadata(coin_name.clone()).await; - assert!(response.is_ok()); - let result = response.unwrap(); - assert!(result.is_none()); - } - } - - mod get_total_supply_tests { - use mockall::predicate; - use sui_types::id::UID; - - use super::{super::*, *}; - - #[tokio::test] - async fn test_success_response_for_gas_coin() { - let coin_type = "0x2::sui::SUI"; - let mock_internal = MockCoinReadInternal::new(); - let coin_read_api = CoinReadApi { - internal: Box::new(mock_internal), - }; - - let response = coin_read_api.get_total_supply(coin_type.to_string()).await; - - let supply = response.unwrap(); - let expected = expect!["10000000000000000000"]; - expected.assert_eq(&supply.value.to_string()); - } - - #[tokio::test] - async fn test_success_response_for_other_coin() { - let package_id = get_test_package_id(); - let (coin_name, _, treasury_cap_struct, _, treasury_cap_object) = - get_test_treasury_cap_peripherals(package_id); - let mut mock_internal = MockCoinReadInternal::new(); - mock_internal - .expect_find_package_object() - .with(predicate::always(), predicate::eq(treasury_cap_struct)) - .returning(move |object_id, _| { - if object_id == &package_id { - Ok(treasury_cap_object.clone()) - } else { - panic!("should not be called with any other object id") - } - }); - let coin_read_api = CoinReadApi { - internal: Box::new(mock_internal), - }; - - let response = coin_read_api.get_total_supply(coin_name.clone()).await; - - assert!(response.is_ok()); - let result = response.unwrap(); - let expected = expect!["420"]; - expected.assert_eq(&result.value.to_string()); - } - - #[tokio::test] - async fn test_object_not_found() { - let package_id = get_test_package_id(); - let (coin_name, _, _, _, _) = get_test_treasury_cap_peripherals(package_id); - let transaction_digest = TransactionDigest::from([0; 32]); - let transaction_effects = TransactionEffects::default(); - - let mut mock_state = MockStateRead::new(); - mock_state - .expect_find_publish_txn_digest() - .return_once(move |_| Ok(transaction_digest)); - mock_state - .expect_get_executed_transaction_and_effects() - .return_once(move |_, _| Ok((create_fake_transaction(), transaction_effects))); - - let coin_read_api = CoinReadApi::new_for_tests(Arc::new(mock_state), None); - let response = coin_read_api.get_total_supply(coin_name.clone()).await; - - assert!(response.is_err()); - let error_result = response.unwrap_err(); - let error_object: ErrorObjectOwned = error_result.into(); - let expected = expect!["-32602"]; - expected.assert_eq(&error_object.code().to_string()); - let expected = expect![ - "Cannot find object [0x2::coin::TreasuryCap<0xf::test_coin::TEST_COIN>] from [0x000000000000000000000000000000000000000000000000000000000000000f] package event." - ]; - expected.assert_eq(error_object.message()); - } - - #[tokio::test] - async fn test_find_package_object_not_treasury_cap() { - let package_id = get_test_package_id(); - let (coin_name, input_coin_struct, treasury_cap_struct, _, _) = - get_test_treasury_cap_peripherals(package_id); - let coin_metadata = CoinMetadata { - id: UID::new(get_test_package_id()), - decimals: 2, - name: "test_coin".to_string(), - symbol: "TEST".to_string(), - description: "test coin".to_string(), - icon_url: None, - }; - let coin_metadata_object = - Object::coin_metadata_for_testing(input_coin_struct.clone(), coin_metadata); - let mut mock_internal = MockCoinReadInternal::new(); - mock_internal - .expect_find_package_object() - .with(predicate::always(), predicate::eq(treasury_cap_struct)) - .returning(move |object_id, _| { - if object_id == &package_id { - Ok(coin_metadata_object.clone()) - } else { - panic!("should not be called with any other object id") - } - }); - - let coin_read_api = CoinReadApi { - internal: Box::new(mock_internal), - }; - - let response = coin_read_api.get_total_supply(coin_name.clone()).await; - let error_result = response.unwrap_err(); - let error_object: ErrorObjectOwned = error_result.into(); - assert_eq!( - error_object.code(), - jsonrpsee::types::error::CALL_EXECUTION_FAILED_CODE - ); - let expected = expect![ - "Failure deserializing object in the requested format: \"Unable to deserialize TreasuryCap object: remaining input\"" - ]; - expected.assert_eq(error_object.message()); - } - } -} diff --git a/crates/sui-json-rpc/src/error.rs b/crates/sui-json-rpc/src/error.rs deleted file mode 100644 index ed4e39e30cc..00000000000 --- a/crates/sui-json-rpc/src/error.rs +++ /dev/null @@ -1,526 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use fastcrypto::error::FastCryptoError; -use hyper::header::InvalidHeaderValue; -use itertools::Itertools; -use jsonrpsee::{ - core::Error as RpcError, - types::{ - error::{CallError, INTERNAL_ERROR_CODE}, - ErrorObject, - }, -}; -use sui_json_rpc_api::{TRANSACTION_EXECUTION_CLIENT_ERROR_CODE, TRANSIENT_ERROR_CODE}; -use sui_types::{ - error::{SuiError, SuiObjectResponseError, UserInputError}, - quorum_driver_types::QuorumDriverError, -}; -use thiserror::Error; -use tokio::task::JoinError; - -use crate::{authority_state::StateReadError, name_service::NameServiceError}; - -pub type RpcInterimResult = Result; - -#[derive(Debug, Error)] -pub enum Error { - #[error(transparent)] - SuiError(SuiError), - - #[error(transparent)] - InternalError(#[from] anyhow::Error), - - #[error("Deserialization error: {0}")] - BcsError(#[from] bcs::Error), - #[error("Unexpected error: {0}")] - UnexpectedError(String), - - #[error(transparent)] - RPCServerError(#[from] jsonrpsee::core::Error), - - #[error(transparent)] - InvalidHeaderValue(#[from] InvalidHeaderValue), - - #[error(transparent)] - UserInputError(#[from] UserInputError), - - #[error(transparent)] - EncodingError(#[from] eyre::Report), - - #[error(transparent)] - TokioJoinError(#[from] JoinError), - - #[error(transparent)] - QuorumDriverError(#[from] QuorumDriverError), - - #[error(transparent)] - FastCryptoError(#[from] FastCryptoError), - - #[error(transparent)] - SuiObjectResponseError(#[from] SuiObjectResponseError), - - #[error(transparent)] - SuiRpcInputError(#[from] SuiRpcInputError), - - // TODO(wlmyng): convert StateReadError::Internal message to generic internal error message. - #[error(transparent)] - StateReadError(#[from] StateReadError), - - #[error("Unsupported Feature: {0}")] - UnsupportedFeature(String), - - #[error("transparent")] - NameServiceError(#[from] NameServiceError), -} - -impl From for Error { - fn from(e: SuiError) -> Self { - match e { - SuiError::UserInputError { error } => Self::UserInputError(error), - SuiError::SuiObjectResponseError { error } => Self::SuiObjectResponseError(error), - SuiError::UnsupportedFeatureError { error } => Self::UnsupportedFeature(error), - SuiError::IndexStoreNotAvailable => Self::UnsupportedFeature( - "Required indexes are not available on this node".to_string(), - ), - other => Self::SuiError(other), - } - } -} - -impl From for RpcError { - /// `InvalidParams`/`INVALID_PARAMS_CODE` for client errors. - fn from(e: Error) -> RpcError { - match e { - Error::UserInputError(_) => RpcError::Call(CallError::InvalidParams(e.into())), - Error::UnsupportedFeature(_) => RpcError::Call(CallError::InvalidParams(e.into())), - Error::SuiObjectResponseError(err) => match err { - SuiObjectResponseError::NotExists { .. } - | SuiObjectResponseError::DynamicFieldNotFound { .. } - | SuiObjectResponseError::Deleted { .. } - | SuiObjectResponseError::DisplayError { .. } => { - RpcError::Call(CallError::InvalidParams(err.into())) - } - _ => RpcError::Call(CallError::Failed(err.into())), - }, - Error::NameServiceError(err) => match err { - NameServiceError::ExceedsMaxLength { .. } - | NameServiceError::InvalidHyphens { .. } - | NameServiceError::InvalidLength { .. } - | NameServiceError::InvalidUnderscore { .. } - | NameServiceError::LabelsEmpty { .. } - | NameServiceError::InvalidSeparator { .. } => { - RpcError::Call(CallError::InvalidParams(err.into())) - } - _ => RpcError::Call(CallError::Failed(err.into())), - }, - Error::SuiRpcInputError(err) => RpcError::Call(CallError::InvalidParams(err.into())), - Error::SuiError(sui_error) => match sui_error { - SuiError::TransactionNotFound { .. } - | SuiError::TransactionsNotFound { .. } - | SuiError::TransactionEventsNotFound { .. } => { - RpcError::Call(CallError::InvalidParams(sui_error.into())) - } - _ => RpcError::Call(CallError::Failed(sui_error.into())), - }, - Error::StateReadError(err) => match err { - StateReadError::Client(_) => RpcError::Call(CallError::InvalidParams(err.into())), - _ => { - let error_object = ErrorObject::owned( - jsonrpsee::types::error::INTERNAL_ERROR_CODE, - err.to_string(), - None::<()>, - ); - RpcError::Call(CallError::Custom(error_object)) - } - }, - Error::QuorumDriverError(err) => { - match err { - QuorumDriverError::InvalidUserSignature(err) => { - let inner_error_str = match err { - // TODO(wlmyng): update SuiError display trait to render UserInputError - // with display - SuiError::UserInputError { error } => error.to_string(), - _ => err.to_string(), - }; - - let error_message = format!("Invalid user signature: {inner_error_str}"); - - let error_object = ErrorObject::owned( - TRANSACTION_EXECUTION_CLIENT_ERROR_CODE, - error_message, - None::<()>, - ); - RpcError::Call(CallError::Custom(error_object)) - } - QuorumDriverError::TxAlreadyFinalizedWithDifferentUserSignatures => { - let error_object = ErrorObject::owned( - TRANSACTION_EXECUTION_CLIENT_ERROR_CODE, - "The transaction is already finalized but with different user signatures", - None::<()>, - ); - RpcError::Call(CallError::Custom(error_object)) - } - QuorumDriverError::TimeoutBeforeFinality - | QuorumDriverError::FailedWithTransientErrorAfterMaximumAttempts { .. } => { - let error_object = - ErrorObject::owned(TRANSIENT_ERROR_CODE, err.to_string(), None::<()>); - RpcError::Call(CallError::Custom(error_object)) - } - QuorumDriverError::ObjectsDoubleUsed { - conflicting_txes, - retried_tx, - retried_tx_success, - } => { - let error_message = format!( - "Failed to sign transaction by a quorum of validators because of locked objects. Retried a conflicting transaction {:?}, success: {:?}", - retried_tx, retried_tx_success - ); - - let new_map = conflicting_txes - .into_iter() - .map(|(digest, (pairs, _))| { - ( - digest, - pairs.into_iter().map(|(_, obj_ref)| obj_ref).collect(), - ) - }) - .collect::>>(); - - let error_object = ErrorObject::owned( - TRANSACTION_EXECUTION_CLIENT_ERROR_CODE, - error_message, - Some(new_map), - ); - RpcError::Call(CallError::Custom(error_object)) - } - QuorumDriverError::NonRecoverableTransactionError { errors } => { - let new_errors: Vec = errors - .into_iter() - // sort by total stake, descending, so users see the most prominent one - // first - .sorted_by(|(_, a, _), (_, b, _)| b.cmp(a)) - .filter_map(|(err, _, _)| { - match &err { - // Special handling of UserInputError: - // ObjectNotFound and DependentPackageNotFound are considered - // retryable errors but they have different treatment - // in AuthorityAggregator. - // The optimal fix would be to examine if the total stake - // of ObjectNotFound/DependentPackageNotFound exceeds the - // quorum threshold, but it takes a Committee here. - // So, we take an easier route and consider them non-retryable - // at all. Combining this with the sorting above, clients will - // see the dominant error first. - SuiError::UserInputError { error } => Some(error.to_string()), - _ => { - if err.is_retryable().0 { - None - } else { - Some(err.to_string()) - } - } - } - }) - .collect(); - - assert!( - !new_errors.is_empty(), - "NonRecoverableTransactionError should have at least one non-retryable error" - ); - - let error_list = new_errors.join(", "); - let error_msg = format!( - "Transaction execution failed due to issues with transaction inputs, please review the errors and try again: {}.", - error_list - ); - - let error_object = ErrorObject::owned( - TRANSACTION_EXECUTION_CLIENT_ERROR_CODE, - error_msg, - None::<()>, - ); - RpcError::Call(CallError::Custom(error_object)) - } - QuorumDriverError::QuorumDriverInternalError(_) => { - let error_object = ErrorObject::owned( - INTERNAL_ERROR_CODE, - "Internal error occurred while executing transaction.", - None::<()>, - ); - RpcError::Call(CallError::Custom(error_object)) - } - QuorumDriverError::SystemOverload { .. } - | QuorumDriverError::SystemOverloadRetryAfter { .. } => { - let error_object = - ErrorObject::owned(TRANSIENT_ERROR_CODE, err.to_string(), None::<()>); - RpcError::Call(CallError::Custom(error_object)) - } - } - } - _ => RpcError::Call(CallError::Failed(e.into())), - } - } -} - -#[derive(Debug, Error)] -pub enum SuiRpcInputError { - #[error("Input contains duplicates")] - ContainsDuplicates, - - #[error("Input exceeds limit of {0}")] - SizeLimitExceeded(String), - - #[error("{0}")] - GenericNotFound(String), - - #[error("{0}")] - GenericInvalid(String), - - #[error( - "request_type` must set to `None` or `WaitForLocalExecution` if effects is required in the response" - )] - InvalidExecuteTransactionRequestType, - - #[error("Unsupported protocol version requested. Min supported: {0}, max supported: {1}")] - ProtocolVersionUnsupported(u64, u64), - - #[error("{0}")] - CannotParseSuiStructTag(String), - - #[error(transparent)] - Base64(#[from] eyre::Report), - - #[error("Deserialization error: {0}")] - Bcs(#[from] bcs::Error), - - #[error(transparent)] - FastCryptoError(#[from] FastCryptoError), - - #[error(transparent)] - Anyhow(#[from] anyhow::Error), - - #[error(transparent)] - UserInputError(#[from] UserInputError), -} - -impl From for RpcError { - fn from(e: SuiRpcInputError) -> Self { - RpcError::Call(CallError::InvalidParams(e.into())) - } -} - -#[cfg(test)] -mod tests { - use expect_test::expect; - use jsonrpsee::types::ErrorObjectOwned; - use sui_types::{ - base_types::{AuthorityName, ObjectID, ObjectRef, SequenceNumber}, - committee::StakeUnit, - crypto::{AuthorityPublicKey, AuthorityPublicKeyBytes}, - digests::{ObjectDigest, TransactionDigest}, - }; - - use super::*; - - fn test_object_ref() -> ObjectRef { - ( - ObjectID::ZERO, - SequenceNumber::from_u64(0), - ObjectDigest::new([0; 32]), - ) - } - - mod match_quorum_driver_error_tests { - use super::*; - - #[test] - fn test_invalid_user_signature() { - let quorum_driver_error = - QuorumDriverError::InvalidUserSignature(SuiError::InvalidSignature { - error: "Test inner invalid signature".to_string(), - }); - - let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); - - let error_object: ErrorObjectOwned = rpc_error.into(); - let expected_code = expect!["-32002"]; - expected_code.assert_eq(&error_object.code().to_string()); - let expected_message = expect![ - "Invalid user signature: Signature is not valid: Test inner invalid signature" - ]; - expected_message.assert_eq(error_object.message()); - } - - #[test] - fn test_timeout_before_finality() { - let quorum_driver_error = QuorumDriverError::TimeoutBeforeFinality; - - let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); - - let error_object: ErrorObjectOwned = rpc_error.into(); - let expected_code = expect!["-32050"]; - expected_code.assert_eq(&error_object.code().to_string()); - let expected_message = expect!["Transaction timed out before reaching finality"]; - expected_message.assert_eq(error_object.message()); - } - - #[test] - fn test_failed_with_transient_error_after_maximum_attempts() { - let quorum_driver_error = - QuorumDriverError::FailedWithTransientErrorAfterMaximumAttempts { - total_attempts: 10, - }; - - let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); - - let error_object: ErrorObjectOwned = rpc_error.into(); - let expected_code = expect!["-32050"]; - expected_code.assert_eq(&error_object.code().to_string()); - let expected_message = expect![ - "Transaction failed to reach finality with transient error after 10 attempts." - ]; - expected_message.assert_eq(error_object.message()); - } - - #[test] - fn test_objects_double_used() { - use sui_types::crypto::VerifyingKey; - let mut conflicting_txes: BTreeMap< - TransactionDigest, - (Vec<(AuthorityName, ObjectRef)>, StakeUnit), - > = BTreeMap::new(); - let tx_digest = TransactionDigest::default(); - let object_ref = test_object_ref(); - let stake_unit: StakeUnit = 10; - let authority_name = AuthorityPublicKeyBytes([0; AuthorityPublicKey::LENGTH]); - conflicting_txes.insert(tx_digest, (vec![(authority_name, object_ref)], stake_unit)); - - let quorum_driver_error = QuorumDriverError::ObjectsDoubleUsed { - conflicting_txes, - retried_tx: Some(TransactionDigest::default()), - retried_tx_success: Some(true), - }; - - let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); - - let error_object: ErrorObjectOwned = rpc_error.into(); - let expected_code = expect!["-32002"]; - expected_code.assert_eq(&error_object.code().to_string()); - let expected_message = expect![ - "Failed to sign transaction by a quorum of validators because of locked objects. Retried a conflicting transaction Some(TransactionDigest(11111111111111111111111111111111)), success: Some(true)" - ]; - expected_message.assert_eq(error_object.message()); - let expected_data = expect![[ - r#"{"11111111111111111111111111111111":[["0x0000000000000000000000000000000000000000000000000000000000000000",0,"11111111111111111111111111111111"]]}"# - ]]; - let actual_data = error_object.data().unwrap().to_string(); - expected_data.assert_eq(&actual_data); - } - - #[test] - fn test_non_recoverable_transaction_error() { - let quorum_driver_error = QuorumDriverError::NonRecoverableTransactionError { - errors: vec![ - ( - SuiError::UserInputError { - error: UserInputError::GasBalanceTooLow { - gas_balance: 10, - needed_gas_amount: 100, - }, - }, - 0, - vec![], - ), - ( - SuiError::UserInputError { - error: UserInputError::ObjectVersionUnavailableForConsumption { - provided_obj_ref: test_object_ref(), - current_version: 10.into(), - }, - }, - 0, - vec![], - ), - ], - }; - - let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); - - let error_object: ErrorObjectOwned = rpc_error.into(); - let expected_code = expect!["-32002"]; - expected_code.assert_eq(&error_object.code().to_string()); - let expected_message = expect![ - "Transaction execution failed due to issues with transaction inputs, please review the errors and try again: Balance of gas object 10 is lower than the needed amount: 100., Object (0x0000000000000000000000000000000000000000000000000000000000000000, SequenceNumber(0), o#11111111111111111111111111111111) is not available for consumption, its current version: SequenceNumber(10).." - ]; - expected_message.assert_eq(error_object.message()); - } - - #[test] - fn test_non_recoverable_transaction_error_with_transient_errors() { - let quorum_driver_error = QuorumDriverError::NonRecoverableTransactionError { - errors: vec![ - ( - SuiError::UserInputError { - error: UserInputError::ObjectNotFound { - object_id: test_object_ref().0, - version: None, - }, - }, - 0, - vec![], - ), - ( - SuiError::RpcError("Hello".to_string(), "Testing".to_string()), - 0, - vec![], - ), - ], - }; - - let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); - - let error_object: ErrorObjectOwned = rpc_error.into(); - let expected_code = expect!["-32002"]; - expected_code.assert_eq(&error_object.code().to_string()); - let expected_message = expect![ - "Transaction execution failed due to issues with transaction inputs, please review the errors and try again: Could not find the referenced object 0x0000000000000000000000000000000000000000000000000000000000000000 at version None.." - ]; - expected_message.assert_eq(error_object.message()); - } - - #[test] - fn test_quorum_driver_internal_error() { - let quorum_driver_error = - QuorumDriverError::QuorumDriverInternalError(SuiError::UnexpectedMessage); - - let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); - - let error_object: ErrorObjectOwned = rpc_error.into(); - let expected_code = expect!["-32603"]; - expected_code.assert_eq(&error_object.code().to_string()); - let expected_message = expect!["Internal error occurred while executing transaction."]; - expected_message.assert_eq(error_object.message()); - } - - #[test] - fn test_system_overload() { - let quorum_driver_error = QuorumDriverError::SystemOverload { - overloaded_stake: 10, - errors: vec![(SuiError::UnexpectedMessage, 0, vec![])], - }; - - let rpc_error: RpcError = Error::QuorumDriverError(quorum_driver_error).into(); - - let error_object: ErrorObjectOwned = rpc_error.into(); - let expected_code = expect!["-32050"]; - expected_code.assert_eq(&error_object.code().to_string()); - let expected_message = expect![ - "Transaction is not processed because 10 of validators by stake are overloaded with certificates pending execution." - ]; - expected_message.assert_eq(error_object.message()); - } - } -} diff --git a/crates/sui-json-rpc/src/governance_api.rs b/crates/sui-json-rpc/src/governance_api.rs deleted file mode 100644 index ac525786509..00000000000 --- a/crates/sui-json-rpc/src/governance_api.rs +++ /dev/null @@ -1,641 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{cmp::max, collections::BTreeMap, sync::Arc}; - -use async_trait::async_trait; -use cached::{proc_macro::cached, SizedCache}; -use itertools::Itertools; -use jsonrpsee::{core::RpcResult, RpcModule}; -use mysten_metrics::spawn_monitored_task; -use sui_core::authority::AuthorityState; -use sui_json_rpc_api::{GovernanceReadApiOpenRpc, GovernanceReadApiServer, JsonRpcMetrics}; -use sui_json_rpc_types::{ - DelegatedStake, DelegatedTimelockedStake, Stake, StakeStatus, SuiCommittee, TimelockedStake, - ValidatorApy, ValidatorApys, -}; -use sui_open_rpc::Module; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, - committee::EpochId, - dynamic_field::get_dynamic_field_from_store, - error::{SuiError, UserInputError}, - governance::StakedSui, - id::ID, - object::{Object, ObjectRead}, - sui_serde::BigInt, - sui_system_state::{ - get_validator_from_table, sui_system_state_summary::SuiSystemStateSummary, - PoolTokenExchangeRate, SuiSystemState, SuiSystemStateTrait, - }, - timelock::timelocked_staked_sui::TimelockedStakedSui, -}; -use tracing::{info, instrument}; - -use crate::{ - authority_state::StateRead, - error::{Error, RpcInterimResult, SuiRpcInputError}, - with_tracing, ObjectProvider, SuiRpcModule, -}; - -#[derive(Clone)] -pub struct GovernanceReadApi { - state: Arc, - pub metrics: Arc, -} - -impl GovernanceReadApi { - pub fn new(state: Arc, metrics: Arc) -> Self { - Self { state, metrics } - } - - async fn get_staked_sui(&self, owner: SuiAddress) -> Result, Error> { - let state = self.state.clone(); - let result = - spawn_monitored_task!(async move { state.get_staked_sui(owner).await }).await??; - - self.metrics - .get_stake_sui_result_size - .report(result.len() as u64); - self.metrics - .get_stake_sui_result_size_total - .inc_by(result.len() as u64); - Ok(result) - } - - async fn get_timelocked_staked_sui( - &self, - owner: SuiAddress, - ) -> Result, Error> { - let state = self.state.clone(); - let result = - spawn_monitored_task!(async move { state.get_timelocked_staked_sui(owner).await }) - .await??; - - self.metrics - .get_stake_sui_result_size - .report(result.len() as u64); - self.metrics - .get_stake_sui_result_size_total - .inc_by(result.len() as u64); - Ok(result) - } - - async fn get_stakes_by_ids( - &self, - staked_sui_ids: Vec, - ) -> Result, Error> { - let state = self.state.clone(); - let stakes_read = spawn_monitored_task!(async move { - staked_sui_ids - .iter() - .map(|id| state.get_object_read(id)) - .collect::, _>>() - }) - .await??; - - if stakes_read.is_empty() { - return Ok(vec![]); - } - - let stakes: Vec<(StakedSui, bool)> = self - .stakes_with_status(stakes_read.into_iter()) - .await? - .into_iter() - .map(|(o, b)| StakedSui::try_from(&o).map(|stake| (stake, b))) - .collect::>()?; - - self.get_delegated_stakes(stakes).await - } - - async fn get_stakes(&self, owner: SuiAddress) -> Result, Error> { - let timer = self.metrics.get_stake_sui_latency.start_timer(); - let stakes = self.get_staked_sui(owner).await?; - if stakes.is_empty() { - return Ok(vec![]); - } - drop(timer); - - let _timer = self.metrics.get_delegated_sui_latency.start_timer(); - - let self_clone = self.clone(); - spawn_monitored_task!( - self_clone.get_delegated_stakes(stakes.into_iter().map(|s| (s, true)).collect()) - ) - .await? - } - - async fn get_timelocked_stakes_by_ids( - &self, - timelocked_staked_sui_ids: Vec, - ) -> Result, Error> { - let state = self.state.clone(); - let stakes_read = spawn_monitored_task!(async move { - timelocked_staked_sui_ids - .iter() - .map(|id| state.get_object_read(id)) - .collect::, _>>() - }) - .await??; - - if stakes_read.is_empty() { - return Ok(vec![]); - } - - let stakes: Vec<(TimelockedStakedSui, bool)> = self - .stakes_with_status(stakes_read.into_iter()) - .await? - .into_iter() - .map(|(o, b)| TimelockedStakedSui::try_from(&o).map(|stake| (stake, b))) - .collect::>()?; - - self.get_delegated_timelocked_stakes(stakes).await - } - - async fn get_timelocked_stakes( - &self, - owner: SuiAddress, - ) -> Result, Error> { - let timer = self.metrics.get_stake_sui_latency.start_timer(); - let stakes = self.get_timelocked_staked_sui(owner).await?; - if stakes.is_empty() { - return Ok(vec![]); - } - drop(timer); - - let _timer = self.metrics.get_delegated_sui_latency.start_timer(); - - let self_clone = self.clone(); - spawn_monitored_task!( - self_clone - .get_delegated_timelocked_stakes(stakes.into_iter().map(|s| (s, true)).collect()) - ) - .await? - } - - async fn get_delegated_stakes( - &self, - stakes: Vec<(StakedSui, bool)>, - ) -> Result, Error> { - let pools = stakes.into_iter().fold( - BTreeMap::<_, Vec<_>>::new(), - |mut pools, (stake, exists)| { - pools - .entry(stake.pool_id()) - .or_default() - .push((stake, exists)); - pools - }, - ); - - let system_state = self.get_system_state()?; - let system_state_summary: SuiSystemStateSummary = - system_state.clone().into_sui_system_state_summary(); - - let rates = exchange_rates(&self.state, system_state_summary.epoch) - .await? - .into_iter() - .map(|rates| (rates.pool_id, rates)) - .collect::>(); - - let mut delegated_stakes = vec![]; - for (pool_id, stakes) in pools { - // Rate table and rate can be null when the pool is not active - let rate_table = rates.get(&pool_id).ok_or_else(|| { - SuiRpcInputError::GenericNotFound( - "Cannot find rates for staking pool {pool_id}".to_string(), - ) - })?; - let current_rate = rate_table.rates.first().map(|(_, rate)| rate); - - let mut delegations = vec![]; - for (stake, exists) in stakes { - let status = stake_status( - system_state_summary.epoch, - stake.activation_epoch(), - stake.principal(), - exists, - current_rate, - rate_table, - ); - delegations.push(Stake { - staked_sui_id: stake.id(), - // TODO: this might change when we implement warm up period. - stake_request_epoch: stake.activation_epoch() - 1, - stake_active_epoch: stake.activation_epoch(), - principal: stake.principal(), - status, - }) - } - delegated_stakes.push(DelegatedStake { - validator_address: rate_table.address, - staking_pool: pool_id, - stakes: delegations, - }) - } - Ok(delegated_stakes) - } - - async fn get_delegated_timelocked_stakes( - &self, - stakes: Vec<(TimelockedStakedSui, bool)>, - ) -> Result, Error> { - let pools = stakes.into_iter().fold( - BTreeMap::<_, Vec<_>>::new(), - |mut pools, (stake, exists)| { - pools - .entry(stake.pool_id()) - .or_default() - .push((stake, exists)); - pools - }, - ); - - let system_state = self.get_system_state()?; - let system_state_summary: SuiSystemStateSummary = - system_state.clone().into_sui_system_state_summary(); - - let rates = exchange_rates(&self.state, system_state_summary.epoch) - .await? - .into_iter() - .map(|rates| (rates.pool_id, rates)) - .collect::>(); - - let mut delegated_stakes = vec![]; - for (pool_id, stakes) in pools { - // Rate table and rate can be null when the pool is not active - let rate_table = rates.get(&pool_id).ok_or_else(|| { - SuiRpcInputError::GenericNotFound( - "Cannot find rates for staking pool {pool_id}".to_string(), - ) - })?; - let current_rate = rate_table.rates.first().map(|(_, rate)| rate); - - let mut delegations = vec![]; - for (stake, exists) in stakes { - let status = stake_status( - system_state_summary.epoch, - stake.activation_epoch(), - stake.principal(), - exists, - current_rate, - rate_table, - ); - delegations.push(TimelockedStake { - timelocked_staked_sui_id: stake.id(), - // TODO: this might change when we implement warm up period. - stake_request_epoch: stake.activation_epoch() - 1, - stake_active_epoch: stake.activation_epoch(), - principal: stake.principal(), - status, - expiration_timestamp_ms: stake.expiration_timestamp_ms(), - }) - } - delegated_stakes.push(DelegatedTimelockedStake { - validator_address: rate_table.address, - staking_pool: pool_id, - stakes: delegations, - }) - } - Ok(delegated_stakes) - } - - async fn stakes_with_status( - &self, - iter: impl Iterator, - ) -> Result, Error> { - let mut stakes = vec![]; - - for stake in iter { - match stake { - ObjectRead::Exists(_, o, _) => stakes.push((o, true)), - ObjectRead::Deleted((object_id, version, _)) => { - let Some(o) = self - .state - .find_object_lt_or_eq_version(&object_id, &version.one_before().unwrap()) - .await? - else { - Err(SuiRpcInputError::UserInputError( - UserInputError::ObjectNotFound { - object_id, - version: None, - }, - ))? - }; - stakes.push((o, false)); - } - ObjectRead::NotExists(id) => Err(SuiRpcInputError::UserInputError( - UserInputError::ObjectNotFound { - object_id: id, - version: None, - }, - ))?, - } - } - - Ok(stakes) - } - - fn get_system_state(&self) -> Result { - Ok(self.state.get_system_state()?) - } -} - -#[async_trait] -impl GovernanceReadApiServer for GovernanceReadApi { - #[instrument(skip(self))] - async fn get_stakes_by_ids( - &self, - staked_sui_ids: Vec, - ) -> RpcResult> { - with_tracing!(async move { self.get_stakes_by_ids(staked_sui_ids).await }) - } - - #[instrument(skip(self))] - async fn get_stakes(&self, owner: SuiAddress) -> RpcResult> { - with_tracing!(async move { self.get_stakes(owner).await }) - } - - #[instrument(skip(self))] - async fn get_timelocked_stakes_by_ids( - &self, - timelocked_staked_sui_ids: Vec, - ) -> RpcResult> { - with_tracing!(async move { - self.get_timelocked_stakes_by_ids(timelocked_staked_sui_ids) - .await - }) - } - - #[instrument(skip(self))] - async fn get_timelocked_stakes( - &self, - owner: SuiAddress, - ) -> RpcResult> { - with_tracing!(async move { self.get_timelocked_stakes(owner).await }) - } - - #[instrument(skip(self))] - async fn get_committee_info(&self, epoch: Option>) -> RpcResult { - with_tracing!(async move { - self.state - .get_or_latest_committee(epoch) - .map(|committee| committee.into()) - .map_err(Error::from) - }) - } - - #[instrument(skip(self))] - async fn get_latest_sui_system_state(&self) -> RpcResult { - with_tracing!(async move { - Ok(self - .state - .get_system_state() - .map_err(Error::from)? - .into_sui_system_state_summary()) - }) - } - - #[instrument(skip(self))] - async fn get_reference_gas_price(&self) -> RpcResult> { - with_tracing!(async move { - let epoch_store = self.state.load_epoch_store_one_call_per_task(); - Ok(epoch_store.reference_gas_price().into()) - }) - } - - #[instrument(skip(self))] - async fn get_validators_apy(&self) -> RpcResult { - info!("get_validator_apy"); - let system_state_summary: SuiSystemStateSummary = - self.get_latest_sui_system_state().await?; - - let exchange_rate_table = exchange_rates(&self.state, system_state_summary.epoch) - .await - .map_err(Error::from)?; - - let apys = calculate_apys( - system_state_summary.stake_subsidy_start_epoch, - exchange_rate_table, - ); - - Ok(ValidatorApys { - apys, - epoch: system_state_summary.epoch, - }) - } -} - -pub fn calculate_apys( - stake_subsidy_start_epoch: u64, - exchange_rate_table: Vec, -) -> Vec { - let mut apys = vec![]; - - for rates in exchange_rate_table.into_iter().filter(|r| r.active) { - // we start the apy calculation from the epoch when the stake subsidy starts - let exchange_rates = rates.rates.into_iter().filter_map(|(epoch, rate)| { - if epoch >= stake_subsidy_start_epoch { - Some(rate) - } else { - None - } - }); - - // we need at least 2 data points to calculate apy - let average_apy = if exchange_rates.clone().count() >= 2 { - // rates are sorted by epoch in descending order. - let er_e = exchange_rates.clone().dropping(1); - // rate e+1 - let er_e_1 = exchange_rates.dropping_back(1); - let apys = er_e - .zip(er_e_1) - .map(calculate_apy) - .filter(|apy| *apy > 0.0 && *apy < 0.1) - .take(30) - .collect::>(); - - let apy_counts = apys.len() as f64; - apys.iter().sum::() / apy_counts - } else { - 0.0 - }; - apys.push(ValidatorApy { - address: rates.address, - apy: average_apy, - }); - } - apys -} - -#[test] -fn test_apys_calculation_filter_outliers() { - // staking pool exchange rates extracted from mainnet - let file = - std::fs::File::open("src/unit_tests/data/validator_exchange_rate/rates.json").unwrap(); - let rates: BTreeMap> = - serde_json::from_reader(file).unwrap(); - - let mut address_map = BTreeMap::new(); - - let exchange_rates = rates - .into_iter() - .map(|(validator, rates)| { - let address = SuiAddress::random_for_testing_only(); - address_map.insert(address, validator); - ValidatorExchangeRates { - address, - pool_id: ObjectID::random(), - active: true, - rates, - } - }) - .collect(); - - let apys = calculate_apys(20, exchange_rates); - - for apy in apys { - println!("{}: {}", address_map[&apy.address], apy.apy); - assert!(apy.apy < 0.07) - } -} - -// APY_e = (ER_e+1 / ER_e) ^ 365 -fn calculate_apy((rate_e, rate_e_1): (PoolTokenExchangeRate, PoolTokenExchangeRate)) -> f64 { - (rate_e.rate() / rate_e_1.rate()).powf(365.0) - 1.0 -} - -fn stake_status( - epoch: u64, - activation_epoch: u64, - principal: u64, - exists: bool, - current_rate: Option<&PoolTokenExchangeRate>, - rate_table: &ValidatorExchangeRates, -) -> StakeStatus { - if !exists { - StakeStatus::Unstaked - } else if epoch >= activation_epoch { - let estimated_reward = if let Some(current_rate) = current_rate { - let stake_rate = rate_table - .rates - .iter() - .find_map(|(epoch, rate)| (*epoch == activation_epoch).then(|| rate.clone())) - .unwrap_or_default(); - let estimated_reward = - ((stake_rate.rate() / current_rate.rate()) - 1.0) * principal as f64; - max(0, estimated_reward.round() as u64) - } else { - 0 - }; - StakeStatus::Active { estimated_reward } - } else { - StakeStatus::Pending - } -} - -/// Cached exchange rates for validators for the given epoch, the cache size is -/// 1, it will be cleared when the epoch changes. rates are in descending order -/// by epoch. -#[cached( - type = "SizedCache>", - create = "{ SizedCache::with_size(1) }", - convert = "{ _current_epoch }", - result = true -)] -async fn exchange_rates( - state: &Arc, - _current_epoch: EpochId, -) -> RpcInterimResult> { - let system_state = state.get_system_state()?; - let system_state_summary: SuiSystemStateSummary = system_state.into_sui_system_state_summary(); - - // Get validator rate tables - let mut tables = vec![]; - - for validator in system_state_summary.active_validators { - tables.push(( - validator.sui_address, - validator.staking_pool_id, - validator.exchange_rates_id, - validator.exchange_rates_size, - true, - )); - } - - // Get inactive validator rate tables - for df in state.get_dynamic_fields( - system_state_summary.inactive_pools_id, - None, - system_state_summary.inactive_pools_size as usize, - )? { - let pool_id: ID = - bcs::from_bytes(&df.1.bcs_name).map_err(|e| SuiError::ObjectDeserializationError { - error: e.to_string(), - })?; - let validator = get_validator_from_table( - state.get_object_store().as_ref(), - system_state_summary.inactive_pools_id, - &pool_id, - )?; // TODO(wlmyng): roll this into StateReadError - tables.push(( - validator.sui_address, - validator.staking_pool_id, - validator.exchange_rates_id, - validator.exchange_rates_size, - false, - )); - } - - let mut exchange_rates = vec![]; - // Get exchange rates for each validator - for (address, pool_id, exchange_rates_id, exchange_rates_size, active) in tables { - let mut rates = state - .get_dynamic_fields(exchange_rates_id, None, exchange_rates_size as usize)? - .into_iter() - .map(|df| { - let epoch: EpochId = bcs::from_bytes(&df.1.bcs_name).map_err(|e| { - SuiError::ObjectDeserializationError { - error: e.to_string(), - } - })?; - - let exchange_rate: PoolTokenExchangeRate = get_dynamic_field_from_store( - &state.get_object_store().as_ref(), - exchange_rates_id, - &epoch, - )?; - - Ok::<_, SuiError>((epoch, exchange_rate)) - }) - .collect::, _>>()?; - - rates.sort_by(|(a, _), (b, _)| a.cmp(b).reverse()); - - exchange_rates.push(ValidatorExchangeRates { - address, - pool_id, - active, - rates, - }); - } - Ok(exchange_rates) -} - -#[derive(Clone, Debug)] -pub struct ValidatorExchangeRates { - pub address: SuiAddress, - pub pool_id: ObjectID, - pub active: bool, - pub rates: Vec<(EpochId, PoolTokenExchangeRate)>, -} - -impl SuiRpcModule for GovernanceReadApi { - fn rpc(self) -> RpcModule { - self.into_rpc() - } - - fn rpc_doc_module() -> Module { - GovernanceReadApiOpenRpc::module_doc() - } -} diff --git a/crates/sui-json-rpc/src/indexer_api.rs b/crates/sui-json-rpc/src/indexer_api.rs deleted file mode 100644 index c15908b30c9..00000000000 --- a/crates/sui-json-rpc/src/indexer_api.rs +++ /dev/null @@ -1,510 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::sync::Arc; - -use anyhow::bail; -use async_trait::async_trait; -use futures::{future, Stream}; -use jsonrpsee::{ - core::{error::SubscriptionClosed, RpcResult}, - types::SubscriptionResult, - RpcModule, SubscriptionSink, -}; -use move_bytecode_utils::layout::TypeLayoutBuilder; -use move_core_types::language_storage::TypeTag; -use mysten_metrics::spawn_monitored_task; -use serde::Serialize; -use sui_core::authority::AuthorityState; -use sui_json::SuiJsonValue; -use sui_json_rpc_api::{ - cap_page_limit, validate_limit, IndexerApiOpenRpc, IndexerApiServer, JsonRpcMetrics, - ReadApiServer, QUERY_MAX_RESULT_LIMIT, -}; -use sui_json_rpc_types::{ - DynamicFieldPage, EventFilter, EventPage, ObjectsPage, Page, SuiObjectDataOptions, - SuiObjectResponse, SuiObjectResponseQuery, SuiTransactionBlockResponse, - SuiTransactionBlockResponseQuery, TransactionBlocksPage, TransactionFilter, -}; -use sui_open_rpc::Module; -use sui_storage::key_value_store::TransactionKeyValueStore; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, - digests::TransactionDigest, - dynamic_field::{DynamicFieldName, Field}, - error::SuiObjectResponseError, - event::EventID, -}; -use tokio::sync::{OwnedSemaphorePermit, Semaphore}; -use tracing::{debug, instrument, warn}; - -use crate::{ - authority_state::{StateRead, StateReadResult}, - error::{Error, SuiRpcInputError}, - name_service::{Domain, NameRecord, NameServiceConfig, NameServiceError}, - with_tracing, SuiRpcModule, -}; - -pub fn spawn_subscription( - mut sink: SubscriptionSink, - rx: S, - permit: Option, -) where - S: Stream + Unpin + Send + 'static, - T: Serialize, -{ - spawn_monitored_task!(async move { - let _permit = permit; - match sink.pipe_from_stream(rx).await { - SubscriptionClosed::Success => { - debug!("Subscription completed."); - sink.close(SubscriptionClosed::Success); - } - SubscriptionClosed::RemotePeerAborted => { - debug!("Subscription aborted by remote peer."); - sink.close(SubscriptionClosed::RemotePeerAborted); - } - SubscriptionClosed::Failed(err) => { - debug!("Subscription failed: {err:?}"); - sink.close(err); - } - }; - }); -} -const DEFAULT_MAX_SUBSCRIPTIONS: usize = 100; - -pub struct IndexerApi { - state: Arc, - read_api: R, - transaction_kv_store: Arc, - name_service_config: NameServiceConfig, - pub metrics: Arc, - subscription_semaphore: Arc, -} - -impl IndexerApi { - pub fn new( - state: Arc, - read_api: R, - transaction_kv_store: Arc, - name_service_config: NameServiceConfig, - metrics: Arc, - max_subscriptions: Option, - ) -> Self { - let max_subscriptions = max_subscriptions.unwrap_or(DEFAULT_MAX_SUBSCRIPTIONS); - Self { - state, - transaction_kv_store, - read_api, - name_service_config, - metrics, - subscription_semaphore: Arc::new(Semaphore::new(max_subscriptions)), - } - } - - fn extract_values_from_dynamic_field_name( - &self, - name: DynamicFieldName, - ) -> Result<(TypeTag, Vec), SuiRpcInputError> { - let DynamicFieldName { - type_: name_type, - value, - } = name; - let epoch_store = self.state.load_epoch_store_one_call_per_task(); - let layout = TypeLayoutBuilder::build_with_types(&name_type, epoch_store.module_cache())?; - let sui_json_value = SuiJsonValue::new(value)?; - let name_bcs_value = sui_json_value.to_bcs_bytes(&layout)?; - Ok((name_type, name_bcs_value)) - } - - fn acquire_subscribe_permit(&self) -> anyhow::Result { - match self.subscription_semaphore.clone().try_acquire_owned() { - Ok(p) => Ok(p), - Err(_) => bail!("Resources exhausted"), - } - } - - fn get_latest_checkpoint_timestamp_ms(&self) -> StateReadResult { - let latest_checkpoint = self.state.get_latest_checkpoint_sequence_number()?; - - let checkpoint = self - .state - .get_verified_checkpoint_by_sequence_number(latest_checkpoint)?; - - Ok(checkpoint.timestamp_ms) - } -} - -#[async_trait] -impl IndexerApiServer for IndexerApi { - #[instrument(skip(self))] - async fn get_owned_objects( - &self, - address: SuiAddress, - query: Option, - cursor: Option, - limit: Option, - ) -> RpcResult { - with_tracing!(async move { - let limit = - validate_limit(limit, *QUERY_MAX_RESULT_LIMIT).map_err(SuiRpcInputError::from)?; - self.metrics.get_owned_objects_limit.report(limit as u64); - let SuiObjectResponseQuery { filter, options } = query.unwrap_or_default(); - let options = options.unwrap_or_default(); - let mut objects = self - .state - .get_owner_objects_with_limit(address, cursor, limit + 1, filter) - .map_err(Error::from)?; - - // objects here are of size (limit + 1), where the last one is the cursor for - // the next page - let has_next_page = objects.len() > limit; - objects.truncate(limit); - let next_cursor = objects - .last() - .cloned() - .map_or(cursor, |o_info| Some(o_info.object_id)); - - let data = match options.is_not_in_object_info() { - true => { - let object_ids = objects.iter().map(|obj| obj.object_id).collect(); - self.read_api - .multi_get_objects(object_ids, Some(options)) - .await? - } - false => objects - .into_iter() - .map(|o_info| SuiObjectResponse::try_from((o_info, options.clone()))) - .collect::, _>>()?, - }; - - self.metrics - .get_owned_objects_result_size - .report(data.len() as u64); - self.metrics - .get_owned_objects_result_size_total - .inc_by(data.len() as u64); - Ok(Page { - data, - next_cursor, - has_next_page, - }) - }) - } - - #[instrument(skip(self))] - async fn query_transaction_blocks( - &self, - query: SuiTransactionBlockResponseQuery, - // If `Some`, the query will start from the next item after the specified cursor - cursor: Option, - limit: Option, - descending_order: Option, - ) -> RpcResult { - with_tracing!(async move { - let limit = cap_page_limit(limit); - self.metrics.query_tx_blocks_limit.report(limit as u64); - let descending = descending_order.unwrap_or_default(); - let opts = query.options.unwrap_or_default(); - - // Retrieve 1 extra item for next cursor - let mut digests = self - .state - .get_transactions( - &self.transaction_kv_store, - query.filter, - cursor, - Some(limit + 1), - descending, - ) - .await - .map_err(Error::from)?; - - // extract next cursor - let has_next_page = digests.len() > limit; - digests.truncate(limit); - let next_cursor = digests.last().cloned().map_or(cursor, Some); - - let data: Vec = if opts.only_digest() { - digests - .into_iter() - .map(SuiTransactionBlockResponse::new) - .collect() - } else { - self.read_api - .multi_get_transaction_blocks(digests, Some(opts)) - .await? - }; - - self.metrics - .query_tx_blocks_result_size - .report(data.len() as u64); - self.metrics - .query_tx_blocks_result_size_total - .inc_by(data.len() as u64); - Ok(Page { - data, - next_cursor, - has_next_page, - }) - }) - } - #[instrument(skip(self))] - async fn query_events( - &self, - query: EventFilter, - // exclusive cursor if `Some`, otherwise start from the beginning - cursor: Option, - limit: Option, - descending_order: Option, - ) -> RpcResult { - with_tracing!(async move { - let descending = descending_order.unwrap_or_default(); - let limit = cap_page_limit(limit); - self.metrics.query_events_limit.report(limit as u64); - // Retrieve 1 extra item for next cursor - let mut data = self - .state - .query_events( - &self.transaction_kv_store, - query, - cursor, - limit + 1, - descending, - ) - .await - .map_err(Error::from)?; - let has_next_page = data.len() > limit; - data.truncate(limit); - let next_cursor = data.last().map_or(cursor, |e| Some(e.id)); - self.metrics - .query_events_result_size - .report(data.len() as u64); - self.metrics - .query_events_result_size_total - .inc_by(data.len() as u64); - Ok(EventPage { - data, - next_cursor, - has_next_page, - }) - }) - } - - #[instrument(skip(self))] - fn subscribe_event(&self, sink: SubscriptionSink, filter: EventFilter) -> SubscriptionResult { - let permit = self.acquire_subscribe_permit()?; - spawn_subscription( - sink, - self.state - .get_subscription_handler() - .subscribe_events(filter), - Some(permit), - ); - Ok(()) - } - - fn subscribe_transaction( - &self, - sink: SubscriptionSink, - filter: TransactionFilter, - ) -> SubscriptionResult { - let permit = self.acquire_subscribe_permit()?; - spawn_subscription( - sink, - self.state - .get_subscription_handler() - .subscribe_transactions(filter), - Some(permit), - ); - Ok(()) - } - - #[instrument(skip(self))] - async fn get_dynamic_fields( - &self, - parent_object_id: ObjectID, - // If `Some`, the query will start from the next item after the specified cursor - cursor: Option, - limit: Option, - ) -> RpcResult { - with_tracing!(async move { - let limit = cap_page_limit(limit); - self.metrics.get_dynamic_fields_limit.report(limit as u64); - let mut data = self - .state - .get_dynamic_fields(parent_object_id, cursor, limit + 1) - .map_err(Error::from)?; - let has_next_page = data.len() > limit; - data.truncate(limit); - let next_cursor = data.last().cloned().map_or(cursor, |c| Some(c.0)); - self.metrics - .get_dynamic_fields_result_size - .report(data.len() as u64); - self.metrics - .get_dynamic_fields_result_size_total - .inc_by(data.len() as u64); - Ok(DynamicFieldPage { - data: data.into_iter().map(|(_, w)| w).collect(), - next_cursor, - has_next_page, - }) - }) - } - - #[instrument(skip(self))] - async fn get_dynamic_field_object( - &self, - parent_object_id: ObjectID, - name: DynamicFieldName, - ) -> RpcResult { - with_tracing!(async move { - let (name_type, name_bcs_value) = self.extract_values_from_dynamic_field_name(name)?; - - let id = self - .state - .get_dynamic_field_object_id(parent_object_id, name_type, &name_bcs_value) - .map_err(Error::from)?; - // TODO(chris): add options to `get_dynamic_field_object` API as well - if let Some(id) = id { - self.read_api - .get_object(id, Some(SuiObjectDataOptions::full_content())) - .await - .map_err(Error::from) - } else { - Ok(SuiObjectResponse::new_with_error( - SuiObjectResponseError::DynamicFieldNotFound { parent_object_id }, - )) - } - }) - } - - #[instrument(skip(self))] - async fn resolve_name_service_address(&self, name: String) -> RpcResult> { - with_tracing!(async move { - // prepare the requested domain's field id. - let domain = name.parse::().map_err(Error::from)?; - let record_id = self.name_service_config.record_field_id(&domain); - - // prepare the parent's field id. - let parent_domain = domain.parent(); - let parent_record_id = self.name_service_config.record_field_id(&parent_domain); - - let current_timestamp_ms = self.get_latest_checkpoint_timestamp_ms()?; - - // Do these two reads in parallel. - let mut requests = vec![self.state.get_object(&record_id)]; - - // Also add the parent in the DB reads if the requested domain is a subdomain. - if domain.is_subdomain() { - requests.push(self.state.get_object(&parent_record_id)); - } - - // Couldn't find a `multi_get_object` for this crate (looks like it uses a k,v - // db) Always fetching both parent + child at the same time (even - // for node subdomains), to avoid sequential db reads. We do this - // because we do not know if the requested domain is a node - // subdomain or a leaf subdomain, and we can save a trip to the db. - let mut results = future::try_join_all(requests).await?; - - // Removing without checking vector len, since it is known (== 1 or 2 depending - // on whether it is a subdomain or not). - let Some(object) = results.remove(0) else { - return Ok(None); - }; - - let name_record = NameRecord::try_from(object)?; - - // Handling SLD names & node subdomains is the same (we handle them as `node` - // records) We check their expiration, and and if not expired, - // return the target address. - if !name_record.is_leaf_record() { - return if !name_record.is_node_expired(current_timestamp_ms) { - Ok(name_record.target_address) - } else { - Err(Error::from(NameServiceError::NameExpired)) - }; - } - - // == Handle leaf subdomains case == - // We can remove since we know that if we're here, we have a parent - // (which also means we queried it in the future above). - let Some(parent_object) = results.remove(0) else { - return Err(Error::from(NameServiceError::NameExpired)); - }; - - let parent_name_record = NameRecord::try_from(parent_object)?; - - // For a leaf record, we check that: - // 1. The parent is a valid parent for that leaf record - // 2. The parent is not expired - if parent_name_record.is_valid_leaf_parent(&name_record) - && !parent_name_record.is_node_expired(current_timestamp_ms) - { - Ok(name_record.target_address) - } else { - Err(Error::from(NameServiceError::NameExpired)) - } - }) - } - - #[instrument(skip(self))] - async fn resolve_name_service_names( - &self, - address: SuiAddress, - _cursor: Option, - _limit: Option, - ) -> RpcResult> { - with_tracing!(async move { - let reverse_record_id = self - .name_service_config - .reverse_record_field_id(address.as_ref()); - - let mut result = Page { - data: vec![], - next_cursor: None, - has_next_page: false, - }; - - let Some(field_reverse_record_object) = - self.state.get_object(&reverse_record_id).await? - else { - return Ok(result); - }; - - let domain = field_reverse_record_object - .to_rust::>() - .ok_or_else(|| { - Error::UnexpectedError(format!("Malformed Object {reverse_record_id}")) - })? - .value; - - let domain_name = domain.to_string(); - - let resolved_address = self - .resolve_name_service_address(domain_name.clone()) - .await?; - - // If looking up the domain returns an empty result, we return an empty result. - if resolved_address.is_none() { - return Ok(result); - } - - // TODO(manos): Discuss why is this even a paginated response. - // This API is always going to return a single domain name. - result.data.push(domain_name); - - Ok(result) - }) - } -} - -impl SuiRpcModule for IndexerApi { - fn rpc(self) -> RpcModule { - self.into_rpc() - } - - fn rpc_doc_module() -> Module { - IndexerApiOpenRpc::module_doc() - } -} diff --git a/crates/sui-json-rpc/src/lib.rs b/crates/sui-json-rpc/src/lib.rs deleted file mode 100644 index 7da266f82b4..00000000000 --- a/crates/sui-json-rpc/src/lib.rs +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{env, net::SocketAddr, str::FromStr}; - -pub use balance_changes::*; -use hyper::{ - header::{HeaderName, HeaderValue}, - Body, Method, Request, -}; -use jsonrpsee::RpcModule; -pub use object_changes::*; -use prometheus::Registry; -use sui_json_rpc_api::{ - CLIENT_SDK_TYPE_HEADER, CLIENT_SDK_VERSION_HEADER, CLIENT_TARGET_API_VERSION_HEADER, -}; -use sui_open_rpc::{Module, Project}; -use tokio::runtime::Handle; -use tower_http::{ - cors::{AllowOrigin, CorsLayer}, - trace::TraceLayer, -}; -use tracing::info; - -use crate::{error::Error, metrics::MetricsLogger, routing_layer::RpcRouter}; - -pub mod authority_state; -pub mod axum_router; -mod balance_changes; -pub mod coin_api; -pub mod error; -pub mod governance_api; -pub mod indexer_api; -pub mod logger; -mod metrics; -pub mod move_utils; -pub mod name_service; -mod object_changes; -pub mod read_api; -mod routing_layer; -pub mod transaction_builder_api; -pub mod transaction_execution_api; - -pub const APP_NAME_HEADER: &str = "app-name"; - -pub const MAX_REQUEST_SIZE: u32 = 2 << 30; - -pub struct JsonRpcServerBuilder { - module: RpcModule<()>, - rpc_doc: Project, - registry: Registry, -} - -pub fn sui_rpc_doc(version: &str) -> Project { - Project::new( - version, - "Sui JSON-RPC", - "Sui JSON-RPC API for interaction with Sui Full node. Make RPC calls using https://fullnode.NETWORK.sui.io:443, where NETWORK is the network you want to use (testnet, devnet, mainnet). By default, local networks use port 9000.", - "Mysten Labs", - "https://mystenlabs.com", - "build@mystenlabs.com", - "Apache-2.0", - "https://raw.githubusercontent.com/MystenLabs/sui/main/LICENSE", - ) -} - -pub enum ServerType { - WebSocket, - Http, -} - -impl JsonRpcServerBuilder { - pub fn new(version: &str, prometheus_registry: &Registry) -> Self { - Self { - module: RpcModule::new(()), - rpc_doc: sui_rpc_doc(version), - registry: prometheus_registry.clone(), - } - } - - pub fn register_module(&mut self, module: T) -> Result<(), Error> { - self.rpc_doc.add_module(T::rpc_doc_module()); - Ok(self.module.merge(module.rpc())?) - } - - fn cors() -> Result { - let acl = match env::var("ACCESS_CONTROL_ALLOW_ORIGIN") { - Ok(value) => { - let allow_hosts = value - .split(',') - .map(HeaderValue::from_str) - .collect::, _>>()?; - AllowOrigin::list(allow_hosts) - } - _ => AllowOrigin::any(), - }; - info!(?acl); - - let cors = CorsLayer::new() - // Allow `POST` when accessing the resource - .allow_methods([Method::POST]) - // Allow requests from any origin - .allow_origin(acl) - .allow_headers([ - hyper::header::CONTENT_TYPE, - HeaderName::from_static(CLIENT_SDK_TYPE_HEADER), - HeaderName::from_static(CLIENT_SDK_VERSION_HEADER), - HeaderName::from_static(CLIENT_TARGET_API_VERSION_HEADER), - HeaderName::from_static(APP_NAME_HEADER), - ]); - Ok(cors) - } - - fn trace_layer() -> TraceLayer< - tower_http::classify::SharedClassifier, - impl tower_http::trace::MakeSpan + Clone, - (), - (), - (), - (), - (), - > { - TraceLayer::new_for_http() - .make_span_with(|request: &Request| { - let request_id = request - .headers() - .get("x-req-id") - .and_then(|v| v.to_str().ok()) - .map(tracing::field::display); - - tracing::info_span!("json-rpc-request", "x-req-id" = request_id) - }) - .on_request(()) - .on_response(()) - .on_body_chunk(()) - .on_eos(()) - .on_failure(()) - } - - pub fn to_router(&self, server_type: Option) -> Result { - let routing = self.rpc_doc.method_routing.clone(); - - let disable_routing = env::var("DISABLE_BACKWARD_COMPATIBILITY") - .ok() - .and_then(|v| bool::from_str(&v).ok()) - .unwrap_or_default(); - info!( - "Compatibility method routing {}.", - if disable_routing { - "disabled" - } else { - "enabled" - } - ); - let rpc_router = RpcRouter::new(routing, disable_routing); - - let rpc_docs = self.rpc_doc.clone(); - let mut module = self.module.clone(); - module.register_method("rpc.discover", move |_, _| Ok(rpc_docs.clone()))?; - let methods_names = module.method_names().collect::>(); - - let metrics_logger = MetricsLogger::new(&self.registry, &methods_names); - - let middleware = tower::ServiceBuilder::new() - .layer(Self::trace_layer()) - .layer(Self::cors()?); - - let service = - crate::axum_router::JsonRpcService::new(module.into(), rpc_router, metrics_logger); - - let mut router = axum::Router::new(); - - match server_type { - Some(ServerType::WebSocket) => { - router = router - .route( - "/", - axum::routing::get(crate::axum_router::ws::ws_json_rpc_upgrade), - ) - .route( - "/subscribe", - axum::routing::get(crate::axum_router::ws::ws_json_rpc_upgrade), - ); - } - Some(ServerType::Http) => { - router = router - .route( - "/", - axum::routing::post(crate::axum_router::json_rpc_handler), - ) - .route( - "/json-rpc", - axum::routing::post(crate::axum_router::json_rpc_handler), - ) - .route( - "/public", - axum::routing::post(crate::axum_router::json_rpc_handler), - ); - } - None => { - router = router - .route( - "/", - axum::routing::post(crate::axum_router::json_rpc_handler), - ) - .route( - "/", - axum::routing::get(crate::axum_router::ws::ws_json_rpc_upgrade), - ) - .route( - "/subscribe", - axum::routing::get(crate::axum_router::ws::ws_json_rpc_upgrade), - ) - .route( - "/json-rpc", - axum::routing::post(crate::axum_router::json_rpc_handler), - ) - .route( - "/public", - axum::routing::post(crate::axum_router::json_rpc_handler), - ); - } - } - - let app = router.with_state(service).layer(middleware); - - info!("Available JSON-RPC methods : {:?}", methods_names); - - Ok(app) - } - - pub async fn start( - self, - listen_address: SocketAddr, - _custom_runtime: Option, - server_type: Option, - ) -> Result { - let app = self.to_router(server_type)?; - - let server = axum::Server::bind(&listen_address).serve(app.into_make_service()); - - let addr = server.local_addr(); - let handle = tokio::spawn(async move { server.await.unwrap() }); - - let handle = ServerHandle { - handle: ServerHandleInner::Axum(handle), - }; - info!(local_addr =? addr, "Sui JSON-RPC server listening on {addr}"); - Ok(handle) - } -} - -pub struct ServerHandle { - handle: ServerHandleInner, -} - -impl ServerHandle { - pub async fn stopped(self) { - match self.handle { - ServerHandleInner::Axum(handle) => handle.await.unwrap(), - } - } -} - -enum ServerHandleInner { - Axum(tokio::task::JoinHandle<()>), -} - -pub trait SuiRpcModule -where - Self: Sized, -{ - fn rpc(self) -> RpcModule; - fn rpc_doc_module() -> Module; -} diff --git a/crates/sui-json-rpc/src/logger.rs b/crates/sui-json-rpc/src/logger.rs deleted file mode 100644 index 47aff630551..00000000000 --- a/crates/sui-json-rpc/src/logger.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[macro_export] -macro_rules! with_tracing { - ($time_spent_threshold:expr, $future:expr) => {{ - use tracing::{info, error, Instrument, Span}; - use jsonrpsee::core::{RpcResult, Error as RpcError}; - use jsonrpsee::types::error::{CallError}; - use $crate::error::RpcInterimResult; - use anyhow::anyhow; - - async move { - let start = std::time::Instant::now(); - let interim_result: RpcInterimResult<_> = $future.await; - let elapsed = start.elapsed(); - let result: RpcResult<_> = interim_result.map_err(|e: Error| { - let anyhow_error = anyhow!("{:?}", e); - - let rpc_error: RpcError = e.into(); - if !matches!(rpc_error, RpcError::Call(CallError::InvalidParams(_))) { - error!(error=?anyhow_error); - } - rpc_error - }); - - if elapsed > $time_spent_threshold { - info!(?elapsed, "RPC took longer than threshold to complete."); - } - result - } - .instrument(Span::current()) - .await - }}; - - ($future:expr) => {{ - with_tracing!(std::time::Duration::from_secs(1), $future) - }}; -} diff --git a/crates/sui-json-rpc/src/metrics.rs b/crates/sui-json-rpc/src/metrics.rs deleted file mode 100644 index fd2889f142b..00000000000 --- a/crates/sui-json-rpc/src/metrics.rs +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::HashSet, net::SocketAddr}; - -use hyper::body::HttpBody; -use jsonrpsee::{ - server::logger::{HttpRequest, Logger, MethodKind, TransportProtocol}, - types::Params, -}; -use prometheus::{ - register_histogram_vec_with_registry, register_int_counter_vec_with_registry, - register_int_gauge_vec_with_registry, HistogramVec, IntCounterVec, IntGaugeVec, -}; -use sui_json_rpc_api::{ - CLIENT_SDK_TYPE_HEADER, CLIENT_TARGET_API_VERSION_HEADER, TRANSIENT_ERROR_CODE, -}; -use tokio::time::Instant; - -const SPAM_LABEL: &str = "SPAM"; -const LATENCY_SEC_BUCKETS: &[f64] = &[ - 0.001, 0.005, 0.01, 0.05, 0.1, 0.25, 0.5, 1., 2.5, 5., 10., 20., 30., 60., 90., -]; - -#[derive(Debug, Clone)] -pub struct Metrics { - /// Counter of requests, route is a label (ie separate timeseries per route) - requests_by_route: IntCounterVec, - /// Gauge of inflight requests, route is a label (ie separate timeseries per - /// route) - inflight_requests_by_route: IntGaugeVec, - /// Request latency, route is a label - req_latency_by_route: HistogramVec, - /// Failed requests by route - errors_by_route: IntCounterVec, - server_errors_by_route: IntCounterVec, - client_errors_by_route: IntCounterVec, - transient_errors_by_route: IntCounterVec, - /// Client info - client: IntCounterVec, - /// Connection count - inflight_connection: IntGaugeVec, - /// Request size - rpc_request_size: HistogramVec, - /// Response size - rpc_response_size: HistogramVec, -} - -#[derive(Clone)] -pub struct MetricsLogger { - metrics: Metrics, - method_whitelist: HashSet, -} - -impl MetricsLogger { - fn check_spam<'a>(&'a self, method_name: &'a str) -> &'a str { - if self.method_whitelist.contains(method_name) { - method_name - } else { - SPAM_LABEL - } - } - - pub fn new(registry: &prometheus::Registry, method_whitelist: &[&str]) -> Self { - let metrics = Metrics { - requests_by_route: register_int_counter_vec_with_registry!( - "rpc_requests_by_route", - "Number of requests by route", - &["route"], - registry, - ) - .unwrap(), - inflight_requests_by_route: register_int_gauge_vec_with_registry!( - "inflight_rpc_requests_by_route", - "Number of inflight requests by route", - &["route"], - registry, - ) - .unwrap(), - req_latency_by_route: register_histogram_vec_with_registry!( - "req_latency_by_route", - "Latency of a request by route", - &["route"], - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - client_errors_by_route: register_int_counter_vec_with_registry!( - "client_errors_by_route", - "Number of client errors by route", - &["route"], - registry, - ) - .unwrap(), - server_errors_by_route: register_int_counter_vec_with_registry!( - "server_errors_by_route", - "Number of server errors by route", - &["route"], - registry, - ) - .unwrap(), - transient_errors_by_route: register_int_counter_vec_with_registry!( - "transient_errors_by_route", - "Number of transient errors by route", - &["route"], - registry, - ) - .unwrap(), - errors_by_route: register_int_counter_vec_with_registry!( - "errors_by_route", - "Number of client and server errors by route", - &["route"], - registry - ) - .unwrap(), - client: register_int_counter_vec_with_registry!( - "rpc_client", - "Connected RPC client's info", - &["client_type", "api_version"], - registry, - ) - .unwrap(), - inflight_connection: register_int_gauge_vec_with_registry!( - "rpc_inflight_connection", - "Number of inflight RPC connection by protocol", - &["protocol"], - registry, - ) - .unwrap(), - rpc_request_size: register_histogram_vec_with_registry!( - "rpc_request_size", - "Request size of rpc requests", - &["protocol"], - prometheus::exponential_buckets(32.0, 2.0, 19) - .unwrap() - .to_vec(), - registry, - ) - .unwrap(), - rpc_response_size: register_histogram_vec_with_registry!( - "rpc_response_size", - "Response size of rpc requests", - &["protocol"], - prometheus::exponential_buckets(1024.0, 2.0, 20) - .unwrap() - .to_vec(), - registry, - ) - .unwrap(), - }; - - Self { - metrics, - method_whitelist: method_whitelist.iter().map(|s| (*s).into()).collect(), - } - } -} - -impl Logger for MetricsLogger { - type Instant = Instant; - - fn on_connect(&self, _remote_addr: SocketAddr, request: &HttpRequest, t: TransportProtocol) { - let client_type = request - .headers() - .get(CLIENT_SDK_TYPE_HEADER) - .and_then(|v| v.to_str().ok()) - .unwrap_or("Unknown"); - - let api_version = request - .headers() - .get(CLIENT_TARGET_API_VERSION_HEADER) - .and_then(|v| v.to_str().ok()) - .unwrap_or("Unknown"); - self.metrics - .client - .with_label_values(&[client_type, api_version]) - .inc(); - self.metrics - .inflight_connection - .with_label_values(&[&t.to_string()]) - .inc(); - - self.metrics - .rpc_request_size - .with_label_values(&[&t.to_string()]) - .observe( - request - .size_hint() - .exact() - .unwrap_or_else(|| request.size_hint().lower()) as f64, - ); - } - - fn on_request(&self, _transport: TransportProtocol) -> Self::Instant { - Instant::now() - } - - fn on_call( - &self, - method_name: &str, - _params: Params, - _kind: MethodKind, - _transport: TransportProtocol, - ) { - let method_name = self.check_spam(method_name); - self.metrics - .inflight_requests_by_route - .with_label_values(&[method_name]) - .inc(); - self.metrics - .requests_by_route - .with_label_values(&[method_name]) - .inc(); - } - - fn on_result( - &self, - method_name: &str, - _success: bool, - error_code: Option, - started_at: Self::Instant, - _transport: TransportProtocol, - ) { - let method_name = self.check_spam(method_name); - self.metrics - .inflight_requests_by_route - .with_label_values(&[method_name]) - .dec(); - let req_latency_secs = (Instant::now() - started_at).as_secs_f64(); - self.metrics - .req_latency_by_route - .with_label_values(&[method_name]) - .observe(req_latency_secs); - - if let Some(code) = error_code { - if code == jsonrpsee::types::error::CALL_EXECUTION_FAILED_CODE - || code == jsonrpsee::types::error::INTERNAL_ERROR_CODE - { - self.metrics - .server_errors_by_route - .with_label_values(&[method_name]) - .inc(); - } else if code == TRANSIENT_ERROR_CODE { - self.metrics - .transient_errors_by_route - .with_label_values(&[method_name]) - .inc(); - } else { - self.metrics - .client_errors_by_route - .with_label_values(&[method_name]) - .inc(); - } - self.metrics - .errors_by_route - .with_label_values(&[method_name]) - .inc(); - } - } - - fn on_response(&self, result: &str, _started_at: Self::Instant, t: TransportProtocol) { - self.metrics - .rpc_response_size - .with_label_values(&[&t.to_string()]) - .observe(std::mem::size_of_val(result) as f64) - } - - fn on_disconnect(&self, _remote_addr: SocketAddr, t: TransportProtocol) { - self.metrics - .inflight_connection - .with_label_values(&[&t.to_string()]) - .dec(); - } -} diff --git a/crates/sui-json-rpc/src/move_utils.rs b/crates/sui-json-rpc/src/move_utils.rs deleted file mode 100644 index 24e79b05766..00000000000 --- a/crates/sui-json-rpc/src/move_utils.rs +++ /dev/null @@ -1,350 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::BTreeMap, sync::Arc}; - -use async_trait::async_trait; -use jsonrpsee::{core::RpcResult, RpcModule}; -#[cfg(test)] -use mockall::automock; -use move_binary_format::{ - binary_config::BinaryConfig, - normalized::{Module as NormalizedModule, Type}, -}; -use move_core_types::identifier::Identifier; -use sui_core::authority::AuthorityState; -use sui_json_rpc_api::{MoveUtilsOpenRpc, MoveUtilsServer}; -use sui_json_rpc_types::{ - MoveFunctionArgType, ObjectValueKind, SuiMoveNormalizedFunction, SuiMoveNormalizedModule, - SuiMoveNormalizedStruct, -}; -use sui_open_rpc::Module; -use sui_types::{ - base_types::ObjectID, - move_package::normalize_modules, - object::{Data, ObjectRead}, -}; -use tap::TapFallible; -use tracing::{error, instrument, warn}; - -use crate::{ - authority_state::StateRead, - error::{Error, SuiRpcInputError}, - with_tracing, SuiRpcModule, -}; - -#[cfg_attr(test, automock)] -#[async_trait] -pub trait MoveUtilsInternalTrait { - fn get_state(&self) -> &dyn StateRead; - - async fn get_move_module( - &self, - package: ObjectID, - module_name: String, - ) -> Result; - - async fn get_move_modules_by_package( - &self, - package: ObjectID, - ) -> Result, Error>; - - fn get_object_read(&self, package: ObjectID) -> Result; -} - -pub struct MoveUtilsInternal { - state: Arc, -} - -impl MoveUtilsInternal { - pub fn new(state: Arc) -> Self { - Self { state } - } -} - -#[async_trait] -impl MoveUtilsInternalTrait for MoveUtilsInternal { - fn get_state(&self) -> &dyn StateRead { - Arc::as_ref(&self.state) - } - - async fn get_move_module( - &self, - package: ObjectID, - module_name: String, - ) -> Result { - let normalized = self.get_move_modules_by_package(package).await?; - Ok(match normalized.get(&module_name) { - Some(module) => Ok(module.clone()), - None => Err(SuiRpcInputError::GenericNotFound(format!( - "No module found with module name {}", - module_name - ))), - }?) - } - - async fn get_move_modules_by_package( - &self, - package: ObjectID, - ) -> Result, Error> { - let object_read = self.get_state().get_object_read(&package).tap_err(|_| { - warn!("Failed to call get_move_modules_by_package for package: {package:?}"); - })?; - - match object_read { - ObjectRead::Exists(_obj_ref, object, _layout) => { - match object.into_inner().data { - Data::Package(p) => { - // we are on the read path - it's OK to use VERSION_MAX of the supported - // Move binary format - let binary_config = BinaryConfig::with_extraneous_bytes_check(false); - normalize_modules( - p.serialized_module_map().values(), - &binary_config, - ) - .map_err(|e| { - error!("Failed to call get_move_modules_by_package for package: {package:?}"); - Error::from(e) - }) - } - _ => Err(SuiRpcInputError::GenericInvalid(format!( - "Object is not a package with ID {}", - package - )))?, - } - } - _ => Err(SuiRpcInputError::GenericNotFound(format!( - "Package object does not exist with ID {}", - package - )))?, - } - } - - fn get_object_read(&self, package: ObjectID) -> Result { - self.state.get_object_read(&package).map_err(Error::from) - } -} - -pub struct MoveUtils { - internal: Arc, -} - -impl MoveUtils { - pub fn new(state: Arc) -> Self { - Self { - internal: Arc::new(MoveUtilsInternal::new(state)) - as Arc, - } - } -} - -impl SuiRpcModule for MoveUtils { - fn rpc(self) -> RpcModule { - self.into_rpc() - } - - fn rpc_doc_module() -> Module { - MoveUtilsOpenRpc::module_doc() - } -} - -#[async_trait] -impl MoveUtilsServer for MoveUtils { - #[instrument(skip(self))] - async fn get_normalized_move_modules_by_package( - &self, - package: ObjectID, - ) -> RpcResult> { - with_tracing!(async move { - let modules = self.internal.get_move_modules_by_package(package).await?; - Ok(modules - .into_iter() - .map(|(name, module)| (name, module.into())) - .collect::>()) - }) - } - - #[instrument(skip(self))] - async fn get_normalized_move_module( - &self, - package: ObjectID, - module_name: String, - ) -> RpcResult { - with_tracing!(async move { - let module = self.internal.get_move_module(package, module_name).await?; - Ok(module.into()) - }) - } - - #[instrument(skip(self))] - async fn get_normalized_move_struct( - &self, - package: ObjectID, - module_name: String, - struct_name: String, - ) -> RpcResult { - with_tracing!(async move { - let module = self.internal.get_move_module(package, module_name).await?; - let structs = module.structs; - let identifier = Identifier::new(struct_name.as_str()) - .map_err(|e| SuiRpcInputError::GenericInvalid(format!("{e}")))?; - match structs.get(&identifier) { - Some(struct_) => Ok(struct_.clone().into()), - None => Err(SuiRpcInputError::GenericNotFound(format!( - "No struct was found with struct name {}", - struct_name - )))?, - } - }) - } - - #[instrument(skip(self))] - async fn get_normalized_move_function( - &self, - package: ObjectID, - module_name: String, - function_name: String, - ) -> RpcResult { - with_tracing!(async move { - let module = self.internal.get_move_module(package, module_name).await?; - let functions = module.functions; - let identifier = Identifier::new(function_name.as_str()) - .map_err(|e| SuiRpcInputError::GenericInvalid(format!("{e}")))?; - match functions.get(&identifier) { - Some(function) => Ok(function.clone().into()), - None => Err(SuiRpcInputError::GenericNotFound(format!( - "No function was found with function name {}", - function_name - )))?, - } - }) - } - - #[instrument(skip(self))] - async fn get_move_function_arg_types( - &self, - package: ObjectID, - module: String, - function: String, - ) -> RpcResult> { - with_tracing!(async move { - let object_read = self.internal.get_object_read(package)?; - - let normalized = match object_read { - ObjectRead::Exists(_obj_ref, object, _layout) => match object.into_inner().data { - Data::Package(p) => { - // we are on the read path - it's OK to use VERSION_MAX of the supported - // Move binary format - let binary_config = BinaryConfig::with_extraneous_bytes_check(false); - normalize_modules(p.serialized_module_map().values(), &binary_config) - .map_err(Error::from) - } - _ => Err(SuiRpcInputError::GenericInvalid(format!( - "Object is not a package with ID {}", - package - )))?, - }, - _ => Err(SuiRpcInputError::GenericNotFound(format!( - "Package object does not exist with ID {}", - package - )))?, - }?; - - let identifier = Identifier::new(function.as_str()) - .map_err(|e| SuiRpcInputError::GenericInvalid(format!("{e}")))?; - let parameters = normalized - .get(&module) - .and_then(|m| m.functions.get(&identifier).map(|f| f.parameters.clone())); - - match parameters { - Some(parameters) => Ok(parameters - .iter() - .map(|p| match p { - Type::Struct { - address: _, - module: _, - name: _, - type_arguments: _, - } => MoveFunctionArgType::Object(ObjectValueKind::ByValue), - Type::Reference(_) => { - MoveFunctionArgType::Object(ObjectValueKind::ByImmutableReference) - } - Type::MutableReference(_) => { - MoveFunctionArgType::Object(ObjectValueKind::ByMutableReference) - } - _ => MoveFunctionArgType::Pure, - }) - .collect::>()), - None => Err(SuiRpcInputError::GenericNotFound(format!( - "No parameters found for function {}", - function - )))?, - } - }) - } -} - -#[cfg(test)] -mod tests { - - mod get_normalized_move_module_tests { - use jsonrpsee::types::ErrorObjectOwned; - use move_binary_format::file_format::basic_test_module; - - use super::super::*; - - fn setup() -> (ObjectID, String) { - (ObjectID::random(), String::from("test_module")) - } - - #[tokio::test] - async fn test_success_response() { - let (package, module_name) = setup(); - let mut mock_internal = MockMoveUtilsInternalTrait::new(); - - let m = basic_test_module(); - let normalized_module = NormalizedModule::new(&m); - let expected_module: SuiMoveNormalizedModule = normalized_module.clone().into(); - - mock_internal - .expect_get_move_module() - .return_once(move |_package, _module_name| Ok(normalized_module)); - - let move_utils = MoveUtils { - internal: Arc::new(mock_internal), - }; - - let response = move_utils - .get_normalized_move_module(package, module_name) - .await; - - assert!(response.is_ok()); - let result = response.unwrap(); - assert_eq!(result, expected_module); - } - - #[tokio::test] - async fn test_no_module_found() { - let (package, module_name) = setup(); - let mut mock_internal = MockMoveUtilsInternalTrait::new(); - let error_string = format!("No module found with module name {module_name}"); - let expected_error = - Error::SuiRpcInputError(SuiRpcInputError::GenericNotFound(error_string.clone())); - mock_internal - .expect_get_move_module() - .return_once(move |_package, _module_name| Err(expected_error)); - let move_utils = MoveUtils { - internal: Arc::new(mock_internal), - }; - - let response = move_utils - .get_normalized_move_module(package, module_name) - .await; - let error_result = response.unwrap_err(); - let error_object: ErrorObjectOwned = error_result.into(); - - assert_eq!(error_object.code(), -32602); - assert_eq!(error_object.message(), &error_string); - } - } -} diff --git a/crates/sui-json-rpc/src/object_changes.rs b/crates/sui-json-rpc/src/object_changes.rs deleted file mode 100644 index b6a661a2fa7..00000000000 --- a/crates/sui-json-rpc/src/object_changes.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use sui_json_rpc_types::ObjectChange; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress}, - effects::ObjectRemoveKind, - object::Owner, - storage::WriteKind, -}; - -use crate::ObjectProvider; - -pub async fn get_object_changes, E>( - object_provider: &P, - sender: SuiAddress, - modified_at_versions: Vec<(ObjectID, SequenceNumber)>, - all_changed_objects: Vec<(ObjectRef, Owner, WriteKind)>, - all_removed_objects: Vec<(ObjectRef, ObjectRemoveKind)>, -) -> Result, E> { - let mut object_changes = vec![]; - - let modify_at_version = modified_at_versions.into_iter().collect::>(); - - for ((object_id, version, digest), owner, kind) in all_changed_objects { - let o = object_provider.get_object(&object_id, &version).await?; - if let Some(type_) = o.type_() { - let object_type = type_.clone().into(); - - match kind { - WriteKind::Mutate => object_changes.push(ObjectChange::Mutated { - sender, - owner, - object_type, - object_id, - version, - // modify_at_version should always be available for mutated object - previous_version: modify_at_version - .get(&object_id) - .cloned() - .unwrap_or_default(), - digest, - }), - WriteKind::Create => object_changes.push(ObjectChange::Created { - sender, - owner, - object_type, - object_id, - version, - digest, - }), - _ => {} - } - } else if let Some(p) = o.data.try_as_package() { - if kind == WriteKind::Create { - object_changes.push(ObjectChange::Published { - package_id: p.id(), - version: p.version(), - digest, - modules: p.serialized_module_map().keys().cloned().collect(), - }) - } - }; - } - - for ((id, version, _), kind) in all_removed_objects { - let o = object_provider - .find_object_lt_or_eq_version(&id, &version) - .await?; - if let Some(o) = o { - if let Some(type_) = o.type_() { - let object_type = type_.clone().into(); - match kind { - ObjectRemoveKind::Delete => object_changes.push(ObjectChange::Deleted { - sender, - object_type, - object_id: id, - version, - }), - ObjectRemoveKind::Wrap => object_changes.push(ObjectChange::Wrapped { - sender, - object_type, - object_id: id, - version, - }), - } - } - }; - } - - Ok(object_changes) -} diff --git a/crates/sui-json-rpc/src/read_api.rs b/crates/sui-json-rpc/src/read_api.rs deleted file mode 100644 index 7517c305a36..00000000000 --- a/crates/sui-json-rpc/src/read_api.rs +++ /dev/null @@ -1,1483 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::HashMap, sync::Arc}; - -use anyhow::anyhow; -use async_trait::async_trait; -use futures::future::join_all; -use indexmap::map::IndexMap; -use itertools::Itertools; -use jsonrpsee::{core::RpcResult, RpcModule}; -use move_bytecode_utils::module_cache::GetModule; -use move_core_types::{ - annotated_value::{MoveStruct, MoveStructLayout, MoveValue}, - language_storage::StructTag, -}; -use mysten_metrics::spawn_monitored_task; -use sui_core::authority::AuthorityState; -use sui_json_rpc_api::{ - validate_limit, JsonRpcMetrics, ReadApiOpenRpc, ReadApiServer, QUERY_MAX_RESULT_LIMIT, - QUERY_MAX_RESULT_LIMIT_CHECKPOINTS, -}; -use sui_json_rpc_types::{ - BalanceChange, Checkpoint, CheckpointId, CheckpointPage, DisplayFieldsResponse, EventFilter, - ObjectChange, ProtocolConfigResponse, SuiEvent, SuiGetPastObjectRequest, SuiLoadedChildObject, - SuiLoadedChildObjectsResponse, SuiMoveStruct, SuiMoveValue, SuiObjectDataOptions, - SuiObjectResponse, SuiPastObjectResponse, SuiTransactionBlock, SuiTransactionBlockEvents, - SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, -}; -use sui_open_rpc::Module; -use sui_protocol_config::{ProtocolConfig, ProtocolVersion}; -use sui_storage::key_value_store::TransactionKeyValueStore; -use sui_types::{ - base_types::{ObjectID, SequenceNumber, TransactionDigest}, - collection_types::VecMap, - crypto::AggregateAuthoritySignature, - digests::TransactionEventsDigest, - display::DisplayVersionUpdatedEvent, - effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, - error::{SuiError, SuiObjectResponseError}, - messages_checkpoint::{ - CheckpointContents, CheckpointContentsDigest, CheckpointSequenceNumber, CheckpointSummary, - CheckpointTimestamp, - }, - object::{Object, ObjectRead, PastObjectRead}, - sui_serde::BigInt, - transaction::{Transaction, TransactionDataAPI}, -}; -use tap::TapFallible; -use tracing::{debug, error, info, instrument, trace, warn}; - -use crate::{ - authority_state::{StateRead, StateReadError, StateReadResult}, - error::{Error, RpcInterimResult, SuiRpcInputError}, - get_balance_changes_from_effect, get_object_changes, with_tracing, ObjectProviderCache, - SuiRpcModule, -}; - -const MAX_DISPLAY_NESTED_LEVEL: usize = 10; - -// An implementation of the read portion of the JSON-RPC interface intended for -// use in Fullnodes. -#[derive(Clone)] -pub struct ReadApi { - pub state: Arc, - pub transaction_kv_store: Arc, - pub metrics: Arc, -} - -// Internal data structure to make it easy to work with data returned from -// authority store and also enable code sharing between -// get_transaction_with_options, multi_get_transaction_with_options, etc. -#[derive(Default)] -struct IntermediateTransactionResponse { - digest: TransactionDigest, - transaction: Option, - effects: Option, - events: Option, - checkpoint_seq: Option, - balance_changes: Option>, - object_changes: Option>, - timestamp: Option, - errors: Vec, -} - -impl IntermediateTransactionResponse { - pub fn new(digest: TransactionDigest) -> Self { - Self { - digest, - ..Default::default() - } - } - - pub fn transaction(&self) -> &Option { - &self.transaction - } -} - -impl ReadApi { - pub fn new( - state: Arc, - transaction_kv_store: Arc, - metrics: Arc, - ) -> Self { - Self { - state, - transaction_kv_store, - metrics, - } - } - - async fn get_checkpoint_internal(&self, id: CheckpointId) -> Result { - Ok(match id { - CheckpointId::SequenceNumber(seq) => { - let verified_summary = self - .transaction_kv_store - .get_checkpoint_summary(seq) - .await?; - let content = self - .transaction_kv_store - .get_checkpoint_contents_by_digest(verified_summary.content_digest) - .await?; - let signature = verified_summary.auth_sig().signature.clone(); - (verified_summary.into_data(), content, signature).into() - } - CheckpointId::Digest(digest) => { - let verified_summary = self - .transaction_kv_store - .get_checkpoint_summary_by_digest(digest) - .await?; - let content = self - .transaction_kv_store - .get_checkpoint_contents_by_digest(verified_summary.content_digest) - .await?; - let signature = verified_summary.auth_sig().signature.clone(); - (verified_summary.into_data(), content, signature).into() - } - }) - } - - pub async fn get_checkpoints_internal( - state: Arc, - transaction_kv_store: Arc, - // If `Some`, the query will start from the next item after the specified cursor - cursor: Option, - limit: u64, - descending_order: bool, - ) -> StateReadResult> { - let max_checkpoint = state.get_latest_checkpoint_sequence_number()?; - let checkpoint_numbers = - calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); - - let verified_checkpoints = transaction_kv_store - .multi_get_checkpoints_summaries(&checkpoint_numbers) - .await?; - - let checkpoint_summaries_and_signatures: Vec<( - CheckpointSummary, - AggregateAuthoritySignature, - )> = verified_checkpoints - .into_iter() - .flatten() - .map(|check| { - ( - check.clone().into_summary_and_sequence().1, - check.get_validator_signature(), - ) - }) - .collect(); - - let checkpoint_contents_digest: Vec = - checkpoint_summaries_and_signatures - .iter() - .map(|summary| summary.0.content_digest) - .collect(); - let checkpoint_contents = transaction_kv_store - .multi_get_checkpoints_contents_by_digest(checkpoint_contents_digest.as_slice()) - .await?; - let contents: Vec = checkpoint_contents.into_iter().flatten().collect(); - - let mut checkpoints: Vec = vec![]; - - for (summary_and_sig, content) in checkpoint_summaries_and_signatures - .into_iter() - .zip(contents.into_iter()) - { - checkpoints.push(Checkpoint::from(( - summary_and_sig.0, - content, - summary_and_sig.1, - ))); - } - - Ok(checkpoints) - } - - async fn multi_get_transaction_blocks_internal( - &self, - digests: Vec, - opts: Option, - ) -> Result, Error> { - trace!("start"); - - let num_digests = digests.len(); - if num_digests > *QUERY_MAX_RESULT_LIMIT { - Err(SuiRpcInputError::SizeLimitExceeded( - QUERY_MAX_RESULT_LIMIT.to_string(), - ))? - } - self.metrics - .get_tx_blocks_limit - .report(digests.len() as u64); - - let opts = opts.unwrap_or_default(); - - // use LinkedHashMap to dedup and can iterate in insertion order. - let mut temp_response: IndexMap<&TransactionDigest, IntermediateTransactionResponse> = - IndexMap::from_iter( - digests - .iter() - .map(|k| (k, IntermediateTransactionResponse::new(*k))), - ); - if temp_response.len() < num_digests { - Err(SuiRpcInputError::ContainsDuplicates)? - } - - if opts.require_input() { - trace!("getting input"); - let digests_clone = digests.clone(); - let transactions = - self.transaction_kv_store.multi_get_tx(&digests_clone).await.tap_err( - |err| debug!(digests=?digests_clone, "Failed to multi get transactions: {:?}", err), - )?; - - for ((_digest, cache_entry), txn) in - temp_response.iter_mut().zip(transactions.into_iter()) - { - cache_entry.transaction = txn; - } - } - - // Fetch effects when `show_events` is true because events relies on effects - if opts.require_effects() { - trace!("getting effects"); - let digests_clone = digests.clone(); - let effects_list = self.transaction_kv_store - .multi_get_fx_by_tx_digest(&digests_clone) - .await - .tap_err( - |err| debug!(digests=?digests_clone, "Failed to multi get effects for transactions: {:?}", err), - )?; - for ((_digest, cache_entry), e) in - temp_response.iter_mut().zip(effects_list.into_iter()) - { - cache_entry.effects = e; - } - } - - trace!("getting checkpoint sequence numbers"); - let checkpoint_seq_list = self - .transaction_kv_store - .multi_get_transaction_checkpoint(&digests) - .await - .tap_err( - |err| debug!(digests=?digests, "Failed to multi get checkpoint sequence number: {:?}", err))?; - for ((_digest, cache_entry), seq) in temp_response - .iter_mut() - .zip(checkpoint_seq_list.into_iter()) - { - cache_entry.checkpoint_seq = seq; - } - - let unique_checkpoint_numbers = temp_response - .values() - .filter_map(|cache_entry| cache_entry.checkpoint_seq.map(::from)) - // It's likely that many transactions have the same checkpoint, so we don't - // need to over-fetch - .unique() - .collect::>(); - - // fetch timestamp from the DB - trace!("getting checkpoint summaries"); - let timestamps = self - .transaction_kv_store - .multi_get_checkpoints_summaries(&unique_checkpoint_numbers) - .await - .map_err(|e| { - Error::UnexpectedError(format!("Failed to fetch checkpoint summaries by these checkpoint ids: {unique_checkpoint_numbers:?} with error: {e:?}")) - })? - .into_iter() - .map(|c| c.map(|checkpoint| checkpoint.timestamp_ms)); - - // construct a hashmap of checkpoint -> timestamp for fast lookup - let checkpoint_to_timestamp = unique_checkpoint_numbers - .into_iter() - .zip(timestamps) - .collect::>(); - - // fill cache with the timestamp - for (_, cache_entry) in temp_response.iter_mut() { - if cache_entry.checkpoint_seq.is_some() { - // safe to unwrap because is_some is checked - cache_entry.timestamp = *checkpoint_to_timestamp - .get( - cache_entry - .checkpoint_seq - .map(::from) - .as_ref() - .unwrap(), - ) - // Safe to unwrap because checkpoint_seq is guaranteed to exist in - // checkpoint_to_timestamp - .unwrap(); - } - } - - if opts.show_events { - trace!("getting events"); - - let event_digests_list = temp_response - .values() - .filter_map(|cache_entry| match &cache_entry.effects { - Some(eff) => eff.events_digest().cloned(), - None => None, - }) - .collect::>(); - - // fetch events from the DB - let events = self - .transaction_kv_store - .multi_get_events(&event_digests_list) - .await - .map_err(|e| { - Error::UnexpectedError(format!("Failed to call multi_get_events for transactions {digests:?} with event digests {event_digests_list:?}: {e:?}")) - })? - .into_iter(); - - // construct a hashmap of event digests -> events for fast lookup - let event_digest_to_events = event_digests_list - .into_iter() - .zip(events) - .collect::>(); - - // fill cache with the events - for (_, cache_entry) in temp_response.iter_mut() { - let transaction_digest = cache_entry.digest; - let event_digest: Option> = cache_entry - .effects - .as_ref() - .map(|e| e.events_digest().cloned()); - let event_digest = event_digest.flatten(); - if event_digest.is_some() { - // safe to unwrap because `is_some` is checked - let event_digest = event_digest.as_ref().unwrap(); - let events= event_digest_to_events - .get(event_digest) - .cloned() - .unwrap_or_else(|| panic!("Expect event digest {event_digest:?} to be found in cache for transaction {transaction_digest}")) - .map(|events| to_sui_transaction_events(self, cache_entry.digest, events)); - match events { - Some(Ok(e)) => cache_entry.events = Some(e), - Some(Err(e)) => cache_entry.errors.push(e.to_string()), - None => { - error!( - "Failed to fetch events with event digest {event_digest:?} for txn {transaction_digest}" - ); - cache_entry.errors.push(format!( - "Failed to fetch events with event digest {event_digest:?}", - )) - } - } - } else { - // events field will be Some if and only if `show_events` is true and - // there is no error in converting fetching events - cache_entry.events = Some(SuiTransactionBlockEvents::default()); - } - } - } - - let object_cache = - ObjectProviderCache::new((self.state.clone(), self.transaction_kv_store.clone())); - if opts.show_balance_changes { - trace!("getting balance changes"); - - let mut results = vec![]; - for resp in temp_response.values() { - let input_objects = if let Some(tx) = resp.transaction() { - tx.data() - .inner() - .intent_message - .value - .input_objects() - .unwrap_or_default() - } else { - // don't have the input tx, so not much we can do. perhaps this is an Err? - Vec::new() - }; - results.push(get_balance_changes_from_effect( - &object_cache, - resp.effects.as_ref().ok_or_else(|| { - SuiRpcInputError::GenericNotFound( - "unable to derive balance changes because effect is empty".to_string(), - ) - })?, - input_objects, - None, - )); - } - let results = join_all(results).await; - for (result, entry) in results.into_iter().zip(temp_response.iter_mut()) { - match result { - Ok(balance_changes) => entry.1.balance_changes = Some(balance_changes), - Err(e) => entry - .1 - .errors - .push(format!("Failed to fetch balance changes {e:?}")), - } - } - } - - if opts.show_object_changes { - trace!("getting object changes"); - - let mut results = vec![]; - for resp in temp_response.values() { - let effects = resp.effects.as_ref().ok_or_else(|| { - SuiRpcInputError::GenericNotFound( - "unable to derive object changes because effect is empty".to_string(), - ) - })?; - - results.push(get_object_changes( - &object_cache, - resp.transaction - .as_ref() - .ok_or_else(|| { - SuiRpcInputError::GenericNotFound( - "unable to derive object changes because transaction is empty" - .to_string(), - ) - })? - .data() - .intent_message() - .value - .sender(), - effects.modified_at_versions(), - effects.all_changed_objects(), - effects.all_removed_objects(), - )); - } - let results = join_all(results).await; - for (result, entry) in results.into_iter().zip(temp_response.iter_mut()) { - match result { - Ok(object_changes) => entry.1.object_changes = Some(object_changes), - Err(e) => entry - .1 - .errors - .push(format!("Failed to fetch object changes {e:?}")), - } - } - } - - let epoch_store = self.state.load_epoch_store_one_call_per_task(); - let converted_tx_block_resps = temp_response - .into_iter() - .map(|c| convert_to_response(c.1, &opts, epoch_store.module_cache())) - .collect::, _>>()?; - - self.metrics - .get_tx_blocks_result_size - .report(converted_tx_block_resps.len() as u64); - self.metrics - .get_tx_blocks_result_size_total - .inc_by(converted_tx_block_resps.len() as u64); - - trace!("done"); - - Ok(converted_tx_block_resps) - } -} - -#[async_trait] -impl ReadApiServer for ReadApi { - #[instrument(skip(self))] - async fn get_object( - &self, - object_id: ObjectID, - options: Option, - ) -> RpcResult { - with_tracing!(async move { - let state = self.state.clone(); - let object_read = spawn_monitored_task!(async move { - state.get_object_read(&object_id).map_err(|e| { - warn!(?object_id, "Failed to get object: {:?}", e); - Error::from(e) - }) - }) - .await - .map_err(Error::from)??; - let options = options.unwrap_or_default(); - - match object_read { - ObjectRead::NotExists(id) => Ok(SuiObjectResponse::new_with_error( - SuiObjectResponseError::NotExists { object_id: id }, - )), - ObjectRead::Exists(object_ref, o, layout) => { - let mut display_fields = None; - if options.show_display { - match get_display_fields(self, &self.transaction_kv_store, &o, &layout) - .await - { - Ok(rendered_fields) => display_fields = Some(rendered_fields), - Err(e) => { - return Ok(SuiObjectResponse::new( - Some((object_ref, o, layout, options, None).try_into()?), - Some(SuiObjectResponseError::DisplayError { - error: e.to_string(), - }), - )); - } - } - } - Ok(SuiObjectResponse::new_with_data( - (object_ref, o, layout, options, display_fields).try_into()?, - )) - } - ObjectRead::Deleted((object_id, version, digest)) => Ok( - SuiObjectResponse::new_with_error(SuiObjectResponseError::Deleted { - object_id, - version, - digest, - }), - ), - } - }) - } - - #[instrument(skip(self))] - async fn multi_get_objects( - &self, - object_ids: Vec, - options: Option, - ) -> RpcResult> { - with_tracing!(async move { - if object_ids.len() <= *QUERY_MAX_RESULT_LIMIT { - self.metrics - .get_objects_limit - .report(object_ids.len() as u64); - let mut futures = vec![]; - for object_id in object_ids { - futures.push(self.get_object(object_id, options.clone())); - } - let results = join_all(futures).await; - - let objects_result: Result, String> = results - .into_iter() - .map(|result| match result { - Ok(response) => Ok(response), - Err(error) => { - error!("Failed to fetch object with error: {error:?}"); - Err(format!("Error: {}", error)) - } - }) - .collect(); - - let objects = objects_result.map_err(|err| { - Error::UnexpectedError(format!("Failed to fetch objects with error: {}", err)) - })?; - - self.metrics - .get_objects_result_size - .report(objects.len() as u64); - self.metrics - .get_objects_result_size_total - .inc_by(objects.len() as u64); - Ok(objects) - } else { - Err(SuiRpcInputError::SizeLimitExceeded( - QUERY_MAX_RESULT_LIMIT.to_string(), - ))? - } - }) - } - - #[instrument(skip(self))] - async fn try_get_past_object( - &self, - object_id: ObjectID, - version: SequenceNumber, - options: Option, - ) -> RpcResult { - with_tracing!(async move { - let state = self.state.clone(); - let past_read = spawn_monitored_task!(async move { - state.get_past_object_read(&object_id, version) - .map_err(|e| { - error!("Failed to call try_get_past_object for object: {object_id:?} version: {version:?} with error: {e:?}"); - Error::from(e) - })}).await.map_err(Error::from)??; - let options = options.unwrap_or_default(); - match past_read { - PastObjectRead::ObjectNotExists(id) => { - Ok(SuiPastObjectResponse::ObjectNotExists(id)) - } - PastObjectRead::VersionFound(object_ref, o, layout) => { - let display_fields = if options.show_display { - // TODO (jian): api breaking change to also modify past objects. - Some( - get_display_fields(self, &self.transaction_kv_store, &o, &layout) - .await - .map_err(|e| { - Error::UnexpectedError(format!( - "Unable to render object at version {version}: {e}" - )) - })?, - ) - } else { - None - }; - Ok(SuiPastObjectResponse::VersionFound( - (object_ref, o, layout, options, display_fields).try_into()?, - )) - } - PastObjectRead::ObjectDeleted(oref) => { - Ok(SuiPastObjectResponse::ObjectDeleted(oref.into())) - } - PastObjectRead::VersionNotFound(id, seq_num) => { - Ok(SuiPastObjectResponse::VersionNotFound(id, seq_num)) - } - PastObjectRead::VersionTooHigh { - object_id, - asked_version, - latest_version, - } => Ok(SuiPastObjectResponse::VersionTooHigh { - object_id, - asked_version, - latest_version, - }), - } - }) - } - - #[instrument(skip(self))] - async fn try_multi_get_past_objects( - &self, - past_objects: Vec, - options: Option, - ) -> RpcResult> { - with_tracing!(async move { - if past_objects.len() <= *QUERY_MAX_RESULT_LIMIT { - let mut futures = vec![]; - for past_object in past_objects { - futures.push(self.try_get_past_object( - past_object.object_id, - past_object.version, - options.clone(), - )); - } - let results = join_all(futures).await; - - let (oks, errs): (Vec<_>, Vec<_>) = results.into_iter().partition(Result::is_ok); - let success = oks.into_iter().filter_map(Result::ok).collect(); - let errors: Vec<_> = errs.into_iter().filter_map(Result::err).collect(); - if !errors.is_empty() { - let error_string = errors - .iter() - .map(|e| e.to_string()) - .collect::>() - .join("; "); - Err(anyhow!("{error_string}").into()) // Collects errors not related to SuiPastObjectResponse variants - } else { - Ok(success) - } - } else { - Err(SuiRpcInputError::SizeLimitExceeded( - QUERY_MAX_RESULT_LIMIT.to_string(), - ))? - } - }) - } - - #[instrument(skip(self))] - async fn get_total_transaction_blocks(&self) -> RpcResult> { - with_tracing!(async move { - Ok(self - .state - .get_total_transaction_blocks() - .map_err(Error::from)? - .into()) // converts into BigInt - }) - } - - #[instrument(skip(self))] - async fn get_transaction_block( - &self, - digest: TransactionDigest, - opts: Option, - ) -> RpcResult { - with_tracing!(async move { - let opts = opts.unwrap_or_default(); - let mut temp_response = IntermediateTransactionResponse::new(digest); - - // Fetch transaction to determine existence - let transaction_kv_store = self.transaction_kv_store.clone(); - let transaction = spawn_monitored_task!(async move { - transaction_kv_store.get_tx(digest).await.map_err(|err| { - debug!(tx_digest=?digest, "Failed to get transaction: {:?}", err); - Error::from(err) - }) - }) - .await - .map_err(Error::from)??; - let input_objects = transaction - .data() - .inner() - .intent_message - .value - .input_objects() - .unwrap_or_default(); - - // the input is needed for object_changes to retrieve the sender address. - if opts.require_input() { - temp_response.transaction = Some(transaction); - } - - // Fetch effects when `show_events` is true because events relies on effects - if opts.require_effects() { - let transaction_kv_store = self.transaction_kv_store.clone(); - temp_response.effects = Some( - spawn_monitored_task!(async move { - transaction_kv_store - .get_fx_by_tx_digest(digest) - .await - .map_err(|err| { - debug!(tx_digest=?digest, "Failed to get effects: {:?}", err); - Error::from(err) - }) - }) - .await - .map_err(Error::from)??, - ); - } - - temp_response.checkpoint_seq = self - .transaction_kv_store - .deprecated_get_transaction_checkpoint(digest) - .await - .map_err(|e| { - error!("Failed to retrieve checkpoint sequence for transaction {digest:?} with error: {e:?}"); - Error::from(e) - })?; - - if let Some(checkpoint_seq) = &temp_response.checkpoint_seq { - let kv_store = self.transaction_kv_store.clone(); - let checkpoint_seq = *checkpoint_seq; - let checkpoint = spawn_monitored_task!(async move { - kv_store - // safe to unwrap because we have checked `is_some` above - .get_checkpoint_summary(checkpoint_seq) - .await - .map_err(|e| { - error!("Failed to get checkpoint by sequence number: {checkpoint_seq:?} with error: {e:?}"); - Error::from(e) - }) - }).await.map_err(Error::from)??; - // TODO(chris): we don't need to fetch the whole checkpoint summary - temp_response.timestamp = Some(checkpoint.timestamp_ms); - } - - if opts.show_events && temp_response.effects.is_some() { - // safe to unwrap because we have checked is_some - if let Some(event_digest) = temp_response.effects.as_ref().unwrap().events_digest() - { - let transaction_kv_store = self.transaction_kv_store.clone(); - let event_digest = *event_digest; - let events = spawn_monitored_task!(async move { - transaction_kv_store - .get_events(event_digest) - .await - .map_err(|e| { - error!("Failed to call get transaction events for events digest: {event_digest:?} with error {e:?}"); - Error::from(e) - }) - }) - .await - .map_err(Error::from)??; - match to_sui_transaction_events(self, digest, events) { - Ok(e) => temp_response.events = Some(e), - Err(e) => temp_response.errors.push(e.to_string()), - }; - } else { - // events field will be Some if and only if `show_events` is true and - // there is no error in converting fetching events - temp_response.events = Some(SuiTransactionBlockEvents::default()); - } - } - - let object_cache = - ObjectProviderCache::new((self.state.clone(), self.transaction_kv_store.clone())); - if opts.show_balance_changes { - if let Some(effects) = &temp_response.effects { - let balance_changes = get_balance_changes_from_effect( - &object_cache, - effects, - input_objects, - None, - ) - .await; - - if let Ok(balance_changes) = balance_changes { - temp_response.balance_changes = Some(balance_changes); - } else { - temp_response.errors.push(format!( - "Cannot retrieve balance changes: {}", - balance_changes.unwrap_err() - )); - } - } - } - - if opts.show_object_changes { - if let (Some(effects), Some(input)) = - (&temp_response.effects, &temp_response.transaction) - { - let sender = input.data().intent_message().value.sender(); - let object_changes = get_object_changes( - &object_cache, - sender, - effects.modified_at_versions(), - effects.all_changed_objects(), - effects.all_removed_objects(), - ) - .await; - - if let Ok(object_changes) = object_changes { - temp_response.object_changes = Some(object_changes); - } else { - temp_response.errors.push(format!( - "Cannot retrieve object changes: {}", - object_changes.unwrap_err() - )); - } - } - } - let epoch_store = self.state.load_epoch_store_one_call_per_task(); - convert_to_response(temp_response, &opts, epoch_store.module_cache()) - }) - } - - #[instrument(skip(self))] - async fn multi_get_transaction_blocks( - &self, - digests: Vec, - opts: Option, - ) -> RpcResult> { - with_tracing!(async move { - let cloned_self = self.clone(); - spawn_monitored_task!(async move { - cloned_self - .multi_get_transaction_blocks_internal(digests, opts) - .await - }) - .await - .map_err(Error::from)? - }) - } - - #[instrument(skip(self))] - async fn get_events(&self, transaction_digest: TransactionDigest) -> RpcResult> { - with_tracing!(async move { - let state = self.state.clone(); - let transaction_kv_store = self.transaction_kv_store.clone(); - spawn_monitored_task!(async move{ - let store = state.load_epoch_store_one_call_per_task(); - let effect = transaction_kv_store - .get_fx_by_tx_digest(transaction_digest) - .await - .map_err(Error::from)?; - let events = if let Some(event_digest) = effect.events_digest() { - transaction_kv_store - .get_events(*event_digest) - .await - .map_err( - |e| { - error!("Failed to get transaction events for event digest {event_digest:?} with error: {e:?}"); - Error::StateReadError(e.into()) - })? - .data - .into_iter() - .enumerate() - .map(|(seq, e)| { - let layout = store.executor().type_layout_resolver(Box::new(&state.get_backing_package_store().as_ref())).get_annotated_layout(&e.type_)?; - SuiEvent::try_from( - e, - *effect.transaction_digest(), - seq as u64, - None, - layout, - ) - }) - .collect::, _>>() - .map_err(Error::SuiError)? - } else { - vec![] - }; - Ok(events) - }).await.map_err(Error::from)? - }) - } - - #[instrument(skip(self))] - async fn get_latest_checkpoint_sequence_number(&self) -> RpcResult> { - with_tracing!(async move { - Ok(self - .state - .get_latest_checkpoint_sequence_number() - .map_err(|e| { - SuiRpcInputError::GenericNotFound(format!( - "Latest checkpoint sequence number was not found with error :{e}" - )) - })? - .into()) - }) - } - - #[instrument(skip(self))] - async fn get_checkpoint(&self, id: CheckpointId) -> RpcResult { - with_tracing!(self.get_checkpoint_internal(id)) - } - - #[instrument(skip(self))] - async fn get_checkpoints( - &self, - // If `Some`, the query will start from the next item after the specified cursor - cursor: Option>, - limit: Option, - descending_order: bool, - ) -> RpcResult { - with_tracing!(async move { - let limit = validate_limit(limit, QUERY_MAX_RESULT_LIMIT_CHECKPOINTS) - .map_err(SuiRpcInputError::from)?; - - let state = self.state.clone(); - let kv_store = self.transaction_kv_store.clone(); - - self.metrics.get_checkpoints_limit.report(limit as u64); - - let mut data = spawn_monitored_task!(Self::get_checkpoints_internal( - state, - kv_store, - cursor.map(|s| *s), - limit as u64 + 1, - descending_order, - )) - .await - .map_err(Error::from)? - .map_err(Error::from)?; - - let has_next_page = data.len() > limit; - data.truncate(limit); - - let next_cursor = if has_next_page { - data.last().cloned().map(|d| d.sequence_number.into()) - } else { - None - }; - - self.metrics - .get_checkpoints_result_size - .report(data.len() as u64); - self.metrics - .get_checkpoints_result_size_total - .inc_by(data.len() as u64); - - Ok(CheckpointPage { - data, - next_cursor, - has_next_page, - }) - }) - } - - #[instrument(skip(self))] - async fn get_checkpoints_deprecated_limit( - &self, - cursor: Option>, - limit: Option>, - descending_order: bool, - ) -> RpcResult { - with_tracing!(async move { - self.get_checkpoints(cursor, limit.map(|l| *l as usize), descending_order) - .await - .map_err(Error::from) - }) - } - - #[instrument(skip(self))] - async fn get_loaded_child_objects( - &self, - digest: TransactionDigest, - ) -> RpcResult { - with_tracing!(async move { - Ok(SuiLoadedChildObjectsResponse { - loaded_child_objects: match self - .state - .loaded_child_object_versions(&digest) - .map_err(|e| { - error!( - "Failed to get loaded child objects at {digest:?} with error: {e:?}" - ); - Error::StateReadError(e) - })? { - Some(v) => v - .into_iter() - .map(|q| SuiLoadedChildObject::new(q.0, q.1)) - .collect::>(), - None => vec![], - }, - }) - }) - } - - #[instrument(skip(self))] - async fn get_protocol_config( - &self, - version: Option>, - ) -> RpcResult { - with_tracing!(async move { - version - .map(|v| { - ProtocolConfig::get_for_version_if_supported( - (*v).into(), - self.state.get_chain_identifier()?.chain(), - ) - .ok_or(SuiRpcInputError::ProtocolVersionUnsupported( - ProtocolVersion::MIN.as_u64(), - ProtocolVersion::MAX.as_u64(), - )) - .map_err(Error::from) - }) - .unwrap_or(Ok(self - .state - .load_epoch_store_one_call_per_task() - .protocol_config() - .clone())) - .map(ProtocolConfigResponse::from) - }) - } - - #[instrument(skip(self))] - async fn get_chain_identifier(&self) -> RpcResult { - with_tracing!(async move { - let ci = self.state.get_chain_identifier()?; - Ok(ci.to_string()) - }) - } -} - -impl SuiRpcModule for ReadApi { - fn rpc(self) -> RpcModule { - self.into_rpc() - } - - fn rpc_doc_module() -> Module { - ReadApiOpenRpc::module_doc() - } -} - -fn to_sui_transaction_events( - fullnode_api: &ReadApi, - tx_digest: TransactionDigest, - events: TransactionEvents, -) -> Result { - let epoch_store = fullnode_api.state.load_epoch_store_one_call_per_task(); - let backing_package_store = fullnode_api.state.get_backing_package_store(); - let mut layout_resolver = epoch_store - .executor() - .type_layout_resolver(Box::new(backing_package_store.as_ref())); - Ok(SuiTransactionBlockEvents::try_from( - events, - tx_digest, - None, - layout_resolver.as_mut(), - )?) -} - -#[derive(Debug, thiserror::Error)] -pub enum ObjectDisplayError { - #[error("Not a move struct")] - NotMoveStruct, - - #[error("Failed to extract layout")] - Layout, - - #[error("Failed to extract Move object")] - MoveObject, - - #[error(transparent)] - Deserialization(#[from] SuiError), - - #[error("Failed to deserialize 'VersionUpdatedEvent': {0}")] - Bcs(#[from] bcs::Error), - - #[error(transparent)] - StateReadError(#[from] StateReadError), -} - -async fn get_display_fields( - fullnode_api: &ReadApi, - kv_store: &Arc, - original_object: &Object, - original_layout: &Option, -) -> Result { - let Some((object_type, layout)) = get_object_type_and_struct(original_object, original_layout)? - else { - return Ok(DisplayFieldsResponse { - data: None, - error: None, - }); - }; - if let Some(display_object) = - get_display_object_by_type(kv_store, fullnode_api, &object_type).await? - { - return get_rendered_fields(display_object.fields, &layout); - } - Ok(DisplayFieldsResponse { - data: None, - error: None, - }) -} - -async fn get_display_object_by_type( - kv_store: &Arc, - fullnode_api: &ReadApi, - object_type: &StructTag, - // TODO: add query version support -) -> Result, ObjectDisplayError> { - let mut events = fullnode_api - .state - .query_events( - kv_store, - EventFilter::MoveEventType(DisplayVersionUpdatedEvent::type_(object_type)), - None, - 1, - true, - ) - .await?; - - // If there's any recent version of Display, give it to the client. - // TODO: add support for version query. - if let Some(event) = events.pop() { - let display: DisplayVersionUpdatedEvent = bcs::from_bytes(&event.bcs[..])?; - Ok(Some(display)) - } else { - Ok(None) - } -} - -pub fn get_object_type_and_struct( - o: &Object, - layout: &Option, -) -> Result, ObjectDisplayError> { - if let Some(object_type) = o.type_() { - let move_struct = get_move_struct(o, layout)?; - Ok(Some((object_type.clone().into(), move_struct))) - } else { - Ok(None) - } -} - -fn get_move_struct( - o: &Object, - layout: &Option, -) -> Result { - let layout = layout.as_ref().ok_or_else(|| ObjectDisplayError::Layout)?; - Ok(o.data - .try_as_move() - .ok_or_else(|| ObjectDisplayError::MoveObject)? - .to_move_struct(layout)?) -} - -pub fn get_rendered_fields( - fields: VecMap, - move_struct: &MoveStruct, -) -> Result { - let sui_move_value: SuiMoveValue = MoveValue::Struct(move_struct.clone()).into(); - if let SuiMoveValue::Struct(move_struct) = sui_move_value { - let fields = - fields - .contents - .iter() - .map(|entry| match parse_template(&entry.value, &move_struct) { - Ok(value) => Ok((entry.key.clone(), value)), - Err(e) => Err(e), - }); - let (oks, errs): (Vec<_>, Vec<_>) = fields.partition(Result::is_ok); - let success = oks.into_iter().filter_map(Result::ok).collect(); - let errors: Vec<_> = errs.into_iter().filter_map(Result::err).collect(); - let error_string = errors - .iter() - .map(|e| e.to_string()) - .collect::>() - .join("; "); - let error = if !error_string.is_empty() { - Some(SuiObjectResponseError::DisplayError { - error: anyhow!("{error_string}").to_string(), - }) - } else { - None - }; - - return Ok(DisplayFieldsResponse { - data: Some(success), - error, - }); - } - Err(ObjectDisplayError::NotMoveStruct)? -} - -fn parse_template(template: &str, move_struct: &SuiMoveStruct) -> Result { - let mut output = template.to_string(); - let mut var_name = String::new(); - let mut in_braces = false; - let mut escaped = false; - - for ch in template.chars() { - match ch { - '\\' => { - escaped = true; - continue; - } - '{' if !escaped => { - in_braces = true; - var_name.clear(); - } - '}' if !escaped => { - in_braces = false; - let value = get_value_from_move_struct(move_struct, &var_name)?; - output = output.replace(&format!("{{{}}}", var_name), &value.to_string()); - } - _ if !escaped => { - if in_braces { - var_name.push(ch); - } - } - _ => {} - } - escaped = false; - } - - Ok(output.replace('\\', "")) -} - -fn get_value_from_move_struct( - move_struct: &SuiMoveStruct, - var_name: &str, -) -> Result { - let parts: Vec<&str> = var_name.split('.').collect(); - if parts.is_empty() { - Err(anyhow!("Display template value cannot be empty"))?; - } - if parts.len() > MAX_DISPLAY_NESTED_LEVEL { - Err(anyhow!( - "Display template value nested depth cannot exist {}", - MAX_DISPLAY_NESTED_LEVEL - ))?; - } - let mut current_value = &SuiMoveValue::Struct(move_struct.clone()); - // iterate over the parts and try to access the corresponding field - for part in parts { - match current_value { - SuiMoveValue::Struct(move_struct) => { - if let SuiMoveStruct::WithTypes { type_: _, fields } - | SuiMoveStruct::WithFields(fields) = move_struct - { - if let Some(value) = fields.get(part) { - current_value = value; - } else { - Err(anyhow!( - "Field value {} cannot be found in struct", - var_name - ))?; - } - } else { - Err(Error::UnexpectedError(format!( - "Unexpected move struct type for field {}", - var_name - )))?; - } - } - _ => { - return Err(Error::UnexpectedError(format!( - "Unexpected move value type for field {}", - var_name - )))?; - } - } - } - - match current_value { - SuiMoveValue::Option(move_option) => match move_option.as_ref() { - Some(move_value) => Ok(move_value.to_string()), - None => Ok("".to_string()), - }, - SuiMoveValue::Vector(_) => Err(anyhow!( - "Vector is not supported as a Display value {}", - var_name - ))?, - - _ => Ok(current_value.to_string()), - } -} - -fn convert_to_response( - cache: IntermediateTransactionResponse, - opts: &SuiTransactionBlockResponseOptions, - module_cache: &impl GetModule, -) -> RpcInterimResult { - let mut response = SuiTransactionBlockResponse::new(cache.digest); - response.errors = cache.errors; - - if opts.show_raw_input && cache.transaction.is_some() { - let sender_signed_data = cache.transaction.as_ref().unwrap().data(); - let raw_tx = bcs::to_bytes(sender_signed_data) - .map_err(|e| anyhow!("Failed to serialize raw transaction with error: {}", e))?; // TODO: is this a client or server error? - response.raw_transaction = raw_tx; - } - - if opts.show_input && cache.transaction.is_some() { - let tx_block = - SuiTransactionBlock::try_from(cache.transaction.unwrap().into_data(), module_cache)?; - response.transaction = Some(tx_block); - } - - if opts.show_effects && cache.effects.is_some() { - let effects = cache.effects.unwrap().try_into().map_err(|e| { - anyhow!( - // TODO: is this a client or server error? - "Failed to convert transaction block effects with error: {}", - e - ) - })?; - response.effects = Some(effects); - } - - response.checkpoint = cache.checkpoint_seq; - response.timestamp_ms = cache.timestamp; - - if opts.show_events { - response.events = cache.events; - } - - if opts.show_balance_changes { - response.balance_changes = cache.balance_changes; - } - - if opts.show_object_changes { - response.object_changes = cache.object_changes; - } - Ok(response) -} - -fn calculate_checkpoint_numbers( - // If `Some`, the query will start from the next item after the specified cursor - cursor: Option, - limit: u64, - descending_order: bool, - max_checkpoint: CheckpointSequenceNumber, -) -> Vec { - let (start_index, end_index) = match cursor { - Some(t) => { - if descending_order { - let start = std::cmp::min(t.saturating_sub(1), max_checkpoint); - let end = start.saturating_sub(limit - 1); - (end, start) - } else { - let start = - std::cmp::min(t.checked_add(1).unwrap_or(max_checkpoint), max_checkpoint); - let end = std::cmp::min( - start.checked_add(limit - 1).unwrap_or(max_checkpoint), - max_checkpoint, - ); - (start, end) - } - } - None => { - if descending_order { - (max_checkpoint.saturating_sub(limit - 1), max_checkpoint) - } else { - (0, std::cmp::min(limit - 1, max_checkpoint)) - } - } - }; - - if descending_order { - (start_index..=end_index).rev().collect() - } else { - (start_index..=end_index).collect() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_calculate_checkpoint_numbers() { - let cursor = Some(10); - let limit = 5; - let descending_order = true; - let max_checkpoint = 15; - - let checkpoint_numbers = - calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); - - assert_eq!(checkpoint_numbers, vec![9, 8, 7, 6, 5]); - } - - #[test] - fn test_calculate_checkpoint_numbers_descending_no_cursor() { - let cursor = None; - let limit = 5; - let descending_order = true; - let max_checkpoint = 15; - - let checkpoint_numbers = - calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); - - assert_eq!(checkpoint_numbers, vec![15, 14, 13, 12, 11]); - } - - #[test] - fn test_calculate_checkpoint_numbers_ascending_no_cursor() { - let cursor = None; - let limit = 5; - let descending_order = false; - let max_checkpoint = 15; - - let checkpoint_numbers = - calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); - - assert_eq!(checkpoint_numbers, vec![0, 1, 2, 3, 4]); - } - - #[test] - fn test_calculate_checkpoint_numbers_ascending_with_cursor() { - let cursor = Some(10); - let limit = 5; - let descending_order = false; - let max_checkpoint = 15; - - let checkpoint_numbers = - calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); - - assert_eq!(checkpoint_numbers, vec![11, 12, 13, 14, 15]); - } - - #[test] - fn test_calculate_checkpoint_numbers_ascending_limit_exceeds_max() { - let cursor = None; - let limit = 20; - let descending_order = false; - let max_checkpoint = 15; - - let checkpoint_numbers = - calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); - - assert_eq!(checkpoint_numbers, (0..=15).collect::>()); - } - - #[test] - fn test_calculate_checkpoint_numbers_descending_limit_exceeds_max() { - let cursor = None; - let limit = 20; - let descending_order = true; - let max_checkpoint = 15; - - let checkpoint_numbers = - calculate_checkpoint_numbers(cursor, limit, descending_order, max_checkpoint); - - assert_eq!(checkpoint_numbers, (0..=15).rev().collect::>()); - } -} diff --git a/crates/sui-json-rpc/src/transaction_builder_api.rs b/crates/sui-json-rpc/src/transaction_builder_api.rs deleted file mode 100644 index 654672fcd56..00000000000 --- a/crates/sui-json-rpc/src/transaction_builder_api.rs +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::sync::Arc; - -use async_trait::async_trait; -use fastcrypto::encoding::Base64; -use jsonrpsee::{core::RpcResult, RpcModule}; -use move_core_types::language_storage::StructTag; -use sui_core::authority::AuthorityState; -use sui_json::SuiJsonValue; -use sui_json_rpc_api::{TransactionBuilderOpenRpc, TransactionBuilderServer}; -use sui_json_rpc_types::{ - RPCTransactionRequestParams, SuiObjectDataFilter, SuiObjectDataOptions, SuiObjectResponse, - SuiTransactionBlockBuilderMode, SuiTypeTag, TransactionBlockBytes, -}; -use sui_open_rpc::Module; -use sui_transaction_builder::{DataReader, TransactionBuilder}; -use sui_types::{ - base_types::{ObjectID, ObjectInfo, SuiAddress}, - sui_serde::BigInt, -}; - -use crate::{authority_state::StateRead, SuiRpcModule}; - -pub struct TransactionBuilderApi(TransactionBuilder); - -impl TransactionBuilderApi { - pub fn new(state: Arc) -> Self { - let reader = Arc::new(AuthorityStateDataReader::new(state)); - Self(TransactionBuilder::new(reader)) - } - - pub fn new_with_data_reader(data_reader: Arc) -> Self { - Self(TransactionBuilder::new(data_reader)) - } -} - -pub struct AuthorityStateDataReader(Arc); - -impl AuthorityStateDataReader { - pub fn new(state: Arc) -> Self { - Self(state) - } -} - -#[async_trait] -impl DataReader for AuthorityStateDataReader { - async fn get_owned_objects( - &self, - address: SuiAddress, - object_type: StructTag, - ) -> Result, anyhow::Error> { - Ok(self - .0 - // DataReader is used internally, don't need a limit - .get_owner_objects( - address, - None, - Some(SuiObjectDataFilter::StructType(object_type)), - )?) - } - - async fn get_object_with_options( - &self, - object_id: ObjectID, - options: SuiObjectDataOptions, - ) -> Result { - let result = self.0.get_object_read(&object_id)?; - Ok((result, options).try_into()?) - } - - async fn get_reference_gas_price(&self) -> Result { - let epoch_store = self.0.load_epoch_store_one_call_per_task(); - Ok(epoch_store.reference_gas_price()) - } -} - -#[async_trait] -impl TransactionBuilderServer for TransactionBuilderApi { - async fn transfer_object( - &self, - signer: SuiAddress, - object_id: ObjectID, - gas: Option, - gas_budget: BigInt, - recipient: SuiAddress, - ) -> RpcResult { - let data = self - .0 - .transfer_object(signer, object_id, gas, *gas_budget, recipient) - .await?; - Ok(TransactionBlockBytes::from_data(data)?) - } - - async fn transfer_sui( - &self, - signer: SuiAddress, - sui_object_id: ObjectID, - gas_budget: BigInt, - recipient: SuiAddress, - amount: Option>, - ) -> RpcResult { - let data = self - .0 - .transfer_sui( - signer, - sui_object_id, - *gas_budget, - recipient, - amount.map(|a| *a), - ) - .await?; - Ok(TransactionBlockBytes::from_data(data)?) - } - - async fn pay( - &self, - signer: SuiAddress, - input_coins: Vec, - recipients: Vec, - amounts: Vec>, - gas: Option, - gas_budget: BigInt, - ) -> RpcResult { - let data = self - .0 - .pay( - signer, - input_coins, - recipients, - amounts.into_iter().map(|a| *a).collect(), - gas, - *gas_budget, - ) - .await?; - Ok(TransactionBlockBytes::from_data(data)?) - } - - async fn pay_sui( - &self, - signer: SuiAddress, - input_coins: Vec, - recipients: Vec, - amounts: Vec>, - gas_budget: BigInt, - ) -> RpcResult { - let data = self - .0 - .pay_sui( - signer, - input_coins, - recipients, - amounts.into_iter().map(|a| *a).collect(), - *gas_budget, - ) - .await?; - Ok(TransactionBlockBytes::from_data(data)?) - } - - async fn pay_all_sui( - &self, - signer: SuiAddress, - input_coins: Vec, - recipient: SuiAddress, - gas_budget: BigInt, - ) -> RpcResult { - let data = self - .0 - .pay_all_sui(signer, input_coins, recipient, *gas_budget) - .await?; - Ok(TransactionBlockBytes::from_data(data)?) - } - - async fn publish( - &self, - sender: SuiAddress, - compiled_modules: Vec, - dependencies: Vec, - gas: Option, - gas_budget: BigInt, - ) -> RpcResult { - let compiled_modules = compiled_modules - .into_iter() - .map(|data| data.to_vec().map_err(|e| anyhow::anyhow!(e))) - .collect::, _>>()?; - let data = self - .0 - .publish(sender, compiled_modules, dependencies, gas, *gas_budget) - .await?; - Ok(TransactionBlockBytes::from_data(data)?) - } - - async fn split_coin( - &self, - signer: SuiAddress, - coin_object_id: ObjectID, - split_amounts: Vec>, - gas: Option, - gas_budget: BigInt, - ) -> RpcResult { - let split_amounts = split_amounts.into_iter().map(|a| *a).collect(); - let data = self - .0 - .split_coin(signer, coin_object_id, split_amounts, gas, *gas_budget) - .await?; - Ok(TransactionBlockBytes::from_data(data)?) - } - - async fn split_coin_equal( - &self, - signer: SuiAddress, - coin_object_id: ObjectID, - split_count: BigInt, - gas: Option, - gas_budget: BigInt, - ) -> RpcResult { - let data = self - .0 - .split_coin_equal(signer, coin_object_id, *split_count, gas, *gas_budget) - .await?; - Ok(TransactionBlockBytes::from_data(data)?) - } - - async fn merge_coin( - &self, - signer: SuiAddress, - primary_coin: ObjectID, - coin_to_merge: ObjectID, - gas: Option, - gas_budget: BigInt, - ) -> RpcResult { - let data = self - .0 - .merge_coins(signer, primary_coin, coin_to_merge, gas, *gas_budget) - .await?; - Ok(TransactionBlockBytes::from_data(data)?) - } - - async fn move_call( - &self, - signer: SuiAddress, - package_object_id: ObjectID, - module: String, - function: String, - type_arguments: Vec, - rpc_arguments: Vec, - gas: Option, - gas_budget: BigInt, - _txn_builder_mode: Option, - ) -> RpcResult { - Ok(TransactionBlockBytes::from_data( - self.0 - .move_call( - signer, - package_object_id, - &module, - &function, - type_arguments, - rpc_arguments, - gas, - *gas_budget, - None, - ) - .await?, - )?) - } - - async fn batch_transaction( - &self, - signer: SuiAddress, - params: Vec, - gas: Option, - gas_budget: BigInt, - _txn_builder_mode: Option, - ) -> RpcResult { - Ok(TransactionBlockBytes::from_data( - self.0 - .batch_transaction(signer, params, gas, *gas_budget) - .await?, - )?) - } - - async fn request_add_stake( - &self, - signer: SuiAddress, - coins: Vec, - amount: Option>, - validator: SuiAddress, - gas: Option, - gas_budget: BigInt, - ) -> RpcResult { - let amount = amount.map(|a| *a); - Ok(TransactionBlockBytes::from_data( - self.0 - .request_add_stake(signer, coins, amount, validator, gas, *gas_budget) - .await?, - )?) - } - - async fn request_withdraw_stake( - &self, - signer: SuiAddress, - staked_sui: ObjectID, - gas: Option, - gas_budget: BigInt, - ) -> RpcResult { - Ok(TransactionBlockBytes::from_data( - self.0 - .request_withdraw_stake(signer, staked_sui, gas, *gas_budget) - .await?, - )?) - } - - async fn request_add_timelocked_stake( - &self, - signer: SuiAddress, - locked_balance: ObjectID, - validator: SuiAddress, - gas: ObjectID, - gas_budget: BigInt, - ) -> RpcResult { - Ok(TransactionBlockBytes::from_data( - self.0 - .request_add_timelocked_stake(signer, locked_balance, validator, gas, *gas_budget) - .await?, - )?) - } - - async fn request_withdraw_timelocked_stake( - &self, - signer: SuiAddress, - timelocked_staked_sui: ObjectID, - gas: ObjectID, - gas_budget: BigInt, - ) -> RpcResult { - Ok(TransactionBlockBytes::from_data( - self.0 - .request_withdraw_timelocked_stake(signer, timelocked_staked_sui, gas, *gas_budget) - .await?, - )?) - } -} - -impl SuiRpcModule for TransactionBuilderApi { - fn rpc(self) -> RpcModule { - self.into_rpc() - } - - fn rpc_doc_module() -> Module { - TransactionBuilderOpenRpc::module_doc() - } -} diff --git a/crates/sui-json-rpc/src/unit_tests/data/validator_exchange_rate/rates.json b/crates/sui-json-rpc/src/unit_tests/data/validator_exchange_rate/rates.json deleted file mode 100644 index 43f8a2e4076..00000000000 --- a/crates/sui-json-rpc/src/unit_tests/data/validator_exchange_rate/rates.json +++ /dev/null @@ -1 +0,0 @@ -{"01node":[[167,{"sui_amount":35899352829617961,"pool_token_amount":35167964851472947}],[166,{"sui_amount":35894635008379974,"pool_token_amount":35167589707247808}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":35866428578351272,"pool_token_amount":35165428023127803}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":35856795079957317,"pool_token_amount":35164663337242363}],[156,{"sui_amount":35847171423859400,"pool_token_amount":35163907355994735}],[155,{"sui_amount":35842259838498301,"pool_token_amount":35163521931965938}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":35832323095869636,"pool_token_amount":35162550065203222}],[149,{"sui_amount":35813022905267424,"pool_token_amount":35160987430070301}],[148,{"sui_amount":35807463745655398,"pool_token_amount":35159876066304843}],[146,{"sui_amount":35797885586783620,"pool_token_amount":35159170792411269}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":35781672931381071,"pool_token_amount":35161017940266929}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":35776757993525179,"pool_token_amount":35160631564962536}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[130,{"sui_amount":35722772619255235,"pool_token_amount":35156402658387802}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":35711191416942195,"pool_token_amount":35149371306178667}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":35697871063613660,"pool_token_amount":35149442536686591}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":35681930276104481,"pool_token_amount":35146834152140152}],[121,{"sui_amount":35673342931448668,"pool_token_amount":35147104822309087}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":35654083137501737,"pool_token_amount":35145765162012789}],[116,{"sui_amount":35649170657616036,"pool_token_amount":35145378684309259}],[115,{"sui_amount":35644452365695873,"pool_token_amount":35145183937266114}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":35634728237482068,"pool_token_amount":35144510894842630}],[112,{"sui_amount":35628748498077351,"pool_token_amount":35143072321402701}],[109,{"sui_amount":35611905496842073,"pool_token_amount":35140337533651238}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":35589966297680344,"pool_token_amount":35138670365169253}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":35584282756016771,"pool_token_amount":35138225106374292}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":35526717640965292,"pool_token_amount":35131806722393544}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":35521303474503238,"pool_token_amount":35131383868716957}],[91,{"sui_amount":35510474574512078,"pool_token_amount":35130527004684915}],[89,{"sui_amount":35499596115808720,"pool_token_amount":35129581321508401}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":35467230513826377,"pool_token_amount":35126964014889569}],[81,{"sui_amount":35456345039098400,"pool_token_amount":35125918326891889}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":35450769381797069,"pool_token_amount":35125365328264671}],[78,{"sui_amount":35439234897586982,"pool_token_amount":35123670599410786}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":35389945306716957,"pool_token_amount":35119514866241807}],[68,{"sui_amount":35384479435091140,"pool_token_amount":35119163753307465}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[61,{"sui_amount":35346141703824881,"pool_token_amount":35115817084513559}],[60,{"sui_amount":35340805935962004,"pool_token_amount":35115393004614797}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":35278566657180210,"pool_token_amount":35102418052806218}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":35267358941663083,"pool_token_amount":35101033364695387}],[47,{"sui_amount":35262027719785051,"pool_token_amount":35100611713369984}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":35219950114669908,"pool_token_amount":35103411341100541}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":35208904991784491,"pool_token_amount":35102522980624148}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[31,{"sui_amount":35179804004997458,"pool_token_amount":35100742441498602}],[29,{"sui_amount":35467223071507847,"pool_token_amount":35399577747655396}],[26,{"sui_amount":35145181142328545,"pool_token_amount":35097583828526451}],[24,{"sui_amount":35061152124115585,"pool_token_amount":35028470602959208}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":25000000031979264,"pool_token_amount":25000000000639572}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":25000000000000000,"pool_token_amount":25000000000000000}]],"A41":[[167,{"sui_amount":27565797795973335,"pool_token_amount":27028771266450611}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":27570988699825350,"pool_token_amount":27037046929509186}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":27553351035026007,"pool_token_amount":27035670831590609}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"sui_amount":27512312303009122,"pool_token_amount":27031341388344369}],[148,{"sui_amount":27501705047152318,"pool_token_amount":27027479686385565}],[147,{"sui_amount":27497992476580722,"pool_token_amount":27027113946092485}],[146,{"sui_amount":27494285700456241,"pool_token_amount":27026754050027824}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":27487061166244646,"pool_token_amount":27026046529488669}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":27476330254021937,"pool_token_amount":27025080727677398}],[140,{"sui_amount":27472718971359752,"pool_token_amount":27024725529813471}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":27472043566383301,"pool_token_amount":27033661873253587}],[136,{"sui_amount":27468428307748456,"pool_token_amount":27033306115789485}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":27457595374938662,"pool_token_amount":27032245149447796}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":27440490411762611,"pool_token_amount":27031421635223684}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":27436893047193011,"pool_token_amount":27031081831422650}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":27411617845010411,"pool_token_amount":27028598005480033}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":27397175339106152,"pool_token_amount":27027172793016629}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":27393565173970705,"pool_token_amount":27026816651699294}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":27386344762381823,"pool_token_amount":27026104234305114}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":27375500086580902,"pool_token_amount":27025023279725843}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":27384350632639936,"pool_token_amount":27040895219174179}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":27367622471924243,"pool_token_amount":27039243030388432}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[100,{"sui_amount":27350656048228135,"pool_token_amount":27037570842598090}],[98,{"sui_amount":27342410413461125,"pool_token_amount":27036757447809085}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":27313459808425425,"pool_token_amount":27033907906923433}],[90,{"sui_amount":27310957366889275,"pool_token_amount":27035035218211974}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":27306914055767692,"pool_token_amount":27034634971561982}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":27294799187434493,"pool_token_amount":27033435403657578}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":27289494690351082,"pool_token_amount":27031763094695012}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":27271820395297662,"pool_token_amount":27028542724790202}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":27259445090001113,"pool_token_amount":27027193872465250}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":27247432991980248,"pool_token_amount":27025996492303658}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":27247945102257861,"pool_token_amount":27030077055639129}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":27216337605333506,"pool_token_amount":27025314036515480}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":27212003616707252,"pool_token_amount":27024883679550149}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":27191969876884773,"pool_token_amount":27019588521613874}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":27166125409771648,"pool_token_amount":27004638726859948}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":27120210053332182,"pool_token_amount":26995383251432965}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":27107627867288215,"pool_token_amount":27004962454692101}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":27098562165947582,"pool_token_amount":27003305482367730}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":27086218526696561,"pool_token_amount":27002071083781656}],[37,{"sui_amount":27081998987719701,"pool_token_amount":27001659418114157}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":27057970258189577,"pool_token_amount":26997774075236993}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":27044174160138780,"pool_token_amount":26996389240972581}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"sui_amount":20023367414445940,"pool_token_amount":20001786010006704}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":20009758488195300,"pool_token_amount":20000598798782603}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":20004677735991001,"pool_token_amount":20000103331086132}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":20000000015774701,"pool_token_amount":20000000000315481}],[17,{"sui_amount":20000000012328401,"pool_token_amount":20000000000246557}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"ANodes":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":35776912762248031,"pool_token_amount":35076572465911553}],[161,{"sui_amount":35776516365178193,"pool_token_amount":35080336624703625}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":35771787934955269,"pool_token_amount":35079857980153053}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":35766975860986207,"pool_token_amount":35079386080312534}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":35737864137765631,"pool_token_amount":35080564537901476}],[151,{"sui_amount":35727132243792307,"pool_token_amount":35074281080335284}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":35682512508539158,"pool_token_amount":35068759206392545}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":35672882832158783,"pool_token_amount":35067812743747567}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":35629717333082480,"pool_token_amount":35063947453361888}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":35609588069220101,"pool_token_amount":35061413191115062}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":35590331420668866,"pool_token_amount":35059903042806352}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":35580707919696605,"pool_token_amount":35059152832281300}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":35532548771963267,"pool_token_amount":35055335389180914}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":35511677699193499,"pool_token_amount":35053687792337210}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[103,{"sui_amount":35489461473129249,"pool_token_amount":35051952326213164}],[101,{"sui_amount":35478408487180345,"pool_token_amount":35051099340719939}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":35451002516035482,"pool_token_amount":35048932644271300}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":35434715454817781,"pool_token_amount":35047644272561064}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":35429295678033087,"pool_token_amount":35047216336294694}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":35407910958684515,"pool_token_amount":35045496355655081}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":35375745831871334,"pool_token_amount":35042935854596487}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":35327813171723261,"pool_token_amount":35039435486502309}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":35272403621844127,"pool_token_amount":35034778847672262}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":35240406948357111,"pool_token_amount":35032245960105482}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":35229761892216064,"pool_token_amount":35031422287895324}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":35217965961883103,"pool_token_amount":35029455587337167}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":35212630512489798,"pool_token_amount":35029031036092834}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":35187307993908212,"pool_token_amount":35013602723013988}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":35180933395388450,"pool_token_amount":35012143195957992}],[48,{"sui_amount":35175599279093302,"pool_token_amount":35011719430622372}],[47,{"sui_amount":35170264961734642,"pool_token_amount":35011294673397494}],[46,{"sui_amount":35164626028659785,"pool_token_amount":35010566836151741}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"sui_amount":35137822123488198,"pool_token_amount":35008413361728057}],[39,{"sui_amount":35126683731718677,"pool_token_amount":35007299999113715}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":35110084291329007,"pool_token_amount":35005973619213076}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":35085984357790107,"pool_token_amount":35003468850605816}],[31,{"sui_amount":35080051684969255,"pool_token_amount":35002957729714668}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"sui_amount":25042622108777768,"pool_token_amount":25013929985989569}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":25029558797371582,"pool_token_amount":25012207725171793}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":25005943238434252,"pool_token_amount":25000170765339556}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":25000000032208364,"pool_token_amount":25000000000644154}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":25000000019248364,"pool_token_amount":25000000000384956}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":25000000000572400,"pool_token_amount":25000000000011444}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":25000000000000000,"pool_token_amount":25000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Aftermath":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":107326933123545581,"pool_token_amount":105113560956765493}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":107298584497769675,"pool_token_amount":105112451268316333}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":107284450207927809,"pool_token_amount":105111897415382603}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":107255177735401777,"pool_token_amount":105110749211025972}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":107211274260816842,"pool_token_amount":105109027957048783}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"sui_amount":107137043341814663,"pool_token_amount":105105128030477816}],[146,{"sui_amount":107083902945467558,"pool_token_amount":105107869576035515}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":106995939981008817,"pool_token_amount":105103208346478044}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":106981492479992000,"pool_token_amount":105102640668813979}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":106956675962719528,"pool_token_amount":105091895452746007}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":106898755428504594,"pool_token_amount":105089533686362393}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":106855108351198517,"pool_token_amount":105087552026933733}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":106826096685286558,"pool_token_amount":105086328988979437}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":106782736392211683,"pool_token_amount":105084632465584310}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":106768289350353497,"pool_token_amount":105084063773177035}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":106739392924263508,"pool_token_amount":105082926074476266}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":106724942505968547,"pool_token_amount":105082357027388350}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":106667208493604265,"pool_token_amount":105080122453542964}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":106549359730511791,"pool_token_amount":105073286476162634}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":106467649957621572,"pool_token_amount":105069988504145854}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":106453452842122193,"pool_token_amount":105071813402100574}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[99,{"sui_amount":106370409881896138,"pool_token_amount":105068606927363071}],[98,{"sui_amount":106353921370554989,"pool_token_amount":105067956412602915}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":106321131377478568,"pool_token_amount":105066690195265350}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":106222556546129616,"pool_token_amount":105061803015942703}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":106190450231860081,"pool_token_amount":105060533660928540}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":106174297918768752,"pool_token_amount":105059895399080670}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":106042455978565748,"pool_token_amount":104959922101866367}],[84,{"sui_amount":106026130172312016,"pool_token_amount":104958886154088921}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":105994186183246095,"pool_token_amount":104957620214339329}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":105960376666159956,"pool_token_amount":104955034668039030}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":105928274047503014,"pool_token_amount":104953487247633894}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":105896478538823031,"pool_token_amount":104952225140410116}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":105830431648445243,"pool_token_amount":104948628147371969}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":105746277043784963,"pool_token_amount":104945384758770885}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":105729385600945089,"pool_token_amount":104944714218293348}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":105662329319958462,"pool_token_amount":104939681624455969}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":105630763503057974,"pool_token_amount":104938640517845953}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":105564060346189754,"pool_token_amount":104933319889933989}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":105468611464212946,"pool_token_amount":104930608931863046}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":105452777469885941,"pool_token_amount":104930247201362920}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"sui_amount":105327781921035290,"pool_token_amount":104929342106086780}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":105116022491668488,"pool_token_amount":104917061673361592}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":25405902238434252,"pool_token_amount":25400037437186026}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":25000000000691200,"pool_token_amount":25000000000013816}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Ahoy Validator":[[167,{"sui_amount":137536556634519065,"pool_token_amount":134660856618901182}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":137502729281141466,"pool_token_amount":134661693349568612}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":137467077483403773,"pool_token_amount":134660744242601154}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":137432509022301453,"pool_token_amount":134660739742482524}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":137361751793581491,"pool_token_amount":134660682803590203}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":137326119985718382,"pool_token_amount":134660683174765992}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"sui_amount":137236781078120340,"pool_token_amount":134660441933397429}],[149,{"sui_amount":137218955399086884,"pool_token_amount":134660436071910779}],[148,{"sui_amount":137202333399116466,"pool_token_amount":134661517940145946}],[147,{"sui_amount":137183208512157532,"pool_token_amount":134660059933081454}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":137112338487996913,"pool_token_amount":134659775814189883}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":137041806001363114,"pool_token_amount":134659703377109446}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":136989109021061677,"pool_token_amount":134659700344161840}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":136936772699347172,"pool_token_amount":134660203276785633}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":137339542445201749,"pool_token_amount":135160564582719192}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":137269828867400668,"pool_token_amount":135161410832508839}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":137216915522700760,"pool_token_amount":135161421725769360}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":137181613851657855,"pool_token_amount":135161394370760660}],[117,{"sui_amount":137163981416581946,"pool_token_amount":135161395438475736}],[116,{"sui_amount":137146409437449345,"pool_token_amount":135161455363992860}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":137128681207677113,"pool_token_amount":135161456455717408}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":137093212473277407,"pool_token_amount":135161446932863334}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":137057827122667632,"pool_token_amount":135161428019237217}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":136940145602921211,"pool_token_amount":135161337570391070}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":136919784388067637,"pool_token_amount":135161386416538189}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"sui_amount":136858808042889288,"pool_token_amount":135161663539327888}],[97,{"sui_amount":136767365299724206,"pool_token_amount":135150907430503097}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":136747577891802889,"pool_token_amount":135151179946329724}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":136569360774064533,"pool_token_amount":135150949506361963}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":136530160188369629,"pool_token_amount":135150985487653693}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":136471190344212381,"pool_token_amount":135150627503657867}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":136095498533212531,"pool_token_amount":135175309888560686}],[61,{"sui_amount":136076245216832988,"pool_token_amount":135175493000305786}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":136056687938046260,"pool_token_amount":135175482910819079}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":136037299596173487,"pool_token_amount":135175634795734766}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":135850655977030339,"pool_token_amount":135146048253782527}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":135734934931634380,"pool_token_amount":135148626536702810}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":135695392675213274,"pool_token_amount":135148591036333149}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":135675429301120486,"pool_token_amount":135148489202469978}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":135574776878503731,"pool_token_amount":135148133631043139}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":135554263461423538,"pool_token_amount":135148209689437509}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":100526499684542534,"pool_token_amount":100257379408674274}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":100493790983202954,"pool_token_amount":100257245858401769}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":100441120563435796,"pool_token_amount":100253725710004158}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":100423388647635235,"pool_token_amount":100252845829209127}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Allnodes":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":41945226777940910,"pool_token_amount":41058717489928776}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":41933387589231820,"pool_token_amount":41057569157037985}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":41947929794460088,"pool_token_amount":41103354368762468}],[156,{"sui_amount":41942655910180052,"pool_token_amount":41103505187266885}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":41931349675742423,"pool_token_amount":41103064220258078}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"sui_amount":41841638502044587,"pool_token_amount":41046928310421344}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"sui_amount":41843932876285206,"pool_token_amount":41060013976513164}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":41820083443540515,"pool_token_amount":41063268316838961}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":41803813342841935,"pool_token_amount":41057960828336695}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":41775654335610327,"pool_token_amount":41051663915234929}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":41759599461538987,"pool_token_amount":41046567901553573}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":41752200377003645,"pool_token_amount":41044638238708895}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":41742650650682184,"pool_token_amount":41040594749351098}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":41730211471976507,"pool_token_amount":41039058842248097}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":41711760929287013,"pool_token_amount":41026263701797818}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":41703161107376949,"pool_token_amount":41023151631856085}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":41688021114557743,"pool_token_amount":41019024609001103}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":41681957461154797,"pool_token_amount":41018310615762379}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[120,{"sui_amount":41660448525927971,"pool_token_amount":41018248453409150}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":41655075270979316,"pool_token_amount":41018305805930474}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":41650175466005178,"pool_token_amount":41019099119304947}],[117,{"sui_amount":41643536165007314,"pool_token_amount":41017908299252250}],[116,{"sui_amount":41631429336570009,"pool_token_amount":41011331978740780}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":41609283289939211,"pool_token_amount":41005563539552877}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":41553427689994447,"pool_token_amount":40961490972781829}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":41570436019285049,"pool_token_amount":41001388585514539}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":48065107380532829,"pool_token_amount":47500461133153483}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":47925269003691818,"pool_token_amount":47487418020412692}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":47899205590229658,"pool_token_amount":47482854304459720}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":47860299510468105,"pool_token_amount":47489321867141342}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":47851383639288819,"pool_token_amount":47487931328251677}],[65,{"sui_amount":48491364885554483,"pool_token_amount":48130720199721504}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":48389961305918353,"pool_token_amount":48087113334345430}],[56,{"sui_amount":48382835338071581,"pool_token_amount":48087176153055754}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":46363439714269269,"pool_token_amount":46087049435813747}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":45637528012794795,"pool_token_amount":45405762861244766}],[47,{"sui_amount":45614917394395907,"pool_token_amount":45396920176703552}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":45508456906330550,"pool_token_amount":45345917078726522}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":45500322617991066,"pool_token_amount":45344760959613013}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":35580301554891828,"pool_token_amount":35481265429849100}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":35485129761915502,"pool_token_amount":35416306743889336}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":35474352629132506,"pool_token_amount":35411657684784245}],[25,{"sui_amount":25435749166272888,"pool_token_amount":25405778066530643}],[24,{"sui_amount":25205554474744994,"pool_token_amount":25181297927578319}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":25135090838487568,"pool_token_amount":25123107106458969}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":25650000019248364,"pool_token_amount":25649999999894508}],[16,{"sui_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Anchorage Digital-1":[[167,{"sui_amount":30616090018098256,"pool_token_amount":30065177769519725}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[159,{"sui_amount":30579497301791575,"pool_token_amount":30058940988783163}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":30575387543367356,"pool_token_amount":30058698600526780}],[157,{"sui_amount":30571277687624579,"pool_token_amount":30058456175899796}],[156,{"sui_amount":30567168191159251,"pool_token_amount":30058213741830163}],[155,{"sui_amount":30563058484490832,"pool_token_amount":30057971264690708}],[152,{"sui_amount":30550524568810380,"pool_token_amount":30057043702629882}],[151,{"sui_amount":30546414409305347,"pool_token_amount":30056801076089132}],[150,{"sui_amount":30542304421178100,"pool_token_amount":30056558428987848}],[149,{"sui_amount":30538193986235439,"pool_token_amount":30056315724793393}],[148,{"sui_amount":30534043599829442,"pool_token_amount":30056033623938680}],[145,{"sui_amount":30522427466064763,"pool_token_amount":30056018829848775}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":30510138198094224,"pool_token_amount":30055339234123614}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":30498051539468497,"pool_token_amount":30054672527726691}],[138,{"sui_amount":30494081119572262,"pool_token_amount":30054479972351211}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":30467816621944545,"pool_token_amount":30054916236948756}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":30459791890809073,"pool_token_amount":30054450552641164}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":30429898714491600,"pool_token_amount":30073540174854425}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":30432233185012054,"pool_token_amount":30091135159620143}],[111,{"sui_amount":30418236693775841,"pool_token_amount":30081117418103842}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":30414199254081588,"pool_token_amount":30080948525172185}],[109,{"sui_amount":30404846013543378,"pool_token_amount":30075948421509901}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":30365906038700441,"pool_token_amount":30054724899180680}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":30360151498615884,"pool_token_amount":30053456938944156}],[101,{"sui_amount":30315905353895954,"pool_token_amount":30022896535349530}],[100,{"sui_amount":30312201857552185,"pool_token_amount":30023607529927007}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":30286068107266744,"pool_token_amount":30023466990907308}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[88,{"sui_amount":121426725771408009,"pool_token_amount":120512524303800711}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":121390640030155877,"pool_token_amount":120511029711187150}],[85,{"sui_amount":151371443802214618,"pool_token_amount":150301217857128704}],[84,{"sui_amount":151348137636636847,"pool_token_amount":150299372217082560}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":151325321704224328,"pool_token_amount":150298012747241011}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":418194398973115559,"pool_token_amount":415872299316475160}],[73,{"sui_amount":205920313530691210,"pool_token_amount":204864557337488098}],[72,{"sui_amount":30162036770237338,"pool_token_amount":30011760879402318}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[67,{"sui_amount":30136511170752886,"pool_token_amount":30008506235489081}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":30131732371316310,"pool_token_amount":30008220445532962}],[64,{"sui_amount":30122508354655963,"pool_token_amount":30007669233509732}],[61,{"sui_amount":30109178317181310,"pool_token_amount":30006878499594518}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":30100285732944022,"pool_token_amount":30006345783501753}],[58,{"sui_amount":30095840204331590,"pool_token_amount":30006079884222607}],[57,{"sui_amount":30091388777545584,"pool_token_amount":30005807972010196}],[56,{"sui_amount":30086843217197839,"pool_token_amount":30005442682900979}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":30077845551822847,"pool_token_amount":30004908936336770}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":30064174085885139,"pool_token_amount":30004090520926897}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"sui_amount":30045922560270961,"pool_token_amount":30002973925880759}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":30032264350030784,"pool_token_amount":30002165822405313}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[42,{"sui_amount":30023129868417929,"pool_token_amount":30001598541320198}],[41,{"sui_amount":30018358648801955,"pool_token_amount":30001111457703588}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":0,"pool_token_amount":0}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}]],"Anchorage Digital-2":[[167,{"sui_amount":185541314736551107,"pool_token_amount":182261342386316939}],[163,{"sui_amount":78356771142147363,"pool_token_amount":77010096883805943}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":78346277492229607,"pool_token_amount":77009413416231209}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":78342541720780234,"pool_token_amount":77024813858921809}],[158,{"sui_amount":41967546616598638,"pool_token_amount":41272210603053443}],[155,{"sui_amount":41950406218185594,"pool_token_amount":41271199087837047}],[146,{"sui_amount":41898630259021708,"pool_token_amount":41267640635804831}],[145,{"sui_amount":41892907413273460,"pool_token_amount":41267301509697613}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":41881468580414524,"pool_token_amount":41266625384485949}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":41859605112602178,"pool_token_amount":41266265164526663}],[138,{"sui_amount":41853882344943895,"pool_token_amount":41265926664896805}],[137,{"sui_amount":41848155631564404,"pool_token_amount":41265587888249633}],[136,{"sui_amount":41842431472457252,"pool_token_amount":41265249219228351}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":41830991090267079,"pool_token_amount":41264572220407878}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":41813758319199497,"pool_token_amount":41263489993672364}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":41795845707716580,"pool_token_amount":41272361573909075}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[120,{"sui_amount":41761507387857848,"pool_token_amount":41270302285702617}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[115,{"sui_amount":41733266872581162,"pool_token_amount":41268944567901452}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":41721482554731648,"pool_token_amount":41267918132421561}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":41703537255487844,"pool_token_amount":41266115206096109}],[109,{"sui_amount":41697171384383365,"pool_token_amount":41265727958171889}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[103,{"sui_amount":41658281933521508,"pool_token_amount":41263419243124864}],[102,{"sui_amount":41651691245713593,"pool_token_amount":41263029418995973}],[98,{"sui_amount":41625535101707443,"pool_token_amount":41261475274867463}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":41612660771152366,"pool_token_amount":41260671310041890}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":41593545280008979,"pool_token_amount":41259532983353503}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":41586771040094167,"pool_token_amount":41258710188952494}],[91,{"sui_amount":41577945563629037,"pool_token_amount":41255838453720002}],[89,{"sui_amount":41565318531392365,"pool_token_amount":41255045603527479}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":41546420082302621,"pool_token_amount":41253870454006017}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":41531289801904249,"pool_token_amount":41256627563745822}],[81,{"sui_amount":41518825592682724,"pool_token_amount":41255885549089481}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":41499908893301804,"pool_token_amount":41254754771173522}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":41493977799525556,"pool_token_amount":41260494923035693}],[73,{"sui_amount":41475079127096501,"pool_token_amount":41259363483432692}],[72,{"sui_amount":41468410783593773,"pool_token_amount":41258965463775930}],[70,{"sui_amount":41455070320262079,"pool_token_amount":41258168083080432}],[69,{"sui_amount":41448399102459307,"pool_token_amount":41257769711202696}],[67,{"sui_amount":41435065426488955,"pool_token_amount":41256975183168449}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"sui_amount":41420430450792027,"pool_token_amount":41260815718800467}],[63,{"sui_amount":41413884443569930,"pool_token_amount":41260226896182575}],[61,{"sui_amount":40410405673849937,"pool_token_amount":40271920257251776}],[60,{"sui_amount":40404071773175228,"pool_token_amount":40271335434266736}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":40397959745528798,"pool_token_amount":40270969917366796}],[58,{"sui_amount":40391847143688757,"pool_token_amount":40270604314138582}],[57,{"sui_amount":40385733681859852,"pool_token_amount":40270237670279970}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":40342939305879506,"pool_token_amount":40267673163363283}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"sui_amount":40324600351510926,"pool_token_amount":40266573784649205}],[46,{"sui_amount":40318487041911971,"pool_token_amount":40266206763947877}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[40,{"sui_amount":30014044653921477,"pool_token_amount":30000894139882708}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}]],"Ankr":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":27834875247327235,"pool_token_amount":27253033497682335}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":27836880080343632,"pool_token_amount":27283088913768974}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":27832958184081050,"pool_token_amount":27282807317414573}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":27816143848252139,"pool_token_amount":27280577646300312}],[150,{"sui_amount":27811756686295983,"pool_token_amount":27279839827878546}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"sui_amount":27799258180662917,"pool_token_amount":27281849703855080}],[145,{"sui_amount":27795434999842648,"pool_token_amount":27281669830893990}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":27791720839257627,"pool_token_amount":27281596920054668}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":27740483348993766,"pool_token_amount":27263440975355820}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":27736770135156685,"pool_token_amount":27263367987636859}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":27729406225174524,"pool_token_amount":27263285122071558}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":27719418011874332,"pool_token_amount":27264205410898092}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":27700724346843030,"pool_token_amount":27252981680306358}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":27673603141580631,"pool_token_amount":27251352891366267}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":27673880253609058,"pool_token_amount":27262373805472577}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":27658899253699824,"pool_token_amount":27276688633407965}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[102,{"sui_amount":27628348366327421,"pool_token_amount":27275234895506011}],[101,{"sui_amount":27561481532339594,"pool_token_amount":27213342024764992}],[98,{"sui_amount":27548166774698423,"pool_token_amount":27212504720258817}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":27540654495424777,"pool_token_amount":27213220066274005}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":27535971916342781,"pool_token_amount":27212648238627647}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":27527806401533686,"pool_token_amount":27212681985299208}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":27523740821498482,"pool_token_amount":27212601606771544}],[91,{"sui_amount":27494274850780766,"pool_token_amount":27187402284281455}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":27478000667596089,"pool_token_amount":27187085242867303}],[86,{"sui_amount":27473864718774010,"pool_token_amount":27187016297141523}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":27442067093077398,"pool_token_amount":27183522882229672}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":27431395630117394,"pool_token_amount":27176945478949593}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":27410772345158717,"pool_token_amount":27180477410158867}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":29459085552519888,"pool_token_amount":29234601351455807}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":29453846212297206,"pool_token_amount":29233941276367279}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":29415472997908016,"pool_token_amount":29208822588061827}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":29370446211134410,"pool_token_amount":29193636362692127}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":29364840222584189,"pool_token_amount":29192286547298983}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":29362188212849614,"pool_token_amount":29193981633786170}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":29352692988567436,"pool_token_amount":29193205827572392}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"sui_amount":29322845693552819,"pool_token_amount":29189518601526347}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"sui_amount":34229972150543251,"pool_token_amount":34105627318578118}],[39,{"sui_amount":34224816344374222,"pool_token_amount":34105591065961725}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":27214493453369373,"pool_token_amount":27132023725291198}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":27205536146597418,"pool_token_amount":27131890245260586}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":27064716682726903,"pool_token_amount":27023244716152260}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":20018666175233170,"pool_token_amount":20004810987516623}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":20006918736012401,"pool_token_amount":20002343818644342}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":20000000007028393,"pool_token_amount":20000000000140558}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":20000000000550400,"pool_token_amount":20000000000011000}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Artifact":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":137862115188376758,"pool_token_amount":134942434593093588}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":137825567605310661,"pool_token_amount":134941304341510022}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":137807257574032215,"pool_token_amount":134940702905398273}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":137639647395556718,"pool_token_amount":134935366040537214}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":137600958251495320,"pool_token_amount":134933091658482167}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":137507413493465297,"pool_token_amount":134930338997658502}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":137435221409740001,"pool_token_amount":134947934321438351}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":137416665013198772,"pool_token_amount":134947387703979095}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":137379504009657730,"pool_token_amount":134946252825926207}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":137360915116130296,"pool_token_amount":134945690743525593}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":137317750006935155,"pool_token_amount":134938700045816046}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":137299185011390033,"pool_token_amount":134938152744656623}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":137280618944431880,"pool_token_amount":134937605340123618}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":137224865457446643,"pool_token_amount":134935922922175097}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":137206292098193338,"pool_token_amount":134935376455327402}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":137168979606658695,"pool_token_amount":134934140336912606}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":137130750215103629,"pool_token_amount":134931967353104085}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":137056503154335462,"pool_token_amount":134929777159531447}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":137037941301505053,"pool_token_amount":134929227989361407}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":137000882130444594,"pool_token_amount":134928182022431127}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":136926671254663359,"pool_token_amount":134925988009971660}],[114,{"sui_amount":136908119524231652,"pool_token_amount":134925439589627837}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":136871015616318731,"pool_token_amount":134924345398394902}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":136852381954567139,"pool_token_amount":134923717842422098}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":136808082769970247,"pool_token_amount":134937249749042401}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":136787345563496965,"pool_token_amount":134936636139786637}],[106,{"sui_amount":136765950246937607,"pool_token_amount":134936002961078292}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[100,{"sui_amount":136635415376911864,"pool_token_amount":134930142278328766}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":136529688936556445,"pool_token_amount":134926858136946214}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":136385486334008396,"pool_token_amount":134923778058596886}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":136308893885281589,"pool_token_amount":134926972944636903}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":136242330344720848,"pool_token_amount":134920179436748065}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":136147683103649781,"pool_token_amount":134925494178471182}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":136127223847199174,"pool_token_amount":134924877258981885}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":136042033585041869,"pool_token_amount":134921863802792998}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":135997456585594866,"pool_token_amount":134919368391532383}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":135953977689210075,"pool_token_amount":134918155416623725}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":135869517333281209,"pool_token_amount":134915641306189642}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":135761901076415678,"pool_token_amount":134887556663842826}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":135662242669134461,"pool_token_amount":134887621125404356}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":135600106410351783,"pool_token_amount":134885656977453758}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"sui_amount":135398654784451497,"pool_token_amount":134885153738724074}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":105256756576208717,"pool_token_amount":104971505534810890}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":105219464625355488,"pool_token_amount":104968974435030257}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":105149452893004498,"pool_token_amount":104969330822448905}],[27,{"sui_amount":105129879133599505,"pool_token_amount":104968744615556752}],[24,{"sui_amount":80078457195260956,"pool_token_amount":80004203292103525}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80038219627099941,"pool_token_amount":80001036313506367}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Astro-Stakers":[[167,{"sui_amount":35713278970292193,"pool_token_amount":34996053193317523}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":35689423749681498,"pool_token_amount":34993682161632499}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":35680206906493335,"pool_token_amount":34992868768258510}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":35675399916531949,"pool_token_amount":34992449010807307}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":35671975080833742,"pool_token_amount":34997679690444800}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":35652320698112945,"pool_token_amount":34995579486427809}],[151,{"sui_amount":35642620557283760,"pool_token_amount":34994654491113370}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[148,{"sui_amount":35628185488145877,"pool_token_amount":34993426947075393}],[147,{"sui_amount":60577452505114017,"pool_token_amount":26236842628119062}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":35592582142192685,"pool_token_amount":34992997557837346}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":35564198482086036,"pool_token_amount":34999326594715117}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":35516947924316720,"pool_token_amount":34995630254946649}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":35507516617401540,"pool_token_amount":34994884987860295}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":35498088513362556,"pool_token_amount":34994141586952539}],[117,{"sui_amount":35493375375786496,"pool_token_amount":34993769888385284}],[116,{"sui_amount":35488667477271984,"pool_token_amount":34993403132402910}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":35474532566035655,"pool_token_amount":34992292526523222}],[111,{"sui_amount":35471010290962981,"pool_token_amount":34997374727669152}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":90853781868271072,"pool_token_amount":39531943192078969}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":35456003188550117,"pool_token_amount":34996361707123798}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":90592941540681178,"pool_token_amount":39456929245771835}],[101,{"sui_amount":35416877721351908,"pool_token_amount":34992325583302708}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":35396304673824127,"pool_token_amount":34996497599125638}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":35380165758821357,"pool_token_amount":34995252942485528}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":35371510736889665,"pool_token_amount":34996341194194067}],[90,{"sui_amount":35364254744973390,"pool_token_amount":34993970056038254}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":35336084464674732,"pool_token_amount":34990073463073998}],[84,{"sui_amount":35339475110401111,"pool_token_amount":34998197529435746}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":35334243140478538,"pool_token_amount":34997782102725819}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":35323994930424614,"pool_token_amount":34997164786909958}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":35321906905556185,"pool_token_amount":35004836701284836}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":35317442416658004,"pool_token_amount":35005176775559149}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":35312212546762876,"pool_token_amount":35004759357845348}],[76,{"sui_amount":35306991300627034,"pool_token_amount":35004346654768113}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":35296610609115636,"pool_token_amount":35003584483176460}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":35268849953543809,"pool_token_amount":35001306407084036}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":35264100987930229,"pool_token_amount":35001666844050248}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":35165553764197714,"pool_token_amount":35001689027603212}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":35132626204420787,"pool_token_amount":35003112187036668}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":35096772974984347,"pool_token_amount":34997884467147200}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":35082624023242250,"pool_token_amount":35000001506307002}],[32,{"sui_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"sui_amount":35076652400821513,"pool_token_amount":34999451534318999}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":35063056765722483,"pool_token_amount":34997012098735410}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":35049403563688967,"pool_token_amount":34995143489510391}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":25018970896908741,"pool_token_amount":25001568139606424}],[22,{"sui_amount":25012063523938587,"pool_token_amount":25000445971954923}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":25000000031979264,"pool_token_amount":25000000000639572}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":25000000000691200,"pool_token_amount":25000000000013816}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":25000000000572400,"pool_token_amount":25000000000011444}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":25000000000550800,"pool_token_amount":25000000000011015}],[1,{"sui_amount":80000000000000000,"pool_token_amount":80000000000000000}]],"B-Harvest":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":35765158602133587,"pool_token_amount":35051088968862214}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":35751024871142051,"pool_token_amount":35049980709922754}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":35746314182985307,"pool_token_amount":35049611244294572}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":35732286267435756,"pool_token_amount":35048511653839870}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":35722663304652903,"pool_token_amount":35047756500911537}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":35693660996126419,"pool_token_amount":35045360289820211}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":35674353916445634,"pool_token_amount":35043792889878392}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":35659901873578123,"pool_token_amount":35042657034674146}],[143,{"sui_amount":35655087542314004,"pool_token_amount":35042278554275118}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":35644989796184889,"pool_token_amount":35049680686203601}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":35624056671757400,"pool_token_amount":35050532254051576}],[133,{"sui_amount":35619339173630539,"pool_token_amount":35050160929580610}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":35595440804209119,"pool_token_amount":35048280975112915}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":35581127117242251,"pool_token_amount":35047186415298330}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":35543228089945697,"pool_token_amount":35044216934980948}],[116,{"sui_amount":35538114873176832,"pool_token_amount":35043541495178942}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":35528600516191395,"pool_token_amount":35042893073776583}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":35518950774474835,"pool_token_amount":35042111635408411}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":35489146925095486,"pool_token_amount":35031162072947334}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":35483793473825320,"pool_token_amount":35030737588926148}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":35478311672866445,"pool_token_amount":35030313768143641}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[103,{"sui_amount":35461633220746223,"pool_token_amount":35029057169890208}],[102,{"sui_amount":35456198138968843,"pool_token_amount":35028628576063338}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":35417959704071513,"pool_token_amount":35025508708949830}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":35385820100716313,"pool_token_amount":35022752122945458}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":35336371307999881,"pool_token_amount":35017410212679203}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":35335652893883714,"pool_token_amount":35036067175547151}],[74,{"sui_amount":35324968823084977,"pool_token_amount":35035206890575737}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":35308407824094411,"pool_token_amount":35033891784706207}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":35249061890994194,"pool_token_amount":35010299605283561}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":35243712148069340,"pool_token_amount":35009860818271533}],[61,{"sui_amount":35233042996312325,"pool_token_amount":35009012890488731}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":35222111095230316,"pool_token_amount":35007904296682887}],[57,{"sui_amount":35211416948754273,"pool_token_amount":35007031045258756}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":35200727794233377,"pool_token_amount":35006163438280608}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":35190086405486136,"pool_token_amount":35005343344790001}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":35163403385624182,"pool_token_amount":35003211139287678}],[46,{"sui_amount":35152731513682432,"pool_token_amount":35002358471770052}],[45,{"sui_amount":35147397366238596,"pool_token_amount":35001933565404943}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":35136712708223016,"pool_token_amount":35001067702743317}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":35131161700856040,"pool_token_amount":35000427347017464}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":35103821663111259,"pool_token_amount":34998055010017790}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":35062754399343267,"pool_token_amount":34994544079561871}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"sui_amount":35035681401063743,"pool_token_amount":34990912115140125}],[25,{"sui_amount":25031038260567467,"pool_token_amount":25003751495335602}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":25013579004167687,"pool_token_amount":25002019783848360}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":25000000000556200,"pool_token_amount":25000000000011122}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":25000000000000000,"pool_token_amount":25000000000000000}]],"BLRD":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":27583003289648636,"pool_token_amount":27046345869492508}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":27571776452856234,"pool_token_amount":27044890931831286}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":27539204823290162,"pool_token_amount":27042139209187112}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":27535402249425880,"pool_token_amount":27041683369225441}],[151,{"sui_amount":27527953178565894,"pool_token_amount":27040924753865908}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":27513121856075906,"pool_token_amount":27039474715699595}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":27502180492043232,"pool_token_amount":27038397515933725}],[143,{"sui_amount":27498569743462205,"pool_token_amount":27038042529590402}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":27476909914549197,"pool_token_amount":27035927629297368}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":27466069150963047,"pool_token_amount":27034860823619890}],[133,{"sui_amount":27462457774350892,"pool_token_amount":27034507150509510}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":27458849021174011,"pool_token_amount":27034156396238808}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":27448004434973300,"pool_token_amount":27033089481630029}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":27440774126418952,"pool_token_amount":27032377337121289}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":27433650208091656,"pool_token_amount":27031764381956176}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":27422839633208281,"pool_token_amount":27030722221313044}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":27401175660428719,"pool_token_amount":27028586166083839}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":27394055922118103,"pool_token_amount":27027973056580850}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":27390445577332496,"pool_token_amount":27027616846433565}],[112,{"sui_amount":27386835115614161,"pool_token_amount":27027260582491069}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":27350689273576645,"pool_token_amount":27023715499978234}],[100,{"sui_amount":27337809362990484,"pool_token_amount":27022355594034138}],[99,{"sui_amount":27333684099060599,"pool_token_amount":27021947825660448}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":27308667691480606,"pool_token_amount":27019430261698433}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":27300449023153587,"pool_token_amount":27018530675809497}],[90,{"sui_amount":27295366239961235,"pool_token_amount":27017103983430315}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":27287283277054265,"pool_token_amount":27016303873068721}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":27238716888187057,"pool_token_amount":27011309697355408}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":27226602067867611,"pool_token_amount":27010108169249211}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":27218153385511551,"pool_token_amount":27009268174831969}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":27213923456861450,"pool_token_amount":27008843962738348}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":27209587165283514,"pool_token_amount":27008413601320411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":27188235632961521,"pool_token_amount":27006280772034083}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":27184840919599247,"pool_token_amount":27006485709693223}],[61,{"sui_amount":27176839055778768,"pool_token_amount":27005690720535486}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":27160828791718552,"pool_token_amount":27004094115962377}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":27139999171817926,"pool_token_amount":27001584901815219}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":27102806673307910,"pool_token_amount":26997717279493295}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":27086314290010801,"pool_token_amount":26996035941887027}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":27077969626228151,"pool_token_amount":26995203302102022}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":27073726593772775,"pool_token_amount":26994780296248228}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":27042390894325100,"pool_token_amount":26992174712191332}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":27037707419149628,"pool_token_amount":26991706670632558}],[25,{"sui_amount":20023263034545418,"pool_token_amount":20000578545609992}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":20009421066195300,"pool_token_amount":20000261536395933}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":20000000000475400,"pool_token_amount":20000000000009502}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":20000000000445300,"pool_token_amount":20000000000008902}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":20000000000428400,"pool_token_amount":20000000000008567}]],"BartestneT":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":117507085722508773,"pool_token_amount":115091407327147149}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":117475013827648459,"pool_token_amount":115088906132189620}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":117411875248929974,"pool_token_amount":115085809474497376}],[157,{"sui_amount":117395836788729088,"pool_token_amount":115085023438118622}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":117303741557402156,"pool_token_amount":115054483933747444}],[152,{"sui_amount":117287701202352552,"pool_token_amount":115053697293946917}],[149,{"sui_amount":117239582969471468,"pool_token_amount":115051337934664603}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":117175180392260465,"pool_token_amount":115047336398830934}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":117064214969497686,"pool_token_amount":115041886776230445}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":117000764050850904,"pool_token_amount":115038770327267194}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":116921549891928770,"pool_token_amount":115034879725424279}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":116824247801047043,"pool_token_amount":115027605967221918}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":116776893558444729,"pool_token_amount":115025584614418039}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":116758177050419063,"pool_token_amount":115022134246869657}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":116742022067112446,"pool_token_amount":115021206371674357}],[117,{"sui_amount":116726177903400886,"pool_token_amount":115020581946689906}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":116645056291773765,"pool_token_amount":115015587498683988}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":116613358624109126,"pool_token_amount":115014337221559288}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":116560412420590850,"pool_token_amount":115012261424624900}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":116542220680300949,"pool_token_amount":115011543416467491}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[98,{"sui_amount":116396392046862043,"pool_token_amount":115004412054516890}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":116306470954550318,"pool_token_amount":114999891472960489}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":116288741499872194,"pool_token_amount":114999015899317966}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":116147935557915967,"pool_token_amount":114992041621923716}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":116130350595358052,"pool_token_amount":114991171123931149}],[82,{"sui_amount":116112876179452772,"pool_token_amount":114990305973828623}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":115936047996076687,"pool_token_amount":114981520336283687}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":115862034125527143,"pool_token_amount":114977867308741314}],[67,{"sui_amount":115843475418718681,"pool_token_amount":114976946454660674}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":115806360915702993,"pool_token_amount":114975107302040885}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":115754082478085879,"pool_token_amount":114972574530759978}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":115596435605821169,"pool_token_amount":114964506707440225}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":115526304170483845,"pool_token_amount":114961191740252668}],[48,{"sui_amount":115508641603284596,"pool_token_amount":114960339981216908}],[46,{"sui_amount":115473299964996026,"pool_token_amount":114958615389218842}],[45,{"sui_amount":115455618601595035,"pool_token_amount":114957741502911352}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"sui_amount":115366668151935908,"pool_token_amount":114953899061725000}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":105239137148993302,"pool_token_amount":104975934211119013}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":105185795307633888,"pool_token_amount":104973992787873847}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":105129202218291575,"pool_token_amount":104971108666619143}],[25,{"sui_amount":80096058906784554,"pool_token_amount":80006712332966508}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":80059248507012938,"pool_token_amount":80004520970081798}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"sui_amount":80000000049908508,"pool_token_amount":80000000000998159}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":80000000001754400,"pool_token_amount":80000000000035087}]],"BiXinKelePool":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[162,{"sui_amount":42340374111669720,"pool_token_amount":41521842502667070}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":42305707837400262,"pool_token_amount":41518612295669502}],[155,{"sui_amount":42304003382673775,"pool_token_amount":41522132128613802}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":42280426851748501,"pool_token_amount":41519764387052654}],[150,{"sui_amount":42274612722396020,"pool_token_amount":41519250529116154}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":42234957940338748,"pool_token_amount":41521186438267286}],[140,{"sui_amount":42223522699839723,"pool_token_amount":41520174596343228}],[136,{"sui_amount":42203289942160419,"pool_token_amount":41520764568436564}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":42197569916120985,"pool_token_amount":41520258091146304}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":42191045559970246,"pool_token_amount":41518960427124654}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":42177486074264492,"pool_token_amount":41520990088095296}],[130,{"sui_amount":42171763006099532,"pool_token_amount":41520483028633484}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":42166047666719313,"pool_token_amount":41519986566243959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":42154607810705995,"pool_token_amount":41518979979300318}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[122,{"sui_amount":42131124827568450,"pool_token_amount":41521482619108673}],[120,{"sui_amount":42119689255529894,"pool_token_amount":41520468246856456}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":42096823538790465,"pool_token_amount":41518439232144521}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":42085238325951417,"pool_token_amount":41522405011420462}],[109,{"sui_amount":42061676694083832,"pool_token_amount":41520263961219080}],[107,{"sui_amount":42048933867825307,"pool_token_amount":41519102142636544}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[98,{"sui_amount":41994260756087382,"pool_token_amount":41518271188003300}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":41982574827184676,"pool_token_amount":41523981199863461}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[89,{"sui_amount":41944015098773049,"pool_token_amount":41520163358102447}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":41931222961006951,"pool_token_amount":41518895201483001}],[84,{"sui_amount":41924375100018228,"pool_token_amount":41529134652761944}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[78,{"sui_amount":41889611556739718,"pool_token_amount":41528725811902398}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[72,{"sui_amount":41859620862269647,"pool_token_amount":41533407886346002}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":41861352402193453,"pool_token_amount":41553100417333572}],[67,{"sui_amount":41847795170597414,"pool_token_amount":41551755213603120}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[58,{"sui_amount":41799397625107841,"pool_token_amount":41555445764505896}],[55,{"sui_amount":41780392083448999,"pool_token_amount":41553556044641193}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":41774056975706019,"pool_token_amount":41552925973347520}],[53,{"sui_amount":41767721958070670,"pool_token_amount":41552296722117405}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":41749487978781002,"pool_token_amount":41551173180254168}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":41743153143039671,"pool_token_amount":41550542705794559}],[48,{"sui_amount":41739873632174967,"pool_token_amount":41553053934397006}],[46,{"sui_amount":41727204346745637,"pool_token_amount":41551792590227341}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":41711225748197813,"pool_token_amount":41552913348429428}],[41,{"sui_amount":41698331530818861,"pool_token_amount":41551627834534411}],[39,{"sui_amount":35102460727004260,"pool_token_amount":34988799332079983}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":35100462800728419,"pool_token_amount":34991696064706283}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":35089423977843002,"pool_token_amount":34990593730539865}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":35077765096156622,"pool_token_amount":34989441820683982}],[31,{"sui_amount":35063105920818553,"pool_token_amount":34990697774499023}],[28,{"sui_amount":35044302510401945,"pool_token_amount":34988126658221397}],[26,{"sui_amount":35033708955650315,"pool_token_amount":34989740538840425}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":25000000019836964,"pool_token_amount":25000000000396727}],[17,{"sui_amount":25000000015495364,"pool_token_amount":25000000000309897}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":25000000000691200,"pool_token_amount":25000000000013816}],[10,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"BlockEden.xyz":[[167,{"sui_amount":36726098257932527,"pool_token_amount":35997418274243052}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":36721286185188055,"pool_token_amount":35996946614186807}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":36697234918922741,"pool_token_amount":35994588371741247}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":36713402325485080,"pool_token_amount":36023376782171812}],[156,{"sui_amount":36702360957029306,"pool_token_amount":36021305914171443}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":36676922608875615,"pool_token_amount":36018210190155582}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"sui_amount":36657255465077044,"pool_token_amount":36016265183919536}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":36632172107223620,"pool_token_amount":36013800098993296}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":36612104728883417,"pool_token_amount":36011826869126917}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":36607081295999820,"pool_token_amount":36011332761382451}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":36597054705955635,"pool_token_amount":36010357134450204}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":36592036849614676,"pool_token_amount":36009863392588193}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":36587018234622476,"pool_token_amount":36009369515120462}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":36581233027348593,"pool_token_amount":36008121612258155}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":36561152810147210,"pool_token_amount":36006150041836188}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":36551141797998123,"pool_token_amount":36005186536428898}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":36546130464944381,"pool_token_amount":36004697322492802}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":36541109542557706,"pool_token_amount":36004199121686470}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":36536092983028107,"pool_token_amount":36003704836294058}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":36516050366878178,"pool_token_amount":36001748159881534}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":36459939708194725,"pool_token_amount":35996363436761505}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":36443052484019378,"pool_token_amount":35994698630983787}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":36431428578332547,"pool_token_amount":35993549117064649}],[98,{"sui_amount":36402697647983429,"pool_token_amount":35990707075389107}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":36391459319647805,"pool_token_amount":35989600370496064}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":36380346038435370,"pool_token_amount":35988483433167089}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":36347640026133045,"pool_token_amount":35985695229610714}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":36342158426369897,"pool_token_amount":35985165909873277}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":36330671112396717,"pool_token_amount":35983561423219369}],[84,{"sui_amount":36325217444472978,"pool_token_amount":35983021266895089}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":36293320362502507,"pool_token_amount":35995357160305232}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":36275662178674804,"pool_token_amount":35998083238230451}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":36269879697370177,"pool_token_amount":35997508521688108}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":36252533389231561,"pool_token_amount":35995780415671904}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":36213816627490468,"pool_token_amount":35987427687414356}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":36202424436802869,"pool_token_amount":35985848262726344}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":36185515332308174,"pool_token_amount":35983954324672914}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":36179958036887836,"pool_token_amount":35983401690656406}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":36143197509138010,"pool_token_amount":35995591339694884}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":36102290654584148,"pool_token_amount":35989917813028023}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":36084842483334300,"pool_token_amount":35988011249911319}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":36059269811637942,"pool_token_amount":35984667775929741}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":25039782258486216,"pool_token_amount":25003759785108899}],[26,{"sui_amount":25034801958386532,"pool_token_amount":25003283169811624}],[24,{"sui_amount":25024242607987629,"pool_token_amount":25002433641925894}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":25018192297371582,"pool_token_amount":25001793172110713}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"sui_amount":25000000015495364,"pool_token_amount":25000000000309897}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":25000000000556200,"pool_token_amount":25000000000011122}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":25000000000000000,"pool_token_amount":25000000000000000}]],"BlockVision":[[167,{"sui_amount":46607803587975292,"pool_token_amount":45673670729982689}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":46587396047413958,"pool_token_amount":45681080005439287}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":46575958210517682,"pool_token_amount":45680827649645088}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":46556716590362088,"pool_token_amount":45678944730435931}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":46543795515237337,"pool_token_amount":45677596449974285}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":46516950926451233,"pool_token_amount":45673918429053368}],[151,{"sui_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"sui_amount":46497902341046995,"pool_token_amount":45672046977649258}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":46491582640218351,"pool_token_amount":45671426231548280}],[145,{"sui_amount":46646654185460203,"pool_token_amount":45834972334352696}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":46640329074678463,"pool_token_amount":45834349944425657}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":46627693386122617,"pool_token_amount":45833109030994389}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":46621374180460882,"pool_token_amount":45832487878537731}],[140,{"sui_amount":46614715436211159,"pool_token_amount":45831533333613963}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":46481622812681162,"pool_token_amount":45817980000005562}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":46471804078584205,"pool_token_amount":45813907119182523}],[116,{"sui_amount":46472809981708079,"pool_token_amount":45826113253484207}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":46459548968193817,"pool_token_amount":45824250247006539}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":46452697871413456,"pool_token_amount":45823101370510538}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":46419838821696086,"pool_token_amount":45819989676226466}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[103,{"sui_amount":46385419628666925,"pool_token_amount":45818383855626061}],[97,{"sui_amount":46341361368391645,"pool_token_amount":45813407275029996}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":46334129448159712,"pool_token_amount":45812517951052328}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":46305863311208504,"pool_token_amount":45809721695500571}],[91,{"sui_amount":46298763472603576,"pool_token_amount":45809017825187549}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":46284515186775850,"pool_token_amount":45807525827293200}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":46250371461504245,"pool_token_amount":45786326226986529}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":46201001280409080,"pool_token_amount":45781868371492020}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":46144959833852695,"pool_token_amount":45777920426803856}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":46130192463121860,"pool_token_amount":45776662579561301}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":46115298145833641,"pool_token_amount":45775480997819888}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":36219131146128700,"pool_token_amount":35962994828045792}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":36196943377438282,"pool_token_amount":35961166565416945}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":36180387750367603,"pool_token_amount":35959651642335581}],[58,{"sui_amount":36172938977818605,"pool_token_amount":35957227858910484}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":36142397107783807,"pool_token_amount":35952079429877998}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":36131580903692518,"pool_token_amount":35951288294753847}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":36126145451701718,"pool_token_amount":35950864800649017}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":36115241466243832,"pool_token_amount":35949985681950708}],[47,{"sui_amount":36109721026399380,"pool_token_amount":35949477395268828}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":36042050348150236,"pool_token_amount":35943723615283869}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":36027560045494744,"pool_token_amount":35940491951540558}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":35996494613928347,"pool_token_amount":35932265282671106}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":25928292013911136,"pool_token_amount":25905581543356260}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":25000000019836964,"pool_token_amount":25000000000396727}],[16,{"sui_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":25000000000000000,"pool_token_amount":25000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Blockdaemon":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":117288640199503743,"pool_token_amount":115022542115133813}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":117273101265919288,"pool_token_amount":115021323017898189}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":117257564618341846,"pool_token_amount":115020103951444885}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":117210972618313961,"pool_token_amount":115016447268860550}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":71436868631769519,"pool_token_amount":70116922309784292}],[156,{"sui_amount":71438425477812847,"pool_token_amount":70136012438258919}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":71406330842745910,"pool_token_amount":70130853090019222}],[152,{"sui_amount":71393994847305286,"pool_token_amount":70127524146213132}],[151,{"sui_amount":71379386092053931,"pool_token_amount":70121961953584903}],[149,{"sui_amount":71356721085359079,"pool_token_amount":70117272979164092}],[148,{"sui_amount":71346856513304848,"pool_token_amount":70116370957793311}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":71221418224848324,"pool_token_amount":70104227164658824}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":71685072742026922,"pool_token_amount":70594346710692852}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":71675348560626864,"pool_token_amount":70593210628961066}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":69597840175880794,"pool_token_amount":68596183444039653}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":69588514937115838,"pool_token_amount":68595172377006267}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":69579082024997025,"pool_token_amount":68594056585145341}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":69225009616437019,"pool_token_amount":68361166530743031}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":69181666712656893,"pool_token_amount":68356005054540980}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":69159109292616167,"pool_token_amount":68352681647512675}],[101,{"sui_amount":69148293088747823,"pool_token_amount":68351399708348462}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":69072734091495939,"pool_token_amount":68341904524458573}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":69044119588316808,"pool_token_amount":68322834712712927}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":69012691006141175,"pool_token_amount":68319105679448956}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":67532470414976835,"pool_token_amount":66862665199964625}],[88,{"sui_amount":67522262075036777,"pool_token_amount":66861454964004613}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":67501354821424457,"pool_token_amount":66858539235338928}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":67387504858777390,"pool_token_amount":66772367104012764}],[82,{"sui_amount":67377373375645190,"pool_token_amount":66771159808143360}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":67368611543917786,"pool_token_amount":66771309002581518}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":67337767714563755,"pool_token_amount":66767617742143326}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":67180452235726896,"pool_token_amount":66638112742897960}],[74,{"sui_amount":66836887504620136,"pool_token_amount":66306150679380405}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":66805110323109360,"pool_token_amount":66302278113091469}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":66794425819739484,"pool_token_amount":66300996016645965}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":66762152386889836,"pool_token_amount":66296922032996619}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":66183279429175683,"pool_token_amount":65749398369969696}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":66173021786197030,"pool_token_amount":65747952593502821}],[61,{"sui_amount":65952419128535825,"pool_token_amount":65546231424387952}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":56030308367314341,"pool_token_amount":55722510418909828}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":55936306726847350,"pool_token_amount":55710916425978336}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":55927762658267547,"pool_token_amount":55709906674913006}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":55709994950093679,"pool_token_amount":55508087495401772}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":35568778891434308,"pool_token_amount":35518021214312457}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":28458499105190570,"pool_token_amount":28439798063978626}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":20000000000475400,"pool_token_amount":20000000000009502}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":20000000000000000,"pool_token_amount":20000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Blockscope.net":[[167,{"sui_amount":153534198820848694,"pool_token_amount":150274929096901219}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":153518389867009701,"pool_token_amount":150297702297512327}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":153477691897123987,"pool_token_amount":150296109384786094}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":153416655773220935,"pool_token_amount":150293515132567143}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":153426153454153680,"pool_token_amount":150322434056859873}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":153374653949713384,"pool_token_amount":150291586978391208}],[156,{"sui_amount":153333010431509130,"pool_token_amount":150290006041737339}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":153270116568171834,"pool_token_amount":150287407482011017}],[149,{"sui_amount":153185831947258645,"pool_token_amount":150283652880840739}],[148,{"sui_amount":153165664818645081,"pool_token_amount":150283412805022073}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":152978867311361093,"pool_token_amount":150275518009600716}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":152674558008304557,"pool_token_amount":150269033564837113}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":152661552665646693,"pool_token_amount":150275766441977749}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":152599626679559908,"pool_token_amount":150273403651902143}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":152517778996650403,"pool_token_amount":150270936585865692}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":152440611895372564,"pool_token_amount":150253530114421457}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":152326021706340826,"pool_token_amount":150264555288680330}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":152301705707579374,"pool_token_amount":150263108958091891}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"sui_amount":152185142162393659,"pool_token_amount":150261211757025566}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":152066226996732910,"pool_token_amount":150255390759042180}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":152041274043986389,"pool_token_amount":150252958056325315}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":151867187410039168,"pool_token_amount":150256555324569125}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":151821346498510800,"pool_token_amount":150254765741644168}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":151752796156411992,"pool_token_amount":150252061290152323}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":151702169947041477,"pool_token_amount":150246154909996301}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":151656561327572090,"pool_token_amount":150244345480937263}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[75,{"sui_amount":151588172979086253,"pool_token_amount":150241610312275054}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":151500919855600098,"pool_token_amount":150313839951090541}],[67,{"sui_amount":151476693519767621,"pool_token_amount":150312878490635771}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":211569526460800051,"pool_token_amount":210081373524611121}],[62,{"sui_amount":211537677154121410,"pool_token_amount":210080046557786807}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":211168233926581951,"pool_token_amount":209987221128348745}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":210861246511467226,"pool_token_amount":209989206122422742}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":150750193360006689,"pool_token_amount":150215953913045113}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":150701000334755610,"pool_token_amount":150211950366773571}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":170717347131493151,"pool_token_amount":170193186545118769}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":170577906774042100,"pool_token_amount":170193754895966477}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":170547990711068127,"pool_token_amount":170191985905942429}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":200512622418438545,"pool_token_amount":200167865729086964}],[27,{"sui_amount":200278530506479079,"pool_token_amount":199970361652571880}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":150109326426139993,"pool_token_amount":150005218149539212}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":150000000119670491,"pool_token_amount":150000000002393397}],[16,{"sui_amount":150000000053253526,"pool_token_amount":150000000001065061}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":150000000004141300,"pool_token_amount":150000000000082818}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":150000000004043500,"pool_token_amount":150000000000080863}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":150000000003424100,"pool_token_amount":150000000000068478}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":150000000003391500,"pool_token_amount":150000000000067827}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":150000000000000000,"pool_token_amount":150000000000000000}]],"Brightlystake":[[167,{"sui_amount":36769230841564408,"pool_token_amount":36024115216251123}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":36764417768819936,"pool_token_amount":36023737071503661}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":36759606726530334,"pool_token_amount":36023359941883640}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":36754794669380732,"pool_token_amount":36022982687259198}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":36745172404617873,"pool_token_amount":36022228186774669}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":36710403799881928,"pool_token_amount":36019508534723032}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"sui_amount":36675407772585449,"pool_token_amount":36016481019170804}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":36645429186369394,"pool_token_amount":36014143198263539}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":36635398273518208,"pool_token_amount":36013354498697102}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":36625362822615350,"pool_token_amount":36012566161194036}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":36620339389731753,"pool_token_amount":36012171009825574}],[136,{"sui_amount":36615318197448704,"pool_token_amount":36011775984938839}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":36610300630679112,"pool_token_amount":36011381195588743}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":36605282774338153,"pool_token_amount":36010986333672924}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":36580181618111295,"pool_token_amount":36009010341673221}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":36565956601321017,"pool_token_amount":36008645705975036}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":36555918344644827,"pool_token_amount":36007850303815779}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":36536274173648860,"pool_token_amount":36015773660083363}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":36516195572413630,"pool_token_amount":36014169416832669}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":36511181204824278,"pool_token_amount":36013773782051044}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":36479564153868692,"pool_token_amount":36011315430693987}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":36468136936306594,"pool_token_amount":36010412914407764}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":36462333289713413,"pool_token_amount":36009954445906952}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"sui_amount":36444980643223536,"pool_token_amount":36008585988784421}],[100,{"sui_amount":36439244672666878,"pool_token_amount":36008132603310864}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":36395420422834749,"pool_token_amount":36010733690785295}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":36384411269771772,"pool_token_amount":36009863118726027}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":36367938257677045,"pool_token_amount":36008573843613143}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":36362361009068500,"pool_token_amount":36008134829582751}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":36338122943693593,"pool_token_amount":36004309660594371}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":36288172337124500,"pool_token_amount":36000322585914038}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":36282392950205188,"pool_token_amount":35999863902474222}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":36264918787122773,"pool_token_amount":35998457478433048}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":36246932690953432,"pool_token_amount":35996740004231445}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":36235819023465515,"pool_token_amount":35995856985470463}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":36208462896607788,"pool_token_amount":35993668126902994}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"sui_amount":36142783148242106,"pool_token_amount":35988445472046849}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":36074726519212041,"pool_token_amount":35982918324858086}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":25020913919159091,"pool_token_amount":25004513096698381}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":25000000032208364,"pool_token_amount":25000000000644154}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":25000000000691200,"pool_token_amount":25000000000013816}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":25000000000572400,"pool_token_amount":25000000000011444}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":25000000000000000,"pool_token_amount":25000000000000000}]],"Bware Labs":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":146784382780059539,"pool_token_amount":143759286021164538}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":146764938664203343,"pool_token_amount":143758524285208267}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":146706117942754360,"pool_token_amount":143756031291441145}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":146686168570314931,"pool_token_amount":143755247472704417}],[156,{"sui_amount":146647146649979252,"pool_token_amount":143754538305239924}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":146587071106841353,"pool_token_amount":143752155126356036}],[151,{"sui_amount":146545851227910896,"pool_token_amount":143749295073691403}],[150,{"sui_amount":146526517315144242,"pool_token_amount":143749115307613462}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[146,{"sui_amount":146444848995064398,"pool_token_amount":143743891779732159}],[145,{"sui_amount":146425070494820295,"pool_token_amount":143743112403576442}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":146353273485848634,"pool_token_amount":143765769355950655}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":146254697680320373,"pool_token_amount":143762190302938380}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":146206761099925675,"pool_token_amount":143790904798750682}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":146186871572949801,"pool_token_amount":143790018695295506}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":146146416762428695,"pool_token_amount":143787602641459143}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":146106705434014864,"pool_token_amount":143785880948635209}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":146047342527348873,"pool_token_amount":143783480688359384}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":145967928678127705,"pool_token_amount":143780009903919325}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":145924456041829437,"pool_token_amount":143774552790549447}],[116,{"sui_amount":145906203187342510,"pool_token_amount":143775253722463489}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":145865148496314038,"pool_token_amount":143772174670342845}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":145787145441725356,"pool_token_amount":143770076154815515}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":145740894336536112,"pool_token_amount":143766053938314785}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":145696126777616354,"pool_token_amount":143764359171946584}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":145697279566892731,"pool_token_amount":143787225507500204}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":145718666495755034,"pool_token_amount":143831399663630885}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":145671741662335297,"pool_token_amount":143828506414599409}],[98,{"sui_amount":145514818199475423,"pool_token_amount":143759472917433129}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":145469975926808931,"pool_token_amount":143757717053750866}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":145382105024153378,"pool_token_amount":143755617010282070}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":145250460175141421,"pool_token_amount":143750824036867680}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":145085100268633625,"pool_token_amount":143649511101442250}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":144802454097370050,"pool_token_amount":143689353175008581}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":144687462939137379,"pool_token_amount":143683016747743577}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":144511209022757107,"pool_token_amount":143674438204976024}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":144422721809338544,"pool_token_amount":143670481345745795}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"sui_amount":135516576825767879,"pool_token_amount":134909425586675485}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":135476225346396078,"pool_token_amount":134908763697212518}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":135434304858339750,"pool_token_amount":134906755229450777}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":135308191752127750,"pool_token_amount":134902535824410380}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":105230953709859342,"pool_token_amount":104983615062711155}],[32,{"sui_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"sui_amount":105211077441032321,"pool_token_amount":104980926686452397}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":105172345603542116,"pool_token_amount":104976897133465962}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":105153804011626162,"pool_token_amount":104975940299204622}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028266523,"pool_token_amount":80000000000565321}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002203900,"pool_token_amount":80000000000044070}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840600,"pool_token_amount":80000000000036807}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":80000000000000000,"pool_token_amount":80000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Chainbase":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":117577822382942294,"pool_token_amount":115226068340249335}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":117544855034706312,"pool_token_amount":115223937754596019}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":117459107566486304,"pool_token_amount":115215347475905944}],[150,{"sui_amount":117423891982332319,"pool_token_amount":115211011698008326}],[148,{"sui_amount":117391731757489749,"pool_token_amount":115209580610274669}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":117342824433894908,"pool_token_amount":115236374524967167}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":117310881343169523,"pool_token_amount":115234883915398782}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":117214052907431250,"pool_token_amount":115229505488921206}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":117198196482596536,"pool_token_amount":115228881969987401}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":117149243005998327,"pool_token_amount":115225662137422628}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":117061034374164802,"pool_token_amount":115213798874800937}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":117045138758838941,"pool_token_amount":115213131509669069}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":117013757124979704,"pool_token_amount":115212202186977274}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":116982279845293100,"pool_token_amount":115211179953859403}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":116966030389834725,"pool_token_amount":115210158964692172}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":116907456658505668,"pool_token_amount":115197414965439345}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":116875377900396173,"pool_token_amount":115195780994705596}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":116692511695754711,"pool_token_amount":115090511890835526}],[109,{"sui_amount":116674855668016892,"pool_token_amount":115089779365586764}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":116657198408643355,"pool_token_amount":115089042919273080}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":116566136119862675,"pool_token_amount":115085427198329762}],[102,{"sui_amount":116547862632465168,"pool_token_amount":115084706491435934}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":116376621550063788,"pool_token_amount":115018127070662600}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":116340625990072925,"pool_token_amount":115016349109141558}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":116303893136287961,"pool_token_amount":115013442843911597}],[91,{"sui_amount":116286204072287563,"pool_token_amount":115012568206039313}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":116180507604635458,"pool_token_amount":115007280555852187}],[84,{"sui_amount":116163042644200082,"pool_token_amount":115006424625624592}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":116110503770040669,"pool_token_amount":115003817090518355}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":116056837126488637,"pool_token_amount":115000597105914237}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":116004431765947569,"pool_token_amount":114997953427540998}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":115950475001135540,"pool_token_amount":114995229622604707}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":115932024419831869,"pool_token_amount":114994313751514638}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":115913464152626096,"pool_token_amount":114993295243469961}],[69,{"sui_amount":115895107365548365,"pool_token_amount":114992583991658673}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":115860821067273796,"pool_token_amount":114993552138983230}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":115684253912996973,"pool_token_amount":114984917099424926}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":115666797473555976,"pool_token_amount":114984043841091909}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":115614147269467571,"pool_token_amount":114981563931883341}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":115471519716460137,"pool_token_amount":114972857605971538}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":115419816768374564,"pool_token_amount":114971627340963700}],[41,{"sui_amount":115401854213710844,"pool_token_amount":114970669173663083}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"sui_amount":115383958672855189,"pool_token_amount":114969776988466112}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":115330537047612262,"pool_token_amount":114967815907867608}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":115312622363614037,"pool_token_amount":114967405109250343}],[35,{"sui_amount":115292173111324517,"pool_token_amount":114965124004445852}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":105217937553705507,"pool_token_amount":104987313012455525}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":80000000001754400,"pool_token_amount":80000000000035087}]],"Chainflow":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":35409788647552165,"pool_token_amount":34673011613600693}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":35395936634215096,"pool_token_amount":34672315662306405}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":35388263913714077,"pool_token_amount":34673376279431562}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":35378940904241390,"pool_token_amount":34672919516414422}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":35368744997799002,"pool_token_amount":34671699776931458}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":43412076220755621,"pool_token_amount":42579672315151533}],[152,{"sui_amount":43406100319523589,"pool_token_amount":42579322391400740}],[151,{"sui_amount":43400186715335746,"pool_token_amount":42579033289082820}],[148,{"sui_amount":43382543651669465,"pool_token_amount":42578168663061769}],[145,{"sui_amount":43364886136720430,"pool_token_amount":42577303939225812}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":43333752707910066,"pool_token_amount":42574338730776608}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":43309863097317438,"pool_token_amount":42572983955145918}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":43303943380169856,"pool_token_amount":42572693949449936}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":43293097775844878,"pool_token_amount":42573092602169277}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":43269577314513662,"pool_token_amount":42572101231051023}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":43257741837589259,"pool_token_amount":42571532228220360}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":43239982313022100,"pool_token_amount":42570658223200416}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":43228142115069700,"pool_token_amount":42570075338351811}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":43180025902030943,"pool_token_amount":42566977226428050}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":43159963813921007,"pool_token_amount":42563824089264340}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":43134952747046881,"pool_token_amount":42563088615388870}],[106,{"sui_amount":43128201369080241,"pool_token_amount":42562754598675600}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":43100783194272242,"pool_token_amount":42561391032396688}],[99,{"sui_amount":44740551632511322,"pool_token_amount":44200657505248202}],[97,{"sui_amount":44726635591660039,"pool_token_amount":44199971928492274}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":44706239015526958,"pool_token_amount":44198960213459099}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":44685591166087603,"pool_token_amount":44197941275889369}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":44637957349794845,"pool_token_amount":44195770637430755}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":44617630043701898,"pool_token_amount":44194801846126824}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":44610732389955072,"pool_token_amount":44194463072798678}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":44590342039058168,"pool_token_amount":44193419079496894}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":44576782888616309,"pool_token_amount":44192746166622396}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":44570002681448199,"pool_token_amount":44192410076888575}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":44513207083212184,"pool_token_amount":44189488930042610}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":44458144124992273,"pool_token_amount":44186288477748362}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":44424106426037401,"pool_token_amount":44184256236123410}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":44410788056858013,"pool_token_amount":44183611980397196}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"sui_amount":40010415586695381,"pool_token_amount":39834128764147422}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":27084280535194315,"pool_token_amount":27000364782145286}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":27070717142854052,"pool_token_amount":26999388254791990}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":27062066739373944,"pool_token_amount":26999405856747586}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":27050035290237434,"pool_token_amount":27000470516898304}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"sui_amount":20027663030388938,"pool_token_amount":20005529696874868}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":20004800435991001,"pool_token_amount":20000226003028721}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":20000000000539900,"pool_token_amount":20000000000010790}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":20000000000527000,"pool_token_amount":20000000000010533}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":20000000000000000,"pool_token_amount":20000000000000000}]],"Chainode Tech":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":142958035385106038,"pool_token_amount":139960901742283840}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":142900940354411529,"pool_token_amount":139958765634925152}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":142776332324246486,"pool_token_amount":139947569325771903}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":142756531718752408,"pool_token_amount":139946652467509390}],[148,{"sui_amount":142659258755585636,"pool_token_amount":139943666885501185}],[147,{"sui_amount":142639897403471752,"pool_token_amount":139943096149437272}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":142543621961513572,"pool_token_amount":139940304264233264}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":142524866975188698,"pool_token_amount":139940231472076509}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":142447638127662904,"pool_token_amount":139937824111633396}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":142409342823310620,"pool_token_amount":139936937072287062}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":142390094445653040,"pool_token_amount":139936388891757733}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":142333313518421920,"pool_token_amount":139935706810780868}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":142294647485064908,"pool_token_amount":139934471709798009}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":142253265479821093,"pool_token_amount":139930563675223707}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":142234103876536491,"pool_token_amount":139930002081251411}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":142157146190932413,"pool_token_amount":139927443447016322}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":142122225774389379,"pool_token_amount":139929753960386043}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":142039636848081710,"pool_token_amount":139921995730532827}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":141961470077079073,"pool_token_amount":139918588270775806}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"sui_amount":141725591144519983,"pool_token_amount":139911931667913698}],[98,{"sui_amount":141659781200826143,"pool_token_amount":139910177393089223}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":141572281997656820,"pool_token_amount":139907506248129317}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":141550533326995686,"pool_token_amount":139906796295232163}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":141529065008682580,"pool_token_amount":139906257390617125}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":141441806508072543,"pool_token_amount":139902336935083060}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":141398887538260729,"pool_token_amount":139900991027795231}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":141332708183995362,"pool_token_amount":139896880653662348}],[82,{"sui_amount":141312250805055909,"pool_token_amount":139897042681580293}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":141176799641644045,"pool_token_amount":139865723492036040}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":140885262917779334,"pool_token_amount":139872653832979904}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":140793406845571034,"pool_token_amount":139863227514301200}],[58,{"sui_amount":140766159196467334,"pool_token_amount":139856614423578010}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":140701795135978688,"pool_token_amount":139854148826320750}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":140678919157644108,"pool_token_amount":139852092329946144}],[53,{"sui_amount":140656665481057209,"pool_token_amount":139850657079900409}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":140635832113545037,"pool_token_amount":139850633305241600}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":140459767909395486,"pool_token_amount":139820374964068107}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":140373814637831858,"pool_token_amount":139818090649868563}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"sui_amount":290870382900803457,"pool_token_amount":289809012108653824}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":290779039016417747,"pool_token_amount":289805458116930935}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":290587797719274670,"pool_token_amount":289797793882258966}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":290384384402756652,"pool_token_amount":289786004763378889}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":170146493011515008,"pool_token_amount":169988655968295230}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":151135775838466498,"pool_token_amount":151100721529907548}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":150699994193211591,"pool_token_amount":150699994002980605}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":150000000004141300,"pool_token_amount":150000000000082818}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Chorus One":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":54080953251060883,"pool_token_amount":53009458894272051}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":54059101244255698,"pool_token_amount":53007670522545240}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":54051509069056695,"pool_token_amount":53006772864187313}],[151,{"sui_amount":54036687286531284,"pool_token_amount":53005332678897891}],[149,{"sui_amount":54021845426146677,"pool_token_amount":53003872314838807}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":53978613813285079,"pool_token_amount":53019568958822113}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":53944678313504663,"pool_token_amount":53018629802196732}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":53918322510470106,"pool_token_amount":53018653363708625}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":53911195408835416,"pool_token_amount":53018131726872331}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":51941653342512591,"pool_token_amount":51112383188806046}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":51867714425729609,"pool_token_amount":51114426378277846}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":51826146728070822,"pool_token_amount":51113097091343310}],[106,{"sui_amount":51818187169202139,"pool_token_amount":51112457496902602}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":51785741463703203,"pool_token_amount":51109525828067086}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":51731184887840282,"pool_token_amount":51105576309103202}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":51720484649706071,"pool_token_amount":51109181366121324}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":49967424957381648,"pool_token_amount":49403968941287606}],[88,{"sui_amount":48370271690057824,"pool_token_amount":47831423849303516}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":48356039897420181,"pool_token_amount":47830526313133117}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":46697442180664170,"pool_token_amount":46215168262146206}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":46694371007344132,"pool_token_amount":46218374375944796}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":46714166234290421,"pool_token_amount":46250861135939552}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":46709449036105335,"pool_token_amount":46252531926327891}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":46691403512566763,"pool_token_amount":46253584778809393}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":46682149496808985,"pool_token_amount":46270389143939415}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":46676869074466667,"pool_token_amount":46271800767876012}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":47214288054429489,"pool_token_amount":46882942590602223}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":47208604024039500,"pool_token_amount":46896666938780321}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":47274252063377412,"pool_token_amount":46968257093341508}],[53,{"sui_amount":46864340451483726,"pool_token_amount":46567362125753846}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":46783065306639684,"pool_token_amount":46511938436690961}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":46758661389410100,"pool_token_amount":46520006681332185}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":46141628218439155,"pool_token_amount":45912491876469371}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":45274933977311375,"pool_token_amount":45056372515774157}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":43525518579757756,"pool_token_amount":43339675055682412}],[37,{"sui_amount":43402614866097177,"pool_token_amount":43223280974055640}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":61496899062769681,"pool_token_amount":61296782483020231}],[31,{"sui_amount":61363094272544484,"pool_token_amount":61172787370322622}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":50313536902738581,"pool_token_amount":50173513831948263}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":41352630470643454,"pool_token_amount":41244518786446533}],[26,{"sui_amount":94872571850944512,"pool_token_amount":94751612564350375}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":88042403058745881,"pool_token_amount":88003390297898862}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000002273548}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000172313}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000147259}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000147259}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000147259}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000141726}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":80000000001754400,"pool_token_amount":80000000000140351}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Citadel.one":[[167,{"sui_amount":107406082183618986,"pool_token_amount":105129567882884570}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":107391618860056758,"pool_token_amount":105128787738772398}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":107320038369811515,"pool_token_amount":105125581100859966}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":107244042656128262,"pool_token_amount":105119573067406285}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[149,{"sui_amount":107153054092014711,"pool_token_amount":105126798222941140}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[146,{"sui_amount":107103914630372440,"pool_token_amount":105119678770872358}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":107054601088447237,"pool_token_amount":105112125984241578}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":107024831612910544,"pool_token_amount":105110122877981881}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":106979851021198371,"pool_token_amount":105106818125401518}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":106965577215117279,"pool_token_amount":105106439890856073}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":112422352596839808,"pool_token_amount":110541027965248960}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":116709056489353127,"pool_token_amount":114905528769455124}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":116694269987236747,"pool_token_amount":114905858879158388}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":116678179172202629,"pool_token_amount":114904899482915869}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":116576833119589336,"pool_token_amount":114909866352659871}],[112,{"sui_amount":116558594028718868,"pool_token_amount":114906882650251984}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":116401308064499356,"pool_token_amount":114901326300914456}],[100,{"sui_amount":124415995423891311,"pool_token_amount":122869345889362156}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":124298218354724220,"pool_token_amount":122862726179721904}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":138372681131037020,"pool_token_amount":136836900437570441}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":138165218675109114,"pool_token_amount":136830216703539781}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":138143821815058664,"pool_token_amount":136829555057972350}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":138105457604604295,"pool_token_amount":136831114041690491}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":138084758940797735,"pool_token_amount":136830386619147659}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":138001661368642461,"pool_token_amount":136827654384984771}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":137957031989117001,"pool_token_amount":136825084627885541}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":137913136870763346,"pool_token_amount":136823470730751843}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":137891060870463173,"pool_token_amount":136822526093851396}],[67,{"sui_amount":137868259029041346,"pool_token_amount":136820966704251900}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":137752811823759485,"pool_token_amount":136847560126604818}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":137731896982169368,"pool_token_amount":136846601287885984}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":137629864501462707,"pool_token_amount":136824622407835570}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":137565392791742818,"pool_token_amount":136820464179140355}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":135567963800160780,"pool_token_amount":134972106176280701}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":135413845837989264,"pool_token_amount":134958571255683046}],[37,{"sui_amount":135392350864566672,"pool_token_amount":134957488598172650}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":135347619677642545,"pool_token_amount":134955006554861147}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":119180157721560771,"pool_token_amount":118971376586994786}],[26,{"sui_amount":105134187484493701,"pool_token_amount":104994092822569334}],[25,{"sui_amount":80113555197234743,"pool_token_amount":80022944607766672}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":80072220866053486,"pool_token_amount":80016602158353330}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":80000000000000000,"pool_token_amount":80000000000000000}]],"Cogent Crypto":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":107207805969636319,"pool_token_amount":105015247359294744}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":107194424316230440,"pool_token_amount":105015247340614492}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":107113617093432410,"pool_token_amount":105015269934046747}],[157,{"sui_amount":107099860027799498,"pool_token_amount":105015269969364557}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":107072347882255574,"pool_token_amount":105015270318536719}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":107058590091578971,"pool_token_amount":105015270467076362}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":107044663439285133,"pool_token_amount":105015105569926655}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":106921613729711161,"pool_token_amount":105015180450721069}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":106895470215720781,"pool_token_amount":105016170297961646}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":106881893026007289,"pool_token_amount":105016170478698747}],[139,{"sui_amount":106851414698235033,"pool_token_amount":105012908964976826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":106781818704856353,"pool_token_amount":105011291802314570}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":106768232414246738,"pool_token_amount":105011292011510318}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":106687644282284084,"pool_token_amount":105012242777418926}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":106659614664244470,"pool_token_amount":105011389630339426}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":106646036823880220,"pool_token_amount":105011393649042301}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":106632466193037270,"pool_token_amount":105011403800516702}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":106592233103621247,"pool_token_amount":105011903576324070}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"sui_amount":106315911477872597,"pool_token_amount":105010781291881295}],[100,{"sui_amount":106300381952951661,"pool_token_amount":105010780335637485}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":106192344527397873,"pool_token_amount":105010749653772835}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":106131608158666886,"pool_token_amount":105010545312023228}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":106025314460746792,"pool_token_amount":105009488496473232}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":105988030798020476,"pool_token_amount":105002817299634764}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":105973121201740768,"pool_token_amount":105002866415841452}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":105943204635614329,"pool_token_amount":105002844368501292}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":105867514671167587,"pool_token_amount":105003206809088014}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":105820076124741795,"pool_token_amount":105003211792730189}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":105804197670344125,"pool_token_amount":105003211931587851}],[67,{"sui_amount":105787828067497427,"pool_token_amount":105002724452120633}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":105680983825024918,"pool_token_amount":105002650095807499}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":105560931901563905,"pool_token_amount":104988105625592095}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":105545649979922298,"pool_token_amount":104987975020501584}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":105530502973929311,"pool_token_amount":104987976114569684}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":105486551321663789,"pool_token_amount":104989462671472338}],[45,{"sui_amount":105442476767433184,"pool_token_amount":104990824180489232}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":105427333327648932,"pool_token_amount":104990828006620240}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":106354017750438671,"pool_token_amount":105990813326963723}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":106291394426795312,"pool_token_amount":105992020108702764}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":106274422562672731,"pool_token_amount":105991975631158148}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":106257450628970816,"pool_token_amount":105991934296959032}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":106241384456106218,"pool_token_amount":105992928673921661}],[31,{"sui_amount":106222766814646827,"pool_token_amount":105991347733069284}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":106156732660136850,"pool_token_amount":105995912379614449}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002203900,"pool_token_amount":80000000000000000}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001944400,"pool_token_amount":80000000000000000}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840600,"pool_token_amount":80000000000000000}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840600,"pool_token_amount":80000000000000000}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840600,"pool_token_amount":80000000000000000}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":80000000000000000,"pool_token_amount":80000000000000000}]],"Coinbase Cloud":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":88914549388206032,"pool_token_amount":87260808812530140}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[147,{"sui_amount":88814510828742909,"pool_token_amount":87248168714767575}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":88741004170319277,"pool_token_amount":87239822226145181}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":88706062613253975,"pool_token_amount":87237434118232869}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":88645202401443850,"pool_token_amount":87230895712583068}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":88633293439042599,"pool_token_amount":87229845284394832}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":88608840055103019,"pool_token_amount":87227122305512933}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":88579882483035166,"pool_token_amount":87219798847448114}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":88528204939460923,"pool_token_amount":87211332628981351}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":88513146704505513,"pool_token_amount":87207084016899067}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":88477122828887681,"pool_token_amount":87203349956971873}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":88465912329671950,"pool_token_amount":87202977483741604}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":88453875646049197,"pool_token_amount":87201790111371524}],[116,{"sui_amount":88432399549937142,"pool_token_amount":87201971549949104}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":88408130863671535,"pool_token_amount":87199399743615744}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":88385700422339490,"pool_token_amount":87198642480983868}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":88345052711918964,"pool_token_amount":87191796456751209}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":81202538526639672,"pool_token_amount":80175656596058555}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":81160970481248452,"pool_token_amount":80168714468738974}],[102,{"sui_amount":81148250744756966,"pool_token_amount":80167460720204198}],[99,{"sui_amount":81109600770097577,"pool_token_amount":80162959814647964}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":81073315456385888,"pool_token_amount":80160627291947101}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":81034496220253609,"pool_token_amount":80155659737302221}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":80911213280326687,"pool_token_amount":80142981999170688}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":80887257269063737,"pool_token_amount":80141081173918848}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":80739676248268495,"pool_token_amount":80117280120078120}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":80713868200887503,"pool_token_amount":80114701945680810}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":80552635876344416,"pool_token_amount":80076356462862348}],[56,{"sui_amount":80562770503738770,"pool_token_amount":80097374004013606}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":80551331018925673,"pool_token_amount":80096940635231529}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":80500858391837456,"pool_token_amount":80090816635191553}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":80444129029648963,"pool_token_amount":80111697527371606}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":80423911299137841,"pool_token_amount":80113778340557392}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":80374381512812731,"pool_token_amount":80109284997077117}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":80353064920585107,"pool_token_amount":80110840618833373}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":80310991122644322,"pool_token_amount":80105399807338553}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":80272463815920138,"pool_token_amount":80103816694961694}],[29,{"sui_amount":80240265605912857,"pool_token_amount":80084281137364170}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":120121085039220710,"pool_token_amount":120012858608996896}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":80107243722791027,"pool_token_amount":80053240670599132}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80021048452971536,"pool_token_amount":80002423622832443}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":80000000063519457,"pool_token_amount":80000000001270376}],[18,{"sui_amount":80000000061655557,"pool_token_amount":80000000001233099}],[17,{"sui_amount":80000000049632057,"pool_token_amount":80000000000992630}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002203900,"pool_token_amount":80000000000044070}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002152000,"pool_token_amount":80000000000043033}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001944400,"pool_token_amount":80000000000038882}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840600,"pool_token_amount":80000000000036807}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823300,"pool_token_amount":80000000000036462}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"sui_amount":0,"pool_token_amount":0}]],"ComingChat":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":28463675459547091,"pool_token_amount":27926896514497238}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":28452321064330866,"pool_token_amount":27925758693454604}],[157,{"sui_amount":28448511929708881,"pool_token_amount":27925384829118793}],[156,{"sui_amount":28444692724484111,"pool_token_amount":27925000740791627}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":28437044360653470,"pool_token_amount":27924223322007977}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":28432753118023934,"pool_token_amount":27923376217690560}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"sui_amount":28406336891847696,"pool_token_amount":27921006569400592}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":28398379301090006,"pool_token_amount":27919933748339392}],[143,{"sui_amount":28394574032967564,"pool_token_amount":27919565010417363}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":28364020493535311,"pool_token_amount":27916520493301352}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":28360218188438285,"pool_token_amount":27916156243399528}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":28341988836830724,"pool_token_amount":27915112461599480}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":28338179501177277,"pool_token_amount":27914744440325659}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":28318956515283324,"pool_token_amount":27912710996008318}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":28321966749244834,"pool_token_amount":27922444047325507}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":28318186635290983,"pool_token_amount":27922098968228146}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":28291067961775178,"pool_token_amount":27922415380153372}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":28283839004419633,"pool_token_amount":27922052362497950}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":28277688277587911,"pool_token_amount":27923509733753733}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":28264775035487188,"pool_token_amount":27922318877635167}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[101,{"sui_amount":28248105769705079,"pool_token_amount":27921500754936167}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":28187681550346928,"pool_token_amount":27922116234749930}],[84,{"sui_amount":28183863544039400,"pool_token_amount":27922104830836409}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":28170643427567791,"pool_token_amount":27920121767440030}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":28167575233537033,"pool_token_amount":27920952979743226}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[75,{"sui_amount":28158350477344736,"pool_token_amount":27930263756701998}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":28152023187744325,"pool_token_amount":27931528863636878}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":28138655183397713,"pool_token_amount":27930176029048547}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":28129467086288302,"pool_token_amount":27929000134825463}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":28117450693627330,"pool_token_amount":27928986214820019}],[64,{"sui_amount":28113166647153362,"pool_token_amount":27928506155400033}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":28109030604604224,"pool_token_amount":27928173329595839}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":28085166818159359,"pool_token_amount":27923145709454424}],[56,{"sui_amount":28077431531786683,"pool_token_amount":27923013532739940}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":28051964205069460,"pool_token_amount":27920367015285224}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":28047499031664099,"pool_token_amount":27919705862928915}],[47,{"sui_amount":28039239968323626,"pool_token_amount":27919051748586408}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":28023178378932909,"pool_token_amount":27918196709942772}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"sui_amount":28019197404062445,"pool_token_amount":27925592818304495}],[39,{"sui_amount":28014687516890535,"pool_token_amount":27924986210692435}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":28015881366411440,"pool_token_amount":27958747041936385}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":27948628780081799,"pool_token_amount":27909012002583526}],[25,{"sui_amount":20940517851008343,"pool_token_amount":20918348989513696}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":20007327815991001,"pool_token_amount":20002752805100917}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":20000000000475400,"pool_token_amount":20000000000009502}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":20000000000428400,"pool_token_amount":20000000000008567}],[1,{"sui_amount":20000000000000000,"pool_token_amount":20000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"ContributionDAO":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":164384858116336134,"pool_token_amount":160950273799944227}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":166870175485885992,"pool_token_amount":163446829962754937}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":166762664561014249,"pool_token_amount":163449622738997413}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"sui_amount":171656119979301668,"pool_token_amount":168357978272732954}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[146,{"sui_amount":171562619594415091,"pool_token_amount":168354906988604968}],[145,{"sui_amount":171539331063793423,"pool_token_amount":168354126208424638}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":171447044581001781,"pool_token_amount":168351795964222834}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":173817701384548551,"pool_token_amount":170769492956330425}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":173608983078978238,"pool_token_amount":170765940942128741}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":173534204843560009,"pool_token_amount":170781821340314889}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":173441362353087590,"pool_token_amount":170757591756228110}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":173417893293727589,"pool_token_amount":170756898578611854}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":173348450661717623,"pool_token_amount":170755766824265324}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":173230444758528969,"pool_token_amount":170751634255896785}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":173194954378111553,"pool_token_amount":170761538019387817}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":173019039971374319,"pool_token_amount":170767063800148781}],[102,{"sui_amount":172991860562966398,"pool_token_amount":170766259987883938}],[98,{"sui_amount":172886734929657115,"pool_token_amount":170765526691278326}],[97,{"sui_amount":172856411713878258,"pool_token_amount":170761056231547097}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":172803196611882425,"pool_token_amount":170759527399312257}],[94,{"sui_amount":172776618331402674,"pool_token_amount":170758765478366535}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":172724489731257692,"pool_token_amount":170757911534800446}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":172433801337669237,"pool_token_amount":170645900037110253}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":172323977431512483,"pool_token_amount":170636894076567931}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":172296949550218528,"pool_token_amount":170636001854383568}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":172245066371664352,"pool_token_amount":170634414760461696}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":172171324595306711,"pool_token_amount":170636027371623444}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":232014369045137219,"pool_token_amount":230411316005419493}],[61,{"sui_amount":231979679198360030,"pool_token_amount":230410483016542845}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":231944586430933419,"pool_token_amount":230409256275922183}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":231910117154478691,"pool_token_amount":230408638485991881}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":231665017888331586,"pool_token_amount":230402061444264705}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":231437647034198444,"pool_token_amount":230414268347426375}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":231367468786063792,"pool_token_amount":230412657393514363}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":231296993332003246,"pool_token_amount":230411296703256947}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":171216209892595208,"pool_token_amount":170637808821354472}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":171166936577431191,"pool_token_amount":170640973346031054}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":171112348207293251,"pool_token_amount":170642016038660056}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":170979843956704996,"pool_token_amount":170622403747245364}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":200924629241227068,"pool_token_amount":200578604616873409}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":150635151102499971,"pool_token_amount":150600252037017451}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":150399001193211591,"pool_token_amount":150399001003360554}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":150000001116171591,"pool_token_amount":150000001002323420}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":150000000004141300,"pool_token_amount":150000000000082818}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":150000000003652300,"pool_token_amount":150000000000073040}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":150000000003391500,"pool_token_amount":150000000000067827}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":150000000000000000,"pool_token_amount":150000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Cosmostation":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":62519184749121786,"pool_token_amount":61218068270816353}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":62512572583848752,"pool_token_amount":61219578600017324}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":62497185016804999,"pool_token_amount":61212687603700174}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":62283033259586780,"pool_token_amount":61060138298515259}],[151,{"sui_amount":62255343478020503,"pool_token_amount":61041178899081599}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":62126171317968074,"pool_token_amount":60963177780383500}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":62146128885575718,"pool_token_amount":61007084472527030}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":62135726053437039,"pool_token_amount":61004978091254334}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":62104214303974874,"pool_token_amount":60990405242455411}],[138,{"sui_amount":62102568925932558,"pool_token_amount":60996908281103934}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":62014071580228635,"pool_token_amount":60934342927864214}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":61987779166830548,"pool_token_amount":60932864695270223}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61909138043938543,"pool_token_amount":60879939343466564}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":61857524031022491,"pool_token_amount":60845443991475031}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":61823687784102379,"pool_token_amount":60820189869627136}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":61762381327179564,"pool_token_amount":60775938735086494}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":61699118417289499,"pool_token_amount":60778414425113034}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":61797730793895232,"pool_token_amount":60916352565956710}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":61736691419853675,"pool_token_amount":60873529798553550}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":61715277007317657,"pool_token_amount":60861464303559765}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":62640434102520000,"pool_token_amount":61896961428110144}],[94,{"sui_amount":62619420751975078,"pool_token_amount":61885625971831149}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":62592428321710388,"pool_token_amount":61868249035075106}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":62260242577486533,"pool_token_amount":61613151320741684}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":61802460577884500,"pool_token_amount":61196382829439248}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":61732371362429901,"pool_token_amount":61163674309617290}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":61647415656713789,"pool_token_amount":61125468611036690}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":61529044034002753,"pool_token_amount":61102346778432297}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":61558788162134750,"pool_token_amount":61204744041918738}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":61542839706022923,"pool_token_amount":61216292252554819}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":61522094502311688,"pool_token_amount":61213965541379444}],[48,{"sui_amount":60192333450565162,"pool_token_amount":59899937118440345}],[47,{"sui_amount":60186572054858265,"pool_token_amount":59903200695603127}],[45,{"sui_amount":60167518817932864,"pool_token_amount":59902231450720866}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":60137263281299123,"pool_token_amount":59890109384247530}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"sui_amount":45284812687764803,"pool_token_amount":45119375707648245}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":27770541328762752,"pool_token_amount":27695096560602518}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":27711390383903623,"pool_token_amount":27654362412042329}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":27549723497508046,"pool_token_amount":27497598504318174}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"sui_amount":20519078129426077,"pool_token_amount":20491507790020986}],[25,{"sui_amount":20062522493480638,"pool_token_amount":20039702184294168}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":20000000025396901,"pool_token_amount":20000000000507924}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"sui_amount":20000000012328401,"pool_token_amount":20000000000246557}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":20000000000539900,"pool_token_amount":20000000000010790}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":20000000000441000,"pool_token_amount":20000000000008817}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"sui_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Cypher Capital":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":27536875750219004,"pool_token_amount":27000961445357885}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":27523861787362059,"pool_token_amount":27000938673622838}],[161,{"sui_amount":27520620998211608,"pool_token_amount":27000941849579642}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":27514055893754746,"pool_token_amount":27000962690733229}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":27510718991636619,"pool_token_amount":27000963739218610}],[157,{"sui_amount":27507668405587819,"pool_token_amount":27001245910345879}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":27500993881894685,"pool_token_amount":27001247051502824}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"sui_amount":27477138071521897,"pool_token_amount":27000768583039884}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":27473787648484808,"pool_token_amount":27000758789679148}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":27464038440734772,"pool_token_amount":27000764747052716}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":27450750655027401,"pool_token_amount":27000480907624011}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":27447500217935035,"pool_token_amount":27000481196129132}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":27421371187519271,"pool_token_amount":27000376444620660}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":27414684228253039,"pool_token_amount":27000200452602857}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":27405605200240322,"pool_token_amount":27000869811614678}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":27402355668508966,"pool_token_amount":27000870890984506}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":27399248831950581,"pool_token_amount":27001012967319843}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":27392772073344406,"pool_token_amount":27001038005433548}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":27379773313354645,"pool_token_amount":27001038998488234}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":27364760957454912,"pool_token_amount":27002255993532020}],[112,{"sui_amount":27361095495736577,"pool_token_amount":27001845458399758}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":27347435582189446,"pool_token_amount":27001909985820610}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":27343754985326573,"pool_token_amount":27001941672664053}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":27328638824600972,"pool_token_amount":27001939032589038}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":27297890838209768,"pool_token_amount":27001047726338283}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":27290447847016634,"pool_token_amount":27001033658057914}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":27283147384655587,"pool_token_amount":27001042715463291}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":27261013342247848,"pool_token_amount":27000711952536311}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":27209994165049538,"pool_token_amount":27000839902279679}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":27202277096692741,"pool_token_amount":27000828156765046}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":27161550036004983,"pool_token_amount":26997333649082802}],[58,{"sui_amount":27157949148668486,"pool_token_amount":26997333692701212}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":27148032283830513,"pool_token_amount":26998215129700362}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":27140619975178699,"pool_token_amount":26998205838876158}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":27754389969509502,"pool_token_amount":27619970012298412}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":27105854365198213,"pool_token_amount":26996672715681242}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":27083320945488131,"pool_token_amount":26996349150830067}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":27071702202441299,"pool_token_amount":26996357109312650}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":27063121762563623,"pool_token_amount":26995982050313244}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":27047658154124729,"pool_token_amount":26997033952637780}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":27033489747759826,"pool_token_amount":26991994335921175}],[24,{"sui_amount":20020601696933047,"pool_token_amount":20002166498497671}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":20000000007017893,"pool_token_amount":20000000000140348}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":20000000000539900,"pool_token_amount":20000000000010790}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":20000000000527000,"pool_token_amount":20000000000010533}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":20000000000475400,"pool_token_amount":20000000000009502}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":20000000000428400,"pool_token_amount":20000000000008567}]],"DSRV":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":137963016637127908,"pool_token_amount":135102872277069316}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":137926385218785058,"pool_token_amount":135101299111054378}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":137858998325742264,"pool_token_amount":135104840939317018}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":137785716586466793,"pool_token_amount":135103752938575248}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":137766761407287419,"pool_token_amount":135102813451236595}],[151,{"sui_amount":137728947390623029,"pool_token_amount":135101217043191731}],[149,{"sui_amount":137691253746787644,"pool_token_amount":135099737965663351}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":137660896365330409,"pool_token_amount":135105091824639617}],[146,{"sui_amount":137642267461327884,"pool_token_amount":135104389106167030}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":137566741198477203,"pool_token_amount":135117997030388331}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":137517389092589614,"pool_token_amount":135122037273372253}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":137498896878136665,"pool_token_amount":135121399607071910}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":137432569458110987,"pool_token_amount":135126295829319420}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":137376652228232271,"pool_token_amount":135124099250780988}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":137347171984008825,"pool_token_amount":135147746610887320}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":137272650407492204,"pool_token_amount":135144554293457112}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":137198613374795340,"pool_token_amount":135141826156395258}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":137162269507748038,"pool_token_amount":135141116045708697}],[116,{"sui_amount":137144443633324228,"pool_token_amount":135141099423694860}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":137106447223271924,"pool_token_amount":135138947188009398}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":136990975962631765,"pool_token_amount":135134586925819454}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":136968036411680263,"pool_token_amount":135131701760965754}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":136946539095120905,"pool_token_amount":135130756786301341}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[98,{"sui_amount":136775235236496314,"pool_token_amount":135123984074261243}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":136691136657491831,"pool_token_amount":135120797032679676}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":136607454720849562,"pool_token_amount":135117022565421377}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":136566119811591526,"pool_token_amount":135115366206837655}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":136507237924502945,"pool_token_amount":135115922267389648}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":136438102501667544,"pool_token_amount":135125544402614939}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":136350833142315120,"pool_token_amount":135137151519719852}],[74,{"sui_amount":136310910122784457,"pool_token_amount":135136500478169887}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":136179730839072490,"pool_token_amount":135150658434617056}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":136132230454290463,"pool_token_amount":135145020831286122}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":136072080177740536,"pool_token_amount":135143985035282446}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":136028824998582310,"pool_token_amount":135140130048625117}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":135963976501082518,"pool_token_amount":135134529809135353}],[56,{"sui_amount":135942199940277584,"pool_token_amount":135132505730355926}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":135774570172051718,"pool_token_amount":135123798431862670}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":135670452708013156,"pool_token_amount":135099485959960333}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":135628428465983539,"pool_token_amount":135097480468167306}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"sui_amount":135607453813013951,"pool_token_amount":135096676345486694}],[40,{"sui_amount":135586405179843407,"pool_token_amount":135095797405103136}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":105427815284828088,"pool_token_amount":105177837112827071}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":105095578425649817,"pool_token_amount":104915865207057700}],[26,{"sui_amount":130084127584822057,"pool_token_amount":129916052005953240}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":26020681646333831,"pool_token_amount":26014579051656928}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":25000000019248364,"pool_token_amount":25000000000384956}],[16,{"sui_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":25000000000550800,"pool_token_amount":25000000000011015}]],"Dankuzone_w_DAIC":[[167,{"sui_amount":138080083416507696,"pool_token_amount":135167029376847076}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":138061837641894298,"pool_token_amount":135166314942586174}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":138043595774316778,"pool_token_amount":135165600570724121}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":138025350058828201,"pool_token_amount":135164885957495829}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":137879442942225766,"pool_token_amount":135161071809948553}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":137841752093305435,"pool_token_amount":135159593801987374}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":137785112423688894,"pool_token_amount":135157184920686186}],[149,{"sui_amount":137747418779853509,"pool_token_amount":135155705833628269}],[147,{"sui_amount":137710112499552665,"pool_token_amount":135154240620814965}],[146,{"sui_amount":137691453240475021,"pool_token_amount":135153508102373389}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":137544930218913138,"pool_token_amount":135149993801334068}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":137507765109717997,"pool_token_amount":135148532985656918}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":137452066183831292,"pool_token_amount":135146343921982824}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":137433394734349457,"pool_token_amount":135145609591802482}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":137377558006107984,"pool_token_amount":135143411126249089}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":137340414445455947,"pool_token_amount":135141960962194826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":137321819850859809,"pool_token_amount":135141199800307774}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":137229006908621420,"pool_token_amount":135137542449771813}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":137191096683909441,"pool_token_amount":135135292658800142}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":137172542673512735,"pool_token_amount":135134562566531638}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":140267602802911162,"pool_token_amount":138368372478377374}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":140246308144662790,"pool_token_amount":138367532224860138}],[106,{"sui_amount":140224350174350652,"pool_token_amount":138366566219151502}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":140202239569158620,"pool_token_amount":138365702044250767}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":140180185725225756,"pool_token_amount":138364831441564367}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[97,{"sui_amount":140026662576722300,"pool_token_amount":138358150354157529}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":139831339731203777,"pool_token_amount":138347710903317466}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":139767213443742347,"pool_token_amount":138344566569057947}],[84,{"sui_amount":139746047867667554,"pool_token_amount":138343605033759798}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":139724767393719270,"pool_token_amount":138342635008261689}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":139639847237545302,"pool_token_amount":138339269164782443}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":139545255194387667,"pool_token_amount":138345465069493390}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":139412753603668193,"pool_token_amount":138340202867525305}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":139340453392872240,"pool_token_amount":138352307878795715}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":139297464420419605,"pool_token_amount":138349667339099827}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":139126636410988266,"pool_token_amount":138340541714142121}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":139060235386822738,"pool_token_amount":138335311498139311}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"sui_amount":138982126920488357,"pool_token_amount":138338701109536182}],[46,{"sui_amount":138960899838722887,"pool_token_amount":138337855957141578}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":138875862764554333,"pool_token_amount":138334450835922404}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"sui_amount":138832346120875683,"pool_token_amount":138332236713545847}],[39,{"sui_amount":138818442967931451,"pool_token_amount":138339010134456434}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":83738601953438460,"pool_token_amount":83500301328716065}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":80420087405893087,"pool_token_amount":80256121167999926}],[29,{"sui_amount":80161854581012482,"pool_token_amount":80011597637622209}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019005353317487,"pool_token_amount":80000380998369127}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":80000000062001508,"pool_token_amount":80000000001240018}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Durian":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":112267558263135962,"pool_token_amount":110230936368613960}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":112223052049043288,"pool_token_amount":110226565964074639}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":112147889304559927,"pool_token_amount":110219181624430528}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"sui_amount":112025341842676628,"pool_token_amount":110207265934664426}],[149,{"sui_amount":112010002903850323,"pool_token_amount":110205756934143752}],[146,{"sui_amount":111963019072553158,"pool_token_amount":110199849530244235}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":111902415446230020,"pool_token_amount":110193883512725326}],[136,{"sui_amount":111811477203248373,"pool_token_amount":110184925799770217}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":111796324152728200,"pool_token_amount":110183432537771751}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":111781175338271632,"pool_token_amount":110181944044877418}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":111736479321134839,"pool_token_amount":110178228418045972}],[130,{"sui_amount":111721318211706225,"pool_token_amount":110176733449909262}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":111691179754320532,"pool_token_amount":110173761090014635}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":111676021886553934,"pool_token_amount":110172265895985840}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":111660968323272814,"pool_token_amount":110170779033589194}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":111645920333820480,"pool_token_amount":110169295215933111}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":111630869567627884,"pool_token_amount":110167810044976076}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[122,{"sui_amount":111600767370981176,"pool_token_amount":110164839096778408}],[121,{"sui_amount":111585718030759838,"pool_token_amount":110163353525803186}],[120,{"sui_amount":111570575482516635,"pool_token_amount":110161860363946524}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":111540285177472290,"pool_token_amount":110158869395202733}],[115,{"sui_amount":111494853657740427,"pool_token_amount":110154377426622797}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":111463978144692063,"pool_token_amount":110150802286329956}],[111,{"sui_amount":111433690465308719,"pool_token_amount":110147809017034600}],[110,{"sui_amount":111418540924322977,"pool_token_amount":110146311544228286}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[101,{"sui_amount":111262854764800132,"pool_token_amount":110130773163864372}],[100,{"sui_amount":111245533142896723,"pool_token_amount":110129059518019194}],[98,{"sui_amount":111210846873555936,"pool_token_amount":110125543495444120}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":111159227488275607,"pool_token_amount":110120426759873934}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[92,{"sui_amount":111108029005125132,"pool_token_amount":110115354947391209}],[91,{"sui_amount":111091128622996337,"pool_token_amount":110113680007841474}],[88,{"sui_amount":111040592186085280,"pool_token_amount":110108670143997350}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":110906463518233142,"pool_token_amount":110095820351163048}],[78,{"sui_amount":110873091255231928,"pool_token_amount":110092505506146723}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":110856407727769952,"pool_token_amount":110090847111845389}],[74,{"sui_amount":110806130373018823,"pool_token_amount":110085616571945580}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":110735555299407114,"pool_token_amount":110077912873537262}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[63,{"sui_amount":123167566926711444,"pool_token_amount":122559535783128935}],[60,{"sui_amount":123111367164326325,"pool_token_amount":122553480573901455}],[56,{"sui_amount":123037126207873879,"pool_token_amount":122546087720432536}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":122943324541879711,"pool_token_amount":122536748703684554}],[49,{"sui_amount":122905752993538340,"pool_token_amount":122532996540078638}],[48,{"sui_amount":122886968934813259,"pool_token_amount":122531123831150087}],[45,{"sui_amount":122830620970753970,"pool_token_amount":122525500987837353}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":122811837847620318,"pool_token_amount":122523625545853435}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[40,{"sui_amount":122738165301376243,"pool_token_amount":122518085489366982}],[39,{"sui_amount":122719047108522842,"pool_token_amount":122516176199742487}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":122680666455669859,"pool_token_amount":122512344209576959}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":122661126172852919,"pool_token_amount":122510392862215734}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":122619947322425958,"pool_token_amount":122506232213155640}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Everstake":[[167,{"sui_amount":142807814844400421,"pool_token_amount":139915388182180342}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":142755276649338752,"pool_token_amount":139914966400649257}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":142668308449215587,"pool_token_amount":139915395390638255}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":142646923007800151,"pool_token_amount":139911968057284587}],[157,{"sui_amount":142628927969922627,"pool_token_amount":139911866109265261}],[156,{"sui_amount":142612293886035551,"pool_token_amount":139913097806804180}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":142553129466176960,"pool_token_amount":139907712189942118}],[151,{"sui_amount":56044122752153279,"pool_token_amount":24261207903505724}],[150,{"sui_amount":142497353928904084,"pool_token_amount":139905652561190858}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"sui_amount":86799377164006941,"pool_token_amount":85263290878246503}],[145,{"sui_amount":86913965466182396,"pool_token_amount":85386480891838675}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":86891645334307783,"pool_token_amount":85385775249981104}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":86858612950253401,"pool_token_amount":85385143979313986}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":86847814094820369,"pool_token_amount":85385144734298588}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":86814010880531092,"pool_token_amount":85383796119505059}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":86989285207594538,"pool_token_amount":85694716411568756}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":86977543242634697,"pool_token_amount":85693790127055006}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":86931768006466329,"pool_token_amount":85691331250097953}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":86884548024335412,"pool_token_amount":85687709125545605}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":86835643548359176,"pool_token_amount":85682431841782889}],[109,{"sui_amount":86858160445957156,"pool_token_amount":85716599000094488}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":86815010731465766,"pool_token_amount":85710264988386857}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[103,{"sui_amount":86773929952778410,"pool_token_amount":85707097718944487}],[99,{"sui_amount":86718514545540289,"pool_token_amount":85701691549308646}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":86643199287062388,"pool_token_amount":85700317041390445}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":86630799747285777,"pool_token_amount":85700076354670299}],[91,{"sui_amount":86615534451865062,"pool_token_amount":85696972481870354}],[90,{"sui_amount":86597381657834345,"pool_token_amount":85690980801647459}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":86544027634107068,"pool_token_amount":85685991533340907}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":86430991017804854,"pool_token_amount":85585969727140681}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":86370404126001794,"pool_token_amount":85585697406562242}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":86356644537015932,"pool_token_amount":85583932870432048}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[75,{"sui_amount":86322790608735465,"pool_token_amount":85597821608625581}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":36122599071277852,"pool_token_amount":35850174350039561}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":36117875196316832,"pool_token_amount":35850661227931114}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":36057160086425352,"pool_token_amount":35835750307537514}],[57,{"sui_amount":36046229392550506,"pool_token_amount":35834845292752257}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":36033540217560529,"pool_token_amount":35837279833773449}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"sui_amount":35937688889289594,"pool_token_amount":35811986967819966}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":35910852347053993,"pool_token_amount":35806063668195359}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":35877912547779336,"pool_token_amount":35789838643085958}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":35865950143283234,"pool_token_amount":35783526668662324}],[31,{"sui_amount":35862889594629692,"pool_token_amount":35786085908081500}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":35875187600549083,"pool_token_amount":35803974279050581}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":35861744741958327,"pool_token_amount":35802112905141738}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":25000000031979264,"pool_token_amount":25000000000639572}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":25000000000691200,"pool_token_amount":25000000000013816}],[14,{"sui_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Figment":[[167,{"sui_amount":292743642775759795,"pool_token_amount":286983970506020159}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":291523528851287664,"pool_token_amount":285855783676031397}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":291444822731714201,"pool_token_amount":285846548652630199}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":291406029639003614,"pool_token_amount":285877286535784655}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":291325264865836623,"pool_token_amount":285866938319057748}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":290938382323267860,"pool_token_amount":285592204010232568}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":290817896775832045,"pool_token_amount":285578901407950349}],[148,{"sui_amount":283792402875372040,"pool_token_amount":278851178036127116}],[147,{"sui_amount":283752787109841267,"pool_token_amount":278846227777308756}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":283351212973998446,"pool_token_amount":278756435517782366}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":275114149409027680,"pool_token_amount":270850481360075857}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":285040150213521019,"pool_token_amount":280692170187570658}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":285001665349129436,"pool_token_amount":280688374201156796}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":283176416489789132,"pool_token_amount":278992489857477649}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":283108343933225978,"pool_token_amount":278959340778255276}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":282917168595728151,"pool_token_amount":278974341120296874}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":282878796128614259,"pool_token_amount":278970440103571712}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":271607209499381778,"pool_token_amount":267992531521566520}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":271570640782890514,"pool_token_amount":267989133698667147}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":271446068579788185,"pool_token_amount":267931606134779372}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":271409168172897213,"pool_token_amount":267927892801510410}],[109,{"sui_amount":271392679306863261,"pool_token_amount":267947976891255946}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":271344023847870244,"pool_token_amount":267936296423971220}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":207957982878284414,"pool_token_amount":205861336931255317}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":201735598303361325,"pool_token_amount":199918798669038221}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":201704228860793560,"pool_token_amount":199914809728174711}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":126665348941072051,"pool_token_amount":125576284188324766}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":126716705623580901,"pool_token_amount":125695177118723916}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":126664080936609335,"pool_token_amount":125714275263664706}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":125390481226779874,"pool_token_amount":124539861942466116}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":125351323341784029,"pool_token_amount":124535838077392571}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":135175605670953098,"pool_token_amount":134352237904087001}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":135140513307421238,"pool_token_amount":134335556161003829}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":135098025740606303,"pool_token_amount":134329710596287866}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":118803634776285189,"pool_token_amount":118192617498425390}],[53,{"sui_amount":118785430173449732,"pool_token_amount":118190729571815216}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":118767236950132408,"pool_token_amount":118188852267904324}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":117743497393932472,"pool_token_amount":117202212035851224}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":116725062411805344,"pool_token_amount":116204389183489566}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"sui_amount":97425390702465801,"pool_token_amount":97112421153483550}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":71988979532118606,"pool_token_amount":71864217406875960}],[29,{"sui_amount":71976178396788602,"pool_token_amount":71862731076251528}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":153275492884432024,"pool_token_amount":153239949469566931}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":150000000116171591,"pool_token_amount":150000000002323421}],[16,{"sui_amount":150000000053253526,"pool_token_amount":150000000001065062}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":150000000003652300,"pool_token_amount":150000000000073041}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069130}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":150000005003424100,"pool_token_amount":150000005000068478}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":150000005003391500,"pool_token_amount":150000005000067827}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":150000000000000000,"pool_token_amount":150000000000000000}]],"Forbole":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":27642822756141381,"pool_token_amount":27126156519265838}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":27624047329178017,"pool_token_amount":27124110091027145}],[151,{"sui_amount":27620338160797721,"pool_token_amount":27123745886583784}],[150,{"sui_amount":27616601147076411,"pool_token_amount":27123354156736969}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[148,{"sui_amount":27609182356984187,"pool_token_amount":27122625483172203}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":27594428492188599,"pool_token_amount":27121262411449704}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":27583295656833484,"pool_token_amount":27120168083713941}],[140,{"sui_amount":27579584060779168,"pool_token_amount":27119803155449955}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":27572155545207219,"pool_token_amount":27122361915210868}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":27564543863186190,"pool_token_amount":27121451105599050}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":27560830649349109,"pool_token_amount":27121085752615374}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":27553907668126423,"pool_token_amount":27120851770279555}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":27556977028396919,"pool_token_amount":27136960375176111}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":27553298333507867,"pool_token_amount":27136629566186357}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":27542513468714026,"pool_token_amount":27135612883551777}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":27511167000244482,"pool_token_amount":27130787406930810}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"sui_amount":27492111978575890,"pool_token_amount":27128461913238457}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":27488399839040130,"pool_token_amount":27128095609076314}],[109,{"sui_amount":27484296333707292,"pool_token_amount":27127710390235543}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":27486171238866479,"pool_token_amount":27133226187367375}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":27453679858301709,"pool_token_amount":27123847043322726}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":27407942968932371,"pool_token_amount":27119612254177374}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":27399852874618436,"pool_token_amount":27118810810788890}],[88,{"sui_amount":27395815242829627,"pool_token_amount":27118412988216372}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":27383724654869506,"pool_token_amount":27117218174585504}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":27375334554835290,"pool_token_amount":27116150773237697}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":27359581888419338,"pool_token_amount":27115032726579727}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":27358711295251988,"pool_token_amount":27121311958184803}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":27351211208748465,"pool_token_amount":27121015855141326}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":27338870474729039,"pool_token_amount":27119788629564554}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":27312196713693759,"pool_token_amount":27123796589421875}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":27308195656498562,"pool_token_amount":27123399243634706}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":27296122024637149,"pool_token_amount":27122137361330633}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":27222065431237231,"pool_token_amount":27052130393018720}],[57,{"sui_amount":27213830571377595,"pool_token_amount":27051103597167495}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":27208999209961929,"pool_token_amount":27049880818421886}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":27150118059221951,"pool_token_amount":27006053123200235}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"sui_amount":27129018932943452,"pool_token_amount":27003471593888027}],[45,{"sui_amount":27120694150354101,"pool_token_amount":27002552427204267}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":27112422316048740,"pool_token_amount":27001685777781687}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":27086790993747702,"pool_token_amount":27000356993575653}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":27082535860841283,"pool_token_amount":27000260342236597}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":27058841267455243,"pool_token_amount":26998801090726417}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":27046323328515804,"pool_token_amount":26999915133869243}],[26,{"sui_amount":20033267984099894,"pool_token_amount":20006437518766712}],[25,{"sui_amount":20028145911136436,"pool_token_amount":20005458321224873}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":20017852200211770,"pool_token_amount":20003997637414117}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":20004781250991001,"pool_token_amount":20000206822415692}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":20000000000475400,"pool_token_amount":20000000000009502}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Galaxy Digital":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":137919474941004479,"pool_token_amount":135027862106056252}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":137882923907542015,"pool_token_amount":135026370983865984}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":137788892509831649,"pool_token_amount":135020492605667663}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":137751226956119942,"pool_token_amount":135018850521330787}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":137693148386375584,"pool_token_amount":135032483501683058}],[151,{"sui_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":137504146050218934,"pool_token_amount":135022847841416883}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":137467238483144216,"pool_token_amount":135021587935866408}],[140,{"sui_amount":137448235517354948,"pool_token_amount":135020421751653344}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":137410786930262340,"pool_token_amount":135018654358533198}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":137354647613858667,"pool_token_amount":135016061526230850}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":137335212596626860,"pool_token_amount":135014477388800172}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":137056183745821594,"pool_token_amount":135003008641055967}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":136979490575177590,"pool_token_amount":134997637761992548}],[114,{"sui_amount":136958388064933198,"pool_token_amount":134994392619288367}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":136920959365007845,"pool_token_amount":134992612330300394}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":136884146692894480,"pool_token_amount":134991446043851660}],[109,{"sui_amount":136863485999169873,"pool_token_amount":134990600760585485}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":136820200633017719,"pool_token_amount":134987072595211790}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":136775676808803015,"pool_token_amount":134983808483637807}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":136754571231809844,"pool_token_amount":134983324323798159}],[100,{"sui_amount":136674211747637070,"pool_token_amount":134984964748139850}],[97,{"sui_amount":136626067092875576,"pool_token_amount":134997542544118728}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":136604950179177385,"pool_token_amount":134996699313575835}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":136578605884996768,"pool_token_amount":134990636488708488}],[94,{"sui_amount":136546888094715192,"pool_token_amount":134979268009693212}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":136525902032842776,"pool_token_amount":134978454440713915}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":136505169805124573,"pool_token_amount":134977679560799530}],[90,{"sui_amount":136463756148671222,"pool_token_amount":134976037563092790}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":136438151559776759,"pool_token_amount":134970335009884421}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":136309160237052333,"pool_token_amount":134960035788098974}],[82,{"sui_amount":136271641980070343,"pool_token_amount":134942354667655353}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":136228111640555639,"pool_token_amount":134938924654883215}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":136207635061061585,"pool_token_amount":134938113342811545}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":136144558357631838,"pool_token_amount":134933986954662946}],[75,{"sui_amount":136466109184104423,"pool_token_amount":135272291209185669}],[74,{"sui_amount":136438997268724325,"pool_token_amount":135264984187000428}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":136373377517051551,"pool_token_amount":135261279455711091}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":136811022226621543,"pool_token_amount":135757776596121699}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":136767477459046791,"pool_token_amount":135756276779978815}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"sui_amount":136644549050675177,"pool_token_amount":135753082816031755}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":136559433933295295,"pool_token_amount":135747277285928170}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"sui_amount":135904847494610289,"pool_token_amount":135393883200513826}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":105763339498424840,"pool_token_amount":105478989479366670}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":105726237551781905,"pool_token_amount":105476503345668666}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":105688200233411812,"pool_token_amount":105473050298482246}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078923191536673,"pool_token_amount":80005247106203323}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Gaucho":[[167,{"sui_amount":27526361136218989,"pool_token_amount":26994038145237773}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":27517339029170399,"pool_token_amount":26994745906659261}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":27513730517164046,"pool_token_amount":26994391908174855}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":27494344303301326,"pool_token_amount":26994752246283589}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"sui_amount":27463366649778599,"pool_token_amount":26997029694082003}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":27452466620726189,"pool_token_amount":26995904118792013}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":27428108850956138,"pool_token_amount":26997532979638656}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":27418908915533852,"pool_token_amount":26998079793450379}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":27404459008791858,"pool_token_amount":26996665167474833}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":27391980471588136,"pool_token_amount":26993985205535229}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":27388367710766295,"pool_token_amount":26993628291313997}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":27390585658103239,"pool_token_amount":27005428149678431}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":27354426969874864,"pool_token_amount":27001813548604032}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":27325703491140879,"pool_token_amount":26998155943239433}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":27317337374047619,"pool_token_amount":26997331089448439}],[99,{"sui_amount":27301897283427224,"pool_token_amount":26996803081238006}],[98,{"sui_amount":27297777914138532,"pool_token_amount":26996398426784022}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":27289390014911352,"pool_token_amount":26995318074925092}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":27285202390946649,"pool_token_amount":26994820974167471}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":27257428760427077,"pool_token_amount":26999191486490054}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":27253409462385471,"pool_token_amount":26998712432527932}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":27241391121089436,"pool_token_amount":26997285275771218}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":27229156997241884,"pool_token_amount":26995837216389126}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":27221243054819080,"pool_token_amount":26994976078692214}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":27213186924933140,"pool_token_amount":26993969669848666}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":27205070341751182,"pool_token_amount":26993000930717957}],[72,{"sui_amount":27202888391779627,"pool_token_amount":26994523785518684}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":27190550479867904,"pool_token_amount":26993444567070368}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":27184737948929214,"pool_token_amount":26995150115221609}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":27176068388927063,"pool_token_amount":26994115727572704}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":27172067605527914,"pool_token_amount":26993638847947062}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":27168957332397986,"pool_token_amount":26997625122484525}],[61,{"sui_amount":27164955291099788,"pool_token_amount":26997226547782272}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":27160953465200052,"pool_token_amount":26996828836091722}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":27112653177601147,"pool_token_amount":26992465209852314}],[45,{"sui_amount":27101538586374329,"pool_token_amount":26992452884229542}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":27089592147949644,"pool_token_amount":26991612424871262}],[41,{"sui_amount":27085884776131352,"pool_token_amount":26991606482358613}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"sui_amount":27082597079719365,"pool_token_amount":26992018628228272}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":27063191772577468,"pool_token_amount":26991645259036868}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":27055150195916347,"pool_token_amount":26991807663942133}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":27041573553594913,"pool_token_amount":26994743348070854}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":27036867706521641,"pool_token_amount":26994252914124742}],[24,{"sui_amount":20019242481249717,"pool_token_amount":20002312351963101}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":20004772935991001,"pool_token_amount":20000571853482870}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":20000000025396901,"pool_token_amount":20000000002539676}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":20000000000527000,"pool_token_amount":20000000000052693}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000441000,"pool_token_amount":20000000000044097}],[4,{"sui_amount":20000000000441000,"pool_token_amount":20000000000044097}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":20000000000428400,"pool_token_amount":20000000000042839}]],"H2O Nodes":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":27510777003913803,"pool_token_amount":26995000383438210}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":27494172229173946,"pool_token_amount":26994995816745830}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":27487496189921606,"pool_token_amount":26994995956687129}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":27483884809743696,"pool_token_amount":26994727867656870}],[148,{"sui_amount":27467805238473411,"pool_token_amount":26995329276548019}],[146,{"sui_amount":27461305038549391,"pool_token_amount":26995329610323116}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":27424571265840938,"pool_token_amount":26994379788946396}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":27421331176253903,"pool_token_amount":26994391174175311}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":27414466375677658,"pool_token_amount":26994036533760919}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":27404704556452605,"pool_token_amount":26994035892552765}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":27398206005630459,"pool_token_amount":26994044574357438}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":27394834806572048,"pool_token_amount":26993926326163981}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":27391537320103757,"pool_token_amount":26993880153107829}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":27375312064434312,"pool_token_amount":26993907931036430}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":27372062310401493,"pool_token_amount":26993907961507156}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":27368812611663877,"pool_token_amount":26993907940397229}],[116,{"sui_amount":27362313687465359,"pool_token_amount":26993907048777640}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":27359067549313505,"pool_token_amount":26993910060984330}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":27349309592114633,"pool_token_amount":26993900156118938}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":27335382442987823,"pool_token_amount":26993700830039650}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":27331655057309259,"pool_token_amount":26993686318894489}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":27324067647729662,"pool_token_amount":26993681034573353}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":27320230975845488,"pool_token_amount":26993606097502182}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"sui_amount":27308970076620561,"pool_token_amount":26993592000390155}],[99,{"sui_amount":27301625697339957,"pool_token_amount":26993676401422702}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":27275509136406350,"pool_token_amount":26993589296899374}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":27263350289186476,"pool_token_amount":26995973405572351}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":27243418147426284,"pool_token_amount":26994154718801895}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":27233191123406411,"pool_token_amount":26994939341432652}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":27206714979924658,"pool_token_amount":26993788264066668}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":27175572266624339,"pool_token_amount":26993458712542982}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":27157420374076683,"pool_token_amount":26993313158001845}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":27146050475160166,"pool_token_amount":26996329491435200}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":27142076228456426,"pool_token_amount":26995958435863162}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":27123249456097021,"pool_token_amount":26991957563722292}],[50,{"sui_amount":27120302918282739,"pool_token_amount":26992708230940279}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"sui_amount":27109322672932486,"pool_token_amount":26992830633733852}],[45,{"sui_amount":27101065881785060,"pool_token_amount":26991978870030775}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":27089913931250442,"pool_token_amount":26991929803709525}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":27068327488534391,"pool_token_amount":26992772771809520}],[35,{"sui_amount":27063894195705282,"pool_token_amount":26992341903812665}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":27050395123396914,"pool_token_amount":26991159369103250}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":27038083147476398,"pool_token_amount":26991255765256061}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":27034053793249757,"pool_token_amount":26991440755232235}],[27,{"sui_amount":27029515518592186,"pool_token_amount":26991406809668803}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":20000000000527000,"pool_token_amount":20000000000052693}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":20000000000449600,"pool_token_amount":20000000000044955}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":20000000000449600,"pool_token_amount":20000000000044955}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":20000000000449600,"pool_token_amount":20000000000044955}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":20000000000441000,"pool_token_amount":20000000000044097}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"HashQuark":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":27584339390695727,"pool_token_amount":27045526082924395}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":27577122065909678,"pool_token_amount":27044818405872704}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":27555295421496316,"pool_token_amount":27042696084489513}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":27529182221904269,"pool_token_amount":27039999786870388}],[148,{"sui_amount":27518070491058708,"pool_token_amount":27038922438198313}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":27514359942656420,"pool_token_amount":27038558747744807}],[145,{"sui_amount":27507034356508894,"pool_token_amount":27037838812869941}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":27470964197507322,"pool_token_amount":27034342704056893}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":27447387540228726,"pool_token_amount":27033551338016299}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":27423100453843110,"pool_token_amount":27032044725413751}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":27419489828976745,"pool_token_amount":27031688811342289}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":27405045324997703,"pool_token_amount":27030261876194760}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":27393635191949598,"pool_token_amount":27031827431230405}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":27378388134900034,"pool_token_amount":27030325277194999}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":27374262991324440,"pool_token_amount":27029918006762803}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":27365838601043554,"pool_token_amount":27029086099288717}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":27361659974184341,"pool_token_amount":27028673374479649}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":27353194008729705,"pool_token_amount":27027839695838602}],[97,{"sui_amount":27332353359224401,"pool_token_amount":27025780736528803}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":27311533296119395,"pool_token_amount":27023720623049603}],[91,{"sui_amount":27307480233285638,"pool_token_amount":27023322285442151}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":27282259477714264,"pool_token_amount":27019935783286764}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":27270235628391594,"pool_token_amount":27018741682208525}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":27262349888093996,"pool_token_amount":27018272633383940}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":27258342600759624,"pool_token_amount":27017874600348146}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":27254340024918160,"pool_token_amount":27017477873742996}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":27241977926897295,"pool_token_amount":27015933695698477}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":27233864243715337,"pool_token_amount":27015129005891963}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":27212519069856259,"pool_token_amount":27013008221130627}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":27171416736003391,"pool_token_amount":27008842508889411}],[57,{"sui_amount":27167391853389081,"pool_token_amount":27008420959531017}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":27159389258663801,"pool_token_amount":27007625349524305}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":27155272996969054,"pool_token_amount":27007212444826048}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":27141874516661961,"pool_token_amount":27004930201073228}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"sui_amount":27125418188666850,"pool_token_amount":27003285370754058}],[45,{"sui_amount":27117692534004072,"pool_token_amount":27002962599976241}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":27113527590475142,"pool_token_amount":27002500279921431}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":27078261796052896,"pool_token_amount":27001076037915242}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":27068917001028875,"pool_token_amount":26999938606429077}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":27058607333487426,"pool_token_amount":27003030163185747}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":27056244904866752,"pool_token_amount":27009824683347126}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":20000000025418301,"pool_token_amount":20000000000508352}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":20000000015327401,"pool_token_amount":20000000000306536}],[16,{"sui_amount":20000000007028393,"pool_token_amount":20000000000140558}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":20000000000485900,"pool_token_amount":20000000000009712}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":20000000000438600,"pool_token_amount":20000000000008771}],[1,{"sui_amount":20000000000000000,"pool_token_amount":20000000000000000}]],"HashedPotatoes":[[167,{"sui_amount":130557842427601670,"pool_token_amount":127774977072322661}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":130540599168053117,"pool_token_amount":127774470800426095}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":130490434738237381,"pool_token_amount":127774477951986871}],[161,{"sui_amount":130457540905298790,"pool_token_amount":127774999618288570}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":130241380268773155,"pool_token_amount":127697651789898346}],[148,{"sui_amount":130084818506381742,"pool_token_amount":127628413075113258}],[146,{"sui_amount":130049924409814482,"pool_token_amount":127627782950215028}],[145,{"sui_amount":130033664425228507,"pool_token_amount":127628548764085271}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":129980893530669239,"pool_token_amount":127626897630040787}],[141,{"sui_amount":129963838178414911,"pool_token_amount":127626869610727397}],[138,{"sui_amount":129913260504066092,"pool_token_amount":127627384635473391}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":129863761530074859,"pool_token_amount":127628993204915884}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":129846199034273535,"pool_token_amount":127628475396268885}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[130,{"sui_amount":129778135849353840,"pool_token_amount":127628575523769641}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":129760554579365501,"pool_token_amount":127628056821182031}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":129625587529387654,"pool_token_amount":127528834812488938}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[122,{"sui_amount":129537699835082291,"pool_token_amount":127525673520872115}],[121,{"sui_amount":129520078476024586,"pool_token_amount":127524996363106389}],[120,{"sui_amount":129502526828963194,"pool_token_amount":127524477924083613}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":129485480517095677,"pool_token_amount":127524458028006618}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":129467928478667331,"pool_token_amount":127523939441087435}],[117,{"sui_amount":129450379563205289,"pool_token_amount":127523420878280317}],[116,{"sui_amount":129434085473408630,"pool_token_amount":127524137858532092}],[114,{"sui_amount":129398857148361510,"pool_token_amount":127522972312046502}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[110,{"sui_amount":129333380314058782,"pool_token_amount":127525562034877835}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[100,{"sui_amount":129145095508118739,"pool_token_amount":127531487239712885}],[98,{"sui_amount":129104004817310348,"pool_token_amount":127529313875111511}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":129007618940952807,"pool_token_amount":127529414524941091}],[91,{"sui_amount":128968717638287702,"pool_token_amount":127528600070273964}],[88,{"sui_amount":128904295467414258,"pool_token_amount":127521125372399040}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":128884780022582452,"pool_token_amount":127520549215608296}],[85,{"sui_amount":128845777058247299,"pool_token_amount":127519322331517070}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":128640457961715592,"pool_token_amount":127521366486070054}],[72,{"sui_amount":128600170410012772,"pool_token_amount":127520222556593651}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[68,{"sui_amount":128525720351900896,"pool_token_amount":127525305528901313}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":128253143218349294,"pool_token_amount":127519479426653916}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":128171066650086595,"pool_token_amount":127513335737732617}],[49,{"sui_amount":128151571465152672,"pool_token_amount":127512816628775851}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[42,{"sui_amount":127223818889977427,"pool_token_amount":126721134170399022}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":127103711090611124,"pool_token_amount":126716636049287833}],[35,{"sui_amount":117092034728337755,"pool_token_amount":116754259532480528}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[30,{"sui_amount":116988867212019885,"pool_token_amount":116747758846326601}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"sui_amount":88478735265669778,"pool_token_amount":88359670681293343}],[25,{"sui_amount":88459954555207252,"pool_token_amount":88359014054772290}],[24,{"sui_amount":86676843435024461,"pool_token_amount":86596470812715472}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":83835661161998830,"pool_token_amount":83796871811254358}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":80000000001754400,"pool_token_amount":80000000000035087}],[1,{"sui_amount":80000000000000000,"pool_token_amount":80000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Imperator.co":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":35721802088453064,"pool_token_amount":35021896243074698}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":35717091400296320,"pool_token_amount":35021526771482918}],[161,{"sui_amount":35712485744143645,"pool_token_amount":35021165494148675}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":35688149062808508,"pool_token_amount":35018823217866004}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":35663826454004482,"pool_token_amount":35016675611831847}],[150,{"sui_amount":35659019831911417,"pool_token_amount":35016302640769673}],[149,{"sui_amount":35656152866872329,"pool_token_amount":35017835029267002}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":35646024696964571,"pool_token_amount":35016586564201296}],[145,{"sui_amount":35636540118280372,"pool_token_amount":35015885251108976}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":35630744136620430,"pool_token_amount":35023252194233938}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":35619844906704336,"pool_token_amount":35025421582077879}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":35599939217262857,"pool_token_amount":35022924850003715}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":35594385128715362,"pool_token_amount":35026091110862680}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":35570560563984412,"pool_token_amount":35024192804028554}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":35565886493955930,"pool_token_amount":35023864624863013}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":35543491740104567,"pool_token_amount":35023173599247169}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":35538667578358449,"pool_token_amount":35026968863676840}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":35530141956265225,"pool_token_amount":35027115058822499}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":35514151099599560,"pool_token_amount":35024447037869223}],[114,{"sui_amount":35509437956957944,"pool_token_amount":35024075185229755}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":35480785555379158,"pool_token_amount":35022637799040818}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":35458917027415867,"pool_token_amount":35021032739062247}],[101,{"sui_amount":35442489922156353,"pool_token_amount":35019737873706075}],[99,{"sui_amount":35431712349172407,"pool_token_amount":35018885887847740}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":35415728606820556,"pool_token_amount":35017792177789475}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":35361399912124527,"pool_token_amount":35012424052801463}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":35340127926374308,"pool_token_amount":35010536647216213}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":35323421325482242,"pool_token_amount":35008491026316986}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":35315194798961599,"pool_token_amount":35009868969597405}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":35285644961127017,"pool_token_amount":35010173001530498}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":35265071364752478,"pool_token_amount":35010053713520794}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":35242880347469237,"pool_token_amount":35012790769018021}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":35223203032261194,"pool_token_amount":35012746419621431}],[56,{"sui_amount":35212524374377810,"pool_token_amount":35011888946551286}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":35204534370774014,"pool_token_amount":35008824705870293}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":35178643396717086,"pool_token_amount":35007481498947437}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":35173294798197324,"pool_token_amount":35007042875620268}],[46,{"sui_amount":35165732752791722,"pool_token_amount":35014173058756113}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":35094243074800592,"pool_token_amount":35008794028196864}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":35087242259963465,"pool_token_amount":35007227025863986}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":35076061272097820,"pool_token_amount":35006989626794125}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"sui_amount":25046991626220558,"pool_token_amount":25014580852377278}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":25024577933511914,"pool_token_amount":25007293593432911}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":25000000019248364,"pool_token_amount":25000000000384956}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":25000000000572400,"pool_token_amount":25000000000011444}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":25000000000556200,"pool_token_amount":25000000000011122}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"InfStones":[[167,{"sui_amount":27585923008343310,"pool_token_amount":27048243974445277}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":27582313953676653,"pool_token_amount":27047890103028430}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":27567887968996165,"pool_token_amount":27046482311441912}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":27560684888657346,"pool_token_amount":27045784517946125}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":27542245610994133,"pool_token_amount":27044067430100644}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":27534304908944516,"pool_token_amount":27042826093103557}],[150,{"sui_amount":27523094674363220,"pool_token_amount":27041651826645344}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":27497065350079298,"pool_token_amount":27035590897013279}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":27475395863964137,"pool_token_amount":27033459682712452}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":27465549815580439,"pool_token_amount":27033375535497738}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":27457588555905088,"pool_token_amount":27031940716713989}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":27450157573019721,"pool_token_amount":27031029367815716}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":27439323942776406,"pool_token_amount":27029974981087125}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":27414052700987037,"pool_token_amount":27027498180512796}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":27410442076120672,"pool_token_amount":27027142208856486}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":27396110133858122,"pool_token_amount":27025826079693872}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":27389145709991175,"pool_token_amount":27025366152839520}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":27378347677208491,"pool_token_amount":27024330081747657}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":27374838712886973,"pool_token_amount":27024075099777728}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":27366835887606697,"pool_token_amount":27023307246746105}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":27362519746889691,"pool_token_amount":27022711310710498}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":27354089764623168,"pool_token_amount":27021873744960050}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":27345801537389407,"pool_token_amount":27021125988143623}],[99,{"sui_amount":27329272887906381,"pool_token_amount":27019521840625265}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":27312699641903439,"pool_token_amount":27017907191080417}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":27296219031074870,"pool_token_amount":27016283752228417}],[90,{"sui_amount":27292174250428405,"pool_token_amount":27015884314910346}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":27268350358397648,"pool_token_amount":27013845127480386}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":27264375033245508,"pool_token_amount":27013479310998602}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":27256718237080685,"pool_token_amount":27013038766739749}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":27252478792628987,"pool_token_amount":27012609692832604}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":27224408518954837,"pool_token_amount":27021186773553930}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":27142768749228686,"pool_token_amount":27013615985615512}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":27138646662868620,"pool_token_amount":27013196781201883}],[48,{"sui_amount":27134534657711255,"pool_token_amount":27012787936288320}],[45,{"sui_amount":27122239457980975,"pool_token_amount":27011600164260913}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":27113957196175031,"pool_token_amount":27010722885973152}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":27105758279645454,"pool_token_amount":27009929442176529}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"sui_amount":27101675906840736,"pool_token_amount":27009549590435460}],[39,{"sui_amount":27097561487443432,"pool_token_amount":27009137753217744}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":27093446367041789,"pool_token_amount":27008726686933403}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":27071668389919846,"pool_token_amount":27006785076817543}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":20000000025396901,"pool_token_amount":20000000000507924}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":20000000015774701,"pool_token_amount":20000000000315481}],[16,{"sui_amount":20000000007017893,"pool_token_amount":20000000000140348}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":20000000000445300,"pool_token_amount":20000000000008902}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":20000000000441000,"pool_token_amount":20000000000008817}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Juicy Stake":[[167,{"sui_amount":44298253330197315,"pool_token_amount":43409073870845232}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":44270752143795229,"pool_token_amount":43409073602080747}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":44252955510071905,"pool_token_amount":43407888770903965}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":44241768789992107,"pool_token_amount":43407888849001502}],[156,{"sui_amount":44236182904250937,"pool_token_amount":43407895807574124}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":44224802533338675,"pool_token_amount":43407889087045168}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":44213300949142295,"pool_token_amount":43407672980138513}],[150,{"sui_amount":44201884101697189,"pool_token_amount":43407630894546088}],[148,{"sui_amount":44190688991312816,"pool_token_amount":43407624347750799}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":44168058965715120,"pool_token_amount":43407396581373460}],[143,{"sui_amount":44162462245067219,"pool_token_amount":43407396573714025}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":44112062246122329,"pool_token_amount":43407397411683743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":44083884267620089,"pool_token_amount":43407235128422899}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":44055441498673269,"pool_token_amount":43406802411583027}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":44043711529093867,"pool_token_amount":43406278338827790}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":44004894193714422,"pool_token_amount":43406631291103983}],[114,{"sui_amount":43999289623265375,"pool_token_amount":43406622498300499}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[103,{"sui_amount":43932631932569954,"pool_token_amount":43406762093994583}],[102,{"sui_amount":43926177582336617,"pool_token_amount":43406761720731562}],[99,{"sui_amount":43906939435416152,"pool_token_amount":43406740804282871}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":43887972530546628,"pool_token_amount":43406732593018539}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":43852369720234434,"pool_token_amount":43407059386871873}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":43840724774462430,"pool_token_amount":43407071954171689}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":43834804601837643,"pool_token_amount":43407074747603031}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":43805352695436091,"pool_token_amount":43407066845288230}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":43787281212849481,"pool_token_amount":43406725528327826}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":43757343182008108,"pool_token_amount":43406139734873914}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":43696187824423912,"pool_token_amount":43406115243350595}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":43684649441635407,"pool_token_amount":43406311905060368}],[61,{"sui_amount":43679491095902386,"pool_token_amount":43407017432264449}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":43648937363981075,"pool_token_amount":43405812958332984}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":43585672078299269,"pool_token_amount":43407524900324861}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":43579433671385672,"pool_token_amount":43407421419211946}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":43566858008535219,"pool_token_amount":43407218810605913}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":43534937506792891,"pool_token_amount":43406500458933035}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":27055012063530254,"pool_token_amount":26995269015724549}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":27046582618768200,"pool_token_amount":26995044040031765}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":27042229197357008,"pool_token_amount":26994895519663056}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"sui_amount":20029513993995886,"pool_token_amount":20004501126099622}],[25,{"sui_amount":20024962137832010,"pool_token_amount":20003753756616914}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":20011406311485771,"pool_token_amount":20002620042905490}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":20000000015785201,"pool_token_amount":20000000000315691}],[16,{"sui_amount":20000000007028393,"pool_token_amount":20000000000140558}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":20000000000455800,"pool_token_amount":20000000000009112}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":20000000000442900,"pool_token_amount":20000000000008856}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":20000000000000000,"pool_token_amount":20000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"KiligLab":[[167,{"sui_amount":45891858260305156,"pool_token_amount":44978998755003397}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":45889008902946022,"pool_token_amount":44986995711280461}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":45882693580435177,"pool_token_amount":44986200130459935}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":45864360837934499,"pool_token_amount":44984405153987777}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":45858246003087478,"pool_token_amount":44983805402087669}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":45845615161714123,"pool_token_amount":44982566325314073}],[157,{"sui_amount":45839320076814572,"pool_token_amount":44981966382760110}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":45826682570037257,"pool_token_amount":44980719124777067}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[149,{"sui_amount":45798530157417132,"pool_token_amount":44986565295468654}],[145,{"sui_amount":45773795853794426,"pool_token_amount":44984174222095251}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":45748943140640406,"pool_token_amount":44981754404234857}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":45717763158014418,"pool_token_amount":44978634846467979}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":45720848517158409,"pool_token_amount":44987180523973928}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":45671049965011799,"pool_token_amount":44982279566331907}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":45646199912545629,"pool_token_amount":44979860881987182}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":45631874808670059,"pool_token_amount":44987812544853877}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":45625656371933204,"pool_token_amount":44987199477708071}],[117,{"sui_amount":45619439041636130,"pool_token_amount":44986586444481092}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":45594544327905006,"pool_token_amount":44984108876259851}],[112,{"sui_amount":45588325310813907,"pool_token_amount":44983494412449917}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":45575885986085031,"pool_token_amount":44982266020408023}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":45562046261705942,"pool_token_amount":44980887546800181}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":45533597725814349,"pool_token_amount":44978053506040356}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":45528165663263604,"pool_token_amount":44985478762630142}],[101,{"sui_amount":45521031911493030,"pool_token_amount":44984774780435579}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":45446948720988939,"pool_token_amount":44973887882232948}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":45415628578274036,"pool_token_amount":44980048098618786}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":45394926865699806,"pool_token_amount":44977997501706888}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":45360105208176796,"pool_token_amount":44974448001842490}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":45329264438044661,"pool_token_amount":44981460059082168}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":45307473711381475,"pool_token_amount":44979295608014878}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":45292804690352264,"pool_token_amount":44977839225093810}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":45254372959861889,"pool_token_amount":44983188761052699}],[58,{"sui_amount":45247472390515630,"pool_token_amount":44982493893171214}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":45206476910464549,"pool_token_amount":44978433099240215}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":45179238850656564,"pool_token_amount":44975714357443124}],[45,{"sui_amount":45158802354818683,"pool_token_amount":44973889411748608}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":45149010984015784,"pool_token_amount":44982770234936920}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":45106393278005786,"pool_token_amount":44978520876021449}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":45083649385109576,"pool_token_amount":44976292129358451}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":45068258196515068,"pool_token_amount":44974723340602668}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":45057522654885279,"pool_token_amount":44977993270604737}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":45049617420409517,"pool_token_amount":44977214034394033}],[26,{"sui_amount":25036109499423111,"pool_token_amount":25004589769410312}],[25,{"sui_amount":25030883517696156,"pool_token_amount":25004068740176551}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":25000000000691200,"pool_token_amount":25000000000013816}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":25000000000556200,"pool_token_amount":25000000000011122}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":25000000000550800,"pool_token_amount":25000000000011015}]],"Kiln":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":68092362944260716,"pool_token_amount":66744507887485992}],[165,{"sui_amount":68083342240313707,"pool_token_amount":66743623672785197}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":68084749784775352,"pool_token_amount":66769952661699251}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":68066716831307359,"pool_token_amount":66768184084167207}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":38061436208126394,"pool_token_amount":37339927039920280}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"sui_amount":38003974845759561,"pool_token_amount":37334090712704391}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":37987374400357540,"pool_token_amount":37331533162838468}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":37982154499274411,"pool_token_amount":37331020184131221}],[143,{"sui_amount":37976938973782594,"pool_token_amount":37330507572172712}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":37971724205310598,"pool_token_amount":37329994971295040}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":37943586498833499,"pool_token_amount":37334131722175332}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":37933784089975103,"pool_token_amount":37333641186278615}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":29925788356288799,"pool_token_amount":29459452116764855}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":39943721330147832,"pool_token_amount":39337301790329134}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":39938299839843535,"pool_token_amount":39336767168247251}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":39900471704410535,"pool_token_amount":39333125846965452}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":39895166483541688,"pool_token_amount":39332701375389752}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":39867165218258917,"pool_token_amount":39329118888224818}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":39852665007213907,"pool_token_amount":39334052474409869}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":39827972442425321,"pool_token_amount":39331213189292993}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":39821684814769959,"pool_token_amount":39330591379943740}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":39815417882011095,"pool_token_amount":39329973304731433}],[103,{"sui_amount":39827278127086468,"pool_token_amount":39347278476136704}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":38980281642335700,"pool_token_amount":38558897742072399}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":38956275670406692,"pool_token_amount":38556426444199514}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":34962444923840285,"pool_token_amount":34608290724224941}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":34944301701941623,"pool_token_amount":34613755770860622}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":36570386116772559,"pool_token_amount":36275224840498945}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":36564717881061061,"pool_token_amount":36274662591780693}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":36552592981990906,"pool_token_amount":36273152491334687}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":36529003260622861,"pool_token_amount":36270789338347867}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":36523112481209079,"pool_token_amount":36270203530802035}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":36602146132623738,"pool_token_amount":36368909038540045}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":36593111333518516,"pool_token_amount":36374842460118566}],[56,{"sui_amount":36568351190401405,"pool_token_amount":36365144176084912}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":35524197994233215,"pool_token_amount":35364883931745005}],[47,{"sui_amount":35518863676874555,"pool_token_amount":35364352892267574}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"sui_amount":35988430580944185,"pool_token_amount":35861341657942680}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":30965723835787095,"pool_token_amount":30877930252642800}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":30948966153639107,"pool_token_amount":30875186172977120}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":30943708820539110,"pool_token_amount":30874640702364577}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":29282809216264338,"pool_token_amount":29230727372647571}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"sui_amount":21760237236095525,"pool_token_amount":21736531128789764}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":20000000000527000,"pool_token_amount":20000000000010533}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":20000000000428400,"pool_token_amount":20000000000008567}],[0,{"sui_amount":0,"pool_token_amount":0}]],"KingSuper":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":35700011785373341,"pool_token_amount":35001990637668625}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":35679918180059372,"pool_token_amount":34999008837479320}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":35670295217276519,"pool_token_amount":34998159245806681}],[156,{"sui_amount":35665484099536562,"pool_token_amount":34997734403865260}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":35660659735710728,"pool_token_amount":34997296731403765}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":35614539377593803,"pool_token_amount":34999149959295867}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":35590666546683225,"pool_token_amount":34997038011982875}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":35585947773233470,"pool_token_amount":34996620405312062}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":35576364884927390,"pool_token_amount":34995646028481313}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":35552579811823822,"pool_token_amount":34993542706649068}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":35584320235156034,"pool_token_amount":35050347825019472}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":35579495989645478,"pool_token_amount":35049912986996972}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":35574680092477499,"pool_token_amount":35049486007213264}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":35565114914492874,"pool_token_amount":35048698249304797}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":35560403068840825,"pool_token_amount":35048282157148367}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":35555688936409735,"pool_token_amount":35047863994975958}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":35550974960074405,"pool_token_amount":35047445796210260}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":35497059120626255,"pool_token_amount":35038436839726964}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":35486220740709595,"pool_token_amount":35037478415435652}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":35480432623382144,"pool_token_amount":35036784369236054}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":35469279155843067,"pool_token_amount":35035796662704747}],[101,{"sui_amount":35458430472756772,"pool_token_amount":35034828551742043}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":35417951734650529,"pool_token_amount":35034287393707866}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":35412621894888169,"pool_token_amount":35033845608239350}],[91,{"sui_amount":35407326441305730,"pool_token_amount":35033426502517792}],[90,{"sui_amount":35402039449138008,"pool_token_amount":35033003459906483}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":35365821390969013,"pool_token_amount":35026413673105283}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":35321254869558539,"pool_token_amount":35021299167035107}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":35316418665245273,"pool_token_amount":35021370483027896}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":35300078515380193,"pool_token_amount":35020072182926538}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":35294515412572888,"pool_token_amount":35019625188680572}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":35289552361141034,"pool_token_amount":35019775431725579}],[69,{"sui_amount":35283991012969136,"pool_token_amount":35019332099095075}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":35255885092625066,"pool_token_amount":35011730396593624}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":35250550714761084,"pool_token_amount":35011306601698699}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":35244965971836230,"pool_token_amount":35010634415534648}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":35207736377920710,"pool_token_amount":35007778404207118}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":35191748022493328,"pool_token_amount":35006522044644930}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"sui_amount":35158698650613196,"pool_token_amount":35002938460320905}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":35129542246156355,"pool_token_amount":34998340191651267}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"sui_amount":35118630306539844,"pool_token_amount":34997350812738874}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":35096602900833656,"pool_token_amount":34995506340741075}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":35061377465698240,"pool_token_amount":34992818882254452}],[29,{"sui_amount":35055129975064124,"pool_token_amount":34992098773840095}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":25005936738205152,"pool_token_amount":25000164266835462}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Laine":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":27849627234575506,"pool_token_amount":27329538102523327}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":27846018479414373,"pool_token_amount":27329183965957895}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":27838600365871978,"pool_token_amount":27328455878549114}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":27827474141879584,"pool_token_amount":27327363512891423}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":27819764977139917,"pool_token_amount":27326349391322045}],[151,{"sui_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":27800031609628709,"pool_token_amount":27326642767473194}],[145,{"sui_amount":27792605640234784,"pool_token_amount":27325912770711633}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":27782582092804442,"pool_token_amount":27325911389800786}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":27786679166701418,"pool_token_amount":27333227290508963}],[140,{"sui_amount":27782967570647102,"pool_token_amount":27332862187388367}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":27771873656344363,"pool_token_amount":27331815289194064}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":27768157973877504,"pool_token_amount":27331449608016211}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":27753308840273646,"pool_token_amount":27329992274132020}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":27723625880896407,"pool_token_amount":27327096734806734}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":27715700671639335,"pool_token_amount":27325871881175947}],[120,{"sui_amount":27709188362207194,"pool_token_amount":27326038155469354}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":33514374482542776,"pool_token_amount":33055798842098896}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":33503567843795481,"pool_token_amount":33057158466890397}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":33499244436343006,"pool_token_amount":33056900007956366}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":33486183167549064,"pool_token_amount":33056035053656379}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":33482623431897005,"pool_token_amount":33056530731034440}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":33478084667698088,"pool_token_amount":33056061305009295}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":33470482686835669,"pool_token_amount":33057473013794943}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":33451584501243393,"pool_token_amount":33057144045139436}],[99,{"sui_amount":33428848021701014,"pool_token_amount":33057746087376733}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":33405469068265209,"pool_token_amount":33056973769373269}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":33400333657810561,"pool_token_amount":33056316925992262}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":33392131873000627,"pool_token_amount":33056845120418841}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":33381422421684720,"pool_token_amount":33059158412207548}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":33376486684742923,"pool_token_amount":33058571841329799}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":33367247814252812,"pool_token_amount":33058001791136097}],[84,{"sui_amount":33363533407801976,"pool_token_amount":33058591532147315}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":33351142269838022,"pool_token_amount":33059221162010250}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[75,{"sui_amount":33323845540249518,"pool_token_amount":33057967309149189}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":33316077782602017,"pool_token_amount":33058994288667370}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"sui_amount":33276925506416017,"pool_token_amount":33060910149139874}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":33244618925582827,"pool_token_amount":33059033057145344}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"sui_amount":27111810280705155,"pool_token_amount":26999998757379517}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":27099940107438272,"pool_token_amount":26998988072044059}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"sui_amount":27089007273884930,"pool_token_amount":26998912553792797}],[39,{"sui_amount":27085387548947100,"pool_token_amount":26998911826311862}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":27082290207787903,"pool_token_amount":26999433376534695}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":27077930796406896,"pool_token_amount":26998797913434555}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":27041066771050932,"pool_token_amount":26997876361028829}],[26,{"sui_amount":20034545124314116,"pool_token_amount":20009321562600132}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":20000000025396901,"pool_token_amount":20000000000507924}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":20000000015774701,"pool_token_amount":20000000000315481}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":20000000000475400,"pool_token_amount":20000000000009502}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":20000000000445300,"pool_token_amount":20000000000008902}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Latitude.sh":[[167,{"sui_amount":26509070831423817,"pool_token_amount":25989689838865610}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":26505662279770129,"pool_token_amount":25989355661548818}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":26498847955531754,"pool_token_amount":25988689262208225}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":26495359916392142,"pool_token_amount":25988276559299335}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":26491952184426506,"pool_token_amount":25987942307671872}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":26485135144942421,"pool_token_amount":25987269481517081}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":26484434320982063,"pool_token_amount":25989680720990836}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":26480755990558421,"pool_token_amount":25989169617217715}],[156,{"sui_amount":26473739470255868,"pool_token_amount":25988480948779087}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":26447982545543300,"pool_token_amount":25991099625080355}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":26427030850173270,"pool_token_amount":25989143865833310}],[140,{"sui_amount":26423519880903216,"pool_token_amount":25988798585981133}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":26420008335090361,"pool_token_amount":25988453208116423}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":26407020892273870,"pool_token_amount":25991234905142344}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":26392966336543077,"pool_token_amount":25989851328241447}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":26389450082018461,"pool_token_amount":25989505072783709}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":26361250419539814,"pool_token_amount":25992867373795923}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":26359866837697053,"pool_token_amount":25994618594609530}],[117,{"sui_amount":91735889242077333,"pool_token_amount":39881683429017994}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":26349970698786360,"pool_token_amount":25997321055826039}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":26331146925739238,"pool_token_amount":25998148715490680}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":26327244762873680,"pool_token_amount":25997763433703630}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[101,{"sui_amount":26309800324036249,"pool_token_amount":26001646086682463}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":26288035129314738,"pool_token_amount":26000960021254616}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":26279316363398754,"pool_token_amount":26002667360610815}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":26271460763759915,"pool_token_amount":26005176798501219}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":26267533324510600,"pool_token_amount":26004710282326290}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":26250380390803722,"pool_token_amount":26004760392810069}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":26251855854719124,"pool_token_amount":26013016210616327}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":26244427986293075,"pool_token_amount":26012546289351818}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":26231229252176981,"pool_token_amount":26006252780921124}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":26197127018320811,"pool_token_amount":26011225663451224}],[64,{"sui_amount":26189206787522249,"pool_token_amount":26010352986292317}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":26185317877081008,"pool_token_amount":26009890383662064}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":26166177079244200,"pool_token_amount":26011279808720983}],[56,{"sui_amount":26162291889630366,"pool_token_amount":26010820742008980}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":26147160159787446,"pool_token_amount":26009390766892407}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":26141174039987063,"pool_token_amount":26010246347065036}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":26137276228565123,"pool_token_amount":26009851354192931}],[48,{"sui_amount":26133437216266681,"pool_token_amount":26009515166476164}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":26132839292851846,"pool_token_amount":26029938211449149}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":26081111534099511,"pool_token_amount":26019382325951462}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":26072047980030809,"pool_token_amount":26018228276678392}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":26039577625617673,"pool_token_amount":25994222959179611}],[26,{"sui_amount":50072342562650958,"pool_token_amount":50007853545577582}],[25,{"sui_amount":50067275141967916,"pool_token_amount":50012290668024540}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":30038474872136477,"pool_token_amount":30017992831062200}],[22,{"sui_amount":30030681280478123,"pool_token_amount":30016716320129205}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":30009102717457676,"pool_token_amount":30002131759037633}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":30000000015600000,"pool_token_amount":30000000000311998}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":30000000000708500,"pool_token_amount":30000000000014169}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Luganodes":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":96329527998020117,"pool_token_amount":41644204951793117}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":56165165021692366,"pool_token_amount":24292548120612612}],[157,{"sui_amount":56133766379699994,"pool_token_amount":24281972251683936}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":56164461678878119,"pool_token_amount":24307275222852175}],[152,{"sui_amount":56087476777549264,"pool_token_amount":24276965327300506}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"sui_amount":60577452505114017,"pool_token_amount":26236842628119062}],[146,{"sui_amount":61028024757043826,"pool_token_amount":26435261896804474}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":60948493143585976,"pool_token_amount":26416896265984412}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":91751962059697911,"pool_token_amount":39883805121777235}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":91065346618394553,"pool_token_amount":39599820736424146}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":90853781868271072,"pool_token_amount":39531943192078969}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":90592941540681178,"pool_token_amount":39456929245771835}],[102,{"sui_amount":90550852084750085,"pool_token_amount":39444175030853695}],[101,{"sui_amount":90533676868699085,"pool_token_amount":39442243526737071}],[100,{"sui_amount":72314789716618414,"pool_token_amount":31509342874047423}],[99,{"sui_amount":72286345940688156,"pool_token_amount":31501355614297751}],[98,{"sui_amount":71544830309771065,"pool_token_amount":31182574757908908}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":71865033943422279,"pool_token_amount":31335208017305475}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":57225361915554973,"pool_token_amount":24962238505752810}],[91,{"sui_amount":57198594009202988,"pool_token_amount":24953968704899441}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":56134737346669942,"pool_token_amount":24509909200651398}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":56078491158587159,"pool_token_amount":24492000195313410}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":55903534227070337,"pool_token_amount":24435659206860652}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":54994200746248848,"pool_token_amount":24068706805022661}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":51750233583129534,"pool_token_amount":22665000810403999}],[62,{"sui_amount":51827902612488554,"pool_token_amount":22702134927584654}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":51704737391863522,"pool_token_amount":22657467429128359}],[58,{"sui_amount":51641004987674724,"pool_token_amount":22632610654026878}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":51701912027185925,"pool_token_amount":22671719669662475}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":50911749863394918,"pool_token_amount":22340389803748236}],[48,{"sui_amount":50877824927525009,"pool_token_amount":22328576079481569}],[47,{"sui_amount":50870138248218154,"pool_token_amount":22328275305306473}],[46,{"sui_amount":50862143481529370,"pool_token_amount":22327839403634026}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"sui_amount":50743565089263543,"pool_token_amount":22294347438376725}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":50711252482838312,"pool_token_amount":22293532425396754}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":30139769709059235,"pool_token_amount":13267207670651649}],[27,{"sui_amount":30127673471947111,"pool_token_amount":13264086030984455}],[26,{"sui_amount":80113503978686921,"pool_token_amount":80012028484843096}],[25,{"sui_amount":80095591658132118,"pool_token_amount":80009433428161240}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":80058393469495627,"pool_token_amount":80005382967023720}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":80000000063865408,"pool_token_amount":80000000001277295}],[18,{"sui_amount":80000000062001508,"pool_token_amount":80000000001240018}],[17,{"sui_amount":80000000049908508,"pool_token_amount":80000000000998159}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":80000000001754400,"pool_token_amount":80000000000035087}],[1,{"sui_amount":80000000000000000,"pool_token_amount":80000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"MIDL.dev":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":26514232620390599,"pool_token_amount":25996809920720965}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":26480352143627837,"pool_token_amount":25994120017629535}],[154,{"sui_amount":26477192639999892,"pool_token_amount":25994120073590468}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"sui_amount":26464579199632539,"pool_token_amount":25994144680646862}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":26449123513780896,"pool_token_amount":25994489649935088}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":26436826410566017,"pool_token_amount":25994833726627147}],[140,{"sui_amount":26433316443456150,"pool_token_amount":25994491210803470}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":26423823723192198,"pool_token_amount":25994491614978846}],[136,{"sui_amount":26420308888389368,"pool_token_amount":25994147570631742}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":26391766916318452,"pool_token_amount":25978515302287705}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":26385788139283380,"pool_token_amount":25978859912086283}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":26374016091909378,"pool_token_amount":25976619050037459}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":26370504060091888,"pool_token_amount":25976274867807975}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":26354662648784385,"pool_token_amount":25976245401412092}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":26352200252059464,"pool_token_amount":25976934148415455}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":26342018745661308,"pool_token_amount":25976245498705601}],[116,{"sui_amount":26338909714122390,"pool_token_amount":25976296228961696}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":26318375970249814,"pool_token_amount":25978216293027503}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":26296772473658692,"pool_token_amount":25978241938263774}],[102,{"sui_amount":26294322773535058,"pool_token_amount":25979423329565457}],[100,{"sui_amount":26286280910946865,"pool_token_amount":25978633580178512}],[99,{"sui_amount":26282270237614104,"pool_token_amount":25978239186527028}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":26268324026041109,"pool_token_amount":25978623898393372}],[94,{"sui_amount":26264361519067700,"pool_token_amount":25978233976142718}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":26253757508136959,"pool_token_amount":25981804209575796}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":26232198711789899,"pool_token_amount":25981421294997121}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":26230262517415663,"pool_token_amount":25982978146115750}],[82,{"sui_amount":26226366946939410,"pool_token_amount":25982594190959446}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":26218463912443682,"pool_token_amount":25981814202924227}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":26193472412256981,"pool_token_amount":25981454299808908}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":26189064620869205,"pool_token_amount":25984428848146025}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":26175155863343554,"pool_token_amount":25981653581630382}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":26164728530927334,"pool_token_amount":25978653634440603}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":26153771831154259,"pool_token_amount":25978407049933342}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":26139711324806961,"pool_token_amount":25978358605054394}],[57,{"sui_amount":26132695845126980,"pool_token_amount":25978348807157569}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":26119021156186849,"pool_token_amount":25978684953983421}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":26104862152283013,"pool_token_amount":25982024978345426}],[45,{"sui_amount":26092693289041643,"pool_token_amount":25980371592420231}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":26065279909004945,"pool_token_amount":25977990554869562}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":26058014445576270,"pool_token_amount":25978053553023385}],[35,{"sui_amount":26054221044565932,"pool_token_amount":25978063455607839}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":26036568438339148,"pool_token_amount":25976039682707869}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":26023895321856219,"pool_token_amount":25975288338923823}],[27,{"sui_amount":26020115879173464,"pool_token_amount":25975812086636136}],[26,{"sui_amount":50048539506516356,"pool_token_amount":49986060172559477}],[24,{"sui_amount":50026808049006233,"pool_token_amount":49983749030288053}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":30007112717457676,"pool_token_amount":30000711120006228}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":30000000015600000,"pool_token_amount":30000000001559998}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":30000000000708500,"pool_token_amount":30000000000070849}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Moonlet":[[167,{"sui_amount":27619444183493069,"pool_token_amount":27086509728333933}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":27612226847010355,"pool_token_amount":27085801878635158}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":27604657242034010,"pool_token_amount":27084748502772909}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":27593835873508812,"pool_token_amount":27083686621202142}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":27589923566390251,"pool_token_amount":27083123300816787}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":27578797295695347,"pool_token_amount":27082030978343047}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":27571379415098638,"pool_token_amount":27081302506906699}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":27530890444537155,"pool_token_amount":27077615469942829}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":27523468656319991,"pool_token_amount":27076885465325409}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":27498025288383735,"pool_token_amount":27074250321676021}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":27490697671896365,"pool_token_amount":27073528808420494}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":27472564592397012,"pool_token_amount":27071780922237812}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":27461728271751977,"pool_token_amount":27070712971063480}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":27439457893087746,"pool_token_amount":27067982773876777}],[116,{"sui_amount":27432300393206127,"pool_token_amount":27067332152359624}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":27424883133252288,"pool_token_amount":27066603387872280}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":27416356748813961,"pool_token_amount":27064780202568639}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":27412746306184240,"pool_token_amount":27064423787816616}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":27407641721883532,"pool_token_amount":27062593391075865}],[109,{"sui_amount":27403627487306777,"pool_token_amount":27062197020865944}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":27395281793973215,"pool_token_amount":27061188841104119}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":27391049501445544,"pool_token_amount":27060771666576177}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":27386741992993145,"pool_token_amount":27060346104876292}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[99,{"sui_amount":27361537031571394,"pool_token_amount":27057917390757922}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":27311791118763073,"pool_token_amount":27051994475292501}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":27302248434480744,"pool_token_amount":27049563007197822}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":27295333219105092,"pool_token_amount":27049698606252653}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":27258219026628049,"pool_token_amount":27023588560871286}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"sui_amount":27234553753979272,"pool_token_amount":27021078015569396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":27221979822183509,"pool_token_amount":27019567671006230}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":27217652893673630,"pool_token_amount":27018963208054331}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":27200097551506005,"pool_token_amount":27016682044564832}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":27191172600751597,"pool_token_amount":27015102441961639}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":27186532843556400,"pool_token_amount":27013990859797750}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":27155205566796152,"pool_token_amount":27010850041218327}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":27151095306275383,"pool_token_amount":27010361184951979}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":27125637330146448,"pool_token_amount":27006634733075128}],[46,{"sui_amount":27117195965593112,"pool_token_amount":27005435611450736}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":27104630979988421,"pool_token_amount":27003732772049434}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":27086552187395557,"pool_token_amount":27000142199815281}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":27073946992024168,"pool_token_amount":26998702580517597}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":27051219906579858,"pool_token_amount":26996397813319176}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":27041913523291543,"pool_token_amount":26995399821660808}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":20009796366205800,"pool_token_amount":20001104332934567}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":20000000025407401,"pool_token_amount":20000000000508134}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":20000000000550400,"pool_token_amount":20000000000011000}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":20000000000455800,"pool_token_amount":20000000000009112}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":20000000000000000,"pool_token_amount":20000000000000000}]],"MoveFuns DAO":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":27518268768068142,"pool_token_amount":26999617710408116}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":27508714562254921,"pool_token_amount":26999590822546842}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":27499515582435558,"pool_token_amount":26999996189831822}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":27488128364749654,"pool_token_amount":27001633907757788}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":27481923380677570,"pool_token_amount":27001951586934433}],[151,{"sui_amount":27475349532499500,"pool_token_amount":27001906918423424}],[150,{"sui_amount":27473093934582291,"pool_token_amount":27002898046732300}],[148,{"sui_amount":27466573625787492,"pool_token_amount":27002906237500766}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":27438028479567003,"pool_token_amount":27002965325572620}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":27427096358601922,"pool_token_amount":27001600280075282}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":27389845058292017,"pool_token_amount":27002496764326443}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":27401456226524207,"pool_token_amount":27039011550775723}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":27392193163799983,"pool_token_amount":27039276040229354}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":27375608638235519,"pool_token_amount":27039288921867017}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":27357231767264279,"pool_token_amount":27035925597068664}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":27354515342494757,"pool_token_amount":27036967574990327}],[101,{"sui_amount":27345978031137191,"pool_token_amount":27036123689044316}],[100,{"sui_amount":27341534416050110,"pool_token_amount":27035507293047596}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":27326417031108622,"pool_token_amount":27035112950987141}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":27313456342411246,"pool_token_amount":27033220647859966}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":27309887580971637,"pool_token_amount":27033229571355779}],[90,{"sui_amount":27300350479957154,"pool_token_amount":27030846322341405}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":27288587431510602,"pool_token_amount":27029760879299949}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":27256103863125643,"pool_token_amount":27015077405815932}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":27233281772286790,"pool_token_amount":27013607260362906}],[75,{"sui_amount":27229279635149302,"pool_token_amount":27013130004938607}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":27208500399034328,"pool_token_amount":27010660911122942}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":27204684202013482,"pool_token_amount":27010660724992396}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":27187606723060702,"pool_token_amount":27008852546491751}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":27122688268592902,"pool_token_amount":26997303485773077}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":27115450618710864,"pool_token_amount":26997303590982665}],[47,{"sui_amount":27111832195382323,"pool_token_amount":26997303678402433}],[46,{"sui_amount":27108215755461009,"pool_token_amount":26997305901399157}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":27108381879292568,"pool_token_amount":27004679539831335}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":27075202633409557,"pool_token_amount":27000684421622889}],[35,{"sui_amount":27070854956120513,"pool_token_amount":27000250258047668}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":27042883153583434,"pool_token_amount":26996459699710037}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"sui_amount":20027798726725227,"pool_token_amount":20003241077149585}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":20014499841797003,"pool_token_amount":20001593259539134}],[22,{"sui_amount":20009481366205800,"pool_token_amount":20000789467092587}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":20004670736001501,"pool_token_amount":20000096332687010}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"sui_amount":20000000012338901,"pool_token_amount":20000000000246767}],[16,{"sui_amount":20000000007028393,"pool_token_amount":20000000000140558}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":20000000000537500,"pool_token_amount":20000000000010743}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":20000000000442900,"pool_token_amount":20000000000008856}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":20000000000438600,"pool_token_amount":20000000000008771}]],"Mysten-1":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":163441637694686424,"pool_token_amount":159914291668660775}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":163410170306520965,"pool_token_amount":159904264921051253}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":164141481996889669,"pool_token_amount":160724143856099529}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":163983153492818341,"pool_token_amount":160719356462042189}],[150,{"sui_amount":163912427548567797,"pool_token_amount":160714471399808156}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[148,{"sui_amount":163866807778047169,"pool_token_amount":160712610831279196}],[147,{"sui_amount":60577452505114017,"pool_token_amount":26236842628119062}],[146,{"sui_amount":164929923243860802,"pool_token_amount":161798271815226197}],[145,{"sui_amount":164901778494163109,"pool_token_amount":161792090699449538}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":164673983426353488,"pool_token_amount":161632834139475884}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":169354902783913294,"pool_token_amount":166360125375880825}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":169302942652745502,"pool_token_amount":166331119610448187}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":169094848567256891,"pool_token_amount":166148711511411574}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":169545144984646063,"pool_token_amount":166635498787384885}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":169246559494164668,"pool_token_amount":166430302793148498}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":178402948011520949,"pool_token_amount":175482307768133892}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":178389415300718393,"pool_token_amount":175492209556221921}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":178354432811163014,"pool_token_amount":175504230367379829}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":178334228710128626,"pool_token_amount":175530803600049249}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":173082460279549347,"pool_token_amount":170453069607399956}],[116,{"sui_amount":173056613410042654,"pool_token_amount":170450264272264294}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":173027868260943970,"pool_token_amount":170444603421029452}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":173392282829452162,"pool_token_amount":170871876050064016}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":90592941540681178,"pool_token_amount":39456929245771835}],[98,{"sui_amount":187771620682393874,"pool_token_amount":185433113602606250}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":187588973788062152,"pool_token_amount":185392738130168630}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":187197078177877907,"pool_token_amount":185032994348771218}],[91,{"sui_amount":192196546811316816,"pool_token_amount":190003701222146148}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":202030095830817499,"pool_token_amount":199845089498626912}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":202004212759229481,"pool_token_amount":199849169816608936}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":201967921440062492,"pool_token_amount":199842807595652337}],[84,{"sui_amount":201914846972840740,"pool_token_amount":199819757130272081}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":201873981914708426,"pool_token_amount":199808892251715119}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":235800837567320740,"pool_token_amount":233611750365407312}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":237676123514431719,"pool_token_amount":235719612975419901}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":297161394210778727,"pool_token_amount":295133607223623561}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":287258659250032597,"pool_token_amount":285425306378627458}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":281210813905946301,"pool_token_amount":279749936124865325}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"sui_amount":285733287603883689,"pool_token_amount":284378754541901170}],[45,{"sui_amount":285646987364760834,"pool_token_amount":284377850517587650}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":285495001036961726,"pool_token_amount":284311543179653005}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"sui_amount":282132384042115288,"pool_token_amount":281090364834692140}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":278215092903384668,"pool_token_amount":277406161611102295}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":214170578353193153,"pool_token_amount":213583380013958676}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":214098463341352950,"pool_token_amount":213582588184990999}],[32,{"sui_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":212374814522779206,"pool_token_amount":212006446995715987}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":167545672555838728,"pool_token_amount":167428590588548431}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":160834576781276838,"pool_token_amount":160797255768874326}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"sui_amount":150000000093514591,"pool_token_amount":150000000001870281}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":150000000003391500,"pool_token_amount":150000000000067827}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Mysten-2":[[167,{"sui_amount":235295269344792213,"pool_token_amount":230211799601628356}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":235345963753313416,"pool_token_amount":230350805875585554}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":234539352823554067,"pool_token_amount":229864140658159581}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":234504216001323691,"pool_token_amount":229921869429502923}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":234081310004737504,"pool_token_amount":229903098968029510}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":234030175534512311,"pool_token_amount":229913790011766932}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":233976658966869444,"pool_token_amount":229891648360753048}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":233662800007398175,"pool_token_amount":229765790727899017}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":233072043605134557,"pool_token_amount":229245661128241453}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":233015355134655981,"pool_token_amount":229220178161876123}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":232992180849146309,"pool_token_amount":229227655656707688}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":232954271052359226,"pool_token_amount":229250924780744849}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":232709313102081588,"pool_token_amount":229252673157036902}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":232468577896923941,"pool_token_amount":229106713943180969}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":232335927127585332,"pool_token_amount":229104450488548038}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":232209069867521115,"pool_token_amount":229048344240681035}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":239921442285803733,"pool_token_amount":236802885789585849}],[101,{"sui_amount":239890940773046850,"pool_token_amount":236808957773467747}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":287883155287886818,"pool_token_amount":284621886837909687}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":287758648799390383,"pool_token_amount":284583152162775706}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":287716186189924424,"pool_token_amount":284583355320982318}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":287539145051501336,"pool_token_amount":284534569784782025}],[84,{"sui_amount":287466557291069394,"pool_token_amount":284504618940344444}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":284408438314731825,"pool_token_amount":281602589938178045}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":284364856189137730,"pool_token_amount":281602421558179693}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":284322904345084575,"pool_token_amount":281602349684947498}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":285520804788520990,"pool_token_amount":283216310398421781}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":285381403666917506,"pool_token_amount":283211024296396057}],[65,{"sui_amount":285399198463993527,"pool_token_amount":283273117985019265}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":349549100176942886,"pool_token_amount":347161272308717773}],[60,{"sui_amount":345616340111990250,"pool_token_amount":343306013011173866}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":345733180377014204,"pool_token_amount":343472732447453610}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":342307698245778626,"pool_token_amount":340321690461096847}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":346938410364761503,"pool_token_amount":345183316274927609}],[48,{"sui_amount":345043245119861702,"pool_token_amount":343350648477957146}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"sui_amount":279877599324715089,"pool_token_amount":278839536686300588}],[39,{"sui_amount":279830095829099375,"pool_token_amount":278834640957440291}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":251631468245564555,"pool_token_amount":250852300841119746}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":231274834478189325,"pool_token_amount":230672725365119502}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":230720770035458853,"pool_token_amount":230158419225046727}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":182209990407556936,"pool_token_amount":181857432728907603}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":210088091267080309,"pool_token_amount":209762013985346442}],[26,{"sui_amount":179996518744232507,"pool_token_amount":179752613704658111}],[25,{"sui_amount":174813370641117737,"pool_token_amount":174612636113053916}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":158929203575013686,"pool_token_amount":158892390962988946}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"sui_amount":150000000093514591,"pool_token_amount":150000000001870281}],[16,{"sui_amount":150000000053253526,"pool_token_amount":150000000001065061}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":150000000003391500,"pool_token_amount":150000000000067827}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Nelrann":[[167,{"sui_amount":137809475740112083,"pool_token_amount":134902865500725574}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":137755474118990725,"pool_token_amount":134901438645260737}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":137682669617442116,"pool_token_amount":134898535725769531}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":137586271661507734,"pool_token_amount":134927515975351668}],[151,{"sui_amount":137550185366324705,"pool_token_amount":134927425420659788}],[151,{"sui_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":137442580054316943,"pool_token_amount":134927369125372005}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":137424393464003589,"pool_token_amount":134927017159909143}],[143,{"sui_amount":137407083453186081,"pool_token_amount":134927511190178911}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":137389273169165757,"pool_token_amount":134927511436159513}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":137372091630130703,"pool_token_amount":134928132891352699}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":137303013402676284,"pool_token_amount":134930325198012728}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":137139393425748967,"pool_token_amount":134927241114890950}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":137103765210076558,"pool_token_amount":134927261866180950}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":137068106009936109,"pool_token_amount":134927241319123646}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[120,{"sui_amount":136996504638696571,"pool_token_amount":134926917029330686}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":91735889242077333,"pool_token_amount":39881683429017994}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":136851084712296860,"pool_token_amount":134924026874397138}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":136788319290461834,"pool_token_amount":134897273547460118}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[102,{"sui_amount":136634232195334493,"pool_token_amount":134905515298038361}],[98,{"sui_amount":136561331482629768,"pool_token_amount":134914015779595844}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":136509207044537178,"pool_token_amount":134902479207220197}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":136428753350821144,"pool_token_amount":134902454206345491}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":136369595062065220,"pool_token_amount":134902883979505110}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":136208938223207945,"pool_token_amount":134880705055319713}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":136188875991115703,"pool_token_amount":134880305361278396}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":136128595376228089,"pool_token_amount":134879735556080752}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[75,{"sui_amount":136071260855455308,"pool_token_amount":134881292454512521}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":136009697070013226,"pool_token_amount":134880236550997261}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":135934907037741075,"pool_token_amount":134888511732587753}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"sui_amount":135849165100807926,"pool_token_amount":134885156326837817}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":135828715252946961,"pool_token_amount":134884344137541344}],[62,{"sui_amount":135808266604519526,"pool_token_amount":134883531878501105}],[60,{"sui_amount":135766913073955110,"pool_token_amount":134881459837802974}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":135777064619514460,"pool_token_amount":134911051168073684}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":135630094942699792,"pool_token_amount":134902524200320601}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":135609417669094800,"pool_token_amount":134901696008066952}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":135547148135322010,"pool_token_amount":134898975450503458}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":135420689137211322,"pool_token_amount":134892117197055319}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"sui_amount":135399589629070786,"pool_token_amount":134891228107888076}],[39,{"sui_amount":135357419191352053,"pool_token_amount":134889797317261869}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":105240200061506850,"pool_token_amount":104975280522328447}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":105202587531743277,"pool_token_amount":104972069241288095}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"sui_amount":80112926935672189,"pool_token_amount":80006854498085866}],[25,{"sui_amount":80097951021108794,"pool_token_amount":80008042263818632}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":80059867024596320,"pool_token_amount":80004946598047977}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Neuler":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":35683373161066808,"pool_token_amount":34994490394891766}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":35672267369426080,"pool_token_amount":35004440087395369}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":35662645421288504,"pool_token_amount":35003591177397047}],[156,{"sui_amount":35657834303548547,"pool_token_amount":35003166178372890}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":35653022939722713,"pool_token_amount":35002741105396664}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":35643140313591205,"pool_token_amount":35001636639481344}],[148,{"sui_amount":35616028443376967,"pool_token_amount":34996511364336165}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":35547720116812150,"pool_token_amount":34988699062238596}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":35535543557153537,"pool_token_amount":34993710464371625}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":35526101185446392,"pool_token_amount":34992874464360129}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":35521386206958587,"pool_token_amount":34992459204630464}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":35511954695858077,"pool_token_amount":34991622956728828}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":35474237218626610,"pool_token_amount":34988277617412508}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":35454948161905751,"pool_token_amount":34990404576133077}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":35450234528602603,"pool_token_amount":34989939388397839}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":35428567898756390,"pool_token_amount":34996550040770823}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":35412209762026023,"pool_token_amount":34994936615958897}],[101,{"sui_amount":35406801156498106,"pool_token_amount":34994402125739546}],[98,{"sui_amount":35390641586080974,"pool_token_amount":34992804765192307}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":35363606589049442,"pool_token_amount":34990066918972081}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":35353004293942582,"pool_token_amount":34989018709370224}],[90,{"sui_amount":35347724302356720,"pool_token_amount":34988497930191400}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":35345593457950473,"pool_token_amount":34995791103041222}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":35324580332679633,"pool_token_amount":34993715558494393}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":35308895520533857,"pool_token_amount":34992168731029072}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":35304485902829944,"pool_token_amount":34992663164850980}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":35293920887039378,"pool_token_amount":34991518677611392}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":35273122848776624,"pool_token_amount":34994308470972340}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":35254180762654491,"pool_token_amount":34995368138808965}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":35229392268668234,"pool_token_amount":34999954563620544}],[62,{"sui_amount":35224165972598948,"pool_token_amount":34999432655312142}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":35208489779429513,"pool_token_amount":34997870357033418}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":35160566616344537,"pool_token_amount":34992788276251319}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"sui_amount":35139471965681958,"pool_token_amount":34990906972612088}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":35117850015223609,"pool_token_amount":34988498850001897}],[41,{"sui_amount":35118011976131997,"pool_token_amount":34993445031405187}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":35095530372939148,"pool_token_amount":34995706841903712}],[35,{"sui_amount":35089741957335133,"pool_token_amount":34995236939593584}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":35077824004748050,"pool_token_amount":34994162920308389}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":35059848655958500,"pool_token_amount":34992461931344813}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"sui_amount":25029747651635214,"pool_token_amount":25002933540529482}],[24,{"sui_amount":25024234138651360,"pool_token_amount":25002425051304324}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Node Guardians":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":27549387941524800,"pool_token_amount":27022168902974431}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":27534958060993249,"pool_token_amount":27020753278189034}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":27528562404322186,"pool_token_amount":27021028759532416}],[156,{"sui_amount":27521145942685438,"pool_token_amount":27020301627890637}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":27502393269837002,"pool_token_amount":27018277072292323}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"sui_amount":60577452505114017,"pool_token_amount":26236842628119062}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":27487384201233860,"pool_token_amount":27029437512367461}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":27483773976752721,"pool_token_amount":27029082504199523}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":27473017818851890,"pool_token_amount":27028093611184334}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[130,{"sui_amount":27443294401457074,"pool_token_amount":27027653577526474}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":27439677682536288,"pool_token_amount":27027297382731225}],[128,{"sui_amount":27435760170691895,"pool_token_amount":27026644689701177}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":27396876583154162,"pool_token_amount":27026765427911265}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":27393534458616104,"pool_token_amount":27026673739012322}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"sui_amount":27375841229763777,"pool_token_amount":27022039955103829}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":90853781868271072,"pool_token_amount":39531943192078969}],[109,{"sui_amount":27368010833734157,"pool_token_amount":27021085449334992}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":90592941540681178,"pool_token_amount":39456929245771835}],[101,{"sui_amount":27344673232891896,"pool_token_amount":27027785359588034}],[100,{"sui_amount":27340428613976078,"pool_token_amount":27027365814228845}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":27319758840997582,"pool_token_amount":27025371699939035}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":27292274202566033,"pool_token_amount":27016462199406908}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":27272058539074558,"pool_token_amount":27014425172001060}],[84,{"sui_amount":27268013768750358,"pool_token_amount":27013990644589804}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":27251647299013930,"pool_token_amount":27022983851297102}],[76,{"sui_amount":27247697707989586,"pool_token_amount":27022637559355919}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":27243695570852098,"pool_token_amount":27022239758749069}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":27234550890817198,"pool_token_amount":27020412184669709}],[72,{"sui_amount":27230325606596405,"pool_token_amount":27019991192633847}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":27203018872386779,"pool_token_amount":27015922457042914}],[66,{"sui_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":27177321828618797,"pool_token_amount":27012155776517138}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":27150824800568588,"pool_token_amount":27003712663946294}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":27146803902323669,"pool_token_amount":27003394547831230}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":27137876601793015,"pool_token_amount":27001878226260155}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":27129611648690434,"pool_token_amount":27001019101811283}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":27125539649886122,"pool_token_amount":27000649745530941}],[47,{"sui_amount":27128192260536855,"pool_token_amount":27010659490295903}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":27110083096013936,"pool_token_amount":27007366564048671}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"sui_amount":27097700804550695,"pool_token_amount":27006092670552160}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":27088545265609991,"pool_token_amount":27004346883417797}],[37,{"sui_amount":27084214722228984,"pool_token_amount":27003824557641794}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":27079960689322565,"pool_token_amount":27003390546323224}],[36,{"sui_amount":50711252482838312,"pool_token_amount":22293532425396754}],[35,{"sui_amount":27075459896187847,"pool_token_amount":27002892386111750}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":27053458881544443,"pool_token_amount":27001412982505045}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":27044019877524983,"pool_token_amount":27000394992326079}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":20004687736001501,"pool_token_amount":20000113328799675}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":20000000015785201,"pool_token_amount":20000000000315691}],[18,{"sui_amount":20000000015327401,"pool_token_amount":20000000000306536}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":20000000000000000,"pool_token_amount":20000000000000000}],[1,{"sui_amount":80000000000000000,"pool_token_amount":80000000000000000}]],"NodeReal":[[167,{"sui_amount":27585591028843761,"pool_token_amount":27040328439926695}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":27571176284491383,"pool_token_amount":27039074505752318}],[162,{"sui_amount":27567568097727115,"pool_token_amount":27038756035758663}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[155,{"sui_amount":27541813623509680,"pool_token_amount":27036484483614853}],[154,{"sui_amount":27538104502634295,"pool_token_amount":27036156787154624}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":27530336116290323,"pool_token_amount":27035157842308499}],[148,{"sui_amount":27515496144096493,"pool_token_amount":27033843343880050}],[146,{"sui_amount":27508072784951241,"pool_token_amount":27033186895188856}],[145,{"sui_amount":27504460004118292,"pool_token_amount":27032868266900692}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[141,{"sui_amount":27489859278277655,"pool_token_amount":27031437869883073}],[139,{"sui_amount":27482636119938358,"pool_token_amount":27030798587239713}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":27468954579293631,"pool_token_amount":27030283533121817}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":27443676592924012,"pool_token_amount":27028065732652181}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":27440062796214057,"pool_token_amount":27027745415958252}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":27428173578639094,"pool_token_amount":27025747625879371}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":27424561655640837,"pool_token_amount":27025427321840576}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":27403930097928189,"pool_token_amount":27024525894617856}],[115,{"sui_amount":27396736324057543,"pool_token_amount":27023910990946537}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":27348539350570812,"pool_token_amount":27014792269595554}],[98,{"sui_amount":27323650742759822,"pool_token_amount":27012360989953580}],[97,{"sui_amount":27319561207605778,"pool_token_amount":27011958486459938}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":27306986786882489,"pool_token_amount":27010715925176839}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[92,{"sui_amount":27298794557361848,"pool_token_amount":27009951309649590}],[91,{"sui_amount":27294738465080476,"pool_token_amount":27009549991425587}],[90,{"sui_amount":27290692681888124,"pool_token_amount":27009149639801859}],[89,{"sui_amount":27286662691234095,"pool_token_amount":27008762664888870}],[88,{"sui_amount":27281853089448708,"pool_token_amount":27007600704973231}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":27237607568412242,"pool_token_amount":27003321239506881}],[76,{"sui_amount":27233589183155670,"pool_token_amount":27002906805078700}],[74,{"sui_amount":27225905506340878,"pool_token_amount":27002429510230693}],[72,{"sui_amount":27217568972680382,"pool_token_amount":27001601749960647}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[56,{"sui_amount":27160338937569391,"pool_token_amount":27003884254199815}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":27143993833755693,"pool_token_amount":27002253476230554}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":27139880766421816,"pool_token_amount":27001843421951713}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":27127983734451455,"pool_token_amount":27001053215716512}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":27078145873887525,"pool_token_amount":26995870365207456}],[35,{"sui_amount":27073650077267865,"pool_token_amount":26995731871358726}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[32,{"sui_amount":27057051152845784,"pool_token_amount":26992549422006409}],[31,{"sui_amount":27052468438083302,"pool_token_amount":26992433544606514}],[30,{"sui_amount":27047657069735885,"pool_token_amount":26992089456532519}],[26,{"sui_amount":20030294000214454,"pool_token_amount":20003465129949797}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":20004782736001501,"pool_token_amount":20000208307076332}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":20000000025407401,"pool_token_amount":20000000000508134}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":20000000015327401,"pool_token_amount":20000000000306536}],[17,{"sui_amount":20000000012338901,"pool_token_amount":20000000000246767}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":20000000000550400,"pool_token_amount":20000000000011000}],[11,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":20000000000438600,"pool_token_amount":20000000000008771}],[1,{"sui_amount":20000000000000000,"pool_token_amount":20000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Nodeinfra":[[167,{"sui_amount":27559375009982524,"pool_token_amount":27023114402197502}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":27552658634595625,"pool_token_amount":27022897940985306}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":27541827892855012,"pool_token_amount":27021831150986408}],[161,{"sui_amount":27538223466255215,"pool_token_amount":27021477513390935}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"sui_amount":27499952346286940,"pool_token_amount":27019864215793870}],[147,{"sui_amount":27488324010012325,"pool_token_amount":27018281195208317}],[145,{"sui_amount":27481098742458786,"pool_token_amount":27017570980307168}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":27470267029924433,"pool_token_amount":27016508640675664}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":27444971752503706,"pool_token_amount":27014018250337281}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":27405217257893820,"pool_token_amount":27010100968621481}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":27401605334895563,"pool_token_amount":27009744983398486}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":27397992729941081,"pool_token_amount":27009388888707104}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":27387160451948090,"pool_token_amount":27008321796792989}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":27374229577048502,"pool_token_amount":27008387221949382}],[114,{"sui_amount":27372074317960531,"pool_token_amount":27009466574912603}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":27368463973174924,"pool_token_amount":27009110322803380}],[112,{"sui_amount":27364853511456589,"pool_token_amount":27008754016858665}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[99,{"sui_amount":27312192384929801,"pool_token_amount":27003609743056723}],[97,{"sui_amount":27303971457607102,"pool_token_amount":27002790654838127}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":27276918430073200,"pool_token_amount":26998074760871620}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":27244771784203299,"pool_token_amount":26994970395309954}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":27232525983674144,"pool_token_amount":26993754203843731}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":27216597319584065,"pool_token_amount":26992250105515658}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":27231218614348909,"pool_token_amount":27013896738148185}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":27226406364909206,"pool_token_amount":27012794381456514}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":27217858682553146,"pool_token_amount":27011856060338729}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":27209295462325109,"pool_token_amount":27011004372986002}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":27200595071792134,"pool_token_amount":27010111839363411}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":27196261083165880,"pool_token_amount":27009681475549188}],[65,{"sui_amount":27192193458597933,"pool_token_amount":27009515802248531}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":27184191618003587,"pool_token_amount":27008720941198055}],[62,{"sui_amount":27180890384218668,"pool_token_amount":27009018606613222}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":27164672641353807,"pool_token_amount":27007215958583499}],[56,{"sui_amount":27156670394056208,"pool_token_amount":27006420319506660}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":27139409271377577,"pool_token_amount":27003877955426277}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":27135297106402316,"pool_token_amount":27003468705193414}],[50,{"sui_amount":27131183220633612,"pool_token_amount":27003057523961289}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":27122958655832562,"pool_token_amount":27002238903711211}],[45,{"sui_amount":27110518995872938,"pool_token_amount":27000907096808987}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":27106410185946457,"pool_token_amount":27000500597770554}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":27098162824490009,"pool_token_amount":26999658406911454}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"sui_amount":27094046211665189,"pool_token_amount":26999244655137552}],[39,{"sui_amount":27085817385488932,"pool_token_amount":26998421010725256}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":27077549809816872,"pool_token_amount":26997665133070293}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":27073288781514822,"pool_token_amount":26997224139608307}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":27059716145380343,"pool_token_amount":26995860571105599}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":20014265190222270,"pool_token_amount":20001169522666181}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":20000000015785201,"pool_token_amount":20000000000315691}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":20000000000537500,"pool_token_amount":20000000000010743}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Nodes.Guru":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":117686475508155709,"pool_token_amount":115267653332480162}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":117656643199765360,"pool_token_amount":115267346005533449}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":117550084704028124,"pool_token_amount":115251559939281019}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":117516661399016828,"pool_token_amount":115248667501666984}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":117500473527274997,"pool_token_amount":115247736096791087}],[151,{"sui_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":117410802427652665,"pool_token_amount":115249285771423689}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":117349142247463573,"pool_token_amount":115247992529795738}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":117317412206804757,"pool_token_amount":115246399812528423}],[140,{"sui_amount":117301856163328200,"pool_token_amount":115245909655156547}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":117286772808572916,"pool_token_amount":115245886329679640}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":117253632441711201,"pool_token_amount":115242948570419268}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":117237602668038003,"pool_token_amount":115242008810254448}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":117175598050371743,"pool_token_amount":115240293631739007}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":117143655247642915,"pool_token_amount":115238521013833552}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":117020286231247571,"pool_token_amount":115235726223372769}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":116985207290927499,"pool_token_amount":115245663336677806}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":116953154793690429,"pool_token_amount":115243746510513481}],[117,{"sui_amount":91735889242077333,"pool_token_amount":39881683429017994}],[116,{"sui_amount":116932458914536402,"pool_token_amount":115238184464763911}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":116900205381062389,"pool_token_amount":115236066759408840}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":116880747276634126,"pool_token_amount":115231724492410761}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":116844176802042231,"pool_token_amount":115225352517402143}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":116632233851013511,"pool_token_amount":115064185738035447}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":116596598293215343,"pool_token_amount":115062693232664481}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[101,{"sui_amount":116494913854153055,"pool_token_amount":115048178987678343}],[100,{"sui_amount":116476254193041723,"pool_token_amount":115046756588766829}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":116283491639441372,"pool_token_amount":115040955437544956}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":116265380274235427,"pool_token_amount":115039595263943274}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":116230151378895092,"pool_token_amount":115037841004740780}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":116012752828188771,"pool_token_amount":115037419058933300}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":115975543242596101,"pool_token_amount":115035281147655888}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":115920158202729100,"pool_token_amount":115032720922193014}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":115825454813068252,"pool_token_amount":115024125395181210}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":115751037234786463,"pool_token_amount":115016069721124256}],[58,{"sui_amount":115731586493599066,"pool_token_amount":115013213496596261}],[56,{"sui_amount":115696865244205473,"pool_token_amount":115011760715269246}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":115642102941652648,"pool_token_amount":115007181058830997}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":115605746267406187,"pool_token_amount":115004311810474000}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"sui_amount":115557482963744787,"pool_token_amount":115023706236820249}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":115390985947892987,"pool_token_amount":114993716335627981}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":115372104392035525,"pool_token_amount":114991953477763892}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":105249387658034717,"pool_token_amount":105001597031879604}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":105217926973029570,"pool_token_amount":105004241458509192}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":105153641467935837,"pool_token_amount":104993485488856848}],[26,{"sui_amount":80136740927695027,"pool_token_amount":80030085351175731}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"OKXEarn":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":37117193911214958,"pool_token_amount":36299830180084796}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":37098382686898554,"pool_token_amount":36290952530626613}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":37031754388508754,"pool_token_amount":36230579699154831}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[155,{"sui_amount":36691054568484356,"pool_token_amount":35921660419390522}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":36576345684678609,"pool_token_amount":35823876116360722}],[149,{"sui_amount":36832295016221346,"pool_token_amount":36089454557074817}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"sui_amount":60577452505114017,"pool_token_amount":26236842628119062}],[146,{"sui_amount":90637706624017590,"pool_token_amount":88861972057746799}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":91676070457145353,"pool_token_amount":89916978933042797}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":91789575260950215,"pool_token_amount":90040528525810426}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":91611122856196091,"pool_token_amount":89926830106174626}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[130,{"sui_amount":84399389503615740,"pool_token_amount":82926336877593665}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":88429624215059049,"pool_token_amount":86910316373790238}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":85924627861814632,"pool_token_amount":84459821259626824}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":40316111875612709,"pool_token_amount":39672005793691464}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":35940779234887846,"pool_token_amount":35371606219528685}],[116,{"sui_amount":35757488763792394,"pool_token_amount":35200892209887660}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":35754278652756605,"pool_token_amount":35207430402317214}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"sui_amount":35594768774960408,"pool_token_amount":35064867171568191}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":35595148155654409,"pool_token_amount":35070085214521681}],[110,{"sui_amount":90853781868271072,"pool_token_amount":39531943192078969}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":35480073272708419,"pool_token_amount":34972372517598419}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":90592941540681178,"pool_token_amount":39456929245771835}],[98,{"sui_amount":55440878995164449,"pool_token_amount":54734071288674762}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":55390412076583163,"pool_token_amount":54718195271047831}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":55065932487194005,"pool_token_amount":54414254001141609}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":54661766092066391,"pool_token_amount":54072103591064238}],[84,{"sui_amount":54648129937144691,"pool_token_amount":54066762412997276}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":54497589434355597,"pool_token_amount":53925973275156457}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":51605282027759458,"pool_token_amount":51082107620827325}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":51525946690543514,"pool_token_amount":51027034863500756}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":51346918790211696,"pool_token_amount":50945528147776939}],[66,{"sui_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"sui_amount":51361125823217545,"pool_token_amount":50967787819336203}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":51310194421359715,"pool_token_amount":50932687984784971}],[62,{"sui_amount":51291452733995272,"pool_token_amount":50921806331572814}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":53018708705851792,"pool_token_amount":52653007471509033}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":53000418196113380,"pool_token_amount":52642790838179819}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":52595215625265200,"pool_token_amount":52264111366265692}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":50803671852930646,"pool_token_amount":50506838772844657}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":50794839710415273,"pool_token_amount":50505684919807707}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":50798309443646145,"pool_token_amount":50532030244679497}],[46,{"sui_amount":50728803960814566,"pool_token_amount":50486097658412292}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50695288561974175,"pool_token_amount":50468225808107331}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":50774239432369488,"pool_token_amount":50570329505007321}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50748846187197510,"pool_token_amount":50560758518909024}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":50711252482838312,"pool_token_amount":22293532425396754}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":58062561588327535,"pool_token_amount":57895943687738580}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"sui_amount":57394344276014225,"pool_token_amount":57258924062197410}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":41067072549102541,"pool_token_amount":41003176544476025}],[25,{"sui_amount":20055970167260436,"pool_token_amount":20032981601027745}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":20017447026216700,"pool_token_amount":20008283836979363}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":20000000015327401,"pool_token_amount":20000000000306536}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":80000000000000000,"pool_token_amount":80000000000000000}]],"ONBUFF":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":35755553804594748,"pool_token_amount":35058506559768683}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":35732104748007190,"pool_token_amount":35056207722090948}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":35703420042653996,"pool_token_amount":35053378534122671}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":35698608210309877,"pool_token_amount":35052906111223115}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":35693659766522488,"pool_token_amount":35052299677394546}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":35650437962733896,"pool_token_amount":35048057536358684}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":35631180322615120,"pool_token_amount":35046163964578203}],[139,{"sui_amount":35626464818431187,"pool_token_amount":35045700155888273}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":35617024018024647,"pool_token_amount":35044771409110378}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":35564823924500976,"pool_token_amount":35039636678408932}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":35545907540867349,"pool_token_amount":35037725555020282}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":35541192080609846,"pool_token_amount":35037260750035872}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":35536479210585666,"pool_token_amount":35036797033373768}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":35531765078154576,"pool_token_amount":35036332248346953}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":35508022834094689,"pool_token_amount":35034101605106797}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":35489036616644660,"pool_token_amount":35032112504521598}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":35456667239824997,"pool_token_amount":35028914358903676}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[100,{"sui_amount":35434962106102993,"pool_token_amount":35026770467439139}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":35402541559263863,"pool_token_amount":35023567342293244}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":35386653101222386,"pool_token_amount":35022014966751572}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":35370838432684529,"pool_token_amount":35020467479836343}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":35355091766686781,"pool_token_amount":35018945142654994}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":35307687972425842,"pool_token_amount":35014239126206605}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":35297235171560046,"pool_token_amount":35013198002032912}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":35280674163874326,"pool_token_amount":35011554103757100}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":35269253699062733,"pool_token_amount":35010150921555160}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":35241468944455550,"pool_token_amount":35007092342708018}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":35230722045938881,"pool_token_amount":35005756526602261}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":35220274863673652,"pool_token_amount":35004719309521732}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":35199268834721407,"pool_token_amount":35002630247915968}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":35193544977025882,"pool_token_amount":35001613573636610}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":35188210149451895,"pool_token_amount":35001083000273660}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":35177539104634003,"pool_token_amount":35000021498089074}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"sui_amount":35145529604766253,"pool_token_amount":34996833821675267}],[45,{"sui_amount":35140188457322417,"pool_token_amount":34996295693346909}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":35124175931939861,"pool_token_amount":34994692890405050}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":35102601029089741,"pool_token_amount":34992533945057383}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":35091569207686855,"pool_token_amount":34991438633860568}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":35074002871551300,"pool_token_amount":34989684085299975}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":35062198072594542,"pool_token_amount":34988496476530898}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":25023781437987629,"pool_token_amount":25001028637337304}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":25017968127371582,"pool_token_amount":25000625016830827}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":25000000032208364,"pool_token_amount":25000000000644154}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":25000000019248364,"pool_token_amount":25000000000384956}],[16,{"sui_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":25000000000572400,"pool_token_amount":25000000000011444}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":25000000000550800,"pool_token_amount":25000000000011015}],[0,{"sui_amount":0,"pool_token_amount":0}]],"ORBR":[[167,{"sui_amount":37166551428297432,"pool_token_amount":36739934539084584}],[166,{"sui_amount":37161124281809436,"pool_token_amount":36739231388310030}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[163,{"sui_amount":37146692020246402,"pool_token_amount":36738948107480308}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":37141899980829434,"pool_token_amount":36738871616396680}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[158,{"sui_amount":37720878501117888,"pool_token_amount":37331413550568382}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[153,{"sui_amount":37685935182468646,"pool_token_amount":37322104761579782}],[151,{"sui_amount":37675328242194215,"pool_token_amount":37321719046719007}],[150,{"sui_amount":37670115574450640,"pool_token_amount":37321615771401709}],[149,{"sui_amount":37664556083540768,"pool_token_amount":37321169417696832}],[145,{"sui_amount":45812999125957202,"pool_token_amount":45420581514136164}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":45807476144261182,"pool_token_amount":45421152941660251}],[142,{"sui_amount":45794040024733841,"pool_token_amount":45419914601184896}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":45787820113923876,"pool_token_amount":45419790237044066}],[140,{"sui_amount":45781600683066284,"pool_token_amount":45419666847698070}],[138,{"sui_amount":45749025891593452,"pool_token_amount":45399447203893213}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":45731266556735384,"pool_token_amount":45393936511308898}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":45724332183498229,"pool_token_amount":45393105659059332}],[134,{"sui_amount":45696910041769075,"pool_token_amount":45371935689696061}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":45671314415343845,"pool_token_amount":45370747214168143}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":47661002606006315,"pool_token_amount":47360232370765032}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":47632295104678364,"pool_token_amount":47338339005366235}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[125,{"sui_amount":46869983151948425,"pool_token_amount":46593044471280248}],[124,{"sui_amount":46863660829866980,"pool_token_amount":46592917797286589}],[123,{"sui_amount":46857239534986850,"pool_token_amount":46592692260065743}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":46850917476697248,"pool_token_amount":46592566532268605}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[117,{"sui_amount":46819024420911861,"pool_token_amount":46591933983830437}],[116,{"sui_amount":46812606798686281,"pool_token_amount":46591806253556240}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":44806489574726589,"pool_token_amount":44601117865325630}],[112,{"sui_amount":44788225292321188,"pool_token_amount":44600840122651124}],[111,{"sui_amount":44782192609546458,"pool_token_amount":44600802947305149}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":44762256747498687,"pool_token_amount":44600198035195350}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":44755516019574611,"pool_token_amount":44600122484177976}],[105,{"sui_amount":44741335522148600,"pool_token_amount":44599742721578875}],[104,{"sui_amount":36607405114830822,"pool_token_amount":36497225126432413}],[103,{"sui_amount":36601556355737172,"pool_token_amount":36497079187257996}],[102,{"sui_amount":36595773574119664,"pool_token_amount":36496964427572255}],[101,{"sui_amount":36590019738652305,"pool_token_amount":36496849658499637}],[98,{"sui_amount":36572825277692958,"pool_token_amount":36496503805283449}],[97,{"sui_amount":36567142570956670,"pool_token_amount":36496390386792727}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":36561586390033658,"pool_token_amount":36496284140778387}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":36548594108821223,"pool_token_amount":36494166762680151}],[93,{"sui_amount":36542947094847127,"pool_token_amount":36494053011129644}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":36537302453762035,"pool_token_amount":36493942227904212}],[90,{"sui_amount":36516247849461691,"pool_token_amount":36483927056717866}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":36510632139783770,"pool_token_amount":36483814841397702}],[88,{"sui_amount":36505020512493374,"pool_token_amount":36483701711530543}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":30015169822670723,"pool_token_amount":30002035795725712}],[86,{"sui_amount":30010636393852955,"pool_token_amount":30001898147572120}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":30005571973828314,"pool_token_amount":30001208863739583}],[84,{"sui_amount":0,"pool_token_amount":0}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}]],"Omnistake":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":28609683756336419,"pool_token_amount":28004743583313009}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":28605971862184793,"pool_token_amount":28004632112000689}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":28586456680186872,"pool_token_amount":28003227799768482}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"sui_amount":28549792300337147,"pool_token_amount":27999885573763917}],[149,{"sui_amount":28549360574739794,"pool_token_amount":28003086801899093}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":28554577447329977,"pool_token_amount":28026346905253312}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":28530333875668853,"pool_token_amount":28024328434166752}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":28508154519694028,"pool_token_amount":28024351831519103}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":28496520385442474,"pool_token_amount":28023831312883033}],[128,{"sui_amount":28491899208860911,"pool_token_amount":28022928303406095}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":28489459674176497,"pool_token_amount":28024168354951369}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":28443394266123413,"pool_token_amount":27997041978155747}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":28433451936347332,"pool_token_amount":27994534759066199}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":37075407573613345,"pool_token_amount":36528644943698378}],[114,{"sui_amount":37073327634173446,"pool_token_amount":36531483751777509}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":37053210453244984,"pool_token_amount":36531025831543706}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":37036806136951066,"pool_token_amount":36530846805863449}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":37013423129748596,"pool_token_amount":36535924435312521}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":47027926800044093,"pool_token_amount":46465622639475634}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":47020780522216210,"pool_token_amount":46465465929213536}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":47006421112943850,"pool_token_amount":46465182109476554}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":46992636222638200,"pool_token_amount":46465542858922888}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":43449944565865205,"pool_token_amount":43001178945336799}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":43412193445454598,"pool_token_amount":42989290990401509}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":46594225658605383,"pool_token_amount":46168267731461459}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":46580846147807644,"pool_token_amount":46168607781239828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":46559160099871554,"pool_token_amount":46168165202265338}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":46536773040504645,"pool_token_amount":46167680526758754}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":46468540072514688,"pool_token_amount":46135751569220313}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":46454002294426730,"pool_token_amount":46134942830072989}],[61,{"sui_amount":41377742452410679,"pool_token_amount":41099605675352496}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":31322896198533209,"pool_token_amount":31166979922328649}],[45,{"sui_amount":31304210743706198,"pool_token_amount":31166593736249823}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":31289938083883902,"pool_token_amount":31165555568573313}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"sui_amount":36218916656993845,"pool_token_amount":36086749399634529}],[39,{"sui_amount":36213437307298100,"pool_token_amount":36086824903145392}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":27076151112747869,"pool_token_amount":26993934984689386}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":27051774894397587,"pool_token_amount":26991796188445484}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":27047205226050170,"pool_token_amount":26991693263781969}],[29,{"sui_amount":27043237089605684,"pool_token_amount":26992302322216005}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"sui_amount":20027567552081893,"pool_token_amount":20004880247703561}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":20011379893195300,"pool_token_amount":20002219509646472}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"sui_amount":20000000012328401,"pool_token_amount":20000000000246557}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":20000000000539900,"pool_token_amount":20000000000010790}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":20000000000527000,"pool_token_amount":20000000000010533}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":20000000000475400,"pool_token_amount":20000000000009502}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"sui_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":20000000000000000,"pool_token_amount":20000000000000000}]],"Overclock":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":142999389579770529,"pool_token_amount":140049918905452751}],[161,{"sui_amount":142980566463966982,"pool_token_amount":140049181510264273}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":142961667744315645,"pool_token_amount":140048391222678431}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":142848738647059522,"pool_token_amount":140047493504963810}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":142794821295851077,"pool_token_amount":140049548137401985}],[150,{"sui_amount":142775395358253005,"pool_token_amount":140048806116149086}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":142515253062174650,"pool_token_amount":140048083984265495}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":142495986620258156,"pool_token_amount":140047327623070507}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":142443539037406140,"pool_token_amount":140050330445713498}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":142386592048976881,"pool_token_amount":140048937069548647}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":142334484685174936,"pool_token_amount":140052289146787502}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":142315220862856152,"pool_token_amount":140051529909445646}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":142273814138357506,"pool_token_amount":140047180635217814}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":142104623766623584,"pool_token_amount":140044415934398182}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":142072334007002080,"pool_token_amount":140049029951615373}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":142015250628736030,"pool_token_amount":140049471809885579}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":141993817748324883,"pool_token_amount":140048600824923372}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":141907135236627103,"pool_token_amount":140046761905445397}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[99,{"sui_amount":141801390854424873,"pool_token_amount":140047257919027394}],[98,{"sui_amount":141781153913330901,"pool_token_amount":140048117059380185}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":141700499569270507,"pool_token_amount":140051344805212227}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":141682706874274208,"pool_token_amount":140054438142231380}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":141641258692663021,"pool_token_amount":140054357663467990}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":141333114169078173,"pool_token_amount":140054044363732384}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":141182216032082762,"pool_token_amount":140051283879429328}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":141142874908971489,"pool_token_amount":140055226590559006}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":141055657231325881,"pool_token_amount":140052103458879527}],[62,{"sui_amount":141032394265066998,"pool_token_amount":140049238665884212}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":140968954346296688,"pool_token_amount":140046952359552197}],[57,{"sui_amount":140926685338719287,"pool_token_amount":140045556123828752}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":140985829385269786,"pool_token_amount":140145062672926545}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":140966092576964849,"pool_token_amount":140145913655632911}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":140925502393417998,"pool_token_amount":140146510814211497}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"sui_amount":140824275130468155,"pool_token_amount":140148339086110193}],[45,{"sui_amount":140783170430647632,"pool_token_amount":140148627960237007}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":140762444940478916,"pool_token_amount":140148599744574864}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":140739919719869320,"pool_token_amount":140146780382931320}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"sui_amount":140703664649285555,"pool_token_amount":140152224979887424}],[39,{"sui_amount":291172403862715598,"pool_token_amount":290163853029919274}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":290987407824137599,"pool_token_amount":290066450205351398}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":290632780024112799,"pool_token_amount":290039693997968899}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":200545470488099766,"pool_token_amount":200203372949593630}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":150329971659880520,"pool_token_amount":150260697787320436}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":150292350986533445,"pool_token_amount":150257547817221532}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":150000000116171591,"pool_token_amount":150000000002323420}],[16,{"sui_amount":150000000053253526,"pool_token_amount":150000000001065061}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":150000000003391500,"pool_token_amount":150000000000067827}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":150000000000000000,"pool_token_amount":150000000000000000}]],"P-OPS Team":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":117507999616454287,"pool_token_amount":115066175877758327}],[165,{"sui_amount":117492463959942243,"pool_token_amount":115065415236161618}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":117413795378752461,"pool_token_amount":115060630673260775}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":117365444722578103,"pool_token_amount":115058043559176431}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":117301076531251171,"pool_token_amount":115054688731749144}],[150,{"sui_amount":117252927004031719,"pool_token_amount":115052298585385906}],[148,{"sui_amount":117220686006119339,"pool_token_amount":115050474323984981}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":117157265239231932,"pool_token_amount":115047361391440062}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":116949858554748616,"pool_token_amount":115035989811116969}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":116902419693790534,"pool_token_amount":115033628349846384}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":116886566252281967,"pool_token_amount":115032854995181265}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":116642957744414580,"pool_token_amount":115014796392303047}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":116593965502648890,"pool_token_amount":115012685246804737}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":116576360351517112,"pool_token_amount":115011826409528183}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":116485176321630308,"pool_token_amount":115007195451454250}],[97,{"sui_amount":116376438722698525,"pool_token_amount":115001825555964470}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":116339595274818573,"pool_token_amount":114999250154338816}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":116268338264319134,"pool_token_amount":114995732289456757}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":116232982831830309,"pool_token_amount":114993910453241346}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":116160033012008246,"pool_token_amount":114987865478494127}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":116089894117099336,"pool_token_amount":114984268273074527}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":116019343285948774,"pool_token_amount":114980753617300744}],[74,{"sui_amount":115966994021310137,"pool_token_amount":114978156389626168}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":115948892037300831,"pool_token_amount":114977167643851788}],[72,{"sui_amount":115930443457588704,"pool_token_amount":114976253420375035}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":115854411490181571,"pool_token_amount":114970598890074131}],[67,{"sui_amount":115835852783373109,"pool_token_amount":114969678033622305}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":115817289421832312,"pool_token_amount":114968752091534491}],[65,{"sui_amount":115798732284105861,"pool_token_amount":114967832924977867}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":115766378046641741,"pool_token_amount":114968625280906524}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":115677688848886076,"pool_token_amount":114962857964878693}],[57,{"sui_amount":115660262561446509,"pool_token_amount":114962012820749924}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":115324673957084787,"pool_token_amount":114928568281439339}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":115307565977090514,"pool_token_amount":114928572936993589}],[37,{"sui_amount":115290264485871172,"pool_token_amount":114928507177808913}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":105274275401329003,"pool_token_amount":104959913543685611}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":105240694077841743,"pool_token_amount":104959911339347613}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":105155816484799688,"pool_token_amount":104960405580501455}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":80124710617595157,"pool_token_amount":80003429141768846}],[25,{"sui_amount":80092037019762735,"pool_token_amount":80002132413388206}],[24,{"sui_amount":80076374232695145,"pool_token_amount":80003267106809736}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":80056776280851811,"pool_token_amount":80001857206186208}],[22,{"sui_amount":80038209583037116,"pool_token_amount":80001594140761966}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"P2P.ORG":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":232659480398663754,"pool_token_amount":228063512468797756}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":232628734485942527,"pool_token_amount":228060519700181068}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":233226276807079287,"pool_token_amount":228728722043871235}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":233155130173266768,"pool_token_amount":228715040372659305}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":232997551630969843,"pool_token_amount":228700733022766608}],[148,{"sui_amount":289202953612938816,"pool_token_amount":284017178525462232}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":288897112272647680,"pool_token_amount":283958438005597010}],[140,{"sui_amount":288847859266574580,"pool_token_amount":283944546326174875}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":288806048453616593,"pool_token_amount":283937885723380482}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":288767571538732592,"pool_token_amount":283934525975436670}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":288681343656081675,"pool_token_amount":283918717798690755}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":288634218721917840,"pool_token_amount":283906834915618491}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":288480355869737383,"pool_token_amount":283979384195112947}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":288401067611510260,"pool_token_amount":283970381577575968}],[128,{"sui_amount":288357327637111374,"pool_token_amount":283961854833854496}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":289016310521043611,"pool_token_amount":284852994504290249}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":288933579801905464,"pool_token_amount":284840671450151446}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":288854988916870947,"pool_token_amount":284832509545270569}],[116,{"sui_amount":288815685723464798,"pool_token_amount":284828460183233986}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":288694358835989253,"pool_token_amount":284812946488579765}],[112,{"sui_amount":288723576450062383,"pool_token_amount":284876508475425537}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":288467953878970605,"pool_token_amount":284849825940752169}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":288422395462941486,"pool_token_amount":284845189486402309}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":288285892793695342,"pool_token_amount":284831151829094437}],[101,{"sui_amount":288240894021778068,"pool_token_amount":284826702495415625}],[99,{"sui_amount":288151317415176764,"pool_token_amount":284817822744733955}],[98,{"sui_amount":288106658303800354,"pool_token_amount":284813408495757562}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":227690406179096068,"pool_token_amount":225366688318660085}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":227551297911497604,"pool_token_amount":225351551250794161}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":227487110537400031,"pool_token_amount":225348992579373152}],[82,{"sui_amount":227452230235124151,"pool_token_amount":225344903853984477}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":227418147227344030,"pool_token_amount":225341601681707308}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":35366235229697407,"pool_token_amount":35101408355847458}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":35335635512230172,"pool_token_amount":35095654822793532}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":35324523339277213,"pool_token_amount":35094155028242909}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":35313455985824558,"pool_token_amount":35092700596751841}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":35290717854026524,"pool_token_amount":35089188620600728}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":35274495285735541,"pool_token_amount":35087480527576910}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":35263826265629940,"pool_token_amount":35086420107864466}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":35253157328816786,"pool_token_amount":35085358509259351}],[46,{"sui_amount":35248749163291111,"pool_token_amount":35095307685875763}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":35227185584149274,"pool_token_amount":35092958037959521}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":35200644447289464,"pool_token_amount":35091140691570459}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":35159752689687761,"pool_token_amount":35087408140840125}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":25069117160534757,"pool_token_amount":25045377211693528}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":25048370994433130,"pool_token_amount":25030656722899593}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":25000000032208364,"pool_token_amount":25000000000000000}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":25000000019836964,"pool_token_amount":25000000000000000}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":25000000000550800,"pool_token_amount":25000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Parasol":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":28105228053244035,"pool_token_amount":27536160498788316}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":28091871431126661,"pool_token_amount":27538887772305042}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":28084444517315103,"pool_token_amount":27538006615920671}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":28076626338269187,"pool_token_amount":27536914058787744}],[156,{"sui_amount":28072817536635842,"pool_token_amount":27536465788136761}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":28069008540177744,"pool_token_amount":27536017441004312}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":28057214563343112,"pool_token_amount":27534313298563638}],[151,{"sui_amount":28056547857180506,"pool_token_amount":27536949195700017}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"sui_amount":28038251873682442,"pool_token_amount":27535187593397500}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":28033044295129726,"pool_token_amount":27536493663106548}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":28112681500505769,"pool_token_amount":27637267823656994}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":28105254831322450,"pool_token_amount":27636393384224769}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":28101541617485369,"pool_token_amount":27635955231494465}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":28082871194658214,"pool_token_amount":27624022283627387}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":28075027212001431,"pool_token_amount":27638821378783803}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":28067632996623100,"pool_token_amount":27637975437091059}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":28063930052036571,"pool_token_amount":27637546560962875}],[121,{"sui_amount":28060218895940668,"pool_token_amount":27637108867598263}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":28056864329134685,"pool_token_amount":27637021295062126}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":28049608378034057,"pool_token_amount":27639524364416735}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":28042619156010909,"pool_token_amount":27639072060199247}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":27934111927294777,"pool_token_amount":27541782108832332}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":27927405829933619,"pool_token_amount":27538389814066462}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":27907353000476612,"pool_token_amount":27536249737794829}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":27910376229811811,"pool_token_amount":27547552541928937}],[102,{"sui_amount":27900291883127294,"pool_token_amount":27545903541431180}],[101,{"sui_amount":27896034058972133,"pool_token_amount":27545819485371256}],[99,{"sui_amount":27887065845130865,"pool_token_amount":27545174256178643}],[97,{"sui_amount":27874411977067631,"pool_token_amount":27540847686972144}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":27849381322636822,"pool_token_amount":27540420751151143}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":27840674866615040,"pool_token_amount":27539867947540308}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":27787719911747577,"pool_token_amount":27511537907946286}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":27762247029114079,"pool_token_amount":27506399198940400}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":27714901158552257,"pool_token_amount":27504817043634705}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":27679811355469954,"pool_token_amount":27502418996315286}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":27657768377537697,"pool_token_amount":27500536588739527}],[53,{"sui_amount":27653383522729181,"pool_token_amount":27500184345552557}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":27643370837573201,"pool_token_amount":27498242771149748}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"sui_amount":27625325241828109,"pool_token_amount":27496326140878180}],[45,{"sui_amount":27617205990063838,"pool_token_amount":27496266505492534}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":27591776099166270,"pool_token_amount":27495455437639117}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":27587510786321686,"pool_token_amount":27495331366010997}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":27551706625148448,"pool_token_amount":27490620328339613}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":27547028803693176,"pool_token_amount":27490518189373048}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":27032327474120123,"pool_token_amount":26990832958257579}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":20014778685211770,"pool_token_amount":20000925844348894}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":20000000025396901,"pool_token_amount":20000000000507924}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":20000000015774701,"pool_token_amount":20000000000315481}],[17,{"sui_amount":20000000012328401,"pool_token_amount":20000000000246557}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":20000000000428400,"pool_token_amount":20000000000008567}]],"Peeranha":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":35758894183310856,"pool_token_amount":35059584722303078}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":35740154577996887,"pool_token_amount":35058114604866237}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":35730531615214034,"pool_token_amount":35057359411338561}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":35712760133772216,"pool_token_amount":35048608597983111}],[154,{"sui_amount":35707948301428097,"pool_token_amount":35048230809827779}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":35674249429866097,"pool_token_amount":35045573157131616}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":35600706280581514,"pool_token_amount":35038081533126534}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":35586347929643986,"pool_token_amount":35036952729338780}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":35576910378190902,"pool_token_amount":35036211162652818}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":35553334979475706,"pool_token_amount":35034357003091252}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":35534477539224661,"pool_token_amount":35032870155426745}],[117,{"sui_amount":91735889242077333,"pool_token_amount":39881683429017994}],[116,{"sui_amount":35524858921441345,"pool_token_amount":35032118752807723}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":35520545617559264,"pool_token_amount":35032232381766662}],[114,{"sui_amount":35515803294599231,"pool_token_amount":35031922731963921}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":35511012519884878,"pool_token_amount":35031565582343472}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":35506218573566429,"pool_token_amount":35031205400529076}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":35496008901754460,"pool_token_amount":35029872980269025}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[97,{"sui_amount":35424606144160149,"pool_token_amount":35023537077944574}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":35403007903923037,"pool_token_amount":35021849424684213}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":35397702072264658,"pool_token_amount":35021431359272768}],[90,{"sui_amount":35387125626202785,"pool_token_amount":35020595091092075}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":35376572869390470,"pool_token_amount":35019759556506773}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":35355203441000764,"pool_token_amount":35017747773056079}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":35344640004056391,"pool_token_amount":35016919848256162}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":35323442580813547,"pool_token_amount":35015187493469136}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[75,{"sui_amount":35307547006622099,"pool_token_amount":35013926782957597}],[74,{"sui_amount":35302080761635434,"pool_token_amount":35013373602220286}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":35291078870419226,"pool_token_amount":35012501511453523}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":35285521767611921,"pool_token_amount":35012060452512747}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":35268844737064485,"pool_token_amount":35010734612118056}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":35241547224458920,"pool_token_amount":35008502228175824}],[62,{"sui_amount":35236321928389634,"pool_token_amount":35008085140956805}],[61,{"sui_amount":35230987206660724,"pool_token_amount":35007661127587170}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":35214952671244891,"pool_token_amount":35006358888327130}],[57,{"sui_amount":35209602159102672,"pool_token_amount":35005918750020835}],[56,{"sui_amount":35204267008185572,"pool_token_amount":35005494406998279}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":35188102590145810,"pool_token_amount":35004062887966901}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":35182496140752505,"pool_token_amount":35003368701807392}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":35171923464700508,"pool_token_amount":35002615254084999}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":35133989981184742,"pool_token_amount":34999051598883865}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"sui_amount":35123291162317273,"pool_token_amount":34998172737625768}],[40,{"sui_amount":35117843997705116,"pool_token_amount":34997737600067856}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":35054492355530874,"pool_token_amount":34992633808071220}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":35041902797559540,"pool_token_amount":34991493278221693}],[25,{"sui_amount":25031167537251109,"pool_token_amount":25004352851489906}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":25000000019248364,"pool_token_amount":25000000000384956}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Persimmon":[[164,{"sui_amount":112227683037367362,"pool_token_amount":110219866592942141}],[163,{"sui_amount":112212848044823513,"pool_token_amount":110218409633966776}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":112168361201187388,"pool_token_amount":110214040384139651}],[159,{"sui_amount":112153082745924805,"pool_token_amount":110212592250579525}],[158,{"sui_amount":112137746331489804,"pool_token_amount":110211085144072776}],[157,{"sui_amount":112122401453904101,"pool_token_amount":110209569855531985}],[156,{"sui_amount":112107066017044711,"pool_token_amount":110208062474042964}],[155,{"sui_amount":112091729795857642,"pool_token_amount":110206554829842020}],[152,{"sui_amount":112045633103266527,"pool_token_amount":110201949563954170}],[146,{"sui_amount":111954084150651889,"pool_token_amount":110192941661678562}],[145,{"sui_amount":111938926279742138,"pool_token_amount":110191449718713516}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":111863192236624004,"pool_token_amount":110183997214292913}],[136,{"sui_amount":111802547348269505,"pool_token_amount":110178022664719383}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":111787394297749332,"pool_token_amount":110176529377012610}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":111772240372724398,"pool_token_amount":110175035820938328}],[133,{"sui_amount":111757084156599136,"pool_token_amount":110173541856771525}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":111741926151803171,"pool_token_amount":110172047533916426}],[130,{"sui_amount":111713320426136078,"pool_token_amount":110170749562640274}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":111606106091983701,"pool_token_amount":110158648006646530}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":111576024232726264,"pool_token_amount":110155696425068691}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":111530569363589453,"pool_token_amount":110151190480703361}],[115,{"sui_amount":111485142945264110,"pool_token_amount":110146703472966633}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":111454860063083419,"pool_token_amount":110143713785461507}],[112,{"sui_amount":111439716183370166,"pool_token_amount":110142217212247030}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":111392585360485755,"pool_token_amount":110137558412981767}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":111358810039405209,"pool_token_amount":110134224098524191}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":111306070949162748,"pool_token_amount":110128791996608064}],[101,{"sui_amount":111253657870930831,"pool_token_amount":110123606276422893}],[99,{"sui_amount":111219032062719251,"pool_token_amount":110120178621905145}],[97,{"sui_amount":111184581204658067,"pool_token_amount":110116769120924392}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":111065073303964671,"pool_token_amount":110104840784559689}],[88,{"sui_amount":111031394295129591,"pool_token_amount":110101501772695079}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":111014568925803947,"pool_token_amount":110099834224206812}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":110863498586347382,"pool_token_amount":110084945178590118}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":110830146749414945,"pool_token_amount":110081631405103542}],[72,{"sui_amount":110762123888928727,"pool_token_amount":110074870983042892}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":110727005700839138,"pool_token_amount":110071388816803774}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":110656095774589185,"pool_token_amount":110064338285972802}],[65,{"sui_amount":110638614640091332,"pool_token_amount":110062868193081271}],[60,{"sui_amount":110555058643750240,"pool_token_amount":110054374710059572}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":110538289477447614,"pool_token_amount":110052615795473233}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":110471379015976413,"pool_token_amount":110045850638640449}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":110437798651186561,"pool_token_amount":110042493658894013}],[52,{"sui_amount":110421014216654574,"pool_token_amount":110040821223313695}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"sui_amount":110319988540272170,"pool_token_amount":110030748189089607}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[41,{"sui_amount":110236973211213625,"pool_token_amount":110023967832868463}],[39,{"sui_amount":110202741139117584,"pool_token_amount":110020551901244503}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[33,{"sui_amount":110094964850204691,"pool_token_amount":110009727906822850}],[31,{"sui_amount":110057570637844902,"pool_token_amount":110005982016592208}],[30,{"sui_amount":110038784151262396,"pool_token_amount":110004104248529913}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}]],"Qredo":[[167,{"sui_amount":27599107811630911,"pool_token_amount":27058723875922703}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":27595498756964254,"pool_token_amount":27058370036516572}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":27591890475148197,"pool_token_amount":27058016231275616}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":27588281432178205,"pool_token_amount":27057662309719039}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":27577360306807787,"pool_token_amount":27056502784447443}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":27544796417047322,"pool_token_amount":27053939547162182}],[148,{"sui_amount":27529959444853492,"pool_token_amount":27052482023197506}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":27510159761668195,"pool_token_amount":27049175048019860}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":27502938562293733,"pool_token_amount":27048464985708973}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":27488489199243800,"pool_token_amount":27047048146695410}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":27477651438145127,"pool_token_amount":27045984306455959}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":27464515975774454,"pool_token_amount":27042658640711101}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":27461305301950217,"pool_token_amount":27042700474238432}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":27447971639082239,"pool_token_amount":27042385303753672}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":27444359878260398,"pool_token_amount":27042029464185640}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":27437134771008295,"pool_token_amount":27041316615532141}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":27429908324044875,"pool_token_amount":27040602578885700}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":27394481133804883,"pool_token_amount":27034503140709555}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":27387257779722297,"pool_token_amount":27033789277101706}],[109,{"sui_amount":27383230655651339,"pool_token_amount":27033380311076653}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":27371169854306997,"pool_token_amount":27032466162998719}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"sui_amount":27350129740134709,"pool_token_amount":27030437759135852}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":27313218252081368,"pool_token_amount":27027224562043597}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":27288951821799689,"pool_token_amount":27024816837539144}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":27284806368104000,"pool_token_amount":27024292542209565}],[84,{"sui_amount":27280801606684136,"pool_token_amount":27023897686337208}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":27276110027113460,"pool_token_amount":27022822371624461}],[82,{"sui_amount":27272094120287115,"pool_token_amount":27022416455073403}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":27267310736697625,"pool_token_amount":27021249687187487}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":27263909930206789,"pool_token_amount":27021651834861810}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":27235421383449975,"pool_token_amount":27018505050122596}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":27226972701093915,"pool_token_amount":27017665066677253}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":27194179871560463,"pool_token_amount":27015398134428427}],[61,{"sui_amount":27185625007739984,"pool_token_amount":27014053784763418}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":27181624187361666,"pool_token_amount":27013657127064800}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":27168944730890429,"pool_token_amount":27011791261843452}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":27152127916385030,"pool_token_amount":27009591688927958}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":27143907117106444,"pool_token_amount":27008777459760939}],[50,{"sui_amount":27139794231337740,"pool_token_amount":27008367323166028}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":27135660069296138,"pool_token_amount":27007936137062748}],[48,{"sui_amount":27130593672870713,"pool_token_amount":27006577410664521}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":27113919772079627,"pool_token_amount":27004714396463452}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":27087984195364060,"pool_token_amount":27001000872703755}],[37,{"sui_amount":27083752651983053,"pool_token_amount":27000577282926805}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":27074939798215303,"pool_token_amount":26999587348485205}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":27034349053275831,"pool_token_amount":26992853096947182}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":20000000000527000,"pool_token_amount":20000000000010533}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"QuantNode":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":27584178708123104,"pool_token_amount":27058590379361670}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":27562256673518819,"pool_token_amount":27056462570033452}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":27554841344744369,"pool_token_amount":27055736368186019}],[154,{"sui_amount":27551132223868984,"pool_token_amount":27055372174060122}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":27547285860004702,"pool_token_amount":27054873306438337}],[149,{"sui_amount":27532431488476590,"pool_token_amount":27053398739410541}],[148,{"sui_amount":27526746132210402,"pool_token_amount":27051092652392961}],[145,{"sui_amount":27515708975491280,"pool_token_amount":27050007876419024}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":27512095197606132,"pool_token_amount":27049652614309482}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":27479047711490971,"pool_token_amount":27036330883070778}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":27449748567997737,"pool_token_amount":27033110918164541}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":27443534972742359,"pool_token_amount":27043013946484426}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":27413869864191389,"pool_token_amount":27029794688786512}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":27410259039251653,"pool_token_amount":27029438664773628}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":27403038270963458,"pool_token_amount":27028726577097304}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":27396009092377394,"pool_token_amount":27028202725973182}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":27388786680788512,"pool_token_amount":27027488362219339}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":27378005553916819,"pool_token_amount":27026470167206828}],[109,{"sui_amount":27373981319340064,"pool_token_amount":27026064025983141}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":27345259385703128,"pool_token_amount":27023559067487466}],[99,{"sui_amount":27332631663794315,"pool_token_amount":27022310970765038}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":27307668257664995,"pool_token_amount":27019845685944340}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":27299547583990550,"pool_token_amount":27019043014821838}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":27287428914813513,"pool_token_amount":27017852418455666}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":27279353698265701,"pool_token_amount":27017052820401389}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":27263370644235871,"pool_token_amount":27015518685246700}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":27255116716194683,"pool_token_amount":27014684685477184}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":27247148038159528,"pool_token_amount":27013930650453094}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":27235064948176851,"pool_token_amount":27012662915016780}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":27226949264994893,"pool_token_amount":27011856134462129}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":27181644059518491,"pool_token_amount":27008289905212821}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":27144145998919972,"pool_token_amount":27003429726485459}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":27135919189343523,"pool_token_amount":27002609463593674}],[50,{"sui_amount":27131807303574819,"pool_token_amount":27002200295045777}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":27123561730979871,"pool_token_amount":27001360808233130}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":27102628393612395,"pool_token_amount":26998941162758177}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"sui_amount":27089788534258292,"pool_token_amount":26997211441934633}],[39,{"sui_amount":27085565714860988,"pool_token_amount":26996691582657661}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":27077222051078338,"pool_token_amount":26995859896355301}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":27072978018171919,"pool_token_amount":26995435870948281}],[35,{"sui_amount":27068561226098944,"pool_token_amount":26995021490536900}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":27059384431074923,"pool_token_amount":26994051475202143}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":27054694043644871,"pool_token_amount":26993471702404773}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":20032535617404197,"pool_token_amount":20002790034527758}],[26,{"sui_amount":20028489960849676,"pool_token_amount":20002347428849774}],[24,{"sui_amount":20019713178904400,"pool_token_amount":20001278877477511}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":20015043495211770,"pool_token_amount":20001190470087279}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"sui_amount":20000000012328401,"pool_token_amount":20000000000246557}],[16,{"sui_amount":20000000007017893,"pool_token_amount":20000000000140348}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":20000000000000000,"pool_token_amount":20000000000000000}]],"RepublicCrypto":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":27518394127507575,"pool_token_amount":27002626099761244}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":27511073067126818,"pool_token_amount":27001905047644859}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":27492528915835205,"pool_token_amount":27000084509766762}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":27488560151970923,"pool_token_amount":26999465392784663}],[152,{"sui_amount":27484784639491233,"pool_token_amount":26999036056515951}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":27437272211411380,"pool_token_amount":26991018583311625}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":27453709430673486,"pool_token_amount":27013589026104062}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":27439201795195527,"pool_token_amount":27012116986496014}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":27428360250380923,"pool_token_amount":27011049578550259}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":27417512450030962,"pool_token_amount":27009981174517965}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":27413899667232716,"pool_token_amount":27009626164828883}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":27385005526819903,"pool_token_amount":27006778175512439}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":27374164898342820,"pool_token_amount":27005700126390502}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":27286617867340238,"pool_token_amount":26997419556264862}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":27274522069082917,"pool_token_amount":26996303707021622}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":27262208344662218,"pool_token_amount":26994919952538944}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":27250113020474940,"pool_token_amount":26993720060432218}],[84,{"sui_amount":27246097244419589,"pool_token_amount":26993314237854970}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":27234000202662398,"pool_token_amount":26992046956064731}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":27229769758210700,"pool_token_amount":26991626777986109}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":27230094522354776,"pool_token_amount":27002668417978373}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":27222631199291328,"pool_token_amount":27002408679052580}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":27214501516245364,"pool_token_amount":27001587947935496}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":27193063623700910,"pool_token_amount":26999275412290430}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":27184396566623173,"pool_token_amount":26998415715910099}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":27172074058231472,"pool_token_amount":26997203802513422}],[61,{"sui_amount":27164078727035926,"pool_token_amount":26996415207245318}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":27159962901136190,"pool_token_amount":26995904198310273}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":27154651301220999,"pool_token_amount":26994203473907275}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":27118243039153853,"pool_token_amount":26990723640875579}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":27114129952793787,"pool_token_amount":26990313370583526}],[47,{"sui_amount":27118002721444452,"pool_token_amount":27001538161967465}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":27080602536551803,"pool_token_amount":26997463722009625}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":27045211816627500,"pool_token_amount":26994224996840980}],[29,{"sui_amount":27040538101686602,"pool_token_amount":26993756709836426}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":27035856256303972,"pool_token_amount":26993290235514122}],[26,{"sui_amount":20028084520041390,"pool_token_amount":20003446259403312}],[25,{"sui_amount":20024005503451592,"pool_token_amount":20003171079883520}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":20014574675222270,"pool_token_amount":20001852252391789}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":20000000015785201,"pool_token_amount":20000000001578507}],[18,{"sui_amount":20000000015327401,"pool_token_amount":20000000001532728}],[17,{"sui_amount":20000000012338901,"pool_token_amount":20000000001233879}],[16,{"sui_amount":20000000007028393,"pool_token_amount":20000000000702830}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":20000000000537500,"pool_token_amount":20000000000053743}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":20000000000460100,"pool_token_amount":20000000000046005}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":20000000000460100,"pool_token_amount":20000000000046005}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":20000000000460100,"pool_token_amount":20000000000046005}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":20000000000460100,"pool_token_amount":20000000000046005}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000451500,"pool_token_amount":20000000000045147}],[4,{"sui_amount":20000000000451500,"pool_token_amount":20000000000045147}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Restake":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":35717582725975671,"pool_token_amount":35007219033944051}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":35703413994984135,"pool_token_amount":35005937839805020}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":35698703306827391,"pool_token_amount":35005522159738621}],[161,{"sui_amount":35694096650674716,"pool_token_amount":35005114718663386}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":35655478328876849,"pool_token_amount":35001413777721165}],[152,{"sui_amount":35650635236768091,"pool_token_amount":35000958219030582}],[150,{"sui_amount":35641011649457129,"pool_token_amount":35000107826835567}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":35625205569842308,"pool_token_amount":34997399381212711}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":35601176885340147,"pool_token_amount":34995230593969343}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":35604544504016375,"pool_token_amount":35006978275899326}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":35580991263551123,"pool_token_amount":35004928920783392}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":35571458650580629,"pool_token_amount":35004086638446579}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":35554309153394555,"pool_token_amount":35004295058928420}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":35525330041841593,"pool_token_amount":35001120116466332}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":35515884202875397,"pool_token_amount":35000270002985383}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":35501926603725040,"pool_token_amount":34999197277182035}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[103,{"sui_amount":35441922477589680,"pool_token_amount":35007702862211387}],[102,{"sui_amount":35436489411883104,"pool_token_amount":35007168893471447}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":35405019251432707,"pool_token_amount":35004847949929551}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":35367239132873658,"pool_token_amount":35000717729347229}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":35356797552731012,"pool_token_amount":34999777565974945}],[86,{"sui_amount":35351743308628229,"pool_token_amount":34999469832131043}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":35345709285561347,"pool_token_amount":34998169807947148}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":35334418857184595,"pool_token_amount":34996313471800797}],[82,{"sui_amount":35329203780680881,"pool_token_amount":34995811323877697}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":35317882424665424,"pool_token_amount":34994122020282344}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":35304788969244336,"pool_token_amount":34999792715827689}],[74,{"sui_amount":35294650050199905,"pool_token_amount":34999063146874409}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":35283647145321490,"pool_token_amount":34997971994591947}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":35278087042514185,"pool_token_amount":34997417807920068}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":35255814551423449,"pool_token_amount":34995171218703469}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":35244905840822630,"pool_token_amount":34994270915479394}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"sui_amount":35221680559966033,"pool_token_amount":34995330436387159}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":35216313439817731,"pool_token_amount":34995032670618110}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":35190668192976831,"pool_token_amount":34994624547421400}],[53,{"sui_amount":35185114605386545,"pool_token_amount":34994142476951964}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":35164100370475282,"pool_token_amount":34993404481729347}],[48,{"sui_amount":35158766254209608,"pool_token_amount":34993140017057700}],[47,{"sui_amount":35153499914264973,"pool_token_amount":34992942224866677}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":35103421153391202,"pool_token_amount":34988705878533004}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":35094727543853031,"pool_token_amount":34990491700264662}],[35,{"sui_amount":35088894008249016,"pool_token_amount":34990149742164635}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":35082997652691813,"pool_token_amount":34989851017398974}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":35054517425779291,"pool_token_amount":34989478071084203}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":35048373126142559,"pool_token_amount":34989160049621319}],[24,{"sui_amount":25028874952704661,"pool_token_amount":25005890002660342}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":25015591324167687,"pool_token_amount":25004031152199461}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":25000000019248364,"pool_token_amount":25000000000384956}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":25000000000572400,"pool_token_amount":25000000000011444}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Scale3Labs":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":107222357865350365,"pool_token_amount":105000494150105556}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":107208122197127154,"pool_token_amount":104999797115882505}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":107107607234778958,"pool_token_amount":104994974581276331}],[156,{"sui_amount":107092912419194197,"pool_token_amount":104994197525443621}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":107048765814818858,"pool_token_amount":104991810120249031}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"sui_amount":106960093485371249,"pool_token_amount":104986486418307666}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":106857121484892416,"pool_token_amount":104979712216431345}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":106828217467246334,"pool_token_amount":104978293248557867}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":106731822099801048,"pool_token_amount":104991543728152811}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":106717355226093962,"pool_token_amount":104990832178079217}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":106688689784414561,"pool_token_amount":104989661105188292}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":106659744254927597,"pool_token_amount":104988190987957248}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":106630877595296484,"pool_token_amount":104986798023813915}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":106588554165550386,"pool_token_amount":104985665450931528}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":106574110867059171,"pool_token_amount":104984954145595697}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":107703402117528133,"pool_token_amount":106179773178117190}],[112,{"sui_amount":107688739690771181,"pool_token_amount":106179031696277629}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":107609365432363324,"pool_token_amount":106205752690152651}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":107576138953245047,"pool_token_amount":106204779608852885}],[99,{"sui_amount":107508990047880501,"pool_token_amount":106201481199547936}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":107406855753509742,"pool_token_amount":106194206153868299}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":107283263515989368,"pool_token_amount":106194371837270365}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":107250116810080593,"pool_token_amount":106192017672419437}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":107149833228810307,"pool_token_amount":106199464807713232}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":107133711537584103,"pool_token_amount":106198660223290785}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":111517071077289884,"pool_token_amount":110677010907401348}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":111499179484097641,"pool_token_amount":110676123067593298}],[66,{"sui_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":111446346849820957,"pool_token_amount":110672201666522711}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":111378371772431070,"pool_token_amount":110668027709242495}],[58,{"sui_amount":126436300717398597,"pool_token_amount":125650408066685002}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":126438128399750527,"pool_token_amount":125688325522154968}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":126380230194459064,"pool_token_amount":125685247119390386}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":126361301551419031,"pool_token_amount":125684590507196072}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":126306520836068722,"pool_token_amount":125684605634841908}],[45,{"sui_amount":126237539863274624,"pool_token_amount":125688983548105860}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":126198957695699504,"pool_token_amount":125687149871855832}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":126159950446736197,"pool_token_amount":125685107639431452}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":126127670238763111,"pool_token_amount":125690083491351270}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":126088085226035135,"pool_token_amount":125688023995415001}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":126067999650383527,"pool_token_amount":125687035218797835}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":125981750441425048,"pool_token_amount":125681834621982432}],[32,{"sui_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":125920519088971911,"pool_token_amount":125682184437956645}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":100878348090299029,"pool_token_amount":100722094039367962}],[24,{"sui_amount":80120676710549734,"pool_token_amount":80045819984284639}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80039431872812636,"pool_token_amount":80002248108640848}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":80000000001754400,"pool_token_amount":80000000000035087}]],"SenseiNode":[[167,{"sui_amount":27162396517391731,"pool_token_amount":26619852612617942}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":27151855870666605,"pool_token_amount":26619012580476678}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":27148347595093622,"pool_token_amount":26618737425935374}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":27134011764523766,"pool_token_amount":26617426885116120}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":27130403196100028,"pool_token_amount":26617143695337453}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":27115968806450440,"pool_token_amount":26616010580394867}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"sui_amount":27093952870227529,"pool_token_amount":26613954423592405}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":27090352788916733,"pool_token_amount":26613681620634691}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":27079298743478046,"pool_token_amount":26612618379435326}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":27054655694904172,"pool_token_amount":26614531917711992}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":27036997990896381,"pool_token_amount":26613512550813873}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":27026150205630873,"pool_token_amount":26612658227676292}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":27011858579862503,"pool_token_amount":26611675835663857}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":27008246656864246,"pool_token_amount":26611391162253864}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":26997410585034461,"pool_token_amount":26610536001328247}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":26993799760094725,"pool_token_amount":26610251274417663}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":26990189054720514,"pool_token_amount":26609966521907753}],[116,{"sui_amount":26982969079130202,"pool_token_amount":26609397024984589}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":26965302283502734,"pool_token_amount":26608351953044323}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":26961690472049869,"pool_token_amount":26608066832580332}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":26949617108700187,"pool_token_amount":26607084555729423}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":26945498221308261,"pool_token_amount":26606759229573203}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":26928623196264628,"pool_token_amount":26605287826864003}],[98,{"sui_amount":27921532955999946,"pool_token_amount":27601962771733221}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":27913128883057364,"pool_token_amount":27601298092163681}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":27871041910068049,"pool_token_amount":27597584367591736}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":27833762954518448,"pool_token_amount":27594536848853596}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":27825538158344935,"pool_token_amount":27593883563842005}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":27817200682349386,"pool_token_amount":27593220704394446}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":27808529718879052,"pool_token_amount":27592530738187915}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":27804093609044404,"pool_token_amount":27592087322151683}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":27791095195350465,"pool_token_amount":27591060770612979}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":27786761206724211,"pool_token_amount":27590716547130030}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":27774213930399436,"pool_token_amount":27589729767151923}],[62,{"sui_amount":27770080973918336,"pool_token_amount":27589382135138947}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":27753101025248712,"pool_token_amount":27587546650447791}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":27740791811017396,"pool_token_amount":27586593007136325}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":27718718830117940,"pool_token_amount":27583453292628092}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":27714100743757874,"pool_token_amount":27582622400298940}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":27649415410565028,"pool_token_amount":27576575748696065}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":27640034913333078,"pool_token_amount":27575796218381600}],[31,{"sui_amount":27635161034796068,"pool_token_amount":27575219052618349}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"sui_amount":20032226211314164,"pool_token_amount":20005568803634186}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":20018800856834969,"pool_token_amount":20004946069801195}],[22,{"sui_amount":20013666061485663,"pool_token_amount":20004504611660062}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":20000000000550400,"pool_token_amount":20000000000011000}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Shinlabs":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":139611708560290726,"pool_token_amount":136763299300037560}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":139524795178930598,"pool_token_amount":136765082773353556}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":132868400714405272,"pool_token_amount":130307934356827088}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[149,{"sui_amount":132781302015114272,"pool_token_amount":130307043169385011}],[148,{"sui_amount":132764154217177886,"pool_token_amount":130307038885608840}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"sui_amount":132723021619968019,"pool_token_amount":130300153588652790}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":132688780612661779,"pool_token_amount":130300054896609656}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":132654716863609162,"pool_token_amount":130300099514534420}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":139223886130366403,"pool_token_amount":136788748772952893}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":139117847397577901,"pool_token_amount":136789792169450744}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":139080456341026962,"pool_token_amount":136788188188768743}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":139044692193630716,"pool_token_amount":136788191997471619}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":139026856803332103,"pool_token_amount":136788204030916513}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":138991194732180944,"pool_token_amount":136788221359484758}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":138974304790193155,"pool_token_amount":136789142884538911}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":138919887852746577,"pool_token_amount":136788213032796344}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":138902052155119590,"pool_token_amount":136788204783564201}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":138622774492862190,"pool_token_amount":136706713066975721}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":138584152847581472,"pool_token_amount":136705737655804546}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":138564357981472328,"pool_token_amount":136705748814406209}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":138545423046159958,"pool_token_amount":136706817754025842}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":138503004218615786,"pool_token_amount":136705748832838246}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":138482287567639454,"pool_token_amount":136705762772910618}],[102,{"sui_amount":138440833821224606,"pool_token_amount":136705751042294063}],[97,{"sui_amount":138338899111063414,"pool_token_amount":136705748561542417}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":138278904774575410,"pool_token_amount":136706767783363885}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":138098774532810181,"pool_token_amount":136705887887785280}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":138039470627260157,"pool_token_amount":136705901230469171}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":138019740809129886,"pool_token_amount":136705942052512369}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":137529392656175494,"pool_token_amount":136459732738741750}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":137465471371773456,"pool_token_amount":136458531816196650}],[65,{"sui_amount":137444500652830732,"pool_token_amount":136458465783626606}],[64,{"sui_amount":137424863545067882,"pool_token_amount":136458466000488595}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":137226744346358137,"pool_token_amount":136457270916167311}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":137147067434472997,"pool_token_amount":136456998121301762}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":137127220941503317,"pool_token_amount":136457000918202124}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":137028423748931730,"pool_token_amount":136457551057041109}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":136988519637787407,"pool_token_amount":136457557620659479}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"sui_amount":136948199951125878,"pool_token_amount":136457468949489798}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":136907421409009929,"pool_token_amount":136457246144819479}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":111830157316270752,"pool_token_amount":111531576637886176}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80038347680691165,"pool_token_amount":80001732175825940}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019059452971536,"pool_token_amount":80000435085770481}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000102695557,"pool_token_amount":80000000002053897}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":80000000063519457,"pool_token_amount":80000000001270376}],[17,{"sui_amount":80000000049632057,"pool_token_amount":80000000000992630}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002203900,"pool_token_amount":80000000000044070}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840600,"pool_token_amount":80000000000036807}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":80000000001754400,"pool_token_amount":80000000000035087}]],"SpartanLabs":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":27547245658401028,"pool_token_amount":27020192382591089}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":27532661014212797,"pool_token_amount":27018628855789878}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":27508749939811092,"pool_token_amount":27017912889657129}],[154,{"sui_amount":27505782726472684,"pool_token_amount":27018277353467790}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":27501905792608402,"pool_token_amount":27017748320275127}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":27481169500422208,"pool_token_amount":27017056075393402}],[146,{"sui_amount":27477315530442539,"pool_token_amount":27016462622509627}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":27464311563245603,"pool_token_amount":27016462435563941}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":27460204513163930,"pool_token_amount":27018817863562819}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":27446182802874414,"pool_token_amount":27017824936923604}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":27421822133932454,"pool_token_amount":27016257663738559}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":27418407863150306,"pool_token_amount":27016100634346458}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":27409285739967418,"pool_token_amount":27016723472926903}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":27405671805713572,"pool_token_amount":27016365702591967}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":27387469390511232,"pool_token_amount":27014442737013479}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":27378109384114359,"pool_token_amount":27014825460864941}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":27371789843658988,"pool_token_amount":27015001822001450}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":27357285047911629,"pool_token_amount":27013515285971014}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":27336617859745926,"pool_token_amount":27011394293353707}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":27294864112060036,"pool_token_amount":27010060577625171}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":27290799983694214,"pool_token_amount":27009578842830244}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":27282655382139453,"pool_token_amount":27008591615361461}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":27274582318646288,"pool_token_amount":27007646484437601}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":27268975428160200,"pool_token_amount":27009133863609751}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":27245903917334874,"pool_token_amount":27007272553179504}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":27232258655720258,"pool_token_amount":27004421819445083}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":27229667631986378,"pool_token_amount":27005346382791867}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":27221185127402517,"pool_token_amount":27003917039132501}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":27214364252608477,"pool_token_amount":27004233853416931}],[72,{"sui_amount":27209597423387684,"pool_token_amount":27003191624293027}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":27190714086188016,"pool_token_amount":27003090182651467}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":27178984156569400,"pool_token_amount":27002513283122167}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":27166831235553724,"pool_token_amount":27000933047429690}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":27164074351931425,"pool_token_amount":27001693348214883}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":27155969779147988,"pool_token_amount":27000636450881459}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":27141737389968610,"pool_token_amount":26996987571772358}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":27137624127045613,"pool_token_amount":26996495737286529}],[53,{"sui_amount":27133116272237097,"pool_token_amount":26995611815540298}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":27114040991149295,"pool_token_amount":27005441304503609}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":27105504296605873,"pool_token_amount":27004146689362894}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":27076433352218195,"pool_token_amount":27000639615277626}],[35,{"sui_amount":27071987531276152,"pool_token_amount":27000107589839493}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":20004670735991001,"pool_token_amount":20000096332686800}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":20000000000539900,"pool_token_amount":20000000000010790}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":20000000000445300,"pool_token_amount":20000000000008902}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":20000000000000000,"pool_token_amount":20000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"StakeWithUs":[[167,{"sui_amount":35729691752167733,"pool_token_amount":34991691318695007}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":35710596199938210,"pool_token_amount":34990523462019824}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":35729749900219522,"pool_token_amount":35017966599669879}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":35722739167915772,"pool_token_amount":35019869853643073}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":35711566205132919,"pool_token_amount":35017878638762219}],[156,{"sui_amount":35706755087392962,"pool_token_amount":35017642755209708}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":35687267870579759,"pool_token_amount":35016463469652879}],[149,{"sui_amount":35672796306242455,"pool_token_amount":35015720056891954}],[148,{"sui_amount":35667984146630429,"pool_token_amount":35015483880345763}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":35663165136334697,"pool_token_amount":35015243606678772}],[145,{"sui_amount":35653627783207483,"pool_token_amount":35014771657611839}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":35642207505964691,"pool_token_amount":35017034788668077}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":35618425028988118,"pool_token_amount":35015869493881207}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":35600150042070455,"pool_token_amount":35015621205025248}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":35595331603064336,"pool_token_amount":35015384238298189}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":35585795077487345,"pool_token_amount":35014916625891468}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":35581020250208696,"pool_token_amount":35014632171605876}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":35565472042788744,"pool_token_amount":35016973847483581}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":35557726135716247,"pool_token_amount":35013758417460810}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":35553035676713734,"pool_token_amount":35013550971686829}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":35548319220400500,"pool_token_amount":35013318726791130}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":35524592625992763,"pool_token_amount":35012097782546485}],[116,{"sui_amount":35519779409223898,"pool_token_amount":35011860593223620}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":35514965855852814,"pool_token_amount":35011623356749379}],[114,{"sui_amount":35510152433589531,"pool_token_amount":35011386096196211}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":35507548640686428,"pool_token_amount":35013328026376711}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":35397607283699603,"pool_token_amount":35009662524794529}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":35324647948890487,"pool_token_amount":35001988393115768}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":35305378766695231,"pool_token_amount":34997650448005621}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"sui_amount":35294917965829435,"pool_token_amount":34997119688106960}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":35283939368822334,"pool_token_amount":34996598250727260}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":35272791849375334,"pool_token_amount":34996015875520173}],[69,{"sui_amount":35267210201203436,"pool_token_amount":34995717964211492}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":35239709615169573,"pool_token_amount":34994304822950869}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":35202983694291402,"pool_token_amount":34992328606109193}],[56,{"sui_amount":35197759692351585,"pool_token_amount":34992068969029724}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":35170267394573663,"pool_token_amount":34989825177688468}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":35154238340628952,"pool_token_amount":34989004090657681}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":35140039443149765,"pool_token_amount":34995047835089040}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":35111763311607658,"pool_token_amount":34992334126500570}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":35077642794641073,"pool_token_amount":34990565161358095}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":35071178517617621,"pool_token_amount":34989710025511554}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":35053441786161812,"pool_token_amount":34988875404574428}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"sui_amount":25035417722297042,"pool_token_amount":25002574712649377}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":25000000032208364,"pool_token_amount":25000000000644154}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"sui_amount":25000000015495364,"pool_token_amount":25000000000309897}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":25000000000556200,"pool_token_amount":25000000000011122}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":25000000000550800,"pool_token_amount":25000000000011015}]],"Staked":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":36949601339442825,"pool_token_amount":36157498663574861}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":36923039168832917,"pool_token_amount":36154666241495964}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":36682971076521228,"pool_token_amount":35957953831799029}],[152,{"sui_amount":36672313744059013,"pool_token_amount":35952226117725788}],[149,{"sui_amount":36623048972448322,"pool_token_amount":35918086638863669}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"sui_amount":36610561383988330,"pool_token_amount":35920010567189873}],[145,{"sui_amount":36605641592825814,"pool_token_amount":35920009587425340}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":36538889799577763,"pool_token_amount":35864155975761380}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":36506335985090428,"pool_token_amount":35861161371696829}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":36436740216906980,"pool_token_amount":35850289673319021}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":35994589679477176,"pool_token_amount":35434218051395270}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":36004792287292992,"pool_token_amount":35449005665954031}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":35979975845323287,"pool_token_amount":35429314404940052}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":35973962972015437,"pool_token_amount":35428137469376119}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":35948147390913741,"pool_token_amount":35416940650428408}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":35828817005253989,"pool_token_amount":35338824908677144}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":35826590474930167,"pool_token_amount":35347454059997940}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":35821168983204186,"pool_token_amount":35347604405296427}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":35803432143033672,"pool_token_amount":35341096820929709}],[101,{"sui_amount":35797899811889914,"pool_token_amount":35341090569486946}],[100,{"sui_amount":35792403004430765,"pool_token_amount":35341102451276759}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":35675525676224536,"pool_token_amount":35310632243800751}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":35661991272880647,"pool_token_amount":35307821705575196}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":35652407078778878,"pool_token_amount":35303623840096673}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":35601388196022417,"pool_token_amount":35300808583581360}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":35589982575904881,"pool_token_amount":35300301212394958}],[69,{"sui_amount":35384470054329079,"pool_token_amount":35101865277351566}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":35381295957482109,"pool_token_amount":35114928346295341}],[65,{"sui_amount":35376557559410719,"pool_token_amount":35115630269030643}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":35358029061210431,"pool_token_amount":35102427674138110}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":35340820856234910,"pool_token_amount":35100914023964529}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":35313765423063737,"pool_token_amount":35084431436784669}],[57,{"sui_amount":35286280538236279,"pool_token_amount":35067513096334982}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":35253811855045489,"pool_token_amount":35061332420217571}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":35246366328619940,"pool_token_amount":35059126921411452}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":35186469337314982,"pool_token_amount":35041145731854890}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":35180236913437407,"pool_token_amount":35040145761593312}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"sui_amount":35191026240440461,"pool_token_amount":35061527793948450}],[39,{"sui_amount":35182345110274014,"pool_token_amount":35058196225490404}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":35177013853902416,"pool_token_amount":35058313023837521}],[37,{"sui_amount":35171316973611639,"pool_token_amount":35057962139031474}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":35165771071166302,"pool_token_amount":35057887765722777}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":35126902103848439,"pool_token_amount":35036297323031852}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":35106194827453728,"pool_token_amount":35045240623781731}],[27,{"sui_amount":35103941465434498,"pool_token_amount":35049411290733502}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":25000000032208364,"pool_token_amount":25000000000644154}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":25000000000000000,"pool_token_amount":25000000000000000}]],"Stakely":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":27762804674573226,"pool_token_amount":27199200600475944}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":27743098486923114,"pool_token_amount":27196775892784810}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":27732469848657900,"pool_token_amount":27196718482713363}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[150,{"sui_amount":27710201021493154,"pool_token_amount":27195612998543851}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[145,{"sui_amount":27683882992364250,"pool_token_amount":27187082002344788}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":27629374598619965,"pool_token_amount":27185523459846181}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":27625655415303010,"pool_token_amount":27185338617921749}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":27603424425082252,"pool_token_amount":27187762942494988}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":27596067377921217,"pool_token_amount":27187462435319588}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":27585533103239935,"pool_token_amount":27187503467571946}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":27556453630039662,"pool_token_amount":27187027624947083}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":27535936260173896,"pool_token_amount":27194598631996849}],[99,{"sui_amount":27511267383932034,"pool_token_amount":27182188529984450}],[98,{"sui_amount":27507792550651420,"pool_token_amount":27182732270956926}],[97,{"sui_amount":27503581441579801,"pool_token_amount":27182518659522367}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":27461600250504285,"pool_token_amount":27179562099774593}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":27434297111797914,"pool_token_amount":27179577440624487}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":27421175524007266,"pool_token_amount":27181964004608183}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":27402305571673416,"pool_token_amount":27182936076681587}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":27397994565696040,"pool_token_amount":27182745919002039}],[69,{"sui_amount":27244236581933108,"pool_token_amount":27034283113713075}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":27235203391400133,"pool_token_amount":27033490810244142}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":27225992980288273,"pool_token_amount":27036295924553270}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":27220480473093076,"pool_token_amount":27034596346580647}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":27209635066632573,"pool_token_amount":27035150867820853}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":27196945826155067,"pool_token_amount":27030095957215174}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":27167878738824695,"pool_token_amount":27024191738104784}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":27162941571490818,"pool_token_amount":27023166485975317}],[50,{"sui_amount":27156202563211104,"pool_token_amount":27020348420524822}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":27153439548901120,"pool_token_amount":27021486381704188}],[47,{"sui_amount":27145158353963145,"pool_token_amount":27021020780682951}],[46,{"sui_amount":27142588929943663,"pool_token_amount":27022351914550034}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":27129697034533784,"pool_token_amount":27021183828583049}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":27116594222406354,"pool_token_amount":27015915627013999}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[40,{"sui_amount":27111277814971973,"pool_token_amount":27014511243154113}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":27100623872868049,"pool_token_amount":27011682582791398}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":27092866808465014,"pool_token_amount":27011973927133025}],[35,{"sui_amount":27087770359920184,"pool_token_amount":27011103729559939}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":27068074938619894,"pool_token_amount":27004424290727303}],[32,{"sui_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"sui_amount":27062932318606154,"pool_token_amount":27003613420603570}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":20023317397249717,"pool_token_amount":20004881001927239}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":20000000015316901,"pool_token_amount":20000000000306326}],[16,{"sui_amount":20000000007017893,"pool_token_amount":20000000000140348}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":20000000000475400,"pool_token_amount":20000000000009502}],[12,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":20000000000000000,"pool_token_amount":20000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Staketab":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":27555917617214541,"pool_token_amount":27028831210170886}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":27537897281789926,"pool_token_amount":27027168813617822}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":27533977134068662,"pool_token_amount":27026597389419518}],[156,{"sui_amount":27526407480514259,"pool_token_amount":27025719869659726}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":27522714519445620,"pool_token_amount":27025371253632667}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":27515099203721423,"pool_token_amount":27024449409796747}],[151,{"sui_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"sui_amount":27477392712972315,"pool_token_amount":27010276147430573}],[145,{"sui_amount":27473030428918954,"pool_token_amount":27009185150604109}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":27451174599059268,"pool_token_amount":27006870426367889}],[138,{"sui_amount":27447533288380145,"pool_token_amount":27006488342781624}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":27414922994538640,"pool_token_amount":27003207585342578}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":27390404246196049,"pool_token_amount":27001477710451867}],[120,{"sui_amount":27382011107480852,"pool_token_amount":26999611625474993}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":27374775646369830,"pool_token_amount":26998885777949133}],[117,{"sui_amount":91735889242077333,"pool_token_amount":39881683429017994}],[116,{"sui_amount":27367385078862758,"pool_token_amount":26998005390096765}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":27362481215864858,"pool_token_amount":26996373013833813}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":27344896545444415,"pool_token_amount":26998618211333503}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":27340882941424173,"pool_token_amount":26998221934802815}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[102,{"sui_amount":27315809573589787,"pool_token_amount":26995752363268394}],[101,{"sui_amount":27311666811173158,"pool_token_amount":26995342938273299}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":27289054943396904,"pool_token_amount":26998832561499814}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":27284989813072721,"pool_token_amount":26998430370946556}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":27264745509457303,"pool_token_amount":26996432113353037}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":27229625151539937,"pool_token_amount":26994054599636048}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":27226239705397537,"pool_token_amount":26997842193840795}],[74,{"sui_amount":27215053407122431,"pool_token_amount":26997461837242754}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":27189472265138274,"pool_token_amount":26994710683274801}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"sui_amount":27175727505458259,"pool_token_amount":27010559565408948}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":27158903687748346,"pool_token_amount":27008153575345101}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":27146138918396074,"pool_token_amount":27006402012356652}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":27142024176289873,"pool_token_amount":27005990865758226}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":27125523738314235,"pool_token_amount":27004302272438978}],[45,{"sui_amount":27121971079142759,"pool_token_amount":27011820191091292}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":27113731248697735,"pool_token_amount":27010985160960882}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"sui_amount":27092555696710581,"pool_token_amount":27000950067280571}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":27080108363178739,"pool_token_amount":26999717228605699}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":27071387534543246,"pool_token_amount":26998818996204802}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":27058031309906146,"pool_token_amount":26997778994559239}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":27039340575876393,"pool_token_amount":26995715327430054}],[27,{"sui_amount":27034342941288914,"pool_token_amount":26995222681248733}],[25,{"sui_amount":20025411726048901,"pool_token_amount":20003828758669413}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":20010986044009000,"pool_token_amount":20001825795265510}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":20004689113804701,"pool_token_amount":20000114706287817}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":20000000015327401,"pool_token_amount":20000000000306536}],[17,{"sui_amount":20000000012338901,"pool_token_amount":20000000000246767}],[16,{"sui_amount":20000000007028393,"pool_token_amount":20000000000140558}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":20000000000537500,"pool_token_amount":20000000000010743}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":20000000000455800,"pool_token_amount":20000000000009112}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":20000000000442900,"pool_token_amount":20000000000008856}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Stakin":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":27575508880189594,"pool_token_amount":27061004051953791}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":27566501426013069,"pool_token_amount":27058716161008865}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":27549988859924576,"pool_token_amount":27052335579276793}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"sui_amount":27517424711541047,"pool_token_amount":27043300299443701}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":27513103678217411,"pool_token_amount":27042336575162531}],[146,{"sui_amount":27509371889643755,"pool_token_amount":27041952089102544}],[145,{"sui_amount":27505755239687262,"pool_token_amount":27041594050593172}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":27495399421682722,"pool_token_amount":27040999738079456}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":27486936528327654,"pool_token_amount":27039069271433442}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":27476093400938358,"pool_token_amount":27038002498260332}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":27468850726419136,"pool_token_amount":27037276654950700}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":27461622674899420,"pool_token_amount":27036563575885117}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":27458100601288283,"pool_token_amount":27036298132288842}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":27454555680072654,"pool_token_amount":27036010586084730}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":27446984131365825,"pool_token_amount":27034963386775665}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":27425068856232969,"pool_token_amount":27032594179359398}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":27421456251278487,"pool_token_amount":27032238088340317}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":27399261666862837,"pool_token_amount":27042396941149216}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":27391978430506321,"pool_token_amount":27041623884697743}],[109,{"sui_amount":27387963095929566,"pool_token_amount":27041226509208606}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":27386231461853520,"pool_token_amount":27088072831253007}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":27382043837888817,"pool_token_amount":27087658626962945}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":27365280853188209,"pool_token_amount":27085755709646799}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":27302635193000921,"pool_token_amount":27030956155841233}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":27278821950185709,"pool_token_amount":27025323830464924}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":27278808081704576,"pool_token_amount":27032457683621908}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":27271579123086174,"pool_token_amount":27032639620305906}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":27267571735751802,"pool_token_amount":27032241411265673}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":27255562199026961,"pool_token_amount":27031047987911888}],[75,{"sui_amount":27251680474962789,"pool_token_amount":27030769617816815}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":27239131789191871,"pool_token_amount":27029336014489962}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":27234080908482857,"pool_token_amount":27035743536733032}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":27229746787207876,"pool_token_amount":27035313281007594}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":27221062329323628,"pool_token_amount":27034436320075600}],[65,{"sui_amount":27216728157947731,"pool_token_amount":27034005874416138}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":27212732378521767,"pool_token_amount":27033613453075020}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":27208731321326570,"pool_token_amount":27033215980915191}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":27192024047369767,"pool_token_amount":27030926846579831}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":27159578151927257,"pool_token_amount":27020346281089708}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"sui_amount":27143820725663105,"pool_token_amount":27026768106695547}],[46,{"sui_amount":27139700173170968,"pool_token_amount":27026350211342309}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":27130375940233374,"pool_token_amount":27028121227533376}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"sui_amount":27120986001695752,"pool_token_amount":27026141234095889}],[40,{"sui_amount":27115541647140552,"pool_token_amount":27024404158250367}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":20023961849970848,"pool_token_amount":20006654446950867}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":20004728736001501,"pool_token_amount":20000154319424337}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"sui_amount":20000000012338901,"pool_token_amount":20000000000246767}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Staking Defense League":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":41589390909004724,"pool_token_amount":40779872762468142}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":41573059098495481,"pool_token_amount":40778271180951176}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":41515607426649619,"pool_token_amount":40772179324043950}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"sui_amount":41487423806768891,"pool_token_amount":40769405448992558}],[145,{"sui_amount":41481802344267042,"pool_token_amount":40768853031124541}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":41484241299934774,"pool_token_amount":40786164747535722}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":41428034837938967,"pool_token_amount":40780636542251781}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":41416789910967757,"pool_token_amount":40779529553409871}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":41411163904123583,"pool_token_amount":40778975608609681}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":41405538219391962,"pool_token_amount":40778421627807354}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":41377441713567337,"pool_token_amount":40775653852953090}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":41371822106142396,"pool_token_amount":40775100064840633}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":35498196780249327,"pool_token_amount":34994650837725555}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":35488768671482907,"pool_token_amount":34993721344439502}],[117,{"sui_amount":35484055533906847,"pool_token_amount":34993256604889595}],[116,{"sui_amount":35479429467909791,"pool_token_amount":34992877513166796}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":35451096837039328,"pool_token_amount":34990037873131755}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":35440508063895202,"pool_token_amount":34988896763678047}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":45415904083807471,"pool_token_amount":44857743912401435}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[100,{"sui_amount":45380081969167486,"pool_token_amount":44854211843004424}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":45338035680086889,"pool_token_amount":44849998432518196}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":45331034622984296,"pool_token_amount":44849305862197779}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":45317274901866990,"pool_token_amount":44847946203968320}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":45283031296197958,"pool_token_amount":44844748120281644}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":45254682112820120,"pool_token_amount":44841291120258393}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":45219871280311440,"pool_token_amount":44837752160245628}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":45194810025728462,"pool_token_amount":44850204563661523}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":45173126486028363,"pool_token_amount":44848047074663042}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":45151288109954348,"pool_token_amount":44845728488899256}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":45123822311418323,"pool_token_amount":44842986528506672}],[60,{"sui_amount":45116923277931781,"pool_token_amount":44842294658088747}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":45103522846433733,"pool_token_amount":44841302753665685}],[56,{"sui_amount":45089756271097682,"pool_token_amount":44839947494130659}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":45062502457404793,"pool_token_amount":44837216996102204}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":45059691790172764,"pool_token_amount":44852637337875491}],[48,{"sui_amount":45052799597026860,"pool_token_amount":44851950389732427}],[47,{"sui_amount":45046020568717871,"pool_token_amount":44851275509046702}],[45,{"sui_amount":45032357926560628,"pool_token_amount":44849821402930483}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":45025461810379289,"pool_token_amount":44849129208505913}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"sui_amount":45004051758373241,"pool_token_amount":44846534484016339}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":44982996686817694,"pool_token_amount":44844395232437029}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":35082384491653355,"pool_token_amount":34994678797247816}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":35070561943877156,"pool_token_amount":34993474331145170}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":25000000019836964,"pool_token_amount":25000000001983684}],[16,{"sui_amount":25000000008826354,"pool_token_amount":25000000000882626}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":25000000000577800,"pool_token_amount":25000000000057775}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":25000000000577800,"pool_token_amount":25000000000057775}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":25000000000577800,"pool_token_amount":25000000000057775}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":25000000000572400,"pool_token_amount":25000000000057236}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":25000000000556200,"pool_token_amount":25000000000055618}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Staking Facilities":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":65596897858751769,"pool_token_amount":64288423150902756}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[145,{"sui_amount":65654257542050518,"pool_token_amount":64492508287812106}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":65635634723391625,"pool_token_amount":64490707234424425}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":65617580477757339,"pool_token_amount":64489456367395709}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":65560867847675182,"pool_token_amount":64483237982639866}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":65532936698511152,"pool_token_amount":64480542701123361}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":65524005328117875,"pool_token_amount":64480019135612364}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":65495290562874055,"pool_token_amount":64476383177884223}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":65705961139311638,"pool_token_amount":64716897002302479}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":65697031663730445,"pool_token_amount":64716369298175783}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":65678932368526141,"pool_token_amount":64715078317126431}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":65651952912925215,"pool_token_amount":64713297859251826}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":65583790492388076,"pool_token_amount":64712270280210802}],[109,{"sui_amount":65575653514262477,"pool_token_amount":64713446353294326}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":65554503871618459,"pool_token_amount":64711087491542211}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[97,{"sui_amount":65450807655223615,"pool_token_amount":64702506716907789}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":35435341382817915,"pool_token_amount":35035162493583824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":35424463713391868,"pool_token_amount":35034292449189658}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":35419043539939188,"pool_token_amount":35033863610358739}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":35388894543311478,"pool_token_amount":35028303307286196}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":35383510103052327,"pool_token_amount":35027876940787653}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":35378127588205647,"pool_token_amount":35027450667108266}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":35372768949161209,"pool_token_amount":35027024790555343}],[84,{"sui_amount":35367426593697774,"pool_token_amount":35026601591703889}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":35345935105873218,"pool_token_amount":35024888494730500}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":35340687563593972,"pool_token_amount":35024558370610554}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":35318247425999665,"pool_token_amount":35021778767447313}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":35295552173327280,"pool_token_amount":35019247971593362}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":35284324898515687,"pool_token_amount":35018257434340198}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":35267854799123045,"pool_token_amount":35017131651532658}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":35235121987392150,"pool_token_amount":35014071918194498}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":35229787854173018,"pool_token_amount":35013647864659326}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":35207448553176079,"pool_token_amount":35010956836127238}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":35201359725602092,"pool_token_amount":35009782639848292}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":35169387207701523,"pool_token_amount":35007271886167993}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":35136910938706813,"pool_token_amount":35004254822217761}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"sui_amount":35131153660825246,"pool_token_amount":35003409208225707}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":35098604898359189,"pool_token_amount":35001473583976443}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":35087204785469941,"pool_token_amount":35000916212725753}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":35081064667562852,"pool_token_amount":35000207790819527}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":25007401238205152,"pool_token_amount":25001628428764371}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"sui_amount":25000000015495364,"pool_token_amount":25000000000309897}],[16,{"sui_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":25000000000691200,"pool_token_amount":25000000000013816}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":25000000000550800,"pool_token_amount":25000000000011015}],[0,{"sui_amount":0,"pool_token_amount":0}]],"StakingCabin":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":153253153410074065,"pool_token_amount":150056789711924972}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":153232905650128209,"pool_token_amount":150055996693250359}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":153212659715077485,"pool_token_amount":150055203645477580}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":153087263235998544,"pool_token_amount":150048857899683080}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":153068686571206791,"pool_token_amount":150050271441464400}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":153031485245977317,"pool_token_amount":150072683686244135}],[150,{"sui_amount":152989366284571285,"pool_token_amount":150070638993492354}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":152931118110432845,"pool_token_amount":150072236623617762}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":152524593634717832,"pool_token_amount":150062582648464462}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":152462713432141938,"pool_token_amount":150059983352337341}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":152448679022560641,"pool_token_amount":150065606798658195}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":152290389708022856,"pool_token_amount":150065620752103073}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":152155917411270170,"pool_token_amount":150052562350534343}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":152110750512204785,"pool_token_amount":150051612372469433}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":152039183752302053,"pool_token_amount":150048797635177739}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":152015212491910670,"pool_token_amount":150047853239976803}],[102,{"sui_amount":151991388266654612,"pool_token_amount":150046914504113697}],[101,{"sui_amount":151967682474336265,"pool_token_amount":150045978400469060}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":151858670280952878,"pool_token_amount":150049942044590428}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":151718465648767935,"pool_token_amount":150043325924071795}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":151625780726125033,"pool_token_amount":150060748897046474}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":151593128828421776,"pool_token_amount":150071898370452002}],[82,{"sui_amount":151570034221471092,"pool_token_amount":150070719944872053}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":151546919523532999,"pool_token_amount":150069519351685532}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":151453147635780648,"pool_token_amount":150064119405585092}],[76,{"sui_amount":151429891612838617,"pool_token_amount":150062744927155515}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":151415117448487144,"pool_token_amount":150069780704368660}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":151369196708294556,"pool_token_amount":150068260901878185}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":151320732046712979,"pool_token_amount":150065908629023405}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":211342511247333584,"pool_token_amount":209825360086523094}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":211158031429948576,"pool_token_amount":209793669193123472}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":211031151005243615,"pool_token_amount":209819943500254598}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":210952300310995334,"pool_token_amount":209802869977476433}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"sui_amount":210759081778546902,"pool_token_amount":209794802776820019}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":210694239236732270,"pool_token_amount":209791638127519084}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":210662116757723265,"pool_token_amount":209790354434862410}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":150549849069866022,"pool_token_amount":150016029618847034}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":170517866660301934,"pool_token_amount":169994363346912355}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":170400864064812041,"pool_token_amount":169988919273662947}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"sui_amount":200183190770187480,"pool_token_amount":199955186355126146}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":150108379972026044,"pool_token_amount":150004272677911561}],[22,{"sui_amount":150071728832923326,"pool_token_amount":150002623246420502}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":150036202666533445,"pool_token_amount":150001458813436172}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":150000000116171591,"pool_token_amount":150000000002323420}],[17,{"sui_amount":150000000093514591,"pool_token_amount":150000000001870281}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":150000000004141300,"pool_token_amount":150000000000082818}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":150000000003652300,"pool_token_amount":150000000000073040}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":150000000003391500,"pool_token_amount":150000000000067827}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":150000000003391500,"pool_token_amount":150000000000067827}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"Stardust Staking":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":35778494725565083,"pool_token_amount":35073149779274828}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":35759755462514268,"pool_token_amount":35071496197434013}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":35745972448646927,"pool_token_amount":35070682610666804}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":35731538428723176,"pool_token_amount":35069407932593938}],[154,{"sui_amount":35726726596379057,"pool_token_amount":35068982892250647}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":35721685102591668,"pool_token_amount":35068332555397017}],[152,{"sui_amount":35716826985735807,"pool_token_amount":35067862218116071}],[149,{"sui_amount":35703114359368386,"pool_token_amount":35067296656174513}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":35678913876754869,"pool_token_amount":35065049402407726}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":38977559176067445,"pool_token_amount":38335729575021223}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":38966911873477944,"pool_token_amount":38334787037190842}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":38914850412939180,"pool_token_amount":38331203551919356}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":38898930663153034,"pool_token_amount":38329821727562882}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":38881478030281678,"pool_token_amount":38326927683648254}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":38860218949300669,"pool_token_amount":38325043117652156}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":38854900984164735,"pool_token_amount":38324568399426323}],[114,{"sui_amount":38849586163793115,"pool_token_amount":38324096594016597}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":38838927594249111,"pool_token_amount":38323125155925696}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":42151081194056583,"pool_token_amount":41596863519094964}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":42132652750213226,"pool_token_amount":41595227450356746}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":52056444453386477,"pool_token_amount":51415917397116259}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":52031729691151195,"pool_token_amount":51413721015003426}],[100,{"sui_amount":52015416176081777,"pool_token_amount":51412271933639465}],[99,{"sui_amount":52007280241252547,"pool_token_amount":51411548187929750}],[97,{"sui_amount":51991084555344837,"pool_token_amount":51410031789223495}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":51983027266398127,"pool_token_amount":51409235860654308}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":51958936992907766,"pool_token_amount":51406856366059933}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":51919136987398089,"pool_token_amount":51402544426338763}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":51872132630897834,"pool_token_amount":51397889348432529}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":51856213270542124,"pool_token_amount":51396309876980749}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":51825067250368015,"pool_token_amount":51393216482409327}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":51817176459492803,"pool_token_amount":51392336407210705}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":51809395893891385,"pool_token_amount":51391565501470854}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":51793268402749096,"pool_token_amount":51390055677054671}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":51760319291681407,"pool_token_amount":51386947841830299}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":51743680965611324,"pool_token_amount":51385325268277170}],[65,{"sui_amount":51735346020662207,"pool_token_amount":51384498373943926}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51727567726071925,"pool_token_amount":51383727491857613}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":51719863776449724,"pool_token_amount":51383031461021441}],[61,{"sui_amount":51704282609530115,"pool_token_amount":51381465274391862}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":35142602426512309,"pool_token_amount":34999549513637668}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":35137254143016319,"pool_token_amount":34999004844926209}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":35112012086131889,"pool_token_amount":34997877039897905}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"sui_amount":25037590623813189,"pool_token_amount":25005926672795173}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":25000000031979264,"pool_token_amount":25000000000639572}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"sui_amount":0,"pool_token_amount":0}]],"Swiss Staking":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":35798757682239192,"pool_token_amount":35075994939056683}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":35789106773149110,"pool_token_amount":35075032892012643}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":35751864319241262,"pool_token_amount":35068622694459546}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":35742342166202585,"pool_token_amount":35067966628012298}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":35727743941586011,"pool_token_amount":35066674264145731}],[150,{"sui_amount":35722932248248373,"pool_token_amount":35066296450710245}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[147,{"sui_amount":35708522545536717,"pool_token_amount":35065191535839632}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":35679157116836484,"pool_token_amount":35062458542959119}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":35669515239420536,"pool_token_amount":35061690532118812}],[138,{"sui_amount":35664696066549928,"pool_token_amount":35061311567354765}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":35645663868674448,"pool_token_amount":35060035794549354}],[133,{"sui_amount":35640752080890717,"pool_token_amount":35059564396435372}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":35616351599469710,"pool_token_amount":35057372822672378}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":35611686971684466,"pool_token_amount":35057053858144059}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":35606872490023622,"pool_token_amount":35056676526531131}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":35582121184840944,"pool_token_amount":35054118734857344}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":35573577872977145,"pool_token_amount":35054429182320264}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":35569270144035536,"pool_token_amount":35054548875250245}],[116,{"sui_amount":35559715110831034,"pool_token_amount":35053860423206290}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":35530439437369558,"pool_token_amount":35051287188644896}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":35490505034413253,"pool_token_amount":35046643261968294}],[99,{"sui_amount":35472148057722636,"pool_token_amount":35048579051835145}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":35435089732182461,"pool_token_amount":35046602393609556}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":35415836398284491,"pool_token_amount":35042191318077688}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":35406637385095450,"pool_token_amount":35042894217087270}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":35392539847304235,"pool_token_amount":35043585127873399}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":35375451118227688,"pool_token_amount":35041263852424451}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":35375340386446450,"pool_token_amount":35055862644462790}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":35376696482687083,"pool_token_amount":35071807296667227}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":35354535502310780,"pool_token_amount":35069806982602916}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":35328353525884868,"pool_token_amount":35059052233532652}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":35316142953283812,"pool_token_amount":35057080681604850}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":35277235088840784,"pool_token_amount":35033276033511741}],[62,{"sui_amount":35272097203286878,"pool_token_amount":35033047448844481}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":35256234315731302,"pool_token_amount":35031916610365508}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":35226209246111928,"pool_token_amount":35032301813125300}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":35220293146133644,"pool_token_amount":35031459078482784}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":35173241016600067,"pool_token_amount":35030024548813202}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[41,{"sui_amount":35162886175314225,"pool_token_amount":35029912602016803}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":35114731831469410,"pool_token_amount":35035847571516464}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":35088539377562827,"pool_token_amount":35027124942569709}],[25,{"sui_amount":25048007689290837,"pool_token_amount":25018853767181175}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":25042735627245832,"pool_token_amount":25025089583790887}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":25000000019248364,"pool_token_amount":25000000000384956}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":25000000000610200,"pool_token_amount":25000000000012198}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":25000000000000000,"pool_token_amount":25000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"SyncNode":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":35791326818787930,"pool_token_amount":35088758289283253}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":35776243126819896,"pool_token_amount":35090598739302893}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":35766825917489009,"pool_token_amount":35089675010996787}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":35736860359351263,"pool_token_amount":35090017113481804}],[150,{"sui_amount":35722379705184440,"pool_token_amount":35088555353628683}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"sui_amount":35706517766381152,"pool_token_amount":35089997459172609}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":35687053470046859,"pool_token_amount":35088085182445472}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":35682238837034242,"pool_token_amount":35087611799507039}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":35670629457807989,"pool_token_amount":35088984372269655}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":35660987617711495,"pool_token_amount":35088036736921603}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":35620312090612983,"pool_token_amount":35090867179161375}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":35558092116896998,"pool_token_amount":35059369822626981}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":35548589973006855,"pool_token_amount":35058455290773873}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":35541032405475837,"pool_token_amount":35059546792203036}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":35499836029678639,"pool_token_amount":35059409876526470}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":35488637411291369,"pool_token_amount":35058269156714914}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[100,{"sui_amount":35469768370377336,"pool_token_amount":35059338835645355}],[99,{"sui_amount":35464218019281961,"pool_token_amount":35058745741526967}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":35412882376215201,"pool_token_amount":35027408075839729}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":35403201373983190,"pool_token_amount":35027394685535199}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":35389441445370902,"pool_token_amount":35027926176098312}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":35384162678240767,"pool_token_amount":35027403691338491}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":35370232084560203,"pool_token_amount":35027904908125027}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":35355514831869865,"pool_token_amount":35027429296280525}],[82,{"sui_amount":35352852851032402,"pool_token_amount":35029556007176974}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":35336716416343841,"pool_token_amount":35027957808277853}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":35313166294708345,"pool_token_amount":35028415494033305}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":35307720342749960,"pool_token_amount":35027875290222055}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":35287509175790555,"pool_token_amount":35027675460623190}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":35234104166773319,"pool_token_amount":35027883334707887}],[56,{"sui_amount":35192353652691283,"pool_token_amount":34995819929136961}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":35187099794995758,"pool_token_amount":34995270628191435}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":35179632653122472,"pool_token_amount":34997396018077127}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":35164506673181211,"pool_token_amount":34996677605670439}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":35153841962853990,"pool_token_amount":34995620636151989}],[47,{"sui_amount":35150107373352441,"pool_token_amount":34996682350713804}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":35130572101588057,"pool_token_amount":34996352514620615}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":35125218134221081,"pool_token_amount":34995802128743484}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"sui_amount":35115526523032189,"pool_token_amount":34995714188292690}],[39,{"sui_amount":35112118398066697,"pool_token_amount":34997202810688916}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":35064771454393029,"pool_token_amount":34997224177682950}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":35046973389652898,"pool_token_amount":34990606731975758}],[26,{"sui_amount":25036780886670047,"pool_token_amount":25005151890543232}],[25,{"sui_amount":25032018195276228,"pool_token_amount":25005093653707674}],[24,{"sui_amount":25026169049945033,"pool_token_amount":25004250003880932}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":25013264464700365,"pool_token_amount":25002068628317055}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"SynergyNodes":[[167,{"sui_amount":35711973488397131,"pool_token_amount":34999579084893220}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":35703304665126911,"pool_token_amount":34999579173392202}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":35681830274195488,"pool_token_amount":34999587263939251}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":35668550012823683,"pool_token_amount":34999587329457781}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":35650720104633172,"pool_token_amount":34999466522936534}],[151,{"sui_amount":35642251017238150,"pool_token_amount":34999844670304153}],[149,{"sui_amount":35633012080680255,"pool_token_amount":34999466714899788}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"sui_amount":35624242641197734,"pool_token_amount":34999462158956603}],[146,{"sui_amount":35619914147116045,"pool_token_amount":34999471324332348}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":35606628758588605,"pool_token_amount":34999480921655847}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":35567371036903277,"pool_token_amount":34999463940676521}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":35550201038648822,"pool_token_amount":34999836387954911}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":35545479211370173,"pool_token_amount":34999464489192044}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":35510760786316251,"pool_token_amount":34999461996199143}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[118,{"sui_amount":35498127188891416,"pool_token_amount":34999833863114390}],[117,{"sui_amount":35493414051315356,"pool_token_amount":34999462104490310}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":35480383466141681,"pool_token_amount":34999440032278676}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":35476047053637811,"pool_token_amount":34999440089795714}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":35448532328213831,"pool_token_amount":34999501848747979}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":35436326440540295,"pool_token_amount":34997409392708235}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":35431327734612563,"pool_token_amount":34997429488963574}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[99,{"sui_amount":35406391217838728,"pool_token_amount":34997417936869707}],[98,{"sui_amount":35397636561402248,"pool_token_amount":34993658705474278}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":35348671269283555,"pool_token_amount":34993821233363631}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":35304576111031336,"pool_token_amount":34993336108694415}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":35281033541493148,"pool_token_amount":34993822729905847}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":35245453304624334,"pool_token_amount":34993828851906497}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":35235610614189585,"pool_token_amount":34994207663716338}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":35204096547790040,"pool_token_amount":34991545896486089}],[57,{"sui_amount":35194485465483141,"pool_token_amount":34991546050149754}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":35175051503562695,"pool_token_amount":34991541281078344}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":35156694455532143,"pool_token_amount":34992810551498211}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":35130331205959595,"pool_token_amount":34990994085135102}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":35125518757533072,"pool_token_amount":34991089049456378}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":35120129616885749,"pool_token_amount":34990609983115475}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":35105248694044705,"pool_token_amount":34990556412617032}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":35074278565517779,"pool_token_amount":34990910392585385}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":35064233564442748,"pool_token_amount":34991714388408580}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":35039628838964770,"pool_token_amount":34989635842359541}],[26,{"sui_amount":35034205124962368,"pool_token_amount":34990615288737785}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":25017678795897347,"pool_token_amount":25001650820581813}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":25006004474400779,"pool_token_amount":25000603107139777}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"sui_amount":25000000015495364,"pool_token_amount":25000000001549526}],[16,{"sui_amount":25000000008826354,"pool_token_amount":25000000000882626}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":25000000000675000,"pool_token_amount":25000000000067493}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":25000000000577800,"pool_token_amount":25000000000057775}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":25000000000577800,"pool_token_amount":25000000000057775}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":25000000000567000,"pool_token_amount":25000000000056697}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":25000000000567000,"pool_token_amount":25000000000056697}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":25000000000556200,"pool_token_amount":25000000000055618}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"TDMTech":[[167,{"sui_amount":27589557383739965,"pool_token_amount":27006016284351285}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":27575115492280906,"pool_token_amount":27005726784817025}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":27564294123755708,"pool_token_amount":27005514798228952}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":27539946807910348,"pool_token_amount":27010152010554934}],[151,{"sui_amount":27536237639530052,"pool_token_amount":27010079253818621}],[149,{"sui_amount":27525953208861926,"pool_token_amount":27007122425584929}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"sui_amount":27512311478767397,"pool_token_amount":27004442229950841}],[145,{"sui_amount":27508697681193527,"pool_token_amount":27004371287515646}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":27496923080337509,"pool_token_amount":27003235797564622}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":27477762695392705,"pool_token_amount":27001805026345815}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":27470551036770165,"pool_token_amount":27001678931973145}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":27462481065649381,"pool_token_amount":27011158301081466}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":27427590861707608,"pool_token_amount":27001223477261830}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":27423978256753126,"pool_token_amount":27001152347846300}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":27416475289877823,"pool_token_amount":27000733940396040}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":27390474461360573,"pool_token_amount":26999517966155011}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":27383304381562531,"pool_token_amount":26999425711441778}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":27375678335532911,"pool_token_amount":26999275317470334}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":27367529586153592,"pool_token_amount":26999104905488694}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":27350740082362819,"pool_token_amount":26998776465634339}],[102,{"sui_amount":27346461613600206,"pool_token_amount":26998692964694853}],[99,{"sui_amount":27333838922544972,"pool_token_amount":26998448545073645}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":27321426128460210,"pool_token_amount":26998203300021873}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":27313049568616745,"pool_token_amount":26998037736128407}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":27308873523706875,"pool_token_amount":26997957120788517}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":27292673832160874,"pool_token_amount":26997647480524988}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":27284595850068398,"pool_token_amount":26997487654799246}],[86,{"sui_amount":27280558963827675,"pool_token_amount":26997407766244965}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":27260240398843856,"pool_token_amount":26996739820062974}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":27255920954392158,"pool_token_amount":26996566918709735}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":27247975512134885,"pool_token_amount":26996471081178388}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":27333689366742490,"pool_token_amount":27096949858228020}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":27312562214718690,"pool_token_amount":27096524044523712}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":27303694024185715,"pool_token_amount":27096153620579071}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":27299360035559461,"pool_token_amount":27096067599671703}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":27282973201066937,"pool_token_amount":27095693575134032}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":27274953333869003,"pool_token_amount":27095517721445269}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":27048393710135736,"pool_token_amount":26992886488521080}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"sui_amount":27027576229189627,"pool_token_amount":26991373615238473}],[24,{"sui_amount":20018898351260217,"pool_token_amount":20000464418682403}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":20000000000537500,"pool_token_amount":20000000000010743}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":20000000000485900,"pool_token_amount":20000000000009712}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":20000000000455800,"pool_token_amount":20000000000009112}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":20000000000442900,"pool_token_amount":20000000000008856}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":20000000000438600,"pool_token_amount":20000000000008771}]],"TPT":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":117499746240642406,"pool_token_amount":115058061432529879}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":117484210584130362,"pool_token_amount":115057300791148522}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":117468671650545907,"pool_token_amount":115056539893710020}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":117453135002968465,"pool_token_amount":115055779012629097}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":117430883382578058,"pool_token_amount":115062883072540807}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":117415345688112094,"pool_token_amount":115062121853356406}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":117399305442574297,"pool_token_amount":115061335914501112}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":117335153965459233,"pool_token_amount":115058191604663668}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":117137973083202030,"pool_token_amount":115057947022319271}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":117090423281810635,"pool_token_amount":115055611447696023}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":117063450766057520,"pool_token_amount":115058735109841484}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":117031728290126876,"pool_token_amount":115057176046966478}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":117015871865292162,"pool_token_amount":115056396601636746}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":116972253781016022,"pool_token_amount":115057956389510601}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":116834124174893672,"pool_token_amount":115054905638482125}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":116711836485066823,"pool_token_amount":115052984218794069}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":116696783380523935,"pool_token_amount":115052984344838624}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":116666476520806176,"pool_token_amount":115052787630317866}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":116654188101776994,"pool_token_amount":115055520585119737}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":116618954805710732,"pool_token_amount":115053782937161860}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":116601231850585116,"pool_token_amount":115052912442796714}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"sui_amount":116496940114595933,"pool_token_amount":115052902093852188}],[98,{"sui_amount":116445324378069792,"pool_token_amount":115052894177834511}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":116376908195592509,"pool_token_amount":115052876149089546}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":116359953317159169,"pool_token_amount":115052870792566143}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":116295878377112979,"pool_token_amount":115055925357985270}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":116243132354310343,"pool_token_amount":115053398777954246}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":116096545293690412,"pool_token_amount":114957754101397365}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":116063379028252635,"pool_token_amount":114957787414592485}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":115996326837235975,"pool_token_amount":114957738593110886}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":115964794374914474,"pool_token_amount":114959343193170555}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":115814786520985803,"pool_token_amount":114948601345629952}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":115796228159445006,"pool_token_amount":114947680367499749}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":115713975562439083,"pool_token_amount":114949352743909091}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":115696510155077672,"pool_token_amount":114948472975594869}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":115608725706055891,"pool_token_amount":114943705785601381}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":115556233467574842,"pool_token_amount":114941279445508607}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":115325914401329057,"pool_token_amount":114946822613603152}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":115291139864358217,"pool_token_amount":114946786358335707}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":105257622392237026,"pool_token_amount":104976716952716637}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":105224512521195147,"pool_token_amount":104977642895881384}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":80057756688790512,"pool_token_amount":80002837191788368}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":80000000062001508,"pool_token_amount":80000000001240018}],[17,{"sui_amount":80000000049908508,"pool_token_amount":80000000000998159}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[0,{"sui_amount":0,"pool_token_amount":0}]],"TestnetPride":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":177178709111745073,"pool_token_amount":173413292207400062}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":177131916228080118,"pool_token_amount":173412031848405560}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":177082689656313381,"pool_token_amount":173408384664569309}],[161,{"sui_amount":177059361007521881,"pool_token_amount":173407699326354920}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":177011047893843814,"pool_token_amount":173405428359475633}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":176888633746643387,"pool_token_amount":173399998093165993}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":176864346361206767,"pool_token_amount":173399067833898533}],[151,{"sui_amount":176816389275148742,"pool_token_amount":173398002873527725}],[149,{"sui_amount":176698738437162807,"pool_token_amount":173328400086966604}],[148,{"sui_amount":176674771194357695,"pool_token_amount":173327688408663644}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":176656954633652387,"pool_token_amount":173401225355031251}],[143,{"sui_amount":176631798490337802,"pool_token_amount":173399261018362977}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":176465802758189163,"pool_token_amount":173395136475029286}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":176287522439523524,"pool_token_amount":173379169953361251}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":176190096547649618,"pool_token_amount":173374131090885463}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":176141474241278185,"pool_token_amount":173371680334419857}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":176069648916780400,"pool_token_amount":173369087132984374}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":175952549873027836,"pool_token_amount":173367577802077591}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":175678904178362112,"pool_token_amount":173288181993736959}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":175567985049971171,"pool_token_amount":173284378379731034}],[102,{"sui_amount":175540458657775204,"pool_token_amount":173283564286315090}],[98,{"sui_amount":175430933344871918,"pool_token_amount":173280025226665064}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":175377163391528304,"pool_token_amount":173278817199809780}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":175350113598410558,"pool_token_amount":173278015402677193}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":175058436456472454,"pool_token_amount":173270106952862389}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":174978771924513301,"pool_token_amount":173267015967534966}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":174908907485673130,"pool_token_amount":173274461030400900}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":174830164618878786,"pool_token_amount":173272079415921334}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":234721706499276583,"pool_token_amount":233032101986549935}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":234614903470417633,"pool_token_amount":233028171819224059}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":234470351423429228,"pool_token_amount":233020905176676076}],[56,{"sui_amount":234435276020206761,"pool_token_amount":233020226876596945}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":234397686763977888,"pool_token_amount":233017155972850453}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":234325145049780864,"pool_token_amount":233013851381616593}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":234234500827422372,"pool_token_amount":233026956166094067}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":234055168347464797,"pool_token_amount":233020784253925607}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"sui_amount":173985000713418685,"pool_token_amount":173345267404012439}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":173927420932867858,"pool_token_amount":173366689954421297}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":203449412632413171,"pool_token_amount":203136281767622411}],[26,{"sui_amount":203384427705029963,"pool_token_amount":203111132495227021}],[25,{"sui_amount":203338218887619243,"pool_token_amount":203106570302539433}],[24,{"sui_amount":173297867115400822,"pool_token_amount":173137507758920081}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":153260301729060518,"pool_token_amount":153153971066438216}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[17,{"sui_amount":150000000093514591,"pool_token_amount":150000000001870281}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":150000000004141300,"pool_token_amount":150000000000082818}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":150000000004043500,"pool_token_amount":150000000000080863}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":150000000003326900,"pool_token_amount":150000000000066536}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":150000000003294600,"pool_token_amount":150000000000065891}]],"Triton One":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":198991009805458895,"pool_token_amount":194785864649637002}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":198803728897897046,"pool_token_amount":194778876201495653}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":198768027370344087,"pool_token_amount":194872556779211613}],[151,{"sui_amount":198719341333845034,"pool_token_amount":194876309294530149}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":203737325869460339,"pool_token_amount":200086888375657790}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":203560143524387067,"pool_token_amount":199991474108306424}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":203505845699295916,"pool_token_amount":199990554815261384}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":203276280400971599,"pool_token_amount":199974647969004350}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":203412797808014374,"pool_token_amount":200266391800596439}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":203333980585887146,"pool_token_amount":200215037851992091}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":203306498198861744,"pool_token_amount":200214226026559132}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":203224091735731705,"pool_token_amount":200212009473236461}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":203172378702422825,"pool_token_amount":200213770673772247}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":203090108141743260,"pool_token_amount":200211689944467682}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":203062656841151321,"pool_token_amount":200210914993052867}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":202965764665155526,"pool_token_amount":200203247006383330}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":202934080145268489,"pool_token_amount":200202317066556481}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[100,{"sui_amount":202742868116663072,"pool_token_amount":200196394297017248}],[97,{"sui_amount":202648954193533223,"pool_token_amount":200193612818845603}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":202614698798565489,"pool_token_amount":200189786749588769}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":202595567579273229,"pool_token_amount":200200823927421286}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":202491211098378176,"pool_token_amount":200186969630967513}],[91,{"sui_amount":202445950072728454,"pool_token_amount":200171612022406513}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":202329178176887505,"pool_token_amount":200114871742331488}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":202194407932305893,"pool_token_amount":200069722219844067}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":172166816115626413,"pool_token_amount":170382623233018610}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":171822855443734707,"pool_token_amount":170315948414895472}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":171796287535230526,"pool_token_amount":170315153560280824}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":171741750462219965,"pool_token_amount":170313456227177298}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":171714511808886425,"pool_token_amount":170312646843633573}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":231746433387505864,"pool_token_amount":230078225440051694}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[57,{"sui_amount":231498962012049306,"pool_token_amount":230067889799375063}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":231428703108166560,"pool_token_amount":230065674515928084}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":231245681084855439,"pool_token_amount":230053602489739875}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":231210111514283364,"pool_token_amount":230052213776373398}],[47,{"sui_amount":231139380498801780,"pool_token_amount":230049950628451325}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":230998199769007888,"pool_token_amount":230045478693494553}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":170872659228154180,"pool_token_amount":170270078109020074}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":170845499009182599,"pool_token_amount":170268807990236286}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":170788779790350746,"pool_token_amount":170264550347116954}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":170729590965583526,"pool_token_amount":170260897998974284}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":170675580515823623,"pool_token_amount":170263223647232491}],[31,{"sui_amount":170642085918564367,"pool_token_amount":170257885411481016}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":150293042126533445,"pool_token_amount":150258238797174382}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":150000000119670491,"pool_token_amount":150000000002393397}],[18,{"sui_amount":150000000116171591,"pool_token_amount":150000000002323420}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":150000000003652300,"pool_token_amount":150000000000073040}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":150000000003456700,"pool_token_amount":150000000000069129}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":150000000003391500,"pool_token_amount":150000000000067827}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":150000000003294600,"pool_token_amount":150000000000065891}]],"XPRV":[[167,{"sui_amount":28433832350657133,"pool_token_amount":27875846984865131}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":28430123044483991,"pool_token_amount":27875483333005919}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":28415270159743620,"pool_token_amount":27874010950271860}],[161,{"sui_amount":28411565610188536,"pool_token_amount":27873647551624501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":28407856611839968,"pool_token_amount":27873283673695788}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":28396378874143627,"pool_token_amount":27872113208804441}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":28380930792358347,"pool_token_amount":27870409842497367}],[151,{"sui_amount":28373321947038933,"pool_token_amount":27869671575611086}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"sui_amount":28354278425753637,"pool_token_amount":27867808553436391}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":28342836972707198,"pool_token_amount":27866683015536441}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":28335221206819440,"pool_token_amount":27865940037890630}],[140,{"sui_amount":28331409297372993,"pool_token_amount":27865565159656615}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":28327596761967368,"pool_token_amount":27865190174444731}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":28323776583305287,"pool_token_amount":27864809965324529}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":28316137667830062,"pool_token_amount":27864053978178374}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":28308510745998865,"pool_token_amount":27863303416345808}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":28263641571739343,"pool_token_amount":27859062577389535}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":28237058775138396,"pool_token_amount":27856437072776569}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":28196478128337676,"pool_token_amount":27852393635110356}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":28187644101162435,"pool_token_amount":27851520057106231}],[101,{"sui_amount":28178877056040005,"pool_token_amount":27850654633191608}],[99,{"sui_amount":28170163272643066,"pool_token_amount":27849793340004021}],[98,{"sui_amount":28165814877641750,"pool_token_amount":27849366120281138}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":28153013194036144,"pool_token_amount":27848216170649063}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":28144419075122907,"pool_token_amount":27847365114938084}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":28098841278417034,"pool_token_amount":27842967945084509}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":28078020626674975,"pool_token_amount":27840889999744788}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":28069794830501462,"pool_token_amount":27840072528342575}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":28061439854505913,"pool_token_amount":27839226853117436}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":28052768891035579,"pool_token_amount":27838364777449858}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":28035087349683527,"pool_token_amount":27836603064909454}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":28030642233143878,"pool_token_amount":27836161700329014}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":28004629189679650,"pool_token_amount":27832677511120410}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":28000517461989130,"pool_token_amount":27832268862996942}],[57,{"sui_amount":27992301344023125,"pool_token_amount":27831459306861029}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":27984053892141673,"pool_token_amount":27830718554664686}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":27975530426034577,"pool_token_amount":27829802754784297}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":27954593676026232,"pool_token_amount":27827880873840843}],[46,{"sui_amount":27946140285737349,"pool_token_amount":27827032858066130}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":27914725117342875,"pool_token_amount":27822342378992317}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":27905986683322338,"pool_token_amount":27821416570911152}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":27901622991657448,"pool_token_amount":27820973448928955}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":27881703017381339,"pool_token_amount":27817776935090289}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":27036225833098401,"pool_token_amount":26995215285790416}],[24,{"sui_amount":20020118981025677,"pool_token_amount":20001684160504849}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":20015286295222270,"pool_token_amount":20001432914590529}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":20000000000442900,"pool_token_amount":20000000000008856}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[1,{"sui_amount":20000000000000000,"pool_token_amount":20000000000000000}]],"[NODERS]TEAM x Criterion VC":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":35685512405161687,"pool_token_amount":34990548761264640}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":35680901822951009,"pool_token_amount":34990096681652182}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":35662463274914515,"pool_token_amount":34988288208345689}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":35642456906122631,"pool_token_amount":34989726080558016}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[151,{"sui_amount":35621104854325186,"pool_token_amount":34990022922078565}],[149,{"sui_amount":35611480944552159,"pool_token_amount":34989077523002324}],[145,{"sui_amount":35594889267432401,"pool_token_amount":34989542229932358}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":35590171279848642,"pool_token_amount":34989078454243244}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":35581044976198111,"pool_token_amount":34988447645272869}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":35548026481556977,"pool_token_amount":34989379385759977}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":35501793539658555,"pool_token_amount":34989849349375010}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":35487648765784962,"pool_token_amount":34988456000772605}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":35482934633353872,"pool_token_amount":34987991218365342}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":35468034376982322,"pool_token_amount":34990030976442642}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":35453844070558531,"pool_token_amount":34988586502645621}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":35445163166658383,"pool_token_amount":34988394493978352}],[109,{"sui_amount":35439922360567106,"pool_token_amount":34987877166531510}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":35440110211606420,"pool_token_amount":34992719167325704}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":35434758674125628,"pool_token_amount":34992190768893508}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":35418339698927867,"pool_token_amount":34990569140492434}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[102,{"sui_amount":35407433979698612,"pool_token_amount":34989491657954172}],[99,{"sui_amount":35391249803911875,"pool_token_amount":34987893899063425}],[98,{"sui_amount":35386401982332557,"pool_token_amount":34987889991339302}],[97,{"sui_amount":35383222820365260,"pool_token_amount":34989500349815882}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":35377775638657477,"pool_token_amount":34988961691698808}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":35372343045750659,"pool_token_amount":34988424401982961}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":35365301066186645,"pool_token_amount":34991022246494472}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":35359994224662397,"pool_token_amount":34990498071016053}],[90,{"sui_amount":35349418781117843,"pool_token_amount":34989453291537979}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":35324124581544146,"pool_token_amount":34987881955006384}],[84,{"sui_amount":35319415609361708,"pool_token_amount":34987881023750211}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":35303911537176922,"pool_token_amount":34986513188134171}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":35295011936511709,"pool_token_amount":34991884415352838}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":35274119560355052,"pool_token_amount":34989817205668296}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":35263207797353194,"pool_token_amount":34988716894055157}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":35239041836218477,"pool_token_amount":34989555962055678}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":35217483964757468,"pool_token_amount":34987416784401823}],[61,{"sui_amount":35207027086995165,"pool_token_amount":34986368916024809}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":35181936707389152,"pool_token_amount":34989466908485596}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[47,{"sui_amount":35144558372430937,"pool_token_amount":34990496893732683}],[46,{"sui_amount":35139223817847847,"pool_token_amount":34989965776752999}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":35128550386908021,"pool_token_amount":34988898413175756}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":35090088100129445,"pool_token_amount":34999855819793100}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":35084201632528454,"pool_token_amount":34999274082785235}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":35072407836900776,"pool_token_amount":34998097472524947}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":35056903087806092,"pool_token_amount":34999119511241006}],[27,{"sui_amount":35050340429815906,"pool_token_amount":34998463428624354}],[26,{"sui_amount":25044566109124850,"pool_token_amount":25011994690715090}],[25,{"sui_amount":25039340119345633,"pool_token_amount":25011473670993887}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[23,{"sui_amount":25017803301414388,"pool_token_amount":25000952838081825}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"flipside":[[167,{"sui_amount":27532373588994884,"pool_token_amount":26995323800644628}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":27512992500354338,"pool_token_amount":26995423737105904}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":27499708296725803,"pool_token_amount":26995402304595710}],[156,{"sui_amount":27496370603089881,"pool_token_amount":26995402367441105}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":27493032755888594,"pool_token_amount":26995402447128066}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":27482834538446799,"pool_token_amount":26995222616107719}],[150,{"sui_amount":27476129200268487,"pool_token_amount":26995194240137059}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":27451230606734737,"pool_token_amount":26996542467427820}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":27447619631841414,"pool_token_amount":26996187350498645}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":27440400474450271,"pool_token_amount":26995480807183917}],[138,{"sui_amount":27436786094629896,"pool_token_amount":26995125228977740}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":27471345006980257,"pool_token_amount":27038746789141594}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":27467732150258859,"pool_token_amount":27038391192233070}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":27461064798095201,"pool_token_amount":27038230916663063}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":27457450485634085,"pool_token_amount":27037875050059726}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":27428550802606367,"pool_token_amount":27035037065133579}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[117,{"sui_amount":27406886151991049,"pool_token_amount":27032902834648847}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":27392465674457751,"pool_token_amount":27031497979236754}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":27385243770109695,"pool_token_amount":27030784374385394}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":27377597724080075,"pool_token_amount":27030011849113484}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":27369458974700756,"pool_token_amount":27029208252576632}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":27365225673870635,"pool_token_amount":27028790182019597}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[102,{"sui_amount":27348390991217020,"pool_token_amount":27027130618303913}],[100,{"sui_amount":27340172278468169,"pool_token_amount":27026570787440683}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[95,{"sui_amount":27318548597338802,"pool_token_amount":27023633611815261}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":27293010945122241,"pool_token_amount":27020251629358645}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":27288971293336854,"pool_token_amount":27019851700870231}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":27268866621258136,"pool_token_amount":27017862153907054}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":27253088766137304,"pool_token_amount":27016718970621909}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":27249085196039786,"pool_token_amount":27016321199007480}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":27241079235156409,"pool_token_amount":27015525604577592}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":27220500732480903,"pool_token_amount":27013469059909230}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":27203269321719891,"pool_token_amount":27011756872847752}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[60,{"sui_amount":27174554896427157,"pool_token_amount":27008867932340924}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":27166127501878763,"pool_token_amount":27007649397677727}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":27150373744240000,"pool_token_amount":27006407025015528}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":27142126147188912,"pool_token_amount":27005566887576850}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":27087679279503524,"pool_token_amount":26999259034798305}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":27083590231811537,"pool_token_amount":26998873959970908}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":27066003482032974,"pool_token_amount":26997020878411106}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":27061473674306134,"pool_token_amount":26996594665778317}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":27051620169443605,"pool_token_amount":26994956181712961}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":20010541466205800,"pool_token_amount":20001381426613839}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":20000000025407401,"pool_token_amount":20000000000508134}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":20000000015785201,"pool_token_amount":20000000000315691}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":20000000000537500,"pool_token_amount":20000000000010743}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"gumi":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":28089649481105705,"pool_token_amount":27549229553296235}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[157,{"sui_amount":28064485933472788,"pool_token_amount":27547373924223226}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":28053054368008802,"pool_token_amount":27546247804964792}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":28049043023242419,"pool_token_amount":27545675569264851}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"sui_amount":28022628323883408,"pool_token_amount":27543041640343834}],[145,{"sui_amount":28018914143063139,"pool_token_amount":27542676578186921}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":28007776053591359,"pool_token_amount":27541579468802480}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":28004064773854762,"pool_token_amount":27541214517874844}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":27988600877241149,"pool_token_amount":27539155075100299}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":27973745206140639,"pool_token_amount":27537693099464101}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":27970030992607222,"pool_token_amount":27537327467278177}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":27966314282594134,"pool_token_amount":27536959773445759}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":27947740289374544,"pool_token_amount":27535132253951162}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":27940288679184536,"pool_token_amount":27534374105151262}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":27936576425005469,"pool_token_amount":27534008272436664}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":27932862469927464,"pool_token_amount":27533641341284628}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":27925440392910477,"pool_token_amount":27532910596400905}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":27921729267289709,"pool_token_amount":27532544699952348}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":27910797961529416,"pool_token_amount":27531644331061758}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":27903978672157769,"pool_token_amount":27531505705898765}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":27900268040029037,"pool_token_amount":27531139595394793}],[112,{"sui_amount":27896577295174092,"pool_token_amount":27530793174323566}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":27880688624499085,"pool_token_amount":27529033886588305}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":27859422089003889,"pool_token_amount":27526933462659154}],[98,{"sui_amount":27836969500709625,"pool_token_amount":27523652198440132}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":27828517434230719,"pool_token_amount":27522773738140656}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":27794576633666186,"pool_token_amount":27518904826715602}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":27790426127529759,"pool_token_amount":27518493892249750}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":27773902642797369,"pool_token_amount":27516849371604790}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":27744873624322560,"pool_token_amount":27513877598687063}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"sui_amount":27735148759807722,"pool_token_amount":27511574195854449}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":27722254405021128,"pool_token_amount":27510293190437566}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":27650316857266168,"pool_token_amount":27502525673774415}],[53,{"sui_amount":27646204002457652,"pool_token_amount":27502116586609965}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":27642091260215080,"pool_token_amount":27501707455871122}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":27637979192881203,"pool_token_amount":27501298337498057}],[50,{"sui_amount":27633867307112499,"pool_token_amount":27500889182409629}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":27625642734517551,"pool_token_amount":27500070628102297}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":27609178230209736,"pool_token_amount":27498416096826301}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":27605066239433305,"pool_token_amount":27498006547388062}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":27583961979008942,"pool_token_amount":27495917674290648}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":27561470974180397,"pool_token_amount":27493464986141190}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":27542688954400532,"pool_token_amount":27491505311441638}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[25,{"sui_amount":20024226520465665,"pool_token_amount":20001541198081181}],[24,{"sui_amount":20019503314880995,"pool_token_amount":20001068989964456}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":20000000000537500,"pool_token_amount":20000000000010743}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":20000000000460100,"pool_token_amount":20000000000009197}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":20000000000455800,"pool_token_amount":20000000000009112}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[5,{"sui_amount":20000000000451500,"pool_token_amount":20000000000009027}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"mrgn":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":143781241375204268,"pool_token_amount":140728373974689481}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":143762283318436356,"pool_token_amount":140727898640005615}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":143743307388722593,"pool_token_amount":140727409559102965}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[158,{"sui_amount":143626212256738294,"pool_token_amount":140722029232498623}],[156,{"sui_amount":143587095237597251,"pool_token_amount":140720855634157745}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":143564101484413469,"pool_token_amount":140716902184771534}],[154,{"sui_amount":143597778717958572,"pool_token_amount":140768504113805144}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":143577797641885482,"pool_token_amount":140767505580571284}],[149,{"sui_amount":142196869237580888,"pool_token_amount":139487369055511228}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[145,{"sui_amount":143441925318899996,"pool_token_amount":140782849002839805}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":143396024740534671,"pool_token_amount":140774671444527960}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":143372554739672573,"pool_token_amount":140770061459112067}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[139,{"sui_amount":143313593685504624,"pool_token_amount":140767488136017455}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":143274086953709866,"pool_token_amount":140765619686574362}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":143155919245644861,"pool_token_amount":140760298825871130}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":143135973218894731,"pool_token_amount":140759168799034963}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":142826578361803996,"pool_token_amount":140713484612977550}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[112,{"sui_amount":142749002650021331,"pool_token_amount":140711042416771739}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":142710482024021199,"pool_token_amount":140710093249898521}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":142667445911338223,"pool_token_amount":140708822108848609}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":142645827419318108,"pool_token_amount":140708192635477275}],[106,{"sui_amount":142623516795253190,"pool_token_amount":140707532405009780}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[100,{"sui_amount":142488303920234969,"pool_token_amount":140702371943728416}],[99,{"sui_amount":142466187932556592,"pool_token_amount":140701716777744444}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":142355481139597324,"pool_token_amount":140697731424860664}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":142333688531592497,"pool_token_amount":140697086221028453}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[91,{"sui_amount":142236644939543520,"pool_token_amount":140642683535537714}],[90,{"sui_amount":142216521203279543,"pool_token_amount":140643481155432065}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":142151924625217515,"pool_token_amount":140641612680325821}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":142108315905709257,"pool_token_amount":140639693942024777}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":141977014802261872,"pool_token_amount":140633684214749104}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":141955701995257903,"pool_token_amount":140633083807176029}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":141824281644694518,"pool_token_amount":140627642536047104}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":141689056436470155,"pool_token_amount":140623982193974760}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[61,{"sui_amount":141581048855008034,"pool_token_amount":140620781320569534}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":141343996236636074,"pool_token_amount":140612660096400970}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[46,{"sui_amount":141258034926011825,"pool_token_amount":140610795539826013}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":140167814503844322,"pool_token_amount":139609291100031220}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[40,{"sui_amount":140123639114120493,"pool_token_amount":139607603527808617}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[36,{"sui_amount":140034352402448289,"pool_token_amount":139604517205229291}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":107995433736031548,"pool_token_amount":107753230994049485}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":107465327177211600,"pool_token_amount":107279053971767767}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":81595177526042636,"pool_token_amount":81558627631456920}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019026363317487,"pool_token_amount":80001922034404952}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000010304137}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[18,{"sui_amount":80000000062001508,"pool_token_amount":80000000006200139}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000215393}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000184075}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000184075}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000180597}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"n1stake":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":35695884510858364,"pool_token_amount":34999397177594524}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":35682052513059262,"pool_token_amount":34998041704088657}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[162,{"sui_amount":35677442052301834,"pool_token_amount":34997589495740220}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":35663414152987650,"pool_token_amount":34996214172156392}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[154,{"sui_amount":35638358475438100,"pool_token_amount":34992867428158254}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":35628472854794850,"pool_token_amount":34991665648475076}],[151,{"sui_amount":56044122752153279,"pool_token_amount":24261207903505724}],[148,{"sui_amount":35609224891436473,"pool_token_amount":34989774908603394}],[148,{"sui_amount":55959630457571875,"pool_token_amount":24233572661704475}],[146,{"sui_amount":35599795219329414,"pool_token_amount":34988848288772563}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[144,{"sui_amount":35590361238027694,"pool_token_amount":34987922811019785}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":35580933856845646,"pool_token_amount":34986995974482635}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[141,{"sui_amount":35589883926123985,"pool_token_amount":34999970316353537}],[140,{"sui_amount":60921757383204538,"pool_token_amount":26408517011573826}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":60888915412323835,"pool_token_amount":26403984377137302}],[136,{"sui_amount":35566292970770879,"pool_token_amount":34997649766885778}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":35547326761594003,"pool_token_amount":34995785812494174}],[132,{"sui_amount":60754735447988994,"pool_token_amount":26361957590248632}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":35537788657287212,"pool_token_amount":34994893671667603}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":61138279756466260,"pool_token_amount":26538176001355381}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":35518912126868975,"pool_token_amount":34993223207508904}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":35509480865535750,"pool_token_amount":34992387834479265}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[121,{"sui_amount":35495339415527013,"pool_token_amount":34991140290294962}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":91036948805633324,"pool_token_amount":39597131861236643}],[112,{"sui_amount":35452878920298045,"pool_token_amount":34987340628884302}],[112,{"sui_amount":90973078203396260,"pool_token_amount":39574180743673393}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":35459098053544175,"pool_token_amount":35001950483034802}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[107,{"sui_amount":90678520340117795,"pool_token_amount":39471835547676215}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":35426838065794494,"pool_token_amount":34999023851407946}],[102,{"sui_amount":35415932356821990,"pool_token_amount":34998000251301289}],[99,{"sui_amount":35399445178722090,"pool_token_amount":34996183045679838}],[97,{"sui_amount":35388746558362346,"pool_token_amount":34995200663423735}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":35383292384933425,"pool_token_amount":34994682021246894}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[89,{"sui_amount":56187492030615276,"pool_token_amount":24519549385808255}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":35335415839966122,"pool_token_amount":34990188332254264}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":35303984229399429,"pool_token_amount":34987237813460523}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":35302790303492847,"pool_token_amount":35000327554196805}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[74,{"sui_amount":35281874305664661,"pool_token_amount":34998340487047747}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[73,{"sui_amount":35276539495582833,"pool_token_amount":34997837752908948}],[73,{"sui_amount":56159278346694944,"pool_token_amount":24560930745639293}],[72,{"sui_amount":35270977542662803,"pool_token_amount":34997309052626871}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":55470446440637224,"pool_token_amount":24270115106147411}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[68,{"sui_amount":35248719052239813,"pool_token_amount":34995186785710478}],[67,{"sui_amount":35243162553192326,"pool_token_amount":34994662715071092}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":35237725157518728,"pool_token_amount":34994256757198971}],[64,{"sui_amount":35226826282559102,"pool_token_amount":34993121496684913}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":35221602680111719,"pool_token_amount":34992628546658942}],[62,{"sui_amount":35216379384042433,"pool_token_amount":34992135559388359}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[56,{"sui_amount":35185960702377644,"pool_token_amount":34990094273326690}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[51,{"sui_amount":51181856487911554,"pool_token_amount":22452827715301953}],[50,{"sui_amount":35166080371835165,"pool_token_amount":34999041352051031}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[45,{"sui_amount":35138995641189211,"pool_token_amount":34996108608441680}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":35123076964091264,"pool_token_amount":34994678958666948}],[42,{"sui_amount":50779740415595677,"pool_token_amount":22303997541950075}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[38,{"sui_amount":50737792264121628,"pool_token_amount":22298447154851180}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":35084613848909738,"pool_token_amount":34990962962551550}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":35066922499685804,"pool_token_amount":34989252208275169}],[31,{"sui_amount":35061020819628992,"pool_token_amount":34988654367370199}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":50675677986519222,"pool_token_amount":22299539739331414}],[29,{"sui_amount":35049301829058695,"pool_token_amount":34987645711790961}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[28,{"sui_amount":35043127530283935,"pool_token_amount":34986991635518040}],[27,{"sui_amount":35036744125201953,"pool_token_amount":34986414567028118}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":25000000008826354,"pool_token_amount":25000000000176518}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[14,{"sui_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":25000000000567000,"pool_token_amount":25000000000011337}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}]],"proofgroup":[[167,{"sui_amount":35772142215430461,"pool_token_amount":35044630444734000}],[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":35762719581942334,"pool_token_amount":35043984234276463}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":35743980318891519,"pool_token_amount":35042698612246563}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":35734554057886969,"pool_token_amount":35042048943705223}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[156,{"sui_amount":56188193923605998,"pool_token_amount":24308524299947607}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[152,{"sui_amount":35700696013427073,"pool_token_amount":35039562770667406}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":35638210338012381,"pool_token_amount":35035268828159321}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":35633491564562626,"pool_token_amount":35034944101792459}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":35619333104022033,"pool_token_amount":35033969535367050}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":35614511961912440,"pool_token_amount":35033633942146394}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":35604976024779460,"pool_token_amount":35032977271896757}],[131,{"sui_amount":61200538240221176,"pool_token_amount":26558679616291721}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[128,{"sui_amount":35585937671829082,"pool_token_amount":35031705696880001}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":35566873606110726,"pool_token_amount":35030393612034431}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":35552627797126937,"pool_token_amount":35029413158471376}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":35528845211603282,"pool_token_amount":35027759659204033}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[115,{"sui_amount":35525886019425708,"pool_token_amount":35029255900634413}],[114,{"sui_amount":35521070597162425,"pool_token_amount":35028921698855211}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[109,{"sui_amount":35496855487637924,"pool_token_amount":35027611692468671}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":35491502013389145,"pool_token_amount":35027240067274166}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":35475070509787718,"pool_token_amount":35026104736170958}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[101,{"sui_amount":35452888341247571,"pool_token_amount":35024405988200284}],[98,{"sui_amount":35436284673213118,"pool_token_amount":35023060157927975}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":35409060225899448,"pool_token_amount":35021039061486381}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[90,{"sui_amount":57186833400164593,"pool_token_amount":24952237241716518}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":35371746017007473,"pool_token_amount":35018457367933253}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":35354045531814445,"pool_token_amount":35015395593946908}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":35337527302222253,"pool_token_amount":35013900222920192}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":35332185585793852,"pool_token_amount":35013529727146290}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[77,{"sui_amount":35321726128541859,"pool_token_amount":35012797673176745}],[76,{"sui_amount":35316392269509581,"pool_token_amount":35012427568586350}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":35294712270130274,"pool_token_amount":35010916253222684}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[70,{"sui_amount":35286594809324366,"pool_token_amount":35013119836907039}],[69,{"sui_amount":35281036465130049,"pool_token_amount":35012734694850448}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[65,{"sui_amount":35256003176342132,"pool_token_amount":35008403290394893}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[63,{"sui_amount":35245314055553296,"pool_token_amount":35007641785184758}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[59,{"sui_amount":35223767014795454,"pool_token_amount":35005951138361062}],[58,{"sui_amount":35218432380461630,"pool_token_amount":35005580023125408}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":35202254199954330,"pool_token_amount":35004294021820698}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[48,{"sui_amount":35163661677670141,"pool_token_amount":35000452507330301}],[45,{"sui_amount":35147454666865835,"pool_token_amount":34999134229356807}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":35142113383369845,"pool_token_amount":34998755434776608}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":35131421441483279,"pool_token_amount":34997989159133137}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[34,{"sui_amount":50692390295195912,"pool_token_amount":22292389021125117}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[27,{"sui_amount":35041315958748060,"pool_token_amount":34988508064706652}],[25,{"sui_amount":25029360201706229,"pool_token_amount":25001139969309546}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":25011906824167687,"pool_token_amount":25000348354054695}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[19,{"sui_amount":25000000019836964,"pool_token_amount":25000000000396727}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":25000000000675000,"pool_token_amount":25000000000013493}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[13,{"sui_amount":80000000001945200,"pool_token_amount":80000000000038898}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":25000000000577800,"pool_token_amount":25000000000011551}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[7,{"sui_amount":80000000001823400,"pool_token_amount":80000000000036464}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":25000000000550800,"pool_token_amount":25000000000011015}],[1,{"sui_amount":25000000000000000,"pool_token_amount":25000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]],"stakefish":[[167,{"sui_amount":208881385873158384,"pool_token_amount":90247695315699644}],[166,{"sui_amount":95913680739475174,"pool_token_amount":41444685619290495}],[165,{"sui_amount":96367742104664436,"pool_token_amount":41645863907718956}],[164,{"sui_amount":96352449800357745,"pool_token_amount":41644207423648719}],[163,{"sui_amount":96337649322853891,"pool_token_amount":41642762419710501}],[161,{"sui_amount":96202746163005059,"pool_token_amount":41594343386922479}],[160,{"sui_amount":96187910895314859,"pool_token_amount":41592885347432275}],[159,{"sui_amount":56158647597223730,"pool_token_amount":24286724137068177}],[155,{"sui_amount":56172060035596590,"pool_token_amount":24304549631279918}],[154,{"sui_amount":56169370360384329,"pool_token_amount":24306392658405239}],[153,{"sui_amount":29987466294310320,"pool_token_amount":29396693730148779}],[151,{"sui_amount":29979659782829278,"pool_token_amount":29396746064794266}],[149,{"sui_amount":29969296302076027,"pool_token_amount":29394290770324031}],[149,{"sui_amount":55998206783406189,"pool_token_amount":24247345210350525}],[147,{"sui_amount":60577452505114017,"pool_token_amount":26236842628119062}],[145,{"sui_amount":61011740165518247,"pool_token_amount":26431456289890675}],[143,{"sui_amount":60941275508518380,"pool_token_amount":26407345445876172}],[142,{"sui_amount":29926742928748465,"pool_token_amount":29379547446181397}],[142,{"sui_amount":60887050348866878,"pool_token_amount":26387055543305147}],[139,{"sui_amount":29915506088501234,"pool_token_amount":29380097874815043}],[139,{"sui_amount":61155058038470407,"pool_token_amount":26512913755951022}],[138,{"sui_amount":61143239422020933,"pool_token_amount":26511041507554672}],[137,{"sui_amount":29904117564503015,"pool_token_amount":29376646075112161}],[136,{"sui_amount":60872175072904209,"pool_token_amount":26399939040663480}],[135,{"sui_amount":29896952575462895,"pool_token_amount":29377339403359865}],[135,{"sui_amount":60871668395294213,"pool_token_amount":26402931636731743}],[134,{"sui_amount":60360812990985173,"pool_token_amount":26184562351206618}],[133,{"sui_amount":29888849828079269,"pool_token_amount":29377109318607311}],[133,{"sui_amount":60012425885620314,"pool_token_amount":26036612776892024}],[132,{"sui_amount":29884817162144206,"pool_token_amount":29377013381909179}],[130,{"sui_amount":61151512266114651,"pool_token_amount":26540661586893959}],[129,{"sui_amount":29869433137088863,"pool_token_amount":29373499711540314}],[128,{"sui_amount":29864756707821774,"pool_token_amount":29372773558718077}],[128,{"sui_amount":61068669793963343,"pool_token_amount":26511219104947826}],[127,{"sui_amount":29860771210262593,"pool_token_amount":29372723919018755}],[127,{"sui_amount":60697501996813641,"pool_token_amount":26353310490251126}],[126,{"sui_amount":60398230627062173,"pool_token_amount":26226590838726727}],[125,{"sui_amount":29850986614554744,"pool_token_amount":29370836955533486}],[125,{"sui_amount":60367268758920307,"pool_token_amount":26216361552415576}],[124,{"sui_amount":29846154173539812,"pool_token_amount":29369952245583494}],[124,{"sui_amount":60366297900473592,"pool_token_amount":26219156603975963}],[123,{"sui_amount":60384867120680711,"pool_token_amount":26230440118575316}],[122,{"sui_amount":60341010770956679,"pool_token_amount":26214606825799235}],[121,{"sui_amount":60288245777136946,"pool_token_amount":26194861606527510}],[120,{"sui_amount":29837022687388869,"pool_token_amount":29376447741189862}],[120,{"sui_amount":103544263515843302,"pool_token_amount":44998846516813681}],[119,{"sui_amount":29833261047429264,"pool_token_amount":29376615394667133}],[119,{"sui_amount":101639408852691686,"pool_token_amount":44176404869955651}],[116,{"sui_amount":91109376671005846,"pool_token_amount":39614137953180303}],[114,{"sui_amount":91046858901959660,"pool_token_amount":39596611581490333}],[113,{"sui_amount":29793892295406813,"pool_token_amount":29361069801172803}],[111,{"sui_amount":90976017183645388,"pool_token_amount":39580291191024981}],[110,{"sui_amount":90853781868271072,"pool_token_amount":39531943192078969}],[109,{"sui_amount":29766564766399940,"pool_token_amount":29350070552647092}],[109,{"sui_amount":90818329079549994,"pool_token_amount":39521890749819817}],[108,{"sui_amount":90698340129651440,"pool_token_amount":39475045972524013}],[106,{"sui_amount":90192067570871508,"pool_token_amount":39265598805458620}],[105,{"sui_amount":90175659610215140,"pool_token_amount":39264020836990014}],[104,{"sui_amount":90167351064918546,"pool_token_amount":39265954008075857}],[103,{"sui_amount":90592941540681178,"pool_token_amount":39456929245771835}],[97,{"sui_amount":35622556754076862,"pool_token_amount":35189307561422818}],[97,{"sui_amount":71776871800572258,"pool_token_amount":31288050467663824}],[96,{"sui_amount":71886997864179676,"pool_token_amount":31340431105064028}],[94,{"sui_amount":71831190143424985,"pool_token_amount":31324806217884421}],[93,{"sui_amount":57297456596387695,"pool_token_amount":24990266938343304}],[92,{"sui_amount":35605171138173493,"pool_token_amount":35198429693195976}],[90,{"sui_amount":35593350420808782,"pool_token_amount":35197209709578066}],[89,{"sui_amount":35588684905836326,"pool_token_amount":35197820690881089}],[88,{"sui_amount":35579717253618074,"pool_token_amount":35194172033909190}],[88,{"sui_amount":56166885509250623,"pool_token_amount":24513909287171205}],[87,{"sui_amount":56159191397121175,"pool_token_amount":24513900357593235}],[86,{"sui_amount":35560905889181868,"pool_token_amount":35186000649044621}],[86,{"sui_amount":56150732419112959,"pool_token_amount":24513558706135662}],[85,{"sui_amount":35553934892259634,"pool_token_amount":35184297720899163}],[84,{"sui_amount":56112589201535947,"pool_token_amount":24503565573990159}],[83,{"sui_amount":35509889152282837,"pool_token_amount":35151179795604794}],[82,{"sui_amount":35502708655654310,"pool_token_amount":35149254591849708}],[82,{"sui_amount":56006352436776612,"pool_token_amount":24463819272006984}],[81,{"sui_amount":55978239754239443,"pool_token_amount":24454868217994275}],[80,{"sui_amount":55982125522980618,"pool_token_amount":24460024235460896}],[79,{"sui_amount":35462458208177270,"pool_token_amount":35125055580699049}],[79,{"sui_amount":55961329588981957,"pool_token_amount":24454268814291919}],[78,{"sui_amount":55960538033470520,"pool_token_amount":24457247594498015}],[76,{"sui_amount":55868024788764297,"pool_token_amount":24423460365495828}],[75,{"sui_amount":35430972578159967,"pool_token_amount":35114584443905531}],[75,{"sui_amount":55850720690115760,"pool_token_amount":24419219347532396}],[74,{"sui_amount":56170074562925206,"pool_token_amount":24562195984152762}],[72,{"sui_amount":55976309982391719,"pool_token_amount":24484411032467644}],[71,{"sui_amount":55974557670685480,"pool_token_amount":24487145354181172}],[69,{"sui_amount":55120976705461675,"pool_token_amount":24120723901360968}],[67,{"sui_amount":35404646451811103,"pool_token_amount":35131352034301923}],[67,{"sui_amount":54922461833202986,"pool_token_amount":24040767862338264}],[66,{"sui_amount":35387363056137505,"pool_token_amount":35119605286884066}],[66,{"sui_amount":51784455072163348,"pool_token_amount":22670478176028089}],[65,{"sui_amount":51823276602441004,"pool_token_amount":22690764268333320}],[64,{"sui_amount":51778255658294528,"pool_token_amount":22674161574456638}],[62,{"sui_amount":35360029536078967,"pool_token_amount":35113446846709509}],[61,{"sui_amount":51828889965075384,"pool_token_amount":22705681335215212}],[60,{"sui_amount":51767721213259183,"pool_token_amount":22681996064361105}],[58,{"sui_amount":35300503330313385,"pool_token_amount":35075094549986471}],[57,{"sui_amount":51850391248165534,"pool_token_amount":22727510604811786}],[56,{"sui_amount":51803631385540799,"pool_token_amount":22710127677423461}],[55,{"sui_amount":51759272177735391,"pool_token_amount":22693797392845026}],[54,{"sui_amount":35250633848556019,"pool_token_amount":35046426386715321}],[53,{"sui_amount":35242541953131432,"pool_token_amount":35043579960269895}],[53,{"sui_amount":51338770888184515,"pool_token_amount":22515550259973405}],[52,{"sui_amount":51247000185712319,"pool_token_amount":22478374119493055}],[50,{"sui_amount":50934197981567236,"pool_token_amount":22347210750473799}],[49,{"sui_amount":35217819963063001,"pool_token_amount":35039791182265267}],[45,{"sui_amount":50850726085209275,"pool_token_amount":22325900694756381}],[44,{"sui_amount":50842818014652001,"pool_token_amount":22325502556608480}],[43,{"sui_amount":50789688769216860,"pool_token_amount":22305247493117139}],[42,{"sui_amount":41565353909791740,"pool_token_amount":41401171064416038}],[41,{"sui_amount":41578069248243148,"pool_token_amount":41420132016189796}],[41,{"sui_amount":50751904872745126,"pool_token_amount":22294891070200423}],[39,{"sui_amount":50745854999086066,"pool_token_amount":22298648024946857}],[37,{"sui_amount":50721441626504806,"pool_token_amount":22294607372353135}],[35,{"sui_amount":50702614556263042,"pool_token_amount":22293262884852417}],[33,{"sui_amount":50686714832591120,"pool_token_amount":22293516307138165}],[32,{"sui_amount":27076471991557233,"pool_token_amount":27011934871055111}],[32,{"sui_amount":50678079971606277,"pool_token_amount":22293347995706515}],[31,{"sui_amount":50689300221492278,"pool_token_amount":22301908815863665}],[30,{"sui_amount":27055367005343712,"pool_token_amount":26999791776119831}],[29,{"sui_amount":27050707684424655,"pool_token_amount":26999711110626054}],[29,{"sui_amount":30151303906408166,"pool_token_amount":13270093016174002}],[26,{"sui_amount":20034300924308984,"pool_token_amount":20007469271295953}],[24,{"sui_amount":20023379351249717,"pool_token_amount":20004942863108159}],[24,{"sui_amount":80078147421796327,"pool_token_amount":80007905147939202}],[22,{"sui_amount":20011405966195300,"pool_token_amount":20002245765140753}],[22,{"sui_amount":80048898706042636,"pool_token_amount":80013225045080085}],[21,{"sui_amount":80019014353317487,"pool_token_amount":80000389996274385}],[20,{"sui_amount":20000000025396901,"pool_token_amount":20000000000507924}],[20,{"sui_amount":80000000103041508,"pool_token_amount":80000000002060816}],[16,{"sui_amount":80000000028419474,"pool_token_amount":80000000000568380}],[15,{"sui_amount":80000000002206200,"pool_token_amount":80000000000044116}],[14,{"sui_amount":80000000002154000,"pool_token_amount":80000000000043073}],[12,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[11,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[10,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[9,{"sui_amount":20000000000449600,"pool_token_amount":20000000000008987}],[9,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[8,{"sui_amount":80000000001840800,"pool_token_amount":80000000000036811}],[6,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[4,{"sui_amount":20000000000441000,"pool_token_amount":20000000000008817}],[4,{"sui_amount":80000000001806000,"pool_token_amount":80000000000036117}],[3,{"sui_amount":20000000000432600,"pool_token_amount":20000000000008650}],[3,{"sui_amount":80000000001771600,"pool_token_amount":80000000000035430}],[2,{"sui_amount":20000000000428400,"pool_token_amount":20000000000008567}],[1,{"sui_amount":80000000000000000,"pool_token_amount":80000000000000000}],[0,{"sui_amount":0,"pool_token_amount":0}]]} \ No newline at end of file diff --git a/crates/sui-json/Cargo.toml b/crates/sui-json/Cargo.toml deleted file mode 100644 index d5cb7157faf..00000000000 --- a/crates/sui-json/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "sui-json" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -bcs.workspace = true -serde.workspace = true -serde_json.workspace = true -schemars.workspace = true - -sui-framework.workspace = true -sui-types.workspace = true - -move-binary-format.workspace = true -move-bytecode-utils.workspace = true -move-core-types.workspace = true -fastcrypto = { workspace = true } - -[dev-dependencies] -test-fuzz.workspace = true -sui-types = { workspace = true, features = ["test-utils"] } -sui-move-build.workspace = true diff --git a/crates/sui-json/src/lib.rs b/crates/sui-json/src/lib.rs deleted file mode 100644 index 6835d8206f9..00000000000 --- a/crates/sui-json/src/lib.rs +++ /dev/null @@ -1,962 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::{BTreeMap, VecDeque}, - fmt::{self, Debug, Formatter}, - str::FromStr, -}; - -use anyhow::{anyhow, bail}; -use fastcrypto::encoding::{Encoding, Hex}; -use move_binary_format::{ - access::ModuleAccess, binary_config::BinaryConfig, binary_views::BinaryIndexedView, - file_format::SignatureToken, -}; -use move_bytecode_utils::resolve_struct; -pub use move_core_types::annotated_value::MoveTypeLayout; -use move_core_types::{ - account_address::AccountAddress, - annotated_value::{MoveFieldLayout, MoveStruct, MoveStructLayout, MoveValue}, - ident_str, - identifier::{IdentStr, Identifier}, - language_storage::{StructTag, TypeTag}, - runtime_value as R, - u256::U256, -}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_json::{json, Number, Value as JsonValue}; -use sui_types::{ - base_types::{ - is_primitive_type_tag, ObjectID, SuiAddress, TxContext, TxContextKind, RESOLVED_ASCII_STR, - RESOLVED_STD_OPTION, RESOLVED_UTF8_STR, STD_ASCII_MODULE_NAME, STD_ASCII_STRUCT_NAME, - STD_OPTION_MODULE_NAME, STD_OPTION_STRUCT_NAME, STD_UTF8_MODULE_NAME, STD_UTF8_STRUCT_NAME, - }, - id::{ID, RESOLVED_SUI_ID}, - move_package::MovePackage, - object::bounded_visitor::BoundedVisitor, - transfer::RESOLVED_RECEIVING_STRUCT, - MOVE_STDLIB_ADDRESS, -}; - -const HEX_PREFIX: &str = "0x"; - -#[cfg(test)] -mod tests; - -/// A list of error categories encountered when parsing numbers. -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub enum SuiJsonValueErrorKind { - /// JSON value must be of specific types. - ValueTypeNotAllowed, - - /// JSON arrays must be homogeneous. - ArrayNotHomogeneous, -} - -#[derive(Debug)] -pub struct SuiJsonValueError { - kind: SuiJsonValueErrorKind, - val: JsonValue, -} - -impl SuiJsonValueError { - pub fn new(val: &JsonValue, kind: SuiJsonValueErrorKind) -> Self { - Self { - kind, - val: val.clone(), - } - } -} - -impl std::error::Error for SuiJsonValueError {} - -impl fmt::Display for SuiJsonValueError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let err_str = match self.kind { - SuiJsonValueErrorKind::ValueTypeNotAllowed => { - format!("JSON value type {} not allowed.", self.val) - } - SuiJsonValueErrorKind::ArrayNotHomogeneous => { - format!("Array not homogeneous. Mismatched value: {}.", self.val) - } - }; - write!(f, "{err_str}") - } -} - -// Intermediate type to hold resolved args -#[derive(Eq, PartialEq, Debug)] -pub enum ResolvedCallArg { - Object(ObjectID), - Pure(Vec), - ObjVec(Vec), -} - -#[derive(Eq, PartialEq, Clone, Deserialize, Serialize, JsonSchema)] -pub struct SuiJsonValue(JsonValue); -impl SuiJsonValue { - pub fn new(json_value: JsonValue) -> Result { - Self::check_value(&json_value)?; - Ok(Self(json_value)) - } - - fn check_value(json_value: &JsonValue) -> Result<(), anyhow::Error> { - match json_value { - // No checks needed for Bool and String - JsonValue::Bool(_) | JsonValue::String(_) => (), - JsonValue::Number(n) => { - // Must be castable to u64 - if !n.is_u64() { - return Err(anyhow!( - "{n} not allowed. Number must be unsigned integer of at most u32" - )); - } - } - // Must be homogeneous - JsonValue::Array(a) => { - // Fail if not homogeneous - check_valid_homogeneous(&JsonValue::Array(a.to_vec()))? - } - JsonValue::Object(v) => { - for (_, value) in v { - Self::check_value(value)?; - } - } - JsonValue::Null => bail!("Null not allowed."), - }; - Ok(()) - } - - pub fn from_object_id(id: ObjectID) -> SuiJsonValue { - Self(JsonValue::String(id.to_hex_uncompressed())) - } - - pub fn to_bcs_bytes(&self, ty: &MoveTypeLayout) -> Result, anyhow::Error> { - let move_value = Self::to_move_value(&self.0, ty)?; - R::MoveValue::simple_serialize(&move_value) - .ok_or_else(|| anyhow!("Unable to serialize {:?}. Expected {}", move_value, ty)) - } - - pub fn from_bcs_bytes( - layout: Option<&MoveTypeLayout>, - bytes: &[u8], - ) -> Result { - let json = if let Some(layout) = layout { - // Try to convert Vec inputs into string - fn try_parse_string(layout: &MoveTypeLayout, bytes: &[u8]) -> Option { - if let MoveTypeLayout::Vector(t) = layout { - if let MoveTypeLayout::U8 = **t { - return bcs::from_bytes::(bytes).ok(); - } - } - None - } - if let Some(s) = try_parse_string(layout, bytes) { - json!(s) - } else { - let result = BoundedVisitor::deserialize_value(bytes, layout).map_or_else( - |_| { - // fallback to array[u8] if fail to convert to json. - JsonValue::Array( - bytes - .iter() - .map(|b| JsonValue::Number(Number::from(*b))) - .collect(), - ) - }, - |move_value| { - move_value_to_json(&move_value).unwrap_or_else(|| { - // fallback to array[u8] if fail to convert to json. - JsonValue::Array( - bytes - .iter() - .map(|b| JsonValue::Number(Number::from(*b))) - .collect(), - ) - }) - }, - ); - result - } - } else { - json!(bytes) - }; - SuiJsonValue::new(json) - } - - pub fn to_json_value(&self) -> JsonValue { - self.0.clone() - } - - pub fn to_sui_address(&self) -> anyhow::Result { - json_value_to_sui_address(&self.0) - } - - fn handle_inner_struct_layout( - inner_vec: &[MoveFieldLayout], - val: &JsonValue, - ty: &MoveTypeLayout, - s: &String, - ) -> Result { - // delegate MoveValue construction to the case when JsonValue::String and - // MoveTypeLayout::Vector are handled to get an address (with 0x string - // prefix) or a vector of u8s (no prefix) - debug_assert!(matches!(val, JsonValue::String(_))); - - if inner_vec.len() != 1 { - bail!( - "Cannot convert string arg {s} to {ty} which is expected \ - to be a struct with one field" - ); - } - - match &inner_vec[0].layout { - MoveTypeLayout::Vector(inner) => match **inner { - MoveTypeLayout::U8 => Ok(R::MoveValue::Struct(R::MoveStruct(vec![ - Self::to_move_value(val, &inner_vec[0].layout.clone())?, - ]))), - MoveTypeLayout::Address => Ok(R::MoveValue::Struct(R::MoveStruct(vec![ - Self::to_move_value(val, &MoveTypeLayout::Address)?, - ]))), - _ => bail!( - "Cannot convert string arg {s} to {ty} \ - which is expected to be a struct \ - with one field of address or u8 vector type" - ), - }, - MoveTypeLayout::Struct(MoveStructLayout { type_, .. }) if type_ == &ID::type_() => { - Ok(R::MoveValue::Struct(R::MoveStruct(vec![ - Self::to_move_value(val, &inner_vec[0].layout.clone())?, - ]))) - } - _ => bail!( - "Cannot convert string arg {s} to {ty} which is expected \ - to be a struct with one field of a vector type" - ), - } - } - - pub fn to_move_value( - val: &JsonValue, - ty: &MoveTypeLayout, - ) -> Result { - Ok(match (val, ty) { - // Bool to Bool is simple - (JsonValue::Bool(b), MoveTypeLayout::Bool) => R::MoveValue::Bool(*b), - - // In constructor, we have already checked that the JSON number is unsigned int of at - // most U32 - (JsonValue::Number(n), MoveTypeLayout::U8) => match n.as_u64() { - Some(x) => R::MoveValue::U8(u8::try_from(x)?), - None => return Err(anyhow!("{} is not a valid number. Only u8 allowed.", n)), - }, - (JsonValue::Number(n), MoveTypeLayout::U16) => match n.as_u64() { - Some(x) => R::MoveValue::U16(u16::try_from(x)?), - None => return Err(anyhow!("{} is not a valid number. Only u16 allowed.", n)), - }, - (JsonValue::Number(n), MoveTypeLayout::U32) => match n.as_u64() { - Some(x) => R::MoveValue::U32(u32::try_from(x)?), - None => return Err(anyhow!("{} is not a valid number. Only u32 allowed.", n)), - }, - - // u8, u16, u32, u64, u128, u256 can be encoded as String - (JsonValue::String(s), MoveTypeLayout::U8) => { - R::MoveValue::U8(u8::try_from(convert_string_to_u256(s.as_str())?)?) - } - (JsonValue::String(s), MoveTypeLayout::U16) => { - R::MoveValue::U16(u16::try_from(convert_string_to_u256(s.as_str())?)?) - } - (JsonValue::String(s), MoveTypeLayout::U32) => { - R::MoveValue::U32(u32::try_from(convert_string_to_u256(s.as_str())?)?) - } - (JsonValue::String(s), MoveTypeLayout::U64) => { - R::MoveValue::U64(u64::try_from(convert_string_to_u256(s.as_str())?)?) - } - (JsonValue::String(s), MoveTypeLayout::U128) => { - R::MoveValue::U128(u128::try_from(convert_string_to_u256(s.as_str())?)?) - } - (JsonValue::String(s), MoveTypeLayout::U256) => { - R::MoveValue::U256(convert_string_to_u256(s.as_str())?) - } - // For ascii and utf8 strings - ( - JsonValue::String(s), - MoveTypeLayout::Struct(MoveStructLayout { type_, fields: _ }), - ) if is_move_string_type(type_) => { - R::MoveValue::Vector(s.as_bytes().iter().copied().map(R::MoveValue::U8).collect()) - } - // For ID - (JsonValue::String(s), MoveTypeLayout::Struct(MoveStructLayout { type_, fields })) - if type_ == &ID::type_() => - { - if fields.len() != 1 { - bail!( - "Cannot convert string arg {s} to {type_} which is expected to be a struct with one field" - ); - }; - let addr = SuiAddress::from_str(s)?; - R::MoveValue::Address(addr.into()) - } - (JsonValue::Object(o), MoveTypeLayout::Struct(MoveStructLayout { fields, .. })) => { - let mut field_values = vec![]; - for layout in fields { - let field = o - .get(layout.name.as_str()) - .ok_or_else(|| anyhow!("Missing field {} for struct {ty}", layout.name))?; - field_values.push(Self::to_move_value(field, &layout.layout)?); - } - R::MoveValue::Struct(R::MoveStruct(field_values)) - } - // Unnest fields - (value, MoveTypeLayout::Struct(MoveStructLayout { fields, .. })) - if fields.len() == 1 => - { - Self::to_move_value(value, &fields[0].layout)? - } - (JsonValue::String(s), MoveTypeLayout::Vector(t)) => { - match &**t { - MoveTypeLayout::U8 => { - // We can encode U8 Vector as string in 2 ways - // 1. If it starts with 0x, we treat it as hex strings, where each pair is a - // byte - // 2. If it does not start with 0x, we treat each character as an ASCII - // encoded byte - // We have to support both for the convenience of the user. This is because - // sometime we need Strings as arg Other times we need vec of hex bytes for - // address. Issue is both Address and Strings are represented as Vec in - // Move call - let vec = if s.starts_with(HEX_PREFIX) { - // If starts with 0x, treat as hex vector - Hex::decode(s).map_err(|e| anyhow!(e))? - } else { - // Else raw bytes - s.as_bytes().to_vec() - }; - R::MoveValue::Vector(vec.iter().copied().map(R::MoveValue::U8).collect()) - } - MoveTypeLayout::Struct(MoveStructLayout { fields: inner, .. }) => { - Self::handle_inner_struct_layout(inner, val, ty, s)? - } - _ => bail!("Cannot convert string arg {s} to {ty}"), - } - } - - // We have already checked that the array is homogeneous in the constructor - (JsonValue::Array(a), MoveTypeLayout::Vector(inner)) => { - // Recursively build an IntermediateValue array - R::MoveValue::Vector( - a.iter() - .map(|i| Self::to_move_value(i, inner)) - .collect::, _>>()?, - ) - } - - (v, MoveTypeLayout::Address) => { - let addr = json_value_to_sui_address(v)?; - R::MoveValue::Address(addr.into()) - } - - _ => bail!("Unexpected arg {val:?} for expected type {ty:?}"), - }) - } -} - -impl Debug for SuiJsonValue { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -fn json_value_to_sui_address(value: &JsonValue) -> anyhow::Result { - match value { - JsonValue::String(s) => { - let s = s.trim().to_lowercase(); - if !s.starts_with(HEX_PREFIX) { - bail!("Address hex string must start with 0x.",); - } - Ok(SuiAddress::from_str(&s)?) - } - JsonValue::Array(bytes) => { - fn value_to_byte_array(v: &Vec) -> Option> { - let mut bytes = vec![]; - for b in v { - let b = b.as_u64()?; - if b <= u8::MAX as u64 { - bytes.push(b as u8); - } else { - return None; - } - } - Some(bytes) - } - let bytes = value_to_byte_array(bytes) - .ok_or_else(|| anyhow!("Invalid input: Cannot parse input into SuiAddress."))?; - Ok(SuiAddress::try_from(bytes)?) - } - v => bail!("Unexpected arg {v} for expected type address"), - } -} - -fn move_value_to_json(move_value: &MoveValue) -> Option { - Some(match move_value { - MoveValue::Vector(values) => JsonValue::Array( - values - .iter() - .map(move_value_to_json) - .collect::>()?, - ), - MoveValue::Bool(v) => json!(v), - MoveValue::Signer(v) | MoveValue::Address(v) => json!(SuiAddress::from(*v).to_string()), - MoveValue::U8(v) => json!(v), - MoveValue::U64(v) => json!(v.to_string()), - MoveValue::U128(v) => json!(v.to_string()), - MoveValue::U16(v) => json!(v), - MoveValue::U32(v) => json!(v), - MoveValue::U256(v) => json!(v.to_string()), - MoveValue::Struct(move_struct) => match move_struct { - MoveStruct { fields, type_ } if is_move_string_type(type_) => { - // ascii::string and utf8::string has a single bytes field. - let (_, v) = fields.first()?; - let string: String = bcs::from_bytes(&v.simple_serialize()?).ok()?; - json!(string) - } - MoveStruct { fields, type_ } if is_move_option_type(type_) => { - // option has a single vec field. - let (_, v) = fields.first()?; - if let MoveValue::Vector(v) = v { - JsonValue::Array(v.iter().filter_map(move_value_to_json).collect::>()) - } else { - return None; - } - } - MoveStruct { fields, type_ } if type_ == &ID::type_() => { - // option has a single vec field. - let (_, v) = fields.first()?; - if let MoveValue::Address(address) = v { - json!(SuiAddress::from(*address)) - } else { - return None; - } - } - // We only care about values here, assuming struct type information is known at the - // client side. - MoveStruct { fields, .. } => { - let fields = fields - .iter() - .map(|(key, value)| (key, move_value_to_json(value))) - .collect::>(); - json!(fields) - } - }, - }) -} - -fn is_move_string_type(tag: &StructTag) -> bool { - (tag.address == MOVE_STDLIB_ADDRESS - && tag.module.as_ident_str() == STD_UTF8_MODULE_NAME - && tag.name.as_ident_str() == STD_UTF8_STRUCT_NAME) - || (tag.address == MOVE_STDLIB_ADDRESS - && tag.module.as_ident_str() == STD_ASCII_MODULE_NAME - && tag.name.as_ident_str() == STD_ASCII_STRUCT_NAME) -} -fn is_move_option_type(tag: &StructTag) -> bool { - tag.address == MOVE_STDLIB_ADDRESS - && tag.module.as_ident_str() == STD_OPTION_MODULE_NAME - && tag.name.as_ident_str() == STD_OPTION_STRUCT_NAME -} - -impl FromStr for SuiJsonValue { - type Err = anyhow::Error; - fn from_str(s: &str) -> Result { - fn try_escape_array(s: &str) -> JsonValue { - let s = s.trim(); - if s.starts_with('[') && s.ends_with(']') { - if let Some(s) = s.strip_prefix('[').and_then(|s| s.strip_suffix(']')) { - return JsonValue::Array(s.split(',').map(try_escape_array).collect()); - } - } - json!(s) - } - // if serde_json fails, the failure usually cause by missing quote escapes, try - // parse array manually. - SuiJsonValue::new(serde_json::from_str(s).unwrap_or_else(|_| try_escape_array(s))) - } -} - -#[derive(Eq, PartialEq, Debug, Clone, Hash)] -enum ValidJsonType { - Bool, - Number, - String, - Array, - // Matches any type - Any, -} - -/// Check via BFS -/// The invariant is that all types at a given level must be the same or be -/// empty, and all must be valid -pub fn check_valid_homogeneous(val: &JsonValue) -> Result<(), SuiJsonValueError> { - let mut deq: VecDeque<&JsonValue> = VecDeque::new(); - deq.push_back(val); - check_valid_homogeneous_rec(&mut deq) -} - -/// Check via BFS -/// The invariant is that all types at a given level must be the same or be -/// empty -fn check_valid_homogeneous_rec(curr_q: &mut VecDeque<&JsonValue>) -> Result<(), SuiJsonValueError> { - if curr_q.is_empty() { - // Nothing to do - return Ok(()); - } - // Queue for the next level - let mut next_q = VecDeque::new(); - // The types at this level must be the same - let mut level_type = ValidJsonType::Any; - - // Process all in this queue/level - while let Some(v) = curr_q.pop_front() { - let curr = match v { - JsonValue::Bool(_) => ValidJsonType::Bool, - JsonValue::Number(x) if x.is_u64() => ValidJsonType::Number, - JsonValue::String(_) => ValidJsonType::String, - JsonValue::Array(w) => { - // Add to the next level - w.iter().for_each(|t| next_q.push_back(t)); - ValidJsonType::Array - } - // Not valid - _ => { - return Err(SuiJsonValueError::new( - v, - SuiJsonValueErrorKind::ValueTypeNotAllowed, - )); - } - }; - - if level_type == ValidJsonType::Any { - // Update the level with the first found type - level_type = curr; - } else if level_type != curr { - // Mismatch in the level - return Err(SuiJsonValueError::new( - v, - SuiJsonValueErrorKind::ArrayNotHomogeneous, - )); - } - } - // Process the next level - check_valid_homogeneous_rec(&mut next_q) -} - -/// Checks if a give SignatureToken represents a primitive type and, if so, -/// returns MoveTypeLayout for this type (if available). The reason we need to -/// return both information about whether a SignatureToken represents a -/// primitive and an Option representing MoveTypeLayout is that there -/// can be signature tokens that represent primitives but that do not have -/// corresponding MoveTypeLayout (e.g., SignatureToken::StructInstantiation). -pub fn primitive_type( - view: &BinaryIndexedView, - type_args: &[TypeTag], - param: &SignatureToken, -) -> (bool, Option) { - match param { - SignatureToken::Bool => (true, Some(MoveTypeLayout::Bool)), - SignatureToken::U8 => (true, Some(MoveTypeLayout::U8)), - SignatureToken::U16 => (true, Some(MoveTypeLayout::U16)), - SignatureToken::U32 => (true, Some(MoveTypeLayout::U32)), - SignatureToken::U64 => (true, Some(MoveTypeLayout::U64)), - SignatureToken::U128 => (true, Some(MoveTypeLayout::U128)), - SignatureToken::U256 => (true, Some(MoveTypeLayout::U256)), - SignatureToken::Address => (true, Some(MoveTypeLayout::Address)), - SignatureToken::Vector(inner) => { - let (is_primitive, inner_layout_opt) = primitive_type(view, type_args, inner); - match inner_layout_opt { - Some(inner_layout) => ( - is_primitive, - Some(MoveTypeLayout::Vector(Box::new(inner_layout))), - ), - None => (is_primitive, None), - } - } - SignatureToken::Struct(struct_handle_idx) => { - let resolved_struct = resolve_struct(view, *struct_handle_idx); - if resolved_struct == RESOLVED_ASCII_STR { - ( - true, - Some(MoveTypeLayout::Struct(MoveStructLayout { - type_: resolved_to_struct(RESOLVED_ASCII_STR), - fields: vec![MoveFieldLayout::new( - ident_str!("bytes").into(), - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - )], - })), - ) - } else if resolved_struct == RESOLVED_UTF8_STR { - // both structs structs representing strings have one field - a vector of type - // u8 - ( - true, - Some(MoveTypeLayout::Struct(MoveStructLayout { - type_: resolved_to_struct(RESOLVED_UTF8_STR), - fields: vec![MoveFieldLayout::new( - ident_str!("bytes").into(), - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - )], - })), - ) - } else if resolved_struct == RESOLVED_SUI_ID { - ( - true, - Some(MoveTypeLayout::Struct(MoveStructLayout { - type_: resolved_to_struct(RESOLVED_SUI_ID), - fields: vec![MoveFieldLayout::new( - ident_str!("bytes").into(), - MoveTypeLayout::Address, - )], - })), - ) - } else { - (false, None) - } - } - SignatureToken::StructInstantiation(struct_inst) => { - let (idx, targs) = &**struct_inst; - let resolved_struct = resolve_struct(view, *idx); - // is option of a primitive - if resolved_struct == RESOLVED_STD_OPTION && targs.len() == 1 { - // there is no MoveLayout for this so while we can still report whether a type - // is primitive or not, we can't return the layout - let (is_primitive, inner_layout) = primitive_type(view, type_args, &targs[0]); - let layout = - inner_layout.map(|inner_layout| MoveTypeLayout::Vector(Box::new(inner_layout))); - (is_primitive, layout) - } else { - (false, None) - } - } - - SignatureToken::TypeParameter(idx) => ( - type_args - .get(*idx as usize) - .map(is_primitive_type_tag) - .unwrap_or(false), - None, - ), - - SignatureToken::Signer - | SignatureToken::Reference(_) - | SignatureToken::MutableReference(_) => (false, None), - } -} - -fn resolved_to_struct(resolved_type: (&AccountAddress, &IdentStr, &IdentStr)) -> StructTag { - StructTag { - address: *resolved_type.0, - module: resolved_type.1.into(), - name: resolved_type.2.into(), - type_params: vec![], - } -} - -fn resolve_object_arg(idx: usize, arg: &JsonValue) -> Result { - // Every elem has to be a string convertible to a ObjectID - match arg { - JsonValue::String(s) => { - let s = s.trim().to_lowercase(); - if !s.starts_with(HEX_PREFIX) { - bail!("ObjectID hex string must start with 0x.",); - } - Ok(ObjectID::from_hex_literal(&s)?) - } - _ => bail!( - "Unable to parse arg {:?} as ObjectID at pos {}. Expected {:?}-byte hex string \ - prefixed with 0x.", - arg, - idx, - ObjectID::LENGTH, - ), - } -} - -fn resolve_object_vec_arg(idx: usize, arg: &SuiJsonValue) -> Result, anyhow::Error> { - // Every elem has to be a string convertible to a ObjectID - match arg.to_json_value() { - JsonValue::Array(a) => { - let mut object_ids = vec![]; - for id in a { - object_ids.push(resolve_object_arg(idx, &id)?); - } - Ok(object_ids) - } - JsonValue::String(s) if s.starts_with('[') && s.ends_with(']') => { - // Due to how escaping of square bracket works, we may be dealing with a JSON - // string representing a JSON array rather than with the array - // itself ("[0x42,0x7]" rather than [0x42,0x7]). - let mut object_ids = vec![]; - for tok in s[1..s.len() - 1].to_string().split(',') { - let id = JsonValue::String(tok.to_string()); - object_ids.push(resolve_object_arg(idx, &id)?); - } - Ok(object_ids) - } - _ => bail!( - "Unable to parse arg {:?} as vector of ObjectIDs at pos {}. \ - Expected a vector of {:?}-byte hex strings prefixed with 0x.\n\ - Consider escaping your curly braces with a backslash (as in \\[0x42,0x7\\]) \ - or enclosing the whole vector in single quotes (as in '[0x42,0x7]')", - arg.to_json_value(), - idx, - ObjectID::LENGTH, - ), - } -} - -fn resolve_call_arg( - view: &BinaryIndexedView, - type_args: &[TypeTag], - idx: usize, - arg: &SuiJsonValue, - param: &SignatureToken, -) -> Result { - let (is_primitive, layout_opt) = primitive_type(view, type_args, param); - if is_primitive { - match layout_opt { - Some(layout) => { - return Ok(ResolvedCallArg::Pure(arg.to_bcs_bytes(&layout).map_err( - |e| { - anyhow!( - "Could not serialize argument of type {:?} at {} into {}. Got error: {:?}", - param, - idx, - layout, - e - ) - }, - )?)); - } - None => { - debug_assert!( - false, - "Should be unreachable. All primitive type function args \ - should have a corresponding MoveLayout" - ); - bail!( - "Could not serialize argument of type {:?} at {}", - param, - idx - ); - } - } - } - - // in terms of non-primitives we only currently support objects and "flat" - // (depth == 1) vectors of objects (but not, for example, vectors of - // references) - match param { - SignatureToken::Struct(_) - | SignatureToken::StructInstantiation(_) - | SignatureToken::TypeParameter(_) - | SignatureToken::Reference(_) - | SignatureToken::MutableReference(_) => Ok(ResolvedCallArg::Object(resolve_object_arg( - idx, - &arg.to_json_value(), - )?)), - SignatureToken::Vector(inner) => match &**inner { - SignatureToken::Struct(_) | SignatureToken::StructInstantiation(_) => { - Ok(ResolvedCallArg::ObjVec(resolve_object_vec_arg(idx, arg)?)) - } - _ => { - bail!( - "Unexpected non-primitive vector arg {:?} at {} with value {:?}", - param, - idx, - arg - ); - } - }, - _ => bail!( - "Unexpected non-primitive arg {:?} at {} with value {:?}", - param, - idx, - arg - ), - } -} - -pub fn is_receiving_argument(view: &BinaryIndexedView, arg_type: &SignatureToken) -> bool { - use SignatureToken as ST; - - // Progress down into references to determine if the underlying type is a - // receiving type or not. - let mut token = arg_type; - while let ST::Reference(inner) | ST::MutableReference(inner) = token { - token = inner; - } - - matches!( - token, - ST::StructInstantiation(struct_inst) if resolve_struct(view, struct_inst.0) == RESOLVED_RECEIVING_STRUCT && struct_inst.1.len() == 1 - ) -} - -fn resolve_call_args( - view: &BinaryIndexedView, - type_args: &[TypeTag], - json_args: &[SuiJsonValue], - parameter_types: &[SignatureToken], -) -> Result, anyhow::Error> { - json_args - .iter() - .zip(parameter_types) - .enumerate() - .map(|(idx, (arg, param))| resolve_call_arg(view, type_args, idx, arg, param)) - .collect() -} - -/// Resolve the JSON args of a function into the expected formats to make them -/// usable by Move call This is because we have special types which we need to -/// specify in other formats -pub fn resolve_move_function_args( - package: &MovePackage, - module_ident: Identifier, - function: Identifier, - type_args: &[TypeTag], - combined_args_json: Vec, -) -> Result, anyhow::Error> { - // Extract the expected function signature - let module = package.deserialize_module(&module_ident, &BinaryConfig::standard())?; - let function_str = function.as_ident_str(); - let fdef = module - .function_defs - .iter() - .find(|fdef| { - module.identifier_at(module.function_handle_at(fdef.function).name) == function_str - }) - .ok_or_else(|| { - anyhow!( - "Could not resolve function {} in module {}", - function, - module_ident - ) - })?; - let function_signature = module.function_handle_at(fdef.function); - let parameters = &module.signature_at(function_signature.parameters).0; - - let view = BinaryIndexedView::Module(&module); - - // Lengths have to match, less one, due to TxContext - let expected_len = match parameters.last() { - Some(param) if TxContext::kind(&view, param) != TxContextKind::None => parameters.len() - 1, - _ => parameters.len(), - }; - if combined_args_json.len() != expected_len { - bail!( - "Expected {} args, found {}", - expected_len, - combined_args_json.len() - ); - } - // Check that the args are valid and convert to the correct format - let call_args = resolve_call_args(&view, type_args, &combined_args_json, parameters)?; - let tupled_call_args = call_args - .into_iter() - .zip(parameters.iter()) - .map(|(arg, expected_type)| (arg, expected_type.clone())) - .collect::>(); - Ok(tupled_call_args) -} - -fn convert_string_to_u256(s: &str) -> Result { - // Try as normal number - if let Ok(v) = s.parse::() { - return Ok(v); - } - - // Check prefix - // For now only Hex supported - // TODO: add support for bin and octal? - - let s = s.trim().to_lowercase(); - if !s.starts_with(HEX_PREFIX) { - bail!("Unable to convert {s} to unsigned int.",); - } - U256::from_str_radix(s.trim_start_matches(HEX_PREFIX), 16).map_err(|e| e.into()) -} - -#[macro_export] -macro_rules! call_args { - ($($value:expr),*) => { - Ok::<_, anyhow::Error>(vec![$(sui_json::call_arg!($value)?,)*]) - }; - } - -#[macro_export] -macro_rules! call_arg { - ($value:expr) => {{ - use sui_json::SuiJsonValue; - trait SuiJsonArg { - fn to_sui_json(&self) -> anyhow::Result; - } - // TODO: anyway to condense this? - impl SuiJsonArg for &str { - fn to_sui_json(&self) -> anyhow::Result { - SuiJsonValue::from_str(self) - } - } - impl SuiJsonArg for String { - fn to_sui_json(&self) -> anyhow::Result { - SuiJsonValue::from_str(&self) - } - } - impl SuiJsonArg for sui_types::base_types::ObjectID { - fn to_sui_json(&self) -> anyhow::Result { - SuiJsonValue::from_str(&self.to_string()) - } - } - impl SuiJsonArg for sui_types::base_types::SuiAddress { - fn to_sui_json(&self) -> anyhow::Result { - SuiJsonValue::from_str(&self.to_string()) - } - } - impl SuiJsonArg for u64 { - fn to_sui_json(&self) -> anyhow::Result { - SuiJsonValue::from_bcs_bytes( - Some(&sui_json::MoveTypeLayout::U64), - &bcs::to_bytes(self)?, - ) - } - } - impl SuiJsonArg for Vec { - fn to_sui_json(&self) -> anyhow::Result { - SuiJsonValue::from_bcs_bytes(None, &self) - } - } - impl SuiJsonArg for &[u8] { - fn to_sui_json(&self) -> anyhow::Result { - SuiJsonValue::from_bcs_bytes(None, self) - } - } - $value.to_sui_json() - }}; -} - -#[macro_export] -macro_rules! type_args { - ($($value:expr), *) => {{ - use sui_json_rpc_types::SuiTypeTag; - use sui_types::TypeTag; - trait SuiJsonTypeArg { - fn to_sui_json(&self) -> anyhow::Result; - } - impl SuiJsonTypeArg for T { - fn to_sui_json(&self) -> anyhow::Result { - Ok(sui_types::parse_sui_type_tag(&self.to_string())?.into()) - } - } - Ok::<_, anyhow::Error>(vec![$($value.to_sui_json()?,)*]) - }}; - } diff --git a/crates/sui-json/src/tests.rs b/crates/sui-json/src/tests.rs deleted file mode 100644 index 9ab3ecdac7e..00000000000 --- a/crates/sui-json/src/tests.rs +++ /dev/null @@ -1,941 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{path::Path, str::FromStr}; - -use fastcrypto::encoding::{Encoding, Hex}; -use move_core_types::{ - account_address::AccountAddress, - annotated_value::{MoveFieldLayout, MoveStructLayout, MoveTypeLayout}, - ident_str, - identifier::Identifier, - language_storage::StructTag, - u256::U256, -}; -use serde_json::{json, Value}; -use sui_framework::BuiltInFramework; -use sui_move_build::BuildConfig; -use sui_types::{ - base_types::{ - ObjectID, SuiAddress, TransactionDigest, STD_ASCII_MODULE_NAME, STD_ASCII_STRUCT_NAME, - STD_OPTION_MODULE_NAME, STD_OPTION_STRUCT_NAME, - }, - dynamic_field::derive_dynamic_field_id, - gas_coin::GasCoin, - object::Object, - parse_sui_type_tag, MOVE_STDLIB_ADDRESS, -}; -use test_fuzz::runtime::num_traits::ToPrimitive; - -use super::{check_valid_homogeneous, resolve_move_function_args, SuiJsonValue, HEX_PREFIX}; -use crate::ResolvedCallArg; - -// Negative test cases -#[test] -fn test_json_not_homogeneous() { - let checks = vec![ - (json!([1, 2, 3, true, 5, 6, 7])), - // Although we can encode numbers as strings, we do not allow mixing primitive - // numbers and string encoded numbers - (json!([1, 2, "4", 4, 5, 6, 7])), - (json!([1, 2, 3, 4, "", 6, 7])), - (json!([ - 1, - 2, - 3, - 4, - "456478542957455650244254734723567875646785024425473472356787564678463250089787", - 6, - 7 - ])), - (json!([[], 2, 3, 5, 6, 7])), - (json!([[[9, 53, 434], [0], [300]], [], [300, 4, 5, 6, 7]])), - (json!([1, 2, 3, 4, 5, 6, 0.4])), - (json!([4.2])), - (json!(4.7)), - ]; - // Driver - for arg in checks { - assert!(check_valid_homogeneous(&arg).is_err()); - } -} - -// Positive test cases -#[test] -fn test_json_is_homogeneous() { - let checks = vec![ - (json!([1, 2, 3, 4, 5, 6, 7])), - (json!(["123", "456"])), - (json!([ - "123", - "456478542957455650244254734723567875646785024425473472356787564678463250089787" - ])), - (json!([])), - (json!([[[9, 53, 434], [0], [300]], [], [[332], [4, 5, 6, 7]]])), - (json!([[], [true], [false], []])), - (json!([[[[[2]]]], [], [[]], []])), - (json!([3])), - (json!([])), - (json!(1)), - ]; - - // Driver - for arg in checks { - assert!(check_valid_homogeneous(&arg).is_ok()); - } -} - -#[test] -fn test_json_struct_homogeneous() { - let positive = json!({"inner_vec":[1, 2, 3, 4, 5, 6, 7]}); - assert!(SuiJsonValue::new(positive).is_ok()); - - let negative = json!({"inner_vec":[1, 2, 3, true, 5, 6, 7]}); - assert!(SuiJsonValue::new(negative).is_err()); -} - -#[test] -fn test_json_is_not_valid_sui_json() { - let checks = vec![ - // Not homogeneous - (json!([1, 2, 3, true, 5, 6, 7])), - // Not homogeneous - (json!([1, 2, 3, "123456", 5, 6, 7])), - // Float not allowed - (json!(1.3)), - // Negative not allowed - (json!(-10)), - // Not homogeneous - (json!([[[9, 53, 434], [0], [300]], [], [300, 4, 5, 6, 7]])), - ]; - - // Driver - for arg in checks { - assert!(SuiJsonValue::new(arg).is_err()); - } -} - -#[test] -fn test_json_is_valid_sui_json() { - let checks = vec![ - // Homogeneous - (json!([1, 2, 3, 4, 5, 6, 7])), - // String allowed - (json!("a string")), - // Bool allowed - (json!(true)), - // Uint allowed - (json!(100)), - (json!([])), - // Homogeneous - (json!([[[9, 53, 434], [0], [300]], [], [[332], [4, 5, 6, 7]]])), - ]; - - // Driver - for arg in checks { - assert!(SuiJsonValue::new(arg).is_ok()); - } -} - -#[test] -fn test_basic_args_linter_pure_args_bad() { - let bad_hex_val = "0x1234AB CD"; - - let checks = vec![ - // Although U256 value can be encoded as num, we enforce it must be a string - (Value::from(123), MoveTypeLayout::U256), - // Space not allowed - (Value::from(" 9"), MoveTypeLayout::U8), - // Hex must start with 0x - (Value::from("AB"), MoveTypeLayout::U8), - // Too large - (Value::from("123456789"), MoveTypeLayout::U8), - // Too large - ( - Value::from("123456789123456789123456789123456789"), - MoveTypeLayout::U64, - ), - // Too large - ( - Value::from( - "123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789", - ), - MoveTypeLayout::U128, - ), - // U64 value greater than 255 cannot be used as U8 - (Value::from(900u64), MoveTypeLayout::U8), - // floats cannot be used as U8 - (Value::from(0.4f32), MoveTypeLayout::U8), - // floats cannot be used as U64 - (Value::from(3.4f32), MoveTypeLayout::U64), - // Negative cannot be used as U64 - (Value::from(-19), MoveTypeLayout::U64), - // Negative cannot be used as Unsigned - (Value::from(-1), MoveTypeLayout::U8), - // u8 vector from bad hex repr - ( - Value::from(bad_hex_val), - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - ), - // u8 vector from heterogeneous array - ( - json!([1, 2, 3, true, 5, 6, 7]), - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - ), - // U64 deep nest, bad because heterogeneous array - ( - json!([[[9, 53, 434], [0], [300]], [], [300, 4, 5, 6, 7]]), - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::Vector(Box::new( - MoveTypeLayout::U64, - )))), - ), - ]; - - // Driver - for (arg, expected_type) in checks { - let r = SuiJsonValue::new(arg); - assert!(r.is_err() || r.unwrap().to_bcs_bytes(&expected_type).is_err()); - } -} - -#[test] -fn test_basic_args_linter_pure_args_good() { - let good_ascii_str = "123456789hdffwfof libgude ihibhdede +_))@+"; - let good_utf8_str = "enbeuf√12∫∆∂3456789hdπ˚ffwfof libgude ˚ø˙߃çß +_))@+"; - let good_hex_val = "0x1234ABCD"; - let u128_val = u64::MAX as u128 + 0xff; - let u256_hex_val = "0x1234567812345678877EDA56789098ABCDEF12"; - let u256_val = U256::from_str_radix(u256_hex_val.trim_start_matches("0x"), 16).unwrap(); - - let checks = vec![ - // Expected Bool match - ( - Value::from(true), - MoveTypeLayout::Bool, - bcs::to_bytes(&true).unwrap(), - ), - // Expected U8 match - ( - Value::from(9u8), - MoveTypeLayout::U8, - bcs::to_bytes(&9u8).unwrap(), - ), - // Expected U8 match - ( - Value::from(u8::MAX), - MoveTypeLayout::U8, - bcs::to_bytes(&u8::MAX).unwrap(), - ), - // Expected U16 match - ( - Value::from(9000u16), - MoveTypeLayout::U16, - bcs::to_bytes(&9000u16).unwrap(), - ), - // Expected U32 match - ( - Value::from(1233459000u32), - MoveTypeLayout::U32, - bcs::to_bytes(&1233459000u32).unwrap(), - ), - // Expected U16 match - ( - Value::from(u16::MAX), - MoveTypeLayout::U16, - bcs::to_bytes(&u16::MAX).unwrap(), - ), - // Expected U32 match - ( - Value::from(u32::MAX), - MoveTypeLayout::U32, - bcs::to_bytes(&u32::MAX).unwrap(), - ), - // U64 value less than 256 can be used as U8 - ( - Value::from(9u64), - MoveTypeLayout::U8, - bcs::to_bytes(&9u8).unwrap(), - ), - // U8 value encoded as str - ( - Value::from("89"), - MoveTypeLayout::U8, - bcs::to_bytes(&89u8).unwrap(), - ), - // U16 value encoded as str - ( - Value::from("12389"), - MoveTypeLayout::U16, - bcs::to_bytes(&12389u16).unwrap(), - ), - // U32 value encoded as str - ( - Value::from("123899856"), - MoveTypeLayout::U32, - bcs::to_bytes(&123899856u32).unwrap(), - ), - // U8 value encoded as str promoted to U64 - ( - Value::from("89"), - MoveTypeLayout::U64, - bcs::to_bytes(&89u64).unwrap(), - ), - // U64 value encoded as str - ( - Value::from("890"), - MoveTypeLayout::U64, - bcs::to_bytes(&890u64).unwrap(), - ), - // U64 value encoded as str - ( - Value::from(format!("{}", u64::MAX)), - MoveTypeLayout::U64, - bcs::to_bytes(&u64::MAX).unwrap(), - ), - // U128 value encoded as str - ( - Value::from(format!("{u128_val}")), - MoveTypeLayout::U128, - bcs::to_bytes(&u128_val).unwrap(), - ), - // U128 value encoded as str - ( - Value::from(format!("{}", u128::MAX)), - MoveTypeLayout::U128, - bcs::to_bytes(&u128::MAX).unwrap(), - ), - // U256 value encoded as str - ( - Value::from(format!("{u256_val}")), - MoveTypeLayout::U256, - bcs::to_bytes(&u256_val).unwrap(), - ), - // U8 value encoded as hex str - ( - Value::from("0x12"), - MoveTypeLayout::U8, - bcs::to_bytes(&0x12u8).unwrap(), - ), - // U8 value encoded as hex str promoted to U64 - ( - Value::from("0x12"), - MoveTypeLayout::U64, - bcs::to_bytes(&0x12u64).unwrap(), - ), - // U64 value encoded as hex str - ( - Value::from("0x890"), - MoveTypeLayout::U64, - bcs::to_bytes(&0x890u64).unwrap(), - ), - // U128 value encoded as hex str - ( - Value::from(format!("0x{:02x}", u128_val)), - MoveTypeLayout::U128, - bcs::to_bytes(&u128_val).unwrap(), - ), - // U256 value encoded as hex str - ( - Value::from(u256_hex_val.to_string()), - MoveTypeLayout::U256, - bcs::to_bytes(&u256_val).unwrap(), - ), - // U256 value encoded as hex str - ( - Value::from(format!("0x{:02x}", U256::max_value())), - MoveTypeLayout::U256, - bcs::to_bytes(&U256::max_value()).unwrap(), - ), - // u8 vector can be gotten from string - ( - Value::from(good_ascii_str), - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - bcs::to_bytes(&good_ascii_str.as_bytes()).unwrap(), - ), - // u8 vector from bad string - ( - Value::from(good_utf8_str), - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - bcs::to_bytes(&good_utf8_str.as_bytes()).unwrap(), - ), - // u8 vector from hex repr - ( - Value::from(good_hex_val), - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - bcs::to_bytes(&Hex::decode(good_hex_val.trim_start_matches(HEX_PREFIX)).unwrap()) - .unwrap(), - ), - // u8 vector from u8 array - ( - json!([1, 2, 3, 4, 5, 6, 7]), - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - bcs::to_bytes(&vec![1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8]).unwrap(), - ), - // Vector of vector of u8s - ( - json!([[1, 2, 3], [], [3, 4, 5, 6, 7]]), - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::Vector(Box::new( - MoveTypeLayout::U8, - )))), - bcs::to_bytes(&vec![ - vec![1u8, 2u8, 3u8], - vec![], - vec![3u8, 4u8, 5u8, 6u8, 7u8], - ]) - .unwrap(), - ), - // U64 nest - ( - json!([["1111", "2", "3"], [], ["300", "4", "5", "6", "7"]]), - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::Vector(Box::new( - MoveTypeLayout::U64, - )))), - bcs::to_bytes(&vec![ - vec![1111u64, 2u64, 3u64], - vec![], - vec![300u64, 4u64, 5u64, 6u64, 7u64], - ]) - .unwrap(), - ), - // U32 deep nest, good - ( - json!([[[9, 53, 434], [0], [300]], [], [[332], [4, 5, 6, 7]]]), - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::Vector(Box::new( - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U32)), - )))), - bcs::to_bytes(&vec![ - vec![vec![9u32, 53u32, 434u32], vec![0u32], vec![300u32]], - vec![], - vec![vec![332u32], vec![4u32, 5u32, 6u32, 7u32]], - ]) - .unwrap(), - ), - ]; - - // Driver - for (arg, expected_type, expected_val) in checks { - let r = SuiJsonValue::new(arg); - // Must conform - assert!(r.is_ok()); - // Must be serializable - let sr = r.unwrap().to_bcs_bytes(&expected_type); - // Must match expected serialized value - assert_eq!(sr.unwrap(), expected_val); - } -} - -#[test] -fn test_basic_args_linter_top_level() { - let path = - Path::new(env!("CARGO_MANIFEST_DIR")).join("../../sui_programmability/examples/nfts"); - let compiled_modules = BuildConfig::new_for_testing() - .build(path) - .unwrap() - .into_modules(); - let example_package = Object::new_package_for_testing( - &compiled_modules, - TransactionDigest::genesis_marker(), - BuiltInFramework::genesis_move_packages(), - ) - .unwrap(); - let example_package = example_package.data.try_as_package().unwrap(); - - let module = Identifier::new("geniteam").unwrap(); - let function = Identifier::new("create_monster").unwrap(); - - // Function signature: - // public fun create_monster( - // _player: &mut Player, - // farm: &mut Farm, - // pet_monsters: &mut Collection, - // monster_name: vector, - // monster_img_index: u64, - // breed: u8, - // monster_affinity: u8, - // monster_description: vector, - // display: vector, - // ctx: &mut TxContext - // ) - - let monster_name_raw = "MonsterName"; - let monster_img_id_raw = "12345678"; - let breed_raw = 89; - let monster_affinity_raw = 200; - let monster_description_raw = "MonsterDescription"; - let display_raw = "DisplayUrl"; - - let player_id = json!(format!("0x{}", ObjectID::random())); - // This is okay since not starting with 0x - let monster_name = json!(monster_name_raw); - // Well within U64 bounds - let monster_img_id = json!(monster_img_id_raw); - // Well within U8 bounds - let breed = json!(breed_raw); - // Well within U8 bounds - let monster_affinity = json!(monster_affinity_raw); - // This is okay since not starting with 0x - let monster_description = json!(monster_description_raw); - // This is okay since not starting with 0x - let display = json!(display_raw); - - // They have to be ordered - let args = vec![ - player_id, - monster_name.clone(), - monster_img_id.clone(), - breed, - monster_affinity.clone(), - monster_description.clone(), - display.clone(), - ] - .iter() - .map(|q| SuiJsonValue::new(q.clone()).unwrap()) - .collect(); - - let json_args = - resolve_move_function_args(example_package, module.clone(), function.clone(), &[], args) - .unwrap(); - - assert!(!json_args.is_empty()); - - assert_eq!( - json_args[1].0, - ResolvedCallArg::Pure(bcs::to_bytes(&monster_name_raw.as_bytes().to_vec()).unwrap()) - ); - assert_eq!( - json_args[2].0, - ResolvedCallArg::Pure( - bcs::to_bytes(&(monster_img_id_raw.parse::().unwrap())).unwrap() - ), - ); - assert_eq!( - json_args[3].0, - ResolvedCallArg::Pure(bcs::to_bytes(&(breed_raw as u8)).unwrap()) - ); - assert_eq!( - json_args[4].0, - ResolvedCallArg::Pure(bcs::to_bytes(&(monster_affinity_raw as u8)).unwrap()), - ); - assert_eq!( - json_args[5].0, - ResolvedCallArg::Pure(bcs::to_bytes(&monster_description_raw.as_bytes().to_vec()).unwrap()), - ); - - // Breed is u8 so too large - let args = vec![ - monster_name, - monster_img_id, - json!(10000u64), - monster_affinity, - monster_description, - display, - ] - .iter() - .map(|q| SuiJsonValue::new(q.clone()).unwrap()) - .collect(); - assert!(resolve_move_function_args(example_package, module, function, &[], args,).is_err()); - - // Test with vecu8 as address - let path = - Path::new(env!("CARGO_MANIFEST_DIR")).join("../../sui_programmability/examples/basics"); - let compiled_modules = BuildConfig::new_for_testing() - .build(path) - .unwrap() - .into_modules(); - let example_package = Object::new_package_for_testing( - &compiled_modules, - TransactionDigest::genesis_marker(), - BuiltInFramework::genesis_move_packages(), - ) - .unwrap(); - let framework_pkg = example_package.data.try_as_package().unwrap(); - - let module = Identifier::new("object_basics").unwrap(); - let function = Identifier::new("create").unwrap(); - - // Function signature: - // public fun create(value: u64, recipient: vector, ctx: &mut TxContext) - let value_raw = "29897"; - let address = SuiAddress::random_for_testing_only(); - - let value = json!(value_raw); - // Encode as hex string - let addr = json!(format!("{address}")); - - // They have to be ordered - let args = [value, addr] - .iter() - .map(|q| SuiJsonValue::new(q.clone()).unwrap()) - .collect(); - - let args = resolve_move_function_args(framework_pkg, module, function, &[], args).unwrap(); - - assert_eq!( - args[0].0, - ResolvedCallArg::Pure(bcs::to_bytes(&(value_raw.parse::().unwrap())).unwrap()) - ); - - // Need to verify this specially - // BCS serialzes addresses like vectors so there's a length prefix, which makes - // the vec longer by 1 - assert_eq!( - args[1].0, - ResolvedCallArg::Pure(bcs::to_bytes(&AccountAddress::from(address)).unwrap()), - ); - - // Test with object args - - let module = Identifier::new("object_basics").unwrap(); - let function = Identifier::new("transfer").unwrap(); - - // Function signature: - // public fun transfer(o: Object, recipient: vector, _ctx: &mut TxContext) - let object_id_raw = ObjectID::random(); - let address = SuiAddress::random_for_testing_only(); - - let object_id = json!(format!("{object_id_raw}")); - // Encode as hex string - let addr = json!(format!("{address}")); - - // They have to be ordered - let args = [object_id, addr] - .iter() - .map(|q| SuiJsonValue::new(q.clone()).unwrap()) - .collect(); - - let args = resolve_move_function_args(framework_pkg, module, function, &[], args).unwrap(); - - assert_eq!( - args[0].0, - ResolvedCallArg::Object( - ObjectID::from_hex_literal(&format!("0x{}", object_id_raw)).unwrap() - ) - ); - - // Need to verify this specially - // BCS serialzes addresses like vectors so there's a length prefix, which makes - // the vec longer by 1 - assert_eq!( - args[1].0, - ResolvedCallArg::Pure(bcs::to_bytes(&AccountAddress::from(address)).unwrap()) - ); - - // Test with object vector args - let path = Path::new(env!("CARGO_MANIFEST_DIR")) - .join("../sui-core/src/unit_tests/data/entry_point_vector"); - let compiled_modules = BuildConfig::new_for_testing() - .build(path) - .unwrap() - .into_modules(); - let example_package = Object::new_package_for_testing( - &compiled_modules, - TransactionDigest::genesis_marker(), - BuiltInFramework::genesis_move_packages(), - ) - .unwrap(); - let example_package = example_package.data.try_as_package().unwrap(); - - let module = Identifier::new("entry_point_vector").unwrap(); - let function = Identifier::new("two_obj_vec_destroy").unwrap(); - - // Function signature: - // public entry fun two_obj_vec_destroy(v: vector, _: &mut TxContext) - let object_id_raw1 = ObjectID::random(); - let object_id_raw2 = ObjectID::random(); - let object_id1 = json!(format!("0x{}", object_id_raw1)); - let object_id2 = json!(format!("0x{}", object_id_raw2)); - - let args = vec![SuiJsonValue::new(Value::Array(vec![object_id1, object_id2])).unwrap()]; - - let args = resolve_move_function_args(example_package, module, function, &[], args).unwrap(); - - assert!(matches!(args[0].0, ResolvedCallArg::ObjVec { .. })); - - if let ResolvedCallArg::ObjVec(vec) = &args[0].0 { - assert_eq!(vec.len(), 2); - assert_eq!( - vec[0], - ObjectID::from_hex_literal(&format!("0x{}", object_id_raw1)).unwrap() - ); - assert_eq!( - vec[1], - ObjectID::from_hex_literal(&format!("0x{}", object_id_raw2)).unwrap() - ); - } -} - -#[test] -fn test_convert_address_from_bcs() { - let bcs_bytes = [ - 50, 134, 111, 1, 9, 250, 27, 169, 17, 57, 45, 205, 45, 66, 96, 241, 216, 36, 49, 51, 22, - 245, 70, 122, 191, 100, 24, 123, 62, 239, 165, 85, - ]; - - let value = SuiJsonValue::from_bcs_bytes(Some(&MoveTypeLayout::Signer), &bcs_bytes).unwrap(); - - assert_eq!( - "0x32866f0109fa1ba911392dcd2d4260f1d824313316f5467abf64187b3eefa555", - value.0.as_str().unwrap() - ); -} - -#[test] -fn test_convert_number_from_bcs() { - let bcs_bytes = [160u8, 134, 1, 0]; - let value = SuiJsonValue::from_bcs_bytes(Some(&MoveTypeLayout::U32), &bcs_bytes).unwrap(); - assert_eq!(100000, value.0.as_u64().unwrap()); -} - -#[test] -fn test_no_address_zero_trimming() { - let bcs_bytes = bcs::to_bytes( - &AccountAddress::from_str( - "0x0000000000000000000000000000011111111111111111111111111111111111", - ) - .unwrap(), - ) - .unwrap(); - let value = SuiJsonValue::from_bcs_bytes(Some(&MoveTypeLayout::Address), &bcs_bytes).unwrap(); - assert_eq!( - "0x0000000000000000000000000000011111111111111111111111111111111111", - value.0.as_str().unwrap() - ); -} - -#[test] -fn test_convert_number_array_from_bcs() { - let bcs_bytes = [ - 5, 80, 195, 0, 0, 80, 195, 0, 0, 80, 195, 0, 0, 80, 195, 0, 0, 80, 195, 0, 0, - ]; - - let value = SuiJsonValue::from_bcs_bytes( - Some(&MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U32))), - &bcs_bytes, - ) - .unwrap(); - - for value in value.0.as_array().unwrap() { - assert_eq!(50000, value.as_u64().unwrap()) - } -} - -#[test] -fn test_from_str() { - // test number - let test = SuiJsonValue::from_str("10000").unwrap(); - assert!(test.0.is_number()); - // Test array - let test = SuiJsonValue::from_str("[10,10,10,10]").unwrap(); - assert!(test.0.is_array()); - assert_eq!( - vec![10, 10, 10, 10], - test.0 - .as_array() - .unwrap() - .iter() - .map(|value| value.as_u64().unwrap().to_u8().unwrap()) - .collect::>() - ); - // test bool - let test = SuiJsonValue::from_str("true").unwrap(); - assert!(test.0.is_boolean()); - - // test id without quotes - let object_id = ObjectID::random().to_hex_uncompressed(); - let test = SuiJsonValue::from_str(&object_id).unwrap(); - assert!(test.0.is_string()); - assert_eq!(object_id, test.0.as_str().unwrap()); - - // test id with quotes - let test = SuiJsonValue::from_str(&format!("\"{}\"", &object_id)).unwrap(); - assert!(test.0.is_string()); - assert_eq!(object_id, test.0.as_str().unwrap()); - - // test string without quotes - let test = SuiJsonValue::from_str("Some string").unwrap(); - assert!(test.0.is_string()); - assert_eq!("Some string", test.0.as_str().unwrap()); - - // test string with quotes - let test = SuiJsonValue::from_str("\"Some string\"").unwrap(); - assert!(test.0.is_string()); - assert_eq!("Some string", test.0.as_str().unwrap()); - - let test = SuiJsonValue::from_object_id( - ObjectID::from_str("0x0000000000000000000000000000000000000000000000000000000000000001") - .unwrap(), - ); - assert!(test.0.is_string()); - assert_eq!( - "0x0000000000000000000000000000000000000000000000000000000000000001", - test.0.as_str().unwrap() - ); -} - -#[test] -fn test_sui_call_arg_string_type() { - let arg1 = bcs::to_bytes("Some String").unwrap(); - - let string_layout = Some(MoveTypeLayout::Struct(MoveStructLayout { - type_: StructTag { - address: MOVE_STDLIB_ADDRESS, - module: STD_ASCII_MODULE_NAME.into(), - name: STD_ASCII_STRUCT_NAME.into(), - type_params: vec![], - }, - fields: vec![MoveFieldLayout { - name: ident_str!("bytes").into(), - layout: MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - }], - })); - let v = SuiJsonValue::from_bcs_bytes(string_layout.as_ref(), &arg1).unwrap(); - - assert_eq!(json! {"Some String"}, v.to_json_value()); -} - -#[test] -fn test_sui_call_arg_option_type() { - let arg1 = bcs::to_bytes(&Some("Some String")).unwrap(); - - let string_layout = MoveTypeLayout::Struct(MoveStructLayout { - type_: StructTag { - address: MOVE_STDLIB_ADDRESS, - module: STD_ASCII_MODULE_NAME.into(), - name: STD_ASCII_STRUCT_NAME.into(), - type_params: vec![], - }, - fields: vec![MoveFieldLayout { - name: ident_str!("bytes").into(), - layout: MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - }], - }); - - let option_layout = MoveTypeLayout::Struct(MoveStructLayout { - type_: StructTag { - address: MOVE_STDLIB_ADDRESS, - module: STD_OPTION_MODULE_NAME.into(), - name: STD_OPTION_STRUCT_NAME.into(), - type_params: vec![], - }, - fields: vec![MoveFieldLayout { - name: ident_str!("vec").into(), - layout: MoveTypeLayout::Vector(Box::new(string_layout.clone())), - }], - }); - - let v = SuiJsonValue::from_bcs_bytes(Some(option_layout).as_ref(), &arg1).unwrap(); - - let bytes = v - .to_bcs_bytes(&MoveTypeLayout::Vector(Box::new(string_layout))) - .unwrap(); - - assert_eq!(json! {["Some String"]}, v.to_json_value()); - assert_eq!(arg1, bytes); - - let s = SuiJsonValue::from_str("[test, test2]").unwrap(); - println!("{s:?}"); -} - -#[test] -fn test_convert_struct() { - let layout = MoveTypeLayout::Struct(GasCoin::layout()); - - let value = json!({"id":"0xf1416fe18c7baa1673187375777a7606708481311cb3548509ec91a5871c6b9a", "balance": "1000000"}); - let sui_json = SuiJsonValue::new(value).unwrap(); - - println!("JS: {:#?}", sui_json); - - let bcs = sui_json.to_bcs_bytes(&layout).unwrap(); - - let coin: GasCoin = bcs::from_bytes(&bcs).unwrap(); - assert_eq!( - coin.0.id.id.bytes, - ObjectID::from_str("0xf1416fe18c7baa1673187375777a7606708481311cb3548509ec91a5871c6b9a") - .unwrap() - ); - assert_eq!(coin.0.balance.value(), 1000000); -} - -#[test] -fn test_convert_string_vec() { - let test_vec = vec!["0xbbb", "test_str"]; - let bcs = bcs::to_bytes(&test_vec).unwrap(); - let string_layout = MoveTypeLayout::Struct(MoveStructLayout { - type_: StructTag { - address: MOVE_STDLIB_ADDRESS, - module: STD_ASCII_MODULE_NAME.into(), - name: STD_ASCII_STRUCT_NAME.into(), - type_params: vec![], - }, - fields: vec![MoveFieldLayout { - name: ident_str!("bytes").into(), - layout: MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - }], - }); - - let layout = MoveTypeLayout::Vector(Box::new(string_layout)); - - let value = json!(test_vec); - let sui_json = SuiJsonValue::new(value).unwrap(); - - let bcs2 = sui_json.to_bcs_bytes(&layout).unwrap(); - - assert_eq!(bcs, bcs2); -} - -#[test] -fn test_string_vec_df_name_child_id_eq() { - let parent_id = - ObjectID::from_str("0x13a3ab664bfbdff0ab03cd1ce8c6fb3f31a8803f2e6e0b14b610f8e94fcb8509") - .unwrap(); - let name = json!({ - "labels": [ - "0x0001", - "sui" - ] - }); - - let string_layout = MoveTypeLayout::Struct(MoveStructLayout { - type_: StructTag { - address: MOVE_STDLIB_ADDRESS, - module: STD_ASCII_MODULE_NAME.into(), - name: STD_ASCII_STRUCT_NAME.into(), - type_params: vec![], - }, - fields: vec![MoveFieldLayout { - name: ident_str!("bytes").into(), - layout: MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - }], - }); - - let layout = MoveTypeLayout::Struct(MoveStructLayout { - type_: StructTag { - address: MOVE_STDLIB_ADDRESS, - module: STD_ASCII_MODULE_NAME.into(), - name: STD_ASCII_STRUCT_NAME.into(), - type_params: vec![], - }, - fields: vec![MoveFieldLayout::new( - Identifier::from_str("labels").unwrap(), - MoveTypeLayout::Vector(Box::new(string_layout)), - )], - }); - - let sui_json = SuiJsonValue::new(name).unwrap(); - let bcs2 = sui_json.to_bcs_bytes(&layout).unwrap(); - - let child_id = derive_dynamic_field_id( - parent_id, - &parse_sui_type_tag( - "0x3278d6445c6403c96abe9e25cc1213a85de2bd627026ee57906691f9bbf2bf8a::domain::Domain", - ) - .unwrap(), - &bcs2, - ) - .unwrap(); - - assert_eq!( - "0x2c2e361ee262b9f1f9a930e27e092cce5906b1e63a699ee60aec2de452ab9c70", - child_id.to_string() - ); -} diff --git a/crates/sui-keys/Cargo.toml b/crates/sui-keys/Cargo.toml deleted file mode 100644 index 8c9693de194..00000000000 --- a/crates/sui-keys/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "sui-keys" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -serde.workspace = true -serde_json.workspace = true -signature.workspace = true -rand.workspace = true -tiny-bip39.workspace = true -bip32.workspace = true -slip10_ed25519.workspace = true -fastcrypto = { workspace = true, features = ["copy_key"] } -shared-crypto.workspace = true -sui-types.workspace = true -regex.workspace = true - -[dev-dependencies] -tempfile.workspace = true diff --git a/crates/sui-keys/src/lib.rs b/crates/sui-keys/src/lib.rs deleted file mode 100644 index c95be489e8a..00000000000 --- a/crates/sui-keys/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod key_derive; -pub mod keypair_file; -pub mod keystore; -pub mod random_names; diff --git a/crates/sui-keys/tests/tests.rs b/crates/sui-keys/tests/tests.rs deleted file mode 100644 index fcdc8beacee..00000000000 --- a/crates/sui-keys/tests/tests.rs +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{fs, str::FromStr}; - -use fastcrypto::{hash::HashFunction, traits::EncodeDecodeBase64}; -use sui_keys::{ - key_derive::generate_new_key, - keystore::{AccountKeystore, FileBasedKeystore, InMemKeystore, Keystore}, -}; -use sui_types::{ - base_types::{SuiAddress, SUI_ADDRESS_LENGTH}, - crypto::{DefaultHash, Ed25519SuiSignature, SignatureScheme, SuiSignatureInner}, -}; -use tempfile::TempDir; - -#[test] -fn alias_exists_test() { - let temp_dir = TempDir::new().unwrap(); - let keystore_path = temp_dir.path().join("sui.keystore"); - let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - keystore - .generate_and_add_new_key( - SignatureScheme::ED25519, - Some("my_alias_test".to_string()), - None, - None, - ) - .unwrap(); - let aliases = keystore.alias_names(); - assert_eq!(1, aliases.len()); - assert_eq!(vec!["my_alias_test"], aliases); - assert!(!aliases.contains(&"alias_does_not_exist")); -} - -#[test] -fn create_alias_keystore_file_test() { - let temp_dir = TempDir::new().unwrap(); - let mut keystore_path = temp_dir.path().join("sui.keystore"); - let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - keystore - .generate_and_add_new_key(SignatureScheme::ED25519, None, None, None) - .unwrap(); - keystore_path.set_extension("aliases"); - assert!(keystore_path.exists()); - - keystore_path = temp_dir.path().join("myfile.keystore"); - let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - keystore - .generate_and_add_new_key(SignatureScheme::ED25519, None, None, None) - .unwrap(); - keystore_path.set_extension("aliases"); - assert!(keystore_path.exists()); -} - -#[test] -fn check_reading_aliases_file_correctly() { - // when reading the alias file containing alias + public key base 64, - // make sure the addresses are correctly converted back from pk - - let temp_dir = TempDir::new().unwrap(); - let mut keystore_path = temp_dir.path().join("sui.keystore"); - let keystore_path_keep = temp_dir.path().join("sui.keystore"); - let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - let kp = keystore - .generate_and_add_new_key(SignatureScheme::ED25519, None, None, None) - .unwrap(); - keystore_path.set_extension("aliases"); - assert!(keystore_path.exists()); - - let new_keystore = Keystore::from(FileBasedKeystore::new(&keystore_path_keep).unwrap()); - let addresses = new_keystore.addresses_with_alias(); - assert_eq!(kp.0, *addresses.first().unwrap().0) -} - -#[test] -fn create_alias_if_not_exists_test() { - let temp_dir = TempDir::new().unwrap(); - let keystore_path = temp_dir.path().join("sui.keystore"); - let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - - let alias = Some("my_alias_test".to_string()); - keystore - .generate_and_add_new_key(SignatureScheme::ED25519, alias.clone(), None, None) - .unwrap(); - - // test error first - let create_alias_result = keystore.create_alias(alias); - assert!(create_alias_result.is_err()); - // test expected result - let create_alias_result = keystore.create_alias(Some("test".to_string())); - assert_eq!("test".to_string(), create_alias_result.unwrap()); - assert!(keystore.create_alias(Some("_test".to_string())).is_err()); - assert!(keystore.create_alias(Some("-A".to_string())).is_err()); - assert!(keystore.create_alias(Some("1A".to_string())).is_err()); - assert!(keystore.create_alias(Some("&&AA".to_string())).is_err()); -} - -#[test] -fn keystore_no_aliases() { - // this tests if when calling FileBasedKeystore::new, it creates a - // sui.aliases file with the existing address in the sui.keystore, - // and a new alias for it. - // This idea is to test the correct conversion - // from the old type (which only contains keys and an optional path) - // to the new type which contains keys and aliases (and an optional path), and - // if it creates the aliases file. - - let temp_dir = TempDir::new().unwrap(); - let mut keystore_path = temp_dir.path().join("sui.keystore"); - let (_, keypair, _, _) = generate_new_key(SignatureScheme::ED25519, None, None).unwrap(); - let private_keys = vec![keypair.encode_base64()]; - let keystore_data = serde_json::to_string_pretty(&private_keys).unwrap(); - fs::write(&keystore_path, keystore_data).unwrap(); - - let keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - keystore_path.set_extension("aliases"); - assert!(keystore_path.exists()); - assert_eq!(1, keystore.aliases().len()); -} - -#[test] -fn update_alias_test() { - let temp_dir = TempDir::new().unwrap(); - let keystore_path = temp_dir.path().join("sui.keystore"); - let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - keystore - .generate_and_add_new_key( - SignatureScheme::ED25519, - Some("my_alias_test".to_string()), - None, - None, - ) - .unwrap(); - let aliases = keystore.alias_names(); - assert_eq!(1, aliases.len()); - assert_eq!(vec!["my_alias_test"], aliases); - - // read the alias file again and check if it was saved - let keystore1 = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - let aliases1 = keystore1.alias_names(); - assert_eq!(vec!["my_alias_test"], aliases1); - - let update = keystore.update_alias("alias_does_not_exist", None); - assert!(update.is_err()); - - let _ = keystore.update_alias("my_alias_test", Some("new_alias")); - let aliases = keystore.alias_names(); - assert_eq!(vec!["new_alias"], aliases); - - // check that it errors on empty alias - assert!(keystore.update_alias("new_alias", Some(" ")).is_err()); - assert!(keystore.update_alias("new_alias", Some(" ")).is_err()); - // check that alias is trimmed - assert!(keystore.update_alias("new_alias", Some(" o ")).is_ok()); - assert_eq!(vec!["o"], keystore.alias_names()); - // check the regex works and new alias can be only [A-Za-z][A-Za-z0-9-_]* - assert!(keystore.update_alias("o", Some("_alias")).is_err()); - assert!(keystore.update_alias("o", Some("-alias")).is_err()); - assert!(keystore.update_alias("o", Some("123")).is_err()); - - let update = keystore.update_alias("o", None).unwrap(); - let aliases = keystore.alias_names(); - assert_eq!(vec![&update], aliases); -} - -#[test] -fn update_alias_in_memory_test() { - let mut keystore = Keystore::InMem(InMemKeystore::new_insecure_for_tests(0)); - keystore - .generate_and_add_new_key( - SignatureScheme::ED25519, - Some("my_alias_test".to_string()), - None, - None, - ) - .unwrap(); - let aliases = keystore.alias_names(); - assert_eq!(1, aliases.len()); - assert_eq!(vec!["my_alias_test"], aliases); - - let update = keystore.update_alias("alias_does_not_exist", None); - assert!(update.is_err()); - - let _ = keystore.update_alias("my_alias_test", Some("new_alias")); - let aliases = keystore.alias_names(); - assert_eq!(vec!["new_alias"], aliases); - - let update = keystore.update_alias("new_alias", None).unwrap(); - let aliases = keystore.alias_names(); - assert_eq!(vec![&update], aliases); -} - -#[test] -fn mnemonic_test() { - let temp_dir = TempDir::new().unwrap(); - let keystore_path = temp_dir.path().join("sui.keystore"); - let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - let (address, phrase, scheme) = keystore - .generate_and_add_new_key(SignatureScheme::ED25519, None, None, None) - .unwrap(); - - let keystore_path_2 = temp_dir.path().join("sui2.keystore"); - let mut keystore2 = Keystore::from(FileBasedKeystore::new(&keystore_path_2).unwrap()); - let imported_address = keystore2 - .import_from_mnemonic(&phrase, SignatureScheme::ED25519, None) - .unwrap(); - assert_eq!(scheme.flag(), Ed25519SuiSignature::SCHEME.flag()); - assert_eq!(address, imported_address); -} - -/// This test confirms rust's implementation of mnemonic is the same with the -/// Sui Wallet -#[test] -fn sui_wallet_address_mnemonic_test() -> Result<(), anyhow::Error> { - let phrase = "result crisp session latin must fruit genuine question prevent start coconut brave speak student dismiss"; - let expected_address = - SuiAddress::from_str("0x936accb491f0facaac668baaedcf4d0cfc6da1120b66f77fa6a43af718669973")?; - - let temp_dir = TempDir::new().unwrap(); - let keystore_path = temp_dir.path().join("sui.keystore"); - let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - - keystore - .import_from_mnemonic(phrase, SignatureScheme::ED25519, None) - .unwrap(); - - let pubkey = keystore.keys()[0].clone(); - assert_eq!(pubkey.flag(), Ed25519SuiSignature::SCHEME.flag()); - - let mut hasher = DefaultHash::default(); - hasher.update([pubkey.flag()]); - hasher.update(pubkey); - let g_arr = hasher.finalize(); - let mut res = [0u8; SUI_ADDRESS_LENGTH]; - res.copy_from_slice(&AsRef::<[u8]>::as_ref(&g_arr)[..SUI_ADDRESS_LENGTH]); - let address = SuiAddress::try_from(res.as_slice())?; - - assert_eq!(expected_address, address); - - Ok(()) -} - -#[test] -fn keystore_display_test() -> Result<(), anyhow::Error> { - let temp_dir = TempDir::new().unwrap(); - let keystore_path = temp_dir.path().join("sui.keystore"); - let keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - assert!(keystore.to_string().contains("sui.keystore")); - assert!(!keystore.to_string().contains("keys:")); - Ok(()) -} - -#[test] -fn get_alias_by_address_test() { - let temp_dir = TempDir::new().unwrap(); - let keystore_path = temp_dir.path().join("sui.keystore"); - let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - let alias = "my_alias_test".to_string(); - let keypair = keystore - .generate_and_add_new_key(SignatureScheme::ED25519, Some(alias.clone()), None, None) - .unwrap(); - assert_eq!(alias, keystore.get_alias_by_address(&keypair.0).unwrap()); - - // Test getting an alias of an address that is not in keystore - let address = generate_new_key(SignatureScheme::ED25519, None, None).unwrap(); - assert!(keystore.get_alias_by_address(&address.0).is_err()) -} diff --git a/crates/sui-light-client/Cargo.toml b/crates/sui-light-client/Cargo.toml deleted file mode 100644 index 7b63ec6fdb6..00000000000 --- a/crates/sui-light-client/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "sui-light-client" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -async-trait.workspace = true -bcs.workspace = true -bytes.workspace = true -clap.workspace = true -move-core-types.workspace = true -serde.workspace = true -tokio = { workspace = true, features = ["full"] } -serde_yaml.workspace = true -serde_json.workspace = true -sui-types.workspace = true -sui-config.workspace = true -sui-rest-api.workspace = true -sui-json.workspace = true -sui-sdk.workspace = true -move-binary-format.workspace = true -sui-json-rpc-types.workspace = true -sui-package-resolver.workspace = true - diff --git a/crates/sui-light-client/README.md b/crates/sui-light-client/README.md deleted file mode 100644 index fd5ca232ea3..00000000000 --- a/crates/sui-light-client/README.md +++ /dev/null @@ -1,62 +0,0 @@ -This crate contains a Command Line Interface light client for Sui. - -# What is a light client? - -A light client allows checking the authenticity and validity of on-chain state, such as transactions, their effects including events and object contents, without the cost of running a full node. - -Running a *full node* requires downloading the full sequence of all transaction and re-executing them. Then the full state of the blockchain is available locally to serve reads. This is however an expensive process in terms of network bandwidth needed to download the full sequence of transactions, as well as CPU to re-execute it, and storage to store the full state of the blockchain. - -Alternatively, a *light client* only needs to download minimal information to authenticate blockchain state. Specifically in Sui, the light client needs to *sync* all end-of-epoch checkpoints that contain information about the committee in the next epoch. Sync involves downloading the checkpoints and checking their validity by checking their certificate. - -Once all end-of-epoch checkpoints are downloaded and checked, any event or current object can be checked for its validity. To do that the light client downloads the checkpoint in which the transaction was executed, and the effects structure that summarizes its effects on the system, including events emitted and objects created. The chain of validity from the checkpoint to the effects and its contents is checked via the certificate on the checkpoint and the hashes of all structures. - -## Ensuring valid data display - -A light client can ensure the correctness of the event and object data using the techniques defined above. However, the light client CLI utility also needs to pretty-print the structures in JSON, which requires knowledge of the correct type for each event or object. Types themselves are defined in modules that have been uploaded by past transactions. Therefore to ensure correct display the light client authenticates that all modules needed to display sought items are also correct. - -# Usage - -The light client requires a config file and a directory to cache checkpoints, and then can be used to check the validity of transaction and their events or of objects. - -## Setup - -The config file for the light client takes a URL for a full node, a directory (that must exist) and within the directory to name of the genesis blob for the Sui network. - -``` -full_node_url: "http://ord-mnt-rpcbig-06.mainnet.sui.io:9000" -checkpoint_summary_dir: "checkpoints_dir" -genesis_filename: "genesis.blob" -``` - -The genesis blob for the Sui mainnet can be found here: https://github.com/MystenLabs/sui-genesis/blob/main/mainnet/genesis.blob - -## Sync - -Every day there is a need to download new checkpoints through sync by doing: -``` -$ sui-light-client --config light_client.yaml sync -``` - -Where `light_client.yaml` is the config file above. - -This command will download all end-of-epoch checkpoints, and check them for validity. They will be cached within the checkpoint summary directory for use by future invocations. - -## Check Transaction - -To check a transaction was executed, as well as the events it emitted do: -``` -$ sui-light-client --config light_client.yaml transaction -t 8RiKBwuAbtu8zNCtz8SrcfHyEUzto6zi6cMVA9t4WhWk -``` - -Where the base58 encoding of the transaction ID is specified. If the transaction has been executed the transaction ID the effects digest are displayed and all the events are printed in JSON. If not an error is printed. - -## Check Object - -To check an object provide its ID in the following way: - -``` -$ sui-light-client --config light_client.yaml object -o 0xc646887891adfc0540ec271fd0203603fb4c841a119ec1e00c469441 -abfc7078 -``` - -The object ID is represented in Hex as displayed in explorers. If the object exists in the latest state it is printed out in JSON, otherwise an error is printed. \ No newline at end of file diff --git a/crates/sui-light-client/src/main.rs b/crates/sui-light-client/src/main.rs deleted file mode 100644 index fd31e29fc15..00000000000 --- a/crates/sui-light-client/src/main.rs +++ /dev/null @@ -1,705 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - fs, - io::{Read, Write}, - path::PathBuf, - str::FromStr, - sync::Arc, -}; - -use anyhow::anyhow; -use async_trait::async_trait; -use clap::{Parser, Subcommand}; -use move_core_types::account_address::AccountAddress; -use sui_config::genesis::Genesis; -use sui_json::SuiJsonValue; -use sui_json_rpc_types::SuiTransactionBlockResponseOptions; -use sui_package_resolver::{Package, PackageStore, Resolver, Result as ResolverResult}; -use sui_rest_api::{CheckpointData, Client}; -use sui_sdk::SuiClientBuilder; -use sui_types::{ - base_types::{ObjectID, SequenceNumber}, - committee::Committee, - crypto::AuthorityQuorumSignInfo, - digests::TransactionDigest, - effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, - message_envelope::Envelope, - messages_checkpoint::{CertifiedCheckpointSummary, CheckpointSummary, EndOfEpochData}, - object::{Data, Object}, -}; - -/// A light client for the Sui blockchain -#[derive(Parser, Debug)] -#[command(author, version, about, long_about = None)] -struct Args { - /// Sets a custom config file - #[arg(short, long, value_name = "FILE")] - config: Option, - - #[command(subcommand)] - command: Option, -} - -struct RemotePackageStore { - client: Client, - config: Config, -} - -impl RemotePackageStore { - pub fn new(client: Client, config: Config) -> Self { - Self { client, config } - } -} - -#[async_trait] -impl PackageStore for RemotePackageStore { - /// Latest version of the object at `id`. - async fn version(&self, id: AccountAddress) -> ResolverResult { - Ok(self.client.get_object(id.into()).await.unwrap().version()) - } - /// Read package contents. Fails if `id` is not an object, not a package, or - /// is malformed in some way. - async fn fetch(&self, id: AccountAddress) -> ResolverResult> { - let object = get_verified_object(&self.config, id.into()).await.unwrap(); - let package = Package::read(&object).unwrap(); - Ok(Arc::new(package)) - } -} - -#[derive(Subcommand, Debug)] -enum SCommands { - /// Sync all end-of-epoch checkpoints - Sync {}, - - /// Checks a specific transaction using the light client - Transaction { - /// Transaction hash - #[arg(short, long, value_name = "TID")] - tid: String, - }, - - /// Checks a specific object using the light client - Object { - /// Transaction hash - #[arg(short, long, value_name = "OID")] - oid: String, - }, -} - -// The config file for the light client including the root of trust genesis -// digest -#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] -struct Config { - /// Full node url - full_node_url: String, - - /// Checkpoint summary directory - checkpoint_summary_dir: PathBuf, - - // Genesis file name - genesis_filename: PathBuf, -} - -impl Config { - pub fn rest_url(&self) -> String { - format!("{}/rest", self.full_node_url) - } -} - -// The list of checkpoints at the end of each epoch -#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] -struct CheckpointsList { - // List of end of epoch checkpoints - checkpoints: Vec, -} - -fn read_checkpoint_list(config: &Config) -> anyhow::Result { - let mut checkpoints_path = config.checkpoint_summary_dir.clone(); - checkpoints_path.push("checkpoints.yaml"); - // Read the resulting file and parse the yaml checkpoint list - let reader = fs::File::open(checkpoints_path.clone())?; - Ok(serde_yaml::from_reader(reader)?) -} - -fn read_checkpoint( - config: &Config, - seq: u64, -) -> anyhow::Result>> { - read_checkpoint_general(config, seq, None) -} - -fn read_checkpoint_general( - config: &Config, - seq: u64, - path: Option<&str>, -) -> anyhow::Result>> { - // Read the resulting file and parse the yaml checkpoint list - let mut checkpoint_path = config.checkpoint_summary_dir.clone(); - if let Some(path) = path { - checkpoint_path.push(path); - } - checkpoint_path.push(format!("{}.yaml", seq)); - let mut reader = fs::File::open(checkpoint_path.clone())?; - let metadata = fs::metadata(&checkpoint_path)?; - let mut buffer = vec![0; metadata.len() as usize]; - reader.read_exact(&mut buffer)?; - bcs::from_bytes(&buffer).map_err(|_| anyhow!("Unable to parse checkpoint file")) -} - -fn write_checkpoint( - config: &Config, - summary: &Envelope>, -) -> anyhow::Result<()> { - write_checkpoint_general(config, summary, None) -} - -fn write_checkpoint_general( - config: &Config, - summary: &Envelope>, - path: Option<&str>, -) -> anyhow::Result<()> { - // Write the checkpoint summary to a file - let mut checkpoint_path = config.checkpoint_summary_dir.clone(); - if let Some(path) = path { - checkpoint_path.push(path); - } - checkpoint_path.push(format!("{}.yaml", summary.sequence_number)); - let mut writer = fs::File::create(checkpoint_path.clone())?; - let bytes = - bcs::to_bytes(&summary).map_err(|_| anyhow!("Unable to serialize checkpoint summary"))?; - writer.write_all(&bytes)?; - Ok(()) -} - -fn write_checkpoint_list( - config: &Config, - checkpoints_list: &CheckpointsList, -) -> anyhow::Result<()> { - // Write the checkpoint list to a file - let mut checkpoints_path = config.checkpoint_summary_dir.clone(); - checkpoints_path.push("checkpoints.yaml"); - let mut writer = fs::File::create(checkpoints_path.clone())?; - let bytes = serde_yaml::to_vec(&checkpoints_list)?; - writer - .write_all(&bytes) - .map_err(|_| anyhow!("Unable to serialize checkpoint list")) -} - -async fn download_checkpoint_summary( - config: &Config, - seq: u64, -) -> anyhow::Result { - // Download the checkpoint from the server - let client = Client::new(config.rest_url()); - client.get_checkpoint_summary(seq).await -} - -/// Run binary search to for each end of epoch checkpoint that is missing -/// between the latest on the list and the latest checkpoint. -async fn sync_checkpoint_list_to_latest(config: &Config) -> anyhow::Result<()> { - // Get the local checkpoint list - let mut checkpoints_list: CheckpointsList = read_checkpoint_list(config)?; - let latest_in_list = checkpoints_list - .checkpoints - .last() - .ok_or(anyhow!("Empty checkpoint list"))?; - - // Download the latest in list checkpoint - let summary = download_checkpoint_summary(config, *latest_in_list).await?; - let mut last_epoch = summary.epoch(); - let mut last_checkpoint_seq = summary.sequence_number; - - // Download the very latest checkpoint - let client = Client::new(config.rest_url()); - let latest = client.get_latest_checkpoint().await?; - - // Binary search to find missing checkpoints - while last_epoch + 1 < latest.epoch() { - let mut start = last_checkpoint_seq; - let mut end = latest.sequence_number; - - let target_epoch = last_epoch + 1; - // Print target - println!("Target Epoch: {}", target_epoch); - let mut found_summary = None; - - while start < end { - let mid = (start + end) / 2; - let summary = download_checkpoint_summary(config, mid).await?; - - // print summary epoch and seq - println!( - "Epoch: {} Seq: {}: {}", - summary.epoch(), - summary.sequence_number, - summary.end_of_epoch_data.is_some() - ); - - if summary.epoch() == target_epoch && summary.end_of_epoch_data.is_some() { - found_summary = Some(summary); - break; - } - - if summary.epoch() <= target_epoch { - start = mid + 1; - } else { - end = mid; - } - } - - if let Some(summary) = found_summary { - // Note: Do not write summary to file, since we must only persist - // checkpoints that have been verified by the previous committee - - // Add to the list - checkpoints_list.checkpoints.push(summary.sequence_number); - write_checkpoint_list(config, &checkpoints_list)?; - - // Update - last_epoch = summary.epoch(); - last_checkpoint_seq = summary.sequence_number; - } - } - - Ok(()) -} - -async fn check_and_sync_checkpoints(config: &Config) -> anyhow::Result<()> { - sync_checkpoint_list_to_latest(config).await?; - - // Get the local checkpoint list - let checkpoints_list: CheckpointsList = read_checkpoint_list(config)?; - - // Load the genesis committee - let mut genesis_path = config.checkpoint_summary_dir.clone(); - genesis_path.push(&config.genesis_filename); - let genesis_committee = Genesis::load(&genesis_path)?.committee()?; - - // Check the signatures of all checkpoints - // And download any missing ones - - let mut prev_committee = genesis_committee; - for ckp_id in &checkpoints_list.checkpoints { - // check if there is a file with this name ckp_id.yaml in the - // checkpoint_summary_dir - let mut checkpoint_path = config.checkpoint_summary_dir.clone(); - checkpoint_path.push(format!("{}.yaml", ckp_id)); - - // If file exists read the file otherwise download it from the server - let summary = if checkpoint_path.exists() { - read_checkpoint(config, *ckp_id)? - } else { - // Download the checkpoint from the server - let summary = download_checkpoint_summary(config, *ckp_id).await?; - summary.clone().verify(&prev_committee)?; - // Write the checkpoint summary to a file - write_checkpoint(config, &summary)?; - summary - }; - - // Print the id of the checkpoint and the epoch number - println!( - "Epoch: {} Checkpoint ID: {}", - summary.epoch(), - summary.digest() - ); - - // Extract the new committee information - if let Some(EndOfEpochData { - next_epoch_committee, - .. - }) = &summary.end_of_epoch_data - { - let next_committee = next_epoch_committee.iter().cloned().collect(); - prev_committee = - Committee::new(summary.epoch().checked_add(1).unwrap(), next_committee); - } else { - return Err(anyhow!( - "Expected all checkpoints to be end-of-epoch checkpoints" - )); - } - } - - Ok(()) -} - -async fn get_full_checkpoint(config: &Config, seq: u64) -> anyhow::Result { - // Downloading the checkpoint from the server - let client: Client = Client::new(config.rest_url()); - let full_checkpoint = client.get_full_checkpoint(seq).await?; - - Ok(full_checkpoint) -} - -fn extract_verified_effects_and_events( - checkpoint: &CheckpointData, - committee: &Committee, - tid: TransactionDigest, -) -> anyhow::Result<(TransactionEffects, Option)> { - let summary = &checkpoint.checkpoint_summary; - - // Verify the checkpoint summary using the committee - summary.verify_with_contents(committee, Some(&checkpoint.checkpoint_contents))?; - - // Check the validity of the transaction - let contents = &checkpoint.checkpoint_contents; - let (matching_tx, _) = checkpoint - .transactions - .iter() - .zip(contents.iter()) - // Note that we get the digest of the effects to ensure this is - // indeed the correct effects that are authenticated in the contents. - .find(|(tx, digest)| { - tx.effects.execution_digests() == **digest && digest.transaction == tid - }) - .ok_or(anyhow!("Transaction not found in checkpoint contents"))?; - - // Check the events are all correct. - let events_digest = matching_tx.events.as_ref().map(|events| events.digest()); - anyhow::ensure!( - events_digest.as_ref() == matching_tx.effects.events_digest(), - "Events digest does not match" - ); - - // Since we do not check objects we do not return them - Ok((matching_tx.effects.clone(), matching_tx.events.clone())) -} - -async fn get_verified_effects_and_events( - config: &Config, - tid: TransactionDigest, -) -> anyhow::Result<(TransactionEffects, Option)> { - let sui_mainnet: Arc = Arc::new( - SuiClientBuilder::default() - .build(config.full_node_url.as_str()) - .await - .unwrap(), - ); - let read_api = sui_mainnet.read_api(); - - // Lookup the transaction id and get the checkpoint sequence number - let options = SuiTransactionBlockResponseOptions::new(); - let seq = read_api - .get_transaction_with_options(tid, options) - .await? - .checkpoint - .ok_or(anyhow!("Transaction not found"))?; - - // Download the full checkpoint for this sequence number - let full_check_point = get_full_checkpoint(config, seq).await?; - - // Load the list of stored checkpoints - let checkpoints_list: CheckpointsList = read_checkpoint_list(config)?; - - // find the stored checkpoint before the seq checkpoint - let prev_ckp_id = checkpoints_list - .checkpoints - .iter() - .filter(|ckp_id| **ckp_id < seq) - .last(); - - let committee = if let Some(prev_ckp_id) = prev_ckp_id { - // Read it from the store - let prev_ckp = read_checkpoint(config, *prev_ckp_id)?; - - // Check we have the right checkpoint - anyhow::ensure!( - prev_ckp.epoch().checked_add(1).unwrap() == full_check_point.checkpoint_summary.epoch(), - "Checkpoint sequence number does not match. Need to Sync." - ); - - // Get the committee from the previous checkpoint - let current_committee = prev_ckp - .end_of_epoch_data - .as_ref() - .ok_or(anyhow!( - "Expected all checkpoints to be end-of-epoch checkpoints" - ))? - .next_epoch_committee - .iter() - .cloned() - .collect(); - - // Make a committee object using this - Committee::new(prev_ckp.epoch().checked_add(1).unwrap(), current_committee) - } else { - // Since we did not find a small committee checkpoint we use the genesis - let mut genesis_path = config.checkpoint_summary_dir.clone(); - genesis_path.push(&config.genesis_filename); - Genesis::load(&genesis_path)?.committee()? - }; - - extract_verified_effects_and_events(&full_check_point, &committee, tid) -} - -async fn get_verified_object(config: &Config, id: ObjectID) -> anyhow::Result { - let client: Client = Client::new(config.rest_url()); - let object = client.get_object(id).await?; - - // Need to authenticate this object - let (effects, _) = get_verified_effects_and_events(config, object.previous_transaction).await?; - - // check that this object ID, version and hash is in the effects - effects - .all_changed_objects() - .iter() - .find(|object_ref| object_ref.0 == object.compute_object_reference()) - .ok_or(anyhow!("Object not found"))?; - - Ok(object) -} - -#[tokio::main] -pub async fn main() { - // Command line arguments and config loading - let args = Args::parse(); - - let path = args - .config - .unwrap_or_else(|| panic!("Need a config file path")); - let reader = fs::File::open(path.clone()) - .unwrap_or_else(|_| panic!("Unable to load config from {}", path.display())); - let config: Config = serde_yaml::from_reader(reader).unwrap(); - - // Print config parameters - println!( - "Checkpoint Dir: {}", - config.checkpoint_summary_dir.display() - ); - - let client: Client = Client::new(config.rest_url()); - let remote_package_store = RemotePackageStore::new(client, config.clone()); - let resolver = Resolver::new(remote_package_store); - - match args.command { - Some(SCommands::Transaction { tid }) => { - let (effects, events) = get_verified_effects_and_events( - &config, - TransactionDigest::from_str(&tid).unwrap(), - ) - .await - .unwrap(); - - let exec_digests = effects.execution_digests(); - println!( - "Executed TID: {} Effects: {}", - exec_digests.transaction, exec_digests.effects - ); - - for event in events.as_ref().unwrap().data.iter() { - let type_layout = resolver - .type_layout(event.type_.clone().into()) - .await - .unwrap(); - - let json_val = - SuiJsonValue::from_bcs_bytes(Some(&type_layout), &event.contents).unwrap(); - - println!( - "Event:\n - Package: {}\n - Module: {}\n - Sender: {}\n - Type: {}\n{}", - event.package_id, - event.transaction_module, - event.sender, - event.type_, - serde_json::to_string_pretty(&json_val.to_json_value()).unwrap() - ); - } - } - Some(SCommands::Object { oid }) => { - let oid = ObjectID::from_str(&oid).unwrap(); - let object = get_verified_object(&config, oid).await.unwrap(); - - if let Data::Move(move_object) = &object.data { - let object_type = move_object.type_().clone(); - - let type_layout = resolver - .type_layout(object_type.clone().into()) - .await - .unwrap(); - - let json_val = - SuiJsonValue::from_bcs_bytes(Some(&type_layout), move_object.contents()) - .unwrap(); - - let (oid, version, hash) = object.compute_object_reference(); - println!( - "OID: {}\n - Version: {}\n - Hash: {}\n - Owner: {}\n - Type: {}\n{}", - oid, - version, - hash, - object.owner, - object_type, - serde_json::to_string_pretty(&json_val.to_json_value()).unwrap() - ); - } - } - - Some(SCommands::Sync {}) => { - check_and_sync_checkpoints(&config) - .await - .expect("Failed to sync checkpoints"); - } - _ => {} - } -} - -// Make a test namespace -#[cfg(test)] -mod tests { - use std::path::{Path, PathBuf}; - - use sui_types::messages_checkpoint::FullCheckpointContents; - - use super::*; - - async fn read_full_checkpoint(checkpoint_path: &PathBuf) -> anyhow::Result { - let mut reader = fs::File::open(checkpoint_path.clone())?; - let metadata = fs::metadata(checkpoint_path)?; - let mut buffer = vec![0; metadata.len() as usize]; - reader.read_exact(&mut buffer)?; - bcs::from_bytes(&buffer).map_err(|_| anyhow!("Unable to parse checkpoint file")) - } - - // clippy ignore dead-code - #[allow(dead_code)] - async fn write_full_checkpoint( - checkpoint_path: &Path, - checkpoint: &CheckpointData, - ) -> anyhow::Result<()> { - let mut writer = fs::File::create(checkpoint_path)?; - let bytes = bcs::to_bytes(&checkpoint) - .map_err(|_| anyhow!("Unable to serialize checkpoint summary"))?; - writer.write_all(&bytes)?; - Ok(()) - } - - async fn read_data() -> (Committee, CheckpointData) { - let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - d.push("example_config/20873329.yaml"); - - let mut reader = fs::File::open(d.clone()).unwrap(); - let metadata = fs::metadata(&d).unwrap(); - let mut buffer = vec![0; metadata.len() as usize]; - reader.read_exact(&mut buffer).unwrap(); - let checkpoint: Envelope> = - bcs::from_bytes(&buffer) - .map_err(|_| anyhow!("Unable to parse checkpoint file")) - .unwrap(); - - let prev_committee = checkpoint - .end_of_epoch_data - .as_ref() - .ok_or(anyhow!( - "Expected all checkpoints to be end-of-epoch checkpoints" - )) - .unwrap() - .next_epoch_committee - .iter() - .cloned() - .collect(); - - // Make a committee object using this - let committee = Committee::new(checkpoint.epoch().checked_add(1).unwrap(), prev_committee); - - let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - d.push("example_config/20958462.bcs"); - - let full_checkpoint = read_full_checkpoint(&d).await.unwrap(); - - (committee, full_checkpoint) - } - - #[tokio::test] - async fn test_checkpoint_all_good() { - let (committee, full_checkpoint) = read_data().await; - - extract_verified_effects_and_events( - &full_checkpoint, - &committee, - TransactionDigest::from_str("8RiKBwuAbtu8zNCtz8SrcfHyEUzto6zi6cMVA9t4WhWk").unwrap(), - ) - .unwrap(); - } - - #[tokio::test] - async fn test_checkpoint_bad_committee() { - let (mut committee, full_checkpoint) = read_data().await; - - // Change committee - committee.epoch += 10; - - assert!( - extract_verified_effects_and_events( - &full_checkpoint, - &committee, - TransactionDigest::from_str("8RiKBwuAbtu8zNCtz8SrcfHyEUzto6zi6cMVA9t4WhWk") - .unwrap(), - ) - .is_err() - ); - } - - #[tokio::test] - async fn test_checkpoint_no_transaction() { - let (committee, full_checkpoint) = read_data().await; - - assert!( - extract_verified_effects_and_events( - &full_checkpoint, - &committee, - TransactionDigest::from_str("8RiKBwuAbtu8zNCtz8SrcfHyEUzto6zj6cMVA9t4WhWk") - .unwrap(), - ) - .is_err() - ); - } - - #[tokio::test] - async fn test_checkpoint_bad_contents() { - let (committee, mut full_checkpoint) = read_data().await; - - // Change contents - let random_contents = FullCheckpointContents::random_for_testing(); - full_checkpoint.checkpoint_contents = random_contents.checkpoint_contents(); - - assert!( - extract_verified_effects_and_events( - &full_checkpoint, - &committee, - TransactionDigest::from_str("8RiKBwuAbtu8zNCtz8SrcfHyEUzto6zj6cMVA9t4WhWk") - .unwrap(), - ) - .is_err() - ); - } - - #[tokio::test] - async fn test_checkpoint_bad_events() { - let (committee, mut full_checkpoint) = read_data().await; - - let event = full_checkpoint.transactions[4] - .events - .as_ref() - .unwrap() - .data[0] - .clone(); - - for t in &mut full_checkpoint.transactions { - if let Some(events) = &mut t.events { - events.data.push(event.clone()); - } - } - - assert!( - extract_verified_effects_and_events( - &full_checkpoint, - &committee, - TransactionDigest::from_str("8RiKBwuAbtu8zNCtz8SrcfHyEUzto6zj6cMVA9t4WhWk") - .unwrap(), - ) - .is_err() - ); - } -} diff --git a/crates/sui-macros/Cargo.toml b/crates/sui-macros/Cargo.toml deleted file mode 100644 index c7e99bd255f..00000000000 --- a/crates/sui-macros/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "sui-macros" -version = "0.7.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -sui-proc-macros.workspace = true -once_cell.workspace = true -futures.workspace = true -tracing.workspace = true diff --git a/crates/sui-macros/src/lib.rs b/crates/sui-macros/src/lib.rs deleted file mode 100644 index 3ce525956fc..00000000000 --- a/crates/sui-macros/src/lib.rs +++ /dev/null @@ -1,732 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::HashMap, future::Future, sync::Arc}; - -use futures::future::BoxFuture; -pub use sui_proc_macros::*; - -/// Evaluates an expression in a new thread which will not be subject to -/// interception of getrandom(), clock_gettime(), etc. -#[cfg(msim)] -#[macro_export] -macro_rules! nondeterministic { - ($expr: expr) => { - std::thread::scope(move |s| s.spawn(move || $expr).join().unwrap()) - }; -} - -/// Simply evaluates expr. -#[cfg(not(msim))] -#[macro_export] -macro_rules! nondeterministic { - ($expr: expr) => { - $expr - }; -} - -type FpCallback = dyn Fn() -> Box + Send + Sync; -type FpMap = HashMap<&'static str, Arc>; - -#[cfg(msim)] -fn with_fp_map(func: impl FnOnce(&mut FpMap) -> T) -> T { - thread_local! { - static MAP: std::cell::RefCell = Default::default(); - } - - MAP.with(|val| func(&mut val.borrow_mut())) -} - -#[cfg(not(msim))] -fn with_fp_map(func: impl FnOnce(&mut FpMap) -> T) -> T { - use std::sync::Mutex; - - use once_cell::sync::Lazy; - - static MAP: Lazy> = Lazy::new(Default::default); - let mut map = MAP.lock().unwrap(); - func(&mut map) -} - -fn get_callback(identifier: &'static str) -> Option> { - with_fp_map(|map| map.get(identifier).cloned()) -} - -fn get_sync_fp_result(result: Box) { - if result.downcast::<()>().is_err() { - panic!("sync failpoint must return ()"); - } -} - -fn get_async_fp_result(result: Box) -> BoxFuture<'static, ()> { - match result.downcast::>() { - Ok(fut) => *fut, - Err(err) => panic!( - "async failpoint must return BoxFuture<'static, ()> {:?}", - err - ), - } -} - -fn get_fp_if_result(result: Box) -> bool { - match result.downcast::() { - Ok(b) => *b, - Err(_) => panic!("failpoint-if must return bool"), - } -} - -fn get_fp_some_result( - result: Box, -) -> Option { - match result.downcast::>() { - Ok(opt) => *opt, - Err(_) => panic!("failpoint-arg must return Option"), - } -} - -pub fn handle_fail_point(identifier: &'static str) { - if let Some(callback) = get_callback(identifier) { - get_sync_fp_result(callback()); - tracing::trace!("hit failpoint {}", identifier); - } -} - -pub async fn handle_fail_point_async(identifier: &'static str) { - if let Some(callback) = get_callback(identifier) { - tracing::trace!("hit async failpoint {}", identifier); - let fut = get_async_fp_result(callback()); - fut.await; - } -} - -pub fn handle_fail_point_if(identifier: &'static str) -> bool { - if let Some(callback) = get_callback(identifier) { - tracing::trace!("hit failpoint_if {}", identifier); - get_fp_if_result(callback()) - } else { - false - } -} - -pub fn handle_fail_point_arg(identifier: &'static str) -> Option { - if let Some(callback) = get_callback(identifier) { - tracing::trace!("hit failpoint_arg {}", identifier); - get_fp_some_result(callback()) - } else { - None - } -} - -fn register_fail_point_impl(identifier: &'static str, callback: Arc) { - with_fp_map(move |map| { - assert!( - map.insert(identifier, callback).is_none(), - "duplicate fail point registration" - ); - }) -} - -fn clear_fail_point_impl(identifier: &'static str) { - with_fp_map(move |map| { - assert!( - map.remove(identifier).is_some(), - "fail point {:?} does not exist", - identifier - ); - }) -} - -pub fn register_fail_point(identifier: &'static str, callback: impl Fn() + Sync + Send + 'static) { - register_fail_point_impl( - identifier, - Arc::new(move || { - callback(); - Box::new(()) - }), - ); -} - -/// Register an asynchronous fail point. Because it is async it can yield -/// execution of the calling task, e.g. by sleeping. -pub fn register_fail_point_async( - identifier: &'static str, - callback: impl Fn() -> F + Sync + Send + 'static, -) where - F: Future + Send + 'static, -{ - register_fail_point_impl( - identifier, - Arc::new(move || { - let result: BoxFuture<'static, ()> = Box::pin(callback()); - Box::new(result) - }), - ); -} - -/// Register code to run locally if the fail point is hit. Example: -/// -/// In the test: -/// -/// ```ignore -/// register_fail_point_if("foo", || { -/// sui_simulator::current_simnode_id() == 2 -/// }); -/// ``` -/// -/// In the code: -/// -/// ```ignore -/// let mut was_hit = false; -/// fail_point_if("foo", || { -/// was_hit = true; -/// }); -/// ``` -pub fn register_fail_point_if( - identifier: &'static str, - callback: impl Fn() -> bool + Sync + Send + 'static, -) { - register_fail_point_impl(identifier, Arc::new(move || Box::new(callback()))); -} - -/// Register code to run locally if the fail point is hit, with a value provided -/// by the test. If the registered callback returns a Some(v), then the `v` is -/// passed to the callback in the test. -/// -/// In the test: -/// -/// ```ignore -/// register_fail_point_arg("foo", || { -/// Some(42) -/// }); -/// ``` -/// -/// In the code: -/// -/// ```ignore -/// let mut value = 0; -/// fail_point_arg!("foo", |arg| { -/// value = arg; -/// }); -/// ``` -pub fn register_fail_point_arg( - identifier: &'static str, - callback: impl Fn() -> Option + Sync + Send + 'static, -) { - register_fail_point_impl(identifier, Arc::new(move || Box::new(callback()))); -} - -pub fn register_fail_points( - identifiers: &[&'static str], - callback: impl Fn() + Sync + Send + 'static, -) { - let cb: Arc = Arc::new(move || { - callback(); - Box::new(()) - }); - for id in identifiers { - register_fail_point_impl(id, cb.clone()); - } -} - -pub fn clear_fail_point(identifier: &'static str) { - clear_fail_point_impl(identifier); -} - -/// Trigger a fail point. Tests can trigger various behavior when the fail point -/// is hit. -#[cfg(any(msim, fail_points))] -#[macro_export] -macro_rules! fail_point { - ($tag: expr) => { - $crate::handle_fail_point($tag) - }; -} - -/// Trigger an async fail point. Tests can trigger various async behavior when -/// the fail point is hit. -#[cfg(any(msim, fail_points))] -#[macro_export] -macro_rules! fail_point_async { - ($tag: expr) => { - $crate::handle_fail_point_async($tag).await - }; -} - -/// Trigger a failpoint that runs a callback at the callsite if it is enabled. -/// (whether it is enabled is controlled by whether the registration callback -/// returns true/false). -#[cfg(any(msim, fail_points))] -#[macro_export] -macro_rules! fail_point_if { - ($tag: expr, $callback: expr) => { - if $crate::handle_fail_point_if($tag) { - ($callback)(); - } - }; -} - -/// Trigger a failpoint that runs a callback at the callsite if it is enabled. -/// If the registration callback returns Some(v), then the `v` is passed to the -/// callback in the test. Otherwise the failpoint is skipped -#[cfg(any(msim, fail_points))] -#[macro_export] -macro_rules! fail_point_arg { - ($tag: expr, $callback: expr) => { - if let Some(arg) = $crate::handle_fail_point_arg($tag) { - ($callback)(arg); - } - }; -} - -#[cfg(not(any(msim, fail_points)))] -#[macro_export] -macro_rules! fail_point { - ($tag: expr) => {}; -} - -#[cfg(not(any(msim, fail_points)))] -#[macro_export] -macro_rules! fail_point_async { - ($tag: expr) => {}; -} - -#[cfg(not(any(msim, fail_points)))] -#[macro_export] -macro_rules! fail_point_if { - ($tag: expr, $callback: expr) => {}; -} - -#[cfg(not(any(msim, fail_points)))] -#[macro_export] -macro_rules! fail_point_arg { - ($tag: expr, $callback: expr) => {}; -} - -/// Use to write INFO level logs only when REPLAY_LOG -/// environment variable is set. Useful for log lines that -/// are only relevant to test infra which still may need to -/// run a release build. Also note that since logs of a chain -/// replay are exceedingly verbose, this will allow one to bubble -/// up "debug level" info while running with RUST_LOG=info. -#[macro_export] -macro_rules! replay_log { - ($($arg:tt)+) => { - if std::env::var("REPLAY_LOG").is_ok() { - tracing::info!($($arg)+); - } - }; -} - -// These tests need to be run in release mode, since debug mode does overflow -// checks by default! -#[cfg(test)] -mod test { - use super::*; - - // Uncomment to test error messages - // #[with_checked_arithmetic] - // struct TestStruct; - - macro_rules! pass_through { - ($($tt:tt)*) => { - $($tt)* - } - } - - #[with_checked_arithmetic] - #[test] - fn test_skip_checked_arithmetic() { - // comment out this attr to test the error message - #[skip_checked_arithmetic] - pass_through! { - fn unchecked_add(a: i32, b: i32) -> i32 { - a + b - } - } - - // this will not panic even if we pass in (i32::MAX, 1), because we skipped - // processing the item macro, so we also need to make sure it doesn't - // panic in debug mode. - unchecked_add(1, 2); - } - - checked_arithmetic! { - - struct Test { - a: i32, - b: i32, - } - - fn unchecked_add(a: i32, b: i32) -> i32 { - a + b - } - - #[test] - fn test_checked_arithmetic_macro() { - unchecked_add(1, 2); - } - - #[test] - #[should_panic] - fn test_checked_arithmetic_macro_panic() { - unchecked_add(i32::MAX, 1); - } - - fn unchecked_add_hidden(a: i32, b: i32) -> i32 { - let inner = |a: i32, b: i32| a + b; - inner(a, b) - } - - #[test] - #[should_panic] - fn test_checked_arithmetic_macro_panic_hidden() { - unchecked_add_hidden(i32::MAX, 1); - } - - fn unchecked_add_hidden_2(a: i32, b: i32) -> i32 { - fn inner(a: i32, b: i32) -> i32 { - a + b - } - inner(a, b) - } - - #[test] - #[should_panic] - fn test_checked_arithmetic_macro_panic_hidden_2() { - unchecked_add_hidden_2(i32::MAX, 1); - } - - impl Test { - fn add(&self) -> i32 { - self.a + self.b - } - } - - #[test] - #[should_panic] - fn test_checked_arithmetic_impl() { - let t = Test { a: 1, b: i32::MAX }; - t.add(); - } - - #[test] - #[should_panic] - fn test_macro_overflow() { - #[allow(arithmetic_overflow)] - fn f() { - println!("{}", i32::MAX + 1); - } - - f() - } - - // Make sure that we still do addition correctly! - #[test] - fn test_non_overflow() { - fn f() { - assert_eq!(1i32 + 2i32, 3i32); - assert_eq!(3i32 - 1i32, 2i32); - assert_eq!(4i32 * 3i32, 12i32); - assert_eq!(12i32 / 3i32, 4i32); - assert_eq!(12i32 % 5i32, 2i32); - - let mut a = 1i32; - a += 2i32; - assert_eq!(a, 3i32); - - let mut a = 3i32; - a -= 1i32; - assert_eq!(a, 2i32); - - let mut a = 4i32; - a *= 3i32; - assert_eq!(a, 12i32); - - let mut a = 12i32; - a /= 3i32; - assert_eq!(a, 4i32); - - let mut a = 12i32; - a %= 5i32; - assert_eq!(a, 2i32); - } - - f(); - } - - - #[test] - fn test_exprs_evaluated_once_right() { - let mut called = false; - let mut f = || { - if called { - panic!("called twice"); - } - called = true; - 1i32 - }; - - assert_eq!(2i32 + f(), 3); - } - - #[test] - fn test_exprs_evaluated_once_left() { - let mut called = false; - let mut f = || { - if called { - panic!("called twice"); - } - called = true; - 1i32 - }; - - assert_eq!(f() + 2i32, 3); - } - - #[test] - fn test_assign_op_evals_once() { - struct Foo { - a: i32, - called: bool, - } - - impl Foo { - fn get_a_mut(&mut self) -> &mut i32 { - if self.called { - panic!("called twice"); - } - let ret = &mut self.a; - self.called = true; - ret - } - } - - let mut foo = Foo { a: 1, called: false }; - - *foo.get_a_mut() += 2; - assert_eq!(foo.a, 3); - } - - #[test] - fn test_more_macro_syntax() { - struct Foo { - a: i32, - b: i32, - } - - impl Foo { - const BAR: i32 = 1; - - fn new(a: i32, b: i32) -> Foo { - Foo { a, b } - } - } - - fn new_foo(a: i32) -> Foo { - Foo { a, b: 0 } - } - - // verify that we translate the contents of macros correctly - assert_eq!(Foo::BAR + 1, 2); - assert_eq!(Foo::new(1, 2).b, 2); - assert_eq!(new_foo(1).a, 1); - - let v = vec![Foo::new(1, 2), Foo::new(3, 2)]; - - assert_eq!(v[0].a, 1); - assert_eq!(v[1].b, 2); - } - - } - - #[with_checked_arithmetic] - mod with_checked_arithmetic_tests { - - struct Test { - a: i32, - b: i32, - } - - fn unchecked_add(a: i32, b: i32) -> i32 { - a + b - } - - #[test] - fn test_checked_arithmetic_macro() { - unchecked_add(1, 2); - } - - #[test] - #[should_panic] - fn test_checked_arithmetic_macro_panic() { - unchecked_add(i32::MAX, 1); - } - - fn unchecked_add_hidden(a: i32, b: i32) -> i32 { - let inner = |a: i32, b: i32| a + b; - inner(a, b) - } - - #[test] - #[should_panic] - fn test_checked_arithmetic_macro_panic_hidden() { - unchecked_add_hidden(i32::MAX, 1); - } - - fn unchecked_add_hidden_2(a: i32, b: i32) -> i32 { - fn inner(a: i32, b: i32) -> i32 { - a + b - } - inner(a, b) - } - - #[test] - #[should_panic] - fn test_checked_arithmetic_macro_panic_hidden_2() { - unchecked_add_hidden_2(i32::MAX, 1); - } - - impl Test { - fn add(&self) -> i32 { - self.a + self.b - } - } - - #[test] - #[should_panic] - fn test_checked_arithmetic_impl() { - let t = Test { a: 1, b: i32::MAX }; - t.add(); - } - - #[test] - #[should_panic] - fn test_macro_overflow() { - #[allow(arithmetic_overflow)] - fn f() { - println!("{}", i32::MAX + 1); - } - - f() - } - - // Make sure that we still do addition correctly! - #[test] - fn test_non_overflow() { - fn f() { - assert_eq!(1i32 + 2i32, 3i32); - assert_eq!(3i32 - 1i32, 2i32); - assert_eq!(4i32 * 3i32, 12i32); - assert_eq!(12i32 / 3i32, 4i32); - assert_eq!(12i32 % 5i32, 2i32); - - let mut a = 1i32; - a += 2i32; - assert_eq!(a, 3i32); - - let mut a = 3i32; - a -= 1i32; - assert_eq!(a, 2i32); - - let mut a = 4i32; - a *= 3i32; - assert_eq!(a, 12i32); - - let mut a = 12i32; - a /= 3i32; - assert_eq!(a, 4i32); - - let mut a = 12i32; - a %= 5i32; - assert_eq!(a, 2i32); - } - - f(); - } - - #[test] - fn test_exprs_evaluated_once_right() { - let mut called = false; - let mut f = || { - if called { - panic!("called twice"); - } - called = true; - 1i32 - }; - - assert_eq!(2i32 + f(), 3); - } - - #[test] - fn test_exprs_evaluated_once_left() { - let mut called = false; - let mut f = || { - if called { - panic!("called twice"); - } - called = true; - 1i32 - }; - - assert_eq!(f() + 2i32, 3); - } - - #[test] - fn test_assign_op_evals_once() { - struct Foo { - a: i32, - called: bool, - } - - impl Foo { - fn get_a_mut(&mut self) -> &mut i32 { - if self.called { - panic!("called twice"); - } - let ret = &mut self.a; - self.called = true; - ret - } - } - - let mut foo = Foo { - a: 1, - called: false, - }; - - *foo.get_a_mut() += 2; - assert_eq!(foo.a, 3); - } - - #[test] - fn test_more_macro_syntax() { - struct Foo { - a: i32, - b: i32, - } - - impl Foo { - const BAR: i32 = 1; - - fn new(a: i32, b: i32) -> Foo { - Foo { a, b } - } - } - - fn new_foo(a: i32) -> Foo { - Foo { a, b: 0 } - } - - // verify that we translate the contents of macros correctly - assert_eq!(Foo::BAR + 1, 2); - assert_eq!(Foo::new(1, 2).b, 2); - assert_eq!(new_foo(1).a, 1); - - let v = vec![Foo::new(1, 2), Foo::new(3, 2)]; - - assert_eq!(v[0].a, 1); - assert_eq!(v[1].b, 2); - } - } -} diff --git a/crates/sui-metric-checker/Cargo.toml b/crates/sui-metric-checker/Cargo.toml deleted file mode 100644 index 51193f8f147..00000000000 --- a/crates/sui-metric-checker/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "sui-metric-checker" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -backoff.workspace = true -base64.workspace = true -chrono.workspace = true -clap = { version = "4.3.0", features = ["derive"] } -humantime.workspace = true -once_cell.workspace = true -prometheus-http-query.workspace = true -reqwest.workspace = true -serde.workspace = true -serde_yaml = "0.9.21" -strum_macros.workspace = true -telemetry-subscribers.workspace = true -tokio = { workspace = true, features = ["full"] } -tracing.workspace = true diff --git a/crates/sui-metric-checker/README.md b/crates/sui-metric-checker/README.md deleted file mode 100644 index 405e2e01c91..00000000000 --- a/crates/sui-metric-checker/README.md +++ /dev/null @@ -1,26 +0,0 @@ -The `sui-metric-checker` crate is used for querying prometheus metrics and validating the results. It will primarily be used to check for performance regressions in nightly deployments. Requires `api_key`, `api_user` & prometheus `url` which can be found in `sui-ops` repo or by asking the PE team. - -## Guide - -### Example Usage - -``` -RUST_LOG=debug cargo run --package sui-metric-checker --bin sui-metric-checker -- --api-key xxxxxxxx --api-user xxxx_metrics --config checks.yaml --url https://xxxx.sui.io/prometheus -``` - -### Example Config - -[example/config.yaml](example/config.yaml#L1-L32) - -### Example Error Output - -``` -Error: Following queries failed to meet threshold conditions: [ - "After 3 retry attempts - Did not get expected response from server for histogram_quantile(0.5, sum by(le) (rate(latency_s_bucket{network=\"private-testnet\"}[15m])))", - "After 3 retry attempts - Did not get expected response from server for histogram_quantile(0.95, sum by(le) (rate(latency_s_bucket{network=\"private-testnet\"}[15m])))", - "After 3 retry attempts - Did not get expected response from server for sum(rate(num_success{network=\"private-testnet\"}[5m]))", - "Query \"histogram_quantile(0.50, sum by(le) (rate(batch_execution_latency_bucket{network=\"private-testnet\"}[15m])))\" returned value of 3.112150385622982 which is Greater 3", - "Query \"avg(rate(total_transaction_effects{network=\"private-testnet\"}[5m]))\" returned value of 1.081275647819765 which is Less 5500", - "Query \"avg (rate(batch_size_sum{network=\"private-testnet\"}[5m]))\" returned value of 0.24698238962944846 which is Less 5500", -] -``` diff --git a/crates/sui-metric-checker/src/lib.rs b/crates/sui-metric-checker/src/lib.rs deleted file mode 100644 index bf5da3d4fdc..00000000000 --- a/crates/sui-metric-checker/src/lib.rs +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use anyhow::anyhow; -use chrono::{DateTime, Duration, NaiveDateTime, Utc}; -use humantime::parse_duration; -use serde::Deserialize; -use strum_macros::Display; - -pub mod query; - -#[derive(Debug, Display, Deserialize, PartialEq)] -pub enum QueryType { - Instant, - Range { - // Both start & end accepts specific time formats - // - "%Y-%m-%d %H:%M:%S" (UTC) - // Or relative time + offset, i.e. - // - "now" - // - "now-1h" - // - "now-30m 10s" - start: String, - end: String, - // Query resolution step width as float number of seconds - step: f64, - }, -} - -#[derive(Debug, Display, Deserialize, PartialEq)] -pub enum Condition { - Greater, - Equal, - Less, -} - -// Used to specify validation rules for query result e.g. -// -// validate_result: -// threshold: 10 -// failure_condition: Greater -// -// Program will report error if queried value is greater than 10, otherwise -// no error will be reported. -#[derive(Debug, Deserialize, PartialEq)] -pub struct QueryResultValidation { - // Threshold to report error on - pub threshold: f64, - // Program will report error if threshold violates condition specifed by this - // field. - pub failure_condition: Condition, -} - -#[derive(Debug, Deserialize, PartialEq)] -pub struct Query { - // PromQL query to exeute - pub query: String, - // Type of query to execute - Instant or Range. - #[serde(rename = "type")] - pub query_type: QueryType, - // Optional validation rules for the query result, otherwise the query result - // is just to be printed in debug logs. - pub validate_result: Option, -} - -#[derive(Debug, Deserialize)] -pub struct Config { - pub queries: Vec, -} - -// Used to mock now() in tests and use consistent now() return values across -// queries in performance checks. -pub trait NowProvider { - fn now() -> DateTime; -} - -pub struct UtcNowProvider; - -// Basic implementation of NowProvider that returns current time in UTC. -impl NowProvider for UtcNowProvider { - fn now() -> DateTime { - Utc::now() - } -} - -// Convert timestamp string to unix seconds. -// Accepts the following time formats -// - "%Y-%m-%d %H:%M:%S" (UTC) -// Or relative time + offset, i.e. -// - "now" -// - "now-1h" -// - "now-30m 10s" -pub fn timestamp_string_to_unix_seconds( - timestamp: &str, -) -> Result { - if timestamp.starts_with("now") { - if let Some(relative_timestamp) = timestamp.strip_prefix("now-") { - let duration = parse_duration(relative_timestamp)?; - let now = N::now(); - let new_datetime = now.checked_sub_signed(Duration::from_std(duration)?); - - if let Some(datetime) = new_datetime { - return Ok(datetime.timestamp()); - } else { - return Err(anyhow!("Unable to calculate time offset")); - } - } - - return Ok(N::now().timestamp()); - } - - if let Ok(datetime) = NaiveDateTime::parse_from_str(timestamp, "%Y-%m-%d %H:%M:%S") { - let utc_datetime: DateTime = DateTime::from_naive_utc_and_offset(datetime, Utc); - Ok(utc_datetime.timestamp()) - } else { - Err(anyhow!("Invalid timestamp format")) - } -} - -pub fn fails_threshold_condition( - queried_value: f64, - threshold: f64, - failure_condition: &Condition, -) -> bool { - match failure_condition { - Condition::Greater => queried_value > threshold, - Condition::Equal => queried_value == threshold, - Condition::Less => queried_value < threshold, - } -} - -fn unix_seconds_to_timestamp_string(unix_seconds: i64) -> String { - let datetime = NaiveDateTime::from_timestamp_opt(unix_seconds, 0); - let timestamp: DateTime = DateTime::from_naive_utc_and_offset(datetime.unwrap(), Utc); - timestamp.to_string() -} - -#[cfg(test)] -mod tests { - use chrono::TimeZone; - - use super::*; - - struct MockNowProvider; - - impl NowProvider for MockNowProvider { - fn now() -> DateTime { - Utc.timestamp_opt(1628553600, 0).unwrap() - } - } - - #[test] - fn test_parse_timestamp_string_to_unix_seconds() { - let timestamp = "2021-08-10 00:00:00"; - let unix_seconds = timestamp_string_to_unix_seconds::(timestamp).unwrap(); - assert_eq!(unix_seconds, 1628553600); - - let timestamp = "now"; - let unix_seconds = timestamp_string_to_unix_seconds::(timestamp).unwrap(); - assert_eq!(unix_seconds, 1628553600); - - let timestamp = "now-1h"; - let unix_seconds = timestamp_string_to_unix_seconds::(timestamp).unwrap(); - assert_eq!(unix_seconds, 1628553600 - 3600); - - let timestamp = "now-30m 10s"; - let unix_seconds = timestamp_string_to_unix_seconds::(timestamp).unwrap(); - assert_eq!(unix_seconds, 1628553600 - 1810); - } - - #[test] - fn test_unix_seconds_to_timestamp_string() { - let unix_seconds = 1628534400; - let timestamp = unix_seconds_to_timestamp_string(unix_seconds); - assert_eq!(timestamp, "2021-08-09 18:40:00 UTC"); - } - - #[test] - fn test_parse_config() { - let config = r#" - queries: - - query: 'max(current_epoch{network="testnet"})' - type: Instant - - - query: 'histogram_quantile(0.50, sum by(le) (rate(round_latency{network="testnet"}[15m])))' - type: !Range - start: "now-1h" - end: "now" - step: 60.0 - validate_result: - threshold: 3.0 - failure_condition: Greater - "#; - - let config: Config = serde_yaml::from_str(config).unwrap(); - - let expected_range_query = Query { - query: "histogram_quantile(0.50, sum by(le) (rate(round_latency{network=\"testnet\"}[15m])))".to_string(), - query_type: QueryType::Range { - start: "now-1h".to_string(), - end: "now".to_string(), - step: 60.0, - }, - validate_result: Some(QueryResultValidation { - threshold: 3.0, - failure_condition: Condition::Greater, - }), - }; - - let expected_instant_query = Query { - query: "max(current_epoch{network=\"testnet\"})".to_string(), - query_type: QueryType::Instant, - validate_result: None, - }; - - let expected_queries = vec![expected_instant_query, expected_range_query]; - - assert_eq!(config.queries, expected_queries); - } -} diff --git a/crates/sui-metric-checker/src/main.rs b/crates/sui-metric-checker/src/main.rs deleted file mode 100644 index bda21156ff0..00000000000 --- a/crates/sui-metric-checker/src/main.rs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use std::{fs::File, io::Read, time::Duration}; - -use anyhow::anyhow; -use backoff::{future::retry, ExponentialBackoff}; -use chrono::{DateTime, Utc}; -use clap::*; -use once_cell::sync::Lazy; -use prometheus_http_query::Client; -use sui_metric_checker::{ - fails_threshold_condition, - query::{instant_query, range_query}, - timestamp_string_to_unix_seconds, Config, NowProvider, QueryType, -}; - -#[derive(Parser)] -pub struct Opts { - #[arg(long, required = true)] - api_user: String, - #[arg(long, required = true)] - api_key: String, - // Path to the config file - #[arg(long, required = true)] - config: String, - // URL of the Prometheus server - #[arg(long, required = true)] - url: String, -} - -// This allows us to use the same value for now() for all queries checked during -// the duration of tool. -struct UtcNowOnceProvider {} - -impl NowProvider for UtcNowOnceProvider { - fn now() -> DateTime { - static NOW: Lazy> = Lazy::new(Utc::now); - *NOW - } -} - -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - let opts: Opts = Opts::parse(); - let _guard = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .init(); - - let auth_header = format!("{}:{}", opts.api_user, opts.api_key); - - let mut file = File::open(opts.config)?; - let mut contents = String::new(); - file.read_to_string(&mut contents)?; - let config: Config = serde_yaml::from_str(&contents)?; - - let client = { - let c = reqwest::Client::builder() - .no_proxy() - .timeout(Duration::from_secs(10)) - .build() - .unwrap(); - Client::from(c, &opts.url).unwrap() - }; - - let backoff = ExponentialBackoff { - max_elapsed_time: Some(Duration::from_secs(5)), - ..ExponentialBackoff::default() - }; - - let mut failed_queries = Vec::new(); - for query in config.queries { - let queried_result = match query.query_type { - QueryType::Instant => { - retry(backoff.clone(), || async { - instant_query(&auth_header, client.clone(), &query.query) - .await - .map_err(backoff::Error::transient) - }) - .await - } - QueryType::Range { start, end, step } => { - retry(backoff.clone(), || async { - range_query( - &auth_header, - client.clone(), - &query.query, - timestamp_string_to_unix_seconds::(&start)?, - timestamp_string_to_unix_seconds::(&end)?, - step, - ) - .await - .map_err(backoff::Error::transient) - }) - .await - } - }; - - if let Some(validate_result) = query.validate_result { - match queried_result { - Ok(queried_value) => { - if fails_threshold_condition( - queried_value, - validate_result.threshold, - &validate_result.failure_condition, - ) { - failed_queries.push(format!( - "Query \"{}\" returned value of {queried_value} which is {} {}", - query.query, - validate_result.failure_condition, - validate_result.threshold - )); - } - } - Err(error) => { - failed_queries.push(error.to_string()); - continue; - } - } - } - } - - if !failed_queries.is_empty() { - return Err(anyhow!( - "Following queries failed to meet threshold conditions: {failed_queries:#?}" - )); - } - - Ok(()) -} diff --git a/crates/sui-metric-checker/src/query.rs b/crates/sui-metric-checker/src/query.rs deleted file mode 100644 index b34cee4f549..00000000000 --- a/crates/sui-metric-checker/src/query.rs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use anyhow::anyhow; -use base64::{engine::general_purpose, Engine}; -use prometheus_http_query::Client; -use reqwest::header::{HeaderValue, AUTHORIZATION}; -use tracing::debug; - -use crate::unix_seconds_to_timestamp_string; - -pub async fn instant_query( - auth_header: &str, - client: Client, - query: &str, -) -> Result { - debug!("Executing {query}"); - let response = client - .query(query) - .header( - AUTHORIZATION, - HeaderValue::from_str(&format!( - "Basic {}", - general_purpose::STANDARD.encode(auth_header) - ))?, - ) - .get() - .await?; - - let result = response - .data() - .as_vector() - .unwrap_or_else(|| panic!("Expected result of type vector for {query}")); - - if !result.is_empty() { - let first = result.first().unwrap(); - debug!("Got value {}", first.sample().value()); - Ok(first.sample().value()) - } else { - Err(anyhow!( - "Did not get expected response from server for {query}" - )) - } -} - -// This will return the average value of the queried metric over the given time -// range. -pub async fn range_query( - auth_header: &str, - client: Client, - query: &str, - start: i64, - end: i64, - step: f64, -) -> Result { - debug!("Executing {query}"); - let response = client - .query_range(query, start, end, step) - .header( - AUTHORIZATION, - HeaderValue::from_str(&format!( - "Basic {}", - general_purpose::STANDARD.encode(auth_header) - ))?, - ) - .get() - .await?; - - let result = response - .data() - .as_matrix() - .unwrap_or_else(|| panic!("Expected result of type matrix for {query}")); - - if !result.is_empty() { - let samples = result.first().unwrap().samples(); - let sum: f64 = samples.iter().map(|sample| sample.value()).sum(); - let count = samples.len(); - - let avg = if count > 0 { sum / count as f64 } else { 0.0 }; - debug!( - "Got average value {avg} over time range {} - {}", - unix_seconds_to_timestamp_string(start), - unix_seconds_to_timestamp_string(end) - ); - Ok(avg) - } else { - Err(anyhow!( - "Did not get expected response from server for {query}" - )) - } -} diff --git a/crates/sui-move-build/Cargo.toml b/crates/sui-move-build/Cargo.toml deleted file mode 100644 index 4896cf3c216..00000000000 --- a/crates/sui-move-build/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "sui-move-build" -version.workspace = true -edition = "2021" -authors = ["Mysten Labs "] -description = "Logic for building Sui Move Packages" -license = "Apache-2.0" -publish = false - -[dependencies] -anyhow.workspace = true -fastcrypto.workspace = true -tempfile.workspace = true - -move-bytecode-verifier = { path = "../../external-crates/move/crates/move-bytecode-verifier" } -sui-verifier = { path = "../../sui-execution/latest/sui-verifier", package = "sui-verifier-latest" } - -serde-reflection.workspace = true -sui-types.workspace = true -sui-protocol-config.workspace = true - -move-binary-format.workspace = true -move-bytecode-utils.workspace = true -move-command-line-common.workspace = true -move-compiler.workspace = true -move-core-types.workspace = true -move-ir-types.workspace = true -move-package.workspace = true -move-symbol-pool.workspace = true - -[dev-dependencies] -datatest-stable.workspace = true diff --git a/crates/sui-move-build/src/lib.rs b/crates/sui-move-build/src/lib.rs deleted file mode 100644 index eaf4240ca31..00000000000 --- a/crates/sui-move-build/src/lib.rs +++ /dev/null @@ -1,788 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -extern crate move_ir_types; - -use std::{ - collections::{BTreeMap, BTreeSet, HashSet}, - io::Write, - path::{Path, PathBuf}, - str::FromStr, -}; - -use fastcrypto::encoding::Base64; -use move_binary_format::{ - access::ModuleAccess, - normalized::{self, Type}, - CompiledModule, -}; -use move_bytecode_utils::{layout::SerdeLayoutBuilder, module_cache::GetModule}; -use move_compiler::{ - compiled_unit::AnnotatedCompiledModule, - diagnostics::{report_diagnostics_to_buffer, report_warnings, Diagnostics, FilesSourceText}, - editions::Edition, - linters::LINT_WARNING_PREFIX, -}; -use move_core_types::{ - account_address::AccountAddress, - language_storage::{ModuleId, StructTag, TypeTag}, -}; -use move_package::{ - compilation::{ - build_plan::BuildPlan, compiled_package::CompiledPackage as MoveCompiledPackage, - }, - package_hooks::{PackageHooks, PackageIdentifier}, - resolution::resolution_graph::{Package, ResolvedGraph}, - source_package::parsed_manifest::{CustomDepInfo, SourceManifest}, - BuildConfig as MoveBuildConfig, -}; -use move_symbol_pool::Symbol; -use serde_reflection::Registry; -use sui_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; -use sui_types::{ - base_types::ObjectID, - error::{SuiError, SuiResult}, - is_system_package, - move_package::{FnInfo, FnInfoKey, FnInfoMap, MovePackage}, - DEEPBOOK_ADDRESS, MOVE_STDLIB_ADDRESS, STARDUST_ADDRESS, SUI_FRAMEWORK_ADDRESS, - SUI_SYSTEM_ADDRESS, TIMELOCK_ADDRESS, -}; -use sui_verifier::{default_verifier_config, verifier as sui_bytecode_verifier}; - -#[cfg(test)] -#[path = "unit_tests/build_tests.rs"] -mod build_tests; - -/// Wrapper around the core Move `CompiledPackage` with some Sui-specific traits -/// and info -#[derive(Debug, Clone)] -pub struct CompiledPackage { - pub package: MoveCompiledPackage, - /// Address the package is recorded as being published at. - pub published_at: Result, - /// The dependency IDs of this package - pub dependency_ids: PackageDependencies, - /// Path to the Move package (i.e., where the Move.toml file is) - pub path: PathBuf, -} - -/// Wrapper around the core Move `BuildConfig` with some Sui-specific info -#[derive(Clone)] -pub struct BuildConfig { - pub config: MoveBuildConfig, - /// If true, run the Move bytecode verifier on the bytecode from a - /// successful build - pub run_bytecode_verifier: bool, - /// If true, print build diagnostics to stderr--no printing if false - pub print_diags_to_stderr: bool, -} - -impl BuildConfig { - pub fn new_for_testing() -> Self { - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); - let mut build_config: Self = Default::default(); - let install_dir = tempfile::tempdir().unwrap().into_path(); - let lock_file = install_dir.join("Move.lock"); - build_config.config.install_dir = Some(install_dir); - build_config.config.lock_file = Some(lock_file); - build_config - .config - .lint_flag - .set(move_compiler::linters::LintLevel::None); - build_config - } - - pub fn new_for_testing_replace_addresses(dep_original_addresses: I) -> Self - where - I: IntoIterator, - S: Into, - { - let mut build_config = Self::new_for_testing(); - for (addr_name, obj_id) in dep_original_addresses { - build_config - .config - .additional_named_addresses - .insert(addr_name.into(), AccountAddress::from(obj_id)); - } - build_config - } - - fn fn_info(units: &[AnnotatedCompiledModule]) -> FnInfoMap { - let mut fn_info_map = BTreeMap::new(); - for u in units { - let mod_addr = u.named_module.address.into_inner(); - let mod_is_test = u.attributes.is_test_or_test_only(); - for (_, s, info) in &u.function_infos { - let fn_name = s.as_str().to_string(); - let is_test = mod_is_test || info.attributes.is_test_or_test_only(); - fn_info_map.insert(FnInfoKey { fn_name, mod_addr }, FnInfo { is_test }); - } - } - - fn_info_map - } - - fn compile_package( - resolution_graph: ResolvedGraph, - writer: &mut W, - ) -> anyhow::Result<(MoveCompiledPackage, FnInfoMap)> { - let build_plan = BuildPlan::create(resolution_graph)?; - let mut fn_info = None; - let compiled_pkg = build_plan.compile_with_driver(writer, |compiler| { - let (files, units_res) = compiler.build()?; - match units_res { - Ok((units, warning_diags)) => { - decorate_warnings(warning_diags, Some(&files)); - fn_info = Some(Self::fn_info(&units)); - Ok((files, units)) - } - Err(error_diags) => { - // with errors present don't even try decorating warnings output to avoid - // clutter - assert!(!error_diags.is_empty()); - let diags_buf = - report_diagnostics_to_buffer(&files, error_diags, /* color */ true); - if let Err(err) = std::io::stderr().write_all(&diags_buf) { - anyhow::bail!("Cannot output compiler diagnostics: {}", err); - } - anyhow::bail!("Compilation error"); - } - } - })?; - Ok((compiled_pkg, fn_info.unwrap())) - } - - /// Given a `path` and a `build_config`, build the package in that path, - /// including its dependencies. If we are building the Sui framework, we - /// skip the check that the addresses should be 0 - pub fn build(self, path: PathBuf) -> SuiResult { - let print_diags_to_stderr = self.print_diags_to_stderr; - let run_bytecode_verifier = self.run_bytecode_verifier; - let resolution_graph = self.resolution_graph(&path)?; - let result = build_from_resolution_graph( - path.clone(), - resolution_graph, - run_bytecode_verifier, - print_diags_to_stderr, - ); - if let Ok(ref compiled) = result { - compiled - .package - .compiled_package_info - .build_flags - .update_lock_file_toolchain_version(&path, env!("CARGO_PKG_VERSION").into()) - .map_err(|e| SuiError::ModuleBuildFailure { - error: format!("Failed to update Move.lock toolchain version: {e}"), - })?; - } - result - } - - pub fn resolution_graph(mut self, path: &Path) -> SuiResult { - if let Some(err_msg) = set_sui_flavor(&mut self.config) { - return Err(SuiError::ModuleBuildFailure { error: err_msg }); - } - - if self.print_diags_to_stderr { - self.config - .resolution_graph_for_package(path, &mut std::io::stderr()) - } else { - self.config - .resolution_graph_for_package(path, &mut std::io::sink()) - } - .map_err(|err| SuiError::ModuleBuildFailure { - error: format!("{:?}", err), - }) - } -} - -/// There may be additional information that needs to be displayed after -/// diagnostics are reported (optionally report diagnostics themselves if files -/// argument is provided). -pub fn decorate_warnings(warning_diags: Diagnostics, files: Option<&FilesSourceText>) { - let any_linter_warnings = warning_diags.any_with_prefix(LINT_WARNING_PREFIX); - let (filtered_diags_num, filtered_categories) = - warning_diags.filtered_source_diags_with_prefix(LINT_WARNING_PREFIX); - if let Some(f) = files { - report_warnings(f, warning_diags); - } - if any_linter_warnings { - eprintln!("Please report feedback on the linter warnings at https://forums.sui.io\n"); - } - if filtered_diags_num > 0 { - eprintln!( - "Total number of linter warnings suppressed: {filtered_diags_num} (filtered categories: {filtered_categories})" - ); - } -} - -/// Sets build config's default flavor to `Flavor::Sui`. Returns error message -/// if the flavor was previously set to something else than `Flavor::Sui`. -pub fn set_sui_flavor(build_config: &mut MoveBuildConfig) -> Option { - use move_compiler::editions::Flavor; - - let flavor = build_config.default_flavor.get_or_insert(Flavor::Sui); - if flavor != &Flavor::Sui { - return Some(format!( - "The flavor of the Move compiler cannot be overridden with anything but \ - \"{}\", but the default override was set to: \"{flavor}\"", - Flavor::Sui, - )); - } - None -} - -pub fn build_from_resolution_graph( - path: PathBuf, - resolution_graph: ResolvedGraph, - run_bytecode_verifier: bool, - print_diags_to_stderr: bool, -) -> SuiResult { - let (published_at, dependency_ids) = gather_published_ids(&resolution_graph); - - let result = if print_diags_to_stderr { - BuildConfig::compile_package(resolution_graph, &mut std::io::stderr()) - } else { - BuildConfig::compile_package(resolution_graph, &mut std::io::sink()) - }; - // write build failure diagnostics to stderr, convert `error` to `String` using - // `Debug` format to include anyhow's error context chain. - let (package, fn_info) = match result { - Err(error) => { - return Err(SuiError::ModuleBuildFailure { - error: format!("{:?}", error), - }); - } - Ok((package, fn_info)) => (package, fn_info), - }; - let compiled_modules = package.root_modules_map(); - if run_bytecode_verifier { - for m in compiled_modules.iter_modules() { - move_bytecode_verifier::verify_module_unmetered(m).map_err(|err| { - SuiError::ModuleVerificationFailure { - error: err.to_string(), - } - })?; - sui_bytecode_verifier::sui_verify_module_unmetered( - m, - &fn_info, - &default_verifier_config( - &ProtocolConfig::get_for_version(ProtocolVersion::MAX, Chain::Unknown), - false, - ), - )?; - } - // TODO(https://github.com/MystenLabs/sui/issues/69): Run Move linker - } - Ok(CompiledPackage { - package, - published_at, - dependency_ids, - path, - }) -} - -impl CompiledPackage { - /// Return all of the bytecode modules in this package (not including direct - /// or transitive deps) Note: these are not topologically sorted by - /// dependency--use `get_dependency_sorted_modules` to produce a list of - /// modules suitable for publishing or static analysis - pub fn get_modules(&self) -> impl Iterator { - self.package.root_modules().map(|m| &m.unit.module) - } - - /// Return all of the bytecode modules in this package (not including direct - /// or transitive deps) Note: these are not topologically sorted by - /// dependency--use `get_dependency_sorted_modules` to produce a list of - /// modules suitable for publishing or static analysis - pub fn into_modules(self) -> Vec { - self.package - .root_compiled_units - .into_iter() - .map(|m| m.unit.module) - .collect() - } - - /// Return all of the bytecode modules that this package depends on (both - /// directly and transitively) Note: these are not topologically sorted - /// by dependency. - pub fn get_dependent_modules(&self) -> impl Iterator { - self.package - .deps_compiled_units - .iter() - .map(|(_, m)| &m.unit.module) - } - - /// Return all of the bytecode modules in this package and the modules of - /// its direct and transitive dependencies. Note: these are not - /// topologically sorted by dependency. - pub fn get_modules_and_deps(&self) -> impl Iterator { - self.package.all_modules().map(|m| &m.unit.module) - } - - /// Return the bytecode modules in this package, topologically sorted in - /// dependency order. Optionally include dependencies that have not been - /// published (are at address 0x0), if `with_unpublished_deps` is true. - /// This is the function to call if you would like to publish - /// or statically analyze the modules. - pub fn get_dependency_sorted_modules( - &self, - with_unpublished_deps: bool, - ) -> Vec { - let all_modules = self.package.all_modules_map(); - let graph = all_modules.compute_dependency_graph(); - - // SAFETY: package built successfully - let modules = graph.compute_topological_order().unwrap(); - - if with_unpublished_deps { - // For each transitive dependent module, if they are not to be published, they - // must have a non-zero address (meaning they are already published - // on-chain). - modules - .filter(|module| module.address() == &AccountAddress::ZERO) - .cloned() - .collect() - } else { - // Collect all module IDs from the current package to be published (module names - // are not sufficient as we may have modules with the same names in - // user code and in Sui framework which would result in the latter - // being pulled into a set of modules to be published). - let self_modules: HashSet<_> = self - .package - .root_modules_map() - .iter_modules() - .iter() - .map(|m| m.self_id()) - .collect(); - - modules - .filter(|module| self_modules.contains(&module.self_id())) - .cloned() - .collect() - } - } - - /// Return the set of Object IDs corresponding to this package's transitive - /// dependencies' original package IDs. - pub fn get_dependency_original_package_ids(&self) -> Vec { - let mut ids: BTreeSet<_> = self - .package - .deps_compiled_units - .iter() - .map(|(_, m)| ObjectID::from(*m.unit.module.address())) - .collect(); - - // `0x0` is not a real dependency ID -- it means that the package has - // unpublished dependencies. - ids.remove(&ObjectID::ZERO); - ids.into_iter().collect() - } - - pub fn get_package_digest(&self, with_unpublished_deps: bool) -> [u8; 32] { - let hash_modules = true; - MovePackage::compute_digest_for_modules_and_deps( - &self.get_package_bytes(with_unpublished_deps), - self.dependency_ids.published.values(), - hash_modules, - ) - } - - /// Return a serialized representation of the bytecode modules in this - /// package, topologically sorted in dependency order - pub fn get_package_bytes(&self, with_unpublished_deps: bool) -> Vec> { - self.get_dependency_sorted_modules(with_unpublished_deps) - .iter() - .map(|m| { - let mut bytes = Vec::new(); - m.serialize(&mut bytes).unwrap(); // safe because package built successfully - bytes - }) - .collect() - } - - /// Return the base64-encoded representation of the bytecode modules in this - /// package, topologically sorted in dependency order - pub fn get_package_base64(&self, with_unpublished_deps: bool) -> Vec { - self.get_package_bytes(with_unpublished_deps) - .iter() - .map(|b| Base64::from_bytes(b)) - .collect() - } - - pub fn get_package_dependencies_hex(&self) -> Vec { - self.dependency_ids - .published - .values() - .map(|object_id| object_id.to_hex_uncompressed()) - .collect() - } - - /// Get bytecode modules from DeepBook that are used by this package - pub fn get_deepbook_modules(&self) -> impl Iterator { - self.get_modules_and_deps() - .filter(|m| *m.self_id().address() == DEEPBOOK_ADDRESS) - } - - /// Get bytecode modules from the Sui System that are used by this package - pub fn get_sui_system_modules(&self) -> impl Iterator { - self.get_modules_and_deps() - .filter(|m| *m.self_id().address() == SUI_SYSTEM_ADDRESS) - } - - /// Get bytecode modules from the Sui Framework that are used by this - /// package - pub fn get_sui_framework_modules(&self) -> impl Iterator { - self.get_modules_and_deps() - .filter(|m| *m.self_id().address() == SUI_FRAMEWORK_ADDRESS) - } - - /// Get bytecode modules from the Move stdlib that are used by this package - pub fn get_stdlib_modules(&self) -> impl Iterator { - self.get_modules_and_deps() - .filter(|m| *m.self_id().address() == MOVE_STDLIB_ADDRESS) - } - - /// Get bytecode modules from Stardust that are used by this package - pub fn get_stardust_modules(&self) -> impl Iterator { - self.get_modules_and_deps() - .filter(|m| *m.self_id().address() == STARDUST_ADDRESS) - } - - /// Get bytecode modules from Timelock that are used by this package - pub fn get_timelock_modules(&self) -> impl Iterator { - self.get_modules_and_deps() - .filter(|m| *m.self_id().address() == TIMELOCK_ADDRESS) - } - - /// Generate layout schemas for all types declared by this package, as well - /// as all struct types passed into `entry` functions declared by - /// modules in this package (either directly or by reference). - /// These layout schemas can be consumed by clients (e.g., the TypeScript - /// SDK) to enable BCS serialization/deserialization of the package's - /// objects, tx arguments, and events. - pub fn generate_struct_layouts(&self) -> Registry { - let mut package_types = BTreeSet::new(); - for m in self.get_modules() { - let normalized_m = normalized::Module::new(m); - // 1. generate struct layouts for all declared types - 'structs: for (name, s) in normalized_m.structs { - let mut dummy_type_parameters = Vec::new(); - for t in &s.type_parameters { - if t.is_phantom { - // if all of t's type parameters are phantom, we can generate a type layout - // we make this happen by creating a StructTag with dummy `type_params`, - // since the layout generator won't look at them. we - // need to do this because SerdeLayoutBuilder will refuse to generate a - // layout for any open StructTag, but phantom types - // cannot affect the layout of a struct, so we just use dummy values - dummy_type_parameters.push(TypeTag::Signer) - } else { - // open type--do not attempt to generate a layout - // TODO: handle generating layouts for open types? - continue 'structs; - } - } - debug_assert!(dummy_type_parameters.len() == s.type_parameters.len()); - package_types.insert(StructTag { - address: *m.address(), - module: m.name().to_owned(), - name, - type_params: dummy_type_parameters, - }); - } - // 2. generate struct layouts for all parameters of `entry` funs - for (_name, f) in normalized_m.functions { - if f.is_entry { - for t in f.parameters { - let tag_opt = match t.clone() { - Type::Address - | Type::Bool - | Type::Signer - | Type::TypeParameter(_) - | Type::U8 - | Type::U16 - | Type::U32 - | Type::U64 - | Type::U128 - | Type::U256 - | Type::Vector(_) => continue, - Type::Reference(t) | Type::MutableReference(t) => t.into_struct_tag(), - s @ Type::Struct { .. } => s.into_struct_tag(), - }; - if let Some(tag) = tag_opt { - package_types.insert(tag); - } - } - } - } - } - let mut layout_builder = SerdeLayoutBuilder::new(self); - for typ in &package_types { - layout_builder.build_struct_layout(typ).unwrap(); - } - layout_builder.into_registry() - } - - /// Checks whether this package corresponds to a built-in framework - pub fn is_system_package(&self) -> bool { - // System packages always have "published-at" addresses - let Ok(published_at) = self.published_at else { - return false; - }; - - is_system_package(published_at) - } - - /// Checks for root modules with non-zero package addresses. Returns an - /// arbitrary one, if one can can be found, otherwise returns `None`. - pub fn published_root_module(&self) -> Option<&CompiledModule> { - self.package.root_compiled_units.iter().find_map(|unit| { - if unit.unit.module.self_id().address() != &AccountAddress::ZERO { - Some(&unit.unit.module) - } else { - None - } - }) - } - - pub fn verify_unpublished_dependencies( - &self, - unpublished_deps: &BTreeSet, - ) -> SuiResult<()> { - if unpublished_deps.is_empty() { - return Ok(()); - } - - let errors = self - .package - .deps_compiled_units - .iter() - .filter_map(|(p, m)| { - if !unpublished_deps.contains(p) || m.unit.module.address() == &AccountAddress::ZERO - { - return None; - } - Some(format!( - " - {}::{} in dependency {}", - m.unit.module.address(), - m.unit.name, - p - )) - }) - .collect::>(); - - if errors.is_empty() { - return Ok(()); - } - - let mut error_message = vec![]; - error_message.push( - "The following modules in package dependencies set a non-zero self-address:".into(), - ); - error_message.extend(errors); - error_message.push( - "If these packages really are unpublished, their self-addresses should be set \ - to \"0x0\" in the [addresses] section of the manifest when publishing. If they \ - are already published, ensure they specify the address in the `published-at` of \ - their Move.toml manifest." - .into(), - ); - - Err(SuiError::ModulePublishFailure { - error: error_message.join("\n"), - }) - } - - pub fn published_dependency_ids(&self) -> Vec { - self.dependency_ids.published.values().cloned().collect() - } -} - -impl Default for BuildConfig { - fn default() -> Self { - let config = MoveBuildConfig { - default_flavor: Some(move_compiler::editions::Flavor::Sui), - ..MoveBuildConfig::default() - }; - BuildConfig { - config, - run_bytecode_verifier: true, - print_diags_to_stderr: false, - } - } -} - -impl GetModule for CompiledPackage { - type Error = anyhow::Error; - // TODO: return ref here for better efficiency? Borrow checker + - // all_modules_map() make it hard to do this - type Item = CompiledModule; - - fn get_module_by_id(&self, id: &ModuleId) -> Result, Self::Error> { - Ok(self.package.all_modules_map().get_module(id).ok().cloned()) - } -} - -pub const PUBLISHED_AT_MANIFEST_FIELD: &str = "published-at"; - -pub struct SuiPackageHooks; - -impl PackageHooks for SuiPackageHooks { - fn custom_package_info_fields(&self) -> Vec { - vec![ - PUBLISHED_AT_MANIFEST_FIELD.to_string(), - // TODO: remove this once version fields are removed from all manifests - "version".to_string(), - ] - } - - fn custom_dependency_key(&self) -> Option { - None - } - - fn resolve_custom_dependency( - &self, - _dep_name: move_symbol_pool::Symbol, - _info: &CustomDepInfo, - ) -> anyhow::Result<()> { - Ok(()) - } - - fn custom_resolve_pkg_id( - &self, - manifest: &SourceManifest, - ) -> anyhow::Result { - if manifest.package.edition == Some(Edition::DEVELOPMENT) { - return Err(Edition::DEVELOPMENT.unknown_edition_error()); - } - Ok(manifest.package.name) - } - - fn resolve_version(&self, _: &SourceManifest) -> anyhow::Result> { - Ok(None) - } -} - -#[derive(Debug, Clone)] -pub struct PackageDependencies { - /// Set of published dependencies (name and address). - pub published: BTreeMap, - /// Set of unpublished dependencies (name). - pub unpublished: BTreeSet, - /// Set of dependencies with invalid `published-at` addresses. - pub invalid: BTreeMap, -} - -#[derive(Debug, Clone)] -pub enum PublishedAtError { - Invalid(String), - NotPresent, -} - -/// Partition packages in `resolution_graph` into one of four groups: -/// - The ID that the package itself is published at (if it is published) -/// - The IDs of dependencies that have been published -/// - The names of packages that have not been published on chain. -/// - The names of packages that have a `published-at` field that isn't filled -/// with a valid address. -pub fn gather_published_ids( - resolution_graph: &ResolvedGraph, -) -> (Result, PackageDependencies) { - let root = resolution_graph.root_package(); - - let mut published = BTreeMap::new(); - let mut unpublished = BTreeSet::new(); - let mut invalid = BTreeMap::new(); - let mut published_at = Err(PublishedAtError::NotPresent); - - for (name, package) in &resolution_graph.package_table { - let property = published_at_property(package); - if name == &root { - // Separate out the root package as a special case - published_at = property; - continue; - } - - match property { - Ok(id) => { - published.insert(*name, id); - } - Err(PublishedAtError::NotPresent) => { - unpublished.insert(*name); - } - Err(PublishedAtError::Invalid(value)) => { - invalid.insert(*name, value); - } - }; - } - - ( - published_at, - PackageDependencies { - published, - unpublished, - invalid, - }, - ) -} - -pub fn published_at_property(package: &Package) -> Result { - let Some(value) = package - .source_package - .package - .custom_properties - .get(&Symbol::from(PUBLISHED_AT_MANIFEST_FIELD)) - else { - return Err(PublishedAtError::NotPresent); - }; - - ObjectID::from_str(value.as_str()).map_err(|_| PublishedAtError::Invalid(value.to_owned())) -} - -pub fn check_unpublished_dependencies(unpublished: &BTreeSet) -> Result<(), SuiError> { - if unpublished.is_empty() { - return Ok(()); - }; - - let mut error_messages = unpublished - .iter() - .map(|name| { - format!( - "Package dependency \"{name}\" does not specify a published address \ - (the Move.toml manifest for \"{name}\" does not contain a published-at field).", - ) - }) - .collect::>(); - - error_messages.push( - "If this is intentional, you may use the --with-unpublished-dependencies flag to \ - continue publishing these dependencies as part of your package (they won't be \ - linked against existing packages on-chain)." - .into(), - ); - - Err(SuiError::ModulePublishFailure { - error: error_messages.join("\n"), - }) -} - -pub fn check_invalid_dependencies(invalid: &BTreeMap) -> Result<(), SuiError> { - if invalid.is_empty() { - return Ok(()); - } - - let error_messages = invalid - .iter() - .map(|(name, value)| { - format!( - "Package dependency \"{name}\" does not specify a valid published \ - address: could not parse value \"{value}\" for published-at field." - ) - }) - .collect::>(); - - Err(SuiError::ModulePublishFailure { - error: error_messages.join("\n"), - }) -} diff --git a/crates/sui-move/Cargo.toml b/crates/sui-move/Cargo.toml deleted file mode 100644 index 34cfd61d32a..00000000000 --- a/crates/sui-move/Cargo.toml +++ /dev/null @@ -1,68 +0,0 @@ -[package] -name = "sui-move" -version.workspace = true -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -clap.workspace = true -colored.workspace = true -once_cell = { workspace = true, optional = true } -serde_json.workspace = true -serde_yaml.workspace = true -tracing.workspace = true -prometheus.workspace = true -git-version.workspace = true -const-str.workspace = true - -move-binary-format.workspace = true -move-cli.workspace = true -move-compiler.workspace = true -move-disassembler.workspace = true -move-ir-types.workspace = true -move-package.workspace = true -move-prover.workspace = true -move-unit-test.workspace = true -telemetry-subscribers.workspace = true -tokio = { workspace = true, features = ["full"] } - -move-vm-runtime = { path = "../../external-crates/move/crates/move-vm-runtime" } -sui-move-natives = { path = "../../sui-execution/latest/sui-move-natives", package = "sui-move-natives-latest" } - -sui-move-build.workspace = true -sui-protocol-config.workspace = true -sui-types.workspace = true - -[target.'cfg(not(target_env = "msvc"))'.dependencies] -jemalloc-ctl.workspace = true - -[dev-dependencies] -assert_cmd.workspace = true -futures.workspace = true -jsonrpsee.workspace = true -rand.workspace = true -tempfile.workspace = true - -move-package.workspace = true - -mysten-metrics.workspace = true -sui-core.workspace = true -sui-macros.workspace = true -sui-node.workspace = true -sui-simulator.workspace = true - -[package.metadata.cargo-udeps.ignore] -normal = ["jemalloc-ctl"] - -[features] -default = [] -build = [] -coverage = [] -disassemble = [] -prove = [] -unit_test = ["build", "dep:once_cell"] -calibrate = [] -all = ["build", "coverage", "disassemble", "prove", "unit_test", "calibrate"] diff --git a/crates/sui-move/src/build.rs b/crates/sui-move/src/build.rs deleted file mode 100644 index ee7471c0955..00000000000 --- a/crates/sui-move/src/build.rs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{fs, path::PathBuf}; - -use clap::Parser; -use move_cli::base; -use move_package::{source_package::layout::SourcePackageLayout, BuildConfig as MoveBuildConfig}; -use serde_json::json; -use sui_move_build::{check_invalid_dependencies, check_unpublished_dependencies, BuildConfig}; - -const LAYOUTS_DIR: &str = "layouts"; -const STRUCT_LAYOUTS_FILENAME: &str = "struct_layouts.yaml"; - -#[derive(Parser)] -#[group(id = "sui-move-build")] -pub struct Build { - /// Include the contents of packages in dependencies that haven't been - /// published (only relevant when dumping bytecode as base64) - #[clap(long, global = true)] - pub with_unpublished_dependencies: bool, - /// Whether we are printing in base64. - #[clap(long, global = true)] - pub dump_bytecode_as_base64: bool, - /// If true, generate struct layout schemas for - /// all struct types passed into `entry` functions declared by modules in - /// this package These layout schemas can be consumed by clients (e.g., - /// the TypeScript SDK) to enable serialization/deserialization of - /// transaction arguments and events. - #[clap(long, global = true)] - pub generate_struct_layouts: bool, -} - -impl Build { - pub fn execute( - &self, - path: Option, - build_config: MoveBuildConfig, - ) -> anyhow::Result<()> { - let rerooted_path = base::reroot_path(path.clone())?; - let build_config = resolve_lock_file_path(build_config, path)?; - Self::execute_internal( - rerooted_path, - build_config, - self.with_unpublished_dependencies, - self.dump_bytecode_as_base64, - self.generate_struct_layouts, - ) - } - - pub fn execute_internal( - rerooted_path: PathBuf, - config: MoveBuildConfig, - with_unpublished_deps: bool, - dump_bytecode_as_base64: bool, - generate_struct_layouts: bool, - ) -> anyhow::Result<()> { - let pkg = BuildConfig { - config, - run_bytecode_verifier: true, - print_diags_to_stderr: true, - } - .build(rerooted_path)?; - if dump_bytecode_as_base64 { - check_invalid_dependencies(&pkg.dependency_ids.invalid)?; - if !with_unpublished_deps { - check_unpublished_dependencies(&pkg.dependency_ids.unpublished)?; - } - - let package_dependencies = pkg.get_package_dependencies_hex(); - println!( - "{}", - json!({ - "modules": pkg.get_package_base64(with_unpublished_deps), - "dependencies": json!(package_dependencies), - "digest": pkg.get_package_digest(with_unpublished_deps), - }) - ) - } - - if generate_struct_layouts { - let layout_str = serde_yaml::to_string(&pkg.generate_struct_layouts()).unwrap(); - // store under /build//layouts/struct_layouts.yaml - let mut layout_filename = pkg.path; - layout_filename.push("build"); - layout_filename.push(pkg.package.compiled_package_info.package_name.as_str()); - layout_filename.push(LAYOUTS_DIR); - layout_filename.push(STRUCT_LAYOUTS_FILENAME); - fs::write(layout_filename, layout_str)? - } - - Ok(()) - } -} - -/// Resolve Move.lock file path in package directory (where Move.toml is). -pub fn resolve_lock_file_path( - mut build_config: MoveBuildConfig, - package_path: Option, -) -> Result { - if build_config.lock_file.is_none() { - let package_root = base::reroot_path(package_path)?; - let lock_file_path = package_root.join(SourcePackageLayout::Lock.path()); - build_config.lock_file = Some(lock_file_path); - } - Ok(build_config) -} diff --git a/crates/sui-move/src/lib.rs b/crates/sui-move/src/lib.rs deleted file mode 100644 index 6e2aed8fcbc..00000000000 --- a/crates/sui-move/src/lib.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::path::PathBuf; - -use clap::Parser; -#[cfg(feature = "unit_test")] -use move_cli::base::test::UnitTestResult; -use move_package::BuildConfig; -use sui_move_build::set_sui_flavor; - -#[cfg(feature = "build")] -pub mod build; -#[cfg(feature = "coverage")] -pub mod coverage; -#[cfg(feature = "disassemble")] -pub mod disassemble; -pub mod manage_package; -pub mod migrate; -pub mod new; -#[cfg(feature = "unit_test")] -pub mod unit_test; - -#[derive(Parser)] -pub enum Command { - #[cfg(feature = "build")] - Build(build::Build), - #[cfg(feature = "coverage")] - Coverage(coverage::Coverage), - #[cfg(feature = "disassemble")] - Disassemble(disassemble::Disassemble), - ManagePackage(manage_package::ManagePackage), - Migrate(migrate::Migrate), - New(new::New), - #[cfg(feature = "unit_test")] - Test(unit_test::Test), -} -#[derive(Parser)] -pub struct Calib { - #[clap(name = "runs", short = 'r', long = "runs", default_value = "1")] - runs: usize, - #[clap(name = "summarize", short = 's', long = "summarize")] - summarize: bool, -} - -pub fn execute_move_command( - package_path: Option, - mut build_config: BuildConfig, - command: Command, -) -> anyhow::Result<()> { - if let Some(err_msg) = set_sui_flavor(&mut build_config) { - anyhow::bail!(err_msg); - } - match command { - #[cfg(feature = "build")] - Command::Build(c) => c.execute(package_path, build_config), - #[cfg(feature = "coverage")] - Command::Coverage(c) => c.execute(package_path, build_config), - #[cfg(feature = "disassemble")] - Command::Disassemble(c) => c.execute(package_path, build_config), - Command::ManagePackage(c) => c.execute(package_path, build_config), - Command::Migrate(c) => c.execute(package_path, build_config), - Command::New(c) => c.execute(package_path), - - #[cfg(feature = "unit_test")] - Command::Test(c) => { - let result = c.execute(package_path, build_config)?; - - // Return a non-zero exit code if any test failed - if let UnitTestResult::Failure = result { - std::process::exit(1) - } - - Ok(()) - } - } -} diff --git a/crates/sui-move/src/main.rs b/crates/sui-move/src/main.rs deleted file mode 100644 index fe56307d978..00000000000 --- a/crates/sui-move/src/main.rs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::path::PathBuf; - -use clap::*; -use colored::Colorize; -use move_package::BuildConfig as MoveBuildConfig; -use sui_move::execute_move_command; -use sui_types::exit_main; -use tracing::debug; - -const GIT_REVISION: &str = { - if let Some(revision) = option_env!("GIT_REVISION") { - revision - } else { - let version = git_version::git_version!( - args = ["--always", "--dirty", "--exclude", "*"], - fallback = "" - ); - - if version.is_empty() { - panic!("unable to query git revision"); - } - version - } -}; -const VERSION: &str = const_str::concat!(env!("CARGO_PKG_VERSION"), "-", GIT_REVISION); - -#[derive(Parser)] -#[clap( - name = env!("CARGO_BIN_NAME"), - about = "Sui-Move CLI", - rename_all = "kebab-case", - author, - version = VERSION, -)] -struct Args { - /// Path to a package which the command should be run with respect to. - #[clap(long = "path", short = 'p', global = true)] - pub package_path: Option, - /// If true, run the Move bytecode verifier on the bytecode from a - /// successful build - #[clap(long = "path", short = 'p', global = true)] - pub run_bytecode_verifier: bool, - /// If true, print build diagnostics to stderr--no printing if false - #[clap(long = "path", short = 'p', global = true)] - pub print_diags_to_stderr: bool, - /// Package build options - #[clap(flatten)] - pub build_config: MoveBuildConfig, - /// Subcommands. - #[clap(subcommand)] - pub cmd: sui_move::Command, -} - -#[tokio::main] -async fn main() { - #[cfg(windows)] - colored::control::set_virtual_terminal(true).unwrap(); - - let bin_name = env!("CARGO_BIN_NAME"); - let args = Args::parse(); - // let _guard = match args.command { - // SuiCommand::Console { .. } | SuiCommand::Client { .. } => { - // telemetry_subscribers::TelemetryConfig::new() - // .with_log_file(&format!("{bin_name}.log")) - // .with_env() - // .init() - // } - // _ => telemetry_subscribers::TelemetryConfig::new() - // .with_env() - // .init(), - // }; - - let _guard = telemetry_subscribers::TelemetryConfig::new() - .with_log_file(&format!("{bin_name}.log")) - .with_env() - .init(); - debug!("Sui-Move CLI version: {VERSION}"); - - exit_main!(execute_move_command( - args.package_path, - args.build_config, - args.cmd - )); -} diff --git a/crates/sui-move/src/sui-natives.bpl b/crates/sui-move/src/sui-natives.bpl deleted file mode 100644 index c6780825834..00000000000 --- a/crates/sui-move/src/sui-natives.bpl +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// ================================================================================== -// Native address - - -procedure {:inline 1} $2_address_from_bytes(bytes: Vec (int)) returns (res: int); - -procedure {:inline 1} $2_address_to_u256(addr: int) returns (res: int); - -procedure {:inline 1} $2_address_from_u256(num: int) returns (res: int); - -// ================================================================================== -// Native object - - -procedure {:inline 1} $2_object_delete_impl(id: int); - -procedure {:inline 1} $2_object_record_new_uid(id: int); - -{%- for instance in object_instances %} -{%- set S = "'" ~ instance.suffix ~ "'" -%} -{%- set T = instance.name -%} - -// ---------------------------------------------------------------------------------- -// Native object implementation for object type `{{instance.suffix}}` - -procedure {:inline 1} $2_object_borrow_uid{{S}}(obj: {{T}}) returns (res: $2_object_UID) { - res := $id#{{T}}(obj); -} - -function $2_object_$borrow_uid{{S}}(obj: {{T}}): $2_object_UID { - $id#{{T}}(obj) -} - - -{%- endfor %} - -// ================================================================================== -// Native tx_context - -procedure {:inline 1} $2_tx_context_derive_id(tx_hash: Vec (int), ids_created: int) returns (res: int); - -// ================================================================================== -// Native event - - -{%- for instance in sui_event_instances %} - -{%- set S = "'" ~ instance.suffix ~ "'" -%} -{%- set T = instance.name -%} - -// ---------------------------------------------------------------------------------- -// Native Sui event implementation for object type `{{instance.suffix}}` - -procedure {:inline 1} $2_event_emit{{S}}(event: {{T}}); - -{%- endfor %} - -// ================================================================================== -// Native types - - -{%- for instance in sui_types_instances %} - -{%- set S = "'" ~ instance.suffix ~ "'" -%} -{%- set T = instance.name -%} - -// ---------------------------------------------------------------------------------- -// Native Sui types implementation for object type `{{instance.suffix}}` - -procedure {:inline 1} $2_types_is_one_time_witness{{S}}(_: {{T}}) returns (res: bool); - -{%- endfor %} - -// ================================================================================== -// Native dynamic_field - -procedure {:inline 1} $2_dynamic_field_has_child_object(parent: int, id: int) returns (res: bool); - -{%- for instance in dynamic_field_instances %} - -{%- set S = "'" ~ instance.suffix ~ "'" -%} -{%- set T = instance.name -%} - -// ---------------------------------------------------------------------------------- -// Native dynamic field implementation for object type `{{instance.suffix}}` - -procedure {:inline 1} $2_dynamic_field_hash_type_and_key{{S}}(parent: int, k: {{T}}) returns (res: int); - -procedure {:inline 1} $2_dynamic_field_add_child_object{{S}}(parent: int, child: {{T}}); - -procedure {:inline 1} $2_dynamic_field_borrow_child_object{{S}}(object: $2_object_UID, id: int) returns (res: {{T}}); - -procedure {:inline 1} $2_dynamic_field_borrow_child_object_mut{{S}}(object: $Mutation $2_object_UID, id: int) returns (res: $Mutation ({{T}}), m: $Mutation ($2_object_UID)); - -procedure {:inline 1} $2_dynamic_field_remove_child_object{{S}}(parent: int, id: int) returns (res: {{T}}); - -procedure {:inline 1} $2_dynamic_field_has_child_object_with_ty{{S}}(parent: int, id: int) returns (res: bool); - -{%- endfor %} - -// ================================================================================== -// Native prover - - -{%- for instance in prover_instances %} - -{%- set S = "'" ~ instance.suffix ~ "'" -%} -{%- set T = instance.name -%} - -// ---------------------------------------------------------------------------------- -// Native Sui prover implementation for object type `{{instance.suffix}}` - -function $2_prover_vec_remove{{S}}(v: Vec ({{T}}), elem_idx: int): Vec ({{T}}) { - RemoveAtVec(v, elem_idx) -} - -{%- endfor %} - - -// ================================================================================== -// Reads and writes to dynamic fields (skeletons) - -function GetDynField(o: T, addr: int): V; - -function UpdateDynField(o: T, addr: int, v: V): T; diff --git a/crates/sui-network/Cargo.toml b/crates/sui-network/Cargo.toml deleted file mode 100644 index 7025abfa20d..00000000000 --- a/crates/sui-network/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -[package] -name = "sui-network" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anemo.workspace = true -anemo-tower.workspace = true -governor.workspace = true -serde.workspace = true -tonic.workspace = true -dashmap.workspace = true -tower.workspace = true - -sui-archival.workspace = true -sui-storage.workspace = true -sui-types.workspace = true -sui-config.workspace = true -sui-swarm-config.workspace = true - -arc-swap.workspace = true -bcs.workspace = true -bytes.workspace = true -fastcrypto.workspace = true -fastcrypto-tbls.workspace = true -mysten-network.workspace = true -tokio = { workspace = true, features = ["full"] } -tracing.workspace = true -futures.workspace = true -tap.workspace = true -rand.workspace = true -anyhow.workspace = true -prometheus.workspace = true -mysten-metrics.workspace = true - -[build-dependencies] -anemo-build.workspace = true -tonic-build.workspace = true - -[dev-dependencies] -telemetry-subscribers.workspace = true -tokio = { workspace = true, features = ["test-util"] } -ed25519-consensus.workspace = true -tempfile = "3.3.0" diff --git a/crates/sui-network/README.md b/crates/sui-network/README.md deleted file mode 100644 index 4b467feddae..00000000000 --- a/crates/sui-network/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# sui-network - -## Changing an RPC service - -The general process for changing an RPC service is as follows: -1. Change the service definition in the `tests/bootstrap.rs` file. -2. Run `cargo test --test bootstrap` to re-run the code generation. - Generated rust files are in the `src/generated` directory. -3. Update any other corresponding logic that would have been affected by - the interface change, e.g. the server implementation of the service or - usages of the generated client. diff --git a/crates/sui-network/build.rs b/crates/sui-network/build.rs deleted file mode 100644 index 84693cd993f..00000000000 --- a/crates/sui-network/build.rs +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - env, - path::{Path, PathBuf}, -}; - -use tonic_build::manual::{Builder, Method, Service}; - -type Result = ::std::result::Result>; - -fn main() -> Result<()> { - let out_dir = if env::var("DUMP_GENERATED_GRPC").is_ok() { - PathBuf::from("") - } else { - PathBuf::from(env::var("OUT_DIR")?) - }; - - let codec_path = "mysten_network::codec::BcsCodec"; - - let validator_service = Service::builder() - .name("Validator") - .package("sui.validator") - .comment("The Validator interface") - .method( - Method::builder() - .name("transaction") - .route_name("Transaction") - .input_type("sui_types::transaction::Transaction") - .output_type("sui_types::messages_grpc::HandleTransactionResponse") - .codec_path(codec_path) - .build(), - ) - .method( - Method::builder() - .name("handle_certificate_v2") - .route_name("CertifiedTransactionV2") - .input_type("sui_types::transaction::CertifiedTransaction") - .output_type("sui_types::messages_grpc::HandleCertificateResponseV2") - .codec_path(codec_path) - .build(), - ) - .method( - Method::builder() - .name("submit_certificate") - .route_name("SubmitCertificate") - .input_type("sui_types::transaction::CertifiedTransaction") - .output_type("sui_types::messages_grpc::SubmitCertificateResponse") - .codec_path(codec_path) - .build(), - ) - .method( - Method::builder() - .name("object_info") - .route_name("ObjectInfo") - .input_type("sui_types::messages_grpc::ObjectInfoRequest") - .output_type("sui_types::messages_grpc::ObjectInfoResponse") - .codec_path(codec_path) - .build(), - ) - .method( - Method::builder() - .name("transaction_info") - .route_name("TransactionInfo") - .input_type("sui_types::messages_grpc::TransactionInfoRequest") - .output_type("sui_types::messages_grpc::TransactionInfoResponse") - .codec_path(codec_path) - .build(), - ) - .method( - Method::builder() - .name("checkpoint") - .route_name("Checkpoint") - .input_type("sui_types::messages_checkpoint::CheckpointRequest") - .output_type("sui_types::messages_checkpoint::CheckpointResponse") - .codec_path(codec_path) - .build(), - ) - .method( - Method::builder() - .name("checkpoint_v2") - .route_name("CheckpointV2") - .input_type("sui_types::messages_checkpoint::CheckpointRequestV2") - .output_type("sui_types::messages_checkpoint::CheckpointResponseV2") - .codec_path(codec_path) - .build(), - ) - .method( - Method::builder() - .name("get_system_state_object") - .route_name("GetSystemStateObject") - .input_type("sui_types::messages_grpc::SystemStateRequest") - .output_type("sui_types::sui_system_state::SuiSystemState") - .codec_path(codec_path) - .build(), - ) - .build(); - - Builder::new() - .out_dir(&out_dir) - .compile(&[validator_service]); - - build_anemo_services(&out_dir); - - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-env-changed=DUMP_GENERATED_GRPC"); - - Ok(()) -} - -fn build_anemo_services(out_dir: &Path) { - let codec_path = "mysten_network::codec::anemo::BcsSnappyCodec"; - - let discovery = anemo_build::manual::Service::builder() - .name("Discovery") - .package("sui") - .method( - anemo_build::manual::Method::builder() - .name("get_known_peers") - .route_name("GetKnownPeers") - .request_type("()") - .response_type("crate::discovery::GetKnownPeersResponse") - .codec_path(codec_path) - .build(), - ) - .build(); - - let state_sync = anemo_build::manual::Service::builder() - .name("StateSync") - .package("sui") - .method( - anemo_build::manual::Method::builder() - .name("push_checkpoint_summary") - .route_name("PushCheckpointSummary") - .request_type("sui_types::messages_checkpoint::CertifiedCheckpointSummary") - .response_type("()") - .codec_path(codec_path) - .build(), - ) - .method( - anemo_build::manual::Method::builder() - .name("get_checkpoint_summary") - .route_name("GetCheckpointSummary") - .request_type("crate::state_sync::GetCheckpointSummaryRequest") - .response_type("Option") - .codec_path(codec_path) - .build(), - ) - .method( - anemo_build::manual::Method::builder() - .name("get_checkpoint_contents") - .route_name("GetCheckpointContents") - .request_type("sui_types::messages_checkpoint::CheckpointContentsDigest") - .response_type("Option") - .codec_path(codec_path) - .build(), - ) - .method( - anemo_build::manual::Method::builder() - .name("get_checkpoint_availability") - .route_name("GetCheckpointAvailability") - .request_type("()") - .response_type("crate::state_sync::GetCheckpointAvailabilityResponse") - .codec_path(codec_path) - .build(), - ) - .build(); - - let randomness = anemo_build::manual::Service::builder() - .name("Randomness") - .package("sui") - .method( - anemo_build::manual::Method::builder() - .name("send_signatures") - .route_name("SendSignatures") - .request_type("crate::randomness::SendSignaturesRequest") - .response_type("()") - .codec_path(codec_path) - .build(), - ) - .build(); - - anemo_build::manual::Builder::new() - .out_dir(out_dir) - .compile(&[discovery, state_sync, randomness]); -} diff --git a/crates/sui-network/src/api.rs b/crates/sui-network/src/api.rs deleted file mode 100644 index 7377bd197bc..00000000000 --- a/crates/sui-network/src/api.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod validator { - include!(concat!(env!("OUT_DIR"), "/sui.validator.Validator.rs")); -} - -pub use validator::{ - validator_client::ValidatorClient, - validator_server::{Validator, ValidatorServer}, -}; diff --git a/crates/sui-network/src/discovery/builder.rs b/crates/sui-network/src/discovery/builder.rs deleted file mode 100644 index a957c5d3f69..00000000000 --- a/crates/sui-network/src/discovery/builder.rs +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::HashMap, - sync::{Arc, RwLock}, -}; - -use anemo::codegen::InboundRequestLayer; -use anemo_tower::rate_limit; -use sui_config::p2p::P2pConfig; -use tap::Pipe; -use tokio::{ - sync::{oneshot, watch}, - task::JoinSet, -}; - -use super::{ - metrics::Metrics, server::Server, Discovery, DiscoveryEventLoop, DiscoveryServer, State, -}; -use crate::discovery::TrustedPeerChangeEvent; - -/// Discovery Service Builder. -pub struct Builder { - config: Option, - metrics: Option, - trusted_peer_change_rx: watch::Receiver, -} - -impl Builder { - #[allow(clippy::new_without_default)] - pub fn new(trusted_peer_change_rx: watch::Receiver) -> Self { - Self { - config: None, - metrics: None, - trusted_peer_change_rx, - } - } - - pub fn config(mut self, config: P2pConfig) -> Self { - self.config = Some(config); - self - } - - pub fn with_metrics(mut self, registry: &prometheus::Registry) -> Self { - self.metrics = Some(Metrics::enabled(registry)); - self - } - - pub fn build(self) -> (UnstartedDiscovery, DiscoveryServer) { - let discovery_config = self - .config - .clone() - .and_then(|config| config.discovery) - .unwrap_or_default(); - let (builder, server) = self.build_internal(); - let mut discovery_server = DiscoveryServer::new(server); - - // Apply rate limits from configuration as needed. - if let Some(limit) = discovery_config.get_known_peers_rate_limit { - discovery_server = discovery_server.add_layer_for_get_known_peers( - InboundRequestLayer::new(rate_limit::RateLimitLayer::new( - governor::Quota::per_second(limit), - rate_limit::WaitMode::Block, - )), - ); - } - (builder, discovery_server) - } - - pub(super) fn build_internal(self) -> (UnstartedDiscovery, Server) { - let Builder { - config, - metrics, - trusted_peer_change_rx, - } = self; - let config = config.unwrap(); - let metrics = metrics.unwrap_or_else(Metrics::disabled); - let (sender, receiver) = oneshot::channel(); - - let handle = Handle { - _shutdown_handle: Arc::new(sender), - }; - - let state = State { - our_info: None, - connected_peers: HashMap::default(), - known_peers: HashMap::default(), - } - .pipe(RwLock::new) - .pipe(Arc::new); - - let server = Server { - state: state.clone(), - }; - - ( - UnstartedDiscovery { - handle, - config, - shutdown_handle: receiver, - state, - trusted_peer_change_rx, - metrics, - }, - server, - ) - } -} - -/// Handle to an unstarted discovery system -pub struct UnstartedDiscovery { - pub(super) handle: Handle, - pub(super) config: P2pConfig, - pub(super) shutdown_handle: oneshot::Receiver<()>, - pub(super) state: Arc>, - pub(super) trusted_peer_change_rx: watch::Receiver, - pub(super) metrics: Metrics, -} - -impl UnstartedDiscovery { - pub(super) fn build(self, network: anemo::Network) -> (DiscoveryEventLoop, Handle) { - let Self { - handle, - config, - shutdown_handle, - state, - trusted_peer_change_rx, - metrics, - } = self; - - let discovery_config = config.discovery.clone().unwrap_or_default(); - let allowlisted_peers = Arc::new( - discovery_config - .allowlisted_peers - .clone() - .into_iter() - .map(|ap| (ap.peer_id, ap.address)) - .chain(config.seed_peers.iter().filter_map(|peer| { - peer.peer_id - .map(|peer_id| (peer_id, Some(peer.address.clone()))) - })) - .collect::>(), - ); - ( - DiscoveryEventLoop { - config, - discovery_config: Arc::new(discovery_config), - allowlisted_peers, - network, - tasks: JoinSet::new(), - pending_dials: Default::default(), - dial_seed_peers_task: None, - shutdown_handle, - state, - trusted_peer_change_rx, - metrics, - }, - handle, - ) - } - - pub fn start(self, network: anemo::Network) -> Handle { - let (event_loop, handle) = self.build(network); - tokio::spawn(event_loop.start()); - - handle - } -} - -/// A Handle to the Discovery subsystem. The Discovery system will be shutdown -/// once its Handle has been dropped. -pub struct Handle { - _shutdown_handle: Arc>, -} diff --git a/crates/sui-network/src/discovery/metrics.rs b/crates/sui-network/src/discovery/metrics.rs deleted file mode 100644 index d2ca05c5601..00000000000 --- a/crates/sui-network/src/discovery/metrics.rs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::sync::Arc; - -use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; -use tap::Pipe; - -#[derive(Clone)] -pub(super) struct Metrics(Option>); - -impl std::fmt::Debug for Metrics { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - fmt.debug_struct("Metrics").finish() - } -} - -impl Metrics { - pub fn enabled(registry: &Registry) -> Self { - Metrics(Some(Inner::new(registry))) - } - - pub fn disabled() -> Self { - Metrics(None) - } - - pub fn inc_num_peers_with_external_address(&self) { - if let Some(inner) = &self.0 { - inner.num_peers_with_external_address.inc(); - } - } - - pub fn dec_num_peers_with_external_address(&self) { - if let Some(inner) = &self.0 { - inner.num_peers_with_external_address.dec(); - } - } -} - -struct Inner { - num_peers_with_external_address: IntGauge, -} - -impl Inner { - pub fn new(registry: &Registry) -> Arc { - Self { - num_peers_with_external_address: register_int_gauge_with_registry!( - "num_peers_with_external_address", - "Number of peers with an external address configured for discovery", - registry - ) - .unwrap(), - } - .pipe(Arc::new) - } -} diff --git a/crates/sui-network/src/discovery/mod.rs b/crates/sui-network/src/discovery/mod.rs deleted file mode 100644 index 00586067668..00000000000 --- a/crates/sui-network/src/discovery/mod.rs +++ /dev/null @@ -1,513 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::HashMap, - sync::{Arc, RwLock}, - time::Duration, -}; - -use anemo::{ - types::{PeerEvent, PeerInfo}, - Network, Peer, PeerId, Request, Response, -}; -use futures::StreamExt; -use serde::{Deserialize, Serialize}; -use sui_config::p2p::{AccessType, DiscoveryConfig, P2pConfig, SeedPeer}; -use sui_types::multiaddr::Multiaddr; -use tap::{Pipe, TapFallible}; -use tokio::{ - sync::{broadcast::error::RecvError, oneshot, watch}, - task::{AbortHandle, JoinSet}, -}; -use tracing::{debug, info, trace}; - -const TIMEOUT: Duration = Duration::from_secs(1); -const ONE_DAY_MILLISECONDS: u64 = 24 * 60 * 60 * 1_000; - -mod generated { - include!(concat!(env!("OUT_DIR"), "/sui.Discovery.rs")); -} -mod builder; -mod metrics; -mod server; -#[cfg(test)] -mod tests; - -pub use builder::{Builder, Handle, UnstartedDiscovery}; -pub use generated::{ - discovery_client::DiscoveryClient, - discovery_server::{Discovery, DiscoveryServer}, -}; -pub use server::GetKnownPeersResponse; - -use self::metrics::Metrics; - -/// The internal discovery state shared between the main event loop and the -/// request handler -struct State { - our_info: Option, - connected_peers: HashMap, - known_peers: HashMap, -} - -/// The information necessary to dial another peer. -/// -/// `NodeInfo` contains all the information that is shared with other nodes via -/// the discovery service to advertise how a node can be reached. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct NodeInfo { - pub peer_id: PeerId, - pub addresses: Vec, - - /// Creation time. - /// - /// This is used to determine which of two NodeInfo's from the same PeerId - /// should be retained. - pub timestamp_ms: u64, - - /// See docstring for `AccessType`. - pub access_type: AccessType, -} - -#[derive(Clone, Debug, Default)] -pub struct TrustedPeerChangeEvent { - pub new_peers: Vec, -} - -struct DiscoveryEventLoop { - config: P2pConfig, - discovery_config: Arc, - allowlisted_peers: Arc>>, - network: Network, - tasks: JoinSet<()>, - pending_dials: HashMap, - dial_seed_peers_task: Option, - shutdown_handle: oneshot::Receiver<()>, - state: Arc>, - trusted_peer_change_rx: watch::Receiver, - metrics: Metrics, -} - -impl DiscoveryEventLoop { - pub async fn start(mut self) { - info!("Discovery started"); - - self.construct_our_info(); - self.configure_preferred_peers(); - - let mut interval = tokio::time::interval(self.discovery_config.interval_period()); - let mut peer_events = { - let (subscriber, _peers) = self.network.subscribe().unwrap(); - subscriber - }; - - loop { - tokio::select! { - now = interval.tick() => { - let now_unix = now_unix(); - self.handle_tick(now.into_std(), now_unix); - } - peer_event = peer_events.recv() => { - self.handle_peer_event(peer_event); - }, - Ok(()) = self.trusted_peer_change_rx.changed() => { - let event: TrustedPeerChangeEvent = self.trusted_peer_change_rx.borrow_and_update().clone(); - self.handle_trusted_peer_change_event(event); - } - Some(task_result) = self.tasks.join_next() => { - match task_result { - Ok(()) => {}, - Err(e) => { - if e.is_cancelled() { - // avoid crashing on ungraceful shutdown - } else if e.is_panic() { - // propagate panics. - std::panic::resume_unwind(e.into_panic()); - } else { - panic!("task failed: {e}"); - } - }, - }; - }, - // Once the shutdown notification resolves we can terminate the event loop - _ = &mut self.shutdown_handle => { - break; - } - } - } - - info!("Discovery ended"); - } - - fn construct_our_info(&mut self) { - if self.state.read().unwrap().our_info.is_some() { - return; - } - - let address = self - .config - .external_address - .clone() - .and_then(|addr| addr.to_anemo_address().ok().map(|_| addr)) - .into_iter() - .collect(); - let our_info = NodeInfo { - peer_id: self.network.peer_id(), - addresses: address, - timestamp_ms: now_unix(), - access_type: self.discovery_config.access_type(), - }; - - self.state.write().unwrap().our_info = Some(our_info); - } - - fn configure_preferred_peers(&mut self) { - for (peer_id, address) in self - .discovery_config - .allowlisted_peers - .iter() - .map(|sp| (sp.peer_id, sp.address.clone())) - .chain(self.config.seed_peers.iter().filter_map(|ap| { - ap.peer_id - .map(|peer_id| (peer_id, Some(ap.address.clone()))) - })) - { - let anemo_address = if let Some(address) = address { - let Ok(address) = address.to_anemo_address() else { - debug!(p2p_address=?address, "Can't convert p2p address to anemo address"); - continue; - }; - Some(address) - } else { - None - }; - - // TODO: once we have `PeerAffinity::Allowlisted` we should update allowlisted - // peers' affinity. - let peer_info = anemo::types::PeerInfo { - peer_id, - affinity: anemo::types::PeerAffinity::High, - address: anemo_address.into_iter().collect(), - }; - self.network.known_peers().insert(peer_info); - } - } - - fn update_our_info_timestamp(&mut self, now_unix: u64) { - if let Some(our_info) = &mut self.state.write().unwrap().our_info { - our_info.timestamp_ms = now_unix; - } - } - - // TODO: we don't boot out old committee member yets, however we may want to do - // this in the future along with other network management work. - fn handle_trusted_peer_change_event( - &mut self, - trusted_peer_change_event: TrustedPeerChangeEvent, - ) { - for peer_info in trusted_peer_change_event.new_peers { - debug!(?peer_info, "Add committee member as preferred peer."); - self.network.known_peers().insert(peer_info); - } - } - - fn handle_peer_event(&mut self, peer_event: Result) { - match peer_event { - Ok(PeerEvent::NewPeer(peer_id)) => { - if let Some(peer) = self.network.peer(peer_id) { - self.state - .write() - .unwrap() - .connected_peers - .insert(peer_id, ()); - - // Query the new node for any peers - self.tasks.spawn(query_peer_for_their_known_peers( - peer, - self.state.clone(), - self.metrics.clone(), - self.allowlisted_peers.clone(), - )); - } - } - Ok(PeerEvent::LostPeer(peer_id, _)) => { - self.state.write().unwrap().connected_peers.remove(&peer_id); - } - - Err(RecvError::Closed) => { - panic!("PeerEvent channel shouldn't be able to be closed"); - } - - Err(RecvError::Lagged(_)) => { - trace!("State-Sync fell behind processing PeerEvents"); - } - } - } - - fn handle_tick(&mut self, _now: std::time::Instant, now_unix: u64) { - self.update_our_info_timestamp(now_unix); - - self.tasks - .spawn(query_connected_peers_for_their_known_peers( - self.network.clone(), - self.discovery_config.clone(), - self.state.clone(), - self.metrics.clone(), - self.allowlisted_peers.clone(), - )); - - // Cull old peers older than a day - self.state - .write() - .unwrap() - .known_peers - .retain(|_k, v| now_unix.saturating_sub(v.timestamp_ms) < ONE_DAY_MILLISECONDS); - - // Clean out the pending_dials - self.pending_dials.retain(|_k, v| !v.is_finished()); - if let Some(abort_handle) = &self.dial_seed_peers_task { - if abort_handle.is_finished() { - self.dial_seed_peers_task = None; - } - } - - // Spawn some dials - let state = self.state.read().unwrap(); - let eligible = state - .known_peers - .clone() - .into_iter() - .filter(|(peer_id, info)| { - peer_id != &self.network.peer_id() && - !info.addresses.is_empty() // Peer has addresses we can dial - && !state.connected_peers.contains_key(peer_id) // We're not already connected - && !self.pending_dials.contains_key(peer_id) // There is no pending dial to this node - }) - .collect::>(); - - // No need to connect to any more peers if we're already connected to a bunch - let number_of_connections = state.connected_peers.len(); - let number_to_dial = std::cmp::min( - eligible.len(), - self.discovery_config - .target_concurrent_connections() - .saturating_sub(number_of_connections), - ); - - // randomize the order - for (peer_id, info) in rand::seq::SliceRandom::choose_multiple( - eligible.as_slice(), - &mut rand::thread_rng(), - number_to_dial, - ) { - let abort_handle = self.tasks.spawn(try_to_connect_to_peer( - self.network.clone(), - info.to_owned(), - )); - self.pending_dials.insert(*peer_id, abort_handle); - } - - // If we aren't connected to anything and we aren't presently trying to connect - // to anyone we need to try the seed peers - if self.dial_seed_peers_task.is_none() - && state.connected_peers.is_empty() - && self.pending_dials.is_empty() - && !self.config.seed_peers.is_empty() - { - let abort_handle = self.tasks.spawn(try_to_connect_to_seed_peers( - self.network.clone(), - self.discovery_config.clone(), - self.config.seed_peers.clone(), - )); - - self.dial_seed_peers_task = Some(abort_handle); - } - } -} - -async fn try_to_connect_to_peer(network: Network, info: NodeInfo) { - for multiaddr in &info.addresses { - if let Ok(address) = multiaddr.to_anemo_address() { - // Ignore the result and just log the error if there is one - if network - .connect_with_peer_id(address, info.peer_id) - .await - .tap_err(|e| { - debug!( - "error dialing {} at address '{}': {e}", - info.peer_id.short_display(4), - multiaddr - ) - }) - .is_ok() - { - return; - } - } - } -} - -async fn try_to_connect_to_seed_peers( - network: Network, - config: Arc, - seed_peers: Vec, -) { - let network = &network; - - futures::stream::iter(seed_peers.into_iter().filter_map(|seed| { - seed.address - .to_anemo_address() - .ok() - .map(|address| (seed, address)) - })) - .for_each_concurrent( - config.target_concurrent_connections(), - |(seed, address)| async move { - // Ignore the result and just log the error if there is one - let _ = if let Some(peer_id) = seed.peer_id { - network.connect_with_peer_id(address, peer_id).await - } else { - network.connect(address).await - } - .tap_err(|e| debug!("error dialing multiaddr '{}': {e}", seed.address)); - }, - ) - .await; -} - -async fn query_peer_for_their_known_peers( - peer: Peer, - state: Arc>, - metrics: Metrics, - allowlisted_peers: Arc>>, -) { - let mut client = DiscoveryClient::new(peer); - - let request = Request::new(()).with_timeout(TIMEOUT); - if let Some(found_peers) = client - .get_known_peers(request) - .await - .ok() - .map(Response::into_inner) - .map( - |GetKnownPeersResponse { - own_info, - mut known_peers, - }| { - if !own_info.addresses.is_empty() { - known_peers.push(own_info) - } - known_peers - }, - ) - { - update_known_peers(state, metrics, found_peers, allowlisted_peers); - } -} - -async fn query_connected_peers_for_their_known_peers( - network: Network, - config: Arc, - state: Arc>, - metrics: Metrics, - allowlisted_peers: Arc>>, -) { - use rand::seq::IteratorRandom; - - let peers_to_query = network - .peers() - .into_iter() - .flat_map(|id| network.peer(id)) - .choose_multiple(&mut rand::thread_rng(), config.peers_to_query()); - - let found_peers = peers_to_query - .into_iter() - .map(DiscoveryClient::new) - .map(|mut client| async move { - let request = Request::new(()).with_timeout(TIMEOUT); - client - .get_known_peers(request) - .await - .ok() - .map(Response::into_inner) - .map( - |GetKnownPeersResponse { - own_info, - mut known_peers, - }| { - known_peers.push(own_info); - known_peers - }, - ) - }) - .pipe(futures::stream::iter) - .buffer_unordered(config.peers_to_query()) - .filter_map(std::future::ready) - .flat_map(futures::stream::iter) - .collect::>() - .await; - - update_known_peers(state, metrics, found_peers, allowlisted_peers); -} - -fn update_known_peers( - state: Arc>, - metrics: Metrics, - found_peers: Vec, - allowlisted_peers: Arc>>, -) { - use std::collections::hash_map::Entry; - - let now_unix = now_unix(); - let our_peer_id = state.read().unwrap().our_info.clone().unwrap().peer_id; - let known_peers = &mut state.write().unwrap().known_peers; - for peer in found_peers { - // Skip peers whose timestamp is too far in the future from our clock - // or that are too old - if peer.timestamp_ms > now_unix.saturating_add(30 * 1_000) // 30 seconds - || now_unix.saturating_sub(peer.timestamp_ms) > ONE_DAY_MILLISECONDS - { - continue; - } - - if peer.peer_id == our_peer_id { - continue; - } - - // If Peer is Private, and not in our allowlist, skip it. - if peer.access_type == AccessType::Private && !allowlisted_peers.contains_key(&peer.peer_id) - { - continue; - } - - match known_peers.entry(peer.peer_id) { - Entry::Occupied(mut o) => { - if peer.timestamp_ms > o.get().timestamp_ms { - if o.get().addresses.is_empty() && !peer.addresses.is_empty() { - metrics.inc_num_peers_with_external_address(); - } - if !o.get().addresses.is_empty() && peer.addresses.is_empty() { - metrics.dec_num_peers_with_external_address(); - } - o.insert(peer); - } - } - Entry::Vacant(v) => { - if !peer.addresses.is_empty() { - metrics.inc_num_peers_with_external_address(); - } - v.insert(peer); - } - } - } -} - -fn now_unix() -> u64 { - use std::time::{SystemTime, UNIX_EPOCH}; - - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_millis() as u64 -} diff --git a/crates/sui-network/src/discovery/server.rs b/crates/sui-network/src/discovery/server.rs deleted file mode 100644 index 4b868e0cd11..00000000000 --- a/crates/sui-network/src/discovery/server.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::sync::{Arc, RwLock}; - -use anemo::{Request, Response}; -use serde::{Deserialize, Serialize}; - -use super::{Discovery, NodeInfo, State}; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct GetKnownPeersResponse { - pub own_info: NodeInfo, - pub known_peers: Vec, -} - -pub(super) struct Server { - pub(super) state: Arc>, -} - -#[anemo::async_trait] -impl Discovery for Server { - async fn get_known_peers( - &self, - _request: Request<()>, - ) -> Result, anemo::rpc::Status> { - let state = self.state.read().unwrap(); - let own_info = state - .our_info - .clone() - .ok_or_else(|| anemo::rpc::Status::internal("own_info has not been initialized yet"))?; - let known_peers = state.known_peers.values().cloned().collect(); - - Ok(Response::new(GetKnownPeersResponse { - own_info, - known_peers, - })) - } -} diff --git a/crates/sui-network/src/discovery/tests.rs b/crates/sui-network/src/discovery/tests.rs deleted file mode 100644 index 5ec355c8c79..00000000000 --- a/crates/sui-network/src/discovery/tests.rs +++ /dev/null @@ -1,721 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::HashSet; - -use anemo::{types::PeerAffinity, Result}; -use fastcrypto::ed25519::Ed25519PublicKey; -use futures::stream::FuturesUnordered; -use sui_config::p2p::AllowlistedPeer; -use tokio::time::timeout; - -use super::*; -use crate::utils::{build_network, build_network_with_anemo_config}; - -#[tokio::test] -async fn get_known_peers() -> Result<()> { - let config = P2pConfig::default(); - let (UnstartedDiscovery { state, .. }, server) = Builder::new(create_test_channel().1) - .config(config) - .build_internal(); - - // Err when own_info not set - server.get_known_peers(Request::new(())).await.unwrap_err(); - - // Normal response with our_info - let our_info = NodeInfo { - peer_id: PeerId([9; 32]), - addresses: Vec::new(), - timestamp_ms: now_unix(), - access_type: AccessType::Public, - }; - state.write().unwrap().our_info = Some(our_info.clone()); - let response = server - .get_known_peers(Request::new(())) - .await - .unwrap() - .into_inner(); - assert_eq!(response.own_info, our_info); - assert!(response.known_peers.is_empty()); - - // Normal response with some known peers - let other_peer = NodeInfo { - peer_id: PeerId([13; 32]), - addresses: Vec::new(), - timestamp_ms: now_unix(), - access_type: AccessType::Public, - }; - state - .write() - .unwrap() - .known_peers - .insert(other_peer.peer_id, other_peer.clone()); - let response = server - .get_known_peers(Request::new(())) - .await - .unwrap() - .into_inner(); - assert_eq!(response.own_info, our_info); - assert_eq!(response.known_peers, vec![other_peer]); - - Ok(()) -} - -#[tokio::test] -async fn make_connection_to_seed_peer() -> Result<()> { - let config = P2pConfig::default(); - let (builder, server) = Builder::new(create_test_channel().1).config(config).build(); - let network_1 = build_network(|router| router.add_rpc_service(server)); - let (_event_loop_1, _handle_1) = builder.build(network_1.clone()); - - let mut config = P2pConfig::default(); - config.seed_peers.push(SeedPeer { - peer_id: None, - address: format!("/dns/localhost/udp/{}", network_1.local_addr().port()).parse()?, - }); - let (builder, server) = Builder::new(create_test_channel().1).config(config).build(); - let network_2 = build_network(|router| router.add_rpc_service(server)); - let (mut event_loop_2, _handle_2) = builder.build(network_2.clone()); - - let (mut subscriber_1, _) = network_1.subscribe()?; - let (mut subscriber_2, _) = network_2.subscribe()?; - - event_loop_2.handle_tick(std::time::Instant::now(), now_unix()); - - assert_eq!( - subscriber_2.recv().await?, - PeerEvent::NewPeer(network_1.peer_id()) - ); - assert_eq!( - subscriber_1.recv().await?, - PeerEvent::NewPeer(network_2.peer_id()) - ); - - Ok(()) -} - -#[tokio::test] -async fn make_connection_to_seed_peer_with_peer_id() -> Result<()> { - let config = P2pConfig::default(); - let (builder, server) = Builder::new(create_test_channel().1).config(config).build(); - let network_1 = build_network(|router| router.add_rpc_service(server)); - let (_event_loop_1, _handle_1) = builder.build(network_1.clone()); - - let mut config = P2pConfig::default(); - config.seed_peers.push(SeedPeer { - peer_id: Some(network_1.peer_id()), - address: format!("/dns/localhost/udp/{}", network_1.local_addr().port()).parse()?, - }); - let (builder, server) = Builder::new(create_test_channel().1).config(config).build(); - let network_2 = build_network(|router| router.add_rpc_service(server)); - let (mut event_loop_2, _handle_2) = builder.build(network_2.clone()); - - let (mut subscriber_1, _) = network_1.subscribe()?; - let (mut subscriber_2, _) = network_2.subscribe()?; - - event_loop_2.handle_tick(std::time::Instant::now(), now_unix()); - - assert_eq!( - subscriber_2.recv().await?, - PeerEvent::NewPeer(network_1.peer_id()) - ); - assert_eq!( - subscriber_1.recv().await?, - PeerEvent::NewPeer(network_2.peer_id()) - ); - - Ok(()) -} - -#[tokio::test(flavor = "current_thread", start_paused = true)] -async fn three_nodes_can_connect_via_discovery() -> Result<()> { - // Setup the peer that will be the seed for the other two - let config = P2pConfig::default(); - let (builder, server) = Builder::new(create_test_channel().1).config(config).build(); - let network_1 = build_network(|router| router.add_rpc_service(server)); - let (event_loop_1, _handle_1) = builder.build(network_1.clone()); - - let mut config = P2pConfig::default(); - config.seed_peers.push(SeedPeer { - peer_id: Some(network_1.peer_id()), - address: format!("/dns/localhost/udp/{}", network_1.local_addr().port()).parse()?, - }); - let (builder, server) = Builder::new(create_test_channel().1) - .config(config.clone()) - .build(); - let network_2 = build_network(|router| router.add_rpc_service(server)); - let (mut event_loop_2, _handle_2) = builder.build(network_2.clone()); - // Set an external_address address for node 2 so that it can share its address - event_loop_2.config.external_address = - Some(format!("/dns/localhost/udp/{}", network_2.local_addr().port()).parse()?); - - let (builder, server) = Builder::new(create_test_channel().1).config(config).build(); - let network_3 = build_network(|router| router.add_rpc_service(server)); - let (event_loop_3, _handle_3) = builder.build(network_3.clone()); - - let (mut subscriber_1, _) = network_1.subscribe()?; - let (mut subscriber_2, _) = network_2.subscribe()?; - let (mut subscriber_3, _) = network_3.subscribe()?; - - // Start all the event loops - tokio::spawn(event_loop_1.start()); - tokio::spawn(event_loop_2.start()); - tokio::spawn(event_loop_3.start()); - - let peer_id_1 = network_1.peer_id(); - let peer_id_2 = network_2.peer_id(); - let peer_id_3 = network_3.peer_id(); - - // Get two events from node and make sure they're all connected - let peers_1 = [subscriber_1.recv().await?, subscriber_1.recv().await?] - .into_iter() - .map(unwrap_new_peer_event) - .collect::>(); - assert!(peers_1.contains(&peer_id_2)); - assert!(peers_1.contains(&peer_id_3)); - - let peers_2 = [subscriber_2.recv().await?, subscriber_2.recv().await?] - .into_iter() - .map(unwrap_new_peer_event) - .collect::>(); - assert!(peers_2.contains(&peer_id_1)); - assert!(peers_2.contains(&peer_id_3)); - - let peers_3 = [subscriber_3.recv().await?, subscriber_3.recv().await?] - .into_iter() - .map(unwrap_new_peer_event) - .collect::>(); - assert!(peers_3.contains(&peer_id_1)); - assert!(peers_3.contains(&peer_id_2)); - - Ok(()) -} - -#[tokio::test(flavor = "current_thread", start_paused = true)] -async fn peers_are_added_from_reocnfig_channel() -> Result<()> { - let (tx_1, rx_1) = create_test_channel(); - let config = P2pConfig::default(); - let (builder, server) = Builder::new(rx_1).config(config.clone()).build(); - let network_1 = build_network(|router| router.add_rpc_service(server)); - let (event_loop_1, _handle_1) = builder.build(network_1.clone()); - - let (builder, server) = Builder::new(create_test_channel().1) - .config(config.clone()) - .build(); - let network_2 = build_network(|router| router.add_rpc_service(server)); - let (event_loop_2, _handle_2) = builder.build(network_2.clone()); - - let (mut subscriber_1, _) = network_1.subscribe()?; - let (mut subscriber_2, _) = network_2.subscribe()?; - - // Start all the event loops - tokio::spawn(event_loop_1.start()); - tokio::spawn(event_loop_2.start()); - - let peer_id_1 = network_1.peer_id(); - let peer_id_2 = network_2.peer_id(); - - // At this moment peer 1 and peer 2 are not connected. - let mut futures = FuturesUnordered::new(); - futures.push(timeout(Duration::from_secs(2), subscriber_1.recv())); - futures.push(timeout(Duration::from_secs(2), subscriber_2.recv())); - while let Some(result) = futures.next().await { - let _elapse = result.unwrap_err(); - } - - let (mut subscriber_1, _) = network_1.subscribe()?; - let (mut subscriber_2, _) = network_2.subscribe()?; - - // We send peer 1 a new peer info (peer 2) in the channel. - let peer_2_network_pubkey = - Ed25519PublicKey(ed25519_consensus::VerificationKey::try_from(peer_id_2.0).unwrap()); - let peer2_addr: Multiaddr = format!("/dns/localhost/udp/{}", network_2.local_addr().port()) - .parse() - .unwrap(); - tx_1.send(TrustedPeerChangeEvent { - new_peers: vec![PeerInfo { - peer_id: PeerId(peer_2_network_pubkey.0.to_bytes()), - affinity: PeerAffinity::High, - address: vec![peer2_addr.to_anemo_address().unwrap()], - }], - }) - .unwrap(); - - // Now peer 1 and peer 2 are connected. - let new_peer_for_1 = unwrap_new_peer_event(subscriber_1.recv().await.unwrap()); - assert_eq!(new_peer_for_1, peer_id_2); - let new_peer_for_2 = unwrap_new_peer_event(subscriber_2.recv().await.unwrap()); - assert_eq!(new_peer_for_2, peer_id_1); - - Ok(()) -} - -#[tokio::test] -async fn test_access_types() { - // This test case constructs a mesh graph of 11 nodes, with the following - // topology. For allowlisted nodes, `+` means the peer is allowlisted with - // an address, otherwise not. An allowlisted peer with address will be - // proactively connected in anemo network. - // - // - // The topology: - // ------------ 11 (private, seed: 1, - // allowed: 7, 8) / - // ------ 1 (public) ------ - // / \ - // 2 (public, seed: 1, allowed: 7, 8) 3 (private, seed: 1, allowed: - // 4+, 5+) | / \ - // | 4 (private, allowed: 3+, 5, 6) 5 (private, - // allowed: 3, 4+) | \ - // | 6 (private, allowed: 4+) - // 7 (private, allowed: 2+, 8+) - // | - // | - // 8 (private, allowed: 7+, 9+) p.s. 8's max connection is 0 - // | - // | - // 9 (public) - // | - // | - // 10 (private, seed: 9) - - telemetry_subscribers::init_for_testing(); - - let default_discovery_config = DiscoveryConfig { - target_concurrent_connections: Some(100), - interval_period_ms: Some(1000), - ..Default::default() - }; - let default_p2p_config = P2pConfig { - discovery: Some(default_discovery_config.clone()), - ..Default::default() - }; - let default_private_discovery_config = DiscoveryConfig { - target_concurrent_connections: Some(100), - interval_period_ms: Some(1000), - access_type: Some(AccessType::Private), - ..Default::default() - }; - - // None 1, public - let (builder_1, network_1) = set_up_network(default_p2p_config.clone()); - - let mut config = default_p2p_config.clone(); - config.seed_peers.push(SeedPeer { - peer_id: Some(network_1.peer_id()), - address: format!("/dns/localhost/udp/{}", network_1.local_addr().port()) - .parse() - .unwrap(), - }); - - // Node 2, public, seed: Node 1, allowlist: Node 7, Node 8 - let (mut builder_2, network_2) = set_up_network(config.clone()); - - // Node 3, private, seed: Node 1 - let (mut builder_3, network_3) = set_up_network(config.clone()); - - // Node 4, private, allowlist: Node 3, 5, and 6 - let (mut builder_4, network_4) = set_up_network(P2pConfig::default()); - - // Node 5, private, allowlisted: Node 3 and Node 4 - let (builder_5, network_5) = { - let mut private_discovery_config = default_private_discovery_config.clone(); - private_discovery_config.allowlisted_peers = vec![ - // Intitially 5 does not know how to contact 3 or 4. - local_allowlisted_peer(network_3.peer_id(), None), - local_allowlisted_peer(network_4.peer_id(), Some(network_4.local_addr().port())), - ]; - set_up_network(P2pConfig::default().set_discovery_config(private_discovery_config)) - }; - - // Node 6, private, allowlisted: Node 4 - let (builder_6, network_6) = { - let mut private_discovery_config = default_private_discovery_config.clone(); - private_discovery_config.allowlisted_peers = vec![local_allowlisted_peer( - network_4.peer_id(), - Some(network_4.local_addr().port()), - )]; - set_up_network(P2pConfig::default().set_discovery_config(private_discovery_config)) - }; - - // Node 3: Add Node 4 and Node 5 to allowlist - let mut private_discovery_config = default_private_discovery_config.clone(); - private_discovery_config.allowlisted_peers = vec![ - local_allowlisted_peer(network_4.peer_id(), Some(network_4.local_addr().port())), - local_allowlisted_peer(network_5.peer_id(), Some(network_5.local_addr().port())), - ]; - builder_3.config.discovery = Some(private_discovery_config); - - // Node 4: Add Node 3, Node 5, and Node 6 to allowlist - let mut private_discovery_config = default_private_discovery_config.clone(); - private_discovery_config.allowlisted_peers = vec![ - local_allowlisted_peer(network_3.peer_id(), Some(network_3.local_addr().port())), - local_allowlisted_peer(network_5.peer_id(), None), - local_allowlisted_peer(network_6.peer_id(), None), - ]; - builder_4.config.discovery = Some(private_discovery_config); - - // Node 7, private, allowlisted: Node 2, Node 8 - let (mut builder_7, network_7) = set_up_network( - P2pConfig::default().set_discovery_config(default_private_discovery_config.clone()), - ); - - // Node 9, public - let (builder_9, network_9) = set_up_network(default_p2p_config.clone()); - - // Node 8, private, allowlisted: Node 7, Node 9 - let (builder_8, network_8) = { - let mut private_discovery_config = default_private_discovery_config.clone(); - private_discovery_config.allowlisted_peers = vec![ - local_allowlisted_peer(network_7.peer_id(), Some(network_7.local_addr().port())), - local_allowlisted_peer(network_9.peer_id(), Some(network_9.local_addr().port())), - ]; - let mut p2p_config = P2pConfig::default(); - let mut anemo_config = anemo::Config::default(); - anemo_config.max_concurrent_connections = Some(0); - p2p_config.anemo_config = Some(anemo_config); - set_up_network(p2p_config.set_discovery_config(private_discovery_config)) - }; - - // Node 2, Add Node 7 and Node 8 to allowlist - let mut discovery_config = default_discovery_config.clone(); - discovery_config.allowlisted_peers = vec![ - local_allowlisted_peer(network_7.peer_id(), None), - local_allowlisted_peer(network_8.peer_id(), None), - ]; - builder_2.config.discovery = Some(discovery_config); - - // Node 7: Add Node 2, and Node 8 to allowlist - let mut private_discovery_config = default_private_discovery_config.clone(); - private_discovery_config.allowlisted_peers = vec![ - local_allowlisted_peer(network_2.peer_id(), Some(network_2.local_addr().port())), - local_allowlisted_peer(network_8.peer_id(), Some(network_8.local_addr().port())), - ]; - builder_7.config.discovery = Some(private_discovery_config); - - // Node 10, private, seed: 9 - let (builder_10, network_10) = { - let mut p2p_config = default_p2p_config.clone(); - p2p_config.seed_peers.push(SeedPeer { - peer_id: Some(network_9.peer_id()), - address: format!("/dns/localhost/udp/{}", network_9.local_addr().port()) - .parse() - .unwrap(), - }); - p2p_config.discovery = Some(default_private_discovery_config.clone()); - set_up_network(p2p_config.clone()) - }; - - // Node 11, private, seed: 1, allow: 7, 8 - let (builder_11, network_11) = { - let mut p2p_config = default_p2p_config.clone(); - p2p_config.seed_peers.push(SeedPeer { - peer_id: Some(network_1.peer_id()), - address: format!("/dns/localhost/udp/{}", network_1.local_addr().port()) - .parse() - .unwrap(), - }); - let mut private_discovery_config = default_private_discovery_config.clone(); - private_discovery_config.allowlisted_peers = vec![ - local_allowlisted_peer(network_8.peer_id(), None), - local_allowlisted_peer(network_7.peer_id(), None), - ]; - p2p_config.discovery = Some(private_discovery_config); - set_up_network(p2p_config) - }; - - let (event_loop_1, _handle_1, state_1) = start_network(builder_1, network_1.clone()); - let (event_loop_2, _handle_2, state_2) = start_network(builder_2, network_2.clone()); - let (event_loop_3, _handle_3, state_3) = start_network(builder_3, network_3.clone()); - let (event_loop_4, _handle_4, state_4) = start_network(builder_4, network_4.clone()); - let (event_loop_5, _handle_5, state_5) = start_network(builder_5, network_5.clone()); - let (event_loop_6, _handle_6, state_6) = start_network(builder_6, network_6.clone()); - let (event_loop_7, _handle_7, state_7) = start_network(builder_7, network_7.clone()); - let (event_loop_8, _handle_8, state_8) = start_network(builder_8, network_8.clone()); - let (event_loop_9, _handle_9, state_9) = start_network(builder_9, network_9.clone()); - let (event_loop_10, _handle_10, state_10) = start_network(builder_10, network_10.clone()); - let (event_loop_11, _handle_11, state_11) = start_network(builder_11, network_11.clone()); - - // Start all the event loops - tokio::spawn(event_loop_1.start()); - tokio::spawn(event_loop_2.start()); - tokio::spawn(event_loop_3.start()); - tokio::spawn(event_loop_4.start()); - tokio::spawn(event_loop_5.start()); - tokio::spawn(event_loop_6.start()); - tokio::spawn(event_loop_7.start()); - tokio::spawn(event_loop_8.start()); - tokio::spawn(event_loop_9.start()); - tokio::spawn(event_loop_10.start()); - tokio::spawn(event_loop_11.start()); - - let peer_id_1 = network_1.peer_id(); - let peer_id_2 = network_2.peer_id(); - let peer_id_3 = network_3.peer_id(); - let peer_id_4 = network_4.peer_id(); - let peer_id_5 = network_5.peer_id(); - let peer_id_6 = network_6.peer_id(); - let peer_id_7 = network_7.peer_id(); - let peer_id_8 = network_8.peer_id(); - let peer_id_9 = network_9.peer_id(); - let peer_id_10 = network_10.peer_id(); - let peer_id_11 = network_11.peer_id(); - - info!("peer_id_1: {:?}", peer_id_1); - info!("peer_id_2: {:?}", peer_id_2); - info!("peer_id_3: {:?}", peer_id_3); - info!("peer_id_4: {:?}", peer_id_4); - info!("peer_id_5: {:?}", peer_id_5); - info!("peer_id_6: {:?}", peer_id_6); - info!("peer_id_7: {:?}", peer_id_7); - info!("peer_id_8: {:?}", peer_id_8); - info!("peer_id_9: {:?}", peer_id_9); - info!("peer_id_10: {:?}", peer_id_10); - info!("peer_id_11: {:?}", peer_id_11); - - // Let them fully connect - tokio::time::sleep(Duration::from_secs(10)).await; - - // Node 1 is connected to everyone. But it does not "know" private nodes. - assert_peers( - "Node 1", - &network_1, - &state_1, - HashSet::from_iter(vec![]), - HashSet::from_iter(vec![ - peer_id_2, peer_id_3, peer_id_4, peer_id_5, peer_id_6, peer_id_7, peer_id_8, peer_id_9, - peer_id_10, peer_id_11, - ]), - HashSet::from_iter(vec![peer_id_2, peer_id_9]), - HashSet::from_iter(vec![ - peer_id_2, peer_id_3, peer_id_4, peer_id_5, peer_id_6, peer_id_7, peer_id_8, peer_id_9, - peer_id_10, peer_id_11, - ]), - ); - - // Node 1 is connected to everyone. But it does not "know" private nodes except - // the allowlisted ones 7 and 8. - assert_peers( - "Node 2", - &network_2, - &state_2, - HashSet::from_iter(vec![peer_id_1, peer_id_7, peer_id_8]), - HashSet::from_iter(vec![ - peer_id_1, peer_id_3, peer_id_4, peer_id_5, peer_id_6, peer_id_7, peer_id_8, peer_id_9, - peer_id_10, peer_id_11, - ]), - HashSet::from_iter(vec![peer_id_1, peer_id_7, peer_id_8, peer_id_9]), - HashSet::from_iter(vec![ - peer_id_1, peer_id_3, peer_id_4, peer_id_5, peer_id_6, peer_id_7, peer_id_8, peer_id_9, - peer_id_10, peer_id_11, - ]), - ); - - assert_peers( - "Node 3", - &network_3, - &state_3, - HashSet::from_iter(vec![peer_id_1, peer_id_4, peer_id_5]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_4, peer_id_5, peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_4, peer_id_5, peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_4, peer_id_5, peer_id_9]), - ); - - assert_peers( - "Node 4", - &network_4, - &state_4, - HashSet::from_iter(vec![peer_id_3, peer_id_5, peer_id_6]), - HashSet::from_iter(vec![ - peer_id_1, peer_id_2, peer_id_3, peer_id_5, peer_id_6, peer_id_9, - ]), - HashSet::from_iter(vec![ - peer_id_1, peer_id_2, peer_id_3, peer_id_5, peer_id_6, peer_id_9, - ]), - HashSet::from_iter(vec![ - peer_id_1, peer_id_2, peer_id_3, peer_id_5, peer_id_6, peer_id_9, - ]), - ); - - assert_peers( - "Node 5", - &network_5, - &state_5, - HashSet::from_iter(vec![peer_id_3, peer_id_4]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_3, peer_id_4, peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_3, peer_id_4, peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_3, peer_id_4, peer_id_9]), - ); - - assert_peers( - "Node 6", - &network_6, - &state_6, - HashSet::from_iter(vec![peer_id_4]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_4, peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_4, peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_4, peer_id_9]), - ); - - // Node 11 finds Node 7 via Node 2, and invites Node 7 to connect. Node 7 says - // yes. - assert_peers( - "Node 7", - &network_7, - &state_7, - HashSet::from_iter(vec![peer_id_2, peer_id_8]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_8, peer_id_9, peer_id_11]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_8, peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_8, peer_id_9, peer_id_11]), - ); - - // Node 11 finds Node 8 via Node 2, and invites Node 8 to connect. Node 8 said - // No because its `max_concurrent_connections` is 0. - assert_peers( - "Node 8", - &network_8, - &state_8, - HashSet::from_iter(vec![peer_id_7, peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_7, peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_7, peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_7, peer_id_9]), - ); - - assert_peers( - "Node 9", - &network_9, - &state_9, - HashSet::from_iter(vec![]), - HashSet::from_iter(vec![ - peer_id_1, peer_id_2, peer_id_3, peer_id_4, peer_id_5, peer_id_6, peer_id_7, peer_id_8, - peer_id_10, peer_id_11, - ]), - HashSet::from_iter(vec![peer_id_1, peer_id_2]), - HashSet::from_iter(vec![ - peer_id_1, peer_id_2, peer_id_3, peer_id_4, peer_id_5, peer_id_6, peer_id_7, peer_id_8, - peer_id_10, peer_id_11, - ]), - ); - - // Node 10 does not talk to any other private nodes. - assert_peers( - "Node 10", - &network_10, - &state_10, - HashSet::from_iter(vec![peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_9]), - ); - - // 11 allowlists 8 but 8 does not 11, so they can't connect - // although 8 is still in 11's known peer list - assert_peers( - "Node 11", - &network_11, - &state_11, - HashSet::from_iter(vec![peer_id_1, peer_id_7, peer_id_8]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_7, peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_7, peer_id_8, peer_id_9]), - HashSet::from_iter(vec![peer_id_1, peer_id_2, peer_id_7, peer_id_9]), - ); -} - -fn assert_peers( - self_name: &str, - network: &Network, - state: &Arc>, - expected_network_known_peers: HashSet, - expected_network_connected_peers: HashSet, - expected_discovery_known_peers: HashSet, - expected_discovery_connected_peers: HashSet, -) { - let actual = network - .known_peers() - .get_all() - .iter() - .map(|pi| pi.peer_id) - .collect::>(); - assert_eq!( - actual, expected_network_known_peers, - "{} network known peers mismatch. Expected: {:#?}, actual: {:#?}", - self_name, expected_network_known_peers, actual, - ); - let actual = network.peers().iter().copied().collect::>(); - assert_eq!( - actual, expected_network_connected_peers, - "{} network connected peers mismatch. Expected: {:#?}, actual: {:#?}", - self_name, expected_network_connected_peers, actual, - ); - let actual = state - .read() - .unwrap() - .known_peers - .keys() - .cloned() - .collect::>(); - assert_eq!( - actual, expected_discovery_known_peers, - "{} discovery known peers mismatch. Expected: {:#?}, actual: {:#?}", - self_name, expected_discovery_known_peers, actual, - ); - - let actual = state - .read() - .unwrap() - .connected_peers - .keys() - .cloned() - .collect::>(); - assert_eq!( - actual, expected_discovery_connected_peers, - "{} discovery connected peers mismatch. Expected: {:#?}, actual: {:#?}", - self_name, expected_discovery_connected_peers, actual, - ); -} - -fn unwrap_new_peer_event(event: PeerEvent) -> PeerId { - match event { - PeerEvent::NewPeer(peer_id) => peer_id, - e => panic!("unexpected event: {e:?}"), - } -} - -fn local_allowlisted_peer(peer_id: PeerId, port: Option) -> AllowlistedPeer { - AllowlistedPeer { - peer_id, - address: port.map(|port| format!("/dns/localhost/udp/{}", port).parse().unwrap()), - } -} - -fn set_up_network(p2p_config: P2pConfig) -> (UnstartedDiscovery, Network) { - let anemo_config = p2p_config.anemo_config.clone().unwrap_or_default(); - let (builder, server) = Builder::new(create_test_channel().1) - .config(p2p_config) - .build(); - let network = - build_network_with_anemo_config(|router| router.add_rpc_service(server), anemo_config); - (builder, network) -} - -fn start_network( - builder: UnstartedDiscovery, - network: Network, -) -> (DiscoveryEventLoop, Handle, Arc>) { - let (mut event_loop, handle) = builder.build(network.clone()); - event_loop.config.external_address = Some( - format!("/dns/localhost/udp/{}", network.local_addr().port()) - .parse() - .unwrap(), - ); - let state = event_loop.state.clone(); - (event_loop, handle, state) -} - -fn create_test_channel() -> ( - watch::Sender, - watch::Receiver, -) { - let (tx, rx) = watch::channel(TrustedPeerChangeEvent { new_peers: vec![] }); - (tx, rx) -} diff --git a/crates/sui-network/src/lib.rs b/crates/sui-network/src/lib.rs deleted file mode 100644 index 1b79970c1f9..00000000000 --- a/crates/sui-network/src/lib.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::time::Duration; - -use mysten_network::config::Config; - -pub mod api; -pub mod discovery; -pub mod randomness; -pub mod state_sync; -pub mod utils; - -pub use tonic; - -pub const DEFAULT_CONNECT_TIMEOUT_SEC: Duration = Duration::from_secs(10); -pub const DEFAULT_REQUEST_TIMEOUT_SEC: Duration = Duration::from_secs(30); -pub const DEFAULT_HTTP2_KEEPALIVE_SEC: Duration = Duration::from_secs(5); - -pub fn default_mysten_network_config() -> Config { - let mut net_config = mysten_network::config::Config::new(); - net_config.connect_timeout = Some(DEFAULT_CONNECT_TIMEOUT_SEC); - net_config.request_timeout = Some(DEFAULT_REQUEST_TIMEOUT_SEC); - net_config.http2_keepalive_interval = Some(DEFAULT_HTTP2_KEEPALIVE_SEC); - net_config -} diff --git a/crates/sui-network/src/randomness/builder.rs b/crates/sui-network/src/randomness/builder.rs deleted file mode 100644 index 9efcb526fbf..00000000000 --- a/crates/sui-network/src/randomness/builder.rs +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::{BTreeMap, BTreeSet, HashMap, HashSet}, - sync::Arc, -}; - -use anemo::codegen::InboundRequestLayer; -use anemo_tower::{auth::RequireAuthorizationLayer, inflight_limit}; -use sui_config::p2p::RandomnessConfig; -use sui_types::{base_types::AuthorityName, committee::EpochId, crypto::RandomnessRound}; -use tokio::sync::mpsc; - -use super::{ - auth::AllowedPeersUpdatable, metrics::Metrics, server::Server, Handle, RandomnessEventLoop, - RandomnessMessage, RandomnessServer, -}; - -/// Randomness Service Builder. -pub struct Builder { - name: AuthorityName, - config: Option, - metrics: Option, - randomness_tx: mpsc::Sender<(EpochId, RandomnessRound, Vec)>, -} - -impl Builder { - pub fn new( - name: AuthorityName, - randomness_tx: mpsc::Sender<(EpochId, RandomnessRound, Vec)>, - ) -> Self { - Self { - name, - config: None, - metrics: None, - randomness_tx, - } - } - - pub fn config(mut self, config: RandomnessConfig) -> Self { - self.config = Some(config); - self - } - - pub fn with_metrics(mut self, registry: &prometheus::Registry) -> Self { - self.metrics = Some(Metrics::enabled(registry)); - self - } - - pub fn build(self) -> (UnstartedRandomness, anemo::Router) { - let Builder { - name, - config, - metrics, - randomness_tx, - } = self; - let config = config.unwrap_or_default(); - let metrics = metrics.unwrap_or_else(Metrics::disabled); - let (sender, mailbox) = mpsc::channel(config.mailbox_capacity()); - let handle = Handle { - sender: sender.clone(), - }; - let server = Server { - sender: sender.downgrade(), - }; - let randomness_server = RandomnessServer::new(server).add_layer_for_send_signatures( - InboundRequestLayer::new(inflight_limit::InflightLimitLayer::new( - config.send_partial_signatures_inflight_limit(), - inflight_limit::WaitMode::ReturnError, - )), - ); - - let allowed_peers = AllowedPeersUpdatable::new(Arc::new(HashSet::new())); - let router = anemo::Router::new() - .route_layer(RequireAuthorizationLayer::new(allowed_peers.clone())) - .add_rpc_service(randomness_server); - - ( - UnstartedRandomness { - name, - config, - handle, - mailbox, - allowed_peers, - metrics, - randomness_tx, - }, - router, - ) - } -} - -/// Handle to an unstarted randomness network system -pub struct UnstartedRandomness { - pub(super) name: AuthorityName, - pub(super) config: RandomnessConfig, - pub(super) handle: Handle, - pub(super) mailbox: mpsc::Receiver, - pub(super) allowed_peers: AllowedPeersUpdatable, - pub(super) metrics: Metrics, - pub(super) randomness_tx: mpsc::Sender<(EpochId, RandomnessRound, Vec)>, -} - -impl UnstartedRandomness { - pub(super) fn build(self, network: anemo::Network) -> (RandomnessEventLoop, Handle) { - let Self { - name, - config, - handle, - mailbox, - allowed_peers, - metrics, - randomness_tx, - } = self; - ( - RandomnessEventLoop { - name, - config, - mailbox, - network, - allowed_peers, - metrics, - randomness_tx, - - epoch: 0, - authority_info: Arc::new(HashMap::new()), - peer_share_counts: None, - dkg_output: None, - aggregation_threshold: 0, - pending_tasks: BTreeSet::new(), - send_tasks: BTreeMap::new(), - round_request_time: BTreeMap::new(), - received_partial_sigs: BTreeMap::new(), - completed_sigs: BTreeSet::new(), - completed_rounds: BTreeSet::new(), - }, - handle, - ) - } - - pub fn start(self, network: anemo::Network) -> Handle { - let (event_loop, handle) = self.build(network); - tokio::spawn(event_loop.start()); - - handle - } -} diff --git a/crates/sui-network/src/randomness/metrics.rs b/crates/sui-network/src/randomness/metrics.rs deleted file mode 100644 index d8d834389ff..00000000000 --- a/crates/sui-network/src/randomness/metrics.rs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::sync::Arc; - -use prometheus::{ - register_histogram_with_registry, register_int_gauge_with_registry, Histogram, IntGauge, - Registry, -}; -use sui_types::{committee::EpochId, crypto::RandomnessRound}; -use tap::Pipe; - -#[derive(Clone)] -pub(super) struct Metrics(Option>); - -impl std::fmt::Debug for Metrics { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - fmt.debug_struct("Metrics").finish() - } -} - -impl Metrics { - pub fn enabled(registry: &Registry) -> Self { - Metrics(Some(Inner::new(registry))) - } - - pub fn disabled() -> Self { - Metrics(None) - } - - pub fn set_epoch(&self, epoch: EpochId) { - if let Some(inner) = &self.0 { - inner.current_epoch.set(epoch as i64); - inner.highest_round_generated.set(-1); - } - } - - pub fn record_completed_round(&self, round: RandomnessRound) { - if let Some(inner) = &self.0 { - inner - .highest_round_generated - .set(inner.highest_round_generated.get().max(round.0 as i64)); - } - } - - pub fn set_num_rounds_pending(&self, num_rounds_pending: usize) { - if let Some(inner) = &self.0 { - inner.num_rounds_pending.set(num_rounds_pending as i64); - } - } - - pub fn round_generation_latency_metric(&self) -> Option<&Histogram> { - self.0.as_ref().map(|inner| &inner.round_generation_latency) - } - - pub fn round_observation_latency_metric(&self) -> Option<&Histogram> { - self.0 - .as_ref() - .map(|inner| &inner.round_observation_latency) - } -} - -struct Inner { - current_epoch: IntGauge, - highest_round_generated: IntGauge, - num_rounds_pending: IntGauge, - round_generation_latency: Histogram, - round_observation_latency: Histogram, -} - -const LATENCY_SEC_BUCKETS: &[f64] = &[ - 0.001, 0.005, 0.01, 0.05, 0.1, 0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.2, 1.4, - 1.6, 1.8, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10., - 12.5, 15., 17.5, 20., 25., 30., 60., 90., 120., 180., 300., -]; - -impl Inner { - pub fn new(registry: &Registry) -> Arc { - Self { - current_epoch: register_int_gauge_with_registry!( - "randomness_current_epoch", - "The current epoch for which randomness is being generated (only updated after DKG completes)", - registry - ).unwrap(), - highest_round_generated: register_int_gauge_with_registry!( - "randomness_highest_round_generated", - "The highest round for which randomness has been generated for the current epoch", - registry - ).unwrap(), - num_rounds_pending: register_int_gauge_with_registry!( - "randomness_num_rounds_pending", - "The number of rounds of randomness that are pending generation/observation", - registry - ).unwrap(), - round_generation_latency: register_histogram_with_registry!( - "randomness_round_generation_latency", - "Time taken to generate a single round of randomness, from when the round is requested to when the full signature is aggregated", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ).unwrap(), - round_observation_latency: register_histogram_with_registry!( - "randomness_round_observation_latency", - "Time taken from when partial signatures are sent for a round of randomness to when the value is observed in an executed checkpoint", - LATENCY_SEC_BUCKETS.to_vec(), - registry - ).unwrap(), - } - .pipe(Arc::new) - } -} diff --git a/crates/sui-network/src/randomness/mod.rs b/crates/sui-network/src/randomness/mod.rs deleted file mode 100644 index 4a2c4a6aa8a..00000000000 --- a/crates/sui-network/src/randomness/mod.rs +++ /dev/null @@ -1,708 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::{btree_map::BTreeMap, BTreeSet, HashMap}, - ops::Bound, - sync::Arc, - time::{self, Duration}, -}; - -use anemo::PeerId; -use anyhow::Result; -use fastcrypto::groups::bls12381; -use fastcrypto_tbls::{dkg, nodes::PartyId, tbls::ThresholdBls, types::ThresholdBls12381MinSig}; -use mysten_metrics::spawn_monitored_task; -use mysten_network::anemo_ext::NetworkExt; -use serde::{Deserialize, Serialize}; -use sui_config::p2p::RandomnessConfig; -use sui_types::{ - base_types::AuthorityName, - committee::EpochId, - crypto::{RandomnessPartialSignature, RandomnessRound, RandomnessSignature}, -}; -use tokio::sync::mpsc; -use tracing::{debug, error, info, instrument, warn}; - -use self::{auth::AllowedPeersUpdatable, metrics::Metrics}; - -mod auth; -mod builder; -mod generated { - include!(concat!(env!("OUT_DIR"), "/sui.Randomness.rs")); -} -mod metrics; -mod server; -#[cfg(test)] -mod tests; - -pub use builder::{Builder, UnstartedRandomness}; -pub use generated::{ - randomness_client::RandomnessClient, - randomness_server::{Randomness, RandomnessServer}, -}; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct SendSignaturesRequest { - epoch: EpochId, - round: RandomnessRound, - // BCS-serialized `RandomnessPartialSignature` values. We store raw bytes here to enable - // defenses against too-large messages. - partial_sigs: Vec>, - // TODO: add support for receiving full signature from validators who have already - // reconstructed it. - sig: Option, -} - -/// A handle to the Randomness network subsystem. -/// -/// This handle can be cloned and shared. Once all copies of a Randomness -/// system's Handle have been dropped, the Randomness system will be gracefully -/// shutdown. -#[derive(Clone, Debug)] -pub struct Handle { - sender: mpsc::Sender, -} - -impl Handle { - /// Transitions the Randomness system to a new epoch. Cancels all partial - /// signature sends for prior epochs. - pub fn update_epoch( - &self, - new_epoch: EpochId, - authority_info: HashMap, - dkg_output: dkg::Output, - aggregation_threshold: u16, - ) { - self.sender - .try_send(RandomnessMessage::UpdateEpoch( - new_epoch, - authority_info, - dkg_output, - aggregation_threshold, - )) - .expect("RandomnessEventLoop mailbox should not overflow or be closed") - } - - /// Begins transmitting partial signatures for the given epoch and round - /// until completed. - pub fn send_partial_signatures(&self, epoch: EpochId, round: RandomnessRound) { - self.sender - .try_send(RandomnessMessage::SendPartialSignatures(epoch, round)) - .expect("RandomnessEventLoop mailbox should not overflow or be closed") - } - - /// Records the given round as complete, stopping any partial signature - /// sends. - pub fn complete_round(&self, epoch: EpochId, round: RandomnessRound) { - self.sender - .try_send(RandomnessMessage::CompleteRound(epoch, round)) - .expect("RandomnessEventLoop mailbox should not overflow or be closed") - } - - // For testing. - pub fn new_stub() -> Self { - let (sender, mut receiver) = mpsc::channel(1); - // Keep receiver open until all senders are closed. - tokio::spawn(async move { - loop { - tokio::select! { - m = receiver.recv() => { - if m.is_none() { - break; - } - }, - } - } - }); - Self { sender } - } -} - -#[derive(Clone, Debug)] -enum RandomnessMessage { - UpdateEpoch( - EpochId, - HashMap, - dkg::Output, - u16, // aggregation_threshold - ), - SendPartialSignatures(EpochId, RandomnessRound), - CompleteRound(EpochId, RandomnessRound), - ReceivePartialSignatures(PeerId, EpochId, RandomnessRound, Vec>), -} - -struct RandomnessEventLoop { - name: AuthorityName, - config: RandomnessConfig, - mailbox: mpsc::Receiver, - network: anemo::Network, - allowed_peers: AllowedPeersUpdatable, - metrics: Metrics, - randomness_tx: mpsc::Sender<(EpochId, RandomnessRound, Vec)>, - - epoch: EpochId, - authority_info: Arc>, - peer_share_counts: Option>, - dkg_output: Option>, - aggregation_threshold: u16, - pending_tasks: BTreeSet<(EpochId, RandomnessRound)>, - send_tasks: BTreeMap<(EpochId, RandomnessRound), tokio::task::JoinHandle<()>>, - round_request_time: BTreeMap<(EpochId, RandomnessRound), time::Instant>, - received_partial_sigs: - BTreeMap<(EpochId, RandomnessRound, PeerId), Vec>, - completed_sigs: BTreeSet<(EpochId, RandomnessRound)>, - completed_rounds: BTreeSet<(EpochId, RandomnessRound)>, -} - -impl RandomnessEventLoop { - pub async fn start(mut self) { - info!("Randomness network event loop started"); - - loop { - tokio::select! { - maybe_message = self.mailbox.recv() => { - // Once all handles to our mailbox have been dropped this - // will yield `None` and we can terminate the event loop. - if let Some(message) = maybe_message { - self.handle_message(message); - } else { - break; - } - }, - } - } - - info!("Randomness network event loop ended"); - } - - fn handle_message(&mut self, message: RandomnessMessage) { - match message { - RandomnessMessage::UpdateEpoch( - epoch, - authority_info, - dkg_output, - aggregation_threshold, - ) => { - if let Err(e) = - self.update_epoch(epoch, authority_info, dkg_output, aggregation_threshold) - { - error!("BUG: failed to update epoch in RandomnessEventLoop: {e:?}"); - } - } - RandomnessMessage::SendPartialSignatures(epoch, round) => { - self.send_partial_signatures(epoch, round) - } - RandomnessMessage::CompleteRound(epoch, round) => self.complete_round(epoch, round), - RandomnessMessage::ReceivePartialSignatures(peer_id, epoch, round, sigs) => { - self.receive_partial_signatures(peer_id, epoch, round, sigs) - } - } - } - - #[instrument(level = "debug", skip_all, fields(?new_epoch))] - fn update_epoch( - &mut self, - new_epoch: EpochId, - authority_info: HashMap, - dkg_output: dkg::Output, - aggregation_threshold: u16, - ) -> Result<()> { - assert!(self.dkg_output.is_none() || new_epoch > self.epoch); - - debug!("updating randomness network loop to new epoch"); - - self.peer_share_counts = Some(authority_info.iter().try_fold( - HashMap::new(), - |mut acc, (_name, (peer_id, party_id))| -> Result<_> { - let weight = dkg_output.nodes.node_id_to_node(*party_id)?.weight; - acc.insert(*peer_id, weight); - Ok(acc) - }, - )?); - self.allowed_peers.update(Arc::new( - authority_info - .values() - .map(|(peer_id, _)| *peer_id) - .collect(), - )); - self.epoch = new_epoch; - self.authority_info = Arc::new(authority_info); - self.dkg_output = Some(dkg_output); - self.aggregation_threshold = aggregation_threshold; - for (_, task) in std::mem::take(&mut self.send_tasks) { - task.abort(); - } - self.metrics.set_epoch(new_epoch); - - // Throw away info from old epochs. - self.round_request_time = self - .round_request_time - .split_off(&(new_epoch, RandomnessRound(0))); - self.received_partial_sigs = - self.received_partial_sigs - .split_off(&(new_epoch, RandomnessRound(0), PeerId([0; 32]))); - self.completed_sigs = self - .completed_sigs - .split_off(&(new_epoch, RandomnessRound(0))); - self.completed_rounds = self - .completed_rounds - .split_off(&(new_epoch, RandomnessRound(0))); - - // Start any pending tasks for the new epoch. - self.maybe_start_pending_tasks(); - - // Aggregate any sigs received early from the new epoch. - // (We can't call `maybe_aggregate_partial_signatures` directly while iterating, - // because it takes `&mut self`, so we store in a Vec first.) - let mut aggregate_rounds = BTreeSet::new(); - for (epoch, round, _) in self.received_partial_sigs.keys() { - if *epoch < new_epoch { - error!( - "BUG: received partial sigs for old epoch still present after attempting to remove them" - ); - debug_assert!( - false, - "received partial sigs for old epoch still present after attempting to remove them" - ); - continue; - } - if *epoch > new_epoch { - break; - } - if !self.completed_sigs.contains(&(*epoch, *round)) { - aggregate_rounds.insert(*round); - } - } - for round in aggregate_rounds { - self.maybe_aggregate_partial_signatures(new_epoch, round); - } - - Ok(()) - } - - #[instrument(level = "debug", skip_all, fields(?epoch, ?round))] - fn send_partial_signatures(&mut self, epoch: EpochId, round: RandomnessRound) { - if epoch < self.epoch { - error!( - "BUG: skipping sending partial sigs, we are already up to epoch {}", - self.epoch - ); - debug_assert!( - false, - "skipping sending partial sigs, we are already up to higher epoch" - ); - return; - } - if self.completed_rounds.contains(&(epoch, round)) { - info!("skipping sending partial sigs, we already have completed this round"); - return; - } - - self.pending_tasks.insert((epoch, round)); - self.round_request_time - .insert((epoch, round), time::Instant::now()); - self.maybe_start_pending_tasks(); - } - - #[instrument(level = "debug", skip_all, fields(?epoch, ?round))] - fn complete_round(&mut self, epoch: EpochId, round: RandomnessRound) { - debug!("completing randomness round"); - self.pending_tasks.remove(&(epoch, round)); - self.round_request_time.remove(&(epoch, round)); - self.completed_sigs.insert((epoch, round)); // in case we got it from a checkpoint - self.completed_rounds.insert((epoch, round)); - if let Some(task) = self.send_tasks.remove(&(epoch, round)) { - task.abort(); - self.maybe_start_pending_tasks(); - } else { - self.update_rounds_pending_metric(); - } - } - - #[instrument(level = "debug", skip_all, fields(?peer_id, ?epoch, ?round))] - fn receive_partial_signatures( - &mut self, - peer_id: PeerId, - epoch: EpochId, - round: RandomnessRound, - sig_bytes: Vec>, - ) { - // Big slate of validity checks on received partial signatures. - let peer_share_counts = if let Some(peer_share_counts) = &self.peer_share_counts { - peer_share_counts - } else { - debug!("can't accept partial signatures until DKG has completed"); - return; - }; - if epoch < self.epoch { - debug!( - "skipping received partial sigs, we are already up to epoch {}", - self.epoch - ); - return; - } - if epoch > self.epoch + 1 { - debug!( - "skipping received partial sigs, we are still on epoch {}", - self.epoch - ); - return; - } - if self.completed_sigs.contains(&(epoch, round)) { - debug!("skipping received partial sigs, we already have completed this sig"); - return; - } - let expected_share_count = if let Some(count) = peer_share_counts.get(&peer_id) { - count - } else { - debug!("received partial sigs from unknown peer"); - return; - }; - if sig_bytes.len() != *expected_share_count as usize { - // No need to verify share IDs here as well, since if we receive incorrect IDs, - // we will catch it later when aggregating/verifying the partial - // sigs. - debug!( - "received partial sigs with wrong share count: expected {expected_share_count}, got {}", - sig_bytes.len(), - ); - return; - } - let (last_completed_epoch, last_completed_round) = match self.completed_sigs.last() { - Some((last_completed_epoch, last_completed_round)) => { - (*last_completed_epoch, *last_completed_round) - } - // If we just changed epochs and haven't completed any sigs yet, this will be used. - None => (self.epoch, RandomnessRound(0)), - }; - if epoch == last_completed_epoch - && round.0 - >= last_completed_round - .0 - .saturating_add(self.config.max_partial_sigs_rounds_ahead()) - { - debug!( - "skipping received partial sigs, most recent round we completed was only {last_completed_round}", - ); - return; - } - if epoch > last_completed_epoch && round.0 >= self.config.max_partial_sigs_rounds_ahead() { - debug!( - "skipping received partial sigs, most recent epoch we completed was only {last_completed_epoch}", - ); - return; - } - - // We passed all the checks, deserialize and save the partial sigs. - let partial_sigs = - match sig_bytes - .iter() - .try_fold(Vec::new(), |mut acc, bytes| -> Result<_> { - let sig: RandomnessPartialSignature = bcs::from_bytes(bytes)?; - acc.push(sig); - Ok(acc) - }) { - Ok(partial_sigs) => partial_sigs, - Err(e) => { - debug!("failed to deserialize partial sigs: {e:?}"); - return; - } - }; - debug!("recording received partial signatures"); - self.received_partial_sigs - .insert((epoch, round, peer_id), partial_sigs); - - self.maybe_aggregate_partial_signatures(epoch, round); - } - - #[instrument(level = "debug", skip_all, fields(?epoch, ?round))] - fn maybe_aggregate_partial_signatures(&mut self, epoch: EpochId, round: RandomnessRound) { - if self.completed_sigs.contains(&(epoch, round)) { - error!("BUG: called maybe_aggregate_partial_signatures for already-completed round"); - debug_assert!( - false, - "called maybe_aggregate_partial_signatures for already-completed round" - ); - return; - } - - if !(self.send_tasks.contains_key(&(epoch, round)) - || self.pending_tasks.contains(&(epoch, round))) - { - // We have to wait here, because even if we have enough information from other - // nodes to complete the signature, local shared object versions are - // not set until consensus finishes processing the corresponding - // commit. This function will be called again - // after maybe_start_pending_tasks begins this round locally. - debug!( - "waiting to aggregate randomness partial signatures until local consensus catches up" - ); - return; - } - - let vss_pk = { - let Some(dkg_output) = &self.dkg_output else { - debug!("called maybe_aggregate_partial_signatures before DKG completed"); - return; - }; - &dkg_output.vss_pk - }; - - let sig_bounds = ( - Bound::Included((epoch, round, PeerId([0; 32]))), - Bound::Excluded((epoch, round + 1, PeerId([0; 32]))), - ); - - // If we have enough partial signatures, aggregate them. - let sig_range = self - .received_partial_sigs - .range(sig_bounds) - .flat_map(|(_, sigs)| sigs); - let mut sig = match ThresholdBls12381MinSig::aggregate( - self.aggregation_threshold, - sig_range, - ) { - Ok(sig) => sig, - Err(fastcrypto::error::FastCryptoError::NotEnoughInputs) => return, // wait for more - // input - Err(e) => { - error!("error while aggregating randomness partial signatures: {e:?}"); - return; - } - }; - - // Try to verify the aggregated signature all at once. (Should work in the happy - // path.) - if ThresholdBls12381MinSig::verify(vss_pk.c0(), &round.signature_message(), &sig).is_err() { - // If verifiation fails, some of the inputs must be invalid. We have to go - // through one-by-one to find which. - // TODO: add test for individual sig verification. - self.received_partial_sigs - .retain(|&(e, r, peer_id), partial_sigs| { - if epoch != e || round != r { - return true; - } - if ThresholdBls12381MinSig::partial_verify_batch( - vss_pk, - &round.signature_message(), - partial_sigs.iter(), - &mut rand::thread_rng(), - ) - .is_err() - { - warn!( - "received invalid partial signatures from possibly-Byzantine peer {peer_id}" - ); - // TODO: Ignore future messages from peers sending bad signatures. - return false; - } - true - }); - let sig_range = self - .received_partial_sigs - .range(sig_bounds) - .flat_map(|(_, sigs)| sigs); - sig = match ThresholdBls12381MinSig::aggregate(self.aggregation_threshold, sig_range) { - Ok(sig) => sig, - Err(fastcrypto::error::FastCryptoError::NotEnoughInputs) => return, /* wait for more input */ - Err(e) => { - error!("error while aggregating randomness partial signatures: {e:?}"); - return; - } - }; - if let Err(e) = - ThresholdBls12381MinSig::verify(vss_pk.c0(), &round.signature_message(), &sig) - { - error!( - "error while verifying randomness partial signatures after removing invalid partials: {e:?}" - ); - debug_assert!( - false, - "error while verifying randomness partial signatures after removing invalid partials" - ); - return; - } - } - - debug!("successfully generated randomness full signature"); - self.completed_sigs.insert((epoch, round)); - self.metrics.record_completed_round(round); - if let Some(start_time) = self.round_request_time.get(&(epoch, round)) { - if let Some(metric) = self.metrics.round_generation_latency_metric() { - metric.observe(start_time.elapsed().as_secs_f64()); - } - } - - let keys_to_remove: Vec<_> = self - .received_partial_sigs - .range(sig_bounds) - .map(|(key, _)| *key) - .collect(); - for key in keys_to_remove { - // Have to remove keys one-by-one because BTreeMap does not support - // range-removal. - self.received_partial_sigs.remove(&key); - } - - let bytes = bcs::to_bytes(&sig).expect("signature serialization should not fail"); - self.randomness_tx - .try_send((epoch, round, bytes)) - .expect("RandomnessRoundReceiver mailbox should not overflow or be closed"); - } - - fn maybe_start_pending_tasks(&mut self) { - let dkg_output = if let Some(dkg_output) = &self.dkg_output { - dkg_output - } else { - return; // can't start tasks until first DKG completes - }; - let shares = if let Some(shares) = &dkg_output.shares { - shares - } else { - return; // can't participate in randomness generation without shares - }; - - let mut last_handled_key = None; - let mut rounds_to_aggregate = Vec::new(); - for (epoch, round) in &self.pending_tasks { - if epoch > &self.epoch { - break; // wait for DKG in new epoch - } - - if self.send_tasks.len() >= self.config.max_partial_sigs_concurrent_sends() { - break; // limit concurrent tasks - } - - last_handled_key = Some((*epoch, *round)); - - if epoch < &self.epoch { - info!( - "skipping sending partial sigs for epoch {epoch} round {round}, we are already up to epoch {}", - self.epoch - ); - continue; - } - - if self.completed_rounds.contains(&(*epoch, *round)) { - info!( - "skipping sending partial sigs for epoch {epoch} round {round}, we already have completed this round", - ); - continue; - } - - self.send_tasks.entry((*epoch, *round)).or_insert_with(|| { - let name = self.name; - let network = self.network.clone(); - let retry_interval = self.config.partial_signature_retry_interval(); - let metrics = self.metrics.clone(); - let authority_info = self.authority_info.clone(); - let epoch = *epoch; - let round = *round; - let partial_sigs = ThresholdBls12381MinSig::partial_sign_batch( - shares.iter(), - &round.signature_message(), - ); - - // Record own partial sigs. - if !self.completed_sigs.contains(&(epoch, round)) { - self.received_partial_sigs - .insert((epoch, round, self.network.peer_id()), partial_sigs.clone()); - rounds_to_aggregate.push((epoch, round)); - } - - debug!("sending partial sigs for epoch {epoch}, round {round}"); - spawn_monitored_task!(RandomnessEventLoop::send_partial_signatures_task( - name, - network, - retry_interval, - metrics, - authority_info, - epoch, - round, - partial_sigs - )) - }); - } - - if let Some(last_handled_key) = last_handled_key { - // Remove stuff from the pending_tasks map that we've handled. - let split_point = self - .pending_tasks - .range((Bound::Excluded(last_handled_key), Bound::Unbounded)) - .next() - .cloned(); - if let Some(key) = split_point { - self.pending_tasks = self.pending_tasks.split_off(&key); - } else { - self.pending_tasks.clear(); - } - } - self.update_rounds_pending_metric(); - - // After starting a round, we have generated our own partial sigs. Check if - // that's enough for us to aggregate already. - for (epoch, round) in rounds_to_aggregate { - self.maybe_aggregate_partial_signatures(epoch, round); - } - } - - async fn send_partial_signatures_task( - name: AuthorityName, - network: anemo::Network, - retry_interval: Duration, - metrics: Metrics, - authority_info: Arc>, - epoch: EpochId, - round: RandomnessRound, - partial_sigs: Vec, - ) { - let _metrics_guard = metrics - .round_observation_latency_metric() - .map(|metric| metric.start_timer()); - - let peers: HashMap<_, _> = authority_info - .iter() - .map(|(name, (peer_id, _party_id))| (name, network.waiting_peer(*peer_id))) - .collect(); - let partial_sigs: Vec<_> = partial_sigs - .iter() - .map(|sig| bcs::to_bytes(sig).expect("message serialization should not fail")) - .collect(); - - loop { - let mut requests = Vec::new(); - for (peer_name, peer) in &peers { - if name == **peer_name { - continue; // don't send partial sigs to self - } - let mut client = RandomnessClient::new(peer.clone()); - const SEND_PARTIAL_SIGNATURES_TIMEOUT: Duration = Duration::from_secs(10); - let request = anemo::Request::new(SendSignaturesRequest { - epoch, - round, - partial_sigs: partial_sigs.clone(), - sig: None, - }) - .with_timeout(SEND_PARTIAL_SIGNATURES_TIMEOUT); - requests.push(async move { - let result = client.send_signatures(request).await; - if let Err(e) = result { - debug!("failed to send partial signatures to {peer_name}: {e:?}"); - } - }); - } - - // Process all requests. - futures::future::join_all(requests).await; - - // Keep retrying send to all peers until task is aborted via external message. - tokio::time::sleep(retry_interval).await; - } - } - - fn update_rounds_pending_metric(&self) { - self.metrics - .set_num_rounds_pending(self.pending_tasks.len() + self.send_tasks.len()); - } -} diff --git a/crates/sui-network/src/randomness/server.rs b/crates/sui-network/src/randomness/server.rs deleted file mode 100644 index dc493a562f1..00000000000 --- a/crates/sui-network/src/randomness/server.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use anemo::{Request, Response}; -use tokio::sync::mpsc; - -use super::{Randomness, RandomnessMessage, SendSignaturesRequest}; - -pub(super) struct Server { - pub(super) sender: mpsc::WeakSender, -} - -#[anemo::async_trait] -impl Randomness for Server { - async fn send_signatures( - &self, - request: Request, - ) -> Result, anemo::rpc::Status> { - let sender = self - .sender - .upgrade() - .ok_or_else(|| anemo::rpc::Status::internal("shutting down"))?; - let peer_id = *request - .peer_id() - .ok_or_else(|| anemo::rpc::Status::internal("missing peer ID"))?; - let SendSignaturesRequest { - epoch, - round, - partial_sigs, - sig: _, - } = request.into_inner(); - let _ = sender // throw away error, caller will retry - .send(RandomnessMessage::ReceivePartialSignatures( - peer_id, - epoch, - round, - partial_sigs, - )) - .await; - Ok(anemo::Response::new(())) - } -} diff --git a/crates/sui-network/src/randomness/tests.rs b/crates/sui-network/src/randomness/tests.rs deleted file mode 100644 index 9c7ec25032e..00000000000 --- a/crates/sui-network/src/randomness/tests.rs +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use fastcrypto::{groups::bls12381, serde_helpers::ToFromByteArray}; -use fastcrypto_tbls::{mocked_dkg, nodes}; -use sui_swarm_config::test_utils::CommitteeFixture; -use sui_types::{ - base_types::ConciseableName, - committee::Committee, - crypto::{AuthorityPublicKeyBytes, ToFromBytes}, -}; -use tracing::Instrument; - -use crate::{randomness::*, utils}; - -type PkG = bls12381::G2Element; -type EncG = bls12381::G2Element; - -#[tokio::test] -async fn test_multiple_epochs() { - telemetry_subscribers::init_for_testing(); - let committee_fixture = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); - let committee = committee_fixture.committee(); - - let mut randomness_rxs = Vec::new(); - let mut networks: Vec = Vec::new(); - let mut nodes = Vec::new(); - let mut handles = Vec::new(); - let mut authority_info = HashMap::new(); - - for (authority, stake) in committee.members() { - let (tx, rx) = mpsc::channel(3); - randomness_rxs.push(rx); - let (unstarted, router) = Builder::new(*authority, tx).build(); - - let network = utils::build_network(|r| r.merge(router)); - for n in networks.iter() { - network.connect(n.local_addr()).await.unwrap(); - } - networks.push(network.clone()); - - let node = node_from_committee(committee, authority, *stake); - authority_info.insert(*authority, (network.peer_id(), node.id)); - nodes.push(node); - - let (r, handle) = unstarted.build(network); - handles.push((authority, handle)); - - let span = tracing::span!( - tracing::Level::INFO, - "RandomnessEventLoop", - authority = ?authority.concise(), - ); - tokio::spawn(r.start().instrument(span)); - } - info!(?authority_info, "authorities constructed"); - - let nodes = nodes::Nodes::new(nodes).unwrap(); - - // Test first round. - for (authority, handle) in handles.iter() { - let mock_dkg_output = mocked_dkg::generate_mocked_output::( - nodes.clone(), - committee.validity_threshold().try_into().unwrap(), - 0, - committee - .authority_index(authority) - .unwrap() - .try_into() - .unwrap(), - ); - handle.send_partial_signatures(0, RandomnessRound(0)); - handle.update_epoch( - 0, - authority_info.clone(), - mock_dkg_output, - committee.validity_threshold().try_into().unwrap(), - ); - } - for rx in randomness_rxs.iter_mut() { - let (epoch, round, bytes) = rx.recv().await.unwrap(); - assert_eq!(0, epoch); - assert_eq!(0, round.0); - assert_ne!(0, bytes.len()); - } - - // Test a few more rounds. Generation of rounds in epoch 1 should block until - // epoch is updated. - for (_authority, handle) in handles.iter() { - handle.complete_round(0, RandomnessRound(0)); - handle.send_partial_signatures(0, RandomnessRound(1)); - handle.send_partial_signatures(1, RandomnessRound(0)); - handle.send_partial_signatures(1, RandomnessRound(1)); - } - for rx in randomness_rxs.iter_mut() { - let (epoch, round, bytes) = rx.recv().await.unwrap(); - assert_eq!(0, epoch); - assert_eq!(1, round.0); - assert_ne!(0, bytes.len()); - assert!(rx.try_recv().is_err()); // there should not be anything else ready yet - } - for (authority, handle) in handles.iter() { - // update to epoch 1 - let mock_dkg_output = mocked_dkg::generate_mocked_output::( - nodes.clone(), - committee.validity_threshold().try_into().unwrap(), - 1, - committee - .authority_index(authority) - .unwrap() - .try_into() - .unwrap(), - ); - handle.update_epoch( - 1, - authority_info.clone(), - mock_dkg_output, - committee.validity_threshold().try_into().unwrap(), - ); - } - let mut rounds_seen = BTreeSet::new(); // use a set because rounds could be generated out-of-order - for rx in randomness_rxs.iter_mut() { - // now we expect the two rounds we started earlier to be generated - let (epoch, round, bytes) = rx.recv().await.unwrap(); - assert_eq!(1, epoch); - rounds_seen.insert(round); - assert_ne!(0, bytes.len()); - let (epoch, round, bytes) = rx.recv().await.unwrap(); - assert_eq!(1, epoch); - rounds_seen.insert(round); - assert_ne!(0, bytes.len()); - } - assert!(rounds_seen.contains(&RandomnessRound(0))); - assert!(rounds_seen.contains(&RandomnessRound(1))); -} - -#[tokio::test] -async fn test_record_own_partial_sigs() { - telemetry_subscribers::init_for_testing(); - let committee_fixture = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); - let committee = committee_fixture.committee(); - - let mut randomness_rxs = Vec::new(); - let mut networks: Vec = Vec::new(); - let mut nodes = Vec::new(); - let mut handles = Vec::new(); - let mut authority_info = HashMap::new(); - - for (authority, stake) in committee.members() { - let (tx, rx) = mpsc::channel(3); - randomness_rxs.push(rx); - let (unstarted, router) = Builder::new(*authority, tx).build(); - - let network = utils::build_network(|r| r.merge(router)); - for n in networks.iter() { - network.connect(n.local_addr()).await.unwrap(); - } - networks.push(network.clone()); - - let node = node_from_committee(committee, authority, *stake); - authority_info.insert(*authority, (network.peer_id(), node.id)); - nodes.push(node); - - let (r, handle) = unstarted.build(network); - handles.push((authority, handle)); - - let span = tracing::span!( - tracing::Level::INFO, - "RandomnessEventLoop", - authority = ?authority.concise(), - ); - tokio::spawn(r.start().instrument(span)); - } - info!(?authority_info, "authorities constructed"); - - let nodes = nodes::Nodes::new(nodes).unwrap(); - - // Only send partial sigs from authorities 0 and 1. They should still be able to - // reach the threshold to generate full signatures, only if they are - // correctly recording and using their own partial signatures as well. - for (authority, handle) in handles.iter().take(2) { - let mock_dkg_output = mocked_dkg::generate_mocked_output::( - nodes.clone(), - committee.validity_threshold().try_into().unwrap(), - 0, - committee - .authority_index(authority) - .unwrap() - .try_into() - .unwrap(), - ); - handle.send_partial_signatures(0, RandomnessRound(0)); - handle.update_epoch( - 0, - authority_info.clone(), - mock_dkg_output, - committee.validity_threshold().try_into().unwrap(), - ); - } - for (i, rx) in randomness_rxs.iter_mut().enumerate() { - if i < 2 { - let (epoch, round, bytes) = rx.recv().await.unwrap(); - assert_eq!(0, epoch); - assert_eq!(0, round.0); - assert_ne!(0, bytes.len()); - } else { - assert!(rx.try_recv().is_err()); - } - } -} - -fn node_from_committee( - committee: &Committee, - authority: &AuthorityPublicKeyBytes, - stake: u64, -) -> nodes::Node { - let id = committee - .authority_index(authority) - .unwrap() - .try_into() - .unwrap(); - let pk = bls12381::G2Element::from_byte_array( - committee - .public_key(authority) - .expect("lookup of known committee member should succeed") - .as_bytes() - .try_into() - .expect("key length should match"), - ) - .expect("should work to convert BLS key to G2Element"); - fastcrypto_tbls::nodes::Node:: { - id, - pk: fastcrypto_tbls::ecies::PublicKey::from(pk), - weight: stake.try_into().unwrap(), - } -} diff --git a/crates/sui-network/src/state_sync/builder.rs b/crates/sui-network/src/state_sync/builder.rs deleted file mode 100644 index e43fd31c4c0..00000000000 --- a/crates/sui-network/src/state_sync/builder.rs +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::HashMap, - sync::{Arc, RwLock}, - time::Duration, -}; - -use anemo::codegen::InboundRequestLayer; -use anemo_tower::{inflight_limit, rate_limit}; -use sui_archival::reader::ArchiveReaderBalancer; -use sui_config::p2p::StateSyncConfig; -use sui_types::{messages_checkpoint::VerifiedCheckpoint, storage::WriteStore}; -use tap::Pipe; -use tokio::{ - sync::{broadcast, mpsc}, - task::JoinSet, -}; - -use super::{ - metrics::Metrics, - server::{CheckpointContentsDownloadLimitLayer, Server}, - Handle, PeerHeights, StateSync, StateSyncEventLoop, StateSyncMessage, StateSyncServer, -}; - -pub struct Builder { - store: Option, - config: Option, - metrics: Option, - archive_readers: Option, -} - -impl Builder<()> { - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - Self { - store: None, - config: None, - metrics: None, - archive_readers: None, - } - } -} - -impl Builder { - pub fn store(self, store: NewStore) -> Builder { - Builder { - store: Some(store), - config: self.config, - metrics: self.metrics, - archive_readers: self.archive_readers, - } - } - - pub fn config(mut self, config: StateSyncConfig) -> Self { - self.config = Some(config); - self - } - - pub fn with_metrics(mut self, registry: &prometheus::Registry) -> Self { - self.metrics = Some(Metrics::enabled(registry)); - self - } - - pub fn archive_readers(mut self, archive_readers: ArchiveReaderBalancer) -> Self { - self.archive_readers = Some(archive_readers); - self - } -} - -impl Builder -where - S: WriteStore + Clone + Send + Sync + 'static, -{ - pub fn build(self) -> (UnstartedStateSync, StateSyncServer) { - let state_sync_config = self.config.clone().unwrap_or_default(); - let (mut builder, server) = self.build_internal(); - let mut state_sync_server = StateSyncServer::new(server); - - // Apply rate limits from configuration as needed. - if let Some(limit) = state_sync_config.push_checkpoint_summary_rate_limit { - state_sync_server = state_sync_server.add_layer_for_push_checkpoint_summary( - InboundRequestLayer::new(rate_limit::RateLimitLayer::new( - governor::Quota::per_second(limit), - rate_limit::WaitMode::Block, - )), - ); - } - if let Some(limit) = state_sync_config.get_checkpoint_summary_rate_limit { - state_sync_server = state_sync_server.add_layer_for_get_checkpoint_summary( - InboundRequestLayer::new(rate_limit::RateLimitLayer::new( - governor::Quota::per_second(limit), - rate_limit::WaitMode::Block, - )), - ); - } - if let Some(limit) = state_sync_config.get_checkpoint_contents_rate_limit { - state_sync_server = state_sync_server.add_layer_for_get_checkpoint_contents( - InboundRequestLayer::new(rate_limit::RateLimitLayer::new( - governor::Quota::per_second(limit), - rate_limit::WaitMode::Block, - )), - ); - } - if let Some(limit) = state_sync_config.get_checkpoint_contents_inflight_limit { - state_sync_server = state_sync_server.add_layer_for_get_checkpoint_contents( - InboundRequestLayer::new(inflight_limit::InflightLimitLayer::new( - limit, - inflight_limit::WaitMode::ReturnError, - )), - ); - } - if let Some(limit) = state_sync_config.get_checkpoint_contents_per_checkpoint_limit { - let layer = CheckpointContentsDownloadLimitLayer::new(limit); - builder.download_limit_layer = Some(layer.clone()); - state_sync_server = state_sync_server - .add_layer_for_get_checkpoint_contents(InboundRequestLayer::new(layer)); - } - - (builder, state_sync_server) - } - - pub(super) fn build_internal(self) -> (UnstartedStateSync, Server) { - let Builder { - store, - config, - metrics, - archive_readers, - } = self; - let store = store.unwrap(); - let config = config.unwrap_or_default(); - let metrics = metrics.unwrap_or_else(Metrics::disabled); - let archive_readers = archive_readers.unwrap_or_default(); - - let (sender, mailbox) = mpsc::channel(config.mailbox_capacity()); - let (checkpoint_event_sender, _receiver) = - broadcast::channel(config.synced_checkpoint_broadcast_channel_capacity()); - let weak_sender = sender.downgrade(); - let handle = Handle { - sender, - checkpoint_event_sender: checkpoint_event_sender.clone(), - }; - let peer_heights = PeerHeights { - peers: HashMap::new(), - unprocessed_checkpoints: HashMap::new(), - sequence_number_to_digest: HashMap::new(), - wait_interval_when_no_peer_to_sync_content: Duration::from_secs(10), - } - .pipe(RwLock::new) - .pipe(Arc::new); - - let server = Server { - store: store.clone(), - peer_heights: peer_heights.clone(), - sender: weak_sender, - }; - - ( - UnstartedStateSync { - config, - handle, - mailbox, - store, - download_limit_layer: None, - peer_heights, - checkpoint_event_sender, - metrics, - archive_readers, - }, - server, - ) - } -} - -pub struct UnstartedStateSync { - pub(super) config: StateSyncConfig, - pub(super) handle: Handle, - pub(super) mailbox: mpsc::Receiver, - pub(super) download_limit_layer: Option, - pub(super) store: S, - pub(super) peer_heights: Arc>, - pub(super) checkpoint_event_sender: broadcast::Sender, - pub(super) metrics: Metrics, - pub(super) archive_readers: ArchiveReaderBalancer, -} - -impl UnstartedStateSync -where - S: WriteStore + Clone + Send + Sync + 'static, -{ - pub(super) fn build(self, network: anemo::Network) -> (StateSyncEventLoop, Handle) { - let Self { - config, - handle, - mailbox, - download_limit_layer, - store, - peer_heights, - checkpoint_event_sender, - metrics, - archive_readers, - } = self; - - ( - StateSyncEventLoop { - config, - mailbox, - weak_sender: handle.sender.downgrade(), - tasks: JoinSet::new(), - sync_checkpoint_summaries_task: None, - sync_checkpoint_contents_task: None, - download_limit_layer, - store, - peer_heights, - checkpoint_event_sender, - network, - metrics, - archive_readers, - sync_checkpoint_from_archive_task: None, - }, - handle, - ) - } - - pub fn start(self, network: anemo::Network) -> Handle { - let (event_loop, handle) = self.build(network); - tokio::spawn(event_loop.start()); - - handle - } -} diff --git a/crates/sui-network/src/state_sync/metrics.rs b/crates/sui-network/src/state_sync/metrics.rs deleted file mode 100644 index 17e98e038fb..00000000000 --- a/crates/sui-network/src/state_sync/metrics.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::sync::Arc; - -use mysten_metrics::histogram::Histogram; -use prometheus::{register_int_gauge_with_registry, IntGauge, Registry}; -use sui_types::messages_checkpoint::CheckpointSequenceNumber; -use tap::Pipe; - -#[derive(Clone)] -pub(super) struct Metrics(Option>); - -impl std::fmt::Debug for Metrics { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - fmt.debug_struct("Metrics").finish() - } -} - -impl Metrics { - pub fn enabled(registry: &Registry) -> Self { - Metrics(Some(Inner::new(registry))) - } - - pub fn disabled() -> Self { - Metrics(None) - } - - pub fn set_highest_known_checkpoint(&self, sequence_number: CheckpointSequenceNumber) { - if let Some(inner) = &self.0 { - inner.highest_known_checkpoint.set(sequence_number as i64); - } - } - - pub fn set_highest_verified_checkpoint(&self, sequence_number: CheckpointSequenceNumber) { - if let Some(inner) = &self.0 { - inner - .highest_verified_checkpoint - .set(sequence_number as i64); - } - } - - pub fn set_highest_synced_checkpoint(&self, sequence_number: CheckpointSequenceNumber) { - if let Some(inner) = &self.0 { - inner.highest_synced_checkpoint.set(sequence_number as i64); - } - } - - pub fn checkpoint_summary_age_metric(&self) -> Option<&Histogram> { - if let Some(inner) = &self.0 { - return Some(&inner.checkpoint_summary_age_ms); - } - None - } -} - -struct Inner { - highest_known_checkpoint: IntGauge, - highest_verified_checkpoint: IntGauge, - highest_synced_checkpoint: IntGauge, - checkpoint_summary_age_ms: Histogram, -} - -impl Inner { - pub fn new(registry: &Registry) -> Arc { - Self { - highest_known_checkpoint: register_int_gauge_with_registry!( - "highest_known_checkpoint", - "Highest known checkpoint", - registry - ) - .unwrap(), - - highest_verified_checkpoint: register_int_gauge_with_registry!( - "highest_verified_checkpoint", - "Highest verified checkpoint", - registry - ) - .unwrap(), - - highest_synced_checkpoint: register_int_gauge_with_registry!( - "highest_synced_checkpoint", - "Highest synced checkpoint", - registry - ) - .unwrap(), - - checkpoint_summary_age_ms: Histogram::new_in_registry( - "checkpoint_summary_age_ms", - "Age of checkpoints summaries when they arrive and are verified.", - registry, - ), - } - .pipe(Arc::new) - } -} diff --git a/crates/sui-network/src/state_sync/mod.rs b/crates/sui-network/src/state_sync/mod.rs deleted file mode 100644 index cf3b72bc1d2..00000000000 --- a/crates/sui-network/src/state_sync/mod.rs +++ /dev/null @@ -1,1432 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//! Peer-to-peer data synchronization of checkpoints. -//! -//! This StateSync module is responsible for the synchronization and -//! dissemination of checkpoints and the transactions, and their effects, -//! contained within. This module is *not* responsible for the execution of the -//! transactions included in a checkpoint, that process is left to another -//! component in the system. -//! -//! # High-level Overview of StateSync -//! -//! StateSync discovers new checkpoints via a few different sources: -//! 1. If this node is a Validator, checkpoints will be produced via consensus -//! at which point consensus can notify state-sync of the new checkpoint via -//! [Handle::send_checkpoint]. -//! 2. A peer notifies us of the latest checkpoint which they have synchronized. -//! State-Sync will also periodically query its peers to discover what their -//! latest checkpoint is. -//! -//! We keep track of two different watermarks: -//! * highest_verified_checkpoint - This is the highest checkpoint header that -//! we've locally verified. This indicated that we have in our persistent -//! store (and have verified) all checkpoint headers up to and including this -//! value. -//! * highest_synced_checkpoint - This is the highest checkpoint that we've -//! fully synchronized, meaning we've downloaded and have in our persistent -//! stores all of the transactions, and their effects (but not the objects), -//! for all checkpoints up to and including this point. This is the watermark -//! that is shared with other peers, either via notification or when they -//! query for our latest checkpoint, and is intended to be used as a guarantee -//! of data availability. -//! -//! The `PeerHeights` struct is used to track the highest_synced_checkpoint -//! watermark for all of our peers. -//! -//! When a new checkpoint is discovered, and we've determined that it is higher -//! than our highest_verified_checkpoint, then StateSync will kick off a task to -//! synchronize and verify all checkpoints between our highest_synced_checkpoint -//! and the newly discovered checkpoint. This process is done by querying one of -//! our peers for the checkpoints we're missing (using the `PeerHeights` struct -//! as a way to intelligently select which peers have the data available for -//! us to query) at which point we will locally verify the signatures on the -//! checkpoint header with the appropriate committee (based on the epoch). As -//! checkpoints are verified, the highest_synced_checkpoint watermark will be -//! ratcheted up. -//! -//! Once we've ratcheted up our highest_verified_checkpoint, and if it is higher -//! than highest_synced_checkpoint, StateSync will then kick off a task to -//! synchronize the contents of all of the checkpoints from -//! highest_synced_checkpoint..=highest_verified_checkpoint. After the -//! contents of each checkpoint is fully downloaded, StateSync will update our -//! highest_synced_checkpoint watermark and send out a notification on a -//! broadcast channel indicating that a new checkpoint has been fully -//! downloaded. Notifications on this broadcast channel will always be made in -//! order. StateSync will also send out a notification to its peers of the newly -//! synchronized checkpoint so that it can help other peers synchronize. - -use std::{ - collections::{HashMap, VecDeque}, - sync::{ - atomic::{AtomicU64, Ordering}, - Arc, RwLock, - }, - time::Duration, -}; - -use anemo::{types::PeerEvent, PeerId, Request, Response, Result}; -use futures::{stream::FuturesOrdered, FutureExt, StreamExt}; -use rand::Rng; -use sui_config::p2p::StateSyncConfig; -use sui_types::{ - committee::Committee, - digests::CheckpointDigest, - messages_checkpoint::{ - CertifiedCheckpointSummary as Checkpoint, CheckpointSequenceNumber, EndOfEpochData, - FullCheckpointContents, VerifiedCheckpoint, VerifiedCheckpointContents, - }, - storage::WriteStore, -}; -use tap::{Pipe, TapFallible, TapOptional}; -use tokio::{ - sync::{broadcast, mpsc, oneshot, watch}, - task::{AbortHandle, JoinSet}, -}; -use tracing::{debug, info, instrument, trace, warn}; - -mod generated { - include!(concat!(env!("OUT_DIR"), "/sui.StateSync.rs")); -} -mod builder; -mod metrics; -mod server; -#[cfg(test)] -mod tests; - -pub use builder::{Builder, UnstartedStateSync}; -pub use generated::{ - state_sync_client::StateSyncClient, - state_sync_server::{StateSync, StateSyncServer}, -}; -pub use server::{GetCheckpointAvailabilityResponse, GetCheckpointSummaryRequest}; -use sui_archival::reader::ArchiveReaderBalancer; -use sui_storage::verify_checkpoint; - -use self::{metrics::Metrics, server::CheckpointContentsDownloadLimitLayer}; - -/// A handle to the StateSync subsystem. -/// -/// This handle can be cloned and shared. Once all copies of a StateSync -/// system's Handle have been dropped, the StateSync system will be gracefully -/// shutdown. -#[derive(Clone, Debug)] -pub struct Handle { - sender: mpsc::Sender, - checkpoint_event_sender: broadcast::Sender, -} - -impl Handle { - /// Send a newly minted checkpoint from Consensus to StateSync so that it - /// can be disseminated to other nodes on the network. - /// - /// # Invariant - /// - /// Consensus must only notify StateSync of new checkpoints that have been - /// fully committed to persistent storage. This includes - /// CheckpointContents and all Transactions and TransactionEffects - /// included therein. - pub async fn send_checkpoint(&self, checkpoint: VerifiedCheckpoint) { - self.sender - .send(StateSyncMessage::VerifiedCheckpoint(Box::new(checkpoint))) - .await - .unwrap() - } - - /// Subscribe to the stream of checkpoints that have been fully synchronized - /// and downloaded. - pub fn subscribe_to_synced_checkpoints(&self) -> broadcast::Receiver { - self.checkpoint_event_sender.subscribe() - } -} - -struct PeerHeights { - /// Table used to track the highest checkpoint for each of our peers. - peers: HashMap, - unprocessed_checkpoints: HashMap, - sequence_number_to_digest: HashMap, - - // The amount of time to wait before retry if there are no peers to sync content from. - wait_interval_when_no_peer_to_sync_content: Duration, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -struct PeerStateSyncInfo { - /// The digest of the Peer's genesis checkpoint. - genesis_checkpoint_digest: CheckpointDigest, - /// Indicates if this Peer is on the same chain as us. - on_same_chain_as_us: bool, - /// Highest checkpoint sequence number we know of for this Peer. - height: CheckpointSequenceNumber, - /// lowest available checkpoint watermark for this Peer. - /// This defaults to 0 for now. - lowest: CheckpointSequenceNumber, -} - -impl PeerHeights { - pub fn highest_known_checkpoint(&self) -> Option<&Checkpoint> { - self.highest_known_checkpoint_sequence_number() - .and_then(|s| self.sequence_number_to_digest.get(&s)) - .and_then(|digest| self.unprocessed_checkpoints.get(digest)) - } - - pub fn highest_known_checkpoint_sequence_number(&self) -> Option { - self.peers - .values() - .filter_map(|info| info.on_same_chain_as_us.then_some(info.height)) - .max() - } - - pub fn peers_on_same_chain(&self) -> impl Iterator { - self.peers - .iter() - .filter(|(_peer_id, info)| info.on_same_chain_as_us) - } - - // Returns a bool that indicates if the update was done successfully. - // - // This will return false if the given peer doesn't have an entry or is not on - // the same chain as us - pub fn update_peer_info( - &mut self, - peer_id: PeerId, - checkpoint: Checkpoint, - low_watermark: Option, - ) -> bool { - let info = match self.peers.get_mut(&peer_id) { - Some(info) if info.on_same_chain_as_us => info, - _ => return false, - }; - - info.height = std::cmp::max(*checkpoint.sequence_number(), info.height); - if let Some(low_watermark) = low_watermark { - info.lowest = low_watermark; - } - self.insert_checkpoint(checkpoint); - - true - } - - pub fn insert_peer_info(&mut self, peer_id: PeerId, info: PeerStateSyncInfo) { - use std::collections::hash_map::Entry; - - match self.peers.entry(peer_id) { - Entry::Occupied(mut entry) => { - // If there's already an entry and the genesis checkpoint digests match then - // update the maximum height. Otherwise we'll use the more - // recent one - let entry = entry.get_mut(); - if entry.genesis_checkpoint_digest == info.genesis_checkpoint_digest { - entry.height = std::cmp::max(entry.height, info.height); - } else { - *entry = info; - } - } - Entry::Vacant(entry) => { - entry.insert(info); - } - } - } - - pub fn mark_peer_as_not_on_same_chain(&mut self, peer_id: PeerId) { - if let Some(info) = self.peers.get_mut(&peer_id) { - info.on_same_chain_as_us = false; - } - } - - pub fn cleanup_old_checkpoints(&mut self, sequence_number: CheckpointSequenceNumber) { - self.unprocessed_checkpoints - .retain(|_digest, checkpoint| *checkpoint.sequence_number() > sequence_number); - self.sequence_number_to_digest - .retain(|&s, _digest| s > sequence_number); - } - - // TODO: also record who gives this checkpoint info for peer quality - // measurement? - pub fn insert_checkpoint(&mut self, checkpoint: Checkpoint) { - let digest = *checkpoint.digest(); - let sequence_number = *checkpoint.sequence_number(); - self.unprocessed_checkpoints.insert(digest, checkpoint); - self.sequence_number_to_digest - .insert(sequence_number, digest); - } - - pub fn remove_checkpoint(&mut self, digest: &CheckpointDigest) { - if let Some(checkpoint) = self.unprocessed_checkpoints.remove(digest) { - self.sequence_number_to_digest - .remove(checkpoint.sequence_number()); - } - } - - pub fn get_checkpoint_by_sequence_number( - &self, - sequence_number: CheckpointSequenceNumber, - ) -> Option<&Checkpoint> { - self.sequence_number_to_digest - .get(&sequence_number) - .and_then(|digest| self.get_checkpoint_by_digest(digest)) - } - - pub fn get_checkpoint_by_digest(&self, digest: &CheckpointDigest) -> Option<&Checkpoint> { - self.unprocessed_checkpoints.get(digest) - } - - #[cfg(test)] - pub fn set_wait_interval_when_no_peer_to_sync_content(&mut self, duration: Duration) { - self.wait_interval_when_no_peer_to_sync_content = duration; - } - - pub fn wait_interval_when_no_peer_to_sync_content(&self) -> Duration { - self.wait_interval_when_no_peer_to_sync_content - } -} - -// PeerBalancer is an Iterator that selects peers based on RTT with some added -// randomness. -#[derive(Clone)] -struct PeerBalancer { - peers: VecDeque<(anemo::Peer, PeerStateSyncInfo)>, - requested_checkpoint: Option, - request_type: PeerCheckpointRequestType, -} - -#[derive(Clone)] -enum PeerCheckpointRequestType { - Summary, - Content, -} - -impl PeerBalancer { - pub fn new( - network: &anemo::Network, - peer_heights: Arc>, - request_type: PeerCheckpointRequestType, - ) -> Self { - let mut peers: Vec<_> = peer_heights - .read() - .unwrap() - .peers_on_same_chain() - // Filter out any peers who we aren't connected with. - .filter_map(|(peer_id, info)| network.peer(*peer_id).map(|peer| (peer, *info))) - .collect(); - peers.sort_by(|(peer_a, _), (peer_b, _)| { - peer_a.connection_rtt().cmp(&peer_b.connection_rtt()) - }); - Self { - peers: peers.into(), - requested_checkpoint: None, - request_type, - } - } - - pub fn with_checkpoint(mut self, checkpoint: CheckpointSequenceNumber) -> Self { - self.requested_checkpoint = Some(checkpoint); - self - } -} - -impl Iterator for PeerBalancer { - type Item = StateSyncClient; - - fn next(&mut self) -> Option { - while !self.peers.is_empty() { - const SELECTION_WINDOW: usize = 2; - let idx = - rand::thread_rng().gen_range(0..std::cmp::min(SELECTION_WINDOW, self.peers.len())); - let (peer, info) = self.peers.remove(idx).unwrap(); - let requested_checkpoint = self.requested_checkpoint.unwrap_or(0); - match &self.request_type { - // Summary will never be pruned - PeerCheckpointRequestType::Summary if info.height >= requested_checkpoint => { - return Some(StateSyncClient::new(peer)); - } - PeerCheckpointRequestType::Content - if info.height >= requested_checkpoint - && info.lowest <= requested_checkpoint => - { - return Some(StateSyncClient::new(peer)); - } - _ => {} - } - } - None - } -} - -#[derive(Clone, Debug)] -enum StateSyncMessage { - StartSyncJob, - // Validators will send this to the StateSyncEventLoop in order to kick off notifying our - // peers of the new checkpoint. - VerifiedCheckpoint(Box), - // Notification that the checkpoint content sync task will send to the event loop in the event - // it was able to successfully sync a checkpoint's contents. If multiple checkpoints were - // synced at the same time, only the highest checkpoint is sent. - SyncedCheckpoint(Box), -} - -struct StateSyncEventLoop { - config: StateSyncConfig, - - mailbox: mpsc::Receiver, - /// Weak reference to our own mailbox - weak_sender: mpsc::WeakSender, - - tasks: JoinSet<()>, - sync_checkpoint_summaries_task: Option, - sync_checkpoint_contents_task: Option, - download_limit_layer: Option, - - store: S, - peer_heights: Arc>, - checkpoint_event_sender: broadcast::Sender, - network: anemo::Network, - metrics: Metrics, - - archive_readers: ArchiveReaderBalancer, - sync_checkpoint_from_archive_task: Option, -} - -impl StateSyncEventLoop -where - S: WriteStore + Clone + Send + Sync + 'static, -{ - // Note: A great deal of care is taken to ensure that all event handlers are - // non-asynchronous and that the only "await" points are from the select - // macro picking which event to handle. This ensures that the event loop is - // able to process events at a high speed and reduce the chance for building - // up a backlog of events to process. - pub async fn start(mut self) { - info!("State-Synchronizer started"); - - self.config.pinned_checkpoints.sort(); - - let mut interval = tokio::time::interval(self.config.interval_period()); - let mut peer_events = { - let (subscriber, peers) = self.network.subscribe().unwrap(); - for peer_id in peers { - self.spawn_get_latest_from_peer(peer_id); - } - subscriber - }; - let ( - target_checkpoint_contents_sequence_sender, - target_checkpoint_contents_sequence_receiver, - ) = watch::channel(0); - - // Spawn tokio task to update metrics periodically in the background - let (_sender, receiver) = oneshot::channel(); - tokio::spawn(update_checkpoint_watermark_metrics( - receiver, - self.store.clone(), - self.metrics.clone(), - )); - - // Start checkpoint contents sync loop. - let task = sync_checkpoint_contents( - self.network.clone(), - self.store.clone(), - self.peer_heights.clone(), - self.weak_sender.clone(), - self.checkpoint_event_sender.clone(), - self.config.checkpoint_content_download_concurrency(), - self.config.checkpoint_content_download_tx_concurrency(), - self.config.checkpoint_content_timeout(), - target_checkpoint_contents_sequence_receiver, - ); - let task_handle = self.tasks.spawn(task); - self.sync_checkpoint_contents_task = Some(task_handle); - - // Start archive based checkpoint content sync loop. - // TODO: Consider switching to sync from archive only on startup. - // Right now because the peer set is fixed at startup, a node may eventually - // end up with peers who have all purged their local state. In such a scenario - // it will be stuck until restart when it ends up with a different set - // of peers. Once the discovery mechanism can dynamically identify and - // connect to other peers on the network, we will rely on sync from - // archive as a fall back. - let task = sync_checkpoint_contents_from_archive( - self.network.clone(), - self.archive_readers.clone(), - self.store.clone(), - self.peer_heights.clone(), - ); - let task_handle = self.tasks.spawn(task); - self.sync_checkpoint_from_archive_task = Some(task_handle); - - // Start main loop. - loop { - tokio::select! { - now = interval.tick() => { - self.handle_tick(now.into_std()); - }, - maybe_message = self.mailbox.recv() => { - // Once all handles to our mailbox have been dropped this - // will yield `None` and we can terminate the event loop - if let Some(message) = maybe_message { - self.handle_message(message); - } else { - break; - } - }, - peer_event = peer_events.recv() => { - self.handle_peer_event(peer_event); - }, - Some(task_result) = self.tasks.join_next() => { - match task_result { - Ok(()) => {}, - Err(e) => { - if e.is_cancelled() { - // avoid crashing on ungraceful shutdown - } else if e.is_panic() { - // propagate panics. - std::panic::resume_unwind(e.into_panic()); - } else { - panic!("task failed: {e}"); - } - }, - }; - - if matches!(&self.sync_checkpoint_contents_task, Some(t) if t.is_finished()) { - panic!("sync_checkpoint_contents task unexpectedly terminated") - } - - if matches!(&self.sync_checkpoint_summaries_task, Some(t) if t.is_finished()) { - self.sync_checkpoint_summaries_task = None; - } - - if matches!(&self.sync_checkpoint_from_archive_task, Some(t) if t.is_finished()) { - panic!("sync_checkpoint_from_archive task unexpectedly terminated") - } - }, - } - - self.maybe_start_checkpoint_summary_sync_task(); - self.maybe_trigger_checkpoint_contents_sync_task( - &target_checkpoint_contents_sequence_sender, - ); - } - - info!("State-Synchronizer ended"); - } - - fn handle_message(&mut self, message: StateSyncMessage) { - debug!("Received message: {:?}", message); - match message { - StateSyncMessage::StartSyncJob => self.maybe_start_checkpoint_summary_sync_task(), - StateSyncMessage::VerifiedCheckpoint(checkpoint) => { - self.handle_checkpoint_from_consensus(checkpoint) - } - // After we've successfully synced a checkpoint we can notify our peers - StateSyncMessage::SyncedCheckpoint(checkpoint) => { - self.spawn_notify_peers_of_checkpoint(*checkpoint) - } - } - } - - // Handle a checkpoint that we received from consensus - #[instrument(level = "debug", skip_all)] - fn handle_checkpoint_from_consensus(&mut self, checkpoint: Box) { - // Always check previous_digest matches in case there is a gap between - // state sync and consensus. - let prev_digest = *self.store.get_checkpoint_by_sequence_number(checkpoint.sequence_number() - 1) - .expect("store operation should not fail") - .unwrap_or_else(|| panic!("Got checkpoint {} from consensus but cannot find checkpoint {} in certified_checkpoints", checkpoint.sequence_number(), checkpoint.sequence_number() - 1)) - .digest(); - if checkpoint.previous_digest != Some(prev_digest) { - panic!( - "Checkpoint {} from consensus has mismatched previous_digest, expected: {:?}, actual: {:?}", - checkpoint.sequence_number(), - Some(prev_digest), - checkpoint.previous_digest - ); - } - - let latest_checkpoint = self - .store - .get_highest_verified_checkpoint() - .expect("store operation should not fail"); - - // If this is an older checkpoint, just ignore it - if latest_checkpoint.sequence_number() >= checkpoint.sequence_number() { - return; - } - - let checkpoint = *checkpoint; - let next_sequence_number = latest_checkpoint.sequence_number().checked_add(1).unwrap(); - if *checkpoint.sequence_number() > next_sequence_number { - debug!( - "consensus sent too new of a checkpoint, expecting: {}, got: {}", - next_sequence_number, - checkpoint.sequence_number() - ); - } - - // Because checkpoint from consensus sends in order, when we have checkpoint n, - // we must have all of the checkpoints before n from either state sync or - // consensus. - #[cfg(debug_assertions)] - { - let _ = (next_sequence_number..=*checkpoint.sequence_number()) - .map(|n| { - let checkpoint = self - .store - .get_checkpoint_by_sequence_number(n) - .expect("store operation should not fail") - .unwrap_or_else(|| panic!("store should contain checkpoint {n}")); - self.store - .get_full_checkpoint_contents(&checkpoint.content_digest) - .expect("store operation should not fail") - .unwrap_or_else(|| { - panic!( - "store should contain checkpoint contents for {:?}", - checkpoint.content_digest - ) - }); - }) - .collect::>(); - } - - // If this is the last checkpoint of a epoch, we need to make sure - // new committee is in store before we verify newer checkpoints in next epoch. - // This could happen before this validator's reconfiguration finishes, because - // state sync does not reconfig. - // TODO: make CheckpointAggregator use WriteStore so we don't need to do this - // committee insertion in two places (only in `insert_checkpoint`). - if let Some(EndOfEpochData { - next_epoch_committee, - .. - }) = checkpoint.end_of_epoch_data.as_ref() - { - let next_committee = next_epoch_committee.iter().cloned().collect(); - let committee = - Committee::new(checkpoint.epoch().checked_add(1).unwrap(), next_committee); - self.store - .insert_committee(committee) - .expect("store operation should not fail"); - } - - self.store - .update_highest_verified_checkpoint(&checkpoint) - .expect("store operation should not fail"); - self.store - .update_highest_synced_checkpoint(&checkpoint) - .expect("store operation should not fail"); - - // We don't care if no one is listening as this is a broadcast channel - let _ = self.checkpoint_event_sender.send(checkpoint.clone()); - - self.spawn_notify_peers_of_checkpoint(checkpoint); - } - - fn handle_peer_event( - &mut self, - peer_event: Result, - ) { - use tokio::sync::broadcast::error::RecvError; - - match peer_event { - Ok(PeerEvent::NewPeer(peer_id)) => { - self.spawn_get_latest_from_peer(peer_id); - } - Ok(PeerEvent::LostPeer(peer_id, _)) => { - self.peer_heights.write().unwrap().peers.remove(&peer_id); - } - - Err(RecvError::Closed) => { - panic!("PeerEvent channel shouldn't be able to be closed"); - } - - Err(RecvError::Lagged(_)) => { - trace!("State-Sync fell behind processing PeerEvents"); - } - } - } - - fn spawn_get_latest_from_peer(&mut self, peer_id: PeerId) { - if let Some(peer) = self.network.peer(peer_id) { - let genesis_checkpoint_digest = *self - .store - .get_checkpoint_by_sequence_number(0) - .expect("store operation should not fail") - .expect("store should contain genesis checkpoint") - .digest(); - let task = get_latest_from_peer( - genesis_checkpoint_digest, - peer, - self.peer_heights.clone(), - self.config.timeout(), - ); - self.tasks.spawn(task); - } - } - - fn handle_tick(&mut self, _now: std::time::Instant) { - let task = query_peers_for_their_latest_checkpoint( - self.network.clone(), - self.peer_heights.clone(), - self.weak_sender.clone(), - self.config.timeout(), - ); - self.tasks.spawn(task); - - if let Some(layer) = self.download_limit_layer.as_ref() { - layer.maybe_prune_map(); - } - } - - fn maybe_start_checkpoint_summary_sync_task(&mut self) { - // Only run one sync task at a time - if self.sync_checkpoint_summaries_task.is_some() { - return; - } - - let highest_processed_checkpoint = self - .store - .get_highest_verified_checkpoint() - .expect("store operation should not fail"); - - let highest_known_checkpoint = self - .peer_heights - .read() - .unwrap() - .highest_known_checkpoint() - .cloned(); - - if Some(highest_processed_checkpoint.sequence_number()) - < highest_known_checkpoint - .as_ref() - .map(|x| x.sequence_number()) - { - // start sync job - let task = sync_to_checkpoint( - self.network.clone(), - self.store.clone(), - self.peer_heights.clone(), - self.metrics.clone(), - self.config.pinned_checkpoints.clone(), - self.config.checkpoint_header_download_concurrency(), - self.config.timeout(), - // The if condition should ensure that this is Some - highest_known_checkpoint.unwrap(), - ) - .map(|result| match result { - Ok(()) => {} - Err(e) => { - debug!("error syncing checkpoint {e}"); - } - }); - let task_handle = self.tasks.spawn(task); - self.sync_checkpoint_summaries_task = Some(task_handle); - } - } - - fn maybe_trigger_checkpoint_contents_sync_task( - &mut self, - target_sequence_channel: &watch::Sender, - ) { - let highest_verified_checkpoint = self - .store - .get_highest_verified_checkpoint() - .expect("store operation should not fail"); - let highest_synced_checkpoint = self - .store - .get_highest_synced_checkpoint() - .expect("store operation should not fail"); - - if highest_verified_checkpoint.sequence_number() - > highest_synced_checkpoint.sequence_number() - // skip if we aren't connected to any peers that can help - && self - .peer_heights - .read() - .unwrap() - .highest_known_checkpoint_sequence_number() - > Some(*highest_synced_checkpoint.sequence_number()) - { - let _ = target_sequence_channel.send_if_modified(|num| { - let new_num = *highest_verified_checkpoint.sequence_number(); - if *num == new_num { - return false; - } - *num = new_num; - true - }); - } - } - - fn spawn_notify_peers_of_checkpoint(&mut self, checkpoint: VerifiedCheckpoint) { - let task = notify_peers_of_checkpoint( - self.network.clone(), - self.peer_heights.clone(), - checkpoint, - self.config.timeout(), - ); - self.tasks.spawn(task); - } -} - -async fn notify_peers_of_checkpoint( - network: anemo::Network, - peer_heights: Arc>, - checkpoint: VerifiedCheckpoint, - timeout: Duration, -) { - let futs = peer_heights - .read() - .unwrap() - .peers_on_same_chain() - // Filter out any peers who we know already have a checkpoint higher than this one - .filter_map(|(peer_id, info)| { - (*checkpoint.sequence_number() > info.height).then_some(peer_id) - }) - // Filter out any peers who we aren't connected with - .flat_map(|peer_id| network.peer(*peer_id)) - .map(StateSyncClient::new) - .map(|mut client| { - let request = Request::new(checkpoint.inner().clone()).with_timeout(timeout); - async move { client.push_checkpoint_summary(request).await } - }) - .collect::>(); - futures::future::join_all(futs).await; -} - -async fn get_latest_from_peer( - our_genesis_checkpoint_digest: CheckpointDigest, - peer: anemo::Peer, - peer_heights: Arc>, - timeout: Duration, -) { - let peer_id = peer.peer_id(); - let mut client = StateSyncClient::new(peer); - - let info = { - let maybe_info = peer_heights.read().unwrap().peers.get(&peer_id).copied(); - - if let Some(info) = maybe_info { - info - } else { - // TODO do we want to create a new API just for querying a node's chainid? - // - // We need to query this node's genesis checkpoint to see if they're on the same - // chain as us - let request = Request::new(GetCheckpointSummaryRequest::BySequenceNumber(0)) - .with_timeout(timeout); - let response = client - .get_checkpoint_summary(request) - .await - .map(Response::into_inner); - - let info = match response { - Ok(Some(checkpoint)) => { - let digest = *checkpoint.digest(); - PeerStateSyncInfo { - genesis_checkpoint_digest: digest, - on_same_chain_as_us: our_genesis_checkpoint_digest == digest, - height: *checkpoint.sequence_number(), - lowest: CheckpointSequenceNumber::default(), - } - } - Ok(None) => PeerStateSyncInfo { - genesis_checkpoint_digest: CheckpointDigest::default(), - on_same_chain_as_us: false, - height: CheckpointSequenceNumber::default(), - lowest: CheckpointSequenceNumber::default(), - }, - Err(status) => { - trace!("get_latest_checkpoint_summary request failed: {status:?}"); - return; - } - }; - peer_heights - .write() - .unwrap() - .insert_peer_info(peer_id, info); - info - } - }; - - // Bail early if this node isn't on the same chain as us - if !info.on_same_chain_as_us { - return; - } - let Some((highest_checkpoint, low_watermark)) = - query_peer_for_latest_info(&mut client, timeout).await - else { - return; - }; - peer_heights - .write() - .unwrap() - .update_peer_info(peer_id, highest_checkpoint, low_watermark); -} - -/// Queries a peer for their highest_synced_checkpoint and low checkpoint -/// watermark -async fn query_peer_for_latest_info( - client: &mut StateSyncClient, - timeout: Duration, -) -> Option<(Checkpoint, Option)> { - let request = Request::new(()).with_timeout(timeout); - let response = client - .get_checkpoint_availability(request) - .await - .map(Response::into_inner); - match response { - Ok(GetCheckpointAvailabilityResponse { - highest_synced_checkpoint, - lowest_available_checkpoint, - }) => { - return Some((highest_synced_checkpoint, Some(lowest_available_checkpoint))); - } - Err(status) => { - // If peer hasn't upgraded they would return 404 NotFound error - if status.status() != anemo::types::response::StatusCode::NotFound { - trace!("get_checkpoint_availability request failed: {status:?}"); - return None; - } - } - }; - - // Then we try the old query - // TODO: remove this once the new feature stabilizes - let request = Request::new(GetCheckpointSummaryRequest::Latest).with_timeout(timeout); - let response = client - .get_checkpoint_summary(request) - .await - .map(Response::into_inner); - match response { - Ok(Some(checkpoint)) => Some((checkpoint, None)), - Ok(None) => None, - Err(status) => { - trace!("get_checkpoint_summary (latest) request failed: {status:?}"); - None - } - } -} - -async fn query_peers_for_their_latest_checkpoint( - network: anemo::Network, - peer_heights: Arc>, - sender: mpsc::WeakSender, - timeout: Duration, -) { - let peer_heights = &peer_heights; - let futs = peer_heights - .read() - .unwrap() - .peers_on_same_chain() - // Filter out any peers who we aren't connected with - .flat_map(|(peer_id, _info)| network.peer(*peer_id)) - .map(|peer| { - let peer_id = peer.peer_id(); - let mut client = StateSyncClient::new(peer); - - async move { - let response = query_peer_for_latest_info(&mut client, timeout).await; - match response { - Some((highest_checkpoint, low_watermark)) => peer_heights - .write() - .unwrap() - .update_peer_info(peer_id, highest_checkpoint.clone(), low_watermark) - .then_some(highest_checkpoint), - None => None, - } - } - }) - .collect::>(); - - let checkpoints = futures::future::join_all(futs).await.into_iter().flatten(); - - let highest_checkpoint = checkpoints.max_by_key(|checkpoint| *checkpoint.sequence_number()); - - let our_highest_checkpoint = peer_heights - .read() - .unwrap() - .highest_known_checkpoint() - .cloned(); - - let _new_checkpoint = match (highest_checkpoint, our_highest_checkpoint) { - (Some(theirs), None) => theirs, - (Some(theirs), Some(ours)) if theirs.sequence_number() > ours.sequence_number() => theirs, - _ => return, - }; - - if let Some(sender) = sender.upgrade() { - let _ = sender.send(StateSyncMessage::StartSyncJob).await; - } -} - -async fn sync_to_checkpoint( - network: anemo::Network, - store: S, - peer_heights: Arc>, - metrics: Metrics, - pinned_checkpoints: Vec<(CheckpointSequenceNumber, CheckpointDigest)>, - checkpoint_header_download_concurrency: usize, - timeout: Duration, - checkpoint: Checkpoint, -) -> Result<()> -where - S: WriteStore, -{ - metrics.set_highest_known_checkpoint(*checkpoint.sequence_number()); - - let mut current = store - .get_highest_verified_checkpoint() - .expect("store operation should not fail"); - if current.sequence_number() >= checkpoint.sequence_number() { - return Err(anyhow::anyhow!( - "target checkpoint {} is older than highest verified checkpoint {}", - checkpoint.sequence_number(), - current.sequence_number(), - )); - } - - let peer_balancer = PeerBalancer::new( - &network, - peer_heights.clone(), - PeerCheckpointRequestType::Summary, - ); - // range of the next sequence_numbers to fetch - let mut request_stream = (current.sequence_number().checked_add(1).unwrap() - ..=*checkpoint.sequence_number()) - .map(|next| { - let peers = peer_balancer.clone().with_checkpoint(next); - let peer_heights = peer_heights.clone(); - let pinned_checkpoints = &pinned_checkpoints; - async move { - if let Some(checkpoint) = peer_heights - .read() - .unwrap() - .get_checkpoint_by_sequence_number(next) - { - return (Some(checkpoint.to_owned()), next, None); - } - - // Iterate through peers trying each one in turn until we're able to - // successfully get the target checkpoint - for mut peer in peers { - let request = Request::new(GetCheckpointSummaryRequest::BySequenceNumber(next)) - .with_timeout(timeout); - if let Some(checkpoint) = peer - .get_checkpoint_summary(request) - .await - .tap_err(|e| trace!("{e:?}")) - .ok() - .and_then(Response::into_inner) - .tap_none(|| trace!("peer unable to help sync")) - { - // peer didn't give us a checkpoint with the height that we requested - if *checkpoint.sequence_number() != next { - tracing::debug!( - "peer returned checkpoint with wrong sequence number: expected {next}, got {}", - checkpoint.sequence_number() - ); - continue; - } - - // peer gave us a checkpoint whose digest does not match pinned digest - let checkpoint_digest = checkpoint.digest(); - if let Ok(pinned_digest_index) = pinned_checkpoints.binary_search_by_key( - checkpoint.sequence_number(), - |(seq_num, _digest)| *seq_num - ) { - if pinned_checkpoints[pinned_digest_index].1 != *checkpoint_digest { - tracing::debug!( - "peer returned checkpoint with digest that does not match pinned digest: expected {:?}, got {:?}", - pinned_checkpoints[pinned_digest_index].1, - checkpoint_digest - ); - continue; - } - } - - // Insert in our store in the event that things fail and we need to retry - peer_heights - .write() - .unwrap() - .insert_checkpoint(checkpoint.clone()); - return (Some(checkpoint), next, Some(peer.inner().peer_id())); - } - } - (None, next, None) - } - }) - .pipe(futures::stream::iter) - .buffered(checkpoint_header_download_concurrency); - - while let Some((maybe_checkpoint, next, maybe_peer_id)) = request_stream.next().await { - assert_eq!( - current - .sequence_number() - .checked_add(1) - .expect("exhausted u64"), - next - ); - - // Verify the checkpoint - let checkpoint = 'cp: { - let checkpoint = maybe_checkpoint.ok_or_else(|| { - anyhow::anyhow!("no peers were able to help sync checkpoint {next}") - })?; - // Skip verification for manually pinned checkpoints. - if pinned_checkpoints - .binary_search_by_key(checkpoint.sequence_number(), |(seq_num, _digest)| *seq_num) - .is_ok() - { - break 'cp VerifiedCheckpoint::new_unchecked(checkpoint); - } - match verify_checkpoint(¤t, &store, checkpoint) { - Ok(verified_checkpoint) => verified_checkpoint, - Err(checkpoint) => { - let mut peer_heights = peer_heights.write().unwrap(); - // Remove the checkpoint from our temporary store so that we can try querying - // another peer for a different one - peer_heights.remove_checkpoint(checkpoint.digest()); - - // Mark peer as not on the same chain as us - if let Some(peer_id) = maybe_peer_id { - peer_heights.mark_peer_as_not_on_same_chain(peer_id); - } - - return Err(anyhow::anyhow!( - "unable to verify checkpoint {checkpoint:?}" - )); - } - } - }; - - debug!(checkpoint_seq = ?checkpoint.sequence_number(), "verified checkpoint summary"); - if let Some(checkpoint_summary_age_metric) = metrics.checkpoint_summary_age_metric() { - checkpoint.report_checkpoint_age_ms(checkpoint_summary_age_metric); - } - - current = checkpoint.clone(); - // Insert the newly verified checkpoint into our store, which will bump our - // highest verified checkpoint watermark as well. - store - .insert_checkpoint(&checkpoint) - .expect("store operation should not fail"); - } - - peer_heights - .write() - .unwrap() - .cleanup_old_checkpoints(*checkpoint.sequence_number()); - - Ok(()) -} - -async fn sync_checkpoint_contents_from_archive( - network: anemo::Network, - archive_readers: ArchiveReaderBalancer, - store: S, - peer_heights: Arc>, -) where - S: WriteStore + Clone + Send + Sync + 'static, -{ - loop { - let peers: Vec<_> = peer_heights - .read() - .unwrap() - .peers_on_same_chain() - // Filter out any peers who we aren't connected with. - .filter_map(|(peer_id, info)| network.peer(*peer_id).map(|peer| (peer, *info))) - .collect(); - let lowest_checkpoint_on_peers = peers - .iter() - .map(|(_p, state_sync_info)| state_sync_info.lowest) - .min(); - let highest_synced = store - .get_highest_synced_checkpoint() - .expect("store operation should not fail") - .sequence_number; - let sync_from_archive = if let Some(lowest_checkpoint_on_peers) = lowest_checkpoint_on_peers - { - highest_synced < lowest_checkpoint_on_peers - } else { - false - }; - if sync_from_archive { - let start = highest_synced - .checked_add(1) - .expect("Checkpoint seq num overflow"); - let checkpoint_range = start..lowest_checkpoint_on_peers.unwrap(); - if let Some(archive_reader) = archive_readers - .pick_one_random(checkpoint_range.clone()) - .await - { - let txn_counter = Arc::new(AtomicU64::new(0)); - let checkpoint_counter = Arc::new(AtomicU64::new(0)); - if let Err(err) = archive_reader - .read( - store.clone(), - checkpoint_range, - txn_counter.clone(), - checkpoint_counter.clone(), - true, - ) - .await - { - warn!("State sync from archive failed with error: {:?}", err); - } else { - info!( - "State sync from archive is complete. Checkpoints downloaded = {:?}, Txns downloaded = {:?}", - checkpoint_counter.load(Ordering::Relaxed), - txn_counter.load(Ordering::Relaxed) - ); - } - } else { - warn!("Failed to find an archive reader to complete the state sync request"); - } - } - tokio::time::sleep(Duration::from_secs(5)).await; - } -} - -async fn sync_checkpoint_contents( - network: anemo::Network, - store: S, - peer_heights: Arc>, - sender: mpsc::WeakSender, - checkpoint_event_sender: broadcast::Sender, - checkpoint_content_download_concurrency: usize, - checkpoint_content_download_tx_concurrency: u64, - timeout: Duration, - mut target_sequence_channel: watch::Receiver, -) where - S: WriteStore + Clone, -{ - let mut highest_synced = store - .get_highest_synced_checkpoint() - .expect("store operation should not fail"); - - let mut current_sequence = highest_synced.sequence_number().checked_add(1).unwrap(); - let mut target_sequence_cursor = 0; - let mut highest_started_network_total_transactions = highest_synced.network_total_transactions; - let mut checkpoint_contents_tasks = FuturesOrdered::new(); - - let mut tx_concurrency_remaining = checkpoint_content_download_tx_concurrency; - - loop { - tokio::select! { - result = target_sequence_channel.changed() => { - match result { - Ok(()) => { - target_sequence_cursor = (*target_sequence_channel.borrow_and_update()).checked_add(1).unwrap(); - } - Err(_) => { - // Watch channel is closed, exit loop. - return - } - } - }, - Some(maybe_checkpoint) = checkpoint_contents_tasks.next() => { - match maybe_checkpoint { - Ok(checkpoint) => { - let _: &VerifiedCheckpoint = &checkpoint; // type hint - - store - .update_highest_synced_checkpoint(&checkpoint) - .expect("store operation should not fail"); - // We don't care if no one is listening as this is a broadcast channel - let _ = checkpoint_event_sender.send(checkpoint.clone()); - tx_concurrency_remaining += checkpoint.network_total_transactions - highest_synced.network_total_transactions; - highest_synced = checkpoint; - - } - Err(checkpoint) => { - let _: &VerifiedCheckpoint = &checkpoint; // type hint - if let Some(lowest_peer_checkpoint) = - peer_heights.read().ok().and_then(|x| x.peers.values().map(|state_sync_info| state_sync_info.lowest).min()) { - if checkpoint.sequence_number() >= &lowest_peer_checkpoint { - info!("unable to sync contents of checkpoint through state sync {} with lowest peer checkpoint: {}", checkpoint.sequence_number(), lowest_peer_checkpoint); - } - } else { - info!("unable to sync contents of checkpoint through state sync {}", checkpoint.sequence_number()); - - } - // Retry contents sync on failure. - checkpoint_contents_tasks.push_front(sync_one_checkpoint_contents( - network.clone(), - &store, - peer_heights.clone(), - timeout, - checkpoint, - )); - } - } - }, - } - - // Start new tasks up to configured concurrency limits. - while current_sequence < target_sequence_cursor - && checkpoint_contents_tasks.len() < checkpoint_content_download_concurrency - { - let next_checkpoint = store - .get_checkpoint_by_sequence_number(current_sequence) - .expect("store operation should not fail") - .expect( - "BUG: store should have all checkpoints older than highest_verified_checkpoint", - ); - - // Enforce transaction count concurrency limit. - let tx_count = next_checkpoint.network_total_transactions - - highest_started_network_total_transactions; - if tx_count > tx_concurrency_remaining { - break; - } - tx_concurrency_remaining -= tx_count; - - highest_started_network_total_transactions = next_checkpoint.network_total_transactions; - current_sequence += 1; - checkpoint_contents_tasks.push_back(sync_one_checkpoint_contents( - network.clone(), - &store, - peer_heights.clone(), - timeout, - next_checkpoint, - )); - } - - if highest_synced.sequence_number() % checkpoint_content_download_concurrency as u64 == 0 - || checkpoint_contents_tasks.is_empty() - { - // Periodically notify event loop to notify our peers that we've synced to a new - // checkpoint height - if let Some(sender) = sender.upgrade() { - let message = StateSyncMessage::SyncedCheckpoint(Box::new(highest_synced.clone())); - let _ = sender.send(message).await; - } - } - } -} - -#[instrument(level = "debug", skip_all, fields(sequence_number = ?checkpoint.sequence_number()))] -async fn sync_one_checkpoint_contents( - network: anemo::Network, - store: S, - peer_heights: Arc>, - timeout: Duration, - checkpoint: VerifiedCheckpoint, -) -> Result -where - S: WriteStore + Clone, -{ - debug!("syncing checkpoint contents"); - - // Check if we already have produced this checkpoint locally. If so, we don't - // need to get it from peers anymore. - if store - .get_highest_synced_checkpoint() - .expect("store operation should not fail") - .sequence_number() - >= checkpoint.sequence_number() - { - debug!("checkpoint was already created via consensus output"); - return Ok(checkpoint); - } - - // Request checkpoint contents from peers. - let peers = PeerBalancer::new( - &network, - peer_heights.clone(), - PeerCheckpointRequestType::Content, - ) - .with_checkpoint(*checkpoint.sequence_number()); - let Some(_contents) = get_full_checkpoint_contents(peers, &store, &checkpoint, timeout).await - else { - // Delay completion in case of error so we don't hammer the network with - // retries. - let duration = peer_heights - .read() - .unwrap() - .wait_interval_when_no_peer_to_sync_content(); - info!("retrying checkpoint sync after {:?}", duration); - tokio::time::sleep(duration).await; - return Err(checkpoint); - }; - debug!("completed checkpoint contents sync"); - Ok(checkpoint) -} - -#[instrument(level = "debug", skip_all)] -async fn get_full_checkpoint_contents( - peers: PeerBalancer, - store: S, - checkpoint: &VerifiedCheckpoint, - timeout: Duration, -) -> Option -where - S: WriteStore, -{ - let digest = checkpoint.content_digest; - if let Some(contents) = store - .get_full_checkpoint_contents_by_sequence_number(*checkpoint.sequence_number()) - .expect("store operation should not fail") - .or_else(|| { - store - .get_full_checkpoint_contents(&digest) - .expect("store operation should not fail") - }) - { - debug!("store already contains checkpoint contents"); - return Some(contents); - } - - // Iterate through our selected peers trying each one in turn until we're able - // to successfully get the target checkpoint - for mut peer in peers { - debug!( - ?timeout, - "requesting checkpoint contents from {}", - peer.inner().peer_id(), - ); - let request = Request::new(digest).with_timeout(timeout); - if let Some(contents) = peer - .get_checkpoint_contents(request) - .await - .tap_err(|e| trace!("{e:?}")) - .ok() - .and_then(Response::into_inner) - .tap_none(|| trace!("peer unable to help sync")) - { - if contents.verify_digests(digest).is_ok() { - let verified_contents = VerifiedCheckpointContents::new_unchecked(contents.clone()); - store - .insert_checkpoint_contents(checkpoint, verified_contents) - .expect("store operation should not fail"); - return Some(contents); - } - } - } - debug!("no peers had checkpoint contents"); - None -} - -async fn update_checkpoint_watermark_metrics( - mut recv: oneshot::Receiver<()>, - store: S, - metrics: Metrics, -) -> Result<()> -where - S: WriteStore + Clone + Send + Sync, -{ - let mut interval = tokio::time::interval(Duration::from_secs(5)); - loop { - tokio::select! { - _now = interval.tick() => { - let highest_verified_checkpoint = store.get_highest_verified_checkpoint() - .expect("store operation should not fail"); - metrics.set_highest_verified_checkpoint(highest_verified_checkpoint.sequence_number); - let highest_synced_checkpoint = store.get_highest_synced_checkpoint() - .expect("store operation should not fail"); - metrics.set_highest_synced_checkpoint(highest_synced_checkpoint.sequence_number); - }, - _ = &mut recv => break, - } - } - Ok(()) -} diff --git a/crates/sui-network/src/state_sync/server.rs b/crates/sui-network/src/state_sync/server.rs deleted file mode 100644 index bec7ca78733..00000000000 --- a/crates/sui-network/src/state_sync/server.rs +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - sync::{Arc, RwLock}, - task::{Context, Poll}, -}; - -use anemo::{rpc::Status, types::response::StatusCode, Request, Response, Result}; -use dashmap::DashMap; -use futures::future::BoxFuture; -use serde::{Deserialize, Serialize}; -use sui_types::{ - digests::{CheckpointContentsDigest, CheckpointDigest}, - messages_checkpoint::{ - CertifiedCheckpointSummary as Checkpoint, CheckpointSequenceNumber, FullCheckpointContents, - VerifiedCheckpoint, - }, - storage::WriteStore, -}; -use tokio::sync::{mpsc, OwnedSemaphorePermit, Semaphore}; - -use super::{PeerHeights, StateSync, StateSyncMessage}; - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum GetCheckpointSummaryRequest { - Latest, - ByDigest(CheckpointDigest), - BySequenceNumber(CheckpointSequenceNumber), -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct GetCheckpointAvailabilityResponse { - pub(crate) highest_synced_checkpoint: Checkpoint, - pub(crate) lowest_available_checkpoint: CheckpointSequenceNumber, -} - -pub(super) struct Server { - pub(super) store: S, - pub(super) peer_heights: Arc>, - pub(super) sender: mpsc::WeakSender, -} - -#[anemo::async_trait] -impl StateSync for Server -where - S: WriteStore + Send + Sync + 'static, -{ - async fn push_checkpoint_summary( - &self, - request: Request, - ) -> Result, Status> { - let peer_id = request - .peer_id() - .copied() - .ok_or_else(|| Status::internal("unable to query sender's PeerId"))?; - - let checkpoint = request.into_inner(); - if !self - .peer_heights - .write() - .unwrap() - .update_peer_info(peer_id, checkpoint.clone(), None) - { - return Ok(Response::new(())); - } - - let highest_verified_checkpoint = *self - .store - .get_highest_verified_checkpoint() - .map_err(|e| Status::internal(e.to_string()))? - .sequence_number(); - - // If this checkpoint is higher than our highest verified checkpoint notify the - // event loop to potentially sync it - if *checkpoint.sequence_number() > highest_verified_checkpoint { - if let Some(sender) = self.sender.upgrade() { - sender.send(StateSyncMessage::StartSyncJob).await.unwrap(); - } - } - - Ok(Response::new(())) - } - - async fn get_checkpoint_summary( - &self, - request: Request, - ) -> Result>, Status> { - let checkpoint = match request.inner() { - GetCheckpointSummaryRequest::Latest => { - self.store.get_highest_synced_checkpoint().map(Some) - } - GetCheckpointSummaryRequest::ByDigest(digest) => { - self.store.get_checkpoint_by_digest(digest) - } - GetCheckpointSummaryRequest::BySequenceNumber(sequence_number) => self - .store - .get_checkpoint_by_sequence_number(*sequence_number), - } - .map_err(|e| Status::internal(e.to_string()))? - .map(VerifiedCheckpoint::into_inner); - - Ok(Response::new(checkpoint)) - } - - async fn get_checkpoint_availability( - &self, - _request: Request<()>, - ) -> Result, Status> { - let highest_synced_checkpoint = self - .store - .get_highest_synced_checkpoint() - .map_err(|e| Status::internal(e.to_string())) - .map(VerifiedCheckpoint::into_inner)?; - let lowest_available_checkpoint = self - .store - .get_lowest_available_checkpoint() - .map_err(|e| Status::internal(e.to_string()))?; - - Ok(Response::new(GetCheckpointAvailabilityResponse { - highest_synced_checkpoint, - lowest_available_checkpoint, - })) - } - - async fn get_checkpoint_contents( - &self, - request: Request, - ) -> Result>, Status> { - let contents = self - .store - .get_full_checkpoint_contents(request.inner()) - .map_err(|e| Status::internal(e.to_string()))?; - Ok(Response::new(contents)) - } -} - -/// [`Layer`] for adding a per-checkpoint limit to the number of inflight -/// GetCheckpointContent requests. -#[derive(Clone)] -pub(super) struct CheckpointContentsDownloadLimitLayer { - inflight_per_checkpoint: Arc>>, - max_inflight_per_checkpoint: usize, -} - -impl CheckpointContentsDownloadLimitLayer { - pub(super) fn new(max_inflight_per_checkpoint: usize) -> Self { - Self { - inflight_per_checkpoint: Arc::new(DashMap::new()), - max_inflight_per_checkpoint, - } - } - - pub(super) fn maybe_prune_map(&self) { - const PRUNE_THRESHOLD: usize = 5000; - if self.inflight_per_checkpoint.len() >= PRUNE_THRESHOLD { - self.inflight_per_checkpoint.retain(|_, semaphore| { - semaphore.available_permits() < self.max_inflight_per_checkpoint - }); - } - } -} - -impl tower::layer::Layer for CheckpointContentsDownloadLimitLayer { - type Service = CheckpointContentsDownloadLimit; - - fn layer(&self, inner: S) -> Self::Service { - CheckpointContentsDownloadLimit { - inner, - inflight_per_checkpoint: self.inflight_per_checkpoint.clone(), - max_inflight_per_checkpoint: self.max_inflight_per_checkpoint, - } - } -} - -/// Middleware for adding a per-checkpoint limit to the number of inflight -/// GetCheckpointContent requests. -#[derive(Clone)] -pub(super) struct CheckpointContentsDownloadLimit { - inner: S, - inflight_per_checkpoint: Arc>>, - max_inflight_per_checkpoint: usize, -} - -impl tower::Service> for CheckpointContentsDownloadLimit -where - S: tower::Service< - Request, - Response = Response>, - Error = Status, - > - + 'static - + Clone - + Send, - >>::Future: Send, - Request: 'static + Send + Sync, -{ - type Response = Response>; - type Error = S::Error; - type Future = BoxFuture<'static, Result>; - - #[inline] - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, req: Request) -> Self::Future { - let inflight_per_checkpoint = self.inflight_per_checkpoint.clone(); - let max_inflight_per_checkpoint = self.max_inflight_per_checkpoint; - let mut inner = self.inner.clone(); - - let fut = async move { - let semaphore = { - let semaphore_entry = inflight_per_checkpoint - .entry(*req.body()) - .or_insert_with(|| Arc::new(Semaphore::new(max_inflight_per_checkpoint))); - semaphore_entry.value().clone() - }; - let permit = semaphore.try_acquire_owned().map_err(|e| match e { - tokio::sync::TryAcquireError::Closed => { - anemo::rpc::Status::new(StatusCode::InternalServerError) - } - tokio::sync::TryAcquireError::NoPermits => { - anemo::rpc::Status::new(StatusCode::TooManyRequests) - } - })?; - - struct SemaphoreExtension(OwnedSemaphorePermit); - inner.call(req).await.map(move |mut response| { - // Insert permit as extension so it's not dropped until the response is sent. - response.extensions_mut().insert(SemaphoreExtension(permit)); - response - }) - }; - Box::pin(fut) - } -} diff --git a/crates/sui-network/src/state_sync/tests.rs b/crates/sui-network/src/state_sync/tests.rs deleted file mode 100644 index 9354a5f33e2..00000000000 --- a/crates/sui-network/src/state_sync/tests.rs +++ /dev/null @@ -1,927 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::HashMap, num::NonZeroUsize, time::Duration}; - -use anemo::{PeerId, Request}; -use anyhow::anyhow; -use prometheus::Registry; -use sui_archival::{reader::ArchiveReaderBalancer, writer::ArchiveWriter}; -use sui_config::{ - node::ArchiveReaderConfig, - object_storage_config::{ObjectStoreConfig, ObjectStoreType}, -}; -use sui_storage::{FileCompression, StorageFormat}; -use sui_swarm_config::test_utils::{empty_contents, CommitteeFixture}; -use sui_types::{ - messages_checkpoint::CheckpointDigest, - storage::{ReadStore, SharedInMemoryStore, WriteStore}, -}; -use tempfile::tempdir; -use tokio::time::{timeout, Instant}; - -use crate::{ - state_sync::{ - Builder, GetCheckpointSummaryRequest, PeerStateSyncInfo, StateSync, StateSyncMessage, - UnstartedStateSync, - }, - utils::build_network, -}; - -#[tokio::test] -async fn server_push_checkpoint() { - let committee = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); - let (ordered_checkpoints, _, _sequence_number_to_digest, _checkpoints) = - committee.make_empty_checkpoints(2, None); - let store = SharedInMemoryStore::default(); - store.inner_mut().insert_genesis_state( - ordered_checkpoints.first().cloned().unwrap(), - empty_contents(), - committee.committee().to_owned(), - ); - - let ( - UnstartedStateSync { - handle: _handle, - mut mailbox, - peer_heights, - .. - }, - server, - ) = Builder::new().store(store).build_internal(); - let peer_id = PeerId([9; 32]); // fake PeerId - - peer_heights.write().unwrap().peers.insert( - peer_id, - PeerStateSyncInfo { - genesis_checkpoint_digest: *ordered_checkpoints[0].digest(), - on_same_chain_as_us: true, - height: 0, - lowest: 0, - }, - ); - - let checkpoint = ordered_checkpoints[1].inner().to_owned(); - let request = Request::new(checkpoint.clone()).with_extension(peer_id); - server.push_checkpoint_summary(request).await.unwrap(); - - assert_eq!( - peer_heights.read().unwrap().peers.get(&peer_id), - Some(&PeerStateSyncInfo { - genesis_checkpoint_digest: *ordered_checkpoints[0].digest(), - on_same_chain_as_us: true, - height: 1, - lowest: 0, - }) - ); - assert_eq!( - peer_heights - .read() - .unwrap() - .unprocessed_checkpoints - .get(checkpoint.digest()) - .unwrap() - .data(), - checkpoint.data(), - ); - assert_eq!( - peer_heights - .read() - .unwrap() - .highest_known_checkpoint() - .unwrap() - .data(), - checkpoint.data(), - ); - assert!(matches!( - mailbox.try_recv().unwrap(), - StateSyncMessage::StartSyncJob - )); -} - -#[tokio::test] -async fn server_get_checkpoint() { - let committee = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); - let (ordered_checkpoints, _, _sequence_number_to_digest, _checkpoints) = - committee.make_empty_checkpoints(3, None); - - let (builder, server) = Builder::new() - .store(SharedInMemoryStore::default()) - .build_internal(); - - builder.store.inner_mut().insert_genesis_state( - ordered_checkpoints.first().cloned().unwrap(), - empty_contents(), - committee.committee().to_owned(), - ); - - // Requests for the Latest checkpoint should return the genesis checkpoint - let response = server - .get_checkpoint_summary(Request::new(GetCheckpointSummaryRequest::Latest)) - .await - .unwrap() - .into_inner(); - assert_eq!( - response.unwrap().data(), - ordered_checkpoints.first().unwrap().data(), - ); - - // Requests for checkpoints that aren't in the server's store - let requests = [ - GetCheckpointSummaryRequest::BySequenceNumber(9), - GetCheckpointSummaryRequest::ByDigest(CheckpointDigest::new([10; 32])), - ]; - for request in requests { - let response = server - .get_checkpoint_summary(Request::new(request)) - .await - .unwrap() - .into_inner(); - assert!(response.is_none()); - } - - // Populate the node's store with some checkpoints - for checkpoint in ordered_checkpoints.clone() { - builder.store.inner_mut().insert_checkpoint(&checkpoint) - } - let latest = ordered_checkpoints.last().unwrap().clone(); - builder - .store - .inner_mut() - .update_highest_synced_checkpoint(&latest); - - let request = Request::new(GetCheckpointSummaryRequest::Latest); - let response = server - .get_checkpoint_summary(request) - .await - .unwrap() - .into_inner() - .unwrap(); - assert_eq!(response.data(), latest.data()); - - for checkpoint in ordered_checkpoints { - let request = Request::new(GetCheckpointSummaryRequest::ByDigest(*checkpoint.digest())); - let response = server - .get_checkpoint_summary(request) - .await - .unwrap() - .into_inner() - .unwrap(); - assert_eq!(response.data(), checkpoint.data()); - - let request = Request::new(GetCheckpointSummaryRequest::BySequenceNumber( - *checkpoint.sequence_number(), - )); - let response = server - .get_checkpoint_summary(request) - .await - .unwrap() - .into_inner() - .unwrap(); - assert_eq!(response.data(), checkpoint.data()); - } -} - -#[tokio::test] -async fn isolated_sync_job() { - let committee = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); - // build mock data - let (ordered_checkpoints, _, sequence_number_to_digest, checkpoints) = - committee.make_empty_checkpoints(100, None); - - // Build and connect two nodes - let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); - let network_1 = build_network(|router| router.add_rpc_service(server)); - let (mut event_loop_1, _handle_1) = builder.build(network_1.clone()); - let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); - let network_2 = build_network(|router| router.add_rpc_service(server)); - let (event_loop_2, _handle_2) = builder.build(network_2.clone()); - network_1.connect(network_2.local_addr()).await.unwrap(); - - // Init the root committee in both nodes - event_loop_1.store.inner_mut().insert_genesis_state( - ordered_checkpoints.first().cloned().unwrap(), - empty_contents(), - committee.committee().to_owned(), - ); - event_loop_2.store.inner_mut().insert_genesis_state( - ordered_checkpoints.first().cloned().unwrap(), - empty_contents(), - committee.committee().to_owned(), - ); - - // Node 2 will have all the data - { - let mut store = event_loop_2.store.inner_mut(); - for checkpoint in ordered_checkpoints.clone() { - store.insert_checkpoint(&checkpoint); - } - } - - // Node 1 will know that Node 2 has the data - event_loop_1.peer_heights.write().unwrap().peers.insert( - network_2.peer_id(), - PeerStateSyncInfo { - genesis_checkpoint_digest: *ordered_checkpoints[0].digest(), - on_same_chain_as_us: true, - height: *ordered_checkpoints.last().unwrap().sequence_number(), - lowest: 0, - }, - ); - event_loop_1 - .peer_heights - .write() - .unwrap() - .insert_checkpoint(ordered_checkpoints.last().cloned().unwrap().into_inner()); - - // Sync the data - event_loop_1.maybe_start_checkpoint_summary_sync_task(); - event_loop_1.tasks.join_next().await.unwrap().unwrap(); - assert_eq!( - ordered_checkpoints.last().map(|x| x.data()), - Some( - event_loop_1 - .store - .get_highest_verified_checkpoint() - .unwrap() - .data() - ) - ); - - { - let store = event_loop_1.store.inner(); - let expected = checkpoints - .iter() - .map(|(key, value)| (key, value.data())) - .collect::>(); - let actual = store - .checkpoints() - .iter() - .map(|(key, value)| (key, value.data())) - .collect::>(); - assert_eq!(actual, expected); - assert_eq!( - store.checkpoint_sequence_number_to_digest(), - &sequence_number_to_digest - ); - } -} - -#[tokio::test] -async fn test_state_sync_using_archive() -> anyhow::Result<()> { - let committee = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); - // build mock data - let (ordered_checkpoints, _, sequence_number_to_digest, checkpoints) = - committee.make_empty_checkpoints(100, None); - // Initialize archive store with all checkpoints - let temp_dir = tempdir()?.into_path(); - let local_path = temp_dir.join("local_dir"); - let remote_path = temp_dir.join("remote_dir"); - let local_store_config = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(local_path.clone()), - ..Default::default() - }; - let remote_store_config = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(remote_path.clone()), - ..Default::default() - }; - let archive_writer = ArchiveWriter::new( - local_store_config.clone(), - remote_store_config.clone(), - FileCompression::Zstd, - StorageFormat::Blob, - Duration::from_secs(10), - 20, - &Registry::default(), - ) - .await?; - let test_store = SharedInMemoryStore::default(); - test_store.inner_mut().insert_genesis_state( - ordered_checkpoints.first().cloned().unwrap(), - empty_contents(), - committee.committee().to_owned(), - ); - // We ensure that only a part of the data exists in the archive store (and no - // new checkpoints after sequence number >= 50 are written to the archive - // store). This is to test the fact that a node can download latest - // checkpoints from a peer and back fill missing older data from archive - for checkpoint in &ordered_checkpoints[0..50] { - test_store.inner_mut().insert_checkpoint(checkpoint); - } - let kill = archive_writer.start(test_store).await?; - let archive_reader_config = ArchiveReaderConfig { - remote_store_config, - download_concurrency: NonZeroUsize::new(1).unwrap(), - use_for_pruning_watermark: false, - }; - // We will delete all checkpoints older than this checkpoint on Node 2 - let oldest_checkpoint_to_keep: u64 = 10; - let archive_readers = - ArchiveReaderBalancer::new(vec![archive_reader_config], &Registry::default())?; - let archive_reader = archive_readers.pick_one_random(0..u64::MAX).await.unwrap(); - loop { - archive_reader.sync_manifest_once().await?; - if let Ok(latest_available_checkpoint_in_archive) = - archive_reader.latest_available_checkpoint().await - { - // We only need enough checkpoints to be in archive store for this test - if latest_available_checkpoint_in_archive >= oldest_checkpoint_to_keep { - break; - } - } - tokio::time::sleep(Duration::from_secs(1)).await; - } - // Build and connect two nodes where Node 1 will be given access to an archive - // store Node 2 will prune older checkpoints, so Node 1 is forced to - // backfill from the archive - let (builder, server) = Builder::new() - .store(SharedInMemoryStore::default()) - .archive_readers(archive_readers) - .build(); - let network_1 = build_network(|router| router.add_rpc_service(server)); - let (event_loop_1, _handle_1) = builder.build(network_1.clone()); - let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); - let network_2 = build_network(|router| router.add_rpc_service(server)); - let (event_loop_2, _handle_2) = builder.build(network_2.clone()); - network_1.connect(network_2.local_addr()).await.unwrap(); - - // Init the root committee in both nodes - event_loop_1.store.inner_mut().insert_genesis_state( - ordered_checkpoints.first().cloned().unwrap(), - empty_contents(), - committee.committee().to_owned(), - ); - event_loop_2.store.inner_mut().insert_genesis_state( - ordered_checkpoints.first().cloned().unwrap(), - empty_contents(), - committee.committee().to_owned(), - ); - - // Node 2 will have all the data at first - { - let mut store = event_loop_2.store.inner_mut(); - for checkpoint in ordered_checkpoints.clone() { - store.insert_checkpoint(&checkpoint); - store.insert_checkpoint_contents(&checkpoint, empty_contents()); - store.update_highest_synced_checkpoint(&checkpoint); - } - } - // Prune first 10 checkpoint contents from Node 2 - { - let mut store = event_loop_2.store.inner_mut(); - for checkpoint in &ordered_checkpoints[0..(oldest_checkpoint_to_keep as usize)] { - store.delete_checkpoint_content_test_only(checkpoint.sequence_number)?; - } - // Now Node 2 has deleted checkpoint contents from range [0, 10) on local store - assert_eq!( - store.get_lowest_available_checkpoint(), - oldest_checkpoint_to_keep - ); - assert_eq!( - store - .get_highest_synced_checkpoint() - .unwrap() - .sequence_number, - ordered_checkpoints.last().unwrap().sequence_number - ); - assert_eq!( - store - .get_highest_verified_checkpoint() - .unwrap() - .sequence_number, - ordered_checkpoints.last().unwrap().sequence_number - ); - } - - // Node 1 will know that Node 2 has the data starting checkpoint 10 - event_loop_1.peer_heights.write().unwrap().peers.insert( - network_2.peer_id(), - PeerStateSyncInfo { - genesis_checkpoint_digest: *ordered_checkpoints[0].digest(), - on_same_chain_as_us: true, - height: *ordered_checkpoints.last().unwrap().sequence_number(), - lowest: oldest_checkpoint_to_keep, - }, - ); - - // Get handle to node 1 store - let store_1 = event_loop_1.store.clone(); - - // Sync the data - // Start both event loops - tokio::spawn(event_loop_1.start()); - tokio::spawn(event_loop_2.start()); - - let total_time = Instant::now(); - loop { - { - let store = store_1.inner(); - if let Some(highest_synced_checkpoint) = store.get_highest_synced_checkpoint() { - if highest_synced_checkpoint.sequence_number - == ordered_checkpoints.last().unwrap().sequence_number - { - // Node 1 is fully synced to the latest checkpoint on Node 2 - let expected = checkpoints - .iter() - .map(|(key, value)| (key, value.data())) - .collect::>(); - let actual = store - .checkpoints() - .iter() - .map(|(key, value)| (key, value.data())) - .collect::>(); - assert_eq!(actual, expected); - assert_eq!( - store.checkpoint_sequence_number_to_digest(), - &sequence_number_to_digest - ); - break; - } - } - } - if total_time.elapsed() > Duration::from_secs(120) { - return Err(anyhow!("Test timed out")); - } - tokio::time::sleep(Duration::from_secs(1)).await; - } - kill.send(())?; - Ok(()) -} - -#[tokio::test] -async fn sync_with_checkpoints_being_inserted() { - telemetry_subscribers::init_for_testing(); - let committee = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); - // build mock data - let (ordered_checkpoints, _contents, sequence_number_to_digest, checkpoints) = - committee.make_empty_checkpoints(4, None); - - // Build and connect two nodes - let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); - let network_1 = build_network(|router| router.add_rpc_service(server)); - let (event_loop_1, handle_1) = builder.build(network_1.clone()); - let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); - let network_2 = build_network(|router| router.add_rpc_service(server)); - let (event_loop_2, handle_2) = builder.build(network_2.clone()); - network_1.connect(network_2.local_addr()).await.unwrap(); - - // Init the root committee in both nodes - event_loop_1.store.inner_mut().insert_genesis_state( - ordered_checkpoints.first().cloned().unwrap(), - empty_contents(), - committee.committee().to_owned(), - ); - event_loop_2.store.inner_mut().insert_genesis_state( - ordered_checkpoints.first().cloned().unwrap(), - empty_contents(), - committee.committee().to_owned(), - ); - - // get handles to each node's stores - let store_1 = event_loop_1.store.clone(); - let store_2 = event_loop_2.store.clone(); - // make sure that node_1 knows about node_2 - event_loop_1.peer_heights.write().unwrap().peers.insert( - network_2.peer_id(), - PeerStateSyncInfo { - genesis_checkpoint_digest: *ordered_checkpoints[0].digest(), - on_same_chain_as_us: true, - height: 0, - lowest: 0, - }, - ); - // Start both event loops - tokio::spawn(event_loop_1.start()); - tokio::spawn(event_loop_2.start()); - - let mut subscriber_1 = handle_1.subscribe_to_synced_checkpoints(); - let mut subscriber_2 = handle_2.subscribe_to_synced_checkpoints(); - - // Inject one checkpoint and verify that it was shared with the other node - let mut checkpoint_iter = ordered_checkpoints.clone().into_iter().skip(1); - let checkpoint = checkpoint_iter.next().unwrap(); - store_1 - .insert_checkpoint_contents(&checkpoint, empty_contents()) - .unwrap(); - store_1.insert_certified_checkpoint(&checkpoint); - handle_1.send_checkpoint(checkpoint).await; - - timeout(Duration::from_secs(1), async { - assert_eq!( - subscriber_1.recv().await.unwrap().data(), - ordered_checkpoints[1].data(), - ); - assert_eq!( - subscriber_2.recv().await.unwrap().data(), - ordered_checkpoints[1].data() - ); - }) - .await - .unwrap(); - - // Inject all the checkpoints - for checkpoint in checkpoint_iter { - store_1.insert_certified_checkpoint(&checkpoint); - handle_1.send_checkpoint(checkpoint).await; - } - - timeout(Duration::from_secs(1), async { - for checkpoint in &ordered_checkpoints[2..] { - assert_eq!(subscriber_1.recv().await.unwrap().data(), checkpoint.data()); - assert_eq!(subscriber_2.recv().await.unwrap().data(), checkpoint.data()); - } - }) - .await - .unwrap(); - - let store_1 = store_1.inner(); - let store_2 = store_2.inner(); - assert_eq!( - ordered_checkpoints.last().map(|x| x.digest()), - store_1 - .get_highest_verified_checkpoint() - .as_ref() - .map(|x| x.digest()) - ); - assert_eq!( - ordered_checkpoints.last().map(|x| x.digest()), - store_2 - .get_highest_verified_checkpoint() - .as_ref() - .map(|x| x.digest()) - ); - - let expected = checkpoints - .iter() - .map(|(key, value)| (key, value.data())) - .collect::>(); - let actual_1 = store_1 - .checkpoints() - .iter() - .map(|(key, value)| (key, value.data())) - .collect::>(); - assert_eq!(actual_1, expected); - assert_eq!( - store_1.checkpoint_sequence_number_to_digest(), - &sequence_number_to_digest - ); - - let actual_2 = store_2 - .checkpoints() - .iter() - .map(|(key, value)| (key, value.data())) - .collect::>(); - assert_eq!(actual_2, expected); - assert_eq!( - store_2.checkpoint_sequence_number_to_digest(), - &sequence_number_to_digest - ); -} - -#[tokio::test] -async fn sync_with_checkpoints_watermark() { - telemetry_subscribers::init_for_testing(); - let committee = CommitteeFixture::generate(rand::rngs::OsRng, 0, 4); - // build mock data - let (ordered_checkpoints, contents, _sequence_number_to_digest, _checkpoints) = - committee.make_random_checkpoints(4, None); - let last_checkpoint_seq = *ordered_checkpoints - .last() - .cloned() - .unwrap() - .sequence_number(); - // Build and connect two nodes - let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); - let network_1 = build_network(|router| router.add_rpc_service(server)); - let (event_loop_1, handle_1) = builder.build(network_1.clone()); - let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); - let network_2 = build_network(|router| router.add_rpc_service(server)); - let (event_loop_2, handle_2) = builder.build(network_2.clone()); - - // Init the root committee in both nodes - let genesis_checkpoint_content = contents.first().cloned().unwrap(); - event_loop_1.store.inner_mut().insert_genesis_state( - ordered_checkpoints.first().cloned().unwrap(), - genesis_checkpoint_content.clone(), - committee.committee().to_owned(), - ); - event_loop_2.store.inner_mut().insert_genesis_state( - ordered_checkpoints.first().cloned().unwrap(), - genesis_checkpoint_content.clone(), - committee.committee().to_owned(), - ); - - // get handles to each node's stores - let store_1 = event_loop_1.store.clone(); - let store_2 = event_loop_2.store.clone(); - let peer_id_1 = network_1.peer_id(); - - let peer_heights_1 = event_loop_1.peer_heights.clone(); - let peer_heights_2 = event_loop_2.peer_heights.clone(); - peer_heights_1 - .write() - .unwrap() - .set_wait_interval_when_no_peer_to_sync_content(Duration::from_secs(1)); - peer_heights_2 - .write() - .unwrap() - .set_wait_interval_when_no_peer_to_sync_content(Duration::from_secs(1)); - - // Start both event loops - tokio::spawn(event_loop_1.start()); - tokio::spawn(event_loop_2.start()); - - let mut subscriber_1 = handle_1.subscribe_to_synced_checkpoints(); - let mut subscriber_2 = handle_2.subscribe_to_synced_checkpoints(); - - network_1.connect(network_2.local_addr()).await.unwrap(); - - // Inject one checkpoint and verify that it was shared with the other node - let mut checkpoint_iter = ordered_checkpoints.clone().into_iter().skip(1); - let mut contents_iter = contents.clone().into_iter().skip(1); - let checkpoint_1 = checkpoint_iter.next().unwrap(); - let contents_1 = contents_iter.next().unwrap(); - let checkpoint_seq = checkpoint_1.sequence_number(); - store_1 - .insert_checkpoint_contents(&checkpoint_1, contents_1.clone()) - .unwrap(); - store_1.insert_certified_checkpoint(&checkpoint_1); - handle_1.send_checkpoint(checkpoint_1.clone()).await; - - timeout(Duration::from_secs(3), async { - assert_eq!( - subscriber_1.recv().await.unwrap().data(), - ordered_checkpoints[1].data(), - ); - assert_eq!( - subscriber_2.recv().await.unwrap().data(), - ordered_checkpoints[1].data() - ); - }) - .await - .unwrap(); - - assert_eq!( - store_1 - .get_highest_synced_checkpoint() - .unwrap() - .sequence_number(), - checkpoint_seq - ); - assert_eq!( - store_2 - .get_highest_synced_checkpoint() - .unwrap() - .sequence_number(), - checkpoint_seq - ); - assert_eq!( - store_1 - .get_highest_verified_checkpoint() - .unwrap() - .sequence_number(), - &1 - ); - assert_eq!( - store_2 - .get_highest_verified_checkpoint() - .unwrap() - .sequence_number(), - &1 - ); - - // So far so good. - // Now we increase Peer 1's low watermark to a high number. - let a_very_high_checkpoint_seq = 1000; - store_1 - .inner_mut() - .set_lowest_available_checkpoint(a_very_high_checkpoint_seq); - - assert!(peer_heights_2.write().unwrap().update_peer_info( - peer_id_1, - checkpoint_1.clone().into(), - Some(a_very_high_checkpoint_seq), - )); - - // Inject all the checkpoints to Peer 1 - for (checkpoint, contents) in checkpoint_iter.zip(contents_iter) { - store_1 - .insert_checkpoint_contents(&checkpoint, contents) - .unwrap(); - store_1.insert_certified_checkpoint(&checkpoint); - handle_1.send_checkpoint(checkpoint).await; - } - - // Peer 1 has all the checkpoint contents, but not Peer 2 - timeout(Duration::from_secs(1), async { - for (checkpoint, contents) in ordered_checkpoints[2..] - .iter() - .zip(contents.clone().into_iter().skip(2)) - { - assert_eq!(subscriber_1.recv().await.unwrap().data(), checkpoint.data()); - let content_digest = contents.into_checkpoint_contents_digest(); - store_1 - .get_full_checkpoint_contents(&content_digest) - .unwrap() - .unwrap(); - assert_eq!( - store_2 - .get_full_checkpoint_contents(&content_digest) - .unwrap(), - None - ); - } - }) - .await - .unwrap(); - subscriber_2.try_recv().unwrap_err(); - - assert_eq!( - store_1 - .get_highest_synced_checkpoint() - .unwrap() - .sequence_number(), - ordered_checkpoints.last().unwrap().sequence_number() - ); - assert_eq!( - store_2 - .get_highest_synced_checkpoint() - .unwrap() - .sequence_number(), - ordered_checkpoints[1].sequence_number() - ); - - assert_eq!( - store_1 - .get_highest_verified_checkpoint() - .unwrap() - .sequence_number(), - &last_checkpoint_seq - ); - - // Add Peer 3 - let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); - let network_3 = build_network(|router| router.add_rpc_service(server)); - let (event_loop_3, handle_3) = builder.build(network_3.clone()); - - let mut subscriber_3 = handle_3.subscribe_to_synced_checkpoints(); - network_3.connect(network_1.local_addr()).await.unwrap(); - network_3.connect(network_2.local_addr()).await.unwrap(); - let store_3 = event_loop_3.store.clone(); - let peer_heights_3 = event_loop_3.peer_heights.clone(); - peer_heights_3 - .write() - .unwrap() - .set_wait_interval_when_no_peer_to_sync_content(Duration::from_secs(1)); - event_loop_3.store.inner_mut().insert_genesis_state( - ordered_checkpoints.first().cloned().unwrap(), - genesis_checkpoint_content.clone(), - committee.committee().to_owned(), - ); - tokio::spawn(event_loop_3.start()); - - // Peer 3 is able to sync checkpoint 1 with teh help from Peer 2 - timeout(Duration::from_secs(1), async { - assert_eq!( - subscriber_3.recv().await.unwrap().data(), - ordered_checkpoints[1].data() - ); - let content_digest = contents[1].clone().into_checkpoint_contents_digest(); - store_3 - .get_full_checkpoint_contents(&content_digest) - .unwrap() - .unwrap(); - }) - .await - .unwrap(); - subscriber_3.try_recv().unwrap_err(); - subscriber_2.try_recv().unwrap_err(); - - assert_eq!( - store_2 - .get_highest_synced_checkpoint() - .unwrap() - .sequence_number(), - ordered_checkpoints[1].sequence_number(), - ); - assert_eq!( - store_3 - .get_highest_synced_checkpoint() - .unwrap() - .sequence_number(), - ordered_checkpoints[1].sequence_number(), - ); - - // Now set Peer 1's low watermark back to 0 - store_1.inner_mut().set_lowest_available_checkpoint(0); - - // Peer 2 and Peer 3 will know about this change by - // `get_checkpoint_availability` Soon we expect them to have all - // checkpoints's content. - timeout(Duration::from_secs(6), async { - for (checkpoint, contents) in ordered_checkpoints[2..] - .iter() - .zip(contents.clone().into_iter().skip(2)) - { - assert_eq!(subscriber_2.recv().await.unwrap().data(), checkpoint.data()); - assert_eq!(subscriber_3.recv().await.unwrap().data(), checkpoint.data()); - let content_digest = contents.into_checkpoint_contents_digest(); - store_2 - .get_full_checkpoint_contents(&content_digest) - .unwrap() - .unwrap(); - store_3 - .get_full_checkpoint_contents(&content_digest) - .unwrap() - .unwrap(); - } - }) - .await - .unwrap(); - assert_eq!( - store_2 - .get_highest_synced_checkpoint() - .unwrap() - .sequence_number(), - &last_checkpoint_seq - ); - assert_eq!( - store_3 - .get_highest_synced_checkpoint() - .unwrap() - .sequence_number(), - &last_checkpoint_seq - ); - assert_eq!( - store_2 - .get_highest_verified_checkpoint() - .unwrap() - .sequence_number(), - &last_checkpoint_seq - ); - assert_eq!( - store_3 - .get_highest_verified_checkpoint() - .unwrap() - .sequence_number(), - &last_checkpoint_seq - ); - - // Now set Peer 1 and 2's low watermark to a very high number - store_1 - .inner_mut() - .set_lowest_available_checkpoint(a_very_high_checkpoint_seq); - - store_2 - .inner_mut() - .set_lowest_available_checkpoint(a_very_high_checkpoint_seq); - - // Start Peer 4 - let (builder, server) = Builder::new().store(SharedInMemoryStore::default()).build(); - let network_4 = build_network(|router| router.add_rpc_service(server)); - let (event_loop_4, handle_4) = builder.build(network_4.clone()); - - let mut subscriber_4 = handle_4.subscribe_to_synced_checkpoints(); - let store_4 = event_loop_4.store.clone(); - let peer_heights_4 = event_loop_4.peer_heights.clone(); - peer_heights_4 - .write() - .unwrap() - .set_wait_interval_when_no_peer_to_sync_content(Duration::from_secs(1)); - event_loop_4.store.inner_mut().insert_genesis_state( - ordered_checkpoints.first().cloned().unwrap(), - genesis_checkpoint_content, - committee.committee().to_owned(), - ); - tokio::spawn(event_loop_4.start()); - // Need to connect 4 to 1, 2, 3 manually, as it does not have discovery enabled - network_4.connect(network_1.local_addr()).await.unwrap(); - network_4.connect(network_2.local_addr()).await.unwrap(); - network_4.connect(network_3.local_addr()).await.unwrap(); - - // Peer 4 syncs everything with Peer 3 - timeout(Duration::from_secs(3), async { - for (checkpoint, contents) in ordered_checkpoints[1..] - .iter() - .zip(contents.clone().into_iter().skip(1)) - { - assert_eq!(subscriber_4.recv().await.unwrap().data(), checkpoint.data()); - let content_digest = contents.into_checkpoint_contents_digest(); - store_4 - .get_full_checkpoint_contents(&content_digest) - .unwrap() - .unwrap(); - } - }) - .await - .unwrap(); - assert_eq!( - store_4 - .get_highest_synced_checkpoint() - .unwrap() - .sequence_number(), - &last_checkpoint_seq - ); -} diff --git a/crates/sui-network/src/utils.rs b/crates/sui-network/src/utils.rs deleted file mode 100644 index 5a6df36ac40..00000000000 --- a/crates/sui-network/src/utils.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[cfg(test)] -pub fn build_network(f: impl FnOnce(anemo::Router) -> anemo::Router) -> anemo::Network { - build_network_impl(f, None) -} - -#[cfg(test)] -pub fn build_network_with_anemo_config( - f: impl FnOnce(anemo::Router) -> anemo::Router, - anemo_config: anemo::Config, -) -> anemo::Network { - build_network_impl(f, Some(anemo_config)) -} - -#[cfg(test)] -fn build_network_impl( - f: impl FnOnce(anemo::Router) -> anemo::Router, - anemo_config: Option, -) -> anemo::Network { - let router = f(anemo::Router::new()); - let network = anemo::Network::bind("localhost:0") - .private_key(random_key()) - .config(anemo_config.unwrap_or_default()) - .server_name("test") - .start(router) - .unwrap(); - - println!( - "starting network {} {}", - network.local_addr(), - network.peer_id(), - ); - network -} - -#[cfg(test)] -fn random_key() -> [u8; 32] { - let mut rng = rand::thread_rng(); - let mut bytes = [0u8; 32]; - rand::RngCore::fill_bytes(&mut rng, &mut bytes[..]); - bytes -} diff --git a/crates/sui-node/Cargo.toml b/crates/sui-node/Cargo.toml deleted file mode 100644 index e1a21e4fac6..00000000000 --- a/crates/sui-node/Cargo.toml +++ /dev/null @@ -1,56 +0,0 @@ -[package] -name = "sui-node" -version.workspace = true -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anemo.workspace = true -anemo-tower.workspace = true -arc-swap.workspace = true -axum.workspace = true -anyhow.workspace = true -clap.workspace = true -prometheus.workspace = true -tokio = { workspace = true, features = ["full"] } -tracing.workspace = true -futures.workspace = true -tower.workspace = true -reqwest.workspace = true -tap.workspace = true -serde.workspace = true -snap.workspace = true -git-version.workspace = true -const-str.workspace = true -url.workspace = true -humantime.workspace = true - -sui-archival.workspace = true -sui-tls.workspace = true -sui-macros.workspace = true -sui-config.workspace = true -sui-core.workspace = true -sui-rest-api.workspace = true -sui-storage.workspace = true -sui-network.workspace = true -sui-json-rpc.workspace = true -sui-json-rpc-api.workspace = true -sui-protocol-config.workspace = true -sui-snapshot.workspace = true -sui-telemetry.workspace = true -sui-types.workspace = true -mysten-metrics.workspace = true -mysten-common.workspace = true -narwhal-network.workspace = true -narwhal-worker.workspace = true -typed-store.workspace = true -mysten-network.workspace = true -telemetry-subscribers.workspace = true -fastcrypto.workspace = true -fastcrypto-zkp.workspace = true -move-vm-profiler.workspace = true - -[target.'cfg(msim)'.dependencies] -sui-simulator.workspace = true diff --git a/crates/sui-node/src/admin.rs b/crates/sui-node/src/admin.rs deleted file mode 100644 index 219d1a911cd..00000000000 --- a/crates/sui-node/src/admin.rs +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - net::{IpAddr, Ipv4Addr, SocketAddr}, - sync::Arc, -}; - -use axum::{ - extract::{Query, State}, - http::StatusCode, - routing::{get, post}, - Router, -}; -use humantime::parse_duration; -use serde::Deserialize; -use sui_types::error::SuiError; -use telemetry_subscribers::TracingHandle; -use tracing::info; - -use crate::SuiNode; - -// Example commands: -// -// Set buffer stake for current epoch 2 to 1500 basis points: -// -// $ curl -X POST 'http://127.0.0.1:1337/set-override-buffer-stake?buffer_bps=1500&epoch=2' -// -// Clear buffer stake override for current epoch 2, use -// ProtocolConfig::buffer_stake_for_protocol_upgrade_bps: -// -// $ curl -X POST 'http://127.0.0.1:1337/clear-override-buffer-stake?epoch=2' -// -// Vote to close epoch 2 early -// -// $ curl -X POST 'http://127.0.0.1:1337/force-close-epoch?epoch=2' -// -// View current all capabilities from all authorities that have been received by -// this node: -// -// $ curl 'http://127.0.0.1:1337/capabilities' -// -// View the node config (private keys will be masked): -// -// $ curl 'http://127.0.0.1:1337/node-config' -// -// Set a time-limited tracing config. After the duration expires, tracing will -// be disabled automatically. -// -// $ curl -X POST 'http://127.0.0.1:1337/enable-tracing?filter=info&duration=10s' -// -// Reset tracing to the TRACE_FILTER env var. -// -// $ curl -X POST 'http://127.0.0.1:1337/reset-tracing' - -const LOGGING_ROUTE: &str = "/logging"; -const TRACING_ROUTE: &str = "/enable-tracing"; -const TRACING_RESET_ROUTE: &str = "/reset-tracing"; -const SET_BUFFER_STAKE_ROUTE: &str = "/set-override-buffer-stake"; -const CLEAR_BUFFER_STAKE_ROUTE: &str = "/clear-override-buffer-stake"; -const FORCE_CLOSE_EPOCH: &str = "/force-close-epoch"; -const CAPABILITIES: &str = "/capabilities"; -const NODE_CONFIG: &str = "/node-config"; - -struct AppState { - node: Arc, - tracing_handle: TracingHandle, -} - -pub async fn run_admin_server(node: Arc, port: u16, tracing_handle: TracingHandle) { - let filter = tracing_handle.get_log().unwrap(); - - let app_state = AppState { - node, - tracing_handle, - }; - - let app = Router::new() - .route(LOGGING_ROUTE, get(get_filter)) - .route(CAPABILITIES, get(capabilities)) - .route(NODE_CONFIG, get(node_config)) - .route(LOGGING_ROUTE, post(set_filter)) - .route( - SET_BUFFER_STAKE_ROUTE, - post(set_override_protocol_upgrade_buffer_stake), - ) - .route( - CLEAR_BUFFER_STAKE_ROUTE, - post(clear_override_protocol_upgrade_buffer_stake), - ) - .route(FORCE_CLOSE_EPOCH, post(force_close_epoch)) - .route(TRACING_ROUTE, post(enable_tracing)) - .route(TRACING_RESET_ROUTE, post(reset_tracing)) - .with_state(Arc::new(app_state)); - - let socket_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port); - info!( - filter =% filter, - address =% socket_address, - "starting admin server" - ); - - axum::Server::bind(&socket_address) - .serve(app.into_make_service()) - .await - .unwrap() -} - -#[derive(Deserialize)] -struct EnableTracing { - // These params change the filter, and reset it after the duration expires. - filter: Option, - duration: Option, - - // Change the trace output file (if file output was enabled at program start) - trace_file: Option, - - // Change the tracing sample rate - sample_rate: Option, -} - -async fn enable_tracing( - State(state): State>, - query: Query, -) -> (StatusCode, String) { - let Query(EnableTracing { - filter, - duration, - trace_file, - sample_rate, - }) = query; - - let mut response = Vec::new(); - - if let Some(sample_rate) = sample_rate { - state.tracing_handle.update_sampling_rate(sample_rate); - response.push(format!("sample rate set to {:?}", sample_rate)); - } - - if let Some(trace_file) = trace_file { - if let Err(err) = state.tracing_handle.update_trace_file(&trace_file) { - response.push(format!("can't update trace file: {:?}", err)); - return (StatusCode::BAD_REQUEST, response.join("\n")); - } else { - response.push(format!("trace file set to {:?}", trace_file)); - } - } - - let Some(filter) = filter else { - return (StatusCode::OK, response.join("\n")); - }; - - // Duration is required if filter is set - let Some(duration) = duration else { - response.push("can't update filter: missing duration".into()); - return (StatusCode::BAD_REQUEST, response.join("\n")); - }; - - let Ok(duration) = parse_duration(&duration) else { - response.push("can't update filter: invalid duration".into()); - return (StatusCode::BAD_REQUEST, response.join("\n")); - }; - - match state.tracing_handle.update_trace_filter(&filter, duration) { - Ok(()) => { - response.push(format!("filter set to {:?}", filter)); - response.push(format!("filter will be reset after {:?}", duration)); - (StatusCode::OK, response.join("\n")) - } - Err(err) => { - response.push(format!("can't update filter: {:?}", err)); - (StatusCode::BAD_REQUEST, response.join("\n")) - } - } -} - -async fn reset_tracing(State(state): State>) -> (StatusCode, String) { - state.tracing_handle.reset_trace(); - ( - StatusCode::OK, - "tracing filter reset to TRACE_FILTER env var".into(), - ) -} - -async fn get_filter(State(state): State>) -> (StatusCode, String) { - match state.tracing_handle.get_log() { - Ok(filter) => (StatusCode::OK, filter), - Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()), - } -} - -async fn set_filter( - State(state): State>, - new_filter: String, -) -> (StatusCode, String) { - match state.tracing_handle.update_log(&new_filter) { - Ok(()) => { - info!(filter =% new_filter, "Log filter updated"); - (StatusCode::OK, "".into()) - } - Err(err) => (StatusCode::BAD_REQUEST, err.to_string()), - } -} - -async fn capabilities(State(state): State>) -> (StatusCode, String) { - let epoch_store = state.node.state().load_epoch_store_one_call_per_task(); - let capabilities = epoch_store.get_capabilities(); - - let mut output = String::new(); - for capability in &capabilities { - output.push_str(&format!("{:?}\n", capability)); - } - - (StatusCode::OK, output) -} - -async fn node_config(State(state): State>) -> (StatusCode, String) { - let node_config = &state.node.config; - - // Note private keys will be masked - (StatusCode::OK, format!("{:#?}\n", node_config)) -} - -#[derive(Deserialize)] -struct Epoch { - epoch: u64, -} - -async fn clear_override_protocol_upgrade_buffer_stake( - State(state): State>, - epoch: Query, -) -> (StatusCode, String) { - let Query(Epoch { epoch }) = epoch; - - match state - .node - .clear_override_protocol_upgrade_buffer_stake(epoch) - { - Ok(()) => ( - StatusCode::OK, - "protocol upgrade buffer stake cleared\n".to_string(), - ), - Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()), - } -} - -#[derive(Deserialize)] -struct SetBufferStake { - buffer_bps: u64, - epoch: u64, -} - -async fn set_override_protocol_upgrade_buffer_stake( - State(state): State>, - buffer_state: Query, -) -> (StatusCode, String) { - let Query(SetBufferStake { buffer_bps, epoch }) = buffer_state; - - match state - .node - .set_override_protocol_upgrade_buffer_stake(epoch, buffer_bps) - { - Ok(()) => ( - StatusCode::OK, - format!("protocol upgrade buffer stake set to '{}'\n", buffer_bps), - ), - Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()), - } -} - -async fn force_close_epoch( - State(state): State>, - epoch: Query, -) -> (StatusCode, String) { - let Query(Epoch { - epoch: expected_epoch, - }) = epoch; - let epoch_store = state.node.state().load_epoch_store_one_call_per_task(); - let actual_epoch = epoch_store.epoch(); - if actual_epoch != expected_epoch { - let err = SuiError::WrongEpoch { - expected_epoch, - actual_epoch, - }; - return (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()); - } - - match state.node.close_epoch(&epoch_store).await { - Ok(()) => ( - StatusCode::OK, - "close_epoch() called successfully\n".to_string(), - ), - Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()), - } -} diff --git a/crates/sui-node/src/handle.rs b/crates/sui-node/src/handle.rs deleted file mode 100644 index bbd9a8f0959..00000000000 --- a/crates/sui-node/src/handle.rs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//! SuiNodeHandle wraps SuiNode in a way suitable for access by test code. -//! -//! When starting a SuiNode directly, in a test (as opposed to using Swarm), the -//! node may be running inside of a simulator node. It is therefore a mistake to -//! do something like: -//! -//! ```ignore -//! use test_utils::authority::{start_node, spawn_checkpoint_processes}; -//! -//! let node = start_node(config, registry).await; -//! spawn_checkpoint_processes(config, &[node]).await; -//! ``` -//! -//! Because this would cause the checkpointing processes to be running inside -//! the current simulator node rather than the node in which the SuiNode is -//! running. -//! -//! SuiNodeHandle provides an easy way to do the right thing here: -//! -//! ```ignore -//! let node_handle = start_node(config, registry).await; -//! node_handle.with_async(|sui_node| async move { -//! spawn_checkpoint_processes(config, &[sui_node]).await; -//! }); -//! ``` -//! -//! Code executed inside of with or with_async will run in the context of the -//! simulator node. This allows tests to break the simulator abstraction and -//! magically mutate or inspect state that is conceptually running on a -//! different "machine", but without producing extremely confusing behavior that -//! might result otherwise. (For instance, any network connection that is -//! initiated from a task spawned from within a with or with_async will appear -//! to originate from the correct simulator node. -//! -//! It is possible to exfiltrate state: -//! -//! ```ignore -//! let state = node_handle.with(|sui_node| sui_node.state); -//! // DO NOT DO THIS! -//! do_stuff_with_state(state) -//! ``` -//! -//! We can't prevent this completely, but we can at least make the right way the -//! easy way. - -use std::{future::Future, sync::Arc}; - -use sui_core::authority::AuthorityState; - -use super::SuiNode; - -/// Wrap SuiNode to allow correct access to SuiNode in simulator tests. -pub struct SuiNodeHandle { - node: Option>, - shutdown_on_drop: bool, -} - -impl SuiNodeHandle { - pub fn new(node: Arc) -> Self { - Self { - node: Some(node), - shutdown_on_drop: false, - } - } - - pub fn inner(&self) -> &Arc { - self.node.as_ref().unwrap() - } - - pub fn with(&self, cb: impl FnOnce(&SuiNode) -> T) -> T { - let _guard = self.guard(); - cb(self.inner()) - } - - pub fn state(&self) -> Arc { - self.with(|sui_node| sui_node.state()) - } - - pub fn shutdown_on_drop(&mut self) { - self.shutdown_on_drop = true; - } -} - -impl Clone for SuiNodeHandle { - fn clone(&self) -> Self { - Self { - node: self.node.clone(), - shutdown_on_drop: false, - } - } -} - -#[cfg(not(msim))] -impl SuiNodeHandle { - // Must return something to silence lints above at `let _guard = ...` - fn guard(&self) -> u32 { - 0 - } - - pub async fn with_async<'a, F, R, T>(&'a self, cb: F) -> T - where - F: FnOnce(&'a SuiNode) -> R, - R: Future, - { - cb(self.inner()).await - } -} - -#[cfg(msim)] -impl SuiNodeHandle { - fn guard(&self) -> sui_simulator::runtime::NodeEnterGuard { - self.inner().sim_state.sim_node.enter_node() - } - - pub async fn with_async<'a, F, R, T>(&'a self, cb: F) -> T - where - F: FnOnce(&'a SuiNode) -> R, - R: Future, - { - let fut = cb(self.node.as_ref().unwrap()); - self.inner() - .sim_state - .sim_node - .await_future_in_node(fut) - .await - } -} - -#[cfg(msim)] -impl Drop for SuiNodeHandle { - fn drop(&mut self) { - if self.shutdown_on_drop { - let node_id = self.inner().sim_state.sim_node.id(); - sui_simulator::runtime::Handle::try_current().map(|h| h.delete_node(node_id)); - } - } -} - -impl From> for SuiNodeHandle { - fn from(node: Arc) -> Self { - SuiNodeHandle::new(node) - } -} diff --git a/crates/sui-node/src/lib.rs b/crates/sui-node/src/lib.rs deleted file mode 100644 index 8540c4431d9..00000000000 --- a/crates/sui-node/src/lib.rs +++ /dev/null @@ -1,1963 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[cfg(msim)] -use std::sync::atomic::Ordering; -use std::{ - collections::{BTreeSet, HashMap, HashSet}, - fmt, - path::PathBuf, - str::FromStr, - sync::Arc, - time::Duration, -}; - -use anemo::Network; -use anemo_tower::{ - callback::CallbackLayer, - trace::{DefaultMakeSpan, DefaultOnFailure, TraceLayer}, -}; -use anyhow::{anyhow, Result}; -use arc_swap::ArcSwap; -use fastcrypto_zkp::bn254::zk_login::{JwkId, OIDCProvider, JWK}; -use futures::TryFutureExt; -pub use handle::SuiNodeHandle; -use mysten_metrics::{spawn_monitored_task, RegistryService}; -use mysten_network::server::ServerBuilder; -use narwhal_network::metrics::{ - MetricsMakeCallbackHandler, NetworkConnectionMetrics, NetworkMetrics, -}; -use narwhal_worker::LazyNarwhalClient; -use prometheus::Registry; -use sui_archival::{reader::ArchiveReaderBalancer, writer::ArchiveWriter}; -use sui_config::{ - node::{ConsensusProtocol, DBCheckpointConfig, RunWithRange}, - node_config_metrics::NodeConfigMetrics, - object_storage_config::{ObjectStoreConfig, ObjectStoreType}, - ConsensusConfig, NodeConfig, -}; -use sui_core::{ - authority::{ - authority_per_epoch_store::AuthorityPerEpochStore, - authority_store_tables::AuthorityPerpetualTables, - epoch_start_configuration::{EpochStartConfigTrait, EpochStartConfiguration}, - AuthorityState, AuthorityStore, RandomnessRoundReceiver, CHAIN_IDENTIFIER, - }, - authority_aggregator::AuthorityAggregator, - authority_client::NetworkAuthorityClient, - authority_server::{ValidatorService, ValidatorServiceMetrics}, - checkpoints::{ - checkpoint_executor::{CheckpointExecutor, StopReason}, - CheckpointMetrics, CheckpointService, CheckpointStore, SendCheckpointToStateSync, - SubmitCheckpointToConsensus, - }, - consensus_adapter::{ - CheckConnection, ConnectionMonitorStatus, ConsensusAdapter, ConsensusAdapterMetrics, - SubmitToConsensus, - }, - consensus_manager::{ConsensusManager, ConsensusManagerTrait}, - consensus_throughput_calculator::{ - ConsensusThroughputCalculator, ConsensusThroughputProfiler, ThroughputProfileRanges, - }, - consensus_validator::{SuiTxValidator, SuiTxValidatorMetrics}, - db_checkpoint_handler::DBCheckpointHandler, - epoch::{ - committee_store::CommitteeStore, data_removal::EpochDataRemover, - epoch_metrics::EpochMetrics, randomness::RandomnessManager, - reconfiguration::ReconfigurationInitiator, - }, - execution_cache::{ - ExecutionCache, ExecutionCacheMetrics, ExecutionCacheReconfigAPI, NotifyReadWrapper, - }, - module_cache_metrics::ResolverMetrics, - overload_monitor::overload_monitor, - signature_verifier::SignatureVerifierMetrics, - state_accumulator::StateAccumulator, - storage::RocksDbStore, - transaction_orchestrator::TransactiondOrchestrator, -}; -use sui_json_rpc::{ - coin_api::CoinReadApi, governance_api::GovernanceReadApi, indexer_api::IndexerApi, - move_utils::MoveUtils, read_api::ReadApi, transaction_builder_api::TransactionBuilderApi, - transaction_execution_api::TransactionExecutionApi, JsonRpcServerBuilder, ServerType, -}; -use sui_json_rpc_api::JsonRpcMetrics; -use sui_macros::{fail_point, fail_point_async, replay_log}; -use sui_network::{ - api::ValidatorServer, discovery, discovery::TrustedPeerChangeEvent, randomness, state_sync, -}; -use sui_protocol_config::{Chain, ProtocolConfig, ProtocolVersion, SupportedProtocolVersions}; -use sui_snapshot::uploader::StateSnapshotUploader; -use sui_storage::{ - http_key_value_store::HttpKVStore, - key_value_store::{FallbackTransactionKVStore, TransactionKeyValueStore}, - key_value_store_metrics::KeyValueStoreMetrics, - FileCompression, IndexStore, StorageFormat, -}; -use sui_types::{ - base_types::{AuthorityName, ConciseableName, EpochId}, - committee::Committee, - crypto::{KeypairTraits, RandomnessRound}, - digests::ChainIdentifier, - error::{SuiError, SuiResult}, - message_envelope::get_google_jwk_bytes, - messages_consensus::{check_total_jwk_size, AuthorityCapabilities, ConsensusTransaction}, - quorum_driver_types::QuorumDriverEffectsQueueResult, - sui_system_state::{ - epoch_start_sui_system_state::{EpochStartSystemState, EpochStartSystemStateTrait}, - SuiSystemState, SuiSystemStateTrait, - }, -}; -use tap::tap::TapFallible; -use tokio::{ - runtime::Handle, - sync::{broadcast, mpsc, watch, Mutex}, - task::JoinHandle, -}; -use tower::ServiceBuilder; -use tracing::{debug, error, error_span, info, warn, Instrument}; -use typed_store::{rocks::default_db_options, DBMetrics}; - -use crate::metrics::{GrpcMetrics, SuiNodeMetrics}; - -pub mod admin; -mod handle; -pub mod metrics; - -pub struct ValidatorComponents { - validator_server_handle: JoinHandle>, - validator_overload_monitor_handle: Option>, - consensus_manager: ConsensusManager, - consensus_epoch_data_remover: EpochDataRemover, - consensus_adapter: Arc, - // dropping this will eventually stop checkpoint tasks. The receiver side of this channel - // is copied into each checkpoint service task, and they are listening to any change to this - // channel. When the sender is dropped, a change is triggered and those tasks will exit. - checkpoint_service_exit: watch::Sender<()>, - checkpoint_metrics: Arc, - sui_tx_validator_metrics: Arc, -} - -#[cfg(msim)] -mod simulator { - use std::sync::atomic::AtomicBool; - - use super::*; - pub(super) struct SimState { - pub sim_node: sui_simulator::runtime::NodeHandle, - pub sim_safe_mode_expected: AtomicBool, - _leak_detector: sui_simulator::NodeLeakDetector, - } - - impl Default for SimState { - fn default() -> Self { - Self { - sim_node: sui_simulator::runtime::NodeHandle::current(), - sim_safe_mode_expected: AtomicBool::new(false), - _leak_detector: sui_simulator::NodeLeakDetector::new(), - } - } - } - - type JwkInjector = dyn Fn(AuthorityName, &OIDCProvider) -> SuiResult> - + Send - + Sync - + 'static; - - fn default_fetch_jwks( - _authority: AuthorityName, - _provider: &OIDCProvider, - ) -> SuiResult> { - use fastcrypto_zkp::bn254::zk_login::parse_jwks; - // Just load a default Twitch jwk for testing. - parse_jwks( - sui_types::zk_login_util::DEFAULT_JWK_BYTES, - &OIDCProvider::Twitch, - ) - .map_err(|_| SuiError::JWKRetrievalError) - } - - thread_local! { - static JWK_INJECTOR: std::cell::RefCell> = std::cell::RefCell::new(Arc::new(default_fetch_jwks)); - } - - pub(super) fn get_jwk_injector() -> Arc { - JWK_INJECTOR.with(|injector| injector.borrow().clone()) - } - - pub fn set_jwk_injector(injector: Arc) { - JWK_INJECTOR.with(|cell| *cell.borrow_mut() = injector); - } -} - -#[cfg(msim)] -pub use simulator::set_jwk_injector; -#[cfg(msim)] -use simulator::*; -use sui_core::{ - consensus_handler::ConsensusHandlerInitializer, mysticeti_adapter::LazyMysticetiClient, -}; -use sui_types::execution_config_utils::to_binary_config; - -pub struct SuiNode { - config: NodeConfig, - validator_components: Mutex>, - /// The http server responsible for serving JSON-RPC as well as the - /// experimental rest service - _http_server: Option>, - state: Arc, - transaction_orchestrator: Option>>, - registry_service: RegistryService, - metrics: Arc, - - _discovery: discovery::Handle, - state_sync_handle: state_sync::Handle, - randomness_handle: randomness::Handle, - checkpoint_store: Arc, - accumulator: Arc, - connection_monitor_status: Arc, - - /// Broadcast channel to send the starting system state for the next epoch. - end_of_epoch_channel: broadcast::Sender, - - /// Broadcast channel to notify state-sync for new validator peers. - trusted_peer_change_tx: watch::Sender, - - _db_checkpoint_handle: Option>, - - #[cfg(msim)] - sim_state: SimState, - - _state_archive_handle: Option>, - - _state_snapshot_uploader_handle: Option>, - // Channel to allow signaling upstream to shutdown sui-node - shutdown_channel_tx: broadcast::Sender>, -} - -impl fmt::Debug for SuiNode { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("SuiNode") - .field("name", &self.state.name.concise()) - .finish() - } -} - -static MAX_JWK_KEYS_PER_FETCH: usize = 100; - -impl SuiNode { - pub async fn start( - config: NodeConfig, - registry_service: RegistryService, - custom_rpc_runtime: Option, - ) -> Result> { - Self::start_async(config, registry_service, custom_rpc_runtime, "unknown").await - } - - fn start_jwk_updater( - config: &NodeConfig, - metrics: Arc, - authority: AuthorityName, - epoch_store: Arc, - consensus_adapter: Arc, - ) { - let epoch = epoch_store.epoch(); - - let supported_providers = config - .zklogin_oauth_providers - .get(&epoch_store.get_chain_identifier().chain()) - .unwrap_or(&BTreeSet::new()) - .iter() - .map(|s| OIDCProvider::from_str(s).expect("Invalid provider string")) - .collect::>(); - - let fetch_interval = Duration::from_secs(config.jwk_fetch_interval_seconds); - - info!( - ?fetch_interval, - "Starting JWK updater tasks with supported providers: {:?}", supported_providers - ); - - fn validate_jwk( - metrics: &Arc, - provider: &OIDCProvider, - id: &JwkId, - jwk: &JWK, - ) -> bool { - let Ok(iss_provider) = OIDCProvider::from_iss(&id.iss) else { - warn!( - "JWK iss {:?} (retrieved from {:?}) is not a valid provider", - id.iss, provider - ); - metrics - .invalid_jwks - .with_label_values(&[&provider.to_string()]) - .inc(); - return false; - }; - - if iss_provider != *provider { - warn!( - "JWK iss {:?} (retrieved from {:?}) does not match provider {:?}", - id.iss, provider, iss_provider - ); - metrics - .invalid_jwks - .with_label_values(&[&provider.to_string()]) - .inc(); - return false; - } - - if !check_total_jwk_size(id, jwk) { - warn!("JWK {:?} (retrieved from {:?}) is too large", id, provider); - metrics - .invalid_jwks - .with_label_values(&[&provider.to_string()]) - .inc(); - return false; - } - - true - } - - // metrics is: - // pub struct SuiNodeMetrics { - // pub jwk_requests: IntCounterVec, - // pub jwk_request_errors: IntCounterVec, - // pub total_jwks: IntCounterVec, - // pub unique_jwks: IntCounterVec, - // } - - for p in supported_providers.into_iter() { - let provider_str = p.to_string(); - let epoch_store = epoch_store.clone(); - let consensus_adapter = consensus_adapter.clone(); - let metrics = metrics.clone(); - spawn_monitored_task!(epoch_store.clone().within_alive_epoch( - async move { - // note: restart-safe de-duplication happens after consensus, this is - // just best-effort to reduce unneeded submissions. - let mut seen = HashSet::new(); - loop { - info!("fetching JWK for provider {:?}", p); - metrics.jwk_requests.with_label_values(&[&provider_str]).inc(); - match Self::fetch_jwks(authority, &p).await { - Err(e) => { - metrics.jwk_request_errors.with_label_values(&[&provider_str]).inc(); - warn!("Error when fetching JWK for provider {:?} {:?}", p, e); - // Retry in 30 seconds - tokio::time::sleep(Duration::from_secs(30)).await; - continue; - } - Ok(mut keys) => { - metrics.total_jwks - .with_label_values(&[&provider_str]) - .inc_by(keys.len() as u64); - - keys.retain(|(id, jwk)| { - validate_jwk(&metrics, &p, id, jwk) && - !epoch_store.jwk_active_in_current_epoch(id, jwk) && - seen.insert((id.clone(), jwk.clone())) - }); - - metrics.unique_jwks - .with_label_values(&[&provider_str]) - .inc_by(keys.len() as u64); - - // prevent oauth providers from sending too many keys, - // inadvertently or otherwise - if keys.len() > MAX_JWK_KEYS_PER_FETCH { - warn!("Provider {:?} sent too many JWKs, only the first {} will be used", p, MAX_JWK_KEYS_PER_FETCH); - keys.truncate(MAX_JWK_KEYS_PER_FETCH); - } - - for (id, jwk) in keys.into_iter() { - info!("Submitting JWK to consensus: {:?}", id); - - let txn = ConsensusTransaction::new_jwk_fetched(authority, id, jwk); - consensus_adapter.submit(txn, None, &epoch_store) - .tap_err(|e| warn!("Error when submitting JWKs to consensus {:?}", e)) - .ok(); - } - } - } - tokio::time::sleep(fetch_interval).await; - } - } - .instrument(error_span!("jwk_updater_task", epoch)), - )); - } - } - - pub async fn start_async( - config: NodeConfig, - registry_service: RegistryService, - custom_rpc_runtime: Option, - software_version: &'static str, - ) -> Result> { - NodeConfigMetrics::new(®istry_service.default_registry()).record_metrics(&config); - let mut config = config.clone(); - if config.supported_protocol_versions.is_none() { - info!( - "populating config.supported_protocol_versions with default {:?}", - SupportedProtocolVersions::SYSTEM_DEFAULT - ); - config.supported_protocol_versions = Some(SupportedProtocolVersions::SYSTEM_DEFAULT); - } - - let run_with_range = config.run_with_range; - let is_validator = config.consensus_config().is_some(); - let is_full_node = !is_validator; - let prometheus_registry = registry_service.default_registry(); - - info!(node =? config.protocol_public_key(), - "Initializing sui-node listening on {}", config.network_address - ); - - // Initialize metrics to track db usage before creating any stores - DBMetrics::init(&prometheus_registry); - mysten_metrics::init_metrics(&prometheus_registry); - - let genesis = config.genesis()?; - - let secret = Arc::pin(config.protocol_key_pair().copy()); - let genesis_committee = genesis.committee()?; - let committee_store = Arc::new(CommitteeStore::new( - config.db_path().join("epochs"), - &genesis_committee, - None, - )); - - let perpetual_options = default_db_options().optimize_db_for_write_throughput(4); - let perpetual_tables = Arc::new(AuthorityPerpetualTables::open( - &config.db_path().join("store"), - Some(perpetual_options.options), - )); - let is_genesis = perpetual_tables - .database_is_empty() - .expect("Database read should not fail at init."); - let store = AuthorityStore::open( - perpetual_tables, - genesis, - config.indirect_objects_threshold, - config - .expensive_safety_check_config - .enable_epoch_sui_conservation_check(), - &prometheus_registry, - ) - .await?; - let execution_cache_metrics = Arc::new(ExecutionCacheMetrics::new(&prometheus_registry)); - let execution_cache = Arc::new(ExecutionCache::new(store.clone(), execution_cache_metrics)); - - let cur_epoch = store.get_recovery_epoch_at_restart()?; - let committee = committee_store - .get_committee(&cur_epoch)? - .expect("Committee of the current epoch must exist"); - let epoch_start_configuration = store - .get_epoch_start_configuration()? - .expect("EpochStartConfiguration of the current epoch must exist"); - let cache_metrics = Arc::new(ResolverMetrics::new(&prometheus_registry)); - let signature_verifier_metrics = SignatureVerifierMetrics::new(&prometheus_registry); - - let epoch_options = default_db_options().optimize_db_for_write_throughput(4); - let epoch_store = AuthorityPerEpochStore::new( - config.protocol_public_key(), - committee.clone(), - &config.db_path().join("store"), - Some(epoch_options.options), - EpochMetrics::new(®istry_service.default_registry()), - epoch_start_configuration, - execution_cache.clone(), - cache_metrics, - signature_verifier_metrics, - &config.expensive_safety_check_config, - ChainIdentifier::from(*genesis.checkpoint().digest()), - ); - - replay_log!( - "Beginning replay run. Epoch: {:?}, Protocol config: {:?}", - epoch_store.epoch(), - epoch_store.protocol_config() - ); - - // the database is empty at genesis time - if is_genesis { - // When we are opening the db table, the only time when it's safe to - // check SUI conservation is at genesis. Otherwise we may be in the middle of - // an epoch and the SUI conservation check will fail. This also initialize - // the expected_network_sui_amount table. - execution_cache - .expensive_check_sui_conservation(&epoch_store) - .expect("SUI conservation check cannot fail at genesis"); - } - - let effective_buffer_stake = epoch_store.get_effective_buffer_stake_bps(); - let default_buffer_stake = epoch_store - .protocol_config() - .buffer_stake_for_protocol_upgrade_bps(); - if effective_buffer_stake != default_buffer_stake { - warn!( - ?effective_buffer_stake, - ?default_buffer_stake, - "buffer_stake_for_protocol_upgrade_bps is currently overridden" - ); - } - - let checkpoint_store = CheckpointStore::new(&config.db_path().join("checkpoints")); - checkpoint_store.insert_genesis_checkpoint( - genesis.checkpoint(), - genesis.checkpoint_contents().clone(), - &epoch_store, - ); - - let state_sync_store = RocksDbStore::new( - execution_cache.clone(), - committee_store.clone(), - checkpoint_store.clone(), - ); - - let index_store = if is_full_node && config.enable_index_processing { - Some(Arc::new(IndexStore::new( - config.db_path().join("indexes"), - &prometheus_registry, - epoch_store - .protocol_config() - .max_move_identifier_len_as_option(), - ))) - } else { - None - }; - - let chain_identifier = ChainIdentifier::from(*genesis.checkpoint().digest()); - // It's ok if the value is already set due to data races. - let _ = CHAIN_IDENTIFIER.set(chain_identifier); - - // Create network - // TODO only configure validators as seed/preferred peers for validators and not - // for fullnodes once we've had a chance to re-work fullnode - // configuration generation. - let archive_readers = - ArchiveReaderBalancer::new(config.archive_reader_config(), &prometheus_registry)?; - let (trusted_peer_change_tx, trusted_peer_change_rx) = watch::channel(Default::default()); - let (randomness_tx, randomness_rx) = mpsc::channel( - config - .p2p_config - .randomness - .clone() - .unwrap_or_default() - .mailbox_capacity(), - ); - let (p2p_network, discovery_handle, state_sync_handle, randomness_handle) = - Self::create_p2p_network( - &config, - state_sync_store.clone(), - chain_identifier, - trusted_peer_change_rx, - archive_readers.clone(), - randomness_tx, - &prometheus_registry, - )?; - - // We must explicitly send this instead of relying on the initial value to - // trigger watch value change, so that state-sync is able to process it. - send_trusted_peer_change( - &config, - &trusted_peer_change_tx, - epoch_store.epoch_start_state(), - ) - .expect("Initial trusted peers must be set"); - - // Start archiving local state to remote store - let state_archive_handle = - Self::start_state_archival(&config, &prometheus_registry, state_sync_store.clone()) - .await?; - - // Start uploading state snapshot to remote store - let state_snapshot_handle = Self::start_state_snapshot(&config, &prometheus_registry)?; - - // Start uploading db checkpoints to remote store - let (db_checkpoint_config, db_checkpoint_handle) = Self::start_db_checkpoint( - &config, - &prometheus_registry, - state_snapshot_handle.is_some(), - )?; - - let mut pruning_config = config.authority_store_pruning_config; - if !epoch_store - .protocol_config() - .simplified_unwrap_then_delete() - { - // We cannot prune tombstones if simplified_unwrap_then_delete is not enabled. - pruning_config.set_killswitch_tombstone_pruning(true); - } - - let state = AuthorityState::new( - config.protocol_public_key(), - secret, - config.supported_protocol_versions.unwrap(), - store.clone(), - execution_cache, - epoch_store.clone(), - committee_store.clone(), - index_store.clone(), - checkpoint_store.clone(), - &prometheus_registry, - pruning_config, - genesis.objects(), - &db_checkpoint_config, - config.expensive_safety_check_config.clone(), - config.transaction_deny_config.clone(), - config.certificate_deny_config.clone(), - config.indirect_objects_threshold, - config.state_debug_dump_config.clone(), - config.authority_overload_config.clone(), - archive_readers, - ) - .await; - // ensure genesis txn was executed - if epoch_store.epoch() == 0 { - let txn = &genesis.transaction(); - let span = error_span!("genesis_txn", tx_digest = ?txn.digest()); - let transaction = - sui_types::executable_transaction::VerifiedExecutableTransaction::new_unchecked( - sui_types::executable_transaction::ExecutableTransaction::new_from_data_and_sig( - genesis.transaction().data().clone(), - sui_types::executable_transaction::CertificateProof::Checkpoint(0, 0), - ), - ); - state - .try_execute_immediately(&transaction, None, &epoch_store) - .instrument(span) - .await - .unwrap(); - } - - // Start the loop that receives new randomness and generates transactions for - // it. - RandomnessRoundReceiver::spawn(state.clone(), randomness_rx); - - if config - .expensive_safety_check_config - .enable_secondary_index_checks() - { - if let Some(indexes) = state.indexes.clone() { - sui_core::verify_indexes::verify_indexes( - state.get_accumulator_store().as_ref(), - indexes, - ) - .expect("secondary indexes are inconsistent"); - } - } - - let (end_of_epoch_channel, end_of_epoch_receiver) = - broadcast::channel(config.end_of_epoch_broadcast_channel_capacity); - - let transaction_orchestrator = if is_full_node && run_with_range.is_none() { - Some(Arc::new( - TransactiondOrchestrator::new_with_network_clients( - state.clone(), - end_of_epoch_receiver, - &config.db_path(), - &prometheus_registry, - )?, - )) - } else { - None - }; - - let http_server = build_http_server( - state.clone(), - state_sync_store, - &transaction_orchestrator.clone(), - &config, - &prometheus_registry, - custom_rpc_runtime, - software_version, - )?; - - let accumulator = Arc::new(StateAccumulator::new(store)); - - let authority_names_to_peer_ids = epoch_store - .epoch_start_state() - .get_authority_names_to_peer_ids(); - - let network_connection_metrics = - NetworkConnectionMetrics::new("sui", ®istry_service.default_registry()); - - let authority_names_to_peer_ids = ArcSwap::from_pointee(authority_names_to_peer_ids); - - let (_connection_monitor_handle, connection_statuses) = - narwhal_network::connectivity::ConnectionMonitor::spawn( - p2p_network.downgrade(), - network_connection_metrics, - HashMap::new(), - None, - ); - - let connection_monitor_status = ConnectionMonitorStatus { - connection_statuses, - authority_names_to_peer_ids, - }; - - let connection_monitor_status = Arc::new(connection_monitor_status); - let sui_node_metrics = Arc::new(SuiNodeMetrics::new(®istry_service.default_registry())); - - let validator_components = if state.is_validator(&epoch_store) { - let components = Self::construct_validator_components( - config.clone(), - state.clone(), - committee, - epoch_store.clone(), - checkpoint_store.clone(), - state_sync_handle.clone(), - randomness_handle.clone(), - accumulator.clone(), - connection_monitor_status.clone(), - ®istry_service, - sui_node_metrics.clone(), - ) - .await?; - // This is only needed during cold start. - components.consensus_adapter.submit_recovered(&epoch_store); - - Some(components) - } else { - None - }; - - // setup shutdown channel - let (shutdown_channel, _) = broadcast::channel::>(1); - - let node = Self { - config, - validator_components: Mutex::new(validator_components), - _http_server: http_server, - state, - transaction_orchestrator, - registry_service, - metrics: sui_node_metrics, - - _discovery: discovery_handle, - state_sync_handle, - randomness_handle, - checkpoint_store, - accumulator, - end_of_epoch_channel, - connection_monitor_status, - trusted_peer_change_tx, - - _db_checkpoint_handle: db_checkpoint_handle, - - #[cfg(msim)] - sim_state: Default::default(), - - _state_archive_handle: state_archive_handle, - _state_snapshot_uploader_handle: state_snapshot_handle, - shutdown_channel_tx: shutdown_channel, - }; - - info!("SuiNode started!"); - let node = Arc::new(node); - let node_copy = node.clone(); - spawn_monitored_task!(async move { - let result = Self::monitor_reconfiguration(node_copy).await; - if let Err(error) = result { - warn!("Reconfiguration finished with error {:?}", error); - } - }); - - Ok(node) - } - - pub fn subscribe_to_epoch_change(&self) -> broadcast::Receiver { - self.end_of_epoch_channel.subscribe() - } - - pub fn subscribe_to_shutdown_channel(&self) -> broadcast::Receiver> { - self.shutdown_channel_tx.subscribe() - } - - pub fn current_epoch_for_testing(&self) -> EpochId { - self.state.current_epoch_for_testing() - } - - pub fn db_checkpoint_path(&self) -> PathBuf { - self.config.db_checkpoint_path() - } - - // Init reconfig process by starting to reject user certs - pub async fn close_epoch(&self, epoch_store: &Arc) -> SuiResult { - info!("close_epoch (current epoch = {})", epoch_store.epoch()); - self.validator_components - .lock() - .await - .as_ref() - .ok_or_else(|| SuiError::from("Node is not a validator"))? - .consensus_adapter - .close_epoch(epoch_store); - Ok(()) - } - - pub fn clear_override_protocol_upgrade_buffer_stake(&self, epoch: EpochId) -> SuiResult { - self.state - .clear_override_protocol_upgrade_buffer_stake(epoch) - } - - pub fn set_override_protocol_upgrade_buffer_stake( - &self, - epoch: EpochId, - buffer_stake_bps: u64, - ) -> SuiResult { - self.state - .set_override_protocol_upgrade_buffer_stake(epoch, buffer_stake_bps) - } - - // Testing-only API to start epoch close process. - // For production code, please use the non-testing version. - pub async fn close_epoch_for_testing(&self) -> SuiResult { - let epoch_store = self.state.epoch_store_for_testing(); - self.close_epoch(&epoch_store).await - } - - async fn start_state_archival( - config: &NodeConfig, - prometheus_registry: &Registry, - state_sync_store: RocksDbStore, - ) -> Result>> { - if let Some(remote_store_config) = &config.state_archive_write_config.object_store_config { - let local_store_config = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(config.archive_path()), - ..Default::default() - }; - let archive_writer = ArchiveWriter::new( - local_store_config, - remote_store_config.clone(), - FileCompression::Zstd, - StorageFormat::Blob, - Duration::from_secs(600), - 256 * 1024 * 1024, - prometheus_registry, - ) - .await?; - Ok(Some(archive_writer.start(state_sync_store).await?)) - } else { - Ok(None) - } - } - - fn start_state_snapshot( - config: &NodeConfig, - prometheus_registry: &Registry, - ) -> Result>> { - if let Some(remote_store_config) = &config.state_snapshot_write_config.object_store_config { - let snapshot_uploader = StateSnapshotUploader::new( - &config.db_checkpoint_path(), - &config.snapshot_path(), - remote_store_config.clone(), - 60, - prometheus_registry, - )?; - Ok(Some(snapshot_uploader.start())) - } else { - Ok(None) - } - } - - fn start_db_checkpoint( - config: &NodeConfig, - prometheus_registry: &Registry, - state_snapshot_enabled: bool, - ) -> Result<( - DBCheckpointConfig, - Option>, - )> { - let checkpoint_path = Some( - config - .db_checkpoint_config - .checkpoint_path - .clone() - .unwrap_or_else(|| config.db_checkpoint_path()), - ); - let db_checkpoint_config = if config.db_checkpoint_config.checkpoint_path.is_none() { - DBCheckpointConfig { - checkpoint_path, - perform_db_checkpoints_at_epoch_end: if state_snapshot_enabled { - true - } else { - config - .db_checkpoint_config - .perform_db_checkpoints_at_epoch_end - }, - ..config.db_checkpoint_config.clone() - } - } else { - config.db_checkpoint_config.clone() - }; - - match ( - db_checkpoint_config.object_store_config.as_ref(), - state_snapshot_enabled, - ) { - // If db checkpoint config object store not specified but - // state snapshot object store is specified, create handler - // anyway for marking db checkpoints as completed so that they - // can be uploaded as state snapshots. - (None, false) => Ok((db_checkpoint_config, None)), - (_, _) => { - let handler = DBCheckpointHandler::new( - &db_checkpoint_config.checkpoint_path.clone().unwrap(), - db_checkpoint_config.object_store_config.as_ref(), - 60, - db_checkpoint_config - .prune_and_compact_before_upload - .unwrap_or(true), - config.indirect_objects_threshold, - config.authority_store_pruning_config, - prometheus_registry, - state_snapshot_enabled, - )?; - Ok(( - db_checkpoint_config, - Some(DBCheckpointHandler::start(handler)), - )) - } - } - } - - fn create_p2p_network( - config: &NodeConfig, - state_sync_store: RocksDbStore, - chain_identifier: ChainIdentifier, - trusted_peer_change_rx: watch::Receiver, - archive_readers: ArchiveReaderBalancer, - randomness_tx: mpsc::Sender<(EpochId, RandomnessRound, Vec)>, - prometheus_registry: &Registry, - ) -> Result<( - Network, - discovery::Handle, - state_sync::Handle, - randomness::Handle, - )> { - let (state_sync, state_sync_server) = state_sync::Builder::new() - .config(config.p2p_config.state_sync.clone().unwrap_or_default()) - .store(state_sync_store) - .archive_readers(archive_readers) - .with_metrics(prometheus_registry) - .build(); - - let (discovery, discovery_server) = discovery::Builder::new(trusted_peer_change_rx) - .config(config.p2p_config.clone()) - .build(); - - let (randomness, randomness_router) = - randomness::Builder::new(config.protocol_public_key(), randomness_tx) - .config(config.p2p_config.randomness.clone().unwrap_or_default()) - .with_metrics(prometheus_registry) - .build(); - - let p2p_network = { - let routes = anemo::Router::new() - .add_rpc_service(discovery_server) - .add_rpc_service(state_sync_server); - let routes = routes.merge(randomness_router); - - let inbound_network_metrics = - NetworkMetrics::new("sui", "inbound", prometheus_registry); - let outbound_network_metrics = - NetworkMetrics::new("sui", "outbound", prometheus_registry); - - let service = ServiceBuilder::new() - .layer( - TraceLayer::new_for_server_errors() - .make_span_with(DefaultMakeSpan::new().level(tracing::Level::INFO)) - .on_failure(DefaultOnFailure::new().level(tracing::Level::WARN)), - ) - .layer(CallbackLayer::new(MetricsMakeCallbackHandler::new( - Arc::new(inbound_network_metrics), - config.p2p_config.excessive_message_size(), - ))) - .service(routes); - - let outbound_layer = ServiceBuilder::new() - .layer( - TraceLayer::new_for_client_and_server_errors() - .make_span_with(DefaultMakeSpan::new().level(tracing::Level::INFO)) - .on_failure(DefaultOnFailure::new().level(tracing::Level::WARN)), - ) - .layer(CallbackLayer::new(MetricsMakeCallbackHandler::new( - Arc::new(outbound_network_metrics), - config.p2p_config.excessive_message_size(), - ))) - .into_inner(); - - let mut anemo_config = config.p2p_config.anemo_config.clone().unwrap_or_default(); - // Set the max_frame_size to be 1 GB to work around the issue of there being too - // many staking events in the epoch change txn. - anemo_config.max_frame_size = Some(1 << 30); - - // Set a higher default value for socket send/receive buffers if not already - // configured. - let mut quic_config = anemo_config.quic.unwrap_or_default(); - if quic_config.socket_send_buffer_size.is_none() { - quic_config.socket_send_buffer_size = Some(20 << 20); - } - if quic_config.socket_receive_buffer_size.is_none() { - quic_config.socket_receive_buffer_size = Some(20 << 20); - } - quic_config.allow_failed_socket_buffer_size_setting = true; - - // Set high-performance defaults for quinn transport. - // With 200MiB buffer size and ~500ms RTT, max throughput ~400MiB/s. - if quic_config.stream_receive_window.is_none() { - quic_config.stream_receive_window = Some(100 << 20); - } - if quic_config.receive_window.is_none() { - quic_config.receive_window = Some(200 << 20); - } - if quic_config.send_window.is_none() { - quic_config.send_window = Some(200 << 20); - } - if quic_config.crypto_buffer_size.is_none() { - quic_config.crypto_buffer_size = Some(1 << 20); - } - if quic_config.max_idle_timeout_ms.is_none() { - quic_config.max_idle_timeout_ms = Some(30_000); - } - if quic_config.keep_alive_interval_ms.is_none() { - quic_config.keep_alive_interval_ms = Some(5_000); - } - anemo_config.quic = Some(quic_config); - - let server_name = format!("sui-{}", chain_identifier); - let network = Network::bind(config.p2p_config.listen_address) - .server_name(&server_name) - .private_key(config.network_key_pair().copy().private().0.to_bytes()) - .config(anemo_config) - .outbound_request_layer(outbound_layer) - .start(service)?; - info!( - server_name = server_name, - "P2p network started on {}", - network.local_addr() - ); - - network - }; - - let discovery_handle = discovery.start(p2p_network.clone()); - let state_sync_handle = state_sync.start(p2p_network.clone()); - let randomness_handle = randomness.start(p2p_network.clone()); - - Ok(( - p2p_network, - discovery_handle, - state_sync_handle, - randomness_handle, - )) - } - - async fn construct_validator_components( - config: NodeConfig, - state: Arc, - committee: Arc, - epoch_store: Arc, - checkpoint_store: Arc, - state_sync_handle: state_sync::Handle, - randomness_handle: randomness::Handle, - accumulator: Arc, - connection_monitor_status: Arc, - registry_service: &RegistryService, - sui_node_metrics: Arc, - ) -> Result { - let mut config_clone = config.clone(); - let consensus_config = config_clone - .consensus_config - .as_mut() - .ok_or_else(|| anyhow!("Validator is missing consensus config"))?; - - // Only allow overriding the consensus protocol, if the protocol version - // supports fields needed by Mysticeti. - if epoch_store.protocol_config().version >= ProtocolVersion::new(36) { - if let Ok(consensus_choice) = std::env::var("CONSENSUS") { - let consensus_protocol = match consensus_choice.as_str() { - "narwhal" => ConsensusProtocol::Narwhal, - "mysticeti" => ConsensusProtocol::Mysticeti, - "swap_each_epoch" => { - if epoch_store.epoch() % 2 == 0 { - ConsensusProtocol::Narwhal - } else { - ConsensusProtocol::Mysticeti - } - } - _ => { - let consensus = consensus_config.protocol.clone(); - warn!( - "Consensus env var was set to an invalid choice, using default consensus protocol {consensus:?}" - ); - consensus - } - }; - info!("Constructing consensus protocol {consensus_protocol:?}..."); - consensus_config.protocol = consensus_protocol; - } - } - - // TODO (mysticeti): Move protocol choice to a protocol config flag. - let (consensus_adapter, consensus_manager) = match consensus_config.protocol { - ConsensusProtocol::Narwhal => { - let consensus_adapter = Arc::new(Self::construct_consensus_adapter( - &committee, - consensus_config, - state.name, - connection_monitor_status.clone(), - ®istry_service.default_registry(), - epoch_store.protocol_config().clone(), - Arc::new(LazyNarwhalClient::new( - consensus_config.address().to_owned(), - )), - )); - let consensus_manager = - ConsensusManager::new_narwhal(&config, consensus_config, registry_service); - (consensus_adapter, consensus_manager) - } - ConsensusProtocol::Mysticeti => { - let client = Arc::new(LazyMysticetiClient::new()); - - let consensus_adapter = Arc::new(Self::construct_consensus_adapter( - &committee, - consensus_config, - state.name, - connection_monitor_status.clone(), - ®istry_service.default_registry(), - epoch_store.protocol_config().clone(), - client.clone(), - )); - let consensus_manager = ConsensusManager::new_mysticeti( - &config, - consensus_config, - registry_service, - client, - ); - (consensus_adapter, consensus_manager) - } - }; - - let mut consensus_epoch_data_remover = - EpochDataRemover::new(consensus_manager.get_storage_base_path()); - - // This only gets started up once, not on every epoch. (Make call to remove - // every epoch.) - consensus_epoch_data_remover.run().await; - - let checkpoint_metrics = CheckpointMetrics::new(®istry_service.default_registry()); - let sui_tx_validator_metrics = - SuiTxValidatorMetrics::new(®istry_service.default_registry()); - - let validator_server_handle = Self::start_grpc_validator_service( - &config, - state.clone(), - consensus_adapter.clone(), - ®istry_service.default_registry(), - ) - .await?; - - // Starts an overload monitor that monitors the execution of the authority. - // Don't start the overload monitor when max_load_shedding_percentage is 0. - let validator_overload_monitor_handle = if config - .authority_overload_config - .max_load_shedding_percentage - > 0 - { - let authority_state = Arc::downgrade(&state); - let overload_config = config.authority_overload_config.clone(); - fail_point!("starting_overload_monitor"); - Some(spawn_monitored_task!(overload_monitor( - authority_state, - overload_config, - ))) - } else { - None - }; - - Self::start_epoch_specific_validator_components( - &config, - state.clone(), - consensus_adapter, - checkpoint_store, - epoch_store, - state_sync_handle, - randomness_handle, - consensus_manager, - consensus_epoch_data_remover, - accumulator, - validator_server_handle, - validator_overload_monitor_handle, - checkpoint_metrics, - sui_node_metrics, - sui_tx_validator_metrics, - ) - .await - } - - async fn start_epoch_specific_validator_components( - config: &NodeConfig, - state: Arc, - consensus_adapter: Arc, - checkpoint_store: Arc, - epoch_store: Arc, - state_sync_handle: state_sync::Handle, - randomness_handle: randomness::Handle, - consensus_manager: ConsensusManager, - consensus_epoch_data_remover: EpochDataRemover, - accumulator: Arc, - validator_server_handle: JoinHandle>, - validator_overload_monitor_handle: Option>, - checkpoint_metrics: Arc, - sui_node_metrics: Arc, - sui_tx_validator_metrics: Arc, - ) -> Result { - let (checkpoint_service, checkpoint_service_exit) = Self::start_checkpoint_service( - config, - consensus_adapter.clone(), - checkpoint_store, - epoch_store.clone(), - state.clone(), - state_sync_handle, - accumulator, - checkpoint_metrics.clone(), - ); - - // create a new map that gets injected into both the consensus handler and the - // consensus adapter the consensus handler will write values forwarded - // from consensus, and the consensus adapter will read the values to - // make decisions about which validator submits a transaction to consensus - let low_scoring_authorities = Arc::new(ArcSwap::new(Arc::new(HashMap::new()))); - - consensus_adapter.swap_low_scoring_authorities(low_scoring_authorities.clone()); - - if epoch_store.randomness_state_enabled() { - let randomness_manager = RandomnessManager::try_new( - Arc::downgrade(&epoch_store), - consensus_adapter.clone(), - randomness_handle, - config.protocol_key_pair(), - ) - .await; - if let Some(randomness_manager) = randomness_manager { - epoch_store.set_randomness_manager(randomness_manager)?; - } - } - - let throughput_calculator = Arc::new(ConsensusThroughputCalculator::new( - None, - state.metrics.clone(), - )); - - let throughput_profiler = Arc::new(ConsensusThroughputProfiler::new( - throughput_calculator.clone(), - None, - None, - state.metrics.clone(), - ThroughputProfileRanges::from_chain(epoch_store.get_chain_identifier()), - )); - - consensus_adapter.swap_throughput_profiler(throughput_profiler); - - let consensus_handler_initializer = ConsensusHandlerInitializer::new( - state.clone(), - checkpoint_service.clone(), - epoch_store.clone(), - low_scoring_authorities, - throughput_calculator, - ); - - consensus_manager - .start( - config, - epoch_store.clone(), - consensus_handler_initializer, - SuiTxValidator::new( - epoch_store.clone(), - checkpoint_service.clone(), - state.transaction_manager().clone(), - sui_tx_validator_metrics.clone(), - ), - ) - .await; - - if epoch_store.authenticator_state_enabled() { - Self::start_jwk_updater( - config, - sui_node_metrics, - state.name, - epoch_store.clone(), - consensus_adapter.clone(), - ); - } - - Ok(ValidatorComponents { - validator_server_handle, - validator_overload_monitor_handle, - consensus_manager, - consensus_epoch_data_remover, - consensus_adapter, - checkpoint_service_exit, - checkpoint_metrics, - sui_tx_validator_metrics, - }) - } - - fn start_checkpoint_service( - config: &NodeConfig, - consensus_adapter: Arc, - checkpoint_store: Arc, - epoch_store: Arc, - state: Arc, - state_sync_handle: state_sync::Handle, - accumulator: Arc, - checkpoint_metrics: Arc, - ) -> (Arc, watch::Sender<()>) { - let epoch_start_timestamp_ms = epoch_store.epoch_start_state().epoch_start_timestamp_ms(); - let epoch_duration_ms = epoch_store.epoch_start_state().epoch_duration_ms(); - - debug!( - "Starting checkpoint service with epoch start timestamp {} - and epoch duration {}", - epoch_start_timestamp_ms, epoch_duration_ms - ); - - let checkpoint_output = Box::new(SubmitCheckpointToConsensus { - sender: consensus_adapter, - signer: state.secret.clone(), - authority: config.protocol_public_key(), - next_reconfiguration_timestamp_ms: epoch_start_timestamp_ms - .checked_add(epoch_duration_ms) - .expect("Overflow calculating next_reconfiguration_timestamp_ms"), - metrics: checkpoint_metrics.clone(), - }); - - let certified_checkpoint_output = SendCheckpointToStateSync::new(state_sync_handle); - let max_tx_per_checkpoint = max_tx_per_checkpoint(epoch_store.protocol_config()); - let max_checkpoint_size_bytes = - epoch_store.protocol_config().max_checkpoint_size_bytes() as usize; - - let notify_read: NotifyReadWrapper<_> = state.get_effects_notify_read().clone(); - CheckpointService::spawn( - state.clone(), - checkpoint_store, - epoch_store, - Arc::new(notify_read), - accumulator, - checkpoint_output, - Box::new(certified_checkpoint_output), - checkpoint_metrics, - max_tx_per_checkpoint, - max_checkpoint_size_bytes, - ) - } - - fn construct_consensus_adapter( - committee: &Committee, - consensus_config: &ConsensusConfig, - authority: AuthorityName, - connection_monitor_status: Arc, - prometheus_registry: &Registry, - protocol_config: ProtocolConfig, - consensus_client: Arc, - ) -> ConsensusAdapter { - let ca_metrics = ConsensusAdapterMetrics::new(prometheus_registry); - // The consensus adapter allows the authority to send user certificates through - // consensus. - - ConsensusAdapter::new( - consensus_client, - authority, - connection_monitor_status, - consensus_config.max_pending_transactions(), - consensus_config.max_pending_transactions() * 2 / committee.num_members(), - consensus_config.max_submit_position, - consensus_config.submit_delay_step_override(), - ca_metrics, - protocol_config, - ) - } - - async fn start_grpc_validator_service( - config: &NodeConfig, - state: Arc, - consensus_adapter: Arc, - prometheus_registry: &Registry, - ) -> Result>> { - let validator_service = ValidatorService::new( - state.clone(), - consensus_adapter, - Arc::new(ValidatorServiceMetrics::new(prometheus_registry)), - ); - - let mut server_conf = mysten_network::config::Config::new(); - server_conf.global_concurrency_limit = config.grpc_concurrency_limit; - server_conf.load_shed = config.grpc_load_shed; - let mut server_builder = - ServerBuilder::from_config(&server_conf, GrpcMetrics::new(prometheus_registry)); - - server_builder = server_builder.add_service(ValidatorServer::new(validator_service)); - - let server = server_builder - .bind(config.network_address()) - .await - .map_err(|err| anyhow!(err.to_string()))?; - let local_addr = server.local_addr(); - info!("Listening to traffic on {local_addr}"); - let grpc_server = spawn_monitored_task!(server.serve().map_err(Into::into)); - - Ok(grpc_server) - } - - pub fn state(&self) -> Arc { - self.state.clone() - } - - // Only used for testing because of how epoch store is loaded. - pub fn reference_gas_price_for_testing(&self) -> Result { - self.state.reference_gas_price_for_testing() - } - - pub fn clone_committee_store(&self) -> Arc { - self.state.committee_store().clone() - } - - // pub fn clone_authority_store(&self) -> Arc { - // self.state.db() - // } - - /// Clone an AuthorityAggregator currently used in this node's - /// QuorumDriver, if the node is a fullnode. After reconfig, - /// QuorumDriver builds a new AuthorityAggregator. The caller - /// of this function will mostly likely want to call this again - /// to get a fresh one. - pub fn clone_authority_aggregator( - &self, - ) -> Option>> { - self.transaction_orchestrator - .as_ref() - .map(|to| to.clone_authority_aggregator()) - } - - pub fn transaction_orchestrator( - &self, - ) -> Option>> { - self.transaction_orchestrator.clone() - } - - pub fn get_google_jwk_bytes(&self) -> Result, SuiError> { - Ok(get_google_jwk_bytes() - .read() - .map_err(|_| SuiError::JWKRetrievalError)? - .to_vec()) - } - - pub fn subscribe_to_transaction_orchestrator_effects( - &self, - ) -> Result> { - self.transaction_orchestrator - .as_ref() - .map(|to| to.subscribe_to_effects_queue()) - .ok_or_else(|| anyhow::anyhow!("Transaction Orchestrator is not enabled in this node.")) - } - - /// This function awaits the completion of checkpoint execution of the - /// current epoch, after which it iniitiates reconfiguration of the - /// entire system. - pub async fn monitor_reconfiguration(self: Arc) -> Result<()> { - let mut checkpoint_executor = CheckpointExecutor::new( - self.state_sync_handle.subscribe_to_synced_checkpoints(), - self.checkpoint_store.clone(), - self.state.clone(), - self.accumulator.clone(), - self.config.checkpoint_executor_config.clone(), - &self.registry_service.default_registry(), - ); - - let run_with_range = self.config.run_with_range; - loop { - let cur_epoch_store = self.state.load_epoch_store_one_call_per_task(); - - // Advertise capabilities to committee, if we are a validator. - if let Some(components) = &*self.validator_components.lock().await { - // TODO: without this sleep, the consensus message is not delivered reliably. - tokio::time::sleep(Duration::from_millis(1)).await; - - let config = cur_epoch_store.protocol_config(); - let binary_config = to_binary_config(config); - let transaction = - ConsensusTransaction::new_capability_notification(AuthorityCapabilities::new( - self.state.name, - self.config - .supported_protocol_versions - .expect("Supported versions should be populated"), - self.state - .get_available_system_packages(&binary_config) - .await, - )); - info!(?transaction, "submitting capabilities to consensus"); - components - .consensus_adapter - .submit(transaction, None, &cur_epoch_store)?; - } - - let stop_condition = checkpoint_executor - .run_epoch(cur_epoch_store.clone(), run_with_range) - .await; - - if stop_condition == StopReason::RunWithRangeCondition { - SuiNode::shutdown(&self).await; - self.shutdown_channel_tx - .send(run_with_range) - .expect("RunWithRangeCondition met but failed to send shutdown message"); - return Ok(()); - } - - // Safe to call because we are in the middle of reconfiguration. - let latest_system_state = self - .state - .get_cache_reader() - .get_sui_system_state_object_unsafe() - .expect("Read Sui System State object cannot fail"); - - #[cfg(msim)] - if !self - .sim_state - .sim_safe_mode_expected - .load(Ordering::Relaxed) - { - debug_assert!(!latest_system_state.safe_mode()); - } - - #[cfg(not(msim))] - debug_assert!(!latest_system_state.safe_mode()); - - if let Err(err) = self.end_of_epoch_channel.send(latest_system_state.clone()) { - if self.state.is_fullnode(&cur_epoch_store) { - warn!( - "Failed to send end of epoch notification to subscriber: {:?}", - err - ); - } - } - - cur_epoch_store.record_is_safe_mode_metric(latest_system_state.safe_mode()); - let new_epoch_start_state = latest_system_state.into_epoch_start_state(); - let next_epoch_committee = new_epoch_start_state.get_sui_committee(); - let next_epoch = next_epoch_committee.epoch(); - assert_eq!(cur_epoch_store.epoch() + 1, next_epoch); - - info!( - next_epoch, - "Finished executing all checkpoints in epoch. About to reconfigure the system." - ); - - fail_point_async!("reconfig_delay"); - - // We save the connection monitor status map regardless of validator / fullnode - // status so that we don't need to restart the connection monitor - // every epoch. Update the mappings that will be used by the - // consensus adapter if it exists or is about to be created. - let authority_names_to_peer_ids = - new_epoch_start_state.get_authority_names_to_peer_ids(); - self.connection_monitor_status - .update_mapping_for_epoch(authority_names_to_peer_ids); - - cur_epoch_store.record_epoch_reconfig_start_time_metric(); - - let _ = send_trusted_peer_change( - &self.config, - &self.trusted_peer_change_tx, - &new_epoch_start_state, - ); - - // The following code handles 4 different cases, depending on whether the node - // was a validator in the previous epoch, and whether the node is a validator - // in the new epoch. - let new_validator_components = if let Some(ValidatorComponents { - validator_server_handle, - validator_overload_monitor_handle, - consensus_manager, - consensus_epoch_data_remover, - consensus_adapter, - checkpoint_service_exit, - checkpoint_metrics, - sui_tx_validator_metrics, - }) = self.validator_components.lock().await.take() - { - info!("Reconfiguring the validator."); - // Stop the old checkpoint service. - drop(checkpoint_service_exit); - - consensus_manager.shutdown().await; - - let new_epoch_store = self - .reconfigure_state( - &self.state, - &cur_epoch_store, - next_epoch_committee.clone(), - new_epoch_start_state, - &checkpoint_executor, - ) - .await; - - consensus_epoch_data_remover - .remove_old_data(next_epoch - 1) - .await; - - if self.state.is_validator(&new_epoch_store) { - // Only restart Narwhal if this node is still a validator in the new epoch. - Some( - Self::start_epoch_specific_validator_components( - &self.config, - self.state.clone(), - consensus_adapter, - self.checkpoint_store.clone(), - new_epoch_store.clone(), - self.state_sync_handle.clone(), - self.randomness_handle.clone(), - consensus_manager, - consensus_epoch_data_remover, - self.accumulator.clone(), - validator_server_handle, - validator_overload_monitor_handle, - checkpoint_metrics, - self.metrics.clone(), - sui_tx_validator_metrics, - ) - .await?, - ) - } else { - info!("This node is no longer a validator after reconfiguration"); - None - } - } else { - let new_epoch_store = self - .reconfigure_state( - &self.state, - &cur_epoch_store, - next_epoch_committee.clone(), - new_epoch_start_state, - &checkpoint_executor, - ) - .await; - - if self.state.is_validator(&new_epoch_store) { - info!("Promoting the node from fullnode to validator, starting grpc server"); - - Some( - Self::construct_validator_components( - self.config.clone(), - self.state.clone(), - Arc::new(next_epoch_committee.clone()), - new_epoch_store.clone(), - self.checkpoint_store.clone(), - self.state_sync_handle.clone(), - self.randomness_handle.clone(), - self.accumulator.clone(), - self.connection_monitor_status.clone(), - &self.registry_service, - self.metrics.clone(), - ) - .await?, - ) - } else { - None - } - }; - *self.validator_components.lock().await = new_validator_components; - - // Force releasing current epoch store DB handle, because the - // Arc may linger. - cur_epoch_store.release_db_handles(); - - if cfg!(msim) - && !matches!( - self.config - .authority_store_pruning_config - .num_epochs_to_retain_for_checkpoints(), - None | Some(u64::MAX) | Some(0) - ) - { - self.state - .prune_checkpoints_for_eligible_epochs_for_testing( - self.config.clone(), - sui_core::authority::authority_store_pruner::AuthorityStorePruningMetrics::new_for_test(), - ) - .await?; - } - - info!("Reconfiguration finished"); - } - } - - async fn shutdown(&self) { - if let Some(validator_components) = &*self.validator_components.lock().await { - validator_components.consensus_manager.shutdown().await; - } - } - - async fn reconfigure_state( - &self, - state: &Arc, - cur_epoch_store: &AuthorityPerEpochStore, - next_epoch_committee: Committee, - next_epoch_start_system_state: EpochStartSystemState, - checkpoint_executor: &CheckpointExecutor, - ) -> Arc { - let next_epoch = next_epoch_committee.epoch(); - - let last_checkpoint = self - .checkpoint_store - .get_epoch_last_checkpoint(cur_epoch_store.epoch()) - .expect("Error loading last checkpoint for current epoch") - .expect("Could not load last checkpoint for current epoch"); - - let epoch_start_configuration = EpochStartConfiguration::new( - next_epoch_start_system_state, - *last_checkpoint.digest(), - state.get_object_store().as_ref(), - None, - ) - .expect("EpochStartConfiguration construction cannot fail"); - - let new_epoch_store = self - .state - .reconfigure( - cur_epoch_store, - self.config.supported_protocol_versions.unwrap(), - next_epoch_committee, - epoch_start_configuration, - checkpoint_executor, - self.accumulator.clone(), - &self.config.expensive_safety_check_config, - ) - .await - .expect("Reconfigure authority state cannot fail"); - info!(next_epoch, "Node State has been reconfigured"); - assert_eq!(next_epoch, new_epoch_store.epoch()); - self.state.get_reconfig_api().update_epoch_flags_metrics( - cur_epoch_store.epoch_start_config().flags(), - new_epoch_store.epoch_start_config().flags(), - ); - - new_epoch_store - } - - pub fn get_config(&self) -> &NodeConfig { - &self.config - } -} - -#[cfg(not(msim))] -impl SuiNode { - async fn fetch_jwks( - _authority: AuthorityName, - provider: &OIDCProvider, - ) -> SuiResult> { - use fastcrypto_zkp::bn254::zk_login::fetch_jwks; - let client = reqwest::Client::new(); - fetch_jwks(provider, &client) - .await - .map_err(|_| SuiError::JWKRetrievalError) - } -} - -#[cfg(msim)] -impl SuiNode { - pub fn get_sim_node_id(&self) -> sui_simulator::task::NodeId { - self.sim_state.sim_node.id() - } - - pub fn set_safe_mode_expected(&self, new_value: bool) { - info!("Setting safe mode expected to {}", new_value); - self.sim_state - .sim_safe_mode_expected - .store(new_value, Ordering::Relaxed); - } - - #[allow(unused_variables)] - async fn fetch_jwks( - authority: AuthorityName, - provider: &OIDCProvider, - ) -> SuiResult> { - get_jwk_injector()(authority, provider) - } -} - -/// Notify state-sync that a new list of trusted peers are now available. -fn send_trusted_peer_change( - config: &NodeConfig, - sender: &watch::Sender, - epoch_state_state: &EpochStartSystemState, -) -> Result<(), watch::error::SendError> { - sender - .send(TrustedPeerChangeEvent { - new_peers: epoch_state_state.get_validator_as_p2p_peers(config.protocol_public_key()), - }) - .tap_err(|err| { - warn!( - "Failed to send validator peer information to state sync: {:?}", - err - ); - }) -} - -fn build_kv_store( - state: &Arc, - config: &NodeConfig, - registry: &Registry, -) -> Result> { - let metrics = KeyValueStoreMetrics::new(registry); - let db_store = TransactionKeyValueStore::new("rocksdb", metrics.clone(), state.clone()); - - let base_url = &config.transaction_kv_store_read_config.base_url; - - if base_url.is_empty() { - info!("no http kv store url provided, using local db only"); - return Ok(Arc::new(db_store)); - } - - let base_url: url::Url = base_url.parse().tap_err(|e| { - error!( - "failed to parse config.transaction_kv_store_config.base_url ({:?}) as url: {}", - base_url, e - ) - })?; - - let network_str = match state.get_chain_identifier().map(|c| c.chain()) { - Some(Chain::Mainnet) => "/mainnet", - Some(Chain::Testnet) => "/testnet", - _ => { - info!("using local db only for kv store for unknown chain"); - return Ok(Arc::new(db_store)); - } - }; - - let base_url = base_url.join(network_str)?.to_string(); - let http_store = HttpKVStore::new_kv(&base_url, metrics.clone())?; - info!("using local key-value store with fallback to http key-value store"); - Ok(Arc::new(FallbackTransactionKVStore::new_kv( - db_store, - http_store, - metrics, - "json_rpc_fallback", - ))) -} - -pub fn build_http_server( - state: Arc, - store: RocksDbStore, - transaction_orchestrator: &Option>>, - config: &NodeConfig, - prometheus_registry: &Registry, - _custom_runtime: Option, - software_version: &'static str, -) -> Result>> { - // Validators do not expose these APIs - if config.consensus_config().is_some() { - return Ok(None); - } - - let chain_id = state.get_chain_identifier().unwrap(); - - let mut router = axum::Router::new(); - - let json_rpc_router = { - let mut server = JsonRpcServerBuilder::new(env!("CARGO_PKG_VERSION"), prometheus_registry); - - let kv_store = build_kv_store(&state, config, prometheus_registry)?; - - let metrics = Arc::new(JsonRpcMetrics::new(prometheus_registry)); - server.register_module(ReadApi::new( - state.clone(), - kv_store.clone(), - metrics.clone(), - ))?; - server.register_module(CoinReadApi::new( - state.clone(), - kv_store.clone(), - metrics.clone(), - ))?; - - // if run_with_range is enabled we want to prevent any transactions - // run_with_range = None is normal operating conditions - if config.run_with_range.is_none() { - server.register_module(TransactionBuilderApi::new(state.clone()))?; - } - server.register_module(GovernanceReadApi::new(state.clone(), metrics.clone()))?; - - if let Some(transaction_orchestrator) = transaction_orchestrator { - server.register_module(TransactionExecutionApi::new( - state.clone(), - transaction_orchestrator.clone(), - metrics.clone(), - ))?; - } - - let name_service_config = - if let (Some(package_address), Some(registry_id), Some(reverse_registry_id)) = ( - config.name_service_package_address, - config.name_service_registry_id, - config.name_service_reverse_registry_id, - ) { - sui_json_rpc::name_service::NameServiceConfig::new( - package_address, - registry_id, - reverse_registry_id, - ) - } else { - sui_json_rpc::name_service::NameServiceConfig::default() - }; - - server.register_module(IndexerApi::new( - state.clone(), - ReadApi::new(state.clone(), kv_store.clone(), metrics.clone()), - kv_store, - name_service_config, - metrics, - config.indexer_max_subscriptions, - ))?; - server.register_module(MoveUtils::new(state))?; - - let server_type = if config.websocket_only { - Some(ServerType::WebSocket) - } else { - None - }; - server.to_router(server_type)? - }; - - router = router.merge(json_rpc_router); - - if config.enable_experimental_rest_api { - let rest_router = - sui_rest_api::RestService::new(Arc::new(store.clone()), chain_id, software_version) - .into_router(); - router = router.nest("/rest", rest_router); - } - - let server = axum::Server::bind(&config.json_rpc_address).serve(router.into_make_service()); - - let addr = server.local_addr(); - let handle = tokio::spawn(async move { server.await.unwrap() }); - - info!(local_addr =? addr, "Sui JSON-RPC server listening on {addr}"); - - Ok(Some(handle)) -} - -#[cfg(not(test))] -fn max_tx_per_checkpoint(protocol_config: &ProtocolConfig) -> usize { - protocol_config.max_transactions_per_checkpoint() as usize -} - -#[cfg(test)] -fn max_tx_per_checkpoint(_: &ProtocolConfig) -> usize { - 2 -} diff --git a/crates/sui-node/src/main.rs b/crates/sui-node/src/main.rs deleted file mode 100644 index 735d7ce2f67..00000000000 --- a/crates/sui-node/src/main.rs +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{path::PathBuf, sync::Arc, time::Duration}; - -use clap::{ArgGroup, Parser}; -use mysten_common::sync::async_once_cell::AsyncOnceCell; -use sui_config::{node::RunWithRange, Config, NodeConfig}; -use sui_core::runtime::SuiRuntimes; -use sui_node::metrics; -use sui_protocol_config::SupportedProtocolVersions; -use sui_telemetry::send_telemetry_event; -use sui_types::{ - committee::EpochId, messages_checkpoint::CheckpointSequenceNumber, multiaddr::Multiaddr, -}; -use tokio::{sync::broadcast, time::sleep}; -use tracing::{error, info}; - -const GIT_REVISION: &str = { - if let Some(revision) = option_env!("GIT_REVISION") { - revision - } else { - let version = git_version::git_version!( - args = ["--always", "--abbrev=12", "--dirty", "--exclude", "*"], - fallback = "" - ); - - if version.is_empty() { - panic!("unable to query git revision"); - } - version - } -}; -const VERSION: &str = const_str::concat!(env!("CARGO_PKG_VERSION"), "-", GIT_REVISION); - -#[derive(Parser)] -#[clap(rename_all = "kebab-case")] -#[clap(name = env!("CARGO_BIN_NAME"))] -#[clap(version = VERSION)] -#[clap(group(ArgGroup::new("exclusive").required(false)))] -struct Args { - #[clap(long)] - pub config_path: PathBuf, - - #[clap(long, help = "Specify address to listen on")] - listen_address: Option, - - #[clap(long, group = "exclusive")] - run_with_range_epoch: Option, - - #[clap(long, group = "exclusive")] - run_with_range_checkpoint: Option, -} - -fn main() { - // Ensure that a validator never calls - // get_for_min_version/get_for_max_version_UNSAFE. TODO: re-enable after we - // figure out how to eliminate crashes in prod because of this. - // ProtocolConfig::poison_get_for_min_version(); - - move_vm_profiler::gas_profiler_feature_enabled! { - panic!("Cannot run the sui-node binary with gas-profiler feature enabled"); - } - - let args = Args::parse(); - let mut config = NodeConfig::load(&args.config_path).unwrap(); - assert!( - config.supported_protocol_versions.is_none(), - "supported_protocol_versions cannot be read from the config file" - ); - config.supported_protocol_versions = Some(SupportedProtocolVersions::SYSTEM_DEFAULT); - - // match run_with_range args - // this means that we always modify the config used to start the node - // for run_with_range. i.e if this is set in the config, it is ignored. only the - // cli args enable/disable run_with_range - match (args.run_with_range_epoch, args.run_with_range_checkpoint) { - (None, Some(checkpoint)) => { - config.run_with_range = Some(RunWithRange::Checkpoint(checkpoint)) - } - (Some(epoch), None) => config.run_with_range = Some(RunWithRange::Epoch(epoch)), - _ => config.run_with_range = None, - }; - - let runtimes = SuiRuntimes::new(&config); - let metrics_rt = runtimes.metrics.enter(); - let registry_service = mysten_metrics::start_prometheus_server(config.metrics_address); - let prometheus_registry = registry_service.default_registry(); - - // Initialize logging - let (_guard, filter_handle) = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .with_prom_registry(&prometheus_registry) - .init(); - - drop(metrics_rt); - - info!("Sui Node version: {VERSION}"); - info!( - "Supported protocol versions: {:?}", - config.supported_protocol_versions - ); - - info!( - "Started Prometheus HTTP endpoint at {}", - config.metrics_address - ); - - { - let _enter = runtimes.metrics.enter(); - metrics::start_metrics_push_task(&config, registry_service.clone()); - } - - if let Some(listen_address) = args.listen_address { - config.network_address = listen_address; - } - - let is_validator = config.consensus_config().is_some(); - - let admin_interface_port = config.admin_interface_port; - - // Run node in a separate runtime so that admin/monitoring functions continue to - // work if it deadlocks. - let node_once_cell = Arc::new(AsyncOnceCell::>::new()); - let node_once_cell_clone = node_once_cell.clone(); - let rpc_runtime = runtimes.json_rpc.handle().clone(); - - // let sui-node signal main to shutdown runtimes - let (runtime_shutdown_tx, runtime_shutdown_rx) = broadcast::channel::<()>(1); - - runtimes.sui_node.spawn(async move { - match sui_node::SuiNode::start_async(config, registry_service, Some(rpc_runtime), VERSION).await { - Ok(sui_node) => node_once_cell_clone - .set(sui_node) - .expect("Failed to set node in AsyncOnceCell"), - - Err(e) => { - error!("Failed to start node: {e:?}"); - std::process::exit(1); - } - } - - // get node, subscribe to shutdown channel - let node = node_once_cell_clone.get().await; - let mut shutdown_rx = node.subscribe_to_shutdown_channel(); - - // when we get a shutdown signal from sui-node, forward it on to the runtime_shutdown_channel here in - // main to signal runtimes to all shutdown. - tokio::select! { - _ = shutdown_rx.recv() => { - runtime_shutdown_tx.send(()).expect("failed to forward shutdown signal from sui-node to sui-node main"); - } - } - // TODO: Do we want to provide a way for the node to gracefully shutdown? - loop { - tokio::time::sleep(Duration::from_secs(1000)).await; - } - }); - - let node_once_cell_clone = node_once_cell.clone(); - runtimes.metrics.spawn(async move { - let node = node_once_cell_clone.get().await; - let chain_identifier = match node.state().get_chain_identifier() { - Some(chain_identifier) => chain_identifier.to_string(), - None => "unknown".to_string(), - }; - - info!("Sui chain identifier: {chain_identifier}"); - prometheus_registry - .register(mysten_metrics::uptime_metric( - if is_validator { - "validator" - } else { - "fullnode" - }, - VERSION, - chain_identifier.as_str(), - )) - .unwrap(); - - sui_node::admin::run_admin_server(node, admin_interface_port, filter_handle).await - }); - - runtimes.metrics.spawn(async move { - let node = node_once_cell.get().await; - let state = node.state(); - loop { - send_telemetry_event(state.clone(), is_validator).await; - sleep(Duration::from_secs(3600)).await; - } - }); - - // wait for SIGINT on the main thread - tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap() - .block_on(wait_termination(runtime_shutdown_rx)); - - // Drop and wait all runtimes on main thread - drop(runtimes); -} - -#[cfg(not(unix))] -async fn wait_termination(mut shutdown_rx: tokio::sync::broadcast::Receiver<()>) { - tokio::select! { - _ = tokio::signal::ctrl_c() => {}, - _ = shutdown_rx.recv() => {}, - } -} - -#[cfg(unix)] -async fn wait_termination(mut shutdown_rx: tokio::sync::broadcast::Receiver<()>) { - use futures::FutureExt; - use tokio::signal::unix::*; - - let sigint = tokio::signal::ctrl_c().boxed(); - let mut sigterm = signal(SignalKind::terminate()).unwrap(); - let sigterm_recv = sigterm.recv().boxed(); - let shutdown_recv = shutdown_rx.recv().boxed(); - - tokio::select! { - _ = sigint => {}, - _ = sigterm_recv => {}, - _ = shutdown_recv => {}, - } -} diff --git a/crates/sui-node/src/metrics.rs b/crates/sui-node/src/metrics.rs deleted file mode 100644 index 27d1fe44286..00000000000 --- a/crates/sui-node/src/metrics.rs +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use std::time::{Duration, SystemTime, UNIX_EPOCH}; - -use axum::http::header; -use mysten_metrics::RegistryService; -use mysten_network::metrics::MetricsCallbackProvider; -use prometheus::{ - register_histogram_vec_with_registry, register_int_counter_vec_with_registry, - register_int_gauge_vec_with_registry, Encoder, HistogramVec, IntCounterVec, IntGaugeVec, - Registry, PROTOBUF_FORMAT, -}; -use sui_network::tonic::Code; -use tracing::error; - -pub struct MetricsPushClient { - certificate: std::sync::Arc, - client: reqwest::Client, -} - -impl MetricsPushClient { - pub fn new(network_key: sui_types::crypto::NetworkKeyPair) -> Self { - use fastcrypto::traits::KeyPair; - let certificate = std::sync::Arc::new(sui_tls::SelfSignedCertificate::new( - network_key.private(), - sui_tls::SUI_VALIDATOR_SERVER_NAME, - )); - let identity = certificate.reqwest_identity(); - let client = reqwest::Client::builder() - .identity(identity) - .build() - .unwrap(); - - Self { - certificate, - client, - } - } - - pub fn certificate(&self) -> &sui_tls::SelfSignedCertificate { - &self.certificate - } - - pub fn client(&self) -> &reqwest::Client { - &self.client - } -} - -/// Starts a task to periodically push metrics to a configured endpoint if a -/// metrics push endpoint is configured. -pub fn start_metrics_push_task(config: &sui_config::NodeConfig, registry: RegistryService) { - use fastcrypto::traits::KeyPair; - use sui_config::node::MetricsConfig; - - const DEFAULT_METRICS_PUSH_INTERVAL: Duration = Duration::from_secs(60); - - let (interval, url) = match &config.metrics { - Some(MetricsConfig { - push_interval_seconds, - push_url: Some(url), - }) => { - let interval = push_interval_seconds - .map(Duration::from_secs) - .unwrap_or(DEFAULT_METRICS_PUSH_INTERVAL); - let url = reqwest::Url::parse(url).expect("unable to parse metrics push url"); - (interval, url) - } - _ => return, - }; - - // make a copy so we can make a new client later when we hit errors posting - // metrics - let config_copy = config.clone(); - let mut client = MetricsPushClient::new(config_copy.network_key_pair().copy()); - - async fn push_metrics( - client: &MetricsPushClient, - url: &reqwest::Url, - registry: &RegistryService, - ) -> Result<(), anyhow::Error> { - // now represents a collection timestamp for all of the metrics we send to the - // proxy - let now = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_millis() as i64; - - let mut metric_families = registry.gather_all(); - for mf in metric_families.iter_mut() { - for m in mf.mut_metric() { - m.set_timestamp_ms(now); - } - } - - let mut buf: Vec = vec![]; - let encoder = prometheus::ProtobufEncoder::new(); - encoder.encode(&metric_families, &mut buf)?; - - let mut s = snap::raw::Encoder::new(); - let compressed = s.compress_vec(&buf).map_err(|err| { - error!("unable to snappy encode; {err}"); - err - })?; - - let response = client - .client() - .post(url.to_owned()) - .header(reqwest::header::CONTENT_ENCODING, "snappy") - .header(header::CONTENT_TYPE, PROTOBUF_FORMAT) - .body(compressed) - .send() - .await?; - - if !response.status().is_success() { - let status = response.status(); - let body = match response.text().await { - Ok(body) => body, - Err(error) => format!("couldn't decode response body; {error}"), - }; - return Err(anyhow::anyhow!( - "metrics push failed: [{}]:{}", - status, - body - )); - } - - tracing::debug!("successfully pushed metrics to {url}"); - - Ok(()) - } - - tokio::spawn(async move { - tracing::info!(push_url =% url, interval =? interval, "Started Metrics Push Service"); - - let mut interval = tokio::time::interval(interval); - interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); - - loop { - interval.tick().await; - - if let Err(error) = push_metrics(&client, &url, ®istry).await { - tracing::warn!("unable to push metrics: {error}; new client will be created"); - // aggressively recreate our client connection if we hit an error - // since our tick interval is only every min, this should not be racey - client = MetricsPushClient::new(config_copy.network_key_pair().copy()); - } - } - }); -} - -pub struct SuiNodeMetrics { - pub jwk_requests: IntCounterVec, - pub jwk_request_errors: IntCounterVec, - - pub total_jwks: IntCounterVec, - pub invalid_jwks: IntCounterVec, - pub unique_jwks: IntCounterVec, -} - -impl SuiNodeMetrics { - pub fn new(registry: &Registry) -> Self { - Self { - jwk_requests: register_int_counter_vec_with_registry!( - "jwk_requests", - "Total number of JWK requests", - &["provider"], - registry, - ) - .unwrap(), - jwk_request_errors: register_int_counter_vec_with_registry!( - "jwk_request_errors", - "Total number of JWK request errors", - &["provider"], - registry, - ) - .unwrap(), - total_jwks: register_int_counter_vec_with_registry!( - "total_jwks", - "Total number of JWKs", - &["provider"], - registry, - ) - .unwrap(), - invalid_jwks: register_int_counter_vec_with_registry!( - "invalid_jwks", - "Total number of invalid JWKs", - &["provider"], - registry, - ) - .unwrap(), - unique_jwks: register_int_counter_vec_with_registry!( - "unique_jwks", - "Total number of unique JWKs", - &["provider"], - registry, - ) - .unwrap(), - } - } -} - -#[derive(Clone)] -pub struct GrpcMetrics { - inflight_grpc: IntGaugeVec, - grpc_requests: IntCounterVec, - grpc_request_latency: HistogramVec, -} - -const LATENCY_SEC_BUCKETS: &[f64] = &[ - 0.001, 0.005, 0.01, 0.05, 0.1, 0.25, 0.5, 1., 2.5, 5., 10., 20., 30., 60., 90., -]; - -impl GrpcMetrics { - pub fn new(registry: &Registry) -> Self { - Self { - inflight_grpc: register_int_gauge_vec_with_registry!( - "inflight_grpc", - "Total in-flight GRPC requests per route", - &["path"], - registry, - ) - .unwrap(), - grpc_requests: register_int_counter_vec_with_registry!( - "grpc_requests", - "Total GRPC requests per route", - &["path", "status"], - registry, - ) - .unwrap(), - grpc_request_latency: register_histogram_vec_with_registry!( - "grpc_request_latency", - "Latency of GRPC requests per route", - &["path"], - LATENCY_SEC_BUCKETS.to_vec(), - registry, - ) - .unwrap(), - } - } -} - -impl MetricsCallbackProvider for GrpcMetrics { - fn on_request(&self, _path: String) {} - - fn on_response(&self, path: String, latency: Duration, _status: u16, grpc_status_code: Code) { - self.grpc_requests - .with_label_values(&[path.as_str(), format!("{grpc_status_code:?}").as_str()]) - .inc(); - self.grpc_request_latency - .with_label_values(&[path.as_str()]) - .observe(latency.as_secs_f64()); - } - - fn on_start(&self, path: &str) { - self.inflight_grpc.with_label_values(&[path]).inc(); - } - - fn on_drop(&self, path: &str) { - self.inflight_grpc.with_label_values(&[path]).dec(); - } -} - -#[cfg(test)] -mod tests { - use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - - use mysten_metrics::start_prometheus_server; - use prometheus::{IntCounter, Registry}; - - #[tokio::test] - pub async fn test_metrics_endpoint_with_multiple_registries_add_remove() { - let port: u16 = 8081; - let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port); - - let registry_service = start_prometheus_server(socket); - - tokio::task::yield_now().await; - - // now add a few registries to the service along side with metrics - let registry_1 = Registry::new_custom(Some("narwhal".to_string()), None).unwrap(); - let counter_1 = IntCounter::new("counter_1", "a sample counter 1").unwrap(); - registry_1.register(Box::new(counter_1)).unwrap(); - - let registry_2 = Registry::new_custom(Some("sui".to_string()), None).unwrap(); - let counter_2 = IntCounter::new("counter_2", "a sample counter 2").unwrap(); - registry_2.register(Box::new(counter_2.clone())).unwrap(); - - let registry_1_id = registry_service.add(registry_1); - let _registry_2_id = registry_service.add(registry_2); - - // request the endpoint - let result = get_metrics(port).await; - - assert!(result.contains( - "# HELP sui_counter_2 a sample counter 2 -# TYPE sui_counter_2 counter -sui_counter_2 0" - )); - - assert!(result.contains( - "# HELP narwhal_counter_1 a sample counter 1 -# TYPE narwhal_counter_1 counter -narwhal_counter_1 0" - )); - - // Now remove registry 1 - assert!(registry_service.remove(registry_1_id)); - - // AND increase metric 2 - counter_2.inc(); - - // Now pull again metrics - // request the endpoint - let result = get_metrics(port).await; - - // Registry 1 metrics should not be present anymore - assert!(!result.contains( - "# HELP narwhal_counter_1 a sample counter 1 -# TYPE narwhal_counter_1 counter -narwhal_counter_1 0" - )); - - // Registry 2 metric should have increased by 1 - assert!(result.contains( - "# HELP sui_counter_2 a sample counter 2 -# TYPE sui_counter_2 counter -sui_counter_2 1" - )); - } - - async fn get_metrics(port: u16) -> String { - let client = reqwest::Client::new(); - let response = client - .get(format!("http://127.0.0.1:{}/metrics", port)) - .send() - .await - .unwrap(); - response.text().await.unwrap() - } -} diff --git a/crates/sui-open-rpc-macros/Cargo.toml b/crates/sui-open-rpc-macros/Cargo.toml deleted file mode 100644 index b893b2cf95f..00000000000 --- a/crates/sui-open-rpc-macros/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "sui-open-rpc-macros" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[lib] -proc-macro = true - -[dependencies] -syn.workspace = true -quote.workspace = true -proc-macro2.workspace = true -itertools.workspace = true -derive-syn-parse.workspace = true -unescape.workspace = true diff --git a/crates/sui-open-rpc-macros/src/lib.rs b/crates/sui-open-rpc-macros/src/lib.rs deleted file mode 100644 index 6532fa43f69..00000000000 --- a/crates/sui-open-rpc-macros/src/lib.rs +++ /dev/null @@ -1,487 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use derive_syn_parse::Parse; -use itertools::Itertools; -use proc_macro::TokenStream; -use proc_macro2::{Ident, Span, TokenStream as TokenStream2, TokenTree}; -use quote::{quote, ToTokens, TokenStreamExt}; -use syn::{ - parse, - parse::{Parse, ParseStream}, - parse_macro_input, - punctuated::Punctuated, - spanned::Spanned, - token::{Comma, Paren}, - Attribute, GenericArgument, LitStr, PatType, Path, PathArguments, Token, TraitItem, Type, -}; -use unescape::unescape; - -const SUI_RPC_ATTRS: [&str; 2] = ["deprecated", "version"]; - -/// Add a [Service name]OpenRpc struct and implementation providing access to -/// Open RPC doc builder. This proc macro must be use in conjunction with -/// `jsonrpsee_proc_macro::rpc` -/// -/// The generated method `open_rpc` is added to [Service name]OpenRpc, -/// ideally we want to add this to the trait generated by jsonrpsee framework, -/// creating a new struct to provide access to the method is a workaround. -/// -/// TODO: consider contributing the open rpc doc macro to jsonrpsee to simplify -/// the logics. -#[proc_macro_attribute] -pub fn open_rpc(attr: TokenStream, item: TokenStream) -> TokenStream { - let attr: OpenRpcAttributes = parse_macro_input!(attr); - - let mut trait_data: syn::ItemTrait = syn::parse(item).unwrap(); - let rpc_definition = parse_rpc_method(&mut trait_data).unwrap(); - - let namespace = attr - .find_attr("namespace") - .map(|str| str.value()) - .unwrap_or_default(); - - let tag = attr.find_attr("tag").to_quote(); - - let methods = rpc_definition.methods.iter().map(|method|{ - let name = &method.name; - let deprecated = method.deprecated; - let doc = &method.doc; - let mut inputs = Vec::new(); - for (name, ty, description) in &method.params { - let (ty, required) = extract_type_from_option(ty.clone()); - let description = if let Some(description) = description { - quote! {Some(#description.to_string())} - } else { - quote! {None} - }; - - inputs.push(quote! { - let des = builder.create_content_descriptor::<#ty>(#name, None, #description, #required); - inputs.push(des); - }) - } - let returns_ty = if let Some(ty) = &method.returns { - let (ty, required) = extract_type_from_option(ty.clone()); - let name = quote! {#ty}.to_string(); - quote! {Some(builder.create_content_descriptor::<#ty>(#name, None, None, #required));} - } else { - quote! {None;} - }; - - if method.is_pubsub { - quote! { - let mut inputs: Vec = Vec::new(); - #(#inputs)* - let result = #returns_ty - builder.add_subscription(#namespace, #name, inputs, result, #doc, #tag, #deprecated); - } - } else { - quote! { - let mut inputs: Vec = Vec::new(); - #(#inputs)* - let result = #returns_ty - builder.add_method(#namespace, #name, inputs, result, #doc, #tag, #deprecated); - } - } - }).collect::>(); - - let routes = rpc_definition - .version_routing - .into_iter() - .map(|route| { - let name = route.name; - let route_to = route.route_to; - let comparator = route.token.to_string(); - let version = route.version; - quote! { - builder.add_method_routing(#namespace, #name, #route_to, #comparator, #version); - } - }) - .collect::>(); - - let open_rpc_name = quote::format_ident!("{}OpenRpc", &rpc_definition.name); - - quote! { - #trait_data - pub struct #open_rpc_name; - impl #open_rpc_name { - pub fn module_doc() -> sui_open_rpc::Module{ - let mut builder = sui_open_rpc::RpcModuleDocBuilder::default(); - #(#methods)* - #(#routes)* - builder.build() - } - } - } - .into() -} - -trait OptionalQuote { - fn to_quote(&self) -> TokenStream2; - - fn unwrap_quote(&self, quote: F) -> TokenStream2 - where - F: FnOnce(LitStr) -> TokenStream2; -} - -impl OptionalQuote for Option { - fn to_quote(&self) -> TokenStream2 { - if let Some(value) = self { - quote!(Some(#value.to_string())) - } else { - quote!(None) - } - } - - fn unwrap_quote(&self, quote: F) -> TokenStream2 - where - F: FnOnce(LitStr) -> TokenStream2, - { - if let Some(lit_str) = self { - quote(lit_str.clone()) - } else { - quote!() - } - } -} - -struct RpcDefinition { - name: Ident, - methods: Vec, - version_routing: Vec, -} -struct Method { - name: String, - params: Vec<(String, Type, Option)>, - returns: Option, - doc: String, - is_pubsub: bool, - deprecated: bool, -} -struct Routing { - name: String, - route_to: String, - token: TokenStream2, - version: String, -} - -fn parse_rpc_method(trait_data: &mut syn::ItemTrait) -> Result { - let mut methods = Vec::new(); - let mut version_routing = Vec::new(); - for trait_item in &mut trait_data.items { - if let TraitItem::Method(method) = trait_item { - let doc = extract_doc_comments(&method.attrs).to_string(); - let params: Vec<_> = method - .sig - .inputs - .iter_mut() - .filter_map(|arg| { - match arg { - syn::FnArg::Receiver(_) => None, - syn::FnArg::Typed(arg) => { - let description = if let Some(description) = arg.attrs.iter().position(|a|a.path.is_ident("doc")){ - let doc = extract_doc_comments(&arg.attrs); - arg.attrs.remove(description); - Some(doc) - }else{ - None - }; - match *arg.pat.clone() { - syn::Pat::Ident(name) => { - Some(get_type(arg).map(|ty| (name.ident.to_string(), ty, description))) - } - syn::Pat::Wild(wild) => Some(Err(syn::Error::new( - wild.underscore_token.span(), - "Method argument names must be valid Rust identifiers; got `_` instead", - ))), - _ => Some(Err(syn::Error::new( - arg.span(), - format!("Unexpected method signature input; got {:?} ", *arg.pat), - ))), - } - }, - } - }) - .collect::>()?; - - let (method_name, returns, is_pubsub, deprecated) = if let Some(attr) = - find_attr(&mut method.attrs, "method") - { - let token: TokenStream = attr.tokens.clone().into(); - let returns = match &method.sig.output { - syn::ReturnType::Default => None, - syn::ReturnType::Type(_, output) => extract_type_from(output, "RpcResult"), - }; - let mut attributes = parse::(token)?; - let method_name = attributes.get_value("name"); - let deprecated = attributes.find("deprecated").is_some(); - - if let Some(version_attr) = attributes.find("version") { - if let (Some(token), Some(version)) = (&version_attr.token, &version_attr.value) - { - let route_to = - format!("{method_name}_{}", version.value().replace('.', "_")); - version_routing.push(Routing { - name: method_name, - route_to: route_to.clone(), - token: token.to_token_stream(), - version: version.value(), - }); - if let Some(name) = attributes.find_mut("name") { - name.value - .replace(LitStr::new(&route_to, Span::call_site())); - } - attr.tokens = remove_sui_rpc_attributes(attributes); - continue; - } - } - attr.tokens = remove_sui_rpc_attributes(attributes); - (method_name, returns, false, deprecated) - } else if let Some(attr) = find_attr(&mut method.attrs, "subscription") { - let token: TokenStream = attr.tokens.clone().into(); - let attributes = parse::(token)?; - let name = attributes.get_value("name"); - let type_ = attributes - .find("item") - .expect("Subscription should have a [item] attribute") - .type_ - .clone() - .expect("[item] attribute should have a value"); - let deprecated = attributes.find("deprecated").is_some(); - attr.tokens = remove_sui_rpc_attributes(attributes); - (name, Some(type_), true, deprecated) - } else { - panic!("Unknown method name") - }; - - methods.push(Method { - name: method_name, - params, - returns, - doc, - is_pubsub, - deprecated, - }); - } - } - Ok(RpcDefinition { - name: trait_data.ident.clone(), - methods, - version_routing, - }) -} -// Remove Sui rpc specific attributes. -fn remove_sui_rpc_attributes(attributes: Attributes) -> TokenStream2 { - let attrs = attributes - .attrs - .into_iter() - .filter(|r| !SUI_RPC_ATTRS.contains(&r.key.to_string().as_str())) - .collect::>(); - quote! {(#attrs)} -} - -fn extract_type_from(ty: &Type, from_ty: &str) -> Option { - fn path_is(path: &Path, from_ty: &str) -> bool { - path.leading_colon.is_none() - && path.segments.len() == 1 - && path.segments.iter().next().unwrap().ident == from_ty - } - - if let Type::Path(p) = ty { - if p.qself.is_none() && path_is(&p.path, from_ty) { - if let PathArguments::AngleBracketed(a) = &p.path.segments[0].arguments { - if let Some(GenericArgument::Type(ty)) = a.args.first() { - return Some(ty.clone()); - } - } - } - } - None -} - -fn extract_type_from_option(ty: Type) -> (Type, bool) { - if let Some(ty) = extract_type_from(&ty, "Option") { - (ty, false) - } else { - (ty, true) - } -} - -fn get_type(pat_type: &mut PatType) -> Result { - Ok( - if let Some((pos, attr)) = pat_type - .attrs - .iter() - .find_position(|a| a.path.is_ident("schemars")) - { - let attribute = parse::(attr.tokens.clone().into())?; - - let stream = syn::parse_str(&attribute.value.value())?; - let tokens = respan_token_stream(stream, attribute.value.span()); - - let path = syn::parse2(tokens)?; - pat_type.attrs.remove(pos); - path - } else { - pat_type.ty.as_ref().clone() - }, - ) -} - -fn find_attr<'a>(attrs: &'a mut [Attribute], ident: &str) -> Option<&'a mut Attribute> { - attrs.iter_mut().find(|a| a.path.is_ident(ident)) -} - -fn respan_token_stream(stream: TokenStream2, span: Span) -> TokenStream2 { - stream - .into_iter() - .map(|mut token| { - if let TokenTree::Group(g) = &mut token { - *g = proc_macro2::Group::new(g.delimiter(), respan_token_stream(g.stream(), span)); - } - token.set_span(span); - token - }) - .collect() -} - -fn extract_doc_comments(attrs: &[Attribute]) -> String { - let s = attrs - .iter() - .filter(|attr| { - attr.path.is_ident("doc") - && match attr.parse_meta() { - Ok(syn::Meta::NameValue(meta)) => matches!(&meta.lit, syn::Lit::Str(_)), - _ => false, - } - }) - .map(|attr| { - let s = attr.tokens.to_string(); - s[4..s.len() - 1].to_string() - }) - .join(" "); - unescape(&s).unwrap_or_else(|| panic!("Cannot unescape doc comments : [{s}]")) -} - -#[derive(Parse, Debug)] -struct OpenRpcAttributes { - #[parse_terminated(OpenRpcAttribute::parse)] - fields: Punctuated, -} - -impl OpenRpcAttributes { - fn find_attr(&self, name: &str) -> Option { - self.fields - .iter() - .find(|attr| attr.label == name) - .map(|attr| attr.value.clone()) - } -} - -#[derive(Parse, Debug)] -struct OpenRpcAttribute { - label: Ident, - _eq_token: Token![=], - value: syn::LitStr, -} - -#[derive(Parse, Debug)] -struct NamedAttribute { - #[paren] - _paren_token: Paren, - #[inside(_paren_token)] - _ident: Ident, - #[inside(_paren_token)] - _eq_token: Token![=], - #[inside(_paren_token)] - value: syn::LitStr, -} - -#[derive(Debug)] -struct Attributes { - pub attrs: Punctuated, -} - -impl Attributes { - pub fn find(&self, attr_name: &str) -> Option<&Attr> { - self.attrs.iter().find(|attr| attr.key == attr_name) - } - pub fn find_mut(&mut self, attr_name: &str) -> Option<&mut Attr> { - self.attrs.iter_mut().find(|attr| attr.key == attr_name) - } - pub fn get_value(&self, attr_name: &str) -> String { - self.attrs - .iter() - .find(|attr| attr.key == attr_name) - .unwrap_or_else(|| panic!("Method should have a [{attr_name}] attribute.")) - .value - .as_ref() - .unwrap_or_else(|| panic!("[{attr_name}] attribute should have a value")) - .value() - } -} - -impl Parse for Attributes { - fn parse(input: ParseStream) -> syn::Result { - let content; - let _paren = syn::parenthesized!(content in input); - let attrs = content.parse_terminated(Attr::parse)?; - Ok(Self { attrs }) - } -} - -#[derive(Debug)] -struct Attr { - pub key: Ident, - pub token: Option, - pub value: Option, - pub type_: Option, -} - -impl ToTokens for Attr { - fn to_tokens(&self, tokens: &mut TokenStream2) { - tokens.append(self.key.clone()); - if let Some(token) = &self.token { - tokens.extend(token.to_token_stream()); - } - if let Some(value) = &self.value { - tokens.append(value.token()); - } - if let Some(type_) = &self.type_ { - tokens.extend(type_.to_token_stream()); - } - } -} - -impl Parse for Attr { - fn parse(input: ParseStream) -> syn::Result { - let key = input.parse()?; - let token = if input.peek(Token!(=)) { - Some(input.parse::()?.to_token_stream()) - } else if input.peek(Token!(<=)) { - Some(input.parse::()?.to_token_stream()) - } else { - None - }; - - let value = if token.is_some() && input.peek(syn::LitStr) { - Some(input.parse::()?) - } else { - None - }; - - let type_ = if token.is_some() && input.peek(syn::Ident) { - Some(input.parse::()?) - } else { - None - }; - - Ok(Self { - key, - token, - value, - type_, - }) - } -} diff --git a/crates/sui-open-rpc/Cargo.toml b/crates/sui-open-rpc/Cargo.toml deleted file mode 100644 index 3bbe0f53ab5..00000000000 --- a/crates/sui-open-rpc/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = "sui-open-rpc" -version.workspace = true -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -schemars.workspace = true -serde.workspace = true -serde_json.workspace = true -bcs.workspace = true -versions.workspace = true - -[dev-dependencies] -anyhow.workspace = true -clap.workspace = true -pretty_assertions.workspace = true -tokio = { workspace = true, features = ["full"] } -fastcrypto = { workspace = true } -sui-json-rpc.workspace = true -sui-json-rpc-api.workspace = true -sui-json-rpc-types.workspace = true -sui-json.workspace = true -sui-types = { workspace = true, features = ["test-utils"] } -sui-protocol-config.workspace = true -rand.workspace = true - -move-core-types.workspace = true - -[[example]] -name = "generate-json-rpc-spec" -path = "src/generate_json_rpc_spec.rs" -test = false diff --git a/crates/sui-open-rpc/src/examples.rs b/crates/sui-open-rpc/src/examples.rs deleted file mode 100644 index eb93293f866..00000000000 --- a/crates/sui-open-rpc/src/examples.rs +++ /dev/null @@ -1,1589 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::{BTreeMap, HashMap}, - ops::Range, - str::FromStr, -}; - -use fastcrypto::traits::EncodeDecodeBase64; -use move_core_types::{ - annotated_value::MoveStructLayout, - identifier::Identifier, - language_storage::{ModuleId, StructTag, TypeTag}, - resolver::ModuleResolver, -}; -use rand::{rngs::StdRng, Rng, SeedableRng}; -use serde_json::json; -use sui_json::SuiJsonValue; -use sui_json_rpc::error::Error; -use sui_json_rpc_types::{ - Balance, Checkpoint, CheckpointId, CheckpointPage, Coin, CoinPage, DelegatedStake, - DevInspectArgs, DevInspectResults, DynamicFieldPage, EventFilter, EventPage, MoveCallParams, - MoveFunctionArgType, ObjectChange, - ObjectValueKind::{ByImmutableReference, ByMutableReference, ByValue}, - ObjectsPage, OwnedObjectRef, Page, ProtocolConfigResponse, RPCTransactionRequestParams, Stake, - StakeStatus, SuiCoinMetadata, SuiCommittee, SuiData, SuiEvent, SuiExecutionStatus, - SuiGetPastObjectRequest, SuiLoadedChildObject, SuiLoadedChildObjectsResponse, SuiMoveAbility, - SuiMoveAbilitySet, SuiMoveNormalizedFunction, SuiMoveNormalizedModule, SuiMoveNormalizedStruct, - SuiMoveNormalizedType, SuiMoveVisibility, SuiObjectData, SuiObjectDataFilter, - SuiObjectDataOptions, SuiObjectRef, SuiObjectResponse, SuiObjectResponseQuery, SuiParsedData, - SuiPastObjectResponse, SuiTransactionBlock, SuiTransactionBlockData, - SuiTransactionBlockEffects, SuiTransactionBlockEffectsV1, SuiTransactionBlockEvents, - SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, - SuiTransactionBlockResponseQuery, SuiTypeTag, TransactionBlockBytes, TransactionBlocksPage, - TransactionFilter, TransferObjectParams, ValidatorApy, ValidatorApys, -}; -use sui_open_rpc::ExamplePairing; -use sui_protocol_config::{Chain, ProtocolConfig}; -use sui_types::{ - balance::Supply, - base_types::{ - random_object_ref, MoveObjectType, ObjectDigest, ObjectID, ObjectType, SequenceNumber, - SuiAddress, TransactionDigest, - }, - committee::Committee, - crypto::{get_key_pair_from_rng, AccountKeyPair, AggregateAuthoritySignature}, - digests::TransactionEventsDigest, - dynamic_field::{DynamicFieldInfo, DynamicFieldName, DynamicFieldType}, - event::EventID, - gas::GasCostSummary, - gas_coin::GasCoin, - messages_checkpoint::CheckpointDigest, - object::{MoveObject, Owner}, - parse_sui_struct_tag, - programmable_transaction_builder::ProgrammableTransactionBuilder, - quorum_driver_types::ExecuteTransactionRequestType, - signature::GenericSignature, - transaction::{CallArg, ObjectArg, TransactionData, TEST_ONLY_GAS_UNIT_FOR_TRANSFER}, - utils::to_sender_signed_transaction, - SUI_FRAMEWORK_PACKAGE_ID, -}; - -struct Examples { - function_name: String, - examples: Vec, -} - -#[derive(serde::Serialize)] -struct Value { - value: String, -} - -impl Examples { - fn new(name: &str, examples: Vec) -> Self { - Self { - function_name: name.to_string(), - examples, - } - } -} - -pub struct RpcExampleProvider { - rng: StdRng, -} - -impl RpcExampleProvider { - pub fn new() -> Self { - Self { - rng: StdRng::from_seed([0; 32]), - } - } - - pub fn examples(&mut self) -> BTreeMap> { - [ - self.batch_transaction_examples(), - self.get_object_example(), - self.get_past_object_example(), - self.get_owned_objects(), - self.get_total_transaction_blocks(), - self.get_transaction_block(), - self.query_transaction_blocks(), - self.get_events(), - self.execute_transaction_example(), - self.dry_run_transaction_block(), - self.dev_inspect_transaction_block(), - self.get_checkpoint_example(), - self.get_checkpoints(), - self.sui_get_committee_info(), - self.sui_get_reference_gas_price(), - self.suix_get_all_balances(), - self.suix_get_all_coins(), - self.suix_get_balance(), - self.suix_get_coin_metadata(), - self.sui_get_latest_checkpoint_sequence_number(), - self.suix_get_coins(), - self.suix_get_total_supply(), - self.suix_get_dynamic_fields(), - self.suix_get_dynamic_field_object(), - self.suix_get_owned_objects(), - self.sui_get_loaded_child_objects(), - self.sui_get_move_function_arg_types(), - self.sui_get_normalized_move_function(), - self.sui_get_normalized_move_module(), - self.sui_get_normalized_move_modules_by_package(), - self.sui_get_normalized_move_struct(), - self.multi_get_objects_example(), - self.multi_get_transaction_blocks(), - self.suix_get_validators_apy(), - self.suix_get_dynamic_fields(), - self.suix_get_dynamic_field_object(), - self.suix_get_owned_objects(), - self.suix_query_events(), - self.suix_get_latest_sui_system_state(), - self.get_protocol_config(), - self.sui_get_chain_identifier(), - self.suix_get_stakes(), - self.suix_get_stakes_by_ids(), - self.suix_resolve_name_service_address(), - self.suix_resolve_name_service_names(), - self.sui_try_multi_get_past_objects(), - ] - .into_iter() - .map(|example| (example.function_name, example.examples)) - .collect() - } - - fn batch_transaction_examples(&mut self) -> Examples { - let signer = SuiAddress::from(ObjectID::new(self.rng.gen())); - let recipient = SuiAddress::from(ObjectID::new(self.rng.gen())); - let gas_id = ObjectID::new(self.rng.gen()); - let object_id = ObjectID::new(self.rng.gen()); - let coin_ref = random_object_ref(); - let random_amount: u64 = 10; - - let tx_params = vec![ - RPCTransactionRequestParams::MoveCallRequestParams(MoveCallParams { - package_object_id: SUI_FRAMEWORK_PACKAGE_ID, - module: "pay".to_string(), - function: "split".to_string(), - type_arguments: vec![SuiTypeTag::new("0x2::sui::SUI".to_string())], - arguments: vec![ - SuiJsonValue::new(json!(coin_ref.0)).unwrap(), - SuiJsonValue::new(json!(random_amount)).unwrap(), - ], - }), - RPCTransactionRequestParams::TransferObjectRequestParams(TransferObjectParams { - recipient, - object_id, - }), - ]; - - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - builder - .move_call( - SUI_FRAMEWORK_PACKAGE_ID, - Identifier::from_str("pay").unwrap(), - Identifier::from_str("split").unwrap(), - vec![], - vec![ - CallArg::Object(ObjectArg::ImmOrOwnedObject(coin_ref)), - CallArg::Pure(bcs::to_bytes(&random_amount).unwrap()), - ], - ) - .unwrap(); - builder - .transfer_object( - recipient, - ( - object_id, - SequenceNumber::from_u64(1), - ObjectDigest::new(self.rng.gen()), - ), - ) - .unwrap(); - builder.finish() - }; - let gas_price = 10; - let data = TransactionData::new_programmable( - signer, - vec![( - gas_id, - SequenceNumber::from_u64(1), - ObjectDigest::new(self.rng.gen()), - )], - pt, - TEST_ONLY_GAS_UNIT_FOR_TRANSFER * gas_price, - gas_price, - ); - - let result = TransactionBlockBytes::from_data(data).unwrap(); - - Examples::new( - "sui_batchTransaction", - vec![ExamplePairing::new( - "Creates unsigned batch transaction data.", - vec![ - ("signer", json!(signer)), - ("single_transaction_params", json!(tx_params)), - ("gas", json!(gas_id)), - ("gas_budget", json!(1000)), - ("txn_builder_mode", json!("Commit")), - ], - json!(result), - )], - ) - } - - fn execute_transaction_example(&mut self) -> Examples { - let (data, signatures, _, _, result) = self.get_transfer_data_response(); - let tx_bytes = TransactionBlockBytes::from_data(data).unwrap(); - - Examples::new( - "sui_executeTransactionBlock", - vec![ExamplePairing::new( - "Executes a transaction with serialized signatures.", - vec![ - ("tx_bytes", json!(tx_bytes.tx_bytes)), - ( - "signatures", - json!( - signatures - .into_iter() - .map(|sig| sig.encode_base64()) - .collect::>() - ), - ), - ( - "options", - json!(SuiTransactionBlockResponseOptions::full_content()), - ), - ( - "request_type", - json!(ExecuteTransactionRequestType::WaitForLocalExecution), - ), - ], - json!(result), - )], - ) - } - - fn dry_run_transaction_block(&mut self) -> Examples { - let (data, _, _, _, result) = self.get_transfer_data_response(); - let tx_bytes = TransactionBlockBytes::from_data(data).unwrap(); - - Examples::new( - "sui_dryRunTransactionBlock", - vec![ExamplePairing::new( - "Dry runs a transaction block to get back estimated gas fees and other potential effects.", - vec![("tx_bytes", json!(tx_bytes.tx_bytes))], - json!(result), - )], - ) - } - - fn dev_inspect_transaction_block(&mut self) -> Examples { - let (data, _, _, _, result) = self.get_transfer_data_response(); - let tx_bytes = TransactionBlockBytes::from_data(data).unwrap(); - - let dev_inspect_results = DevInspectResults { - effects: result.effects.unwrap(), - events: SuiTransactionBlockEvents { data: vec![] }, - results: None, - error: None, - raw_txn_data: vec![], - raw_effects: vec![], - }; - - Examples::new( - "sui_devInspectTransactionBlock", - vec![ExamplePairing::new( - "Runs the transaction in dev-inspect mode. Which allows for nearly any transaction (or Move call) with any arguments. Detailed results are provided, including both the transaction effects and any return values.", - vec![ - ( - "sender_address", - json!(SuiAddress::from(ObjectID::new(self.rng.gen()))), - ), - ("tx_bytes", json!(tx_bytes.tx_bytes)), - ("gas_price", json!(1000)), - ("epoch", json!(8888)), - ("additional_args", json!(None::)), - ], - json!(dev_inspect_results), - )], - ) - } - - fn multi_get_objects_example(&mut self) -> Examples { - let objects = self.get_object_responses(5); - let object_ids = objects - .iter() - .map(|o| o.object_id().unwrap()) - .collect::>(); - Examples::new( - "sui_multiGetObjects", - vec![ExamplePairing::new( - "Gets objects by IDs.", - vec![ - ("object_ids", json!(object_ids)), - ("options", json!(SuiObjectDataOptions::full_content())), - ], - json!(objects), - )], - ) - } - - fn get_object_responses(&mut self, object_count: usize) -> Vec { - (0..object_count) - .map(|_| { - let object_id = ObjectID::new(self.rng.gen()); - let coin = GasCoin::new(object_id, 100000000); - - SuiObjectResponse::new_with_data(SuiObjectData { - content: Some( - SuiParsedData::try_from_object( - coin.to_object(SequenceNumber::from_u64(1)), - GasCoin::layout(), - ) - .unwrap(), - ), - owner: Some(Owner::AddressOwner(SuiAddress::from(ObjectID::new( - self.rng.gen(), - )))), - previous_transaction: Some(TransactionDigest::new(self.rng.gen())), - storage_rebate: Some(100), - object_id, - version: SequenceNumber::from_u64(1), - digest: ObjectDigest::new(self.rng.gen()), - type_: Some(ObjectType::Struct(MoveObjectType::gas_coin())), - bcs: None, - display: None, - }) - }) - .collect() - } - - fn get_object_example(&mut self) -> Examples { - let result = self.get_object_responses(1).pop().unwrap(); - Examples::new( - "sui_getObject", - vec![ExamplePairing::new( - "Gets Object data for the ID in the request.", - vec![ - ("object_id", json!(result.object_id().unwrap())), - ("options", json!(SuiObjectDataOptions::full_content())), - ], - json!(result), - )], - ) - } - - fn get_past_object_example(&mut self) -> Examples { - let object_id = ObjectID::new(self.rng.gen()); - - let coin = GasCoin::new(object_id, 10000); - - let result = SuiPastObjectResponse::VersionFound(SuiObjectData { - content: Some( - SuiParsedData::try_from_object( - coin.to_object(SequenceNumber::from_u64(1)), - GasCoin::layout(), - ) - .unwrap(), - ), - owner: Some(Owner::AddressOwner(SuiAddress::from(ObjectID::new( - self.rng.gen(), - )))), - previous_transaction: Some(TransactionDigest::new(self.rng.gen())), - storage_rebate: Some(100), - object_id, - version: SequenceNumber::from_u64(4), - digest: ObjectDigest::new(self.rng.gen()), - type_: Some(ObjectType::Struct(MoveObjectType::gas_coin())), - bcs: None, - display: None, - }); - - Examples::new( - "sui_tryGetPastObject", - vec![ExamplePairing::new( - "Gets Past Object data.", - vec![ - ("object_id", json!(object_id)), - ("version", json!(4)), - ("options", json!(SuiObjectDataOptions::full_content())), - ], - json!(result), - )], - ) - } - - fn get_checkpoint_example(&mut self) -> Examples { - let result = Checkpoint { - epoch: 5000, - sequence_number: 1000, - digest: CheckpointDigest::new(self.rng.gen()), - network_total_transactions: 792385, - previous_digest: Some(CheckpointDigest::new(self.rng.gen())), - epoch_rolling_gas_cost_summary: Default::default(), - timestamp_ms: 1676911928, - end_of_epoch_data: None, - transactions: vec![TransactionDigest::new(self.rng.gen())], - checkpoint_commitments: vec![], - validator_signature: AggregateAuthoritySignature::default(), - }; - - Examples::new( - "sui_getCheckpoint", - vec![ExamplePairing::new( - "Gets checkpoint information for the checkpoint ID in the request.", - vec![("id", json!(CheckpointId::SequenceNumber(1000)))], - json!(result), - )], - ) - } - - fn get_checkpoints(&mut self) -> Examples { - let limit = 4; - let descending_order = false; - let seq = 1004; - let page = (0..4) - .map(|idx| Checkpoint { - epoch: 5000, - sequence_number: seq + 1 + idx, - digest: CheckpointDigest::new(self.rng.gen()), - network_total_transactions: 792385, - previous_digest: Some(CheckpointDigest::new(self.rng.gen())), - epoch_rolling_gas_cost_summary: Default::default(), - timestamp_ms: 1676911928, - end_of_epoch_data: None, - transactions: vec![TransactionDigest::new(self.rng.gen())], - checkpoint_commitments: vec![], - validator_signature: AggregateAuthoritySignature::default(), - }) - .collect::>(); - let pagelen = page.len() as u64; - let result = CheckpointPage { - data: page, - next_cursor: Some((seq + pagelen).into()), - has_next_page: true, - }; - - Examples::new( - "sui_getCheckpoints", - vec![ExamplePairing::new( - "Gets a paginated list in descending order of all checkpoints starting at the provided cursor. Each page of results has a maximum number of checkpoints set by the provided limit.", - vec![ - ("cursor", json!(seq.to_string())), - ("limit", json!(limit)), - ("descending_order", json!(descending_order)), - ], - json!(result), - )], - ) - } - - fn get_owned_objects(&mut self) -> Examples { - let owner = SuiAddress::from(ObjectID::new(self.rng.gen())); - let result = (0..4) - .map(|_| SuiObjectData { - object_id: ObjectID::new(self.rng.gen()), - version: Default::default(), - digest: ObjectDigest::new(self.rng.gen()), - type_: Some(ObjectType::Struct(MoveObjectType::gas_coin())), - owner: Some(Owner::AddressOwner(owner)), - previous_transaction: Some(TransactionDigest::new(self.rng.gen())), - storage_rebate: None, - display: None, - content: None, - bcs: None, - }) - .collect::>(); - - Examples::new( - "sui_getOwnedObjects", - vec![ExamplePairing::new( - "Gets objects owned by the address in the request.", - vec![ - ("address", json!(owner)), - ( - "query", - json!(SuiObjectResponseQuery { - filter: Some(SuiObjectDataFilter::StructType( - StructTag::from_str("0x2::coin::Coin<0x2::sui::SUI>").unwrap() - )), - options: Some( - SuiObjectDataOptions::new() - .with_type() - .with_owner() - .with_previous_transaction() - ) - }), - ), - ("cursor", json!(ObjectID::new(self.rng.gen()))), - ("limit", json!(100)), - ("at_checkpoint", json!(None::)), - ], - json!(result), - )], - ) - } - - fn get_total_transaction_blocks(&mut self) -> Examples { - Examples::new( - "sui_getTotalTransactionBlocks", - vec![ExamplePairing::new( - "Gets total number of transactions on the network.", - vec![], - json!("2451485"), - )], - ) - } - - fn get_transaction_block(&mut self) -> Examples { - let (_, _, _, _, result) = self.get_transfer_data_response(); - Examples::new( - "sui_getTransactionBlock", - vec![ExamplePairing::new( - "Returns the transaction response object for specified transaction digest.", - vec![ - ("digest", json!(result.digest)), - ( - "options", - json!( - SuiTransactionBlockResponseOptions::new() - .with_input() - .with_effects() - .with_events() - ), - ), - ], - json!(result), - )], - ) - } - - fn query_transaction_blocks(&mut self) -> Examples { - let mut data = self.get_transaction_digests(5..9); - let has_next_page = data.len() > (9 - 5); - data.truncate(9 - 5); - let next_cursor = data.last().cloned(); - let data = data - .into_iter() - .map(SuiTransactionBlockResponse::new) - .collect(); - - let result = TransactionBlocksPage { - data, - next_cursor, - has_next_page, - }; - Examples::new( - "suix_queryTransactionBlocks", - vec![ExamplePairing::new( - "Returns the transaction digest for specified query criteria.", - vec![ - ( - "query", - json!(SuiTransactionBlockResponseQuery { - filter: Some(TransactionFilter::InputObject(ObjectID::new( - self.rng.gen() - ))), - options: None, - }), - ), - ("cursor", json!(TransactionDigest::new(self.rng.gen()))), - ("limit", json!(100)), - ("descending_order", json!(false)), - ], - json!(result), - )], - ) - } - - fn multi_get_transaction_blocks(&mut self) -> Examples { - let data = (0..3) - .map(|_| self.get_transfer_data_response().4) - .collect::>(); - let digests = data.iter().map(|x| x.digest).collect::>(); - Examples::new( - "sui_multiGetTransactionBlocks", - vec![ExamplePairing::new( - "Returns the transaction data for specified digest.", - vec![ - ("digests", json!(digests)), - ( - "options", - json!( - SuiTransactionBlockResponseOptions::new() - .with_input() - .with_effects() - .with_events() - ), - ), - ], - json!(data), - )], - ) - } - - fn get_transaction_digests(&mut self, range: Range) -> Vec { - range - .into_iter() - .map(|_| TransactionDigest::new(self.rng.gen())) - .collect() - } - - fn get_event_ids(&mut self, range: Range) -> Vec { - range - .into_iter() - .map(|_| EventID { - tx_digest: TransactionDigest::new(self.rng.gen()), - event_seq: 1, - }) - .collect() - } - - fn get_protocol_config(&mut self) -> Examples { - let version = Some(6); - Examples::new( - "sui_getProtocolConfig", - vec![ExamplePairing::new( - "Returns the protocol config for the given protocol version. If none is specified, the node uses the version of the latest epoch it has processed", - vec![("version", json!(version))], - json!(Self::get_protocol_config_impl(version)), - )], - ) - } - - fn get_protocol_config_impl(version: Option) -> ProtocolConfigResponse { - ProtocolConfigResponse::from( - version - .map(|v| { - ProtocolConfig::get_for_version_if_supported(v.into(), Chain::Unknown) - .unwrap_or(ProtocolConfig::get_for_min_version()) - }) - .unwrap_or(ProtocolConfig::get_for_min_version()), - ) - } - - fn get_transfer_data_response( - &mut self, - ) -> ( - TransactionData, - Vec, - SuiAddress, - ObjectID, - SuiTransactionBlockResponse, - ) { - let (signer, kp): (_, AccountKeyPair) = get_key_pair_from_rng(&mut self.rng); - let recipient = SuiAddress::from(ObjectID::new(self.rng.gen())); - let obj_id = ObjectID::new(self.rng.gen()); - let gas_ref = ( - ObjectID::new(self.rng.gen()), - SequenceNumber::from_u64(2), - ObjectDigest::new(self.rng.gen()), - ); - let object_ref = ( - obj_id, - SequenceNumber::from_u64(2), - ObjectDigest::new(self.rng.gen()), - ); - - let data = TransactionData::new_transfer( - recipient, - object_ref, - signer, - gas_ref, - TEST_ONLY_GAS_UNIT_FOR_TRANSFER * 10, - 10, - ); - let data1 = data.clone(); - let data2 = data.clone(); - - let tx = to_sender_signed_transaction(data, &kp); - let signatures = tx.data().tx_signatures().to_vec(); - let raw_transaction = bcs::to_bytes(tx.data()).unwrap(); - - let tx_digest = tx.digest(); - let object_change = ObjectChange::Transferred { - sender: signer, - recipient: Owner::AddressOwner(recipient), - object_type: parse_sui_struct_tag("0x2::example::Object").unwrap(), - object_id: object_ref.0, - version: object_ref.1, - digest: ObjectDigest::new(self.rng.gen()), - }; - struct NoOpsModuleResolver; - impl ModuleResolver for NoOpsModuleResolver { - type Error = Error; - fn get_module(&self, _id: &ModuleId) -> Result>, Self::Error> { - Ok(None) - } - } - let result = SuiTransactionBlockResponse { - digest: *tx_digest, - effects: Some(SuiTransactionBlockEffects::V1( - SuiTransactionBlockEffectsV1 { - status: SuiExecutionStatus::Success, - executed_epoch: 0, - modified_at_versions: vec![], - gas_used: GasCostSummary { - computation_cost: 100, - storage_cost: 100, - storage_rebate: 10, - non_refundable_storage_fee: 0, - }, - shared_objects: vec![], - transaction_digest: TransactionDigest::new(self.rng.gen()), - created: vec![], - mutated: vec![ - OwnedObjectRef { - owner: Owner::AddressOwner(signer), - reference: gas_ref.into(), - }, - OwnedObjectRef { - owner: Owner::AddressOwner(recipient), - reference: object_ref.into(), - }, - ], - unwrapped: vec![], - deleted: vec![], - unwrapped_then_deleted: vec![], - wrapped: vec![], - gas_object: OwnedObjectRef { - owner: Owner::ObjectOwner(signer), - reference: SuiObjectRef::from(gas_ref), - }, - events_digest: Some(TransactionEventsDigest::new(self.rng.gen())), - dependencies: vec![], - }, - )), - events: None, - object_changes: Some(vec![object_change]), - balance_changes: None, - timestamp_ms: None, - transaction: Some(SuiTransactionBlock { - data: SuiTransactionBlockData::try_from(data1, &&mut NoOpsModuleResolver).unwrap(), - tx_signatures: signatures.clone(), - }), - raw_transaction, - confirmed_local_execution: None, - checkpoint: None, - errors: vec![], - raw_effects: vec![], - }; - - (data2, signatures, recipient, obj_id, result) - } - - fn get_events(&mut self) -> Examples { - let tx_dig = - TransactionDigest::from_str("11a72GCQ5hGNpWGh2QhQkkusTEGS6EDqifJqxr7nSYX").unwrap(); - let event = SuiEvent { - id: EventID { - tx_digest: tx_dig, - event_seq: 0, - }, - package_id: ObjectID::new(self.rng.gen()), - transaction_module: Identifier::from_str("test_module").unwrap(), - sender: SuiAddress::from(ObjectID::new(self.rng.gen())), - type_: parse_sui_struct_tag("0x9::test::TestEvent").unwrap(), - parsed_json: json!({"test": "example value"}), - bcs: vec![], - timestamp_ms: None, - }; - - let page = EventPage { - data: vec![event], - next_cursor: Some((tx_dig, 5).into()), - has_next_page: false, - }; - Examples::new( - "sui_getEvents", - vec![ExamplePairing::new( - "Returns the events the transaction in the request emits.", - vec![("transaction_digest", json!(tx_dig))], - json!(page), - )], - ) - } - - fn sui_get_committee_info(&mut self) -> Examples { - let epoch = 5000; - let committee = json!(Committee::new_simple_test_committee_of_size(4)); - let vals = json!(committee[0]["voting_rights"]); - let suicomm = SuiCommittee { - epoch, - validators: serde_json::from_value(vals).unwrap(), - }; - - Examples::new( - "suix_getCommitteeInfo", - vec![ExamplePairing::new( - "Gets committee information for epoch 5000.", - vec![("epoch", json!(epoch.to_string()))], - json!(suicomm), - )], - ) - } - - fn sui_get_reference_gas_price(&mut self) -> Examples { - let result = 1000; - Examples::new( - "suix_getReferenceGasPrice", - vec![ExamplePairing::new( - "Gets reference gas price information for the network.", - vec![], - json!(result), - )], - ) - } - - fn suix_get_all_balances(&mut self) -> Examples { - let address = SuiAddress::from(ObjectID::new(self.rng.gen())); - - let result = Balance { - coin_type: "0x2::sui::SUI".to_string(), - coin_object_count: 15, - total_balance: 3000000000, - locked_balance: HashMap::new(), - }; - Examples::new( - "suix_getAllBalances", - vec![ExamplePairing::new( - "Gets all balances for the address in the request.", - vec![("owner", json!(address))], - json!(vec![result]), - )], - ) - } - - fn suix_get_all_coins(&mut self) -> Examples { - let limit = 3; - let owner = SuiAddress::from(ObjectID::new(self.rng.gen())); - let cursor = ObjectID::new(self.rng.gen()); - let next = ObjectID::new(self.rng.gen()); - let coins = (0..3) - .map(|_| Coin { - coin_type: "0x2::sui::SUI".to_string(), - coin_object_id: ObjectID::new(self.rng.gen()), - version: SequenceNumber::from_u64(103626), - digest: ObjectDigest::new(self.rng.gen()), - balance: 200000000, - // locked_until_epoch: None, - previous_transaction: TransactionDigest::new(self.rng.gen()), - }) - .collect::>(); - let page = CoinPage { - data: coins, - next_cursor: Some(next), - has_next_page: true, - }; - - Examples::new( - "suix_getAllCoins", - vec![ExamplePairing::new( - "Gets all coins for the address in the request body. Begin listing the coins that are after the provided `cursor` value and return only the `limit` amount of results per page.", - vec![ - ("owner", json!(owner)), - ("cursor", json!(cursor)), - ("limit", json!(limit)), - ], - json!(page), - )], - ) - } - - fn suix_get_balance(&mut self) -> Examples { - let owner = SuiAddress::from(ObjectID::new(self.rng.gen())); - let coin_type = "0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC".to_string(); - let result = Balance { - coin_type: coin_type.clone(), - coin_object_count: 15, - total_balance: 15, - locked_balance: HashMap::new(), - }; - - Examples::new( - "suix_getBalance", - vec![ExamplePairing::new( - "Gets the balance of the specified type of coin for the address in the request.", - vec![("owner", json!(owner)), ("coin_type", json!(coin_type))], - json!(result), - )], - ) - } - - fn suix_get_coin_metadata(&mut self) -> Examples { - let result = SuiCoinMetadata { - decimals: 9, - name: "Usdc".to_string(), - symbol: "USDC".to_string(), - description: "Stable coin.".to_string(), - icon_url: None, - id: Some(ObjectID::new(self.rng.gen())), - }; - - Examples::new( - "suix_getCoinMetadata", - vec![ExamplePairing::new( - "Gets the metadata for the coin type in the request.", - vec![( - "coin_type", - json!("0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC".to_string()), - )], - json!(result), - )], - ) - } - - fn sui_get_latest_checkpoint_sequence_number(&mut self) -> Examples { - let result = "507021"; - Examples::new( - "sui_getLatestCheckpointSequenceNumber", - vec![ExamplePairing::new( - "Gets the sequence number for the latest checkpoint.", - vec![], - json!(result), - )], - ) - } - - fn suix_get_coins(&mut self) -> Examples { - let coin_type = "0x2::sui::SUI".to_string(); - let owner = SuiAddress::from(ObjectID::new(self.rng.gen())); - let coins = (0..3) - .map(|_| Coin { - coin_type: coin_type.clone(), - coin_object_id: ObjectID::new(self.rng.gen()), - version: SequenceNumber::from_u64(103626), - digest: ObjectDigest::new(self.rng.gen()), - balance: 200000000, - // locked_until_epoch: None, - previous_transaction: TransactionDigest::new(self.rng.gen()), - }) - .collect::>(); - - let next_cursor = coins.last().unwrap().coin_object_id; - - let page = CoinPage { - data: coins, - next_cursor: Some(next_cursor), - has_next_page: true, - }; - - Examples::new( - "suix_getCoins", - vec![ExamplePairing::new( - "Gets all SUI coins owned by the address provided. Return a paginated list of `limit` results per page. Similar to `suix_getAllCoins`, but provides a way to filter by coin type.", - vec![ - ("owner", json!(owner)), - ("coin_type", json!(coin_type)), - ("cursor", json!(ObjectID::new(self.rng.gen()))), - ("limit", json!(3)), - ], - json!(page), - )], - ) - } - - fn suix_get_total_supply(&mut self) -> Examples { - let mut coin = ObjectID::new(self.rng.gen()).to_string(); - coin.push_str("::acoin::ACOIN"); - - let result = Supply { value: 12023692 }; - - Examples::new( - "suix_getTotalSupply", - vec![ExamplePairing::new( - "Gets total supply for the type of coin provided.", - vec![("coin_type", json!(coin))], - json!(result), - )], - ) - } - - fn sui_get_loaded_child_objects(&mut self) -> Examples { - let mut sequence = SequenceNumber::from_u64(self.rng.gen_range(24506..6450624)); - let seqs = (0..6) - .map(|x| { - if x % 2 == 0 || x % 3 == 0 { - sequence = SequenceNumber::from_u64(self.rng.gen_range(24506..6450624)); - } - - SuiLoadedChildObject::new(ObjectID::new(self.rng.gen()), sequence) - }) - .collect::>(); - let result = { - SuiLoadedChildObjectsResponse { - loaded_child_objects: seqs, - } - }; - - Examples::new( - "sui_getLoadedChildObjects", - vec![ExamplePairing::new( - "Gets loaded child objects associated with the transaction the request provides.", - vec![("digest", json!(ObjectDigest::new(self.rng.gen())))], - json!(result), - )], - ) - } - - fn sui_get_move_function_arg_types(&mut self) -> Examples { - let result = vec![ - MoveFunctionArgType::Object(ByMutableReference), - MoveFunctionArgType::Pure, - MoveFunctionArgType::Pure, - MoveFunctionArgType::Object(ByValue), - MoveFunctionArgType::Object(ByImmutableReference), - MoveFunctionArgType::Object(ByValue), - MoveFunctionArgType::Object(ByMutableReference), - ]; - - Examples::new( - "sui_getMoveFunctionArgTypes", - vec![ExamplePairing::new( - "Returns the argument types for the package and function the request provides.", - vec![ - ("package", json!(ObjectID::new(self.rng.gen()))), - ("module", json!("suifrens".to_string())), - ("function", json!("mint".to_string())), - ], - json!(result), - )], - ) - } - - fn sui_get_normalized_move_function(&mut self) -> Examples { - let ability_set = SuiMoveAbilitySet { - abilities: vec![SuiMoveAbility::Store, SuiMoveAbility::Key], - }; - - let result = SuiMoveNormalizedFunction { - is_entry: false, - type_parameters: vec![ability_set], - parameters: vec![SuiMoveNormalizedType::U64], - visibility: SuiMoveVisibility::Public, - return_: vec![SuiMoveNormalizedType::U64], - }; - - Examples::new( - "sui_getNormalizedMoveFunction", - vec![ExamplePairing::new( - "Returns the structured representation of the function the request provides.", - vec![ - ("package", json!(ObjectID::new(self.rng.gen()))), - ("module_name", json!("moduleName".to_string())), - ("function_name", json!("functionName".to_string())), - ], - json!(result), - )], - ) - } - - fn sui_get_normalized_move_module(&mut self) -> Examples { - let result = SuiMoveNormalizedModule { - address: ObjectID::new(self.rng.gen()).to_string(), - exposed_functions: BTreeMap::new(), - file_format_version: 6, - friends: vec![], - name: "module".to_string(), - structs: BTreeMap::new(), - }; - - Examples::new( - "sui_getNormalizedMoveModule", - vec![ExamplePairing::new( - "Gets a structured representation of the Move module for the package in the request.", - vec![ - ("package", json!(ObjectID::new(self.rng.gen()))), - ("module_name", json!("module".to_string())), - ], - json!(result), - )], - ) - } - - fn sui_get_normalized_move_modules_by_package(&mut self) -> Examples { - let result = SuiMoveNormalizedModule { - address: ObjectID::new(self.rng.gen()).to_string(), - exposed_functions: BTreeMap::new(), - file_format_version: 6, - friends: vec![], - name: "module".to_string(), - structs: BTreeMap::new(), - }; - - Examples::new( - "sui_getNormalizedMoveModulesByPackage", - vec![ExamplePairing::new( - "Gets structured representations of all the modules for the package in the request.", - vec![("package", json!(ObjectID::new(self.rng.gen())))], - json!(result), - )], - ) - } - - fn sui_get_normalized_move_struct(&mut self) -> Examples { - let abilities = SuiMoveAbilitySet { - abilities: vec![SuiMoveAbility::Store, SuiMoveAbility::Key], - }; - let fields = vec![].into_iter().collect::>(); - let type_parameters = vec![].into_iter().collect::>(); - let result = SuiMoveNormalizedStruct { - abilities, - fields, - type_parameters, - }; - - Examples::new( - "sui_getNormalizedMoveStruct", - vec![ExamplePairing::new( - "Gets a structured representation of the struct in the request.", - vec![ - ("package", json!(ObjectID::new(self.rng.gen()))), - ("module_name", json!("module".to_string())), - ("struct_name", json!("StructName".to_string())), - ], - json!(result), - )], - ) - } - - fn suix_get_validators_apy(&mut self) -> Examples { - let result = vec![ - ValidatorApy { - address: SuiAddress::from(ObjectID::new(self.rng.gen())), - apy: 0.06, - }, - ValidatorApy { - address: SuiAddress::from(ObjectID::new(self.rng.gen())), - apy: 0.02, - }, - ValidatorApy { - address: SuiAddress::from(ObjectID::new(self.rng.gen())), - apy: 0.05, - }, - ]; - - Examples::new( - "suix_getValidatorsApy", - vec![ExamplePairing::new( - "Gets the APY for all validators.", - vec![], - json!(ValidatorApys { - apys: result, - epoch: 420 - }), - )], - ) - } - - fn suix_get_dynamic_fields(&mut self) -> Examples { - let object_id = ObjectID::new(self.rng.gen()); - let dynamic_fields = (0..3) - .map(|_| DynamicFieldInfo { - name: DynamicFieldName { - type_: TypeTag::from_str("0x9::test::TestField").unwrap(), - value: serde_json::Value::String("some_value".to_string()), - }, - bcs_name: bcs::to_bytes("0x9::test::TestField").unwrap(), - type_: DynamicFieldType::DynamicField, - object_type: "test".to_string(), - object_id: ObjectID::new(self.rng.gen()), - version: SequenceNumber::from_u64(1), - digest: ObjectDigest::new(self.rng.gen()), - }) - .collect::>(); - - let next_cursor = ObjectID::new(self.rng.gen()); - - let page = DynamicFieldPage { - data: dynamic_fields, - next_cursor: Some(next_cursor), - has_next_page: true, - }; - - Examples::new( - "suix_getDynamicFields", - vec![ExamplePairing::new( - "Gets dynamic fields for the object the request provides in a paginated list of `limit` dynamic field results per page. The default limit is 50.", - vec![ - ("parent_object_id", json!(object_id)), - ("cursor", json!(ObjectID::new(self.rng.gen()))), - ("limit", json!(3)), - ], - json!(page), - )], - ) - } - - fn suix_get_dynamic_field_object(&mut self) -> Examples { - let parent_object_id = ObjectID::new(self.rng.gen()); - let field_name = DynamicFieldName { - type_: TypeTag::from_str("0x9::test::TestField").unwrap(), - value: serde_json::Value::String("some_value".to_string()), - }; - - let struct_tag = parse_sui_struct_tag("0x9::test::TestField").unwrap(); - let resp = SuiObjectResponse::new_with_data(SuiObjectData { - content: Some( - SuiParsedData::try_from_object( - unsafe { - MoveObject::new_from_execution_with_limit( - MoveObjectType::from(struct_tag.clone()), - true, - SequenceNumber::from_u64(1), - Vec::new(), - 5, - ) - .unwrap() - }, - MoveStructLayout { - type_: struct_tag, - fields: Vec::new(), - }, - ) - .unwrap(), - ), - owner: Some(Owner::AddressOwner(SuiAddress::from(ObjectID::new( - self.rng.gen(), - )))), - previous_transaction: Some(TransactionDigest::new(self.rng.gen())), - storage_rebate: Some(100), - object_id: parent_object_id, - version: SequenceNumber::from_u64(1), - digest: ObjectDigest::new(self.rng.gen()), - type_: Some(ObjectType::Struct(MoveObjectType::from( - parse_sui_struct_tag("0x9::test::TestField").unwrap(), - ))), - bcs: None, - display: None, - }); - Examples::new( - "suix_getDynamicFieldObject", - vec![ExamplePairing::new( - "Gets the information for the dynamic field the request provides.", - vec![ - ("parent_object_id", json!(parent_object_id)), - ("name", json!(field_name)), - ], - json!(resp), - )], - ) - } - - fn suix_get_owned_objects(&mut self) -> Examples { - let owner = SuiAddress::from(ObjectID::new(self.rng.gen())); - let version: u64 = 13488; - let options = Some( - SuiObjectDataOptions::new() - .with_type() - .with_owner() - .with_previous_transaction(), - ); - let filter = Some(SuiObjectDataFilter::MatchAll(vec![ - SuiObjectDataFilter::StructType( - StructTag::from_str("0x2::coin::Coin<0x2::sui::SUI>").unwrap(), - ), - SuiObjectDataFilter::AddressOwner(owner), - SuiObjectDataFilter::Version(version), - ])); - let query = json!(SuiObjectResponseQuery { filter, options }); - let object_id = ObjectID::new(self.rng.gen()); - - let items = (0..3) - .map(|_| { - SuiObjectResponse::new_with_data(SuiObjectData { - content: None, - owner: Some(Owner::AddressOwner(owner)), - previous_transaction: Some(TransactionDigest::new(self.rng.gen())), - storage_rebate: Some(100), - object_id: ObjectID::new(self.rng.gen()), - version: SequenceNumber::from_u64(version), - digest: ObjectDigest::new(self.rng.gen()), - type_: Some(ObjectType::Struct(MoveObjectType::gas_coin())), - bcs: None, - display: None, - }) - }) - .collect::>(); - - let next_cursor = items.last().unwrap().object_id(); - let result = ObjectsPage { - data: items, - next_cursor: Some(next_cursor.unwrap()), - has_next_page: true, - }; - - Examples::new( - "suix_getOwnedObjects", - vec![ExamplePairing::new( - "Returns all the objects the address provided in the request owns and that match the filter. By default, only the digest value is returned, but the request returns additional information by setting the relevant keys to true. A cursor value is also provided, so the list of results begin after that value.", - vec![ - ("address", json!(owner)), - ("query", json!(query)), - ("cursor", json!(object_id)), - ("limit", json!(3)), - ], - json!(result), - )], - ) - } - - fn suix_query_events(&mut self) -> Examples { - let package_id = ObjectID::new(self.rng.gen()); - let identifier = Identifier::from_str("test").unwrap(); - let mut event_ids = self.get_event_ids(5..9); - let has_next_page = event_ids.len() > (9 - 5); - event_ids.truncate(9 - 5); - let next_cursor = event_ids.last().cloned(); - let cursor = event_ids.last().cloned(); - - let data = event_ids - .into_iter() - .map(|event_id| SuiEvent { - id: event_id, - package_id, - transaction_module: identifier.clone(), - sender: SuiAddress::from(ObjectID::new(self.rng.gen())), - type_: StructTag::from_str("0x3::test::Test<0x3::test::Test>").unwrap(), - parsed_json: serde_json::Value::String("some_value".to_string()), - bcs: vec![], - timestamp_ms: None, - }) - .collect(); - - let result = EventPage { - data, - next_cursor, - has_next_page, - }; - Examples::new( - "suix_queryEvents", - vec![ExamplePairing::new( - "Returns the events for a specified query criteria.", - vec![ - ( - "query", - json!(EventFilter::MoveModule { - package: ObjectID::new(self.rng.gen()), - module: Identifier::from_str("test").unwrap(), - }), - ), - ("cursor", json!(cursor)), - ("limit", json!(100)), - ("descending_order", json!(false)), - ], - json!(result), - )], - ) - } - - fn suix_get_latest_sui_system_state(&mut self) -> Examples { - let result = "some_system_state"; - Examples::new( - "suix_getLatestSuiSystemState", - vec![ExamplePairing::new( - "Gets objects owned by the address in the request.", - vec![], - json!(result), - )], - ) - } - - fn sui_get_chain_identifier(&mut self) -> Examples { - let result = "4c78adac".to_string(); - Examples::new( - "sui_getChainIdentifier", - vec![ExamplePairing::new( - "Gets the identifier for the chain receiving the POST.", - vec![], - json!(result), - )], - ) - } - - fn suix_get_stakes(&mut self) -> Examples { - let principal = 200000000000; - let owner = SuiAddress::from(ObjectID::new(self.rng.gen())); - let result = vec![ - DelegatedStake { - validator_address: SuiAddress::from(ObjectID::new(self.rng.gen())), - staking_pool: ObjectID::new(self.rng.gen()), - stakes: vec![ - Stake { - staked_sui_id: ObjectID::new(self.rng.gen()), - stake_request_epoch: 62, - stake_active_epoch: 63, - principal, - status: StakeStatus::Active { - estimated_reward: (principal as f64 * 0.0026) as u64, - }, - }, - Stake { - staked_sui_id: ObjectID::new(self.rng.gen()), - stake_request_epoch: 142, - stake_active_epoch: 143, - principal, - status: StakeStatus::Pending, - }, - ], - }, - DelegatedStake { - validator_address: SuiAddress::from(ObjectID::new(self.rng.gen())), - staking_pool: ObjectID::new(self.rng.gen()), - stakes: vec![Stake { - staked_sui_id: ObjectID::new(self.rng.gen()), - stake_request_epoch: 244, - stake_active_epoch: 245, - principal, - status: StakeStatus::Unstaked, - }], - }, - ]; - - Examples::new( - "suix_getStakes", - vec![ExamplePairing::new( - "Returns the staking information for the address the request provides.", - vec![("owner", json!(owner))], - json!(result), - )], - ) - } - - fn suix_get_stakes_by_ids(&mut self) -> Examples { - let principal = 200000000000; - let stake1 = ObjectID::new(self.rng.gen()); - let stake2 = ObjectID::new(self.rng.gen()); - let result = DelegatedStake { - validator_address: SuiAddress::from(ObjectID::new(self.rng.gen())), - staking_pool: ObjectID::new(self.rng.gen()), - stakes: vec![ - Stake { - staked_sui_id: stake1, - stake_request_epoch: 62, - stake_active_epoch: 63, - principal, - status: StakeStatus::Active { - estimated_reward: (principal as f64 * 0.0026) as u64, - }, - }, - Stake { - staked_sui_id: stake2, - stake_request_epoch: 244, - stake_active_epoch: 245, - principal, - status: StakeStatus::Unstaked, - }, - ], - }; - Examples::new( - "suix_getStakesByIds", - vec![ExamplePairing::new( - "Returns the staking information for the address the request provides.", - vec![("staked_sui_ids", json!(vec![stake1, stake2]))], - json!(result), - )], - ) - } - - fn suix_resolve_name_service_address(&mut self) -> Examples { - let result = ObjectID::new(self.rng.gen()); - Examples::new( - "suix_resolveNameServiceAddress", - vec![ExamplePairing::new( - "Returns the resolved address for the name the request provides.", - vec![("name", json!("example.sui".to_string()))], - json!(result), - )], - ) - } - - fn suix_resolve_name_service_names(&mut self) -> Examples { - let next_cursor = Some(ObjectID::new(self.rng.gen())); - let object_id = ObjectID::new(self.rng.gen()); - let result = Page { - data: vec!["example.sui".to_string()], - next_cursor, - has_next_page: false, - }; - Examples::new( - "suix_resolveNameServiceNames", - vec![ExamplePairing::new( - "Returns the SuiNS name for the address the request provides. Currently, the API returns only the first name in cases where there are multiple. Future support will use the cursor ID and limit values in the request to control pagination of the response for addresses with multiple names.", - vec![ - ("address", json!(object_id)), - ("cursor", json!(next_cursor)), - ("limit", json!(3)), - ], - json!(result), - )], - ) - } - - fn sui_try_multi_get_past_objects(&mut self) -> Examples { - let object_id = ObjectID::new(self.rng.gen()); - let object_id2 = ObjectID::new(self.rng.gen()); - let version = SequenceNumber::from_u64(4); - let version2 = SequenceNumber::from_u64(12); - let objects = vec![ - SuiGetPastObjectRequest { object_id, version }, - SuiGetPastObjectRequest { - object_id: object_id2, - version: version2, - }, - ]; - let coin = GasCoin::new(object_id, 10000); - let coin2 = GasCoin::new(object_id, 20000); - let result = vec![ - SuiPastObjectResponse::VersionFound(SuiObjectData { - content: Some( - SuiParsedData::try_from_object( - coin.to_object(SequenceNumber::from_u64(1)), - GasCoin::layout(), - ) - .unwrap(), - ), - owner: Some(Owner::AddressOwner(SuiAddress::from(ObjectID::new( - self.rng.gen(), - )))), - previous_transaction: Some(TransactionDigest::new(self.rng.gen())), - storage_rebate: Some(100), - object_id, - version: SequenceNumber::from_u64(4), - digest: ObjectDigest::new(self.rng.gen()), - type_: Some(ObjectType::Struct(MoveObjectType::gas_coin())), - bcs: None, - display: None, - }), - SuiPastObjectResponse::VersionFound(SuiObjectData { - content: Some( - SuiParsedData::try_from_object( - coin2.to_object(SequenceNumber::from_u64(4)), - GasCoin::layout(), - ) - .unwrap(), - ), - owner: Some(Owner::AddressOwner(SuiAddress::from(ObjectID::new( - self.rng.gen(), - )))), - previous_transaction: Some(TransactionDigest::new(self.rng.gen())), - storage_rebate: Some(100), - object_id: object_id2, - version: version2, - digest: ObjectDigest::new(self.rng.gen()), - type_: Some(ObjectType::Struct(MoveObjectType::gas_coin())), - bcs: None, - display: None, - }), - ]; - - Examples::new( - "sui_tryMultiGetPastObjects", - vec![ExamplePairing::new( - "Gets Past Object data for a vector of objects.", - vec![ - ("past_objects", json!(objects)), - ("options", json!(SuiObjectDataOptions::full_content())), - ], - json!(result), - )], - ) - } -} diff --git a/crates/sui-open-rpc/src/lib.rs b/crates/sui-open-rpc/src/lib.rs deleted file mode 100644 index 06305550e11..00000000000 --- a/crates/sui-open-rpc/src/lib.rs +++ /dev/null @@ -1,449 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -extern crate core; - -use std::collections::{btree_map::Entry::Occupied, BTreeMap, HashMap}; - -use schemars::{ - gen::{SchemaGenerator, SchemaSettings}, - schema::SchemaObject, - JsonSchema, -}; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use versions::Versioning; - -/// OPEN-RPC documentation following the OpenRPC specification -/// The implementation is partial, only required fields and subset of optional -/// fields in the specification are implemented catered to Sui's need. -#[derive(Serialize, Deserialize, Clone)] -pub struct Project { - openrpc: String, - info: Info, - methods: Vec, - components: Components, - // Method routing for backward compatibility, not part of the open rpc spec. - #[serde(skip)] - pub method_routing: HashMap, -} - -impl Project { - pub fn new( - version: &str, - title: &str, - description: &str, - contact_name: &str, - url: &str, - email: &str, - license: &str, - license_url: &str, - ) -> Self { - let openrpc = "1.2.6".to_string(); - Self { - openrpc, - info: Info { - title: title.to_string(), - description: Some(description.to_string()), - contact: Some(Contact { - name: contact_name.to_string(), - url: Some(url.to_string()), - email: Some(email.to_string()), - }), - license: Some(License { - name: license.to_string(), - url: Some(license_url.to_string()), - }), - version: version.to_owned(), - ..Default::default() - }, - methods: vec![], - components: Components { - content_descriptors: Default::default(), - schemas: Default::default(), - }, - method_routing: Default::default(), - } - } - - pub fn add_module(&mut self, module: Module) { - self.methods.extend(module.methods); - - self.methods.sort_by(|m, n| m.name.cmp(&n.name)); - - self.components.schemas.extend(module.components.schemas); - self.components - .content_descriptors - .extend(module.components.content_descriptors); - self.method_routing.extend(module.method_routing); - } - - pub fn add_examples(&mut self, mut example_provider: BTreeMap>) { - for method in &mut self.methods { - if let Occupied(entry) = example_provider.entry(method.name.clone()) { - let examples = entry.remove(); - let param_names = method - .params - .iter() - .map(|p| p.name.clone()) - .collect::>(); - - // Make sure example's parameters are correct. - for example in examples.iter() { - let example_param_names = example - .params - .iter() - .map(|param| param.name.clone()) - .collect::>(); - assert_eq!( - param_names, example_param_names, - "Provided example parameters doesn't match the function parameters." - ); - } - - method.examples = examples - } else { - println!("No example found for method: {}", method.name); - } - } - } -} - -pub struct Module { - methods: Vec, - components: Components, - method_routing: BTreeMap, -} - -pub struct RpcModuleDocBuilder { - schema_generator: SchemaGenerator, - methods: BTreeMap, - method_routing: BTreeMap, - content_descriptors: BTreeMap, -} - -#[derive(Serialize, Deserialize, Default, Clone)] -pub struct ContentDescriptor { - name: String, - #[serde(skip_serializing_if = "Option::is_none")] - summary: Option, - #[serde(skip_serializing_if = "Option::is_none")] - description: Option, - #[serde(skip_serializing_if = "default")] - required: bool, - schema: SchemaObject, - #[serde(skip_serializing_if = "default")] - deprecated: bool, -} - -#[derive(Serialize, Deserialize, Default, Clone)] -struct Method { - name: String, - #[serde(skip_serializing_if = "Vec::is_empty")] - tags: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - description: Option, - params: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - result: Option, - #[serde(skip_serializing_if = "Vec::is_empty")] - examples: Vec, - #[serde(skip_serializing_if = "std::ops::Not::not")] - deprecated: bool, -} -#[derive(Clone, Debug)] -pub struct MethodRouting { - min: Option, - max: Option, - pub route_to: String, -} - -impl MethodRouting { - pub fn le(version: &str, route_to: &str) -> Self { - Self { - min: None, - max: Some(Versioning::new(version).unwrap()), - route_to: route_to.to_string(), - } - } - - pub fn eq(version: &str, route_to: &str) -> Self { - Self { - min: Some(Versioning::new(version).unwrap()), - max: Some(Versioning::new(version).unwrap()), - route_to: route_to.to_string(), - } - } - - pub fn matches(&self, version: &str) -> bool { - let version = Versioning::new(version); - match (&version, &self.min, &self.max) { - (Some(version), None, Some(max)) => version <= max, - (Some(version), Some(min), None) => version >= min, - (Some(version), Some(min), Some(max)) => version >= min && version <= max, - (_, _, _) => false, - } - } -} - -#[test] -fn test_version_matching() { - let routing = MethodRouting::eq("1.5", "test"); - assert!(routing.matches("1.5")); - assert!(!routing.matches("1.6")); - assert!(!routing.matches("1.4")); - - let routing = MethodRouting::le("1.5", "test"); - assert!(routing.matches("1.5")); - assert!(routing.matches("1.4.5")); - assert!(routing.matches("1.4")); - assert!(routing.matches("1.3")); - - assert!(!routing.matches("1.6")); - assert!(!routing.matches("1.5.1")); -} - -#[derive(Serialize, Deserialize, Default, Clone)] -pub struct ExamplePairing { - name: String, - #[serde(skip_serializing_if = "Option::is_none")] - description: Option, - #[serde(skip_serializing_if = "Option::is_none")] - summary: Option, - params: Vec, - result: Example, -} - -impl ExamplePairing { - pub fn new(name: &str, params: Vec<(&str, Value)>, result: Value) -> Self { - Self { - name: name.to_string(), - description: None, - summary: None, - params: params - .into_iter() - .map(|(name, value)| Example { - name: name.to_string(), - summary: None, - description: None, - value, - }) - .collect(), - result: Example { - name: "Result".to_string(), - summary: None, - description: None, - value: result, - }, - } - } -} - -#[derive(Serialize, Deserialize, Default, Clone)] -pub struct Example { - name: String, - #[serde(skip_serializing_if = "Option::is_none")] - summary: Option, - #[serde(skip_serializing_if = "Option::is_none")] - description: Option, - value: Value, -} - -#[derive(Serialize, Deserialize, Default, Clone)] -struct Tag { - name: String, - #[serde(skip_serializing_if = "Option::is_none")] - summary: Option, - #[serde(skip_serializing_if = "Option::is_none")] - description: Option, -} - -impl Tag { - pub fn new(name: &str) -> Self { - Self { - name: name.to_string(), - summary: None, - description: None, - } - } -} - -#[derive(Serialize, Deserialize, Default, Clone)] -#[serde(rename_all = "camelCase")] -struct Info { - title: String, - #[serde(skip_serializing_if = "Option::is_none")] - description: Option, - #[serde(skip_serializing_if = "Option::is_none")] - terms_of_service: Option, - #[serde(skip_serializing_if = "Option::is_none")] - contact: Option, - #[serde(skip_serializing_if = "Option::is_none")] - license: Option, - version: String, -} - -fn default(value: &T) -> bool -where - T: Default + PartialEq, -{ - value == &T::default() -} - -#[derive(Serialize, Deserialize, Default, Clone)] -struct Contact { - name: String, - #[serde(skip_serializing_if = "Option::is_none")] - url: Option, - #[serde(skip_serializing_if = "Option::is_none")] - email: Option, -} -#[derive(Serialize, Deserialize, Default, Clone)] -struct License { - name: String, - #[serde(skip_serializing_if = "Option::is_none")] - url: Option, -} - -impl Default for RpcModuleDocBuilder { - fn default() -> Self { - let schema_generator = SchemaSettings::default() - .with(|s| { - s.definitions_path = "#/components/schemas/".to_string(); - }) - .into_generator(); - - Self { - schema_generator, - methods: BTreeMap::new(), - method_routing: Default::default(), - content_descriptors: BTreeMap::new(), - } - } -} - -impl RpcModuleDocBuilder { - pub fn build(mut self) -> Module { - Module { - methods: self.methods.into_values().collect(), - components: Components { - content_descriptors: self.content_descriptors, - schemas: self - .schema_generator - .root_schema_for::() - .definitions - .into_iter() - .map(|(name, schema)| (name, schema.into_object())) - .collect::>(), - }, - method_routing: self.method_routing, - } - } - - pub fn add_method_routing( - &mut self, - namespace: &str, - name: &str, - route_to: &str, - comparator: &str, - version: &str, - ) { - let name = format!("{namespace}_{name}"); - let route_to = format!("{namespace}_{route_to}"); - let routing = match comparator { - "<=" => MethodRouting::le(version, &route_to), - "=" => MethodRouting::eq(version, &route_to), - _ => panic!("Unsupported version comparator {comparator}"), - }; - if self.method_routing.insert(name.clone(), routing).is_some() { - panic!("Routing for method [{name}] already exists.") - } - } - - pub fn add_method( - &mut self, - namespace: &str, - name: &str, - params: Vec, - result: Option, - doc: &str, - tag: Option, - deprecated: bool, - ) { - let tags = tag.map(|t| Tag::new(&t)).into_iter().collect::>(); - self.add_method_internal(namespace, name, params, result, doc, tags, deprecated) - } - - pub fn add_subscription( - &mut self, - namespace: &str, - name: &str, - params: Vec, - result: Option, - doc: &str, - tag: Option, - deprecated: bool, - ) { - let mut tags = tag.map(|t| Tag::new(&t)).into_iter().collect::>(); - tags.push(Tag::new("Websocket")); - tags.push(Tag::new("PubSub")); - self.add_method_internal(namespace, name, params, result, doc, tags, deprecated) - } - - fn add_method_internal( - &mut self, - namespace: &str, - name: &str, - params: Vec, - result: Option, - doc: &str, - tags: Vec, - deprecated: bool, - ) { - let description = if doc.trim().is_empty() { - None - } else { - Some(doc.trim().to_string()) - }; - let name = format!("{}_{}", namespace, name); - self.methods.insert( - name.clone(), - Method { - name, - description, - params, - result, - tags, - examples: Vec::new(), - deprecated, - }, - ); - } - - pub fn create_content_descriptor( - &mut self, - name: &str, - summary: Option, - description: Option, - required: bool, - ) -> ContentDescriptor { - let schema = self.schema_generator.subschema_for::().into_object(); - ContentDescriptor { - name: name.replace(' ', ""), - summary, - description, - required, - schema, - deprecated: false, - } - } -} - -#[derive(Serialize, Deserialize, Clone)] -#[serde(rename_all = "camelCase")] -struct Components { - #[serde(skip_serializing_if = "BTreeMap::is_empty")] - content_descriptors: BTreeMap, - #[serde(skip_serializing_if = "BTreeMap::is_empty")] - schemas: BTreeMap, -} diff --git a/crates/sui-oracle/Cargo.toml b/crates/sui-oracle/Cargo.toml deleted file mode 100644 index 2be3fc99b2b..00000000000 --- a/crates/sui-oracle/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "sui-oracle" -version.workspace = true -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow = { version = "1.0.64", features = ["backtrace"] } -clap.workspace = true -prometheus = "0.13.3" -tokio = { workspace = true, features = ["full"] } -tracing = "0.1.36" -once_cell.workspace = true -reqwest = { version = "0.11.13", default_features = false, features = ["blocking", "json", "rustls-tls"] } -serde = { version = "1.0.144", features = ["derive", "rc"] } -serde_json = { version = "1.0.1" } -jsonpath_lib = "0.3.0" -chrono.workspace = true -tap.workspace = true -bcs.workspace = true - -sui-config = { path = "../sui-config" } -sui-json-rpc-types = { path = "../sui-json-rpc-types" } -sui-sdk = { path = "../sui-sdk" } -sui-types = { path = "../sui-types" } -mysten-metrics = { path = "../mysten-metrics" } -telemetry-subscribers.workspace = true - -[dev-dependencies] -sui-keys = { path = "../sui-keys" } -sui-move-build = { path = "../sui-move-build" } -shared-crypto = { path = "../shared-crypto" } -bcs = "0.1.5" -rand = "0.8.5" -dirs = "4.0.0" diff --git a/crates/sui-oracle/README.md b/crates/sui-oracle/README.md deleted file mode 100644 index 88fe6393d8f..00000000000 --- a/crates/sui-oracle/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# sui-oracle - -This oracle is intended to serve as general reference and informational purposes only. We make no representations or warranties of any kind, express or implied, about the completeness, accuracy, reliability, suitability, or availability of the information provided by the oracle. - -Any reliance on such information by a user is strictly at the user’s own risk. We do not assume any responsibility for errors, omissions, or inaccuracies in the information and shall not be liable for any loss or damage arising from or related to its use. - -The information provided through this oracle does not constitute professional, investment or legal advice. diff --git a/crates/sui-oracle/move/oracle/Move.toml b/crates/sui-oracle/move/oracle/Move.toml deleted file mode 100644 index 05c38235009..00000000000 --- a/crates/sui-oracle/move/oracle/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "sui-oracle" -version = "0.0.1" - -[dependencies] -Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "9d0fba4a490e1cf80101bbd4019c7bb1ccfce99b" } - -[addresses] -oracle = "0x0" -sui = "0x2" \ No newline at end of file diff --git a/crates/sui-oracle/move/oracle/sources/data.move b/crates/sui-oracle/move/oracle/sources/data.move deleted file mode 100644 index 75edce5b15a..00000000000 --- a/crates/sui-oracle/move/oracle/sources/data.move +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module oracle::data { - use std::string::String; - - struct Data has drop, copy { - value: T, - metadata: Metadata, - } - - struct Metadata has drop, copy { - ticker: String, - sequence_number: u64, - timestamp: u64, - oracle: address, - /// An identifier for the reading (for example real time of observation, or sequence number of observation on other chain). - identifier: String, - } - - public fun new( - value: T, - ticker: String, - sequence_number: u64, - timestamp: u64, - oracle: address, - identifier: String - ): Data { - Data { - value, - metadata: Metadata { - ticker, - sequence_number, - timestamp, - oracle, - identifier, - }, - } - } - - public fun value(data: &Data): &T { - &data.value - } - - public fun oracle_address(data: &Data): &address { - &data.metadata.oracle - } - - public fun timestamp(data: &Data): u64 { - data.metadata.timestamp - } -} diff --git a/crates/sui-oracle/src/config.rs b/crates/sui-oracle/src/config.rs deleted file mode 100644 index 158328dcabd..00000000000 --- a/crates/sui-oracle/src/config.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::HashMap, net::SocketAddr, time::Duration}; - -use serde::{Deserialize, Serialize}; -use sui_config::Config; -use sui_types::base_types::ObjectID; - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct DataSourceConfig { - pub url: String, - pub json_path: String, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct UploadFeedConfig { - pub submission_interval: Duration, - pub data_source_config: DataSourceConfig, - pub upload_parameters: UploadParameters, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct UploadParameters { - pub write_package_id: ObjectID, - pub write_module_name: String, - pub write_function_name: String, - pub write_data_provider_object_id: ObjectID, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct DownloadFeedConfigs { - pub read_interval: Option, - pub read_feeds: HashMap, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct OracleNodeConfig { - pub gas_object_id: ObjectID, - pub upload_feeds: HashMap>, - pub download_feeds: DownloadFeedConfigs, - - #[serde(default = "default_metrics_address")] - pub metrics_address: SocketAddr, -} - -fn default_metrics_address() -> SocketAddr { - use std::net::{IpAddr, Ipv4Addr}; - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9400) -} - -impl Config for OracleNodeConfig {} diff --git a/crates/sui-oracle/src/lib.rs b/crates/sui-oracle/src/lib.rs deleted file mode 100644 index f673d795971..00000000000 --- a/crates/sui-oracle/src/lib.rs +++ /dev/null @@ -1,710 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::HashMap, - ops::Add, - str::FromStr, - sync::Arc, - time::{Duration, Instant, SystemTime}, -}; - -use chrono::{DateTime, Utc}; -use config::{DownloadFeedConfigs, UploadFeedConfig, UploadParameters}; -use metrics::OracleMetrics; -use mysten_metrics::monitored_scope; -use once_cell::sync::OnceCell; -use prometheus::Registry; -use sui_json_rpc_types::{ - SuiObjectDataOptions, SuiTransactionBlockEffects, SuiTransactionBlockEffectsAPI, - SuiTransactionBlockResponse, SuiTransactionBlockResponseOptions, -}; -use sui_sdk::{ - apis::ReadApi, rpc_types::SuiObjectResponse, wallet_context::WalletContext, SuiClient, -}; -use sui_types::{ - base_types::{random_object_ref, ObjectID, ObjectRef, SuiAddress}, - error::UserInputError, - object::{Object, Owner}, - parse_sui_type_tag, - programmable_transaction_builder::ProgrammableTransactionBuilder, - quorum_driver_types::NON_RECOVERABLE_ERROR_MSG, - transaction::{Argument, CallArg, Command, ObjectArg, Transaction, TransactionData}, - Identifier, -}; -use tap::tap::TapFallible; -use tracing::{debug, error, info, warn}; -pub mod config; -mod metrics; - -// TODO: allow more flexible decimals -const DECIMAL: u8 = 6; -const METRICS_MULTIPLIER: f64 = 10u64.pow(DECIMAL as u32) as f64; -const UPLOAD_FAILURE_RECOVER_SEC: u64 = 10; -static STALE_OBJ_ERROR: OnceCell = OnceCell::new(); - -pub struct OracleNode { - upload_feeds: HashMap>, - gas_obj_id: ObjectID, - download_feeds: DownloadFeedConfigs, - wallet_ctx: WalletContext, - metrics: Arc, -} - -impl OracleNode { - pub fn new( - upload_feeds: HashMap>, - gas_obj_id: ObjectID, - download_feeds: DownloadFeedConfigs, - wallet_ctx: WalletContext, - registry: Registry, - ) -> Self { - Self { - upload_feeds, - gas_obj_id, - download_feeds, - wallet_ctx, - metrics: Arc::new(OracleMetrics::new(®istry)), - } - } - - pub async fn run(mut self) -> anyhow::Result<()> { - info!("Starting OracleNode..."); - let signer_address = self.wallet_ctx.active_address()?; - let client = Arc::new(self.wallet_ctx.get_client().await?); - - let wallet_ctx = Arc::new(self.wallet_ctx); - DataProviderRunner::new( - self.upload_feeds, - self.gas_obj_id, - wallet_ctx, - client.clone(), - signer_address, - self.metrics.clone(), - ) - .await - .spawn(); - - let (sender, mut receiver) = tokio::sync::mpsc::channel(1000); - - // Spawn a reader thread if reader_interval is configured. - if let Some(read_interval) = self.download_feeds.read_interval { - tokio::spawn( - OnChainDataReader { - client: client.clone(), - read_interval, - read_configs: self.download_feeds.read_feeds, - metrics: self.metrics.clone(), - } - .start(sender.clone()), - ); - } - - while let Some((read_feed, object_id, value)) = receiver.recv().await { - info!( - read_feed, - ?object_id, - ?value, - "Received data from on chain reader." - ); - } - - Ok(()) - } -} - -struct DataProviderRunner { - providers: Vec>, - uploader: OnChainDataUploader, -} - -impl DataProviderRunner { - pub async fn new( - upload_feeds: HashMap>, - gas_coin_id: ObjectID, - wallet_ctx: Arc, - client: Arc, - signer_address: SuiAddress, - metrics: Arc, - ) -> Self { - let mut providers = vec![]; - let mut staleness_tolerance = HashMap::new(); - let mut oracle_object_args = HashMap::new(); - let (sender, receiver) = tokio::sync::mpsc::channel(10000); - for (feed_name, upload_feed) in upload_feeds { - for (source_name, data_feed) in upload_feed { - staleness_tolerance.insert( - make_onchain_feed_name(&feed_name, &source_name), - data_feed.submission_interval, - ); - let oracle_obj_id = data_feed.upload_parameters.write_data_provider_object_id; - let data_provider = DataProvider { - feed_name: feed_name.clone(), - source_name: source_name.clone(), - upload_feed: Arc::new(data_feed), - sender: sender.clone(), - metrics: metrics.clone(), - }; - providers.push(Arc::new(data_provider)); - if let std::collections::hash_map::Entry::Vacant(e) = - oracle_object_args.entry(oracle_obj_id) - { - e.insert( - get_object_arg(client.read_api(), oracle_obj_id, true) - .await - .unwrap(), - ); - } - } - } - info!("Staleness tolerance: {:?}", staleness_tolerance); - - let gas_obj_ref = get_gas_obj_ref(client.read_api(), gas_coin_id, signer_address).await; - info!("Gas object: {:?}", gas_obj_ref); - - let uploader = OnChainDataUploader { - wallet_ctx: wallet_ctx.clone(), - client: client.clone(), - receiver, - signer_address, - gas_obj_ref, - staleness_tolerance, - oracle_object_args, - metrics: metrics.clone(), - }; - Self { - providers, - uploader, - } - } - - pub fn spawn(mut self) { - for data_provider in self.providers { - tokio::spawn(async move { - data_provider.run().await; - }); - } - tokio::spawn(async move { - self.uploader.run().await; - }); - } -} - -async fn get_gas_obj_ref( - read_api: &ReadApi, - gas_obj_id: ObjectID, - owner_address: SuiAddress, -) -> ObjectRef { - loop { - match read_api - .get_object_with_options(gas_obj_id, SuiObjectDataOptions::default().with_owner()) - .await - .map(|resp| resp.data) - { - Ok(Some(gas_obj)) => { - assert_eq!( - gas_obj.owner, - Some(Owner::AddressOwner(owner_address)), - "Provided gas obj {:?} does not belong to {}", - gas_obj, - owner_address - ); - return gas_obj.object_ref(); - } - other => { - warn!("Can't get gas object: {:?}: {:?}", gas_obj_id, other); - tokio::time::sleep(Duration::from_secs(5)).await; - } - } - } -} - -struct DataProvider { - pub feed_name: String, - pub source_name: String, - pub upload_feed: Arc, - pub sender: tokio::sync::mpsc::Sender, - metrics: Arc, -} - -impl DataProvider { - pub async fn run(&self) { - info!( - feed_name = self.feed_name, - source_name = self.source_name, - "Starting DataProvider" - ); - let mut interval = tokio::time::interval(self.upload_feed.submission_interval); - interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); - - loop { - interval.tick().await; - self.run_once().await; - } - } - - async fn run_once(&self) { - debug!( - feed_name = self.feed_name, - source_name = self.source_name, - "Running data provider once." - ); - let value = self.retrieve_from_data_source().await; - if value.is_err() { - error!( - feed_name = self.feed_name, - source_name = self.source_name, - "Failed to retrieve data from data source: {:?}", - value - ); - self.metrics - .data_source_errors - .with_label_values(&[&self.feed_name, &self.source_name]) - .inc(); - return; - } - - self.metrics - .data_source_successes - .with_label_values(&[&self.feed_name, &self.source_name]) - .inc(); - - // TODO: allow more flexible multiplers and data types - let value = (value.unwrap() * METRICS_MULTIPLIER) as u64; - self.send_to_uploader(value).await; - } - - async fn retrieve_from_data_source(&self) -> anyhow::Result { - // TODO: support websocket - let url = &self.upload_feed.data_source_config.url; - let json_path = &self.upload_feed.data_source_config.json_path; - let response = reqwest::Client::new().get(url).send().await?; - - if !response.status().is_success() { - anyhow::bail!("Failed to fetch data: {:?}", response); - } - - let json_blob: serde_json::Value = response.json().await.unwrap(); - let data = jsonpath_lib::select(&json_blob, json_path)?; - - if data.is_empty() { - anyhow::bail!( - "Failed to find data from json blob: {:?} with json path: {:?}", - json_blob, - json_path - ); - } - // Assume there is one single value per request - match data[0].as_str() { - Some(value_str) => match value_str.parse::() { - Ok(value) => Ok(value), - Err(_) => anyhow::bail!( - "Failed to parse data {:?} as f64 from json blob: {:?}", - data[0], - json_blob - ), - }, - None => anyhow::bail!( - "Failed to parse data {:?} as string from json blob: {:?}", - data[0], - json_blob - ), - } - } - - async fn send_to_uploader(&self, value: u64) { - let _ = self - .sender - .send(DataPoint { - feed_name: make_onchain_feed_name(&self.feed_name, &self.source_name), - upload_parameters: self.upload_feed.upload_parameters.clone(), - value, - retrieval_timestamp: SystemTime::now(), - retrieval_instant: Instant::now(), - }) - .await - .tap_err(|err| error!("Failed to send data point to uploader: {:?}", err)); - } -} - -fn make_onchain_feed_name(feed_name: &str, source_name: &str) -> String { - format!( - "{}-{}", - feed_name.to_ascii_lowercase(), - source_name.to_ascii_lowercase() - ) -} - -struct OnChainDataUploader { - wallet_ctx: Arc, - client: Arc, - receiver: tokio::sync::mpsc::Receiver, - signer_address: SuiAddress, - gas_obj_ref: ObjectRef, - staleness_tolerance: HashMap, - oracle_object_args: HashMap, - metrics: Arc, -} - -impl OnChainDataUploader { - async fn run(&mut self) { - info!("Starting OnChainDataUploader"); - // The minimal latency is 1 second so we collect data every 1 second - let mut read_interval = tokio::time::interval(Duration::from_millis(500)); - read_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); - loop { - read_interval.tick().await; - let data_points = self.collect().await; - if !data_points.is_empty() { - if let Err(err) = self.upload(data_points).await { - error!( - "Upload failure: {err}. About to resting for {UPLOAD_FAILURE_RECOVER_SEC} sec." - ); - tokio::time::sleep(Duration::from_secs(UPLOAD_FAILURE_RECOVER_SEC)).await; - self.gas_obj_ref = get_gas_obj_ref( - self.client.read_api(), - self.gas_obj_ref.0, - self.signer_address, - ) - .await; - error!("Updated gas object reference: {:?}", self.gas_obj_ref); - } - } - } - } - - async fn collect(&mut self) -> Vec { - let start = Instant::now(); - let mut data_points = vec![]; - while let Ok(Some(data_point)) = - tokio::time::timeout(Duration::from_millis(100), self.receiver.recv()).await - { - let feed_name = &data_point.feed_name; - debug!( - feed_name = data_point.feed_name, - value = data_point.value, - "Received data from data provider." - ); - // TODO: for each source, at most take one value in each submission - let staleness_tolerance = - self.staleness_tolerance.get(feed_name).unwrap_or_else(|| { - panic!("Bug, missing staleness tolerance for feed: {}", feed_name) - }); - let duration_since = data_point.retrieval_instant.elapsed(); - if duration_since > staleness_tolerance.add(Duration::from_secs(1)) { - warn!( - feed_name, - value = data_point.value, - ?duration_since, - ?staleness_tolerance, - "Data is too stale, skipping." - ); - self.metrics - .data_staleness - .with_label_values(&[feed_name]) - .inc(); - } else { - data_points.push(data_point); - } - - // One run only waits for 1 second - // But if we don't have any valid data points, we wait until we do. - if data_points.is_empty() && start.elapsed() >= Duration::from_millis(500) { - break; - } - } - debug!("Collected {} data points", data_points.len()); - data_points - } - - async fn upload( - &mut self, - data_points: Vec, - ) -> anyhow::Result { - let _scope = monitored_scope("Oracle::OnChainDataUploader::upload"); - // TODO add more error handling & polling perhaps - let mut builder = ProgrammableTransactionBuilder::new(); - let mut is_first = true; - for data_point in &data_points { - let package_id = data_point.upload_parameters.write_package_id; - let feed_name = &data_point.feed_name; - let oracle_obj_arg = *self - .oracle_object_args - .get(&data_point.upload_parameters.write_data_provider_object_id) - .unwrap_or_else(|| { - panic!("Bug, missing oracle object arg for feed: {}", feed_name) - }); - let duration_since_start = data_point.retrieval_instant.elapsed(); - let data_point_ts: DateTime = - DateTime::from(data_point.retrieval_timestamp + duration_since_start); - - let mut arguments = if is_first { - vec![ - builder.input(CallArg::Object(oracle_obj_arg)).unwrap(), - builder.input(CallArg::CLOCK_IMM).unwrap(), - ] - } else { - vec![Argument::Input(0), Argument::Input(1)] - }; - - let decimal = builder - .input(CallArg::Pure(bcs::to_bytes(&DECIMAL).unwrap())) - .unwrap(); - let value = builder - .input(CallArg::Pure(bcs::to_bytes(&data_point.value).unwrap())) - .unwrap(); - - arguments.extend_from_slice(&[ - builder - .input(CallArg::Pure(bcs::to_bytes(&feed_name)?)) - .unwrap(), - builder.programmable_move_call( - package_id, - Identifier::from_str("decimal_value").unwrap(), - Identifier::from_str("new").unwrap(), - vec![], - vec![value, decimal], - ), - builder - .input(CallArg::Pure(bcs::to_bytes(&format!("{}", data_point_ts))?)) - .unwrap(), - ]); - - builder.command(Command::move_call( - package_id, - Identifier::new(data_point.upload_parameters.write_module_name.clone()).unwrap(), - Identifier::new(data_point.upload_parameters.write_function_name.clone()).unwrap(), - // TODO: allow more generic data types - vec![ - parse_sui_type_tag(&format!("{package_id}::decimal_value::DecimalValue")) - .unwrap(), - ], - arguments, - )); - is_first = false; - } - let pt = builder.finish(); - let rgp = self - .client - .governance_api() - .get_reference_gas_price() - .await?; - let tx = TransactionData::new_programmable( - self.signer_address, - vec![self.gas_obj_ref], - pt, - // 15_000_000 is a heuristic number - 15_000_000 * data_points.len() as u64, - rgp, - ); - - let signed_tx = self.wallet_ctx.sign_transaction(&tx); - let tx_digest = *signed_tx.digest(); - - let timer_start = Instant::now(); - let response = self.execute(signed_tx).await?; - let time_spend_sec = timer_start.elapsed().as_secs_f32(); - - // We asked for effects. - // But is there a better way to handle this instead of panic? - let effects = response.effects.expect("Expect to see effects in response"); - - // It's critical to update the gas object reference for next transaction - self.gas_obj_ref = effects.gas_object().reference.to_object_ref(); - - let success = effects.status().is_ok(); - - // Update metrics - for data_point in &data_points { - if success { - self.metrics - .upload_successes - .with_label_values(&[&data_point.feed_name]) - .inc(); - self.metrics - .uploaded_values - .with_label_values(&[&data_point.feed_name]) - .observe(data_point.value); - } else { - self.metrics - .upload_data_errors - .with_label_values(&[&data_point.feed_name]) - .inc(); - } - } - - let gas_usage = effects.gas_cost_summary().gas_used(); - let storage_rebate = effects.gas_cost_summary().storage_rebate; - let computation_cost = effects.gas_cost_summary().computation_cost; - let net_gas_usage = effects.gas_cost_summary().net_gas_usage(); - self.metrics.computation_gas_used.observe(computation_cost); - self.metrics.total_gas_cost.inc_by(gas_usage); - self.metrics.total_gas_rebate.inc_by(storage_rebate); - - if success { - self.metrics - .total_data_points_uploaded - .inc_by(data_points.len() as u64); - info!( - ?tx_digest, - net_gas_usage, - time_spend_sec, - "Upload succeeded with {} data points", - data_points.len(), - ); - Ok(effects) - } else { - error!( - ?tx_digest, - net_gas_usage, - "Upload failed with {} data points. Err: {:?}", - data_points.len(), - effects.status(), - ); - anyhow::bail!("Failed to submit data on chain: {:?}", effects.status()); - } - } - - async fn execute(&mut self, tx: Transaction) -> anyhow::Result { - let tx_digest = tx.digest(); - let mut retry_attempts = 3; - loop { - match self - .client - .quorum_driver_api() - .execute_transaction_block( - tx.clone(), - SuiTransactionBlockResponseOptions::new().with_effects(), - // TODO: after 1.4.0, we can simply use `WaitForEffectsCert` which is faster. - // Some(sui_types::quorum_driver_types::ExecuteTransactionRequestType::WaitForEffectsCert), - Some(sui_types::quorum_driver_types::ExecuteTransactionRequestType::WaitForLocalExecution), - ) - .await { - Ok(response) => return Ok(response), - Err(sui_sdk::error::Error::RpcError(err)) => { - // jsonrpsee translate every SuiError into jsonrpsee::core::Error, so we need to further distinguish - if err.to_string().contains(NON_RECOVERABLE_ERROR_MSG) { - let stale_obj_error = STALE_OBJ_ERROR - .get_or_init(|| - String::from(UserInputError::ObjectVersionUnavailableForConsumption { provided_obj_ref: random_object_ref(), current_version: 0.into() }.as_ref()) - ); - if err.to_string().contains(stale_obj_error) { - error!(?tx_digest, "Failed to submit tx, it looks like gas object is stale : {:?}", err); - let new_ref = get_gas_obj_ref(self.client.read_api(), self.gas_obj_ref.0, self.signer_address).await; - self.gas_obj_ref = new_ref; - info!("Gas object updated: {:?}", new_ref); - anyhow::bail!("Gas object is stale, now updated to {:?}. tx_digest={:?}", new_ref, tx_digest); - } else { - error!(?tx_digest, "Failed to submit tx, with non recoverable error: {:?}", err); - anyhow::bail!("Non-retryable error {:?}. tx_digest={:?}", err, tx_digest); - } - } - // Likely retryable error? - error!(?tx_digest, "Failed to submit tx, with (likely) recoverable error: {:?}. Remaining retry times: {}", err, retry_attempts); - retry_attempts -= 1; - if retry_attempts <= 0 { - anyhow::bail!("Too many RPC errors: {}. tx_digest={:?}", err, tx_digest); - } - } - // All other errors are unexpected - Err(err) => { - error!(?tx_digest, "Failed to submit tx, with unexpected error: {:?}", err); - anyhow::bail!("Unexpected error in tx submission {:?}. tx_digest={:?}", err, tx_digest); - } - } - } - } -} - -#[derive(Debug)] -struct DataPoint { - feed_name: String, - upload_parameters: UploadParameters, - value: u64, - retrieval_timestamp: SystemTime, - retrieval_instant: Instant, -} - -struct OnChainDataReader { - pub client: Arc, - // For now we share one read interval for all reads - pub read_interval: Duration, - pub read_configs: HashMap, - metrics: Arc, -} - -impl OnChainDataReader { - pub async fn start(self, sender: tokio::sync::mpsc::Sender<(String, ObjectID, f64)>) { - info!( - "Starting on-chain data reader with interval {:?} and config: {:?}", - self.read_interval, self.read_configs - ); - let mut read_interval = tokio::time::interval(self.read_interval); - read_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); - loop { - read_interval.tick().await; - for (feed_name, object_id) in &self.read_configs { - match self - .client - .read_api() - .get_object_with_options(*object_id, SuiObjectDataOptions::default()) - .await - { - Ok(SuiObjectResponse { - data: Some(_data), .. - }) => { - // TODO parse value based on returned BCS - let value = 5_f64; - let _ = sender.send((feed_name.clone(), *object_id, value)).await; - self.metrics - .downloaded_values - .with_label_values(&[feed_name]) - .observe((value * METRICS_MULTIPLIER) as u64); - self.metrics - .download_successes - .with_label_values(&[feed_name, &object_id.to_string()]) - .inc(); - } - other => { - error!( - read_feed = feed_name, - ?object_id, - "Failed to read data from on-chain: {:?}", - other - ); - self.metrics - .download_data_errors - .with_label_values(&[feed_name, &object_id.to_string()]) - .inc(); - } - } - } - } - } -} - -async fn get_object_arg( - read_api: &ReadApi, - id: ObjectID, - is_mutable_ref: bool, -) -> anyhow::Result { - let response = read_api - .get_object_with_options(id, SuiObjectDataOptions::bcs_lossless()) - .await?; - - let obj: Object = response.into_object()?.try_into()?; - let obj_ref = obj.compute_object_reference(); - let owner = obj.owner; - Ok(match owner { - Owner::Shared { - initial_shared_version, - } => ObjectArg::SharedObject { - id, - initial_shared_version, - mutable: is_mutable_ref, - }, - Owner::AddressOwner(_) | Owner::ObjectOwner(_) | Owner::Immutable => { - ObjectArg::ImmOrOwnedObject(obj_ref) - } - }) -} diff --git a/crates/sui-oracle/src/main.rs b/crates/sui-oracle/src/main.rs deleted file mode 100644 index a3fb31feba8..00000000000 --- a/crates/sui-oracle/src/main.rs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{path::PathBuf, time::Duration}; - -use clap::Parser; -use mysten_metrics::start_prometheus_server; -use sui_config::Config; -use sui_oracle::{config::OracleNodeConfig, OracleNode}; -use sui_sdk::wallet_context::WalletContext; - -#[derive(Parser)] -#[clap(rename_all = "kebab-case")] -#[clap(name = env!("CARGO_BIN_NAME"))] -struct Args { - #[clap(long)] - pub oracle_config_path: PathBuf, - #[clap(long)] - pub client_config_path: PathBuf, -} - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - let args = Args::parse(); - - let config = OracleNodeConfig::load(&args.oracle_config_path)?; - - let wallet_ctx = WalletContext::new( - &args.client_config_path, - // TODO make this configurable - Some(Duration::from_secs(10)), // request times out after 10 secs - None, - )?; - - // Init metrics server - let registry_service = start_prometheus_server(config.metrics_address); - let prometheus_registry = registry_service.default_registry(); - - // Init logging - let (_guard, _filter_handle) = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .with_prom_registry(&prometheus_registry) - .init(); - - OracleNode::new( - config.upload_feeds, - config.gas_object_id, - config.download_feeds, - wallet_ctx, - prometheus_registry, - ) - .run() - .await?; - - Ok(()) -} diff --git a/crates/sui-oracle/src/metrics.rs b/crates/sui-oracle/src/metrics.rs deleted file mode 100644 index 02da8f14e45..00000000000 --- a/crates/sui-oracle/src/metrics.rs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use mysten_metrics::histogram::{Histogram, HistogramVec}; -use prometheus::{ - register_int_counter_vec_with_registry, register_int_counter_with_registry, IntCounter, - IntCounterVec, Registry, -}; - -#[derive(Clone)] -pub struct OracleMetrics { - pub(crate) data_source_successes: IntCounterVec, - pub(crate) data_source_errors: IntCounterVec, - pub(crate) data_staleness: IntCounterVec, - pub(crate) upload_successes: IntCounterVec, - pub(crate) upload_data_errors: IntCounterVec, - pub(crate) download_successes: IntCounterVec, - pub(crate) download_data_errors: IntCounterVec, - pub(crate) uploaded_values: HistogramVec, - pub(crate) downloaded_values: HistogramVec, - - pub(crate) total_gas_cost: IntCounter, - pub(crate) total_gas_rebate: IntCounter, - pub(crate) computation_gas_used: Histogram, - pub(crate) total_data_points_uploaded: IntCounter, -} - -impl OracleMetrics { - pub fn new(registry: &Registry) -> Self { - Self { - data_source_successes: register_int_counter_vec_with_registry!( - "oracle_data_source_successes", - "Total number of successful data retrieval requests to data sources", - &["feed", "source"], - registry, - ) - .unwrap(), - data_source_errors: register_int_counter_vec_with_registry!( - "oracle_data_source_errors", - "Total number of erroneous data retrieval requests to data sources", - &["feed", "source"], - registry, - ) - .unwrap(), - data_staleness: register_int_counter_vec_with_registry!( - "oracle_data_staleness", - "Total number of stale data that are skipped", - &["feed"], - registry, - ) - .unwrap(), - upload_successes: register_int_counter_vec_with_registry!( - "oracle_upload_successes", - "Total number of successful data upload", - &["feed"], - registry, - ) - .unwrap(), - upload_data_errors: register_int_counter_vec_with_registry!( - "oracle_upload_data_errors", - "Total number of erroneous data upload", - &["feed"], - registry, - ) - .unwrap(), - download_successes: register_int_counter_vec_with_registry!( - "oracle_download_successes", - "Total number of successful data download", - &["feed", "object_id"], - registry, - ) - .unwrap(), - download_data_errors: register_int_counter_vec_with_registry!( - "oracle_download_data_errors", - "Total number of erroneous data download", - &["feed", "object_id"], - registry, - ) - .unwrap(), - uploaded_values: HistogramVec::new_in_registry( - "oracle_uploaded_values", - "Values uploaded on chain", - &["feed"], - registry, - ), - downloaded_values: HistogramVec::new_in_registry( - "oracle_downloaded_values", - "Values downloaded on chain", - &["feed"], - registry, - ), - total_gas_cost: register_int_counter_with_registry!( - "oracle_total_gas_cost", - "Total number of gas used, before gas rebate", - registry, - ) - .unwrap(), - total_gas_rebate: register_int_counter_with_registry!( - "oracle_total_gas_rebate", - "Total number of gas rebate", - registry, - ) - .unwrap(), - computation_gas_used: Histogram::new_in_registry( - "oracle_computation_gas_used", - "computation gas used", - registry, - ), - total_data_points_uploaded: register_int_counter_with_registry!( - "oracle_total_data_points_uploaded", - "Total number of data points uploaded", - registry, - ) - .unwrap(), - } - } -} diff --git a/crates/sui-oracle/tests/data/Test/Move.toml b/crates/sui-oracle/tests/data/Test/Move.toml deleted file mode 100644 index 71c4c71ec02..00000000000 --- a/crates/sui-oracle/tests/data/Test/Move.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "test" -version = "0.0.1" - -[dependencies] -Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "9d0fba4a490e1cf80101bbd4019c7bb1ccfce99b" } -sui-oracle = { local = "../../../move/oracle" } - -[addresses] -test = "0x0" -sui = "0x2" \ No newline at end of file diff --git a/crates/sui-oracle/tests/data/Test/sources/test_module.move b/crates/sui-oracle/tests/data/Test/sources/test_module.move deleted file mode 100644 index 6fe6b441988..00000000000 --- a/crates/sui-oracle/tests/data/Test/sources/test_module.move +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module test::test_module { - - use std::option; - use std::option::Option; - use std::string; - - use oracle::data; - use oracle::data::Data; - use oracle::decimal_value; - use oracle::decimal_value::DecimalValue; - use oracle::meta_oracle; - use oracle::simple_oracle; - use oracle::simple_oracle::SimpleOracle; - use sui::object; - use sui::object::UID; - use sui::transfer; - use sui::tx_context; - use sui::tx_context::TxContext; - - struct MockUSD has key, store { - id: UID, - amount: u64, - decimals: u8, - } - - public fun simple_fx_ptb(single_data: Option>, mist_amount: u64, ctx: &mut TxContext) { - let single_data = option::destroy_some(single_data); - let value = data::value(&single_data); - let decimals = decimal_value::decimal(value); - let value = decimal_value::value(value); - - let amount = mist_amount * value; - let usd = MockUSD { - id: object::new(ctx), - amount, - decimals, - }; - transfer::transfer(usd, tx_context::sender(ctx)); - } - - public fun simple_fx(oracle: &SimpleOracle, mist_amount: u64, ctx: &mut TxContext) { - let single_data = simple_oracle::get_latest_data(oracle, string::utf8(b"SUIUSD")); - let single_data = option::destroy_some(single_data); - let value = data::value(&single_data); - let decimals = decimal_value::decimal(value); - let value = decimal_value::value(value); - - let amount = mist_amount * value; - let usd = MockUSD { - id: object::new(ctx), - amount, - decimals, - }; - transfer::transfer(usd, tx_context::sender(ctx)); - } - - public fun trusted_fx( - oracle1: &SimpleOracle, - oracle2: &SimpleOracle, - oracle3: &SimpleOracle, - mist_amount: u64, - ctx: &mut TxContext - ) { - let meta_oracle = meta_oracle::new(3, 60000, string::utf8(b"SUIUSD")); - meta_oracle::add_simple_oracle(&mut meta_oracle, oracle1); - meta_oracle::add_simple_oracle(&mut meta_oracle, oracle2); - meta_oracle::add_simple_oracle(&mut meta_oracle, oracle3); - - let trusted_data = meta_oracle::median(meta_oracle); - let value = meta_oracle::value(&trusted_data); - let decimals = decimal_value::decimal(value); - let value = decimal_value::value(value); - - let amount = mist_amount * value; - let usd = MockUSD { - id: object::new(ctx), - amount, - decimals, - }; - transfer::transfer(usd, tx_context::sender(ctx)); - } -} diff --git a/crates/sui-package-resolver/Cargo.toml b/crates/sui-package-resolver/Cargo.toml deleted file mode 100644 index da71b10eb35..00000000000 --- a/crates/sui-package-resolver/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "sui-package-resolver" -version = "0.1.0" -edition = "2021" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -async-trait.workspace = true -bcs.workspace = true -move-binary-format.workspace = true -move-core-types.workspace = true -sui-types.workspace = true -thiserror.workspace = true -sui-rest-api.workspace = true -tokio.workspace = true -eyre.workspace = true -serde.workspace = true -lru.workspace = true - -[dev-dependencies] -hyper.workspace = true -insta.workspace = true -move-compiler.workspace = true -serde_json.workspace = true -sui-move-build.workspace = true -tower.workspace = true diff --git a/crates/sui-package-resolver/src/error.rs b/crates/sui-package-resolver/src/error.rs deleted file mode 100644 index af06bbc3832..00000000000 --- a/crates/sui-package-resolver/src/error.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use move_binary_format::errors::VMError; -use move_core_types::account_address::AccountAddress; -use sui_types::TypeTag; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum Error { - #[error("{0}")] - Bcs(#[from] bcs::Error), - - #[error("Store {} error: {}", store, source)] - Store { - store: &'static str, - source: Box, - }, - - #[error("{0}")] - Deserialize(VMError), - - #[error("Package has no modules: {0}")] - EmptyPackage(AccountAddress), - - #[error("Function not found: {0}::{1}::{2}")] - FunctionNotFound(AccountAddress, String, String), - - #[error( - "Conflicting types for input {0}: {} and {}", - .1.to_canonical_display(/* with_prefix */ true), - .2.to_canonical_display(/* with_prefix */ true), - )] - InputTypeConflict(u16, TypeTag, TypeTag), - - #[error("Linkage not found for package: {0}")] - LinkageNotFound(AccountAddress), - - #[error("Module not found: {0}::{1}")] - ModuleNotFound(AccountAddress, String), - - #[error("No origin package found for {0}::{1}::{2}")] - NoTypeOrigin(AccountAddress, String, String), - - #[error("Not a package: {0}")] - NotAPackage(AccountAddress), - - #[error("Not an identifier: '{0}'")] - NotAnIdentifier(String), - - #[error("Package not found: {0}")] - PackageNotFound(AccountAddress), - - #[error("Struct not found: {0}::{1}::{2}")] - StructNotFound(AccountAddress, String, String), - - #[error("More than {0} struct definitions required to resolve type")] - TooManyTypeNodes(usize, usize), - - #[error("Expected at most {0} type parameters, got {1}")] - TooManyTypeParams(usize, usize), - - #[error("Expected {0} type parameters, but got {1}")] - TypeArityMismatch(usize, usize), - - #[error("Type parameter nesting exceeded limit of {0}")] - TypeParamNesting(usize, usize), - - #[error("Type Parameter {0} out of bounds ({1})")] - TypeParamOOB(u16, usize), - - #[error("Unexpected reference type.")] - UnexpectedReference, - - #[error("Unexpected type: 'signer'.")] - UnexpectedSigner, - - #[error("Unexpected error: {0}")] - UnexpectedError(Box), - - #[error("Type layout nesting exceeded limit of {0}")] - ValueNesting(usize), -} diff --git a/crates/sui-package-resolver/src/lib.rs b/crates/sui-package-resolver/src/lib.rs deleted file mode 100644 index 5313c717d9f..00000000000 --- a/crates/sui-package-resolver/src/lib.rs +++ /dev/null @@ -1,2553 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - borrow::Cow, - collections::{btree_map::Entry, BTreeMap, BTreeSet}, - num::NonZeroUsize, - sync::{Arc, Mutex}, -}; - -use async_trait::async_trait; -use lru::LruCache; -use move_binary_format::{ - access::ModuleAccess, - errors::Location, - file_format::{ - AbilitySet, FunctionDefinitionIndex, Signature as MoveSignature, SignatureIndex, - SignatureToken, StructDefinitionIndex, StructFieldInformation, StructHandleIndex, - StructTypeParameter, TableIndex, Visibility, - }, - CompiledModule, -}; -use move_core_types::{ - account_address::AccountAddress, - annotated_value::{MoveFieldLayout, MoveStructLayout, MoveTypeLayout}, - language_storage::{StructTag, TypeTag}, -}; -use sui_types::{ - base_types::{is_primitive_type_tag, SequenceNumber}, - is_system_package, - move_package::TypeOrigin, - object::Object, - transaction::{Argument, CallArg, Command, ProgrammableTransaction}, - Identifier, -}; - -use crate::error::Error; - -pub mod error; - -// TODO Move to ServiceConfig - -const PACKAGE_CACHE_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(1024) }; - -pub type Result = std::result::Result; - -/// The Resolver is responsible for providing information about types. It relies -/// on its internal `package_store` to load packages and then type definitions -/// from those packages. -#[derive(Debug)] -pub struct Resolver { - package_store: S, - limits: Option, -} - -/// Optional configuration that imposes limits on the work that the resolver can -/// do for each request. -#[derive(Debug)] -pub struct Limits { - /// Maximum recursion depth through type parameters. - pub max_type_argument_depth: usize, - /// Maximum number of type arguments in a single type instantiation. - pub max_type_argument_width: usize, - /// Maximum size for the resolution context. - pub max_type_nodes: usize, - /// Maximum recursion depth through struct fields. - pub max_move_value_depth: usize, -} - -/// Store which fetches package for the given address from the backend db and -/// caches it locally in an lru cache. On every call to `fetch` it checks -/// backend db and if package version is stale locally, it updates the local -/// state before returning to the user -pub struct PackageStoreWithLruCache { - pub(crate) packages: Mutex>>, - pub(crate) inner: T, -} - -#[derive(Clone, Debug)] -pub struct Package { - /// The ID this package was loaded from on-chain. - storage_id: AccountAddress, - - /// The ID that this package is associated with at runtime. Bytecode in - /// other packages refers to types and functions from this package using - /// this ID. - runtime_id: AccountAddress, - - /// The package's transitive dependencies as a mapping from the package's - /// runtime ID (the ID it is referred to by in other packages) to its - /// storage ID (the ID it is loaded from on chain). - linkage: Linkage, - - /// The version this package was loaded at -- necessary for cache - /// invalidation of system packages. - version: SequenceNumber, - - modules: BTreeMap, -} - -type Linkage = BTreeMap; - -#[derive(Clone, Debug)] -pub struct Module { - bytecode: CompiledModule, - - /// Index mapping struct names to their defining ID, and the index for their - /// definition in the bytecode, to speed up definition lookups. - struct_index: BTreeMap, - - /// Index mapping function names to the index for their definition in the - /// bytecode, to speed up definition lookups. - function_index: BTreeMap, -} - -/// Deserialized representation of a struct definition. -#[derive(Debug)] -pub struct StructDef { - /// The storage ID of the package that first introduced this type. - pub defining_id: AccountAddress, - - /// This type's abilities. - pub abilities: AbilitySet, - - /// Ability constraints and phantom status for type parameters - pub type_params: Vec, - - /// Serialized representation of fields (names and deserialized signatures). - /// Signatures refer to packages at their runtime IDs (not their storage - /// ID or defining ID). - pub fields: Vec<(String, OpenSignatureBody)>, -} - -/// Deserialized representation of a function definition -#[derive(Debug)] -pub struct FunctionDef { - /// Whether the function is `public`, `private` or `public(friend)`. - pub visibility: Visibility, - - /// Whether the function is marked `entry` or not. - pub is_entry: bool, - - /// Ability constraints for type parameters - pub type_params: Vec, - - /// Formal parameter types. - pub parameters: Vec, - - /// Return types. - pub return_: Vec, -} - -/// Fully qualified struct identifier. Uses copy-on-write strings so that when -/// it is used as a key to a map, an instance can be created to query the map -/// without having to allocate strings on the heap. -#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Hash)] -pub struct DatatypeRef<'m, 'n> { - pub package: AccountAddress, - pub module: Cow<'m, str>, - pub name: Cow<'n, str>, -} - -/// A `StructRef` that owns its strings. -pub type DatatypeKey = DatatypeRef<'static, 'static>; - -#[derive(Copy, Clone, Debug)] -pub enum Reference { - Immutable, - Mutable, -} - -/// A function parameter or return signature, with its type parameters -/// instantiated. -#[derive(Clone, Debug)] -pub struct Signature { - pub ref_: Option, - pub body: TypeTag, -} - -/// Deserialized representation of a type signature that could appear as a -/// function parameter or return. -#[derive(Clone, Debug)] -pub struct OpenSignature { - pub ref_: Option, - pub body: OpenSignatureBody, -} - -/// Deserialized representation of a type signature that could appear as a field -/// type for a struct. -#[derive(Clone, Debug)] -pub enum OpenSignatureBody { - Address, - Bool, - U8, - U16, - U32, - U64, - U128, - U256, - Vector(Box), - Datatype(DatatypeKey, Vec), - TypeParameter(u16), -} - -/// Information necessary to convert a type tag into a type layout. -#[derive(Debug, Default)] -struct ResolutionContext<'l> { - /// Definitions (field information) for structs referred to by types added - /// to this context. - structs: BTreeMap, - /// Limits configuration from the calling resolver. - limits: Option<&'l Limits>, -} - -/// Interface to abstract over access to a store of live packages. Used to -/// override the default store during testing. -#[async_trait] -pub trait PackageStore: Send + Sync + 'static { - /// Latest version of the object at `id`. - async fn version(&self, id: AccountAddress) -> Result; - /// Read package contents. Fails if `id` is not an object, not a package, or - /// is malformed in some way. - async fn fetch(&self, id: AccountAddress) -> Result>; -} - -macro_rules! as_ref_impl { - ($type:ty) => { - #[async_trait] - impl PackageStore for $type { - async fn version(&self, id: AccountAddress) -> Result { - self.as_ref().version(id).await - } - async fn fetch(&self, id: AccountAddress) -> Result> { - self.as_ref().fetch(id).await - } - } - }; -} - -as_ref_impl!(Arc); -as_ref_impl!(Box); - -/// Check $value does not exceed $limit in config, if the limit config exists, -/// returning an error containing the max value and actual value otherwise. -macro_rules! check_max_limit { - ($err:ident, $config:expr; $limit:ident $op:tt $value:expr) => { - if let Some(l) = $config { - let max = l.$limit; - let val = $value; - if !(max $op val) { - return Err(Error::$err(max, val)); - } - } - }; -} - -impl Resolver { - pub fn new(package_store: S) -> Self { - Self { - package_store, - limits: None, - } - } - - pub fn new_with_limits(package_store: S, limits: Limits) -> Self { - Self { - package_store, - limits: Some(limits), - } - } - - pub fn package_store(&self) -> &S { - &self.package_store - } - - pub fn package_store_mut(&mut self) -> &mut S { - &mut self.package_store - } -} - -impl Resolver { - /// Return the type layout corresponding to the given type tag. The layout - /// always refers to structs in terms of their defining ID (i.e. their - /// package ID always points to the first package that introduced them). - pub async fn type_layout(&self, mut tag: TypeTag) -> Result { - let mut context = ResolutionContext::new(self.limits.as_ref()); - - // (1). Fetch all the information from this store that is necessary to resolve - // types referenced by this tag. - context - .add_type_tag( - &mut tag, - &self.package_store, - // visit_fields - true, - // visit_phantoms - true, - ) - .await?; - - // (2). Use that information to resolve the tag into a layout. - let max_depth = self - .limits - .as_ref() - .map_or(usize::MAX, |l| l.max_move_value_depth); - - Ok(context.resolve_type_layout(&tag, max_depth)?.0) - } - - /// Return the abilities of a concrete type, based on the abilities in its - /// type definition, and the abilities of its concrete type parameters: - /// An instance of a generic type has `store`, `copy, or `drop` if its - /// definition has the ability, and all its non-phantom type parameters - /// have the ability as well. Similar rules apply for `key` except that it - /// requires its type parameters to have `store`. - pub async fn abilities(&self, mut tag: TypeTag) -> Result { - let mut context = ResolutionContext::new(self.limits.as_ref()); - - // (1). Fetch all the information from this store that is necessary to resolve - // types referenced by this tag. - context - .add_type_tag( - &mut tag, - &self.package_store, - // visit_fields - false, - // visit_phantoms - false, - ) - .await?; - - // (2). Use that information to calculate the type's abilities. - context.resolve_abilities(&tag) - } - - /// Returns the signatures of parameters to function `pkg::module::function` - /// in the package store, assuming the function exists. - pub async fn function_parameters( - &self, - pkg: AccountAddress, - module: &str, - function: &str, - ) -> Result> { - let mut context = ResolutionContext::new(self.limits.as_ref()); - - let package = self.package_store.fetch(pkg).await?; - let Some(def) = package.module(module)?.function_def(function)? else { - return Err(Error::FunctionNotFound( - pkg, - module.to_string(), - function.to_string(), - )); - }; - - let mut sigs = def.parameters.clone(); - - // (1). Fetch all the information from this store that is necessary to resolve - // types referenced by this tag. - for sig in &sigs { - context - .add_signature( - sig.body.clone(), - &self.package_store, - package.as_ref(), - // visit_fields - false, - ) - .await?; - } - - // (2). Use that information to relocate package IDs in the signature. - for sig in &mut sigs { - context.relocate_signature(&mut sig.body)?; - } - - Ok(sigs) - } - - /// Attempts to infer the type layouts for pure inputs to the programmable - /// transaction. - /// - /// The returned vector contains an element for each input to `tx`. Elements - /// corresponding to pure inputs that are used as arguments to - /// transaction commands will contain `Some(layout)`. Elements for other - /// inputs (non-pure inputs, and unused pure inputs) will be `None`. - /// - /// Layout resolution can fail if a type/module/package doesn't exist, if - /// layout resolution hits a limit, or if a pure input is somehow used - /// in multiple conflicting occasions (with different types). - pub async fn pure_input_layouts( - &self, - tx: &ProgrammableTransaction, - ) -> Result>> { - let mut tags = vec![None; tx.inputs.len()]; - let mut register_type = |arg: &Argument, tag: &TypeTag| { - let &Argument::Input(ix) = arg else { - return Ok(()); - }; - - if !matches!(tx.inputs.get(ix as usize), Some(CallArg::Pure(_))) { - return Ok(()); - } - - let Some(type_) = tags.get_mut(ix as usize) else { - return Ok(()); - }; - - if let Some(prev) = type_.replace(tag.clone()) { - // SAFETY: We just inserted `tag` in here. - let curr = type_.take().unwrap(); - return Err(Error::InputTypeConflict(ix, prev, curr)); - }; - - Ok(()) - }; - - // (1). Infer type tags for pure inputs from their uses. - for cmd in &tx.commands { - match cmd { - Command::MoveCall(call) => { - let params = self - .function_parameters( - call.package.into(), - call.module.as_str(), - call.function.as_str(), - ) - .await?; - - for (open_sig, arg) in params.iter().zip(call.arguments.iter()) { - let sig = open_sig.instantiate(&call.type_arguments)?; - register_type(arg, &sig.body)?; - } - } - - Command::TransferObjects(_, arg) => register_type(arg, &TypeTag::Address)?, - - Command::SplitCoins(_, amounts) => { - for amount in amounts { - register_type(amount, &TypeTag::U64)?; - } - } - - Command::MakeMoveVec(Some(tag), elems) if is_primitive_type_tag(tag) => { - for elem in elems { - register_type(elem, tag)?; - } - } - - _ => { /* nop */ } - } - } - - // (2). Gather all the unique type tags to convert into layouts. There are - // relatively few primitive types so this is worth doing to avoid - // redundant work. - let unique_tags: BTreeSet<_> = tags.iter().filter_map(|t| t.clone()).collect(); - - // (3). Convert the type tags into layouts. - let mut layouts = BTreeMap::new(); - for tag in unique_tags { - let layout = self.type_layout(tag.clone()).await?; - layouts.insert(tag, layout); - } - - // (4) Prepare the result vector. - Ok(tags - .iter() - .map(|t| t.as_ref().and_then(|t| layouts.get(t).cloned())) - .collect()) - } -} - -impl PackageStoreWithLruCache { - pub fn new(inner: T) -> Self { - let packages = Mutex::new(LruCache::new(PACKAGE_CACHE_SIZE)); - Self { packages, inner } - } -} - -#[async_trait] -impl PackageStore for PackageStoreWithLruCache { - async fn version(&self, id: AccountAddress) -> Result { - self.inner.version(id).await - } - - async fn fetch(&self, id: AccountAddress) -> Result> { - let candidate = { - // Release the lock after getting the package - let mut packages = self.packages.lock().unwrap(); - packages.get(&id).map(Arc::clone) - }; - - // System packages can be invalidated in the cache if a newer version exists. - match candidate { - Some(package) if !is_system_package(id) => return Ok(package), - Some(package) if self.version(id).await? <= package.version => return Ok(package), - Some(_) | None => { /* nop */ } - } - - let package = self.inner.fetch(id).await?; - // Try and insert the package into the cache, accounting for races. In most - // cases the racing fetches will produce the same package, but for - // system packages, they may not, so favour the package that has the - // newer version, or if they are the same, the package that is already - // in the cache. - - let mut packages = self.packages.lock().unwrap(); - Ok(match packages.peek(&id) { - Some(prev) if package.version <= prev.version => { - let package = prev.clone(); - packages.promote(&id); - package - } - - Some(_) | None => { - packages.push(id, package.clone()); - package - } - }) - } -} - -impl Package { - pub fn read(object: &Object) -> Result { - let storage_id = AccountAddress::from(object.id()); - let Some(package) = object.data.try_as_package() else { - return Err(Error::NotAPackage(storage_id)); - }; - - let mut type_origins: BTreeMap> = BTreeMap::new(); - for TypeOrigin { - module_name, - struct_name, - package, - } in package.type_origin_table() - { - type_origins - .entry(module_name.to_string()) - .or_default() - .insert(struct_name.to_string(), AccountAddress::from(*package)); - } - - let mut runtime_id = None; - let mut modules = BTreeMap::new(); - for (name, bytes) in package.serialized_module_map() { - let origins = type_origins.remove(name).unwrap_or_default(); - let bytecode = CompiledModule::deserialize_with_defaults(bytes) - .map_err(|e| Error::Deserialize(e.finish(Location::Undefined)))?; - - runtime_id = Some(*bytecode.address()); - - let name = name.clone(); - match Module::read(bytecode, origins) { - Ok(module) => modules.insert(name, module), - Err(struct_) => return Err(Error::NoTypeOrigin(storage_id, name, struct_)), - }; - } - - let Some(runtime_id) = runtime_id else { - return Err(Error::EmptyPackage(storage_id)); - }; - - let linkage = package - .linkage_table() - .iter() - .map(|(&dep, linkage)| (dep.into(), linkage.upgraded_id.into())) - .collect(); - - Ok(Package { - storage_id, - runtime_id, - version: package.version(), - modules, - linkage, - }) - } - - pub fn module(&self, module: &str) -> Result<&Module> { - self.modules - .get(module) - .ok_or_else(|| Error::ModuleNotFound(self.storage_id, module.to_string())) - } - - pub fn modules(&self) -> &BTreeMap { - &self.modules - } - - fn struct_def(&self, module_name: &str, struct_name: &str) -> Result { - let module = self.module(module_name)?; - let Some(struct_def) = module.struct_def(struct_name)? else { - return Err(Error::StructNotFound( - self.storage_id, - module_name.to_string(), - struct_name.to_string(), - )); - }; - - Ok(struct_def) - } - - /// Translate the `runtime_id` of a package to a specific storage ID using - /// this package's linkage table. Returns an error if the package in - /// question is not present in the linkage table. - fn relocate(&self, runtime_id: AccountAddress) -> Result { - // Special case the current package, because it doesn't get an entry in the - // linkage table. - if runtime_id == self.runtime_id { - return Ok(self.storage_id); - } - - self.linkage - .get(&runtime_id) - .ok_or_else(|| Error::LinkageNotFound(runtime_id)) - .copied() - } -} - -impl Module { - /// Deserialize a module from its bytecode, and a table containing the - /// origins of its structs. Fails if the origin table is missing an - /// entry for one of its types, returning the name of the type in that - /// case. - fn read( - bytecode: CompiledModule, - mut origins: BTreeMap, - ) -> std::result::Result { - let mut struct_index = BTreeMap::new(); - for (index, def) in bytecode.struct_defs.iter().enumerate() { - let sh = bytecode.struct_handle_at(def.struct_handle); - let struct_ = bytecode.identifier_at(sh.name).to_string(); - let index = StructDefinitionIndex::new(index as TableIndex); - - let Some(defining_id) = origins.remove(&struct_) else { - return Err(struct_); - }; - - struct_index.insert(struct_, (defining_id, index)); - } - - let mut function_index = BTreeMap::new(); - for (index, def) in bytecode.function_defs.iter().enumerate() { - let fh = bytecode.function_handle_at(def.function); - let function = bytecode.identifier_at(fh.name).to_string(); - let index = FunctionDefinitionIndex::new(index as TableIndex); - - function_index.insert(function, index); - } - - Ok(Module { - bytecode, - struct_index, - function_index, - }) - } - - pub fn bytecode(&self) -> &CompiledModule { - &self.bytecode - } - - /// The module's name - pub fn name(&self) -> &str { - self.bytecode - .identifier_at(self.bytecode.self_handle().name) - .as_str() - } - - /// Iterate over the structs with names strictly after `after` (or from the - /// beginning), and strictly before `before` (or to the end). - pub fn structs( - &self, - after: Option<&str>, - before: Option<&str>, - ) -> impl DoubleEndedIterator + Clone { - use std::ops::Bound as B; - self.struct_index - .range::(( - after.map_or(B::Unbounded, B::Excluded), - before.map_or(B::Unbounded, B::Excluded), - )) - .map(|(name, _)| name.as_str()) - } - - /// Get the struct definition corresponding to the struct with name `name` - /// in this module. Returns `Ok(None)` if the struct cannot be found in - /// this module, `Err(...)` if there was an error deserializing it, and - /// `Ok(Some(def))` on success. - pub fn struct_def(&self, name: &str) -> Result> { - let Some(&(defining_id, index)) = self.struct_index.get(name) else { - return Ok(None); - }; - - let struct_def = self.bytecode.struct_def_at(index); - let struct_handle = self.bytecode.struct_handle_at(struct_def.struct_handle); - let abilities = struct_handle.abilities; - let type_params = struct_handle.type_parameters.clone(); - - let fields = match &struct_def.field_information { - StructFieldInformation::Native => vec![], - StructFieldInformation::Declared(fields) => fields - .iter() - .map(|f| { - Ok(( - self.bytecode.identifier_at(f.name).to_string(), - OpenSignatureBody::read(&f.signature.0, &self.bytecode)?, - )) - }) - .collect::>()?, - }; - - Ok(Some(StructDef { - defining_id, - abilities, - type_params, - fields, - })) - } - - /// Iterate over the functions with names strictly after `after` (or from - /// the beginning), and strictly before `before` (or to the end). - pub fn functions( - &self, - after: Option<&str>, - before: Option<&str>, - ) -> impl DoubleEndedIterator + Clone { - use std::ops::Bound as B; - self.function_index - .range::(( - after.map_or(B::Unbounded, B::Excluded), - before.map_or(B::Unbounded, B::Excluded), - )) - .map(|(name, _)| name.as_str()) - } - - /// Get the function definition corresponding to the function with name - /// `name` in this module. Returns `Ok(None)` if the function cannot be - /// found in this module, `Err(...)` if there was an error deserializing - /// it, and `Ok(Some(def))` on success. - pub fn function_def(&self, name: &str) -> Result> { - let Some(&index) = self.function_index.get(name) else { - return Ok(None); - }; - - let function_def = self.bytecode.function_def_at(index); - let function_handle = self.bytecode.function_handle_at(function_def.function); - - Ok(Some(FunctionDef { - visibility: function_def.visibility, - is_entry: function_def.is_entry, - type_params: function_handle.type_parameters.clone(), - parameters: read_signature(function_handle.parameters, &self.bytecode)?, - return_: read_signature(function_handle.return_, &self.bytecode)?, - })) - } -} - -impl OpenSignature { - fn read(sig: &SignatureToken, bytecode: &CompiledModule) -> Result { - use SignatureToken as S; - Ok(match sig { - S::Reference(sig) => OpenSignature { - ref_: Some(Reference::Immutable), - body: OpenSignatureBody::read(sig, bytecode)?, - }, - - S::MutableReference(sig) => OpenSignature { - ref_: Some(Reference::Mutable), - body: OpenSignatureBody::read(sig, bytecode)?, - }, - - sig => OpenSignature { - ref_: None, - body: OpenSignatureBody::read(sig, bytecode)?, - }, - }) - } - - /// Return a specific instantiation of this signature, with `type_params` as - /// the actual type parameters. This function does not check that the - /// supplied type parameters are valid (meet the ability constraints of - /// the struct or function this signature is part of), but will - /// produce an error if the signature references a type parameter that is - /// out of bounds. - pub fn instantiate(&self, type_params: &[TypeTag]) -> Result { - Ok(Signature { - ref_: self.ref_, - body: self.body.instantiate(type_params)?, - }) - } -} - -impl OpenSignatureBody { - fn read(sig: &SignatureToken, bytecode: &CompiledModule) -> Result { - use OpenSignatureBody as O; - use SignatureToken as S; - - Ok(match sig { - S::Signer => return Err(Error::UnexpectedSigner), - S::Reference(_) | S::MutableReference(_) => return Err(Error::UnexpectedReference), - - S::Address => O::Address, - S::Bool => O::Bool, - S::U8 => O::U8, - S::U16 => O::U16, - S::U32 => O::U32, - S::U64 => O::U64, - S::U128 => O::U128, - S::U256 => O::U256, - S::TypeParameter(ix) => O::TypeParameter(*ix), - - S::Vector(sig) => O::Vector(Box::new(OpenSignatureBody::read(sig, bytecode)?)), - - S::Struct(ix) => O::Datatype(DatatypeKey::read(*ix, bytecode), vec![]), - S::StructInstantiation(struct_inst) => { - let (ix, params) = &**struct_inst; - O::Datatype( - DatatypeKey::read(*ix, bytecode), - params - .iter() - .map(|sig| OpenSignatureBody::read(sig, bytecode)) - .collect::>()?, - ) - } - }) - } - - fn instantiate(&self, type_params: &[TypeTag]) -> Result { - use OpenSignatureBody as O; - use TypeTag as T; - - Ok(match self { - O::Address => T::Address, - O::Bool => T::Bool, - O::U8 => T::U8, - O::U16 => T::U16, - O::U32 => T::U32, - O::U64 => T::U64, - O::U128 => T::U128, - O::U256 => T::U256, - O::Vector(s) => T::Vector(Box::new(s.instantiate(type_params)?)), - - O::Datatype(key, dty_params) => T::Struct(Box::new(StructTag { - address: key.package, - module: ident(&key.module)?, - name: ident(&key.name)?, - type_params: dty_params - .iter() - .map(|p| p.instantiate(type_params)) - .collect::>()?, - })), - - O::TypeParameter(ix) => type_params - .get(*ix as usize) - .cloned() - .ok_or_else(|| Error::TypeParamOOB(*ix, type_params.len()))?, - }) - } -} - -impl<'m, 'n> DatatypeRef<'m, 'n> { - pub fn as_key(&self) -> DatatypeKey { - DatatypeKey { - package: self.package, - module: self.module.to_string().into(), - name: self.name.to_string().into(), - } - } -} - -impl DatatypeKey { - fn read(ix: StructHandleIndex, bytecode: &CompiledModule) -> Self { - let sh = bytecode.struct_handle_at(ix); - let mh = bytecode.module_handle_at(sh.module); - - let package = *bytecode.address_identifier_at(mh.address); - let module = bytecode.identifier_at(mh.name).to_string().into(); - let name = bytecode.identifier_at(sh.name).to_string().into(); - - DatatypeKey { - package, - module, - name, - } - } -} - -impl<'l> ResolutionContext<'l> { - fn new(limits: Option<&'l Limits>) -> Self { - ResolutionContext { - structs: BTreeMap::new(), - limits, - } - } - - /// Gather definitions for types that contribute to the definition of `tag` - /// into this resolution context, fetching data from the `store` as - /// necessary. Also updates package addresses in `tag` to point to - /// runtime IDs instead of storage IDs to ensure queries made using these - /// addresses during the subsequent resolution phase find the relevant type - /// information in the context. - /// - /// The `visit_fields` flag controls whether the traversal looks inside - /// types at their fields (which is necessary for layout resolution) or - /// not (only explores the outer type and any type parameters). - /// - /// The `visit_phantoms` flag controls whether the traversal recurses - /// through phantom type parameters (which is also necessary for type - /// resolution) or not. - async fn add_type_tag( - &mut self, - tag: &mut TypeTag, - store: &S, - visit_fields: bool, - visit_phantoms: bool, - ) -> Result<()> { - use TypeTag as T; - - struct ToVisit<'t> { - tag: &'t mut TypeTag, - depth: usize, - } - - let mut frontier = vec![ToVisit { tag, depth: 0 }]; - while let Some(ToVisit { tag, depth }) = frontier.pop() { - macro_rules! push_ty_param { - ($tag:expr) => {{ - check_max_limit!( - TypeParamNesting, self.limits; - max_type_argument_depth > depth - ); - - frontier.push(ToVisit { tag: $tag, depth: depth + 1 }) - }} - } - - match tag { - T::Address - | T::Bool - | T::U8 - | T::U16 - | T::U32 - | T::U64 - | T::U128 - | T::U256 - | T::Signer => { - // Nothing further to add to context - } - - T::Vector(tag) => push_ty_param!(tag), - - T::Struct(s) => { - let context = store.fetch(s.address).await?; - let def = context - .clone() - .struct_def(s.module.as_str(), s.name.as_str())?; - - // Normalize `address` (the ID of a package that contains the definition of this - // struct) to be a runtime ID, because that's what the resolution context uses - // for keys. Take care to do this before generating the key that is used to - // query and/or write into `self.structs. - s.address = context.runtime_id; - let key = DatatypeRef::from(s.as_ref()).as_key(); - - if def.type_params.len() != s.type_params.len() { - return Err(Error::TypeArityMismatch( - def.type_params.len(), - s.type_params.len(), - )); - } - - check_max_limit!( - TooManyTypeParams, self.limits; - max_type_argument_width >= s.type_params.len() - ); - - for (param, def) in s.type_params.iter_mut().zip(def.type_params.iter()) { - if !def.is_phantom || visit_phantoms { - push_ty_param!(param); - } - } - - if self.structs.contains_key(&key) { - continue; - } - - if visit_fields { - for (_, sig) in &def.fields { - self.add_signature(sig.clone(), store, &context, visit_fields) - .await?; - } - } - - check_max_limit!( - TooManyTypeNodes, self.limits; - max_type_nodes > self.structs.len() - ); - - self.structs.insert(key, def); - } - } - } - - Ok(()) - } - - // Like `add_type_tag` but for type signatures. Needs a linkage table to - // translate runtime IDs into storage IDs. - async fn add_signature( - &mut self, - sig: OpenSignatureBody, - store: &T, - context: &Package, - visit_fields: bool, - ) -> Result<()> { - use OpenSignatureBody as O; - - let mut frontier = vec![sig]; - while let Some(sig) = frontier.pop() { - match sig { - O::Address - | O::Bool - | O::U8 - | O::U16 - | O::U32 - | O::U64 - | O::U128 - | O::U256 - | O::TypeParameter(_) => { - // Nothing further to add to context - } - - O::Vector(sig) => frontier.push(*sig), - - O::Datatype(key, params) => { - check_max_limit!( - TooManyTypeParams, self.limits; - max_type_argument_width >= params.len() - ); - - let params_count = params.len(); - let struct_count = self.structs.len(); - frontier.extend(params.into_iter()); - - let def = match self.structs.entry(key.clone()) { - Entry::Occupied(e) => e.into_mut(), - - Entry::Vacant(e) => { - let storage_id = context.relocate(key.package)?; - let package = store.fetch(storage_id).await?; - let def = package.struct_def(&key.module, &key.name)?; - - if visit_fields { - frontier.extend(def.fields.iter().map(|f| &f.1).cloned()); - } - - check_max_limit!( - TooManyTypeNodes, self.limits; - max_type_nodes > struct_count - ); - - e.insert(def) - } - }; - - if def.type_params.len() != params_count { - return Err(Error::TypeArityMismatch( - def.type_params.len(), - params_count, - )); - } - } - } - } - - Ok(()) - } - - /// Translate a type `tag` into its layout using only the information - /// contained in this context. Requires that the necessary information - /// was added to the context through calls to `add_type_tag` and - /// `add_signature` before being called. - /// - /// `max_depth` controls how deep the layout is allowed to grow to. The - /// actual depth reached is returned alongside the layout (assuming it - /// does not exceed `max_depth`). - fn resolve_type_layout( - &self, - tag: &TypeTag, - max_depth: usize, - ) -> Result<(MoveTypeLayout, usize)> { - use MoveTypeLayout as L; - use TypeTag as T; - - if max_depth == 0 { - return Err(Error::ValueNesting( - self.limits.map_or(0, |l| l.max_move_value_depth), - )); - } - - Ok(match tag { - T::Signer => return Err(Error::UnexpectedSigner), - - T::Address => (L::Address, 1), - T::Bool => (L::Bool, 1), - T::U8 => (L::U8, 1), - T::U16 => (L::U16, 1), - T::U32 => (L::U32, 1), - T::U64 => (L::U64, 1), - T::U128 => (L::U128, 1), - T::U256 => (L::U256, 1), - - T::Vector(tag) => { - let (layout, depth) = self.resolve_type_layout(tag, max_depth - 1)?; - (L::Vector(Box::new(layout)), depth + 1) - } - - T::Struct(s) => { - // TODO (optimization): Could introduce a layout cache to further speed up - // resolution. Relevant entries in that cache would need to be gathered in the - // ResolutionContext as it is built, and then used here to avoid the recursive - // exploration. This optimisation is complicated by the fact that in the cache, - // these layouts are naturally keyed based on defining ID, but during - // resolution, they are keyed by runtime IDs. - - // SAFETY: `add_type_tag` ensures `structs` has an element with this key. - let key = DatatypeRef::from(s.as_ref()); - let def = &self.structs[&key]; - - let StructTag { - module, - name, - type_params, - .. - } = s.as_ref(); - - // TODO (optimization): This could be made more efficient by only generating - // layouts for non-phantom types. This efficiency could be - // extended to the exploration phase (i.e. only explore layouts - // of non-phantom types). But this optimisation is complicated - // by the fact that we still need to create a correct type tag for a - // phantom parameter, which is currently done by converting a type layout into a - // tag. - let param_layouts = type_params - .iter() - // Reduce the max depth because we know these type parameters will be nested - // wthin this struct. - .map(|tag| self.resolve_type_layout(tag, max_depth - 1)) - .collect::>>()?; - - // SAFETY: `param_layouts` contains `MoveTypeLayout`-s that are generated by - // this `ResolutionContext`, which guarantees that struct - // layouts come with types, which is necessary to avoid errors - // when converting layouts into type tags. - let type_params = param_layouts.iter().map(|l| TypeTag::from(&l.0)).collect(); - - let type_ = StructTag { - address: def.defining_id, - module: module.clone(), - name: name.clone(), - type_params, - }; - - let mut fields = Vec::with_capacity(def.fields.len()); - let mut field_depth = 0; - - for (name, sig) in &def.fields { - let (layout, depth) = - self.resolve_signature_layout(sig, ¶m_layouts, max_depth - 1)?; - - field_depth = field_depth.max(depth); - fields.push(MoveFieldLayout { - name: ident(name.as_str())?, - layout, - }) - } - - ( - L::Struct(MoveStructLayout { type_, fields }), - field_depth + 1, - ) - } - }) - } - - /// Like `resolve_type_tag` but for signatures. Needs to be provided the - /// layouts of type parameters which are substituted when a type - /// parameter is encountered. - /// - /// `max_depth` controls how deep the layout is allowed to grow to. The - /// actual depth reached is returned alongside the layout (assuming it - /// does not exceed `max_depth`). - fn resolve_signature_layout( - &self, - sig: &OpenSignatureBody, - param_layouts: &[(MoveTypeLayout, usize)], - max_depth: usize, - ) -> Result<(MoveTypeLayout, usize)> { - use MoveTypeLayout as L; - use OpenSignatureBody as O; - - if max_depth == 0 { - return Err(Error::ValueNesting( - self.limits.map_or(0, |l| l.max_move_value_depth), - )); - } - - Ok(match sig { - O::Address => (L::Address, 1), - O::Bool => (L::Bool, 1), - O::U8 => (L::U8, 1), - O::U16 => (L::U16, 1), - O::U32 => (L::U32, 1), - O::U64 => (L::U64, 1), - O::U128 => (L::U128, 1), - O::U256 => (L::U256, 1), - - O::TypeParameter(ix) => { - let (layout, depth) = param_layouts - .get(*ix as usize) - .ok_or_else(|| Error::TypeParamOOB(*ix, param_layouts.len())) - .cloned()?; - - // We need to re-check the type parameter before we use it because it might have - // been fine when it was created, but result in too deep a layout when we use it - // at this position. - if depth > max_depth { - return Err(Error::ValueNesting( - self.limits.map_or(0, |l| l.max_move_value_depth), - )); - } - - (layout, depth) - } - - O::Vector(sig) => { - let (layout, depth) = - self.resolve_signature_layout(sig.as_ref(), param_layouts, max_depth - 1)?; - - (L::Vector(Box::new(layout)), depth + 1) - } - - O::Datatype(key, params) => { - // SAFETY: `add_signature` ensures `structs` has an element with this key. - let def = &self.structs[key]; - - let param_layouts = params - .iter() - .map(|sig| self.resolve_signature_layout(sig, param_layouts, max_depth - 1)) - .collect::>>()?; - - // SAFETY: `param_layouts` contains `MoveTypeLayout`-s that are generated by - // this `ResolutionContext`, which guarantees that struct - // layouts come with types, which is necessary to avoid errors - // when converting layouts into type tags. - let type_params = param_layouts.iter().map(|l| TypeTag::from(&l.0)).collect(); - - let type_ = StructTag { - address: def.defining_id, - module: ident(&key.module)?, - name: ident(&key.name)?, - type_params, - }; - - let mut fields = Vec::with_capacity(def.fields.len()); - let mut field_depth = 0; - for (name, sig) in &def.fields { - let (layout, depth) = - self.resolve_signature_layout(sig, ¶m_layouts, max_depth - 1)?; - - field_depth = field_depth.max(depth); - fields.push(MoveFieldLayout { - name: ident(name.as_str())?, - layout, - }); - } - - ( - L::Struct(MoveStructLayout { type_, fields }), - field_depth + 1, - ) - } - }) - } - - /// Calculate the abilities for a concrete type `tag`. Requires that the - /// necessary information was added to the context through calls to - /// `add_type_tag` before being called. - fn resolve_abilities(&self, tag: &TypeTag) -> Result { - use TypeTag as T; - Ok(match tag { - T::Signer => return Err(Error::UnexpectedSigner), - - T::Bool | T::U8 | T::U16 | T::U32 | T::U64 | T::U128 | T::U256 | T::Address => { - AbilitySet::PRIMITIVES - } - - T::Vector(tag) => self.resolve_abilities(tag)?.intersect(AbilitySet::VECTOR), - - T::Struct(s) => { - // SAFETY: `add_type_tag` ensures `structs` has an element with this key. - let key = DatatypeRef::from(s.as_ref()); - let def = &self.structs[&key]; - - if def.type_params.len() != s.type_params.len() { - return Err(Error::TypeArityMismatch( - def.type_params.len(), - s.type_params.len(), - )); - } - - let param_abilities: Result> = s - .type_params - .iter() - .zip(def.type_params.iter()) - .map(|(p, d)| { - if d.is_phantom { - Ok(AbilitySet::EMPTY) - } else { - self.resolve_abilities(p) - } - }) - .collect(); - - AbilitySet::polymorphic_abilities( - def.abilities, - def.type_params.iter().map(|p| p.is_phantom), - param_abilities?.into_iter(), - ) - // This error is unexpected because the only reason it would fail is because of a - // type parameter arity mismatch, which we check for above. - .map_err(|e| Error::UnexpectedError(Box::new(e)))? - } - }) - } - - /// Translate the (runtime) package IDs in `sig` to defining IDs using only - /// the information contained in this context. Requires that the - /// necessary information was added to the context through calls to - /// `add_signature` before being called. - fn relocate_signature(&self, sig: &mut OpenSignatureBody) -> Result<()> { - use OpenSignatureBody as O; - - match sig { - O::Address | O::Bool | O::U8 | O::U16 | O::U32 | O::U64 | O::U128 | O::U256 => { - // nop - } - - O::TypeParameter(_) => { /* nop */ } - - O::Vector(sig) => self.relocate_signature(sig.as_mut())?, - - O::Datatype(key, params) => { - // SAFETY: `add_signature` ensures `structs` has an element with this key. - let def = &self.structs[key]; - for param in params { - self.relocate_signature(param)?; - } - - key.package = def.defining_id; - } - } - - Ok(()) - } -} - -impl<'s> From<&'s StructTag> for DatatypeRef<'s, 's> { - fn from(tag: &'s StructTag) -> Self { - DatatypeRef { - package: tag.address, - module: tag.module.as_str().into(), - name: tag.name.as_str().into(), - } - } -} - -/// Translate a string into an `Identifier`, but translating errors into this -/// module's error type. -fn ident(s: &str) -> Result { - Identifier::new(s).map_err(|_| Error::NotAnIdentifier(s.to_string())) -} - -/// Read and deserialize a signature index (from function parameter or return -/// types) into a vector of signatures. -fn read_signature(idx: SignatureIndex, bytecode: &CompiledModule) -> Result> { - let MoveSignature(tokens) = bytecode.signature_at(idx); - let mut sigs = Vec::with_capacity(tokens.len()); - - for token in tokens { - sigs.push(OpenSignature::read(token, bytecode)?); - } - - Ok(sigs) -} - -#[cfg(test)] -mod tests { - use std::{ - path::PathBuf, - str::FromStr, - sync::{Arc, RwLock}, - }; - - use async_trait::async_trait; - use move_binary_format::file_format::Ability; - use move_compiler::compiled_unit::NamedCompiledModule; - use move_core_types::ident_str; - use sui_move_build::{BuildConfig, CompiledPackage}; - use sui_types::{ - base_types::random_object_ref, - transaction::{ObjectArg, ProgrammableMoveCall}, - }; - - use super::*; - - /// Layout for a type that only refers to base types or other types in the - /// same module. - #[tokio::test] - async fn test_simple_type() { - let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); - let package_resolver = Resolver::new(cache); - let layout = package_resolver - .type_layout(type_("0xa0::m::T0")) - .await - .unwrap(); - insta::assert_snapshot!(format!("{layout:#}")); - } - - /// A type that refers to types from other modules in the same package. - #[tokio::test] - async fn test_cross_module() { - let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); - let resolver = Resolver::new(cache); - let layout = resolver.type_layout(type_("0xa0::n::T0")).await.unwrap(); - insta::assert_snapshot!(format!("{layout:#}")); - } - - /// A type that refers to types from other modules in the same package. - #[tokio::test] - async fn test_cross_package() { - let (_, cache) = package_cache([ - (1, build_package("a0"), a0_types()), - (1, build_package("b0"), b0_types()), - ]); - let resolver = Resolver::new(cache); - - let layout = resolver.type_layout(type_("0xb0::m::T0")).await.unwrap(); - insta::assert_snapshot!(format!("{layout:#}")); - } - - /// A type from an upgraded package, mixing structs defined in the original - /// package and the upgraded package. - #[tokio::test] - async fn test_upgraded_package() { - let (_, cache) = package_cache([ - (1, build_package("a0"), a0_types()), - (2, build_package("a1"), a1_types()), - ]); - let resolver = Resolver::new(cache); - - let layout = resolver.type_layout(type_("0xa1::n::T1")).await.unwrap(); - insta::assert_snapshot!(format!("{layout:#}")); - } - - /// A generic type instantiation where the type parameters are resolved - /// relative to linkage contexts from different versions of the same - /// package. - #[tokio::test] - async fn test_multiple_linkage_contexts() { - let (_, cache) = package_cache([ - (1, build_package("a0"), a0_types()), - (2, build_package("a1"), a1_types()), - ]); - let resolver = Resolver::new(cache); - - let layout = resolver - .type_layout(type_("0xa0::m::T1<0xa0::m::T0, 0xa1::m::T3>")) - .await - .unwrap(); - insta::assert_snapshot!(format!("{layout:#}")); - } - - /// Refer to a type, not by its defining ID, but by the ID of some later - /// version of that package. This doesn't currently work during - /// execution but it simplifies making queries: A type can be referred - /// to using the ID of any package that declares it, rather than only the - /// package that first declared it (whose ID is its defining ID). - #[tokio::test] - async fn test_upgraded_package_non_defining_id() { - let (_, cache) = package_cache([ - (1, build_package("a0"), a0_types()), - (2, build_package("a1"), a1_types()), - ]); - let resolver = Resolver::new(cache); - - let layout = resolver - .type_layout(type_("0xa1::m::T1<0xa1::m::T3, 0xa1::m::T0>")) - .await - .unwrap(); - insta::assert_snapshot!(format!("{layout:#}")); - } - - /// A type that refers to a types in a relinked package. C depends on B and - /// overrides its dependency on A from v1 to v2. The type in C refers - /// to types that were defined in both B, A v1, and A v2. - #[tokio::test] - async fn test_relinking() { - let (_, cache) = package_cache([ - (1, build_package("a0"), a0_types()), - (2, build_package("a1"), a1_types()), - (1, build_package("b0"), b0_types()), - (1, build_package("c0"), c0_types()), - ]); - let resolver = Resolver::new(cache); - - let layout = resolver.type_layout(type_("0xc0::m::T0")).await.unwrap(); - insta::assert_snapshot!(format!("{layout:#}")); - } - - #[tokio::test] - async fn test_value_nesting_boundary() { - let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); - - let resolver = Resolver::new_with_limits( - cache, - Limits { - max_type_argument_width: 100, - max_type_argument_depth: 100, - max_type_nodes: 100, - max_move_value_depth: 3, - }, - ); - - // The layout of this type is fine, because it is *just* at the correct depth. - let layout = resolver - .type_layout(type_("0xa0::m::T1")) - .await - .unwrap(); - insta::assert_snapshot!(format!("{layout:#}")); - } - - #[tokio::test] - async fn test_err_value_nesting_simple() { - let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); - - let resolver = Resolver::new_with_limits( - cache, - Limits { - max_type_argument_width: 100, - max_type_argument_depth: 100, - max_type_nodes: 100, - max_move_value_depth: 2, - }, - ); - - // The depth limit is now too low, so this will fail. - let err = resolver - .type_layout(type_("0xa0::m::T1")) - .await - .unwrap_err(); - assert!(matches!(err, Error::ValueNesting(2))) - } - - #[tokio::test] - async fn test_err_value_nesting_big_type_param() { - let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); - - let resolver = Resolver::new_with_limits( - cache, - Limits { - max_type_argument_width: 100, - max_type_argument_depth: 100, - max_type_nodes: 100, - max_move_value_depth: 3, - }, - ); - - // This layout calculation will fail early because we know that the type - // parameter we're calculating will eventually contribute to a layout - // that exceeds the max depth. - let err = resolver - .type_layout(type_("0xa0::m::T1>, u8>")) - .await - .unwrap_err(); - assert!(matches!(err, Error::ValueNesting(3))) - } - - #[tokio::test] - async fn test_err_value_nesting_big_phantom_type_param() { - let (_, cache) = package_cache([ - (1, build_package("sui"), sui_types()), - (1, build_package("d0"), d0_types()), - ]); - - let resolver = Resolver::new_with_limits( - cache, - Limits { - max_type_argument_width: 100, - max_type_argument_depth: 100, - max_type_nodes: 100, - max_move_value_depth: 3, - }, - ); - - // Check that this layout request would succeed. - let _ = resolver - .type_layout(type_("0xd0::m::O")) - .await - .unwrap(); - - // But this one fails, even though the big layout is for a phantom type - // parameter. This may change in future if we optimise the way we handle - // phantom type parameters to not calculate their full layout, just - // their type tag. - let err = resolver - .type_layout(type_("0xd0::m::O>>")) - .await - .unwrap_err(); - assert!(matches!(err, Error::ValueNesting(3))) - } - - #[tokio::test] - async fn test_err_value_nesting_type_param_application() { - let (_, cache) = package_cache([ - (1, build_package("sui"), sui_types()), - (1, build_package("d0"), d0_types()), - ]); - - let resolver = Resolver::new_with_limits( - cache, - Limits { - max_type_argument_width: 100, - max_type_argument_depth: 100, - max_type_nodes: 100, - max_move_value_depth: 3, - }, - ); - - // Make sure that even if all type parameters individually meet the depth - // requirements, that we correctly fail if they extend the layout's - // depth on application. - let err = resolver - .type_layout(type_("0xd0::m::O, u8>")) - .await - .unwrap_err(); - - assert!(matches!(err, Error::ValueNesting(3))) - } - - #[tokio::test] - async fn test_system_package_invalidation() { - let (inner, cache) = package_cache([(1, build_package("s0"), s0_types())]); - let resolver = Resolver::new(cache); - - let not_found = resolver.type_layout(type_("0x1::m::T1")).await.unwrap_err(); - assert!(matches!(not_found, Error::StructNotFound(_, _, _))); - - // Add a new version of the system package into the store underlying the cache. - inner.write().unwrap().replace( - addr("0x1"), - cached_package(2, BTreeMap::new(), &build_package("s1"), &s1_types()), - ); - - let layout = resolver.type_layout(type_("0x1::m::T1")).await.unwrap(); - insta::assert_snapshot!(format!("{layout:#}")); - } - - #[tokio::test] - async fn test_caching() { - let (inner, cache) = package_cache([ - (1, build_package("a0"), a0_types()), - (1, build_package("s0"), s0_types()), - ]); - let resolver = Resolver::new(cache); - - let stats = |inner: &Arc>| { - let i = inner.read().unwrap(); - (i.fetches, i.version_checks) - }; - - assert_eq!(stats(&inner), (0, 0)); - let l0 = resolver.type_layout(type_("0xa0::m::T0")).await.unwrap(); - - // Load A0. - assert_eq!(stats(&inner), (1, 0)); - - // Layouts are the same, no need to reload the package. Not a system package, - // so no version check needed. - let l1 = resolver.type_layout(type_("0xa0::m::T0")).await.unwrap(); - assert_eq!(format!("{l0}"), format!("{l1}")); - assert_eq!(stats(&inner), (1, 0)); - - // Different type, but same package, so no extra fetch. - let l2 = resolver.type_layout(type_("0xa0::m::T2")).await.unwrap(); - assert_ne!(format!("{l0}"), format!("{l2}")); - assert_eq!(stats(&inner), (1, 0)); - - // New package to load. It's a system package, which would need a version check - // if it already existed in the cache, but it doesn't yet, so we only - // see a fetch. - let l3 = resolver.type_layout(type_("0x1::m::T0")).await.unwrap(); - assert_eq!(stats(&inner), (2, 0)); - - // Reload the same system package type, which will cause a version check. - let l4 = resolver.type_layout(type_("0x1::m::T0")).await.unwrap(); - assert_eq!(format!("{l3}"), format!("{l4}")); - assert_eq!(stats(&inner), (2, 1)); - - // Upgrade the system package - inner.write().unwrap().replace( - addr("0x1"), - cached_package(2, BTreeMap::new(), &build_package("s1"), &s1_types()), - ); - - // Reload the same system type again. The version check fails and the system - // package is refetched (even though the type is the same as before). - // This usage pattern (layouts for system types) is why a layout cache - // would be particularly helpful (future optimisation). - let l5 = resolver.type_layout(type_("0x1::m::T0")).await.unwrap(); - assert_eq!(format!("{l4}"), format!("{l5}")); - assert_eq!(stats(&inner), (3, 2)); - } - - #[tokio::test] - async fn test_err_not_a_package() { - let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); - let resolver = Resolver::new(cache); - let err = resolver - .type_layout(type_("0x42::m::T0")) - .await - .unwrap_err(); - assert!(matches!(err, Error::PackageNotFound(_))); - } - - #[tokio::test] - async fn test_err_no_module() { - let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); - let resolver = Resolver::new(cache); - let err = resolver - .type_layout(type_("0xa0::l::T0")) - .await - .unwrap_err(); - assert!(matches!(err, Error::ModuleNotFound(_, _))); - } - - #[tokio::test] - async fn test_err_no_struct() { - let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); - let resolver = Resolver::new(cache); - - let err = resolver - .type_layout(type_("0xa0::m::T9")) - .await - .unwrap_err(); - assert!(matches!(err, Error::StructNotFound(_, _, _))); - } - - #[tokio::test] - async fn test_err_type_arity() { - let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); - let resolver = Resolver::new(cache); - - // Too few - let err = resolver - .type_layout(type_("0xa0::m::T1")) - .await - .unwrap_err(); - assert!(matches!(err, Error::TypeArityMismatch(2, 1))); - - // Too many - let err = resolver - .type_layout(type_("0xa0::m::T1")) - .await - .unwrap_err(); - assert!(matches!(err, Error::TypeArityMismatch(2, 3))); - } - - #[tokio::test] - async fn test_structs() { - let (_, cache) = package_cache([(1, build_package("a0"), a0_types())]); - let a0 = cache.fetch(addr("0xa0")).await.unwrap(); - let m = a0.module("m").unwrap(); - - assert_eq!( - m.structs(None, None).collect::>(), - vec!["T0", "T1", "T2"], - ); - - assert_eq!(m.structs(None, Some("T1")).collect::>(), vec!["T0"],); - - assert_eq!( - m.structs(Some("T0"), Some("T2")).collect::>(), - vec!["T1"], - ); - - assert_eq!(m.structs(Some("T1"), None).collect::>(), vec!["T2"],); - - let t0 = m.struct_def("T0").unwrap().unwrap(); - let t1 = m.struct_def("T1").unwrap().unwrap(); - let t2 = m.struct_def("T2").unwrap().unwrap(); - - insta::assert_snapshot!(format!( - "a0::m::T0: {t0:#?}\n\ - a0::m::T1: {t1:#?}\n\ - a0::m::T2: {t2:#?}", - )); - } - - #[tokio::test] - async fn test_functions() { - let (_, cache) = package_cache([ - (1, build_package("a0"), a0_types()), - (2, build_package("a1"), a1_types()), - (1, build_package("b0"), b0_types()), - (1, build_package("c0"), c0_types()), - ]); - - let c0 = cache.fetch(addr("0xc0")).await.unwrap(); - let m = c0.module("m").unwrap(); - - assert_eq!( - m.functions(None, None).collect::>(), - vec!["bar", "baz", "foo"], - ); - - assert_eq!( - m.functions(None, Some("baz")).collect::>(), - vec!["bar"], - ); - - assert_eq!( - m.functions(Some("bar"), Some("foo")).collect::>(), - vec!["baz"], - ); - - assert_eq!( - m.functions(Some("baz"), None).collect::>(), - vec!["foo"], - ); - - let foo = m.function_def("foo").unwrap().unwrap(); - let bar = m.function_def("bar").unwrap().unwrap(); - let baz = m.function_def("baz").unwrap().unwrap(); - - insta::assert_snapshot!(format!( - "c0::m::foo: {foo:#?}\n\ - c0::m::bar: {bar:#?}\n\ - c0::m::baz: {baz:#?}" - )); - } - - #[tokio::test] - async fn test_function_parameters() { - let (_, cache) = package_cache([ - (1, build_package("a0"), a0_types()), - (2, build_package("a1"), a1_types()), - (1, build_package("b0"), b0_types()), - (1, build_package("c0"), c0_types()), - ]); - - let resolver = Resolver::new(cache); - let c0 = addr("0xc0"); - - let foo = resolver.function_parameters(c0, "m", "foo").await.unwrap(); - let bar = resolver.function_parameters(c0, "m", "bar").await.unwrap(); - let baz = resolver.function_parameters(c0, "m", "baz").await.unwrap(); - - insta::assert_snapshot!(format!( - "c0::m::foo: {foo:#?}\n\ - c0::m::bar: {bar:#?}\n\ - c0::m::baz: {baz:#?}" - )); - } - - #[tokio::test] - async fn test_signature_instantiation() { - use OpenSignatureBody as O; - use TypeTag as T; - - let sig = O::Datatype( - key("0x2::table::Table"), - vec![ - O::TypeParameter(1), - O::Vector(Box::new(O::Datatype( - key("0x1::option::Option"), - vec![O::TypeParameter(0)], - ))), - ], - ); - - insta::assert_debug_snapshot!(sig.instantiate(&[T::U64, T::Bool]).unwrap()); - } - - #[tokio::test] - async fn test_signature_instantiation_error() { - use OpenSignatureBody as O; - use TypeTag as T; - - let sig = O::Datatype( - key("0x2::table::Table"), - vec![ - O::TypeParameter(1), - O::Vector(Box::new(O::Datatype( - key("0x1::option::Option"), - vec![O::TypeParameter(99)], - ))), - ], - ); - - insta::assert_display_snapshot!( - sig.instantiate(&[T::U64, T::Bool]).unwrap_err(), - @"Type Parameter 99 out of bounds (2)" - ); - } - - /// Primitive types should have the expected primitive abilities - #[tokio::test] - async fn test_primitive_abilities() { - use Ability as A; - use AbilitySet as S; - - let (_, cache) = package_cache([]); - let resolver = Resolver::new(cache); - - for prim in ["address", "bool", "u8", "u16", "u32", "u64", "u128", "u256"] { - assert_eq!( - resolver.abilities(type_(prim)).await.unwrap(), - S::EMPTY | A::Copy | A::Drop | A::Store, - "Unexpected primitive abilities for: {prim}", - ); - } - } - - /// Generic type abilities depend on the abilities of their type parameters. - #[tokio::test] - async fn test_simple_generic_abilities() { - use Ability as A; - use AbilitySet as S; - - let (_, cache) = package_cache([ - (1, build_package("sui"), sui_types()), - (1, build_package("d0"), d0_types()), - ]); - let resolver = Resolver::new(cache); - - let a1 = resolver - .abilities(type_("0xd0::m::T")) - .await - .unwrap(); - assert_eq!(a1, S::EMPTY | A::Copy | A::Drop | A::Store); - - let a2 = resolver - .abilities(type_("0xd0::m::T<0xd0::m::S, u64>")) - .await - .unwrap(); - assert_eq!(a2, S::EMPTY | A::Drop | A::Store); - - let a3 = resolver - .abilities(type_("0xd0::m::T<0xd0::m::R, 0xd0::m::S>")) - .await - .unwrap(); - assert_eq!(a3, S::EMPTY | A::Drop); - - let a4 = resolver - .abilities(type_("0xd0::m::T<0xd0::m::Q, 0xd0::m::R>")) - .await - .unwrap(); - assert_eq!(a4, S::EMPTY); - } - - /// Generic abilities also need to handle nested type parameters - #[tokio::test] - async fn test_nested_generic_abilities() { - use Ability as A; - use AbilitySet as S; - - let (_, cache) = package_cache([ - (1, build_package("sui"), sui_types()), - (1, build_package("d0"), d0_types()), - ]); - let resolver = Resolver::new(cache); - - let a1 = resolver - .abilities(type_("0xd0::m::T<0xd0::m::T<0xd0::m::R, u32>, u64>")) - .await - .unwrap(); - assert_eq!(a1, S::EMPTY | A::Copy | A::Drop); - } - - /// Key is different from other abilities in that it requires fields to have - /// `store`, rather than itself. - #[tokio::test] - async fn test_key_abilities() { - use Ability as A; - use AbilitySet as S; - - let (_, cache) = package_cache([ - (1, build_package("sui"), sui_types()), - (1, build_package("d0"), d0_types()), - ]); - let resolver = Resolver::new(cache); - - let a1 = resolver - .abilities(type_("0xd0::m::O")) - .await - .unwrap(); - assert_eq!(a1, S::EMPTY | A::Key | A::Store); - - let a2 = resolver - .abilities(type_("0xd0::m::O<0xd0::m::S, u64>")) - .await - .unwrap(); - assert_eq!(a2, S::EMPTY | A::Key | A::Store); - - // We would not be able to get an instance of this type, but in case the - // question is asked, its abilities would be empty. - let a3 = resolver - .abilities(type_("0xd0::m::O<0xd0::m::R, u64>")) - .await - .unwrap(); - assert_eq!(a3, S::EMPTY); - - // Key does not propagate up by itself, so this type is also uninhabitable. - let a4 = resolver - .abilities(type_("0xd0::m::O<0xd0::m::P, u32>")) - .await - .unwrap(); - assert_eq!(a4, S::EMPTY); - } - - /// Phantom types don't impact abilities - #[tokio::test] - async fn test_phantom_abilities() { - use Ability as A; - use AbilitySet as S; - - let (_, cache) = package_cache([ - (1, build_package("sui"), sui_types()), - (1, build_package("d0"), d0_types()), - ]); - let resolver = Resolver::new(cache); - - let a1 = resolver - .abilities(type_("0xd0::m::O")) - .await - .unwrap(); - assert_eq!(a1, S::EMPTY | A::Key | A::Store); - } - - #[tokio::test] - async fn test_err_ability_arity() { - let (_, cache) = package_cache([ - (1, build_package("sui"), sui_types()), - (1, build_package("d0"), d0_types()), - ]); - let resolver = Resolver::new(cache); - - // Too few - let err = resolver - .abilities(type_("0xd0::m::T")) - .await - .unwrap_err(); - assert!(matches!(err, Error::TypeArityMismatch(2, 1))); - - // Too many - let err = resolver - .abilities(type_("0xd0::m::T")) - .await - .unwrap_err(); - assert!(matches!(err, Error::TypeArityMismatch(2, 3))); - } - - #[tokio::test] - async fn test_err_ability_signer() { - let (_, cache) = package_cache([]); - let resolver = Resolver::new(cache); - - let err = resolver.abilities(type_("signer")).await.unwrap_err(); - assert!(matches!(err, Error::UnexpectedSigner)); - } - - #[tokio::test] - async fn test_err_too_many_type_params() { - let (_, cache) = package_cache([ - (1, build_package("sui"), sui_types()), - (1, build_package("d0"), d0_types()), - ]); - - let resolver = Resolver::new_with_limits( - cache, - Limits { - max_type_argument_width: 1, - max_type_argument_depth: 100, - max_type_nodes: 100, - max_move_value_depth: 100, - }, - ); - - let err = resolver - .abilities(type_("0xd0::m::O")) - .await - .unwrap_err(); - assert!(matches!(err, Error::TooManyTypeParams(1, 2))); - } - - #[tokio::test] - async fn test_err_too_many_type_nodes() { - use Ability as A; - use AbilitySet as S; - - let (_, cache) = package_cache([ - (1, build_package("sui"), sui_types()), - (1, build_package("d0"), d0_types()), - ]); - - let resolver = Resolver::new_with_limits( - cache, - Limits { - max_type_argument_width: 100, - max_type_argument_depth: 100, - max_type_nodes: 2, - max_move_value_depth: 100, - }, - ); - - // This request is OK, because one of O's type parameters is phantom, so we can - // avoid loading its definition. - let a1 = resolver - .abilities(type_("0xd0::m::O<0xd0::m::S, 0xd0::m::Q>")) - .await - .unwrap(); - assert_eq!(a1, S::EMPTY | A::Key | A::Store); - - // But this request will hit the limit - let err = resolver - .abilities(type_("0xd0::m::T<0xd0::m::P, 0xd0::m::Q>")) - .await - .unwrap_err(); - assert!(matches!(err, Error::TooManyTypeNodes(2, _))); - } - - #[tokio::test] - async fn test_err_type_param_nesting() { - use Ability as A; - use AbilitySet as S; - - let (_, cache) = package_cache([ - (1, build_package("sui"), sui_types()), - (1, build_package("d0"), d0_types()), - ]); - - let resolver = Resolver::new_with_limits( - cache, - Limits { - max_type_argument_width: 100, - max_type_argument_depth: 2, - max_type_nodes: 100, - max_move_value_depth: 100, - }, - ); - - // This request is OK, because one of O's type parameters is phantom, so we can - // avoid loading its definition. - let a1 = resolver - .abilities(type_( - "0xd0::m::O<0xd0::m::S, 0xd0::m::T, vector>>", - )) - .await - .unwrap(); - assert_eq!(a1, S::EMPTY | A::Key | A::Store); - - // But this request will hit the limit - let err = resolver - .abilities(type_("vector<0xd0::m::T<0xd0::m::O, u16>>")) - .await - .unwrap_err(); - assert!(matches!(err, Error::TypeParamNesting(2, _))); - } - - #[tokio::test] - async fn test_pure_input_layouts() { - use CallArg as I; - use ObjectArg::ImmOrOwnedObject as O; - use TypeTag as T; - - let (_, cache) = package_cache([ - (1, build_package("std"), std_types()), - (1, build_package("sui"), sui_types()), - (1, build_package("e0"), e0_types()), - ]); - - let resolver = Resolver::new(cache); - - // Helper function to generate a PTB calling 0xe0::m::foo. - fn ptb(t: TypeTag, y: CallArg) -> ProgrammableTransaction { - ProgrammableTransaction { - inputs: vec![ - I::Object(O(random_object_ref())), - I::Pure(bcs::to_bytes(&42u64).unwrap()), - I::Object(O(random_object_ref())), - y, - I::Object(O(random_object_ref())), - I::Pure(bcs::to_bytes("hello").unwrap()), - I::Pure(bcs::to_bytes("world").unwrap()), - ], - commands: vec![Command::MoveCall(Box::new(ProgrammableMoveCall { - package: addr("0xe0").into(), - module: ident_str!("m").to_owned(), - function: ident_str!("foo").to_owned(), - type_arguments: vec![t], - arguments: (0..=6).map(Argument::Input).collect(), - }))], - } - } - - let ptb_u64 = ptb(T::U64, I::Pure(bcs::to_bytes(&1u64).unwrap())); - - let ptb_opt = ptb( - TypeTag::Struct(Box::new(StructTag { - address: addr("0x1"), - module: ident_str!("option").to_owned(), - name: ident_str!("Option").to_owned(), - type_params: vec![TypeTag::U64], - })), - I::Pure(bcs::to_bytes(&[vec![1u64], vec![], vec![3]]).unwrap()), - ); - - let ptb_obj = ptb( - TypeTag::Struct(Box::new(StructTag { - address: addr("0xe0"), - module: ident_str!("m").to_owned(), - name: ident_str!("O").to_owned(), - type_params: vec![], - })), - I::Object(O(random_object_ref())), - ); - - let inputs_u64 = resolver.pure_input_layouts(&ptb_u64).await.unwrap(); - let inputs_opt = resolver.pure_input_layouts(&ptb_opt).await.unwrap(); - let inputs_obj = resolver.pure_input_layouts(&ptb_obj).await.unwrap(); - - // Make the output format a little nicer for the snapshot - let mut output = "---\n".to_string(); - for inputs in [inputs_u64, inputs_opt, inputs_obj] { - for input in inputs { - if let Some(layout) = input { - output += &format!("{layout:#}\n"); - } else { - output += "???\n"; - } - } - output += "---\n"; - } - - insta::assert_snapshot!(output); - } - - #[tokio::test] - async fn test_pure_input_layouts_conflicting() { - use CallArg as I; - use ObjectArg::ImmOrOwnedObject as O; - use TypeTag as T; - - let (_, cache) = package_cache([ - (1, build_package("std"), std_types()), - (1, build_package("sui"), sui_types()), - (1, build_package("e0"), e0_types()), - ]); - - let resolver = Resolver::new(cache); - - let ptb = ProgrammableTransaction { - inputs: vec![ - I::Object(O(random_object_ref())), - I::Pure(bcs::to_bytes(&42u64).unwrap()), - I::Object(O(random_object_ref())), - I::Pure(bcs::to_bytes(&43u64).unwrap()), - I::Object(O(random_object_ref())), - I::Pure(bcs::to_bytes("hello").unwrap()), - I::Pure(bcs::to_bytes("world").unwrap()), - ], - commands: vec![ - Command::MoveCall(Box::new(ProgrammableMoveCall { - package: addr("0xe0").into(), - module: ident_str!("m").to_owned(), - function: ident_str!("foo").to_owned(), - type_arguments: vec![T::U64], - arguments: (0..=6).map(Argument::Input).collect(), - })), - // This command is using the input that was previously used as a U64, but now as a - // U32, which will cause an error. - Command::MakeMoveVec(Some(T::U32), vec![Argument::Input(3)]), - ], - }; - - insta::assert_display_snapshot!( - resolver.pure_input_layouts(&ptb).await.unwrap_err(), - @"Conflicting types for input 3: u64 and u32" - ); - } - - /// *** Test Helpers - /// ************************************************************************ - /// ** - - type TypeOriginTable = Vec; - - fn a0_types() -> TypeOriginTable { - vec![ - struct_("0xa0", "m", "T0"), - struct_("0xa0", "m", "T1"), - struct_("0xa0", "m", "T2"), - struct_("0xa0", "n", "T0"), - ] - } - - fn a1_types() -> TypeOriginTable { - let mut types = a0_types(); - - types.extend([ - struct_("0xa1", "m", "T3"), - struct_("0xa1", "m", "T4"), - struct_("0xa1", "n", "T1"), - ]); - - types - } - - fn b0_types() -> TypeOriginTable { - vec![struct_("0xb0", "m", "T0")] - } - - fn c0_types() -> TypeOriginTable { - vec![struct_("0xc0", "m", "T0")] - } - - fn d0_types() -> TypeOriginTable { - vec![ - struct_("0xd0", "m", "O"), - struct_("0xd0", "m", "P"), - struct_("0xd0", "m", "Q"), - struct_("0xd0", "m", "R"), - struct_("0xd0", "m", "S"), - struct_("0xd0", "m", "T"), - ] - } - - fn e0_types() -> TypeOriginTable { - vec![struct_("0xe0", "m", "O")] - } - - fn s0_types() -> TypeOriginTable { - vec![struct_("0x1", "m", "T0")] - } - - fn s1_types() -> TypeOriginTable { - let mut types = s0_types(); - - types.extend([struct_("0x1", "m", "T1")]); - - types - } - - fn sui_types() -> TypeOriginTable { - vec![struct_("0x2", "object", "UID")] - } - - fn std_types() -> TypeOriginTable { - vec![ - struct_("0x1", "ascii", "String"), - struct_("0x1", "option", "Option"), - struct_("0x1", "string", "String"), - ] - } - - /// Build an in-memory package cache from locally compiled packages. - /// Assumes that all packages in `packages` are published (all modules - /// have a non-zero package address and all packages - /// have a 'published-at' address), and their transitive dependencies are - /// also in `packages`. - fn package_cache( - packages: impl IntoIterator, - ) -> (Arc>, Box) { - let packages_by_storage_id: BTreeMap = packages - .into_iter() - .map(|(version, package, origins)| { - (package_storage_id(&package), (version, package, origins)) - }) - .collect(); - - let packages = packages_by_storage_id - .iter() - .map(|(&storage_id, (version, compiled_package, origins))| { - let linkage = compiled_package - .dependency_ids - .published - .values() - .map(|dep_id| { - let storage_id = AccountAddress::from(*dep_id); - let runtime_id = package_runtime_id( - &packages_by_storage_id - .get(&storage_id) - .unwrap_or_else(|| panic!("Dependency {storage_id} not in store")) - .1, - ); - - (runtime_id, storage_id) - }) - .collect(); - - let package = cached_package(*version, linkage, compiled_package, origins); - (storage_id, package) - }) - .collect(); - - let inner = Arc::new(RwLock::new(InnerStore { - packages, - fetches: 0, - version_checks: 0, - })); - - let store = InMemoryPackageStore { - inner: inner.clone(), - }; - - let store_with_cache = PackageStoreWithLruCache::new(store); - - (inner, Box::new(store_with_cache)) - } - - fn cached_package( - version: u64, - linkage: Linkage, - package: &CompiledPackage, - origins: &TypeOriginTable, - ) -> Package { - let storage_id = package_storage_id(package); - let runtime_id = package_runtime_id(package); - let version = SequenceNumber::from_u64(version); - - let mut modules = BTreeMap::new(); - for unit in &package.package.root_compiled_units { - let NamedCompiledModule { name, module, .. } = &unit.unit; - - let origins = origins - .iter() - .filter(|key| key.module == name.as_str()) - .map(|key| (key.name.to_string(), key.package)) - .collect(); - - let module = match Module::read(module.clone(), origins) { - Ok(module) => module, - Err(struct_) => { - panic!("Missing type origin for {}::{struct_}", module.self_id()); - } - }; - - modules.insert(name.to_string(), module); - } - - Package { - storage_id, - runtime_id, - linkage, - version, - modules, - } - } - - fn package_storage_id(package: &CompiledPackage) -> AccountAddress { - AccountAddress::from(*package.published_at.as_ref().unwrap_or_else(|_| { - panic!( - "Package {} doesn't have published-at set", - package.package.compiled_package_info.package_name, - ) - })) - } - - fn package_runtime_id(package: &CompiledPackage) -> AccountAddress { - *package - .published_root_module() - .expect("No compiled module") - .address() - } - - fn build_package(dir: &str) -> CompiledPackage { - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.extend(["tests", "packages", dir]); - BuildConfig::new_for_testing().build(path).unwrap() - } - - fn addr(a: &str) -> AccountAddress { - AccountAddress::from_str(a).unwrap() - } - - fn struct_(a: &str, m: &'static str, n: &'static str) -> DatatypeKey { - DatatypeKey { - package: addr(a), - module: m.into(), - name: n.into(), - } - } - - fn type_(t: &str) -> TypeTag { - TypeTag::from_str(t).unwrap() - } - - fn key(t: &str) -> DatatypeKey { - let tag = StructTag::from_str(t).unwrap(); - DatatypeRef::from(&tag).as_key() - } - - struct InMemoryPackageStore { - /// All the contents are stored in an `InnerStore` that can be probed - /// and queried from outside. - inner: Arc>, - } - - struct InnerStore { - packages: BTreeMap, - fetches: usize, - version_checks: usize, - } - - #[async_trait] - impl PackageStore for InMemoryPackageStore { - async fn version(&self, id: AccountAddress) -> Result { - let mut inner = self.inner.as_ref().write().unwrap(); - inner.version_checks += 1; - inner - .packages - .get(&id) - .ok_or_else(|| Error::PackageNotFound(id)) - .map(|p| p.version) - } - - async fn fetch(&self, id: AccountAddress) -> Result> { - let mut inner = self.inner.as_ref().write().unwrap(); - inner.fetches += 1; - inner - .packages - .get(&id) - .cloned() - .ok_or_else(|| Error::PackageNotFound(id)) - .map(Arc::new) - } - } - - impl InnerStore { - fn replace(&mut self, id: AccountAddress, package: Package) { - self.packages.insert(id, package); - } - } -} diff --git a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__cross_module.snap b/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__cross_module.snap deleted file mode 100644 index 5c75b54f943..00000000000 --- a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__cross_module.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: crates/sui-package-resolver/src/lib.rs -expression: "format!(\"{layout:#}\")" ---- -struct 0xa0::n::T0 { - t: struct 0xa0::m::T1 { - a: address, - p: u16, - q: vector, - }, - u: struct 0xa0::m::T2 { - x: u8, - }, -} diff --git a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__cross_package.snap b/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__cross_package.snap deleted file mode 100644 index d2d94860119..00000000000 --- a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__cross_package.snap +++ /dev/null @@ -1,19 +0,0 @@ ---- -source: crates/sui-package-resolver/src/lib.rs -expression: "format!(\"{layout:#}\")" ---- -struct 0xb0::m::T0 { - m: struct 0xa0::m::T2 { - x: u8, - }, - n: struct 0xa0::n::T0 { - t: struct 0xa0::m::T1 { - a: address, - p: u16, - q: vector, - }, - u: struct 0xa0::m::T2 { - x: u8, - }, - }, -} diff --git a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__function_parameters.snap b/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__function_parameters.snap deleted file mode 100644 index 7d559a92925..00000000000 --- a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__function_parameters.snap +++ /dev/null @@ -1,39 +0,0 @@ ---- -source: crates/sui-package-resolver/src/lib.rs -expression: "format!(\"c0::m::foo: {foo:#?}\\n\\\n c0::m::bar: {bar:#?}\\n\\\n c0::m::baz: {baz:#?}\")" ---- -c0::m::foo: [] -c0::m::bar: [ - OpenSignature { - ref_: Some( - Immutable, - ), - body: Datatype( - DatatypeRef { - package: 00000000000000000000000000000000000000000000000000000000000000c0, - module: "m", - name: "T0", - }, - [], - ), - }, - OpenSignature { - ref_: Some( - Mutable, - ), - body: Datatype( - DatatypeRef { - package: 00000000000000000000000000000000000000000000000000000000000000a1, - module: "n", - name: "T1", - }, - [], - ), - }, -] -c0::m::baz: [ - OpenSignature { - ref_: None, - body: U8, - }, -] diff --git a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__functions.snap b/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__functions.snap deleted file mode 100644 index 8d1995f042d..00000000000 --- a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__functions.snap +++ /dev/null @@ -1,71 +0,0 @@ ---- -source: crates/sui-package-resolver/src/lib.rs -expression: "format!(\"c0::m::foo: {foo:#?}\\n\\\n c0::m::bar: {bar:#?}\\n\\\n c0::m::baz: {baz:#?}\")" ---- -c0::m::foo: FunctionDef { - visibility: Public, - is_entry: false, - type_params: [], - parameters: [], - return_: [], -} -c0::m::bar: FunctionDef { - visibility: Friend, - is_entry: false, - type_params: [], - parameters: [ - OpenSignature { - ref_: Some( - Immutable, - ), - body: Datatype( - DatatypeRef { - package: 00000000000000000000000000000000000000000000000000000000000000c0, - module: "m", - name: "T0", - }, - [], - ), - }, - OpenSignature { - ref_: Some( - Mutable, - ), - body: Datatype( - DatatypeRef { - package: 00000000000000000000000000000000000000000000000000000000000000a0, - module: "n", - name: "T1", - }, - [], - ), - }, - ], - return_: [ - OpenSignature { - ref_: None, - body: U64, - }, - ], -} -c0::m::baz: FunctionDef { - visibility: Private, - is_entry: false, - type_params: [], - parameters: [ - OpenSignature { - ref_: None, - body: U8, - }, - ], - return_: [ - OpenSignature { - ref_: None, - body: U16, - }, - OpenSignature { - ref_: None, - body: U32, - }, - ], -} diff --git a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__multiple_linkage_contexts.snap b/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__multiple_linkage_contexts.snap deleted file mode 100644 index ed5106f0d5f..00000000000 --- a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__multiple_linkage_contexts.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: crates/sui-package-resolver/src/lib.rs -expression: "format!(\"{layout:#}\")" ---- -struct 0xa0::m::T1<0xa0::m::T0, 0xa1::m::T3> { - a: address, - p: struct 0xa0::m::T0 { - b: bool, - v: vector { - a: address, - p: struct 0xa0::m::T2 { - x: u8, - }, - q: vector, - }>, - }, - q: vector, -} diff --git a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__pure_input_layouts.snap b/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__pure_input_layouts.snap deleted file mode 100644 index b646a7b92b9..00000000000 --- a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__pure_input_layouts.snap +++ /dev/null @@ -1,56 +0,0 @@ ---- -source: crates/sui-package-resolver/src/lib.rs -expression: output ---- ---- -??? -u64 -??? -u64 -??? -struct 0x1::option::Option<0x1::string::String> { - vec: vector, - }>, -} -vector { - vec: vector, - }>, -}> ---- -??? -u64 -??? -struct 0x1::option::Option { - vec: vector, -} -??? -struct 0x1::option::Option<0x1::string::String> { - vec: vector, - }>, -} -vector { - vec: vector, - }>, -}> ---- -??? -u64 -??? -??? -??? -struct 0x1::option::Option<0x1::string::String> { - vec: vector, - }>, -} -vector { - vec: vector, - }>, -}> ---- - diff --git a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__relinking.snap b/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__relinking.snap deleted file mode 100644 index 8be1e8cf0ee..00000000000 --- a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__relinking.snap +++ /dev/null @@ -1,49 +0,0 @@ ---- -source: crates/sui-package-resolver/src/lib.rs -expression: "format!(\"{layout:#}\")" ---- -struct 0xc0::m::T0 { - t: struct 0xa0::n::T0 { - t: struct 0xa0::m::T1 { - a: address, - p: u16, - q: vector, - }, - u: struct 0xa0::m::T2 { - x: u8, - }, - }, - u: struct 0xa1::n::T1 { - t: struct 0xa0::m::T1<0xa1::m::T3, u32> { - a: address, - p: struct 0xa1::m::T3 { - y: u16, - }, - q: vector, - }, - u: struct 0xa1::m::T4 { - z: u32, - }, - }, - v: struct 0xa0::m::T2 { - x: u8, - }, - w: struct 0xa1::m::T3 { - y: u16, - }, - x: struct 0xb0::m::T0 { - m: struct 0xa0::m::T2 { - x: u8, - }, - n: struct 0xa0::n::T0 { - t: struct 0xa0::m::T1 { - a: address, - p: u16, - q: vector, - }, - u: struct 0xa0::m::T2 { - x: u8, - }, - }, - }, -} diff --git a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__signature_instantiation.snap b/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__signature_instantiation.snap deleted file mode 100644 index 321d0cd2280..00000000000 --- a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__signature_instantiation.snap +++ /dev/null @@ -1,34 +0,0 @@ ---- -source: crates/sui-package-resolver/src/lib.rs -expression: "sig.instantiate(&[T::U64, T::Bool]).unwrap()" ---- -Struct( - StructTag { - address: 0000000000000000000000000000000000000000000000000000000000000002, - module: Identifier( - "table", - ), - name: Identifier( - "Table", - ), - type_params: [ - Bool, - Vector( - Struct( - StructTag { - address: 0000000000000000000000000000000000000000000000000000000000000001, - module: Identifier( - "option", - ), - name: Identifier( - "Option", - ), - type_params: [ - U64, - ], - }, - ), - ), - ], - }, -) diff --git a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__simple_type.snap b/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__simple_type.snap deleted file mode 100644 index f8cc32c9667..00000000000 --- a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__simple_type.snap +++ /dev/null @@ -1,14 +0,0 @@ ---- -source: crates/sui-package-resolver/src/lib.rs -expression: "format!(\"{layout:#}\")" ---- -struct 0xa0::m::T0 { - b: bool, - v: vector { - a: address, - p: struct 0xa0::m::T2 { - x: u8, - }, - q: vector, - }>, -} diff --git a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__structs.snap b/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__structs.snap deleted file mode 100644 index 5447f425bfb..00000000000 --- a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__structs.snap +++ /dev/null @@ -1,83 +0,0 @@ ---- -source: crates/sui-package-resolver/src/lib.rs -expression: "format!(\"a0::m::T0: {t0:#?}\\n\\\n a0::m::T1: {t1:#?}\\n\\\n a0::m::T2: {t2:#?}\",)" ---- -a0::m::T0: StructDef { - defining_id: 00000000000000000000000000000000000000000000000000000000000000a0, - abilities: [], - type_params: [], - fields: [ - ( - "b", - Bool, - ), - ( - "v", - Vector( - Datatype( - DatatypeRef { - package: 00000000000000000000000000000000000000000000000000000000000000a0, - module: "m", - name: "T1", - }, - [ - Datatype( - DatatypeRef { - package: 00000000000000000000000000000000000000000000000000000000000000a0, - module: "m", - name: "T2", - }, - [], - ), - U128, - ], - ), - ), - ), - ], -} -a0::m::T1: StructDef { - defining_id: 00000000000000000000000000000000000000000000000000000000000000a0, - abilities: [], - type_params: [ - StructTypeParameter { - constraints: [], - is_phantom: false, - }, - StructTypeParameter { - constraints: [], - is_phantom: false, - }, - ], - fields: [ - ( - "a", - Address, - ), - ( - "p", - TypeParameter( - 0, - ), - ), - ( - "q", - Vector( - TypeParameter( - 1, - ), - ), - ), - ], -} -a0::m::T2: StructDef { - defining_id: 00000000000000000000000000000000000000000000000000000000000000a0, - abilities: [], - type_params: [], - fields: [ - ( - "x", - U8, - ), - ], -} diff --git a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__system_package_invalidation.snap b/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__system_package_invalidation.snap deleted file mode 100644 index 57c8085986e..00000000000 --- a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__system_package_invalidation.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: crates/sui-package-resolver/src/lib.rs -expression: "format!(\"{layout:#}\")" ---- -struct 0x1::m::T1 { - x: u256, -} diff --git a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__upgraded_package.snap b/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__upgraded_package.snap deleted file mode 100644 index 95b2fb8509c..00000000000 --- a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__upgraded_package.snap +++ /dev/null @@ -1,16 +0,0 @@ ---- -source: crates/sui-package-resolver/src/lib.rs -expression: "format!(\"{layout:#}\")" ---- -struct 0xa1::n::T1 { - t: struct 0xa0::m::T1<0xa1::m::T3, u32> { - a: address, - p: struct 0xa1::m::T3 { - y: u16, - }, - q: vector, - }, - u: struct 0xa1::m::T4 { - z: u32, - }, -} diff --git a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__upgraded_package_non_defining_id.snap b/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__upgraded_package_non_defining_id.snap deleted file mode 100644 index 8794612a080..00000000000 --- a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__upgraded_package_non_defining_id.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: crates/sui-package-resolver/src/lib.rs -expression: "format!(\"{layout:#}\")" ---- -struct 0xa0::m::T1<0xa1::m::T3, 0xa0::m::T0> { - a: address, - p: struct 0xa1::m::T3 { - y: u16, - }, - q: vector { - a: address, - p: struct 0xa0::m::T2 { - x: u8, - }, - q: vector, - }>, - }>, -} diff --git a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__value_nesting_boundary.snap b/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__value_nesting_boundary.snap deleted file mode 100644 index c0cb21b4569..00000000000 --- a/crates/sui-package-resolver/src/snapshots/sui_package_resolver__tests__value_nesting_boundary.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: crates/sui-package-resolver/src/lib.rs -expression: "format!(\"{layout:#}\")" ---- -struct 0xa0::m::T1 { - a: address, - p: u8, - q: vector, -} diff --git a/crates/sui-package-resolver/tests/packages/a0/sources/m.move b/crates/sui-package-resolver/tests/packages/a0/sources/m.move deleted file mode 100644 index abdb250f3a1..00000000000 --- a/crates/sui-package-resolver/tests/packages/a0/sources/m.move +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[allow(unused_field)] -module a::m { - struct T0 { - b: bool, - v: vector>, - } - - struct T1 { - a: address, - p: P0, - q: vector, - } - - struct T2 { - x: u8, - } -} diff --git a/crates/sui-package-resolver/tests/packages/a0/sources/n.move b/crates/sui-package-resolver/tests/packages/a0/sources/n.move deleted file mode 100644 index 2b3f0fd633f..00000000000 --- a/crates/sui-package-resolver/tests/packages/a0/sources/n.move +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[allow(unused_field)] -module a::n { - struct T0 { - t: a::m::T1, - u: a::m::T2, - } -} diff --git a/crates/sui-package-resolver/tests/packages/a1/sources/m.move b/crates/sui-package-resolver/tests/packages/a1/sources/m.move deleted file mode 100644 index 4a241b24de0..00000000000 --- a/crates/sui-package-resolver/tests/packages/a1/sources/m.move +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[allow(unused_field)] -module a::m { - struct T0 { - b: bool, - v: vector>, - } - - struct T1 { - a: address, - p: P0, - q: vector, - } - - struct T2 { - x: u8, - } - - struct T3 { - y: u16, - } - - struct T4 { - z: u32, - } -} diff --git a/crates/sui-package-resolver/tests/packages/a1/sources/n.move b/crates/sui-package-resolver/tests/packages/a1/sources/n.move deleted file mode 100644 index b1080ad8313..00000000000 --- a/crates/sui-package-resolver/tests/packages/a1/sources/n.move +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[allow(unused_field)] -module a::n { - struct T0 { - t: a::m::T1, - u: a::m::T2, - } - - struct T1 { - t: a::m::T1, - u: a::m::T4, - } -} diff --git a/crates/sui-package-resolver/tests/packages/b0/sources/m.move b/crates/sui-package-resolver/tests/packages/b0/sources/m.move deleted file mode 100644 index a04925f8936..00000000000 --- a/crates/sui-package-resolver/tests/packages/b0/sources/m.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[allow(unused_field)] -module b::m { - use a::m::T2 as M; - use a::n::T0 as N; - - struct T0 { - m: M, - n: N, - } -} diff --git a/crates/sui-package-resolver/tests/packages/c0/sources/m.move b/crates/sui-package-resolver/tests/packages/c0/sources/m.move deleted file mode 100644 index b95feefc8ce..00000000000 --- a/crates/sui-package-resolver/tests/packages/c0/sources/m.move +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module c::m { - #[allow(unused_field)] - struct T0 { - t: a::n::T0, - u: a::n::T1, - v: a::m::T2, - w: a::m::T3, - x: b::m::T0, - } - - public fun foo() {} - - public(friend) fun bar(_t0: &T0, _t1: &mut a::n::T1): u64 { 42 } - - #[allow(unused_function)] - fun baz(x: u8): (u16, u32) { ((x as u16), (x as u32)) } -} diff --git a/crates/sui-package-resolver/tests/packages/d0/Move.toml b/crates/sui-package-resolver/tests/packages/d0/Move.toml deleted file mode 100644 index 9d5bbc7a3ba..00000000000 --- a/crates/sui-package-resolver/tests/packages/d0/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "D" -version = "0.0.1" -published-at = "0xd0" - -[dependencies] -Sui = { local = "../sui" } - -[addresses] -d = "0xd0" diff --git a/crates/sui-package-resolver/tests/packages/d0/sources/m.move b/crates/sui-package-resolver/tests/packages/d0/sources/m.move deleted file mode 100644 index cbc39bc51f5..00000000000 --- a/crates/sui-package-resolver/tests/packages/d0/sources/m.move +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[allow(unused_field)] -module d::m { - use sui::object::UID; - - struct O has key, store { - id: UID, - xs: vector, - } - - - struct T has copy, drop, store { - u: U, - v: V, - } - - struct P has key { id: UID } - struct Q { x: u32 } - struct R has copy, drop { x: u16 } - struct S has drop, store { x: u8 } -} diff --git a/crates/sui-package-resolver/tests/packages/e0/Move.toml b/crates/sui-package-resolver/tests/packages/e0/Move.toml deleted file mode 100644 index 2d6f06349aa..00000000000 --- a/crates/sui-package-resolver/tests/packages/e0/Move.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "E" -version = "0.0.1" -published-at = "0xe0" - -[dependencies] -Sui = { local = "../sui" } -StdLib = { local = "../std" } - -[addresses] -e = "0xe0" diff --git a/crates/sui-package-resolver/tests/packages/e0/sources/m.move b/crates/sui-package-resolver/tests/packages/e0/sources/m.move deleted file mode 100644 index 0a4997cd03f..00000000000 --- a/crates/sui-package-resolver/tests/packages/e0/sources/m.move +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[allow(unused_field)] -module e::m { - use std::ascii::String as ASCII; - use std::option::Option; - use std::string::String as UTF8; - use sui::object::UID; - - struct O has key { id: UID } - - public native fun foo( - o: &O, - x: u64, - p: &mut O, - y: T, - q: O, - z: Option, - w: vector>, - ); -} diff --git a/crates/sui-package-resolver/tests/packages/s0/sources/m.move b/crates/sui-package-resolver/tests/packages/s0/sources/m.move deleted file mode 100644 index a9b3e8ce00f..00000000000 --- a/crates/sui-package-resolver/tests/packages/s0/sources/m.move +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[allow(unused_field)] -module s::m { - struct T0 { - x: u64 - } -} diff --git a/crates/sui-package-resolver/tests/packages/s1/sources/m.move b/crates/sui-package-resolver/tests/packages/s1/sources/m.move deleted file mode 100644 index f13f8f4afdd..00000000000 --- a/crates/sui-package-resolver/tests/packages/s1/sources/m.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[allow(unused_field)] -module s::m { - struct T0 { - x: u64 - } - - struct T1 { - x: u256 - } -} diff --git a/crates/sui-package-resolver/tests/packages/sui/Move.toml b/crates/sui-package-resolver/tests/packages/sui/Move.toml deleted file mode 100644 index f6987b262ae..00000000000 --- a/crates/sui-package-resolver/tests/packages/sui/Move.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "Sui" -version = "0.0.1" -published-at = "0x2" - -[addresses] -sui = "0x2" diff --git a/crates/sui-package-resolver/tests/packages/sui/sources/object.move b/crates/sui-package-resolver/tests/packages/sui/sources/object.move deleted file mode 100644 index 3cace363e15..00000000000 --- a/crates/sui-package-resolver/tests/packages/sui/sources/object.move +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[allow(unused_field)] -module sui::object { - /// A test version of the UID type to allow us to have types with - /// `key` in these test packages. It has a different structure to - /// the real UID, but that is not relevant. - struct UID has store { - id: address, - } -} diff --git a/crates/sui-proc-macros/Cargo.toml b/crates/sui-proc-macros/Cargo.toml deleted file mode 100644 index 0ccf1b0d770..00000000000 --- a/crates/sui-proc-macros/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "sui-proc-macros" -version = "0.7.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[lib] -proc-macro = true - -[dependencies] -quote.workspace = true -syn = { version = "2", features = ["full", "fold", "extra-traits"] } -proc-macro2.workspace = true -sui-enum-compat-util.workspace = true - -[target.'cfg(msim)'.dependencies] -msim-macros.workspace = true diff --git a/crates/sui-proc-macros/src/lib.rs b/crates/sui-proc-macros/src/lib.rs deleted file mode 100644 index 38a93cbee43..00000000000 --- a/crates/sui-proc-macros/src/lib.rs +++ /dev/null @@ -1,590 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use proc_macro::TokenStream; -use quote::{quote, quote_spanned, ToTokens}; -use syn::{ - fold::{fold_expr, fold_item_macro, fold_stmt, Fold}, - parse::Parser, - parse2, parse_macro_input, - punctuated::Punctuated, - spanned::Spanned, - Attribute, BinOp, Data, DataEnum, DeriveInput, Expr, ExprBinary, ExprMacro, Item, ItemMacro, - Stmt, StmtMacro, Token, UnOp, -}; - -#[proc_macro_attribute] -pub fn init_static_initializers(_args: TokenStream, item: TokenStream) -> TokenStream { - let mut input = parse_macro_input!(item as syn::ItemFn); - - let body = &input.block; - input.block = syn::parse2(quote! { - { - // We have some lazily-initialized static state in the program. The initializers - // alter the thread-local hash container state any time they create a new hash - // container. Therefore, we need to ensure that these initializers are run in a - // separate thread before the first test thread is launched. Otherwise, they would - // run inside of the first test thread, but not subsequent ones. - // - // Note that none of this has any effect on process-level determinism. Without this - // code, we can still get the same test results from two processes started with the - // same seed. - // - // However, when using sim_test(check_determinism) or MSIM_TEST_CHECK_DETERMINISM=1, - // we want the same test invocation to be deterministic when run twice - // _in the same process_, so we need to take care of this. This will also - // be very important for being able to reproduce a failure that occurs in the Nth - // iteration of a multi-iteration test run. - std::thread::spawn(|| { - use sui_protocol_config::ProtocolConfig; - ::sui_simulator::telemetry_subscribers::init_for_testing(); - ::sui_simulator::sui_types::execution::get_denied_certificates(); - ::sui_simulator::sui_framework::BuiltInFramework::all_package_ids(); - ::sui_simulator::sui_types::gas::SuiGasStatus::new_unmetered(); - - // For reasons I can't understand, LruCache causes divergent behavior the second - // time one is constructed and inserted into, so construct one before the first - // test run for determinism. - let mut cache = ::sui_simulator::lru::LruCache::new(1.try_into().unwrap()); - cache.put(1, 1); - - { - // Initialize the static initializers here: - // https://github.com/move-language/move/blob/652badf6fd67e1d4cc2aa6dc69d63ad14083b673/language/tools/move-package/src/package_lock.rs#L12 - use std::path::PathBuf; - use sui_simulator::sui_move_build::{BuildConfig, SuiPackageHooks}; - use sui_simulator::tempfile::TempDir; - use sui_simulator::move_package::package_hooks::register_package_hooks; - - register_package_hooks(Box::new(SuiPackageHooks {})); - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.extend(["..", "..", "sui_programmability", "examples", "basics"]); - let mut build_config = BuildConfig::default(); - - build_config.config.install_dir = Some(TempDir::new().unwrap().into_path()); - let _all_module_bytes = build_config - .build(path) - .unwrap() - .get_package_bytes(/* with_unpublished_deps */ false); - } - - - use ::sui_simulator::anemo_tower::callback::CallbackLayer; - use ::sui_simulator::anemo_tower::trace::DefaultMakeSpan; - use ::sui_simulator::anemo_tower::trace::DefaultOnFailure; - use ::sui_simulator::anemo_tower::trace::TraceLayer; - use ::sui_simulator::narwhal_network::metrics::MetricsMakeCallbackHandler; - use ::sui_simulator::narwhal_network::metrics::NetworkMetrics; - - use std::sync::Arc; - use ::sui_simulator::fastcrypto::traits::KeyPair; - use ::sui_simulator::rand_crate::rngs::{StdRng, OsRng}; - use ::sui_simulator::rand::SeedableRng; - use ::sui_simulator::tower::ServiceBuilder; - - // anemo uses x509-parser, which has many lazy static variables. start a network to - // initialize all that static state before the first test. - let rt = ::sui_simulator::runtime::Runtime::new(); - rt.block_on(async move { - use ::sui_simulator::anemo::{Network, Request}; - - let make_network = |port: u16| { - let registry = prometheus::Registry::new(); - let inbound_network_metrics = - NetworkMetrics::new("sui", "inbound", ®istry); - let outbound_network_metrics = - NetworkMetrics::new("sui", "outbound", ®istry); - - let service = ServiceBuilder::new() - .layer( - TraceLayer::new_for_server_errors() - .make_span_with(DefaultMakeSpan::new().level(tracing::Level::INFO)) - .on_failure(DefaultOnFailure::new().level(tracing::Level::WARN)), - ) - .layer(CallbackLayer::new(MetricsMakeCallbackHandler::new( - Arc::new(inbound_network_metrics), - usize::MAX, - ))) - .service(::sui_simulator::anemo::Router::new()); - - let outbound_layer = ServiceBuilder::new() - .layer( - TraceLayer::new_for_client_and_server_errors() - .make_span_with(DefaultMakeSpan::new().level(tracing::Level::INFO)) - .on_failure(DefaultOnFailure::new().level(tracing::Level::WARN)), - ) - .layer(CallbackLayer::new(MetricsMakeCallbackHandler::new( - Arc::new(outbound_network_metrics), - usize::MAX, - ))) - .into_inner(); - - - Network::bind(format!("127.0.0.1:{}", port)) - .server_name("static-init-network") - .private_key( - ::sui_simulator::fastcrypto::ed25519::Ed25519KeyPair::generate(&mut StdRng::from_rng(OsRng).unwrap()) - .private() - .0 - .to_bytes(), - ) - .start(service) - .unwrap() - }; - let n1 = make_network(80); - let n2 = make_network(81); - - let _peer = n1.connect(n2.local_addr()).await.unwrap(); - }); - }).join().unwrap(); - - #body - } - }) - .expect("Parsing failure"); - - let result = quote! { - #input - }; - - result.into() -} - -/// The sui_test macro will invoke either `#[msim::test]` or `#[tokio::test]`, -/// depending on whether the simulator config var is enabled. -/// -/// This should be used for tests that can meaningfully run in either -/// environment. -#[proc_macro_attribute] -pub fn sui_test(args: TokenStream, item: TokenStream) -> TokenStream { - let input = parse_macro_input!(item as syn::ItemFn); - let arg_parser = Punctuated::::parse_terminated; - let args = arg_parser.parse(args).unwrap().into_iter(); - - let header = if cfg!(msim) { - quote! { - #[::sui_simulator::sim_test(crate = "sui_simulator", #(#args)* )] - } - } else { - quote! { - #[::tokio::test(#(#args)*)] - } - }; - - let result = quote! { - #header - #[::sui_macros::init_static_initializers] - #input - }; - - result.into() -} - -/// The sim_test macro will invoke `#[msim::test]` if the simulator config var -/// is enabled. -/// -/// Otherwise, it will emit an ignored test - if forcibly run, the ignored test -/// will panic. -/// -/// This macro must be used in order to pass any simulator-specific arguments, -/// such as `check_determinism`, which is not understood by tokio. -#[proc_macro_attribute] -pub fn sim_test(args: TokenStream, item: TokenStream) -> TokenStream { - let input = parse_macro_input!(item as syn::ItemFn); - let arg_parser = Punctuated::::parse_terminated; - let args = arg_parser.parse(args).unwrap().into_iter(); - - let ignore = input - .attrs - .iter() - .find(|attr| attr.path().is_ident("ignore")) - .map_or(quote! {}, |_| quote! { #[ignore] }); - - let result = if cfg!(msim) { - let sig = &input.sig; - let return_type = &sig.output; - let body = &input.block; - quote! { - #[::sui_simulator::sim_test(crate = "sui_simulator", #(#args)*)] - #[::sui_macros::init_static_initializers] - #ignore - #sig { - async fn body_fn() #return_type { #body } - - let ret = body_fn().await; - - ::sui_simulator::task::shutdown_all_nodes(); - - // all node handles should have been dropped after the above block exits, but task - // shutdown is asynchronous, so we need a brief delay before checking for leaks. - tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; - - assert_eq!( - sui_simulator::NodeLeakDetector::get_current_node_count(), - 0, - "SuiNode leak detected" - ); - - ret - } - } - } else { - let fn_name = &input.sig.ident; - let sig = &input.sig; - let body = &input.block; - quote! { - #[allow(clippy::needless_return)] - #[tokio::test] - #ignore - #sig { - if std::env::var("SUI_SKIP_SIMTESTS").is_ok() { - println!("not running test {} in `cargo test`: SUI_SKIP_SIMTESTS is set", stringify!(#fn_name)); - - struct Ret; - - impl From for () { - fn from(_ret: Ret) -> Self { - } - } - - impl From for Result<(), E> { - fn from(_ret: Ret) -> Self { - Ok(()) - } - } - - return Ret.into(); - } - - #body - } - } - }; - - result.into() -} - -#[proc_macro] -pub fn checked_arithmetic(input: TokenStream) -> TokenStream { - let input_file = CheckArithmetic.fold_file(parse_macro_input!(input)); - - let output_items = input_file.items; - - let output = quote! { - #(#output_items)* - }; - - TokenStream::from(output) -} - -#[proc_macro_attribute] -pub fn with_checked_arithmetic(_attr: TokenStream, item: TokenStream) -> TokenStream { - let input_item = parse_macro_input!(item as Item); - match input_item { - Item::Fn(input_fn) => { - let transformed_fn = CheckArithmetic.fold_item_fn(input_fn); - TokenStream::from(quote! { #transformed_fn }) - } - Item::Impl(input_impl) => { - let transformed_impl = CheckArithmetic.fold_item_impl(input_impl); - TokenStream::from(quote! { #transformed_impl }) - } - item => { - let transformed_impl = CheckArithmetic.fold_item(item); - TokenStream::from(quote! { #transformed_impl }) - } - } -} - -struct CheckArithmetic; - -impl CheckArithmetic { - fn maybe_skip_macro(&self, attrs: &mut Vec) -> bool { - if let Some(idx) = attrs - .iter() - .position(|attr| attr.path().is_ident("skip_checked_arithmetic")) - { - // Skip processing macro because it is annotated with - // #[skip_checked_arithmetic] - attrs.remove(idx); - true - } else { - false - } - } - - fn process_macro_contents( - &mut self, - tokens: proc_macro2::TokenStream, - ) -> syn::Result { - // Parse the macro's contents as a comma-separated list of expressions. - let parser = Punctuated::::parse_terminated; - let Ok(exprs) = parser.parse(tokens.clone().into()) else { - return Err(syn::Error::new_spanned( - tokens, - "could not process macro contents - use #[skip_checked_arithmetic] to skip this macro", - )); - }; - - // Fold each sub expression. - let folded_exprs = exprs - .into_iter() - .map(|expr| self.fold_expr(expr)) - .collect::>(); - - // Convert the folded expressions back into tokens and reconstruct the macro. - let mut folded_tokens = proc_macro2::TokenStream::new(); - for (i, folded_expr) in folded_exprs.into_iter().enumerate() { - if i > 0 { - folded_tokens.extend(std::iter::once::( - proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone).into(), - )); - } - folded_expr.to_tokens(&mut folded_tokens); - } - - Ok(folded_tokens) - } -} - -impl Fold for CheckArithmetic { - fn fold_stmt(&mut self, stmt: Stmt) -> Stmt { - let stmt = fold_stmt(self, stmt); - if let Stmt::Macro(stmt_macro) = stmt { - let StmtMacro { - mut attrs, - mut mac, - semi_token, - } = stmt_macro; - - if self.maybe_skip_macro(&mut attrs) { - Stmt::Macro(StmtMacro { - attrs, - mac, - semi_token, - }) - } else { - match self.process_macro_contents(mac.tokens.clone()) { - Ok(folded_tokens) => { - mac.tokens = folded_tokens; - Stmt::Macro(StmtMacro { - attrs, - mac, - semi_token, - }) - } - Err(error) => parse2(error.to_compile_error()).unwrap(), - } - } - } else { - stmt - } - } - - fn fold_item_macro(&mut self, mut item_macro: ItemMacro) -> ItemMacro { - if !self.maybe_skip_macro(&mut item_macro.attrs) { - let err = syn::Error::new_spanned( - item_macro.to_token_stream(), - "cannot process macros - use #[skip_checked_arithmetic] to skip \ - processing this macro", - ); - - return parse2(err.to_compile_error()).unwrap(); - } - fold_item_macro(self, item_macro) - } - - fn fold_expr(&mut self, expr: Expr) -> Expr { - let span = expr.span(); - let expr = fold_expr(self, expr); - let expr = match expr { - Expr::Macro(expr_macro) => { - let ExprMacro { mut attrs, mut mac } = expr_macro; - - if self.maybe_skip_macro(&mut attrs) { - return Expr::Macro(ExprMacro { attrs, mac }); - } else { - match self.process_macro_contents(mac.tokens.clone()) { - Ok(folded_tokens) => { - mac.tokens = folded_tokens; - let expr_macro = Expr::Macro(ExprMacro { attrs, mac }); - quote!(#expr_macro) - } - Err(error) => { - return Expr::Verbatim(error.to_compile_error()); - } - } - } - } - - Expr::Binary(expr_binary) => { - let ExprBinary { - attrs, - mut left, - op, - mut right, - } = expr_binary; - - fn remove_parens(expr: &mut Expr) { - if let Expr::Paren(paren) = expr { - // i don't even think rust allows this, but just in case - assert!(paren.attrs.is_empty(), "TODO: attrs on parenthesized"); - *expr = *paren.expr.clone(); - } - } - - macro_rules! wrap_op { - ($left: expr, $right: expr, $method: ident, $span: expr) => {{ - // Remove parens from exprs since both sides get assigned to tmp variables. - // otherwise we get lint errors - remove_parens(&mut $left); - remove_parens(&mut $right); - - quote_spanned!($span => { - // assign in one stmt in case either #left or #right contains - // references to `left` or `right` symbols. - let (left, right) = (#left, #right); - left.$method(right) - .unwrap_or_else(|| - panic!( - "Overflow or underflow in {} {} + {}", - stringify!($method), - left, - right, - ) - ) - }) - }}; - } - - macro_rules! wrap_op_assign { - ($left: expr, $right: expr, $method: ident, $span: expr) => {{ - // Remove parens from exprs since both sides get assigned to tmp variables. - // otherwise we get lint errors - remove_parens(&mut $left); - remove_parens(&mut $right); - - quote_spanned!($span => { - // assign in one stmt in case either #left or #right contains - // references to `left` or `right` symbols. - let (left, right) = (&mut #left, #right); - *left = (*left).$method(right) - .unwrap_or_else(|| - panic!( - "Overflow or underflow in {} {} + {}", - stringify!($method), - *left, - right - ) - ) - }) - }}; - } - - match op { - BinOp::Add(_) => { - wrap_op!(left, right, checked_add, span) - } - BinOp::Sub(_) => { - wrap_op!(left, right, checked_sub, span) - } - BinOp::Mul(_) => { - wrap_op!(left, right, checked_mul, span) - } - BinOp::Div(_) => { - wrap_op!(left, right, checked_div, span) - } - BinOp::Rem(_) => { - wrap_op!(left, right, checked_rem, span) - } - BinOp::AddAssign(_) => { - wrap_op_assign!(left, right, checked_add, span) - } - BinOp::SubAssign(_) => { - wrap_op_assign!(left, right, checked_sub, span) - } - BinOp::MulAssign(_) => { - wrap_op_assign!(left, right, checked_mul, span) - } - BinOp::DivAssign(_) => { - wrap_op_assign!(left, right, checked_div, span) - } - BinOp::RemAssign(_) => { - wrap_op_assign!(left, right, checked_rem, span) - } - _ => { - let expr_binary = ExprBinary { - attrs, - left, - op, - right, - }; - quote_spanned!(span => #expr_binary) - } - } - } - Expr::Unary(expr_unary) => { - let op = &expr_unary.op; - let operand = &expr_unary.expr; - match op { - UnOp::Neg(_) => { - quote_spanned!(span => #operand.checked_neg().expect("Overflow or underflow in negation")) - } - _ => quote_spanned!(span => #expr_unary), - } - } - _ => quote_spanned!(span => #expr), - }; - - parse2(expr).unwrap() - } -} - -/// This proc macro generates a function `order_to_variant_map` which returns a -/// map of the position of each variant to the name of the variant. -/// It is intended to catch changes in enum order when backward compat is -/// required. ```rust,ignore -/// /// Example for this enum -/// #[derive(EnumVariantOrder)] -/// pub enum MyEnum { -/// A, -/// B(u64), -/// C{x: bool, y: i8}, -/// } -/// let order_map = MyEnum::order_to_variant_map(); -/// assert!(order_map.get(0).unwrap() == "A"); -/// assert!(order_map.get(1).unwrap() == "B"); -/// assert!(order_map.get(2).unwrap() == "C"); -/// ``` -#[proc_macro_derive(EnumVariantOrder)] -pub fn enum_variant_order_derive(input: TokenStream) -> TokenStream { - let ast = parse_macro_input!(input as DeriveInput); - let name = &ast.ident; - - if let Data::Enum(DataEnum { variants, .. }) = ast.data { - let variant_entries = variants - .iter() - .enumerate() - .map(|(index, variant)| { - let variant_name = variant.ident.to_string(); - quote! { - map.insert( #index as u64, (#variant_name).to_string()); - } - }) - .collect::>(); - - let deriv = quote! { - impl sui_enum_compat_util::EnumOrderMap for #name { - fn order_to_variant_map() -> std::collections::BTreeMap { - let mut map = std::collections::BTreeMap::new(); - #(#variant_entries)* - map - } - } - }; - - deriv.into() - } else { - panic!("EnumVariantOrder can only be used with enums."); - } -} diff --git a/crates/sui-protocol-config-macros/Cargo.toml b/crates/sui-protocol-config-macros/Cargo.toml deleted file mode 100644 index 920fe7f6848..00000000000 --- a/crates/sui-protocol-config-macros/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "sui-protocol-config-macros" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2.workspace = true -syn.workspace = true -quote.workspace = true diff --git a/crates/sui-protocol-config-macros/src/lib.rs b/crates/sui-protocol-config-macros/src/lib.rs deleted file mode 100644 index 5a2135fb438..00000000000 --- a/crates/sui-protocol-config-macros/src/lib.rs +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -extern crate proc_macro; - -use proc_macro::TokenStream; -use quote::quote; -use syn::{parse_macro_input, Data, DeriveInput, Fields, Type}; - -/// This proc macro generates getters, attribute lookup, etc for protocol config -/// fields of type `Option` and for the feature flags -/// Example for a field: `new_constant: Option`, and for feature flags -/// `feature: bool`, we derive ```rust,ignore -/// /// Returns the value of the field if exists at the given version, -/// otherise panic pub fn new_constant(&self) -> u64 { -/// self.new_constant.expect(Self::CONSTANT_ERR_MSG) -/// } -/// /// Returns the value of the field if exists at the given version, -/// otherise None. pub fn new_constant_as_option(&self) -> Option { -/// self.new_constant -/// } -/// // We auto derive an enum such that the variants are all the types of -/// the fields pub enum ProtocolConfigValue { -/// u32(u32), -/// u64(u64), -/// .............. -/// } -/// // This enum is used to return field values so that the type is also -/// encoded in the response -/// -/// /// Returns the value of the field if exists at the given version, -/// otherise None pub fn lookup_attr(&self, value: String) -> -/// Option; -/// -/// /// Returns a map of all configs to values -/// pub fn attr_map(&self) -> std::collections::BTreeMap>; -/// -/// /// Returns a feature by the string name or None if it doesn't exist -/// pub fn lookup_feature(&self, value: String) -> Option; -/// -/// /// Returns a map of all features to values -/// pub fn feature_map(&self) -> std::collections::BTreeMap; -/// ``` -#[proc_macro_derive(ProtocolConfigAccessors)] -pub fn accessors_macro(input: TokenStream) -> TokenStream { - let ast = parse_macro_input!(input as DeriveInput); - - let struct_name = &ast.ident; - let data = &ast.data; - let mut inner_types = vec![]; - - let tokens = match data { - Data::Struct(data_struct) => match &data_struct.fields { - // Operate on each field of the ProtocolConfig struct - Fields::Named(fields_named) => fields_named.named.iter().filter_map(|field| { - // Extract field name and type - let field_name = field.ident.as_ref().expect("Field must be named"); - let field_type = &field.ty; - // Check if field is of type Option - match field_type { - Type::Path(type_path) - if type_path - .path - .segments - .last() - .map_or(false, |segment| segment.ident == "Option") => - { - // Extract inner type T from Option - let inner_type = if let syn::PathArguments::AngleBracketed( - angle_bracketed_generic_arguments, - ) = &type_path.path.segments.last().unwrap().arguments - { - if let Some(syn::GenericArgument::Type(ty)) = - angle_bracketed_generic_arguments.args.first() - { - ty.clone() - } else { - panic!("Expected a type argument."); - } - } else { - panic!("Expected angle bracketed arguments."); - }; - - let as_option_name = format!("{field_name}_as_option"); - let as_option_name: proc_macro2::TokenStream = - as_option_name.parse().unwrap(); - let test_setter_name: proc_macro2::TokenStream = - format!("set_{field_name}_for_testing").parse().unwrap(); - let test_un_setter_name: proc_macro2::TokenStream = - format!("disable_{field_name}_for_testing").parse().unwrap(); - let test_setter_from_str_name: proc_macro2::TokenStream = - format!("set_{field_name}_from_str_for_testing").parse().unwrap(); - - let getter = quote! { - // Derive the getter - pub fn #field_name(&self) -> #inner_type { - self.#field_name.expect(Self::CONSTANT_ERR_MSG) - } - - pub fn #as_option_name(&self) -> #field_type { - self.#field_name - } - }; - - let test_setter = quote! { - // Derive the setter - pub fn #test_setter_name(&mut self, val: #inner_type) { - self.#field_name = Some(val); - } - - // Derive the setter from String - pub fn #test_setter_from_str_name(&mut self, val: String) { - use std::str::FromStr; - self.#test_setter_name(#inner_type::from_str(&val).unwrap()); - } - - // Derive the un-setter - pub fn #test_un_setter_name(&mut self) { - self.#field_name = None; - } - }; - - let value_setter = quote! { - stringify!(#field_name) => self.#test_setter_from_str_name(val), - }; - - - let value_lookup = quote! { - stringify!(#field_name) => self.#field_name.map(|v| ProtocolConfigValue::#inner_type(v)), - }; - - let field_name_str = quote! { - stringify!(#field_name) - }; - - // Track all the types seen - if inner_types.contains(&inner_type) { - None - } else { - inner_types.push(inner_type.clone()); - Some(quote! { - #inner_type - }) - }; - - Some(((getter, (test_setter, value_setter)), (value_lookup, field_name_str))) - } - _ => None, - } - }), - _ => panic!("Only named fields are supported."), - }, - _ => panic!("Only structs supported."), - }; - - #[allow(clippy::type_complexity)] - let ((getters, (test_setters, value_setters)), (value_lookup, field_names_str)): ( - (Vec<_>, (Vec<_>, Vec<_>)), - (Vec<_>, Vec<_>), - ) = tokens.unzip(); - let output = quote! { - // For each getter, expand it out into a function in the impl block - impl #struct_name { - const CONSTANT_ERR_MSG: &'static str = "protocol constant not present in current protocol version"; - #(#getters)* - - /// Lookup a config attribute by its string representation - pub fn lookup_attr(&self, value: String) -> Option { - match value.as_str() { - #(#value_lookup)* - _ => None, - } - } - - /// Get a map of all config attribute from string representations - pub fn attr_map(&self) -> std::collections::BTreeMap> { - vec![ - #(((#field_names_str).to_owned(), self.lookup_attr((#field_names_str).to_owned())),)* - ].into_iter().collect() - } - - /// Get the feature flags - pub fn lookup_feature(&self, value: String) -> Option { - self.feature_flags.lookup_attr(value) - } - - pub fn feature_map(&self) -> std::collections::BTreeMap { - self.feature_flags.attr_map() - } - } - - // For each attr, derive a setter from the raw value and from string repr - impl #struct_name { - #(#test_setters)* - - pub fn set_attr_for_testing(&mut self, attr: String, val: String) { - match attr.as_str() { - #(#value_setters)* - _ => panic!("Attempting to set unknown attribute: {}", attr), - } - } - } - - #[allow(non_camel_case_types)] - #[derive(Clone, Serialize, Debug, PartialEq, Deserialize, schemars::JsonSchema)] - pub enum ProtocolConfigValue { - #(#inner_types(#inner_types),)* - } - - impl std::fmt::Display for ProtocolConfigValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use std::fmt::Write; - let mut writer = String::new(); - match self { - #( - ProtocolConfigValue::#inner_types(x) => { - write!(writer, "{}", x)?; - } - )* - } - write!(f, "{}", writer) - } - } - }; - - TokenStream::from(output) -} - -#[proc_macro_derive(ProtocolConfigFeatureFlagsGetters)] -pub fn feature_flag_getters_macro(input: TokenStream) -> TokenStream { - let ast = parse_macro_input!(input as DeriveInput); - - let struct_name = &ast.ident; - let data = &ast.data; - - let getters = match data { - Data::Struct(data_struct) => match &data_struct.fields { - // Operate on each field of the ProtocolConfig struct - Fields::Named(fields_named) => fields_named.named.iter().filter_map(|field| { - // Extract field name and type - let field_name = field.ident.as_ref().expect("Field must be named"); - let field_type = &field.ty; - // Check if field is of type bool - match field_type { - Type::Path(type_path) - if type_path - .path - .segments - .last() - .map_or(false, |segment| segment.ident == "bool") => - { - Some(( - quote! { - // Derive the getter - pub fn #field_name(&self) -> #field_type { - self.#field_name - } - }, - ( - quote! { - stringify!(#field_name) => Some(self.#field_name), - }, - quote! { - stringify!(#field_name) - }, - ), - )) - } - _ => None, - } - }), - _ => panic!("Only named fields are supported."), - }, - _ => panic!("Only structs supported."), - }; - - let (by_fn_getters, (string_name_getters, field_names)): (Vec<_>, (Vec<_>, Vec<_>)) = - getters.unzip(); - - let output = quote! { - // For each getter, expand it out into a function in the impl block - impl #struct_name { - #(#by_fn_getters)* - - /// Lookup a feature flag by its string representation - pub fn lookup_attr(&self, value: String) -> Option { - match value.as_str() { - #(#string_name_getters)* - _ => None, - } - } - - /// Get a map of all feature flags from string representations - pub fn attr_map(&self) -> std::collections::BTreeMap { - vec![ - // Okay to unwrap since we added all above - #(((#field_names).to_owned(), self.lookup_attr((#field_names).to_owned()).unwrap()),)* - ].into_iter().collect() - } - } - }; - - TokenStream::from(output) -} diff --git a/crates/sui-protocol-config/Cargo.toml b/crates/sui-protocol-config/Cargo.toml deleted file mode 100644 index 5d80c99ba7c..00000000000 --- a/crates/sui-protocol-config/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "sui-protocol-config" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -serde.workspace = true -tracing.workspace = true -serde_with.workspace = true -sui-protocol-config-macros.workspace = true -schemars.workspace = true -insta.workspace = true -clap.workspace = true - -[dev-dependencies] -insta.workspace = true diff --git a/crates/sui-protocol-config/src/lib.rs b/crates/sui-protocol-config/src/lib.rs deleted file mode 100644 index 39887054d06..00000000000 --- a/crates/sui-protocol-config/src/lib.rs +++ /dev/null @@ -1,2480 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - cell::RefCell, - collections::BTreeSet, - sync::atomic::{AtomicBool, Ordering}, -}; - -use clap::*; -use serde::{Deserialize, Serialize}; -use serde_with::skip_serializing_none; -use sui_protocol_config_macros::{ProtocolConfigAccessors, ProtocolConfigFeatureFlagsGetters}; -use tracing::{info, warn}; - -/// The minimum and maximum protocol versions supported by this build. -const MIN_PROTOCOL_VERSION: u64 = 1; -const MAX_PROTOCOL_VERSION: u64 = 42; - -// Record history of protocol version allocations here: -// -// Version 1: Original version. -// Version 2: Framework changes, including advancing epoch_start_time in -// safemode. Version 3: gas model v2, including all sui conservation fixes. Fix -// for loaded child object changes, enable package upgrades, add -// limits on `max_size_written_objects`, -// `max_size_written_objects_system_tx` Version 4: New reward slashing rate. -// Framework changes to skip stake susbidy when the epoch length is -// short. Version 5: Package upgrade compatibility error fix. New gas cost -// table. New scoring decision mechanism that includes up to f -// scoring authorities. Version 6: Change to how bytes are charged in the gas -// meter, increase buffer stake to 0.5f Version 7: Disallow adding new abilities -// to types during package upgrades, -// disable_invariant_violation_check_in_swap_loc, disable init -// functions becoming entry, hash module bytes individually before -// computing package digest. Version 8: Disallow changing abilities and type -// constraints for type parameters in structs during upgrades. -// Version 9: Limit the length of Move idenfitiers to 128. -// Disallow extraneous module bytes, -// advance_to_highest_supported_protocol_version, -// Version 10:increase bytecode verifier `max_verifier_meter_ticks_per_function` -// and `max_meter_ticks_per_module` limits each from 6_000_000 to -// 16_000_000. sui-system framework changes. -// Version 11: Introduce `std::type_name::get_with_original_ids` to the system -// frameworks. Bound max depth of values within the VM. Version 12: Changes to -// deepbook in framework to add API for querying marketplace. Change -// NW Batch to use versioned metadata field. Changes to sui-system -// package to add PTB-friendly unstake function, and minor cleanup. Version 13: -// System package change deprecating `0xdee9::clob` and `0xdee9::custodian`, -// replaced by `0xdee9::clob_v2` and `0xdee9::custodian_v2`. -// Version 14: Introduce a config variable to allow charging of computation to -// be either bucket base or rounding up. The presence of -// `gas_rounding_step` (or `None`) decides whether rounding is -// applied or not. Version 15: Add reordering of user transactions by gas price -// after consensus. Add `sui::table_vec::drop` to the framework via -// a system package upgrade. Version 16: Enabled simplified_unwrap_then_delete -// feature flag, which allows the execution engine to no longer -// consult the object store when generating unwrapped_then_deleted in the -// effects; this also allows us to stop including wrapped tombstones -// in accumulator. Add self-matching prevention for deepbook. -// Version 17: Enable upgraded multisig support. -// Version 18: Introduce execution layer versioning, preserve all existing -// behaviour in v0. Gas minimum charges moved to be a multiplier -// over the reference gas price. In this protocol version the -// multiplier is the same as the lowest bucket of computation such -// that the minimum transaction cost is the same as the minimum computation -// bucket. -// Add a feature flag to indicate the changes semantics of -// `base_tx_cost_fixed`. Version 19: Changes to sui-system package to enable -// liquid staking. Add limit for total size of events. -// Increase limit for number of events emitted to 1024. -// Version 20: Enables the flag `narwhal_new_leader_election_schedule` for the -// new narwhal leader schedule algorithm for enhanced fault -// tolerance and sets the bad node stake threshold value. Both -// values are set for all the environments except mainnet. Version 21: ZKLogin -// known providers. Version 22: Child object format change. -// Version 23: Enabling the flag `narwhal_new_leader_election_schedule` for the -// new narwhal leader schedule algorithm for enhanced fault -// tolerance and sets the bad node stake threshold value for -// mainnet. Version 24: Re-enable simple gas conservation checks. -// Package publish/upgrade number in a single transaction limited. -// JWK / authenticator state flags. -// Version 25: Add sui::table_vec::swap and sui::table_vec::swap_remove to -// system packages. Version 26: New gas model version. -// Add support for receiving objects off of other objects in devnet -// only. Version 28: Add sui::zklogin::verify_zklogin_id and related functions -// to sui framework. Enable transaction effects v2 in devnet. -// Version 29: Add verify_legacy_zklogin_address flag to sui framework, this add -// ability to verify transactions from a legacy zklogin address. -// Version 30: Enable Narwhal CertificateV2 -// Add support for random beacon. -// Enable transaction effects v2 in testnet. -// Deprecate supported oauth providers from protocol config and rely -// on node config instead. -// In execution, has_public_transfer is recomputed when loading the -// object. Add support for shared obj deletion and receiving objects -// off of other objects in devnet only. Version 31: Add support for shared -// object deletion in devnet only. Add support for getting object ID -// referenced by receiving object in sui framework. Create new -// execution layer version, and preserve previous behavior in v1. -// Update semantics of `sui::transfer::receive` and add -// `sui::transfer::public_receive`. Version 32: Add delete functions for -// VerifiedID and VerifiedIssuer. Add sui::token module to sui -// framework. Enable transfer to object in testnet. -// Enable Narwhal CertificateV2 on mainnet -// Make critbit tree and order getters public in deepbook. -// Version 33: Add support for `receiving_object_id` function in framework -// Hardened OTW check. -// Enable transfer-to-object in mainnet. -// Enable shared object deletion in testnet. -// Enable effects v2 in mainnet. -// Version 34: Framework changes for random beacon. -// Version 35: Add poseidon hash function. -// Enable coin deny list. -// Version 36: Enable group operations native functions in devnet. -// Enable shared object deletion in mainnet. -// Set the consensus accepted transaction size and the included -// transactions size in the proposed block. Version 37: Reject entry functions -// with mutable Random. Version 38: Introduce limits for binary tables size. -// Version 39: Allow skipped epochs for randomness updates. -// Extra version to fix `test_upgrade_compatibility` simtest. -// Version 40: -// Version 41: Enable group operations native functions in testnet and mainnet -// (without msm). Version 42: Migrate sui framework and related code to Move -// 2024 -#[derive(Copy, Clone, Debug, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] -pub struct ProtocolVersion(u64); - -impl ProtocolVersion { - // The minimum and maximum protocol version supported by this binary. - // Counterintuitively, this constant may change over time as support for old - // protocol versions is removed from the source. This ensures that when a - // new network (such as a testnet) is created, its genesis committee will - // use a protocol version that is actually supported by the binary. - pub const MIN: Self = Self(MIN_PROTOCOL_VERSION); - - pub const MAX: Self = Self(MAX_PROTOCOL_VERSION); - - #[cfg(not(msim))] - const MAX_ALLOWED: Self = Self::MAX; - - // We create one additional "fake" version in simulator builds so that we can - // test upgrades. - #[cfg(msim)] - pub const MAX_ALLOWED: Self = Self(MAX_PROTOCOL_VERSION + 1); - - pub fn new(v: u64) -> Self { - Self(v) - } - - pub const fn as_u64(&self) -> u64 { - self.0 - } - - // For serde deserialization - we don't define a Default impl because there - // isn't a single universally appropriate default value. - pub fn max() -> Self { - Self::MAX - } -} - -impl From for ProtocolVersion { - fn from(v: u64) -> Self { - Self::new(v) - } -} - -impl std::ops::Sub for ProtocolVersion { - type Output = Self; - fn sub(self, rhs: u64) -> Self::Output { - Self::new(self.0 - rhs) - } -} - -impl std::ops::Add for ProtocolVersion { - type Output = Self; - fn add(self, rhs: u64) -> Self::Output { - Self::new(self.0 + rhs) - } -} - -/// Models the set of protocol versions supported by a validator. -/// The `sui-node` binary will always use the SYSTEM_DEFAULT constant, but for -/// testing we need to be able to inject arbitrary versions into SuiNode. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, Hash, PartialEq, Eq)] -pub struct SupportedProtocolVersions { - pub min: ProtocolVersion, - pub max: ProtocolVersion, -} - -impl SupportedProtocolVersions { - pub const SYSTEM_DEFAULT: Self = Self { - min: ProtocolVersion::MIN, - max: ProtocolVersion::MAX, - }; - - /// Use by VersionedProtocolMessage implementors to describe in which range - /// of versions a message variant is supported. - pub fn new_for_message(min: u64, max: u64) -> Self { - let min = ProtocolVersion::new(min); - let max = ProtocolVersion::new(max); - Self { min, max } - } - - pub fn new_for_testing(min: u64, max: u64) -> Self { - let min = min.into(); - let max = max.into(); - Self { min, max } - } - - pub fn is_version_supported(&self, v: ProtocolVersion) -> bool { - v.0 >= self.min.0 && v.0 <= self.max.0 - } -} - -#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Copy, PartialOrd, Ord, Eq, ValueEnum)] -pub enum Chain { - Mainnet, - Testnet, - Unknown, -} - -impl Default for Chain { - fn default() -> Self { - Self::Unknown - } -} - -pub struct Error(pub String); - -/// Records on/off feature flags that may vary at each protocol version. -#[derive(Default, Clone, Serialize, Debug, ProtocolConfigFeatureFlagsGetters)] -struct FeatureFlags { - // Add feature flags here, e.g.: - // new_protocol_feature: bool, - #[serde(skip_serializing_if = "is_false")] - package_upgrades: bool, - // If true, validators will commit to the root state digest - // in end of epoch checkpoint proposals - #[serde(skip_serializing_if = "is_false")] - commit_root_state_digest: bool, - // Pass epoch start time to advance_epoch safe mode function. - #[serde(skip_serializing_if = "is_false")] - advance_epoch_start_time_in_safe_mode: bool, - // If true, apply the fix to correctly capturing loaded child object versions in execution's - // object runtime. - #[serde(skip_serializing_if = "is_false")] - loaded_child_objects_fixed: bool, - // If true, treat missing types in the upgraded modules when creating an upgraded package as a - // compatibility error. - #[serde(skip_serializing_if = "is_false")] - missing_type_is_compatibility_error: bool, - // If true, then the scoring decision mechanism will not get disabled when we do have more than - // f low scoring authorities, but it will simply flag as low scoring only up to f authorities. - #[serde(skip_serializing_if = "is_false")] - scoring_decision_with_validity_cutoff: bool, - - // DEPRECATED: this was an ephemeral feature flag only used by consensus handler, which has now - // been deployed everywhere. - #[serde(skip_serializing_if = "is_false")] - consensus_order_end_of_epoch_last: bool, - - // Disallow adding abilities to types during package upgrades. - #[serde(skip_serializing_if = "is_false")] - disallow_adding_abilities_on_upgrade: bool, - // Disables unnecessary invariant check in the Move VM when swapping the value out of a local - #[serde(skip_serializing_if = "is_false")] - disable_invariant_violation_check_in_swap_loc: bool, - // advance to highest supported protocol version at epoch change, instead of the next - // consecutive protocol version. - #[serde(skip_serializing_if = "is_false")] - advance_to_highest_supported_protocol_version: bool, - // If true, disallow entry modifiers on entry functions - #[serde(skip_serializing_if = "is_false")] - ban_entry_init: bool, - // If true, hash module bytes individually when calculating package digests for upgrades - #[serde(skip_serializing_if = "is_false")] - package_digest_hash_module: bool, - // If true, disallow changing struct type parameters during package upgrades - #[serde(skip_serializing_if = "is_false")] - disallow_change_struct_type_params_on_upgrade: bool, - // If true, checks no extra bytes in a compiled module - #[serde(skip_serializing_if = "is_false")] - no_extraneous_module_bytes: bool, - // If true, then use the versioned metadata format in narwhal entities. - #[serde(skip_serializing_if = "is_false")] - narwhal_versioned_metadata: bool, - - // Enable zklogin auth - #[serde(skip_serializing_if = "is_false")] - zklogin_auth: bool, - // How we order transactions coming out of consensus before sending to execution. - #[serde(skip_serializing_if = "ConsensusTransactionOrdering::is_none")] - consensus_transaction_ordering: ConsensusTransactionOrdering, - - // Previously, the unwrapped_then_deleted field in TransactionEffects makes a distinction - // between whether an object has existed in the store previously (i.e. whether there is a - // tombstone). Such dependency makes effects generation inefficient, and requires us to - // include wrapped tombstone in state root hash. - // To prepare for effects V2, with this flag set to true, we simplify the definition of - // unwrapped_then_deleted to always include unwrapped then deleted objects, - // regardless of their previous state in the store. - #[serde(skip_serializing_if = "is_false")] - simplified_unwrap_then_delete: bool, - // Enable upgraded multisig support - #[serde(skip_serializing_if = "is_false")] - upgraded_multisig_supported: bool, - // If true minimum txn charge is a multiplier of the gas price - #[serde(skip_serializing_if = "is_false")] - txn_base_cost_as_multiplier: bool, - - // If true, the ability to delete shared objects is in effect - #[serde(skip_serializing_if = "is_false")] - shared_object_deletion: bool, - - // If true, then the new algorithm for the leader election schedule will be used - #[serde(skip_serializing_if = "is_false")] - narwhal_new_leader_election_schedule: bool, - - // A list of supported OIDC providers that can be used for zklogin. - #[serde(skip_serializing_if = "is_empty")] - zklogin_supported_providers: BTreeSet, - - // If true, use the new child object format - #[serde(skip_serializing_if = "is_false")] - loaded_child_object_format: bool, - - #[serde(skip_serializing_if = "is_false")] - enable_jwk_consensus_updates: bool, - - #[serde(skip_serializing_if = "is_false")] - end_of_epoch_transaction_supported: bool, - - // Perform simple conservation checks keeping into account out of gas scenarios - // while charging for storage. - #[serde(skip_serializing_if = "is_false")] - simple_conservation_checks: bool, - - // If true, use the new child object format type logging - #[serde(skip_serializing_if = "is_false")] - loaded_child_object_format_type: bool, - - // Enable receiving sent objects - #[serde(skip_serializing_if = "is_false")] - receive_objects: bool, - - // Enable random beacon protocol - #[serde(skip_serializing_if = "is_false")] - random_beacon: bool, - - #[serde(skip_serializing_if = "is_false")] - enable_effects_v2: bool, - - // If true, then use CertificateV2 in narwhal. - #[serde(skip_serializing_if = "is_false")] - narwhal_certificate_v2: bool, - - // If true, allow verify with legacy zklogin address - #[serde(skip_serializing_if = "is_false")] - verify_legacy_zklogin_address: bool, - - // Enable throughput aware consensus submission - #[serde(skip_serializing_if = "is_false")] - throughput_aware_consensus_submission: bool, - - // If true, recompute has_public_transfer from the type instead of what is stored in the object - #[serde(skip_serializing_if = "is_false")] - recompute_has_public_transfer_in_execution: bool, - - // If true, multisig containing zkLogin sig is accepted. - #[serde(skip_serializing_if = "is_false")] - accept_zklogin_in_multisig: bool, - - // If true, consensus prologue transaction also includes the consensus output digest. - // It can be used to detect consensus output folk. - #[serde(skip_serializing_if = "is_false")] - include_consensus_digest_in_prologue: bool, - - // If true, use the hardened OTW check - #[serde(skip_serializing_if = "is_false")] - hardened_otw_check: bool, - - // If true allow calling receiving_object_id function - #[serde(skip_serializing_if = "is_false")] - allow_receiving_object_id: bool, - - // Enable the poseidon hash function - #[serde(skip_serializing_if = "is_false")] - enable_poseidon: bool, - - // If true, enable the coin deny list. - #[serde(skip_serializing_if = "is_false")] - enable_coin_deny_list: bool, - - // Enable native functions for group operations. - #[serde(skip_serializing_if = "is_false")] - enable_group_ops_native_functions: bool, - - // Enable native function for msm. - #[serde(skip_serializing_if = "is_false")] - enable_group_ops_native_function_msm: bool, - - // Reject functions with mutable Random. - #[serde(skip_serializing_if = "is_false")] - reject_mutable_random_on_entry_functions: bool, -} - -fn is_false(b: &bool) -> bool { - !b -} - -fn is_empty(b: &BTreeSet) -> bool { - b.is_empty() -} - -/// Ordering mechanism for transactions in one Narwhal consensus output. -#[derive(Default, Copy, Clone, PartialEq, Eq, Serialize, Debug)] -pub enum ConsensusTransactionOrdering { - /// No ordering. Transactions are processed in the order they appear in the - /// consensus output. - #[default] - None, - /// Order transactions by gas price, highest first. - ByGasPrice, -} - -impl ConsensusTransactionOrdering { - pub fn is_none(&self) -> bool { - matches!(self, ConsensusTransactionOrdering::None) - } -} - -/// Constants that change the behavior of the protocol. -/// -/// The value of each constant here must be fixed for a given protocol version. -/// To change the value of a constant, advance the protocol version, and add -/// support for it in `get_for_version` under the new version number. -/// (below). -/// -/// To add a new field to this struct, use the following procedure: -/// - Advance the protocol version. -/// - Add the field as a private `Option` to the struct. -/// - Initialize the field to `None` in prior protocol versions. -/// - Initialize the field to `Some(val)` for your new protocol version. -/// - Add a public getter that simply unwraps the field. -/// - Two public getters of the form `field(&self) -> field_type` and -/// `field_as_option(&self) -> Option` will be automatically -/// generated for you. -/// Example for a field: `new_constant: Option` -/// ```rust,ignore -/// pub fn new_constant(&self) -> u64 { -/// self.new_constant.expect(Self::CONSTANT_ERR_MSG) -/// } -/// pub fn new_constant_as_option(&self) -> Option { -/// self.new_constant.expect(Self::CONSTANT_ERR_MSG) -/// } -/// ``` -/// With `pub fn new_constant(&self) -> u64`, if the constant is accessed in a -/// protocol version in which it is not defined, the validator will crash. -/// (Crashing is necessary because this type of error would almost always result -/// in forking if not prevented here). If you don't want the validator to crash, -/// you can use the `pub fn new_constant_as_option(&self) -> Option` -/// getter, which will return `None` if the field is not defined at that -/// version. -/// - If you want a customized getter, you can add a method in the impl. -#[skip_serializing_none] -#[derive(Clone, Serialize, Debug, ProtocolConfigAccessors)] -pub struct ProtocolConfig { - pub version: ProtocolVersion, - - feature_flags: FeatureFlags, - - // ==== Transaction input limits ==== - /// Maximum serialized size of a transaction (in bytes). - max_tx_size_bytes: Option, - - /// Maximum number of input objects to a transaction. Enforced by the - /// transaction input checker - max_input_objects: Option, - - /// Max size of objects a transaction can write to disk after completion. - /// Enforce by the Sui adapter. This is the sum of the serialized size - /// of all objects written to disk. The max size of individual objects - /// on the other hand is `max_move_object_size`. - max_size_written_objects: Option, - /// Max size of objects a system transaction can write to disk after - /// completion. Enforce by the Sui adapter. Similar to - /// `max_size_written_objects` but for system transactions. - max_size_written_objects_system_tx: Option, - - /// Maximum size of serialized transaction effects. - max_serialized_tx_effects_size_bytes: Option, - - /// Maximum size of serialized transaction effects for system transactions. - max_serialized_tx_effects_size_bytes_system_tx: Option, - - /// Maximum number of gas payment objects for a transaction. - max_gas_payment_objects: Option, - - /// Maximum number of modules in a Publish transaction. - max_modules_in_publish: Option, - - /// Maximum number of transitive dependencies in a package when publishing. - max_package_dependencies: Option, - - /// Maximum number of arguments in a move call or a - /// ProgrammableTransaction's TransferObjects command. - max_arguments: Option, - - /// Maximum number of total type arguments, computed recursively. - max_type_arguments: Option, - - /// Maximum depth of an individual type argument. - max_type_argument_depth: Option, - - /// Maximum size of a Pure CallArg. - max_pure_argument_size: Option, - - /// Maximum number of Commands in a ProgrammableTransaction. - max_programmable_tx_commands: Option, - - // ==== Move VM, Move bytecode verifier, and execution limits === - /// Maximum Move bytecode version the VM understands. All older versions are - /// accepted. - move_binary_format_version: Option, - /// Configuration controlling binary tables size. - binary_module_handles: Option, - binary_struct_handles: Option, - binary_function_handles: Option, - binary_function_instantiations: Option, - binary_signatures: Option, - binary_constant_pool: Option, - binary_identifiers: Option, - binary_address_identifiers: Option, - binary_struct_defs: Option, - binary_struct_def_instantiations: Option, - binary_function_defs: Option, - binary_field_handles: Option, - binary_field_instantiations: Option, - binary_friend_decls: Option, - - /// Maximum size of the `contents` part of an object, in bytes. Enforced by - /// the Sui adapter when effects are produced. - max_move_object_size: Option, - - // TODO: Option 500 KB exceeds the max - // computation gas cost - /// Maximum size of a Move package object, in bytes. Enforced by the Sui - /// adapter at the end of a publish transaction. - max_move_package_size: Option, - - /// Max number of publish or upgrade commands allowed in a programmable - /// transaction block. - max_publish_or_upgrade_per_ptb: Option, - - /// Maximum number of gas units that a single MoveCall transaction can use. - /// Enforced by the Sui adapter. - max_tx_gas: Option, - - /// Maximum amount of the proposed gas price in MIST (defined in the - /// transaction). - max_gas_price: Option, - - /// The max computation bucket for gas. This is the max that can be charged - /// for computation. - max_gas_computation_bucket: Option, - - // Define the value used to round up computation gas charges - gas_rounding_step: Option, - - /// Maximum number of nested loops. Enforced by the Move bytecode verifier. - max_loop_depth: Option, - - /// Maximum number of type arguments that can be bound to generic type - /// parameters. Enforced by the Move bytecode verifier. - max_generic_instantiation_length: Option, - - /// Maximum number of parameters that a Move function can have. Enforced by - /// the Move bytecode verifier. - max_function_parameters: Option, - - /// Maximum number of basic blocks that a Move function can have. Enforced - /// by the Move bytecode verifier. - max_basic_blocks: Option, - - /// Maximum stack size value. Enforced by the Move bytecode verifier. - max_value_stack_size: Option, - - /// Maximum number of "type nodes", a metric for how big a SignatureToken - /// will be when expanded into a fully qualified type. Enforced by the Move - /// bytecode verifier. - max_type_nodes: Option, - - /// Maximum number of push instructions in one function. Enforced by the - /// Move bytecode verifier. - max_push_size: Option, - - /// Maximum number of struct definitions in a module. Enforced by the Move - /// bytecode verifier. - max_struct_definitions: Option, - - /// Maximum number of function definitions in a module. Enforced by the Move - /// bytecode verifier. - max_function_definitions: Option, - - /// Maximum number of fields allowed in a struct definition. Enforced by the - /// Move bytecode verifier. - max_fields_in_struct: Option, - - /// Maximum dependency depth. Enforced by the Move linker when loading - /// dependent modules. - max_dependency_depth: Option, - - /// Maximum number of Move events that a single transaction can emit. - /// Enforced by the VM during execution. - max_num_event_emit: Option, - - /// Maximum number of new IDs that a single transaction can create. Enforced - /// by the VM during execution. - max_num_new_move_object_ids: Option, - - /// Maximum number of new IDs that a single system transaction can create. - /// Enforced by the VM during execution. - max_num_new_move_object_ids_system_tx: Option, - - /// Maximum number of IDs that a single transaction can delete. Enforced by - /// the VM during execution. - max_num_deleted_move_object_ids: Option, - - /// Maximum number of IDs that a single system transaction can delete. - /// Enforced by the VM during execution. - max_num_deleted_move_object_ids_system_tx: Option, - - /// Maximum number of IDs that a single transaction can transfer. Enforced - /// by the VM during execution. - max_num_transferred_move_object_ids: Option, - - /// Maximum number of IDs that a single system transaction can transfer. - /// Enforced by the VM during execution. - max_num_transferred_move_object_ids_system_tx: Option, - - /// Maximum size of a Move user event. Enforced by the VM during execution. - max_event_emit_size: Option, - - /// Maximum size of a Move user event. Enforced by the VM during execution. - max_event_emit_size_total: Option, - - /// Maximum length of a vector in Move. Enforced by the VM during execution, - /// and for constants, by the verifier. - max_move_vector_len: Option, - - /// Maximum length of an `Identifier` in Move. Enforced by the bytecode - /// verifier at signing. - max_move_identifier_len: Option, - - /// Maximum depth of a Move value within the VM. - max_move_value_depth: Option, - - /// Maximum number of back edges in Move function. Enforced by the bytecode - /// verifier at signing. - max_back_edges_per_function: Option, - - /// Maximum number of back edges in Move module. Enforced by the bytecode - /// verifier at signing. - max_back_edges_per_module: Option, - - /// Maximum number of meter `ticks` spent verifying a Move function. - /// Enforced by the bytecode verifier at signing. - max_verifier_meter_ticks_per_function: Option, - - /// Maximum number of meter `ticks` spent verifying a Move function. - /// Enforced by the bytecode verifier at signing. - max_meter_ticks_per_module: Option, - - // === Object runtime internal operation limits ==== - // These affect dynamic fields - /// Maximum number of cached objects in the object runtime ObjectStore. - /// Enforced by object runtime during execution - object_runtime_max_num_cached_objects: Option, - - /// Maximum number of cached objects in the object runtime ObjectStore in - /// system transaction. Enforced by object runtime during execution - object_runtime_max_num_cached_objects_system_tx: Option, - - /// Maximum number of stored objects accessed by object runtime ObjectStore. - /// Enforced by object runtime during execution - object_runtime_max_num_store_entries: Option, - - /// Maximum number of stored objects accessed by object runtime ObjectStore - /// in system transaction. Enforced by object runtime during execution - object_runtime_max_num_store_entries_system_tx: Option, - - // === Execution gas costs ==== - /// Base cost for any Sui transaction - base_tx_cost_fixed: Option, - - /// Additional cost for a transaction that publishes a package - /// i.e., the base cost of such a transaction is base_tx_cost_fixed + - /// package_publish_cost_fixed - package_publish_cost_fixed: Option, - - /// Cost per byte of a Move call transaction - /// i.e., the cost of such a transaction is base_cost + - /// (base_tx_cost_per_byte * size) - base_tx_cost_per_byte: Option, - - /// Cost per byte for a transaction that publishes a package - package_publish_cost_per_byte: Option, - - // Per-byte cost of reading an object during transaction execution - obj_access_cost_read_per_byte: Option, - - // Per-byte cost of writing an object during transaction execution - obj_access_cost_mutate_per_byte: Option, - - // Per-byte cost of deleting an object during transaction execution - obj_access_cost_delete_per_byte: Option, - - /// Per-byte cost charged for each input object to a transaction. - /// Meant to approximate the cost of checking locks for each object - // TODO: Option tx digest map - obj_access_cost_verify_per_byte: Option, - - /// === Gas version. gas model === - - /// Gas model version, what code we are using to charge gas - gas_model_version: Option, - - /// === Storage gas costs === - - /// Per-byte cost of storing an object in the Sui global object store. Some - /// of this cost may be refundable if the object is later freed - obj_data_cost_refundable: Option, - - // Per-byte cost of storing an object in the Sui transaction log (e.g., in - // CertifiedTransactionEffects) This depends on the size of various fields including the - // effects TODO: Option, - - /// === Tokenomics === - - // TODO: Option, - - /// 5% of the storage fund's share of rewards are reinvested into the - /// storage fund. In basis point. - storage_fund_reinvest_rate: Option, - - /// The share of rewards that will be slashed and redistributed is 50%. - /// In basis point. - reward_slashing_rate: Option, - - /// Unit gas price, Mist per internal gas unit. - storage_gas_price: Option, - - /// === Core Protocol === - - /// Max number of transactions per checkpoint. - /// Note that this is a protocol constant and not a config as validators - /// must have this set to the same value, otherwise they *will* fork. - max_transactions_per_checkpoint: Option, - - /// Max size of a checkpoint in bytes. - /// Note that this is a protocol constant and not a config as validators - /// must have this set to the same value, otherwise they *will* fork. - max_checkpoint_size_bytes: Option, - - /// A protocol upgrade always requires 2f+1 stake to agree. We support a - /// buffer of additional stake (as a fraction of f, expressed in basis - /// points) that is required before an upgrade can happen automatically. - /// 10000bps would indicate that complete unanimity is required (all - /// 3f+1 must vote), while 0bps would indicate that 2f+1 is sufficient. - buffer_stake_for_protocol_upgrade_bps: Option, - - // === Native Function Costs === - - // `address` module - // Cost params for the Move native function `address::from_bytes(bytes: vector)` - address_from_bytes_cost_base: Option, - // Cost params for the Move native function `address::to_u256(address): u256` - address_to_u256_cost_base: Option, - // Cost params for the Move native function `address::from_u256(u256): address` - address_from_u256_cost_base: Option, - - // `dynamic_field` module - // Cost params for the Move native function `hash_type_and_key(parent: - // address, k: K): address` - dynamic_field_hash_type_and_key_cost_base: Option, - dynamic_field_hash_type_and_key_type_cost_per_byte: Option, - dynamic_field_hash_type_and_key_value_cost_per_byte: Option, - dynamic_field_hash_type_and_key_type_tag_cost_per_byte: Option, - // Cost params for the Move native function `add_child_object(parent: address, - // child: Child)` - dynamic_field_add_child_object_cost_base: Option, - dynamic_field_add_child_object_type_cost_per_byte: Option, - dynamic_field_add_child_object_value_cost_per_byte: Option, - dynamic_field_add_child_object_struct_tag_cost_per_byte: Option, - // Cost params for the Move native function `borrow_child_object_mut(parent: &mut - // UID, id: address): &mut Child` - dynamic_field_borrow_child_object_cost_base: Option, - dynamic_field_borrow_child_object_child_ref_cost_per_byte: Option, - dynamic_field_borrow_child_object_type_cost_per_byte: Option, - // Cost params for the Move native function `remove_child_object(parent: address, - // id: address): Child` - dynamic_field_remove_child_object_cost_base: Option, - dynamic_field_remove_child_object_child_cost_per_byte: Option, - dynamic_field_remove_child_object_type_cost_per_byte: Option, - // Cost params for the Move native function `has_child_object(parent: address, id: address): - // bool` - dynamic_field_has_child_object_cost_base: Option, - // Cost params for the Move native function `has_child_object_with_ty(parent: - // address, id: address): bool` - dynamic_field_has_child_object_with_ty_cost_base: Option, - dynamic_field_has_child_object_with_ty_type_cost_per_byte: Option, - dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: Option, - - // `event` module - // Cost params for the Move native function `event::emit(event: T)` - event_emit_cost_base: Option, - event_emit_value_size_derivation_cost_per_byte: Option, - event_emit_tag_size_derivation_cost_per_byte: Option, - event_emit_output_cost_per_byte: Option, - - // `object` module - // Cost params for the Move native function `borrow_uid(obj: &T): &UID` - object_borrow_uid_cost_base: Option, - // Cost params for the Move native function `delete_impl(id: address)` - object_delete_impl_cost_base: Option, - // Cost params for the Move native function `record_new_uid(id: address)` - object_record_new_uid_cost_base: Option, - - // Transfer - // Cost params for the Move native function `transfer_impl(obj: T, recipient: address)` - transfer_transfer_internal_cost_base: Option, - // Cost params for the Move native function `freeze_object(obj: T)` - transfer_freeze_object_cost_base: Option, - // Cost params for the Move native function `share_object(obj: T)` - transfer_share_object_cost_base: Option, - // Cost params for the Move native function - // `receive_object(p: &mut UID, recv: ReceivingT)` - transfer_receive_object_cost_base: Option, - - // TxContext - // Cost params for the Move native function `transfer_impl(obj: T, recipient: address)` - tx_context_derive_id_cost_base: Option, - - // Types - // Cost params for the Move native function `is_one_time_witness(_: &T): bool` - types_is_one_time_witness_cost_base: Option, - types_is_one_time_witness_type_tag_cost_per_byte: Option, - types_is_one_time_witness_type_cost_per_byte: Option, - - // Validator - // Cost params for the Move native function `validate_metadata_bcs(metadata: vector)` - validator_validate_metadata_cost_base: Option, - validator_validate_metadata_data_cost_per_byte: Option, - - // Crypto natives - crypto_invalid_arguments_cost: Option, - // bls12381::bls12381_min_sig_verify - bls12381_bls12381_min_sig_verify_cost_base: Option, - bls12381_bls12381_min_sig_verify_msg_cost_per_byte: Option, - bls12381_bls12381_min_sig_verify_msg_cost_per_block: Option, - - // bls12381::bls12381_min_pk_verify - bls12381_bls12381_min_pk_verify_cost_base: Option, - bls12381_bls12381_min_pk_verify_msg_cost_per_byte: Option, - bls12381_bls12381_min_pk_verify_msg_cost_per_block: Option, - - // ecdsa_k1::ecrecover - ecdsa_k1_ecrecover_keccak256_cost_base: Option, - ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: Option, - ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: Option, - ecdsa_k1_ecrecover_sha256_cost_base: Option, - ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: Option, - ecdsa_k1_ecrecover_sha256_msg_cost_per_block: Option, - - // ecdsa_k1::decompress_pubkey - ecdsa_k1_decompress_pubkey_cost_base: Option, - - // ecdsa_k1::secp256k1_verify - ecdsa_k1_secp256k1_verify_keccak256_cost_base: Option, - ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: Option, - ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: Option, - ecdsa_k1_secp256k1_verify_sha256_cost_base: Option, - ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: Option, - ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: Option, - - // ecdsa_r1::ecrecover - ecdsa_r1_ecrecover_keccak256_cost_base: Option, - ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: Option, - ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: Option, - ecdsa_r1_ecrecover_sha256_cost_base: Option, - ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: Option, - ecdsa_r1_ecrecover_sha256_msg_cost_per_block: Option, - - // ecdsa_r1::secp256k1_verify - ecdsa_r1_secp256r1_verify_keccak256_cost_base: Option, - ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: Option, - ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: Option, - ecdsa_r1_secp256r1_verify_sha256_cost_base: Option, - ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: Option, - ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: Option, - - // ecvrf::verify - ecvrf_ecvrf_verify_cost_base: Option, - ecvrf_ecvrf_verify_alpha_string_cost_per_byte: Option, - ecvrf_ecvrf_verify_alpha_string_cost_per_block: Option, - - // ed25519 - ed25519_ed25519_verify_cost_base: Option, - ed25519_ed25519_verify_msg_cost_per_byte: Option, - ed25519_ed25519_verify_msg_cost_per_block: Option, - - // groth16::prepare_verifying_key - groth16_prepare_verifying_key_bls12381_cost_base: Option, - groth16_prepare_verifying_key_bn254_cost_base: Option, - - // groth16::verify_groth16_proof_internal - groth16_verify_groth16_proof_internal_bls12381_cost_base: Option, - groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: Option, - groth16_verify_groth16_proof_internal_bn254_cost_base: Option, - groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: Option, - groth16_verify_groth16_proof_internal_public_input_cost_per_byte: Option, - - // hash::blake2b256 - hash_blake2b256_cost_base: Option, - hash_blake2b256_data_cost_per_byte: Option, - hash_blake2b256_data_cost_per_block: Option, - - // hash::keccak256 - hash_keccak256_cost_base: Option, - hash_keccak256_data_cost_per_byte: Option, - hash_keccak256_data_cost_per_block: Option, - - // poseidon::poseidon_bn254 - poseidon_bn254_cost_base: Option, - poseidon_bn254_cost_per_block: Option, - - // group_ops - group_ops_bls12381_decode_scalar_cost: Option, - group_ops_bls12381_decode_g1_cost: Option, - group_ops_bls12381_decode_g2_cost: Option, - group_ops_bls12381_decode_gt_cost: Option, - group_ops_bls12381_scalar_add_cost: Option, - group_ops_bls12381_g1_add_cost: Option, - group_ops_bls12381_g2_add_cost: Option, - group_ops_bls12381_gt_add_cost: Option, - group_ops_bls12381_scalar_sub_cost: Option, - group_ops_bls12381_g1_sub_cost: Option, - group_ops_bls12381_g2_sub_cost: Option, - group_ops_bls12381_gt_sub_cost: Option, - group_ops_bls12381_scalar_mul_cost: Option, - group_ops_bls12381_g1_mul_cost: Option, - group_ops_bls12381_g2_mul_cost: Option, - group_ops_bls12381_gt_mul_cost: Option, - group_ops_bls12381_scalar_div_cost: Option, - group_ops_bls12381_g1_div_cost: Option, - group_ops_bls12381_g2_div_cost: Option, - group_ops_bls12381_gt_div_cost: Option, - group_ops_bls12381_g1_hash_to_base_cost: Option, - group_ops_bls12381_g2_hash_to_base_cost: Option, - group_ops_bls12381_g1_hash_to_cost_per_byte: Option, - group_ops_bls12381_g2_hash_to_cost_per_byte: Option, - group_ops_bls12381_g1_msm_base_cost: Option, - group_ops_bls12381_g2_msm_base_cost: Option, - group_ops_bls12381_g1_msm_base_cost_per_input: Option, - group_ops_bls12381_g2_msm_base_cost_per_input: Option, - group_ops_bls12381_msm_max_len: Option, - group_ops_bls12381_pairing_cost: Option, - - // hmac::hmac_sha3_256 - hmac_hmac_sha3_256_cost_base: Option, - hmac_hmac_sha3_256_input_cost_per_byte: Option, - hmac_hmac_sha3_256_input_cost_per_block: Option, - - // zklogin::check_zklogin_id - check_zklogin_id_cost_base: Option, - // zklogin::check_zklogin_issuer - check_zklogin_issuer_cost_base: Option, - - // Const params for consensus scoring decision - // The scaling factor property for the MED outlier detection - scoring_decision_mad_divisor: Option, - // The cutoff value for the MED outlier detection - scoring_decision_cutoff_value: Option, - - /// === Execution Version === - execution_version: Option, - - // Dictates the threshold (percentage of stake) that is used to calculate the "bad" nodes to be - // swapped when creating the consensus schedule. The values should be of the range [0 - 33]. - // Anything above 33 (f) will not be allowed. - consensus_bad_nodes_stake_threshold: Option, - - max_jwk_votes_per_validator_per_epoch: Option, - // The maximum age of a JWK in epochs before it is removed from the AuthenticatorState object. - // Applied at the end of an epoch as a delta from the new epoch value, so setting this to 1 - // will cause the new epoch to start with JWKs from the previous epoch still valid. - max_age_of_jwk_in_epochs: Option, - - /// === random beacon === - - /// Maximum allowed precision loss when reducing voting weights for the - /// random beacon protocol. - random_beacon_reduction_allowed_delta: Option, - - /// Minimum number of shares below which voting weights will not be reduced - /// for the random beacon protocol. - random_beacon_reduction_lower_bound: Option, - - /// Consensus Round after which DKG should be aborted and randomness - /// disabled for the epoch, if it hasn't already completed. - random_beacon_dkg_timeout_round: Option, - - /// The maximum serialised transaction size (in bytes) accepted by - /// consensus. That should be bigger than the `max_tx_size_bytes` with - /// some additional headroom. - consensus_max_transaction_size_bytes: Option, - /// The maximum size of transactions included in a consensus proposed block - consensus_max_transactions_in_block_bytes: Option, -} - -// feature flags -impl ProtocolConfig { - // Add checks for feature flag support here, e.g.: - // pub fn check_new_protocol_feature_supported(&self) -> Result<(), Error> { - // if self.feature_flags.new_protocol_feature_supported { - // Ok(()) - // } else { - // Err(Error(format!( - // "new_protocol_feature is not supported at {:?}", - // self.version - // ))) - // } - // } - - pub fn check_package_upgrades_supported(&self) -> Result<(), Error> { - if self.feature_flags.package_upgrades { - Ok(()) - } else { - Err(Error(format!( - "package upgrades are not supported at {:?}", - self.version - ))) - } - } - - pub fn allow_receiving_object_id(&self) -> bool { - self.feature_flags.allow_receiving_object_id - } - - pub fn receiving_objects_supported(&self) -> bool { - self.feature_flags.receive_objects - } - - pub fn package_upgrades_supported(&self) -> bool { - self.feature_flags.package_upgrades - } - - pub fn check_commit_root_state_digest_supported(&self) -> bool { - self.feature_flags.commit_root_state_digest - } - - pub fn get_advance_epoch_start_time_in_safe_mode(&self) -> bool { - self.feature_flags.advance_epoch_start_time_in_safe_mode - } - - pub fn loaded_child_objects_fixed(&self) -> bool { - self.feature_flags.loaded_child_objects_fixed - } - - pub fn missing_type_is_compatibility_error(&self) -> bool { - self.feature_flags.missing_type_is_compatibility_error - } - - pub fn scoring_decision_with_validity_cutoff(&self) -> bool { - self.feature_flags.scoring_decision_with_validity_cutoff - } - - pub fn narwhal_versioned_metadata(&self) -> bool { - self.feature_flags.narwhal_versioned_metadata - } - - pub fn consensus_order_end_of_epoch_last(&self) -> bool { - self.feature_flags.consensus_order_end_of_epoch_last - } - - pub fn disallow_adding_abilities_on_upgrade(&self) -> bool { - self.feature_flags.disallow_adding_abilities_on_upgrade - } - - pub fn disable_invariant_violation_check_in_swap_loc(&self) -> bool { - self.feature_flags - .disable_invariant_violation_check_in_swap_loc - } - - pub fn advance_to_highest_supported_protocol_version(&self) -> bool { - self.feature_flags - .advance_to_highest_supported_protocol_version - } - - pub fn ban_entry_init(&self) -> bool { - self.feature_flags.ban_entry_init - } - - pub fn package_digest_hash_module(&self) -> bool { - self.feature_flags.package_digest_hash_module - } - - pub fn disallow_change_struct_type_params_on_upgrade(&self) -> bool { - self.feature_flags - .disallow_change_struct_type_params_on_upgrade - } - - pub fn no_extraneous_module_bytes(&self) -> bool { - self.feature_flags.no_extraneous_module_bytes - } - - pub fn zklogin_auth(&self) -> bool { - self.feature_flags.zklogin_auth - } - - pub fn zklogin_supported_providers(&self) -> &BTreeSet { - &self.feature_flags.zklogin_supported_providers - } - - pub fn consensus_transaction_ordering(&self) -> ConsensusTransactionOrdering { - self.feature_flags.consensus_transaction_ordering - } - - pub fn simplified_unwrap_then_delete(&self) -> bool { - self.feature_flags.simplified_unwrap_then_delete - } - - pub fn supports_upgraded_multisig(&self) -> bool { - self.feature_flags.upgraded_multisig_supported - } - - pub fn txn_base_cost_as_multiplier(&self) -> bool { - self.feature_flags.txn_base_cost_as_multiplier - } - - pub fn shared_object_deletion(&self) -> bool { - self.feature_flags.shared_object_deletion - } - - pub fn narwhal_new_leader_election_schedule(&self) -> bool { - self.feature_flags.narwhal_new_leader_election_schedule - } - - pub fn loaded_child_object_format(&self) -> bool { - self.feature_flags.loaded_child_object_format - } - - pub fn enable_jwk_consensus_updates(&self) -> bool { - let ret = self.feature_flags.enable_jwk_consensus_updates; - if ret { - // jwk updates required end-of-epoch transactions - assert!(self.feature_flags.end_of_epoch_transaction_supported); - } - ret - } - - pub fn simple_conservation_checks(&self) -> bool { - self.feature_flags.simple_conservation_checks - } - - pub fn loaded_child_object_format_type(&self) -> bool { - self.feature_flags.loaded_child_object_format_type - } - - pub fn end_of_epoch_transaction_supported(&self) -> bool { - let ret = self.feature_flags.end_of_epoch_transaction_supported; - if !ret { - // jwk updates required end-of-epoch transactions - assert!(!self.feature_flags.enable_jwk_consensus_updates); - } - ret - } - - pub fn recompute_has_public_transfer_in_execution(&self) -> bool { - self.feature_flags - .recompute_has_public_transfer_in_execution - } - - // this function only exists for readability in the genesis code. - pub fn create_authenticator_state_in_genesis(&self) -> bool { - self.enable_jwk_consensus_updates() - } - - pub fn random_beacon(&self) -> bool { - self.feature_flags.random_beacon - } - - pub fn enable_effects_v2(&self) -> bool { - self.feature_flags.enable_effects_v2 - } - - pub fn narwhal_certificate_v2(&self) -> bool { - self.feature_flags.narwhal_certificate_v2 - } - - pub fn verify_legacy_zklogin_address(&self) -> bool { - self.feature_flags.verify_legacy_zklogin_address - } - - pub fn accept_zklogin_in_multisig(&self) -> bool { - self.feature_flags.accept_zklogin_in_multisig - } - - pub fn throughput_aware_consensus_submission(&self) -> bool { - self.feature_flags.throughput_aware_consensus_submission - } - - pub fn include_consensus_digest_in_prologue(&self) -> bool { - self.feature_flags.include_consensus_digest_in_prologue - } - - pub fn hardened_otw_check(&self) -> bool { - self.feature_flags.hardened_otw_check - } - - pub fn enable_poseidon(&self) -> bool { - self.feature_flags.enable_poseidon - } - - pub fn enable_coin_deny_list(&self) -> bool { - self.feature_flags.enable_coin_deny_list - } - - pub fn enable_group_ops_native_functions(&self) -> bool { - self.feature_flags.enable_group_ops_native_functions - } - - pub fn enable_group_ops_native_function_msm(&self) -> bool { - self.feature_flags.enable_group_ops_native_function_msm - } - - pub fn reject_mutable_random_on_entry_functions(&self) -> bool { - self.feature_flags.reject_mutable_random_on_entry_functions - } -} - -#[cfg(not(msim))] -static POISON_VERSION_METHODS: AtomicBool = AtomicBool::new(false); - -// Use a thread local in sim tests for test isolation. -#[cfg(msim)] -thread_local! { - static POISON_VERSION_METHODS: AtomicBool = AtomicBool::new(false); -} - -// Instantiations for each protocol version. -impl ProtocolConfig { - /// Get the value ProtocolConfig that are in effect during the given - /// protocol version. - pub fn get_for_version(version: ProtocolVersion, chain: Chain) -> Self { - // ProtocolVersion can be deserialized so we need to check it here as well. - assert!( - version >= ProtocolVersion::MIN, - "Network protocol version is {:?}, but the minimum supported version by the binary is {:?}. Please upgrade the binary.", - version, - ProtocolVersion::MIN.0, - ); - assert!( - version <= ProtocolVersion::MAX_ALLOWED, - "Network protocol version is {:?}, but the maximum supported version by the binary is {:?}. Please upgrade the binary.", - version, - ProtocolVersion::MAX_ALLOWED.0, - ); - - let mut ret = Self::get_for_version_impl(version, chain); - ret.version = version; - - CONFIG_OVERRIDE.with(|ovr| { - if let Some(override_fn) = &*ovr.borrow() { - warn!( - "overriding ProtocolConfig settings with custom settings (you should not see this log outside of tests)" - ); - override_fn(version, ret) - } else { - ret - } - }) - } - - /// Get the value ProtocolConfig that are in effect during the given - /// protocol version. Or none if the version is not supported. - pub fn get_for_version_if_supported(version: ProtocolVersion, chain: Chain) -> Option { - if version.0 >= ProtocolVersion::MIN.0 && version.0 <= ProtocolVersion::MAX_ALLOWED.0 { - let mut ret = Self::get_for_version_impl(version, chain); - ret.version = version; - Some(ret) - } else { - None - } - } - - #[cfg(not(msim))] - pub fn poison_get_for_min_version() { - POISON_VERSION_METHODS.store(true, Ordering::Relaxed); - } - - #[cfg(not(msim))] - fn load_poison_get_for_min_version() -> bool { - POISON_VERSION_METHODS.load(Ordering::Relaxed) - } - - #[cfg(msim)] - pub fn poison_get_for_min_version() { - POISON_VERSION_METHODS.with(|p| p.store(true, Ordering::Relaxed)); - } - - #[cfg(msim)] - fn load_poison_get_for_min_version() -> bool { - POISON_VERSION_METHODS.with(|p| p.load(Ordering::Relaxed)) - } - - /// Convenience to get the constants at the current minimum supported - /// version. Mainly used by client code that may not yet be - /// protocol-version aware. - pub fn get_for_min_version() -> Self { - if Self::load_poison_get_for_min_version() { - panic!("get_for_min_version called on validator"); - } - ProtocolConfig::get_for_version(ProtocolVersion::MIN, Chain::Unknown) - } - - /// CAREFUL! - You probably want to use `get_for_version` instead. - /// - /// Convenience to get the constants at the current maximum supported - /// version. Mainly used by genesis. Note well that this function uses - /// the max version supported locally by the node, which is not - /// necessarily the current version of the network. ALSO, this function - /// disregards chain specific config (by using Chain::Unknown), thereby - /// potentially returning a protocol config that is incorrect for some - /// feature flags. Definitely safe for testing and for protocol version - /// 11 and prior. - #[allow(non_snake_case)] - pub fn get_for_max_version_UNSAFE() -> Self { - if Self::load_poison_get_for_min_version() { - panic!("get_for_max_version_UNSAFE called on validator"); - } - ProtocolConfig::get_for_version(ProtocolVersion::MAX, Chain::Unknown) - } - - fn get_for_version_impl(version: ProtocolVersion, chain: Chain) -> Self { - #[cfg(msim)] - { - // populate the fake simulator version # with a different base tx cost. - if version == ProtocolVersion::MAX_ALLOWED { - let mut config = Self::get_for_version_impl(version - 1, Chain::Unknown); - config.base_tx_cost_fixed = Some(config.base_tx_cost_fixed() + 1000); - return config; - } - } - - // IMPORTANT: Never modify the value of any constant for a pre-existing protocol - // version. To change the values here you must create a new protocol - // version with the new values! - let mut cfg = Self { - // will be overwritten before being returned - version, - - // All flags are disabled in V1 - feature_flags: Default::default(), - - max_tx_size_bytes: Some(128 * 1024), - // We need this number to be at least 100x less than - // `max_serialized_tx_effects_size_bytes`otherwise effects can be huge - max_input_objects: Some(2048), - max_serialized_tx_effects_size_bytes: Some(512 * 1024), - max_serialized_tx_effects_size_bytes_system_tx: Some(512 * 1024 * 16), - max_gas_payment_objects: Some(256), - max_modules_in_publish: Some(128), - max_package_dependencies: None, - max_arguments: Some(512), - max_type_arguments: Some(16), - max_type_argument_depth: Some(16), - max_pure_argument_size: Some(16 * 1024), - max_programmable_tx_commands: Some(1024), - move_binary_format_version: Some(6), - binary_module_handles: None, - binary_struct_handles: None, - binary_function_handles: None, - binary_function_instantiations: None, - binary_signatures: None, - binary_constant_pool: None, - binary_identifiers: None, - binary_address_identifiers: None, - binary_struct_defs: None, - binary_struct_def_instantiations: None, - binary_function_defs: None, - binary_field_handles: None, - binary_field_instantiations: None, - binary_friend_decls: None, - max_move_object_size: Some(250 * 1024), - max_move_package_size: Some(100 * 1024), - max_publish_or_upgrade_per_ptb: None, - max_tx_gas: Some(10_000_000_000), - max_gas_price: Some(100_000), - max_gas_computation_bucket: Some(5_000_000), - max_loop_depth: Some(5), - max_generic_instantiation_length: Some(32), - max_function_parameters: Some(128), - max_basic_blocks: Some(1024), - max_value_stack_size: Some(1024), - max_type_nodes: Some(256), - max_push_size: Some(10000), - max_struct_definitions: Some(200), - max_function_definitions: Some(1000), - max_fields_in_struct: Some(32), - max_dependency_depth: Some(100), - max_num_event_emit: Some(256), - max_num_new_move_object_ids: Some(2048), - max_num_new_move_object_ids_system_tx: Some(2048 * 16), - max_num_deleted_move_object_ids: Some(2048), - max_num_deleted_move_object_ids_system_tx: Some(2048 * 16), - max_num_transferred_move_object_ids: Some(2048), - max_num_transferred_move_object_ids_system_tx: Some(2048 * 16), - max_event_emit_size: Some(250 * 1024), - max_move_vector_len: Some(256 * 1024), - - // TODO: Is this too low/high? - max_back_edges_per_function: Some(10_000), - - // TODO: Is this too low/high? - max_back_edges_per_module: Some(10_000), - - // TODO: Is this too low/high? - max_verifier_meter_ticks_per_function: Some(6_000_000), - - // TODO: Is this too low/high? - max_meter_ticks_per_module: Some(6_000_000), - - object_runtime_max_num_cached_objects: Some(1000), - object_runtime_max_num_cached_objects_system_tx: Some(1000 * 16), - object_runtime_max_num_store_entries: Some(1000), - object_runtime_max_num_store_entries_system_tx: Some(1000 * 16), - base_tx_cost_fixed: Some(110_000), - package_publish_cost_fixed: Some(1_000), - base_tx_cost_per_byte: Some(0), - package_publish_cost_per_byte: Some(80), - obj_access_cost_read_per_byte: Some(15), - obj_access_cost_mutate_per_byte: Some(40), - obj_access_cost_delete_per_byte: Some(40), - obj_access_cost_verify_per_byte: Some(200), - obj_data_cost_refundable: Some(100), - obj_metadata_cost_non_refundable: Some(50), - gas_model_version: Some(1), - storage_rebate_rate: Some(9900), - storage_fund_reinvest_rate: Some(500), - reward_slashing_rate: Some(5000), - storage_gas_price: Some(1), - max_transactions_per_checkpoint: Some(10_000), - max_checkpoint_size_bytes: Some(30 * 1024 * 1024), - - // For now, perform upgrades with a bare quorum of validators. - // MUSTFIX: This number should be increased to at least 2000 (20%) for mainnet. - buffer_stake_for_protocol_upgrade_bps: Some(0), - - // === Native Function Costs === - // `address` module - // Cost params for the Move native function `address::from_bytes(bytes: vector)` - address_from_bytes_cost_base: Some(52), - // Cost params for the Move native function `address::to_u256(address): u256` - address_to_u256_cost_base: Some(52), - // Cost params for the Move native function `address::from_u256(u256): address` - address_from_u256_cost_base: Some(52), - - // `dynamic_field` module - // Cost params for the Move native function `hash_type_and_key(parent: address, k: K): address` - dynamic_field_hash_type_and_key_cost_base: Some(100), - dynamic_field_hash_type_and_key_type_cost_per_byte: Some(2), - dynamic_field_hash_type_and_key_value_cost_per_byte: Some(2), - dynamic_field_hash_type_and_key_type_tag_cost_per_byte: Some(2), - // Cost params for the Move native function `add_child_object(parent: - // address, child: Child)` - dynamic_field_add_child_object_cost_base: Some(100), - dynamic_field_add_child_object_type_cost_per_byte: Some(10), - dynamic_field_add_child_object_value_cost_per_byte: Some(10), - dynamic_field_add_child_object_struct_tag_cost_per_byte: Some(10), - // Cost params for the Move native function `borrow_child_object_mut(parent: - // &mut UID, id: address): &mut Child` - dynamic_field_borrow_child_object_cost_base: Some(100), - dynamic_field_borrow_child_object_child_ref_cost_per_byte: Some(10), - dynamic_field_borrow_child_object_type_cost_per_byte: Some(10), - // Cost params for the Move native function `remove_child_object(parent: - // address, id: address): Child` - dynamic_field_remove_child_object_cost_base: Some(100), - dynamic_field_remove_child_object_child_cost_per_byte: Some(2), - dynamic_field_remove_child_object_type_cost_per_byte: Some(2), - // Cost params for the Move native function `has_child_object(parent: address, id: - // address): bool` - dynamic_field_has_child_object_cost_base: Some(100), - // Cost params for the Move native function `has_child_object_with_ty(parent: address, id: address): bool` - dynamic_field_has_child_object_with_ty_cost_base: Some(100), - dynamic_field_has_child_object_with_ty_type_cost_per_byte: Some(2), - dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: Some(2), - - // `event` module - // Cost params for the Move native function `event::emit(event: T)` - event_emit_cost_base: Some(52), - event_emit_value_size_derivation_cost_per_byte: Some(2), - event_emit_tag_size_derivation_cost_per_byte: Some(5), - event_emit_output_cost_per_byte: Some(10), - - // `object` module - // Cost params for the Move native function `borrow_uid(obj: &T): &UID` - object_borrow_uid_cost_base: Some(52), - // Cost params for the Move native function `delete_impl(id: address)` - object_delete_impl_cost_base: Some(52), - // Cost params for the Move native function `record_new_uid(id: address)` - object_record_new_uid_cost_base: Some(52), - - // `transfer` module - // Cost params for the Move native function `transfer_impl(obj: T, recipient: - // address)` - transfer_transfer_internal_cost_base: Some(52), - // Cost params for the Move native function `freeze_object(obj: T)` - transfer_freeze_object_cost_base: Some(52), - // Cost params for the Move native function `share_object(obj: T)` - transfer_share_object_cost_base: Some(52), - transfer_receive_object_cost_base: None, - - // `tx_context` module - // Cost params for the Move native function `transfer_impl(obj: T, recipient: - // address)` - tx_context_derive_id_cost_base: Some(52), - - // `types` module - // Cost params for the Move native function `is_one_time_witness(_: &T): bool` - types_is_one_time_witness_cost_base: Some(52), - types_is_one_time_witness_type_tag_cost_per_byte: Some(2), - types_is_one_time_witness_type_cost_per_byte: Some(2), - - // `validator` module - // Cost params for the Move native function `validate_metadata_bcs(metadata: - // vector)` - validator_validate_metadata_cost_base: Some(52), - validator_validate_metadata_data_cost_per_byte: Some(2), - - // Crypto - crypto_invalid_arguments_cost: Some(100), - // bls12381::bls12381_min_pk_verify - bls12381_bls12381_min_sig_verify_cost_base: Some(52), - bls12381_bls12381_min_sig_verify_msg_cost_per_byte: Some(2), - bls12381_bls12381_min_sig_verify_msg_cost_per_block: Some(2), - - // bls12381::bls12381_min_pk_verify - bls12381_bls12381_min_pk_verify_cost_base: Some(52), - bls12381_bls12381_min_pk_verify_msg_cost_per_byte: Some(2), - bls12381_bls12381_min_pk_verify_msg_cost_per_block: Some(2), - - // ecdsa_k1::ecrecover - ecdsa_k1_ecrecover_keccak256_cost_base: Some(52), - ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: Some(2), - ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: Some(2), - ecdsa_k1_ecrecover_sha256_cost_base: Some(52), - ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: Some(2), - ecdsa_k1_ecrecover_sha256_msg_cost_per_block: Some(2), - - // ecdsa_k1::decompress_pubkey - ecdsa_k1_decompress_pubkey_cost_base: Some(52), - - // ecdsa_k1::secp256k1_verify - ecdsa_k1_secp256k1_verify_keccak256_cost_base: Some(52), - ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: Some(2), - ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: Some(2), - ecdsa_k1_secp256k1_verify_sha256_cost_base: Some(52), - ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: Some(2), - ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: Some(2), - - // ecdsa_r1::ecrecover - ecdsa_r1_ecrecover_keccak256_cost_base: Some(52), - ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: Some(2), - ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: Some(2), - ecdsa_r1_ecrecover_sha256_cost_base: Some(52), - ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: Some(2), - ecdsa_r1_ecrecover_sha256_msg_cost_per_block: Some(2), - - // ecdsa_r1::secp256k1_verify - ecdsa_r1_secp256r1_verify_keccak256_cost_base: Some(52), - ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: Some(2), - ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: Some(2), - ecdsa_r1_secp256r1_verify_sha256_cost_base: Some(52), - ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: Some(2), - ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: Some(2), - - // ecvrf::verify - ecvrf_ecvrf_verify_cost_base: Some(52), - ecvrf_ecvrf_verify_alpha_string_cost_per_byte: Some(2), - ecvrf_ecvrf_verify_alpha_string_cost_per_block: Some(2), - - // ed25519 - ed25519_ed25519_verify_cost_base: Some(52), - ed25519_ed25519_verify_msg_cost_per_byte: Some(2), - ed25519_ed25519_verify_msg_cost_per_block: Some(2), - - // groth16::prepare_verifying_key - groth16_prepare_verifying_key_bls12381_cost_base: Some(52), - groth16_prepare_verifying_key_bn254_cost_base: Some(52), - - // groth16::verify_groth16_proof_internal - groth16_verify_groth16_proof_internal_bls12381_cost_base: Some(52), - groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: Some(2), - groth16_verify_groth16_proof_internal_bn254_cost_base: Some(52), - groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: Some(2), - groth16_verify_groth16_proof_internal_public_input_cost_per_byte: Some(2), - - // hash::blake2b256 - hash_blake2b256_cost_base: Some(52), - hash_blake2b256_data_cost_per_byte: Some(2), - hash_blake2b256_data_cost_per_block: Some(2), - // hash::keccak256 - hash_keccak256_cost_base: Some(52), - hash_keccak256_data_cost_per_byte: Some(2), - hash_keccak256_data_cost_per_block: Some(2), - - poseidon_bn254_cost_base: None, - poseidon_bn254_cost_per_block: None, - - // hmac::hmac_sha3_256 - hmac_hmac_sha3_256_cost_base: Some(52), - hmac_hmac_sha3_256_input_cost_per_byte: Some(2), - hmac_hmac_sha3_256_input_cost_per_block: Some(2), - - // group ops - group_ops_bls12381_decode_scalar_cost: None, - group_ops_bls12381_decode_g1_cost: None, - group_ops_bls12381_decode_g2_cost: None, - group_ops_bls12381_decode_gt_cost: None, - group_ops_bls12381_scalar_add_cost: None, - group_ops_bls12381_g1_add_cost: None, - group_ops_bls12381_g2_add_cost: None, - group_ops_bls12381_gt_add_cost: None, - group_ops_bls12381_scalar_sub_cost: None, - group_ops_bls12381_g1_sub_cost: None, - group_ops_bls12381_g2_sub_cost: None, - group_ops_bls12381_gt_sub_cost: None, - group_ops_bls12381_scalar_mul_cost: None, - group_ops_bls12381_g1_mul_cost: None, - group_ops_bls12381_g2_mul_cost: None, - group_ops_bls12381_gt_mul_cost: None, - group_ops_bls12381_scalar_div_cost: None, - group_ops_bls12381_g1_div_cost: None, - group_ops_bls12381_g2_div_cost: None, - group_ops_bls12381_gt_div_cost: None, - group_ops_bls12381_g1_hash_to_base_cost: None, - group_ops_bls12381_g2_hash_to_base_cost: None, - group_ops_bls12381_g1_hash_to_cost_per_byte: None, - group_ops_bls12381_g2_hash_to_cost_per_byte: None, - group_ops_bls12381_g1_msm_base_cost: None, - group_ops_bls12381_g2_msm_base_cost: None, - group_ops_bls12381_g1_msm_base_cost_per_input: None, - group_ops_bls12381_g2_msm_base_cost_per_input: None, - group_ops_bls12381_msm_max_len: None, - group_ops_bls12381_pairing_cost: None, - - // zklogin::check_zklogin_id - check_zklogin_id_cost_base: None, - // zklogin::check_zklogin_issuer - check_zklogin_issuer_cost_base: None, - - max_size_written_objects: None, - max_size_written_objects_system_tx: None, - - // Const params for consensus scoring decision - scoring_decision_mad_divisor: None, - scoring_decision_cutoff_value: None, - - // Limits the length of a Move identifier - max_move_identifier_len: None, - max_move_value_depth: None, - - gas_rounding_step: None, - - execution_version: None, - - max_event_emit_size_total: None, - - consensus_bad_nodes_stake_threshold: None, - - max_jwk_votes_per_validator_per_epoch: None, - - max_age_of_jwk_in_epochs: None, - - random_beacon_reduction_allowed_delta: None, - - random_beacon_reduction_lower_bound: None, - - random_beacon_dkg_timeout_round: None, - - consensus_max_transaction_size_bytes: None, - - consensus_max_transactions_in_block_bytes: None, - // When adding a new constant, set it to None in the earliest version, like this: - // new_constant: None, - }; - for cur in 2..=version.0 { - match cur { - 1 => unreachable!(), - 2 => { - cfg.feature_flags.advance_epoch_start_time_in_safe_mode = true; - } - 3 => { - // changes for gas model - cfg.gas_model_version = Some(2); - // max gas budget is in MIST and an absolute value 50SUI - cfg.max_tx_gas = Some(50_000_000_000); - // min gas budget is in MIST and an absolute value 2000MIST or 0.000002SUI - cfg.base_tx_cost_fixed = Some(2_000); - // storage gas price multiplier - cfg.storage_gas_price = Some(76); - cfg.feature_flags.loaded_child_objects_fixed = true; - // max size of written objects during a TXn - // this is a sum of all objects written during a TXn - cfg.max_size_written_objects = Some(5 * 1000 * 1000); - // max size of written objects during a system TXn to allow for larger writes - // akin to `max_size_written_objects` but for system TXns - cfg.max_size_written_objects_system_tx = Some(50 * 1000 * 1000); - cfg.feature_flags.package_upgrades = true; - } - // This is the first protocol version currently possible. - // Mainnet starts with version 4. Previous versions are pre mainnet and have - // all been wiped out. - // Every other chain is after version 4. - 4 => { - // Change reward slashing rate to 100%. - cfg.reward_slashing_rate = Some(10000); - // protect old and new lookup for object version - cfg.gas_model_version = Some(3); - } - 5 => { - cfg.feature_flags.missing_type_is_compatibility_error = true; - cfg.gas_model_version = Some(4); - cfg.feature_flags.scoring_decision_with_validity_cutoff = true; - cfg.scoring_decision_mad_divisor = Some(2.3); - cfg.scoring_decision_cutoff_value = Some(2.5); - } - 6 => { - cfg.gas_model_version = Some(5); - cfg.buffer_stake_for_protocol_upgrade_bps = Some(5000); - cfg.feature_flags.consensus_order_end_of_epoch_last = true; - } - 7 => { - cfg.feature_flags.disallow_adding_abilities_on_upgrade = true; - cfg.feature_flags - .disable_invariant_violation_check_in_swap_loc = true; - cfg.feature_flags.ban_entry_init = true; - cfg.feature_flags.package_digest_hash_module = true; - } - 8 => { - cfg.feature_flags - .disallow_change_struct_type_params_on_upgrade = true; - } - 9 => { - // Limits the length of a Move identifier - cfg.max_move_identifier_len = Some(128); - cfg.feature_flags.no_extraneous_module_bytes = true; - cfg.feature_flags - .advance_to_highest_supported_protocol_version = true; - } - 10 => { - cfg.max_verifier_meter_ticks_per_function = Some(16_000_000); - cfg.max_meter_ticks_per_module = Some(16_000_000); - } - 11 => { - cfg.max_move_value_depth = Some(128); - } - 12 => { - cfg.feature_flags.narwhal_versioned_metadata = true; - if chain != Chain::Mainnet { - cfg.feature_flags.commit_root_state_digest = true; - } - - if chain != Chain::Mainnet && chain != Chain::Testnet { - cfg.feature_flags.zklogin_auth = true; - } - } - 13 => {} - 14 => { - cfg.gas_rounding_step = Some(1_000); - cfg.gas_model_version = Some(6); - } - 15 => { - cfg.feature_flags.consensus_transaction_ordering = - ConsensusTransactionOrdering::ByGasPrice; - } - 16 => { - cfg.feature_flags.simplified_unwrap_then_delete = true; - } - 17 => { - cfg.feature_flags.upgraded_multisig_supported = true; - } - 18 => { - cfg.execution_version = Some(1); - // Following flags are implied by this execution version. Once support for - // earlier protocol versions is dropped, these flags can be - // removed: cfg.feature_flags.package_upgrades = true; - // cfg.feature_flags.disallow_adding_abilities_on_upgrade = true; - // cfg.feature_flags.disallow_change_struct_type_params_on_upgrade = true; - // cfg.feature_flags.loaded_child_objects_fixed = true; - // cfg.feature_flags.ban_entry_init = true; - // cfg.feature_flags.pack_digest_hash_modules = true; - cfg.feature_flags.txn_base_cost_as_multiplier = true; - // this is a multiplier of the gas price - cfg.base_tx_cost_fixed = Some(1_000); - } - 19 => { - cfg.max_num_event_emit = Some(1024); - // We maintain the same total size limit for events, but increase the number of - // events that can be emitted. - cfg.max_event_emit_size_total = Some( - 256 /* former event count limit */ * 250 * 1024, // size limit per event - ); - } - 20 => { - cfg.feature_flags.commit_root_state_digest = true; - - if chain != Chain::Mainnet { - cfg.feature_flags.narwhal_new_leader_election_schedule = true; - cfg.consensus_bad_nodes_stake_threshold = Some(20); - } - } - - 21 => { - if chain != Chain::Mainnet { - cfg.feature_flags.zklogin_supported_providers = BTreeSet::from([ - "Google".to_string(), - "Facebook".to_string(), - "Twitch".to_string(), - ]); - } - } - 22 => { - cfg.feature_flags.loaded_child_object_format = true; - } - 23 => { - cfg.feature_flags.loaded_child_object_format_type = true; - cfg.feature_flags.narwhal_new_leader_election_schedule = true; - // Taking a baby step approach, we consider only 20% by stake as bad nodes so we - // have a 80% by stake of nodes participating in the leader committee. That - // allow us for more redundancy in case we have validators - // under performing - since the responsibility is shared - // amongst more nodes. We can increase that once we do have - // higher confidence. - cfg.consensus_bad_nodes_stake_threshold = Some(20); - } - 24 => { - cfg.feature_flags.simple_conservation_checks = true; - cfg.max_publish_or_upgrade_per_ptb = Some(5); - - cfg.feature_flags.end_of_epoch_transaction_supported = true; - - if chain != Chain::Mainnet { - cfg.feature_flags.enable_jwk_consensus_updates = true; - // Max of 10 votes per hour - cfg.max_jwk_votes_per_validator_per_epoch = Some(240); - cfg.max_age_of_jwk_in_epochs = Some(1); - } - } - 25 => { - // Enable zkLogin for all providers in all networks. - cfg.feature_flags.zklogin_supported_providers = BTreeSet::from([ - "Google".to_string(), - "Facebook".to_string(), - "Twitch".to_string(), - ]); - cfg.feature_flags.zklogin_auth = true; - - // Enable jwk consensus updates - cfg.feature_flags.enable_jwk_consensus_updates = true; - cfg.max_jwk_votes_per_validator_per_epoch = Some(240); - cfg.max_age_of_jwk_in_epochs = Some(1); - } - 26 => { - cfg.gas_model_version = Some(7); - // Only enable receiving objects in devnet - if chain != Chain::Mainnet && chain != Chain::Testnet { - cfg.transfer_receive_object_cost_base = Some(52); - cfg.feature_flags.receive_objects = true; - } - } - 27 => { - cfg.gas_model_version = Some(8); - } - 28 => { - // zklogin::check_zklogin_id - cfg.check_zklogin_id_cost_base = Some(200); - // zklogin::check_zklogin_issuer - cfg.check_zklogin_issuer_cost_base = Some(200); - - // Only enable effects v2 on devnet. - if chain != Chain::Mainnet && chain != Chain::Testnet { - cfg.feature_flags.enable_effects_v2 = true; - } - } - 29 => { - cfg.feature_flags.verify_legacy_zklogin_address = true; - } - 30 => { - // Only enable nw certificate v2 on testnet. - if chain != Chain::Mainnet { - cfg.feature_flags.narwhal_certificate_v2 = true; - } - - cfg.random_beacon_reduction_allowed_delta = Some(800); - // Only enable effects v2 on devnet and testnet. - if chain != Chain::Mainnet { - cfg.feature_flags.enable_effects_v2 = true; - } - - // zklogin_supported_providers config is deprecated, zklogin - // signature verifier will use the fetched jwk map to determine - // whether the provider is supported based on node config. - cfg.feature_flags.zklogin_supported_providers = BTreeSet::default(); - - cfg.feature_flags.recompute_has_public_transfer_in_execution = true; - } - 31 => { - cfg.execution_version = Some(2); - // Only enable shared object deletion on devnet - if chain != Chain::Mainnet && chain != Chain::Testnet { - cfg.feature_flags.shared_object_deletion = true; - } - } - 32 => { - // enable zklogin in multisig in devnet and testnet - if chain != Chain::Mainnet { - cfg.feature_flags.accept_zklogin_in_multisig = true; - } - // enable receiving objects in devnet and testnet - if chain != Chain::Mainnet { - cfg.transfer_receive_object_cost_base = Some(52); - cfg.feature_flags.receive_objects = true; - } - // Only enable random beacon on devnet - if chain != Chain::Mainnet && chain != Chain::Testnet { - cfg.feature_flags.random_beacon = true; - cfg.random_beacon_reduction_lower_bound = Some(1600); - cfg.random_beacon_dkg_timeout_round = Some(200); - } - // Only enable consensus digest in consensus commit prologue in devnet. - if chain != Chain::Testnet && chain != Chain::Mainnet { - cfg.feature_flags.include_consensus_digest_in_prologue = true; - } - - // enable nw cert v2 on mainnet - cfg.feature_flags.narwhal_certificate_v2 = true; - } - 33 => { - cfg.feature_flags.hardened_otw_check = true; - cfg.feature_flags.allow_receiving_object_id = true; - - // Enable transfer-to-object in mainnet - cfg.transfer_receive_object_cost_base = Some(52); - cfg.feature_flags.receive_objects = true; - - // Enable shared object deletion in testnet and devnet - if chain != Chain::Mainnet { - cfg.feature_flags.shared_object_deletion = true; - } - - cfg.feature_flags.enable_effects_v2 = true; - } - 34 => {} - 35 => { - // Add costs for poseidon::poseidon_bn254 - if chain != Chain::Mainnet && chain != Chain::Testnet { - cfg.feature_flags.enable_poseidon = true; - cfg.poseidon_bn254_cost_base = Some(260); - cfg.poseidon_bn254_cost_per_block = Some(10); - } - - cfg.feature_flags.enable_coin_deny_list = true; - } - 36 => { - // Only enable group ops on devnet - if chain != Chain::Mainnet && chain != Chain::Testnet { - cfg.feature_flags.enable_group_ops_native_functions = true; - cfg.feature_flags.enable_group_ops_native_function_msm = true; - // Next values are arbitrary in a similar way as the other crypto native - // functions. - cfg.group_ops_bls12381_decode_scalar_cost = Some(52); - cfg.group_ops_bls12381_decode_g1_cost = Some(52); - cfg.group_ops_bls12381_decode_g2_cost = Some(52); - cfg.group_ops_bls12381_decode_gt_cost = Some(52); - cfg.group_ops_bls12381_scalar_add_cost = Some(52); - cfg.group_ops_bls12381_g1_add_cost = Some(52); - cfg.group_ops_bls12381_g2_add_cost = Some(52); - cfg.group_ops_bls12381_gt_add_cost = Some(52); - cfg.group_ops_bls12381_scalar_sub_cost = Some(52); - cfg.group_ops_bls12381_g1_sub_cost = Some(52); - cfg.group_ops_bls12381_g2_sub_cost = Some(52); - cfg.group_ops_bls12381_gt_sub_cost = Some(52); - cfg.group_ops_bls12381_scalar_mul_cost = Some(52); - cfg.group_ops_bls12381_g1_mul_cost = Some(52); - cfg.group_ops_bls12381_g2_mul_cost = Some(52); - cfg.group_ops_bls12381_gt_mul_cost = Some(52); - cfg.group_ops_bls12381_scalar_div_cost = Some(52); - cfg.group_ops_bls12381_g1_div_cost = Some(52); - cfg.group_ops_bls12381_g2_div_cost = Some(52); - cfg.group_ops_bls12381_gt_div_cost = Some(52); - cfg.group_ops_bls12381_g1_hash_to_base_cost = Some(52); - cfg.group_ops_bls12381_g2_hash_to_base_cost = Some(52); - cfg.group_ops_bls12381_g1_hash_to_cost_per_byte = Some(2); - cfg.group_ops_bls12381_g2_hash_to_cost_per_byte = Some(2); - cfg.group_ops_bls12381_g1_msm_base_cost = Some(52); - cfg.group_ops_bls12381_g2_msm_base_cost = Some(52); - cfg.group_ops_bls12381_g1_msm_base_cost_per_input = Some(52); - cfg.group_ops_bls12381_g2_msm_base_cost_per_input = Some(52); - cfg.group_ops_bls12381_msm_max_len = Some(32); - cfg.group_ops_bls12381_pairing_cost = Some(52); - } - // Enable shared object deletion on all networks. - cfg.feature_flags.shared_object_deletion = true; - - cfg.consensus_max_transaction_size_bytes = Some(256 * 1024); // 256KB - cfg.consensus_max_transactions_in_block_bytes = Some(6 * 1_024 * 1024); - // 6 MB - } - 37 => { - cfg.feature_flags.reject_mutable_random_on_entry_functions = true; - - // Enable consensus digest in consensus commit prologue in testnet and devnet. - if chain != Chain::Mainnet { - cfg.feature_flags.include_consensus_digest_in_prologue = true; - } - } - 38 => { - cfg.binary_module_handles = Some(100); - cfg.binary_struct_handles = Some(300); - cfg.binary_function_handles = Some(1500); - cfg.binary_function_instantiations = Some(750); - cfg.binary_signatures = Some(1000); - // constants and identifiers are proportional to the binary size, - // and they vastly depend on the code, so we are leaving them - // reasonably high - cfg.binary_constant_pool = Some(4000); - cfg.binary_identifiers = Some(10000); - cfg.binary_address_identifiers = Some(100); - cfg.binary_struct_defs = Some(200); - cfg.binary_struct_def_instantiations = Some(100); - cfg.binary_function_defs = Some(1000); - cfg.binary_field_handles = Some(500); - cfg.binary_field_instantiations = Some(250); - cfg.binary_friend_decls = Some(100); - // reduce dependencies maximum - cfg.max_package_dependencies = Some(32); - cfg.max_modules_in_publish = Some(64); - // bump execution version - cfg.execution_version = Some(3); - } - 39 => { - // It is important that we keep this protocol version blank - // due to an issue with random.move. - } - 40 => {} - 41 => { - // Enable group ops and all networks (but not msm) - cfg.feature_flags.enable_group_ops_native_functions = true; - // Next values are arbitrary in a similar way as the other crypto native - // functions. - cfg.group_ops_bls12381_decode_scalar_cost = Some(52); - cfg.group_ops_bls12381_decode_g1_cost = Some(52); - cfg.group_ops_bls12381_decode_g2_cost = Some(52); - cfg.group_ops_bls12381_decode_gt_cost = Some(52); - cfg.group_ops_bls12381_scalar_add_cost = Some(52); - cfg.group_ops_bls12381_g1_add_cost = Some(52); - cfg.group_ops_bls12381_g2_add_cost = Some(52); - cfg.group_ops_bls12381_gt_add_cost = Some(52); - cfg.group_ops_bls12381_scalar_sub_cost = Some(52); - cfg.group_ops_bls12381_g1_sub_cost = Some(52); - cfg.group_ops_bls12381_g2_sub_cost = Some(52); - cfg.group_ops_bls12381_gt_sub_cost = Some(52); - cfg.group_ops_bls12381_scalar_mul_cost = Some(52); - cfg.group_ops_bls12381_g1_mul_cost = Some(52); - cfg.group_ops_bls12381_g2_mul_cost = Some(52); - cfg.group_ops_bls12381_gt_mul_cost = Some(52); - cfg.group_ops_bls12381_scalar_div_cost = Some(52); - cfg.group_ops_bls12381_g1_div_cost = Some(52); - cfg.group_ops_bls12381_g2_div_cost = Some(52); - cfg.group_ops_bls12381_gt_div_cost = Some(52); - cfg.group_ops_bls12381_g1_hash_to_base_cost = Some(52); - cfg.group_ops_bls12381_g2_hash_to_base_cost = Some(52); - cfg.group_ops_bls12381_g1_hash_to_cost_per_byte = Some(2); - cfg.group_ops_bls12381_g2_hash_to_cost_per_byte = Some(2); - cfg.group_ops_bls12381_g1_msm_base_cost = Some(52); - cfg.group_ops_bls12381_g2_msm_base_cost = Some(52); - cfg.group_ops_bls12381_g1_msm_base_cost_per_input = Some(52); - cfg.group_ops_bls12381_g2_msm_base_cost_per_input = Some(52); - cfg.group_ops_bls12381_msm_max_len = Some(32); - cfg.group_ops_bls12381_pairing_cost = Some(52); - } - 42 => {} - // Use this template when making changes: - // - // // modify an existing constant. - // move_binary_format_version: Some(7), - // - // // Add a new constant (which is set to None in prior versions). - // new_constant: Some(new_value), - // - // // Remove a constant (ensure that it is never accessed during this version). - // max_move_object_size: None, - _ => panic!("unsupported version {:?}", version), - } - } - cfg - } - - /// Override one or more settings in the config, for testing. - /// This must be called at the beginning of the test, before - /// get_for_(min|max)_version is called, since those functions cache - /// their return value. - pub fn apply_overrides_for_testing( - override_fn: impl Fn(ProtocolVersion, Self) -> Self + Send + 'static, - ) -> OverrideGuard { - CONFIG_OVERRIDE.with(|ovr| { - let mut cur = ovr.borrow_mut(); - assert!(cur.is_none(), "config override already present"); - *cur = Some(Box::new(override_fn)); - OverrideGuard - }) - } -} - -// Setters for tests -impl ProtocolConfig { - pub fn set_package_upgrades_for_testing(&mut self, val: bool) { - self.feature_flags.package_upgrades = val - } - pub fn set_advance_to_highest_supported_protocol_version_for_testing(&mut self, val: bool) { - self.feature_flags - .advance_to_highest_supported_protocol_version = val - } - pub fn set_commit_root_state_digest_supported(&mut self, val: bool) { - self.feature_flags.commit_root_state_digest = val - } - pub fn set_zklogin_auth_for_testing(&mut self, val: bool) { - self.feature_flags.zklogin_auth = val - } - pub fn set_enable_jwk_consensus_updates_for_testing(&mut self, val: bool) { - self.feature_flags.enable_jwk_consensus_updates = val - } - pub fn set_random_beacon_for_testing(&mut self, val: bool) { - self.feature_flags.random_beacon = val - } - pub fn set_upgraded_multisig_for_testing(&mut self, val: bool) { - self.feature_flags.upgraded_multisig_supported = val - } - pub fn set_accept_zklogin_in_multisig_for_testing(&mut self, val: bool) { - self.feature_flags.accept_zklogin_in_multisig = val - } - #[cfg(msim)] - pub fn set_simplified_unwrap_then_delete(&mut self, val: bool) { - self.feature_flags.simplified_unwrap_then_delete = val; - if val == false { - // Given that we will never enable effect V2 before turning on - // simplified_unwrap_then_delete, we also need to disable effect V2 here. - self.set_enable_effects_v2(false); - } - } - pub fn set_shared_object_deletion(&mut self, val: bool) { - self.feature_flags.shared_object_deletion = val; - } - - pub fn set_narwhal_new_leader_election_schedule(&mut self, val: bool) { - self.feature_flags.narwhal_new_leader_election_schedule = val; - } - - pub fn set_consensus_bad_nodes_stake_threshold(&mut self, val: u64) { - self.consensus_bad_nodes_stake_threshold = Some(val); - } - pub fn set_receive_object_for_testing(&mut self, val: bool) { - self.feature_flags.receive_objects = val - } - pub fn set_narwhal_certificate_v2(&mut self, val: bool) { - self.feature_flags.narwhal_certificate_v2 = val - } - pub fn set_verify_legacy_zklogin_address(&mut self, val: bool) { - self.feature_flags.verify_legacy_zklogin_address = val - } - pub fn set_enable_effects_v2(&mut self, val: bool) { - self.feature_flags.enable_effects_v2 = val; - } - pub fn set_consensus_max_transaction_size_bytes(&mut self, val: u64) { - self.consensus_max_transaction_size_bytes = Some(val); - } - pub fn set_consensus_max_transactions_in_block_bytes(&mut self, val: u64) { - self.consensus_max_transactions_in_block_bytes = Some(val); - } -} - -type OverrideFn = dyn Fn(ProtocolVersion, ProtocolConfig) -> ProtocolConfig + Send; - -thread_local! { - static CONFIG_OVERRIDE: RefCell>> = RefCell::new(None); -} - -#[must_use] -pub struct OverrideGuard; - -impl Drop for OverrideGuard { - fn drop(&mut self) { - info!("restoring override fn"); - CONFIG_OVERRIDE.with(|ovr| { - *ovr.borrow_mut() = None; - }); - } -} - -/// Defines which limit got crossed. -/// The value which crossed the limit and value of the limit crossed are -/// embedded -#[derive(PartialEq, Eq)] -pub enum LimitThresholdCrossed { - None, - Soft(u128, u128), - Hard(u128, u128), -} - -/// Convenience function for comparing limit ranges -/// V::MAX must be at >= U::MAX and T::MAX -pub fn check_limit_in_range, U: Into, V: PartialOrd + Into>( - x: T, - soft_limit: U, - hard_limit: V, -) -> LimitThresholdCrossed { - let x: V = x.into(); - let soft_limit: V = soft_limit.into(); - - debug_assert!(soft_limit <= hard_limit); - - // It is important to preserve this comparison order because if soft_limit == - // hard_limit we want LimitThresholdCrossed::Hard - if x >= hard_limit { - LimitThresholdCrossed::Hard(x.into(), hard_limit.into()) - } else if x < soft_limit { - LimitThresholdCrossed::None - } else { - LimitThresholdCrossed::Soft(x.into(), soft_limit.into()) - } -} - -#[macro_export] -macro_rules! check_limit { - ($x:expr, $hard:expr) => { - check_limit!($x, $hard, $hard) - }; - ($x:expr, $soft:expr, $hard:expr) => { - check_limit_in_range($x as u64, $soft, $hard) - }; -} - -/// Used to check which limits were crossed if the TX is metered (not system tx) -/// Args are: is_metered, value_to_check, metered_limit, unmetered_limit -/// metered_limit is always less than or equal to unmetered_hard_limit -#[macro_export] -macro_rules! check_limit_by_meter { - ($is_metered:expr, $x:expr, $metered_limit:expr, $unmetered_hard_limit:expr, $metric:expr) => {{ - // If this is metered, we use the metered_limit limit as the upper bound - let (h, metered_str) = if $is_metered { - ($metered_limit, "metered") - } else { - // Unmetered gets more headroom - ($unmetered_hard_limit, "unmetered") - }; - use sui_protocol_config::check_limit_in_range; - let result = check_limit_in_range($x as u64, $metered_limit, h); - match result { - LimitThresholdCrossed::None => {} - LimitThresholdCrossed::Soft(_, _) => { - $metric.with_label_values(&[metered_str, "soft"]).inc(); - } - LimitThresholdCrossed::Hard(_, _) => { - $metric.with_label_values(&[metered_str, "hard"]).inc(); - } - }; - result - }}; -} - -#[cfg(all(test, not(msim)))] -mod test { - use insta::assert_yaml_snapshot; - - use super::*; - - #[test] - fn snapshot_tests() { - println!("\n============================================================================"); - println!("! !"); - println!("! IMPORTANT: never update snapshots from this test. only add new versions! !"); - println!("! !"); - println!("============================================================================\n"); - for chain_id in &[Chain::Unknown, Chain::Mainnet, Chain::Testnet] { - // make Chain::Unknown snapshots compatible with pre-chain-id snapshots so that - // we don't break the release-time compatibility tests. Once Chain - // Id configs have been released everywhere, we can remove this and - // only test Mainnet and Testnet - let chain_str = match chain_id { - Chain::Unknown => "".to_string(), - _ => format!("{:?}_", chain_id), - }; - for i in MIN_PROTOCOL_VERSION..=MAX_PROTOCOL_VERSION { - let cur = ProtocolVersion::new(i); - assert_yaml_snapshot!( - format!("{}version_{}", chain_str, cur.as_u64()), - ProtocolConfig::get_for_version(cur, *chain_id) - ); - } - } - } - - #[test] - fn test_getters() { - let prot: ProtocolConfig = - ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Unknown); - assert_eq!( - prot.max_arguments(), - prot.max_arguments_as_option().unwrap() - ); - } - - #[test] - fn test_setters() { - let mut prot: ProtocolConfig = - ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Unknown); - prot.set_max_arguments_for_testing(123); - assert_eq!(prot.max_arguments(), 123); - - prot.set_max_arguments_from_str_for_testing("321".to_string()); - assert_eq!(prot.max_arguments(), 321); - - prot.disable_max_arguments_for_testing(); - assert_eq!(prot.max_arguments_as_option(), None); - - prot.set_attr_for_testing("max_arguments".to_string(), "456".to_string()); - assert_eq!(prot.max_arguments(), 456); - } - - #[test] - fn lookup_by_string_test() { - let prot: ProtocolConfig = - ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Unknown); - // Does not exist - assert!(prot.lookup_attr("some random string".to_string()).is_none()); - - assert!( - prot.lookup_attr("max_arguments".to_string()) - == Some(ProtocolConfigValue::u32(prot.max_arguments())), - ); - - // We didnt have this in version 1 - assert!( - prot.lookup_attr("max_move_identifier_len".to_string()) - .is_none() - ); - - // But we did in version 9 - let prot: ProtocolConfig = - ProtocolConfig::get_for_version(ProtocolVersion::new(9), Chain::Unknown); - assert!( - prot.lookup_attr("max_move_identifier_len".to_string()) - == Some(ProtocolConfigValue::u64(prot.max_move_identifier_len())) - ); - - let prot: ProtocolConfig = - ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Unknown); - // We didnt have this in version 1 - assert!( - prot.attr_map() - .get("max_move_identifier_len") - .unwrap() - .is_none() - ); - // We had this in version 1 - assert!( - prot.attr_map().get("max_arguments").unwrap() - == &Some(ProtocolConfigValue::u32(prot.max_arguments())) - ); - - // Check feature flags - let prot: ProtocolConfig = - ProtocolConfig::get_for_version(ProtocolVersion::new(1), Chain::Unknown); - // Does not exist - assert!( - prot.feature_flags - .lookup_attr("some random string".to_owned()) - .is_none() - ); - assert!( - prot.feature_flags - .attr_map() - .get("some random string") - .is_none() - ); - - // Was false in v1 - assert!( - prot.feature_flags - .lookup_attr("package_upgrades".to_owned()) - == Some(false) - ); - assert!( - prot.feature_flags - .attr_map() - .get("package_upgrades") - .unwrap() - == &false - ); - let prot: ProtocolConfig = - ProtocolConfig::get_for_version(ProtocolVersion::new(4), Chain::Unknown); - // Was true from v3 and up - assert!( - prot.feature_flags - .lookup_attr("package_upgrades".to_owned()) - == Some(true) - ); - assert!( - prot.feature_flags - .attr_map() - .get("package_upgrades") - .unwrap() - == &true - ); - } - - #[test] - fn limit_range_fn_test() { - let low = 100u32; - let high = 10000u64; - - assert!(check_limit!(1u8, low, high) == LimitThresholdCrossed::None); - assert!(matches!( - check_limit!(255u16, low, high), - LimitThresholdCrossed::Soft(255u128, 100) - )); - // This wont compile because lossy - // assert!(check_limit!(100000000u128, low, high) == - // LimitThresholdCrossed::None); This wont compile because lossy - // assert!(check_limit!(100000000usize, low, high) == - // LimitThresholdCrossed::None); - - assert!(matches!( - check_limit!(2550000u64, low, high), - LimitThresholdCrossed::Hard(2550000, 10000) - )); - - assert!(matches!( - check_limit!(2550000u64, high, high), - LimitThresholdCrossed::Hard(2550000, 10000) - )); - - assert!(matches!( - check_limit!(1u8, high), - LimitThresholdCrossed::None - )); - - assert!(check_limit!(255u16, high) == LimitThresholdCrossed::None); - - assert!(matches!( - check_limit!(2550000u64, high), - LimitThresholdCrossed::Hard(2550000, 10000) - )); - } -} diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_1.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_1.snap deleted file mode 100644 index 2054ea0da22..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_1.snap +++ /dev/null @@ -1,161 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 1 -feature_flags: {} -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 10000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 110000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 1 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 5000 -storage_gas_price: 1 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_10.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_10.snap deleted file mode 100644 index ca0e669641d..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_10.snap +++ /dev/null @@ -1,179 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 10 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_11.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_11.snap deleted file mode 100644 index b5a47c349db..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_11.snap +++ /dev/null @@ -1,180 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 11 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_12.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_12.snap deleted file mode 100644 index 78f62ac0784..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_12.snap +++ /dev/null @@ -1,181 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 12 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_13.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_13.snap deleted file mode 100644 index e05985d4109..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_13.snap +++ /dev/null @@ -1,181 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 13 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_14.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_14.snap deleted file mode 100644 index 7dc7acfe846..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_14.snap +++ /dev/null @@ -1,182 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 14 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_15.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_15.snap deleted file mode 100644 index 64838bafff0..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_15.snap +++ /dev/null @@ -1,183 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 15 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_16.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_16.snap deleted file mode 100644 index 7f0c0b680b3..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_16.snap +++ /dev/null @@ -1,184 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 16 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_17.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_17.snap deleted file mode 100644 index 67e764471fe..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_17.snap +++ /dev/null @@ -1,185 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 17 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_18.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_18.snap deleted file mode 100644 index a0ef828c1dc..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_18.snap +++ /dev/null @@ -1,187 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 18 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_19.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_19.snap deleted file mode 100644 index 74a03e8f3bd..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_19.snap +++ /dev/null @@ -1,188 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 19 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_2.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_2.snap deleted file mode 100644 index 84e0d4dcb37..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_2.snap +++ /dev/null @@ -1,162 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 2 -feature_flags: - advance_epoch_start_time_in_safe_mode: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 10000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 110000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 1 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 5000 -storage_gas_price: 1 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_20.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_20.snap deleted file mode 100644 index 66637ea7497..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_20.snap +++ /dev/null @@ -1,189 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 20 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_21.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_21.snap deleted file mode 100644 index 2d1bc3b7679..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_21.snap +++ /dev/null @@ -1,190 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -assertion_line: 1578 -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 21 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_22.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_22.snap deleted file mode 100644 index c567c81097c..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_22.snap +++ /dev/null @@ -1,190 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 22 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - loaded_child_object_format: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_23.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_23.snap deleted file mode 100644 index 9d597266e34..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_23.snap +++ /dev/null @@ -1,193 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 23 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_24.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_24.snap deleted file mode 100644 index 8f979463c7a..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_24.snap +++ /dev/null @@ -1,196 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 24 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_25.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_25.snap deleted file mode 100644 index 090964857ec..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_25.snap +++ /dev/null @@ -1,204 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 25 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_26.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_26.snap deleted file mode 100644 index 6e417c4df1b..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_26.snap +++ /dev/null @@ -1,204 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 26 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 7 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_27.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_27.snap deleted file mode 100644 index 79802ad5c42..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_27.snap +++ /dev/null @@ -1,204 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 27 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_28.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_28.snap deleted file mode 100644 index 9e88e835c71..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_28.snap +++ /dev/null @@ -1,206 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 28 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_29.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_29.snap deleted file mode 100644 index ec44a3a9129..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_29.snap +++ /dev/null @@ -1,207 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 29 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - verify_legacy_zklogin_address: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_3.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_3.snap deleted file mode 100644 index 909b9cca478..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_3.snap +++ /dev/null @@ -1,166 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 3 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 2 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 5000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_30.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_30.snap deleted file mode 100644 index 50c7e3e9ee0..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_30.snap +++ /dev/null @@ -1,205 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 30 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_31.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_31.snap deleted file mode 100644 index 051abce77ea..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_31.snap +++ /dev/null @@ -1,205 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 31 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_32.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_32.snap deleted file mode 100644 index aeb65b3b693..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_32.snap +++ /dev/null @@ -1,206 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 32 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_33.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_33.snap deleted file mode 100644 index 4b72129f811..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_33.snap +++ /dev/null @@ -1,211 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 33 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - hardened_otw_check: true - allow_receiving_object_id: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_34.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_34.snap deleted file mode 100644 index 59a294fd2a2..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_34.snap +++ /dev/null @@ -1,211 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 34 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - hardened_otw_check: true - allow_receiving_object_id: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_35.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_35.snap deleted file mode 100644 index 771a370b88c..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_35.snap +++ /dev/null @@ -1,212 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 35 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_36.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_36.snap deleted file mode 100644 index 2cf05242b9d..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_36.snap +++ /dev/null @@ -1,215 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 36 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_37.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_37.snap deleted file mode 100644 index 9967595041c..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_37.snap +++ /dev/null @@ -1,216 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 37 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_38.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_38.snap deleted file mode 100644 index 2e9cfea0cae..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_38.snap +++ /dev/null @@ -1,231 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 38 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_39.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_39.snap deleted file mode 100644 index 81ae35c9710..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_39.snap +++ /dev/null @@ -1,231 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 39 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_4.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_4.snap deleted file mode 100644 index 5a3c10d77c7..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_4.snap +++ /dev/null @@ -1,166 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 4 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 3 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_40.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_40.snap deleted file mode 100644 index 2ae7a736586..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_40.snap +++ /dev/null @@ -1,231 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 40 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_41.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_41.snap deleted file mode 100644 index 81dc925f58f..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_41.snap +++ /dev/null @@ -1,262 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 41 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true - enable_group_ops_native_functions: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -group_ops_bls12381_decode_scalar_cost: 52 -group_ops_bls12381_decode_g1_cost: 52 -group_ops_bls12381_decode_g2_cost: 52 -group_ops_bls12381_decode_gt_cost: 52 -group_ops_bls12381_scalar_add_cost: 52 -group_ops_bls12381_g1_add_cost: 52 -group_ops_bls12381_g2_add_cost: 52 -group_ops_bls12381_gt_add_cost: 52 -group_ops_bls12381_scalar_sub_cost: 52 -group_ops_bls12381_g1_sub_cost: 52 -group_ops_bls12381_g2_sub_cost: 52 -group_ops_bls12381_gt_sub_cost: 52 -group_ops_bls12381_scalar_mul_cost: 52 -group_ops_bls12381_g1_mul_cost: 52 -group_ops_bls12381_g2_mul_cost: 52 -group_ops_bls12381_gt_mul_cost: 52 -group_ops_bls12381_scalar_div_cost: 52 -group_ops_bls12381_g1_div_cost: 52 -group_ops_bls12381_g2_div_cost: 52 -group_ops_bls12381_gt_div_cost: 52 -group_ops_bls12381_g1_hash_to_base_cost: 52 -group_ops_bls12381_g2_hash_to_base_cost: 52 -group_ops_bls12381_g1_hash_to_cost_per_byte: 2 -group_ops_bls12381_g2_hash_to_cost_per_byte: 2 -group_ops_bls12381_g1_msm_base_cost: 52 -group_ops_bls12381_g2_msm_base_cost: 52 -group_ops_bls12381_g1_msm_base_cost_per_input: 52 -group_ops_bls12381_g2_msm_base_cost_per_input: 52 -group_ops_bls12381_msm_max_len: 32 -group_ops_bls12381_pairing_cost: 52 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_42.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_42.snap deleted file mode 100644 index d6b4f8d6750..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_42.snap +++ /dev/null @@ -1,262 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 42 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true - enable_group_ops_native_functions: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -group_ops_bls12381_decode_scalar_cost: 52 -group_ops_bls12381_decode_g1_cost: 52 -group_ops_bls12381_decode_g2_cost: 52 -group_ops_bls12381_decode_gt_cost: 52 -group_ops_bls12381_scalar_add_cost: 52 -group_ops_bls12381_g1_add_cost: 52 -group_ops_bls12381_g2_add_cost: 52 -group_ops_bls12381_gt_add_cost: 52 -group_ops_bls12381_scalar_sub_cost: 52 -group_ops_bls12381_g1_sub_cost: 52 -group_ops_bls12381_g2_sub_cost: 52 -group_ops_bls12381_gt_sub_cost: 52 -group_ops_bls12381_scalar_mul_cost: 52 -group_ops_bls12381_g1_mul_cost: 52 -group_ops_bls12381_g2_mul_cost: 52 -group_ops_bls12381_gt_mul_cost: 52 -group_ops_bls12381_scalar_div_cost: 52 -group_ops_bls12381_g1_div_cost: 52 -group_ops_bls12381_g2_div_cost: 52 -group_ops_bls12381_gt_div_cost: 52 -group_ops_bls12381_g1_hash_to_base_cost: 52 -group_ops_bls12381_g2_hash_to_base_cost: 52 -group_ops_bls12381_g1_hash_to_cost_per_byte: 2 -group_ops_bls12381_g2_hash_to_cost_per_byte: 2 -group_ops_bls12381_g1_msm_base_cost: 52 -group_ops_bls12381_g2_msm_base_cost: 52 -group_ops_bls12381_g1_msm_base_cost_per_input: 52 -group_ops_bls12381_g2_msm_base_cost_per_input: 52 -group_ops_bls12381_msm_max_len: 32 -group_ops_bls12381_pairing_cost: 52 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_5.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_5.snap deleted file mode 100644 index c7ec728a6e9..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_5.snap +++ /dev/null @@ -1,170 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 5 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 4 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_6.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_6.snap deleted file mode 100644 index 2f5e9b84e18..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_6.snap +++ /dev/null @@ -1,171 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 6 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_7.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_7.snap deleted file mode 100644 index f259aef8f8e..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_7.snap +++ /dev/null @@ -1,175 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 7 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - ban_entry_init: true - package_digest_hash_module: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_8.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_8.snap deleted file mode 100644 index 30e47cddfcd..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_8.snap +++ /dev/null @@ -1,176 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 8 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_9.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_9.snap deleted file mode 100644 index ea60c2e2227..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_9.snap +++ /dev/null @@ -1,179 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 9 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_1.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_1.snap deleted file mode 100644 index 2054ea0da22..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_1.snap +++ /dev/null @@ -1,161 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 1 -feature_flags: {} -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 10000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 110000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 1 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 5000 -storage_gas_price: 1 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_10.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_10.snap deleted file mode 100644 index ca0e669641d..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_10.snap +++ /dev/null @@ -1,179 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 10 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_11.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_11.snap deleted file mode 100644 index b5a47c349db..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_11.snap +++ /dev/null @@ -1,180 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 11 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_12.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_12.snap deleted file mode 100644 index 654806391d9..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_12.snap +++ /dev/null @@ -1,182 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 12 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_13.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_13.snap deleted file mode 100644 index c7b71cd8859..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_13.snap +++ /dev/null @@ -1,182 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 13 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_14.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_14.snap deleted file mode 100644 index 37d4f2e2f5e..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_14.snap +++ /dev/null @@ -1,183 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 14 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_15.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_15.snap deleted file mode 100644 index 63e7a656cc1..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_15.snap +++ /dev/null @@ -1,184 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 15 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_16.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_16.snap deleted file mode 100644 index 4cd96200670..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_16.snap +++ /dev/null @@ -1,185 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 16 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_17.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_17.snap deleted file mode 100644 index 8d8ea894d75..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_17.snap +++ /dev/null @@ -1,186 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 17 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_18.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_18.snap deleted file mode 100644 index 0ca6c89d356..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_18.snap +++ /dev/null @@ -1,188 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 18 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_19.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_19.snap deleted file mode 100644 index 4d7e3b6aa10..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_19.snap +++ /dev/null @@ -1,189 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 19 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_2.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_2.snap deleted file mode 100644 index 84e0d4dcb37..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_2.snap +++ /dev/null @@ -1,162 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 2 -feature_flags: - advance_epoch_start_time_in_safe_mode: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 10000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 110000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 1 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 5000 -storage_gas_price: 1 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_20.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_20.snap deleted file mode 100644 index 303dcb8d347..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_20.snap +++ /dev/null @@ -1,191 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 20 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_21.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_21.snap deleted file mode 100644 index 19901cd46d8..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_21.snap +++ /dev/null @@ -1,195 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 21 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_22.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_22.snap deleted file mode 100644 index c0829a989bd..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_22.snap +++ /dev/null @@ -1,196 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 22 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_23.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_23.snap deleted file mode 100644 index 8032ebea8e0..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_23.snap +++ /dev/null @@ -1,197 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 23 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_24.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_24.snap deleted file mode 100644 index 49f07d77bb8..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_24.snap +++ /dev/null @@ -1,203 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 24 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_25.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_25.snap deleted file mode 100644 index 090964857ec..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_25.snap +++ /dev/null @@ -1,204 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 25 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_26.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_26.snap deleted file mode 100644 index 6e417c4df1b..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_26.snap +++ /dev/null @@ -1,204 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 26 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 7 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_27.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_27.snap deleted file mode 100644 index 79802ad5c42..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_27.snap +++ /dev/null @@ -1,204 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 27 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_28.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_28.snap deleted file mode 100644 index 9e88e835c71..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_28.snap +++ /dev/null @@ -1,206 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 28 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_29.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_29.snap deleted file mode 100644 index ec44a3a9129..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_29.snap +++ /dev/null @@ -1,207 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 29 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - verify_legacy_zklogin_address: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_3.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_3.snap deleted file mode 100644 index 909b9cca478..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_3.snap +++ /dev/null @@ -1,166 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 3 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 2 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 5000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_30.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_30.snap deleted file mode 100644 index f253b3568ab..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_30.snap +++ /dev/null @@ -1,207 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 30 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_31.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_31.snap deleted file mode 100644 index 9dc8fded148..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_31.snap +++ /dev/null @@ -1,207 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 31 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_32.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_32.snap deleted file mode 100644 index 31cfe89f607..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_32.snap +++ /dev/null @@ -1,210 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 32 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_33.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_33.snap deleted file mode 100644 index f6e6eacadb5..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_33.snap +++ /dev/null @@ -1,213 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 33 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - hardened_otw_check: true - allow_receiving_object_id: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_34.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_34.snap deleted file mode 100644 index 07a8a685d34..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_34.snap +++ /dev/null @@ -1,213 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 34 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - hardened_otw_check: true - allow_receiving_object_id: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_35.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_35.snap deleted file mode 100644 index a19a7264dc6..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_35.snap +++ /dev/null @@ -1,214 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 35 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_36.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_36.snap deleted file mode 100644 index 9a7597b38dc..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_36.snap +++ /dev/null @@ -1,216 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 36 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_37.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_37.snap deleted file mode 100644 index 1f9f81396b9..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_37.snap +++ /dev/null @@ -1,218 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 37 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_38.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_38.snap deleted file mode 100644 index 7ea12e6d491..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_38.snap +++ /dev/null @@ -1,233 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 38 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_39.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_39.snap deleted file mode 100644 index 1f97738ecd1..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_39.snap +++ /dev/null @@ -1,233 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 39 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_4.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_4.snap deleted file mode 100644 index 5a3c10d77c7..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_4.snap +++ /dev/null @@ -1,166 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 4 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 3 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_40.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_40.snap deleted file mode 100644 index 545c4fc98c3..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_40.snap +++ /dev/null @@ -1,233 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 40 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_41.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_41.snap deleted file mode 100644 index d599dcc4740..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_41.snap +++ /dev/null @@ -1,264 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 41 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true - enable_group_ops_native_functions: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -group_ops_bls12381_decode_scalar_cost: 52 -group_ops_bls12381_decode_g1_cost: 52 -group_ops_bls12381_decode_g2_cost: 52 -group_ops_bls12381_decode_gt_cost: 52 -group_ops_bls12381_scalar_add_cost: 52 -group_ops_bls12381_g1_add_cost: 52 -group_ops_bls12381_g2_add_cost: 52 -group_ops_bls12381_gt_add_cost: 52 -group_ops_bls12381_scalar_sub_cost: 52 -group_ops_bls12381_g1_sub_cost: 52 -group_ops_bls12381_g2_sub_cost: 52 -group_ops_bls12381_gt_sub_cost: 52 -group_ops_bls12381_scalar_mul_cost: 52 -group_ops_bls12381_g1_mul_cost: 52 -group_ops_bls12381_g2_mul_cost: 52 -group_ops_bls12381_gt_mul_cost: 52 -group_ops_bls12381_scalar_div_cost: 52 -group_ops_bls12381_g1_div_cost: 52 -group_ops_bls12381_g2_div_cost: 52 -group_ops_bls12381_gt_div_cost: 52 -group_ops_bls12381_g1_hash_to_base_cost: 52 -group_ops_bls12381_g2_hash_to_base_cost: 52 -group_ops_bls12381_g1_hash_to_cost_per_byte: 2 -group_ops_bls12381_g2_hash_to_cost_per_byte: 2 -group_ops_bls12381_g1_msm_base_cost: 52 -group_ops_bls12381_g2_msm_base_cost: 52 -group_ops_bls12381_g1_msm_base_cost_per_input: 52 -group_ops_bls12381_g2_msm_base_cost_per_input: 52 -group_ops_bls12381_msm_max_len: 32 -group_ops_bls12381_pairing_cost: 52 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_42.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_42.snap deleted file mode 100644 index 003146a845d..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_42.snap +++ /dev/null @@ -1,264 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 42 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_coin_deny_list: true - enable_group_ops_native_functions: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -group_ops_bls12381_decode_scalar_cost: 52 -group_ops_bls12381_decode_g1_cost: 52 -group_ops_bls12381_decode_g2_cost: 52 -group_ops_bls12381_decode_gt_cost: 52 -group_ops_bls12381_scalar_add_cost: 52 -group_ops_bls12381_g1_add_cost: 52 -group_ops_bls12381_g2_add_cost: 52 -group_ops_bls12381_gt_add_cost: 52 -group_ops_bls12381_scalar_sub_cost: 52 -group_ops_bls12381_g1_sub_cost: 52 -group_ops_bls12381_g2_sub_cost: 52 -group_ops_bls12381_gt_sub_cost: 52 -group_ops_bls12381_scalar_mul_cost: 52 -group_ops_bls12381_g1_mul_cost: 52 -group_ops_bls12381_g2_mul_cost: 52 -group_ops_bls12381_gt_mul_cost: 52 -group_ops_bls12381_scalar_div_cost: 52 -group_ops_bls12381_g1_div_cost: 52 -group_ops_bls12381_g2_div_cost: 52 -group_ops_bls12381_gt_div_cost: 52 -group_ops_bls12381_g1_hash_to_base_cost: 52 -group_ops_bls12381_g2_hash_to_base_cost: 52 -group_ops_bls12381_g1_hash_to_cost_per_byte: 2 -group_ops_bls12381_g2_hash_to_cost_per_byte: 2 -group_ops_bls12381_g1_msm_base_cost: 52 -group_ops_bls12381_g2_msm_base_cost: 52 -group_ops_bls12381_g1_msm_base_cost_per_input: 52 -group_ops_bls12381_g2_msm_base_cost_per_input: 52 -group_ops_bls12381_msm_max_len: 32 -group_ops_bls12381_pairing_cost: 52 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_5.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_5.snap deleted file mode 100644 index c7ec728a6e9..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_5.snap +++ /dev/null @@ -1,170 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 5 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 4 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_6.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_6.snap deleted file mode 100644 index 2f5e9b84e18..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_6.snap +++ /dev/null @@ -1,171 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 6 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_7.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_7.snap deleted file mode 100644 index f259aef8f8e..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_7.snap +++ /dev/null @@ -1,175 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 7 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - ban_entry_init: true - package_digest_hash_module: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_8.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_8.snap deleted file mode 100644 index 30e47cddfcd..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_8.snap +++ /dev/null @@ -1,176 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 8 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_9.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_9.snap deleted file mode 100644 index ea60c2e2227..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_9.snap +++ /dev/null @@ -1,179 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 9 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_1.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_1.snap deleted file mode 100644 index 2054ea0da22..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_1.snap +++ /dev/null @@ -1,161 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 1 -feature_flags: {} -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 10000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 110000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 1 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 5000 -storage_gas_price: 1 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_10.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_10.snap deleted file mode 100644 index ca0e669641d..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_10.snap +++ /dev/null @@ -1,179 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 10 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_11.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_11.snap deleted file mode 100644 index b5a47c349db..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_11.snap +++ /dev/null @@ -1,180 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 11 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_12.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_12.snap deleted file mode 100644 index 0193270fabf..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_12.snap +++ /dev/null @@ -1,183 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 12 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_13.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_13.snap deleted file mode 100644 index a6a74337ac5..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_13.snap +++ /dev/null @@ -1,183 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 13 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_14.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_14.snap deleted file mode 100644 index 106ca5bc89b..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_14.snap +++ /dev/null @@ -1,184 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 14 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_15.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_15.snap deleted file mode 100644 index 47e3c1f8b7e..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_15.snap +++ /dev/null @@ -1,185 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 15 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_16.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_16.snap deleted file mode 100644 index fe40b84319a..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_16.snap +++ /dev/null @@ -1,186 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 16 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_17.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_17.snap deleted file mode 100644 index e9ebf0ec1d4..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_17.snap +++ /dev/null @@ -1,187 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 17 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_18.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_18.snap deleted file mode 100644 index 947b490e10b..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_18.snap +++ /dev/null @@ -1,189 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 18 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_19.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_19.snap deleted file mode 100644 index a49d81383fa..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_19.snap +++ /dev/null @@ -1,190 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 19 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_2.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_2.snap deleted file mode 100644 index 84e0d4dcb37..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_2.snap +++ /dev/null @@ -1,162 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 2 -feature_flags: - advance_epoch_start_time_in_safe_mode: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 10000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 110000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 1 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 5000 -storage_gas_price: 1 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_20.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_20.snap deleted file mode 100644 index 1fc62707605..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_20.snap +++ /dev/null @@ -1,192 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 20 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_21.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_21.snap deleted file mode 100644 index 2253b7dfd08..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_21.snap +++ /dev/null @@ -1,196 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 21 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_22.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_22.snap deleted file mode 100644 index 0ce8b51b165..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_22.snap +++ /dev/null @@ -1,197 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 22 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_23.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_23.snap deleted file mode 100644 index 0035c33c9bd..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_23.snap +++ /dev/null @@ -1,198 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 23 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_24.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_24.snap deleted file mode 100644 index d1689a889d2..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_24.snap +++ /dev/null @@ -1,204 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 24 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_25.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_25.snap deleted file mode 100644 index 090964857ec..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_25.snap +++ /dev/null @@ -1,204 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 25 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 6 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_26.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_26.snap deleted file mode 100644 index 0f2f5f7c748..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_26.snap +++ /dev/null @@ -1,206 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 26 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 7 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_27.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_27.snap deleted file mode 100644 index ad0dd73de2c..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_27.snap +++ /dev/null @@ -1,206 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 27 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_28.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_28.snap deleted file mode 100644 index 361d906b89f..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_28.snap +++ /dev/null @@ -1,209 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 28 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_29.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_29.snap deleted file mode 100644 index 32cd1e3bf4b..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_29.snap +++ /dev/null @@ -1,210 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 29 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - zklogin_supported_providers: - - Facebook - - Google - - Twitch - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - verify_legacy_zklogin_address: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_3.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_3.snap deleted file mode 100644 index 909b9cca478..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_3.snap +++ /dev/null @@ -1,166 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 3 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 2 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 5000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_30.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_30.snap deleted file mode 100644 index 8f8427682ba..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_30.snap +++ /dev/null @@ -1,209 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 30 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 1 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_31.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_31.snap deleted file mode 100644 index a866bb9aac4..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_31.snap +++ /dev/null @@ -1,210 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 31 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_32.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_32.snap deleted file mode 100644 index 44f0f044714..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_32.snap +++ /dev/null @@ -1,215 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 32 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - random_beacon: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -random_beacon_reduction_lower_bound: 1600 -random_beacon_dkg_timeout_round: 200 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_33.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_33.snap deleted file mode 100644 index 97b3c9ddc07..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_33.snap +++ /dev/null @@ -1,217 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 33 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - random_beacon: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -random_beacon_reduction_lower_bound: 1600 -random_beacon_dkg_timeout_round: 200 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_34.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_34.snap deleted file mode 100644 index 9103619a2b7..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_34.snap +++ /dev/null @@ -1,217 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 34 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - random_beacon: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -random_beacon_reduction_lower_bound: 1600 -random_beacon_dkg_timeout_round: 200 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_35.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_35.snap deleted file mode 100644 index a40146c221f..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_35.snap +++ /dev/null @@ -1,221 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 35 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - random_beacon: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_poseidon: true - enable_coin_deny_list: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -poseidon_bn254_cost_base: 260 -poseidon_bn254_cost_per_block: 10 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -random_beacon_reduction_lower_bound: 1600 -random_beacon_dkg_timeout_round: 200 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_36.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_36.snap deleted file mode 100644 index c0061c3b1ae..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_36.snap +++ /dev/null @@ -1,255 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 36 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - random_beacon: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_poseidon: true - enable_coin_deny_list: true - enable_group_ops_native_functions: true - enable_group_ops_native_function_msm: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -poseidon_bn254_cost_base: 260 -poseidon_bn254_cost_per_block: 10 -group_ops_bls12381_decode_scalar_cost: 52 -group_ops_bls12381_decode_g1_cost: 52 -group_ops_bls12381_decode_g2_cost: 52 -group_ops_bls12381_decode_gt_cost: 52 -group_ops_bls12381_scalar_add_cost: 52 -group_ops_bls12381_g1_add_cost: 52 -group_ops_bls12381_g2_add_cost: 52 -group_ops_bls12381_gt_add_cost: 52 -group_ops_bls12381_scalar_sub_cost: 52 -group_ops_bls12381_g1_sub_cost: 52 -group_ops_bls12381_g2_sub_cost: 52 -group_ops_bls12381_gt_sub_cost: 52 -group_ops_bls12381_scalar_mul_cost: 52 -group_ops_bls12381_g1_mul_cost: 52 -group_ops_bls12381_g2_mul_cost: 52 -group_ops_bls12381_gt_mul_cost: 52 -group_ops_bls12381_scalar_div_cost: 52 -group_ops_bls12381_g1_div_cost: 52 -group_ops_bls12381_g2_div_cost: 52 -group_ops_bls12381_gt_div_cost: 52 -group_ops_bls12381_g1_hash_to_base_cost: 52 -group_ops_bls12381_g2_hash_to_base_cost: 52 -group_ops_bls12381_g1_hash_to_cost_per_byte: 2 -group_ops_bls12381_g2_hash_to_cost_per_byte: 2 -group_ops_bls12381_g1_msm_base_cost: 52 -group_ops_bls12381_g2_msm_base_cost: 52 -group_ops_bls12381_g1_msm_base_cost_per_input: 52 -group_ops_bls12381_g2_msm_base_cost_per_input: 52 -group_ops_bls12381_msm_max_len: 32 -group_ops_bls12381_pairing_cost: 52 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -random_beacon_reduction_lower_bound: 1600 -random_beacon_dkg_timeout_round: 200 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_37.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_37.snap deleted file mode 100644 index 4d92ffe614a..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_37.snap +++ /dev/null @@ -1,256 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 37 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - random_beacon: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_poseidon: true - enable_coin_deny_list: true - enable_group_ops_native_functions: true - enable_group_ops_native_function_msm: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -poseidon_bn254_cost_base: 260 -poseidon_bn254_cost_per_block: 10 -group_ops_bls12381_decode_scalar_cost: 52 -group_ops_bls12381_decode_g1_cost: 52 -group_ops_bls12381_decode_g2_cost: 52 -group_ops_bls12381_decode_gt_cost: 52 -group_ops_bls12381_scalar_add_cost: 52 -group_ops_bls12381_g1_add_cost: 52 -group_ops_bls12381_g2_add_cost: 52 -group_ops_bls12381_gt_add_cost: 52 -group_ops_bls12381_scalar_sub_cost: 52 -group_ops_bls12381_g1_sub_cost: 52 -group_ops_bls12381_g2_sub_cost: 52 -group_ops_bls12381_gt_sub_cost: 52 -group_ops_bls12381_scalar_mul_cost: 52 -group_ops_bls12381_g1_mul_cost: 52 -group_ops_bls12381_g2_mul_cost: 52 -group_ops_bls12381_gt_mul_cost: 52 -group_ops_bls12381_scalar_div_cost: 52 -group_ops_bls12381_g1_div_cost: 52 -group_ops_bls12381_g2_div_cost: 52 -group_ops_bls12381_gt_div_cost: 52 -group_ops_bls12381_g1_hash_to_base_cost: 52 -group_ops_bls12381_g2_hash_to_base_cost: 52 -group_ops_bls12381_g1_hash_to_cost_per_byte: 2 -group_ops_bls12381_g2_hash_to_cost_per_byte: 2 -group_ops_bls12381_g1_msm_base_cost: 52 -group_ops_bls12381_g2_msm_base_cost: 52 -group_ops_bls12381_g1_msm_base_cost_per_input: 52 -group_ops_bls12381_g2_msm_base_cost_per_input: 52 -group_ops_bls12381_msm_max_len: 32 -group_ops_bls12381_pairing_cost: 52 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 2 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -random_beacon_reduction_lower_bound: 1600 -random_beacon_dkg_timeout_round: 200 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_38.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_38.snap deleted file mode 100644 index 0f755b39d73..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_38.snap +++ /dev/null @@ -1,271 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 38 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - random_beacon: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_poseidon: true - enable_coin_deny_list: true - enable_group_ops_native_functions: true - enable_group_ops_native_function_msm: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -poseidon_bn254_cost_base: 260 -poseidon_bn254_cost_per_block: 10 -group_ops_bls12381_decode_scalar_cost: 52 -group_ops_bls12381_decode_g1_cost: 52 -group_ops_bls12381_decode_g2_cost: 52 -group_ops_bls12381_decode_gt_cost: 52 -group_ops_bls12381_scalar_add_cost: 52 -group_ops_bls12381_g1_add_cost: 52 -group_ops_bls12381_g2_add_cost: 52 -group_ops_bls12381_gt_add_cost: 52 -group_ops_bls12381_scalar_sub_cost: 52 -group_ops_bls12381_g1_sub_cost: 52 -group_ops_bls12381_g2_sub_cost: 52 -group_ops_bls12381_gt_sub_cost: 52 -group_ops_bls12381_scalar_mul_cost: 52 -group_ops_bls12381_g1_mul_cost: 52 -group_ops_bls12381_g2_mul_cost: 52 -group_ops_bls12381_gt_mul_cost: 52 -group_ops_bls12381_scalar_div_cost: 52 -group_ops_bls12381_g1_div_cost: 52 -group_ops_bls12381_g2_div_cost: 52 -group_ops_bls12381_gt_div_cost: 52 -group_ops_bls12381_g1_hash_to_base_cost: 52 -group_ops_bls12381_g2_hash_to_base_cost: 52 -group_ops_bls12381_g1_hash_to_cost_per_byte: 2 -group_ops_bls12381_g2_hash_to_cost_per_byte: 2 -group_ops_bls12381_g1_msm_base_cost: 52 -group_ops_bls12381_g2_msm_base_cost: 52 -group_ops_bls12381_g1_msm_base_cost_per_input: 52 -group_ops_bls12381_g2_msm_base_cost_per_input: 52 -group_ops_bls12381_msm_max_len: 32 -group_ops_bls12381_pairing_cost: 52 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -random_beacon_reduction_lower_bound: 1600 -random_beacon_dkg_timeout_round: 200 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_39.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_39.snap deleted file mode 100644 index 778835cb614..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_39.snap +++ /dev/null @@ -1,271 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 39 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - random_beacon: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_poseidon: true - enable_coin_deny_list: true - enable_group_ops_native_functions: true - enable_group_ops_native_function_msm: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -poseidon_bn254_cost_base: 260 -poseidon_bn254_cost_per_block: 10 -group_ops_bls12381_decode_scalar_cost: 52 -group_ops_bls12381_decode_g1_cost: 52 -group_ops_bls12381_decode_g2_cost: 52 -group_ops_bls12381_decode_gt_cost: 52 -group_ops_bls12381_scalar_add_cost: 52 -group_ops_bls12381_g1_add_cost: 52 -group_ops_bls12381_g2_add_cost: 52 -group_ops_bls12381_gt_add_cost: 52 -group_ops_bls12381_scalar_sub_cost: 52 -group_ops_bls12381_g1_sub_cost: 52 -group_ops_bls12381_g2_sub_cost: 52 -group_ops_bls12381_gt_sub_cost: 52 -group_ops_bls12381_scalar_mul_cost: 52 -group_ops_bls12381_g1_mul_cost: 52 -group_ops_bls12381_g2_mul_cost: 52 -group_ops_bls12381_gt_mul_cost: 52 -group_ops_bls12381_scalar_div_cost: 52 -group_ops_bls12381_g1_div_cost: 52 -group_ops_bls12381_g2_div_cost: 52 -group_ops_bls12381_gt_div_cost: 52 -group_ops_bls12381_g1_hash_to_base_cost: 52 -group_ops_bls12381_g2_hash_to_base_cost: 52 -group_ops_bls12381_g1_hash_to_cost_per_byte: 2 -group_ops_bls12381_g2_hash_to_cost_per_byte: 2 -group_ops_bls12381_g1_msm_base_cost: 52 -group_ops_bls12381_g2_msm_base_cost: 52 -group_ops_bls12381_g1_msm_base_cost_per_input: 52 -group_ops_bls12381_g2_msm_base_cost_per_input: 52 -group_ops_bls12381_msm_max_len: 32 -group_ops_bls12381_pairing_cost: 52 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -random_beacon_reduction_lower_bound: 1600 -random_beacon_dkg_timeout_round: 200 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_4.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_4.snap deleted file mode 100644 index 5a3c10d77c7..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_4.snap +++ /dev/null @@ -1,166 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 4 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 3 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_40.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_40.snap deleted file mode 100644 index e21cf796168..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_40.snap +++ /dev/null @@ -1,271 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 40 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - random_beacon: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_poseidon: true - enable_coin_deny_list: true - enable_group_ops_native_functions: true - enable_group_ops_native_function_msm: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -poseidon_bn254_cost_base: 260 -poseidon_bn254_cost_per_block: 10 -group_ops_bls12381_decode_scalar_cost: 52 -group_ops_bls12381_decode_g1_cost: 52 -group_ops_bls12381_decode_g2_cost: 52 -group_ops_bls12381_decode_gt_cost: 52 -group_ops_bls12381_scalar_add_cost: 52 -group_ops_bls12381_g1_add_cost: 52 -group_ops_bls12381_g2_add_cost: 52 -group_ops_bls12381_gt_add_cost: 52 -group_ops_bls12381_scalar_sub_cost: 52 -group_ops_bls12381_g1_sub_cost: 52 -group_ops_bls12381_g2_sub_cost: 52 -group_ops_bls12381_gt_sub_cost: 52 -group_ops_bls12381_scalar_mul_cost: 52 -group_ops_bls12381_g1_mul_cost: 52 -group_ops_bls12381_g2_mul_cost: 52 -group_ops_bls12381_gt_mul_cost: 52 -group_ops_bls12381_scalar_div_cost: 52 -group_ops_bls12381_g1_div_cost: 52 -group_ops_bls12381_g2_div_cost: 52 -group_ops_bls12381_gt_div_cost: 52 -group_ops_bls12381_g1_hash_to_base_cost: 52 -group_ops_bls12381_g2_hash_to_base_cost: 52 -group_ops_bls12381_g1_hash_to_cost_per_byte: 2 -group_ops_bls12381_g2_hash_to_cost_per_byte: 2 -group_ops_bls12381_g1_msm_base_cost: 52 -group_ops_bls12381_g2_msm_base_cost: 52 -group_ops_bls12381_g1_msm_base_cost_per_input: 52 -group_ops_bls12381_g2_msm_base_cost_per_input: 52 -group_ops_bls12381_msm_max_len: 32 -group_ops_bls12381_pairing_cost: 52 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -random_beacon_reduction_lower_bound: 1600 -random_beacon_dkg_timeout_round: 200 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_41.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_41.snap deleted file mode 100644 index 9e9587bd8ec..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_41.snap +++ /dev/null @@ -1,271 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 41 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - random_beacon: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_poseidon: true - enable_coin_deny_list: true - enable_group_ops_native_functions: true - enable_group_ops_native_function_msm: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -poseidon_bn254_cost_base: 260 -poseidon_bn254_cost_per_block: 10 -group_ops_bls12381_decode_scalar_cost: 52 -group_ops_bls12381_decode_g1_cost: 52 -group_ops_bls12381_decode_g2_cost: 52 -group_ops_bls12381_decode_gt_cost: 52 -group_ops_bls12381_scalar_add_cost: 52 -group_ops_bls12381_g1_add_cost: 52 -group_ops_bls12381_g2_add_cost: 52 -group_ops_bls12381_gt_add_cost: 52 -group_ops_bls12381_scalar_sub_cost: 52 -group_ops_bls12381_g1_sub_cost: 52 -group_ops_bls12381_g2_sub_cost: 52 -group_ops_bls12381_gt_sub_cost: 52 -group_ops_bls12381_scalar_mul_cost: 52 -group_ops_bls12381_g1_mul_cost: 52 -group_ops_bls12381_g2_mul_cost: 52 -group_ops_bls12381_gt_mul_cost: 52 -group_ops_bls12381_scalar_div_cost: 52 -group_ops_bls12381_g1_div_cost: 52 -group_ops_bls12381_g2_div_cost: 52 -group_ops_bls12381_gt_div_cost: 52 -group_ops_bls12381_g1_hash_to_base_cost: 52 -group_ops_bls12381_g2_hash_to_base_cost: 52 -group_ops_bls12381_g1_hash_to_cost_per_byte: 2 -group_ops_bls12381_g2_hash_to_cost_per_byte: 2 -group_ops_bls12381_g1_msm_base_cost: 52 -group_ops_bls12381_g2_msm_base_cost: 52 -group_ops_bls12381_g1_msm_base_cost_per_input: 52 -group_ops_bls12381_g2_msm_base_cost_per_input: 52 -group_ops_bls12381_msm_max_len: 32 -group_ops_bls12381_pairing_cost: 52 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -random_beacon_reduction_lower_bound: 1600 -random_beacon_dkg_timeout_round: 200 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_42.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_42.snap deleted file mode 100644 index b0ced9f507c..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_42.snap +++ /dev/null @@ -1,271 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 42 -feature_flags: - package_upgrades: true - commit_root_state_digest: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true - narwhal_versioned_metadata: true - zklogin_auth: true - consensus_transaction_ordering: ByGasPrice - simplified_unwrap_then_delete: true - upgraded_multisig_supported: true - txn_base_cost_as_multiplier: true - shared_object_deletion: true - narwhal_new_leader_election_schedule: true - loaded_child_object_format: true - enable_jwk_consensus_updates: true - end_of_epoch_transaction_supported: true - simple_conservation_checks: true - loaded_child_object_format_type: true - receive_objects: true - random_beacon: true - enable_effects_v2: true - narwhal_certificate_v2: true - verify_legacy_zklogin_address: true - recompute_has_public_transfer_in_execution: true - accept_zklogin_in_multisig: true - include_consensus_digest_in_prologue: true - hardened_otw_check: true - allow_receiving_object_id: true - enable_poseidon: true - enable_coin_deny_list: true - enable_group_ops_native_functions: true - enable_group_ops_native_function_msm: true - reject_mutable_random_on_entry_functions: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 64 -max_package_dependencies: 32 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -binary_module_handles: 100 -binary_struct_handles: 300 -binary_function_handles: 1500 -binary_function_instantiations: 750 -binary_signatures: 1000 -binary_constant_pool: 4000 -binary_identifiers: 10000 -binary_address_identifiers: 100 -binary_struct_defs: 200 -binary_struct_def_instantiations: 100 -binary_function_defs: 1000 -binary_field_handles: 500 -binary_field_instantiations: 250 -binary_friend_decls: 100 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_publish_or_upgrade_per_ptb: 5 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -gas_rounding_step: 1000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 1024 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_event_emit_size_total: 65536000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_move_value_depth: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 16000000 -max_meter_ticks_per_module: 16000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 1000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 8 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -transfer_receive_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -poseidon_bn254_cost_base: 260 -poseidon_bn254_cost_per_block: 10 -group_ops_bls12381_decode_scalar_cost: 52 -group_ops_bls12381_decode_g1_cost: 52 -group_ops_bls12381_decode_g2_cost: 52 -group_ops_bls12381_decode_gt_cost: 52 -group_ops_bls12381_scalar_add_cost: 52 -group_ops_bls12381_g1_add_cost: 52 -group_ops_bls12381_g2_add_cost: 52 -group_ops_bls12381_gt_add_cost: 52 -group_ops_bls12381_scalar_sub_cost: 52 -group_ops_bls12381_g1_sub_cost: 52 -group_ops_bls12381_g2_sub_cost: 52 -group_ops_bls12381_gt_sub_cost: 52 -group_ops_bls12381_scalar_mul_cost: 52 -group_ops_bls12381_g1_mul_cost: 52 -group_ops_bls12381_g2_mul_cost: 52 -group_ops_bls12381_gt_mul_cost: 52 -group_ops_bls12381_scalar_div_cost: 52 -group_ops_bls12381_g1_div_cost: 52 -group_ops_bls12381_g2_div_cost: 52 -group_ops_bls12381_gt_div_cost: 52 -group_ops_bls12381_g1_hash_to_base_cost: 52 -group_ops_bls12381_g2_hash_to_base_cost: 52 -group_ops_bls12381_g1_hash_to_cost_per_byte: 2 -group_ops_bls12381_g2_hash_to_cost_per_byte: 2 -group_ops_bls12381_g1_msm_base_cost: 52 -group_ops_bls12381_g2_msm_base_cost: 52 -group_ops_bls12381_g1_msm_base_cost_per_input: 52 -group_ops_bls12381_g2_msm_base_cost_per_input: 52 -group_ops_bls12381_msm_max_len: 32 -group_ops_bls12381_pairing_cost: 52 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -check_zklogin_id_cost_base: 200 -check_zklogin_issuer_cost_base: 200 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 -execution_version: 3 -consensus_bad_nodes_stake_threshold: 20 -max_jwk_votes_per_validator_per_epoch: 240 -max_age_of_jwk_in_epochs: 1 -random_beacon_reduction_allowed_delta: 800 -random_beacon_reduction_lower_bound: 1600 -random_beacon_dkg_timeout_round: 200 -consensus_max_transaction_size_bytes: 262144 -consensus_max_transactions_in_block_bytes: 6291456 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_5.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_5.snap deleted file mode 100644 index c7ec728a6e9..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_5.snap +++ /dev/null @@ -1,170 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 5 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 4 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 0 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_6.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_6.snap deleted file mode 100644 index 2f5e9b84e18..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_6.snap +++ /dev/null @@ -1,171 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 6 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_7.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_7.snap deleted file mode 100644 index f259aef8f8e..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_7.snap +++ /dev/null @@ -1,175 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 7 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - ban_entry_init: true - package_digest_hash_module: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_8.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_8.snap deleted file mode 100644 index 30e47cddfcd..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_8.snap +++ /dev/null @@ -1,176 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 8 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_9.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_9.snap deleted file mode 100644 index ea60c2e2227..00000000000 --- a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_9.snap +++ /dev/null @@ -1,179 +0,0 @@ ---- -source: crates/sui-protocol-config/src/lib.rs -expression: "ProtocolConfig::get_for_version(cur, *chain_id)" ---- -version: 9 -feature_flags: - package_upgrades: true - advance_epoch_start_time_in_safe_mode: true - loaded_child_objects_fixed: true - missing_type_is_compatibility_error: true - scoring_decision_with_validity_cutoff: true - consensus_order_end_of_epoch_last: true - disallow_adding_abilities_on_upgrade: true - disable_invariant_violation_check_in_swap_loc: true - advance_to_highest_supported_protocol_version: true - ban_entry_init: true - package_digest_hash_module: true - disallow_change_struct_type_params_on_upgrade: true - no_extraneous_module_bytes: true -max_tx_size_bytes: 131072 -max_input_objects: 2048 -max_size_written_objects: 5000000 -max_size_written_objects_system_tx: 50000000 -max_serialized_tx_effects_size_bytes: 524288 -max_serialized_tx_effects_size_bytes_system_tx: 8388608 -max_gas_payment_objects: 256 -max_modules_in_publish: 128 -max_arguments: 512 -max_type_arguments: 16 -max_type_argument_depth: 16 -max_pure_argument_size: 16384 -max_programmable_tx_commands: 1024 -move_binary_format_version: 6 -max_move_object_size: 256000 -max_move_package_size: 102400 -max_tx_gas: 50000000000 -max_gas_price: 100000 -max_gas_computation_bucket: 5000000 -max_loop_depth: 5 -max_generic_instantiation_length: 32 -max_function_parameters: 128 -max_basic_blocks: 1024 -max_value_stack_size: 1024 -max_type_nodes: 256 -max_push_size: 10000 -max_struct_definitions: 200 -max_function_definitions: 1000 -max_fields_in_struct: 32 -max_dependency_depth: 100 -max_num_event_emit: 256 -max_num_new_move_object_ids: 2048 -max_num_new_move_object_ids_system_tx: 32768 -max_num_deleted_move_object_ids: 2048 -max_num_deleted_move_object_ids_system_tx: 32768 -max_num_transferred_move_object_ids: 2048 -max_num_transferred_move_object_ids_system_tx: 32768 -max_event_emit_size: 256000 -max_move_vector_len: 262144 -max_move_identifier_len: 128 -max_back_edges_per_function: 10000 -max_back_edges_per_module: 10000 -max_verifier_meter_ticks_per_function: 6000000 -max_meter_ticks_per_module: 6000000 -object_runtime_max_num_cached_objects: 1000 -object_runtime_max_num_cached_objects_system_tx: 16000 -object_runtime_max_num_store_entries: 1000 -object_runtime_max_num_store_entries_system_tx: 16000 -base_tx_cost_fixed: 2000 -package_publish_cost_fixed: 1000 -base_tx_cost_per_byte: 0 -package_publish_cost_per_byte: 80 -obj_access_cost_read_per_byte: 15 -obj_access_cost_mutate_per_byte: 40 -obj_access_cost_delete_per_byte: 40 -obj_access_cost_verify_per_byte: 200 -gas_model_version: 5 -obj_data_cost_refundable: 100 -obj_metadata_cost_non_refundable: 50 -storage_rebate_rate: 9900 -storage_fund_reinvest_rate: 500 -reward_slashing_rate: 10000 -storage_gas_price: 76 -max_transactions_per_checkpoint: 10000 -max_checkpoint_size_bytes: 31457280 -buffer_stake_for_protocol_upgrade_bps: 5000 -address_from_bytes_cost_base: 52 -address_to_u256_cost_base: 52 -address_from_u256_cost_base: 52 -dynamic_field_hash_type_and_key_cost_base: 100 -dynamic_field_hash_type_and_key_type_cost_per_byte: 2 -dynamic_field_hash_type_and_key_value_cost_per_byte: 2 -dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 -dynamic_field_add_child_object_cost_base: 100 -dynamic_field_add_child_object_type_cost_per_byte: 10 -dynamic_field_add_child_object_value_cost_per_byte: 10 -dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 -dynamic_field_borrow_child_object_cost_base: 100 -dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 -dynamic_field_borrow_child_object_type_cost_per_byte: 10 -dynamic_field_remove_child_object_cost_base: 100 -dynamic_field_remove_child_object_child_cost_per_byte: 2 -dynamic_field_remove_child_object_type_cost_per_byte: 2 -dynamic_field_has_child_object_cost_base: 100 -dynamic_field_has_child_object_with_ty_cost_base: 100 -dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 -dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 -event_emit_cost_base: 52 -event_emit_value_size_derivation_cost_per_byte: 2 -event_emit_tag_size_derivation_cost_per_byte: 5 -event_emit_output_cost_per_byte: 10 -object_borrow_uid_cost_base: 52 -object_delete_impl_cost_base: 52 -object_record_new_uid_cost_base: 52 -transfer_transfer_internal_cost_base: 52 -transfer_freeze_object_cost_base: 52 -transfer_share_object_cost_base: 52 -tx_context_derive_id_cost_base: 52 -types_is_one_time_witness_cost_base: 52 -types_is_one_time_witness_type_tag_cost_per_byte: 2 -types_is_one_time_witness_type_cost_per_byte: 2 -validator_validate_metadata_cost_base: 52 -validator_validate_metadata_data_cost_per_byte: 2 -crypto_invalid_arguments_cost: 100 -bls12381_bls12381_min_sig_verify_cost_base: 52 -bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 -bls12381_bls12381_min_pk_verify_cost_base: 52 -bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 -bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_keccak256_cost_base: 52 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_k1_ecrecover_sha256_cost_base: 52 -ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_k1_decompress_pubkey_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_keccak256_cost_base: 52 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 -ecdsa_r1_ecrecover_sha256_cost_base: 52 -ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 -ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 -ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 -ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 -ecvrf_ecvrf_verify_cost_base: 52 -ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 -ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 -ed25519_ed25519_verify_cost_base: 52 -ed25519_ed25519_verify_msg_cost_per_byte: 2 -ed25519_ed25519_verify_msg_cost_per_block: 2 -groth16_prepare_verifying_key_bls12381_cost_base: 52 -groth16_prepare_verifying_key_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 -groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_bn254_cost_base: 52 -groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 -groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 -hash_blake2b256_cost_base: 52 -hash_blake2b256_data_cost_per_byte: 2 -hash_blake2b256_data_cost_per_block: 2 -hash_keccak256_cost_base: 52 -hash_keccak256_data_cost_per_byte: 2 -hash_keccak256_data_cost_per_block: 2 -hmac_hmac_sha3_256_cost_base: 52 -hmac_hmac_sha3_256_input_cost_per_byte: 2 -hmac_hmac_sha3_256_input_cost_per_block: 2 -scoring_decision_mad_divisor: 2.3 -scoring_decision_cutoff_value: 2.5 - diff --git a/crates/sui-proxy/Cargo.toml b/crates/sui-proxy/Cargo.toml deleted file mode 100644 index acacf0d1bae..00000000000 --- a/crates/sui-proxy/Cargo.toml +++ /dev/null @@ -1,56 +0,0 @@ -[package] -name = "sui-proxy" -version = "0.0.2" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -axum.workspace = true -axum-server.workspace = true -anyhow.workspace = true -bytes.workspace = true -clap.workspace = true -protobuf.workspace = true -tokio = { workspace = true, features = ["full"] } -tracing.workspace = true -const-str.workspace = true -tower-http.workspace = true -tower.workspace = true -serde.workspace = true -serde_with.workspace = true -serde_json.workspace = true -serde_yaml.workspace = true -git-version.workspace = true -itertools.workspace = true -rand.workspace = true -reqwest.workspace = true -hyper.workspace = true -sui-tls.workspace = true -sui-types.workspace = true -mysten-metrics.workspace = true -multiaddr.workspace = true -prometheus.workspace = true -snap.workspace = true -rustls.workspace = true -rustls-pemfile.workspace = true -prost.workspace = true -once_cell.workspace = true -http-body.workspace = true -hex.workspace = true -ipnetwork.workspace = true - - -telemetry-subscribers.workspace = true -fastcrypto.workspace = true - -[dev-dependencies] -mime.workspace = true -serde_json.workspace = true -tower.workspace = true -axum-server.workspace = true -sui-types = { workspace = true, features = ["test-utils"] } - -[build-dependencies] -prost-build.workspace = true diff --git a/crates/sui-proxy/build.rs b/crates/sui-proxy/build.rs deleted file mode 100644 index 133ea834e5c..00000000000 --- a/crates/sui-proxy/build.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use std::io::Result; -fn main() -> Result<()> { - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-env-changed=BUILD_REMOTE_WRITE"); - - // add this env var to build. you'll need protoc installed locally and a copy of - // the proto files - if option_env!("BUILD_REMOTE_WRITE").is_some() { - prost_build::compile_protos( - &["protobufs/remote.proto", "protobufs/types.proto"], - &["protobufs/"], - )?; - } - Ok(()) -} diff --git a/crates/sui-proxy/src/admin.rs b/crates/sui-proxy/src/admin.rs deleted file mode 100644 index 252ee90d29f..00000000000 --- a/crates/sui-proxy/src/admin.rs +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use std::{ - fs, - io::BufReader, - net::{IpAddr, SocketAddr}, - sync::Arc, - time::Duration, -}; - -use anyhow::{Error, Result}; -use axum::{extract::DefaultBodyLimit, middleware, routing::post, Extension, Router}; -use fastcrypto::{ - ed25519::{Ed25519KeyPair, Ed25519PublicKey}, - traits::{KeyPair, ToFromBytes}, -}; -use sui_tls::{rustls::ServerConfig, AllowAll, CertVerifier, SelfSignedCertificate, TlsAcceptor}; -use tokio::signal; -use tower::ServiceBuilder; -use tower_http::{ - trace::{DefaultOnResponse, TraceLayer}, - LatencyUnit, -}; -use tracing::{error, info, Level}; - -use crate::{ - config::{DynamicPeerValidationConfig, RemoteWriteConfig, StaticPeerValidationConfig}, - handlers::publish_metrics, - histogram_relay::HistogramRelay, - ip::{is_private, to_multiaddr}, - middleware::{expect_content_length, expect_mysten_proxy_header, expect_valid_public_key}, - peers::{SuiNodeProvider, SuiPeer}, - var, -}; - -/// Configure our graceful shutdown scenarios -pub async fn shutdown_signal(h: axum_server::Handle) { - let ctrl_c = async { - signal::ctrl_c() - .await - .expect("failed to install Ctrl+C handler"); - }; - - #[cfg(unix)] - let terminate = async { - signal::unix::signal(signal::unix::SignalKind::terminate()) - .expect("failed to install signal handler") - .recv() - .await; - }; - - #[cfg(not(unix))] - let terminate = std::future::pending::<()>(); - - tokio::select! { - _ = ctrl_c => {}, - _ = terminate => {}, - } - - let grace = 30; - info!( - "signal received, starting graceful shutdown, grace period {} seconds, if needed", - &grace - ); - h.graceful_shutdown(Some(Duration::from_secs(grace))) -} - -/// Reqwest client holds the global client for remote_push api calls -/// it also holds the username and password. The client has an underlying -/// connection pool. See reqwest documentation for details -#[derive(Clone)] -pub struct ReqwestClient { - pub client: reqwest::Client, - pub settings: RemoteWriteConfig, -} - -pub fn make_reqwest_client(settings: RemoteWriteConfig, user_agent: &str) -> ReqwestClient { - ReqwestClient { - client: reqwest::Client::builder() - .user_agent(user_agent) - .pool_max_idle_per_host(settings.pool_max_idle_per_host) - .timeout(Duration::from_secs(var!("MIMIR_CLIENT_TIMEOUT", 30))) - .build() - .expect("cannot create reqwest client"), - settings, - } -} - -// Labels are adhoc labels we will inject per our config -#[derive(Clone)] -pub struct Labels { - pub network: String, - pub inventory_hostname: String, -} - -/// App will configure our routes. This fn is also used to instrument our tests -pub fn app( - labels: Labels, - client: ReqwestClient, - relay: HistogramRelay, - allower: Option, -) -> Router { - // build our application with a route and our sender mpsc - let mut router = Router::new() - .route("/publish/metrics", post(publish_metrics)) - .route_layer(DefaultBodyLimit::max(var!( - "MAX_BODY_SIZE", - 1024 * 1024 * 5 - ))) - .route_layer(middleware::from_fn(expect_mysten_proxy_header)) - .route_layer(middleware::from_fn(expect_content_length)); - if let Some(allower) = allower { - router = router - .route_layer(middleware::from_fn(expect_valid_public_key)) - .layer(Extension(Arc::new(allower))); - } - router - .layer(Extension(relay)) - .layer(Extension(labels)) - .layer(Extension(client)) - .layer( - ServiceBuilder::new().layer( - TraceLayer::new_for_http().on_response( - DefaultOnResponse::new() - .level(Level::INFO) - .latency_unit(LatencyUnit::Seconds), - ), - ), - ) -} - -/// Server creates our http/https server -pub async fn server( - listener: std::net::TcpListener, - app: Router, - acceptor: Option, -) -> std::io::Result<()> { - // setup our graceful shutdown - let handle = axum_server::Handle::new(); - // Spawn a task to gracefully shutdown server. - tokio::spawn(shutdown_signal(handle.clone())); - - if let Some(verify_peers) = acceptor { - axum_server::Server::from_tcp(listener) - .acceptor(verify_peers) - .handle(handle) - .serve(app.into_make_service_with_connect_info::()) - .await - } else { - axum_server::Server::from_tcp(listener) - .handle(handle) - .serve(app.into_make_service_with_connect_info::()) - .await - } -} - -/// CertKeyPair wraps a self signed certificate and the corresponding public key -pub struct CertKeyPair(pub SelfSignedCertificate, pub Ed25519PublicKey); - -/// Generate server certs for use with peer verification -pub fn generate_self_cert(hostname: String) -> CertKeyPair { - let mut rng = rand::thread_rng(); - let keypair = Ed25519KeyPair::generate(&mut rng); - CertKeyPair( - SelfSignedCertificate::new(keypair.copy().private(), &hostname), - keypair.public().to_owned(), - ) -} - -/// Load a certificate for use by the listening service -fn load_certs(filename: &str) -> Vec { - let certfile = fs::File::open(filename) - .unwrap_or_else(|e| panic!("cannot open certificate file: {}; {}", filename, e)); - let mut reader = BufReader::new(certfile); - rustls_pemfile::certs(&mut reader) - .unwrap() - .iter() - .map(|v| rustls::Certificate(v.clone())) - .collect() -} - -/// Load a private key -fn load_private_key(filename: &str) -> rustls::PrivateKey { - let keyfile = fs::File::open(filename) - .unwrap_or_else(|e| panic!("cannot open private key file {}; {}", filename, e)); - let mut reader = BufReader::new(keyfile); - - loop { - match rustls_pemfile::read_one(&mut reader).expect("cannot parse private key .pem file") { - Some(rustls_pemfile::Item::RSAKey(key)) => return rustls::PrivateKey(key), - Some(rustls_pemfile::Item::PKCS8Key(key)) => return rustls::PrivateKey(key), - Some(rustls_pemfile::Item::ECKey(key)) => return rustls::PrivateKey(key), - None => break, - _ => {} - } - } - - panic!( - "no keys found in {:?} (encrypted keys not supported)", - filename - ); -} - -/// load the static keys we'll use to allow external non-validator nodes to push -/// metrics -fn load_static_peers( - static_peers: Option, -) -> Result, Error> { - let Some(static_peers) = static_peers else { - return Ok(vec![]); - }; - let static_keys = static_peers.pub_keys.into_iter().filter_map(|spk|{ - let p2p_address: IpAddr = spk.p2p_address.parse().unwrap(); - if is_private(p2p_address) { - error!("{} appears to be a private address. We only allow 169.254.0.0/16 addresses to be private; ignoring this entry", p2p_address); - dbg!("skipping {}", spk); - return None; - } - Some(spk) - }).map(|spk|{ - let peer_id = hex::decode(spk.peer_id).unwrap(); - let public_key = Ed25519PublicKey::from_bytes(peer_id.as_ref()).unwrap(); - let p2p_address: IpAddr = spk.p2p_address.parse().unwrap(); - let s = SuiPeer{ - name:spk.name.clone(), - p2p_address: to_multiaddr(p2p_address), - public_key, - }; - info!("loaded static peer: {} public key: {} p2p address: {}", &s.name, &s.public_key, &s.p2p_address); - s - }).collect(); - Ok(static_keys) -} - -/// Default allow mode for server, we don't verify clients, everything is -/// accepted -pub fn create_server_cert_default_allow( - hostname: String, -) -> Result { - let CertKeyPair(server_certificate, _) = generate_self_cert(hostname); - - CertVerifier::new(AllowAll).rustls_server_config( - vec![server_certificate.rustls_certificate()], - server_certificate.rustls_private_key(), - ) -} - -/// Verify clients against sui blockchain, clients that are not found in -/// sui_getValidators will be rejected -pub fn create_server_cert_enforce_peer( - dynamic_peers: DynamicPeerValidationConfig, - static_peers: Option, -) -> Result<(ServerConfig, Option), sui_tls::rustls::Error> { - let (Some(certificate_path), Some(private_key_path)) = - (dynamic_peers.certificate_file, dynamic_peers.private_key) - else { - return Err(sui_tls::rustls::Error::General( - "missing certs to initialize server".into(), - )); - }; - let static_peers = load_static_peers(static_peers).map_err(|e| { - sui_tls::rustls::Error::General(format!("unable to load static pub keys: {}", e)) - })?; - let allower = SuiNodeProvider::new(dynamic_peers.url, dynamic_peers.interval, static_peers); - allower.poll_peer_list(); - let c = CertVerifier::new(allower.clone()).rustls_server_config( - load_certs(&certificate_path), - load_private_key(&private_key_path), - )?; - Ok((c, Some(allower))) -} diff --git a/crates/sui-proxy/src/config.rs b/crates/sui-proxy/src/config.rs deleted file mode 100644 index ef129c886b6..00000000000 --- a/crates/sui-proxy/src/config.rs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use core::time::Duration; -use std::net::SocketAddr; - -use anyhow::{Context, Result}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use serde_with::{serde_as, DurationSeconds}; -use tracing::debug; - -#[serde_as] -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct ProxyConfig { - pub network: String, - pub listen_address: SocketAddr, - pub remote_write: RemoteWriteConfig, - pub dynamic_peers: DynamicPeerValidationConfig, - pub static_peers: Option, - pub metrics_address: String, - pub histogram_address: String, -} - -#[serde_as] -#[derive(Clone, Debug, Deserialize, Serialize, Default)] -#[serde(rename_all = "kebab-case")] -pub struct RemoteWriteConfig { - // TODO upgrade to https - /// the remote_write url to post data to - #[serde(default = "remote_write_url")] - pub url: String, - /// username is used for posting data to the remote_write api - pub username: String, - pub password: String, - - /// Sets the maximum idle connection per host allowed in the pool. - /// - #[serde(default = "pool_max_idle_per_host_default")] - pub pool_max_idle_per_host: usize, -} - -/// DynamicPeerValidationConfig controls what sui-node binaries that are -/// functioning as a validator that we'll speak with. Peer in this case is peers -/// within the consensus committee, for each epoch. This membership is -/// determined dynamically for each epoch via json-rpc calls to a full node. -#[serde_as] -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct DynamicPeerValidationConfig { - /// url is the json-rpc url we use to obtain valid peers on the blockchain - pub url: String, - #[serde_as(as = "DurationSeconds")] - pub interval: Duration, - /// if certificate_file and private_key are not provided, we'll create a - /// self-signed cert using this hostname - #[serde(default = "hostname_default")] - pub hostname: Option, - - /// incoming client connections to this proxy will be presented with this - /// pub key please use an absolute path - pub certificate_file: Option, - /// private key for tls - /// please use an absolute path - pub private_key: Option, -} - -/// StaticPeerValidationConfig, unlike the DynamicPeerValidationConfig, is not -/// determined dynamically from rpc calls. It instead searches a local -/// directory for pub keys that we will add to an allow list. -#[serde_as] -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct StaticPeerValidationConfig { - pub pub_keys: Vec, -} - -/// StaticPubKey holds a human friendly name, ip and the key file for the pub -/// key if you don't have a valid public routable ip, use an ip from -/// 169.254.0.0/16. -#[serde_as] -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct StaticPubKey { - /// friendly name we will see in metrics - pub name: String, - /// friendly ip address we may see in metrics - pub p2p_address: String, - /// the peer_id from a node config file (Ed25519 PublicKey) - pub peer_id: String, -} - -/// the default idle worker per host (reqwest to remote write url call) -fn pool_max_idle_per_host_default() -> usize { - 8 -} - -/// the default hostname we will use if not provided -fn hostname_default() -> Option { - Some("localhost".to_string()) -} - -/// the default remote write url -fn remote_write_url() -> String { - "http://metrics-gw.testnet.sui.io/api/v1/push".to_string() -} - -/// load our config file from a path -pub fn load, T: DeserializeOwned + Serialize>(path: P) -> Result { - let path = path.as_ref(); - debug!("Reading config from {:?}", path); - Ok(serde_yaml::from_reader( - std::fs::File::open(path).context(format!("cannot open {:?}", path))?, - )?) -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn config_load() { - const TEMPLATE: &str = include_str!("./data/config.yaml"); - - let _template: ProxyConfig = serde_yaml::from_str(TEMPLATE).unwrap(); - } -} diff --git a/crates/sui-proxy/src/lib.rs b/crates/sui-proxy/src/lib.rs deleted file mode 100644 index a9da073c68b..00000000000 --- a/crates/sui-proxy/src/lib.rs +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -pub mod admin; -pub mod config; -pub mod consumer; -pub mod handlers; -pub mod histogram_relay; -mod ip; -pub mod metrics; -pub mod middleware; -pub mod peers; -pub mod prom_to_mimir; -pub mod remote_write; - -/// var extracts environment variables at runtime with a default fallback value -/// if a default is not provided, the value is simply an empty string if not -/// found This function will return the provided default if env::var cannot find -/// the key or if the key is somehow malformed. -#[macro_export] -macro_rules! var { - ($key:expr) => { - match std::env::var($key) { - Ok(val) => val, - Err(_) => "".into(), - } - }; - ($key:expr, $default:expr) => { - match std::env::var($key) { - Ok(val) => val.parse::<_>().unwrap(), - Err(_) => $default, - } - }; -} - -#[cfg(test)] -mod tests { - use std::{net::TcpListener, time::Duration}; - - use axum::{ - http::{header, StatusCode}, - routing::post, - Router, - }; - use multiaddr::Multiaddr; - use prometheus::{Encoder, PROTOBUF_FORMAT}; - use protobuf::RepeatedField; - use sui_tls::{CertVerifier, TlsAcceptor}; - - use super::*; - use crate::{ - admin::{CertKeyPair, Labels}, - config::RemoteWriteConfig, - histogram_relay::HistogramRelay, - peers::SuiNodeProvider, - prom_to_mimir::tests::*, - }; - - async fn run_dummy_remote_write(listener: TcpListener) { - /// i accept everything, send me the trash - async fn handler() -> StatusCode { - StatusCode::OK - } - - // build our application with a route - let app = Router::new().route("/v1/push", post(handler)); - - // run it - axum::Server::from_tcp(listener) - .unwrap() - .serve(app.into_make_service()) - .await - .unwrap(); - } - - /// axum_acceptor is a basic e2e test that creates a mock remote_write post - /// endpoint and has a simple sui-node client that posts data to the - /// proxy using the protobuf format. The server processes this data and - /// sends it to the mock remote_write which accepts everything. Future work - /// is to make this more robust and expand the scope of coverage, - /// probabaly moving this test elsewhere and renaming it. - #[tokio::test] - async fn axum_acceptor() { - // generate self-signed certificates - let CertKeyPair(client_priv_cert, client_pub_key) = admin::generate_self_cert("sui".into()); - let CertKeyPair(server_priv_cert, _) = admin::generate_self_cert("localhost".into()); - - // create a fake rpc server - let dummy_remote_write_listener = std::net::TcpListener::bind("localhost:0").unwrap(); - let dummy_remote_write_address = dummy_remote_write_listener.local_addr().unwrap(); - let dummy_remote_write_url = format!( - "http://localhost:{}/v1/push", - dummy_remote_write_address.port() - ); - - let _dummy_remote_write = - tokio::spawn(async move { run_dummy_remote_write(dummy_remote_write_listener).await }); - - // init the tls config and allower - let mut allower = SuiNodeProvider::new("".into(), Duration::from_secs(30), vec![]); - let tls_config = CertVerifier::new(allower.clone()) - .rustls_server_config( - vec![server_priv_cert.rustls_certificate()], - server_priv_cert.rustls_private_key(), - ) - .unwrap(); - - let client = admin::make_reqwest_client( - RemoteWriteConfig { - url: dummy_remote_write_url.to_owned(), - username: "bar".into(), - password: "foo".into(), - ..Default::default() - }, - "dummy user agent", - ); - - let app = admin::app( - Labels { - network: "unittest-network".into(), - inventory_hostname: "ansible_inventory_name".into(), - }, - client, - HistogramRelay::new(), - Some(allower.clone()), - ); - - let listener = std::net::TcpListener::bind("localhost:0").unwrap(); - let server_address = listener.local_addr().unwrap(); - let server_url = format!( - "https://localhost:{}/publish/metrics", - server_address.port() - ); - - let acceptor = TlsAcceptor::new(tls_config); - let _server = tokio::spawn(async move { - admin::server(listener, app, Some(acceptor)).await.unwrap(); - }); - - // build a client - let client = reqwest::Client::builder() - .add_root_certificate(server_priv_cert.reqwest_certificate()) - .identity(client_priv_cert.reqwest_identity()) - .https_only(true) - .build() - .unwrap(); - - // Client request is rejected because it isn't in the allowlist - client.get(&server_url).send().await.unwrap_err(); - - // Insert the client's public key into the allowlist and verify the request is - // successful - allower.get_mut().write().unwrap().insert( - client_pub_key.to_owned(), - peers::SuiPeer { - name: "some-node".into(), - p2p_address: Multiaddr::empty(), - public_key: client_pub_key.to_owned(), - }, - ); - - let mf = create_metric_family( - "foo_metric", - "some help this is", - None, - RepeatedField::from_vec(vec![create_metric_counter( - RepeatedField::from_vec(create_labels(vec![("some", "label")])), - create_counter(2046.0), - )]), - ); - - let mut buf = vec![]; - let encoder = prometheus::ProtobufEncoder::new(); - encoder.encode(&[mf], &mut buf).unwrap(); - - let res = client - .post(&server_url) - .header(header::CONTENT_TYPE, PROTOBUF_FORMAT) - .body(buf) - .send() - .await - .expect("expected a successful post with a self-signed certificate"); - let status = res.status(); - let body = res.text().await.unwrap(); - assert_eq!("created", body); - assert_eq!(status, StatusCode::CREATED); - } -} diff --git a/crates/sui-proxy/src/main.rs b/crates/sui-proxy/src/main.rs deleted file mode 100644 index cfe32e7aa6c..00000000000 --- a/crates/sui-proxy/src/main.rs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use std::env; - -use anyhow::Result; -use clap::Parser; -use sui_proxy::{ - admin::{ - app, create_server_cert_default_allow, create_server_cert_enforce_peer, - make_reqwest_client, server, Labels, - }, - config::{load, ProxyConfig}, - histogram_relay, metrics, -}; -use sui_tls::TlsAcceptor; -use telemetry_subscribers::TelemetryConfig; -use tracing::info; - -// WARNING!!! -// -// Do not move or use similar logic to generate git revision information outside -// of a binary entry point (e.g. main.rs). Placing the below logic into a -// library can result in unessesary builds. -const GIT_REVISION: &str = { - if let Some(revision) = option_env!("GIT_REVISION") { - revision - } else { - git_version::git_version!( - args = ["--always", "--abbrev=12", "--dirty", "--exclude", "*"], - fallback = "DIRTY" - ) - } -}; - -// VERSION mimics what other sui binaries use for the same const -pub const VERSION: &str = const_str::concat!(env!("CARGO_PKG_VERSION"), "-", GIT_REVISION); - -/// user agent we use when posting to mimir -static APP_USER_AGENT: &str = const_str::concat!( - env!("CARGO_PKG_NAME"), - "/", - env!("CARGO_PKG_VERSION"), - "/", - VERSION -); - -#[derive(Parser, Debug)] -#[clap(rename_all = "kebab-case")] -#[clap(name = env!("CARGO_BIN_NAME"))] -#[clap(version = VERSION)] -struct Args { - #[clap( - long, - short, - default_value = "./sui-proxy.yaml", - help = "Specify the config file path to use" - )] - config: String, -} - -#[tokio::main] -async fn main() -> Result<()> { - let (_guard, _handle) = TelemetryConfig::new().init(); - - let args = Args::parse(); - - let config: ProxyConfig = load(args.config)?; - - info!( - "listen on {:?} send to {:?}", - config.listen_address, config.remote_write.url - ); - - let listener = std::net::TcpListener::bind(config.listen_address).unwrap(); - - let (tls_config, allower) = - // we'll only use the dynamic peers in some cases - it makes little sense to run with the statics - // since this first mode allows all. - if config.dynamic_peers.certificate_file.is_none() || config.dynamic_peers.private_key.is_none() { - ( - create_server_cert_default_allow(config.dynamic_peers.hostname.unwrap()) - .expect("unable to create self-signed server cert"), - None, - ) - } else { - create_server_cert_enforce_peer(config.dynamic_peers, config.static_peers) - .expect("unable to create tls server config") - }; - let histogram_listener = std::net::TcpListener::bind(config.histogram_address).unwrap(); - let metrics_listener = std::net::TcpListener::bind(config.metrics_address).unwrap(); - let acceptor = TlsAcceptor::new(tls_config); - let client = make_reqwest_client(config.remote_write, APP_USER_AGENT); - let histogram_relay = histogram_relay::start_prometheus_server(histogram_listener); - let registry_service = metrics::start_prometheus_server(metrics_listener); - let prometheus_registry = registry_service.default_registry(); - prometheus_registry - .register(mysten_metrics::uptime_metric( - "sui-proxy", - VERSION, - "unavailable", - )) - .unwrap(); - let app = app( - Labels { - network: config.network, - inventory_hostname: env::var("INVENTORY_HOSTNAME") - .expect("INVENTORY_HOSTNAME not found in environment"), - }, - client, - histogram_relay, - allower, - ); - - server(listener, app, Some(acceptor)).await.unwrap(); - - Ok(()) -} diff --git a/crates/sui-proxy/src/metrics.rs b/crates/sui-proxy/src/metrics.rs deleted file mode 100644 index 9f2b65f7d7c..00000000000 --- a/crates/sui-proxy/src/metrics.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use std::net::TcpListener; - -use axum::{extract::Extension, http::StatusCode, routing::get, Router}; -use mysten_metrics::RegistryService; -use prometheus::{Registry, TextEncoder}; -use tower::ServiceBuilder; -use tower_http::{ - trace::{DefaultOnResponse, TraceLayer}, - LatencyUnit, -}; -use tracing::Level; - -const METRICS_ROUTE: &str = "/metrics"; - -// Creates a new http server that has as a sole purpose to expose -// and endpoint that prometheus agent can use to poll for the metrics. -// A RegistryService is returned that can be used to get access in prometheus -// Registries. -pub fn start_prometheus_server(addr: TcpListener) -> RegistryService { - let registry = Registry::new(); - - let registry_service = RegistryService::new(registry); - - let app = Router::new() - .route(METRICS_ROUTE, get(metrics)) - .layer(Extension(registry_service.clone())) - .layer( - ServiceBuilder::new().layer( - TraceLayer::new_for_http().on_response( - DefaultOnResponse::new() - .level(Level::INFO) - .latency_unit(LatencyUnit::Seconds), - ), - ), - ); - - tokio::spawn(async move { - axum::Server::from_tcp(addr) - .unwrap() - .serve(app.into_make_service()) - .await - .unwrap(); - }); - - registry_service -} - -// DO NOT remove this handler, it is not compatible with the -// mysten_metrics::metric equivalent -async fn metrics(Extension(registry_service): Extension) -> (StatusCode, String) { - let mut metric_families = registry_service.gather_all(); - metric_families.extend(prometheus::gather()); - match TextEncoder.encode_to_string(&metric_families) { - Ok(metrics) => (StatusCode::OK, metrics), - Err(error) => ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("unable to encode metrics: {error}"), - ), - } -} diff --git a/crates/sui-replay/Cargo.toml b/crates/sui-replay/Cargo.toml deleted file mode 100644 index 8a5cfc3c414..00000000000 --- a/crates/sui-replay/Cargo.toml +++ /dev/null @@ -1,50 +0,0 @@ -[package] -name = "sui-replay" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -bcs.workspace = true -prometheus.workspace = true -async-trait.workspace = true -jsonrpsee.workspace = true -async-recursion.workspace = true -clap = { version = "4.1.4", features = ["derive"] } -futures.workspace = true -serde.workspace = true -serde_json.workspace = true -similar.workspace = true -thiserror.workspace = true -tracing.workspace = true -rand.workspace = true -lru.workspace = true -parking_lot.workspace = true -serde_with.workspace = true -serde_yaml.workspace = true -shellexpand.workspace = true -tempfile.workspace = true -http.workspace = true - -move-vm-config.workspace = true -move-binary-format.workspace = true -move-bytecode-utils.workspace = true -move-core-types.workspace = true -tokio.workspace = true -tabled.workspace = true - -shared-crypto.workspace = true -sui-config.workspace = true -sui-core.workspace = true -sui-execution.workspace = true -sui-framework.workspace = true -sui-json-rpc.workspace = true -sui-json-rpc-api.workspace = true -sui-json-rpc-types.workspace = true -sui-protocol-config.workspace = true -sui-sdk.workspace = true -sui-storage.workspace = true -sui-types.workspace = true diff --git a/crates/sui-replay/src/config.rs b/crates/sui-replay/src/config.rs deleted file mode 100644 index be1d9d0aa1b..00000000000 --- a/crates/sui-replay/src/config.rs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr}; - -use http::Uri; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use tracing::log::warn; - -use crate::types::ReplayEngineError; - -pub const DEFAULT_CONFIG_PATH: &str = "~/.sui-replay/network-config.yaml"; - -#[serde_as] -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] -#[serde(rename_all = "kebab-case")] -pub struct ReplayableNetworkConfigSet { - #[serde(skip)] - path: Option, - #[serde(default)] - pub base_network_configs: Vec, -} - -#[serde_as] -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] -#[serde(rename_all = "kebab-case")] -pub struct ReplayableNetworkBaseConfig { - #[serde(default)] - pub name: String, - #[serde(default)] - pub epoch_zero_start_timestamp: u64, - #[serde(default)] - pub epoch_zero_rgp: u64, - #[serde(default = "default_full_node_address")] - pub public_full_node: String, -} - -impl ReplayableNetworkConfigSet { - pub fn load_config(override_path: Option) -> Result { - let path = override_path.unwrap_or_else(|| { - warn!( - "No network config path specified, using default path: {}", - DEFAULT_CONFIG_PATH - ); - DEFAULT_CONFIG_PATH.to_string() - }); - let path = shellexpand::tilde(&path).to_string(); - let path = PathBuf::from_str(&path).unwrap(); - ReplayableNetworkConfigSet::from_file(path.clone()).map_err(|err| { - ReplayEngineError::UnableToOpenYamlFile { - path: path.as_os_str().to_string_lossy().to_string(), - err: err.to_string(), - } - }) - } - - pub fn save_config(&self, override_path: Option) -> Result { - let path = override_path.unwrap_or_else(|| DEFAULT_CONFIG_PATH.to_string()); - let path = shellexpand::tilde(&path).to_string(); - let path = PathBuf::from_str(&path).unwrap(); - self.to_file(path.clone()) - .map_err(|err| ReplayEngineError::UnableToOpenYamlFile { - path: path.as_os_str().to_string_lossy().to_string(), - err: err.to_string(), - })?; - Ok(path) - } - - pub fn from_file(path: PathBuf) -> Result { - let file = - File::open(path.clone()).map_err(|err| ReplayEngineError::UnableToOpenYamlFile { - path: path.as_os_str().to_string_lossy().to_string(), - err: err.to_string(), - })?; - let reader = BufReader::new(file); - let mut config: ReplayableNetworkConfigSet = - serde_yaml::from_reader(reader).map_err(|err| { - ReplayEngineError::UnableToOpenYamlFile { - path: path.as_os_str().to_string_lossy().to_string(), - err: err.to_string(), - } - })?; - config.path = Some(path); - Ok(config) - } - - pub fn to_file(&self, path: PathBuf) -> Result<(), ReplayEngineError> { - let prefix = path.parent().unwrap(); - std::fs::create_dir_all(prefix).unwrap(); - let file = - File::create(path.clone()).map_err(|err| ReplayEngineError::UnableToOpenYamlFile { - path: path.as_os_str().to_string_lossy().to_string(), - err: err.to_string(), - })?; - serde_yaml::to_writer(file, self).map_err(|err| { - ReplayEngineError::UnableToWriteYamlFile { - path: path.as_os_str().to_string_lossy().to_string(), - err: err.to_string(), - } - })?; - Ok(()) - } -} - -impl Default for ReplayableNetworkConfigSet { - fn default() -> Self { - let testnet = ReplayableNetworkBaseConfig { - name: "testnet".to_string(), - epoch_zero_start_timestamp: 0, - epoch_zero_rgp: 0, - public_full_node: url_from_str("https://fullnode.testnet.sui.io:443") - .expect("invalid socket address") - .to_string(), - }; - let devnet = ReplayableNetworkBaseConfig { - name: "devnet".to_string(), - epoch_zero_start_timestamp: 0, - epoch_zero_rgp: 0, - public_full_node: url_from_str("https://fullnode.devnet.sui.io:443") - .expect("invalid socket address") - .to_string(), - }; - let mainnet = ReplayableNetworkBaseConfig { - name: "mainnet".to_string(), - epoch_zero_start_timestamp: 0, - epoch_zero_rgp: 0, - public_full_node: url_from_str("https://fullnode.mainnet.sui.io:443") - .expect("invalid socket address") - .to_string(), - }; - - Self { - path: None, - base_network_configs: vec![testnet, devnet, mainnet], - } - } -} - -pub fn default_full_node_address() -> String { - // Assume local node - "0.0.0.0:9000".to_string() -} - -pub fn url_from_str(s: &str) -> Result { - Uri::from_str(s).map_err(|e| ReplayEngineError::InvalidUrl { - err: e.to_string(), - url: s.to_string(), - }) -} - -#[test] -fn test_yaml() { - let mut set = ReplayableNetworkConfigSet::default(); - - let path = tempfile::tempdir().unwrap().path().to_path_buf(); - let path_str = path.to_str().unwrap().to_owned(); - - let final_path = set.save_config(Some(path_str.clone())).unwrap(); - - // Read from file - let data = ReplayableNetworkConfigSet::load_config(Some(path_str)).unwrap(); - set.path = Some(final_path); - assert!(set == data); -} diff --git a/crates/sui-replay/src/displays/gas_status_displays.rs b/crates/sui-replay/src/displays/gas_status_displays.rs deleted file mode 100644 index 3f940742777..00000000000 --- a/crates/sui-replay/src/displays/gas_status_displays.rs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt::{Display, Formatter}; - -use sui_types::{gas::SuiGasStatus, gas_model::gas_v2::SuiGasStatus as GasStatusV2}; -use tabled::{ - builder::Builder as TableBuilder, - settings::{style::HorizontalLine, Style as TableStyle}, -}; - -use crate::displays::Pretty; - -impl<'a> Display for Pretty<'a, SuiGasStatus> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Pretty(sui_gas_status) = self; - match sui_gas_status { - SuiGasStatus::V2(s) => { - display_info(f, s)?; - per_object_storage_table(f, s)?; - } - }; - Ok(()) - } -} - -fn per_object_storage_table(f: &mut Formatter, sui_gas_status: &GasStatusV2) -> std::fmt::Result { - let mut builder = TableBuilder::default(); - builder.push_record(vec!["Object ID", "Bytes", "Old Rebate", "New Rebate"]); - for (object_id, per_obj_storage) in sui_gas_status.per_object_storage() { - builder.push_record(vec![ - object_id.to_string(), - per_obj_storage.new_size.to_string(), - per_obj_storage.storage_rebate.to_string(), - per_obj_storage.storage_cost.to_string(), - ]); - } - let mut table = builder.build(); - - table.with(TableStyle::rounded().horizontals([HorizontalLine::new( - 1, - TableStyle::modern().get_horizontal(), - )])); - write!(f, "\n{}\n", table) -} - -fn display_info(f: &mut Formatter<'_>, sui_gas_status: &GasStatusV2) -> std::fmt::Result { - let mut builder = TableBuilder::default(); - builder.push_record(vec!["Gas Info".to_string()]); - builder.push_record(vec![format!( - "Reference Gas Price: {}", - sui_gas_status.reference_gas_price() - )]); - builder.push_record(vec![format!( - "Gas Price: {}", - sui_gas_status.gas_status.gas_price() - )]); - - builder.push_record(vec![format!( - "Max Gas Stack Height: {}", - sui_gas_status.gas_status.stack_height_high_water_mark() - )]); - - builder.push_record(vec![format!( - "Max Gas Stack Size: {}", - sui_gas_status.gas_status.stack_size_high_water_mark() - )]); - - builder.push_record(vec![format!( - "Number of Bytecode Instructions Executed: {}", - sui_gas_status.gas_status.instructions_executed() - )]); - - let mut table = builder.build(); - table.with(TableStyle::rounded()); - - write!(f, "\n{}\n", table) -} diff --git a/crates/sui-replay/src/displays/mod.rs b/crates/sui-replay/src/displays/mod.rs deleted file mode 100644 index 0caf5b0b2a6..00000000000 --- a/crates/sui-replay/src/displays/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod gas_status_displays; -pub mod transaction_displays; - -pub struct Pretty<'a, T>(pub &'a T); diff --git a/crates/sui-replay/src/displays/transaction_displays.rs b/crates/sui-replay/src/displays/transaction_displays.rs deleted file mode 100644 index dce8b89d7ad..00000000000 --- a/crates/sui-replay/src/displays/transaction_displays.rs +++ /dev/null @@ -1,358 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - fmt::{Display, Formatter}, - sync::Arc, -}; - -use move_core_types::{ - annotated_value::{MoveTypeLayout, MoveValue}, - language_storage::TypeTag, -}; -use sui_execution::Executor; -use sui_types::{ - execution_mode::ExecutionResult, - object::bounded_visitor::BoundedVisitor, - transaction::{ - write_sep, Argument, CallArg, CallArg::Pure, Command, ObjectArg, ProgrammableMoveCall, - ProgrammableTransaction, - }, -}; -use tabled::{ - builder::Builder as TableBuilder, - settings::{style::HorizontalLine, Panel as TablePanel, Style as TableStyle}, -}; - -use crate::{displays::Pretty, replay::LocalExec}; - -pub struct FullPTB { - pub ptb: ProgrammableTransaction, - pub results: Vec, -} - -pub struct ResolvedResults { - pub mutable_reference_outputs: Vec<(Argument, MoveValue)>, - pub return_values: Vec, -} - -/// These Display implementations provide alternate displays that are used to -/// format info contained in these Structs when calling the CLI replay command -/// with an additional provided flag. -impl<'a> Display for Pretty<'a, FullPTB> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Pretty(full_ptb) = self; - let FullPTB { ptb, results } = full_ptb; - - let ProgrammableTransaction { inputs, commands } = ptb; - - // write input objects section - if !inputs.is_empty() { - let mut builder = TableBuilder::default(); - for (i, input) in inputs.iter().enumerate() { - match input { - Pure(v) => { - if v.len() <= 16 { - builder.push_record(vec![format!("{i:<3} Pure Arg {:?}", v)]); - } else { - builder.push_record(vec![format!( - "{i:<3} Pure Arg [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, ...]", - v[0], - v[1], - v[2], - v[3], - v[4], - v[5], - v[6], - v[7], - v[8], - v[9], - v[10], - v[11], - v[12], - v[13], - v[14], - )]); - } - } - - CallArg::Object(ObjectArg::ImmOrOwnedObject(o)) => { - builder.push_record(vec![format!("{i:<3} Imm/Owned Object ID: {}", o.0)]); - } - CallArg::Object(ObjectArg::SharedObject { id, .. }) => { - builder.push_record(vec![format!("{i:<3} Shared Object ID: {}", id)]); - } - CallArg::Object(ObjectArg::Receiving(o)) => { - builder.push_record(vec![format!("{i:<3} Receiving Object ID: {}", o.0)]); - } - }; - } - - let mut table = builder.build(); - table.with(TablePanel::header("Input Objects")); - table.with(TableStyle::rounded().horizontals([HorizontalLine::new( - 1, - TableStyle::modern().get_horizontal(), - )])); - write!(f, "\n{}\n", table)?; - } else { - write!(f, "\n No input objects for this transaction")?; - } - - // write command results section - if !results.is_empty() { - write!(f, "\n\n")?; - } - for (i, result) in results.iter().enumerate() { - if i == results.len() - 1 { - write!( - f, - "╭───────────────────╮\n│ Command {i:<2} Output │\n╰───────────────────╯{}\n\n\n", - Pretty(result) - )? - } else { - write!( - f, - "╭───────────────────╮\n│ Command {i:<2} Output │\n╰───────────────────╯{}\n", - Pretty(result) - )? - } - } - - // write ptb functions section - let mut builder = TableBuilder::default(); - if !commands.is_empty() { - for (i, c) in commands.iter().enumerate() { - if i == commands.len() - 1 { - builder.push_record(vec![format!("{i:<2} {}", Pretty(c))]); - } else { - builder.push_record(vec![format!("{i:<2} {}\n", Pretty(c))]); - } - } - - let mut table = builder.build(); - table.with(TablePanel::header("Commands")); - table.with(TableStyle::rounded().horizontals([HorizontalLine::new( - 1, - TableStyle::modern().get_horizontal(), - )])); - write!(f, "\n{}\n", table)?; - } else { - write!(f, "\n No commands for this transaction")?; - } - - Ok(()) - } -} - -impl<'a> Display for Pretty<'a, Command> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Pretty(command) = self; - match command { - Command::MoveCall(p) => { - write!(f, "{}", Pretty(&**p)) - } - Command::MakeMoveVec(ty_opt, elems) => { - write!(f, "MakeMoveVec:\n ┌")?; - if let Some(ty) = ty_opt { - write!(f, "\n │ Type Tag: {ty}")?; - } - write!(f, "\n │ Arguments:\n │ ")?; - write_sep(f, elems.iter().map(Pretty), "\n │ ")?; - write!(f, "\n └") - } - Command::TransferObjects(objs, addr) => { - write!(f, "TransferObjects:\n ┌\n │ Arguments: \n │ ")?; - write_sep(f, objs.iter().map(Pretty), "\n │ ")?; - write!(f, "\n │ Address: {}\n └", Pretty(addr)) - } - Command::SplitCoins(coin, amounts) => { - write!( - f, - "SplitCoins:\n ┌\n │ Coin: {}\n │ Amounts: \n │ ", - Pretty(coin) - )?; - write_sep(f, amounts.iter().map(Pretty), "\n │ ")?; - write!(f, "\n └") - } - Command::MergeCoins(target, coins) => { - write!( - f, - "MergeCoins:\n ┌\n │ Target: {}\n │ Coins: \n │ ", - Pretty(target) - )?; - write_sep(f, coins.iter().map(Pretty), "\n │ ")?; - write!(f, "\n └") - } - Command::Publish(_bytes, deps) => { - write!(f, "Publish:\n ┌\n │ Dependencies: \n │ ")?; - write_sep(f, deps, "\n │ ")?; - write!(f, "\n └") - } - Command::Upgrade(_bytes, deps, current_package_id, ticket) => { - write!(f, "Upgrade:\n ┌\n │ Dependencies: \n │ ")?; - write_sep(f, deps, "\n │ ")?; - write!(f, "\n │ Current Package ID: {current_package_id}")?; - write!(f, "\n │ Ticket: {}", Pretty(ticket))?; - write!(f, "\n └") - } - } - } -} - -impl<'a> Display for Pretty<'a, ProgrammableMoveCall> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Pretty(move_call) = self; - let ProgrammableMoveCall { - package, - module, - function, - type_arguments, - arguments, - } = move_call; - - write!( - f, - "MoveCall:\n ┌\n │ Function: {} \n │ Module: {}\n │ Package: {}", - function, module, package - )?; - - if !type_arguments.is_empty() { - write!(f, "\n │ Type Arguments: \n │ ")?; - write_sep(f, type_arguments, "\n │ ")?; - } - if !arguments.is_empty() { - write!(f, "\n │ Arguments: \n │ ")?; - write_sep(f, arguments.iter().map(Pretty), "\n │ ")?; - } - - write!(f, "\n └") - } -} - -impl<'a> Display for Pretty<'a, Argument> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Pretty(argument) = self; - - let output = match argument { - Argument::GasCoin => "GasCoin".to_string(), - Argument::Input(i) => format!("Input {}", i), - Argument::Result(i) => format!("Result {}", i), - Argument::NestedResult(j, k) => format!("Result {}: {}", j, k), - }; - write!(f, "{}", output) - } -} -impl<'a> Display for Pretty<'a, ResolvedResults> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Pretty(ResolvedResults { - mutable_reference_outputs, - return_values, - }) = self; - - let len_m_ref = mutable_reference_outputs.len(); - let len_ret_vals = return_values.len(); - - if len_ret_vals > 0 { - write!(f, "\n Return Values:\n ──────────────")?; - } - - for (i, value) in return_values.iter().enumerate() { - write!(f, "\n • Result {i:<2} ")?; - write!(f, "\n{:#}\n", value)?; - } - - if len_m_ref > 0 { - write!( - f, - "\n Mutable Reference Outputs:\n ──────────────────────────" - )?; - } - - for (arg, value) in mutable_reference_outputs { - write!(f, "\n • {} ", arg)?; - write!(f, "\n{:#}\n", value)?; - } - - if len_ret_vals == 0 && len_m_ref == 0 { - write!(f, "\n No return values")?; - } - - Ok(()) - } -} - -impl<'a> Display for Pretty<'a, TypeTag> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Pretty(type_tag) = self; - match type_tag { - TypeTag::Vector(v) => { - write!(f, "Vector of {}", Pretty(&**v)) - } - TypeTag::Struct(s) => { - write!(f, "{}::{}", s.module, s.name) - } - _ => { - write!(f, "{}", type_tag) - } - } - } -} - -fn resolve_to_layout( - type_tag: &TypeTag, - executor: &Arc, - store_factory: &LocalExec, -) -> MoveTypeLayout { - match type_tag { - TypeTag::Vector(inner) => { - MoveTypeLayout::Vector(Box::from(resolve_to_layout(inner, executor, store_factory))) - } - TypeTag::Struct(inner) => { - let mut layout_resolver = executor.type_layout_resolver(Box::new(store_factory)); - MoveTypeLayout::Struct(layout_resolver.get_annotated_layout(inner).unwrap()) - } - TypeTag::Bool => MoveTypeLayout::Bool, - TypeTag::U8 => MoveTypeLayout::U8, - TypeTag::U64 => MoveTypeLayout::U64, - TypeTag::U128 => MoveTypeLayout::U128, - TypeTag::Address => MoveTypeLayout::Address, - TypeTag::Signer => MoveTypeLayout::Signer, - TypeTag::U16 => MoveTypeLayout::U16, - TypeTag::U32 => MoveTypeLayout::U32, - TypeTag::U256 => MoveTypeLayout::U256, - } -} - -fn resolve_value( - bytes: &[u8], - type_tag: &TypeTag, - executor: &Arc, - store_factory: &LocalExec, -) -> anyhow::Result { - let layout = resolve_to_layout(type_tag, executor, store_factory); - BoundedVisitor::deserialize_value(bytes, &layout) -} - -pub fn transform_command_results_to_annotated( - executor: &Arc, - store_factory: &LocalExec, - results: Vec, -) -> anyhow::Result> { - let mut output = Vec::new(); - for (m_refs, return_vals) in results.iter() { - let mut m_refs_out = Vec::new(); - let mut return_vals_out = Vec::new(); - for (arg, bytes, tag) in m_refs { - m_refs_out.push((*arg, resolve_value(bytes, tag, executor, store_factory)?)); - } - for (bytes, tag) in return_vals { - return_vals_out.push(resolve_value(bytes, tag, executor, store_factory)?); - } - output.push(ResolvedResults { - mutable_reference_outputs: m_refs_out, - return_values: return_vals_out, - }); - } - Ok(output) -} diff --git a/crates/sui-replay/src/lib.rs b/crates/sui-replay/src/lib.rs deleted file mode 100644 index 87131a4eee3..00000000000 --- a/crates/sui-replay/src/lib.rs +++ /dev/null @@ -1,605 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{env, io::BufRead, path::PathBuf, str::FromStr}; - -use async_recursion::async_recursion; -use clap::Parser; -use config::ReplayableNetworkConfigSet; -use fuzz::{ReplayFuzzer, ReplayFuzzerConfig}; -use fuzz_mutations::base_fuzzers; -use move_vm_config::runtime::get_default_output_filepath; -use sui_config::node::ExpensiveSafetyCheckConfig; -use sui_protocol_config::Chain; -use sui_types::{ - digests::{get_mainnet_chain_identifier, get_testnet_chain_identifier, TransactionDigest}, - message_envelope::Message, -}; -use tracing::{error, info, warn}; -use transaction_provider::{FuzzStartPoint, TransactionSource}; - -use crate::replay::{ExecutionSandboxState, LocalExec, ProtocolVersionSummary}; -pub mod config; -mod data_fetcher; -mod displays; -pub mod fuzz; -pub mod fuzz_mutations; -mod replay; -pub mod transaction_provider; -pub mod types; - -static DEFAULT_SANDBOX_BASE_PATH: &str = - concat!(env!("CARGO_MANIFEST_DIR"), "/tests/sandbox_snapshots"); - -#[cfg(test)] -mod tests; - -#[derive(Parser, Clone)] -#[command(rename_all = "kebab-case")] -pub enum ReplayToolCommand { - /// Generate a new network config file - #[command(name = "gen")] - GenerateDefaultConfig, - - /// Persist sandbox state - #[command(name = "ps")] - PersistSandbox { - #[arg(long, short)] - tx_digest: String, - #[arg(long, short, default_value = DEFAULT_SANDBOX_BASE_PATH)] - base_path: PathBuf, - }, - - /// Replay from sandbox state file - /// This is a completely local execution - #[command(name = "rs")] - ReplaySandbox { - #[arg(long, short)] - path: PathBuf, - }, - - /// Profile transaction - #[command(name = "rp")] - ProfileTransaction { - #[arg(long, short)] - tx_digest: String, - /// Optional version of the executor to use, if not specified defaults - /// to the one originally used for the transaction. - #[arg(long, short, allow_hyphen_values = true)] - executor_version: Option, - /// Optional protocol version to use, if not specified defaults to the - /// one originally used for the transaction. - #[arg(long, short, allow_hyphen_values = true)] - protocol_version: Option, - /// Optional output filepath for the profile generated by this run, if - /// not specified defaults to - /// `gas_profile_{tx_digest}_{unix_timestamp}.json in the working - /// directory. - #[arg(long, short, allow_hyphen_values = true)] - profile_output: Option, - }, - - /// Replay transaction - #[command(name = "tx")] - ReplayTransaction { - #[arg(long, short)] - tx_digest: String, - #[arg(long, short)] - show_effects: bool, - #[arg(long, short)] - diag: bool, - /// Optional version of the executor to use, if not specified defaults - /// to the one originally used for the transaction. - #[arg(long, short, allow_hyphen_values = true)] - executor_version: Option, - /// Optional protocol version to use, if not specified defaults to the - /// one originally used for the transaction. - #[arg(long, short, allow_hyphen_values = true)] - protocol_version: Option, - }, - - /// Replay transactions listed in a file - #[command(name = "rb")] - ReplayBatch { - #[arg(long, short)] - path: PathBuf, - #[arg(long, short)] - terminate_early: bool, - #[arg(long, short, default_value = "16")] - batch_size: u64, - }, - - /// Replay a transaction from a node state dump - #[command(name = "rd")] - ReplayDump { - #[arg(long, short)] - path: String, - #[arg(long, short)] - show_effects: bool, - }, - - /// Replay all transactions in a range of checkpoints - #[command(name = "ch")] - ReplayCheckpoints { - #[arg(long, short)] - start: u64, - #[arg(long, short)] - end: u64, - #[arg(long, short)] - terminate_early: bool, - #[arg(long, short, default_value = "16")] - max_tasks: u64, - }, - - /// Replay all transactions in an epoch - #[command(name = "ep")] - ReplayEpoch { - #[arg(long, short)] - epoch: u64, - #[arg(long, short)] - terminate_early: bool, - #[arg(long, short, default_value = "16")] - max_tasks: u64, - }, - - /// Run the replay based fuzzer - #[command(name = "fz")] - Fuzz { - #[arg(long, short)] - start: Option, - #[arg(long, short)] - num_mutations_per_base: u64, - #[arg(long, short = 'b', default_value = "18446744073709551614")] - num_base_transactions: u64, - }, - - #[command(name = "report")] - Report, -} - -#[async_recursion] -pub async fn execute_replay_command( - rpc_url: Option, - safety_checks: bool, - use_authority: bool, - cfg_path: Option, - cmd: ReplayToolCommand, -) -> anyhow::Result> { - let safety = if safety_checks { - ExpensiveSafetyCheckConfig::new_enable_all() - } else { - ExpensiveSafetyCheckConfig::default() - }; - Ok(match cmd { - ReplayToolCommand::ReplaySandbox { path } => { - let contents = std::fs::read_to_string(path)?; - let sandbox_state: ExecutionSandboxState = serde_json::from_str(&contents)?; - info!("Executing tx: {}", sandbox_state.transaction_info.tx_digest); - let sandbox_state = LocalExec::certificate_execute_with_sandbox_state( - &sandbox_state, - None, - &sandbox_state.pre_exec_diag, - ) - .await?; - sandbox_state.check_effects()?; - info!("Execution finished successfully. Local and on-chain effects match."); - None - } - ReplayToolCommand::PersistSandbox { - tx_digest, - base_path, - } => { - let tx_digest = TransactionDigest::from_str(&tx_digest)?; - info!("Executing tx: {}", tx_digest); - let sandbox_state = LocalExec::replay_with_network_config( - rpc_url, - cfg_path.map(|p| p.to_str().unwrap().to_string()), - tx_digest, - safety, - use_authority, - None, - None, - None, - ) - .await?; - - let out = serde_json::to_string(&sandbox_state).unwrap(); - let path = base_path.join(format!("{}.json", tx_digest)); - std::fs::write(path, out)?; - None - } - ReplayToolCommand::GenerateDefaultConfig => { - let set = ReplayableNetworkConfigSet::default(); - let path = set.save_config(None).unwrap(); - println!("Default config saved to: {}", path.to_str().unwrap()); - warn!("Note: default config nodes might prune epochs/objects"); - None - } - ReplayToolCommand::Fuzz { - start, - num_mutations_per_base, - num_base_transactions, - } => { - let config = ReplayFuzzerConfig { - num_mutations_per_base, - mutator: Box::new(base_fuzzers(num_mutations_per_base)), - tx_source: TransactionSource::TailLatest { start }, - fail_over_on_err: false, - expensive_safety_check_config: Default::default(), - }; - let fuzzer = ReplayFuzzer::new(rpc_url.expect("Url must be provided"), config) - .await - .unwrap(); - fuzzer.run(num_base_transactions).await.unwrap(); - None - } - ReplayToolCommand::ReplayDump { path, show_effects } => { - let mut lx = LocalExec::new_for_state_dump(&path, rpc_url).await?; - let (sandbox_state, node_dump_state) = lx.execute_state_dump(safety).await?; - if show_effects { - println!("{:#?}", sandbox_state.local_exec_effects); - } - - sandbox_state.check_effects()?; - - let effects = node_dump_state.computed_effects.digest(); - if effects != node_dump_state.expected_effects_digest { - error!( - "Effects digest mismatch for {}: expected: {:?}, got: {:?}", - node_dump_state.tx_digest, node_dump_state.expected_effects_digest, effects, - ); - anyhow::bail!("Effects mismatch"); - } - - info!("Execution finished successfully. Local and on-chain effects match."); - Some((1u64, 1u64)) - } - ReplayToolCommand::ReplayBatch { - path, - terminate_early, - batch_size, - } => { - async fn exec_batch( - rpc_url: Option, - safety: ExpensiveSafetyCheckConfig, - use_authority: bool, - cfg_path: Option, - tx_digests: &[TransactionDigest], - ) -> anyhow::Result<()> { - let mut handles = vec![]; - for tx_digest in tx_digests { - let tx_digest = *tx_digest; - let rpc_url = rpc_url.clone(); - let cfg_path = cfg_path.clone(); - let safety = safety.clone(); - handles.push(tokio::spawn(async move { - info!("Executing tx: {}", tx_digest); - let sandbox_state = LocalExec::replay_with_network_config( - rpc_url, - cfg_path.map(|p| p.to_str().unwrap().to_string()), - tx_digest, - safety, - use_authority, - None, - None, - None, - ) - .await?; - - sandbox_state.check_effects()?; - - info!("Execution finished successfully: {}. Local and on-chain effects match.", tx_digest); - Ok::<_, anyhow::Error>(()) - })); - } - futures::future::join_all(handles) - .await - .into_iter() - .collect::, _>>() - .expect("Join all failed") - .into_iter() - .collect::, _>>()?; - Ok(()) - } - - // While file end not reached, read up to max_tasks lines from path - let file = std::fs::File::open(path).unwrap(); - let reader = std::io::BufReader::new(file); - - let mut chunk = Vec::new(); - for tx_digest in reader.lines() { - chunk.push( - match TransactionDigest::from_str(&tx_digest.expect("Unable to readline")) { - Ok(digest) => digest, - Err(e) => { - panic!("Error parsing tx digest: {:?}", e); - } - }, - ); - if chunk.len() == batch_size as usize { - println!("Executing batch: {:?}", chunk); - // execute all in chunk - match exec_batch( - rpc_url.clone(), - safety.clone(), - use_authority, - cfg_path.clone(), - &chunk, - ) - .await - { - Ok(_) => info!("Batch executed successfully: {:?}", chunk), - Err(e) => { - error!("Error executing batch: {:?}", e); - if terminate_early { - return Err(e); - } - } - } - println!("Finished batch execution"); - - chunk.clear(); - } - } - if !chunk.is_empty() { - println!("Executing batch: {:?}", chunk); - match exec_batch( - rpc_url.clone(), - safety, - use_authority, - cfg_path.clone(), - &chunk, - ) - .await - { - Ok(_) => info!("Batch executed successfully: {:?}", chunk), - Err(e) => { - error!("Error executing batch: {:?}", e); - if terminate_early { - return Err(e); - } - } - } - println!("Finished batch execution"); - } - - // TODO: clean this up - Some((0u64, 0u64)) - } - ReplayToolCommand::ProfileTransaction { - tx_digest, - executor_version, - protocol_version, - profile_output, - } => { - let output_path = profile_output.or(Some(get_default_output_filepath())); - - let tx_digest = TransactionDigest::from_str(&tx_digest)?; - info!("Executing tx: {}", tx_digest); - let _sandbox_state = LocalExec::replay_with_network_config( - rpc_url, - cfg_path.map(|p| p.to_str().unwrap().to_string()), - tx_digest, - safety, - use_authority, - executor_version, - protocol_version, - output_path, - ) - .await?; - - println!("Execution finished successfully."); - Some((1u64, 1u64)) - } - - ReplayToolCommand::ReplayTransaction { - tx_digest, - show_effects, - diag, - executor_version, - protocol_version, - } => { - let tx_digest = TransactionDigest::from_str(&tx_digest)?; - info!("Executing tx: {}", tx_digest); - let sandbox_state = LocalExec::replay_with_network_config( - rpc_url, - cfg_path.map(|p| p.to_str().unwrap().to_string()), - tx_digest, - safety, - use_authority, - executor_version, - protocol_version, - None, - ) - .await?; - - if diag { - println!("{:#?}", sandbox_state.pre_exec_diag); - } - if show_effects { - println!("{}", sandbox_state.local_exec_effects); - } - - sandbox_state.check_effects()?; - - println!("Execution finished successfully. Local and on-chain effects match."); - Some((1u64, 1u64)) - } - - ReplayToolCommand::Report => { - let mut lx = - LocalExec::new_from_fn_url(&rpc_url.expect("Url must be provided")).await?; - let epoch_table = lx.protocol_ver_to_epoch_map().await?; - - // We need this for other activities in this session - lx.current_protocol_version = *epoch_table.keys().peekable().last().unwrap(); - - println!( - " Protocol Version | Epoch Change TX | Epoch Range | Checkpoint Range " - ); - println!( - "---------------------------------------------------------------------------------------------------------------" - ); - - for ( - protocol_version, - ProtocolVersionSummary { - epoch_change_tx: tx_digest, - epoch_start: start_epoch, - epoch_end: end_epoch, - checkpoint_start, - checkpoint_end, - .. - }, - ) in epoch_table - { - println!( - " {:^16} | {:^43} | {:^10}-{:^10}| {:^10}-{:^10} ", - protocol_version, - tx_digest, - start_epoch, - end_epoch, - checkpoint_start.unwrap_or(u64::MAX), - checkpoint_end.unwrap_or(u64::MAX) - ); - } - - lx.populate_protocol_version_tables().await?; - for x in lx.protocol_version_system_package_table { - println!("Protocol version: {}", x.0); - for (package_id, seq_num) in x.1 { - println!("Package: {} Seq: {}", package_id, seq_num); - } - } - None - } - - ReplayToolCommand::ReplayCheckpoints { - start, - end, - terminate_early, - max_tasks, - } => { - assert!(start <= end, "Start checkpoint must be <= end checkpoint"); - assert!(max_tasks > 0, "Max tasks must be > 0"); - let checkpoints_per_task = ((end - start + max_tasks) / max_tasks) as usize; - let mut handles = vec![]; - info!( - "Executing checkpoints {} to {} with at most {} tasks and at most {} checkpoints per task", - start, end, max_tasks, checkpoints_per_task - ); - - let range: Vec<_> = (start..=end).collect(); - for (task_count, checkpoints) in range.chunks(checkpoints_per_task).enumerate() { - let checkpoints = checkpoints.to_vec(); - let rpc_url = rpc_url.clone(); - let safety = safety.clone(); - handles.push(tokio::spawn(async move { - info!("Spawning task {task_count} for checkpoints {checkpoints:?}"); - let time = std::time::Instant::now(); - let (succeeded, total) = LocalExec::new_from_fn_url(&rpc_url.expect("Url must be provided")) - .await - .unwrap() - .init_for_execution() - .await - .unwrap() - .execute_all_in_checkpoints(&checkpoints, &safety, terminate_early, use_authority) - .await - .unwrap(); - let time = time.elapsed(); - info!( - "Task {task_count}: executed checkpoints {:?} @ {} total transactions, {} succeeded", - checkpoints, total, succeeded - ); - (succeeded, total, time) - })); - } - - let mut total_tx = 0; - let mut total_time_ms = 0; - let mut total_succeeded = 0; - futures::future::join_all(handles) - .await - .into_iter() - .for_each(|x| match x { - Ok((suceeded, total, time)) => { - total_tx += total; - total_time_ms += time.as_millis() as u64; - total_succeeded += suceeded; - } - Err(e) => { - error!("Task failed: {:?}", e); - } - }); - info!( - "Executed {} checkpoints @ {}/{} total TXs succeeded in {} ms ({}) avg TX/s", - end - start + 1, - total_succeeded, - total_tx, - total_time_ms, - (total_tx as f64) / (total_time_ms as f64 / 1000.0) - ); - Some((total_succeeded, total_tx)) - } - ReplayToolCommand::ReplayEpoch { - epoch, - terminate_early, - max_tasks, - } => { - let lx = - LocalExec::new_from_fn_url(&rpc_url.clone().expect("Url must be provided")).await?; - - let (start, end) = lx.checkpoints_for_epoch(epoch).await?; - - info!( - "Executing epoch {} (checkpoint range {}-{}) with at most {} tasks", - epoch, start, end, max_tasks - ); - let status = execute_replay_command( - rpc_url, - safety_checks, - use_authority, - cfg_path, - ReplayToolCommand::ReplayCheckpoints { - start, - end, - terminate_early, - max_tasks, - }, - ) - .await; - match status { - Ok(Some((succeeded, total))) => { - info!( - "Epoch {} replay finished {} out of {} TXs", - epoch, succeeded, total - ); - - return Ok(Some((succeeded, total))); - } - Ok(None) => { - return Ok(None); - } - Err(e) => { - error!("Epoch {} replay failed: {:?}", epoch, e); - return Err(e); - } - } - } - }) -} - -pub(crate) fn chain_from_chain_id(chain: &str) -> Chain { - let mainnet_chain_id = format!("{}", get_mainnet_chain_identifier()); - // TODO: Since testnet periodically resets, we need to ensure that the chain id - // is updated to the latest one. - let testnet_chain_id = format!("{}", get_testnet_chain_identifier()); - - if mainnet_chain_id == chain { - Chain::Mainnet - } else if testnet_chain_id == chain { - Chain::Testnet - } else { - Chain::Unknown - } -} diff --git a/crates/sui-replay/src/tests.rs b/crates/sui-replay/src/tests.rs deleted file mode 100644 index 690fef644b0..00000000000 --- a/crates/sui-replay/src/tests.rs +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use sui_config::node::ExpensiveSafetyCheckConfig; -use sui_json_rpc_api::QUERY_MAX_RESULT_LIMIT; -use sui_json_rpc_types::SuiTransactionBlockResponseOptions; -use sui_sdk::{SuiClient, SuiClientBuilder}; -use sui_types::{base_types::SuiAddress, digests::TransactionDigest}; - -use crate::{ - config::ReplayableNetworkConfigSet, - types::{ReplayEngineError, MAX_CONCURRENT_REQUESTS, RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD}, - LocalExec, -}; - -/// Keep searching for non-system TXs in the checkppints for this long -/// Very unlikely to take this long, but we want to be sure we find one -const NUM_CHECKPOINTS_TO_ATTEMPT: usize = 1_000; - -/// Checks that replaying the latest tx on each testnet and mainnet does not -/// fail -#[ignore] -#[tokio::test] -async fn verify_latest_tx_replay_testnet_mainnet() { - let _ = verify_latest_tx_replay_impl().await; -} -async fn verify_latest_tx_replay_impl() { - let default_cfg = ReplayableNetworkConfigSet::default(); - let urls: Vec<_> = default_cfg - .base_network_configs - .iter() - .filter(|q| q.name != "devnet") // Devnet is not always stable - .map(|c| c.public_full_node.clone()) - .collect(); - - let mut handles = vec![]; - for url in urls { - handles.push(tokio::spawn(async move { - { - let mut num_checkpoint_trials_left = NUM_CHECKPOINTS_TO_ATTEMPT; - let rpc_client = SuiClientBuilder::default() - .request_timeout(RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD) - .max_concurrent_requests(MAX_CONCURRENT_REQUESTS) - .build(&url) - .await - .unwrap(); - - let chain_id = rpc_client.read_api().get_chain_identifier().await.unwrap(); - - let mut subject_checkpoint = rpc_client - .read_api() - .get_latest_checkpoint_sequence_number() - .await - .unwrap(); - let txs = rpc_client - .read_api() - .get_checkpoint(subject_checkpoint.into()) - .await - .unwrap() - .transactions; - - let mut non_system_txs = extract_one_system_tx(&rpc_client, txs).await; - num_checkpoint_trials_left -= 1; - while non_system_txs.is_none() && num_checkpoint_trials_left > 0 { - num_checkpoint_trials_left -= 1; - subject_checkpoint -= 1; - let txs = rpc_client - .read_api() - .get_checkpoint(subject_checkpoint.into()) - .await - .unwrap() - .transactions; - non_system_txs = extract_one_system_tx(&rpc_client, txs).await; - } - - if non_system_txs.is_none() { - panic!( - "No non-system txs found in the last {} checkpoints for network {} using rpc url {}", - NUM_CHECKPOINTS_TO_ATTEMPT, chain_id, url - ); - } - let tx: TransactionDigest = non_system_txs.unwrap(); - (url.clone(), execute_replay(&url, &tx) - .await - ) - } - })); - } - - let rets = futures::future::join_all(handles) - .await - .into_iter() - .collect::, _>>() - .expect("Join all failed"); - - for (url, ret) in rets { - if let Err(e) = ret { - panic!("Replay failed for network {} with error {:?}", url, e); - } - } -} - -async fn extract_one_system_tx( - rpc_client: &SuiClient, - mut txs: Vec, -) -> Option { - let opts = SuiTransactionBlockResponseOptions::full_content(); - txs.retain(|q| *q != TransactionDigest::genesis_marker()); - - for ch in txs.chunks(*QUERY_MAX_RESULT_LIMIT) { - match rpc_client - .read_api() - .multi_get_transactions_with_options(ch.to_vec(), opts.clone()) - .await - .unwrap() - .into_iter() - .filter_map(|x| { - if match x.transaction.unwrap().data { - sui_json_rpc_types::SuiTransactionBlockData::V1(tx) => tx.sender, - } != SuiAddress::ZERO - { - Some(x.digest) - } else { - None - } - }) - .next() - { - Some(tx) => { - tokio::task::yield_now().await; - return Some(tx); - } - None => { - continue; - } - } - } - None -} - -async fn execute_replay(url: &str, tx: &TransactionDigest) -> Result<(), ReplayEngineError> { - LocalExec::new_from_fn_url(url) - .await? - .init_for_execution() - .await? - .execute_transaction( - tx, - ExpensiveSafetyCheckConfig::default(), - true, - None, - None, - None, - ) - .await? - .check_effects()?; - tokio::task::yield_now().await; - LocalExec::new_from_fn_url(url) - .await? - .init_for_execution() - .await? - .execute_transaction( - tx, - ExpensiveSafetyCheckConfig::default(), - false, - None, - None, - None, - ) - .await? - .check_effects()?; - tokio::task::yield_now().await; - - Ok(()) -} diff --git a/crates/sui-replay/src/types.rs b/crates/sui-replay/src/types.rs deleted file mode 100644 index 7c5030ede23..00000000000 --- a/crates/sui-replay/src/types.rs +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt::Debug; - -use jsonrpsee::core::Error as JsonRpseeError; -use move_binary_format::CompiledModule; -use move_core_types::{ - account_address::AccountAddress, - language_storage::{ModuleId, StructTag}, -}; -use serde::{Deserialize, Serialize}; -use sui_json_rpc_types::{SuiEvent, SuiTransactionBlockEffects}; -use sui_protocol_config::{Chain, ProtocolVersion}; -use sui_sdk::error::Error as SuiRpcError; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress, VersionNumber}, - digests::{ObjectDigest, TransactionDigest}, - error::{SuiError, SuiObjectResponseError, SuiResult, UserInputError}, - object::Object, - transaction::{InputObjectKind, SenderSignedData, TransactionKind}, -}; -use thiserror::Error; -use tokio::time::Duration; -use tracing::{error, warn}; - -use crate::config::ReplayableNetworkConfigSet; - -// TODO: make these configurable -pub(crate) const RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD: Duration = Duration::from_millis(100_000); -pub(crate) const RPC_TIMEOUT_ERR_NUM_RETRIES: u32 = 3; -pub(crate) const MAX_CONCURRENT_REQUESTS: usize = 1_000; - -// Struct tag used in system epoch change events -pub(crate) const EPOCH_CHANGE_STRUCT_TAG: &str = - "0x3::sui_system_state_inner::SystemEpochInfoEvent"; - -pub(crate) const ONE_DAY_MS: u64 = 24 * 60 * 60 * 1000; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct OnChainTransactionInfo { - pub tx_digest: TransactionDigest, - pub sender_signed_data: SenderSignedData, - pub sender: SuiAddress, - pub input_objects: Vec, - pub kind: TransactionKind, - pub modified_at_versions: Vec<(ObjectID, SequenceNumber)>, - pub shared_object_refs: Vec, - pub gas: Vec<(ObjectID, SequenceNumber, ObjectDigest)>, - pub gas_budget: u64, - pub gas_price: u64, - pub executed_epoch: u64, - pub dependencies: Vec, - pub effects: SuiTransactionBlockEffects, - pub protocol_version: ProtocolVersion, - pub epoch_start_timestamp: u64, - pub reference_gas_price: u64, - #[serde(default = "unspecified_chain")] - pub chain: Chain, -} - -fn unspecified_chain() -> Chain { - warn!("Unable to determine chain id. Defaulting to unknown"); - Chain::Unknown -} - -#[derive(Clone, Debug, Default, Serialize, Deserialize)] -pub struct DiagInfo { - pub loaded_child_objects: Vec<(ObjectID, VersionNumber)>, -} - -#[allow(clippy::large_enum_variant)] -#[derive(Debug, Error, Clone)] -pub enum ReplayEngineError { - #[error("SuiError: {:#?}", err)] - SuiError { err: SuiError }, - - #[error("SuiRpcError: {:#?}", err)] - SuiRpcError { err: String }, - - #[error("SuiObjectResponseError: {:#?}", err)] - SuiObjectResponseError { err: SuiObjectResponseError }, - - #[error("UserInputError: {:#?}", err)] - UserInputError { err: UserInputError }, - - #[error("GeneralError: {:#?}", err)] - GeneralError { err: String }, - - #[error("SuiRpcRequestTimeout")] - SuiRpcRequestTimeout, - - #[error("ObjectNotExist: {:#?}", id)] - ObjectNotExist { id: ObjectID }, - - #[error("ObjectVersionNotFound: {:#?} version {}", id, version)] - ObjectVersionNotFound { - id: ObjectID, - version: SequenceNumber, - }, - - #[error( - "ObjectVersionTooHigh: {:#?}, requested version {}, latest version found {}", - id, - asked_version, - latest_version - )] - ObjectVersionTooHigh { - id: ObjectID, - asked_version: SequenceNumber, - latest_version: SequenceNumber, - }, - - #[error( - "ObjectDeleted: {:#?} at version {:#?} digest {:#?}", - id, - version, - digest - )] - ObjectDeleted { - id: ObjectID, - version: SequenceNumber, - digest: ObjectDigest, - }, - - #[error( - "EffectsForked: Effects for digest {} forked with diff {}", - digest, - diff - )] - EffectsForked { - digest: TransactionDigest, - diff: String, - on_chain: Box, - local: Box, - }, - - #[error("Genesis replay not supported digest {:#?}", digest)] - GenesisReplayNotSupported { digest: TransactionDigest }, - - #[error( - "Fatal! No framework versions for protocol version {protocol_version}. Make sure version tables are populated" - )] - FrameworkObjectVersionTableNotPopulated { protocol_version: u64 }, - - #[error("Protocol version not found for epoch {epoch}")] - ProtocolVersionNotFound { epoch: u64 }, - - #[error("Error querying system events for epoch {epoch}")] - ErrorQueryingSystemEvents { epoch: u64 }, - - #[error("Invalid epoch change transaction in events for epoch {epoch}")] - InvalidEpochChangeTx { epoch: u64 }, - - #[error("Unexpected event format {:#?}", event)] - UnexpectedEventFormat { event: SuiEvent }, - - #[error("Unable to find event for epoch {epoch}")] - EventNotFound { epoch: u64 }, - - #[error("Unable to find checkpoints for epoch {epoch}")] - UnableToDetermineCheckpoint { epoch: u64 }, - - #[error("Unable to query system events; {}", rpc_err)] - UnableToQuerySystemEvents { rpc_err: String }, - - #[error("Internal error or cache corrupted! Object {id}{} should be in cache.", version.map(|q| format!(" version {:#?}", q)).unwrap_or_default() )] - InternalCacheInvariantViolation { - id: ObjectID, - version: Option, - }, - - #[error("Error getting dynamic fields loaded objects: {}", rpc_err)] - UnableToGetDynamicFieldLoadedObjects { rpc_err: String }, - - #[error("Unsupported epoch in replay engine: {epoch}")] - EpochNotSupported { epoch: u64 }, - - #[error("Unable to open yaml cfg file at {}: {}", path, err)] - UnableToOpenYamlFile { path: String, err: String }, - - #[error("Unable to write yaml file at {}: {}", path, err)] - UnableToWriteYamlFile { path: String, err: String }, - - #[error("Unable to convert string {} to URL {}", url, err)] - InvalidUrl { url: String, err: String }, - - #[error( - "Unable to execute transaction with existing network configs {:#?}", - cfgs - )] - UnableToExecuteWithNetworkConfigs { cfgs: ReplayableNetworkConfigSet }, - - #[error("Unable to get chain id: {}", err)] - UnableToGetChainId { err: String }, -} - -impl From for ReplayEngineError { - fn from(err: SuiObjectResponseError) -> Self { - match err { - SuiObjectResponseError::NotExists { object_id } => { - ReplayEngineError::ObjectNotExist { id: object_id } - } - SuiObjectResponseError::Deleted { - object_id, - digest, - version, - } => ReplayEngineError::ObjectDeleted { - id: object_id, - version, - digest, - }, - _ => ReplayEngineError::SuiObjectResponseError { err }, - } - } -} - -impl From for SuiError { - fn from(err: ReplayEngineError) -> Self { - SuiError::Unknown(format!("{:#?}", err)) - } -} - -impl From for ReplayEngineError { - fn from(err: SuiError) -> Self { - ReplayEngineError::SuiError { err } - } -} -impl From for ReplayEngineError { - fn from(err: SuiRpcError) -> Self { - match err { - SuiRpcError::RpcError(JsonRpseeError::RequestTimeout) => { - ReplayEngineError::SuiRpcRequestTimeout - } - _ => ReplayEngineError::SuiRpcError { - err: format!("{:?}", err), - }, - } - } -} - -impl From for ReplayEngineError { - fn from(err: UserInputError) -> Self { - ReplayEngineError::UserInputError { err } - } -} - -impl From for ReplayEngineError { - fn from(err: anyhow::Error) -> Self { - ReplayEngineError::GeneralError { - err: format!("{:#?}", err), - } - } -} - -/// TODO: Limited set but will add more -#[derive(Debug)] -pub enum ExecutionStoreEvent { - BackingPackageGetPackageObject { - package_id: ObjectID, - result: SuiResult>, - }, - ChildObjectResolverStoreReadChildObject { - parent: ObjectID, - child: ObjectID, - result: SuiResult>, - }, - ParentSyncStoreGetLatestParentEntryRef { - object_id: ObjectID, - result: SuiResult>, - }, - ResourceResolverGetResource { - address: AccountAddress, - typ: StructTag, - result: SuiResult>>, - }, - ModuleResolverGetModule { - module_id: ModuleId, - result: SuiResult>>, - }, - ObjectStoreGetObject { - object_id: ObjectID, - result: SuiResult>, - }, - ObjectStoreGetObjectByKey { - object_id: ObjectID, - version: VersionNumber, - result: SuiResult>, - }, - GetModuleGetModuleByModuleId { - id: ModuleId, - result: SuiResult>, - }, - ReceiveObject { - owner: ObjectID, - receive: ObjectID, - receive_at_version: SequenceNumber, - result: SuiResult>, - }, -} diff --git a/crates/sui-replay/tests/sandbox_snapshots/4fxF3X4N8D6JGByWdbJvCCv1iuoT8GSEhXgPHJnzNHWP.json b/crates/sui-replay/tests/sandbox_snapshots/4fxF3X4N8D6JGByWdbJvCCv1iuoT8GSEhXgPHJnzNHWP.json deleted file mode 100644 index 6d1942842d7..00000000000 --- a/crates/sui-replay/tests/sandbox_snapshots/4fxF3X4N8D6JGByWdbJvCCv1iuoT8GSEhXgPHJnzNHWP.json +++ /dev/null @@ -1 +0,0 @@ -{"transaction_info":{"tx_digest":"4fxF3X4N8D6JGByWdbJvCCv1iuoT8GSEhXgPHJnzNHWP","sender_signed_data":[{"intent_message":{"intent":{"scope":0,"version":0,"app_id":0},"value":{"V1":{"kind":{"ProgrammableTransaction":{"inputs":[{"Object":{"ImmOrOwnedObject":["0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623",10941462,"97EMwmR1yvKzotocnPsNs5gLiHPkDztrM5WsVeE9d1y"]}},{"Pure":[0]},{"Pure":[32,246,193,86,67,237,66,165,149,9,252,108,46,208,117,166,90,184,114,112,210,57,76,234,29,82,22,132,25,179,156,59,27]}],"commands":[{"MoveCall":{"package":"0x0000000000000000000000000000000000000000000000000000000000000002","module":"package","function":"authorize_upgrade","type_arguments":[],"arguments":[{"Input":0},{"Input":1},{"Input":2}]}},{"Upgrade":[[[161,28,235,11,6,0,0,0,7,1,0,2,3,2,30,5,32,6,7,38,34,8,72,32,6,104,50,12,154,1,163,2,0,5,0,0,0,1,0,0,6,0,1,0,0,4,0,1,0,0,1,0,1,0,0,3,0,1,0,0,2,0,1,0,2,15,15,1,15,0,3,97,100,100,3,100,105,118,3,109,105,110,3,109,111,100,3,109,117,108,9,115,97,102,101,95,109,97,116,104,3,115,117,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,233,3,0,0,0,0,0,0,3,8,234,3,0,0,0,0,0,0,3,8,235,3,0,0,0,0,0,0,3,8,236,3,0,0,0,0,0,0,3,8,237,3,0,0,0,0,0,0,0,1,0,0,1,13,10,0,11,1,22,12,2,10,2,11,0,38,4,9,5,11,7,0,39,11,2,2,1,1,0,0,2,11,10,1,10,0,37,4,5,5,7,7,1,39,11,0,11,1,23,2,2,1,0,0,1,21,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,10,1,24,12,2,10,2,11,0,26,11,1,33,4,17,5,19,7,2,39,11,2,2,3,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,5,5,7,7,3,39,11,0,11,1,26,2,4,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,4,39,11,0,11,1,25,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,0],[161,28,235,11,6,0,0,0,9,1,0,10,2,10,16,3,26,47,4,73,12,5,85,63,7,148,1,156,1,8,176,2,64,6,240,2,20,12,132,3,114,0,14,1,3,1,4,1,12,1,13,1,0,4,1,0,1,2,1,12,1,0,1,4,2,2,0,0,10,0,1,1,0,0,11,0,2,1,0,2,5,1,8,1,0,2,6,1,2,1,0,2,9,7,1,1,0,2,15,5,6,1,0,3,7,11,8,1,12,4,8,9,10,0,5,4,4,4,2,4,6,1,0,4,3,4,3,11,1,1,9,0,3,7,8,2,1,11,1,1,9,0,1,11,0,1,9,0,2,3,11,1,1,9,0,1,9,0,1,6,11,1,1,9,0,1,3,3,7,11,1,1,9,0,3,7,8,2,0,1,6,8,2,1,5,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,4,99,111,105,110,12,100,101,115,116,114,111,121,95,122,101,114,111,12,105,110,116,111,95,98,97,108,97,110,99,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,10,115,112,108,105,116,95,99,111,105,110,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,117,116,105,108,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,176,179,0,0,0,0,0,0,3,8,177,179,0,0,0,0,0,0,0,1,0,0,3,44,14,0,56,0,12,3,10,1,6,0,0,0,0,0,0,0,0,36,4,8,5,12,11,2,1,7,0,39,11,3,10,1,38,4,17,5,21,11,2,1,7,1,39,13,0,11,1,10,2,56,1,12,4,14,0,56,0,6,0,0,0,0,0,0,0,0,33,4,37,11,2,1,11,0,56,2,11,4,2,11,0,11,2,46,17,7,56,3,11,4,2,1,1,0,0,8,6,11,0,11,1,11,2,56,4,56,5,2,0],[161,28,235,11,6,0,0,0,14,1,0,18,2,18,54,3,72,145,1,4,217,1,30,5,247,1,203,1,7,194,3,145,4,8,211,7,96,6,179,8,20,10,199,8,67,11,138,9,2,12,140,9,146,3,13,158,12,6,14,164,12,6,15,170,12,4,0,37,1,13,1,47,2,14,2,15,2,23,2,36,2,44,2,46,0,2,12,1,0,1,0,3,12,0,0,5,3,0,0,4,3,0,0,6,3,0,0,7,3,0,1,8,7,0,2,10,7,0,3,0,4,1,0,1,4,1,12,1,0,1,6,11,4,0,8,9,2,0,0,28,0,1,0,0,17,2,1,1,0,0,20,3,1,1,0,0,50,4,1,1,0,0,21,5,1,1,0,0,52,6,1,1,0,0,51,7,1,1,0,0,26,8,9,1,0,0,16,10,11,0,0,35,12,11,1,0,0,48,12,11,1,0,2,25,1,26,1,0,2,30,26,27,0,3,31,25,11,1,0,3,42,29,19,1,0,3,49,32,11,1,0,3,53,1,19,1,0,4,24,30,24,1,0,4,29,24,19,1,0,4,49,23,11,1,0,5,22,18,1,1,3,6,33,0,13,0,7,38,17,1,1,12,7,41,18,1,1,8,8,40,14,15,0,22,16,16,18,23,20,20,21,19,18,18,18,13,18,11,18,20,28,14,18,17,18,20,31,22,24,15,18,7,18,1,7,8,11,0,3,6,8,1,2,7,8,11,3,7,11,0,1,9,0,11,9,1,9,0,7,8,11,4,7,11,0,1,9,0,3,5,7,8,11,2,7,11,0,1,9,0,3,5,7,8,1,7,11,0,1,9,0,3,5,7,8,11,5,6,8,1,7,11,0,1,9,0,3,5,7,8,11,1,6,11,0,1,9,0,1,2,3,3,2,2,1,3,2,6,11,0,1,9,0,3,1,8,10,1,6,8,11,1,5,1,8,1,2,9,0,5,1,9,0,1,11,8,1,9,0,1,11,0,1,9,0,1,8,2,2,11,8,1,9,0,3,1,6,11,9,1,9,0,1,11,9,1,9,0,2,7,11,8,1,9,0,11,8,1,9,0,1,8,7,1,8,6,1,8,4,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,11,1,8,5,1,6,11,8,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,19,80,111,111,108,66,97,108,97,110,99,101,82,101,103,105,115,116,101,114,10,80,111,111,108,67,114,101,97,116,101,11,80,111,111,108,68,101,112,111,115,105,116,12,80,111,111,108,87,105,116,104,100,114,97,119,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,7,99,114,101,97,116,111,114,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,2,105,100,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,7,108,101,110,100,105,110,103,3,110,101,119,10,110,101,119,95,97,109,111,117,110,116,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,9,114,101,99,105,112,105,101,110,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,7,115,116,111,114,97,103,101,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,17,164,0,0,0,0,0,0,3,8,18,164,0,0,0,0,0,0,0,2,4,27,8,10,14,11,8,1,9,0,45,11,8,1,9,0,19,2,1,2,2,27,8,10,18,5,2,2,1,18,5,3,2,4,40,5,12,3,34,3,37,8,6,4,2,3,40,5,12,3,37,8,6,5,2,4,40,5,39,5,12,3,37,8,6,0,18,0,0,0,0,1,11,10,0,17,21,10,0,46,17,24,18,1,11,0,46,17,24,56,0,2,1,3,0,0,1,13,10,2,17,21,56,1,56,1,11,1,57,0,56,2,11,2,46,17,24,18,2,56,3,2,2,3,0,0,22,20,14,1,56,4,12,4,11,1,56,5,12,3,11,0,54,0,11,3,56,6,1,11,2,46,17,24,11,4,56,7,17,12,18,4,56,8,2,3,3,0,0,24,20,11,0,54,0,10,1,56,9,10,3,56,10,12,4,11,3,46,17,24,10,2,11,1,56,7,17,12,18,5,56,11,11,4,11,2,56,12,2,4,3,0,0,19,22,10,0,55,0,56,13,10,1,38,4,7,5,11,11,0,1,7,1,39,10,0,54,0,11,1,56,9,12,2,11,0,54,1,11,2,56,6,1,2,5,1,0,0,1,22,10,1,55,1,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,1,11,2,56,9,11,4,56,10,11,3,56,12,2,6,3,0,0,1,22,10,1,55,0,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,0,11,2,56,9,11,4,56,10,11,3,56,12,2,7,1,0,0,1,4,11,0,55,2,20,2,8,1,0,0,1,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,9,1,0,0,9,8,11,0,56,14,12,2,11,1,11,2,49,9,17,8,2,10,1,0,0,9,8,11,0,56,14,12,2,11,1,49,9,11,2,17,8,2,0,1,0,2,0,3,0,18,1,18,2,18,0,32,0,43,0],[161,28,235,11,6,0,0,0,7,1,0,4,3,4,55,5,59,8,7,67,101,8,168,1,64,6,232,1,200,1,12,176,3,168,5,0,6,1,0,0,4,0,1,0,0,9,0,1,0,0,1,0,1,0,0,2,0,1,0,0,11,2,1,0,0,10,2,1,0,0,7,2,1,0,0,5,2,1,0,0,8,1,1,0,0,12,1,1,0,1,3,0,1,0,0,1,15,2,15,15,1,1,7,97,100,100,114,101,115,115,8,104,97,108,102,95,114,97,121,8,104,97,108,102,95,119,97,100,3,109,97,120,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,10,114,97,121,95,116,111,95,119,97,100,3,119,97,100,7,119,97,100,95,100,105,118,7,119,97,100,95,109,117,108,10,119,97,100,95,116,111,95,114,97,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,100,167,179,182,224,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,178,211,89,91,240,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,77,4,0,0,0,0,0,0,3,8,78,4,0,0,0,0,0,0,3,8,79,4,0,0,0,0,0,0,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,0,2,2,1,0,0,0,2,7,3,2,3,1,0,0,0,2,7,1,2,4,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,1,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,1,22,7,0,26,2,5,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,0,26,37,4,20,5,22,7,5,39,11,0,7,0,24,11,2,22,11,1,26,2,6,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,3,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,3,22,7,2,26,2,7,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,2,26,37,4,20,5,22,7,5,39,11,0,7,2,24,11,2,22,11,1,26,2,8,1,0,0,2,19,7,4,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,1,10,1,11,0,22,12,2,10,2,11,1,38,4,13,5,15,7,6,39,11,2,7,4,26,2,9,1,0,0,1,15,10,0,7,4,24,12,1,10,1,7,4,26,11,0,33,4,11,5,13,7,5,39,11,1,2,0],[161,28,235,11,6,0,0,0,12,1,0,29,2,29,92,3,121,144,3,4,137,4,54,5,191,4,153,3,7,216,7,131,16,8,219,23,96,6,187,24,93,10,152,25,164,1,12,188,26,186,19,13,246,45,66,15,184,46,2,0,120,0,90,0,94,1,22,1,131,1,1,141,1,2,30,2,31,2,47,2,85,2,123,2,127,2,130,1,0,4,12,0,0,11,12,0,0,10,12,0,0,9,4,0,0,20,4,0,0,8,5,0,0,19,5,0,0,15,4,0,0,0,4,0,0,3,4,0,0,12,3,0,0,5,3,0,1,6,12,1,0,1,1,7,12,0,3,13,7,0,4,17,7,0,6,1,8,0,7,2,12,1,0,1,9,18,4,0,10,14,12,2,7,1,4,1,12,16,2,0,0,73,0,1,0,0,144,1,2,1,0,0,143,1,3,1,0,0,74,4,1,1,0,0,115,5,1,0,0,117,6,1,0,0,107,6,1,0,0,112,6,1,0,0,118,6,1,0,0,106,6,1,0,0,113,6,1,0,0,108,6,1,0,0,116,6,1,0,0,114,6,1,0,0,110,6,1,0,0,109,6,1,0,0,111,6,1,0,0,102,2,1,1,0,0,88,2,7,0,0,59,2,8,0,0,64,9,10,0,0,58,11,8,0,0,52,11,12,0,0,60,13,14,0,0,50,13,14,0,0,53,13,15,0,0,55,13,15,0,0,61,13,15,0,0,65,16,15,0,0,56,11,17,0,0,49,11,14,0,0,63,13,14,0,0,62,11,14,0,0,51,13,18,0,0,57,13,19,0,0,133,1,20,1,0,0,134,1,21,1,0,0,68,20,1,0,0,70,22,1,0,0,44,22,1,0,0,69,22,1,0,0,43,22,1,0,0,67,23,1,0,0,42,23,1,0,0,71,24,1,0,0,136,1,16,1,0,0,97,16,1,0,0,135,1,16,1,0,0,96,16,1,0,0,146,1,25,1,1,0,0,45,3,1,0,1,36,43,1,1,0,1,132,1,62,17,1,0,1,145,1,63,1,1,0,2,93,1,14,0,4,48,1,38,1,0,4,75,38,12,0,5,35,57,7,1,0,5,72,57,59,1,0,5,95,60,36,1,0,6,125,40,17,0,7,54,42,8,1,0,8,46,36,1,1,3,9,84,0,26,0,10,21,41,1,2,7,4,10,25,49,50,2,7,4,10,28,46,47,2,7,4,10,35,49,7,2,7,4,10,84,0,33,2,7,4,10,95,46,55,2,7,4,11,91,30,1,1,12,11,119,36,1,1,8,12,105,27,28,0,70,29,70,31,68,32,68,34,71,35,17,36,55,36,68,39,64,32,61,36,51,36,62,44,66,32,65,32,67,34,65,34,67,39,65,39,69,39,64,39,64,34,66,34,57,8,58,8,59,8,52,36,53,36,1,7,8,20,0,1,6,8,2,2,6,8,1,7,8,2,20,6,8,1,6,8,13,6,8,16,7,8,2,2,1,15,15,15,15,15,15,15,15,15,15,15,15,6,11,17,1,9,0,7,8,20,3,6,8,0,7,8,2,1,4,6,8,0,7,8,2,2,15,1,1,1,2,2,6,8,2,5,2,10,2,10,2,2,6,8,2,2,1,8,14,2,7,8,2,2,1,15,2,15,15,3,7,8,2,2,5,1,3,5,15,15,15,15,15,3,15,15,15,4,7,8,2,2,15,15,6,7,8,2,2,15,15,3,15,4,7,8,2,2,5,15,3,7,8,7,5,15,3,7,8,2,2,15,8,6,8,1,6,8,13,7,8,2,2,7,11,12,1,9,0,3,5,7,8,20,1,8,18,1,6,8,20,1,5,1,8,1,2,9,0,5,1,8,0,2,2,8,3,1,11,19,2,9,0,9,1,2,5,8,4,1,8,2,1,9,0,18,2,15,15,15,8,7,8,7,3,8,8,8,9,2,8,14,1,15,15,15,2,2,8,3,1,8,15,2,5,15,1,6,8,16,3,7,11,19,2,9,0,9,1,9,0,9,1,1,6,11,17,1,9,0,3,6,8,13,2,7,8,20,1,8,11,1,7,8,3,2,7,11,19,2,9,0,9,1,9,0,1,7,9,1,3,2,2,8,14,2,6,11,19,2,9,0,9,1,9,0,1,6,9,1,1,6,8,4,1,6,8,3,3,15,6,8,3,15,3,7,8,7,7,8,3,7,8,7,1,9,1,3,10,2,8,4,7,8,4,2,6,10,9,0,6,9,0,2,3,7,8,4,2,1,3,2,7,10,9,0,3,5,2,3,7,15,3,3,2,6,11,12,1,9,0,3,5,6,8,13,7,11,12,1,9,0,3,5,7,8,20,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,12,67,111,105,110,77,101,116,97,100,97,116,97,18,76,105,113,117,105,100,97,116,105,111,110,70,97,99,116,111,114,115,8,79,119,110,101,114,67,97,112,6,80,97,117,115,101,100,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,23,82,101,115,101,114,118,101,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,11,82,101,115,101,114,118,101,68,97,116,97,7,83,116,111,114,97,103,101,15,83,116,111,114,97,103,101,65,100,109,105,110,67,97,112,26,83,116,111,114,97,103,101,67,111,110,102,105,103,117,114,97,116,111,114,83,101,116,116,105,110,103,6,83,116,114,105,110,103,5,84,97,98,108,101,12,84,111,107,101,110,66,97,108,97,110,99,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,20,85,115,101,114,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,8,85,115,101,114,73,110,102,111,3,97,100,100,5,97,115,99,105,105,9,98,97,115,101,95,114,97,116,101,5,98,111,110,117,115,6,98,111,114,114,111,119,14,98,111,114,114,111,119,95,98,97,108,97,110,99,101,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,5,99,108,111,99,107,4,99,111,105,110,9,99,111,105,110,95,116,121,112,101,11,99,111,108,108,97,116,101,114,97,108,115,12,99,111,110,102,105,103,117,114,97,116,111,114,8,99,111,110,116,97,105,110,115,11,99,114,101,97,116,101,95,112,111,111,108,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,20,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,114,97,116,101,4,100,97,116,97,16,100,101,99,114,101,97,115,101,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,12,100,101,115,116,111,114,121,95,117,115,101,114,4,101,109,105,116,5,101,118,101,110,116,3,103,101,116,13,103,101,116,95,97,115,115,101,116,95,108,116,118,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,13,103,101,116,95,99,111,105,110,95,116,121,112,101,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,12,103,101,116,95,100,101,99,105,109,97,108,115,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,20,103,101,116,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,16,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,114,101,115,101,114,118,101,11,105,110,116,111,95,115,116,114,105,110,103,11,105,115,95,105,115,111,108,97,116,101,100,20,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,5,108,111,97,110,115,5,108,111,103,105,99,3,108,116,118,10,109,117,108,116,105,112,108,105,101,114,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,111,114,97,99,108,101,95,105,100,5,112,97,117,115,101,6,112,97,117,115,101,100,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,105,111,3,114,97,121,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,14,114,101,115,101,114,118,101,95,102,97,99,116,111,114,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,97,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,98,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,99,18,114,101,115,101,114,118,101,95,118,97,108,105,100,97,116,105,111,110,8,114,101,115,101,114,118,101,115,14,114,101,115,101,114,118,101,115,95,99,111,117,110,116,6,115,101,110,100,101,114,13,115,101,116,95,98,97,115,101,95,114,97,116,101,14,115,101,116,95,98,111,114,114,111,119,95,99,97,112,24,115,101,116,95,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,98,111,110,117,115,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,114,97,116,105,111,25,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,7,115,101,116,95,108,116,118,14,115,101,116,95,109,117,108,116,105,112,108,105,101,114,23,115,101,116,95,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,115,101,116,95,112,97,117,115,101,18,115,101,116,95,114,101,115,101,114,118,101,95,102,97,99,116,111,114,14,115,101,116,95,115,117,112,112,108,121,95,99,97,112,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,7,115,116,111,114,97,103,101,14,115,117,112,112,108,121,95,98,97,108,97,110,99,101,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,9,116,104,114,101,115,104,111,108,100,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,9,117,115,101,114,95,105,110,102,111,10,117,115,101,114,95,115,116,97,116,101,5,117,115,101,114,115,5,118,97,108,117,101,6,118,101,99,116,111,114,7,118,101,114,115,105,111,110,15,118,101,114,115,105,111,110,95,109,105,103,114,97,116,101,20,118,101,114,115,105,111,110,95,118,101,114,105,102,105,99,97,116,105,111,110,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,3,0,0,0,0,0,0,0,3,8,248,167,0,0,0,0,0,0,3,8,249,167,0,0,0,0,0,0,3,8,250,167,0,0,0,0,0,0,3,8,251,167,0,0,0,0,0,0,3,8,252,167,0,0,0,0,0,0,3,8,253,167,0,0,0,0,0,0,3,8,254,167,0,0,0,0,0,0,3,8,255,167,0,0,0,0,0,0,2,1,255,0,2,1,66,8,18,1,2,1,66,8,18,2,2,7,66,8,18,142,1,3,89,1,103,11,19,2,2,8,3,104,2,139,1,10,5,137,1,11,19,2,5,8,4,3,2,21,66,2,87,2,32,8,14,76,1,122,15,27,15,40,15,38,15,39,15,37,15,121,8,7,26,8,7,78,3,82,15,129,1,15,128,1,15,29,8,8,79,8,9,99,15,100,15,101,15,4,2,2,33,10,2,80,10,2,5,2,1,41,15,6,2,1,41,15,7,2,2,138,1,11,19,2,5,15,126,15,8,2,5,23,15,83,15,77,15,98,15,86,15,9,2,3,92,15,24,15,124,15,10,2,3,105,5,34,5,140,1,1,11,2,1,89,1,0,0,0,0,1,27,10,0,17,63,18,1,10,0,46,17,72,56,0,10,0,17,63,18,0,10,0,46,17,72,56,1,10,0,17,63,7,0,9,10,0,56,2,49,0,64,28,0,0,0,0,0,0,0,0,11,0,56,3,18,2,56,4,2,1,0,0,0,1,10,11,0,16,0,20,7,0,33,4,7,5,9,7,1,39,2,2,1,4,0,1,16,10,1,16,0,20,7,0,35,4,7,5,11,11,1,1,7,2,39,7,0,11,1,15,0,21,2,3,1,4,0,37,117,10,3,46,17,1,10,3,16,1,20,12,35,10,35,7,9,35,4,12,5,24,11,3,1,11,1,1,11,19,1,11,18,1,11,2,1,7,5,39,10,3,46,56,5,10,3,16,1,20,12,20,11,4,12,29,56,6,17,56,12,30,11,5,12,31,11,6,12,32,11,7,12,33,17,54,12,34,17,54,12,21,11,13,12,22,11,14,12,23,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,24,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,25,11,2,17,60,12,26,11,8,11,10,11,11,11,12,11,9,18,8,12,27,11,15,11,16,11,17,18,9,12,28,11,20,11,29,11,30,11,31,11,32,11,33,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,34,11,21,11,24,11,25,11,26,11,22,11,23,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,27,11,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,12,37,10,3,15,2,10,35,11,37,56,8,11,35,49,1,22,11,3,15,1,21,11,18,56,9,12,36,11,1,11,36,11,19,56,10,2,4,1,4,0,1,11,10,1,46,17,1,10,2,11,1,15,3,21,11,2,18,11,56,11,2,5,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,4,21,2,6,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,5,21,2,7,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,6,21,2,8,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,7,21,2,9,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,9,21,2,10,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,10,21,2,11,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,11,21,2,12,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,12,21,2,13,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,13,21,2,14,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,15,21,2,15,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,16,21,2,16,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,17,21,2,17,1,0,0,48,36,56,6,17,56,12,3,10,0,16,1,20,12,1,49,0,12,2,10,2,10,1,35,4,33,5,14,10,0,16,2,10,2,56,13,16,18,20,10,3,34,4,24,5,28,11,0,1,7,7,39,11,2,49,1,22,12,2,5,9,11,0,1,2,18,1,0,0,1,4,11,0,16,3,20,2,19,1,0,0,1,4,11,0,16,1,20,2,20,1,0,0,51,23,10,0,16,19,10,1,56,14,32,4,11,11,0,1,64,8,0,0,0,0,0,0,0,0,64,8,0,0,0,0,0,0,0,0,2,11,0,16,19,11,1,56,15,12,2,10,2,16,20,20,11,2,16,21,20,2,21,1,0,0,1,7,11,0,16,2,11,1,56,13,16,22,20,2,22,1,0,0,1,7,11,0,16,2,11,1,56,13,16,18,20,2,23,1,0,0,1,7,11,0,16,2,11,1,56,13,16,4,20,2,24,1,0,0,1,7,11,0,16,2,11,1,56,13,16,5,20,2,25,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,23,20,11,2,16,24,20,2,26,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,25,20,11,2,16,26,20,2,27,1,0,0,52,14,11,0,16,2,11,1,56,13,12,2,10,2,16,27,16,28,20,11,2,16,29,16,28,20,2,28,1,0,0,53,41,11,0,16,2,11,1,56,13,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,4,16,27,16,30,10,2,56,16,4,22,10,4,16,27,16,30,10,2,56,17,20,12,5,10,4,16,29,16,30,10,2,56,16,4,36,11,4,16,29,16,30,11,2,56,17,20,12,3,5,38,11,4,1,11,5,11,3,2,29,1,0,0,1,7,11,0,16,2,11,1,56,13,16,31,20,2,30,1,0,0,1,7,11,0,16,2,11,1,56,13,16,6,20,2,31,1,0,0,1,7,11,0,16,2,11,1,56,13,16,7,20,2,32,1,0,0,1,7,11,0,16,2,11,1,56,13,16,32,20,2,33,1,0,0,52,26,11,0,16,2,11,1,56,13,12,2,10,2,16,8,16,9,20,10,2,16,8,16,10,20,10,2,16,8,16,11,20,10,2,16,8,16,12,20,11,2,16,8,16,13,20,2,34,1,0,0,52,18,11,0,16,2,11,1,56,13,12,2,10,2,16,14,16,15,20,10,2,16,14,16,16,20,11,2,16,14,16,17,20,2,35,3,0,0,45,17,10,0,46,17,1,11,0,15,2,11,1,56,12,12,4,11,3,10,4,15,23,21,11,2,11,4,15,24,21,2,36,3,0,0,45,29,10,0,46,17,1,11,0,15,2,11,1,56,12,12,6,11,2,10,6,15,26,21,11,3,10,6,15,25,21,11,4,10,6,15,31,21,10,6,16,32,20,11,5,22,11,6,15,32,21,2,37,3,0,0,54,31,10,0,46,17,1,11,0,15,2,11,1,56,12,12,5,10,5,15,27,12,6,11,5,15,29,12,4,10,6,16,28,20,11,2,22,11,6,15,28,21,10,4,16,28,20,11,3,22,11,4,15,28,21,2,38,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,42,2,39,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,43,2,40,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,42,2,41,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,43,2,42,0,0,0,14,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,0,15,30,11,1,11,3,10,2,22,56,19,10,0,16,28,20,11,2,22,11,0,15,28,21,2,43,0,0,0,14,37,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,3,10,2,38,4,17,5,21,11,0,1,7,6,39,10,0,15,30,11,1,11,3,10,2,23,56,19,10,0,16,28,20,11,2,23,11,0,15,28,21,2,44,3,0,0,45,14,11,0,15,2,11,1,56,12,12,3,10,3,16,32,20,11,2,22,11,3,15,32,21,2,45,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,64,8,0,0,0,0,0,0,0,0,11,3,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,21,14,1,56,22,32,4,37,11,5,15,21,11,1,68,8,5,39,11,5,1,2,46,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,21,14,1,56,23,12,3,4,17,11,4,15,21,11,3,56,24,1,5,19,11,4,1,2,47,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,11,3,64,8,0,0,0,0,0,0,0,0,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,20,14,1,56,22,32,4,37,11,5,15,20,11,1,68,8,5,39,11,5,1,2,48,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,20,14,1,56,23,12,3,4,17,11,4,15,20,11,3,56,24,1,5,19,11,4,1,2,49,1,0,0,61,58,10,2,10,3,12,8,46,11,8,17,22,56,6,17,56,33,4,11,5,21,11,2,1,11,1,1,11,4,1,11,7,1,7,8,39,11,2,15,2,11,3,56,12,15,32,12,10,10,4,10,10,20,52,12,9,46,11,9,56,25,12,11,10,5,12,12,11,5,10,11,35,4,44,11,11,12,12,10,10,20,10,12,77,23,11,10,21,11,1,11,4,11,12,11,6,11,7,56,26,2,50,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,2,1,2,4,2,3,2,2,3,4,3,5,3,13,3,14,3,16,8,0,8,1,8,2,8,3,8,4,3,17,9,0,9,1,9,2,3,2,2,6,4,0,4,1,3,1,3,6,3,7,3,8,3,9,3,10,7,1,3,11,7,0,3,12,3,15,0,81,0],[161,28,235,11,6,0,0,0,8,1,0,12,2,12,12,3,24,75,5,99,67,7,166,1,189,2,8,227,3,96,6,195,4,44,12,239,4,164,5,0,10,0,23,0,21,2,17,1,11,1,16,1,2,12,0,3,1,8,0,4,0,8,0,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,6,3,1,0,0,7,3,1,0,0,9,4,1,0,0,4,4,1,0,1,12,0,8,0,1,13,0,3,0,1,15,0,3,0,2,19,6,1,0,2,20,3,1,0,2,22,3,1,0,3,14,10,11,0,5,18,12,13,0,2,7,8,0,2,1,15,3,7,8,0,2,15,2,15,15,4,6,8,2,6,8,1,15,2,7,15,15,15,15,15,15,15,0,6,15,15,15,15,15,15,5,15,15,15,15,15,2,2,15,3,6,8,2,6,8,1,2,3,1,15,2,2,3,2,1,3,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,20,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,9,103,101,116,95,105,110,100,101,120,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,4,109,97,116,104,6,111,114,97,99,108,101,3,112,111,119,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,153,183,0,0,0,0,0,0,0,1,0,0,5,31,10,0,10,1,17,9,12,7,12,8,11,0,11,1,17,8,12,3,12,4,11,7,11,3,17,12,12,5,11,8,11,4,17,12,12,6,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,29,11,5,11,6,17,11,12,2,11,2,2,1,1,0,0,7,37,10,0,10,1,17,7,12,6,1,12,4,12,5,12,3,11,0,11,1,17,0,12,7,10,7,10,6,35,4,23,11,3,11,7,11,5,17,12,22,12,2,5,35,11,3,10,6,11,5,17,12,22,11,7,11,6,23,11,4,17,12,22,12,2,11,2,2,2,1,0,0,3,20,10,0,10,1,17,7,1,12,3,1,1,1,11,0,11,1,17,0,12,4,11,2,11,4,17,12,17,10,11,3,23,17,12,2,3,1,0,0,5,60,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,17,10,2,10,0,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,5,11,1,7,0,26,12,6,10,6,10,6,17,12,12,3,10,3,10,6,17,12,12,2,10,0,10,4,24,11,3,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,7,10,0,11,4,24,11,5,24,11,2,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,17,10,11,6,11,0,24,22,11,7,22,11,8,22,2,4,1,0,0,6,8,17,10,11,1,11,0,24,7,0,26,22,2,5,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,11,5,24,6,10,0,0,0,0,0,0,0,11,4,17,14,77,26,2,6,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,6,10,0,0,0,0,0,0,0,11,4,17,14,77,24,11,5,26,2,0],[161,28,235,11,6,0,0,0,9,1,0,18,2,18,18,3,36,169,1,4,205,1,4,5,209,1,165,2,7,246,3,149,6,8,139,10,128,1,6,139,11,10,12,149,11,225,14,0,16,0,9,0,38,0,43,0,41,3,37,1,45,2,4,2,10,2,1,12,1,0,1,3,3,12,0,5,2,8,0,8,0,8,0,0,17,0,1,1,0,0,21,2,1,0,0,22,2,1,0,0,20,3,1,0,0,24,3,1,0,0,19,4,1,0,0,23,4,1,0,0,18,5,1,0,0,6,6,7,0,0,13,8,7,1,0,0,14,9,1,0,0,15,10,1,0,0,12,9,1,0,1,5,7,1,0,1,7,7,1,0,1,8,25,1,0,2,36,13,14,1,0,3,25,22,1,0,3,26,28,34,0,3,27,28,7,0,3,28,28,7,0,3,29,22,14,0,3,30,28,29,0,3,31,22,19,0,3,32,28,7,0,3,33,17,18,0,3,34,26,7,0,4,39,15,1,0,4,40,7,1,0,4,42,7,1,0,6,11,20,21,1,0,7,35,15,1,0,8,44,31,14,0,16,12,30,19,9,6,8,3,7,8,1,6,8,2,7,11,0,1,9,0,5,2,3,3,1,1,15,7,6,8,3,6,8,2,7,8,1,5,2,15,1,7,6,8,3,6,8,2,7,8,1,2,5,15,1,6,6,8,3,7,8,1,2,5,15,1,7,6,8,3,7,8,1,6,8,2,5,2,15,1,3,6,8,3,7,8,1,2,2,15,15,7,6,8,3,7,8,1,7,11,0,1,9,0,2,3,3,1,6,6,8,3,7,8,1,2,15,15,1,7,6,8,3,7,8,1,2,15,15,15,1,9,1,3,3,15,15,15,15,3,3,1,9,0,2,6,11,0,1,9,0,3,1,3,0,11,5,2,6,2,10,2,15,10,2,15,3,3,15,15,2,6,8,1,5,2,10,2,10,2,1,2,2,6,10,9,0,6,9,0,1,1,2,6,8,1,2,9,5,6,2,15,3,10,2,3,15,10,2,15,3,2,15,2,4,6,8,3,6,8,2,15,2,3,7,8,1,2,5,11,5,6,2,10,2,15,15,10,2,15,3,3,15,15,2,7,8,1,2,3,15,15,15,10,2,15,15,15,15,3,3,15,15,15,1,6,8,3,7,1,3,3,15,3,3,15,6,15,15,15,15,15,15,5,15,15,15,15,15,7,15,15,15,15,15,15,15,5,67,108,111,99,107,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,23,99,97,108,99,117,108,97,116,101,95,99,117,114,114,101,110,116,95,105,110,100,101,120,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,28,100,121,110,97,109,105,99,95,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,21,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,97,112,121,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,18,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,111,114,21,100,121,110,97,109,105,99,95,104,101,97,108,116,104,95,102,97,99,116,111,114,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,31,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,36,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,30,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,25,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,23,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,3,109,97,120,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,4,112,111,111,108,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,201,175,0,0,0,0,0,0,0,1,0,0,11,99,10,6,6,0,0,0,0,0,0,0,0,36,4,9,10,7,6,0,0,0,0,0,0,0,0,36,12,9,5,11,9,12,9,11,9,32,4,15,5,25,11,1,1,11,3,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,17,10,6,6,0,0,0,0,0,0,0,0,36,4,38,10,3,11,6,12,10,46,11,10,56,0,12,17,6,0,0,0,0,0,0,0,0,12,16,10,7,6,0,0,0,0,0,0,0,0,36,4,52,11,3,11,7,12,11,46,11,11,56,0,12,16,5,54,11,3,1,10,0,10,2,10,1,10,4,10,5,10,17,77,10,8,17,1,12,13,10,0,10,2,10,1,10,4,10,5,11,16,77,10,8,17,2,12,14,11,0,11,1,11,2,11,4,11,5,11,17,77,11,8,17,7,12,15,10,14,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,95,11,13,11,14,17,28,11,15,17,29,12,12,5,97,17,31,12,12,11,12,2,1,1,0,0,16,86,10,2,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,17,6,0,0,0,0,0,0,0,0,12,14,10,12,12,10,14,12,14,4,56,1,32,4,31,10,6,4,31,13,10,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,10,14,10,15,35,4,78,5,36,14,10,10,14,66,19,12,9,10,2,10,9,20,12,8,46,11,8,17,17,12,16,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,9,20,33,4,57,10,5,12,13,10,0,10,1,10,2,11,9,20,10,3,11,13,10,6,17,3,12,11,11,17,11,11,11,16,17,29,22,12,17,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,2,1,11,1,1,11,0,1,11,17,2,2,1,0,0,23,76,10,2,10,3,12,7,46,11,7,17,25,12,14,1,14,14,65,19,12,12,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,6,0,0,0,0,0,0,0,0,12,10,10,14,12,11,14,14,14,4,56,1,32,4,31,10,6,4,31,13,11,10,4,68,19,11,12,6,1,0,0,0,0,0,0,0,22,12,12,10,10,10,12,35,4,68,5,36,14,11,10,10,66,19,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,10,4,10,8,20,33,4,49,10,5,12,9,10,0,10,1,10,2,11,8,20,10,3,11,9,10,6,17,4,12,13,11,15,11,13,22,12,15,11,10,6,1,0,0,0,0,0,0,0,22,12,10,5,31,11,2,1,11,1,1,11,0,1,11,15,2,3,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,5,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,4,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,6,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,5,1,0,0,7,27,10,1,10,2,11,3,17,26,1,12,7,11,5,4,13,11,7,11,4,22,12,7,5,17,11,7,11,4,23,12,7,11,0,11,1,11,2,17,8,1,12,6,11,7,11,6,17,29,2,6,1,0,0,7,27,10,1,10,2,11,3,17,26,12,6,1,11,5,4,13,11,6,11,4,22,12,6,5,17,11,6,11,4,23,12,6,11,0,11,1,11,2,17,8,12,7,1,11,6,11,7,17,29,2,7,1,0,0,27,91,10,1,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,6,0,0,0,0,0,0,0,0,12,14,10,12,12,9,14,12,14,4,56,1,32,4,27,13,9,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,10,14,10,15,35,4,81,5,36,14,9,10,14,66,19,12,8,10,1,10,8,20,17,22,12,16,1,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,8,20,33,4,56,10,5,12,13,10,0,10,2,10,1,11,8,20,10,3,11,13,10,6,17,3,12,17,11,10,10,17,11,16,17,29,22,12,10,11,11,11,17,22,12,11,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,1,1,11,2,1,11,0,1,11,10,11,11,17,28,2,8,1,0,0,30,42,11,0,17,32,12,8,10,1,10,2,12,3,46,11,3,17,21,12,9,10,1,10,2,17,20,12,4,12,6,11,1,11,2,17,19,12,5,12,7,11,8,11,9,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,12,10,12,11,5,17,13,11,4,17,29,12,10,11,12,11,7,17,14,11,6,17,29,12,11,11,10,11,11,2,9,1,0,0,32,76,10,4,6,0,0,0,0,0,0,0,0,36,4,9,10,5,6,0,0,0,0,0,0,0,0,36,12,7,5,11,9,12,7,11,7,32,4,15,5,23,11,1,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,12,10,4,6,0,0,0,0,0,0,0,0,36,4,36,10,2,11,4,12,8,46,11,8,56,0,12,12,6,0,0,0,0,0,0,0,0,12,11,10,5,6,0,0,0,0,0,0,0,0,36,4,50,11,2,11,5,12,9,46,11,9,56,0,12,11,5,52,11,2,1,10,0,10,1,10,3,10,12,77,10,11,77,10,6,17,10,12,10,11,0,11,1,11,3,10,10,11,12,77,11,11,77,11,6,17,11,12,13,11,10,11,13,2,10,1,0,0,33,41,10,1,10,2,17,18,12,10,1,12,8,12,9,12,7,11,0,11,1,11,2,11,3,11,4,11,5,17,12,12,11,10,11,10,10,35,4,27,11,7,11,11,11,9,17,29,22,12,6,5,39,11,7,10,11,11,9,17,29,22,11,11,11,10,23,11,8,17,29,22,12,6,11,6,2,11,1,0,0,7,24,10,1,10,2,17,18,1,12,7,1,1,1,11,0,11,1,11,2,11,4,11,5,11,6,17,12,12,8,11,3,11,8,17,29,17,27,11,7,23,17,29,2,12,1,0,0,35,62,10,1,10,2,17,24,12,11,12,12,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,5,4,16,11,12,11,3,22,12,12,5,20,11,12,11,3,23,12,12,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,35,11,5,4,31,11,11,11,4,22,12,11,5,35,11,11,11,4,23,12,11,11,0,11,1,11,2,17,8,12,7,12,8,11,12,11,8,17,29,12,10,11,11,11,7,17,29,12,9,10,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,56,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,5,60,11,9,11,10,17,28,12,6,11,6,2,0],[161,28,235,11,6,0,0,0,14,1,0,30,2,30,66,3,96,181,1,4,149,2,46,5,195,2,164,3,7,231,5,187,6,8,162,12,96,6,130,13,94,10,224,13,116,11,212,14,2,12,214,14,189,15,13,147,30,40,14,187,30,8,15,195,30,2,0,44,0,72,0,62,0,64,1,18,1,78,2,21,2,26,2,27,2,36,2,53,2,73,2,76,2,77,0,82,0,4,12,1,0,1,0,6,4,0,0,3,12,0,0,7,3,0,0,5,3,0,1,8,12,0,4,9,7,0,5,12,7,0,6,0,4,1,0,1,7,1,8,0,8,2,12,1,0,1,10,13,4,0,11,10,12,2,7,1,4,1,13,11,2,0,0,47,0,1,0,0,67,2,1,0,0,66,2,1,0,0,15,3,1,1,0,0,79,4,1,0,0,24,5,6,0,0,25,7,1,1,0,0,39,8,9,0,0,40,10,11,0,0,33,12,13,0,1,41,46,37,0,1,42,47,37,0,2,60,1,34,0,2,61,37,34,0,3,51,37,34,0,5,38,1,36,1,0,5,48,36,33,0,6,69,49,40,1,0,7,74,32,9,0,8,37,50,51,1,0,9,34,22,1,1,3,10,52,0,14,0,11,14,26,1,2,7,4,11,22,24,45,2,7,4,11,23,27,28,2,7,4,11,29,24,25,2,7,4,11,52,0,18,2,7,4,11,63,27,43,2,7,4,12,58,52,1,1,12,12,68,22,1,1,8,13,65,15,16,0,14,70,39,40,1,0,26,17,26,19,29,21,25,17,22,17,24,17,20,29,20,30,25,19,22,19,24,19,15,22,26,38,31,22,29,41,25,38,27,38,22,38,23,19,23,38,17,22,19,22,28,51,1,7,8,13,0,4,7,8,2,15,1,7,8,13,9,7,8,2,6,8,9,2,3,3,11,10,1,9,0,3,2,7,8,13,5,7,8,2,6,8,9,7,8,5,2,5,5,6,8,2,7,8,5,3,2,5,2,10,15,10,15,6,7,8,2,7,11,0,1,9,0,6,8,9,7,8,5,5,7,8,13,2,6,8,2,2,1,3,3,6,8,2,2,3,4,3,3,15,2,5,6,8,2,7,8,5,6,8,9,2,5,3,10,8,6,10,15,10,2,1,8,11,1,6,8,13,1,5,2,15,1,1,11,12,2,9,0,9,1,2,2,8,1,1,2,1,8,2,1,9,0,1,7,1,2,6,11,12,2,9,0,9,1,9,0,1,1,3,7,11,12,2,9,0,9,1,9,0,9,1,2,7,11,12,2,9,0,9,1,9,0,1,7,9,1,1,8,3,1,8,4,4,1,11,8,1,9,0,3,7,8,1,1,6,8,9,1,8,6,1,15,1,11,12,2,5,15,1,8,7,2,15,15,2,5,15,3,11,10,1,9,0,3,7,8,13,1,11,8,1,9,0,1,11,0,1,9,0,17,7,8,5,3,2,5,5,5,3,3,7,15,15,10,15,7,11,12,2,5,15,3,7,8,1,15,10,15,7,11,12,2,5,15,1,9,1,18,6,11,12,2,5,15,3,3,15,15,10,15,15,6,11,12,2,5,15,3,6,8,1,15,15,3,15,15,15,15,10,15,1,6,9,1,2,7,8,5,2,3,7,8,5,2,5,9,5,15,3,7,8,1,15,15,6,11,12,2,5,15,15,7,11,12,2,5,15,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,13,1,11,10,1,9,0,2,9,0,5,1,6,8,1,10,10,8,6,3,3,3,10,2,6,8,1,10,15,15,6,11,12,2,5,15,10,15,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,9,73,110,99,101,110,116,105,118,101,12,73,110,99,101,110,116,105,118,101,66,97,108,16,80,111,111,108,65,100,109,105,110,83,101,116,116,105,110,103,8,80,111,111,108,73,110,102,111,16,80,111,111,108,79,119,110,101,114,83,101,116,116,105,110,103,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,3,97,100,100,8,97,100,100,95,112,111,111,108,5,97,100,109,105,110,6,97,100,109,105,110,115,5,97,115,99,105,105,5,97,115,115,101,116,6,97,115,115,101,116,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,24,99,97,108,99,95,112,111,111,108,95,117,112,100,97,116,101,95,114,101,119,97,114,100,115,12,99,108,97,105,109,95,114,101,119,97,114,100,5,99,108,111,99,107,4,99,111,105,110,10,99,111,105,110,95,116,121,112,101,115,8,99,111,110,116,97,105,110,115,7,99,114,101,97,116,111,114,11,99,117,114,114,101,110,116,95,105,100,120,18,100,105,115,116,114,105,98,117,116,101,100,95,97,109,111,117,110,116,6,101,97,114,110,101,100,4,101,109,105,116,9,101,110,100,95,116,105,109,101,115,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,14,103,101,116,95,112,111,111,108,95,99,111,117,110,116,13,103,101,116,95,112,111,111,108,95,105,110,102,111,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,9,105,110,99,101,110,116,105,118,101,13,105,110,100,101,120,95,114,101,119,97,114,100,115,19,105,110,100,101,120,95,114,101,119,97,114,100,115,95,112,97,105,100,115,4,105,110,105,116,11,105,110,116,111,95,115,116,114,105,110,103,16,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,7,108,101,110,100,105,110,103,3,109,117,108,3,110,101,119,6,111,98,106,101,99,116,10,111,114,97,99,108,101,95,105,100,115,5,111,119,110,101,114,6,111,119,110,101,114,115,5,112,111,111,108,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,9,115,97,102,101,95,109,97,116,104,6,115,101,110,100,101,114,9,115,101,116,95,97,100,109,105,110,9,115,101,116,95,111,119,110,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,11,115,116,97,114,116,95,116,105,109,101,115,7,115,116,111,114,97,103,101,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,13,116,111,116,97,108,95,115,117,112,112,108,121,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,13,117,112,100,97,116,101,95,114,101,119,97,114,100,16,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,22,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,95,112,97,105,100,115,5,117,116,105,108,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,153,183,0,0,0,0,0,0,3,8,154,183,0,0,0,0,0,0,3,8,155,183,0,0,0,0,0,0,3,8,156,183,0,0,0,0,0,0,3,8,157,183,0,0,0,0,0,0,3,8,158,183,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,43,8,11,19,2,31,3,32,15,21,11,8,1,9,0,1,2,12,43,2,49,3,28,10,8,6,71,10,3,35,10,3,75,10,15,59,10,15,45,10,15,46,10,11,12,2,5,15,80,10,11,12,2,5,15,81,10,11,12,2,5,15,54,10,2,2,2,6,43,8,11,30,5,56,11,12,2,15,1,17,11,12,2,15,1,57,11,12,2,2,8,1,20,10,2,3,2,3,65,5,55,15,83,1,4,2,3,65,5,16,15,83,1,0,22,0,0,0,0,1,15,10,0,17,21,10,0,46,17,30,10,0,56,0,10,0,56,0,11,0,56,1,64,20,0,0,0,0,0,0,0,0,18,2,56,2,2,1,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,1,10,1,56,3,32,4,27,11,0,15,1,10,1,10,2,56,4,5,35,11,0,15,1,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,3,56,6,2,2,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,2,10,1,56,3,32,4,27,11,0,15,2,10,1,10,2,56,4,5,35,11,0,15,2,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,4,56,7,2,3,1,4,0,31,139,1,10,0,16,0,20,10,8,46,17,30,33,4,9,5,17,11,0,1,11,8,1,11,1,1,7,0,39,10,3,11,1,17,18,36,4,27,10,4,10,3,36,12,9,5,29,9,12,9,11,9,4,32,5,38,11,0,1,11,8,1,7,1,39,10,0,16,3,10,2,56,8,32,4,65,10,0,15,3,10,2,10,2,6,0,0,0,0,0,0,0,0,64,33,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,20,0,0,0,0,0,0,0,0,18,1,56,9,10,0,15,4,10,2,68,20,11,0,15,3,10,2,56,10,12,12,10,12,16,5,65,33,12,11,10,12,15,5,56,11,17,16,68,33,10,12,15,6,10,3,68,9,10,12,15,7,10,4,68,9,10,12,15,8,10,6,77,68,34,10,12,15,9,10,6,77,11,4,11,3,23,77,17,13,68,34,10,12,15,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,34,10,12,15,11,10,8,56,12,68,35,10,12,15,12,10,8,56,12,68,35,10,12,15,13,10,8,56,12,68,35,11,12,15,14,11,7,68,20,11,5,11,6,10,8,56,13,12,10,11,8,17,21,11,2,11,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,10,57,0,56,14,2,4,3,0,0,42,118,10,0,16,3,10,3,56,8,4,111,11,1,17,18,12,11,10,0,11,2,10,11,10,3,10,4,12,8,12,7,12,6,12,5,46,11,5,11,6,11,7,11,8,17,5,12,20,12,15,11,0,15,3,11,3,56,10,12,18,11,11,10,18,15,15,21,10,18,16,5,65,33,12,17,6,0,0,0,0,0,0,0,0,12,12,10,12,10,17,35,4,108,5,45,14,15,10,12,66,34,20,12,14,14,20,10,12,66,34,20,12,19,10,18,15,10,10,12,67,34,12,13,10,14,11,13,21,10,18,15,11,10,12,67,35,12,16,10,16,10,4,12,9,46,11,9,56,15,4,79,10,16,10,4,56,16,1,11,16,10,4,11,14,56,17,10,18,15,12,10,12,67,35,12,21,10,21,10,4,12,10,46,11,10,56,15,4,99,10,21,10,4,56,16,1,11,21,10,4,11,19,56,17,11,12,6,1,0,0,0,0,0,0,0,22,12,12,5,40,11,18,1,5,117,11,2,1,11,0,1,11,1,1,2,5,0,0,0,44,166,1,11,0,16,3,10,3,56,18,12,14,10,14,16,5,65,33,12,13,6,0,0,0,0,0,0,0,0,12,7,64,34,0,0,0,0,0,0,0,0,12,10,64,34,0,0,0,0,0,0,0,0,12,22,10,7,10,13,35,4,159,1,5,20,10,14,16,6,10,7,66,9,20,12,17,10,17,10,14,16,15,20,35,4,36,10,14,16,15,20,12,17,10,14,16,7,10,7,66,9,20,12,6,10,2,10,6,35,4,48,10,2,12,6,10,14,16,9,10,7,66,34,20,12,15,10,14,16,10,10,7,66,34,20,12,9,10,17,10,6,35,4,90,11,6,11,17,23,77,12,19,10,1,10,3,17,10,1,12,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,10,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,15,11,19,17,14,11,20,26,12,8,11,9,11,8,22,12,9,13,10,10,9,68,34,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,21,10,4,7,6,34,4,151,1,10,14,16,12,10,7,66,35,12,5,10,5,10,4,56,15,4,114,11,5,10,4,56,19,20,12,21,5,116,11,5,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,14,16,11,10,7,66,35,12,12,10,12,10,4,56,15,4,133,1,11,12,10,4,56,19,20,12,11,5,135,1,11,12,1,10,1,10,3,10,4,17,11,1,12,18,11,9,11,11,23,11,18,24,12,16,11,21,11,16,22,12,21,13,22,11,21,68,34,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,15,11,1,1,11,14,1,11,10,11,22,2,6,1,4,0,48,105,10,0,11,2,11,3,10,1,55,0,20,10,4,17,4,11,0,15,3,10,1,55,0,20,56,10,12,9,10,1,55,1,20,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,9,16,12,10,8,66,35,12,12,10,12,10,4,56,15,4,36,11,12,10,4,56,19,20,12,11,5,38,11,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,9,15,13,10,8,67,35,12,14,10,14,10,4,12,6,46,11,6,56,15,4,56,10,14,10,4,56,16,12,13,11,14,10,4,10,11,56,17,11,11,11,13,23,17,12,26,12,7,11,9,16,8,11,8,66,34,20,12,10,10,1,55,2,20,10,7,22,11,10,37,4,81,5,87,11,5,1,11,1,1,7,4,39,10,1,55,2,20,10,7,22,10,1,54,2,21,11,1,54,3,11,7,52,56,20,11,5,56,21,11,4,56,22,2,7,1,0,0,9,19,6,0,0,0,0,0,0,0,0,12,2,10,0,16,3,10,1,56,8,4,15,11,0,16,3,11,1,56,18,16,5,65,33,12,2,5,17,11,0,1,11,2,2,8,1,0,0,53,47,10,0,16,3,10,1,56,8,4,6,5,10,11,0,1,7,2,39,11,0,16,3,11,1,56,18,12,3,10,3,16,5,65,33,10,2,36,4,22,5,26,11,3,1,7,2,39,10,3,16,6,10,2,66,9,20,10,3,16,7,10,2,66,9,20,10,3,16,9,10,2,66,34,20,11,3,16,14,11,2,66,20,20,2,9,1,0,0,54,97,64,33,0,0,0,0,0,0,0,0,12,5,64,34,0,0,0,0,0,0,0,0,12,14,64,20,0,0,0,0,0,0,0,0,12,9,10,0,16,3,10,3,56,8,4,87,11,2,17,18,12,6,10,0,11,1,11,6,10,3,10,4,17,5,12,11,1,11,0,16,3,11,3,56,18,12,10,10,10,16,5,65,33,12,8,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,84,5,38,10,10,16,13,10,7,66,35,12,13,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,10,13,10,4,56,15,4,55,11,13,10,4,56,19,20,12,12,5,57,11,13,1,13,5,10,10,16,5,10,7,66,33,20,68,33,13,14,14,11,10,7,66,34,20,11,12,23,68,34,13,9,10,10,16,14,10,7,66,20,20,68,20,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,33,11,10,1,5,93,11,1,1,11,0,1,11,2,1,11,5,11,14,11,9,2,2,1,2,2,2,3,2,4,2,5,1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,1,11,1,1,0,1,0,2,0,3,0,4,16,22,17,22,18,22,19,22,0,50,0],[161,28,235,11,6,0,0,0,9,1,0,10,2,10,12,3,22,82,4,104,4,5,108,83,7,191,1,154,2,8,217,3,64,6,153,4,70,12,223,4,237,4,0,22,0,15,0,13,1,3,1,16,1,0,12,0,3,1,7,0,4,2,7,0,0,18,0,1,1,0,0,21,0,1,1,0,0,17,0,1,1,0,0,20,0,1,1,0,0,19,2,1,2,0,0,1,5,8,10,0,1,6,7,6,0,1,7,8,9,0,1,8,8,10,0,1,9,8,9,0,2,11,1,10,0,2,12,9,10,0,2,14,9,10,0,4,4,1,5,1,0,4,10,5,6,0,13,4,13,14,3,7,8,0,2,15,0,4,7,8,0,2,2,15,7,7,8,0,2,15,15,15,15,15,1,9,0,1,8,2,1,8,1,2,6,8,0,2,2,7,8,0,2,2,15,15,1,15,8,7,8,0,2,15,15,15,15,15,15,9,7,8,0,2,15,15,15,15,15,15,15,4,7,8,0,2,7,8,0,2,1,9,1,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,5,97,115,99,105,105,3,103,101,116,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,13,103,101,116,95,99,111,105,110,95,116,121,112,101,9,103,101,116,95,105,110,100,101,120,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,11,105,110,116,111,95,115,116,114,105,110,103,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,9,116,121,112,101,95,110,97,109,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,225,171,0,0,0,0,0,0,3,8,226,171,0,0,0,0,0,0,3,8,227,171,0,0,0,0,0,0,3,8,228,171,0,0,0,0,0,0,3,8,229,171,0,0,0,0,0,0,3,8,230,171,0,0,0,0,0,0,3,8,231,171,0,0,0,0,0,0,0,1,0,0,3,58,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,1,12,8,10,0,10,1,17,7,1,12,5,11,8,11,5,17,12,12,7,11,0,11,1,17,8,12,9,11,7,11,2,22,17,10,24,12,6,11,9,11,6,38,4,55,5,57,7,1,39,2,1,1,0,0,11,54,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,10,11,0,11,1,17,7,12,6,12,7,11,10,11,7,17,12,12,9,11,5,11,6,17,12,12,8,11,9,11,8,11,2,22,38,4,51,5,53,7,3,39,2,2,1,0,0,12,71,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,11,10,0,10,1,17,7,12,6,12,8,11,11,11,8,17,12,12,10,11,5,11,6,17,12,12,9,10,9,10,2,22,10,10,35,4,51,5,55,11,0,1,7,3,39,11,9,11,2,22,11,10,17,11,12,7,11,0,11,1,17,5,11,7,38,4,68,5,70,7,2,39,2,3,1,0,0,8,23,11,0,11,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,15,7,4,39,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,20,5,22,7,0,39,2,4,1,0,0,13,40,10,0,11,1,12,5,12,4,56,0,17,14,11,4,46,11,5,17,6,33,4,13,5,17,11,0,1,7,4,39,11,0,11,2,12,7,12,6,56,1,17,14,11,6,46,11,7,17,6,33,4,30,5,32,7,4,39,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,37,5,39,7,0,39,2,0],[161,28,235,11,6,0,0,0,10,1,0,20,2,20,12,3,32,220,2,4,252,2,12,5,136,3,214,2,7,222,5,205,9,8,171,15,128,1,6,171,16,60,12,231,16,222,18,15,197,35,2,0,42,0,11,0,53,0,73,0,48,0,52,3,45,1,74,2,3,2,12,2,2,12,0,6,1,8,0,9,0,8,0,0,18,0,1,1,0,0,21,2,3,1,0,0,17,2,1,1,0,0,20,2,4,1,0,0,19,5,6,2,0,0,0,57,7,1,0,0,56,8,1,0,0,55,9,1,0,0,36,10,1,0,0,15,10,1,0,0,35,10,1,0,0,14,10,1,0,0,39,11,12,0,0,64,13,14,0,0,63,15,4,0,0,16,15,4,0,0,62,11,4,0,0,65,11,4,0,0,67,16,4,0,0,61,16,4,0,0,60,17,4,0,0,66,17,4,0,0,38,17,12,0,0,40,17,12,0,0,8,18,19,0,1,4,44,4,0,1,5,9,4,0,1,6,22,4,0,1,7,22,4,0,1,9,21,4,0,1,10,44,4,0,2,14,10,1,0,2,15,10,1,0,2,22,31,4,0,2,23,9,32,0,2,24,9,22,0,2,25,9,22,0,2,26,31,3,0,2,27,9,6,0,2,28,31,28,0,2,29,27,28,0,2,30,9,22,0,2,31,9,4,0,2,32,39,40,0,2,33,17,22,0,2,34,34,1,0,2,35,10,1,0,2,36,10,1,0,2,37,21,1,0,2,50,17,1,0,2,51,17,1,0,2,55,34,1,0,2,56,33,1,0,2,58,17,1,0,2,59,17,1,0,3,68,21,1,1,0,3,69,21,1,1,0,3,70,25,1,2,0,0,3,71,21,1,1,0,3,72,21,1,1,0,4,46,1,4,0,4,47,22,4,0,4,49,22,4,0,5,44,22,4,0,7,13,46,12,1,0,8,43,1,4,0,9,54,30,3,0,56,20,59,20,55,20,58,20,57,24,64,28,5,6,8,2,7,8,0,2,5,15,0,6,6,8,2,6,8,1,7,8,0,2,5,15,1,3,1,15,7,6,8,2,6,8,1,7,8,0,5,2,2,15,3,15,15,15,2,6,8,2,7,8,0,3,6,8,2,7,8,0,2,2,7,8,0,2,4,7,8,0,2,5,15,4,6,8,2,6,8,1,7,8,0,5,1,1,4,6,8,2,6,8,1,7,8,0,10,5,1,10,15,4,6,8,2,7,8,0,6,8,1,5,5,6,8,2,6,8,1,7,8,0,2,5,3,7,8,0,2,5,7,6,8,2,7,8,0,6,8,1,5,2,2,15,6,15,15,15,15,15,1,1,9,0,3,7,8,0,2,15,2,15,15,6,15,15,1,15,15,15,2,9,0,9,1,4,7,8,0,2,2,15,2,2,2,1,6,8,0,1,2,18,2,15,15,15,15,3,15,15,3,15,15,15,15,15,15,15,15,15,1,6,8,2,2,6,8,0,2,5,15,15,15,15,15,6,7,8,0,2,15,15,3,15,4,7,8,0,2,15,15,4,15,3,3,10,15,1,5,4,15,15,15,15,9,5,6,2,15,15,10,2,3,3,15,15,2,6,8,0,5,2,10,2,10,2,9,5,2,6,2,15,10,2,3,3,15,15,7,5,6,2,3,3,15,10,2,15,3,2,15,2,4,6,8,2,6,8,1,15,2,2,5,10,2,2,6,10,9,0,6,9,0,18,2,15,15,15,15,1,15,15,15,15,15,2,15,15,15,15,15,15,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,7,105,115,95,108,111,97,110,7,108,101,110,100,105,110,103,5,108,111,103,105,99,3,109,97,120,3,109,105,110,6,111,114,97,99,108,101,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,9,115,97,102,101,95,109,97,116,104,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,19,117,112,100,97,116,101,95,115,116,97,116,101,95,111,102,95,97,108,108,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,24,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,95,98,97,116,99,104,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,33,78,0,0,0,0,0,0,3,8,34,78,0,0,0,0,0,0,3,8,35,78,0,0,0,0,0,0,3,8,36,78,0,0,0,0,0,0,3,8,37,78,0,0,0,0,0,0,3,8,38,78,0,0,0,0,0,0,0,3,0,0,1,26,11,0,10,1,17,5,10,1,10,2,10,4,56,0,10,1,10,2,10,3,11,4,17,8,10,1,10,2,10,3,17,22,32,4,22,10,1,10,2,11,3,17,53,11,1,11,2,17,7,2,1,3,0,0,22,92,10,2,10,3,10,4,17,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,16,11,2,1,11,1,1,11,0,1,7,4,39,10,0,10,2,17,5,10,2,10,3,10,5,56,1,10,2,10,3,10,4,17,20,12,7,11,5,10,7,17,63,12,6,10,2,10,3,10,4,10,6,17,9,11,0,11,1,10,2,10,4,17,12,4,44,5,48,11,2,1,7,0,39,10,6,10,7,33,4,61,10,2,10,3,10,4,17,22,4,61,10,2,10,3,10,4,17,49,10,7,10,6,36,4,86,10,7,10,6,23,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,4,86,10,2,10,3,11,7,10,6,23,17,48,10,2,10,3,10,4,17,22,4,86,10,2,10,3,11,4,17,49,11,2,11,3,17,7,11,6,52,2,2,3,0,0,1,37,10,0,10,2,17,5,10,2,10,3,10,5,56,2,10,2,10,3,10,4,11,5,17,10,10,2,10,3,10,4,17,23,32,4,22,10,2,10,3,10,4,17,54,11,0,11,1,10,2,11,4,17,12,4,29,5,33,11,2,1,7,0,39,11,2,11,3,17,7,2,3,3,0,0,6,58,10,2,10,3,10,4,17,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,14,11,2,1,11,0,1,7,5,39,11,0,10,2,17,5,10,2,10,3,10,5,56,3,10,2,10,3,10,4,17,21,12,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,5,12,8,10,6,10,5,35,4,40,10,6,12,8,11,5,10,6,23,12,7,10,2,10,3,10,4,10,8,17,11,11,8,11,6,33,4,53,10,2,10,3,11,4,17,50,11,2,11,3,17,7,11,7,2,4,3,0,0,23,92,10,2,10,5,10,3,17,23,4,6,5,14,11,2,1,11,1,1,11,0,1,7,3,39,10,2,10,4,10,3,17,22,4,20,5,28,11,2,1,11,1,1,11,0,1,7,2,39,10,0,10,2,17,5,10,2,10,5,10,4,10,6,56,4,10,0,10,1,10,2,10,3,17,12,32,4,44,5,52,11,2,1,11,1,1,11,0,1,7,1,39,11,0,10,2,11,1,10,3,10,4,10,5,11,6,17,24,12,9,12,8,12,12,12,7,12,11,12,10,10,2,10,5,10,3,11,11,17,11,10,2,10,4,10,3,11,10,17,9,11,9,4,82,10,2,10,5,11,3,17,50,10,2,11,4,17,7,11,2,11,5,17,7,11,7,11,8,11,12,2,5,0,0,0,26,25,10,1,46,17,40,12,2,49,0,12,3,10,3,10,2,35,4,20,5,11,10,0,10,1,10,3,17,6,11,3,49,1,22,12,3,5,6,11,1,1,11,0,1,2,6,0,0,0,29,97,11,0,17,66,12,8,10,1,10,2,12,3,46,11,3,17,37,12,11,10,8,11,11,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,18,10,1,10,2,17,36,12,4,12,6,10,1,10,2,17,35,12,5,12,7,10,18,11,7,17,28,10,6,17,62,12,13,11,18,11,5,17,27,10,4,17,62,12,12,10,1,10,2,17,34,1,12,14,1,1,1,10,1,10,2,17,41,12,19,12,20,10,19,10,12,10,4,23,17,62,12,9,11,20,10,13,11,6,23,17,62,12,10,11,9,10,12,17,61,12,15,11,10,10,13,17,61,12,17,11,19,10,12,11,4,23,17,62,11,14,17,62,10,12,17,61,12,16,10,1,10,2,11,12,11,13,11,8,10,16,17,52,11,1,11,2,11,17,11,15,11,16,22,17,45,2,7,0,0,0,22,15,10,0,10,1,17,26,12,2,10,0,10,1,10,2,17,29,12,3,11,0,11,1,11,2,11,3,17,51,2,8,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,47,2,9,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,32,2,10,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,46,2,11,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,31,2,12,1,0,0,1,8,11,0,11,2,11,1,11,3,17,14,17,60,38,2,13,1,0,0,35,37,14,3,65,36,12,6,6,0,0,0,0,0,0,0,0,12,5,64,4,0,0,0,0,0,0,0,0,12,7,10,5,10,6,35,4,29,5,12,10,0,10,2,10,1,14,3,10,5,66,36,20,17,14,12,4,13,7,11,4,68,4,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,7,11,2,1,11,1,1,11,0,1,11,7,2,14,1,0,0,37,33,10,0,10,2,10,1,10,3,17,16,12,6,10,0,10,1,10,2,10,3,17,15,12,5,11,0,11,2,11,1,11,3,17,17,12,7,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,29,11,6,11,7,17,61,11,5,17,62,12,4,5,31,17,65,12,4,11,4,2,15,1,0,0,38,72,10,1,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,6,0,0,0,0,0,0,0,0,12,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,10,9,10,10,35,4,56,5,22,14,8,10,9,66,28,12,5,10,1,10,5,20,17,38,12,11,1,1,10,0,10,2,10,1,11,5,20,10,3,17,19,12,12,11,6,10,12,11,11,17,62,22,12,6,11,7,11,12,22,12,7,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,17,11,1,1,11,2,1,11,0,1,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,11,6,11,7,17,61,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,16,1,0,0,41,59,10,2,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,6,0,0,0,0,0,0,0,0,12,9,10,9,10,10,35,4,51,5,20,14,8,10,9,66,28,12,6,10,2,10,6,20,12,5,46,11,5,17,33,12,11,10,0,10,1,10,2,11,6,20,10,3,17,19,12,7,11,12,11,7,11,11,17,62,22,12,12,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,15,11,2,1,11,1,1,11,0,1,11,12,2,17,1,0,0,42,49,10,2,10,3,12,4,46,11,4,17,43,12,9,1,14,9,65,28,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,41,5,20,14,9,10,6,66,28,12,5,10,0,10,1,10,2,11,5,20,10,3,17,18,12,8,11,10,11,8,22,12,10,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,15,11,2,1,11,1,1,11,0,1,11,10,2,18,1,0,0,43,18,10,2,10,3,11,4,17,21,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,19,1,0,0,43,18,10,2,10,3,11,4,17,20,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,20,1,0,0,22,15,10,0,10,1,11,2,17,44,1,12,3,11,0,11,1,17,36,1,12,4,11,3,11,4,17,62,2,21,1,0,0,22,15,10,0,10,1,11,2,17,44,12,3,1,11,0,11,1,17,36,12,4,1,11,3,11,4,17,62,2,22,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,1,12,4,14,4,14,1,56,5,2,23,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,12,4,1,14,4,14,1,56,5,2,24,0,0,0,47,113,10,1,10,4,17,38,1,12,15,12,16,10,0,10,2,10,1,10,4,10,3,17,19,11,16,17,62,12,20,10,0,10,2,10,1,10,5,11,3,17,18,12,19,9,12,12,10,19,10,20,35,4,32,11,19,12,20,8,12,12,10,1,10,5,12,7,46,11,7,17,39,12,18,10,0,10,2,11,6,11,18,17,30,12,21,10,21,10,20,36,4,54,11,21,10,20,23,12,11,5,58,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,11,21,12,20,10,20,11,15,17,62,12,8,11,1,10,4,17,42,12,22,10,8,11,22,17,62,12,23,10,20,10,23,23,12,17,10,0,10,2,10,20,10,4,17,25,12,13,10,0,10,2,11,20,10,5,17,25,12,14,10,0,10,2,11,17,10,4,17,25,12,9,10,0,10,2,11,23,11,4,17,25,12,24,11,0,11,2,11,11,11,8,22,11,5,17,25,12,10,11,13,11,14,11,9,11,24,11,10,11,12,2,0,41,0],[161,28,235,11,6,0,0,0,10,1,0,22,2,22,52,3,74,130,1,4,204,1,38,5,242,1,222,2,7,208,4,238,3,8,190,8,96,6,158,9,10,10,168,9,49,12,217,9,201,4,0,26,0,25,0,30,0,34,0,39,2,32,1,14,1,15,1,19,1,41,0,44,0,3,3,0,0,11,3,0,0,0,3,0,0,8,3,0,0,5,3,0,1,4,12,0,3,6,12,1,0,1,4,9,12,0,5,7,8,0,6,1,8,0,7,2,12,1,0,1,9,10,2,0,0,46,0,1,0,0,16,2,1,1,0,0,47,3,1,1,0,0,13,4,1,1,0,0,35,5,1,1,0,0,29,6,1,2,0,0,1,43,11,1,0,2,20,22,1,1,0,2,21,19,1,1,0,2,22,32,33,2,0,0,2,23,22,28,1,0,2,24,22,16,1,0,3,16,17,1,1,0,3,17,35,1,1,0,3,31,18,16,1,0,3,42,18,16,1,0,3,47,23,1,1,0,4,33,0,7,0,7,45,15,16,1,0,8,18,12,1,1,3,9,37,9,10,0,10,38,13,14,1,0,21,12,18,12,12,12,14,12,8,12,19,20,11,12,15,12,16,12,19,24,7,12,19,26,10,12,19,29,9,31,15,34,16,34,13,34,19,36,1,6,8,7,0,8,6,8,9,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,5,7,8,11,9,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,5,7,8,5,7,8,11,7,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,7,8,11,8,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,11,12,6,8,9,6,8,8,7,8,7,2,7,11,6,1,9,0,2,7,11,6,1,9,1,11,10,1,9,0,5,3,7,8,5,7,8,11,1,1,5,3,3,3,5,11,10,1,9,0,1,6,8,11,1,5,5,7,8,5,6,8,9,7,8,7,2,5,1,9,0,3,11,10,1,9,0,3,7,8,11,1,11,10,1,9,0,1,6,11,10,1,9,0,1,3,3,7,11,6,1,9,0,11,10,1,9,0,7,8,11,2,6,11,6,1,9,0,3,5,6,8,9,7,8,7,2,5,15,1,8,0,6,3,3,3,3,3,5,6,6,8,9,6,8,8,7,8,7,2,5,15,4,7,11,6,1,9,0,3,5,7,8,11,1,8,1,3,3,3,5,1,8,2,8,3,3,15,3,3,3,5,11,10,1,9,0,1,15,1,8,3,14,3,3,3,3,15,15,3,3,3,3,3,5,11,10,1,9,0,15,2,9,0,9,1,7,6,8,9,6,8,8,7,8,7,5,2,2,15,3,15,15,15,1,9,1,2,7,11,6,1,9,0,3,1,8,4,11,66,111,114,114,111,119,69,118,101,110,116,5,67,108,111,99,107,4,67,111,105,110,12,68,101,112,111,115,105,116,69,118,101,110,116,9,73,110,99,101,110,116,105,118,101,20,76,105,113,117,105,100,97,116,105,111,110,67,97,108,108,69,118,101,110,116,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,112,97,121,69,118,101,110,116,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,13,87,105,116,104,100,114,97,119,69,118,101,110,116,6,97,109,111,117,110,116,6,98,111,114,114,111,119,5,99,108,111,99,107,4,99,111,105,110,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,9,105,110,99,101,110,116,105,118,101,7,108,101,110,100,105,110,103,16,108,105,113,117,105,100,97,116,101,95,97,109,111,117,110,116,14,108,105,113,117,105,100,97,116,101,95,117,115,101,114,16,108,105,113,117,105,100,97,116,105,111,110,95,99,97,108,108,5,108,111,103,105,99,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,5,112,97,117,115,101,4,112,111,111,108,5,114,101,112,97,121,7,114,101,115,101,114,118,101,6,115,101,110,100,101,114,10,115,112,108,105,116,95,99,111,105,110,7,115,116,111,114,97,103,101,2,116,111,10,116,120,95,99,111,110,116,101,120,116,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,13,117,112,100,97,116,101,95,114,101,119,97,114,100,5,117,116,105,108,115,5,118,97,108,117,101,15,119,104,101,110,95,110,111,116,95,112,97,117,115,101,100,8,119,105,116,104,100,114,97,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,41,160,0,0,0,0,0,0,0,2,3,36,2,37,5,12,3,1,2,4,36,2,37,5,40,5,12,3,2,2,3,36,2,37,5,12,3,3,2,3,36,2,37,5,12,3,4,2,4,36,2,37,5,28,5,27,3,0,0,0,0,1,8,11,0,17,17,32,4,5,5,7,7,0,39,2,1,1,4,0,8,45,10,1,46,17,0,10,7,46,17,20,12,11,11,6,10,0,10,1,10,3,10,11,17,6,11,4,11,5,10,7,56,0,12,12,14,12,56,1,12,9,10,2,11,12,11,7,56,2,11,2,10,9,12,8,46,11,8,56,3,12,10,11,0,11,1,10,3,10,11,11,10,77,56,4,11,3,11,11,11,9,18,0,56,5,2,2,1,4,0,21,50,10,2,46,17,0,10,8,46,17,20,12,14,11,7,10,0,10,2,10,4,10,14,17,6,10,3,11,5,12,9,46,11,9,56,3,12,13,11,0,11,1,11,2,10,4,11,14,11,13,77,56,6,12,11,10,3,11,11,12,10,46,11,10,56,7,12,12,11,3,10,12,10,6,10,8,56,8,11,4,11,8,46,17,20,11,6,11,12,18,1,56,9,2,3,1,4,0,25,35,10,2,46,17,0,10,6,46,17,20,12,9,10,3,10,5,12,7,46,11,7,56,3,12,8,11,0,11,1,11,2,10,4,10,9,11,8,77,56,10,11,3,10,5,11,9,10,6,56,8,11,4,11,6,46,17,20,11,5,18,2,56,11,2,4,1,4,0,27,65,10,2,46,17,0,10,7,46,17,20,12,14,11,5,11,6,10,7,56,0,12,15,14,15,56,1,12,13,10,3,11,15,10,7,56,2,10,3,10,13,12,8,46,11,8,56,3,12,12,11,0,11,1,11,2,10,4,10,14,11,12,77,56,12,12,10,10,3,11,10,52,12,9,46,11,9,56,7,12,11,10,11,6,0,0,0,0,0,0,0,0,36,4,53,11,3,10,11,11,14,10,7,56,8,5,55,11,3,1,11,4,11,7,46,17,20,11,13,11,11,23,18,3,56,13,2,5,1,4,0,30,90,10,2,46,17,0,10,11,46,17,20,12,23,11,10,10,0,10,2,10,5,10,8,17,6,11,7,11,9,10,11,56,0,12,24,14,24,56,1,12,18,10,4,11,24,10,11,56,2,10,4,11,18,12,12,46,11,12,56,3,12,21,11,0,11,1,11,2,10,8,10,5,11,3,11,21,77,56,14,12,25,12,17,12,16,10,4,11,17,52,12,13,46,11,13,56,7,12,20,11,4,11,20,10,23,10,11,56,8,10,6,11,16,52,12,14,46,11,14,56,15,12,19,10,6,10,19,10,23,11,11,56,16,10,6,11,25,52,12,15,46,11,15,56,15,12,22,11,6,10,22,56,17,11,5,11,23,11,8,11,19,11,22,22,18,4,56,18,2,0]],["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"],"0xb2345915de1f9bd661e9ab27eb27e376cdf6391359ea64fbfdb4550b092c1aa0",{"Result":0}]},{"MoveCall":{"package":"0x0000000000000000000000000000000000000000000000000000000000000002","module":"package","function":"commit_upgrade","type_arguments":[],"arguments":[{"Input":0},{"Result":1}]}}]}},"sender":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57","gas_data":{"payment":[["0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1",26932892,"Ex867bCQkeiTCvcRqhkbAtZWPyVPcMbNRj1acbfyZdAs"]],"owner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57","price":750,"budget":300000000},"expiration":"None"}}},"tx_signatures":["AI5U6xMfN2yyPDsdvVvw1AFxBXD4cd6wejUm9G9Edx8Rnj28g4Hz8Lz2nFW1hEiwVYDED+VQ9Qrkl7DXLfoODwUcypkmsYEh2xu++z3ojPaRBoPqgLGIm3/ZtoRgRAd5fw=="]}],"sender":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57","input_objects":[{"ImmOrOwnedMoveObject":["0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623",10941462,"97EMwmR1yvKzotocnPsNs5gLiHPkDztrM5WsVeE9d1y"]},{"MovePackage":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"MovePackage":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"MovePackage":"0xb2345915de1f9bd661e9ab27eb27e376cdf6391359ea64fbfdb4550b092c1aa0"},{"MovePackage":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"},{"ImmOrOwnedMoveObject":["0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1",26932892,"Ex867bCQkeiTCvcRqhkbAtZWPyVPcMbNRj1acbfyZdAs"]}],"kind":{"ProgrammableTransaction":{"inputs":[{"Object":{"ImmOrOwnedObject":["0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623",10941462,"97EMwmR1yvKzotocnPsNs5gLiHPkDztrM5WsVeE9d1y"]}},{"Pure":[0]},{"Pure":[32,246,193,86,67,237,66,165,149,9,252,108,46,208,117,166,90,184,114,112,210,57,76,234,29,82,22,132,25,179,156,59,27]}],"commands":[{"MoveCall":{"package":"0x0000000000000000000000000000000000000000000000000000000000000002","module":"package","function":"authorize_upgrade","type_arguments":[],"arguments":[{"Input":0},{"Input":1},{"Input":2}]}},{"Upgrade":[[[161,28,235,11,6,0,0,0,7,1,0,2,3,2,30,5,32,6,7,38,34,8,72,32,6,104,50,12,154,1,163,2,0,5,0,0,0,1,0,0,6,0,1,0,0,4,0,1,0,0,1,0,1,0,0,3,0,1,0,0,2,0,1,0,2,15,15,1,15,0,3,97,100,100,3,100,105,118,3,109,105,110,3,109,111,100,3,109,117,108,9,115,97,102,101,95,109,97,116,104,3,115,117,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,233,3,0,0,0,0,0,0,3,8,234,3,0,0,0,0,0,0,3,8,235,3,0,0,0,0,0,0,3,8,236,3,0,0,0,0,0,0,3,8,237,3,0,0,0,0,0,0,0,1,0,0,1,13,10,0,11,1,22,12,2,10,2,11,0,38,4,9,5,11,7,0,39,11,2,2,1,1,0,0,2,11,10,1,10,0,37,4,5,5,7,7,1,39,11,0,11,1,23,2,2,1,0,0,1,21,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,10,1,24,12,2,10,2,11,0,26,11,1,33,4,17,5,19,7,2,39,11,2,2,3,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,5,5,7,7,3,39,11,0,11,1,26,2,4,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,4,39,11,0,11,1,25,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,0],[161,28,235,11,6,0,0,0,9,1,0,10,2,10,16,3,26,47,4,73,12,5,85,63,7,148,1,156,1,8,176,2,64,6,240,2,20,12,132,3,114,0,14,1,3,1,4,1,12,1,13,1,0,4,1,0,1,2,1,12,1,0,1,4,2,2,0,0,10,0,1,1,0,0,11,0,2,1,0,2,5,1,8,1,0,2,6,1,2,1,0,2,9,7,1,1,0,2,15,5,6,1,0,3,7,11,8,1,12,4,8,9,10,0,5,4,4,4,2,4,6,1,0,4,3,4,3,11,1,1,9,0,3,7,8,2,1,11,1,1,9,0,1,11,0,1,9,0,2,3,11,1,1,9,0,1,9,0,1,6,11,1,1,9,0,1,3,3,7,11,1,1,9,0,3,7,8,2,0,1,6,8,2,1,5,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,4,99,111,105,110,12,100,101,115,116,114,111,121,95,122,101,114,111,12,105,110,116,111,95,98,97,108,97,110,99,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,10,115,112,108,105,116,95,99,111,105,110,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,117,116,105,108,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,176,179,0,0,0,0,0,0,3,8,177,179,0,0,0,0,0,0,0,1,0,0,3,44,14,0,56,0,12,3,10,1,6,0,0,0,0,0,0,0,0,36,4,8,5,12,11,2,1,7,0,39,11,3,10,1,38,4,17,5,21,11,2,1,7,1,39,13,0,11,1,10,2,56,1,12,4,14,0,56,0,6,0,0,0,0,0,0,0,0,33,4,37,11,2,1,11,0,56,2,11,4,2,11,0,11,2,46,17,7,56,3,11,4,2,1,1,0,0,8,6,11,0,11,1,11,2,56,4,56,5,2,0],[161,28,235,11,6,0,0,0,14,1,0,18,2,18,54,3,72,145,1,4,217,1,30,5,247,1,203,1,7,194,3,145,4,8,211,7,96,6,179,8,20,10,199,8,67,11,138,9,2,12,140,9,146,3,13,158,12,6,14,164,12,6,15,170,12,4,0,37,1,13,1,47,2,14,2,15,2,23,2,36,2,44,2,46,0,2,12,1,0,1,0,3,12,0,0,5,3,0,0,4,3,0,0,6,3,0,0,7,3,0,1,8,7,0,2,10,7,0,3,0,4,1,0,1,4,1,12,1,0,1,6,11,4,0,8,9,2,0,0,28,0,1,0,0,17,2,1,1,0,0,20,3,1,1,0,0,50,4,1,1,0,0,21,5,1,1,0,0,52,6,1,1,0,0,51,7,1,1,0,0,26,8,9,1,0,0,16,10,11,0,0,35,12,11,1,0,0,48,12,11,1,0,2,25,1,26,1,0,2,30,26,27,0,3,31,25,11,1,0,3,42,29,19,1,0,3,49,32,11,1,0,3,53,1,19,1,0,4,24,30,24,1,0,4,29,24,19,1,0,4,49,23,11,1,0,5,22,18,1,1,3,6,33,0,13,0,7,38,17,1,1,12,7,41,18,1,1,8,8,40,14,15,0,22,16,16,18,23,20,20,21,19,18,18,18,13,18,11,18,20,28,14,18,17,18,20,31,22,24,15,18,7,18,1,7,8,11,0,3,6,8,1,2,7,8,11,3,7,11,0,1,9,0,11,9,1,9,0,7,8,11,4,7,11,0,1,9,0,3,5,7,8,11,2,7,11,0,1,9,0,3,5,7,8,1,7,11,0,1,9,0,3,5,7,8,11,5,6,8,1,7,11,0,1,9,0,3,5,7,8,11,1,6,11,0,1,9,0,1,2,3,3,2,2,1,3,2,6,11,0,1,9,0,3,1,8,10,1,6,8,11,1,5,1,8,1,2,9,0,5,1,9,0,1,11,8,1,9,0,1,11,0,1,9,0,1,8,2,2,11,8,1,9,0,3,1,6,11,9,1,9,0,1,11,9,1,9,0,2,7,11,8,1,9,0,11,8,1,9,0,1,8,7,1,8,6,1,8,4,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,11,1,8,5,1,6,11,8,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,19,80,111,111,108,66,97,108,97,110,99,101,82,101,103,105,115,116,101,114,10,80,111,111,108,67,114,101,97,116,101,11,80,111,111,108,68,101,112,111,115,105,116,12,80,111,111,108,87,105,116,104,100,114,97,119,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,7,99,114,101,97,116,111,114,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,2,105,100,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,7,108,101,110,100,105,110,103,3,110,101,119,10,110,101,119,95,97,109,111,117,110,116,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,9,114,101,99,105,112,105,101,110,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,7,115,116,111,114,97,103,101,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,17,164,0,0,0,0,0,0,3,8,18,164,0,0,0,0,0,0,0,2,4,27,8,10,14,11,8,1,9,0,45,11,8,1,9,0,19,2,1,2,2,27,8,10,18,5,2,2,1,18,5,3,2,4,40,5,12,3,34,3,37,8,6,4,2,3,40,5,12,3,37,8,6,5,2,4,40,5,39,5,12,3,37,8,6,0,18,0,0,0,0,1,11,10,0,17,21,10,0,46,17,24,18,1,11,0,46,17,24,56,0,2,1,3,0,0,1,13,10,2,17,21,56,1,56,1,11,1,57,0,56,2,11,2,46,17,24,18,2,56,3,2,2,3,0,0,22,20,14,1,56,4,12,4,11,1,56,5,12,3,11,0,54,0,11,3,56,6,1,11,2,46,17,24,11,4,56,7,17,12,18,4,56,8,2,3,3,0,0,24,20,11,0,54,0,10,1,56,9,10,3,56,10,12,4,11,3,46,17,24,10,2,11,1,56,7,17,12,18,5,56,11,11,4,11,2,56,12,2,4,3,0,0,19,22,10,0,55,0,56,13,10,1,38,4,7,5,11,11,0,1,7,1,39,10,0,54,0,11,1,56,9,12,2,11,0,54,1,11,2,56,6,1,2,5,1,0,0,1,22,10,1,55,1,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,1,11,2,56,9,11,4,56,10,11,3,56,12,2,6,3,0,0,1,22,10,1,55,0,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,0,11,2,56,9,11,4,56,10,11,3,56,12,2,7,1,0,0,1,4,11,0,55,2,20,2,8,1,0,0,1,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,9,1,0,0,9,8,11,0,56,14,12,2,11,1,11,2,49,9,17,8,2,10,1,0,0,9,8,11,0,56,14,12,2,11,1,49,9,11,2,17,8,2,0,1,0,2,0,3,0,18,1,18,2,18,0,32,0,43,0],[161,28,235,11,6,0,0,0,7,1,0,4,3,4,55,5,59,8,7,67,101,8,168,1,64,6,232,1,200,1,12,176,3,168,5,0,6,1,0,0,4,0,1,0,0,9,0,1,0,0,1,0,1,0,0,2,0,1,0,0,11,2,1,0,0,10,2,1,0,0,7,2,1,0,0,5,2,1,0,0,8,1,1,0,0,12,1,1,0,1,3,0,1,0,0,1,15,2,15,15,1,1,7,97,100,100,114,101,115,115,8,104,97,108,102,95,114,97,121,8,104,97,108,102,95,119,97,100,3,109,97,120,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,10,114,97,121,95,116,111,95,119,97,100,3,119,97,100,7,119,97,100,95,100,105,118,7,119,97,100,95,109,117,108,10,119,97,100,95,116,111,95,114,97,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,100,167,179,182,224,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,178,211,89,91,240,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,77,4,0,0,0,0,0,0,3,8,78,4,0,0,0,0,0,0,3,8,79,4,0,0,0,0,0,0,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,0,2,2,1,0,0,0,2,7,3,2,3,1,0,0,0,2,7,1,2,4,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,1,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,1,22,7,0,26,2,5,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,0,26,37,4,20,5,22,7,5,39,11,0,7,0,24,11,2,22,11,1,26,2,6,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,3,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,3,22,7,2,26,2,7,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,2,26,37,4,20,5,22,7,5,39,11,0,7,2,24,11,2,22,11,1,26,2,8,1,0,0,2,19,7,4,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,1,10,1,11,0,22,12,2,10,2,11,1,38,4,13,5,15,7,6,39,11,2,7,4,26,2,9,1,0,0,1,15,10,0,7,4,24,12,1,10,1,7,4,26,11,0,33,4,11,5,13,7,5,39,11,1,2,0],[161,28,235,11,6,0,0,0,12,1,0,29,2,29,92,3,121,144,3,4,137,4,54,5,191,4,153,3,7,216,7,131,16,8,219,23,96,6,187,24,93,10,152,25,164,1,12,188,26,186,19,13,246,45,66,15,184,46,2,0,120,0,90,0,94,1,22,1,131,1,1,141,1,2,30,2,31,2,47,2,85,2,123,2,127,2,130,1,0,4,12,0,0,11,12,0,0,10,12,0,0,9,4,0,0,20,4,0,0,8,5,0,0,19,5,0,0,15,4,0,0,0,4,0,0,3,4,0,0,12,3,0,0,5,3,0,1,6,12,1,0,1,1,7,12,0,3,13,7,0,4,17,7,0,6,1,8,0,7,2,12,1,0,1,9,18,4,0,10,14,12,2,7,1,4,1,12,16,2,0,0,73,0,1,0,0,144,1,2,1,0,0,143,1,3,1,0,0,74,4,1,1,0,0,115,5,1,0,0,117,6,1,0,0,107,6,1,0,0,112,6,1,0,0,118,6,1,0,0,106,6,1,0,0,113,6,1,0,0,108,6,1,0,0,116,6,1,0,0,114,6,1,0,0,110,6,1,0,0,109,6,1,0,0,111,6,1,0,0,102,2,1,1,0,0,88,2,7,0,0,59,2,8,0,0,64,9,10,0,0,58,11,8,0,0,52,11,12,0,0,60,13,14,0,0,50,13,14,0,0,53,13,15,0,0,55,13,15,0,0,61,13,15,0,0,65,16,15,0,0,56,11,17,0,0,49,11,14,0,0,63,13,14,0,0,62,11,14,0,0,51,13,18,0,0,57,13,19,0,0,133,1,20,1,0,0,134,1,21,1,0,0,68,20,1,0,0,70,22,1,0,0,44,22,1,0,0,69,22,1,0,0,43,22,1,0,0,67,23,1,0,0,42,23,1,0,0,71,24,1,0,0,136,1,16,1,0,0,97,16,1,0,0,135,1,16,1,0,0,96,16,1,0,0,146,1,25,1,1,0,0,45,3,1,0,1,36,43,1,1,0,1,132,1,62,17,1,0,1,145,1,63,1,1,0,2,93,1,14,0,4,48,1,38,1,0,4,75,38,12,0,5,35,57,7,1,0,5,72,57,59,1,0,5,95,60,36,1,0,6,125,40,17,0,7,54,42,8,1,0,8,46,36,1,1,3,9,84,0,26,0,10,21,41,1,2,7,4,10,25,49,50,2,7,4,10,28,46,47,2,7,4,10,35,49,7,2,7,4,10,84,0,33,2,7,4,10,95,46,55,2,7,4,11,91,30,1,1,12,11,119,36,1,1,8,12,105,27,28,0,70,29,70,31,68,32,68,34,71,35,17,36,55,36,68,39,64,32,61,36,51,36,62,44,66,32,65,32,67,34,65,34,67,39,65,39,69,39,64,39,64,34,66,34,57,8,58,8,59,8,52,36,53,36,1,7,8,20,0,1,6,8,2,2,6,8,1,7,8,2,20,6,8,1,6,8,13,6,8,16,7,8,2,2,1,15,15,15,15,15,15,15,15,15,15,15,15,6,11,17,1,9,0,7,8,20,3,6,8,0,7,8,2,1,4,6,8,0,7,8,2,2,15,1,1,1,2,2,6,8,2,5,2,10,2,10,2,2,6,8,2,2,1,8,14,2,7,8,2,2,1,15,2,15,15,3,7,8,2,2,5,1,3,5,15,15,15,15,15,3,15,15,15,4,7,8,2,2,15,15,6,7,8,2,2,15,15,3,15,4,7,8,2,2,5,15,3,7,8,7,5,15,3,7,8,2,2,15,8,6,8,1,6,8,13,7,8,2,2,7,11,12,1,9,0,3,5,7,8,20,1,8,18,1,6,8,20,1,5,1,8,1,2,9,0,5,1,8,0,2,2,8,3,1,11,19,2,9,0,9,1,2,5,8,4,1,8,2,1,9,0,18,2,15,15,15,8,7,8,7,3,8,8,8,9,2,8,14,1,15,15,15,2,2,8,3,1,8,15,2,5,15,1,6,8,16,3,7,11,19,2,9,0,9,1,9,0,9,1,1,6,11,17,1,9,0,3,6,8,13,2,7,8,20,1,8,11,1,7,8,3,2,7,11,19,2,9,0,9,1,9,0,1,7,9,1,3,2,2,8,14,2,6,11,19,2,9,0,9,1,9,0,1,6,9,1,1,6,8,4,1,6,8,3,3,15,6,8,3,15,3,7,8,7,7,8,3,7,8,7,1,9,1,3,10,2,8,4,7,8,4,2,6,10,9,0,6,9,0,2,3,7,8,4,2,1,3,2,7,10,9,0,3,5,2,3,7,15,3,3,2,6,11,12,1,9,0,3,5,6,8,13,7,11,12,1,9,0,3,5,7,8,20,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,12,67,111,105,110,77,101,116,97,100,97,116,97,18,76,105,113,117,105,100,97,116,105,111,110,70,97,99,116,111,114,115,8,79,119,110,101,114,67,97,112,6,80,97,117,115,101,100,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,23,82,101,115,101,114,118,101,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,11,82,101,115,101,114,118,101,68,97,116,97,7,83,116,111,114,97,103,101,15,83,116,111,114,97,103,101,65,100,109,105,110,67,97,112,26,83,116,111,114,97,103,101,67,111,110,102,105,103,117,114,97,116,111,114,83,101,116,116,105,110,103,6,83,116,114,105,110,103,5,84,97,98,108,101,12,84,111,107,101,110,66,97,108,97,110,99,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,20,85,115,101,114,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,8,85,115,101,114,73,110,102,111,3,97,100,100,5,97,115,99,105,105,9,98,97,115,101,95,114,97,116,101,5,98,111,110,117,115,6,98,111,114,114,111,119,14,98,111,114,114,111,119,95,98,97,108,97,110,99,101,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,5,99,108,111,99,107,4,99,111,105,110,9,99,111,105,110,95,116,121,112,101,11,99,111,108,108,97,116,101,114,97,108,115,12,99,111,110,102,105,103,117,114,97,116,111,114,8,99,111,110,116,97,105,110,115,11,99,114,101,97,116,101,95,112,111,111,108,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,20,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,114,97,116,101,4,100,97,116,97,16,100,101,99,114,101,97,115,101,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,12,100,101,115,116,111,114,121,95,117,115,101,114,4,101,109,105,116,5,101,118,101,110,116,3,103,101,116,13,103,101,116,95,97,115,115,101,116,95,108,116,118,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,13,103,101,116,95,99,111,105,110,95,116,121,112,101,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,12,103,101,116,95,100,101,99,105,109,97,108,115,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,20,103,101,116,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,16,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,114,101,115,101,114,118,101,11,105,110,116,111,95,115,116,114,105,110,103,11,105,115,95,105,115,111,108,97,116,101,100,20,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,5,108,111,97,110,115,5,108,111,103,105,99,3,108,116,118,10,109,117,108,116,105,112,108,105,101,114,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,111,114,97,99,108,101,95,105,100,5,112,97,117,115,101,6,112,97,117,115,101,100,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,105,111,3,114,97,121,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,14,114,101,115,101,114,118,101,95,102,97,99,116,111,114,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,97,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,98,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,99,18,114,101,115,101,114,118,101,95,118,97,108,105,100,97,116,105,111,110,8,114,101,115,101,114,118,101,115,14,114,101,115,101,114,118,101,115,95,99,111,117,110,116,6,115,101,110,100,101,114,13,115,101,116,95,98,97,115,101,95,114,97,116,101,14,115,101,116,95,98,111,114,114,111,119,95,99,97,112,24,115,101,116,95,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,98,111,110,117,115,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,114,97,116,105,111,25,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,7,115,101,116,95,108,116,118,14,115,101,116,95,109,117,108,116,105,112,108,105,101,114,23,115,101,116,95,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,115,101,116,95,112,97,117,115,101,18,115,101,116,95,114,101,115,101,114,118,101,95,102,97,99,116,111,114,14,115,101,116,95,115,117,112,112,108,121,95,99,97,112,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,7,115,116,111,114,97,103,101,14,115,117,112,112,108,121,95,98,97,108,97,110,99,101,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,9,116,104,114,101,115,104,111,108,100,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,9,117,115,101,114,95,105,110,102,111,10,117,115,101,114,95,115,116,97,116,101,5,117,115,101,114,115,5,118,97,108,117,101,6,118,101,99,116,111,114,7,118,101,114,115,105,111,110,15,118,101,114,115,105,111,110,95,109,105,103,114,97,116,101,20,118,101,114,115,105,111,110,95,118,101,114,105,102,105,99,97,116,105,111,110,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,3,0,0,0,0,0,0,0,3,8,248,167,0,0,0,0,0,0,3,8,249,167,0,0,0,0,0,0,3,8,250,167,0,0,0,0,0,0,3,8,251,167,0,0,0,0,0,0,3,8,252,167,0,0,0,0,0,0,3,8,253,167,0,0,0,0,0,0,3,8,254,167,0,0,0,0,0,0,3,8,255,167,0,0,0,0,0,0,2,1,255,0,2,1,66,8,18,1,2,1,66,8,18,2,2,7,66,8,18,142,1,3,89,1,103,11,19,2,2,8,3,104,2,139,1,10,5,137,1,11,19,2,5,8,4,3,2,21,66,2,87,2,32,8,14,76,1,122,15,27,15,40,15,38,15,39,15,37,15,121,8,7,26,8,7,78,3,82,15,129,1,15,128,1,15,29,8,8,79,8,9,99,15,100,15,101,15,4,2,2,33,10,2,80,10,2,5,2,1,41,15,6,2,1,41,15,7,2,2,138,1,11,19,2,5,15,126,15,8,2,5,23,15,83,15,77,15,98,15,86,15,9,2,3,92,15,24,15,124,15,10,2,3,105,5,34,5,140,1,1,11,2,1,89,1,0,0,0,0,1,27,10,0,17,63,18,1,10,0,46,17,72,56,0,10,0,17,63,18,0,10,0,46,17,72,56,1,10,0,17,63,7,0,9,10,0,56,2,49,0,64,28,0,0,0,0,0,0,0,0,11,0,56,3,18,2,56,4,2,1,0,0,0,1,10,11,0,16,0,20,7,0,33,4,7,5,9,7,1,39,2,2,1,4,0,1,16,10,1,16,0,20,7,0,35,4,7,5,11,11,1,1,7,2,39,7,0,11,1,15,0,21,2,3,1,4,0,37,117,10,3,46,17,1,10,3,16,1,20,12,35,10,35,7,9,35,4,12,5,24,11,3,1,11,1,1,11,19,1,11,18,1,11,2,1,7,5,39,10,3,46,56,5,10,3,16,1,20,12,20,11,4,12,29,56,6,17,56,12,30,11,5,12,31,11,6,12,32,11,7,12,33,17,54,12,34,17,54,12,21,11,13,12,22,11,14,12,23,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,24,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,25,11,2,17,60,12,26,11,8,11,10,11,11,11,12,11,9,18,8,12,27,11,15,11,16,11,17,18,9,12,28,11,20,11,29,11,30,11,31,11,32,11,33,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,34,11,21,11,24,11,25,11,26,11,22,11,23,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,27,11,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,12,37,10,3,15,2,10,35,11,37,56,8,11,35,49,1,22,11,3,15,1,21,11,18,56,9,12,36,11,1,11,36,11,19,56,10,2,4,1,4,0,1,11,10,1,46,17,1,10,2,11,1,15,3,21,11,2,18,11,56,11,2,5,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,4,21,2,6,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,5,21,2,7,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,6,21,2,8,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,7,21,2,9,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,9,21,2,10,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,10,21,2,11,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,11,21,2,12,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,12,21,2,13,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,13,21,2,14,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,15,21,2,15,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,16,21,2,16,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,17,21,2,17,1,0,0,48,36,56,6,17,56,12,3,10,0,16,1,20,12,1,49,0,12,2,10,2,10,1,35,4,33,5,14,10,0,16,2,10,2,56,13,16,18,20,10,3,34,4,24,5,28,11,0,1,7,7,39,11,2,49,1,22,12,2,5,9,11,0,1,2,18,1,0,0,1,4,11,0,16,3,20,2,19,1,0,0,1,4,11,0,16,1,20,2,20,1,0,0,51,23,10,0,16,19,10,1,56,14,32,4,11,11,0,1,64,8,0,0,0,0,0,0,0,0,64,8,0,0,0,0,0,0,0,0,2,11,0,16,19,11,1,56,15,12,2,10,2,16,20,20,11,2,16,21,20,2,21,1,0,0,1,7,11,0,16,2,11,1,56,13,16,22,20,2,22,1,0,0,1,7,11,0,16,2,11,1,56,13,16,18,20,2,23,1,0,0,1,7,11,0,16,2,11,1,56,13,16,4,20,2,24,1,0,0,1,7,11,0,16,2,11,1,56,13,16,5,20,2,25,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,23,20,11,2,16,24,20,2,26,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,25,20,11,2,16,26,20,2,27,1,0,0,52,14,11,0,16,2,11,1,56,13,12,2,10,2,16,27,16,28,20,11,2,16,29,16,28,20,2,28,1,0,0,53,41,11,0,16,2,11,1,56,13,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,4,16,27,16,30,10,2,56,16,4,22,10,4,16,27,16,30,10,2,56,17,20,12,5,10,4,16,29,16,30,10,2,56,16,4,36,11,4,16,29,16,30,11,2,56,17,20,12,3,5,38,11,4,1,11,5,11,3,2,29,1,0,0,1,7,11,0,16,2,11,1,56,13,16,31,20,2,30,1,0,0,1,7,11,0,16,2,11,1,56,13,16,6,20,2,31,1,0,0,1,7,11,0,16,2,11,1,56,13,16,7,20,2,32,1,0,0,1,7,11,0,16,2,11,1,56,13,16,32,20,2,33,1,0,0,52,26,11,0,16,2,11,1,56,13,12,2,10,2,16,8,16,9,20,10,2,16,8,16,10,20,10,2,16,8,16,11,20,10,2,16,8,16,12,20,11,2,16,8,16,13,20,2,34,1,0,0,52,18,11,0,16,2,11,1,56,13,12,2,10,2,16,14,16,15,20,10,2,16,14,16,16,20,11,2,16,14,16,17,20,2,35,3,0,0,45,17,10,0,46,17,1,11,0,15,2,11,1,56,12,12,4,11,3,10,4,15,23,21,11,2,11,4,15,24,21,2,36,3,0,0,45,29,10,0,46,17,1,11,0,15,2,11,1,56,12,12,6,11,2,10,6,15,26,21,11,3,10,6,15,25,21,11,4,10,6,15,31,21,10,6,16,32,20,11,5,22,11,6,15,32,21,2,37,3,0,0,54,31,10,0,46,17,1,11,0,15,2,11,1,56,12,12,5,10,5,15,27,12,6,11,5,15,29,12,4,10,6,16,28,20,11,2,22,11,6,15,28,21,10,4,16,28,20,11,3,22,11,4,15,28,21,2,38,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,42,2,39,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,43,2,40,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,42,2,41,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,43,2,42,0,0,0,14,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,0,15,30,11,1,11,3,10,2,22,56,19,10,0,16,28,20,11,2,22,11,0,15,28,21,2,43,0,0,0,14,37,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,3,10,2,38,4,17,5,21,11,0,1,7,6,39,10,0,15,30,11,1,11,3,10,2,23,56,19,10,0,16,28,20,11,2,23,11,0,15,28,21,2,44,3,0,0,45,14,11,0,15,2,11,1,56,12,12,3,10,3,16,32,20,11,2,22,11,3,15,32,21,2,45,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,64,8,0,0,0,0,0,0,0,0,11,3,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,21,14,1,56,22,32,4,37,11,5,15,21,11,1,68,8,5,39,11,5,1,2,46,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,21,14,1,56,23,12,3,4,17,11,4,15,21,11,3,56,24,1,5,19,11,4,1,2,47,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,11,3,64,8,0,0,0,0,0,0,0,0,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,20,14,1,56,22,32,4,37,11,5,15,20,11,1,68,8,5,39,11,5,1,2,48,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,20,14,1,56,23,12,3,4,17,11,4,15,20,11,3,56,24,1,5,19,11,4,1,2,49,1,0,0,61,58,10,2,10,3,12,8,46,11,8,17,22,56,6,17,56,33,4,11,5,21,11,2,1,11,1,1,11,4,1,11,7,1,7,8,39,11,2,15,2,11,3,56,12,15,32,12,10,10,4,10,10,20,52,12,9,46,11,9,56,25,12,11,10,5,12,12,11,5,10,11,35,4,44,11,11,12,12,10,10,20,10,12,77,23,11,10,21,11,1,11,4,11,12,11,6,11,7,56,26,2,50,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,2,1,2,4,2,3,2,2,3,4,3,5,3,13,3,14,3,16,8,0,8,1,8,2,8,3,8,4,3,17,9,0,9,1,9,2,3,2,2,6,4,0,4,1,3,1,3,6,3,7,3,8,3,9,3,10,7,1,3,11,7,0,3,12,3,15,0,81,0],[161,28,235,11,6,0,0,0,8,1,0,12,2,12,12,3,24,75,5,99,67,7,166,1,189,2,8,227,3,96,6,195,4,44,12,239,4,164,5,0,10,0,23,0,21,2,17,1,11,1,16,1,2,12,0,3,1,8,0,4,0,8,0,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,6,3,1,0,0,7,3,1,0,0,9,4,1,0,0,4,4,1,0,1,12,0,8,0,1,13,0,3,0,1,15,0,3,0,2,19,6,1,0,2,20,3,1,0,2,22,3,1,0,3,14,10,11,0,5,18,12,13,0,2,7,8,0,2,1,15,3,7,8,0,2,15,2,15,15,4,6,8,2,6,8,1,15,2,7,15,15,15,15,15,15,15,0,6,15,15,15,15,15,15,5,15,15,15,15,15,2,2,15,3,6,8,2,6,8,1,2,3,1,15,2,2,3,2,1,3,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,20,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,9,103,101,116,95,105,110,100,101,120,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,4,109,97,116,104,6,111,114,97,99,108,101,3,112,111,119,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,153,183,0,0,0,0,0,0,0,1,0,0,5,31,10,0,10,1,17,9,12,7,12,8,11,0,11,1,17,8,12,3,12,4,11,7,11,3,17,12,12,5,11,8,11,4,17,12,12,6,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,29,11,5,11,6,17,11,12,2,11,2,2,1,1,0,0,7,37,10,0,10,1,17,7,12,6,1,12,4,12,5,12,3,11,0,11,1,17,0,12,7,10,7,10,6,35,4,23,11,3,11,7,11,5,17,12,22,12,2,5,35,11,3,10,6,11,5,17,12,22,11,7,11,6,23,11,4,17,12,22,12,2,11,2,2,2,1,0,0,3,20,10,0,10,1,17,7,1,12,3,1,1,1,11,0,11,1,17,0,12,4,11,2,11,4,17,12,17,10,11,3,23,17,12,2,3,1,0,0,5,60,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,17,10,2,10,0,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,5,11,1,7,0,26,12,6,10,6,10,6,17,12,12,3,10,3,10,6,17,12,12,2,10,0,10,4,24,11,3,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,7,10,0,11,4,24,11,5,24,11,2,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,17,10,11,6,11,0,24,22,11,7,22,11,8,22,2,4,1,0,0,6,8,17,10,11,1,11,0,24,7,0,26,22,2,5,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,11,5,24,6,10,0,0,0,0,0,0,0,11,4,17,14,77,26,2,6,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,6,10,0,0,0,0,0,0,0,11,4,17,14,77,24,11,5,26,2,0],[161,28,235,11,6,0,0,0,9,1,0,18,2,18,18,3,36,169,1,4,205,1,4,5,209,1,165,2,7,246,3,149,6,8,139,10,128,1,6,139,11,10,12,149,11,225,14,0,16,0,9,0,38,0,43,0,41,3,37,1,45,2,4,2,10,2,1,12,1,0,1,3,3,12,0,5,2,8,0,8,0,8,0,0,17,0,1,1,0,0,21,2,1,0,0,22,2,1,0,0,20,3,1,0,0,24,3,1,0,0,19,4,1,0,0,23,4,1,0,0,18,5,1,0,0,6,6,7,0,0,13,8,7,1,0,0,14,9,1,0,0,15,10,1,0,0,12,9,1,0,1,5,7,1,0,1,7,7,1,0,1,8,25,1,0,2,36,13,14,1,0,3,25,22,1,0,3,26,28,34,0,3,27,28,7,0,3,28,28,7,0,3,29,22,14,0,3,30,28,29,0,3,31,22,19,0,3,32,28,7,0,3,33,17,18,0,3,34,26,7,0,4,39,15,1,0,4,40,7,1,0,4,42,7,1,0,6,11,20,21,1,0,7,35,15,1,0,8,44,31,14,0,16,12,30,19,9,6,8,3,7,8,1,6,8,2,7,11,0,1,9,0,5,2,3,3,1,1,15,7,6,8,3,6,8,2,7,8,1,5,2,15,1,7,6,8,3,6,8,2,7,8,1,2,5,15,1,6,6,8,3,7,8,1,2,5,15,1,7,6,8,3,7,8,1,6,8,2,5,2,15,1,3,6,8,3,7,8,1,2,2,15,15,7,6,8,3,7,8,1,7,11,0,1,9,0,2,3,3,1,6,6,8,3,7,8,1,2,15,15,1,7,6,8,3,7,8,1,2,15,15,15,1,9,1,3,3,15,15,15,15,3,3,1,9,0,2,6,11,0,1,9,0,3,1,3,0,11,5,2,6,2,10,2,15,10,2,15,3,3,15,15,2,6,8,1,5,2,10,2,10,2,1,2,2,6,10,9,0,6,9,0,1,1,2,6,8,1,2,9,5,6,2,15,3,10,2,3,15,10,2,15,3,2,15,2,4,6,8,3,6,8,2,15,2,3,7,8,1,2,5,11,5,6,2,10,2,15,15,10,2,15,3,3,15,15,2,7,8,1,2,3,15,15,15,10,2,15,15,15,15,3,3,15,15,15,1,6,8,3,7,1,3,3,15,3,3,15,6,15,15,15,15,15,15,5,15,15,15,15,15,7,15,15,15,15,15,15,15,5,67,108,111,99,107,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,23,99,97,108,99,117,108,97,116,101,95,99,117,114,114,101,110,116,95,105,110,100,101,120,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,28,100,121,110,97,109,105,99,95,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,21,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,97,112,121,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,18,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,111,114,21,100,121,110,97,109,105,99,95,104,101,97,108,116,104,95,102,97,99,116,111,114,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,31,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,36,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,30,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,25,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,23,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,3,109,97,120,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,4,112,111,111,108,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,201,175,0,0,0,0,0,0,0,1,0,0,11,99,10,6,6,0,0,0,0,0,0,0,0,36,4,9,10,7,6,0,0,0,0,0,0,0,0,36,12,9,5,11,9,12,9,11,9,32,4,15,5,25,11,1,1,11,3,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,17,10,6,6,0,0,0,0,0,0,0,0,36,4,38,10,3,11,6,12,10,46,11,10,56,0,12,17,6,0,0,0,0,0,0,0,0,12,16,10,7,6,0,0,0,0,0,0,0,0,36,4,52,11,3,11,7,12,11,46,11,11,56,0,12,16,5,54,11,3,1,10,0,10,2,10,1,10,4,10,5,10,17,77,10,8,17,1,12,13,10,0,10,2,10,1,10,4,10,5,11,16,77,10,8,17,2,12,14,11,0,11,1,11,2,11,4,11,5,11,17,77,11,8,17,7,12,15,10,14,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,95,11,13,11,14,17,28,11,15,17,29,12,12,5,97,17,31,12,12,11,12,2,1,1,0,0,16,86,10,2,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,17,6,0,0,0,0,0,0,0,0,12,14,10,12,12,10,14,12,14,4,56,1,32,4,31,10,6,4,31,13,10,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,10,14,10,15,35,4,78,5,36,14,10,10,14,66,19,12,9,10,2,10,9,20,12,8,46,11,8,17,17,12,16,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,9,20,33,4,57,10,5,12,13,10,0,10,1,10,2,11,9,20,10,3,11,13,10,6,17,3,12,11,11,17,11,11,11,16,17,29,22,12,17,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,2,1,11,1,1,11,0,1,11,17,2,2,1,0,0,23,76,10,2,10,3,12,7,46,11,7,17,25,12,14,1,14,14,65,19,12,12,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,6,0,0,0,0,0,0,0,0,12,10,10,14,12,11,14,14,14,4,56,1,32,4,31,10,6,4,31,13,11,10,4,68,19,11,12,6,1,0,0,0,0,0,0,0,22,12,12,10,10,10,12,35,4,68,5,36,14,11,10,10,66,19,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,10,4,10,8,20,33,4,49,10,5,12,9,10,0,10,1,10,2,11,8,20,10,3,11,9,10,6,17,4,12,13,11,15,11,13,22,12,15,11,10,6,1,0,0,0,0,0,0,0,22,12,10,5,31,11,2,1,11,1,1,11,0,1,11,15,2,3,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,5,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,4,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,6,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,5,1,0,0,7,27,10,1,10,2,11,3,17,26,1,12,7,11,5,4,13,11,7,11,4,22,12,7,5,17,11,7,11,4,23,12,7,11,0,11,1,11,2,17,8,1,12,6,11,7,11,6,17,29,2,6,1,0,0,7,27,10,1,10,2,11,3,17,26,12,6,1,11,5,4,13,11,6,11,4,22,12,6,5,17,11,6,11,4,23,12,6,11,0,11,1,11,2,17,8,12,7,1,11,6,11,7,17,29,2,7,1,0,0,27,91,10,1,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,6,0,0,0,0,0,0,0,0,12,14,10,12,12,9,14,12,14,4,56,1,32,4,27,13,9,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,10,14,10,15,35,4,81,5,36,14,9,10,14,66,19,12,8,10,1,10,8,20,17,22,12,16,1,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,8,20,33,4,56,10,5,12,13,10,0,10,2,10,1,11,8,20,10,3,11,13,10,6,17,3,12,17,11,10,10,17,11,16,17,29,22,12,10,11,11,11,17,22,12,11,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,1,1,11,2,1,11,0,1,11,10,11,11,17,28,2,8,1,0,0,30,42,11,0,17,32,12,8,10,1,10,2,12,3,46,11,3,17,21,12,9,10,1,10,2,17,20,12,4,12,6,11,1,11,2,17,19,12,5,12,7,11,8,11,9,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,12,10,12,11,5,17,13,11,4,17,29,12,10,11,12,11,7,17,14,11,6,17,29,12,11,11,10,11,11,2,9,1,0,0,32,76,10,4,6,0,0,0,0,0,0,0,0,36,4,9,10,5,6,0,0,0,0,0,0,0,0,36,12,7,5,11,9,12,7,11,7,32,4,15,5,23,11,1,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,12,10,4,6,0,0,0,0,0,0,0,0,36,4,36,10,2,11,4,12,8,46,11,8,56,0,12,12,6,0,0,0,0,0,0,0,0,12,11,10,5,6,0,0,0,0,0,0,0,0,36,4,50,11,2,11,5,12,9,46,11,9,56,0,12,11,5,52,11,2,1,10,0,10,1,10,3,10,12,77,10,11,77,10,6,17,10,12,10,11,0,11,1,11,3,10,10,11,12,77,11,11,77,11,6,17,11,12,13,11,10,11,13,2,10,1,0,0,33,41,10,1,10,2,17,18,12,10,1,12,8,12,9,12,7,11,0,11,1,11,2,11,3,11,4,11,5,17,12,12,11,10,11,10,10,35,4,27,11,7,11,11,11,9,17,29,22,12,6,5,39,11,7,10,11,11,9,17,29,22,11,11,11,10,23,11,8,17,29,22,12,6,11,6,2,11,1,0,0,7,24,10,1,10,2,17,18,1,12,7,1,1,1,11,0,11,1,11,2,11,4,11,5,11,6,17,12,12,8,11,3,11,8,17,29,17,27,11,7,23,17,29,2,12,1,0,0,35,62,10,1,10,2,17,24,12,11,12,12,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,5,4,16,11,12,11,3,22,12,12,5,20,11,12,11,3,23,12,12,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,35,11,5,4,31,11,11,11,4,22,12,11,5,35,11,11,11,4,23,12,11,11,0,11,1,11,2,17,8,12,7,12,8,11,12,11,8,17,29,12,10,11,11,11,7,17,29,12,9,10,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,56,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,5,60,11,9,11,10,17,28,12,6,11,6,2,0],[161,28,235,11,6,0,0,0,14,1,0,30,2,30,66,3,96,181,1,4,149,2,46,5,195,2,164,3,7,231,5,187,6,8,162,12,96,6,130,13,94,10,224,13,116,11,212,14,2,12,214,14,189,15,13,147,30,40,14,187,30,8,15,195,30,2,0,44,0,72,0,62,0,64,1,18,1,78,2,21,2,26,2,27,2,36,2,53,2,73,2,76,2,77,0,82,0,4,12,1,0,1,0,6,4,0,0,3,12,0,0,7,3,0,0,5,3,0,1,8,12,0,4,9,7,0,5,12,7,0,6,0,4,1,0,1,7,1,8,0,8,2,12,1,0,1,10,13,4,0,11,10,12,2,7,1,4,1,13,11,2,0,0,47,0,1,0,0,67,2,1,0,0,66,2,1,0,0,15,3,1,1,0,0,79,4,1,0,0,24,5,6,0,0,25,7,1,1,0,0,39,8,9,0,0,40,10,11,0,0,33,12,13,0,1,41,46,37,0,1,42,47,37,0,2,60,1,34,0,2,61,37,34,0,3,51,37,34,0,5,38,1,36,1,0,5,48,36,33,0,6,69,49,40,1,0,7,74,32,9,0,8,37,50,51,1,0,9,34,22,1,1,3,10,52,0,14,0,11,14,26,1,2,7,4,11,22,24,45,2,7,4,11,23,27,28,2,7,4,11,29,24,25,2,7,4,11,52,0,18,2,7,4,11,63,27,43,2,7,4,12,58,52,1,1,12,12,68,22,1,1,8,13,65,15,16,0,14,70,39,40,1,0,26,17,26,19,29,21,25,17,22,17,24,17,20,29,20,30,25,19,22,19,24,19,15,22,26,38,31,22,29,41,25,38,27,38,22,38,23,19,23,38,17,22,19,22,28,51,1,7,8,13,0,4,7,8,2,15,1,7,8,13,9,7,8,2,6,8,9,2,3,3,11,10,1,9,0,3,2,7,8,13,5,7,8,2,6,8,9,7,8,5,2,5,5,6,8,2,7,8,5,3,2,5,2,10,15,10,15,6,7,8,2,7,11,0,1,9,0,6,8,9,7,8,5,5,7,8,13,2,6,8,2,2,1,3,3,6,8,2,2,3,4,3,3,15,2,5,6,8,2,7,8,5,6,8,9,2,5,3,10,8,6,10,15,10,2,1,8,11,1,6,8,13,1,5,2,15,1,1,11,12,2,9,0,9,1,2,2,8,1,1,2,1,8,2,1,9,0,1,7,1,2,6,11,12,2,9,0,9,1,9,0,1,1,3,7,11,12,2,9,0,9,1,9,0,9,1,2,7,11,12,2,9,0,9,1,9,0,1,7,9,1,1,8,3,1,8,4,4,1,11,8,1,9,0,3,7,8,1,1,6,8,9,1,8,6,1,15,1,11,12,2,5,15,1,8,7,2,15,15,2,5,15,3,11,10,1,9,0,3,7,8,13,1,11,8,1,9,0,1,11,0,1,9,0,17,7,8,5,3,2,5,5,5,3,3,7,15,15,10,15,7,11,12,2,5,15,3,7,8,1,15,10,15,7,11,12,2,5,15,1,9,1,18,6,11,12,2,5,15,3,3,15,15,10,15,15,6,11,12,2,5,15,3,6,8,1,15,15,3,15,15,15,15,10,15,1,6,9,1,2,7,8,5,2,3,7,8,5,2,5,9,5,15,3,7,8,1,15,15,6,11,12,2,5,15,15,7,11,12,2,5,15,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,13,1,11,10,1,9,0,2,9,0,5,1,6,8,1,10,10,8,6,3,3,3,10,2,6,8,1,10,15,15,6,11,12,2,5,15,10,15,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,9,73,110,99,101,110,116,105,118,101,12,73,110,99,101,110,116,105,118,101,66,97,108,16,80,111,111,108,65,100,109,105,110,83,101,116,116,105,110,103,8,80,111,111,108,73,110,102,111,16,80,111,111,108,79,119,110,101,114,83,101,116,116,105,110,103,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,3,97,100,100,8,97,100,100,95,112,111,111,108,5,97,100,109,105,110,6,97,100,109,105,110,115,5,97,115,99,105,105,5,97,115,115,101,116,6,97,115,115,101,116,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,24,99,97,108,99,95,112,111,111,108,95,117,112,100,97,116,101,95,114,101,119,97,114,100,115,12,99,108,97,105,109,95,114,101,119,97,114,100,5,99,108,111,99,107,4,99,111,105,110,10,99,111,105,110,95,116,121,112,101,115,8,99,111,110,116,97,105,110,115,7,99,114,101,97,116,111,114,11,99,117,114,114,101,110,116,95,105,100,120,18,100,105,115,116,114,105,98,117,116,101,100,95,97,109,111,117,110,116,6,101,97,114,110,101,100,4,101,109,105,116,9,101,110,100,95,116,105,109,101,115,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,14,103,101,116,95,112,111,111,108,95,99,111,117,110,116,13,103,101,116,95,112,111,111,108,95,105,110,102,111,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,9,105,110,99,101,110,116,105,118,101,13,105,110,100,101,120,95,114,101,119,97,114,100,115,19,105,110,100,101,120,95,114,101,119,97,114,100,115,95,112,97,105,100,115,4,105,110,105,116,11,105,110,116,111,95,115,116,114,105,110,103,16,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,7,108,101,110,100,105,110,103,3,109,117,108,3,110,101,119,6,111,98,106,101,99,116,10,111,114,97,99,108,101,95,105,100,115,5,111,119,110,101,114,6,111,119,110,101,114,115,5,112,111,111,108,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,9,115,97,102,101,95,109,97,116,104,6,115,101,110,100,101,114,9,115,101,116,95,97,100,109,105,110,9,115,101,116,95,111,119,110,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,11,115,116,97,114,116,95,116,105,109,101,115,7,115,116,111,114,97,103,101,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,13,116,111,116,97,108,95,115,117,112,112,108,121,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,13,117,112,100,97,116,101,95,114,101,119,97,114,100,16,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,22,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,95,112,97,105,100,115,5,117,116,105,108,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,153,183,0,0,0,0,0,0,3,8,154,183,0,0,0,0,0,0,3,8,155,183,0,0,0,0,0,0,3,8,156,183,0,0,0,0,0,0,3,8,157,183,0,0,0,0,0,0,3,8,158,183,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,43,8,11,19,2,31,3,32,15,21,11,8,1,9,0,1,2,12,43,2,49,3,28,10,8,6,71,10,3,35,10,3,75,10,15,59,10,15,45,10,15,46,10,11,12,2,5,15,80,10,11,12,2,5,15,81,10,11,12,2,5,15,54,10,2,2,2,6,43,8,11,30,5,56,11,12,2,15,1,17,11,12,2,15,1,57,11,12,2,2,8,1,20,10,2,3,2,3,65,5,55,15,83,1,4,2,3,65,5,16,15,83,1,0,22,0,0,0,0,1,15,10,0,17,21,10,0,46,17,30,10,0,56,0,10,0,56,0,11,0,56,1,64,20,0,0,0,0,0,0,0,0,18,2,56,2,2,1,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,1,10,1,56,3,32,4,27,11,0,15,1,10,1,10,2,56,4,5,35,11,0,15,1,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,3,56,6,2,2,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,2,10,1,56,3,32,4,27,11,0,15,2,10,1,10,2,56,4,5,35,11,0,15,2,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,4,56,7,2,3,1,4,0,31,139,1,10,0,16,0,20,10,8,46,17,30,33,4,9,5,17,11,0,1,11,8,1,11,1,1,7,0,39,10,3,11,1,17,18,36,4,27,10,4,10,3,36,12,9,5,29,9,12,9,11,9,4,32,5,38,11,0,1,11,8,1,7,1,39,10,0,16,3,10,2,56,8,32,4,65,10,0,15,3,10,2,10,2,6,0,0,0,0,0,0,0,0,64,33,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,20,0,0,0,0,0,0,0,0,18,1,56,9,10,0,15,4,10,2,68,20,11,0,15,3,10,2,56,10,12,12,10,12,16,5,65,33,12,11,10,12,15,5,56,11,17,16,68,33,10,12,15,6,10,3,68,9,10,12,15,7,10,4,68,9,10,12,15,8,10,6,77,68,34,10,12,15,9,10,6,77,11,4,11,3,23,77,17,13,68,34,10,12,15,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,34,10,12,15,11,10,8,56,12,68,35,10,12,15,12,10,8,56,12,68,35,10,12,15,13,10,8,56,12,68,35,11,12,15,14,11,7,68,20,11,5,11,6,10,8,56,13,12,10,11,8,17,21,11,2,11,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,10,57,0,56,14,2,4,3,0,0,42,118,10,0,16,3,10,3,56,8,4,111,11,1,17,18,12,11,10,0,11,2,10,11,10,3,10,4,12,8,12,7,12,6,12,5,46,11,5,11,6,11,7,11,8,17,5,12,20,12,15,11,0,15,3,11,3,56,10,12,18,11,11,10,18,15,15,21,10,18,16,5,65,33,12,17,6,0,0,0,0,0,0,0,0,12,12,10,12,10,17,35,4,108,5,45,14,15,10,12,66,34,20,12,14,14,20,10,12,66,34,20,12,19,10,18,15,10,10,12,67,34,12,13,10,14,11,13,21,10,18,15,11,10,12,67,35,12,16,10,16,10,4,12,9,46,11,9,56,15,4,79,10,16,10,4,56,16,1,11,16,10,4,11,14,56,17,10,18,15,12,10,12,67,35,12,21,10,21,10,4,12,10,46,11,10,56,15,4,99,10,21,10,4,56,16,1,11,21,10,4,11,19,56,17,11,12,6,1,0,0,0,0,0,0,0,22,12,12,5,40,11,18,1,5,117,11,2,1,11,0,1,11,1,1,2,5,0,0,0,44,166,1,11,0,16,3,10,3,56,18,12,14,10,14,16,5,65,33,12,13,6,0,0,0,0,0,0,0,0,12,7,64,34,0,0,0,0,0,0,0,0,12,10,64,34,0,0,0,0,0,0,0,0,12,22,10,7,10,13,35,4,159,1,5,20,10,14,16,6,10,7,66,9,20,12,17,10,17,10,14,16,15,20,35,4,36,10,14,16,15,20,12,17,10,14,16,7,10,7,66,9,20,12,6,10,2,10,6,35,4,48,10,2,12,6,10,14,16,9,10,7,66,34,20,12,15,10,14,16,10,10,7,66,34,20,12,9,10,17,10,6,35,4,90,11,6,11,17,23,77,12,19,10,1,10,3,17,10,1,12,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,10,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,15,11,19,17,14,11,20,26,12,8,11,9,11,8,22,12,9,13,10,10,9,68,34,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,21,10,4,7,6,34,4,151,1,10,14,16,12,10,7,66,35,12,5,10,5,10,4,56,15,4,114,11,5,10,4,56,19,20,12,21,5,116,11,5,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,14,16,11,10,7,66,35,12,12,10,12,10,4,56,15,4,133,1,11,12,10,4,56,19,20,12,11,5,135,1,11,12,1,10,1,10,3,10,4,17,11,1,12,18,11,9,11,11,23,11,18,24,12,16,11,21,11,16,22,12,21,13,22,11,21,68,34,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,15,11,1,1,11,14,1,11,10,11,22,2,6,1,4,0,48,105,10,0,11,2,11,3,10,1,55,0,20,10,4,17,4,11,0,15,3,10,1,55,0,20,56,10,12,9,10,1,55,1,20,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,9,16,12,10,8,66,35,12,12,10,12,10,4,56,15,4,36,11,12,10,4,56,19,20,12,11,5,38,11,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,9,15,13,10,8,67,35,12,14,10,14,10,4,12,6,46,11,6,56,15,4,56,10,14,10,4,56,16,12,13,11,14,10,4,10,11,56,17,11,11,11,13,23,17,12,26,12,7,11,9,16,8,11,8,66,34,20,12,10,10,1,55,2,20,10,7,22,11,10,37,4,81,5,87,11,5,1,11,1,1,7,4,39,10,1,55,2,20,10,7,22,10,1,54,2,21,11,1,54,3,11,7,52,56,20,11,5,56,21,11,4,56,22,2,7,1,0,0,9,19,6,0,0,0,0,0,0,0,0,12,2,10,0,16,3,10,1,56,8,4,15,11,0,16,3,11,1,56,18,16,5,65,33,12,2,5,17,11,0,1,11,2,2,8,1,0,0,53,47,10,0,16,3,10,1,56,8,4,6,5,10,11,0,1,7,2,39,11,0,16,3,11,1,56,18,12,3,10,3,16,5,65,33,10,2,36,4,22,5,26,11,3,1,7,2,39,10,3,16,6,10,2,66,9,20,10,3,16,7,10,2,66,9,20,10,3,16,9,10,2,66,34,20,11,3,16,14,11,2,66,20,20,2,9,1,0,0,54,97,64,33,0,0,0,0,0,0,0,0,12,5,64,34,0,0,0,0,0,0,0,0,12,14,64,20,0,0,0,0,0,0,0,0,12,9,10,0,16,3,10,3,56,8,4,87,11,2,17,18,12,6,10,0,11,1,11,6,10,3,10,4,17,5,12,11,1,11,0,16,3,11,3,56,18,12,10,10,10,16,5,65,33,12,8,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,84,5,38,10,10,16,13,10,7,66,35,12,13,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,10,13,10,4,56,15,4,55,11,13,10,4,56,19,20,12,12,5,57,11,13,1,13,5,10,10,16,5,10,7,66,33,20,68,33,13,14,14,11,10,7,66,34,20,11,12,23,68,34,13,9,10,10,16,14,10,7,66,20,20,68,20,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,33,11,10,1,5,93,11,1,1,11,0,1,11,2,1,11,5,11,14,11,9,2,2,1,2,2,2,3,2,4,2,5,1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,1,11,1,1,0,1,0,2,0,3,0,4,16,22,17,22,18,22,19,22,0,50,0],[161,28,235,11,6,0,0,0,9,1,0,10,2,10,12,3,22,82,4,104,4,5,108,83,7,191,1,154,2,8,217,3,64,6,153,4,70,12,223,4,237,4,0,22,0,15,0,13,1,3,1,16,1,0,12,0,3,1,7,0,4,2,7,0,0,18,0,1,1,0,0,21,0,1,1,0,0,17,0,1,1,0,0,20,0,1,1,0,0,19,2,1,2,0,0,1,5,8,10,0,1,6,7,6,0,1,7,8,9,0,1,8,8,10,0,1,9,8,9,0,2,11,1,10,0,2,12,9,10,0,2,14,9,10,0,4,4,1,5,1,0,4,10,5,6,0,13,4,13,14,3,7,8,0,2,15,0,4,7,8,0,2,2,15,7,7,8,0,2,15,15,15,15,15,1,9,0,1,8,2,1,8,1,2,6,8,0,2,2,7,8,0,2,2,15,15,1,15,8,7,8,0,2,15,15,15,15,15,15,9,7,8,0,2,15,15,15,15,15,15,15,4,7,8,0,2,7,8,0,2,1,9,1,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,5,97,115,99,105,105,3,103,101,116,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,13,103,101,116,95,99,111,105,110,95,116,121,112,101,9,103,101,116,95,105,110,100,101,120,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,11,105,110,116,111,95,115,116,114,105,110,103,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,9,116,121,112,101,95,110,97,109,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,225,171,0,0,0,0,0,0,3,8,226,171,0,0,0,0,0,0,3,8,227,171,0,0,0,0,0,0,3,8,228,171,0,0,0,0,0,0,3,8,229,171,0,0,0,0,0,0,3,8,230,171,0,0,0,0,0,0,3,8,231,171,0,0,0,0,0,0,0,1,0,0,3,58,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,1,12,8,10,0,10,1,17,7,1,12,5,11,8,11,5,17,12,12,7,11,0,11,1,17,8,12,9,11,7,11,2,22,17,10,24,12,6,11,9,11,6,38,4,55,5,57,7,1,39,2,1,1,0,0,11,54,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,10,11,0,11,1,17,7,12,6,12,7,11,10,11,7,17,12,12,9,11,5,11,6,17,12,12,8,11,9,11,8,11,2,22,38,4,51,5,53,7,3,39,2,2,1,0,0,12,71,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,11,10,0,10,1,17,7,12,6,12,8,11,11,11,8,17,12,12,10,11,5,11,6,17,12,12,9,10,9,10,2,22,10,10,35,4,51,5,55,11,0,1,7,3,39,11,9,11,2,22,11,10,17,11,12,7,11,0,11,1,17,5,11,7,38,4,68,5,70,7,2,39,2,3,1,0,0,8,23,11,0,11,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,15,7,4,39,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,20,5,22,7,0,39,2,4,1,0,0,13,40,10,0,11,1,12,5,12,4,56,0,17,14,11,4,46,11,5,17,6,33,4,13,5,17,11,0,1,7,4,39,11,0,11,2,12,7,12,6,56,1,17,14,11,6,46,11,7,17,6,33,4,30,5,32,7,4,39,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,37,5,39,7,0,39,2,0],[161,28,235,11,6,0,0,0,10,1,0,20,2,20,12,3,32,220,2,4,252,2,12,5,136,3,214,2,7,222,5,205,9,8,171,15,128,1,6,171,16,60,12,231,16,222,18,15,197,35,2,0,42,0,11,0,53,0,73,0,48,0,52,3,45,1,74,2,3,2,12,2,2,12,0,6,1,8,0,9,0,8,0,0,18,0,1,1,0,0,21,2,3,1,0,0,17,2,1,1,0,0,20,2,4,1,0,0,19,5,6,2,0,0,0,57,7,1,0,0,56,8,1,0,0,55,9,1,0,0,36,10,1,0,0,15,10,1,0,0,35,10,1,0,0,14,10,1,0,0,39,11,12,0,0,64,13,14,0,0,63,15,4,0,0,16,15,4,0,0,62,11,4,0,0,65,11,4,0,0,67,16,4,0,0,61,16,4,0,0,60,17,4,0,0,66,17,4,0,0,38,17,12,0,0,40,17,12,0,0,8,18,19,0,1,4,44,4,0,1,5,9,4,0,1,6,22,4,0,1,7,22,4,0,1,9,21,4,0,1,10,44,4,0,2,14,10,1,0,2,15,10,1,0,2,22,31,4,0,2,23,9,32,0,2,24,9,22,0,2,25,9,22,0,2,26,31,3,0,2,27,9,6,0,2,28,31,28,0,2,29,27,28,0,2,30,9,22,0,2,31,9,4,0,2,32,39,40,0,2,33,17,22,0,2,34,34,1,0,2,35,10,1,0,2,36,10,1,0,2,37,21,1,0,2,50,17,1,0,2,51,17,1,0,2,55,34,1,0,2,56,33,1,0,2,58,17,1,0,2,59,17,1,0,3,68,21,1,1,0,3,69,21,1,1,0,3,70,25,1,2,0,0,3,71,21,1,1,0,3,72,21,1,1,0,4,46,1,4,0,4,47,22,4,0,4,49,22,4,0,5,44,22,4,0,7,13,46,12,1,0,8,43,1,4,0,9,54,30,3,0,56,20,59,20,55,20,58,20,57,24,64,28,5,6,8,2,7,8,0,2,5,15,0,6,6,8,2,6,8,1,7,8,0,2,5,15,1,3,1,15,7,6,8,2,6,8,1,7,8,0,5,2,2,15,3,15,15,15,2,6,8,2,7,8,0,3,6,8,2,7,8,0,2,2,7,8,0,2,4,7,8,0,2,5,15,4,6,8,2,6,8,1,7,8,0,5,1,1,4,6,8,2,6,8,1,7,8,0,10,5,1,10,15,4,6,8,2,7,8,0,6,8,1,5,5,6,8,2,6,8,1,7,8,0,2,5,3,7,8,0,2,5,7,6,8,2,7,8,0,6,8,1,5,2,2,15,6,15,15,15,15,15,1,1,9,0,3,7,8,0,2,15,2,15,15,6,15,15,1,15,15,15,2,9,0,9,1,4,7,8,0,2,2,15,2,2,2,1,6,8,0,1,2,18,2,15,15,15,15,3,15,15,3,15,15,15,15,15,15,15,15,15,1,6,8,2,2,6,8,0,2,5,15,15,15,15,15,6,7,8,0,2,15,15,3,15,4,7,8,0,2,15,15,4,15,3,3,10,15,1,5,4,15,15,15,15,9,5,6,2,15,15,10,2,3,3,15,15,2,6,8,0,5,2,10,2,10,2,9,5,2,6,2,15,10,2,3,3,15,15,7,5,6,2,3,3,15,10,2,15,3,2,15,2,4,6,8,2,6,8,1,15,2,2,5,10,2,2,6,10,9,0,6,9,0,18,2,15,15,15,15,1,15,15,15,15,15,2,15,15,15,15,15,15,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,7,105,115,95,108,111,97,110,7,108,101,110,100,105,110,103,5,108,111,103,105,99,3,109,97,120,3,109,105,110,6,111,114,97,99,108,101,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,9,115,97,102,101,95,109,97,116,104,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,19,117,112,100,97,116,101,95,115,116,97,116,101,95,111,102,95,97,108,108,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,24,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,95,98,97,116,99,104,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,33,78,0,0,0,0,0,0,3,8,34,78,0,0,0,0,0,0,3,8,35,78,0,0,0,0,0,0,3,8,36,78,0,0,0,0,0,0,3,8,37,78,0,0,0,0,0,0,3,8,38,78,0,0,0,0,0,0,0,3,0,0,1,26,11,0,10,1,17,5,10,1,10,2,10,4,56,0,10,1,10,2,10,3,11,4,17,8,10,1,10,2,10,3,17,22,32,4,22,10,1,10,2,11,3,17,53,11,1,11,2,17,7,2,1,3,0,0,22,92,10,2,10,3,10,4,17,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,16,11,2,1,11,1,1,11,0,1,7,4,39,10,0,10,2,17,5,10,2,10,3,10,5,56,1,10,2,10,3,10,4,17,20,12,7,11,5,10,7,17,63,12,6,10,2,10,3,10,4,10,6,17,9,11,0,11,1,10,2,10,4,17,12,4,44,5,48,11,2,1,7,0,39,10,6,10,7,33,4,61,10,2,10,3,10,4,17,22,4,61,10,2,10,3,10,4,17,49,10,7,10,6,36,4,86,10,7,10,6,23,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,4,86,10,2,10,3,11,7,10,6,23,17,48,10,2,10,3,10,4,17,22,4,86,10,2,10,3,11,4,17,49,11,2,11,3,17,7,11,6,52,2,2,3,0,0,1,37,10,0,10,2,17,5,10,2,10,3,10,5,56,2,10,2,10,3,10,4,11,5,17,10,10,2,10,3,10,4,17,23,32,4,22,10,2,10,3,10,4,17,54,11,0,11,1,10,2,11,4,17,12,4,29,5,33,11,2,1,7,0,39,11,2,11,3,17,7,2,3,3,0,0,6,58,10,2,10,3,10,4,17,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,14,11,2,1,11,0,1,7,5,39,11,0,10,2,17,5,10,2,10,3,10,5,56,3,10,2,10,3,10,4,17,21,12,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,5,12,8,10,6,10,5,35,4,40,10,6,12,8,11,5,10,6,23,12,7,10,2,10,3,10,4,10,8,17,11,11,8,11,6,33,4,53,10,2,10,3,11,4,17,50,11,2,11,3,17,7,11,7,2,4,3,0,0,23,92,10,2,10,5,10,3,17,23,4,6,5,14,11,2,1,11,1,1,11,0,1,7,3,39,10,2,10,4,10,3,17,22,4,20,5,28,11,2,1,11,1,1,11,0,1,7,2,39,10,0,10,2,17,5,10,2,10,5,10,4,10,6,56,4,10,0,10,1,10,2,10,3,17,12,32,4,44,5,52,11,2,1,11,1,1,11,0,1,7,1,39,11,0,10,2,11,1,10,3,10,4,10,5,11,6,17,24,12,9,12,8,12,12,12,7,12,11,12,10,10,2,10,5,10,3,11,11,17,11,10,2,10,4,10,3,11,10,17,9,11,9,4,82,10,2,10,5,11,3,17,50,10,2,11,4,17,7,11,2,11,5,17,7,11,7,11,8,11,12,2,5,0,0,0,26,25,10,1,46,17,40,12,2,49,0,12,3,10,3,10,2,35,4,20,5,11,10,0,10,1,10,3,17,6,11,3,49,1,22,12,3,5,6,11,1,1,11,0,1,2,6,0,0,0,29,97,11,0,17,66,12,8,10,1,10,2,12,3,46,11,3,17,37,12,11,10,8,11,11,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,18,10,1,10,2,17,36,12,4,12,6,10,1,10,2,17,35,12,5,12,7,10,18,11,7,17,28,10,6,17,62,12,13,11,18,11,5,17,27,10,4,17,62,12,12,10,1,10,2,17,34,1,12,14,1,1,1,10,1,10,2,17,41,12,19,12,20,10,19,10,12,10,4,23,17,62,12,9,11,20,10,13,11,6,23,17,62,12,10,11,9,10,12,17,61,12,15,11,10,10,13,17,61,12,17,11,19,10,12,11,4,23,17,62,11,14,17,62,10,12,17,61,12,16,10,1,10,2,11,12,11,13,11,8,10,16,17,52,11,1,11,2,11,17,11,15,11,16,22,17,45,2,7,0,0,0,22,15,10,0,10,1,17,26,12,2,10,0,10,1,10,2,17,29,12,3,11,0,11,1,11,2,11,3,17,51,2,8,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,47,2,9,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,32,2,10,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,46,2,11,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,31,2,12,1,0,0,1,8,11,0,11,2,11,1,11,3,17,14,17,60,38,2,13,1,0,0,35,37,14,3,65,36,12,6,6,0,0,0,0,0,0,0,0,12,5,64,4,0,0,0,0,0,0,0,0,12,7,10,5,10,6,35,4,29,5,12,10,0,10,2,10,1,14,3,10,5,66,36,20,17,14,12,4,13,7,11,4,68,4,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,7,11,2,1,11,1,1,11,0,1,11,7,2,14,1,0,0,37,33,10,0,10,2,10,1,10,3,17,16,12,6,10,0,10,1,10,2,10,3,17,15,12,5,11,0,11,2,11,1,11,3,17,17,12,7,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,29,11,6,11,7,17,61,11,5,17,62,12,4,5,31,17,65,12,4,11,4,2,15,1,0,0,38,72,10,1,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,6,0,0,0,0,0,0,0,0,12,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,10,9,10,10,35,4,56,5,22,14,8,10,9,66,28,12,5,10,1,10,5,20,17,38,12,11,1,1,10,0,10,2,10,1,11,5,20,10,3,17,19,12,12,11,6,10,12,11,11,17,62,22,12,6,11,7,11,12,22,12,7,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,17,11,1,1,11,2,1,11,0,1,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,11,6,11,7,17,61,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,16,1,0,0,41,59,10,2,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,6,0,0,0,0,0,0,0,0,12,9,10,9,10,10,35,4,51,5,20,14,8,10,9,66,28,12,6,10,2,10,6,20,12,5,46,11,5,17,33,12,11,10,0,10,1,10,2,11,6,20,10,3,17,19,12,7,11,12,11,7,11,11,17,62,22,12,12,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,15,11,2,1,11,1,1,11,0,1,11,12,2,17,1,0,0,42,49,10,2,10,3,12,4,46,11,4,17,43,12,9,1,14,9,65,28,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,41,5,20,14,9,10,6,66,28,12,5,10,0,10,1,10,2,11,5,20,10,3,17,18,12,8,11,10,11,8,22,12,10,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,15,11,2,1,11,1,1,11,0,1,11,10,2,18,1,0,0,43,18,10,2,10,3,11,4,17,21,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,19,1,0,0,43,18,10,2,10,3,11,4,17,20,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,20,1,0,0,22,15,10,0,10,1,11,2,17,44,1,12,3,11,0,11,1,17,36,1,12,4,11,3,11,4,17,62,2,21,1,0,0,22,15,10,0,10,1,11,2,17,44,12,3,1,11,0,11,1,17,36,12,4,1,11,3,11,4,17,62,2,22,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,1,12,4,14,4,14,1,56,5,2,23,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,12,4,1,14,4,14,1,56,5,2,24,0,0,0,47,113,10,1,10,4,17,38,1,12,15,12,16,10,0,10,2,10,1,10,4,10,3,17,19,11,16,17,62,12,20,10,0,10,2,10,1,10,5,11,3,17,18,12,19,9,12,12,10,19,10,20,35,4,32,11,19,12,20,8,12,12,10,1,10,5,12,7,46,11,7,17,39,12,18,10,0,10,2,11,6,11,18,17,30,12,21,10,21,10,20,36,4,54,11,21,10,20,23,12,11,5,58,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,11,21,12,20,10,20,11,15,17,62,12,8,11,1,10,4,17,42,12,22,10,8,11,22,17,62,12,23,10,20,10,23,23,12,17,10,0,10,2,10,20,10,4,17,25,12,13,10,0,10,2,11,20,10,5,17,25,12,14,10,0,10,2,11,17,10,4,17,25,12,9,10,0,10,2,11,23,11,4,17,25,12,24,11,0,11,2,11,11,11,8,22,11,5,17,25,12,10,11,13,11,14,11,9,11,24,11,10,11,12,2,0,41,0],[161,28,235,11,6,0,0,0,10,1,0,22,2,22,52,3,74,130,1,4,204,1,38,5,242,1,222,2,7,208,4,238,3,8,190,8,96,6,158,9,10,10,168,9,49,12,217,9,201,4,0,26,0,25,0,30,0,34,0,39,2,32,1,14,1,15,1,19,1,41,0,44,0,3,3,0,0,11,3,0,0,0,3,0,0,8,3,0,0,5,3,0,1,4,12,0,3,6,12,1,0,1,4,9,12,0,5,7,8,0,6,1,8,0,7,2,12,1,0,1,9,10,2,0,0,46,0,1,0,0,16,2,1,1,0,0,47,3,1,1,0,0,13,4,1,1,0,0,35,5,1,1,0,0,29,6,1,2,0,0,1,43,11,1,0,2,20,22,1,1,0,2,21,19,1,1,0,2,22,32,33,2,0,0,2,23,22,28,1,0,2,24,22,16,1,0,3,16,17,1,1,0,3,17,35,1,1,0,3,31,18,16,1,0,3,42,18,16,1,0,3,47,23,1,1,0,4,33,0,7,0,7,45,15,16,1,0,8,18,12,1,1,3,9,37,9,10,0,10,38,13,14,1,0,21,12,18,12,12,12,14,12,8,12,19,20,11,12,15,12,16,12,19,24,7,12,19,26,10,12,19,29,9,31,15,34,16,34,13,34,19,36,1,6,8,7,0,8,6,8,9,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,5,7,8,11,9,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,5,7,8,5,7,8,11,7,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,7,8,11,8,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,11,12,6,8,9,6,8,8,7,8,7,2,7,11,6,1,9,0,2,7,11,6,1,9,1,11,10,1,9,0,5,3,7,8,5,7,8,11,1,1,5,3,3,3,5,11,10,1,9,0,1,6,8,11,1,5,5,7,8,5,6,8,9,7,8,7,2,5,1,9,0,3,11,10,1,9,0,3,7,8,11,1,11,10,1,9,0,1,6,11,10,1,9,0,1,3,3,7,11,6,1,9,0,11,10,1,9,0,7,8,11,2,6,11,6,1,9,0,3,5,6,8,9,7,8,7,2,5,15,1,8,0,6,3,3,3,3,3,5,6,6,8,9,6,8,8,7,8,7,2,5,15,4,7,11,6,1,9,0,3,5,7,8,11,1,8,1,3,3,3,5,1,8,2,8,3,3,15,3,3,3,5,11,10,1,9,0,1,15,1,8,3,14,3,3,3,3,15,15,3,3,3,3,3,5,11,10,1,9,0,15,2,9,0,9,1,7,6,8,9,6,8,8,7,8,7,5,2,2,15,3,15,15,15,1,9,1,2,7,11,6,1,9,0,3,1,8,4,11,66,111,114,114,111,119,69,118,101,110,116,5,67,108,111,99,107,4,67,111,105,110,12,68,101,112,111,115,105,116,69,118,101,110,116,9,73,110,99,101,110,116,105,118,101,20,76,105,113,117,105,100,97,116,105,111,110,67,97,108,108,69,118,101,110,116,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,112,97,121,69,118,101,110,116,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,13,87,105,116,104,100,114,97,119,69,118,101,110,116,6,97,109,111,117,110,116,6,98,111,114,114,111,119,5,99,108,111,99,107,4,99,111,105,110,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,9,105,110,99,101,110,116,105,118,101,7,108,101,110,100,105,110,103,16,108,105,113,117,105,100,97,116,101,95,97,109,111,117,110,116,14,108,105,113,117,105,100,97,116,101,95,117,115,101,114,16,108,105,113,117,105,100,97,116,105,111,110,95,99,97,108,108,5,108,111,103,105,99,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,5,112,97,117,115,101,4,112,111,111,108,5,114,101,112,97,121,7,114,101,115,101,114,118,101,6,115,101,110,100,101,114,10,115,112,108,105,116,95,99,111,105,110,7,115,116,111,114,97,103,101,2,116,111,10,116,120,95,99,111,110,116,101,120,116,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,13,117,112,100,97,116,101,95,114,101,119,97,114,100,5,117,116,105,108,115,5,118,97,108,117,101,15,119,104,101,110,95,110,111,116,95,112,97,117,115,101,100,8,119,105,116,104,100,114,97,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,41,160,0,0,0,0,0,0,0,2,3,36,2,37,5,12,3,1,2,4,36,2,37,5,40,5,12,3,2,2,3,36,2,37,5,12,3,3,2,3,36,2,37,5,12,3,4,2,4,36,2,37,5,28,5,27,3,0,0,0,0,1,8,11,0,17,17,32,4,5,5,7,7,0,39,2,1,1,4,0,8,45,10,1,46,17,0,10,7,46,17,20,12,11,11,6,10,0,10,1,10,3,10,11,17,6,11,4,11,5,10,7,56,0,12,12,14,12,56,1,12,9,10,2,11,12,11,7,56,2,11,2,10,9,12,8,46,11,8,56,3,12,10,11,0,11,1,10,3,10,11,11,10,77,56,4,11,3,11,11,11,9,18,0,56,5,2,2,1,4,0,21,50,10,2,46,17,0,10,8,46,17,20,12,14,11,7,10,0,10,2,10,4,10,14,17,6,10,3,11,5,12,9,46,11,9,56,3,12,13,11,0,11,1,11,2,10,4,11,14,11,13,77,56,6,12,11,10,3,11,11,12,10,46,11,10,56,7,12,12,11,3,10,12,10,6,10,8,56,8,11,4,11,8,46,17,20,11,6,11,12,18,1,56,9,2,3,1,4,0,25,35,10,2,46,17,0,10,6,46,17,20,12,9,10,3,10,5,12,7,46,11,7,56,3,12,8,11,0,11,1,11,2,10,4,10,9,11,8,77,56,10,11,3,10,5,11,9,10,6,56,8,11,4,11,6,46,17,20,11,5,18,2,56,11,2,4,1,4,0,27,65,10,2,46,17,0,10,7,46,17,20,12,14,11,5,11,6,10,7,56,0,12,15,14,15,56,1,12,13,10,3,11,15,10,7,56,2,10,3,10,13,12,8,46,11,8,56,3,12,12,11,0,11,1,11,2,10,4,10,14,11,12,77,56,12,12,10,10,3,11,10,52,12,9,46,11,9,56,7,12,11,10,11,6,0,0,0,0,0,0,0,0,36,4,53,11,3,10,11,11,14,10,7,56,8,5,55,11,3,1,11,4,11,7,46,17,20,11,13,11,11,23,18,3,56,13,2,5,1,4,0,30,90,10,2,46,17,0,10,11,46,17,20,12,23,11,10,10,0,10,2,10,5,10,8,17,6,11,7,11,9,10,11,56,0,12,24,14,24,56,1,12,18,10,4,11,24,10,11,56,2,10,4,11,18,12,12,46,11,12,56,3,12,21,11,0,11,1,11,2,10,8,10,5,11,3,11,21,77,56,14,12,25,12,17,12,16,10,4,11,17,52,12,13,46,11,13,56,7,12,20,11,4,11,20,10,23,10,11,56,8,10,6,11,16,52,12,14,46,11,14,56,15,12,19,10,6,10,19,10,23,11,11,56,16,10,6,11,25,52,12,15,46,11,15,56,15,12,22,11,6,10,22,56,17,11,5,11,23,11,8,11,19,11,22,22,18,4,56,18,2,0]],["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"],"0xb2345915de1f9bd661e9ab27eb27e376cdf6391359ea64fbfdb4550b092c1aa0",{"Result":0}]},{"MoveCall":{"package":"0x0000000000000000000000000000000000000000000000000000000000000002","module":"package","function":"commit_upgrade","type_arguments":[],"arguments":[{"Input":0},{"Result":1}]}}]}},"modified_at_versions":[["0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1",26932892],["0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623",10941462]],"shared_object_refs":[],"gas":[["0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1",26932892,"Ex867bCQkeiTCvcRqhkbAtZWPyVPcMbNRj1acbfyZdAs"]],"gas_budget":300000000,"gas_price":750,"executed_epoch":158,"dependencies":["3fqrGiknVvk82qum6zLYR749UTTyavaoH8TLU6bym8di","5rr1KbGr5ht2kWrPwgArYuaYsauoDG8CpuJLnaKnkgL6","7SuYS2Zphhb7KFnoanQBArUmXUQjKhehZ5fQkET4wNcN","ACKQVv64dXCmpxE1QPU2QMLxVpmtbzrFGMtWYY6szJrQ","BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn"],"effects":{"messageVersion":"v1","status":{"status":"success"},"executedEpoch":"158","gasUsed":{"computationCost":"750000","storageCost":"216204800","storageRebate":"2595780","nonRefundableStorageFee":"26220"},"modifiedAtVersions":[{"objectId":"0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1","sequenceNumber":"26932892"},{"objectId":"0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623","sequenceNumber":"10941462"}],"transactionDigest":"4fxF3X4N8D6JGByWdbJvCCv1iuoT8GSEhXgPHJnzNHWP","created":[{"owner":"Immutable","reference":{"objectId":"0x0440aedc27c9a57ea357bd8fe1525a00d60d7f442a380924a7e7c1d79853bb8b","version":5,"digest":"Gm4LuFuwBvgmBuLSMAxEp2zkp1RLsfgwzv8xdscmzowH"}}],"mutated":[{"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"reference":{"objectId":"0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1","version":26932893,"digest":"J4QwR5VqcZDAekVtbABBjvZ6n1sCi4nDS7hBiaDkex37"}},{"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"reference":{"objectId":"0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623","version":26932893,"digest":"Bt3M5wQ3RStRoKWwioJ8vJUQvxL453r9HWBH2MpBzQaA"}}],"gasObject":{"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"reference":{"objectId":"0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1","version":26932893,"digest":"J4QwR5VqcZDAekVtbABBjvZ6n1sCi4nDS7hBiaDkex37"}},"dependencies":["3fqrGiknVvk82qum6zLYR749UTTyavaoH8TLU6bym8di","5rr1KbGr5ht2kWrPwgArYuaYsauoDG8CpuJLnaKnkgL6","7SuYS2Zphhb7KFnoanQBArUmXUQjKhehZ5fQkET4wNcN","ACKQVv64dXCmpxE1QPU2QMLxVpmtbzrFGMtWYY6szJrQ","BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn"]},"protocol_version":23,"epoch_start_timestamp":1694970685122,"reference_gas_price":750},"required_objects":[{"data":{"Move":{"type_":"GasCoin","has_public_transfer":true,"version":26932892,"contents":[179,30,221,225,60,75,107,81,44,23,235,191,230,227,135,11,211,138,190,145,151,205,207,128,30,246,4,231,19,97,15,161,200,98,235,223,0,0,0,0]}},"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"previous_transaction":"7SuYS2Zphhb7KFnoanQBArUmXUQjKhehZ5fQkET4wNcN","storage_rebate":988000},{"data":{"Move":{"type_":{"Other":{"address":"0000000000000000000000000000000000000000000000000000000000000002","module":"package","name":"UpgradeCap","type_args":[]}},"has_public_transfer":true,"version":10941462,"contents":[219,161,180,15,53,55,68,27,81,210,132,143,192,161,73,97,14,72,230,124,28,196,140,106,214,65,118,118,34,0,6,35,178,52,89,21,222,31,155,214,97,233,171,39,235,39,227,118,205,246,57,19,89,234,100,251,253,180,85,11,9,44,26,160,4,0,0,0,0,0,0,0,0]}},"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"previous_transaction":"3fqrGiknVvk82qum6zLYR749UTTyavaoH8TLU6bym8di","storage_rebate":1634000},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000001","version":2,"module_map":{"address":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,3,7,10,15,8,25,32,12,57,16,0,0,0,1,0,1,0,0,1,3,7,97,100,100,114,101,115,115,6,108,101,110,103,116,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,6,32,0,0,0,0,0,0,0,2,0],"ascii":[161,28,235,11,6,0,0,0,11,1,0,4,2,4,14,3,18,84,4,102,8,5,110,59,7,169,1,200,1,8,241,2,32,6,145,3,10,10,155,3,11,12,166,3,186,2,13,224,5,4,0,5,0,16,0,2,7,0,0,0,7,0,1,1,7,1,0,0,0,8,0,1,0,0,20,2,3,0,0,21,2,4,0,0,3,5,6,0,0,18,7,8,0,0,17,9,1,0,0,14,5,10,0,0,4,5,11,0,0,10,3,2,0,0,6,1,0,0,0,13,0,6,0,0,11,0,6,0,1,9,13,14,1,0,1,12,12,6,1,0,1,15,8,13,1,0,1,19,14,13,1,0,13,3,12,3,14,3,15,3,1,2,1,8,1,1,10,2,1,8,0,1,11,2,1,8,0,1,6,8,0,1,1,2,7,8,0,8,1,0,1,7,8,0,1,3,1,6,10,2,1,6,11,2,1,9,0,1,11,2,1,9,0,1,9,0,2,3,3,4,67,104,97,114,6,79,112,116,105,111,110,6,83,116,114,105,110,103,24,97,108,108,95,99,104,97,114,97,99,116,101,114,115,95,112,114,105,110,116,97,98,108,101,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,4,98,121,116,101,5,98,121,116,101,115,4,99,104,97,114,12,100,101,115,116,114,111,121,95,115,111,109,101,10,105,110,116,111,95,98,121,116,101,115,17,105,115,95,112,114,105,110,116,97,98,108,101,95,99,104,97,114,7,105,115,95,115,111,109,101,13,105,115,95,118,97,108,105,100,95,99,104,97,114,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,8,112,111,112,95,99,104,97,114,9,112,117,115,104,95,99,104,97,114,4,115,111,109,101,6,115,116,114,105,110,103,10,116,114,121,95,115,116,114,105,110,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,1,0,0,0,0,0,0,2,1,7,10,2,1,2,1,6,2,0,1,0,0,8,9,10,0,17,10,4,4,5,6,7,0,39,11,0,18,1,2,1,1,0,0,4,12,11,0,17,2,12,1,14,1,56,0,4,7,5,9,7,0,39,11,1,56,1,2,2,1,0,0,15,30,14,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,25,5,11,14,0,10,1,66,0,20,17,10,32,4,20,56,2,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,5,40,11,0,18,0,56,3,2,3,1,0,0,15,32,10,0,16,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,29,5,12,10,0,16,0,10,1,66,0,20,17,11,32,4,24,11,0,1,9,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,40,8,2,4,1,0,0,8,7,11,0,15,0,14,1,16,1,20,68,0,2,5,1,0,0,8,5,11,0,15,0,69,0,18,1,2,6,1,0,0,8,4,11,0,17,7,65,0,2,7,1,0,0,8,3,11,0,16,0,2,8,1,0,0,8,3,11,0,19,0,2,9,1,0,0,8,3,11,0,19,1,2,10,1,0,0,8,4,11,0,49,127,37,2,11,1,0,0,6,13,10,0,49,32,38,4,9,11,0,49,126,37,12,1,5,11,9,12,1,11,1,2,0,0,1,0,0],"bcs":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,7,7,15,13,8,28,32,12,60,4,0,0,0,1,0,1,1,0,1,6,9,0,1,10,2,3,98,99,115,8,116,111,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,0],"bit_vector":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,36,7,77,109,8,186,1,32,6,218,1,40,10,130,2,8,12,138,2,239,3,13,249,5,4,0,2,0,0,7,0,0,6,0,1,0,0,7,2,3,0,0,9,2,3,0,0,8,2,3,0,0,3,4,5,0,0,4,6,0,0,0,5,4,0,0,1,3,1,8,0,2,7,8,0,3,0,2,6,8,0,3,1,1,1,6,8,0,2,10,1,3,1,7,1,5,3,7,1,3,3,3,9,66,105,116,86,101,99,116,111,114,9,98,105,116,95,102,105,101,108,100,10,98,105,116,95,118,101,99,116,111,114,12,105,115,95,105,110,100,101,120,95,115,101,116,6,108,101,110,103,116,104,32,108,111,110,103,101,115,116,95,115,101,116,95,115,101,113,117,101,110,99,101,95,115,116,97,114,116,105,110,103,95,97,116,3,110,101,119,3,115,101,116,10,115,104,105,102,116,95,108,101,102,116,5,117,110,115,101,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,3,8,1,0,2,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,4,0,0,0,0,0,0,0,2,2,4,3,1,10,1,0,1,0,0,7,37,10,0,6,0,0,0,0,0,0,0,0,36,4,5,5,7,7,1,39,10,0,7,3,35,4,12,5,14,7,1,39,6,0,0,0,0,0,0,0,0,12,2,64,5,0,0,0,0,0,0,0,0,12,1,40,10,2,10,0,35,4,32,5,24,13,1,9,68,5,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,18,40,11,0,11,1,18,0,2,1,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,8,11,2,21,2,2,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,9,11,2,21,2,3,1,0,0,9,89,10,1,10,0,16,1,20,38,4,33,10,0,16,0,65,5,12,6,6,0,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,30,5,17,10,0,15,0,10,4,67,5,12,3,9,11,3,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,12,11,0,1,5,88,10,1,12,5,10,5,10,0,16,1,20,35,4,65,5,42,10,0,10,5,12,2,46,11,2,17,4,4,55,10,0,10,5,10,1,23,17,1,5,60,10,0,10,5,10,1,23,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,35,10,0,16,1,20,11,1,23,12,5,10,5,10,0,16,1,20,35,4,86,5,78,10,0,10,5,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,71,11,0,1,2,4,1,0,0,3,17,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,16,0,11,1,66,5,20,2,5,1,0,0,3,4,11,0,16,0,65,5,2,6,1,0,0,0,37,10,1,10,0,16,1,20,35,4,7,5,11,11,0,1,7,0,39,10,1,12,2,10,2,10,0,16,1,20,35,4,33,5,20,10,0,10,2,17,4,32,4,28,11,0,1,5,33,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,13,11,2,11,1,23,2,0,1,0,0,0],"debug":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,11,5,13,5,7,18,30,8,48,32,12,80,8,0,0,0,1,0,1,1,0,0,2,1,1,0,1,6,9,0,0,5,100,101,98,117,103,5,112,114,105,110,116,17,112,114,105,110,116,95,115,116,97,99,107,95,116,114,97,99,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"fixed_point32":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,30,5,36,22,7,58,122,8,180,1,32,6,212,1,68,10,152,2,5,12,157,2,137,2,13,166,4,2,0,4,0,0,7,0,0,7,0,1,0,0,3,0,1,0,0,1,2,3,0,0,2,1,3,0,0,5,3,1,0,0,6,3,4,0,2,3,8,0,1,3,2,3,3,1,8,0,1,1,1,4,4,1,4,4,4,0,12,70,105,120,101,100,80,111,105,110,116,51,50,20,99,114,101,97,116,101,95,102,114,111,109,95,114,97,116,105,111,110,97,108,21,99,114,101,97,116,101,95,102,114,111,109,95,114,97,119,95,118,97,108,117,101,10,100,105,118,105,100,101,95,117,54,52,13,102,105,120,101,100,95,112,111,105,110,116,51,50,13,103,101,116,95,114,97,119,95,118,97,108,117,101,7,105,115,95,122,101,114,111,12,109,117,108,116,105,112,108,121,95,117,54,52,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,16,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,3,8,1,0,1,0,0,0,0,0,3,8,2,0,2,0,0,0,0,0,3,8,3,0,2,0,0,0,0,0,3,8,4,0,1,0,0,0,0,0,3,8,5,0,2,0,0,0,0,0,0,2,1,8,3,0,1,0,0,5,20,11,0,53,14,1,16,0,20,53,24,49,32,48,12,2,10,2,7,0,37,4,15,5,17,7,3,39,11,2,52,2,1,1,0,0,5,29,14,1,16,0,20,6,0,0,0,0,0,0,0,0,34,4,7,5,9,7,4,39,11,0,53,49,32,47,14,1,16,0,20,53,26,12,2,10,2,7,0,37,4,24,5,26,7,2,39,11,2,52,2,2,1,0,0,6,48,10,0,53,49,64,47,12,5,11,1,53,49,32,47,12,4,10,4,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,15,5,17,7,1,39,11,5,11,4,26,12,3,10,3,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,8,12,2,5,32,11,0,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,35,5,37,7,5,39,10,3,7,0,37,4,42,5,44,7,5,39,11,3,52,18,0,2,3,1,0,0,7,3,11,0,18,0,2,4,1,0,0,7,4,14,0,16,0,20,2,5,1,0,0,7,6,14,0,16,0,20,6,0,0,0,0,0,0,0,0,33,2,0,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,3,7,15,23,8,38,32,12,70,8,0,0,0,1,0,0,0,0,2,0,0,0,1,10,2,4,104,97,115,104,8,115,104,97,50,95,50,53,54,8,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"option":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,6,3,10,120,4,130,1,14,5,144,1,135,1,7,151,2,219,1,8,242,3,32,6,146,4,20,10,166,4,7,11,173,4,2,12,175,4,128,4,13,175,8,2,14,177,8,2,0,15,0,22,0,0,7,1,0,0,0,14,0,1,1,0,0,17,2,1,1,0,0,12,3,4,1,0,0,13,3,4,1,0,0,4,5,4,1,0,0,1,3,6,1,0,0,3,5,6,1,0,0,10,7,2,1,3,0,9,8,0,1,0,0,8,9,2,1,0,0,2,9,10,1,0,0,18,8,2,1,0,0,19,8,1,1,0,0,7,11,2,1,2,0,6,1,2,1,0,0,5,1,0,1,0,0,20,1,12,1,0,1,4,14,4,1,0,1,11,13,4,1,0,1,16,2,12,1,0,19,2,18,2,17,2,3,2,0,2,1,2,2,2,0,1,11,0,1,9,0,1,9,0,1,6,11,0,1,9,0,1,1,2,6,11,0,1,9,0,6,9,0,1,6,9,0,2,6,11,0,1,9,0,9,0,2,7,11,0,1,9,0,9,0,1,7,11,0,1,9,0,1,7,9,0,2,11,0,1,9,0,9,0,1,10,9,0,1,6,10,9,0,2,6,10,9,0,6,9,0,2,6,9,0,6,10,9,0,2,9,0,6,10,9,0,1,7,10,9,0,2,9,0,7,10,9,0,3,11,0,1,9,0,11,0,1,9,0,7,10,9,0,2,9,0,10,9,0,6,79,112,116,105,111,110,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,119,105,116,104,95,100,101,102,97,117,108,116,8,99,111,110,116,97,105,110,115,12,100,101,115,116,114,111,121,95,110,111,110,101,12,100,101,115,116,114,111,121,95,115,111,109,101,20,100,101,115,116,114,111,121,95,119,105,116,104,95,100,101,102,97,117,108,116,7,101,120,116,114,97,99,116,4,102,105,108,108,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,4,110,111,110,101,6,111,112,116,105,111,110,9,115,105,110,103,108,101,116,111,110,4,115,111,109,101,4,115,119,97,112,12,115,119,97,112,95,111,114,95,102,105,108,108,6,116,111,95,118,101,99,3,118,101,99,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,4,0,0,0,0,0,3,8,1,0,4,0,0,0,0,0,0,2,1,21,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,0,4,11,0,55,0,56,1,2,3,1,0,0,0,5,11,0,55,0,56,1,32,2,4,1,0,0,0,5,11,0,55,0,11,1,56,2,2,5,1,0,0,0,13,10,0,56,3,4,4,5,8,11,0,1,7,1,39,11,0,55,0,6,0,0,0,0,0,0,0,0,66,2,2,6,1,0,0,15,19,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,17,11,1,1,11,3,6,0,0,0,0,0,0,0,0,66,2,12,2,11,2,2,7,1,0,0,16,18,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,16,11,3,6,0,0,0,0,0,0,0,0,66,2,20,12,2,11,2,2,8,1,0,0,17,16,11,0,54,0,12,2,10,2,46,56,1,4,8,5,12,11,2,1,7,0,39,11,2,11,1,68,2,2,9,1,0,0,0,13,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,69,2,2,10,1,0,0,0,14,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,6,0,0,0,0,0,0,0,0,67,2,2,11,1,0,0,18,20,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,12,3,10,3,69,2,12,2,11,3,11,1,68,2,11,2,2,12,1,0,0,19,21,11,0,54,0,12,4,10,4,46,56,1,4,10,56,4,12,2,5,14,10,4,69,2,56,5,12,2,11,2,12,3,11,4,11,1,68,2,11,3,2,13,1,0,0,20,15,11,0,58,0,12,3,13,3,46,56,1,4,10,11,1,12,2,5,13,13,3,69,2,12,2,11,2,2,14,1,0,0,20,16,14,0,56,3,4,4,5,6,7,1,39,11,0,58,0,12,2,13,2,69,2,12,1,11,2,70,2,0,0,0,0,0,0,0,0,11,1,2,15,1,0,0,0,10,14,0,56,6,4,4,5,6,7,0,39,11,0,58,0,70,2,0,0,0,0,0,0,0,0,2,16,1,0,0,0,3,11,0,58,0,2,0,0,0,2,0],"string":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,14,3,22,114,4,136,1,8,5,144,1,123,7,139,2,248,1,8,131,4,32,6,163,4,20,10,183,4,6,12,189,4,133,3,13,194,7,2,0,19,0,4,0,17,0,24,0,1,7,0,1,1,7,0,2,0,7,1,0,0,0,23,0,1,0,0,6,2,1,0,0,21,1,2,0,0,22,0,3,0,0,5,4,5,0,0,14,4,6,0,0,15,4,7,0,0,2,8,9,0,0,3,10,9,0,0,8,11,9,0,0,20,12,1,0,0,7,13,7,0,0,9,5,6,0,0,11,14,6,0,0,12,15,0,0,0,10,16,7,0,1,13,2,0,0,1,19,0,2,0,2,16,9,18,1,0,2,18,17,18,1,0,3,2,21,9,1,0,3,14,20,6,1,0,19,1,18,1,21,19,20,19,1,10,2,1,8,0,1,8,1,1,11,2,1,8,0,1,6,8,0,1,6,10,2,1,1,1,3,2,7,8,0,8,0,0,2,7,8,0,10,2,3,7,8,0,3,8,0,3,6,8,0,3,3,2,6,8,0,6,8,0,2,6,10,2,3,3,6,10,2,3,3,2,6,10,2,6,10,2,1,9,0,1,11,2,1,9,0,1,2,1,6,10,9,0,2,7,10,9,0,10,9,0,8,1,3,3,3,6,10,2,8,0,8,0,3,5,1,1,1,6,10,2,3,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,97,112,112,101,110,100,11,97,112,112,101,110,100,95,117,116,102,56,5,97,115,99,105,105,5,98,121,116,101,115,10,102,114,111,109,95,97,115,99,105,105,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,19,105,110,116,101,114,110,97,108,95,99,104,101,99,107,95,117,116,102,56,17,105,110,116,101,114,110,97,108,95,105,110,100,101,120,95,111,102,25,105,110,116,101,114,110,97,108,95,105,115,95,99,104,97,114,95,98,111,117,110,100,97,114,121,19,105,110,116,101,114,110,97,108,95,115,117,98,95,115,116,114,105,110,103,10,105,110,116,111,95,98,121,116,101,115,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,4,115,111,109,101,6,115,116,114,105,110,103,10,115,117,98,95,115,116,114,105,110,103,8,116,111,95,97,115,99,105,105,8,116,114,121,95,117,116,102,56,4,117,116,102,56,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,5,10,2,0,1,0,0,9,9,14,0,17,12,4,4,5,6,7,0,39,11,0,18,0,2,1,1,0,0,9,4,11,0,17,16,18,0,2,2,1,0,0,9,4,11,0,19,0,17,17,2,3,1,0,0,3,12,14,0,17,12,4,8,11,0,18,0,56,0,12,1,5,10,56,1,12,1,11,1,2,4,1,0,0,9,3,11,0,16,0,2,5,1,0,0,9,4,11,0,16,0,56,2,2,6,1,0,0,9,4,11,0,16,0,65,19,2,7,1,0,0,9,7,11,0,15,0,14,1,16,0,20,56,3,2,8,1,0,0,9,5,11,0,11,1,17,0,17,7,2,9,1,0,0,22,56,10,0,16,0,12,7,10,1,10,7,65,19,37,4,13,11,7,10,1,17,13,12,3,5,17,11,7,1,9,12,3,11,3,4,20,5,24,11,0,1,7,1,39,10,0,46,17,6,12,10,10,0,10,1,12,4,46,6,0,0,0,0,0,0,0,0,11,4,17,10,12,9,10,0,11,1,11,10,12,6,12,5,46,11,5,11,6,17,10,12,8,13,9,11,2,17,7,13,9,11,8,17,7,11,9,11,0,21,2,10,1,0,0,23,48,11,0,16,0,12,6,10,6,65,19,12,7,10,2,11,7,37,4,15,10,1,10,2,37,12,3,5,17,9,12,3,11,3,4,24,10,6,10,1,17,13,12,4,5,26,9,12,4,11,4,4,33,10,6,10,2,17,13,12,5,5,35,9,12,5,11,5,4,38,5,42,11,6,1,7,1,39,11,6,11,1,11,2,17,14,18,0,2,11,1,0,0,9,6,11,0,16,0,11,1,16,0,17,15,2,12,0,2,0,13,0,2,0,14,0,2,0,15,0,2,0,0,0,0],"type_name":[161,28,235,11,6,0,0,0,10,1,0,6,2,6,8,3,14,47,5,61,44,7,105,143,1,8,248,1,32,6,152,2,7,10,159,2,6,12,165,2,215,1,13,252,3,2,0,14,0,2,0,4,0,1,7,0,2,0,7,0,0,6,0,1,1,0,0,9,0,1,1,0,0,5,2,3,0,0,7,2,4,0,0,8,2,4,0,0,10,1,4,0,1,11,0,6,0,2,3,3,7,0,2,13,9,4,0,0,1,8,0,1,6,8,0,1,6,8,1,1,8,1,4,10,2,3,3,6,10,2,1,3,1,6,10,2,1,2,1,10,2,5,2,6,2,3,10,2,6,10,2,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,13,98,111,114,114,111,119,95,115,116,114,105,110,103,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,11,105,110,116,111,95,115,116,114,105,110,103,6,108,101,110,103,116,104,4,110,97,109,101,6,115,116,114,105,110,103,9,116,121,112,101,95,110,97,109,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,58,10,2,1,0,0,2,1,12,8,1,0,1,2,0,1,1,2,0,2,1,0,0,0,3,11,0,16,0,2,3,1,0,0,5,33,17,6,6,2,0,0,0,0,0,0,0,24,12,3,11,0,16,0,17,7,12,4,7,1,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,28,5,17,13,1,10,4,10,2,66,8,20,68,8,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,4,1,11,1,17,8,2,4,1,0,0,10,39,17,6,6,2,0,0,0,0,0,0,0,24,6,2,0,0,0,0,0,0,0,22,12,3,11,0,16,0,17,7,12,5,7,1,12,4,10,5,10,3,66,8,12,2,7,0,12,1,10,2,14,1,34,4,32,5,23,13,4,11,2,20,68,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,12,11,5,1,11,2,1,11,4,17,8,2,5,1,0,0,0,4,14,0,16,0,20,2,0,0,0],"vector":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,102,4,104,4,5,108,97,7,205,1,154,1,8,231,2,32,6,135,3,10,12,145,3,216,4,0,17,0,5,0,1,1,0,0,9,2,3,1,0,0,1,4,5,1,0,0,11,6,0,1,0,0,2,7,8,1,0,0,10,9,10,1,0,0,4,1,0,1,0,0,15,11,0,1,0,0,14,10,1,1,0,0,13,9,0,1,0,0,0,12,0,1,0,0,8,2,13,1,0,0,3,14,13,1,0,0,6,14,15,1,0,0,12,7,10,1,0,0,7,16,0,1,0,0,16,7,10,1,0,9,10,11,10,0,1,10,9,0,1,6,10,9,0,1,3,2,6,10,9,0,3,1,6,9,0,2,7,10,9,0,9,0,2,7,10,9,0,3,1,7,9,0,1,7,10,9,0,1,9,0,3,7,10,9,0,3,3,2,7,10,9,0,10,9,0,1,1,2,6,10,9,0,6,9,0,2,1,3,3,7,10,9,0,9,0,3,3,3,3,3,2,3,3,3,3,7,10,9,0,3,6,97,112,112,101,110,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,5,101,109,112,116,121,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,7,114,101,118,101,114,115,101,9,115,105,110,103,108,101,116,111,110,4,115,119,97,112,11,115,119,97,112,95,114,101,109,111,118,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,2,0,4,1,2,0,5,1,2,0,6,1,2,0,7,1,2,0,8,1,0,0,1,7,64,10,0,0,0,0,0,0,0,0,12,1,13,1,11,0,68,10,11,1,2,9,1,0,0,17,38,10,0,46,65,10,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,2,6,0,0,0,0,0,0,0,0,12,2,11,3,6,1,0,0,0,0,0,0,0,23,12,1,10,2,10,1,35,4,35,5,22,10,0,10,2,10,1,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,1,6,1,0,0,0,0,0,0,0,23,12,1,5,17,11,0,1,2,10,1,0,0,0,17,13,1,56,0,14,1,56,1,32,4,12,5,7,10,0,13,1,69,10,68,10,5,2,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,11,1,0,0,0,5,11,0,65,10,6,0,0,0,0,0,0,0,0,33,2,12,1,0,0,18,33,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,27,5,10,10,0,10,2,66,10,10,1,33,4,22,11,0,1,11,1,1,8,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,2,13,1,0,0,18,35,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,28,5,10,10,0,10,2,66,10,10,1,33,4,23,11,0,1,11,1,1,8,11,2,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,6,0,0,0,0,0,0,0,0,2,14,1,0,0,19,37,10,0,46,65,10,12,4,10,1,10,4,38,4,12,11,0,1,7,0,39,11,4,6,1,0,0,0,0,0,0,0,23,12,4,10,1,10,4,35,4,34,5,21,10,0,12,3,10,1,12,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,11,3,11,2,10,1,71,10,5,16,11,0,69,10,2,15,1,0,0,3,32,10,0,46,65,10,12,3,10,2,10,3,36,4,12,11,0,1,7,0,39,10,0,11,1,68,10,10,2,10,3,35,4,29,5,20,10,0,10,2,10,3,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,2,16,1,0,0,3,23,10,0,46,56,1,32,4,6,5,10,11,0,1,7,0,39,10,0,46,65,10,6,1,0,0,0,0,0,0,0,23,12,2,10,0,11,1,11,2,71,10,11,0,69,10,2,0]},"type_origin_table":[{"module_name":"fixed_point32","struct_name":"FixedPoint32","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"option","struct_name":"Option","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"Char","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"bit_vector","struct_name":"BitVector","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"string","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"type_name","struct_name":"TypeName","package":"0x0000000000000000000000000000000000000000000000000000000000000001"}],"linkage_table":{}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000002","version":10,"module_map":{"address":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,8,3,18,61,4,79,2,5,81,20,7,101,129,1,8,230,1,64,6,166,2,54,12,220,2,69,0,1,1,2,1,3,1,11,0,8,1,0,7,0,3,0,7,0,0,15,0,1,0,0,7,1,0,0,0,6,2,0,0,0,13,0,2,0,0,12,0,3,0,0,14,0,4,0,0,9,5,6,0,0,10,5,1,0,1,11,2,3,0,2,13,7,2,1,0,3,5,3,4,0,4,4,2,2,0,9,0,1,5,1,15,1,10,2,1,8,0,1,8,1,0,1,3,1,6,9,0,6,83,116,114,105,110,103,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,6,101,110,99,111,100,101,10,102,114,111,109,95,97,115,99,105,105,10,102,114,111,109,95,98,121,116,101,115,9,102,114,111,109,95,117,50,53,54,3,104,101,120,6,108,101,110,103,116,104,3,109,97,120,6,115,116,114,105,110,103,15,116,111,95,97,115,99,105,105,95,115,116,114,105,110,103,8,116,111,95,98,121,116,101,115,9,116,111,95,115,116,114,105,110,103,7,116,111,95,117,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,32,0,0,0,0,0,0,0,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,3,8,0,0,0,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,0,0,5,3,14,0,56,0,2,4,1,0,0,5,5,11,0,17,3,17,11,17,8,2,5,1,0,0,5,4,11,0,17,4,17,10,2,6,1,0,0,5,2,7,0,2,7,1,0,0,5,2,7,1,2,0],"bag":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,112,4,132,1,12,5,144,1,82,7,226,1,185,1,8,155,3,32,6,187,3,10,10,197,3,8,12,205,3,230,1,13,179,5,4,0,4,0,11,0,18,0,21,0,0,12,0,2,2,4,0,3,1,2,0,0,17,0,1,0,0,3,2,3,2,7,4,0,5,4,5,2,7,4,0,6,6,7,2,7,4,0,19,6,8,2,7,4,0,7,4,9,1,7,0,8,4,9,2,7,4,0,16,10,11,0,0,15,10,9,0,0,10,1,3,0,1,3,14,3,2,7,4,1,5,15,5,2,7,4,1,6,16,7,2,7,4,1,12,15,9,1,7,1,13,15,9,2,7,4,1,19,16,8,2,7,4,2,9,12,3,0,2,17,0,12,0,10,13,11,13,12,13,15,13,13,17,14,13,1,7,8,2,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,1,9,0,2,8,1,3,3,66,97,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,3,98,97,103,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,14,8,1,20,3,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,18,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,0,0,0,1,0],"balance":[161,28,235,11,6,0,0,0,14,1,0,4,2,4,16,3,20,83,4,103,2,5,105,99,7,204,1,224,1,8,172,3,32,6,204,3,74,10,150,4,10,11,160,4,4,12,164,4,219,2,13,255,6,4,14,131,7,4,15,135,7,2,0,3,0,16,0,1,4,1,0,1,0,0,4,1,0,1,1,2,2,0,0,17,0,1,1,0,0,15,2,1,1,0,0,5,3,4,1,2,0,10,5,6,1,0,0,6,7,1,1,0,0,19,8,6,1,0,0,11,9,1,1,0,0,13,10,6,1,0,0,18,11,6,1,0,0,9,6,8,1,0,0,4,12,6,1,0,0,7,13,8,1,0,0,8,4,1,1,0,1,12,14,15,0,7,3,1,6,11,1,1,9,0,1,3,1,6,11,0,1,9,0,1,9,0,1,11,0,1,9,0,2,7,11,0,1,9,0,3,1,11,1,1,9,0,2,7,11,0,1,9,0,11,1,1,9,0,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,7,11,1,1,9,0,2,3,6,8,2,2,11,1,1,9,0,6,8,2,1,6,8,2,1,5,7,66,97,108,97,110,99,101,6,83,117,112,112,108,121,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,22,99,114,101,97,116,101,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,115,13,99,114,101,97,116,101,95,115,117,112,112,108,121,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,23,100,101,115,116,114,111,121,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,12,100,101,115,116,114,111,121,95,122,101,114,111,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,4,106,111,105,110,6,115,101,110,100,101,114,5,115,112,108,105,116,3,115,117,105,12,115,117,112,112,108,121,95,118,97,108,117,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,17,3,1,2,1,17,3,0,3,1,3,0,1,0,0,8,4,11,0,55,0,20,2,1,1,0,0,8,4,11,0,55,1,20,2,2,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,0,2,3,1,0,0,8,24,10,1,6,255,255,255,255,255,255,255,255,10,0,55,1,20,23,35,4,9,5,13,11,0,1,7,1,39,10,0,55,1,20,10,1,22,11,0,54,1,21,11,1,57,1,2,4,1,0,0,1,24,11,1,58,1,12,2,10,0,55,1,20,10,2,38,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,10,2,23,11,0,54,1,21,11,2,2,5,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,1,2,6,1,0,0,1,15,11,1,58,1,12,2,10,0,55,0,20,11,2,22,10,0,54,0,21,11,0,55,0,20,2,7,1,0,0,8,22,10,0,55,0,20,10,1,38,4,7,5,11,11,0,1,7,2,39,10,0,55,0,20,10,1,23,11,0,54,0,21,11,1,57,1,2,8,1,0,0,1,8,10,0,55,0,20,12,1,11,0,11,1,56,0,2,9,1,0,0,8,13,14,0,55,0,20,6,0,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,11,0,58,1,1,2,10,0,0,0,8,11,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,57,1,2,11,0,0,0,8,12,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,58,1,1,2,12,3,0,0,8,3,11,0,58,0,2,1,0,0,0,0,3,1,3,0,14,0],"bcs":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,10,3,20,135,1,4,155,1,24,5,179,1,131,1,7,182,2,222,2,8,148,5,64,6,212,5,55,10,139,6,6,12,145,6,203,8,13,220,14,2,0,3,1,3,1,10,1,31,0,2,0,0,7,0,2,1,7,1,0,0,0,30,0,1,1,0,0,8,1,2,0,0,6,2,1,0,0,11,3,4,0,0,12,3,5,0,0,20,3,6,0,0,19,3,7,0,0,18,3,8,0,0,23,3,7,0,0,21,3,9,0,0,22,3,10,0,0,26,3,1,0,0,27,3,11,0,0,25,3,12,0,0,24,3,13,0,0,13,3,14,0,0,14,3,15,0,0,17,3,16,0,0,16,3,17,0,0,15,3,18,0,1,30,0,1,1,0,2,9,19,33,1,0,2,29,20,33,1,0,3,28,21,19,1,0,4,5,1,4,0,4,7,19,7,0,20,20,23,6,22,4,21,4,22,5,21,5,22,6,21,6,22,7,21,7,22,8,21,8,1,6,9,0,1,10,2,1,8,0,1,7,8,0,1,5,1,1,1,2,1,3,1,4,1,10,5,1,10,1,1,10,10,2,1,10,3,1,10,4,1,11,1,1,5,1,11,1,1,1,1,11,1,1,2,1,11,1,1,3,1,11,1,1,4,0,1,9,0,1,7,10,9,0,2,10,2,3,2,1,2,3,3,2,3,3,4,2,4,4,3,3,2,3,3,3,3,10,5,3,3,3,10,1,3,3,3,10,2,3,3,3,10,10,2,3,3,3,10,3,3,3,3,10,4,1,11,1,1,9,0,3,66,67,83,6,79,112,116,105,111,110,7,97,100,100,114,101,115,115,3,98,99,115,5,98,121,116,101,115,10,102,114,111,109,95,98,121,116,101,115,20,105,110,116,111,95,114,101,109,97,105,110,100,101,114,95,98,121,116,101,115,6,108,101,110,103,116,104,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,12,112,101,101,108,95,97,100,100,114,101,115,115,9,112,101,101,108,95,98,111,111,108,19,112,101,101,108,95,111,112,116,105,111,110,95,97,100,100,114,101,115,115,16,112,101,101,108,95,111,112,116,105,111,110,95,98,111,111,108,16,112,101,101,108,95,111,112,116,105,111,110,95,117,49,50,56,15,112,101,101,108,95,111,112,116,105,111,110,95,117,54,52,14,112,101,101,108,95,111,112,116,105,111,110,95,117,56,9,112,101,101,108,95,117,49,50,56,8,112,101,101,108,95,117,54,52,7,112,101,101,108,95,117,56,16,112,101,101,108,95,118,101,99,95,97,100,100,114,101,115,115,13,112,101,101,108,95,118,101,99,95,98,111,111,108,15,112,101,101,108,95,118,101,99,95,108,101,110,103,116,104,13,112,101,101,108,95,118,101,99,95,117,49,50,56,12,112,101,101,108,95,118,101,99,95,117,54,52,11,112,101,101,108,95,118,101,99,95,117,56,15,112,101,101,108,95,118,101,99,95,118,101,99,95,117,56,7,114,101,118,101,114,115,101,4,115,111,109,101,8,116,111,95,98,121,116,101,115,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,10,5,1,0,10,1,1,0,10,2,1,0,10,10,2,1,0,10,3,1,0,10,4,1,0,0,2,1,4,10,2,0,1,0,0,19,3,11,0,56,0,2,1,1,0,0,19,5,13,0,56,1,11,0,18,0,2,2,1,0,0,1,7,11,0,19,0,12,1,13,1,56,1,11,1,2,3,1,0,0,22,35,10,0,16,0,65,6,17,25,38,4,7,5,11,11,0,1,7,0,39,64,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,12,2,12,1,10,2,17,25,35,4,30,5,20,13,1,10,0,15,0,69,6,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,11,1,17,24,2,4,1,0,0,23,21,11,0,17,5,12,2,10,2,49,0,33,4,10,9,12,1,5,19,11,2,49,1,33,4,15,5,17,7,1,39,8,12,1,11,1,2,5,1,0,0,19,15,10,0,16,0,65,6,6,1,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,11,0,15,0,69,6,2,6,1,0,0,24,40,10,0,16,0,65,6,6,8,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,64,35,4,36,5,20,10,0,15,0,69,6,52,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,7,1,0,0,25,40,10,0,16,0,65,6,6,16,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,128,35,4,36,5,20,10,0,15,0,69,6,53,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,8,1,0,0,26,48,6,0,0,0,0,0,0,0,0,49,0,6,0,0,0,0,0,0,0,0,12,2,12,3,12,4,10,2,6,4,0,0,0,0,0,0,0,37,4,11,5,15,11,0,1,7,2,39,10,0,15,0,69,6,52,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,4,10,1,6,127,0,0,0,0,0,0,0,28,10,3,47,27,12,4,11,1,6,128,0,0,0,0,0,0,0,28,6,0,0,0,0,0,0,0,0,33,4,39,5,44,11,3,49,7,22,12,3,5,6,11,0,1,11,4,2,9,1,0,0,27,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,3,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,3,68,4,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,10,1,0,0,28,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,4,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,4,68,5,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,11,1,0,0,29,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,5,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,5,68,6,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,12,1,0,0,30,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,6,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,11,68,1,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,13,1,0,0,31,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,7,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,6,68,7,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,14,1,0,0,32,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,8,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,7,68,8,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,15,1,0,0,14,14,10,0,17,4,4,8,11,0,17,3,56,2,12,1,5,12,11,0,1,56,3,12,1,11,1,2,16,1,0,0,15,14,10,0,17,4,4,8,11,0,17,4,56,4,12,1,5,12,11,0,1,56,5,12,1,11,1,2,17,1,0,0,16,14,10,0,17,4,4,8,11,0,17,5,56,6,12,1,5,12,11,0,1,56,7,12,1,11,1,2,18,1,0,0,17,14,10,0,17,4,4,8,11,0,17,6,56,8,12,1,5,12,11,0,1,56,9,12,1,11,1,2,19,1,0,0,18,14,10,0,17,4,4,8,11,0,17,7,56,10,12,1,5,12,11,0,1,56,11,12,1,11,1,2,0,0,0],"bls12381":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,12,7,24,56,8,80,32,12,112,8,0,0,0,2,0,1,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,8,98,108,115,49,50,51,56,49,22,98,108,115,49,50,51,56,49,95,109,105,110,95,112,107,95,118,101,114,105,102,121,23,98,108,115,49,50,51,56,49,95,109,105,110,95,115,105,103,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"borrow":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,24,3,32,59,4,91,10,5,101,83,7,184,1,158,1,8,214,2,64,6,150,3,20,10,170,3,19,11,189,3,2,12,191,3,125,13,188,4,4,14,192,4,4,0,5,1,15,0,14,0,19,0,3,4,1,12,0,0,0,0,0,1,2,7,1,0,0,2,1,7,0,3,4,2,0,0,12,0,1,1,12,0,5,2,3,1,12,0,16,4,5,1,12,0,6,1,6,1,12,1,7,9,6,1,0,1,8,11,6,1,0,1,9,15,5,1,0,1,18,6,9,1,0,2,11,12,13,1,8,3,10,7,8,0,7,6,5,6,8,6,6,6,4,6,2,9,0,7,8,4,1,11,0,1,9,0,1,7,11,0,1,9,0,2,9,0,8,1,3,7,11,0,1,9,0,9,0,8,1,0,1,9,0,1,7,8,4,1,5,1,11,2,1,9,0,2,8,3,9,0,1,7,11,2,1,9,0,1,6,9,0,1,8,3,2,8,3,5,2,7,11,2,1,9,0,9,0,6,66,111,114,114,111,119,2,73,68,6,79,112,116,105,111,110,8,82,101,102,101,114,101,110,116,9,84,120,67,111,110,116,101,120,116,6,98,111,114,114,111,119,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,7,101,120,116,114,97,99,116,4,102,105,108,108,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,3,111,98,106,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,117,116,95,98,97,99,107,3,114,101,102,4,115,111,109,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,2,11,5,20,11,2,1,9,0,1,2,2,17,5,13,8,3,0,6,0,1,0,0,5,6,11,1,17,9,11,0,56,0,57,0,2,1,1,0,0,10,14,10,0,54,0,56,1,12,2,14,2,56,2,12,1,11,2,11,0,55,1,20,11,1,18,1,2,2,1,0,0,14,30,11,2,19,1,12,3,12,4,14,1,56,2,11,3,33,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,11,4,33,4,21,5,25,11,0,1,7,0,39,11,0,54,0,11,1,56,3,2,3,1,0,0,9,7,11,0,58,0,12,1,1,11,1,56,4,2,0,1,0,0,0,6,1,6,0],"clock":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,31,4,51,2,5,53,30,7,83,122,8,205,1,32,6,237,1,44,10,153,2,8,12,161,2,79,13,240,2,2,0,3,0,7,0,11,0,12,0,0,8,0,1,2,4,0,3,1,2,0,0,10,0,1,0,0,5,2,3,0,0,4,4,3,0,1,3,3,6,0,2,9,8,3,1,8,3,8,2,5,0,4,7,1,6,8,0,1,3,1,6,8,2,0,3,7,8,0,3,6,8,2,1,5,1,8,1,1,8,0,1,9,0,5,67,108,111,99,107,9,84,120,67,111,110,116,101,120,116,3,85,73,68,5,99,108,111,99,107,25,99,111,110,115,101,110,115,117,115,95,99,111,109,109,105,116,95,112,114,111,108,111,103,117,101,6,99,114,101,97,116,101,2,105,100,6,111,98,106,101,99,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,1,10,3,0,1,0,0,3,4,11,0,16,0,20,2,1,0,0,0,3,13,11,0,17,5,7,1,33,4,6,5,8,7,0,39,17,3,6,0,0,0,0,0,0,0,0,18,0,56,0,2,2,0,0,0,3,15,11,2,17,5,7,1,33,4,6,5,10,11,0,1,7,0,39,11,1,11,0,15,0,21,2,0,1,0],"coin":[161,28,235,11,6,0,0,0,13,1,0,20,2,20,62,3,82,155,2,4,237,2,34,5,143,3,221,2,7,236,5,164,5,8,144,11,64,6,208,11,30,10,238,11,52,11,162,12,6,12,168,12,249,4,13,161,17,14,14,175,17,14,0,15,1,11,1,43,1,48,0,12,0,42,0,56,0,58,0,59,0,64,0,1,12,1,0,1,0,2,12,1,0,1,0,7,12,1,0,1,0,3,3,1,0,1,1,5,7,0,2,4,7,1,0,0,3,5,7,0,4,0,4,1,0,1,4,6,4,1,0,1,5,9,4,0,7,8,2,0,9,10,7,0,0,55,0,1,1,0,0,57,2,3,1,0,0,50,0,4,1,0,0,51,5,6,1,0,0,66,7,1,1,0,0,12,7,8,1,0,0,13,9,10,1,0,0,24,11,12,1,0,0,33,12,13,1,0,0,54,14,12,1,0,0,45,15,16,1,0,0,35,17,16,1,0,0,47,18,12,1,0,0,23,18,19,1,0,0,67,20,12,1,0,0,22,12,16,1,0,0,16,21,22,1,2,0,36,23,12,1,0,0,38,24,13,1,0,0,14,25,1,1,0,0,37,26,16,1,0,0,62,27,16,1,0,0,63,28,16,1,0,0,60,27,16,1,0,0,61,28,16,1,0,0,25,29,30,1,0,0,28,29,31,1,0,0,29,29,32,1,0,0,26,29,31,1,0,0,27,29,33,1,0,0,49,5,4,1,0,1,48,41,32,0,2,46,34,46,1,0,3,65,41,31,0,4,17,34,3,1,2,4,19,43,1,1,0,4,22,13,16,1,0,4,32,42,13,1,0,4,35,37,1,1,0,4,47,36,13,1,0,4,52,4,1,1,0,4,66,8,1,1,0,4,67,16,13,1,0,5,20,35,16,0,5,40,20,35,0,6,44,44,16,1,12,8,34,39,40,1,2,9,41,32,45,0,40,34,41,34,39,34,8,34,38,34,9,34,4,34,12,34,42,34,36,34,46,34,34,34,37,34,35,34,17,34,45,12,32,45,1,6,11,2,1,9,0,1,3,1,11,2,1,9,0,1,11,8,1,9,0,1,6,11,8,1,9,0,1,7,11,2,1,9,0,1,7,11,8,1,9,0,1,6,11,0,1,9,0,1,6,11,7,1,9,0,1,7,11,0,1,9,0,1,7,11,7,1,9,0,2,11,7,1,9,0,7,8,10,1,11,0,1,9,0,1,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,10,2,7,11,7,1,9,0,11,0,1,9,0,0,2,7,11,0,1,9,0,11,0,1,9,0,3,7,11,0,1,9,0,3,7,8,10,1,10,11,0,1,9,0,1,7,8,10,7,9,0,2,10,2,10,2,10,2,11,5,1,8,11,7,8,10,2,11,2,1,9,0,11,1,1,9,0,3,7,11,2,1,9,0,3,7,8,10,2,7,11,2,1,9,0,3,2,7,11,2,1,9,0,11,0,1,9,0,4,7,11,2,1,9,0,3,5,7,8,10,3,6,11,2,1,9,0,7,11,1,1,9,0,8,6,3,6,11,2,1,9,0,7,11,1,1,9,0,8,4,1,6,11,1,1,9,0,1,2,1,8,6,1,8,4,1,11,5,1,8,11,1,9,0,1,8,9,2,7,11,7,1,9,0,3,2,7,11,7,1,9,0,11,7,1,9,0,3,3,3,10,11,0,1,9,0,1,6,9,0,1,1,1,10,2,2,7,11,8,1,9,0,3,2,7,11,8,1,9,0,11,7,1,9,0,2,9,0,5,1,8,11,1,11,5,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,15,67,117,114,114,101,110,99,121,67,114,101,97,116,101,100,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,85,114,108,5,97,115,99,105,105,7,98,97,108,97,110,99,101,11,98,97,108,97,110,99,101,95,109,117,116,4,98,117,114,110,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,13,99,114,101,97,116,101,95,115,117,112,112,108,121,8,100,101,99,105,109,97,108,115,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,6,100,101,108,101,116,101,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,122,101,114,111,13,100,105,118,105,100,101,95,105,110,116,111,95,110,12,102,114,111,109,95,98,97,108,97,110,99,101,12,103,101,116,95,100,101,99,105,109,97,108,115,15,103,101,116,95,100,101,115,99,114,105,112,116,105,111,110,12,103,101,116,95,105,99,111,110,95,117,114,108,8,103,101,116,95,110,97,109,101,10,103,101,116,95,115,121,109,98,111,108,8,105,99,111,110,95,117,114,108,2,105,100,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,12,105,110,116,111,95,98,97,108,97,110,99,101,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,4,106,111,105,110,4,109,105,110,116,17,109,105,110,116,95,97,110,100,95,116,114,97,110,115,102,101,114,12,109,105,110,116,95,98,97,108,97,110,99,101,4,110,97,109,101,3,110,101,119,10,110,101,119,95,117,110,115,97,102,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,3,112,117,116,4,115,111,109,101,5,115,112,108,105,116,6,115,116,114,105,110,103,6,115,117,112,112,108,121,12,115,117,112,112,108,121,95,105,109,109,117,116,10,115,117,112,112,108,121,95,109,117,116,12,115,117,112,112,108,121,95,118,97,108,117,101,6,115,121,109,98,111,108,4,116,97,107,101,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,5,116,121,112,101,115,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,15,117,112,100,97,116,101,95,105,99,111,110,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,13,117,112,100,97,116,101,95,115,121,109,98,111,108,3,117,114,108,4,117,116,102,56,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,2,31,8,9,12,11,7,1,9,0,1,2,6,31,8,9,18,2,39,8,6,53,8,4,21,8,6,30,11,5,1,8,11,2,2,2,31,8,9,55,11,8,1,9,0,3,2,1,18,2,2,34,0,34,1,34,0,1,0,0,16,4,11,0,55,0,56,0,2,1,1,0,0,3,6,11,0,58,0,12,1,17,43,11,1,2,2,1,0,0,16,3,11,0,55,0,2,3,1,0,0,16,3,11,0,54,0,2,4,1,0,0,16,4,11,0,55,1,56,1,2,5,1,0,0,16,3,11,0,55,1,2,6,1,0,0,16,3,11,0,54,1,2,7,1,0,0,16,5,11,1,17,44,11,0,57,1,2,8,1,0,0,13,6,11,0,58,1,12,1,17,43,11,1,2,9,1,0,0,16,7,11,2,17,44,11,0,11,1,56,2,57,1,2,10,1,0,0,16,6,11,0,11,1,56,3,56,4,1,2,11,1,4,0,13,10,11,1,58,1,12,2,17,43,11,0,54,1,11,2,56,4,1,2,12,1,0,0,16,6,11,0,54,1,11,1,11,2,56,5,2,13,1,0,0,38,59,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,11,11,0,1,11,2,1,7,1,39,10,1,10,0,46,56,6,37,4,18,5,24,11,0,1,11,2,1,7,2,39,64,12,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,3,10,0,46,56,6,10,1,26,12,4,40,10,3,10,1,6,1,0,0,0,0,0,0,0,23,35,4,53,5,42,13,5,10,0,10,4,10,2,56,7,68,12,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,34,11,0,1,11,2,1,11,5,2,14,1,0,0,16,5,11,0,17,44,56,8,57,1,2,15,1,0,0,13,7,11,0,58,1,12,1,17,43,11,1,56,9,2,16,1,0,0,16,25,14,0,56,10,4,4,5,8,11,6,1,7,0,39,10,6,17,44,11,0,56,11,57,0,11,6,17,44,11,1,11,3,17,33,11,2,17,31,11,4,17,33,11,5,57,2,2,17,1,0,0,16,8,11,2,17,44,11,0,54,0,11,1,56,12,57,1,2,18,1,0,0,16,5,11,0,54,0,11,1,56,12,2,19,1,4,0,13,9,11,1,58,1,12,2,17,43,11,0,54,0,11,2,56,13,2,20,1,4,0,16,7,11,0,11,1,11,3,56,14,11,2,56,15,2,21,1,4,0,16,5,11,2,11,1,54,2,21,2,22,1,4,0,16,5,11,2,11,1,54,3,21,2,23,1,4,0,16,5,11,2,11,1,54,4,21,2,24,1,4,0,16,7,11,2,17,47,56,16,11,1,54,5,21,2,25,1,0,0,16,4,11,0,55,6,20,2,26,1,0,0,16,4,11,0,55,2,20,2,27,1,0,0,16,4,11,0,55,3,20,2,28,1,0,0,16,4,11,0,55,4,20,2,29,1,0,0,16,4,11,0,55,5,20,2,30,1,0,0,16,3,11,0,55,0,2,2,1,0,1,1,2,1,3,1,4,1,5,1,1,0,34,1,34,2,34,3,34,4,34,5,34,6,34,0],"display":[161,28,235,11,6,0,0,0,13,1,0,16,2,16,46,3,62,132,1,4,194,1,22,5,216,1,196,1,7,156,3,223,2,8,251,5,64,6,187,6,20,10,207,6,38,11,245,6,6,12,251,6,160,3,13,155,10,6,14,161,10,6,0,14,1,31,0,18,0,26,0,27,0,32,0,33,0,36,0,0,12,1,8,1,0,1,3,1,8,1,0,8,3,1,8,1,1,4,7,0,3,2,7,0,3,6,4,0,4,3,12,0,6,5,2,0,7,7,7,2,1,0,0,0,0,24,0,1,1,8,0,25,2,1,1,8,0,12,0,3,1,8,0,35,4,3,1,8,0,9,5,3,1,8,0,11,6,3,1,8,0,15,5,3,1,8,0,29,7,3,1,8,0,23,8,9,1,8,0,37,10,11,1,8,0,19,10,12,1,8,0,13,13,1,1,8,0,10,5,3,1,8,2,16,14,3,1,3,3,24,13,28,0,3,34,21,22,0,4,20,8,9,1,0,5,28,19,3,1,12,6,30,17,18,0,7,17,3,30,2,1,0,7,22,31,3,2,1,0,7,29,26,27,2,1,0,8,14,11,14,0,14,12,14,17,1,13,23,21,25,16,14,13,29,19,25,20,25,2,6,8,6,7,8,7,1,11,0,1,9,0,4,6,8,6,10,8,3,10,8,3,7,8,7,0,1,7,11,0,1,9,0,3,7,11,0,1,9,0,8,3,8,3,3,7,11,0,1,9,0,10,8,3,10,8,3,2,7,11,0,1,9,0,8,3,1,6,8,6,1,1,1,6,11,0,1,9,0,1,13,1,6,11,8,2,8,3,8,3,1,7,8,7,1,9,0,3,11,0,1,9,0,3,3,1,8,3,1,6,8,7,1,5,2,9,0,5,2,13,11,8,2,8,3,8,3,1,6,8,5,1,8,4,1,11,2,1,9,0,2,3,3,2,8,3,8,3,2,7,11,8,2,9,0,9,1,6,9,0,2,9,0,9,1,1,8,5,1,11,1,1,9,0,1,11,8,2,9,0,9,1,3,7,11,8,2,9,0,9,1,9,0,9,1,7,68,105,115,112,108,97,121,14,68,105,115,112,108,97,121,67,114,101,97,116,101,100,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,6,86,101,99,77,97,112,14,86,101,114,115,105,111,110,85,112,100,97,116,101,100,3,97,100,100,12,97,100,100,95,105,110,116,101,114,110,97,108,12,97,100,100,95,109,117,108,116,105,112,108,101,15,99,114,101,97,116,101,95,97,110,100,95,107,101,101,112,15,99,114,101,97,116,101,95,105,110,116,101,114,110,97,108,7,100,105,115,112,108,97,121,4,101,100,105,116,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,6,102,105,101,108,100,115,12,102,114,111,109,95,112,97,99,107,97,103,101,2,105,100,6,105,110,115,101,114,116,13,105,115,95,97,117,116,104,111,114,105,122,101,100,3,110,101,119,15,110,101,119,95,119,105,116,104,95,102,105,101,108,100,115,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,6,115,101,110,100,101,114,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,112,100,97,116,101,95,118,101,114,115,105,111,110,7,118,101,99,95,109,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,3,21,8,5,19,11,8,2,8,3,8,3,37,13,1,2,1,21,8,4,2,2,3,21,8,4,37,13,19,11,8,2,8,3,8,3,2,14,1,14,0,14,0,1,0,0,3,11,11,0,56,0,4,4,5,8,11,1,1,7,0,39,11,1,56,1,2,1,1,0,0,15,43,14,1,65,16,12,6,10,6,14,2,65,16,33,4,9,5,15,11,0,1,11,3,1,7,1,39,6,0,0,0,0,0,0,0,0,12,5,11,0,11,3,56,2,12,4,10,5,10,6,35,4,41,5,26,13,4,14,1,10,5,66,16,20,14,2,10,5,66,16,20,56,3,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,21,11,4,2,2,1,4,0,3,8,11,0,10,1,56,2,11,1,46,17,18,56,4,2,3,1,4,0,20,24,10,0,55,0,20,72,1,0,22,10,0,54,0,21,10,0,55,0,20,12,1,10,0,55,1,20,12,2,11,0,55,2,17,15,11,1,11,2,57,0,56,5,2,4,1,4,0,3,5,11,0,11,1,11,2,56,3,2,5,1,4,0,24,38,14,1,65,16,12,4,10,4,14,2,65,16,33,4,9,5,13,11,0,1,7,1,39,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,35,5,20,10,0,14,1,10,3,66,16,20,14,2,10,3,66,16,20,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,15,11,0,1,2,6,1,4,0,3,11,10,0,54,1,14,1,56,6,1,1,11,0,11,1,11,2,56,3,2,7,1,4,0,3,7,11,0,54,1,14,1,56,6,1,1,2,8,1,0,0,3,3,11,0,56,7,2,9,1,0,0,3,4,11,0,55,0,20,2,10,1,0,0,3,3,11,0,55,1,2,11,0,0,0,28,12,11,0,17,14,12,1,14,1,17,15,57,1,56,8,11,1,56,9,72,0,0,57,2,2,12,0,0,0,3,6,11,0,54,1,11,1,11,2,56,10,2,0,2,0,1,0,0,0,14,1,14,2,14,0],"dynamic_field":[161,28,235,11,6,0,0,0,14,1,0,6,2,6,22,3,28,133,1,4,161,1,24,5,185,1,168,1,7,225,2,129,3,8,226,5,64,6,162,6,40,10,202,6,12,11,214,6,2,12,216,6,235,2,13,195,9,6,14,201,9,8,15,209,9,2,0,11,1,26,0,25,0,0,8,2,7,0,4,0,1,2,7,1,0,0,2,1,7,0,2,3,4,0,0,4,0,1,2,7,4,0,6,2,3,2,7,4,0,9,4,5,2,7,4,0,27,4,6,2,7,4,0,13,2,7,1,7,0,29,4,8,2,7,4,0,14,2,7,2,7,4,0,15,2,9,1,7,0,16,4,10,1,7,0,19,11,12,1,7,0,5,11,1,1,8,0,7,9,13,1,8,0,8,10,14,1,8,0,28,15,16,1,8,0,17,15,7,0,0,18,15,7,1,8,1,24,1,24,1,0,1,30,16,24,1,0,2,10,19,1,0,2,21,28,12,0,2,23,12,19,0,2,31,18,12,0,9,16,10,21,11,21,12,21,13,21,4,16,3,20,17,6,16,6,15,21,11,26,12,26,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,9,1,2,6,8,3,5,2,7,8,3,5,2,5,9,0,1,5,1,6,9,0,1,7,9,0,2,5,5,1,9,0,3,11,0,2,9,0,9,1,5,5,1,6,8,3,1,8,3,2,9,0,9,1,1,11,0,2,9,0,9,1,3,5,5,9,1,2,9,0,11,1,1,9,1,1,11,1,1,9,0,4,6,11,0,2,9,0,8,2,5,6,8,3,6,8,2,1,11,0,2,9,0,8,2,2,9,0,8,2,1,6,8,2,4,7,11,0,2,9,0,8,2,5,7,8,3,7,8,2,5,70,105,101,108,100,2,73,68,6,79,112,116,105,111,110,3,85,73,68,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,6,100,101,108,101,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,16,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,17,104,97,115,104,95,116,121,112,101,95,97,110,100,95,107,101,121,2,105,100,13,105,100,95,116,111,95,97,100,100,114,101,115,115,4,110,97,109,101,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,3,20,8,3,22,9,0,32,9,1,0,20,0,1,0,0,17,26,11,0,46,17,21,12,5,10,5,10,1,56,0,12,4,10,5,10,4,17,14,32,4,14,5,16,7,0,39,11,4,17,20,11,1,11,2,57,0,12,3,11,5,11,3,56,1,2,1,1,0,0,12,10,10,0,17,21,11,1,56,0,12,2,11,0,11,2,56,2,55,0,2,2,1,0,0,12,11,10,0,46,17,21,11,1,56,0,12,2,11,0,11,2,56,3,54,0,2,3,1,0,0,22,17,11,0,46,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,4,58,0,12,4,1,17,18,11,4,2,4,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,17,14,2,5,1,0,0,23,19,10,0,10,1,12,2,46,11,2,56,5,4,13,11,0,11,1,56,6,56,7,12,3,5,17,11,0,1,56,8,12,3,11,3,2,6,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,9,2,7,3,0,0,25,22,10,0,17,21,11,1,56,0,12,3,11,0,11,3,56,10,12,2,10,2,55,1,12,4,10,2,55,2,1,11,2,55,3,12,5,11,4,11,5,17,19,2,8,3,0,0,29,24,10,0,46,17,21,11,1,56,0,12,3,11,0,11,3,56,11,12,2,10,2,54,1,12,4,10,2,54,2,1,11,2,54,3,12,5,11,4,11,5,46,17,19,2,9,3,2,0,10,3,2,0,11,3,2,0,12,3,2,0,13,3,2,0,14,3,2,0,15,3,2,0,0,2,0,0,0,1,0,20,1,27,2,27,0,27,0,12,0],"dynamic_object_field":[161,28,235,11,6,0,0,0,10,1,0,8,2,8,20,3,28,138,1,4,166,1,26,5,192,1,131,1,7,195,2,178,2,8,245,4,64,10,181,5,6,11,187,5,2,12,189,5,233,1,0,11,1,22,0,10,0,21,0,3,7,1,0,0,1,1,7,1,0,0,3,0,7,0,3,2,4,0,0,4,0,1,2,7,12,0,6,2,3,2,7,12,0,9,4,5,2,7,12,0,23,4,6,2,7,12,0,12,2,7,1,7,0,13,2,7,2,7,12,0,17,2,8,1,7,1,20,1,24,1,0,1,25,10,24,1,0,2,4,0,1,2,7,4,2,5,18,1,1,8,2,7,15,11,1,8,2,8,19,20,1,8,2,13,2,7,2,7,4,2,14,2,15,1,7,2,15,4,19,1,7,2,16,22,7,1,8,2,23,4,6,2,7,4,2,24,22,10,1,8,3,17,11,12,1,8,3,18,17,12,0,3,26,16,17,0,19,6,9,13,14,14,10,6,11,6,15,14,12,6,18,6,17,13,13,13,16,6,7,12,8,12,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,8,2,3,11,0,1,9,0,8,2,11,0,1,9,0,1,9,0,1,6,9,0,1,8,2,2,11,0,1,9,0,8,2,1,11,0,1,9,0,2,6,8,3,5,1,6,8,3,1,5,2,5,9,0,2,7,8,3,5,1,7,9,0,4,11,0,1,9,0,11,0,1,9,0,9,1,5,2,5,5,2,11,0,1,9,0,5,1,11,1,1,9,0,2,73,68,6,79,112,116,105,111,110,3,85,73,68,7,87,114,97,112,112,101,114,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,4,110,97,109,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,19,9,0,0,10,0,1,0,0,9,21,11,1,57,0,12,5,14,2,56,0,12,4,10,0,10,5,11,4,56,1,11,0,11,5,12,3,46,11,3,56,2,1,17,21,11,2,56,3,2,1,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,2,56,4,2,2,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,5,56,6,2,3,1,0,0,21,20,11,1,57,0,12,3,10,0,10,3,12,2,46,11,2,56,2,12,5,17,21,11,5,56,7,12,4,11,0,11,3,56,8,1,11,4,2,4,1,0,0,14,7,11,1,57,0,12,2,11,0,11,2,56,9,2,5,1,0,0,23,20,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,9,2,11,0,11,2,56,2,12,3,17,21,11,3,56,10,2,6,1,0,0,23,21,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,56,11,2,11,0,11,2,56,2,12,3,1,11,3,17,20,56,12,2,0],"ecdsa_k1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,15,5,17,28,7,45,64,8,109,32,6,141,1,26,12,167,1,12,0,1,0,2,0,1,0,0,0,2,1,0,0,3,3,4,0,3,6,10,2,6,10,2,2,1,10,2,1,6,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,17,100,101,99,111,109,112,114,101,115,115,95,112,117,98,107,101,121,8,101,99,100,115,97,95,107,49,19,115,101,99,112,50,53,54,107,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,107,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,2,1,2,0,0],"ecdsa_r1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,10,5,12,24,7,36,46,8,82,32,6,114,26,12,140,1,8,0,0,0,1,0,1,0,0,2,2,3,0,3,6,10,2,6,10,2,2,1,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,8,101,99,100,115,97,95,114,49,19,115,101,99,112,50,53,54,114,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,114,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,0],"ecvrf":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,5,5,7,15,7,22,19,8,41,32,6,73,30,12,103,4,0,0,0,1,0,1,0,4,6,10,2,6,10,2,6,10,2,6,10,2,1,1,5,101,99,118,114,102,12,101,99,118,114,102,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,1,2,0,0],"ed25519":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,12,7,19,23,8,42,32,12,74,4,0,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,7,101,100,50,53,53,49,57,14,101,100,50,53,53,49,57,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"event":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,4,7,12,11,8,23,32,12,55,4,0,1,0,0,0,1,1,3,1,9,0,0,4,101,109,105,116,5,101,118,101,110,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"groth16":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,16,3,18,50,5,68,76,7,144,1,237,2,8,253,3,32,6,157,4,30,10,187,4,32,12,219,4,180,1,13,143,6,14,0,10,0,0,7,0,0,1,7,0,0,3,7,0,0,2,7,0,0,5,0,1,0,0,6,0,1,0,0,16,2,3,0,0,17,3,4,0,0,15,5,6,0,0,14,5,7,0,0,12,8,3,0,0,13,9,3,0,0,18,10,11,0,0,19,12,11,0,0,1,8,0,4,10,2,10,2,10,2,10,2,1,8,1,1,10,10,2,1,10,2,1,8,2,1,8,3,2,6,8,0,6,10,2,2,2,6,10,2,4,6,8,0,6,8,1,6,8,2,6,8,3,1,1,7,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,5,67,117,114,118,101,20,80,114,101,112,97,114,101,100,86,101,114,105,102,121,105,110,103,75,101,121,11,80,114,111,111,102,80,111,105,110,116,115,17,80,117,98,108,105,99,80,114,111,111,102,73,110,112,117,116,115,22,97,108,112,104,97,95,103,49,95,98,101,116,97,95,103,50,95,98,121,116,101,115,8,98,108,115,49,50,51,56,49,5,98,110,50,53,52,5,98,121,116,101,115,21,100,101,108,116,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,21,103,97,109,109,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,7,103,114,111,116,104,49,54,2,105,100,21,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,30,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,95,105,110,116,101,114,110,97,108,23,112,114,111,111,102,95,112,111,105,110,116,115,95,102,114,111,109,95,98,121,116,101,115,30,112,117,98,108,105,99,95,112,114,111,111,102,95,105,110,112,117,116,115,95,102,114,111,109,95,98,121,116,101,115,14,112,118,107,95,102,114,111,109,95,98,121,116,101,115,12,112,118,107,95,116,111,95,98,121,116,101,115,20,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,29,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,95,105,110,116,101,114,110,97,108,21,118,107,95,103,97,109,109,97,95,97,98,99,95,103,49,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,11,2,1,2,4,20,10,2,4,10,2,9,10,2,8,10,2,2,2,1,7,10,2,3,2,1,7,10,2,0,1,0,0,0,3,49,0,18,0,2,1,1,0,0,0,3,49,1,18,0,2,2,1,0,0,0,6,11,0,11,1,11,2,11,3,18,1,2,3,1,0,0,4,24,64,5,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,68,5,13,1,14,0,16,1,20,68,5,13,1,14,0,16,2,20,68,5,13,1,14,0,16,3,20,68,5,11,1,2,4,1,0,0,0,3,11,0,18,2,2,5,1,0,0,0,3,11,0,18,3,2,6,1,0,0,0,6,11,0,16,4,20,11,1,17,7,2,7,0,2,0,8,1,0,0,0,17,11,0,16,4,20,10,1,16,0,10,1,16,1,10,1,16,2,11,1,16,3,11,2,16,5,11,3,16,6,17,9,2,9,0,2,0,1,0,1,1,1,2,1,3,0,0,2,0,3,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,7,7,19,26,8,45,32,12,77,8,0,1,0,0,0,1,0,0,2,0,1,0,1,6,10,2,1,10,2,10,98,108,97,107,101,50,98,50,53,54,4,104,97,115,104,9,107,101,99,99,97,107,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"hex":[161,28,235,11,6,0,0,0,8,1,0,4,3,4,21,4,25,2,5,27,37,7,64,44,8,108,64,6,172,1,159,6,12,203,7,194,2,0,4,1,5,0,3,0,0,0,0,1,0,0,0,0,2,1,1,0,1,0,3,4,1,0,3,1,1,10,2,1,2,5,10,10,2,7,10,2,3,3,10,2,2,7,10,9,0,10,9,0,0,4,2,3,3,10,2,5,1,1,1,2,2,6,97,112,112,101,110,100,6,100,101,99,111,100,101,11,100,101,99,111,100,101,95,98,121,116,101,6,101,110,99,111,100,101,3,104,101,120,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,10,10,2,130,6,128,2,2,48,48,2,48,49,2,48,50,2,48,51,2,48,52,2,48,53,2,48,54,2,48,55,2,48,56,2,48,57,2,48,97,2,48,98,2,48,99,2,48,100,2,48,101,2,48,102,2,49,48,2,49,49,2,49,50,2,49,51,2,49,52,2,49,53,2,49,54,2,49,55,2,49,56,2,49,57,2,49,97,2,49,98,2,49,99,2,49,100,2,49,101,2,49,102,2,50,48,2,50,49,2,50,50,2,50,51,2,50,52,2,50,53,2,50,54,2,50,55,2,50,56,2,50,57,2,50,97,2,50,98,2,50,99,2,50,100,2,50,101,2,50,102,2,51,48,2,51,49,2,51,50,2,51,51,2,51,52,2,51,53,2,51,54,2,51,55,2,51,56,2,51,57,2,51,97,2,51,98,2,51,99,2,51,100,2,51,101,2,51,102,2,52,48,2,52,49,2,52,50,2,52,51,2,52,52,2,52,53,2,52,54,2,52,55,2,52,56,2,52,57,2,52,97,2,52,98,2,52,99,2,52,100,2,52,101,2,52,102,2,53,48,2,53,49,2,53,50,2,53,51,2,53,52,2,53,53,2,53,54,2,53,55,2,53,56,2,53,57,2,53,97,2,53,98,2,53,99,2,53,100,2,53,101,2,53,102,2,54,48,2,54,49,2,54,50,2,54,51,2,54,52,2,54,53,2,54,54,2,54,55,2,54,56,2,54,57,2,54,97,2,54,98,2,54,99,2,54,100,2,54,101,2,54,102,2,55,48,2,55,49,2,55,50,2,55,51,2,55,52,2,55,53,2,55,54,2,55,55,2,55,56,2,55,57,2,55,97,2,55,98,2,55,99,2,55,100,2,55,101,2,55,102,2,56,48,2,56,49,2,56,50,2,56,51,2,56,52,2,56,53,2,56,54,2,56,55,2,56,56,2,56,57,2,56,97,2,56,98,2,56,99,2,56,100,2,56,101,2,56,102,2,57,48,2,57,49,2,57,50,2,57,51,2,57,52,2,57,53,2,57,54,2,57,55,2,57,56,2,57,57,2,57,97,2,57,98,2,57,99,2,57,100,2,57,101,2,57,102,2,97,48,2,97,49,2,97,50,2,97,51,2,97,52,2,97,53,2,97,54,2,97,55,2,97,56,2,97,57,2,97,97,2,97,98,2,97,99,2,97,100,2,97,101,2,97,102,2,98,48,2,98,49,2,98,50,2,98,51,2,98,52,2,98,53,2,98,54,2,98,55,2,98,56,2,98,57,2,98,97,2,98,98,2,98,99,2,98,100,2,98,101,2,98,102,2,99,48,2,99,49,2,99,50,2,99,51,2,99,52,2,99,53,2,99,54,2,99,55,2,99,56,2,99,57,2,99,97,2,99,98,2,99,99,2,99,100,2,99,101,2,99,102,2,100,48,2,100,49,2,100,50,2,100,51,2,100,52,2,100,53,2,100,54,2,100,55,2,100,56,2,100,57,2,100,97,2,100,98,2,100,99,2,100,100,2,100,101,2,100,102,2,101,48,2,101,49,2,101,50,2,101,51,2,101,52,2,101,53,2,101,54,2,101,55,2,101,56,2,101,57,2,101,97,2,101,98,2,101,99,2,101,100,2,101,101,2,101,102,2,102,48,2,102,49,2,102,50,2,102,51,2,102,52,2,102,53,2,102,54,2,102,55,2,102,56,2,102,57,2,102,97,2,102,98,2,102,99,2,102,100,2,102,101,2,102,102,10,2,1,0,0,1,0,0,2,33,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,4,12,5,12,3,10,3,10,4,35,4,31,5,12,13,5,12,2,7,2,12,1,11,2,14,1,14,0,10,3,66,1,20,52,66,0,20,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,5,2,1,1,0,0,5,47,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,3,12,4,12,2,10,3,6,2,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,14,5,16,7,0,39,10,2,10,3,35,4,45,5,21,14,0,10,2,66,1,20,17,2,49,16,24,14,0,10,2,6,1,0,0,0,0,0,0,0,22,66,1,20,17,2,22,12,1,13,4,11,1,68,1,11,2,6,2,0,0,0,0,0,0,0,22,12,2,5,16,11,4,2,2,0,0,0,6,64,49,48,10,0,37,4,9,10,0,49,58,35,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,5,5,62,49,65,10,0,37,4,27,10,0,49,71,35,12,2,5,29,9,12,2,11,2,4,38,49,10,11,0,22,49,65,23,12,4,5,60,49,97,10,0,37,4,47,10,0,49,103,35,12,3,5,49,9,12,3,11,3,4,52,5,54,7,1,39,49,10,11,0,22,49,97,23,12,4,11,4,12,5,11,5,2,0],"hmac":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,10,7,17,19,8,36,32,12,68,4,0,0,0,1,0,1,0,2,6,10,2,6,10,2,1,10,2,4,104,109,97,99,13,104,109,97,99,95,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"kiosk":[161,28,235,11,6,0,0,0,14,1,0,24,2,24,94,3,118,135,3,4,253,3,68,5,193,4,137,4,7,202,8,159,8,8,233,16,64,6,169,17,130,1,10,171,18,101,11,144,19,8,12,152,19,146,14,13,170,33,18,14,188,33,6,15,194,33,2,0,50,1,62,0,21,0,26,0,31,0,32,0,34,0,61,0,86,0,88,0,89,0,90,0,8,12,0,0,9,12,0,0,13,12,1,12,1,0,1,0,0,0,4,7,0,0,10,7,0,0,11,7,0,0,6,3,1,12,1,0,7,3,1,12,1,0,5,3,1,12,1,1,12,7,1,0,0,2,0,4,1,0,1,3,2,12,1,0,1,7,3,7,0,7,18,4,0,8,14,2,0,10,15,12,1,0,1,10,16,0,1,0,1,11,17,2,0,0,27,0,1,0,0,59,0,2,0,0,25,3,4,0,0,83,5,1,0,0,84,6,1,0,0,64,7,1,1,12,0,56,8,1,1,12,0,87,9,10,1,12,0,54,11,1,1,12,0,65,12,1,1,12,0,29,9,1,1,12,0,71,13,14,1,12,0,55,15,16,1,12,0,75,17,14,1,12,0,79,18,1,1,12,0,97,19,4,0,0,57,20,1,1,12,0,66,20,1,1,12,0,94,21,22,0,0,40,23,24,0,0,41,23,24,1,12,0,46,23,24,0,0,44,23,24,0,0,45,23,24,0,0,39,25,24,0,0,93,25,22,0,0,82,26,1,0,0,91,27,28,0,0,92,21,22,0,0,63,27,29,0,0,48,27,30,0,0,69,27,31,0,0,70,25,32,0,0,22,33,34,1,12,0,23,9,35,1,12,0,24,9,36,1,12,0,80,37,1,1,12,0,53,38,39,0,0,73,40,39,1,12,0,72,40,39,1,12,0,74,40,31,1,12,1,30,74,10,1,0,1,47,73,24,1,0,2,96,75,31,1,0,2,98,1,48,1,0,3,38,50,51,1,0,3,76,65,1,1,0,3,87,76,51,1,0,3,96,63,31,1,0,4,19,59,1,2,7,4,4,35,78,24,1,7,4,77,54,57,2,7,4,4,78,54,55,2,7,4,5,19,59,1,2,7,12,5,22,78,81,2,7,12,5,23,54,82,2,7,12,5,35,78,24,1,7,5,36,78,24,2,7,12,5,77,54,57,2,7,12,6,33,10,1,1,3,7,28,46,1,0,7,42,34,39,1,8,7,59,0,46,0,7,95,28,39,0,9,85,10,1,1,8,9,88,44,1,1,8,10,60,67,68,1,0,11,81,42,29,0,65,43,64,45,44,47,61,45,45,47,17,10,16,10,52,53,58,56,20,10,49,53,59,60,61,10,5,10,8,10,51,53,59,61,48,47,52,64,46,47,59,66,66,10,42,31,41,31,43,47,47,47,49,64,53,56,56,77,57,56,50,79,50,80,54,56,55,56,1,7,8,18,0,2,8,0,8,1,3,8,0,8,1,7,8,18,1,11,12,1,8,15,3,7,8,0,6,8,1,6,8,18,3,7,8,0,6,8,1,5,3,7,8,0,6,8,1,9,0,4,7,8,0,6,8,1,6,11,16,1,9,0,9,0,3,7,8,0,6,8,1,8,13,1,9,0,4,7,8,0,6,8,1,8,13,3,4,7,8,0,6,8,1,9,0,3,3,7,8,0,8,13,11,12,1,8,15,2,9,0,11,17,1,9,0,5,7,8,0,6,8,1,8,13,3,7,8,18,1,11,2,1,9,0,3,7,8,0,11,2,1,9,0,11,12,1,8,15,2,7,8,0,11,2,1,9,0,4,7,8,0,6,8,1,11,10,1,3,7,8,18,2,7,8,0,9,0,1,7,8,0,1,7,8,14,2,6,8,0,8,13,1,1,2,7,8,0,6,8,1,3,7,8,0,6,8,1,1,1,6,8,0,1,6,8,14,1,5,1,14,1,3,1,7,11,11,1,8,15,3,6,8,0,6,8,1,8,13,1,6,9,0,1,7,9,0,2,9,0,8,3,3,7,8,0,9,0,8,3,1,6,8,1,1,8,13,1,6,11,2,1,9,0,2,8,1,8,0,1,6,8,18,1,8,1,2,9,0,5,1,8,0,1,8,14,1,8,15,1,11,11,1,9,0,5,8,14,8,13,8,14,14,11,11,1,8,15,2,11,11,1,9,0,7,8,18,1,11,12,1,9,0,3,8,13,8,13,8,13,2,8,5,3,2,7,8,14,9,0,1,11,10,1,9,1,2,8,4,9,0,1,9,1,2,8,13,8,13,3,7,8,14,9,0,9,1,1,11,7,1,9,0,1,11,9,1,9,0,2,9,0,3,1,6,11,12,1,9,0,2,8,6,1,2,7,11,11,1,9,0,11,12,1,9,0,1,11,8,1,9,0,3,8,13,3,8,13,1,11,17,1,9,0,6,8,13,8,13,3,8,13,8,14,8,13,5,8,13,8,13,8,13,3,3,3,8,14,8,13,8,13,3,3,3,3,1,6,11,10,1,9,0,1,11,10,1,9,0,1,6,11,11,1,9,0,3,7,11,11,1,9,0,3,7,8,18,1,8,4,2,6,8,14,9,0,1,8,6,1,8,5,1,6,9,1,1,7,9,1,7,66,97,108,97,110,99,101,6,66,111,114,114,111,119,4,67,111,105,110,2,73,68,4,73,116,101,109,12,73,116,101,109,68,101,108,105,115,116,101,100,10,73,116,101,109,76,105,115,116,101,100,13,73,116,101,109,80,117,114,99,104,97,115,101,100,5,75,105,111,115,107,13,75,105,111,115,107,79,119,110,101,114,67,97,112,7,76,105,115,116,105,110,103,4,76,111,99,107,6,79,112,116,105,111,110,11,80,117,114,99,104,97,115,101,67,97,112,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,16,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,10,98,111,114,114,111,119,95,118,97,108,18,99,108,111,115,101,95,97,110,100,95,119,105,116,104,100,114,97,119,4,99,111,105,110,7,100,101,102,97,117,108,116,6,100,101,108,101,116,101,6,100,101,108,105,115,116,12,100,101,115,116,114,111,121,95,115,111,109,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,4,101,109,105,116,5,101,118,101,110,116,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,3,102,111,114,12,102,114,111,109,95,98,97,108,97,110,99,101,10,104,97,115,95,97,99,99,101,115,115,8,104,97,115,95,105,116,101,109,18,104,97,115,95,105,116,101,109,95,119,105,116,104,95,116,121,112,101,2,105,100,12,105,115,95,101,120,99,108,117,115,105,118,101,9,105,115,95,108,105,115,116,101,100,21,105,115,95,108,105,115,116,101,100,95,101,120,99,108,117,115,105,118,101,108,121,9,105,115,95,108,111,99,107,101,100,7,105,115,95,115,111,109,101,10,105,116,101,109,95,99,111,117,110,116,7,105,116,101,109,95,105,100,5,107,105,111,115,107,15,107,105,111,115,107,95,101,120,116,101,110,115,105,111,110,8,107,105,111,115,107,95,105,100,19,107,105,111,115,107,95,111,119,110,101,114,95,99,97,112,95,102,111,114,4,108,105,115,116,22,108,105,115,116,95,119,105,116,104,95,112,117,114,99,104,97,115,101,95,99,97,112,4,108,111,99,107,13,108,111,99,107,95,105,110,116,101,114,110,97,108,9,109,105,110,95,112,114,105,99,101,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,5,111,119,110,101,114,5,112,108,97,99,101,14,112,108,97,99,101,95,97,110,100,95,108,105,115,116,14,112,108,97,99,101,95,105,110,116,101,114,110,97,108,5,112,114,105,99,101,7,112,114,111,102,105,116,115,14,112,114,111,102,105,116,115,95,97,109,111,117,110,116,11,112,114,111,102,105,116,115,95,109,117,116,8,112,117,114,99,104,97,115,101,17,112,117,114,99,104,97,115,101,95,99,97,112,95,105,116,101,109,18,112,117,114,99,104,97,115,101,95,99,97,112,95,107,105,111,115,107,22,112,117,114,99,104,97,115,101,95,99,97,112,95,109,105,110,95,112,114,105,99,101,17,112,117,114,99,104,97,115,101,95,119,105,116,104,95,99,97,112,3,112,117,116,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,19,114,101,116,117,114,110,95,112,117,114,99,104,97,115,101,95,99,97,112,10,114,101,116,117,114,110,95,118,97,108,6,115,101,110,100,101,114,20,115,101,116,95,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,9,115,101,116,95,111,119,110,101,114,16,115,101,116,95,111,119,110,101,114,95,99,117,115,116,111,109,12,115,104,97,114,101,95,111,98,106,101,99,116,3,115,117,105,4,116,97,107,101,8,116,114,97,110,115,102,101,114,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,3,117,105,100,7,117,105,100,95,109,117,116,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,16,117,105,100,95,109,117,116,95,105,110,116,101,114,110,97,108,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,0,2,5,42,8,14,68,11,11,1,8,15,63,5,48,14,20,1,1,2,2,42,8,14,37,8,13,2,2,4,42,8,14,52,8,13,49,8,13,58,3,3,2,2,52,8,13,49,8,13,4,2,1,42,8,13,5,2,2,42,8,13,43,1,6,2,1,42,8,13,7,2,3,50,8,13,42,8,13,67,3,8,2,3,50,8,13,42,8,13,67,3,9,2,2,50,8,13,42,8,13,7,10,9,10,8,10,2,10,0,0,4,0,41,12,10,0,17,1,12,1,12,2,11,1,11,0,46,17,67,56,0,11,2,56,1,2,1,1,0,0,41,19,10,0,17,62,56,2,10,0,46,17,67,73,0,0,0,0,9,18,0,12,2,11,0,17,62,14,2,56,3,18,1,12,1,11,2,11,1,2,2,1,0,0,49,38,11,0,19,0,1,12,6,1,12,7,12,5,11,1,19,1,12,4,12,3,14,5,17,63,11,4,33,4,17,5,21,11,2,1,7,0,39,11,6,73,0,0,0,0,33,4,26,5,30,11,2,1,7,3,39,11,3,17,60,11,5,17,60,11,7,11,2,56,4,2,3,1,0,0,1,17,10,0,11,1,17,24,4,5,5,11,11,0,1,11,2,1,7,0,39,11,2,17,67,11,0,15,0,21,2,4,1,0,0,1,14,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,2,11,0,15,0,21,2,5,1,0,0,1,13,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,11,2,56,5,2,6,1,0,0,1,13,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,11,3,56,6,2,7,1,0,0,52,68,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,21,32,4,18,5,22,11,0,1,7,8,39,10,0,10,2,12,4,46,11,4,17,23,32,4,31,5,35,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,19,4,43,5,47,11,0,1,7,11,39,10,0,16,1,20,73,1,0,0,0,23,10,0,15,1,21,10,0,15,2,10,2,9,18,5,56,7,1,11,0,15,2,11,2,18,4,56,8,2,8,1,0,0,58,49,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,4,46,11,4,56,9,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,5,46,11,5,17,23,32,4,30,5,34,11,0,1,7,4,39,10,0,15,2,10,2,9,18,5,10,3,56,10,11,0,46,56,3,11,2,11,3,57,0,56,11,2,9,1,0,0,39,13,14,2,56,12,12,4,10,0,10,1,11,2,56,13,11,0,11,1,11,4,11,3,56,14,2,10,1,0,0,52,60,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,56,9,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,23,32,4,30,5,34,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,22,4,42,5,46,11,0,1,7,12,39,10,0,15,2,10,2,9,18,5,56,15,1,11,0,46,56,3,11,2,57,1,56,16,2,11,1,0,0,62,56,10,0,15,2,10,1,9,18,5,56,15,12,4,10,0,15,2,10,1,18,4,56,8,12,3,10,0,16,1,20,73,1,0,0,0,23,10,0,15,1,21,10,4,14,2,56,17,33,4,27,5,31,11,0,1,7,1,39,10,0,15,2,10,1,18,6,56,18,1,10,0,15,3,11,2,56,19,10,0,46,56,3,10,1,10,4,57,2,56,20,11,3,11,1,11,4,11,0,46,56,3,56,21,2,12,1,0,0,69,64,10,0,11,1,17,24,4,5,5,11,11,0,1,11,4,1,7,0,39,10,0,10,2,12,5,46,11,5,56,9,4,19,5,25,11,0,1,11,4,1,7,11,39,10,0,10,2,12,6,46,11,6,17,22,32,4,34,5,40,11,0,1,11,4,1,7,6,39,10,0,15,2,10,2,8,18,5,10,3,56,10,11,3,12,7,11,2,12,8,11,4,17,62,12,9,11,0,46,56,3,12,10,11,9,11,10,11,8,11,7,57,3,2,13,1,0,0,70,68,11,1,58,3,12,6,12,4,12,5,17,60,11,4,12,3,14,2,56,17,12,7,10,7,11,6,38,4,16,5,20,11,0,1,7,1,39,10,0,46,56,3,11,5,33,4,27,5,31,11,0,1,7,5,39,10,0,15,2,10,3,8,18,5,56,15,1,10,0,15,3,11,2,56,19,10,0,16,1,20,73,1,0,0,0,23,10,0,15,1,21,10,0,15,2,10,3,18,6,56,18,1,10,0,15,2,10,3,18,4,56,8,11,3,11,7,11,0,46,56,3,56,21,2,14,1,0,0,71,27,11,1,58,3,1,12,3,12,4,12,2,10,0,46,56,3,11,4,33,4,13,5,17,11,0,1,7,5,39,11,0,15,2,11,3,8,18,5,56,15,1,11,2,17,60,2,15,1,0,0,72,45,10,0,11,1,17,24,4,5,5,11,11,0,1,11,3,1,7,0,39,14,2,56,22,4,33,11,2,56,23,12,6,10,6,10,0,16,3,56,24,37,4,24,5,30,11,0,1,11,3,1,7,2,39,11,6,12,4,5,37,10,0,16,3,56,24,12,4,11,4,12,5,11,0,15,3,11,5,11,3,56,25,2,16,3,0,0,1,11,10,0,15,2,14,1,56,12,18,6,8,56,26,11,0,11,1,56,5,2,17,3,0,0,1,16,10,0,16,1,20,73,1,0,0,0,22,10,0,15,1,21,11,0,15,2,14,1,56,12,18,4,11,1,56,27,2,18,3,0,0,1,3,11,0,15,2,2,19,1,0,0,1,6,11,0,16,2,11,1,18,4,56,28,2,20,1,0,0,1,6,11,0,16,2,11,1,18,4,56,29,2,21,1,0,0,1,6,11,0,16,2,11,1,18,6,56,30,2,22,1,0,0,24,18,10,0,16,2,10,1,9,18,5,56,31,4,12,11,0,1,8,12,2,5,16,11,0,11,1,17,23,12,2,11,2,2,23,1,0,0,1,7,11,0,16,2,11,1,8,18,5,56,31,2,24,1,0,0,1,8,11,0,46,56,3,11,1,16,4,20,33,2,25,1,0,0,1,12,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,15,2,2,26,1,0,0,1,14,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,2,11,0,15,5,21,2,27,1,0,0,1,3,11,0,16,2,2,28,1,0,0,1,12,10,0,16,5,20,4,5,5,9,11,0,1,7,7,39,11,0,15,2,2,29,1,0,0,1,4,11,0,16,0,20,2,30,1,0,0,1,4,11,0,16,1,20,2,31,1,0,0,1,4,11,0,16,3,56,24,2,32,1,0,0,1,12,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,15,3,2,33,1,0,0,1,27,10,0,56,3,11,1,16,4,20,33,4,8,5,12,11,0,1,7,0,39,10,0,10,2,17,19,4,17,5,21,11,0,1,7,11,39,11,0,16,2,11,2,18,4,56,32,2,34,1,0,0,58,40,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,19,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,22,32,4,30,5,34,11,0,1,7,9,39,11,0,15,2,11,2,18,4,56,33,2,35,1,0,0,58,45,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,19,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,22,32,4,30,5,34,11,0,1,7,9,39,10,0,15,2,10,2,18,4,56,8,11,0,46,56,3,11,2,18,3,2,36,1,0,0,58,32,11,2,19,3,12,3,12,4,10,0,46,56,3,11,4,33,4,11,5,15,11,0,1,7,5,39,14,1,56,12,10,3,33,4,21,5,25,11,0,1,7,10,39,11,0,15,2,11,3,18,4,11,1,56,27,2,37,1,0,0,1,4,11,0,16,4,20,2,38,1,0,0,1,4,11,0,55,0,20,2,39,1,0,0,1,4,11,0,55,1,20,2,40,1,0,0,1,4,11,0,55,2,20,2,0,2,0,3,0,0,0,1,1,1,0,4,2,1,2,2,2,3,6,10,7,10,8,10,0,51,0],"kiosk_extension":[161,28,235,11,6,0,0,0,12,1,0,14,2,14,36,3,50,162,1,4,212,1,26,5,238,1,142,1,7,252,2,164,3,8,160,6,32,6,192,6,76,10,140,7,15,11,155,7,2,12,157,7,143,4,13,172,11,6,0,26,0,9,0,17,0,25,0,30,0,37,0,38,0,1,4,0,0,2,7,1,0,1,1,0,12,0,3,3,12,0,3,4,12,0,4,7,4,0,5,5,12,1,0,1,6,6,2,0,0,8,0,1,1,2,0,15,2,1,1,2,0,18,2,1,1,2,0,34,2,1,1,2,0,35,3,4,1,2,0,36,5,6,1,2,0,32,7,1,2,2,12,0,27,7,1,2,2,12,0,24,8,9,1,2,0,23,8,9,1,2,0,13,8,9,1,2,0,12,8,9,1,2,0,20,8,10,1,2,0,21,11,12,1,2,1,14,16,1,0,1,29,15,16,0,2,8,18,1,2,7,4,2,10,24,25,2,7,4,2,11,19,26,2,7,4,2,19,24,9,1,7,2,34,19,20,2,7,4,3,22,2,9,0,3,28,21,1,1,12,3,33,21,1,1,12,3,39,8,22,0,3,40,2,13,0,3,41,11,13,0,16,17,8,14,13,14,20,17,12,14,10,14,11,14,23,20,22,20,19,23,9,14,17,17,18,17,5,9,0,7,8,3,6,8,4,4,7,8,7,0,2,7,8,3,6,8,4,2,9,0,6,8,3,1,6,8,2,2,9,0,7,8,3,1,7,8,2,4,9,0,7,8,3,9,1,6,11,6,1,9,1,1,6,8,3,1,1,1,6,8,0,1,7,8,3,1,7,8,0,1,7,8,5,1,9,0,1,7,8,7,1,8,2,2,11,1,1,9,0,8,0,3,7,8,5,9,0,9,1,2,7,8,5,9,0,1,9,1,2,7,8,3,9,0,1,6,8,5,1,11,1,1,9,0,2,6,8,5,9,0,1,6,9,1,1,7,9,1,3,66,97,103,9,69,120,116,101,110,115,105,111,110,12,69,120,116,101,110,115,105,111,110,75,101,121,5,75,105,111,115,107,13,75,105,111,115,107,79,119,110,101,114,67,97,112,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,3,98,97,103,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,97,110,95,108,111,99,107,9,99,97,110,95,112,108,97,99,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,7,100,105,115,97,98,108,101,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,6,101,110,97,98,108,101,7,101,120,105,115,116,115,95,9,101,120,116,101,110,115,105,111,110,13,101,120,116,101,110,115,105,111,110,95,109,117,116,10,104,97,115,95,97,99,99,101,115,115,10,105,115,95,101,110,97,98,108,101,100,12,105,115,95,105,110,115,116,97,108,108,101,100,5,107,105,111,115,107,15,107,105,111,115,107,95,101,120,116,101,110,115,105,111,110,4,108,111,99,107,13,108,111,99,107,95,105,110,116,101,114,110,97,108,3,110,101,119,6,111,98,106,101,99,116,11,112,101,114,109,105,115,115,105,111,110,115,5,112,108,97,99,101,14,112,108,97,99,101,95,105,110,116,101,114,110,97,108,6,114,101,109,111,118,101,7,115,116,111,114,97,103,101,11,115,116,111,114,97,103,101,95,109,117,116,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,3,117,105,100,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,16,117,105,100,95,109,117,116,95,105,110,116,101,114,110,97,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,4,16,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,16,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,35,8,2,31,4,23,1,1,2,1,16,1,1,14,0,1,0,0,1,25,10,1,10,2,17,21,4,5,5,13,11,1,1,11,4,1,11,2,1,7,0,39,11,1,11,2,17,25,9,57,0,11,4,17,15,11,3,8,18,0,56,0,2,1,1,0,0,1,24,10,0,11,1,17,21,4,5,5,9,11,0,1,7,0,39,10,0,46,56,1,4,14,5,18,11,0,1,7,3,39,9,11,0,56,2,15,0,21,2,2,1,0,0,1,24,10,0,11,1,17,21,4,5,5,9,11,0,1,7,0,39,10,0,46,56,1,4,14,5,18,11,0,1,7,3,39,8,11,0,56,2,15,0,21,2,3,1,0,0,1,33,10,0,10,1,17,21,4,5,5,11,11,0,1,11,1,1,7,0,39,10,0,46,56,1,4,16,5,22,11,0,1,11,1,1,7,3,39,11,0,11,1,17,25,9,57,0,56,3,19,0,1,1,17,14,2,4,1,0,0,1,12,10,1,56,1,4,4,5,8,11,1,1,7,3,39,11,1,56,4,16,1,2,5,1,0,0,1,13,10,1,46,56,1,4,5,5,9,11,1,1,7,3,39,11,1,56,2,15,1,2,6,1,0,0,9,31,10,1,46,56,1,4,5,5,9,11,1,1,7,3,39,10,1,46,56,5,4,16,8,12,4,5,20,10,1,46,56,6,12,4,11,4,4,23,5,27,11,1,1,7,2,39,11,1,11,2,56,7,2,7,1,0,0,1,22,10,1,46,56,1,4,5,5,9,11,1,1,7,3,39,10,1,46,56,6,4,14,5,18,11,1,1,7,2,39,11,1,11,2,56,8,2,8,1,0,0,1,6,11,0,17,24,9,57,0,56,9,2,9,1,0,0,1,5,11,0,56,4,16,0,20,2,10,1,0,0,9,19,10,0,56,10,4,13,11,0,56,4,16,2,20,7,4,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,12,1,5,17,11,0,1,9,12,1,11,1,2,11,1,0,0,9,19,10,0,56,10,4,13,11,0,56,4,16,2,20,7,5,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,12,1,5,17,11,0,1,9,12,1,11,1,2,12,0,0,0,1,6,11,0,17,24,9,57,0,56,11,2,13,0,0,0,1,6,11,0,17,26,9,57,0,56,12,2,0,2,0,0,0,1,0],"linked_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,30,3,40,212,1,4,252,1,28,5,152,2,188,1,7,212,3,205,2,8,161,6,64,6,225,6,20,10,245,6,38,11,155,7,4,12,159,7,151,5,13,182,12,14,14,196,12,14,0,24,1,29,0,14,0,28,0,40,0,0,12,2,7,0,4,1,0,1,4,2,7,0,4,0,1,2,7,1,0,0,3,4,4,0,4,3,2,0,0,25,0,1,2,7,4,0,17,2,3,2,7,4,0,6,2,3,2,7,4,0,34,4,5,2,7,4,0,33,4,5,2,7,4,0,7,6,7,2,7,4,0,8,8,9,2,7,4,0,32,6,3,2,7,4,0,26,6,3,2,7,4,0,35,8,10,2,7,4,0,31,11,12,2,7,4,0,30,11,12,2,7,4,0,9,6,13,2,7,4,0,23,2,14,2,7,4,0,20,2,13,2,7,4,0,11,1,5,2,7,4,0,13,1,5,2,7,6,1,7,3,25,1,0,1,12,17,16,1,0,1,16,19,5,1,0,1,21,3,13,1,0,1,22,3,13,1,0,1,27,5,17,1,0,1,37,16,17,1,0,1,38,19,17,1,0,2,5,22,5,2,7,4,2,7,23,7,2,7,4,2,8,21,9,2,7,4,2,15,23,13,2,7,4,2,35,21,10,2,7,4,3,10,15,5,0,3,25,0,15,0,22,16,24,16,20,16,19,16,21,16,18,16,23,16,27,20,25,20,26,20,29,20,17,16,9,12,28,20,1,7,8,4,1,11,0,2,9,0,9,1,1,6,11,0,2,9,0,9,1,1,6,11,2,1,9,0,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,7,11,0,2,9,0,9,1,2,9,0,9,1,1,1,1,3,1,8,3,1,9,0,1,11,2,1,9,0,5,11,2,1,9,0,11,2,1,9,0,11,2,1,9,0,9,0,11,2,1,9,0,2,7,11,2,1,9,0,9,0,2,9,0,11,1,2,9,0,9,1,2,7,8,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,3,11,2,1,9,0,11,2,1,9,0,9,1,1,6,9,0,2,8,3,3,11,76,105,110,107,101,100,84,97,98,108,101,4,78,111,100,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,4,98,97,99,107,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,4,102,105,108,108,5,102,114,111,110,116,4,104,101,97,100,2,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,6,108,101,110,103,116,104,12,108,105,110,107,101,100,95,116,97,98,108,101,3,110,101,119,4,110,101,120,116,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,111,112,95,98,97,99,107,9,112,111,112,95,102,114,111,110,116,4,112,114,101,118,9,112,117,115,104,95,98,97,99,107,10,112,117,115,104,95,102,114,111,110,116,6,114,101,109,111,118,101,4,115,105,122,101,4,115,111,109,101,12,115,119,97,112,95,111,114,95,102,105,108,108,4,116,97,105,108,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,19,8,3,36,3,18,11,2,1,9,0,39,11,2,1,9,0,1,2,3,32,11,2,1,9,0,26,11,2,1,9,0,41,9,1,0,12,1,12,0,1,0,0,5,7,11,0,17,31,6,0,0,0,0,0,0,0,0,56,0,56,0,57,0,2,1,1,0,0,5,3,11,0,55,0,2,2,1,0,0,5,3,11,0,55,1,2,3,1,0,0,18,54,10,0,54,0,10,1,56,1,12,5,10,0,55,1,56,2,4,13,10,0,54,1,10,1,56,3,56,0,12,7,14,5,56,4,4,33,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,3,21,11,6,56,6,12,3,5,35,56,0,12,3,11,3,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,4,1,0,0,18,54,10,0,55,0,56,2,4,8,10,0,54,0,10,1,56,3,10,0,54,1,10,1,56,1,12,5,14,5,56,4,4,31,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,5,21,11,6,56,6,12,3,5,33,56,0,12,3,11,3,12,7,56,0,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,5,1,0,0,5,6,11,0,55,2,11,1,56,9,55,6,2,6,1,0,0,5,6,11,0,54,2,11,1,56,7,54,6,2,7,1,0,0,5,6,11,0,55,2,11,1,56,9,55,3,2,8,1,0,0,5,6,11,0,55,2,11,1,56,9,55,5,2,9,1,0,0,24,65,10,0,54,2,10,1,56,10,58,1,12,4,12,2,12,3,10,0,55,4,20,6,1,0,0,0,0,0,0,0,23,10,0,54,4,21,14,3,56,4,4,28,10,2,10,0,54,2,14,3,56,11,20,56,7,54,5,21,14,2,56,4,4,40,10,3,10,0,54,2,14,2,56,11,20,56,7,54,3,21,10,0,55,0,56,11,14,1,33,4,50,11,2,10,0,54,0,21,10,0,55,1,56,11,14,1,33,4,61,11,3,11,0,54,1,21,5,63,11,0,1,11,4,2,10,1,0,0,16,19,10,0,55,0,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,0,56,11,20,12,1,10,1,11,0,11,1,56,12,2,11,1,0,0,16,19,10,0,55,1,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,1,56,11,20,12,1,10,1,11,0,11,1,56,12,2,12,1,0,0,5,5,11,0,55,2,11,1,56,13,2,13,1,0,0,5,4,11,0,55,4,20,2,14,1,0,0,5,6,11,0,55,4,20,6,0,0,0,0,0,0,0,0,33,2,15,1,0,0,26,16,11,0,58,0,1,1,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,11,5,13,7,0,39,11,1,17,30,2,16,1,0,0,5,7,11,0,58,0,1,1,1,17,30,2,0,2,0,3,0,0,1,0,0,1,1,1,1,2,0,12,1,12,2,12,3,12,4,12,5,12,6,12,0],"math":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,35,5,37,18,7,55,57,8,112,32,12,144,1,249,3,0,2,0,3,0,1,0,0,4,0,1,0,0,0,0,1,0,0,5,2,1,0,0,6,1,1,0,0,7,3,3,0,0,1,0,1,0,2,3,3,1,3,2,3,2,1,4,3,4,4,4,3,15,15,15,4,100,105,102,102,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,4,109,97,116,104,3,109,97,120,3,109,105,110,3,112,111,119,4,115,113,114,116,9,115,113,114,116,95,117,49,50,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,1,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,2,1,0,0,1,15,10,0,10,1,36,4,9,11,0,11,1,23,12,2,5,13,11,1,11,0,23,12,2,11,2,2,3,1,0,0,1,33,6,1,0,0,0,0,0,0,0,12,2,10,1,49,1,38,4,31,5,7,10,1,49,2,25,49,0,33,4,22,10,0,11,0,24,12,0,11,1,49,2,26,12,1,5,30,11,2,10,0,24,12,2,11,1,49,1,23,12,1,5,2,11,2,2,4,1,0,0,4,43,50,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,12,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,53,12,3,10,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,52,2,5,1,0,0,5,43,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,77,12,3,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,53,2,6,1,0,0,1,19,10,0,10,1,25,6,0,0,0,0,0,0,0,0,33,4,11,11,0,11,1,26,12,2,5,17,11,0,11,1,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,2,0],"object":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,126,4,146,1,6,5,152,1,35,7,187,1,250,2,8,181,4,64,6,245,4,112,10,229,5,11,12,240,5,130,2,13,242,7,4,15,246,7,8,0,24,1,4,0,3,0,30,0,0,7,0,0,2,4,0,3,1,2,0,0,21,0,1,0,0,20,0,2,0,0,19,1,3,0,0,18,2,3,0,0,27,4,5,0,0,8,6,5,0,0,31,7,0,0,0,34,7,3,0,0,33,7,1,0,0,32,7,2,0,0,22,8,5,0,0,9,5,6,0,0,15,9,3,1,8,0,5,9,0,1,8,0,17,9,1,1,8,0,16,9,2,1,8,0,6,9,7,1,8,0,23,2,5,0,0,10,2,6,0,0,25,2,6,0,1,28,9,1,1,0,2,14,1,2,0,3,13,8,2,0,3,26,4,2,0,20,2,16,10,20,3,1,6,8,0,1,10,2,1,5,1,8,0,1,6,8,2,1,8,1,0,1,6,8,1,1,7,8,2,1,6,9,0,1,9,0,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,100,100,114,101,115,115,3,98,99,115,9,98,111,114,114,111,119,95,105,100,10,98,111,114,114,111,119,95,117,105,100,5,98,121,116,101,115,5,99,108,111,99,107,6,100,101,108,101,116,101,11,100,101,108,101,116,101,95,105,109,112,108,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,2,105,100,10,105,100,95,97,100,100,114,101,115,115,8,105,100,95,98,121,116,101,115,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,102,114,111,109,95,98,121,116,101,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,11,105,100,95,116,111,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,6,111,98,106,101,99,116,14,114,101,99,111,114,100,95,110,101,119,95,117,105,100,6,115,101,110,100,101,114,16,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,12,117,105,100,95,116,111,95,98,121,116,101,115,12,117,105,100,95,116,111,95,105,110,110,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,7,5,1,2,1,15,8,0,0,1,0,0,6,4,11,0,16,0,56,0,2,1,1,0,0,6,4,11,0,16,0,20,2,2,1,0,0,6,4,11,0,17,21,17,3,2,3,1,0,0,6,3,11,0,18,0,2,4,0,0,0,6,12,11,0,17,23,7,3,33,4,6,5,8,7,2,39,7,0,18,0,18,1,2,5,3,0,0,6,4,7,1,18,0,18,1,2,6,1,0,0,6,3,11,0,16,1,2,7,1,0,0,6,4,11,0,16,1,20,2,8,1,0,0,6,5,11,0,16,1,16,0,56,0,2,9,1,0,0,6,5,11,0,16,1,16,0,20,2,10,1,0,0,6,5,11,0,17,22,18,0,18,1,2,11,1,0,0,6,5,11,0,19,1,19,0,17,18,2,12,1,0,0,6,5,11,0,56,1,16,1,20,2,13,1,0,0,6,4,11,0,56,1,16,1,2,14,1,0,0,6,5,11,0,56,1,16,1,56,2,2,15,1,0,0,6,6,11,0,56,1,16,1,16,0,20,2,16,0,2,0,17,3,0,0,6,6,10,0,17,19,11,0,18,0,18,1,2,18,0,2,0,19,0,2,0,0,0,1,0,0,8,0,11,0,12,0,29,0],"object_bag":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,22,3,32,124,4,156,1,14,5,170,1,88,7,130,2,231,1,8,233,3,64,6,169,4,10,10,179,4,8,12,187,4,245,1,13,176,6,4,0,20,1,21,0,12,0,19,0,24,0,1,12,0,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,18,0,1,0,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,22,6,8,2,7,12,0,8,4,9,1,7,0,9,4,9,2,7,12,0,17,10,11,0,0,16,10,9,0,0,11,1,3,0,0,25,4,12,1,7,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,13,16,9,1,7,2,14,16,9,2,7,12,2,15,16,12,1,7,2,22,17,8,2,7,12,3,10,13,3,0,3,18,0,13,0,11,14,12,14,13,14,17,14,14,18,15,14,16,18,1,7,8,4,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,9,79,98,106,101,99,116,66,97,103,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,10,111,98,106,101,99,116,95,98,97,103,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,15,8,3,23,3,0,1,0,0,3,5,11,0,17,19,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,19,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,18,2,10,1,0,0,3,5,11,0,16,0,11,1,56,6,2,0,0,0,1,0],"object_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,26,3,36,120,4,156,1,12,5,168,1,113,7,153,2,199,1,8,224,3,64,6,160,4,10,10,170,4,8,11,178,4,2,12,180,4,230,1,13,154,6,4,14,158,6,4,0,18,1,19,0,11,0,17,0,22,0,1,12,2,7,1,12,1,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,16,0,1,2,7,12,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,20,6,8,2,7,12,0,8,4,9,2,7,12,0,15,10,11,2,7,12,0,14,10,9,2,7,12,0,10,1,3,2,7,12,0,23,4,12,2,7,12,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,12,16,9,1,7,2,13,16,12,1,7,2,20,17,8,2,7,12,3,9,13,3,0,3,16,0,13,0,10,14,11,14,12,14,15,14,13,18,14,18,1,7,8,4,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,13,8,3,21,3,0,14,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,19,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,9,1,0,0,3,5,11,0,55,0,11,1,56,5,2,0,0,0,1,0,14,1,14,0],"package":[161,28,235,11,6,0,0,0,11,1,0,14,2,14,36,3,50,183,1,4,233,1,10,5,243,1,118,7,233,2,144,5,8,249,7,64,6,185,8,93,10,150,9,48,12,198,9,129,4,13,199,13,20,0,36,1,10,1,50,0,33,0,48,0,49,0,51,0,1,12,0,0,6,12,0,0,8,0,0,0,7,0,0,1,2,7,0,2,4,7,0,3,0,7,0,3,5,4,0,5,3,2,0,0,14,0,1,1,2,0,15,0,2,1,2,0,12,1,2,0,0,22,3,4,1,0,0,21,3,4,1,0,0,39,3,5,0,0,40,3,5,0,0,52,6,7,0,0,54,6,8,0,0,53,6,9,0,0,46,10,7,0,0,47,10,9,0,0,41,11,7,0,0,42,11,7,0,0,45,10,12,0,0,17,2,9,0,0,9,2,9,0,0,19,2,9,0,0,34,13,2,0,0,35,13,2,0,0,30,14,2,0,0,11,15,16,0,0,16,17,2,0,0,43,18,2,0,2,23,24,25,0,2,24,24,25,0,2,25,2,19,1,0,3,18,23,2,0,3,26,21,7,1,8,3,27,27,7,0,3,28,31,27,0,3,32,22,23,0,4,38,28,2,1,12,5,44,26,27,0,6,29,21,4,1,2,34,20,26,20,0,20,32,1,28,14,2,9,0,7,8,8,1,8,0,0,1,6,8,0,1,1,1,6,8,4,1,6,8,1,1,8,6,1,3,1,2,1,6,8,2,1,6,8,3,1,6,10,2,1,7,8,1,1,8,1,3,7,8,1,2,10,2,1,8,2,2,7,8,1,8,3,2,7,8,1,2,1,8,5,1,9,0,1,6,9,0,1,7,8,8,1,8,7,1,6,8,5,1,8,4,1,6,8,8,1,5,2,9,0,5,2,1,8,5,2,8,6,8,6,1,6,8,6,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,15,97,100,100,105,116,105,118,101,95,112,111,108,105,99,121,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,14,98,117,114,110,95,112,117,98,108,105,115,104,101,114,3,99,97,112,5,99,108,97,105,109,14,99,108,97,105,109,95,97,110,100,95,107,101,101,112,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,17,99,111,109,112,97,116,105,98,108,101,95,112,111,108,105,99,121,6,100,101,108,101,116,101,15,100,101,112,95,111,110,108,121,95,112,111,108,105,99,121,6,100,105,103,101,115,116,11,102,114,111,109,95,109,111,100,117,108,101,12,102,114,111,109,95,112,97,99,107,97,103,101,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,14,109,97,107,101,95,105,109,109,117,116,97,98,108,101,11,109,111,100,117,108,101,95,110,97,109,101,3,110,101,119,6,111,98,106,101,99,116,22,111,110,108,121,95,97,100,100,105,116,105,118,101,95,117,112,103,114,97,100,101,115,17,111,110,108,121,95,100,101,112,95,117,112,103,114,97,100,101,115,7,112,97,99,107,97,103,101,6,112,111,108,105,99,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,16,112,117,98,108,105,115,104,101,100,95,109,111,100,117,108,101,17,112,117,98,108,105,115,104,101,100,95,112,97,99,107,97,103,101,11,114,101,99,101,105,112,116,95,99,97,112,15,114,101,99,101,105,112,116,95,112,97,99,107,97,103,101,8,114,101,115,116,114,105,99,116,6,115,101,110,100,101,114,13,116,105,99,107,101,116,95,100,105,103,101,115,116,14,116,105,99,107,101,116,95,112,97,99,107,97,103,101,13,116,105,99,107,101,116,95,112,111,108,105,99,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,5,116,121,112,101,115,15,117,112,103,114,97,100,101,95,112,97,99,107,97,103,101,14,117,112,103,114,97,100,101,95,112,111,108,105,99,121,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,2,1,0,2,1,128,2,1,192,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,26,8,7,36,8,4,31,8,4,1,2,4,26,8,7,36,8,6,54,3,37,2,2,2,4,13,8,6,36,8,6,37,2,20,10,2,3,2,2,13,8,6,36,8,6,0,1,0,0,19,18,14,0,56,0,4,4,5,8,11,1,1,7,0,39,56,1,12,2,11,1,17,31,14,2,17,24,14,2,17,25,18,0,2,1,1,0,0,2,8,11,0,10,1,56,2,11,1,46,17,33,56,3,2,2,1,0,0,2,6,11,0,19,0,1,1,17,27,2,3,1,0,0,19,9,56,1,12,1,14,1,17,24,11,0,16,0,20,33,2,4,1,0,0,29,23,56,1,12,2,14,2,17,24,10,0,16,0,20,33,4,17,14,2,17,25,11,0,16,1,20,33,12,1,5,21,11,0,1,9,12,1,11,1,2,5,1,0,0,2,3,11,0,16,1,2,6,1,0,0,2,3,11,0,16,0,2,7,1,0,0,2,4,11,0,16,2,20,2,8,1,0,0,2,4,11,0,16,3,20,2,9,1,0,0,2,4,11,0,16,4,20,2,10,1,0,0,2,4,11,0,16,5,20,2,11,1,0,0,2,4,11,0,16,6,20,2,12,1,0,0,2,4,11,0,16,7,20,2,13,1,0,0,2,4,11,0,16,8,20,2,14,1,0,0,2,3,11,0,16,9,2,15,1,0,0,2,2,7,5,2,16,1,0,0,2,2,7,6,2,17,1,0,0,2,2,7,7,2,18,1,4,0,2,4,11,0,7,6,17,23,2,19,1,4,0,2,4,11,0,7,7,17,23,2,20,1,4,0,2,7,11,0,19,1,1,1,1,17,27,2,21,1,0,0,30,41,7,8,17,29,12,3,10,0,16,2,20,10,3,34,4,10,5,14,11,0,1,7,2,39,10,1,10,0,16,4,20,38,4,21,5,25,11,0,1,7,1,39,10,0,16,2,20,12,4,11,3,10,0,15,2,21,11,0,46,56,4,11,4,11,1,11,2,18,2,2,22,1,0,0,30,39,11,1,19,3,12,3,12,2,10,0,46,56,4,11,2,33,4,11,5,15,11,0,1,7,4,39,10,0,16,2,17,30,7,8,33,4,22,5,26,11,0,1,7,3,39,11,3,10,0,15,2,21,10,0,16,3,20,6,1,0,0,0,0,0,0,0,22,11,0,15,3,21,2,23,0,0,0,2,16,10,0,16,4,20,10,1,37,4,7,5,11,11,0,1,7,1,39,11,1,11,0,15,4,21,2,0,1,0,2,1,1,1,2,1,3,2,1,2,2,3,0,3,1,2,3,0],"pay":[161,28,235,11,6,0,0,0,9,1,0,8,2,8,10,3,18,77,4,95,14,5,109,126,7,235,1,173,1,8,152,3,32,6,184,3,10,12,194,3,214,2,0,9,0,2,0,15,0,16,1,0,12,1,0,1,3,1,2,0,0,8,0,1,1,0,0,12,2,1,1,0,0,14,3,1,1,0,0,13,4,1,1,0,0,3,2,1,1,0,0,5,5,1,1,0,0,6,6,1,1,0,0,7,7,1,1,0,1,4,2,16,1,0,1,5,5,1,1,0,1,12,2,10,1,0,2,10,11,1,1,12,3,11,8,9,0,11,10,10,12,0,12,1,12,8,12,9,12,6,12,2,11,0,1,9,0,6,8,1,0,3,7,11,0,1,9,0,3,7,8,1,3,7,11,0,1,9,0,10,3,7,8,1,4,7,11,0,1,9,0,3,5,7,8,1,2,7,11,0,1,9,0,11,0,1,9,0,2,7,11,0,1,9,0,10,11,0,1,9,0,2,10,11,0,1,9,0,5,1,6,8,1,1,5,1,11,0,1,9,0,2,9,0,5,1,9,0,2,3,3,1,3,3,3,3,10,11,0,1,9,0,1,10,11,0,1,9,0,3,11,0,1,9,0,3,3,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,15,100,105,118,105,100,101,95,97,110,100,95,107,101,101,112,13,100,105,118,105,100,101,95,105,110,116,111,95,110,4,106,111,105,110,8,106,111,105,110,95,118,101,99,21,106,111,105,110,95,118,101,99,95,97,110,100,95,116,114,97,110,115,102,101,114,4,107,101,101,112,3,112,97,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,18,115,112,108,105,116,95,97,110,100,95,116,114,97,110,115,102,101,114,9,115,112,108,105,116,95,118,101,99,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,5,11,0,11,1,17,12,56,0,2,1,1,4,0,1,8,11,0,11,1,10,2,56,1,11,2,46,56,2,2,2,1,4,0,13,27,6,0,0,0,0,0,0,0,0,14,1,65,14,12,4,12,3,10,3,10,4,35,4,22,5,10,10,0,14,1,10,3,66,14,20,10,2,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,2,1,2,3,1,4,0,1,7,11,0,11,1,11,3,56,1,11,2,56,0,2,4,1,4,0,15,31,11,0,11,1,10,2,56,4,12,5,6,0,0,0,0,0,0,0,0,14,5,65,10,12,4,12,3,10,3,10,4,35,4,26,5,15,13,5,69,10,10,2,46,17,12,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,10,11,2,1,11,5,70,10,0,0,0,0,0,0,0,0,2,5,1,4,0,1,4,11,0,11,1,56,5,2,6,1,4,0,17,26,6,0,0,0,0,0,0,0,0,14,1,65,10,12,4,12,3,10,3,10,4,35,4,21,5,10,13,1,69,10,12,2,10,0,11,2,56,5,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,7,1,4,0,10,18,14,0,65,10,6,0,0,0,0,0,0,0,0,36,4,6,5,8,7,0,39,13,0,69,10,12,2,13,2,11,0,56,6,11,2,11,1,56,0,2,0],"priority_queue":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,12,3,16,60,4,76,10,5,86,167,1,7,253,1,184,1,8,181,3,64,6,245,3,14,10,131,4,18,11,149,4,4,12,153,4,243,5,13,140,10,4,14,144,10,4,0,11,1,16,0,1,6,1,2,0,0,0,6,1,2,0,0,6,0,1,1,2,0,8,2,3,1,2,0,4,4,5,1,2,0,7,3,6,1,2,0,2,7,0,1,2,0,13,8,5,1,2,0,5,9,5,1,2,0,9,10,11,1,2,1,12,15,13,1,0,1,14,15,13,1,0,6,13,9,6,5,13,8,16,8,13,1,10,11,1,1,9,0,1,11,0,1,9,0,1,7,11,0,1,9,0,2,3,9,0,3,7,11,0,1,9,0,3,9,0,0,1,11,1,1,9,0,2,10,3,10,9,0,2,7,10,11,1,1,9,0,3,3,7,10,11,1,1,9,0,3,3,1,6,11,0,1,9,0,1,10,3,2,3,3,1,9,0,3,3,3,9,0,2,7,10,9,0,3,1,3,5,3,3,3,10,11,1,1,9,0,9,0,5,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,13,7,10,11,1,1,9,0,1,3,7,10,11,1,1,9,0,3,1,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,3,3,2,3,10,3,5,69,110,116,114,121,13,80,114,105,111,114,105,116,121,81,117,101,117,101,14,99,114,101,97,116,101,95,101,110,116,114,105,101,115,7,101,110,116,114,105,101,115,6,105,110,115,101,114,116,21,109,97,120,95,104,101,97,112,105,102,121,95,114,101,99,117,114,115,105,118,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,7,112,111,112,95,109,97,120,10,112,114,105,111,114,105,116,105,101,115,8,112,114,105,111,114,105,116,121,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,6,114,101,109,111,118,101,22,114,101,115,116,111,114,101,95,104,101,97,112,95,114,101,99,117,114,115,105,118,101,11,115,119,97,112,95,114,101,109,111,118,101,5,118,97,108,117,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,10,3,1,0,0,2,1,3,10,11,1,1,9,0,1,2,2,10,3,15,9,0,0,13,1,13,0,1,0,0,12,24,14,0,65,6,12,2,10,2,6,2,0,0,0,0,0,0,0,26,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,21,5,12,11,1,6,1,0,0,0,0,0,0,0,23,12,1,13,0,10,2,10,1,56,0,5,7,11,0,57,0,2,1,1,0,0,14,30,10,0,55,0,65,6,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,10,0,54,0,6,0,0,0,0,0,0,0,0,56,1,58,1,12,3,12,2,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,6,0,0,0,0,0,0,0,0,56,0,11,2,11,3,2,2,1,0,0,16,17,10,0,54,0,11,1,11,2,57,1,68,6,10,0,55,0,65,6,6,1,0,0,0,0,0,0,0,23,12,3,11,0,54,0,11,3,56,2,2,3,1,0,0,5,4,11,0,11,1,57,1,2,4,1,0,0,17,40,14,0,65,16,12,3,14,1,65,13,10,3,33,4,9,5,11,6,0,0,0,0,0,0,0,0,39,64,6,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,38,5,20,13,0,6,0,0,0,0,0,0,0,0,56,3,12,4,13,1,6,0,0,0,0,0,0,0,0,56,4,12,6,13,5,11,4,11,6,57,1,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,5,2,5,0,0,0,18,46,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,1,6,1,0,0,0,0,0,0,0,23,6,2,0,0,0,0,0,0,0,26,12,6,10,0,10,1,12,3,12,2,10,0,10,6,12,5,12,4,11,2,46,11,3,66,6,55,1,20,11,4,46,11,5,66,6,55,1,20,36,4,43,10,0,11,1,10,6,71,6,11,0,11,6,56,2,5,45,11,0,1,2,6,0,0,0,19,110,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,2,10,1,35,4,12,5,16,11,0,1,6,1,0,0,0,0,0,0,0,39,10,2,6,2,0,0,0,0,0,0,0,24,6,1,0,0,0,0,0,0,0,22,12,13,10,13,6,1,0,0,0,0,0,0,0,22,12,15,10,2,12,14,10,13,10,1,35,4,55,10,0,10,13,12,5,12,3,10,0,10,14,12,7,12,6,11,3,46,11,5,66,6,55,1,20,11,6,46,11,7,66,6,55,1,20,36,12,8,5,57,9,12,8,11,8,4,61,11,13,12,14,10,15,10,1,35,4,88,10,0,10,15,12,10,12,9,10,0,10,14,12,12,12,11,11,9,46,11,10,66,6,55,1,20,11,11,46,11,12,66,6,55,1,20,36,12,4,5,90,9,12,4,11,4,4,94,11,15,12,14,10,14,10,2,34,4,107,10,0,10,14,11,2,71,6,11,0,11,1,11,14,56,0,5,109,11,0,1,2,7,1,0,0,20,28,7,1,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,0,55,0,65,6,35,4,24,5,11,13,2,10,0,55,0,10,1,66,6,55,1,20,68,16,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,4,11,0,1,11,2,2,0,0,1,0,0,13,1,13,0],"prover":[161,28,235,11,6,0,0,0,4,1,0,2,7,2,7,8,9,32,6,41,30,0,0,6,112,114,111,118,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0],"sui":[161,28,235,11,6,0,0,0,10,1,0,14,2,14,48,3,62,62,4,124,14,5,138,1,133,1,7,143,2,129,2,8,144,4,64,6,208,4,102,10,182,5,5,12,187,5,109,0,22,1,18,0,9,0,10,0,23,0,25,0,26,0,4,2,0,1,3,7,1,0,0,2,0,4,1,0,1,2,5,4,1,0,1,3,1,12,1,0,1,3,2,12,1,0,1,3,6,12,1,0,1,5,7,2,0,6,8,7,0,0,16,0,1,0,0,23,2,3,0,1,17,3,9,1,0,2,12,16,7,1,0,2,15,17,18,1,0,3,11,11,12,1,2,3,24,15,16,1,0,4,19,14,3,1,12,4,20,20,3,1,12,5,14,5,7,0,5,21,5,6,0,2,8,5,10,7,13,6,10,4,10,3,10,8,19,1,7,8,7,1,11,2,1,8,0,2,11,4,1,8,0,5,0,4,11,5,1,8,0,11,3,1,8,0,11,2,1,8,0,11,6,1,8,0,1,6,8,7,1,5,1,3,1,8,8,1,11,1,1,9,0,1,8,0,7,9,0,2,10,2,10,2,10,2,11,1,1,8,8,7,8,7,2,11,6,1,9,0,11,5,1,9,0,1,11,5,1,8,0,1,9,0,1,11,6,1,9,0,1,11,3,1,9,0,2,7,11,3,1,9,0,3,1,11,2,1,9,0,1,11,4,1,8,0,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,114,108,7,98,97,108,97,110,99,101,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,11,100,117,109,109,121,95,102,105,101,108,100,5,101,112,111,99,104,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,3,115,117,105,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,228,11,84,2,0,0,0,3,8,0,0,232,137,4,35,199,138,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,2,4,3,83,85,73,10,2,4,3,83,117,105,10,2,1,0,0,2,1,13,1,0,0,0,0,4,47,10,0,46,17,10,7,5,33,4,7,5,11,11,0,1,7,1,39,10,0,46,17,9,6,0,0,0,0,0,0,0,0,33,4,18,5,22,11,0,1,7,0,39,9,18,0,49,9,7,6,7,7,7,8,56,0,11,0,56,1,12,1,12,4,11,1,56,2,11,4,56,3,12,2,13,2,7,4,56,4,12,3,11,2,56,5,1,11,3,2,1,1,4,0,3,4,11,0,11,1,56,6,2,0],"table":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,16,3,24,115,4,139,1,10,5,149,1,104,7,253,1,167,1,8,164,3,32,6,196,3,10,10,206,3,8,11,214,3,2,12,216,3,229,1,13,189,5,4,14,193,5,4,0,19,0,10,0,16,0,20,0,0,12,2,7,1,4,1,2,2,4,0,3,1,2,0,0,15,0,1,2,7,4,0,3,2,3,2,7,4,0,4,4,5,2,7,4,0,5,6,7,2,7,4,0,17,6,8,2,7,4,0,6,4,9,2,7,4,0,14,10,11,2,7,4,0,13,10,9,2,7,4,0,8,1,3,2,7,4,0,9,1,3,2,7,6,1,3,14,3,2,7,4,1,4,15,5,2,7,4,1,5,16,7,2,7,4,1,11,15,9,2,7,4,1,17,16,8,2,7,4,2,7,12,3,0,2,15,0,12,0,10,13,11,13,12,13,14,13,13,13,1,7,8,2,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,2,8,1,3,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,1,18,3,0,13,0,1,0,0,3,5,11,0,17,16,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,17,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,15,2,9,1,0,0,3,5,11,0,58,0,1,17,15,2,0,0,0,1,0,13,1,13,0],"table_vec":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,18,3,24,116,4,140,1,22,5,162,1,138,1,7,172,2,164,1,8,208,3,32,6,240,3,20,10,132,4,10,11,142,4,2,12,144,4,130,2,13,146,6,2,14,148,6,2,0,18,0,17,0,19,0,1,4,1,4,1,1,0,12,2,7,1,4,1,2,2,2,0,0,9,0,1,1,4,0,16,2,1,1,4,0,11,3,4,1,4,0,10,3,5,1,4,0,4,6,7,1,4,0,14,8,9,1,4,0,5,10,11,1,4,0,13,12,13,1,4,0,7,1,9,1,4,0,8,1,9,1,6,1,3,19,9,2,7,4,1,4,17,18,2,7,4,1,5,20,21,2,7,4,1,7,15,9,2,7,4,1,8,15,9,2,7,6,1,11,16,4,2,7,4,1,12,0,15,2,7,4,1,15,20,22,2,7,4,16,14,0,13,5,13,15,14,2,13,11,14,10,14,12,14,17,14,13,14,14,14,1,7,8,2,1,11,0,1,9,0,2,9,0,7,8,2,1,6,11,0,1,9,0,1,3,1,1,2,6,11,0,1,9,0,3,1,6,9,0,2,7,11,0,1,9,0,9,0,0,2,7,11,0,1,9,0,3,1,7,9,0,1,7,11,0,1,9,0,1,9,0,2,3,9,0,1,11,1,2,9,0,9,1,1,6,11,1,2,9,0,9,1,2,6,11,1,2,9,0,9,1,9,0,1,6,9,1,3,7,11,1,2,9,0,9,1,9,0,9,1,2,7,11,1,2,9,0,9,1,9,0,1,7,9,1,1,9,1,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,5,101,109,112,116,121,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,6,11,1,2,3,9,0,0,13,0,1,0,0,9,4,11,0,56,0,57,0,2,1,1,0,0,1,8,11,1,56,1,12,2,13,2,11,0,56,2,11,2,2,2,1,0,0,9,4,11,0,55,0,56,3,2,3,1,0,0,9,5,11,0,56,4,6,0,0,0,0,0,0,0,0,33,2,4,1,0,0,9,15,10,0,56,4,10,1,36,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,5,2,5,1,0,0,4,10,10,0,46,56,4,12,2,11,0,54,0,11,2,11,1,56,6,2,6,1,0,0,9,16,10,0,46,56,4,10,1,36,4,7,5,11,11,0,1,7,0,39,11,0,54,0,11,1,56,7,2,7,1,0,0,4,20,10,0,46,56,4,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,56,8,2,8,1,0,0,9,12,14,0,56,4,6,0,0,0,0,0,0,0,0,33,4,6,5,8,7,1,39,11,0,58,0,56,9,2,9,1,0,0,9,4,11,0,58,0,56,10,2,0,0,0,13,0],"transfer":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,54,4,56,6,5,62,8,7,70,144,1,8,214,1,32,6,246,1,10,12,128,2,82,0,7,0,7,0,1,1,8,0,4,0,1,1,12,0,0,2,1,1,8,0,2,2,1,1,12,0,5,2,1,1,8,0,3,2,1,1,12,0,1,2,1,1,8,0,6,2,1,1,8,0,8,0,1,1,8,8,2,6,2,7,2,2,9,0,5,0,1,9,0,13,102,114,101,101,122,101,95,111,98,106,101,99,116,18,102,114,101,101,122,101,95,111,98,106,101,99,116,95,105,109,112,108,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,17,115,104,97,114,101,95,111,98,106,101,99,116,95,105,109,112,108,8,116,114,97,110,115,102,101,114,13,116,114,97,110,115,102,101,114,95,105,109,112,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,56,0,2,1,1,0,0,1,4,11,0,11,1,56,0,2,2,1,0,0,1,3,11,0,56,1,2,3,1,0,0,1,3,11,0,56,1,2,4,1,0,0,1,3,11,0,56,2,2,5,1,0,0,1,3,11,0,56,2,2,6,3,2,0,7,3,2,0,8,3,2,0,0],"transfer_policy":[161,28,235,11,6,0,0,0,13,1,0,26,2,26,78,3,104,150,2,4,254,2,50,5,176,3,192,3,7,240,6,138,5,8,250,11,64,6,186,12,60,10,246,12,55,11,173,13,10,12,183,13,150,5,13,205,18,16,14,221,18,16,0,63,1,48,1,65,0,19,0,21,0,29,0,32,0,47,0,49,0,60,0,62,0,64,0,70,0,10,0,1,0,1,0,7,12,1,0,1,0,8,12,1,0,1,0,9,3,1,0,1,0,5,7,1,2,1,1,3,7,1,0,0,2,12,7,0,3,0,4,1,0,1,4,1,12,1,0,1,7,2,7,0,7,13,4,0,8,4,12,0,9,6,2,0,11,11,2,0,12,14,7,1,3,0,0,46,0,1,1,0,0,45,2,3,1,0,0,24,2,4,1,0,0,71,5,6,1,0,0,26,7,6,1,0,0,22,8,0,1,0,0,17,9,4,3,0,2,6,0,38,10,11,3,0,2,6,0,18,12,4,2,0,2,0,16,13,4,2,0,2,0,39,14,15,2,0,2,0,55,16,4,3,0,2,6,0,66,14,17,1,0,0,67,16,18,1,0,0,56,14,19,1,0,0,44,20,21,1,0,0,50,20,22,1,0,0,34,20,21,1,0,1,27,41,25,1,0,1,43,40,15,1,0,2,37,4,23,1,0,3,69,42,22,1,0,3,72,4,32,1,0,4,35,46,44,1,0,4,52,58,4,1,0,4,61,43,44,1,0,5,15,54,4,2,7,4,5,20,56,57,2,7,4,5,33,56,15,1,7,5,54,61,52,2,7,4,6,30,25,4,1,3,7,25,29,4,0,7,40,39,21,1,8,7,45,28,29,0,7,68,17,21,0,8,36,27,15,1,0,10,58,25,4,1,8,10,62,37,4,1,8,11,57,35,36,0,12,23,50,15,1,3,12,31,4,24,1,3,12,41,55,4,1,3,12,42,24,48,1,3,12,54,62,4,1,3,12,59,49,22,1,3,40,23,35,25,30,30,22,31,1,25,36,34,37,33,32,34,19,22,18,22,21,31,25,31,23,31,42,23,44,23,39,23,10,51,26,53,20,52,41,23,27,53,24,31,28,59,29,53,43,23,3,8,9,3,8,9,1,11,0,1,9,0,2,6,8,11,7,8,13,2,11,1,1,9,0,11,2,1,9,0,0,4,7,11,1,1,9,0,6,11,2,1,9,0,11,5,1,3,7,8,13,1,11,8,1,8,12,3,11,1,1,9,0,11,2,1,9,0,7,8,13,2,6,11,1,1,9,0,11,0,1,9,0,4,9,1,7,11,1,1,9,0,6,11,2,1,9,0,9,2,2,9,1,6,11,1,1,9,0,1,6,9,2,3,9,1,7,11,1,1,9,0,11,8,1,8,12,2,9,1,7,11,0,1,9,0,1,6,11,1,1,9,0,1,1,2,7,11,1,1,9,0,6,11,2,1,9,0,1,6,8,10,1,7,8,10,1,6,11,14,1,8,6,1,6,11,0,1,9,0,1,8,9,1,3,1,8,6,1,11,14,1,9,0,1,9,0,5,8,10,11,14,1,8,6,11,7,1,8,12,8,10,8,9,1,6,8,11,1,7,8,13,1,8,10,1,11,3,1,9,0,1,8,12,1,11,7,1,9,0,1,11,2,1,9,0,1,11,1,1,9,0,1,6,8,13,1,5,2,9,0,5,3,3,3,3,1,6,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,1,6,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,13,1,11,8,1,9,0,2,11,7,1,8,12,8,10,2,11,7,1,9,0,7,8,13,7,10,8,6,8,9,8,9,3,11,14,1,8,6,8,6,3,1,10,9,0,1,6,11,14,1,9,0,2,6,11,14,1,9,0,6,9,0,2,9,0,9,1,1,9,1,2,11,4,1,9,1,9,2,3,7,8,10,9,0,9,1,2,7,11,14,1,9,0,9,0,2,6,8,10,9,0,1,6,9,1,2,7,11,7,1,9,0,11,8,1,9,0,1,11,4,1,9,1,2,8,6,7,11,14,1,8,6,2,7,8,10,9,0,2,7,11,14,1,9,0,6,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,9,80,117,98,108,105,115,104,101,114,7,82,117,108,101,75,101,121,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,17,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,97,112,21,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,114,101,97,116,101,100,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,86,101,99,83,101,116,3,97,100,100,11,97,100,100,95,114,101,99,101,105,112,116,8,97,100,100,95,114,117,108,101,14,97,100,100,95,116,111,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,4,99,111,105,110,15,99,111,110,102,105,114,109,95,114,101,113,117,101,115,116,8,99,111,110,116,97,105,110,115,7,100,101,102,97,117,108,116,6,100,101,108,101,116,101,20,100,101,115,116,114,111,121,95,97,110,100,95,119,105,116,104,100,114,97,119,12,100,101,115,116,114,111,121,95,115,111,109,101,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,7,101,120,105,115,116,115,95,4,102,114,111,109,12,102,114,111,109,95,98,97,108,97,110,99,101,12,102,114,111,109,95,112,97,99,107,97,103,101,3,103,101,116,8,103,101,116,95,114,117,108,101,8,104,97,115,95,114,117,108,101,2,105,100,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,7,105,115,95,115,111,109,101,4,105,116,101,109,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,4,112,97,105,100,9,112,111,108,105,99,121,95,105,100,3,112,117,116,8,114,101,99,101,105,112,116,115,6,114,101,109,111,118,101,11,114,101,109,111,118,101,95,114,117,108,101,5,114,117,108,101,115,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,105,122,101,3,115,117,105,4,116,97,107,101,8,116,114,97,110,115,102,101,114,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,3,117,105,100,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,7,118,101,99,95,115,101,116,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,4,44,8,9,50,3,34,8,9,53,11,14,1,8,6,1,2,3,40,8,10,19,11,7,1,8,12,56,11,14,1,8,6,2,2,2,40,8,10,51,8,9,3,2,1,40,8,9,4,2,1,28,1,0,25,3,25,1,25,2,25,4,52,0,1,0,0,4,6,11,0,11,1,11,2,56,0,57,0,2,1,1,0,0,26,32,11,0,56,1,4,4,5,8,11,1,1,6,0,0,0,0,0,0,0,0,39,10,1,17,33,12,5,14,5,17,34,12,6,10,6,57,1,56,2,11,5,12,2,56,0,12,3,56,3,12,4,11,2,11,4,11,3,57,2,11,1,17,33,11,6,57,3,2,2,0,4,0,33,11,11,0,10,1,56,4,12,2,56,5,11,2,11,1,46,17,38,56,6,2,3,1,0,0,38,49,10,0,46,56,7,11,1,55,0,20,33,4,9,5,15,11,0,1,11,3,1,7,4,39,14,2,56,8,4,37,11,2,56,9,12,6,10,6,10,0,55,1,56,10,37,4,28,5,34,11,0,1,11,3,1,7,5,39,11,6,12,4,5,41,10,0,55,1,56,10,12,4,11,4,12,5,11,0,54,1,11,5,11,3,56,11,2,4,1,0,0,45,27,14,0,56,7,14,1,55,0,20,33,4,8,5,12,11,2,1,7,4,39,11,1,58,3,1,12,4,11,0,58,2,1,12,3,17,31,11,4,17,31,11,3,11,2,56,12,2,5,1,0,0,47,52,11,1,58,0,12,6,12,3,12,5,12,4,11,6,56,13,12,2,14,2,65,23,12,8,10,8,10,0,55,2,56,14,33,4,19,5,23,11,0,1,7,0,39,10,8,6,0,0,0,0,0,0,0,0,36,4,46,5,28,13,2,69,23,12,7,10,0,55,2,14,7,56,15,4,37,5,41,11,0,1,7,1,39,11,8,6,1,0,0,0,0,0,0,0,23,12,8,5,23,11,0,1,11,4,11,5,11,3,2,6,1,0,0,4,34,10,1,46,56,7,11,2,55,0,20,33,4,9,5,13,11,1,1,7,4,39,10,1,46,56,16,32,4,19,5,23,11,1,1,7,3,39,10,1,54,3,9,57,4,11,3,56,17,11,1,54,2,56,18,56,19,2,7,1,0,0,4,6,11,1,55,3,9,57,4,56,20,2,8,1,0,0,4,14,10,1,46,56,16,4,5,5,9,11,1,1,7,2,39,11,1,54,1,11,2,56,21,2,9,1,0,0,4,5,11,1,54,4,56,18,56,19,2,10,1,0,0,4,6,11,0,55,3,9,57,4,56,22,2,11,1,0,0,60,28,10,0,46,56,7,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,10,0,54,3,9,57,4,56,23,1,11,0,54,2,12,3,56,18,12,2,11,3,14,2,56,24,2,12,1,0,0,4,3,11,0,55,3,2,13,1,0,0,4,16,10,0,46,56,7,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,11,0,54,3,2,14,1,0,0,4,3,11,0,55,2,2,15,1,0,0,4,4,11,0,55,5,20,2,16,1,0,0,4,4,11,0,55,6,20,2,17,1,0,0,4,4,11,0,55,7,20,2,2,1,1,1,1,2,1,0,0,3,0,0,0,1,0,2,0,25,1,25,2,25,3,25,4,25,5,25,6,25,7,25,0],"tx_context":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,24,7,65,111,8,176,1,32,6,208,1,20,10,228,1,14,12,242,1,107,13,221,2,10,0,8,0,0,2,0,0,7,0,1,0,0,2,0,2,0,0,3,0,3,0,0,4,0,3,0,0,5,4,1,0,0,6,0,3,0,0,1,5,1,0,1,6,8,0,1,5,1,6,10,2,1,3,1,7,8,0,2,10,2,3,0,2,5,3,9,84,120,67,111,110,116,101,120,116,9,100,101,114,105,118,101,95,105,100,6,100,105,103,101,115,116,5,101,112,111,99,104,18,101,112,111,99,104,95,116,105,109,101,115,116,97,109,112,95,109,115,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,11,105,100,115,95,99,114,101,97,116,101,100,6,115,101,110,100,101,114,10,116,120,95,99,111,110,116,101,120,116,7,116,120,95,104,97,115,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,32,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,5,7,5,9,10,2,3,3,4,3,6,3,0,1,0,0,6,4,11,0,16,0,20,2,1,1,0,0,6,3,11,0,16,1,2,2,1,0,0,6,4,11,0,16,2,20,2,3,1,0,0,6,4,11,0,16,3,20,2,4,1,0,0,7,18,10,0,16,4,20,12,2,10,0,16,1,20,10,2,17,6,12,1,11,2,6,1,0,0,0,0,0,0,0,22,11,0,15,4,21,11,1,2,5,0,0,0,6,4,11,0,16,4,20,2,6,0,2,0,0,0,0,1,0,2,0,3,0,4,0],"types":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,6,7,14,26,8,40,32,12,72,4,0,1,0,0,0,1,1,2,1,6,9,0,1,1,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,5,116,121,112,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"url":[161,28,235,11,6,0,0,0,9,1,0,4,2,4,8,3,12,25,5,37,20,7,57,78,8,135,1,64,10,199,1,6,12,205,1,50,13,255,1,2,0,8,1,2,0,1,7,0,1,0,7,0,0,4,0,1,0,0,5,2,1,0,0,3,3,0,0,0,7,4,5,0,1,6,2,0,0,1,8,1,1,8,0,1,10,2,1,6,8,0,2,7,8,0,8,1,0,6,83,116,114,105,110,103,3,85,114,108,5,97,115,99,105,105,9,105,110,110,101,114,95,117,114,108,10,110,101,119,95,117,110,115,97,102,101,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,6,115,116,114,105,110,103,6,117,112,100,97,116,101,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,8,8,1,0,1,0,0,5,3,11,0,18,0,2,1,1,0,0,5,4,11,0,17,4,18,0,2,2,1,0,0,5,4,11,0,16,0,20,2,3,1,0,0,5,5,11,1,11,0,15,0,21,2,0,0,0],"vec_map":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,22,3,28,168,1,4,196,1,28,5,224,1,254,1,7,222,3,153,2,8,247,5,64,6,183,6,50,10,233,6,21,11,254,6,4,12,130,7,235,5,13,237,12,6,14,243,12,6,0,30,1,21,1,31,0,2,7,2,1,0,0,0,0,0,7,2,1,0,0,0,1,1,7,1,0,0,0,7,0,1,2,1,0,0,14,2,0,2,1,0,0,23,3,4,2,1,0,0,22,5,4,2,1,0,0,13,3,6,2,1,0,0,8,7,8,2,1,0,0,28,7,9,2,1,1,0,3,7,10,2,1,0,0,26,11,12,2,1,0,0,16,11,10,2,1,0,0,5,1,0,2,1,0,0,15,1,13,2,1,0,0,19,11,14,2,1,0,0,12,7,15,2,1,0,0,11,7,12,2,1,0,0,9,16,17,2,1,0,0,10,18,19,2,1,0,0,24,18,4,2,1,0,1,6,27,24,1,0,1,17,28,10,1,0,1,20,0,27,1,0,1,27,24,27,1,0,2,16,25,10,1,0,2,23,23,24,1,0,2,25,31,0,1,0,7,4,14,4,23,20,22,20,5,4,21,26,20,26,13,4,19,12,8,4,24,20,21,12,20,12,18,12,0,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,2,7,11,0,2,9,0,9,1,6,9,0,2,9,0,9,1,1,7,11,0,2,9,0,9,1,1,7,9,1,2,6,11,0,2,9,0,9,1,6,9,0,1,6,9,1,1,11,2,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,2,10,9,0,10,9,1,1,10,9,0,1,11,2,1,3,2,6,11,0,2,9,0,9,1,3,2,6,9,0,6,9,1,2,7,11,0,2,9,0,9,1,3,2,6,9,0,7,9,1,1,11,1,2,9,0,9,1,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,9,0,1,6,10,9,0,1,9,1,1,11,2,1,9,0,1,6,11,2,1,9,0,1,10,11,1,2,9,0,9,1,7,10,11,1,2,9,0,9,1,3,9,0,10,9,0,3,9,1,10,9,1,1,7,10,9,0,4,6,11,1,2,9,0,9,1,3,10,9,0,3,2,3,3,1,6,11,1,2,9,0,9,1,1,7,11,1,2,9,0,9,1,5,69,110,116,114,121,6,79,112,116,105,111,110,6,86,101,99,77,97,112,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,3,103,101,116,16,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,20,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,95,109,117,116,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,7,103,101,116,95,109,117,116,6,105,110,115,101,114,116,16,105,110,116,111,95,107,101,121,115,95,118,97,108,117,101,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,3,107,101,121,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,3,112,111,112,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,101,110,116,114,121,95,98,121,95,105,100,120,7,114,101,118,101,114,115,101,4,115,105,122,101,4,115,111,109,101,7,116,114,121,95,103,101,116,5,118,97,108,117,101,7,118,101,99,95,109,97,112,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,1,4,10,11,1,2,9,0,9,1,1,2,2,18,9,0,29,9,1,0,4,1,4,0,1,0,0,0,3,64,20,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,21,20,10,0,14,1,12,3,46,11,3,56,0,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,11,2,57,1,68,20,2,2,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,56,2,58,1,2,3,1,0,0,0,15,10,0,55,0,56,3,32,4,6,5,10,11,0,1,7,4,39,11,0,54,0,69,20,58,1,2,4,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,67,20,54,1,2,5,1,0,0,12,10,10,0,11,1,56,1,12,2,11,0,55,0,11,2,66,20,55,1,2,6,1,0,0,9,19,10,0,10,1,56,0,4,11,11,0,11,1,56,4,20,56,5,12,2,5,17,11,0,1,11,1,1,56,6,12,2,11,2,2,7,1,0,0,15,7,11,0,11,1,56,7,12,2,14,2,56,8,2,8,1,0,0,0,4,11,0,55,0,65,20,2,9,1,0,0,0,5,11,0,56,9,6,0,0,0,0,0,0,0,0,33,2,10,1,0,0,29,12,11,0,58,0,12,1,14,1,56,3,4,7,5,9,7,2,39,11,1,70,20,0,0,0,0,0,0,0,0,2,11,1,0,0,30,40,11,0,58,0,12,1,13,1,56,10,6,0,0,0,0,0,0,0,0,12,2,14,1,65,20,12,5,64,24,0,0,0,0,0,0,0,0,12,4,64,26,0,0,0,0,0,0,0,0,12,7,10,2,10,5,35,4,35,5,19,13,1,69,20,58,1,12,6,12,3,13,4,11,3,68,24,13,7,11,6,68,26,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,14,11,1,70,20,0,0,0,0,0,0,0,0,11,4,11,7,2,12,1,0,0,32,32,6,0,0,0,0,0,0,0,0,12,2,10,0,55,0,65,20,12,4,64,24,0,0,0,0,0,0,0,0,12,3,10,2,10,4,35,4,28,5,13,10,0,55,0,10,2,66,20,12,1,13,3,11,1,55,2,20,68,24,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,8,11,0,1,11,3,2,13,1,0,0,33,36,6,0,0,0,0,0,0,0,0,12,2,10,0,56,9,12,3,10,2,10,3,35,4,30,5,10,10,0,55,0,10,2,66,20,55,2,10,1,33,4,25,11,0,1,11,1,1,11,2,56,11,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,12,2,14,1,0,0,15,13,11,0,11,1,56,7,12,2,14,2,56,8,4,8,5,10,7,1,39,11,2,56,13,2,15,1,0,0,34,20,10,1,10,0,56,9,35,4,6,5,10,11,0,1,7,3,39,11,0,55,0,11,1,66,20,12,2,10,2,55,2,11,2,55,1,2,16,1,0,0,35,21,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,67,20,12,2,10,2,55,2,11,2,54,1,2,17,1,0,0,0,17,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,56,2,58,1,2,0,0,1,1,1,0,0,4,1,4,2,4,0],"vec_set":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,12,3,18,102,4,120,20,5,140,1,95,7,235,1,164,1,8,143,3,64,6,207,3,20,10,227,3,7,11,234,3,2,12,236,3,156,2,13,136,6,2,14,138,6,2,0,19,1,14,1,20,0,1,7,1,3,0,1,0,7,1,0,0,0,5,0,1,1,3,0,16,2,1,1,3,0,8,3,0,1,3,0,15,4,0,1,3,0,2,5,6,1,3,0,17,7,8,1,3,0,10,7,6,1,3,0,9,1,9,1,3,0,12,7,10,1,3,0,7,5,11,1,3,0,6,5,8,1,3,1,4,17,2,1,0,1,11,15,6,1,0,1,13,0,17,1,0,1,18,2,17,1,0,2,15,14,2,1,0,2,16,2,9,1,0,16,2,4,2,10,2,15,2,9,2,12,8,5,2,14,8,13,8,11,8,0,1,11,0,1,9,0,1,9,0,2,7,11,0,1,9,0,9,0,2,7,11,0,1,9,0,6,9,0,2,6,11,0,1,9,0,6,9,0,1,1,1,6,11,0,1,9,0,1,3,1,10,9,0,1,6,10,9,0,1,11,1,1,3,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,6,11,1,1,9,0,2,3,3,1,11,1,1,9,0,6,79,112,116,105,111,110,6,86,101,99,83,101,116,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,4,115,105,122,101,4,115,111,109,101,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,3,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,12,18,10,0,14,1,12,2,46,11,2,56,1,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,68,2,2,3,1,0,0,13,13,10,0,11,1,12,2,46,11,2,56,2,12,3,11,0,54,0,11,3,56,3,1,2,4,1,0,0,11,7,11,0,11,1,56,4,12,2,14,2,56,5,2,5,1,0,0,0,4,11,0,55,0,65,2,2,6,1,0,0,0,5,11,0,56,6,6,0,0,0,0,0,0,0,0,33,2,7,1,0,0,0,3,11,0,58,0,2,8,1,0,0,0,3,11,0,55,0,2,9,0,0,0,16,35,6,0,0,0,0,0,0,0,0,12,2,10,0,56,6,12,3,10,2,10,3,35,4,29,5,10,10,0,55,0,10,2,66,2,10,1,33,4,24,11,0,1,11,1,1,11,2,56,7,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,8,2,10,0,0,0,11,13,11,0,11,1,56,4,12,2,14,2,56,5,4,8,5,10,7,1,39,11,2,56,9,2,0,0,0,2,0],"versioned":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,20,3,28,85,4,113,10,5,123,97,7,220,1,236,1,8,200,3,32,6,232,3,10,10,242,3,16,12,130,4,197,1,13,199,5,4,0,23,0,11,0,16,0,20,0,4,12,0,0,3,0,0,2,0,7,0,2,2,4,0,3,1,2,0,0,8,0,1,1,4,0,22,2,3,0,0,13,2,4,1,4,0,14,5,6,1,4,0,19,5,7,1,4,0,21,8,9,1,4,0,10,1,10,1,4,1,5,14,9,2,7,4,1,6,15,16,2,7,4,1,7,17,18,2,7,4,1,18,17,19,2,7,4,2,9,12,9,0,2,12,4,20,1,8,2,15,11,12,0,7,13,8,13,9,13,10,13,12,1,3,3,9,0,7,8,4,1,8,0,1,6,8,0,1,3,1,6,9,0,1,7,8,0,1,7,9,0,2,9,0,8,1,4,7,8,0,3,9,0,8,1,0,1,9,0,1,7,8,4,1,8,3,2,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,8,2,3,8,3,9,0,3,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,16,86,101,114,115,105,111,110,67,104,97,110,103,101,67,97,112,9,86,101,114,115,105,111,110,101,100,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,2,105,100,10,108,111,97,100,95,118,97,108,117,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,3,110,101,119,6,111,98,106,101,99,116,11,111,108,100,95,118,101,114,115,105,111,110,6,114,101,109,111,118,101,24,114,101,109,111,118,101,95,118,97,108,117,101,95,102,111,114,95,117,112,103,114,97,100,101,10,116,120,95,99,111,110,116,101,120,116,7,117,112,103,114,97,100,101,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,12,118,101,114,115,105,111,110,101,100,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,3,22,3,1,2,2,24,8,2,17,3,0,1,0,0,1,12,11,2,17,13,10,0,18,0,12,3,13,3,15,0,11,0,11,1,56,0,11,3,2,1,1,0,0,9,4,11,0,16,1,20,2,2,1,0,0,9,7,10,0,16,0,11,0,16,1,20,56,1,2,3,1,0,0,9,7,10,0,15,0,11,0,16,1,20,56,2,2,4,1,0,0,9,14,10,0,15,0,10,0,16,1,20,56,3,10,0,46,56,4,11,0,16,1,20,18,1,2,5,1,0,0,3,32,11,3,19,1,12,4,10,0,46,56,4,33,4,9,5,13,11,0,1,7,0,39,11,4,10,1,35,4,18,5,22,11,0,1,7,0,39,10,0,15,0,10,1,11,2,56,0,11,1,11,0,15,1,21,2,6,1,0,0,21,12,11,0,19,0,12,3,12,1,13,1,11,3,56,3,12,2,11,1,17,11,11,2,2,0,0,0,1,0]},"type_origin_table":[{"module_name":"tx_context","struct_name":"TxContext","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"ID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"UID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_field","struct_name":"Field","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bag","struct_name":"Bag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Supply","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Balance","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bcs","struct_name":"BCS","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Referent","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"clock","struct_name":"Clock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"url","struct_name":"Url","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"Coin","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CoinMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"TreasuryCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CurrencyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"VecMap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"Publisher","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeTicket","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeReceipt","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"Display","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"DisplayCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"VersionUpdated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_object_field","struct_name":"Wrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"Curve","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PreparedVerifyingKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PublicProofInputs","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"ProofPoints","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_set","struct_name":"VecSet","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"sui","struct_name":"SUI","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferRequest","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicy","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"RuleKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Kiosk","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"KioskOwnerCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"PurchaseCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Item","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Listing","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Lock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemListed","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemPurchased","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemDelisted","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk_extension","struct_name":"Extension","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk_extension","struct_name":"ExtensionKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"LinkedTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"Node","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_bag","struct_name":"ObjectBag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_table","struct_name":"ObjectTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"PriorityQueue","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table","struct_name":"Table","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table_vec","struct_name":"TableVec","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"Versioned","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"VersionChangeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"ACKQVv64dXCmpxE1QPU2QMLxVpmtbzrFGMtWYY6szJrQ","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000003","version":7,"module_map":{"genesis":[161,28,235,11,6,0,0,0,11,1,0,26,2,26,58,3,84,107,4,191,1,14,5,205,1,176,2,7,253,3,137,9,8,134,13,96,6,230,13,20,10,250,13,93,12,215,14,219,3,13,178,18,24,0,31,1,44,1,72,2,18,2,20,2,43,2,61,2,66,0,54,0,63,0,64,0,67,0,70,0,3,3,0,0,2,3,0,0,9,0,0,0,8,0,0,1,4,7,1,0,0,3,0,4,1,0,1,4,1,12,1,0,1,5,11,4,0,6,5,2,0,7,10,2,0,8,6,4,0,10,7,4,0,11,12,4,0,0,22,0,1,0,0,15,2,1,0,0,14,3,1,0,1,25,25,26,1,0,1,36,24,14,1,0,2,35,22,14,1,0,3,26,9,1,1,0,3,53,8,9,1,0,3,75,1,9,1,0,4,29,30,31,1,0,6,65,32,1,0,7,27,5,6,0,8,22,17,18,0,9,22,19,1,0,10,23,15,16,0,11,13,34,1,0,11,42,12,10,0,11,52,29,1,0,12,32,27,28,0,12,34,13,14,0,7,7,8,7,5,21,4,23,3,23,9,7,6,7,6,8,7,11,5,1,8,8,8,1,10,8,0,8,2,7,8,9,0,4,11,5,1,8,8,10,8,3,7,10,8,12,7,8,9,1,7,10,8,12,25,10,8,3,3,3,10,2,3,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,8,10,3,11,5,1,8,8,11,5,1,8,8,5,8,11,8,12,10,8,12,10,2,10,2,1,6,8,9,1,3,1,8,8,2,7,11,5,1,9,0,3,1,11,5,1,9,0,1,8,12,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,9,2,6,10,8,12,6,8,12,1,1,8,3,3,3,3,3,3,3,7,8,9,1,8,11,5,11,5,1,8,8,3,3,13,7,8,9,1,8,10,8,8,7,10,8,12,11,5,1,8,8,3,3,8,11,8,10,7,8,9,5,11,5,1,8,8,3,5,11,4,1,5,5,1,8,3,1,6,10,9,0,1,5,1,6,11,4,1,9,0,1,11,4,1,9,0,1,9,0,2,7,10,8,12,5,1,7,8,12,4,7,8,12,11,5,1,8,8,5,7,8,9,2,11,5,1,9,0,7,8,9,1,11,6,1,9,0,2,11,6,1,8,8,5,2,3,3,2,7,8,12,3,7,66,97,108,97,110,99,101,4,67,111,105,110,22,71,101,110,101,115,105,115,67,104,97,105,110,80,97,114,97,109,101,116,101,114,115,24,71,101,110,101,115,105,115,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,15,84,111,107,101,110,65,108,108,111,99,97,116,105,111,110,25,84,111,107,101,110,68,105,115,116,114,105,98,117,116,105,111,110,83,99,104,101,100,117,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,9,86,97,108,105,100,97,116,111,114,8,97,99,116,105,118,97,116,101,19,97,99,116,105,118,97,116,101,95,118,97,108,105,100,97,116,111,114,115,15,97,108,108,111,99,97,116,101,95,116,111,107,101,110,115,11,97,108,108,111,99,97,116,105,111,110,115,11,97,109,111,117,110,116,95,109,105,115,116,7,98,97,108,97,110,99,101,24,99,104,97,105,110,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,4,99,111,105,110,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,12,102,114,111,109,95,98,97,108,97,110,99,101,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,9,105,109,97,103,101,95,117,114,108,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,4,110,97,109,101,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,18,110,101,116,119,111,114,107,95,112,117,98,108,105,99,95,107,101,121,3,110,101,119,6,111,98,106,101,99,116,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,19,112,114,111,116,111,99,111,108,95,112,117,98,108,105,99,95,107,101,121,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,17,114,101,99,105,112,105,101,110,116,95,97,100,100,114,101,115,115,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,23,115,116,97,107,101,95,115,117,98,115,105,100,121,95,102,117,110,100,95,109,105,115,116,41,115,116,97,107,101,95,115,117,98,115,105,100,121,95,105,110,105,116,105,97,108,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,21,115,116,97,107,101,100,95,119,105,116,104,95,118,97,108,105,100,97,116,111,114,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,118,97,108,105,100,97,116,111,114,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,13,118,97,108,105,100,97,116,111,114,95,115,101,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,6,118,101,99,116,111,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,17,119,111,114,107,101,114,95,112,117,98,108,105,99,95,107,101,121,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,15,39,10,2,24,10,2,33,10,2,47,10,2,62,5,30,3,21,3,49,10,2,48,10,2,41,10,2,74,10,2,40,10,2,45,10,2,46,10,2,73,10,2,1,2,12,50,3,19,3,28,3,59,3,57,3,58,3,55,13,37,3,38,3,69,3,71,3,68,3,2,2,2,56,3,16,10,8,3,3,2,3,51,5,17,3,60,11,4,1,5,0,0,0,0,4,147,1,10,5,46,17,11,6,0,0,0,0,0,0,0,0,33,4,7,5,11,11,5,1,7,0,39,11,4,19,2,12,6,12,22,13,1,11,22,56,0,12,24,56,1,12,23,64,10,0,0,0,0,0,0,0,0,12,28,14,3,65,11,12,8,6,0,0,0,0,0,0,0,0,12,11,10,11,10,8,35,4,89,5,33,14,3,10,11,66,11,20,19,0,12,29,12,17,12,16,12,14,12,30,12,15,12,19,12,20,12,7,12,10,12,25,12,18,12,12,12,9,12,13,11,25,11,20,11,15,11,30,11,19,11,13,11,9,11,12,11,18,11,14,11,16,11,17,11,29,11,10,11,7,10,5,17,16,12,27,14,28,14,27,17,19,32,4,77,5,81,11,5,1,7,1,39,13,28,11,27,68,10,11,11,6,1,0,0,0,0,0,0,0,22,12,11,5,28,11,1,11,6,13,28,10,5,17,1,13,28,17,2,14,2,16,0,20,14,2,16,1,20,14,2,16,2,20,14,2,16,3,20,14,2,16,4,20,14,2,16,5,20,14,2,16,6,20,10,5,17,14,12,26,11,24,14,2,16,7,20,14,2,16,8,20,14,2,16,9,20,10,5,17,12,12,21,11,0,11,28,11,23,14,2,16,10,20,14,2,16,11,20,11,26,11,21,11,5,17,13,2,1,0,0,0,20,44,14,1,56,2,32,4,35,5,5,13,1,69,21,19,3,12,7,12,5,12,6,13,0,11,5,56,0,12,4,14,7,56,3,4,29,11,7,56,4,12,8,10,2,11,8,17,18,11,4,11,6,10,3,17,17,5,34,11,4,10,3,56,5,11,6,17,10,5,0,11,2,1,11,3,1,11,1,70,21,0,0,0,0,0,0,0,0,11,0,56,6,2,2,0,0,0,33,24,10,0,46,65,10,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,1,35,4,21,5,11,10,0,10,2,67,10,6,0,0,0,0,0,0,0,0,17,15,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,2,1,2,1,3,1,7,1,8,1,9,1,10,1,11,1,4,1,5,1,6,1,0,1,1,0],"stake_subsidy":[161,28,235,11,6,0,0,0,12,1,0,12,2,12,22,3,34,37,4,71,4,5,75,74,7,149,1,176,2,8,197,3,64,6,133,4,28,10,161,4,20,12,181,4,180,1,13,233,5,10,15,243,5,4,0,18,1,6,1,7,1,14,1,21,1,23,0,3,4,0,1,0,12,0,2,1,4,1,0,1,4,2,2,0,5,4,2,0,0,8,0,1,0,0,5,2,3,0,0,10,4,5,0,1,16,7,8,0,2,17,13,14,1,0,2,24,11,5,1,0,3,15,12,5,0,5,10,4,10,5,11,2,1,8,3,3,3,13,7,8,4,1,8,0,1,7,8,0,1,11,2,1,8,3,1,6,8,0,1,3,0,1,7,8,4,1,8,1,3,4,11,2,1,8,3,3,1,8,3,1,6,11,2,1,9,0,2,3,3,2,7,11,2,1,9,0,3,1,11,2,1,9,0,3,66,97,103,7,66,97,108,97,110,99,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,84,120,67,111,110,116,101,120,116,13,97,100,118,97,110,99,101,95,101,112,111,99,104,3,98,97,103,7,98,97,108,97,110,99,101,6,99,114,101,97,116,101,27,99,117,114,114,101,110,116,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,28,99,117,114,114,101,110,116,95,101,112,111,99,104,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,20,100,105,115,116,114,105,98,117,116,105,111,110,95,99,111,117,110,116,101,114,12,101,120,116,114,97,95,102,105,101,108,100,115,7,103,101,110,101,115,105,115,4,109,97,116,104,3,109,105,110,3,110,101,119,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,6,7,11,2,1,8,3,11,3,9,3,20,3,19,13,12,8,1,0,3,0,0,6,19,10,3,7,0,75,37,4,6,5,10,11,4,1,7,1,39,11,0,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,11,4,17,3,18,0,2,1,3,0,0,9,57,10,0,16,0,20,10,0,16,1,56,0,17,6,12,3,10,0,15,1,11,3,56,1,12,2,10,0,16,2,20,6,1,0,0,0,0,0,0,0,22,10,0,15,2,21,10,0,16,2,20,10,0,16,3,20,25,6,0,0,0,0,0,0,0,0,33,4,53,10,0,16,0,20,53,10,0,16,4,20,53,24,7,0,26,12,1,10,0,16,0,20,11,1,52,23,11,0,15,0,21,5,55,11,0,1,11,2,2,2,1,0,0,6,8,10,0,16,0,20,11,0,16,1,56,0,17,6,2,0,2,0,0,0,1,0,3,0,4,0,13,0,22,0],"staking_pool":[161,28,235,11,6,0,0,0,12,1,0,20,2,20,52,3,72,173,2,4,245,2,34,5,151,3,205,2,7,228,5,200,8,8,172,14,96,6,140,15,200,1,10,212,16,66,12,150,17,145,11,13,167,28,28,15,195,28,4,0,68,1,45,2,14,2,15,2,40,2,44,2,69,2,72,2,73,2,74,0,7,12,0,0,4,7,0,0,6,12,0,1,3,7,1,0,0,2,0,12,0,3,1,4,1,0,1,5,2,7,0,5,10,4,0,6,5,2,0,7,8,12,2,7,1,4,1,9,9,2,0,0,42,0,1,0,0,59,2,3,0,0,60,4,5,0,0,79,6,7,0,0,75,3,5,0,0,22,8,9,0,0,58,10,9,0,0,57,11,9,0,0,56,11,9,0,0,80,12,5,0,0,11,13,9,0,0,19,13,9,0,0,71,14,15,0,0,51,16,17,0,0,67,16,15,0,0,66,16,15,0,0,35,14,18,0,0,33,14,18,0,0,64,19,3,0,0,65,19,9,0,0,39,20,9,0,0,32,21,18,0,0,54,22,23,0,0,48,14,15,0,0,49,14,15,0,0,24,14,24,0,0,70,25,15,0,0,52,25,15,0,0,36,22,18,0,0,27,26,15,0,0,28,26,15,0,0,31,9,23,0,0,17,22,9,0,1,16,48,37,1,0,1,26,46,9,1,0,1,29,52,47,1,3,1,34,48,18,1,0,1,37,48,18,1,0,1,43,9,31,1,0,1,63,47,31,1,0,2,42,0,34,0,3,38,40,15,1,0,3,64,45,33,1,0,3,78,36,15,1,0,3,81,9,33,1,0,4,41,42,15,0,5,21,30,9,0,5,30,37,17,1,8,5,42,0,30,0,7,13,43,9,2,7,4,7,16,53,54,2,7,4,7,18,53,18,2,7,4,7,42,0,29,2,7,4,8,73,50,9,1,8,9,23,39,15,0,9,62,39,49,0,52,28,38,15,44,32,43,32,47,1,41,32,49,28,42,32,34,15,39,15,36,15,37,15,53,3,35,15,33,15,51,28,50,28,1,7,8,10,1,8,0,4,7,8,0,11,5,1,8,8,3,7,8,10,1,8,2,3,7,8,0,8,2,7,8,10,1,11,5,1,8,8,2,7,8,0,8,2,2,3,11,5,1,8,8,2,7,8,0,11,5,1,8,8,0,2,7,8,0,7,8,10,1,7,8,0,4,7,8,0,3,3,3,2,7,8,0,3,1,6,8,0,1,3,1,6,8,2,1,8,6,1,1,3,7,8,2,3,7,8,10,2,7,8,2,8,2,2,6,8,2,6,8,2,2,6,8,0,3,1,8,1,1,6,11,9,2,3,8,1,1,6,8,1,2,6,8,1,3,1,11,9,2,3,8,1,2,3,8,1,1,11,9,2,9,0,9,1,1,8,7,1,11,3,1,9,0,1,8,8,1,11,5,1,9,0,1,8,4,2,8,2,3,1,6,11,5,1,9,0,1,6,9,0,5,3,11,5,1,8,8,3,11,5,1,8,8,3,1,6,8,10,2,7,11,5,1,9,0,11,5,1,9,0,3,3,8,1,11,5,1,8,8,2,3,3,3,7,11,9,2,9,0,9,1,9,0,9,1,5,3,3,8,1,3,3,2,7,11,5,1,9,0,3,2,7,11,3,1,9,0,9,0,1,9,0,1,6,11,3,1,9,0,1,5,2,9,0,5,2,6,8,2,11,5,1,8,8,2,6,11,3,1,9,0,9,0,2,6,11,9,2,9,0,9,1,9,0,1,6,9,1,3,3,8,1,3,3,66,97,103,7,66,97,108,97,110,99,101,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,16,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,3,97,100,100,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,24,99,104,101,99,107,95,98,97,108,97,110,99,101,95,105,110,118,97,114,105,97,110,116,115,8,99,111,110,116,97,105,110,115,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,18,100,101,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,6,100,101,108,101,116,101,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,5,101,112,111,99,104,14,101,120,99,104,97,110,103,101,95,114,97,116,101,115,12,101,120,116,114,97,95,102,105,101,108,100,115,4,102,105,108,108,14,103,101,116,95,115,117,105,95,97,109,111,117,110,116,16,103,101,116,95,116,111,107,101,110,95,97,109,111,117,110,116,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,2,105,100,21,105,110,105,116,105,97,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,25,105,115,95,101,113,117,97,108,95,115,116,97,107,105,110,103,95,109,101,116,97,100,97,116,97,11,105,115,95,105,110,97,99,116,105,118,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,21,105,115,95,112,114,101,97,99,116,105,118,101,95,97,116,95,101,112,111,99,104,7,105,115,95,115,111,109,101,4,106,111,105,110,15,106,111,105,110,95,115,116,97,107,101,100,95,115,117,105,4,109,97,116,104,3,109,105,110,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,27,112,101,110,100,105,110,103,95,112,111,111,108,95,116,111,107,101,110,95,119,105,116,104,100,114,97,119,13,112,101,110,100,105,110,103,95,115,116,97,107,101,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,26,112,101,110,100,105,110,103,95,116,111,116,97,108,95,115,117,105,95,119,105,116,104,100,114,97,119,7,112,111,111,108,95,105,100,17,112,111,111,108,95,116,111,107,101,110,95,97,109,111,117,110,116,18,112,111,111,108,95,116,111,107,101,110,95,98,97,108,97,110,99,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,9,112,114,105,110,99,105,112,97,108,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,30,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,12,114,101,119,97,114,100,115,95,112,111,111,108,6,115,101,110,100,101,114,4,115,111,109,101,5,115,112,108,105,116,16,115,112,108,105,116,95,115,116,97,107,101,100,95,115,117,105,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,97,109,111,117,110,116,11,115,117,105,95,98,97,108,97,110,99,101,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,17,117,110,119,114,97,112,95,115,116,97,107,101,100,95,115,117,105,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,5,118,97,108,117,101,23,119,105,116,104,100,114,97,119,95,102,114,111,109,95,112,114,105,110,99,105,112,97,108,16,119,105,116,104,100,114,97,119,95,114,101,119,97,114,100,115,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,0,2,11,30,8,7,12,11,3,1,3,20,11,3,1,3,71,3,61,11,5,1,8,8,53,3,24,11,9,2,3,8,1,47,3,50,3,46,3,25,8,4,1,2,2,70,3,52,3,2,2,4,30,8,7,51,8,6,66,3,55,11,5,1,8,8,0,3,0,0,27,18,10,0,56,0,12,1,10,0,17,48,56,1,56,1,6,0,0,0,0,0,0,0,0,56,2,6,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,0,17,40,18,0,2,1,3,0,0,35,45,14,1,56,3,12,5,10,0,46,17,17,32,4,9,5,15,11,0,1,11,3,1,7,11,39,10,5,6,0,0,0,0,0,0,0,0,36,4,20,5,26,11,0,1,11,3,1,7,18,39,11,3,17,48,10,0,46,56,4,11,2,11,1,18,2,12,4,10,0,16,0,20,11,5,22,11,0,15,0,21,11,4,2,2,3,0,0,38,52,10,0,11,1,17,3,12,4,12,3,14,4,56,3,12,5,10,0,10,5,10,3,11,2,46,17,54,17,9,12,6,11,5,14,6,56,3,22,12,7,10,0,16,1,20,11,7,22,10,0,15,1,21,10,0,16,2,20,11,3,22,10,0,15,2,21,10,0,46,17,17,4,44,11,0,17,7,5,46,11,0,1,13,4,11,6,56,5,1,11,4,2,3,3,0,0,41,31,14,1,16,3,20,10,0,46,56,4,33,4,9,5,13,11,0,1,7,2,39,11,0,14,1,16,4,20,12,2,46,11,2,17,22,12,3,11,1,17,4,12,4,14,3,14,4,56,3,17,30,11,4,2,4,0,0,0,5,8,11,0,19,2,12,1,1,1,17,46,11,1,2,5,3,0,0,9,15,10,0,16,5,20,14,1,56,3,22,10,0,15,5,21,11,0,15,6,11,1,56,5,1,2,6,3,0,0,42,28,11,1,46,17,54,6,1,0,0,0,0,0,0,0,22,12,3,10,0,17,7,10,0,17,8,10,0,15,7,10,3,10,0,16,5,20,10,0,16,8,20,18,1,56,6,11,0,11,3,12,2,46,11,2,17,32,2,7,0,0,0,9,29,10,0,16,5,20,10,0,16,1,20,23,10,0,15,5,21,10,0,16,8,20,10,0,16,2,20,23,10,0,15,8,21,6,0,0,0,0,0,0,0,0,10,0,15,1,21,6,0,0,0,0,0,0,0,0,11,0,15,2,21,2,8,3,0,0,23,31,10,0,16,5,20,10,0,16,8,20,18,1,12,1,10,0,16,5,20,10,0,16,0,20,22,10,0,15,5,21,14,1,10,0,16,5,20,17,30,10,0,15,8,21,6,0,0,0,0,0,0,0,0,11,0,15,0,21,2,9,0,0,0,44,33,10,0,11,3,12,4,46,11,4,17,22,12,6,14,6,11,2,17,29,12,8,10,8,10,1,38,4,20,11,8,11,1,23,12,5,5,22,6,0,0,0,0,0,0,0,0,12,5,11,5,10,0,16,6,56,3,17,45,12,7,11,0,15,6,11,7,56,7,2,10,3,0,0,9,29,10,0,15,7,10,1,17,31,56,6,10,0,46,17,16,4,10,5,14,11,0,1,7,15,39,10,0,46,17,17,32,4,20,5,24,11,0,1,7,17,39,11,0,15,9,11,1,56,8,2,11,3,0,0,9,16,10,0,46,17,17,32,4,6,5,10,11,0,1,7,12,39,11,1,56,9,11,0,15,10,21,2,12,1,0,0,9,4,11,0,16,5,20,2,13,1,0,0,9,4,11,0,16,3,20,2,14,1,0,0,9,4,11,0,16,11,56,3,2,15,1,0,0,9,4,11,0,16,4,20,2,16,1,0,0,9,4,11,0,16,9,56,10,2,17,1,0,0,9,4,11,0,16,10,56,11,2,18,1,0,0,15,53,10,0,16,11,56,3,12,3,10,1,10,3,37,4,9,5,15,11,0,1,11,2,1,7,4,39,11,3,10,1,23,7,0,38,4,22,5,28,11,0,1,11,2,1,7,19,39,10,1,7,0,38,4,33,5,39,11,0,1,11,2,1,7,19,39,11,2,17,48,10,0,16,3,20,10,0,16,4,20,11,0,15,11,11,1,56,7,18,2,2,19,1,4,0,9,9,11,0,11,1,10,2,17,18,11,2,46,17,55,56,12,2,20,1,4,0,51,24,10,0,14,1,12,2,46,11,2,17,21,4,8,5,12,11,0,1,7,13,39,11,1,19,2,12,3,1,1,17,46,11,0,15,11,11,3,56,5,1,2,21,1,0,0,18,25,10,0,16,3,20,10,1,16,3,20,33,4,17,11,0,16,4,20,11,1,16,4,20,33,12,2,5,23,11,0,1,11,1,1,9,12,2,11,2,2,22,1,0,0,42,45,10,0,10,1,17,28,4,8,11,0,1,17,31,2,10,0,16,10,10,1,56,13,11,1,17,45,12,3,10,0,16,9,56,14,20,12,2,10,3,10,2,38,4,41,5,25,10,0,16,7,10,3,56,15,4,36,11,0,16,7,11,3,56,16,20,2,11,3,6,1,0,0,0,0,0,0,0,23,12,3,5,20,11,0,1,17,31,2,23,1,0,0,9,4,11,0,16,0,20,2,24,1,0,0,9,4,11,0,16,1,20,2,25,3,0,0,9,3,11,0,16,7,2,26,1,0,0,9,4,11,0,16,12,20,2,27,1,0,0,9,4,11,0,16,13,20,2,28,0,0,0,18,17,10,0,17,16,4,8,11,0,1,8,12,2,5,15,11,0,16,9,56,14,20,11,1,36,12,2,11,2,2,29,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,12,20,53,11,1,53,24,11,0,16,13,20,53,26,52,2,30,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,13,20,53,11,1,53,24,11,0,16,12,20,53,26,52,2,31,0,0,0,9,4,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,18,1,2,32,0,0,0,55,22,10,0,11,1,17,22,12,3,14,3,10,0,16,5,20,17,30,12,4,11,0,16,8,20,12,2,11,4,11,2,33,4,19,5,21,7,10,39,2,0,7,0,8,0,9,2,1,2,2,0,3,0,4,0,6,0,5,0,1,0,2,2,3,1,0,1,1,0,76,0,77,0],"storage_fund":[161,28,235,11,6,0,0,0,11,1,0,6,2,6,14,3,20,44,4,64,8,5,72,73,7,145,1,178,1,8,195,2,64,10,131,3,15,12,146,3,107,13,253,3,4,15,129,4,2,0,9,1,4,1,10,0,2,4,0,1,0,4,1,0,1,2,1,2,0,0,6,0,1,0,0,3,2,0,0,0,13,3,4,0,0,12,3,4,0,1,5,8,4,1,0,1,8,9,7,1,0,1,14,10,4,1,0,1,15,5,7,1,0,7,6,4,6,5,6,6,6,1,11,1,1,8,2,1,8,0,6,7,8,0,11,1,1,8,2,11,1,1,8,2,11,1,1,8,2,3,3,1,6,8,0,1,3,0,1,8,2,1,11,1,1,9,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,6,11,1,1,9,0,7,66,97,108,97,110,99,101,3,83,85,73,11,83,116,111,114,97,103,101,70,117,110,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,4,106,111,105,110,3,110,101,119,22,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,98,97,108,97,110,99,101,5,115,112,108,105,116,12,115,116,111,114,97,103,101,95,102,117,110,100,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,13,116,111,116,97,108,95,98,97,108,97,110,99,101,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,11,1,1,8,2,7,11,1,1,8,2,0,3,0,0,5,4,56,0,11,0,18,0,2,1,3,0,0,0,30,10,0,15,0,11,2,56,1,1,10,0,15,0,11,3,56,1,1,10,0,15,1,11,1,56,1,1,10,0,15,1,11,5,56,2,12,6,10,0,15,0,11,6,56,1,1,11,0,15,1,11,4,56,2,2,2,1,0,0,5,4,11,0,16,1,56,3,2,3,1,0,0,5,8,10,0,16,1,56,3,11,0,16,0,56,3,22,2,0,1,0,0,0,11,0],"sui_system":[161,28,235,11,6,0,0,0,12,1,0,30,2,30,78,3,108,188,3,4,168,4,16,5,184,4,214,3,7,142,8,237,13,8,251,21,96,6,219,22,54,10,145,23,8,12,153,23,251,6,13,148,30,4,15,152,30,2,0,57,1,33,2,20,2,22,2,24,2,32,2,56,2,60,2,61,2,62,0,54,0,55,0,58,0,83,0,84,0,8,8,0,1,3,7,1,0,0,2,0,4,1,0,1,3,1,12,1,0,1,5,2,7,0,5,14,4,0,6,5,2,0,7,12,12,2,7,1,4,1,9,13,2,0,10,6,4,0,11,4,7,0,11,7,12,0,12,9,4,0,12,10,4,0,12,11,4,0,13,16,4,0,14,15,12,0,0,23,0,1,0,0,42,2,1,0,0,44,3,1,0,0,41,3,1,0,0,43,3,1,0,0,46,4,1,0,0,52,4,1,0,0,45,5,1,0,0,51,5,1,0,0,38,6,1,0,0,40,6,7,0,0,39,8,1,0,0,47,9,1,0,0,48,9,10,0,0,37,11,1,0,0,63,11,1,0,0,49,3,1,0,0,73,12,1,0,0,71,12,1,0,0,72,12,1,0,0,81,12,1,0,0,74,12,1,0,0,64,12,1,0,0,76,12,1,0,0,66,12,1,0,0,77,12,1,0,0,67,12,1,0,0,79,12,1,0,0,69,12,1,0,0,78,13,1,0,0,68,13,1,0,0,80,12,1,0,0,70,12,1,0,0,75,12,1,0,0,65,12,1,0,0,34,14,15,0,0,17,16,17,0,0,19,18,10,0,0,30,16,19,0,0,31,16,20,0,0,29,16,20,0,3,25,39,40,1,0,4,18,26,1,2,7,4,4,21,49,53,2,7,4,4,36,49,50,2,7,4,8,35,35,1,1,12,8,53,28,1,1,8,9,50,33,34,0,12,17,19,17,0,12,19,47,10,0,12,23,22,23,0,12,27,1,24,0,12,34,46,15,0,12,37,43,1,0,12,38,36,7,0,12,39,37,7,0,12,41,30,1,0,12,42,29,1,0,12,43,30,1,0,12,44,30,1,0,12,45,32,1,0,12,46,31,1,0,12,47,42,10,0,12,49,30,1,0,12,51,32,1,0,12,52,31,1,0,12,59,19,24,0,12,63,43,1,0,12,64,44,1,0,12,65,44,1,0,12,66,44,1,0,12,67,44,1,0,12,68,45,1,0,12,69,44,1,0,12,70,44,1,0,12,71,44,1,0,12,72,44,1,0,12,73,44,1,0,12,74,44,1,0,12,75,44,1,0,12,76,44,1,0,12,77,44,1,0,12,78,45,1,0,12,79,44,1,0,12,80,44,1,0,12,81,44,1,0,12,82,23,51,0,42,25,46,27,45,7,41,38,45,41,44,25,42,52,43,52,8,8,5,10,8,15,11,2,1,8,6,3,3,8,14,8,9,7,8,8,0,16,7,8,0,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,8,2,7,8,0,7,8,8,3,7,8,0,6,8,16,3,3,7,8,0,3,7,8,8,4,7,8,0,11,3,1,8,6,5,7,8,8,1,8,11,5,7,8,0,10,11,3,1,8,6,11,1,1,3,5,7,8,8,3,7,8,0,8,11,7,8,8,1,11,2,1,8,6,3,7,8,0,6,8,16,5,3,7,8,0,10,2,6,8,8,4,7,8,0,10,2,10,2,6,8,8,2,7,8,0,6,8,4,1,6,11,7,2,3,8,10,1,7,8,0,1,10,5,11,11,2,1,8,6,11,2,1,8,6,7,8,0,3,3,3,3,3,3,3,7,8,8,1,6,8,13,1,7,8,13,3,8,0,8,12,3,7,10,8,15,11,2,1,8,6,3,3,8,14,8,9,7,8,8,1,8,12,1,3,2,3,8,12,3,7,8,5,9,0,9,1,1,8,0,1,9,0,16,7,8,13,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,8,2,7,8,13,7,8,8,3,7,8,13,6,8,16,3,3,7,8,13,3,7,8,8,1,6,8,8,1,5,2,9,0,5,4,7,8,13,11,3,1,8,6,5,7,8,8,5,7,8,13,10,11,3,1,8,6,11,1,1,3,5,7,8,8,1,8,6,2,11,2,1,9,0,7,8,8,1,11,3,1,9,0,1,11,3,1,8,6,3,7,8,13,8,11,7,8,8,3,7,8,13,6,8,16,5,3,7,8,13,10,2,6,8,8,4,7,8,13,10,2,10,2,6,8,8,2,7,8,13,6,8,4,11,7,8,13,3,3,11,2,1,8,6,11,2,1,8,6,3,3,3,3,3,7,8,8,2,7,8,13,8,13,2,7,8,5,9,0,1,9,1,1,8,13,2,3,8,13,1,7,9,1,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,14,83,117,105,83,121,115,116,101,109,83,116,97,116,101,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,26,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,101,115,3,97,100,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,4,99,111,105,110,6,99,114,101,97,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,2,105,100,24,108,111,97,100,95,105,110,110,101,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,17,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,21,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,95,109,117,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,19,112,111,111,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,27,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,110,111,110,95,101,110,116,114,121,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,32,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,95,110,111,110,95,101,110,116,114,121,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,6,115,101,110,100,101,114,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,28,8,5,85,3,0,3,0,0,21,23,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,50,12,9,17,51,12,10,11,0,10,10,18,0,12,8,13,8,15,0,11,10,11,9,56,0,11,8,56,1,2,1,1,4,0,1,19,11,0,17,39,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,11,15,17,57,2,2,1,4,0,1,5,11,0,17,39,11,1,17,59,2,3,1,4,0,1,5,11,0,17,39,11,1,17,56,2,4,1,4,0,1,5,11,0,17,39,11,1,17,58,2,5,1,4,0,1,6,11,0,17,39,11,1,11,2,17,61,2,6,1,4,0,1,6,11,0,17,39,11,1,11,2,17,65,2,7,1,4,0,1,6,11,0,17,39,11,1,11,2,17,60,2,8,1,4,0,1,6,11,0,17,39,11,1,11,2,17,64,2,9,1,4,0,1,10,11,0,11,1,11,2,10,3,17,10,11,3,46,17,47,56,2,2,10,1,0,0,1,7,11,0,17,39,11,1,11,2,11,3,17,54,2,11,1,4,0,1,12,11,0,17,39,11,1,11,2,11,3,10,4,17,55,11,4,46,17,47,56,2,2,12,1,4,0,1,11,11,0,11,1,10,2,17,13,10,2,56,3,11,2,46,17,47,56,4,2,13,1,0,0,1,6,11,0,17,39,11,1,11,2,17,62,2,14,1,4,0,1,6,11,0,17,39,11,1,11,2,17,53,2,15,1,4,0,1,6,11,0,17,39,11,1,11,2,17,67,2,16,1,4,0,1,5,11,0,17,39,11,1,17,63,2,17,1,4,0,1,6,11,0,17,39,11,1,11,2,17,77,2,18,1,4,0,1,6,11,0,17,39,11,1,11,2,17,75,2,19,1,4,0,1,6,11,0,17,39,11,1,11,2,17,76,2,20,1,4,0,1,6,11,0,17,39,11,1,11,2,17,85,2,21,1,4,0,1,6,11,0,17,39,11,1,11,2,17,78,2,22,1,4,0,1,6,11,0,17,39,11,1,11,2,17,68,2,23,1,4,0,1,6,11,0,17,39,11,1,11,2,17,80,2,24,1,4,0,1,6,11,0,17,39,11,1,11,2,17,70,2,25,1,4,0,1,6,11,0,17,39,11,1,11,2,17,81,2,26,1,4,0,1,6,11,0,17,39,11,1,11,2,17,71,2,27,1,4,0,1,6,11,0,17,39,11,1,11,2,17,83,2,28,1,4,0,1,6,11,0,17,39,11,1,11,2,17,73,2,29,1,4,0,1,7,11,0,17,39,11,1,11,2,11,3,17,82,2,30,1,4,0,1,7,11,0,17,39,11,1,11,2,11,3,17,72,2,31,1,4,0,1,6,11,0,17,39,11,1,11,2,17,84,2,32,1,4,0,1,6,11,0,17,39,11,1,11,2,17,74,2,33,1,4,0,1,6,11,0,17,39,11,1,11,2,17,79,2,34,1,4,0,1,6,11,0,17,39,11,1,11,2,17,69,2,35,1,0,0,1,5,11,0,17,39,11,1,17,52,2,36,1,0,0,1,4,11,0,17,38,17,48,2,37,0,0,0,20,29,11,2,17,39,12,11,10,10,46,17,47,7,2,33,4,10,5,16,11,11,1,11,10,1,7,0,39,11,11,11,3,11,4,11,0,11,1,11,5,11,6,11,7,11,8,11,9,11,10,17,49,2,38,0,0,0,1,4,11,0,17,40,46,2,39,0,0,0,1,3,11,0,17,40,2,40,0,0,0,48,47,10,0,16,1,20,6,1,0,0,0,0,0,0,0,33,4,25,10,0,15,0,10,0,16,1,20,56,5,17,86,12,2,6,2,0,0,0,0,0,0,0,10,0,15,1,21,10,0,15,0,10,0,16,1,20,11,2,56,6,10,0,15,0,10,0,16,1,20,56,7,12,1,10,1,46,17,66,11,0,16,1,20,33,4,41,5,45,11,1,1,7,1,39,11,1,2,0,0,0,1,0,26,0],"sui_system_state_inner":[161,28,235,11,6,0,0,0,12,1,0,45,2,45,108,3,153,1,235,5,4,132,7,50,5,182,7,151,7,7,205,14,129,30,8,206,44,96,6,174,45,117,10,163,46,189,1,12,224,47,134,18,13,230,65,46,15,148,66,4,0,115,1,70,2,27,2,28,2,29,2,41,2,69,2,72,2,113,2,117,2,123,2,124,2,177,1,2,178,1,0,103,0,106,0,109,0,164,1,0,165,1,0,169,1,0,13,4,0,0,14,4,0,0,10,4,0,0,11,4,0,0,12,3,0,1,4,7,1,0,0,2,0,12,0,3,1,4,1,0,1,4,2,12,1,0,1,6,3,7,0,8,6,2,0,9,15,12,2,7,1,4,1,11,16,2,0,12,21,7,2,1,0,0,0,13,22,7,1,3,0,14,7,4,0,15,5,7,0,15,8,12,0,16,9,4,0,17,18,4,0,18,17,12,0,18,19,2,0,19,20,4,0,0,31,0,1,0,0,32,2,3,0,0,163,1,1,4,0,0,83,5,6,0,0,85,7,6,0,0,82,7,6,0,0,84,7,6,0,0,87,8,6,0,0,99,8,6,0,0,86,9,6,0,0,98,9,6,0,0,80,10,11,0,0,81,12,11,0,0,88,13,14,0,0,78,15,6,0,0,125,15,6,0,0,79,16,6,0,0,126,16,6,0,0,89,7,6,0,0,154,1,17,6,0,0,152,1,17,6,0,0,153,1,17,6,0,0,162,1,17,6,0,0,155,1,17,6,0,0,132,1,17,6,0,0,157,1,17,6,0,0,134,1,17,6,0,0,158,1,17,6,0,0,135,1,17,6,0,0,160,1,17,6,0,0,137,1,17,6,0,0,159,1,18,6,0,0,136,1,18,6,0,0,161,1,17,6,0,0,138,1,17,6,0,0,156,1,17,6,0,0,133,1,17,6,0,0,25,19,14,0,0,38,20,21,0,0,74,20,21,0,0,116,20,21,0,0,46,6,21,0,0,40,20,21,0,0,170,1,22,21,0,0,171,1,22,23,0,0,172,1,20,24,0,0,49,22,25,0,0,51,20,21,0,0,50,20,21,0,0,73,26,27,0,0,23,20,28,0,0,43,29,14,0,1,34,99,68,1,0,1,59,98,63,1,0,2,66,39,40,0,3,35,38,6,1,0,3,60,85,21,1,0,3,101,89,38,1,0,3,176,1,87,21,1,0,3,181,1,84,38,1,0,3,182,1,6,38,1,0,4,44,100,58,1,0,4,56,58,38,1,0,5,36,68,6,1,3,7,61,97,6,1,0,10,75,101,6,1,12,11,38,43,21,0,11,95,43,44,0,12,30,67,63,2,1,0,12,37,6,36,2,1,0,12,47,67,93,2,1,0,12,48,71,72,2,1,0,12,55,70,6,2,1,0,12,77,71,77,2,1,0,13,30,73,63,1,3,13,37,6,69,1,3,13,55,74,6,1,3,13,58,76,63,1,3,13,77,75,6,1,3,13,100,68,69,1,3,14,25,88,14,0,15,102,60,21,0,16,25,91,14,0,16,66,14,34,0,16,118,86,21,0,16,120,86,21,0,17,66,45,42,0,17,67,78,6,0,17,87,54,6,0,17,96,57,6,0,17,97,54,6,0,17,127,79,6,0,17,128,1,79,6,0,17,129,1,79,6,0,17,130,1,79,6,0,17,131,1,82,6,0,17,139,1,79,6,0,17,140,1,79,6,0,17,141,1,79,6,0,17,142,1,79,6,0,17,143,1,79,6,0,17,144,1,79,6,0,17,145,1,79,6,0,17,146,1,79,6,0,17,147,1,79,6,0,17,148,1,82,6,0,17,149,1,79,6,0,17,150,1,79,6,0,17,151,1,79,6,0,18,179,1,65,66,0,19,23,33,28,0,19,24,33,49,0,19,25,90,6,0,19,26,81,6,0,19,33,33,21,0,19,52,56,53,0,19,53,56,53,0,19,54,52,53,0,19,57,62,63,0,19,66,31,32,0,19,68,33,21,0,19,73,94,27,0,19,80,59,11,0,19,82,48,6,0,19,83,46,6,0,19,84,47,6,0,19,85,47,6,0,19,86,55,6,0,19,88,61,14,0,19,107,33,24,0,19,121,33,21,0,19,171,1,62,23,0,19,173,1,62,21,0,19,180,1,51,50,0,69,35,60,37,62,37,68,35,79,44,72,35,71,35,74,44,76,44,78,44,77,44,73,35,59,37,56,37,58,37,57,37,63,92,70,35,75,44,64,37,53,21,52,21,61,37,65,96,55,37,7,10,8,19,11,7,1,8,10,3,3,8,0,8,15,7,8,12,1,8,2,8,3,3,3,3,3,3,3,7,8,12,1,8,0,1,8,3,16,7,8,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,0,2,7,8,3,7,8,12,3,7,8,3,6,8,20,3,3,7,8,3,3,7,8,12,4,7,8,3,11,8,1,8,10,5,7,8,12,1,8,17,5,7,8,3,10,11,8,1,8,10,11,5,1,3,5,7,8,12,3,7,8,3,8,17,7,8,12,1,11,7,1,8,10,3,7,8,3,6,8,20,5,3,8,21,5,7,11,13,2,5,11,14,1,5,3,7,8,3,10,2,6,8,12,4,7,8,3,10,2,10,2,6,8,12,11,7,8,3,3,3,11,7,1,8,10,11,7,1,8,10,3,3,3,3,3,7,8,12,1,6,8,3,1,3,2,6,8,3,5,1,8,9,1,6,11,11,2,8,9,5,1,11,14,1,5,2,7,8,3,6,8,9,1,6,11,11,2,3,8,16,1,10,5,3,10,11,8,1,8,10,11,5,1,3,7,8,12,2,3,8,22,2,10,8,19,7,8,12,1,8,22,1,6,8,22,1,8,18,2,5,11,14,1,5,1,11,13,2,9,0,9,1,1,8,10,1,11,7,1,9,0,1,7,8,12,1,8,6,23,3,3,3,3,3,8,6,8,0,3,3,1,11,7,1,8,10,3,3,11,7,1,8,10,8,15,3,8,6,8,18,3,3,11,13,2,5,11,14,1,5,3,8,22,1,8,19,1,6,8,12,1,5,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,3,7,8,22,8,19,7,8,12,2,7,8,22,7,8,12,3,7,8,22,3,7,8,12,1,6,10,8,19,1,8,21,3,7,8,22,6,8,20,2,3,7,8,22,6,8,21,1,1,7,8,19,3,7,8,19,8,21,3,3,7,8,22,3,6,8,12,2,7,8,22,6,8,12,2,7,8,19,3,1,11,8,1,9,0,4,7,8,22,5,11,7,1,8,10,7,8,12,1,6,8,17,3,7,8,22,8,17,7,8,12,2,6,8,22,5,1,1,4,6,5,6,5,5,7,11,14,1,5,1,6,8,21,1,6,5,2,6,11,13,2,9,0,9,1,6,9,0,1,9,0,1,11,14,1,9,0,3,7,11,13,2,9,0,9,1,9,0,9,1,2,7,11,13,2,9,0,9,1,6,9,0,1,7,9,1,2,6,11,14,1,9,0,6,9,0,2,7,11,14,1,9,0,9,0,2,7,11,14,1,9,0,6,9,0,1,6,11,14,1,9,0,2,9,0,9,1,2,7,8,19,7,8,12,2,7,8,19,10,2,2,7,8,19,6,8,19,2,6,8,22,6,8,19,3,7,8,19,10,2,10,2,44,1,3,3,3,3,3,3,1,1,1,11,7,1,8,10,3,3,3,3,3,3,3,3,4,3,3,3,11,7,1,8,10,3,3,3,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,3,11,7,1,8,10,4,11,7,1,8,10,4,3,3,3,3,4,3,1,7,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,1,6,8,18,1,6,11,7,1,9,0,1,7,8,15,2,7,11,7,1,9,0,3,9,7,8,22,7,11,7,1,8,10,7,11,7,1,8,10,7,11,13,2,5,11,14,1,5,3,3,3,3,7,8,12,6,7,8,18,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,1,8,4,1,6,9,1,2,7,8,22,6,8,9,5,11,7,1,8,10,3,11,7,1,8,10,11,8,1,8,10,11,7,1,8,10,1,11,8,1,8,10,2,7,11,8,1,9,0,10,11,8,1,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,2,11,7,1,9,0,7,8,12,2,9,0,5,3,66,97,103,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,11,83,116,111,114,97,103,101,70,117,110,100,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,20,83,121,115,116,101,109,69,112,111,99,104,73,110,102,111,69,118,101,110,116,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,18,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,86,50,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,6,86,101,99,77,97,112,6,86,101,99,83,101,116,26,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,101,115,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,3,98,97,103,7,98,97,108,97,110,99,101,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,5,101,109,112,116,121,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,24,101,112,111,99,104,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,20,101,120,116,114,97,99,116,95,99,111,105,110,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,3,103,101,116,7,103,101,116,95,109,117,116,16,103,101,116,95,114,101,112,111,114,116,101,114,115,95,111,102,31,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,111,98,106,101,99,116,95,114,101,98,97,116,101,115,30,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,116,111,116,97,108,95,98,97,108,97,110,99,101,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,6,105,110,115,101,114,116,12,105,110,116,111,95,98,97,108,97,110,99,101,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,106,111,105,110,8,106,111,105,110,95,118,101,99,28,108,101,102,116,111,118,101,114,95,115,116,111,114,97,103,101,95,102,117,110,100,95,105,110,102,108,111,119,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,19,109,105,110,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,3,110,101,119,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,114,97,109,101,116,101,114,115,3,112,97,121,19,112,111,111,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,115,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,19,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,21,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,9,115,97,102,101,95,109,111,100,101,29,115,97,102,101,95,109,111,100,101,95,99,111,109,112,117,116,97,116,105,111,110,95,114,101,119,97,114,100,115,36,115,97,102,101,95,109,111,100,101,95,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,115,116,111,114,97,103,101,95,102,101,101,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,119,97,114,100,115,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,9,115,105,110,103,108,101,116,111,110,5,115,112,108,105,116,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,13,115,116,97,107,101,95,115,117,98,115,105,100,121,20,115,116,97,107,101,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,12,115,116,97,107,105,110,103,95,112,111,111,108,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,14,115,116,111,114,97,103,101,95,99,104,97,114,103,101,12,115,116,111,114,97,103,101,95,102,117,110,100,20,115,116,111,114,97,103,101,95,102,117,110,100,95,98,97,108,97,110,99,101,25,115,116,111,114,97,103,101,95,102,117,110,100,95,114,101,105,110,118,101,115,116,109,101,110,116,14,115,116,111,114,97,103,101,95,114,101,98,97,116,101,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,5,116,97,98,108,101,13,116,111,116,97,108,95,98,97,108,97,110,99,101,14,116,111,116,97,108,95,103,97,115,95,102,101,101,115,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,31,116,111,116,97,108,95,115,116,97,107,101,95,114,101,119,97,114,100,115,95,100,105,115,116,114,105,98,117,116,101,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,26,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,24,118,97,108,105,100,97,116,111,114,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,31,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,10,118,97,108,105,100,97,116,111,114,115,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,3,8,1,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,8,39,3,105,3,63,3,65,3,167,1,3,174,1,3,166,1,3,42,8,6,1,2,9,39,3,105,3,64,3,63,3,65,3,167,1,3,174,1,3,166,1,3,42,8,6,2,2,16,38,3,74,3,116,3,175,1,8,22,109,8,18,71,8,0,76,3,168,1,11,13,2,5,11,14,1,5,103,8,15,90,1,94,11,7,1,8,10,91,11,7,1,8,10,93,3,92,3,40,3,42,8,6,3,2,16,38,3,74,3,116,3,175,1,8,22,109,8,18,71,8,1,76,3,168,1,11,13,2,5,11,14,1,5,103,8,15,90,1,94,11,7,1,8,10,91,11,7,1,8,10,93,3,92,3,40,3,42,8,6,4,2,12,38,3,74,3,76,3,121,3,111,3,108,3,112,3,110,3,104,3,119,3,122,3,62,3,0,3,0,0,30,27,11,0,10,6,17,119,12,8,14,8,17,114,12,7,6,0,0,0,0,0,0,0,0,11,2,17,41,11,8,11,1,17,83,11,4,11,7,56,0,11,5,9,56,1,56,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,3,11,6,17,54,18,2,2,1,3,0,0,6,11,11,0,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,54,18,0,2,2,3,0,0,41,55,11,0,19,2,12,17,12,3,12,12,12,13,12,11,12,14,12,10,12,15,12,21,12,9,12,7,12,18,12,23,1,12,8,12,1,11,7,19,0,12,6,12,19,12,22,12,20,12,5,12,4,12,16,12,2,11,1,11,8,6,2,0,0,0,0,0,0,0,11,23,11,18,11,2,11,16,6,4,0,0,0,0,0,0,0,11,4,11,5,11,20,11,22,11,19,11,6,18,1,11,9,11,21,11,15,11,10,11,14,11,11,11,13,11,12,11,3,11,17,18,3,2,3,3,0,0,42,26,10,15,46,17,67,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,10,15,17,86,12,16,11,0,15,0,11,16,11,15,17,124,2,4,3,0,0,6,5,11,0,15,0,11,1,17,126,2,5,3,0,0,6,25,10,0,16,0,17,120,10,0,16,1,16,2,20,35,4,10,5,16,11,0,1,11,1,1,7,3,39,10,0,15,0,11,0,16,1,16,3,20,11,1,17,123,2,6,3,0,0,6,31,10,0,16,0,17,111,65,42,10,0,16,1,16,4,20,38,4,26,10,0,16,0,17,120,10,0,16,1,16,4,20,36,4,20,5,26,11,0,1,11,1,1,7,3,39,11,0,15,0,11,1,17,125,2,7,3,0,0,50,15,10,0,15,0,11,1,7,1,17,133,1,12,3,11,0,15,0,14,3,9,17,117,11,3,11,2,17,88,2,8,3,0,0,50,15,10,0,15,0,11,1,7,2,17,133,1,12,3,11,0,15,0,14,3,8,17,117,11,3,11,2,17,90,2,9,3,0,0,6,7,11,0,15,0,11,1,11,2,46,17,127,2,10,3,0,0,6,8,11,0,15,0,11,2,46,17,116,11,1,17,89,2,11,3,0,0,6,8,11,0,15,0,11,2,11,1,56,2,11,3,17,122,2,12,3,0,0,14,12,11,1,11,2,10,4,17,51,12,5,11,0,15,0,11,3,11,5,11,4,17,122,2,13,3,0,0,6,20,14,1,17,81,10,2,46,17,66,37,4,8,5,14,11,0,1,11,2,1,7,9,39,11,0,15,0,11,1,11,2,17,128,1,2,14,3,0,0,6,22,10,0,16,0,10,2,17,118,4,6,5,12,11,0,1,11,1,1,7,4,39,10,0,15,0,11,1,7,0,17,133,1,11,2,11,0,15,5,17,16,2,15,3,0,0,6,10,10,0,15,0,11,1,7,0,17,133,1,11,2,11,0,15,5,17,17,2,16,0,0,0,64,46,14,0,17,109,20,12,5,10,5,10,1,34,4,9,5,13,11,2,1,7,6,39,10,2,14,1,12,3,46,11,3,56,3,32,4,27,11,2,11,1,11,5,56,4,56,5,5,45,11,2,14,1,56,6,12,6,10,6,14,5,12,4,46,11,4,56,7,32,4,43,11,6,11,5,56,8,5,45,11,6,1,2,17,0,0,0,64,50,10,2,14,1,12,3,46,11,3,56,3,4,8,5,12,11,2,1,7,7,39,10,2,14,1,56,6,12,6,14,0,17,109,20,12,5,10,6,14,5,12,4,46,11,4,56,7,4,28,5,34,11,2,1,11,6,1,7,7,39,10,6,14,5,56,9,11,6,46,56,10,4,47,11,2,14,1,56,11,1,1,5,49,11,2,1,2,18,3,0,0,6,8,11,0,15,0,10,1,46,17,116,11,1,17,87,2,19,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,100,2,20,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,98,2,21,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,99,2,22,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,108,2,23,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,101,11,3,46,12,4,11,0,16,0,11,4,17,113,2,24,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,91,2,25,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,103,11,3,46,12,4,11,0,16,0,11,4,17,113,2,26,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,93,2,27,3,0,0,6,7,11,0,15,0,11,2,17,115,11,1,17,104,2,28,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,94,2,29,3,0,0,6,7,11,0,15,0,11,2,17,115,11,1,17,106,2,30,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,96,2,31,3,0,0,80,17,10,0,15,0,11,3,17,115,12,4,10,4,11,1,11,2,17,105,11,4,46,12,5,11,0,16,0,11,5,17,113,2,32,3,0,0,6,8,11,0,15,0,11,3,17,116,11,1,11,2,17,95,2,33,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,107,11,3,46,12,4,11,0,16,0,11,4,17,113,2,34,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,97,2,35,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,102,11,3,46,12,4,11,0,16,0,11,4,17,113,2,36,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,92,2,37,3,0,0,83,220,2,10,0,16,6,20,12,37,10,9,10,0,15,6,21,7,12,52,12,28,10,7,10,28,37,4,20,10,8,11,28,37,12,11,5,22,9,12,11,11,11,4,25,5,31,11,0,1,11,10,1,7,8,39,10,0,16,1,16,7,20,6,0,0,0,0,0,0,0,0,36,4,43,6,20,0,0,0,0,0,0,0,10,0,15,1,15,7,21,10,0,15,8,56,12,12,40,13,3,11,40,56,13,1,10,0,15,9,56,12,12,39,13,4,11,39,56,13,1,11,5,10,0,16,10,20,22,12,5,6,0,0,0,0,0,0,0,0,10,0,15,10,21,11,6,10,0,16,11,20,22,12,6,6,0,0,0,0,0,0,0,0,10,0,15,11,21,10,0,16,0,17,130,1,12,54,10,0,16,12,17,84,12,44,10,44,11,54,22,12,52,14,3,56,14,12,43,14,4,56,14,12,29,10,10,46,17,66,10,0,16,1,16,7,20,38,4,116,11,9,11,37,10,0,16,1,16,13,20,22,38,12,20,5,118,9,12,20,11,20,4,125,10,0,15,14,17,80,12,21,5,127,56,1,12,21,11,21,12,41,14,41,56,14,12,42,13,4,11,41,56,13,1,11,52,53,12,53,10,29,53,12,30,11,44,53,11,30,24,11,53,26,12,48,13,4,10,48,52,56,15,12,47,11,48,11,7,53,24,7,12,26,12,46,13,47,10,46,52,56,15,12,45,10,0,16,15,20,6,1,0,0,0,0,0,0,0,22,10,0,15,15,21,11,1,10,0,16,15,20,33,4,181,1,5,187,1,11,0,1,11,10,1,7,11,39,14,4,56,14,12,32,14,47,56,14,12,50,10,0,15,0,13,4,13,47,10,0,15,5,11,8,10,0,16,1,16,16,20,10,0,16,1,16,17,20,10,0,16,1,16,18,20,11,10,17,112,10,0,16,0,17,130,1,12,36,14,4,56,14,12,31,14,47,56,14,12,49,11,32,11,31,23,12,33,11,50,11,49,23,12,51,11,2,10,0,15,19,21,10,0,16,0,17,114,10,0,15,20,21,11,47,12,34,13,34,11,4,56,13,1,14,34,56,14,12,35,10,0,15,12,11,3,11,45,11,34,10,5,11,6,17,82,12,38,10,0,16,15,20,12,22,10,0,16,19,20,12,23,10,0,16,20,20,12,24,11,36,12,25,11,43,12,26,11,46,52,12,27,11,5,12,12,10,0,16,12,17,84,12,13,11,42,12,14,11,29,12,15,11,33,11,51,22,12,16,11,35,12,17,11,22,11,23,11,24,11,25,11,27,11,26,11,12,11,13,11,14,11,15,11,16,11,17,18,4,56,16,9,10,0,15,21,21,10,0,16,10,20,6,0,0,0,0,0,0,0,0,33,4,198,2,10,0,16,8,56,14,6,0,0,0,0,0,0,0,0,33,12,18,5,200,2,9,12,18,11,18,4,209,2,11,0,16,9,56,14,6,0,0,0,0,0,0,0,0,33,12,19,5,213,2,11,0,1,9,12,19,11,19,4,216,2,5,218,2,7,10,39,11,38,2,38,3,0,0,6,4,11,0,16,15,20,2,39,3,0,0,6,4,11,0,16,19,20,2,40,3,0,0,6,4,11,0,16,22,20,2,41,3,0,0,6,2,7,3,2,42,3,0,0,6,4,11,0,16,6,20,2,43,3,0,0,6,5,11,0,16,0,11,1,17,132,1,2,44,3,0,0,6,5,11,0,16,0,11,1,17,131,1,2,45,3,0,0,6,4,11,0,16,0,17,129,1,2,46,3,0,0,25,18,10,0,16,5,14,1,56,3,4,12,11,0,16,5,14,1,56,17,20,12,2,5,16,11,0,1,56,18,12,2,11,2,2,47,3,0,0,6,4,11,0,16,12,17,84,2,48,3,0,0,6,4,11,0,16,12,17,85,2,49,3,0,0,6,5,11,0,15,0,11,1,17,121,2,50,3,0,0,6,4,11,0,16,0,17,110,2,51,0,0,0,95,45,13,0,69,96,12,6,13,6,11,0,56,19,11,6,56,2,12,7,14,1,56,20,4,39,11,1,56,21,12,4,13,7,11,4,56,15,12,5,14,7,56,14,6,0,0,0,0,0,0,0,0,36,4,32,11,7,10,2,56,22,11,2,46,17,67,56,23,5,36,11,2,1,11,7,56,24,11,5,12,3,5,43,11,2,1,11,7,12,3,11,3,2,3,3,3,5,1,3,1,4,1,2,3,7,3,14,1,1,3,10,3,11,3,12,3,13,3,4,1,0,3,8,3,0,1,5,1,6,1,7,3,1,3,6,3,9,3,2,0,45,0,114,0],"validator":[161,28,235,11,6,0,0,0,12,1,0,33,2,33,72,3,105,197,4,4,174,5,40,5,214,5,131,4,7,217,9,247,19,8,208,29,96,6,176,30,190,1,10,238,31,156,1,12,138,33,237,27,13,247,60,60,15,179,61,13,0,137,1,1,20,1,23,1,74,1,105,2,21,2,22,2,34,2,72,2,106,2,113,2,114,2,134,1,0,103,0,139,1,0,14,4,0,0,13,4,0,0,8,3,0,0,11,3,0,1,9,7,0,3,3,7,1,0,0,4,9,7,0,5,0,12,0,6,1,4,1,0,1,8,2,7,0,9,5,2,0,11,10,2,0,12,12,7,0,13,4,7,0,13,6,12,0,13,7,12,0,14,15,2,0,0,56,0,1,0,0,54,2,3,0,0,26,4,5,0,0,16,4,5,0,0,18,6,5,0,0,88,7,8,0,0,89,7,5,0,0,92,9,10,0,0,91,11,5,0,0,96,11,5,0,0,90,4,5,0,0,95,4,5,0,0,29,12,5,0,0,83,13,5,0,0,47,14,15,0,0,49,14,16,0,0,107,14,17,0,0,50,14,18,0,0,30,14,18,0,0,42,14,19,0,0,84,14,19,0,0,52,14,18,0,0,75,14,18,0,0,80,14,18,0,0,145,1,14,18,0,0,86,14,20,0,0,85,14,20,0,0,53,14,20,0,0,146,1,14,20,0,0,62,14,21,0,0,64,14,21,0,0,65,14,21,0,0,69,14,21,0,0,67,14,22,0,0,66,14,22,0,0,63,14,22,0,0,70,14,22,0,0,73,14,23,0,0,60,14,24,0,0,112,14,24,0,0,100,14,24,0,0,111,14,24,0,0,144,1,14,24,0,0,97,4,5,0,0,76,14,24,0,0,77,14,24,0,0,38,14,24,0,0,25,14,24,0,0,79,25,26,0,0,104,14,27,0,0,43,28,15,0,0,45,29,15,1,0,0,44,30,15,1,0,0,58,13,5,0,0,125,31,5,0,0,123,31,5,0,0,124,31,5,0,0,133,1,31,5,0,0,126,31,5,0,0,116,31,5,0,0,128,1,31,5,0,0,118,31,5,0,0,129,1,31,5,0,0,119,31,5,0,0,131,1,31,5,0,0,121,31,5,0,0,130,1,32,5,0,0,120,32,5,0,0,127,31,5,0,0,117,31,5,0,0,132,1,31,5,0,0,122,31,5,0,0,31,6,5,0,0,135,1,16,5,0,0,136,1,33,5,0,0,40,14,34,0,0,55,35,3,0,1,105,33,41,0,2,110,65,33,1,0,3,24,67,65,1,0,3,36,70,53,1,0,3,46,67,15,1,0,3,48,67,15,1,0,3,71,5,37,1,0,3,98,53,37,1,0,4,37,41,38,0,5,54,43,44,0,6,142,1,48,24,1,0,7,32,53,5,1,3,8,41,65,27,1,8,10,87,54,5,1,12,11,33,49,24,0,11,94,49,17,0,12,57,33,42,0,13,17,45,5,0,13,27,45,5,0,13,28,61,5,0,13,47,34,15,0,13,54,43,64,0,13,76,34,24,0,13,77,34,24,0,13,79,63,26,0,13,82,51,5,0,13,83,62,5,0,13,88,50,8,0,13,92,57,10,0,13,99,56,24,0,13,101,56,24,0,13,108,34,24,0,14,58,69,27,0,14,143,1,59,60,0,83,33,83,38,87,47,88,52,90,8,88,58,89,64,52,38,52,33,51,38,51,33,81,53,79,53,84,38,84,33,82,38,80,38,82,33,80,33,78,1,14,5,10,2,10,2,10,2,10,2,8,6,8,6,8,12,8,12,8,6,8,6,8,6,8,6,8,7,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,11,1,8,1,2,7,8,1,3,0,1,7,8,1,4,7,8,1,11,8,1,8,10,5,7,8,11,1,8,14,3,7,8,1,8,14,7,8,11,1,11,8,1,8,10,3,7,8,1,8,16,3,2,7,8,1,11,8,1,8,10,2,7,8,1,7,8,11,1,6,8,1,1,1,1,6,8,0,1,5,1,6,8,6,1,6,8,12,1,6,10,2,1,6,11,5,1,8,6,1,6,11,5,1,10,2,1,6,8,9,1,3,2,6,8,1,3,1,8,13,1,8,9,2,6,8,1,6,8,1,2,6,11,5,1,9,0,6,9,0,2,6,11,5,1,9,0,6,11,5,1,9,0,2,7,8,1,10,2,3,7,8,1,10,2,10,2,1,10,2,1,6,8,15,4,8,0,3,3,7,8,11,22,5,8,6,8,6,8,6,8,6,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,8,6,11,5,1,8,6,10,2,11,5,1,8,6,11,5,1,8,6,8,7,10,2,10,2,10,2,8,6,8,6,8,12,8,12,1,11,5,1,9,0,1,8,6,8,1,1,1,1,1,1,1,8,0,1,2,1,8,4,1,8,12,1,7,8,11,1,8,7,2,7,8,15,3,3,3,3,8,14,1,8,10,1,6,11,8,1,9,0,1,6,8,11,4,7,8,15,11,8,1,8,10,3,7,8,11,1,7,8,15,1,8,2,1,9,0,2,9,0,5,5,3,3,3,3,11,8,1,8,10,1,6,8,14,3,7,8,15,8,14,7,8,11,1,8,3,1,6,8,16,1,6,5,2,7,8,15,11,8,1,8,10,2,7,8,15,7,8,11,2,6,8,15,3,1,8,15,1,6,9,0,29,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,6,11,5,1,9,0,2,1,1,2,5,7,8,11,1,7,11,5,1,9,0,3,8,9,8,15,5,3,66,97,103,7,66,97,108,97,110,99,101,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,19,83,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,21,85,110,115,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,3,85,114,108,9,86,97,108,105,100,97,116,111,114,17,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,8,97,99,116,105,118,97,116,101,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,6,97,109,111,117,110,116,5,97,115,99,105,105,3,98,97,103,7,98,97,108,97,110,99,101,3,98,99,115,6,98,111,114,114,111,119,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,10,100,101,97,99,116,105,118,97,116,101,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,11,100,101,115,99,114,105,112,116,105,111,110,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,5,101,112,111,99,104,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,10,102,114,111,109,95,97,115,99,105,105,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,20,103,101,116,95,115,116,97,107,105,110,103,95,112,111,111,108,95,114,101,102,2,105,100,9,105,109,97,103,101,95,117,114,108,12,105,115,95,100,117,112,108,105,99,97,116,101,13,105,115,95,101,113,117,97,108,95,115,111,109,101,23,105,115,95,101,113,117,97,108,95,115,111,109,101,95,97,110,100,95,118,97,108,117,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,8,109,101,116,97,100,97,116,97,4,110,97,109,101,11,110,101,116,95,97,100,100,114,101,115,115,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,20,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,102,114,111,109,95,109,101,116,97,100,97,116,97,12,110,101,119,95,109,101,116,97,100,97,116,97,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,20,110,101,120,116,95,101,112,111,99,104,95,103,97,115,95,112,114,105,99,101,22,110,101,120,116,95,101,112,111,99,104,95,110,101,116,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,22,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,32,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,16,110,101,120,116,95,101,112,111,99,104,95,115,116,97,107,101,25,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,7,112,111,111,108,95,105,100,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,16,112,114,105,110,99,105,112,97,108,95,97,109,111,117,110,116,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,21,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,13,114,101,119,97,114,100,95,97,109,111,117,110,116,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,111,109,101,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,12,115,116,97,107,101,95,97,109,111,117,110,116,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,14,115,116,97,107,101,114,95,97,100,100,114,101,115,115,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,6,115,116,114,105,110,103,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,11,115,117,105,95,98,97,108,97,110,99,101,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,111,95,98,121,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,15,117,110,115,116,97,107,105,110,103,95,101,112,111,99,104,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,3,117,114,108,17,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,21,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,95,98,99,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,12,118,111,116,105,110,103,95,112,111,119,101,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,19,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,100,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,3,8,102,0,0,0,0,0,0,0,3,8,208,7,0,0,0,0,0,0,3,8,0,1,0,0,0,0,0,0,3,8,160,134,1,0,0,0,0,0,0,2,22,107,5,86,10,2,53,10,2,146,1,10,2,85,10,2,50,8,6,30,8,6,42,8,12,84,8,12,51,8,6,75,8,6,80,8,6,145,1,8,6,67,11,5,1,10,2,66,11,5,1,10,2,63,11,5,1,10,2,70,11,5,1,10,2,61,11,5,1,8,6,64,11,5,1,8,6,65,11,5,1,8,6,69,11,5,1,8,6,35,8,7,1,2,10,49,8,0,144,1,3,73,8,9,38,3,103,8,15,25,3,68,3,60,3,59,3,35,8,7,2,2,5,78,8,9,138,1,5,102,5,33,3,19,3,3,2,7,78,8,9,138,1,5,102,5,99,3,115,3,81,3,93,3,0,3,0,0,36,68,11,0,12,14,11,1,12,25,11,2,12,29,11,3,12,30,11,4,12,31,11,5,12,32,11,6,12,33,11,7,12,34,11,8,12,35,11,9,12,15,11,10,12,16,11,11,12,17,11,12,12,18,56,0,12,19,56,0,12,20,56,0,12,21,56,0,12,22,56,1,12,23,56,1,12,24,56,1,12,26,56,1,12,27,11,13,12,28,11,14,11,25,11,29,11,30,11,31,11,32,11,33,11,34,11,35,11,15,11,16,11,17,11,18,11,19,11,22,11,20,11,21,11,23,11,24,11,26,11,27,11,28,18,0,2,1,3,0,0,39,137,1,14,9,65,40,7,17,37,4,11,14,10,65,40,7,17,37,12,16,5,13,9,12,16,11,16,4,21,14,11,65,40,7,17,37,12,17,5,23,9,12,17,11,17,4,31,14,12,65,40,7,17,37,12,18,5,33,9,12,18,11,18,4,41,14,5,65,40,7,17,37,12,19,5,43,9,12,19,11,19,4,51,14,6,65,40,7,17,37,12,20,5,53,9,12,20,11,20,4,61,14,7,65,40,7,17,37,12,21,5,63,9,12,21,11,21,4,71,14,8,65,40,7,17,37,12,22,5,73,9,12,22,11,22,4,76,5,80,11,15,1,7,9,39,10,14,7,16,37,4,85,5,89,11,15,1,7,8,39,10,13,7,18,35,4,94,5,98,11,15,1,7,15,39,11,0,11,1,11,2,11,3,11,4,11,5,17,77,17,85,11,6,17,77,17,85,11,7,17,93,11,8,17,93,11,9,17,77,17,85,11,10,17,77,17,85,11,11,17,77,17,85,11,12,17,77,17,85,10,15,17,86,17,0,12,23,14,23,17,73,11,23,11,13,11,14,11,15,17,76,2,2,3,0,0,5,5,11,0,15,0,11,1,17,95,2,3,3,0,0,5,5,11,0,15,0,11,1,17,94,2,4,3,0,0,5,13,10,0,16,1,20,10,0,15,2,21,10,0,16,3,20,11,0,15,4,21,2,5,3,0,0,46,58,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,8,5,14,11,0,1,11,3,1,7,11,39,10,3,46,17,91,6,1,0,0,0,0,0,0,0,22,12,5,10,0,15,0,11,1,11,5,10,3,17,104,12,6,10,0,16,0,17,97,4,34,10,0,15,0,17,102,10,0,16,5,20,10,4,22,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,11,2,11,3,46,17,91,11,4,18,2,56,3,11,6,2,6,3,0,0,24,47,10,3,46,17,91,6,0,0,0,0,0,0,0,0,33,4,7,5,13,11,0,1,11,3,1,7,12,39,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,21,5,27,11,0,1,11,3,1,7,11,39,10,0,15,0,11,1,6,0,0,0,0,0,0,0,0,11,3,17,104,11,2,56,4,10,0,15,0,17,102,10,0,16,5,20,11,4,22,11,0,15,5,21,2,7,3,0,0,55,47,14,1,17,107,12,3,14,1,17,106,12,5,10,0,15,0,11,1,10,2,17,105,12,7,14,7,56,2,12,6,10,6,10,3,23,12,4,10,0,16,5,20,11,6,23,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,10,2,46,17,92,11,5,11,2,46,17,91,11,3,11,4,18,3,56,5,11,7,2,8,3,0,0,5,28,10,2,7,18,35,4,5,5,9,11,0,1,7,15,39,14,1,17,110,20,10,0,16,6,16,7,20,33,4,19,5,23,11,0,1,7,14,39,11,2,11,0,15,1,21,2,9,3,0,0,5,41,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,2,7,18,35,4,14,5,18,11,0,1,7,15,39,14,1,17,110,20,10,0,16,6,16,7,20,33,4,28,5,32,11,0,1,7,14,39,10,2,10,0,15,1,21,11,2,11,0,15,2,21,2,10,3,0,0,5,14,10,1,7,16,37,4,5,5,9,11,0,1,7,8,39,11,1,11,0,15,3,21,2,11,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,1,7,16,37,4,14,5,18,11,0,1,7,8,39,11,1,11,0,15,4,21,2,12,3,0,0,5,14,10,0,16,5,20,14,1,56,2,22,10,0,15,5,21,11,0,15,0,11,1,17,96,2,13,3,0,0,5,16,10,0,15,0,11,1,17,103,10,0,46,17,40,11,0,16,5,20,33,4,13,5,15,7,11,39,2,14,1,0,0,5,4,11,0,16,0,17,97,2,15,1,0,0,5,3,11,0,16,6,2,16,1,0,0,5,5,11,0,16,6,16,7,20,2,17,1,0,0,5,4,11,0,16,6,16,8,2,18,1,0,0,5,4,11,0,16,6,16,9,2,19,1,0,0,5,4,11,0,16,6,16,10,2,20,1,0,0,5,4,11,0,16,6,16,11,2,21,1,0,0,5,4,11,0,16,6,16,12,2,22,1,0,0,5,4,11,0,16,6,16,13,2,23,1,0,0,5,4,11,0,16,6,16,14,2,24,1,0,0,5,4,11,0,16,6,16,15,2,25,1,0,0,5,4,11,0,16,6,16,16,2,26,1,0,0,5,4,11,0,16,6,16,17,2,27,1,0,0,5,4,11,0,16,6,16,18,2,28,1,0,0,5,4,11,0,16,6,16,19,2,29,1,0,0,5,4,11,0,16,6,16,20,2,30,1,0,0,5,4,11,0,16,6,16,21,2,31,1,0,0,5,4,11,0,16,6,16,22,2,32,1,0,0,5,4,11,0,16,6,16,23,2,33,1,0,0,5,4,11,0,16,6,16,24,2,34,1,0,0,5,4,11,0,16,6,16,25,2,35,1,0,0,5,4,11,0,16,6,16,26,2,36,1,0,0,5,4,11,0,16,6,16,27,2,37,1,0,0,5,3,11,0,16,28,2,38,1,0,0,5,4,11,0,16,1,20,2,39,1,0,0,5,5,40,11,0,16,0,17,108,2,40,1,0,0,5,4,11,0,16,0,17,108,2,41,1,0,0,5,3,11,0,17,40,2,42,1,0,0,5,4,11,0,16,29,20,2,43,3,0,0,5,5,11,1,11,0,15,29,21,2,44,1,0,0,5,4,11,0,16,0,17,99,2,45,1,0,0,5,4,11,0,16,0,17,100,2,46,1,0,0,5,4,11,0,16,2,20,2,47,1,0,0,5,4,11,0,16,4,20,2,48,1,0,0,5,5,11,0,16,0,11,1,17,101,2,49,1,0,0,5,4,11,0,16,0,56,6,2,50,1,0,0,66,151,3,10,0,16,6,16,7,20,10,1,16,6,16,7,20,33,4,13,8,12,2,5,23,10,0,16,6,16,8,20,10,1,16,6,16,8,20,33,12,2,11,2,4,28,8,12,13,5,38,10,0,16,6,16,12,20,10,1,16,6,16,12,20,33,12,13,11,13,4,43,8,12,24,5,53,10,0,16,6,16,13,20,10,1,16,6,16,13,20,33,12,24,11,24,4,58,8,12,25,5,68,10,0,16,6,16,16,20,10,1,16,6,16,16,20,33,12,25,11,25,4,73,8,12,26,5,83,10,0,16,6,16,18,20,10,1,16,6,16,18,20,33,12,26,11,26,4,88,8,12,27,5,98,10,0,16,6,16,18,20,10,1,16,6,16,19,20,33,12,27,11,27,4,103,8,12,28,5,113,10,0,16,6,16,19,20,10,1,16,6,16,19,20,33,12,28,11,28,4,118,8,12,29,5,128,1,10,0,16,6,16,19,20,10,1,16,6,16,18,20,33,12,29,11,29,4,133,1,8,12,30,5,141,1,10,0,16,6,16,20,10,1,16,6,16,20,56,7,12,30,11,30,4,146,1,8,12,3,5,154,1,10,0,16,6,16,21,10,1,16,6,16,21,56,7,12,3,11,3,4,159,1,8,12,4,5,167,1,10,0,16,6,16,24,10,1,16,6,16,24,56,8,12,4,11,4,4,172,1,8,12,5,5,180,1,10,0,16,6,16,26,10,1,16,6,16,26,56,8,12,5,11,5,4,185,1,8,12,6,5,193,1,10,0,16,6,16,26,10,1,16,6,16,27,56,8,12,6,11,6,4,198,1,8,12,7,5,206,1,10,0,16,6,16,27,10,1,16,6,16,27,56,8,12,7,11,7,4,211,1,8,12,8,5,219,1,10,0,16,6,16,27,10,1,16,6,16,26,56,8,12,8,11,8,4,224,1,8,12,9,5,232,1,10,0,16,6,16,20,10,1,16,6,16,12,56,9,12,9,11,9,4,237,1,8,12,10,5,245,1,10,0,16,6,16,21,10,1,16,6,16,13,56,9,12,10,11,10,4,250,1,8,12,11,5,130,2,10,0,16,6,16,24,10,1,16,6,16,16,56,10,12,11,11,11,4,135,2,8,12,12,5,143,2,10,0,16,6,16,26,10,1,16,6,16,18,56,10,12,12,11,12,4,148,2,8,12,14,5,156,2,10,0,16,6,16,26,10,1,16,6,16,19,56,10,12,14,11,14,4,161,2,8,12,15,5,169,2,10,0,16,6,16,27,10,1,16,6,16,19,56,10,12,15,11,15,4,174,2,8,12,16,5,182,2,10,0,16,6,16,27,10,1,16,6,16,18,56,10,12,16,11,16,4,187,2,8,12,17,5,195,2,10,1,16,6,16,20,10,0,16,6,16,12,56,9,12,17,11,17,4,200,2,8,12,18,5,208,2,10,1,16,6,16,21,10,0,16,6,16,13,56,9,12,18,11,18,4,213,2,8,12,19,5,221,2,10,1,16,6,16,24,10,0,16,6,16,16,56,10,12,19,11,19,4,226,2,8,12,20,5,234,2,10,1,16,6,16,26,10,0,16,6,16,18,56,10,12,20,11,20,4,239,2,8,12,21,5,247,2,10,1,16,6,16,26,10,0,16,6,16,19,56,10,12,21,11,21,4,252,2,8,12,22,5,132,3,10,1,16,6,16,27,10,0,16,6,16,19,56,10,12,22,11,22,4,141,3,11,0,1,11,1,1,8,12,23,5,149,3,11,1,16,6,16,27,11,0,16,6,16,18,56,10,12,23,11,23,2,51,0,0,0,15,17,10,0,56,11,4,10,11,1,1,11,0,1,9,12,2,5,15,11,0,56,12,11,1,33,12,2,11,2,2,52,0,0,0,68,26,10,0,56,11,4,6,8,12,2,5,9,10,1,56,11,12,2,11,2,4,18,11,1,1,11,0,1,9,12,3,5,24,11,0,56,12,11,1,56,12,33,12,3,11,3,2,53,3,0,0,17,25,10,1,46,17,92,12,2,10,2,10,0,16,6,16,7,20,33,4,12,5,18,11,0,1,11,1,1,7,13,39,11,2,11,1,17,109,11,0,15,28,21,2,54,3,0,0,5,18,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,11,0,15,6,15,8,21,2,55,3,0,0,5,18,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,11,0,15,6,15,9,21,2,56,3,0,0,5,17,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,93,11,0,15,6,15,10,21,2,57,3,0,0,5,17,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,93,11,0,15,6,15,11,21,2,58,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,20,21,11,0,16,6,17,73,2,59,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,12,21,11,0,16,6,17,73,2,60,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,21,21,11,0,16,6,17,73,2,61,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,13,21,11,0,16,6,17,73,2,62,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,22,21,11,0,16,6,17,73,2,63,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,14,21,11,0,16,6,17,73,2,64,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,23,21,11,0,16,6,17,73,2,65,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,15,21,11,0,16,6,17,73,2,66,3,0,0,5,16,11,1,56,14,10,0,15,6,15,24,21,11,2,56,14,10,0,15,6,15,25,21,11,0,16,6,17,73,2,67,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,16,21,11,2,10,0,15,6,15,17,21,11,0,16,6,17,73,2,68,3,0,0,5,10,11,1,56,14,10,0,15,6,15,26,21,11,0,16,6,17,73,2,69,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,18,21,11,0,16,6,17,73,2,70,3,0,0,5,10,11,1,56,14,10,0,15,6,15,27,21,11,0,16,6,17,73,2,71,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,19,21,11,0,16,6,17,73,2,72,3,0,0,5,143,1,10,0,46,17,29,56,15,4,18,10,0,15,6,15,20,56,16,10,0,15,6,15,12,21,56,1,10,0,15,6,15,20,21,10,0,46,17,30,56,15,4,36,10,0,15,6,15,21,56,16,10,0,15,6,15,13,21,56,1,10,0,15,6,15,21,21,10,0,46,17,31,56,15,4,54,10,0,15,6,15,22,56,16,10,0,15,6,15,14,21,56,1,10,0,15,6,15,22,21,10,0,46,17,32,56,15,4,72,10,0,15,6,15,23,56,16,10,0,15,6,15,15,21,56,1,10,0,15,6,15,23,21,10,0,46,17,33,56,17,4,103,10,0,15,6,15,24,56,18,10,0,15,6,15,16,21,56,0,10,0,15,6,15,24,21,10,0,15,6,15,25,56,18,10,0,15,6,15,17,21,56,0,10,0,15,6,15,25,21,10,0,46,17,35,56,17,4,121,10,0,15,6,15,26,56,18,10,0,15,6,15,18,21,56,0,10,0,15,6,15,26,21,10,0,46,17,36,56,17,4,140,1,10,0,15,6,15,27,56,18,10,0,15,6,15,19,21,56,0,11,0,15,6,15,27,21,5,142,1,11,0,1,2,73,1,0,0,5,4,11,0,56,19,17,74,2,74,1,2,0,75,3,0,0,5,3,11,0,16,0,2,76,0,0,0,71,24,14,0,16,7,20,12,6,10,3,17,98,12,5,11,6,10,3,17,109,12,4,11,0,6,0,0,0,0,0,0,0,0,11,4,10,1,11,5,10,2,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,17,86,18,1,2,1,4,1,7,1,3,1,8,1,5,1,6,1,0,0,0,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,1,0,4,0,2,0,3,0,17,0,18,0,19,0,20,0,13,0,14,0,15,0,16,1,2,1,1,0,39,0,109,0,140,1,0,141,1,0,144,1,0],"validator_cap":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,20,3,28,42,4,70,4,5,74,54,7,128,1,226,2,8,226,3,64,6,162,4,34,10,196,4,13,12,209,4,112,13,193,5,4,15,197,5,6,0,18,1,10,1,14,1,15,0,3,12,0,0,4,2,0,1,0,7,0,1,2,4,0,3,1,2,0,0,16,0,1,0,0,20,2,1,0,0,9,3,4,0,0,8,0,5,0,1,6,13,4,1,8,1,7,10,11,0,2,11,14,6,1,12,3,12,8,9,0,4,12,6,12,1,6,8,0,1,6,5,1,6,8,1,2,5,7,8,4,1,8,2,1,8,1,0,4,1,8,0,8,2,5,1,6,8,4,1,5,1,7,8,4,1,8,3,1,8,0,1,6,9,0,2,9,0,5,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,28,97,117,116,104,111,114,105,122,101,114,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,6,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,3,5,5,1,2,1,5,5,0,3,0,0,6,3,11,0,16,0,2,1,3,0,0,6,3,11,0,16,1,2,2,3,0,0,7,35,10,1,46,17,7,12,5,10,5,7,0,33,4,11,8,12,2,5,15,11,5,10,0,33,12,2,11,2,4,18,5,22,11,1,1,6,0,0,0,0,0,0,0,0,39,11,1,17,5,10,0,18,0,12,3,14,3,56,0,12,4,11,3,11,0,56,1,11,4,2,3,3,0,0,6,5,11,0,16,0,20,18,1,2,0,1,1,0,0,13,0,17,0,19,0],"validator_set":[161,28,235,11,6,0,0,0,12,1,0,54,2,54,116,3,170,1,173,6,4,215,7,137,1,5,224,8,136,10,7,232,18,175,24,8,151,43,96,6,247,43,195,1,10,186,45,141,1,12,199,46,159,36,13,230,82,16,15,246,82,5,0,166,1,1,107,1,174,1,2,32,2,33,2,59,2,105,2,118,2,147,1,2,151,1,2,152,1,2,158,1,2,159,1,2,172,1,2,173,1,0,143,1,0,162,1,0,165,1,0,170,1,0,177,1,0,20,4,0,0,15,3,0,0,16,3,0,0,17,3,0,0,18,3,0,1,4,7,1,0,0,3,0,12,0,4,1,4,1,0,1,6,3,7,0,7,2,6,1,2,0,7,6,6,1,2,0,8,7,2,0,9,10,12,2,7,1,4,1,10,11,4,1,4,1,12,12,2,0,13,22,7,2,1,0,0,0,14,23,7,1,3,0,15,5,7,0,15,8,12,0,15,9,12,0,16,14,4,0,17,13,12,0,17,19,2,0,18,21,4,0,0,100,0,1,0,0,130,1,2,3,0,0,132,1,4,3,0,0,129,1,5,3,0,0,30,6,3,0,0,131,1,4,3,0,0,128,1,7,8,0,0,134,1,9,10,0,0,133,1,11,3,0,0,29,12,3,0,0,161,1,13,3,0,0,54,14,3,0,0,49,15,16,0,0,155,1,15,16,0,0,169,1,17,16,0,0,167,1,17,16,0,0,168,1,17,18,0,0,145,1,15,19,0,0,110,20,21,0,0,103,15,16,0,0,85,17,22,0,0,88,6,22,0,0,87,23,22,0,0,45,23,16,0,0,89,6,22,0,0,44,24,16,0,0,71,25,26,0,0,63,27,28,0,0,64,29,28,0,0,75,30,31,0,0,76,32,26,0,0,68,33,26,0,0,79,34,26,0,0,77,35,26,0,0,78,35,26,0,0,80,27,36,0,0,69,37,36,0,0,70,17,36,0,0,73,17,36,0,0,176,1,38,39,0,0,119,40,3,0,0,122,41,3,0,0,37,42,3,0,0,121,43,3,0,0,139,1,44,3,0,0,120,45,3,0,0,36,46,16,0,0,28,47,3,0,0,40,48,49,0,0,41,50,51,0,0,42,52,53,0,0,39,54,53,0,0,53,55,3,0,0,56,56,3,0,0,150,1,30,16,0,0,26,15,46,0,0,94,17,22,0,0,91,57,22,0,0,25,15,51,0,1,51,118,85,1,0,1,62,84,85,1,0,1,93,83,22,1,0,1,104,3,118,1,0,1,138,1,85,118,1,0,2,43,86,22,1,0,2,90,132,1,22,1,0,2,127,102,85,1,0,3,100,60,70,0,4,52,155,1,3,1,0,4,96,156,1,16,1,0,4,140,1,154,1,155,1,1,0,4,171,1,88,16,1,0,5,55,85,3,1,3,6,81,117,18,1,8,7,100,108,109,1,2,7,101,106,107,1,2,7,117,110,106,1,2,9,27,64,3,2,7,4,9,34,72,92,2,7,4,9,35,77,93,2,7,4,9,43,72,22,2,7,4,9,100,60,61,2,7,4,9,127,77,78,2,7,4,10,34,116,117,1,4,10,35,121,122,1,4,10,57,60,65,1,4,10,90,113,22,1,4,10,98,113,16,1,4,10,116,142,1,85,1,4,10,124,81,3,1,4,11,123,157,1,3,1,12,12,58,76,16,0,12,135,1,76,63,0,13,43,98,22,2,1,0,13,57,3,69,2,1,0,13,67,98,92,2,1,0,13,72,99,93,2,1,0,13,83,101,3,2,1,0,13,90,137,1,22,2,1,0,13,97,137,1,138,1,2,1,0,13,115,149,1,100,2,1,0,13,127,99,100,2,1,0,13,137,1,137,1,16,2,1,0,14,43,139,1,22,1,3,14,84,150,1,138,1,1,3,14,90,141,1,22,1,3,14,127,140,1,3,1,3,15,60,112,21,0,15,111,91,18,0,16,24,79,3,0,16,28,26,3,0,16,38,36,16,0,16,47,79,3,0,16,48,158,1,3,0,16,54,26,3,0,16,65,36,16,0,16,74,36,112,0,16,86,115,22,0,16,92,36,22,0,16,106,36,130,1,0,16,114,160,1,161,1,0,16,120,145,1,3,0,16,128,1,89,8,0,16,133,1,79,3,0,16,134,1,95,10,0,16,142,1,36,16,0,16,144,1,36,18,0,16,148,1,36,63,0,16,156,1,36,16,0,16,177,1,36,16,0,17,102,128,1,39,0,17,160,1,128,1,124,0,17,175,1,123,124,0,18,46,73,74,0,18,50,74,62,0,18,99,94,26,0,19,125,3,16,0,19,136,1,47,3,0,19,157,1,3,16,0,81,59,77,59,85,62,81,66,81,67,94,68,80,67,77,67,82,67,82,59,77,66,89,62,61,16,60,16,64,16,71,87,80,59,78,59,80,66,79,66,93,68,101,68,96,68,97,68,66,62,75,16,74,16,76,16,87,62,83,62,79,67,63,16,62,16,59,16,84,62,73,129,1,65,16,72,134,1,93,136,1,101,136,1,99,136,1,96,136,1,103,63,106,63,105,63,86,62,88,62,72,143,1,94,103,97,103,98,136,1,100,136,1,104,63,102,103,93,103,95,103,70,87,69,87,90,8,68,87,95,136,1,64,63,72,162,1,2,10,8,20,7,8,14,1,8,0,3,7,8,0,8,20,7,8,14,0,2,7,8,0,7,8,14,3,7,8,0,3,7,8,14,2,6,8,0,6,8,20,4,7,8,0,5,11,7,1,8,11,7,8,14,1,8,18,3,7,8,0,8,18,7,8,14,1,11,7,1,8,11,3,7,8,0,3,6,8,14,9,7,8,0,7,11,7,1,8,11,7,11,7,1,8,11,7,11,15,2,5,11,16,1,5,3,3,3,3,7,8,14,6,7,8,0,3,3,3,7,11,15,2,5,11,16,1,5,7,8,14,1,7,8,0,1,6,8,0,1,3,2,6,8,0,5,1,8,8,1,6,11,12,2,8,8,5,2,7,8,0,6,8,8,1,6,11,12,2,3,8,17,1,1,2,6,10,8,20,6,8,20,2,6,11,13,1,8,20,6,8,20,2,7,8,0,5,1,7,8,20,2,6,10,8,20,5,1,11,5,1,3,2,6,11,13,1,8,20,5,2,6,10,8,20,6,10,5,1,10,3,2,7,10,8,20,5,3,7,8,0,5,1,3,7,8,0,6,8,22,1,2,7,8,0,6,8,14,1,6,8,20,3,7,8,0,5,2,3,7,8,0,6,8,21,2,1,8,22,3,7,8,0,7,11,15,2,5,11,16,1,5,7,8,14,5,7,8,0,8,20,7,11,15,2,5,11,16,1,5,1,7,8,14,2,7,11,15,2,5,11,16,1,5,5,2,7,8,0,3,1,7,10,3,2,7,10,8,20,7,8,14,1,6,10,8,20,1,7,10,8,20,4,10,3,3,6,10,3,6,10,3,4,3,11,15,2,3,3,3,11,15,2,3,3,2,6,8,0,11,15,2,5,11,16,1,5,1,10,5,4,6,10,8,20,3,3,3,2,10,3,10,3,9,6,10,8,20,3,3,10,3,10,3,3,11,15,2,3,3,3,11,15,2,3,3,6,7,10,8,20,6,10,3,6,10,3,7,11,7,1,8,11,7,11,7,1,8,11,7,8,14,6,3,6,10,8,20,6,10,3,6,10,3,6,11,15,2,5,11,16,1,5,6,10,5,2,6,8,0,8,8,6,3,3,11,12,2,8,8,5,3,6,8,20,8,0,2,8,8,5,1,7,8,14,1,11,12,2,9,0,9,1,1,8,20,1,5,3,7,11,12,2,9,0,9,1,9,0,9,1,1,11,13,1,9,0,2,8,8,8,23,2,5,8,23,2,5,3,1,11,15,2,9,0,9,1,1,8,6,4,6,8,20,6,8,20,1,5,2,6,11,12,2,9,0,9,1,9,0,2,8,20,7,8,14,1,8,23,3,8,8,8,20,5,1,6,8,14,2,7,11,12,2,9,0,9,1,9,0,1,9,1,2,7,8,20,3,5,6,8,20,6,8,20,1,8,20,5,2,7,11,13,1,9,0,9,0,3,5,3,11,5,1,3,1,6,11,5,1,9,0,1,7,11,5,1,9,0,1,9,0,2,6,10,9,0,6,9,0,1,8,11,1,6,11,7,1,9,0,4,7,8,20,11,7,1,8,11,5,7,8,14,3,7,8,20,8,8,5,1,6,8,18,1,6,9,1,1,7,9,1,1,7,8,23,3,7,8,20,8,18,7,8,14,14,11,15,2,5,11,16,1,5,6,10,5,10,3,10,3,11,15,2,3,3,11,15,2,3,3,3,10,5,3,3,3,3,10,3,10,3,8,3,3,7,3,3,8,20,8,20,5,6,8,20,2,6,11,15,2,9,0,9,1,6,9,0,2,7,11,15,2,9,0,9,1,6,9,0,2,9,0,9,1,3,7,11,15,2,9,0,9,1,9,0,9,1,2,7,10,9,0,3,2,3,3,10,10,11,9,1,3,3,3,11,10,1,3,3,3,3,6,8,20,3,6,10,8,20,1,11,9,1,3,2,3,9,0,1,11,9,1,9,0,1,10,11,9,1,9,0,1,11,10,1,9,0,1,7,11,10,1,9,0,2,6,8,20,5,1,6,8,19,1,6,11,13,1,9,0,3,3,3,3,2,6,8,20,6,8,20,2,6,11,13,1,9,0,3,1,6,9,0,1,11,5,1,9,0,5,5,3,11,5,1,3,3,10,3,4,3,3,11,5,1,3,11,5,1,3,2,7,11,13,1,9,0,3,1,7,9,0,1,6,8,22,1,6,5,2,3,11,5,1,3,6,1,1,3,3,11,5,1,3,11,5,1,3,5,5,6,8,20,8,8,5,6,8,20,1,6,8,21,1,8,21,1,6,8,8,2,3,8,20,1,6,10,9,0,3,3,5,8,8,1,8,4,7,6,5,6,5,3,3,6,5,10,5,7,11,16,1,5,2,5,11,16,1,5,1,6,11,15,2,9,0,9,1,1,10,9,0,2,6,11,16,1,9,0,6,9,0,2,7,11,16,1,9,0,6,9,0,1,6,11,16,1,9,0,1,7,11,13,1,9,0,1,8,3,6,3,3,3,3,3,3,2,7,8,20,7,8,14,4,3,3,3,6,8,20,7,11,15,2,3,3,11,15,2,3,3,4,4,3,3,3,5,10,5,6,10,8,20,11,16,1,5,10,5,5,1,7,11,15,2,9,0,9,1,1,11,16,1,9,0,6,3,3,4,10,3,10,3,3,17,3,3,3,10,3,3,10,3,3,4,3,3,3,3,3,3,3,3,4,8,3,3,11,7,1,8,11,3,7,8,20,5,4,11,7,1,8,11,2,7,11,7,1,9,0,3,1,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,2,9,0,5,2,7,8,20,11,7,1,8,11,8,10,5,3,3,3,3,10,5,6,8,20,5,2,6,8,20,3,1,8,17,1,8,2,5,3,3,10,5,5,6,10,8,20,3,66,97,103,7,66,97,108,97,110,99,101,5,69,110,116,114,121,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,13,80,114,105,111,114,105,116,121,81,117,101,117,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,23,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,25,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,86,50,18,86,97,108,105,100,97,116,111,114,74,111,105,110,69,118,101,110,116,19,86,97,108,105,100,97,116,111,114,76,101,97,118,101,69,118,101,110,116,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,6,86,101,99,77,97,112,6,86,101,99,83,101,116,8,97,99,116,105,118,97,116,101,26,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,101,115,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,3,97,100,100,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,18,97,116,95,114,105,115,107,95,118,97,108,105,100,97,116,111,114,115,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,22,99,97,108,99,117,108,97,116,101,95,116,111,116,97,108,95,115,116,97,107,101,115,38,99,108,101,97,110,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,95,108,101,97,118,105,110,103,95,118,97,108,105,100,97,116,111,114,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,36,99,111,109,112,117,116,101,95,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,26,99,111,109,112,117,116,101,95,114,101,119,97,114,100,95,97,100,106,117,115,116,109,101,110,116,115,26,99,111,109,112,117,116,101,95,115,108,97,115,104,101,100,95,118,97,108,105,100,97,116,111,114,115,38,99,111,109,112,117,116,101,95,117,110,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,8,99,111,110,116,97,105,110,115,25,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,116,97,98,108,101,118,101,99,20,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,118,101,99,9,99,114,101,97,116,101,95,118,49,10,100,101,97,99,116,105,118,97,116,101,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,17,100,105,115,116,114,105,98,117,116,101,95,114,101,119,97,114,100,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,27,101,109,105,116,95,118,97,108,105,100,97,116,111,114,95,101,112,111,99,104,95,101,118,101,110,116,115,5,101,109,112,116,121,5,101,112,111,99,104,5,101,118,101,110,116,14,101,120,99,104,97,110,103,101,95,114,97,116,101,115,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,14,102,105,110,100,95,118,97,108,105,100,97,116,111,114,29,102,105,110,100,95,118,97,108,105,100,97,116,111,114,95,102,114,111,109,95,116,97,98,108,101,95,118,101,99,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,3,103,101,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,24,103,101,116,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,37,103,101,116,95,99,97,110,100,105,100,97,116,101,95,111,114,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,7,103,101,116,95,109,117,116,25,103,101,116,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,95,114,101,102,20,103,101,116,95,115,116,97,107,105,110,103,95,112,111,111,108,95,114,101,102,21,103,101,116,95,118,97,108,105,100,97,116,111,114,95,105,110,100,105,99,101,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,114,101,102,2,105,100,19,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,12,105,115,95,100,117,112,108,105,99,97,116,101,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,34,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,35,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,21,105,115,95,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,22,105,115,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,12,105,115,95,118,111,108,117,110,116,97,114,121,4,106,111,105,110,4,107,101,121,115,6,108,101,110,103,116,104,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,25,112,101,110,100,105,110,103,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,16,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,19,112,111,111,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,115,7,112,111,111,108,95,105,100,19,112,111,111,108,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,24,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,3,112,111,112,8,112,111,112,95,98,97,99,107,7,112,111,112,95,109,97,120,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,24,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,26,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,115,27,112,114,111,99,101,115,115,95,118,97,108,105,100,97,116,111,114,95,100,101,112,97,114,116,117,114,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,9,112,117,115,104,95,98,97,99,107,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,26,114,101,102,101,114,101,110,99,101,95,103,97,115,95,115,117,114,118,101,121,95,113,117,111,116,101,6,114,101,109,111,118,101,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,6,115,101,110,100,101,114,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,105,122,101,4,115,111,109,101,17,115,111,114,116,95,114,101,109,111,118,97,108,95,108,105,115,116,5,115,112,108,105,116,5,115,116,97,107,101,12,115,116,97,107,101,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,27,115,116,111,114,97,103,101,95,102,117,110,100,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,29,115,117,109,95,118,111,116,105,110,103,95,112,111,119,101,114,95,98,121,95,97,100,100,114,101,115,115,101,115,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,26,116,97,108,108,121,105,110,103,95,114,117,108,101,95,103,108,111,98,97,108,95,115,99,111,114,101,23,116,97,108,108,121,105,110,103,95,114,117,108,101,95,114,101,112,111,114,116,101,114,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,39,117,112,100,97,116,101,95,97,110,100,95,112,114,111,99,101,115,115,95,108,111,119,95,115,116,97,107,101,95,100,101,112,97,114,116,117,114,101,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,20,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,10,3,1,0,10,5,1,0,0,2,9,155,1,3,26,10,8,20,108,11,13,1,8,20,109,10,3,145,1,11,12,2,8,8,5,82,11,12,2,8,8,8,23,164,1,11,12,2,5,8,23,31,11,15,2,5,3,61,8,6,1,2,10,58,3,163,1,5,126,3,141,1,3,38,3,112,3,146,1,3,113,8,17,154,1,10,5,153,1,3,2,2,11,58,3,163,1,5,126,3,141,1,3,177,1,3,38,3,112,3,146,1,3,113,8,17,154,1,10,5,153,1,3,3,2,3,58,3,163,1,5,144,1,8,8,4,2,4,58,3,163,1,5,144,1,8,8,95,1,0,3,0,0,58,51,14,0,17,46,12,5,10,1,56,0,12,4,14,0,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,16,14,0,10,2,66,62,12,6,13,4,10,6,17,126,11,6,17,127,56,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,11,5,11,0,10,1,56,2,64,16,0,0,0,0,0,0,0,0,11,4,10,1,56,3,10,1,56,4,56,5,11,1,17,67,18,0,12,7,13,7,15,0,17,137,1,11,7,2,1,3,0,0,71,69,10,0,14,1,12,3,46,11,3,17,21,32,4,17,10,0,14,1,12,4,46,11,4,17,24,32,12,5,5,19,9,12,5,11,5,4,22,5,28,11,0,1,11,2,1,7,7,39,14,1,17,127,12,6,10,0,16,1,10,6,56,6,32,4,38,5,44,11,0,1,11,2,1,7,11,39,14,1,17,118,4,48,5,54,11,0,1,11,2,1,7,12,39,10,0,15,2,14,1,17,126,11,6,56,1,11,0,15,1,14,1,17,127,11,1,11,2,17,133,1,56,7,2,2,3,0,0,75,53,10,1,46,17,92,12,4,10,0,16,1,10,4,56,6,4,10,5,16,11,0,1,11,1,1,7,13,39,10,0,15,1,11,4,56,8,17,134,1,12,3,14,3,17,118,4,26,5,32,11,0,1,11,1,1,7,12,39,14,3,17,126,12,2,10,0,15,2,10,2,56,9,1,13,3,10,1,46,17,91,17,112,11,0,15,3,11,2,11,3,11,1,17,133,1,56,10,2,3,3,0,0,80,69,11,2,46,17,92,12,7,10,0,16,1,10,7,56,6,4,10,5,14,11,0,1,7,13,39,10,0,15,1,11,7,56,8,17,134,1,12,6,10,0,14,6,12,3,46,11,3,17,21,32,4,37,10,0,14,6,12,4,46,11,4,17,24,32,12,5,5,39,9,12,5,11,5,4,42,5,46,11,0,1,7,7,39,14,6,17,118,4,50,5,54,11,0,1,7,12,39,14,6,17,128,1,11,1,38,4,60,5,64,11,0,1,7,10,39,11,0,15,4,11,6,56,11,2,4,3,0,0,3,16,10,0,16,0,10,1,17,23,11,0,16,4,11,1,17,25,22,6,1,0,0,0,0,0,0,0,33,4,13,5,15,7,7,39,2,5,3,0,0,82,36,11,1,46,17,92,12,2,10,0,16,0,11,2,17,27,12,4,14,4,56,12,4,13,5,17,11,0,1,7,9,39,13,4,56,13,12,3,10,0,16,5,14,3,56,14,32,4,27,5,31,11,0,1,7,16,39,11,0,15,5,11,3,68,16,2,6,3,0,0,3,22,14,2,56,15,7,4,38,4,6,5,12,11,0,1,11,3,1,7,15,39,11,0,11,1,17,26,11,2,10,3,46,17,92,11,3,17,122,2,7,3,0,0,90,43,14,1,17,108,12,4,10,0,16,2,10,4,56,16,4,20,10,0,16,2,14,1,17,108,56,17,20,12,5,11,0,11,5,17,26,12,3,5,38,10,0,16,3,10,4,56,18,4,26,5,32,11,0,1,11,2,1,7,8,39,11,0,15,3,11,4,56,19,17,135,1,12,3,11,3,11,1,11,2,17,124,2,8,3,0,0,63,10,11,2,17,92,12,3,11,0,15,0,11,3,17,30,11,1,17,123,2,9,3,0,0,96,110,10,8,46,17,91,6,1,0,0,0,0,0,0,0,22,12,15,17,138,1,12,20,10,0,16,0,10,20,10,1,46,56,15,10,2,46,56,15,17,50,12,22,12,21,10,0,10,3,20,12,9,46,11,9,17,49,12,16,10,0,16,0,14,16,17,54,12,17,10,0,16,0,14,16,17,29,11,4,14,21,14,22,17,48,12,14,12,19,12,13,12,18,10,0,16,0,11,20,11,17,11,21,11,22,11,18,11,13,11,19,11,14,17,51,12,12,12,11,10,0,15,0,14,11,14,12,11,1,11,2,10,8,17,52,10,0,15,0,17,47,10,0,15,0,10,8,17,45,10,15,10,0,16,0,14,11,14,12,10,3,14,16,12,10,46,11,10,17,53,10,0,11,15,17,43,10,0,10,3,10,8,17,40,10,0,11,5,11,6,11,7,11,3,11,8,17,10,10,0,16,0,17,46,10,0,15,6,21,10,0,15,0,17,137,1,11,0,17,11,2,10,0,0,0,97,106,10,0,16,0,65,62,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,99,5,9,11,7,6,1,0,0,0,0,0,0,0,23,12,7,10,0,16,0,10,7,66,62,12,13,10,13,17,127,12,12,11,13,17,128,1,12,9,10,9,10,1,38,4,40,10,0,16,7,14,12,56,20,4,39,10,0,15,7,14,12,56,21,1,1,5,98,11,9,10,2,38,4,87,10,0,16,7,14,12,56,20,4,64,10,0,15,7,14,12,56,22,12,8,10,8,20,6,1,0,0,0,0,0,0,0,22,10,8,21,11,8,20,12,6,5,71,10,0,15,7,11,12,6,1,0,0,0,0,0,0,0,56,23,6,1,0,0,0,0,0,0,0,12,6,11,6,10,3,36,4,86,10,0,15,0,10,7,56,24,12,10,10,0,11,10,10,4,9,10,5,17,41,5,98,10,0,15,0,10,7,56,24,12,11,10,0,11,11,10,4,9,10,5,17,41,5,4,11,4,1,11,0,1,11,5,1,2,11,0,0,0,103,24,10,0,16,0,65,62,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,21,5,11,10,0,15,0,10,1,67,62,17,114,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,12,1,0,0,104,60,11,0,16,0,12,10,10,10,65,62,12,3,64,105,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,15,10,10,10,2,66,62,12,8,13,1,10,8,17,115,11,8,17,129,1,56,25,68,105,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,10,11,10,1,11,1,56,26,12,4,6,0,0,0,0,0,0,0,0,12,6,17,138,1,17,136,1,23,12,7,6,0,0,0,0,0,0,0,0,12,5,10,6,10,7,35,4,58,5,49,13,4,56,27,12,9,12,5,11,6,11,9,22,12,6,5,44,11,5,2,13,1,0,0,3,4,11,0,16,6,20,2,14,1,0,0,3,6,11,0,16,0,11,1,17,35,17,128,1,2,15,1,0,0,3,6,11,0,16,0,11,1,17,35,17,125,2,16,1,0,0,3,6,11,0,16,0,11,1,17,35,17,126,2,17,1,0,0,3,3,11,0,16,2,2,18,3,0,0,111,31,10,0,16,2,10,1,20,56,16,4,19,10,0,16,2,11,1,20,56,17,20,12,3,11,0,11,3,7,2,17,36,12,2,5,27,11,0,15,3,11,1,20,56,19,17,135,1,46,12,2,11,2,17,116,17,107,2,19,3,0,0,3,12,10,0,16,0,65,62,10,0,16,5,65,16,23,11,0,16,4,56,28,22,2,20,3,0,0,28,8,11,0,16,0,11,1,17,27,12,2,14,2,56,12,2,21,0,0,0,3,5,11,0,16,0,11,1,17,22,2,22,3,0,0,3,6,11,0,11,1,17,23,6,0,0,0,0,0,0,0,0,36,2,23,0,0,0,114,33,10,0,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,66,62,10,1,17,117,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,24,0,0,0,3,7,11,0,16,4,11,1,17,25,6,0,0,0,0,0,0,0,0,36,2,25,0,0,0,114,33,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,56,29,10,1,17,117,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,26,0,0,0,3,16,10,0,16,1,10,1,56,6,4,11,11,0,15,1,11,1,56,30,17,135,1,2,11,0,15,0,11,1,17,30,2,27,0,0,0,103,31,10,0,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,66,62,17,127,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,28,0,0,0,103,31,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,56,29,17,127,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,29,0,0,0,119,46,10,1,65,63,12,5,6,0,0,0,0,0,0,0,0,12,3,7,20,12,6,10,3,10,5,35,4,40,5,12,10,1,10,3,66,63,20,12,2,10,0,11,2,17,27,12,4,14,4,56,12,4,25,5,31,11,0,1,11,1,1,7,9,39,13,6,11,4,56,33,68,16,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,0,1,11,1,1,11,6,2,30,3,0,0,82,22,10,0,11,1,12,2,46,11,2,17,27,12,4,14,4,56,12,4,11,5,15,11,0,1,7,9,39,13,4,56,13,12,3,11,0,11,3,67,62,2,31,0,0,0,120,45,10,0,16,0,10,1,17,27,12,5,14,5,56,12,4,16,13,5,56,13,12,3,11,0,15,0,11,3,67,62,2,10,0,16,4,10,1,17,28,12,6,14,6,56,12,4,32,13,6,56,13,12,4,11,0,15,4,11,4,56,34,2,11,2,4,35,5,39,11,0,1,7,14,39,11,0,15,1,11,1,56,30,17,135,1,2,32,3,0,0,3,7,11,0,11,1,17,132,1,20,11,2,17,31,2,33,3,0,0,63,8,11,1,17,92,12,2,11,0,11,2,9,17,31,2,34,3,0,0,63,8,11,1,17,92,12,2,11,0,11,2,8,17,31,2,35,0,0,0,125,19,10,0,11,1,17,27,12,3,14,3,56,12,4,8,5,12,11,0,1,7,9,39,13,3,56,13,12,2,11,0,11,2,66,62,2,36,3,0,0,126,57,10,0,16,0,10,1,17,27,12,7,14,7,56,12,4,11,8,12,3,5,15,10,2,7,0,33,12,3,11,3,4,25,13,7,56,13,12,5,11,0,16,0,11,5,66,62,2,10,0,16,4,10,1,17,28,12,8,14,8,56,12,4,36,8,12,4,5,40,11,2,7,1,33,12,4,11,4,4,50,13,8,56,13,12,6,11,0,16,4,11,6,56,29,2,11,0,15,1,11,1,56,30,17,135,1,46,2,37,1,0,0,125,21,10,0,16,0,11,1,17,27,12,3,14,3,56,12,4,9,5,13,11,0,1,7,9,39,13,3,56,13,12,2,11,0,16,0,11,2,66,62,2,38,1,0,0,125,21,10,0,16,4,11,1,17,28,12,3,14,3,56,12,4,9,5,13,11,0,1,7,17,39,13,3,56,13,12,2,11,0,16,4,11,2,56,29,2,39,3,0,0,127,39,10,1,17,131,1,20,12,6,10,2,7,0,33,4,16,11,0,11,6,12,3,46,11,3,17,37,12,4,5,21,11,0,11,6,11,2,17,36,12,4,11,4,12,7,10,1,56,35,12,5,11,7,17,119,14,5,33,4,32,5,36,11,1,1,7,19,39,11,1,17,130,1,2,40,0,0,0,131,1,32,10,0,15,5,17,44,10,0,16,5,56,36,32,4,25,5,9,10,0,15,5,69,16,12,3,10,0,15,0,11,3,56,24,12,4,10,0,11,4,10,1,8,10,2,17,41,5,3,11,1,1,11,0,1,11,2,1,2,41,0,0,0,133,1,58,10,4,46,17,91,6,1,0,0,0,0,0,0,0,22,12,5,14,1,17,127,12,6,14,1,17,126,12,7,10,0,15,2,10,7,56,9,1,10,0,16,7,14,6,56,20,4,28,10,0,15,7,14,6,56,21,1,1,10,0,16,6,20,14,1,17,128,1,23,10,0,15,6,21,11,2,10,6,17,42,10,5,11,6,14,1,17,126,11,3,18,4,56,37,13,1,11,5,17,112,11,0,15,3,11,7,11,1,11,4,17,133,1,56,10,2,42,0,0,0,135,1,69,10,0,14,1,12,2,46,11,2,56,38,4,12,10,0,14,1,56,39,1,1,10,0,46,56,40,12,7,14,7,65,63,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,66,5,26,14,7,10,4,66,63,12,6,10,0,10,6,56,41,12,8,10,8,14,1,12,3,46,11,3,56,42,4,57,10,8,14,1,56,43,11,8,46,56,44,4,54,10,0,11,6,56,39,1,1,5,56,11,6,1,5,61,11,8,1,11,6,1,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,21,11,0,1,2,43,0,0,0,62,28,10,0,16,4,56,45,32,4,25,5,6,10,0,15,4,56,46,12,2,13,2,10,1,17,109,10,1,14,2,17,127,14,2,17,126,18,3,56,47,10,0,15,0,11,2,68,62,5,0,11,0,1,2,44,0,0,0,144,1,57,10,0,46,65,16,12,6,6,1,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,54,5,11,10,0,10,4,12,1,46,11,1,66,16,20,12,3,10,4,12,5,10,5,6,0,0,0,0,0,0,0,0,36,4,49,5,26,11,5,6,1,0,0,0,0,0,0,0,23,12,5,10,0,10,5,12,2,46,11,2,66,16,20,10,3,36,4,41,5,42,5,49,10,0,10,5,10,5,6,1,0,0,0,0,0,0,0,22,71,16,5,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,1,2,45,0,0,0,103,26,10,0,46,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,21,5,11,10,0,10,2,67,62,10,1,17,121,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,11,1,1,2,46,0,0,0,146,1,30,6,0,0,0,0,0,0,0,0,12,3,10,0,65,62,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,26,5,12,10,0,10,1,66,62,12,4,11,3,11,4,17,128,1,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,47,0,0,0,103,23,10,0,46,65,62,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,20,5,11,10,0,10,1,67,62,17,110,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,48,0,0,0,147,1,69,6,0,0,0,0,0,0,0,0,12,8,56,48,12,4,6,0,0,0,0,0,0,0,0,12,9,56,48,12,5,13,0,46,56,36,32,4,60,5,14,13,0,69,16,12,10,10,2,10,10,66,16,20,53,10,1,53,24,7,3,26,12,6,13,4,10,10,10,6,52,56,49,11,8,11,6,52,22,12,8,10,3,10,10,66,16,20,53,10,1,53,24,7,3,26,12,7,13,5,11,10,10,7,52,56,49,11,9,11,7,52,22,12,9,5,8,11,3,1,11,2,1,11,8,11,4,11,9,11,5,2,49,0,0,0,148,1,40,7,21,12,5,14,1,56,50,32,4,36,5,7,13,1,56,51,12,4,12,6,10,0,10,6,17,20,4,16,5,20,11,0,1,7,5,39,10,0,16,0,12,3,11,4,56,52,12,2,11,3,14,2,17,54,17,136,1,38,4,35,13,5,11,6,68,63,5,2,11,0,1,11,5,2,50,0,0,0,151,1,47,64,16,0,0,0,0,0,0,0,0,12,7,64,16,0,0,0,0,0,0,0,0,12,8,10,0,65,62,12,5,11,3,10,5,26,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,42,5,18,10,0,10,4,66,62,17,129,1,53,10,2,53,24,10,1,53,26,12,6,13,7,11,6,52,68,16,13,8,10,9,68,16,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,13,11,0,1,11,7,11,8,2,51,0,0,0,152,1,108,11,1,11,2,23,12,22,64,16,0,0,0,0,0,0,0,0,12,12,64,16,0,0,0,0,0,0,0,0,12,14,10,0,65,62,12,20,10,20,14,6,56,53,23,12,21,6,0,0,0,0,0,0,0,0,12,19,10,19,10,20,35,4,103,5,23,10,0,10,19,66,62,17,129,1,53,12,25,14,3,10,19,66,16,20,12,23,14,6,14,19,56,54,4,48,14,6,14,19,56,55,20,12,15,11,23,11,15,23,12,9,5,61,10,5,53,11,25,24,10,22,53,26,12,16,11,23,11,16,52,22,12,9,11,9,12,11,13,12,11,11,68,16,14,4,10,19,66,16,20,12,24,14,8,14,19,56,54,4,85,14,8,14,19,56,55,20,12,17,11,24,11,17,23,12,10,5,93,10,7,10,21,26,12,18,11,24,11,18,22,12,10,11,10,12,13,13,14,11,13,68,16,11,19,6,1,0,0,0,0,0,0,0,22,12,19,5,18,11,0,1,11,12,11,14,2,52,0,0,0,153,1,107,10,0,46,65,62,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,9,5,23,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,7,18,39,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,94,5,30,10,0,10,6,67,62,12,10,10,1,10,6,66,16,20,12,9,10,3,10,9,56,56,12,8,11,9,53,10,10,46,17,111,53,24,7,3,26,12,12,13,8,11,12,52,56,56,12,13,13,13,10,4,10,2,10,6,66,16,20,56,56,56,57,1,14,13,56,15,6,0,0,0,0,0,0,0,0,36,4,84,10,10,46,17,127,12,11,10,10,11,13,10,11,10,5,17,122,11,11,56,58,5,86,11,13,56,59,11,10,11,8,17,113,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,25,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,2,53,0,0,0,159,1,84,10,1,65,62,12,9,6,0,0,0,0,0,0,0,0,12,8,10,8,10,9,35,4,73,5,10,10,1,10,8,66,62,12,12,10,12,17,127,12,13,10,4,14,13,56,38,4,28,10,4,14,13,56,60,20,56,52,12,6,5,30,7,21,12,6,11,6,12,11,10,5,14,13,56,61,4,39,6,0,0,0,0,0,0,0,0,12,7,5,41,6,1,0,0,0,0,0,0,0,12,7,11,7,12,10,10,0,11,13,10,12,17,115,10,12,17,128,1,10,12,17,129,1,10,12,17,111,10,2,10,8,66,16,20,10,3,10,8,66,16,20,11,12,10,0,17,120,11,11,11,10,18,2,56,62,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,5,11,1,1,11,3,1,11,5,1,11,4,1,11,2,1,2,54,1,0,0,146,1,35,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,1,65,63,12,3,10,2,10,3,35,4,29,5,12,10,0,10,1,10,2,66,63,20,17,35,12,5,11,4,11,5,17,129,1,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,55,1,0,0,3,3,11,0,16,0,2,56,1,0,0,3,5,11,0,16,1,11,1,56,6,2,57,1,0,0,3,5,11,0,16,3,11,1,56,18,2,58,3,0,0,163,1,32,11,0,16,0,12,5,7,21,12,3,6,0,0,0,0,0,0,0,0,12,1,10,5,65,62,12,2,10,1,10,2,35,4,28,5,15,10,5,10,1,66,62,17,127,12,4,13,3,11,4,68,63,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,10,11,5,1,11,3,2,0,1,0,6,0,4,0,5,0,2,0,3,0,0,0,7,0,66,0,149,1,0],"validator_wrapper":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,16,3,24,48,4,72,6,5,78,52,7,130,1,211,1,8,213,2,64,6,149,3,10,10,159,3,6,12,165,3,100,13,137,4,2,15,139,4,2,0,14,1,10,1,16,0,12,0,2,4,0,1,0,2,0,2,3,12,0,3,1,4,0,0,5,0,1,0,0,8,2,3,0,0,6,1,4,0,0,11,2,5,0,0,15,6,7,0,2,4,8,9,1,4,2,6,9,12,1,4,2,9,10,11,1,4,2,15,13,7,0,5,4,7,4,6,4,2,8,3,7,8,1,1,8,0,1,7,8,0,1,7,8,3,1,8,3,0,1,6,8,0,1,3,3,3,9,0,7,8,1,1,8,2,1,7,8,2,1,7,9,0,1,9,0,1,6,8,2,9,84,120,67,111,110,116,101,120,116,9,86,97,108,105,100,97,116,111,114,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,9,86,101,114,115,105,111,110,101,100,6,99,114,101,97,116,101,9,99,114,101,97,116,101,95,118,49,7,100,101,115,116,114,111,121,5,105,110,110,101,114,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,10,116,120,95,99,111,110,116,101,120,116,17,117,112,103,114,97,100,101,95,116,111,95,108,97,116,101,115,116,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,1,7,8,2,0,3,0,0,5,6,6,1,0,0,0,0,0,0,0,11,0,11,1,56,0,18,0,2,1,3,0,0,5,6,10,0,17,3,11,0,15,0,56,1,2,2,3,0,0,5,6,13,0,17,3,11,0,19,0,56,2,2,3,0,0,0,5,10,11,0,46,17,4,6,1,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,2,4,0,0,0,5,4,11,0,16,0,17,8,2,0,0,0,13,0],"voting_power":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,87,4,107,4,5,111,134,1,7,245,1,176,2,8,165,4,96,6,133,5,70,10,203,5,16,12,219,5,254,6,13,217,12,4,15,221,12,2,0,22,1,21,2,9,0,18,0,1,2,0,0,2,2,0,3,0,4,0,0,13,0,1,0,0,6,2,3,0,0,15,4,5,0,0,7,6,1,0,0,3,7,1,0,0,17,8,1,0,0,4,4,1,0,0,16,1,5,0,0,12,1,5,0,1,7,17,1,1,0,1,8,19,20,1,0,2,5,11,5,0,2,10,11,5,0,2,11,11,5,0,3,13,21,1,0,3,15,14,5,0,3,22,14,5,0,9,13,10,13,1,7,10,8,2,0,2,6,10,8,2,3,2,10,8,1,3,1,6,10,8,2,1,3,2,7,10,8,1,8,1,3,7,10,8,1,3,3,2,7,10,8,2,10,8,1,4,3,10,8,1,3,3,1,8,2,2,3,3,8,3,8,1,3,10,8,1,3,3,3,3,1,8,1,1,6,8,2,3,3,3,3,4,3,1,3,3,3,7,10,9,0,9,0,3,7,1,3,3,3,3,3,7,8,1,1,6,10,9,0,1,1,2,7,8,2,3,12,3,3,3,3,3,3,3,3,3,6,8,2,6,8,2,3,9,86,97,108,105,100,97,116,111,114,15,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,17,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,86,50,19,97,100,106,117,115,116,95,118,111,116,105,110,103,95,112,111,119,101,114,16,99,104,101,99,107,95,105,110,118,97,114,105,97,110,116,115,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,22,105,110,105,116,95,118,111,116,105,110,103,95,112,111,119,101,114,95,105,110,102,111,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,4,109,97,116,104,3,109,97,120,3,109,105,110,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,5,115,116,97,107,101,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,19,117,112,100,97,116,101,95,118,111,116,105,110,103,95,112,111,119,101,114,9,118,97,108,105,100,97,116,111,114,15,118,97,108,105,100,97,116,111,114,95,105,110,100,101,120,13,118,97,108,105,100,97,116,111,114,95,115,101,116,6,118,101,99,116,111,114,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,16,39,0,0,0,0,0,0,3,8,11,26,0,0,0,0,0,0,3,8,232,3,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,2,19,3,22,3,1,2,3,19,3,22,3,14,3,0,3,0,0,9,29,7,0,7,2,7,0,10,0,46,65,10,17,11,17,12,17,13,12,4,10,0,10,4,12,1,46,11,1,17,1,12,3,12,2,13,2,11,4,11,3,17,4,10,0,11,2,17,5,11,0,46,17,6,2,1,0,0,0,12,58,10,0,17,2,12,8,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,7,64,13,0,0,0,0,0,0,0,0,12,5,10,2,10,4,35,4,51,5,17,10,0,10,2,66,10,17,15,12,6,10,6,53,7,0,53,24,10,8,53,26,52,10,1,17,13,12,9,10,2,10,9,11,6,18,1,12,3,13,5,11,3,17,3,11,7,11,9,22,12,7,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,0,1,11,5,7,0,11,7,23,2,2,0,0,0,15,28,6,0,0,0,0,0,0,0,0,12,1,10,0,65,10,12,2,6,0,0,0,0,0,0,0,0,12,3,10,1,10,2,35,4,24,5,12,11,3,10,0,10,1,66,10,17,15,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,3,0,0,0,16,39,6,0,0,0,0,0,0,0,0,12,4,10,0,46,65,13,12,5,10,4,10,5,35,4,25,5,11,10,0,10,4,12,2,46,11,2,66,13,16,0,20,14,1,16,0,20,36,12,3,5,27,9,12,3,11,3,4,34,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,11,1,11,4,56,0,2,4,0,0,0,18,84,6,0,0,0,0,0,0,0,0,12,5,10,0,46,65,13,12,6,10,5,10,6,35,4,16,5,11,10,2,6,0,0,0,0,0,0,0,0,36,12,3,5,18,9,12,3,11,3,4,74,10,0,10,5,67,13,12,9,10,2,10,6,10,5,23,17,11,12,7,10,1,10,9,16,1,20,11,7,22,17,13,12,8,10,2,11,8,10,9,16,1,20,23,17,13,12,4,10,9,16,1,20,10,4,22,10,9,15,1,21,11,9,16,1,20,10,1,37,4,61,5,65,11,0,1,7,5,39,11,2,11,4,23,12,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,6,11,0,1,11,2,6,0,0,0,0,0,0,0,0,33,4,81,5,83,7,3,39,2,5,0,0,0,11,22,14,1,56,1,32,4,17,5,5,13,1,69,13,19,1,1,12,3,12,2,10,0,11,2,67,10,11,3,17,14,5,0,11,0,1,11,1,70,13,0,0,0,0,0,0,0,0,2,6,0,0,0,22,119,6,0,0,0,0,0,0,0,0,12,3,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,9,10,3,10,4,35,4,35,5,12,10,0,10,3,66,10,17,16,12,12,10,12,6,0,0,0,0,0,0,0,0,36,4,22,5,26,11,0,1,7,6,39,11,9,11,12,22,12,9,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,9,7,0,33,4,40,5,44,11,0,1,7,3,39,6,0,0,0,0,0,0,0,0,12,1,10,1,10,4,35,4,116,5,51,10,1,6,1,0,0,0,0,0,0,0,22,12,2,10,2,10,4,35,4,111,5,60,10,0,10,1,66,10,12,10,10,0,10,2,66,10,12,11,10,10,17,15,12,7,10,11,17,15,12,8,11,10,17,16,12,5,11,11,17,16,12,6,10,7,10,8,36,4,93,10,5,10,6,38,4,89,5,93,11,0,1,7,4,39,11,7,11,8,35,4,106,11,5,11,6,37,4,102,5,106,11,0,1,7,4,39,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,55,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,46,11,0,1,2,7,1,0,0,1,2,7,0,2,8,1,0,0,1,2,7,1,2,1,2,1,1,0,20,0]},"type_origin_table":[{"module_name":"validator_cap","struct_name":"UnverifiedValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_cap","struct_name":"ValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakingPool","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"PoolTokenExchangeRate","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakedSui","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"ValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"Validator","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"StakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"UnstakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfo","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfoV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_wrapper","struct_name":"ValidatorWrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorSet","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEventV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorJoinEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorLeaveEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"storage_fund","struct_name":"StorageFund","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"stake_subsidy","struct_name":"StakeSubsidy","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SystemParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SystemParametersV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SuiSystemStateInner","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SuiSystemStateInnerV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SystemEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system","struct_name":"SuiSystemState","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisChainParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenDistributionSchedule","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenAllocation","package":"0x0000000000000000000000000000000000000000000000000000000000000003"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"F8GGcAVhtPumDoXzc6z9N8Hf9zoTNFx1BPiCy7FJNZsQ","storage_rebate":0},{"data":{"Package":{"id":"0x000000000000000000000000000000000000000000000000000000000000dee9","version":10,"module_map":{"clob":[161,28,235,11,6,0,0,0,13,1,0,35,2,35,134,1,3,169,1,195,4,4,236,5,178,1,5,158,7,249,9,7,151,17,237,14,8,132,32,96,6,228,32,147,2,10,247,34,226,1,11,217,36,8,12,225,36,179,39,13,148,76,40,14,188,76,26,0,45,0,53,0,54,0,94,1,105,1,135,1,2,28,2,46,2,47,2,64,2,85,2,103,2,124,2,127,2,133,1,2,134,1,0,16,7,0,0,14,7,2,0,1,0,1,0,10,7,2,0,1,0,1,0,12,7,2,0,1,0,1,0,9,6,0,0,19,4,0,0,15,8,2,0,1,0,1,0,13,7,2,0,1,0,1,0,11,7,2,0,1,0,1,1,4,4,1,4,0,2,0,12,0,2,5,12,1,0,1,4,8,7,1,0,0,5,21,7,0,6,1,4,1,0,1,7,2,8,0,8,3,12,1,0,1,10,7,12,2,7,0,4,1,11,6,7,0,11,22,4,0,12,17,2,0,13,18,12,2,7,1,4,1,15,20,2,0,0,60,0,1,0,0,49,2,3,0,0,51,4,1,2,0,0,0,50,5,1,2,0,0,0,57,6,1,2,0,0,0,58,7,1,2,0,0,0,144,1,8,9,2,0,0,0,145,1,8,10,2,0,0,0,125,11,12,2,0,0,0,126,13,12,2,0,0,0,93,14,15,2,0,0,0,92,14,15,2,0,0,0,91,16,15,2,0,0,0,110,17,18,2,0,0,0,78,19,20,2,0,0,0,109,21,22,2,0,0,0,107,20,23,0,0,62,24,1,2,0,0,0,63,25,1,2,0,0,0,44,26,1,2,0,0,0,121,27,28,2,0,0,0,43,29,1,2,0,0,0,36,30,1,2,0,0,0,86,31,32,2,0,0,0,24,31,33,2,0,0,0,74,34,35,2,0,0,0,73,36,37,2,0,0,0,72,36,37,2,0,0,0,71,38,20,2,0,0,0,75,39,40,2,0,0,1,39,84,60,1,4,1,40,84,60,1,4,1,42,71,72,1,4,1,66,84,20,1,4,1,67,84,78,1,4,1,79,91,20,1,4,1,82,70,23,1,4,1,95,70,35,1,4,1,96,70,35,1,4,1,98,2,51,1,4,1,102,84,35,1,4,1,112,84,35,1,4,1,120,71,45,1,4,2,23,97,20,1,0,2,24,97,35,1,0,2,55,90,55,1,0,2,56,77,55,1,0,2,77,62,1,1,0,2,87,90,1,1,0,2,98,2,54,1,0,2,137,1,77,1,1,0,2,143,1,63,9,1,0,3,97,35,20,0,3,138,1,35,20,0,3,139,1,35,20,0,3,140,1,35,78,0,4,38,74,60,1,0,4,83,74,23,1,0,5,70,1,46,1,0,6,84,80,20,1,0,6,123,79,55,1,0,6,142,1,67,20,1,0,6,146,1,1,55,1,0,7,131,1,66,20,0,8,68,68,9,1,0,8,80,9,55,1,0,8,84,88,1,1,0,8,142,1,59,20,1,0,9,61,45,1,1,3,10,27,73,74,2,7,4,10,38,75,76,2,7,4,10,41,83,82,2,7,4,10,48,75,23,2,7,4,10,59,43,1,2,7,4,10,69,73,74,2,7,4,10,82,73,23,2,7,4,10,98,2,43,2,7,4,10,99,75,74,2,7,4,10,114,92,1,2,7,4,10,119,83,47,2,7,4,11,76,60,61,1,8,11,98,2,48,0,11,136,1,49,50,0,13,25,95,1,2,7,4,13,38,94,76,2,7,4,13,41,81,82,2,7,4,13,48,94,23,2,7,4,13,98,2,53,2,7,4,14,122,45,1,1,8,73,42,58,45,58,47,39,0,87,52,49,45,49,47,62,45,62,47,88,57,68,58,67,45,80,3,65,45,47,45,67,47,65,47,47,47,51,45,51,47,13,56,10,56,61,45,64,45,64,47,36,0,38,0,32,0,74,42,56,20,75,42,70,42,50,45,17,56,46,45,60,47,59,47,59,45,18,56,77,42,57,20,85,52,79,35,79,42,71,42,40,0,42,0,34,0,37,0,50,47,46,47,60,45,41,0,11,56,66,45,12,56,66,47,48,47,48,45,76,42,35,0,78,42,68,93,86,52,76,35,83,52,78,35,43,47,45,47,61,47,45,45,14,56,68,98,68,99,72,35,70,35,20,56,30,0,72,42,75,35,69,35,84,52,74,35,31,0,77,35,44,45,44,47,33,0,28,56,1,8,5,0,1,7,8,22,1,8,10,6,3,3,3,3,11,14,1,8,20,7,8,22,4,3,3,11,16,1,8,20,7,8,22,3,7,11,6,2,9,0,9,1,11,16,1,9,0,6,8,10,3,7,11,6,2,9,0,9,1,11,16,1,9,1,6,8,10,4,7,11,6,2,9,0,9,1,3,6,8,10,7,8,22,1,11,16,1,9,0,1,11,16,1,9,1,6,7,11,6,2,9,0,9,1,3,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,3,11,16,1,9,0,11,16,1,9,1,3,5,7,11,6,2,9,0,9,1,3,6,8,15,11,16,1,9,1,7,8,22,5,7,11,6,2,9,0,9,1,3,3,3,11,14,1,9,1,2,11,14,1,9,0,11,14,1,9,1,4,7,11,6,2,9,0,9,1,3,3,11,14,1,9,0,7,7,11,6,2,9,0,9,1,3,1,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,2,11,16,1,9,0,11,16,1,9,1,7,7,11,6,2,9,0,9,1,3,3,1,3,6,8,10,7,8,22,1,3,9,7,11,6,2,9,0,9,1,3,3,1,3,2,6,8,15,6,8,10,7,8,22,4,3,3,1,3,1,1,2,8,18,6,8,4,5,8,18,6,8,4,3,3,3,3,7,11,6,2,9,0,9,1,3,6,8,10,5,7,11,9,1,8,5,7,11,17,2,3,3,3,3,8,18,1,8,4,2,7,11,6,2,9,0,9,1,6,8,10,3,7,11,6,2,9,0,9,1,10,3,6,8,10,2,6,11,6,2,9,0,9,1,6,8,10,1,10,8,4,4,3,3,3,3,1,6,11,6,2,9,0,9,1,2,3,3,4,6,11,6,2,9,0,9,1,3,3,6,8,15,2,10,3,10,3,3,6,11,9,1,8,5,3,3,3,6,11,6,2,9,0,9,1,3,6,8,10,1,6,8,4,1,11,17,2,3,8,4,2,3,8,4,1,11,17,2,9,0,9,1,4,8,13,8,18,8,19,8,13,1,9,0,1,8,13,1,9,1,1,8,19,1,6,8,19,1,6,8,18,1,11,9,1,9,0,2,8,18,11,17,2,3,3,1,11,21,2,9,0,9,1,1,11,11,1,9,0,1,11,14,1,9,0,2,9,0,9,1,1,11,6,2,9,0,9,1,1,8,0,1,6,11,16,1,9,0,1,6,9,0,1,8,18,3,7,11,11,1,9,0,8,18,11,14,1,9,0,4,7,11,11,1,9,0,3,6,8,10,7,8,22,4,3,11,16,1,9,0,11,16,1,9,1,3,3,11,14,1,9,0,11,14,1,9,1,3,1,6,8,15,1,6,11,14,1,9,0,2,11,14,1,9,0,7,8,22,30,1,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,11,14,1,9,1,1,3,3,3,1,3,7,8,5,3,1,6,11,9,1,9,0,2,7,11,9,1,9,0,3,1,7,9,0,1,6,11,17,2,9,0,9,1,1,6,11,12,1,9,0,2,6,11,17,2,9,0,9,1,9,0,1,6,9,1,3,7,11,11,1,9,0,8,18,3,2,1,3,2,7,11,14,1,9,0,3,2,7,11,14,1,9,0,11,14,1,9,0,2,7,11,21,2,9,0,9,1,9,0,1,7,9,1,2,7,11,17,2,9,0,9,1,9,0,2,6,11,9,1,9,0,3,26,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,27,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,1,3,6,8,4,7,8,4,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,3,11,14,1,9,0,11,14,1,9,1,11,14,1,9,1,2,7,11,16,1,9,0,11,16,1,9,0,7,3,7,11,9,1,8,5,8,4,3,3,3,8,18,3,7,11,11,1,9,0,6,8,10,3,3,7,11,9,1,9,0,3,9,0,3,7,11,17,2,9,0,9,1,9,0,9,1,1,11,1,2,9,0,9,1,2,6,11,21,2,9,0,9,1,9,0,3,7,11,21,2,9,0,9,1,9,0,9,1,11,11,14,1,9,0,11,14,1,9,0,11,14,1,9,0,3,3,11,14,1,9,1,11,14,1,9,1,11,14,1,9,1,3,3,8,18,2,6,11,11,1,9,0,8,18,1,11,2,2,9,0,9,1,1,11,3,2,9,0,9,1,11,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,1,8,4,3,3,8,18,7,11,17,2,3,3,3,3,7,8,5,8,4,13,3,7,11,9,1,8,5,3,3,1,7,11,9,1,8,5,8,4,3,3,8,18,3,8,18,7,11,17,2,3,3,17,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,3,1,3,3,3,8,4,3,8,18,3,3,8,18,7,11,17,2,3,3,7,6,8,5,10,8,4,6,8,4,6,11,12,1,3,3,8,18,6,11,17,2,3,3,5,3,3,3,3,8,18,6,3,10,3,3,3,3,10,3,4,3,6,8,4,6,11,12,1,3,6,11,17,2,3,8,4,4,6,11,9,1,8,5,3,8,18,6,11,17,2,3,3,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,11,67,114,105,116,98,105,116,84,114,101,101,9,67,117,115,116,111,100,105,97,110,2,73,68,11,76,105,110,107,101,100,84,97,98,108,101,6,79,112,116,105,111,110,5,79,114,100,101,114,13,79,114,100,101,114,67,97,110,99,101,108,101,100,11,79,114,100,101,114,70,105,108,108,101,100,13,79,114,100,101,114,70,105,108,108,101,100,86,50,11,79,114,100,101,114,80,108,97,99,101,100,13,79,114,100,101,114,80,108,97,99,101,100,86,50,4,80,111,111,108,11,80,111,111,108,67,114,101,97,116,101,100,3,83,85,73,5,84,97,98,108,101,9,84,105,99,107,76,101,118,101,108,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,3,97,100,100,4,97,115,107,115,4,98,97,99,107,7,98,97,108,97,110,99,101,10,98,97,115,101,95,97,115,115,101,116,28,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,99,97,110,99,101,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,102,105,108,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,112,108,97,99,101,100,29,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,114,101,109,97,105,110,105,110,103,23,98,97,115,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,14,98,97,115,101,95,99,117,115,116,111,100,105,97,110,18,98,97,116,99,104,95,99,97,110,99,101,108,95,111,114,100,101,114,4,98,105,100,115,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,17,99,97,110,99,101,108,95,97,108,108,95,111,114,100,101,114,115,12,99,97,110,99,101,108,95,111,114,100,101,114,4,99,108,111,98,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,14,99,114,101,97,116,101,95,97,99,99,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,12,99,114,101,97,116,101,95,112,111,111,108,95,12,99,114,101,97,116,105,111,110,95,102,101,101,7,99,114,105,116,98,105,116,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,100,101,112,111,115,105,116,95,98,97,115,101,13,100,101,112,111,115,105,116,95,113,117,111,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,19,100,101,115,116,114,111,121,95,101,109,112,116,121,95,108,101,118,101,108,4,101,109,105,116,19,101,109,105,116,95,111,114,100,101,114,95,99,97,110,99,101,108,101,100,17,101,109,105,116,95,111,114,100,101,114,95,102,105,108,108,101,100,5,101,118,101,110,116,16,101,120,112,105,114,101,95,116,105,109,101,115,116,97,109,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,12,102,114,111,109,95,98,97,108,97,110,99,101,5,102,114,111,110,116,3,103,101,116,22,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,97,115,107,95,115,105,100,101,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,98,105,100,95,115,105,100,101,16,103,101,116,95,109,97,114,107,101,116,95,112,114,105,99,101,16,103,101,116,95,111,114,100,101,114,95,115,116,97,116,117,115,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,18,105,110,106,101,99,116,95,108,105,109,105,116,95,111,114,100,101,114,11,105,110,115,101,114,116,95,108,101,97,102,12,105,110,116,111,95,98,97,108,97,110,99,101,6,105,115,95,98,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,4,106,111,105,110,12,108,105,110,107,101,100,95,116,97,98,108,101,16,108,105,115,116,95,111,112,101,110,95,111,114,100,101,114,115,12,108,111,99,107,95,98,97,108,97,110,99,101,8,108,111,116,95,115,105,122,101,17,109,97,107,101,114,95,114,101,98,97,116,101,95,114,97,116,101,13,109,97,107,101,114,95,114,101,98,97,116,101,115,9,109,97,116,99,104,95,97,115,107,9,109,97,116,99,104,95,98,105,100,29,109,97,116,99,104,95,98,105,100,95,119,105,116,104,95,113,117,111,116,101,95,113,117,97,110,116,105,116,121,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,3,109,117,108,3,110,101,119,4,110,101,120,116,17,110,101,120,116,95,97,115,107,95,111,114,100,101,114,95,105,100,17,110,101,120,116,95,98,105,100,95,111,114,100,101,114,95,105,100,9,110,101,120,116,95,108,101,97,102,6,111,98,106,101,99,116,11,111,112,101,110,95,111,114,100,101,114,115,6,111,112,116,105,111,110,8,111,114,100,101,114,95,105,100,12,111,114,100,101,114,95,105,115,95,98,105,100,5,111,119,110,101,114,17,112,108,97,99,101,95,108,105,109,105,116,95,111,114,100,101,114,18,112,108,97,99,101,95,109,97,114,107,101,116,95,111,114,100,101,114,7,112,111,111,108,95,105,100,13,112,114,101,118,105,111,117,115,95,108,101,97,102,5,112,114,105,99,101,9,112,117,115,104,95,98,97,99,107,8,113,117,97,110,116,105,116,121,11,113,117,111,116,101,95,97,115,115,101,116,24,113,117,111,116,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,15,113,117,111,116,101,95,99,117,115,116,111,100,105,97,110,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,12,114,101,109,111,118,101,95,111,114,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,3,115,117,105,25,115,119,97,112,95,101,120,97,99,116,95,98,97,115,101,95,102,111,114,95,113,117,111,116,101,25,115,119,97,112,95,101,120,97,99,116,95,113,117,111,116,101,95,102,111,114,95,98,97,115,101,5,116,97,98,108,101,16,116,97,107,101,114,95,99,111,109,109,105,115,115,105,111,110,14,116,97,107,101,114,95,102,101,101,95,114,97,116,101,9,116,105,99,107,95,115,105,122,101,12,116,105,109,101,115,116,97,109,112,95,109,115,14,116,111,116,97,108,95,113,117,97,110,116,105,116,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,10,117,110,115,97,102,101,95,100,105,118,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,15,117,115,114,95,111,112,101,110,95,111,114,100,101,114,115,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,13,119,105,116,104,100,114,97,119,95,98,97,115,101,14,119,105,116,104,100,114,97,119,95,113,117,111,116,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,3,8,19,0,0,0,0,0,0,0,3,8,20,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,2,1,4,2,1,0,2,1,1,2,1,2,2,1,3,3,8,0,0,0,0,0,0,0,128,3,8,64,75,76,0,0,0,0,0,3,8,160,37,38,0,0,0,0,0,3,8,0,232,118,72,23,0,0,0,0,2,7,111,8,18,29,8,13,116,8,13,129,1,3,89,3,130,1,3,88,3,1,2,7,111,8,18,106,3,81,1,108,8,18,32,3,113,3,65,3,2,2,6,111,8,18,106,3,81,1,108,8,18,30,3,113,3,3,2,10,111,8,18,106,3,81,1,108,8,18,132,1,3,31,3,33,3,113,3,128,1,3,90,3,4,2,6,106,3,113,3,115,3,81,1,108,8,18,65,3,5,2,2,113,3,104,11,17,2,3,8,4,6,2,15,76,8,19,37,11,9,1,8,5,26,11,9,1,8,5,101,3,100,3,141,1,11,21,2,8,18,11,17,2,3,3,129,1,3,89,3,130,1,3,88,3,35,11,11,1,9,0,118,11,11,1,9,1,52,11,14,1,8,20,34,11,14,1,9,0,117,11,14,1,9,1,7,2,6,111,8,18,106,3,81,1,108,8,18,32,3,113,3,8,2,8,111,8,18,106,3,81,1,108,8,18,132,1,3,31,3,33,3,113,3,6,56,1,56,2,56,3,56,0,0,0,0,41,7,11,0,19,5,12,1,1,11,1,56,0,2,1,1,0,0,1,2,7,0,39,2,0,0,0,44,72,56,1,12,6,56,2,12,9,10,3,10,2,17,54,6,0,0,0,0,0,0,0,0,36,4,11,5,15,11,5,1,7,20,39,10,6,10,9,34,4,20,5,24,11,5,1,7,16,39,10,0,10,1,38,4,29,5,33,11,5,1,7,2,39,10,5,17,81,12,8,14,8,17,82,20,12,7,11,8,10,5,56,3,10,5,56,3,7,1,7,27,10,5,56,4,10,0,10,1,10,2,10,3,10,5,56,5,11,5,56,6,11,4,56,7,56,8,57,0,56,9,11,7,11,6,11,9,11,0,11,1,11,2,11,3,18,0,56,10,2,3,1,0,0,1,2,7,0,39,4,1,0,0,1,20,14,1,56,11,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,7,39,11,0,54,0,11,2,56,12,11,1,56,13,56,14,2,5,1,0,0,1,20,14,1,56,15,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,8,39,11,0,54,1,11,2,56,12,11,1,56,16,56,17,2,6,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,6,39,11,0,54,0,11,1,11,2,11,3,56,18,2,7,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,6,39,11,0,54,1,11,1,11,2,11,3,56,19,2,8,1,0,0,64,49,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,5,1,11,4,1,7,6,39,14,2,56,11,10,1,38,4,19,5,27,11,0,1,11,5,1,11,4,1,7,7,39,14,3,56,15,12,6,11,0,11,1,9,11,2,11,3,11,4,11,5,56,20,12,8,12,7,14,8,56,15,12,9,11,7,11,8,11,9,11,6,23,2,9,1,0,0,65,48,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,4,1,11,2,1,7,6,39,14,3,56,15,10,1,38,4,19,5,27,11,0,1,11,4,1,11,2,1,7,8,39,11,0,11,1,7,27,11,2,17,63,11,3,56,16,56,21,12,6,12,5,14,5,56,22,12,7,11,5,10,4,56,23,11,6,11,4,56,24,11,7,2,10,0,0,0,69,193,2,10,0,55,2,17,82,20,12,24,11,1,12,30,56,7,12,10,11,4,12,26,10,0,54,3,12,9,10,9,46,56,25,4,25,11,0,1,11,9,1,11,10,11,26,2,10,9,46,56,26,12,32,12,34,9,12,31,10,9,46,56,25,32,4,43,5,38,10,34,10,2,37,12,5,5,45,9,12,5,11,5,4,190,2,10,9,10,32,56,27,12,33,10,33,16,4,56,28,56,29,20,12,23,10,33,16,4,56,30,32,4,158,2,5,63,10,33,16,4,10,23,56,31,12,16,10,16,16,5,20,12,15,9,12,27,10,16,16,6,20,10,3,37,4,95,8,12,27,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,32,10,24,10,16,56,33,5,227,1,10,15,10,16,16,8,20,17,52,12,19,10,19,10,0,55,4,20,17,55,12,28,4,112,11,28,6,1,0,0,0,0,0,0,0,22,12,28,10,19,11,28,22,12,18,10,30,10,18,36,4,127,11,18,12,12,11,19,12,13,10,15,12,11,5,170,1,8,12,31,10,30,7,21,10,0,55,4,20,22,17,53,10,16,16,8,20,17,53,10,0,55,5,20,26,10,0,55,5,20,24,12,11,10,11,10,16,16,8,20,17,54,12,13,10,13,10,0,55,4,20,17,55,12,29,4,166,1,11,29,6,1,0,0,0,0,0,0,0,22,12,29,10,13,11,29,22,12,12,10,13,10,0,55,6,20,17,54,12,20,11,15,10,11,23,12,15,11,30,10,12,23,12,30,10,0,54,0,10,16,16,7,20,10,11,56,34,12,14,13,26,10,12,56,35,12,25,10,0,54,1,10,16,16,7,20,13,25,10,20,10,13,22,56,35,56,17,10,0,54,7,11,25,56,36,1,13,10,11,14,56,37,1,10,0,55,2,17,82,20,10,16,11,11,11,12,11,13,23,11,20,56,38,11,27,4,232,1,8,12,6,5,236,1,10,15,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,143,2,10,23,12,22,10,33,16,4,10,23,56,39,12,21,10,21,56,40,32,4,254,1,11,21,56,29,20,12,23,5,128,2,11,21,1,10,0,54,8,11,16,16,7,20,56,41,10,22,56,42,1,10,33,15,4,11,22,56,43,1,5,154,2,11,16,1,10,33,15,4,10,23,56,44,12,17,11,15,11,17,15,5,21,10,31,4,157,2,5,158,2,5,57,11,33,16,4,56,30,4,182,2,10,9,11,34,12,7,46,11,7,56,45,1,12,34,10,9,11,32,56,46,17,0,10,9,10,34,12,8,46,11,8,56,47,12,32,1,10,31,4,189,2,11,0,1,11,9,1,5,190,2,5,32,11,10,11,26,2,11,0,0,0,85,153,2,10,0,55,2,17,82,20,12,22,11,1,12,25,56,7,12,11,11,4,12,23,10,0,54,3,12,10,10,10,46,56,25,4,25,11,0,1,11,10,1,11,11,11,23,2,10,10,46,56,26,12,28,12,30,10,10,46,56,25,32,4,41,5,36,10,30,10,2,37,12,5,5,43,9,12,5,11,5,4,150,2,10,10,10,28,56,27,12,29,10,29,16,4,56,28,56,29,20,12,21,10,29,16,4,56,30,32,4,244,1,5,61,10,29,16,4,10,21,56,31,12,16,10,16,16,5,20,12,15,9,12,24,10,16,16,6,20,10,3,37,4,93,8,12,24,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,32,10,22,10,16,56,33,5,183,1,10,25,10,15,36,4,100,10,15,12,6,5,102,10,25,12,6,11,6,12,12,10,12,10,16,16,8,20,17,52,12,13,10,13,10,0,55,6,20,17,54,12,18,10,13,10,0,55,4,20,17,55,12,26,4,127,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,15,10,12,23,12,15,11,25,10,12,23,12,25,10,0,54,0,10,16,16,7,20,10,12,56,34,12,14,13,23,10,26,56,35,12,27,10,0,54,1,10,16,16,7,20,13,27,10,18,56,35,56,17,10,0,54,7,11,27,56,36,1,13,11,11,14,56,37,1,10,0,54,1,10,16,16,7,20,13,23,11,13,56,35,56,17,10,0,55,2,17,82,20,10,16,11,12,11,26,11,18,56,38,11,24,4,188,1,8,12,7,5,192,1,10,15,6,0,0,0,0,0,0,0,0,33,12,7,11,7,4,227,1,10,21,12,20,10,29,16,4,10,21,56,39,12,19,10,19,56,40,32,4,210,1,11,19,56,29,20,12,21,5,212,1,11,19,1,10,0,54,8,11,16,16,7,20,56,41,10,20,56,42,1,10,29,15,4,11,20,56,43,1,5,238,1,11,16,1,10,29,15,4,10,21,56,44,12,17,11,15,11,17,15,5,21,10,25,6,0,0,0,0,0,0,0,0,33,4,243,1,5,244,1,5,55,11,29,16,4,56,30,4,140,2,10,10,11,30,12,8,46,11,8,56,45,1,12,30,10,10,11,28,56,46,17,0,10,10,10,30,12,9,46,11,9,56,47,12,28,1,10,25,6,0,0,0,0,0,0,0,0,33,4,149,2,11,0,1,11,10,1,5,150,2,5,30,11,11,11,23,2,12,0,0,0,86,158,2,10,0,55,2,17,82,20,12,22,11,3,12,10,56,8,12,23,10,0,54,9,12,9,10,9,46,56,25,4,23,11,0,1,11,9,1,11,10,11,23,2,10,9,46,56,48,12,28,12,30,10,9,46,56,25,32,4,39,5,34,10,30,10,1,38,12,4,5,41,9,12,4,11,4,4,155,2,10,9,10,28,56,27,12,29,10,29,16,4,56,28,56,29,20,12,21,10,29,16,4,56,30,32,4,248,1,5,59,10,29,16,4,10,21,56,31,12,15,10,15,16,5,20,12,14,9,12,24,10,15,16,6,20,10,2,37,4,97,8,12,24,10,15,16,5,20,10,15,16,8,20,17,52,12,17,10,0,54,1,10,15,16,7,20,11,17,56,49,10,22,10,15,56,33,5,186,1,14,10,56,22,12,25,10,25,10,14,38,4,107,10,14,12,5,5,109,11,25,12,5,11,5,12,11,10,11,10,15,16,8,20,17,52,12,12,10,12,10,0,55,6,20,17,54,12,18,10,12,10,0,55,4,20,17,55,12,26,4,134,1,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,14,10,11,23,12,14,10,0,54,1,10,15,16,7,20,11,12,56,50,12,13,13,13,10,26,56,35,12,27,10,0,54,1,10,15,16,7,20,13,27,10,18,56,35,56,17,10,0,54,7,11,27,56,36,1,13,23,11,13,56,36,1,10,0,54,0,10,15,16,7,20,13,10,10,11,56,51,56,14,10,0,55,2,17,82,20,10,15,11,11,11,26,11,18,56,38,11,24,4,191,1,8,12,6,5,195,1,10,14,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,230,1,10,21,12,20,10,29,16,4,10,21,56,39,12,19,10,19,56,40,32,4,213,1,11,19,56,29,20,12,21,5,215,1,11,19,1,10,0,54,8,11,15,16,7,20,56,41,10,20,56,42,1,10,29,15,4,11,20,56,43,1,5,241,1,11,15,1,10,29,15,4,10,21,56,44,12,16,11,14,11,16,15,5,21,14,10,56,22,6,0,0,0,0,0,0,0,0,33,4,247,1,5,248,1,5,53,11,29,16,4,56,30,4,144,2,10,9,11,30,12,7,46,11,7,56,52,1,12,30,10,9,11,28,56,46,17,0,10,9,10,30,12,8,46,11,8,56,47,12,28,1,14,10,56,22,6,0,0,0,0,0,0,0,0,33,4,154,2,11,0,1,11,9,1,5,155,2,5,28,11,10,11,23,2,13,1,0,0,87,85,10,1,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,9,5,17,11,0,1,11,6,1,11,5,1,7,6,39,10,1,6,0,0,0,0,0,0,0,0,34,4,22,5,30,11,0,1,11,6,1,11,5,1,7,6,39,11,2,4,52,11,0,11,1,7,27,11,5,17,63,11,4,56,16,56,53,12,9,12,7,13,3,11,7,10,6,56,23,56,54,11,9,11,6,56,24,12,4,5,82,11,1,14,3,56,11,37,4,58,5,66,11,0,1,11,6,1,11,5,1,7,7,39,11,0,7,0,11,5,17,63,11,3,56,13,56,55,12,8,10,6,56,23,12,3,13,4,11,8,11,6,56,24,56,56,11,3,11,4,2,14,0,0,0,89,118,10,5,56,12,12,13,10,3,4,30,10,2,10,1,17,52,12,11,10,0,54,1,11,5,11,11,56,57,10,0,55,10,20,12,10,10,0,55,10,20,6,1,0,0,0,0,0,0,0,22,10,0,54,10,21,10,0,54,9,12,8,5,50,10,0,54,0,11,5,10,2,56,58,10,0,55,11,20,12,10,10,0,55,11,20,6,1,0,0,0,0,0,0,0,22,10,0,54,11,21,10,0,54,3,12,8,10,10,10,1,10,2,10,3,10,13,10,4,18,4,12,9,10,8,10,1,12,7,46,11,7,56,47,12,12,32,4,75,10,8,10,1,10,1,10,6,56,59,18,5,56,60,12,12,11,8,11,12,56,27,15,4,10,10,11,9,56,61,10,0,55,2,17,82,20,10,10,11,3,10,13,11,2,10,1,11,4,57,1,56,62,10,0,55,8,10,13,56,63,32,4,107,10,0,54,8,10,13,11,6,56,64,56,65,5,109,11,6,1,11,0,54,8,11,13,56,41,10,10,11,1,56,66,11,10,2,15,1,0,0,96,144,2,10,2,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,8,1,11,6,1,11,7,1,7,6,39,10,1,6,0,0,0,0,0,0,0,0,36,4,20,5,30,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,1,10,0,55,12,20,25,6,0,0,0,0,0,0,0,0,33,4,39,5,49,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,2,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,58,5,68,11,0,1,11,8,1,11,6,1,11,7,1,7,6,39,10,4,10,6,17,63,36,4,74,5,84,11,0,1,11,8,1,11,6,1,11,7,1,7,19,39,10,7,56,12,12,19,10,3,4,128,1,10,0,55,1,10,19,56,67,12,18,10,0,54,1,10,7,10,18,56,68,12,14,10,0,10,2,10,1,11,6,17,63,11,14,56,53,12,16,12,10,14,10,56,22,12,12,11,18,14,16,56,69,23,12,17,10,0,54,0,10,19,11,10,56,14,10,0,54,1,11,19,11,16,56,17,5,160,1,10,0,54,0,10,7,10,2,56,70,12,9,10,0,10,1,11,6,17,63,11,9,56,55,12,15,12,11,10,2,14,11,56,22,23,12,12,14,15,56,69,12,17,10,0,54,0,10,19,11,11,56,14,10,0,54,1,11,19,11,15,56,17,10,5,7,24,33,4,175,1,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,25,33,4,197,1,11,0,1,11,8,1,11,7,1,10,12,11,2,33,4,190,1,5,192,1,7,9,39,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,26,33,4,228,1,10,12,6,0,0,0,0,0,0,0,0,33,4,206,1,5,214,1,11,0,1,11,8,1,11,7,1,7,10,39,11,0,11,1,11,2,11,3,11,4,11,7,11,8,56,71,12,13,11,12,11,17,8,11,13,2,11,5,7,23,33,4,233,1,5,241,1,11,0,1,11,8,1,11,7,1,7,14,39,10,2,10,12,36,4,133,2,11,0,11,1,11,2,10,12,23,11,3,11,4,11,7,11,8,56,71,12,13,11,12,11,17,8,11,13,2,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,16,0,0,0,1,4,11,0,7,27,35,2,17,0,0,0,1,19,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,11,1,16,8,20,57,2,56,72,2,18,0,0,0,1,27,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,10,2,10,1,16,5,20,11,2,23,11,1,16,8,20,11,3,11,4,57,3,56,73,2,19,1,0,0,100,110,11,2,56,12,12,12,10,0,55,8,10,12,56,63,4,9,5,13,11,0,1,7,12,39,10,0,54,8,10,12,56,41,12,13,10,13,10,1,12,3,46,11,3,56,74,4,26,5,32,11,13,1,11,0,1,7,3,39,10,13,10,1,12,4,46,11,4,56,75,20,12,11,10,1,17,16,12,8,10,8,4,49,10,0,55,9,12,5,5,52,10,0,55,3,12,5,11,5,11,11,56,47,12,10,4,58,5,64,11,13,1,11,0,1,7,3,39,10,8,4,70,10,0,54,9,12,6,5,73,10,0,54,3,12,6,11,6,11,13,11,10,11,1,10,12,56,76,12,9,11,8,4,96,14,9,16,5,20,14,9,16,8,20,17,52,12,7,10,0,54,1,11,12,11,7,56,49,5,103,10,0,54,0,11,12,14,9,16,5,20,56,32,11,0,55,2,17,82,20,14,9,56,33,2,20,0,0,0,101,54,11,1,10,3,56,42,1,10,0,10,2,12,5,46,11,5,56,77,16,4,10,3,56,78,4,15,5,19,11,0,1,7,3,39,10,0,10,2,56,27,12,6,10,6,15,4,11,3,56,43,12,7,14,7,16,7,20,11,4,33,4,35,5,41,11,0,1,11,6,1,7,4,39,11,6,16,4,56,30,4,50,11,0,11,2,56,46,17,0,5,52,11,0,1,11,7,2,21,1,0,0,102,104,10,0,55,2,17,82,20,12,11,11,1,56,12,12,13,10,0,55,8,10,13,56,63,4,14,5,18,11,0,1,7,12,39,10,0,54,8,10,13,56,41,12,14,10,14,46,56,79,32,4,99,5,29,10,14,46,56,80,56,29,20,12,9,10,14,10,9,12,2,46,11,2,56,75,20,12,10,10,9,17,16,12,6,10,6,4,52,10,0,54,9,12,3,5,55,10,0,54,3,12,3,11,3,12,7,10,7,11,10,12,4,46,11,4,56,47,12,12,1,11,7,10,14,11,12,11,9,10,13,56,76,12,8,11,6,4,88,14,8,16,5,20,14,8,16,8,20,17,52,12,5,10,0,54,1,10,13,11,5,56,49,5,95,10,0,54,0,10,13,14,8,16,5,20,56,32,10,11,14,8,56,33,5,23,11,14,1,11,0,1,2,22,1,0,0,103,148,1,10,0,55,2,17,82,20,12,15,11,2,56,12,12,18,10,0,55,8,10,18,56,63,4,14,5,18,11,0,1,6,0,0,0,0,0,0,0,0,39,6,0,0,0,0,0,0,0,0,12,16,6,0,0,0,0,0,0,0,0,12,17,14,1,65,20,12,10,6,0,0,0,0,0,0,0,0,12,8,10,0,54,8,10,18,56,41,12,19,10,8,10,10,35,4,143,1,5,37,14,1,10,8,66,20,20,12,14,10,19,10,14,12,3,46,11,3,56,74,4,50,5,56,11,19,1,11,0,1,7,3,39,10,19,10,14,12,4,46,11,4,56,75,20,12,12,10,14,17,16,12,9,10,12,10,17,34,4,96,11,12,12,17,10,9,4,79,10,0,55,9,12,5,5,82,10,0,55,3,12,5,11,5,10,17,56,47,12,11,4,88,5,94,11,19,1,11,0,1,7,11,39,11,11,12,16,10,9,4,102,10,0,54,9,12,6,5,105,10,0,54,3,12,6,11,6,10,19,10,16,11,14,10,18,56,76,12,13,11,9,4,128,1,14,13,16,5,20,14,13,16,8,20,17,52,12,7,10,0,54,1,10,18,11,7,56,49,5,135,1,10,0,54,0,10,18,14,13,16,5,20,56,32,10,15,14,13,56,33,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,32,11,19,1,11,0,1,2,23,1,0,0,104,84,11,1,56,12,12,7,10,0,55,8,11,7,56,81,12,8,64,28,0,0,0,0,0,0,0,0,12,3,10,8,56,82,12,5,10,5,56,40,32,4,76,5,18,10,8,10,5,56,29,20,56,75,20,12,6,10,5,56,29,20,17,16,4,36,10,0,55,9,11,6,56,83,12,2,5,41,10,0,55,3,11,6,56,83,12,2,11,2,16,4,10,5,56,29,20,56,31,12,4,13,3,10,4,16,18,20,10,4,16,8,20,10,4,16,5,20,10,4,16,19,20,10,4,16,7,20,11,4,16,6,20,18,4,68,28,10,8,11,5,56,29,20,56,84,12,5,5,13,11,8,1,11,0,1,11,5,1,11,3,2,24,1,0,0,105,20,11,1,56,12,12,6,10,0,55,0,10,6,56,85,12,3,12,2,11,0,55,1,11,6,56,86,12,5,12,4,11,2,11,3,11,4,11,5,2,25,1,0,0,35,13,10,0,55,9,56,48,1,12,2,11,0,55,3,56,26,1,12,1,11,2,11,1,2,26,1,0,0,106,86,10,0,55,9,56,26,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,9,56,48,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,9,11,1,56,87,12,1,10,0,55,9,11,2,56,87,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,9,10,1,10,3,17,63,56,88,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,9,11,1,56,45,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,27,1,0,0,106,86,10,0,55,3,56,26,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,3,56,48,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,3,11,1,56,87,12,1,10,0,55,3,11,2,56,87,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,3,10,1,10,3,17,63,56,88,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,3,11,1,56,45,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,28,0,0,0,107,49,11,0,11,1,56,83,16,4,12,6,6,0,0,0,0,0,0,0,0,12,3,10,6,56,28,12,5,10,5,56,40,32,4,43,5,15,10,6,10,5,56,29,20,56,31,12,4,10,4,16,6,20,10,2,36,4,34,11,3,11,4,16,5,20,22,12,3,5,36,11,4,1,10,6,11,5,56,29,20,56,39,12,5,5,10,11,6,1,11,5,1,11,3,2,29,1,0,0,108,52,11,2,56,12,12,5,10,0,55,8,10,5,56,63,4,9,5,13,11,0,1,7,12,39,10,0,55,8,11,5,56,81,12,6,10,6,10,1,56,74,4,23,5,29,11,6,1,11,0,1,7,3,39,11,6,10,1,56,75,20,12,4,10,1,7,27,35,4,42,11,0,55,9,12,3,5,45,11,0,55,3,12,3,11,3,11,4,56,83,16,4,11,1,56,31,2,6,10,6,11,6,0,6,2,5,1,4,2,4,5,4,4,4,1,6,6,6,9,6,7,6,14,6,5,6,1,6,3,6,4,6,8,4,0,4,3,0,56,1,56,2,56,3,56,9,56,10,56,11,56,12,56,13,56,14,56,15,56,16,56,17,56,0],"clob_v2":[161,28,235,11,6,0,0,0,13,1,0,40,2,40,146,1,3,186,1,246,4,4,176,6,202,1,5,250,7,210,12,7,204,20,130,17,8,206,37,96,6,174,38,157,2,10,203,40,131,2,11,206,42,20,12,226,42,169,51,13,139,94,46,14,185,94,26,0,50,0,59,0,60,0,102,1,115,1,150,1,1,158,1,2,31,2,51,2,52,2,70,2,91,2,113,2,138,1,2,141,1,2,148,1,2,149,1,0,17,7,0,0,15,7,2,0,1,0,1,0,13,7,2,0,1,0,1,0,2,7,2,0,1,0,1,0,1,7,2,0,1,0,1,0,14,7,2,0,1,0,1,0,8,7,1,0,1,0,24,7,1,0,1,0,12,6,0,0,20,4,0,0,16,8,2,0,1,0,1,1,6,4,1,4,0,2,0,12,0,2,7,12,1,0,1,4,11,7,1,0,0,5,22,7,0,7,3,4,1,0,1,8,4,8,0,9,5,12,1,0,1,11,10,12,2,7,0,4,1,12,9,7,0,12,23,4,0,13,18,2,0,14,19,12,2,7,1,4,1,16,21,2,0,0,66,0,1,0,0,54,2,3,0,0,57,4,1,2,0,0,0,56,5,1,2,0,0,0,55,6,1,2,0,0,0,63,7,1,2,0,0,0,64,8,1,2,0,0,0,160,1,9,10,2,0,0,0,161,1,9,11,2,0,0,0,139,1,12,13,2,0,0,0,140,1,14,13,2,0,0,0,101,15,16,2,0,0,0,100,15,16,2,0,0,0,99,17,16,2,0,0,0,122,18,19,2,0,0,0,84,20,21,2,0,0,0,121,22,23,2,0,0,0,117,21,24,0,0,68,25,1,2,0,0,0,69,26,1,2,0,0,0,47,27,1,2,0,0,0,133,1,28,29,2,0,0,0,46,30,1,2,0,0,0,39,31,1,2,0,0,0,48,32,1,2,0,0,0,92,33,34,2,0,0,0,26,33,35,2,0,0,0,80,36,37,2,0,0,0,79,38,39,2,0,0,0,78,38,39,2,0,0,0,77,40,21,2,0,0,0,81,41,42,2,0,0,1,42,94,84,1,4,1,43,94,84,1,4,1,45,80,81,1,4,1,72,94,21,1,4,1,73,94,88,1,4,1,85,104,21,1,4,1,88,78,24,1,4,1,103,78,50,1,4,1,104,78,50,1,4,1,107,2,54,1,4,1,111,94,50,1,4,1,124,94,50,1,4,1,132,1,80,47,1,4,2,25,110,21,1,0,2,26,110,50,1,0,2,27,64,65,0,2,61,103,58,1,0,2,62,87,58,1,0,2,83,66,1,1,0,2,93,103,1,1,0,2,105,2,3,0,2,107,2,57,1,0,2,152,1,87,1,1,0,2,159,1,70,10,1,0,3,106,50,21,0,3,153,1,50,21,0,3,154,1,50,21,0,3,155,1,50,88,0,4,41,83,84,1,0,4,89,83,24,1,0,4,112,1,123,1,0,4,136,1,47,123,1,0,5,76,1,48,1,0,6,88,95,24,1,0,7,90,90,21,1,0,7,137,1,89,58,1,0,7,157,1,75,21,1,0,7,162,1,1,58,1,0,8,147,1,74,21,0,9,74,76,10,1,0,9,86,10,58,1,0,9,90,100,1,1,0,9,137,1,101,10,1,0,9,157,1,63,21,1,0,10,67,47,1,1,3,11,30,82,83,2,7,4,11,41,85,86,2,7,4,11,44,93,92,2,7,4,11,53,85,24,2,7,4,11,65,45,1,2,7,4,11,75,82,83,2,7,4,11,88,82,24,2,7,4,11,107,2,45,2,7,4,11,108,85,83,2,7,4,11,126,105,1,2,7,4,11,131,1,93,49,2,7,4,12,107,2,51,0,12,151,1,52,53,0,14,28,108,1,2,7,4,14,41,107,86,2,7,4,14,44,91,92,2,7,4,14,53,107,24,2,7,4,14,107,2,56,2,7,4,15,135,1,47,1,1,8,81,44,64,47,64,49,41,0,94,55,53,47,53,49,69,47,69,49,95,60,76,61,75,62,4,59,72,62,2,59,75,47,72,47,50,47,76,67,75,49,72,49,50,49,76,68,76,69,55,47,76,71,55,49,14,59,11,59,68,47,71,47,71,49,38,0,40,0,34,0,82,44,60,21,83,44,78,44,54,47,18,59,49,47,67,49,66,49,66,47,19,59,85,44,61,21,92,55,87,50,87,44,79,44,42,0,44,0,36,0,65,79,76,96,39,0,54,49,49,49,67,47,43,0,12,59,73,47,74,47,13,59,73,49,51,49,51,47,84,44,37,0,86,44,76,106,93,55,84,50,90,55,86,50,45,49,48,49,68,49,48,47,15,59,76,112,76,114,80,50,78,50,21,59,32,0,80,44,83,50,77,50,91,55,82,50,33,0,85,50,46,47,46,49,63,21,62,21,35,0,30,59,1,8,9,0,1,7,8,24,1,8,12,6,3,3,3,3,11,16,1,8,22,7,8,24,4,3,3,11,18,1,8,22,7,8,24,6,3,3,3,3,11,18,1,8,22,7,8,24,3,7,11,10,2,9,0,9,1,11,18,1,9,0,6,8,12,3,7,11,10,2,9,0,9,1,11,18,1,9,1,6,8,12,4,7,11,10,2,9,0,9,1,3,6,8,12,7,8,24,1,11,18,1,9,0,1,11,18,1,9,1,8,7,11,10,2,9,0,9,1,3,6,8,12,3,11,18,1,9,0,11,18,1,9,1,6,8,17,7,8,24,3,11,18,1,9,0,11,18,1,9,1,3,7,7,11,10,2,9,0,9,1,3,6,8,12,3,6,8,17,11,18,1,9,1,7,8,24,7,7,11,10,2,9,0,9,1,6,8,12,3,3,3,3,11,16,1,9,1,2,11,16,1,9,0,11,16,1,9,1,6,7,11,10,2,9,0,9,1,6,8,12,3,3,3,11,16,1,9,0,9,7,11,10,2,9,0,9,1,6,8,12,3,3,1,11,18,1,9,0,11,18,1,9,1,6,8,17,7,8,24,2,11,18,1,9,0,11,18,1,9,1,10,7,11,10,2,9,0,9,1,3,3,3,3,1,2,3,6,8,12,7,8,24,1,3,11,7,11,10,2,9,0,9,1,3,3,3,2,1,3,2,6,8,17,6,8,12,7,8,24,4,3,3,1,3,1,1,2,8,20,6,8,8,7,8,20,3,5,6,8,8,3,3,3,3,7,11,10,2,9,0,9,1,3,6,8,12,5,7,11,11,1,8,9,7,11,19,2,3,3,3,3,5,1,8,8,2,7,11,10,2,9,0,9,1,6,8,12,3,7,11,10,2,9,0,9,1,10,3,6,8,12,4,7,11,10,2,9,0,9,1,6,8,17,10,3,10,5,2,6,11,10,2,9,0,9,1,6,8,12,1,10,8,8,4,3,3,3,3,1,6,11,10,2,9,0,9,1,2,11,14,1,3,11,14,1,3,4,6,11,10,2,9,0,9,1,3,3,6,8,17,2,10,3,10,3,3,6,11,11,1,8,9,3,3,3,6,11,10,2,9,0,9,1,3,6,8,12,1,6,8,8,1,11,19,2,3,8,8,2,3,8,8,1,11,19,2,9,0,9,1,4,8,15,8,20,8,21,8,15,1,9,0,1,8,15,1,9,1,2,3,3,1,8,21,1,6,8,21,1,6,8,20,1,11,11,1,9,0,2,5,11,19,2,3,3,1,11,23,2,9,0,9,1,1,11,13,1,9,0,1,11,16,1,9,0,2,9,0,9,1,1,11,10,2,9,0,9,1,1,8,0,1,8,22,1,6,11,18,1,9,0,1,6,8,12,1,5,3,7,11,13,1,9,0,5,11,16,1,9,0,1,11,6,1,9,0,1,11,6,1,9,1,1,11,7,1,9,0,4,7,11,13,1,9,0,3,6,8,12,7,8,24,1,11,7,1,9,1,4,3,11,18,1,9,0,11,18,1,9,1,3,3,11,16,1,9,0,11,16,1,9,1,3,1,6,8,17,1,6,11,16,1,9,0,2,11,16,1,9,0,7,8,24,40,1,1,3,3,1,3,3,1,5,3,3,3,7,11,11,1,8,9,11,16,1,9,0,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,3,3,11,16,1,9,0,3,6,8,8,7,8,8,3,3,3,6,11,14,1,3,3,3,8,20,11,16,1,9,1,11,16,1,9,1,1,3,3,3,1,3,7,8,9,3,1,6,11,11,1,9,0,1,11,3,2,9,0,9,1,2,7,11,11,1,9,0,3,1,7,9,0,1,6,11,19,2,9,0,9,1,1,6,11,14,1,9,0,1,6,9,0,2,6,11,19,2,9,0,9,1,9,0,1,6,9,1,3,7,11,13,1,9,0,5,3,2,1,3,2,7,11,16,1,9,0,3,2,7,11,16,1,9,0,11,16,1,9,0,2,7,11,23,2,9,0,9,1,9,0,1,7,9,1,2,7,11,19,2,9,0,9,1,9,0,2,6,11,11,1,9,0,3,1,6,10,9,0,1,11,4,2,9,0,9,1,36,1,3,1,3,3,1,3,3,1,5,3,3,3,7,11,11,1,8,9,11,16,1,9,0,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,3,11,16,1,9,0,3,6,8,8,7,8,8,3,6,11,14,1,3,3,3,8,20,11,16,1,9,1,1,3,3,11,16,1,9,1,3,7,8,9,3,37,1,3,1,3,3,1,3,3,1,5,3,3,3,7,11,11,1,8,9,11,16,1,9,0,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,3,11,16,1,9,1,3,6,8,8,7,8,8,3,3,6,11,14,1,3,3,3,8,20,11,16,1,9,1,1,3,3,11,16,1,9,1,3,7,8,9,3,5,11,16,1,9,0,11,16,1,9,0,11,18,1,9,0,11,16,1,9,1,11,16,1,9,1,2,7,11,18,1,9,0,11,18,1,9,0,3,7,11,18,1,9,0,3,7,8,24,7,3,7,11,11,1,8,9,8,8,3,5,3,3,3,7,11,13,1,9,0,6,8,12,3,3,7,11,11,1,9,0,3,9,0,3,7,11,19,2,9,0,9,1,9,0,9,1,1,11,1,2,9,0,9,1,2,6,11,23,2,9,0,9,1,9,0,3,7,11,23,2,9,0,9,1,9,0,9,1,12,11,16,1,9,0,11,16,1,9,0,11,16,1,9,0,3,3,3,5,11,16,1,9,1,11,16,1,9,1,11,16,1,9,1,3,3,2,6,11,13,1,9,0,5,8,8,20,3,3,1,5,3,3,3,1,11,2,2,9,0,9,1,13,8,20,3,3,3,3,3,3,5,3,1,5,3,3,1,11,5,2,9,0,9,1,11,3,3,6,11,11,1,8,9,7,11,11,1,8,9,3,1,8,8,5,3,3,7,11,19,2,3,3,3,3,7,8,9,8,8,22,3,3,3,3,7,11,11,1,8,9,3,3,3,1,5,3,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,1,7,11,11,1,8,9,8,8,3,3,5,8,20,3,7,11,19,2,3,3,26,5,3,3,3,3,3,6,11,11,1,8,9,7,11,11,1,8,9,3,3,1,3,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,1,3,3,3,8,8,3,5,8,20,3,3,7,11,19,2,3,3,28,1,5,3,3,3,3,3,7,11,11,1,8,9,3,3,3,3,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,1,3,3,3,3,7,11,11,1,8,9,8,8,3,5,8,20,3,3,7,11,19,2,3,3,7,6,8,9,10,8,8,6,8,8,6,11,14,1,3,3,5,6,11,19,2,3,3,5,3,3,5,3,3,4,11,14,1,3,11,14,1,3,11,14,1,3,11,14,1,3,1,11,14,1,9,0,6,3,10,3,3,3,3,10,3,4,3,6,8,8,6,11,14,1,3,6,11,19,2,3,8,8,4,6,11,11,1,8,9,3,5,6,11,19,2,3,3,10,65,99,99,111,117,110,116,67,97,112,17,65,108,108,79,114,100,101,114,115,67,97,110,99,101,108,101,100,26,65,108,108,79,114,100,101,114,115,67,97,110,99,101,108,101,100,67,111,109,112,111,110,101,110,116,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,11,67,114,105,116,98,105,116,84,114,101,101,9,67,117,115,116,111,100,105,97,110,12,68,101,112,111,115,105,116,65,115,115,101,116,2,73,68,11,76,105,110,107,101,100,84,97,98,108,101,6,79,112,116,105,111,110,5,79,114,100,101,114,13,79,114,100,101,114,67,97,110,99,101,108,101,100,11,79,114,100,101,114,70,105,108,108,101,100,11,79,114,100,101,114,80,108,97,99,101,100,4,80,111,111,108,11,80,111,111,108,67,114,101,97,116,101,100,3,83,85,73,5,84,97,98,108,101,9,84,105,99,107,76,101,118,101,108,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,13,87,105,116,104,100,114,97,119,65,115,115,101,116,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,13,97,99,99,111,117,110,116,95,111,119,110,101,114,3,97,100,100,4,97,115,107,115,4,98,97,99,107,7,98,97,108,97,110,99,101,10,98,97,115,101,95,97,115,115,101,116,28,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,99,97,110,99,101,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,102,105,108,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,112,108,97,99,101,100,29,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,114,101,109,97,105,110,105,110,103,23,98,97,115,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,14,98,97,115,101,95,99,117,115,116,111,100,105,97,110,18,98,97,116,99,104,95,99,97,110,99,101,108,95,111,114,100,101,114,4,98,105,100,115,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,17,99,97,110,99,101,108,95,97,108,108,95,111,114,100,101,114,115,12,99,97,110,99,101,108,95,111,114,100,101,114,23,99,108,101,97,110,95,117,112,95,101,120,112,105,114,101,100,95,111,114,100,101,114,115,15,99,108,105,101,110,116,95,111,114,100,101,114,95,105,100,7,99,108,111,98,95,118,50,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,14,99,114,101,97,116,101,95,97,99,99,111,117,110,116,22,99,114,101,97,116,101,95,99,117,115,116,111,109,105,122,101,100,95,112,111,111,108,11,99,114,101,97,116,101,95,112,111,111,108,12,99,114,101,97,116,101,95,112,111,111,108,95,12,99,114,101,97,116,105,111,110,95,102,101,101,7,99,114,105,116,98,105,116,12,99,117,115,116,111,100,105,97,110,95,118,50,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,100,101,112,111,115,105,116,95,98,97,115,101,13,100,101,112,111,115,105,116,95,113,117,111,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,19,100,101,115,116,114,111,121,95,101,109,112,116,121,95,108,101,118,101,108,4,101,109,105,116,19,101,109,105,116,95,111,114,100,101,114,95,99,97,110,99,101,108,101,100,17,101,109,105,116,95,111,114,100,101,114,95,102,105,108,108,101,100,5,101,118,101,110,116,16,101,120,112,105,114,101,95,116,105,109,101,115,116,97,109,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,12,102,114,111,109,95,98,97,108,97,110,99,101,5,102,114,111,110,116,3,103,101,116,22,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,97,115,107,95,115,105,100,101,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,98,105,100,95,115,105,100,101,16,103,101,116,95,109,97,114,107,101,116,95,112,114,105,99,101,16,103,101,116,95,111,114,100,101,114,95,115,116,97,116,117,115,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,18,105,110,106,101,99,116,95,108,105,109,105,116,95,111,114,100,101,114,11,105,110,115,101,114,116,95,108,101,97,102,12,105,110,116,111,95,98,97,108,97,110,99,101,6,105,115,95,98,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,4,106,111,105,110,12,108,105,110,107,101,100,95,116,97,98,108,101,16,108,105,115,116,95,111,112,101,110,95,111,114,100,101,114,115,12,108,111,99,107,95,98,97,108,97,110,99,101,8,108,111,116,95,115,105,122,101,13,109,97,107,101,114,95,97,100,100,114,101,115,115,21,109,97,107,101,114,95,99,108,105,101,110,116,95,111,114,100,101,114,95,105,100,17,109,97,107,101,114,95,114,101,98,97,116,101,95,114,97,116,101,13,109,97,107,101,114,95,114,101,98,97,116,101,115,9,109,97,116,99,104,95,97,115,107,9,109,97,116,99,104,95,98,105,100,29,109,97,116,99,104,95,98,105,100,95,119,105,116,104,95,113,117,111,116,101,95,113,117,97,110,116,105,116,121,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,109,117,108,3,110,101,119,4,110,101,120,116,17,110,101,120,116,95,97,115,107,95,111,114,100,101,114,95,105,100,17,110,101,120,116,95,98,105,100,95,111,114,100,101,114,95,105,100,9,110,101,120,116,95,108,101,97,102,4,110,111,110,101,6,111,98,106,101,99,116,11,111,112,101,110,95,111,114,100,101,114,115,6,111,112,116,105,111,110,8,111,114,100,101,114,95,105,100,12,111,114,100,101,114,95,105,115,95,98,105,100,15,111,114,100,101,114,115,95,99,97,110,99,101,108,101,100,17,111,114,105,103,105,110,97,108,95,113,117,97,110,116,105,116,121,5,111,119,110,101,114,17,112,108,97,99,101,95,108,105,109,105,116,95,111,114,100,101,114,18,112,108,97,99,101,95,109,97,114,107,101,116,95,111,114,100,101,114,7,112,111,111,108,95,105,100,13,112,114,101,118,105,111,117,115,95,108,101,97,102,5,112,114,105,99,101,9,112,117,115,104,95,98,97,99,107,8,113,117,97,110,116,105,116,121,11,113,117,111,116,101,95,97,115,115,101,116,24,113,117,111,116,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,15,113,117,111,116,101,95,99,117,115,116,111,100,105,97,110,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,12,114,101,109,111,118,101,95,111,114,100,101,114,24,115,101,108,102,95,109,97,116,99,104,105,110,103,95,112,114,101,118,101,110,116,105,111,110,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,115,112,108,105,116,3,115,117,105,25,115,119,97,112,95,101,120,97,99,116,95,98,97,115,101,95,102,111,114,95,113,117,111,116,101,25,115,119,97,112,95,101,120,97,99,116,95,113,117,111,116,101,95,102,111,114,95,98,97,115,101,5,116,97,98,108,101,13,116,97,107,101,114,95,97,100,100,114,101,115,115,21,116,97,107,101,114,95,99,108,105,101,110,116,95,111,114,100,101,114,95,105,100,16,116,97,107,101,114,95,99,111,109,109,105,115,115,105,111,110,14,116,97,107,101,114,95,102,101,101,95,114,97,116,101,9,116,105,99,107,95,115,105,122,101,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,10,117,110,115,97,102,101,95,100,105,118,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,15,117,115,114,95,111,112,101,110,95,111,114,100,101,114,115,5,118,97,108,117,101,6,118,101,99,116,111,114,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,13,119,105,116,104,100,114,97,119,95,98,97,115,101,14,119,105,116,104,100,114,97,119,95,113,117,111,116,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,3,8,19,0,0,0,0,0,0,0,3,8,20,0,0,0,0,0,0,0,3,8,21,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,2,1,0,2,1,4,2,1,1,2,1,2,2,1,3,3,8,0,0,0,0,0,0,0,128,3,8,0,0,0,0,0,0,0,0,3,8,160,37,38,0,0,0,0,0,3,8,96,227,22,0,0,0,0,0,3,8,0,232,118,72,23,0,0,0,0,2,7,123,8,20,32,8,15,128,1,8,15,145,1,3,97,3,146,1,3,94,3,1,2,9,123,8,20,116,3,49,3,87,1,120,5,119,3,35,3,125,3,71,3,2,2,8,123,8,20,116,3,49,3,87,1,120,5,119,3,33,3,125,3,3,2,7,116,3,49,3,87,1,120,5,119,3,33,3,125,3,4,2,2,123,8,20,118,10,11,3,2,9,0,9,1,5,2,13,123,8,20,116,3,143,1,3,96,3,87,1,142,1,5,95,5,119,3,34,3,36,3,125,3,144,1,3,98,3,6,2,3,123,8,20,127,3,120,5,7,2,3,123,8,20,127,3,120,5,8,2,9,116,3,49,3,125,3,119,3,127,3,87,1,120,5,71,3,134,1,2,9,2,2,125,3,114,11,19,2,3,8,8,10,2,15,82,8,21,40,11,11,1,8,9,29,11,11,1,8,9,110,3,109,3,156,1,11,23,2,5,11,19,2,3,3,145,1,3,97,3,146,1,3,94,3,38,11,13,1,9,0,130,1,11,13,1,9,1,58,11,16,1,8,22,37,11,16,1,9,0,129,1,11,16,1,9,1,10,59,6,47,6,49,7,47,7,49,3,59,4,59,1,59,2,59,5,59,0,0,0,0,43,7,11,0,19,9,12,1,1,11,1,56,0,2,1,1,0,0,1,3,11,0,17,52,2,2,0,0,0,46,72,56,1,12,6,56,2,12,9,10,3,10,2,17,58,6,0,0,0,0,0,0,0,0,36,4,11,5,15,11,5,1,7,19,39,10,6,10,9,34,4,20,5,24,11,5,1,7,15,39,10,0,10,1,38,4,29,5,33,11,5,1,7,1,39,10,5,17,88,12,8,14,8,17,89,20,12,7,11,8,10,5,56,3,10,5,56,3,7,0,7,27,10,5,56,4,10,0,10,1,10,2,10,3,10,5,56,5,11,5,56,6,11,4,56,7,56,8,57,0,56,9,11,7,11,6,11,9,11,0,11,1,11,2,11,3,18,0,56,10,2,3,1,0,0,1,18,14,2,56,11,7,31,33,4,6,5,10,11,3,1,7,17,39,11,0,11,1,7,29,7,30,11,2,11,3,56,12,2,4,1,0,0,1,19,14,4,56,11,7,31,33,4,6,5,10,11,5,1,7,17,39,11,2,11,3,11,0,11,1,11,4,56,13,11,5,56,14,2,5,1,0,0,21,31,14,1,56,15,12,3,10,3,6,0,0,0,0,0,0,0,0,34,4,8,5,14,11,0,1,11,2,1,7,6,39,10,0,54,0,10,2,17,47,11,1,56,16,56,17,11,0,55,1,17,89,20,11,3,11,2,17,47,57,1,56,18,2,6,1,0,0,21,31,14,1,56,19,12,3,10,3,6,0,0,0,0,0,0,0,0,34,4,8,5,14,11,0,1,11,2,1,7,7,39,10,0,54,2,10,2,17,47,11,1,56,20,56,21,11,0,55,1,17,89,20,11,3,11,2,17,47,57,2,56,22,2,7,1,0,0,1,29,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,10,0,55,1,17,89,20,10,1,10,2,17,47,57,3,56,23,11,0,54,0,11,1,11,2,11,3,56,24,2,8,1,0,0,1,29,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,10,0,55,1,17,89,20,10,1,10,2,17,47,57,4,56,25,11,0,54,2,11,1,11,2,11,3,56,26,2,9,1,0,0,72,55,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,7,1,11,6,1,11,2,1,7,5,39,14,4,56,15,10,3,38,4,21,5,31,11,0,1,11,7,1,11,6,1,11,2,1,7,6,39,14,5,56,19,12,8,11,0,11,2,11,1,11,3,9,11,4,11,5,11,6,11,7,56,27,12,10,12,9,14,10,56,19,12,11,11,9,11,10,11,11,11,8,23,2,10,1,0,0,73,54,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,6,1,11,4,1,11,2,1,7,5,39,14,5,56,19,10,3,38,4,21,5,31,11,0,1,11,6,1,11,4,1,11,2,1,7,7,39,11,0,11,2,11,1,11,3,7,27,11,4,17,70,11,5,56,20,56,28,12,8,12,7,14,7,56,29,12,9,11,7,10,6,56,30,11,8,11,6,56,31,11,9,2,11,0,0,0,77,134,3,10,0,55,1,17,89,20,12,36,11,3,12,42,56,7,12,20,11,6,12,38,10,0,54,3,12,19,10,19,46,56,32,4,27,11,0,1,11,19,1,11,1,1,11,20,11,38,2,10,19,46,56,33,12,44,12,46,9,12,43,64,79,0,0,0,0,0,0,0,0,12,22,10,19,46,56,32,32,4,47,5,42,10,46,10,4,37,12,7,5,49,9,12,7,11,7,4,251,2,10,19,10,44,56,34,12,45,10,45,16,4,56,35,56,36,20,12,35,10,45,16,4,56,37,32,4,217,2,5,67,10,45,16,4,10,35,56,38,12,28,10,28,16,5,20,12,27,9,12,39,10,28,16,6,20,10,5,37,4,87,8,12,11,5,94,10,1,17,47,10,28,16,7,20,33,12,11,11,11,4,151,1,8,12,39,10,0,54,0,10,28,16,7,20,10,28,16,5,20,56,39,10,36,10,28,56,40,10,28,16,8,20,12,12,10,28,16,9,20,12,13,10,28,16,10,20,12,14,10,28,16,7,20,12,15,10,28,16,11,20,12,16,10,28,16,5,20,12,17,10,28,16,12,20,12,18,11,13,11,12,11,14,11,15,11,16,11,17,11,18,57,5,12,21,13,22,11,21,68,79,5,158,2,10,27,10,28,16,12,20,17,56,12,31,10,31,10,0,55,4,20,17,59,12,40,4,168,1,11,40,6,1,0,0,0,0,0,0,0,22,12,40,10,31,11,40,22,12,30,10,42,10,30,36,4,183,1,11,30,12,24,11,31,12,25,10,27,12,23,5,226,1,8,12,43,10,42,7,21,10,0,55,4,20,22,17,57,10,28,16,12,20,17,57,10,0,55,5,20,26,10,0,55,5,20,24,12,23,10,23,10,28,16,12,20,17,58,12,25,10,25,10,0,55,4,20,17,59,12,41,4,222,1,11,41,6,1,0,0,0,0,0,0,0,22,12,41,10,25,11,41,22,12,24,10,25,10,0,55,6,20,17,58,12,32,11,27,10,23,23,12,27,11,42,10,24,23,12,42,10,0,54,0,10,28,16,7,20,10,23,56,41,12,26,13,38,10,24,56,42,12,37,10,0,54,2,10,28,16,7,20,13,37,10,32,10,25,22,56,42,56,21,10,0,54,7,11,37,56,43,1,13,20,11,26,56,44,1,10,0,55,1,17,89,20,10,2,10,1,17,47,10,28,11,23,11,24,11,25,23,11,32,56,45,11,39,4,163,2,8,12,8,5,167,2,10,27,6,0,0,0,0,0,0,0,0,33,12,8,11,8,4,202,2,10,35,12,34,10,45,16,4,10,35,56,46,12,33,10,33,56,47,32,4,185,2,11,33,56,36,20,12,35,5,187,2,11,33,1,10,0,54,8,11,28,16,7,20,56,48,10,34,56,49,1,10,45,15,4,11,34,56,50,1,5,213,2,11,28,1,10,45,15,4,10,35,56,51,12,29,11,27,11,29,15,5,21,10,43,4,216,2,5,217,2,5,61,11,45,16,4,56,37,4,241,2,10,19,11,46,12,9,46,11,9,56,52,1,12,46,10,19,11,44,56,53,17,0,10,19,10,46,12,10,46,11,10,56,54,12,44,1,10,43,4,250,2,11,0,1,11,19,1,11,1,1,5,251,2,5,36,14,22,56,55,32,4,131,3,11,36,11,22,57,6,56,56,11,20,11,38,2,12,0,0,0,97,222,2,10,0,55,1,17,89,20,12,34,11,3,12,37,56,7,12,21,11,6,12,35,10,0,54,3,12,20,10,20,46,56,32,4,27,11,0,1,11,20,1,11,1,1,11,21,11,35,2,10,20,46,56,33,12,40,12,42,64,79,0,0,0,0,0,0,0,0,12,23,10,20,46,56,32,32,4,45,5,40,10,42,10,4,37,12,7,5,47,9,12,7,11,7,4,211,2,10,20,10,40,56,34,12,41,10,41,16,4,56,35,56,36,20,12,33,10,41,16,4,56,37,32,4,175,2,5,65,10,41,16,4,10,33,56,38,12,28,10,28,16,5,20,12,27,9,12,36,10,28,16,6,20,10,5,37,4,85,8,12,12,5,92,10,1,17,47,10,28,16,7,20,33,12,12,11,12,4,149,1,8,12,36,10,0,54,0,10,28,16,7,20,10,28,16,5,20,56,39,10,34,10,28,56,40,10,28,16,8,20,12,13,10,28,16,9,20,12,14,10,28,16,10,20,12,15,10,28,16,7,20,12,16,10,28,16,11,20,12,17,10,28,16,5,20,12,18,10,28,16,12,20,12,19,11,14,11,13,11,15,11,16,11,17,11,18,11,19,57,5,12,22,13,23,11,22,68,79,5,242,1,10,37,10,27,36,4,156,1,10,27,12,8,5,158,1,10,37,12,8,11,8,12,24,10,24,10,28,16,12,20,17,56,12,25,10,25,10,0,55,6,20,17,58,12,30,10,25,10,0,55,4,20,17,59,12,38,4,183,1,11,38,6,1,0,0,0,0,0,0,0,22,12,38,11,27,10,24,23,12,27,11,37,10,24,23,12,37,10,0,54,0,10,28,16,7,20,10,24,56,41,12,26,13,35,10,38,56,42,12,39,10,0,54,2,10,28,16,7,20,13,39,10,30,56,42,56,21,10,0,54,7,11,39,56,43,1,13,21,11,26,56,44,1,10,0,54,2,10,28,16,7,20,13,35,11,25,56,42,56,21,10,0,55,1,17,89,20,10,2,10,1,17,47,10,28,11,24,11,38,11,30,56,45,11,36,4,247,1,8,12,9,5,251,1,10,27,6,0,0,0,0,0,0,0,0,33,12,9,11,9,4,158,2,10,33,12,32,10,41,16,4,10,33,56,46,12,31,10,31,56,47,32,4,141,2,11,31,56,36,20,12,33,5,143,2,11,31,1,10,0,54,8,11,28,16,7,20,56,48,10,32,56,49,1,10,41,15,4,11,32,56,50,1,5,169,2,11,28,1,10,41,15,4,10,33,56,51,12,29,11,27,11,29,15,5,21,10,37,6,0,0,0,0,0,0,0,0,33,4,174,2,5,175,2,5,59,11,41,16,4,56,37,4,199,2,10,20,11,42,12,10,46,11,10,56,52,1,12,42,10,20,11,40,56,53,17,0,10,20,10,42,12,11,46,11,11,56,54,12,40,1,10,37,6,0,0,0,0,0,0,0,0,33,4,210,2,11,0,1,11,20,1,11,1,1,5,211,2,5,34,14,23,56,55,32,4,219,2,11,34,11,23,57,6,56,56,11,21,11,35,2,13,0,0,0,98,227,2,10,0,55,1,17,89,20,12,34,11,5,12,20,56,8,12,35,10,0,54,9,12,19,10,19,46,56,32,4,25,11,0,1,11,19,1,11,1,1,11,20,11,35,2,10,19,46,56,57,12,40,12,42,64,79,0,0,0,0,0,0,0,0,12,22,10,19,46,56,32,32,4,43,5,38,10,42,10,3,38,12,6,5,45,9,12,6,11,6,4,216,2,10,19,10,40,56,34,12,41,10,41,16,4,56,35,56,36,20,12,33,10,41,16,4,56,37,32,4,179,2,5,63,10,41,16,4,10,33,56,38,12,27,10,27,16,5,20,12,26,9,12,36,10,27,16,6,20,10,4,37,4,83,8,12,11,5,90,10,1,17,47,10,27,16,7,20,33,12,11,11,11,4,153,1,8,12,36,10,27,16,5,20,10,27,16,12,20,17,56,12,29,10,0,54,2,10,27,16,7,20,11,29,56,58,10,34,10,27,56,40,10,27,16,8,20,12,12,10,27,16,9,20,12,13,10,27,16,10,20,12,14,10,27,16,7,20,12,15,10,27,16,11,20,12,16,10,27,16,5,20,12,17,10,27,16,12,20,12,18,11,13,11,12,11,14,11,15,11,16,11,17,11,18,57,5,12,21,13,22,11,21,68,79,5,245,1,14,20,56,29,12,37,10,37,10,26,38,4,163,1,10,26,12,7,5,165,1,11,37,12,7,11,7,12,23,10,23,10,27,16,12,20,17,56,12,24,10,24,10,0,55,6,20,17,58,12,30,10,24,10,0,55,4,20,17,59,12,38,4,190,1,11,38,6,1,0,0,0,0,0,0,0,22,12,38,11,26,10,23,23,12,26,10,0,54,2,10,27,16,7,20,11,24,56,59,12,25,13,25,10,38,56,42,12,39,10,0,54,2,10,27,16,7,20,13,39,10,30,56,42,56,21,10,0,54,7,11,39,56,43,1,13,35,11,25,56,43,1,10,0,54,0,10,27,16,7,20,13,20,10,23,56,60,56,17,10,0,55,1,17,89,20,10,2,10,1,17,47,10,27,11,23,11,38,11,30,56,45,11,36,4,250,1,8,12,8,5,254,1,10,26,6,0,0,0,0,0,0,0,0,33,12,8,11,8,4,161,2,10,33,12,32,10,41,16,4,10,33,56,46,12,31,10,31,56,47,32,4,144,2,11,31,56,36,20,12,33,5,146,2,11,31,1,10,0,54,8,11,27,16,7,20,56,48,10,32,56,49,1,10,41,15,4,11,32,56,50,1,5,172,2,11,27,1,10,41,15,4,10,33,56,51,12,28,11,26,11,28,15,5,21,14,20,56,29,6,0,0,0,0,0,0,0,0,33,4,178,2,5,179,2,5,57,11,41,16,4,56,37,4,203,2,10,19,11,42,12,9,46,11,9,56,61,1,12,42,10,19,11,40,56,53,17,0,10,19,10,42,12,10,46,11,10,56,54,12,40,1,14,20,56,29,6,0,0,0,0,0,0,0,0,33,4,215,2,11,0,1,11,19,1,11,1,1,5,216,2,5,32,14,22,56,55,32,4,224,2,11,34,11,22,57,6,56,56,11,20,11,35,2,14,1,0,0,99,103,10,3,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,9,5,19,11,0,1,11,8,1,11,7,1,11,1,1,7,5,39,10,3,6,0,0,0,0,0,0,0,0,34,4,24,5,34,11,0,1,11,8,1,11,7,1,11,1,1,7,5,39,11,4,4,58,11,0,11,1,11,2,11,3,7,27,11,7,17,70,11,6,56,20,56,62,12,13,12,9,13,5,11,9,10,8,56,30,56,63,11,13,11,8,56,31,12,6,5,100,10,3,14,5,56,15,37,4,64,5,74,11,0,1,11,8,1,11,7,1,11,1,1,7,6,39,13,5,11,3,10,8,56,64,12,11,11,0,11,1,11,2,7,28,11,7,17,70,11,11,56,16,56,65,12,12,12,10,13,5,11,10,10,8,56,30,56,63,13,6,11,12,11,8,56,31,56,66,11,5,11,6,2,15,0,0,0,102,123,10,8,17,47,12,14,10,5,4,30,10,4,10,2,17,56,12,15,10,0,54,2,11,8,11,15,56,67,10,0,55,10,20,12,13,10,0,55,10,20,6,1,0,0,0,0,0,0,0,22,10,0,54,10,21,10,0,54,9,12,11,5,50,10,0,54,0,11,8,10,4,56,68,10,0,55,11,20,12,13,10,0,55,11,20,6,1,0,0,0,0,0,0,0,22,10,0,54,11,21,10,0,54,3,12,11,10,13,10,1,10,2,10,3,10,4,10,5,10,14,10,7,11,6,18,8,12,12,10,11,10,2,12,10,46,11,10,56,54,12,16,32,4,78,10,11,10,2,10,2,10,9,56,69,18,9,56,70,12,16,11,11,11,16,56,34,15,4,10,13,11,12,56,71,10,0,55,1,17,89,20,10,13,11,1,11,5,10,14,11,3,11,4,10,2,11,7,57,7,56,72,10,0,55,8,10,14,56,73,32,4,112,10,0,54,8,10,14,11,9,56,74,56,75,5,114,11,9,1,11,0,54,8,11,14,56,48,10,13,11,2,56,76,11,13,2,16,1,0,0,109,171,2,10,4,7,22,33,4,5,5,15,11,0,1,11,10,1,11,8,1,11,9,1,7,20,39,10,3,6,0,0,0,0,0,0,0,0,36,4,20,5,30,11,0,1,11,10,1,11,8,1,11,9,1,7,5,39,10,2,6,0,0,0,0,0,0,0,0,36,4,35,5,45,11,0,1,11,10,1,11,8,1,11,9,1,7,4,39,10,2,10,0,55,12,20,25,6,0,0,0,0,0,0,0,0,33,4,54,5,64,11,0,1,11,10,1,11,8,1,11,9,1,7,4,39,10,3,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,73,5,83,11,0,1,11,10,1,11,8,1,11,9,1,7,5,39,10,6,10,8,17,70,36,4,89,5,99,11,0,1,11,10,1,11,8,1,11,9,1,7,18,39,10,9,17,47,12,17,10,3,12,16,10,5,4,147,1,10,0,55,2,10,17,56,77,12,22,10,0,54,2,10,9,10,22,56,78,12,18,10,0,10,9,10,1,10,3,10,2,11,8,17,70,11,18,56,62,12,20,12,12,14,12,56,29,12,14,11,22,14,20,56,79,23,12,21,10,0,54,0,10,17,11,12,56,17,10,0,54,2,11,17,11,20,56,21,5,181,1,10,0,54,0,10,9,10,3,56,80,12,11,10,0,10,9,10,1,10,2,11,8,17,70,11,11,56,65,12,19,12,13,10,3,14,13,56,29,23,12,14,14,19,56,79,12,21,10,0,54,0,10,17,11,13,56,17,10,0,54,2,11,17,11,19,56,21,10,7,7,24,33,4,196,1,11,0,1,11,10,1,11,9,1,11,14,11,21,9,6,0,0,0,0,0,0,0,0,2,10,7,7,25,33,4,218,1,11,0,1,11,10,1,11,9,1,10,14,11,3,33,4,211,1,5,213,1,7,8,39,11,14,11,21,9,6,0,0,0,0,0,0,0,0,2,10,7,7,26,33,4,252,1,10,14,6,0,0,0,0,0,0,0,0,33,4,227,1,5,235,1,11,0,1,11,10,1,11,9,1,7,9,39,11,0,11,1,11,2,11,16,11,3,11,5,11,4,11,6,11,9,11,10,56,81,12,15,11,14,11,21,8,11,15,2,11,7,7,22,33,4,129,2,5,137,2,11,0,1,11,10,1,11,9,1,7,13,39,10,3,10,14,36,4,160,2,11,0,11,1,11,2,11,16,11,3,10,14,23,11,5,11,4,11,6,11,9,11,10,56,81,12,15,11,14,11,21,8,11,15,2,11,0,1,11,10,1,11,9,1,11,14,11,21,9,6,0,0,0,0,0,0,0,0,2,17,0,0,0,1,4,11,0,7,27,35,2,18,0,0,0,111,41,11,0,12,2,10,1,16,8,20,12,3,10,1,16,9,20,12,4,10,1,16,10,20,12,5,10,1,16,7,20,12,6,10,1,16,11,20,12,7,10,1,16,5,20,12,8,11,1,16,12,20,12,9,11,2,11,4,11,3,11,5,11,6,11,7,11,8,11,9,57,8,56,82,2,19,0,0,0,113,58,11,0,12,7,10,3,16,9,20,12,12,11,1,12,13,11,2,12,14,10,3,16,8,20,12,15,10,3,16,10,20,12,16,10,3,16,7,20,12,17,10,3,16,11,20,12,18,10,4,12,19,10,3,16,5,20,11,4,23,12,8,11,3,16,12,20,12,9,11,5,12,10,11,6,12,11,11,7,11,12,11,13,11,15,11,16,11,14,11,17,11,18,11,19,11,8,11,9,11,10,11,11,57,9,56,83,2,20,1,0,0,115,115,11,2,17,47,12,10,10,0,55,8,10,10,56,73,4,9,5,13,11,0,1,7,11,39,10,0,54,8,10,10,56,48,12,13,10,13,10,1,12,3,46,11,3,56,84,4,26,5,32,11,13,1,11,0,1,7,2,39,10,13,10,1,12,4,46,11,4,56,85,20,12,12,10,1,17,17,12,8,10,8,4,49,10,0,55,9,12,5,5,52,10,0,55,3,12,5,11,5,11,12,56,54,12,11,4,58,5,64,11,13,1,11,0,1,7,2,39,10,8,4,70,10,0,54,9,12,6,5,73,10,0,54,3,12,6,11,6,11,13,11,11,11,1,10,10,56,86,12,9,11,8,4,101,14,9,16,5,20,14,9,16,12,20,17,59,12,7,4,95,11,7,6,1,0,0,0,0,0,0,0,22,12,7,10,0,54,2,11,10,11,7,56,58,5,108,10,0,54,0,11,10,14,9,16,5,20,56,39,11,0,55,1,17,89,20,14,9,56,40,2,21,0,0,0,116,54,11,1,10,3,56,49,1,10,0,10,2,12,5,46,11,5,56,87,16,4,10,3,56,88,4,15,5,19,11,0,1,7,2,39,10,0,10,2,56,34,12,6,10,6,15,4,11,3,56,50,12,7,14,7,16,7,20,11,4,33,4,35,5,41,11,0,1,11,6,1,7,3,39,11,6,16,4,56,37,4,50,11,0,11,2,56,53,17,0,5,52,11,0,1,11,7,2,22,1,0,0,117,154,1,10,0,55,1,17,89,20,12,21,11,1,17,47,12,20,10,0,55,8,10,20,56,73,4,14,5,18,11,0,1,7,11,39,10,0,54,8,10,20,56,48,12,23,64,79,0,0,0,0,0,0,0,0,12,14,10,23,46,56,89,32,4,141,1,5,31,10,23,46,56,90,56,36,20,12,18,10,23,10,18,12,5,46,11,5,56,85,20,12,19,10,18,17,17,12,15,10,15,4,54,10,0,54,9,12,6,5,57,10,0,54,3,12,6,11,6,12,16,10,16,11,19,12,7,46,11,7,56,54,12,22,1,11,16,10,23,11,22,11,18,10,20,56,86,12,17,11,15,4,90,14,17,16,5,20,14,17,16,12,20,17,56,12,12,10,0,54,2,10,20,11,12,56,58,5,97,10,0,54,0,10,20,14,17,16,5,20,56,39,10,21,14,17,56,40,14,17,16,8,20,12,8,14,17,16,9,20,12,9,14,17,16,10,20,12,10,14,17,16,7,20,12,11,14,17,16,11,20,12,2,14,17,16,5,20,12,3,14,17,16,12,20,12,4,11,9,11,8,11,10,11,11,11,2,11,3,11,4,57,5,12,13,13,14,11,13,68,79,5,25,11,23,1,11,0,1,14,14,56,55,32,4,153,1,11,21,11,14,57,6,56,56,2,23,1,0,0,118,203,1,10,0,55,1,17,89,20,12,25,11,2,17,47,12,24,10,0,55,8,10,24,56,73,4,14,5,18,11,0,1,6,0,0,0,0,0,0,0,0,39,6,0,0,0,0,0,0,0,0,12,26,6,0,0,0,0,0,0,0,0,12,27,14,1,65,21,12,19,6,0,0,0,0,0,0,0,0,12,17,10,0,54,8,10,24,56,48,12,28,64,79,0,0,0,0,0,0,0,0,12,16,10,17,10,19,35,4,190,1,5,39,14,1,10,17,66,21,20,12,23,10,28,10,23,12,7,46,11,7,56,84,4,52,5,58,11,28,1,11,0,1,7,2,39,10,28,10,23,12,8,46,11,8,56,85,20,12,21,10,23,17,17,12,18,10,21,10,27,34,4,98,11,21,12,27,10,18,4,81,10,0,55,9,12,9,5,84,10,0,55,3,12,9,11,9,10,27,56,54,12,20,4,90,5,96,11,28,1,11,0,1,7,10,39,11,20,12,26,10,18,4,104,10,0,54,9,12,10,5,107,10,0,54,3,12,10,11,10,10,28,10,26,11,23,10,24,56,86,12,22,11,18,4,135,1,14,22,16,5,20,14,22,16,12,20,17,59,12,14,4,129,1,11,14,6,1,0,0,0,0,0,0,0,22,12,14,10,0,54,2,10,24,11,14,56,58,5,142,1,10,0,54,0,10,24,14,22,16,5,20,56,39,10,25,14,22,56,40,14,22,16,8,20,12,11,14,22,16,9,20,12,12,14,22,16,10,20,12,13,14,22,16,7,20,12,3,14,22,16,11,20,12,4,14,22,16,5,20,12,5,14,22,16,12,20,12,6,11,12,11,11,11,13,11,3,11,4,11,5,11,6,57,5,12,15,13,16,11,15,68,79,11,17,6,1,0,0,0,0,0,0,0,22,12,17,5,34,11,28,1,11,0,1,14,16,56,55,32,4,202,1,11,25,11,16,57,6,56,56,2,24,1,0,0,119,214,1,10,0,55,1,17,89,20,12,28,11,1,17,70,12,23,14,2,65,21,12,20,10,20,14,3,65,65,33,4,17,5,21,11,0,1,7,12,39,6,0,0,0,0,0,0,0,0,12,18,6,0,0,0,0,0,0,0,0,12,29,6,0,0,0,0,0,0,0,0,12,30,64,79,0,0,0,0,0,0,0,0,12,17,10,18,10,20,35,4,203,1,5,34,14,2,10,18,66,21,20,12,26,14,3,10,18,66,65,20,12,27,10,0,55,8,10,27,56,73,32,4,51,5,29,10,0,54,8,10,27,56,48,12,31,10,31,10,26,12,9,46,11,9,56,84,32,4,67,11,31,1,5,29,10,31,10,26,12,10,46,11,10,56,85,20,12,22,10,26,17,17,12,19,10,19,4,84,10,0,54,9,12,11,5,87,10,0,54,3,12,11,11,11,12,24,10,22,10,30,34,4,114,11,22,12,30,10,24,10,30,12,12,46,11,12,56,54,12,21,4,104,5,112,11,31,1,11,0,1,11,24,1,7,10,39,11,21,12,29,11,24,11,31,10,29,11,26,10,27,56,86,12,25,14,25,16,6,20,10,23,35,4,128,1,5,132,1,11,0,1,7,18,39,11,19,4,148,1,14,25,16,5,20,14,25,16,12,20,17,56,12,15,10,0,54,2,11,27,11,15,56,58,5,155,1,10,0,54,0,11,27,14,25,16,5,20,56,39,10,28,14,25,56,40,14,25,16,8,20,12,13,14,25,16,9,20,12,14,14,25,16,10,20,12,4,14,25,16,7,20,12,5,14,25,16,11,20,12,6,14,25,16,5,20,12,7,14,25,16,12,20,12,8,11,14,11,13,11,4,11,5,11,6,11,7,11,8,57,5,12,16,13,17,11,16,68,79,11,18,6,1,0,0,0,0,0,0,0,22,12,18,5,29,11,0,1,14,17,56,55,32,4,213,1,11,28,11,17,57,6,56,56,2,25,1,0,0,120,93,11,1,17,47,12,7,10,0,55,8,11,7,56,91,12,8,64,29,0,0,0,0,0,0,0,0,12,3,10,8,56,92,12,5,10,5,56,47,32,4,85,5,18,10,8,10,5,56,36,20,56,85,20,12,6,10,5,56,36,20,17,17,4,36,10,0,55,9,11,6,56,93,12,2,5,41,10,0,55,3,11,6,56,93,12,2,11,2,16,4,10,5,56,36,20,56,38,12,4,13,3,10,4,16,9,20,10,4,16,8,20,10,4,16,12,20,10,4,16,11,20,10,4,16,5,20,10,4,16,10,20,10,4,16,7,20,10,4,16,6,20,11,4,16,22,20,18,8,68,29,10,8,11,5,56,36,20,56,94,12,5,5,13,11,8,1,11,0,1,11,5,1,11,3,2,26,1,0,0,121,20,11,1,17,47,12,4,10,0,55,0,10,4,56,95,12,3,12,2,11,0,55,2,11,4,56,96,12,6,12,5,11,2,11,3,11,5,11,6,2,27,1,0,0,122,37,10,0,55,9,56,32,32,4,12,10,0,55,9,56,57,1,56,97,12,1,5,14,56,98,12,1,11,1,12,4,10,0,55,3,56,32,32,4,28,11,0,55,3,56,33,1,56,97,12,2,5,32,11,0,1,56,98,12,2,11,2,12,3,11,4,11,3,2,28,1,0,0,124,90,64,21,0,0,0,0,0,0,0,0,12,9,64,21,0,0,0,0,0,0,0,0,12,5,10,0,55,9,56,32,4,15,11,0,1,11,3,1,11,9,11,5,2,10,0,55,9,56,33,1,12,8,10,1,10,8,35,4,26,11,8,12,1,10,0,55,9,56,57,1,12,7,10,2,10,7,36,4,37,11,7,12,2,10,0,55,9,11,1,56,99,12,1,10,0,55,9,11,2,56,99,12,2,10,1,10,2,37,4,87,5,52,10,0,55,9,10,1,10,3,17,70,56,100,12,4,10,4,6,0,0,0,0,0,0,0,0,34,4,69,13,9,10,1,68,21,13,5,11,4,68,21,10,0,55,9,11,1,56,52,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,84,11,0,1,11,3,1,5,87,11,6,12,1,5,47,11,9,11,5,2,29,1,0,0,124,90,64,21,0,0,0,0,0,0,0,0,12,9,64,21,0,0,0,0,0,0,0,0,12,5,10,0,55,3,56,32,4,15,11,0,1,11,3,1,11,9,11,5,2,10,0,55,3,56,33,1,12,8,10,1,10,8,35,4,26,11,8,12,1,10,0,55,3,56,57,1,12,7,10,2,10,7,36,4,37,11,7,12,2,10,0,55,3,11,1,56,99,12,1,10,0,55,3,11,2,56,99,12,2,10,1,10,2,37,4,87,5,52,10,0,55,3,10,1,10,3,17,70,56,100,12,4,10,4,6,0,0,0,0,0,0,0,0,34,4,69,13,9,10,1,68,21,13,5,11,4,68,21,10,0,55,3,11,1,56,52,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,84,11,0,1,11,3,1,5,87,11,6,12,1,5,47,11,9,11,5,2,30,0,0,0,125,49,11,0,11,1,56,93,16,4,12,6,6,0,0,0,0,0,0,0,0,12,3,10,6,56,35,12,5,10,5,56,47,32,4,43,5,15,10,6,10,5,56,36,20,56,38,12,4,10,4,16,6,20,10,2,36,4,34,11,3,11,4,16,5,20,22,12,3,5,36,11,4,1,10,6,11,5,56,36,20,56,46,12,5,5,10,11,6,1,11,5,1,11,3,2,31,1,0,0,126,52,11,2,17,47,12,5,10,0,55,8,10,5,56,73,4,9,5,13,11,0,1,7,11,39,10,0,55,8,11,5,56,91,12,6,10,6,10,1,56,84,4,23,5,29,11,6,1,11,0,1,7,2,39,11,6,10,1,56,85,20,12,4,10,1,7,27,35,4,42,11,0,55,9,12,3,5,45,11,0,55,3,12,3,11,3,11,4,56,93,16,4,11,1,56,38,2,10,10,10,0,10,11,10,2,9,1,8,4,8,7,8,6,8,1,8,0,8,5,8,3,8,2,10,6,10,9,10,7,10,14,10,5,10,1,10,3,10,4,10,8,8,8,0,59,1,59,2,59,3,59,13,59,14,59,15,59,16,59,17,59,18,59,19,59,20,59,21,59,0],"critbit":[161,28,235,11,6,0,0,0,14,1,0,8,2,8,28,3,36,194,1,4,230,1,54,5,156,2,232,1,7,132,4,166,4,8,170,8,64,6,234,8,120,10,226,9,51,11,149,10,4,12,153,10,173,14,13,198,24,28,14,226,24,20,15,246,24,4,0,14,0,30,1,45,1,46,0,2,6,1,0,0,0,1,6,0,0,0,4,1,4,0,2,3,12,2,7,1,4,1,3,4,2,0,0,33,0,1,1,4,0,44,2,3,1,4,0,22,2,4,1,4,0,32,2,5,1,4,0,31,2,5,1,4,0,38,6,5,1,4,0,35,6,5,1,4,0,27,6,3,1,4,0,42,6,3,1,4,0,20,7,3,1,4,0,18,6,8,1,4,0,17,6,3,1,4,0,40,9,10,1,4,0,10,9,11,1,4,0,7,6,12,1,4,0,8,6,12,1,4,0,16,1,13,1,6,0,15,1,13,1,4,0,19,6,3,1,4,0,47,14,13,1,4,0,23,15,4,1,4,1,13,25,26,0,2,5,24,13,2,7,4,2,6,20,21,2,7,4,2,9,28,30,2,7,4,2,15,17,13,2,7,4,2,16,17,13,2,7,6,2,22,19,4,2,7,4,2,28,19,3,2,7,4,2,33,0,17,2,7,4,2,39,28,29,2,7,4,29,16,29,18,28,18,27,18,2,10,23,18,10,10,20,10,23,16,8,10,7,10,22,18,18,10,22,16,19,10,6,10,5,10,30,18,1,10,24,16,24,18,30,16,14,10,26,16,26,18,25,18,25,16,1,7,8,4,1,11,2,1,9,0,1,6,11,2,1,9,0,1,3,1,1,2,3,3,2,6,11,2,1,9,0,3,3,7,11,2,1,9,0,3,9,0,2,1,3,2,7,11,2,1,9,0,3,1,9,0,1,7,9,0,1,6,9,0,0,4,7,11,2,1,9,0,3,3,1,3,6,11,2,1,9,0,3,3,2,3,8,1,1,11,3,2,9,0,9,1,2,3,11,0,1,9,0,1,6,11,3,2,9,0,9,1,2,6,11,3,2,9,0,9,1,9,0,1,6,9,1,4,1,3,3,3,16,3,3,3,3,3,2,6,8,1,1,1,8,1,3,3,11,0,1,9,0,3,3,3,3,7,11,3,2,9,0,9,1,9,0,9,1,1,4,1,2,16,3,3,3,3,3,3,3,3,3,1,3,3,6,8,1,3,3,9,0,2,7,11,3,2,9,0,9,1,9,0,1,9,1,1,7,9,1,2,11,3,2,3,8,1,11,3,2,3,11,0,1,9,0,2,6,8,1,3,11,67,114,105,116,98,105,116,84,114,101,101,12,73,110,116,101,114,110,97,108,78,111,100,101,4,76,101,97,102,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,4,99,108,111,98,7,99,108,111,98,95,118,50,19,99,111,117,110,116,95,108,101,97,100,105,110,103,95,122,101,114,111,115,7,99,114,105,116,98,105,116,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,29,103,101,116,95,99,108,111,115,101,115,116,95,108,101,97,102,95,105,110,100,101,120,95,98,121,95,107,101,121,11,105,110,115,101,114,116,95,108,101,97,102,14,105,110,116,101,114,110,97,108,95,110,111,100,101,115,8,105,115,95,101,109,112,116,121,13,105,115,95,108,101,102,116,95,99,104,105,108,100,3,107,101,121,6,108,101,97,118,101,115,10,108,101,102,116,95,99,104,105,108,100,14,108,101,102,116,95,109,111,115,116,95,108,101,97,102,6,108,101,110,103,116,104,4,109,97,115,107,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,3,110,101,119,24,110,101,120,116,95,105,110,116,101,114,110,97,108,95,110,111,100,101,95,105,110,100,101,120,9,110,101,120,116,95,108,101,97,102,15,110,101,120,116,95,108,101,97,102,95,105,110,100,101,120,6,112,97,114,101,110,116,13,112,114,101,118,105,111,117,115,95,108,101,97,102,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,11,114,105,103,104,116,95,99,104,105,108,100,15,114,105,103,104,116,95,109,111,115,116,95,108,101,97,102,4,114,111,111,116,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,112,100,97,116,101,95,99,104,105,108,100,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,128,3,8,255,255,255,255,255,255,255,255,3,8,255,255,255,255,255,255,255,127,0,2,3,24,3,48,9,0,37,3,1,2,4,29,3,26,3,41,3,37,3,2,2,7,43,3,21,11,3,2,3,8,1,25,11,3,2,3,11,0,1,9,0,32,3,31,3,34,3,36,3,2,10,0,10,0,3,0,0,13,11,7,9,10,0,56,0,11,0,56,1,7,9,7,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,57,0,2,1,3,0,0,13,4,11,0,55,0,56,2,2,2,3,0,0,13,4,11,0,55,0,56,3,2,3,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,1,20,56,5,55,2,20,11,0,55,1,20,2,4,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,0,55,3,20,2,5,1,0,0,22,78,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,36,5,30,10,0,10,4,11,5,56,7,12,2,5,38,9,12,2,11,2,4,50,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,59,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,7,20,56,9,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,6,3,0,0,22,79,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,37,5,30,10,0,10,4,11,5,56,7,32,12,2,5,39,9,12,2,11,2,4,51,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,60,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,8,20,56,10,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,7,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,7,20,12,2,5,2,11,0,1,11,2,2,8,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,8,20,12,2,5,2,11,0,1,11,2,2,9,3,0,0,23,247,1,10,1,11,2,7,9,57,1,12,15,10,0,55,6,20,12,16,10,0,55,6,20,6,1,0,0,0,0,0,0,0,22,10,0,54,6,21,10,16,7,11,6,1,0,0,0,0,0,0,0,23,35,4,24,5,28,11,0,1,7,1,39,10,0,54,0,10,16,11,15,56,11,10,0,10,1,12,3,46,11,3,56,12,12,7,10,7,7,9,33,4,69,10,16,6,0,0,0,0,0,0,0,0,33,4,49,5,53,11,0,1,7,2,39,7,10,10,16,23,10,0,54,7,21,10,16,10,0,54,1,21,11,16,11,0,54,3,21,6,0,0,0,0,0,0,0,0,2,10,0,55,0,11,7,56,5,55,2,20,12,6,10,6,10,1,34,4,81,5,85,11,0,1,7,3,39,49,64,11,6,10,1,29,53,17,21,49,64,23,23,12,8,6,1,0,0,0,0,0,0,0,11,8,49,1,23,47,12,17,10,17,7,9,7,9,7,9,18,1,12,12,10,0,55,8,20,12,13,10,0,55,8,20,6,1,0,0,0,0,0,0,0,22,10,0,54,8,21,10,0,54,5,10,13,11,12,56,13,10,0,55,7,20,12,18,7,9,12,14,10,18,7,9,35,4,169,1,5,135,1,10,0,55,5,10,18,56,8,12,9,10,17,10,9,16,12,20,36,4,149,1,11,9,1,5,169,1,11,18,12,14,10,1,10,9,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,164,1,11,9,16,7,20,12,18,5,168,1,11,9,16,8,20,12,18,5,130,1,10,14,7,9,33,4,178,1,10,13,10,0,54,7,21,5,193,1,10,0,10,14,10,18,12,5,12,4,46,11,4,11,5,56,7,12,10,10,0,11,14,10,13,11,10,56,14,11,17,10,1,28,6,0,0,0,0,0,0,0,0,33,12,11,10,0,10,13,7,10,10,16,23,10,11,56,14,10,0,11,13,11,18,11,11,32,56,14,10,0,55,0,10,0,55,1,20,56,5,55,2,20,10,1,36,4,227,1,10,16,10,0,54,1,21,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,1,35,4,243,1,10,16,11,0,54,3,21,5,245,1,11,0,1,11,16,2,10,3,0,0,3,27,10,0,56,4,4,8,11,0,1,9,7,9,2,10,0,10,1,56,12,12,2,11,0,55,0,10,2,56,5,55,2,20,11,1,34,4,24,9,7,9,2,8,11,2,2,11,3,0,0,3,18,10,0,56,4,4,7,11,0,1,6,0,0,0,0,0,0,0,0,2,10,0,11,1,56,12,12,2,11,0,55,0,11,2,56,5,55,2,20,2,12,3,0,0,27,171,1,10,0,55,0,10,1,56,5,55,2,20,12,12,10,0,55,1,20,10,1,33,4,25,10,0,10,12,12,4,46,11,4,56,15,12,9,1,11,9,10,0,54,1,21,10,0,55,3,20,10,1,33,4,43,10,0,11,12,12,5,46,11,5,56,16,12,10,1,11,10,10,0,54,3,21,10,0,54,0,10,1,56,17,58,1,12,15,12,17,1,10,0,46,56,18,6,0,0,0,0,0,0,0,0,33,4,78,7,9,10,0,54,7,21,7,9,10,0,54,1,21,7,9,10,0,54,3,21,6,0,0,0,0,0,0,0,0,10,0,54,8,21,6,0,0,0,0,0,0,0,0,11,0,54,6,21,5,169,1,10,15,7,9,34,4,83,5,87,11,0,1,7,6,39,10,0,55,5,10,15,56,8,12,14,10,14,16,6,20,12,13,10,0,10,15,7,10,11,1,23,12,7,12,6,46,11,6,11,7,56,7,4,113,11,14,16,8,20,12,8,5,117,11,14,16,7,20,12,8,11,8,12,16,10,13,7,9,33,4,149,1,10,16,7,9,35,4,135,1,7,9,10,0,54,5,10,16,56,19,15,6,21,5,144,1,7,9,10,0,54,0,7,10,10,16,23,56,20,54,4,21,11,16,10,0,54,7,21,5,164,1,10,0,10,13,10,15,12,3,12,2,46,11,2,11,3,56,7,12,11,10,0,11,13,11,16,11,11,56,14,11,0,54,5,11,15,56,21,1,11,17,2,13,3,0,0,13,6,11,0,54,0,11,1,56,20,54,9,2,14,3,0,0,13,6,11,0,55,0,11,1,56,5,55,9,2,15,3,0,0,3,14,10,0,11,1,56,6,12,2,4,6,5,10,11,0,1,7,4,39,11,0,11,2,56,22,2,16,3,0,0,31,14,11,0,58,0,1,1,1,1,12,2,12,1,1,11,1,56,23,11,2,56,24,2,17,3,0,0,31,23,14,0,55,0,56,2,6,0,0,0,0,0,0,0,0,33,4,7,5,9,6,0,0,0,0,0,0,0,0,39,11,0,58,0,1,1,1,1,12,2,12,1,1,11,2,56,25,11,1,56,26,2,18,0,0,0,32,46,10,0,55,7,20,12,3,10,3,7,9,33,4,12,11,0,1,7,9,2,10,3,7,9,35,4,40,5,17,10,0,55,5,11,3,56,8,12,2,10,1,10,2,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,35,11,2,16,7,20,12,3,5,39,11,2,16,8,20,12,3,5,12,11,0,1,7,10,11,3,23,2,19,0,0,0,13,48,10,1,7,9,34,4,5,5,9,11,0,1,7,7,39,11,3,4,19,10,2,10,0,54,5,10,1,56,19,15,7,21,5,26,10,2,10,0,54,5,10,1,56,19,15,8,21,10,2,7,9,36,4,40,11,1,11,0,54,0,7,10,11,2,23,56,20,54,4,21,5,47,11,1,11,0,54,5,11,2,56,19,15,6,21,2,20,0,0,0,13,9,11,0,55,5,11,1,56,8,16,7,20,11,2,33,2,2,2,2,3,0,0,2,4,0,2,2,1,1,3,1,1,1,2,2,6,2,0,2,5,1,0,0,1,0,10,1,10,2,10,3,10,4,10,5,10,9,10,10,10,11,10,13,10,0,11,0,12,0],"custodian":[161,28,235,11,6,0,0,0,14,1,0,12,2,12,48,3,60,158,1,4,218,1,30,5,248,1,246,1,7,238,3,166,4,8,148,8,64,6,212,8,10,10,222,8,38,11,132,9,4,12,136,9,238,2,13,246,11,8,14,254,11,6,15,132,12,2,0,23,1,15,1,21,1,35,1,37,1,38,0,0,4,1,0,1,0,1,12,0,0,4,12,1,0,1,1,2,4,1,0,1,2,3,12,1,0,1,3,5,7,0,3,8,4,0,4,6,12,2,7,1,4,1,5,7,2,0,0,33,0,1,0,0,10,2,3,1,0,0,34,0,4,1,0,0,42,5,6,1,0,0,28,7,8,1,0,0,24,9,10,1,0,0,29,11,8,1,0,0,25,12,10,1,0,0,31,9,8,1,0,0,40,12,8,1,0,0,9,2,13,1,0,0,12,2,13,1,0,0,19,14,15,1,0,0,17,2,16,1,0,1,30,27,13,1,0,1,36,30,10,1,0,1,41,24,13,1,0,1,43,8,10,1,0,2,26,26,6,1,0,3,34,0,17,0,3,39,28,29,0,4,13,31,8,2,7,4,4,16,21,23,2,7,4,4,18,32,33,2,7,4,4,22,21,22,2,7,4,4,34,0,25,2,7,4,24,20,22,20,16,19,25,20,5,19,18,19,12,19,14,19,15,19,6,19,7,19,4,19,17,19,21,20,23,20,1,7,8,8,1,8,1,2,6,11,2,1,9,0,8,5,2,3,3,1,11,2,1,9,0,4,7,11,2,1,9,0,3,6,8,1,7,8,8,1,11,4,1,9,0,3,7,11,2,1,9,0,8,5,11,3,1,9,0,0,3,7,11,2,1,9,0,6,8,1,3,1,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,11,3,1,9,0,3,7,11,2,1,9,0,8,5,3,1,3,2,7,11,2,1,9,0,8,5,1,7,11,0,1,9,0,1,6,11,0,1,9,0,1,8,6,3,6,11,0,1,9,0,3,3,1,9,0,2,8,5,11,0,1,9,0,2,6,11,7,2,9,0,9,1,9,0,1,1,1,6,9,1,1,6,11,3,1,9,0,1,11,7,2,9,0,9,1,2,11,3,1,9,0,7,8,8,2,7,11,3,1,9,0,11,3,1,9,0,1,6,8,6,1,8,5,2,7,11,3,1,9,0,3,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,7,9,1,7,65,99,99,111,117,110,116,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,4,67,111,105,110,9,67,117,115,116,111,100,105,97,110,2,73,68,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,16,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,115,22,97,99,99,111,117,110,116,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,3,97,100,100,17,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,22,98,111,114,114,111,119,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,26,98,111,114,114,111,119,95,109,117,116,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,4,99,108,111,98,4,99,111,105,110,8,99,111,110,116,97,105,110,115,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,105,110,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,4,106,111,105,110,12,108,111,99,107,95,98,97,108,97,110,99,101,14,108,111,99,107,101,100,95,98,97,108,97,110,99,101,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,110,101,119,6,111,98,106,101,99,116,5,115,112,108,105,116,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,0,2,2,14,11,3,1,9,0,32,11,3,1,9,0,1,2,1,27,8,6,2,2,2,27,8,6,11,11,7,2,8,5,11,0,1,9,0,2,19,0,19,0,1,0,0,8,4,11,0,17,19,18,1,2,1,3,0,0,18,27,10,0,55,0,10,1,56,0,32,4,11,11,0,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,2,11,0,55,0,11,1,56,1,12,2,10,2,55,1,56,2,12,3,11,2,55,2,56,2,12,4,11,3,11,4,2,2,3,0,0,8,6,10,0,17,19,11,0,56,3,57,0,2,3,3,0,0,8,7,11,0,11,2,11,1,56,4,11,3,56,5,2,4,3,0,0,8,8,11,0,11,1,56,6,54,1,11,2,56,7,1,2,5,3,0,0,8,9,11,0,11,1,16,3,17,20,56,6,54,1,11,2,56,8,2,6,3,0,0,8,10,11,0,11,1,16,3,17,20,56,6,54,2,11,2,56,7,1,2,7,3,0,0,8,7,11,0,11,1,56,6,54,2,11,2,56,8,2,8,3,0,0,10,10,10,0,10,1,11,2,56,4,12,3,11,0,11,1,11,3,56,9,2,9,3,0,0,10,10,10,0,10,1,11,2,56,10,12,3,11,0,11,1,11,3,56,11,2,10,3,0,0,8,7,11,0,55,0,11,1,56,1,55,1,56,2,2,11,3,0,0,8,7,11,0,55,0,11,1,56,1,55,2,56,2,2,12,0,0,0,8,18,10,0,55,0,10,1,56,0,32,4,13,10,0,54,0,10,1,56,12,56,12,57,1,56,13,11,0,54,0,11,1,56,14,2,13,0,0,0,8,15,10,0,55,0,10,1,56,0,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,1,2,2,1,0,0,0,1,1,0,0,19,1,19,2,19,0,20,0],"custodian_v2":[161,28,235,11,6,0,0,0,14,1,0,12,2,12,44,3,56,178,1,4,234,1,30,5,136,2,255,1,7,135,4,242,4,8,249,8,64,6,185,9,20,10,205,9,39,11,244,9,4,12,248,9,189,3,13,181,13,10,14,191,13,6,15,197,13,2,0,24,1,15,1,21,1,38,1,41,1,42,0,0,4,1,0,1,0,1,12,0,0,4,12,1,0,1,1,2,4,1,0,1,2,3,12,1,0,1,3,7,4,0,4,5,12,2,7,1,4,1,5,6,2,0,0,36,0,1,0,0,23,2,1,0,0,28,1,3,0,0,12,4,5,0,0,9,6,7,1,0,0,37,0,8,1,0,0,46,9,10,1,0,0,31,11,3,1,0,0,25,12,13,1,0,0,32,14,3,1,0,0,26,15,13,1,0,0,34,12,3,1,0,0,44,15,3,1,0,0,8,6,16,1,0,0,11,6,16,1,0,0,19,17,18,1,0,0,17,6,19,1,0,1,33,32,16,1,0,1,40,33,13,1,0,1,45,29,16,1,0,1,47,3,13,1,0,2,29,31,10,1,0,3,27,21,3,0,3,37,0,21,0,3,43,22,5,0,4,13,34,3,2,7,4,4,16,26,28,2,7,4,4,18,35,36,2,7,4,4,22,26,27,2,7,4,4,37,0,30,2,7,4,28,25,26,25,19,24,29,25,8,24,21,24,15,24,17,24,18,24,9,24,10,24,7,24,20,24,25,25,27,25,1,7,8,7,1,8,1,2,6,8,1,7,8,7,0,1,6,8,1,1,5,2,6,11,2,1,9,0,5,2,3,3,1,11,2,1,9,0,4,7,11,2,1,9,0,3,6,8,1,7,8,7,1,11,4,1,9,0,3,7,11,2,1,9,0,5,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,3,1,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,11,3,1,9,0,3,7,11,2,1,9,0,5,3,1,3,2,7,11,2,1,9,0,5,1,7,11,0,1,9,0,1,6,11,0,1,9,0,2,8,5,5,1,8,5,1,6,8,5,3,6,11,0,1,9,0,3,3,1,9,0,2,5,11,0,1,9,0,2,6,11,6,2,9,0,9,1,9,0,1,1,1,6,9,1,1,6,11,3,1,9,0,1,11,6,2,9,0,9,1,2,11,3,1,9,0,7,8,7,2,7,11,3,1,9,0,11,3,1,9,0,2,7,11,3,1,9,0,3,3,7,11,6,2,9,0,9,1,9,0,9,1,2,7,11,6,2,9,0,9,1,9,0,1,7,9,1,7,65,99,99,111,117,110,116,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,4,67,111,105,110,9,67,117,115,116,111,100,105,97,110,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,16,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,115,22,97,99,99,111,117,110,116,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,13,97,99,99,111,117,110,116,95,111,119,110,101,114,3,97,100,100,17,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,22,98,111,114,114,111,119,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,26,98,111,114,114,111,119,95,109,117,116,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,7,99,108,111,98,95,118,50,4,99,111,105,110,8,99,111,110,116,97,105,110,115,24,99,114,101,97,116,101,95,99,104,105,108,100,95,97,99,99,111,117,110,116,95,99,97,112,12,99,117,115,116,111,100,105,97,110,95,118,50,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,6,100,101,108,101,116,101,18,100,101,108,101,116,101,95,97,99,99,111,117,110,116,95,99,97,112,12,102,114,111,109,95,98,97,108,97,110,99,101,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,105,110,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,4,106,111,105,110,12,108,111,99,107,95,98,97,108,97,110,99,101,14,108,111,99,107,101,100,95,98,97,108,97,110,99,101,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,110,101,119,6,111,98,106,101,99,116,5,111,119,110,101,114,5,115,112,108,105,116,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,2,14,11,3,1,9,0,35,11,3,1,9,0,1,2,2,30,8,5,39,5,2,2,2,30,8,5,10,11,6,2,5,11,0,1,9,0,2,24,0,24,0,3,0,0,20,10,11,0,17,23,12,1,14,1,17,24,12,2,11,1,11,2,18,1,2,1,1,0,0,3,22,10,0,16,0,17,24,10,0,16,1,20,33,4,9,5,15,11,1,1,11,0,1,7,1,39,11,1,17,23,11,0,16,1,20,18,1,2,2,1,0,0,3,5,11,0,19,1,1,17,22,2,3,1,0,0,3,4,11,0,16,1,20,2,4,3,0,0,23,27,10,0,55,0,10,1,56,0,32,4,11,11,0,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,2,11,0,55,0,11,1,56,1,12,2,10,2,55,1,56,2,12,3,11,2,55,2,56,2,12,4,11,3,11,4,2,5,3,0,0,3,6,10,0,17,23,11,0,56,3,57,0,2,6,3,0,0,3,7,11,0,11,2,11,1,56,4,11,3,56,5,2,7,3,0,0,3,8,11,0,11,1,56,6,54,1,11,2,56,7,1,2,8,3,0,0,3,9,11,0,11,1,16,1,20,56,6,54,1,11,2,56,8,2,9,3,0,0,3,10,11,0,11,1,16,1,20,56,6,54,2,11,2,56,7,1,2,10,3,0,0,3,7,11,0,11,1,56,6,54,2,11,2,56,8,2,11,3,0,0,13,10,10,0,10,1,11,2,56,4,12,3,11,0,11,1,11,3,56,9,2,12,3,0,0,13,10,10,0,10,1,11,2,56,10,12,3,11,0,11,1,11,3,56,11,2,13,3,0,0,3,7,11,0,55,0,11,1,56,1,55,1,56,2,2,14,3,0,0,3,7,11,0,55,0,11,1,56,1,55,2,56,2,2,15,0,0,0,3,18,10,0,55,0,10,1,56,0,32,4,13,10,0,54,0,10,1,56,12,56,12,57,1,56,13,11,0,54,0,11,1,56,14,2,16,0,0,0,3,15,10,0,55,0,10,1,56,0,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,1,2,1,0,1,1,2,1,0,0,0,1,2,24,3,24,4,24,0,20,0],"math":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,40,5,42,20,7,62,126,8,188,1,32,6,220,1,38,12,130,2,183,5,15,185,7,6,0,5,0,10,0,1,0,0,11,0,2,0,0,6,0,1,0,0,7,0,2,0,0,8,0,1,0,0,9,0,2,0,0,4,0,2,0,0,2,3,4,0,2,3,3,1,3,2,1,3,1,4,1,2,0,3,1,4,4,2,2,2,4,99,108,111,98,7,99,108,111,98,95,118,50,19,99,111,117,110,116,95,108,101,97,100,105,110,103,95,122,101,114,111,115,7,99,114,105,116,98,105,116,9,100,105,118,95,114,111,117,110,100,4,109,97,116,104,3,109,117,108,9,109,117,108,95,114,111,117,110,100,10,117,110,115,97,102,101,95,100,105,118,16,117,110,115,97,102,101,95,100,105,118,95,114,111,117,110,100,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,3,8,0,202,154,59,0,0,0,0,4,16,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,3,0,0,1,7,11,0,11,1,17,1,12,2,1,11,2,2,1,3,0,0,6,26,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,10,4,24,7,1,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,18,9,12,2,11,2,11,3,11,4,24,7,1,26,52,2,2,1,0,0,1,14,11,0,11,1,17,1,12,2,1,10,2,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,2,3,1,0,0,2,15,11,0,11,1,17,1,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,4,3,0,0,1,7,11,0,11,1,17,5,12,2,1,11,2,2,5,3,0,0,6,28,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,7,0,53,24,10,4,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,9,12,2,11,2,11,3,7,0,53,24,11,4,26,52,2,6,1,0,0,2,15,11,0,11,1,17,5,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,7,3,0,0,7,107,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,49,128,12,1,5,105,49,0,12,2,10,0,50,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,23,11,0,49,64,47,12,0,11,2,49,64,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,37,11,0,49,32,47,12,0,11,2,49,32,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,51,11,0,49,16,47,12,0,11,2,49,16,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,65,11,0,49,8,47,12,0,11,2,49,8,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,79,11,0,49,4,47,12,0,11,2,49,4,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,93,11,0,49,2,47,12,0,11,2,49,2,22,12,2,11,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,103,11,2,49,1,22,12,2,11,2,12,1,11,1,2,0,0,0,1,0,3,0]},"type_origin_table":[{"module_name":"custodian","struct_name":"Account","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"AccountCap","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"Custodian","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"Leaf","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"InternalNode","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"CritbitTree","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"PoolCreated","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlacedV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilledV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Order","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"TickLevel","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Pool","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlaced","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian_v2","struct_name":"Account","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian_v2","struct_name":"AccountCap","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian_v2","struct_name":"Custodian","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"PoolCreated","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"OrderPlaced","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"OrderCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"AllOrdersCanceledComponent","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"AllOrdersCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"OrderFilled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"DepositAsset","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"WithdrawAsset","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"Order","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"TickLevel","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"Pool","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"ACKQVv64dXCmpxE1QPU2QMLxVpmtbzrFGMtWYY6szJrQ","storage_rebate":0},{"data":{"Package":{"id":"0xb2345915de1f9bd661e9ab27eb27e376cdf6391359ea64fbfdb4550b092c1aa0","version":4,"module_map":{"calculator":[161,28,235,11,6,0,0,0,8,1,0,12,2,12,12,3,24,75,5,99,67,7,166,1,189,2,8,227,3,96,6,195,4,44,12,239,4,164,5,0,10,0,23,0,21,2,17,1,11,1,16,1,2,12,0,3,1,8,0,4,0,8,0,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,6,3,1,0,0,7,3,1,0,0,9,4,1,0,0,4,4,1,0,1,12,0,8,0,1,13,0,3,0,1,15,0,3,0,2,19,6,1,0,2,20,3,1,0,2,22,3,1,0,3,14,10,11,0,5,18,12,13,0,2,7,8,0,2,1,15,3,7,8,0,2,15,2,15,15,4,6,8,2,6,8,1,15,2,7,15,15,15,15,15,15,15,0,6,15,15,15,15,15,15,5,15,15,15,15,15,2,2,15,3,6,8,2,6,8,1,2,3,1,15,2,2,3,2,1,3,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,20,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,9,103,101,116,95,105,110,100,101,120,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,4,109,97,116,104,6,111,114,97,99,108,101,3,112,111,119,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,153,183,0,0,0,0,0,0,0,1,0,0,5,31,10,0,10,1,17,9,12,7,12,8,11,0,11,1,17,8,12,3,12,4,11,7,11,3,17,12,12,5,11,8,11,4,17,12,12,6,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,29,11,5,11,6,17,11,12,2,11,2,2,1,1,0,0,7,37,10,0,10,1,17,7,12,6,1,12,4,12,5,12,3,11,0,11,1,17,0,12,7,10,7,10,6,35,4,23,11,3,11,7,11,5,17,12,22,12,2,5,35,11,3,10,6,11,5,17,12,22,11,7,11,6,23,11,4,17,12,22,12,2,11,2,2,2,1,0,0,3,20,10,0,10,1,17,7,1,12,3,1,1,1,11,0,11,1,17,0,12,4,11,2,11,4,17,12,17,10,11,3,23,17,12,2,3,1,0,0,5,60,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,17,10,2,10,0,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,5,11,1,7,0,26,12,6,10,6,10,6,17,12,12,3,10,3,10,6,17,12,12,2,10,0,10,4,24,11,3,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,7,10,0,11,4,24,11,5,24,11,2,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,17,10,11,6,11,0,24,22,11,7,22,11,8,22,2,4,1,0,0,6,8,17,10,11,1,11,0,24,7,0,26,22,2,5,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,11,5,24,6,10,0,0,0,0,0,0,0,11,4,17,14,77,26,2,6,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,6,10,0,0,0,0,0,0,0,11,4,17,14,77,24,11,5,26,2,0],"dynamic_calculator":[161,28,235,11,6,0,0,0,9,1,0,18,2,18,18,3,36,169,1,4,205,1,4,5,209,1,165,2,7,246,3,149,6,8,139,10,128,1,6,139,11,10,12,149,11,225,14,0,16,0,9,0,38,0,43,0,41,3,37,1,45,2,4,2,10,2,1,12,1,0,1,3,3,12,0,5,2,8,0,8,0,8,0,0,17,0,1,1,0,0,21,2,1,0,0,22,2,1,0,0,20,3,1,0,0,24,3,1,0,0,19,4,1,0,0,23,4,1,0,0,18,5,1,0,0,6,6,7,0,0,13,8,7,1,0,0,14,9,1,0,0,15,10,1,0,0,12,9,1,0,1,5,7,1,0,1,7,7,1,0,1,8,25,1,0,2,36,13,14,1,0,3,25,22,1,0,3,26,28,34,0,3,27,28,7,0,3,28,28,7,0,3,29,22,14,0,3,30,28,29,0,3,31,22,19,0,3,32,28,7,0,3,33,17,18,0,3,34,26,7,0,4,39,15,1,0,4,40,7,1,0,4,42,7,1,0,6,11,20,21,1,0,7,35,15,1,0,8,44,31,14,0,16,12,30,19,9,6,8,3,7,8,1,6,8,2,7,11,0,1,9,0,5,2,3,3,1,1,15,7,6,8,3,6,8,2,7,8,1,5,2,15,1,7,6,8,3,6,8,2,7,8,1,2,5,15,1,6,6,8,3,7,8,1,2,5,15,1,7,6,8,3,7,8,1,6,8,2,5,2,15,1,3,6,8,3,7,8,1,2,2,15,15,7,6,8,3,7,8,1,7,11,0,1,9,0,2,3,3,1,6,6,8,3,7,8,1,2,15,15,1,7,6,8,3,7,8,1,2,15,15,15,1,9,1,3,3,15,15,15,15,3,3,1,9,0,2,6,11,0,1,9,0,3,1,3,0,11,5,2,6,2,10,2,15,10,2,15,3,3,15,15,2,6,8,1,5,2,10,2,10,2,1,2,2,6,10,9,0,6,9,0,1,1,2,6,8,1,2,9,5,6,2,15,3,10,2,3,15,10,2,15,3,2,15,2,4,6,8,3,6,8,2,15,2,3,7,8,1,2,5,11,5,6,2,10,2,15,15,10,2,15,3,3,15,15,2,7,8,1,2,3,15,15,15,10,2,15,15,15,15,3,3,15,15,15,1,6,8,3,7,1,3,3,15,3,3,15,6,15,15,15,15,15,15,5,15,15,15,15,15,7,15,15,15,15,15,15,15,5,67,108,111,99,107,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,23,99,97,108,99,117,108,97,116,101,95,99,117,114,114,101,110,116,95,105,110,100,101,120,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,28,100,121,110,97,109,105,99,95,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,21,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,97,112,121,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,18,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,111,114,21,100,121,110,97,109,105,99,95,104,101,97,108,116,104,95,102,97,99,116,111,114,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,31,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,36,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,30,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,25,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,23,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,3,109,97,120,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,4,112,111,111,108,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,6,118,101,99,116,111,114,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,201,175,0,0,0,0,0,0,0,1,0,0,11,99,10,6,6,0,0,0,0,0,0,0,0,36,4,9,10,7,6,0,0,0,0,0,0,0,0,36,12,9,5,11,9,12,9,11,9,32,4,15,5,25,11,1,1,11,3,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,17,10,6,6,0,0,0,0,0,0,0,0,36,4,38,10,3,11,6,12,10,46,11,10,56,0,12,17,6,0,0,0,0,0,0,0,0,12,16,10,7,6,0,0,0,0,0,0,0,0,36,4,52,11,3,11,7,12,11,46,11,11,56,0,12,16,5,54,11,3,1,10,0,10,2,10,1,10,4,10,5,10,17,77,10,8,17,1,12,13,10,0,10,2,10,1,10,4,10,5,11,16,77,10,8,17,2,12,14,11,0,11,1,11,2,11,4,11,5,11,17,77,11,8,17,7,12,15,10,14,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,95,11,13,11,14,17,28,11,15,17,29,12,12,5,97,17,31,12,12,11,12,2,1,1,0,0,16,86,10,2,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,17,6,0,0,0,0,0,0,0,0,12,14,10,12,12,10,14,12,14,4,56,1,32,4,31,10,6,4,31,13,10,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,10,14,10,15,35,4,78,5,36,14,10,10,14,66,19,12,9,10,2,10,9,20,12,8,46,11,8,17,17,12,16,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,9,20,33,4,57,10,5,12,13,10,0,10,1,10,2,11,9,20,10,3,11,13,10,6,17,3,12,11,11,17,11,11,11,16,17,29,22,12,17,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,2,1,11,1,1,11,0,1,11,17,2,2,1,0,0,23,76,10,2,10,3,12,7,46,11,7,17,25,12,14,1,14,14,65,19,12,12,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,6,0,0,0,0,0,0,0,0,12,10,10,14,12,11,14,14,14,4,56,1,32,4,31,10,6,4,31,13,11,10,4,68,19,11,12,6,1,0,0,0,0,0,0,0,22,12,12,10,10,10,12,35,4,68,5,36,14,11,10,10,66,19,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,10,4,10,8,20,33,4,49,10,5,12,9,10,0,10,1,10,2,11,8,20,10,3,11,9,10,6,17,4,12,13,11,15,11,13,22,12,15,11,10,6,1,0,0,0,0,0,0,0,22,12,10,5,31,11,2,1,11,1,1,11,0,1,11,15,2,3,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,5,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,4,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,6,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,5,1,0,0,7,27,10,1,10,2,11,3,17,26,1,12,7,11,5,4,13,11,7,11,4,22,12,7,5,17,11,7,11,4,23,12,7,11,0,11,1,11,2,17,8,1,12,6,11,7,11,6,17,29,2,6,1,0,0,7,27,10,1,10,2,11,3,17,26,12,6,1,11,5,4,13,11,6,11,4,22,12,6,5,17,11,6,11,4,23,12,6,11,0,11,1,11,2,17,8,12,7,1,11,6,11,7,17,29,2,7,1,0,0,27,91,10,1,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,6,0,0,0,0,0,0,0,0,12,14,10,12,12,9,14,12,14,4,56,1,32,4,27,13,9,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,10,14,10,15,35,4,81,5,36,14,9,10,14,66,19,12,8,10,1,10,8,20,17,22,12,16,1,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,8,20,33,4,56,10,5,12,13,10,0,10,2,10,1,11,8,20,10,3,11,13,10,6,17,3,12,17,11,10,10,17,11,16,17,29,22,12,10,11,11,11,17,22,12,11,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,1,1,11,2,1,11,0,1,11,10,11,11,17,28,2,8,1,0,0,30,42,11,0,17,32,12,8,10,1,10,2,12,3,46,11,3,17,21,12,9,10,1,10,2,17,20,12,4,12,6,11,1,11,2,17,19,12,5,12,7,11,8,11,9,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,12,10,12,11,5,17,13,11,4,17,29,12,10,11,12,11,7,17,14,11,6,17,29,12,11,11,10,11,11,2,9,1,0,0,32,76,10,4,6,0,0,0,0,0,0,0,0,36,4,9,10,5,6,0,0,0,0,0,0,0,0,36,12,7,5,11,9,12,7,11,7,32,4,15,5,23,11,1,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,12,10,4,6,0,0,0,0,0,0,0,0,36,4,36,10,2,11,4,12,8,46,11,8,56,0,12,12,6,0,0,0,0,0,0,0,0,12,11,10,5,6,0,0,0,0,0,0,0,0,36,4,50,11,2,11,5,12,9,46,11,9,56,0,12,11,5,52,11,2,1,10,0,10,1,10,3,10,12,77,10,11,77,10,6,17,10,12,10,11,0,11,1,11,3,10,10,11,12,77,11,11,77,11,6,17,11,12,13,11,10,11,13,2,10,1,0,0,33,41,10,1,10,2,17,18,12,10,1,12,8,12,9,12,7,11,0,11,1,11,2,11,3,11,4,11,5,17,12,12,11,10,11,10,10,35,4,27,11,7,11,11,11,9,17,29,22,12,6,5,39,11,7,10,11,11,9,17,29,22,11,11,11,10,23,11,8,17,29,22,12,6,11,6,2,11,1,0,0,7,24,10,1,10,2,17,18,1,12,7,1,1,1,11,0,11,1,11,2,11,4,11,5,11,6,17,12,12,8,11,3,11,8,17,29,17,27,11,7,23,17,29,2,12,1,0,0,35,62,10,1,10,2,17,24,12,11,12,12,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,5,4,16,11,12,11,3,22,12,12,5,20,11,12,11,3,23,12,12,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,35,11,5,4,31,11,11,11,4,22,12,11,5,35,11,11,11,4,23,12,11,11,0,11,1,11,2,17,8,12,7,12,8,11,12,11,8,17,29,12,10,11,11,11,7,17,29,12,9,10,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,56,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,5,60,11,9,11,10,17,28,12,6,11,6,2,0],"incentive":[161,28,235,11,6,0,0,0,14,1,0,30,2,30,66,3,96,181,1,4,149,2,46,5,195,2,164,3,7,231,5,187,6,8,162,12,96,6,130,13,94,10,224,13,116,11,212,14,2,12,214,14,189,15,13,147,30,40,14,187,30,8,15,195,30,2,0,44,0,72,0,62,0,64,1,18,1,78,2,21,2,26,2,27,2,36,2,53,2,73,2,76,2,77,0,82,0,4,12,1,0,1,0,6,4,0,0,3,12,0,0,7,3,0,0,5,3,0,1,8,12,0,4,9,7,0,5,12,7,0,6,0,4,1,0,1,7,1,8,0,8,2,12,1,0,1,10,13,4,0,11,10,12,2,7,1,4,1,13,11,2,0,0,47,0,1,0,0,67,2,1,0,0,66,2,1,0,0,15,3,1,1,0,0,79,4,1,0,0,24,5,6,0,0,25,7,1,1,0,0,39,8,9,0,0,40,10,11,0,0,33,12,13,0,1,41,46,37,0,1,42,47,37,0,2,60,1,34,0,2,61,37,34,0,3,51,37,34,0,5,38,1,36,1,0,5,48,36,33,0,6,69,49,40,1,0,7,74,32,9,0,8,37,50,51,1,0,9,34,22,1,1,3,10,52,0,14,0,11,14,26,1,2,7,4,11,22,24,45,2,7,4,11,23,27,28,2,7,4,11,29,24,25,2,7,4,11,52,0,18,2,7,4,11,63,27,43,2,7,4,12,58,52,1,1,12,12,68,22,1,1,8,13,65,15,16,0,14,70,39,40,1,0,26,17,26,19,29,21,25,17,22,17,24,17,20,29,20,30,25,19,22,19,24,19,15,22,26,38,31,22,29,41,25,38,27,38,22,38,23,19,23,38,17,22,19,22,28,51,1,7,8,13,0,4,7,8,2,15,1,7,8,13,9,7,8,2,6,8,9,2,3,3,11,10,1,9,0,3,2,7,8,13,5,7,8,2,6,8,9,7,8,5,2,5,5,6,8,2,7,8,5,3,2,5,2,10,15,10,15,6,7,8,2,7,11,0,1,9,0,6,8,9,7,8,5,5,7,8,13,2,6,8,2,2,1,3,3,6,8,2,2,3,4,3,3,15,2,5,6,8,2,7,8,5,6,8,9,2,5,3,10,8,6,10,15,10,2,1,8,11,1,6,8,13,1,5,2,15,1,1,11,12,2,9,0,9,1,2,2,8,1,1,2,1,8,2,1,9,0,1,7,1,2,6,11,12,2,9,0,9,1,9,0,1,1,3,7,11,12,2,9,0,9,1,9,0,9,1,2,7,11,12,2,9,0,9,1,9,0,1,7,9,1,1,8,3,1,8,4,4,1,11,8,1,9,0,3,7,8,1,1,6,8,9,1,8,6,1,15,1,11,12,2,5,15,1,8,7,2,15,15,2,5,15,3,11,10,1,9,0,3,7,8,13,1,11,8,1,9,0,1,11,0,1,9,0,17,7,8,5,3,2,5,5,5,3,3,7,15,15,10,15,7,11,12,2,5,15,3,7,8,1,15,10,15,7,11,12,2,5,15,1,9,1,18,6,11,12,2,5,15,3,3,15,15,10,15,15,6,11,12,2,5,15,3,6,8,1,15,15,3,15,15,15,15,10,15,1,6,9,1,2,7,8,5,2,3,7,8,5,2,5,9,5,15,3,7,8,1,15,15,6,11,12,2,5,15,15,7,11,12,2,5,15,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,13,1,11,10,1,9,0,2,9,0,5,1,6,8,1,10,10,8,6,3,3,3,10,2,6,8,1,10,15,15,6,11,12,2,5,15,10,15,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,9,73,110,99,101,110,116,105,118,101,12,73,110,99,101,110,116,105,118,101,66,97,108,16,80,111,111,108,65,100,109,105,110,83,101,116,116,105,110,103,8,80,111,111,108,73,110,102,111,16,80,111,111,108,79,119,110,101,114,83,101,116,116,105,110,103,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,3,97,100,100,8,97,100,100,95,112,111,111,108,5,97,100,109,105,110,6,97,100,109,105,110,115,5,97,115,99,105,105,5,97,115,115,101,116,6,97,115,115,101,116,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,24,99,97,108,99,95,112,111,111,108,95,117,112,100,97,116,101,95,114,101,119,97,114,100,115,12,99,108,97,105,109,95,114,101,119,97,114,100,5,99,108,111,99,107,4,99,111,105,110,10,99,111,105,110,95,116,121,112,101,115,8,99,111,110,116,97,105,110,115,7,99,114,101,97,116,111,114,11,99,117,114,114,101,110,116,95,105,100,120,18,100,105,115,116,114,105,98,117,116,101,100,95,97,109,111,117,110,116,6,101,97,114,110,101,100,4,101,109,105,116,9,101,110,100,95,116,105,109,101,115,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,14,103,101,116,95,112,111,111,108,95,99,111,117,110,116,13,103,101,116,95,112,111,111,108,95,105,110,102,111,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,9,105,110,99,101,110,116,105,118,101,13,105,110,100,101,120,95,114,101,119,97,114,100,115,19,105,110,100,101,120,95,114,101,119,97,114,100,115,95,112,97,105,100,115,4,105,110,105,116,11,105,110,116,111,95,115,116,114,105,110,103,16,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,7,108,101,110,100,105,110,103,3,109,117,108,3,110,101,119,6,111,98,106,101,99,116,10,111,114,97,99,108,101,95,105,100,115,5,111,119,110,101,114,6,111,119,110,101,114,115,5,112,111,111,108,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,9,115,97,102,101,95,109,97,116,104,6,115,101,110,100,101,114,9,115,101,116,95,97,100,109,105,110,9,115,101,116,95,111,119,110,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,11,115,116,97,114,116,95,116,105,109,101,115,7,115,116,111,114,97,103,101,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,13,116,111,116,97,108,95,115,117,112,112,108,121,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,13,117,112,100,97,116,101,95,114,101,119,97,114,100,16,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,22,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,95,112,97,105,100,115,5,117,116,105,108,115,5,118,97,108,117,101,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,153,183,0,0,0,0,0,0,3,8,154,183,0,0,0,0,0,0,3,8,155,183,0,0,0,0,0,0,3,8,156,183,0,0,0,0,0,0,3,8,157,183,0,0,0,0,0,0,3,8,158,183,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,43,8,11,19,2,31,3,32,15,21,11,8,1,9,0,1,2,12,43,2,49,3,28,10,8,6,71,10,3,35,10,3,75,10,15,59,10,15,45,10,15,46,10,11,12,2,5,15,80,10,11,12,2,5,15,81,10,11,12,2,5,15,54,10,2,2,2,6,43,8,11,30,5,56,11,12,2,15,1,17,11,12,2,15,1,57,11,12,2,2,8,1,20,10,2,3,2,3,65,5,55,15,83,1,4,2,3,65,5,16,15,83,1,0,22,0,0,0,0,1,15,10,0,17,21,10,0,46,17,30,10,0,56,0,10,0,56,0,11,0,56,1,64,20,0,0,0,0,0,0,0,0,18,2,56,2,2,1,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,1,10,1,56,3,32,4,27,11,0,15,1,10,1,10,2,56,4,5,35,11,0,15,1,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,3,56,6,2,2,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,2,10,1,56,3,32,4,27,11,0,15,2,10,1,10,2,56,4,5,35,11,0,15,2,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,4,56,7,2,3,1,4,0,31,139,1,10,0,16,0,20,10,8,46,17,30,33,4,9,5,17,11,0,1,11,8,1,11,1,1,7,0,39,10,3,11,1,17,18,36,4,27,10,4,10,3,36,12,9,5,29,9,12,9,11,9,4,32,5,38,11,0,1,11,8,1,7,1,39,10,0,16,3,10,2,56,8,32,4,65,10,0,15,3,10,2,10,2,6,0,0,0,0,0,0,0,0,64,33,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,20,0,0,0,0,0,0,0,0,18,1,56,9,10,0,15,4,10,2,68,20,11,0,15,3,10,2,56,10,12,12,10,12,16,5,65,33,12,11,10,12,15,5,56,11,17,16,68,33,10,12,15,6,10,3,68,9,10,12,15,7,10,4,68,9,10,12,15,8,10,6,77,68,34,10,12,15,9,10,6,77,11,4,11,3,23,77,17,13,68,34,10,12,15,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,34,10,12,15,11,10,8,56,12,68,35,10,12,15,12,10,8,56,12,68,35,10,12,15,13,10,8,56,12,68,35,11,12,15,14,11,7,68,20,11,5,11,6,10,8,56,13,12,10,11,8,17,21,11,2,11,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,10,57,0,56,14,2,4,3,0,0,42,118,10,0,16,3,10,3,56,8,4,111,11,1,17,18,12,11,10,0,11,2,10,11,10,3,10,4,12,8,12,7,12,6,12,5,46,11,5,11,6,11,7,11,8,17,5,12,20,12,15,11,0,15,3,11,3,56,10,12,18,11,11,10,18,15,15,21,10,18,16,5,65,33,12,17,6,0,0,0,0,0,0,0,0,12,12,10,12,10,17,35,4,108,5,45,14,15,10,12,66,34,20,12,14,14,20,10,12,66,34,20,12,19,10,18,15,10,10,12,67,34,12,13,10,14,11,13,21,10,18,15,11,10,12,67,35,12,16,10,16,10,4,12,9,46,11,9,56,15,4,79,10,16,10,4,56,16,1,11,16,10,4,11,14,56,17,10,18,15,12,10,12,67,35,12,21,10,21,10,4,12,10,46,11,10,56,15,4,99,10,21,10,4,56,16,1,11,21,10,4,11,19,56,17,11,12,6,1,0,0,0,0,0,0,0,22,12,12,5,40,11,18,1,5,117,11,2,1,11,0,1,11,1,1,2,5,0,0,0,44,166,1,11,0,16,3,10,3,56,18,12,14,10,14,16,5,65,33,12,13,6,0,0,0,0,0,0,0,0,12,7,64,34,0,0,0,0,0,0,0,0,12,10,64,34,0,0,0,0,0,0,0,0,12,22,10,7,10,13,35,4,159,1,5,20,10,14,16,6,10,7,66,9,20,12,17,10,17,10,14,16,15,20,35,4,36,10,14,16,15,20,12,17,10,14,16,7,10,7,66,9,20,12,6,10,2,10,6,35,4,48,10,2,12,6,10,14,16,9,10,7,66,34,20,12,15,10,14,16,10,10,7,66,34,20,12,9,10,17,10,6,35,4,90,11,6,11,17,23,77,12,19,10,1,10,3,17,10,1,12,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,10,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,15,11,19,17,14,11,20,26,12,8,11,9,11,8,22,12,9,13,10,10,9,68,34,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,21,10,4,7,6,34,4,151,1,10,14,16,12,10,7,66,35,12,5,10,5,10,4,56,15,4,114,11,5,10,4,56,19,20,12,21,5,116,11,5,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,14,16,11,10,7,66,35,12,12,10,12,10,4,56,15,4,133,1,11,12,10,4,56,19,20,12,11,5,135,1,11,12,1,10,1,10,3,10,4,17,11,1,12,18,11,9,11,11,23,11,18,24,12,16,11,21,11,16,22,12,21,13,22,11,21,68,34,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,15,11,1,1,11,14,1,11,10,11,22,2,6,1,4,0,48,105,10,0,11,2,11,3,10,1,55,0,20,10,4,17,4,11,0,15,3,10,1,55,0,20,56,10,12,9,10,1,55,1,20,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,9,16,12,10,8,66,35,12,12,10,12,10,4,56,15,4,36,11,12,10,4,56,19,20,12,11,5,38,11,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,9,15,13,10,8,67,35,12,14,10,14,10,4,12,6,46,11,6,56,15,4,56,10,14,10,4,56,16,12,13,11,14,10,4,10,11,56,17,11,11,11,13,23,17,12,26,12,7,11,9,16,8,11,8,66,34,20,12,10,10,1,55,2,20,10,7,22,11,10,37,4,81,5,87,11,5,1,11,1,1,7,4,39,10,1,55,2,20,10,7,22,10,1,54,2,21,11,1,54,3,11,7,52,56,20,11,5,56,21,11,4,56,22,2,7,1,0,0,9,19,6,0,0,0,0,0,0,0,0,12,2,10,0,16,3,10,1,56,8,4,15,11,0,16,3,11,1,56,18,16,5,65,33,12,2,5,17,11,0,1,11,2,2,8,1,0,0,53,47,10,0,16,3,10,1,56,8,4,6,5,10,11,0,1,7,2,39,11,0,16,3,11,1,56,18,12,3,10,3,16,5,65,33,10,2,36,4,22,5,26,11,3,1,7,2,39,10,3,16,6,10,2,66,9,20,10,3,16,7,10,2,66,9,20,10,3,16,9,10,2,66,34,20,11,3,16,14,11,2,66,20,20,2,9,1,0,0,54,97,64,33,0,0,0,0,0,0,0,0,12,5,64,34,0,0,0,0,0,0,0,0,12,14,64,20,0,0,0,0,0,0,0,0,12,9,10,0,16,3,10,3,56,8,4,87,11,2,17,18,12,6,10,0,11,1,11,6,10,3,10,4,17,5,12,11,1,11,0,16,3,11,3,56,18,12,10,10,10,16,5,65,33,12,8,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,84,5,38,10,10,16,13,10,7,66,35,12,13,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,10,13,10,4,56,15,4,55,11,13,10,4,56,19,20,12,12,5,57,11,13,1,13,5,10,10,16,5,10,7,66,33,20,68,33,13,14,14,11,10,7,66,34,20,11,12,23,68,34,13,9,10,10,16,14,10,7,66,20,20,68,20,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,33,11,10,1,5,93,11,1,1,11,0,1,11,2,1,11,5,11,14,11,9,2,2,1,2,2,2,3,2,4,2,5,1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,1,11,1,1,0,1,0,2,0,3,0,4,16,22,17,22,18,22,19,22,0,50,0],"lending":[161,28,235,11,6,0,0,0,10,1,0,22,2,22,52,3,74,130,1,4,204,1,38,5,242,1,222,2,7,208,4,238,3,8,190,8,96,6,158,9,10,10,168,9,49,12,217,9,201,4,0,26,0,25,0,30,0,34,0,39,2,32,1,14,1,15,1,19,1,41,0,44,0,3,3,0,0,11,3,0,0,0,3,0,0,8,3,0,0,5,3,0,1,4,12,0,3,6,12,1,0,1,4,9,12,0,5,7,8,0,6,1,8,0,7,2,12,1,0,1,9,10,2,0,0,46,0,1,0,0,16,2,1,1,0,0,47,3,1,1,0,0,13,4,1,1,0,0,35,5,1,1,0,0,29,6,1,2,0,0,1,43,11,1,0,2,20,22,1,1,0,2,21,19,1,1,0,2,22,32,33,2,0,0,2,23,22,28,1,0,2,24,22,16,1,0,3,16,17,1,1,0,3,17,35,1,1,0,3,31,18,16,1,0,3,42,18,16,1,0,3,47,23,1,1,0,4,33,0,7,0,7,45,15,16,1,0,8,18,12,1,1,3,9,37,9,10,0,10,38,13,14,1,0,21,12,18,12,12,12,14,12,8,12,19,20,11,12,15,12,16,12,19,24,7,12,19,26,10,12,19,29,9,31,15,34,16,34,13,34,19,36,1,6,8,7,0,8,6,8,9,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,5,7,8,11,9,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,5,7,8,5,7,8,11,7,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,7,8,11,8,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,11,12,6,8,9,6,8,8,7,8,7,2,7,11,6,1,9,0,2,7,11,6,1,9,1,11,10,1,9,0,5,3,7,8,5,7,8,11,1,1,5,3,3,3,5,11,10,1,9,0,1,6,8,11,1,5,5,7,8,5,6,8,9,7,8,7,2,5,1,9,0,3,11,10,1,9,0,3,7,8,11,1,11,10,1,9,0,1,6,11,10,1,9,0,1,3,3,7,11,6,1,9,0,11,10,1,9,0,7,8,11,2,6,11,6,1,9,0,3,5,6,8,9,7,8,7,2,5,15,1,8,0,6,3,3,3,3,3,5,6,6,8,9,6,8,8,7,8,7,2,5,15,4,7,11,6,1,9,0,3,5,7,8,11,1,8,1,3,3,3,5,1,8,2,8,3,3,15,3,3,3,5,11,10,1,9,0,1,15,1,8,3,14,3,3,3,3,15,15,3,3,3,3,3,5,11,10,1,9,0,15,2,9,0,9,1,7,6,8,9,6,8,8,7,8,7,5,2,2,15,3,15,15,15,1,9,1,2,7,11,6,1,9,0,3,1,8,4,11,66,111,114,114,111,119,69,118,101,110,116,5,67,108,111,99,107,4,67,111,105,110,12,68,101,112,111,115,105,116,69,118,101,110,116,9,73,110,99,101,110,116,105,118,101,20,76,105,113,117,105,100,97,116,105,111,110,67,97,108,108,69,118,101,110,116,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,112,97,121,69,118,101,110,116,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,13,87,105,116,104,100,114,97,119,69,118,101,110,116,6,97,109,111,117,110,116,6,98,111,114,114,111,119,5,99,108,111,99,107,4,99,111,105,110,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,9,105,110,99,101,110,116,105,118,101,7,108,101,110,100,105,110,103,16,108,105,113,117,105,100,97,116,101,95,97,109,111,117,110,116,14,108,105,113,117,105,100,97,116,101,95,117,115,101,114,16,108,105,113,117,105,100,97,116,105,111,110,95,99,97,108,108,5,108,111,103,105,99,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,5,112,97,117,115,101,4,112,111,111,108,5,114,101,112,97,121,7,114,101,115,101,114,118,101,6,115,101,110,100,101,114,10,115,112,108,105,116,95,99,111,105,110,7,115,116,111,114,97,103,101,2,116,111,10,116,120,95,99,111,110,116,101,120,116,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,13,117,112,100,97,116,101,95,114,101,119,97,114,100,5,117,116,105,108,115,5,118,97,108,117,101,15,119,104,101,110,95,110,111,116,95,112,97,117,115,101,100,8,119,105,116,104,100,114,97,119,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,41,160,0,0,0,0,0,0,0,2,3,36,2,37,5,12,3,1,2,4,36,2,37,5,40,5,12,3,2,2,3,36,2,37,5,12,3,3,2,3,36,2,37,5,12,3,4,2,4,36,2,37,5,28,5,27,3,0,0,0,0,1,8,11,0,17,17,32,4,5,5,7,7,0,39,2,1,1,4,0,8,45,10,1,46,17,0,10,7,46,17,20,12,11,11,6,10,0,10,1,10,3,10,11,17,6,11,4,11,5,10,7,56,0,12,12,14,12,56,1,12,9,10,2,11,12,11,7,56,2,11,2,10,9,12,8,46,11,8,56,3,12,10,11,0,11,1,10,3,10,11,11,10,77,56,4,11,3,11,11,11,9,18,0,56,5,2,2,1,4,0,21,50,10,2,46,17,0,10,8,46,17,20,12,14,11,7,10,0,10,2,10,4,10,14,17,6,10,3,11,5,12,9,46,11,9,56,3,12,13,11,0,11,1,11,2,10,4,11,14,11,13,77,56,6,12,11,10,3,11,11,12,10,46,11,10,56,7,12,12,11,3,10,12,10,6,10,8,56,8,11,4,11,8,46,17,20,11,6,11,12,18,1,56,9,2,3,1,4,0,25,35,10,2,46,17,0,10,6,46,17,20,12,9,10,3,10,5,12,7,46,11,7,56,3,12,8,11,0,11,1,11,2,10,4,10,9,11,8,77,56,10,11,3,10,5,11,9,10,6,56,8,11,4,11,6,46,17,20,11,5,18,2,56,11,2,4,1,4,0,27,65,10,2,46,17,0,10,7,46,17,20,12,14,11,5,11,6,10,7,56,0,12,15,14,15,56,1,12,13,10,3,11,15,10,7,56,2,10,3,10,13,12,8,46,11,8,56,3,12,12,11,0,11,1,11,2,10,4,10,14,11,12,77,56,12,12,10,10,3,11,10,52,12,9,46,11,9,56,7,12,11,10,11,6,0,0,0,0,0,0,0,0,36,4,53,11,3,10,11,11,14,10,7,56,8,5,55,11,3,1,11,4,11,7,46,17,20,11,13,11,11,23,18,3,56,13,2,5,1,4,0,30,90,10,2,46,17,0,10,11,46,17,20,12,23,11,10,10,0,10,2,10,5,10,8,17,6,11,7,11,9,10,11,56,0,12,24,14,24,56,1,12,18,10,4,11,24,10,11,56,2,10,4,11,18,12,12,46,11,12,56,3,12,21,11,0,11,1,11,2,10,8,10,5,11,3,11,21,77,56,14,12,25,12,17,12,16,10,4,11,17,52,12,13,46,11,13,56,7,12,20,11,4,11,20,10,23,10,11,56,8,10,6,11,16,52,12,14,46,11,14,56,15,12,19,10,6,10,19,10,23,11,11,56,16,10,6,11,25,52,12,15,46,11,15,56,15,12,22,11,6,10,22,56,17,11,5,11,23,11,8,11,19,11,22,22,18,4,56,18,2,0],"logic":[161,28,235,11,6,0,0,0,10,1,0,20,2,20,12,3,32,220,2,4,252,2,12,5,136,3,214,2,7,222,5,205,9,8,171,15,128,1,6,171,16,60,12,231,16,222,18,15,197,35,2,0,42,0,11,0,53,0,73,0,48,0,52,3,45,1,74,2,3,2,12,2,2,12,0,6,1,8,0,9,0,8,0,0,18,0,1,1,0,0,21,2,3,1,0,0,17,2,1,1,0,0,20,2,4,1,0,0,19,5,6,2,0,0,0,57,7,1,0,0,56,8,1,0,0,55,9,1,0,0,36,10,1,0,0,15,10,1,0,0,35,10,1,0,0,14,10,1,0,0,39,11,12,0,0,64,13,14,0,0,63,15,4,0,0,16,15,4,0,0,62,11,4,0,0,65,11,4,0,0,67,16,4,0,0,61,16,4,0,0,60,17,4,0,0,66,17,4,0,0,38,17,12,0,0,40,17,12,0,0,8,18,19,0,1,4,44,4,0,1,5,9,4,0,1,6,22,4,0,1,7,22,4,0,1,9,21,4,0,1,10,44,4,0,2,14,10,1,0,2,15,10,1,0,2,22,31,4,0,2,23,9,32,0,2,24,9,22,0,2,25,9,22,0,2,26,31,3,0,2,27,9,6,0,2,28,31,28,0,2,29,27,28,0,2,30,9,22,0,2,31,9,4,0,2,32,39,40,0,2,33,17,22,0,2,34,34,1,0,2,35,10,1,0,2,36,10,1,0,2,37,21,1,0,2,50,17,1,0,2,51,17,1,0,2,55,34,1,0,2,56,33,1,0,2,58,17,1,0,2,59,17,1,0,3,68,21,1,1,0,3,69,21,1,1,0,3,70,25,1,2,0,0,3,71,21,1,1,0,3,72,21,1,1,0,4,46,1,4,0,4,47,22,4,0,4,49,22,4,0,5,44,22,4,0,7,13,46,12,1,0,8,43,1,4,0,9,54,30,3,0,56,20,59,20,55,20,58,20,57,24,64,28,5,6,8,2,7,8,0,2,5,15,0,6,6,8,2,6,8,1,7,8,0,2,5,15,1,3,1,15,7,6,8,2,6,8,1,7,8,0,5,2,2,15,3,15,15,15,2,6,8,2,7,8,0,3,6,8,2,7,8,0,2,2,7,8,0,2,4,7,8,0,2,5,15,4,6,8,2,6,8,1,7,8,0,5,1,1,4,6,8,2,6,8,1,7,8,0,10,5,1,10,15,4,6,8,2,7,8,0,6,8,1,5,5,6,8,2,6,8,1,7,8,0,2,5,3,7,8,0,2,5,7,6,8,2,7,8,0,6,8,1,5,2,2,15,6,15,15,15,15,15,1,1,9,0,3,7,8,0,2,15,2,15,15,6,15,15,1,15,15,15,2,9,0,9,1,4,7,8,0,2,2,15,2,2,2,1,6,8,0,1,2,18,2,15,15,15,15,3,15,15,3,15,15,15,15,15,15,15,15,15,1,6,8,2,2,6,8,0,2,5,15,15,15,15,15,6,7,8,0,2,15,15,3,15,4,7,8,0,2,15,15,4,15,3,3,10,15,1,5,4,15,15,15,15,9,5,6,2,15,15,10,2,3,3,15,15,2,6,8,0,5,2,10,2,10,2,9,5,2,6,2,15,10,2,3,3,15,15,7,5,6,2,3,3,15,10,2,15,3,2,15,2,4,6,8,2,6,8,1,15,2,2,5,10,2,2,6,10,9,0,6,9,0,18,2,15,15,15,15,1,15,15,15,15,15,2,15,15,15,15,15,15,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,7,105,115,95,108,111,97,110,7,108,101,110,100,105,110,103,5,108,111,103,105,99,3,109,97,120,3,109,105,110,6,111,114,97,99,108,101,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,9,115,97,102,101,95,109,97,116,104,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,19,117,112,100,97,116,101,95,115,116,97,116,101,95,111,102,95,97,108,108,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,24,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,95,98,97,116,99,104,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,6,118,101,99,116,111,114,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,33,78,0,0,0,0,0,0,3,8,34,78,0,0,0,0,0,0,3,8,35,78,0,0,0,0,0,0,3,8,36,78,0,0,0,0,0,0,3,8,37,78,0,0,0,0,0,0,3,8,38,78,0,0,0,0,0,0,0,3,0,0,1,26,11,0,10,1,17,5,10,1,10,2,10,4,56,0,10,1,10,2,10,3,11,4,17,8,10,1,10,2,10,3,17,22,32,4,22,10,1,10,2,11,3,17,53,11,1,11,2,17,7,2,1,3,0,0,22,92,10,2,10,3,10,4,17,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,16,11,2,1,11,1,1,11,0,1,7,4,39,10,0,10,2,17,5,10,2,10,3,10,5,56,1,10,2,10,3,10,4,17,20,12,7,11,5,10,7,17,63,12,6,10,2,10,3,10,4,10,6,17,9,11,0,11,1,10,2,10,4,17,12,4,44,5,48,11,2,1,7,0,39,10,6,10,7,33,4,61,10,2,10,3,10,4,17,22,4,61,10,2,10,3,10,4,17,49,10,7,10,6,36,4,86,10,7,10,6,23,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,4,86,10,2,10,3,11,7,10,6,23,17,48,10,2,10,3,10,4,17,22,4,86,10,2,10,3,11,4,17,49,11,2,11,3,17,7,11,6,52,2,2,3,0,0,1,37,10,0,10,2,17,5,10,2,10,3,10,5,56,2,10,2,10,3,10,4,11,5,17,10,10,2,10,3,10,4,17,23,32,4,22,10,2,10,3,10,4,17,54,11,0,11,1,10,2,11,4,17,12,4,29,5,33,11,2,1,7,0,39,11,2,11,3,17,7,2,3,3,0,0,6,58,10,2,10,3,10,4,17,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,14,11,2,1,11,0,1,7,5,39,11,0,10,2,17,5,10,2,10,3,10,5,56,3,10,2,10,3,10,4,17,21,12,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,5,12,8,10,6,10,5,35,4,40,10,6,12,8,11,5,10,6,23,12,7,10,2,10,3,10,4,10,8,17,11,11,8,11,6,33,4,53,10,2,10,3,11,4,17,50,11,2,11,3,17,7,11,7,2,4,3,0,0,23,92,10,2,10,5,10,3,17,23,4,6,5,14,11,2,1,11,1,1,11,0,1,7,3,39,10,2,10,4,10,3,17,22,4,20,5,28,11,2,1,11,1,1,11,0,1,7,2,39,10,0,10,2,17,5,10,2,10,5,10,4,10,6,56,4,10,0,10,1,10,2,10,3,17,12,32,4,44,5,52,11,2,1,11,1,1,11,0,1,7,1,39,11,0,10,2,11,1,10,3,10,4,10,5,11,6,17,24,12,9,12,8,12,12,12,7,12,11,12,10,10,2,10,5,10,3,11,11,17,11,10,2,10,4,10,3,11,10,17,9,11,9,4,82,10,2,10,5,11,3,17,50,10,2,11,4,17,7,11,2,11,5,17,7,11,7,11,8,11,12,2,5,0,0,0,26,25,10,1,46,17,40,12,2,49,0,12,3,10,3,10,2,35,4,20,5,11,10,0,10,1,10,3,17,6,11,3,49,1,22,12,3,5,6,11,1,1,11,0,1,2,6,0,0,0,29,97,11,0,17,66,12,8,10,1,10,2,12,3,46,11,3,17,37,12,11,10,8,11,11,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,18,10,1,10,2,17,36,12,4,12,6,10,1,10,2,17,35,12,5,12,7,10,18,11,7,17,28,10,6,17,62,12,13,11,18,11,5,17,27,10,4,17,62,12,12,10,1,10,2,17,34,1,12,14,1,1,1,10,1,10,2,17,41,12,19,12,20,10,19,10,12,10,4,23,17,62,12,9,11,20,10,13,11,6,23,17,62,12,10,11,9,10,12,17,61,12,15,11,10,10,13,17,61,12,17,11,19,10,12,11,4,23,17,62,11,14,17,62,10,12,17,61,12,16,10,1,10,2,11,12,11,13,11,8,10,16,17,52,11,1,11,2,11,17,11,15,11,16,22,17,45,2,7,0,0,0,22,15,10,0,10,1,17,26,12,2,10,0,10,1,10,2,17,29,12,3,11,0,11,1,11,2,11,3,17,51,2,8,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,47,2,9,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,32,2,10,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,46,2,11,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,31,2,12,1,0,0,1,8,11,0,11,2,11,1,11,3,17,14,17,60,38,2,13,1,0,0,35,37,14,3,65,36,12,6,6,0,0,0,0,0,0,0,0,12,5,64,4,0,0,0,0,0,0,0,0,12,7,10,5,10,6,35,4,29,5,12,10,0,10,2,10,1,14,3,10,5,66,36,20,17,14,12,4,13,7,11,4,68,4,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,7,11,2,1,11,1,1,11,0,1,11,7,2,14,1,0,0,37,33,10,0,10,2,10,1,10,3,17,16,12,6,10,0,10,1,10,2,10,3,17,15,12,5,11,0,11,2,11,1,11,3,17,17,12,7,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,29,11,6,11,7,17,61,11,5,17,62,12,4,5,31,17,65,12,4,11,4,2,15,1,0,0,38,72,10,1,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,6,0,0,0,0,0,0,0,0,12,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,10,9,10,10,35,4,56,5,22,14,8,10,9,66,28,12,5,10,1,10,5,20,17,38,12,11,1,1,10,0,10,2,10,1,11,5,20,10,3,17,19,12,12,11,6,10,12,11,11,17,62,22,12,6,11,7,11,12,22,12,7,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,17,11,1,1,11,2,1,11,0,1,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,11,6,11,7,17,61,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,16,1,0,0,41,59,10,2,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,6,0,0,0,0,0,0,0,0,12,9,10,9,10,10,35,4,51,5,20,14,8,10,9,66,28,12,6,10,2,10,6,20,12,5,46,11,5,17,33,12,11,10,0,10,1,10,2,11,6,20,10,3,17,19,12,7,11,12,11,7,11,11,17,62,22,12,12,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,15,11,2,1,11,1,1,11,0,1,11,12,2,17,1,0,0,42,49,10,2,10,3,12,4,46,11,4,17,43,12,9,1,14,9,65,28,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,41,5,20,14,9,10,6,66,28,12,5,10,0,10,1,10,2,11,5,20,10,3,17,18,12,8,11,10,11,8,22,12,10,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,15,11,2,1,11,1,1,11,0,1,11,10,2,18,1,0,0,43,18,10,2,10,3,11,4,17,21,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,19,1,0,0,43,18,10,2,10,3,11,4,17,20,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,20,1,0,0,22,15,10,0,10,1,11,2,17,44,1,12,3,11,0,11,1,17,36,1,12,4,11,3,11,4,17,62,2,21,1,0,0,22,15,10,0,10,1,11,2,17,44,12,3,1,11,0,11,1,17,36,12,4,1,11,3,11,4,17,62,2,22,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,1,12,4,14,4,14,1,56,5,2,23,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,12,4,1,14,4,14,1,56,5,2,24,0,0,0,47,113,10,1,10,4,17,38,1,12,15,12,16,10,0,10,2,10,1,10,4,10,3,17,19,11,16,17,62,12,20,10,0,10,2,10,1,10,5,11,3,17,18,12,19,9,12,12,10,19,10,20,35,4,32,11,19,12,20,8,12,12,10,1,10,5,12,7,46,11,7,17,39,12,18,10,0,10,2,11,6,11,18,17,30,12,21,10,21,10,20,36,4,54,11,21,10,20,23,12,11,5,58,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,11,21,12,20,10,20,11,15,17,62,12,8,11,1,10,4,17,42,12,22,10,8,11,22,17,62,12,23,10,20,10,23,23,12,17,10,0,10,2,10,20,10,4,17,25,12,13,10,0,10,2,11,20,10,5,17,25,12,14,10,0,10,2,11,17,10,4,17,25,12,9,10,0,10,2,11,23,11,4,17,25,12,24,11,0,11,2,11,11,11,8,22,11,5,17,25,12,10,11,13,11,14,11,9,11,24,11,10,11,12,2,0,41,0],"pool":[161,28,235,11,6,0,0,0,14,1,0,18,2,18,54,3,72,145,1,4,217,1,30,5,247,1,203,1,7,194,3,145,4,8,211,7,96,6,179,8,20,10,199,8,67,11,138,9,2,12,140,9,146,3,13,158,12,6,14,164,12,6,15,170,12,4,0,37,1,13,1,47,2,14,2,15,2,23,2,36,2,44,2,46,0,2,12,1,0,1,0,3,12,0,0,5,3,0,0,4,3,0,0,6,3,0,0,7,3,0,1,8,7,0,2,10,7,0,3,0,4,1,0,1,4,1,12,1,0,1,6,11,4,0,8,9,2,0,0,28,0,1,0,0,17,2,1,1,0,0,20,3,1,1,0,0,50,4,1,1,0,0,21,5,1,1,0,0,52,6,1,1,0,0,51,7,1,1,0,0,26,8,9,1,0,0,16,10,11,0,0,35,12,11,1,0,0,48,12,11,1,0,2,25,1,26,1,0,2,30,26,27,0,3,31,25,11,1,0,3,42,29,19,1,0,3,49,32,11,1,0,3,53,1,19,1,0,4,24,30,24,1,0,4,29,24,19,1,0,4,49,23,11,1,0,5,22,18,1,1,3,6,33,0,13,0,7,38,17,1,1,12,7,41,18,1,1,8,8,40,14,15,0,22,16,16,18,23,20,20,21,19,18,18,18,13,18,11,18,20,28,14,18,17,18,20,31,22,24,15,18,7,18,1,7,8,11,0,3,6,8,1,2,7,8,11,3,7,11,0,1,9,0,11,9,1,9,0,7,8,11,4,7,11,0,1,9,0,3,5,7,8,11,2,7,11,0,1,9,0,3,5,7,8,1,7,11,0,1,9,0,3,5,7,8,11,5,6,8,1,7,11,0,1,9,0,3,5,7,8,11,1,6,11,0,1,9,0,1,2,3,3,2,2,1,3,2,6,11,0,1,9,0,3,1,8,10,1,6,8,11,1,5,1,8,1,2,9,0,5,1,9,0,1,11,8,1,9,0,1,11,0,1,9,0,1,8,2,2,11,8,1,9,0,3,1,6,11,9,1,9,0,1,11,9,1,9,0,2,7,11,8,1,9,0,11,8,1,9,0,1,8,7,1,8,6,1,8,4,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,11,1,8,5,1,6,11,8,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,19,80,111,111,108,66,97,108,97,110,99,101,82,101,103,105,115,116,101,114,10,80,111,111,108,67,114,101,97,116,101,11,80,111,111,108,68,101,112,111,115,105,116,12,80,111,111,108,87,105,116,104,100,114,97,119,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,7,99,114,101,97,116,111,114,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,2,105,100,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,7,108,101,110,100,105,110,103,3,110,101,119,10,110,101,119,95,97,109,111,117,110,116,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,9,114,101,99,105,112,105,101,110,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,7,115,116,111,114,97,103,101,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,4,122,101,114,111,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,17,164,0,0,0,0,0,0,3,8,18,164,0,0,0,0,0,0,0,2,4,27,8,10,14,11,8,1,9,0,45,11,8,1,9,0,19,2,1,2,2,27,8,10,18,5,2,2,1,18,5,3,2,4,40,5,12,3,34,3,37,8,6,4,2,3,40,5,12,3,37,8,6,5,2,4,40,5,39,5,12,3,37,8,6,0,18,0,0,0,0,1,11,10,0,17,21,10,0,46,17,24,18,1,11,0,46,17,24,56,0,2,1,3,0,0,1,13,10,2,17,21,56,1,56,1,11,1,57,0,56,2,11,2,46,17,24,18,2,56,3,2,2,3,0,0,22,20,14,1,56,4,12,4,11,1,56,5,12,3,11,0,54,0,11,3,56,6,1,11,2,46,17,24,11,4,56,7,17,12,18,4,56,8,2,3,3,0,0,24,20,11,0,54,0,10,1,56,9,10,3,56,10,12,4,11,3,46,17,24,10,2,11,1,56,7,17,12,18,5,56,11,11,4,11,2,56,12,2,4,3,0,0,19,22,10,0,55,0,56,13,10,1,38,4,7,5,11,11,0,1,7,1,39,10,0,54,0,11,1,56,9,12,2,11,0,54,1,11,2,56,6,1,2,5,1,0,0,1,22,10,1,55,1,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,1,11,2,56,9,11,4,56,10,11,3,56,12,2,6,3,0,0,1,22,10,1,55,0,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,0,11,2,56,9,11,4,56,10,11,3,56,12,2,7,1,0,0,1,4,11,0,55,2,20,2,8,1,0,0,1,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,9,1,0,0,9,8,11,0,56,14,12,2,11,1,11,2,49,9,17,8,2,10,1,0,0,9,8,11,0,56,14,12,2,11,1,49,9,11,2,17,8,2,0,1,0,2,0,3,0,18,1,18,2,18,0,32,0,43,0],"ray_math":[161,28,235,11,6,0,0,0,7,1,0,4,3,4,55,5,59,8,7,67,101,8,168,1,64,6,232,1,200,1,12,176,3,168,5,0,6,1,0,0,4,0,1,0,0,9,0,1,0,0,1,0,1,0,0,2,0,1,0,0,11,2,1,0,0,10,2,1,0,0,7,2,1,0,0,5,2,1,0,0,8,1,1,0,0,12,1,1,0,1,3,0,1,0,0,1,15,2,15,15,1,1,7,97,100,100,114,101,115,115,8,104,97,108,102,95,114,97,121,8,104,97,108,102,95,119,97,100,3,109,97,120,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,10,114,97,121,95,116,111,95,119,97,100,3,119,97,100,7,119,97,100,95,100,105,118,7,119,97,100,95,109,117,108,10,119,97,100,95,116,111,95,114,97,121,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,100,167,179,182,224,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,178,211,89,91,240,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,77,4,0,0,0,0,0,0,3,8,78,4,0,0,0,0,0,0,3,8,79,4,0,0,0,0,0,0,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,0,2,2,1,0,0,0,2,7,3,2,3,1,0,0,0,2,7,1,2,4,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,1,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,1,22,7,0,26,2,5,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,0,26,37,4,20,5,22,7,5,39,11,0,7,0,24,11,2,22,11,1,26,2,6,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,3,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,3,22,7,2,26,2,7,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,2,26,37,4,20,5,22,7,5,39,11,0,7,2,24,11,2,22,11,1,26,2,8,1,0,0,2,19,7,4,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,1,10,1,11,0,22,12,2,10,2,11,1,38,4,13,5,15,7,6,39,11,2,7,4,26,2,9,1,0,0,1,15,10,0,7,4,24,12,1,10,1,7,4,26,11,0,33,4,11,5,13,7,5,39,11,1,2,0],"safe_math":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,30,5,32,6,7,38,34,8,72,32,6,104,50,12,154,1,163,2,0,5,0,0,0,1,0,0,6,0,1,0,0,4,0,1,0,0,1,0,1,0,0,3,0,1,0,0,2,0,1,0,2,15,15,1,15,0,3,97,100,100,3,100,105,118,3,109,105,110,3,109,111,100,3,109,117,108,9,115,97,102,101,95,109,97,116,104,3,115,117,98,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,3,8,233,3,0,0,0,0,0,0,3,8,234,3,0,0,0,0,0,0,3,8,235,3,0,0,0,0,0,0,3,8,236,3,0,0,0,0,0,0,3,8,237,3,0,0,0,0,0,0,0,1,0,0,1,13,10,0,11,1,22,12,2,10,2,11,0,38,4,9,5,11,7,0,39,11,2,2,1,1,0,0,2,11,10,1,10,0,37,4,5,5,7,7,1,39,11,0,11,1,23,2,2,1,0,0,1,21,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,10,1,24,12,2,10,2,11,0,26,11,1,33,4,17,5,19,7,2,39,11,2,2,3,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,5,5,7,7,3,39,11,0,11,1,26,2,4,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,4,39,11,0,11,1,25,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,0],"storage":[161,28,235,11,6,0,0,0,12,1,0,29,2,29,92,3,121,144,3,4,137,4,54,5,191,4,153,3,7,216,7,131,16,8,219,23,96,6,187,24,93,10,152,25,164,1,12,188,26,186,19,13,246,45,66,15,184,46,2,0,120,0,90,0,94,1,22,1,131,1,1,141,1,2,30,2,31,2,47,2,85,2,123,2,127,2,130,1,0,4,12,0,0,11,12,0,0,10,12,0,0,9,4,0,0,20,4,0,0,8,5,0,0,19,5,0,0,15,4,0,0,0,4,0,0,3,4,0,0,12,3,0,0,5,3,0,1,6,12,1,0,1,1,7,12,0,3,13,7,0,4,17,7,0,6,1,8,0,7,2,12,1,0,1,9,18,4,0,10,14,12,2,7,1,4,1,12,16,2,0,0,73,0,1,0,0,144,1,2,1,0,0,143,1,3,1,0,0,74,4,1,1,0,0,115,5,1,0,0,117,6,1,0,0,107,6,1,0,0,112,6,1,0,0,118,6,1,0,0,106,6,1,0,0,113,6,1,0,0,108,6,1,0,0,116,6,1,0,0,114,6,1,0,0,110,6,1,0,0,109,6,1,0,0,111,6,1,0,0,102,2,1,1,0,0,88,2,7,0,0,59,2,8,0,0,64,9,10,0,0,58,11,8,0,0,52,11,12,0,0,60,13,14,0,0,50,13,14,0,0,53,13,15,0,0,55,13,15,0,0,61,13,15,0,0,65,16,15,0,0,56,11,17,0,0,49,11,14,0,0,63,13,14,0,0,62,11,14,0,0,51,13,18,0,0,57,13,19,0,0,133,1,20,1,0,0,134,1,21,1,0,0,68,20,1,0,0,70,22,1,0,0,44,22,1,0,0,69,22,1,0,0,43,22,1,0,0,67,23,1,0,0,42,23,1,0,0,71,24,1,0,0,136,1,16,1,0,0,97,16,1,0,0,135,1,16,1,0,0,96,16,1,0,0,146,1,25,1,1,0,0,45,3,1,0,1,36,43,1,1,0,1,132,1,62,17,1,0,1,145,1,63,1,1,0,2,93,1,14,0,4,48,1,38,1,0,4,75,38,12,0,5,35,57,7,1,0,5,72,57,59,1,0,5,95,60,36,1,0,6,125,40,17,0,7,54,42,8,1,0,8,46,36,1,1,3,9,84,0,26,0,10,21,41,1,2,7,4,10,25,49,50,2,7,4,10,28,46,47,2,7,4,10,35,49,7,2,7,4,10,84,0,33,2,7,4,10,95,46,55,2,7,4,11,91,30,1,1,12,11,119,36,1,1,8,12,105,27,28,0,70,29,70,31,68,32,68,34,71,35,17,36,55,36,68,39,64,32,61,36,51,36,62,44,66,32,65,32,67,34,65,34,67,39,65,39,69,39,64,39,64,34,66,34,57,8,58,8,59,8,52,36,53,36,1,7,8,20,0,1,6,8,2,2,6,8,1,7,8,2,20,6,8,1,6,8,13,6,8,16,7,8,2,2,1,15,15,15,15,15,15,15,15,15,15,15,15,6,11,17,1,9,0,7,8,20,3,6,8,0,7,8,2,1,4,6,8,0,7,8,2,2,15,1,1,1,2,2,6,8,2,5,2,10,2,10,2,2,6,8,2,2,1,8,14,2,7,8,2,2,1,15,2,15,15,3,7,8,2,2,5,1,3,5,15,15,15,15,15,3,15,15,15,4,7,8,2,2,15,15,6,7,8,2,2,15,15,3,15,4,7,8,2,2,5,15,3,7,8,7,5,15,3,7,8,2,2,15,8,6,8,1,6,8,13,7,8,2,2,7,11,12,1,9,0,3,5,7,8,20,1,8,18,1,6,8,20,1,5,1,8,1,2,9,0,5,1,8,0,2,2,8,3,1,11,19,2,9,0,9,1,2,5,8,4,1,8,2,1,9,0,18,2,15,15,15,8,7,8,7,3,8,8,8,9,2,8,14,1,15,15,15,2,2,8,3,1,8,15,2,5,15,1,6,8,16,3,7,11,19,2,9,0,9,1,9,0,9,1,1,6,11,17,1,9,0,3,6,8,13,2,7,8,20,1,8,11,1,7,8,3,2,7,11,19,2,9,0,9,1,9,0,1,7,9,1,3,2,2,8,14,2,6,11,19,2,9,0,9,1,9,0,1,6,9,1,1,6,8,4,1,6,8,3,3,15,6,8,3,15,3,7,8,7,7,8,3,7,8,7,1,9,1,3,10,2,8,4,7,8,4,2,6,10,9,0,6,9,0,2,3,7,8,4,2,1,3,2,7,10,9,0,3,5,2,3,7,15,3,3,2,6,11,12,1,9,0,3,5,6,8,13,7,11,12,1,9,0,3,5,7,8,20,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,12,67,111,105,110,77,101,116,97,100,97,116,97,18,76,105,113,117,105,100,97,116,105,111,110,70,97,99,116,111,114,115,8,79,119,110,101,114,67,97,112,6,80,97,117,115,101,100,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,23,82,101,115,101,114,118,101,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,11,82,101,115,101,114,118,101,68,97,116,97,7,83,116,111,114,97,103,101,15,83,116,111,114,97,103,101,65,100,109,105,110,67,97,112,26,83,116,111,114,97,103,101,67,111,110,102,105,103,117,114,97,116,111,114,83,101,116,116,105,110,103,6,83,116,114,105,110,103,5,84,97,98,108,101,12,84,111,107,101,110,66,97,108,97,110,99,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,20,85,115,101,114,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,8,85,115,101,114,73,110,102,111,3,97,100,100,5,97,115,99,105,105,9,98,97,115,101,95,114,97,116,101,5,98,111,110,117,115,6,98,111,114,114,111,119,14,98,111,114,114,111,119,95,98,97,108,97,110,99,101,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,5,99,108,111,99,107,4,99,111,105,110,9,99,111,105,110,95,116,121,112,101,11,99,111,108,108,97,116,101,114,97,108,115,12,99,111,110,102,105,103,117,114,97,116,111,114,8,99,111,110,116,97,105,110,115,11,99,114,101,97,116,101,95,112,111,111,108,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,20,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,114,97,116,101,4,100,97,116,97,16,100,101,99,114,101,97,115,101,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,12,100,101,115,116,111,114,121,95,117,115,101,114,4,101,109,105,116,5,101,118,101,110,116,3,103,101,116,13,103,101,116,95,97,115,115,101,116,95,108,116,118,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,13,103,101,116,95,99,111,105,110,95,116,121,112,101,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,12,103,101,116,95,100,101,99,105,109,97,108,115,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,20,103,101,116,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,16,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,114,101,115,101,114,118,101,11,105,110,116,111,95,115,116,114,105,110,103,11,105,115,95,105,115,111,108,97,116,101,100,20,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,5,108,111,97,110,115,5,108,111,103,105,99,3,108,116,118,10,109,117,108,116,105,112,108,105,101,114,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,111,114,97,99,108,101,95,105,100,5,112,97,117,115,101,6,112,97,117,115,101,100,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,105,111,3,114,97,121,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,14,114,101,115,101,114,118,101,95,102,97,99,116,111,114,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,97,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,98,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,99,18,114,101,115,101,114,118,101,95,118,97,108,105,100,97,116,105,111,110,8,114,101,115,101,114,118,101,115,14,114,101,115,101,114,118,101,115,95,99,111,117,110,116,6,115,101,110,100,101,114,13,115,101,116,95,98,97,115,101,95,114,97,116,101,14,115,101,116,95,98,111,114,114,111,119,95,99,97,112,24,115,101,116,95,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,98,111,110,117,115,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,114,97,116,105,111,25,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,7,115,101,116,95,108,116,118,14,115,101,116,95,109,117,108,116,105,112,108,105,101,114,23,115,101,116,95,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,115,101,116,95,112,97,117,115,101,18,115,101,116,95,114,101,115,101,114,118,101,95,102,97,99,116,111,114,14,115,101,116,95,115,117,112,112,108,121,95,99,97,112,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,7,115,116,111,114,97,103,101,14,115,117,112,112,108,121,95,98,97,108,97,110,99,101,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,9,116,104,114,101,115,104,111,108,100,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,9,117,115,101,114,95,105,110,102,111,10,117,115,101,114,95,115,116,97,116,101,5,117,115,101,114,115,5,118,97,108,117,101,6,118,101,99,116,111,114,7,118,101,114,115,105,111,110,15,118,101,114,115,105,111,110,95,109,105,103,114,97,116,101,20,118,101,114,115,105,111,110,95,118,101,114,105,102,105,99,97,116,105,111,110,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,3,0,0,0,0,0,0,0,3,8,248,167,0,0,0,0,0,0,3,8,249,167,0,0,0,0,0,0,3,8,250,167,0,0,0,0,0,0,3,8,251,167,0,0,0,0,0,0,3,8,252,167,0,0,0,0,0,0,3,8,253,167,0,0,0,0,0,0,3,8,254,167,0,0,0,0,0,0,3,8,255,167,0,0,0,0,0,0,2,1,255,0,2,1,66,8,18,1,2,1,66,8,18,2,2,7,66,8,18,142,1,3,89,1,103,11,19,2,2,8,3,104,2,139,1,10,5,137,1,11,19,2,5,8,4,3,2,21,66,2,87,2,32,8,14,76,1,122,15,27,15,40,15,38,15,39,15,37,15,121,8,7,26,8,7,78,3,82,15,129,1,15,128,1,15,29,8,8,79,8,9,99,15,100,15,101,15,4,2,2,33,10,2,80,10,2,5,2,1,41,15,6,2,1,41,15,7,2,2,138,1,11,19,2,5,15,126,15,8,2,5,23,15,83,15,77,15,98,15,86,15,9,2,3,92,15,24,15,124,15,10,2,3,105,5,34,5,140,1,1,11,2,1,89,1,0,0,0,0,1,27,10,0,17,63,18,1,10,0,46,17,72,56,0,10,0,17,63,18,0,10,0,46,17,72,56,1,10,0,17,63,7,0,9,10,0,56,2,49,0,64,28,0,0,0,0,0,0,0,0,11,0,56,3,18,2,56,4,2,1,0,0,0,1,10,11,0,16,0,20,7,0,33,4,7,5,9,7,1,39,2,2,1,4,0,1,16,10,1,16,0,20,7,0,35,4,7,5,11,11,1,1,7,2,39,7,0,11,1,15,0,21,2,3,1,4,0,37,117,10,3,46,17,1,10,3,16,1,20,12,35,10,35,7,9,35,4,12,5,24,11,3,1,11,1,1,11,19,1,11,18,1,11,2,1,7,5,39,10,3,46,56,5,10,3,16,1,20,12,20,11,4,12,29,56,6,17,56,12,30,11,5,12,31,11,6,12,32,11,7,12,33,17,54,12,34,17,54,12,21,11,13,12,22,11,14,12,23,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,24,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,25,11,2,17,60,12,26,11,8,11,10,11,11,11,12,11,9,18,8,12,27,11,15,11,16,11,17,18,9,12,28,11,20,11,29,11,30,11,31,11,32,11,33,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,34,11,21,11,24,11,25,11,26,11,22,11,23,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,27,11,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,12,37,10,3,15,2,10,35,11,37,56,8,11,35,49,1,22,11,3,15,1,21,11,18,56,9,12,36,11,1,11,36,11,19,56,10,2,4,1,4,0,1,11,10,1,46,17,1,10,2,11,1,15,3,21,11,2,18,11,56,11,2,5,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,4,21,2,6,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,5,21,2,7,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,6,21,2,8,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,7,21,2,9,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,9,21,2,10,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,10,21,2,11,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,11,21,2,12,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,12,21,2,13,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,13,21,2,14,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,15,21,2,15,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,16,21,2,16,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,17,21,2,17,1,0,0,48,36,56,6,17,56,12,3,10,0,16,1,20,12,1,49,0,12,2,10,2,10,1,35,4,33,5,14,10,0,16,2,10,2,56,13,16,18,20,10,3,34,4,24,5,28,11,0,1,7,7,39,11,2,49,1,22,12,2,5,9,11,0,1,2,18,1,0,0,1,4,11,0,16,3,20,2,19,1,0,0,1,4,11,0,16,1,20,2,20,1,0,0,51,23,10,0,16,19,10,1,56,14,32,4,11,11,0,1,64,8,0,0,0,0,0,0,0,0,64,8,0,0,0,0,0,0,0,0,2,11,0,16,19,11,1,56,15,12,2,10,2,16,20,20,11,2,16,21,20,2,21,1,0,0,1,7,11,0,16,2,11,1,56,13,16,22,20,2,22,1,0,0,1,7,11,0,16,2,11,1,56,13,16,18,20,2,23,1,0,0,1,7,11,0,16,2,11,1,56,13,16,4,20,2,24,1,0,0,1,7,11,0,16,2,11,1,56,13,16,5,20,2,25,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,23,20,11,2,16,24,20,2,26,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,25,20,11,2,16,26,20,2,27,1,0,0,52,14,11,0,16,2,11,1,56,13,12,2,10,2,16,27,16,28,20,11,2,16,29,16,28,20,2,28,1,0,0,53,41,11,0,16,2,11,1,56,13,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,4,16,27,16,30,10,2,56,16,4,22,10,4,16,27,16,30,10,2,56,17,20,12,5,10,4,16,29,16,30,10,2,56,16,4,36,11,4,16,29,16,30,11,2,56,17,20,12,3,5,38,11,4,1,11,5,11,3,2,29,1,0,0,1,7,11,0,16,2,11,1,56,13,16,31,20,2,30,1,0,0,1,7,11,0,16,2,11,1,56,13,16,6,20,2,31,1,0,0,1,7,11,0,16,2,11,1,56,13,16,7,20,2,32,1,0,0,1,7,11,0,16,2,11,1,56,13,16,32,20,2,33,1,0,0,52,26,11,0,16,2,11,1,56,13,12,2,10,2,16,8,16,9,20,10,2,16,8,16,10,20,10,2,16,8,16,11,20,10,2,16,8,16,12,20,11,2,16,8,16,13,20,2,34,1,0,0,52,18,11,0,16,2,11,1,56,13,12,2,10,2,16,14,16,15,20,10,2,16,14,16,16,20,11,2,16,14,16,17,20,2,35,3,0,0,45,17,10,0,46,17,1,11,0,15,2,11,1,56,12,12,4,11,3,10,4,15,23,21,11,2,11,4,15,24,21,2,36,3,0,0,45,29,10,0,46,17,1,11,0,15,2,11,1,56,12,12,6,11,2,10,6,15,26,21,11,3,10,6,15,25,21,11,4,10,6,15,31,21,10,6,16,32,20,11,5,22,11,6,15,32,21,2,37,3,0,0,54,31,10,0,46,17,1,11,0,15,2,11,1,56,12,12,5,10,5,15,27,12,6,11,5,15,29,12,4,10,6,16,28,20,11,2,22,11,6,15,28,21,10,4,16,28,20,11,3,22,11,4,15,28,21,2,38,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,42,2,39,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,43,2,40,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,42,2,41,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,43,2,42,0,0,0,14,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,0,15,30,11,1,11,3,10,2,22,56,19,10,0,16,28,20,11,2,22,11,0,15,28,21,2,43,0,0,0,14,37,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,3,10,2,38,4,17,5,21,11,0,1,7,6,39,10,0,15,30,11,1,11,3,10,2,23,56,19,10,0,16,28,20,11,2,23,11,0,15,28,21,2,44,3,0,0,45,14,11,0,15,2,11,1,56,12,12,3,10,3,16,32,20,11,2,22,11,3,15,32,21,2,45,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,64,8,0,0,0,0,0,0,0,0,11,3,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,21,14,1,56,22,32,4,37,11,5,15,21,11,1,68,8,5,39,11,5,1,2,46,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,21,14,1,56,23,12,3,4,17,11,4,15,21,11,3,56,24,1,5,19,11,4,1,2,47,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,11,3,64,8,0,0,0,0,0,0,0,0,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,20,14,1,56,22,32,4,37,11,5,15,20,11,1,68,8,5,39,11,5,1,2,48,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,20,14,1,56,23,12,3,4,17,11,4,15,20,11,3,56,24,1,5,19,11,4,1,2,49,1,0,0,61,58,10,2,10,3,12,8,46,11,8,17,22,56,6,17,56,33,4,11,5,21,11,2,1,11,1,1,11,4,1,11,7,1,7,8,39,11,2,15,2,11,3,56,12,15,32,12,10,10,4,10,10,20,52,12,9,46,11,9,56,25,12,11,10,5,12,12,11,5,10,11,35,4,44,11,11,12,12,10,10,20,10,12,77,23,11,10,21,11,1,11,4,11,12,11,6,11,7,56,26,2,50,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,2,1,2,4,2,3,2,2,3,4,3,5,3,13,3,14,3,16,8,0,8,1,8,2,8,3,8,4,3,17,9,0,9,1,9,2,3,2,2,6,4,0,4,1,3,1,3,6,3,7,3,8,3,9,3,10,7,1,3,11,7,0,3,12,3,15,0,81,0],"utils":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,16,3,26,47,4,73,12,5,85,63,7,148,1,156,1,8,176,2,64,6,240,2,20,12,132,3,114,0,14,1,3,1,4,1,12,1,13,1,0,4,1,0,1,2,1,12,1,0,1,4,2,2,0,0,10,0,1,1,0,0,11,0,2,1,0,2,5,1,8,1,0,2,6,1,2,1,0,2,9,7,1,1,0,2,15,5,6,1,0,3,7,11,8,1,12,4,8,9,10,0,5,4,4,4,2,4,6,1,0,4,3,4,3,11,1,1,9,0,3,7,8,2,1,11,1,1,9,0,1,11,0,1,9,0,2,3,11,1,1,9,0,1,9,0,1,6,11,1,1,9,0,1,3,3,7,11,1,1,9,0,3,7,8,2,0,1,6,8,2,1,5,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,4,99,111,105,110,12,100,101,115,116,114,111,121,95,122,101,114,111,12,105,110,116,111,95,98,97,108,97,110,99,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,10,115,112,108,105,116,95,99,111,105,110,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,117,116,105,108,115,5,118,97,108,117,101,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,176,179,0,0,0,0,0,0,3,8,177,179,0,0,0,0,0,0,0,1,0,0,3,44,14,0,56,0,12,3,10,1,6,0,0,0,0,0,0,0,0,36,4,8,5,12,11,2,1,7,0,39,11,3,10,1,38,4,17,5,21,11,2,1,7,1,39,13,0,11,1,10,2,56,1,12,4,14,0,56,0,6,0,0,0,0,0,0,0,0,33,4,37,11,2,1,11,0,56,2,11,4,2,11,0,11,2,46,17,7,56,3,11,4,2,1,1,0,0,8,6,11,0,11,1,11,2,56,4,56,5,2,0],"validation":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,12,3,22,82,4,104,4,5,108,83,7,191,1,154,2,8,217,3,64,6,153,4,70,12,223,4,237,4,0,22,0,15,0,13,1,3,1,16,1,0,12,0,3,1,7,0,4,2,7,0,0,18,0,1,1,0,0,21,0,1,1,0,0,17,0,1,1,0,0,20,0,1,1,0,0,19,2,1,2,0,0,1,5,8,10,0,1,6,7,6,0,1,7,8,9,0,1,8,8,10,0,1,9,8,9,0,2,11,1,10,0,2,12,9,10,0,2,14,9,10,0,4,4,1,5,1,0,4,10,5,6,0,13,4,13,14,3,7,8,0,2,15,0,4,7,8,0,2,2,15,7,7,8,0,2,15,15,15,15,15,1,9,0,1,8,2,1,8,1,2,6,8,0,2,2,7,8,0,2,2,15,15,1,15,8,7,8,0,2,15,15,15,15,15,15,9,7,8,0,2,15,15,15,15,15,15,15,4,7,8,0,2,7,8,0,2,1,9,1,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,5,97,115,99,105,105,3,103,101,116,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,13,103,101,116,95,99,111,105,110,95,116,121,112,101,9,103,101,116,95,105,110,100,101,120,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,11,105,110,116,111,95,115,116,114,105,110,103,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,9,116,121,112,101,95,110,97,109,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,225,171,0,0,0,0,0,0,3,8,226,171,0,0,0,0,0,0,3,8,227,171,0,0,0,0,0,0,3,8,228,171,0,0,0,0,0,0,3,8,229,171,0,0,0,0,0,0,3,8,230,171,0,0,0,0,0,0,3,8,231,171,0,0,0,0,0,0,0,1,0,0,3,58,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,1,12,8,10,0,10,1,17,7,1,12,5,11,8,11,5,17,12,12,7,11,0,11,1,17,8,12,9,11,7,11,2,22,17,10,24,12,6,11,9,11,6,38,4,55,5,57,7,1,39,2,1,1,0,0,11,54,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,10,11,0,11,1,17,7,12,6,12,7,11,10,11,7,17,12,12,9,11,5,11,6,17,12,12,8,11,9,11,8,11,2,22,38,4,51,5,53,7,3,39,2,2,1,0,0,12,71,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,11,10,0,10,1,17,7,12,6,12,8,11,11,11,8,17,12,12,10,11,5,11,6,17,12,12,9,10,9,10,2,22,10,10,35,4,51,5,55,11,0,1,7,3,39,11,9,11,2,22,11,10,17,11,12,7,11,0,11,1,17,5,11,7,38,4,68,5,70,7,2,39,2,3,1,0,0,8,23,11,0,11,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,15,7,4,39,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,20,5,22,7,0,39,2,4,1,0,0,13,40,10,0,11,1,12,5,12,4,56,0,17,14,11,4,46,11,5,17,6,33,4,13,5,17,11,0,1,7,4,39,11,0,11,2,12,7,12,6,56,1,17,14,11,6,46,11,7,17,6,33,4,30,5,32,7,4,39,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,37,5,39,7,0,39,2,0]},"type_origin_table":[{"module_name":"pool","struct_name":"Pool","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolAdminCap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolCreate","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolBalanceRegister","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolDeposit","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolWithdraw","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"OwnerCap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"StorageAdminCap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"Storage","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"ReserveData","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"UserInfo","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"ReserveConfigurationMap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"UserConfigurationMap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"TokenBalance","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"BorrowRateFactors","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"LiquidationFactors","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"StorageConfiguratorSetting","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"Paused","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"IncentiveBal","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"PoolInfo","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"Incentive","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"PoolOwnerSetting","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"PoolAdminSetting","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"DepositEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"WithdrawEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"BorrowEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"RepayEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"LiquidationCallEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":9},"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f":{"upgraded_id":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f","upgraded_version":1}}}},"owner":"Immutable","previous_transaction":"3fqrGiknVvk82qum6zLYR749UTTyavaoH8TLU6bym8di","storage_rebate":213582800},{"data":{"Package":{"id":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f","version":1,"module_map":{"oracle":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,36,3,48,102,4,150,1,16,5,166,1,216,1,7,254,2,157,3,8,155,6,64,6,219,6,70,10,161,7,38,12,199,7,251,3,13,194,11,12,0,19,1,11,1,18,1,26,1,29,1,30,0,1,12,0,0,2,12,0,0,4,8,0,0,3,4,0,1,0,8,0,2,7,4,0,3,5,12,2,7,1,4,1,5,6,2,0,0,16,0,1,0,0,37,2,1,0,0,36,3,1,0,0,24,4,1,0,0,22,5,1,0,0,32,6,1,0,0,33,7,1,0,0,14,8,9,0,1,28,24,25,0,2,17,0,11,0,3,8,26,1,2,7,4,3,9,22,34,2,7,4,3,10,28,29,2,7,4,3,12,22,23,2,7,4,3,17,0,18,2,7,4,4,21,15,1,1,12,4,25,20,1,1,8,5,23,12,13,0,15,14,15,16,14,17,16,19,13,17,10,17,12,17,11,17,1,7,8,7,0,1,6,8,2,2,6,8,0,7,8,2,3,6,8,0,7,8,2,3,6,6,8,0,6,8,4,7,8,2,2,15,2,5,6,8,1,6,8,4,7,8,2,2,15,5,6,8,1,6,8,4,7,8,2,10,2,10,15,3,6,8,4,6,8,2,2,3,1,15,2,2,8,5,11,6,2,2,8,3,1,8,5,1,6,8,7,1,5,1,8,0,2,9,0,5,1,8,1,2,2,8,3,1,11,6,2,9,0,9,1,1,8,2,1,9,0,2,2,7,11,6,2,2,8,3,2,6,11,6,2,9,0,9,1,9,0,1,1,1,6,8,4,1,3,3,7,11,6,2,9,0,9,1,9,0,9,1,3,2,7,8,3,7,11,6,2,2,8,3,2,7,11,6,2,9,0,9,1,9,0,1,7,9,1,3,3,3,6,2,1,2,1,15,5,1,3,6,11,6,2,2,8,3,6,8,3,1,1,6,9,1,5,67,108,111,99,107,14,79,114,97,99,108,101,65,100,109,105,110,67,97,112,15,79,114,97,99,108,101,70,101,101,100,101,114,67,97,112,5,80,114,105,99,101,11,80,114,105,99,101,79,114,97,99,108,101,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,7,100,101,99,105,109,97,108,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,2,105,100,4,105,110,105,116,3,110,101,119,6,111,98,106,101,99,116,6,111,114,97,99,108,101,13,112,114,105,99,101,95,111,114,97,99,108,101,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,20,114,101,103,105,115,116,101,114,95,116,111,107,101,110,95,112,114,105,99,101,6,115,101,110,100,101,114,19,115,101,116,95,117,112,100,97,116,101,95,105,110,116,101,114,118,97,108,12,115,104,97,114,101,95,111,98,106,101,99,116,5,116,97,98,108,101,9,116,105,109,101,115,116,97,109,112,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,15,117,112,100,97,116,101,95,105,110,116,101,114,118,97,108,18,117,112,100,97,116,101,95,116,111,107,101,110,95,112,114,105,99,101,24,117,112,100,97,116,101,95,116,111,107,101,110,95,112,114,105,99,101,95,98,97,116,99,104,5,118,97,108,117,101,7,118,101,114,115,105,111,110,15,118,101,114,115,105,111,110,95,109,105,103,114,97,116,101,20,118,101,114,115,105,111,110,95,118,101,114,105,102,105,99,97,116,105,111,110,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,48,117,0,0,0,0,0,0,3,8,80,195,0,0,0,0,0,0,3,8,81,195,0,0,0,0,0,0,3,8,82,195,0,0,0,0,0,0,3,8,83,195,0,0,0,0,0,0,3,8,84,195,0,0,0,0,0,0,0,2,1,15,8,5,1,2,1,15,8,5,2,2,4,15,8,5,35,3,31,3,20,11,6,2,2,8,3,3,2,3,34,15,13,2,27,3,0,0,0,0,10,27,10,0,17,9,18,0,10,0,46,17,17,56,0,10,0,17,9,18,1,10,0,46,17,17,56,1,10,0,17,9,12,1,11,0,56,2,12,2,11,1,7,0,7,1,11,2,18,2,56,3,2,1,0,0,0,1,10,11,0,16,0,20,7,0,33,4,7,5,9,7,2,39,2,2,0,4,0,1,16,10,1,16,0,20,7,0,35,4,7,5,11,11,1,1,7,3,39,7,0,11,1,15,0,21,2,3,1,4,0,1,8,10,1,46,17,1,11,2,11,1,15,1,21,2,4,1,4,0,21,30,10,2,46,17,1,11,2,15,2,12,7,10,7,10,3,12,6,46,11,6,56,4,32,4,15,5,21,11,7,1,11,1,1,7,6,39,11,7,11,3,11,4,11,5,11,1,17,8,18,3,56,5,2,5,1,4,0,27,34,10,2,46,17,1,11,2,15,2,12,7,10,7,10,3,12,5,46,11,5,56,4,4,14,5,20,11,7,1,11,1,1,7,5,39,11,7,11,3,56,6,12,6,11,4,10,6,15,3,21,11,1,17,8,11,6,15,4,21,2,6,1,4,0,30,53,10,2,46,17,1,14,3,65,31,12,6,10,6,14,4,65,32,33,4,12,5,20,11,2,1,11,1,1,11,0,1,7,4,39,6,0,0,0,0,0,0,0,0,12,5,10,5,10,6,35,4,46,5,27,14,3,10,5,66,31,12,7,10,0,10,1,10,2,11,7,20,14,4,10,5,66,32,20,17,5,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,22,11,2,1,11,1,1,11,0,1,2,7,1,0,0,33,60,10,1,17,1,10,1,16,2,12,5,10,5,10,2,56,4,4,10,5,18,11,5,1,11,1,1,11,0,1,7,5,39,11,5,11,2,56,7,12,6,11,0,17,8,12,4,9,12,7,10,6,16,3,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,44,11,4,10,6,16,4,20,23,11,1,16,1,20,37,12,3,5,48,11,1,1,9,12,3,11,3,4,52,8,12,7,11,7,10,6,16,3,20,11,6,16,5,20,2,2,1,2,2,2,3,3,0,3,2,3,1,0]},"type_origin_table":[{"module_name":"oracle","struct_name":"OracleAdminCap","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"},{"module_name":"oracle","struct_name":"OracleFeederCap","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"},{"module_name":"oracle","struct_name":"PriceOracle","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"},{"module_name":"oracle","struct_name":"Price","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":8}}}},"owner":"Immutable","previous_transaction":"5rr1KbGr5ht2kWrPwgArYuaYsauoDG8CpuJLnaKnkgL6","storage_rebate":15010000},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000001","version":2,"module_map":{"address":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,3,7,10,15,8,25,32,12,57,16,0,0,0,1,0,1,0,0,1,3,7,97,100,100,114,101,115,115,6,108,101,110,103,116,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,6,32,0,0,0,0,0,0,0,2,0],"ascii":[161,28,235,11,6,0,0,0,11,1,0,4,2,4,14,3,18,84,4,102,8,5,110,59,7,169,1,200,1,8,241,2,32,6,145,3,10,10,155,3,11,12,166,3,186,2,13,224,5,4,0,5,0,16,0,2,7,0,0,0,7,0,1,1,7,1,0,0,0,8,0,1,0,0,20,2,3,0,0,21,2,4,0,0,3,5,6,0,0,18,7,8,0,0,17,9,1,0,0,14,5,10,0,0,4,5,11,0,0,10,3,2,0,0,6,1,0,0,0,13,0,6,0,0,11,0,6,0,1,9,13,14,1,0,1,12,12,6,1,0,1,15,8,13,1,0,1,19,14,13,1,0,13,3,12,3,14,3,15,3,1,2,1,8,1,1,10,2,1,8,0,1,11,2,1,8,0,1,6,8,0,1,1,2,7,8,0,8,1,0,1,7,8,0,1,3,1,6,10,2,1,6,11,2,1,9,0,1,11,2,1,9,0,1,9,0,2,3,3,4,67,104,97,114,6,79,112,116,105,111,110,6,83,116,114,105,110,103,24,97,108,108,95,99,104,97,114,97,99,116,101,114,115,95,112,114,105,110,116,97,98,108,101,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,4,98,121,116,101,5,98,121,116,101,115,4,99,104,97,114,12,100,101,115,116,114,111,121,95,115,111,109,101,10,105,110,116,111,95,98,121,116,101,115,17,105,115,95,112,114,105,110,116,97,98,108,101,95,99,104,97,114,7,105,115,95,115,111,109,101,13,105,115,95,118,97,108,105,100,95,99,104,97,114,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,8,112,111,112,95,99,104,97,114,9,112,117,115,104,95,99,104,97,114,4,115,111,109,101,6,115,116,114,105,110,103,10,116,114,121,95,115,116,114,105,110,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,1,0,0,0,0,0,0,2,1,7,10,2,1,2,1,6,2,0,1,0,0,8,9,10,0,17,10,4,4,5,6,7,0,39,11,0,18,1,2,1,1,0,0,4,12,11,0,17,2,12,1,14,1,56,0,4,7,5,9,7,0,39,11,1,56,1,2,2,1,0,0,15,30,14,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,25,5,11,14,0,10,1,66,0,20,17,10,32,4,20,56,2,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,5,40,11,0,18,0,56,3,2,3,1,0,0,15,32,10,0,16,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,29,5,12,10,0,16,0,10,1,66,0,20,17,11,32,4,24,11,0,1,9,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,40,8,2,4,1,0,0,8,7,11,0,15,0,14,1,16,1,20,68,0,2,5,1,0,0,8,5,11,0,15,0,69,0,18,1,2,6,1,0,0,8,4,11,0,17,7,65,0,2,7,1,0,0,8,3,11,0,16,0,2,8,1,0,0,8,3,11,0,19,0,2,9,1,0,0,8,3,11,0,19,1,2,10,1,0,0,8,4,11,0,49,127,37,2,11,1,0,0,6,13,10,0,49,32,38,4,9,11,0,49,126,37,12,1,5,11,9,12,1,11,1,2,0,0,1,0,0],"bcs":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,7,7,15,13,8,28,32,12,60,4,0,0,0,1,0,1,1,0,1,6,9,0,1,10,2,3,98,99,115,8,116,111,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,0],"bit_vector":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,36,7,77,109,8,186,1,32,6,218,1,40,10,130,2,8,12,138,2,239,3,13,249,5,4,0,2,0,0,7,0,0,6,0,1,0,0,7,2,3,0,0,9,2,3,0,0,8,2,3,0,0,3,4,5,0,0,4,6,0,0,0,5,4,0,0,1,3,1,8,0,2,7,8,0,3,0,2,6,8,0,3,1,1,1,6,8,0,2,10,1,3,1,7,1,5,3,7,1,3,3,3,9,66,105,116,86,101,99,116,111,114,9,98,105,116,95,102,105,101,108,100,10,98,105,116,95,118,101,99,116,111,114,12,105,115,95,105,110,100,101,120,95,115,101,116,6,108,101,110,103,116,104,32,108,111,110,103,101,115,116,95,115,101,116,95,115,101,113,117,101,110,99,101,95,115,116,97,114,116,105,110,103,95,97,116,3,110,101,119,3,115,101,116,10,115,104,105,102,116,95,108,101,102,116,5,117,110,115,101,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,3,8,1,0,2,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,4,0,0,0,0,0,0,0,2,2,4,3,1,10,1,0,1,0,0,7,37,10,0,6,0,0,0,0,0,0,0,0,36,4,5,5,7,7,1,39,10,0,7,3,35,4,12,5,14,7,1,39,6,0,0,0,0,0,0,0,0,12,2,64,5,0,0,0,0,0,0,0,0,12,1,40,10,2,10,0,35,4,32,5,24,13,1,9,68,5,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,18,40,11,0,11,1,18,0,2,1,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,8,11,2,21,2,2,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,9,11,2,21,2,3,1,0,0,9,89,10,1,10,0,16,1,20,38,4,33,10,0,16,0,65,5,12,6,6,0,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,30,5,17,10,0,15,0,10,4,67,5,12,3,9,11,3,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,12,11,0,1,5,88,10,1,12,5,10,5,10,0,16,1,20,35,4,65,5,42,10,0,10,5,12,2,46,11,2,17,4,4,55,10,0,10,5,10,1,23,17,1,5,60,10,0,10,5,10,1,23,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,35,10,0,16,1,20,11,1,23,12,5,10,5,10,0,16,1,20,35,4,86,5,78,10,0,10,5,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,71,11,0,1,2,4,1,0,0,3,17,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,16,0,11,1,66,5,20,2,5,1,0,0,3,4,11,0,16,0,65,5,2,6,1,0,0,0,37,10,1,10,0,16,1,20,35,4,7,5,11,11,0,1,7,0,39,10,1,12,2,10,2,10,0,16,1,20,35,4,33,5,20,10,0,10,2,17,4,32,4,28,11,0,1,5,33,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,13,11,2,11,1,23,2,0,1,0,0,0],"debug":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,11,5,13,5,7,18,30,8,48,32,12,80,8,0,0,0,1,0,1,1,0,0,2,1,1,0,1,6,9,0,0,5,100,101,98,117,103,5,112,114,105,110,116,17,112,114,105,110,116,95,115,116,97,99,107,95,116,114,97,99,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"fixed_point32":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,30,5,36,22,7,58,122,8,180,1,32,6,212,1,68,10,152,2,5,12,157,2,137,2,13,166,4,2,0,4,0,0,7,0,0,7,0,1,0,0,3,0,1,0,0,1,2,3,0,0,2,1,3,0,0,5,3,1,0,0,6,3,4,0,2,3,8,0,1,3,2,3,3,1,8,0,1,1,1,4,4,1,4,4,4,0,12,70,105,120,101,100,80,111,105,110,116,51,50,20,99,114,101,97,116,101,95,102,114,111,109,95,114,97,116,105,111,110,97,108,21,99,114,101,97,116,101,95,102,114,111,109,95,114,97,119,95,118,97,108,117,101,10,100,105,118,105,100,101,95,117,54,52,13,102,105,120,101,100,95,112,111,105,110,116,51,50,13,103,101,116,95,114,97,119,95,118,97,108,117,101,7,105,115,95,122,101,114,111,12,109,117,108,116,105,112,108,121,95,117,54,52,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,16,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,3,8,1,0,1,0,0,0,0,0,3,8,2,0,2,0,0,0,0,0,3,8,3,0,2,0,0,0,0,0,3,8,4,0,1,0,0,0,0,0,3,8,5,0,2,0,0,0,0,0,0,2,1,8,3,0,1,0,0,5,20,11,0,53,14,1,16,0,20,53,24,49,32,48,12,2,10,2,7,0,37,4,15,5,17,7,3,39,11,2,52,2,1,1,0,0,5,29,14,1,16,0,20,6,0,0,0,0,0,0,0,0,34,4,7,5,9,7,4,39,11,0,53,49,32,47,14,1,16,0,20,53,26,12,2,10,2,7,0,37,4,24,5,26,7,2,39,11,2,52,2,2,1,0,0,6,48,10,0,53,49,64,47,12,5,11,1,53,49,32,47,12,4,10,4,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,15,5,17,7,1,39,11,5,11,4,26,12,3,10,3,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,8,12,2,5,32,11,0,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,35,5,37,7,5,39,10,3,7,0,37,4,42,5,44,7,5,39,11,3,52,18,0,2,3,1,0,0,7,3,11,0,18,0,2,4,1,0,0,7,4,14,0,16,0,20,2,5,1,0,0,7,6,14,0,16,0,20,6,0,0,0,0,0,0,0,0,33,2,0,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,3,7,15,23,8,38,32,12,70,8,0,0,0,1,0,0,0,0,2,0,0,0,1,10,2,4,104,97,115,104,8,115,104,97,50,95,50,53,54,8,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"option":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,6,3,10,120,4,130,1,14,5,144,1,135,1,7,151,2,219,1,8,242,3,32,6,146,4,20,10,166,4,7,11,173,4,2,12,175,4,128,4,13,175,8,2,14,177,8,2,0,15,0,22,0,0,7,1,0,0,0,14,0,1,1,0,0,17,2,1,1,0,0,12,3,4,1,0,0,13,3,4,1,0,0,4,5,4,1,0,0,1,3,6,1,0,0,3,5,6,1,0,0,10,7,2,1,3,0,9,8,0,1,0,0,8,9,2,1,0,0,2,9,10,1,0,0,18,8,2,1,0,0,19,8,1,1,0,0,7,11,2,1,2,0,6,1,2,1,0,0,5,1,0,1,0,0,20,1,12,1,0,1,4,14,4,1,0,1,11,13,4,1,0,1,16,2,12,1,0,19,2,18,2,17,2,3,2,0,2,1,2,2,2,0,1,11,0,1,9,0,1,9,0,1,6,11,0,1,9,0,1,1,2,6,11,0,1,9,0,6,9,0,1,6,9,0,2,6,11,0,1,9,0,9,0,2,7,11,0,1,9,0,9,0,1,7,11,0,1,9,0,1,7,9,0,2,11,0,1,9,0,9,0,1,10,9,0,1,6,10,9,0,2,6,10,9,0,6,9,0,2,6,9,0,6,10,9,0,2,9,0,6,10,9,0,1,7,10,9,0,2,9,0,7,10,9,0,3,11,0,1,9,0,11,0,1,9,0,7,10,9,0,2,9,0,10,9,0,6,79,112,116,105,111,110,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,119,105,116,104,95,100,101,102,97,117,108,116,8,99,111,110,116,97,105,110,115,12,100,101,115,116,114,111,121,95,110,111,110,101,12,100,101,115,116,114,111,121,95,115,111,109,101,20,100,101,115,116,114,111,121,95,119,105,116,104,95,100,101,102,97,117,108,116,7,101,120,116,114,97,99,116,4,102,105,108,108,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,4,110,111,110,101,6,111,112,116,105,111,110,9,115,105,110,103,108,101,116,111,110,4,115,111,109,101,4,115,119,97,112,12,115,119,97,112,95,111,114,95,102,105,108,108,6,116,111,95,118,101,99,3,118,101,99,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,4,0,0,0,0,0,3,8,1,0,4,0,0,0,0,0,0,2,1,21,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,0,4,11,0,55,0,56,1,2,3,1,0,0,0,5,11,0,55,0,56,1,32,2,4,1,0,0,0,5,11,0,55,0,11,1,56,2,2,5,1,0,0,0,13,10,0,56,3,4,4,5,8,11,0,1,7,1,39,11,0,55,0,6,0,0,0,0,0,0,0,0,66,2,2,6,1,0,0,15,19,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,17,11,1,1,11,3,6,0,0,0,0,0,0,0,0,66,2,12,2,11,2,2,7,1,0,0,16,18,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,16,11,3,6,0,0,0,0,0,0,0,0,66,2,20,12,2,11,2,2,8,1,0,0,17,16,11,0,54,0,12,2,10,2,46,56,1,4,8,5,12,11,2,1,7,0,39,11,2,11,1,68,2,2,9,1,0,0,0,13,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,69,2,2,10,1,0,0,0,14,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,6,0,0,0,0,0,0,0,0,67,2,2,11,1,0,0,18,20,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,12,3,10,3,69,2,12,2,11,3,11,1,68,2,11,2,2,12,1,0,0,19,21,11,0,54,0,12,4,10,4,46,56,1,4,10,56,4,12,2,5,14,10,4,69,2,56,5,12,2,11,2,12,3,11,4,11,1,68,2,11,3,2,13,1,0,0,20,15,11,0,58,0,12,3,13,3,46,56,1,4,10,11,1,12,2,5,13,13,3,69,2,12,2,11,2,2,14,1,0,0,20,16,14,0,56,3,4,4,5,6,7,1,39,11,0,58,0,12,2,13,2,69,2,12,1,11,2,70,2,0,0,0,0,0,0,0,0,11,1,2,15,1,0,0,0,10,14,0,56,6,4,4,5,6,7,0,39,11,0,58,0,70,2,0,0,0,0,0,0,0,0,2,16,1,0,0,0,3,11,0,58,0,2,0,0,0,2,0],"string":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,14,3,22,114,4,136,1,8,5,144,1,123,7,139,2,248,1,8,131,4,32,6,163,4,20,10,183,4,6,12,189,4,133,3,13,194,7,2,0,19,0,4,0,17,0,24,0,1,7,0,1,1,7,0,2,0,7,1,0,0,0,23,0,1,0,0,6,2,1,0,0,21,1,2,0,0,22,0,3,0,0,5,4,5,0,0,14,4,6,0,0,15,4,7,0,0,2,8,9,0,0,3,10,9,0,0,8,11,9,0,0,20,12,1,0,0,7,13,7,0,0,9,5,6,0,0,11,14,6,0,0,12,15,0,0,0,10,16,7,0,1,13,2,0,0,1,19,0,2,0,2,16,9,18,1,0,2,18,17,18,1,0,3,2,21,9,1,0,3,14,20,6,1,0,19,1,18,1,21,19,20,19,1,10,2,1,8,0,1,8,1,1,11,2,1,8,0,1,6,8,0,1,6,10,2,1,1,1,3,2,7,8,0,8,0,0,2,7,8,0,10,2,3,7,8,0,3,8,0,3,6,8,0,3,3,2,6,8,0,6,8,0,2,6,10,2,3,3,6,10,2,3,3,2,6,10,2,6,10,2,1,9,0,1,11,2,1,9,0,1,2,1,6,10,9,0,2,7,10,9,0,10,9,0,8,1,3,3,3,6,10,2,8,0,8,0,3,5,1,1,1,6,10,2,3,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,97,112,112,101,110,100,11,97,112,112,101,110,100,95,117,116,102,56,5,97,115,99,105,105,5,98,121,116,101,115,10,102,114,111,109,95,97,115,99,105,105,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,19,105,110,116,101,114,110,97,108,95,99,104,101,99,107,95,117,116,102,56,17,105,110,116,101,114,110,97,108,95,105,110,100,101,120,95,111,102,25,105,110,116,101,114,110,97,108,95,105,115,95,99,104,97,114,95,98,111,117,110,100,97,114,121,19,105,110,116,101,114,110,97,108,95,115,117,98,95,115,116,114,105,110,103,10,105,110,116,111,95,98,121,116,101,115,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,4,115,111,109,101,6,115,116,114,105,110,103,10,115,117,98,95,115,116,114,105,110,103,8,116,111,95,97,115,99,105,105,8,116,114,121,95,117,116,102,56,4,117,116,102,56,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,5,10,2,0,1,0,0,9,9,14,0,17,12,4,4,5,6,7,0,39,11,0,18,0,2,1,1,0,0,9,4,11,0,17,16,18,0,2,2,1,0,0,9,4,11,0,19,0,17,17,2,3,1,0,0,3,12,14,0,17,12,4,8,11,0,18,0,56,0,12,1,5,10,56,1,12,1,11,1,2,4,1,0,0,9,3,11,0,16,0,2,5,1,0,0,9,4,11,0,16,0,56,2,2,6,1,0,0,9,4,11,0,16,0,65,19,2,7,1,0,0,9,7,11,0,15,0,14,1,16,0,20,56,3,2,8,1,0,0,9,5,11,0,11,1,17,0,17,7,2,9,1,0,0,22,56,10,0,16,0,12,7,10,1,10,7,65,19,37,4,13,11,7,10,1,17,13,12,3,5,17,11,7,1,9,12,3,11,3,4,20,5,24,11,0,1,7,1,39,10,0,46,17,6,12,10,10,0,10,1,12,4,46,6,0,0,0,0,0,0,0,0,11,4,17,10,12,9,10,0,11,1,11,10,12,6,12,5,46,11,5,11,6,17,10,12,8,13,9,11,2,17,7,13,9,11,8,17,7,11,9,11,0,21,2,10,1,0,0,23,48,11,0,16,0,12,6,10,6,65,19,12,7,10,2,11,7,37,4,15,10,1,10,2,37,12,3,5,17,9,12,3,11,3,4,24,10,6,10,1,17,13,12,4,5,26,9,12,4,11,4,4,33,10,6,10,2,17,13,12,5,5,35,9,12,5,11,5,4,38,5,42,11,6,1,7,1,39,11,6,11,1,11,2,17,14,18,0,2,11,1,0,0,9,6,11,0,16,0,11,1,16,0,17,15,2,12,0,2,0,13,0,2,0,14,0,2,0,15,0,2,0,0,0,0],"type_name":[161,28,235,11,6,0,0,0,10,1,0,6,2,6,8,3,14,47,5,61,44,7,105,143,1,8,248,1,32,6,152,2,7,10,159,2,6,12,165,2,215,1,13,252,3,2,0,14,0,2,0,4,0,1,7,0,2,0,7,0,0,6,0,1,1,0,0,9,0,1,1,0,0,5,2,3,0,0,7,2,4,0,0,8,2,4,0,0,10,1,4,0,1,11,0,6,0,2,3,3,7,0,2,13,9,4,0,0,1,8,0,1,6,8,0,1,6,8,1,1,8,1,4,10,2,3,3,6,10,2,1,3,1,6,10,2,1,2,1,10,2,5,2,6,2,3,10,2,6,10,2,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,13,98,111,114,114,111,119,95,115,116,114,105,110,103,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,11,105,110,116,111,95,115,116,114,105,110,103,6,108,101,110,103,116,104,4,110,97,109,101,6,115,116,114,105,110,103,9,116,121,112,101,95,110,97,109,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,58,10,2,1,0,0,2,1,12,8,1,0,1,2,0,1,1,2,0,2,1,0,0,0,3,11,0,16,0,2,3,1,0,0,5,33,17,6,6,2,0,0,0,0,0,0,0,24,12,3,11,0,16,0,17,7,12,4,7,1,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,28,5,17,13,1,10,4,10,2,66,8,20,68,8,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,4,1,11,1,17,8,2,4,1,0,0,10,39,17,6,6,2,0,0,0,0,0,0,0,24,6,2,0,0,0,0,0,0,0,22,12,3,11,0,16,0,17,7,12,5,7,1,12,4,10,5,10,3,66,8,12,2,7,0,12,1,10,2,14,1,34,4,32,5,23,13,4,11,2,20,68,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,12,11,5,1,11,2,1,11,4,17,8,2,5,1,0,0,0,4,14,0,16,0,20,2,0,0,0],"vector":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,102,4,104,4,5,108,97,7,205,1,154,1,8,231,2,32,6,135,3,10,12,145,3,216,4,0,17,0,5,0,1,1,0,0,9,2,3,1,0,0,1,4,5,1,0,0,11,6,0,1,0,0,2,7,8,1,0,0,10,9,10,1,0,0,4,1,0,1,0,0,15,11,0,1,0,0,14,10,1,1,0,0,13,9,0,1,0,0,0,12,0,1,0,0,8,2,13,1,0,0,3,14,13,1,0,0,6,14,15,1,0,0,12,7,10,1,0,0,7,16,0,1,0,0,16,7,10,1,0,9,10,11,10,0,1,10,9,0,1,6,10,9,0,1,3,2,6,10,9,0,3,1,6,9,0,2,7,10,9,0,9,0,2,7,10,9,0,3,1,7,9,0,1,7,10,9,0,1,9,0,3,7,10,9,0,3,3,2,7,10,9,0,10,9,0,1,1,2,6,10,9,0,6,9,0,2,1,3,3,7,10,9,0,9,0,3,3,3,3,3,2,3,3,3,3,7,10,9,0,3,6,97,112,112,101,110,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,5,101,109,112,116,121,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,7,114,101,118,101,114,115,101,9,115,105,110,103,108,101,116,111,110,4,115,119,97,112,11,115,119,97,112,95,114,101,109,111,118,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,2,0,4,1,2,0,5,1,2,0,6,1,2,0,7,1,2,0,8,1,0,0,1,7,64,10,0,0,0,0,0,0,0,0,12,1,13,1,11,0,68,10,11,1,2,9,1,0,0,17,38,10,0,46,65,10,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,2,6,0,0,0,0,0,0,0,0,12,2,11,3,6,1,0,0,0,0,0,0,0,23,12,1,10,2,10,1,35,4,35,5,22,10,0,10,2,10,1,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,1,6,1,0,0,0,0,0,0,0,23,12,1,5,17,11,0,1,2,10,1,0,0,0,17,13,1,56,0,14,1,56,1,32,4,12,5,7,10,0,13,1,69,10,68,10,5,2,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,11,1,0,0,0,5,11,0,65,10,6,0,0,0,0,0,0,0,0,33,2,12,1,0,0,18,33,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,27,5,10,10,0,10,2,66,10,10,1,33,4,22,11,0,1,11,1,1,8,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,2,13,1,0,0,18,35,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,28,5,10,10,0,10,2,66,10,10,1,33,4,23,11,0,1,11,1,1,8,11,2,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,6,0,0,0,0,0,0,0,0,2,14,1,0,0,19,37,10,0,46,65,10,12,4,10,1,10,4,38,4,12,11,0,1,7,0,39,11,4,6,1,0,0,0,0,0,0,0,23,12,4,10,1,10,4,35,4,34,5,21,10,0,12,3,10,1,12,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,11,3,11,2,10,1,71,10,5,16,11,0,69,10,2,15,1,0,0,3,32,10,0,46,65,10,12,3,10,2,10,3,36,4,12,11,0,1,7,0,39,10,0,11,1,68,10,10,2,10,3,35,4,29,5,20,10,0,10,2,10,3,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,2,16,1,0,0,3,23,10,0,46,56,1,32,4,6,5,10,11,0,1,7,0,39,10,0,46,65,10,6,1,0,0,0,0,0,0,0,23,12,2,10,0,11,1,11,2,71,10,11,0,69,10,2,0]},"type_origin_table":[{"module_name":"fixed_point32","struct_name":"FixedPoint32","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"option","struct_name":"Option","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"Char","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"bit_vector","struct_name":"BitVector","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"string","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"type_name","struct_name":"TypeName","package":"0x0000000000000000000000000000000000000000000000000000000000000001"}],"linkage_table":{}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000002","version":10,"module_map":{"address":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,8,3,18,61,4,79,2,5,81,20,7,101,129,1,8,230,1,64,6,166,2,54,12,220,2,69,0,1,1,2,1,3,1,11,0,8,1,0,7,0,3,0,7,0,0,15,0,1,0,0,7,1,0,0,0,6,2,0,0,0,13,0,2,0,0,12,0,3,0,0,14,0,4,0,0,9,5,6,0,0,10,5,1,0,1,11,2,3,0,2,13,7,2,1,0,3,5,3,4,0,4,4,2,2,0,9,0,1,5,1,15,1,10,2,1,8,0,1,8,1,0,1,3,1,6,9,0,6,83,116,114,105,110,103,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,6,101,110,99,111,100,101,10,102,114,111,109,95,97,115,99,105,105,10,102,114,111,109,95,98,121,116,101,115,9,102,114,111,109,95,117,50,53,54,3,104,101,120,6,108,101,110,103,116,104,3,109,97,120,6,115,116,114,105,110,103,15,116,111,95,97,115,99,105,105,95,115,116,114,105,110,103,8,116,111,95,98,121,116,101,115,9,116,111,95,115,116,114,105,110,103,7,116,111,95,117,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,32,0,0,0,0,0,0,0,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,3,8,0,0,0,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,0,0,5,3,14,0,56,0,2,4,1,0,0,5,5,11,0,17,3,17,11,17,8,2,5,1,0,0,5,4,11,0,17,4,17,10,2,6,1,0,0,5,2,7,0,2,7,1,0,0,5,2,7,1,2,0],"bag":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,112,4,132,1,12,5,144,1,82,7,226,1,185,1,8,155,3,32,6,187,3,10,10,197,3,8,12,205,3,230,1,13,179,5,4,0,4,0,11,0,18,0,21,0,0,12,0,2,2,4,0,3,1,2,0,0,17,0,1,0,0,3,2,3,2,7,4,0,5,4,5,2,7,4,0,6,6,7,2,7,4,0,19,6,8,2,7,4,0,7,4,9,1,7,0,8,4,9,2,7,4,0,16,10,11,0,0,15,10,9,0,0,10,1,3,0,1,3,14,3,2,7,4,1,5,15,5,2,7,4,1,6,16,7,2,7,4,1,12,15,9,1,7,1,13,15,9,2,7,4,1,19,16,8,2,7,4,2,9,12,3,0,2,17,0,12,0,10,13,11,13,12,13,15,13,13,17,14,13,1,7,8,2,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,1,9,0,2,8,1,3,3,66,97,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,3,98,97,103,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,14,8,1,20,3,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,18,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,0,0,0,1,0],"balance":[161,28,235,11,6,0,0,0,14,1,0,4,2,4,16,3,20,83,4,103,2,5,105,99,7,204,1,224,1,8,172,3,32,6,204,3,74,10,150,4,10,11,160,4,4,12,164,4,219,2,13,255,6,4,14,131,7,4,15,135,7,2,0,3,0,16,0,1,4,1,0,1,0,0,4,1,0,1,1,2,2,0,0,17,0,1,1,0,0,15,2,1,1,0,0,5,3,4,1,2,0,10,5,6,1,0,0,6,7,1,1,0,0,19,8,6,1,0,0,11,9,1,1,0,0,13,10,6,1,0,0,18,11,6,1,0,0,9,6,8,1,0,0,4,12,6,1,0,0,7,13,8,1,0,0,8,4,1,1,0,1,12,14,15,0,7,3,1,6,11,1,1,9,0,1,3,1,6,11,0,1,9,0,1,9,0,1,11,0,1,9,0,2,7,11,0,1,9,0,3,1,11,1,1,9,0,2,7,11,0,1,9,0,11,1,1,9,0,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,7,11,1,1,9,0,2,3,6,8,2,2,11,1,1,9,0,6,8,2,1,6,8,2,1,5,7,66,97,108,97,110,99,101,6,83,117,112,112,108,121,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,22,99,114,101,97,116,101,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,115,13,99,114,101,97,116,101,95,115,117,112,112,108,121,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,23,100,101,115,116,114,111,121,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,12,100,101,115,116,114,111,121,95,122,101,114,111,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,4,106,111,105,110,6,115,101,110,100,101,114,5,115,112,108,105,116,3,115,117,105,12,115,117,112,112,108,121,95,118,97,108,117,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,17,3,1,2,1,17,3,0,3,1,3,0,1,0,0,8,4,11,0,55,0,20,2,1,1,0,0,8,4,11,0,55,1,20,2,2,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,0,2,3,1,0,0,8,24,10,1,6,255,255,255,255,255,255,255,255,10,0,55,1,20,23,35,4,9,5,13,11,0,1,7,1,39,10,0,55,1,20,10,1,22,11,0,54,1,21,11,1,57,1,2,4,1,0,0,1,24,11,1,58,1,12,2,10,0,55,1,20,10,2,38,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,10,2,23,11,0,54,1,21,11,2,2,5,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,1,2,6,1,0,0,1,15,11,1,58,1,12,2,10,0,55,0,20,11,2,22,10,0,54,0,21,11,0,55,0,20,2,7,1,0,0,8,22,10,0,55,0,20,10,1,38,4,7,5,11,11,0,1,7,2,39,10,0,55,0,20,10,1,23,11,0,54,0,21,11,1,57,1,2,8,1,0,0,1,8,10,0,55,0,20,12,1,11,0,11,1,56,0,2,9,1,0,0,8,13,14,0,55,0,20,6,0,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,11,0,58,1,1,2,10,0,0,0,8,11,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,57,1,2,11,0,0,0,8,12,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,58,1,1,2,12,3,0,0,8,3,11,0,58,0,2,1,0,0,0,0,3,1,3,0,14,0],"bcs":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,10,3,20,135,1,4,155,1,24,5,179,1,131,1,7,182,2,222,2,8,148,5,64,6,212,5,55,10,139,6,6,12,145,6,203,8,13,220,14,2,0,3,1,3,1,10,1,31,0,2,0,0,7,0,2,1,7,1,0,0,0,30,0,1,1,0,0,8,1,2,0,0,6,2,1,0,0,11,3,4,0,0,12,3,5,0,0,20,3,6,0,0,19,3,7,0,0,18,3,8,0,0,23,3,7,0,0,21,3,9,0,0,22,3,10,0,0,26,3,1,0,0,27,3,11,0,0,25,3,12,0,0,24,3,13,0,0,13,3,14,0,0,14,3,15,0,0,17,3,16,0,0,16,3,17,0,0,15,3,18,0,1,30,0,1,1,0,2,9,19,33,1,0,2,29,20,33,1,0,3,28,21,19,1,0,4,5,1,4,0,4,7,19,7,0,20,20,23,6,22,4,21,4,22,5,21,5,22,6,21,6,22,7,21,7,22,8,21,8,1,6,9,0,1,10,2,1,8,0,1,7,8,0,1,5,1,1,1,2,1,3,1,4,1,10,5,1,10,1,1,10,10,2,1,10,3,1,10,4,1,11,1,1,5,1,11,1,1,1,1,11,1,1,2,1,11,1,1,3,1,11,1,1,4,0,1,9,0,1,7,10,9,0,2,10,2,3,2,1,2,3,3,2,3,3,4,2,4,4,3,3,2,3,3,3,3,10,5,3,3,3,10,1,3,3,3,10,2,3,3,3,10,10,2,3,3,3,10,3,3,3,3,10,4,1,11,1,1,9,0,3,66,67,83,6,79,112,116,105,111,110,7,97,100,100,114,101,115,115,3,98,99,115,5,98,121,116,101,115,10,102,114,111,109,95,98,121,116,101,115,20,105,110,116,111,95,114,101,109,97,105,110,100,101,114,95,98,121,116,101,115,6,108,101,110,103,116,104,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,12,112,101,101,108,95,97,100,100,114,101,115,115,9,112,101,101,108,95,98,111,111,108,19,112,101,101,108,95,111,112,116,105,111,110,95,97,100,100,114,101,115,115,16,112,101,101,108,95,111,112,116,105,111,110,95,98,111,111,108,16,112,101,101,108,95,111,112,116,105,111,110,95,117,49,50,56,15,112,101,101,108,95,111,112,116,105,111,110,95,117,54,52,14,112,101,101,108,95,111,112,116,105,111,110,95,117,56,9,112,101,101,108,95,117,49,50,56,8,112,101,101,108,95,117,54,52,7,112,101,101,108,95,117,56,16,112,101,101,108,95,118,101,99,95,97,100,100,114,101,115,115,13,112,101,101,108,95,118,101,99,95,98,111,111,108,15,112,101,101,108,95,118,101,99,95,108,101,110,103,116,104,13,112,101,101,108,95,118,101,99,95,117,49,50,56,12,112,101,101,108,95,118,101,99,95,117,54,52,11,112,101,101,108,95,118,101,99,95,117,56,15,112,101,101,108,95,118,101,99,95,118,101,99,95,117,56,7,114,101,118,101,114,115,101,4,115,111,109,101,8,116,111,95,98,121,116,101,115,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,10,5,1,0,10,1,1,0,10,2,1,0,10,10,2,1,0,10,3,1,0,10,4,1,0,0,2,1,4,10,2,0,1,0,0,19,3,11,0,56,0,2,1,1,0,0,19,5,13,0,56,1,11,0,18,0,2,2,1,0,0,1,7,11,0,19,0,12,1,13,1,56,1,11,1,2,3,1,0,0,22,35,10,0,16,0,65,6,17,25,38,4,7,5,11,11,0,1,7,0,39,64,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,12,2,12,1,10,2,17,25,35,4,30,5,20,13,1,10,0,15,0,69,6,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,11,1,17,24,2,4,1,0,0,23,21,11,0,17,5,12,2,10,2,49,0,33,4,10,9,12,1,5,19,11,2,49,1,33,4,15,5,17,7,1,39,8,12,1,11,1,2,5,1,0,0,19,15,10,0,16,0,65,6,6,1,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,11,0,15,0,69,6,2,6,1,0,0,24,40,10,0,16,0,65,6,6,8,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,64,35,4,36,5,20,10,0,15,0,69,6,52,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,7,1,0,0,25,40,10,0,16,0,65,6,6,16,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,128,35,4,36,5,20,10,0,15,0,69,6,53,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,8,1,0,0,26,48,6,0,0,0,0,0,0,0,0,49,0,6,0,0,0,0,0,0,0,0,12,2,12,3,12,4,10,2,6,4,0,0,0,0,0,0,0,37,4,11,5,15,11,0,1,7,2,39,10,0,15,0,69,6,52,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,4,10,1,6,127,0,0,0,0,0,0,0,28,10,3,47,27,12,4,11,1,6,128,0,0,0,0,0,0,0,28,6,0,0,0,0,0,0,0,0,33,4,39,5,44,11,3,49,7,22,12,3,5,6,11,0,1,11,4,2,9,1,0,0,27,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,3,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,3,68,4,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,10,1,0,0,28,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,4,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,4,68,5,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,11,1,0,0,29,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,5,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,5,68,6,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,12,1,0,0,30,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,6,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,11,68,1,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,13,1,0,0,31,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,7,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,6,68,7,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,14,1,0,0,32,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,8,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,7,68,8,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,15,1,0,0,14,14,10,0,17,4,4,8,11,0,17,3,56,2,12,1,5,12,11,0,1,56,3,12,1,11,1,2,16,1,0,0,15,14,10,0,17,4,4,8,11,0,17,4,56,4,12,1,5,12,11,0,1,56,5,12,1,11,1,2,17,1,0,0,16,14,10,0,17,4,4,8,11,0,17,5,56,6,12,1,5,12,11,0,1,56,7,12,1,11,1,2,18,1,0,0,17,14,10,0,17,4,4,8,11,0,17,6,56,8,12,1,5,12,11,0,1,56,9,12,1,11,1,2,19,1,0,0,18,14,10,0,17,4,4,8,11,0,17,7,56,10,12,1,5,12,11,0,1,56,11,12,1,11,1,2,0,0,0],"bls12381":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,12,7,24,56,8,80,32,12,112,8,0,0,0,2,0,1,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,8,98,108,115,49,50,51,56,49,22,98,108,115,49,50,51,56,49,95,109,105,110,95,112,107,95,118,101,114,105,102,121,23,98,108,115,49,50,51,56,49,95,109,105,110,95,115,105,103,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"borrow":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,24,3,32,59,4,91,10,5,101,83,7,184,1,158,1,8,214,2,64,6,150,3,20,10,170,3,19,11,189,3,2,12,191,3,125,13,188,4,4,14,192,4,4,0,5,1,15,0,14,0,19,0,3,4,1,12,0,0,0,0,0,1,2,7,1,0,0,2,1,7,0,3,4,2,0,0,12,0,1,1,12,0,5,2,3,1,12,0,16,4,5,1,12,0,6,1,6,1,12,1,7,9,6,1,0,1,8,11,6,1,0,1,9,15,5,1,0,1,18,6,9,1,0,2,11,12,13,1,8,3,10,7,8,0,7,6,5,6,8,6,6,6,4,6,2,9,0,7,8,4,1,11,0,1,9,0,1,7,11,0,1,9,0,2,9,0,8,1,3,7,11,0,1,9,0,9,0,8,1,0,1,9,0,1,7,8,4,1,5,1,11,2,1,9,0,2,8,3,9,0,1,7,11,2,1,9,0,1,6,9,0,1,8,3,2,8,3,5,2,7,11,2,1,9,0,9,0,6,66,111,114,114,111,119,2,73,68,6,79,112,116,105,111,110,8,82,101,102,101,114,101,110,116,9,84,120,67,111,110,116,101,120,116,6,98,111,114,114,111,119,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,7,101,120,116,114,97,99,116,4,102,105,108,108,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,3,111,98,106,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,117,116,95,98,97,99,107,3,114,101,102,4,115,111,109,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,2,11,5,20,11,2,1,9,0,1,2,2,17,5,13,8,3,0,6,0,1,0,0,5,6,11,1,17,9,11,0,56,0,57,0,2,1,1,0,0,10,14,10,0,54,0,56,1,12,2,14,2,56,2,12,1,11,2,11,0,55,1,20,11,1,18,1,2,2,1,0,0,14,30,11,2,19,1,12,3,12,4,14,1,56,2,11,3,33,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,11,4,33,4,21,5,25,11,0,1,7,0,39,11,0,54,0,11,1,56,3,2,3,1,0,0,9,7,11,0,58,0,12,1,1,11,1,56,4,2,0,1,0,0,0,6,1,6,0],"clock":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,31,4,51,2,5,53,30,7,83,122,8,205,1,32,6,237,1,44,10,153,2,8,12,161,2,79,13,240,2,2,0,3,0,7,0,11,0,12,0,0,8,0,1,2,4,0,3,1,2,0,0,10,0,1,0,0,5,2,3,0,0,4,4,3,0,1,3,3,6,0,2,9,8,3,1,8,3,8,2,5,0,4,7,1,6,8,0,1,3,1,6,8,2,0,3,7,8,0,3,6,8,2,1,5,1,8,1,1,8,0,1,9,0,5,67,108,111,99,107,9,84,120,67,111,110,116,101,120,116,3,85,73,68,5,99,108,111,99,107,25,99,111,110,115,101,110,115,117,115,95,99,111,109,109,105,116,95,112,114,111,108,111,103,117,101,6,99,114,101,97,116,101,2,105,100,6,111,98,106,101,99,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,1,10,3,0,1,0,0,3,4,11,0,16,0,20,2,1,0,0,0,3,13,11,0,17,5,7,1,33,4,6,5,8,7,0,39,17,3,6,0,0,0,0,0,0,0,0,18,0,56,0,2,2,0,0,0,3,15,11,2,17,5,7,1,33,4,6,5,10,11,0,1,7,0,39,11,1,11,0,15,0,21,2,0,1,0],"coin":[161,28,235,11,6,0,0,0,13,1,0,20,2,20,62,3,82,155,2,4,237,2,34,5,143,3,221,2,7,236,5,164,5,8,144,11,64,6,208,11,30,10,238,11,52,11,162,12,6,12,168,12,249,4,13,161,17,14,14,175,17,14,0,15,1,11,1,43,1,48,0,12,0,42,0,56,0,58,0,59,0,64,0,1,12,1,0,1,0,2,12,1,0,1,0,7,12,1,0,1,0,3,3,1,0,1,1,5,7,0,2,4,7,1,0,0,3,5,7,0,4,0,4,1,0,1,4,6,4,1,0,1,5,9,4,0,7,8,2,0,9,10,7,0,0,55,0,1,1,0,0,57,2,3,1,0,0,50,0,4,1,0,0,51,5,6,1,0,0,66,7,1,1,0,0,12,7,8,1,0,0,13,9,10,1,0,0,24,11,12,1,0,0,33,12,13,1,0,0,54,14,12,1,0,0,45,15,16,1,0,0,35,17,16,1,0,0,47,18,12,1,0,0,23,18,19,1,0,0,67,20,12,1,0,0,22,12,16,1,0,0,16,21,22,1,2,0,36,23,12,1,0,0,38,24,13,1,0,0,14,25,1,1,0,0,37,26,16,1,0,0,62,27,16,1,0,0,63,28,16,1,0,0,60,27,16,1,0,0,61,28,16,1,0,0,25,29,30,1,0,0,28,29,31,1,0,0,29,29,32,1,0,0,26,29,31,1,0,0,27,29,33,1,0,0,49,5,4,1,0,1,48,41,32,0,2,46,34,46,1,0,3,65,41,31,0,4,17,34,3,1,2,4,19,43,1,1,0,4,22,13,16,1,0,4,32,42,13,1,0,4,35,37,1,1,0,4,47,36,13,1,0,4,52,4,1,1,0,4,66,8,1,1,0,4,67,16,13,1,0,5,20,35,16,0,5,40,20,35,0,6,44,44,16,1,12,8,34,39,40,1,2,9,41,32,45,0,40,34,41,34,39,34,8,34,38,34,9,34,4,34,12,34,42,34,36,34,46,34,34,34,37,34,35,34,17,34,45,12,32,45,1,6,11,2,1,9,0,1,3,1,11,2,1,9,0,1,11,8,1,9,0,1,6,11,8,1,9,0,1,7,11,2,1,9,0,1,7,11,8,1,9,0,1,6,11,0,1,9,0,1,6,11,7,1,9,0,1,7,11,0,1,9,0,1,7,11,7,1,9,0,2,11,7,1,9,0,7,8,10,1,11,0,1,9,0,1,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,10,2,7,11,7,1,9,0,11,0,1,9,0,0,2,7,11,0,1,9,0,11,0,1,9,0,3,7,11,0,1,9,0,3,7,8,10,1,10,11,0,1,9,0,1,7,8,10,7,9,0,2,10,2,10,2,10,2,11,5,1,8,11,7,8,10,2,11,2,1,9,0,11,1,1,9,0,3,7,11,2,1,9,0,3,7,8,10,2,7,11,2,1,9,0,3,2,7,11,2,1,9,0,11,0,1,9,0,4,7,11,2,1,9,0,3,5,7,8,10,3,6,11,2,1,9,0,7,11,1,1,9,0,8,6,3,6,11,2,1,9,0,7,11,1,1,9,0,8,4,1,6,11,1,1,9,0,1,2,1,8,6,1,8,4,1,11,5,1,8,11,1,9,0,1,8,9,2,7,11,7,1,9,0,3,2,7,11,7,1,9,0,11,7,1,9,0,3,3,3,10,11,0,1,9,0,1,6,9,0,1,1,1,10,2,2,7,11,8,1,9,0,3,2,7,11,8,1,9,0,11,7,1,9,0,2,9,0,5,1,8,11,1,11,5,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,15,67,117,114,114,101,110,99,121,67,114,101,97,116,101,100,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,85,114,108,5,97,115,99,105,105,7,98,97,108,97,110,99,101,11,98,97,108,97,110,99,101,95,109,117,116,4,98,117,114,110,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,13,99,114,101,97,116,101,95,115,117,112,112,108,121,8,100,101,99,105,109,97,108,115,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,6,100,101,108,101,116,101,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,122,101,114,111,13,100,105,118,105,100,101,95,105,110,116,111,95,110,12,102,114,111,109,95,98,97,108,97,110,99,101,12,103,101,116,95,100,101,99,105,109,97,108,115,15,103,101,116,95,100,101,115,99,114,105,112,116,105,111,110,12,103,101,116,95,105,99,111,110,95,117,114,108,8,103,101,116,95,110,97,109,101,10,103,101,116,95,115,121,109,98,111,108,8,105,99,111,110,95,117,114,108,2,105,100,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,12,105,110,116,111,95,98,97,108,97,110,99,101,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,4,106,111,105,110,4,109,105,110,116,17,109,105,110,116,95,97,110,100,95,116,114,97,110,115,102,101,114,12,109,105,110,116,95,98,97,108,97,110,99,101,4,110,97,109,101,3,110,101,119,10,110,101,119,95,117,110,115,97,102,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,3,112,117,116,4,115,111,109,101,5,115,112,108,105,116,6,115,116,114,105,110,103,6,115,117,112,112,108,121,12,115,117,112,112,108,121,95,105,109,109,117,116,10,115,117,112,112,108,121,95,109,117,116,12,115,117,112,112,108,121,95,118,97,108,117,101,6,115,121,109,98,111,108,4,116,97,107,101,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,5,116,121,112,101,115,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,15,117,112,100,97,116,101,95,105,99,111,110,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,13,117,112,100,97,116,101,95,115,121,109,98,111,108,3,117,114,108,4,117,116,102,56,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,2,31,8,9,12,11,7,1,9,0,1,2,6,31,8,9,18,2,39,8,6,53,8,4,21,8,6,30,11,5,1,8,11,2,2,2,31,8,9,55,11,8,1,9,0,3,2,1,18,2,2,34,0,34,1,34,0,1,0,0,16,4,11,0,55,0,56,0,2,1,1,0,0,3,6,11,0,58,0,12,1,17,43,11,1,2,2,1,0,0,16,3,11,0,55,0,2,3,1,0,0,16,3,11,0,54,0,2,4,1,0,0,16,4,11,0,55,1,56,1,2,5,1,0,0,16,3,11,0,55,1,2,6,1,0,0,16,3,11,0,54,1,2,7,1,0,0,16,5,11,1,17,44,11,0,57,1,2,8,1,0,0,13,6,11,0,58,1,12,1,17,43,11,1,2,9,1,0,0,16,7,11,2,17,44,11,0,11,1,56,2,57,1,2,10,1,0,0,16,6,11,0,11,1,56,3,56,4,1,2,11,1,4,0,13,10,11,1,58,1,12,2,17,43,11,0,54,1,11,2,56,4,1,2,12,1,0,0,16,6,11,0,54,1,11,1,11,2,56,5,2,13,1,0,0,38,59,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,11,11,0,1,11,2,1,7,1,39,10,1,10,0,46,56,6,37,4,18,5,24,11,0,1,11,2,1,7,2,39,64,12,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,3,10,0,46,56,6,10,1,26,12,4,40,10,3,10,1,6,1,0,0,0,0,0,0,0,23,35,4,53,5,42,13,5,10,0,10,4,10,2,56,7,68,12,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,34,11,0,1,11,2,1,11,5,2,14,1,0,0,16,5,11,0,17,44,56,8,57,1,2,15,1,0,0,13,7,11,0,58,1,12,1,17,43,11,1,56,9,2,16,1,0,0,16,25,14,0,56,10,4,4,5,8,11,6,1,7,0,39,10,6,17,44,11,0,56,11,57,0,11,6,17,44,11,1,11,3,17,33,11,2,17,31,11,4,17,33,11,5,57,2,2,17,1,0,0,16,8,11,2,17,44,11,0,54,0,11,1,56,12,57,1,2,18,1,0,0,16,5,11,0,54,0,11,1,56,12,2,19,1,4,0,13,9,11,1,58,1,12,2,17,43,11,0,54,0,11,2,56,13,2,20,1,4,0,16,7,11,0,11,1,11,3,56,14,11,2,56,15,2,21,1,4,0,16,5,11,2,11,1,54,2,21,2,22,1,4,0,16,5,11,2,11,1,54,3,21,2,23,1,4,0,16,5,11,2,11,1,54,4,21,2,24,1,4,0,16,7,11,2,17,47,56,16,11,1,54,5,21,2,25,1,0,0,16,4,11,0,55,6,20,2,26,1,0,0,16,4,11,0,55,2,20,2,27,1,0,0,16,4,11,0,55,3,20,2,28,1,0,0,16,4,11,0,55,4,20,2,29,1,0,0,16,4,11,0,55,5,20,2,30,1,0,0,16,3,11,0,55,0,2,2,1,0,1,1,2,1,3,1,4,1,5,1,1,0,34,1,34,2,34,3,34,4,34,5,34,6,34,0],"display":[161,28,235,11,6,0,0,0,13,1,0,16,2,16,46,3,62,132,1,4,194,1,22,5,216,1,196,1,7,156,3,223,2,8,251,5,64,6,187,6,20,10,207,6,38,11,245,6,6,12,251,6,160,3,13,155,10,6,14,161,10,6,0,14,1,31,0,18,0,26,0,27,0,32,0,33,0,36,0,0,12,1,8,1,0,1,3,1,8,1,0,8,3,1,8,1,1,4,7,0,3,2,7,0,3,6,4,0,4,3,12,0,6,5,2,0,7,7,7,2,1,0,0,0,0,24,0,1,1,8,0,25,2,1,1,8,0,12,0,3,1,8,0,35,4,3,1,8,0,9,5,3,1,8,0,11,6,3,1,8,0,15,5,3,1,8,0,29,7,3,1,8,0,23,8,9,1,8,0,37,10,11,1,8,0,19,10,12,1,8,0,13,13,1,1,8,0,10,5,3,1,8,2,16,14,3,1,3,3,24,13,28,0,3,34,21,22,0,4,20,8,9,1,0,5,28,19,3,1,12,6,30,17,18,0,7,17,3,30,2,1,0,7,22,31,3,2,1,0,7,29,26,27,2,1,0,8,14,11,14,0,14,12,14,17,1,13,23,21,25,16,14,13,29,19,25,20,25,2,6,8,6,7,8,7,1,11,0,1,9,0,4,6,8,6,10,8,3,10,8,3,7,8,7,0,1,7,11,0,1,9,0,3,7,11,0,1,9,0,8,3,8,3,3,7,11,0,1,9,0,10,8,3,10,8,3,2,7,11,0,1,9,0,8,3,1,6,8,6,1,1,1,6,11,0,1,9,0,1,13,1,6,11,8,2,8,3,8,3,1,7,8,7,1,9,0,3,11,0,1,9,0,3,3,1,8,3,1,6,8,7,1,5,2,9,0,5,2,13,11,8,2,8,3,8,3,1,6,8,5,1,8,4,1,11,2,1,9,0,2,3,3,2,8,3,8,3,2,7,11,8,2,9,0,9,1,6,9,0,2,9,0,9,1,1,8,5,1,11,1,1,9,0,1,11,8,2,9,0,9,1,3,7,11,8,2,9,0,9,1,9,0,9,1,7,68,105,115,112,108,97,121,14,68,105,115,112,108,97,121,67,114,101,97,116,101,100,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,6,86,101,99,77,97,112,14,86,101,114,115,105,111,110,85,112,100,97,116,101,100,3,97,100,100,12,97,100,100,95,105,110,116,101,114,110,97,108,12,97,100,100,95,109,117,108,116,105,112,108,101,15,99,114,101,97,116,101,95,97,110,100,95,107,101,101,112,15,99,114,101,97,116,101,95,105,110,116,101,114,110,97,108,7,100,105,115,112,108,97,121,4,101,100,105,116,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,6,102,105,101,108,100,115,12,102,114,111,109,95,112,97,99,107,97,103,101,2,105,100,6,105,110,115,101,114,116,13,105,115,95,97,117,116,104,111,114,105,122,101,100,3,110,101,119,15,110,101,119,95,119,105,116,104,95,102,105,101,108,100,115,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,6,115,101,110,100,101,114,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,112,100,97,116,101,95,118,101,114,115,105,111,110,7,118,101,99,95,109,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,3,21,8,5,19,11,8,2,8,3,8,3,37,13,1,2,1,21,8,4,2,2,3,21,8,4,37,13,19,11,8,2,8,3,8,3,2,14,1,14,0,14,0,1,0,0,3,11,11,0,56,0,4,4,5,8,11,1,1,7,0,39,11,1,56,1,2,1,1,0,0,15,43,14,1,65,16,12,6,10,6,14,2,65,16,33,4,9,5,15,11,0,1,11,3,1,7,1,39,6,0,0,0,0,0,0,0,0,12,5,11,0,11,3,56,2,12,4,10,5,10,6,35,4,41,5,26,13,4,14,1,10,5,66,16,20,14,2,10,5,66,16,20,56,3,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,21,11,4,2,2,1,4,0,3,8,11,0,10,1,56,2,11,1,46,17,18,56,4,2,3,1,4,0,20,24,10,0,55,0,20,72,1,0,22,10,0,54,0,21,10,0,55,0,20,12,1,10,0,55,1,20,12,2,11,0,55,2,17,15,11,1,11,2,57,0,56,5,2,4,1,4,0,3,5,11,0,11,1,11,2,56,3,2,5,1,4,0,24,38,14,1,65,16,12,4,10,4,14,2,65,16,33,4,9,5,13,11,0,1,7,1,39,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,35,5,20,10,0,14,1,10,3,66,16,20,14,2,10,3,66,16,20,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,15,11,0,1,2,6,1,4,0,3,11,10,0,54,1,14,1,56,6,1,1,11,0,11,1,11,2,56,3,2,7,1,4,0,3,7,11,0,54,1,14,1,56,6,1,1,2,8,1,0,0,3,3,11,0,56,7,2,9,1,0,0,3,4,11,0,55,0,20,2,10,1,0,0,3,3,11,0,55,1,2,11,0,0,0,28,12,11,0,17,14,12,1,14,1,17,15,57,1,56,8,11,1,56,9,72,0,0,57,2,2,12,0,0,0,3,6,11,0,54,1,11,1,11,2,56,10,2,0,2,0,1,0,0,0,14,1,14,2,14,0],"dynamic_field":[161,28,235,11,6,0,0,0,14,1,0,6,2,6,22,3,28,133,1,4,161,1,24,5,185,1,168,1,7,225,2,129,3,8,226,5,64,6,162,6,40,10,202,6,12,11,214,6,2,12,216,6,235,2,13,195,9,6,14,201,9,8,15,209,9,2,0,11,1,26,0,25,0,0,8,2,7,0,4,0,1,2,7,1,0,0,2,1,7,0,2,3,4,0,0,4,0,1,2,7,4,0,6,2,3,2,7,4,0,9,4,5,2,7,4,0,27,4,6,2,7,4,0,13,2,7,1,7,0,29,4,8,2,7,4,0,14,2,7,2,7,4,0,15,2,9,1,7,0,16,4,10,1,7,0,19,11,12,1,7,0,5,11,1,1,8,0,7,9,13,1,8,0,8,10,14,1,8,0,28,15,16,1,8,0,17,15,7,0,0,18,15,7,1,8,1,24,1,24,1,0,1,30,16,24,1,0,2,10,19,1,0,2,21,28,12,0,2,23,12,19,0,2,31,18,12,0,9,16,10,21,11,21,12,21,13,21,4,16,3,20,17,6,16,6,15,21,11,26,12,26,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,9,1,2,6,8,3,5,2,7,8,3,5,2,5,9,0,1,5,1,6,9,0,1,7,9,0,2,5,5,1,9,0,3,11,0,2,9,0,9,1,5,5,1,6,8,3,1,8,3,2,9,0,9,1,1,11,0,2,9,0,9,1,3,5,5,9,1,2,9,0,11,1,1,9,1,1,11,1,1,9,0,4,6,11,0,2,9,0,8,2,5,6,8,3,6,8,2,1,11,0,2,9,0,8,2,2,9,0,8,2,1,6,8,2,4,7,11,0,2,9,0,8,2,5,7,8,3,7,8,2,5,70,105,101,108,100,2,73,68,6,79,112,116,105,111,110,3,85,73,68,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,6,100,101,108,101,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,16,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,17,104,97,115,104,95,116,121,112,101,95,97,110,100,95,107,101,121,2,105,100,13,105,100,95,116,111,95,97,100,100,114,101,115,115,4,110,97,109,101,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,3,20,8,3,22,9,0,32,9,1,0,20,0,1,0,0,17,26,11,0,46,17,21,12,5,10,5,10,1,56,0,12,4,10,5,10,4,17,14,32,4,14,5,16,7,0,39,11,4,17,20,11,1,11,2,57,0,12,3,11,5,11,3,56,1,2,1,1,0,0,12,10,10,0,17,21,11,1,56,0,12,2,11,0,11,2,56,2,55,0,2,2,1,0,0,12,11,10,0,46,17,21,11,1,56,0,12,2,11,0,11,2,56,3,54,0,2,3,1,0,0,22,17,11,0,46,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,4,58,0,12,4,1,17,18,11,4,2,4,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,17,14,2,5,1,0,0,23,19,10,0,10,1,12,2,46,11,2,56,5,4,13,11,0,11,1,56,6,56,7,12,3,5,17,11,0,1,56,8,12,3,11,3,2,6,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,9,2,7,3,0,0,25,22,10,0,17,21,11,1,56,0,12,3,11,0,11,3,56,10,12,2,10,2,55,1,12,4,10,2,55,2,1,11,2,55,3,12,5,11,4,11,5,17,19,2,8,3,0,0,29,24,10,0,46,17,21,11,1,56,0,12,3,11,0,11,3,56,11,12,2,10,2,54,1,12,4,10,2,54,2,1,11,2,54,3,12,5,11,4,11,5,46,17,19,2,9,3,2,0,10,3,2,0,11,3,2,0,12,3,2,0,13,3,2,0,14,3,2,0,15,3,2,0,0,2,0,0,0,1,0,20,1,27,2,27,0,27,0,12,0],"dynamic_object_field":[161,28,235,11,6,0,0,0,10,1,0,8,2,8,20,3,28,138,1,4,166,1,26,5,192,1,131,1,7,195,2,178,2,8,245,4,64,10,181,5,6,11,187,5,2,12,189,5,233,1,0,11,1,22,0,10,0,21,0,3,7,1,0,0,1,1,7,1,0,0,3,0,7,0,3,2,4,0,0,4,0,1,2,7,12,0,6,2,3,2,7,12,0,9,4,5,2,7,12,0,23,4,6,2,7,12,0,12,2,7,1,7,0,13,2,7,2,7,12,0,17,2,8,1,7,1,20,1,24,1,0,1,25,10,24,1,0,2,4,0,1,2,7,4,2,5,18,1,1,8,2,7,15,11,1,8,2,8,19,20,1,8,2,13,2,7,2,7,4,2,14,2,15,1,7,2,15,4,19,1,7,2,16,22,7,1,8,2,23,4,6,2,7,4,2,24,22,10,1,8,3,17,11,12,1,8,3,18,17,12,0,3,26,16,17,0,19,6,9,13,14,14,10,6,11,6,15,14,12,6,18,6,17,13,13,13,16,6,7,12,8,12,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,8,2,3,11,0,1,9,0,8,2,11,0,1,9,0,1,9,0,1,6,9,0,1,8,2,2,11,0,1,9,0,8,2,1,11,0,1,9,0,2,6,8,3,5,1,6,8,3,1,5,2,5,9,0,2,7,8,3,5,1,7,9,0,4,11,0,1,9,0,11,0,1,9,0,9,1,5,2,5,5,2,11,0,1,9,0,5,1,11,1,1,9,0,2,73,68,6,79,112,116,105,111,110,3,85,73,68,7,87,114,97,112,112,101,114,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,4,110,97,109,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,19,9,0,0,10,0,1,0,0,9,21,11,1,57,0,12,5,14,2,56,0,12,4,10,0,10,5,11,4,56,1,11,0,11,5,12,3,46,11,3,56,2,1,17,21,11,2,56,3,2,1,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,2,56,4,2,2,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,5,56,6,2,3,1,0,0,21,20,11,1,57,0,12,3,10,0,10,3,12,2,46,11,2,56,2,12,5,17,21,11,5,56,7,12,4,11,0,11,3,56,8,1,11,4,2,4,1,0,0,14,7,11,1,57,0,12,2,11,0,11,2,56,9,2,5,1,0,0,23,20,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,9,2,11,0,11,2,56,2,12,3,17,21,11,3,56,10,2,6,1,0,0,23,21,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,56,11,2,11,0,11,2,56,2,12,3,1,11,3,17,20,56,12,2,0],"ecdsa_k1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,15,5,17,28,7,45,64,8,109,32,6,141,1,26,12,167,1,12,0,1,0,2,0,1,0,0,0,2,1,0,0,3,3,4,0,3,6,10,2,6,10,2,2,1,10,2,1,6,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,17,100,101,99,111,109,112,114,101,115,115,95,112,117,98,107,101,121,8,101,99,100,115,97,95,107,49,19,115,101,99,112,50,53,54,107,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,107,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,2,1,2,0,0],"ecdsa_r1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,10,5,12,24,7,36,46,8,82,32,6,114,26,12,140,1,8,0,0,0,1,0,1,0,0,2,2,3,0,3,6,10,2,6,10,2,2,1,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,8,101,99,100,115,97,95,114,49,19,115,101,99,112,50,53,54,114,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,114,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,0],"ecvrf":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,5,5,7,15,7,22,19,8,41,32,6,73,30,12,103,4,0,0,0,1,0,1,0,4,6,10,2,6,10,2,6,10,2,6,10,2,1,1,5,101,99,118,114,102,12,101,99,118,114,102,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,1,2,0,0],"ed25519":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,12,7,19,23,8,42,32,12,74,4,0,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,7,101,100,50,53,53,49,57,14,101,100,50,53,53,49,57,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"event":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,4,7,12,11,8,23,32,12,55,4,0,1,0,0,0,1,1,3,1,9,0,0,4,101,109,105,116,5,101,118,101,110,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"groth16":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,16,3,18,50,5,68,76,7,144,1,237,2,8,253,3,32,6,157,4,30,10,187,4,32,12,219,4,180,1,13,143,6,14,0,10,0,0,7,0,0,1,7,0,0,3,7,0,0,2,7,0,0,5,0,1,0,0,6,0,1,0,0,16,2,3,0,0,17,3,4,0,0,15,5,6,0,0,14,5,7,0,0,12,8,3,0,0,13,9,3,0,0,18,10,11,0,0,19,12,11,0,0,1,8,0,4,10,2,10,2,10,2,10,2,1,8,1,1,10,10,2,1,10,2,1,8,2,1,8,3,2,6,8,0,6,10,2,2,2,6,10,2,4,6,8,0,6,8,1,6,8,2,6,8,3,1,1,7,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,5,67,117,114,118,101,20,80,114,101,112,97,114,101,100,86,101,114,105,102,121,105,110,103,75,101,121,11,80,114,111,111,102,80,111,105,110,116,115,17,80,117,98,108,105,99,80,114,111,111,102,73,110,112,117,116,115,22,97,108,112,104,97,95,103,49,95,98,101,116,97,95,103,50,95,98,121,116,101,115,8,98,108,115,49,50,51,56,49,5,98,110,50,53,52,5,98,121,116,101,115,21,100,101,108,116,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,21,103,97,109,109,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,7,103,114,111,116,104,49,54,2,105,100,21,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,30,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,95,105,110,116,101,114,110,97,108,23,112,114,111,111,102,95,112,111,105,110,116,115,95,102,114,111,109,95,98,121,116,101,115,30,112,117,98,108,105,99,95,112,114,111,111,102,95,105,110,112,117,116,115,95,102,114,111,109,95,98,121,116,101,115,14,112,118,107,95,102,114,111,109,95,98,121,116,101,115,12,112,118,107,95,116,111,95,98,121,116,101,115,20,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,29,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,95,105,110,116,101,114,110,97,108,21,118,107,95,103,97,109,109,97,95,97,98,99,95,103,49,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,11,2,1,2,4,20,10,2,4,10,2,9,10,2,8,10,2,2,2,1,7,10,2,3,2,1,7,10,2,0,1,0,0,0,3,49,0,18,0,2,1,1,0,0,0,3,49,1,18,0,2,2,1,0,0,0,6,11,0,11,1,11,2,11,3,18,1,2,3,1,0,0,4,24,64,5,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,68,5,13,1,14,0,16,1,20,68,5,13,1,14,0,16,2,20,68,5,13,1,14,0,16,3,20,68,5,11,1,2,4,1,0,0,0,3,11,0,18,2,2,5,1,0,0,0,3,11,0,18,3,2,6,1,0,0,0,6,11,0,16,4,20,11,1,17,7,2,7,0,2,0,8,1,0,0,0,17,11,0,16,4,20,10,1,16,0,10,1,16,1,10,1,16,2,11,1,16,3,11,2,16,5,11,3,16,6,17,9,2,9,0,2,0,1,0,1,1,1,2,1,3,0,0,2,0,3,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,7,7,19,26,8,45,32,12,77,8,0,1,0,0,0,1,0,0,2,0,1,0,1,6,10,2,1,10,2,10,98,108,97,107,101,50,98,50,53,54,4,104,97,115,104,9,107,101,99,99,97,107,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"hex":[161,28,235,11,6,0,0,0,8,1,0,4,3,4,21,4,25,2,5,27,37,7,64,44,8,108,64,6,172,1,159,6,12,203,7,194,2,0,4,1,5,0,3,0,0,0,0,1,0,0,0,0,2,1,1,0,1,0,3,4,1,0,3,1,1,10,2,1,2,5,10,10,2,7,10,2,3,3,10,2,2,7,10,9,0,10,9,0,0,4,2,3,3,10,2,5,1,1,1,2,2,6,97,112,112,101,110,100,6,100,101,99,111,100,101,11,100,101,99,111,100,101,95,98,121,116,101,6,101,110,99,111,100,101,3,104,101,120,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,10,10,2,130,6,128,2,2,48,48,2,48,49,2,48,50,2,48,51,2,48,52,2,48,53,2,48,54,2,48,55,2,48,56,2,48,57,2,48,97,2,48,98,2,48,99,2,48,100,2,48,101,2,48,102,2,49,48,2,49,49,2,49,50,2,49,51,2,49,52,2,49,53,2,49,54,2,49,55,2,49,56,2,49,57,2,49,97,2,49,98,2,49,99,2,49,100,2,49,101,2,49,102,2,50,48,2,50,49,2,50,50,2,50,51,2,50,52,2,50,53,2,50,54,2,50,55,2,50,56,2,50,57,2,50,97,2,50,98,2,50,99,2,50,100,2,50,101,2,50,102,2,51,48,2,51,49,2,51,50,2,51,51,2,51,52,2,51,53,2,51,54,2,51,55,2,51,56,2,51,57,2,51,97,2,51,98,2,51,99,2,51,100,2,51,101,2,51,102,2,52,48,2,52,49,2,52,50,2,52,51,2,52,52,2,52,53,2,52,54,2,52,55,2,52,56,2,52,57,2,52,97,2,52,98,2,52,99,2,52,100,2,52,101,2,52,102,2,53,48,2,53,49,2,53,50,2,53,51,2,53,52,2,53,53,2,53,54,2,53,55,2,53,56,2,53,57,2,53,97,2,53,98,2,53,99,2,53,100,2,53,101,2,53,102,2,54,48,2,54,49,2,54,50,2,54,51,2,54,52,2,54,53,2,54,54,2,54,55,2,54,56,2,54,57,2,54,97,2,54,98,2,54,99,2,54,100,2,54,101,2,54,102,2,55,48,2,55,49,2,55,50,2,55,51,2,55,52,2,55,53,2,55,54,2,55,55,2,55,56,2,55,57,2,55,97,2,55,98,2,55,99,2,55,100,2,55,101,2,55,102,2,56,48,2,56,49,2,56,50,2,56,51,2,56,52,2,56,53,2,56,54,2,56,55,2,56,56,2,56,57,2,56,97,2,56,98,2,56,99,2,56,100,2,56,101,2,56,102,2,57,48,2,57,49,2,57,50,2,57,51,2,57,52,2,57,53,2,57,54,2,57,55,2,57,56,2,57,57,2,57,97,2,57,98,2,57,99,2,57,100,2,57,101,2,57,102,2,97,48,2,97,49,2,97,50,2,97,51,2,97,52,2,97,53,2,97,54,2,97,55,2,97,56,2,97,57,2,97,97,2,97,98,2,97,99,2,97,100,2,97,101,2,97,102,2,98,48,2,98,49,2,98,50,2,98,51,2,98,52,2,98,53,2,98,54,2,98,55,2,98,56,2,98,57,2,98,97,2,98,98,2,98,99,2,98,100,2,98,101,2,98,102,2,99,48,2,99,49,2,99,50,2,99,51,2,99,52,2,99,53,2,99,54,2,99,55,2,99,56,2,99,57,2,99,97,2,99,98,2,99,99,2,99,100,2,99,101,2,99,102,2,100,48,2,100,49,2,100,50,2,100,51,2,100,52,2,100,53,2,100,54,2,100,55,2,100,56,2,100,57,2,100,97,2,100,98,2,100,99,2,100,100,2,100,101,2,100,102,2,101,48,2,101,49,2,101,50,2,101,51,2,101,52,2,101,53,2,101,54,2,101,55,2,101,56,2,101,57,2,101,97,2,101,98,2,101,99,2,101,100,2,101,101,2,101,102,2,102,48,2,102,49,2,102,50,2,102,51,2,102,52,2,102,53,2,102,54,2,102,55,2,102,56,2,102,57,2,102,97,2,102,98,2,102,99,2,102,100,2,102,101,2,102,102,10,2,1,0,0,1,0,0,2,33,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,4,12,5,12,3,10,3,10,4,35,4,31,5,12,13,5,12,2,7,2,12,1,11,2,14,1,14,0,10,3,66,1,20,52,66,0,20,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,5,2,1,1,0,0,5,47,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,3,12,4,12,2,10,3,6,2,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,14,5,16,7,0,39,10,2,10,3,35,4,45,5,21,14,0,10,2,66,1,20,17,2,49,16,24,14,0,10,2,6,1,0,0,0,0,0,0,0,22,66,1,20,17,2,22,12,1,13,4,11,1,68,1,11,2,6,2,0,0,0,0,0,0,0,22,12,2,5,16,11,4,2,2,0,0,0,6,64,49,48,10,0,37,4,9,10,0,49,58,35,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,5,5,62,49,65,10,0,37,4,27,10,0,49,71,35,12,2,5,29,9,12,2,11,2,4,38,49,10,11,0,22,49,65,23,12,4,5,60,49,97,10,0,37,4,47,10,0,49,103,35,12,3,5,49,9,12,3,11,3,4,52,5,54,7,1,39,49,10,11,0,22,49,97,23,12,4,11,4,12,5,11,5,2,0],"hmac":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,10,7,17,19,8,36,32,12,68,4,0,0,0,1,0,1,0,2,6,10,2,6,10,2,1,10,2,4,104,109,97,99,13,104,109,97,99,95,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"kiosk":[161,28,235,11,6,0,0,0,14,1,0,24,2,24,94,3,118,135,3,4,253,3,68,5,193,4,137,4,7,202,8,159,8,8,233,16,64,6,169,17,130,1,10,171,18,101,11,144,19,8,12,152,19,146,14,13,170,33,18,14,188,33,6,15,194,33,2,0,50,1,62,0,21,0,26,0,31,0,32,0,34,0,61,0,86,0,88,0,89,0,90,0,8,12,0,0,9,12,0,0,13,12,1,12,1,0,1,0,0,0,4,7,0,0,10,7,0,0,11,7,0,0,6,3,1,12,1,0,7,3,1,12,1,0,5,3,1,12,1,1,12,7,1,0,0,2,0,4,1,0,1,3,2,12,1,0,1,7,3,7,0,7,18,4,0,8,14,2,0,10,15,12,1,0,1,10,16,0,1,0,1,11,17,2,0,0,27,0,1,0,0,59,0,2,0,0,25,3,4,0,0,83,5,1,0,0,84,6,1,0,0,64,7,1,1,12,0,56,8,1,1,12,0,87,9,10,1,12,0,54,11,1,1,12,0,65,12,1,1,12,0,29,9,1,1,12,0,71,13,14,1,12,0,55,15,16,1,12,0,75,17,14,1,12,0,79,18,1,1,12,0,97,19,4,0,0,57,20,1,1,12,0,66,20,1,1,12,0,94,21,22,0,0,40,23,24,0,0,41,23,24,1,12,0,46,23,24,0,0,44,23,24,0,0,45,23,24,0,0,39,25,24,0,0,93,25,22,0,0,82,26,1,0,0,91,27,28,0,0,92,21,22,0,0,63,27,29,0,0,48,27,30,0,0,69,27,31,0,0,70,25,32,0,0,22,33,34,1,12,0,23,9,35,1,12,0,24,9,36,1,12,0,80,37,1,1,12,0,53,38,39,0,0,73,40,39,1,12,0,72,40,39,1,12,0,74,40,31,1,12,1,30,74,10,1,0,1,47,73,24,1,0,2,96,75,31,1,0,2,98,1,48,1,0,3,38,50,51,1,0,3,76,65,1,1,0,3,87,76,51,1,0,3,96,63,31,1,0,4,19,59,1,2,7,4,4,35,78,24,1,7,4,77,54,57,2,7,4,4,78,54,55,2,7,4,5,19,59,1,2,7,12,5,22,78,81,2,7,12,5,23,54,82,2,7,12,5,35,78,24,1,7,5,36,78,24,2,7,12,5,77,54,57,2,7,12,6,33,10,1,1,3,7,28,46,1,0,7,42,34,39,1,8,7,59,0,46,0,7,95,28,39,0,9,85,10,1,1,8,9,88,44,1,1,8,10,60,67,68,1,0,11,81,42,29,0,65,43,64,45,44,47,61,45,45,47,17,10,16,10,52,53,58,56,20,10,49,53,59,60,61,10,5,10,8,10,51,53,59,61,48,47,52,64,46,47,59,66,66,10,42,31,41,31,43,47,47,47,49,64,53,56,56,77,57,56,50,79,50,80,54,56,55,56,1,7,8,18,0,2,8,0,8,1,3,8,0,8,1,7,8,18,1,11,12,1,8,15,3,7,8,0,6,8,1,6,8,18,3,7,8,0,6,8,1,5,3,7,8,0,6,8,1,9,0,4,7,8,0,6,8,1,6,11,16,1,9,0,9,0,3,7,8,0,6,8,1,8,13,1,9,0,4,7,8,0,6,8,1,8,13,3,4,7,8,0,6,8,1,9,0,3,3,7,8,0,8,13,11,12,1,8,15,2,9,0,11,17,1,9,0,5,7,8,0,6,8,1,8,13,3,7,8,18,1,11,2,1,9,0,3,7,8,0,11,2,1,9,0,11,12,1,8,15,2,7,8,0,11,2,1,9,0,4,7,8,0,6,8,1,11,10,1,3,7,8,18,2,7,8,0,9,0,1,7,8,0,1,7,8,14,2,6,8,0,8,13,1,1,2,7,8,0,6,8,1,3,7,8,0,6,8,1,1,1,6,8,0,1,6,8,14,1,5,1,14,1,3,1,7,11,11,1,8,15,3,6,8,0,6,8,1,8,13,1,6,9,0,1,7,9,0,2,9,0,8,3,3,7,8,0,9,0,8,3,1,6,8,1,1,8,13,1,6,11,2,1,9,0,2,8,1,8,0,1,6,8,18,1,8,1,2,9,0,5,1,8,0,1,8,14,1,8,15,1,11,11,1,9,0,5,8,14,8,13,8,14,14,11,11,1,8,15,2,11,11,1,9,0,7,8,18,1,11,12,1,9,0,3,8,13,8,13,8,13,2,8,5,3,2,7,8,14,9,0,1,11,10,1,9,1,2,8,4,9,0,1,9,1,2,8,13,8,13,3,7,8,14,9,0,9,1,1,11,7,1,9,0,1,11,9,1,9,0,2,9,0,3,1,6,11,12,1,9,0,2,8,6,1,2,7,11,11,1,9,0,11,12,1,9,0,1,11,8,1,9,0,3,8,13,3,8,13,1,11,17,1,9,0,6,8,13,8,13,3,8,13,8,14,8,13,5,8,13,8,13,8,13,3,3,3,8,14,8,13,8,13,3,3,3,3,1,6,11,10,1,9,0,1,11,10,1,9,0,1,6,11,11,1,9,0,3,7,11,11,1,9,0,3,7,8,18,1,8,4,2,6,8,14,9,0,1,8,6,1,8,5,1,6,9,1,1,7,9,1,7,66,97,108,97,110,99,101,6,66,111,114,114,111,119,4,67,111,105,110,2,73,68,4,73,116,101,109,12,73,116,101,109,68,101,108,105,115,116,101,100,10,73,116,101,109,76,105,115,116,101,100,13,73,116,101,109,80,117,114,99,104,97,115,101,100,5,75,105,111,115,107,13,75,105,111,115,107,79,119,110,101,114,67,97,112,7,76,105,115,116,105,110,103,4,76,111,99,107,6,79,112,116,105,111,110,11,80,117,114,99,104,97,115,101,67,97,112,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,16,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,10,98,111,114,114,111,119,95,118,97,108,18,99,108,111,115,101,95,97,110,100,95,119,105,116,104,100,114,97,119,4,99,111,105,110,7,100,101,102,97,117,108,116,6,100,101,108,101,116,101,6,100,101,108,105,115,116,12,100,101,115,116,114,111,121,95,115,111,109,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,4,101,109,105,116,5,101,118,101,110,116,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,3,102,111,114,12,102,114,111,109,95,98,97,108,97,110,99,101,10,104,97,115,95,97,99,99,101,115,115,8,104,97,115,95,105,116,101,109,18,104,97,115,95,105,116,101,109,95,119,105,116,104,95,116,121,112,101,2,105,100,12,105,115,95,101,120,99,108,117,115,105,118,101,9,105,115,95,108,105,115,116,101,100,21,105,115,95,108,105,115,116,101,100,95,101,120,99,108,117,115,105,118,101,108,121,9,105,115,95,108,111,99,107,101,100,7,105,115,95,115,111,109,101,10,105,116,101,109,95,99,111,117,110,116,7,105,116,101,109,95,105,100,5,107,105,111,115,107,15,107,105,111,115,107,95,101,120,116,101,110,115,105,111,110,8,107,105,111,115,107,95,105,100,19,107,105,111,115,107,95,111,119,110,101,114,95,99,97,112,95,102,111,114,4,108,105,115,116,22,108,105,115,116,95,119,105,116,104,95,112,117,114,99,104,97,115,101,95,99,97,112,4,108,111,99,107,13,108,111,99,107,95,105,110,116,101,114,110,97,108,9,109,105,110,95,112,114,105,99,101,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,5,111,119,110,101,114,5,112,108,97,99,101,14,112,108,97,99,101,95,97,110,100,95,108,105,115,116,14,112,108,97,99,101,95,105,110,116,101,114,110,97,108,5,112,114,105,99,101,7,112,114,111,102,105,116,115,14,112,114,111,102,105,116,115,95,97,109,111,117,110,116,11,112,114,111,102,105,116,115,95,109,117,116,8,112,117,114,99,104,97,115,101,17,112,117,114,99,104,97,115,101,95,99,97,112,95,105,116,101,109,18,112,117,114,99,104,97,115,101,95,99,97,112,95,107,105,111,115,107,22,112,117,114,99,104,97,115,101,95,99,97,112,95,109,105,110,95,112,114,105,99,101,17,112,117,114,99,104,97,115,101,95,119,105,116,104,95,99,97,112,3,112,117,116,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,19,114,101,116,117,114,110,95,112,117,114,99,104,97,115,101,95,99,97,112,10,114,101,116,117,114,110,95,118,97,108,6,115,101,110,100,101,114,20,115,101,116,95,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,9,115,101,116,95,111,119,110,101,114,16,115,101,116,95,111,119,110,101,114,95,99,117,115,116,111,109,12,115,104,97,114,101,95,111,98,106,101,99,116,3,115,117,105,4,116,97,107,101,8,116,114,97,110,115,102,101,114,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,3,117,105,100,7,117,105,100,95,109,117,116,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,16,117,105,100,95,109,117,116,95,105,110,116,101,114,110,97,108,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,0,2,5,42,8,14,68,11,11,1,8,15,63,5,48,14,20,1,1,2,2,42,8,14,37,8,13,2,2,4,42,8,14,52,8,13,49,8,13,58,3,3,2,2,52,8,13,49,8,13,4,2,1,42,8,13,5,2,2,42,8,13,43,1,6,2,1,42,8,13,7,2,3,50,8,13,42,8,13,67,3,8,2,3,50,8,13,42,8,13,67,3,9,2,2,50,8,13,42,8,13,7,10,9,10,8,10,2,10,0,0,4,0,41,12,10,0,17,1,12,1,12,2,11,1,11,0,46,17,67,56,0,11,2,56,1,2,1,1,0,0,41,19,10,0,17,62,56,2,10,0,46,17,67,73,0,0,0,0,9,18,0,12,2,11,0,17,62,14,2,56,3,18,1,12,1,11,2,11,1,2,2,1,0,0,49,38,11,0,19,0,1,12,6,1,12,7,12,5,11,1,19,1,12,4,12,3,14,5,17,63,11,4,33,4,17,5,21,11,2,1,7,0,39,11,6,73,0,0,0,0,33,4,26,5,30,11,2,1,7,3,39,11,3,17,60,11,5,17,60,11,7,11,2,56,4,2,3,1,0,0,1,17,10,0,11,1,17,24,4,5,5,11,11,0,1,11,2,1,7,0,39,11,2,17,67,11,0,15,0,21,2,4,1,0,0,1,14,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,2,11,0,15,0,21,2,5,1,0,0,1,13,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,11,2,56,5,2,6,1,0,0,1,13,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,11,3,56,6,2,7,1,0,0,52,68,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,21,32,4,18,5,22,11,0,1,7,8,39,10,0,10,2,12,4,46,11,4,17,23,32,4,31,5,35,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,19,4,43,5,47,11,0,1,7,11,39,10,0,16,1,20,73,1,0,0,0,23,10,0,15,1,21,10,0,15,2,10,2,9,18,5,56,7,1,11,0,15,2,11,2,18,4,56,8,2,8,1,0,0,58,49,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,4,46,11,4,56,9,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,5,46,11,5,17,23,32,4,30,5,34,11,0,1,7,4,39,10,0,15,2,10,2,9,18,5,10,3,56,10,11,0,46,56,3,11,2,11,3,57,0,56,11,2,9,1,0,0,39,13,14,2,56,12,12,4,10,0,10,1,11,2,56,13,11,0,11,1,11,4,11,3,56,14,2,10,1,0,0,52,60,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,56,9,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,23,32,4,30,5,34,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,22,4,42,5,46,11,0,1,7,12,39,10,0,15,2,10,2,9,18,5,56,15,1,11,0,46,56,3,11,2,57,1,56,16,2,11,1,0,0,62,56,10,0,15,2,10,1,9,18,5,56,15,12,4,10,0,15,2,10,1,18,4,56,8,12,3,10,0,16,1,20,73,1,0,0,0,23,10,0,15,1,21,10,4,14,2,56,17,33,4,27,5,31,11,0,1,7,1,39,10,0,15,2,10,1,18,6,56,18,1,10,0,15,3,11,2,56,19,10,0,46,56,3,10,1,10,4,57,2,56,20,11,3,11,1,11,4,11,0,46,56,3,56,21,2,12,1,0,0,69,64,10,0,11,1,17,24,4,5,5,11,11,0,1,11,4,1,7,0,39,10,0,10,2,12,5,46,11,5,56,9,4,19,5,25,11,0,1,11,4,1,7,11,39,10,0,10,2,12,6,46,11,6,17,22,32,4,34,5,40,11,0,1,11,4,1,7,6,39,10,0,15,2,10,2,8,18,5,10,3,56,10,11,3,12,7,11,2,12,8,11,4,17,62,12,9,11,0,46,56,3,12,10,11,9,11,10,11,8,11,7,57,3,2,13,1,0,0,70,68,11,1,58,3,12,6,12,4,12,5,17,60,11,4,12,3,14,2,56,17,12,7,10,7,11,6,38,4,16,5,20,11,0,1,7,1,39,10,0,46,56,3,11,5,33,4,27,5,31,11,0,1,7,5,39,10,0,15,2,10,3,8,18,5,56,15,1,10,0,15,3,11,2,56,19,10,0,16,1,20,73,1,0,0,0,23,10,0,15,1,21,10,0,15,2,10,3,18,6,56,18,1,10,0,15,2,10,3,18,4,56,8,11,3,11,7,11,0,46,56,3,56,21,2,14,1,0,0,71,27,11,1,58,3,1,12,3,12,4,12,2,10,0,46,56,3,11,4,33,4,13,5,17,11,0,1,7,5,39,11,0,15,2,11,3,8,18,5,56,15,1,11,2,17,60,2,15,1,0,0,72,45,10,0,11,1,17,24,4,5,5,11,11,0,1,11,3,1,7,0,39,14,2,56,22,4,33,11,2,56,23,12,6,10,6,10,0,16,3,56,24,37,4,24,5,30,11,0,1,11,3,1,7,2,39,11,6,12,4,5,37,10,0,16,3,56,24,12,4,11,4,12,5,11,0,15,3,11,5,11,3,56,25,2,16,3,0,0,1,11,10,0,15,2,14,1,56,12,18,6,8,56,26,11,0,11,1,56,5,2,17,3,0,0,1,16,10,0,16,1,20,73,1,0,0,0,22,10,0,15,1,21,11,0,15,2,14,1,56,12,18,4,11,1,56,27,2,18,3,0,0,1,3,11,0,15,2,2,19,1,0,0,1,6,11,0,16,2,11,1,18,4,56,28,2,20,1,0,0,1,6,11,0,16,2,11,1,18,4,56,29,2,21,1,0,0,1,6,11,0,16,2,11,1,18,6,56,30,2,22,1,0,0,24,18,10,0,16,2,10,1,9,18,5,56,31,4,12,11,0,1,8,12,2,5,16,11,0,11,1,17,23,12,2,11,2,2,23,1,0,0,1,7,11,0,16,2,11,1,8,18,5,56,31,2,24,1,0,0,1,8,11,0,46,56,3,11,1,16,4,20,33,2,25,1,0,0,1,12,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,15,2,2,26,1,0,0,1,14,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,2,11,0,15,5,21,2,27,1,0,0,1,3,11,0,16,2,2,28,1,0,0,1,12,10,0,16,5,20,4,5,5,9,11,0,1,7,7,39,11,0,15,2,2,29,1,0,0,1,4,11,0,16,0,20,2,30,1,0,0,1,4,11,0,16,1,20,2,31,1,0,0,1,4,11,0,16,3,56,24,2,32,1,0,0,1,12,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,11,0,15,3,2,33,1,0,0,1,27,10,0,56,3,11,1,16,4,20,33,4,8,5,12,11,0,1,7,0,39,10,0,10,2,17,19,4,17,5,21,11,0,1,7,11,39,11,0,16,2,11,2,18,4,56,32,2,34,1,0,0,58,40,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,19,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,22,32,4,30,5,34,11,0,1,7,9,39,11,0,15,2,11,2,18,4,56,33,2,35,1,0,0,58,45,10,0,11,1,17,24,4,5,5,9,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,19,4,17,5,21,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,22,32,4,30,5,34,11,0,1,7,9,39,10,0,15,2,10,2,18,4,56,8,11,0,46,56,3,11,2,18,3,2,36,1,0,0,58,32,11,2,19,3,12,3,12,4,10,0,46,56,3,11,4,33,4,11,5,15,11,0,1,7,5,39,14,1,56,12,10,3,33,4,21,5,25,11,0,1,7,10,39,11,0,15,2,11,3,18,4,11,1,56,27,2,37,1,0,0,1,4,11,0,16,4,20,2,38,1,0,0,1,4,11,0,55,0,20,2,39,1,0,0,1,4,11,0,55,1,20,2,40,1,0,0,1,4,11,0,55,2,20,2,0,2,0,3,0,0,0,1,1,1,0,4,2,1,2,2,2,3,6,10,7,10,8,10,0,51,0],"kiosk_extension":[161,28,235,11,6,0,0,0,12,1,0,14,2,14,36,3,50,162,1,4,212,1,26,5,238,1,142,1,7,252,2,164,3,8,160,6,32,6,192,6,76,10,140,7,15,11,155,7,2,12,157,7,143,4,13,172,11,6,0,26,0,9,0,17,0,25,0,30,0,37,0,38,0,1,4,0,0,2,7,1,0,1,1,0,12,0,3,3,12,0,3,4,12,0,4,7,4,0,5,5,12,1,0,1,6,6,2,0,0,8,0,1,1,2,0,15,2,1,1,2,0,18,2,1,1,2,0,34,2,1,1,2,0,35,3,4,1,2,0,36,5,6,1,2,0,32,7,1,2,2,12,0,27,7,1,2,2,12,0,24,8,9,1,2,0,23,8,9,1,2,0,13,8,9,1,2,0,12,8,9,1,2,0,20,8,10,1,2,0,21,11,12,1,2,1,14,16,1,0,1,29,15,16,0,2,8,18,1,2,7,4,2,10,24,25,2,7,4,2,11,19,26,2,7,4,2,19,24,9,1,7,2,34,19,20,2,7,4,3,22,2,9,0,3,28,21,1,1,12,3,33,21,1,1,12,3,39,8,22,0,3,40,2,13,0,3,41,11,13,0,16,17,8,14,13,14,20,17,12,14,10,14,11,14,23,20,22,20,19,23,9,14,17,17,18,17,5,9,0,7,8,3,6,8,4,4,7,8,7,0,2,7,8,3,6,8,4,2,9,0,6,8,3,1,6,8,2,2,9,0,7,8,3,1,7,8,2,4,9,0,7,8,3,9,1,6,11,6,1,9,1,1,6,8,3,1,1,1,6,8,0,1,7,8,3,1,7,8,0,1,7,8,5,1,9,0,1,7,8,7,1,8,2,2,11,1,1,9,0,8,0,3,7,8,5,9,0,9,1,2,7,8,5,9,0,1,9,1,2,7,8,3,9,0,1,6,8,5,1,11,1,1,9,0,2,6,8,5,9,0,1,6,9,1,1,7,9,1,3,66,97,103,9,69,120,116,101,110,115,105,111,110,12,69,120,116,101,110,115,105,111,110,75,101,121,5,75,105,111,115,107,13,75,105,111,115,107,79,119,110,101,114,67,97,112,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,3,98,97,103,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,97,110,95,108,111,99,107,9,99,97,110,95,112,108,97,99,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,7,100,105,115,97,98,108,101,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,6,101,110,97,98,108,101,7,101,120,105,115,116,115,95,9,101,120,116,101,110,115,105,111,110,13,101,120,116,101,110,115,105,111,110,95,109,117,116,10,104,97,115,95,97,99,99,101,115,115,10,105,115,95,101,110,97,98,108,101,100,12,105,115,95,105,110,115,116,97,108,108,101,100,5,107,105,111,115,107,15,107,105,111,115,107,95,101,120,116,101,110,115,105,111,110,4,108,111,99,107,13,108,111,99,107,95,105,110,116,101,114,110,97,108,3,110,101,119,6,111,98,106,101,99,116,11,112,101,114,109,105,115,115,105,111,110,115,5,112,108,97,99,101,14,112,108,97,99,101,95,105,110,116,101,114,110,97,108,6,114,101,109,111,118,101,7,115,116,111,114,97,103,101,11,115,116,111,114,97,103,101,95,109,117,116,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,3,117,105,100,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,16,117,105,100,95,109,117,116,95,105,110,116,101,114,110,97,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,4,16,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,16,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,35,8,2,31,4,23,1,1,2,1,16,1,1,14,0,1,0,0,1,25,10,1,10,2,17,21,4,5,5,13,11,1,1,11,4,1,11,2,1,7,0,39,11,1,11,2,17,25,9,57,0,11,4,17,15,11,3,8,18,0,56,0,2,1,1,0,0,1,24,10,0,11,1,17,21,4,5,5,9,11,0,1,7,0,39,10,0,46,56,1,4,14,5,18,11,0,1,7,3,39,9,11,0,56,2,15,0,21,2,2,1,0,0,1,24,10,0,11,1,17,21,4,5,5,9,11,0,1,7,0,39,10,0,46,56,1,4,14,5,18,11,0,1,7,3,39,8,11,0,56,2,15,0,21,2,3,1,0,0,1,33,10,0,10,1,17,21,4,5,5,11,11,0,1,11,1,1,7,0,39,10,0,46,56,1,4,16,5,22,11,0,1,11,1,1,7,3,39,11,0,11,1,17,25,9,57,0,56,3,19,0,1,1,17,14,2,4,1,0,0,1,12,10,1,56,1,4,4,5,8,11,1,1,7,3,39,11,1,56,4,16,1,2,5,1,0,0,1,13,10,1,46,56,1,4,5,5,9,11,1,1,7,3,39,11,1,56,2,15,1,2,6,1,0,0,9,31,10,1,46,56,1,4,5,5,9,11,1,1,7,3,39,10,1,46,56,5,4,16,8,12,4,5,20,10,1,46,56,6,12,4,11,4,4,23,5,27,11,1,1,7,2,39,11,1,11,2,56,7,2,7,1,0,0,1,22,10,1,46,56,1,4,5,5,9,11,1,1,7,3,39,10,1,46,56,6,4,14,5,18,11,1,1,7,2,39,11,1,11,2,56,8,2,8,1,0,0,1,6,11,0,17,24,9,57,0,56,9,2,9,1,0,0,1,5,11,0,56,4,16,0,20,2,10,1,0,0,9,19,10,0,56,10,4,13,11,0,56,4,16,2,20,7,4,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,12,1,5,17,11,0,1,9,12,1,11,1,2,11,1,0,0,9,19,10,0,56,10,4,13,11,0,56,4,16,2,20,7,5,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,12,1,5,17,11,0,1,9,12,1,11,1,2,12,0,0,0,1,6,11,0,17,24,9,57,0,56,11,2,13,0,0,0,1,6,11,0,17,26,9,57,0,56,12,2,0,2,0,0,0,1,0],"linked_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,30,3,40,212,1,4,252,1,28,5,152,2,188,1,7,212,3,205,2,8,161,6,64,6,225,6,20,10,245,6,38,11,155,7,4,12,159,7,151,5,13,182,12,14,14,196,12,14,0,24,1,29,0,14,0,28,0,40,0,0,12,2,7,0,4,1,0,1,4,2,7,0,4,0,1,2,7,1,0,0,3,4,4,0,4,3,2,0,0,25,0,1,2,7,4,0,17,2,3,2,7,4,0,6,2,3,2,7,4,0,34,4,5,2,7,4,0,33,4,5,2,7,4,0,7,6,7,2,7,4,0,8,8,9,2,7,4,0,32,6,3,2,7,4,0,26,6,3,2,7,4,0,35,8,10,2,7,4,0,31,11,12,2,7,4,0,30,11,12,2,7,4,0,9,6,13,2,7,4,0,23,2,14,2,7,4,0,20,2,13,2,7,4,0,11,1,5,2,7,4,0,13,1,5,2,7,6,1,7,3,25,1,0,1,12,17,16,1,0,1,16,19,5,1,0,1,21,3,13,1,0,1,22,3,13,1,0,1,27,5,17,1,0,1,37,16,17,1,0,1,38,19,17,1,0,2,5,22,5,2,7,4,2,7,23,7,2,7,4,2,8,21,9,2,7,4,2,15,23,13,2,7,4,2,35,21,10,2,7,4,3,10,15,5,0,3,25,0,15,0,22,16,24,16,20,16,19,16,21,16,18,16,23,16,27,20,25,20,26,20,29,20,17,16,9,12,28,20,1,7,8,4,1,11,0,2,9,0,9,1,1,6,11,0,2,9,0,9,1,1,6,11,2,1,9,0,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,7,11,0,2,9,0,9,1,2,9,0,9,1,1,1,1,3,1,8,3,1,9,0,1,11,2,1,9,0,5,11,2,1,9,0,11,2,1,9,0,11,2,1,9,0,9,0,11,2,1,9,0,2,7,11,2,1,9,0,9,0,2,9,0,11,1,2,9,0,9,1,2,7,8,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,3,11,2,1,9,0,11,2,1,9,0,9,1,1,6,9,0,2,8,3,3,11,76,105,110,107,101,100,84,97,98,108,101,4,78,111,100,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,4,98,97,99,107,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,4,102,105,108,108,5,102,114,111,110,116,4,104,101,97,100,2,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,6,108,101,110,103,116,104,12,108,105,110,107,101,100,95,116,97,98,108,101,3,110,101,119,4,110,101,120,116,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,111,112,95,98,97,99,107,9,112,111,112,95,102,114,111,110,116,4,112,114,101,118,9,112,117,115,104,95,98,97,99,107,10,112,117,115,104,95,102,114,111,110,116,6,114,101,109,111,118,101,4,115,105,122,101,4,115,111,109,101,12,115,119,97,112,95,111,114,95,102,105,108,108,4,116,97,105,108,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,19,8,3,36,3,18,11,2,1,9,0,39,11,2,1,9,0,1,2,3,32,11,2,1,9,0,26,11,2,1,9,0,41,9,1,0,12,1,12,0,1,0,0,5,7,11,0,17,31,6,0,0,0,0,0,0,0,0,56,0,56,0,57,0,2,1,1,0,0,5,3,11,0,55,0,2,2,1,0,0,5,3,11,0,55,1,2,3,1,0,0,18,54,10,0,54,0,10,1,56,1,12,5,10,0,55,1,56,2,4,13,10,0,54,1,10,1,56,3,56,0,12,7,14,5,56,4,4,33,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,3,21,11,6,56,6,12,3,5,35,56,0,12,3,11,3,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,4,1,0,0,18,54,10,0,55,0,56,2,4,8,10,0,54,0,10,1,56,3,10,0,54,1,10,1,56,1,12,5,14,5,56,4,4,31,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,5,21,11,6,56,6,12,3,5,33,56,0,12,3,11,3,12,7,56,0,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,5,1,0,0,5,6,11,0,55,2,11,1,56,9,55,6,2,6,1,0,0,5,6,11,0,54,2,11,1,56,7,54,6,2,7,1,0,0,5,6,11,0,55,2,11,1,56,9,55,3,2,8,1,0,0,5,6,11,0,55,2,11,1,56,9,55,5,2,9,1,0,0,24,65,10,0,54,2,10,1,56,10,58,1,12,4,12,2,12,3,10,0,55,4,20,6,1,0,0,0,0,0,0,0,23,10,0,54,4,21,14,3,56,4,4,28,10,2,10,0,54,2,14,3,56,11,20,56,7,54,5,21,14,2,56,4,4,40,10,3,10,0,54,2,14,2,56,11,20,56,7,54,3,21,10,0,55,0,56,11,14,1,33,4,50,11,2,10,0,54,0,21,10,0,55,1,56,11,14,1,33,4,61,11,3,11,0,54,1,21,5,63,11,0,1,11,4,2,10,1,0,0,16,19,10,0,55,0,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,0,56,11,20,12,1,10,1,11,0,11,1,56,12,2,11,1,0,0,16,19,10,0,55,1,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,1,56,11,20,12,1,10,1,11,0,11,1,56,12,2,12,1,0,0,5,5,11,0,55,2,11,1,56,13,2,13,1,0,0,5,4,11,0,55,4,20,2,14,1,0,0,5,6,11,0,55,4,20,6,0,0,0,0,0,0,0,0,33,2,15,1,0,0,26,16,11,0,58,0,1,1,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,11,5,13,7,0,39,11,1,17,30,2,16,1,0,0,5,7,11,0,58,0,1,1,1,17,30,2,0,2,0,3,0,0,1,0,0,1,1,1,1,2,0,12,1,12,2,12,3,12,4,12,5,12,6,12,0],"math":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,35,5,37,18,7,55,57,8,112,32,12,144,1,249,3,0,2,0,3,0,1,0,0,4,0,1,0,0,0,0,1,0,0,5,2,1,0,0,6,1,1,0,0,7,3,3,0,0,1,0,1,0,2,3,3,1,3,2,3,2,1,4,3,4,4,4,3,15,15,15,4,100,105,102,102,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,4,109,97,116,104,3,109,97,120,3,109,105,110,3,112,111,119,4,115,113,114,116,9,115,113,114,116,95,117,49,50,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,1,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,2,1,0,0,1,15,10,0,10,1,36,4,9,11,0,11,1,23,12,2,5,13,11,1,11,0,23,12,2,11,2,2,3,1,0,0,1,33,6,1,0,0,0,0,0,0,0,12,2,10,1,49,1,38,4,31,5,7,10,1,49,2,25,49,0,33,4,22,10,0,11,0,24,12,0,11,1,49,2,26,12,1,5,30,11,2,10,0,24,12,2,11,1,49,1,23,12,1,5,2,11,2,2,4,1,0,0,4,43,50,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,12,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,53,12,3,10,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,52,2,5,1,0,0,5,43,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,77,12,3,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,53,2,6,1,0,0,1,19,10,0,10,1,25,6,0,0,0,0,0,0,0,0,33,4,11,11,0,11,1,26,12,2,5,17,11,0,11,1,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,2,0],"object":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,126,4,146,1,6,5,152,1,35,7,187,1,250,2,8,181,4,64,6,245,4,112,10,229,5,11,12,240,5,130,2,13,242,7,4,15,246,7,8,0,24,1,4,0,3,0,30,0,0,7,0,0,2,4,0,3,1,2,0,0,21,0,1,0,0,20,0,2,0,0,19,1,3,0,0,18,2,3,0,0,27,4,5,0,0,8,6,5,0,0,31,7,0,0,0,34,7,3,0,0,33,7,1,0,0,32,7,2,0,0,22,8,5,0,0,9,5,6,0,0,15,9,3,1,8,0,5,9,0,1,8,0,17,9,1,1,8,0,16,9,2,1,8,0,6,9,7,1,8,0,23,2,5,0,0,10,2,6,0,0,25,2,6,0,1,28,9,1,1,0,2,14,1,2,0,3,13,8,2,0,3,26,4,2,0,20,2,16,10,20,3,1,6,8,0,1,10,2,1,5,1,8,0,1,6,8,2,1,8,1,0,1,6,8,1,1,7,8,2,1,6,9,0,1,9,0,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,100,100,114,101,115,115,3,98,99,115,9,98,111,114,114,111,119,95,105,100,10,98,111,114,114,111,119,95,117,105,100,5,98,121,116,101,115,5,99,108,111,99,107,6,100,101,108,101,116,101,11,100,101,108,101,116,101,95,105,109,112,108,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,2,105,100,10,105,100,95,97,100,100,114,101,115,115,8,105,100,95,98,121,116,101,115,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,102,114,111,109,95,98,121,116,101,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,11,105,100,95,116,111,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,6,111,98,106,101,99,116,14,114,101,99,111,114,100,95,110,101,119,95,117,105,100,6,115,101,110,100,101,114,16,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,12,117,105,100,95,116,111,95,98,121,116,101,115,12,117,105,100,95,116,111,95,105,110,110,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,7,5,1,2,1,15,8,0,0,1,0,0,6,4,11,0,16,0,56,0,2,1,1,0,0,6,4,11,0,16,0,20,2,2,1,0,0,6,4,11,0,17,21,17,3,2,3,1,0,0,6,3,11,0,18,0,2,4,0,0,0,6,12,11,0,17,23,7,3,33,4,6,5,8,7,2,39,7,0,18,0,18,1,2,5,3,0,0,6,4,7,1,18,0,18,1,2,6,1,0,0,6,3,11,0,16,1,2,7,1,0,0,6,4,11,0,16,1,20,2,8,1,0,0,6,5,11,0,16,1,16,0,56,0,2,9,1,0,0,6,5,11,0,16,1,16,0,20,2,10,1,0,0,6,5,11,0,17,22,18,0,18,1,2,11,1,0,0,6,5,11,0,19,1,19,0,17,18,2,12,1,0,0,6,5,11,0,56,1,16,1,20,2,13,1,0,0,6,4,11,0,56,1,16,1,2,14,1,0,0,6,5,11,0,56,1,16,1,56,2,2,15,1,0,0,6,6,11,0,56,1,16,1,16,0,20,2,16,0,2,0,17,3,0,0,6,6,10,0,17,19,11,0,18,0,18,1,2,18,0,2,0,19,0,2,0,0,0,1,0,0,8,0,11,0,12,0,29,0],"object_bag":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,22,3,32,124,4,156,1,14,5,170,1,88,7,130,2,231,1,8,233,3,64,6,169,4,10,10,179,4,8,12,187,4,245,1,13,176,6,4,0,20,1,21,0,12,0,19,0,24,0,1,12,0,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,18,0,1,0,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,22,6,8,2,7,12,0,8,4,9,1,7,0,9,4,9,2,7,12,0,17,10,11,0,0,16,10,9,0,0,11,1,3,0,0,25,4,12,1,7,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,13,16,9,1,7,2,14,16,9,2,7,12,2,15,16,12,1,7,2,22,17,8,2,7,12,3,10,13,3,0,3,18,0,13,0,11,14,12,14,13,14,17,14,14,18,15,14,16,18,1,7,8,4,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,9,79,98,106,101,99,116,66,97,103,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,10,111,98,106,101,99,116,95,98,97,103,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,15,8,3,23,3,0,1,0,0,3,5,11,0,17,19,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,19,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,18,2,10,1,0,0,3,5,11,0,16,0,11,1,56,6,2,0,0,0,1,0],"object_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,26,3,36,120,4,156,1,12,5,168,1,113,7,153,2,199,1,8,224,3,64,6,160,4,10,10,170,4,8,11,178,4,2,12,180,4,230,1,13,154,6,4,14,158,6,4,0,18,1,19,0,11,0,17,0,22,0,1,12,2,7,1,12,1,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,16,0,1,2,7,12,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,20,6,8,2,7,12,0,8,4,9,2,7,12,0,15,10,11,2,7,12,0,14,10,9,2,7,12,0,10,1,3,2,7,12,0,23,4,12,2,7,12,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,12,16,9,1,7,2,13,16,12,1,7,2,20,17,8,2,7,12,3,9,13,3,0,3,16,0,13,0,10,14,11,14,12,14,15,14,13,18,14,18,1,7,8,4,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,13,8,3,21,3,0,14,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,19,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,9,1,0,0,3,5,11,0,55,0,11,1,56,5,2,0,0,0,1,0,14,1,14,0],"package":[161,28,235,11,6,0,0,0,11,1,0,14,2,14,36,3,50,183,1,4,233,1,10,5,243,1,118,7,233,2,144,5,8,249,7,64,6,185,8,93,10,150,9,48,12,198,9,129,4,13,199,13,20,0,36,1,10,1,50,0,33,0,48,0,49,0,51,0,1,12,0,0,6,12,0,0,8,0,0,0,7,0,0,1,2,7,0,2,4,7,0,3,0,7,0,3,5,4,0,5,3,2,0,0,14,0,1,1,2,0,15,0,2,1,2,0,12,1,2,0,0,22,3,4,1,0,0,21,3,4,1,0,0,39,3,5,0,0,40,3,5,0,0,52,6,7,0,0,54,6,8,0,0,53,6,9,0,0,46,10,7,0,0,47,10,9,0,0,41,11,7,0,0,42,11,7,0,0,45,10,12,0,0,17,2,9,0,0,9,2,9,0,0,19,2,9,0,0,34,13,2,0,0,35,13,2,0,0,30,14,2,0,0,11,15,16,0,0,16,17,2,0,0,43,18,2,0,2,23,24,25,0,2,24,24,25,0,2,25,2,19,1,0,3,18,23,2,0,3,26,21,7,1,8,3,27,27,7,0,3,28,31,27,0,3,32,22,23,0,4,38,28,2,1,12,5,44,26,27,0,6,29,21,4,1,2,34,20,26,20,0,20,32,1,28,14,2,9,0,7,8,8,1,8,0,0,1,6,8,0,1,1,1,6,8,4,1,6,8,1,1,8,6,1,3,1,2,1,6,8,2,1,6,8,3,1,6,10,2,1,7,8,1,1,8,1,3,7,8,1,2,10,2,1,8,2,2,7,8,1,8,3,2,7,8,1,2,1,8,5,1,9,0,1,6,9,0,1,7,8,8,1,8,7,1,6,8,5,1,8,4,1,6,8,8,1,5,2,9,0,5,2,1,8,5,2,8,6,8,6,1,6,8,6,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,15,97,100,100,105,116,105,118,101,95,112,111,108,105,99,121,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,14,98,117,114,110,95,112,117,98,108,105,115,104,101,114,3,99,97,112,5,99,108,97,105,109,14,99,108,97,105,109,95,97,110,100,95,107,101,101,112,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,17,99,111,109,112,97,116,105,98,108,101,95,112,111,108,105,99,121,6,100,101,108,101,116,101,15,100,101,112,95,111,110,108,121,95,112,111,108,105,99,121,6,100,105,103,101,115,116,11,102,114,111,109,95,109,111,100,117,108,101,12,102,114,111,109,95,112,97,99,107,97,103,101,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,14,109,97,107,101,95,105,109,109,117,116,97,98,108,101,11,109,111,100,117,108,101,95,110,97,109,101,3,110,101,119,6,111,98,106,101,99,116,22,111,110,108,121,95,97,100,100,105,116,105,118,101,95,117,112,103,114,97,100,101,115,17,111,110,108,121,95,100,101,112,95,117,112,103,114,97,100,101,115,7,112,97,99,107,97,103,101,6,112,111,108,105,99,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,16,112,117,98,108,105,115,104,101,100,95,109,111,100,117,108,101,17,112,117,98,108,105,115,104,101,100,95,112,97,99,107,97,103,101,11,114,101,99,101,105,112,116,95,99,97,112,15,114,101,99,101,105,112,116,95,112,97,99,107,97,103,101,8,114,101,115,116,114,105,99,116,6,115,101,110,100,101,114,13,116,105,99,107,101,116,95,100,105,103,101,115,116,14,116,105,99,107,101,116,95,112,97,99,107,97,103,101,13,116,105,99,107,101,116,95,112,111,108,105,99,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,5,116,121,112,101,115,15,117,112,103,114,97,100,101,95,112,97,99,107,97,103,101,14,117,112,103,114,97,100,101,95,112,111,108,105,99,121,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,2,1,0,2,1,128,2,1,192,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,26,8,7,36,8,4,31,8,4,1,2,4,26,8,7,36,8,6,54,3,37,2,2,2,4,13,8,6,36,8,6,37,2,20,10,2,3,2,2,13,8,6,36,8,6,0,1,0,0,19,18,14,0,56,0,4,4,5,8,11,1,1,7,0,39,56,1,12,2,11,1,17,31,14,2,17,24,14,2,17,25,18,0,2,1,1,0,0,2,8,11,0,10,1,56,2,11,1,46,17,33,56,3,2,2,1,0,0,2,6,11,0,19,0,1,1,17,27,2,3,1,0,0,19,9,56,1,12,1,14,1,17,24,11,0,16,0,20,33,2,4,1,0,0,29,23,56,1,12,2,14,2,17,24,10,0,16,0,20,33,4,17,14,2,17,25,11,0,16,1,20,33,12,1,5,21,11,0,1,9,12,1,11,1,2,5,1,0,0,2,3,11,0,16,1,2,6,1,0,0,2,3,11,0,16,0,2,7,1,0,0,2,4,11,0,16,2,20,2,8,1,0,0,2,4,11,0,16,3,20,2,9,1,0,0,2,4,11,0,16,4,20,2,10,1,0,0,2,4,11,0,16,5,20,2,11,1,0,0,2,4,11,0,16,6,20,2,12,1,0,0,2,4,11,0,16,7,20,2,13,1,0,0,2,4,11,0,16,8,20,2,14,1,0,0,2,3,11,0,16,9,2,15,1,0,0,2,2,7,5,2,16,1,0,0,2,2,7,6,2,17,1,0,0,2,2,7,7,2,18,1,4,0,2,4,11,0,7,6,17,23,2,19,1,4,0,2,4,11,0,7,7,17,23,2,20,1,4,0,2,7,11,0,19,1,1,1,1,17,27,2,21,1,0,0,30,41,7,8,17,29,12,3,10,0,16,2,20,10,3,34,4,10,5,14,11,0,1,7,2,39,10,1,10,0,16,4,20,38,4,21,5,25,11,0,1,7,1,39,10,0,16,2,20,12,4,11,3,10,0,15,2,21,11,0,46,56,4,11,4,11,1,11,2,18,2,2,22,1,0,0,30,39,11,1,19,3,12,3,12,2,10,0,46,56,4,11,2,33,4,11,5,15,11,0,1,7,4,39,10,0,16,2,17,30,7,8,33,4,22,5,26,11,0,1,7,3,39,11,3,10,0,15,2,21,10,0,16,3,20,6,1,0,0,0,0,0,0,0,22,11,0,15,3,21,2,23,0,0,0,2,16,10,0,16,4,20,10,1,37,4,7,5,11,11,0,1,7,1,39,11,1,11,0,15,4,21,2,0,1,0,2,1,1,1,2,1,3,2,1,2,2,3,0,3,1,2,3,0],"pay":[161,28,235,11,6,0,0,0,9,1,0,8,2,8,10,3,18,77,4,95,14,5,109,126,7,235,1,173,1,8,152,3,32,6,184,3,10,12,194,3,214,2,0,9,0,2,0,15,0,16,1,0,12,1,0,1,3,1,2,0,0,8,0,1,1,0,0,12,2,1,1,0,0,14,3,1,1,0,0,13,4,1,1,0,0,3,2,1,1,0,0,5,5,1,1,0,0,6,6,1,1,0,0,7,7,1,1,0,1,4,2,16,1,0,1,5,5,1,1,0,1,12,2,10,1,0,2,10,11,1,1,12,3,11,8,9,0,11,10,10,12,0,12,1,12,8,12,9,12,6,12,2,11,0,1,9,0,6,8,1,0,3,7,11,0,1,9,0,3,7,8,1,3,7,11,0,1,9,0,10,3,7,8,1,4,7,11,0,1,9,0,3,5,7,8,1,2,7,11,0,1,9,0,11,0,1,9,0,2,7,11,0,1,9,0,10,11,0,1,9,0,2,10,11,0,1,9,0,5,1,6,8,1,1,5,1,11,0,1,9,0,2,9,0,5,1,9,0,2,3,3,1,3,3,3,3,10,11,0,1,9,0,1,10,11,0,1,9,0,3,11,0,1,9,0,3,3,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,15,100,105,118,105,100,101,95,97,110,100,95,107,101,101,112,13,100,105,118,105,100,101,95,105,110,116,111,95,110,4,106,111,105,110,8,106,111,105,110,95,118,101,99,21,106,111,105,110,95,118,101,99,95,97,110,100,95,116,114,97,110,115,102,101,114,4,107,101,101,112,3,112,97,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,18,115,112,108,105,116,95,97,110,100,95,116,114,97,110,115,102,101,114,9,115,112,108,105,116,95,118,101,99,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,5,11,0,11,1,17,12,56,0,2,1,1,4,0,1,8,11,0,11,1,10,2,56,1,11,2,46,56,2,2,2,1,4,0,13,27,6,0,0,0,0,0,0,0,0,14,1,65,14,12,4,12,3,10,3,10,4,35,4,22,5,10,10,0,14,1,10,3,66,14,20,10,2,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,2,1,2,3,1,4,0,1,7,11,0,11,1,11,3,56,1,11,2,56,0,2,4,1,4,0,15,31,11,0,11,1,10,2,56,4,12,5,6,0,0,0,0,0,0,0,0,14,5,65,10,12,4,12,3,10,3,10,4,35,4,26,5,15,13,5,69,10,10,2,46,17,12,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,10,11,2,1,11,5,70,10,0,0,0,0,0,0,0,0,2,5,1,4,0,1,4,11,0,11,1,56,5,2,6,1,4,0,17,26,6,0,0,0,0,0,0,0,0,14,1,65,10,12,4,12,3,10,3,10,4,35,4,21,5,10,13,1,69,10,12,2,10,0,11,2,56,5,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,7,1,4,0,10,18,14,0,65,10,6,0,0,0,0,0,0,0,0,36,4,6,5,8,7,0,39,13,0,69,10,12,2,13,2,11,0,56,6,11,2,11,1,56,0,2,0],"priority_queue":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,12,3,16,60,4,76,10,5,86,167,1,7,253,1,184,1,8,181,3,64,6,245,3,14,10,131,4,18,11,149,4,4,12,153,4,243,5,13,140,10,4,14,144,10,4,0,11,1,16,0,1,6,1,2,0,0,0,6,1,2,0,0,6,0,1,1,2,0,8,2,3,1,2,0,4,4,5,1,2,0,7,3,6,1,2,0,2,7,0,1,2,0,13,8,5,1,2,0,5,9,5,1,2,0,9,10,11,1,2,1,12,15,13,1,0,1,14,15,13,1,0,6,13,9,6,5,13,8,16,8,13,1,10,11,1,1,9,0,1,11,0,1,9,0,1,7,11,0,1,9,0,2,3,9,0,3,7,11,0,1,9,0,3,9,0,0,1,11,1,1,9,0,2,10,3,10,9,0,2,7,10,11,1,1,9,0,3,3,7,10,11,1,1,9,0,3,3,1,6,11,0,1,9,0,1,10,3,2,3,3,1,9,0,3,3,3,9,0,2,7,10,9,0,3,1,3,5,3,3,3,10,11,1,1,9,0,9,0,5,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,13,7,10,11,1,1,9,0,1,3,7,10,11,1,1,9,0,3,1,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,3,3,2,3,10,3,5,69,110,116,114,121,13,80,114,105,111,114,105,116,121,81,117,101,117,101,14,99,114,101,97,116,101,95,101,110,116,114,105,101,115,7,101,110,116,114,105,101,115,6,105,110,115,101,114,116,21,109,97,120,95,104,101,97,112,105,102,121,95,114,101,99,117,114,115,105,118,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,7,112,111,112,95,109,97,120,10,112,114,105,111,114,105,116,105,101,115,8,112,114,105,111,114,105,116,121,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,6,114,101,109,111,118,101,22,114,101,115,116,111,114,101,95,104,101,97,112,95,114,101,99,117,114,115,105,118,101,11,115,119,97,112,95,114,101,109,111,118,101,5,118,97,108,117,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,10,3,1,0,0,2,1,3,10,11,1,1,9,0,1,2,2,10,3,15,9,0,0,13,1,13,0,1,0,0,12,24,14,0,65,6,12,2,10,2,6,2,0,0,0,0,0,0,0,26,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,21,5,12,11,1,6,1,0,0,0,0,0,0,0,23,12,1,13,0,10,2,10,1,56,0,5,7,11,0,57,0,2,1,1,0,0,14,30,10,0,55,0,65,6,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,10,0,54,0,6,0,0,0,0,0,0,0,0,56,1,58,1,12,3,12,2,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,6,0,0,0,0,0,0,0,0,56,0,11,2,11,3,2,2,1,0,0,16,17,10,0,54,0,11,1,11,2,57,1,68,6,10,0,55,0,65,6,6,1,0,0,0,0,0,0,0,23,12,3,11,0,54,0,11,3,56,2,2,3,1,0,0,5,4,11,0,11,1,57,1,2,4,1,0,0,17,40,14,0,65,16,12,3,14,1,65,13,10,3,33,4,9,5,11,6,0,0,0,0,0,0,0,0,39,64,6,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,38,5,20,13,0,6,0,0,0,0,0,0,0,0,56,3,12,4,13,1,6,0,0,0,0,0,0,0,0,56,4,12,6,13,5,11,4,11,6,57,1,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,5,2,5,0,0,0,18,46,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,1,6,1,0,0,0,0,0,0,0,23,6,2,0,0,0,0,0,0,0,26,12,6,10,0,10,1,12,3,12,2,10,0,10,6,12,5,12,4,11,2,46,11,3,66,6,55,1,20,11,4,46,11,5,66,6,55,1,20,36,4,43,10,0,11,1,10,6,71,6,11,0,11,6,56,2,5,45,11,0,1,2,6,0,0,0,19,110,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,2,10,1,35,4,12,5,16,11,0,1,6,1,0,0,0,0,0,0,0,39,10,2,6,2,0,0,0,0,0,0,0,24,6,1,0,0,0,0,0,0,0,22,12,13,10,13,6,1,0,0,0,0,0,0,0,22,12,15,10,2,12,14,10,13,10,1,35,4,55,10,0,10,13,12,5,12,3,10,0,10,14,12,7,12,6,11,3,46,11,5,66,6,55,1,20,11,6,46,11,7,66,6,55,1,20,36,12,8,5,57,9,12,8,11,8,4,61,11,13,12,14,10,15,10,1,35,4,88,10,0,10,15,12,10,12,9,10,0,10,14,12,12,12,11,11,9,46,11,10,66,6,55,1,20,11,11,46,11,12,66,6,55,1,20,36,12,4,5,90,9,12,4,11,4,4,94,11,15,12,14,10,14,10,2,34,4,107,10,0,10,14,11,2,71,6,11,0,11,1,11,14,56,0,5,109,11,0,1,2,7,1,0,0,20,28,7,1,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,0,55,0,65,6,35,4,24,5,11,13,2,10,0,55,0,10,1,66,6,55,1,20,68,16,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,4,11,0,1,11,2,2,0,0,1,0,0,13,1,13,0],"prover":[161,28,235,11,6,0,0,0,4,1,0,2,7,2,7,8,9,32,6,41,30,0,0,6,112,114,111,118,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0],"sui":[161,28,235,11,6,0,0,0,10,1,0,14,2,14,48,3,62,62,4,124,14,5,138,1,133,1,7,143,2,129,2,8,144,4,64,6,208,4,102,10,182,5,5,12,187,5,109,0,22,1,18,0,9,0,10,0,23,0,25,0,26,0,4,2,0,1,3,7,1,0,0,2,0,4,1,0,1,2,5,4,1,0,1,3,1,12,1,0,1,3,2,12,1,0,1,3,6,12,1,0,1,5,7,2,0,6,8,7,0,0,16,0,1,0,0,23,2,3,0,1,17,3,9,1,0,2,12,16,7,1,0,2,15,17,18,1,0,3,11,11,12,1,2,3,24,15,16,1,0,4,19,14,3,1,12,4,20,20,3,1,12,5,14,5,7,0,5,21,5,6,0,2,8,5,10,7,13,6,10,4,10,3,10,8,19,1,7,8,7,1,11,2,1,8,0,2,11,4,1,8,0,5,0,4,11,5,1,8,0,11,3,1,8,0,11,2,1,8,0,11,6,1,8,0,1,6,8,7,1,5,1,3,1,8,8,1,11,1,1,9,0,1,8,0,7,9,0,2,10,2,10,2,10,2,11,1,1,8,8,7,8,7,2,11,6,1,9,0,11,5,1,9,0,1,11,5,1,8,0,1,9,0,1,11,6,1,9,0,1,11,3,1,9,0,2,7,11,3,1,9,0,3,1,11,2,1,9,0,1,11,4,1,8,0,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,114,108,7,98,97,108,97,110,99,101,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,11,100,117,109,109,121,95,102,105,101,108,100,5,101,112,111,99,104,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,3,115,117,105,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,228,11,84,2,0,0,0,3,8,0,0,232,137,4,35,199,138,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,2,4,3,83,85,73,10,2,4,3,83,117,105,10,2,1,0,0,2,1,13,1,0,0,0,0,4,47,10,0,46,17,10,7,5,33,4,7,5,11,11,0,1,7,1,39,10,0,46,17,9,6,0,0,0,0,0,0,0,0,33,4,18,5,22,11,0,1,7,0,39,9,18,0,49,9,7,6,7,7,7,8,56,0,11,0,56,1,12,1,12,4,11,1,56,2,11,4,56,3,12,2,13,2,7,4,56,4,12,3,11,2,56,5,1,11,3,2,1,1,4,0,3,4,11,0,11,1,56,6,2,0],"table":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,16,3,24,115,4,139,1,10,5,149,1,104,7,253,1,167,1,8,164,3,32,6,196,3,10,10,206,3,8,11,214,3,2,12,216,3,229,1,13,189,5,4,14,193,5,4,0,19,0,10,0,16,0,20,0,0,12,2,7,1,4,1,2,2,4,0,3,1,2,0,0,15,0,1,2,7,4,0,3,2,3,2,7,4,0,4,4,5,2,7,4,0,5,6,7,2,7,4,0,17,6,8,2,7,4,0,6,4,9,2,7,4,0,14,10,11,2,7,4,0,13,10,9,2,7,4,0,8,1,3,2,7,4,0,9,1,3,2,7,6,1,3,14,3,2,7,4,1,4,15,5,2,7,4,1,5,16,7,2,7,4,1,11,15,9,2,7,4,1,17,16,8,2,7,4,2,7,12,3,0,2,15,0,12,0,10,13,11,13,12,13,14,13,13,13,1,7,8,2,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,2,8,1,3,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,1,18,3,0,13,0,1,0,0,3,5,11,0,17,16,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,17,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,15,2,9,1,0,0,3,5,11,0,58,0,1,17,15,2,0,0,0,1,0,13,1,13,0],"table_vec":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,18,3,24,116,4,140,1,22,5,162,1,138,1,7,172,2,164,1,8,208,3,32,6,240,3,20,10,132,4,10,11,142,4,2,12,144,4,130,2,13,146,6,2,14,148,6,2,0,18,0,17,0,19,0,1,4,1,4,1,1,0,12,2,7,1,4,1,2,2,2,0,0,9,0,1,1,4,0,16,2,1,1,4,0,11,3,4,1,4,0,10,3,5,1,4,0,4,6,7,1,4,0,14,8,9,1,4,0,5,10,11,1,4,0,13,12,13,1,4,0,7,1,9,1,4,0,8,1,9,1,6,1,3,19,9,2,7,4,1,4,17,18,2,7,4,1,5,20,21,2,7,4,1,7,15,9,2,7,4,1,8,15,9,2,7,6,1,11,16,4,2,7,4,1,12,0,15,2,7,4,1,15,20,22,2,7,4,16,14,0,13,5,13,15,14,2,13,11,14,10,14,12,14,17,14,13,14,14,14,1,7,8,2,1,11,0,1,9,0,2,9,0,7,8,2,1,6,11,0,1,9,0,1,3,1,1,2,6,11,0,1,9,0,3,1,6,9,0,2,7,11,0,1,9,0,9,0,0,2,7,11,0,1,9,0,3,1,7,9,0,1,7,11,0,1,9,0,1,9,0,2,3,9,0,1,11,1,2,9,0,9,1,1,6,11,1,2,9,0,9,1,2,6,11,1,2,9,0,9,1,9,0,1,6,9,1,3,7,11,1,2,9,0,9,1,9,0,9,1,2,7,11,1,2,9,0,9,1,9,0,1,7,9,1,1,9,1,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,5,101,109,112,116,121,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,6,11,1,2,3,9,0,0,13,0,1,0,0,9,4,11,0,56,0,57,0,2,1,1,0,0,1,8,11,1,56,1,12,2,13,2,11,0,56,2,11,2,2,2,1,0,0,9,4,11,0,55,0,56,3,2,3,1,0,0,9,5,11,0,56,4,6,0,0,0,0,0,0,0,0,33,2,4,1,0,0,9,15,10,0,56,4,10,1,36,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,5,2,5,1,0,0,4,10,10,0,46,56,4,12,2,11,0,54,0,11,2,11,1,56,6,2,6,1,0,0,9,16,10,0,46,56,4,10,1,36,4,7,5,11,11,0,1,7,0,39,11,0,54,0,11,1,56,7,2,7,1,0,0,4,20,10,0,46,56,4,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,56,8,2,8,1,0,0,9,12,14,0,56,4,6,0,0,0,0,0,0,0,0,33,4,6,5,8,7,1,39,11,0,58,0,56,9,2,9,1,0,0,9,4,11,0,58,0,56,10,2,0,0,0,13,0],"transfer":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,54,4,56,6,5,62,8,7,70,144,1,8,214,1,32,6,246,1,10,12,128,2,82,0,7,0,7,0,1,1,8,0,4,0,1,1,12,0,0,2,1,1,8,0,2,2,1,1,12,0,5,2,1,1,8,0,3,2,1,1,12,0,1,2,1,1,8,0,6,2,1,1,8,0,8,0,1,1,8,8,2,6,2,7,2,2,9,0,5,0,1,9,0,13,102,114,101,101,122,101,95,111,98,106,101,99,116,18,102,114,101,101,122,101,95,111,98,106,101,99,116,95,105,109,112,108,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,17,115,104,97,114,101,95,111,98,106,101,99,116,95,105,109,112,108,8,116,114,97,110,115,102,101,114,13,116,114,97,110,115,102,101,114,95,105,109,112,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,56,0,2,1,1,0,0,1,4,11,0,11,1,56,0,2,2,1,0,0,1,3,11,0,56,1,2,3,1,0,0,1,3,11,0,56,1,2,4,1,0,0,1,3,11,0,56,2,2,5,1,0,0,1,3,11,0,56,2,2,6,3,2,0,7,3,2,0,8,3,2,0,0],"transfer_policy":[161,28,235,11,6,0,0,0,13,1,0,26,2,26,78,3,104,150,2,4,254,2,50,5,176,3,192,3,7,240,6,138,5,8,250,11,64,6,186,12,60,10,246,12,55,11,173,13,10,12,183,13,150,5,13,205,18,16,14,221,18,16,0,63,1,48,1,65,0,19,0,21,0,29,0,32,0,47,0,49,0,60,0,62,0,64,0,70,0,10,0,1,0,1,0,7,12,1,0,1,0,8,12,1,0,1,0,9,3,1,0,1,0,5,7,1,2,1,1,3,7,1,0,0,2,12,7,0,3,0,4,1,0,1,4,1,12,1,0,1,7,2,7,0,7,13,4,0,8,4,12,0,9,6,2,0,11,11,2,0,12,14,7,1,3,0,0,46,0,1,1,0,0,45,2,3,1,0,0,24,2,4,1,0,0,71,5,6,1,0,0,26,7,6,1,0,0,22,8,0,1,0,0,17,9,4,3,0,2,6,0,38,10,11,3,0,2,6,0,18,12,4,2,0,2,0,16,13,4,2,0,2,0,39,14,15,2,0,2,0,55,16,4,3,0,2,6,0,66,14,17,1,0,0,67,16,18,1,0,0,56,14,19,1,0,0,44,20,21,1,0,0,50,20,22,1,0,0,34,20,21,1,0,1,27,41,25,1,0,1,43,40,15,1,0,2,37,4,23,1,0,3,69,42,22,1,0,3,72,4,32,1,0,4,35,46,44,1,0,4,52,58,4,1,0,4,61,43,44,1,0,5,15,54,4,2,7,4,5,20,56,57,2,7,4,5,33,56,15,1,7,5,54,61,52,2,7,4,6,30,25,4,1,3,7,25,29,4,0,7,40,39,21,1,8,7,45,28,29,0,7,68,17,21,0,8,36,27,15,1,0,10,58,25,4,1,8,10,62,37,4,1,8,11,57,35,36,0,12,23,50,15,1,3,12,31,4,24,1,3,12,41,55,4,1,3,12,42,24,48,1,3,12,54,62,4,1,3,12,59,49,22,1,3,40,23,35,25,30,30,22,31,1,25,36,34,37,33,32,34,19,22,18,22,21,31,25,31,23,31,42,23,44,23,39,23,10,51,26,53,20,52,41,23,27,53,24,31,28,59,29,53,43,23,3,8,9,3,8,9,1,11,0,1,9,0,2,6,8,11,7,8,13,2,11,1,1,9,0,11,2,1,9,0,0,4,7,11,1,1,9,0,6,11,2,1,9,0,11,5,1,3,7,8,13,1,11,8,1,8,12,3,11,1,1,9,0,11,2,1,9,0,7,8,13,2,6,11,1,1,9,0,11,0,1,9,0,4,9,1,7,11,1,1,9,0,6,11,2,1,9,0,9,2,2,9,1,6,11,1,1,9,0,1,6,9,2,3,9,1,7,11,1,1,9,0,11,8,1,8,12,2,9,1,7,11,0,1,9,0,1,6,11,1,1,9,0,1,1,2,7,11,1,1,9,0,6,11,2,1,9,0,1,6,8,10,1,7,8,10,1,6,11,14,1,8,6,1,6,11,0,1,9,0,1,8,9,1,3,1,8,6,1,11,14,1,9,0,1,9,0,5,8,10,11,14,1,8,6,11,7,1,8,12,8,10,8,9,1,6,8,11,1,7,8,13,1,8,10,1,11,3,1,9,0,1,8,12,1,11,7,1,9,0,1,11,2,1,9,0,1,11,1,1,9,0,1,6,8,13,1,5,2,9,0,5,3,3,3,3,1,6,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,1,6,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,13,1,11,8,1,9,0,2,11,7,1,8,12,8,10,2,11,7,1,9,0,7,8,13,7,10,8,6,8,9,8,9,3,11,14,1,8,6,8,6,3,1,10,9,0,1,6,11,14,1,9,0,2,6,11,14,1,9,0,6,9,0,2,9,0,9,1,1,9,1,2,11,4,1,9,1,9,2,3,7,8,10,9,0,9,1,2,7,11,14,1,9,0,9,0,2,6,8,10,9,0,1,6,9,1,2,7,11,7,1,9,0,11,8,1,9,0,1,11,4,1,9,1,2,8,6,7,11,14,1,8,6,2,7,8,10,9,0,2,7,11,14,1,9,0,6,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,9,80,117,98,108,105,115,104,101,114,7,82,117,108,101,75,101,121,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,17,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,97,112,21,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,114,101,97,116,101,100,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,86,101,99,83,101,116,3,97,100,100,11,97,100,100,95,114,101,99,101,105,112,116,8,97,100,100,95,114,117,108,101,14,97,100,100,95,116,111,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,4,99,111,105,110,15,99,111,110,102,105,114,109,95,114,101,113,117,101,115,116,8,99,111,110,116,97,105,110,115,7,100,101,102,97,117,108,116,6,100,101,108,101,116,101,20,100,101,115,116,114,111,121,95,97,110,100,95,119,105,116,104,100,114,97,119,12,100,101,115,116,114,111,121,95,115,111,109,101,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,7,101,120,105,115,116,115,95,4,102,114,111,109,12,102,114,111,109,95,98,97,108,97,110,99,101,12,102,114,111,109,95,112,97,99,107,97,103,101,3,103,101,116,8,103,101,116,95,114,117,108,101,8,104,97,115,95,114,117,108,101,2,105,100,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,7,105,115,95,115,111,109,101,4,105,116,101,109,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,4,112,97,105,100,9,112,111,108,105,99,121,95,105,100,3,112,117,116,8,114,101,99,101,105,112,116,115,6,114,101,109,111,118,101,11,114,101,109,111,118,101,95,114,117,108,101,5,114,117,108,101,115,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,105,122,101,3,115,117,105,4,116,97,107,101,8,116,114,97,110,115,102,101,114,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,3,117,105,100,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,7,118,101,99,95,115,101,116,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,4,44,8,9,50,3,34,8,9,53,11,14,1,8,6,1,2,3,40,8,10,19,11,7,1,8,12,56,11,14,1,8,6,2,2,2,40,8,10,51,8,9,3,2,1,40,8,9,4,2,1,28,1,0,25,3,25,1,25,2,25,4,52,0,1,0,0,4,6,11,0,11,1,11,2,56,0,57,0,2,1,1,0,0,26,32,11,0,56,1,4,4,5,8,11,1,1,6,0,0,0,0,0,0,0,0,39,10,1,17,33,12,5,14,5,17,34,12,6,10,6,57,1,56,2,11,5,12,2,56,0,12,3,56,3,12,4,11,2,11,4,11,3,57,2,11,1,17,33,11,6,57,3,2,2,0,4,0,33,11,11,0,10,1,56,4,12,2,56,5,11,2,11,1,46,17,38,56,6,2,3,1,0,0,38,49,10,0,46,56,7,11,1,55,0,20,33,4,9,5,15,11,0,1,11,3,1,7,4,39,14,2,56,8,4,37,11,2,56,9,12,6,10,6,10,0,55,1,56,10,37,4,28,5,34,11,0,1,11,3,1,7,5,39,11,6,12,4,5,41,10,0,55,1,56,10,12,4,11,4,12,5,11,0,54,1,11,5,11,3,56,11,2,4,1,0,0,45,27,14,0,56,7,14,1,55,0,20,33,4,8,5,12,11,2,1,7,4,39,11,1,58,3,1,12,4,11,0,58,2,1,12,3,17,31,11,4,17,31,11,3,11,2,56,12,2,5,1,0,0,47,52,11,1,58,0,12,6,12,3,12,5,12,4,11,6,56,13,12,2,14,2,65,23,12,8,10,8,10,0,55,2,56,14,33,4,19,5,23,11,0,1,7,0,39,10,8,6,0,0,0,0,0,0,0,0,36,4,46,5,28,13,2,69,23,12,7,10,0,55,2,14,7,56,15,4,37,5,41,11,0,1,7,1,39,11,8,6,1,0,0,0,0,0,0,0,23,12,8,5,23,11,0,1,11,4,11,5,11,3,2,6,1,0,0,4,34,10,1,46,56,7,11,2,55,0,20,33,4,9,5,13,11,1,1,7,4,39,10,1,46,56,16,32,4,19,5,23,11,1,1,7,3,39,10,1,54,3,9,57,4,11,3,56,17,11,1,54,2,56,18,56,19,2,7,1,0,0,4,6,11,1,55,3,9,57,4,56,20,2,8,1,0,0,4,14,10,1,46,56,16,4,5,5,9,11,1,1,7,2,39,11,1,54,1,11,2,56,21,2,9,1,0,0,4,5,11,1,54,4,56,18,56,19,2,10,1,0,0,4,6,11,0,55,3,9,57,4,56,22,2,11,1,0,0,60,28,10,0,46,56,7,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,10,0,54,3,9,57,4,56,23,1,11,0,54,2,12,3,56,18,12,2,11,3,14,2,56,24,2,12,1,0,0,4,3,11,0,55,3,2,13,1,0,0,4,16,10,0,46,56,7,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,11,0,54,3,2,14,1,0,0,4,3,11,0,55,2,2,15,1,0,0,4,4,11,0,55,5,20,2,16,1,0,0,4,4,11,0,55,6,20,2,17,1,0,0,4,4,11,0,55,7,20,2,2,1,1,1,1,2,1,0,0,3,0,0,0,1,0,2,0,25,1,25,2,25,3,25,4,25,5,25,6,25,7,25,0],"tx_context":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,24,7,65,111,8,176,1,32,6,208,1,20,10,228,1,14,12,242,1,107,13,221,2,10,0,8,0,0,2,0,0,7,0,1,0,0,2,0,2,0,0,3,0,3,0,0,4,0,3,0,0,5,4,1,0,0,6,0,3,0,0,1,5,1,0,1,6,8,0,1,5,1,6,10,2,1,3,1,7,8,0,2,10,2,3,0,2,5,3,9,84,120,67,111,110,116,101,120,116,9,100,101,114,105,118,101,95,105,100,6,100,105,103,101,115,116,5,101,112,111,99,104,18,101,112,111,99,104,95,116,105,109,101,115,116,97,109,112,95,109,115,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,11,105,100,115,95,99,114,101,97,116,101,100,6,115,101,110,100,101,114,10,116,120,95,99,111,110,116,101,120,116,7,116,120,95,104,97,115,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,32,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,5,7,5,9,10,2,3,3,4,3,6,3,0,1,0,0,6,4,11,0,16,0,20,2,1,1,0,0,6,3,11,0,16,1,2,2,1,0,0,6,4,11,0,16,2,20,2,3,1,0,0,6,4,11,0,16,3,20,2,4,1,0,0,7,18,10,0,16,4,20,12,2,10,0,16,1,20,10,2,17,6,12,1,11,2,6,1,0,0,0,0,0,0,0,22,11,0,15,4,21,11,1,2,5,0,0,0,6,4,11,0,16,4,20,2,6,0,2,0,0,0,0,1,0,2,0,3,0,4,0],"types":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,6,7,14,26,8,40,32,12,72,4,0,1,0,0,0,1,1,2,1,6,9,0,1,1,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,5,116,121,112,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"url":[161,28,235,11,6,0,0,0,9,1,0,4,2,4,8,3,12,25,5,37,20,7,57,78,8,135,1,64,10,199,1,6,12,205,1,50,13,255,1,2,0,8,1,2,0,1,7,0,1,0,7,0,0,4,0,1,0,0,5,2,1,0,0,3,3,0,0,0,7,4,5,0,1,6,2,0,0,1,8,1,1,8,0,1,10,2,1,6,8,0,2,7,8,0,8,1,0,6,83,116,114,105,110,103,3,85,114,108,5,97,115,99,105,105,9,105,110,110,101,114,95,117,114,108,10,110,101,119,95,117,110,115,97,102,101,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,6,115,116,114,105,110,103,6,117,112,100,97,116,101,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,8,8,1,0,1,0,0,5,3,11,0,18,0,2,1,1,0,0,5,4,11,0,17,4,18,0,2,2,1,0,0,5,4,11,0,16,0,20,2,3,1,0,0,5,5,11,1,11,0,15,0,21,2,0,0,0],"vec_map":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,22,3,28,168,1,4,196,1,28,5,224,1,254,1,7,222,3,153,2,8,247,5,64,6,183,6,50,10,233,6,21,11,254,6,4,12,130,7,235,5,13,237,12,6,14,243,12,6,0,30,1,21,1,31,0,2,7,2,1,0,0,0,0,0,7,2,1,0,0,0,1,1,7,1,0,0,0,7,0,1,2,1,0,0,14,2,0,2,1,0,0,23,3,4,2,1,0,0,22,5,4,2,1,0,0,13,3,6,2,1,0,0,8,7,8,2,1,0,0,28,7,9,2,1,1,0,3,7,10,2,1,0,0,26,11,12,2,1,0,0,16,11,10,2,1,0,0,5,1,0,2,1,0,0,15,1,13,2,1,0,0,19,11,14,2,1,0,0,12,7,15,2,1,0,0,11,7,12,2,1,0,0,9,16,17,2,1,0,0,10,18,19,2,1,0,0,24,18,4,2,1,0,1,6,27,24,1,0,1,17,28,10,1,0,1,20,0,27,1,0,1,27,24,27,1,0,2,16,25,10,1,0,2,23,23,24,1,0,2,25,31,0,1,0,7,4,14,4,23,20,22,20,5,4,21,26,20,26,13,4,19,12,8,4,24,20,21,12,20,12,18,12,0,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,2,7,11,0,2,9,0,9,1,6,9,0,2,9,0,9,1,1,7,11,0,2,9,0,9,1,1,7,9,1,2,6,11,0,2,9,0,9,1,6,9,0,1,6,9,1,1,11,2,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,2,10,9,0,10,9,1,1,10,9,0,1,11,2,1,3,2,6,11,0,2,9,0,9,1,3,2,6,9,0,6,9,1,2,7,11,0,2,9,0,9,1,3,2,6,9,0,7,9,1,1,11,1,2,9,0,9,1,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,9,0,1,6,10,9,0,1,9,1,1,11,2,1,9,0,1,6,11,2,1,9,0,1,10,11,1,2,9,0,9,1,7,10,11,1,2,9,0,9,1,3,9,0,10,9,0,3,9,1,10,9,1,1,7,10,9,0,4,6,11,1,2,9,0,9,1,3,10,9,0,3,2,3,3,1,6,11,1,2,9,0,9,1,1,7,11,1,2,9,0,9,1,5,69,110,116,114,121,6,79,112,116,105,111,110,6,86,101,99,77,97,112,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,3,103,101,116,16,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,20,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,95,109,117,116,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,7,103,101,116,95,109,117,116,6,105,110,115,101,114,116,16,105,110,116,111,95,107,101,121,115,95,118,97,108,117,101,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,3,107,101,121,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,3,112,111,112,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,101,110,116,114,121,95,98,121,95,105,100,120,7,114,101,118,101,114,115,101,4,115,105,122,101,4,115,111,109,101,7,116,114,121,95,103,101,116,5,118,97,108,117,101,7,118,101,99,95,109,97,112,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,1,4,10,11,1,2,9,0,9,1,1,2,2,18,9,0,29,9,1,0,4,1,4,0,1,0,0,0,3,64,20,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,21,20,10,0,14,1,12,3,46,11,3,56,0,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,11,2,57,1,68,20,2,2,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,56,2,58,1,2,3,1,0,0,0,15,10,0,55,0,56,3,32,4,6,5,10,11,0,1,7,4,39,11,0,54,0,69,20,58,1,2,4,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,67,20,54,1,2,5,1,0,0,12,10,10,0,11,1,56,1,12,2,11,0,55,0,11,2,66,20,55,1,2,6,1,0,0,9,19,10,0,10,1,56,0,4,11,11,0,11,1,56,4,20,56,5,12,2,5,17,11,0,1,11,1,1,56,6,12,2,11,2,2,7,1,0,0,15,7,11,0,11,1,56,7,12,2,14,2,56,8,2,8,1,0,0,0,4,11,0,55,0,65,20,2,9,1,0,0,0,5,11,0,56,9,6,0,0,0,0,0,0,0,0,33,2,10,1,0,0,29,12,11,0,58,0,12,1,14,1,56,3,4,7,5,9,7,2,39,11,1,70,20,0,0,0,0,0,0,0,0,2,11,1,0,0,30,40,11,0,58,0,12,1,13,1,56,10,6,0,0,0,0,0,0,0,0,12,2,14,1,65,20,12,5,64,24,0,0,0,0,0,0,0,0,12,4,64,26,0,0,0,0,0,0,0,0,12,7,10,2,10,5,35,4,35,5,19,13,1,69,20,58,1,12,6,12,3,13,4,11,3,68,24,13,7,11,6,68,26,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,14,11,1,70,20,0,0,0,0,0,0,0,0,11,4,11,7,2,12,1,0,0,32,32,6,0,0,0,0,0,0,0,0,12,2,10,0,55,0,65,20,12,4,64,24,0,0,0,0,0,0,0,0,12,3,10,2,10,4,35,4,28,5,13,10,0,55,0,10,2,66,20,12,1,13,3,11,1,55,2,20,68,24,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,8,11,0,1,11,3,2,13,1,0,0,33,36,6,0,0,0,0,0,0,0,0,12,2,10,0,56,9,12,3,10,2,10,3,35,4,30,5,10,10,0,55,0,10,2,66,20,55,2,10,1,33,4,25,11,0,1,11,1,1,11,2,56,11,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,12,2,14,1,0,0,15,13,11,0,11,1,56,7,12,2,14,2,56,8,4,8,5,10,7,1,39,11,2,56,13,2,15,1,0,0,34,20,10,1,10,0,56,9,35,4,6,5,10,11,0,1,7,3,39,11,0,55,0,11,1,66,20,12,2,10,2,55,2,11,2,55,1,2,16,1,0,0,35,21,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,67,20,12,2,10,2,55,2,11,2,54,1,2,17,1,0,0,0,17,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,56,2,58,1,2,0,0,1,1,1,0,0,4,1,4,2,4,0],"vec_set":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,12,3,18,102,4,120,20,5,140,1,95,7,235,1,164,1,8,143,3,64,6,207,3,20,10,227,3,7,11,234,3,2,12,236,3,156,2,13,136,6,2,14,138,6,2,0,19,1,14,1,20,0,1,7,1,3,0,1,0,7,1,0,0,0,5,0,1,1,3,0,16,2,1,1,3,0,8,3,0,1,3,0,15,4,0,1,3,0,2,5,6,1,3,0,17,7,8,1,3,0,10,7,6,1,3,0,9,1,9,1,3,0,12,7,10,1,3,0,7,5,11,1,3,0,6,5,8,1,3,1,4,17,2,1,0,1,11,15,6,1,0,1,13,0,17,1,0,1,18,2,17,1,0,2,15,14,2,1,0,2,16,2,9,1,0,16,2,4,2,10,2,15,2,9,2,12,8,5,2,14,8,13,8,11,8,0,1,11,0,1,9,0,1,9,0,2,7,11,0,1,9,0,9,0,2,7,11,0,1,9,0,6,9,0,2,6,11,0,1,9,0,6,9,0,1,1,1,6,11,0,1,9,0,1,3,1,10,9,0,1,6,10,9,0,1,11,1,1,3,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,6,11,1,1,9,0,2,3,3,1,11,1,1,9,0,6,79,112,116,105,111,110,6,86,101,99,83,101,116,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,4,115,105,122,101,4,115,111,109,101,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,3,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,12,18,10,0,14,1,12,2,46,11,2,56,1,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,68,2,2,3,1,0,0,13,13,10,0,11,1,12,2,46,11,2,56,2,12,3,11,0,54,0,11,3,56,3,1,2,4,1,0,0,11,7,11,0,11,1,56,4,12,2,14,2,56,5,2,5,1,0,0,0,4,11,0,55,0,65,2,2,6,1,0,0,0,5,11,0,56,6,6,0,0,0,0,0,0,0,0,33,2,7,1,0,0,0,3,11,0,58,0,2,8,1,0,0,0,3,11,0,55,0,2,9,0,0,0,16,35,6,0,0,0,0,0,0,0,0,12,2,10,0,56,6,12,3,10,2,10,3,35,4,29,5,10,10,0,55,0,10,2,66,2,10,1,33,4,24,11,0,1,11,1,1,11,2,56,7,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,8,2,10,0,0,0,11,13,11,0,11,1,56,4,12,2,14,2,56,5,4,8,5,10,7,1,39,11,2,56,9,2,0,0,0,2,0],"versioned":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,20,3,28,85,4,113,10,5,123,97,7,220,1,236,1,8,200,3,32,6,232,3,10,10,242,3,16,12,130,4,197,1,13,199,5,4,0,23,0,11,0,16,0,20,0,4,12,0,0,3,0,0,2,0,7,0,2,2,4,0,3,1,2,0,0,8,0,1,1,4,0,22,2,3,0,0,13,2,4,1,4,0,14,5,6,1,4,0,19,5,7,1,4,0,21,8,9,1,4,0,10,1,10,1,4,1,5,14,9,2,7,4,1,6,15,16,2,7,4,1,7,17,18,2,7,4,1,18,17,19,2,7,4,2,9,12,9,0,2,12,4,20,1,8,2,15,11,12,0,7,13,8,13,9,13,10,13,12,1,3,3,9,0,7,8,4,1,8,0,1,6,8,0,1,3,1,6,9,0,1,7,8,0,1,7,9,0,2,9,0,8,1,4,7,8,0,3,9,0,8,1,0,1,9,0,1,7,8,4,1,8,3,2,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,8,2,3,8,3,9,0,3,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,16,86,101,114,115,105,111,110,67,104,97,110,103,101,67,97,112,9,86,101,114,115,105,111,110,101,100,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,2,105,100,10,108,111,97,100,95,118,97,108,117,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,3,110,101,119,6,111,98,106,101,99,116,11,111,108,100,95,118,101,114,115,105,111,110,6,114,101,109,111,118,101,24,114,101,109,111,118,101,95,118,97,108,117,101,95,102,111,114,95,117,112,103,114,97,100,101,10,116,120,95,99,111,110,116,101,120,116,7,117,112,103,114,97,100,101,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,12,118,101,114,115,105,111,110,101,100,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,3,22,3,1,2,2,24,8,2,17,3,0,1,0,0,1,12,11,2,17,13,10,0,18,0,12,3,13,3,15,0,11,0,11,1,56,0,11,3,2,1,1,0,0,9,4,11,0,16,1,20,2,2,1,0,0,9,7,10,0,16,0,11,0,16,1,20,56,1,2,3,1,0,0,9,7,10,0,15,0,11,0,16,1,20,56,2,2,4,1,0,0,9,14,10,0,15,0,10,0,16,1,20,56,3,10,0,46,56,4,11,0,16,1,20,18,1,2,5,1,0,0,3,32,11,3,19,1,12,4,10,0,46,56,4,33,4,9,5,13,11,0,1,7,0,39,11,4,10,1,35,4,18,5,22,11,0,1,7,0,39,10,0,15,0,10,1,11,2,56,0,11,1,11,0,15,1,21,2,6,1,0,0,21,12,11,0,19,0,12,3,12,1,13,1,11,3,56,3,12,2,11,1,17,11,11,2,2,0,0,0,1,0]},"type_origin_table":[{"module_name":"tx_context","struct_name":"TxContext","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"ID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"UID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_field","struct_name":"Field","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bag","struct_name":"Bag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Supply","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Balance","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bcs","struct_name":"BCS","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Referent","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"clock","struct_name":"Clock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"url","struct_name":"Url","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"Coin","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CoinMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"TreasuryCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CurrencyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"VecMap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"Publisher","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeTicket","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeReceipt","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"Display","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"DisplayCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"VersionUpdated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_object_field","struct_name":"Wrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"Curve","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PreparedVerifyingKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PublicProofInputs","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"ProofPoints","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_set","struct_name":"VecSet","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"sui","struct_name":"SUI","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferRequest","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicy","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"RuleKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Kiosk","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"KioskOwnerCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"PurchaseCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Item","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Listing","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Lock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemListed","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemPurchased","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemDelisted","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk_extension","struct_name":"Extension","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk_extension","struct_name":"ExtensionKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"LinkedTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"Node","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_bag","struct_name":"ObjectBag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_table","struct_name":"ObjectTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"PriorityQueue","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table","struct_name":"Table","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table_vec","struct_name":"TableVec","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"Versioned","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"VersionChangeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"ACKQVv64dXCmpxE1QPU2QMLxVpmtbzrFGMtWYY6szJrQ","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000003","version":7,"module_map":{"genesis":[161,28,235,11,6,0,0,0,11,1,0,26,2,26,58,3,84,107,4,191,1,14,5,205,1,176,2,7,253,3,137,9,8,134,13,96,6,230,13,20,10,250,13,93,12,215,14,219,3,13,178,18,24,0,31,1,44,1,72,2,18,2,20,2,43,2,61,2,66,0,54,0,63,0,64,0,67,0,70,0,3,3,0,0,2,3,0,0,9,0,0,0,8,0,0,1,4,7,1,0,0,3,0,4,1,0,1,4,1,12,1,0,1,5,11,4,0,6,5,2,0,7,10,2,0,8,6,4,0,10,7,4,0,11,12,4,0,0,22,0,1,0,0,15,2,1,0,0,14,3,1,0,1,25,25,26,1,0,1,36,24,14,1,0,2,35,22,14,1,0,3,26,9,1,1,0,3,53,8,9,1,0,3,75,1,9,1,0,4,29,30,31,1,0,6,65,32,1,0,7,27,5,6,0,8,22,17,18,0,9,22,19,1,0,10,23,15,16,0,11,13,34,1,0,11,42,12,10,0,11,52,29,1,0,12,32,27,28,0,12,34,13,14,0,7,7,8,7,5,21,4,23,3,23,9,7,6,7,6,8,7,11,5,1,8,8,8,1,10,8,0,8,2,7,8,9,0,4,11,5,1,8,8,10,8,3,7,10,8,12,7,8,9,1,7,10,8,12,25,10,8,3,3,3,10,2,3,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,8,10,3,11,5,1,8,8,11,5,1,8,8,5,8,11,8,12,10,8,12,10,2,10,2,1,6,8,9,1,3,1,8,8,2,7,11,5,1,9,0,3,1,11,5,1,9,0,1,8,12,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,9,2,6,10,8,12,6,8,12,1,1,8,3,3,3,3,3,3,3,7,8,9,1,8,11,5,11,5,1,8,8,3,3,13,7,8,9,1,8,10,8,8,7,10,8,12,11,5,1,8,8,3,3,8,11,8,10,7,8,9,5,11,5,1,8,8,3,5,11,4,1,5,5,1,8,3,1,6,10,9,0,1,5,1,6,11,4,1,9,0,1,11,4,1,9,0,1,9,0,2,7,10,8,12,5,1,7,8,12,4,7,8,12,11,5,1,8,8,5,7,8,9,2,11,5,1,9,0,7,8,9,1,11,6,1,9,0,2,11,6,1,8,8,5,2,3,3,2,7,8,12,3,7,66,97,108,97,110,99,101,4,67,111,105,110,22,71,101,110,101,115,105,115,67,104,97,105,110,80,97,114,97,109,101,116,101,114,115,24,71,101,110,101,115,105,115,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,15,84,111,107,101,110,65,108,108,111,99,97,116,105,111,110,25,84,111,107,101,110,68,105,115,116,114,105,98,117,116,105,111,110,83,99,104,101,100,117,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,9,86,97,108,105,100,97,116,111,114,8,97,99,116,105,118,97,116,101,19,97,99,116,105,118,97,116,101,95,118,97,108,105,100,97,116,111,114,115,15,97,108,108,111,99,97,116,101,95,116,111,107,101,110,115,11,97,108,108,111,99,97,116,105,111,110,115,11,97,109,111,117,110,116,95,109,105,115,116,7,98,97,108,97,110,99,101,24,99,104,97,105,110,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,4,99,111,105,110,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,12,102,114,111,109,95,98,97,108,97,110,99,101,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,9,105,109,97,103,101,95,117,114,108,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,4,110,97,109,101,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,18,110,101,116,119,111,114,107,95,112,117,98,108,105,99,95,107,101,121,3,110,101,119,6,111,98,106,101,99,116,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,19,112,114,111,116,111,99,111,108,95,112,117,98,108,105,99,95,107,101,121,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,17,114,101,99,105,112,105,101,110,116,95,97,100,100,114,101,115,115,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,23,115,116,97,107,101,95,115,117,98,115,105,100,121,95,102,117,110,100,95,109,105,115,116,41,115,116,97,107,101,95,115,117,98,115,105,100,121,95,105,110,105,116,105,97,108,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,21,115,116,97,107,101,100,95,119,105,116,104,95,118,97,108,105,100,97,116,111,114,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,118,97,108,105,100,97,116,111,114,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,13,118,97,108,105,100,97,116,111,114,95,115,101,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,6,118,101,99,116,111,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,17,119,111,114,107,101,114,95,112,117,98,108,105,99,95,107,101,121,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,15,39,10,2,24,10,2,33,10,2,47,10,2,62,5,30,3,21,3,49,10,2,48,10,2,41,10,2,74,10,2,40,10,2,45,10,2,46,10,2,73,10,2,1,2,12,50,3,19,3,28,3,59,3,57,3,58,3,55,13,37,3,38,3,69,3,71,3,68,3,2,2,2,56,3,16,10,8,3,3,2,3,51,5,17,3,60,11,4,1,5,0,0,0,0,4,147,1,10,5,46,17,11,6,0,0,0,0,0,0,0,0,33,4,7,5,11,11,5,1,7,0,39,11,4,19,2,12,6,12,22,13,1,11,22,56,0,12,24,56,1,12,23,64,10,0,0,0,0,0,0,0,0,12,28,14,3,65,11,12,8,6,0,0,0,0,0,0,0,0,12,11,10,11,10,8,35,4,89,5,33,14,3,10,11,66,11,20,19,0,12,29,12,17,12,16,12,14,12,30,12,15,12,19,12,20,12,7,12,10,12,25,12,18,12,12,12,9,12,13,11,25,11,20,11,15,11,30,11,19,11,13,11,9,11,12,11,18,11,14,11,16,11,17,11,29,11,10,11,7,10,5,17,16,12,27,14,28,14,27,17,19,32,4,77,5,81,11,5,1,7,1,39,13,28,11,27,68,10,11,11,6,1,0,0,0,0,0,0,0,22,12,11,5,28,11,1,11,6,13,28,10,5,17,1,13,28,17,2,14,2,16,0,20,14,2,16,1,20,14,2,16,2,20,14,2,16,3,20,14,2,16,4,20,14,2,16,5,20,14,2,16,6,20,10,5,17,14,12,26,11,24,14,2,16,7,20,14,2,16,8,20,14,2,16,9,20,10,5,17,12,12,21,11,0,11,28,11,23,14,2,16,10,20,14,2,16,11,20,11,26,11,21,11,5,17,13,2,1,0,0,0,20,44,14,1,56,2,32,4,35,5,5,13,1,69,21,19,3,12,7,12,5,12,6,13,0,11,5,56,0,12,4,14,7,56,3,4,29,11,7,56,4,12,8,10,2,11,8,17,18,11,4,11,6,10,3,17,17,5,34,11,4,10,3,56,5,11,6,17,10,5,0,11,2,1,11,3,1,11,1,70,21,0,0,0,0,0,0,0,0,11,0,56,6,2,2,0,0,0,33,24,10,0,46,65,10,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,1,35,4,21,5,11,10,0,10,2,67,10,6,0,0,0,0,0,0,0,0,17,15,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,2,1,2,1,3,1,7,1,8,1,9,1,10,1,11,1,4,1,5,1,6,1,0,1,1,0],"stake_subsidy":[161,28,235,11,6,0,0,0,12,1,0,12,2,12,22,3,34,37,4,71,4,5,75,74,7,149,1,176,2,8,197,3,64,6,133,4,28,10,161,4,20,12,181,4,180,1,13,233,5,10,15,243,5,4,0,18,1,6,1,7,1,14,1,21,1,23,0,3,4,0,1,0,12,0,2,1,4,1,0,1,4,2,2,0,5,4,2,0,0,8,0,1,0,0,5,2,3,0,0,10,4,5,0,1,16,7,8,0,2,17,13,14,1,0,2,24,11,5,1,0,3,15,12,5,0,5,10,4,10,5,11,2,1,8,3,3,3,13,7,8,4,1,8,0,1,7,8,0,1,11,2,1,8,3,1,6,8,0,1,3,0,1,7,8,4,1,8,1,3,4,11,2,1,8,3,3,1,8,3,1,6,11,2,1,9,0,2,3,3,2,7,11,2,1,9,0,3,1,11,2,1,9,0,3,66,97,103,7,66,97,108,97,110,99,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,84,120,67,111,110,116,101,120,116,13,97,100,118,97,110,99,101,95,101,112,111,99,104,3,98,97,103,7,98,97,108,97,110,99,101,6,99,114,101,97,116,101,27,99,117,114,114,101,110,116,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,28,99,117,114,114,101,110,116,95,101,112,111,99,104,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,20,100,105,115,116,114,105,98,117,116,105,111,110,95,99,111,117,110,116,101,114,12,101,120,116,114,97,95,102,105,101,108,100,115,7,103,101,110,101,115,105,115,4,109,97,116,104,3,109,105,110,3,110,101,119,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,6,7,11,2,1,8,3,11,3,9,3,20,3,19,13,12,8,1,0,3,0,0,6,19,10,3,7,0,75,37,4,6,5,10,11,4,1,7,1,39,11,0,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,11,4,17,3,18,0,2,1,3,0,0,9,57,10,0,16,0,20,10,0,16,1,56,0,17,6,12,3,10,0,15,1,11,3,56,1,12,2,10,0,16,2,20,6,1,0,0,0,0,0,0,0,22,10,0,15,2,21,10,0,16,2,20,10,0,16,3,20,25,6,0,0,0,0,0,0,0,0,33,4,53,10,0,16,0,20,53,10,0,16,4,20,53,24,7,0,26,12,1,10,0,16,0,20,11,1,52,23,11,0,15,0,21,5,55,11,0,1,11,2,2,2,1,0,0,6,8,10,0,16,0,20,11,0,16,1,56,0,17,6,2,0,2,0,0,0,1,0,3,0,4,0,13,0,22,0],"staking_pool":[161,28,235,11,6,0,0,0,12,1,0,20,2,20,52,3,72,173,2,4,245,2,34,5,151,3,205,2,7,228,5,200,8,8,172,14,96,6,140,15,200,1,10,212,16,66,12,150,17,145,11,13,167,28,28,15,195,28,4,0,68,1,45,2,14,2,15,2,40,2,44,2,69,2,72,2,73,2,74,0,7,12,0,0,4,7,0,0,6,12,0,1,3,7,1,0,0,2,0,12,0,3,1,4,1,0,1,5,2,7,0,5,10,4,0,6,5,2,0,7,8,12,2,7,1,4,1,9,9,2,0,0,42,0,1,0,0,59,2,3,0,0,60,4,5,0,0,79,6,7,0,0,75,3,5,0,0,22,8,9,0,0,58,10,9,0,0,57,11,9,0,0,56,11,9,0,0,80,12,5,0,0,11,13,9,0,0,19,13,9,0,0,71,14,15,0,0,51,16,17,0,0,67,16,15,0,0,66,16,15,0,0,35,14,18,0,0,33,14,18,0,0,64,19,3,0,0,65,19,9,0,0,39,20,9,0,0,32,21,18,0,0,54,22,23,0,0,48,14,15,0,0,49,14,15,0,0,24,14,24,0,0,70,25,15,0,0,52,25,15,0,0,36,22,18,0,0,27,26,15,0,0,28,26,15,0,0,31,9,23,0,0,17,22,9,0,1,16,48,37,1,0,1,26,46,9,1,0,1,29,52,47,1,3,1,34,48,18,1,0,1,37,48,18,1,0,1,43,9,31,1,0,1,63,47,31,1,0,2,42,0,34,0,3,38,40,15,1,0,3,64,45,33,1,0,3,78,36,15,1,0,3,81,9,33,1,0,4,41,42,15,0,5,21,30,9,0,5,30,37,17,1,8,5,42,0,30,0,7,13,43,9,2,7,4,7,16,53,54,2,7,4,7,18,53,18,2,7,4,7,42,0,29,2,7,4,8,73,50,9,1,8,9,23,39,15,0,9,62,39,49,0,52,28,38,15,44,32,43,32,47,1,41,32,49,28,42,32,34,15,39,15,36,15,37,15,53,3,35,15,33,15,51,28,50,28,1,7,8,10,1,8,0,4,7,8,0,11,5,1,8,8,3,7,8,10,1,8,2,3,7,8,0,8,2,7,8,10,1,11,5,1,8,8,2,7,8,0,8,2,2,3,11,5,1,8,8,2,7,8,0,11,5,1,8,8,0,2,7,8,0,7,8,10,1,7,8,0,4,7,8,0,3,3,3,2,7,8,0,3,1,6,8,0,1,3,1,6,8,2,1,8,6,1,1,3,7,8,2,3,7,8,10,2,7,8,2,8,2,2,6,8,2,6,8,2,2,6,8,0,3,1,8,1,1,6,11,9,2,3,8,1,1,6,8,1,2,6,8,1,3,1,11,9,2,3,8,1,2,3,8,1,1,11,9,2,9,0,9,1,1,8,7,1,11,3,1,9,0,1,8,8,1,11,5,1,9,0,1,8,4,2,8,2,3,1,6,11,5,1,9,0,1,6,9,0,5,3,11,5,1,8,8,3,11,5,1,8,8,3,1,6,8,10,2,7,11,5,1,9,0,11,5,1,9,0,3,3,8,1,11,5,1,8,8,2,3,3,3,7,11,9,2,9,0,9,1,9,0,9,1,5,3,3,8,1,3,3,2,7,11,5,1,9,0,3,2,7,11,3,1,9,0,9,0,1,9,0,1,6,11,3,1,9,0,1,5,2,9,0,5,2,6,8,2,11,5,1,8,8,2,6,11,3,1,9,0,9,0,2,6,11,9,2,9,0,9,1,9,0,1,6,9,1,3,3,8,1,3,3,66,97,103,7,66,97,108,97,110,99,101,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,16,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,3,97,100,100,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,24,99,104,101,99,107,95,98,97,108,97,110,99,101,95,105,110,118,97,114,105,97,110,116,115,8,99,111,110,116,97,105,110,115,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,18,100,101,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,6,100,101,108,101,116,101,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,5,101,112,111,99,104,14,101,120,99,104,97,110,103,101,95,114,97,116,101,115,12,101,120,116,114,97,95,102,105,101,108,100,115,4,102,105,108,108,14,103,101,116,95,115,117,105,95,97,109,111,117,110,116,16,103,101,116,95,116,111,107,101,110,95,97,109,111,117,110,116,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,2,105,100,21,105,110,105,116,105,97,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,25,105,115,95,101,113,117,97,108,95,115,116,97,107,105,110,103,95,109,101,116,97,100,97,116,97,11,105,115,95,105,110,97,99,116,105,118,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,21,105,115,95,112,114,101,97,99,116,105,118,101,95,97,116,95,101,112,111,99,104,7,105,115,95,115,111,109,101,4,106,111,105,110,15,106,111,105,110,95,115,116,97,107,101,100,95,115,117,105,4,109,97,116,104,3,109,105,110,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,27,112,101,110,100,105,110,103,95,112,111,111,108,95,116,111,107,101,110,95,119,105,116,104,100,114,97,119,13,112,101,110,100,105,110,103,95,115,116,97,107,101,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,26,112,101,110,100,105,110,103,95,116,111,116,97,108,95,115,117,105,95,119,105,116,104,100,114,97,119,7,112,111,111,108,95,105,100,17,112,111,111,108,95,116,111,107,101,110,95,97,109,111,117,110,116,18,112,111,111,108,95,116,111,107,101,110,95,98,97,108,97,110,99,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,9,112,114,105,110,99,105,112,97,108,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,30,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,12,114,101,119,97,114,100,115,95,112,111,111,108,6,115,101,110,100,101,114,4,115,111,109,101,5,115,112,108,105,116,16,115,112,108,105,116,95,115,116,97,107,101,100,95,115,117,105,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,97,109,111,117,110,116,11,115,117,105,95,98,97,108,97,110,99,101,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,17,117,110,119,114,97,112,95,115,116,97,107,101,100,95,115,117,105,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,5,118,97,108,117,101,23,119,105,116,104,100,114,97,119,95,102,114,111,109,95,112,114,105,110,99,105,112,97,108,16,119,105,116,104,100,114,97,119,95,114,101,119,97,114,100,115,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,0,2,11,30,8,7,12,11,3,1,3,20,11,3,1,3,71,3,61,11,5,1,8,8,53,3,24,11,9,2,3,8,1,47,3,50,3,46,3,25,8,4,1,2,2,70,3,52,3,2,2,4,30,8,7,51,8,6,66,3,55,11,5,1,8,8,0,3,0,0,27,18,10,0,56,0,12,1,10,0,17,48,56,1,56,1,6,0,0,0,0,0,0,0,0,56,2,6,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,0,17,40,18,0,2,1,3,0,0,35,45,14,1,56,3,12,5,10,0,46,17,17,32,4,9,5,15,11,0,1,11,3,1,7,11,39,10,5,6,0,0,0,0,0,0,0,0,36,4,20,5,26,11,0,1,11,3,1,7,18,39,11,3,17,48,10,0,46,56,4,11,2,11,1,18,2,12,4,10,0,16,0,20,11,5,22,11,0,15,0,21,11,4,2,2,3,0,0,38,52,10,0,11,1,17,3,12,4,12,3,14,4,56,3,12,5,10,0,10,5,10,3,11,2,46,17,54,17,9,12,6,11,5,14,6,56,3,22,12,7,10,0,16,1,20,11,7,22,10,0,15,1,21,10,0,16,2,20,11,3,22,10,0,15,2,21,10,0,46,17,17,4,44,11,0,17,7,5,46,11,0,1,13,4,11,6,56,5,1,11,4,2,3,3,0,0,41,31,14,1,16,3,20,10,0,46,56,4,33,4,9,5,13,11,0,1,7,2,39,11,0,14,1,16,4,20,12,2,46,11,2,17,22,12,3,11,1,17,4,12,4,14,3,14,4,56,3,17,30,11,4,2,4,0,0,0,5,8,11,0,19,2,12,1,1,1,17,46,11,1,2,5,3,0,0,9,15,10,0,16,5,20,14,1,56,3,22,10,0,15,5,21,11,0,15,6,11,1,56,5,1,2,6,3,0,0,42,28,11,1,46,17,54,6,1,0,0,0,0,0,0,0,22,12,3,10,0,17,7,10,0,17,8,10,0,15,7,10,3,10,0,16,5,20,10,0,16,8,20,18,1,56,6,11,0,11,3,12,2,46,11,2,17,32,2,7,0,0,0,9,29,10,0,16,5,20,10,0,16,1,20,23,10,0,15,5,21,10,0,16,8,20,10,0,16,2,20,23,10,0,15,8,21,6,0,0,0,0,0,0,0,0,10,0,15,1,21,6,0,0,0,0,0,0,0,0,11,0,15,2,21,2,8,3,0,0,23,31,10,0,16,5,20,10,0,16,8,20,18,1,12,1,10,0,16,5,20,10,0,16,0,20,22,10,0,15,5,21,14,1,10,0,16,5,20,17,30,10,0,15,8,21,6,0,0,0,0,0,0,0,0,11,0,15,0,21,2,9,0,0,0,44,33,10,0,11,3,12,4,46,11,4,17,22,12,6,14,6,11,2,17,29,12,8,10,8,10,1,38,4,20,11,8,11,1,23,12,5,5,22,6,0,0,0,0,0,0,0,0,12,5,11,5,10,0,16,6,56,3,17,45,12,7,11,0,15,6,11,7,56,7,2,10,3,0,0,9,29,10,0,15,7,10,1,17,31,56,6,10,0,46,17,16,4,10,5,14,11,0,1,7,15,39,10,0,46,17,17,32,4,20,5,24,11,0,1,7,17,39,11,0,15,9,11,1,56,8,2,11,3,0,0,9,16,10,0,46,17,17,32,4,6,5,10,11,0,1,7,12,39,11,1,56,9,11,0,15,10,21,2,12,1,0,0,9,4,11,0,16,5,20,2,13,1,0,0,9,4,11,0,16,3,20,2,14,1,0,0,9,4,11,0,16,11,56,3,2,15,1,0,0,9,4,11,0,16,4,20,2,16,1,0,0,9,4,11,0,16,9,56,10,2,17,1,0,0,9,4,11,0,16,10,56,11,2,18,1,0,0,15,53,10,0,16,11,56,3,12,3,10,1,10,3,37,4,9,5,15,11,0,1,11,2,1,7,4,39,11,3,10,1,23,7,0,38,4,22,5,28,11,0,1,11,2,1,7,19,39,10,1,7,0,38,4,33,5,39,11,0,1,11,2,1,7,19,39,11,2,17,48,10,0,16,3,20,10,0,16,4,20,11,0,15,11,11,1,56,7,18,2,2,19,1,4,0,9,9,11,0,11,1,10,2,17,18,11,2,46,17,55,56,12,2,20,1,4,0,51,24,10,0,14,1,12,2,46,11,2,17,21,4,8,5,12,11,0,1,7,13,39,11,1,19,2,12,3,1,1,17,46,11,0,15,11,11,3,56,5,1,2,21,1,0,0,18,25,10,0,16,3,20,10,1,16,3,20,33,4,17,11,0,16,4,20,11,1,16,4,20,33,12,2,5,23,11,0,1,11,1,1,9,12,2,11,2,2,22,1,0,0,42,45,10,0,10,1,17,28,4,8,11,0,1,17,31,2,10,0,16,10,10,1,56,13,11,1,17,45,12,3,10,0,16,9,56,14,20,12,2,10,3,10,2,38,4,41,5,25,10,0,16,7,10,3,56,15,4,36,11,0,16,7,11,3,56,16,20,2,11,3,6,1,0,0,0,0,0,0,0,23,12,3,5,20,11,0,1,17,31,2,23,1,0,0,9,4,11,0,16,0,20,2,24,1,0,0,9,4,11,0,16,1,20,2,25,3,0,0,9,3,11,0,16,7,2,26,1,0,0,9,4,11,0,16,12,20,2,27,1,0,0,9,4,11,0,16,13,20,2,28,0,0,0,18,17,10,0,17,16,4,8,11,0,1,8,12,2,5,15,11,0,16,9,56,14,20,11,1,36,12,2,11,2,2,29,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,12,20,53,11,1,53,24,11,0,16,13,20,53,26,52,2,30,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,13,20,53,11,1,53,24,11,0,16,12,20,53,26,52,2,31,0,0,0,9,4,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,18,1,2,32,0,0,0,55,22,10,0,11,1,17,22,12,3,14,3,10,0,16,5,20,17,30,12,4,11,0,16,8,20,12,2,11,4,11,2,33,4,19,5,21,7,10,39,2,0,7,0,8,0,9,2,1,2,2,0,3,0,4,0,6,0,5,0,1,0,2,2,3,1,0,1,1,0,76,0,77,0],"storage_fund":[161,28,235,11,6,0,0,0,11,1,0,6,2,6,14,3,20,44,4,64,8,5,72,73,7,145,1,178,1,8,195,2,64,10,131,3,15,12,146,3,107,13,253,3,4,15,129,4,2,0,9,1,4,1,10,0,2,4,0,1,0,4,1,0,1,2,1,2,0,0,6,0,1,0,0,3,2,0,0,0,13,3,4,0,0,12,3,4,0,1,5,8,4,1,0,1,8,9,7,1,0,1,14,10,4,1,0,1,15,5,7,1,0,7,6,4,6,5,6,6,6,1,11,1,1,8,2,1,8,0,6,7,8,0,11,1,1,8,2,11,1,1,8,2,11,1,1,8,2,3,3,1,6,8,0,1,3,0,1,8,2,1,11,1,1,9,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,6,11,1,1,9,0,7,66,97,108,97,110,99,101,3,83,85,73,11,83,116,111,114,97,103,101,70,117,110,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,4,106,111,105,110,3,110,101,119,22,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,98,97,108,97,110,99,101,5,115,112,108,105,116,12,115,116,111,114,97,103,101,95,102,117,110,100,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,13,116,111,116,97,108,95,98,97,108,97,110,99,101,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,11,1,1,8,2,7,11,1,1,8,2,0,3,0,0,5,4,56,0,11,0,18,0,2,1,3,0,0,0,30,10,0,15,0,11,2,56,1,1,10,0,15,0,11,3,56,1,1,10,0,15,1,11,1,56,1,1,10,0,15,1,11,5,56,2,12,6,10,0,15,0,11,6,56,1,1,11,0,15,1,11,4,56,2,2,2,1,0,0,5,4,11,0,16,1,56,3,2,3,1,0,0,5,8,10,0,16,1,56,3,11,0,16,0,56,3,22,2,0,1,0,0,0,11,0],"sui_system":[161,28,235,11,6,0,0,0,12,1,0,30,2,30,78,3,108,188,3,4,168,4,16,5,184,4,214,3,7,142,8,237,13,8,251,21,96,6,219,22,54,10,145,23,8,12,153,23,251,6,13,148,30,4,15,152,30,2,0,57,1,33,2,20,2,22,2,24,2,32,2,56,2,60,2,61,2,62,0,54,0,55,0,58,0,83,0,84,0,8,8,0,1,3,7,1,0,0,2,0,4,1,0,1,3,1,12,1,0,1,5,2,7,0,5,14,4,0,6,5,2,0,7,12,12,2,7,1,4,1,9,13,2,0,10,6,4,0,11,4,7,0,11,7,12,0,12,9,4,0,12,10,4,0,12,11,4,0,13,16,4,0,14,15,12,0,0,23,0,1,0,0,42,2,1,0,0,44,3,1,0,0,41,3,1,0,0,43,3,1,0,0,46,4,1,0,0,52,4,1,0,0,45,5,1,0,0,51,5,1,0,0,38,6,1,0,0,40,6,7,0,0,39,8,1,0,0,47,9,1,0,0,48,9,10,0,0,37,11,1,0,0,63,11,1,0,0,49,3,1,0,0,73,12,1,0,0,71,12,1,0,0,72,12,1,0,0,81,12,1,0,0,74,12,1,0,0,64,12,1,0,0,76,12,1,0,0,66,12,1,0,0,77,12,1,0,0,67,12,1,0,0,79,12,1,0,0,69,12,1,0,0,78,13,1,0,0,68,13,1,0,0,80,12,1,0,0,70,12,1,0,0,75,12,1,0,0,65,12,1,0,0,34,14,15,0,0,17,16,17,0,0,19,18,10,0,0,30,16,19,0,0,31,16,20,0,0,29,16,20,0,3,25,39,40,1,0,4,18,26,1,2,7,4,4,21,49,53,2,7,4,4,36,49,50,2,7,4,8,35,35,1,1,12,8,53,28,1,1,8,9,50,33,34,0,12,17,19,17,0,12,19,47,10,0,12,23,22,23,0,12,27,1,24,0,12,34,46,15,0,12,37,43,1,0,12,38,36,7,0,12,39,37,7,0,12,41,30,1,0,12,42,29,1,0,12,43,30,1,0,12,44,30,1,0,12,45,32,1,0,12,46,31,1,0,12,47,42,10,0,12,49,30,1,0,12,51,32,1,0,12,52,31,1,0,12,59,19,24,0,12,63,43,1,0,12,64,44,1,0,12,65,44,1,0,12,66,44,1,0,12,67,44,1,0,12,68,45,1,0,12,69,44,1,0,12,70,44,1,0,12,71,44,1,0,12,72,44,1,0,12,73,44,1,0,12,74,44,1,0,12,75,44,1,0,12,76,44,1,0,12,77,44,1,0,12,78,45,1,0,12,79,44,1,0,12,80,44,1,0,12,81,44,1,0,12,82,23,51,0,42,25,46,27,45,7,41,38,45,41,44,25,42,52,43,52,8,8,5,10,8,15,11,2,1,8,6,3,3,8,14,8,9,7,8,8,0,16,7,8,0,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,8,2,7,8,0,7,8,8,3,7,8,0,6,8,16,3,3,7,8,0,3,7,8,8,4,7,8,0,11,3,1,8,6,5,7,8,8,1,8,11,5,7,8,0,10,11,3,1,8,6,11,1,1,3,5,7,8,8,3,7,8,0,8,11,7,8,8,1,11,2,1,8,6,3,7,8,0,6,8,16,5,3,7,8,0,10,2,6,8,8,4,7,8,0,10,2,10,2,6,8,8,2,7,8,0,6,8,4,1,6,11,7,2,3,8,10,1,7,8,0,1,10,5,11,11,2,1,8,6,11,2,1,8,6,7,8,0,3,3,3,3,3,3,3,7,8,8,1,6,8,13,1,7,8,13,3,8,0,8,12,3,7,10,8,15,11,2,1,8,6,3,3,8,14,8,9,7,8,8,1,8,12,1,3,2,3,8,12,3,7,8,5,9,0,9,1,1,8,0,1,9,0,16,7,8,13,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,8,2,7,8,13,7,8,8,3,7,8,13,6,8,16,3,3,7,8,13,3,7,8,8,1,6,8,8,1,5,2,9,0,5,4,7,8,13,11,3,1,8,6,5,7,8,8,5,7,8,13,10,11,3,1,8,6,11,1,1,3,5,7,8,8,1,8,6,2,11,2,1,9,0,7,8,8,1,11,3,1,9,0,1,11,3,1,8,6,3,7,8,13,8,11,7,8,8,3,7,8,13,6,8,16,5,3,7,8,13,10,2,6,8,8,4,7,8,13,10,2,10,2,6,8,8,2,7,8,13,6,8,4,11,7,8,13,3,3,11,2,1,8,6,11,2,1,8,6,3,3,3,3,3,7,8,8,2,7,8,13,8,13,2,7,8,5,9,0,1,9,1,1,8,13,2,3,8,13,1,7,9,1,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,14,83,117,105,83,121,115,116,101,109,83,116,97,116,101,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,26,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,101,115,3,97,100,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,4,99,111,105,110,6,99,114,101,97,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,2,105,100,24,108,111,97,100,95,105,110,110,101,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,17,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,21,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,95,109,117,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,19,112,111,111,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,27,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,110,111,110,95,101,110,116,114,121,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,32,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,95,110,111,110,95,101,110,116,114,121,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,6,115,101,110,100,101,114,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,28,8,5,85,3,0,3,0,0,21,23,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,50,12,9,17,51,12,10,11,0,10,10,18,0,12,8,13,8,15,0,11,10,11,9,56,0,11,8,56,1,2,1,1,4,0,1,19,11,0,17,39,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,11,15,17,57,2,2,1,4,0,1,5,11,0,17,39,11,1,17,59,2,3,1,4,0,1,5,11,0,17,39,11,1,17,56,2,4,1,4,0,1,5,11,0,17,39,11,1,17,58,2,5,1,4,0,1,6,11,0,17,39,11,1,11,2,17,61,2,6,1,4,0,1,6,11,0,17,39,11,1,11,2,17,65,2,7,1,4,0,1,6,11,0,17,39,11,1,11,2,17,60,2,8,1,4,0,1,6,11,0,17,39,11,1,11,2,17,64,2,9,1,4,0,1,10,11,0,11,1,11,2,10,3,17,10,11,3,46,17,47,56,2,2,10,1,0,0,1,7,11,0,17,39,11,1,11,2,11,3,17,54,2,11,1,4,0,1,12,11,0,17,39,11,1,11,2,11,3,10,4,17,55,11,4,46,17,47,56,2,2,12,1,4,0,1,11,11,0,11,1,10,2,17,13,10,2,56,3,11,2,46,17,47,56,4,2,13,1,0,0,1,6,11,0,17,39,11,1,11,2,17,62,2,14,1,4,0,1,6,11,0,17,39,11,1,11,2,17,53,2,15,1,4,0,1,6,11,0,17,39,11,1,11,2,17,67,2,16,1,4,0,1,5,11,0,17,39,11,1,17,63,2,17,1,4,0,1,6,11,0,17,39,11,1,11,2,17,77,2,18,1,4,0,1,6,11,0,17,39,11,1,11,2,17,75,2,19,1,4,0,1,6,11,0,17,39,11,1,11,2,17,76,2,20,1,4,0,1,6,11,0,17,39,11,1,11,2,17,85,2,21,1,4,0,1,6,11,0,17,39,11,1,11,2,17,78,2,22,1,4,0,1,6,11,0,17,39,11,1,11,2,17,68,2,23,1,4,0,1,6,11,0,17,39,11,1,11,2,17,80,2,24,1,4,0,1,6,11,0,17,39,11,1,11,2,17,70,2,25,1,4,0,1,6,11,0,17,39,11,1,11,2,17,81,2,26,1,4,0,1,6,11,0,17,39,11,1,11,2,17,71,2,27,1,4,0,1,6,11,0,17,39,11,1,11,2,17,83,2,28,1,4,0,1,6,11,0,17,39,11,1,11,2,17,73,2,29,1,4,0,1,7,11,0,17,39,11,1,11,2,11,3,17,82,2,30,1,4,0,1,7,11,0,17,39,11,1,11,2,11,3,17,72,2,31,1,4,0,1,6,11,0,17,39,11,1,11,2,17,84,2,32,1,4,0,1,6,11,0,17,39,11,1,11,2,17,74,2,33,1,4,0,1,6,11,0,17,39,11,1,11,2,17,79,2,34,1,4,0,1,6,11,0,17,39,11,1,11,2,17,69,2,35,1,0,0,1,5,11,0,17,39,11,1,17,52,2,36,1,0,0,1,4,11,0,17,38,17,48,2,37,0,0,0,20,29,11,2,17,39,12,11,10,10,46,17,47,7,2,33,4,10,5,16,11,11,1,11,10,1,7,0,39,11,11,11,3,11,4,11,0,11,1,11,5,11,6,11,7,11,8,11,9,11,10,17,49,2,38,0,0,0,1,4,11,0,17,40,46,2,39,0,0,0,1,3,11,0,17,40,2,40,0,0,0,48,47,10,0,16,1,20,6,1,0,0,0,0,0,0,0,33,4,25,10,0,15,0,10,0,16,1,20,56,5,17,86,12,2,6,2,0,0,0,0,0,0,0,10,0,15,1,21,10,0,15,0,10,0,16,1,20,11,2,56,6,10,0,15,0,10,0,16,1,20,56,7,12,1,10,1,46,17,66,11,0,16,1,20,33,4,41,5,45,11,1,1,7,1,39,11,1,2,0,0,0,1,0,26,0],"sui_system_state_inner":[161,28,235,11,6,0,0,0,12,1,0,45,2,45,108,3,153,1,235,5,4,132,7,50,5,182,7,151,7,7,205,14,129,30,8,206,44,96,6,174,45,117,10,163,46,189,1,12,224,47,134,18,13,230,65,46,15,148,66,4,0,115,1,70,2,27,2,28,2,29,2,41,2,69,2,72,2,113,2,117,2,123,2,124,2,177,1,2,178,1,0,103,0,106,0,109,0,164,1,0,165,1,0,169,1,0,13,4,0,0,14,4,0,0,10,4,0,0,11,4,0,0,12,3,0,1,4,7,1,0,0,2,0,12,0,3,1,4,1,0,1,4,2,12,1,0,1,6,3,7,0,8,6,2,0,9,15,12,2,7,1,4,1,11,16,2,0,12,21,7,2,1,0,0,0,13,22,7,1,3,0,14,7,4,0,15,5,7,0,15,8,12,0,16,9,4,0,17,18,4,0,18,17,12,0,18,19,2,0,19,20,4,0,0,31,0,1,0,0,32,2,3,0,0,163,1,1,4,0,0,83,5,6,0,0,85,7,6,0,0,82,7,6,0,0,84,7,6,0,0,87,8,6,0,0,99,8,6,0,0,86,9,6,0,0,98,9,6,0,0,80,10,11,0,0,81,12,11,0,0,88,13,14,0,0,78,15,6,0,0,125,15,6,0,0,79,16,6,0,0,126,16,6,0,0,89,7,6,0,0,154,1,17,6,0,0,152,1,17,6,0,0,153,1,17,6,0,0,162,1,17,6,0,0,155,1,17,6,0,0,132,1,17,6,0,0,157,1,17,6,0,0,134,1,17,6,0,0,158,1,17,6,0,0,135,1,17,6,0,0,160,1,17,6,0,0,137,1,17,6,0,0,159,1,18,6,0,0,136,1,18,6,0,0,161,1,17,6,0,0,138,1,17,6,0,0,156,1,17,6,0,0,133,1,17,6,0,0,25,19,14,0,0,38,20,21,0,0,74,20,21,0,0,116,20,21,0,0,46,6,21,0,0,40,20,21,0,0,170,1,22,21,0,0,171,1,22,23,0,0,172,1,20,24,0,0,49,22,25,0,0,51,20,21,0,0,50,20,21,0,0,73,26,27,0,0,23,20,28,0,0,43,29,14,0,1,34,99,68,1,0,1,59,98,63,1,0,2,66,39,40,0,3,35,38,6,1,0,3,60,85,21,1,0,3,101,89,38,1,0,3,176,1,87,21,1,0,3,181,1,84,38,1,0,3,182,1,6,38,1,0,4,44,100,58,1,0,4,56,58,38,1,0,5,36,68,6,1,3,7,61,97,6,1,0,10,75,101,6,1,12,11,38,43,21,0,11,95,43,44,0,12,30,67,63,2,1,0,12,37,6,36,2,1,0,12,47,67,93,2,1,0,12,48,71,72,2,1,0,12,55,70,6,2,1,0,12,77,71,77,2,1,0,13,30,73,63,1,3,13,37,6,69,1,3,13,55,74,6,1,3,13,58,76,63,1,3,13,77,75,6,1,3,13,100,68,69,1,3,14,25,88,14,0,15,102,60,21,0,16,25,91,14,0,16,66,14,34,0,16,118,86,21,0,16,120,86,21,0,17,66,45,42,0,17,67,78,6,0,17,87,54,6,0,17,96,57,6,0,17,97,54,6,0,17,127,79,6,0,17,128,1,79,6,0,17,129,1,79,6,0,17,130,1,79,6,0,17,131,1,82,6,0,17,139,1,79,6,0,17,140,1,79,6,0,17,141,1,79,6,0,17,142,1,79,6,0,17,143,1,79,6,0,17,144,1,79,6,0,17,145,1,79,6,0,17,146,1,79,6,0,17,147,1,79,6,0,17,148,1,82,6,0,17,149,1,79,6,0,17,150,1,79,6,0,17,151,1,79,6,0,18,179,1,65,66,0,19,23,33,28,0,19,24,33,49,0,19,25,90,6,0,19,26,81,6,0,19,33,33,21,0,19,52,56,53,0,19,53,56,53,0,19,54,52,53,0,19,57,62,63,0,19,66,31,32,0,19,68,33,21,0,19,73,94,27,0,19,80,59,11,0,19,82,48,6,0,19,83,46,6,0,19,84,47,6,0,19,85,47,6,0,19,86,55,6,0,19,88,61,14,0,19,107,33,24,0,19,121,33,21,0,19,171,1,62,23,0,19,173,1,62,21,0,19,180,1,51,50,0,69,35,60,37,62,37,68,35,79,44,72,35,71,35,74,44,76,44,78,44,77,44,73,35,59,37,56,37,58,37,57,37,63,92,70,35,75,44,64,37,53,21,52,21,61,37,65,96,55,37,7,10,8,19,11,7,1,8,10,3,3,8,0,8,15,7,8,12,1,8,2,8,3,3,3,3,3,3,3,7,8,12,1,8,0,1,8,3,16,7,8,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,0,2,7,8,3,7,8,12,3,7,8,3,6,8,20,3,3,7,8,3,3,7,8,12,4,7,8,3,11,8,1,8,10,5,7,8,12,1,8,17,5,7,8,3,10,11,8,1,8,10,11,5,1,3,5,7,8,12,3,7,8,3,8,17,7,8,12,1,11,7,1,8,10,3,7,8,3,6,8,20,5,3,8,21,5,7,11,13,2,5,11,14,1,5,3,7,8,3,10,2,6,8,12,4,7,8,3,10,2,10,2,6,8,12,11,7,8,3,3,3,11,7,1,8,10,11,7,1,8,10,3,3,3,3,3,7,8,12,1,6,8,3,1,3,2,6,8,3,5,1,8,9,1,6,11,11,2,8,9,5,1,11,14,1,5,2,7,8,3,6,8,9,1,6,11,11,2,3,8,16,1,10,5,3,10,11,8,1,8,10,11,5,1,3,7,8,12,2,3,8,22,2,10,8,19,7,8,12,1,8,22,1,6,8,22,1,8,18,2,5,11,14,1,5,1,11,13,2,9,0,9,1,1,8,10,1,11,7,1,9,0,1,7,8,12,1,8,6,23,3,3,3,3,3,8,6,8,0,3,3,1,11,7,1,8,10,3,3,11,7,1,8,10,8,15,3,8,6,8,18,3,3,11,13,2,5,11,14,1,5,3,8,22,1,8,19,1,6,8,12,1,5,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,3,7,8,22,8,19,7,8,12,2,7,8,22,7,8,12,3,7,8,22,3,7,8,12,1,6,10,8,19,1,8,21,3,7,8,22,6,8,20,2,3,7,8,22,6,8,21,1,1,7,8,19,3,7,8,19,8,21,3,3,7,8,22,3,6,8,12,2,7,8,22,6,8,12,2,7,8,19,3,1,11,8,1,9,0,4,7,8,22,5,11,7,1,8,10,7,8,12,1,6,8,17,3,7,8,22,8,17,7,8,12,2,6,8,22,5,1,1,4,6,5,6,5,5,7,11,14,1,5,1,6,8,21,1,6,5,2,6,11,13,2,9,0,9,1,6,9,0,1,9,0,1,11,14,1,9,0,3,7,11,13,2,9,0,9,1,9,0,9,1,2,7,11,13,2,9,0,9,1,6,9,0,1,7,9,1,2,6,11,14,1,9,0,6,9,0,2,7,11,14,1,9,0,9,0,2,7,11,14,1,9,0,6,9,0,1,6,11,14,1,9,0,2,9,0,9,1,2,7,8,19,7,8,12,2,7,8,19,10,2,2,7,8,19,6,8,19,2,6,8,22,6,8,19,3,7,8,19,10,2,10,2,44,1,3,3,3,3,3,3,1,1,1,11,7,1,8,10,3,3,3,3,3,3,3,3,4,3,3,3,11,7,1,8,10,3,3,3,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,3,11,7,1,8,10,4,11,7,1,8,10,4,3,3,3,3,4,3,1,7,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,1,6,8,18,1,6,11,7,1,9,0,1,7,8,15,2,7,11,7,1,9,0,3,9,7,8,22,7,11,7,1,8,10,7,11,7,1,8,10,7,11,13,2,5,11,14,1,5,3,3,3,3,7,8,12,6,7,8,18,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,1,8,4,1,6,9,1,2,7,8,22,6,8,9,5,11,7,1,8,10,3,11,7,1,8,10,11,8,1,8,10,11,7,1,8,10,1,11,8,1,8,10,2,7,11,8,1,9,0,10,11,8,1,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,2,11,7,1,9,0,7,8,12,2,9,0,5,3,66,97,103,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,11,83,116,111,114,97,103,101,70,117,110,100,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,20,83,121,115,116,101,109,69,112,111,99,104,73,110,102,111,69,118,101,110,116,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,18,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,86,50,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,6,86,101,99,77,97,112,6,86,101,99,83,101,116,26,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,101,115,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,3,98,97,103,7,98,97,108,97,110,99,101,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,5,101,109,112,116,121,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,24,101,112,111,99,104,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,20,101,120,116,114,97,99,116,95,99,111,105,110,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,3,103,101,116,7,103,101,116,95,109,117,116,16,103,101,116,95,114,101,112,111,114,116,101,114,115,95,111,102,31,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,111,98,106,101,99,116,95,114,101,98,97,116,101,115,30,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,116,111,116,97,108,95,98,97,108,97,110,99,101,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,6,105,110,115,101,114,116,12,105,110,116,111,95,98,97,108,97,110,99,101,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,106,111,105,110,8,106,111,105,110,95,118,101,99,28,108,101,102,116,111,118,101,114,95,115,116,111,114,97,103,101,95,102,117,110,100,95,105,110,102,108,111,119,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,19,109,105,110,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,3,110,101,119,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,114,97,109,101,116,101,114,115,3,112,97,121,19,112,111,111,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,115,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,19,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,21,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,9,115,97,102,101,95,109,111,100,101,29,115,97,102,101,95,109,111,100,101,95,99,111,109,112,117,116,97,116,105,111,110,95,114,101,119,97,114,100,115,36,115,97,102,101,95,109,111,100,101,95,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,115,116,111,114,97,103,101,95,102,101,101,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,119,97,114,100,115,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,9,115,105,110,103,108,101,116,111,110,5,115,112,108,105,116,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,13,115,116,97,107,101,95,115,117,98,115,105,100,121,20,115,116,97,107,101,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,12,115,116,97,107,105,110,103,95,112,111,111,108,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,14,115,116,111,114,97,103,101,95,99,104,97,114,103,101,12,115,116,111,114,97,103,101,95,102,117,110,100,20,115,116,111,114,97,103,101,95,102,117,110,100,95,98,97,108,97,110,99,101,25,115,116,111,114,97,103,101,95,102,117,110,100,95,114,101,105,110,118,101,115,116,109,101,110,116,14,115,116,111,114,97,103,101,95,114,101,98,97,116,101,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,5,116,97,98,108,101,13,116,111,116,97,108,95,98,97,108,97,110,99,101,14,116,111,116,97,108,95,103,97,115,95,102,101,101,115,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,31,116,111,116,97,108,95,115,116,97,107,101,95,114,101,119,97,114,100,115,95,100,105,115,116,114,105,98,117,116,101,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,26,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,24,118,97,108,105,100,97,116,111,114,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,31,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,10,118,97,108,105,100,97,116,111,114,115,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,3,8,1,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,8,39,3,105,3,63,3,65,3,167,1,3,174,1,3,166,1,3,42,8,6,1,2,9,39,3,105,3,64,3,63,3,65,3,167,1,3,174,1,3,166,1,3,42,8,6,2,2,16,38,3,74,3,116,3,175,1,8,22,109,8,18,71,8,0,76,3,168,1,11,13,2,5,11,14,1,5,103,8,15,90,1,94,11,7,1,8,10,91,11,7,1,8,10,93,3,92,3,40,3,42,8,6,3,2,16,38,3,74,3,116,3,175,1,8,22,109,8,18,71,8,1,76,3,168,1,11,13,2,5,11,14,1,5,103,8,15,90,1,94,11,7,1,8,10,91,11,7,1,8,10,93,3,92,3,40,3,42,8,6,4,2,12,38,3,74,3,76,3,121,3,111,3,108,3,112,3,110,3,104,3,119,3,122,3,62,3,0,3,0,0,30,27,11,0,10,6,17,119,12,8,14,8,17,114,12,7,6,0,0,0,0,0,0,0,0,11,2,17,41,11,8,11,1,17,83,11,4,11,7,56,0,11,5,9,56,1,56,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,3,11,6,17,54,18,2,2,1,3,0,0,6,11,11,0,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,54,18,0,2,2,3,0,0,41,55,11,0,19,2,12,17,12,3,12,12,12,13,12,11,12,14,12,10,12,15,12,21,12,9,12,7,12,18,12,23,1,12,8,12,1,11,7,19,0,12,6,12,19,12,22,12,20,12,5,12,4,12,16,12,2,11,1,11,8,6,2,0,0,0,0,0,0,0,11,23,11,18,11,2,11,16,6,4,0,0,0,0,0,0,0,11,4,11,5,11,20,11,22,11,19,11,6,18,1,11,9,11,21,11,15,11,10,11,14,11,11,11,13,11,12,11,3,11,17,18,3,2,3,3,0,0,42,26,10,15,46,17,67,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,10,15,17,86,12,16,11,0,15,0,11,16,11,15,17,124,2,4,3,0,0,6,5,11,0,15,0,11,1,17,126,2,5,3,0,0,6,25,10,0,16,0,17,120,10,0,16,1,16,2,20,35,4,10,5,16,11,0,1,11,1,1,7,3,39,10,0,15,0,11,0,16,1,16,3,20,11,1,17,123,2,6,3,0,0,6,31,10,0,16,0,17,111,65,42,10,0,16,1,16,4,20,38,4,26,10,0,16,0,17,120,10,0,16,1,16,4,20,36,4,20,5,26,11,0,1,11,1,1,7,3,39,11,0,15,0,11,1,17,125,2,7,3,0,0,50,15,10,0,15,0,11,1,7,1,17,133,1,12,3,11,0,15,0,14,3,9,17,117,11,3,11,2,17,88,2,8,3,0,0,50,15,10,0,15,0,11,1,7,2,17,133,1,12,3,11,0,15,0,14,3,8,17,117,11,3,11,2,17,90,2,9,3,0,0,6,7,11,0,15,0,11,1,11,2,46,17,127,2,10,3,0,0,6,8,11,0,15,0,11,2,46,17,116,11,1,17,89,2,11,3,0,0,6,8,11,0,15,0,11,2,11,1,56,2,11,3,17,122,2,12,3,0,0,14,12,11,1,11,2,10,4,17,51,12,5,11,0,15,0,11,3,11,5,11,4,17,122,2,13,3,0,0,6,20,14,1,17,81,10,2,46,17,66,37,4,8,5,14,11,0,1,11,2,1,7,9,39,11,0,15,0,11,1,11,2,17,128,1,2,14,3,0,0,6,22,10,0,16,0,10,2,17,118,4,6,5,12,11,0,1,11,1,1,7,4,39,10,0,15,0,11,1,7,0,17,133,1,11,2,11,0,15,5,17,16,2,15,3,0,0,6,10,10,0,15,0,11,1,7,0,17,133,1,11,2,11,0,15,5,17,17,2,16,0,0,0,64,46,14,0,17,109,20,12,5,10,5,10,1,34,4,9,5,13,11,2,1,7,6,39,10,2,14,1,12,3,46,11,3,56,3,32,4,27,11,2,11,1,11,5,56,4,56,5,5,45,11,2,14,1,56,6,12,6,10,6,14,5,12,4,46,11,4,56,7,32,4,43,11,6,11,5,56,8,5,45,11,6,1,2,17,0,0,0,64,50,10,2,14,1,12,3,46,11,3,56,3,4,8,5,12,11,2,1,7,7,39,10,2,14,1,56,6,12,6,14,0,17,109,20,12,5,10,6,14,5,12,4,46,11,4,56,7,4,28,5,34,11,2,1,11,6,1,7,7,39,10,6,14,5,56,9,11,6,46,56,10,4,47,11,2,14,1,56,11,1,1,5,49,11,2,1,2,18,3,0,0,6,8,11,0,15,0,10,1,46,17,116,11,1,17,87,2,19,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,100,2,20,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,98,2,21,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,99,2,22,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,108,2,23,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,101,11,3,46,12,4,11,0,16,0,11,4,17,113,2,24,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,91,2,25,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,103,11,3,46,12,4,11,0,16,0,11,4,17,113,2,26,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,93,2,27,3,0,0,6,7,11,0,15,0,11,2,17,115,11,1,17,104,2,28,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,94,2,29,3,0,0,6,7,11,0,15,0,11,2,17,115,11,1,17,106,2,30,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,96,2,31,3,0,0,80,17,10,0,15,0,11,3,17,115,12,4,10,4,11,1,11,2,17,105,11,4,46,12,5,11,0,16,0,11,5,17,113,2,32,3,0,0,6,8,11,0,15,0,11,3,17,116,11,1,11,2,17,95,2,33,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,107,11,3,46,12,4,11,0,16,0,11,4,17,113,2,34,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,97,2,35,3,0,0,80,16,10,0,15,0,11,2,17,115,12,3,10,3,11,1,17,102,11,3,46,12,4,11,0,16,0,11,4,17,113,2,36,3,0,0,6,7,11,0,15,0,11,2,17,116,11,1,17,92,2,37,3,0,0,83,220,2,10,0,16,6,20,12,37,10,9,10,0,15,6,21,7,12,52,12,28,10,7,10,28,37,4,20,10,8,11,28,37,12,11,5,22,9,12,11,11,11,4,25,5,31,11,0,1,11,10,1,7,8,39,10,0,16,1,16,7,20,6,0,0,0,0,0,0,0,0,36,4,43,6,20,0,0,0,0,0,0,0,10,0,15,1,15,7,21,10,0,15,8,56,12,12,40,13,3,11,40,56,13,1,10,0,15,9,56,12,12,39,13,4,11,39,56,13,1,11,5,10,0,16,10,20,22,12,5,6,0,0,0,0,0,0,0,0,10,0,15,10,21,11,6,10,0,16,11,20,22,12,6,6,0,0,0,0,0,0,0,0,10,0,15,11,21,10,0,16,0,17,130,1,12,54,10,0,16,12,17,84,12,44,10,44,11,54,22,12,52,14,3,56,14,12,43,14,4,56,14,12,29,10,10,46,17,66,10,0,16,1,16,7,20,38,4,116,11,9,11,37,10,0,16,1,16,13,20,22,38,12,20,5,118,9,12,20,11,20,4,125,10,0,15,14,17,80,12,21,5,127,56,1,12,21,11,21,12,41,14,41,56,14,12,42,13,4,11,41,56,13,1,11,52,53,12,53,10,29,53,12,30,11,44,53,11,30,24,11,53,26,12,48,13,4,10,48,52,56,15,12,47,11,48,11,7,53,24,7,12,26,12,46,13,47,10,46,52,56,15,12,45,10,0,16,15,20,6,1,0,0,0,0,0,0,0,22,10,0,15,15,21,11,1,10,0,16,15,20,33,4,181,1,5,187,1,11,0,1,11,10,1,7,11,39,14,4,56,14,12,32,14,47,56,14,12,50,10,0,15,0,13,4,13,47,10,0,15,5,11,8,10,0,16,1,16,16,20,10,0,16,1,16,17,20,10,0,16,1,16,18,20,11,10,17,112,10,0,16,0,17,130,1,12,36,14,4,56,14,12,31,14,47,56,14,12,49,11,32,11,31,23,12,33,11,50,11,49,23,12,51,11,2,10,0,15,19,21,10,0,16,0,17,114,10,0,15,20,21,11,47,12,34,13,34,11,4,56,13,1,14,34,56,14,12,35,10,0,15,12,11,3,11,45,11,34,10,5,11,6,17,82,12,38,10,0,16,15,20,12,22,10,0,16,19,20,12,23,10,0,16,20,20,12,24,11,36,12,25,11,43,12,26,11,46,52,12,27,11,5,12,12,10,0,16,12,17,84,12,13,11,42,12,14,11,29,12,15,11,33,11,51,22,12,16,11,35,12,17,11,22,11,23,11,24,11,25,11,27,11,26,11,12,11,13,11,14,11,15,11,16,11,17,18,4,56,16,9,10,0,15,21,21,10,0,16,10,20,6,0,0,0,0,0,0,0,0,33,4,198,2,10,0,16,8,56,14,6,0,0,0,0,0,0,0,0,33,12,18,5,200,2,9,12,18,11,18,4,209,2,11,0,16,9,56,14,6,0,0,0,0,0,0,0,0,33,12,19,5,213,2,11,0,1,9,12,19,11,19,4,216,2,5,218,2,7,10,39,11,38,2,38,3,0,0,6,4,11,0,16,15,20,2,39,3,0,0,6,4,11,0,16,19,20,2,40,3,0,0,6,4,11,0,16,22,20,2,41,3,0,0,6,2,7,3,2,42,3,0,0,6,4,11,0,16,6,20,2,43,3,0,0,6,5,11,0,16,0,11,1,17,132,1,2,44,3,0,0,6,5,11,0,16,0,11,1,17,131,1,2,45,3,0,0,6,4,11,0,16,0,17,129,1,2,46,3,0,0,25,18,10,0,16,5,14,1,56,3,4,12,11,0,16,5,14,1,56,17,20,12,2,5,16,11,0,1,56,18,12,2,11,2,2,47,3,0,0,6,4,11,0,16,12,17,84,2,48,3,0,0,6,4,11,0,16,12,17,85,2,49,3,0,0,6,5,11,0,15,0,11,1,17,121,2,50,3,0,0,6,4,11,0,16,0,17,110,2,51,0,0,0,95,45,13,0,69,96,12,6,13,6,11,0,56,19,11,6,56,2,12,7,14,1,56,20,4,39,11,1,56,21,12,4,13,7,11,4,56,15,12,5,14,7,56,14,6,0,0,0,0,0,0,0,0,36,4,32,11,7,10,2,56,22,11,2,46,17,67,56,23,5,36,11,2,1,11,7,56,24,11,5,12,3,5,43,11,2,1,11,7,12,3,11,3,2,3,3,3,5,1,3,1,4,1,2,3,7,3,14,1,1,3,10,3,11,3,12,3,13,3,4,1,0,3,8,3,0,1,5,1,6,1,7,3,1,3,6,3,9,3,2,0,45,0,114,0],"validator":[161,28,235,11,6,0,0,0,12,1,0,33,2,33,72,3,105,197,4,4,174,5,40,5,214,5,131,4,7,217,9,247,19,8,208,29,96,6,176,30,190,1,10,238,31,156,1,12,138,33,237,27,13,247,60,60,15,179,61,13,0,137,1,1,20,1,23,1,74,1,105,2,21,2,22,2,34,2,72,2,106,2,113,2,114,2,134,1,0,103,0,139,1,0,14,4,0,0,13,4,0,0,8,3,0,0,11,3,0,1,9,7,0,3,3,7,1,0,0,4,9,7,0,5,0,12,0,6,1,4,1,0,1,8,2,7,0,9,5,2,0,11,10,2,0,12,12,7,0,13,4,7,0,13,6,12,0,13,7,12,0,14,15,2,0,0,56,0,1,0,0,54,2,3,0,0,26,4,5,0,0,16,4,5,0,0,18,6,5,0,0,88,7,8,0,0,89,7,5,0,0,92,9,10,0,0,91,11,5,0,0,96,11,5,0,0,90,4,5,0,0,95,4,5,0,0,29,12,5,0,0,83,13,5,0,0,47,14,15,0,0,49,14,16,0,0,107,14,17,0,0,50,14,18,0,0,30,14,18,0,0,42,14,19,0,0,84,14,19,0,0,52,14,18,0,0,75,14,18,0,0,80,14,18,0,0,145,1,14,18,0,0,86,14,20,0,0,85,14,20,0,0,53,14,20,0,0,146,1,14,20,0,0,62,14,21,0,0,64,14,21,0,0,65,14,21,0,0,69,14,21,0,0,67,14,22,0,0,66,14,22,0,0,63,14,22,0,0,70,14,22,0,0,73,14,23,0,0,60,14,24,0,0,112,14,24,0,0,100,14,24,0,0,111,14,24,0,0,144,1,14,24,0,0,97,4,5,0,0,76,14,24,0,0,77,14,24,0,0,38,14,24,0,0,25,14,24,0,0,79,25,26,0,0,104,14,27,0,0,43,28,15,0,0,45,29,15,1,0,0,44,30,15,1,0,0,58,13,5,0,0,125,31,5,0,0,123,31,5,0,0,124,31,5,0,0,133,1,31,5,0,0,126,31,5,0,0,116,31,5,0,0,128,1,31,5,0,0,118,31,5,0,0,129,1,31,5,0,0,119,31,5,0,0,131,1,31,5,0,0,121,31,5,0,0,130,1,32,5,0,0,120,32,5,0,0,127,31,5,0,0,117,31,5,0,0,132,1,31,5,0,0,122,31,5,0,0,31,6,5,0,0,135,1,16,5,0,0,136,1,33,5,0,0,40,14,34,0,0,55,35,3,0,1,105,33,41,0,2,110,65,33,1,0,3,24,67,65,1,0,3,36,70,53,1,0,3,46,67,15,1,0,3,48,67,15,1,0,3,71,5,37,1,0,3,98,53,37,1,0,4,37,41,38,0,5,54,43,44,0,6,142,1,48,24,1,0,7,32,53,5,1,3,8,41,65,27,1,8,10,87,54,5,1,12,11,33,49,24,0,11,94,49,17,0,12,57,33,42,0,13,17,45,5,0,13,27,45,5,0,13,28,61,5,0,13,47,34,15,0,13,54,43,64,0,13,76,34,24,0,13,77,34,24,0,13,79,63,26,0,13,82,51,5,0,13,83,62,5,0,13,88,50,8,0,13,92,57,10,0,13,99,56,24,0,13,101,56,24,0,13,108,34,24,0,14,58,69,27,0,14,143,1,59,60,0,83,33,83,38,87,47,88,52,90,8,88,58,89,64,52,38,52,33,51,38,51,33,81,53,79,53,84,38,84,33,82,38,80,38,82,33,80,33,78,1,14,5,10,2,10,2,10,2,10,2,8,6,8,6,8,12,8,12,8,6,8,6,8,6,8,6,8,7,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,11,1,8,1,2,7,8,1,3,0,1,7,8,1,4,7,8,1,11,8,1,8,10,5,7,8,11,1,8,14,3,7,8,1,8,14,7,8,11,1,11,8,1,8,10,3,7,8,1,8,16,3,2,7,8,1,11,8,1,8,10,2,7,8,1,7,8,11,1,6,8,1,1,1,1,6,8,0,1,5,1,6,8,6,1,6,8,12,1,6,10,2,1,6,11,5,1,8,6,1,6,11,5,1,10,2,1,6,8,9,1,3,2,6,8,1,3,1,8,13,1,8,9,2,6,8,1,6,8,1,2,6,11,5,1,9,0,6,9,0,2,6,11,5,1,9,0,6,11,5,1,9,0,2,7,8,1,10,2,3,7,8,1,10,2,10,2,1,10,2,1,6,8,15,4,8,0,3,3,7,8,11,22,5,8,6,8,6,8,6,8,6,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,8,6,11,5,1,8,6,10,2,11,5,1,8,6,11,5,1,8,6,8,7,10,2,10,2,10,2,8,6,8,6,8,12,8,12,1,11,5,1,9,0,1,8,6,8,1,1,1,1,1,1,1,8,0,1,2,1,8,4,1,8,12,1,7,8,11,1,8,7,2,7,8,15,3,3,3,3,8,14,1,8,10,1,6,11,8,1,9,0,1,6,8,11,4,7,8,15,11,8,1,8,10,3,7,8,11,1,7,8,15,1,8,2,1,9,0,2,9,0,5,5,3,3,3,3,11,8,1,8,10,1,6,8,14,3,7,8,15,8,14,7,8,11,1,8,3,1,6,8,16,1,6,5,2,7,8,15,11,8,1,8,10,2,7,8,15,7,8,11,2,6,8,15,3,1,8,15,1,6,9,0,29,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,6,11,5,1,9,0,2,1,1,2,5,7,8,11,1,7,11,5,1,9,0,3,8,9,8,15,5,3,66,97,103,7,66,97,108,97,110,99,101,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,19,83,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,21,85,110,115,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,3,85,114,108,9,86,97,108,105,100,97,116,111,114,17,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,8,97,99,116,105,118,97,116,101,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,6,97,109,111,117,110,116,5,97,115,99,105,105,3,98,97,103,7,98,97,108,97,110,99,101,3,98,99,115,6,98,111,114,114,111,119,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,10,100,101,97,99,116,105,118,97,116,101,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,11,100,101,115,99,114,105,112,116,105,111,110,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,5,101,112,111,99,104,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,10,102,114,111,109,95,97,115,99,105,105,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,20,103,101,116,95,115,116,97,107,105,110,103,95,112,111,111,108,95,114,101,102,2,105,100,9,105,109,97,103,101,95,117,114,108,12,105,115,95,100,117,112,108,105,99,97,116,101,13,105,115,95,101,113,117,97,108,95,115,111,109,101,23,105,115,95,101,113,117,97,108,95,115,111,109,101,95,97,110,100,95,118,97,108,117,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,8,109,101,116,97,100,97,116,97,4,110,97,109,101,11,110,101,116,95,97,100,100,114,101,115,115,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,20,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,102,114,111,109,95,109,101,116,97,100,97,116,97,12,110,101,119,95,109,101,116,97,100,97,116,97,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,20,110,101,120,116,95,101,112,111,99,104,95,103,97,115,95,112,114,105,99,101,22,110,101,120,116,95,101,112,111,99,104,95,110,101,116,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,22,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,32,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,16,110,101,120,116,95,101,112,111,99,104,95,115,116,97,107,101,25,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,7,112,111,111,108,95,105,100,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,16,112,114,105,110,99,105,112,97,108,95,97,109,111,117,110,116,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,21,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,13,114,101,119,97,114,100,95,97,109,111,117,110,116,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,111,109,101,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,12,115,116,97,107,101,95,97,109,111,117,110,116,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,14,115,116,97,107,101,114,95,97,100,100,114,101,115,115,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,6,115,116,114,105,110,103,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,11,115,117,105,95,98,97,108,97,110,99,101,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,111,95,98,121,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,15,117,110,115,116,97,107,105,110,103,95,101,112,111,99,104,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,3,117,114,108,17,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,21,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,95,98,99,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,12,118,111,116,105,110,103,95,112,111,119,101,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,19,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,100,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,3,8,102,0,0,0,0,0,0,0,3,8,208,7,0,0,0,0,0,0,3,8,0,1,0,0,0,0,0,0,3,8,160,134,1,0,0,0,0,0,0,2,22,107,5,86,10,2,53,10,2,146,1,10,2,85,10,2,50,8,6,30,8,6,42,8,12,84,8,12,51,8,6,75,8,6,80,8,6,145,1,8,6,67,11,5,1,10,2,66,11,5,1,10,2,63,11,5,1,10,2,70,11,5,1,10,2,61,11,5,1,8,6,64,11,5,1,8,6,65,11,5,1,8,6,69,11,5,1,8,6,35,8,7,1,2,10,49,8,0,144,1,3,73,8,9,38,3,103,8,15,25,3,68,3,60,3,59,3,35,8,7,2,2,5,78,8,9,138,1,5,102,5,33,3,19,3,3,2,7,78,8,9,138,1,5,102,5,99,3,115,3,81,3,93,3,0,3,0,0,36,68,11,0,12,14,11,1,12,25,11,2,12,29,11,3,12,30,11,4,12,31,11,5,12,32,11,6,12,33,11,7,12,34,11,8,12,35,11,9,12,15,11,10,12,16,11,11,12,17,11,12,12,18,56,0,12,19,56,0,12,20,56,0,12,21,56,0,12,22,56,1,12,23,56,1,12,24,56,1,12,26,56,1,12,27,11,13,12,28,11,14,11,25,11,29,11,30,11,31,11,32,11,33,11,34,11,35,11,15,11,16,11,17,11,18,11,19,11,22,11,20,11,21,11,23,11,24,11,26,11,27,11,28,18,0,2,1,3,0,0,39,137,1,14,9,65,40,7,17,37,4,11,14,10,65,40,7,17,37,12,16,5,13,9,12,16,11,16,4,21,14,11,65,40,7,17,37,12,17,5,23,9,12,17,11,17,4,31,14,12,65,40,7,17,37,12,18,5,33,9,12,18,11,18,4,41,14,5,65,40,7,17,37,12,19,5,43,9,12,19,11,19,4,51,14,6,65,40,7,17,37,12,20,5,53,9,12,20,11,20,4,61,14,7,65,40,7,17,37,12,21,5,63,9,12,21,11,21,4,71,14,8,65,40,7,17,37,12,22,5,73,9,12,22,11,22,4,76,5,80,11,15,1,7,9,39,10,14,7,16,37,4,85,5,89,11,15,1,7,8,39,10,13,7,18,35,4,94,5,98,11,15,1,7,15,39,11,0,11,1,11,2,11,3,11,4,11,5,17,77,17,85,11,6,17,77,17,85,11,7,17,93,11,8,17,93,11,9,17,77,17,85,11,10,17,77,17,85,11,11,17,77,17,85,11,12,17,77,17,85,10,15,17,86,17,0,12,23,14,23,17,73,11,23,11,13,11,14,11,15,17,76,2,2,3,0,0,5,5,11,0,15,0,11,1,17,95,2,3,3,0,0,5,5,11,0,15,0,11,1,17,94,2,4,3,0,0,5,13,10,0,16,1,20,10,0,15,2,21,10,0,16,3,20,11,0,15,4,21,2,5,3,0,0,46,58,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,8,5,14,11,0,1,11,3,1,7,11,39,10,3,46,17,91,6,1,0,0,0,0,0,0,0,22,12,5,10,0,15,0,11,1,11,5,10,3,17,104,12,6,10,0,16,0,17,97,4,34,10,0,15,0,17,102,10,0,16,5,20,10,4,22,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,11,2,11,3,46,17,91,11,4,18,2,56,3,11,6,2,6,3,0,0,24,47,10,3,46,17,91,6,0,0,0,0,0,0,0,0,33,4,7,5,13,11,0,1,11,3,1,7,12,39,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,21,5,27,11,0,1,11,3,1,7,11,39,10,0,15,0,11,1,6,0,0,0,0,0,0,0,0,11,3,17,104,11,2,56,4,10,0,15,0,17,102,10,0,16,5,20,11,4,22,11,0,15,5,21,2,7,3,0,0,55,47,14,1,17,107,12,3,14,1,17,106,12,5,10,0,15,0,11,1,10,2,17,105,12,7,14,7,56,2,12,6,10,6,10,3,23,12,4,10,0,16,5,20,11,6,23,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,10,2,46,17,92,11,5,11,2,46,17,91,11,3,11,4,18,3,56,5,11,7,2,8,3,0,0,5,28,10,2,7,18,35,4,5,5,9,11,0,1,7,15,39,14,1,17,110,20,10,0,16,6,16,7,20,33,4,19,5,23,11,0,1,7,14,39,11,2,11,0,15,1,21,2,9,3,0,0,5,41,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,2,7,18,35,4,14,5,18,11,0,1,7,15,39,14,1,17,110,20,10,0,16,6,16,7,20,33,4,28,5,32,11,0,1,7,14,39,10,2,10,0,15,1,21,11,2,11,0,15,2,21,2,10,3,0,0,5,14,10,1,7,16,37,4,5,5,9,11,0,1,7,8,39,11,1,11,0,15,3,21,2,11,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,1,7,16,37,4,14,5,18,11,0,1,7,8,39,11,1,11,0,15,4,21,2,12,3,0,0,5,14,10,0,16,5,20,14,1,56,2,22,10,0,15,5,21,11,0,15,0,11,1,17,96,2,13,3,0,0,5,16,10,0,15,0,11,1,17,103,10,0,46,17,40,11,0,16,5,20,33,4,13,5,15,7,11,39,2,14,1,0,0,5,4,11,0,16,0,17,97,2,15,1,0,0,5,3,11,0,16,6,2,16,1,0,0,5,5,11,0,16,6,16,7,20,2,17,1,0,0,5,4,11,0,16,6,16,8,2,18,1,0,0,5,4,11,0,16,6,16,9,2,19,1,0,0,5,4,11,0,16,6,16,10,2,20,1,0,0,5,4,11,0,16,6,16,11,2,21,1,0,0,5,4,11,0,16,6,16,12,2,22,1,0,0,5,4,11,0,16,6,16,13,2,23,1,0,0,5,4,11,0,16,6,16,14,2,24,1,0,0,5,4,11,0,16,6,16,15,2,25,1,0,0,5,4,11,0,16,6,16,16,2,26,1,0,0,5,4,11,0,16,6,16,17,2,27,1,0,0,5,4,11,0,16,6,16,18,2,28,1,0,0,5,4,11,0,16,6,16,19,2,29,1,0,0,5,4,11,0,16,6,16,20,2,30,1,0,0,5,4,11,0,16,6,16,21,2,31,1,0,0,5,4,11,0,16,6,16,22,2,32,1,0,0,5,4,11,0,16,6,16,23,2,33,1,0,0,5,4,11,0,16,6,16,24,2,34,1,0,0,5,4,11,0,16,6,16,25,2,35,1,0,0,5,4,11,0,16,6,16,26,2,36,1,0,0,5,4,11,0,16,6,16,27,2,37,1,0,0,5,3,11,0,16,28,2,38,1,0,0,5,4,11,0,16,1,20,2,39,1,0,0,5,5,40,11,0,16,0,17,108,2,40,1,0,0,5,4,11,0,16,0,17,108,2,41,1,0,0,5,3,11,0,17,40,2,42,1,0,0,5,4,11,0,16,29,20,2,43,3,0,0,5,5,11,1,11,0,15,29,21,2,44,1,0,0,5,4,11,0,16,0,17,99,2,45,1,0,0,5,4,11,0,16,0,17,100,2,46,1,0,0,5,4,11,0,16,2,20,2,47,1,0,0,5,4,11,0,16,4,20,2,48,1,0,0,5,5,11,0,16,0,11,1,17,101,2,49,1,0,0,5,4,11,0,16,0,56,6,2,50,1,0,0,66,151,3,10,0,16,6,16,7,20,10,1,16,6,16,7,20,33,4,13,8,12,2,5,23,10,0,16,6,16,8,20,10,1,16,6,16,8,20,33,12,2,11,2,4,28,8,12,13,5,38,10,0,16,6,16,12,20,10,1,16,6,16,12,20,33,12,13,11,13,4,43,8,12,24,5,53,10,0,16,6,16,13,20,10,1,16,6,16,13,20,33,12,24,11,24,4,58,8,12,25,5,68,10,0,16,6,16,16,20,10,1,16,6,16,16,20,33,12,25,11,25,4,73,8,12,26,5,83,10,0,16,6,16,18,20,10,1,16,6,16,18,20,33,12,26,11,26,4,88,8,12,27,5,98,10,0,16,6,16,18,20,10,1,16,6,16,19,20,33,12,27,11,27,4,103,8,12,28,5,113,10,0,16,6,16,19,20,10,1,16,6,16,19,20,33,12,28,11,28,4,118,8,12,29,5,128,1,10,0,16,6,16,19,20,10,1,16,6,16,18,20,33,12,29,11,29,4,133,1,8,12,30,5,141,1,10,0,16,6,16,20,10,1,16,6,16,20,56,7,12,30,11,30,4,146,1,8,12,3,5,154,1,10,0,16,6,16,21,10,1,16,6,16,21,56,7,12,3,11,3,4,159,1,8,12,4,5,167,1,10,0,16,6,16,24,10,1,16,6,16,24,56,8,12,4,11,4,4,172,1,8,12,5,5,180,1,10,0,16,6,16,26,10,1,16,6,16,26,56,8,12,5,11,5,4,185,1,8,12,6,5,193,1,10,0,16,6,16,26,10,1,16,6,16,27,56,8,12,6,11,6,4,198,1,8,12,7,5,206,1,10,0,16,6,16,27,10,1,16,6,16,27,56,8,12,7,11,7,4,211,1,8,12,8,5,219,1,10,0,16,6,16,27,10,1,16,6,16,26,56,8,12,8,11,8,4,224,1,8,12,9,5,232,1,10,0,16,6,16,20,10,1,16,6,16,12,56,9,12,9,11,9,4,237,1,8,12,10,5,245,1,10,0,16,6,16,21,10,1,16,6,16,13,56,9,12,10,11,10,4,250,1,8,12,11,5,130,2,10,0,16,6,16,24,10,1,16,6,16,16,56,10,12,11,11,11,4,135,2,8,12,12,5,143,2,10,0,16,6,16,26,10,1,16,6,16,18,56,10,12,12,11,12,4,148,2,8,12,14,5,156,2,10,0,16,6,16,26,10,1,16,6,16,19,56,10,12,14,11,14,4,161,2,8,12,15,5,169,2,10,0,16,6,16,27,10,1,16,6,16,19,56,10,12,15,11,15,4,174,2,8,12,16,5,182,2,10,0,16,6,16,27,10,1,16,6,16,18,56,10,12,16,11,16,4,187,2,8,12,17,5,195,2,10,1,16,6,16,20,10,0,16,6,16,12,56,9,12,17,11,17,4,200,2,8,12,18,5,208,2,10,1,16,6,16,21,10,0,16,6,16,13,56,9,12,18,11,18,4,213,2,8,12,19,5,221,2,10,1,16,6,16,24,10,0,16,6,16,16,56,10,12,19,11,19,4,226,2,8,12,20,5,234,2,10,1,16,6,16,26,10,0,16,6,16,18,56,10,12,20,11,20,4,239,2,8,12,21,5,247,2,10,1,16,6,16,26,10,0,16,6,16,19,56,10,12,21,11,21,4,252,2,8,12,22,5,132,3,10,1,16,6,16,27,10,0,16,6,16,19,56,10,12,22,11,22,4,141,3,11,0,1,11,1,1,8,12,23,5,149,3,11,1,16,6,16,27,11,0,16,6,16,18,56,10,12,23,11,23,2,51,0,0,0,15,17,10,0,56,11,4,10,11,1,1,11,0,1,9,12,2,5,15,11,0,56,12,11,1,33,12,2,11,2,2,52,0,0,0,68,26,10,0,56,11,4,6,8,12,2,5,9,10,1,56,11,12,2,11,2,4,18,11,1,1,11,0,1,9,12,3,5,24,11,0,56,12,11,1,56,12,33,12,3,11,3,2,53,3,0,0,17,25,10,1,46,17,92,12,2,10,2,10,0,16,6,16,7,20,33,4,12,5,18,11,0,1,11,1,1,7,13,39,11,2,11,1,17,109,11,0,15,28,21,2,54,3,0,0,5,18,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,11,0,15,6,15,8,21,2,55,3,0,0,5,18,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,11,0,15,6,15,9,21,2,56,3,0,0,5,17,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,93,11,0,15,6,15,10,21,2,57,3,0,0,5,17,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,93,11,0,15,6,15,11,21,2,58,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,20,21,11,0,16,6,17,73,2,59,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,12,21,11,0,16,6,17,73,2,60,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,21,21,11,0,16,6,17,73,2,61,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,13,21,11,0,16,6,17,73,2,62,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,22,21,11,0,16,6,17,73,2,63,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,14,21,11,0,16,6,17,73,2,64,3,0,0,5,22,14,1,65,40,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,77,17,85,56,13,10,0,15,6,15,23,21,11,0,16,6,17,73,2,65,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,40,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,77,17,85,10,0,15,6,15,15,21,11,0,16,6,17,73,2,66,3,0,0,5,16,11,1,56,14,10,0,15,6,15,24,21,11,2,56,14,10,0,15,6,15,25,21,11,0,16,6,17,73,2,67,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,16,21,11,2,10,0,15,6,15,17,21,11,0,16,6,17,73,2,68,3,0,0,5,10,11,1,56,14,10,0,15,6,15,26,21,11,0,16,6,17,73,2,69,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,18,21,11,0,16,6,17,73,2,70,3,0,0,5,10,11,1,56,14,10,0,15,6,15,27,21,11,0,16,6,17,73,2,71,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,19,21,11,0,16,6,17,73,2,72,3,0,0,5,143,1,10,0,46,17,29,56,15,4,18,10,0,15,6,15,20,56,16,10,0,15,6,15,12,21,56,1,10,0,15,6,15,20,21,10,0,46,17,30,56,15,4,36,10,0,15,6,15,21,56,16,10,0,15,6,15,13,21,56,1,10,0,15,6,15,21,21,10,0,46,17,31,56,15,4,54,10,0,15,6,15,22,56,16,10,0,15,6,15,14,21,56,1,10,0,15,6,15,22,21,10,0,46,17,32,56,15,4,72,10,0,15,6,15,23,56,16,10,0,15,6,15,15,21,56,1,10,0,15,6,15,23,21,10,0,46,17,33,56,17,4,103,10,0,15,6,15,24,56,18,10,0,15,6,15,16,21,56,0,10,0,15,6,15,24,21,10,0,15,6,15,25,56,18,10,0,15,6,15,17,21,56,0,10,0,15,6,15,25,21,10,0,46,17,35,56,17,4,121,10,0,15,6,15,26,56,18,10,0,15,6,15,18,21,56,0,10,0,15,6,15,26,21,10,0,46,17,36,56,17,4,140,1,10,0,15,6,15,27,56,18,10,0,15,6,15,19,21,56,0,11,0,15,6,15,27,21,5,142,1,11,0,1,2,73,1,0,0,5,4,11,0,56,19,17,74,2,74,1,2,0,75,3,0,0,5,3,11,0,16,0,2,76,0,0,0,71,24,14,0,16,7,20,12,6,10,3,17,98,12,5,11,6,10,3,17,109,12,4,11,0,6,0,0,0,0,0,0,0,0,11,4,10,1,11,5,10,2,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,17,86,18,1,2,1,4,1,7,1,3,1,8,1,5,1,6,1,0,0,0,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,1,0,4,0,2,0,3,0,17,0,18,0,19,0,20,0,13,0,14,0,15,0,16,1,2,1,1,0,39,0,109,0,140,1,0,141,1,0,144,1,0],"validator_cap":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,20,3,28,42,4,70,4,5,74,54,7,128,1,226,2,8,226,3,64,6,162,4,34,10,196,4,13,12,209,4,112,13,193,5,4,15,197,5,6,0,18,1,10,1,14,1,15,0,3,12,0,0,4,2,0,1,0,7,0,1,2,4,0,3,1,2,0,0,16,0,1,0,0,20,2,1,0,0,9,3,4,0,0,8,0,5,0,1,6,13,4,1,8,1,7,10,11,0,2,11,14,6,1,12,3,12,8,9,0,4,12,6,12,1,6,8,0,1,6,5,1,6,8,1,2,5,7,8,4,1,8,2,1,8,1,0,4,1,8,0,8,2,5,1,6,8,4,1,5,1,7,8,4,1,8,3,1,8,0,1,6,9,0,2,9,0,5,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,28,97,117,116,104,111,114,105,122,101,114,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,6,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,3,5,5,1,2,1,5,5,0,3,0,0,6,3,11,0,16,0,2,1,3,0,0,6,3,11,0,16,1,2,2,3,0,0,7,35,10,1,46,17,7,12,5,10,5,7,0,33,4,11,8,12,2,5,15,11,5,10,0,33,12,2,11,2,4,18,5,22,11,1,1,6,0,0,0,0,0,0,0,0,39,11,1,17,5,10,0,18,0,12,3,14,3,56,0,12,4,11,3,11,0,56,1,11,4,2,3,3,0,0,6,5,11,0,16,0,20,18,1,2,0,1,1,0,0,13,0,17,0,19,0],"validator_set":[161,28,235,11,6,0,0,0,12,1,0,54,2,54,116,3,170,1,173,6,4,215,7,137,1,5,224,8,136,10,7,232,18,175,24,8,151,43,96,6,247,43,195,1,10,186,45,141,1,12,199,46,159,36,13,230,82,16,15,246,82,5,0,166,1,1,107,1,174,1,2,32,2,33,2,59,2,105,2,118,2,147,1,2,151,1,2,152,1,2,158,1,2,159,1,2,172,1,2,173,1,0,143,1,0,162,1,0,165,1,0,170,1,0,177,1,0,20,4,0,0,15,3,0,0,16,3,0,0,17,3,0,0,18,3,0,1,4,7,1,0,0,3,0,12,0,4,1,4,1,0,1,6,3,7,0,7,2,6,1,2,0,7,6,6,1,2,0,8,7,2,0,9,10,12,2,7,1,4,1,10,11,4,1,4,1,12,12,2,0,13,22,7,2,1,0,0,0,14,23,7,1,3,0,15,5,7,0,15,8,12,0,15,9,12,0,16,14,4,0,17,13,12,0,17,19,2,0,18,21,4,0,0,100,0,1,0,0,130,1,2,3,0,0,132,1,4,3,0,0,129,1,5,3,0,0,30,6,3,0,0,131,1,4,3,0,0,128,1,7,8,0,0,134,1,9,10,0,0,133,1,11,3,0,0,29,12,3,0,0,161,1,13,3,0,0,54,14,3,0,0,49,15,16,0,0,155,1,15,16,0,0,169,1,17,16,0,0,167,1,17,16,0,0,168,1,17,18,0,0,145,1,15,19,0,0,110,20,21,0,0,103,15,16,0,0,85,17,22,0,0,88,6,22,0,0,87,23,22,0,0,45,23,16,0,0,89,6,22,0,0,44,24,16,0,0,71,25,26,0,0,63,27,28,0,0,64,29,28,0,0,75,30,31,0,0,76,32,26,0,0,68,33,26,0,0,79,34,26,0,0,77,35,26,0,0,78,35,26,0,0,80,27,36,0,0,69,37,36,0,0,70,17,36,0,0,73,17,36,0,0,176,1,38,39,0,0,119,40,3,0,0,122,41,3,0,0,37,42,3,0,0,121,43,3,0,0,139,1,44,3,0,0,120,45,3,0,0,36,46,16,0,0,28,47,3,0,0,40,48,49,0,0,41,50,51,0,0,42,52,53,0,0,39,54,53,0,0,53,55,3,0,0,56,56,3,0,0,150,1,30,16,0,0,26,15,46,0,0,94,17,22,0,0,91,57,22,0,0,25,15,51,0,1,51,118,85,1,0,1,62,84,85,1,0,1,93,83,22,1,0,1,104,3,118,1,0,1,138,1,85,118,1,0,2,43,86,22,1,0,2,90,132,1,22,1,0,2,127,102,85,1,0,3,100,60,70,0,4,52,155,1,3,1,0,4,96,156,1,16,1,0,4,140,1,154,1,155,1,1,0,4,171,1,88,16,1,0,5,55,85,3,1,3,6,81,117,18,1,8,7,100,108,109,1,2,7,101,106,107,1,2,7,117,110,106,1,2,9,27,64,3,2,7,4,9,34,72,92,2,7,4,9,35,77,93,2,7,4,9,43,72,22,2,7,4,9,100,60,61,2,7,4,9,127,77,78,2,7,4,10,34,116,117,1,4,10,35,121,122,1,4,10,57,60,65,1,4,10,90,113,22,1,4,10,98,113,16,1,4,10,116,142,1,85,1,4,10,124,81,3,1,4,11,123,157,1,3,1,12,12,58,76,16,0,12,135,1,76,63,0,13,43,98,22,2,1,0,13,57,3,69,2,1,0,13,67,98,92,2,1,0,13,72,99,93,2,1,0,13,83,101,3,2,1,0,13,90,137,1,22,2,1,0,13,97,137,1,138,1,2,1,0,13,115,149,1,100,2,1,0,13,127,99,100,2,1,0,13,137,1,137,1,16,2,1,0,14,43,139,1,22,1,3,14,84,150,1,138,1,1,3,14,90,141,1,22,1,3,14,127,140,1,3,1,3,15,60,112,21,0,15,111,91,18,0,16,24,79,3,0,16,28,26,3,0,16,38,36,16,0,16,47,79,3,0,16,48,158,1,3,0,16,54,26,3,0,16,65,36,16,0,16,74,36,112,0,16,86,115,22,0,16,92,36,22,0,16,106,36,130,1,0,16,114,160,1,161,1,0,16,120,145,1,3,0,16,128,1,89,8,0,16,133,1,79,3,0,16,134,1,95,10,0,16,142,1,36,16,0,16,144,1,36,18,0,16,148,1,36,63,0,16,156,1,36,16,0,16,177,1,36,16,0,17,102,128,1,39,0,17,160,1,128,1,124,0,17,175,1,123,124,0,18,46,73,74,0,18,50,74,62,0,18,99,94,26,0,19,125,3,16,0,19,136,1,47,3,0,19,157,1,3,16,0,81,59,77,59,85,62,81,66,81,67,94,68,80,67,77,67,82,67,82,59,77,66,89,62,61,16,60,16,64,16,71,87,80,59,78,59,80,66,79,66,93,68,101,68,96,68,97,68,66,62,75,16,74,16,76,16,87,62,83,62,79,67,63,16,62,16,59,16,84,62,73,129,1,65,16,72,134,1,93,136,1,101,136,1,99,136,1,96,136,1,103,63,106,63,105,63,86,62,88,62,72,143,1,94,103,97,103,98,136,1,100,136,1,104,63,102,103,93,103,95,103,70,87,69,87,90,8,68,87,95,136,1,64,63,72,162,1,2,10,8,20,7,8,14,1,8,0,3,7,8,0,8,20,7,8,14,0,2,7,8,0,7,8,14,3,7,8,0,3,7,8,14,2,6,8,0,6,8,20,4,7,8,0,5,11,7,1,8,11,7,8,14,1,8,18,3,7,8,0,8,18,7,8,14,1,11,7,1,8,11,3,7,8,0,3,6,8,14,9,7,8,0,7,11,7,1,8,11,7,11,7,1,8,11,7,11,15,2,5,11,16,1,5,3,3,3,3,7,8,14,6,7,8,0,3,3,3,7,11,15,2,5,11,16,1,5,7,8,14,1,7,8,0,1,6,8,0,1,3,2,6,8,0,5,1,8,8,1,6,11,12,2,8,8,5,2,7,8,0,6,8,8,1,6,11,12,2,3,8,17,1,1,2,6,10,8,20,6,8,20,2,6,11,13,1,8,20,6,8,20,2,7,8,0,5,1,7,8,20,2,6,10,8,20,5,1,11,5,1,3,2,6,11,13,1,8,20,5,2,6,10,8,20,6,10,5,1,10,3,2,7,10,8,20,5,3,7,8,0,5,1,3,7,8,0,6,8,22,1,2,7,8,0,6,8,14,1,6,8,20,3,7,8,0,5,2,3,7,8,0,6,8,21,2,1,8,22,3,7,8,0,7,11,15,2,5,11,16,1,5,7,8,14,5,7,8,0,8,20,7,11,15,2,5,11,16,1,5,1,7,8,14,2,7,11,15,2,5,11,16,1,5,5,2,7,8,0,3,1,7,10,3,2,7,10,8,20,7,8,14,1,6,10,8,20,1,7,10,8,20,4,10,3,3,6,10,3,6,10,3,4,3,11,15,2,3,3,3,11,15,2,3,3,2,6,8,0,11,15,2,5,11,16,1,5,1,10,5,4,6,10,8,20,3,3,3,2,10,3,10,3,9,6,10,8,20,3,3,10,3,10,3,3,11,15,2,3,3,3,11,15,2,3,3,6,7,10,8,20,6,10,3,6,10,3,7,11,7,1,8,11,7,11,7,1,8,11,7,8,14,6,3,6,10,8,20,6,10,3,6,10,3,6,11,15,2,5,11,16,1,5,6,10,5,2,6,8,0,8,8,6,3,3,11,12,2,8,8,5,3,6,8,20,8,0,2,8,8,5,1,7,8,14,1,11,12,2,9,0,9,1,1,8,20,1,5,3,7,11,12,2,9,0,9,1,9,0,9,1,1,11,13,1,9,0,2,8,8,8,23,2,5,8,23,2,5,3,1,11,15,2,9,0,9,1,1,8,6,4,6,8,20,6,8,20,1,5,2,6,11,12,2,9,0,9,1,9,0,2,8,20,7,8,14,1,8,23,3,8,8,8,20,5,1,6,8,14,2,7,11,12,2,9,0,9,1,9,0,1,9,1,2,7,8,20,3,5,6,8,20,6,8,20,1,8,20,5,2,7,11,13,1,9,0,9,0,3,5,3,11,5,1,3,1,6,11,5,1,9,0,1,7,11,5,1,9,0,1,9,0,2,6,10,9,0,6,9,0,1,8,11,1,6,11,7,1,9,0,4,7,8,20,11,7,1,8,11,5,7,8,14,3,7,8,20,8,8,5,1,6,8,18,1,6,9,1,1,7,9,1,1,7,8,23,3,7,8,20,8,18,7,8,14,14,11,15,2,5,11,16,1,5,6,10,5,10,3,10,3,11,15,2,3,3,11,15,2,3,3,3,10,5,3,3,3,3,10,3,10,3,8,3,3,7,3,3,8,20,8,20,5,6,8,20,2,6,11,15,2,9,0,9,1,6,9,0,2,7,11,15,2,9,0,9,1,6,9,0,2,9,0,9,1,3,7,11,15,2,9,0,9,1,9,0,9,1,2,7,10,9,0,3,2,3,3,10,10,11,9,1,3,3,3,11,10,1,3,3,3,3,6,8,20,3,6,10,8,20,1,11,9,1,3,2,3,9,0,1,11,9,1,9,0,1,10,11,9,1,9,0,1,11,10,1,9,0,1,7,11,10,1,9,0,2,6,8,20,5,1,6,8,19,1,6,11,13,1,9,0,3,3,3,3,2,6,8,20,6,8,20,2,6,11,13,1,9,0,3,1,6,9,0,1,11,5,1,9,0,5,5,3,11,5,1,3,3,10,3,4,3,3,11,5,1,3,11,5,1,3,2,7,11,13,1,9,0,3,1,7,9,0,1,6,8,22,1,6,5,2,3,11,5,1,3,6,1,1,3,3,11,5,1,3,11,5,1,3,5,5,6,8,20,8,8,5,6,8,20,1,6,8,21,1,8,21,1,6,8,8,2,3,8,20,1,6,10,9,0,3,3,5,8,8,1,8,4,7,6,5,6,5,3,3,6,5,10,5,7,11,16,1,5,2,5,11,16,1,5,1,6,11,15,2,9,0,9,1,1,10,9,0,2,6,11,16,1,9,0,6,9,0,2,7,11,16,1,9,0,6,9,0,1,6,11,16,1,9,0,1,7,11,13,1,9,0,1,8,3,6,3,3,3,3,3,3,2,7,8,20,7,8,14,4,3,3,3,6,8,20,7,11,15,2,3,3,11,15,2,3,3,4,4,3,3,3,5,10,5,6,10,8,20,11,16,1,5,10,5,5,1,7,11,15,2,9,0,9,1,1,11,16,1,9,0,6,3,3,4,10,3,10,3,3,17,3,3,3,10,3,3,10,3,3,4,3,3,3,3,3,3,3,3,4,8,3,3,11,7,1,8,11,3,7,8,20,5,4,11,7,1,8,11,2,7,11,7,1,9,0,3,1,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,2,9,0,5,2,7,8,20,11,7,1,8,11,8,10,5,3,3,3,3,10,5,6,8,20,5,2,6,8,20,3,1,8,17,1,8,2,5,3,3,10,5,5,6,10,8,20,3,66,97,103,7,66,97,108,97,110,99,101,5,69,110,116,114,121,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,13,80,114,105,111,114,105,116,121,81,117,101,117,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,23,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,25,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,86,50,18,86,97,108,105,100,97,116,111,114,74,111,105,110,69,118,101,110,116,19,86,97,108,105,100,97,116,111,114,76,101,97,118,101,69,118,101,110,116,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,6,86,101,99,77,97,112,6,86,101,99,83,101,116,8,97,99,116,105,118,97,116,101,26,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,101,115,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,3,97,100,100,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,18,97,116,95,114,105,115,107,95,118,97,108,105,100,97,116,111,114,115,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,22,99,97,108,99,117,108,97,116,101,95,116,111,116,97,108,95,115,116,97,107,101,115,38,99,108,101,97,110,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,95,108,101,97,118,105,110,103,95,118,97,108,105,100,97,116,111,114,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,36,99,111,109,112,117,116,101,95,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,26,99,111,109,112,117,116,101,95,114,101,119,97,114,100,95,97,100,106,117,115,116,109,101,110,116,115,26,99,111,109,112,117,116,101,95,115,108,97,115,104,101,100,95,118,97,108,105,100,97,116,111,114,115,38,99,111,109,112,117,116,101,95,117,110,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,8,99,111,110,116,97,105,110,115,25,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,116,97,98,108,101,118,101,99,20,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,118,101,99,9,99,114,101,97,116,101,95,118,49,10,100,101,97,99,116,105,118,97,116,101,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,17,100,105,115,116,114,105,98,117,116,101,95,114,101,119,97,114,100,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,27,101,109,105,116,95,118,97,108,105,100,97,116,111,114,95,101,112,111,99,104,95,101,118,101,110,116,115,5,101,109,112,116,121,5,101,112,111,99,104,5,101,118,101,110,116,14,101,120,99,104,97,110,103,101,95,114,97,116,101,115,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,14,102,105,110,100,95,118,97,108,105,100,97,116,111,114,29,102,105,110,100,95,118,97,108,105,100,97,116,111,114,95,102,114,111,109,95,116,97,98,108,101,95,118,101,99,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,3,103,101,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,24,103,101,116,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,37,103,101,116,95,99,97,110,100,105,100,97,116,101,95,111,114,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,7,103,101,116,95,109,117,116,25,103,101,116,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,95,114,101,102,20,103,101,116,95,115,116,97,107,105,110,103,95,112,111,111,108,95,114,101,102,21,103,101,116,95,118,97,108,105,100,97,116,111,114,95,105,110,100,105,99,101,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,114,101,102,2,105,100,19,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,12,105,115,95,100,117,112,108,105,99,97,116,101,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,34,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,35,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,21,105,115,95,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,22,105,115,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,12,105,115,95,118,111,108,117,110,116,97,114,121,4,106,111,105,110,4,107,101,121,115,6,108,101,110,103,116,104,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,25,112,101,110,100,105,110,103,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,16,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,19,112,111,111,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,115,7,112,111,111,108,95,105,100,19,112,111,111,108,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,24,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,3,112,111,112,8,112,111,112,95,98,97,99,107,7,112,111,112,95,109,97,120,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,24,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,26,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,115,27,112,114,111,99,101,115,115,95,118,97,108,105,100,97,116,111,114,95,100,101,112,97,114,116,117,114,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,9,112,117,115,104,95,98,97,99,107,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,26,114,101,102,101,114,101,110,99,101,95,103,97,115,95,115,117,114,118,101,121,95,113,117,111,116,101,6,114,101,109,111,118,101,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,6,115,101,110,100,101,114,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,105,122,101,4,115,111,109,101,17,115,111,114,116,95,114,101,109,111,118,97,108,95,108,105,115,116,5,115,112,108,105,116,5,115,116,97,107,101,12,115,116,97,107,101,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,27,115,116,111,114,97,103,101,95,102,117,110,100,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,29,115,117,109,95,118,111,116,105,110,103,95,112,111,119,101,114,95,98,121,95,97,100,100,114,101,115,115,101,115,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,26,116,97,108,108,121,105,110,103,95,114,117,108,101,95,103,108,111,98,97,108,95,115,99,111,114,101,23,116,97,108,108,121,105,110,103,95,114,117,108,101,95,114,101,112,111,114,116,101,114,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,39,117,112,100,97,116,101,95,97,110,100,95,112,114,111,99,101,115,115,95,108,111,119,95,115,116,97,107,101,95,100,101,112,97,114,116,117,114,101,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,20,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,10,3,1,0,10,5,1,0,0,2,9,155,1,3,26,10,8,20,108,11,13,1,8,20,109,10,3,145,1,11,12,2,8,8,5,82,11,12,2,8,8,8,23,164,1,11,12,2,5,8,23,31,11,15,2,5,3,61,8,6,1,2,10,58,3,163,1,5,126,3,141,1,3,38,3,112,3,146,1,3,113,8,17,154,1,10,5,153,1,3,2,2,11,58,3,163,1,5,126,3,141,1,3,177,1,3,38,3,112,3,146,1,3,113,8,17,154,1,10,5,153,1,3,3,2,3,58,3,163,1,5,144,1,8,8,4,2,4,58,3,163,1,5,144,1,8,8,95,1,0,3,0,0,58,51,14,0,17,46,12,5,10,1,56,0,12,4,14,0,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,16,14,0,10,2,66,62,12,6,13,4,10,6,17,126,11,6,17,127,56,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,11,5,11,0,10,1,56,2,64,16,0,0,0,0,0,0,0,0,11,4,10,1,56,3,10,1,56,4,56,5,11,1,17,67,18,0,12,7,13,7,15,0,17,137,1,11,7,2,1,3,0,0,71,69,10,0,14,1,12,3,46,11,3,17,21,32,4,17,10,0,14,1,12,4,46,11,4,17,24,32,12,5,5,19,9,12,5,11,5,4,22,5,28,11,0,1,11,2,1,7,7,39,14,1,17,127,12,6,10,0,16,1,10,6,56,6,32,4,38,5,44,11,0,1,11,2,1,7,11,39,14,1,17,118,4,48,5,54,11,0,1,11,2,1,7,12,39,10,0,15,2,14,1,17,126,11,6,56,1,11,0,15,1,14,1,17,127,11,1,11,2,17,133,1,56,7,2,2,3,0,0,75,53,10,1,46,17,92,12,4,10,0,16,1,10,4,56,6,4,10,5,16,11,0,1,11,1,1,7,13,39,10,0,15,1,11,4,56,8,17,134,1,12,3,14,3,17,118,4,26,5,32,11,0,1,11,1,1,7,12,39,14,3,17,126,12,2,10,0,15,2,10,2,56,9,1,13,3,10,1,46,17,91,17,112,11,0,15,3,11,2,11,3,11,1,17,133,1,56,10,2,3,3,0,0,80,69,11,2,46,17,92,12,7,10,0,16,1,10,7,56,6,4,10,5,14,11,0,1,7,13,39,10,0,15,1,11,7,56,8,17,134,1,12,6,10,0,14,6,12,3,46,11,3,17,21,32,4,37,10,0,14,6,12,4,46,11,4,17,24,32,12,5,5,39,9,12,5,11,5,4,42,5,46,11,0,1,7,7,39,14,6,17,118,4,50,5,54,11,0,1,7,12,39,14,6,17,128,1,11,1,38,4,60,5,64,11,0,1,7,10,39,11,0,15,4,11,6,56,11,2,4,3,0,0,3,16,10,0,16,0,10,1,17,23,11,0,16,4,11,1,17,25,22,6,1,0,0,0,0,0,0,0,33,4,13,5,15,7,7,39,2,5,3,0,0,82,36,11,1,46,17,92,12,2,10,0,16,0,11,2,17,27,12,4,14,4,56,12,4,13,5,17,11,0,1,7,9,39,13,4,56,13,12,3,10,0,16,5,14,3,56,14,32,4,27,5,31,11,0,1,7,16,39,11,0,15,5,11,3,68,16,2,6,3,0,0,3,22,14,2,56,15,7,4,38,4,6,5,12,11,0,1,11,3,1,7,15,39,11,0,11,1,17,26,11,2,10,3,46,17,92,11,3,17,122,2,7,3,0,0,90,43,14,1,17,108,12,4,10,0,16,2,10,4,56,16,4,20,10,0,16,2,14,1,17,108,56,17,20,12,5,11,0,11,5,17,26,12,3,5,38,10,0,16,3,10,4,56,18,4,26,5,32,11,0,1,11,2,1,7,8,39,11,0,15,3,11,4,56,19,17,135,1,12,3,11,3,11,1,11,2,17,124,2,8,3,0,0,63,10,11,2,17,92,12,3,11,0,15,0,11,3,17,30,11,1,17,123,2,9,3,0,0,96,110,10,8,46,17,91,6,1,0,0,0,0,0,0,0,22,12,15,17,138,1,12,20,10,0,16,0,10,20,10,1,46,56,15,10,2,46,56,15,17,50,12,22,12,21,10,0,10,3,20,12,9,46,11,9,17,49,12,16,10,0,16,0,14,16,17,54,12,17,10,0,16,0,14,16,17,29,11,4,14,21,14,22,17,48,12,14,12,19,12,13,12,18,10,0,16,0,11,20,11,17,11,21,11,22,11,18,11,13,11,19,11,14,17,51,12,12,12,11,10,0,15,0,14,11,14,12,11,1,11,2,10,8,17,52,10,0,15,0,17,47,10,0,15,0,10,8,17,45,10,15,10,0,16,0,14,11,14,12,10,3,14,16,12,10,46,11,10,17,53,10,0,11,15,17,43,10,0,10,3,10,8,17,40,10,0,11,5,11,6,11,7,11,3,11,8,17,10,10,0,16,0,17,46,10,0,15,6,21,10,0,15,0,17,137,1,11,0,17,11,2,10,0,0,0,97,106,10,0,16,0,65,62,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,99,5,9,11,7,6,1,0,0,0,0,0,0,0,23,12,7,10,0,16,0,10,7,66,62,12,13,10,13,17,127,12,12,11,13,17,128,1,12,9,10,9,10,1,38,4,40,10,0,16,7,14,12,56,20,4,39,10,0,15,7,14,12,56,21,1,1,5,98,11,9,10,2,38,4,87,10,0,16,7,14,12,56,20,4,64,10,0,15,7,14,12,56,22,12,8,10,8,20,6,1,0,0,0,0,0,0,0,22,10,8,21,11,8,20,12,6,5,71,10,0,15,7,11,12,6,1,0,0,0,0,0,0,0,56,23,6,1,0,0,0,0,0,0,0,12,6,11,6,10,3,36,4,86,10,0,15,0,10,7,56,24,12,10,10,0,11,10,10,4,9,10,5,17,41,5,98,10,0,15,0,10,7,56,24,12,11,10,0,11,11,10,4,9,10,5,17,41,5,4,11,4,1,11,0,1,11,5,1,2,11,0,0,0,103,24,10,0,16,0,65,62,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,21,5,11,10,0,15,0,10,1,67,62,17,114,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,12,1,0,0,104,60,11,0,16,0,12,10,10,10,65,62,12,3,64,105,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,15,10,10,10,2,66,62,12,8,13,1,10,8,17,115,11,8,17,129,1,56,25,68,105,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,10,11,10,1,11,1,56,26,12,4,6,0,0,0,0,0,0,0,0,12,6,17,138,1,17,136,1,23,12,7,6,0,0,0,0,0,0,0,0,12,5,10,6,10,7,35,4,58,5,49,13,4,56,27,12,9,12,5,11,6,11,9,22,12,6,5,44,11,5,2,13,1,0,0,3,4,11,0,16,6,20,2,14,1,0,0,3,6,11,0,16,0,11,1,17,35,17,128,1,2,15,1,0,0,3,6,11,0,16,0,11,1,17,35,17,125,2,16,1,0,0,3,6,11,0,16,0,11,1,17,35,17,126,2,17,1,0,0,3,3,11,0,16,2,2,18,3,0,0,111,31,10,0,16,2,10,1,20,56,16,4,19,10,0,16,2,11,1,20,56,17,20,12,3,11,0,11,3,7,2,17,36,12,2,5,27,11,0,15,3,11,1,20,56,19,17,135,1,46,12,2,11,2,17,116,17,107,2,19,3,0,0,3,12,10,0,16,0,65,62,10,0,16,5,65,16,23,11,0,16,4,56,28,22,2,20,3,0,0,28,8,11,0,16,0,11,1,17,27,12,2,14,2,56,12,2,21,0,0,0,3,5,11,0,16,0,11,1,17,22,2,22,3,0,0,3,6,11,0,11,1,17,23,6,0,0,0,0,0,0,0,0,36,2,23,0,0,0,114,33,10,0,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,66,62,10,1,17,117,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,24,0,0,0,3,7,11,0,16,4,11,1,17,25,6,0,0,0,0,0,0,0,0,36,2,25,0,0,0,114,33,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,56,29,10,1,17,117,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,26,0,0,0,3,16,10,0,16,1,10,1,56,6,4,11,11,0,15,1,11,1,56,30,17,135,1,2,11,0,15,0,11,1,17,30,2,27,0,0,0,103,31,10,0,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,66,62,17,127,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,28,0,0,0,103,31,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,56,29,17,127,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,29,0,0,0,119,46,10,1,65,63,12,5,6,0,0,0,0,0,0,0,0,12,3,7,20,12,6,10,3,10,5,35,4,40,5,12,10,1,10,3,66,63,20,12,2,10,0,11,2,17,27,12,4,14,4,56,12,4,25,5,31,11,0,1,11,1,1,7,9,39,13,6,11,4,56,33,68,16,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,0,1,11,1,1,11,6,2,30,3,0,0,82,22,10,0,11,1,12,2,46,11,2,17,27,12,4,14,4,56,12,4,11,5,15,11,0,1,7,9,39,13,4,56,13,12,3,11,0,11,3,67,62,2,31,0,0,0,120,45,10,0,16,0,10,1,17,27,12,5,14,5,56,12,4,16,13,5,56,13,12,3,11,0,15,0,11,3,67,62,2,10,0,16,4,10,1,17,28,12,6,14,6,56,12,4,32,13,6,56,13,12,4,11,0,15,4,11,4,56,34,2,11,2,4,35,5,39,11,0,1,7,14,39,11,0,15,1,11,1,56,30,17,135,1,2,32,3,0,0,3,7,11,0,11,1,17,132,1,20,11,2,17,31,2,33,3,0,0,63,8,11,1,17,92,12,2,11,0,11,2,9,17,31,2,34,3,0,0,63,8,11,1,17,92,12,2,11,0,11,2,8,17,31,2,35,0,0,0,125,19,10,0,11,1,17,27,12,3,14,3,56,12,4,8,5,12,11,0,1,7,9,39,13,3,56,13,12,2,11,0,11,2,66,62,2,36,3,0,0,126,57,10,0,16,0,10,1,17,27,12,7,14,7,56,12,4,11,8,12,3,5,15,10,2,7,0,33,12,3,11,3,4,25,13,7,56,13,12,5,11,0,16,0,11,5,66,62,2,10,0,16,4,10,1,17,28,12,8,14,8,56,12,4,36,8,12,4,5,40,11,2,7,1,33,12,4,11,4,4,50,13,8,56,13,12,6,11,0,16,4,11,6,56,29,2,11,0,15,1,11,1,56,30,17,135,1,46,2,37,1,0,0,125,21,10,0,16,0,11,1,17,27,12,3,14,3,56,12,4,9,5,13,11,0,1,7,9,39,13,3,56,13,12,2,11,0,16,0,11,2,66,62,2,38,1,0,0,125,21,10,0,16,4,11,1,17,28,12,3,14,3,56,12,4,9,5,13,11,0,1,7,17,39,13,3,56,13,12,2,11,0,16,4,11,2,56,29,2,39,3,0,0,127,39,10,1,17,131,1,20,12,6,10,2,7,0,33,4,16,11,0,11,6,12,3,46,11,3,17,37,12,4,5,21,11,0,11,6,11,2,17,36,12,4,11,4,12,7,10,1,56,35,12,5,11,7,17,119,14,5,33,4,32,5,36,11,1,1,7,19,39,11,1,17,130,1,2,40,0,0,0,131,1,32,10,0,15,5,17,44,10,0,16,5,56,36,32,4,25,5,9,10,0,15,5,69,16,12,3,10,0,15,0,11,3,56,24,12,4,10,0,11,4,10,1,8,10,2,17,41,5,3,11,1,1,11,0,1,11,2,1,2,41,0,0,0,133,1,58,10,4,46,17,91,6,1,0,0,0,0,0,0,0,22,12,5,14,1,17,127,12,6,14,1,17,126,12,7,10,0,15,2,10,7,56,9,1,10,0,16,7,14,6,56,20,4,28,10,0,15,7,14,6,56,21,1,1,10,0,16,6,20,14,1,17,128,1,23,10,0,15,6,21,11,2,10,6,17,42,10,5,11,6,14,1,17,126,11,3,18,4,56,37,13,1,11,5,17,112,11,0,15,3,11,7,11,1,11,4,17,133,1,56,10,2,42,0,0,0,135,1,69,10,0,14,1,12,2,46,11,2,56,38,4,12,10,0,14,1,56,39,1,1,10,0,46,56,40,12,7,14,7,65,63,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,66,5,26,14,7,10,4,66,63,12,6,10,0,10,6,56,41,12,8,10,8,14,1,12,3,46,11,3,56,42,4,57,10,8,14,1,56,43,11,8,46,56,44,4,54,10,0,11,6,56,39,1,1,5,56,11,6,1,5,61,11,8,1,11,6,1,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,21,11,0,1,2,43,0,0,0,62,28,10,0,16,4,56,45,32,4,25,5,6,10,0,15,4,56,46,12,2,13,2,10,1,17,109,10,1,14,2,17,127,14,2,17,126,18,3,56,47,10,0,15,0,11,2,68,62,5,0,11,0,1,2,44,0,0,0,144,1,57,10,0,46,65,16,12,6,6,1,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,54,5,11,10,0,10,4,12,1,46,11,1,66,16,20,12,3,10,4,12,5,10,5,6,0,0,0,0,0,0,0,0,36,4,49,5,26,11,5,6,1,0,0,0,0,0,0,0,23,12,5,10,0,10,5,12,2,46,11,2,66,16,20,10,3,36,4,41,5,42,5,49,10,0,10,5,10,5,6,1,0,0,0,0,0,0,0,22,71,16,5,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,1,2,45,0,0,0,103,26,10,0,46,65,62,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,21,5,11,10,0,10,2,67,62,10,1,17,121,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,11,1,1,2,46,0,0,0,146,1,30,6,0,0,0,0,0,0,0,0,12,3,10,0,65,62,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,26,5,12,10,0,10,1,66,62,12,4,11,3,11,4,17,128,1,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,47,0,0,0,103,23,10,0,46,65,62,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,20,5,11,10,0,10,1,67,62,17,110,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,48,0,0,0,147,1,69,6,0,0,0,0,0,0,0,0,12,8,56,48,12,4,6,0,0,0,0,0,0,0,0,12,9,56,48,12,5,13,0,46,56,36,32,4,60,5,14,13,0,69,16,12,10,10,2,10,10,66,16,20,53,10,1,53,24,7,3,26,12,6,13,4,10,10,10,6,52,56,49,11,8,11,6,52,22,12,8,10,3,10,10,66,16,20,53,10,1,53,24,7,3,26,12,7,13,5,11,10,10,7,52,56,49,11,9,11,7,52,22,12,9,5,8,11,3,1,11,2,1,11,8,11,4,11,9,11,5,2,49,0,0,0,148,1,40,7,21,12,5,14,1,56,50,32,4,36,5,7,13,1,56,51,12,4,12,6,10,0,10,6,17,20,4,16,5,20,11,0,1,7,5,39,10,0,16,0,12,3,11,4,56,52,12,2,11,3,14,2,17,54,17,136,1,38,4,35,13,5,11,6,68,63,5,2,11,0,1,11,5,2,50,0,0,0,151,1,47,64,16,0,0,0,0,0,0,0,0,12,7,64,16,0,0,0,0,0,0,0,0,12,8,10,0,65,62,12,5,11,3,10,5,26,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,42,5,18,10,0,10,4,66,62,17,129,1,53,10,2,53,24,10,1,53,26,12,6,13,7,11,6,52,68,16,13,8,10,9,68,16,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,13,11,0,1,11,7,11,8,2,51,0,0,0,152,1,108,11,1,11,2,23,12,22,64,16,0,0,0,0,0,0,0,0,12,12,64,16,0,0,0,0,0,0,0,0,12,14,10,0,65,62,12,20,10,20,14,6,56,53,23,12,21,6,0,0,0,0,0,0,0,0,12,19,10,19,10,20,35,4,103,5,23,10,0,10,19,66,62,17,129,1,53,12,25,14,3,10,19,66,16,20,12,23,14,6,14,19,56,54,4,48,14,6,14,19,56,55,20,12,15,11,23,11,15,23,12,9,5,61,10,5,53,11,25,24,10,22,53,26,12,16,11,23,11,16,52,22,12,9,11,9,12,11,13,12,11,11,68,16,14,4,10,19,66,16,20,12,24,14,8,14,19,56,54,4,85,14,8,14,19,56,55,20,12,17,11,24,11,17,23,12,10,5,93,10,7,10,21,26,12,18,11,24,11,18,22,12,10,11,10,12,13,13,14,11,13,68,16,11,19,6,1,0,0,0,0,0,0,0,22,12,19,5,18,11,0,1,11,12,11,14,2,52,0,0,0,153,1,107,10,0,46,65,62,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,9,5,23,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,7,18,39,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,94,5,30,10,0,10,6,67,62,12,10,10,1,10,6,66,16,20,12,9,10,3,10,9,56,56,12,8,11,9,53,10,10,46,17,111,53,24,7,3,26,12,12,13,8,11,12,52,56,56,12,13,13,13,10,4,10,2,10,6,66,16,20,56,56,56,57,1,14,13,56,15,6,0,0,0,0,0,0,0,0,36,4,84,10,10,46,17,127,12,11,10,10,11,13,10,11,10,5,17,122,11,11,56,58,5,86,11,13,56,59,11,10,11,8,17,113,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,25,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,2,53,0,0,0,159,1,84,10,1,65,62,12,9,6,0,0,0,0,0,0,0,0,12,8,10,8,10,9,35,4,73,5,10,10,1,10,8,66,62,12,12,10,12,17,127,12,13,10,4,14,13,56,38,4,28,10,4,14,13,56,60,20,56,52,12,6,5,30,7,21,12,6,11,6,12,11,10,5,14,13,56,61,4,39,6,0,0,0,0,0,0,0,0,12,7,5,41,6,1,0,0,0,0,0,0,0,12,7,11,7,12,10,10,0,11,13,10,12,17,115,10,12,17,128,1,10,12,17,129,1,10,12,17,111,10,2,10,8,66,16,20,10,3,10,8,66,16,20,11,12,10,0,17,120,11,11,11,10,18,2,56,62,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,5,11,1,1,11,3,1,11,5,1,11,4,1,11,2,1,2,54,1,0,0,146,1,35,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,1,65,63,12,3,10,2,10,3,35,4,29,5,12,10,0,10,1,10,2,66,63,20,17,35,12,5,11,4,11,5,17,129,1,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,55,1,0,0,3,3,11,0,16,0,2,56,1,0,0,3,5,11,0,16,1,11,1,56,6,2,57,1,0,0,3,5,11,0,16,3,11,1,56,18,2,58,3,0,0,163,1,32,11,0,16,0,12,5,7,21,12,3,6,0,0,0,0,0,0,0,0,12,1,10,5,65,62,12,2,10,1,10,2,35,4,28,5,15,10,5,10,1,66,62,17,127,12,4,13,3,11,4,68,63,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,10,11,5,1,11,3,2,0,1,0,6,0,4,0,5,0,2,0,3,0,0,0,7,0,66,0,149,1,0],"validator_wrapper":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,16,3,24,48,4,72,6,5,78,52,7,130,1,211,1,8,213,2,64,6,149,3,10,10,159,3,6,12,165,3,100,13,137,4,2,15,139,4,2,0,14,1,10,1,16,0,12,0,2,4,0,1,0,2,0,2,3,12,0,3,1,4,0,0,5,0,1,0,0,8,2,3,0,0,6,1,4,0,0,11,2,5,0,0,15,6,7,0,2,4,8,9,1,4,2,6,9,12,1,4,2,9,10,11,1,4,2,15,13,7,0,5,4,7,4,6,4,2,8,3,7,8,1,1,8,0,1,7,8,0,1,7,8,3,1,8,3,0,1,6,8,0,1,3,3,3,9,0,7,8,1,1,8,2,1,7,8,2,1,7,9,0,1,9,0,1,6,8,2,9,84,120,67,111,110,116,101,120,116,9,86,97,108,105,100,97,116,111,114,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,9,86,101,114,115,105,111,110,101,100,6,99,114,101,97,116,101,9,99,114,101,97,116,101,95,118,49,7,100,101,115,116,114,111,121,5,105,110,110,101,114,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,10,116,120,95,99,111,110,116,101,120,116,17,117,112,103,114,97,100,101,95,116,111,95,108,97,116,101,115,116,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,1,7,8,2,0,3,0,0,5,6,6,1,0,0,0,0,0,0,0,11,0,11,1,56,0,18,0,2,1,3,0,0,5,6,10,0,17,3,11,0,15,0,56,1,2,2,3,0,0,5,6,13,0,17,3,11,0,19,0,56,2,2,3,0,0,0,5,10,11,0,46,17,4,6,1,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,2,4,0,0,0,5,4,11,0,16,0,17,8,2,0,0,0,13,0],"voting_power":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,87,4,107,4,5,111,134,1,7,245,1,176,2,8,165,4,96,6,133,5,70,10,203,5,16,12,219,5,254,6,13,217,12,4,15,221,12,2,0,22,1,21,2,9,0,18,0,1,2,0,0,2,2,0,3,0,4,0,0,13,0,1,0,0,6,2,3,0,0,15,4,5,0,0,7,6,1,0,0,3,7,1,0,0,17,8,1,0,0,4,4,1,0,0,16,1,5,0,0,12,1,5,0,1,7,17,1,1,0,1,8,19,20,1,0,2,5,11,5,0,2,10,11,5,0,2,11,11,5,0,3,13,21,1,0,3,15,14,5,0,3,22,14,5,0,9,13,10,13,1,7,10,8,2,0,2,6,10,8,2,3,2,10,8,1,3,1,6,10,8,2,1,3,2,7,10,8,1,8,1,3,7,10,8,1,3,3,2,7,10,8,2,10,8,1,4,3,10,8,1,3,3,1,8,2,2,3,3,8,3,8,1,3,10,8,1,3,3,3,3,1,8,1,1,6,8,2,3,3,3,3,4,3,1,3,3,3,7,10,9,0,9,0,3,7,1,3,3,3,3,3,7,8,1,1,6,10,9,0,1,1,2,7,8,2,3,12,3,3,3,3,3,3,3,3,3,6,8,2,6,8,2,3,9,86,97,108,105,100,97,116,111,114,15,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,17,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,86,50,19,97,100,106,117,115,116,95,118,111,116,105,110,103,95,112,111,119,101,114,16,99,104,101,99,107,95,105,110,118,97,114,105,97,110,116,115,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,22,105,110,105,116,95,118,111,116,105,110,103,95,112,111,119,101,114,95,105,110,102,111,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,4,109,97,116,104,3,109,97,120,3,109,105,110,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,5,115,116,97,107,101,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,19,117,112,100,97,116,101,95,118,111,116,105,110,103,95,112,111,119,101,114,9,118,97,108,105,100,97,116,111,114,15,118,97,108,105,100,97,116,111,114,95,105,110,100,101,120,13,118,97,108,105,100,97,116,111,114,95,115,101,116,6,118,101,99,116,111,114,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,16,39,0,0,0,0,0,0,3,8,11,26,0,0,0,0,0,0,3,8,232,3,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,2,19,3,22,3,1,2,3,19,3,22,3,14,3,0,3,0,0,9,29,7,0,7,2,7,0,10,0,46,65,10,17,11,17,12,17,13,12,4,10,0,10,4,12,1,46,11,1,17,1,12,3,12,2,13,2,11,4,11,3,17,4,10,0,11,2,17,5,11,0,46,17,6,2,1,0,0,0,12,58,10,0,17,2,12,8,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,7,64,13,0,0,0,0,0,0,0,0,12,5,10,2,10,4,35,4,51,5,17,10,0,10,2,66,10,17,15,12,6,10,6,53,7,0,53,24,10,8,53,26,52,10,1,17,13,12,9,10,2,10,9,11,6,18,1,12,3,13,5,11,3,17,3,11,7,11,9,22,12,7,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,0,1,11,5,7,0,11,7,23,2,2,0,0,0,15,28,6,0,0,0,0,0,0,0,0,12,1,10,0,65,10,12,2,6,0,0,0,0,0,0,0,0,12,3,10,1,10,2,35,4,24,5,12,11,3,10,0,10,1,66,10,17,15,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,3,0,0,0,16,39,6,0,0,0,0,0,0,0,0,12,4,10,0,46,65,13,12,5,10,4,10,5,35,4,25,5,11,10,0,10,4,12,2,46,11,2,66,13,16,0,20,14,1,16,0,20,36,12,3,5,27,9,12,3,11,3,4,34,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,11,1,11,4,56,0,2,4,0,0,0,18,84,6,0,0,0,0,0,0,0,0,12,5,10,0,46,65,13,12,6,10,5,10,6,35,4,16,5,11,10,2,6,0,0,0,0,0,0,0,0,36,12,3,5,18,9,12,3,11,3,4,74,10,0,10,5,67,13,12,9,10,2,10,6,10,5,23,17,11,12,7,10,1,10,9,16,1,20,11,7,22,17,13,12,8,10,2,11,8,10,9,16,1,20,23,17,13,12,4,10,9,16,1,20,10,4,22,10,9,15,1,21,11,9,16,1,20,10,1,37,4,61,5,65,11,0,1,7,5,39,11,2,11,4,23,12,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,6,11,0,1,11,2,6,0,0,0,0,0,0,0,0,33,4,81,5,83,7,3,39,2,5,0,0,0,11,22,14,1,56,1,32,4,17,5,5,13,1,69,13,19,1,1,12,3,12,2,10,0,11,2,67,10,11,3,17,14,5,0,11,0,1,11,1,70,13,0,0,0,0,0,0,0,0,2,6,0,0,0,22,119,6,0,0,0,0,0,0,0,0,12,3,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,9,10,3,10,4,35,4,35,5,12,10,0,10,3,66,10,17,16,12,12,10,12,6,0,0,0,0,0,0,0,0,36,4,22,5,26,11,0,1,7,6,39,11,9,11,12,22,12,9,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,9,7,0,33,4,40,5,44,11,0,1,7,3,39,6,0,0,0,0,0,0,0,0,12,1,10,1,10,4,35,4,116,5,51,10,1,6,1,0,0,0,0,0,0,0,22,12,2,10,2,10,4,35,4,111,5,60,10,0,10,1,66,10,12,10,10,0,10,2,66,10,12,11,10,10,17,15,12,7,10,11,17,15,12,8,11,10,17,16,12,5,11,11,17,16,12,6,10,7,10,8,36,4,93,10,5,10,6,38,4,89,5,93,11,0,1,7,4,39,11,7,11,8,35,4,106,11,5,11,6,37,4,102,5,106,11,0,1,7,4,39,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,55,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,46,11,0,1,2,7,1,0,0,1,2,7,0,2,8,1,0,0,1,2,7,1,2,1,2,1,1,0,20,0]},"type_origin_table":[{"module_name":"validator_cap","struct_name":"UnverifiedValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_cap","struct_name":"ValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakingPool","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"PoolTokenExchangeRate","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakedSui","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"ValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"Validator","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"StakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"UnstakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfo","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfoV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_wrapper","struct_name":"ValidatorWrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorSet","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEventV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorJoinEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorLeaveEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"storage_fund","struct_name":"StorageFund","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"stake_subsidy","struct_name":"StakeSubsidy","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SystemParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SystemParametersV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SuiSystemStateInner","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SuiSystemStateInnerV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SystemEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system","struct_name":"SuiSystemState","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisChainParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenDistributionSchedule","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenAllocation","package":"0x0000000000000000000000000000000000000000000000000000000000000003"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"F8GGcAVhtPumDoXzc6z9N8Hf9zoTNFx1BPiCy7FJNZsQ","storage_rebate":0},{"data":{"Package":{"id":"0x000000000000000000000000000000000000000000000000000000000000dee9","version":10,"module_map":{"clob":[161,28,235,11,6,0,0,0,13,1,0,35,2,35,134,1,3,169,1,195,4,4,236,5,178,1,5,158,7,249,9,7,151,17,237,14,8,132,32,96,6,228,32,147,2,10,247,34,226,1,11,217,36,8,12,225,36,179,39,13,148,76,40,14,188,76,26,0,45,0,53,0,54,0,94,1,105,1,135,1,2,28,2,46,2,47,2,64,2,85,2,103,2,124,2,127,2,133,1,2,134,1,0,16,7,0,0,14,7,2,0,1,0,1,0,10,7,2,0,1,0,1,0,12,7,2,0,1,0,1,0,9,6,0,0,19,4,0,0,15,8,2,0,1,0,1,0,13,7,2,0,1,0,1,0,11,7,2,0,1,0,1,1,4,4,1,4,0,2,0,12,0,2,5,12,1,0,1,4,8,7,1,0,0,5,21,7,0,6,1,4,1,0,1,7,2,8,0,8,3,12,1,0,1,10,7,12,2,7,0,4,1,11,6,7,0,11,22,4,0,12,17,2,0,13,18,12,2,7,1,4,1,15,20,2,0,0,60,0,1,0,0,49,2,3,0,0,51,4,1,2,0,0,0,50,5,1,2,0,0,0,57,6,1,2,0,0,0,58,7,1,2,0,0,0,144,1,8,9,2,0,0,0,145,1,8,10,2,0,0,0,125,11,12,2,0,0,0,126,13,12,2,0,0,0,93,14,15,2,0,0,0,92,14,15,2,0,0,0,91,16,15,2,0,0,0,110,17,18,2,0,0,0,78,19,20,2,0,0,0,109,21,22,2,0,0,0,107,20,23,0,0,62,24,1,2,0,0,0,63,25,1,2,0,0,0,44,26,1,2,0,0,0,121,27,28,2,0,0,0,43,29,1,2,0,0,0,36,30,1,2,0,0,0,86,31,32,2,0,0,0,24,31,33,2,0,0,0,74,34,35,2,0,0,0,73,36,37,2,0,0,0,72,36,37,2,0,0,0,71,38,20,2,0,0,0,75,39,40,2,0,0,1,39,84,60,1,4,1,40,84,60,1,4,1,42,71,72,1,4,1,66,84,20,1,4,1,67,84,78,1,4,1,79,91,20,1,4,1,82,70,23,1,4,1,95,70,35,1,4,1,96,70,35,1,4,1,98,2,51,1,4,1,102,84,35,1,4,1,112,84,35,1,4,1,120,71,45,1,4,2,23,97,20,1,0,2,24,97,35,1,0,2,55,90,55,1,0,2,56,77,55,1,0,2,77,62,1,1,0,2,87,90,1,1,0,2,98,2,54,1,0,2,137,1,77,1,1,0,2,143,1,63,9,1,0,3,97,35,20,0,3,138,1,35,20,0,3,139,1,35,20,0,3,140,1,35,78,0,4,38,74,60,1,0,4,83,74,23,1,0,5,70,1,46,1,0,6,84,80,20,1,0,6,123,79,55,1,0,6,142,1,67,20,1,0,6,146,1,1,55,1,0,7,131,1,66,20,0,8,68,68,9,1,0,8,80,9,55,1,0,8,84,88,1,1,0,8,142,1,59,20,1,0,9,61,45,1,1,3,10,27,73,74,2,7,4,10,38,75,76,2,7,4,10,41,83,82,2,7,4,10,48,75,23,2,7,4,10,59,43,1,2,7,4,10,69,73,74,2,7,4,10,82,73,23,2,7,4,10,98,2,43,2,7,4,10,99,75,74,2,7,4,10,114,92,1,2,7,4,10,119,83,47,2,7,4,11,76,60,61,1,8,11,98,2,48,0,11,136,1,49,50,0,13,25,95,1,2,7,4,13,38,94,76,2,7,4,13,41,81,82,2,7,4,13,48,94,23,2,7,4,13,98,2,53,2,7,4,14,122,45,1,1,8,73,42,58,45,58,47,39,0,87,52,49,45,49,47,62,45,62,47,88,57,68,58,67,45,80,3,65,45,47,45,67,47,65,47,47,47,51,45,51,47,13,56,10,56,61,45,64,45,64,47,36,0,38,0,32,0,74,42,56,20,75,42,70,42,50,45,17,56,46,45,60,47,59,47,59,45,18,56,77,42,57,20,85,52,79,35,79,42,71,42,40,0,42,0,34,0,37,0,50,47,46,47,60,45,41,0,11,56,66,45,12,56,66,47,48,47,48,45,76,42,35,0,78,42,68,93,86,52,76,35,83,52,78,35,43,47,45,47,61,47,45,45,14,56,68,98,68,99,72,35,70,35,20,56,30,0,72,42,75,35,69,35,84,52,74,35,31,0,77,35,44,45,44,47,33,0,28,56,1,8,5,0,1,7,8,22,1,8,10,6,3,3,3,3,11,14,1,8,20,7,8,22,4,3,3,11,16,1,8,20,7,8,22,3,7,11,6,2,9,0,9,1,11,16,1,9,0,6,8,10,3,7,11,6,2,9,0,9,1,11,16,1,9,1,6,8,10,4,7,11,6,2,9,0,9,1,3,6,8,10,7,8,22,1,11,16,1,9,0,1,11,16,1,9,1,6,7,11,6,2,9,0,9,1,3,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,3,11,16,1,9,0,11,16,1,9,1,3,5,7,11,6,2,9,0,9,1,3,6,8,15,11,16,1,9,1,7,8,22,5,7,11,6,2,9,0,9,1,3,3,3,11,14,1,9,1,2,11,14,1,9,0,11,14,1,9,1,4,7,11,6,2,9,0,9,1,3,3,11,14,1,9,0,7,7,11,6,2,9,0,9,1,3,1,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,2,11,16,1,9,0,11,16,1,9,1,7,7,11,6,2,9,0,9,1,3,3,1,3,6,8,10,7,8,22,1,3,9,7,11,6,2,9,0,9,1,3,3,1,3,2,6,8,15,6,8,10,7,8,22,4,3,3,1,3,1,1,2,8,18,6,8,4,5,8,18,6,8,4,3,3,3,3,7,11,6,2,9,0,9,1,3,6,8,10,5,7,11,9,1,8,5,7,11,17,2,3,3,3,3,8,18,1,8,4,2,7,11,6,2,9,0,9,1,6,8,10,3,7,11,6,2,9,0,9,1,10,3,6,8,10,2,6,11,6,2,9,0,9,1,6,8,10,1,10,8,4,4,3,3,3,3,1,6,11,6,2,9,0,9,1,2,3,3,4,6,11,6,2,9,0,9,1,3,3,6,8,15,2,10,3,10,3,3,6,11,9,1,8,5,3,3,3,6,11,6,2,9,0,9,1,3,6,8,10,1,6,8,4,1,11,17,2,3,8,4,2,3,8,4,1,11,17,2,9,0,9,1,4,8,13,8,18,8,19,8,13,1,9,0,1,8,13,1,9,1,1,8,19,1,6,8,19,1,6,8,18,1,11,9,1,9,0,2,8,18,11,17,2,3,3,1,11,21,2,9,0,9,1,1,11,11,1,9,0,1,11,14,1,9,0,2,9,0,9,1,1,11,6,2,9,0,9,1,1,8,0,1,6,11,16,1,9,0,1,6,9,0,1,8,18,3,7,11,11,1,9,0,8,18,11,14,1,9,0,4,7,11,11,1,9,0,3,6,8,10,7,8,22,4,3,11,16,1,9,0,11,16,1,9,1,3,3,11,14,1,9,0,11,14,1,9,1,3,1,6,8,15,1,6,11,14,1,9,0,2,11,14,1,9,0,7,8,22,30,1,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,11,14,1,9,1,1,3,3,3,1,3,7,8,5,3,1,6,11,9,1,9,0,2,7,11,9,1,9,0,3,1,7,9,0,1,6,11,17,2,9,0,9,1,1,6,11,12,1,9,0,2,6,11,17,2,9,0,9,1,9,0,1,6,9,1,3,7,11,11,1,9,0,8,18,3,2,1,3,2,7,11,14,1,9,0,3,2,7,11,14,1,9,0,11,14,1,9,0,2,7,11,21,2,9,0,9,1,9,0,1,7,9,1,2,7,11,17,2,9,0,9,1,9,0,2,6,11,9,1,9,0,3,26,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,27,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,1,3,6,8,4,7,8,4,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,3,11,14,1,9,0,11,14,1,9,1,11,14,1,9,1,2,7,11,16,1,9,0,11,16,1,9,0,7,3,7,11,9,1,8,5,8,4,3,3,3,8,18,3,7,11,11,1,9,0,6,8,10,3,3,7,11,9,1,9,0,3,9,0,3,7,11,17,2,9,0,9,1,9,0,9,1,1,11,1,2,9,0,9,1,2,6,11,21,2,9,0,9,1,9,0,3,7,11,21,2,9,0,9,1,9,0,9,1,11,11,14,1,9,0,11,14,1,9,0,11,14,1,9,0,3,3,11,14,1,9,1,11,14,1,9,1,11,14,1,9,1,3,3,8,18,2,6,11,11,1,9,0,8,18,1,11,2,2,9,0,9,1,1,11,3,2,9,0,9,1,11,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,1,8,4,3,3,8,18,7,11,17,2,3,3,3,3,7,8,5,8,4,13,3,7,11,9,1,8,5,3,3,1,7,11,9,1,8,5,8,4,3,3,8,18,3,8,18,7,11,17,2,3,3,17,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,3,1,3,3,3,8,4,3,8,18,3,3,8,18,7,11,17,2,3,3,7,6,8,5,10,8,4,6,8,4,6,11,12,1,3,3,8,18,6,11,17,2,3,3,5,3,3,3,3,8,18,6,3,10,3,3,3,3,10,3,4,3,6,8,4,6,11,12,1,3,6,11,17,2,3,8,4,4,6,11,9,1,8,5,3,8,18,6,11,17,2,3,3,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,11,67,114,105,116,98,105,116,84,114,101,101,9,67,117,115,116,111,100,105,97,110,2,73,68,11,76,105,110,107,101,100,84,97,98,108,101,6,79,112,116,105,111,110,5,79,114,100,101,114,13,79,114,100,101,114,67,97,110,99,101,108,101,100,11,79,114,100,101,114,70,105,108,108,101,100,13,79,114,100,101,114,70,105,108,108,101,100,86,50,11,79,114,100,101,114,80,108,97,99,101,100,13,79,114,100,101,114,80,108,97,99,101,100,86,50,4,80,111,111,108,11,80,111,111,108,67,114,101,97,116,101,100,3,83,85,73,5,84,97,98,108,101,9,84,105,99,107,76,101,118,101,108,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,3,97,100,100,4,97,115,107,115,4,98,97,99,107,7,98,97,108,97,110,99,101,10,98,97,115,101,95,97,115,115,101,116,28,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,99,97,110,99,101,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,102,105,108,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,112,108,97,99,101,100,29,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,114,101,109,97,105,110,105,110,103,23,98,97,115,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,14,98,97,115,101,95,99,117,115,116,111,100,105,97,110,18,98,97,116,99,104,95,99,97,110,99,101,108,95,111,114,100,101,114,4,98,105,100,115,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,17,99,97,110,99,101,108,95,97,108,108,95,111,114,100,101,114,115,12,99,97,110,99,101,108,95,111,114,100,101,114,4,99,108,111,98,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,14,99,114,101,97,116,101,95,97,99,99,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,12,99,114,101,97,116,101,95,112,111,111,108,95,12,99,114,101,97,116,105,111,110,95,102,101,101,7,99,114,105,116,98,105,116,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,100,101,112,111,115,105,116,95,98,97,115,101,13,100,101,112,111,115,105,116,95,113,117,111,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,19,100,101,115,116,114,111,121,95,101,109,112,116,121,95,108,101,118,101,108,4,101,109,105,116,19,101,109,105,116,95,111,114,100,101,114,95,99,97,110,99,101,108,101,100,17,101,109,105,116,95,111,114,100,101,114,95,102,105,108,108,101,100,5,101,118,101,110,116,16,101,120,112,105,114,101,95,116,105,109,101,115,116,97,109,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,12,102,114,111,109,95,98,97,108,97,110,99,101,5,102,114,111,110,116,3,103,101,116,22,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,97,115,107,95,115,105,100,101,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,98,105,100,95,115,105,100,101,16,103,101,116,95,109,97,114,107,101,116,95,112,114,105,99,101,16,103,101,116,95,111,114,100,101,114,95,115,116,97,116,117,115,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,18,105,110,106,101,99,116,95,108,105,109,105,116,95,111,114,100,101,114,11,105,110,115,101,114,116,95,108,101,97,102,12,105,110,116,111,95,98,97,108,97,110,99,101,6,105,115,95,98,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,4,106,111,105,110,12,108,105,110,107,101,100,95,116,97,98,108,101,16,108,105,115,116,95,111,112,101,110,95,111,114,100,101,114,115,12,108,111,99,107,95,98,97,108,97,110,99,101,8,108,111,116,95,115,105,122,101,17,109,97,107,101,114,95,114,101,98,97,116,101,95,114,97,116,101,13,109,97,107,101,114,95,114,101,98,97,116,101,115,9,109,97,116,99,104,95,97,115,107,9,109,97,116,99,104,95,98,105,100,29,109,97,116,99,104,95,98,105,100,95,119,105,116,104,95,113,117,111,116,101,95,113,117,97,110,116,105,116,121,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,3,109,117,108,3,110,101,119,4,110,101,120,116,17,110,101,120,116,95,97,115,107,95,111,114,100,101,114,95,105,100,17,110,101,120,116,95,98,105,100,95,111,114,100,101,114,95,105,100,9,110,101,120,116,95,108,101,97,102,6,111,98,106,101,99,116,11,111,112,101,110,95,111,114,100,101,114,115,6,111,112,116,105,111,110,8,111,114,100,101,114,95,105,100,12,111,114,100,101,114,95,105,115,95,98,105,100,5,111,119,110,101,114,17,112,108,97,99,101,95,108,105,109,105,116,95,111,114,100,101,114,18,112,108,97,99,101,95,109,97,114,107,101,116,95,111,114,100,101,114,7,112,111,111,108,95,105,100,13,112,114,101,118,105,111,117,115,95,108,101,97,102,5,112,114,105,99,101,9,112,117,115,104,95,98,97,99,107,8,113,117,97,110,116,105,116,121,11,113,117,111,116,101,95,97,115,115,101,116,24,113,117,111,116,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,15,113,117,111,116,101,95,99,117,115,116,111,100,105,97,110,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,12,114,101,109,111,118,101,95,111,114,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,3,115,117,105,25,115,119,97,112,95,101,120,97,99,116,95,98,97,115,101,95,102,111,114,95,113,117,111,116,101,25,115,119,97,112,95,101,120,97,99,116,95,113,117,111,116,101,95,102,111,114,95,98,97,115,101,5,116,97,98,108,101,16,116,97,107,101,114,95,99,111,109,109,105,115,115,105,111,110,14,116,97,107,101,114,95,102,101,101,95,114,97,116,101,9,116,105,99,107,95,115,105,122,101,12,116,105,109,101,115,116,97,109,112,95,109,115,14,116,111,116,97,108,95,113,117,97,110,116,105,116,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,10,117,110,115,97,102,101,95,100,105,118,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,15,117,115,114,95,111,112,101,110,95,111,114,100,101,114,115,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,13,119,105,116,104,100,114,97,119,95,98,97,115,101,14,119,105,116,104,100,114,97,119,95,113,117,111,116,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,3,8,19,0,0,0,0,0,0,0,3,8,20,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,2,1,4,2,1,0,2,1,1,2,1,2,2,1,3,3,8,0,0,0,0,0,0,0,128,3,8,64,75,76,0,0,0,0,0,3,8,160,37,38,0,0,0,0,0,3,8,0,232,118,72,23,0,0,0,0,2,7,111,8,18,29,8,13,116,8,13,129,1,3,89,3,130,1,3,88,3,1,2,7,111,8,18,106,3,81,1,108,8,18,32,3,113,3,65,3,2,2,6,111,8,18,106,3,81,1,108,8,18,30,3,113,3,3,2,10,111,8,18,106,3,81,1,108,8,18,132,1,3,31,3,33,3,113,3,128,1,3,90,3,4,2,6,106,3,113,3,115,3,81,1,108,8,18,65,3,5,2,2,113,3,104,11,17,2,3,8,4,6,2,15,76,8,19,37,11,9,1,8,5,26,11,9,1,8,5,101,3,100,3,141,1,11,21,2,8,18,11,17,2,3,3,129,1,3,89,3,130,1,3,88,3,35,11,11,1,9,0,118,11,11,1,9,1,52,11,14,1,8,20,34,11,14,1,9,0,117,11,14,1,9,1,7,2,6,111,8,18,106,3,81,1,108,8,18,32,3,113,3,8,2,8,111,8,18,106,3,81,1,108,8,18,132,1,3,31,3,33,3,113,3,6,56,1,56,2,56,3,56,0,0,0,0,41,7,11,0,19,5,12,1,1,11,1,56,0,2,1,1,0,0,1,2,7,0,39,2,0,0,0,44,72,56,1,12,6,56,2,12,9,10,3,10,2,17,54,6,0,0,0,0,0,0,0,0,36,4,11,5,15,11,5,1,7,20,39,10,6,10,9,34,4,20,5,24,11,5,1,7,16,39,10,0,10,1,38,4,29,5,33,11,5,1,7,2,39,10,5,17,81,12,8,14,8,17,82,20,12,7,11,8,10,5,56,3,10,5,56,3,7,1,7,27,10,5,56,4,10,0,10,1,10,2,10,3,10,5,56,5,11,5,56,6,11,4,56,7,56,8,57,0,56,9,11,7,11,6,11,9,11,0,11,1,11,2,11,3,18,0,56,10,2,3,1,0,0,1,2,7,0,39,4,1,0,0,1,20,14,1,56,11,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,7,39,11,0,54,0,11,2,56,12,11,1,56,13,56,14,2,5,1,0,0,1,20,14,1,56,15,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,8,39,11,0,54,1,11,2,56,12,11,1,56,16,56,17,2,6,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,6,39,11,0,54,0,11,1,11,2,11,3,56,18,2,7,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,6,39,11,0,54,1,11,1,11,2,11,3,56,19,2,8,1,0,0,64,49,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,5,1,11,4,1,7,6,39,14,2,56,11,10,1,38,4,19,5,27,11,0,1,11,5,1,11,4,1,7,7,39,14,3,56,15,12,6,11,0,11,1,9,11,2,11,3,11,4,11,5,56,20,12,8,12,7,14,8,56,15,12,9,11,7,11,8,11,9,11,6,23,2,9,1,0,0,65,48,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,4,1,11,2,1,7,6,39,14,3,56,15,10,1,38,4,19,5,27,11,0,1,11,4,1,11,2,1,7,8,39,11,0,11,1,7,27,11,2,17,63,11,3,56,16,56,21,12,6,12,5,14,5,56,22,12,7,11,5,10,4,56,23,11,6,11,4,56,24,11,7,2,10,0,0,0,69,193,2,10,0,55,2,17,82,20,12,24,11,1,12,30,56,7,12,10,11,4,12,26,10,0,54,3,12,9,10,9,46,56,25,4,25,11,0,1,11,9,1,11,10,11,26,2,10,9,46,56,26,12,32,12,34,9,12,31,10,9,46,56,25,32,4,43,5,38,10,34,10,2,37,12,5,5,45,9,12,5,11,5,4,190,2,10,9,10,32,56,27,12,33,10,33,16,4,56,28,56,29,20,12,23,10,33,16,4,56,30,32,4,158,2,5,63,10,33,16,4,10,23,56,31,12,16,10,16,16,5,20,12,15,9,12,27,10,16,16,6,20,10,3,37,4,95,8,12,27,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,32,10,24,10,16,56,33,5,227,1,10,15,10,16,16,8,20,17,52,12,19,10,19,10,0,55,4,20,17,55,12,28,4,112,11,28,6,1,0,0,0,0,0,0,0,22,12,28,10,19,11,28,22,12,18,10,30,10,18,36,4,127,11,18,12,12,11,19,12,13,10,15,12,11,5,170,1,8,12,31,10,30,7,21,10,0,55,4,20,22,17,53,10,16,16,8,20,17,53,10,0,55,5,20,26,10,0,55,5,20,24,12,11,10,11,10,16,16,8,20,17,54,12,13,10,13,10,0,55,4,20,17,55,12,29,4,166,1,11,29,6,1,0,0,0,0,0,0,0,22,12,29,10,13,11,29,22,12,12,10,13,10,0,55,6,20,17,54,12,20,11,15,10,11,23,12,15,11,30,10,12,23,12,30,10,0,54,0,10,16,16,7,20,10,11,56,34,12,14,13,26,10,12,56,35,12,25,10,0,54,1,10,16,16,7,20,13,25,10,20,10,13,22,56,35,56,17,10,0,54,7,11,25,56,36,1,13,10,11,14,56,37,1,10,0,55,2,17,82,20,10,16,11,11,11,12,11,13,23,11,20,56,38,11,27,4,232,1,8,12,6,5,236,1,10,15,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,143,2,10,23,12,22,10,33,16,4,10,23,56,39,12,21,10,21,56,40,32,4,254,1,11,21,56,29,20,12,23,5,128,2,11,21,1,10,0,54,8,11,16,16,7,20,56,41,10,22,56,42,1,10,33,15,4,11,22,56,43,1,5,154,2,11,16,1,10,33,15,4,10,23,56,44,12,17,11,15,11,17,15,5,21,10,31,4,157,2,5,158,2,5,57,11,33,16,4,56,30,4,182,2,10,9,11,34,12,7,46,11,7,56,45,1,12,34,10,9,11,32,56,46,17,0,10,9,10,34,12,8,46,11,8,56,47,12,32,1,10,31,4,189,2,11,0,1,11,9,1,5,190,2,5,32,11,10,11,26,2,11,0,0,0,85,153,2,10,0,55,2,17,82,20,12,22,11,1,12,25,56,7,12,11,11,4,12,23,10,0,54,3,12,10,10,10,46,56,25,4,25,11,0,1,11,10,1,11,11,11,23,2,10,10,46,56,26,12,28,12,30,10,10,46,56,25,32,4,41,5,36,10,30,10,2,37,12,5,5,43,9,12,5,11,5,4,150,2,10,10,10,28,56,27,12,29,10,29,16,4,56,28,56,29,20,12,21,10,29,16,4,56,30,32,4,244,1,5,61,10,29,16,4,10,21,56,31,12,16,10,16,16,5,20,12,15,9,12,24,10,16,16,6,20,10,3,37,4,93,8,12,24,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,32,10,22,10,16,56,33,5,183,1,10,25,10,15,36,4,100,10,15,12,6,5,102,10,25,12,6,11,6,12,12,10,12,10,16,16,8,20,17,52,12,13,10,13,10,0,55,6,20,17,54,12,18,10,13,10,0,55,4,20,17,55,12,26,4,127,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,15,10,12,23,12,15,11,25,10,12,23,12,25,10,0,54,0,10,16,16,7,20,10,12,56,34,12,14,13,23,10,26,56,35,12,27,10,0,54,1,10,16,16,7,20,13,27,10,18,56,35,56,17,10,0,54,7,11,27,56,36,1,13,11,11,14,56,37,1,10,0,54,1,10,16,16,7,20,13,23,11,13,56,35,56,17,10,0,55,2,17,82,20,10,16,11,12,11,26,11,18,56,38,11,24,4,188,1,8,12,7,5,192,1,10,15,6,0,0,0,0,0,0,0,0,33,12,7,11,7,4,227,1,10,21,12,20,10,29,16,4,10,21,56,39,12,19,10,19,56,40,32,4,210,1,11,19,56,29,20,12,21,5,212,1,11,19,1,10,0,54,8,11,16,16,7,20,56,41,10,20,56,42,1,10,29,15,4,11,20,56,43,1,5,238,1,11,16,1,10,29,15,4,10,21,56,44,12,17,11,15,11,17,15,5,21,10,25,6,0,0,0,0,0,0,0,0,33,4,243,1,5,244,1,5,55,11,29,16,4,56,30,4,140,2,10,10,11,30,12,8,46,11,8,56,45,1,12,30,10,10,11,28,56,46,17,0,10,10,10,30,12,9,46,11,9,56,47,12,28,1,10,25,6,0,0,0,0,0,0,0,0,33,4,149,2,11,0,1,11,10,1,5,150,2,5,30,11,11,11,23,2,12,0,0,0,86,158,2,10,0,55,2,17,82,20,12,22,11,3,12,10,56,8,12,23,10,0,54,9,12,9,10,9,46,56,25,4,23,11,0,1,11,9,1,11,10,11,23,2,10,9,46,56,48,12,28,12,30,10,9,46,56,25,32,4,39,5,34,10,30,10,1,38,12,4,5,41,9,12,4,11,4,4,155,2,10,9,10,28,56,27,12,29,10,29,16,4,56,28,56,29,20,12,21,10,29,16,4,56,30,32,4,248,1,5,59,10,29,16,4,10,21,56,31,12,15,10,15,16,5,20,12,14,9,12,24,10,15,16,6,20,10,2,37,4,97,8,12,24,10,15,16,5,20,10,15,16,8,20,17,52,12,17,10,0,54,1,10,15,16,7,20,11,17,56,49,10,22,10,15,56,33,5,186,1,14,10,56,22,12,25,10,25,10,14,38,4,107,10,14,12,5,5,109,11,25,12,5,11,5,12,11,10,11,10,15,16,8,20,17,52,12,12,10,12,10,0,55,6,20,17,54,12,18,10,12,10,0,55,4,20,17,55,12,26,4,134,1,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,14,10,11,23,12,14,10,0,54,1,10,15,16,7,20,11,12,56,50,12,13,13,13,10,26,56,35,12,27,10,0,54,1,10,15,16,7,20,13,27,10,18,56,35,56,17,10,0,54,7,11,27,56,36,1,13,23,11,13,56,36,1,10,0,54,0,10,15,16,7,20,13,10,10,11,56,51,56,14,10,0,55,2,17,82,20,10,15,11,11,11,26,11,18,56,38,11,24,4,191,1,8,12,6,5,195,1,10,14,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,230,1,10,21,12,20,10,29,16,4,10,21,56,39,12,19,10,19,56,40,32,4,213,1,11,19,56,29,20,12,21,5,215,1,11,19,1,10,0,54,8,11,15,16,7,20,56,41,10,20,56,42,1,10,29,15,4,11,20,56,43,1,5,241,1,11,15,1,10,29,15,4,10,21,56,44,12,16,11,14,11,16,15,5,21,14,10,56,22,6,0,0,0,0,0,0,0,0,33,4,247,1,5,248,1,5,53,11,29,16,4,56,30,4,144,2,10,9,11,30,12,7,46,11,7,56,52,1,12,30,10,9,11,28,56,46,17,0,10,9,10,30,12,8,46,11,8,56,47,12,28,1,14,10,56,22,6,0,0,0,0,0,0,0,0,33,4,154,2,11,0,1,11,9,1,5,155,2,5,28,11,10,11,23,2,13,1,0,0,87,85,10,1,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,9,5,17,11,0,1,11,6,1,11,5,1,7,6,39,10,1,6,0,0,0,0,0,0,0,0,34,4,22,5,30,11,0,1,11,6,1,11,5,1,7,6,39,11,2,4,52,11,0,11,1,7,27,11,5,17,63,11,4,56,16,56,53,12,9,12,7,13,3,11,7,10,6,56,23,56,54,11,9,11,6,56,24,12,4,5,82,11,1,14,3,56,11,37,4,58,5,66,11,0,1,11,6,1,11,5,1,7,7,39,11,0,7,0,11,5,17,63,11,3,56,13,56,55,12,8,10,6,56,23,12,3,13,4,11,8,11,6,56,24,56,56,11,3,11,4,2,14,0,0,0,89,118,10,5,56,12,12,13,10,3,4,30,10,2,10,1,17,52,12,11,10,0,54,1,11,5,11,11,56,57,10,0,55,10,20,12,10,10,0,55,10,20,6,1,0,0,0,0,0,0,0,22,10,0,54,10,21,10,0,54,9,12,8,5,50,10,0,54,0,11,5,10,2,56,58,10,0,55,11,20,12,10,10,0,55,11,20,6,1,0,0,0,0,0,0,0,22,10,0,54,11,21,10,0,54,3,12,8,10,10,10,1,10,2,10,3,10,13,10,4,18,4,12,9,10,8,10,1,12,7,46,11,7,56,47,12,12,32,4,75,10,8,10,1,10,1,10,6,56,59,18,5,56,60,12,12,11,8,11,12,56,27,15,4,10,10,11,9,56,61,10,0,55,2,17,82,20,10,10,11,3,10,13,11,2,10,1,11,4,57,1,56,62,10,0,55,8,10,13,56,63,32,4,107,10,0,54,8,10,13,11,6,56,64,56,65,5,109,11,6,1,11,0,54,8,11,13,56,41,10,10,11,1,56,66,11,10,2,15,1,0,0,96,144,2,10,2,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,8,1,11,6,1,11,7,1,7,6,39,10,1,6,0,0,0,0,0,0,0,0,36,4,20,5,30,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,1,10,0,55,12,20,25,6,0,0,0,0,0,0,0,0,33,4,39,5,49,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,2,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,58,5,68,11,0,1,11,8,1,11,6,1,11,7,1,7,6,39,10,4,10,6,17,63,36,4,74,5,84,11,0,1,11,8,1,11,6,1,11,7,1,7,19,39,10,7,56,12,12,19,10,3,4,128,1,10,0,55,1,10,19,56,67,12,18,10,0,54,1,10,7,10,18,56,68,12,14,10,0,10,2,10,1,11,6,17,63,11,14,56,53,12,16,12,10,14,10,56,22,12,12,11,18,14,16,56,69,23,12,17,10,0,54,0,10,19,11,10,56,14,10,0,54,1,11,19,11,16,56,17,5,160,1,10,0,54,0,10,7,10,2,56,70,12,9,10,0,10,1,11,6,17,63,11,9,56,55,12,15,12,11,10,2,14,11,56,22,23,12,12,14,15,56,69,12,17,10,0,54,0,10,19,11,11,56,14,10,0,54,1,11,19,11,15,56,17,10,5,7,24,33,4,175,1,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,25,33,4,197,1,11,0,1,11,8,1,11,7,1,10,12,11,2,33,4,190,1,5,192,1,7,9,39,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,26,33,4,228,1,10,12,6,0,0,0,0,0,0,0,0,33,4,206,1,5,214,1,11,0,1,11,8,1,11,7,1,7,10,39,11,0,11,1,11,2,11,3,11,4,11,7,11,8,56,71,12,13,11,12,11,17,8,11,13,2,11,5,7,23,33,4,233,1,5,241,1,11,0,1,11,8,1,11,7,1,7,14,39,10,2,10,12,36,4,133,2,11,0,11,1,11,2,10,12,23,11,3,11,4,11,7,11,8,56,71,12,13,11,12,11,17,8,11,13,2,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,16,0,0,0,1,4,11,0,7,27,35,2,17,0,0,0,1,19,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,11,1,16,8,20,57,2,56,72,2,18,0,0,0,1,27,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,10,2,10,1,16,5,20,11,2,23,11,1,16,8,20,11,3,11,4,57,3,56,73,2,19,1,0,0,100,110,11,2,56,12,12,12,10,0,55,8,10,12,56,63,4,9,5,13,11,0,1,7,12,39,10,0,54,8,10,12,56,41,12,13,10,13,10,1,12,3,46,11,3,56,74,4,26,5,32,11,13,1,11,0,1,7,3,39,10,13,10,1,12,4,46,11,4,56,75,20,12,11,10,1,17,16,12,8,10,8,4,49,10,0,55,9,12,5,5,52,10,0,55,3,12,5,11,5,11,11,56,47,12,10,4,58,5,64,11,13,1,11,0,1,7,3,39,10,8,4,70,10,0,54,9,12,6,5,73,10,0,54,3,12,6,11,6,11,13,11,10,11,1,10,12,56,76,12,9,11,8,4,96,14,9,16,5,20,14,9,16,8,20,17,52,12,7,10,0,54,1,11,12,11,7,56,49,5,103,10,0,54,0,11,12,14,9,16,5,20,56,32,11,0,55,2,17,82,20,14,9,56,33,2,20,0,0,0,101,54,11,1,10,3,56,42,1,10,0,10,2,12,5,46,11,5,56,77,16,4,10,3,56,78,4,15,5,19,11,0,1,7,3,39,10,0,10,2,56,27,12,6,10,6,15,4,11,3,56,43,12,7,14,7,16,7,20,11,4,33,4,35,5,41,11,0,1,11,6,1,7,4,39,11,6,16,4,56,30,4,50,11,0,11,2,56,46,17,0,5,52,11,0,1,11,7,2,21,1,0,0,102,104,10,0,55,2,17,82,20,12,11,11,1,56,12,12,13,10,0,55,8,10,13,56,63,4,14,5,18,11,0,1,7,12,39,10,0,54,8,10,13,56,41,12,14,10,14,46,56,79,32,4,99,5,29,10,14,46,56,80,56,29,20,12,9,10,14,10,9,12,2,46,11,2,56,75,20,12,10,10,9,17,16,12,6,10,6,4,52,10,0,54,9,12,3,5,55,10,0,54,3,12,3,11,3,12,7,10,7,11,10,12,4,46,11,4,56,47,12,12,1,11,7,10,14,11,12,11,9,10,13,56,76,12,8,11,6,4,88,14,8,16,5,20,14,8,16,8,20,17,52,12,5,10,0,54,1,10,13,11,5,56,49,5,95,10,0,54,0,10,13,14,8,16,5,20,56,32,10,11,14,8,56,33,5,23,11,14,1,11,0,1,2,22,1,0,0,103,148,1,10,0,55,2,17,82,20,12,15,11,2,56,12,12,18,10,0,55,8,10,18,56,63,4,14,5,18,11,0,1,6,0,0,0,0,0,0,0,0,39,6,0,0,0,0,0,0,0,0,12,16,6,0,0,0,0,0,0,0,0,12,17,14,1,65,20,12,10,6,0,0,0,0,0,0,0,0,12,8,10,0,54,8,10,18,56,41,12,19,10,8,10,10,35,4,143,1,5,37,14,1,10,8,66,20,20,12,14,10,19,10,14,12,3,46,11,3,56,74,4,50,5,56,11,19,1,11,0,1,7,3,39,10,19,10,14,12,4,46,11,4,56,75,20,12,12,10,14,17,16,12,9,10,12,10,17,34,4,96,11,12,12,17,10,9,4,79,10,0,55,9,12,5,5,82,10,0,55,3,12,5,11,5,10,17,56,47,12,11,4,88,5,94,11,19,1,11,0,1,7,11,39,11,11,12,16,10,9,4,102,10,0,54,9,12,6,5,105,10,0,54,3,12,6,11,6,10,19,10,16,11,14,10,18,56,76,12,13,11,9,4,128,1,14,13,16,5,20,14,13,16,8,20,17,52,12,7,10,0,54,1,10,18,11,7,56,49,5,135,1,10,0,54,0,10,18,14,13,16,5,20,56,32,10,15,14,13,56,33,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,32,11,19,1,11,0,1,2,23,1,0,0,104,84,11,1,56,12,12,7,10,0,55,8,11,7,56,81,12,8,64,28,0,0,0,0,0,0,0,0,12,3,10,8,56,82,12,5,10,5,56,40,32,4,76,5,18,10,8,10,5,56,29,20,56,75,20,12,6,10,5,56,29,20,17,16,4,36,10,0,55,9,11,6,56,83,12,2,5,41,10,0,55,3,11,6,56,83,12,2,11,2,16,4,10,5,56,29,20,56,31,12,4,13,3,10,4,16,18,20,10,4,16,8,20,10,4,16,5,20,10,4,16,19,20,10,4,16,7,20,11,4,16,6,20,18,4,68,28,10,8,11,5,56,29,20,56,84,12,5,5,13,11,8,1,11,0,1,11,5,1,11,3,2,24,1,0,0,105,20,11,1,56,12,12,6,10,0,55,0,10,6,56,85,12,3,12,2,11,0,55,1,11,6,56,86,12,5,12,4,11,2,11,3,11,4,11,5,2,25,1,0,0,35,13,10,0,55,9,56,48,1,12,2,11,0,55,3,56,26,1,12,1,11,2,11,1,2,26,1,0,0,106,86,10,0,55,9,56,26,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,9,56,48,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,9,11,1,56,87,12,1,10,0,55,9,11,2,56,87,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,9,10,1,10,3,17,63,56,88,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,9,11,1,56,45,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,27,1,0,0,106,86,10,0,55,3,56,26,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,3,56,48,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,3,11,1,56,87,12,1,10,0,55,3,11,2,56,87,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,3,10,1,10,3,17,63,56,88,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,3,11,1,56,45,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,28,0,0,0,107,49,11,0,11,1,56,83,16,4,12,6,6,0,0,0,0,0,0,0,0,12,3,10,6,56,28,12,5,10,5,56,40,32,4,43,5,15,10,6,10,5,56,29,20,56,31,12,4,10,4,16,6,20,10,2,36,4,34,11,3,11,4,16,5,20,22,12,3,5,36,11,4,1,10,6,11,5,56,29,20,56,39,12,5,5,10,11,6,1,11,5,1,11,3,2,29,1,0,0,108,52,11,2,56,12,12,5,10,0,55,8,10,5,56,63,4,9,5,13,11,0,1,7,12,39,10,0,55,8,11,5,56,81,12,6,10,6,10,1,56,74,4,23,5,29,11,6,1,11,0,1,7,3,39,11,6,10,1,56,75,20,12,4,10,1,7,27,35,4,42,11,0,55,9,12,3,5,45,11,0,55,3,12,3,11,3,11,4,56,83,16,4,11,1,56,31,2,6,10,6,11,6,0,6,2,5,1,4,2,4,5,4,4,4,1,6,6,6,9,6,7,6,14,6,5,6,1,6,3,6,4,6,8,4,0,4,3,0,56,1,56,2,56,3,56,9,56,10,56,11,56,12,56,13,56,14,56,15,56,16,56,17,56,0],"clob_v2":[161,28,235,11,6,0,0,0,13,1,0,40,2,40,146,1,3,186,1,246,4,4,176,6,202,1,5,250,7,210,12,7,204,20,130,17,8,206,37,96,6,174,38,157,2,10,203,40,131,2,11,206,42,20,12,226,42,169,51,13,139,94,46,14,185,94,26,0,50,0,59,0,60,0,102,1,115,1,150,1,1,158,1,2,31,2,51,2,52,2,70,2,91,2,113,2,138,1,2,141,1,2,148,1,2,149,1,0,17,7,0,0,15,7,2,0,1,0,1,0,13,7,2,0,1,0,1,0,2,7,2,0,1,0,1,0,1,7,2,0,1,0,1,0,14,7,2,0,1,0,1,0,8,7,1,0,1,0,24,7,1,0,1,0,12,6,0,0,20,4,0,0,16,8,2,0,1,0,1,1,6,4,1,4,0,2,0,12,0,2,7,12,1,0,1,4,11,7,1,0,0,5,22,7,0,7,3,4,1,0,1,8,4,8,0,9,5,12,1,0,1,11,10,12,2,7,0,4,1,12,9,7,0,12,23,4,0,13,18,2,0,14,19,12,2,7,1,4,1,16,21,2,0,0,66,0,1,0,0,54,2,3,0,0,57,4,1,2,0,0,0,56,5,1,2,0,0,0,55,6,1,2,0,0,0,63,7,1,2,0,0,0,64,8,1,2,0,0,0,160,1,9,10,2,0,0,0,161,1,9,11,2,0,0,0,139,1,12,13,2,0,0,0,140,1,14,13,2,0,0,0,101,15,16,2,0,0,0,100,15,16,2,0,0,0,99,17,16,2,0,0,0,122,18,19,2,0,0,0,84,20,21,2,0,0,0,121,22,23,2,0,0,0,117,21,24,0,0,68,25,1,2,0,0,0,69,26,1,2,0,0,0,47,27,1,2,0,0,0,133,1,28,29,2,0,0,0,46,30,1,2,0,0,0,39,31,1,2,0,0,0,48,32,1,2,0,0,0,92,33,34,2,0,0,0,26,33,35,2,0,0,0,80,36,37,2,0,0,0,79,38,39,2,0,0,0,78,38,39,2,0,0,0,77,40,21,2,0,0,0,81,41,42,2,0,0,1,42,94,84,1,4,1,43,94,84,1,4,1,45,80,81,1,4,1,72,94,21,1,4,1,73,94,88,1,4,1,85,104,21,1,4,1,88,78,24,1,4,1,103,78,50,1,4,1,104,78,50,1,4,1,107,2,54,1,4,1,111,94,50,1,4,1,124,94,50,1,4,1,132,1,80,47,1,4,2,25,110,21,1,0,2,26,110,50,1,0,2,27,64,65,0,2,61,103,58,1,0,2,62,87,58,1,0,2,83,66,1,1,0,2,93,103,1,1,0,2,105,2,3,0,2,107,2,57,1,0,2,152,1,87,1,1,0,2,159,1,70,10,1,0,3,106,50,21,0,3,153,1,50,21,0,3,154,1,50,21,0,3,155,1,50,88,0,4,41,83,84,1,0,4,89,83,24,1,0,4,112,1,123,1,0,4,136,1,47,123,1,0,5,76,1,48,1,0,6,88,95,24,1,0,7,90,90,21,1,0,7,137,1,89,58,1,0,7,157,1,75,21,1,0,7,162,1,1,58,1,0,8,147,1,74,21,0,9,74,76,10,1,0,9,86,10,58,1,0,9,90,100,1,1,0,9,137,1,101,10,1,0,9,157,1,63,21,1,0,10,67,47,1,1,3,11,30,82,83,2,7,4,11,41,85,86,2,7,4,11,44,93,92,2,7,4,11,53,85,24,2,7,4,11,65,45,1,2,7,4,11,75,82,83,2,7,4,11,88,82,24,2,7,4,11,107,2,45,2,7,4,11,108,85,83,2,7,4,11,126,105,1,2,7,4,11,131,1,93,49,2,7,4,12,107,2,51,0,12,151,1,52,53,0,14,28,108,1,2,7,4,14,41,107,86,2,7,4,14,44,91,92,2,7,4,14,53,107,24,2,7,4,14,107,2,56,2,7,4,15,135,1,47,1,1,8,81,44,64,47,64,49,41,0,94,55,53,47,53,49,69,47,69,49,95,60,76,61,75,62,4,59,72,62,2,59,75,47,72,47,50,47,76,67,75,49,72,49,50,49,76,68,76,69,55,47,76,71,55,49,14,59,11,59,68,47,71,47,71,49,38,0,40,0,34,0,82,44,60,21,83,44,78,44,54,47,18,59,49,47,67,49,66,49,66,47,19,59,85,44,61,21,92,55,87,50,87,44,79,44,42,0,44,0,36,0,65,79,76,96,39,0,54,49,49,49,67,47,43,0,12,59,73,47,74,47,13,59,73,49,51,49,51,47,84,44,37,0,86,44,76,106,93,55,84,50,90,55,86,50,45,49,48,49,68,49,48,47,15,59,76,112,76,114,80,50,78,50,21,59,32,0,80,44,83,50,77,50,91,55,82,50,33,0,85,50,46,47,46,49,63,21,62,21,35,0,30,59,1,8,9,0,1,7,8,24,1,8,12,6,3,3,3,3,11,16,1,8,22,7,8,24,4,3,3,11,18,1,8,22,7,8,24,6,3,3,3,3,11,18,1,8,22,7,8,24,3,7,11,10,2,9,0,9,1,11,18,1,9,0,6,8,12,3,7,11,10,2,9,0,9,1,11,18,1,9,1,6,8,12,4,7,11,10,2,9,0,9,1,3,6,8,12,7,8,24,1,11,18,1,9,0,1,11,18,1,9,1,8,7,11,10,2,9,0,9,1,3,6,8,12,3,11,18,1,9,0,11,18,1,9,1,6,8,17,7,8,24,3,11,18,1,9,0,11,18,1,9,1,3,7,7,11,10,2,9,0,9,1,3,6,8,12,3,6,8,17,11,18,1,9,1,7,8,24,7,7,11,10,2,9,0,9,1,6,8,12,3,3,3,3,11,16,1,9,1,2,11,16,1,9,0,11,16,1,9,1,6,7,11,10,2,9,0,9,1,6,8,12,3,3,3,11,16,1,9,0,9,7,11,10,2,9,0,9,1,6,8,12,3,3,1,11,18,1,9,0,11,18,1,9,1,6,8,17,7,8,24,2,11,18,1,9,0,11,18,1,9,1,10,7,11,10,2,9,0,9,1,3,3,3,3,1,2,3,6,8,12,7,8,24,1,3,11,7,11,10,2,9,0,9,1,3,3,3,2,1,3,2,6,8,17,6,8,12,7,8,24,4,3,3,1,3,1,1,2,8,20,6,8,8,7,8,20,3,5,6,8,8,3,3,3,3,7,11,10,2,9,0,9,1,3,6,8,12,5,7,11,11,1,8,9,7,11,19,2,3,3,3,3,5,1,8,8,2,7,11,10,2,9,0,9,1,6,8,12,3,7,11,10,2,9,0,9,1,10,3,6,8,12,4,7,11,10,2,9,0,9,1,6,8,17,10,3,10,5,2,6,11,10,2,9,0,9,1,6,8,12,1,10,8,8,4,3,3,3,3,1,6,11,10,2,9,0,9,1,2,11,14,1,3,11,14,1,3,4,6,11,10,2,9,0,9,1,3,3,6,8,17,2,10,3,10,3,3,6,11,11,1,8,9,3,3,3,6,11,10,2,9,0,9,1,3,6,8,12,1,6,8,8,1,11,19,2,3,8,8,2,3,8,8,1,11,19,2,9,0,9,1,4,8,15,8,20,8,21,8,15,1,9,0,1,8,15,1,9,1,2,3,3,1,8,21,1,6,8,21,1,6,8,20,1,11,11,1,9,0,2,5,11,19,2,3,3,1,11,23,2,9,0,9,1,1,11,13,1,9,0,1,11,16,1,9,0,2,9,0,9,1,1,11,10,2,9,0,9,1,1,8,0,1,8,22,1,6,11,18,1,9,0,1,6,8,12,1,5,3,7,11,13,1,9,0,5,11,16,1,9,0,1,11,6,1,9,0,1,11,6,1,9,1,1,11,7,1,9,0,4,7,11,13,1,9,0,3,6,8,12,7,8,24,1,11,7,1,9,1,4,3,11,18,1,9,0,11,18,1,9,1,3,3,11,16,1,9,0,11,16,1,9,1,3,1,6,8,17,1,6,11,16,1,9,0,2,11,16,1,9,0,7,8,24,40,1,1,3,3,1,3,3,1,5,3,3,3,7,11,11,1,8,9,11,16,1,9,0,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,3,3,11,16,1,9,0,3,6,8,8,7,8,8,3,3,3,6,11,14,1,3,3,3,8,20,11,16,1,9,1,11,16,1,9,1,1,3,3,3,1,3,7,8,9,3,1,6,11,11,1,9,0,1,11,3,2,9,0,9,1,2,7,11,11,1,9,0,3,1,7,9,0,1,6,11,19,2,9,0,9,1,1,6,11,14,1,9,0,1,6,9,0,2,6,11,19,2,9,0,9,1,9,0,1,6,9,1,3,7,11,13,1,9,0,5,3,2,1,3,2,7,11,16,1,9,0,3,2,7,11,16,1,9,0,11,16,1,9,0,2,7,11,23,2,9,0,9,1,9,0,1,7,9,1,2,7,11,19,2,9,0,9,1,9,0,2,6,11,11,1,9,0,3,1,6,10,9,0,1,11,4,2,9,0,9,1,36,1,3,1,3,3,1,3,3,1,5,3,3,3,7,11,11,1,8,9,11,16,1,9,0,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,3,11,16,1,9,0,3,6,8,8,7,8,8,3,6,11,14,1,3,3,3,8,20,11,16,1,9,1,1,3,3,11,16,1,9,1,3,7,8,9,3,37,1,3,1,3,3,1,3,3,1,5,3,3,3,7,11,11,1,8,9,11,16,1,9,0,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,3,11,16,1,9,1,3,6,8,8,7,8,8,3,3,6,11,14,1,3,3,3,8,20,11,16,1,9,1,1,3,3,11,16,1,9,1,3,7,8,9,3,5,11,16,1,9,0,11,16,1,9,0,11,18,1,9,0,11,16,1,9,1,11,16,1,9,1,2,7,11,18,1,9,0,11,18,1,9,0,3,7,11,18,1,9,0,3,7,8,24,7,3,7,11,11,1,8,9,8,8,3,5,3,3,3,7,11,13,1,9,0,6,8,12,3,3,7,11,11,1,9,0,3,9,0,3,7,11,19,2,9,0,9,1,9,0,9,1,1,11,1,2,9,0,9,1,2,6,11,23,2,9,0,9,1,9,0,3,7,11,23,2,9,0,9,1,9,0,9,1,12,11,16,1,9,0,11,16,1,9,0,11,16,1,9,0,3,3,3,5,11,16,1,9,1,11,16,1,9,1,11,16,1,9,1,3,3,2,6,11,13,1,9,0,5,8,8,20,3,3,1,5,3,3,3,1,11,2,2,9,0,9,1,13,8,20,3,3,3,3,3,3,5,3,1,5,3,3,1,11,5,2,9,0,9,1,11,3,3,6,11,11,1,8,9,7,11,11,1,8,9,3,1,8,8,5,3,3,7,11,19,2,3,3,3,3,7,8,9,8,8,22,3,3,3,3,7,11,11,1,8,9,3,3,3,1,5,3,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,1,7,11,11,1,8,9,8,8,3,3,5,8,20,3,7,11,19,2,3,3,26,5,3,3,3,3,3,6,11,11,1,8,9,7,11,11,1,8,9,3,3,1,3,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,1,3,3,3,8,8,3,5,8,20,3,3,7,11,19,2,3,3,28,1,5,3,3,3,3,3,7,11,11,1,8,9,3,3,3,3,11,3,2,9,0,9,1,10,11,3,2,9,0,9,1,3,1,3,3,3,3,7,11,11,1,8,9,8,8,3,5,8,20,3,3,7,11,19,2,3,3,7,6,8,9,10,8,8,6,8,8,6,11,14,1,3,3,5,6,11,19,2,3,3,5,3,3,5,3,3,4,11,14,1,3,11,14,1,3,11,14,1,3,11,14,1,3,1,11,14,1,9,0,6,3,10,3,3,3,3,10,3,4,3,6,8,8,6,11,14,1,3,6,11,19,2,3,8,8,4,6,11,11,1,8,9,3,5,6,11,19,2,3,3,10,65,99,99,111,117,110,116,67,97,112,17,65,108,108,79,114,100,101,114,115,67,97,110,99,101,108,101,100,26,65,108,108,79,114,100,101,114,115,67,97,110,99,101,108,101,100,67,111,109,112,111,110,101,110,116,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,11,67,114,105,116,98,105,116,84,114,101,101,9,67,117,115,116,111,100,105,97,110,12,68,101,112,111,115,105,116,65,115,115,101,116,2,73,68,11,76,105,110,107,101,100,84,97,98,108,101,6,79,112,116,105,111,110,5,79,114,100,101,114,13,79,114,100,101,114,67,97,110,99,101,108,101,100,11,79,114,100,101,114,70,105,108,108,101,100,11,79,114,100,101,114,80,108,97,99,101,100,4,80,111,111,108,11,80,111,111,108,67,114,101,97,116,101,100,3,83,85,73,5,84,97,98,108,101,9,84,105,99,107,76,101,118,101,108,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,13,87,105,116,104,100,114,97,119,65,115,115,101,116,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,13,97,99,99,111,117,110,116,95,111,119,110,101,114,3,97,100,100,4,97,115,107,115,4,98,97,99,107,7,98,97,108,97,110,99,101,10,98,97,115,101,95,97,115,115,101,116,28,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,99,97,110,99,101,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,102,105,108,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,112,108,97,99,101,100,29,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,114,101,109,97,105,110,105,110,103,23,98,97,115,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,14,98,97,115,101,95,99,117,115,116,111,100,105,97,110,18,98,97,116,99,104,95,99,97,110,99,101,108,95,111,114,100,101,114,4,98,105,100,115,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,17,99,97,110,99,101,108,95,97,108,108,95,111,114,100,101,114,115,12,99,97,110,99,101,108,95,111,114,100,101,114,23,99,108,101,97,110,95,117,112,95,101,120,112,105,114,101,100,95,111,114,100,101,114,115,15,99,108,105,101,110,116,95,111,114,100,101,114,95,105,100,7,99,108,111,98,95,118,50,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,14,99,114,101,97,116,101,95,97,99,99,111,117,110,116,22,99,114,101,97,116,101,95,99,117,115,116,111,109,105,122,101,100,95,112,111,111,108,11,99,114,101,97,116,101,95,112,111,111,108,12,99,114,101,97,116,101,95,112,111,111,108,95,12,99,114,101,97,116,105,111,110,95,102,101,101,7,99,114,105,116,98,105,116,12,99,117,115,116,111,100,105,97,110,95,118,50,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,100,101,112,111,115,105,116,95,98,97,115,101,13,100,101,112,111,115,105,116,95,113,117,111,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,19,100,101,115,116,114,111,121,95,101,109,112,116,121,95,108,101,118,101,108,4,101,109,105,116,19,101,109,105,116,95,111,114,100,101,114,95,99,97,110,99,101,108,101,100,17,101,109,105,116,95,111,114,100,101,114,95,102,105,108,108,101,100,5,101,118,101,110,116,16,101,120,112,105,114,101,95,116,105,109,101,115,116,97,109,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,12,102,114,111,109,95,98,97,108,97,110,99,101,5,102,114,111,110,116,3,103,101,116,22,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,97,115,107,95,115,105,100,101,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,98,105,100,95,115,105,100,101,16,103,101,116,95,109,97,114,107,101,116,95,112,114,105,99,101,16,103,101,116,95,111,114,100,101,114,95,115,116,97,116,117,115,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,18,105,110,106,101,99,116,95,108,105,109,105,116,95,111,114,100,101,114,11,105,110,115,101,114,116,95,108,101,97,102,12,105,110,116,111,95,98,97,108,97,110,99,101,6,105,115,95,98,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,4,106,111,105,110,12,108,105,110,107,101,100,95,116,97,98,108,101,16,108,105,115,116,95,111,112,101,110,95,111,114,100,101,114,115,12,108,111,99,107,95,98,97,108,97,110,99,101,8,108,111,116,95,115,105,122,101,13,109,97,107,101,114,95,97,100,100,114,101,115,115,21,109,97,107,101,114,95,99,108,105,101,110,116,95,111,114,100,101,114,95,105,100,17,109,97,107,101,114,95,114,101,98,97,116,101,95,114,97,116,101,13,109,97,107,101,114,95,114,101,98,97,116,101,115,9,109,97,116,99,104,95,97,115,107,9,109,97,116,99,104,95,98,105,100,29,109,97,116,99,104,95,98,105,100,95,119,105,116,104,95,113,117,111,116,101,95,113,117,97,110,116,105,116,121,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,109,117,108,3,110,101,119,4,110,101,120,116,17,110,101,120,116,95,97,115,107,95,111,114,100,101,114,95,105,100,17,110,101,120,116,95,98,105,100,95,111,114,100,101,114,95,105,100,9,110,101,120,116,95,108,101,97,102,4,110,111,110,101,6,111,98,106,101,99,116,11,111,112,101,110,95,111,114,100,101,114,115,6,111,112,116,105,111,110,8,111,114,100,101,114,95,105,100,12,111,114,100,101,114,95,105,115,95,98,105,100,15,111,114,100,101,114,115,95,99,97,110,99,101,108,101,100,17,111,114,105,103,105,110,97,108,95,113,117,97,110,116,105,116,121,5,111,119,110,101,114,17,112,108,97,99,101,95,108,105,109,105,116,95,111,114,100,101,114,18,112,108,97,99,101,95,109,97,114,107,101,116,95,111,114,100,101,114,7,112,111,111,108,95,105,100,13,112,114,101,118,105,111,117,115,95,108,101,97,102,5,112,114,105,99,101,9,112,117,115,104,95,98,97,99,107,8,113,117,97,110,116,105,116,121,11,113,117,111,116,101,95,97,115,115,101,116,24,113,117,111,116,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,15,113,117,111,116,101,95,99,117,115,116,111,100,105,97,110,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,12,114,101,109,111,118,101,95,111,114,100,101,114,24,115,101,108,102,95,109,97,116,99,104,105,110,103,95,112,114,101,118,101,110,116,105,111,110,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,115,112,108,105,116,3,115,117,105,25,115,119,97,112,95,101,120,97,99,116,95,98,97,115,101,95,102,111,114,95,113,117,111,116,101,25,115,119,97,112,95,101,120,97,99,116,95,113,117,111,116,101,95,102,111,114,95,98,97,115,101,5,116,97,98,108,101,13,116,97,107,101,114,95,97,100,100,114,101,115,115,21,116,97,107,101,114,95,99,108,105,101,110,116,95,111,114,100,101,114,95,105,100,16,116,97,107,101,114,95,99,111,109,109,105,115,115,105,111,110,14,116,97,107,101,114,95,102,101,101,95,114,97,116,101,9,116,105,99,107,95,115,105,122,101,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,10,117,110,115,97,102,101,95,100,105,118,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,15,117,115,114,95,111,112,101,110,95,111,114,100,101,114,115,5,118,97,108,117,101,6,118,101,99,116,111,114,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,13,119,105,116,104,100,114,97,119,95,98,97,115,101,14,119,105,116,104,100,114,97,119,95,113,117,111,116,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,3,8,19,0,0,0,0,0,0,0,3,8,20,0,0,0,0,0,0,0,3,8,21,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,2,1,0,2,1,4,2,1,1,2,1,2,2,1,3,3,8,0,0,0,0,0,0,0,128,3,8,0,0,0,0,0,0,0,0,3,8,160,37,38,0,0,0,0,0,3,8,96,227,22,0,0,0,0,0,3,8,0,232,118,72,23,0,0,0,0,2,7,123,8,20,32,8,15,128,1,8,15,145,1,3,97,3,146,1,3,94,3,1,2,9,123,8,20,116,3,49,3,87,1,120,5,119,3,35,3,125,3,71,3,2,2,8,123,8,20,116,3,49,3,87,1,120,5,119,3,33,3,125,3,3,2,7,116,3,49,3,87,1,120,5,119,3,33,3,125,3,4,2,2,123,8,20,118,10,11,3,2,9,0,9,1,5,2,13,123,8,20,116,3,143,1,3,96,3,87,1,142,1,5,95,5,119,3,34,3,36,3,125,3,144,1,3,98,3,6,2,3,123,8,20,127,3,120,5,7,2,3,123,8,20,127,3,120,5,8,2,9,116,3,49,3,125,3,119,3,127,3,87,1,120,5,71,3,134,1,2,9,2,2,125,3,114,11,19,2,3,8,8,10,2,15,82,8,21,40,11,11,1,8,9,29,11,11,1,8,9,110,3,109,3,156,1,11,23,2,5,11,19,2,3,3,145,1,3,97,3,146,1,3,94,3,38,11,13,1,9,0,130,1,11,13,1,9,1,58,11,16,1,8,22,37,11,16,1,9,0,129,1,11,16,1,9,1,10,59,6,47,6,49,7,47,7,49,3,59,4,59,1,59,2,59,5,59,0,0,0,0,43,7,11,0,19,9,12,1,1,11,1,56,0,2,1,1,0,0,1,3,11,0,17,52,2,2,0,0,0,46,72,56,1,12,6,56,2,12,9,10,3,10,2,17,58,6,0,0,0,0,0,0,0,0,36,4,11,5,15,11,5,1,7,19,39,10,6,10,9,34,4,20,5,24,11,5,1,7,15,39,10,0,10,1,38,4,29,5,33,11,5,1,7,1,39,10,5,17,88,12,8,14,8,17,89,20,12,7,11,8,10,5,56,3,10,5,56,3,7,0,7,27,10,5,56,4,10,0,10,1,10,2,10,3,10,5,56,5,11,5,56,6,11,4,56,7,56,8,57,0,56,9,11,7,11,6,11,9,11,0,11,1,11,2,11,3,18,0,56,10,2,3,1,0,0,1,18,14,2,56,11,7,31,33,4,6,5,10,11,3,1,7,17,39,11,0,11,1,7,29,7,30,11,2,11,3,56,12,2,4,1,0,0,1,19,14,4,56,11,7,31,33,4,6,5,10,11,5,1,7,17,39,11,2,11,3,11,0,11,1,11,4,56,13,11,5,56,14,2,5,1,0,0,21,31,14,1,56,15,12,3,10,3,6,0,0,0,0,0,0,0,0,34,4,8,5,14,11,0,1,11,2,1,7,6,39,10,0,54,0,10,2,17,47,11,1,56,16,56,17,11,0,55,1,17,89,20,11,3,11,2,17,47,57,1,56,18,2,6,1,0,0,21,31,14,1,56,19,12,3,10,3,6,0,0,0,0,0,0,0,0,34,4,8,5,14,11,0,1,11,2,1,7,7,39,10,0,54,2,10,2,17,47,11,1,56,20,56,21,11,0,55,1,17,89,20,11,3,11,2,17,47,57,2,56,22,2,7,1,0,0,1,29,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,10,0,55,1,17,89,20,10,1,10,2,17,47,57,3,56,23,11,0,54,0,11,1,11,2,11,3,56,24,2,8,1,0,0,1,29,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,10,0,55,1,17,89,20,10,1,10,2,17,47,57,4,56,25,11,0,54,2,11,1,11,2,11,3,56,26,2,9,1,0,0,72,55,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,7,1,11,6,1,11,2,1,7,5,39,14,4,56,15,10,3,38,4,21,5,31,11,0,1,11,7,1,11,6,1,11,2,1,7,6,39,14,5,56,19,12,8,11,0,11,2,11,1,11,3,9,11,4,11,5,11,6,11,7,56,27,12,10,12,9,14,10,56,19,12,11,11,9,11,10,11,11,11,8,23,2,10,1,0,0,73,54,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,6,1,11,4,1,11,2,1,7,5,39,14,5,56,19,10,3,38,4,21,5,31,11,0,1,11,6,1,11,4,1,11,2,1,7,7,39,11,0,11,2,11,1,11,3,7,27,11,4,17,70,11,5,56,20,56,28,12,8,12,7,14,7,56,29,12,9,11,7,10,6,56,30,11,8,11,6,56,31,11,9,2,11,0,0,0,77,134,3,10,0,55,1,17,89,20,12,36,11,3,12,42,56,7,12,20,11,6,12,38,10,0,54,3,12,19,10,19,46,56,32,4,27,11,0,1,11,19,1,11,1,1,11,20,11,38,2,10,19,46,56,33,12,44,12,46,9,12,43,64,79,0,0,0,0,0,0,0,0,12,22,10,19,46,56,32,32,4,47,5,42,10,46,10,4,37,12,7,5,49,9,12,7,11,7,4,251,2,10,19,10,44,56,34,12,45,10,45,16,4,56,35,56,36,20,12,35,10,45,16,4,56,37,32,4,217,2,5,67,10,45,16,4,10,35,56,38,12,28,10,28,16,5,20,12,27,9,12,39,10,28,16,6,20,10,5,37,4,87,8,12,11,5,94,10,1,17,47,10,28,16,7,20,33,12,11,11,11,4,151,1,8,12,39,10,0,54,0,10,28,16,7,20,10,28,16,5,20,56,39,10,36,10,28,56,40,10,28,16,8,20,12,12,10,28,16,9,20,12,13,10,28,16,10,20,12,14,10,28,16,7,20,12,15,10,28,16,11,20,12,16,10,28,16,5,20,12,17,10,28,16,12,20,12,18,11,13,11,12,11,14,11,15,11,16,11,17,11,18,57,5,12,21,13,22,11,21,68,79,5,158,2,10,27,10,28,16,12,20,17,56,12,31,10,31,10,0,55,4,20,17,59,12,40,4,168,1,11,40,6,1,0,0,0,0,0,0,0,22,12,40,10,31,11,40,22,12,30,10,42,10,30,36,4,183,1,11,30,12,24,11,31,12,25,10,27,12,23,5,226,1,8,12,43,10,42,7,21,10,0,55,4,20,22,17,57,10,28,16,12,20,17,57,10,0,55,5,20,26,10,0,55,5,20,24,12,23,10,23,10,28,16,12,20,17,58,12,25,10,25,10,0,55,4,20,17,59,12,41,4,222,1,11,41,6,1,0,0,0,0,0,0,0,22,12,41,10,25,11,41,22,12,24,10,25,10,0,55,6,20,17,58,12,32,11,27,10,23,23,12,27,11,42,10,24,23,12,42,10,0,54,0,10,28,16,7,20,10,23,56,41,12,26,13,38,10,24,56,42,12,37,10,0,54,2,10,28,16,7,20,13,37,10,32,10,25,22,56,42,56,21,10,0,54,7,11,37,56,43,1,13,20,11,26,56,44,1,10,0,55,1,17,89,20,10,2,10,1,17,47,10,28,11,23,11,24,11,25,23,11,32,56,45,11,39,4,163,2,8,12,8,5,167,2,10,27,6,0,0,0,0,0,0,0,0,33,12,8,11,8,4,202,2,10,35,12,34,10,45,16,4,10,35,56,46,12,33,10,33,56,47,32,4,185,2,11,33,56,36,20,12,35,5,187,2,11,33,1,10,0,54,8,11,28,16,7,20,56,48,10,34,56,49,1,10,45,15,4,11,34,56,50,1,5,213,2,11,28,1,10,45,15,4,10,35,56,51,12,29,11,27,11,29,15,5,21,10,43,4,216,2,5,217,2,5,61,11,45,16,4,56,37,4,241,2,10,19,11,46,12,9,46,11,9,56,52,1,12,46,10,19,11,44,56,53,17,0,10,19,10,46,12,10,46,11,10,56,54,12,44,1,10,43,4,250,2,11,0,1,11,19,1,11,1,1,5,251,2,5,36,14,22,56,55,32,4,131,3,11,36,11,22,57,6,56,56,11,20,11,38,2,12,0,0,0,97,222,2,10,0,55,1,17,89,20,12,34,11,3,12,37,56,7,12,21,11,6,12,35,10,0,54,3,12,20,10,20,46,56,32,4,27,11,0,1,11,20,1,11,1,1,11,21,11,35,2,10,20,46,56,33,12,40,12,42,64,79,0,0,0,0,0,0,0,0,12,23,10,20,46,56,32,32,4,45,5,40,10,42,10,4,37,12,7,5,47,9,12,7,11,7,4,211,2,10,20,10,40,56,34,12,41,10,41,16,4,56,35,56,36,20,12,33,10,41,16,4,56,37,32,4,175,2,5,65,10,41,16,4,10,33,56,38,12,28,10,28,16,5,20,12,27,9,12,36,10,28,16,6,20,10,5,37,4,85,8,12,12,5,92,10,1,17,47,10,28,16,7,20,33,12,12,11,12,4,149,1,8,12,36,10,0,54,0,10,28,16,7,20,10,28,16,5,20,56,39,10,34,10,28,56,40,10,28,16,8,20,12,13,10,28,16,9,20,12,14,10,28,16,10,20,12,15,10,28,16,7,20,12,16,10,28,16,11,20,12,17,10,28,16,5,20,12,18,10,28,16,12,20,12,19,11,14,11,13,11,15,11,16,11,17,11,18,11,19,57,5,12,22,13,23,11,22,68,79,5,242,1,10,37,10,27,36,4,156,1,10,27,12,8,5,158,1,10,37,12,8,11,8,12,24,10,24,10,28,16,12,20,17,56,12,25,10,25,10,0,55,6,20,17,58,12,30,10,25,10,0,55,4,20,17,59,12,38,4,183,1,11,38,6,1,0,0,0,0,0,0,0,22,12,38,11,27,10,24,23,12,27,11,37,10,24,23,12,37,10,0,54,0,10,28,16,7,20,10,24,56,41,12,26,13,35,10,38,56,42,12,39,10,0,54,2,10,28,16,7,20,13,39,10,30,56,42,56,21,10,0,54,7,11,39,56,43,1,13,21,11,26,56,44,1,10,0,54,2,10,28,16,7,20,13,35,11,25,56,42,56,21,10,0,55,1,17,89,20,10,2,10,1,17,47,10,28,11,24,11,38,11,30,56,45,11,36,4,247,1,8,12,9,5,251,1,10,27,6,0,0,0,0,0,0,0,0,33,12,9,11,9,4,158,2,10,33,12,32,10,41,16,4,10,33,56,46,12,31,10,31,56,47,32,4,141,2,11,31,56,36,20,12,33,5,143,2,11,31,1,10,0,54,8,11,28,16,7,20,56,48,10,32,56,49,1,10,41,15,4,11,32,56,50,1,5,169,2,11,28,1,10,41,15,4,10,33,56,51,12,29,11,27,11,29,15,5,21,10,37,6,0,0,0,0,0,0,0,0,33,4,174,2,5,175,2,5,59,11,41,16,4,56,37,4,199,2,10,20,11,42,12,10,46,11,10,56,52,1,12,42,10,20,11,40,56,53,17,0,10,20,10,42,12,11,46,11,11,56,54,12,40,1,10,37,6,0,0,0,0,0,0,0,0,33,4,210,2,11,0,1,11,20,1,11,1,1,5,211,2,5,34,14,23,56,55,32,4,219,2,11,34,11,23,57,6,56,56,11,21,11,35,2,13,0,0,0,98,227,2,10,0,55,1,17,89,20,12,34,11,5,12,20,56,8,12,35,10,0,54,9,12,19,10,19,46,56,32,4,25,11,0,1,11,19,1,11,1,1,11,20,11,35,2,10,19,46,56,57,12,40,12,42,64,79,0,0,0,0,0,0,0,0,12,22,10,19,46,56,32,32,4,43,5,38,10,42,10,3,38,12,6,5,45,9,12,6,11,6,4,216,2,10,19,10,40,56,34,12,41,10,41,16,4,56,35,56,36,20,12,33,10,41,16,4,56,37,32,4,179,2,5,63,10,41,16,4,10,33,56,38,12,27,10,27,16,5,20,12,26,9,12,36,10,27,16,6,20,10,4,37,4,83,8,12,11,5,90,10,1,17,47,10,27,16,7,20,33,12,11,11,11,4,153,1,8,12,36,10,27,16,5,20,10,27,16,12,20,17,56,12,29,10,0,54,2,10,27,16,7,20,11,29,56,58,10,34,10,27,56,40,10,27,16,8,20,12,12,10,27,16,9,20,12,13,10,27,16,10,20,12,14,10,27,16,7,20,12,15,10,27,16,11,20,12,16,10,27,16,5,20,12,17,10,27,16,12,20,12,18,11,13,11,12,11,14,11,15,11,16,11,17,11,18,57,5,12,21,13,22,11,21,68,79,5,245,1,14,20,56,29,12,37,10,37,10,26,38,4,163,1,10,26,12,7,5,165,1,11,37,12,7,11,7,12,23,10,23,10,27,16,12,20,17,56,12,24,10,24,10,0,55,6,20,17,58,12,30,10,24,10,0,55,4,20,17,59,12,38,4,190,1,11,38,6,1,0,0,0,0,0,0,0,22,12,38,11,26,10,23,23,12,26,10,0,54,2,10,27,16,7,20,11,24,56,59,12,25,13,25,10,38,56,42,12,39,10,0,54,2,10,27,16,7,20,13,39,10,30,56,42,56,21,10,0,54,7,11,39,56,43,1,13,35,11,25,56,43,1,10,0,54,0,10,27,16,7,20,13,20,10,23,56,60,56,17,10,0,55,1,17,89,20,10,2,10,1,17,47,10,27,11,23,11,38,11,30,56,45,11,36,4,250,1,8,12,8,5,254,1,10,26,6,0,0,0,0,0,0,0,0,33,12,8,11,8,4,161,2,10,33,12,32,10,41,16,4,10,33,56,46,12,31,10,31,56,47,32,4,144,2,11,31,56,36,20,12,33,5,146,2,11,31,1,10,0,54,8,11,27,16,7,20,56,48,10,32,56,49,1,10,41,15,4,11,32,56,50,1,5,172,2,11,27,1,10,41,15,4,10,33,56,51,12,28,11,26,11,28,15,5,21,14,20,56,29,6,0,0,0,0,0,0,0,0,33,4,178,2,5,179,2,5,57,11,41,16,4,56,37,4,203,2,10,19,11,42,12,9,46,11,9,56,61,1,12,42,10,19,11,40,56,53,17,0,10,19,10,42,12,10,46,11,10,56,54,12,40,1,14,20,56,29,6,0,0,0,0,0,0,0,0,33,4,215,2,11,0,1,11,19,1,11,1,1,5,216,2,5,32,14,22,56,55,32,4,224,2,11,34,11,22,57,6,56,56,11,20,11,35,2,14,1,0,0,99,103,10,3,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,9,5,19,11,0,1,11,8,1,11,7,1,11,1,1,7,5,39,10,3,6,0,0,0,0,0,0,0,0,34,4,24,5,34,11,0,1,11,8,1,11,7,1,11,1,1,7,5,39,11,4,4,58,11,0,11,1,11,2,11,3,7,27,11,7,17,70,11,6,56,20,56,62,12,13,12,9,13,5,11,9,10,8,56,30,56,63,11,13,11,8,56,31,12,6,5,100,10,3,14,5,56,15,37,4,64,5,74,11,0,1,11,8,1,11,7,1,11,1,1,7,6,39,13,5,11,3,10,8,56,64,12,11,11,0,11,1,11,2,7,28,11,7,17,70,11,11,56,16,56,65,12,12,12,10,13,5,11,10,10,8,56,30,56,63,13,6,11,12,11,8,56,31,56,66,11,5,11,6,2,15,0,0,0,102,123,10,8,17,47,12,14,10,5,4,30,10,4,10,2,17,56,12,15,10,0,54,2,11,8,11,15,56,67,10,0,55,10,20,12,13,10,0,55,10,20,6,1,0,0,0,0,0,0,0,22,10,0,54,10,21,10,0,54,9,12,11,5,50,10,0,54,0,11,8,10,4,56,68,10,0,55,11,20,12,13,10,0,55,11,20,6,1,0,0,0,0,0,0,0,22,10,0,54,11,21,10,0,54,3,12,11,10,13,10,1,10,2,10,3,10,4,10,5,10,14,10,7,11,6,18,8,12,12,10,11,10,2,12,10,46,11,10,56,54,12,16,32,4,78,10,11,10,2,10,2,10,9,56,69,18,9,56,70,12,16,11,11,11,16,56,34,15,4,10,13,11,12,56,71,10,0,55,1,17,89,20,10,13,11,1,11,5,10,14,11,3,11,4,10,2,11,7,57,7,56,72,10,0,55,8,10,14,56,73,32,4,112,10,0,54,8,10,14,11,9,56,74,56,75,5,114,11,9,1,11,0,54,8,11,14,56,48,10,13,11,2,56,76,11,13,2,16,1,0,0,109,171,2,10,4,7,22,33,4,5,5,15,11,0,1,11,10,1,11,8,1,11,9,1,7,20,39,10,3,6,0,0,0,0,0,0,0,0,36,4,20,5,30,11,0,1,11,10,1,11,8,1,11,9,1,7,5,39,10,2,6,0,0,0,0,0,0,0,0,36,4,35,5,45,11,0,1,11,10,1,11,8,1,11,9,1,7,4,39,10,2,10,0,55,12,20,25,6,0,0,0,0,0,0,0,0,33,4,54,5,64,11,0,1,11,10,1,11,8,1,11,9,1,7,4,39,10,3,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,73,5,83,11,0,1,11,10,1,11,8,1,11,9,1,7,5,39,10,6,10,8,17,70,36,4,89,5,99,11,0,1,11,10,1,11,8,1,11,9,1,7,18,39,10,9,17,47,12,17,10,3,12,16,10,5,4,147,1,10,0,55,2,10,17,56,77,12,22,10,0,54,2,10,9,10,22,56,78,12,18,10,0,10,9,10,1,10,3,10,2,11,8,17,70,11,18,56,62,12,20,12,12,14,12,56,29,12,14,11,22,14,20,56,79,23,12,21,10,0,54,0,10,17,11,12,56,17,10,0,54,2,11,17,11,20,56,21,5,181,1,10,0,54,0,10,9,10,3,56,80,12,11,10,0,10,9,10,1,10,2,11,8,17,70,11,11,56,65,12,19,12,13,10,3,14,13,56,29,23,12,14,14,19,56,79,12,21,10,0,54,0,10,17,11,13,56,17,10,0,54,2,11,17,11,19,56,21,10,7,7,24,33,4,196,1,11,0,1,11,10,1,11,9,1,11,14,11,21,9,6,0,0,0,0,0,0,0,0,2,10,7,7,25,33,4,218,1,11,0,1,11,10,1,11,9,1,10,14,11,3,33,4,211,1,5,213,1,7,8,39,11,14,11,21,9,6,0,0,0,0,0,0,0,0,2,10,7,7,26,33,4,252,1,10,14,6,0,0,0,0,0,0,0,0,33,4,227,1,5,235,1,11,0,1,11,10,1,11,9,1,7,9,39,11,0,11,1,11,2,11,16,11,3,11,5,11,4,11,6,11,9,11,10,56,81,12,15,11,14,11,21,8,11,15,2,11,7,7,22,33,4,129,2,5,137,2,11,0,1,11,10,1,11,9,1,7,13,39,10,3,10,14,36,4,160,2,11,0,11,1,11,2,11,16,11,3,10,14,23,11,5,11,4,11,6,11,9,11,10,56,81,12,15,11,14,11,21,8,11,15,2,11,0,1,11,10,1,11,9,1,11,14,11,21,9,6,0,0,0,0,0,0,0,0,2,17,0,0,0,1,4,11,0,7,27,35,2,18,0,0,0,111,41,11,0,12,2,10,1,16,8,20,12,3,10,1,16,9,20,12,4,10,1,16,10,20,12,5,10,1,16,7,20,12,6,10,1,16,11,20,12,7,10,1,16,5,20,12,8,11,1,16,12,20,12,9,11,2,11,4,11,3,11,5,11,6,11,7,11,8,11,9,57,8,56,82,2,19,0,0,0,113,58,11,0,12,7,10,3,16,9,20,12,12,11,1,12,13,11,2,12,14,10,3,16,8,20,12,15,10,3,16,10,20,12,16,10,3,16,7,20,12,17,10,3,16,11,20,12,18,10,4,12,19,10,3,16,5,20,11,4,23,12,8,11,3,16,12,20,12,9,11,5,12,10,11,6,12,11,11,7,11,12,11,13,11,15,11,16,11,14,11,17,11,18,11,19,11,8,11,9,11,10,11,11,57,9,56,83,2,20,1,0,0,115,115,11,2,17,47,12,10,10,0,55,8,10,10,56,73,4,9,5,13,11,0,1,7,11,39,10,0,54,8,10,10,56,48,12,13,10,13,10,1,12,3,46,11,3,56,84,4,26,5,32,11,13,1,11,0,1,7,2,39,10,13,10,1,12,4,46,11,4,56,85,20,12,12,10,1,17,17,12,8,10,8,4,49,10,0,55,9,12,5,5,52,10,0,55,3,12,5,11,5,11,12,56,54,12,11,4,58,5,64,11,13,1,11,0,1,7,2,39,10,8,4,70,10,0,54,9,12,6,5,73,10,0,54,3,12,6,11,6,11,13,11,11,11,1,10,10,56,86,12,9,11,8,4,101,14,9,16,5,20,14,9,16,12,20,17,59,12,7,4,95,11,7,6,1,0,0,0,0,0,0,0,22,12,7,10,0,54,2,11,10,11,7,56,58,5,108,10,0,54,0,11,10,14,9,16,5,20,56,39,11,0,55,1,17,89,20,14,9,56,40,2,21,0,0,0,116,54,11,1,10,3,56,49,1,10,0,10,2,12,5,46,11,5,56,87,16,4,10,3,56,88,4,15,5,19,11,0,1,7,2,39,10,0,10,2,56,34,12,6,10,6,15,4,11,3,56,50,12,7,14,7,16,7,20,11,4,33,4,35,5,41,11,0,1,11,6,1,7,3,39,11,6,16,4,56,37,4,50,11,0,11,2,56,53,17,0,5,52,11,0,1,11,7,2,22,1,0,0,117,154,1,10,0,55,1,17,89,20,12,21,11,1,17,47,12,20,10,0,55,8,10,20,56,73,4,14,5,18,11,0,1,7,11,39,10,0,54,8,10,20,56,48,12,23,64,79,0,0,0,0,0,0,0,0,12,14,10,23,46,56,89,32,4,141,1,5,31,10,23,46,56,90,56,36,20,12,18,10,23,10,18,12,5,46,11,5,56,85,20,12,19,10,18,17,17,12,15,10,15,4,54,10,0,54,9,12,6,5,57,10,0,54,3,12,6,11,6,12,16,10,16,11,19,12,7,46,11,7,56,54,12,22,1,11,16,10,23,11,22,11,18,10,20,56,86,12,17,11,15,4,90,14,17,16,5,20,14,17,16,12,20,17,56,12,12,10,0,54,2,10,20,11,12,56,58,5,97,10,0,54,0,10,20,14,17,16,5,20,56,39,10,21,14,17,56,40,14,17,16,8,20,12,8,14,17,16,9,20,12,9,14,17,16,10,20,12,10,14,17,16,7,20,12,11,14,17,16,11,20,12,2,14,17,16,5,20,12,3,14,17,16,12,20,12,4,11,9,11,8,11,10,11,11,11,2,11,3,11,4,57,5,12,13,13,14,11,13,68,79,5,25,11,23,1,11,0,1,14,14,56,55,32,4,153,1,11,21,11,14,57,6,56,56,2,23,1,0,0,118,203,1,10,0,55,1,17,89,20,12,25,11,2,17,47,12,24,10,0,55,8,10,24,56,73,4,14,5,18,11,0,1,6,0,0,0,0,0,0,0,0,39,6,0,0,0,0,0,0,0,0,12,26,6,0,0,0,0,0,0,0,0,12,27,14,1,65,21,12,19,6,0,0,0,0,0,0,0,0,12,17,10,0,54,8,10,24,56,48,12,28,64,79,0,0,0,0,0,0,0,0,12,16,10,17,10,19,35,4,190,1,5,39,14,1,10,17,66,21,20,12,23,10,28,10,23,12,7,46,11,7,56,84,4,52,5,58,11,28,1,11,0,1,7,2,39,10,28,10,23,12,8,46,11,8,56,85,20,12,21,10,23,17,17,12,18,10,21,10,27,34,4,98,11,21,12,27,10,18,4,81,10,0,55,9,12,9,5,84,10,0,55,3,12,9,11,9,10,27,56,54,12,20,4,90,5,96,11,28,1,11,0,1,7,10,39,11,20,12,26,10,18,4,104,10,0,54,9,12,10,5,107,10,0,54,3,12,10,11,10,10,28,10,26,11,23,10,24,56,86,12,22,11,18,4,135,1,14,22,16,5,20,14,22,16,12,20,17,59,12,14,4,129,1,11,14,6,1,0,0,0,0,0,0,0,22,12,14,10,0,54,2,10,24,11,14,56,58,5,142,1,10,0,54,0,10,24,14,22,16,5,20,56,39,10,25,14,22,56,40,14,22,16,8,20,12,11,14,22,16,9,20,12,12,14,22,16,10,20,12,13,14,22,16,7,20,12,3,14,22,16,11,20,12,4,14,22,16,5,20,12,5,14,22,16,12,20,12,6,11,12,11,11,11,13,11,3,11,4,11,5,11,6,57,5,12,15,13,16,11,15,68,79,11,17,6,1,0,0,0,0,0,0,0,22,12,17,5,34,11,28,1,11,0,1,14,16,56,55,32,4,202,1,11,25,11,16,57,6,56,56,2,24,1,0,0,119,214,1,10,0,55,1,17,89,20,12,28,11,1,17,70,12,23,14,2,65,21,12,20,10,20,14,3,65,65,33,4,17,5,21,11,0,1,7,12,39,6,0,0,0,0,0,0,0,0,12,18,6,0,0,0,0,0,0,0,0,12,29,6,0,0,0,0,0,0,0,0,12,30,64,79,0,0,0,0,0,0,0,0,12,17,10,18,10,20,35,4,203,1,5,34,14,2,10,18,66,21,20,12,26,14,3,10,18,66,65,20,12,27,10,0,55,8,10,27,56,73,32,4,51,5,29,10,0,54,8,10,27,56,48,12,31,10,31,10,26,12,9,46,11,9,56,84,32,4,67,11,31,1,5,29,10,31,10,26,12,10,46,11,10,56,85,20,12,22,10,26,17,17,12,19,10,19,4,84,10,0,54,9,12,11,5,87,10,0,54,3,12,11,11,11,12,24,10,22,10,30,34,4,114,11,22,12,30,10,24,10,30,12,12,46,11,12,56,54,12,21,4,104,5,112,11,31,1,11,0,1,11,24,1,7,10,39,11,21,12,29,11,24,11,31,10,29,11,26,10,27,56,86,12,25,14,25,16,6,20,10,23,35,4,128,1,5,132,1,11,0,1,7,18,39,11,19,4,148,1,14,25,16,5,20,14,25,16,12,20,17,56,12,15,10,0,54,2,11,27,11,15,56,58,5,155,1,10,0,54,0,11,27,14,25,16,5,20,56,39,10,28,14,25,56,40,14,25,16,8,20,12,13,14,25,16,9,20,12,14,14,25,16,10,20,12,4,14,25,16,7,20,12,5,14,25,16,11,20,12,6,14,25,16,5,20,12,7,14,25,16,12,20,12,8,11,14,11,13,11,4,11,5,11,6,11,7,11,8,57,5,12,16,13,17,11,16,68,79,11,18,6,1,0,0,0,0,0,0,0,22,12,18,5,29,11,0,1,14,17,56,55,32,4,213,1,11,28,11,17,57,6,56,56,2,25,1,0,0,120,93,11,1,17,47,12,7,10,0,55,8,11,7,56,91,12,8,64,29,0,0,0,0,0,0,0,0,12,3,10,8,56,92,12,5,10,5,56,47,32,4,85,5,18,10,8,10,5,56,36,20,56,85,20,12,6,10,5,56,36,20,17,17,4,36,10,0,55,9,11,6,56,93,12,2,5,41,10,0,55,3,11,6,56,93,12,2,11,2,16,4,10,5,56,36,20,56,38,12,4,13,3,10,4,16,9,20,10,4,16,8,20,10,4,16,12,20,10,4,16,11,20,10,4,16,5,20,10,4,16,10,20,10,4,16,7,20,10,4,16,6,20,11,4,16,22,20,18,8,68,29,10,8,11,5,56,36,20,56,94,12,5,5,13,11,8,1,11,0,1,11,5,1,11,3,2,26,1,0,0,121,20,11,1,17,47,12,4,10,0,55,0,10,4,56,95,12,3,12,2,11,0,55,2,11,4,56,96,12,6,12,5,11,2,11,3,11,5,11,6,2,27,1,0,0,122,37,10,0,55,9,56,32,32,4,12,10,0,55,9,56,57,1,56,97,12,1,5,14,56,98,12,1,11,1,12,4,10,0,55,3,56,32,32,4,28,11,0,55,3,56,33,1,56,97,12,2,5,32,11,0,1,56,98,12,2,11,2,12,3,11,4,11,3,2,28,1,0,0,124,90,64,21,0,0,0,0,0,0,0,0,12,9,64,21,0,0,0,0,0,0,0,0,12,5,10,0,55,9,56,32,4,15,11,0,1,11,3,1,11,9,11,5,2,10,0,55,9,56,33,1,12,8,10,1,10,8,35,4,26,11,8,12,1,10,0,55,9,56,57,1,12,7,10,2,10,7,36,4,37,11,7,12,2,10,0,55,9,11,1,56,99,12,1,10,0,55,9,11,2,56,99,12,2,10,1,10,2,37,4,87,5,52,10,0,55,9,10,1,10,3,17,70,56,100,12,4,10,4,6,0,0,0,0,0,0,0,0,34,4,69,13,9,10,1,68,21,13,5,11,4,68,21,10,0,55,9,11,1,56,52,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,84,11,0,1,11,3,1,5,87,11,6,12,1,5,47,11,9,11,5,2,29,1,0,0,124,90,64,21,0,0,0,0,0,0,0,0,12,9,64,21,0,0,0,0,0,0,0,0,12,5,10,0,55,3,56,32,4,15,11,0,1,11,3,1,11,9,11,5,2,10,0,55,3,56,33,1,12,8,10,1,10,8,35,4,26,11,8,12,1,10,0,55,3,56,57,1,12,7,10,2,10,7,36,4,37,11,7,12,2,10,0,55,3,11,1,56,99,12,1,10,0,55,3,11,2,56,99,12,2,10,1,10,2,37,4,87,5,52,10,0,55,3,10,1,10,3,17,70,56,100,12,4,10,4,6,0,0,0,0,0,0,0,0,34,4,69,13,9,10,1,68,21,13,5,11,4,68,21,10,0,55,3,11,1,56,52,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,84,11,0,1,11,3,1,5,87,11,6,12,1,5,47,11,9,11,5,2,30,0,0,0,125,49,11,0,11,1,56,93,16,4,12,6,6,0,0,0,0,0,0,0,0,12,3,10,6,56,35,12,5,10,5,56,47,32,4,43,5,15,10,6,10,5,56,36,20,56,38,12,4,10,4,16,6,20,10,2,36,4,34,11,3,11,4,16,5,20,22,12,3,5,36,11,4,1,10,6,11,5,56,36,20,56,46,12,5,5,10,11,6,1,11,5,1,11,3,2,31,1,0,0,126,52,11,2,17,47,12,5,10,0,55,8,10,5,56,73,4,9,5,13,11,0,1,7,11,39,10,0,55,8,11,5,56,91,12,6,10,6,10,1,56,84,4,23,5,29,11,6,1,11,0,1,7,2,39,11,6,10,1,56,85,20,12,4,10,1,7,27,35,4,42,11,0,55,9,12,3,5,45,11,0,55,3,12,3,11,3,11,4,56,93,16,4,11,1,56,38,2,10,10,10,0,10,11,10,2,9,1,8,4,8,7,8,6,8,1,8,0,8,5,8,3,8,2,10,6,10,9,10,7,10,14,10,5,10,1,10,3,10,4,10,8,8,8,0,59,1,59,2,59,3,59,13,59,14,59,15,59,16,59,17,59,18,59,19,59,20,59,21,59,0],"critbit":[161,28,235,11,6,0,0,0,14,1,0,8,2,8,28,3,36,194,1,4,230,1,54,5,156,2,232,1,7,132,4,166,4,8,170,8,64,6,234,8,120,10,226,9,51,11,149,10,4,12,153,10,173,14,13,198,24,28,14,226,24,20,15,246,24,4,0,14,0,30,1,45,1,46,0,2,6,1,0,0,0,1,6,0,0,0,4,1,4,0,2,3,12,2,7,1,4,1,3,4,2,0,0,33,0,1,1,4,0,44,2,3,1,4,0,22,2,4,1,4,0,32,2,5,1,4,0,31,2,5,1,4,0,38,6,5,1,4,0,35,6,5,1,4,0,27,6,3,1,4,0,42,6,3,1,4,0,20,7,3,1,4,0,18,6,8,1,4,0,17,6,3,1,4,0,40,9,10,1,4,0,10,9,11,1,4,0,7,6,12,1,4,0,8,6,12,1,4,0,16,1,13,1,6,0,15,1,13,1,4,0,19,6,3,1,4,0,47,14,13,1,4,0,23,15,4,1,4,1,13,25,26,0,2,5,24,13,2,7,4,2,6,20,21,2,7,4,2,9,28,30,2,7,4,2,15,17,13,2,7,4,2,16,17,13,2,7,6,2,22,19,4,2,7,4,2,28,19,3,2,7,4,2,33,0,17,2,7,4,2,39,28,29,2,7,4,29,16,29,18,28,18,27,18,2,10,23,18,10,10,20,10,23,16,8,10,7,10,22,18,18,10,22,16,19,10,6,10,5,10,30,18,1,10,24,16,24,18,30,16,14,10,26,16,26,18,25,18,25,16,1,7,8,4,1,11,2,1,9,0,1,6,11,2,1,9,0,1,3,1,1,2,3,3,2,6,11,2,1,9,0,3,3,7,11,2,1,9,0,3,9,0,2,1,3,2,7,11,2,1,9,0,3,1,9,0,1,7,9,0,1,6,9,0,0,4,7,11,2,1,9,0,3,3,1,3,6,11,2,1,9,0,3,3,2,3,8,1,1,11,3,2,9,0,9,1,2,3,11,0,1,9,0,1,6,11,3,2,9,0,9,1,2,6,11,3,2,9,0,9,1,9,0,1,6,9,1,4,1,3,3,3,16,3,3,3,3,3,2,6,8,1,1,1,8,1,3,3,11,0,1,9,0,3,3,3,3,7,11,3,2,9,0,9,1,9,0,9,1,1,4,1,2,16,3,3,3,3,3,3,3,3,3,1,3,3,6,8,1,3,3,9,0,2,7,11,3,2,9,0,9,1,9,0,1,9,1,1,7,9,1,2,11,3,2,3,8,1,11,3,2,3,11,0,1,9,0,2,6,8,1,3,11,67,114,105,116,98,105,116,84,114,101,101,12,73,110,116,101,114,110,97,108,78,111,100,101,4,76,101,97,102,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,4,99,108,111,98,7,99,108,111,98,95,118,50,19,99,111,117,110,116,95,108,101,97,100,105,110,103,95,122,101,114,111,115,7,99,114,105,116,98,105,116,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,29,103,101,116,95,99,108,111,115,101,115,116,95,108,101,97,102,95,105,110,100,101,120,95,98,121,95,107,101,121,11,105,110,115,101,114,116,95,108,101,97,102,14,105,110,116,101,114,110,97,108,95,110,111,100,101,115,8,105,115,95,101,109,112,116,121,13,105,115,95,108,101,102,116,95,99,104,105,108,100,3,107,101,121,6,108,101,97,118,101,115,10,108,101,102,116,95,99,104,105,108,100,14,108,101,102,116,95,109,111,115,116,95,108,101,97,102,6,108,101,110,103,116,104,4,109,97,115,107,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,3,110,101,119,24,110,101,120,116,95,105,110,116,101,114,110,97,108,95,110,111,100,101,95,105,110,100,101,120,9,110,101,120,116,95,108,101,97,102,15,110,101,120,116,95,108,101,97,102,95,105,110,100,101,120,6,112,97,114,101,110,116,13,112,114,101,118,105,111,117,115,95,108,101,97,102,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,11,114,105,103,104,116,95,99,104,105,108,100,15,114,105,103,104,116,95,109,111,115,116,95,108,101,97,102,4,114,111,111,116,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,112,100,97,116,101,95,99,104,105,108,100,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,128,3,8,255,255,255,255,255,255,255,255,3,8,255,255,255,255,255,255,255,127,0,2,3,24,3,48,9,0,37,3,1,2,4,29,3,26,3,41,3,37,3,2,2,7,43,3,21,11,3,2,3,8,1,25,11,3,2,3,11,0,1,9,0,32,3,31,3,34,3,36,3,2,10,0,10,0,3,0,0,13,11,7,9,10,0,56,0,11,0,56,1,7,9,7,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,57,0,2,1,3,0,0,13,4,11,0,55,0,56,2,2,2,3,0,0,13,4,11,0,55,0,56,3,2,3,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,1,20,56,5,55,2,20,11,0,55,1,20,2,4,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,0,55,3,20,2,5,1,0,0,22,78,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,36,5,30,10,0,10,4,11,5,56,7,12,2,5,38,9,12,2,11,2,4,50,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,59,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,7,20,56,9,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,6,3,0,0,22,79,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,37,5,30,10,0,10,4,11,5,56,7,32,12,2,5,39,9,12,2,11,2,4,51,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,60,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,8,20,56,10,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,7,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,7,20,12,2,5,2,11,0,1,11,2,2,8,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,8,20,12,2,5,2,11,0,1,11,2,2,9,3,0,0,23,247,1,10,1,11,2,7,9,57,1,12,15,10,0,55,6,20,12,16,10,0,55,6,20,6,1,0,0,0,0,0,0,0,22,10,0,54,6,21,10,16,7,11,6,1,0,0,0,0,0,0,0,23,35,4,24,5,28,11,0,1,7,1,39,10,0,54,0,10,16,11,15,56,11,10,0,10,1,12,3,46,11,3,56,12,12,7,10,7,7,9,33,4,69,10,16,6,0,0,0,0,0,0,0,0,33,4,49,5,53,11,0,1,7,2,39,7,10,10,16,23,10,0,54,7,21,10,16,10,0,54,1,21,11,16,11,0,54,3,21,6,0,0,0,0,0,0,0,0,2,10,0,55,0,11,7,56,5,55,2,20,12,6,10,6,10,1,34,4,81,5,85,11,0,1,7,3,39,49,64,11,6,10,1,29,53,17,21,49,64,23,23,12,8,6,1,0,0,0,0,0,0,0,11,8,49,1,23,47,12,17,10,17,7,9,7,9,7,9,18,1,12,12,10,0,55,8,20,12,13,10,0,55,8,20,6,1,0,0,0,0,0,0,0,22,10,0,54,8,21,10,0,54,5,10,13,11,12,56,13,10,0,55,7,20,12,18,7,9,12,14,10,18,7,9,35,4,169,1,5,135,1,10,0,55,5,10,18,56,8,12,9,10,17,10,9,16,12,20,36,4,149,1,11,9,1,5,169,1,11,18,12,14,10,1,10,9,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,164,1,11,9,16,7,20,12,18,5,168,1,11,9,16,8,20,12,18,5,130,1,10,14,7,9,33,4,178,1,10,13,10,0,54,7,21,5,193,1,10,0,10,14,10,18,12,5,12,4,46,11,4,11,5,56,7,12,10,10,0,11,14,10,13,11,10,56,14,11,17,10,1,28,6,0,0,0,0,0,0,0,0,33,12,11,10,0,10,13,7,10,10,16,23,10,11,56,14,10,0,11,13,11,18,11,11,32,56,14,10,0,55,0,10,0,55,1,20,56,5,55,2,20,10,1,36,4,227,1,10,16,10,0,54,1,21,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,1,35,4,243,1,10,16,11,0,54,3,21,5,245,1,11,0,1,11,16,2,10,3,0,0,3,27,10,0,56,4,4,8,11,0,1,9,7,9,2,10,0,10,1,56,12,12,2,11,0,55,0,10,2,56,5,55,2,20,11,1,34,4,24,9,7,9,2,8,11,2,2,11,3,0,0,3,18,10,0,56,4,4,7,11,0,1,6,0,0,0,0,0,0,0,0,2,10,0,11,1,56,12,12,2,11,0,55,0,11,2,56,5,55,2,20,2,12,3,0,0,27,171,1,10,0,55,0,10,1,56,5,55,2,20,12,12,10,0,55,1,20,10,1,33,4,25,10,0,10,12,12,4,46,11,4,56,15,12,9,1,11,9,10,0,54,1,21,10,0,55,3,20,10,1,33,4,43,10,0,11,12,12,5,46,11,5,56,16,12,10,1,11,10,10,0,54,3,21,10,0,54,0,10,1,56,17,58,1,12,15,12,17,1,10,0,46,56,18,6,0,0,0,0,0,0,0,0,33,4,78,7,9,10,0,54,7,21,7,9,10,0,54,1,21,7,9,10,0,54,3,21,6,0,0,0,0,0,0,0,0,10,0,54,8,21,6,0,0,0,0,0,0,0,0,11,0,54,6,21,5,169,1,10,15,7,9,34,4,83,5,87,11,0,1,7,6,39,10,0,55,5,10,15,56,8,12,14,10,14,16,6,20,12,13,10,0,10,15,7,10,11,1,23,12,7,12,6,46,11,6,11,7,56,7,4,113,11,14,16,8,20,12,8,5,117,11,14,16,7,20,12,8,11,8,12,16,10,13,7,9,33,4,149,1,10,16,7,9,35,4,135,1,7,9,10,0,54,5,10,16,56,19,15,6,21,5,144,1,7,9,10,0,54,0,7,10,10,16,23,56,20,54,4,21,11,16,10,0,54,7,21,5,164,1,10,0,10,13,10,15,12,3,12,2,46,11,2,11,3,56,7,12,11,10,0,11,13,11,16,11,11,56,14,11,0,54,5,11,15,56,21,1,11,17,2,13,3,0,0,13,6,11,0,54,0,11,1,56,20,54,9,2,14,3,0,0,13,6,11,0,55,0,11,1,56,5,55,9,2,15,3,0,0,3,14,10,0,11,1,56,6,12,2,4,6,5,10,11,0,1,7,4,39,11,0,11,2,56,22,2,16,3,0,0,31,14,11,0,58,0,1,1,1,1,12,2,12,1,1,11,1,56,23,11,2,56,24,2,17,3,0,0,31,23,14,0,55,0,56,2,6,0,0,0,0,0,0,0,0,33,4,7,5,9,6,0,0,0,0,0,0,0,0,39,11,0,58,0,1,1,1,1,12,2,12,1,1,11,2,56,25,11,1,56,26,2,18,0,0,0,32,46,10,0,55,7,20,12,3,10,3,7,9,33,4,12,11,0,1,7,9,2,10,3,7,9,35,4,40,5,17,10,0,55,5,11,3,56,8,12,2,10,1,10,2,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,35,11,2,16,7,20,12,3,5,39,11,2,16,8,20,12,3,5,12,11,0,1,7,10,11,3,23,2,19,0,0,0,13,48,10,1,7,9,34,4,5,5,9,11,0,1,7,7,39,11,3,4,19,10,2,10,0,54,5,10,1,56,19,15,7,21,5,26,10,2,10,0,54,5,10,1,56,19,15,8,21,10,2,7,9,36,4,40,11,1,11,0,54,0,7,10,11,2,23,56,20,54,4,21,5,47,11,1,11,0,54,5,11,2,56,19,15,6,21,2,20,0,0,0,13,9,11,0,55,5,11,1,56,8,16,7,20,11,2,33,2,2,2,2,3,0,0,2,4,0,2,2,1,1,3,1,1,1,2,2,6,2,0,2,5,1,0,0,1,0,10,1,10,2,10,3,10,4,10,5,10,9,10,10,10,11,10,13,10,0,11,0,12,0],"custodian":[161,28,235,11,6,0,0,0,14,1,0,12,2,12,48,3,60,158,1,4,218,1,30,5,248,1,246,1,7,238,3,166,4,8,148,8,64,6,212,8,10,10,222,8,38,11,132,9,4,12,136,9,238,2,13,246,11,8,14,254,11,6,15,132,12,2,0,23,1,15,1,21,1,35,1,37,1,38,0,0,4,1,0,1,0,1,12,0,0,4,12,1,0,1,1,2,4,1,0,1,2,3,12,1,0,1,3,5,7,0,3,8,4,0,4,6,12,2,7,1,4,1,5,7,2,0,0,33,0,1,0,0,10,2,3,1,0,0,34,0,4,1,0,0,42,5,6,1,0,0,28,7,8,1,0,0,24,9,10,1,0,0,29,11,8,1,0,0,25,12,10,1,0,0,31,9,8,1,0,0,40,12,8,1,0,0,9,2,13,1,0,0,12,2,13,1,0,0,19,14,15,1,0,0,17,2,16,1,0,1,30,27,13,1,0,1,36,30,10,1,0,1,41,24,13,1,0,1,43,8,10,1,0,2,26,26,6,1,0,3,34,0,17,0,3,39,28,29,0,4,13,31,8,2,7,4,4,16,21,23,2,7,4,4,18,32,33,2,7,4,4,22,21,22,2,7,4,4,34,0,25,2,7,4,24,20,22,20,16,19,25,20,5,19,18,19,12,19,14,19,15,19,6,19,7,19,4,19,17,19,21,20,23,20,1,7,8,8,1,8,1,2,6,11,2,1,9,0,8,5,2,3,3,1,11,2,1,9,0,4,7,11,2,1,9,0,3,6,8,1,7,8,8,1,11,4,1,9,0,3,7,11,2,1,9,0,8,5,11,3,1,9,0,0,3,7,11,2,1,9,0,6,8,1,3,1,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,11,3,1,9,0,3,7,11,2,1,9,0,8,5,3,1,3,2,7,11,2,1,9,0,8,5,1,7,11,0,1,9,0,1,6,11,0,1,9,0,1,8,6,3,6,11,0,1,9,0,3,3,1,9,0,2,8,5,11,0,1,9,0,2,6,11,7,2,9,0,9,1,9,0,1,1,1,6,9,1,1,6,11,3,1,9,0,1,11,7,2,9,0,9,1,2,11,3,1,9,0,7,8,8,2,7,11,3,1,9,0,11,3,1,9,0,1,6,8,6,1,8,5,2,7,11,3,1,9,0,3,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,7,9,1,7,65,99,99,111,117,110,116,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,4,67,111,105,110,9,67,117,115,116,111,100,105,97,110,2,73,68,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,16,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,115,22,97,99,99,111,117,110,116,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,3,97,100,100,17,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,22,98,111,114,114,111,119,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,26,98,111,114,114,111,119,95,109,117,116,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,4,99,108,111,98,4,99,111,105,110,8,99,111,110,116,97,105,110,115,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,105,110,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,4,106,111,105,110,12,108,111,99,107,95,98,97,108,97,110,99,101,14,108,111,99,107,101,100,95,98,97,108,97,110,99,101,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,110,101,119,6,111,98,106,101,99,116,5,115,112,108,105,116,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,0,2,2,14,11,3,1,9,0,32,11,3,1,9,0,1,2,1,27,8,6,2,2,2,27,8,6,11,11,7,2,8,5,11,0,1,9,0,2,19,0,19,0,1,0,0,8,4,11,0,17,19,18,1,2,1,3,0,0,18,27,10,0,55,0,10,1,56,0,32,4,11,11,0,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,2,11,0,55,0,11,1,56,1,12,2,10,2,55,1,56,2,12,3,11,2,55,2,56,2,12,4,11,3,11,4,2,2,3,0,0,8,6,10,0,17,19,11,0,56,3,57,0,2,3,3,0,0,8,7,11,0,11,2,11,1,56,4,11,3,56,5,2,4,3,0,0,8,8,11,0,11,1,56,6,54,1,11,2,56,7,1,2,5,3,0,0,8,9,11,0,11,1,16,3,17,20,56,6,54,1,11,2,56,8,2,6,3,0,0,8,10,11,0,11,1,16,3,17,20,56,6,54,2,11,2,56,7,1,2,7,3,0,0,8,7,11,0,11,1,56,6,54,2,11,2,56,8,2,8,3,0,0,10,10,10,0,10,1,11,2,56,4,12,3,11,0,11,1,11,3,56,9,2,9,3,0,0,10,10,10,0,10,1,11,2,56,10,12,3,11,0,11,1,11,3,56,11,2,10,3,0,0,8,7,11,0,55,0,11,1,56,1,55,1,56,2,2,11,3,0,0,8,7,11,0,55,0,11,1,56,1,55,2,56,2,2,12,0,0,0,8,18,10,0,55,0,10,1,56,0,32,4,13,10,0,54,0,10,1,56,12,56,12,57,1,56,13,11,0,54,0,11,1,56,14,2,13,0,0,0,8,15,10,0,55,0,10,1,56,0,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,1,2,2,1,0,0,0,1,1,0,0,19,1,19,2,19,0,20,0],"custodian_v2":[161,28,235,11,6,0,0,0,14,1,0,12,2,12,44,3,56,178,1,4,234,1,30,5,136,2,255,1,7,135,4,242,4,8,249,8,64,6,185,9,20,10,205,9,39,11,244,9,4,12,248,9,189,3,13,181,13,10,14,191,13,6,15,197,13,2,0,24,1,15,1,21,1,38,1,41,1,42,0,0,4,1,0,1,0,1,12,0,0,4,12,1,0,1,1,2,4,1,0,1,2,3,12,1,0,1,3,7,4,0,4,5,12,2,7,1,4,1,5,6,2,0,0,36,0,1,0,0,23,2,1,0,0,28,1,3,0,0,12,4,5,0,0,9,6,7,1,0,0,37,0,8,1,0,0,46,9,10,1,0,0,31,11,3,1,0,0,25,12,13,1,0,0,32,14,3,1,0,0,26,15,13,1,0,0,34,12,3,1,0,0,44,15,3,1,0,0,8,6,16,1,0,0,11,6,16,1,0,0,19,17,18,1,0,0,17,6,19,1,0,1,33,32,16,1,0,1,40,33,13,1,0,1,45,29,16,1,0,1,47,3,13,1,0,2,29,31,10,1,0,3,27,21,3,0,3,37,0,21,0,3,43,22,5,0,4,13,34,3,2,7,4,4,16,26,28,2,7,4,4,18,35,36,2,7,4,4,22,26,27,2,7,4,4,37,0,30,2,7,4,28,25,26,25,19,24,29,25,8,24,21,24,15,24,17,24,18,24,9,24,10,24,7,24,20,24,25,25,27,25,1,7,8,7,1,8,1,2,6,8,1,7,8,7,0,1,6,8,1,1,5,2,6,11,2,1,9,0,5,2,3,3,1,11,2,1,9,0,4,7,11,2,1,9,0,3,6,8,1,7,8,7,1,11,4,1,9,0,3,7,11,2,1,9,0,5,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,3,1,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,11,3,1,9,0,3,7,11,2,1,9,0,5,3,1,3,2,7,11,2,1,9,0,5,1,7,11,0,1,9,0,1,6,11,0,1,9,0,2,8,5,5,1,8,5,1,6,8,5,3,6,11,0,1,9,0,3,3,1,9,0,2,5,11,0,1,9,0,2,6,11,6,2,9,0,9,1,9,0,1,1,1,6,9,1,1,6,11,3,1,9,0,1,11,6,2,9,0,9,1,2,11,3,1,9,0,7,8,7,2,7,11,3,1,9,0,11,3,1,9,0,2,7,11,3,1,9,0,3,3,7,11,6,2,9,0,9,1,9,0,9,1,2,7,11,6,2,9,0,9,1,9,0,1,7,9,1,7,65,99,99,111,117,110,116,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,4,67,111,105,110,9,67,117,115,116,111,100,105,97,110,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,16,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,115,22,97,99,99,111,117,110,116,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,13,97,99,99,111,117,110,116,95,111,119,110,101,114,3,97,100,100,17,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,22,98,111,114,114,111,119,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,26,98,111,114,114,111,119,95,109,117,116,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,7,99,108,111,98,95,118,50,4,99,111,105,110,8,99,111,110,116,97,105,110,115,24,99,114,101,97,116,101,95,99,104,105,108,100,95,97,99,99,111,117,110,116,95,99,97,112,12,99,117,115,116,111,100,105,97,110,95,118,50,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,6,100,101,108,101,116,101,18,100,101,108,101,116,101,95,97,99,99,111,117,110,116,95,99,97,112,12,102,114,111,109,95,98,97,108,97,110,99,101,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,105,110,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,4,106,111,105,110,12,108,111,99,107,95,98,97,108,97,110,99,101,14,108,111,99,107,101,100,95,98,97,108,97,110,99,101,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,110,101,119,6,111,98,106,101,99,116,5,111,119,110,101,114,5,115,112,108,105,116,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,2,14,11,3,1,9,0,35,11,3,1,9,0,1,2,2,30,8,5,39,5,2,2,2,30,8,5,10,11,6,2,5,11,0,1,9,0,2,24,0,24,0,3,0,0,20,10,11,0,17,23,12,1,14,1,17,24,12,2,11,1,11,2,18,1,2,1,1,0,0,3,22,10,0,16,0,17,24,10,0,16,1,20,33,4,9,5,15,11,1,1,11,0,1,7,1,39,11,1,17,23,11,0,16,1,20,18,1,2,2,1,0,0,3,5,11,0,19,1,1,17,22,2,3,1,0,0,3,4,11,0,16,1,20,2,4,3,0,0,23,27,10,0,55,0,10,1,56,0,32,4,11,11,0,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,2,11,0,55,0,11,1,56,1,12,2,10,2,55,1,56,2,12,3,11,2,55,2,56,2,12,4,11,3,11,4,2,5,3,0,0,3,6,10,0,17,23,11,0,56,3,57,0,2,6,3,0,0,3,7,11,0,11,2,11,1,56,4,11,3,56,5,2,7,3,0,0,3,8,11,0,11,1,56,6,54,1,11,2,56,7,1,2,8,3,0,0,3,9,11,0,11,1,16,1,20,56,6,54,1,11,2,56,8,2,9,3,0,0,3,10,11,0,11,1,16,1,20,56,6,54,2,11,2,56,7,1,2,10,3,0,0,3,7,11,0,11,1,56,6,54,2,11,2,56,8,2,11,3,0,0,13,10,10,0,10,1,11,2,56,4,12,3,11,0,11,1,11,3,56,9,2,12,3,0,0,13,10,10,0,10,1,11,2,56,10,12,3,11,0,11,1,11,3,56,11,2,13,3,0,0,3,7,11,0,55,0,11,1,56,1,55,1,56,2,2,14,3,0,0,3,7,11,0,55,0,11,1,56,1,55,2,56,2,2,15,0,0,0,3,18,10,0,55,0,10,1,56,0,32,4,13,10,0,54,0,10,1,56,12,56,12,57,1,56,13,11,0,54,0,11,1,56,14,2,16,0,0,0,3,15,10,0,55,0,10,1,56,0,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,1,2,1,0,1,1,2,1,0,0,0,1,2,24,3,24,4,24,0,20,0],"math":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,40,5,42,20,7,62,126,8,188,1,32,6,220,1,38,12,130,2,183,5,15,185,7,6,0,5,0,10,0,1,0,0,11,0,2,0,0,6,0,1,0,0,7,0,2,0,0,8,0,1,0,0,9,0,2,0,0,4,0,2,0,0,2,3,4,0,2,3,3,1,3,2,1,3,1,4,1,2,0,3,1,4,4,2,2,2,4,99,108,111,98,7,99,108,111,98,95,118,50,19,99,111,117,110,116,95,108,101,97,100,105,110,103,95,122,101,114,111,115,7,99,114,105,116,98,105,116,9,100,105,118,95,114,111,117,110,100,4,109,97,116,104,3,109,117,108,9,109,117,108,95,114,111,117,110,100,10,117,110,115,97,102,101,95,100,105,118,16,117,110,115,97,102,101,95,100,105,118,95,114,111,117,110,100,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,3,8,0,202,154,59,0,0,0,0,4,16,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,3,0,0,1,7,11,0,11,1,17,1,12,2,1,11,2,2,1,3,0,0,6,26,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,10,4,24,7,1,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,18,9,12,2,11,2,11,3,11,4,24,7,1,26,52,2,2,1,0,0,1,14,11,0,11,1,17,1,12,2,1,10,2,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,2,3,1,0,0,2,15,11,0,11,1,17,1,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,4,3,0,0,1,7,11,0,11,1,17,5,12,2,1,11,2,2,5,3,0,0,6,28,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,7,0,53,24,10,4,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,9,12,2,11,2,11,3,7,0,53,24,11,4,26,52,2,6,1,0,0,2,15,11,0,11,1,17,5,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,7,3,0,0,7,107,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,49,128,12,1,5,105,49,0,12,2,10,0,50,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,23,11,0,49,64,47,12,0,11,2,49,64,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,37,11,0,49,32,47,12,0,11,2,49,32,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,51,11,0,49,16,47,12,0,11,2,49,16,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,65,11,0,49,8,47,12,0,11,2,49,8,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,79,11,0,49,4,47,12,0,11,2,49,4,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,93,11,0,49,2,47,12,0,11,2,49,2,22,12,2,11,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,103,11,2,49,1,22,12,2,11,2,12,1,11,1,2,0,0,0,1,0,3,0]},"type_origin_table":[{"module_name":"custodian","struct_name":"Account","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"AccountCap","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"Custodian","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"Leaf","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"InternalNode","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"CritbitTree","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"PoolCreated","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlacedV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilledV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Order","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"TickLevel","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Pool","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlaced","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian_v2","struct_name":"Account","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian_v2","struct_name":"AccountCap","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian_v2","struct_name":"Custodian","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"PoolCreated","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"OrderPlaced","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"OrderCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"AllOrdersCanceledComponent","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"AllOrdersCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"OrderFilled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"DepositAsset","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"WithdrawAsset","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"Order","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"TickLevel","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob_v2","struct_name":"Pool","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"ACKQVv64dXCmpxE1QPU2QMLxVpmtbzrFGMtWYY6szJrQ","storage_rebate":0},{"data":{"Package":{"id":"0xb2345915de1f9bd661e9ab27eb27e376cdf6391359ea64fbfdb4550b092c1aa0","version":4,"module_map":{"calculator":[161,28,235,11,6,0,0,0,8,1,0,12,2,12,12,3,24,75,5,99,67,7,166,1,189,2,8,227,3,96,6,195,4,44,12,239,4,164,5,0,10,0,23,0,21,2,17,1,11,1,16,1,2,12,0,3,1,8,0,4,0,8,0,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,6,3,1,0,0,7,3,1,0,0,9,4,1,0,0,4,4,1,0,1,12,0,8,0,1,13,0,3,0,1,15,0,3,0,2,19,6,1,0,2,20,3,1,0,2,22,3,1,0,3,14,10,11,0,5,18,12,13,0,2,7,8,0,2,1,15,3,7,8,0,2,15,2,15,15,4,6,8,2,6,8,1,15,2,7,15,15,15,15,15,15,15,0,6,15,15,15,15,15,15,5,15,15,15,15,15,2,2,15,3,6,8,2,6,8,1,2,3,1,15,2,2,3,2,1,3,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,20,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,9,103,101,116,95,105,110,100,101,120,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,4,109,97,116,104,6,111,114,97,99,108,101,3,112,111,119,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,153,183,0,0,0,0,0,0,0,1,0,0,5,31,10,0,10,1,17,9,12,7,12,8,11,0,11,1,17,8,12,3,12,4,11,7,11,3,17,12,12,5,11,8,11,4,17,12,12,6,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,29,11,5,11,6,17,11,12,2,11,2,2,1,1,0,0,7,37,10,0,10,1,17,7,12,6,1,12,4,12,5,12,3,11,0,11,1,17,0,12,7,10,7,10,6,35,4,23,11,3,11,7,11,5,17,12,22,12,2,5,35,11,3,10,6,11,5,17,12,22,11,7,11,6,23,11,4,17,12,22,12,2,11,2,2,2,1,0,0,3,20,10,0,10,1,17,7,1,12,3,1,1,1,11,0,11,1,17,0,12,4,11,2,11,4,17,12,17,10,11,3,23,17,12,2,3,1,0,0,5,60,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,17,10,2,10,0,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,5,11,1,7,0,26,12,6,10,6,10,6,17,12,12,3,10,3,10,6,17,12,12,2,10,0,10,4,24,11,3,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,7,10,0,11,4,24,11,5,24,11,2,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,17,10,11,6,11,0,24,22,11,7,22,11,8,22,2,4,1,0,0,6,8,17,10,11,1,11,0,24,7,0,26,22,2,5,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,11,5,24,6,10,0,0,0,0,0,0,0,11,4,17,14,77,26,2,6,1,0,0,9,19,11,0,11,1,11,3,17,13,12,4,12,5,4,8,5,10,7,1,39,11,2,6,10,0,0,0,0,0,0,0,11,4,17,14,77,24,11,5,26,2,0],"dynamic_calculator":[161,28,235,11,6,0,0,0,9,1,0,18,2,18,18,3,36,169,1,4,205,1,4,5,209,1,165,2,7,246,3,149,6,8,139,10,128,1,6,139,11,10,12,149,11,225,14,0,16,0,9,0,38,0,43,0,41,3,37,1,45,2,4,2,10,2,1,12,1,0,1,3,3,12,0,5,2,8,0,8,0,8,0,0,17,0,1,1,0,0,21,2,1,0,0,22,2,1,0,0,20,3,1,0,0,24,3,1,0,0,19,4,1,0,0,23,4,1,0,0,18,5,1,0,0,6,6,7,0,0,13,8,7,1,0,0,14,9,1,0,0,15,10,1,0,0,12,9,1,0,1,5,7,1,0,1,7,7,1,0,1,8,25,1,0,2,36,13,14,1,0,3,25,22,1,0,3,26,28,34,0,3,27,28,7,0,3,28,28,7,0,3,29,22,14,0,3,30,28,29,0,3,31,22,19,0,3,32,28,7,0,3,33,17,18,0,3,34,26,7,0,4,39,15,1,0,4,40,7,1,0,4,42,7,1,0,6,11,20,21,1,0,7,35,15,1,0,8,44,31,14,0,16,12,30,19,9,6,8,3,7,8,1,6,8,2,7,11,0,1,9,0,5,2,3,3,1,1,15,7,6,8,3,6,8,2,7,8,1,5,2,15,1,7,6,8,3,6,8,2,7,8,1,2,5,15,1,6,6,8,3,7,8,1,2,5,15,1,7,6,8,3,7,8,1,6,8,2,5,2,15,1,3,6,8,3,7,8,1,2,2,15,15,7,6,8,3,7,8,1,7,11,0,1,9,0,2,3,3,1,6,6,8,3,7,8,1,2,15,15,1,7,6,8,3,7,8,1,2,15,15,15,1,9,1,3,3,15,15,15,15,3,3,1,9,0,2,6,11,0,1,9,0,3,1,3,0,11,5,2,6,2,10,2,15,10,2,15,3,3,15,15,2,6,8,1,5,2,10,2,10,2,1,2,2,6,10,9,0,6,9,0,1,1,2,6,8,1,2,9,5,6,2,15,3,10,2,3,15,10,2,15,3,2,15,2,4,6,8,3,6,8,2,15,2,3,7,8,1,2,5,11,5,6,2,10,2,15,15,10,2,15,3,3,15,15,2,7,8,1,2,3,15,15,15,10,2,15,15,15,15,3,3,15,15,15,1,6,8,3,7,1,3,3,15,3,3,15,6,15,15,15,15,15,15,5,15,15,15,15,15,7,15,15,15,15,15,15,15,5,67,108,111,99,107,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,23,99,97,108,99,117,108,97,116,101,95,99,117,114,114,101,110,116,95,105,110,100,101,120,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,28,100,121,110,97,109,105,99,95,99,97,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,21,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,97,112,121,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,18,100,121,110,97,109,105,99,95,99,97,108,99,117,108,97,116,111,114,21,100,121,110,97,109,105,99,95,104,101,97,108,116,104,95,102,97,99,116,111,114,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,31,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,36,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,30,100,121,110,97,109,105,99,95,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,25,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,23,100,121,110,97,109,105,99,95,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,3,109,97,120,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,4,112,111,111,108,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,6,118,101,99,116,111,114,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,201,175,0,0,0,0,0,0,0,1,0,0,11,99,10,6,6,0,0,0,0,0,0,0,0,36,4,9,10,7,6,0,0,0,0,0,0,0,0,36,12,9,5,11,9,12,9,11,9,32,4,15,5,25,11,1,1,11,3,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,17,10,6,6,0,0,0,0,0,0,0,0,36,4,38,10,3,11,6,12,10,46,11,10,56,0,12,17,6,0,0,0,0,0,0,0,0,12,16,10,7,6,0,0,0,0,0,0,0,0,36,4,52,11,3,11,7,12,11,46,11,11,56,0,12,16,5,54,11,3,1,10,0,10,2,10,1,10,4,10,5,10,17,77,10,8,17,1,12,13,10,0,10,2,10,1,10,4,10,5,11,16,77,10,8,17,2,12,14,11,0,11,1,11,2,11,4,11,5,11,17,77,11,8,17,7,12,15,10,14,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,95,11,13,11,14,17,28,11,15,17,29,12,12,5,97,17,31,12,12,11,12,2,1,1,0,0,16,86,10,2,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,17,6,0,0,0,0,0,0,0,0,12,14,10,12,12,10,14,12,14,4,56,1,32,4,31,10,6,4,31,13,10,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,10,14,10,15,35,4,78,5,36,14,10,10,14,66,19,12,9,10,2,10,9,20,12,8,46,11,8,17,17,12,16,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,9,20,33,4,57,10,5,12,13,10,0,10,1,10,2,11,9,20,10,3,11,13,10,6,17,3,12,11,11,17,11,11,11,16,17,29,22,12,17,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,2,1,11,1,1,11,0,1,11,17,2,2,1,0,0,23,76,10,2,10,3,12,7,46,11,7,17,25,12,14,1,14,14,65,19,12,12,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,6,0,0,0,0,0,0,0,0,12,10,10,14,12,11,14,14,14,4,56,1,32,4,31,10,6,4,31,13,11,10,4,68,19,11,12,6,1,0,0,0,0,0,0,0,22,12,12,10,10,10,12,35,4,68,5,36,14,11,10,10,66,19,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,10,4,10,8,20,33,4,49,10,5,12,9,10,0,10,1,10,2,11,8,20,10,3,11,9,10,6,17,4,12,13,11,15,11,13,22,12,15,11,10,6,1,0,0,0,0,0,0,0,22,12,10,5,31,11,2,1,11,1,1,11,0,1,11,15,2,3,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,5,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,4,1,0,0,24,21,10,0,10,2,10,3,11,4,11,5,11,6,17,6,12,8,11,2,11,3,12,7,46,11,7,17,23,12,9,11,0,11,1,11,8,11,9,17,15,2,5,1,0,0,7,27,10,1,10,2,11,3,17,26,1,12,7,11,5,4,13,11,7,11,4,22,12,7,5,17,11,7,11,4,23,12,7,11,0,11,1,11,2,17,8,1,12,6,11,7,11,6,17,29,2,6,1,0,0,7,27,10,1,10,2,11,3,17,26,12,6,1,11,5,4,13,11,6,11,4,22,12,6,5,17,11,6,11,4,23,12,6,11,0,11,1,11,2,17,8,12,7,1,11,6,11,7,17,29,2,7,1,0,0,27,91,10,1,10,3,12,7,46,11,7,17,25,1,12,12,14,12,65,19,12,15,6,0,0,0,0,0,0,0,0,12,14,10,12,12,9,14,12,14,4,56,1,32,4,27,13,9,10,4,68,19,11,15,6,1,0,0,0,0,0,0,0,22,12,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,10,14,10,15,35,4,81,5,36,14,9,10,14,66,19,12,8,10,1,10,8,20,17,22,12,16,1,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,4,10,8,20,33,4,56,10,5,12,13,10,0,10,2,10,1,11,8,20,10,3,11,13,10,6,17,3,12,17,11,10,10,17,11,16,17,29,22,12,10,11,11,11,17,22,12,11,11,14,6,1,0,0,0,0,0,0,0,22,12,14,5,31,11,1,1,11,2,1,11,0,1,11,10,11,11,17,28,2,8,1,0,0,30,42,11,0,17,32,12,8,10,1,10,2,12,3,46,11,3,17,21,12,9,10,1,10,2,17,20,12,4,12,6,11,1,11,2,17,19,12,5,12,7,11,8,11,9,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,12,10,12,11,5,17,13,11,4,17,29,12,10,11,12,11,7,17,14,11,6,17,29,12,11,11,10,11,11,2,9,1,0,0,32,76,10,4,6,0,0,0,0,0,0,0,0,36,4,9,10,5,6,0,0,0,0,0,0,0,0,36,12,7,5,11,9,12,7,11,7,32,4,15,5,23,11,1,1,11,2,1,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,12,12,10,4,6,0,0,0,0,0,0,0,0,36,4,36,10,2,11,4,12,8,46,11,8,56,0,12,12,6,0,0,0,0,0,0,0,0,12,11,10,5,6,0,0,0,0,0,0,0,0,36,4,50,11,2,11,5,12,9,46,11,9,56,0,12,11,5,52,11,2,1,10,0,10,1,10,3,10,12,77,10,11,77,10,6,17,10,12,10,11,0,11,1,11,3,10,10,11,12,77,11,11,77,11,6,17,11,12,13,11,10,11,13,2,10,1,0,0,33,41,10,1,10,2,17,18,12,10,1,12,8,12,9,12,7,11,0,11,1,11,2,11,3,11,4,11,5,17,12,12,11,10,11,10,10,35,4,27,11,7,11,11,11,9,17,29,22,12,6,5,39,11,7,10,11,11,9,17,29,22,11,11,11,10,23,11,8,17,29,22,12,6,11,6,2,11,1,0,0,7,24,10,1,10,2,17,18,1,12,7,1,1,1,11,0,11,1,11,2,11,4,11,5,11,6,17,12,12,8,11,3,11,8,17,29,17,27,11,7,23,17,29,2,12,1,0,0,35,62,10,1,10,2,17,24,12,11,12,12,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,20,10,5,4,16,11,12,11,3,22,12,12,5,20,11,12,11,3,23,12,12,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,35,11,5,4,31,11,11,11,4,22,12,11,5,35,11,11,11,4,23,12,11,11,0,11,1,11,2,17,8,12,7,12,8,11,12,11,8,17,29,12,10,11,11,11,7,17,29,12,9,10,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,56,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,5,60,11,9,11,10,17,28,12,6,11,6,2,0],"incentive":[161,28,235,11,6,0,0,0,14,1,0,30,2,30,66,3,96,181,1,4,149,2,46,5,195,2,164,3,7,231,5,187,6,8,162,12,96,6,130,13,94,10,224,13,116,11,212,14,2,12,214,14,189,15,13,147,30,40,14,187,30,8,15,195,30,2,0,44,0,72,0,62,0,64,1,18,1,78,2,21,2,26,2,27,2,36,2,53,2,73,2,76,2,77,0,82,0,4,12,1,0,1,0,6,4,0,0,3,12,0,0,7,3,0,0,5,3,0,1,8,12,0,4,9,7,0,5,12,7,0,6,0,4,1,0,1,7,1,8,0,8,2,12,1,0,1,10,13,4,0,11,10,12,2,7,1,4,1,13,11,2,0,0,47,0,1,0,0,67,2,1,0,0,66,2,1,0,0,15,3,1,1,0,0,79,4,1,0,0,24,5,6,0,0,25,7,1,1,0,0,39,8,9,0,0,40,10,11,0,0,33,12,13,0,1,41,46,37,0,1,42,47,37,0,2,60,1,34,0,2,61,37,34,0,3,51,37,34,0,5,38,1,36,1,0,5,48,36,33,0,6,69,49,40,1,0,7,74,32,9,0,8,37,50,51,1,0,9,34,22,1,1,3,10,52,0,14,0,11,14,26,1,2,7,4,11,22,24,45,2,7,4,11,23,27,28,2,7,4,11,29,24,25,2,7,4,11,52,0,18,2,7,4,11,63,27,43,2,7,4,12,58,52,1,1,12,12,68,22,1,1,8,13,65,15,16,0,14,70,39,40,1,0,26,17,26,19,29,21,25,17,22,17,24,17,20,29,20,30,25,19,22,19,24,19,15,22,26,38,31,22,29,41,25,38,27,38,22,38,23,19,23,38,17,22,19,22,28,51,1,7,8,13,0,4,7,8,2,15,1,7,8,13,9,7,8,2,6,8,9,2,3,3,11,10,1,9,0,3,2,7,8,13,5,7,8,2,6,8,9,7,8,5,2,5,5,6,8,2,7,8,5,3,2,5,2,10,15,10,15,6,7,8,2,7,11,0,1,9,0,6,8,9,7,8,5,5,7,8,13,2,6,8,2,2,1,3,3,6,8,2,2,3,4,3,3,15,2,5,6,8,2,7,8,5,6,8,9,2,5,3,10,8,6,10,15,10,2,1,8,11,1,6,8,13,1,5,2,15,1,1,11,12,2,9,0,9,1,2,2,8,1,1,2,1,8,2,1,9,0,1,7,1,2,6,11,12,2,9,0,9,1,9,0,1,1,3,7,11,12,2,9,0,9,1,9,0,9,1,2,7,11,12,2,9,0,9,1,9,0,1,7,9,1,1,8,3,1,8,4,4,1,11,8,1,9,0,3,7,8,1,1,6,8,9,1,8,6,1,15,1,11,12,2,5,15,1,8,7,2,15,15,2,5,15,3,11,10,1,9,0,3,7,8,13,1,11,8,1,9,0,1,11,0,1,9,0,17,7,8,5,3,2,5,5,5,3,3,7,15,15,10,15,7,11,12,2,5,15,3,7,8,1,15,10,15,7,11,12,2,5,15,1,9,1,18,6,11,12,2,5,15,3,3,15,15,10,15,15,6,11,12,2,5,15,3,6,8,1,15,15,3,15,15,15,15,10,15,1,6,9,1,2,7,8,5,2,3,7,8,5,2,5,9,5,15,3,7,8,1,15,15,6,11,12,2,5,15,15,7,11,12,2,5,15,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,13,1,11,10,1,9,0,2,9,0,5,1,6,8,1,10,10,8,6,3,3,3,10,2,6,8,1,10,15,15,6,11,12,2,5,15,10,15,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,9,73,110,99,101,110,116,105,118,101,12,73,110,99,101,110,116,105,118,101,66,97,108,16,80,111,111,108,65,100,109,105,110,83,101,116,116,105,110,103,8,80,111,111,108,73,110,102,111,16,80,111,111,108,79,119,110,101,114,83,101,116,116,105,110,103,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,3,97,100,100,8,97,100,100,95,112,111,111,108,5,97,100,109,105,110,6,97,100,109,105,110,115,5,97,115,99,105,105,5,97,115,115,101,116,6,97,115,115,101,116,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,24,99,97,108,99,95,112,111,111,108,95,117,112,100,97,116,101,95,114,101,119,97,114,100,115,12,99,108,97,105,109,95,114,101,119,97,114,100,5,99,108,111,99,107,4,99,111,105,110,10,99,111,105,110,95,116,121,112,101,115,8,99,111,110,116,97,105,110,115,7,99,114,101,97,116,111,114,11,99,117,114,114,101,110,116,95,105,100,120,18,100,105,115,116,114,105,98,117,116,101,100,95,97,109,111,117,110,116,6,101,97,114,110,101,100,4,101,109,105,116,9,101,110,100,95,116,105,109,101,115,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,14,103,101,116,95,112,111,111,108,95,99,111,117,110,116,13,103,101,116,95,112,111,111,108,95,105,110,102,111,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,9,105,110,99,101,110,116,105,118,101,13,105,110,100,101,120,95,114,101,119,97,114,100,115,19,105,110,100,101,120,95,114,101,119,97,114,100,115,95,112,97,105,100,115,4,105,110,105,116,11,105,110,116,111,95,115,116,114,105,110,103,16,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,7,108,101,110,100,105,110,103,3,109,117,108,3,110,101,119,6,111,98,106,101,99,116,10,111,114,97,99,108,101,95,105,100,115,5,111,119,110,101,114,6,111,119,110,101,114,115,5,112,111,111,108,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,9,115,97,102,101,95,109,97,116,104,6,115,101,110,100,101,114,9,115,101,116,95,97,100,109,105,110,9,115,101,116,95,111,119,110,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,11,115,116,97,114,116,95,116,105,109,101,115,7,115,116,111,114,97,103,101,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,13,116,111,116,97,108,95,115,117,112,112,108,121,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,13,117,112,100,97,116,101,95,114,101,119,97,114,100,16,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,22,117,115,101,114,95,97,99,99,95,114,101,119,97,114,100,115,95,112,97,105,100,115,5,117,116,105,108,115,5,118,97,108,117,101,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,153,183,0,0,0,0,0,0,3,8,154,183,0,0,0,0,0,0,3,8,155,183,0,0,0,0,0,0,3,8,156,183,0,0,0,0,0,0,3,8,157,183,0,0,0,0,0,0,3,8,158,183,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,43,8,11,19,2,31,3,32,15,21,11,8,1,9,0,1,2,12,43,2,49,3,28,10,8,6,71,10,3,35,10,3,75,10,15,59,10,15,45,10,15,46,10,11,12,2,5,15,80,10,11,12,2,5,15,81,10,11,12,2,5,15,54,10,2,2,2,6,43,8,11,30,5,56,11,12,2,15,1,17,11,12,2,15,1,57,11,12,2,2,8,1,20,10,2,3,2,3,65,5,55,15,83,1,4,2,3,65,5,16,15,83,1,0,22,0,0,0,0,1,15,10,0,17,21,10,0,46,17,30,10,0,56,0,10,0,56,0,11,0,56,1,64,20,0,0,0,0,0,0,0,0,18,2,56,2,2,1,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,1,10,1,56,3,32,4,27,11,0,15,1,10,1,10,2,56,4,5,35,11,0,15,1,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,3,56,6,2,2,1,0,0,23,43,10,0,16,0,20,10,3,46,17,30,33,4,9,5,15,11,0,1,11,3,1,7,0,39,10,0,16,2,10,1,56,3,32,4,27,11,0,15,2,10,1,10,2,56,4,5,35,11,0,15,2,10,1,56,5,12,4,10,2,11,4,21,11,3,46,17,30,11,1,11,2,18,4,56,7,2,3,1,4,0,31,139,1,10,0,16,0,20,10,8,46,17,30,33,4,9,5,17,11,0,1,11,8,1,11,1,1,7,0,39,10,3,11,1,17,18,36,4,27,10,4,10,3,36,12,9,5,29,9,12,9,11,9,4,32,5,38,11,0,1,11,8,1,7,1,39,10,0,16,3,10,2,56,8,32,4,65,10,0,15,3,10,2,10,2,6,0,0,0,0,0,0,0,0,64,33,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,9,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,34,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,35,0,0,0,0,0,0,0,0,64,20,0,0,0,0,0,0,0,0,18,1,56,9,10,0,15,4,10,2,68,20,11,0,15,3,10,2,56,10,12,12,10,12,16,5,65,33,12,11,10,12,15,5,56,11,17,16,68,33,10,12,15,6,10,3,68,9,10,12,15,7,10,4,68,9,10,12,15,8,10,6,77,68,34,10,12,15,9,10,6,77,11,4,11,3,23,77,17,13,68,34,10,12,15,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,34,10,12,15,11,10,8,56,12,68,35,10,12,15,12,10,8,56,12,68,35,10,12,15,13,10,8,56,12,68,35,11,12,15,14,11,7,68,20,11,5,11,6,10,8,56,13,12,10,11,8,17,21,11,2,11,11,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,10,57,0,56,14,2,4,3,0,0,42,118,10,0,16,3,10,3,56,8,4,111,11,1,17,18,12,11,10,0,11,2,10,11,10,3,10,4,12,8,12,7,12,6,12,5,46,11,5,11,6,11,7,11,8,17,5,12,20,12,15,11,0,15,3,11,3,56,10,12,18,11,11,10,18,15,15,21,10,18,16,5,65,33,12,17,6,0,0,0,0,0,0,0,0,12,12,10,12,10,17,35,4,108,5,45,14,15,10,12,66,34,20,12,14,14,20,10,12,66,34,20,12,19,10,18,15,10,10,12,67,34,12,13,10,14,11,13,21,10,18,15,11,10,12,67,35,12,16,10,16,10,4,12,9,46,11,9,56,15,4,79,10,16,10,4,56,16,1,11,16,10,4,11,14,56,17,10,18,15,12,10,12,67,35,12,21,10,21,10,4,12,10,46,11,10,56,15,4,99,10,21,10,4,56,16,1,11,21,10,4,11,19,56,17,11,12,6,1,0,0,0,0,0,0,0,22,12,12,5,40,11,18,1,5,117,11,2,1,11,0,1,11,1,1,2,5,0,0,0,44,166,1,11,0,16,3,10,3,56,18,12,14,10,14,16,5,65,33,12,13,6,0,0,0,0,0,0,0,0,12,7,64,34,0,0,0,0,0,0,0,0,12,10,64,34,0,0,0,0,0,0,0,0,12,22,10,7,10,13,35,4,159,1,5,20,10,14,16,6,10,7,66,9,20,12,17,10,17,10,14,16,15,20,35,4,36,10,14,16,15,20,12,17,10,14,16,7,10,7,66,9,20,12,6,10,2,10,6,35,4,48,10,2,12,6,10,14,16,9,10,7,66,34,20,12,15,10,14,16,10,10,7,66,34,20,12,9,10,17,10,6,35,4,90,11,6,11,17,23,77,12,19,10,1,10,3,17,10,1,12,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,10,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,15,11,19,17,14,11,20,26,12,8,11,9,11,8,22,12,9,13,10,10,9,68,34,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,21,10,4,7,6,34,4,151,1,10,14,16,12,10,7,66,35,12,5,10,5,10,4,56,15,4,114,11,5,10,4,56,19,20,12,21,5,116,11,5,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,14,16,11,10,7,66,35,12,12,10,12,10,4,56,15,4,133,1,11,12,10,4,56,19,20,12,11,5,135,1,11,12,1,10,1,10,3,10,4,17,11,1,12,18,11,9,11,11,23,11,18,24,12,16,11,21,11,16,22,12,21,13,22,11,21,68,34,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,15,11,1,1,11,14,1,11,10,11,22,2,6,1,4,0,48,105,10,0,11,2,11,3,10,1,55,0,20,10,4,17,4,11,0,15,3,10,1,55,0,20,56,10,12,9,10,1,55,1,20,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,10,9,16,12,10,8,66,35,12,12,10,12,10,4,56,15,4,36,11,12,10,4,56,19,20,12,11,5,38,11,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,10,9,15,13,10,8,67,35,12,14,10,14,10,4,12,6,46,11,6,56,15,4,56,10,14,10,4,56,16,12,13,11,14,10,4,10,11,56,17,11,11,11,13,23,17,12,26,12,7,11,9,16,8,11,8,66,34,20,12,10,10,1,55,2,20,10,7,22,11,10,37,4,81,5,87,11,5,1,11,1,1,7,4,39,10,1,55,2,20,10,7,22,10,1,54,2,21,11,1,54,3,11,7,52,56,20,11,5,56,21,11,4,56,22,2,7,1,0,0,9,19,6,0,0,0,0,0,0,0,0,12,2,10,0,16,3,10,1,56,8,4,15,11,0,16,3,11,1,56,18,16,5,65,33,12,2,5,17,11,0,1,11,2,2,8,1,0,0,53,47,10,0,16,3,10,1,56,8,4,6,5,10,11,0,1,7,2,39,11,0,16,3,11,1,56,18,12,3,10,3,16,5,65,33,10,2,36,4,22,5,26,11,3,1,7,2,39,10,3,16,6,10,2,66,9,20,10,3,16,7,10,2,66,9,20,10,3,16,9,10,2,66,34,20,11,3,16,14,11,2,66,20,20,2,9,1,0,0,54,97,64,33,0,0,0,0,0,0,0,0,12,5,64,34,0,0,0,0,0,0,0,0,12,14,64,20,0,0,0,0,0,0,0,0,12,9,10,0,16,3,10,3,56,8,4,87,11,2,17,18,12,6,10,0,11,1,11,6,10,3,10,4,17,5,12,11,1,11,0,16,3,11,3,56,18,12,10,10,10,16,5,65,33,12,8,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,84,5,38,10,10,16,13,10,7,66,35,12,13,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,10,13,10,4,56,15,4,55,11,13,10,4,56,19,20,12,12,5,57,11,13,1,13,5,10,10,16,5,10,7,66,33,20,68,33,13,14,14,11,10,7,66,34,20,11,12,23,68,34,13,9,10,10,16,14,10,7,66,20,20,68,20,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,33,11,10,1,5,93,11,1,1,11,0,1,11,2,1,11,5,11,14,11,9,2,2,1,2,2,2,3,2,4,2,5,1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,1,11,1,1,0,1,0,2,0,3,0,4,16,22,17,22,18,22,19,22,0,50,0],"lending":[161,28,235,11,6,0,0,0,10,1,0,22,2,22,52,3,74,130,1,4,204,1,38,5,242,1,222,2,7,208,4,238,3,8,190,8,96,6,158,9,10,10,168,9,49,12,217,9,201,4,0,26,0,25,0,30,0,34,0,39,2,32,1,14,1,15,1,19,1,41,0,44,0,3,3,0,0,11,3,0,0,0,3,0,0,8,3,0,0,5,3,0,1,4,12,0,3,6,12,1,0,1,4,9,12,0,5,7,8,0,6,1,8,0,7,2,12,1,0,1,9,10,2,0,0,46,0,1,0,0,16,2,1,1,0,0,47,3,1,1,0,0,13,4,1,1,0,0,35,5,1,1,0,0,29,6,1,2,0,0,1,43,11,1,0,2,20,22,1,1,0,2,21,19,1,1,0,2,22,32,33,2,0,0,2,23,22,28,1,0,2,24,22,16,1,0,3,16,17,1,1,0,3,17,35,1,1,0,3,31,18,16,1,0,3,42,18,16,1,0,3,47,23,1,1,0,4,33,0,7,0,7,45,15,16,1,0,8,18,12,1,1,3,9,37,9,10,0,10,38,13,14,1,0,21,12,18,12,12,12,14,12,8,12,19,20,11,12,15,12,16,12,19,24,7,12,19,26,10,12,19,29,9,31,15,34,16,34,13,34,19,36,1,6,8,7,0,8,6,8,9,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,5,7,8,11,9,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,5,7,8,5,7,8,11,7,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,3,7,8,11,8,6,8,9,6,8,8,7,8,7,7,11,6,1,9,0,2,11,10,1,9,0,3,7,8,11,12,6,8,9,6,8,8,7,8,7,2,7,11,6,1,9,0,2,7,11,6,1,9,1,11,10,1,9,0,5,3,7,8,5,7,8,11,1,1,5,3,3,3,5,11,10,1,9,0,1,6,8,11,1,5,5,7,8,5,6,8,9,7,8,7,2,5,1,9,0,3,11,10,1,9,0,3,7,8,11,1,11,10,1,9,0,1,6,11,10,1,9,0,1,3,3,7,11,6,1,9,0,11,10,1,9,0,7,8,11,2,6,11,6,1,9,0,3,5,6,8,9,7,8,7,2,5,15,1,8,0,6,3,3,3,3,3,5,6,6,8,9,6,8,8,7,8,7,2,5,15,4,7,11,6,1,9,0,3,5,7,8,11,1,8,1,3,3,3,5,1,8,2,8,3,3,15,3,3,3,5,11,10,1,9,0,1,15,1,8,3,14,3,3,3,3,15,15,3,3,3,3,3,5,11,10,1,9,0,15,2,9,0,9,1,7,6,8,9,6,8,8,7,8,7,5,2,2,15,3,15,15,15,1,9,1,2,7,11,6,1,9,0,3,1,8,4,11,66,111,114,114,111,119,69,118,101,110,116,5,67,108,111,99,107,4,67,111,105,110,12,68,101,112,111,115,105,116,69,118,101,110,116,9,73,110,99,101,110,116,105,118,101,20,76,105,113,117,105,100,97,116,105,111,110,67,97,108,108,69,118,101,110,116,4,80,111,111,108,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,112,97,121,69,118,101,110,116,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,13,87,105,116,104,100,114,97,119,69,118,101,110,116,6,97,109,111,117,110,116,6,98,111,114,114,111,119,5,99,108,111,99,107,4,99,111,105,110,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,9,105,110,99,101,110,116,105,118,101,7,108,101,110,100,105,110,103,16,108,105,113,117,105,100,97,116,101,95,97,109,111,117,110,116,14,108,105,113,117,105,100,97,116,101,95,117,115,101,114,16,108,105,113,117,105,100,97,116,105,111,110,95,99,97,108,108,5,108,111,103,105,99,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,114,97,99,108,101,5,112,97,117,115,101,4,112,111,111,108,5,114,101,112,97,121,7,114,101,115,101,114,118,101,6,115,101,110,100,101,114,10,115,112,108,105,116,95,99,111,105,110,7,115,116,111,114,97,103,101,2,116,111,10,116,120,95,99,111,110,116,101,120,116,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,13,117,112,100,97,116,101,95,114,101,119,97,114,100,5,117,116,105,108,115,5,118,97,108,117,101,15,119,104,101,110,95,110,111,116,95,112,97,117,115,101,100,8,119,105,116,104,100,114,97,119,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,41,160,0,0,0,0,0,0,0,2,3,36,2,37,5,12,3,1,2,4,36,2,37,5,40,5,12,3,2,2,3,36,2,37,5,12,3,3,2,3,36,2,37,5,12,3,4,2,4,36,2,37,5,28,5,27,3,0,0,0,0,1,8,11,0,17,17,32,4,5,5,7,7,0,39,2,1,1,4,0,8,45,10,1,46,17,0,10,7,46,17,20,12,11,11,6,10,0,10,1,10,3,10,11,17,6,11,4,11,5,10,7,56,0,12,12,14,12,56,1,12,9,10,2,11,12,11,7,56,2,11,2,10,9,12,8,46,11,8,56,3,12,10,11,0,11,1,10,3,10,11,11,10,77,56,4,11,3,11,11,11,9,18,0,56,5,2,2,1,4,0,21,50,10,2,46,17,0,10,8,46,17,20,12,14,11,7,10,0,10,2,10,4,10,14,17,6,10,3,11,5,12,9,46,11,9,56,3,12,13,11,0,11,1,11,2,10,4,11,14,11,13,77,56,6,12,11,10,3,11,11,12,10,46,11,10,56,7,12,12,11,3,10,12,10,6,10,8,56,8,11,4,11,8,46,17,20,11,6,11,12,18,1,56,9,2,3,1,4,0,25,35,10,2,46,17,0,10,6,46,17,20,12,9,10,3,10,5,12,7,46,11,7,56,3,12,8,11,0,11,1,11,2,10,4,10,9,11,8,77,56,10,11,3,10,5,11,9,10,6,56,8,11,4,11,6,46,17,20,11,5,18,2,56,11,2,4,1,4,0,27,65,10,2,46,17,0,10,7,46,17,20,12,14,11,5,11,6,10,7,56,0,12,15,14,15,56,1,12,13,10,3,11,15,10,7,56,2,10,3,10,13,12,8,46,11,8,56,3,12,12,11,0,11,1,11,2,10,4,10,14,11,12,77,56,12,12,10,10,3,11,10,52,12,9,46,11,9,56,7,12,11,10,11,6,0,0,0,0,0,0,0,0,36,4,53,11,3,10,11,11,14,10,7,56,8,5,55,11,3,1,11,4,11,7,46,17,20,11,13,11,11,23,18,3,56,13,2,5,1,4,0,30,90,10,2,46,17,0,10,11,46,17,20,12,23,11,10,10,0,10,2,10,5,10,8,17,6,11,7,11,9,10,11,56,0,12,24,14,24,56,1,12,18,10,4,11,24,10,11,56,2,10,4,11,18,12,12,46,11,12,56,3,12,21,11,0,11,1,11,2,10,8,10,5,11,3,11,21,77,56,14,12,25,12,17,12,16,10,4,11,17,52,12,13,46,11,13,56,7,12,20,11,4,11,20,10,23,10,11,56,8,10,6,11,16,52,12,14,46,11,14,56,15,12,19,10,6,10,19,10,23,11,11,56,16,10,6,11,25,52,12,15,46,11,15,56,15,12,22,11,6,10,22,56,17,11,5,11,23,11,8,11,19,11,22,22,18,4,56,18,2,0],"logic":[161,28,235,11,6,0,0,0,10,1,0,20,2,20,12,3,32,220,2,4,252,2,12,5,136,3,214,2,7,222,5,205,9,8,171,15,128,1,6,171,16,60,12,231,16,222,18,15,197,35,2,0,42,0,11,0,53,0,73,0,48,0,52,3,45,1,74,2,3,2,12,2,2,12,0,6,1,8,0,9,0,8,0,0,18,0,1,1,0,0,21,2,3,1,0,0,17,2,1,1,0,0,20,2,4,1,0,0,19,5,6,2,0,0,0,57,7,1,0,0,56,8,1,0,0,55,9,1,0,0,36,10,1,0,0,15,10,1,0,0,35,10,1,0,0,14,10,1,0,0,39,11,12,0,0,64,13,14,0,0,63,15,4,0,0,16,15,4,0,0,62,11,4,0,0,65,11,4,0,0,67,16,4,0,0,61,16,4,0,0,60,17,4,0,0,66,17,4,0,0,38,17,12,0,0,40,17,12,0,0,8,18,19,0,1,4,44,4,0,1,5,9,4,0,1,6,22,4,0,1,7,22,4,0,1,9,21,4,0,1,10,44,4,0,2,14,10,1,0,2,15,10,1,0,2,22,31,4,0,2,23,9,32,0,2,24,9,22,0,2,25,9,22,0,2,26,31,3,0,2,27,9,6,0,2,28,31,28,0,2,29,27,28,0,2,30,9,22,0,2,31,9,4,0,2,32,39,40,0,2,33,17,22,0,2,34,34,1,0,2,35,10,1,0,2,36,10,1,0,2,37,21,1,0,2,50,17,1,0,2,51,17,1,0,2,55,34,1,0,2,56,33,1,0,2,58,17,1,0,2,59,17,1,0,3,68,21,1,1,0,3,69,21,1,1,0,3,70,25,1,2,0,0,3,71,21,1,1,0,3,72,21,1,1,0,4,46,1,4,0,4,47,22,4,0,4,49,22,4,0,5,44,22,4,0,7,13,46,12,1,0,8,43,1,4,0,9,54,30,3,0,56,20,59,20,55,20,58,20,57,24,64,28,5,6,8,2,7,8,0,2,5,15,0,6,6,8,2,6,8,1,7,8,0,2,5,15,1,3,1,15,7,6,8,2,6,8,1,7,8,0,5,2,2,15,3,15,15,15,2,6,8,2,7,8,0,3,6,8,2,7,8,0,2,2,7,8,0,2,4,7,8,0,2,5,15,4,6,8,2,6,8,1,7,8,0,5,1,1,4,6,8,2,6,8,1,7,8,0,10,5,1,10,15,4,6,8,2,7,8,0,6,8,1,5,5,6,8,2,6,8,1,7,8,0,2,5,3,7,8,0,2,5,7,6,8,2,7,8,0,6,8,1,5,2,2,15,6,15,15,15,15,15,1,1,9,0,3,7,8,0,2,15,2,15,15,6,15,15,1,15,15,15,2,9,0,9,1,4,7,8,0,2,2,15,2,2,2,1,6,8,0,1,2,18,2,15,15,15,15,3,15,15,3,15,15,15,15,15,15,15,15,15,1,6,8,2,2,6,8,0,2,5,15,15,15,15,15,6,7,8,0,2,15,15,3,15,4,7,8,0,2,15,15,4,15,3,3,10,15,1,5,4,15,15,15,15,9,5,6,2,15,15,10,2,3,3,15,15,2,6,8,0,5,2,10,2,10,2,9,5,2,6,2,15,10,2,3,3,15,15,7,5,6,2,3,3,15,10,2,15,3,2,15,2,4,6,8,2,6,8,1,15,2,2,5,10,2,2,6,10,9,0,6,9,0,18,2,15,15,15,15,1,15,15,15,15,15,2,15,15,15,15,15,15,5,67,108,111,99,107,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,7,97,100,100,114,101,115,115,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,21,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,21,99,97,108,99,117,108,97,116,101,95,115,117,112,112,108,121,95,114,97,116,101,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,10,99,97,108,99,117,108,97,116,111,114,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,29,100,121,110,97,109,105,99,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,15,101,120,101,99,117,116,101,95,100,101,112,111,115,105,116,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,103,101,116,95,97,115,115,101,116,95,108,116,118,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,7,105,115,95,108,111,97,110,7,108,101,110,100,105,110,103,5,108,111,103,105,99,3,109,97,120,3,109,105,110,6,111,114,97,99,108,101,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,9,115,97,102,101,95,109,97,116,104,7,115,116,111,114,97,103,101,12,116,105,109,101,115,116,97,109,112,95,109,115,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,19,117,112,100,97,116,101,95,115,116,97,116,101,95,111,102,95,97,108,108,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,24,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,95,98,97,116,99,104,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,6,118,101,99,116,111,114,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,3,8,33,78,0,0,0,0,0,0,3,8,34,78,0,0,0,0,0,0,3,8,35,78,0,0,0,0,0,0,3,8,36,78,0,0,0,0,0,0,3,8,37,78,0,0,0,0,0,0,3,8,38,78,0,0,0,0,0,0,0,3,0,0,1,26,11,0,10,1,17,5,10,1,10,2,10,4,56,0,10,1,10,2,10,3,11,4,17,8,10,1,10,2,10,3,17,22,32,4,22,10,1,10,2,11,3,17,53,11,1,11,2,17,7,2,1,3,0,0,22,92,10,2,10,3,10,4,17,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,16,11,2,1,11,1,1,11,0,1,7,4,39,10,0,10,2,17,5,10,2,10,3,10,5,56,1,10,2,10,3,10,4,17,20,12,7,11,5,10,7,17,63,12,6,10,2,10,3,10,4,10,6,17,9,11,0,11,1,10,2,10,4,17,12,4,44,5,48,11,2,1,7,0,39,10,6,10,7,33,4,61,10,2,10,3,10,4,17,22,4,61,10,2,10,3,10,4,17,49,10,7,10,6,36,4,86,10,7,10,6,23,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,4,86,10,2,10,3,11,7,10,6,23,17,48,10,2,10,3,10,4,17,22,4,86,10,2,10,3,11,4,17,49,11,2,11,3,17,7,11,6,52,2,2,3,0,0,1,37,10,0,10,2,17,5,10,2,10,3,10,5,56,2,10,2,10,3,10,4,11,5,17,10,10,2,10,3,10,4,17,23,32,4,22,10,2,10,3,10,4,17,54,11,0,11,1,10,2,11,4,17,12,4,29,5,33,11,2,1,7,0,39,11,2,11,3,17,7,2,3,3,0,0,6,58,10,2,10,3,10,4,17,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,8,5,14,11,2,1,11,0,1,7,5,39,11,0,10,2,17,5,10,2,10,3,10,5,56,3,10,2,10,3,10,4,17,21,12,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,5,12,8,10,6,10,5,35,4,40,10,6,12,8,11,5,10,6,23,12,7,10,2,10,3,10,4,10,8,17,11,11,8,11,6,33,4,53,10,2,10,3,11,4,17,50,11,2,11,3,17,7,11,7,2,4,3,0,0,23,92,10,2,10,5,10,3,17,23,4,6,5,14,11,2,1,11,1,1,11,0,1,7,3,39,10,2,10,4,10,3,17,22,4,20,5,28,11,2,1,11,1,1,11,0,1,7,2,39,10,0,10,2,17,5,10,2,10,5,10,4,10,6,56,4,10,0,10,1,10,2,10,3,17,12,32,4,44,5,52,11,2,1,11,1,1,11,0,1,7,1,39,11,0,10,2,11,1,10,3,10,4,10,5,11,6,17,24,12,9,12,8,12,12,12,7,12,11,12,10,10,2,10,5,10,3,11,11,17,11,10,2,10,4,10,3,11,10,17,9,11,9,4,82,10,2,10,5,11,3,17,50,10,2,11,4,17,7,11,2,11,5,17,7,11,7,11,8,11,12,2,5,0,0,0,26,25,10,1,46,17,40,12,2,49,0,12,3,10,3,10,2,35,4,20,5,11,10,0,10,1,10,3,17,6,11,3,49,1,22,12,3,5,6,11,1,1,11,0,1,2,6,0,0,0,29,97,11,0,17,66,12,8,10,1,10,2,12,3,46,11,3,17,37,12,11,10,8,11,11,23,77,74,232,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,18,10,1,10,2,17,36,12,4,12,6,10,1,10,2,17,35,12,5,12,7,10,18,11,7,17,28,10,6,17,62,12,13,11,18,11,5,17,27,10,4,17,62,12,12,10,1,10,2,17,34,1,12,14,1,1,1,10,1,10,2,17,41,12,19,12,20,10,19,10,12,10,4,23,17,62,12,9,11,20,10,13,11,6,23,17,62,12,10,11,9,10,12,17,61,12,15,11,10,10,13,17,61,12,17,11,19,10,12,11,4,23,17,62,11,14,17,62,10,12,17,61,12,16,10,1,10,2,11,12,11,13,11,8,10,16,17,52,11,1,11,2,11,17,11,15,11,16,22,17,45,2,7,0,0,0,22,15,10,0,10,1,17,26,12,2,10,0,10,1,10,2,17,29,12,3,11,0,11,1,11,2,11,3,17,51,2,8,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,47,2,9,0,0,0,22,15,10,0,10,1,17,36,1,12,5,11,3,11,5,17,61,12,4,11,0,11,1,11,2,11,4,17,32,2,10,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,46,2,11,0,0,0,22,15,10,0,10,1,17,36,12,4,1,11,3,11,4,17,61,12,5,11,0,11,1,11,2,11,5,17,31,2,12,1,0,0,1,8,11,0,11,2,11,1,11,3,17,14,17,60,38,2,13,1,0,0,35,37,14,3,65,36,12,6,6,0,0,0,0,0,0,0,0,12,5,64,4,0,0,0,0,0,0,0,0,12,7,10,5,10,6,35,4,29,5,12,10,0,10,2,10,1,14,3,10,5,66,36,20,17,14,12,4,13,7,11,4,68,4,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,7,11,2,1,11,1,1,11,0,1,11,7,2,14,1,0,0,37,33,10,0,10,2,10,1,10,3,17,16,12,6,10,0,10,1,10,2,10,3,17,15,12,5,11,0,11,2,11,1,11,3,17,17,12,7,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,29,11,6,11,7,17,61,11,5,17,62,12,4,5,31,17,65,12,4,11,4,2,15,1,0,0,38,72,10,1,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,6,0,0,0,0,0,0,0,0,12,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,10,9,10,10,35,4,56,5,22,14,8,10,9,66,28,12,5,10,1,10,5,20,17,38,12,11,1,1,10,0,10,2,10,1,11,5,20,10,3,17,19,12,12,11,6,10,12,11,11,17,62,22,12,6,11,7,11,12,22,12,7,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,17,11,1,1,11,2,1,11,0,1,10,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,11,6,11,7,17,61,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,16,1,0,0,41,59,10,2,10,3,12,4,46,11,4,17,43,1,12,8,14,8,65,28,12,10,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,6,0,0,0,0,0,0,0,0,12,9,10,9,10,10,35,4,51,5,20,14,8,10,9,66,28,12,6,10,2,10,6,20,12,5,46,11,5,17,33,12,11,10,0,10,1,10,2,11,6,20,10,3,17,19,12,7,11,12,11,7,11,11,17,62,22,12,12,11,9,6,1,0,0,0,0,0,0,0,22,12,9,5,15,11,2,1,11,1,1,11,0,1,11,12,2,17,1,0,0,42,49,10,2,10,3,12,4,46,11,4,17,43,12,9,1,14,9,65,28,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,10,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,41,5,20,14,9,10,6,66,28,12,5,10,0,10,1,10,2,11,5,20,10,3,17,18,12,8,11,10,11,8,22,12,10,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,15,11,2,1,11,1,1,11,0,1,11,10,2,18,1,0,0,43,18,10,2,10,3,11,4,17,21,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,19,1,0,0,43,18,10,2,10,3,11,4,17,20,12,6,11,2,11,3,12,5,46,11,5,17,39,12,7,11,0,11,1,11,6,11,7,17,30,2,20,1,0,0,22,15,10,0,10,1,11,2,17,44,1,12,3,11,0,11,1,17,36,1,12,4,11,3,11,4,17,62,2,21,1,0,0,22,15,10,0,10,1,11,2,17,44,12,3,1,11,0,11,1,17,36,12,4,1,11,3,11,4,17,62,2,22,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,1,12,4,14,4,14,1,56,5,2,23,1,0,0,45,12,11,0,11,2,12,3,46,11,3,17,43,12,4,1,14,4,14,1,56,5,2,24,0,0,0,47,113,10,1,10,4,17,38,1,12,15,12,16,10,0,10,2,10,1,10,4,10,3,17,19,11,16,17,62,12,20,10,0,10,2,10,1,10,5,11,3,17,18,12,19,9,12,12,10,19,10,20,35,4,32,11,19,12,20,8,12,12,10,1,10,5,12,7,46,11,7,17,39,12,18,10,0,10,2,11,6,11,18,17,30,12,21,10,21,10,20,36,4,54,11,21,10,20,23,12,11,5,58,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,11,11,21,12,20,10,20,11,15,17,62,12,8,11,1,10,4,17,42,12,22,10,8,11,22,17,62,12,23,10,20,10,23,23,12,17,10,0,10,2,10,20,10,4,17,25,12,13,10,0,10,2,11,20,10,5,17,25,12,14,10,0,10,2,11,17,10,4,17,25,12,9,10,0,10,2,11,23,11,4,17,25,12,24,11,0,11,2,11,11,11,8,22,11,5,17,25,12,10,11,13,11,14,11,9,11,24,11,10,11,12,2,0,41,0],"pool":[161,28,235,11,6,0,0,0,14,1,0,18,2,18,54,3,72,145,1,4,217,1,30,5,247,1,203,1,7,194,3,145,4,8,211,7,96,6,179,8,20,10,199,8,67,11,138,9,2,12,140,9,146,3,13,158,12,6,14,164,12,6,15,170,12,4,0,37,1,13,1,47,2,14,2,15,2,23,2,36,2,44,2,46,0,2,12,1,0,1,0,3,12,0,0,5,3,0,0,4,3,0,0,6,3,0,0,7,3,0,1,8,7,0,2,10,7,0,3,0,4,1,0,1,4,1,12,1,0,1,6,11,4,0,8,9,2,0,0,28,0,1,0,0,17,2,1,1,0,0,20,3,1,1,0,0,50,4,1,1,0,0,21,5,1,1,0,0,52,6,1,1,0,0,51,7,1,1,0,0,26,8,9,1,0,0,16,10,11,0,0,35,12,11,1,0,0,48,12,11,1,0,2,25,1,26,1,0,2,30,26,27,0,3,31,25,11,1,0,3,42,29,19,1,0,3,49,32,11,1,0,3,53,1,19,1,0,4,24,30,24,1,0,4,29,24,19,1,0,4,49,23,11,1,0,5,22,18,1,1,3,6,33,0,13,0,7,38,17,1,1,12,7,41,18,1,1,8,8,40,14,15,0,22,16,16,18,23,20,20,21,19,18,18,18,13,18,11,18,20,28,14,18,17,18,20,31,22,24,15,18,7,18,1,7,8,11,0,3,6,8,1,2,7,8,11,3,7,11,0,1,9,0,11,9,1,9,0,7,8,11,4,7,11,0,1,9,0,3,5,7,8,11,2,7,11,0,1,9,0,3,5,7,8,1,7,11,0,1,9,0,3,5,7,8,11,5,6,8,1,7,11,0,1,9,0,3,5,7,8,11,1,6,11,0,1,9,0,1,2,3,3,2,2,1,3,2,6,11,0,1,9,0,3,1,8,10,1,6,8,11,1,5,1,8,1,2,9,0,5,1,9,0,1,11,8,1,9,0,1,11,0,1,9,0,1,8,2,2,11,8,1,9,0,3,1,6,11,9,1,9,0,1,11,9,1,9,0,2,7,11,8,1,9,0,11,8,1,9,0,1,8,7,1,8,6,1,8,4,2,7,11,8,1,9,0,3,2,11,8,1,9,0,7,8,11,1,8,5,1,6,11,8,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,19,80,111,111,108,66,97,108,97,110,99,101,82,101,103,105,115,116,101,114,10,80,111,111,108,67,114,101,97,116,101,11,80,111,111,108,68,101,112,111,115,105,116,12,80,111,111,108,87,105,116,104,100,114,97,119,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,7,99,114,101,97,116,111,114,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,16,100,101,112,111,115,105,116,95,116,114,101,97,115,117,114,121,4,101,109,105,116,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,2,105,100,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,7,108,101,110,100,105,110,103,3,110,101,119,10,110,101,119,95,97,109,111,117,110,116,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,9,114,101,99,105,112,105,101,110,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,7,115,116,111,114,97,103,101,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,4,122,101,114,111,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,17,164,0,0,0,0,0,0,3,8,18,164,0,0,0,0,0,0,0,2,4,27,8,10,14,11,8,1,9,0,45,11,8,1,9,0,19,2,1,2,2,27,8,10,18,5,2,2,1,18,5,3,2,4,40,5,12,3,34,3,37,8,6,4,2,3,40,5,12,3,37,8,6,5,2,4,40,5,39,5,12,3,37,8,6,0,18,0,0,0,0,1,11,10,0,17,21,10,0,46,17,24,18,1,11,0,46,17,24,56,0,2,1,3,0,0,1,13,10,2,17,21,56,1,56,1,11,1,57,0,56,2,11,2,46,17,24,18,2,56,3,2,2,3,0,0,22,20,14,1,56,4,12,4,11,1,56,5,12,3,11,0,54,0,11,3,56,6,1,11,2,46,17,24,11,4,56,7,17,12,18,4,56,8,2,3,3,0,0,24,20,11,0,54,0,10,1,56,9,10,3,56,10,12,4,11,3,46,17,24,10,2,11,1,56,7,17,12,18,5,56,11,11,4,11,2,56,12,2,4,3,0,0,19,22,10,0,55,0,56,13,10,1,38,4,7,5,11,11,0,1,7,1,39,10,0,54,0,11,1,56,9,12,2,11,0,54,1,11,2,56,6,1,2,5,1,0,0,1,22,10,1,55,1,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,1,11,2,56,9,11,4,56,10,11,3,56,12,2,6,3,0,0,1,22,10,1,55,0,56,13,10,2,38,4,7,5,13,11,1,1,11,4,1,7,1,39,11,1,54,0,11,2,56,9,11,4,56,10,11,3,56,12,2,7,1,0,0,1,4,11,0,55,2,20,2,8,1,0,0,1,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,9,1,0,0,9,8,11,0,56,14,12,2,11,1,11,2,49,9,17,8,2,10,1,0,0,9,8,11,0,56,14,12,2,11,1,49,9,11,2,17,8,2,0,1,0,2,0,3,0,18,1,18,2,18,0,32,0,43,0],"ray_math":[161,28,235,11,6,0,0,0,7,1,0,4,3,4,55,5,59,8,7,67,101,8,168,1,64,6,232,1,200,1,12,176,3,168,5,0,6,1,0,0,4,0,1,0,0,9,0,1,0,0,1,0,1,0,0,2,0,1,0,0,11,2,1,0,0,10,2,1,0,0,7,2,1,0,0,5,2,1,0,0,8,1,1,0,0,12,1,1,0,1,3,0,1,0,0,1,15,2,15,15,1,1,7,97,100,100,114,101,115,115,8,104,97,108,102,95,114,97,121,8,104,97,108,102,95,119,97,100,3,109,97,120,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,10,114,97,121,95,116,111,95,119,97,100,3,119,97,100,7,119,97,100,95,100,105,118,7,119,97,100,95,109,117,108,10,119,97,100,95,116,111,95,114,97,121,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,100,167,179,182,224,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,178,211,89,91,240,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,77,4,0,0,0,0,0,0,3,8,78,4,0,0,0,0,0,0,3,8,79,4,0,0,0,0,0,0,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,0,2,2,1,0,0,0,2,7,3,2,3,1,0,0,0,2,7,1,2,4,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,1,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,1,22,7,0,26,2,5,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,0,26,37,4,20,5,22,7,5,39,11,0,7,0,24,11,2,22,11,1,26,2,6,1,0,0,3,34,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,2,5,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,2,11,2,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,17,10,7,3,23,10,1,26,37,4,24,5,26,7,5,39,11,0,11,1,24,7,3,22,7,2,26,2,7,1,0,0,1,30,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,7,39,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,2,10,0,17,10,10,2,23,7,2,26,37,4,20,5,22,7,5,39,11,0,7,2,24,11,2,22,11,1,26,2,8,1,0,0,2,19,7,4,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,1,10,1,11,0,22,12,2,10,2,11,1,38,4,13,5,15,7,6,39,11,2,7,4,26,2,9,1,0,0,1,15,10,0,7,4,24,12,1,10,1,7,4,26,11,0,33,4,11,5,13,7,5,39,11,1,2,0],"safe_math":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,30,5,32,6,7,38,34,8,72,32,6,104,50,12,154,1,163,2,0,5,0,0,0,1,0,0,6,0,1,0,0,4,0,1,0,0,1,0,1,0,0,3,0,1,0,0,2,0,1,0,2,15,15,1,15,0,3,97,100,100,3,100,105,118,3,109,105,110,3,109,111,100,3,109,117,108,9,115,97,102,101,95,109,97,116,104,3,115,117,98,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,3,8,233,3,0,0,0,0,0,0,3,8,234,3,0,0,0,0,0,0,3,8,235,3,0,0,0,0,0,0,3,8,236,3,0,0,0,0,0,0,3,8,237,3,0,0,0,0,0,0,0,1,0,0,1,13,10,0,11,1,22,12,2,10,2,11,0,38,4,9,5,11,7,0,39,11,2,2,1,1,0,0,2,11,10,1,10,0,37,4,5,5,7,7,1,39,11,0,11,1,23,2,2,1,0,0,1,21,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,0,10,1,24,12,2,10,2,11,0,26,11,1,33,4,17,5,19,7,2,39,11,2,2,3,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,5,5,7,7,3,39,11,0,11,1,26,2,4,1,0,0,2,11,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,5,5,7,7,4,39,11,0,11,1,25,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,0],"storage":[161,28,235,11,6,0,0,0,12,1,0,29,2,29,92,3,121,144,3,4,137,4,54,5,191,4,153,3,7,216,7,131,16,8,219,23,96,6,187,24,93,10,152,25,164,1,12,188,26,186,19,13,246,45,66,15,184,46,2,0,120,0,90,0,94,1,22,1,131,1,1,141,1,2,30,2,31,2,47,2,85,2,123,2,127,2,130,1,0,4,12,0,0,11,12,0,0,10,12,0,0,9,4,0,0,20,4,0,0,8,5,0,0,19,5,0,0,15,4,0,0,0,4,0,0,3,4,0,0,12,3,0,0,5,3,0,1,6,12,1,0,1,1,7,12,0,3,13,7,0,4,17,7,0,6,1,8,0,7,2,12,1,0,1,9,18,4,0,10,14,12,2,7,1,4,1,12,16,2,0,0,73,0,1,0,0,144,1,2,1,0,0,143,1,3,1,0,0,74,4,1,1,0,0,115,5,1,0,0,117,6,1,0,0,107,6,1,0,0,112,6,1,0,0,118,6,1,0,0,106,6,1,0,0,113,6,1,0,0,108,6,1,0,0,116,6,1,0,0,114,6,1,0,0,110,6,1,0,0,109,6,1,0,0,111,6,1,0,0,102,2,1,1,0,0,88,2,7,0,0,59,2,8,0,0,64,9,10,0,0,58,11,8,0,0,52,11,12,0,0,60,13,14,0,0,50,13,14,0,0,53,13,15,0,0,55,13,15,0,0,61,13,15,0,0,65,16,15,0,0,56,11,17,0,0,49,11,14,0,0,63,13,14,0,0,62,11,14,0,0,51,13,18,0,0,57,13,19,0,0,133,1,20,1,0,0,134,1,21,1,0,0,68,20,1,0,0,70,22,1,0,0,44,22,1,0,0,69,22,1,0,0,43,22,1,0,0,67,23,1,0,0,42,23,1,0,0,71,24,1,0,0,136,1,16,1,0,0,97,16,1,0,0,135,1,16,1,0,0,96,16,1,0,0,146,1,25,1,1,0,0,45,3,1,0,1,36,43,1,1,0,1,132,1,62,17,1,0,1,145,1,63,1,1,0,2,93,1,14,0,4,48,1,38,1,0,4,75,38,12,0,5,35,57,7,1,0,5,72,57,59,1,0,5,95,60,36,1,0,6,125,40,17,0,7,54,42,8,1,0,8,46,36,1,1,3,9,84,0,26,0,10,21,41,1,2,7,4,10,25,49,50,2,7,4,10,28,46,47,2,7,4,10,35,49,7,2,7,4,10,84,0,33,2,7,4,10,95,46,55,2,7,4,11,91,30,1,1,12,11,119,36,1,1,8,12,105,27,28,0,70,29,70,31,68,32,68,34,71,35,17,36,55,36,68,39,64,32,61,36,51,36,62,44,66,32,65,32,67,34,65,34,67,39,65,39,69,39,64,39,64,34,66,34,57,8,58,8,59,8,52,36,53,36,1,7,8,20,0,1,6,8,2,2,6,8,1,7,8,2,20,6,8,1,6,8,13,6,8,16,7,8,2,2,1,15,15,15,15,15,15,15,15,15,15,15,15,6,11,17,1,9,0,7,8,20,3,6,8,0,7,8,2,1,4,6,8,0,7,8,2,2,15,1,1,1,2,2,6,8,2,5,2,10,2,10,2,2,6,8,2,2,1,8,14,2,7,8,2,2,1,15,2,15,15,3,7,8,2,2,5,1,3,5,15,15,15,15,15,3,15,15,15,4,7,8,2,2,15,15,6,7,8,2,2,15,15,3,15,4,7,8,2,2,5,15,3,7,8,7,5,15,3,7,8,2,2,15,8,6,8,1,6,8,13,7,8,2,2,7,11,12,1,9,0,3,5,7,8,20,1,8,18,1,6,8,20,1,5,1,8,1,2,9,0,5,1,8,0,2,2,8,3,1,11,19,2,9,0,9,1,2,5,8,4,1,8,2,1,9,0,18,2,15,15,15,8,7,8,7,3,8,8,8,9,2,8,14,1,15,15,15,2,2,8,3,1,8,15,2,5,15,1,6,8,16,3,7,11,19,2,9,0,9,1,9,0,9,1,1,6,11,17,1,9,0,3,6,8,13,2,7,8,20,1,8,11,1,7,8,3,2,7,11,19,2,9,0,9,1,9,0,1,7,9,1,3,2,2,8,14,2,6,11,19,2,9,0,9,1,9,0,1,6,9,1,1,6,8,4,1,6,8,3,3,15,6,8,3,15,3,7,8,7,7,8,3,7,8,7,1,9,1,3,10,2,8,4,7,8,4,2,6,10,9,0,6,9,0,2,3,7,8,4,2,1,3,2,7,10,9,0,3,5,2,3,7,15,3,3,2,6,11,12,1,9,0,3,5,6,8,13,7,11,12,1,9,0,3,5,7,8,20,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,12,67,111,105,110,77,101,116,97,100,97,116,97,18,76,105,113,117,105,100,97,116,105,111,110,70,97,99,116,111,114,115,8,79,119,110,101,114,67,97,112,6,80,97,117,115,101,100,4,80,111,111,108,12,80,111,111,108,65,100,109,105,110,67,97,112,23,82,101,115,101,114,118,101,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,11,82,101,115,101,114,118,101,68,97,116,97,7,83,116,111,114,97,103,101,15,83,116,111,114,97,103,101,65,100,109,105,110,67,97,112,26,83,116,111,114,97,103,101,67,111,110,102,105,103,117,114,97,116,111,114,83,101,116,116,105,110,103,6,83,116,114,105,110,103,5,84,97,98,108,101,12,84,111,107,101,110,66,97,108,97,110,99,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,20,85,115,101,114,67,111,110,102,105,103,117,114,97,116,105,111,110,77,97,112,8,85,115,101,114,73,110,102,111,3,97,100,100,5,97,115,99,105,105,9,98,97,115,101,95,114,97,116,101,5,98,111,110,117,115,6,98,111,114,114,111,119,14,98,111,114,114,111,119,95,98,97,108,97,110,99,101,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,5,99,108,111,99,107,4,99,111,105,110,9,99,111,105,110,95,116,121,112,101,11,99,111,108,108,97,116,101,114,97,108,115,12,99,111,110,102,105,103,117,114,97,116,111,114,8,99,111,110,116,97,105,110,115,11,99,114,101,97,116,101,95,112,111,111,108,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,20,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,115,117,112,112,108,121,95,114,97,116,101,4,100,97,116,97,16,100,101,99,114,101,97,115,101,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,12,100,101,115,116,111,114,121,95,117,115,101,114,4,101,109,105,116,5,101,118,101,110,116,3,103,101,116,13,103,101,116,95,97,115,115,101,116,95,108,116,118,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,13,103,101,116,95,99,111,105,110,95,116,121,112,101,16,103,101,116,95,99,117,114,114,101,110,116,95,114,97,116,101,12,103,101,116,95,100,101,99,105,109,97,108,115,9,103,101,116,95,105,110,100,101,120,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,23,103,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,13,103,101,116,95,111,114,97,99,108,101,95,105,100,18,103,101,116,95,114,101,115,101,114,118,101,115,95,99,111,117,110,116,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,20,103,101,116,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,15,103,101,116,95,117,115,101,114,95,97,115,115,101,116,115,16,103,101,116,95,117,115,101,114,95,98,97,108,97,110,99,101,2,105,100,16,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,98,97,108,97,110,99,101,95,102,111,114,95,112,111,111,108,23,105,110,99,114,101,97,115,101,95,98,111,114,114,111,119,95,98,97,108,97,110,99,101,23,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,95,98,97,108,97,110,99,101,25,105,110,99,114,101,97,115,101,95,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,114,101,115,101,114,118,101,11,105,110,116,111,95,115,116,114,105,110,103,11,105,115,95,105,115,111,108,97,116,101,100,20,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,108,105,113,117,105,100,97,116,105,111,110,95,102,97,99,116,111,114,115,5,108,111,97,110,115,5,108,111,103,105,99,3,108,116,118,10,109,117,108,116,105,112,108,105,101,114,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,111,114,97,99,108,101,95,105,100,5,112,97,117,115,101,6,112,97,117,115,101,100,4,112,111,111,108,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,5,114,97,116,105,111,3,114,97,121,8,114,97,121,95,109,97,116,104,6,114,101,109,111,118,101,23,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,115,14,114,101,115,101,114,118,101,95,102,97,99,116,111,114,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,97,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,98,15,114,101,115,101,114,118,101,95,102,105,101,108,100,95,99,18,114,101,115,101,114,118,101,95,118,97,108,105,100,97,116,105,111,110,8,114,101,115,101,114,118,101,115,14,114,101,115,101,114,118,101,115,95,99,111,117,110,116,6,115,101,110,100,101,114,13,115,101,116,95,98,97,115,101,95,114,97,116,101,14,115,101,116,95,98,111,114,114,111,119,95,99,97,112,24,115,101,116,95,106,117,109,112,95,114,97,116,101,95,109,117,108,116,105,112,108,105,101,114,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,98,111,110,117,115,21,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,114,97,116,105,111,25,115,101,116,95,108,105,113,117,105,100,97,116,105,111,110,95,116,104,114,101,115,104,111,108,100,7,115,101,116,95,108,116,118,14,115,101,116,95,109,117,108,116,105,112,108,105,101,114,23,115,101,116,95,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,9,115,101,116,95,112,97,117,115,101,18,115,101,116,95,114,101,115,101,114,118,101,95,102,97,99,116,111,114,14,115,101,116,95,115,117,112,112,108,121,95,99,97,112,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,7,115,116,111,114,97,103,101,14,115,117,112,112,108,121,95,98,97,108,97,110,99,101,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,9,116,104,114,101,115,104,111,108,100,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,16,116,114,101,97,115,117,114,121,95,98,97,108,97,110,99,101,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,12,117,112,100,97,116,101,95,115,116,97,116,101,23,117,112,100,97,116,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,17,117,112,100,97,116,101,95,117,115,101,114,95,108,111,97,110,115,9,117,115,101,114,95,105,110,102,111,10,117,115,101,114,95,115,116,97,116,101,5,117,115,101,114,115,5,118,97,108,117,101,6,118,101,99,116,111,114,7,118,101,114,115,105,111,110,15,118,101,114,115,105,111,110,95,109,105,103,114,97,116,101,20,118,101,114,115,105,111,110,95,118,101,114,105,102,105,99,97,116,105,111,110,24,119,105,116,104,100,114,97,119,95,114,101,115,101,114,118,101,95,98,97,108,97,110,99,101,17,119,105,116,104,100,114,97,119,95,116,114,101,97,115,117,114,121,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,3,0,0,0,0,0,0,0,3,8,248,167,0,0,0,0,0,0,3,8,249,167,0,0,0,0,0,0,3,8,250,167,0,0,0,0,0,0,3,8,251,167,0,0,0,0,0,0,3,8,252,167,0,0,0,0,0,0,3,8,253,167,0,0,0,0,0,0,3,8,254,167,0,0,0,0,0,0,3,8,255,167,0,0,0,0,0,0,2,1,255,0,2,1,66,8,18,1,2,1,66,8,18,2,2,7,66,8,18,142,1,3,89,1,103,11,19,2,2,8,3,104,2,139,1,10,5,137,1,11,19,2,5,8,4,3,2,21,66,2,87,2,32,8,14,76,1,122,15,27,15,40,15,38,15,39,15,37,15,121,8,7,26,8,7,78,3,82,15,129,1,15,128,1,15,29,8,8,79,8,9,99,15,100,15,101,15,4,2,2,33,10,2,80,10,2,5,2,1,41,15,6,2,1,41,15,7,2,2,138,1,11,19,2,5,15,126,15,8,2,5,23,15,83,15,77,15,98,15,86,15,9,2,3,92,15,24,15,124,15,10,2,3,105,5,34,5,140,1,1,11,2,1,89,1,0,0,0,0,1,27,10,0,17,63,18,1,10,0,46,17,72,56,0,10,0,17,63,18,0,10,0,46,17,72,56,1,10,0,17,63,7,0,9,10,0,56,2,49,0,64,28,0,0,0,0,0,0,0,0,11,0,56,3,18,2,56,4,2,1,0,0,0,1,10,11,0,16,0,20,7,0,33,4,7,5,9,7,1,39,2,2,1,4,0,1,16,10,1,16,0,20,7,0,35,4,7,5,11,11,1,1,7,2,39,7,0,11,1,15,0,21,2,3,1,4,0,37,117,10,3,46,17,1,10,3,16,1,20,12,35,10,35,7,9,35,4,12,5,24,11,3,1,11,1,1,11,19,1,11,18,1,11,2,1,7,5,39,10,3,46,56,5,10,3,16,1,20,12,20,11,4,12,29,56,6,17,56,12,30,11,5,12,31,11,6,12,32,11,7,12,33,17,54,12,34,17,54,12,21,11,13,12,22,11,14,12,23,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,24,10,19,56,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,7,12,25,11,2,17,60,12,26,11,8,11,10,11,11,11,12,11,9,18,8,12,27,11,15,11,16,11,17,18,9,12,28,11,20,11,29,11,30,11,31,11,32,11,33,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,34,11,21,11,24,11,25,11,26,11,22,11,23,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,27,11,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,12,37,10,3,15,2,10,35,11,37,56,8,11,35,49,1,22,11,3,15,1,21,11,18,56,9,12,36,11,1,11,36,11,19,56,10,2,4,1,4,0,1,11,10,1,46,17,1,10,2,11,1,15,3,21,11,2,18,11,56,11,2,5,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,4,21,2,6,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,5,21,2,7,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,6,21,2,8,1,0,0,45,13,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,7,21,2,9,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,9,21,2,10,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,10,21,2,11,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,11,21,2,12,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,12,21,2,13,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,8,15,13,21,2,14,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,15,21,2,15,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,16,21,2,16,1,0,0,45,14,10,1,46,17,1,11,1,15,2,11,2,56,12,12,4,11,3,11,4,15,14,15,17,21,2,17,1,0,0,48,36,56,6,17,56,12,3,10,0,16,1,20,12,1,49,0,12,2,10,2,10,1,35,4,33,5,14,10,0,16,2,10,2,56,13,16,18,20,10,3,34,4,24,5,28,11,0,1,7,7,39,11,2,49,1,22,12,2,5,9,11,0,1,2,18,1,0,0,1,4,11,0,16,3,20,2,19,1,0,0,1,4,11,0,16,1,20,2,20,1,0,0,51,23,10,0,16,19,10,1,56,14,32,4,11,11,0,1,64,8,0,0,0,0,0,0,0,0,64,8,0,0,0,0,0,0,0,0,2,11,0,16,19,11,1,56,15,12,2,10,2,16,20,20,11,2,16,21,20,2,21,1,0,0,1,7,11,0,16,2,11,1,56,13,16,22,20,2,22,1,0,0,1,7,11,0,16,2,11,1,56,13,16,18,20,2,23,1,0,0,1,7,11,0,16,2,11,1,56,13,16,4,20,2,24,1,0,0,1,7,11,0,16,2,11,1,56,13,16,5,20,2,25,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,23,20,11,2,16,24,20,2,26,1,0,0,52,12,11,0,16,2,11,1,56,13,12,2,10,2,16,25,20,11,2,16,26,20,2,27,1,0,0,52,14,11,0,16,2,11,1,56,13,12,2,10,2,16,27,16,28,20,11,2,16,29,16,28,20,2,28,1,0,0,53,41,11,0,16,2,11,1,56,13,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,4,16,27,16,30,10,2,56,16,4,22,10,4,16,27,16,30,10,2,56,17,20,12,5,10,4,16,29,16,30,10,2,56,16,4,36,11,4,16,29,16,30,11,2,56,17,20,12,3,5,38,11,4,1,11,5,11,3,2,29,1,0,0,1,7,11,0,16,2,11,1,56,13,16,31,20,2,30,1,0,0,1,7,11,0,16,2,11,1,56,13,16,6,20,2,31,1,0,0,1,7,11,0,16,2,11,1,56,13,16,7,20,2,32,1,0,0,1,7,11,0,16,2,11,1,56,13,16,32,20,2,33,1,0,0,52,26,11,0,16,2,11,1,56,13,12,2,10,2,16,8,16,9,20,10,2,16,8,16,10,20,10,2,16,8,16,11,20,10,2,16,8,16,12,20,11,2,16,8,16,13,20,2,34,1,0,0,52,18,11,0,16,2,11,1,56,13,12,2,10,2,16,14,16,15,20,10,2,16,14,16,16,20,11,2,16,14,16,17,20,2,35,3,0,0,45,17,10,0,46,17,1,11,0,15,2,11,1,56,12,12,4,11,3,10,4,15,23,21,11,2,11,4,15,24,21,2,36,3,0,0,45,29,10,0,46,17,1,11,0,15,2,11,1,56,12,12,6,11,2,10,6,15,26,21,11,3,10,6,15,25,21,11,4,10,6,15,31,21,10,6,16,32,20,11,5,22,11,6,15,32,21,2,37,3,0,0,54,31,10,0,46,17,1,11,0,15,2,11,1,56,12,12,5,10,5,15,27,12,6,11,5,15,29,12,4,10,6,16,28,20,11,2,22,11,6,15,28,21,10,4,16,28,20,11,3,22,11,4,15,28,21,2,38,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,42,2,39,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,27,11,2,11,3,17,43,2,40,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,42,2,41,3,0,0,1,12,10,0,46,17,1,11,0,15,2,11,1,56,12,15,29,11,2,11,3,17,43,2,42,0,0,0,14,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,0,15,30,11,1,11,3,10,2,22,56,19,10,0,16,28,20,11,2,22,11,0,15,28,21,2,43,0,0,0,14,37,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,10,0,16,30,10,1,56,16,4,12,10,0,15,30,10,1,56,18,12,3,10,3,10,2,38,4,17,5,21,11,0,1,7,6,39,10,0,15,30,11,1,11,3,10,2,23,56,19,10,0,16,28,20,11,2,23,11,0,15,28,21,2,44,3,0,0,45,14,11,0,15,2,11,1,56,12,12,3,10,3,16,32,20,11,2,22,11,3,15,32,21,2,45,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,64,8,0,0,0,0,0,0,0,0,11,3,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,21,14,1,56,22,32,4,37,11,5,15,21,11,1,68,8,5,39,11,5,1,2,46,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,21,14,1,56,23,12,3,4,17,11,4,15,21,11,3,56,24,1,5,19,11,4,1,2,47,3,0,0,56,40,10,0,16,19,10,2,56,14,32,4,21,64,8,0,0,0,0,0,0,0,0,12,3,13,3,11,1,68,8,11,3,64,8,0,0,0,0,0,0,0,0,18,4,12,4,11,0,15,19,11,2,11,4,56,20,5,39,11,0,15,19,11,2,56,21,12,5,10,5,16,20,14,1,56,22,32,4,37,11,5,15,20,11,1,68,8,5,39,11,5,1,2,48,3,0,0,58,20,11,0,15,19,11,2,56,21,12,4,10,4,16,20,14,1,56,23,12,3,4,17,11,4,15,20,11,3,56,24,1,5,19,11,4,1,2,49,1,0,0,61,58,10,2,10,3,12,8,46,11,8,17,22,56,6,17,56,33,4,11,5,21,11,2,1,11,1,1,11,4,1,11,7,1,7,8,39,11,2,15,2,11,3,56,12,15,32,12,10,10,4,10,10,20,52,12,9,46,11,9,56,25,12,11,10,5,12,12,11,5,10,11,35,4,44,11,11,12,12,10,10,20,10,12,77,23,11,10,21,11,1,11,4,11,12,11,6,11,7,56,26,2,50,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,2,1,2,4,2,3,2,2,3,4,3,5,3,13,3,14,3,16,8,0,8,1,8,2,8,3,8,4,3,17,9,0,9,1,9,2,3,2,2,6,4,0,4,1,3,1,3,6,3,7,3,8,3,9,3,10,7,1,3,11,7,0,3,12,3,15,0,81,0],"utils":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,16,3,26,47,4,73,12,5,85,63,7,148,1,156,1,8,176,2,64,6,240,2,20,12,132,3,114,0,14,1,3,1,4,1,12,1,13,1,0,4,1,0,1,2,1,12,1,0,1,4,2,2,0,0,10,0,1,1,0,0,11,0,2,1,0,2,5,1,8,1,0,2,6,1,2,1,0,2,9,7,1,1,0,2,15,5,6,1,0,3,7,11,8,1,12,4,8,9,10,0,5,4,4,4,2,4,6,1,0,4,3,4,3,11,1,1,9,0,3,7,8,2,1,11,1,1,9,0,1,11,0,1,9,0,2,3,11,1,1,9,0,1,9,0,1,6,11,1,1,9,0,1,3,3,7,11,1,1,9,0,3,7,8,2,0,1,6,8,2,1,5,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,4,99,111,105,110,12,100,101,115,116,114,111,121,95,122,101,114,111,12,105,110,116,111,95,98,97,108,97,110,99,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,10,115,112,108,105,116,95,99,111,105,110,21,115,112,108,105,116,95,99,111,105,110,95,116,111,95,98,97,108,97,110,99,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,117,116,105,108,115,5,118,97,108,117,101,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,176,179,0,0,0,0,0,0,3,8,177,179,0,0,0,0,0,0,0,1,0,0,3,44,14,0,56,0,12,3,10,1,6,0,0,0,0,0,0,0,0,36,4,8,5,12,11,2,1,7,0,39,11,3,10,1,38,4,17,5,21,11,2,1,7,1,39,13,0,11,1,10,2,56,1,12,4,14,0,56,0,6,0,0,0,0,0,0,0,0,33,4,37,11,2,1,11,0,56,2,11,4,2,11,0,11,2,46,17,7,56,3,11,4,2,1,1,0,0,8,6,11,0,11,1,11,2,56,4,56,5,2,0],"validation":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,12,3,22,82,4,104,4,5,108,83,7,191,1,154,2,8,217,3,64,6,153,4,70,12,223,4,237,4,0,22,0,15,0,13,1,3,1,16,1,0,12,0,3,1,7,0,4,2,7,0,0,18,0,1,1,0,0,21,0,1,1,0,0,17,0,1,1,0,0,20,0,1,1,0,0,19,2,1,2,0,0,1,5,8,10,0,1,6,7,6,0,1,7,8,9,0,1,8,8,10,0,1,9,8,9,0,2,11,1,10,0,2,12,9,10,0,2,14,9,10,0,4,4,1,5,1,0,4,10,5,6,0,13,4,13,14,3,7,8,0,2,15,0,4,7,8,0,2,2,15,7,7,8,0,2,15,15,15,15,15,1,9,0,1,8,2,1,8,1,2,6,8,0,2,2,7,8,0,2,2,15,15,1,15,8,7,8,0,2,15,15,15,15,15,15,9,7,8,0,2,15,15,15,15,15,15,15,4,7,8,0,2,7,8,0,2,1,9,1,7,83,116,111,114,97,103,101,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,5,97,115,99,105,105,3,103,101,116,28,103,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,95,114,97,116,105,111,13,103,101,116,95,99,111,105,110,95,116,121,112,101,9,103,101,116,95,105,110,100,101,120,22,103,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,16,103,101,116,95,116,111,116,97,108,95,115,117,112,112,108,121,11,105,110,116,111,95,115,116,114,105,110,103,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,7,115,116,111,114,97,103,101,9,116,121,112,101,95,110,97,109,101,15,118,97,108,105,100,97,116,101,95,98,111,114,114,111,119,16,118,97,108,105,100,97,116,101,95,100,101,112,111,115,105,116,18,118,97,108,105,100,97,116,101,95,108,105,113,117,105,100,97,116,101,14,118,97,108,105,100,97,116,101,95,114,101,112,97,121,17,118,97,108,105,100,97,116,101,95,119,105,116,104,100,114,97,119,10,118,97,108,105,100,97,116,105,111,110,216,153,207,125,43,93,183,22,189,44,245,85,153,251,13,94,227,138,48,97,231,182,187,110,235,247,63,165,188,76,129,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,225,171,0,0,0,0,0,0,3,8,226,171,0,0,0,0,0,0,3,8,227,171,0,0,0,0,0,0,3,8,228,171,0,0,0,0,0,0,3,8,229,171,0,0,0,0,0,0,3,8,230,171,0,0,0,0,0,0,3,8,231,171,0,0,0,0,0,0,0,1,0,0,3,58,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,1,12,8,10,0,10,1,17,7,1,12,5,11,8,11,5,17,12,12,7,11,0,11,1,17,8,12,9,11,7,11,2,22,17,10,24,12,6,11,9,11,6,38,4,55,5,57,7,1,39,2,1,1,0,0,11,54,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,10,11,0,11,1,17,7,12,6,12,7,11,10,11,7,17,12,12,9,11,5,11,6,17,12,12,8,11,9,11,8,11,2,22,38,4,51,5,53,7,3,39,2,2,1,0,0,12,71,10,0,10,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,17,11,0,1,7,4,39,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,22,5,26,11,0,1,7,0,39,10,0,10,1,17,9,12,5,12,11,10,0,10,1,17,7,12,6,12,8,11,11,11,8,17,12,12,10,11,5,11,6,17,12,12,9,10,9,10,2,22,10,10,35,4,51,5,55,11,0,1,7,3,39,11,9,11,2,22,11,10,17,11,12,7,11,0,11,1,17,5,11,7,38,4,68,5,70,7,2,39,2,3,1,0,0,8,23,11,0,11,1,12,4,12,3,56,0,17,14,11,3,46,11,4,17,6,33,4,13,5,15,7,4,39,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,20,5,22,7,0,39,2,4,1,0,0,13,40,10,0,11,1,12,5,12,4,56,0,17,14,11,4,46,11,5,17,6,33,4,13,5,17,11,0,1,7,4,39,11,0,11,2,12,7,12,6,56,1,17,14,11,6,46,11,7,17,6,33,4,30,5,32,7,4,39,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,37,5,39,7,0,39,2,0]},"type_origin_table":[{"module_name":"pool","struct_name":"Pool","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolAdminCap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolCreate","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolBalanceRegister","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolDeposit","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"pool","struct_name":"PoolWithdraw","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"OwnerCap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"StorageAdminCap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"Storage","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"ReserveData","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"UserInfo","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"ReserveConfigurationMap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"UserConfigurationMap","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"TokenBalance","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"BorrowRateFactors","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"LiquidationFactors","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"StorageConfiguratorSetting","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"storage","struct_name":"Paused","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"IncentiveBal","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"PoolInfo","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"Incentive","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"PoolOwnerSetting","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"incentive","struct_name":"PoolAdminSetting","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"DepositEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"WithdrawEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"BorrowEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"RepayEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"},{"module_name":"lending","struct_name":"LiquidationCallEvent","package":"0xd899cf7d2b5db716bd2cf55599fb0d5ee38a3061e7b6bb6eebf73fa5bc4c81ca"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":9},"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f":{"upgraded_id":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f","upgraded_version":1}}}},"owner":"Immutable","previous_transaction":"3fqrGiknVvk82qum6zLYR749UTTyavaoH8TLU6bym8di","storage_rebate":213582800},{"data":{"Move":{"type_":"GasCoin","has_public_transfer":true,"version":26932892,"contents":[179,30,221,225,60,75,107,81,44,23,235,191,230,227,135,11,211,138,190,145,151,205,207,128,30,246,4,231,19,97,15,161,200,98,235,223,0,0,0,0]}},"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"previous_transaction":"7SuYS2Zphhb7KFnoanQBArUmXUQjKhehZ5fQkET4wNcN","storage_rebate":988000},{"data":{"Package":{"id":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f","version":1,"module_map":{"oracle":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,36,3,48,102,4,150,1,16,5,166,1,216,1,7,254,2,157,3,8,155,6,64,6,219,6,70,10,161,7,38,12,199,7,251,3,13,194,11,12,0,19,1,11,1,18,1,26,1,29,1,30,0,1,12,0,0,2,12,0,0,4,8,0,0,3,4,0,1,0,8,0,2,7,4,0,3,5,12,2,7,1,4,1,5,6,2,0,0,16,0,1,0,0,37,2,1,0,0,36,3,1,0,0,24,4,1,0,0,22,5,1,0,0,32,6,1,0,0,33,7,1,0,0,14,8,9,0,1,28,24,25,0,2,17,0,11,0,3,8,26,1,2,7,4,3,9,22,34,2,7,4,3,10,28,29,2,7,4,3,12,22,23,2,7,4,3,17,0,18,2,7,4,4,21,15,1,1,12,4,25,20,1,1,8,5,23,12,13,0,15,14,15,16,14,17,16,19,13,17,10,17,12,17,11,17,1,7,8,7,0,1,6,8,2,2,6,8,0,7,8,2,3,6,8,0,7,8,2,3,6,6,8,0,6,8,4,7,8,2,2,15,2,5,6,8,1,6,8,4,7,8,2,2,15,5,6,8,1,6,8,4,7,8,2,10,2,10,15,3,6,8,4,6,8,2,2,3,1,15,2,2,8,5,11,6,2,2,8,3,1,8,5,1,6,8,7,1,5,1,8,0,2,9,0,5,1,8,1,2,2,8,3,1,11,6,2,9,0,9,1,1,8,2,1,9,0,2,2,7,11,6,2,2,8,3,2,6,11,6,2,9,0,9,1,9,0,1,1,1,6,8,4,1,3,3,7,11,6,2,9,0,9,1,9,0,9,1,3,2,7,8,3,7,11,6,2,2,8,3,2,7,11,6,2,9,0,9,1,9,0,1,7,9,1,3,3,3,6,2,1,2,1,15,5,1,3,6,11,6,2,2,8,3,6,8,3,1,1,6,9,1,5,67,108,111,99,107,14,79,114,97,99,108,101,65,100,109,105,110,67,97,112,15,79,114,97,99,108,101,70,101,101,100,101,114,67,97,112,5,80,114,105,99,101,11,80,114,105,99,101,79,114,97,99,108,101,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,7,100,101,99,105,109,97,108,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,2,105,100,4,105,110,105,116,3,110,101,119,6,111,98,106,101,99,116,6,111,114,97,99,108,101,13,112,114,105,99,101,95,111,114,97,99,108,101,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,20,114,101,103,105,115,116,101,114,95,116,111,107,101,110,95,112,114,105,99,101,6,115,101,110,100,101,114,19,115,101,116,95,117,112,100,97,116,101,95,105,110,116,101,114,118,97,108,12,115,104,97,114,101,95,111,98,106,101,99,116,5,116,97,98,108,101,9,116,105,109,101,115,116,97,109,112,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,15,117,112,100,97,116,101,95,105,110,116,101,114,118,97,108,18,117,112,100,97,116,101,95,116,111,107,101,110,95,112,114,105,99,101,24,117,112,100,97,116,101,95,116,111,107,101,110,95,112,114,105,99,101,95,98,97,116,99,104,5,118,97,108,117,101,7,118,101,114,115,105,111,110,15,118,101,114,115,105,111,110,95,109,105,103,114,97,116,101,20,118,101,114,115,105,111,110,95,118,101,114,105,102,105,99,97,116,105,111,110,202,68,27,68,148,60,22,190,14,110,35,197,169,85,187,151,21,55,234,50,137,174,128,22,251,243,63,255,225,253,33,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,48,117,0,0,0,0,0,0,3,8,80,195,0,0,0,0,0,0,3,8,81,195,0,0,0,0,0,0,3,8,82,195,0,0,0,0,0,0,3,8,83,195,0,0,0,0,0,0,3,8,84,195,0,0,0,0,0,0,0,2,1,15,8,5,1,2,1,15,8,5,2,2,4,15,8,5,35,3,31,3,20,11,6,2,2,8,3,3,2,3,34,15,13,2,27,3,0,0,0,0,10,27,10,0,17,9,18,0,10,0,46,17,17,56,0,10,0,17,9,18,1,10,0,46,17,17,56,1,10,0,17,9,12,1,11,0,56,2,12,2,11,1,7,0,7,1,11,2,18,2,56,3,2,1,0,0,0,1,10,11,0,16,0,20,7,0,33,4,7,5,9,7,2,39,2,2,0,4,0,1,16,10,1,16,0,20,7,0,35,4,7,5,11,11,1,1,7,3,39,7,0,11,1,15,0,21,2,3,1,4,0,1,8,10,1,46,17,1,11,2,11,1,15,1,21,2,4,1,4,0,21,30,10,2,46,17,1,11,2,15,2,12,7,10,7,10,3,12,6,46,11,6,56,4,32,4,15,5,21,11,7,1,11,1,1,7,6,39,11,7,11,3,11,4,11,5,11,1,17,8,18,3,56,5,2,5,1,4,0,27,34,10,2,46,17,1,11,2,15,2,12,7,10,7,10,3,12,5,46,11,5,56,4,4,14,5,20,11,7,1,11,1,1,7,5,39,11,7,11,3,56,6,12,6,11,4,10,6,15,3,21,11,1,17,8,11,6,15,4,21,2,6,1,4,0,30,53,10,2,46,17,1,14,3,65,31,12,6,10,6,14,4,65,32,33,4,12,5,20,11,2,1,11,1,1,11,0,1,7,4,39,6,0,0,0,0,0,0,0,0,12,5,10,5,10,6,35,4,46,5,27,14,3,10,5,66,31,12,7,10,0,10,1,10,2,11,7,20,14,4,10,5,66,32,20,17,5,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,22,11,2,1,11,1,1,11,0,1,2,7,1,0,0,33,60,10,1,17,1,10,1,16,2,12,5,10,5,10,2,56,4,4,10,5,18,11,5,1,11,1,1,11,0,1,7,5,39,11,5,11,2,56,7,12,6,11,0,17,8,12,4,9,12,7,10,6,16,3,20,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,44,11,4,10,6,16,4,20,23,11,1,16,1,20,37,12,3,5,48,11,1,1,9,12,3,11,3,4,52,8,12,7,11,7,10,6,16,3,20,11,6,16,5,20,2,2,1,2,2,2,3,3,0,3,2,3,1,0]},"type_origin_table":[{"module_name":"oracle","struct_name":"OracleAdminCap","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"},{"module_name":"oracle","struct_name":"OracleFeederCap","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"},{"module_name":"oracle","struct_name":"PriceOracle","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"},{"module_name":"oracle","struct_name":"Price","package":"0xca441b44943c16be0e6e23c5a955bb971537ea3289ae8016fbf33fffe1fd210f"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":8}}}},"owner":"Immutable","previous_transaction":"5rr1KbGr5ht2kWrPwgArYuaYsauoDG8CpuJLnaKnkgL6","storage_rebate":15010000},{"data":{"Move":{"type_":{"Other":{"address":"0000000000000000000000000000000000000000000000000000000000000002","module":"package","name":"UpgradeCap","type_args":[]}},"has_public_transfer":true,"version":10941462,"contents":[219,161,180,15,53,55,68,27,81,210,132,143,192,161,73,97,14,72,230,124,28,196,140,106,214,65,118,118,34,0,6,35,178,52,89,21,222,31,155,214,97,233,171,39,235,39,227,118,205,246,57,19,89,234,100,251,253,180,85,11,9,44,26,160,4,0,0,0,0,0,0,0,0]}},"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"previous_transaction":"3fqrGiknVvk82qum6zLYR749UTTyavaoH8TLU6bym8di","storage_rebate":1634000}],"local_exec_effects":{"messageVersion":"v1","status":{"status":"success"},"executedEpoch":"158","gasUsed":{"computationCost":"750000","storageCost":"216204800","storageRebate":"2595780","nonRefundableStorageFee":"26220"},"modifiedAtVersions":[{"objectId":"0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1","sequenceNumber":"26932892"},{"objectId":"0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623","sequenceNumber":"10941462"}],"transactionDigest":"4fxF3X4N8D6JGByWdbJvCCv1iuoT8GSEhXgPHJnzNHWP","created":[{"owner":"Immutable","reference":{"objectId":"0x0440aedc27c9a57ea357bd8fe1525a00d60d7f442a380924a7e7c1d79853bb8b","version":5,"digest":"Gm4LuFuwBvgmBuLSMAxEp2zkp1RLsfgwzv8xdscmzowH"}}],"mutated":[{"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"reference":{"objectId":"0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1","version":26932893,"digest":"J4QwR5VqcZDAekVtbABBjvZ6n1sCi4nDS7hBiaDkex37"}},{"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"reference":{"objectId":"0xdba1b40f3537441b51d2848fc0a149610e48e67c1cc48c6ad641767622000623","version":26932893,"digest":"Bt3M5wQ3RStRoKWwioJ8vJUQvxL453r9HWBH2MpBzQaA"}}],"gasObject":{"owner":{"AddressOwner":"0xad5b541177c80832e38054522eb4d1030b43262d5c5d0f0ee2eb034642418c57"},"reference":{"objectId":"0xb31edde13c4b6b512c17ebbfe6e3870bd38abe9197cdcf801ef604e713610fa1","version":26932893,"digest":"J4QwR5VqcZDAekVtbABBjvZ6n1sCi4nDS7hBiaDkex37"}},"dependencies":["3fqrGiknVvk82qum6zLYR749UTTyavaoH8TLU6bym8di","5rr1KbGr5ht2kWrPwgArYuaYsauoDG8CpuJLnaKnkgL6","7SuYS2Zphhb7KFnoanQBArUmXUQjKhehZ5fQkET4wNcN","ACKQVv64dXCmpxE1QPU2QMLxVpmtbzrFGMtWYY6szJrQ","BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn"]},"pre_exec_diag":{"loaded_child_objects":[]}} \ No newline at end of file diff --git a/crates/sui-replay/tests/sandbox_snapshots/ozN2rhczEUC39poaeVYxMN6b6TEAjiFX7jFSQFhbKmL.json b/crates/sui-replay/tests/sandbox_snapshots/ozN2rhczEUC39poaeVYxMN6b6TEAjiFX7jFSQFhbKmL.json deleted file mode 100644 index 72c2e1ff6eb..00000000000 --- a/crates/sui-replay/tests/sandbox_snapshots/ozN2rhczEUC39poaeVYxMN6b6TEAjiFX7jFSQFhbKmL.json +++ /dev/null @@ -1 +0,0 @@ -{"transaction_info":{"tx_digest":"ozN2rhczEUC39poaeVYxMN6b6TEAjiFX7jFSQFhbKmL","sender_signed_data":[{"intent_message":{"intent":{"scope":0,"version":0,"app_id":0},"value":{"V1":{"kind":{"ProgrammableTransaction":{"inputs":[{"Object":{"SharedObject":{"id":"0x79d7106ea18373fc7542b0849d5ebefc3a9daf8b664a4f82d9b35bbd0c22042d","initial_shared_version":3195547,"mutable":false}}},{"Object":{"SharedObject":{"id":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","initial_shared_version":4346051,"mutable":true}}},{"Object":{"SharedObject":{"id":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","initial_shared_version":3478819,"mutable":true}}}],"commands":[{"MoveCall":{"package":"0x7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d","module":"migrate_proposal","function":"migrate_version","type_arguments":[],"arguments":[{"Input":0},{"Input":1},{"Input":2}]}}]}},"sender":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497","gas_data":{"payment":[["0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004",4346051,"2JXT4194QZ7FC7UEs8Hyh9zRpuCBY7PMZXKEXcvRXfu8"]],"owner":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497","price":820,"budget":500000000},"expiration":"None"}}},"tx_signatures":["AOd+1UjKqv2kF/b4EHVzWhv6U5qPXHWYTFiGjCWOFWdHCxDLrQfA79H9TLHDXHnCdKZCp5srbZA83/tBZ1g72gWOFOU0HVyF2bseRzKe9FsEoneTl3bxmBQ7Hi6cHBw6dg=="]}],"sender":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497","input_objects":[{"SharedMoveObject":{"id":"0x79d7106ea18373fc7542b0849d5ebefc3a9daf8b664a4f82d9b35bbd0c22042d","initial_shared_version":3195547,"mutable":false}},{"SharedMoveObject":{"id":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","initial_shared_version":4346051,"mutable":true}},{"SharedMoveObject":{"id":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","initial_shared_version":3478819,"mutable":true}},{"MovePackage":"0x7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d"},{"ImmOrOwnedMoveObject":["0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004",4346051,"2JXT4194QZ7FC7UEs8Hyh9zRpuCBY7PMZXKEXcvRXfu8"]}],"kind":{"ProgrammableTransaction":{"inputs":[{"Object":{"SharedObject":{"id":"0x79d7106ea18373fc7542b0849d5ebefc3a9daf8b664a4f82d9b35bbd0c22042d","initial_shared_version":3195547,"mutable":false}}},{"Object":{"SharedObject":{"id":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","initial_shared_version":4346051,"mutable":true}}},{"Object":{"SharedObject":{"id":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","initial_shared_version":3478819,"mutable":true}}}],"commands":[{"MoveCall":{"package":"0x7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d","module":"migrate_proposal","function":"migrate_version","type_arguments":[],"arguments":[{"Input":0},{"Input":1},{"Input":2}]}}]}},"modified_at_versions":[["0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004",4346051],["0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934",4346051],["0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621",4346049],["0x898dd24cc48476a7a2ff36372a443fefa53545b016feb317bb091e60e06b2e4c",3478819]],"shared_object_refs":[["0x79d7106ea18373fc7542b0849d5ebefc3a9daf8b664a4f82d9b35bbd0c22042d",4346051,"4KddCShzYaYA2QcVbNphjberckmHf3BQQ13QxTqWzqkh"],["0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934",4346051,"4BbiRiXkVTtkgnXwJJM1Px9u9Pw8XcTYeoi8xCAe5AiH"],["0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621",4346049,"Hbp9rYyMyeFxfGkw6EEUfFpmVrc85NfAyTs2mE6EcxHj"]],"gas":[["0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004",4346051,"2JXT4194QZ7FC7UEs8Hyh9zRpuCBY7PMZXKEXcvRXfu8"]],"gas_budget":500000000,"gas_price":820,"executed_epoch":55,"dependencies":["GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","5kWByxejQ95cxQ5zUCba3WyivedWBmtisRa4ZaWJuWpm","6B3tXa5PpoaRUQiYcytsC1M9fkfzXUc49NsWgC335qC1"],"effects":{"messageVersion":"v1","status":{"status":"success"},"executedEpoch":"55","gasUsed":{"computationCost":"820000","storageCost":"8291600","storageRebate":"7967916","nonRefundableStorageFee":"80484"},"modifiedAtVersions":[{"objectId":"0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004","sequenceNumber":"4346051"},{"objectId":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","sequenceNumber":"4346051"},{"objectId":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","sequenceNumber":"4346049"},{"objectId":"0x898dd24cc48476a7a2ff36372a443fefa53545b016feb317bb091e60e06b2e4c","sequenceNumber":"3478819"}],"sharedObjects":[{"objectId":"0x79d7106ea18373fc7542b0849d5ebefc3a9daf8b664a4f82d9b35bbd0c22042d","version":4346051,"digest":"4KddCShzYaYA2QcVbNphjberckmHf3BQQ13QxTqWzqkh"},{"objectId":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","version":4346051,"digest":"4BbiRiXkVTtkgnXwJJM1Px9u9Pw8XcTYeoi8xCAe5AiH"},{"objectId":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","version":4346049,"digest":"Hbp9rYyMyeFxfGkw6EEUfFpmVrc85NfAyTs2mE6EcxHj"}],"transactionDigest":"ozN2rhczEUC39poaeVYxMN6b6TEAjiFX7jFSQFhbKmL","mutated":[{"owner":{"AddressOwner":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497"},"reference":{"objectId":"0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004","version":4346052,"digest":"3DSxmS55mjcxjp4zni3HqxtpNBchuuEz1HkdY2cSGvx4"}},{"owner":{"Shared":{"initial_shared_version":4346051}},"reference":{"objectId":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","version":4346052,"digest":"EWBifxLP1W6RnLYEFEbsq5SrqCT28VBseSN6JDeBVB4g"}},{"owner":{"Shared":{"initial_shared_version":3478819}},"reference":{"objectId":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","version":4346052,"digest":"97QWr9zmCmV9L7WJHmG6ynSLbwtXtqaxEvJPzCw5r7ZK"}},{"owner":{"ObjectOwner":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621"},"reference":{"objectId":"0x898dd24cc48476a7a2ff36372a443fefa53545b016feb317bb091e60e06b2e4c","version":4346052,"digest":"39Twrdee3mTpzMUiccQdE2c5qYizZGmbGHsqycnCTA2j"}}],"gasObject":{"owner":{"AddressOwner":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497"},"reference":{"objectId":"0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004","version":4346052,"digest":"3DSxmS55mjcxjp4zni3HqxtpNBchuuEz1HkdY2cSGvx4"}},"eventsDigest":"J8u3bJn6FAMiadwesmkYjvm5kvNMKTNJecRQ9H5cndop","dependencies":["GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","5kWByxejQ95cxQ5zUCba3WyivedWBmtisRa4ZaWJuWpm","6B3tXa5PpoaRUQiYcytsC1M9fkfzXUc49NsWgC335qC1"]},"protocol_version":11,"epoch_start_timestamp":1686071016387,"reference_gas_price":820},"required_objects":[{"data":{"Move":{"type_":"GasCoin","has_public_transfer":true,"version":4346051,"contents":[21,32,188,177,31,211,164,184,188,23,93,46,13,51,223,242,149,206,222,73,87,55,189,56,32,255,148,164,64,84,144,4,144,115,177,150,11,0,0,0]}},"owner":{"AddressOwner":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497"},"previous_transaction":"GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","storage_rebate":988000},{"data":{"Move":{"type_":{"Other":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"governance_v1","name":"Proposal","type_args":[{"struct":{"address":"7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d","module":"migrate_proposal","name":"Certificate","type_args":[]}}]}},"has_public_transfer":false,"version":4346051,"contents":[57,252,244,217,254,131,156,97,185,211,22,22,230,144,104,131,113,142,173,223,177,229,32,89,200,170,223,35,213,70,217,52,101,133,153,88,189,98,227,10,160,87,31,151,18,150,47,89,9,141,30,178,159,115,176,145,217,215,19,23,216,230,116,151,55,0,0,0,0,0,0,0,0,85,0,0,0,0,0,0,0,64,55,102,54,98,51,56,48,100,98,102,51,54,50,51,54,50,48,53,54,49,53,99,54,52,102,99,98,98,54,99,52,101,57,52,53,52,98,55,54,101,102,102,48,57,55,100,100,54,99,54,53,51,52,102,54,100,53,48,55,48,100,49,55,100,0,0,0,1]}},"owner":{"Shared":{"initial_shared_version":4346051}},"previous_transaction":"GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","storage_rebate":2728400},{"data":{"Move":{"type_":{"Other":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"genesis","name":"GovernanceGenesis","type_args":[]}},"has_public_transfer":false,"version":4346049,"contents":[66,239,144,6,110,100,146,21,230,171,145,57,154,131,225,165,70,127,215,204,67,110,139,131,173,184,116,58,14,251,166,33,4,81,180,29,10,30,207,114,139,134,133,233,172,144,221,93,63,141,97,190,62,113,16,212,34,139,152,136,114,24,131,222,197,178,165,4,156,215,21,134,54,45,12,106,56,227,76,250,174,126,169,206,109,84,1,163,80,80,106,21,248,23,191,114,2,0,0,0,0,0,0,0,0,1,254,147,243,188,197,217,213,55,232,158,184,214,115,240,234,207,29,60,135,22,250,128,58,250,46,171,68,79,42,167,134,211]}},"owner":{"Shared":{"initial_shared_version":3478819}},"previous_transaction":"6B3tXa5PpoaRUQiYcytsC1M9fkfzXUc49NsWgC335qC1","storage_rebate":2181200},{"data":{"Move":{"type_":{"Other":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"governance_v1","name":"GovernanceInfo","type_args":[]}},"has_public_transfer":false,"version":4346051,"contents":[121,215,16,110,161,131,115,252,117,66,176,132,157,94,190,252,58,157,175,139,102,74,79,130,217,179,91,189,12,34,4,45,1,254,147,243,188,197,217,213,55,232,158,184,214,115,240,234,207,29,60,135,22,250,128,58,250,46,171,68,79,42,167,134,211,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,0,0,0,0,0,0,0,1,101,133,153,88,189,98,227,10,160,87,31,151,18,150,47,89,9,141,30,178,159,115,176,145,217,215,19,23,216,230,116,151,0]}},"owner":{"Shared":{"initial_shared_version":3195547}},"previous_transaction":"GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","storage_rebate":2097600},{"data":{"Move":{"type_":{"Other":{"address":"0000000000000000000000000000000000000000000000000000000000000002","module":"dynamic_field","name":"Field","type_args":[{"struct":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"genesis","name":"Version","type_args":[]}},{"struct":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"genesis","name":"Version_1_0_0","type_args":[]}}]}},"has_public_transfer":false,"version":3478819,"contents":[137,141,210,76,196,132,118,167,162,255,54,55,42,68,63,239,165,53,69,176,22,254,179,23,187,9,30,96,224,107,46,76,0,0]}},"owner":{"ObjectOwner":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621"},"previous_transaction":"McsTGPLu3V5rpv6CyPNv6rG5f4NAZMuVbWfadUqPjR2","storage_rebate":2150800},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000001","version":2,"module_map":{"address":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,3,7,10,15,8,25,32,12,57,16,0,0,0,1,0,1,0,0,1,3,7,97,100,100,114,101,115,115,6,108,101,110,103,116,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,6,32,0,0,0,0,0,0,0,2,0],"ascii":[161,28,235,11,6,0,0,0,11,1,0,4,2,4,14,3,18,84,4,102,8,5,110,59,7,169,1,200,1,8,241,2,32,6,145,3,10,10,155,3,11,12,166,3,186,2,13,224,5,4,0,5,0,16,0,2,7,0,0,0,7,0,1,1,7,1,0,0,0,8,0,1,0,0,20,2,3,0,0,21,2,4,0,0,3,5,6,0,0,18,7,8,0,0,17,9,1,0,0,14,5,10,0,0,4,5,11,0,0,10,3,2,0,0,6,1,0,0,0,13,0,6,0,0,11,0,6,0,1,9,13,14,1,0,1,12,12,6,1,0,1,15,8,13,1,0,1,19,14,13,1,0,13,3,12,3,14,3,15,3,1,2,1,8,1,1,10,2,1,8,0,1,11,2,1,8,0,1,6,8,0,1,1,2,7,8,0,8,1,0,1,7,8,0,1,3,1,6,10,2,1,6,11,2,1,9,0,1,11,2,1,9,0,1,9,0,2,3,3,4,67,104,97,114,6,79,112,116,105,111,110,6,83,116,114,105,110,103,24,97,108,108,95,99,104,97,114,97,99,116,101,114,115,95,112,114,105,110,116,97,98,108,101,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,4,98,121,116,101,5,98,121,116,101,115,4,99,104,97,114,12,100,101,115,116,114,111,121,95,115,111,109,101,10,105,110,116,111,95,98,121,116,101,115,17,105,115,95,112,114,105,110,116,97,98,108,101,95,99,104,97,114,7,105,115,95,115,111,109,101,13,105,115,95,118,97,108,105,100,95,99,104,97,114,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,8,112,111,112,95,99,104,97,114,9,112,117,115,104,95,99,104,97,114,4,115,111,109,101,6,115,116,114,105,110,103,10,116,114,121,95,115,116,114,105,110,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,1,0,0,0,0,0,0,2,1,7,10,2,1,2,1,6,2,0,1,0,0,8,9,10,0,17,10,4,4,5,6,7,0,39,11,0,18,1,2,1,1,0,0,4,12,11,0,17,2,12,1,14,1,56,0,4,7,5,9,7,0,39,11,1,56,1,2,2,1,0,0,15,30,14,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,25,5,11,14,0,10,1,66,0,20,17,10,32,4,20,56,2,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,5,40,11,0,18,0,56,3,2,3,1,0,0,15,32,10,0,16,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,29,5,12,10,0,16,0,10,1,66,0,20,17,11,32,4,24,11,0,1,9,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,40,8,2,4,1,0,0,8,7,11,0,15,0,14,1,16,1,20,68,0,2,5,1,0,0,8,5,11,0,15,0,69,0,18,1,2,6,1,0,0,8,4,11,0,17,7,65,0,2,7,1,0,0,8,3,11,0,16,0,2,8,1,0,0,8,3,11,0,19,0,2,9,1,0,0,8,3,11,0,19,1,2,10,1,0,0,8,4,11,0,49,127,37,2,11,1,0,0,6,13,10,0,49,32,38,4,9,11,0,49,126,37,12,1,5,11,9,12,1,11,1,2,0,0,1,0,0],"bcs":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,7,7,15,13,8,28,32,12,60,4,0,0,0,1,0,1,1,0,1,6,9,0,1,10,2,3,98,99,115,8,116,111,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,0],"bit_vector":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,36,7,77,109,8,186,1,32,6,218,1,40,10,130,2,8,12,138,2,239,3,13,249,5,4,0,2,0,0,7,0,0,6,0,1,0,0,7,2,3,0,0,9,2,3,0,0,8,2,3,0,0,3,4,5,0,0,4,6,0,0,0,5,4,0,0,1,3,1,8,0,2,7,8,0,3,0,2,6,8,0,3,1,1,1,6,8,0,2,10,1,3,1,7,1,5,3,7,1,3,3,3,9,66,105,116,86,101,99,116,111,114,9,98,105,116,95,102,105,101,108,100,10,98,105,116,95,118,101,99,116,111,114,12,105,115,95,105,110,100,101,120,95,115,101,116,6,108,101,110,103,116,104,32,108,111,110,103,101,115,116,95,115,101,116,95,115,101,113,117,101,110,99,101,95,115,116,97,114,116,105,110,103,95,97,116,3,110,101,119,3,115,101,116,10,115,104,105,102,116,95,108,101,102,116,5,117,110,115,101,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,3,8,1,0,2,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,4,0,0,0,0,0,0,0,2,2,4,3,1,10,1,0,1,0,0,7,37,10,0,6,0,0,0,0,0,0,0,0,36,4,5,5,7,7,1,39,10,0,7,3,35,4,12,5,14,7,1,39,6,0,0,0,0,0,0,0,0,12,2,64,5,0,0,0,0,0,0,0,0,12,1,40,10,2,10,0,35,4,32,5,24,13,1,9,68,5,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,18,40,11,0,11,1,18,0,2,1,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,8,11,2,21,2,2,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,9,11,2,21,2,3,1,0,0,9,89,10,1,10,0,16,1,20,38,4,33,10,0,16,0,65,5,12,6,6,0,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,30,5,17,10,0,15,0,10,4,67,5,12,3,9,11,3,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,12,11,0,1,5,88,10,1,12,5,10,5,10,0,16,1,20,35,4,65,5,42,10,0,10,5,12,2,46,11,2,17,4,4,55,10,0,10,5,10,1,23,17,1,5,60,10,0,10,5,10,1,23,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,35,10,0,16,1,20,11,1,23,12,5,10,5,10,0,16,1,20,35,4,86,5,78,10,0,10,5,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,71,11,0,1,2,4,1,0,0,3,17,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,16,0,11,1,66,5,20,2,5,1,0,0,3,4,11,0,16,0,65,5,2,6,1,0,0,0,37,10,1,10,0,16,1,20,35,4,7,5,11,11,0,1,7,0,39,10,1,12,2,10,2,10,0,16,1,20,35,4,33,5,20,10,0,10,2,17,4,32,4,28,11,0,1,5,33,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,13,11,2,11,1,23,2,0,1,0,0,0],"debug":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,11,5,13,5,7,18,30,8,48,32,12,80,8,0,0,0,1,0,1,1,0,0,2,1,1,0,1,6,9,0,0,5,100,101,98,117,103,5,112,114,105,110,116,17,112,114,105,110,116,95,115,116,97,99,107,95,116,114,97,99,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"fixed_point32":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,30,5,36,22,7,58,122,8,180,1,32,6,212,1,68,10,152,2,5,12,157,2,137,2,13,166,4,2,0,4,0,0,7,0,0,7,0,1,0,0,3,0,1,0,0,1,2,3,0,0,2,1,3,0,0,5,3,1,0,0,6,3,4,0,2,3,8,0,1,3,2,3,3,1,8,0,1,1,1,4,4,1,4,4,4,0,12,70,105,120,101,100,80,111,105,110,116,51,50,20,99,114,101,97,116,101,95,102,114,111,109,95,114,97,116,105,111,110,97,108,21,99,114,101,97,116,101,95,102,114,111,109,95,114,97,119,95,118,97,108,117,101,10,100,105,118,105,100,101,95,117,54,52,13,102,105,120,101,100,95,112,111,105,110,116,51,50,13,103,101,116,95,114,97,119,95,118,97,108,117,101,7,105,115,95,122,101,114,111,12,109,117,108,116,105,112,108,121,95,117,54,52,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,16,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,3,8,1,0,1,0,0,0,0,0,3,8,2,0,2,0,0,0,0,0,3,8,3,0,2,0,0,0,0,0,3,8,4,0,1,0,0,0,0,0,3,8,5,0,2,0,0,0,0,0,0,2,1,8,3,0,1,0,0,5,20,11,0,53,14,1,16,0,20,53,24,49,32,48,12,2,10,2,7,0,37,4,15,5,17,7,3,39,11,2,52,2,1,1,0,0,5,29,14,1,16,0,20,6,0,0,0,0,0,0,0,0,34,4,7,5,9,7,4,39,11,0,53,49,32,47,14,1,16,0,20,53,26,12,2,10,2,7,0,37,4,24,5,26,7,2,39,11,2,52,2,2,1,0,0,6,48,10,0,53,49,64,47,12,5,11,1,53,49,32,47,12,4,10,4,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,15,5,17,7,1,39,11,5,11,4,26,12,3,10,3,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,8,12,2,5,32,11,0,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,35,5,37,7,5,39,10,3,7,0,37,4,42,5,44,7,5,39,11,3,52,18,0,2,3,1,0,0,7,3,11,0,18,0,2,4,1,0,0,7,4,14,0,16,0,20,2,5,1,0,0,7,6,14,0,16,0,20,6,0,0,0,0,0,0,0,0,33,2,0,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,3,7,15,23,8,38,32,12,70,8,0,0,0,1,0,0,0,0,2,0,0,0,1,10,2,4,104,97,115,104,8,115,104,97,50,95,50,53,54,8,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"option":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,6,3,10,120,4,130,1,14,5,144,1,135,1,7,151,2,219,1,8,242,3,32,6,146,4,20,10,166,4,7,11,173,4,2,12,175,4,128,4,13,175,8,2,14,177,8,2,0,15,0,22,0,0,7,1,0,0,0,14,0,1,1,0,0,17,2,1,1,0,0,12,3,4,1,0,0,13,3,4,1,0,0,4,5,4,1,0,0,1,3,6,1,0,0,3,5,6,1,0,0,10,7,2,1,3,0,9,8,0,1,0,0,8,9,2,1,0,0,2,9,10,1,0,0,18,8,2,1,0,0,19,8,1,1,0,0,7,11,2,1,2,0,6,1,2,1,0,0,5,1,0,1,0,0,20,1,12,1,0,1,4,14,4,1,0,1,11,13,4,1,0,1,16,2,12,1,0,19,2,18,2,17,2,3,2,0,2,1,2,2,2,0,1,11,0,1,9,0,1,9,0,1,6,11,0,1,9,0,1,1,2,6,11,0,1,9,0,6,9,0,1,6,9,0,2,6,11,0,1,9,0,9,0,2,7,11,0,1,9,0,9,0,1,7,11,0,1,9,0,1,7,9,0,2,11,0,1,9,0,9,0,1,10,9,0,1,6,10,9,0,2,6,10,9,0,6,9,0,2,6,9,0,6,10,9,0,2,9,0,6,10,9,0,1,7,10,9,0,2,9,0,7,10,9,0,3,11,0,1,9,0,11,0,1,9,0,7,10,9,0,2,9,0,10,9,0,6,79,112,116,105,111,110,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,119,105,116,104,95,100,101,102,97,117,108,116,8,99,111,110,116,97,105,110,115,12,100,101,115,116,114,111,121,95,110,111,110,101,12,100,101,115,116,114,111,121,95,115,111,109,101,20,100,101,115,116,114,111,121,95,119,105,116,104,95,100,101,102,97,117,108,116,7,101,120,116,114,97,99,116,4,102,105,108,108,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,4,110,111,110,101,6,111,112,116,105,111,110,9,115,105,110,103,108,101,116,111,110,4,115,111,109,101,4,115,119,97,112,12,115,119,97,112,95,111,114,95,102,105,108,108,6,116,111,95,118,101,99,3,118,101,99,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,4,0,0,0,0,0,3,8,1,0,4,0,0,0,0,0,0,2,1,21,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,0,4,11,0,55,0,56,1,2,3,1,0,0,0,5,11,0,55,0,56,1,32,2,4,1,0,0,0,5,11,0,55,0,11,1,56,2,2,5,1,0,0,0,13,10,0,56,3,4,4,5,8,11,0,1,7,1,39,11,0,55,0,6,0,0,0,0,0,0,0,0,66,2,2,6,1,0,0,15,19,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,17,11,1,1,11,3,6,0,0,0,0,0,0,0,0,66,2,12,2,11,2,2,7,1,0,0,16,18,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,16,11,3,6,0,0,0,0,0,0,0,0,66,2,20,12,2,11,2,2,8,1,0,0,17,16,11,0,54,0,12,2,10,2,46,56,1,4,8,5,12,11,2,1,7,0,39,11,2,11,1,68,2,2,9,1,0,0,0,13,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,69,2,2,10,1,0,0,0,14,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,6,0,0,0,0,0,0,0,0,67,2,2,11,1,0,0,18,20,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,12,3,10,3,69,2,12,2,11,3,11,1,68,2,11,2,2,12,1,0,0,19,21,11,0,54,0,12,4,10,4,46,56,1,4,10,56,4,12,2,5,14,10,4,69,2,56,5,12,2,11,2,12,3,11,4,11,1,68,2,11,3,2,13,1,0,0,20,15,11,0,58,0,12,3,13,3,46,56,1,4,10,11,1,12,2,5,13,13,3,69,2,12,2,11,2,2,14,1,0,0,20,16,14,0,56,3,4,4,5,6,7,1,39,11,0,58,0,12,2,13,2,69,2,12,1,11,2,70,2,0,0,0,0,0,0,0,0,11,1,2,15,1,0,0,0,10,14,0,56,6,4,4,5,6,7,0,39,11,0,58,0,70,2,0,0,0,0,0,0,0,0,2,16,1,0,0,0,3,11,0,58,0,2,0,0,0,2,0],"string":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,14,3,22,114,4,136,1,8,5,144,1,123,7,139,2,248,1,8,131,4,32,6,163,4,20,10,183,4,6,12,189,4,133,3,13,194,7,2,0,19,0,4,0,17,0,24,0,1,7,0,1,1,7,0,2,0,7,1,0,0,0,23,0,1,0,0,6,2,1,0,0,21,1,2,0,0,22,0,3,0,0,5,4,5,0,0,14,4,6,0,0,15,4,7,0,0,2,8,9,0,0,3,10,9,0,0,8,11,9,0,0,20,12,1,0,0,7,13,7,0,0,9,5,6,0,0,11,14,6,0,0,12,15,0,0,0,10,16,7,0,1,13,2,0,0,1,19,0,2,0,2,16,9,18,1,0,2,18,17,18,1,0,3,2,21,9,1,0,3,14,20,6,1,0,19,1,18,1,21,19,20,19,1,10,2,1,8,0,1,8,1,1,11,2,1,8,0,1,6,8,0,1,6,10,2,1,1,1,3,2,7,8,0,8,0,0,2,7,8,0,10,2,3,7,8,0,3,8,0,3,6,8,0,3,3,2,6,8,0,6,8,0,2,6,10,2,3,3,6,10,2,3,3,2,6,10,2,6,10,2,1,9,0,1,11,2,1,9,0,1,2,1,6,10,9,0,2,7,10,9,0,10,9,0,8,1,3,3,3,6,10,2,8,0,8,0,3,5,1,1,1,6,10,2,3,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,97,112,112,101,110,100,11,97,112,112,101,110,100,95,117,116,102,56,5,97,115,99,105,105,5,98,121,116,101,115,10,102,114,111,109,95,97,115,99,105,105,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,19,105,110,116,101,114,110,97,108,95,99,104,101,99,107,95,117,116,102,56,17,105,110,116,101,114,110,97,108,95,105,110,100,101,120,95,111,102,25,105,110,116,101,114,110,97,108,95,105,115,95,99,104,97,114,95,98,111,117,110,100,97,114,121,19,105,110,116,101,114,110,97,108,95,115,117,98,95,115,116,114,105,110,103,10,105,110,116,111,95,98,121,116,101,115,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,4,115,111,109,101,6,115,116,114,105,110,103,10,115,117,98,95,115,116,114,105,110,103,8,116,111,95,97,115,99,105,105,8,116,114,121,95,117,116,102,56,4,117,116,102,56,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,5,10,2,0,1,0,0,9,9,14,0,17,12,4,4,5,6,7,0,39,11,0,18,0,2,1,1,0,0,9,4,11,0,17,16,18,0,2,2,1,0,0,9,4,11,0,19,0,17,17,2,3,1,0,0,3,12,14,0,17,12,4,8,11,0,18,0,56,0,12,1,5,10,56,1,12,1,11,1,2,4,1,0,0,9,3,11,0,16,0,2,5,1,0,0,9,4,11,0,16,0,56,2,2,6,1,0,0,9,4,11,0,16,0,65,19,2,7,1,0,0,9,7,11,0,15,0,14,1,16,0,20,56,3,2,8,1,0,0,9,5,11,0,11,1,17,0,17,7,2,9,1,0,0,22,56,10,0,16,0,12,7,10,1,10,7,65,19,37,4,13,11,7,10,1,17,13,12,3,5,17,11,7,1,9,12,3,11,3,4,20,5,24,11,0,1,7,1,39,10,0,46,17,6,12,10,10,0,10,1,12,4,46,6,0,0,0,0,0,0,0,0,11,4,17,10,12,9,10,0,11,1,11,10,12,6,12,5,46,11,5,11,6,17,10,12,8,13,9,11,2,17,7,13,9,11,8,17,7,11,9,11,0,21,2,10,1,0,0,23,48,11,0,16,0,12,6,10,6,65,19,12,7,10,2,11,7,37,4,15,10,1,10,2,37,12,3,5,17,9,12,3,11,3,4,24,10,6,10,1,17,13,12,4,5,26,9,12,4,11,4,4,33,10,6,10,2,17,13,12,5,5,35,9,12,5,11,5,4,38,5,42,11,6,1,7,1,39,11,6,11,1,11,2,17,14,18,0,2,11,1,0,0,9,6,11,0,16,0,11,1,16,0,17,15,2,12,0,2,0,13,0,2,0,14,0,2,0,15,0,2,0,0,0,0],"type_name":[161,28,235,11,6,0,0,0,10,1,0,6,2,6,8,3,14,47,5,61,44,7,105,143,1,8,248,1,32,6,152,2,7,10,159,2,6,12,165,2,215,1,13,252,3,2,0,14,0,2,0,4,0,1,7,0,2,0,7,0,0,6,0,1,1,0,0,9,0,1,1,0,0,5,2,3,0,0,7,2,4,0,0,8,2,4,0,0,10,1,4,0,1,11,0,6,0,2,3,3,7,0,2,13,9,4,0,0,1,8,0,1,6,8,0,1,6,8,1,1,8,1,4,10,2,3,3,6,10,2,1,3,1,6,10,2,1,2,1,10,2,5,2,6,2,3,10,2,6,10,2,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,13,98,111,114,114,111,119,95,115,116,114,105,110,103,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,11,105,110,116,111,95,115,116,114,105,110,103,6,108,101,110,103,116,104,4,110,97,109,101,6,115,116,114,105,110,103,9,116,121,112,101,95,110,97,109,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,58,10,2,1,0,0,2,1,12,8,1,0,1,2,0,1,1,2,0,2,1,0,0,0,3,11,0,16,0,2,3,1,0,0,5,33,17,6,6,2,0,0,0,0,0,0,0,24,12,3,11,0,16,0,17,7,12,4,7,1,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,28,5,17,13,1,10,4,10,2,66,8,20,68,8,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,4,1,11,1,17,8,2,4,1,0,0,10,39,17,6,6,2,0,0,0,0,0,0,0,24,6,2,0,0,0,0,0,0,0,22,12,3,11,0,16,0,17,7,12,5,7,1,12,4,10,5,10,3,66,8,12,2,7,0,12,1,10,2,14,1,34,4,32,5,23,13,4,11,2,20,68,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,12,11,5,1,11,2,1,11,4,17,8,2,5,1,0,0,0,4,14,0,16,0,20,2,0,0,0],"vector":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,102,4,104,4,5,108,97,7,205,1,154,1,8,231,2,32,6,135,3,10,12,145,3,216,4,0,17,0,5,0,1,1,0,0,9,2,3,1,0,0,1,4,5,1,0,0,11,6,0,1,0,0,2,7,8,1,0,0,10,9,10,1,0,0,4,1,0,1,0,0,15,11,0,1,0,0,14,10,1,1,0,0,13,9,0,1,0,0,0,12,0,1,0,0,8,2,13,1,0,0,3,14,13,1,0,0,6,14,15,1,0,0,12,7,10,1,0,0,7,16,0,1,0,0,16,7,10,1,0,9,10,11,10,0,1,10,9,0,1,6,10,9,0,1,3,2,6,10,9,0,3,1,6,9,0,2,7,10,9,0,9,0,2,7,10,9,0,3,1,7,9,0,1,7,10,9,0,1,9,0,3,7,10,9,0,3,3,2,7,10,9,0,10,9,0,1,1,2,6,10,9,0,6,9,0,2,1,3,3,7,10,9,0,9,0,3,3,3,3,3,2,3,3,3,3,7,10,9,0,3,6,97,112,112,101,110,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,5,101,109,112,116,121,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,7,114,101,118,101,114,115,101,9,115,105,110,103,108,101,116,111,110,4,115,119,97,112,11,115,119,97,112,95,114,101,109,111,118,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,2,0,4,1,2,0,5,1,2,0,6,1,2,0,7,1,2,0,8,1,0,0,1,7,64,10,0,0,0,0,0,0,0,0,12,1,13,1,11,0,68,10,11,1,2,9,1,0,0,17,38,10,0,46,65,10,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,2,6,0,0,0,0,0,0,0,0,12,2,11,3,6,1,0,0,0,0,0,0,0,23,12,1,10,2,10,1,35,4,35,5,22,10,0,10,2,10,1,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,1,6,1,0,0,0,0,0,0,0,23,12,1,5,17,11,0,1,2,10,1,0,0,0,17,13,1,56,0,14,1,56,1,32,4,12,5,7,10,0,13,1,69,10,68,10,5,2,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,11,1,0,0,0,5,11,0,65,10,6,0,0,0,0,0,0,0,0,33,2,12,1,0,0,18,33,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,27,5,10,10,0,10,2,66,10,10,1,33,4,22,11,0,1,11,1,1,8,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,2,13,1,0,0,18,35,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,28,5,10,10,0,10,2,66,10,10,1,33,4,23,11,0,1,11,1,1,8,11,2,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,6,0,0,0,0,0,0,0,0,2,14,1,0,0,19,37,10,0,46,65,10,12,4,10,1,10,4,38,4,12,11,0,1,7,0,39,11,4,6,1,0,0,0,0,0,0,0,23,12,4,10,1,10,4,35,4,34,5,21,10,0,12,3,10,1,12,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,11,3,11,2,10,1,71,10,5,16,11,0,69,10,2,15,1,0,0,3,32,10,0,46,65,10,12,3,10,2,10,3,36,4,12,11,0,1,7,0,39,10,0,11,1,68,10,10,2,10,3,35,4,29,5,20,10,0,10,2,10,3,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,2,16,1,0,0,3,23,10,0,46,56,1,32,4,6,5,10,11,0,1,7,0,39,10,0,46,65,10,6,1,0,0,0,0,0,0,0,23,12,2,10,0,11,1,11,2,71,10,11,0,69,10,2,0]},"type_origin_table":[{"module_name":"fixed_point32","struct_name":"FixedPoint32","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"option","struct_name":"Option","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"Char","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"bit_vector","struct_name":"BitVector","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"string","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"type_name","struct_name":"TypeName","package":"0x0000000000000000000000000000000000000000000000000000000000000001"}],"linkage_table":{}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000002","version":6,"module_map":{"address":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,8,3,18,61,4,79,2,5,81,20,7,101,129,1,8,230,1,64,6,166,2,54,12,220,2,69,0,1,1,2,1,3,1,11,0,8,1,0,7,0,3,0,7,0,0,15,0,1,0,0,7,1,0,0,0,6,2,0,0,0,13,0,2,0,0,12,0,3,0,0,14,0,4,0,0,9,5,6,0,0,10,5,1,0,1,11,2,3,0,2,13,7,2,1,0,3,5,3,4,0,4,4,2,2,0,9,0,1,5,1,15,1,10,2,1,8,0,1,8,1,0,1,3,1,6,9,0,6,83,116,114,105,110,103,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,6,101,110,99,111,100,101,10,102,114,111,109,95,97,115,99,105,105,10,102,114,111,109,95,98,121,116,101,115,9,102,114,111,109,95,117,50,53,54,3,104,101,120,6,108,101,110,103,116,104,3,109,97,120,6,115,116,114,105,110,103,15,116,111,95,97,115,99,105,105,95,115,116,114,105,110,103,8,116,111,95,98,121,116,101,115,9,116,111,95,115,116,114,105,110,103,7,116,111,95,117,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,32,0,0,0,0,0,0,0,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,3,8,0,0,0,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,0,0,5,3,14,0,56,0,2,4,1,0,0,5,5,11,0,17,3,17,11,17,8,2,5,1,0,0,5,4,11,0,17,4,17,10,2,6,1,0,0,5,2,7,0,2,7,1,0,0,5,2,7,1,2,0],"bag":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,112,4,132,1,12,5,144,1,82,7,226,1,185,1,8,155,3,32,6,187,3,10,10,197,3,8,12,205,3,230,1,13,179,5,4,0,4,0,11,0,18,0,21,0,0,12,0,2,2,4,0,3,1,2,0,0,17,0,1,0,0,3,2,3,2,7,4,0,5,4,5,2,7,4,0,6,6,7,2,7,4,0,19,6,8,2,7,4,0,7,4,9,1,7,0,8,4,9,2,7,4,0,16,10,11,0,0,15,10,9,0,0,10,1,3,0,1,3,14,3,2,7,4,1,5,15,5,2,7,4,1,6,16,7,2,7,4,1,12,15,9,1,7,1,13,15,9,2,7,4,1,19,16,8,2,7,4,2,9,12,3,0,2,17,0,12,0,10,13,11,13,12,13,15,13,13,17,14,13,1,7,8,2,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,1,9,0,2,8,1,3,3,66,97,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,3,98,97,103,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,14,8,1,20,3,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,18,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,0,0,0,1,0],"balance":[161,28,235,11,6,0,0,0,14,1,0,4,2,4,16,3,20,83,4,103,2,5,105,99,7,204,1,224,1,8,172,3,32,6,204,3,74,10,150,4,10,11,160,4,4,12,164,4,219,2,13,255,6,4,14,131,7,4,15,135,7,2,0,3,0,16,0,1,4,1,0,1,0,0,4,1,0,1,1,2,2,0,0,17,0,1,1,0,0,15,2,1,1,0,0,5,3,4,1,2,0,10,5,6,1,0,0,6,7,1,1,0,0,19,8,6,1,0,0,11,9,1,1,0,0,13,10,6,1,0,0,18,11,6,1,0,0,9,6,8,1,0,0,4,12,6,1,0,0,7,13,8,1,0,0,8,4,1,1,0,1,12,14,15,0,7,3,1,6,11,1,1,9,0,1,3,1,6,11,0,1,9,0,1,9,0,1,11,0,1,9,0,2,7,11,0,1,9,0,3,1,11,1,1,9,0,2,7,11,0,1,9,0,11,1,1,9,0,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,7,11,1,1,9,0,2,3,6,8,2,2,11,1,1,9,0,6,8,2,1,6,8,2,1,5,7,66,97,108,97,110,99,101,6,83,117,112,112,108,121,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,22,99,114,101,97,116,101,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,115,13,99,114,101,97,116,101,95,115,117,112,112,108,121,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,23,100,101,115,116,114,111,121,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,12,100,101,115,116,114,111,121,95,122,101,114,111,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,4,106,111,105,110,6,115,101,110,100,101,114,5,115,112,108,105,116,3,115,117,105,12,115,117,112,112,108,121,95,118,97,108,117,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,17,3,1,2,1,17,3,0,3,1,3,0,1,0,0,8,4,11,0,55,0,20,2,1,1,0,0,8,4,11,0,55,1,20,2,2,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,0,2,3,1,0,0,8,24,10,1,6,255,255,255,255,255,255,255,255,10,0,55,1,20,23,35,4,9,5,13,11,0,1,7,1,39,10,0,55,1,20,10,1,22,11,0,54,1,21,11,1,57,1,2,4,1,0,0,1,24,11,1,58,1,12,2,10,0,55,1,20,10,2,38,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,10,2,23,11,0,54,1,21,11,2,2,5,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,1,2,6,1,0,0,1,15,11,1,58,1,12,2,10,0,55,0,20,11,2,22,10,0,54,0,21,11,0,55,0,20,2,7,1,0,0,8,22,10,0,55,0,20,10,1,38,4,7,5,11,11,0,1,7,2,39,10,0,55,0,20,10,1,23,11,0,54,0,21,11,1,57,1,2,8,1,0,0,1,8,10,0,55,0,20,12,1,11,0,11,1,56,0,2,9,1,0,0,8,13,14,0,55,0,20,6,0,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,11,0,58,1,1,2,10,0,0,0,8,11,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,57,1,2,11,0,0,0,8,12,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,58,1,1,2,12,3,0,0,8,3,11,0,58,0,2,1,0,0,0,0,3,1,3,0,14,0],"bcs":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,10,3,20,135,1,4,155,1,24,5,179,1,131,1,7,182,2,222,2,8,148,5,64,6,212,5,55,10,139,6,6,12,145,6,203,8,13,220,14,2,0,3,1,3,1,10,1,31,0,2,0,0,7,0,2,1,7,1,0,0,0,30,0,1,1,0,0,8,1,2,0,0,6,2,1,0,0,11,3,4,0,0,12,3,5,0,0,20,3,6,0,0,19,3,7,0,0,18,3,8,0,0,23,3,7,0,0,21,3,9,0,0,22,3,10,0,0,26,3,1,0,0,27,3,11,0,0,25,3,12,0,0,24,3,13,0,0,13,3,14,0,0,14,3,15,0,0,17,3,16,0,0,16,3,17,0,0,15,3,18,0,1,30,0,1,1,0,2,9,19,33,1,0,2,29,20,33,1,0,3,28,21,19,1,0,4,5,1,4,0,4,7,19,7,0,20,20,23,6,22,4,21,4,22,5,21,5,22,6,21,6,22,7,21,7,22,8,21,8,1,6,9,0,1,10,2,1,8,0,1,7,8,0,1,5,1,1,1,2,1,3,1,4,1,10,5,1,10,1,1,10,10,2,1,10,3,1,10,4,1,11,1,1,5,1,11,1,1,1,1,11,1,1,2,1,11,1,1,3,1,11,1,1,4,0,1,9,0,1,7,10,9,0,2,10,2,3,2,1,2,3,3,2,3,3,4,2,4,4,3,3,2,3,3,3,3,10,5,3,3,3,10,1,3,3,3,10,2,3,3,3,10,10,2,3,3,3,10,3,3,3,3,10,4,1,11,1,1,9,0,3,66,67,83,6,79,112,116,105,111,110,7,97,100,100,114,101,115,115,3,98,99,115,5,98,121,116,101,115,10,102,114,111,109,95,98,121,116,101,115,20,105,110,116,111,95,114,101,109,97,105,110,100,101,114,95,98,121,116,101,115,6,108,101,110,103,116,104,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,12,112,101,101,108,95,97,100,100,114,101,115,115,9,112,101,101,108,95,98,111,111,108,19,112,101,101,108,95,111,112,116,105,111,110,95,97,100,100,114,101,115,115,16,112,101,101,108,95,111,112,116,105,111,110,95,98,111,111,108,16,112,101,101,108,95,111,112,116,105,111,110,95,117,49,50,56,15,112,101,101,108,95,111,112,116,105,111,110,95,117,54,52,14,112,101,101,108,95,111,112,116,105,111,110,95,117,56,9,112,101,101,108,95,117,49,50,56,8,112,101,101,108,95,117,54,52,7,112,101,101,108,95,117,56,16,112,101,101,108,95,118,101,99,95,97,100,100,114,101,115,115,13,112,101,101,108,95,118,101,99,95,98,111,111,108,15,112,101,101,108,95,118,101,99,95,108,101,110,103,116,104,13,112,101,101,108,95,118,101,99,95,117,49,50,56,12,112,101,101,108,95,118,101,99,95,117,54,52,11,112,101,101,108,95,118,101,99,95,117,56,15,112,101,101,108,95,118,101,99,95,118,101,99,95,117,56,7,114,101,118,101,114,115,101,4,115,111,109,101,8,116,111,95,98,121,116,101,115,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,10,5,1,0,10,1,1,0,10,2,1,0,10,10,2,1,0,10,3,1,0,10,4,1,0,0,2,1,4,10,2,0,1,0,0,19,3,11,0,56,0,2,1,1,0,0,19,5,13,0,56,1,11,0,18,0,2,2,1,0,0,1,7,11,0,19,0,12,1,13,1,56,1,11,1,2,3,1,0,0,22,35,10,0,16,0,65,6,17,25,38,4,7,5,11,11,0,1,7,0,39,64,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,12,2,12,1,10,2,17,25,35,4,30,5,20,13,1,10,0,15,0,69,6,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,11,1,17,24,2,4,1,0,0,23,21,11,0,17,5,12,2,10,2,49,0,33,4,10,9,12,1,5,19,11,2,49,1,33,4,15,5,17,7,1,39,8,12,1,11,1,2,5,1,0,0,19,15,10,0,16,0,65,6,6,1,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,11,0,15,0,69,6,2,6,1,0,0,24,40,10,0,16,0,65,6,6,8,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,64,35,4,36,5,20,10,0,15,0,69,6,52,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,7,1,0,0,25,40,10,0,16,0,65,6,6,16,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,128,35,4,36,5,20,10,0,15,0,69,6,53,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,8,1,0,0,26,48,6,0,0,0,0,0,0,0,0,49,0,6,0,0,0,0,0,0,0,0,12,2,12,3,12,4,10,2,6,4,0,0,0,0,0,0,0,37,4,11,5,15,11,0,1,7,2,39,10,0,15,0,69,6,52,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,4,10,1,6,127,0,0,0,0,0,0,0,28,10,3,47,27,12,4,11,1,6,128,0,0,0,0,0,0,0,28,6,0,0,0,0,0,0,0,0,33,4,39,5,44,11,3,49,7,22,12,3,5,6,11,0,1,11,4,2,9,1,0,0,27,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,3,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,3,68,4,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,10,1,0,0,28,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,4,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,4,68,5,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,11,1,0,0,29,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,5,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,5,68,6,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,12,1,0,0,30,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,6,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,11,68,1,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,13,1,0,0,31,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,7,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,6,68,7,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,14,1,0,0,32,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,8,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,7,68,8,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,15,1,0,0,14,14,10,0,17,4,4,8,11,0,17,3,56,2,12,1,5,12,11,0,1,56,3,12,1,11,1,2,16,1,0,0,15,14,10,0,17,4,4,8,11,0,17,4,56,4,12,1,5,12,11,0,1,56,5,12,1,11,1,2,17,1,0,0,16,14,10,0,17,4,4,8,11,0,17,5,56,6,12,1,5,12,11,0,1,56,7,12,1,11,1,2,18,1,0,0,17,14,10,0,17,4,4,8,11,0,17,6,56,8,12,1,5,12,11,0,1,56,9,12,1,11,1,2,19,1,0,0,18,14,10,0,17,4,4,8,11,0,17,7,56,10,12,1,5,12,11,0,1,56,11,12,1,11,1,2,0,0,0],"bls12381":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,12,7,24,56,8,80,32,12,112,8,0,0,0,2,0,1,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,8,98,108,115,49,50,51,56,49,22,98,108,115,49,50,51,56,49,95,109,105,110,95,112,107,95,118,101,114,105,102,121,23,98,108,115,49,50,51,56,49,95,109,105,110,95,115,105,103,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"borrow":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,24,3,32,59,4,91,10,5,101,83,7,184,1,158,1,8,214,2,64,6,150,3,20,10,170,3,19,11,189,3,2,12,191,3,125,13,188,4,4,14,192,4,4,0,5,1,15,0,14,0,19,0,3,4,1,12,0,0,0,0,0,1,2,7,1,0,0,2,1,7,0,3,4,2,0,0,12,0,1,1,12,0,5,2,3,1,12,0,16,4,5,1,12,0,6,1,6,1,12,1,7,9,6,1,0,1,8,11,6,1,0,1,9,15,5,1,0,1,18,6,9,1,0,2,11,12,13,1,8,3,10,7,8,0,7,6,5,6,8,6,6,6,4,6,2,9,0,7,8,4,1,11,0,1,9,0,1,7,11,0,1,9,0,2,9,0,8,1,3,7,11,0,1,9,0,9,0,8,1,0,1,9,0,1,7,8,4,1,5,1,11,2,1,9,0,2,8,3,9,0,1,7,11,2,1,9,0,1,6,9,0,1,8,3,2,8,3,5,2,7,11,2,1,9,0,9,0,6,66,111,114,114,111,119,2,73,68,6,79,112,116,105,111,110,8,82,101,102,101,114,101,110,116,9,84,120,67,111,110,116,101,120,116,6,98,111,114,114,111,119,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,7,101,120,116,114,97,99,116,4,102,105,108,108,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,3,111,98,106,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,117,116,95,98,97,99,107,3,114,101,102,4,115,111,109,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,2,11,5,20,11,2,1,9,0,1,2,2,17,5,13,8,3,0,6,0,1,0,0,5,6,11,1,17,9,11,0,56,0,57,0,2,1,1,0,0,10,14,10,0,54,0,56,1,12,2,14,2,56,2,12,1,11,2,11,0,55,1,20,11,1,18,1,2,2,1,0,0,14,30,11,2,19,1,12,3,12,4,14,1,56,2,11,3,33,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,11,4,33,4,21,5,25,11,0,1,7,0,39,11,0,54,0,11,1,56,3,2,3,1,0,0,9,7,11,0,58,0,12,1,1,11,1,56,4,2,0,1,0,0,0,6,1,6,0],"clock":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,31,4,51,2,5,53,30,7,83,122,8,205,1,32,6,237,1,44,10,153,2,8,12,161,2,79,13,240,2,2,0,3,0,7,0,11,0,12,0,0,8,0,1,2,4,0,3,1,2,0,0,10,0,1,0,0,5,2,3,0,0,4,4,3,0,1,3,3,6,0,2,9,8,3,1,8,3,8,2,5,0,4,7,1,6,8,0,1,3,1,6,8,2,0,3,7,8,0,3,6,8,2,1,5,1,8,1,1,8,0,1,9,0,5,67,108,111,99,107,9,84,120,67,111,110,116,101,120,116,3,85,73,68,5,99,108,111,99,107,25,99,111,110,115,101,110,115,117,115,95,99,111,109,109,105,116,95,112,114,111,108,111,103,117,101,6,99,114,101,97,116,101,2,105,100,6,111,98,106,101,99,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,1,10,3,0,1,0,0,3,4,11,0,16,0,20,2,1,0,0,0,3,13,11,0,17,5,7,1,33,4,6,5,8,7,0,39,17,3,6,0,0,0,0,0,0,0,0,18,0,56,0,2,2,0,0,0,3,15,11,2,17,5,7,1,33,4,6,5,10,11,0,1,7,0,39,11,1,11,0,15,0,21,2,0,1,0],"coin":[161,28,235,11,6,0,0,0,13,1,0,20,2,20,62,3,82,155,2,4,237,2,34,5,143,3,221,2,7,236,5,164,5,8,144,11,64,6,208,11,30,10,238,11,52,11,162,12,6,12,168,12,249,4,13,161,17,14,14,175,17,14,0,15,1,11,1,43,1,48,0,12,0,42,0,56,0,58,0,59,0,64,0,1,12,1,0,1,0,2,12,1,0,1,0,7,12,1,0,1,0,3,3,1,0,1,1,5,7,0,2,4,7,1,0,0,3,5,7,0,4,0,4,1,0,1,4,6,4,1,0,1,5,9,4,0,7,8,2,0,9,10,7,0,0,55,0,1,1,0,0,57,2,3,1,0,0,50,0,4,1,0,0,51,5,6,1,0,0,66,7,1,1,0,0,12,7,8,1,0,0,13,9,10,1,0,0,24,11,12,1,0,0,33,12,13,1,0,0,54,14,12,1,0,0,45,15,16,1,0,0,35,17,16,1,0,0,47,18,12,1,0,0,23,18,19,1,0,0,67,20,12,1,0,0,22,12,16,1,0,0,16,21,22,1,2,0,36,23,12,1,0,0,38,24,13,1,0,0,14,25,1,1,0,0,37,26,16,1,0,0,62,27,16,1,0,0,63,28,16,1,0,0,60,27,16,1,0,0,61,28,16,1,0,0,25,29,30,1,0,0,28,29,31,1,0,0,29,29,32,1,0,0,26,29,31,1,0,0,27,29,33,1,0,0,49,5,4,1,0,1,48,41,32,0,2,46,34,46,1,0,3,65,41,31,0,4,17,34,3,1,2,4,19,43,1,1,0,4,22,13,16,1,0,4,32,42,13,1,0,4,35,37,1,1,0,4,47,36,13,1,0,4,52,4,1,1,0,4,66,8,1,1,0,4,67,16,13,1,0,5,20,35,16,0,5,40,20,35,0,6,44,44,16,1,12,8,34,39,40,1,2,9,41,32,45,0,40,34,41,34,39,34,8,34,38,34,9,34,4,34,12,34,42,34,36,34,46,34,34,34,37,34,35,34,17,34,45,12,32,45,1,6,11,2,1,9,0,1,3,1,11,2,1,9,0,1,11,8,1,9,0,1,6,11,8,1,9,0,1,7,11,2,1,9,0,1,7,11,8,1,9,0,1,6,11,0,1,9,0,1,6,11,7,1,9,0,1,7,11,0,1,9,0,1,7,11,7,1,9,0,2,11,7,1,9,0,7,8,10,1,11,0,1,9,0,1,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,10,2,7,11,7,1,9,0,11,0,1,9,0,0,2,7,11,0,1,9,0,11,0,1,9,0,3,7,11,0,1,9,0,3,7,8,10,1,10,11,0,1,9,0,1,7,8,10,7,9,0,2,10,2,10,2,10,2,11,5,1,8,11,7,8,10,2,11,2,1,9,0,11,1,1,9,0,3,7,11,2,1,9,0,3,7,8,10,2,7,11,2,1,9,0,3,2,7,11,2,1,9,0,11,0,1,9,0,4,7,11,2,1,9,0,3,5,7,8,10,3,6,11,2,1,9,0,7,11,1,1,9,0,8,6,3,6,11,2,1,9,0,7,11,1,1,9,0,8,4,1,6,11,1,1,9,0,1,2,1,8,6,1,8,4,1,11,5,1,8,11,1,9,0,1,8,9,2,7,11,7,1,9,0,3,2,7,11,7,1,9,0,11,7,1,9,0,3,3,3,10,11,0,1,9,0,1,6,9,0,1,1,1,10,2,2,7,11,8,1,9,0,3,2,7,11,8,1,9,0,11,7,1,9,0,2,9,0,5,1,8,11,1,11,5,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,15,67,117,114,114,101,110,99,121,67,114,101,97,116,101,100,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,85,114,108,5,97,115,99,105,105,7,98,97,108,97,110,99,101,11,98,97,108,97,110,99,101,95,109,117,116,4,98,117,114,110,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,13,99,114,101,97,116,101,95,115,117,112,112,108,121,8,100,101,99,105,109,97,108,115,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,6,100,101,108,101,116,101,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,122,101,114,111,13,100,105,118,105,100,101,95,105,110,116,111,95,110,12,102,114,111,109,95,98,97,108,97,110,99,101,12,103,101,116,95,100,101,99,105,109,97,108,115,15,103,101,116,95,100,101,115,99,114,105,112,116,105,111,110,12,103,101,116,95,105,99,111,110,95,117,114,108,8,103,101,116,95,110,97,109,101,10,103,101,116,95,115,121,109,98,111,108,8,105,99,111,110,95,117,114,108,2,105,100,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,12,105,110,116,111,95,98,97,108,97,110,99,101,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,4,106,111,105,110,4,109,105,110,116,17,109,105,110,116,95,97,110,100,95,116,114,97,110,115,102,101,114,12,109,105,110,116,95,98,97,108,97,110,99,101,4,110,97,109,101,3,110,101,119,10,110,101,119,95,117,110,115,97,102,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,3,112,117,116,4,115,111,109,101,5,115,112,108,105,116,6,115,116,114,105,110,103,6,115,117,112,112,108,121,12,115,117,112,112,108,121,95,105,109,109,117,116,10,115,117,112,112,108,121,95,109,117,116,12,115,117,112,112,108,121,95,118,97,108,117,101,6,115,121,109,98,111,108,4,116,97,107,101,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,5,116,121,112,101,115,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,15,117,112,100,97,116,101,95,105,99,111,110,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,13,117,112,100,97,116,101,95,115,121,109,98,111,108,3,117,114,108,4,117,116,102,56,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,2,31,8,9,12,11,7,1,9,0,1,2,6,31,8,9,18,2,39,8,6,53,8,4,21,8,6,30,11,5,1,8,11,2,2,2,31,8,9,55,11,8,1,9,0,3,2,1,18,2,2,34,0,34,1,34,0,1,0,0,16,4,11,0,55,0,56,0,2,1,1,0,0,3,6,11,0,58,0,12,1,17,43,11,1,2,2,1,0,0,16,3,11,0,55,0,2,3,1,0,0,16,3,11,0,54,0,2,4,1,0,0,16,4,11,0,55,1,56,1,2,5,1,0,0,16,3,11,0,55,1,2,6,1,0,0,16,3,11,0,54,1,2,7,1,0,0,16,5,11,1,17,44,11,0,57,1,2,8,1,0,0,13,6,11,0,58,1,12,1,17,43,11,1,2,9,1,0,0,16,7,11,2,17,44,11,0,11,1,56,2,57,1,2,10,1,0,0,16,6,11,0,11,1,56,3,56,4,1,2,11,1,4,0,13,10,11,1,58,1,12,2,17,43,11,0,54,1,11,2,56,4,1,2,12,1,0,0,16,6,11,0,54,1,11,1,11,2,56,5,2,13,1,0,0,38,59,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,11,11,0,1,11,2,1,7,1,39,10,1,10,0,46,56,6,37,4,18,5,24,11,0,1,11,2,1,7,2,39,64,12,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,3,10,0,46,56,6,10,1,26,12,4,40,10,3,10,1,6,1,0,0,0,0,0,0,0,23,35,4,53,5,42,13,5,10,0,10,4,10,2,56,7,68,12,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,34,11,0,1,11,2,1,11,5,2,14,1,0,0,16,5,11,0,17,44,56,8,57,1,2,15,1,0,0,13,7,11,0,58,1,12,1,17,43,11,1,56,9,2,16,1,0,0,16,25,14,0,56,10,4,4,5,8,11,6,1,7,0,39,10,6,17,44,11,0,56,11,57,0,11,6,17,44,11,1,11,3,17,33,11,2,17,31,11,4,17,33,11,5,57,2,2,17,1,0,0,16,8,11,2,17,44,11,0,54,0,11,1,56,12,57,1,2,18,1,0,0,16,5,11,0,54,0,11,1,56,12,2,19,1,4,0,13,9,11,1,58,1,12,2,17,43,11,0,54,0,11,2,56,13,2,20,1,4,0,16,7,11,0,11,1,11,3,56,14,11,2,56,15,2,21,1,4,0,16,5,11,2,11,1,54,2,21,2,22,1,4,0,16,5,11,2,11,1,54,3,21,2,23,1,4,0,16,5,11,2,11,1,54,4,21,2,24,1,4,0,16,7,11,2,17,47,56,16,11,1,54,5,21,2,25,1,0,0,16,4,11,0,55,6,20,2,26,1,0,0,16,4,11,0,55,2,20,2,27,1,0,0,16,4,11,0,55,3,20,2,28,1,0,0,16,4,11,0,55,4,20,2,29,1,0,0,16,4,11,0,55,5,20,2,30,1,0,0,16,3,11,0,55,0,2,2,1,0,1,1,2,1,3,1,4,1,5,1,1,0,34,1,34,2,34,3,34,4,34,5,34,6,34,0],"display":[161,28,235,11,6,0,0,0,13,1,0,16,2,16,46,3,62,132,1,4,194,1,22,5,216,1,196,1,7,156,3,223,2,8,251,5,64,6,187,6,20,10,207,6,38,11,245,6,6,12,251,6,160,3,13,155,10,6,14,161,10,6,0,14,1,31,0,18,0,26,0,27,0,32,0,33,0,36,0,0,12,1,8,1,0,1,3,1,8,1,0,8,3,1,8,1,1,4,7,0,3,2,7,0,3,6,4,0,4,3,12,0,6,5,2,0,7,7,7,2,1,0,0,0,0,24,0,1,1,8,0,25,2,1,1,8,0,12,0,3,1,8,0,35,4,3,1,8,0,9,5,3,1,8,0,11,6,3,1,8,0,15,5,3,1,8,0,29,7,3,1,8,0,23,8,9,1,8,0,37,10,11,1,8,0,19,10,12,1,8,0,13,13,1,1,8,0,10,5,3,1,8,2,16,14,3,1,3,3,24,13,28,0,3,34,21,22,0,4,20,8,9,1,0,5,28,19,3,1,12,6,30,17,18,0,7,17,3,30,2,1,0,7,22,31,3,2,1,0,7,29,26,27,2,1,0,8,14,11,14,0,14,12,14,17,1,13,23,21,25,16,14,13,29,19,25,20,25,2,6,8,6,7,8,7,1,11,0,1,9,0,4,6,8,6,10,8,3,10,8,3,7,8,7,0,1,7,11,0,1,9,0,3,7,11,0,1,9,0,8,3,8,3,3,7,11,0,1,9,0,10,8,3,10,8,3,2,7,11,0,1,9,0,8,3,1,6,8,6,1,1,1,6,11,0,1,9,0,1,13,1,6,11,8,2,8,3,8,3,1,7,8,7,1,9,0,3,11,0,1,9,0,3,3,1,8,3,1,6,8,7,1,5,2,9,0,5,2,13,11,8,2,8,3,8,3,1,6,8,5,1,8,4,1,11,2,1,9,0,2,3,3,2,8,3,8,3,2,7,11,8,2,9,0,9,1,6,9,0,2,9,0,9,1,1,8,5,1,11,1,1,9,0,1,11,8,2,9,0,9,1,3,7,11,8,2,9,0,9,1,9,0,9,1,7,68,105,115,112,108,97,121,14,68,105,115,112,108,97,121,67,114,101,97,116,101,100,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,6,86,101,99,77,97,112,14,86,101,114,115,105,111,110,85,112,100,97,116,101,100,3,97,100,100,12,97,100,100,95,105,110,116,101,114,110,97,108,12,97,100,100,95,109,117,108,116,105,112,108,101,15,99,114,101,97,116,101,95,97,110,100,95,107,101,101,112,15,99,114,101,97,116,101,95,105,110,116,101,114,110,97,108,7,100,105,115,112,108,97,121,4,101,100,105,116,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,6,102,105,101,108,100,115,12,102,114,111,109,95,112,97,99,107,97,103,101,2,105,100,6,105,110,115,101,114,116,13,105,115,95,97,117,116,104,111,114,105,122,101,100,3,110,101,119,15,110,101,119,95,119,105,116,104,95,102,105,101,108,100,115,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,6,115,101,110,100,101,114,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,112,100,97,116,101,95,118,101,114,115,105,111,110,7,118,101,99,95,109,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,3,21,8,5,19,11,8,2,8,3,8,3,37,13,1,2,1,21,8,4,2,2,3,21,8,4,37,13,19,11,8,2,8,3,8,3,2,14,1,14,0,14,0,1,0,0,3,11,11,0,56,0,4,4,5,8,11,1,1,7,0,39,11,1,56,1,2,1,1,0,0,15,43,14,1,65,16,12,6,10,6,14,2,65,16,33,4,9,5,15,11,0,1,11,3,1,7,1,39,6,0,0,0,0,0,0,0,0,12,5,11,0,11,3,56,2,12,4,10,5,10,6,35,4,41,5,26,13,4,14,1,10,5,66,16,20,14,2,10,5,66,16,20,56,3,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,21,11,4,2,2,1,4,0,3,8,11,0,10,1,56,2,11,1,46,17,18,56,4,2,3,1,4,0,20,24,10,0,55,0,20,72,1,0,22,10,0,54,0,21,10,0,55,0,20,12,1,10,0,55,1,20,12,2,11,0,55,2,17,15,11,1,11,2,57,0,56,5,2,4,1,4,0,3,5,11,0,11,1,11,2,56,3,2,5,1,4,0,24,38,14,1,65,16,12,4,10,4,14,2,65,16,33,4,9,5,13,11,0,1,7,1,39,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,35,5,20,10,0,14,1,10,3,66,16,20,14,2,10,3,66,16,20,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,15,11,0,1,2,6,1,4,0,3,11,10,0,54,1,14,1,56,6,1,1,11,0,11,1,11,2,56,3,2,7,1,4,0,3,7,11,0,54,1,14,1,56,6,1,1,2,8,1,0,0,3,3,11,0,56,7,2,9,1,0,0,3,4,11,0,55,0,20,2,10,1,0,0,3,3,11,0,55,1,2,11,0,0,0,28,12,11,0,17,14,12,1,14,1,17,15,57,1,56,8,11,1,56,9,72,0,0,57,2,2,12,0,0,0,3,6,11,0,54,1,11,1,11,2,56,10,2,0,2,0,1,0,0,0,14,1,14,2,14,0],"dynamic_field":[161,28,235,11,6,0,0,0,14,1,0,6,2,6,22,3,28,133,1,4,161,1,24,5,185,1,168,1,7,225,2,129,3,8,226,5,64,6,162,6,40,10,202,6,12,11,214,6,2,12,216,6,235,2,13,195,9,6,14,201,9,8,15,209,9,2,0,11,1,26,0,25,0,0,8,2,7,0,4,0,1,2,7,1,0,0,2,1,7,0,2,3,4,0,0,4,0,1,2,7,4,0,6,2,3,2,7,4,0,9,4,5,2,7,4,0,27,4,6,2,7,4,0,13,2,7,1,7,0,29,4,8,2,7,4,0,14,2,7,2,7,4,0,15,2,9,1,7,0,16,4,10,1,7,0,19,11,12,1,7,0,5,11,1,1,8,0,7,9,13,1,8,0,8,10,14,1,8,0,28,15,16,1,8,0,17,15,7,0,0,18,15,7,1,8,1,24,1,24,1,0,1,30,16,24,1,0,2,10,19,1,0,2,21,28,12,0,2,23,12,19,0,2,31,18,12,0,9,16,10,21,11,21,12,21,13,21,4,16,3,20,17,6,16,6,15,21,11,26,12,26,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,9,1,2,6,8,3,5,2,7,8,3,5,2,5,9,0,1,5,1,6,9,0,1,7,9,0,2,5,5,1,9,0,3,11,0,2,9,0,9,1,5,5,1,6,8,3,1,8,3,2,9,0,9,1,1,11,0,2,9,0,9,1,3,5,5,9,1,2,9,0,11,1,1,9,1,1,11,1,1,9,0,4,6,11,0,2,9,0,8,2,5,6,8,3,6,8,2,1,11,0,2,9,0,8,2,2,9,0,8,2,1,6,8,2,4,7,11,0,2,9,0,8,2,5,7,8,3,7,8,2,5,70,105,101,108,100,2,73,68,6,79,112,116,105,111,110,3,85,73,68,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,6,100,101,108,101,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,16,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,17,104,97,115,104,95,116,121,112,101,95,97,110,100,95,107,101,121,2,105,100,13,105,100,95,116,111,95,97,100,100,114,101,115,115,4,110,97,109,101,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,3,20,8,3,22,9,0,32,9,1,0,20,0,1,0,0,17,26,11,0,46,17,21,12,5,10,5,10,1,56,0,12,4,10,5,10,4,17,14,32,4,14,5,16,7,0,39,11,4,17,20,11,1,11,2,57,0,12,3,11,5,11,3,56,1,2,1,1,0,0,12,10,10,0,17,21,11,1,56,0,12,2,11,0,11,2,56,2,55,0,2,2,1,0,0,12,11,10,0,46,17,21,11,1,56,0,12,2,11,0,11,2,56,3,54,0,2,3,1,0,0,22,17,11,0,46,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,4,58,0,12,4,1,17,18,11,4,2,4,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,17,14,2,5,1,0,0,23,19,10,0,10,1,12,2,46,11,2,56,5,4,13,11,0,11,1,56,6,56,7,12,3,5,17,11,0,1,56,8,12,3,11,3,2,6,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,9,2,7,3,0,0,25,22,10,0,17,21,11,1,56,0,12,3,11,0,11,3,56,10,12,2,10,2,55,1,12,4,10,2,55,2,1,11,2,55,3,12,5,11,4,11,5,17,19,2,8,3,0,0,29,24,10,0,46,17,21,11,1,56,0,12,3,11,0,11,3,56,11,12,2,10,2,54,1,12,4,10,2,54,2,1,11,2,54,3,12,5,11,4,11,5,46,17,19,2,9,3,2,0,10,3,2,0,11,3,2,0,12,3,2,0,13,3,2,0,14,3,2,0,15,3,2,0,0,2,0,0,0,1,0,20,1,27,2,27,0,27,0,12,0],"dynamic_object_field":[161,28,235,11,6,0,0,0,10,1,0,8,2,8,20,3,28,138,1,4,166,1,26,5,192,1,131,1,7,195,2,178,2,8,245,4,64,10,181,5,6,11,187,5,2,12,189,5,233,1,0,11,1,22,0,10,0,21,0,3,7,1,0,0,1,1,7,1,0,0,3,0,7,0,3,2,4,0,0,4,0,1,2,7,12,0,6,2,3,2,7,12,0,9,4,5,2,7,12,0,23,4,6,2,7,12,0,12,2,7,1,7,0,13,2,7,2,7,12,0,17,2,8,1,7,1,20,1,24,1,0,1,25,10,24,1,0,2,4,0,1,2,7,4,2,5,18,1,1,8,2,7,15,11,1,8,2,8,19,20,1,8,2,13,2,7,2,7,4,2,14,2,15,1,7,2,15,4,19,1,7,2,16,22,7,1,8,2,23,4,6,2,7,4,2,24,22,10,1,8,3,17,11,12,1,8,3,18,17,12,0,3,26,16,17,0,19,6,9,13,14,14,10,6,11,6,15,14,12,6,18,6,17,13,13,13,16,6,7,12,8,12,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,8,2,3,11,0,1,9,0,8,2,11,0,1,9,0,1,9,0,1,6,9,0,1,8,2,2,11,0,1,9,0,8,2,1,11,0,1,9,0,2,6,8,3,5,1,6,8,3,1,5,2,5,9,0,2,7,8,3,5,1,7,9,0,4,11,0,1,9,0,11,0,1,9,0,9,1,5,2,5,5,2,11,0,1,9,0,5,1,11,1,1,9,0,2,73,68,6,79,112,116,105,111,110,3,85,73,68,7,87,114,97,112,112,101,114,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,4,110,97,109,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,19,9,0,0,10,0,1,0,0,9,21,11,1,57,0,12,5,14,2,56,0,12,4,10,0,10,5,11,4,56,1,11,0,11,5,12,3,46,11,3,56,2,1,17,21,11,2,56,3,2,1,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,2,56,4,2,2,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,5,56,6,2,3,1,0,0,21,20,11,1,57,0,12,3,10,0,10,3,12,2,46,11,2,56,2,12,5,17,21,11,5,56,7,12,4,11,0,11,3,56,8,1,11,4,2,4,1,0,0,14,7,11,1,57,0,12,2,11,0,11,2,56,9,2,5,1,0,0,23,20,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,9,2,11,0,11,2,56,2,12,3,17,21,11,3,56,10,2,6,1,0,0,23,21,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,56,11,2,11,0,11,2,56,2,12,3,1,11,3,17,20,56,12,2,0],"ecdsa_k1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,15,5,17,28,7,45,64,8,109,32,6,141,1,26,12,167,1,12,0,1,0,2,0,1,0,0,0,2,1,0,0,3,3,4,0,3,6,10,2,6,10,2,2,1,10,2,1,6,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,17,100,101,99,111,109,112,114,101,115,115,95,112,117,98,107,101,121,8,101,99,100,115,97,95,107,49,19,115,101,99,112,50,53,54,107,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,107,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,2,1,2,0,0],"ecdsa_r1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,10,5,12,24,7,36,46,8,82,32,6,114,26,12,140,1,8,0,0,0,1,0,1,0,0,2,2,3,0,3,6,10,2,6,10,2,2,1,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,8,101,99,100,115,97,95,114,49,19,115,101,99,112,50,53,54,114,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,114,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,0],"ecvrf":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,5,5,7,15,7,22,19,8,41,32,6,73,30,12,103,4,0,0,0,1,0,1,0,4,6,10,2,6,10,2,6,10,2,6,10,2,1,1,5,101,99,118,114,102,12,101,99,118,114,102,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,1,2,0,0],"ed25519":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,12,7,19,23,8,42,32,12,74,4,0,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,7,101,100,50,53,53,49,57,14,101,100,50,53,53,49,57,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"event":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,4,7,12,11,8,23,32,12,55,4,0,1,0,0,0,1,1,3,1,9,0,0,4,101,109,105,116,5,101,118,101,110,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"groth16":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,16,3,18,50,5,68,76,7,144,1,237,2,8,253,3,32,6,157,4,30,10,187,4,32,12,219,4,180,1,13,143,6,14,0,10,0,0,7,0,0,1,7,0,0,3,7,0,0,2,7,0,0,5,0,1,0,0,6,0,1,0,0,16,2,3,0,0,17,3,4,0,0,15,5,6,0,0,14,5,7,0,0,12,8,3,0,0,13,9,3,0,0,18,10,11,0,0,19,12,11,0,0,1,8,0,4,10,2,10,2,10,2,10,2,1,8,1,1,10,10,2,1,10,2,1,8,2,1,8,3,2,6,8,0,6,10,2,2,2,6,10,2,4,6,8,0,6,8,1,6,8,2,6,8,3,1,1,7,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,5,67,117,114,118,101,20,80,114,101,112,97,114,101,100,86,101,114,105,102,121,105,110,103,75,101,121,11,80,114,111,111,102,80,111,105,110,116,115,17,80,117,98,108,105,99,80,114,111,111,102,73,110,112,117,116,115,22,97,108,112,104,97,95,103,49,95,98,101,116,97,95,103,50,95,98,121,116,101,115,8,98,108,115,49,50,51,56,49,5,98,110,50,53,52,5,98,121,116,101,115,21,100,101,108,116,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,21,103,97,109,109,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,7,103,114,111,116,104,49,54,2,105,100,21,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,30,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,95,105,110,116,101,114,110,97,108,23,112,114,111,111,102,95,112,111,105,110,116,115,95,102,114,111,109,95,98,121,116,101,115,30,112,117,98,108,105,99,95,112,114,111,111,102,95,105,110,112,117,116,115,95,102,114,111,109,95,98,121,116,101,115,14,112,118,107,95,102,114,111,109,95,98,121,116,101,115,12,112,118,107,95,116,111,95,98,121,116,101,115,20,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,29,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,95,105,110,116,101,114,110,97,108,21,118,107,95,103,97,109,109,97,95,97,98,99,95,103,49,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,11,2,1,2,4,20,10,2,4,10,2,9,10,2,8,10,2,2,2,1,7,10,2,3,2,1,7,10,2,0,1,0,0,0,3,49,0,18,0,2,1,1,0,0,0,3,49,1,18,0,2,2,1,0,0,0,6,11,0,11,1,11,2,11,3,18,1,2,3,1,0,0,4,24,64,5,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,68,5,13,1,14,0,16,1,20,68,5,13,1,14,0,16,2,20,68,5,13,1,14,0,16,3,20,68,5,11,1,2,4,1,0,0,0,3,11,0,18,2,2,5,1,0,0,0,3,11,0,18,3,2,6,1,0,0,0,6,11,0,16,4,20,11,1,17,7,2,7,0,2,0,8,1,0,0,0,17,11,0,16,4,20,10,1,16,0,10,1,16,1,10,1,16,2,11,1,16,3,11,2,16,5,11,3,16,6,17,9,2,9,0,2,0,1,0,1,1,1,2,1,3,0,0,2,0,3,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,7,7,19,26,8,45,32,12,77,8,0,1,0,0,0,1,0,0,2,0,1,0,1,6,10,2,1,10,2,10,98,108,97,107,101,50,98,50,53,54,4,104,97,115,104,9,107,101,99,99,97,107,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"hex":[161,28,235,11,6,0,0,0,8,1,0,4,3,4,21,4,25,2,5,27,37,7,64,44,8,108,64,6,172,1,159,6,12,203,7,194,2,0,4,1,5,0,3,0,0,0,0,1,0,0,0,0,2,1,1,0,1,0,3,4,1,0,3,1,1,10,2,1,2,5,10,10,2,7,10,2,3,3,10,2,2,7,10,9,0,10,9,0,0,4,2,3,3,10,2,5,1,1,1,2,2,6,97,112,112,101,110,100,6,100,101,99,111,100,101,11,100,101,99,111,100,101,95,98,121,116,101,6,101,110,99,111,100,101,3,104,101,120,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,10,10,2,130,6,128,2,2,48,48,2,48,49,2,48,50,2,48,51,2,48,52,2,48,53,2,48,54,2,48,55,2,48,56,2,48,57,2,48,97,2,48,98,2,48,99,2,48,100,2,48,101,2,48,102,2,49,48,2,49,49,2,49,50,2,49,51,2,49,52,2,49,53,2,49,54,2,49,55,2,49,56,2,49,57,2,49,97,2,49,98,2,49,99,2,49,100,2,49,101,2,49,102,2,50,48,2,50,49,2,50,50,2,50,51,2,50,52,2,50,53,2,50,54,2,50,55,2,50,56,2,50,57,2,50,97,2,50,98,2,50,99,2,50,100,2,50,101,2,50,102,2,51,48,2,51,49,2,51,50,2,51,51,2,51,52,2,51,53,2,51,54,2,51,55,2,51,56,2,51,57,2,51,97,2,51,98,2,51,99,2,51,100,2,51,101,2,51,102,2,52,48,2,52,49,2,52,50,2,52,51,2,52,52,2,52,53,2,52,54,2,52,55,2,52,56,2,52,57,2,52,97,2,52,98,2,52,99,2,52,100,2,52,101,2,52,102,2,53,48,2,53,49,2,53,50,2,53,51,2,53,52,2,53,53,2,53,54,2,53,55,2,53,56,2,53,57,2,53,97,2,53,98,2,53,99,2,53,100,2,53,101,2,53,102,2,54,48,2,54,49,2,54,50,2,54,51,2,54,52,2,54,53,2,54,54,2,54,55,2,54,56,2,54,57,2,54,97,2,54,98,2,54,99,2,54,100,2,54,101,2,54,102,2,55,48,2,55,49,2,55,50,2,55,51,2,55,52,2,55,53,2,55,54,2,55,55,2,55,56,2,55,57,2,55,97,2,55,98,2,55,99,2,55,100,2,55,101,2,55,102,2,56,48,2,56,49,2,56,50,2,56,51,2,56,52,2,56,53,2,56,54,2,56,55,2,56,56,2,56,57,2,56,97,2,56,98,2,56,99,2,56,100,2,56,101,2,56,102,2,57,48,2,57,49,2,57,50,2,57,51,2,57,52,2,57,53,2,57,54,2,57,55,2,57,56,2,57,57,2,57,97,2,57,98,2,57,99,2,57,100,2,57,101,2,57,102,2,97,48,2,97,49,2,97,50,2,97,51,2,97,52,2,97,53,2,97,54,2,97,55,2,97,56,2,97,57,2,97,97,2,97,98,2,97,99,2,97,100,2,97,101,2,97,102,2,98,48,2,98,49,2,98,50,2,98,51,2,98,52,2,98,53,2,98,54,2,98,55,2,98,56,2,98,57,2,98,97,2,98,98,2,98,99,2,98,100,2,98,101,2,98,102,2,99,48,2,99,49,2,99,50,2,99,51,2,99,52,2,99,53,2,99,54,2,99,55,2,99,56,2,99,57,2,99,97,2,99,98,2,99,99,2,99,100,2,99,101,2,99,102,2,100,48,2,100,49,2,100,50,2,100,51,2,100,52,2,100,53,2,100,54,2,100,55,2,100,56,2,100,57,2,100,97,2,100,98,2,100,99,2,100,100,2,100,101,2,100,102,2,101,48,2,101,49,2,101,50,2,101,51,2,101,52,2,101,53,2,101,54,2,101,55,2,101,56,2,101,57,2,101,97,2,101,98,2,101,99,2,101,100,2,101,101,2,101,102,2,102,48,2,102,49,2,102,50,2,102,51,2,102,52,2,102,53,2,102,54,2,102,55,2,102,56,2,102,57,2,102,97,2,102,98,2,102,99,2,102,100,2,102,101,2,102,102,10,2,1,0,0,1,0,0,2,33,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,4,12,5,12,3,10,3,10,4,35,4,31,5,12,13,5,12,2,7,2,12,1,11,2,14,1,14,0,10,3,66,1,20,52,66,0,20,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,5,2,1,1,0,0,5,47,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,3,12,4,12,2,10,3,6,2,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,14,5,16,7,0,39,10,2,10,3,35,4,45,5,21,14,0,10,2,66,1,20,17,2,49,16,24,14,0,10,2,6,1,0,0,0,0,0,0,0,22,66,1,20,17,2,22,12,1,13,4,11,1,68,1,11,2,6,2,0,0,0,0,0,0,0,22,12,2,5,16,11,4,2,2,0,0,0,6,64,49,48,10,0,37,4,9,10,0,49,58,35,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,5,5,62,49,65,10,0,37,4,27,10,0,49,71,35,12,2,5,29,9,12,2,11,2,4,38,49,10,11,0,22,49,65,23,12,4,5,60,49,97,10,0,37,4,47,10,0,49,103,35,12,3,5,49,9,12,3,11,3,4,52,5,54,7,1,39,49,10,11,0,22,49,97,23,12,4,11,4,12,5,11,5,2,0],"hmac":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,10,7,17,19,8,36,32,12,68,4,0,0,0,1,0,1,0,2,6,10,2,6,10,2,1,10,2,4,104,109,97,99,13,104,109,97,99,95,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"kiosk":[161,28,235,11,6,0,0,0,13,1,0,22,2,22,94,3,116,230,2,4,218,3,64,5,154,4,250,3,7,148,8,189,7,8,209,15,64,6,145,16,130,1,10,147,17,101,11,248,17,8,12,128,18,244,13,13,244,31,18,14,134,32,6,0,51,1,60,0,21,0,26,0,30,0,31,0,33,0,59,0,81,0,83,0,84,0,8,12,0,0,9,12,0,0,13,12,1,12,1,0,1,0,0,0,4,7,0,0,10,7,0,0,11,7,0,0,6,3,1,12,1,0,7,3,1,12,1,0,5,3,1,12,1,1,12,7,1,0,0,2,0,4,1,0,1,3,2,12,1,0,1,7,3,7,0,7,18,4,0,8,14,2,0,9,15,12,1,0,1,9,16,0,1,0,1,10,17,2,0,0,57,0,1,0,0,25,2,3,0,0,79,4,5,0,0,80,6,5,0,0,62,7,5,1,12,0,55,8,5,1,12,0,82,9,10,1,12,0,53,11,5,1,12,0,63,12,5,1,12,0,28,9,5,1,12,0,68,13,14,1,12,0,54,15,16,1,12,0,72,17,14,1,12,0,75,18,5,1,12,0,90,19,3,0,0,39,20,21,0,0,40,20,21,1,12,0,46,20,21,0,0,44,20,21,0,0,45,20,21,0,0,38,22,21,0,0,87,22,23,0,0,78,24,5,0,0,85,25,26,0,0,86,27,23,0,0,61,25,28,0,0,48,25,29,0,0,66,25,30,0,0,67,22,31,0,0,22,32,33,1,12,0,23,9,34,1,12,0,24,9,35,1,12,0,76,36,5,1,12,0,70,37,38,1,12,0,69,37,38,1,12,0,71,37,30,1,12,1,29,70,10,1,0,1,47,69,21,1,0,2,50,61,30,1,0,2,89,71,30,1,0,2,91,5,42,1,0,3,37,46,47,1,0,3,42,47,42,1,0,3,82,72,47,1,0,3,89,60,30,1,0,4,19,49,5,2,7,4,4,34,74,21,1,7,4,73,53,55,2,7,4,4,74,53,54,2,7,4,5,19,49,5,2,7,12,5,22,74,77,2,7,12,5,23,53,78,2,7,12,5,34,74,21,1,7,5,35,74,21,2,7,12,5,73,53,55,2,7,12,6,32,10,5,1,3,7,27,40,5,0,7,41,33,38,1,8,7,57,0,40,0,7,88,26,38,0,9,58,63,64,1,0,10,77,43,28,0,40,41,57,44,41,41,57,10,49,48,45,50,4,10,48,52,54,48,16,10,45,52,55,57,7,10,47,52,55,58,44,41,42,41,38,41,48,50,55,62,60,10,10,10,37,30,36,30,39,41,43,41,52,73,53,48,46,75,46,76,50,48,51,48,1,7,8,18,2,8,0,8,1,3,8,0,8,1,7,8,18,1,11,12,1,8,15,3,7,8,0,6,8,1,6,8,18,0,3,7,8,0,6,8,1,5,3,7,8,0,6,8,1,9,0,4,7,8,0,6,8,1,6,11,16,1,9,0,9,0,3,7,8,0,6,8,1,8,13,1,9,0,4,7,8,0,6,8,1,8,13,3,4,7,8,0,6,8,1,9,0,3,3,7,8,0,8,13,11,12,1,8,15,2,9,0,11,17,1,9,0,5,7,8,0,6,8,1,8,13,3,7,8,18,1,11,2,1,9,0,3,7,8,0,11,2,1,9,0,11,12,1,8,15,2,7,8,0,11,2,1,9,0,4,7,8,0,6,8,1,11,10,1,3,7,8,18,2,6,8,0,8,13,1,1,2,7,8,0,6,8,1,1,7,8,14,3,7,8,0,6,8,1,1,1,6,8,0,1,6,8,14,1,7,8,0,1,5,1,14,1,3,1,7,11,11,1,8,15,3,6,8,0,6,8,1,8,13,1,6,9,0,1,7,9,0,2,9,0,8,3,3,7,8,0,9,0,8,3,1,6,11,2,1,9,0,1,8,13,2,8,1,8,0,1,8,14,1,8,15,1,11,11,1,9,0,1,6,8,18,1,8,0,5,8,14,8,13,8,14,14,11,11,1,8,15,2,11,11,1,9,0,7,8,18,1,11,12,1,9,0,2,8,4,9,0,3,7,8,14,9,0,9,1,2,8,6,1,3,8,13,8,13,8,13,2,8,5,3,2,7,8,14,9,0,1,11,10,1,9,1,1,9,1,2,8,13,8,13,1,11,7,1,9,0,1,11,9,1,9,0,2,9,0,3,1,6,11,12,1,9,0,2,7,11,11,1,9,0,11,11,1,9,0,1,11,8,1,9,0,3,8,13,3,8,13,1,11,17,1,9,0,7,8,13,8,13,8,14,8,13,8,13,3,8,14,5,8,14,8,13,8,13,3,3,3,8,14,8,13,8,13,3,3,3,3,1,6,11,10,1,9,0,1,11,10,1,9,0,1,6,11,11,1,9,0,3,7,11,11,1,9,0,3,7,8,18,1,8,4,2,6,8,14,9,0,1,8,6,1,8,5,1,6,9,1,1,7,9,1,7,66,97,108,97,110,99,101,6,66,111,114,114,111,119,4,67,111,105,110,2,73,68,4,73,116,101,109,12,73,116,101,109,68,101,108,105,115,116,101,100,10,73,116,101,109,76,105,115,116,101,100,13,73,116,101,109,80,117,114,99,104,97,115,101,100,5,75,105,111,115,107,13,75,105,111,115,107,79,119,110,101,114,67,97,112,7,76,105,115,116,105,110,103,4,76,111,99,107,6,79,112,116,105,111,110,11,80,117,114,99,104,97,115,101,67,97,112,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,16,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,10,98,111,114,114,111,119,95,118,97,108,18,99,108,111,115,101,95,97,110,100,95,119,105,116,104,100,114,97,119,4,99,111,105,110,6,100,101,108,101,116,101,6,100,101,108,105,115,116,12,100,101,115,116,114,111,121,95,115,111,109,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,4,101,109,105,116,5,101,118,101,110,116,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,3,102,111,114,12,102,114,111,109,95,98,97,108,97,110,99,101,10,104,97,115,95,97,99,99,101,115,115,8,104,97,115,95,105,116,101,109,18,104,97,115,95,105,116,101,109,95,119,105,116,104,95,116,121,112,101,2,105,100,12,105,110,116,111,95,98,97,108,97,110,99,101,12,105,115,95,101,120,99,108,117,115,105,118,101,9,105,115,95,108,105,115,116,101,100,21,105,115,95,108,105,115,116,101,100,95,101,120,99,108,117,115,105,118,101,108,121,9,105,115,95,108,111,99,107,101,100,7,105,115,95,115,111,109,101,10,105,116,101,109,95,99,111,117,110,116,7,105,116,101,109,95,105,100,4,106,111,105,110,5,107,105,111,115,107,8,107,105,111,115,107,95,105,100,4,108,105,115,116,22,108,105,115,116,95,119,105,116,104,95,112,117,114,99,104,97,115,101,95,99,97,112,4,108,111,99,107,9,109,105,110,95,112,114,105,99,101,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,5,111,119,110,101,114,5,112,108,97,99,101,14,112,108,97,99,101,95,97,110,100,95,108,105,115,116,5,112,114,105,99,101,7,112,114,111,102,105,116,115,14,112,114,111,102,105,116,115,95,97,109,111,117,110,116,11,112,114,111,102,105,116,115,95,109,117,116,8,112,117,114,99,104,97,115,101,17,112,117,114,99,104,97,115,101,95,99,97,112,95,105,116,101,109,18,112,117,114,99,104,97,115,101,95,99,97,112,95,107,105,111,115,107,22,112,117,114,99,104,97,115,101,95,99,97,112,95,109,105,110,95,112,114,105,99,101,17,112,117,114,99,104,97,115,101,95,119,105,116,104,95,99,97,112,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,19,114,101,116,117,114,110,95,112,117,114,99,104,97,115,101,95,99,97,112,10,114,101,116,117,114,110,95,118,97,108,6,115,101,110,100,101,114,20,115,101,116,95,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,9,115,101,116,95,111,119,110,101,114,16,115,101,116,95,111,119,110,101,114,95,99,117,115,116,111,109,3,115,117,105,4,116,97,107,101,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,3,117,105,100,7,117,105,100,95,109,117,116,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,0,2,5,41,8,14,65,11,11,1,8,15,61,5,48,14,20,1,1,2,2,41,8,14,36,8,13,2,2,4,41,8,14,52,8,13,49,8,13,56,3,3,2,2,52,8,13,49,8,13,4,2,1,41,8,13,5,2,2,41,8,13,43,1,6,2,1,41,8,13,7,2,3,51,8,13,41,8,13,64,3,8,2,3,51,8,13,41,8,13,64,3,9,2,2,51,8,13,41,8,13,7,10,9,10,8,10,2,10,0,1,0,0,39,19,10,0,17,58,56,0,10,0,46,17,61,73,0,0,0,0,8,18,0,12,2,11,0,17,58,14,2,56,1,18,1,12,1,11,2,11,1,2,1,1,0,0,45,38,11,0,19,0,1,12,6,1,12,7,12,5,11,1,19,1,12,4,12,3,14,5,17,59,11,4,33,4,17,5,21,11,2,1,7,0,39,11,6,73,0,0,0,0,33,4,26,5,30,11,2,1,7,3,39,11,3,17,56,11,5,17,56,11,7,11,2,56,2,2,2,1,0,0,5,21,10,0,46,56,1,11,1,16,0,20,33,4,9,5,15,11,0,1,11,2,1,7,0,39,11,2,17,61,11,0,15,1,21,2,3,1,0,0,5,18,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,2,11,0,15,1,21,2,4,1,0,0,5,29,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,16,2,20,73,1,0,0,0,22,10,0,15,2,21,11,0,15,3,14,2,56,3,18,4,11,2,56,4,2,5,1,0,0,5,12,10,0,15,3,14,3,56,3,18,6,8,56,5,11,0,11,1,11,3,56,6,2,6,1,0,0,51,72,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,17,32,4,22,5,26,11,0,1,7,8,39,10,0,10,2,12,4,46,11,4,17,19,32,4,35,5,39,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,15,4,47,5,51,11,0,1,7,11,39,10,0,16,2,20,73,1,0,0,0,23,10,0,15,2,21,10,0,15,3,10,2,9,18,5,56,7,1,11,0,15,3,11,2,18,4,56,8,2,7,1,0,0,56,53,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,4,46,11,4,56,9,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,5,46,11,5,17,19,32,4,34,5,38,11,0,1,7,4,39,10,0,15,3,10,2,9,18,5,10,3,56,10,11,0,46,56,1,11,2,11,3,57,0,56,11,2,8,1,0,0,38,13,14,2,56,3,12,4,10,0,10,1,11,2,56,6,11,0,11,1,11,4,11,3,56,12,2,9,1,0,0,51,64,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,56,9,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,19,32,4,34,5,38,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,18,4,46,5,50,11,0,1,7,12,39,10,0,15,3,10,2,9,18,5,56,13,1,11,0,46,56,1,11,2,57,1,56,14,2,10,1,0,0,59,58,10,0,15,3,10,1,9,18,5,56,13,12,4,10,0,15,3,10,1,18,4,56,8,12,3,10,0,16,2,20,73,1,0,0,0,23,10,0,15,2,21,10,4,14,2,56,15,33,4,27,5,31,11,0,1,7,1,39,10,0,15,4,11,2,56,16,56,17,1,10,0,15,3,10,1,18,6,56,18,1,10,0,46,56,1,10,1,10,4,57,2,56,19,11,3,11,1,11,4,11,0,46,56,1,56,20,2,11,1,0,0,65,76,10,0,46,56,1,10,1,16,0,20,33,4,9,5,17,11,0,1,11,4,1,11,1,1,7,0,39,10,0,10,2,12,5,46,11,5,56,9,4,25,5,33,11,0,1,11,4,1,11,1,1,7,11,39,10,0,10,2,12,6,46,11,6,17,18,32,4,42,5,50,11,0,1,11,4,1,11,1,1,7,6,39,11,4,17,58,12,11,11,0,15,3,10,2,8,18,5,10,3,56,10,11,11,12,7,11,2,12,8,11,1,16,0,20,12,9,11,3,12,10,11,7,11,9,11,8,11,10,57,3,2,12,1,0,0,66,50,11,1,58,3,12,6,12,4,12,5,12,3,14,2,56,15,12,7,10,7,11,6,38,4,14,5,18,11,0,1,7,1,39,10,0,46,56,1,11,5,33,4,25,5,29,11,0,1,7,5,39,10,0,15,3,10,4,8,18,5,56,13,1,10,0,15,3,10,4,9,18,5,11,7,56,10,11,3,17,56,11,0,11,4,11,2,56,21,2,13,1,0,0,67,27,11,1,58,3,1,12,3,12,4,12,2,10,0,46,56,1,11,4,33,4,13,5,17,11,0,1,7,5,39,11,0,15,3,11,3,8,18,5,56,13,1,11,2,17,56,2,14,1,0,0,68,49,10,0,46,56,1,11,1,16,0,20,33,4,9,5,15,11,0,1,11,3,1,7,0,39,14,2,56,22,4,37,11,2,56,23,12,6,10,6,10,0,16,4,56,24,37,4,28,5,34,11,0,1,11,3,1,7,2,39,11,6,12,4,5,41,10,0,16,4,56,24,12,4,11,4,12,5,11,0,15,4,11,5,11,3,56,25,2,15,1,0,0,5,6,11,0,16,3,11,1,18,4,56,26,2,16,1,0,0,5,6,11,0,16,3,11,1,18,4,56,27,2,17,1,0,0,5,6,11,0,16,3,11,1,18,6,56,28,2,18,1,0,0,21,18,10,0,16,3,10,1,9,18,5,56,29,4,12,11,0,1,8,12,2,5,16,11,0,11,1,17,19,12,2,11,2,2,19,1,0,0,5,7,11,0,16,3,11,1,8,18,5,56,29,2,20,1,0,0,5,8,11,0,46,56,1,11,1,16,0,20,33,2,21,1,0,0,5,16,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,0,15,3,2,22,1,0,0,5,18,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,2,11,0,15,5,21,2,23,1,0,0,5,12,10,0,16,5,20,4,5,5,9,11,0,1,7,7,39,11,0,16,3,2,24,1,0,0,5,12,10,0,16,5,20,4,5,5,9,11,0,1,7,7,39,11,0,15,3,2,25,1,0,0,5,4,11,0,16,1,20,2,26,1,0,0,5,4,11,0,16,2,20,2,27,1,0,0,5,4,11,0,16,4,56,24,2,28,1,0,0,5,16,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,0,15,4,2,29,1,0,0,5,27,10,0,56,1,11,1,16,0,20,33,4,8,5,12,11,0,1,7,0,39,10,0,10,2,17,15,4,17,5,21,11,0,1,7,11,39,11,0,16,3,11,2,18,4,56,30,2,30,1,0,0,56,44,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,15,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,18,32,4,34,5,38,11,0,1,7,9,39,11,0,15,3,11,2,18,4,56,31,2,31,1,0,0,56,49,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,15,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,18,32,4,34,5,38,11,0,1,7,9,39,10,0,15,3,10,2,18,4,56,8,11,0,46,56,1,11,2,18,3,2,32,1,0,0,56,32,11,2,19,3,12,3,12,4,10,0,46,56,1,11,4,33,4,11,5,15,11,0,1,7,5,39,14,1,56,3,10,3,33,4,21,5,25,11,0,1,7,10,39,11,0,15,3,11,3,18,4,11,1,56,4,2,33,1,0,0,5,4,11,0,55,0,20,2,34,1,0,0,5,4,11,0,55,1,20,2,35,1,0,0,5,4,11,0,55,2,20,2,1,1,0,2,0,3,0,0,0,1,0,4,2,1,2,2,2,3,6,10,7,10,8,10,0],"linked_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,30,3,40,212,1,4,252,1,28,5,152,2,188,1,7,212,3,205,2,8,161,6,64,6,225,6,20,10,245,6,38,11,155,7,4,12,159,7,151,5,13,182,12,14,14,196,12,14,0,24,1,29,0,14,0,28,0,40,0,0,12,2,7,0,4,1,0,1,4,2,7,0,4,0,1,2,7,1,0,0,3,4,4,0,4,3,2,0,0,25,0,1,2,7,4,0,17,2,3,2,7,4,0,6,2,3,2,7,4,0,34,4,5,2,7,4,0,33,4,5,2,7,4,0,7,6,7,2,7,4,0,8,8,9,2,7,4,0,32,6,3,2,7,4,0,26,6,3,2,7,4,0,35,8,10,2,7,4,0,31,11,12,2,7,4,0,30,11,12,2,7,4,0,9,6,13,2,7,4,0,23,2,14,2,7,4,0,20,2,13,2,7,4,0,11,1,5,2,7,4,0,13,1,5,2,7,6,1,7,3,25,1,0,1,12,17,16,1,0,1,16,19,5,1,0,1,21,3,13,1,0,1,22,3,13,1,0,1,27,5,17,1,0,1,37,16,17,1,0,1,38,19,17,1,0,2,5,22,5,2,7,4,2,7,23,7,2,7,4,2,8,21,9,2,7,4,2,15,23,13,2,7,4,2,35,21,10,2,7,4,3,10,15,5,0,3,25,0,15,0,22,16,24,16,20,16,19,16,21,16,18,16,23,16,27,20,25,20,26,20,29,20,17,16,9,12,28,20,1,7,8,4,1,11,0,2,9,0,9,1,1,6,11,0,2,9,0,9,1,1,6,11,2,1,9,0,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,7,11,0,2,9,0,9,1,2,9,0,9,1,1,1,1,3,1,8,3,1,9,0,1,11,2,1,9,0,5,11,2,1,9,0,11,2,1,9,0,11,2,1,9,0,9,0,11,2,1,9,0,2,7,11,2,1,9,0,9,0,2,9,0,11,1,2,9,0,9,1,2,7,8,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,3,11,2,1,9,0,11,2,1,9,0,9,1,1,6,9,0,2,8,3,3,11,76,105,110,107,101,100,84,97,98,108,101,4,78,111,100,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,4,98,97,99,107,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,4,102,105,108,108,5,102,114,111,110,116,4,104,101,97,100,2,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,6,108,101,110,103,116,104,12,108,105,110,107,101,100,95,116,97,98,108,101,3,110,101,119,4,110,101,120,116,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,111,112,95,98,97,99,107,9,112,111,112,95,102,114,111,110,116,4,112,114,101,118,9,112,117,115,104,95,98,97,99,107,10,112,117,115,104,95,102,114,111,110,116,6,114,101,109,111,118,101,4,115,105,122,101,4,115,111,109,101,12,115,119,97,112,95,111,114,95,102,105,108,108,4,116,97,105,108,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,19,8,3,36,3,18,11,2,1,9,0,39,11,2,1,9,0,1,2,3,32,11,2,1,9,0,26,11,2,1,9,0,41,9,1,0,12,1,12,0,1,0,0,5,7,11,0,17,31,6,0,0,0,0,0,0,0,0,56,0,56,0,57,0,2,1,1,0,0,5,3,11,0,55,0,2,2,1,0,0,5,3,11,0,55,1,2,3,1,0,0,18,54,10,0,54,0,10,1,56,1,12,5,10,0,55,1,56,2,4,13,10,0,54,1,10,1,56,3,56,0,12,7,14,5,56,4,4,33,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,3,21,11,6,56,6,12,3,5,35,56,0,12,3,11,3,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,4,1,0,0,18,54,10,0,55,0,56,2,4,8,10,0,54,0,10,1,56,3,10,0,54,1,10,1,56,1,12,5,14,5,56,4,4,31,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,5,21,11,6,56,6,12,3,5,33,56,0,12,3,11,3,12,7,56,0,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,5,1,0,0,5,6,11,0,55,2,11,1,56,9,55,6,2,6,1,0,0,5,6,11,0,54,2,11,1,56,7,54,6,2,7,1,0,0,5,6,11,0,55,2,11,1,56,9,55,3,2,8,1,0,0,5,6,11,0,55,2,11,1,56,9,55,5,2,9,1,0,0,24,65,10,0,54,2,10,1,56,10,58,1,12,4,12,2,12,3,10,0,55,4,20,6,1,0,0,0,0,0,0,0,23,10,0,54,4,21,14,3,56,4,4,28,10,2,10,0,54,2,14,3,56,11,20,56,7,54,5,21,14,2,56,4,4,40,10,3,10,0,54,2,14,2,56,11,20,56,7,54,3,21,10,0,55,0,56,11,14,1,33,4,50,11,2,10,0,54,0,21,10,0,55,1,56,11,14,1,33,4,61,11,3,11,0,54,1,21,5,63,11,0,1,11,4,2,10,1,0,0,16,19,10,0,55,0,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,0,56,11,20,12,1,10,1,11,0,11,1,56,12,2,11,1,0,0,16,19,10,0,55,1,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,1,56,11,20,12,1,10,1,11,0,11,1,56,12,2,12,1,0,0,5,5,11,0,55,2,11,1,56,13,2,13,1,0,0,5,4,11,0,55,4,20,2,14,1,0,0,5,6,11,0,55,4,20,6,0,0,0,0,0,0,0,0,33,2,15,1,0,0,26,16,11,0,58,0,1,1,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,11,5,13,7,0,39,11,1,17,30,2,16,1,0,0,5,7,11,0,58,0,1,1,1,17,30,2,0,2,0,3,0,0,1,0,0,1,1,1,1,2,0,12,1,12,2,12,3,12,4,12,5,12,6,12,0],"math":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,35,5,37,18,7,55,57,8,112,32,12,144,1,249,3,0,2,0,3,0,1,0,0,4,0,1,0,0,0,0,1,0,0,5,2,1,0,0,6,1,1,0,0,7,3,3,0,0,1,0,1,0,2,3,3,1,3,2,3,2,1,4,3,4,4,4,3,15,15,15,4,100,105,102,102,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,4,109,97,116,104,3,109,97,120,3,109,105,110,3,112,111,119,4,115,113,114,116,9,115,113,114,116,95,117,49,50,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,1,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,2,1,0,0,1,15,10,0,10,1,36,4,9,11,0,11,1,23,12,2,5,13,11,1,11,0,23,12,2,11,2,2,3,1,0,0,1,33,6,1,0,0,0,0,0,0,0,12,2,10,1,49,1,38,4,31,5,7,10,1,49,2,25,49,0,33,4,22,10,0,11,0,24,12,0,11,1,49,2,26,12,1,5,30,11,2,10,0,24,12,2,11,1,49,1,23,12,1,5,2,11,2,2,4,1,0,0,4,43,50,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,12,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,53,12,3,10,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,52,2,5,1,0,0,5,43,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,77,12,3,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,53,2,6,1,0,0,1,19,10,0,10,1,25,6,0,0,0,0,0,0,0,0,33,4,11,11,0,11,1,26,12,2,5,17,11,0,11,1,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,2,0],"object":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,126,4,146,1,6,5,152,1,35,7,187,1,250,2,8,181,4,64,6,245,4,112,10,229,5,11,12,240,5,130,2,13,242,7,4,15,246,7,8,0,24,1,4,0,3,0,30,0,0,7,0,0,2,4,0,3,1,2,0,0,21,0,1,0,0,20,0,2,0,0,19,1,3,0,0,18,2,3,0,0,27,4,5,0,0,8,6,5,0,0,31,7,0,0,0,34,7,3,0,0,33,7,1,0,0,32,7,2,0,0,22,8,5,0,0,9,5,6,0,0,15,9,3,1,8,0,5,9,0,1,8,0,17,9,1,1,8,0,16,9,2,1,8,0,6,9,7,1,8,0,23,2,5,0,0,10,2,6,0,0,25,2,6,0,1,28,9,1,1,0,2,14,1,2,0,3,13,8,2,0,3,26,4,2,0,20,2,16,10,20,3,1,6,8,0,1,10,2,1,5,1,8,0,1,6,8,2,1,8,1,0,1,6,8,1,1,7,8,2,1,6,9,0,1,9,0,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,100,100,114,101,115,115,3,98,99,115,9,98,111,114,114,111,119,95,105,100,10,98,111,114,114,111,119,95,117,105,100,5,98,121,116,101,115,5,99,108,111,99,107,6,100,101,108,101,116,101,11,100,101,108,101,116,101,95,105,109,112,108,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,2,105,100,10,105,100,95,97,100,100,114,101,115,115,8,105,100,95,98,121,116,101,115,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,102,114,111,109,95,98,121,116,101,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,11,105,100,95,116,111,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,6,111,98,106,101,99,116,14,114,101,99,111,114,100,95,110,101,119,95,117,105,100,6,115,101,110,100,101,114,16,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,12,117,105,100,95,116,111,95,98,121,116,101,115,12,117,105,100,95,116,111,95,105,110,110,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,7,5,1,2,1,15,8,0,0,1,0,0,6,4,11,0,16,0,56,0,2,1,1,0,0,6,4,11,0,16,0,20,2,2,1,0,0,6,4,11,0,17,21,17,3,2,3,1,0,0,6,3,11,0,18,0,2,4,0,0,0,6,12,11,0,17,23,7,3,33,4,6,5,8,7,2,39,7,0,18,0,18,1,2,5,3,0,0,6,4,7,1,18,0,18,1,2,6,1,0,0,6,3,11,0,16,1,2,7,1,0,0,6,4,11,0,16,1,20,2,8,1,0,0,6,5,11,0,16,1,16,0,56,0,2,9,1,0,0,6,5,11,0,16,1,16,0,20,2,10,1,0,0,6,5,11,0,17,22,18,0,18,1,2,11,1,0,0,6,5,11,0,19,1,19,0,17,18,2,12,1,0,0,6,5,11,0,56,1,16,1,20,2,13,1,0,0,6,4,11,0,56,1,16,1,2,14,1,0,0,6,5,11,0,56,1,16,1,56,2,2,15,1,0,0,6,6,11,0,56,1,16,1,16,0,20,2,16,0,2,0,17,3,0,0,6,6,10,0,17,19,11,0,18,0,18,1,2,18,0,2,0,19,0,2,0,0,0,1,0,0,8,0,11,0,12,0,29,0],"object_bag":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,22,3,32,124,4,156,1,14,5,170,1,88,7,130,2,231,1,8,233,3,64,6,169,4,10,10,179,4,8,12,187,4,245,1,13,176,6,4,0,20,1,21,0,12,0,19,0,24,0,1,12,0,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,18,0,1,0,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,22,6,8,2,7,12,0,8,4,9,1,7,0,9,4,9,2,7,12,0,17,10,11,0,0,16,10,9,0,0,11,1,3,0,0,25,4,12,1,7,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,13,16,9,1,7,2,14,16,9,2,7,12,2,15,16,12,1,7,2,22,17,8,2,7,12,3,10,13,3,0,3,18,0,13,0,11,14,12,14,13,14,17,14,14,18,15,14,16,18,1,7,8,4,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,9,79,98,106,101,99,116,66,97,103,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,10,111,98,106,101,99,116,95,98,97,103,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,15,8,3,23,3,0,1,0,0,3,5,11,0,17,19,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,19,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,18,2,10,1,0,0,3,5,11,0,16,0,11,1,56,6,2,0,0,0,1,0],"object_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,26,3,36,120,4,156,1,12,5,168,1,113,7,153,2,199,1,8,224,3,64,6,160,4,10,10,170,4,8,11,178,4,2,12,180,4,230,1,13,154,6,4,14,158,6,4,0,18,1,19,0,11,0,17,0,22,0,1,12,2,7,1,12,1,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,16,0,1,2,7,12,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,20,6,8,2,7,12,0,8,4,9,2,7,12,0,15,10,11,2,7,12,0,14,10,9,2,7,12,0,10,1,3,2,7,12,0,23,4,12,2,7,12,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,12,16,9,1,7,2,13,16,12,1,7,2,20,17,8,2,7,12,3,9,13,3,0,3,16,0,13,0,10,14,11,14,12,14,15,14,13,18,14,18,1,7,8,4,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,13,8,3,21,3,0,14,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,19,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,9,1,0,0,3,5,11,0,55,0,11,1,56,5,2,0,0,0,1,0,14,1,14,0],"package":[161,28,235,11,6,0,0,0,11,1,0,14,2,14,36,3,50,183,1,4,233,1,10,5,243,1,118,7,233,2,144,5,8,249,7,64,6,185,8,93,10,150,9,48,12,198,9,129,4,13,199,13,20,0,36,1,10,1,50,0,33,0,48,0,49,0,51,0,1,12,0,0,6,12,0,0,8,0,0,0,7,0,0,1,2,7,0,2,4,7,0,3,0,7,0,3,5,4,0,5,3,2,0,0,14,0,1,1,2,0,15,0,2,1,2,0,12,1,2,0,0,22,3,4,1,0,0,21,3,4,1,0,0,39,3,5,0,0,40,3,5,0,0,52,6,7,0,0,54,6,8,0,0,53,6,9,0,0,46,10,7,0,0,47,10,9,0,0,41,11,7,0,0,42,11,7,0,0,45,10,12,0,0,17,2,9,0,0,9,2,9,0,0,19,2,9,0,0,34,13,2,0,0,35,13,2,0,0,30,14,2,0,0,11,15,16,0,0,16,17,2,0,0,43,18,2,0,2,23,24,25,0,2,24,24,25,0,2,25,2,19,1,0,3,18,23,2,0,3,26,21,7,1,8,3,27,27,7,0,3,28,31,27,0,3,32,22,23,0,4,38,28,2,1,12,5,44,26,27,0,6,29,21,4,1,2,34,20,26,20,0,20,32,1,28,14,2,9,0,7,8,8,1,8,0,0,1,6,8,0,1,1,1,6,8,4,1,6,8,1,1,8,6,1,3,1,2,1,6,8,2,1,6,8,3,1,6,10,2,1,7,8,1,1,8,1,3,7,8,1,2,10,2,1,8,2,2,7,8,1,8,3,2,7,8,1,2,1,8,5,1,9,0,1,6,9,0,1,7,8,8,1,8,7,1,6,8,5,1,8,4,1,6,8,8,1,5,2,9,0,5,2,1,8,5,2,8,6,8,6,1,6,8,6,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,15,97,100,100,105,116,105,118,101,95,112,111,108,105,99,121,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,14,98,117,114,110,95,112,117,98,108,105,115,104,101,114,3,99,97,112,5,99,108,97,105,109,14,99,108,97,105,109,95,97,110,100,95,107,101,101,112,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,17,99,111,109,112,97,116,105,98,108,101,95,112,111,108,105,99,121,6,100,101,108,101,116,101,15,100,101,112,95,111,110,108,121,95,112,111,108,105,99,121,6,100,105,103,101,115,116,11,102,114,111,109,95,109,111,100,117,108,101,12,102,114,111,109,95,112,97,99,107,97,103,101,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,14,109,97,107,101,95,105,109,109,117,116,97,98,108,101,11,109,111,100,117,108,101,95,110,97,109,101,3,110,101,119,6,111,98,106,101,99,116,22,111,110,108,121,95,97,100,100,105,116,105,118,101,95,117,112,103,114,97,100,101,115,17,111,110,108,121,95,100,101,112,95,117,112,103,114,97,100,101,115,7,112,97,99,107,97,103,101,6,112,111,108,105,99,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,16,112,117,98,108,105,115,104,101,100,95,109,111,100,117,108,101,17,112,117,98,108,105,115,104,101,100,95,112,97,99,107,97,103,101,11,114,101,99,101,105,112,116,95,99,97,112,15,114,101,99,101,105,112,116,95,112,97,99,107,97,103,101,8,114,101,115,116,114,105,99,116,6,115,101,110,100,101,114,13,116,105,99,107,101,116,95,100,105,103,101,115,116,14,116,105,99,107,101,116,95,112,97,99,107,97,103,101,13,116,105,99,107,101,116,95,112,111,108,105,99,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,5,116,121,112,101,115,15,117,112,103,114,97,100,101,95,112,97,99,107,97,103,101,14,117,112,103,114,97,100,101,95,112,111,108,105,99,121,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,2,1,0,2,1,128,2,1,192,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,26,8,7,36,8,4,31,8,4,1,2,4,26,8,7,36,8,6,54,3,37,2,2,2,4,13,8,6,36,8,6,37,2,20,10,2,3,2,2,13,8,6,36,8,6,0,1,0,0,19,18,14,0,56,0,4,4,5,8,11,1,1,7,0,39,56,1,12,2,11,1,17,31,14,2,17,24,14,2,17,25,18,0,2,1,1,0,0,2,8,11,0,10,1,56,2,11,1,46,17,33,56,3,2,2,1,0,0,2,6,11,0,19,0,1,1,17,27,2,3,1,0,0,19,9,56,1,12,1,14,1,17,24,11,0,16,0,20,33,2,4,1,0,0,29,23,56,1,12,2,14,2,17,24,10,0,16,0,20,33,4,17,14,2,17,25,11,0,16,1,20,33,12,1,5,21,11,0,1,9,12,1,11,1,2,5,1,0,0,2,3,11,0,16,1,2,6,1,0,0,2,3,11,0,16,0,2,7,1,0,0,2,4,11,0,16,2,20,2,8,1,0,0,2,4,11,0,16,3,20,2,9,1,0,0,2,4,11,0,16,4,20,2,10,1,0,0,2,4,11,0,16,5,20,2,11,1,0,0,2,4,11,0,16,6,20,2,12,1,0,0,2,4,11,0,16,7,20,2,13,1,0,0,2,4,11,0,16,8,20,2,14,1,0,0,2,3,11,0,16,9,2,15,1,0,0,2,2,7,5,2,16,1,0,0,2,2,7,6,2,17,1,0,0,2,2,7,7,2,18,1,4,0,2,4,11,0,7,6,17,23,2,19,1,4,0,2,4,11,0,7,7,17,23,2,20,1,4,0,2,7,11,0,19,1,1,1,1,17,27,2,21,1,0,0,30,41,7,8,17,29,12,3,10,0,16,2,20,10,3,34,4,10,5,14,11,0,1,7,2,39,10,1,10,0,16,4,20,38,4,21,5,25,11,0,1,7,1,39,10,0,16,2,20,12,4,11,3,10,0,15,2,21,11,0,46,56,4,11,4,11,1,11,2,18,2,2,22,1,0,0,30,39,11,1,19,3,12,3,12,2,10,0,46,56,4,11,2,33,4,11,5,15,11,0,1,7,4,39,10,0,16,2,17,30,7,8,33,4,22,5,26,11,0,1,7,3,39,11,3,10,0,15,2,21,10,0,16,3,20,6,1,0,0,0,0,0,0,0,22,11,0,15,3,21,2,23,0,0,0,2,16,10,0,16,4,20,10,1,37,4,7,5,11,11,0,1,7,1,39,11,1,11,0,15,4,21,2,0,1,0,2,1,1,1,2,1,3,2,1,2,2,3,0,3,1,2,3,0],"pay":[161,28,235,11,6,0,0,0,9,1,0,8,2,8,10,3,18,77,4,95,14,5,109,126,7,235,1,173,1,8,152,3,32,6,184,3,10,12,194,3,214,2,0,9,0,2,0,15,0,16,1,0,12,1,0,1,3,1,2,0,0,8,0,1,1,0,0,12,2,1,1,0,0,14,3,1,1,0,0,13,4,1,1,0,0,3,2,1,1,0,0,5,5,1,1,0,0,6,6,1,1,0,0,7,7,1,1,0,1,4,2,16,1,0,1,5,5,1,1,0,1,12,2,10,1,0,2,10,11,1,1,12,3,11,8,9,0,11,10,10,12,0,12,1,12,8,12,9,12,6,12,2,11,0,1,9,0,6,8,1,0,3,7,11,0,1,9,0,3,7,8,1,3,7,11,0,1,9,0,10,3,7,8,1,4,7,11,0,1,9,0,3,5,7,8,1,2,7,11,0,1,9,0,11,0,1,9,0,2,7,11,0,1,9,0,10,11,0,1,9,0,2,10,11,0,1,9,0,5,1,6,8,1,1,5,1,11,0,1,9,0,2,9,0,5,1,9,0,2,3,3,1,3,3,3,3,10,11,0,1,9,0,1,10,11,0,1,9,0,3,11,0,1,9,0,3,3,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,15,100,105,118,105,100,101,95,97,110,100,95,107,101,101,112,13,100,105,118,105,100,101,95,105,110,116,111,95,110,4,106,111,105,110,8,106,111,105,110,95,118,101,99,21,106,111,105,110,95,118,101,99,95,97,110,100,95,116,114,97,110,115,102,101,114,4,107,101,101,112,3,112,97,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,18,115,112,108,105,116,95,97,110,100,95,116,114,97,110,115,102,101,114,9,115,112,108,105,116,95,118,101,99,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,5,11,0,11,1,17,12,56,0,2,1,1,4,0,1,8,11,0,11,1,10,2,56,1,11,2,46,56,2,2,2,1,4,0,13,27,6,0,0,0,0,0,0,0,0,14,1,65,14,12,4,12,3,10,3,10,4,35,4,22,5,10,10,0,14,1,10,3,66,14,20,10,2,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,2,1,2,3,1,4,0,1,7,11,0,11,1,11,3,56,1,11,2,56,0,2,4,1,4,0,15,31,11,0,11,1,10,2,56,4,12,5,6,0,0,0,0,0,0,0,0,14,5,65,10,12,4,12,3,10,3,10,4,35,4,26,5,15,13,5,69,10,10,2,46,17,12,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,10,11,2,1,11,5,70,10,0,0,0,0,0,0,0,0,2,5,1,4,0,1,4,11,0,11,1,56,5,2,6,1,4,0,17,26,6,0,0,0,0,0,0,0,0,14,1,65,10,12,4,12,3,10,3,10,4,35,4,21,5,10,13,1,69,10,12,2,10,0,11,2,56,5,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,7,1,4,0,10,18,14,0,65,10,6,0,0,0,0,0,0,0,0,36,4,6,5,8,7,0,39,13,0,69,10,12,2,13,2,11,0,56,6,11,2,11,1,56,0,2,0],"priority_queue":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,12,3,16,60,4,76,10,5,86,167,1,7,253,1,184,1,8,181,3,64,6,245,3,14,10,131,4,18,11,149,4,4,12,153,4,243,5,13,140,10,4,14,144,10,4,0,11,1,16,0,1,6,1,2,0,0,0,6,1,2,0,0,6,0,1,1,2,0,8,2,3,1,2,0,4,4,5,1,2,0,7,3,6,1,2,0,2,7,0,1,2,0,13,8,5,1,2,0,5,9,5,1,2,0,9,10,11,1,2,1,12,15,13,1,0,1,14,15,13,1,0,6,13,9,6,5,13,8,16,8,13,1,10,11,1,1,9,0,1,11,0,1,9,0,1,7,11,0,1,9,0,2,3,9,0,3,7,11,0,1,9,0,3,9,0,0,1,11,1,1,9,0,2,10,3,10,9,0,2,7,10,11,1,1,9,0,3,3,7,10,11,1,1,9,0,3,3,1,6,11,0,1,9,0,1,10,3,2,3,3,1,9,0,3,3,3,9,0,2,7,10,9,0,3,1,3,5,3,3,3,10,11,1,1,9,0,9,0,5,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,13,7,10,11,1,1,9,0,1,3,7,10,11,1,1,9,0,3,1,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,3,3,2,3,10,3,5,69,110,116,114,121,13,80,114,105,111,114,105,116,121,81,117,101,117,101,14,99,114,101,97,116,101,95,101,110,116,114,105,101,115,7,101,110,116,114,105,101,115,6,105,110,115,101,114,116,21,109,97,120,95,104,101,97,112,105,102,121,95,114,101,99,117,114,115,105,118,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,7,112,111,112,95,109,97,120,10,112,114,105,111,114,105,116,105,101,115,8,112,114,105,111,114,105,116,121,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,6,114,101,109,111,118,101,22,114,101,115,116,111,114,101,95,104,101,97,112,95,114,101,99,117,114,115,105,118,101,11,115,119,97,112,95,114,101,109,111,118,101,5,118,97,108,117,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,10,3,1,0,0,2,1,3,10,11,1,1,9,0,1,2,2,10,3,15,9,0,0,13,1,13,0,1,0,0,12,24,14,0,65,6,12,2,10,2,6,2,0,0,0,0,0,0,0,26,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,21,5,12,11,1,6,1,0,0,0,0,0,0,0,23,12,1,13,0,10,2,10,1,56,0,5,7,11,0,57,0,2,1,1,0,0,14,30,10,0,55,0,65,6,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,10,0,54,0,6,0,0,0,0,0,0,0,0,56,1,58,1,12,3,12,2,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,6,0,0,0,0,0,0,0,0,56,0,11,2,11,3,2,2,1,0,0,16,17,10,0,54,0,11,1,11,2,57,1,68,6,10,0,55,0,65,6,6,1,0,0,0,0,0,0,0,23,12,3,11,0,54,0,11,3,56,2,2,3,1,0,0,5,4,11,0,11,1,57,1,2,4,1,0,0,17,40,14,0,65,16,12,3,14,1,65,13,10,3,33,4,9,5,11,6,0,0,0,0,0,0,0,0,39,64,6,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,38,5,20,13,0,6,0,0,0,0,0,0,0,0,56,3,12,4,13,1,6,0,0,0,0,0,0,0,0,56,4,12,6,13,5,11,4,11,6,57,1,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,5,2,5,0,0,0,18,46,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,1,6,1,0,0,0,0,0,0,0,23,6,2,0,0,0,0,0,0,0,26,12,6,10,0,10,1,12,3,12,2,10,0,10,6,12,5,12,4,11,2,46,11,3,66,6,55,1,20,11,4,46,11,5,66,6,55,1,20,36,4,43,10,0,11,1,10,6,71,6,11,0,11,6,56,2,5,45,11,0,1,2,6,0,0,0,19,110,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,2,10,1,35,4,12,5,16,11,0,1,6,1,0,0,0,0,0,0,0,39,10,2,6,2,0,0,0,0,0,0,0,24,6,1,0,0,0,0,0,0,0,22,12,13,10,13,6,1,0,0,0,0,0,0,0,22,12,15,10,2,12,14,10,13,10,1,35,4,55,10,0,10,13,12,5,12,3,10,0,10,14,12,7,12,6,11,3,46,11,5,66,6,55,1,20,11,6,46,11,7,66,6,55,1,20,36,12,8,5,57,9,12,8,11,8,4,61,11,13,12,14,10,15,10,1,35,4,88,10,0,10,15,12,10,12,9,10,0,10,14,12,12,12,11,11,9,46,11,10,66,6,55,1,20,11,11,46,11,12,66,6,55,1,20,36,12,4,5,90,9,12,4,11,4,4,94,11,15,12,14,10,14,10,2,34,4,107,10,0,10,14,11,2,71,6,11,0,11,1,11,14,56,0,5,109,11,0,1,2,7,1,0,0,20,28,7,1,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,0,55,0,65,6,35,4,24,5,11,13,2,10,0,55,0,10,1,66,6,55,1,20,68,16,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,4,11,0,1,11,2,2,0,0,1,0,0,13,1,13,0],"prover":[161,28,235,11,6,0,0,0,4,1,0,2,7,2,7,8,9,32,6,41,30,0,0,6,112,114,111,118,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0],"sui":[161,28,235,11,6,0,0,0,10,1,0,14,2,14,48,3,62,62,4,124,14,5,138,1,133,1,7,143,2,129,2,8,144,4,64,6,208,4,102,10,182,5,5,12,187,5,109,0,22,1,18,0,9,0,10,0,23,0,25,0,26,0,4,2,0,1,3,7,1,0,0,2,0,4,1,0,1,2,5,4,1,0,1,3,1,12,1,0,1,3,2,12,1,0,1,3,6,12,1,0,1,5,7,2,0,6,8,7,0,0,16,0,1,0,0,23,2,3,0,1,17,3,9,1,0,2,12,16,7,1,0,2,15,17,18,1,0,3,11,11,12,1,2,3,24,15,16,1,0,4,19,14,3,1,12,4,20,20,3,1,12,5,14,5,7,0,5,21,5,6,0,2,8,5,10,7,13,6,10,4,10,3,10,8,19,1,7,8,7,1,11,2,1,8,0,2,11,4,1,8,0,5,0,4,11,5,1,8,0,11,3,1,8,0,11,2,1,8,0,11,6,1,8,0,1,6,8,7,1,5,1,3,1,8,8,1,11,1,1,9,0,1,8,0,7,9,0,2,10,2,10,2,10,2,11,1,1,8,8,7,8,7,2,11,6,1,9,0,11,5,1,9,0,1,11,5,1,8,0,1,9,0,1,11,6,1,9,0,1,11,3,1,9,0,2,7,11,3,1,9,0,3,1,11,2,1,9,0,1,11,4,1,8,0,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,114,108,7,98,97,108,97,110,99,101,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,11,100,117,109,109,121,95,102,105,101,108,100,5,101,112,111,99,104,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,3,115,117,105,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,228,11,84,2,0,0,0,3,8,0,0,232,137,4,35,199,138,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,2,4,3,83,85,73,10,2,4,3,83,117,105,10,2,1,0,0,2,1,13,1,0,0,0,0,4,47,10,0,46,17,10,7,5,33,4,7,5,11,11,0,1,7,1,39,10,0,46,17,9,6,0,0,0,0,0,0,0,0,33,4,18,5,22,11,0,1,7,0,39,9,18,0,49,9,7,6,7,7,7,8,56,0,11,0,56,1,12,1,12,4,11,1,56,2,11,4,56,3,12,2,13,2,7,4,56,4,12,3,11,2,56,5,1,11,3,2,1,1,4,0,3,4,11,0,11,1,56,6,2,0],"table":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,16,3,24,115,4,139,1,10,5,149,1,104,7,253,1,167,1,8,164,3,32,6,196,3,10,10,206,3,8,11,214,3,2,12,216,3,229,1,13,189,5,4,14,193,5,4,0,19,0,10,0,16,0,20,0,0,12,2,7,1,4,1,2,2,4,0,3,1,2,0,0,15,0,1,2,7,4,0,3,2,3,2,7,4,0,4,4,5,2,7,4,0,5,6,7,2,7,4,0,17,6,8,2,7,4,0,6,4,9,2,7,4,0,14,10,11,2,7,4,0,13,10,9,2,7,4,0,8,1,3,2,7,4,0,9,1,3,2,7,6,1,3,14,3,2,7,4,1,4,15,5,2,7,4,1,5,16,7,2,7,4,1,11,15,9,2,7,4,1,17,16,8,2,7,4,2,7,12,3,0,2,15,0,12,0,10,13,11,13,12,13,14,13,13,13,1,7,8,2,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,2,8,1,3,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,1,18,3,0,13,0,1,0,0,3,5,11,0,17,16,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,17,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,15,2,9,1,0,0,3,5,11,0,58,0,1,17,15,2,0,0,0,1,0,13,1,13,0],"table_vec":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,18,3,24,103,4,127,20,5,147,1,138,1,7,157,2,159,1,8,188,3,32,6,220,3,20,10,240,3,10,11,250,3,2,12,252,3,245,1,13,241,5,2,14,243,5,2,0,17,0,16,0,18,0,1,4,1,4,1,1,0,12,2,7,1,4,1,2,2,2,0,0,8,0,1,1,4,0,15,2,1,1,4,0,10,3,4,1,4,0,9,3,5,1,4,0,4,6,7,1,4,0,13,8,9,1,4,0,5,10,11,1,4,0,12,12,13,1,4,0,7,1,9,1,4,1,3,19,9,2,7,4,1,4,17,18,2,7,4,1,5,20,21,2,7,4,1,7,15,9,2,7,4,1,10,16,4,2,7,4,1,11,0,15,2,7,4,1,14,20,22,2,7,4,14,14,0,13,5,13,13,14,2,13,10,14,9,14,11,14,15,14,12,14,1,7,8,2,1,11,0,1,9,0,2,9,0,7,8,2,1,6,11,0,1,9,0,1,3,1,1,2,6,11,0,1,9,0,3,1,6,9,0,2,7,11,0,1,9,0,9,0,0,2,7,11,0,1,9,0,3,1,7,9,0,1,7,11,0,1,9,0,1,9,0,2,3,9,0,1,11,1,2,9,0,9,1,1,6,11,1,2,9,0,9,1,2,6,11,1,2,9,0,9,1,9,0,1,6,9,1,3,7,11,1,2,9,0,9,1,9,0,9,1,2,7,11,1,2,9,0,9,1,9,0,1,7,9,1,1,9,1,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,5,101,109,112,116,121,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,6,11,1,2,3,9,0,0,13,0,1,0,0,9,4,11,0,56,0,57,0,2,1,1,0,0,1,8,11,1,56,1,12,2,13,2,11,0,56,2,11,2,2,2,1,0,0,9,4,11,0,55,0,56,3,2,3,1,0,0,9,5,11,0,56,4,6,0,0,0,0,0,0,0,0,33,2,4,1,0,0,9,15,10,0,56,4,10,1,36,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,5,2,5,1,0,0,4,10,10,0,46,56,4,12,2,11,0,54,0,11,2,11,1,56,6,2,6,1,0,0,9,16,10,0,46,56,4,10,1,36,4,7,5,11,11,0,1,7,0,39,11,0,54,0,11,1,56,7,2,7,1,0,0,4,20,10,0,46,56,4,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,56,8,2,8,1,0,0,9,12,14,0,56,4,6,0,0,0,0,0,0,0,0,33,4,6,5,8,7,1,39,11,0,58,0,56,9,2,0,0,0,13,0],"transfer":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,54,4,56,6,5,62,8,7,70,144,1,8,214,1,32,6,246,1,10,12,128,2,82,0,7,0,7,0,1,1,8,0,4,0,1,1,12,0,0,2,1,1,8,0,2,2,1,1,12,0,5,2,1,1,8,0,3,2,1,1,12,0,1,2,1,1,8,0,6,2,1,1,8,0,8,0,1,1,8,8,2,6,2,7,2,2,9,0,5,0,1,9,0,13,102,114,101,101,122,101,95,111,98,106,101,99,116,18,102,114,101,101,122,101,95,111,98,106,101,99,116,95,105,109,112,108,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,17,115,104,97,114,101,95,111,98,106,101,99,116,95,105,109,112,108,8,116,114,97,110,115,102,101,114,13,116,114,97,110,115,102,101,114,95,105,109,112,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,56,0,2,1,1,0,0,1,4,11,0,11,1,56,0,2,2,1,0,0,1,3,11,0,56,1,2,3,1,0,0,1,3,11,0,56,1,2,4,1,0,0,1,3,11,0,56,2,2,5,1,0,0,1,3,11,0,56,2,2,6,3,2,0,7,3,2,0,8,3,2,0,0],"transfer_policy":[161,28,235,11,6,0,0,0,13,1,0,24,2,24,78,3,102,255,1,4,229,2,44,5,145,3,176,3,7,193,6,229,4,8,166,11,64,6,230,11,60,10,162,12,55,11,217,12,10,12,227,12,252,4,13,223,17,16,14,239,17,16,0,59,1,47,1,61,0,19,0,21,0,28,0,31,0,46,0,48,0,57,0,60,0,66,0,10,0,1,0,1,0,7,12,1,0,1,0,8,12,1,0,1,0,9,3,1,0,1,0,5,7,1,2,1,1,3,7,1,0,0,2,12,7,0,3,0,4,1,0,1,4,1,12,1,0,1,7,2,7,0,7,13,4,0,8,4,12,0,9,6,2,0,10,11,2,0,11,14,7,1,3,0,0,45,0,1,1,0,0,44,2,3,1,0,0,67,4,5,1,0,0,25,6,5,1,0,0,22,7,0,1,0,0,17,8,9,3,0,2,6,0,37,10,11,3,0,2,6,0,18,12,9,2,0,2,0,16,13,9,2,0,2,0,38,14,15,2,0,2,0,54,16,9,3,0,2,6,0,62,14,17,1,0,0,63,16,18,1,0,0,55,14,19,1,0,0,43,20,21,1,0,0,49,20,22,1,0,0,33,20,21,1,0,1,26,37,25,1,0,1,42,36,15,1,0,2,36,9,23,1,0,3,65,38,22,1,0,3,68,9,32,1,0,4,34,42,40,1,0,4,51,54,9,1,0,4,58,39,40,1,0,5,15,50,9,2,7,4,5,20,52,53,2,7,4,5,32,52,15,1,7,5,53,57,48,2,7,4,6,29,25,9,1,3,7,24,29,9,0,7,39,35,21,1,8,7,44,28,29,0,7,64,17,21,0,8,35,27,15,1,0,11,23,46,15,1,3,11,30,9,24,1,3,11,40,51,9,1,3,11,41,24,44,1,3,11,53,58,9,1,3,11,56,45,22,1,3,36,23,34,25,29,30,21,31,31,34,18,22,17,22,20,31,24,31,22,31,38,23,40,23,35,23,9,47,25,49,19,48,37,23,26,49,23,31,27,55,28,49,39,23,3,8,9,3,8,9,1,11,0,1,9,0,2,6,8,11,7,8,13,2,11,1,1,9,0,11,2,1,9,0,4,7,11,1,1,9,0,6,11,2,1,9,0,11,5,1,3,7,8,13,1,11,8,1,8,12,3,11,1,1,9,0,11,2,1,9,0,7,8,13,2,6,11,1,1,9,0,11,0,1,9,0,4,9,1,7,11,1,1,9,0,6,11,2,1,9,0,9,2,0,2,9,1,6,11,1,1,9,0,1,6,9,2,3,9,1,7,11,1,1,9,0,11,8,1,8,12,2,9,1,7,11,0,1,9,0,1,6,11,1,1,9,0,1,1,2,7,11,1,1,9,0,6,11,2,1,9,0,1,6,8,10,1,7,8,10,1,6,11,14,1,8,6,1,6,11,0,1,9,0,1,8,9,1,3,1,8,6,1,11,14,1,9,0,1,9,0,5,8,10,11,14,1,8,6,11,7,1,8,12,8,10,8,9,1,6,8,11,1,7,8,13,1,8,10,1,11,3,1,9,0,1,8,12,1,11,7,1,9,0,3,3,3,3,1,11,1,1,9,0,1,6,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,1,6,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,13,1,11,8,1,9,0,2,11,7,1,8,12,8,10,2,11,7,1,9,0,7,8,13,7,10,8,6,8,9,8,9,3,11,14,1,8,6,8,6,3,1,10,9,0,1,6,11,14,1,9,0,2,6,11,14,1,9,0,6,9,0,2,9,0,9,1,1,9,1,2,11,4,1,9,1,9,2,3,7,8,10,9,0,9,1,2,7,11,14,1,9,0,9,0,2,6,8,10,9,0,1,6,9,1,2,7,11,7,1,9,0,11,8,1,9,0,1,11,4,1,9,1,2,8,6,7,11,14,1,8,6,2,7,8,10,9,0,2,7,11,14,1,9,0,6,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,9,80,117,98,108,105,115,104,101,114,7,82,117,108,101,75,101,121,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,17,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,97,112,21,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,114,101,97,116,101,100,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,86,101,99,83,101,116,3,97,100,100,11,97,100,100,95,114,101,99,101,105,112,116,8,97,100,100,95,114,117,108,101,14,97,100,100,95,116,111,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,4,99,111,105,110,15,99,111,110,102,105,114,109,95,114,101,113,117,101,115,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,20,100,101,115,116,114,111,121,95,97,110,100,95,119,105,116,104,100,114,97,119,12,100,101,115,116,114,111,121,95,115,111,109,101,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,7,101,120,105,115,116,115,95,4,102,114,111,109,12,102,114,111,109,95,98,97,108,97,110,99,101,12,102,114,111,109,95,112,97,99,107,97,103,101,3,103,101,116,8,103,101,116,95,114,117,108,101,8,104,97,115,95,114,117,108,101,2,105,100,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,7,105,115,95,115,111,109,101,4,105,116,101,109,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,4,112,97,105,100,9,112,111,108,105,99,121,95,105,100,3,112,117,116,8,114,101,99,101,105,112,116,115,6,114,101,109,111,118,101,11,114,101,109,111,118,101,95,114,117,108,101,5,114,117,108,101,115,4,115,105,122,101,3,115,117,105,4,116,97,107,101,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,3,117,105,100,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,7,118,101,99,95,115,101,116,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,4,43,8,9,49,3,33,8,9,52,11,14,1,8,6,1,2,3,39,8,10,19,11,7,1,8,12,55,11,14,1,8,6,2,2,2,39,8,10,50,8,9,3,2,1,39,8,9,4,2,1,27,1,0,25,3,25,1,25,2,25,4,48,0,1,0,0,9,6,11,0,11,1,11,2,56,0,57,0,2,1,1,0,0,26,32,11,0,56,1,4,4,5,8,11,1,1,6,0,0,0,0,0,0,0,0,39,10,1,17,32,12,5,14,5,17,33,12,6,10,6,57,1,56,2,11,5,12,2,56,0,12,3,56,3,12,4,11,2,11,4,11,3,57,2,11,1,17,32,11,6,57,3,2,2,1,0,0,33,49,10,0,46,56,4,11,1,55,0,20,33,4,9,5,15,11,0,1,11,3,1,7,4,39,14,2,56,5,4,37,11,2,56,6,12,6,10,6,10,0,55,1,56,7,37,4,28,5,34,11,0,1,11,3,1,7,5,39,11,6,12,4,5,41,10,0,55,1,56,7,12,4,11,4,12,5,11,0,54,1,11,5,11,3,56,8,2,3,1,0,0,41,27,14,0,56,4,14,1,55,0,20,33,4,8,5,12,11,2,1,7,4,39,11,1,58,3,1,12,4,11,0,58,2,1,12,3,17,30,11,4,17,30,11,3,11,2,56,9,2,4,1,0,0,43,52,11,1,58,0,12,6,12,3,12,5,12,4,11,6,56,10,12,2,14,2,65,23,12,8,10,8,10,0,55,2,56,11,33,4,19,5,23,11,0,1,7,0,39,10,8,6,0,0,0,0,0,0,0,0,36,4,46,5,28,13,2,69,23,12,7,10,0,55,2,14,7,56,12,4,37,5,41,11,0,1,7,1,39,11,8,6,1,0,0,0,0,0,0,0,23,12,8,5,23,11,0,1,11,4,11,5,11,3,2,5,1,0,0,9,34,10,1,46,56,4,11,2,55,0,20,33,4,9,5,13,11,1,1,7,4,39,10,1,46,56,13,32,4,19,5,23,11,1,1,7,3,39,10,1,54,3,9,57,4,11,3,56,14,11,1,54,2,56,15,56,16,2,6,1,0,0,9,6,11,1,55,3,9,57,4,56,17,2,7,1,0,0,9,14,10,1,46,56,13,4,5,5,9,11,1,1,7,2,39,11,1,54,1,11,2,56,18,2,8,1,0,0,9,5,11,1,54,4,56,15,56,16,2,9,1,0,0,9,6,11,0,55,3,9,57,4,56,19,2,10,1,0,0,56,28,10,0,46,56,4,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,10,0,54,3,9,57,4,56,20,1,11,0,54,2,12,3,56,15,12,2,11,3,14,2,56,21,2,11,1,0,0,9,3,11,0,55,3,2,12,1,0,0,9,16,10,0,46,56,4,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,11,0,54,3,2,13,1,0,0,9,3,11,0,55,2,2,14,1,0,0,9,4,11,0,55,5,20,2,15,1,0,0,9,4,11,0,55,6,20,2,16,1,0,0,9,4,11,0,55,7,20,2,2,1,1,1,1,2,1,0,0,3,0,0,0,1,0,2,0,25,1,25,2,25,3,25,4,25,5,25,6,25,7,25,0],"tx_context":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,24,7,65,111,8,176,1,32,6,208,1,20,10,228,1,14,12,242,1,107,13,221,2,10,0,8,0,0,2,0,0,7,0,1,0,0,2,0,2,0,0,3,0,3,0,0,4,0,3,0,0,5,4,1,0,0,6,0,3,0,0,1,5,1,0,1,6,8,0,1,5,1,6,10,2,1,3,1,7,8,0,2,10,2,3,0,2,5,3,9,84,120,67,111,110,116,101,120,116,9,100,101,114,105,118,101,95,105,100,6,100,105,103,101,115,116,5,101,112,111,99,104,18,101,112,111,99,104,95,116,105,109,101,115,116,97,109,112,95,109,115,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,11,105,100,115,95,99,114,101,97,116,101,100,6,115,101,110,100,101,114,10,116,120,95,99,111,110,116,101,120,116,7,116,120,95,104,97,115,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,32,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,5,7,5,9,10,2,3,3,4,3,6,3,0,1,0,0,6,4,11,0,16,0,20,2,1,1,0,0,6,3,11,0,16,1,2,2,1,0,0,6,4,11,0,16,2,20,2,3,1,0,0,6,4,11,0,16,3,20,2,4,1,0,0,7,18,10,0,16,4,20,12,2,10,0,16,1,20,10,2,17,6,12,1,11,2,6,1,0,0,0,0,0,0,0,22,11,0,15,4,21,11,1,2,5,0,0,0,6,4,11,0,16,4,20,2,6,0,2,0,0,0,0,1,0,2,0,3,0,4,0],"types":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,6,7,14,26,8,40,32,12,72,4,0,1,0,0,0,1,1,2,1,6,9,0,1,1,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,5,116,121,112,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"url":[161,28,235,11,6,0,0,0,9,1,0,4,2,4,8,3,12,25,5,37,20,7,57,78,8,135,1,64,10,199,1,6,12,205,1,50,13,255,1,2,0,8,1,2,0,1,7,0,1,0,7,0,0,4,0,1,0,0,5,2,1,0,0,3,3,0,0,0,7,4,5,0,1,6,2,0,0,1,8,1,1,8,0,1,10,2,1,6,8,0,2,7,8,0,8,1,0,6,83,116,114,105,110,103,3,85,114,108,5,97,115,99,105,105,9,105,110,110,101,114,95,117,114,108,10,110,101,119,95,117,110,115,97,102,101,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,6,115,116,114,105,110,103,6,117,112,100,97,116,101,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,8,8,1,0,1,0,0,5,3,11,0,18,0,2,1,1,0,0,5,4,11,0,17,4,18,0,2,2,1,0,0,5,4,11,0,16,0,20,2,3,1,0,0,5,5,11,1,11,0,15,0,21,2,0,0,0],"vec_map":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,22,3,28,168,1,4,196,1,28,5,224,1,254,1,7,222,3,153,2,8,247,5,64,6,183,6,50,10,233,6,21,11,254,6,4,12,130,7,235,5,13,237,12,6,14,243,12,6,0,30,1,21,1,31,0,2,7,2,1,0,0,0,0,0,7,2,1,0,0,0,1,1,7,1,0,0,0,7,0,1,2,1,0,0,14,2,0,2,1,0,0,23,3,4,2,1,0,0,22,5,4,2,1,0,0,13,3,6,2,1,0,0,8,7,8,2,1,0,0,28,7,9,2,1,1,0,3,7,10,2,1,0,0,26,11,12,2,1,0,0,16,11,10,2,1,0,0,5,1,0,2,1,0,0,15,1,13,2,1,0,0,19,11,14,2,1,0,0,12,7,15,2,1,0,0,11,7,12,2,1,0,0,9,16,17,2,1,0,0,10,18,19,2,1,0,0,24,18,4,2,1,0,1,6,27,24,1,0,1,17,28,10,1,0,1,20,0,27,1,0,1,27,24,27,1,0,2,16,25,10,1,0,2,23,23,24,1,0,2,25,31,0,1,0,7,4,14,4,23,20,22,20,5,4,21,26,20,26,13,4,19,12,8,4,24,20,21,12,20,12,18,12,0,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,2,7,11,0,2,9,0,9,1,6,9,0,2,9,0,9,1,1,7,11,0,2,9,0,9,1,1,7,9,1,2,6,11,0,2,9,0,9,1,6,9,0,1,6,9,1,1,11,2,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,2,10,9,0,10,9,1,1,10,9,0,1,11,2,1,3,2,6,11,0,2,9,0,9,1,3,2,6,9,0,6,9,1,2,7,11,0,2,9,0,9,1,3,2,6,9,0,7,9,1,1,11,1,2,9,0,9,1,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,9,0,1,6,10,9,0,1,9,1,1,11,2,1,9,0,1,6,11,2,1,9,0,1,10,11,1,2,9,0,9,1,7,10,11,1,2,9,0,9,1,3,9,0,10,9,0,3,9,1,10,9,1,1,7,10,9,0,4,6,11,1,2,9,0,9,1,3,10,9,0,3,2,3,3,1,6,11,1,2,9,0,9,1,1,7,11,1,2,9,0,9,1,5,69,110,116,114,121,6,79,112,116,105,111,110,6,86,101,99,77,97,112,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,3,103,101,116,16,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,20,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,95,109,117,116,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,7,103,101,116,95,109,117,116,6,105,110,115,101,114,116,16,105,110,116,111,95,107,101,121,115,95,118,97,108,117,101,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,3,107,101,121,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,3,112,111,112,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,101,110,116,114,121,95,98,121,95,105,100,120,7,114,101,118,101,114,115,101,4,115,105,122,101,4,115,111,109,101,7,116,114,121,95,103,101,116,5,118,97,108,117,101,7,118,101,99,95,109,97,112,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,1,4,10,11,1,2,9,0,9,1,1,2,2,18,9,0,29,9,1,0,4,1,4,0,1,0,0,0,3,64,20,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,21,20,10,0,14,1,12,3,46,11,3,56,0,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,11,2,57,1,68,20,2,2,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,56,2,58,1,2,3,1,0,0,0,15,10,0,55,0,56,3,32,4,6,5,10,11,0,1,7,4,39,11,0,54,0,69,20,58,1,2,4,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,67,20,54,1,2,5,1,0,0,12,10,10,0,11,1,56,1,12,2,11,0,55,0,11,2,66,20,55,1,2,6,1,0,0,9,19,10,0,10,1,56,0,4,11,11,0,11,1,56,4,20,56,5,12,2,5,17,11,0,1,11,1,1,56,6,12,2,11,2,2,7,1,0,0,15,7,11,0,11,1,56,7,12,2,14,2,56,8,2,8,1,0,0,0,4,11,0,55,0,65,20,2,9,1,0,0,0,5,11,0,56,9,6,0,0,0,0,0,0,0,0,33,2,10,1,0,0,29,12,11,0,58,0,12,1,14,1,56,3,4,7,5,9,7,2,39,11,1,70,20,0,0,0,0,0,0,0,0,2,11,1,0,0,30,40,11,0,58,0,12,1,13,1,56,10,6,0,0,0,0,0,0,0,0,12,2,14,1,65,20,12,5,64,24,0,0,0,0,0,0,0,0,12,4,64,26,0,0,0,0,0,0,0,0,12,7,10,2,10,5,35,4,35,5,19,13,1,69,20,58,1,12,6,12,3,13,4,11,3,68,24,13,7,11,6,68,26,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,14,11,1,70,20,0,0,0,0,0,0,0,0,11,4,11,7,2,12,1,0,0,32,32,6,0,0,0,0,0,0,0,0,12,2,10,0,55,0,65,20,12,4,64,24,0,0,0,0,0,0,0,0,12,3,10,2,10,4,35,4,28,5,13,10,0,55,0,10,2,66,20,12,1,13,3,11,1,55,2,20,68,24,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,8,11,0,1,11,3,2,13,1,0,0,33,36,6,0,0,0,0,0,0,0,0,12,2,10,0,56,9,12,3,10,2,10,3,35,4,30,5,10,10,0,55,0,10,2,66,20,55,2,10,1,33,4,25,11,0,1,11,1,1,11,2,56,11,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,12,2,14,1,0,0,15,13,11,0,11,1,56,7,12,2,14,2,56,8,4,8,5,10,7,1,39,11,2,56,13,2,15,1,0,0,34,20,10,1,10,0,56,9,35,4,6,5,10,11,0,1,7,3,39,11,0,55,0,11,1,66,20,12,2,10,2,55,2,11,2,55,1,2,16,1,0,0,35,21,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,67,20,12,2,10,2,55,2,11,2,54,1,2,17,1,0,0,0,17,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,56,2,58,1,2,0,0,1,1,1,0,0,4,1,4,2,4,0],"vec_set":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,12,3,18,102,4,120,20,5,140,1,95,7,235,1,164,1,8,143,3,64,6,207,3,20,10,227,3,7,11,234,3,2,12,236,3,156,2,13,136,6,2,14,138,6,2,0,19,1,14,1,20,0,1,7,1,3,0,1,0,7,1,0,0,0,5,0,1,1,3,0,16,2,1,1,3,0,8,3,0,1,3,0,15,4,0,1,3,0,2,5,6,1,3,0,17,7,8,1,3,0,10,7,6,1,3,0,9,1,9,1,3,0,12,7,10,1,3,0,7,5,11,1,3,0,6,5,8,1,3,1,4,17,2,1,0,1,11,15,6,1,0,1,13,0,17,1,0,1,18,2,17,1,0,2,15,14,2,1,0,2,16,2,9,1,0,16,2,4,2,10,2,15,2,9,2,12,8,5,2,14,8,13,8,11,8,0,1,11,0,1,9,0,1,9,0,2,7,11,0,1,9,0,9,0,2,7,11,0,1,9,0,6,9,0,2,6,11,0,1,9,0,6,9,0,1,1,1,6,11,0,1,9,0,1,3,1,10,9,0,1,6,10,9,0,1,11,1,1,3,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,6,11,1,1,9,0,2,3,3,1,11,1,1,9,0,6,79,112,116,105,111,110,6,86,101,99,83,101,116,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,4,115,105,122,101,4,115,111,109,101,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,3,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,12,18,10,0,14,1,12,2,46,11,2,56,1,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,68,2,2,3,1,0,0,13,13,10,0,11,1,12,2,46,11,2,56,2,12,3,11,0,54,0,11,3,56,3,1,2,4,1,0,0,11,7,11,0,11,1,56,4,12,2,14,2,56,5,2,5,1,0,0,0,4,11,0,55,0,65,2,2,6,1,0,0,0,5,11,0,56,6,6,0,0,0,0,0,0,0,0,33,2,7,1,0,0,0,3,11,0,58,0,2,8,1,0,0,0,3,11,0,55,0,2,9,0,0,0,16,35,6,0,0,0,0,0,0,0,0,12,2,10,0,56,6,12,3,10,2,10,3,35,4,29,5,10,10,0,55,0,10,2,66,2,10,1,33,4,24,11,0,1,11,1,1,11,2,56,7,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,8,2,10,0,0,0,11,13,11,0,11,1,56,4,12,2,14,2,56,5,4,8,5,10,7,1,39,11,2,56,9,2,0,0,0,2,0],"versioned":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,20,3,28,85,4,113,10,5,123,97,7,220,1,236,1,8,200,3,32,6,232,3,10,10,242,3,16,12,130,4,197,1,13,199,5,4,0,23,0,11,0,16,0,20,0,4,12,0,0,3,0,0,2,0,7,0,2,2,4,0,3,1,2,0,0,8,0,1,1,4,0,22,2,3,0,0,13,2,4,1,4,0,14,5,6,1,4,0,19,5,7,1,4,0,21,8,9,1,4,0,10,1,10,1,4,1,5,14,9,2,7,4,1,6,15,16,2,7,4,1,7,17,18,2,7,4,1,18,17,19,2,7,4,2,9,12,9,0,2,12,4,20,1,8,2,15,11,12,0,7,13,8,13,9,13,10,13,12,1,3,3,9,0,7,8,4,1,8,0,1,6,8,0,1,3,1,6,9,0,1,7,8,0,1,7,9,0,2,9,0,8,1,4,7,8,0,3,9,0,8,1,0,1,9,0,1,7,8,4,1,8,3,2,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,8,2,3,8,3,9,0,3,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,16,86,101,114,115,105,111,110,67,104,97,110,103,101,67,97,112,9,86,101,114,115,105,111,110,101,100,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,2,105,100,10,108,111,97,100,95,118,97,108,117,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,3,110,101,119,6,111,98,106,101,99,116,11,111,108,100,95,118,101,114,115,105,111,110,6,114,101,109,111,118,101,24,114,101,109,111,118,101,95,118,97,108,117,101,95,102,111,114,95,117,112,103,114,97,100,101,10,116,120,95,99,111,110,116,101,120,116,7,117,112,103,114,97,100,101,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,12,118,101,114,115,105,111,110,101,100,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,3,22,3,1,2,2,24,8,2,17,3,0,1,0,0,1,12,11,2,17,13,10,0,18,0,12,3,13,3,15,0,11,0,11,1,56,0,11,3,2,1,1,0,0,9,4,11,0,16,1,20,2,2,1,0,0,9,7,10,0,16,0,11,0,16,1,20,56,1,2,3,1,0,0,9,7,10,0,15,0,11,0,16,1,20,56,2,2,4,1,0,0,9,14,10,0,15,0,10,0,16,1,20,56,3,10,0,46,56,4,11,0,16,1,20,18,1,2,5,1,0,0,3,32,11,3,19,1,12,4,10,0,46,56,4,33,4,9,5,13,11,0,1,7,0,39,11,4,10,1,35,4,18,5,22,11,0,1,7,0,39,10,0,15,0,10,1,11,2,56,0,11,1,11,0,15,1,21,2,6,1,0,0,21,12,11,0,19,0,12,3,12,1,13,1,11,3,56,3,12,2,11,1,17,11,11,2,2,0,0,0,1,0]},"type_origin_table":[{"module_name":"tx_context","struct_name":"TxContext","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"ID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"UID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_field","struct_name":"Field","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bag","struct_name":"Bag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Supply","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Balance","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bcs","struct_name":"BCS","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Referent","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"clock","struct_name":"Clock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"url","struct_name":"Url","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"Coin","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CoinMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"TreasuryCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CurrencyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"VecMap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"Publisher","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeTicket","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeReceipt","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"Display","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"DisplayCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"VersionUpdated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_object_field","struct_name":"Wrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"Curve","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PreparedVerifyingKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PublicProofInputs","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"ProofPoints","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_set","struct_name":"VecSet","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"sui","struct_name":"SUI","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferRequest","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicy","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"RuleKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Kiosk","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"KioskOwnerCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"PurchaseCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Item","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Listing","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Lock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemListed","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemPurchased","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemDelisted","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"LinkedTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"Node","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_bag","struct_name":"ObjectBag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_table","struct_name":"ObjectTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"PriorityQueue","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table","struct_name":"Table","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table_vec","struct_name":"TableVec","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"Versioned","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"VersionChangeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000003","version":5,"module_map":{"genesis":[161,28,235,11,6,0,0,0,11,1,0,26,2,26,58,3,84,107,4,191,1,14,5,205,1,176,2,7,253,3,137,9,8,134,13,96,6,230,13,20,10,250,13,93,12,215,14,219,3,13,178,18,24,0,31,1,44,1,72,2,18,2,20,2,43,2,61,2,66,0,54,0,63,0,64,0,67,0,70,0,3,3,0,0,2,3,0,0,9,0,0,0,8,0,0,1,4,7,1,0,0,3,0,4,1,0,1,4,1,12,1,0,1,5,11,4,0,6,5,2,0,7,10,2,0,8,6,4,0,10,7,4,0,11,12,4,0,0,22,0,1,0,0,15,2,1,0,0,14,3,1,0,1,25,25,26,1,0,1,36,24,14,1,0,2,35,22,14,1,0,3,26,9,1,1,0,3,53,8,9,1,0,3,75,1,9,1,0,4,29,30,31,1,0,6,65,32,1,0,7,27,5,6,0,8,22,17,18,0,9,22,19,1,0,10,23,15,16,0,11,13,34,1,0,11,42,12,10,0,11,52,29,1,0,12,32,27,28,0,12,34,13,14,0,7,7,8,7,5,21,4,23,3,23,9,7,6,7,6,8,7,11,5,1,8,8,8,1,10,8,0,8,2,7,8,9,0,4,11,5,1,8,8,10,8,3,7,10,8,12,7,8,9,1,7,10,8,12,25,10,8,3,3,3,10,2,3,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,8,10,3,11,5,1,8,8,11,5,1,8,8,5,8,11,8,12,10,8,12,10,2,10,2,1,6,8,9,1,3,1,8,8,2,7,11,5,1,9,0,3,1,11,5,1,9,0,1,8,12,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,9,2,6,10,8,12,6,8,12,1,1,8,3,3,3,3,3,3,3,7,8,9,1,8,11,5,11,5,1,8,8,3,3,13,7,8,9,1,8,10,8,8,7,10,8,12,11,5,1,8,8,3,3,8,11,8,10,7,8,9,5,11,5,1,8,8,3,5,11,4,1,5,5,1,8,3,1,6,10,9,0,1,5,1,6,11,4,1,9,0,1,11,4,1,9,0,1,9,0,2,7,10,8,12,5,1,7,8,12,4,7,8,12,11,5,1,8,8,5,7,8,9,2,11,5,1,9,0,7,8,9,1,11,6,1,9,0,2,11,6,1,8,8,5,2,3,3,2,7,8,12,3,7,66,97,108,97,110,99,101,4,67,111,105,110,22,71,101,110,101,115,105,115,67,104,97,105,110,80,97,114,97,109,101,116,101,114,115,24,71,101,110,101,115,105,115,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,15,84,111,107,101,110,65,108,108,111,99,97,116,105,111,110,25,84,111,107,101,110,68,105,115,116,114,105,98,117,116,105,111,110,83,99,104,101,100,117,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,9,86,97,108,105,100,97,116,111,114,8,97,99,116,105,118,97,116,101,19,97,99,116,105,118,97,116,101,95,118,97,108,105,100,97,116,111,114,115,15,97,108,108,111,99,97,116,101,95,116,111,107,101,110,115,11,97,108,108,111,99,97,116,105,111,110,115,11,97,109,111,117,110,116,95,109,105,115,116,7,98,97,108,97,110,99,101,24,99,104,97,105,110,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,4,99,111,105,110,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,12,102,114,111,109,95,98,97,108,97,110,99,101,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,9,105,109,97,103,101,95,117,114,108,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,4,110,97,109,101,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,18,110,101,116,119,111,114,107,95,112,117,98,108,105,99,95,107,101,121,3,110,101,119,6,111,98,106,101,99,116,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,19,112,114,111,116,111,99,111,108,95,112,117,98,108,105,99,95,107,101,121,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,17,114,101,99,105,112,105,101,110,116,95,97,100,100,114,101,115,115,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,23,115,116,97,107,101,95,115,117,98,115,105,100,121,95,102,117,110,100,95,109,105,115,116,41,115,116,97,107,101,95,115,117,98,115,105,100,121,95,105,110,105,116,105,97,108,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,21,115,116,97,107,101,100,95,119,105,116,104,95,118,97,108,105,100,97,116,111,114,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,118,97,108,105,100,97,116,111,114,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,13,118,97,108,105,100,97,116,111,114,95,115,101,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,6,118,101,99,116,111,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,17,119,111,114,107,101,114,95,112,117,98,108,105,99,95,107,101,121,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,15,39,10,2,24,10,2,33,10,2,47,10,2,62,5,30,3,21,3,49,10,2,48,10,2,41,10,2,74,10,2,40,10,2,45,10,2,46,10,2,73,10,2,1,2,12,50,3,19,3,28,3,59,3,57,3,58,3,55,13,37,3,38,3,69,3,71,3,68,3,2,2,2,56,3,16,10,8,3,3,2,3,51,5,17,3,60,11,4,1,5,0,0,0,0,4,147,1,10,5,46,17,11,6,0,0,0,0,0,0,0,0,33,4,7,5,11,11,5,1,7,0,39,11,4,19,2,12,6,12,22,13,1,11,22,56,0,12,24,56,1,12,23,64,10,0,0,0,0,0,0,0,0,12,28,14,3,65,11,12,8,6,0,0,0,0,0,0,0,0,12,11,10,11,10,8,35,4,89,5,33,14,3,10,11,66,11,20,19,0,12,29,12,17,12,16,12,14,12,30,12,15,12,19,12,20,12,7,12,10,12,25,12,18,12,12,12,9,12,13,11,25,11,20,11,15,11,30,11,19,11,13,11,9,11,12,11,18,11,14,11,16,11,17,11,29,11,10,11,7,10,5,17,16,12,27,14,28,14,27,17,19,32,4,77,5,81,11,5,1,7,1,39,13,28,11,27,68,10,11,11,6,1,0,0,0,0,0,0,0,22,12,11,5,28,11,1,11,6,13,28,10,5,17,1,13,28,17,2,14,2,16,0,20,14,2,16,1,20,14,2,16,2,20,14,2,16,3,20,14,2,16,4,20,14,2,16,5,20,14,2,16,6,20,10,5,17,14,12,26,11,24,14,2,16,7,20,14,2,16,8,20,14,2,16,9,20,10,5,17,12,12,21,11,0,11,28,11,23,14,2,16,10,20,14,2,16,11,20,11,26,11,21,11,5,17,13,2,1,0,0,0,20,44,14,1,56,2,32,4,35,5,5,13,1,69,21,19,3,12,7,12,5,12,6,13,0,11,5,56,0,12,4,14,7,56,3,4,29,11,7,56,4,12,8,10,2,11,8,17,18,11,4,11,6,10,3,17,17,5,34,11,4,10,3,56,5,11,6,17,10,5,0,11,2,1,11,3,1,11,1,70,21,0,0,0,0,0,0,0,0,11,0,56,6,2,2,0,0,0,33,24,10,0,46,65,10,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,1,35,4,21,5,11,10,0,10,2,67,10,6,0,0,0,0,0,0,0,0,17,15,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,2,1,2,1,3,1,7,1,8,1,9,1,10,1,11,1,4,1,5,1,6,1,0,1,1,0],"stake_subsidy":[161,28,235,11,6,0,0,0,12,1,0,12,2,12,22,3,34,37,4,71,4,5,75,74,7,149,1,176,2,8,197,3,64,6,133,4,28,10,161,4,20,12,181,4,180,1,13,233,5,10,15,243,5,4,0,18,1,6,1,7,1,14,1,21,1,23,0,3,4,0,1,0,12,0,2,1,4,1,0,1,4,2,2,0,5,4,2,0,0,8,0,1,0,0,5,2,3,0,0,10,4,5,0,1,16,7,8,0,2,17,13,14,1,0,2,24,11,5,1,0,3,15,12,5,0,5,10,4,10,5,11,2,1,8,3,3,3,13,7,8,4,1,8,0,1,7,8,0,1,11,2,1,8,3,1,6,8,0,1,3,0,1,7,8,4,1,8,1,3,4,11,2,1,8,3,3,1,8,3,1,6,11,2,1,9,0,2,3,3,2,7,11,2,1,9,0,3,1,11,2,1,9,0,3,66,97,103,7,66,97,108,97,110,99,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,84,120,67,111,110,116,101,120,116,13,97,100,118,97,110,99,101,95,101,112,111,99,104,3,98,97,103,7,98,97,108,97,110,99,101,6,99,114,101,97,116,101,27,99,117,114,114,101,110,116,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,28,99,117,114,114,101,110,116,95,101,112,111,99,104,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,20,100,105,115,116,114,105,98,117,116,105,111,110,95,99,111,117,110,116,101,114,12,101,120,116,114,97,95,102,105,101,108,100,115,7,103,101,110,101,115,105,115,4,109,97,116,104,3,109,105,110,3,110,101,119,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,6,7,11,2,1,8,3,11,3,9,3,20,3,19,13,12,8,1,0,3,0,0,6,19,10,3,7,0,75,37,4,6,5,10,11,4,1,7,1,39,11,0,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,11,4,17,3,18,0,2,1,3,0,0,9,57,10,0,16,0,20,10,0,16,1,56,0,17,6,12,3,10,0,15,1,11,3,56,1,12,2,10,0,16,2,20,6,1,0,0,0,0,0,0,0,22,10,0,15,2,21,10,0,16,2,20,10,0,16,3,20,25,6,0,0,0,0,0,0,0,0,33,4,53,10,0,16,0,20,53,10,0,16,4,20,53,24,7,0,26,12,1,10,0,16,0,20,11,1,52,23,11,0,15,0,21,5,55,11,0,1,11,2,2,2,1,0,0,6,8,10,0,16,0,20,11,0,16,1,56,0,17,6,2,0,2,0,0,0,1,0,3,0,4,0,13,0,22,0],"staking_pool":[161,28,235,11,6,0,0,0,12,1,0,22,2,22,58,3,80,175,2,4,255,2,38,5,165,3,224,2,7,133,6,144,9,8,149,15,96,6,245,15,200,1,10,189,17,66,12,255,17,237,11,13,236,29,28,15,136,30,4,0,73,1,48,2,15,2,16,2,19,2,43,2,47,2,74,2,77,2,78,2,79,0,8,12,0,0,5,7,0,0,7,8,0,1,4,7,1,0,0,2,0,12,0,3,1,4,1,0,1,4,2,12,1,0,1,6,3,7,0,6,11,4,0,7,6,2,0,8,9,12,2,7,1,4,1,10,10,2,0,0,45,0,1,0,0,63,2,3,0,0,64,4,5,0,0,84,6,7,0,0,80,8,9,0,0,24,10,3,0,0,61,11,3,0,0,60,12,3,0,0,59,12,3,0,0,85,13,9,0,0,12,14,3,0,0,65,4,5,0,0,21,14,3,0,0,76,15,5,0,0,54,16,17,0,0,72,16,5,0,0,71,16,5,0,0,38,15,18,0,0,36,15,18,0,0,69,19,8,0,0,70,19,3,0,0,42,20,3,0,0,35,21,18,0,0,57,22,23,0,0,51,15,5,0,0,52,15,5,0,0,39,22,18,0,0,30,24,5,0,0,31,24,5,0,0,34,3,23,0,0,18,22,3,0,1,17,52,35,1,0,1,28,49,3,1,0,1,32,54,51,1,3,1,37,52,18,1,0,1,40,52,18,1,0,1,46,3,29,1,0,1,68,51,29,1,0,2,45,0,32,0,3,41,40,5,1,0,3,69,48,31,1,0,3,83,34,5,1,0,3,86,3,31,1,0,4,29,41,42,1,0,5,44,45,5,0,6,23,28,3,0,6,33,35,17,1,8,6,45,0,28,0,8,14,46,3,2,7,4,8,17,55,56,2,7,4,8,20,55,18,2,7,4,8,45,0,27,2,7,4,9,62,36,3,1,12,9,78,36,3,1,8,10,25,38,5,0,10,67,38,39,0,51,26,36,5,42,30,41,30,46,1,53,8,39,30,43,30,52,43,48,26,40,30,32,5,37,5,34,5,35,5,33,5,31,5,50,26,49,26,1,7,8,11,1,8,0,5,7,8,0,11,5,1,8,9,5,3,7,8,11,0,3,7,8,0,8,2,7,8,11,1,3,2,7,8,0,8,2,2,3,11,5,1,8,9,1,8,2,1,11,5,1,8,9,2,7,8,0,11,5,1,8,9,2,7,8,0,7,8,11,1,7,8,0,4,7,8,0,3,3,3,2,7,8,0,3,1,6,8,0,1,6,8,2,1,8,7,1,1,3,7,8,2,3,7,8,11,2,7,8,2,8,2,2,6,8,2,6,8,2,2,6,8,0,3,1,8,1,2,6,8,1,3,1,11,10,2,3,8,1,2,3,8,1,1,11,10,2,9,0,9,1,1,8,8,1,11,3,1,9,0,1,8,9,1,11,5,1,9,0,1,8,4,2,8,2,3,1,6,11,5,1,9,0,1,6,9,0,2,9,0,5,6,3,11,5,1,8,9,3,11,5,1,8,9,5,3,1,6,8,11,1,5,2,7,11,5,1,9,0,11,5,1,9,0,2,11,5,1,9,0,7,8,11,1,11,6,1,9,0,1,11,6,1,8,9,3,3,8,1,11,5,1,8,9,2,3,3,3,7,11,10,2,9,0,9,1,9,0,9,1,5,3,3,8,1,3,3,2,7,11,5,1,9,0,3,2,7,11,3,1,9,0,9,0,3,11,5,1,8,9,5,3,1,9,0,1,6,11,3,1,9,0,2,6,8,2,11,5,1,8,9,2,6,11,3,1,9,0,9,0,2,6,11,10,2,9,0,9,1,9,0,1,6,9,1,3,3,8,1,3,3,66,97,103,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,16,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,3,97,100,100,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,24,99,104,101,99,107,95,98,97,108,97,110,99,101,95,105,110,118,97,114,105,97,110,116,115,4,99,111,105,110,8,99,111,110,116,97,105,110,115,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,18,100,101,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,6,100,101,108,101,116,101,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,5,101,112,111,99,104,14,101,120,99,104,97,110,103,101,95,114,97,116,101,115,12,101,120,116,114,97,95,102,105,101,108,100,115,4,102,105,108,108,12,102,114,111,109,95,98,97,108,97,110,99,101,14,103,101,116,95,115,117,105,95,97,109,111,117,110,116,16,103,101,116,95,116,111,107,101,110,95,97,109,111,117,110,116,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,2,105,100,21,105,110,105,116,105,97,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,25,105,115,95,101,113,117,97,108,95,115,116,97,107,105,110,103,95,109,101,116,97,100,97,116,97,11,105,115,95,105,110,97,99,116,105,118,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,21,105,115,95,112,114,101,97,99,116,105,118,101,95,97,116,95,101,112,111,99,104,7,105,115,95,115,111,109,101,4,106,111,105,110,15,106,111,105,110,95,115,116,97,107,101,100,95,115,117,105,4,109,97,116,104,3,109,105,110,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,27,112,101,110,100,105,110,103,95,112,111,111,108,95,116,111,107,101,110,95,119,105,116,104,100,114,97,119,13,112,101,110,100,105,110,103,95,115,116,97,107,101,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,26,112,101,110,100,105,110,103,95,116,111,116,97,108,95,115,117,105,95,119,105,116,104,100,114,97,119,7,112,111,111,108,95,105,100,17,112,111,111,108,95,116,111,107,101,110,95,97,109,111,117,110,116,18,112,111,111,108,95,116,111,107,101,110,95,98,97,108,97,110,99,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,9,112,114,105,110,99,105,112,97,108,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,30,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,32,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,95,112,114,101,97,99,116,105,118,101,12,114,101,119,97,114,100,115,95,112,111,111,108,6,115,101,110,100,101,114,4,115,111,109,101,5,115,112,108,105,116,16,115,112,108,105,116,95,115,116,97,107,101,100,95,115,117,105,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,97,109,111,117,110,116,11,115,117,105,95,98,97,108,97,110,99,101,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,17,117,110,119,114,97,112,95,115,116,97,107,101,100,95,115,117,105,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,5,118,97,108,117,101,23,119,105,116,104,100,114,97,119,95,102,114,111,109,95,112,114,105,110,99,105,112,97,108,16,119,105,116,104,100,114,97,119,95,114,101,119,97,114,100,115,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,0,2,11,33,8,8,13,11,3,1,3,22,11,3,1,3,76,3,66,11,5,1,8,9,56,3,26,11,10,2,3,8,1,50,3,53,3,49,3,27,8,4,1,2,2,75,3,55,3,2,2,4,33,8,8,54,8,7,71,3,58,11,5,1,8,9,0,3,0,0,25,18,10,0,56,0,12,1,10,0,17,47,56,1,56,1,6,0,0,0,0,0,0,0,0,56,2,6,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,0,17,38,18,0,2,1,3,0,0,33,47,14,1,56,3,12,6,10,0,46,17,18,32,4,9,5,15,11,0,1,11,4,1,7,11,39,10,6,6,0,0,0,0,0,0,0,0,36,4,20,5,26,11,0,1,11,4,1,7,18,39,11,4,17,47,10,0,46,56,4,11,3,11,1,18,2,12,5,10,0,16,0,20,11,6,22,11,0,15,0,21,11,5,11,2,56,5,2,2,3,0,0,37,61,10,0,11,1,17,3,12,4,12,3,10,2,46,17,55,12,7,14,4,56,3,12,5,10,0,10,5,10,3,10,2,46,17,54,17,9,12,6,11,5,14,6,56,3,22,12,8,10,0,16,1,20,10,8,22,10,0,15,1,21,10,0,16,2,20,11,3,22,10,0,15,2,21,10,0,46,17,18,4,48,11,0,17,7,5,50,11,0,1,13,4,11,6,56,6,1,11,4,11,2,56,7,11,7,56,8,11,8,2,3,3,0,0,44,31,14,1,16,3,20,10,0,46,56,4,33,4,9,5,13,11,0,1,7,2,39,11,0,14,1,16,4,20,12,2,46,11,2,17,23,12,3,11,1,17,4,12,4,14,3,14,4,56,3,17,28,11,4,2,4,0,0,0,9,8,11,0,19,2,12,1,1,1,17,45,11,1,2,5,3,0,0,3,15,10,0,16,5,20,14,1,56,3,22,10,0,15,5,21,11,0,15,6,11,1,56,6,1,2,6,3,0,0,45,28,11,1,46,17,54,6,1,0,0,0,0,0,0,0,22,12,3,10,0,17,7,10,0,17,8,10,0,15,7,10,3,10,0,16,5,20,10,0,16,8,20,18,1,56,9,11,0,11,3,12,2,46,11,2,17,30,2,7,0,0,0,3,29,10,0,16,5,20,10,0,16,1,20,23,10,0,15,5,21,10,0,16,8,20,10,0,16,2,20,23,10,0,15,8,21,6,0,0,0,0,0,0,0,0,10,0,15,1,21,6,0,0,0,0,0,0,0,0,11,0,15,2,21,2,8,3,0,0,23,31,10,0,16,5,20,10,0,16,8,20,18,1,12,1,10,0,16,5,20,10,0,16,0,20,22,10,0,15,5,21,14,1,10,0,16,5,20,17,28,10,0,15,8,21,6,0,0,0,0,0,0,0,0,11,0,15,0,21,2,9,0,0,0,47,33,10,0,11,3,12,4,46,11,4,17,23,12,6,14,6,11,2,17,27,12,8,10,8,10,1,38,4,20,11,8,11,1,23,12,5,5,22,6,0,0,0,0,0,0,0,0,12,5,11,5,10,0,16,6,56,3,17,44,12,7,11,0,15,6,11,7,56,10,2,10,3,0,0,3,29,10,0,15,7,10,1,17,29,56,9,10,0,46,17,17,4,10,5,14,11,0,1,7,15,39,10,0,46,17,18,32,4,20,5,24,11,0,1,7,17,39,11,0,15,9,11,1,56,11,2,11,3,0,0,50,59,14,1,16,3,20,10,0,46,56,4,33,4,9,5,15,11,0,1,11,2,1,7,2,39,10,0,46,17,17,4,20,5,26,11,0,1,11,2,1,7,16,39,10,2,46,17,55,12,4,11,1,17,4,12,3,14,3,56,3,12,5,10,0,16,5,20,10,5,23,10,0,15,5,21,10,0,16,8,20,10,5,23,11,0,15,8,21,11,3,11,2,56,7,11,4,56,8,11,5,2,12,3,0,0,3,16,10,0,46,17,18,32,4,6,5,10,11,0,1,7,12,39,11,1,56,12,11,0,15,10,21,2,13,1,0,0,3,4,11,0,16,5,20,2,14,1,0,0,3,4,11,0,16,3,20,2,15,1,0,0,3,4,11,0,16,11,56,3,2,16,1,0,0,3,4,11,0,16,4,20,2,17,1,0,0,3,4,11,0,16,9,56,13,2,18,1,0,0,3,4,11,0,16,10,56,14,2,19,1,0,0,5,53,10,0,16,11,56,3,12,3,10,1,10,3,37,4,9,5,15,11,0,1,11,2,1,7,4,39,11,3,10,1,23,7,0,38,4,22,5,28,11,0,1,11,2,1,7,19,39,10,1,7,0,38,4,33,5,39,11,0,1,11,2,1,7,19,39,11,2,17,47,10,0,16,3,20,10,0,16,4,20,11,0,15,11,11,1,56,10,18,2,2,20,1,4,0,3,9,11,0,11,1,10,2,17,19,11,2,46,17,55,56,5,2,21,1,4,0,53,24,10,0,14,1,12,2,46,11,2,17,22,4,8,5,12,11,0,1,7,13,39,11,1,19,2,12,3,1,1,17,45,11,0,15,11,11,3,56,6,1,2,22,1,0,0,18,25,10,0,16,3,20,10,1,16,3,20,33,4,17,11,0,16,4,20,11,1,16,4,20,33,12,2,5,23,11,0,1,11,1,1,9,12,2,11,2,2,23,1,0,0,45,45,10,0,10,1,17,26,4,8,11,0,1,17,29,2,10,0,16,10,10,1,56,15,11,1,17,44,12,3,10,0,16,9,56,16,20,12,2,10,3,10,2,38,4,41,5,25,10,0,16,7,10,3,56,17,4,36,11,0,16,7,11,3,56,18,20,2,11,3,6,1,0,0,0,0,0,0,0,23,12,3,5,20,11,0,1,17,29,2,24,1,0,0,3,4,11,0,16,0,20,2,25,1,0,0,3,4,11,0,16,1,20,2,26,0,0,0,18,17,10,0,17,17,4,8,11,0,1,8,12,2,5,15,11,0,16,9,56,16,20,11,1,36,12,2,11,2,2,27,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,12,20,53,11,1,53,24,11,0,16,13,20,53,26,52,2,28,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,13,20,53,11,1,53,24,11,0,16,12,20,53,26,52,2,29,0,0,0,3,4,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,18,1,2,30,0,0,0,57,22,10,0,11,1,17,23,12,3,14,3,10,0,16,5,20,17,28,12,4,11,0,16,8,20,12,2,11,4,11,2,33,4,19,5,21,7,10,39,2,0,7,0,8,0,9,2,1,2,2,0,3,0,4,0,6,0,5,0,1,0,2,2,3,1,0,1,1,0,81,0,82,0],"storage_fund":[161,28,235,11,6,0,0,0,11,1,0,6,2,6,14,3,20,44,4,64,8,5,72,73,7,145,1,178,1,8,195,2,64,10,131,3,15,12,146,3,107,13,253,3,4,15,129,4,2,0,9,1,4,1,10,0,2,4,0,1,0,4,1,0,1,2,1,2,0,0,6,0,1,0,0,3,2,0,0,0,13,3,4,0,0,12,3,4,0,1,5,8,4,1,0,1,8,9,7,1,0,1,14,10,4,1,0,1,15,5,7,1,0,7,6,4,6,5,6,6,6,1,11,1,1,8,2,1,8,0,6,7,8,0,11,1,1,8,2,11,1,1,8,2,11,1,1,8,2,3,3,1,6,8,0,1,3,0,1,8,2,1,11,1,1,9,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,6,11,1,1,9,0,7,66,97,108,97,110,99,101,3,83,85,73,11,83,116,111,114,97,103,101,70,117,110,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,4,106,111,105,110,3,110,101,119,22,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,98,97,108,97,110,99,101,5,115,112,108,105,116,12,115,116,111,114,97,103,101,95,102,117,110,100,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,13,116,111,116,97,108,95,98,97,108,97,110,99,101,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,11,1,1,8,2,7,11,1,1,8,2,0,3,0,0,5,4,56,0,11,0,18,0,2,1,3,0,0,0,30,10,0,15,0,11,2,56,1,1,10,0,15,0,11,3,56,1,1,10,0,15,1,11,1,56,1,1,10,0,15,1,11,5,56,2,12,6,10,0,15,0,11,6,56,1,1,11,0,15,1,11,4,56,2,2,2,1,0,0,5,4,11,0,16,1,56,3,2,3,1,0,0,5,8,10,0,16,1,56,3,11,0,16,0,56,3,22,2,0,1,0,0,0,11,0],"sui_system":[161,28,235,11,6,0,0,0,12,1,0,28,2,28,62,3,90,146,3,4,236,3,10,5,246,3,158,3,7,148,7,191,12,8,211,19,96,6,179,20,54,10,233,20,8,12,241,20,166,6,13,151,27,4,15,155,27,2,0,48,1,28,2,16,2,18,2,20,2,27,2,47,2,51,2,52,0,45,0,46,0,49,0,73,0,74,0,6,8,0,1,2,7,1,0,0,2,0,4,1,0,1,3,1,12,1,0,1,5,11,4,0,6,3,2,0,8,10,2,0,9,4,4,0,10,5,8,0,11,7,4,0,11,8,4,0,11,9,4,0,12,13,4,0,13,12,12,0,0,19,0,1,0,0,34,2,1,0,0,36,3,1,0,0,33,3,1,0,0,35,3,1,0,0,38,4,1,0,0,43,4,1,0,0,37,5,1,0,0,42,5,1,0,0,31,6,1,0,0,32,7,1,0,0,39,8,1,0,0,30,9,1,0,0,53,9,1,0,0,40,3,1,0,0,63,10,1,0,0,61,10,1,0,0,62,10,1,0,0,71,10,1,0,0,64,10,1,0,0,54,10,1,0,0,66,10,1,0,0,56,10,1,0,0,67,10,1,0,0,57,10,1,0,0,69,10,1,0,0,59,10,1,0,0,68,11,1,0,0,58,11,1,0,0,70,10,1,0,0,60,10,1,0,0,65,10,1,0,0,55,10,1,0,0,15,12,13,0,0,25,14,15,0,0,26,14,16,0,0,24,14,16,0,4,14,22,1,2,7,4,4,17,39,43,2,7,4,4,29,39,40,2,7,4,7,44,24,1,1,8,8,41,35,36,0,11,15,37,13,0,11,19,18,19,0,11,22,1,20,0,11,30,32,1,0,11,31,29,1,0,11,32,30,1,0,11,33,26,1,0,11,34,25,1,0,11,35,26,1,0,11,36,26,1,0,11,37,28,1,0,11,38,27,1,0,11,39,31,1,0,11,40,26,1,0,11,42,28,1,0,11,43,27,1,0,11,50,15,20,0,11,53,32,1,0,11,54,33,1,0,11,55,33,1,0,11,56,33,1,0,11,57,33,1,0,11,58,34,1,0,11,59,33,1,0,11,60,33,1,0,11,61,33,1,0,11,62,33,1,0,11,63,33,1,0,11,64,33,1,0,11,65,33,1,0,11,66,33,1,0,11,67,33,1,0,11,68,34,1,0,11,69,33,1,0,11,70,33,1,0,11,71,33,1,0,11,72,19,41,0,37,21,40,23,39,21,37,42,38,42,8,8,4,10,8,12,11,2,1,8,5,3,3,8,11,8,7,7,8,6,0,16,7,8,0,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,6,2,7,8,0,7,8,6,3,7,8,0,6,8,13,3,3,7,8,0,3,7,8,6,4,7,8,0,11,3,1,8,5,5,7,8,6,5,7,8,0,10,11,3,1,8,5,11,1,1,3,5,7,8,6,3,7,8,0,8,8,7,8,6,3,7,8,0,6,8,13,5,3,7,8,0,10,2,6,8,6,4,7,8,0,10,2,10,2,6,8,6,11,11,2,1,8,5,11,2,1,8,5,7,8,0,3,3,3,3,3,3,3,7,8,6,1,11,2,1,8,5,1,7,8,0,1,6,8,10,1,7,8,10,3,8,0,8,9,3,7,10,8,12,11,2,1,8,5,3,3,8,11,8,7,7,8,6,1,8,9,1,3,2,3,8,9,3,7,8,4,9,0,9,1,1,8,0,1,9,0,16,7,8,10,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,6,2,7,8,10,7,8,6,3,7,8,10,6,8,13,3,3,7,8,10,3,7,8,6,4,7,8,10,11,3,1,8,5,5,7,8,6,5,7,8,10,10,11,3,1,8,5,11,1,1,3,5,7,8,6,3,7,8,10,8,8,7,8,6,3,7,8,10,6,8,13,5,3,7,8,10,10,2,6,8,6,4,7,8,10,10,2,10,2,6,8,6,1,6,8,6,1,5,11,7,8,10,3,3,11,2,1,8,5,11,2,1,8,5,3,3,3,3,3,7,8,6,2,7,8,10,8,10,2,7,8,4,9,0,1,9,1,1,8,10,2,3,8,10,1,7,9,1,7,66,97,108,97,110,99,101,4,67,111,105,110,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,14,83,117,105,83,121,115,116,101,109,83,116,97,116,101,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,3,97,100,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,4,99,111,105,110,6,99,114,101,97,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,2,105,100,24,108,111,97,100,95,105,110,110,101,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,17,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,21,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,95,109,117,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,6,115,101,110,100,101,114,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,23,8,4,75,3,0,3,0,0,17,23,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,43,12,9,17,44,12,10,11,0,10,10,18,0,12,8,13,8,15,0,11,10,11,9,56,0,11,8,56,1,2,1,1,4,0,1,19,11,0,17,35,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,11,15,17,49,2,2,1,4,0,1,5,11,0,17,35,11,1,17,51,2,3,1,4,0,1,5,11,0,17,35,11,1,17,48,2,4,1,4,0,1,5,11,0,17,35,11,1,17,50,2,5,1,4,0,1,6,11,0,17,35,11,1,11,2,17,53,2,6,1,4,0,1,6,11,0,17,35,11,1,11,2,17,57,2,7,1,4,0,1,6,11,0,17,35,11,1,11,2,17,52,2,8,1,4,0,1,6,11,0,17,35,11,1,11,2,17,56,2,9,1,4,0,1,7,11,0,17,35,11,1,11,2,11,3,17,46,2,10,1,4,0,1,8,11,0,17,35,11,1,11,2,11,3,11,4,17,47,2,11,1,4,0,1,6,11,0,17,35,11,1,11,2,17,54,2,12,1,4,0,1,6,11,0,17,35,11,1,11,2,17,45,2,13,1,4,0,1,6,11,0,17,35,11,1,11,2,17,59,2,14,1,4,0,1,5,11,0,17,35,11,1,17,55,2,15,1,4,0,1,6,11,0,17,35,11,1,11,2,17,69,2,16,1,4,0,1,6,11,0,17,35,11,1,11,2,17,67,2,17,1,4,0,1,6,11,0,17,35,11,1,11,2,17,68,2,18,1,4,0,1,6,11,0,17,35,11,1,11,2,17,77,2,19,1,4,0,1,6,11,0,17,35,11,1,11,2,17,70,2,20,1,4,0,1,6,11,0,17,35,11,1,11,2,17,60,2,21,1,4,0,1,6,11,0,17,35,11,1,11,2,17,72,2,22,1,4,0,1,6,11,0,17,35,11,1,11,2,17,62,2,23,1,4,0,1,6,11,0,17,35,11,1,11,2,17,73,2,24,1,4,0,1,6,11,0,17,35,11,1,11,2,17,63,2,25,1,4,0,1,6,11,0,17,35,11,1,11,2,17,75,2,26,1,4,0,1,6,11,0,17,35,11,1,11,2,17,65,2,27,1,4,0,1,7,11,0,17,35,11,1,11,2,11,3,17,74,2,28,1,4,0,1,7,11,0,17,35,11,1,11,2,11,3,17,64,2,29,1,4,0,1,6,11,0,17,35,11,1,11,2,17,76,2,30,1,4,0,1,6,11,0,17,35,11,1,11,2,17,66,2,31,1,4,0,1,6,11,0,17,35,11,1,11,2,17,71,2,32,1,4,0,1,6,11,0,17,35,11,1,11,2,17,61,2,33,0,0,0,16,29,11,2,17,35,12,11,10,10,46,17,41,7,2,33,4,10,5,16,11,11,1,11,10,1,7,0,39,11,11,11,3,11,4,11,0,11,1,11,5,11,6,11,7,11,8,11,9,11,10,17,42,2,34,0,0,0,1,4,11,0,17,36,46,2,35,0,0,0,1,3,11,0,17,36,2,36,0,0,0,38,47,10,0,16,1,20,6,1,0,0,0,0,0,0,0,33,4,25,10,0,15,0,10,0,16,1,20,56,2,17,78,12,2,6,2,0,0,0,0,0,0,0,10,0,15,1,21,10,0,15,0,10,0,16,1,20,11,2,56,3,10,0,15,0,10,0,16,1,20,56,4,12,1,10,1,46,17,58,11,0,16,1,20,33,4,41,5,45,11,1,1,7,1,39,11,1,2,0,0,0,1,0,21,0],"sui_system_state_inner":[161,28,235,11,6,0,0,0,12,1,0,45,2,45,104,3,149,1,212,5,4,233,6,50,5,155,7,251,6,7,150,14,188,29,8,210,43,96,6,178,44,117,10,167,45,189,1,12,228,46,229,17,13,201,64,46,15,247,64,4,0,112,1,68,2,25,2,26,2,27,2,39,2,67,2,70,2,110,2,114,2,120,2,121,2,174,1,2,175,1,0,100,0,103,0,106,0,161,1,0,162,1,0,166,1,0,12,4,0,0,13,4,0,0,9,4,0,0,10,4,0,0,11,3,0,1,4,7,1,0,0,2,0,12,0,3,1,4,1,0,1,4,2,12,1,0,1,6,3,7,0,8,5,2,0,9,14,12,2,7,1,4,1,11,15,2,0,12,20,7,2,1,0,0,0,13,21,7,1,3,0,14,6,4,0,15,7,8,0,16,8,4,0,17,17,4,0,18,16,12,0,18,18,2,0,19,19,4,0,0,29,0,1,0,0,30,2,3,0,0,160,1,1,4,0,0,80,5,6,0,0,82,7,6,0,0,79,7,6,0,0,81,7,6,0,0,84,8,6,0,0,96,8,6,0,0,83,9,6,0,0,95,9,6,0,0,77,10,6,0,0,78,11,6,0,0,85,12,6,0,0,75,13,6,0,0,122,13,6,0,0,76,14,6,0,0,123,14,6,0,0,86,7,6,0,0,151,1,15,6,0,0,149,1,15,6,0,0,150,1,15,6,0,0,159,1,15,6,0,0,152,1,15,6,0,0,129,1,15,6,0,0,154,1,15,6,0,0,131,1,15,6,0,0,155,1,15,6,0,0,132,1,15,6,0,0,157,1,15,6,0,0,134,1,15,6,0,0,156,1,16,6,0,0,133,1,16,6,0,0,158,1,15,6,0,0,135,1,15,6,0,0,153,1,15,6,0,0,130,1,15,6,0,0,23,17,18,0,0,36,19,20,0,0,71,19,20,0,0,113,19,20,0,0,44,6,20,0,0,38,19,20,0,0,167,1,21,20,0,0,168,1,21,22,0,0,169,1,19,23,0,0,47,21,24,0,0,49,19,20,0,0,48,19,20,0,0,41,25,18,0,1,32,94,64,1,0,1,57,93,59,1,0,2,64,35,36,0,3,33,34,6,1,0,3,58,81,20,1,0,3,98,85,34,1,0,3,173,1,83,20,1,0,3,178,1,80,34,1,0,3,179,1,6,34,1,0,4,42,95,54,1,0,4,54,54,34,1,0,5,34,64,6,1,3,7,59,92,6,1,0,10,72,96,6,1,12,11,36,39,20,0,11,92,39,40,0,12,28,63,59,2,1,0,12,35,6,32,2,1,0,12,45,63,89,2,1,0,12,46,67,68,2,1,0,12,53,66,6,2,1,0,12,74,67,73,2,1,0,13,28,69,59,1,3,13,35,6,65,1,3,13,53,70,6,1,3,13,56,72,59,1,3,13,74,71,6,1,3,13,97,64,65,1,3,14,23,84,18,0,15,99,56,20,0,16,23,87,18,0,16,64,18,30,0,16,115,82,20,0,16,117,82,20,0,17,64,41,38,0,17,65,74,6,0,17,84,50,6,0,17,93,53,6,0,17,94,50,6,0,17,124,75,6,0,17,125,75,6,0,17,126,75,6,0,17,127,75,6,0,17,128,1,78,6,0,17,136,1,75,6,0,17,137,1,75,6,0,17,138,1,75,6,0,17,139,1,75,6,0,17,140,1,75,6,0,17,141,1,75,6,0,17,142,1,75,6,0,17,143,1,75,6,0,17,144,1,75,6,0,17,145,1,78,6,0,17,146,1,75,6,0,17,147,1,75,6,0,17,148,1,75,6,0,18,176,1,61,62,0,19,22,29,45,0,19,23,86,6,0,19,24,77,6,0,19,31,29,20,0,19,50,52,49,0,19,51,52,49,0,19,52,48,49,0,19,55,58,59,0,19,64,27,28,0,19,66,29,20,0,19,77,55,6,0,19,79,44,6,0,19,80,42,6,0,19,81,43,6,0,19,82,43,6,0,19,83,51,6,0,19,85,57,6,0,19,104,29,23,0,19,118,29,20,0,19,168,1,58,22,0,19,170,1,58,20,0,19,177,1,47,46,0,67,31,58,33,60,33,66,31,77,40,70,31,69,31,72,40,74,40,76,40,75,40,71,31,57,33,54,33,56,33,55,33,61,88,68,31,73,40,62,33,51,20,50,20,59,33,63,91,53,33,7,10,8,18,11,7,1,8,10,3,3,8,0,8,15,7,8,12,1,8,2,8,3,3,3,3,3,3,3,7,8,12,1,8,0,1,8,3,16,7,8,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,0,2,7,8,3,7,8,12,3,7,8,3,6,8,19,3,3,7,8,3,3,7,8,12,4,7,8,3,11,8,1,8,10,5,7,8,12,5,7,8,3,10,11,8,1,8,10,11,5,1,3,5,7,8,12,3,7,8,3,8,16,7,8,12,3,7,8,3,6,8,19,5,3,8,20,5,7,11,13,2,5,11,14,1,5,3,7,8,3,10,2,6,8,12,4,7,8,3,10,2,10,2,6,8,12,11,7,8,3,3,3,11,7,1,8,10,11,7,1,8,10,3,3,3,3,3,7,8,12,1,11,7,1,8,10,1,6,8,3,1,3,2,6,8,3,5,1,8,9,1,6,11,11,2,8,9,5,1,11,14,1,5,3,10,11,8,1,8,10,11,5,1,3,7,8,12,2,3,8,21,2,10,8,18,7,8,12,1,8,21,1,6,8,21,1,8,17,2,5,11,14,1,5,1,11,13,2,9,0,9,1,1,8,10,1,11,7,1,9,0,1,7,8,12,1,8,6,23,3,3,3,3,3,8,6,8,0,3,3,1,11,7,1,8,10,3,3,11,7,1,8,10,8,15,3,8,6,8,17,3,3,11,13,2,5,11,14,1,5,3,8,21,1,8,18,1,6,8,12,1,5,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,3,7,8,21,8,18,7,8,12,2,7,8,21,7,8,12,3,7,8,21,3,7,8,12,1,6,10,8,18,1,8,20,3,7,8,21,6,8,19,2,3,7,8,21,6,8,20,1,1,7,8,18,3,7,8,18,8,20,3,3,7,8,21,3,6,8,12,2,7,8,21,6,8,12,2,7,8,18,3,1,11,8,1,9,0,4,7,8,21,5,11,7,1,8,10,7,8,12,1,6,8,16,3,7,8,21,8,16,7,8,12,2,6,8,21,5,1,1,4,6,5,6,5,5,7,11,14,1,5,1,6,8,20,1,6,5,2,6,11,13,2,9,0,9,1,6,9,0,1,9,0,1,11,14,1,9,0,3,7,11,13,2,9,0,9,1,9,0,9,1,2,7,11,13,2,9,0,9,1,6,9,0,1,7,9,1,2,6,11,14,1,9,0,6,9,0,2,7,11,14,1,9,0,9,0,2,7,11,14,1,9,0,6,9,0,1,6,11,14,1,9,0,2,9,0,9,1,2,7,8,18,7,8,12,2,7,8,18,10,2,2,7,8,18,6,8,18,2,6,8,21,6,8,18,3,7,8,18,10,2,10,2,44,1,3,3,3,3,3,3,1,1,1,11,7,1,8,10,3,3,3,3,3,3,3,3,4,3,3,3,11,7,1,8,10,3,3,3,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,3,11,7,1,8,10,4,11,7,1,8,10,4,3,3,3,3,4,3,1,7,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,1,6,8,17,1,6,11,7,1,9,0,1,7,8,15,2,7,11,7,1,9,0,3,9,7,8,21,7,11,7,1,8,10,7,11,7,1,8,10,7,11,13,2,5,11,14,1,5,3,3,3,3,7,8,12,6,7,8,17,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,1,8,4,1,6,9,1,5,11,7,1,8,10,3,11,7,1,8,10,11,8,1,8,10,11,7,1,8,10,1,11,8,1,8,10,2,7,11,8,1,9,0,10,11,8,1,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,2,11,7,1,9,0,7,8,12,2,9,0,5,3,66,97,103,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,11,83,116,111,114,97,103,101,70,117,110,100,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,20,83,121,115,116,101,109,69,112,111,99,104,73,110,102,111,69,118,101,110,116,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,18,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,86,50,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,6,86,101,99,77,97,112,6,86,101,99,83,101,116,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,3,98,97,103,7,98,97,108,97,110,99,101,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,5,101,109,112,116,121,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,24,101,112,111,99,104,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,20,101,120,116,114,97,99,116,95,99,111,105,110,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,3,103,101,116,7,103,101,116,95,109,117,116,16,103,101,116,95,114,101,112,111,114,116,101,114,115,95,111,102,31,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,111,98,106,101,99,116,95,114,101,98,97,116,101,115,30,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,116,111,116,97,108,95,98,97,108,97,110,99,101,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,6,105,110,115,101,114,116,12,105,110,116,111,95,98,97,108,97,110,99,101,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,106,111,105,110,8,106,111,105,110,95,118,101,99,28,108,101,102,116,111,118,101,114,95,115,116,111,114,97,103,101,95,102,117,110,100,95,105,110,102,108,111,119,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,19,109,105,110,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,3,110,101,119,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,114,97,109,101,116,101,114,115,3,112,97,121,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,19,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,21,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,9,115,97,102,101,95,109,111,100,101,29,115,97,102,101,95,109,111,100,101,95,99,111,109,112,117,116,97,116,105,111,110,95,114,101,119,97,114,100,115,36,115,97,102,101,95,109,111,100,101,95,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,115,116,111,114,97,103,101,95,102,101,101,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,119,97,114,100,115,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,9,115,105,110,103,108,101,116,111,110,5,115,112,108,105,116,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,13,115,116,97,107,101,95,115,117,98,115,105,100,121,20,115,116,97,107,101,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,12,115,116,97,107,105,110,103,95,112,111,111,108,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,14,115,116,111,114,97,103,101,95,99,104,97,114,103,101,12,115,116,111,114,97,103,101,95,102,117,110,100,20,115,116,111,114,97,103,101,95,102,117,110,100,95,98,97,108,97,110,99,101,25,115,116,111,114,97,103,101,95,102,117,110,100,95,114,101,105,110,118,101,115,116,109,101,110,116,14,115,116,111,114,97,103,101,95,114,101,98,97,116,101,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,5,116,97,98,108,101,13,116,111,116,97,108,95,98,97,108,97,110,99,101,14,116,111,116,97,108,95,103,97,115,95,102,101,101,115,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,31,116,111,116,97,108,95,115,116,97,107,101,95,114,101,119,97,114,100,115,95,100,105,115,116,114,105,98,117,116,101,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,26,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,24,118,97,108,105,100,97,116,111,114,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,31,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,10,118,97,108,105,100,97,116,111,114,115,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,3,8,1,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,8,37,3,102,3,61,3,63,3,164,1,3,171,1,3,163,1,3,40,8,6,1,2,9,37,3,102,3,62,3,61,3,63,3,164,1,3,171,1,3,163,1,3,40,8,6,2,2,16,36,3,71,3,113,3,172,1,8,21,106,8,17,69,8,0,73,3,165,1,11,13,2,5,11,14,1,5,100,8,15,87,1,91,11,7,1,8,10,88,11,7,1,8,10,90,3,89,3,38,3,40,8,6,3,2,16,36,3,71,3,113,3,172,1,8,21,106,8,17,69,8,1,73,3,165,1,11,13,2,5,11,14,1,5,100,8,15,87,1,91,11,7,1,8,10,88,11,7,1,8,10,90,3,89,3,38,3,40,8,6,4,2,12,36,3,71,3,73,3,118,3,108,3,105,3,109,3,107,3,101,3,116,3,119,3,60,3,0,3,0,0,26,27,11,0,10,6,17,116,12,8,14,8,17,111,12,7,6,0,0,0,0,0,0,0,0,11,2,17,41,11,8,11,1,17,81,11,4,11,7,56,0,11,5,9,56,1,56,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,3,11,6,17,52,18,2,2,1,3,0,0,6,11,11,0,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,52,18,0,2,2,3,0,0,37,55,11,0,19,2,12,17,12,3,12,12,12,13,12,11,12,14,12,10,12,15,12,21,12,9,12,7,12,18,12,23,1,12,8,12,1,11,7,19,0,12,6,12,19,12,22,12,20,12,5,12,4,12,16,12,2,11,1,11,8,6,2,0,0,0,0,0,0,0,11,23,11,18,11,2,11,16,6,4,0,0,0,0,0,0,0,11,4,11,5,11,20,11,22,11,19,11,6,18,1,11,9,11,21,11,15,11,10,11,14,11,11,11,13,11,12,11,3,11,17,18,3,2,3,3,0,0,38,26,10,15,46,17,65,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,10,15,17,84,12,16,11,0,15,0,11,16,11,15,17,120,2,4,3,0,0,6,5,11,0,15,0,11,1,17,122,2,5,3,0,0,6,25,10,0,16,0,17,117,10,0,16,1,16,2,20,35,4,10,5,16,11,0,1,11,1,1,7,3,39,10,0,15,0,11,0,16,1,16,3,20,11,1,17,119,2,6,3,0,0,6,31,10,0,16,0,17,108,65,38,10,0,16,1,16,4,20,38,4,26,10,0,16,0,17,117,10,0,16,1,16,4,20,36,4,20,5,26,11,0,1,11,1,1,7,3,39,11,0,15,0,11,1,17,121,2,7,3,0,0,46,15,10,0,15,0,11,1,7,1,17,129,1,12,3,11,0,15,0,14,3,9,17,114,11,3,11,2,17,86,2,8,3,0,0,46,15,10,0,15,0,11,1,7,2,17,129,1,12,3,11,0,15,0,14,3,8,17,114,11,3,11,2,17,88,2,9,3,0,0,6,7,11,0,15,0,11,1,11,2,46,17,123,2,10,3,0,0,6,8,11,0,15,0,11,2,46,17,113,11,1,17,87,2,11,3,0,0,6,8,11,0,15,0,11,2,11,1,56,2,11,3,17,118,2,12,3,0,0,18,12,11,1,11,2,10,4,17,49,12,5,11,0,15,0,11,3,11,5,11,4,17,118,2,13,3,0,0,6,20,14,1,17,79,10,2,46,17,64,37,4,8,5,14,11,0,1,11,2,1,7,9,39,11,0,15,0,11,1,11,2,17,124,2,14,3,0,0,6,22,10,0,16,0,10,2,17,115,4,6,5,12,11,0,1,11,1,1,7,4,39,10,0,15,0,11,1,7,0,17,129,1,11,2,11,0,15,5,17,16,2,15,3,0,0,6,10,10,0,15,0,11,1,7,0,17,129,1,11,2,11,0,15,5,17,17,2,16,0,0,0,60,46,14,0,17,107,20,12,5,10,5,10,1,34,4,9,5,13,11,2,1,7,6,39,10,2,14,1,12,3,46,11,3,56,3,32,4,27,11,2,11,1,11,5,56,4,56,5,5,45,11,2,14,1,56,6,12,6,10,6,14,5,12,4,46,11,4,56,7,32,4,43,11,6,11,5,56,8,5,45,11,6,1,2,17,0,0,0,60,50,10,2,14,1,12,3,46,11,3,56,3,4,8,5,12,11,2,1,7,7,39,10,2,14,1,56,6,12,6,14,0,17,107,20,12,5,10,6,14,5,12,4,46,11,4,56,7,4,28,5,34,11,2,1,11,6,1,7,7,39,10,6,14,5,56,9,11,6,46,56,10,4,47,11,2,14,1,56,11,1,1,5,49,11,2,1,2,18,3,0,0,6,8,11,0,15,0,10,1,46,17,113,11,1,17,85,2,19,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,98,2,20,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,96,2,21,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,97,2,22,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,106,2,23,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,99,11,3,46,12,4,11,0,16,0,11,4,17,110,2,24,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,89,2,25,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,101,11,3,46,12,4,11,0,16,0,11,4,17,110,2,26,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,91,2,27,3,0,0,6,7,11,0,15,0,11,2,17,112,11,1,17,102,2,28,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,92,2,29,3,0,0,6,7,11,0,15,0,11,2,17,112,11,1,17,104,2,30,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,94,2,31,3,0,0,76,17,10,0,15,0,11,3,17,112,12,4,10,4,11,1,11,2,17,103,11,4,46,12,5,11,0,16,0,11,5,17,110,2,32,3,0,0,6,8,11,0,15,0,11,3,17,113,11,1,11,2,17,93,2,33,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,105,11,3,46,12,4,11,0,16,0,11,4,17,110,2,34,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,95,2,35,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,100,11,3,46,12,4,11,0,16,0,11,4,17,110,2,36,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,90,2,37,3,0,0,79,220,2,10,0,16,6,20,12,37,10,9,10,0,15,6,21,7,12,52,12,28,10,7,10,28,37,4,20,10,8,11,28,37,12,11,5,22,9,12,11,11,11,4,25,5,31,11,0,1,11,10,1,7,8,39,10,0,16,1,16,7,20,6,0,0,0,0,0,0,0,0,36,4,43,6,20,0,0,0,0,0,0,0,10,0,15,1,15,7,21,10,0,15,8,56,12,12,40,13,3,11,40,56,13,1,10,0,15,9,56,12,12,39,13,4,11,39,56,13,1,11,5,10,0,16,10,20,22,12,5,6,0,0,0,0,0,0,0,0,10,0,15,10,21,11,6,10,0,16,11,20,22,12,6,6,0,0,0,0,0,0,0,0,10,0,15,11,21,10,0,16,0,17,126,12,54,10,0,16,12,17,82,12,44,10,44,11,54,22,12,52,14,3,56,14,12,43,14,4,56,14,12,29,10,10,46,17,64,10,0,16,1,16,7,20,38,4,116,11,9,11,37,10,0,16,1,16,13,20,22,38,12,20,5,118,9,12,20,11,20,4,125,10,0,15,14,17,78,12,21,5,127,56,1,12,21,11,21,12,41,14,41,56,14,12,42,13,4,11,41,56,13,1,11,52,53,12,53,10,29,53,12,30,11,44,53,11,30,24,11,53,26,12,48,13,4,10,48,52,56,15,12,47,11,48,11,7,53,24,7,12,26,12,46,13,47,10,46,52,56,15,12,45,10,0,16,15,20,6,1,0,0,0,0,0,0,0,22,10,0,15,15,21,11,1,10,0,16,15,20,33,4,181,1,5,187,1,11,0,1,11,10,1,7,11,39,14,4,56,14,12,32,14,47,56,14,12,50,10,0,15,0,13,4,13,47,10,0,15,5,11,8,10,0,16,1,16,16,20,10,0,16,1,16,17,20,10,0,16,1,16,18,20,11,10,17,109,10,0,16,0,17,126,12,36,14,4,56,14,12,31,14,47,56,14,12,49,11,32,11,31,23,12,33,11,50,11,49,23,12,51,11,2,10,0,15,19,21,10,0,16,0,17,111,10,0,15,20,21,11,47,12,34,13,34,11,4,56,13,1,14,34,56,14,12,35,10,0,15,12,11,3,11,45,11,34,10,5,11,6,17,80,12,38,10,0,16,15,20,12,22,10,0,16,19,20,12,23,10,0,16,20,20,12,24,11,36,12,25,11,43,12,26,11,46,52,12,27,11,5,12,12,10,0,16,12,17,82,12,13,11,42,12,14,11,29,12,15,11,33,11,51,22,12,16,11,35,12,17,11,22,11,23,11,24,11,25,11,27,11,26,11,12,11,13,11,14,11,15,11,16,11,17,18,4,56,16,9,10,0,15,21,21,10,0,16,10,20,6,0,0,0,0,0,0,0,0,33,4,198,2,10,0,16,8,56,14,6,0,0,0,0,0,0,0,0,33,12,18,5,200,2,9,12,18,11,18,4,209,2,11,0,16,9,56,14,6,0,0,0,0,0,0,0,0,33,12,19,5,213,2,11,0,1,9,12,19,11,19,4,216,2,5,218,2,7,10,39,11,38,2,38,3,0,0,6,4,11,0,16,15,20,2,39,3,0,0,6,4,11,0,16,19,20,2,40,3,0,0,6,4,11,0,16,22,20,2,41,3,0,0,6,2,7,3,2,42,3,0,0,6,4,11,0,16,6,20,2,43,3,0,0,6,5,11,0,16,0,11,1,17,128,1,2,44,3,0,0,6,5,11,0,16,0,11,1,17,127,2,45,3,0,0,6,4,11,0,16,0,17,125,2,46,3,0,0,24,18,10,0,16,5,14,1,56,3,4,12,11,0,16,5,14,1,56,17,20,12,2,5,16,11,0,1,56,18,12,2,11,2,2,47,3,0,0,6,4,11,0,16,12,17,82,2,48,3,0,0,6,4,11,0,16,12,17,83,2,49,0,0,0,90,45,13,0,69,91,12,6,13,6,11,0,56,19,11,6,56,2,12,7,14,1,56,20,4,39,11,1,56,21,12,4,13,7,11,4,56,15,12,5,14,7,56,14,6,0,0,0,0,0,0,0,0,36,4,32,11,7,10,2,56,22,11,2,46,17,65,56,23,5,36,11,2,1,11,7,56,24,11,5,12,3,5,43,11,2,1,11,7,12,3,11,3,2,3,3,3,5,1,3,1,4,1,2,3,7,3,14,1,1,3,10,3,11,3,12,3,13,3,4,1,0,3,8,3,0,1,5,1,6,1,7,3,1,3,6,3,9,3,2,0,43,0,111,0],"validator":[161,28,235,11,6,0,0,0,12,1,0,31,2,31,72,3,103,183,4,4,158,5,38,5,196,5,240,3,7,180,9,201,19,8,253,28,96,6,221,29,190,1,10,155,31,156,1,12,183,32,214,27,13,141,60,60,15,201,60,13,0,134,1,1,20,1,23,1,73,1,103,2,21,2,22,2,34,2,71,2,104,2,111,2,131,1,0,101,0,136,1,0,14,4,0,0,13,4,0,0,8,3,0,0,11,3,0,1,9,7,0,3,3,7,1,0,0,4,9,7,0,5,0,12,0,6,1,4,1,0,1,8,2,7,0,9,5,2,0,10,10,2,0,11,12,7,0,12,4,7,0,12,6,8,0,12,7,12,0,13,15,2,0,0,55,0,1,0,0,53,2,3,0,0,26,4,5,0,0,16,4,5,0,0,18,6,5,0,0,86,7,5,0,0,87,7,5,0,0,90,8,5,0,0,89,9,5,0,0,94,9,5,0,0,88,4,5,0,0,93,4,5,0,0,29,10,5,0,0,82,11,5,0,0,46,12,13,0,0,48,12,14,0,0,105,12,15,0,0,49,12,16,0,0,30,12,16,0,0,41,12,17,0,0,83,12,17,0,0,51,12,16,0,0,74,12,16,0,0,79,12,16,0,0,142,1,12,16,0,0,85,12,18,0,0,84,12,18,0,0,52,12,18,0,0,143,1,12,18,0,0,61,12,19,0,0,63,12,19,0,0,64,12,19,0,0,68,12,19,0,0,66,12,20,0,0,65,12,20,0,0,62,12,20,0,0,69,12,20,0,0,72,12,21,0,0,59,12,22,0,0,110,12,22,0,0,98,12,22,0,0,109,12,22,0,0,141,1,12,22,0,0,95,4,5,0,0,75,12,22,0,0,76,12,22,0,0,38,12,22,0,0,25,12,22,0,0,78,23,24,0,0,102,12,25,0,0,42,26,13,0,0,44,27,13,1,0,0,43,28,13,1,0,0,57,11,5,0,0,122,29,5,0,0,120,29,5,0,0,121,29,5,0,0,130,1,29,5,0,0,123,29,5,0,0,113,29,5,0,0,125,29,5,0,0,115,29,5,0,0,126,29,5,0,0,116,29,5,0,0,128,1,29,5,0,0,118,29,5,0,0,127,30,5,0,0,117,30,5,0,0,124,29,5,0,0,114,29,5,0,0,129,1,29,5,0,0,119,29,5,0,0,31,6,5,0,0,132,1,14,5,0,0,133,1,31,5,0,0,54,32,3,0,1,103,31,38,0,2,108,62,31,1,0,3,24,64,62,1,0,3,36,67,51,1,0,3,45,64,13,1,0,3,47,64,13,1,0,3,70,5,34,1,0,3,96,51,34,1,0,4,37,38,35,0,5,53,40,41,0,6,139,1,45,22,1,0,7,32,51,5,1,3,8,40,62,25,1,8,10,33,46,22,0,10,92,46,15,0,11,56,31,39,0,12,17,42,5,0,12,27,42,5,0,12,28,58,5,0,12,46,48,13,0,12,53,40,61,0,12,75,48,22,0,12,76,48,22,0,12,78,60,24,0,12,81,49,5,0,12,82,59,5,0,12,86,47,5,0,12,90,54,22,0,12,97,53,22,0,12,99,53,22,0,12,106,48,22,0,13,57,66,25,0,13,140,1,56,57,0,82,31,82,35,86,44,87,50,87,55,88,61,52,35,52,31,51,35,51,31,80,51,78,51,83,35,83,31,81,35,79,35,81,31,79,31,77,1,14,5,10,2,10,2,10,2,10,2,8,6,8,6,8,12,8,12,8,6,8,6,8,6,8,6,8,7,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,11,1,8,1,2,7,8,1,3,0,1,7,8,1,4,7,8,1,11,8,1,8,10,5,7,8,11,3,7,8,1,8,14,7,8,11,3,7,8,1,8,16,3,2,7,8,1,11,8,1,8,10,2,7,8,1,7,8,11,1,6,8,1,1,1,1,6,8,0,1,5,1,6,8,6,1,6,8,12,1,6,10,2,1,6,11,5,1,8,6,1,6,11,5,1,10,2,1,6,8,9,1,3,2,6,8,1,3,1,8,13,1,8,9,2,6,8,1,6,8,1,2,6,11,5,1,9,0,6,9,0,2,6,11,5,1,9,0,6,11,5,1,9,0,2,7,8,1,10,2,3,7,8,1,10,2,10,2,1,10,2,4,8,0,3,3,7,8,11,22,5,8,6,8,6,8,6,8,6,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,8,6,11,5,1,8,6,10,2,11,5,1,8,6,11,5,1,8,6,8,7,10,2,10,2,10,2,8,6,8,6,8,12,8,12,1,11,5,1,9,0,1,8,6,8,1,1,1,1,1,1,1,8,0,1,2,1,8,4,1,8,12,1,7,8,11,1,8,7,2,7,8,15,3,2,3,3,1,8,10,1,6,11,8,1,9,0,1,6,8,11,5,7,8,15,11,8,1,8,10,5,3,7,8,11,1,6,8,15,1,7,8,15,1,8,2,1,9,0,4,3,3,3,3,1,6,8,14,3,7,8,15,8,14,7,8,11,1,8,3,1,6,8,16,1,6,5,2,7,8,15,11,8,1,8,10,2,7,8,15,7,8,11,2,6,8,15,3,1,8,15,1,6,9,0,29,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,6,11,5,1,9,0,2,1,1,2,5,7,8,11,1,7,11,5,1,9,0,3,8,9,8,15,5,3,66,97,103,7,66,97,108,97,110,99,101,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,19,83,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,21,85,110,115,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,3,85,114,108,9,86,97,108,105,100,97,116,111,114,17,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,8,97,99,116,105,118,97,116,101,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,6,97,109,111,117,110,116,5,97,115,99,105,105,3,98,97,103,7,98,97,108,97,110,99,101,3,98,99,115,6,98,111,114,114,111,119,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,10,100,101,97,99,116,105,118,97,116,101,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,11,100,101,115,99,114,105,112,116,105,111,110,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,5,101,112,111,99,104,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,10,102,114,111,109,95,97,115,99,105,105,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,2,105,100,9,105,109,97,103,101,95,117,114,108,12,105,115,95,100,117,112,108,105,99,97,116,101,13,105,115,95,101,113,117,97,108,95,115,111,109,101,23,105,115,95,101,113,117,97,108,95,115,111,109,101,95,97,110,100,95,118,97,108,117,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,8,109,101,116,97,100,97,116,97,4,110,97,109,101,11,110,101,116,95,97,100,100,114,101,115,115,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,20,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,102,114,111,109,95,109,101,116,97,100,97,116,97,12,110,101,119,95,109,101,116,97,100,97,116,97,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,20,110,101,120,116,95,101,112,111,99,104,95,103,97,115,95,112,114,105,99,101,22,110,101,120,116,95,101,112,111,99,104,95,110,101,116,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,22,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,32,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,16,110,101,120,116,95,101,112,111,99,104,95,115,116,97,107,101,25,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,7,112,111,111,108,95,105,100,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,16,112,114,105,110,99,105,112,97,108,95,97,109,111,117,110,116,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,21,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,13,114,101,119,97,114,100,95,97,109,111,117,110,116,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,111,109,101,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,12,115,116,97,107,101,95,97,109,111,117,110,116,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,14,115,116,97,107,101,114,95,97,100,100,114,101,115,115,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,6,115,116,114,105,110,103,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,11,115,117,105,95,98,97,108,97,110,99,101,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,111,95,98,121,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,10,116,120,95,99,111,110,116,101,120,116,15,117,110,115,116,97,107,105,110,103,95,101,112,111,99,104,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,3,117,114,108,17,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,21,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,95,98,99,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,12,118,111,116,105,110,103,95,112,111,119,101,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,19,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,100,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,3,8,102,0,0,0,0,0,0,0,3,8,208,7,0,0,0,0,0,0,3,8,0,1,0,0,0,0,0,0,3,8,160,134,1,0,0,0,0,0,0,2,22,105,5,85,10,2,52,10,2,143,1,10,2,84,10,2,49,8,6,30,8,6,41,8,12,83,8,12,50,8,6,74,8,6,79,8,6,142,1,8,6,66,11,5,1,10,2,65,11,5,1,10,2,62,11,5,1,10,2,69,11,5,1,10,2,60,11,5,1,8,6,63,11,5,1,8,6,64,11,5,1,8,6,68,11,5,1,8,6,35,8,7,1,2,10,48,8,0,141,1,3,72,8,9,38,3,101,8,15,25,3,67,3,59,3,58,3,35,8,7,2,2,5,77,8,9,135,1,5,100,5,33,3,19,3,3,2,7,77,8,9,135,1,5,100,5,97,3,112,3,80,3,91,3,0,3,0,0,33,68,11,0,12,14,11,1,12,25,11,2,12,29,11,3,12,30,11,4,12,31,11,5,12,32,11,6,12,33,11,7,12,34,11,8,12,35,11,9,12,15,11,10,12,16,11,11,12,17,11,12,12,18,56,0,12,19,56,0,12,20,56,0,12,21,56,0,12,22,56,1,12,23,56,1,12,24,56,1,12,26,56,1,12,27,11,13,12,28,11,14,11,25,11,29,11,30,11,31,11,32,11,33,11,34,11,35,11,15,11,16,11,17,11,18,11,19,11,22,11,20,11,21,11,23,11,24,11,26,11,27,11,28,18,0,2,1,3,0,0,36,137,1,14,9,65,37,7,17,37,4,11,14,10,65,37,7,17,37,12,16,5,13,9,12,16,11,16,4,21,14,11,65,37,7,17,37,12,17,5,23,9,12,17,11,17,4,31,14,12,65,37,7,17,37,12,18,5,33,9,12,18,11,18,4,41,14,5,65,37,7,17,37,12,19,5,43,9,12,19,11,19,4,51,14,6,65,37,7,17,37,12,20,5,53,9,12,20,11,20,4,61,14,7,65,37,7,17,37,12,21,5,63,9,12,21,11,21,4,71,14,8,65,37,7,17,37,12,22,5,73,9,12,22,11,22,4,76,5,80,11,15,1,7,9,39,10,14,7,16,37,4,85,5,89,11,15,1,7,8,39,10,13,7,18,35,4,94,5,98,11,15,1,7,15,39,11,0,11,1,11,2,11,3,11,4,11,5,17,76,17,84,11,6,17,76,17,84,11,7,17,91,11,8,17,91,11,9,17,76,17,84,11,10,17,76,17,84,11,11,17,76,17,84,11,12,17,76,17,84,10,15,17,85,17,0,12,23,14,23,17,73,11,23,11,13,11,14,11,15,17,75,2,2,3,0,0,5,5,11,0,15,0,11,1,17,93,2,3,3,0,0,5,5,11,0,15,0,11,1,17,92,2,4,3,0,0,5,13,10,0,16,1,20,10,0,15,2,21,10,0,16,3,20,11,0,15,4,21,2,5,3,0,0,43,57,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,8,5,14,11,0,1,11,3,1,7,11,39,10,3,46,17,89,6,1,0,0,0,0,0,0,0,22,12,5,10,0,15,0,11,1,10,2,11,5,10,3,17,102,10,0,16,0,17,95,4,34,10,0,15,0,17,100,10,0,16,5,20,10,4,22,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,11,2,11,3,46,17,89,11,4,18,2,56,3,2,6,3,0,0,22,46,10,3,46,17,89,6,0,0,0,0,0,0,0,0,33,4,7,5,13,11,0,1,11,3,1,7,12,39,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,21,5,27,11,0,1,11,3,1,7,11,39,10,0,15,0,11,1,11,2,6,0,0,0,0,0,0,0,0,11,3,17,102,10,0,15,0,17,100,10,0,16,5,20,11,4,22,11,0,15,5,21,2,7,3,0,0,52,43,14,1,17,105,12,3,14,1,17,104,12,5,10,0,15,0,11,1,10,2,17,103,12,6,10,6,10,3,23,12,4,10,0,16,5,20,11,6,23,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,10,2,46,17,90,11,5,11,2,46,17,89,11,3,11,4,18,3,56,4,2,8,3,0,0,5,28,10,2,7,18,35,4,5,5,9,11,0,1,7,15,39,14,1,17,108,20,10,0,16,6,16,7,20,33,4,19,5,23,11,0,1,7,14,39,11,2,11,0,15,1,21,2,9,3,0,0,5,41,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,2,7,18,35,4,14,5,18,11,0,1,7,15,39,14,1,17,108,20,10,0,16,6,16,7,20,33,4,28,5,32,11,0,1,7,14,39,10,2,10,0,15,1,21,11,2,11,0,15,2,21,2,10,3,0,0,5,14,10,1,7,16,37,4,5,5,9,11,0,1,7,8,39,11,1,11,0,15,3,21,2,11,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,1,7,16,37,4,14,5,18,11,0,1,7,8,39,11,1,11,0,15,4,21,2,12,3,0,0,5,14,10,0,16,5,20,14,1,56,2,22,10,0,15,5,21,11,0,15,0,11,1,17,94,2,13,3,0,0,5,16,10,0,15,0,11,1,17,101,10,0,46,17,40,11,0,16,5,20,33,4,13,5,15,7,11,39,2,14,1,0,0,5,4,11,0,16,0,17,95,2,15,1,0,0,5,3,11,0,16,6,2,16,1,0,0,5,5,11,0,16,6,16,7,20,2,17,1,0,0,5,4,11,0,16,6,16,8,2,18,1,0,0,5,4,11,0,16,6,16,9,2,19,1,0,0,5,4,11,0,16,6,16,10,2,20,1,0,0,5,4,11,0,16,6,16,11,2,21,1,0,0,5,4,11,0,16,6,16,12,2,22,1,0,0,5,4,11,0,16,6,16,13,2,23,1,0,0,5,4,11,0,16,6,16,14,2,24,1,0,0,5,4,11,0,16,6,16,15,2,25,1,0,0,5,4,11,0,16,6,16,16,2,26,1,0,0,5,4,11,0,16,6,16,17,2,27,1,0,0,5,4,11,0,16,6,16,18,2,28,1,0,0,5,4,11,0,16,6,16,19,2,29,1,0,0,5,4,11,0,16,6,16,20,2,30,1,0,0,5,4,11,0,16,6,16,21,2,31,1,0,0,5,4,11,0,16,6,16,22,2,32,1,0,0,5,4,11,0,16,6,16,23,2,33,1,0,0,5,4,11,0,16,6,16,24,2,34,1,0,0,5,4,11,0,16,6,16,25,2,35,1,0,0,5,4,11,0,16,6,16,26,2,36,1,0,0,5,4,11,0,16,6,16,27,2,37,1,0,0,5,3,11,0,16,28,2,38,1,0,0,5,4,11,0,16,1,20,2,39,1,0,0,5,5,40,11,0,16,0,17,106,2,40,1,0,0,5,4,11,0,16,0,17,106,2,41,1,0,0,5,3,11,0,17,40,2,42,1,0,0,5,4,11,0,16,29,20,2,43,3,0,0,5,5,11,1,11,0,15,29,21,2,44,1,0,0,5,4,11,0,16,0,17,97,2,45,1,0,0,5,4,11,0,16,0,17,98,2,46,1,0,0,5,4,11,0,16,2,20,2,47,1,0,0,5,4,11,0,16,4,20,2,48,1,0,0,5,5,11,0,16,0,11,1,17,99,2,49,1,0,0,5,4,11,0,16,0,56,5,2,50,1,0,0,63,151,3,10,0,16,6,16,7,20,10,1,16,6,16,7,20,33,4,13,8,12,2,5,23,10,0,16,6,16,8,20,10,1,16,6,16,8,20,33,12,2,11,2,4,28,8,12,13,5,38,10,0,16,6,16,12,20,10,1,16,6,16,12,20,33,12,13,11,13,4,43,8,12,24,5,53,10,0,16,6,16,13,20,10,1,16,6,16,13,20,33,12,24,11,24,4,58,8,12,25,5,68,10,0,16,6,16,16,20,10,1,16,6,16,16,20,33,12,25,11,25,4,73,8,12,26,5,83,10,0,16,6,16,18,20,10,1,16,6,16,18,20,33,12,26,11,26,4,88,8,12,27,5,98,10,0,16,6,16,18,20,10,1,16,6,16,19,20,33,12,27,11,27,4,103,8,12,28,5,113,10,0,16,6,16,19,20,10,1,16,6,16,19,20,33,12,28,11,28,4,118,8,12,29,5,128,1,10,0,16,6,16,19,20,10,1,16,6,16,18,20,33,12,29,11,29,4,133,1,8,12,30,5,141,1,10,0,16,6,16,20,10,1,16,6,16,20,56,6,12,30,11,30,4,146,1,8,12,3,5,154,1,10,0,16,6,16,21,10,1,16,6,16,21,56,6,12,3,11,3,4,159,1,8,12,4,5,167,1,10,0,16,6,16,24,10,1,16,6,16,24,56,7,12,4,11,4,4,172,1,8,12,5,5,180,1,10,0,16,6,16,26,10,1,16,6,16,26,56,7,12,5,11,5,4,185,1,8,12,6,5,193,1,10,0,16,6,16,26,10,1,16,6,16,27,56,7,12,6,11,6,4,198,1,8,12,7,5,206,1,10,0,16,6,16,27,10,1,16,6,16,27,56,7,12,7,11,7,4,211,1,8,12,8,5,219,1,10,0,16,6,16,27,10,1,16,6,16,26,56,7,12,8,11,8,4,224,1,8,12,9,5,232,1,10,0,16,6,16,20,10,1,16,6,16,12,56,8,12,9,11,9,4,237,1,8,12,10,5,245,1,10,0,16,6,16,21,10,1,16,6,16,13,56,8,12,10,11,10,4,250,1,8,12,11,5,130,2,10,0,16,6,16,24,10,1,16,6,16,16,56,9,12,11,11,11,4,135,2,8,12,12,5,143,2,10,0,16,6,16,26,10,1,16,6,16,18,56,9,12,12,11,12,4,148,2,8,12,14,5,156,2,10,0,16,6,16,26,10,1,16,6,16,19,56,9,12,14,11,14,4,161,2,8,12,15,5,169,2,10,0,16,6,16,27,10,1,16,6,16,19,56,9,12,15,11,15,4,174,2,8,12,16,5,182,2,10,0,16,6,16,27,10,1,16,6,16,18,56,9,12,16,11,16,4,187,2,8,12,17,5,195,2,10,1,16,6,16,20,10,0,16,6,16,12,56,8,12,17,11,17,4,200,2,8,12,18,5,208,2,10,1,16,6,16,21,10,0,16,6,16,13,56,8,12,18,11,18,4,213,2,8,12,19,5,221,2,10,1,16,6,16,24,10,0,16,6,16,16,56,9,12,19,11,19,4,226,2,8,12,20,5,234,2,10,1,16,6,16,26,10,0,16,6,16,18,56,9,12,20,11,20,4,239,2,8,12,21,5,247,2,10,1,16,6,16,26,10,0,16,6,16,19,56,9,12,21,11,21,4,252,2,8,12,22,5,132,3,10,1,16,6,16,27,10,0,16,6,16,19,56,9,12,22,11,22,4,141,3,11,0,1,11,1,1,8,12,23,5,149,3,11,1,16,6,16,27,11,0,16,6,16,18,56,9,12,23,11,23,2,51,0,0,0,13,17,10,0,56,10,4,10,11,1,1,11,0,1,9,12,2,5,15,11,0,56,11,11,1,33,12,2,11,2,2,52,0,0,0,65,26,10,0,56,10,4,6,8,12,2,5,9,10,1,56,10,12,2,11,2,4,18,11,1,1,11,0,1,9,12,3,5,24,11,0,56,11,11,1,56,11,33,12,3,11,3,2,53,3,0,0,15,25,10,1,46,17,90,12,2,10,2,10,0,16,6,16,7,20,33,4,12,5,18,11,0,1,11,1,1,7,13,39,11,2,11,1,17,107,11,0,15,28,21,2,54,3,0,0,5,18,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,11,0,15,6,15,8,21,2,55,3,0,0,5,18,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,11,0,15,6,15,9,21,2,56,3,0,0,5,17,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,91,11,0,15,6,15,10,21,2,57,3,0,0,5,17,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,91,11,0,15,6,15,11,21,2,58,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,20,21,11,0,16,6,17,73,2,59,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,12,21,11,0,16,6,17,73,2,60,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,21,21,11,0,16,6,17,73,2,61,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,13,21,11,0,16,6,17,73,2,62,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,22,21,11,0,16,6,17,73,2,63,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,14,21,11,0,16,6,17,73,2,64,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,23,21,11,0,16,6,17,73,2,65,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,15,21,11,0,16,6,17,73,2,66,3,0,0,5,16,11,1,56,13,10,0,15,6,15,24,21,11,2,56,13,10,0,15,6,15,25,21,11,0,16,6,17,73,2,67,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,16,21,11,2,10,0,15,6,15,17,21,11,0,16,6,17,73,2,68,3,0,0,5,10,11,1,56,13,10,0,15,6,15,26,21,11,0,16,6,17,73,2,69,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,18,21,11,0,16,6,17,73,2,70,3,0,0,5,10,11,1,56,13,10,0,15,6,15,27,21,11,0,16,6,17,73,2,71,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,19,21,11,0,16,6,17,73,2,72,3,0,0,5,143,1,10,0,46,17,29,56,14,4,18,10,0,15,6,15,20,56,15,10,0,15,6,15,12,21,56,1,10,0,15,6,15,20,21,10,0,46,17,30,56,14,4,36,10,0,15,6,15,21,56,15,10,0,15,6,15,13,21,56,1,10,0,15,6,15,21,21,10,0,46,17,31,56,14,4,54,10,0,15,6,15,22,56,15,10,0,15,6,15,14,21,56,1,10,0,15,6,15,22,21,10,0,46,17,32,56,14,4,72,10,0,15,6,15,23,56,15,10,0,15,6,15,15,21,56,1,10,0,15,6,15,23,21,10,0,46,17,33,56,16,4,103,10,0,15,6,15,24,56,17,10,0,15,6,15,16,21,56,0,10,0,15,6,15,24,21,10,0,15,6,15,25,56,17,10,0,15,6,15,17,21,56,0,10,0,15,6,15,25,21,10,0,46,17,35,56,16,4,121,10,0,15,6,15,26,56,17,10,0,15,6,15,18,21,56,0,10,0,15,6,15,26,21,10,0,46,17,36,56,16,4,140,1,10,0,15,6,15,27,56,17,10,0,15,6,15,19,21,56,0,11,0,15,6,15,27,21,5,142,1,11,0,1,2,73,1,0,0,5,4,11,0,56,18,17,74,2,74,1,2,0,75,0,0,0,68,24,14,0,16,7,20,12,6,10,3,17,96,12,5,11,6,10,3,17,107,12,4,11,0,6,0,0,0,0,0,0,0,0,11,4,10,1,11,5,10,2,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,17,85,18,1,2,1,4,1,7,1,3,1,8,1,5,1,6,1,0,0,0,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,1,0,4,0,2,0,3,0,17,0,18,0,19,0,20,0,13,0,14,0,15,0,16,1,2,1,1,0,39,0,107,0,137,1,0,138,1,0,141,1,0],"validator_cap":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,20,3,28,42,4,70,4,5,74,54,7,128,1,226,2,8,226,3,64,6,162,4,34,10,196,4,13,12,209,4,112,13,193,5,4,15,197,5,6,0,18,1,10,1,14,1,15,0,3,12,0,0,4,2,0,1,0,7,0,1,2,4,0,3,1,2,0,0,16,0,1,0,0,20,2,1,0,0,9,3,4,0,0,8,0,5,0,1,6,13,4,1,8,1,7,10,11,0,2,11,14,6,1,12,3,12,8,9,0,4,12,6,12,1,6,8,0,1,6,5,1,6,8,1,2,5,7,8,4,1,8,2,1,8,1,0,4,1,8,0,8,2,5,1,6,8,4,1,5,1,7,8,4,1,8,3,1,8,0,1,6,9,0,2,9,0,5,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,28,97,117,116,104,111,114,105,122,101,114,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,6,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,3,5,5,1,2,1,5,5,0,3,0,0,6,3,11,0,16,0,2,1,3,0,0,6,3,11,0,16,1,2,2,3,0,0,7,35,10,1,46,17,7,12,5,10,5,7,0,33,4,11,8,12,2,5,15,11,5,10,0,33,12,2,11,2,4,18,5,22,11,1,1,6,0,0,0,0,0,0,0,0,39,11,1,17,5,10,0,18,0,12,3,14,3,56,0,12,4,11,3,11,0,56,1,11,4,2,3,3,0,0,6,5,11,0,16,0,20,18,1,2,0,1,1,0,0,13,0,17,0,19,0],"validator_set":[161,28,235,11,6,0,0,0,12,1,0,51,2,51,112,3,163,1,134,6,4,169,7,133,1,5,174,8,210,9,7,128,18,183,23,8,183,41,96,6,151,42,195,1,10,218,43,141,1,12,231,44,251,34,13,226,79,16,15,242,79,5,0,159,1,1,103,1,167,1,2,30,2,31,2,57,2,101,2,113,2,141,1,2,145,1,2,146,1,2,152,1,2,165,1,2,166,1,0,137,1,0,155,1,0,158,1,0,163,1,0,170,1,0,19,4,0,0,14,3,0,0,15,3,0,0,16,3,0,0,17,3,0,1,4,7,1,0,0,3,0,12,0,4,1,4,1,0,1,6,3,7,0,7,2,6,1,2,0,7,6,6,1,2,0,8,7,2,0,9,9,12,2,7,1,4,1,10,10,4,1,4,1,11,11,2,0,12,21,7,2,1,0,0,0,13,22,7,1,3,0,14,5,7,0,14,8,8,0,15,13,4,0,16,12,12,0,16,18,2,0,17,20,4,0,0,96,0,1,0,0,124,2,3,0,0,126,4,3,0,0,123,5,3,0,0,28,6,3,0,0,125,4,3,0,0,122,7,3,0,0,128,1,8,3,0,0,127,9,3,0,0,27,10,3,0,0,154,1,11,3,0,0,52,12,3,0,0,47,13,14,0,0,149,1,13,14,0,0,162,1,15,14,0,0,160,1,15,14,0,0,161,1,15,16,0,0,139,1,13,17,0,0,99,13,14,0,0,81,15,18,0,0,84,6,18,0,0,83,19,18,0,0,43,19,14,0,0,85,6,18,0,0,42,20,14,0,0,68,21,22,0,0,60,23,24,0,0,61,25,24,0,0,71,26,27,0,0,72,28,22,0,0,65,29,22,0,0,75,30,22,0,0,73,31,22,0,0,74,31,22,0,0,76,23,32,0,0,66,33,32,0,0,67,15,32,0,0,70,15,32,0,0,169,1,34,35,0,0,114,36,3,0,0,117,37,3,0,0,35,38,3,0,0,116,39,3,0,0,133,1,40,3,0,0,115,41,3,0,0,34,42,14,0,0,26,43,3,0,0,38,44,45,0,0,39,46,47,0,0,40,48,49,0,0,37,50,49,0,0,51,51,3,0,0,54,52,3,0,0,144,1,26,14,0,0,24,13,42,0,0,90,15,18,0,0,87,53,18,0,1,49,111,81,1,0,1,59,80,81,1,0,1,89,79,18,1,0,1,100,3,111,1,0,1,132,1,81,111,1,0,2,41,82,18,1,0,2,86,125,18,1,0,2,121,97,81,1,0,3,96,56,66,0,4,50,148,1,3,1,0,4,92,149,1,14,1,0,4,134,1,147,1,148,1,1,0,4,164,1,84,14,1,0,5,53,81,3,1,3,6,77,110,16,1,8,7,96,103,104,1,2,7,97,101,102,1,2,7,112,105,101,1,2,9,25,60,3,2,7,4,9,32,68,87,2,7,4,9,33,73,89,2,7,4,9,41,68,18,2,7,4,9,96,56,57,2,7,4,9,121,73,74,2,7,4,10,32,109,110,1,4,10,33,114,115,1,4,10,55,56,61,1,4,10,86,106,18,1,4,10,94,106,14,1,4,10,111,135,1,81,1,4,10,118,77,3,1,4,11,56,72,14,0,11,129,1,72,59,0,12,41,93,18,2,1,0,12,55,3,65,2,1,0,12,64,93,87,2,1,0,12,69,94,89,2,1,0,12,79,96,3,2,1,0,12,86,130,1,18,2,1,0,12,93,130,1,131,1,2,1,0,12,110,142,1,95,2,1,0,12,121,94,95,2,1,0,12,131,1,130,1,14,2,1,0,13,41,132,1,18,1,3,13,80,143,1,131,1,1,3,13,86,134,1,18,1,3,13,121,133,1,3,1,3,14,106,86,16,0,15,23,75,3,0,15,26,22,3,0,15,36,32,14,0,15,45,75,3,0,15,46,150,1,3,0,15,52,22,3,0,15,62,32,14,0,15,82,108,18,0,15,88,32,18,0,15,102,32,123,0,15,109,152,1,153,1,0,15,115,138,1,3,0,15,122,85,3,0,15,127,75,3,0,15,128,1,88,3,0,15,136,1,32,14,0,15,138,1,32,16,0,15,142,1,32,59,0,15,150,1,32,14,0,15,170,1,32,14,0,16,98,121,35,0,16,153,1,121,117,0,16,168,1,116,117,0,17,44,69,70,0,17,48,70,58,0,17,95,90,22,0,18,119,3,14,0,18,130,1,43,3,0,18,151,1,3,14,0,79,55,75,55,83,58,79,62,79,63,91,64,78,63,75,63,80,63,80,55,75,62,87,58,59,14,58,14,62,14,69,83,78,55,76,55,78,62,77,62,90,64,98,64,93,64,94,64,64,58,73,14,72,14,74,14,85,58,81,58,77,63,61,14,60,14,57,14,82,58,71,122,63,14,70,127,90,129,1,98,129,1,96,129,1,93,129,1,100,59,103,59,102,59,84,58,86,58,70,136,1,91,98,94,98,95,129,1,97,129,1,101,59,99,98,90,98,92,98,68,83,67,83,66,83,92,129,1,62,59,70,154,1,2,10,8,19,7,8,14,1,8,0,3,7,8,0,8,19,7,8,14,0,2,7,8,0,7,8,14,3,7,8,0,3,7,8,14,2,6,8,0,6,8,19,4,7,8,0,5,11,7,1,8,11,7,8,14,3,7,8,0,8,18,7,8,14,3,7,8,0,3,6,8,14,9,7,8,0,7,11,7,1,8,11,7,11,7,1,8,11,7,11,15,2,5,11,16,1,5,3,3,3,3,7,8,14,6,7,8,0,3,3,3,7,11,15,2,5,11,16,1,5,7,8,14,1,7,8,0,1,6,8,0,1,3,2,6,8,0,5,1,8,8,1,6,11,12,2,8,8,5,1,1,2,6,10,8,19,6,8,19,2,6,11,13,1,8,19,6,8,19,2,7,8,0,5,1,7,8,19,2,6,10,8,19,5,1,11,5,1,3,2,6,11,13,1,8,19,5,2,6,10,8,19,6,10,5,1,10,3,2,7,10,8,19,5,3,7,8,0,5,1,3,7,8,0,6,8,21,1,2,7,8,0,6,8,14,1,6,8,19,3,7,8,0,5,2,3,7,8,0,6,8,20,2,1,8,21,3,7,8,0,7,11,15,2,5,11,16,1,5,7,8,14,5,7,8,0,8,19,7,11,15,2,5,11,16,1,5,1,7,8,14,2,7,11,15,2,5,11,16,1,5,5,2,7,8,0,3,1,7,10,3,2,7,10,8,19,7,8,14,1,6,10,8,19,1,7,10,8,19,4,10,3,3,6,10,3,6,10,3,4,3,11,15,2,3,3,3,11,15,2,3,3,2,6,8,0,11,15,2,5,11,16,1,5,1,10,5,4,6,10,8,19,3,3,3,2,10,3,10,3,9,6,10,8,19,3,3,10,3,10,3,3,11,15,2,3,3,3,11,15,2,3,3,6,7,10,8,19,6,10,3,6,10,3,7,11,7,1,8,11,7,11,7,1,8,11,7,8,14,6,3,6,10,8,19,6,10,3,6,10,3,6,11,15,2,5,11,16,1,5,6,10,5,2,6,8,0,8,8,6,3,3,11,12,2,8,8,5,3,6,8,19,8,0,2,8,8,5,1,7,8,14,1,11,12,2,9,0,9,1,1,8,19,1,5,3,7,11,12,2,9,0,9,1,9,0,9,1,1,11,13,1,9,0,2,8,8,8,22,2,5,8,22,2,5,3,1,11,15,2,9,0,9,1,1,8,6,4,6,8,19,6,8,19,1,5,2,6,11,12,2,9,0,9,1,9,0,2,8,19,7,8,14,1,8,22,3,8,8,8,19,5,1,6,8,14,2,7,11,12,2,9,0,9,1,9,0,1,9,1,2,7,8,19,3,5,6,8,19,6,8,19,1,8,19,5,2,7,11,13,1,9,0,9,0,3,5,3,11,5,1,3,1,6,11,5,1,9,0,1,7,11,5,1,9,0,1,9,0,2,6,10,9,0,6,9,0,1,8,11,1,6,11,7,1,9,0,4,7,8,19,11,7,1,8,11,5,7,8,14,1,6,8,18,1,6,9,1,3,7,8,19,8,18,7,8,14,1,7,9,1,1,7,8,22,14,11,15,2,5,11,16,1,5,6,10,5,10,3,10,3,11,15,2,3,3,11,15,2,3,3,3,10,5,3,3,3,3,10,3,10,3,8,3,3,7,3,3,8,19,8,19,5,6,8,19,2,6,11,15,2,9,0,9,1,6,9,0,2,7,11,15,2,9,0,9,1,6,9,0,2,9,0,9,1,3,7,11,15,2,9,0,9,1,9,0,9,1,2,7,10,9,0,3,2,3,3,10,10,11,9,1,3,3,3,11,10,1,3,3,3,3,3,6,8,19,6,10,8,19,1,11,9,1,3,2,3,9,0,1,11,9,1,9,0,1,10,11,9,1,9,0,1,11,10,1,9,0,1,7,11,10,1,9,0,1,6,11,13,1,9,0,3,3,3,3,2,6,8,19,6,8,19,2,6,11,13,1,9,0,3,1,6,9,0,1,11,5,1,9,0,5,5,3,11,5,1,3,3,10,3,4,3,3,11,5,1,3,11,5,1,3,2,7,11,13,1,9,0,3,1,7,9,0,1,6,8,21,1,6,5,2,3,11,5,1,3,6,1,1,3,3,11,5,1,3,11,5,1,3,5,5,6,8,19,8,8,5,6,8,19,1,6,8,20,1,8,20,1,6,8,8,2,3,8,19,1,6,10,9,0,3,3,5,8,8,1,8,4,7,6,5,6,5,3,3,6,5,10,5,7,11,16,1,5,2,5,11,16,1,5,1,6,11,15,2,9,0,9,1,1,10,9,0,2,6,11,16,1,9,0,6,9,0,2,7,11,16,1,9,0,6,9,0,1,6,11,16,1,9,0,1,7,11,13,1,9,0,1,8,3,6,3,3,3,3,3,3,2,7,8,19,7,8,14,4,3,3,3,6,8,19,7,11,15,2,3,3,11,15,2,3,3,4,4,3,3,3,5,10,5,6,10,8,19,11,16,1,5,10,5,5,1,7,11,15,2,9,0,9,1,1,11,16,1,9,0,6,3,3,4,10,3,10,3,3,17,3,3,3,10,3,3,10,3,3,4,3,3,3,3,3,3,3,3,4,8,3,3,11,7,1,8,11,3,7,8,19,5,4,11,7,1,8,11,2,7,11,7,1,9,0,3,1,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,2,7,8,19,11,7,1,8,11,8,10,5,3,3,3,3,10,5,6,8,19,5,2,6,8,19,3,1,8,17,1,8,2,3,66,97,103,7,66,97,108,97,110,99,101,5,69,110,116,114,121,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,13,80,114,105,111,114,105,116,121,81,117,101,117,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,23,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,25,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,86,50,18,86,97,108,105,100,97,116,111,114,74,111,105,110,69,118,101,110,116,19,86,97,108,105,100,97,116,111,114,76,101,97,118,101,69,118,101,110,116,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,6,86,101,99,77,97,112,6,86,101,99,83,101,116,8,97,99,116,105,118,97,116,101,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,3,97,100,100,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,18,97,116,95,114,105,115,107,95,118,97,108,105,100,97,116,111,114,115,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,22,99,97,108,99,117,108,97,116,101,95,116,111,116,97,108,95,115,116,97,107,101,115,38,99,108,101,97,110,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,95,108,101,97,118,105,110,103,95,118,97,108,105,100,97,116,111,114,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,36,99,111,109,112,117,116,101,95,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,26,99,111,109,112,117,116,101,95,114,101,119,97,114,100,95,97,100,106,117,115,116,109,101,110,116,115,26,99,111,109,112,117,116,101,95,115,108,97,115,104,101,100,95,118,97,108,105,100,97,116,111,114,115,38,99,111,109,112,117,116,101,95,117,110,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,8,99,111,110,116,97,105,110,115,25,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,116,97,98,108,101,118,101,99,20,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,118,101,99,9,99,114,101,97,116,101,95,118,49,10,100,101,97,99,116,105,118,97,116,101,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,17,100,105,115,116,114,105,98,117,116,101,95,114,101,119,97,114,100,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,27,101,109,105,116,95,118,97,108,105,100,97,116,111,114,95,101,112,111,99,104,95,101,118,101,110,116,115,5,101,109,112,116,121,5,101,112,111,99,104,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,14,102,105,110,100,95,118,97,108,105,100,97,116,111,114,29,102,105,110,100,95,118,97,108,105,100,97,116,111,114,95,102,114,111,109,95,116,97,98,108,101,95,118,101,99,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,3,103,101,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,24,103,101,116,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,37,103,101,116,95,99,97,110,100,105,100,97,116,101,95,111,114,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,7,103,101,116,95,109,117,116,25,103,101,116,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,95,114,101,102,21,103,101,116,95,118,97,108,105,100,97,116,111,114,95,105,110,100,105,99,101,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,114,101,102,2,105,100,19,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,12,105,115,95,100,117,112,108,105,99,97,116,101,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,34,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,35,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,21,105,115,95,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,22,105,115,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,12,105,115,95,118,111,108,117,110,116,97,114,121,4,106,111,105,110,4,107,101,121,115,6,108,101,110,103,116,104,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,25,112,101,110,100,105,110,103,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,16,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,7,112,111,111,108,95,105,100,19,112,111,111,108,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,24,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,3,112,111,112,8,112,111,112,95,98,97,99,107,7,112,111,112,95,109,97,120,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,24,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,26,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,115,27,112,114,111,99,101,115,115,95,118,97,108,105,100,97,116,111,114,95,100,101,112,97,114,116,117,114,101,9,112,117,115,104,95,98,97,99,107,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,26,114,101,102,101,114,101,110,99,101,95,103,97,115,95,115,117,114,118,101,121,95,113,117,111,116,101,6,114,101,109,111,118,101,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,6,115,101,110,100,101,114,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,105,122,101,4,115,111,109,101,17,115,111,114,116,95,114,101,109,111,118,97,108,95,108,105,115,116,5,115,112,108,105,116,5,115,116,97,107,101,12,115,116,97,107,101,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,27,115,116,111,114,97,103,101,95,102,117,110,100,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,29,115,117,109,95,118,111,116,105,110,103,95,112,111,119,101,114,95,98,121,95,97,100,100,114,101,115,115,101,115,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,26,116,97,108,108,121,105,110,103,95,114,117,108,101,95,103,108,111,98,97,108,95,115,99,111,114,101,23,116,97,108,108,121,105,110,103,95,114,117,108,101,95,114,101,112,111,114,116,101,114,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,39,117,112,100,97,116,101,95,97,110,100,95,112,114,111,99,101,115,115,95,108,111,119,95,115,116,97,107,101,95,100,101,112,97,114,116,117,114,101,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,20,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,10,3,1,0,10,5,1,0,0,2,9,149,1,3,24,10,8,19,104,11,13,1,8,19,105,10,3,139,1,11,12,2,8,8,5,78,11,12,2,8,8,8,22,157,1,11,12,2,5,8,22,29,11,15,2,5,3,58,8,6,1,2,10,56,3,156,1,5,120,3,135,1,3,36,3,107,3,140,1,3,108,8,17,148,1,10,5,147,1,3,2,2,11,56,3,156,1,5,120,3,135,1,3,170,1,3,36,3,107,3,140,1,3,108,8,17,148,1,10,5,147,1,3,3,2,3,56,3,156,1,5,138,1,8,8,4,2,4,56,3,156,1,5,138,1,8,8,91,1,0,3,0,0,54,51,14,0,17,45,12,5,10,1,56,0,12,4,14,0,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,16,14,0,10,2,66,58,12,6,13,4,10,6,17,121,11,6,17,122,56,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,11,5,11,0,10,1,56,2,64,14,0,0,0,0,0,0,0,0,11,4,10,1,56,3,10,1,56,4,56,5,11,1,17,65,18,0,12,7,13,7,15,0,17,132,1,11,7,2,1,3,0,0,67,69,10,0,14,1,12,3,46,11,3,17,20,32,4,17,10,0,14,1,12,4,46,11,4,17,23,32,12,5,5,19,9,12,5,11,5,4,22,5,28,11,0,1,11,2,1,7,7,39,14,1,17,122,12,6,10,0,16,1,10,6,56,6,32,4,38,5,44,11,0,1,11,2,1,7,11,39,14,1,17,113,4,48,5,54,11,0,1,11,2,1,7,12,39,10,0,15,2,14,1,17,121,11,6,56,1,11,0,15,1,14,1,17,122,11,1,11,2,17,128,1,56,7,2,2,3,0,0,71,53,10,1,46,17,89,12,4,10,0,16,1,10,4,56,6,4,10,5,16,11,0,1,11,1,1,7,13,39,10,0,15,1,11,4,56,8,17,129,1,12,3,14,3,17,113,4,26,5,32,11,0,1,11,1,1,7,12,39,14,3,17,121,12,2,10,0,15,2,10,2,56,9,1,13,3,10,1,46,17,88,17,108,11,0,15,3,11,2,11,3,11,1,17,128,1,56,10,2,3,3,0,0,76,69,11,2,46,17,89,12,7,10,0,16,1,10,7,56,6,4,10,5,14,11,0,1,7,13,39,10,0,15,1,11,7,56,8,17,129,1,12,6,10,0,14,6,12,3,46,11,3,17,20,32,4,37,10,0,14,6,12,4,46,11,4,17,23,32,12,5,5,39,9,12,5,11,5,4,42,5,46,11,0,1,7,7,39,14,6,17,113,4,50,5,54,11,0,1,7,12,39,14,6,17,123,11,1,38,4,60,5,64,11,0,1,7,10,39,11,0,15,4,11,6,56,11,2,4,3,0,0,3,16,10,0,16,0,10,1,17,22,11,0,16,4,11,1,17,24,22,6,1,0,0,0,0,0,0,0,33,4,13,5,15,7,7,39,2,5,3,0,0,78,36,11,1,46,17,89,12,2,10,0,16,0,11,2,17,26,12,4,14,4,56,12,4,13,5,17,11,0,1,7,9,39,13,4,56,13,12,3,10,0,16,5,14,3,56,14,32,4,27,5,31,11,0,1,7,16,39,11,0,15,5,11,3,68,14,2,6,3,0,0,3,22,14,2,56,15,7,4,38,4,6,5,12,11,0,1,11,3,1,7,15,39,11,0,11,1,17,25,11,2,10,3,46,17,89,11,3,17,117,2,7,3,0,0,55,43,14,1,17,104,12,3,10,0,16,2,10,3,56,16,4,22,10,0,16,2,14,1,17,104,56,17,20,12,4,11,0,11,4,17,25,11,1,11,2,17,119,5,42,10,0,16,3,10,3,56,18,4,28,5,34,11,0,1,11,2,1,7,8,39,11,0,15,3,11,3,56,19,17,130,1,11,1,11,2,17,119,2,8,3,0,0,59,10,11,2,17,89,12,3,11,0,15,0,11,3,17,29,11,1,17,118,2,9,3,0,0,91,110,10,8,46,17,88,6,1,0,0,0,0,0,0,0,22,12,15,17,133,1,12,20,10,0,16,0,10,20,10,1,46,56,15,10,2,46,56,15,17,49,12,22,12,21,10,0,10,3,20,12,9,46,11,9,17,48,12,16,10,0,16,0,14,16,17,53,12,17,10,0,16,0,14,16,17,28,11,4,14,21,14,22,17,47,12,14,12,19,12,13,12,18,10,0,16,0,11,20,11,17,11,21,11,22,11,18,11,13,11,19,11,14,17,50,12,12,12,11,10,0,15,0,14,11,14,12,11,1,11,2,10,8,17,51,10,0,15,0,17,46,10,0,15,0,10,8,17,44,10,15,10,0,16,0,14,11,14,12,10,3,14,16,12,10,46,11,10,17,52,10,0,11,15,17,42,10,0,10,3,10,8,17,39,10,0,11,5,11,6,11,7,11,3,11,8,17,10,10,0,16,0,17,45,10,0,15,6,21,10,0,15,0,17,132,1,11,0,17,11,2,10,0,0,0,92,106,10,0,16,0,65,58,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,99,5,9,11,7,6,1,0,0,0,0,0,0,0,23,12,7,10,0,16,0,10,7,66,58,12,13,10,13,17,122,12,12,11,13,17,123,12,9,10,9,10,1,38,4,40,10,0,16,7,14,12,56,20,4,39,10,0,15,7,14,12,56,21,1,1,5,98,11,9,10,2,38,4,87,10,0,16,7,14,12,56,20,4,64,10,0,15,7,14,12,56,22,12,8,10,8,20,6,1,0,0,0,0,0,0,0,22,10,8,21,11,8,20,12,6,5,71,10,0,15,7,11,12,6,1,0,0,0,0,0,0,0,56,23,6,1,0,0,0,0,0,0,0,12,6,11,6,10,3,36,4,86,10,0,15,0,10,7,56,24,12,10,10,0,11,10,10,4,9,10,5,17,40,5,98,10,0,15,0,10,7,56,24,12,11,10,0,11,11,10,4,9,10,5,17,40,5,4,11,4,1,11,0,1,11,5,1,2,11,0,0,0,98,24,10,0,16,0,65,58,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,21,5,11,10,0,15,0,10,1,67,58,17,110,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,12,1,0,0,99,60,11,0,16,0,12,10,10,10,65,58,12,3,64,100,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,15,10,10,10,2,66,58,12,9,13,1,10,9,17,111,11,9,17,124,56,25,68,100,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,10,11,10,1,11,1,56,26,12,4,6,0,0,0,0,0,0,0,0,12,7,17,133,1,17,131,1,23,12,8,6,0,0,0,0,0,0,0,0,12,5,10,7,10,8,35,4,58,5,49,13,4,56,27,12,6,12,5,11,7,11,6,22,12,7,5,44,11,5,2,13,1,0,0,3,4,11,0,16,6,20,2,14,1,0,0,3,6,11,0,16,0,11,1,17,34,17,123,2,15,1,0,0,3,6,11,0,16,0,11,1,17,34,17,120,2,16,1,0,0,3,6,11,0,16,0,11,1,17,34,17,121,2,17,1,0,0,3,3,11,0,16,2,2,18,3,0,0,3,12,10,0,16,0,65,58,10,0,16,5,65,14,23,11,0,16,4,56,28,22,2,19,3,0,0,24,8,11,0,16,0,11,1,17,26,12,2,14,2,56,12,2,20,0,0,0,3,5,11,0,16,0,11,1,17,21,2,21,3,0,0,3,6,11,0,11,1,17,22,6,0,0,0,0,0,0,0,0,36,2,22,0,0,0,107,33,10,0,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,66,58,10,1,17,112,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,23,0,0,0,3,7,11,0,16,4,11,1,17,24,6,0,0,0,0,0,0,0,0,36,2,24,0,0,0,107,33,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,56,29,10,1,17,112,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,25,0,0,0,3,16,10,0,16,1,10,1,56,6,4,11,11,0,15,1,11,1,56,30,17,130,1,2,11,0,15,0,11,1,17,29,2,26,0,0,0,98,31,10,0,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,66,58,17,122,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,27,0,0,0,98,31,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,56,29,17,122,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,28,0,0,0,112,46,10,1,65,59,12,5,6,0,0,0,0,0,0,0,0,12,3,7,20,12,6,10,3,10,5,35,4,40,5,12,10,1,10,3,66,59,20,12,2,10,0,11,2,17,26,12,4,14,4,56,12,4,25,5,31,11,0,1,11,1,1,7,9,39,13,6,11,4,56,33,68,14,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,0,1,11,1,1,11,6,2,29,3,0,0,78,22,10,0,11,1,12,2,46,11,2,17,26,12,4,14,4,56,12,4,11,5,15,11,0,1,7,9,39,13,4,56,13,12,3,11,0,11,3,67,58,2,30,0,0,0,113,45,10,0,16,0,10,1,17,26,12,5,14,5,56,12,4,16,13,5,56,13,12,3,11,0,15,0,11,3,67,58,2,10,0,16,4,10,1,17,27,12,6,14,6,56,12,4,32,13,6,56,13,12,4,11,0,15,4,11,4,56,34,2,11,2,4,35,5,39,11,0,1,7,14,39,11,0,15,1,11,1,56,30,17,130,1,2,31,3,0,0,3,7,11,0,11,1,17,127,20,11,2,17,30,2,32,3,0,0,59,8,11,1,17,89,12,2,11,0,11,2,9,17,30,2,33,3,0,0,59,8,11,1,17,89,12,2,11,0,11,2,8,17,30,2,34,0,0,0,118,19,10,0,11,1,17,26,12,3,14,3,56,12,4,8,5,12,11,0,1,7,9,39,13,3,56,13,12,2,11,0,11,2,66,58,2,35,3,0,0,119,57,10,0,16,0,10,1,17,26,12,7,14,7,56,12,4,11,8,12,3,5,15,10,2,7,0,33,12,3,11,3,4,25,13,7,56,13,12,5,11,0,16,0,11,5,66,58,2,10,0,16,4,10,1,17,27,12,8,14,8,56,12,4,36,8,12,4,5,40,11,2,7,1,33,12,4,11,4,4,50,13,8,56,13,12,6,11,0,16,4,11,6,56,29,2,11,0,15,1,11,1,56,30,17,130,1,46,2,36,1,0,0,118,21,10,0,16,0,11,1,17,26,12,3,14,3,56,12,4,9,5,13,11,0,1,7,9,39,13,3,56,13,12,2,11,0,16,0,11,2,66,58,2,37,1,0,0,118,21,10,0,16,4,11,1,17,27,12,3,14,3,56,12,4,9,5,13,11,0,1,7,17,39,13,3,56,13,12,2,11,0,16,4,11,2,56,29,2,38,3,0,0,120,39,10,1,17,126,20,12,6,10,2,7,0,33,4,16,11,0,11,6,12,3,46,11,3,17,36,12,4,5,21,11,0,11,6,11,2,17,35,12,4,11,4,12,7,10,1,56,35,12,5,11,7,17,114,14,5,33,4,32,5,36,11,1,1,7,19,39,11,1,17,125,2,39,0,0,0,124,32,10,0,15,5,17,43,10,0,16,5,56,36,32,4,25,5,9,10,0,15,5,69,14,12,3,10,0,15,0,11,3,56,24,12,4,10,0,11,4,10,1,8,10,2,17,40,5,3,11,1,1,11,0,1,11,2,1,2,40,0,0,0,126,58,10,4,46,17,88,6,1,0,0,0,0,0,0,0,22,12,5,14,1,17,122,12,6,14,1,17,121,12,7,10,0,15,2,10,7,56,9,1,10,0,16,7,14,6,56,20,4,28,10,0,15,7,14,6,56,21,1,1,10,0,16,6,20,14,1,17,123,23,10,0,15,6,21,11,2,10,6,17,41,10,5,11,6,14,1,17,121,11,3,18,4,56,37,13,1,11,5,17,108,11,0,15,3,11,7,11,1,11,4,17,128,1,56,10,2,41,0,0,0,128,1,69,10,0,14,1,12,2,46,11,2,56,38,4,12,10,0,14,1,56,39,1,1,10,0,46,56,40,12,7,14,7,65,59,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,66,5,26,14,7,10,4,66,59,12,6,10,0,10,6,56,41,12,8,10,8,14,1,12,3,46,11,3,56,42,4,57,10,8,14,1,56,43,11,8,46,56,44,4,54,10,0,11,6,56,39,1,1,5,56,11,6,1,5,61,11,8,1,11,6,1,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,21,11,0,1,2,42,0,0,0,58,28,10,0,16,4,56,45,32,4,25,5,6,10,0,15,4,56,46,12,2,13,2,10,1,17,105,10,1,14,2,17,122,14,2,17,121,18,3,56,47,10,0,15,0,11,2,68,58,5,0,11,0,1,2,43,0,0,0,137,1,57,10,0,46,65,14,12,6,6,1,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,54,5,11,10,0,10,4,12,1,46,11,1,66,14,20,12,3,10,4,12,5,10,5,6,0,0,0,0,0,0,0,0,36,4,49,5,26,11,5,6,1,0,0,0,0,0,0,0,23,12,5,10,0,10,5,12,2,46,11,2,66,14,20,10,3,36,4,41,5,42,5,49,10,0,10,5,10,5,6,1,0,0,0,0,0,0,0,22,71,14,5,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,1,2,44,0,0,0,98,26,10,0,46,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,21,5,11,10,0,10,2,67,58,10,1,17,116,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,11,1,1,2,45,0,0,0,139,1,30,6,0,0,0,0,0,0,0,0,12,3,10,0,65,58,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,26,5,12,10,0,10,1,66,58,12,4,11,3,11,4,17,123,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,46,0,0,0,98,23,10,0,46,65,58,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,20,5,11,10,0,10,1,67,58,17,106,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,47,0,0,0,140,1,69,6,0,0,0,0,0,0,0,0,12,8,56,48,12,4,6,0,0,0,0,0,0,0,0,12,9,56,48,12,5,13,0,46,56,36,32,4,60,5,14,13,0,69,14,12,10,10,2,10,10,66,14,20,53,10,1,53,24,7,3,26,12,6,13,4,10,10,10,6,52,56,49,11,8,11,6,52,22,12,8,10,3,10,10,66,14,20,53,10,1,53,24,7,3,26,12,7,13,5,11,10,10,7,52,56,49,11,9,11,7,52,22,12,9,5,8,11,3,1,11,2,1,11,8,11,4,11,9,11,5,2,48,0,0,0,141,1,40,7,21,12,5,14,1,56,50,32,4,36,5,7,13,1,56,51,12,4,12,6,10,0,10,6,17,19,4,16,5,20,11,0,1,7,5,39,10,0,16,0,12,3,11,4,56,52,12,2,11,3,14,2,17,53,17,131,1,38,4,35,13,5,11,6,68,59,5,2,11,0,1,11,5,2,49,0,0,0,144,1,47,64,14,0,0,0,0,0,0,0,0,12,7,64,14,0,0,0,0,0,0,0,0,12,8,10,0,65,58,12,5,11,3,10,5,26,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,42,5,18,10,0,10,4,66,58,17,124,53,10,2,53,24,10,1,53,26,12,6,13,7,11,6,52,68,14,13,8,10,9,68,14,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,13,11,0,1,11,7,11,8,2,50,0,0,0,145,1,108,11,1,11,2,23,12,22,64,14,0,0,0,0,0,0,0,0,12,12,64,14,0,0,0,0,0,0,0,0,12,14,10,0,65,58,12,20,10,20,14,6,56,53,23,12,21,6,0,0,0,0,0,0,0,0,12,19,10,19,10,20,35,4,103,5,23,10,0,10,19,66,58,17,124,53,12,25,14,3,10,19,66,14,20,12,23,14,6,14,19,56,54,4,48,14,6,14,19,56,55,20,12,15,11,23,11,15,23,12,9,5,61,10,5,53,11,25,24,10,22,53,26,12,16,11,23,11,16,52,22,12,9,11,9,12,11,13,12,11,11,68,14,14,4,10,19,66,14,20,12,24,14,8,14,19,56,54,4,85,14,8,14,19,56,55,20,12,17,11,24,11,17,23,12,10,5,93,10,7,10,21,26,12,18,11,24,11,18,22,12,10,11,10,12,13,13,14,11,13,68,14,11,19,6,1,0,0,0,0,0,0,0,22,12,19,5,18,11,0,1,11,12,11,14,2,51,0,0,0,146,1,105,10,0,46,65,58,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,9,5,23,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,7,18,39,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,92,5,30,10,0,10,6,67,58,12,10,10,1,10,6,66,14,20,12,9,10,3,10,9,56,56,12,8,11,9,53,10,10,46,17,107,53,24,7,3,26,12,12,13,8,11,12,52,56,56,12,13,13,13,10,4,10,2,10,6,66,14,20,56,56,56,57,1,14,13,56,15,6,0,0,0,0,0,0,0,0,36,4,82,10,10,46,17,122,12,11,10,10,11,13,11,11,10,5,17,117,5,84,11,13,56,58,11,10,11,8,17,109,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,25,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,2,52,0,0,0,151,1,84,10,1,65,58,12,9,6,0,0,0,0,0,0,0,0,12,8,10,8,10,9,35,4,73,5,10,10,1,10,8,66,58,12,12,10,12,17,122,12,13,10,4,14,13,56,38,4,28,10,4,14,13,56,59,20,56,52,12,6,5,30,7,21,12,6,11,6,12,11,10,5,14,13,56,60,4,39,6,0,0,0,0,0,0,0,0,12,7,5,41,6,1,0,0,0,0,0,0,0,12,7,11,7,12,10,10,0,11,13,10,12,17,111,10,12,17,123,10,12,17,124,10,12,17,107,10,2,10,8,66,14,20,10,3,10,8,66,14,20,11,12,10,0,17,115,11,11,11,10,18,2,56,61,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,5,11,1,1,11,3,1,11,5,1,11,4,1,11,2,1,2,53,1,0,0,139,1,35,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,1,65,59,12,3,10,2,10,3,35,4,29,5,12,10,0,10,1,10,2,66,59,20,17,34,12,5,11,4,11,5,17,124,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,54,1,0,0,3,3,11,0,16,0,2,55,1,0,0,3,5,11,0,16,1,11,1,56,6,2,56,1,0,0,3,5,11,0,16,3,11,1,56,18,2,0,1,0,6,0,4,0,5,0,2,0,3,0,0,0,7,0,63,0,143,1,0],"validator_wrapper":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,16,3,24,48,4,72,6,5,78,52,7,130,1,211,1,8,213,2,64,6,149,3,10,10,159,3,6,12,165,3,100,13,137,4,2,15,139,4,2,0,14,1,10,1,16,0,12,0,2,4,0,1,0,2,0,2,3,12,0,3,1,4,0,0,5,0,1,0,0,8,2,3,0,0,6,1,4,0,0,11,2,5,0,0,15,6,7,0,2,4,8,9,1,4,2,6,9,12,1,4,2,9,10,11,1,4,2,15,13,7,0,5,4,7,4,6,4,2,8,3,7,8,1,1,8,0,1,7,8,0,1,7,8,3,1,8,3,0,1,6,8,0,1,3,3,3,9,0,7,8,1,1,8,2,1,7,8,2,1,7,9,0,1,9,0,1,6,8,2,9,84,120,67,111,110,116,101,120,116,9,86,97,108,105,100,97,116,111,114,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,9,86,101,114,115,105,111,110,101,100,6,99,114,101,97,116,101,9,99,114,101,97,116,101,95,118,49,7,100,101,115,116,114,111,121,5,105,110,110,101,114,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,10,116,120,95,99,111,110,116,101,120,116,17,117,112,103,114,97,100,101,95,116,111,95,108,97,116,101,115,116,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,1,7,8,2,0,3,0,0,5,6,6,1,0,0,0,0,0,0,0,11,0,11,1,56,0,18,0,2,1,3,0,0,5,6,10,0,17,3,11,0,15,0,56,1,2,2,3,0,0,5,6,13,0,17,3,11,0,19,0,56,2,2,3,0,0,0,5,10,11,0,46,17,4,6,1,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,2,4,0,0,0,5,4,11,0,16,0,17,8,2,0,0,0,13,0],"voting_power":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,87,4,107,4,5,111,134,1,7,245,1,176,2,8,165,4,96,6,133,5,70,10,203,5,16,12,219,5,254,6,13,217,12,4,15,221,12,2,0,22,1,21,2,9,0,18,0,1,2,0,0,2,2,0,3,0,4,0,0,13,0,1,0,0,6,2,3,0,0,15,4,5,0,0,7,6,1,0,0,3,7,1,0,0,17,8,1,0,0,4,4,1,0,0,16,1,5,0,0,12,1,5,0,1,7,17,1,1,0,1,8,19,20,1,0,2,5,11,5,0,2,10,11,5,0,2,11,11,5,0,3,13,21,1,0,3,15,14,5,0,3,22,14,5,0,9,13,10,13,1,7,10,8,2,0,2,6,10,8,2,3,2,10,8,1,3,1,6,10,8,2,1,3,2,7,10,8,1,8,1,3,7,10,8,1,3,3,2,7,10,8,2,10,8,1,4,3,10,8,1,3,3,1,8,2,2,3,3,8,3,8,1,3,10,8,1,3,3,3,3,1,8,1,1,6,8,2,3,3,3,3,4,3,1,3,3,3,7,10,9,0,9,0,3,7,1,3,3,3,3,3,7,8,1,1,6,10,9,0,1,1,2,7,8,2,3,12,3,3,3,3,3,3,3,3,3,6,8,2,6,8,2,3,9,86,97,108,105,100,97,116,111,114,15,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,17,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,86,50,19,97,100,106,117,115,116,95,118,111,116,105,110,103,95,112,111,119,101,114,16,99,104,101,99,107,95,105,110,118,97,114,105,97,110,116,115,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,22,105,110,105,116,95,118,111,116,105,110,103,95,112,111,119,101,114,95,105,110,102,111,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,4,109,97,116,104,3,109,97,120,3,109,105,110,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,5,115,116,97,107,101,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,19,117,112,100,97,116,101,95,118,111,116,105,110,103,95,112,111,119,101,114,9,118,97,108,105,100,97,116,111,114,15,118,97,108,105,100,97,116,111,114,95,105,110,100,101,120,13,118,97,108,105,100,97,116,111,114,95,115,101,116,6,118,101,99,116,111,114,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,16,39,0,0,0,0,0,0,3,8,11,26,0,0,0,0,0,0,3,8,232,3,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,2,19,3,22,3,1,2,3,19,3,22,3,14,3,0,3,0,0,9,29,7,0,7,2,7,0,10,0,46,65,10,17,11,17,12,17,13,12,4,10,0,10,4,12,1,46,11,1,17,1,12,3,12,2,13,2,11,4,11,3,17,4,10,0,11,2,17,5,11,0,46,17,6,2,1,0,0,0,12,58,10,0,17,2,12,8,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,7,64,13,0,0,0,0,0,0,0,0,12,5,10,2,10,4,35,4,51,5,17,10,0,10,2,66,10,17,15,12,6,10,6,53,7,0,53,24,10,8,53,26,52,10,1,17,13,12,9,10,2,10,9,11,6,18,1,12,3,13,5,11,3,17,3,11,7,11,9,22,12,7,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,0,1,11,5,7,0,11,7,23,2,2,0,0,0,15,28,6,0,0,0,0,0,0,0,0,12,1,10,0,65,10,12,2,6,0,0,0,0,0,0,0,0,12,3,10,1,10,2,35,4,24,5,12,11,3,10,0,10,1,66,10,17,15,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,3,0,0,0,16,39,6,0,0,0,0,0,0,0,0,12,4,10,0,46,65,13,12,5,10,4,10,5,35,4,25,5,11,10,0,10,4,12,2,46,11,2,66,13,16,0,20,14,1,16,0,20,36,12,3,5,27,9,12,3,11,3,4,34,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,11,1,11,4,56,0,2,4,0,0,0,18,84,6,0,0,0,0,0,0,0,0,12,5,10,0,46,65,13,12,6,10,5,10,6,35,4,16,5,11,10,2,6,0,0,0,0,0,0,0,0,36,12,3,5,18,9,12,3,11,3,4,74,10,0,10,5,67,13,12,9,10,2,10,6,10,5,23,17,11,12,7,10,1,10,9,16,1,20,11,7,22,17,13,12,8,10,2,11,8,10,9,16,1,20,23,17,13,12,4,10,9,16,1,20,10,4,22,10,9,15,1,21,11,9,16,1,20,10,1,37,4,61,5,65,11,0,1,7,5,39,11,2,11,4,23,12,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,6,11,0,1,11,2,6,0,0,0,0,0,0,0,0,33,4,81,5,83,7,3,39,2,5,0,0,0,11,22,14,1,56,1,32,4,17,5,5,13,1,69,13,19,1,1,12,3,12,2,10,0,11,2,67,10,11,3,17,14,5,0,11,0,1,11,1,70,13,0,0,0,0,0,0,0,0,2,6,0,0,0,22,119,6,0,0,0,0,0,0,0,0,12,3,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,9,10,3,10,4,35,4,35,5,12,10,0,10,3,66,10,17,16,12,12,10,12,6,0,0,0,0,0,0,0,0,36,4,22,5,26,11,0,1,7,6,39,11,9,11,12,22,12,9,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,9,7,0,33,4,40,5,44,11,0,1,7,3,39,6,0,0,0,0,0,0,0,0,12,1,10,1,10,4,35,4,116,5,51,10,1,6,1,0,0,0,0,0,0,0,22,12,2,10,2,10,4,35,4,111,5,60,10,0,10,1,66,10,12,10,10,0,10,2,66,10,12,11,10,10,17,15,12,7,10,11,17,15,12,8,11,10,17,16,12,5,11,11,17,16,12,6,10,7,10,8,36,4,93,10,5,10,6,38,4,89,5,93,11,0,1,7,4,39,11,7,11,8,35,4,106,11,5,11,6,37,4,102,5,106,11,0,1,7,4,39,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,55,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,46,11,0,1,2,7,1,0,0,1,2,7,0,2,8,1,0,0,1,2,7,1,2,1,2,1,1,0,20,0]},"type_origin_table":[{"module_name":"validator_cap","struct_name":"UnverifiedValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_cap","struct_name":"ValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakingPool","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"PoolTokenExchangeRate","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakedSui","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"ValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"Validator","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"StakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"UnstakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfo","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfoV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_wrapper","struct_name":"ValidatorWrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorSet","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEventV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorJoinEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorLeaveEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"storage_fund","struct_name":"StorageFund","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"stake_subsidy","struct_name":"StakeSubsidy","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SystemParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SystemParametersV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SuiSystemStateInner","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SuiSystemStateInnerV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SystemEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system","struct_name":"SuiSystemState","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisChainParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenDistributionSchedule","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenAllocation","package":"0x0000000000000000000000000000000000000000000000000000000000000003"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"DdYtSHED8qYakCvtPiThXfbiSHFJpFGJkYpbYfohRxxh","storage_rebate":0},{"data":{"Package":{"id":"0x000000000000000000000000000000000000000000000000000000000000dee9","version":5,"module_map":{"clob":[161,28,235,11,6,0,0,0,13,1,0,36,2,36,134,1,3,170,1,204,4,4,246,5,184,1,5,174,7,241,9,7,159,17,135,15,8,166,32,96,6,134,33,147,2,10,153,35,226,1,11,251,36,8,12,131,37,235,39,13,238,76,40,14,150,77,26,0,45,0,53,0,54,0,94,1,107,1,137,1,2,28,2,46,2,47,2,65,2,85,2,105,2,126,2,129,1,2,135,1,2,136,1,0,16,7,0,0,14,7,2,0,1,0,1,0,10,7,2,0,1,0,1,0,12,7,2,0,1,0,1,0,9,6,0,0,19,4,0,0,15,8,2,0,1,0,1,0,13,7,2,0,1,0,1,0,11,7,2,0,1,0,1,1,4,4,1,4,0,2,0,12,0,2,5,12,1,0,1,4,8,7,1,0,0,5,21,7,0,6,1,4,1,0,1,7,2,8,0,8,3,12,1,0,1,10,7,12,2,7,0,4,1,11,6,7,0,11,22,4,0,12,17,2,0,13,18,12,2,7,1,4,1,15,20,2,0,0,60,0,1,0,0,49,2,3,0,0,51,4,1,2,0,0,0,50,5,1,2,0,0,0,57,6,1,2,0,0,0,58,7,1,2,0,0,0,146,1,8,9,2,0,0,0,147,1,8,10,2,0,0,0,127,11,12,2,0,0,0,128,1,13,12,2,0,0,0,93,14,15,2,0,0,0,92,14,15,2,0,0,0,91,16,15,2,0,0,0,112,17,18,2,0,0,0,78,19,20,2,0,0,0,111,21,22,2,0,0,0,109,20,23,0,0,63,24,1,2,0,0,0,64,25,1,2,0,0,0,44,26,1,2,0,0,0,123,27,28,2,0,0,0,43,29,1,2,0,0,0,36,30,1,2,0,0,0,86,31,32,2,0,0,0,24,31,33,2,0,0,0,74,34,35,2,0,0,0,73,34,35,2,0,0,0,72,36,20,2,0,0,0,75,37,38,2,0,0,1,39,84,60,1,4,1,40,84,60,1,4,1,42,71,72,1,4,1,67,84,20,1,4,1,68,84,78,1,4,1,79,91,20,1,4,1,82,70,23,1,4,1,95,70,46,1,4,1,96,70,46,1,4,1,100,2,50,1,4,1,104,84,46,1,4,1,114,84,46,1,4,1,122,71,43,1,4,2,23,97,20,1,0,2,24,97,46,1,0,2,55,90,54,1,0,2,56,77,54,1,0,2,77,62,1,1,0,2,87,90,1,1,0,2,97,2,3,0,2,100,2,53,1,0,2,139,1,77,1,1,0,2,145,1,63,9,1,0,3,61,46,78,0,3,98,46,20,0,3,99,46,78,0,3,140,1,46,78,0,3,141,1,46,20,0,3,142,1,46,78,0,4,38,74,60,1,0,4,83,74,23,1,0,5,71,1,44,1,0,6,84,80,20,1,0,6,125,79,54,1,0,6,144,1,67,20,1,0,6,148,1,1,54,1,0,7,133,1,66,20,0,8,69,68,9,1,0,8,80,9,54,1,0,8,84,88,1,1,0,8,144,1,59,20,1,0,9,62,43,1,1,3,10,27,73,74,2,7,4,10,38,75,76,2,7,4,10,41,83,82,2,7,4,10,48,75,23,2,7,4,10,59,41,1,2,7,4,10,70,73,74,2,7,4,10,82,73,23,2,7,4,10,100,2,41,2,7,4,10,101,75,74,2,7,4,10,116,92,1,2,7,4,10,121,83,45,2,7,4,11,76,60,61,1,8,11,100,2,47,0,11,138,1,48,49,0,13,25,95,1,2,7,4,13,38,94,76,2,7,4,13,41,81,82,2,7,4,13,48,94,23,2,7,4,13,100,2,52,2,7,4,14,124,43,1,1,8,75,40,60,43,60,45,38,0,89,51,49,43,49,45,64,43,64,45,90,56,70,57,69,58,67,58,2,55,69,43,82,3,67,43,46,43,69,45,67,45,46,45,51,43,51,45,13,55,10,55,63,43,66,43,66,45,35,0,37,0,31,0,76,40,58,20,77,40,72,40,50,43,17,55,45,43,62,45,61,45,61,43,18,55,79,40,59,20,87,51,81,46,81,40,73,40,39,0,41,0,33,0,36,0,50,45,45,45,62,43,40,0,11,55,68,43,12,55,68,45,47,45,47,43,78,40,34,0,80,40,70,93,88,51,78,46,85,51,80,46,42,45,44,45,63,45,44,43,14,55,70,98,70,99,74,46,72,46,20,55,29,0,74,40,77,46,71,46,86,51,76,46,30,0,79,46,43,43,43,45,32,0,27,55,1,8,5,0,1,7,8,22,1,8,10,6,3,3,3,3,11,14,1,8,20,7,8,22,4,3,3,11,16,1,8,20,7,8,22,3,7,11,6,2,9,0,9,1,11,16,1,9,0,6,8,10,3,7,11,6,2,9,0,9,1,11,16,1,9,1,6,8,10,4,7,11,6,2,9,0,9,1,3,6,8,10,7,8,22,1,11,16,1,9,0,1,11,16,1,9,1,6,7,11,6,2,9,0,9,1,3,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,3,11,16,1,9,0,11,16,1,9,1,3,5,7,11,6,2,9,0,9,1,3,6,8,15,11,16,1,9,1,7,8,22,5,7,11,6,2,9,0,9,1,3,3,3,11,14,1,9,1,2,11,14,1,9,0,11,14,1,9,1,4,7,11,6,2,9,0,9,1,3,3,11,14,1,9,0,7,7,11,6,2,9,0,9,1,3,1,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,2,11,16,1,9,0,11,16,1,9,1,7,7,11,6,2,9,0,9,1,3,3,1,3,6,8,10,7,8,22,1,3,9,7,11,6,2,9,0,9,1,3,3,1,3,2,6,8,15,6,8,10,7,8,22,4,3,3,1,3,1,1,2,8,18,6,8,4,5,8,18,6,8,4,3,3,3,3,7,11,6,2,9,0,9,1,3,6,8,10,5,7,11,9,1,8,5,7,11,17,2,3,3,3,3,8,18,1,8,4,2,7,11,6,2,9,0,9,1,6,8,10,3,7,11,6,2,9,0,9,1,10,3,6,8,10,2,6,11,6,2,9,0,9,1,6,8,10,1,10,8,4,4,3,3,3,3,4,6,11,6,2,9,0,9,1,3,3,6,8,15,2,10,3,10,3,3,6,11,9,1,8,5,3,3,3,6,11,6,2,9,0,9,1,3,6,8,10,1,6,8,4,1,11,17,2,3,8,4,2,3,8,4,1,11,17,2,9,0,9,1,4,8,13,8,18,8,19,8,13,1,9,0,1,8,13,1,9,1,2,3,3,1,8,19,1,6,8,19,1,6,8,18,1,11,9,1,9,0,2,8,18,11,17,2,3,3,1,11,21,2,9,0,9,1,1,11,11,1,9,0,1,11,14,1,9,0,2,9,0,9,1,1,11,6,2,9,0,9,1,1,8,0,1,8,20,1,6,11,16,1,9,0,1,6,9,0,1,8,18,3,7,11,11,1,9,0,8,18,11,14,1,9,0,4,7,11,11,1,9,0,3,6,8,10,7,8,22,4,3,11,16,1,9,0,11,16,1,9,1,3,3,11,14,1,9,0,11,14,1,9,1,3,1,6,8,15,1,6,11,14,1,9,0,2,11,14,1,9,0,7,8,22,28,1,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,11,14,1,9,1,1,3,3,1,3,7,8,5,3,1,6,11,9,1,9,0,2,7,11,9,1,9,0,3,1,7,9,0,1,6,11,17,2,9,0,9,1,1,6,11,12,1,9,0,2,6,11,17,2,9,0,9,1,9,0,1,6,9,1,3,7,11,11,1,9,0,8,18,3,2,1,3,2,7,11,14,1,9,0,3,2,7,11,14,1,9,0,11,14,1,9,0,2,7,11,21,2,9,0,9,1,9,0,1,7,9,1,2,7,11,17,2,9,0,9,1,9,0,2,6,11,9,1,9,0,3,26,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,27,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,1,3,6,8,4,7,8,4,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,3,11,14,1,9,0,11,14,1,9,1,11,14,1,9,1,2,7,11,16,1,9,0,11,16,1,9,0,7,3,7,11,9,1,8,5,8,4,3,3,3,8,18,3,7,11,11,1,9,0,6,8,10,3,3,7,11,9,1,9,0,3,9,0,3,7,11,17,2,9,0,9,1,9,0,9,1,1,11,1,2,9,0,9,1,2,6,11,21,2,9,0,9,1,9,0,3,7,11,21,2,9,0,9,1,9,0,9,1,11,11,14,1,9,0,11,14,1,9,0,11,14,1,9,0,3,3,11,14,1,9,1,11,14,1,9,1,11,14,1,9,1,3,3,8,18,2,6,11,11,1,9,0,8,18,1,11,2,2,9,0,9,1,1,11,3,2,9,0,9,1,11,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,1,8,4,3,3,8,18,7,11,17,2,3,3,3,3,7,8,5,8,4,13,3,7,11,9,1,8,5,3,3,1,7,11,9,1,8,5,8,4,3,3,8,18,3,8,18,7,11,17,2,3,3,17,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,3,1,3,3,3,8,4,3,8,18,3,3,8,18,7,11,17,2,3,3,7,6,8,5,10,8,4,6,8,4,6,11,12,1,3,3,8,18,6,11,17,2,3,3,5,3,3,3,3,8,18,6,3,10,3,3,3,3,10,3,4,3,6,8,4,6,11,12,1,3,6,11,17,2,3,8,4,4,6,11,9,1,8,5,3,8,18,6,11,17,2,3,3,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,11,67,114,105,116,98,105,116,84,114,101,101,9,67,117,115,116,111,100,105,97,110,2,73,68,11,76,105,110,107,101,100,84,97,98,108,101,6,79,112,116,105,111,110,5,79,114,100,101,114,13,79,114,100,101,114,67,97,110,99,101,108,101,100,11,79,114,100,101,114,70,105,108,108,101,100,13,79,114,100,101,114,70,105,108,108,101,100,86,50,11,79,114,100,101,114,80,108,97,99,101,100,13,79,114,100,101,114,80,108,97,99,101,100,86,50,4,80,111,111,108,11,80,111,111,108,67,114,101,97,116,101,100,3,83,85,73,5,84,97,98,108,101,9,84,105,99,107,76,101,118,101,108,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,3,97,100,100,4,97,115,107,115,4,98,97,99,107,7,98,97,108,97,110,99,101,10,98,97,115,101,95,97,115,115,101,116,28,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,99,97,110,99,101,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,102,105,108,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,112,108,97,99,101,100,29,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,114,101,109,97,105,110,105,110,103,23,98,97,115,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,14,98,97,115,101,95,99,117,115,116,111,100,105,97,110,18,98,97,116,99,104,95,99,97,110,99,101,108,95,111,114,100,101,114,4,98,105,100,115,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,17,99,97,110,99,101,108,95,97,108,108,95,111,114,100,101,114,115,12,99,97,110,99,101,108,95,111,114,100,101,114,4,99,108,111,98,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,14,99,114,101,97,116,101,95,97,99,99,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,12,99,114,101,97,116,101,95,112,111,111,108,95,12,99,114,101,97,116,105,111,110,95,102,101,101,7,99,114,105,116,98,105,116,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,100,101,112,111,115,105,116,95,98,97,115,101,13,100,101,112,111,115,105,116,95,113,117,111,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,19,100,101,115,116,114,111,121,95,101,109,112,116,121,95,108,101,118,101,108,9,100,105,118,95,114,111,117,110,100,4,101,109,105,116,19,101,109,105,116,95,111,114,100,101,114,95,99,97,110,99,101,108,101,100,17,101,109,105,116,95,111,114,100,101,114,95,102,105,108,108,101,100,5,101,118,101,110,116,16,101,120,112,105,114,101,95,116,105,109,101,115,116,97,109,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,12,102,114,111,109,95,98,97,108,97,110,99,101,5,102,114,111,110,116,3,103,101,116,22,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,97,115,107,95,115,105,100,101,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,98,105,100,95,115,105,100,101,16,103,101,116,95,111,114,100,101,114,95,115,116,97,116,117,115,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,18,105,110,106,101,99,116,95,108,105,109,105,116,95,111,114,100,101,114,11,105,110,115,101,114,116,95,108,101,97,102,12,105,110,116,111,95,98,97,108,97,110,99,101,6,105,115,95,98,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,4,106,111,105,110,12,108,105,110,107,101,100,95,116,97,98,108,101,16,108,105,115,116,95,111,112,101,110,95,111,114,100,101,114,115,12,108,111,99,107,95,98,97,108,97,110,99,101,8,108,111,116,95,115,105,122,101,17,109,97,107,101,114,95,114,101,98,97,116,101,95,114,97,116,101,13,109,97,107,101,114,95,114,101,98,97,116,101,115,9,109,97,116,99,104,95,97,115,107,9,109,97,116,99,104,95,98,105,100,29,109,97,116,99,104,95,98,105,100,95,119,105,116,104,95,113,117,111,116,101,95,113,117,97,110,116,105,116,121,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,109,117,108,9,109,117,108,95,114,111,117,110,100,3,110,101,119,4,110,101,120,116,17,110,101,120,116,95,97,115,107,95,111,114,100,101,114,95,105,100,17,110,101,120,116,95,98,105,100,95,111,114,100,101,114,95,105,100,9,110,101,120,116,95,108,101,97,102,6,111,98,106,101,99,116,11,111,112,101,110,95,111,114,100,101,114,115,6,111,112,116,105,111,110,8,111,114,100,101,114,95,105,100,12,111,114,100,101,114,95,105,115,95,98,105,100,5,111,119,110,101,114,17,112,108,97,99,101,95,108,105,109,105,116,95,111,114,100,101,114,18,112,108,97,99,101,95,109,97,114,107,101,116,95,111,114,100,101,114,7,112,111,111,108,95,105,100,13,112,114,101,118,105,111,117,115,95,108,101,97,102,5,112,114,105,99,101,9,112,117,115,104,95,98,97,99,107,8,113,117,97,110,116,105,116,121,11,113,117,111,116,101,95,97,115,115,101,116,24,113,117,111,116,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,15,113,117,111,116,101,95,99,117,115,116,111,100,105,97,110,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,12,114,101,109,111,118,101,95,111,114,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,3,115,117,105,25,115,119,97,112,95,101,120,97,99,116,95,98,97,115,101,95,102,111,114,95,113,117,111,116,101,25,115,119,97,112,95,101,120,97,99,116,95,113,117,111,116,101,95,102,111,114,95,98,97,115,101,5,116,97,98,108,101,16,116,97,107,101,114,95,99,111,109,109,105,115,115,105,111,110,14,116,97,107,101,114,95,102,101,101,95,114,97,116,101,9,116,105,99,107,95,115,105,122,101,12,116,105,109,101,115,116,97,109,112,95,109,115,14,116,111,116,97,108,95,113,117,97,110,116,105,116,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,16,117,110,115,97,102,101,95,100,105,118,95,114,111,117,110,100,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,15,117,115,114,95,111,112,101,110,95,111,114,100,101,114,115,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,13,119,105,116,104,100,114,97,119,95,98,97,115,101,14,119,105,116,104,100,114,97,119,95,113,117,111,116,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,3,8,19,0,0,0,0,0,0,0,3,8,20,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,2,1,4,2,1,0,2,1,1,2,1,2,2,1,3,3,8,0,0,0,0,0,0,0,128,3,8,0,0,0,0,0,0,0,0,3,8,64,75,76,0,0,0,0,0,3,8,160,37,38,0,0,0,0,0,3,8,0,232,118,72,23,0,0,0,0,2,7,113,8,18,29,8,13,118,8,13,131,1,3,89,3,132,1,3,88,3,1,2,7,113,8,18,108,3,81,1,110,8,18,32,3,115,3,66,3,2,2,6,113,8,18,108,3,81,1,110,8,18,30,3,115,3,3,2,10,113,8,18,108,3,81,1,110,8,18,134,1,3,31,3,33,3,115,3,130,1,3,90,3,4,2,6,108,3,115,3,117,3,81,1,110,8,18,66,3,5,2,2,115,3,106,11,17,2,3,8,4,6,2,15,76,8,19,37,11,9,1,8,5,26,11,9,1,8,5,103,3,102,3,143,1,11,21,2,8,18,11,17,2,3,3,131,1,3,89,3,132,1,3,88,3,35,11,11,1,9,0,120,11,11,1,9,1,52,11,14,1,8,20,34,11,14,1,9,0,119,11,14,1,9,1,7,2,6,113,8,18,108,3,81,1,110,8,18,32,3,115,3,8,2,8,113,8,18,108,3,81,1,110,8,18,134,1,3,31,3,33,3,115,3,6,55,1,55,2,55,3,55,0,0,0,0,39,7,11,0,19,5,12,1,1,11,1,56,0,2,1,1,0,0,1,3,11,0,17,48,2,2,0,0,0,42,72,56,1,12,6,56,2,12,9,10,3,10,2,17,56,6,0,0,0,0,0,0,0,0,36,4,11,5,15,11,5,1,7,19,39,10,6,10,9,34,4,20,5,24,11,5,1,7,15,39,10,0,10,1,38,4,29,5,33,11,5,1,7,1,39,10,5,17,83,12,8,14,8,17,84,20,12,7,11,8,10,5,56,3,10,5,56,3,7,0,7,26,10,5,56,4,10,0,10,1,10,2,10,3,10,5,56,5,11,5,56,6,11,4,56,7,56,8,57,0,56,9,11,7,11,6,11,9,11,0,11,1,11,2,11,3,18,0,56,10,2,3,1,0,0,1,19,14,2,56,11,7,30,33,4,6,5,10,11,3,1,7,17,39,7,28,7,29,11,0,11,1,11,2,56,12,11,3,56,13,2,4,1,0,0,1,20,14,1,56,14,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,6,39,11,0,54,0,11,2,56,15,11,1,56,16,56,17,2,5,1,0,0,1,20,14,1,56,18,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,7,39,11,0,54,1,11,2,56,15,11,1,56,19,56,20,2,6,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,11,0,54,0,11,1,11,2,11,3,56,21,2,7,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,11,0,54,1,11,1,11,2,11,3,56,22,2,8,1,0,0,64,49,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,5,1,11,4,1,7,5,39,14,2,56,14,10,1,38,4,19,5,27,11,0,1,11,5,1,11,4,1,7,6,39,14,3,56,18,12,6,11,0,11,1,9,11,2,11,3,11,4,11,5,56,23,12,8,12,7,14,8,56,18,12,9,11,7,11,8,11,9,11,6,23,2,9,1,0,0,65,48,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,4,1,11,2,1,7,5,39,14,3,56,18,10,1,38,4,19,5,27,11,0,1,11,4,1,11,2,1,7,7,39,11,0,11,1,7,26,11,2,17,65,11,3,56,19,56,24,12,6,12,5,14,5,56,25,12,7,11,5,10,4,56,26,11,6,11,4,56,27,11,7,2,10,0,0,0,69,215,2,10,0,55,2,17,84,20,12,23,11,1,12,28,56,7,12,10,11,4,12,25,10,0,54,3,12,9,10,9,46,56,28,4,25,11,0,1,11,9,1,11,10,11,25,2,10,9,46,56,29,12,30,12,32,9,12,29,10,9,46,56,28,32,4,43,5,38,10,32,10,2,37,12,5,5,45,9,12,5,11,5,4,212,2,10,9,10,30,56,30,12,31,10,31,16,4,56,31,56,32,20,12,22,10,31,16,4,56,33,32,4,180,2,5,63,10,31,16,4,10,22,56,34,12,16,10,16,16,5,20,12,15,9,12,26,10,16,16,6,20,10,3,37,4,95,8,12,26,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,35,10,23,10,16,56,36,5,249,1,10,15,10,16,16,8,20,17,54,12,18,4,106,11,18,6,1,0,0,0,0,0,0,0,22,12,18,11,18,7,20,10,0,55,4,20,22,17,54,12,18,4,119,11,18,6,1,0,0,0,0,0,0,0,22,12,18,10,28,10,18,38,4,137,1,11,18,12,12,10,12,7,20,10,0,55,4,20,22,17,52,12,13,1,10,15,12,11,5,186,1,8,12,29,10,28,7,20,10,0,55,4,20,22,17,55,12,13,1,11,13,10,16,16,8,20,17,55,12,11,1,11,11,10,0,55,5,20,26,10,0,55,5,20,24,12,11,10,11,10,16,16,8,20,17,56,12,13,10,13,10,0,55,4,20,17,57,12,27,4,182,1,11,27,6,1,0,0,0,0,0,0,0,22,12,27,10,13,11,27,22,12,12,10,13,10,0,55,6,20,17,56,12,19,11,15,10,11,23,12,15,11,28,10,12,23,12,28,10,28,6,0,0,0,0,0,0,0,0,33,4,206,1,8,12,29,10,0,54,0,10,16,16,7,20,10,11,56,37,12,14,13,25,10,12,56,38,12,24,10,0,54,1,10,16,16,7,20,13,24,10,19,10,13,22,56,38,56,20,10,0,54,7,11,24,56,39,1,13,10,11,14,56,40,1,10,0,55,2,17,84,20,10,16,11,11,11,12,11,13,23,11,19,56,41,11,26,4,254,1,8,12,6,5,130,2,10,15,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,165,2,10,22,12,21,10,31,16,4,10,22,56,42,12,20,10,20,56,43,32,4,148,2,11,20,56,32,20,12,22,5,150,2,11,20,1,10,0,54,8,11,16,16,7,20,56,44,10,21,56,45,1,10,31,15,4,11,21,56,46,1,5,176,2,11,16,1,10,31,15,4,10,22,56,47,12,17,11,15,11,17,15,5,21,10,29,4,179,2,5,180,2,5,57,11,31,16,4,56,33,4,204,2,10,9,11,32,12,7,46,11,7,56,48,1,12,32,10,9,11,30,56,49,17,0,10,9,10,32,12,8,46,11,8,56,50,12,30,1,10,29,4,211,2,11,0,1,11,9,1,5,212,2,5,32,11,10,11,25,2,11,0,0,0,85,153,2,10,0,55,2,17,84,20,12,22,11,1,12,25,56,7,12,11,11,4,12,23,10,0,54,3,12,10,10,10,46,56,28,4,25,11,0,1,11,10,1,11,11,11,23,2,10,10,46,56,29,12,28,12,30,10,10,46,56,28,32,4,41,5,36,10,30,10,2,37,12,5,5,43,9,12,5,11,5,4,150,2,10,10,10,28,56,30,12,29,10,29,16,4,56,31,56,32,20,12,21,10,29,16,4,56,33,32,4,244,1,5,61,10,29,16,4,10,21,56,34,12,16,10,16,16,5,20,12,15,9,12,24,10,16,16,6,20,10,3,37,4,93,8,12,24,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,35,10,22,10,16,56,36,5,183,1,10,25,10,15,36,4,100,10,15,12,6,5,102,10,25,12,6,11,6,12,12,10,12,10,16,16,8,20,17,53,12,13,10,13,10,0,55,6,20,17,56,12,18,10,13,10,0,55,4,20,17,57,12,26,4,127,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,15,10,12,23,12,15,11,25,10,12,23,12,25,10,0,54,0,10,16,16,7,20,10,12,56,37,12,14,13,23,10,26,56,38,12,27,10,0,54,1,10,16,16,7,20,13,27,10,18,56,38,56,20,10,0,54,7,11,27,56,39,1,13,11,11,14,56,40,1,10,0,54,1,10,16,16,7,20,13,23,11,13,56,38,56,20,10,0,55,2,17,84,20,10,16,11,12,11,26,11,18,56,41,11,24,4,188,1,8,12,7,5,192,1,10,15,6,0,0,0,0,0,0,0,0,33,12,7,11,7,4,227,1,10,21,12,20,10,29,16,4,10,21,56,42,12,19,10,19,56,43,32,4,210,1,11,19,56,32,20,12,21,5,212,1,11,19,1,10,0,54,8,11,16,16,7,20,56,44,10,20,56,45,1,10,29,15,4,11,20,56,46,1,5,238,1,11,16,1,10,29,15,4,10,21,56,47,12,17,11,15,11,17,15,5,21,10,25,6,0,0,0,0,0,0,0,0,33,4,243,1,5,244,1,5,55,11,29,16,4,56,33,4,140,2,10,10,11,30,12,8,46,11,8,56,48,1,12,30,10,10,11,28,56,49,17,0,10,10,10,30,12,9,46,11,9,56,50,12,28,1,10,25,6,0,0,0,0,0,0,0,0,33,4,149,2,11,0,1,11,10,1,5,150,2,5,30,11,11,11,23,2,12,0,0,0,86,158,2,10,0,55,2,17,84,20,12,22,11,3,12,10,56,8,12,23,10,0,54,9,12,9,10,9,46,56,28,4,23,11,0,1,11,9,1,11,10,11,23,2,10,9,46,56,51,12,28,12,30,10,9,46,56,28,32,4,39,5,34,10,30,10,1,38,12,4,5,41,9,12,4,11,4,4,155,2,10,9,10,28,56,30,12,29,10,29,16,4,56,31,56,32,20,12,21,10,29,16,4,56,33,32,4,248,1,5,59,10,29,16,4,10,21,56,34,12,15,10,15,16,5,20,12,14,9,12,24,10,15,16,6,20,10,2,37,4,97,8,12,24,10,15,16,5,20,10,15,16,8,20,17,53,12,17,10,0,54,1,10,15,16,7,20,11,17,56,52,10,22,10,15,56,36,5,186,1,14,10,56,25,12,25,10,25,10,14,38,4,107,10,14,12,5,5,109,11,25,12,5,11,5,12,11,10,11,10,15,16,8,20,17,53,12,12,10,12,10,0,55,6,20,17,56,12,18,10,12,10,0,55,4,20,17,57,12,26,4,134,1,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,14,10,11,23,12,14,10,0,54,1,10,15,16,7,20,11,12,56,53,12,13,13,13,10,26,56,38,12,27,10,0,54,1,10,15,16,7,20,13,27,10,18,56,38,56,20,10,0,54,7,11,27,56,39,1,13,23,11,13,56,39,1,10,0,54,0,10,15,16,7,20,13,10,10,11,56,54,56,17,10,0,55,2,17,84,20,10,15,11,11,11,26,11,18,56,41,11,24,4,191,1,8,12,6,5,195,1,10,14,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,230,1,10,21,12,20,10,29,16,4,10,21,56,42,12,19,10,19,56,43,32,4,213,1,11,19,56,32,20,12,21,5,215,1,11,19,1,10,0,54,8,11,15,16,7,20,56,44,10,20,56,45,1,10,29,15,4,11,20,56,46,1,5,241,1,11,15,1,10,29,15,4,10,21,56,47,12,16,11,14,11,16,15,5,21,14,10,56,25,6,0,0,0,0,0,0,0,0,33,4,247,1,5,248,1,5,53,11,29,16,4,56,33,4,144,2,10,9,11,30,12,7,46,11,7,56,55,1,12,30,10,9,11,28,56,49,17,0,10,9,10,30,12,8,46,11,8,56,50,12,28,1,14,10,56,25,6,0,0,0,0,0,0,0,0,33,4,154,2,11,0,1,11,9,1,5,155,2,5,28,11,10,11,23,2,13,1,0,0,87,85,10,1,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,9,5,17,11,0,1,11,6,1,11,5,1,7,5,39,10,1,6,0,0,0,0,0,0,0,0,34,4,22,5,30,11,0,1,11,6,1,11,5,1,7,5,39,11,2,4,52,11,0,11,1,7,26,11,5,17,65,11,4,56,19,56,56,12,9,12,7,13,3,11,7,10,6,56,26,56,57,11,9,11,6,56,27,12,4,5,82,11,1,14,3,56,14,37,4,58,5,66,11,0,1,11,6,1,11,5,1,7,6,39,11,0,7,27,11,5,17,65,11,3,56,16,56,58,12,8,10,6,56,26,12,3,13,4,11,8,11,6,56,27,56,59,11,3,11,4,2,14,0,0,0,89,118,10,5,56,15,12,13,10,3,4,30,10,2,10,1,17,53,12,11,10,0,54,1,11,5,11,11,56,60,10,0,55,10,20,12,10,10,0,55,10,20,6,1,0,0,0,0,0,0,0,22,10,0,54,10,21,10,0,54,9,12,8,5,50,10,0,54,0,11,5,10,2,56,61,10,0,55,11,20,12,10,10,0,55,11,20,6,1,0,0,0,0,0,0,0,22,10,0,54,11,21,10,0,54,3,12,8,10,10,10,1,10,2,10,3,10,13,10,4,18,4,12,9,10,8,10,1,12,7,46,11,7,56,50,12,12,32,4,75,10,8,10,1,10,1,10,6,56,62,18,5,56,63,12,12,11,8,11,12,56,30,15,4,10,10,11,9,56,64,10,0,55,2,17,84,20,10,10,11,3,10,13,11,2,10,1,11,4,57,1,56,65,10,0,55,8,10,13,56,66,32,4,107,10,0,54,8,10,13,11,6,56,67,56,68,5,109,11,6,1,11,0,54,8,11,13,56,44,10,10,11,1,56,69,11,10,2,15,1,0,0,96,144,2,10,2,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,1,6,0,0,0,0,0,0,0,0,36,4,20,5,30,11,0,1,11,8,1,11,6,1,11,7,1,7,4,39,10,1,10,0,55,12,20,25,6,0,0,0,0,0,0,0,0,33,4,39,5,49,11,0,1,11,8,1,11,6,1,11,7,1,7,4,39,10,2,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,58,5,68,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,4,10,6,17,65,36,4,74,5,84,11,0,1,11,8,1,11,6,1,11,7,1,7,18,39,10,7,56,15,12,19,10,3,4,128,1,10,0,55,1,10,19,56,70,12,18,10,0,54,1,10,7,10,18,56,71,12,14,10,0,10,2,10,1,11,6,17,65,11,14,56,56,12,16,12,10,14,10,56,25,12,12,11,18,14,16,56,72,23,12,17,10,0,54,0,10,19,11,10,56,17,10,0,54,1,11,19,11,16,56,20,5,160,1,10,0,54,0,10,7,10,2,56,73,12,9,10,0,10,1,11,6,17,65,11,9,56,58,12,15,12,11,10,2,14,11,56,25,23,12,12,14,15,56,72,12,17,10,0,54,0,10,19,11,11,56,17,10,0,54,1,11,19,11,15,56,20,10,5,7,23,33,4,175,1,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,24,33,4,197,1,11,0,1,11,8,1,11,7,1,10,12,11,2,33,4,190,1,5,192,1,7,8,39,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,25,33,4,228,1,10,12,6,0,0,0,0,0,0,0,0,33,4,206,1,5,214,1,11,0,1,11,8,1,11,7,1,7,9,39,11,0,11,1,11,2,11,3,11,4,11,7,11,8,56,74,12,13,11,12,11,17,8,11,13,2,11,5,7,22,33,4,233,1,5,241,1,11,0,1,11,8,1,11,7,1,7,13,39,10,2,10,12,36,4,133,2,11,0,11,1,11,2,10,12,23,11,3,11,4,11,7,11,8,56,74,12,13,11,12,11,17,8,11,13,2,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,16,0,0,0,1,4,11,0,7,26,35,2,17,0,0,0,1,19,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,11,1,16,8,20,57,2,56,75,2,18,0,0,0,1,27,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,10,2,10,1,16,5,20,11,2,23,11,1,16,8,20,11,3,11,4,57,3,56,76,2,19,1,0,0,100,110,11,2,56,15,12,12,10,0,55,8,10,12,56,66,4,9,5,13,11,0,1,7,11,39,10,0,54,8,10,12,56,44,12,13,10,13,10,1,12,3,46,11,3,56,77,4,26,5,32,11,13,1,11,0,1,7,2,39,10,13,10,1,12,4,46,11,4,56,78,20,12,11,10,1,17,16,12,8,10,8,4,49,10,0,55,9,12,5,5,52,10,0,55,3,12,5,11,5,11,11,56,50,12,10,4,58,5,64,11,13,1,11,0,1,7,2,39,10,8,4,70,10,0,54,9,12,6,5,73,10,0,54,3,12,6,11,6,11,13,11,10,11,1,10,12,56,79,12,9,11,8,4,96,14,9,16,5,20,14,9,16,8,20,17,53,12,7,10,0,54,1,11,12,11,7,56,52,5,103,10,0,54,0,11,12,14,9,16,5,20,56,35,11,0,55,2,17,84,20,14,9,56,36,2,20,0,0,0,101,54,11,1,10,3,56,45,1,10,0,10,2,12,5,46,11,5,56,80,16,4,10,3,56,81,4,15,5,19,11,0,1,7,2,39,10,0,10,2,56,30,12,6,10,6,15,4,11,3,56,46,12,7,14,7,16,7,20,11,4,33,4,35,5,41,11,0,1,11,6,1,7,3,39,11,6,16,4,56,33,4,50,11,0,11,2,56,49,17,0,5,52,11,0,1,11,7,2,21,1,0,0,102,104,10,0,55,2,17,84,20,12,11,11,1,56,15,12,13,10,0,55,8,10,13,56,66,4,14,5,18,11,0,1,7,11,39,10,0,54,8,10,13,56,44,12,14,10,14,46,56,82,32,4,99,5,29,10,14,46,56,83,56,32,20,12,9,10,14,10,9,12,2,46,11,2,56,78,20,12,10,10,9,17,16,12,6,10,6,4,52,10,0,54,9,12,3,5,55,10,0,54,3,12,3,11,3,12,7,10,7,11,10,12,4,46,11,4,56,50,12,12,1,11,7,10,14,11,12,11,9,10,13,56,79,12,8,11,6,4,88,14,8,16,5,20,14,8,16,8,20,17,53,12,5,10,0,54,1,10,13,11,5,56,52,5,95,10,0,54,0,10,13,14,8,16,5,20,56,35,10,11,14,8,56,36,5,23,11,14,1,11,0,1,2,22,1,0,0,103,148,1,10,0,55,2,17,84,20,12,15,11,2,56,15,12,18,10,0,55,8,10,18,56,66,4,14,5,18,11,0,1,6,0,0,0,0,0,0,0,0,39,6,0,0,0,0,0,0,0,0,12,16,6,0,0,0,0,0,0,0,0,12,17,14,1,65,20,12,10,6,0,0,0,0,0,0,0,0,12,8,10,0,54,8,10,18,56,44,12,19,10,8,10,10,35,4,143,1,5,37,14,1,10,8,66,20,20,12,14,10,19,10,14,12,3,46,11,3,56,77,4,50,5,56,11,19,1,11,0,1,7,2,39,10,19,10,14,12,4,46,11,4,56,78,20,12,12,10,14,17,16,12,9,10,12,10,17,34,4,96,11,12,12,17,10,9,4,79,10,0,55,9,12,5,5,82,10,0,55,3,12,5,11,5,10,17,56,50,12,11,4,88,5,94,11,19,1,11,0,1,7,10,39,11,11,12,16,10,9,4,102,10,0,54,9,12,6,5,105,10,0,54,3,12,6,11,6,10,19,10,16,11,14,10,18,56,79,12,13,11,9,4,128,1,14,13,16,5,20,14,13,16,8,20,17,53,12,7,10,0,54,1,10,18,11,7,56,52,5,135,1,10,0,54,0,10,18,14,13,16,5,20,56,35,10,15,14,13,56,36,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,32,11,19,1,11,0,1,2,23,1,0,0,104,84,11,1,56,15,12,7,10,0,55,8,11,7,56,84,12,8,64,28,0,0,0,0,0,0,0,0,12,3,10,8,56,85,12,5,10,5,56,43,32,4,76,5,18,10,8,10,5,56,32,20,56,78,20,12,6,10,5,56,32,20,17,16,4,36,10,0,55,9,11,6,56,86,12,2,5,41,10,0,55,3,11,6,56,86,12,2,11,2,16,4,10,5,56,32,20,56,34,12,4,13,3,10,4,16,18,20,10,4,16,8,20,10,4,16,5,20,10,4,16,19,20,10,4,16,7,20,11,4,16,6,20,18,4,68,28,10,8,11,5,56,32,20,56,87,12,5,5,13,11,8,1,11,0,1,11,5,1,11,3,2,24,1,0,0,105,20,11,1,56,15,12,6,10,0,55,0,10,6,56,88,12,3,12,2,11,0,55,1,11,6,56,89,12,5,12,4,11,2,11,3,11,4,11,5,2,25,1,0,0,106,86,10,0,55,9,56,29,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,9,56,51,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,9,11,1,56,90,12,1,10,0,55,9,11,2,56,90,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,9,10,1,10,3,17,65,56,91,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,9,11,1,56,48,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,26,1,0,0,106,86,10,0,55,3,56,29,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,3,56,51,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,3,11,1,56,90,12,1,10,0,55,3,11,2,56,90,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,3,10,1,10,3,17,65,56,91,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,3,11,1,56,48,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,27,0,0,0,107,49,11,0,11,1,56,86,16,4,12,6,6,0,0,0,0,0,0,0,0,12,3,10,6,56,31,12,5,10,5,56,43,32,4,43,5,15,10,6,10,5,56,32,20,56,34,12,4,10,4,16,6,20,10,2,36,4,34,11,3,11,4,16,5,20,22,12,3,5,36,11,4,1,10,6,11,5,56,32,20,56,42,12,5,5,10,11,6,1,11,5,1,11,3,2,28,1,0,0,108,52,11,2,56,15,12,5,10,0,55,8,10,5,56,66,4,9,5,13,11,0,1,7,11,39,10,0,55,8,11,5,56,84,12,6,10,6,10,1,56,77,4,23,5,29,11,6,1,11,0,1,7,2,39,11,6,10,1,56,78,20,12,4,10,1,7,26,35,4,42,11,0,55,9,12,3,5,45,11,0,55,3,12,3,11,3,11,4,56,86,16,4,11,1,56,34,2,6,10,6,11,6,0,6,2,5,1,4,2,4,5,4,4,4,1,6,6,6,9,6,7,6,14,6,5,6,1,6,3,6,4,6,8,4,0,4,3,0,55,1,55,2,55,3,55,9,55,10,55,11,55,12,55,13,55,14,55,15,55,16,55,17,55,0],"critbit":[161,28,235,11,6,0,0,0,14,1,0,6,2,6,28,3,34,194,1,4,228,1,54,5,154,2,235,1,7,133,4,153,4,8,158,8,64,6,222,8,120,10,214,9,51,11,137,10,4,12,141,10,217,17,13,230,27,28,14,130,28,20,15,150,28,2,0,13,1,43,1,44,0,2,6,1,0,0,0,1,6,0,0,0,4,1,4,0,1,3,12,2,7,1,4,1,2,4,2,0,0,31,0,1,1,4,0,42,2,3,1,4,0,21,2,4,1,4,0,30,2,5,1,4,0,29,2,5,1,4,0,36,6,5,1,4,0,33,6,5,1,4,0,26,6,3,1,4,0,40,6,3,1,4,0,19,7,3,1,4,0,17,6,8,1,4,0,16,6,3,1,4,0,38,9,10,1,4,0,10,9,11,1,4,0,7,6,12,1,4,0,8,6,12,1,4,0,15,1,13,1,6,0,14,1,13,1,4,0,18,6,3,1,4,0,45,14,13,1,4,0,22,15,4,1,4,0,12,16,17,0,1,5,26,13,2,7,4,1,6,22,23,2,7,4,1,9,28,30,2,7,4,1,14,19,13,2,7,4,1,15,19,13,2,7,6,1,21,21,4,2,7,4,1,27,21,3,2,7,4,1,31,0,19,2,7,4,1,37,28,29,2,7,4,29,18,29,20,28,20,27,20,2,10,23,20,10,10,20,10,23,18,8,10,7,10,22,20,18,10,22,18,19,10,6,10,5,10,30,20,1,10,24,18,24,20,30,18,14,10,26,18,26,20,25,20,25,18,1,7,8,4,1,11,2,1,9,0,1,6,11,2,1,9,0,1,3,1,1,2,3,3,2,6,11,2,1,9,0,3,3,7,11,2,1,9,0,3,9,0,2,1,3,2,7,11,2,1,9,0,3,1,9,0,1,7,9,0,1,6,9,0,0,4,7,11,2,1,9,0,3,3,1,3,6,11,2,1,9,0,3,3,1,4,1,2,2,3,8,1,1,11,3,2,9,0,9,1,2,3,11,0,1,9,0,1,6,11,3,2,9,0,9,1,2,6,11,3,2,9,0,9,1,9,0,1,6,9,1,4,1,3,3,3,16,3,3,3,3,3,2,6,8,1,1,1,8,1,3,3,11,0,1,9,0,3,3,3,3,7,11,3,2,9,0,9,1,9,0,9,1,16,3,3,3,3,3,3,3,3,3,1,3,3,6,8,1,3,3,9,0,2,7,11,3,2,9,0,9,1,9,0,1,9,1,1,7,9,1,2,11,3,2,3,8,1,11,3,2,3,11,0,1,9,0,2,6,8,1,3,2,2,2,11,67,114,105,116,98,105,116,84,114,101,101,12,73,110,116,101,114,110,97,108,78,111,100,101,4,76,101,97,102,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,4,99,108,111,98,19,99,111,117,110,116,95,108,101,97,100,105,110,103,95,122,101,114,111,115,7,99,114,105,116,98,105,116,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,29,103,101,116,95,99,108,111,115,101,115,116,95,108,101,97,102,95,105,110,100,101,120,95,98,121,95,107,101,121,11,105,110,115,101,114,116,95,108,101,97,102,14,105,110,116,101,114,110,97,108,95,110,111,100,101,115,8,105,115,95,101,109,112,116,121,13,105,115,95,108,101,102,116,95,99,104,105,108,100,3,107,101,121,6,108,101,97,118,101,115,10,108,101,102,116,95,99,104,105,108,100,14,108,101,102,116,95,109,111,115,116,95,108,101,97,102,6,108,101,110,103,116,104,4,109,97,115,107,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,3,110,101,119,24,110,101,120,116,95,105,110,116,101,114,110,97,108,95,110,111,100,101,95,105,110,100,101,120,9,110,101,120,116,95,108,101,97,102,15,110,101,120,116,95,108,101,97,102,95,105,110,100,101,120,6,112,97,114,101,110,116,13,112,114,101,118,105,111,117,115,95,108,101,97,102,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,11,114,105,103,104,116,95,99,104,105,108,100,15,114,105,103,104,116,95,109,111,115,116,95,108,101,97,102,4,114,111,111,116,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,112,100,97,116,101,95,99,104,105,108,100,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,128,3,8,255,255,255,255,255,255,255,255,3,8,255,255,255,255,255,255,255,127,0,2,3,23,3,46,9,0,35,3,1,2,4,28,3,25,3,39,3,35,3,2,2,7,41,3,20,11,3,2,3,8,1,24,11,3,2,3,11,0,1,9,0,30,3,29,3,32,3,34,3,2,10,0,10,0,3,0,0,13,11,7,9,10,0,56,0,11,0,56,1,7,9,7,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,57,0,2,1,3,0,0,13,4,11,0,55,0,56,2,2,2,3,0,0,13,4,11,0,55,0,56,3,2,3,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,1,20,56,5,55,2,20,11,0,55,1,20,2,4,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,0,55,3,20,2,5,1,0,0,24,78,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,36,5,30,10,0,10,4,11,5,56,7,12,2,5,38,9,12,2,11,2,4,50,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,59,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,7,20,56,9,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,6,3,0,0,24,79,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,37,5,30,10,0,10,4,11,5,56,7,32,12,2,5,39,9,12,2,11,2,4,51,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,60,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,8,20,56,10,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,7,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,7,20,12,2,5,2,11,0,1,11,2,2,8,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,8,20,12,2,5,2,11,0,1,11,2,2,9,3,0,0,25,247,1,10,1,11,2,7,9,57,1,12,15,10,0,55,6,20,12,16,10,0,55,6,20,6,1,0,0,0,0,0,0,0,22,10,0,54,6,21,10,16,7,11,6,1,0,0,0,0,0,0,0,23,35,4,24,5,28,11,0,1,7,1,39,10,0,54,0,10,16,11,15,56,11,10,0,10,1,12,3,46,11,3,56,12,12,7,10,7,7,9,33,4,69,10,16,6,0,0,0,0,0,0,0,0,33,4,49,5,53,11,0,1,7,2,39,7,10,10,16,23,10,0,54,7,21,10,16,10,0,54,1,21,11,16,11,0,54,3,21,6,0,0,0,0,0,0,0,0,2,10,0,55,0,11,7,56,5,55,2,20,12,6,10,6,10,1,34,4,81,5,85,11,0,1,7,3,39,49,64,11,6,10,1,29,53,17,21,49,64,23,23,12,8,6,1,0,0,0,0,0,0,0,11,8,49,1,23,47,12,17,10,17,7,9,7,9,7,9,18,1,12,12,10,0,55,8,20,12,13,10,0,55,8,20,6,1,0,0,0,0,0,0,0,22,10,0,54,8,21,10,0,54,5,10,13,11,12,56,13,10,0,55,7,20,12,18,7,9,12,14,10,18,7,9,35,4,169,1,5,135,1,10,0,55,5,10,18,56,8,12,9,10,17,10,9,16,12,20,36,4,149,1,11,9,1,5,169,1,11,18,12,14,10,1,10,9,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,164,1,11,9,16,7,20,12,18,5,168,1,11,9,16,8,20,12,18,5,130,1,10,14,7,9,33,4,178,1,10,13,10,0,54,7,21,5,193,1,10,0,10,14,10,18,12,5,12,4,46,11,4,11,5,56,7,12,10,10,0,11,14,10,13,11,10,56,14,11,17,10,1,28,6,0,0,0,0,0,0,0,0,33,12,11,10,0,10,13,7,10,10,16,23,10,11,56,14,10,0,11,13,11,18,11,11,32,56,14,10,0,55,0,10,0,55,1,20,56,5,55,2,20,10,1,36,4,227,1,10,16,10,0,54,1,21,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,1,35,4,243,1,10,16,11,0,54,3,21,5,245,1,11,0,1,11,16,2,10,3,0,0,3,27,10,0,56,4,4,8,11,0,1,9,7,9,2,10,0,10,1,56,12,12,2,11,0,55,0,10,2,56,5,55,2,20,11,1,34,4,24,9,7,9,2,8,11,2,2,11,3,0,0,3,18,10,0,56,4,4,7,11,0,1,6,0,0,0,0,0,0,0,0,2,10,0,11,1,56,12,12,2,11,0,55,0,11,2,56,5,55,2,20,2,12,3,0,0,27,171,1,10,0,55,0,10,1,56,5,55,2,20,12,12,10,0,55,1,20,10,1,33,4,25,10,0,10,12,12,4,46,11,4,56,15,12,9,1,11,9,10,0,54,1,21,10,0,55,3,20,10,1,33,4,43,10,0,11,12,12,5,46,11,5,56,16,12,10,1,11,10,10,0,54,3,21,10,0,54,0,10,1,56,17,58,1,12,15,12,17,1,10,0,46,56,18,6,0,0,0,0,0,0,0,0,33,4,78,7,9,10,0,54,7,21,7,9,10,0,54,1,21,7,9,10,0,54,3,21,6,0,0,0,0,0,0,0,0,10,0,54,8,21,6,0,0,0,0,0,0,0,0,11,0,54,6,21,5,169,1,10,15,7,9,34,4,83,5,87,11,0,1,7,6,39,10,0,55,5,10,15,56,8,12,14,10,14,16,6,20,12,13,10,0,10,15,7,10,11,1,23,12,7,12,6,46,11,6,11,7,56,7,4,113,11,14,16,8,20,12,8,5,117,11,14,16,7,20,12,8,11,8,12,16,10,13,7,9,33,4,149,1,10,16,7,9,35,4,135,1,7,9,10,0,54,5,10,16,56,19,15,6,21,5,144,1,7,9,10,0,54,0,7,10,10,16,23,56,20,54,4,21,11,16,10,0,54,7,21,5,164,1,10,0,10,13,10,15,12,3,12,2,46,11,2,11,3,56,7,12,11,10,0,11,13,11,16,11,11,56,14,11,0,54,5,11,15,56,21,1,11,17,2,13,3,0,0,13,6,11,0,54,0,11,1,56,20,54,9,2,14,3,0,0,13,6,11,0,55,0,11,1,56,5,55,9,2,15,3,0,0,3,14,10,0,11,1,56,6,12,2,4,6,5,10,11,0,1,7,4,39,11,0,11,2,56,22,2,16,3,0,0,31,14,11,0,58,0,1,1,1,1,12,2,12,1,1,11,1,56,23,11,2,56,24,2,17,3,0,0,31,23,14,0,55,0,56,2,6,0,0,0,0,0,0,0,0,33,4,7,5,9,6,0,0,0,0,0,0,0,0,39,11,0,58,0,1,1,1,1,12,2,12,1,1,11,2,56,25,11,1,56,26,2,18,0,0,0,32,46,10,0,55,7,20,12,3,10,3,7,9,33,4,12,11,0,1,7,9,2,10,3,7,9,35,4,40,5,17,10,0,55,5,11,3,56,8,12,2,10,1,10,2,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,35,11,2,16,7,20,12,3,5,39,11,2,16,8,20,12,3,5,12,11,0,1,7,10,11,3,23,2,19,0,0,0,13,55,10,1,7,9,34,4,5,5,9,11,0,1,7,7,39,11,3,4,19,10,2,10,0,54,5,10,1,56,19,15,7,21,5,26,10,2,10,0,54,5,10,1,56,19,15,8,21,10,2,7,9,34,4,52,10,2,7,9,36,4,44,11,1,11,0,54,0,7,10,11,2,23,56,20,54,4,21,5,51,11,1,11,0,54,5,11,2,56,19,15,6,21,5,54,11,0,1,2,20,0,0,0,13,9,11,0,55,5,11,1,56,8,16,7,20,11,2,33,2,21,0,0,0,33,107,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,49,128,12,1,5,105,49,0,12,2,10,0,50,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,23,11,0,49,64,47,12,0,11,2,49,64,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,37,11,0,49,32,47,12,0,11,2,49,32,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,51,11,0,49,16,47,12,0,11,2,49,16,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,65,11,0,49,8,47,12,0,11,2,49,8,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,79,11,0,49,4,47,12,0,11,2,49,4,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,93,11,0,49,2,47,12,0,11,2,49,2,22,12,2,11,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,103,11,2,49,1,22,12,2,11,2,12,1,11,1,2,2,2,2,3,0,0,2,4,0,2,2,1,1,3,1,1,1,2,2,6,2,0,2,5,1,0,0,1,0,10,1,10,2,10,3,10,4,10,5,10,9,10,10,10,11,10,13,10,0,11,0],"custodian":[161,28,235,11,6,0,0,0,14,1,0,12,2,12,48,3,60,158,1,4,218,1,30,5,248,1,246,1,7,238,3,166,4,8,148,8,64,6,212,8,10,10,222,8,38,11,132,9,4,12,136,9,238,2,13,246,11,8,14,254,11,6,15,132,12,2,0,23,1,15,1,21,1,35,1,37,1,38,0,0,4,1,0,1,0,1,12,0,0,4,12,1,0,1,1,2,4,1,0,1,2,3,12,1,0,1,3,5,7,0,3,8,4,0,4,6,12,2,7,1,4,1,5,7,2,0,0,33,0,1,0,0,10,2,3,1,0,0,34,0,4,1,0,0,42,5,6,1,0,0,28,7,8,1,0,0,24,9,10,1,0,0,29,11,8,1,0,0,25,12,10,1,0,0,31,9,8,1,0,0,40,12,8,1,0,0,9,2,13,1,0,0,12,2,13,1,0,0,19,14,15,1,0,0,17,2,16,1,0,1,30,27,13,1,0,1,36,30,10,1,0,1,41,24,13,1,0,1,43,8,10,1,0,2,26,26,6,1,0,3,34,0,17,0,3,39,28,29,0,4,13,31,8,2,7,4,4,16,21,23,2,7,4,4,18,32,33,2,7,4,4,22,21,22,2,7,4,4,34,0,25,2,7,4,24,20,22,20,16,19,25,20,5,19,18,19,12,19,14,19,15,19,6,19,7,19,4,19,17,19,21,20,23,20,1,7,8,8,1,8,1,2,6,11,2,1,9,0,8,5,2,3,3,1,11,2,1,9,0,4,7,11,2,1,9,0,3,6,8,1,7,8,8,1,11,4,1,9,0,3,7,11,2,1,9,0,8,5,11,3,1,9,0,0,3,7,11,2,1,9,0,6,8,1,3,1,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,11,3,1,9,0,3,7,11,2,1,9,0,8,5,3,1,3,2,7,11,2,1,9,0,8,5,1,7,11,0,1,9,0,1,6,11,0,1,9,0,1,8,6,3,6,11,0,1,9,0,3,3,1,9,0,2,8,5,11,0,1,9,0,2,6,11,7,2,9,0,9,1,9,0,1,1,1,6,9,1,1,6,11,3,1,9,0,1,11,7,2,9,0,9,1,2,11,3,1,9,0,7,8,8,2,7,11,3,1,9,0,11,3,1,9,0,1,6,8,6,1,8,5,2,7,11,3,1,9,0,3,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,7,9,1,7,65,99,99,111,117,110,116,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,4,67,111,105,110,9,67,117,115,116,111,100,105,97,110,2,73,68,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,16,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,115,22,97,99,99,111,117,110,116,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,3,97,100,100,17,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,22,98,111,114,114,111,119,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,26,98,111,114,114,111,119,95,109,117,116,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,4,99,108,111,98,4,99,111,105,110,8,99,111,110,116,97,105,110,115,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,105,110,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,4,106,111,105,110,12,108,111,99,107,95,98,97,108,97,110,99,101,14,108,111,99,107,101,100,95,98,97,108,97,110,99,101,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,110,101,119,6,111,98,106,101,99,116,5,115,112,108,105,116,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,0,2,2,14,11,3,1,9,0,32,11,3,1,9,0,1,2,1,27,8,6,2,2,2,27,8,6,11,11,7,2,8,5,11,0,1,9,0,2,19,0,19,0,1,0,0,8,4,11,0,17,19,18,1,2,1,3,0,0,18,27,10,0,55,0,10,1,56,0,32,4,11,11,0,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,2,11,0,55,0,11,1,56,1,12,2,10,2,55,1,56,2,12,3,11,2,55,2,56,2,12,4,11,3,11,4,2,2,3,0,0,8,6,10,0,17,19,11,0,56,3,57,0,2,3,3,0,0,8,7,11,0,11,2,11,1,56,4,11,3,56,5,2,4,3,0,0,8,8,11,0,11,1,56,6,54,1,11,2,56,7,1,2,5,3,0,0,8,9,11,0,11,1,16,3,17,20,56,6,54,1,11,2,56,8,2,6,3,0,0,8,10,11,0,11,1,16,3,17,20,56,6,54,2,11,2,56,7,1,2,7,3,0,0,8,7,11,0,11,1,56,6,54,2,11,2,56,8,2,8,3,0,0,10,10,10,0,10,1,11,2,56,4,12,3,11,0,11,1,11,3,56,9,2,9,3,0,0,10,10,10,0,10,1,11,2,56,10,12,3,11,0,11,1,11,3,56,11,2,10,3,0,0,8,7,11,0,55,0,11,1,56,1,55,1,56,2,2,11,3,0,0,8,7,11,0,55,0,11,1,56,1,55,2,56,2,2,12,0,0,0,8,18,10,0,55,0,10,1,56,0,32,4,13,10,0,54,0,10,1,56,12,56,12,57,1,56,13,11,0,54,0,11,1,56,14,2,13,0,0,0,8,15,10,0,55,0,10,1,56,0,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,1,2,2,1,0,0,0,1,1,0,0,19,1,19,2,19,0,20,0],"math":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,30,5,32,13,7,45,79,8,124,32,6,156,1,38,12,194,1,133,2,15,199,3,2,0,2,0,6,0,1,0,0,7,0,2,0,0,3,0,1,0,0,4,0,2,0,0,5,0,2,0,0,1,0,2,0,2,3,3,1,3,2,1,3,0,3,1,4,4,4,99,108,111,98,9,100,105,118,95,114,111,117,110,100,4,109,97,116,104,3,109,117,108,9,109,117,108,95,114,111,117,110,100,16,117,110,115,97,102,101,95,100,105,118,95,114,111,117,110,100,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,3,8,0,202,154,59,0,0,0,0,4,16,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,3,0,0,1,7,11,0,11,1,17,1,12,2,1,11,2,2,1,3,0,0,4,26,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,10,4,24,7,1,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,18,9,12,2,11,2,11,3,11,4,24,7,1,26,52,2,2,1,0,0,1,14,11,0,11,1,17,1,12,2,1,10,2,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,2,3,1,0,0,2,15,11,0,11,1,17,1,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,4,3,0,0,4,28,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,7,0,53,24,10,4,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,9,12,2,11,2,11,3,7,0,53,24,11,4,26,52,2,5,1,0,0,2,15,11,0,11,1,17,4,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,0,0,0]},"type_origin_table":[{"module_name":"custodian","struct_name":"Account","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"AccountCap","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"Custodian","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"Leaf","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"InternalNode","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"CritbitTree","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"PoolCreated","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlacedV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilledV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Order","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"TickLevel","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Pool","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlaced","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Package":{"id":"0x7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d","version":1,"module_map":{"migrate_proposal":[161,28,235,11,6,0,0,0,10,1,0,10,2,10,40,3,50,68,4,118,14,5,132,1,130,1,7,134,2,192,2,8,198,4,128,1,6,198,5,20,10,218,5,5,12,223,5,118,0,19,3,14,3,16,1,21,2,22,0,0,6,0,1,1,0,0,1,2,8,0,1,7,7,0,1,8,7,0,2,3,8,0,2,5,8,1,6,0,3,4,7,1,0,0,4,6,2,0,0,9,0,1,0,0,23,2,1,0,0,20,3,1,0,1,15,1,16,0,1,20,18,1,2,6,6,2,9,6,1,1,6,2,10,9,1,0,2,24,8,7,1,6,3,11,12,1,1,0,3,13,14,15,1,0,3,17,10,11,1,0,3,18,10,11,1,0,5,5,7,5,10,9,8,9,11,9,9,9,4,17,2,7,8,5,7,8,8,0,3,6,8,5,7,11,6,1,8,0,7,8,8,4,6,8,5,7,11,6,1,8,0,7,8,2,7,8,8,1,7,8,8,1,8,0,3,6,8,5,9,0,7,8,8,1,11,7,1,8,1,5,6,8,5,9,0,7,11,6,1,9,0,1,7,8,8,1,8,1,1,6,11,7,1,9,0,1,1,1,11,7,1,9,0,3,8,1,11,7,1,8,1,8,4,1,7,11,7,1,9,0,1,9,0,1,8,4,2,8,3,8,4,3,6,8,1,7,8,2,9,1,11,67,101,114,116,105,102,105,99,97,116,101,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,9,84,120,67,111,110,116,101,120,116,13,86,101,114,115,105,111,110,95,49,95,48,95,48,13,86,101,114,115,105,111,110,95,49,95,48,95,49,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,12,100,101,115,116,114,111,121,95,110,111,110,101,11,100,117,109,109,121,95,102,105,101,108,100,7,101,120,116,114,97,99,116,7,103,101,110,101,115,105,115,17,103,101,116,95,118,101,114,115,105,111,110,95,49,95,48,95,49,13,103,111,118,101,114,110,97,110,99,101,95,118,49,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,16,109,105,103,114,97,116,101,95,112,114,111,112,111,115,97,108,15,109,105,103,114,97,116,101,95,118,101,114,115,105,111,110,6,111,112,116,105,111,110,10,116,120,95,99,111,110,116,101,120,116,13,118,111,116,101,95,112,111,114,112,111,115,97,108,13,118,111,116,101,95,112,114,111,112,111,115,97,108,127,107,56,13,191,54,35,98,5,97,92,100,252,187,108,78,148,84,183,110,255,9,125,214,198,83,79,109,80,112,209,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,12,1,0,1,4,0,4,9,11,0,11,1,12,2,46,9,18,0,11,2,56,0,2,1,1,4,0,7,17,11,0,9,18,0,11,1,8,11,2,56,1,12,3,14,3,56,2,4,12,5,14,7,1,39,11,3,56,3,2,2,1,0,0,13,30,11,0,9,18,0,11,1,8,11,3,56,1,12,5,14,5,56,4,4,12,5,16,11,2,1,7,0,39,13,5,56,5,12,4,17,3,12,6,14,4,11,2,11,6,56,6,11,4,17,6,11,5,56,3,2,0]},"type_origin_table":[{"module_name":"migrate_proposal","struct_name":"Certificate","package":"0x7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":6},"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302":{"upgraded_id":"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302","upgraded_version":1},"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a":{"upgraded_id":"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a","upgraded_version":1},"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e":{"upgraded_id":"0xc5b2a5049cd71586362d0c6a38e34cfaae7ea9ce6d5401a350506a15f817bf72","upgraded_version":2}}}},"owner":"Immutable","previous_transaction":"5kWByxejQ95cxQ5zUCba3WyivedWBmtisRa4ZaWJuWpm","storage_rebate":10830000},{"data":{"Package":{"id":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","version":1,"module_map":{"app_manager":[161,28,235,11,6,0,0,0,10,1,0,10,2,10,24,3,34,46,4,80,2,5,82,54,7,136,1,228,1,8,236,2,64,10,172,3,18,12,190,3,106,13,168,4,4,0,8,0,11,1,16,1,20,1,21,0,3,12,0,0,0,12,0,1,1,0,0,2,2,7,0,2,5,4,0,4,4,2,0,0,14,0,1,0,0,17,2,3,0,0,18,4,3,0,0,12,5,6,0,0,10,3,1,0,2,9,7,1,0,2,15,0,7,0,2,22,12,8,0,3,19,10,1,1,8,8,9,1,7,8,5,0,2,7,8,0,7,8,5,1,8,1,3,6,8,2,7,8,0,7,8,5,1,6,8,1,1,13,1,8,4,1,8,3,1,8,0,1,9,0,3,8,1,8,3,8,4,1,6,8,4,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,2,73,68,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,97,112,112,95,99,97,112,115,6,97,112,112,95,105,100,11,97,112,112,95,109,97,110,97,103,101,114,6,100,101,108,101,116,101,15,100,101,115,116,114,111,121,95,97,112,112,95,99,97,112,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,2,105,100,4,105,110,105,116,3,110,101,119,6,111,98,106,101,99,116,12,114,101,103,105,115,116,101,114,95,97,112,112,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,8,4,6,10,8,3,1,2,2,13,8,4,7,13,0,0,0,0,1,6,11,0,17,6,64,8,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,11,19,11,1,17,6,12,4,14,4,17,7,12,3,11,4,10,0,16,0,65,8,75,18,1,12,2,11,0,15,0,11,3,68,8,11,2,2,2,1,0,0,1,4,11,1,11,2,17,1,2,3,1,0,0,1,4,11,0,16,1,20,2,4,1,0,0,1,5,11,0,19,1,1,17,5,2,0,1,1,1,0],"dola_address":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,12,3,24,109,4,133,1,6,5,139,1,78,7,217,1,191,3,8,152,5,96,6,248,5,14,10,134,6,8,12,142,6,151,2,13,165,8,4,0,13,0,23,1,4,1,27,2,3,2,5,0,0,7,0,2,1,7,0,3,2,7,0,0,20,0,1,0,0,19,2,1,0,0,18,2,3,0,0,29,4,5,0,0,28,6,5,0,0,10,7,5,0,0,6,8,5,0,0,7,5,8,0,0,9,0,5,1,0,0,8,5,3,0,0,15,5,3,0,0,11,3,5,0,1,12,19,1,0,1,24,14,0,0,1,25,15,0,0,1,30,17,18,1,1,2,21,13,3,0,3,17,0,12,1,0,3,22,12,13,0,4,16,3,8,0,5,26,9,3,1,0,20,8,17,11,15,10,0,1,13,1,6,8,0,1,10,2,2,8,0,13,1,8,0,2,8,0,10,2,2,13,10,2,1,5,1,6,9,0,1,2,1,9,0,1,8,2,1,8,1,2,7,10,2,13,2,7,10,2,10,2,6,10,2,3,10,2,13,3,3,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,11,68,111,108,97,65,100,100,114,101,115,115,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,112,111,111,108,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,19,117,112,100,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,13,2,0,0,0,2,2,14,13,13,10,2,0,1,0,0,0,2,7,1,2,1,1,0,0,0,4,11,0,16,0,20,2,2,1,0,0,0,4,11,0,16,1,20,2,3,1,0,0,0,6,11,1,13,0,15,0,21,11,0,2,4,1,0,0,0,6,11,1,13,0,15,1,21,11,0,2,5,1,0,0,0,4,11,0,11,1,18,0,2,6,1,0,0,0,5,7,1,14,0,56,0,18,0,2,7,1,0,0,0,14,14,0,16,1,65,10,6,32,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,14,0,16,1,20,17,19,2,8,1,0,0,3,8,56,1,17,18,17,16,12,0,7,1,11,0,18,0,2,9,1,0,0,0,4,14,0,16,1,20,2,10,1,0,0,3,14,64,10,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,17,13,13,1,14,0,16,1,20,17,14,11,1,2,11,1,0,0,16,30,14,0,65,10,12,6,6,0,0,0,0,0,0,0,0,12,5,6,2,0,0,0,0,0,0,0,12,2,14,0,10,5,10,5,10,2,22,56,2,12,1,14,1,17,12,12,4,11,5,11,2,22,12,5,14,0,11,5,11,6,56,2,12,3,11,4,11,3,18,0,2,0,0,0,1,0],"dola_pool":[161,28,235,11,6,0,0,0,14,1,0,22,2,22,52,3,74,173,1,4,247,1,32,5,151,2,211,1,7,234,3,168,5,8,146,9,96,6,242,9,50,10,164,10,34,11,198,10,2,12,200,10,222,2,13,166,13,4,14,170,13,4,15,174,13,4,0,23,0,22,0,45,1,12,1,54,2,13,2,14,2,27,2,43,2,52,2,53,0,5,12,1,0,1,0,3,3,0,0,10,3,0,1,4,7,0,3,6,7,0,4,8,7,0,5,0,4,1,0,1,6,1,12,1,0,1,6,2,12,1,0,1,8,9,4,0,10,7,2,0,0,30,0,1,1,0,0,19,2,3,1,0,0,16,4,5,0,0,42,6,5,1,0,0,55,6,5,1,0,0,21,7,8,1,0,0,57,9,3,1,0,0,48,10,8,0,1,15,19,21,0,1,17,21,19,0,1,18,3,21,1,0,1,32,30,8,0,1,33,30,29,0,1,34,3,29,0,2,25,22,8,0,2,26,35,8,0,3,37,26,8,0,4,29,3,25,1,0,4,38,25,26,0,5,39,24,5,1,0,5,51,31,15,1,0,5,59,3,15,1,0,6,28,32,23,1,0,6,31,12,1,1,0,6,36,23,15,1,0,6,56,20,5,1,0,7,24,11,3,1,3,8,41,13,14,0,9,46,34,3,1,12,9,50,11,3,1,8,10,49,18,19,0,23,11,21,11,29,16,0,11,25,11,3,11,10,11,24,11,19,11,17,11,26,27,4,11,20,11,22,11,26,33,28,23,1,6,11,0,1,9,0,1,2,2,6,11,8,1,9,0,7,8,10,0,3,3,2,2,1,3,2,6,11,0,1,9,0,3,5,7,11,0,1,9,0,11,7,1,9,0,13,10,2,7,8,10,1,10,2,5,7,11,0,1,9,0,8,3,3,8,3,7,8,10,3,13,10,2,7,8,10,1,9,0,1,6,11,8,1,9,0,1,7,8,10,1,8,9,1,11,6,1,9,0,1,11,0,1,9,0,6,3,3,3,10,2,5,8,3,1,6,8,10,1,5,1,6,11,7,1,9,0,1,8,3,5,8,3,8,3,3,13,10,2,1,11,7,1,9,0,2,7,11,6,1,9,0,11,6,1,9,0,1,8,5,1,8,4,1,8,1,3,3,11,7,1,9,0,5,1,13,1,6,8,3,2,7,11,6,1,9,0,3,2,11,6,1,9,0,7,8,10,1,8,2,2,9,0,5,3,8,3,13,10,2,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,11,68,101,112,111,115,105,116,80,111,111,108,11,68,111,108,97,65,100,100,114,101,115,115,4,80,111,111,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,12,87,105,116,104,100,114,97,119,80,111,111,108,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,11,99,114,101,97,116,101,95,112,111,111,108,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,4,101,109,105,116,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,12,103,101,116,95,100,101,99,105,109,97,108,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,12,105,110,116,111,95,98,97,108,97,110,99,101,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,10,112,111,111,108,95,99,111,100,101,99,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,35,8,9,13,11,6,1,9,0,20,2,1,2,3,44,8,4,49,5,11,3,2,2,3,44,8,4,47,5,11,3,0,11,0,1,0,0,3,4,11,0,55,0,20,2,1,1,0,0,1,10,11,0,56,0,12,2,11,1,17,27,56,1,11,2,57,0,56,2,2,2,1,0,0,3,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,3,1,0,0,1,8,11,0,56,3,12,2,11,1,11,2,49,8,17,2,2,4,1,0,0,1,8,11,0,56,3,12,2,11,1,49,8,11,2,17,2,2,5,3,0,0,17,38,11,4,46,17,30,12,9,14,1,56,4,12,7,10,0,10,7,12,5,46,11,5,56,5,12,6,10,9,17,8,12,10,56,6,11,10,11,6,11,2,11,3,17,14,12,8,11,0,54,1,11,1,56,7,56,8,1,56,9,17,18,11,9,11,7,18,1,56,10,11,8,2,6,3,0,0,28,53,17,13,14,3,17,12,33,4,6,5,12,11,0,1,11,4,1,7,4,39,14,3,17,11,56,9,17,18,17,16,33,4,20,5,26,11,0,1,11,4,1,7,0,39,11,1,17,9,12,7,10,0,11,2,12,5,46,11,5,56,11,12,2,11,0,54,1,10,2,56,12,11,4,56,13,12,6,56,9,17,18,10,7,11,2,18,2,56,14,11,6,11,7,56,15,2,7,3,0,0,3,8,11,2,46,17,30,17,8,11,0,11,1,17,15,2,0,2,0,1,0,11,1,11,0,40,0,58,0],"equilibrium_fee":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,50,5,54,29,7,83,174,1,8,129,2,32,12,161,2,197,5,0,4,0,10,0,2,0,1,0,0,3,2,1,0,0,0,3,1,0,0,1,3,1,0,1,5,0,1,0,1,6,4,1,0,1,7,0,1,0,1,8,4,1,0,1,9,1,1,0,1,11,0,1,0,2,15,15,1,15,3,15,15,15,6,15,15,15,15,15,15,0,4,1,15,15,15,6,1,15,15,15,15,15,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,27,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,112,101,114,99,101,110,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,1,13,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,11,11,1,11,0,17,6,12,2,11,2,2,1,1,0,0,1,17,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,15,11,0,11,1,17,6,11,2,17,6,17,5,17,4,12,3,11,3,2,2,1,0,0,5,93,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,1,10,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,2,23,10,0,10,2,23,10,3,17,1,10,4,36,4,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,10,4,36,4,50,10,1,10,0,10,4,17,9,10,3,17,9,23,17,5,10,4,10,3,17,9,23,17,6,12,7,5,52,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,12,9,10,2,10,9,23,10,5,17,5,10,4,10,3,17,9,23,17,9,24,10,4,10,3,17,9,26,12,8,10,0,11,1,23,11,5,17,7,17,9,24,10,0,11,9,23,11,0,11,2,23,17,6,17,8,17,9,11,4,11,3,17,9,26,11,8,23,2,3,1,0,0,6,51,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,12,7,11,1,10,2,22,11,0,10,2,22,11,3,17,1,11,7,23,12,9,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,4,11,5,17,6,24,12,11,11,2,11,11,17,6,17,5,17,4,12,10,11,9,11,10,17,4,12,8,11,4,11,8,17,9,2,0],"genesis":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,52,3,70,123,4,193,1,22,5,215,1,167,1,7,254,2,226,3,8,224,6,96,6,192,7,61,10,253,7,34,12,159,8,137,2,13,168,10,6,15,174,10,2,0,25,1,14,1,42,1,44,2,23,2,36,2,37,2,40,2,41,0,0,0,0,0,2,12,0,0,1,8,0,0,11,7,0,0,12,7,0,1,4,7,0,2,6,7,0,5,3,7,0,5,7,4,0,6,8,12,0,6,9,0,0,6,10,0,0,8,5,2,0,0,31,0,1,0,0,15,2,3,0,0,17,4,5,0,0,34,6,5,2,6,6,0,18,7,8,0,0,20,8,5,0,0,21,9,5,0,0,16,10,5,0,1,32,29,30,0,2,26,5,22,1,0,2,27,28,29,0,3,30,33,34,1,0,3,38,35,19,1,0,4,13,16,5,2,7,4,4,24,24,25,2,7,4,4,38,26,27,2,7,4,5,19,13,5,0,5,29,17,14,1,8,5,35,12,13,0,6,15,20,3,0,6,17,21,5,0,7,39,19,5,1,8,13,15,17,1,21,18,14,23,15,23,9,27,9,19,13,31,11,14,12,14,14,15,2,8,9,7,8,12,1,8,1,4,6,8,0,7,8,2,2,10,2,1,8,11,2,7,8,2,8,10,0,3,6,8,0,7,8,2,9,1,1,6,8,1,1,8,0,2,7,8,2,8,1,1,6,8,2,2,8,2,8,1,1,7,8,12,1,8,8,1,8,7,2,8,3,8,4,3,7,8,8,9,0,9,1,1,6,9,0,1,8,2,1,9,0,3,7,8,9,2,10,2,2,7,8,9,8,10,1,8,6,2,8,3,9,0,2,6,8,8,9,0,1,1,2,7,8,8,9,0,1,9,1,1,6,8,6,1,8,5,1,10,2,2,8,3,9,1,2,3,8,7,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,7,86,101,114,115,105,111,110,13,86,101,114,115,105,111,110,95,49,95,48,95,48,3,97,100,100,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,15,100,101,115,116,114,111,121,95,109,97,110,97,103,101,114,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,7,103,101,110,101,115,105,115,3,103,101,116,10,103,101,116,95,109,111,100,117,108,101,13,103,111,118,101,114,110,97,110,99,101,95,118,49,2,105,100,8,105,110,100,101,120,95,111,102,12,105,110,105,116,95,103,101,110,101,115,105,115,10,105,110,116,111,95,98,121,116,101,115,11,109,97,110,97,103,101,114,95,105,100,115,15,109,105,103,114,97,116,101,95,118,101,114,115,105,111,110,3,110,101,119,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,11,117,112,103,114,97,100,101,95,99,97,112,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,10,2,8,7,103,101,110,101,115,105,115,0,2,1,22,1,1,2,1,29,8,8,2,2,3,29,8,8,43,8,9,33,10,8,7,3,2,1,22,1,4,2,1,22,1,0,3,0,0,11,26,10,1,17,18,11,0,64,14,0,0,0,0,0,0,0,0,18,2,12,2,11,1,17,18,18,1,12,3,13,2,15,0,9,18,3,9,18,4,56,0,13,2,15,1,14,3,56,1,68,14,11,2,56,2,11,3,2,1,1,0,0,5,6,11,1,15,2,11,2,11,3,17,19,2,2,1,0,0,5,5,11,0,15,2,11,1,17,20,2,3,1,0,0,22,47,10,1,15,0,46,9,18,3,56,3,4,8,5,12,11,1,1,7,1,39,10,1,15,0,9,18,3,56,4,1,56,5,12,3,10,3,56,6,34,4,25,5,29,11,1,1,7,2,39,14,3,17,10,17,8,7,5,33,4,36,5,40,11,1,1,7,3,39,11,1,15,0,9,18,3,11,2,56,7,2,4,1,0,0,5,3,9,18,0,2,5,1,0,0,5,4,11,0,19,0,1,2,6,1,0,0,32,18,14,1,56,1,12,3,10,0,16,1,14,3,56,8,12,2,1,11,0,15,1,11,2,56,9,1,11,1,19,1,17,16,2,7,1,0,0,5,10,11,0,16,0,9,18,3,56,10,4,7,5,9,7,4,39,2,2,0,2,2,2,1,0,28,0],"governance_v1":[161,28,235,11,6,0,0,0,13,1,0,22,2,22,56,3,78,198,1,4,148,2,40,5,188,2,148,2,7,208,4,155,6,8,235,10,96,6,203,11,207,1,10,154,13,72,11,226,13,2,12,228,13,215,9,13,187,23,28,14,215,23,14,0,43,0,38,1,18,1,57,1,71,1,75,2,33,2,56,2,58,2,69,2,70,0,3,8,0,0,7,8,1,6,0,0,1,3,0,0,0,3,0,1,2,0,0,1,4,12,0,2,8,7,0,3,6,7,1,0,0,4,10,7,0,7,5,7,0,7,11,4,0,8,12,12,0,10,9,2,0,0,47,0,1,0,0,13,2,1,0,0,74,3,4,0,0,15,5,1,0,0,62,5,1,0,0,73,6,1,0,0,22,7,1,0,0,31,8,9,0,0,41,10,11,1,6,0,28,12,1,0,0,25,13,1,1,6,0,76,14,15,1,6,0,20,10,1,1,6,1,24,47,12,0,1,27,12,1,0,1,48,25,4,0,2,68,35,11,0,3,19,46,44,1,0,3,35,27,23,1,0,3,37,26,1,1,0,3,49,46,9,1,0,3,50,46,9,1,0,3,55,1,20,1,0,3,65,23,20,1,0,4,39,1,39,1,0,4,40,40,11,0,5,23,29,9,1,0,5,46,29,31,1,0,5,61,32,23,1,0,6,29,23,1,1,3,7,45,44,21,1,8,7,53,0,19,0,7,72,37,38,0,9,64,23,1,1,8,10,32,18,34,0,10,63,18,17,0,22,4,33,22,19,4,18,4,26,17,27,17,28,17,22,34,23,34,24,23,33,41,29,42,30,41,29,45,20,34,17,34,17,4,23,12,21,34,22,12,1,7,8,12,0,3,8,11,7,8,0,7,8,12,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,1,9,0,7,8,12,1,8,6,1,8,4,3,6,8,0,9,0,7,8,12,5,6,8,0,9,0,7,11,1,1,9,0,1,7,8,12,1,11,7,1,8,4,1,10,5,1,5,1,6,8,12,1,8,10,1,11,7,1,9,0,1,8,9,1,8,0,1,9,0,2,5,1,2,8,11,7,8,12,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,1,10,2,12,8,8,3,11,7,1,3,3,5,8,10,5,11,7,1,3,3,8,10,8,9,3,1,6,8,10,1,6,8,9,1,8,8,1,6,8,8,1,11,1,1,9,0,1,8,2,11,1,6,5,6,5,1,1,7,10,5,3,7,10,5,3,3,5,1,6,9,0,1,8,3,1,6,11,7,1,9,0,1,6,8,5,11,67,104,97,110,103,101,83,116,97,116,101,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,10,97,100,100,95,109,101,109,98,101,114,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,12,99,104,101,99,107,95,109,101,109,98,101,114,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,49,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,103,101,110,101,115,105,115,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,9,109,97,120,95,100,101,108,97,121,7,109,101,109,98,101,114,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,6,114,101,109,111,118,101,13,114,101,109,111,118,101,95,109,101,109,98,101,114,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,7,117,112,103,114,97,100,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,8,45,8,10,42,11,7,1,8,5,14,1,17,3,77,3,51,3,52,10,5,44,10,8,9,1,2,10,45,8,10,26,5,66,3,30,11,7,1,3,34,3,59,8,6,21,9,0,36,10,5,16,10,5,67,2,2,2,1,60,8,9,3,2,2,60,8,9,54,2,1,23,0,0,0,0,16,19,64,17,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,35,68,17,11,0,17,31,56,0,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,11,1,64,21,0,0,0,0,0,0,0,0,18,0,56,1,2,1,1,4,0,24,42,10,1,10,2,46,17,35,12,3,46,11,3,17,6,10,1,16,0,20,32,4,20,10,1,16,1,65,21,6,0,0,0,0,0,0,0,0,33,12,4,5,22,9,12,4,11,4,4,25,5,31,11,1,1,11,2,1,7,5,39,10,1,15,2,11,0,11,2,17,15,56,2,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,2,56,3,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,28,19,10,1,15,3,14,2,12,3,46,11,3,56,4,32,4,10,5,14,11,1,1,7,9,39,11,1,15,3,11,2,68,17,2,4,1,0,0,30,21,10,1,10,2,12,3,46,11,3,17,6,10,1,15,3,14,2,12,4,46,11,4,56,5,12,5,1,11,1,15,3,11,5,56,6,1,2,5,1,0,0,1,24,10,4,10,3,10,2,22,36,4,7,5,11,11,1,1,7,7,39,11,2,10,1,15,4,21,11,3,10,1,15,5,21,11,4,11,1,15,6,21,2,6,1,0,0,1,9,11,0,16,3,14,1,56,4,4,6,5,8,7,8,39,2,7,1,0,0,8,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,8,1,0,0,33,75,11,1,46,17,34,12,7,10,0,55,0,20,7,2,33,4,16,11,0,1,7,16,17,16,12,6,5,73,10,0,55,0,20,7,3,33,4,28,11,0,1,7,17,17,16,12,5,5,71,10,0,55,0,20,7,4,33,4,40,11,0,1,7,18,17,16,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,19,17,16,12,3,5,67,11,0,55,0,20,7,0,33,4,62,7,20,17,16,12,2,5,65,7,21,17,16,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,9,1,0,0,1,3,11,0,17,14,2,10,1,0,0,36,86,10,0,16,0,20,4,5,5,11,11,0,1,11,2,1,7,6,39,10,2,46,17,35,12,9,10,0,10,9,17,6,10,2,46,17,34,10,0,16,4,20,22,12,14,10,0,16,5,20,6,0,0,0,0,0,0,0,0,33,4,35,56,7,12,10,5,42,10,14,10,0,16,5,20,22,56,8,12,10,10,2,46,17,34,11,0,16,6,20,22,12,11,11,2,17,31,12,12,14,12,17,32,20,12,13,11,12,12,8,11,9,12,7,11,14,12,6,11,10,12,5,11,11,12,4,56,9,12,3,11,8,11,7,11,6,11,5,11,4,14,3,17,25,11,1,64,17,0,0,0,0,0,0,0,0,64,17,0,0,0,0,0,0,0,0,7,0,57,0,56,10,11,13,18,2,56,11,2,11,1,0,0,43,213,1,10,4,46,17,34,12,11,10,11,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,4,1,7,11,39,10,11,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,4,1,7,14,39,10,2,55,0,20,7,0,33,4,50,7,1,10,2,54,0,21,10,2,46,56,12,7,1,18,3,56,13,10,2,55,0,20,7,1,33,4,57,5,65,11,2,1,11,0,1,11,4,1,7,13,39,11,4,46,17,35,12,15,10,0,10,15,17,6,10,2,54,3,12,12,10,2,54,4,12,10,10,2,55,5,56,14,4,85,8,12,5,5,92,10,11,10,2,55,5,56,15,20,35,12,5,11,5,4,138,1,10,12,14,15,12,6,46,11,6,56,4,32,4,111,10,10,14,15,12,7,46,11,7,56,4,32,12,8,5,113,9,12,8,11,8,4,116,5,126,11,2,1,11,0,1,11,12,1,11,10,1,7,10,39,11,3,4,134,1,11,10,1,10,12,11,15,68,17,5,137,1,11,10,11,15,68,17,5,140,1,11,10,1,10,2,55,5,56,14,4,147,1,8,12,9,5,154,1,11,11,10,2,55,5,56,15,20,38,12,9,11,9,4,205,1,10,0,16,3,65,17,12,14,11,12,46,65,17,12,13,11,14,11,13,17,7,4,184,1,7,2,10,2,54,0,21,11,2,46,56,12,7,2,18,3,56,13,11,0,16,2,56,16,17,13,56,17,2,11,0,1,10,2,55,5,56,18,4,201,1,7,3,10,2,54,0,21,11,2,46,56,12,7,3,18,3,56,13,5,203,1,11,2,1,56,19,2,11,2,1,11,0,1,11,12,1,56,19,2,12,1,4,0,1,45,10,1,46,17,34,10,0,55,1,20,35,4,21,10,0,55,0,20,7,0,33,4,15,5,21,11,0,1,11,1,1,7,12,39,11,1,46,17,35,10,0,55,6,20,33,4,30,5,34,11,0,1,7,15,39,7,4,10,0,54,0,21,11,0,46,56,12,7,4,18,3,56,13,2,0,2,0,7,0,1,0,6,0,3,0,4,0,5,1,9,1,4,1,2,1,7,1,8,1,3,1,1,7,23,8,23,9,23,10,23,11,23,12,23,13,23,0],"governance_v2":[161,28,235,11,6,0,0,0,13,1,0,28,2,28,74,3,102,145,2,4,247,2,58,5,177,3,229,3,7,150,7,131,8,8,153,15,96,6,249,15,129,2,10,250,17,95,11,217,18,2,12,219,18,171,13,13,134,32,38,14,172,32,18,0,54,0,48,0,64,1,22,1,69,1,87,1,93,2,23,2,29,2,41,2,68,2,84,2,85,2,86,0,5,8,0,0,9,8,2,6,0,0,1,0,3,3,0,0,1,3,0,1,4,0,0,1,6,12,0,3,10,7,0,4,8,7,1,0,0,5,13,7,0,7,0,4,1,0,1,8,2,12,1,0,1,10,7,7,0,10,14,4,0,11,11,12,2,7,1,4,1,13,12,2,0,0,59,0,1,0,0,15,2,1,0,0,91,3,4,0,0,18,5,1,0,0,75,5,1,0,0,90,6,1,0,0,89,7,1,0,0,27,8,1,0,0,39,9,10,0,0,51,11,12,2,6,0,0,35,13,1,0,0,32,14,1,2,6,0,0,94,15,16,2,6,0,0,25,17,1,2,6,0,0,28,11,1,2,6,0,1,31,59,13,0,1,34,13,1,0,2,63,40,41,1,0,3,83,37,12,0,4,24,58,52,1,0,4,43,28,26,1,0,4,46,27,1,1,0,4,67,1,22,1,0,4,78,26,22,1,0,5,49,1,23,1,0,5,50,47,12,0,6,30,30,10,1,0,6,58,30,32,1,0,6,74,33,26,1,0,7,61,54,35,1,0,7,79,61,48,1,0,7,92,57,35,1,0,8,36,41,1,1,0,8,47,62,41,1,0,8,60,41,48,1,0,9,37,26,1,1,3,10,57,52,24,1,8,10,65,0,21,0,10,88,45,46,0,11,17,44,1,2,7,4,11,30,55,10,2,7,4,11,65,0,43,2,7,4,11,74,56,39,2,7,4,12,73,64,1,1,12,12,77,26,1,1,8,13,40,20,35,0,13,76,20,19,0,22,4,22,23,44,25,21,23,21,4,20,4,26,19,27,19,28,19,17,39,41,42,39,42,24,26,34,39,44,49,35,50,36,49,35,53,29,39,40,42,42,42,31,39,22,13,32,39,19,4,23,13,30,39,33,39,43,63,1,7,8,14,0,4,6,8,4,7,8,0,8,8,8,5,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,4,6,8,4,7,8,0,3,3,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,2,9,0,9,1,7,8,14,1,8,6,1,8,4,5,6,8,0,9,0,10,11,10,1,9,1,3,7,8,14,7,6,8,0,9,0,7,11,1,2,9,0,9,1,10,11,10,1,9,1,3,1,7,8,14,1,11,7,1,8,4,3,6,8,0,7,11,1,2,9,0,9,1,7,8,14,1,10,5,1,5,1,6,8,14,1,8,12,1,11,7,1,9,0,1,8,8,1,8,11,1,8,0,1,9,0,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,2,9,0,9,1,1,10,2,15,8,8,3,3,3,5,8,12,5,3,3,3,11,13,2,5,3,8,12,8,11,11,10,1,9,1,3,1,9,1,3,10,11,10,1,9,0,3,7,8,14,1,11,10,1,9,0,2,5,3,1,11,13,2,9,0,9,1,3,7,11,13,2,9,0,9,1,9,0,9,1,1,6,8,12,1,6,8,11,1,6,8,8,1,11,9,1,9,0,1,11,1,2,9,0,9,1,1,8,2,17,11,7,1,8,4,11,7,1,8,4,5,5,5,5,1,3,3,7,11,13,2,5,3,3,3,3,7,11,13,2,5,3,11,10,1,9,1,5,3,1,6,9,0,1,8,3,2,7,11,9,1,9,0,11,9,1,9,0,2,6,11,13,2,9,0,9,1,9,0,2,7,11,13,2,9,0,9,1,9,0,1,6,11,9,1,9,0,1,6,11,7,1,9,0,1,6,8,5,11,1,1,1,5,5,7,11,13,2,5,3,3,7,11,13,2,5,3,5,3,3,2,7,11,9,1,9,0,3,2,11,9,1,9,0,7,8,14,1,11,10,1,9,1,2,9,0,5,7,66,97,108,97,110,99,101,11,67,104,97,110,103,101,83,116,97,116,101,4,67,111,105,110,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,3,97,100,100,13,97,100,100,95,103,117,97,114,100,105,97,110,115,11,97,103,97,105,110,115,116,95,110,117,109,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,15,99,104,101,99,107,95,103,117,97,114,100,105,97,110,115,5,99,108,97,105,109,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,9,102,97,118,111,114,95,110,117,109,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,20,103,111,118,101,114,110,97,110,99,101,95,99,111,105,110,95,116,121,112,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,50,9,103,117,97,114,100,105,97,110,115,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,4,106,111,105,110,9,109,97,120,95,100,101,108,97,121,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,24,112,114,111,112,111,115,97,108,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,103,117,97,114,100,105,97,110,115,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,115,112,108,105,116,11,115,116,97,107,101,100,95,99,111,105,110,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,22,117,112,100,97,116,101,95,109,105,110,117,109,117,109,95,115,116,97,107,105,110,103,7,117,112,103,114,97,100,101,5,118,97,108,117,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,22,118,111,116,105,110,103,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,255,255,255,255,255,255,255,255,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,11,57,8,12,53,11,7,1,8,5,52,11,7,1,8,8,55,10,5,16,1,21,3,95,3,62,3,72,3,96,3,56,10,8,11,1,2,13,57,8,12,33,5,81,3,38,3,42,3,70,8,6,26,9,0,80,11,9,1,9,1,44,3,45,11,13,2,5,3,19,3,20,11,13,2,5,3,82,2,2,2,1,71,8,11,3,2,2,71,8,11,66,2,1,36,0,0,0,0,18,22,64,19,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,46,68,19,11,0,17,37,56,0,56,1,64,19,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,6,1,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,64,24,0,0,0,0,0,0,0,0,18,0,56,2,2,1,1,0,0,10,34,10,1,16,0,20,32,4,12,10,1,16,1,65,24,6,0,0,0,0,0,0,0,0,33,12,4,5,14,9,12,4,11,4,4,17,5,21,11,1,1,7,6,39,10,1,15,2,11,2,56,3,10,1,15,3,11,3,56,4,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,3,56,5,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,29,19,10,1,15,4,14,2,12,3,46,11,3,56,6,32,4,10,5,14,11,1,1,7,10,39,11,1,15,4,11,2,68,19,2,4,1,0,0,31,21,10,1,10,2,12,3,46,11,3,17,7,10,1,15,4,14,2,12,4,46,11,4,56,7,12,5,1,11,1,15,4,11,5,56,8,1,2,5,1,0,0,1,9,11,2,10,1,15,5,21,11,3,11,1,15,6,21,2,6,1,0,0,1,33,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,9,11,1,1,7,8,39,10,4,10,3,10,2,22,36,4,16,5,20,11,1,1,7,8,39,11,2,10,1,15,7,21,11,3,10,1,15,8,21,11,4,11,1,15,9,21,2,7,1,0,0,1,9,11,0,16,4,14,1,56,6,4,6,5,8,7,9,39,2,8,1,0,0,9,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,9,1,0,0,34,75,11,1,46,17,45,12,7,10,0,55,0,20,7,3,33,4,16,11,0,1,7,21,17,18,12,6,5,73,10,0,55,0,20,7,4,33,4,28,11,0,1,7,22,17,18,12,5,5,71,10,0,55,0,20,7,5,33,4,40,11,0,1,7,23,17,18,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,24,17,18,12,3,5,67,11,0,55,0,20,7,1,33,4,62,7,25,17,18,12,2,5,65,7,26,17,18,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,10,1,0,0,1,3,11,0,17,16,2,11,1,0,0,38,103,10,0,16,0,20,4,5,5,11,11,0,1,11,4,1,7,7,39,11,2,10,3,10,4,56,9,12,18,10,3,10,0,16,5,20,38,4,23,5,29,11,0,1,11,4,1,7,16,39,10,4,46,17,46,12,11,10,4,46,17,45,12,12,10,12,10,0,16,7,20,22,12,19,10,19,10,0,16,8,20,22,12,13,11,12,11,0,16,9,20,22,12,14,10,4,56,10,12,15,13,15,10,11,10,3,56,11,10,4,17,37,12,16,14,16,17,38,20,12,17,11,16,12,10,11,11,12,9,11,19,12,8,11,13,12,7,11,14,12,6,56,12,12,5,11,10,11,9,11,8,11,7,11,6,14,5,17,25,11,1,11,18,56,13,11,3,11,15,6,0,0,0,0,0,0,0,0,11,4,56,10,7,1,57,0,56,14,11,17,18,2,56,15,2,12,1,0,0,51,175,2,10,6,46,17,45,12,17,10,17,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,6,1,7,12,39,10,17,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,6,1,7,15,39,10,2,55,0,20,7,1,33,4,50,7,2,10,2,54,0,21,10,2,46,56,16,7,2,18,3,56,17,10,2,55,0,20,7,2,33,4,57,5,65,11,2,1,11,0,1,11,6,1,7,14,39,10,6,46,17,46,12,22,10,2,54,3,12,20,10,2,54,4,12,16,11,3,10,4,11,6,56,9,12,21,11,17,10,2,55,5,20,35,4,237,1,11,0,1,10,2,54,6,11,21,56,13,56,18,1,11,5,4,158,1,10,2,55,7,20,10,4,22,10,2,54,7,21,11,4,12,18,10,20,10,22,12,9,46,11,9,56,19,4,119,11,18,10,20,10,22,56,20,22,12,18,10,16,10,22,12,10,46,11,10,56,19,4,151,1,11,16,10,22,56,20,12,14,10,2,55,7,20,10,14,22,10,2,54,7,21,10,2,55,8,20,10,14,23,10,2,54,8,21,11,18,11,14,22,12,18,5,153,1,11,16,1,11,20,11,22,11,18,56,11,5,219,1,10,2,55,8,20,10,4,22,10,2,54,8,21,11,4,12,15,10,16,10,22,12,11,46,11,11,56,19,4,181,1,11,15,10,16,10,22,56,20,22,12,15,10,20,10,22,12,12,46,11,12,56,19,4,213,1,11,20,10,22,56,20,12,19,10,2,55,8,20,10,19,22,10,2,54,8,21,10,2,55,7,20,10,19,23,10,2,54,7,21,11,15,11,19,22,12,15,5,215,1,11,20,1,11,16,11,22,11,15,56,11,10,2,55,7,20,10,2,55,8,20,22,11,2,55,6,56,21,33,4,232,1,5,234,1,7,19,39,56,22,12,8,5,173,2,11,20,1,11,16,1,11,21,56,23,10,2,55,7,20,10,2,55,8,20,22,12,23,10,23,10,2,55,7,20,17,8,4,136,2,11,23,10,0,16,6,20,38,12,13,5,138,2,9,12,13,11,13,4,157,2,7,3,10,2,54,0,21,11,2,46,56,16,7,3,18,3,56,17,11,0,16,3,56,24,17,15,56,25,12,7,5,171,2,11,0,1,7,4,10,2,54,0,21,11,2,46,56,16,7,4,18,3,56,17,56,22,12,7,11,7,12,8,11,8,2,13,1,4,0,19,41,10,2,46,17,45,10,1,55,1,20,35,4,23,10,1,55,0,20,7,1,33,4,15,5,23,11,1,1,11,0,1,11,2,1,7,13,39,11,2,46,17,46,12,3,11,0,11,3,17,7,7,5,10,1,54,0,21,11,1,46,56,16,7,5,18,3,56,17,2,14,1,4,0,60,129,1,10,1,46,17,45,12,8,10,0,55,0,20,7,3,33,4,13,8,12,2,5,19,10,0,55,0,20,7,4,33,12,2,11,2,4,24,8,12,3,5,30,10,0,55,0,20,7,5,33,12,3,11,3,4,35,8,12,4,5,41,11,8,10,0,55,1,20,38,12,4,11,4,4,44,5,50,11,0,1,11,1,1,7,20,39,10,1,46,17,46,12,10,10,0,54,3,12,9,10,0,54,4,12,7,10,9,10,10,12,5,46,11,5,56,19,4,90,11,7,1,11,9,10,10,56,20,12,12,10,0,54,6,10,12,56,26,11,1,56,27,11,10,56,28,10,0,55,7,20,11,12,23,11,0,54,7,21,5,128,1,11,9,1,10,7,10,10,12,6,46,11,6,56,19,4,100,5,108,11,0,1,11,1,1,11,7,1,7,11,39,11,7,10,10,56,20,12,11,10,0,54,6,10,11,56,26,11,1,56,27,11,10,56,28,10,0,55,8,20,11,11,23,11,0,54,8,21,2,0,4,0,10,0,2,0,1,0,3,0,8,0,9,0,5,0,6,0,7,1,12,1,4,1,2,1,9,1,11,1,3,1,7,1,8,1,10,10,36,11,36,12,36,13,36,14,36,15,36,16,36,17,36,18,36,0],"lending_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,126,4,136,1,2,5,138,1,175,1,7,185,2,166,4,8,223,6,32,6,255,6,41,12,168,7,192,10,0,22,0,9,0,23,1,0,7,0,0,20,0,1,0,0,21,0,1,0,0,16,0,1,0,0,19,0,1,0,0,18,0,1,0,0,15,0,1,0,0,17,0,1,0,0,10,2,3,0,0,1,3,2,0,0,14,4,3,0,0,5,3,4,0,0,12,5,3,0,0,3,3,6,0,0,13,7,3,0,0,4,3,7,0,1,2,3,11,0,1,11,11,3,0,2,6,17,18,0,2,7,17,19,0,2,8,17,1,0,2,24,9,0,0,2,25,10,0,0,2,26,13,0,0,2,27,12,0,0,2,28,15,16,1,1,24,1,0,1,2,4,13,3,8,0,2,1,10,2,6,13,3,3,8,0,8,0,2,4,13,3,8,0,3,5,13,3,8,0,3,2,2,10,13,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,11,10,2,10,2,10,2,10,2,3,3,2,3,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,3,10,2,10,2,10,2,16,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,2,3,8,0,13,13,8,0,13,13,10,2,10,2,10,2,10,2,10,2,3,3,2,3,3,13,8,0,13,3,3,10,2,3,10,10,2,10,2,10,2,3,13,10,13,13,3,2,13,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,101,110,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,101,110,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,8,24,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,22,11,4,2,8,1,0,0,14,92,6,0,0,0,0,0,0,0,0,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,1,14,1,17,17,12,11,11,6,11,5,22,12,6,6,8,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,2,14,2,17,18,12,8,11,6,11,5,22,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,3,14,3,17,17,12,9,11,6,11,5,22,12,6,11,9,52,12,5,14,0,10,6,10,6,10,5,22,56,0,17,15,12,10,11,6,11,5,22,12,6,6,1,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,4,14,4,17,19,12,7,11,6,11,5,22,14,0,65,1,33,4,85,5,87,7,0,39,11,11,11,8,11,10,11,7,2,9,1,0,0,20,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,20,13,6,11,1,17,21,13,6,11,2,17,21,11,3,17,16,12,7,13,6,14,7,65,1,75,17,20,13,6,11,7,17,23,11,4,17,16,12,8,13,6,14,8,65,1,75,17,20,13,6,11,8,17,23,13,6,11,5,17,22,11,6,2,10,1,0,0,21,141,1,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,18,12,11,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,18,12,7,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,15,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,19,12,10,11,9,11,8,22,14,0,65,1,33,4,132,1,5,134,1,7,0,39,11,16,11,11,11,7,11,12,11,15,11,10,2,11,1,0,0,8,27,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,21,13,4,7,6,17,22,11,4,2,12,1,0,0,22,118,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,1,14,1,17,17,12,11,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,2,14,2,17,18,12,10,11,7,11,6,22,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,3,14,3,17,17,12,13,11,7,11,6,22,12,7,11,13,52,12,6,14,0,10,7,10,7,10,6,22,56,0,17,15,12,12,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,4,14,4,17,18,12,9,11,7,11,6,22,12,7,6,1,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,5,14,5,17,19,12,8,11,7,11,6,22,12,7,10,8,7,6,33,4,102,5,104,7,1,39,11,7,14,0,65,1,33,4,110,5,112,7,0,39,11,11,11,10,11,12,11,9,11,8,2,13,1,0,0,23,32,64,1,0,0,0,0,0,0,0,0,12,3,14,0,65,18,12,4,13,3,10,4,75,17,20,6,0,0,0,0,0,0,0,0,12,2,10,2,10,4,35,4,27,5,16,13,3,14,0,10,2,66,18,20,17,20,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,13,3,11,1,17,22,11,3,2,14,1,0,0,24,76,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,1,14,1,17,17,12,10,11,8,11,4,22,12,8,72,0,0,12,7,64,18,0,0,0,0,0,0,0,0,12,6,10,7,10,10,35,4,51,5,27,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,2,14,2,17,17,12,5,13,6,11,5,68,18,11,8,11,4,22,12,8,11,7,72,1,0,22,12,7,5,22,6,1,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,3,14,3,17,19,12,9,11,8,11,4,22,14,0,65,1,33,4,71,5,73,7,0,39,11,6,11,9,2,0],"lending_core_storage":[161,28,235,11,6,0,0,0,12,1,0,20,2,20,52,3,72,245,2,4,189,3,40,5,229,3,172,2,7,145,6,149,16,8,166,22,96,6,134,23,20,10,154,23,101,12,255,23,239,16,13,238,40,62,15,172,41,6,0,77,0,17,0,43,0,91,1,122,2,31,2,87,2,109,2,112,2,115,0,6,8,0,0,11,4,0,0,4,4,0,0,5,4,0,0,1,4,0,1,0,12,0,1,8,12,0,2,3,0,0,5,2,8,0,6,10,4,0,7,7,12,2,7,1,4,1,9,9,2,0,0,72,0,1,0,0,93,2,1,0,0,104,3,1,0,0,102,3,1,0,0,106,4,1,0,0,105,4,1,0,0,99,4,1,0,0,103,4,1,0,0,100,4,1,0,0,101,5,1,0,0,45,6,7,0,0,61,8,9,0,0,73,10,11,0,0,30,10,11,0,0,58,6,12,0,0,42,13,11,0,0,41,10,11,0,0,65,13,9,0,0,63,13,9,0,0,66,13,14,0,0,64,13,14,0,0,67,13,14,0,0,69,15,9,0,0,68,15,9,0,0,60,10,12,0,0,52,10,9,0,0,62,10,9,0,0,59,10,9,0,0,57,10,9,0,0,46,10,9,0,0,50,10,9,0,0,53,10,9,0,0,56,10,9,0,0,51,10,9,0,0,55,10,9,0,0,54,10,9,0,0,48,10,9,0,0,47,10,9,0,0,49,10,16,0,0,44,6,17,0,0,85,18,1,0,0,29,18,1,0,0,84,18,1,0,0,28,18,1,0,0,14,15,1,0,0,96,15,1,0,0,13,15,1,0,0,95,15,1,0,0,15,15,1,0,0,97,15,1,0,0,119,19,1,0,0,117,20,1,0,0,118,21,1,0,0,116,22,1,0,0,40,23,1,0,1,45,17,7,0,1,92,0,26,0,3,90,1,9,0,4,34,46,11,1,0,4,71,46,48,1,0,4,94,49,31,1,0,5,110,8,12,0,6,86,24,25,0,7,12,34,1,2,7,4,7,20,32,39,2,7,4,7,23,36,37,2,7,4,7,34,32,11,2,7,4,7,81,40,12,2,7,4,7,86,24,28,2,7,4,7,94,36,44,2,7,4,8,107,31,1,1,8,68,27,68,29,70,30,66,27,68,33,63,27,65,27,64,27,67,27,66,29,64,29,66,33,64,33,69,33,63,33,65,29,58,7,59,7,60,7,63,29,3,6,8,7,7,8,6,7,8,11,0,17,6,8,7,7,8,0,6,8,8,13,1,1,3,15,15,15,15,15,15,15,15,15,7,8,11,4,6,8,7,7,8,0,13,1,4,6,8,7,7,8,0,13,15,7,6,8,7,7,8,0,13,15,15,15,15,1,7,8,0,1,13,1,6,8,8,1,15,2,7,8,0,13,1,1,1,3,2,7,8,0,3,1,10,13,3,7,8,0,3,13,4,15,15,15,15,1,6,8,5,4,7,8,0,13,3,15,4,7,8,0,6,8,8,3,15,3,7,8,0,13,15,6,7,8,0,13,15,15,15,15,4,7,8,0,13,15,15,3,7,8,0,6,8,8,3,1,7,8,11,1,8,9,1,8,5,2,13,8,2,1,11,10,2,9,0,9,1,2,3,8,1,1,8,0,1,9,0,2,6,11,10,2,9,0,9,1,9,0,2,3,15,3,7,11,10,2,9,0,9,1,9,0,9,1,1,7,8,2,2,7,11,10,2,9,0,9,1,9,0,1,7,9,1,1,7,8,4,1,6,9,1,1,6,11,10,2,9,0,9,1,2,15,6,8,2,1,6,8,4,2,15,7,8,3,1,9,1,1,7,8,1,2,6,10,9,0,6,9,0,2,3,7,8,1,2,1,3,2,7,10,9,0,3,2,3,7,8,2,6,65,112,112,67,97,112,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,11,82,101,115,101,114,118,101,68,97,116,97,13,83,99,97,108,101,100,66,97,108,97,110,99,101,7,83,116,111,114,97,103,101,5,84,97,98,108,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,85,115,101,114,73,110,102,111,3,97,100,100,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,17,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,16,98,97,115,101,95,98,111,114,114,111,119,95,114,97,116,101,6,98,111,114,114,111,119,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,18,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,49,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,50,23,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,5,99,108,111,99,107,22,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,11,99,111,108,108,97,116,101,114,97,108,115,8,99,111,110,116,97,105,110,115,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,23,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,22,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,13,100,116,111,107,101,110,95,115,99,97,108,101,100,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,10,103,101,116,95,97,112,112,95,105,100,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,18,103,101,116,95,114,101,115,101,114,118,101,95,108,101,110,103,116,104,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,13,103,101,116,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,2,105,100,8,105,110,100,101,120,95,111,102,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,12,105,115,111,108,97,116,101,95,100,101,98,116,19,108,97,115,116,95,97,118,101,114,97,103,101,95,117,112,100,97,116,101,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,13,108,105,113,117,105,100,95,97,115,115,101,116,115,5,108,111,97,110,115,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,13,111,116,111,107,101,110,95,115,99,97,108,101,100,3,114,97,121,8,114,97,121,95,109,97,116,104,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,20,114,101,103,105,115,116,101,114,95,110,101,119,95,114,101,115,101,114,118,101,6,114,101,109,111,118,101,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,8,114,101,115,101,114,118,101,115,22,115,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,22,115,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,23,115,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,27,115,101,116,95,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,26,115,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,21,115,101,116,95,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,22,115,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,8,116,114,101,97,115,117,114,121,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,10,117,115,101,114,95,105,110,102,111,115,10,117,115,101,114,95,115,116,97,116,101,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,70,8,9,16,8,5,98,11,10,2,13,8,2,120,11,10,2,3,8,1,1,2,5,18,15,75,15,82,10,13,33,10,13,83,10,13,2,2,17,73,1,27,1,74,15,76,15,113,3,114,15,108,15,21,15,36,15,38,15,35,15,37,15,32,15,22,15,24,8,4,89,8,3,39,8,3,3,2,2,121,11,10,2,3,15,111,15,4,2,4,19,15,25,15,26,15,88,15,0,1,0,0,1,13,10,2,17,62,11,0,11,1,10,2,17,56,10,2,56,0,11,2,56,1,18,0,56,2,2,1,1,0,0,1,49,10,1,16,0,10,3,56,3,32,4,7,5,15,11,1,1,11,16,1,11,2,1,7,0,39,11,1,15,0,11,3,11,4,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,2,17,11,11,6,11,7,11,8,11,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,57,17,57,11,10,11,11,11,12,11,13,11,14,11,15,18,4,10,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,11,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,18,2,56,5,2,2,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,1,21,2,3,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,2,21,2,4,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,3,21,2,5,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,4,21,2,6,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,5,21,2,7,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,6,21,2,8,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,7,21,2,9,1,0,0,38,23,11,1,15,0,11,2,56,6,15,8,12,7,11,3,10,7,15,9,21,11,4,10,7,15,10,21,11,5,10,7,15,11,21,11,6,11,7,15,12,21,2,10,1,0,0,1,4,11,0,16,13,17,55,2,11,1,0,0,1,6,11,0,17,61,6,232,3,0,0,0,0,0,0,26,77,2,12,1,0,0,1,7,11,0,16,0,11,1,56,7,16,1,20,2,13,1,0,0,1,7,11,0,16,0,11,1,56,7,16,2,20,2,14,1,0,0,1,4,11,0,16,0,56,8,2,15,1,0,0,12,8,11,0,15,14,11,1,12,2,46,11,2,56,9,2,16,1,0,0,7,8,11,0,15,0,11,1,12,2,46,11,2,56,3,2,17,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,15,20,2,18,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,16,20,2,19,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,17,20,2,20,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,18,20,2,21,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,19,20,2,22,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,20,16,21,10,1,56,11,4,19,11,4,16,20,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,23,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,22,16,21,10,1,56,11,4,19,11,4,16,22,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,24,1,0,0,1,7,11,0,16,0,11,1,56,7,16,23,20,2,25,1,0,0,1,7,11,0,16,0,11,1,56,7,16,24,20,2,26,1,0,0,1,7,11,0,16,0,11,1,56,7,16,3,20,2,27,1,0,0,1,7,11,0,16,0,11,1,56,7,16,4,20,2,28,1,0,0,1,7,11,0,16,0,11,1,56,7,16,5,20,2,29,1,0,0,1,7,11,0,16,0,11,1,56,7,16,7,20,2,30,1,0,0,1,7,11,0,16,0,11,1,56,7,16,6,20,2,31,1,0,0,1,7,11,0,16,0,11,1,56,7,16,25,20,2,32,1,0,0,1,8,11,0,16,0,11,1,56,7,16,20,16,26,20,2,33,1,0,0,1,8,11,0,16,0,11,1,56,7,16,22,16,26,20,2,34,1,0,0,1,7,11,0,16,0,11,1,56,7,16,27,20,2,35,1,0,0,1,7,11,0,16,0,11,1,56,7,16,28,20,2,36,1,0,0,1,7,11,0,16,0,11,1,56,7,16,29,20,2,37,1,0,0,1,7,11,0,16,0,11,1,56,7,16,30,20,2,38,1,0,0,42,19,11,0,16,0,11,1,56,7,16,8,12,2,10,2,16,9,20,10,2,16,10,20,10,2,16,11,20,11,2,16,12,20,2,39,3,0,0,1,3,11,0,16,13,2,40,3,0,0,43,35,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,41,3,0,0,43,44,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,42,3,0,0,43,35,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,43,3,0,0,43,44,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,44,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,17,14,2,56,16,32,4,16,11,3,15,17,11,2,68,7,5,18,11,3,1,2,45,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,17,14,2,56,17,12,3,4,17,11,4,15,17,11,3,56,18,1,5,19,11,4,1,2,46,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,18,14,2,56,16,32,4,16,11,3,15,18,11,2,68,7,5,18,11,3,1,2,47,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,18,14,2,56,17,12,3,4,17,11,4,15,18,11,3,56,18,1,5,19,11,4,1,2,48,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,19,14,2,56,16,32,4,16,11,3,15,19,11,2,68,7,5,18,11,3,1,2,49,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,19,14,2,56,17,12,3,4,17,11,4,15,19,11,3,56,18,1,5,19,11,4,1,2,50,3,0,0,45,15,11,0,15,14,11,2,56,15,12,4,11,1,17,11,10,4,15,15,21,11,3,11,4,15,16,21,2,51,3,0,0,35,10,11,0,15,0,11,1,56,6,12,3,11,2,11,3,15,24,21,2,52,3,0,0,50,30,10,0,15,0,10,1,56,6,12,7,11,2,10,7,15,30,21,11,3,10,7,15,28,21,11,4,11,7,15,25,21,10,0,16,0,10,1,56,7,16,23,20,12,6,11,0,11,1,11,6,11,5,17,40,2,53,3,0,0,35,14,11,0,15,0,11,1,56,6,12,4,11,2,10,4,15,29,21,11,3,11,4,15,27,21,2,54,1,0,0,12,26,10,0,15,14,10,2,12,3,46,11,3,56,9,32,4,21,11,0,15,14,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,1,17,11,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,18,1,56,19,5,25,11,0,1,11,1,1,2,0,2,2,0,2,1,2,5,2,6,2,7,2,12,2,13,2,14,4,0,4,1,4,2,4,3,0,1,0,3,1,1,1,0,1,2,1,3,1,4,2,15,3,0,2,16,2,4,2,2,2,3,3,1,2,9,2,11,2,8,2,10,0,78,0,79,0,80,0],"lending_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,36,2,36,68,3,104,198,1,4,174,2,8,5,182,2,233,3,7,159,6,228,8,8,131,15,128,1,6,131,16,30,10,161,16,36,12,197,16,230,11,0,58,0,17,0,30,0,42,0,56,0,57,0,59,0,64,0,65,0,80,0,82,1,63,2,23,2,24,2,35,2,77,2,79,3,76,0,6,3,0,0,10,3,0,1,0,12,0,2,4,7,0,3,5,8,0,5,13,8,0,7,9,8,0,8,8,12,0,9,15,12,0,10,3,12,0,11,7,7,1,0,0,12,1,8,0,13,2,12,1,0,1,15,11,2,0,16,14,2,0,17,12,12,0,0,78,0,1,0,0,81,2,1,0,0,19,2,1,0,0,70,0,1,0,0,60,0,1,0,0,18,0,1,0,0,21,0,1,0,2,47,17,14,0,2,48,17,10,0,3,22,4,1,0,4,25,14,15,0,4,26,14,35,0,4,27,14,38,0,4,28,14,23,0,4,44,1,16,0,4,45,1,16,0,4,46,1,16,0,4,52,1,16,0,4,53,1,16,0,4,54,1,16,0,5,43,5,6,0,6,18,39,1,0,6,21,39,1,0,6,36,13,1,0,6,37,36,1,0,6,38,13,1,0,6,39,13,1,0,6,40,13,30,0,8,41,24,25,0,8,50,9,10,0,8,51,9,30,0,9,49,11,12,0,10,66,7,8,0,10,67,21,22,0,10,68,21,22,0,10,71,31,12,0,11,29,29,19,1,0,11,55,27,28,1,0,14,34,19,1,1,3,38,18,37,26,36,26,38,32,10,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,10,2,6,8,11,7,8,14,0,11,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,11,12,1,8,13,10,2,6,8,11,7,8,14,17,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,10,2,2,13,3,3,8,3,8,3,13,8,3,1,6,8,4,1,7,8,5,1,6,8,2,8,7,8,15,7,8,9,6,8,2,10,2,7,8,7,7,8,8,6,8,11,7,8,14,4,8,3,8,3,15,10,2,2,7,8,7,8,3,1,13,2,6,8,8,8,3,1,3,7,6,8,7,7,8,5,7,8,6,6,8,11,3,13,15,1,10,2,4,13,3,8,3,2,1,2,1,6,8,3,1,8,0,1,9,0,27,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,6,7,8,15,7,8,9,6,8,2,10,2,6,8,11,7,8,14,2,8,3,10,2,6,13,3,3,8,3,8,3,2,3,7,8,7,13,13,1,11,10,1,8,3,1,8,3,1,6,11,10,1,9,0,1,1,1,11,10,1,9,0,1,15,11,7,8,15,7,8,9,6,8,2,7,8,7,8,3,8,3,13,3,15,11,12,1,8,13,6,8,11,1,8,1,26,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,26,7,8,5,7,8,6,6,8,11,3,3,13,13,8,3,7,8,5,7,8,6,6,8,11,3,13,15,10,2,2,15,13,8,3,8,3,3,3,3,13,13,8,3,5,13,3,8,3,3,2,8,6,8,7,7,8,5,7,8,6,6,8,11,3,3,13,13,14,8,3,7,8,5,7,8,6,6,8,11,3,13,10,2,2,6,13,10,13,3,3,3,8,3,2,10,13,2,6,6,8,7,7,8,5,7,8,6,6,8,11,3,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,76,101,110,100,105,110,103,67,111,114,101,69,118,101,110,116,6,79,112,116,105,111,110,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,6,98,111,114,114,111,119,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,112,111,111,108,95,105,100,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,9,108,105,113,117,105,100,97,116,101,17,108,105,113,117,105,100,97,116,101,95,117,115,101,114,95,105,100,5,110,111,110,99,101,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,5,114,101,112,97,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,14,115,101,110,100,101,114,95,117,115,101,114,95,105,100,8,115,101,113,117,101,110,99,101,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,18,115,111,117,114,99,101,95,99,104,97,105,110,95,110,111,110,99,101,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,9,62,3,72,3,74,13,32,13,31,13,69,10,2,16,15,61,3,20,2,1,2,5,73,3,74,13,75,3,33,8,3,20,2,0,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,26,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,18,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,1,1,4,0,20,168,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,26,12,37,11,26,17,13,12,27,12,35,12,34,12,24,12,33,12,36,10,27,17,19,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,24,77,12,25,10,1,11,34,17,29,12,28,11,2,11,37,12,16,46,11,16,17,31,12,29,14,35,17,8,12,30,10,1,10,28,11,30,17,28,12,31,14,31,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,31,56,2,12,32,10,1,10,6,11,5,10,9,10,29,10,28,11,25,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,27,12,23,10,1,10,32,17,30,10,23,38,4,113,5,125,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,32,10,35,10,36,10,33,10,23,11,7,11,9,17,35,12,11,11,32,12,12,10,36,12,13,10,33,12,14,10,27,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,33,11,29,11,36,14,35,17,8,11,28,14,35,17,7,11,23,6,0,0,0,0,0,0,0,0,11,27,18,0,56,0,2,2,1,4,0,33,167,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,25,12,36,11,25,17,13,12,26,12,34,12,33,12,23,12,32,12,35,10,26,17,15,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,23,77,12,24,10,1,11,33,17,29,12,27,11,2,11,36,12,16,46,11,16,17,31,12,28,14,34,17,8,12,29,10,1,10,27,11,29,17,28,12,30,14,30,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,30,56,2,12,31,10,1,10,6,11,5,10,9,10,28,10,27,10,24,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,23,10,1,10,31,17,30,10,24,38,4,112,5,124,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,31,10,34,10,35,10,32,10,24,11,7,11,9,17,35,12,11,11,31,12,12,10,35,12,13,10,32,12,14,10,26,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,32,11,28,11,35,14,34,17,8,11,27,14,34,17,7,11,24,6,0,0,0,0,0,0,0,0,11,26,18,0,56,0,2,3,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,25,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,17,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,4,1,4,0,34,97,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,24,12,26,12,29,12,28,11,24,17,11,12,25,12,30,12,35,12,32,12,33,11,2,10,29,12,17,46,11,17,17,31,12,31,10,1,11,28,17,29,12,27,10,1,11,35,17,29,12,34,10,1,10,6,10,5,10,8,10,31,10,27,10,26,12,23,12,22,12,21,12,20,12,19,12,18,46,11,18,11,19,11,20,11,21,11,22,11,23,17,26,11,1,11,6,11,5,11,8,10,31,10,30,10,34,11,27,12,16,12,15,12,14,12,13,12,12,12,11,12,10,46,11,10,11,11,11,12,11,13,11,14,11,15,11,16,17,24,11,32,11,31,11,33,14,29,17,8,11,34,14,29,17,7,11,26,11,30,11,25,18,0,56,0,2,5,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,14,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,21,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,6,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,16,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,22,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,0],"lending_logic":[161,28,235,11,6,0,0,0,11,1,0,27,2,27,24,3,51,189,4,4,240,4,4,5,244,4,199,3,7,187,8,241,18,8,172,27,96,6,140,28,144,2,10,156,30,15,12,171,30,253,36,15,168,67,4,0,93,0,48,0,90,0,91,0,104,0,106,0,108,0,111,0,117,1,135,1,2,35,2,40,2,95,0,2,3,0,1,1,0,0,3,5,8,0,4,4,8,0,5,3,12,0,10,0,8,0,0,42,0,1,0,0,44,2,1,0,0,45,2,3,0,0,41,2,1,0,0,43,2,1,0,0,11,4,1,0,0,31,4,1,0,0,34,5,1,0,0,103,6,7,0,0,102,8,7,0,0,83,9,7,0,0,85,10,7,0,0,88,11,7,0,0,84,11,7,0,0,89,11,7,0,0,87,12,7,0,0,33,13,1,0,0,81,12,7,0,0,82,10,7,0,0,128,1,10,3,0,0,126,14,3,0,0,125,11,3,0,0,132,1,14,3,0,0,131,1,11,3,0,0,127,10,3,0,0,129,1,10,3,0,0,133,1,10,3,0,0,134,1,10,3,0,0,28,15,3,0,0,19,15,3,0,0,24,10,3,0,0,25,16,3,0,0,27,17,18,0,0,18,19,20,0,0,119,9,3,0,0,118,9,3,0,0,37,12,1,0,0,99,21,1,0,0,15,21,1,0,0,97,21,1,0,0,13,21,1,0,0,6,8,1,0,0,113,8,1,0,0,120,22,1,0,0,123,23,1,0,0,121,24,1,0,2,51,1,27,0,2,55,1,27,0,2,56,1,27,0,2,61,1,27,0,2,65,1,27,0,2,69,1,27,0,2,80,1,27,0,3,7,11,1,0,3,8,11,1,0,3,9,11,1,0,3,14,53,1,0,3,16,53,1,0,3,30,9,7,0,3,39,30,1,0,3,46,9,7,0,3,47,12,7,0,3,49,61,31,0,3,52,9,3,0,3,53,9,3,0,3,54,9,3,0,3,57,9,3,0,3,58,9,3,0,3,59,9,3,0,3,60,9,3,0,3,62,9,3,0,3,63,9,3,0,3,64,9,3,0,3,66,9,3,0,3,67,9,3,0,3,68,9,26,0,3,70,57,3,0,3,72,9,3,0,3,73,12,3,0,3,74,12,37,0,3,75,12,3,0,3,76,12,37,0,3,77,12,37,0,3,78,11,3,0,3,79,11,3,0,3,86,9,7,0,3,98,53,1,0,3,100,53,1,0,3,114,11,1,0,3,115,11,1,0,3,116,11,1,0,3,121,63,1,0,3,122,6,1,0,3,123,60,1,0,3,124,58,1,0,4,32,32,1,0,4,71,47,48,0,5,50,62,3,0,6,20,20,3,0,6,21,6,3,0,6,22,33,3,0,6,23,33,3,0,6,26,63,3,0,7,96,18,3,0,7,109,1,3,0,7,110,18,3,0,7,112,18,3,0,8,12,18,3,0,8,17,18,3,0,8,101,18,3,0,9,36,39,7,1,0,11,38,29,1,1,3,12,107,49,26,0,111,28,110,31,8,6,8,4,7,8,2,7,8,3,6,8,5,3,3,13,13,0,7,6,8,4,7,8,2,7,8,3,6,8,5,3,13,15,1,15,6,6,8,4,7,8,2,7,8,3,6,8,5,3,13,7,6,8,1,6,8,4,7,8,2,6,8,5,13,3,15,3,7,8,2,13,15,1,1,3,7,8,2,3,15,2,7,8,2,13,3,7,8,2,7,8,3,3,3,7,8,2,3,13,2,7,8,2,3,4,7,8,3,7,8,2,3,6,8,5,4,7,8,2,7,8,3,3,13,3,7,8,3,13,15,4,7,8,2,7,8,3,3,3,6,7,8,2,7,8,3,3,3,13,13,2,15,15,7,7,8,3,13,15,13,15,15,15,4,15,15,15,15,4,7,8,2,3,13,15,4,7,8,2,7,8,3,6,8,5,3,3,7,8,2,6,8,5,13,4,6,8,4,7,8,2,13,15,12,1,15,15,15,15,15,15,15,15,3,15,15,1,3,1,2,1,8,0,1,9,0,3,7,8,2,6,8,5,3,1,13,3,7,8,3,10,13,6,8,5,3,15,15,15,5,15,15,15,15,3,3,1,15,15,5,1,15,6,13,15,10,13,1,10,13,2,1,10,13,2,6,10,9,0,6,9,0,3,1,13,10,13,2,10,13,10,13,7,6,13,15,15,10,13,3,3,15,7,15,3,3,6,13,15,10,13,15,6,6,13,15,10,13,3,3,15,6,3,3,6,13,15,10,13,15,2,2,15,2,7,8,3,13,3,15,2,3,2,3,2,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,6,15,15,15,15,15,15,6,15,3,3,6,13,10,13,3,4,7,8,2,13,3,15,3,6,13,15,10,13,5,15,6,13,15,15,10,13,7,15,15,15,15,15,15,15,1,6,8,5,4,7,8,2,6,8,5,3,15,9,15,15,15,15,15,15,15,15,15,6,7,8,2,13,15,15,15,15,1,7,8,2,3,6,8,4,13,13,4,7,8,2,13,15,15,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,23,76,101,110,100,105,110,103,67,111,114,101,69,120,101,99,117,116,101,69,118,101,110,116,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,16,97,100,100,95,105,115,111,108,97,116,101,95,100,101,98,116,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,6,97,109,111,117,110,116,13,97,115,95,99,111,108,108,97,116,101,114,97,108,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,100,116,111,107,101,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,111,116,111,107,101,110,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,115,99,97,108,101,100,28,99,97,108,99,117,108,97,116,101,95,97,99,116,117,97,108,95,108,105,113,117,105,100,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,35,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,98,97,115,101,95,100,105,115,99,111,117,110,116,30,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,100,105,115,99,111,117,110,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,25,99,97,108,99,117,108,97,116,101,95,109,97,120,95,108,105,113,117,105,100,97,116,105,111,110,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,9,99,97,108,108,95,116,121,112,101,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,22,99,104,101,99,107,95,117,115,101,114,95,102,114,101,115,104,95,112,114,105,99,101,19,99,108,97,105,109,95,102,114,111,109,95,116,114,101,97,115,117,114,121,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,13,99,111,118,101,114,95,100,101,102,105,99,105,116,4,101,109,105,116,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,13,103,101,116,95,116,105,109,101,115,116,97,109,112,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,14,104,97,115,95,99,111,108,108,97,116,101,114,97,108,11,104,97,115,95,100,101,102,105,99,105,116,19,105,115,95,98,111,114,114,111,119,97,98,108,101,95,97,115,115,101,116,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,17,105,115,95,105,115,111,108,97,116,105,111,110,95,109,111,100,101,15,105,115,95,108,105,113,117,105,100,95,97,115,115,101,116,7,105,115,95,108,111,97,110,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,109,97,116,104,3,109,105,110,11,109,105,110,116,95,100,116,111,107,101,110,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,111,116,111,107,101,110,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,24,110,111,116,95,114,101,97,99,104,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,24,110,111,116,95,114,101,97,99,104,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,6,111,114,97,99,108,101,7,112,111,111,108,95,105,100,12,112,111,111,108,95,109,97,110,97,103,101,114,3,112,111,119,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,19,114,101,100,117,99,101,95,105,115,111,108,97,116,101,95,100,101,98,116,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,19,116,111,116,97,108,95,100,116,111,107,101,110,95,115,117,112,112,108,121,19,116,111,116,97,108,95,111,116,111,107,101,110,95,115,117,112,112,108,121,24,117,112,100,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,7,117,115,101,114,95,105,100,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,27,117,115,101,114,95,116,111,116,97,108,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,21,117,115,101,114,95,116,111,116,97,108,95,108,111,97,110,95,118,97,108,117,101,6,118,101,99,116,111,114,11,118,105,111,108,97,116,111,114,95,105,100,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,15,32,0,0,0,200,165,25,144,185,165,111,165,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,34,76,160,196,199,203,249,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,0,2,5,130,1,3,10,15,105,13,136,1,3,29,2,0,3,0,0,25,233,1,10,1,10,5,10,6,17,13,4,6,5,16,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,5,10,7,17,14,4,22,5,32,11,1,1,11,0,1,11,2,1,11,3,1,7,8,39,10,1,10,4,10,7,17,13,4,38,5,48,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,3,10,7,17,44,10,1,10,3,10,6,17,44,10,1,10,2,10,3,10,4,17,43,10,2,10,1,10,5,10,3,17,16,10,1,10,2,10,5,17,11,32,4,73,5,83,11,1,1,11,0,1,11,2,1,11,3,1,7,6,39,10,1,10,2,10,4,10,5,10,6,10,7,17,32,12,15,12,14,10,1,10,6,17,77,12,18,10,1,10,4,10,7,17,21,12,16,10,2,10,6,11,14,10,7,11,15,11,16,11,18,17,33,12,19,12,11,12,10,12,9,10,1,10,6,17,75,12,17,10,1,10,5,10,7,10,10,17,40,10,1,10,5,10,6,10,9,17,38,10,1,10,4,10,7,11,10,17,38,10,1,11,17,10,6,11,19,17,37,10,1,10,2,10,5,17,18,4,145,1,10,1,10,5,17,36,10,1,10,4,10,6,17,14,4,184,1,10,1,10,4,10,6,17,23,12,13,10,13,10,11,17,103,12,12,10,1,10,4,10,6,11,12,17,40,10,11,10,13,36,4,183,1,10,1,10,4,10,6,17,90,10,1,10,4,10,6,11,11,11,13,23,17,37,10,1,10,4,10,6,17,54,5,210,1,10,1,10,4,10,6,11,11,17,37,10,1,10,4,10,6,17,13,32,4,202,1,10,1,10,4,10,6,17,12,32,12,8,5,204,1,9,12,8,11,8,4,210,1,10,1,10,4,10,6,17,54,10,0,10,1,10,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,0,10,1,11,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,5,17,43,11,4,11,9,11,6,11,5,17,49,18,0,56,0,2,1,3,0,0,7,128,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,4,10,5,17,14,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,18,39,10,1,10,5,10,6,17,8,4,42,5,52,11,1,1,11,0,1,11,2,1,11,3,1,7,19,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,10,6,17,37,10,1,10,4,10,5,17,13,32,4,74,10,1,10,4,10,5,17,12,32,12,7,5,76,9,12,7,11,7,4,110,10,1,10,4,17,15,4,87,10,1,10,4,10,5,17,54,5,110,10,1,10,4,17,17,32,4,97,10,1,10,4,10,5,17,53,5,110,10,1,10,5,17,85,4,106,10,1,10,4,10,5,17,54,5,110,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,51,18,0,56,0,2,2,3,0,0,18,95,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,21,12,8,11,6,10,8,17,103,12,7,10,1,10,4,10,5,10,7,17,38,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,48,5,58,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,10,7,11,8,33,4,76,10,1,10,4,10,5,17,13,4,72,10,1,10,4,10,5,17,88,5,76,10,1,10,4,10,5,17,89,11,0,10,1,10,5,10,7,17,45,11,1,11,2,11,3,10,4,17,43,11,4,10,7,11,5,6,0,0,0,0,0,0,0,0,17,52,18,0,56,0,11,7,2,3,3,0,0,1,170,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,13,32,4,30,5,40,11,1,1,11,0,1,11,2,1,11,3,1,7,3,39,10,1,10,4,10,5,17,12,32,4,47,5,57,11,1,1,11,0,1,11,2,1,11,3,1,7,4,39,10,1,10,5,17,10,4,62,5,72,11,1,1,11,0,1,11,2,1,11,3,1,7,13,39,10,1,10,4,17,15,4,111,10,1,10,5,17,58,4,81,5,91,11,1,1,11,0,1,11,2,1,11,3,1,7,12,39,10,1,10,4,10,6,17,9,4,97,5,107,11,1,1,11,0,1,11,2,1,11,3,1,7,11,39,10,1,10,4,10,6,17,41,10,1,10,4,10,5,17,14,32,4,121,10,1,10,4,10,5,17,55,10,1,10,4,10,5,10,6,17,39,10,2,10,1,10,4,10,3,17,16,10,2,10,5,64,31,1,0,0,0,0,0,0,0,10,3,17,95,10,1,10,2,10,4,17,11,4,142,1,5,152,1,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,10,6,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,47,18,0,56,0,2,4,3,0,0,33,88,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,23,12,7,10,6,10,7,17,103,12,9,10,1,10,4,10,5,10,9,17,40,10,1,10,4,17,15,4,45,10,1,10,4,10,9,17,42,10,6,10,7,38,4,70,10,1,10,4,10,5,17,90,11,6,11,7,23,12,8,10,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,10,1,10,4,10,5,11,8,17,37,10,1,10,4,10,5,17,54,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,9,11,5,6,0,0,0,0,0,0,0,0,17,50,18,0,56,0,2,5,3,0,0,1,82,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,12,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,14,39,10,1,10,4,17,15,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,15,39,10,1,10,4,17,17,4,56,10,1,10,5,17,85,32,4,46,5,56,11,1,1,11,0,1,11,2,1,11,3,1,7,17,39,10,1,10,4,10,5,17,89,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,46,18,0,56,0,2,6,3,0,0,1,67,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,13,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,4,10,5,17,88,10,1,10,4,10,5,17,54,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,39,5,49,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,48,18,0,56,0,2,7,1,0,0,34,49,10,2,11,3,10,4,17,44,10,2,10,4,17,75,12,11,10,2,10,11,10,4,17,21,12,10,10,2,10,11,10,4,17,23,12,9,10,10,10,9,36,4,27,11,10,11,9,23,12,7,5,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,11,6,17,103,12,8,10,2,11,11,10,4,10,8,17,38,10,2,11,5,10,4,11,8,17,37,11,1,11,2,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,2,8,1,0,0,35,23,10,0,10,1,17,74,12,4,11,0,11,1,17,34,12,5,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,15,8,12,3,5,21,11,5,11,2,22,11,4,35,12,3,11,3,2,9,1,0,0,36,33,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,5,10,0,10,5,20,17,73,12,4,11,0,11,5,20,17,68,12,6,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,8,12,3,5,31,11,6,11,2,22,11,4,35,12,3,11,3,2,10,1,0,0,1,6,11,0,11,1,17,63,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,2,11,1,0,0,1,7,11,0,11,1,11,2,17,19,17,104,36,2,12,1,0,0,38,19,10,0,10,1,17,61,4,13,11,0,11,1,17,81,12,4,14,4,14,2,56,1,12,3,5,17,11,0,1,9,12,3,11,3,2,13,1,0,0,37,8,11,0,11,1,17,79,12,3,14,3,14,2,56,1,2,14,1,0,0,37,8,11,0,11,1,17,82,12,3,14,3,14,2,56,1,2,15,1,0,0,40,25,10,0,11,1,17,79,12,4,14,4,65,31,6,1,0,0,0,0,0,0,0,33,4,19,14,4,6,0,0,0,0,0,0,0,0,66,31,20,12,3,11,0,11,3,17,85,12,2,5,23,11,0,1,9,12,2,11,2,2,16,1,0,0,41,17,10,1,10,2,17,79,12,4,11,1,11,2,17,82,12,5,10,0,11,4,10,3,17,95,11,0,11,5,11,3,17,95,2,17,1,0,0,37,9,11,0,11,1,17,79,12,2,14,2,65,31,6,0,0,0,0,0,0,0,0,36,2,18,1,0,0,35,23,10,0,10,1,10,2,17,26,12,4,11,0,11,1,11,2,17,27,12,5,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,12,3,5,21,9,12,3,11,3,2,19,1,0,0,33,23,10,0,10,1,10,2,17,24,12,4,11,0,11,1,11,2,17,25,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,19,11,4,11,5,17,105,12,3,5,21,7,0,12,3,11,3,2,20,1,0,0,3,10,11,0,11,2,10,3,17,21,12,4,11,1,11,3,11,4,17,28,2,21,1,0,0,18,13,10,0,11,1,10,2,17,84,12,4,11,0,11,2,17,70,12,3,11,4,11,3,17,107,2,22,1,0,0,3,10,11,0,11,2,10,3,17,23,12,4,11,1,11,3,11,4,17,28,2,23,1,0,0,18,13,10,0,11,1,10,2,17,83,12,4,11,0,11,2,17,64,12,3,11,4,11,3,17,107,2,24,1,0,0,42,49,10,0,10,2,17,79,12,6,14,6,65,31,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,43,5,16,14,6,10,7,66,31,12,3,10,0,10,3,20,17,66,12,4,10,0,10,1,10,2,11,3,20,17,20,12,5,11,9,11,5,11,4,17,106,22,12,9,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,11,11,0,1,11,1,1,11,9,2,25,1,0,0,43,49,10,0,10,2,17,82,12,8,14,8,65,31,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,43,5,16,14,8,10,4,66,31,12,6,10,0,10,6,20,17,63,12,3,10,0,10,1,10,2,11,6,20,17,22,12,7,11,9,11,7,11,3,17,106,22,12,9,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,11,11,0,1,11,1,1,11,9,2,26,1,0,0,44,42,10,0,10,2,17,79,12,5,14,5,65,31,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,36,5,16,14,5,10,6,66,31,12,3,10,0,10,1,10,2,11,3,20,17,20,12,4,11,8,11,4,22,12,8,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,11,11,0,1,11,1,1,11,8,2,27,1,0,0,45,42,10,0,10,2,17,82,12,7,14,7,65,31,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,36,5,16,14,7,10,3,66,31,12,5,10,0,10,1,10,2,11,5,20,17,22,12,6,11,8,11,6,22,12,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,11,11,0,1,11,1,1,11,8,2,28,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,11,4,24,6,10,0,0,0,0,0,0,0,11,3,17,112,77,26,2,29,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,6,10,0,0,0,0,0,0,0,11,3,17,112,77,24,11,4,26,2,30,1,0,0,18,16,10,0,10,1,10,2,17,24,12,3,11,0,11,1,11,2,17,25,12,4,17,104,11,3,11,4,17,105,23,2,31,1,0,0,20,52,10,0,10,3,17,61,4,5,5,11,11,0,1,11,1,1,7,16,39,10,0,10,2,17,61,4,16,5,22,11,0,1,11,1,1,7,16,39,10,0,10,1,10,3,17,30,12,5,10,0,11,2,17,78,12,4,11,0,11,1,11,3,17,25,12,7,11,4,74,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,24,17,105,17,104,17,103,17,104,22,12,6,11,5,11,6,17,106,7,1,17,103,2,32,1,0,0,50,89,10,0,10,1,11,2,10,3,17,31,12,12,10,0,10,1,10,3,17,24,12,10,10,0,10,1,10,3,17,25,12,11,10,0,10,5,17,63,12,6,10,0,10,4,17,66,12,7,11,11,7,2,17,106,11,10,23,12,19,7,2,17,104,10,12,23,17,106,11,6,17,106,11,7,23,12,18,11,19,11,18,17,105,12,14,10,0,10,1,10,3,10,4,17,20,10,14,17,105,12,8,10,14,17,104,11,12,23,17,106,12,16,11,0,10,1,11,3,10,5,17,22,10,16,17,105,12,9,11,8,11,9,17,103,17,104,17,103,12,17,10,1,11,4,11,14,10,17,17,106,17,29,12,13,11,1,11,5,11,16,11,17,17,106,17,29,12,15,11,13,11,15,2,33,1,0,0,51,45,10,5,10,4,38,4,9,11,4,12,8,11,2,12,7,5,17,11,5,12,8,11,2,10,8,11,4,17,105,17,106,12,7,10,0,10,1,10,7,17,28,12,9,10,0,11,3,10,8,17,28,12,11,11,0,11,1,11,9,11,11,23,17,29,11,6,17,106,12,12,10,7,10,12,23,12,10,11,7,11,8,11,10,11,12,2,34,1,0,0,18,12,10,0,10,1,17,72,12,3,11,0,11,1,17,70,12,2,11,3,11,2,17,106,2,35,1,0,0,18,12,10,0,10,1,17,67,12,3,11,0,11,1,17,64,12,2,11,3,11,2,17,106,2,36,0,0,0,52,49,10,0,10,1,17,82,12,6,14,6,65,31,12,4,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,46,5,14,14,6,10,3,66,31,12,5,10,0,10,5,20,17,75,12,7,10,0,10,1,10,5,20,17,23,12,2,10,0,10,1,10,5,20,10,2,17,40,10,0,11,7,11,5,20,11,2,17,39,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,9,11,0,1,2,37,0,0,0,3,12,11,3,10,0,10,2,17,70,17,109,12,4,11,0,11,2,11,1,11,4,17,87,2,38,0,0,0,3,12,11,3,10,0,10,2,17,70,17,108,12,4,11,0,11,2,11,1,11,4,17,57,2,39,0,0,0,3,12,11,3,10,0,10,2,17,64,17,109,12,4,11,0,11,2,11,1,11,4,17,86,2,40,0,0,0,3,12,11,3,10,0,10,2,17,64,17,108,12,4,11,0,11,2,11,1,11,4,17,56,2,41,0,0,0,54,21,10,0,11,1,17,79,12,5,14,5,6,0,0,0,0,0,0,0,0,66,31,12,3,10,0,10,3,20,17,68,11,2,22,12,4,11,0,11,3,20,11,4,17,92,2,42,0,0,0,55,32,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,4,10,0,10,4,20,17,68,12,5,10,5,10,2,38,4,22,11,5,11,2,23,12,3,5,24,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,12,6,11,0,11,4,20,11,6,17,92,2,43,0,0,0,56,58,10,0,10,3,17,61,4,51,10,2,17,76,12,5,10,0,10,3,17,80,12,9,10,0,10,1,10,3,17,24,12,6,10,0,11,1,10,3,17,25,12,7,10,6,10,7,36,4,45,11,6,11,7,23,12,8,10,0,10,3,17,78,12,4,11,5,11,9,11,4,11,8,17,98,12,10,11,0,11,2,11,3,11,10,17,94,5,50,11,0,11,2,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,94,5,57,11,0,1,11,1,1,11,2,1,2,44,0,0,0,59,59,11,1,17,76,12,5,10,0,10,2,17,69,12,7,10,0,10,2,17,67,12,6,10,0,10,2,17,64,12,3,10,0,10,2,17,70,12,4,10,0,10,2,17,77,12,11,10,5,10,7,10,0,10,2,17,65,17,100,10,3,17,106,12,9,10,5,11,7,10,0,10,2,17,71,17,101,11,4,17,106,12,10,11,6,10,9,11,3,23,17,106,11,11,17,106,10,10,17,109,12,8,11,0,11,2,11,9,11,10,11,5,11,8,17,93,2,45,0,0,0,20,36,11,0,10,2,10,1,17,62,17,97,12,5,10,5,10,3,38,4,11,5,15,11,1,1,7,10,39,11,5,11,3,23,12,6,10,1,10,2,10,6,17,99,12,4,10,1,10,2,10,4,11,6,17,102,12,7,11,1,11,2,11,4,11,7,17,91,2,0,92,0,94,0],"lending_portal":[161,28,235,11,6,0,0,0,11,1,0,44,2,44,90,3,134,1,165,2,4,171,3,36,5,207,3,230,5,7,181,9,176,10,8,229,19,128,1,6,229,20,54,10,155,21,59,12,214,21,204,16,13,162,38,4,0,72,0,23,0,38,0,39,0,52,0,69,0,70,0,71,0,75,0,83,0,84,0,103,0,108,1,82,2,30,2,31,2,44,2,81,2,99,2,101,2,102,3,98,0,8,8,0,0,14,3,0,0,9,3,0,0,7,3,0,1,0,12,0,2,4,7,0,3,11,12,1,0,1,4,5,0,0,4,6,8,0,6,17,8,0,9,13,8,0,10,12,12,0,11,20,12,0,12,3,12,0,13,10,7,1,0,0,14,1,8,0,15,2,12,1,0,1,17,19,4,0,18,15,2,0,20,18,2,0,21,16,12,0,0,66,0,1,0,0,60,2,3,0,0,94,4,1,0,0,24,5,1,0,0,28,5,1,0,0,100,6,1,1,0,0,106,7,1,1,0,0,107,8,1,0,0,25,7,1,1,0,0,26,8,1,0,0,90,6,1,1,0,0,73,9,1,1,0,2,32,12,17,0,2,33,1,17,1,0,2,34,45,17,0,2,55,35,28,0,2,59,1,19,0,3,35,27,28,1,0,3,80,25,3,1,0,3,105,43,1,1,0,4,29,16,1,0,5,54,1,26,0,5,58,1,26,0,5,62,1,26,0,5,63,1,26,0,5,64,1,26,0,6,53,49,50,0,7,24,20,1,0,7,28,20,1,0,7,45,34,1,0,7,46,60,1,0,7,47,34,1,0,7,48,34,1,0,7,49,34,42,0,8,74,22,23,1,0,10,21,29,30,0,10,51,38,39,0,10,57,33,19,0,10,61,33,42,0,10,89,29,30,0,11,56,18,3,0,11,67,18,31,0,11,87,32,1,0,12,91,51,3,0,13,36,41,14,1,0,13,68,40,31,1,0,15,37,23,1,1,0,15,97,48,23,1,0,15,104,24,3,1,0,16,43,14,1,1,3,17,77,0,10,0,19,85,53,1,1,12,19,95,14,1,1,8,20,92,11,12,0,21,76,47,3,0,52,13,13,14,34,14,48,14,18,14,17,14,49,36,45,17,44,17,19,14,34,46,47,46,48,46,51,52,49,54,49,55,5,14,46,14,1,7,8,19,0,1,7,8,0,1,3,3,6,8,7,7,8,0,5,8,6,8,8,7,8,9,7,8,10,6,8,15,7,8,11,7,8,12,10,13,7,8,19,11,6,8,8,7,8,9,7,8,10,6,8,15,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,16,1,9,0,3,7,8,19,10,6,8,8,7,8,9,7,8,10,6,8,15,7,8,0,7,8,11,7,8,12,7,11,6,1,9,0,3,7,8,19,16,6,8,8,7,8,9,7,8,10,6,8,15,7,8,13,7,8,0,7,8,20,7,8,11,7,8,12,10,2,10,2,13,3,10,11,16,1,8,18,3,7,8,19,14,6,8,8,7,8,9,7,8,10,6,8,15,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,16,1,9,0,3,13,10,2,3,7,8,19,1,8,17,1,6,8,19,1,5,1,8,0,1,9,0,11,8,5,7,8,9,7,8,10,6,8,15,3,13,6,13,3,3,3,8,5,1,6,8,8,1,8,5,2,6,8,12,8,5,1,13,6,6,8,11,7,8,9,7,8,10,6,8,15,3,13,17,6,8,15,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,3,11,16,1,9,0,13,3,3,8,5,8,5,3,10,11,16,1,9,0,3,7,8,19,1,11,16,1,9,0,1,6,11,16,1,9,0,2,6,11,6,1,9,0,3,1,2,5,7,11,6,1,9,0,11,16,1,9,0,13,10,2,7,8,19,1,10,2,4,7,8,11,8,5,13,15,2,15,15,1,1,2,7,8,12,8,5,2,7,8,11,8,5,7,6,8,11,7,8,9,7,8,10,6,8,15,3,13,15,1,6,8,5,1,8,3,16,8,5,7,8,9,7,8,10,6,8,15,3,13,15,15,13,3,13,11,14,1,8,5,8,5,8,5,8,5,15,3,7,8,11,13,13,1,11,14,1,8,5,1,6,11,14,1,9,0,1,11,14,1,9,0,1,15,5,7,11,6,1,9,0,8,5,3,8,5,7,8,19,21,8,5,7,8,9,7,8,10,6,8,15,3,13,15,15,11,16,1,8,18,13,3,11,14,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,16,1,8,18,3,2,13,10,2,1,8,18,1,6,8,20,3,7,11,16,1,9,0,3,7,8,19,1,7,8,9,1,6,8,4,11,7,8,20,7,8,13,6,8,4,7,8,11,8,5,8,5,13,3,15,11,16,1,8,18,6,8,15,1,11,16,1,8,18,2,9,0,5,1,8,1,1,8,2,15,8,5,7,8,9,7,8,10,6,8,15,3,13,15,13,3,13,11,14,1,8,5,8,5,8,5,8,5,15,20,8,5,7,8,9,7,8,10,6,8,15,3,13,15,11,16,1,8,18,13,3,11,14,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,16,1,8,18,3,17,6,8,15,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,13,3,3,8,5,3,11,16,1,9,0,8,5,16,13,8,5,7,8,9,7,8,10,6,8,15,3,3,13,13,8,5,3,8,5,3,5,13,8,5,8,6,8,11,7,8,9,7,8,10,6,8,15,3,3,13,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,17,76,101,110,100,105,110,103,76,111,99,97,108,69,118,101,110,116,13,76,101,110,100,105,110,103,80,111,114,116,97,108,18,76,101,110,100,105,110,103,80,111,114,116,97,108,69,118,101,110,116,6,79,112,116,105,111,110,4,80,111,111,108,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,13,97,100,100,95,108,105,113,117,105,100,105,116,121,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,12,98,111,114,114,111,119,95,108,111,99,97,108,13,98,111,114,114,111,119,95,114,101,109,111,116,101,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,7,100,101,112,111,115,105,116,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,17,100,111,108,97,95,112,111,111,108,95,97,100,100,114,101,115,115,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,10,102,101,101,95,97,109,111,117,110,116,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,2,105,100,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,9,108,105,113,117,105,100,97,116,101,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,11,109,101,115,115,97,103,101,95,102,101,101,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,7,114,101,108,97,121,101,114,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,5,114,101,112,97,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,6,115,101,110,100,101,114,8,115,101,113,117,101,110,99,101,11,115,101,116,95,114,101,108,97,121,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,112,108,105,116,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,14,119,105,116,104,100,114,97,119,95,108,111,99,97,108,15,119,105,116,104,100,114,97,119,95,114,101,109,111,116,101,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,13,2,1,0,0,2,3,65,8,17,88,5,78,3,1,2,5,93,3,79,3,42,8,5,50,3,27,2,2,2,8,79,3,92,5,40,10,2,96,13,41,13,86,10,2,22,3,27,2,3,2,5,79,3,92,5,40,10,2,22,3,27,2,0,0,0,0,1,9,10,0,17,50,11,0,46,17,53,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,0,0,1,5,11,2,11,1,15,1,21,2,3,1,4,0,15,61,11,0,17,20,11,7,46,17,53,17,12,12,18,11,5,11,18,12,8,46,11,8,17,40,12,15,14,6,65,19,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,19,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,27,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,4,1,4,0,15,61,11,0,17,20,11,7,46,17,53,17,12,12,18,11,5,11,18,12,8,46,11,8,17,40,12,15,14,6,65,19,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,19,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,28,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,5,1,4,0,21,117,11,0,17,20,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,53,17,12,12,27,56,1,12,26,11,8,11,9,10,10,56,2,12,22,10,7,14,22,56,3,12,15,46,11,15,56,4,12,21,11,4,17,1,12,25,11,7,11,22,7,5,64,26,0,0,0,0,0,0,0,0,10,10,56,5,1,10,6,10,26,7,5,10,21,77,17,35,1,12,20,10,5,10,27,12,16,46,11,16,17,41,32,4,74,10,5,10,27,17,42,10,6,10,26,17,37,12,23,11,5,11,27,12,17,46,11,17,17,40,12,24,11,6,11,1,11,2,11,3,11,24,11,23,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,32,11,25,11,10,46,17,53,14,26,17,15,11,21,17,24,18,3,56,6,2,6,1,4,0,37,117,11,0,17,20,17,16,12,20,10,9,46,17,53,17,12,12,24,56,1,12,23,10,5,10,23,17,37,12,18,11,6,10,24,12,10,46,11,10,17,40,12,19,10,5,10,18,11,20,17,36,12,21,14,21,56,7,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,21,56,8,12,22,10,5,11,1,11,2,11,3,11,19,11,18,11,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,33,12,17,10,5,10,22,17,38,10,17,38,4,80,5,90,11,5,1,11,7,1,11,4,1,11,9,1,7,1,39,11,5,11,22,7,5,10,17,17,39,1,12,25,11,7,11,24,11,25,52,10,23,10,9,56,9,11,4,17,1,11,9,46,17,53,14,23,17,15,11,17,52,17,25,18,3,56,6,2,7,1,4,0,44,184,1,11,0,17,20,10,11,10,10,17,14,12,31,10,11,11,9,17,14,12,30,10,15,46,17,53,17,12,12,34,10,7,10,30,17,37,12,25,11,8,11,34,12,16,46,11,16,17,40,12,26,10,7,10,25,10,11,17,36,12,27,14,27,56,7,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,27,56,8,12,28,10,7,10,1,11,2,10,3,11,26,11,25,11,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,33,12,23,10,7,10,28,17,38,10,23,38,4,86,5,102,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,11,13,10,14,10,15,56,10,12,24,10,6,46,17,54,12,36,11,14,10,36,38,4,116,5,132,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,24,11,36,10,15,56,11,12,35,14,24,56,12,12,32,10,5,17,1,12,29,11,6,11,4,11,1,17,26,11,7,10,28,11,31,17,16,10,29,10,23,11,35,11,3,17,43,12,33,11,24,11,5,16,1,20,56,13,11,33,10,29,11,28,11,32,17,25,18,1,56,14,11,29,11,15,46,17,53,14,30,17,15,17,16,11,11,11,10,11,23,52,17,25,18,2,56,15,2,8,1,4,0,56,123,11,0,17,20,17,16,12,19,56,1,12,22,10,9,46,17,53,17,12,12,23,10,5,10,22,17,37,12,17,11,6,10,23,12,10,46,11,10,17,40,12,18,10,5,10,17,11,19,17,36,12,20,14,20,56,7,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,20,56,8,12,21,10,5,10,21,17,38,10,8,77,38,4,58,5,74,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,1,39,10,5,11,1,11,2,11,3,11,18,11,17,10,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,29,11,5,11,21,7,5,10,8,77,17,39,1,12,24,11,7,11,23,11,24,52,10,22,10,9,56,9,11,4,17,1,11,9,46,17,53,14,22,17,15,11,8,17,21,18,3,56,6,2,9,1,4,0,57,186,1,11,0,17,20,10,11,10,10,17,14,12,30,10,11,11,9,17,14,12,29,10,15,46,17,53,17,12,12,33,10,7,10,29,17,37,12,24,11,8,11,33,12,16,46,11,16,17,40,12,25,10,7,10,24,10,11,17,36,12,26,14,26,56,7,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,26,56,8,12,27,10,7,10,27,17,38,10,12,77,38,4,64,5,82,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,10,7,10,1,11,2,10,3,11,25,11,24,10,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,29,11,13,10,14,10,15,56,10,12,23,10,6,46,17,54,12,35,11,14,10,35,38,4,118,5,134,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,23,11,35,10,15,56,11,12,34,14,23,56,12,12,31,10,5,17,1,12,28,11,6,11,4,11,1,17,26,11,7,10,27,11,30,17,16,10,28,10,12,77,11,34,11,3,17,43,12,32,11,23,11,5,16,1,20,56,13,11,32,10,28,11,27,11,31,17,25,18,1,56,14,11,28,11,15,46,17,53,14,29,17,15,17,16,11,11,11,10,11,12,17,21,18,2,56,15,2,10,1,4,0,58,117,11,0,17,20,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,53,17,12,12,27,56,1,12,24,11,8,11,9,10,10,56,2,12,26,10,7,14,26,56,3,12,15,46,11,15,56,4,12,25,11,4,17,1,12,23,11,7,11,26,7,5,64,26,0,0,0,0,0,0,0,0,10,10,56,5,1,10,6,10,24,7,5,10,25,77,17,35,1,12,20,10,5,10,27,12,16,46,11,16,17,41,32,4,74,10,5,10,27,17,42,10,6,10,24,17,37,12,21,11,5,11,27,12,17,46,11,17,17,40,12,22,11,6,11,1,11,2,11,3,11,22,11,21,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,31,11,23,11,10,46,17,53,14,24,17,15,11,25,17,23,18,3,56,6,2,11,1,4,0,59,93,10,0,17,20,10,13,46,17,53,12,27,10,27,17,12,12,25,56,1,12,23,11,10,10,11,17,14,12,29,10,6,11,23,17,37,12,22,10,6,11,29,17,37,12,28,10,4,17,1,12,26,10,9,6,0,0,0,0,0,0,0,0,36,4,43,11,0,10,1,10,2,10,3,11,4,10,5,10,6,11,7,11,8,10,9,11,13,56,16,5,54,11,4,1,11,0,1,11,7,1,11,8,10,9,11,13,56,2,56,17,11,5,11,25,12,15,46,11,15,17,40,12,24,11,6,11,1,11,2,11,3,11,24,11,12,11,28,11,22,12,14,12,21,12,20,12,19,12,18,12,17,12,16,46,11,16,11,17,11,18,11,19,11,20,11,21,11,14,17,30,11,26,11,27,11,11,11,9,17,22,18,3,56,6,2,0,2,0,1,0],"merge_coins":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,10,3,20,53,4,73,14,5,87,102,7,189,1,132,1,8,193,2,96,6,161,3,30,12,191,3,189,1,0,6,1,14,2,2,2,11,2,12,2,0,12,1,0,1,4,1,2,0,0,5,0,1,1,0,1,3,5,6,1,0,1,8,3,4,1,0,2,4,8,4,1,0,2,10,11,1,1,0,2,13,9,10,1,0,2,15,15,1,1,0,3,7,14,4,1,12,4,9,12,13,0,2,1,1,1,3,7,5,7,4,7,7,1,6,7,3,10,11,0,1,9,0,3,7,8,1,1,11,0,1,9,0,6,11,0,1,9,0,11,0,1,9,0,11,0,1,9,0,3,11,0,1,9,0,3,1,7,10,9,0,0,1,6,10,9,0,1,1,1,9,0,2,7,11,0,1,9,0,11,0,1,9,0,1,6,11,0,1,9,0,1,3,3,7,11,0,1,9,0,3,7,8,1,1,6,8,1,1,5,2,9,0,5,1,7,8,1,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,8,105,115,95,101,109,112,116,121,4,106,111,105,110,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,7,114,101,118,101,114,115,101,6,115,101,110,100,101,114,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,118,101,99,116,111,114,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,255,255,255,255,255,255,255,255,0,1,0,0,2,83,14,0,65,1,6,0,0,0,0,0,0,0,0,36,4,67,13,0,56,0,13,0,69,1,12,5,14,0,56,1,32,4,20,5,15,13,5,13,0,69,1,56,2,5,10,11,0,70,1,0,0,0,0,0,0,0,0,14,5,56,3,12,8,10,1,12,6,11,1,7,2,33,4,33,10,8,12,6,11,8,10,6,38,4,38,5,42,11,2,1,7,0,39,14,5,56,3,10,6,36,4,60,13,5,11,6,10,2,56,4,12,7,11,5,11,2,46,17,8,56,5,11,7,12,3,5,64,11,2,1,11,5,12,3,11,3,12,4,5,81,11,0,70,1,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,33,4,74,5,78,11,2,1,7,1,39,11,2,56,6,12,4,11,4,2,0],"oracle":[161,28,235,11,6,0,0,0,11,1,0,36,2,36,84,3,120,157,1,4,149,2,22,5,171,2,231,2,7,146,5,231,6,8,249,11,128,1,6,249,12,70,10,191,13,33,12,224,13,232,5,13,200,19,14,0,47,0,31,2,40,2,41,2,49,2,52,2,54,2,56,2,61,1,23,1,24,1,46,1,62,1,63,1,65,1,66,3,61,3,68,0,10,8,0,0,6,4,0,1,2,0,0,1,3,8,0,2,4,0,1,3,0,3,5,7,0,4,6,7,0,5,7,7,0,6,8,7,0,6,9,12,0,8,12,12,0,9,0,8,0,10,1,12,1,0,1,11,15,4,0,12,11,2,0,13,13,12,2,7,1,4,1,15,14,2,0,16,12,12,0,17,16,0,0,0,43,0,1,0,0,39,2,3,0,0,59,4,1,0,0,58,4,1,0,0,57,5,1,0,0,20,6,1,0,0,21,6,1,0,0,29,7,1,0,1,22,27,1,0,2,28,40,1,1,3,3,33,43,23,0,3,34,43,23,0,4,32,41,42,0,4,35,41,42,0,5,30,19,20,0,6,36,30,20,0,6,37,28,29,0,7,26,33,34,0,7,38,38,39,0,7,67,35,34,0,9,64,22,23,0,11,45,0,8,0,13,17,21,1,2,7,4,13,18,15,17,2,7,4,13,19,36,37,2,7,4,13,25,15,16,2,7,4,13,45,0,10,2,7,4,14,60,13,1,1,8,17,48,31,32,0,26,9,26,11,27,12,25,11,23,11,25,9,22,9,22,11,23,9,24,11,9,29,1,7,8,16,0,2,7,8,0,13,3,15,2,3,3,6,8,2,7,8,0,3,7,6,8,2,7,8,0,10,2,13,15,2,6,8,11,3,7,8,0,10,13,6,8,11,9,6,8,3,7,8,17,7,8,10,7,8,9,7,8,0,13,10,2,6,8,11,11,12,1,8,14,1,8,13,2,13,8,7,1,11,15,2,9,0,9,1,2,13,8,1,1,8,0,1,9,0,4,13,13,6,8,1,7,11,15,2,13,8,1,2,6,11,15,2,9,0,9,1,9,0,1,1,1,6,9,1,5,13,13,8,7,7,11,15,2,13,8,7,7,11,15,2,13,8,1,1,10,2,1,8,7,3,7,11,15,2,9,0,9,1,9,0,9,1,1,6,8,11,1,3,6,13,3,6,13,3,6,8,1,7,11,15,2,13,8,1,1,13,23,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,6,8,11,13,10,2,6,8,11,10,8,18,6,8,11,3,8,5,3,11,4,1,8,8,7,8,1,6,8,7,8,8,11,4,1,8,8,8,5,3,8,6,8,7,8,18,1,6,8,3,1,6,8,9,1,8,8,1,6,8,8,3,6,8,17,10,2,6,8,11,1,8,18,3,6,8,10,10,8,18,6,8,11,1,11,4,1,8,8,5,6,8,10,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,2,7,11,15,2,9,0,9,1,9,0,1,7,9,1,3,6,8,9,6,8,11,3,1,8,6,1,11,4,1,9,0,1,6,8,6,1,8,5,1,6,8,5,5,67,108,111,99,107,4,67,111,105,110,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,15,72,111,116,80,111,116,97,116,111,86,101,99,116,111,114,3,73,54,52,5,80,114,105,99,101,15,80,114,105,99,101,73,100,101,110,116,105,102,105,101,114,9,80,114,105,99,101,73,110,102,111,15,80,114,105,99,101,73,110,102,111,79,98,106,101,99,116,11,80,114,105,99,101,79,114,97,99,108,101,3,83,85,73,5,83,116,97,116,101,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,86,65,65,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,17,99,104,101,99,107,95,103,117,97,114,100,95,112,114,105,99,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,29,99,114,101,97,116,101,95,112,114,105,99,101,95,105,110,102,111,115,95,104,111,116,95,112,111,116,97,116,111,7,100,101,99,105,109,97,108,7,100,101,115,116,114,111,121,24,102,101,101,100,95,116,111,107,101,110,95,112,114,105,99,101,95,98,121,95,112,121,116,104,13,102,114,111,109,95,98,121,116,101,95,118,101,99,7,103,101,110,101,115,105,115,8,103,101,116,95,101,120,112,111,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,110,101,103,97,116,105,118,101,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,112,111,115,105,116,105,118,101,9,103,101,116,95,112,114,105,99,101,20,103,101,116,95,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,37,103,101,116,95,112,114,105,99,101,95,105,110,102,111,95,102,114,111,109,95,112,114,105,99,101,95,105,110,102,111,95,111,98,106,101,99,116,23,103,101,116,95,112,114,105,99,101,95,110,111,95,111,108,100,101,114,95,116,104,97,110,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,17,104,111,116,95,112,111,116,97,116,111,95,118,101,99,116,111,114,3,105,54,52,2,105,100,4,105,110,105,116,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,3,110,101,119,6,111,98,106,101,99,116,6,111,114,97,99,108,101,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,5,112,114,105,99,101,16,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,16,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,16,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,17,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,115,10,112,114,105,99,101,95,105,110,102,111,13,112,114,105,99,101,95,111,114,97,99,108,101,115,4,112,121,116,104,20,114,101,103,105,115,116,101,114,95,116,111,107,101,110,95,112,114,105,99,101,20,115,101,116,95,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,20,115,101,116,95,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,116,97,116,101,3,115,117,105,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,24,117,112,100,97,116,101,95,115,105,110,103,108,101,95,112,114,105,99,101,95,102,101,101,100,3,118,97,97,5,118,97,108,117,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,181,59,15,65,116,16,134,39,251,238,114,226,73,139,88,214,162,113,76,222,213,63,172,83,112,52,194,32,210,99,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,60,0,0,0,0,0,0,0,3,8,16,14,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,5,42,8,13,51,3,50,3,53,11,15,2,13,8,7,55,11,15,2,13,8,1,1,2,3,69,15,27,2,44,3,0,0,0,0,1,11,10,0,17,21,7,1,7,0,10,0,56,0,11,0,56,1,18,0,56,2,2,1,1,0,0,14,32,11,0,15,0,12,5,10,5,10,1,12,2,46,11,2,56,3,4,11,5,15,11,5,1,7,2,39,11,5,11,1,12,3,46,11,3,56,4,12,4,10,4,16,1,20,10,4,16,2,20,11,4,16,3,20,2,2,1,0,0,1,5,11,2,11,1,15,4,21,2,3,1,0,0,1,5,11,2,11,1,15,5,21,2,4,1,0,0,18,58,10,1,15,0,12,11,10,11,10,3,12,7,46,11,7,56,3,32,4,12,5,20,11,11,1,11,1,1,11,6,1,7,3,39,11,2,17,14,12,9,11,1,15,6,12,10,10,10,10,3,12,8,46,11,8,56,5,32,4,35,5,43,11,11,1,11,10,1,11,6,1,7,3,39,11,10,10,3,11,9,56,6,11,11,11,3,11,4,11,5,11,6,17,20,6,232,3,0,0,0,0,0,0,26,18,1,56,7,2,5,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,5,20,35,4,39,5,45,11,8,1,11,0,1,7,4,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,6,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,4,20,35,4,39,5,45,11,8,1,11,0,1,7,5,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,7,1,0,0,26,136,1,11,0,17,8,10,4,16,6,10,5,56,5,4,8,5,20,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,2,39,10,4,15,6,10,5,12,14,46,11,14,56,8,12,24,10,3,46,17,16,12,25,14,25,17,15,12,30,11,24,14,30,33,4,40,5,52,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,6,39,11,1,11,6,10,7,12,16,12,15,46,11,15,11,16,17,28,12,31,10,2,11,31,64,32,1,0,0,0,0,0,0,0,10,7,12,18,12,17,46,11,17,11,18,17,17,12,26,11,2,11,26,10,3,11,8,10,7,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,17,19,12,22,10,7,17,20,6,232,3,0,0,0,0,0,0,26,12,19,11,4,15,0,11,5,56,9,12,23,11,3,11,7,12,13,46,11,13,7,0,17,18,12,29,11,22,56,10,14,29,17,13,12,27,14,27,17,11,12,28,14,29,17,12,12,20,14,20,17,10,12,21,11,28,77,10,23,15,1,21,11,21,51,10,23,15,2,21,11,19,11,23,15,3,21,2,0,4,1,0,1,1,1,2,0,1,0,2,0,3,0],"pool_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,136,1,4,146,1,2,5,148,1,208,1,7,228,2,205,4,8,177,7,32,6,209,7,41,12,250,7,133,12,0,23,0,10,0,24,1,0,7,0,0,18,0,1,0,0,22,0,1,0,0,21,0,1,0,0,19,0,1,0,0,20,0,1,0,0,16,0,1,0,0,17,0,1,0,0,11,2,3,0,0,1,3,4,0,0,15,5,3,0,0,5,3,6,0,0,14,7,3,0,0,4,3,8,0,0,13,9,3,0,0,3,3,9,0,1,2,3,12,0,1,12,12,3,0,2,6,19,20,0,2,7,19,27,0,2,8,19,21,0,2,9,19,1,0,2,25,11,0,0,2,26,25,0,0,2,27,14,0,0,2,28,15,0,0,2,29,13,0,0,2,30,17,18,1,1,26,1,0,1,2,5,8,0,8,0,3,13,10,2,1,10,2,6,8,0,8,0,3,13,2,10,2,5,13,3,8,0,8,0,3,6,13,3,8,0,8,0,3,2,3,8,0,13,10,2,4,8,0,13,2,10,2,3,13,15,2,3,10,2,10,2,10,2,2,7,10,2,13,1,8,0,2,7,10,2,10,2,2,7,10,2,3,2,7,10,2,2,18,10,2,10,2,10,2,10,2,10,2,10,2,3,13,10,2,13,3,3,3,8,0,2,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,17,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,3,3,8,0,2,13,13,8,0,13,2,10,2,10,2,13,10,2,10,2,10,2,10,2,13,10,2,13,3,3,3,2,8,0,13,2,7,10,2,15,9,10,2,10,2,10,2,3,13,15,3,3,2,1,15,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,100,101,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,21,103,101,116,95,100,101,108,101,116,101,95,111,119,110,101,114,95,116,121,112,101,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,16,103,101,116,95,100,101,112,111,115,105,116,95,116,121,112,101,23,103,101,116,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,21,103,101,116,95,115,101,110,100,95,109,101,115,115,97,103,101,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,10,112,111,111,108,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,10,48,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,3,17,21,11,0,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,1,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,2,17,23,13,6,7,2,17,24,14,4,65,1,6,0,0,0,0,0,0,0,0,36,4,46,13,6,14,4,65,1,75,17,21,13,6,11,4,17,25,11,6,2,8,1,0,0,16,172,1,14,0,65,1,12,13,6,0,0,0,0,0,0,0,0,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,1,14,1,17,17,12,8,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,2,14,2,17,17,12,16,11,12,11,11,22,12,12,11,16,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,14,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,3,14,3,17,17,12,18,11,12,11,11,22,12,12,11,18,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,17,11,12,11,11,22,12,12,6,8,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,4,14,4,17,19,12,7,11,12,11,11,22,12,12,6,1,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,5,14,5,17,20,12,15,11,12,11,11,22,12,12,64,1,0,0,0,0,0,0,0,0,12,9,10,13,10,12,36,4,151,1,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,6,14,6,17,17,12,10,11,12,11,11,22,12,12,11,10,52,12,11,14,0,10,12,10,12,10,11,22,56,0,12,9,11,12,11,11,22,12,12,10,15,7,2,33,4,156,1,5,158,1,7,1,39,11,13,11,12,33,4,163,1,5,165,1,7,0,39,11,14,11,17,11,7,11,8,11,15,11,9,2,9,1,0,0,10,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,21,13,6,11,1,17,23,11,2,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,3,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,4,17,23,13,6,7,3,17,24,11,6,2,10,1,0,0,22,152,1,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,15,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,19,12,11,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,17,11,9,11,8,22,12,9,11,17,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,19,12,7,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,20,12,13,11,9,11,8,22,12,9,10,13,7,3,33,4,136,1,5,138,1,7,1,39,11,10,11,9,33,4,143,1,5,145,1,7,0,39,11,15,11,11,11,12,11,16,11,7,11,13,2,11,1,0,0,23,34,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,1,17,21,11,0,17,16,12,4,13,3,14,4,65,1,75,17,21,13,3,11,4,17,25,13,3,7,4,17,24,14,2,65,1,6,0,0,0,0,0,0,0,0,36,4,32,13,3,14,2,65,1,75,17,21,13,3,11,2,17,25,11,3,2,12,1,0,0,24,123,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,5,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,20,12,11,11,9,11,8,22,12,9,64,1,0,0,0,0,0,0,0,0,12,6,10,10,10,9,36,4,104,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,7,11,9,11,8,22,12,9,11,7,52,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,11,9,11,8,22,12,9,10,11,7,4,33,4,109,5,111,7,1,39,11,10,11,9,33,4,116,5,118,7,0,39,11,12,11,5,11,11,11,6,2,13,1,0,0,3,13,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,0,17,21,13,3,11,1,17,22,13,3,11,2,17,24,11,3,2,14,1,0,0,26,64,14,0,65,1,12,8,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,1,14,1,17,17,12,5,11,7,11,4,22,12,7,6,32,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,2,14,2,17,18,12,6,11,7,11,4,22,12,7,6,1,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,3,14,3,17,20,12,9,11,7,11,4,22,12,7,11,8,11,7,33,4,58,5,60,7,0,39,11,5,11,6,11,9,2,0],"pool_manager":[161,28,235,11,6,0,0,0,12,1,0,22,2,22,66,3,88,199,1,4,159,2,62,5,221,2,206,2,7,171,5,144,8,8,187,13,96,6,155,14,138,1,10,165,15,108,12,145,16,154,13,13,171,29,32,15,203,29,4,0,62,0,28,0,30,0,36,1,21,1,58,2,32,2,57,2,74,2,76,2,77,0,9,12,0,0,1,4,0,0,7,4,0,0,4,4,0,0,8,4,0,0,6,4,0,0,0,3,0,0,10,3,0,1,2,7,0,3,3,0,0,4,11,7,0,5,5,7,1,0,0,7,14,4,0,8,12,12,2,7,1,4,1,10,13,2,0,0,51,0,1,0,0,66,2,1,0,0,65,3,1,0,0,71,4,1,0,0,69,5,1,0,0,70,4,1,0,0,47,6,7,0,0,41,8,9,0,0,44,6,10,0,0,37,11,12,0,0,48,6,12,0,0,43,8,12,0,0,42,8,12,0,0,45,6,12,0,0,46,8,12,0,0,38,1,12,0,0,39,1,12,0,0,35,13,14,0,0,34,15,16,0,0,33,17,16,0,0,81,1,18,0,0,16,19,20,0,0,67,19,20,0,1,40,46,9,0,2,24,49,12,0,2,25,49,12,0,2,26,20,12,0,5,56,1,47,1,0,5,73,28,47,1,0,6,29,28,1,1,3,7,55,0,21,0,8,15,31,1,2,7,4,8,22,41,42,2,7,4,8,23,35,36,2,7,4,8,27,41,16,2,7,4,8,55,0,23,2,7,4,9,72,28,1,1,8,35,22,35,24,35,25,35,26,36,27,35,30,31,24,31,26,35,33,31,22,31,25,33,26,33,24,31,30,33,30,32,26,32,25,32,24,32,22,34,33,32,33,32,30,28,32,27,32,34,24,34,25,33,22,31,33,33,33,29,50,29,51,1,7,8,14,0,5,6,8,9,7,8,0,8,10,13,7,8,14,4,6,8,9,7,8,0,8,8,13,4,6,8,9,7,8,0,8,8,15,4,6,8,9,7,8,0,13,15,2,7,8,0,13,1,10,8,8,2,7,8,0,8,8,1,13,1,8,10,3,6,8,0,13,13,1,15,3,7,8,0,13,13,1,11,11,1,8,8,2,6,8,0,13,1,1,2,6,8,0,8,8,1,8,3,4,7,8,0,8,8,13,15,2,15,15,1,8,12,2,13,8,1,1,11,13,2,9,0,9,1,2,13,8,2,2,8,8,13,2,13,10,8,8,1,8,0,1,9,0,8,13,8,10,8,3,11,13,2,8,8,8,4,8,1,7,11,13,2,13,8,1,8,2,7,11,13,2,13,8,2,2,8,8,8,4,3,7,11,13,2,9,0,9,1,9,0,9,1,1,8,8,2,13,8,3,3,13,8,8,7,8,5,2,7,11,13,2,9,0,9,1,9,0,1,7,9,1,4,8,8,13,7,8,2,7,8,4,2,13,7,8,2,3,8,8,13,7,8,4,2,13,13,2,6,11,13,2,9,0,9,1,9,0,1,6,9,1,2,8,8,8,8,2,15,6,11,13,2,13,8,3,4,8,8,3,3,10,8,8,1,6,8,8,1,11,11,1,9,0,9,8,8,13,15,7,11,13,2,13,8,3,7,8,3,13,15,7,8,2,7,8,4,6,15,15,15,15,15,15,1,8,6,1,8,7,12,65,100,100,76,105,113,117,105,100,105,116,121,7,65,112,112,73,110,102,111,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,9,76,105,113,117,105,100,105,116,121,6,79,112,116,105,111,110,11,80,111,111,108,67,97,116,97,108,111,103,8,80,111,111,108,73,110,102,111,13,80,111,111,108,76,105,113,117,105,100,105,116,121,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,15,82,101,109,111,118,101,76,105,113,117,105,100,105,116,121,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,13,97,100,100,95,108,105,113,117,105,100,105,116,121,7,97,108,112,104,97,95,49,6,97,109,111,117,110,116,9,97,112,112,95,105,110,102,111,115,13,97,112,112,95,108,105,113,117,105,100,105,116,121,5,97,115,99,105,105,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,5,101,118,101,110,116,18,101,120,105,115,116,95,99,101,114,116,97,105,110,95,112,111,111,108,13,101,120,105,115,116,95,112,111,111,108,95,105,100,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,100,101,102,97,117,108,116,95,97,108,112,104,97,95,49,20,103,101,116,95,100,101,102,97,117,108,116,95,108,97,109,98,100,97,95,49,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,24,103,101,116,95,112,111,111,108,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,112,111,111,108,95,110,97,109,101,95,98,121,95,105,100,21,103,101,116,95,112,111,111,108,95,116,111,116,97,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,115,95,98,121,95,105,100,19,103,101,116,95,116,111,107,101,110,95,108,105,113,117,105,100,105,116,121,2,105,100,11,105,100,95,116,111,95,112,111,111,108,115,4,105,110,105,116,8,108,97,109,98,100,97,95,49,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,110,97,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,12,112,111,111,108,95,97,100,100,114,101,115,115,12,112,111,111,108,95,99,97,116,97,108,111,103,10,112,111,111,108,95,105,110,102,111,115,12,112,111,111,108,95,109,97,110,97,103,101,114,10,112,111,111,108,95,116,111,95,105,100,5,112,111,111,108,115,13,114,101,103,105,115,116,101,114,95,112,111,111,108,16,114,101,103,105,115,116,101,114,95,112,111,111,108,95,105,100,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,7,114,101,115,101,114,118,101,21,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,97,108,112,104,97,22,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,108,97,109,98,100,97,15,115,101,116,95,112,111,111,108,95,119,101,105,103,104,116,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,116,97,98,108,101,12,116,111,116,97,108,95,119,101,105,103,104,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,119,101,105,103,104,116,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,14,122,101,114,111,95,108,105,113,117,105,100,105,116,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,0,88,241,76,176,44,241,78,240,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,37,164,0,10,139,202,34,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,0,2,4,49,8,12,19,11,13,2,13,8,1,61,11,13,2,13,8,2,60,8,5,1,2,1,20,11,13,2,13,8,3,2,2,5,54,8,10,68,8,3,17,15,75,15,64,11,13,2,8,8,8,4,3,2,1,78,15,4,2,4,78,15,52,15,30,15,79,15,5,2,2,63,11,13,2,8,8,13,50,11,13,2,13,10,8,8,6,2,3,59,8,8,18,15,31,15,7,2,3,59,8,8,18,15,30,15,0,0,0,0,1,14,10,0,17,30,10,0,56,0,10,0,56,1,10,0,56,2,11,0,56,3,18,5,18,0,56,4,2,1,1,0,0,29,54,10,1,10,3,12,5,46,11,5,17,18,32,4,9,5,15,11,1,1,11,4,1,7,2,39,10,1,15,0,12,12,11,2,12,6,17,20,12,7,10,4,56,5,12,8,11,6,11,7,7,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,8,18,2,12,11,11,12,10,3,11,11,56,6,10,1,15,1,15,2,10,3,64,32,0,0,0,0,0,0,0,0,56,7,11,1,15,3,12,10,11,4,56,8,18,1,12,9,11,10,11,3,11,9,56,9,2,2,1,0,0,34,52,10,1,10,3,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,10,1,10,2,12,5,46,11,5,17,19,32,4,21,5,25,11,1,1,7,4,39,10,1,15,1,12,6,10,6,15,4,10,2,10,3,56,10,11,6,15,2,10,3,56,11,10,2,68,32,11,1,15,0,11,3,56,12,15,5,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,4,56,13,2,3,1,0,0,37,43,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,12,6,10,6,15,5,11,2,56,14,12,7,10,6,16,6,20,10,7,16,7,20,23,10,3,22,11,6,15,6,21,11,3,11,7,15,7,21,2,4,1,0,0,38,22,10,1,10,2,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,11,1,15,0,11,2,56,12,12,5,11,3,11,5,15,8,21,2,5,1,0,0,39,29,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,15,5,11,2,56,14,12,6,11,3,11,6,15,9,21,2,6,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,1,15,2,11,1,12,3,46,11,3,56,15,20,2,7,1,0,0,43,22,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,11,0,15,1,15,4,11,1,12,3,46,11,3,56,16,20,2,8,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,0,11,1,12,3,46,11,3,56,17,16,10,20,2,9,1,0,0,44,32,10,0,10,1,17,18,4,5,5,9,11,0,1,7,3,39,11,0,16,3,11,1,56,18,16,11,12,4,10,4,10,2,56,19,4,26,11,4,11,2,56,20,16,12,20,12,3,5,30,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,10,1,0,0,9,20,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,13,16,12,20,2,11,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,14,20,2,12,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,15,20,2,13,1,0,0,9,19,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,6,20,2,14,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,7,20,2,15,1,0,0,1,2,7,0,2,16,1,0,0,1,2,7,1,2,17,1,0,0,45,34,11,0,11,1,17,6,12,6,14,6,65,32,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,32,5,14,14,6,10,4,66,32,20,12,3,14,3,17,23,10,2,33,4,27,11,3,56,22,2,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,9,56,23,2,18,1,0,0,1,5,11,0,16,0,11,1,56,24,2,19,1,0,0,1,6,11,0,16,1,16,4,11,1,56,25,2,20,1,0,0,1,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,2,21,3,0,0,48,119,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,12,16,15,20,10,12,16,9,20,17,25,12,10,10,3,10,10,22,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,32,4,73,11,7,11,2,10,6,18,3,56,27,5,85,11,7,11,2,56,28,12,8,10,8,16,12,20,10,6,22,11,8,15,12,21,10,11,16,13,16,12,20,10,3,22,11,11,15,13,15,12,21,10,12,16,14,20,10,3,22,10,12,15,14,21,10,12,16,15,20,10,10,23,11,12,15,15,21,11,1,11,3,10,10,18,6,56,29,11,6,11,10,2,22,3,0,0,48,151,1,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,12,16,14,20,10,3,38,4,33,5,41,11,0,1,11,12,1,11,11,1,7,8,39,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,11,16,8,20,10,12,16,9,20,17,24,12,10,10,3,10,10,23,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,4,82,5,90,11,12,1,11,11,1,11,7,1,7,6,39,11,7,11,2,56,28,12,8,10,8,16,12,20,10,3,38,4,101,5,109,11,12,1,11,11,1,11,8,1,7,7,39,10,8,16,12,20,10,3,23,11,8,15,12,21,10,11,16,13,16,12,20,10,6,23,11,11,15,13,15,12,21,10,12,16,14,20,10,6,23,10,12,15,14,21,10,12,16,15,20,10,10,22,11,12,15,15,21,11,1,11,3,10,10,18,7,56,30,11,6,11,10,2,0,2,0,3,5,1,0,1,5,0,2,4,2,3,4,3,2,2,4,1,2,0,1,0,3,0,2,1,4,0,4,2,0,53,0,80,0],"rates":[161,28,235,11,6,0,0,0,8,1,0,6,2,6,4,3,10,70,5,80,48,7,128,1,185,2,8,185,3,32,6,217,3,68,12,157,4,128,5,0,13,0,11,0,16,1,0,8,0,0,6,0,1,0,0,2,0,1,0,0,5,2,1,0,0,1,3,1,0,0,3,4,1,0,0,4,4,1,0,1,7,6,1,0,1,8,6,3,0,1,9,6,1,0,1,10,6,1,0,2,12,7,1,0,2,14,5,1,0,2,15,7,1,0,2,17,7,1,0,3,7,8,0,13,15,1,15,4,7,8,0,13,15,15,4,15,15,15,15,3,15,15,15,0,2,7,8,0,13,2,15,15,6,15,15,15,15,15,15,7,15,15,15,15,15,15,15,7,83,116,111,114,97,103,101,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,21,99,97,108,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,3,109,105,110,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,128,81,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,3,29,10,0,10,1,17,8,12,6,11,0,11,1,17,6,12,4,11,6,11,4,17,13,12,5,10,5,10,2,22,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,27,10,5,11,5,11,2,22,17,12,12,3,11,3,2,1,1,0,0,8,39,10,0,10,1,11,2,17,0,12,8,11,0,11,1,17,7,12,7,12,6,12,5,12,4,10,8,10,7,35,4,23,11,4,11,8,11,5,17,13,22,12,3,5,37,11,4,11,5,22,11,6,11,8,10,7,23,17,11,11,7,23,17,12,17,13,22,12,3,11,3,2,2,1,0,0,7,17,10,0,10,1,11,3,17,0,12,5,11,0,11,1,17,9,12,4,11,2,11,5,17,11,11,4,23,17,13,17,13,2,3,1,0,0,7,20,11,0,11,1,23,7,1,17,10,12,4,7,1,10,4,23,12,5,11,2,11,5,24,11,3,11,4,24,22,7,1,26,2,4,1,0,0,9,69,11,0,11,1,23,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,10,17,11,2,10,5,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,6,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,23,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,7,5,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,2,10,2,17,13,7,0,7,0,24,26,12,4,10,4,10,2,17,13,7,0,26,12,3,10,5,10,6,24,11,4,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,10,5,11,6,24,11,7,24,11,3,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,9,17,11,11,2,11,5,24,7,0,26,22,11,8,22,11,9,22,2,5,1,0,0,1,12,11,2,11,0,11,1,23,24,7,0,26,12,3,17,11,11,3,22,2,0],"ray_math":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,40,5,42,13,7,55,59,8,114,32,6,146,1,146,1,12,164,2,247,5,0,7,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,4,2,1,0,0,1,2,1,0,0,2,2,1,0,0,6,1,1,0,0,0,1,3,0,0,1,15,2,15,15,1,2,4,15,2,15,15,4,108,111,103,50,3,109,97,120,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,208,121,0,161,63,121,92,118,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,249,214,165,42,128,81,101,243,159,91,61,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,1,0,0,0,2,7,0,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,10,11,0,11,1,24,7,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,7,0,26,2,3,1,0,0,0,10,11,0,7,0,24,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,11,1,26,2,4,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,6,1,0,0,4,59,10,0,7,0,38,4,5,5,7,7,4,39,10,0,7,0,26,17,7,12,2,10,2,77,7,0,24,12,3,11,0,11,2,48,12,4,10,4,7,0,33,4,27,11,3,2,7,1,12,1,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,57,5,34,10,4,11,4,24,7,0,26,12,4,10,4,7,2,38,4,52,11,3,10,1,22,12,3,11,4,49,1,48,12,4,11,1,49,1,48,12,1,5,29,11,3,2,7,1,0,0,3,112,49,0,12,1,10,0,49,128,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,16,11,0,49,128,48,12,0,11,1,49,128,22,12,1,10,0,49,64,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,30,11,0,49,64,48,12,0,11,1,49,64,22,12,1,10,0,49,32,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,44,11,0,49,32,48,12,0,11,1,49,32,22,12,1,10,0,49,16,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,58,11,0,49,16,48,12,0,11,1,49,16,22,12,1,10,0,49,8,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,72,11,0,49,8,48,12,0,11,1,49,8,22,12,1,10,0,49,4,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,0,49,4,48,12,0,11,1,49,4,22,12,1,10,0,49,2,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,100,11,0,49,2,48,12,0,11,1,49,2,22,12,1,11,0,49,1,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,110,11,1,49,1,22,12,1,11,1,2,0],"scaled_balance":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,25,5,29,6,7,35,75,8,110,32,12,142,1,39,0,6,0,4,0,0,0,1,0,0,2,0,1,0,0,1,0,1,0,1,3,0,1,0,1,5,0,1,0,2,15,15,1,15,0,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,2,4,11,0,11,1,17,4,2,1,1,0,0,2,4,11,0,11,1,17,3,2,2,1,0,0,2,4,11,0,11,1,17,3,2,0],"serde":[161,28,235,11,6,0,0,0,9,1,0,12,2,12,8,3,20,167,1,4,187,1,12,5,199,1,148,1,7,219,2,211,4,8,174,7,96,6,142,8,20,12,162,8,157,35,0,23,1,4,1,6,1,36,1,37,2,2,1,0,7,0,3,1,7,0,0,32,0,1,0,0,28,2,1,0,0,31,3,1,0,0,26,4,1,0,0,29,5,1,0,0,19,6,6,0,0,5,6,6,0,0,27,4,1,0,0,30,5,1,0,0,33,7,1,0,0,24,8,1,0,0,25,9,1,1,0,0,34,7,1,0,0,14,10,6,0,0,10,10,11,0,0,13,10,12,0,0,8,10,13,0,0,11,10,14,0,0,9,10,13,0,0,12,10,14,0,0,7,10,15,0,0,18,10,12,0,0,15,10,16,0,0,38,17,18,1,1,0,39,19,20,1,3,1,20,28,16,0,2,35,27,16,1,0,3,17,1,30,1,0,3,21,30,28,0,4,3,25,1,1,0,4,22,24,1,1,0,5,16,16,15,0,30,6,29,6,26,15,27,29,23,6,23,29,2,7,10,2,2,0,2,7,10,2,13,2,7,10,2,3,2,7,10,2,4,2,7,10,2,15,1,2,2,7,10,2,10,2,2,7,10,2,5,1,7,10,2,1,6,10,2,1,13,1,3,1,4,1,15,1,5,1,10,2,3,6,10,9,0,3,3,1,10,9,0,2,6,10,9,0,9,0,1,10,10,9,0,2,1,2,3,1,1,2,2,4,10,2,1,7,10,9,0,2,7,10,9,0,10,9,0,2,15,10,2,1,6,9,0,1,8,0,1,9,0,1,8,1,2,4,3,2,15,3,3,10,2,3,3,3,1,3,10,9,0,3,3,10,10,9,0,3,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,6,97,112,112,101,110,100,5,97,115,99,105,105,16,97,115,99,105,105,95,116,111,95,104,101,120,95,115,116,114,3,98,99,115,19,100,101,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,16,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,29,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,29,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,30,100,101,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,17,103,101,116,95,118,101,99,116,111,114,95,108,101,110,103,116,104,16,104,101,120,95,115,116,114,95,116,111,95,97,115,99,105,105,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,7,114,101,118,101,114,115,101,5,115,101,114,100,101,17,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,14,115,101,114,105,97,108,105,122,101,95,116,121,112,101,14,115,101,114,105,97,108,105,122,101,95,117,49,50,56,27,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,27,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,28,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,6,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,12,118,101,99,116,111,114,95,115,112,108,105,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,68,6,2,1,1,0,0,1,15,10,0,10,1,49,8,48,72,255,0,28,51,17,0,11,0,11,1,72,255,0,28,51,17,0,2,2,1,0,0,1,63,10,0,10,1,49,56,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,6,255,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,6,255,0,0,0,0,0,0,0,28,51,17,0,2,3,1,0,0,1,127,10,0,10,1,49,120,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,4,1,0,0,1,255,1,10,0,10,1,49,248,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,240,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,232,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,224,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,216,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,208,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,200,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,192,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,184,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,176,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,168,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,160,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,152,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,144,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,136,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,128,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,120,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,5,1,0,0,21,31,10,0,49,0,38,4,9,10,0,49,9,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,22,12,2,5,29,10,0,49,15,37,4,23,5,25,7,1,39,11,0,49,87,22,12,2,11,2,2,6,1,0,0,22,40,10,0,49,48,38,4,9,10,0,49,57,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,3,5,38,10,0,49,97,38,4,27,10,0,49,102,37,12,2,5,29,9,12,2,11,2,4,32,5,34,7,1,39,11,0,49,87,23,12,3,11,3,2,7,1,0,0,23,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,8,1,0,0,26,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,9,1,0,0,1,4,11,0,11,1,56,1,2,10,1,0,0,16,17,14,1,56,2,12,2,14,2,65,6,6,32,0,0,0,0,0,0,0,33,4,9,5,13,11,0,1,7,0,39,11,0,11,2,56,1,2,11,1,0,0,28,8,56,3,17,28,12,1,11,0,11,1,17,25,17,9,2,12,1,0,0,12,17,14,1,65,6,12,2,10,2,6,0,0,0,0,0,0,0,0,33,4,10,11,0,1,2,10,0,11,2,17,2,11,0,11,1,17,9,2,13,1,0,0,1,15,10,0,65,6,6,1,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,6,0,0,0,0,0,0,0,0,66,6,20,2,14,1,0,0,1,24,10,0,65,6,6,2,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,75,49,8,47,11,0,6,1,0,0,0,0,0,0,0,66,6,20,75,22,2,15,1,0,0,1,72,10,0,65,6,6,8,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,52,49,56,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,52,49,48,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,52,49,40,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,52,49,32,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,52,49,24,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,52,49,16,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,52,49,8,47,22,11,0,6,7,0,0,0,0,0,0,0,66,6,20,52,22,2,16,1,0,0,1,136,1,10,0,65,6,6,16,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,53,49,120,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,53,49,112,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,53,49,104,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,53,49,96,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,53,49,88,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,53,49,80,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,53,49,72,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,53,49,64,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,53,49,56,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,53,49,48,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,53,49,40,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,53,49,32,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,53,49,24,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,53,49,16,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,53,49,8,47,22,11,0,6,15,0,0,0,0,0,0,0,66,6,20,53,22,2,17,1,0,0,1,136,2,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,77,49,248,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,77,49,240,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,77,49,232,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,77,49,224,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,77,49,216,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,77,49,208,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,77,49,200,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,77,49,192,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,77,49,184,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,77,49,176,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,77,49,168,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,77,49,160,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,77,49,152,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,77,49,144,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,77,49,136,47,22,10,0,6,15,0,0,0,0,0,0,0,66,6,20,77,49,128,47,22,10,0,6,16,0,0,0,0,0,0,0,66,6,20,77,49,120,47,22,10,0,6,17,0,0,0,0,0,0,0,66,6,20,77,49,112,47,22,10,0,6,18,0,0,0,0,0,0,0,66,6,20,77,49,104,47,22,10,0,6,19,0,0,0,0,0,0,0,66,6,20,77,49,96,47,22,10,0,6,20,0,0,0,0,0,0,0,66,6,20,77,49,88,47,22,10,0,6,21,0,0,0,0,0,0,0,66,6,20,77,49,80,47,22,10,0,6,22,0,0,0,0,0,0,0,66,6,20,77,49,72,47,22,10,0,6,23,0,0,0,0,0,0,0,66,6,20,77,49,64,47,22,10,0,6,24,0,0,0,0,0,0,0,66,6,20,77,49,56,47,22,10,0,6,25,0,0,0,0,0,0,0,66,6,20,77,49,48,47,22,10,0,6,26,0,0,0,0,0,0,0,66,6,20,77,49,40,47,22,10,0,6,27,0,0,0,0,0,0,0,66,6,20,77,49,32,47,22,10,0,6,28,0,0,0,0,0,0,0,66,6,20,77,49,24,47,22,10,0,6,29,0,0,0,0,0,0,0,66,6,20,77,49,16,47,22,10,0,6,30,0,0,0,0,0,0,0,66,6,20,77,49,8,47,22,11,0,6,31,0,0,0,0,0,0,0,66,6,20,77,22,2,18,1,0,0,31,29,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,53,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,19,1,0,0,32,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,77,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,20,1,0,0,1,14,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,20,17,31,2,21,1,0,0,16,8,11,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,2,22,1,0,0,33,46,10,0,65,6,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,64,6,0,0,0,0,0,0,0,0,2,10,3,6,8,0,0,0,0,0,0,0,36,4,16,5,20,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,12,2,11,3,10,2,6,8,0,0,0,0,0,0,0,22,33,4,35,5,39,11,0,1,7,0,39,11,0,6,8,0,0,0,0,0,0,0,11,2,6,8,0,0,0,0,0,0,0,22,56,4,2,23,1,0,0,34,43,10,1,10,2,35,4,10,10,2,10,0,65,29,37,12,3,5,12,9,12,3,11,3,4,15,5,19,11,0,1,7,0,39,64,29,0,0,0,0,0,0,0,0,12,5,11,1,12,4,10,4,10,2,35,4,39,5,28,13,5,10,0,10,4,66,29,20,68,29,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,23,11,0,1,11,5,2,24,1,0,0,35,53,64,18,0,0,0,0,0,0,0,0,12,3,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,29,35,4,38,5,12,10,0,10,2,66,29,20,10,1,33,4,33,10,4,10,2,35,4,29,13,3,10,0,11,4,10,2,56,5,68,18,10,2,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,10,4,10,2,35,4,49,13,3,11,0,11,4,11,2,56,5,68,18,5,51,11,0,1,11,3,2,0],"system_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,71,4,81,2,5,83,78,7,161,1,150,2,8,183,3,32,6,215,3,26,12,241,3,169,2,0,16,0,6,0,11,1,0,7,0,0,9,0,1,0,0,10,0,1,0,0,7,2,3,0,0,1,3,2,0,1,2,3,7,0,1,8,7,3,0,2,3,13,14,0,2,4,13,15,0,2,5,13,1,0,2,12,5,0,0,2,13,6,0,0,2,14,9,0,0,2,15,8,0,0,2,17,11,12,1,1,13,1,0,1,2,4,13,3,8,0,2,1,10,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,12,10,2,10,2,10,2,10,2,8,0,13,3,3,3,3,13,2,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,11,68,111,108,97,65,100,100,114,101,115,115,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,19,101,110,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,115,121,115,116,101,109,95,99,111,100,101,99,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,4,24,64,1,0,0,0,0,0,0,0,0,12,5,13,5,11,0,17,9,13,5,11,1,17,10,11,2,17,5,12,4,13,5,14,4,65,1,75,17,9,13,5,11,4,17,12,13,5,11,3,17,11,11,5,2,3,1,0,0,10,96,14,0,65,1,12,9,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,1,14,1,17,6,12,11,11,8,11,7,22,12,8,6,8,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,2,14,2,17,7,12,10,11,8,11,7,22,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,3,14,3,17,6,12,6,11,8,11,7,22,12,8,11,6,52,12,7,14,0,10,8,10,8,10,7,22,56,0,17,4,12,5,11,8,11,7,22,12,8,6,1,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,4,14,4,17,8,12,12,11,8,11,7,22,12,8,11,9,11,8,33,4,89,5,91,7,0,39,11,11,11,10,11,5,11,12,2,0],"system_core_storage":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,24,3,36,26,4,62,2,5,64,35,7,99,252,1,8,223,2,64,10,159,3,9,12,168,3,34,13,202,3,2,15,204,3,2,0,16,0,7,0,8,1,13,1,18,1,19,0,2,8,0,1,0,12,0,1,3,12,0,2,1,0,0,3,5,4,0,5,4,2,0,0,11,0,1,0,0,9,2,3,0,1,14,0,6,0,3,12,4,5,0,4,15,8,1,1,8,4,7,3,6,8,3,7,8,2,7,8,5,0,1,6,8,0,1,6,8,1,1,7,8,5,1,8,4,1,8,1,1,8,0,1,9,0,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,7,83,116,111,114,97,103,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,3,110,101,119,6,111,98,106,101,99,116,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,10,8,4,6,8,1,0,1,0,0,1,9,10,2,17,3,11,0,11,1,11,2,17,2,18,0,56,0,2,1,3,0,0,1,3,11,0,16,0,2,0,1,0,17,0],"system_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,24,2,24,40,3,64,71,4,135,1,2,5,137,1,117,7,254,1,155,4,8,153,6,96,6,249,6,10,10,131,7,17,12,148,7,191,1,0,33,0,10,0,16,0,19,0,31,0,32,0,38,0,39,1,14,1,18,1,34,2,30,0,7,3,0,1,0,12,0,2,3,7,0,3,4,8,0,5,6,8,0,6,9,12,0,7,2,12,0,8,1,8,0,10,8,2,0,11,5,12,0,0,11,0,1,0,0,35,0,1,0,2,22,13,8,0,2,23,13,14,0,3,13,3,1,0,4,15,8,9,0,4,21,1,10,0,4,24,1,10,0,5,20,4,5,0,6,11,12,1,0,6,27,11,1,0,6,35,12,1,0,7,26,6,7,0,9,17,16,1,1,3,13,15,8,6,8,3,7,8,5,7,8,9,7,8,6,6,8,4,10,2,6,8,7,7,8,8,0,6,10,2,8,2,2,3,8,2,13,1,6,8,3,1,6,8,4,1,6,8,1,6,7,8,9,7,8,6,6,8,1,10,2,6,8,7,7,8,8,2,8,2,10,2,1,10,2,4,13,3,8,2,2,1,2,2,7,8,5,8,2,3,7,8,5,8,2,8,2,1,6,8,2,1,13,1,8,0,1,9,0,6,10,2,2,3,8,2,13,8,2,6,65,112,112,67,97,112,5,67,108,111,99,107,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,5,83,116,97,116,101,7,83,116,111,114,97,103,101,15,83,121,115,116,101,109,67,111,114,101,69,118,101,110,116,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,11,97,112,112,95,109,97,110,97,103,101,114,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,110,111,110,99,101,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,12,115,121,115,116,101,109,95,99,111,100,101,99,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,0,2,6,25,3,28,10,2,29,13,37,13,36,10,2,12,2,0,1,4,0,2,51,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,12,11,8,17,5,12,10,12,9,12,11,12,13,10,10,17,6,33,4,23,5,27,11,1,1,7,0,39,10,12,10,9,33,4,35,11,1,10,12,17,10,5,39,11,1,10,12,10,9,17,9,11,11,14,12,17,2,11,13,14,9,17,3,14,9,17,2,11,10,18,0,56,0,2,1,1,4,0,17,43,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,11,11,8,17,5,12,9,12,13,12,10,12,12,10,9,17,7,33,4,23,5,27,11,1,1,7,0,39,11,1,10,11,10,13,17,11,11,10,14,11,17,2,11,12,14,13,17,3,14,13,17,2,11,9,18,0,56,0,2,0],"system_portal":[161,28,235,11,6,0,0,0,10,1,0,18,2,18,28,3,46,82,4,128,1,4,5,132,1,84,7,216,1,208,3,8,168,5,64,10,232,5,22,12,254,5,187,1,13,185,7,2,0,30,0,13,0,16,0,29,0,37,1,15,1,25,1,31,1,32,0,3,8,0,0,2,3,0,1,0,7,0,2,1,8,0,4,6,12,0,6,5,4,0,8,4,2,0,0,21,0,1,0,0,18,2,3,0,0,8,4,1,0,0,34,4,1,0,1,11,11,12,0,1,12,13,12,0,2,10,9,1,0,3,17,1,16,0,3,19,1,16,0,4,7,15,1,0,4,26,14,1,0,4,33,15,1,0,5,14,7,1,1,3,6,22,0,5,0,7,28,7,1,1,8,8,27,10,11,0,14,6,12,17,1,7,8,6,0,1,7,8,0,1,3,6,6,8,3,7,8,0,7,8,4,13,10,2,7,8,6,1,8,5,1,8,0,1,9,0,3,8,2,5,8,2,1,6,8,3,1,6,8,6,1,5,1,8,2,2,13,10,2,2,7,8,4,8,2,3,7,8,4,8,2,8,2,1,2,1,8,1,3,5,8,2,8,2,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,83,121,115,116,101,109,76,111,99,97,108,69,118,101,110,116,12,83,121,115,116,101,109,80,111,114,116,97,108,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,7,98,105,110,100,105,110,103,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,2,105,100,4,105,110,105,116,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,6,111,98,106,101,99,116,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,115,121,115,116,101,109,95,99,111,100,101,99,13,115,121,115,116,101,109,95,112,111,114,116,97,108,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,117,110,98,105,110,100,105,110,103,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,20,8,5,23,3,1,2,5,24,3,27,5,36,13,35,10,2,9,2,0,0,0,0,1,6,11,0,17,13,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,4,0,8,34,11,0,17,6,11,5,46,17,15,12,7,10,7,17,4,12,8,10,3,10,4,17,5,12,6,10,8,10,6,33,4,21,11,2,11,8,17,10,5,25,11,2,11,8,11,6,17,9,11,1,17,1,11,7,11,3,11,4,17,7,18,1,56,1,2,3,1,4,0,18,26,11,0,17,6,11,5,46,17,15,12,6,10,6,17,4,12,8,10,3,10,4,17,5,12,7,11,2,11,8,11,7,17,11,11,1,17,1,11,6,11,3,11,4,17,8,18,1,56,1,2,0,1,0],"user_manager":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,40,3,58,138,1,4,196,1,42,5,238,1,128,2,7,238,3,161,5,8,143,9,96,6,239,9,60,10,171,10,49,12,220,10,247,4,13,211,15,8,15,219,15,8,0,48,0,15,0,20,1,49,2,19,2,31,2,39,2,40,2,41,0,8,12,0,0,7,4,0,0,0,3,0,0,6,3,0,1,1,7,0,2,2,0,0,5,5,4,0,6,3,12,2,7,1,4,1,8,4,2,0,0,26,0,1,0,0,33,2,1,0,0,43,3,1,0,0,22,4,5,0,0,23,6,7,0,0,32,4,8,0,0,27,4,9,0,0,34,10,1,0,0,10,11,1,0,0,42,11,1,0,1,21,28,29,0,1,44,30,8,0,3,25,37,38,1,0,3,35,39,18,1,0,4,18,18,1,1,3,5,30,0,12,0,6,9,21,1,2,7,4,6,11,20,25,2,7,4,6,12,22,35,2,7,4,6,14,20,9,2,7,4,6,29,32,5,2,7,4,6,30,0,14,2,7,4,6,35,22,23,2,7,4,7,36,18,1,1,8,21,13,21,15,21,16,23,17,19,16,16,16,22,16,19,13,17,13,19,15,17,15,17,16,20,15,16,13,16,15,14,33,18,15,12,8,22,13,13,8,14,40,1,7,8,8,0,4,6,8,5,7,8,0,13,13,3,6,8,5,7,8,0,13,2,6,8,0,8,4,1,3,2,6,8,0,3,1,10,8,4,1,8,4,1,1,2,7,8,0,8,4,3,7,8,0,8,4,8,4,1,8,6,2,8,4,3,1,11,7,2,9,0,9,1,2,3,10,8,4,2,13,13,1,8,0,1,9,0,2,13,7,11,7,2,13,13,2,6,11,7,2,9,0,9,1,9,0,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,9,1,2,8,4,6,8,1,1,6,9,1,1,6,8,1,3,8,4,6,11,7,2,13,13,13,1,6,8,4,1,13,2,8,4,13,6,8,4,8,4,3,8,4,10,8,4,7,8,1,1,6,11,7,2,9,0,9,1,1,8,2,7,8,4,8,4,8,4,8,4,3,7,10,8,4,7,8,1,1,7,9,1,10,8,4,8,4,8,4,6,8,4,3,3,3,8,4,7,10,8,4,7,8,1,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,1,8,3,8,66,105,110,100,85,115,101,114,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,10,85,110,98,105,110,100,85,115,101,114,18,85,115,101,114,65,100,100,114,101,115,115,67,97,116,97,108,111,103,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,97,100,100,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,97,105,110,95,105,100,95,116,111,95,103,114,111,117,112,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,17,100,111,108,97,95,117,115,101,114,95,97,100,100,114,101,115,115,12,100,111,108,97,95,117,115,101,114,95,105,100,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,18,103,101,116,95,117,115,101,114,95,97,100,100,114,101,115,115,101,115,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,16,112,114,111,99,101,115,115,95,103,114,111,117,112,95,105,100,22,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,115,121,115,116,101,109,95,112,111,114,116,97,108,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,24,117,110,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,115,101,114,95,97,100,100,114,101,115,115,95,99,97,116,97,108,111,103,23,117,115,101,114,95,97,100,100,114,101,115,115,95,116,111,95,117,115,101,114,95,105,100,20,117,115,101,114,95,105,100,95,116,111,95,97,100,100,114,101,115,115,101,115,12,117,115,101,114,95,109,97,110,97,103,101,114,6,118,101,99,116,111,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,3,24,8,6,45,8,1,13,11,7,2,13,13,1,2,2,46,11,7,2,8,4,3,47,11,7,2,3,10,8,4,2,2,2,16,8,4,17,3,3,2,2,16,8,4,17,3,0,0,0,0,1,12,10,0,17,15,10,0,56,0,10,0,56,1,18,1,11,0,56,2,18,0,56,3,2,1,1,0,0,19,21,11,1,15,0,12,5,10,5,10,2,12,4,46,11,4,56,4,32,4,12,5,16,11,5,1,7,3,39,11,5,11,2,11,3,56,5,2,2,1,0,0,19,20,11,1,15,0,12,4,10,4,10,2,12,3,46,11,3,56,4,4,11,5,15,11,4,1,7,4,39,11,4,11,2,56,6,1,2,3,1,0,0,24,23,10,0,11,1,17,5,12,2,11,0,16,1,12,3,10,3,16,2,10,2,56,7,4,13,5,17,11,3,1,7,1,39,11,3,16,2,11,2,56,8,20,2,4,1,0,0,26,19,11,0,16,1,12,2,10,2,16,3,10,1,56,9,4,9,5,13,11,2,1,7,1,39,11,2,16,3,11,1,56,10,20,2,5,1,0,0,27,24,14,1,17,10,12,4,11,0,16,0,12,3,10,3,10,4,56,4,4,18,11,1,11,3,11,4,56,11,20,17,11,12,2,5,22,11,3,1,11,1,12,2,11,2,2,6,1,0,0,8,10,10,0,11,1,17,5,12,2,11,0,16,1,16,2,11,2,56,7,2,7,3,0,0,31,50,10,0,11,1,12,2,46,11,2,17,5,12,5,11,0,15,1,12,7,10,7,15,2,10,5,12,3,46,11,3,56,7,32,4,20,5,24,11,7,1,7,0,39,10,7,16,3,56,12,6,1,0,0,0,0,0,0,0,22,12,4,64,8,0,0,0,0,0,0,0,0,12,6,10,7,15,2,10,5,10,4,56,13,13,6,10,5,68,8,11,7,15,3,10,4,11,6,56,14,11,5,11,4,18,2,56,15,2,8,3,0,0,34,49,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,11,2,12,4,46,11,4,17,5,12,6,11,0,15,1,12,9,10,9,15,2,10,6,12,5,46,11,5,56,7,32,4,27,5,31,11,9,1,7,0,39,10,9,15,3,10,7,56,16,12,8,11,9,15,2,10,6,10,7,56,13,11,8,10,6,68,8,11,6,11,7,18,2,56,15,2,9,3,0,0,36,73,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,10,2,12,4,46,11,4,17,3,12,9,10,7,10,9,33,4,19,5,23,11,0,1,7,5,39,10,0,11,2,12,5,46,11,5,17,5,12,10,11,0,15,1,12,12,10,12,15,3,11,9,56,16,12,11,10,11,46,65,8,6,2,0,0,0,0,0,0,0,38,4,45,5,51,11,12,1,11,11,1,7,2,39,10,11,14,10,12,6,46,11,6,56,17,12,8,1,11,12,15,2,10,10,56,18,1,11,11,11,8,56,19,1,11,10,11,7,18,3,56,20,2,0,2,0,1,1,0,1,1,0,28,0,37,0,38,0,50,0],"wormhole_adapter_core":[161,28,235,11,6,0,0,0,12,1,0,46,2,46,114,3,160,1,212,1,4,244,2,22,5,138,3,146,3,7,156,6,196,10,8,224,16,96,6,192,17,30,10,222,17,68,12,162,18,236,4,13,142,23,6,15,148,23,6,0,90,0,27,0,36,0,46,0,62,0,63,0,87,0,91,1,29,1,30,1,44,1,59,1,60,1,81,1,85,1,86,1,89,2,28,2,40,2,45,2,66,2,80,2,88,0,4,12,0,0,15,3,0,0,5,3,0,0,16,3,0,0,6,3,0,0,17,3,0,0,7,3,0,1,0,12,0,2,8,7,0,3,11,0,0,5,14,12,0,6,23,12,0,7,22,12,0,8,2,8,0,9,3,12,1,0,1,11,21,4,0,12,13,12,2,7,1,12,1,13,18,2,0,15,20,2,0,16,25,7,2,1,0,0,0,17,1,7,0,18,9,12,0,19,10,7,0,20,12,0,0,21,19,12,0,22,24,0,0,0,53,0,1,0,0,71,2,1,0,0,35,3,1,0,0,75,4,1,0,0,76,4,1,0,0,73,4,1,0,0,74,4,1,0,0,68,5,6,0,0,67,7,8,0,0,69,5,6,0,0,79,9,10,0,1,47,45,46,0,4,33,24,48,0,4,34,24,44,0,4,42,33,24,0,4,43,54,24,0,4,48,1,32,0,4,49,1,32,0,4,50,1,32,0,4,51,1,32,0,5,26,49,50,0,5,78,49,50,0,6,55,51,23,0,6,70,52,1,0,7,61,42,43,0,10,39,21,1,1,3,11,58,12,13,0,12,58,12,17,2,7,12,14,65,21,1,1,12,16,32,22,23,2,1,0,16,41,1,19,2,1,0,16,54,27,1,2,1,0,16,77,29,30,2,1,0,17,58,24,25,0,18,58,14,15,0,19,58,25,26,0,19,84,26,24,0,20,64,34,35,0,20,66,36,10,0,22,83,43,24,0,27,16,30,18,28,20,29,18,31,18,25,28,32,18,25,37,25,38,25,39,25,40,3,6,8,9,7,8,24,7,8,18,0,4,6,8,9,7,8,0,13,10,2,3,6,8,9,7,8,0,13,7,6,8,9,7,8,24,7,8,0,13,15,11,14,1,8,17,6,8,13,6,7,8,24,7,8,0,6,8,7,10,2,6,8,13,7,8,18,2,8,8,10,2,8,7,8,24,7,8,0,6,8,7,10,2,7,8,10,7,8,11,6,8,13,7,8,18,4,8,8,8,8,15,10,2,11,7,8,24,7,8,0,6,8,7,7,8,10,8,8,8,8,13,3,15,11,14,1,8,17,6,8,13,1,3,3,7,8,24,7,8,18,8,15,1,7,8,18,1,8,15,2,6,8,24,7,8,18,1,8,21,2,8,20,8,12,1,11,16,2,9,0,9,1,2,13,8,22,1,11,19,2,9,0,9,1,1,8,0,1,9,0,2,6,11,19,2,9,0,9,1,6,9,0,1,1,1,10,2,1,8,20,1,8,22,3,7,11,19,2,9,0,9,1,9,0,9,1,1,8,1,2,7,11,19,2,9,0,9,1,6,9,0,2,9,0,9,1,2,8,23,10,2,1,2,3,13,15,2,3,7,8,21,14,10,2,1,8,23,4,7,8,24,11,14,1,8,17,8,23,6,8,13,1,8,3,1,8,5,1,8,4,1,8,6,3,13,10,2,8,8,6,7,8,24,6,11,19,2,13,8,22,7,11,16,2,8,20,8,12,10,2,6,8,13,7,8,18,1,8,25,4,8,8,13,2,10,2,1,6,8,7,1,13,7,8,8,15,3,13,10,2,8,8,8,8,6,8,8,8,8,3,13,2,10,2,4,7,8,10,8,8,13,15,2,15,15,2,6,8,11,8,8,2,7,8,11,8,8,3,15,8,23,10,2,5,13,3,8,8,8,8,3,6,65,112,112,67,97,112,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,12,68,101,108,101,116,101,66,114,105,100,103,101,11,68,101,108,101,116,101,79,119,110,101,114,13,68,101,108,101,116,101,83,112,101,110,100,101,114,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,14,82,101,103,105,115,116,101,114,66,114,105,100,103,101,13,82,101,103,105,115,116,101,114,79,119,110,101,114,15,82,101,103,105,115,116,101,114,83,112,101,110,100,101,114,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,86,65,65,6,86,101,99,77,97,112,13,97,100,100,95,108,105,113,117,105,100,105,116,121,11,97,112,112,95,109,97,110,97,103,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,8,99,111,110,116,97,105,110,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,20,100,101,108,101,116,101,95,114,101,109,111,116,101,95,98,114,105,100,103,101,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,13,100,111,108,97,95,99,111,110,116,114,97,99,116,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,21,103,101,116,95,100,101,108,101,116,101,95,111,119,110,101,114,95,116,121,112,101,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,23,103,101,116,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,6,105,110,115,101,114,116,12,105,115,95,100,111,108,97,95,117,115,101,114,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,10,112,111,111,108,95,99,111,100,101,99,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,22,114,101,103,105,115,116,101,114,95,114,101,109,111,116,101,95,98,114,105,100,103,101,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,19,114,101,109,111,116,101,95,100,101,108,101,116,101,95,111,119,110,101,114,21,114,101,109,111,116,101,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,21,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,23,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,5,115,116,97,116,101,3,115,117,105,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,3,118,97,97,7,118,101,99,95,109,97,112,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,24,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,22,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,99,104,97,105,110,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,4,52,8,15,92,8,21,31,11,16,2,8,20,8,12,72,11,19,2,13,8,22,1,2,2,94,13,93,10,2,2,2,2,94,13,93,10,2,3,2,2,37,13,38,15,4,2,2,37,13,38,15,5,2,2,37,13,38,15,6,2,2,37,13,38,15,0,1,0,0,11,18,10,2,17,26,12,5,11,1,10,2,12,4,12,3,11,5,11,3,46,11,4,17,34,11,2,56,0,56,1,18,0,56,2,2,1,1,0,0,1,23,10,1,16,0,14,2,56,3,32,4,7,5,11,11,1,1,7,1,39,11,1,15,0,10,2,10,3,17,33,17,35,56,4,11,2,11,3,18,1,56,5,2,2,1,0,0,26,22,10,1,16,0,14,2,56,3,4,6,5,10,11,1,1,7,0,39,11,1,15,0,14,2,56,6,12,3,1,11,2,11,3,17,36,18,1,56,5,2,3,1,0,0,31,22,10,3,10,4,17,18,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,3,56,7,2,4,1,0,0,31,22,10,3,10,4,17,19,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,5,56,8,2,5,1,0,0,31,22,10,3,10,4,17,16,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,4,56,9,2,6,1,0,0,31,22,10,3,10,4,17,17,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,6,56,10,2,7,3,0,0,41,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,24,17,39,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,8,3,0,0,47,59,11,0,10,1,16,0,11,1,15,2,11,3,11,6,11,7,17,24,17,39,17,12,12,12,1,12,11,12,10,12,14,12,13,10,2,17,11,11,11,33,4,23,5,31,11,5,1,11,4,1,11,2,1,7,2,39,11,4,10,13,11,2,17,11,11,10,77,17,20,1,12,9,10,5,10,14,12,8,46,11,8,17,22,32,4,52,11,5,10,14,17,23,5,54,11,5,1,11,13,11,14,11,9,11,12,2,9,3,0,0,41,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,24,17,39,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,10,3,0,0,53,28,11,3,10,4,11,2,17,11,11,8,17,21,1,12,11,11,6,11,7,11,4,11,5,11,11,52,17,15,12,13,11,1,15,1,73,0,0,0,0,11,13,17,37,12,12,11,0,11,9,11,12,11,10,17,38,2,0,3,0,1,0,2,0,56,0,57,0,82,0],"wormhole_adapter_pool":[161,28,235,11,6,0,0,0,11,1,0,42,2,42,92,3,134,1,142,1,4,148,2,16,5,164,2,185,2,7,221,4,156,6,8,249,10,96,6,217,11,50,10,139,12,51,12,190,12,168,2,13,230,14,10,0,70,0,29,0,30,0,37,0,51,0,71,1,23,1,24,1,35,1,47,1,48,1,63,1,65,1,66,1,68,2,21,2,33,2,36,2,53,2,62,2,67,0,10,8,0,0,11,8,0,0,12,3,0,1,3,7,0,2,9,12,1,0,1,3,6,8,0,5,17,12,0,6,1,8,0,7,2,12,1,0,1,9,16,4,0,10,8,12,2,7,1,12,1,11,13,2,0,13,15,2,0,14,19,7,2,1,0,0,0,15,0,7,0,16,4,12,0,17,5,7,0,18,7,0,0,19,14,12,0,20,18,0,0,0,41,0,1,0,0,42,2,1,0,0,57,3,1,1,0,0,58,4,1,0,0,54,5,1,1,0,1,38,36,16,0,1,39,36,37,0,2,28,24,16,1,0,2,58,29,16,0,2,69,35,1,1,0,3,22,31,1,0,4,27,16,34,0,5,49,32,33,0,8,32,10,1,1,3,9,45,0,6,0,10,45,0,21,2,7,12,12,60,10,1,1,8,13,59,7,8,0,14,34,1,15,2,1,0,14,43,19,1,2,1,0,15,45,16,17,0,16,45,12,13,0,17,45,17,18,0,18,52,25,26,0,18,53,27,28,0,20,64,33,16,0,16,9,18,14,19,14,15,20,16,22,7,10,9,10,13,38,1,7,8,12,0,5,7,8,0,13,10,2,7,8,18,7,8,12,9,7,8,1,7,8,18,11,8,1,8,11,7,11,4,1,9,0,11,8,1,9,0,13,10,2,6,8,7,7,8,12,7,7,8,1,7,8,18,11,8,1,8,11,13,10,2,6,8,7,7,8,12,7,6,8,5,7,8,18,7,8,1,7,11,4,1,9,0,10,2,6,8,7,7,8,12,1,8,9,1,6,8,12,1,5,1,8,0,1,9,0,3,7,8,12,11,13,2,13,8,16,8,15,2,6,8,18,7,8,12,1,8,15,2,13,8,16,1,11,13,2,9,0,9,1,1,10,2,1,8,14,1,8,16,3,7,11,13,2,9,0,9,1,9,0,9,1,2,8,14,8,6,1,11,10,2,9,0,9,1,1,8,1,2,8,17,10,2,5,7,11,4,1,9,0,11,8,1,9,0,13,10,2,7,8,12,3,7,8,15,14,10,2,1,8,17,4,7,8,18,11,8,1,8,11,8,17,6,8,7,1,3,3,13,10,2,7,8,12,5,3,3,8,3,8,3,13,1,6,8,5,6,7,8,18,6,11,13,2,13,8,16,7,11,10,2,8,14,8,6,10,2,6,8,7,7,8,12,1,8,19,6,13,3,8,3,8,3,3,2,5,7,11,4,1,9,0,8,3,3,8,3,7,8,12,1,6,8,3,1,13,1,8,2,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,4,80,111,111,108,11,80,111,111,108,71,101,110,101,115,105,115,9,80,111,111,108,83,116,97,116,101,17,80,111,111,108,87,105,116,104,100,114,97,119,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,6,97,109,111,117,110,116,7,98,121,116,101,115,51,50,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,7,99,114,101,97,116,111,114,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,12,100,115,116,95,99,104,97,105,110,95,105,100,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,4,105,110,105,116,10,105,110,105,116,105,97,108,105,122,101,6,105,110,115,101,114,116,7,105,115,95,105,110,105,116,3,110,101,119,5,110,111,110,99,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,12,112,111,111,108,95,97,100,100,114,101,115,115,10,112,111,111,108,95,99,111,100,101,99,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,12,115,101,110,100,95,100,101,112,111,115,105,116,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,3,115,117,105,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,40,8,9,26,5,44,1,1,2,4,40,8,9,72,8,15,25,11,10,2,8,14,8,6,56,11,13,2,13,8,16,2,2,6,46,3,61,13,31,13,50,10,2,55,10,2,20,3,0,0,0,0,1,9,10,0,17,14,11,0,46,17,17,9,18,0,56,0,2,1,1,4,0,11,59,10,0,16,0,20,10,4,46,17,17,33,4,9,5,17,11,3,1,11,0,1,11,4,1,7,2,39,10,0,16,1,20,32,4,23,5,31,11,3,1,11,0,1,11,4,1,7,3,39,11,3,10,4,12,5,46,11,5,17,21,12,7,56,1,12,6,13,6,11,1,11,2,17,20,17,22,56,2,10,4,17,14,11,7,11,4,56,3,11,6,18,1,56,4,8,11,0,15,1,21,2,2,3,0,0,23,20,11,3,11,4,11,5,11,6,11,8,56,5,12,10,11,0,15,2,73,0,0,0,0,11,10,17,23,12,9,11,1,11,2,11,9,11,7,17,24,1,2,3,3,0,0,23,18,11,3,11,4,11,6,17,8,12,8,11,0,15,2,73,0,0,0,0,11,8,17,23,12,7,11,1,11,2,11,7,11,5,17,24,1,2,4,1,4,0,30,37,11,0,17,10,11,1,10,2,16,3,11,2,15,4,11,4,11,5,10,6,17,12,17,25,17,11,1,12,7,12,10,12,9,12,8,12,11,11,3,10,10,10,7,10,9,11,6,56,6,11,8,11,11,14,9,17,6,14,9,17,5,14,10,17,5,11,7,18,2,56,7,2,0,1,0,2,1,1,1,3,1,2,0],"wormhole_adapter_verify":[161,28,235,11,6,0,0,0,10,1,0,22,2,22,54,3,76,102,4,178,1,16,5,194,1,206,1,7,144,3,135,3,8,151,6,128,1,6,151,7,30,10,181,7,6,12,187,7,205,1,0,38,1,29,2,14,2,27,2,28,2,35,2,37,3,13,3,19,3,34,3,36,0,8,12,0,1,4,7,1,0,0,2,1,8,0,3,7,4,0,4,3,12,2,7,1,12,1,5,6,2,0,6,10,7,2,1,0,0,0,7,0,7,0,8,2,7,0,9,5,12,0,10,9,0,0,0,22,0,1,0,0,12,2,3,0,0,30,4,5,0,0,32,6,3,0,0,31,7,5,0,1,20,19,13,1,0,1,24,18,10,1,0,1,26,3,14,1,0,1,33,13,14,1,0,3,25,25,26,0,4,11,27,3,2,7,12,4,15,24,10,2,7,12,6,15,9,10,2,1,0,6,21,9,11,2,1,0,10,16,16,22,0,10,17,16,12,0,10,18,16,17,0,10,30,21,5,0,12,8,13,8,8,12,7,12,6,12,5,12,11,23,10,23,2,6,11,6,2,13,8,8,6,13,1,11,1,1,8,8,2,6,11,6,2,13,8,8,6,8,10,0,4,7,8,9,6,11,6,2,13,8,8,10,2,6,8,2,1,8,10,3,7,11,4,2,8,7,8,0,6,8,10,7,8,5,6,7,8,9,6,11,6,2,13,8,8,7,11,4,2,8,7,8,0,10,2,6,8,2,7,8,5,2,13,8,8,2,6,11,6,2,9,0,9,1,6,9,0,1,1,1,6,9,1,1,8,8,1,9,0,1,11,1,1,9,0,2,11,1,1,8,8,13,1,6,8,10,1,13,1,6,11,1,1,9,0,1,7,11,1,1,9,0,3,10,2,6,8,2,8,10,3,6,8,9,10,2,6,8,2,1,8,7,2,8,7,8,0,2,6,11,4,2,9,0,9,1,9,0,1,7,8,5,1,8,3,3,7,11,4,2,9,0,9,1,9,0,9,1,7,66,121,116,101,115,51,50,5,67,108,111,99,107,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,3,97,100,100,20,97,115,115,101,114,116,95,107,110,111,119,110,95,101,109,105,116,116,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,6,100,105,103,101,115,116,15,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,13,101,109,105,116,116,101,114,95,99,104,97,105,110,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,101,120,116,114,97,99,116,3,103,101,116,22,103,101,116,95,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,2,105,100,7,105,115,95,115,111,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,14,114,101,112,108,97,121,95,112,114,111,116,101,99,116,4,115,111,109,101,5,115,116,97,116,101,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,1,23,8,3,0,1,0,0,1,19,10,0,10,1,56,0,4,11,11,0,11,1,56,1,20,56,2,12,2,5,17,11,1,1,11,0,1,56,3,12,2,11,2,2,1,1,0,0,15,25,10,1,17,16,12,3,11,0,14,3,17,0,12,2,14,2,56,4,4,11,5,15,11,1,1,7,0,39,13,2,56,5,11,1,17,15,33,4,22,5,24,7,1,39,2,2,1,0,0,20,15,11,0,11,2,11,3,12,5,12,4,46,11,4,11,5,17,17,12,6,11,1,14,6,17,1,11,6,2,3,1,0,0,22,26,10,0,10,1,17,14,12,3,46,11,3,56,6,32,4,10,5,18,11,1,1,11,2,1,11,0,1,7,2,39,11,0,11,1,17,14,11,2,17,9,18,0,56,7,2,4,1,0,0,5,12,11,0,11,1,11,3,11,4,17,2,12,6,11,2,14,6,11,5,17,3,11,6,2,0]},"type_origin_table":[{"module_name":"dola_address","struct_name":"DolaAddress","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"Pool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"DepositPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"WithdrawPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_verify","struct_name":"Unit","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceManagerCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version_1_0_0","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"app_manager","struct_name":"TotalAppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"app_manager","struct_name":"AppCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"UserInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ReserveData","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ScaledBalance","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"BorrowRateFactors","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"PriceOracle","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"Price","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"Liquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AddLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"RemoveLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_logic","struct_name":"LendingCoreExecuteEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserAddressCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"BindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UnbindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"CoreState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"LendingCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_wormhole_adapter","struct_name":"SystemCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolWithdrawEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":1},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":5},"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302":{"upgraded_id":"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302","upgraded_version":1},"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a":{"upgraded_id":"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a","upgraded_version":1}}}},"owner":"Immutable","previous_transaction":"BPLPMMmGBp3vAM6v31MEKfQLcUzKmgin9gBefQsnbg4m","storage_rebate":548454000},{"data":{"Package":{"id":"0xc5b2a5049cd71586362d0c6a38e34cfaae7ea9ce6d5401a350506a15f817bf72","version":2,"module_map":{"app_manager":[161,28,235,11,6,0,0,0,10,1,0,10,2,10,24,3,34,46,4,80,2,5,82,54,7,136,1,228,1,8,236,2,64,10,172,3,18,12,190,3,106,13,168,4,4,0,8,0,11,1,16,1,20,1,21,0,3,12,0,0,0,12,0,1,1,0,0,2,2,7,0,2,5,4,0,4,4,2,0,0,14,0,1,0,0,17,2,3,0,0,18,4,3,0,0,12,5,6,0,0,10,3,1,0,2,9,7,1,0,2,15,0,7,0,2,22,12,8,0,3,19,10,1,1,8,8,9,1,7,8,5,0,2,7,8,0,7,8,5,1,8,1,3,6,8,2,7,8,0,7,8,5,1,6,8,1,1,13,1,8,4,1,8,3,1,8,0,1,9,0,3,8,1,8,3,8,4,1,6,8,4,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,2,73,68,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,97,112,112,95,99,97,112,115,6,97,112,112,95,105,100,11,97,112,112,95,109,97,110,97,103,101,114,6,100,101,108,101,116,101,15,100,101,115,116,114,111,121,95,97,112,112,95,99,97,112,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,2,105,100,4,105,110,105,116,3,110,101,119,6,111,98,106,101,99,116,12,114,101,103,105,115,116,101,114,95,97,112,112,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,8,4,6,10,8,3,1,2,2,13,8,4,7,13,0,0,0,0,1,6,11,0,17,6,64,8,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,11,19,11,1,17,6,12,4,14,4,17,7,12,3,11,4,10,0,16,0,65,8,75,18,1,12,2,11,0,15,0,11,3,68,8,11,2,2,2,1,0,0,1,4,11,1,11,2,17,1,2,3,1,0,0,1,4,11,0,16,1,20,2,4,1,0,0,1,5,11,0,19,1,1,17,5,2,0,1,1,1,0],"dola_address":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,12,3,24,109,4,133,1,6,5,139,1,78,7,217,1,191,3,8,152,5,96,6,248,5,14,10,134,6,8,12,142,6,151,2,13,165,8,4,0,13,0,23,1,4,1,27,2,3,2,5,0,0,7,0,2,1,7,0,3,2,7,0,0,20,0,1,0,0,19,2,1,0,0,18,2,3,0,0,29,4,5,0,0,28,6,5,0,0,10,7,5,0,0,6,8,5,0,0,7,5,8,0,0,9,0,5,1,0,0,8,5,3,0,0,15,5,3,0,0,11,3,5,0,1,12,19,1,0,1,24,14,0,0,1,25,15,0,0,1,30,17,18,1,1,2,21,13,3,0,3,17,0,12,1,0,3,22,12,13,0,4,16,3,8,0,5,26,9,3,1,0,20,8,17,11,15,10,0,1,13,1,6,8,0,1,10,2,2,8,0,13,1,8,0,2,8,0,10,2,2,13,10,2,1,5,1,6,9,0,1,2,1,9,0,1,8,2,1,8,1,2,7,10,2,13,2,7,10,2,10,2,6,10,2,3,10,2,13,3,3,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,11,68,111,108,97,65,100,100,114,101,115,115,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,112,111,111,108,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,19,117,112,100,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,13,2,0,0,0,2,2,14,13,13,10,2,0,1,0,0,0,2,7,1,2,1,1,0,0,0,4,11,0,16,0,20,2,2,1,0,0,0,4,11,0,16,1,20,2,3,1,0,0,0,6,11,1,13,0,15,0,21,11,0,2,4,1,0,0,0,6,11,1,13,0,15,1,21,11,0,2,5,1,0,0,0,4,11,0,11,1,18,0,2,6,1,0,0,0,5,7,1,14,0,56,0,18,0,2,7,1,0,0,0,14,14,0,16,1,65,10,6,32,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,14,0,16,1,20,17,19,2,8,1,0,0,3,8,56,1,17,18,17,16,12,0,7,1,11,0,18,0,2,9,1,0,0,0,4,14,0,16,1,20,2,10,1,0,0,3,14,64,10,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,17,13,13,1,14,0,16,1,20,17,14,11,1,2,11,1,0,0,16,30,14,0,65,10,12,6,6,0,0,0,0,0,0,0,0,12,5,6,2,0,0,0,0,0,0,0,12,2,14,0,10,5,10,5,10,2,22,56,2,12,1,14,1,17,12,12,4,11,5,11,2,22,12,5,14,0,11,5,11,6,56,2,12,3,11,4,11,3,18,0,2,0,0,0,1,0],"dola_pool":[161,28,235,11,6,0,0,0,14,1,0,22,2,22,52,3,74,173,1,4,247,1,32,5,151,2,211,1,7,234,3,168,5,8,146,9,96,6,242,9,50,10,164,10,34,11,198,10,2,12,200,10,222,2,13,166,13,4,14,170,13,4,15,174,13,4,0,23,0,22,0,45,1,12,1,54,2,13,2,14,2,27,2,43,2,52,2,53,0,5,12,1,0,1,0,3,3,0,0,10,3,0,1,4,7,0,3,6,7,0,4,8,7,0,5,0,4,1,0,1,6,1,12,1,0,1,6,2,12,1,0,1,8,9,4,0,10,7,2,0,0,30,0,1,1,0,0,19,2,3,1,0,0,16,4,5,0,0,42,6,5,1,0,0,55,6,5,1,0,0,21,7,8,1,0,0,57,9,3,1,0,0,48,10,8,0,1,15,19,21,0,1,17,21,19,0,1,18,3,21,1,0,1,32,30,8,0,1,33,30,29,0,1,34,3,29,0,2,25,22,8,0,2,26,35,8,0,3,37,26,8,0,4,29,3,25,1,0,4,38,25,26,0,5,39,24,5,1,0,5,51,31,15,1,0,5,59,3,15,1,0,6,28,32,23,1,0,6,31,12,1,1,0,6,36,23,15,1,0,6,56,20,5,1,0,7,24,11,3,1,3,8,41,13,14,0,9,46,34,3,1,12,9,50,11,3,1,8,10,49,18,19,0,23,11,21,11,29,16,0,11,25,11,3,11,10,11,24,11,19,11,17,11,26,27,4,11,20,11,22,11,26,33,28,23,1,6,11,0,1,9,0,1,2,2,6,11,8,1,9,0,7,8,10,0,3,3,2,2,1,3,2,6,11,0,1,9,0,3,5,7,11,0,1,9,0,11,7,1,9,0,13,10,2,7,8,10,1,10,2,5,7,11,0,1,9,0,8,3,3,8,3,7,8,10,3,13,10,2,7,8,10,1,9,0,1,6,11,8,1,9,0,1,7,8,10,1,8,9,1,11,6,1,9,0,1,11,0,1,9,0,6,3,3,3,10,2,5,8,3,1,6,8,10,1,5,1,6,11,7,1,9,0,1,8,3,5,8,3,8,3,3,13,10,2,1,11,7,1,9,0,2,7,11,6,1,9,0,11,6,1,9,0,1,8,5,1,8,4,1,8,1,3,3,11,7,1,9,0,5,1,13,1,6,8,3,2,7,11,6,1,9,0,3,2,11,6,1,9,0,7,8,10,1,8,2,2,9,0,5,3,8,3,13,10,2,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,11,68,101,112,111,115,105,116,80,111,111,108,11,68,111,108,97,65,100,100,114,101,115,115,4,80,111,111,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,12,87,105,116,104,100,114,97,119,80,111,111,108,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,11,99,114,101,97,116,101,95,112,111,111,108,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,4,101,109,105,116,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,12,103,101,116,95,100,101,99,105,109,97,108,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,12,105,110,116,111,95,98,97,108,97,110,99,101,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,10,112,111,111,108,95,99,111,100,101,99,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,35,8,9,13,11,6,1,9,0,20,2,1,2,3,44,8,4,49,5,11,3,2,2,3,44,8,4,47,5,11,3,0,11,0,1,0,0,3,4,11,0,55,0,20,2,1,1,0,0,1,10,11,0,56,0,12,2,11,1,17,27,56,1,11,2,57,0,56,2,2,2,1,0,0,3,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,3,1,0,0,1,8,11,0,56,3,12,2,11,1,11,2,49,8,17,2,2,4,1,0,0,1,8,11,0,56,3,12,2,11,1,49,8,11,2,17,2,2,5,3,0,0,17,38,11,4,46,17,30,12,9,14,1,56,4,12,7,10,0,10,7,12,5,46,11,5,56,5,12,6,10,9,17,8,12,10,56,6,11,10,11,6,11,2,11,3,17,14,12,8,11,0,54,1,11,1,56,7,56,8,1,56,9,17,18,11,9,11,7,18,1,56,10,11,8,2,6,3,0,0,28,53,17,13,14,3,17,12,33,4,6,5,12,11,0,1,11,4,1,7,4,39,14,3,17,11,56,9,17,18,17,16,33,4,20,5,26,11,0,1,11,4,1,7,0,39,11,1,17,9,12,7,10,0,11,2,12,5,46,11,5,56,11,12,2,11,0,54,1,10,2,56,12,11,4,56,13,12,6,56,9,17,18,10,7,11,2,18,2,56,14,11,6,11,7,56,15,2,7,3,0,0,3,8,11,2,46,17,30,17,8,11,0,11,1,17,15,2,0,2,0,1,0,11,1,11,0,40,0,58,0],"equilibrium_fee":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,50,5,54,29,7,83,174,1,8,129,2,32,12,161,2,197,5,0,4,0,10,0,2,0,1,0,0,3,2,1,0,0,0,3,1,0,0,1,3,1,0,1,5,0,1,0,1,6,4,1,0,1,7,0,1,0,1,8,4,1,0,1,9,1,1,0,1,11,0,1,0,2,15,15,1,15,3,15,15,15,6,15,15,15,15,15,15,0,4,1,15,15,15,6,1,15,15,15,15,15,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,27,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,112,101,114,99,101,110,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,1,13,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,11,11,1,11,0,17,6,12,2,11,2,2,1,1,0,0,1,17,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,15,11,0,11,1,17,6,11,2,17,6,17,5,17,4,12,3,11,3,2,2,1,0,0,5,93,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,1,10,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,2,23,10,0,10,2,23,10,3,17,1,10,4,36,4,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,10,4,36,4,50,10,1,10,0,10,4,17,9,10,3,17,9,23,17,5,10,4,10,3,17,9,23,17,6,12,7,5,52,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,12,9,10,2,10,9,23,10,5,17,5,10,4,10,3,17,9,23,17,9,24,10,4,10,3,17,9,26,12,8,10,0,11,1,23,11,5,17,7,17,9,24,10,0,11,9,23,11,0,11,2,23,17,6,17,8,17,9,11,4,11,3,17,9,26,11,8,23,2,3,1,0,0,6,51,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,12,7,11,1,10,2,22,11,0,10,2,22,11,3,17,1,11,7,23,12,9,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,4,11,5,17,6,24,12,11,11,2,11,11,17,6,17,5,17,4,12,10,11,9,11,10,17,4,12,8,11,4,11,8,17,9,2,0],"genesis":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,56,3,74,128,1,4,202,1,22,5,224,1,175,1,7,143,3,130,4,8,145,7,96,6,241,7,61,10,174,8,39,12,213,8,147,2,13,232,10,6,15,238,10,2,0,26,1,15,1,44,1,46,2,24,2,38,2,39,2,42,2,43,0,0,0,0,0,2,12,0,0,1,8,0,0,11,7,0,0,12,7,0,0,13,7,0,1,4,7,0,2,6,7,0,5,3,7,0,5,7,4,0,6,8,12,0,6,9,0,0,6,10,0,0,8,5,2,0,0,29,0,1,0,0,17,2,0,0,0,33,3,4,0,0,16,5,6,0,0,18,7,0,0,0,36,8,0,2,6,6,0,19,9,10,0,0,21,10,0,0,0,22,11,0,0,1,34,31,32,0,2,27,0,26,1,0,2,28,30,31,0,3,32,35,36,1,0,3,40,37,23,1,0,4,14,20,0,2,7,4,4,25,13,14,2,7,4,4,40,28,29,2,7,4,5,20,17,0,0,5,31,21,18,1,8,5,37,16,17,0,6,16,24,6,0,6,18,25,0,0,7,41,23,0,1,8,15,12,14,19,18,4,22,22,15,27,16,27,10,29,10,23,14,33,12,18,13,18,0,1,8,5,1,6,8,2,2,8,10,7,8,13,1,8,1,4,6,8,0,7,8,2,2,10,2,1,8,12,2,7,8,2,8,11,3,6,8,0,7,8,2,9,1,1,6,8,1,1,8,0,2,7,8,2,8,1,2,8,3,8,5,2,6,8,9,9,0,1,1,2,8,2,8,1,1,7,8,13,1,8,9,1,8,8,2,8,3,8,4,3,7,8,9,9,0,9,1,1,6,9,0,1,8,2,1,9,0,3,7,8,10,2,10,2,2,7,8,10,8,11,1,8,7,2,8,3,9,0,2,7,8,9,9,0,1,9,1,1,6,8,7,1,8,6,1,10,2,2,8,3,9,1,2,3,8,8,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,7,86,101,114,115,105,111,110,13,86,101,114,115,105,111,110,95,49,95,48,95,48,13,86,101,114,115,105,111,110,95,49,95,48,95,49,3,97,100,100,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,15,100,101,115,116,114,111,121,95,109,97,110,97,103,101,114,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,7,103,101,110,101,115,105,115,3,103,101,116,10,103,101,116,95,109,111,100,117,108,101,17,103,101,116,95,118,101,114,115,105,111,110,95,49,95,48,95,49,13,103,111,118,101,114,110,97,110,99,101,95,118,49,2,105,100,8,105,110,100,101,120,95,111,102,12,105,110,105,116,95,103,101,110,101,115,105,115,10,105,110,116,111,95,98,121,116,101,115,11,109,97,110,97,103,101,114,95,105,100,115,15,109,105,103,114,97,116,101,95,118,101,114,115,105,111,110,3,110,101,119,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,11,117,112,103,114,97,100,101,95,99,97,112,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,10,2,8,7,103,101,110,101,115,105,115,0,2,1,23,1,1,2,1,31,8,9,2,2,3,31,8,9,45,8,10,35,10,8,8,3,2,1,23,1,4,2,1,23,1,5,2,1,23,1,0,1,0,0,0,3,9,18,5,2,1,1,0,0,0,10,11,0,16,0,9,18,3,56,0,4,7,5,9,7,4,39,2,2,3,0,0,15,26,10,1,17,19,11,0,64,18,0,0,0,0,0,0,0,0,18,2,12,2,11,1,17,19,18,1,12,3,13,2,15,0,9,18,3,9,18,4,56,1,13,2,15,1,14,3,56,2,68,18,11,2,56,3,11,3,2,3,1,0,0,0,6,11,1,15,2,11,2,11,3,17,20,2,4,1,0,0,0,5,11,0,15,2,11,1,17,21,2,5,1,0,0,26,47,10,1,15,0,46,9,18,3,56,4,4,8,5,12,11,1,1,7,1,39,10,1,15,0,9,18,3,56,5,1,56,6,12,3,10,3,56,7,34,4,25,5,29,11,1,1,7,2,39,14,3,17,11,17,9,7,5,33,4,36,5,40,11,1,1,7,3,39,11,1,15,0,9,18,3,11,2,56,8,2,6,1,0,0,0,3,9,18,0,2,7,1,0,0,0,4,11,0,19,0,1,2,8,1,0,0,34,18,14,1,56,2,12,3,10,0,16,1,14,3,56,9,12,2,1,11,0,15,1,11,2,56,10,1,11,1,19,1,17,17,2,2,0,2,2,2,1,0,30,0],"governance_v1":[161,28,235,11,6,0,0,0,13,1,0,22,2,22,56,3,78,198,1,4,148,2,40,5,188,2,148,2,7,208,4,155,6,8,235,10,96,6,203,11,207,1,10,154,13,72,11,226,13,2,12,228,13,215,9,13,187,23,28,14,215,23,14,0,43,0,38,1,18,1,57,1,71,1,75,2,33,2,56,2,58,2,69,2,70,0,3,8,0,0,7,8,1,6,0,0,1,3,0,0,0,3,0,1,2,0,0,1,4,12,0,2,8,7,0,3,6,7,1,0,0,4,10,7,0,7,5,7,0,7,11,4,0,8,12,12,0,10,9,2,0,0,47,0,1,0,0,13,2,1,0,0,74,3,4,0,0,15,5,1,0,0,62,5,1,0,0,73,6,1,0,0,22,7,1,0,0,31,8,9,0,0,41,10,11,1,6,0,28,12,1,0,0,25,13,1,1,6,0,76,14,15,1,6,0,20,10,1,1,6,1,24,47,12,0,1,27,12,1,0,1,48,25,4,0,2,68,35,11,0,3,19,46,44,1,0,3,35,27,23,1,0,3,37,26,1,1,0,3,49,46,9,1,0,3,50,46,9,1,0,3,55,1,20,1,0,3,65,23,20,1,0,4,39,1,39,1,0,4,40,40,11,0,5,23,29,9,1,0,5,46,29,31,1,0,5,61,32,23,1,0,6,29,23,1,1,3,7,45,44,21,1,8,7,53,0,19,0,7,72,37,38,0,9,64,23,1,1,8,10,32,18,34,0,10,63,18,17,0,22,4,33,22,19,4,18,4,26,17,27,17,28,17,22,34,23,34,24,23,33,41,29,42,30,41,29,45,20,34,17,34,17,4,23,12,21,34,22,12,1,7,8,12,0,3,8,11,7,8,0,7,8,12,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,1,9,0,7,8,12,1,8,6,1,8,4,3,6,8,0,9,0,7,8,12,5,6,8,0,9,0,7,11,1,1,9,0,1,7,8,12,1,11,7,1,8,4,1,10,5,1,5,1,6,8,12,1,8,10,1,11,7,1,9,0,1,8,9,1,8,0,1,9,0,2,5,1,2,8,11,7,8,12,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,1,10,2,12,8,8,3,11,7,1,3,3,5,8,10,5,11,7,1,3,3,8,10,8,9,3,1,6,8,10,1,6,8,9,1,8,8,1,6,8,8,1,11,1,1,9,0,1,8,2,11,1,6,5,6,5,1,1,7,10,5,3,7,10,5,3,3,5,1,6,9,0,1,8,3,1,6,11,7,1,9,0,1,6,8,5,11,67,104,97,110,103,101,83,116,97,116,101,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,10,97,100,100,95,109,101,109,98,101,114,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,12,99,104,101,99,107,95,109,101,109,98,101,114,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,49,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,103,101,110,101,115,105,115,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,9,109,97,120,95,100,101,108,97,121,7,109,101,109,98,101,114,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,6,114,101,109,111,118,101,13,114,101,109,111,118,101,95,109,101,109,98,101,114,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,7,117,112,103,114,97,100,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,8,45,8,10,42,11,7,1,8,5,14,1,17,3,77,3,51,3,52,10,5,44,10,8,9,1,2,10,45,8,10,26,5,66,3,30,11,7,1,3,34,3,59,8,6,21,9,0,36,10,5,16,10,5,67,2,2,2,1,60,8,9,3,2,2,60,8,9,54,2,1,23,0,0,0,0,16,19,64,17,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,35,68,17,11,0,17,31,56,0,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,11,1,64,21,0,0,0,0,0,0,0,0,18,0,56,1,2,1,1,4,0,24,42,10,1,10,2,46,17,35,12,3,46,11,3,17,6,10,1,16,0,20,32,4,20,10,1,16,1,65,21,6,0,0,0,0,0,0,0,0,33,12,4,5,22,9,12,4,11,4,4,25,5,31,11,1,1,11,2,1,7,5,39,10,1,15,2,11,0,11,2,17,15,56,2,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,2,56,3,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,28,19,10,1,15,3,14,2,12,3,46,11,3,56,4,32,4,10,5,14,11,1,1,7,9,39,11,1,15,3,11,2,68,17,2,4,1,0,0,30,21,10,1,10,2,12,3,46,11,3,17,6,10,1,15,3,14,2,12,4,46,11,4,56,5,12,5,1,11,1,15,3,11,5,56,6,1,2,5,1,0,0,1,24,10,4,10,3,10,2,22,36,4,7,5,11,11,1,1,7,7,39,11,2,10,1,15,4,21,11,3,10,1,15,5,21,11,4,11,1,15,6,21,2,6,1,0,0,1,9,11,0,16,3,14,1,56,4,4,6,5,8,7,8,39,2,7,1,0,0,8,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,8,1,0,0,33,75,11,1,46,17,34,12,7,10,0,55,0,20,7,2,33,4,16,11,0,1,7,16,17,16,12,6,5,73,10,0,55,0,20,7,3,33,4,28,11,0,1,7,17,17,16,12,5,5,71,10,0,55,0,20,7,4,33,4,40,11,0,1,7,18,17,16,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,19,17,16,12,3,5,67,11,0,55,0,20,7,0,33,4,62,7,20,17,16,12,2,5,65,7,21,17,16,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,9,1,0,0,1,3,11,0,17,14,2,10,1,0,0,36,86,10,0,16,0,20,4,5,5,11,11,0,1,11,2,1,7,6,39,10,2,46,17,35,12,9,10,0,10,9,17,6,10,2,46,17,34,10,0,16,4,20,22,12,14,10,0,16,5,20,6,0,0,0,0,0,0,0,0,33,4,35,56,7,12,10,5,42,10,14,10,0,16,5,20,22,56,8,12,10,10,2,46,17,34,11,0,16,6,20,22,12,11,11,2,17,31,12,12,14,12,17,32,20,12,13,11,12,12,8,11,9,12,7,11,14,12,6,11,10,12,5,11,11,12,4,56,9,12,3,11,8,11,7,11,6,11,5,11,4,14,3,17,25,11,1,64,17,0,0,0,0,0,0,0,0,64,17,0,0,0,0,0,0,0,0,7,0,57,0,56,10,11,13,18,2,56,11,2,11,1,0,0,43,213,1,10,4,46,17,34,12,11,10,11,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,4,1,7,11,39,10,11,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,4,1,7,14,39,10,2,55,0,20,7,0,33,4,50,7,1,10,2,54,0,21,10,2,46,56,12,7,1,18,3,56,13,10,2,55,0,20,7,1,33,4,57,5,65,11,2,1,11,0,1,11,4,1,7,13,39,11,4,46,17,35,12,15,10,0,10,15,17,6,10,2,54,3,12,12,10,2,54,4,12,10,10,2,55,5,56,14,4,85,8,12,5,5,92,10,11,10,2,55,5,56,15,20,35,12,5,11,5,4,138,1,10,12,14,15,12,6,46,11,6,56,4,32,4,111,10,10,14,15,12,7,46,11,7,56,4,32,12,8,5,113,9,12,8,11,8,4,116,5,126,11,2,1,11,0,1,11,12,1,11,10,1,7,10,39,11,3,4,134,1,11,10,1,10,12,11,15,68,17,5,137,1,11,10,11,15,68,17,5,140,1,11,10,1,10,2,55,5,56,14,4,147,1,8,12,9,5,154,1,11,11,10,2,55,5,56,15,20,38,12,9,11,9,4,205,1,10,0,16,3,65,17,12,14,11,12,46,65,17,12,13,11,14,11,13,17,7,4,184,1,7,2,10,2,54,0,21,11,2,46,56,12,7,2,18,3,56,13,11,0,16,2,56,16,17,13,56,17,2,11,0,1,10,2,55,5,56,18,4,201,1,7,3,10,2,54,0,21,11,2,46,56,12,7,3,18,3,56,13,5,203,1,11,2,1,56,19,2,11,2,1,11,0,1,11,12,1,56,19,2,12,1,4,0,1,45,10,1,46,17,34,10,0,55,1,20,35,4,21,10,0,55,0,20,7,0,33,4,15,5,21,11,0,1,11,1,1,7,12,39,11,1,46,17,35,10,0,55,6,20,33,4,30,5,34,11,0,1,7,15,39,7,4,10,0,54,0,21,11,0,46,56,12,7,4,18,3,56,13,2,0,2,0,7,0,1,0,6,0,3,0,4,0,5,1,9,1,4,1,2,1,7,1,8,1,3,1,1,7,23,8,23,9,23,10,23,11,23,12,23,13,23,0],"governance_v2":[161,28,235,11,6,0,0,0,13,1,0,28,2,28,74,3,102,145,2,4,247,2,58,5,177,3,229,3,7,150,7,131,8,8,153,15,96,6,249,15,129,2,10,250,17,95,11,217,18,2,12,219,18,171,13,13,134,32,38,14,172,32,18,0,54,0,48,0,64,1,22,1,69,1,87,1,93,2,23,2,29,2,41,2,68,2,84,2,85,2,86,0,5,8,0,0,9,8,2,6,0,0,1,0,3,3,0,0,1,3,0,1,4,0,0,1,6,12,0,3,10,7,0,4,8,7,1,0,0,5,13,7,0,7,0,4,1,0,1,8,2,12,1,0,1,10,7,7,0,10,14,4,0,11,11,12,2,7,1,4,1,13,12,2,0,0,59,0,1,0,0,15,2,1,0,0,91,3,4,0,0,18,5,1,0,0,75,5,1,0,0,90,6,1,0,0,89,7,1,0,0,27,8,1,0,0,39,9,10,0,0,51,11,12,2,6,0,0,35,13,1,0,0,32,14,1,2,6,0,0,94,15,16,2,6,0,0,25,17,1,2,6,0,0,28,11,1,2,6,0,1,31,59,13,0,1,34,13,1,0,2,63,40,41,1,0,3,83,37,12,0,4,24,58,52,1,0,4,43,28,26,1,0,4,46,27,1,1,0,4,67,1,22,1,0,4,78,26,22,1,0,5,49,1,23,1,0,5,50,47,12,0,6,30,30,10,1,0,6,58,30,32,1,0,6,74,33,26,1,0,7,61,54,35,1,0,7,79,61,48,1,0,7,92,57,35,1,0,8,36,41,1,1,0,8,47,62,41,1,0,8,60,41,48,1,0,9,37,26,1,1,3,10,57,52,24,1,8,10,65,0,21,0,10,88,45,46,0,11,17,44,1,2,7,4,11,30,55,10,2,7,4,11,65,0,43,2,7,4,11,74,56,39,2,7,4,12,73,64,1,1,12,12,77,26,1,1,8,13,40,20,35,0,13,76,20,19,0,22,4,22,23,44,25,21,23,21,4,20,4,26,19,27,19,28,19,17,39,41,42,39,42,24,26,34,39,44,49,35,50,36,49,35,53,29,39,40,42,42,42,31,39,22,13,32,39,19,4,23,13,30,39,33,39,43,63,1,7,8,14,0,4,6,8,4,7,8,0,8,8,8,5,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,4,6,8,4,7,8,0,3,3,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,2,9,0,9,1,7,8,14,1,8,6,1,8,4,5,6,8,0,9,0,10,11,10,1,9,1,3,7,8,14,7,6,8,0,9,0,7,11,1,2,9,0,9,1,10,11,10,1,9,1,3,1,7,8,14,1,11,7,1,8,4,3,6,8,0,7,11,1,2,9,0,9,1,7,8,14,1,10,5,1,5,1,6,8,14,1,8,12,1,11,7,1,9,0,1,8,8,1,8,11,1,8,0,1,9,0,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,2,9,0,9,1,1,10,2,15,8,8,3,3,3,5,8,12,5,3,3,3,11,13,2,5,3,8,12,8,11,11,10,1,9,1,3,1,9,1,3,10,11,10,1,9,0,3,7,8,14,1,11,10,1,9,0,2,5,3,1,11,13,2,9,0,9,1,3,7,11,13,2,9,0,9,1,9,0,9,1,1,6,8,12,1,6,8,11,1,6,8,8,1,11,9,1,9,0,1,11,1,2,9,0,9,1,1,8,2,17,11,7,1,8,4,11,7,1,8,4,5,5,5,5,1,3,3,7,11,13,2,5,3,3,3,3,7,11,13,2,5,3,11,10,1,9,1,5,3,1,6,9,0,1,8,3,2,7,11,9,1,9,0,11,9,1,9,0,2,6,11,13,2,9,0,9,1,9,0,2,7,11,13,2,9,0,9,1,9,0,1,6,11,9,1,9,0,1,6,11,7,1,9,0,1,6,8,5,11,1,1,1,5,5,7,11,13,2,5,3,3,7,11,13,2,5,3,5,3,3,2,7,11,9,1,9,0,3,2,11,9,1,9,0,7,8,14,1,11,10,1,9,1,2,9,0,5,7,66,97,108,97,110,99,101,11,67,104,97,110,103,101,83,116,97,116,101,4,67,111,105,110,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,3,97,100,100,13,97,100,100,95,103,117,97,114,100,105,97,110,115,11,97,103,97,105,110,115,116,95,110,117,109,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,15,99,104,101,99,107,95,103,117,97,114,100,105,97,110,115,5,99,108,97,105,109,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,9,102,97,118,111,114,95,110,117,109,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,20,103,111,118,101,114,110,97,110,99,101,95,99,111,105,110,95,116,121,112,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,50,9,103,117,97,114,100,105,97,110,115,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,4,106,111,105,110,9,109,97,120,95,100,101,108,97,121,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,24,112,114,111,112,111,115,97,108,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,103,117,97,114,100,105,97,110,115,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,115,112,108,105,116,11,115,116,97,107,101,100,95,99,111,105,110,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,22,117,112,100,97,116,101,95,109,105,110,117,109,117,109,95,115,116,97,107,105,110,103,7,117,112,103,114,97,100,101,5,118,97,108,117,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,22,118,111,116,105,110,103,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,255,255,255,255,255,255,255,255,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,11,57,8,12,53,11,7,1,8,5,52,11,7,1,8,8,55,10,5,16,1,21,3,95,3,62,3,72,3,96,3,56,10,8,11,1,2,13,57,8,12,33,5,81,3,38,3,42,3,70,8,6,26,9,0,80,11,9,1,9,1,44,3,45,11,13,2,5,3,19,3,20,11,13,2,5,3,82,2,2,2,1,71,8,11,3,2,2,71,8,11,66,2,1,36,0,0,0,0,18,22,64,19,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,46,68,19,11,0,17,37,56,0,56,1,64,19,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,6,1,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,64,24,0,0,0,0,0,0,0,0,18,0,56,2,2,1,1,0,0,10,34,10,1,16,0,20,32,4,12,10,1,16,1,65,24,6,0,0,0,0,0,0,0,0,33,12,4,5,14,9,12,4,11,4,4,17,5,21,11,1,1,7,6,39,10,1,15,2,11,2,56,3,10,1,15,3,11,3,56,4,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,3,56,5,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,29,19,10,1,15,4,14,2,12,3,46,11,3,56,6,32,4,10,5,14,11,1,1,7,10,39,11,1,15,4,11,2,68,19,2,4,1,0,0,31,21,10,1,10,2,12,3,46,11,3,17,7,10,1,15,4,14,2,12,4,46,11,4,56,7,12,5,1,11,1,15,4,11,5,56,8,1,2,5,1,0,0,1,9,11,2,10,1,15,5,21,11,3,11,1,15,6,21,2,6,1,0,0,1,33,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,9,11,1,1,7,8,39,10,4,10,3,10,2,22,36,4,16,5,20,11,1,1,7,8,39,11,2,10,1,15,7,21,11,3,10,1,15,8,21,11,4,11,1,15,9,21,2,7,1,0,0,1,9,11,0,16,4,14,1,56,6,4,6,5,8,7,9,39,2,8,1,0,0,9,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,9,1,0,0,34,75,11,1,46,17,45,12,7,10,0,55,0,20,7,3,33,4,16,11,0,1,7,21,17,18,12,6,5,73,10,0,55,0,20,7,4,33,4,28,11,0,1,7,22,17,18,12,5,5,71,10,0,55,0,20,7,5,33,4,40,11,0,1,7,23,17,18,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,24,17,18,12,3,5,67,11,0,55,0,20,7,1,33,4,62,7,25,17,18,12,2,5,65,7,26,17,18,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,10,1,0,0,1,3,11,0,17,16,2,11,1,0,0,38,103,10,0,16,0,20,4,5,5,11,11,0,1,11,4,1,7,7,39,11,2,10,3,10,4,56,9,12,18,10,3,10,0,16,5,20,38,4,23,5,29,11,0,1,11,4,1,7,16,39,10,4,46,17,46,12,11,10,4,46,17,45,12,12,10,12,10,0,16,7,20,22,12,19,10,19,10,0,16,8,20,22,12,13,11,12,11,0,16,9,20,22,12,14,10,4,56,10,12,15,13,15,10,11,10,3,56,11,10,4,17,37,12,16,14,16,17,38,20,12,17,11,16,12,10,11,11,12,9,11,19,12,8,11,13,12,7,11,14,12,6,56,12,12,5,11,10,11,9,11,8,11,7,11,6,14,5,17,25,11,1,11,18,56,13,11,3,11,15,6,0,0,0,0,0,0,0,0,11,4,56,10,7,1,57,0,56,14,11,17,18,2,56,15,2,12,1,0,0,51,175,2,10,6,46,17,45,12,17,10,17,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,6,1,7,12,39,10,17,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,6,1,7,15,39,10,2,55,0,20,7,1,33,4,50,7,2,10,2,54,0,21,10,2,46,56,16,7,2,18,3,56,17,10,2,55,0,20,7,2,33,4,57,5,65,11,2,1,11,0,1,11,6,1,7,14,39,10,6,46,17,46,12,22,10,2,54,3,12,20,10,2,54,4,12,16,11,3,10,4,11,6,56,9,12,21,11,17,10,2,55,5,20,35,4,237,1,11,0,1,10,2,54,6,11,21,56,13,56,18,1,11,5,4,158,1,10,2,55,7,20,10,4,22,10,2,54,7,21,11,4,12,18,10,20,10,22,12,9,46,11,9,56,19,4,119,11,18,10,20,10,22,56,20,22,12,18,10,16,10,22,12,10,46,11,10,56,19,4,151,1,11,16,10,22,56,20,12,14,10,2,55,7,20,10,14,22,10,2,54,7,21,10,2,55,8,20,10,14,23,10,2,54,8,21,11,18,11,14,22,12,18,5,153,1,11,16,1,11,20,11,22,11,18,56,11,5,219,1,10,2,55,8,20,10,4,22,10,2,54,8,21,11,4,12,15,10,16,10,22,12,11,46,11,11,56,19,4,181,1,11,15,10,16,10,22,56,20,22,12,15,10,20,10,22,12,12,46,11,12,56,19,4,213,1,11,20,10,22,56,20,12,19,10,2,55,8,20,10,19,22,10,2,54,8,21,10,2,55,7,20,10,19,23,10,2,54,7,21,11,15,11,19,22,12,15,5,215,1,11,20,1,11,16,11,22,11,15,56,11,10,2,55,7,20,10,2,55,8,20,22,11,2,55,6,56,21,33,4,232,1,5,234,1,7,19,39,56,22,12,8,5,173,2,11,20,1,11,16,1,11,21,56,23,10,2,55,7,20,10,2,55,8,20,22,12,23,10,23,10,2,55,7,20,17,8,4,136,2,11,23,10,0,16,6,20,38,12,13,5,138,2,9,12,13,11,13,4,157,2,7,3,10,2,54,0,21,11,2,46,56,16,7,3,18,3,56,17,11,0,16,3,56,24,17,15,56,25,12,7,5,171,2,11,0,1,7,4,10,2,54,0,21,11,2,46,56,16,7,4,18,3,56,17,56,22,12,7,11,7,12,8,11,8,2,13,1,4,0,19,41,10,2,46,17,45,10,1,55,1,20,35,4,23,10,1,55,0,20,7,1,33,4,15,5,23,11,1,1,11,0,1,11,2,1,7,13,39,11,2,46,17,46,12,3,11,0,11,3,17,7,7,5,10,1,54,0,21,11,1,46,56,16,7,5,18,3,56,17,2,14,1,4,0,60,129,1,10,1,46,17,45,12,8,10,0,55,0,20,7,3,33,4,13,8,12,2,5,19,10,0,55,0,20,7,4,33,12,2,11,2,4,24,8,12,3,5,30,10,0,55,0,20,7,5,33,12,3,11,3,4,35,8,12,4,5,41,11,8,10,0,55,1,20,38,12,4,11,4,4,44,5,50,11,0,1,11,1,1,7,20,39,10,1,46,17,46,12,10,10,0,54,3,12,9,10,0,54,4,12,7,10,9,10,10,12,5,46,11,5,56,19,4,90,11,7,1,11,9,10,10,56,20,12,12,10,0,54,6,10,12,56,26,11,1,56,27,11,10,56,28,10,0,55,7,20,11,12,23,11,0,54,7,21,5,128,1,11,9,1,10,7,10,10,12,6,46,11,6,56,19,4,100,5,108,11,0,1,11,1,1,11,7,1,7,11,39,11,7,10,10,56,20,12,11,10,0,54,6,10,11,56,26,11,1,56,27,11,10,56,28,10,0,55,8,20,11,11,23,11,0,54,8,21,2,0,4,0,10,0,2,0,1,0,3,0,8,0,9,0,5,0,6,0,7,1,12,1,4,1,2,1,9,1,11,1,3,1,7,1,8,1,10,10,36,11,36,12,36,13,36,14,36,15,36,16,36,17,36,18,36,0],"lending_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,126,4,136,1,2,5,138,1,175,1,7,185,2,166,4,8,223,6,32,6,255,6,41,12,168,7,192,10,0,22,0,9,0,23,1,0,7,0,0,20,0,1,0,0,21,0,1,0,0,16,0,1,0,0,19,0,1,0,0,18,0,1,0,0,15,0,1,0,0,17,0,1,0,0,10,2,3,0,0,1,3,2,0,0,14,4,3,0,0,5,3,4,0,0,12,5,3,0,0,3,3,6,0,0,13,7,3,0,0,4,3,7,0,1,2,3,11,0,1,11,11,3,0,2,6,17,18,0,2,7,17,19,0,2,8,17,1,0,2,24,9,0,0,2,25,10,0,0,2,26,13,0,0,2,27,12,0,0,2,28,15,16,1,1,24,1,0,1,2,4,13,3,8,0,2,1,10,2,6,13,3,3,8,0,8,0,2,4,13,3,8,0,3,5,13,3,8,0,3,2,2,10,13,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,11,10,2,10,2,10,2,10,2,3,3,2,3,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,3,10,2,10,2,10,2,16,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,2,3,8,0,13,13,8,0,13,13,10,2,10,2,10,2,10,2,10,2,3,3,2,3,3,13,8,0,13,3,3,10,2,3,10,10,2,10,2,10,2,3,13,10,13,13,3,2,13,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,101,110,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,101,110,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,8,24,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,22,11,4,2,8,1,0,0,14,92,6,0,0,0,0,0,0,0,0,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,1,14,1,17,17,12,11,11,6,11,5,22,12,6,6,8,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,2,14,2,17,18,12,8,11,6,11,5,22,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,3,14,3,17,17,12,9,11,6,11,5,22,12,6,11,9,52,12,5,14,0,10,6,10,6,10,5,22,56,0,17,15,12,10,11,6,11,5,22,12,6,6,1,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,4,14,4,17,19,12,7,11,6,11,5,22,14,0,65,1,33,4,85,5,87,7,0,39,11,11,11,8,11,10,11,7,2,9,1,0,0,20,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,20,13,6,11,1,17,21,13,6,11,2,17,21,11,3,17,16,12,7,13,6,14,7,65,1,75,17,20,13,6,11,7,17,23,11,4,17,16,12,8,13,6,14,8,65,1,75,17,20,13,6,11,8,17,23,13,6,11,5,17,22,11,6,2,10,1,0,0,21,141,1,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,18,12,11,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,18,12,7,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,15,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,19,12,10,11,9,11,8,22,14,0,65,1,33,4,132,1,5,134,1,7,0,39,11,16,11,11,11,7,11,12,11,15,11,10,2,11,1,0,0,8,27,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,21,13,4,7,6,17,22,11,4,2,12,1,0,0,22,118,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,1,14,1,17,17,12,11,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,2,14,2,17,18,12,10,11,7,11,6,22,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,3,14,3,17,17,12,13,11,7,11,6,22,12,7,11,13,52,12,6,14,0,10,7,10,7,10,6,22,56,0,17,15,12,12,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,4,14,4,17,18,12,9,11,7,11,6,22,12,7,6,1,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,5,14,5,17,19,12,8,11,7,11,6,22,12,7,10,8,7,6,33,4,102,5,104,7,1,39,11,7,14,0,65,1,33,4,110,5,112,7,0,39,11,11,11,10,11,12,11,9,11,8,2,13,1,0,0,23,32,64,1,0,0,0,0,0,0,0,0,12,3,14,0,65,18,12,4,13,3,10,4,75,17,20,6,0,0,0,0,0,0,0,0,12,2,10,2,10,4,35,4,27,5,16,13,3,14,0,10,2,66,18,20,17,20,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,13,3,11,1,17,22,11,3,2,14,1,0,0,24,76,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,1,14,1,17,17,12,10,11,8,11,4,22,12,8,72,0,0,12,7,64,18,0,0,0,0,0,0,0,0,12,6,10,7,10,10,35,4,51,5,27,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,2,14,2,17,17,12,5,13,6,11,5,68,18,11,8,11,4,22,12,8,11,7,72,1,0,22,12,7,5,22,6,1,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,3,14,3,17,19,12,9,11,8,11,4,22,14,0,65,1,33,4,71,5,73,7,0,39,11,6,11,9,2,0],"lending_core_storage":[161,28,235,11,6,0,0,0,12,1,0,20,2,20,52,3,72,245,2,4,189,3,40,5,229,3,172,2,7,145,6,149,16,8,166,22,96,6,134,23,20,10,154,23,101,12,255,23,239,16,13,238,40,62,15,172,41,6,0,77,0,17,0,43,0,91,1,122,2,31,2,87,2,109,2,112,2,115,0,6,8,0,0,11,4,0,0,4,4,0,0,5,4,0,0,1,4,0,1,0,12,0,1,8,12,0,2,3,0,0,5,2,8,0,6,10,4,0,7,7,12,2,7,1,4,1,9,9,2,0,0,72,0,1,0,0,93,2,1,0,0,104,3,1,0,0,102,3,1,0,0,106,4,1,0,0,105,4,1,0,0,99,4,1,0,0,103,4,1,0,0,100,4,1,0,0,101,5,1,0,0,45,6,7,0,0,61,8,9,0,0,73,10,11,0,0,30,10,11,0,0,58,6,12,0,0,42,13,11,0,0,41,10,11,0,0,65,13,9,0,0,63,13,9,0,0,66,13,14,0,0,64,13,14,0,0,67,13,14,0,0,69,15,9,0,0,68,15,9,0,0,60,10,12,0,0,52,10,9,0,0,62,10,9,0,0,59,10,9,0,0,57,10,9,0,0,46,10,9,0,0,50,10,9,0,0,53,10,9,0,0,56,10,9,0,0,51,10,9,0,0,55,10,9,0,0,54,10,9,0,0,48,10,9,0,0,47,10,9,0,0,49,10,16,0,0,44,6,17,0,0,85,18,1,0,0,29,18,1,0,0,84,18,1,0,0,28,18,1,0,0,14,15,1,0,0,96,15,1,0,0,13,15,1,0,0,95,15,1,0,0,15,15,1,0,0,97,15,1,0,0,119,19,1,0,0,117,20,1,0,0,118,21,1,0,0,116,22,1,0,0,40,23,1,0,1,45,17,7,0,1,92,0,26,0,3,90,1,9,0,4,34,46,11,1,0,4,71,46,48,1,0,4,94,49,31,1,0,5,110,8,12,0,6,86,24,25,0,7,12,34,1,2,7,4,7,20,32,39,2,7,4,7,23,36,37,2,7,4,7,34,32,11,2,7,4,7,81,40,12,2,7,4,7,86,24,28,2,7,4,7,94,36,44,2,7,4,8,107,31,1,1,8,68,27,68,29,70,30,66,27,68,33,63,27,65,27,64,27,67,27,66,29,64,29,66,33,64,33,69,33,63,33,65,29,58,7,59,7,60,7,63,29,3,6,8,7,7,8,6,7,8,11,0,17,6,8,7,7,8,0,6,8,8,13,1,1,3,15,15,15,15,15,15,15,15,15,7,8,11,4,6,8,7,7,8,0,13,1,4,6,8,7,7,8,0,13,15,7,6,8,7,7,8,0,13,15,15,15,15,1,7,8,0,1,13,1,6,8,8,1,15,2,7,8,0,13,1,1,1,3,2,7,8,0,3,1,10,13,3,7,8,0,3,13,4,15,15,15,15,1,6,8,5,4,7,8,0,13,3,15,4,7,8,0,6,8,8,3,15,3,7,8,0,13,15,6,7,8,0,13,15,15,15,15,4,7,8,0,13,15,15,3,7,8,0,6,8,8,3,1,7,8,11,1,8,9,1,8,5,2,13,8,2,1,11,10,2,9,0,9,1,2,3,8,1,1,8,0,1,9,0,2,6,11,10,2,9,0,9,1,9,0,2,3,15,3,7,11,10,2,9,0,9,1,9,0,9,1,1,7,8,2,2,7,11,10,2,9,0,9,1,9,0,1,7,9,1,1,7,8,4,1,6,9,1,1,6,11,10,2,9,0,9,1,2,15,6,8,2,1,6,8,4,2,15,7,8,3,1,9,1,1,7,8,1,2,6,10,9,0,6,9,0,2,3,7,8,1,2,1,3,2,7,10,9,0,3,2,3,7,8,2,6,65,112,112,67,97,112,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,11,82,101,115,101,114,118,101,68,97,116,97,13,83,99,97,108,101,100,66,97,108,97,110,99,101,7,83,116,111,114,97,103,101,5,84,97,98,108,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,85,115,101,114,73,110,102,111,3,97,100,100,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,17,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,16,98,97,115,101,95,98,111,114,114,111,119,95,114,97,116,101,6,98,111,114,114,111,119,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,18,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,49,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,50,23,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,5,99,108,111,99,107,22,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,11,99,111,108,108,97,116,101,114,97,108,115,8,99,111,110,116,97,105,110,115,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,23,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,22,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,13,100,116,111,107,101,110,95,115,99,97,108,101,100,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,10,103,101,116,95,97,112,112,95,105,100,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,18,103,101,116,95,114,101,115,101,114,118,101,95,108,101,110,103,116,104,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,13,103,101,116,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,2,105,100,8,105,110,100,101,120,95,111,102,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,12,105,115,111,108,97,116,101,95,100,101,98,116,19,108,97,115,116,95,97,118,101,114,97,103,101,95,117,112,100,97,116,101,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,13,108,105,113,117,105,100,95,97,115,115,101,116,115,5,108,111,97,110,115,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,13,111,116,111,107,101,110,95,115,99,97,108,101,100,3,114,97,121,8,114,97,121,95,109,97,116,104,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,20,114,101,103,105,115,116,101,114,95,110,101,119,95,114,101,115,101,114,118,101,6,114,101,109,111,118,101,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,8,114,101,115,101,114,118,101,115,22,115,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,22,115,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,23,115,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,27,115,101,116,95,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,26,115,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,21,115,101,116,95,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,22,115,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,8,116,114,101,97,115,117,114,121,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,10,117,115,101,114,95,105,110,102,111,115,10,117,115,101,114,95,115,116,97,116,101,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,70,8,9,16,8,5,98,11,10,2,13,8,2,120,11,10,2,3,8,1,1,2,5,18,15,75,15,82,10,13,33,10,13,83,10,13,2,2,17,73,1,27,1,74,15,76,15,113,3,114,15,108,15,21,15,36,15,38,15,35,15,37,15,32,15,22,15,24,8,4,89,8,3,39,8,3,3,2,2,121,11,10,2,3,15,111,15,4,2,4,19,15,25,15,26,15,88,15,0,1,0,0,1,13,10,2,17,62,11,0,11,1,10,2,17,56,10,2,56,0,11,2,56,1,18,0,56,2,2,1,1,0,0,1,49,10,1,16,0,10,3,56,3,32,4,7,5,15,11,1,1,11,16,1,11,2,1,7,0,39,11,1,15,0,11,3,11,4,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,2,17,11,11,6,11,7,11,8,11,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,57,17,57,11,10,11,11,11,12,11,13,11,14,11,15,18,4,10,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,11,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,18,2,56,5,2,2,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,1,21,2,3,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,2,21,2,4,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,3,21,2,5,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,4,21,2,6,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,5,21,2,7,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,6,21,2,8,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,7,21,2,9,1,0,0,38,23,11,1,15,0,11,2,56,6,15,8,12,7,11,3,10,7,15,9,21,11,4,10,7,15,10,21,11,5,10,7,15,11,21,11,6,11,7,15,12,21,2,10,1,0,0,1,4,11,0,16,13,17,55,2,11,1,0,0,1,6,11,0,17,61,6,232,3,0,0,0,0,0,0,26,77,2,12,1,0,0,1,7,11,0,16,0,11,1,56,7,16,1,20,2,13,1,0,0,1,7,11,0,16,0,11,1,56,7,16,2,20,2,14,1,0,0,1,4,11,0,16,0,56,8,2,15,1,0,0,12,8,11,0,15,14,11,1,12,2,46,11,2,56,9,2,16,1,0,0,7,8,11,0,15,0,11,1,12,2,46,11,2,56,3,2,17,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,15,20,2,18,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,16,20,2,19,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,17,20,2,20,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,18,20,2,21,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,19,20,2,22,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,20,16,21,10,1,56,11,4,19,11,4,16,20,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,23,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,22,16,21,10,1,56,11,4,19,11,4,16,22,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,24,1,0,0,1,7,11,0,16,0,11,1,56,7,16,23,20,2,25,1,0,0,1,7,11,0,16,0,11,1,56,7,16,24,20,2,26,1,0,0,1,7,11,0,16,0,11,1,56,7,16,3,20,2,27,1,0,0,1,7,11,0,16,0,11,1,56,7,16,4,20,2,28,1,0,0,1,7,11,0,16,0,11,1,56,7,16,5,20,2,29,1,0,0,1,7,11,0,16,0,11,1,56,7,16,7,20,2,30,1,0,0,1,7,11,0,16,0,11,1,56,7,16,6,20,2,31,1,0,0,1,7,11,0,16,0,11,1,56,7,16,25,20,2,32,1,0,0,1,8,11,0,16,0,11,1,56,7,16,20,16,26,20,2,33,1,0,0,1,8,11,0,16,0,11,1,56,7,16,22,16,26,20,2,34,1,0,0,1,7,11,0,16,0,11,1,56,7,16,27,20,2,35,1,0,0,1,7,11,0,16,0,11,1,56,7,16,28,20,2,36,1,0,0,1,7,11,0,16,0,11,1,56,7,16,29,20,2,37,1,0,0,1,7,11,0,16,0,11,1,56,7,16,30,20,2,38,1,0,0,42,19,11,0,16,0,11,1,56,7,16,8,12,2,10,2,16,9,20,10,2,16,10,20,10,2,16,11,20,11,2,16,12,20,2,39,3,0,0,1,3,11,0,16,13,2,40,3,0,0,43,35,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,41,3,0,0,43,44,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,42,3,0,0,43,35,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,43,3,0,0,43,44,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,44,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,17,14,2,56,16,32,4,16,11,3,15,17,11,2,68,7,5,18,11,3,1,2,45,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,17,14,2,56,17,12,3,4,17,11,4,15,17,11,3,56,18,1,5,19,11,4,1,2,46,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,18,14,2,56,16,32,4,16,11,3,15,18,11,2,68,7,5,18,11,3,1,2,47,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,18,14,2,56,17,12,3,4,17,11,4,15,18,11,3,56,18,1,5,19,11,4,1,2,48,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,19,14,2,56,16,32,4,16,11,3,15,19,11,2,68,7,5,18,11,3,1,2,49,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,19,14,2,56,17,12,3,4,17,11,4,15,19,11,3,56,18,1,5,19,11,4,1,2,50,3,0,0,45,15,11,0,15,14,11,2,56,15,12,4,11,1,17,11,10,4,15,15,21,11,3,11,4,15,16,21,2,51,3,0,0,35,10,11,0,15,0,11,1,56,6,12,3,11,2,11,3,15,24,21,2,52,3,0,0,50,30,10,0,15,0,10,1,56,6,12,7,11,2,10,7,15,30,21,11,3,10,7,15,28,21,11,4,11,7,15,25,21,10,0,16,0,10,1,56,7,16,23,20,12,6,11,0,11,1,11,6,11,5,17,40,2,53,3,0,0,35,14,11,0,15,0,11,1,56,6,12,4,11,2,10,4,15,29,21,11,3,11,4,15,27,21,2,54,1,0,0,12,26,10,0,15,14,10,2,12,3,46,11,3,56,9,32,4,21,11,0,15,14,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,1,17,11,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,18,1,56,19,5,25,11,0,1,11,1,1,2,0,2,2,0,2,1,2,5,2,6,2,7,2,12,2,13,2,14,4,0,4,1,4,2,4,3,0,1,0,3,1,1,1,0,1,2,1,3,1,4,2,15,3,0,2,16,2,4,2,2,2,3,3,1,2,9,2,11,2,8,2,10,0,78,0,79,0,80,0],"lending_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,36,2,36,68,3,104,198,1,4,174,2,8,5,182,2,233,3,7,159,6,228,8,8,131,15,128,1,6,131,16,30,10,161,16,36,12,197,16,230,11,0,58,0,17,0,30,0,42,0,56,0,57,0,59,0,64,0,65,0,80,0,82,1,63,2,23,2,24,2,35,2,77,2,79,3,76,0,6,3,0,0,10,3,0,1,0,12,0,2,4,7,0,3,5,8,0,5,13,8,0,7,9,8,0,8,8,12,0,9,15,12,0,10,3,12,0,11,7,7,1,0,0,12,1,8,0,13,2,12,1,0,1,15,11,2,0,16,14,2,0,17,12,12,0,0,78,0,1,0,0,81,2,1,0,0,19,2,1,0,0,70,0,1,0,0,60,0,1,0,0,18,0,1,0,0,21,0,1,0,2,47,17,14,0,2,48,17,10,0,3,22,4,1,0,4,25,14,15,0,4,26,14,35,0,4,27,14,38,0,4,28,14,23,0,4,44,1,16,0,4,45,1,16,0,4,46,1,16,0,4,52,1,16,0,4,53,1,16,0,4,54,1,16,0,5,43,5,6,0,6,18,39,1,0,6,21,39,1,0,6,36,13,1,0,6,37,36,1,0,6,38,13,1,0,6,39,13,1,0,6,40,13,30,0,8,41,24,25,0,8,50,9,10,0,8,51,9,30,0,9,49,11,12,0,10,66,7,8,0,10,67,21,22,0,10,68,21,22,0,10,71,31,12,0,11,29,29,19,1,0,11,55,27,28,1,0,14,34,19,1,1,3,38,18,37,26,36,26,38,32,10,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,10,2,6,8,11,7,8,14,0,11,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,11,12,1,8,13,10,2,6,8,11,7,8,14,17,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,10,2,2,13,3,3,8,3,8,3,13,8,3,1,6,8,4,1,7,8,5,1,6,8,2,8,7,8,15,7,8,9,6,8,2,10,2,7,8,7,7,8,8,6,8,11,7,8,14,4,8,3,8,3,15,10,2,2,7,8,7,8,3,1,13,2,6,8,8,8,3,1,3,7,6,8,7,7,8,5,7,8,6,6,8,11,3,13,15,1,10,2,4,13,3,8,3,2,1,2,1,6,8,3,1,8,0,1,9,0,27,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,6,7,8,15,7,8,9,6,8,2,10,2,6,8,11,7,8,14,2,8,3,10,2,6,13,3,3,8,3,8,3,2,3,7,8,7,13,13,1,11,10,1,8,3,1,8,3,1,6,11,10,1,9,0,1,1,1,11,10,1,9,0,1,15,11,7,8,15,7,8,9,6,8,2,7,8,7,8,3,8,3,13,3,15,11,12,1,8,13,6,8,11,1,8,1,26,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,26,7,8,5,7,8,6,6,8,11,3,3,13,13,8,3,7,8,5,7,8,6,6,8,11,3,13,15,10,2,2,15,13,8,3,8,3,3,3,3,13,13,8,3,5,13,3,8,3,3,2,8,6,8,7,7,8,5,7,8,6,6,8,11,3,3,13,13,14,8,3,7,8,5,7,8,6,6,8,11,3,13,10,2,2,6,13,10,13,3,3,3,8,3,2,10,13,2,6,6,8,7,7,8,5,7,8,6,6,8,11,3,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,76,101,110,100,105,110,103,67,111,114,101,69,118,101,110,116,6,79,112,116,105,111,110,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,6,98,111,114,114,111,119,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,112,111,111,108,95,105,100,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,9,108,105,113,117,105,100,97,116,101,17,108,105,113,117,105,100,97,116,101,95,117,115,101,114,95,105,100,5,110,111,110,99,101,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,5,114,101,112,97,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,14,115,101,110,100,101,114,95,117,115,101,114,95,105,100,8,115,101,113,117,101,110,99,101,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,18,115,111,117,114,99,101,95,99,104,97,105,110,95,110,111,110,99,101,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,9,62,3,72,3,74,13,32,13,31,13,69,10,2,16,15,61,3,20,2,1,2,5,73,3,74,13,75,3,33,8,3,20,2,0,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,26,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,18,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,1,1,4,0,20,168,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,26,12,37,11,26,17,13,12,27,12,35,12,34,12,24,12,33,12,36,10,27,17,19,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,24,77,12,25,10,1,11,34,17,29,12,28,11,2,11,37,12,16,46,11,16,17,31,12,29,14,35,17,8,12,30,10,1,10,28,11,30,17,28,12,31,14,31,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,31,56,2,12,32,10,1,10,6,11,5,10,9,10,29,10,28,11,25,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,27,12,23,10,1,10,32,17,30,10,23,38,4,113,5,125,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,32,10,35,10,36,10,33,10,23,11,7,11,9,17,35,12,11,11,32,12,12,10,36,12,13,10,33,12,14,10,27,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,33,11,29,11,36,14,35,17,8,11,28,14,35,17,7,11,23,6,0,0,0,0,0,0,0,0,11,27,18,0,56,0,2,2,1,4,0,33,167,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,25,12,36,11,25,17,13,12,26,12,34,12,33,12,23,12,32,12,35,10,26,17,15,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,23,77,12,24,10,1,11,33,17,29,12,27,11,2,11,36,12,16,46,11,16,17,31,12,28,14,34,17,8,12,29,10,1,10,27,11,29,17,28,12,30,14,30,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,30,56,2,12,31,10,1,10,6,11,5,10,9,10,28,10,27,10,24,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,23,10,1,10,31,17,30,10,24,38,4,112,5,124,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,31,10,34,10,35,10,32,10,24,11,7,11,9,17,35,12,11,11,31,12,12,10,35,12,13,10,32,12,14,10,26,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,32,11,28,11,35,14,34,17,8,11,27,14,34,17,7,11,24,6,0,0,0,0,0,0,0,0,11,26,18,0,56,0,2,3,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,25,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,17,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,4,1,4,0,34,97,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,24,12,26,12,29,12,28,11,24,17,11,12,25,12,30,12,35,12,32,12,33,11,2,10,29,12,17,46,11,17,17,31,12,31,10,1,11,28,17,29,12,27,10,1,11,35,17,29,12,34,10,1,10,6,10,5,10,8,10,31,10,27,10,26,12,23,12,22,12,21,12,20,12,19,12,18,46,11,18,11,19,11,20,11,21,11,22,11,23,17,26,11,1,11,6,11,5,11,8,10,31,10,30,10,34,11,27,12,16,12,15,12,14,12,13,12,12,12,11,12,10,46,11,10,11,11,11,12,11,13,11,14,11,15,11,16,17,24,11,32,11,31,11,33,14,29,17,8,11,34,14,29,17,7,11,26,11,30,11,25,18,0,56,0,2,5,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,14,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,21,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,6,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,16,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,22,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,0],"lending_logic":[161,28,235,11,6,0,0,0,11,1,0,27,2,27,24,3,51,189,4,4,240,4,4,5,244,4,199,3,7,187,8,241,18,8,172,27,96,6,140,28,144,2,10,156,30,15,12,171,30,196,36,15,239,66,4,0,93,0,48,0,90,0,91,0,104,0,106,0,108,0,111,0,117,1,135,1,2,35,2,40,2,95,0,2,3,0,1,1,0,0,3,5,8,0,4,4,8,0,5,3,12,0,10,0,8,0,0,42,0,1,0,0,44,2,1,0,0,45,2,3,0,0,41,2,1,0,0,43,2,1,0,0,11,4,1,0,0,31,4,1,0,0,34,5,1,0,0,103,6,7,0,0,102,8,7,0,0,83,9,7,0,0,85,10,7,0,0,88,11,7,0,0,84,11,7,0,0,89,11,7,0,0,87,12,7,0,0,33,13,1,0,0,81,12,7,0,0,82,10,7,0,0,128,1,10,3,0,0,126,14,3,0,0,125,11,3,0,0,132,1,14,3,0,0,131,1,11,3,0,0,127,10,3,0,0,129,1,10,3,0,0,133,1,10,3,0,0,134,1,10,3,0,0,28,15,3,0,0,19,15,3,0,0,24,10,3,0,0,25,16,3,0,0,27,17,18,0,0,18,19,20,0,0,119,9,3,0,0,118,9,3,0,0,37,12,1,0,0,99,21,1,0,0,15,21,1,0,0,97,21,1,0,0,13,21,1,0,0,6,8,1,0,0,113,8,1,0,0,120,22,1,0,0,123,23,1,0,0,121,24,1,0,2,51,1,27,0,2,55,1,27,0,2,56,1,27,0,2,61,1,27,0,2,65,1,27,0,2,69,1,27,0,2,80,1,27,0,3,7,11,1,0,3,8,11,1,0,3,9,11,1,0,3,14,53,1,0,3,16,53,1,0,3,30,9,7,0,3,39,30,1,0,3,46,9,7,0,3,47,12,7,0,3,49,61,31,0,3,52,9,3,0,3,53,9,3,0,3,54,9,3,0,3,57,9,3,0,3,58,9,3,0,3,59,9,3,0,3,60,9,3,0,3,62,9,3,0,3,63,9,3,0,3,64,9,3,0,3,66,9,3,0,3,67,9,3,0,3,68,9,26,0,3,70,57,3,0,3,72,9,3,0,3,73,12,3,0,3,74,12,37,0,3,75,12,3,0,3,76,12,37,0,3,77,12,37,0,3,78,11,3,0,3,79,11,3,0,3,86,9,7,0,3,98,53,1,0,3,100,53,1,0,3,114,11,1,0,3,115,11,1,0,3,116,11,1,0,3,121,63,1,0,3,122,6,1,0,3,123,60,1,0,3,124,58,1,0,4,32,32,1,0,4,71,47,48,0,5,50,62,3,0,6,20,20,3,0,6,21,6,3,0,6,22,33,3,0,6,23,33,3,0,6,26,63,3,0,7,96,18,3,0,7,109,1,3,0,7,110,18,3,0,7,112,18,3,0,8,12,18,3,0,8,17,18,3,0,8,101,18,3,0,9,36,39,7,1,0,11,38,29,1,1,3,12,107,49,26,0,111,28,110,31,8,6,8,4,7,8,2,7,8,3,6,8,5,3,3,13,13,0,7,6,8,4,7,8,2,7,8,3,6,8,5,3,13,15,1,15,6,6,8,4,7,8,2,7,8,3,6,8,5,3,13,7,6,8,1,6,8,4,7,8,2,6,8,5,13,3,15,3,7,8,2,13,15,1,1,3,7,8,2,3,15,2,7,8,2,13,3,7,8,2,7,8,3,3,3,7,8,2,3,13,2,7,8,2,3,4,7,8,3,7,8,2,3,6,8,5,4,7,8,2,7,8,3,3,13,3,7,8,3,13,15,4,7,8,2,7,8,3,3,3,6,7,8,2,7,8,3,3,3,13,13,2,15,15,7,7,8,3,13,15,13,15,15,15,4,15,15,15,15,4,7,8,2,3,13,15,4,7,8,2,7,8,3,6,8,5,3,3,7,8,2,6,8,5,13,4,6,8,4,7,8,2,13,15,12,1,15,15,15,15,15,15,15,15,3,15,15,1,3,1,2,1,8,0,1,9,0,3,7,8,2,6,8,5,3,1,13,3,7,8,3,10,13,6,8,5,3,15,15,15,5,15,15,15,15,3,3,1,15,15,5,1,15,6,13,15,10,13,1,10,13,2,1,10,13,2,6,10,9,0,6,9,0,3,1,13,10,13,2,10,13,10,13,7,6,13,15,15,10,13,3,3,15,7,15,3,3,6,13,15,10,13,15,6,6,13,15,10,13,3,3,15,6,3,3,6,13,15,10,13,15,2,2,15,2,7,8,3,13,3,15,2,3,2,3,2,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,6,15,15,15,15,15,15,6,15,3,3,6,13,10,13,3,4,7,8,2,13,3,15,3,6,13,15,10,13,5,15,6,13,15,15,10,13,7,15,15,15,15,15,15,15,1,6,8,5,4,7,8,2,6,8,5,3,15,9,15,15,15,15,15,15,15,15,15,6,7,8,2,13,15,15,15,15,1,7,8,2,3,6,8,4,13,13,4,7,8,2,13,15,15,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,23,76,101,110,100,105,110,103,67,111,114,101,69,120,101,99,117,116,101,69,118,101,110,116,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,16,97,100,100,95,105,115,111,108,97,116,101,95,100,101,98,116,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,6,97,109,111,117,110,116,13,97,115,95,99,111,108,108,97,116,101,114,97,108,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,100,116,111,107,101,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,111,116,111,107,101,110,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,115,99,97,108,101,100,28,99,97,108,99,117,108,97,116,101,95,97,99,116,117,97,108,95,108,105,113,117,105,100,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,35,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,98,97,115,101,95,100,105,115,99,111,117,110,116,30,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,100,105,115,99,111,117,110,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,25,99,97,108,99,117,108,97,116,101,95,109,97,120,95,108,105,113,117,105,100,97,116,105,111,110,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,9,99,97,108,108,95,116,121,112,101,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,22,99,104,101,99,107,95,117,115,101,114,95,102,114,101,115,104,95,112,114,105,99,101,19,99,108,97,105,109,95,102,114,111,109,95,116,114,101,97,115,117,114,121,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,13,99,111,118,101,114,95,100,101,102,105,99,105,116,4,101,109,105,116,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,13,103,101,116,95,116,105,109,101,115,116,97,109,112,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,14,104,97,115,95,99,111,108,108,97,116,101,114,97,108,11,104,97,115,95,100,101,102,105,99,105,116,19,105,115,95,98,111,114,114,111,119,97,98,108,101,95,97,115,115,101,116,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,17,105,115,95,105,115,111,108,97,116,105,111,110,95,109,111,100,101,15,105,115,95,108,105,113,117,105,100,95,97,115,115,101,116,7,105,115,95,108,111,97,110,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,109,97,116,104,3,109,105,110,11,109,105,110,116,95,100,116,111,107,101,110,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,111,116,111,107,101,110,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,24,110,111,116,95,114,101,97,99,104,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,24,110,111,116,95,114,101,97,99,104,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,6,111,114,97,99,108,101,7,112,111,111,108,95,105,100,12,112,111,111,108,95,109,97,110,97,103,101,114,3,112,111,119,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,19,114,101,100,117,99,101,95,105,115,111,108,97,116,101,95,100,101,98,116,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,19,116,111,116,97,108,95,100,116,111,107,101,110,95,115,117,112,112,108,121,19,116,111,116,97,108,95,111,116,111,107,101,110,95,115,117,112,112,108,121,24,117,112,100,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,7,117,115,101,114,95,105,100,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,27,117,115,101,114,95,116,111,116,97,108,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,21,117,115,101,114,95,116,111,116,97,108,95,108,111,97,110,95,118,97,108,117,101,6,118,101,99,116,111,114,11,118,105,111,108,97,116,111,114,95,105,100,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,15,32,0,0,0,200,165,25,144,185,165,111,165,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,34,76,160,196,199,203,249,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,0,2,5,130,1,3,10,15,105,13,136,1,3,29,2,0,3,0,0,25,233,1,10,1,10,5,10,6,17,13,4,6,5,16,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,5,10,7,17,14,4,22,5,32,11,1,1,11,0,1,11,2,1,11,3,1,7,8,39,10,1,10,4,10,7,17,13,4,38,5,48,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,3,10,7,17,44,10,1,10,3,10,6,17,44,10,1,10,2,10,3,10,4,17,43,10,2,10,1,10,5,10,3,17,16,10,1,10,2,10,5,17,11,32,4,73,5,83,11,1,1,11,0,1,11,2,1,11,3,1,7,6,39,10,1,10,2,10,4,10,5,10,6,10,7,17,32,12,15,12,14,10,1,10,6,17,77,12,18,10,1,10,4,10,7,17,21,12,16,10,2,10,6,11,14,10,7,11,15,11,16,11,18,17,33,12,19,12,11,12,10,12,9,10,1,10,6,17,75,12,17,10,1,10,5,10,7,10,10,17,40,10,1,10,5,10,6,10,9,17,38,10,1,10,4,10,7,11,10,17,38,10,1,11,17,10,6,11,19,17,37,10,1,10,2,10,5,17,18,4,145,1,10,1,10,5,17,36,10,1,10,4,10,6,17,14,4,184,1,10,1,10,4,10,6,17,23,12,13,10,13,10,11,17,103,12,12,10,1,10,4,10,6,11,12,17,40,10,11,10,13,36,4,183,1,10,1,10,4,10,6,17,90,10,1,10,4,10,6,11,11,11,13,23,17,37,10,1,10,4,10,6,17,54,5,210,1,10,1,10,4,10,6,11,11,17,37,10,1,10,4,10,6,17,13,32,4,202,1,10,1,10,4,10,6,17,12,32,12,8,5,204,1,9,12,8,11,8,4,210,1,10,1,10,4,10,6,17,54,10,0,10,1,10,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,0,10,1,11,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,5,17,43,11,4,11,9,11,6,11,5,17,49,18,0,56,0,2,1,3,0,0,7,128,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,4,10,5,17,14,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,18,39,10,1,10,5,10,6,17,8,4,42,5,52,11,1,1,11,0,1,11,2,1,11,3,1,7,19,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,10,6,17,37,10,1,10,4,10,5,17,13,32,4,74,10,1,10,4,10,5,17,12,32,12,7,5,76,9,12,7,11,7,4,110,10,1,10,4,17,15,4,87,10,1,10,4,10,5,17,54,5,110,10,1,10,4,17,17,32,4,97,10,1,10,4,10,5,17,53,5,110,10,1,10,5,17,85,4,106,10,1,10,4,10,5,17,54,5,110,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,51,18,0,56,0,2,2,3,0,0,18,95,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,21,12,8,11,6,10,8,17,103,12,7,10,1,10,4,10,5,10,7,17,38,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,48,5,58,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,10,7,11,8,33,4,76,10,1,10,4,10,5,17,13,4,72,10,1,10,4,10,5,17,88,5,76,10,1,10,4,10,5,17,89,11,0,10,1,10,5,10,7,17,45,11,1,11,2,11,3,10,4,17,43,11,4,10,7,11,5,6,0,0,0,0,0,0,0,0,17,52,18,0,56,0,11,7,2,3,3,0,0,1,137,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,5,17,85,32,4,29,5,39,11,1,1,11,0,1,11,2,1,11,3,1,7,13,39,10,1,10,4,17,15,4,78,10,1,10,5,17,58,4,48,5,58,11,1,1,11,0,1,11,2,1,11,3,1,7,12,39,10,1,10,4,10,6,17,9,4,64,5,74,11,1,1,11,0,1,11,2,1,11,3,1,7,11,39,10,1,10,4,10,6,17,41,10,1,10,4,10,5,17,14,32,4,88,10,1,10,4,10,5,17,55,10,1,10,4,10,5,10,6,17,39,10,2,10,1,10,4,10,3,17,16,10,2,10,5,64,31,1,0,0,0,0,0,0,0,10,3,17,95,10,1,10,2,10,4,17,11,4,109,5,119,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,10,6,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,47,18,0,56,0,2,4,3,0,0,33,88,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,23,12,7,10,6,10,7,17,103,12,9,10,1,10,4,10,5,10,9,17,40,10,1,10,4,17,15,4,45,10,1,10,4,10,9,17,42,10,6,10,7,38,4,70,10,1,10,4,10,5,17,90,11,6,11,7,23,12,8,10,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,10,1,10,4,10,5,11,8,17,37,10,1,10,4,10,5,17,54,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,9,11,5,6,0,0,0,0,0,0,0,0,17,50,18,0,56,0,2,5,3,0,0,1,82,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,12,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,14,39,10,1,10,4,17,15,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,15,39,10,1,10,4,17,17,4,56,10,1,10,5,17,85,32,4,46,5,56,11,1,1,11,0,1,11,2,1,11,3,1,7,17,39,10,1,10,4,10,5,17,89,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,46,18,0,56,0,2,6,3,0,0,1,67,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,13,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,4,10,5,17,88,10,1,10,4,10,5,17,54,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,39,5,49,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,48,18,0,56,0,2,7,1,0,0,34,49,10,2,11,3,10,4,17,44,10,2,10,4,17,75,12,11,10,2,10,11,10,4,17,21,12,10,10,2,10,11,10,4,17,23,12,9,10,10,10,9,36,4,27,11,10,11,9,23,12,7,5,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,11,6,17,103,12,8,10,2,11,11,10,4,10,8,17,38,10,2,11,5,10,4,11,8,17,37,11,1,11,2,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,2,8,1,0,0,35,23,10,0,10,1,17,74,12,4,11,0,11,1,17,34,12,5,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,15,8,12,3,5,21,11,5,11,2,22,11,4,35,12,3,11,3,2,9,1,0,0,36,33,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,5,10,0,10,5,20,17,73,12,4,11,0,11,5,20,17,68,12,6,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,8,12,3,5,31,11,6,11,2,22,11,4,35,12,3,11,3,2,10,1,0,0,1,6,11,0,11,1,17,63,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,2,11,1,0,0,1,7,11,0,11,1,11,2,17,19,17,104,36,2,12,1,0,0,38,19,10,0,10,1,17,61,4,13,11,0,11,1,17,81,12,4,14,4,14,2,56,1,12,3,5,17,11,0,1,9,12,3,11,3,2,13,1,0,0,37,8,11,0,11,1,17,79,12,3,14,3,14,2,56,1,2,14,1,0,0,37,8,11,0,11,1,17,82,12,3,14,3,14,2,56,1,2,15,1,0,0,40,25,10,0,11,1,17,79,12,4,14,4,65,31,6,1,0,0,0,0,0,0,0,33,4,19,14,4,6,0,0,0,0,0,0,0,0,66,31,20,12,3,11,0,11,3,17,85,12,2,5,23,11,0,1,9,12,2,11,2,2,16,1,0,0,41,17,10,1,10,2,17,79,12,4,11,1,11,2,17,82,12,5,10,0,11,4,10,3,17,95,11,0,11,5,11,3,17,95,2,17,1,0,0,37,9,11,0,11,1,17,79,12,2,14,2,65,31,6,0,0,0,0,0,0,0,0,36,2,18,1,0,0,35,23,10,0,10,1,10,2,17,26,12,4,11,0,11,1,11,2,17,27,12,5,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,12,3,5,21,9,12,3,11,3,2,19,1,0,0,33,23,10,0,10,1,10,2,17,24,12,4,11,0,11,1,11,2,17,25,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,19,11,4,11,5,17,105,12,3,5,21,7,0,12,3,11,3,2,20,1,0,0,3,10,11,0,11,2,10,3,17,21,12,4,11,1,11,3,11,4,17,28,2,21,1,0,0,18,13,10,0,11,1,10,2,17,84,12,4,11,0,11,2,17,70,12,3,11,4,11,3,17,107,2,22,1,0,0,3,10,11,0,11,2,10,3,17,23,12,4,11,1,11,3,11,4,17,28,2,23,1,0,0,18,13,10,0,11,1,10,2,17,83,12,4,11,0,11,2,17,64,12,3,11,4,11,3,17,107,2,24,1,0,0,42,49,10,0,10,2,17,79,12,6,14,6,65,31,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,43,5,16,14,6,10,7,66,31,12,3,10,0,10,3,20,17,66,12,4,10,0,10,1,10,2,11,3,20,17,20,12,5,11,9,11,5,11,4,17,106,22,12,9,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,11,11,0,1,11,1,1,11,9,2,25,1,0,0,43,49,10,0,10,2,17,82,12,8,14,8,65,31,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,43,5,16,14,8,10,4,66,31,12,6,10,0,10,6,20,17,63,12,3,10,0,10,1,10,2,11,6,20,17,22,12,7,11,9,11,7,11,3,17,106,22,12,9,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,11,11,0,1,11,1,1,11,9,2,26,1,0,0,44,42,10,0,10,2,17,79,12,5,14,5,65,31,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,36,5,16,14,5,10,6,66,31,12,3,10,0,10,1,10,2,11,3,20,17,20,12,4,11,8,11,4,22,12,8,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,11,11,0,1,11,1,1,11,8,2,27,1,0,0,45,42,10,0,10,2,17,82,12,7,14,7,65,31,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,36,5,16,14,7,10,3,66,31,12,5,10,0,10,1,10,2,11,5,20,17,22,12,6,11,8,11,6,22,12,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,11,11,0,1,11,1,1,11,8,2,28,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,11,4,24,6,10,0,0,0,0,0,0,0,11,3,17,112,77,26,2,29,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,6,10,0,0,0,0,0,0,0,11,3,17,112,77,24,11,4,26,2,30,1,0,0,18,16,10,0,10,1,10,2,17,24,12,3,11,0,11,1,11,2,17,25,12,4,17,104,11,3,11,4,17,105,23,2,31,1,0,0,20,52,10,0,10,3,17,61,4,5,5,11,11,0,1,11,1,1,7,16,39,10,0,10,2,17,61,4,16,5,22,11,0,1,11,1,1,7,16,39,10,0,10,1,10,3,17,30,12,5,10,0,11,2,17,78,12,4,11,0,11,1,11,3,17,25,12,7,11,4,74,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,24,17,105,17,104,17,103,17,104,22,12,6,11,5,11,6,17,106,7,1,17,103,2,32,1,0,0,50,89,10,0,10,1,11,2,10,3,17,31,12,12,10,0,10,1,10,3,17,24,12,10,10,0,10,1,10,3,17,25,12,11,10,0,10,5,17,63,12,6,10,0,10,4,17,66,12,7,11,11,7,2,17,106,11,10,23,12,19,7,2,17,104,10,12,23,17,106,11,6,17,106,11,7,23,12,18,11,19,11,18,17,105,12,14,10,0,10,1,10,3,10,4,17,20,10,14,17,105,12,8,10,14,17,104,11,12,23,17,106,12,16,11,0,10,1,11,3,10,5,17,22,10,16,17,105,12,9,11,8,11,9,17,103,17,104,17,103,12,17,10,1,11,4,11,14,10,17,17,106,17,29,12,13,11,1,11,5,11,16,11,17,17,106,17,29,12,15,11,13,11,15,2,33,1,0,0,51,45,10,5,10,4,38,4,9,11,4,12,8,11,2,12,7,5,17,11,5,12,8,11,2,10,8,11,4,17,105,17,106,12,7,10,0,10,1,10,7,17,28,12,9,10,0,11,3,10,8,17,28,12,11,11,0,11,1,11,9,11,11,23,17,29,11,6,17,106,12,12,10,7,10,12,23,12,10,11,7,11,8,11,10,11,12,2,34,1,0,0,18,12,10,0,10,1,17,72,12,3,11,0,11,1,17,70,12,2,11,3,11,2,17,106,2,35,1,0,0,18,12,10,0,10,1,17,67,12,3,11,0,11,1,17,64,12,2,11,3,11,2,17,106,2,36,0,0,0,52,49,10,0,10,1,17,82,12,6,14,6,65,31,12,4,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,46,5,14,14,6,10,3,66,31,12,5,10,0,10,5,20,17,75,12,7,10,0,10,1,10,5,20,17,23,12,2,10,0,10,1,10,5,20,10,2,17,40,10,0,11,7,11,5,20,11,2,17,39,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,9,11,0,1,2,37,0,0,0,3,12,11,3,10,0,10,2,17,70,17,109,12,4,11,0,11,2,11,1,11,4,17,87,2,38,0,0,0,3,12,11,3,10,0,10,2,17,70,17,108,12,4,11,0,11,2,11,1,11,4,17,57,2,39,0,0,0,3,12,11,3,10,0,10,2,17,64,17,109,12,4,11,0,11,2,11,1,11,4,17,86,2,40,0,0,0,3,12,11,3,10,0,10,2,17,64,17,108,12,4,11,0,11,2,11,1,11,4,17,56,2,41,0,0,0,54,21,10,0,11,1,17,79,12,5,14,5,6,0,0,0,0,0,0,0,0,66,31,12,3,10,0,10,3,20,17,68,11,2,22,12,4,11,0,11,3,20,11,4,17,92,2,42,0,0,0,55,32,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,4,10,0,10,4,20,17,68,12,5,10,5,10,2,38,4,22,11,5,11,2,23,12,3,5,24,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,12,6,11,0,11,4,20,11,6,17,92,2,43,0,0,0,56,58,10,0,10,3,17,61,4,51,10,2,17,76,12,5,10,0,10,3,17,80,12,9,10,0,10,1,10,3,17,24,12,6,10,0,11,1,10,3,17,25,12,7,10,6,10,7,36,4,45,11,6,11,7,23,12,8,10,0,10,3,17,78,12,4,11,5,11,9,11,4,11,8,17,98,12,10,11,0,11,2,11,3,11,10,17,94,5,50,11,0,11,2,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,94,5,57,11,0,1,11,1,1,11,2,1,2,44,0,0,0,59,59,11,1,17,76,12,5,10,0,10,2,17,69,12,7,10,0,10,2,17,67,12,6,10,0,10,2,17,64,12,3,10,0,10,2,17,70,12,4,10,0,10,2,17,77,12,11,10,5,10,7,10,0,10,2,17,65,17,100,10,3,17,106,12,9,10,5,11,7,10,0,10,2,17,71,17,101,11,4,17,106,12,10,11,6,10,9,11,3,23,17,106,11,11,17,106,10,10,17,109,12,8,11,0,11,2,11,9,11,10,11,5,11,8,17,93,2,45,0,0,0,20,36,11,0,10,2,10,1,17,62,17,97,12,5,10,5,10,3,38,4,11,5,15,11,1,1,7,10,39,11,5,11,3,23,12,6,10,1,10,2,10,6,17,99,12,4,10,1,10,2,10,4,11,6,17,102,12,7,11,1,11,2,11,4,11,7,17,91,2,0,92,0,94,0],"lending_portal":[161,28,235,11,6,0,0,0,11,1,0,46,2,46,94,3,140,1,185,2,4,197,3,36,5,233,3,172,6,7,149,10,184,11,8,205,21,128,1,6,205,22,88,10,165,23,59,12,224,23,204,17,13,172,41,4,0,76,0,24,0,40,0,41,0,55,0,73,0,74,0,75,0,79,0,87,0,88,0,108,0,113,0,114,1,86,2,32,2,33,2,47,2,85,2,104,2,106,2,107,3,103,0,8,8,0,0,15,3,0,0,9,3,0,0,7,3,0,1,0,12,0,2,4,7,0,3,11,12,1,0,1,4,5,0,0,4,6,8,0,6,18,8,0,9,14,8,0,10,12,12,0,11,21,12,0,12,3,12,0,13,13,8,0,14,10,7,1,0,0,15,1,8,0,16,2,12,1,0,1,18,20,4,0,19,16,2,0,21,19,2,0,22,17,12,0,0,70,0,1,0,0,64,2,3,0,0,99,4,1,0,0,25,5,1,0,0,29,5,1,0,0,30,6,1,0,0,105,7,1,1,0,0,111,8,1,1,0,0,112,9,1,0,0,26,8,1,1,0,0,27,9,1,0,0,94,7,1,1,0,0,77,10,1,1,0,2,34,13,18,0,2,35,1,18,1,0,2,36,55,18,0,2,59,45,31,0,2,63,1,20,0,3,37,38,31,1,0,3,84,37,3,1,0,3,110,53,1,1,0,4,31,17,1,0,5,46,30,31,0,5,57,1,29,0,5,58,1,29,0,5,62,1,29,0,5,66,1,29,0,5,67,1,29,0,5,68,1,29,0,6,56,56,57,0,7,25,21,1,0,7,29,21,1,0,7,48,44,1,0,7,49,64,1,0,7,50,44,1,0,7,51,44,1,0,7,52,44,52,0,8,78,24,25,1,0,10,22,39,40,0,10,54,48,49,0,10,61,43,20,0,10,65,43,52,0,10,93,39,40,0,11,60,19,3,0,11,71,19,41,0,11,91,42,1,0,12,96,58,3,0,13,95,32,3,0,14,38,51,15,1,0,14,72,50,41,1,0,16,39,25,1,1,0,16,102,27,25,1,0,16,109,28,3,1,0,17,45,15,1,1,3,18,81,0,11,0,20,89,34,1,1,12,20,100,15,1,1,8,21,97,12,13,0,22,80,26,3,0,56,14,37,23,51,23,52,23,55,33,53,35,14,15,37,15,52,15,19,15,18,15,53,46,49,18,48,18,20,15,53,59,6,15,50,15,1,7,8,20,0,1,7,8,0,1,3,3,6,8,7,7,8,0,5,8,6,8,8,7,8,9,7,8,10,6,8,16,7,8,11,7,8,12,10,13,7,8,20,9,6,8,8,6,8,16,7,8,14,7,8,0,7,8,21,10,13,10,11,17,1,8,19,3,7,8,20,11,6,8,8,7,8,9,7,8,10,6,8,16,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,17,1,9,0,3,7,8,20,10,6,8,8,7,8,9,7,8,10,6,8,16,7,8,0,7,8,11,7,8,12,7,11,6,1,9,0,3,7,8,20,16,6,8,8,7,8,9,7,8,10,6,8,16,7,8,13,7,8,0,7,8,21,7,8,11,7,8,12,10,2,10,2,13,3,10,11,17,1,8,19,3,7,8,20,14,6,8,8,7,8,9,7,8,10,6,8,16,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,17,1,9,0,3,13,10,2,3,7,8,20,1,8,18,1,6,8,20,1,5,1,8,0,1,9,0,11,8,5,7,8,9,7,8,10,6,8,16,3,13,6,13,3,3,3,8,5,1,6,8,8,1,8,5,2,6,8,12,8,5,1,13,6,6,8,11,7,8,9,7,8,10,6,8,16,3,13,7,11,17,1,8,19,3,10,2,3,3,11,17,1,8,19,3,1,8,19,3,10,11,17,1,9,0,3,7,8,20,1,11,17,1,9,0,1,6,8,21,3,7,11,17,1,9,0,3,7,8,20,1,6,11,17,1,9,0,1,2,2,10,13,2,1,10,2,7,7,8,14,7,8,21,11,17,1,8,19,13,10,2,6,8,16,7,8,20,1,11,17,1,8,19,2,9,0,5,1,8,1,17,6,8,16,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,3,11,17,1,9,0,13,3,3,8,5,8,5,2,6,11,6,1,9,0,3,5,7,11,6,1,9,0,11,17,1,9,0,13,10,2,7,8,20,4,7,8,11,8,5,13,15,2,15,15,1,1,2,7,8,12,8,5,2,7,8,11,8,5,7,6,8,11,7,8,9,7,8,10,6,8,16,3,13,15,1,6,8,5,1,8,3,16,8,5,7,8,9,7,8,10,6,8,16,3,13,15,15,13,3,13,11,15,1,8,5,8,5,8,5,8,5,15,3,7,8,11,13,13,1,11,15,1,8,5,1,6,11,15,1,9,0,1,11,15,1,9,0,1,15,5,7,11,6,1,9,0,8,5,3,8,5,7,8,20,21,8,5,7,8,9,7,8,10,6,8,16,3,13,15,15,11,17,1,8,19,13,3,11,15,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,17,1,8,19,3,2,13,10,2,1,7,8,9,1,6,8,4,11,7,8,21,7,8,13,6,8,4,7,8,11,8,5,8,5,13,3,15,11,17,1,8,19,6,8,16,1,8,2,15,8,5,7,8,9,7,8,10,6,8,16,3,13,15,13,3,13,11,15,1,8,5,8,5,8,5,8,5,15,20,8,5,7,8,9,7,8,10,6,8,16,3,13,15,11,17,1,8,19,13,3,11,15,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,17,1,8,19,3,17,6,8,16,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,13,3,3,8,5,3,11,17,1,9,0,8,5,16,13,8,5,7,8,9,7,8,10,6,8,16,3,3,13,13,8,5,3,8,5,3,5,13,8,5,8,6,8,11,7,8,9,7,8,10,6,8,16,3,3,13,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,17,76,101,110,100,105,110,103,76,111,99,97,108,69,118,101,110,116,13,76,101,110,100,105,110,103,80,111,114,116,97,108,18,76,101,110,100,105,110,103,80,111,114,116,97,108,69,118,101,110,116,6,79,112,116,105,111,110,4,80,111,111,108,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,9,80,111,111,108,83,116,97,116,101,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,13,97,100,100,95,108,105,113,117,105,100,105,116,121,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,12,98,111,114,114,111,119,95,108,111,99,97,108,13,98,111,114,114,111,119,95,114,101,109,111,116,101,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,27,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,95,114,101,109,111,116,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,7,100,101,112,111,115,105,116,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,17,100,111,108,97,95,112,111,111,108,95,97,100,100,114,101,115,115,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,32,101,110,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,10,102,101,101,95,97,109,111,117,110,116,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,2,105,100,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,9,108,105,113,117,105,100,97,116,101,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,11,109,101,115,115,97,103,101,95,102,101,101,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,7,114,101,108,97,121,101,114,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,5,114,101,112,97,121,12,115,101,110,100,95,109,101,115,115,97,103,101,13,115,101,110,100,95,119,105,116,104,100,114,97,119,6,115,101,110,100,101,114,8,115,101,113,117,101,110,99,101,11,115,101,116,95,114,101,108,97,121,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,112,108,105,116,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,14,119,105,116,104,100,114,97,119,95,108,111,99,97,108,15,119,105,116,104,100,114,97,119,95,114,101,109,111,116,101,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,13,2,1,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,69,8,18,92,5,82,3,1,2,5,98,3,83,3,44,8,5,53,3,28,2,2,2,8,83,3,97,5,42,10,2,101,13,43,13,90,10,2,23,3,28,2,3,2,5,83,3,97,5,42,10,2,23,3,28,2,0,0,0,0,1,9,10,0,17,54,11,0,46,17,57,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,0,0,1,5,11,2,11,1,15,1,21,2,3,1,4,0,16,61,11,0,17,21,11,7,46,17,57,17,13,12,18,11,5,11,18,12,8,46,11,8,17,43,12,15,14,6,65,20,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,20,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,30,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,4,1,4,0,16,61,11,0,17,21,11,7,46,17,57,17,13,12,18,11,5,11,18,12,8,46,11,8,17,43,12,15,14,6,65,20,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,20,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,31,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,5,0,4,0,22,66,11,0,17,21,11,6,10,7,10,8,56,1,12,9,10,4,46,17,58,12,15,11,7,10,15,38,4,16,5,28,11,4,1,11,2,1,11,3,1,11,8,1,11,1,1,7,3,39,13,9,11,15,10,8,56,2,12,14,14,9,56,3,12,12,11,5,17,24,17,22,12,11,10,3,17,1,12,10,11,2,11,4,11,14,7,5,11,11,11,1,11,8,17,47,12,13,11,9,11,3,16,1,20,56,4,11,13,11,10,7,6,17,13,11,12,17,24,18,1,56,5,2,6,1,4,0,36,117,11,0,17,21,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,57,17,13,12,27,56,6,12,26,11,8,11,9,10,10,56,7,12,22,10,7,14,22,56,8,12,15,46,11,15,56,9,12,21,11,4,17,1,12,25,11,7,11,22,7,5,64,29,0,0,0,0,0,0,0,0,10,10,56,10,1,10,6,10,26,7,5,10,21,77,17,38,1,12,20,10,5,10,27,12,16,46,11,16,17,44,32,4,74,10,5,10,27,17,45,10,6,10,26,17,40,12,23,11,5,11,27,12,17,46,11,17,17,43,12,24,11,6,11,1,11,2,11,3,11,24,11,23,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,35,11,25,11,10,46,17,57,14,26,17,16,11,21,17,27,18,3,56,11,2,7,1,4,0,47,117,11,0,17,21,17,17,12,20,10,9,46,17,57,17,13,12,24,56,6,12,23,10,5,10,23,17,40,12,18,11,6,10,24,12,10,46,11,10,17,43,12,19,10,5,10,18,11,20,17,39,12,21,14,21,56,12,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,21,56,13,12,22,10,5,11,1,11,2,11,3,11,19,11,18,11,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,36,12,17,10,5,10,22,17,41,10,17,38,4,80,5,90,11,5,1,11,7,1,11,4,1,11,9,1,7,1,39,11,5,11,22,7,5,10,17,17,42,1,12,25,11,7,11,24,11,25,52,10,23,10,9,56,14,11,4,17,1,11,9,46,17,57,14,23,17,16,11,17,52,17,28,18,3,56,11,2,8,1,4,0,54,184,1,11,0,17,21,10,11,10,10,17,15,12,31,10,11,11,9,17,15,12,30,10,15,46,17,57,17,13,12,34,10,7,10,30,17,40,12,25,11,8,11,34,12,16,46,11,16,17,43,12,26,10,7,10,25,10,11,17,39,12,27,14,27,56,12,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,27,56,13,12,28,10,7,10,1,11,2,10,3,11,26,11,25,11,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,36,12,23,10,7,10,28,17,41,10,23,38,4,86,5,102,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,11,13,10,14,10,15,56,1,12,24,10,6,46,17,58,12,36,11,14,10,36,38,4,116,5,132,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,24,11,36,10,15,56,2,12,35,14,24,56,3,12,32,10,5,17,1,12,29,11,6,11,4,11,1,17,29,11,7,10,28,11,31,17,17,10,29,10,23,11,35,11,3,17,46,12,33,11,24,11,5,16,1,20,56,4,11,33,10,29,11,28,11,32,17,28,18,1,56,5,11,29,11,15,46,17,57,14,30,17,16,17,17,11,11,11,10,11,23,52,17,28,18,2,56,15,2,9,1,4,0,60,123,11,0,17,21,17,17,12,19,56,6,12,22,10,9,46,17,57,17,13,12,23,10,5,10,22,17,40,12,17,11,6,10,23,12,10,46,11,10,17,43,12,18,10,5,10,17,11,19,17,39,12,20,14,20,56,12,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,20,56,13,12,21,10,5,10,21,17,41,10,8,77,38,4,58,5,74,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,1,39,10,5,11,1,11,2,11,3,11,18,11,17,10,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,32,11,5,11,21,7,5,10,8,77,17,42,1,12,24,11,7,11,23,11,24,52,10,22,10,9,56,14,11,4,17,1,11,9,46,17,57,14,22,17,16,11,8,17,23,18,3,56,11,2,10,1,4,0,61,186,1,11,0,17,21,10,11,10,10,17,15,12,30,10,11,11,9,17,15,12,29,10,15,46,17,57,17,13,12,33,10,7,10,29,17,40,12,24,11,8,11,33,12,16,46,11,16,17,43,12,25,10,7,10,24,10,11,17,39,12,26,14,26,56,12,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,26,56,13,12,27,10,7,10,27,17,41,10,12,77,38,4,64,5,82,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,10,7,10,1,11,2,10,3,11,25,11,24,10,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,32,11,13,10,14,10,15,56,1,12,23,10,6,46,17,58,12,35,11,14,10,35,38,4,118,5,134,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,23,11,35,10,15,56,2,12,34,14,23,56,3,12,31,10,5,17,1,12,28,11,6,11,4,11,1,17,29,11,7,10,27,11,30,17,17,10,28,10,12,77,11,34,11,3,17,46,12,32,11,23,11,5,16,1,20,56,4,11,32,10,28,11,27,11,31,17,28,18,1,56,5,11,28,11,15,46,17,57,14,29,17,16,17,17,11,11,11,10,11,12,17,23,18,2,56,15,2,11,1,4,0,62,117,11,0,17,21,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,57,17,13,12,27,56,6,12,24,11,8,11,9,10,10,56,7,12,26,10,7,14,26,56,8,12,15,46,11,15,56,9,12,25,11,4,17,1,12,23,11,7,11,26,7,5,64,29,0,0,0,0,0,0,0,0,10,10,56,10,1,10,6,10,24,7,5,10,25,77,17,38,1,12,20,10,5,10,27,12,16,46,11,16,17,44,32,4,74,10,5,10,27,17,45,10,6,10,24,17,40,12,21,11,5,11,27,12,17,46,11,17,17,43,12,22,11,6,11,1,11,2,11,3,11,22,11,21,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,34,11,23,11,10,46,17,57,14,24,17,16,11,25,17,26,18,3,56,11,2,12,1,4,0,63,93,10,0,17,21,10,13,46,17,57,12,27,10,27,17,13,12,25,56,6,12,23,11,10,10,11,17,15,12,29,10,6,11,23,17,40,12,22,10,6,11,29,17,40,12,28,10,4,17,1,12,26,10,9,6,0,0,0,0,0,0,0,0,36,4,43,11,0,10,1,10,2,10,3,11,4,10,5,10,6,11,7,11,8,10,9,11,13,56,16,5,54,11,4,1,11,0,1,11,7,1,11,8,10,9,11,13,56,7,56,17,11,5,11,25,12,15,46,11,15,17,43,12,24,11,6,11,1,11,2,11,3,11,24,11,12,11,28,11,22,12,14,12,21,12,20,12,19,12,18,12,17,12,16,46,11,16,11,17,11,18,11,19,11,20,11,21,11,14,17,33,11,26,11,27,11,11,11,9,17,25,18,3,56,11,2,0,2,0,1,0],"merge_coins":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,10,3,20,53,4,73,14,5,87,102,7,189,1,132,1,8,193,2,96,6,161,3,30,12,191,3,189,1,0,6,1,14,2,2,2,11,2,12,2,0,12,1,0,1,4,1,2,0,0,5,0,1,1,0,1,3,5,6,1,0,1,8,3,4,1,0,2,4,8,4,1,0,2,10,11,1,1,0,2,13,9,10,1,0,2,15,15,1,1,0,3,7,14,4,1,12,4,9,12,13,0,2,1,1,1,3,7,5,7,4,7,7,1,6,7,3,10,11,0,1,9,0,3,7,8,1,1,11,0,1,9,0,6,11,0,1,9,0,11,0,1,9,0,11,0,1,9,0,3,11,0,1,9,0,3,1,7,10,9,0,0,1,6,10,9,0,1,1,1,9,0,2,7,11,0,1,9,0,11,0,1,9,0,1,6,11,0,1,9,0,1,3,3,7,11,0,1,9,0,3,7,8,1,1,6,8,1,1,5,2,9,0,5,1,7,8,1,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,8,105,115,95,101,109,112,116,121,4,106,111,105,110,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,7,114,101,118,101,114,115,101,6,115,101,110,100,101,114,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,118,101,99,116,111,114,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,255,255,255,255,255,255,255,255,0,1,0,0,2,83,14,0,65,1,6,0,0,0,0,0,0,0,0,36,4,67,13,0,56,0,13,0,69,1,12,5,14,0,56,1,32,4,20,5,15,13,5,13,0,69,1,56,2,5,10,11,0,70,1,0,0,0,0,0,0,0,0,14,5,56,3,12,8,10,1,12,6,11,1,7,2,33,4,33,10,8,12,6,11,8,10,6,38,4,38,5,42,11,2,1,7,0,39,14,5,56,3,10,6,36,4,60,13,5,11,6,10,2,56,4,12,7,11,5,11,2,46,17,8,56,5,11,7,12,3,5,64,11,2,1,11,5,12,3,11,3,12,4,5,81,11,0,70,1,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,33,4,74,5,78,11,2,1,7,1,39,11,2,56,6,12,4,11,4,2,0],"oracle":[161,28,235,11,6,0,0,0,11,1,0,36,2,36,84,3,120,157,1,4,149,2,22,5,171,2,231,2,7,146,5,231,6,8,249,11,128,1,6,249,12,70,10,191,13,33,12,224,13,232,5,13,200,19,14,0,47,0,31,2,40,2,41,2,49,2,52,2,54,2,56,2,61,1,23,1,24,1,46,1,62,1,63,1,65,1,66,3,61,3,68,0,10,8,0,0,6,4,0,1,2,0,0,1,3,8,0,2,4,0,1,3,0,3,5,7,0,4,6,7,0,5,7,7,0,6,8,7,0,6,9,12,0,8,12,12,0,9,0,8,0,10,1,12,1,0,1,11,15,4,0,12,11,2,0,13,13,12,2,7,1,4,1,15,14,2,0,16,12,12,0,17,16,0,0,0,43,0,1,0,0,39,2,3,0,0,59,4,1,0,0,58,4,1,0,0,57,5,1,0,0,20,6,1,0,0,21,6,1,0,0,29,7,1,0,1,22,27,1,0,2,28,40,1,1,3,3,33,43,23,0,3,34,43,23,0,4,32,41,42,0,4,35,41,42,0,5,30,19,20,0,6,36,30,20,0,6,37,28,29,0,7,26,33,34,0,7,38,38,39,0,7,67,35,34,0,9,64,22,23,0,11,45,0,8,0,13,17,21,1,2,7,4,13,18,15,17,2,7,4,13,19,36,37,2,7,4,13,25,15,16,2,7,4,13,45,0,10,2,7,4,14,60,13,1,1,8,17,48,31,32,0,26,9,26,11,27,12,25,11,23,11,25,9,22,9,22,11,23,9,24,11,9,29,1,7,8,16,0,2,7,8,0,13,3,15,2,3,3,6,8,2,7,8,0,3,7,6,8,2,7,8,0,10,2,13,15,2,6,8,11,3,7,8,0,10,13,6,8,11,9,6,8,3,7,8,17,7,8,10,7,8,9,7,8,0,13,10,2,6,8,11,11,12,1,8,14,1,8,13,2,13,8,7,1,11,15,2,9,0,9,1,2,13,8,1,1,8,0,1,9,0,4,13,13,6,8,1,7,11,15,2,13,8,1,2,6,11,15,2,9,0,9,1,9,0,1,1,1,6,9,1,5,13,13,8,7,7,11,15,2,13,8,7,7,11,15,2,13,8,1,1,10,2,1,8,7,3,7,11,15,2,9,0,9,1,9,0,9,1,1,6,8,11,1,3,6,13,3,6,13,3,6,8,1,7,11,15,2,13,8,1,1,13,23,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,6,8,11,13,10,2,6,8,11,10,8,18,6,8,11,3,8,5,3,11,4,1,8,8,7,8,1,6,8,7,8,8,11,4,1,8,8,8,5,3,8,6,8,7,8,18,1,6,8,3,1,6,8,9,1,8,8,1,6,8,8,3,6,8,17,10,2,6,8,11,1,8,18,3,6,8,10,10,8,18,6,8,11,1,11,4,1,8,8,5,6,8,10,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,2,7,11,15,2,9,0,9,1,9,0,1,7,9,1,3,6,8,9,6,8,11,3,1,8,6,1,11,4,1,9,0,1,6,8,6,1,8,5,1,6,8,5,5,67,108,111,99,107,4,67,111,105,110,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,15,72,111,116,80,111,116,97,116,111,86,101,99,116,111,114,3,73,54,52,5,80,114,105,99,101,15,80,114,105,99,101,73,100,101,110,116,105,102,105,101,114,9,80,114,105,99,101,73,110,102,111,15,80,114,105,99,101,73,110,102,111,79,98,106,101,99,116,11,80,114,105,99,101,79,114,97,99,108,101,3,83,85,73,5,83,116,97,116,101,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,86,65,65,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,17,99,104,101,99,107,95,103,117,97,114,100,95,112,114,105,99,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,29,99,114,101,97,116,101,95,112,114,105,99,101,95,105,110,102,111,115,95,104,111,116,95,112,111,116,97,116,111,7,100,101,99,105,109,97,108,7,100,101,115,116,114,111,121,24,102,101,101,100,95,116,111,107,101,110,95,112,114,105,99,101,95,98,121,95,112,121,116,104,13,102,114,111,109,95,98,121,116,101,95,118,101,99,7,103,101,110,101,115,105,115,8,103,101,116,95,101,120,112,111,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,110,101,103,97,116,105,118,101,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,112,111,115,105,116,105,118,101,9,103,101,116,95,112,114,105,99,101,20,103,101,116,95,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,37,103,101,116,95,112,114,105,99,101,95,105,110,102,111,95,102,114,111,109,95,112,114,105,99,101,95,105,110,102,111,95,111,98,106,101,99,116,23,103,101,116,95,112,114,105,99,101,95,110,111,95,111,108,100,101,114,95,116,104,97,110,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,17,104,111,116,95,112,111,116,97,116,111,95,118,101,99,116,111,114,3,105,54,52,2,105,100,4,105,110,105,116,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,3,110,101,119,6,111,98,106,101,99,116,6,111,114,97,99,108,101,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,5,112,114,105,99,101,16,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,16,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,16,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,17,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,115,10,112,114,105,99,101,95,105,110,102,111,13,112,114,105,99,101,95,111,114,97,99,108,101,115,4,112,121,116,104,20,114,101,103,105,115,116,101,114,95,116,111,107,101,110,95,112,114,105,99,101,20,115,101,116,95,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,20,115,101,116,95,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,116,97,116,101,3,115,117,105,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,24,117,112,100,97,116,101,95,115,105,110,103,108,101,95,112,114,105,99,101,95,102,101,101,100,3,118,97,97,5,118,97,108,117,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,181,59,15,65,116,16,134,39,251,238,114,226,73,139,88,214,162,113,76,222,213,63,172,83,112,52,194,32,210,99,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,60,0,0,0,0,0,0,0,3,8,16,14,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,5,42,8,13,51,3,50,3,53,11,15,2,13,8,7,55,11,15,2,13,8,1,1,2,3,69,15,27,2,44,3,0,0,0,0,1,11,10,0,17,21,7,1,7,0,10,0,56,0,11,0,56,1,18,0,56,2,2,1,1,0,0,14,32,11,0,15,0,12,5,10,5,10,1,12,2,46,11,2,56,3,4,11,5,15,11,5,1,7,2,39,11,5,11,1,12,3,46,11,3,56,4,12,4,10,4,16,1,20,10,4,16,2,20,11,4,16,3,20,2,2,1,0,0,1,5,11,2,11,1,15,4,21,2,3,1,0,0,1,5,11,2,11,1,15,5,21,2,4,1,0,0,18,58,10,1,15,0,12,11,10,11,10,3,12,7,46,11,7,56,3,32,4,12,5,20,11,11,1,11,1,1,11,6,1,7,3,39,11,2,17,14,12,9,11,1,15,6,12,10,10,10,10,3,12,8,46,11,8,56,5,32,4,35,5,43,11,11,1,11,10,1,11,6,1,7,3,39,11,10,10,3,11,9,56,6,11,11,11,3,11,4,11,5,11,6,17,20,6,232,3,0,0,0,0,0,0,26,18,1,56,7,2,5,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,5,20,35,4,39,5,45,11,8,1,11,0,1,7,4,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,6,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,4,20,35,4,39,5,45,11,8,1,11,0,1,7,5,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,7,1,0,0,26,136,1,11,0,17,8,10,4,16,6,10,5,56,5,4,8,5,20,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,2,39,10,4,15,6,10,5,12,14,46,11,14,56,8,12,24,10,3,46,17,16,12,25,14,25,17,15,12,30,11,24,14,30,33,4,40,5,52,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,6,39,11,1,11,6,10,7,12,16,12,15,46,11,15,11,16,17,28,12,31,10,2,11,31,64,32,1,0,0,0,0,0,0,0,10,7,12,18,12,17,46,11,17,11,18,17,17,12,26,11,2,11,26,10,3,11,8,10,7,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,17,19,12,22,10,7,17,20,6,232,3,0,0,0,0,0,0,26,12,19,11,4,15,0,11,5,56,9,12,23,11,3,11,7,12,13,46,11,13,7,0,17,18,12,29,11,22,56,10,14,29,17,13,12,27,14,27,17,11,12,28,14,29,17,12,12,20,14,20,17,10,12,21,11,28,77,10,23,15,1,21,11,21,51,10,23,15,2,21,11,19,11,23,15,3,21,2,0,4,1,0,1,1,1,2,0,1,0,2,0,3,0],"pool_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,136,1,4,146,1,2,5,148,1,208,1,7,228,2,205,4,8,177,7,32,6,209,7,41,12,250,7,133,12,0,23,0,10,0,24,1,0,7,0,0,18,0,1,0,0,22,0,1,0,0,21,0,1,0,0,19,0,1,0,0,20,0,1,0,0,16,0,1,0,0,17,0,1,0,0,11,2,3,0,0,1,3,4,0,0,15,5,3,0,0,5,3,6,0,0,14,7,3,0,0,4,3,8,0,0,13,9,3,0,0,3,3,9,0,1,2,3,12,0,1,12,12,3,0,2,6,19,20,0,2,7,19,27,0,2,8,19,21,0,2,9,19,1,0,2,25,11,0,0,2,26,25,0,0,2,27,14,0,0,2,28,15,0,0,2,29,13,0,0,2,30,17,18,1,1,26,1,0,1,2,5,8,0,8,0,3,13,10,2,1,10,2,6,8,0,8,0,3,13,2,10,2,5,13,3,8,0,8,0,3,6,13,3,8,0,8,0,3,2,3,8,0,13,10,2,4,8,0,13,2,10,2,3,13,15,2,3,10,2,10,2,10,2,2,7,10,2,13,1,8,0,2,7,10,2,10,2,2,7,10,2,3,2,7,10,2,2,18,10,2,10,2,10,2,10,2,10,2,10,2,3,13,10,2,13,3,3,3,8,0,2,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,17,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,3,3,8,0,2,13,13,8,0,13,2,10,2,10,2,13,10,2,10,2,10,2,10,2,13,10,2,13,3,3,3,2,8,0,13,2,7,10,2,15,9,10,2,10,2,10,2,3,13,15,3,3,2,1,15,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,100,101,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,21,103,101,116,95,100,101,108,101,116,101,95,111,119,110,101,114,95,116,121,112,101,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,16,103,101,116,95,100,101,112,111,115,105,116,95,116,121,112,101,23,103,101,116,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,21,103,101,116,95,115,101,110,100,95,109,101,115,115,97,103,101,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,10,112,111,111,108,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,10,48,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,3,17,21,11,0,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,1,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,2,17,23,13,6,7,2,17,24,14,4,65,1,6,0,0,0,0,0,0,0,0,36,4,46,13,6,14,4,65,1,75,17,21,13,6,11,4,17,25,11,6,2,8,1,0,0,16,172,1,14,0,65,1,12,13,6,0,0,0,0,0,0,0,0,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,1,14,1,17,17,12,8,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,2,14,2,17,17,12,16,11,12,11,11,22,12,12,11,16,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,14,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,3,14,3,17,17,12,18,11,12,11,11,22,12,12,11,18,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,17,11,12,11,11,22,12,12,6,8,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,4,14,4,17,19,12,7,11,12,11,11,22,12,12,6,1,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,5,14,5,17,20,12,15,11,12,11,11,22,12,12,64,1,0,0,0,0,0,0,0,0,12,9,10,13,10,12,36,4,151,1,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,6,14,6,17,17,12,10,11,12,11,11,22,12,12,11,10,52,12,11,14,0,10,12,10,12,10,11,22,56,0,12,9,11,12,11,11,22,12,12,10,15,7,2,33,4,156,1,5,158,1,7,1,39,11,13,11,12,33,4,163,1,5,165,1,7,0,39,11,14,11,17,11,7,11,8,11,15,11,9,2,9,1,0,0,10,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,21,13,6,11,1,17,23,11,2,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,3,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,4,17,23,13,6,7,3,17,24,11,6,2,10,1,0,0,22,152,1,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,15,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,19,12,11,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,17,11,9,11,8,22,12,9,11,17,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,19,12,7,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,20,12,13,11,9,11,8,22,12,9,10,13,7,3,33,4,136,1,5,138,1,7,1,39,11,10,11,9,33,4,143,1,5,145,1,7,0,39,11,15,11,11,11,12,11,16,11,7,11,13,2,11,1,0,0,23,34,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,1,17,21,11,0,17,16,12,4,13,3,14,4,65,1,75,17,21,13,3,11,4,17,25,13,3,7,4,17,24,14,2,65,1,6,0,0,0,0,0,0,0,0,36,4,32,13,3,14,2,65,1,75,17,21,13,3,11,2,17,25,11,3,2,12,1,0,0,24,123,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,5,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,20,12,11,11,9,11,8,22,12,9,64,1,0,0,0,0,0,0,0,0,12,6,10,10,10,9,36,4,104,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,7,11,9,11,8,22,12,9,11,7,52,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,11,9,11,8,22,12,9,10,11,7,4,33,4,109,5,111,7,1,39,11,10,11,9,33,4,116,5,118,7,0,39,11,12,11,5,11,11,11,6,2,13,1,0,0,3,13,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,0,17,21,13,3,11,1,17,22,13,3,11,2,17,24,11,3,2,14,1,0,0,26,64,14,0,65,1,12,8,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,1,14,1,17,17,12,5,11,7,11,4,22,12,7,6,32,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,2,14,2,17,18,12,6,11,7,11,4,22,12,7,6,1,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,3,14,3,17,20,12,9,11,7,11,4,22,12,7,11,8,11,7,33,4,58,5,60,7,0,39,11,5,11,6,11,9,2,0],"pool_manager":[161,28,235,11,6,0,0,0,12,1,0,22,2,22,66,3,88,199,1,4,159,2,62,5,221,2,206,2,7,171,5,144,8,8,187,13,96,6,155,14,138,1,10,165,15,108,12,145,16,154,13,13,171,29,32,15,203,29,4,0,62,0,28,0,30,0,36,1,21,1,58,2,32,2,57,2,74,2,76,2,77,0,9,12,0,0,1,4,0,0,7,4,0,0,4,4,0,0,8,4,0,0,6,4,0,0,0,3,0,0,10,3,0,1,2,7,0,3,3,0,0,4,11,7,0,5,5,7,1,0,0,7,14,4,0,8,12,12,2,7,1,4,1,10,13,2,0,0,51,0,1,0,0,66,2,1,0,0,65,3,1,0,0,71,4,1,0,0,69,5,1,0,0,70,4,1,0,0,47,6,7,0,0,41,8,9,0,0,44,6,10,0,0,37,11,12,0,0,48,6,12,0,0,43,8,12,0,0,42,8,12,0,0,45,6,12,0,0,46,8,12,0,0,38,1,12,0,0,39,1,12,0,0,35,13,14,0,0,34,15,16,0,0,33,17,16,0,0,81,1,18,0,0,16,19,20,0,0,67,19,20,0,1,40,46,9,0,2,24,49,12,0,2,25,49,12,0,2,26,20,12,0,5,56,1,47,1,0,5,73,28,47,1,0,6,29,28,1,1,3,7,55,0,21,0,8,15,31,1,2,7,4,8,22,41,42,2,7,4,8,23,35,36,2,7,4,8,27,41,16,2,7,4,8,55,0,23,2,7,4,9,72,28,1,1,8,35,22,35,24,35,25,35,26,36,27,35,30,31,24,31,26,35,33,31,22,31,25,33,26,33,24,31,30,33,30,32,26,32,25,32,24,32,22,34,33,32,33,32,30,28,32,27,32,34,24,34,25,33,22,31,33,33,33,29,50,29,51,1,7,8,14,0,5,6,8,9,7,8,0,8,10,13,7,8,14,4,6,8,9,7,8,0,8,8,13,4,6,8,9,7,8,0,8,8,15,4,6,8,9,7,8,0,13,15,2,7,8,0,13,1,10,8,8,2,7,8,0,8,8,1,13,1,8,10,3,6,8,0,13,13,1,15,3,7,8,0,13,13,1,11,11,1,8,8,2,6,8,0,13,1,1,2,6,8,0,8,8,1,8,3,4,7,8,0,8,8,13,15,2,15,15,1,8,12,2,13,8,1,1,11,13,2,9,0,9,1,2,13,8,2,2,8,8,13,2,13,10,8,8,1,8,0,1,9,0,8,13,8,10,8,3,11,13,2,8,8,8,4,8,1,7,11,13,2,13,8,1,8,2,7,11,13,2,13,8,2,2,8,8,8,4,3,7,11,13,2,9,0,9,1,9,0,9,1,1,8,8,2,13,8,3,3,13,8,8,7,8,5,2,7,11,13,2,9,0,9,1,9,0,1,7,9,1,4,8,8,13,7,8,2,7,8,4,2,13,7,8,2,3,8,8,13,7,8,4,2,13,13,2,6,11,13,2,9,0,9,1,9,0,1,6,9,1,2,8,8,8,8,2,15,6,11,13,2,13,8,3,4,8,8,3,3,10,8,8,1,6,8,8,1,11,11,1,9,0,9,8,8,13,15,7,11,13,2,13,8,3,7,8,3,13,15,7,8,2,7,8,4,6,15,15,15,15,15,15,1,8,6,1,8,7,12,65,100,100,76,105,113,117,105,100,105,116,121,7,65,112,112,73,110,102,111,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,9,76,105,113,117,105,100,105,116,121,6,79,112,116,105,111,110,11,80,111,111,108,67,97,116,97,108,111,103,8,80,111,111,108,73,110,102,111,13,80,111,111,108,76,105,113,117,105,100,105,116,121,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,15,82,101,109,111,118,101,76,105,113,117,105,100,105,116,121,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,13,97,100,100,95,108,105,113,117,105,100,105,116,121,7,97,108,112,104,97,95,49,6,97,109,111,117,110,116,9,97,112,112,95,105,110,102,111,115,13,97,112,112,95,108,105,113,117,105,100,105,116,121,5,97,115,99,105,105,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,5,101,118,101,110,116,18,101,120,105,115,116,95,99,101,114,116,97,105,110,95,112,111,111,108,13,101,120,105,115,116,95,112,111,111,108,95,105,100,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,100,101,102,97,117,108,116,95,97,108,112,104,97,95,49,20,103,101,116,95,100,101,102,97,117,108,116,95,108,97,109,98,100,97,95,49,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,24,103,101,116,95,112,111,111,108,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,112,111,111,108,95,110,97,109,101,95,98,121,95,105,100,21,103,101,116,95,112,111,111,108,95,116,111,116,97,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,115,95,98,121,95,105,100,19,103,101,116,95,116,111,107,101,110,95,108,105,113,117,105,100,105,116,121,2,105,100,11,105,100,95,116,111,95,112,111,111,108,115,4,105,110,105,116,8,108,97,109,98,100,97,95,49,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,110,97,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,12,112,111,111,108,95,97,100,100,114,101,115,115,12,112,111,111,108,95,99,97,116,97,108,111,103,10,112,111,111,108,95,105,110,102,111,115,12,112,111,111,108,95,109,97,110,97,103,101,114,10,112,111,111,108,95,116,111,95,105,100,5,112,111,111,108,115,13,114,101,103,105,115,116,101,114,95,112,111,111,108,16,114,101,103,105,115,116,101,114,95,112,111,111,108,95,105,100,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,7,114,101,115,101,114,118,101,21,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,97,108,112,104,97,22,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,108,97,109,98,100,97,15,115,101,116,95,112,111,111,108,95,119,101,105,103,104,116,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,116,97,98,108,101,12,116,111,116,97,108,95,119,101,105,103,104,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,119,101,105,103,104,116,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,14,122,101,114,111,95,108,105,113,117,105,100,105,116,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,0,88,241,76,176,44,241,78,240,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,37,164,0,10,139,202,34,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,0,2,4,49,8,12,19,11,13,2,13,8,1,61,11,13,2,13,8,2,60,8,5,1,2,1,20,11,13,2,13,8,3,2,2,5,54,8,10,68,8,3,17,15,75,15,64,11,13,2,8,8,8,4,3,2,1,78,15,4,2,4,78,15,52,15,30,15,79,15,5,2,2,63,11,13,2,8,8,13,50,11,13,2,13,10,8,8,6,2,3,59,8,8,18,15,31,15,7,2,3,59,8,8,18,15,30,15,0,0,0,0,1,14,10,0,17,30,10,0,56,0,10,0,56,1,10,0,56,2,11,0,56,3,18,5,18,0,56,4,2,1,1,0,0,29,54,10,1,10,3,12,5,46,11,5,17,18,32,4,9,5,15,11,1,1,11,4,1,7,2,39,10,1,15,0,12,12,11,2,12,6,17,20,12,7,10,4,56,5,12,8,11,6,11,7,7,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,8,18,2,12,11,11,12,10,3,11,11,56,6,10,1,15,1,15,2,10,3,64,32,0,0,0,0,0,0,0,0,56,7,11,1,15,3,12,10,11,4,56,8,18,1,12,9,11,10,11,3,11,9,56,9,2,2,1,0,0,34,52,10,1,10,3,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,10,1,10,2,12,5,46,11,5,17,19,32,4,21,5,25,11,1,1,7,4,39,10,1,15,1,12,6,10,6,15,4,10,2,10,3,56,10,11,6,15,2,10,3,56,11,10,2,68,32,11,1,15,0,11,3,56,12,15,5,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,4,56,13,2,3,1,0,0,37,43,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,12,6,10,6,15,5,11,2,56,14,12,7,10,6,16,6,20,10,7,16,7,20,23,10,3,22,11,6,15,6,21,11,3,11,7,15,7,21,2,4,1,0,0,38,22,10,1,10,2,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,11,1,15,0,11,2,56,12,12,5,11,3,11,5,15,8,21,2,5,1,0,0,39,29,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,15,5,11,2,56,14,12,6,11,3,11,6,15,9,21,2,6,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,1,15,2,11,1,12,3,46,11,3,56,15,20,2,7,1,0,0,43,22,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,11,0,15,1,15,4,11,1,12,3,46,11,3,56,16,20,2,8,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,0,11,1,12,3,46,11,3,56,17,16,10,20,2,9,1,0,0,44,32,10,0,10,1,17,18,4,5,5,9,11,0,1,7,3,39,11,0,16,3,11,1,56,18,16,11,12,4,10,4,10,2,56,19,4,26,11,4,11,2,56,20,16,12,20,12,3,5,30,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,10,1,0,0,9,20,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,13,16,12,20,2,11,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,14,20,2,12,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,15,20,2,13,1,0,0,9,19,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,6,20,2,14,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,7,20,2,15,1,0,0,1,2,7,0,2,16,1,0,0,1,2,7,1,2,17,1,0,0,45,34,11,0,11,1,17,6,12,6,14,6,65,32,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,32,5,14,14,6,10,4,66,32,20,12,3,14,3,17,23,10,2,33,4,27,11,3,56,22,2,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,9,56,23,2,18,1,0,0,1,5,11,0,16,0,11,1,56,24,2,19,1,0,0,1,6,11,0,16,1,16,4,11,1,56,25,2,20,1,0,0,1,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,2,21,3,0,0,48,119,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,12,16,15,20,10,12,16,9,20,17,25,12,10,10,3,10,10,22,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,32,4,73,11,7,11,2,10,6,18,3,56,27,5,85,11,7,11,2,56,28,12,8,10,8,16,12,20,10,6,22,11,8,15,12,21,10,11,16,13,16,12,20,10,3,22,11,11,15,13,15,12,21,10,12,16,14,20,10,3,22,10,12,15,14,21,10,12,16,15,20,10,10,23,11,12,15,15,21,11,1,11,3,10,10,18,6,56,29,11,6,11,10,2,22,3,0,0,48,151,1,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,12,16,14,20,10,3,38,4,33,5,41,11,0,1,11,12,1,11,11,1,7,8,39,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,11,16,8,20,10,12,16,9,20,17,24,12,10,10,3,10,10,23,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,4,82,5,90,11,12,1,11,11,1,11,7,1,7,6,39,11,7,11,2,56,28,12,8,10,8,16,12,20,10,3,38,4,101,5,109,11,12,1,11,11,1,11,8,1,7,7,39,10,8,16,12,20,10,3,23,11,8,15,12,21,10,11,16,13,16,12,20,10,6,23,11,11,15,13,15,12,21,10,12,16,14,20,10,6,23,10,12,15,14,21,10,12,16,15,20,10,10,22,11,12,15,15,21,11,1,11,3,10,10,18,7,56,30,11,6,11,10,2,0,2,0,3,5,1,0,1,5,0,2,4,2,3,4,3,2,2,4,1,2,0,1,0,3,0,2,1,4,0,4,2,0,53,0,80,0],"rates":[161,28,235,11,6,0,0,0,8,1,0,6,2,6,4,3,10,70,5,80,48,7,128,1,185,2,8,185,3,32,6,217,3,68,12,157,4,128,5,0,13,0,11,0,16,1,0,8,0,0,6,0,1,0,0,2,0,1,0,0,5,2,1,0,0,1,3,1,0,0,3,4,1,0,0,4,4,1,0,1,7,6,1,0,1,8,6,3,0,1,9,6,1,0,1,10,6,1,0,2,12,7,1,0,2,14,5,1,0,2,15,7,1,0,2,17,7,1,0,3,7,8,0,13,15,1,15,4,7,8,0,13,15,15,4,15,15,15,15,3,15,15,15,0,2,7,8,0,13,2,15,15,6,15,15,15,15,15,15,7,15,15,15,15,15,15,15,7,83,116,111,114,97,103,101,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,21,99,97,108,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,3,109,105,110,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,128,81,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,3,29,10,0,10,1,17,8,12,6,11,0,11,1,17,6,12,4,11,6,11,4,17,13,12,5,10,5,10,2,22,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,27,10,5,11,5,11,2,22,17,12,12,3,11,3,2,1,1,0,0,8,39,10,0,10,1,11,2,17,0,12,8,11,0,11,1,17,7,12,7,12,6,12,5,12,4,10,8,10,7,35,4,23,11,4,11,8,11,5,17,13,22,12,3,5,37,11,4,11,5,22,11,6,11,8,10,7,23,17,11,11,7,23,17,12,17,13,22,12,3,11,3,2,2,1,0,0,7,17,10,0,10,1,11,3,17,0,12,5,11,0,11,1,17,9,12,4,11,2,11,5,17,11,11,4,23,17,13,17,13,2,3,1,0,0,7,20,11,0,11,1,23,7,1,17,10,12,4,7,1,10,4,23,12,5,11,2,11,5,24,11,3,11,4,24,22,7,1,26,2,4,1,0,0,9,69,11,0,11,1,23,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,10,17,11,2,10,5,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,6,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,23,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,7,5,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,2,10,2,17,13,7,0,7,0,24,26,12,4,10,4,10,2,17,13,7,0,26,12,3,10,5,10,6,24,11,4,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,10,5,11,6,24,11,7,24,11,3,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,9,17,11,11,2,11,5,24,7,0,26,22,11,8,22,11,9,22,2,5,1,0,0,1,12,11,2,11,0,11,1,23,24,7,0,26,12,3,17,11,11,3,22,2,0],"ray_math":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,40,5,42,13,7,55,59,8,114,32,6,146,1,146,1,12,164,2,247,5,0,7,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,4,2,1,0,0,1,2,1,0,0,2,2,1,0,0,6,1,1,0,0,0,1,3,0,0,1,15,2,15,15,1,2,4,15,2,15,15,4,108,111,103,50,3,109,97,120,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,208,121,0,161,63,121,92,118,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,249,214,165,42,128,81,101,243,159,91,61,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,1,0,0,0,2,7,0,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,10,11,0,11,1,24,7,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,7,0,26,2,3,1,0,0,0,10,11,0,7,0,24,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,11,1,26,2,4,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,6,1,0,0,4,59,10,0,7,0,38,4,5,5,7,7,4,39,10,0,7,0,26,17,7,12,2,10,2,77,7,0,24,12,3,11,0,11,2,48,12,4,10,4,7,0,33,4,27,11,3,2,7,1,12,1,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,57,5,34,10,4,11,4,24,7,0,26,12,4,10,4,7,2,38,4,52,11,3,10,1,22,12,3,11,4,49,1,48,12,4,11,1,49,1,48,12,1,5,29,11,3,2,7,1,0,0,3,112,49,0,12,1,10,0,49,128,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,16,11,0,49,128,48,12,0,11,1,49,128,22,12,1,10,0,49,64,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,30,11,0,49,64,48,12,0,11,1,49,64,22,12,1,10,0,49,32,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,44,11,0,49,32,48,12,0,11,1,49,32,22,12,1,10,0,49,16,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,58,11,0,49,16,48,12,0,11,1,49,16,22,12,1,10,0,49,8,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,72,11,0,49,8,48,12,0,11,1,49,8,22,12,1,10,0,49,4,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,0,49,4,48,12,0,11,1,49,4,22,12,1,10,0,49,2,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,100,11,0,49,2,48,12,0,11,1,49,2,22,12,1,11,0,49,1,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,110,11,1,49,1,22,12,1,11,1,2,0],"scaled_balance":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,25,5,29,6,7,35,75,8,110,32,12,142,1,39,0,6,0,4,0,0,0,1,0,0,2,0,1,0,0,1,0,1,0,1,3,0,1,0,1,5,0,1,0,2,15,15,1,15,0,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,2,4,11,0,11,1,17,4,2,1,1,0,0,2,4,11,0,11,1,17,3,2,2,1,0,0,2,4,11,0,11,1,17,3,2,0],"serde":[161,28,235,11,6,0,0,0,9,1,0,12,2,12,8,3,20,167,1,4,187,1,12,5,199,1,148,1,7,219,2,211,4,8,174,7,96,6,142,8,20,12,162,8,157,35,0,23,1,4,1,6,1,36,1,37,2,2,1,0,7,0,3,1,7,0,0,32,0,1,0,0,28,2,1,0,0,31,3,1,0,0,26,4,1,0,0,29,5,1,0,0,19,6,6,0,0,5,6,6,0,0,27,4,1,0,0,30,5,1,0,0,33,7,1,0,0,24,8,1,0,0,25,9,1,1,0,0,34,7,1,0,0,14,10,6,0,0,10,10,11,0,0,13,10,12,0,0,8,10,13,0,0,11,10,14,0,0,9,10,13,0,0,12,10,14,0,0,7,10,15,0,0,18,10,12,0,0,15,10,16,0,0,38,17,18,1,1,0,39,19,20,1,3,1,20,28,16,0,2,35,27,16,1,0,3,17,1,30,1,0,3,21,30,28,0,4,3,25,1,1,0,4,22,24,1,1,0,5,16,16,15,0,30,6,29,6,26,15,27,29,23,6,23,29,2,7,10,2,2,0,2,7,10,2,13,2,7,10,2,3,2,7,10,2,4,2,7,10,2,15,1,2,2,7,10,2,10,2,2,7,10,2,5,1,7,10,2,1,6,10,2,1,13,1,3,1,4,1,15,1,5,1,10,2,3,6,10,9,0,3,3,1,10,9,0,2,6,10,9,0,9,0,1,10,10,9,0,2,1,2,3,1,1,2,2,4,10,2,1,7,10,9,0,2,7,10,9,0,10,9,0,2,15,10,2,1,6,9,0,1,8,0,1,9,0,1,8,1,2,4,3,2,15,3,3,10,2,3,3,3,1,3,10,9,0,3,3,10,10,9,0,3,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,6,97,112,112,101,110,100,5,97,115,99,105,105,16,97,115,99,105,105,95,116,111,95,104,101,120,95,115,116,114,3,98,99,115,19,100,101,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,16,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,29,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,29,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,30,100,101,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,17,103,101,116,95,118,101,99,116,111,114,95,108,101,110,103,116,104,16,104,101,120,95,115,116,114,95,116,111,95,97,115,99,105,105,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,7,114,101,118,101,114,115,101,5,115,101,114,100,101,17,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,14,115,101,114,105,97,108,105,122,101,95,116,121,112,101,14,115,101,114,105,97,108,105,122,101,95,117,49,50,56,27,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,27,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,28,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,6,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,12,118,101,99,116,111,114,95,115,112,108,105,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,68,6,2,1,1,0,0,1,15,10,0,10,1,49,8,48,72,255,0,28,51,17,0,11,0,11,1,72,255,0,28,51,17,0,2,2,1,0,0,1,63,10,0,10,1,49,56,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,6,255,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,6,255,0,0,0,0,0,0,0,28,51,17,0,2,3,1,0,0,1,127,10,0,10,1,49,120,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,4,1,0,0,1,255,1,10,0,10,1,49,248,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,240,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,232,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,224,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,216,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,208,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,200,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,192,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,184,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,176,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,168,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,160,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,152,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,144,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,136,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,128,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,120,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,5,1,0,0,21,31,10,0,49,0,38,4,9,10,0,49,9,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,22,12,2,5,29,10,0,49,15,37,4,23,5,25,7,1,39,11,0,49,87,22,12,2,11,2,2,6,1,0,0,22,40,10,0,49,48,38,4,9,10,0,49,57,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,3,5,38,10,0,49,97,38,4,27,10,0,49,102,37,12,2,5,29,9,12,2,11,2,4,32,5,34,7,1,39,11,0,49,87,23,12,3,11,3,2,7,1,0,0,23,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,8,1,0,0,26,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,9,1,0,0,1,4,11,0,11,1,56,1,2,10,1,0,0,16,17,14,1,56,2,12,2,14,2,65,6,6,32,0,0,0,0,0,0,0,33,4,9,5,13,11,0,1,7,0,39,11,0,11,2,56,1,2,11,1,0,0,28,8,56,3,17,28,12,1,11,0,11,1,17,25,17,9,2,12,1,0,0,12,17,14,1,65,6,12,2,10,2,6,0,0,0,0,0,0,0,0,33,4,10,11,0,1,2,10,0,11,2,17,2,11,0,11,1,17,9,2,13,1,0,0,1,15,10,0,65,6,6,1,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,6,0,0,0,0,0,0,0,0,66,6,20,2,14,1,0,0,1,24,10,0,65,6,6,2,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,75,49,8,47,11,0,6,1,0,0,0,0,0,0,0,66,6,20,75,22,2,15,1,0,0,1,72,10,0,65,6,6,8,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,52,49,56,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,52,49,48,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,52,49,40,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,52,49,32,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,52,49,24,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,52,49,16,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,52,49,8,47,22,11,0,6,7,0,0,0,0,0,0,0,66,6,20,52,22,2,16,1,0,0,1,136,1,10,0,65,6,6,16,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,53,49,120,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,53,49,112,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,53,49,104,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,53,49,96,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,53,49,88,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,53,49,80,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,53,49,72,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,53,49,64,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,53,49,56,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,53,49,48,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,53,49,40,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,53,49,32,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,53,49,24,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,53,49,16,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,53,49,8,47,22,11,0,6,15,0,0,0,0,0,0,0,66,6,20,53,22,2,17,1,0,0,1,136,2,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,77,49,248,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,77,49,240,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,77,49,232,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,77,49,224,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,77,49,216,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,77,49,208,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,77,49,200,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,77,49,192,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,77,49,184,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,77,49,176,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,77,49,168,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,77,49,160,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,77,49,152,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,77,49,144,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,77,49,136,47,22,10,0,6,15,0,0,0,0,0,0,0,66,6,20,77,49,128,47,22,10,0,6,16,0,0,0,0,0,0,0,66,6,20,77,49,120,47,22,10,0,6,17,0,0,0,0,0,0,0,66,6,20,77,49,112,47,22,10,0,6,18,0,0,0,0,0,0,0,66,6,20,77,49,104,47,22,10,0,6,19,0,0,0,0,0,0,0,66,6,20,77,49,96,47,22,10,0,6,20,0,0,0,0,0,0,0,66,6,20,77,49,88,47,22,10,0,6,21,0,0,0,0,0,0,0,66,6,20,77,49,80,47,22,10,0,6,22,0,0,0,0,0,0,0,66,6,20,77,49,72,47,22,10,0,6,23,0,0,0,0,0,0,0,66,6,20,77,49,64,47,22,10,0,6,24,0,0,0,0,0,0,0,66,6,20,77,49,56,47,22,10,0,6,25,0,0,0,0,0,0,0,66,6,20,77,49,48,47,22,10,0,6,26,0,0,0,0,0,0,0,66,6,20,77,49,40,47,22,10,0,6,27,0,0,0,0,0,0,0,66,6,20,77,49,32,47,22,10,0,6,28,0,0,0,0,0,0,0,66,6,20,77,49,24,47,22,10,0,6,29,0,0,0,0,0,0,0,66,6,20,77,49,16,47,22,10,0,6,30,0,0,0,0,0,0,0,66,6,20,77,49,8,47,22,11,0,6,31,0,0,0,0,0,0,0,66,6,20,77,22,2,18,1,0,0,31,29,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,53,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,19,1,0,0,32,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,77,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,20,1,0,0,1,14,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,20,17,31,2,21,1,0,0,16,8,11,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,2,22,1,0,0,33,46,10,0,65,6,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,64,6,0,0,0,0,0,0,0,0,2,10,3,6,8,0,0,0,0,0,0,0,36,4,16,5,20,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,12,2,11,3,10,2,6,8,0,0,0,0,0,0,0,22,33,4,35,5,39,11,0,1,7,0,39,11,0,6,8,0,0,0,0,0,0,0,11,2,6,8,0,0,0,0,0,0,0,22,56,4,2,23,1,0,0,34,43,10,1,10,2,35,4,10,10,2,10,0,65,29,37,12,3,5,12,9,12,3,11,3,4,15,5,19,11,0,1,7,0,39,64,29,0,0,0,0,0,0,0,0,12,5,11,1,12,4,10,4,10,2,35,4,39,5,28,13,5,10,0,10,4,66,29,20,68,29,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,23,11,0,1,11,5,2,24,1,0,0,35,53,64,18,0,0,0,0,0,0,0,0,12,3,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,29,35,4,38,5,12,10,0,10,2,66,29,20,10,1,33,4,33,10,4,10,2,35,4,29,13,3,10,0,11,4,10,2,56,5,68,18,10,2,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,10,4,10,2,35,4,49,13,3,11,0,11,4,11,2,56,5,68,18,5,51,11,0,1,11,3,2,0],"system_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,71,4,81,2,5,83,78,7,161,1,150,2,8,183,3,32,6,215,3,26,12,241,3,169,2,0,16,0,6,0,11,1,0,7,0,0,9,0,1,0,0,10,0,1,0,0,7,2,3,0,0,1,3,2,0,1,2,3,7,0,1,8,7,3,0,2,3,13,14,0,2,4,13,15,0,2,5,13,1,0,2,12,5,0,0,2,13,6,0,0,2,14,9,0,0,2,15,8,0,0,2,17,11,12,1,1,13,1,0,1,2,4,13,3,8,0,2,1,10,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,12,10,2,10,2,10,2,10,2,8,0,13,3,3,3,3,13,2,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,11,68,111,108,97,65,100,100,114,101,115,115,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,19,101,110,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,115,121,115,116,101,109,95,99,111,100,101,99,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,4,24,64,1,0,0,0,0,0,0,0,0,12,5,13,5,11,0,17,9,13,5,11,1,17,10,11,2,17,5,12,4,13,5,14,4,65,1,75,17,9,13,5,11,4,17,12,13,5,11,3,17,11,11,5,2,3,1,0,0,10,96,14,0,65,1,12,9,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,1,14,1,17,6,12,11,11,8,11,7,22,12,8,6,8,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,2,14,2,17,7,12,10,11,8,11,7,22,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,3,14,3,17,6,12,6,11,8,11,7,22,12,8,11,6,52,12,7,14,0,10,8,10,8,10,7,22,56,0,17,4,12,5,11,8,11,7,22,12,8,6,1,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,4,14,4,17,8,12,12,11,8,11,7,22,12,8,11,9,11,8,33,4,89,5,91,7,0,39,11,11,11,10,11,5,11,12,2,0],"system_core_storage":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,24,3,36,26,4,62,2,5,64,35,7,99,252,1,8,223,2,64,10,159,3,9,12,168,3,34,13,202,3,2,15,204,3,2,0,16,0,7,0,8,1,13,1,18,1,19,0,2,8,0,1,0,12,0,1,3,12,0,2,1,0,0,3,5,4,0,5,4,2,0,0,11,0,1,0,0,9,2,3,0,1,14,0,6,0,3,12,4,5,0,4,15,8,1,1,8,4,7,3,6,8,3,7,8,2,7,8,5,0,1,6,8,0,1,6,8,1,1,7,8,5,1,8,4,1,8,1,1,8,0,1,9,0,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,7,83,116,111,114,97,103,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,3,110,101,119,6,111,98,106,101,99,116,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,10,8,4,6,8,1,0,1,0,0,1,9,10,2,17,3,11,0,11,1,11,2,17,2,18,0,56,0,2,1,3,0,0,1,3,11,0,16,0,2,0,1,0,17,0],"system_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,24,2,24,40,3,64,71,4,135,1,2,5,137,1,117,7,254,1,155,4,8,153,6,96,6,249,6,10,10,131,7,17,12,148,7,191,1,0,33,0,10,0,16,0,19,0,31,0,32,0,38,0,39,1,14,1,18,1,34,2,30,0,7,3,0,1,0,12,0,2,3,7,0,3,4,8,0,5,6,8,0,6,9,12,0,7,2,12,0,8,1,8,0,10,8,2,0,11,5,12,0,0,11,0,1,0,0,35,0,1,0,2,22,13,8,0,2,23,13,14,0,3,13,3,1,0,4,15,8,9,0,4,21,1,10,0,4,24,1,10,0,5,20,4,5,0,6,11,12,1,0,6,27,11,1,0,6,35,12,1,0,7,26,6,7,0,9,17,16,1,1,3,13,15,8,6,8,3,7,8,5,7,8,9,7,8,6,6,8,4,10,2,6,8,7,7,8,8,0,6,10,2,8,2,2,3,8,2,13,1,6,8,3,1,6,8,4,1,6,8,1,6,7,8,9,7,8,6,6,8,1,10,2,6,8,7,7,8,8,2,8,2,10,2,1,10,2,4,13,3,8,2,2,1,2,2,7,8,5,8,2,3,7,8,5,8,2,8,2,1,6,8,2,1,13,1,8,0,1,9,0,6,10,2,2,3,8,2,13,8,2,6,65,112,112,67,97,112,5,67,108,111,99,107,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,5,83,116,97,116,101,7,83,116,111,114,97,103,101,15,83,121,115,116,101,109,67,111,114,101,69,118,101,110,116,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,11,97,112,112,95,109,97,110,97,103,101,114,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,110,111,110,99,101,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,12,115,121,115,116,101,109,95,99,111,100,101,99,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,0,2,6,25,3,28,10,2,29,13,37,13,36,10,2,12,2,0,1,4,0,2,51,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,12,11,8,17,5,12,10,12,9,12,11,12,13,10,10,17,6,33,4,23,5,27,11,1,1,7,0,39,10,12,10,9,33,4,35,11,1,10,12,17,10,5,39,11,1,10,12,10,9,17,9,11,11,14,12,17,2,11,13,14,9,17,3,14,9,17,2,11,10,18,0,56,0,2,1,1,4,0,17,43,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,11,11,8,17,5,12,9,12,13,12,10,12,12,10,9,17,7,33,4,23,5,27,11,1,1,7,0,39,11,1,10,11,10,13,17,11,11,10,14,11,17,2,11,12,14,13,17,3,14,13,17,2,11,9,18,0,56,0,2,0],"system_portal":[161,28,235,11,6,0,0,0,10,1,0,18,2,18,28,3,46,82,4,128,1,4,5,132,1,84,7,216,1,208,3,8,168,5,64,10,232,5,22,12,254,5,187,1,13,185,7,2,0,30,0,13,0,16,0,29,0,37,1,15,1,25,1,31,1,32,0,3,8,0,0,2,3,0,1,0,7,0,2,1,8,0,4,6,12,0,6,5,4,0,8,4,2,0,0,21,0,1,0,0,18,2,3,0,0,8,4,1,0,0,34,4,1,0,1,11,11,12,0,1,12,13,12,0,2,10,9,1,0,3,17,1,16,0,3,19,1,16,0,4,7,15,1,0,4,26,14,1,0,4,33,15,1,0,5,14,7,1,1,3,6,22,0,5,0,7,28,7,1,1,8,8,27,10,11,0,14,6,12,17,1,7,8,6,0,1,7,8,0,1,3,6,6,8,3,7,8,0,7,8,4,13,10,2,7,8,6,1,8,5,1,8,0,1,9,0,3,8,2,5,8,2,1,6,8,3,1,6,8,6,1,5,1,8,2,2,13,10,2,2,7,8,4,8,2,3,7,8,4,8,2,8,2,1,2,1,8,1,3,5,8,2,8,2,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,83,121,115,116,101,109,76,111,99,97,108,69,118,101,110,116,12,83,121,115,116,101,109,80,111,114,116,97,108,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,7,98,105,110,100,105,110,103,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,2,105,100,4,105,110,105,116,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,6,111,98,106,101,99,116,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,115,121,115,116,101,109,95,99,111,100,101,99,13,115,121,115,116,101,109,95,112,111,114,116,97,108,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,117,110,98,105,110,100,105,110,103,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,20,8,5,23,3,1,2,5,24,3,27,5,36,13,35,10,2,9,2,0,0,0,0,1,6,11,0,17,13,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,4,0,8,34,11,0,17,6,11,5,46,17,15,12,7,10,7,17,4,12,8,10,3,10,4,17,5,12,6,10,8,10,6,33,4,21,11,2,11,8,17,10,5,25,11,2,11,8,11,6,17,9,11,1,17,1,11,7,11,3,11,4,17,7,18,1,56,1,2,3,1,4,0,18,26,11,0,17,6,11,5,46,17,15,12,6,10,6,17,4,12,8,10,3,10,4,17,5,12,7,11,2,11,8,11,7,17,11,11,1,17,1,11,6,11,3,11,4,17,8,18,1,56,1,2,0,1,0],"user_manager":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,40,3,58,138,1,4,196,1,42,5,238,1,128,2,7,238,3,161,5,8,143,9,96,6,239,9,60,10,171,10,49,12,220,10,247,4,13,211,15,8,15,219,15,8,0,48,0,15,0,20,1,49,2,19,2,31,2,39,2,40,2,41,0,8,12,0,0,7,4,0,0,0,3,0,0,6,3,0,1,1,7,0,2,2,0,0,5,5,4,0,6,3,12,2,7,1,4,1,8,4,2,0,0,26,0,1,0,0,33,2,1,0,0,43,3,1,0,0,22,4,5,0,0,23,6,7,0,0,32,4,8,0,0,27,4,9,0,0,34,10,1,0,0,10,11,1,0,0,42,11,1,0,1,21,28,29,0,1,44,30,8,0,3,25,37,38,1,0,3,35,39,18,1,0,4,18,18,1,1,3,5,30,0,12,0,6,9,21,1,2,7,4,6,11,20,25,2,7,4,6,12,22,35,2,7,4,6,14,20,9,2,7,4,6,29,32,5,2,7,4,6,30,0,14,2,7,4,6,35,22,23,2,7,4,7,36,18,1,1,8,21,13,21,15,21,16,23,17,19,16,16,16,22,16,19,13,17,13,19,15,17,15,17,16,20,15,16,13,16,15,14,33,18,15,12,8,22,13,13,8,14,40,1,7,8,8,0,4,6,8,5,7,8,0,13,13,3,6,8,5,7,8,0,13,2,6,8,0,8,4,1,3,2,6,8,0,3,1,10,8,4,1,8,4,1,1,2,7,8,0,8,4,3,7,8,0,8,4,8,4,1,8,6,2,8,4,3,1,11,7,2,9,0,9,1,2,3,10,8,4,2,13,13,1,8,0,1,9,0,2,13,7,11,7,2,13,13,2,6,11,7,2,9,0,9,1,9,0,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,9,1,2,8,4,6,8,1,1,6,9,1,1,6,8,1,3,8,4,6,11,7,2,13,13,13,1,6,8,4,1,13,2,8,4,13,6,8,4,8,4,3,8,4,10,8,4,7,8,1,1,6,11,7,2,9,0,9,1,1,8,2,7,8,4,8,4,8,4,8,4,3,7,10,8,4,7,8,1,1,7,9,1,10,8,4,8,4,8,4,6,8,4,3,3,3,8,4,7,10,8,4,7,8,1,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,1,8,3,8,66,105,110,100,85,115,101,114,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,10,85,110,98,105,110,100,85,115,101,114,18,85,115,101,114,65,100,100,114,101,115,115,67,97,116,97,108,111,103,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,97,100,100,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,97,105,110,95,105,100,95,116,111,95,103,114,111,117,112,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,17,100,111,108,97,95,117,115,101,114,95,97,100,100,114,101,115,115,12,100,111,108,97,95,117,115,101,114,95,105,100,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,18,103,101,116,95,117,115,101,114,95,97,100,100,114,101,115,115,101,115,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,16,112,114,111,99,101,115,115,95,103,114,111,117,112,95,105,100,22,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,115,121,115,116,101,109,95,112,111,114,116,97,108,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,24,117,110,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,115,101,114,95,97,100,100,114,101,115,115,95,99,97,116,97,108,111,103,23,117,115,101,114,95,97,100,100,114,101,115,115,95,116,111,95,117,115,101,114,95,105,100,20,117,115,101,114,95,105,100,95,116,111,95,97,100,100,114,101,115,115,101,115,12,117,115,101,114,95,109,97,110,97,103,101,114,6,118,101,99,116,111,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,3,24,8,6,45,8,1,13,11,7,2,13,13,1,2,2,46,11,7,2,8,4,3,47,11,7,2,3,10,8,4,2,2,2,16,8,4,17,3,3,2,2,16,8,4,17,3,0,0,0,0,1,12,10,0,17,15,10,0,56,0,10,0,56,1,18,1,11,0,56,2,18,0,56,3,2,1,1,0,0,19,21,11,1,15,0,12,5,10,5,10,2,12,4,46,11,4,56,4,32,4,12,5,16,11,5,1,7,3,39,11,5,11,2,11,3,56,5,2,2,1,0,0,19,20,11,1,15,0,12,4,10,4,10,2,12,3,46,11,3,56,4,4,11,5,15,11,4,1,7,4,39,11,4,11,2,56,6,1,2,3,1,0,0,24,23,10,0,11,1,17,5,12,2,11,0,16,1,12,3,10,3,16,2,10,2,56,7,4,13,5,17,11,3,1,7,1,39,11,3,16,2,11,2,56,8,20,2,4,1,0,0,26,19,11,0,16,1,12,2,10,2,16,3,10,1,56,9,4,9,5,13,11,2,1,7,1,39,11,2,16,3,11,1,56,10,20,2,5,1,0,0,27,24,14,1,17,10,12,4,11,0,16,0,12,3,10,3,10,4,56,4,4,18,11,1,11,3,11,4,56,11,20,17,11,12,2,5,22,11,3,1,11,1,12,2,11,2,2,6,1,0,0,8,10,10,0,11,1,17,5,12,2,11,0,16,1,16,2,11,2,56,7,2,7,3,0,0,31,50,10,0,11,1,12,2,46,11,2,17,5,12,5,11,0,15,1,12,7,10,7,15,2,10,5,12,3,46,11,3,56,7,32,4,20,5,24,11,7,1,7,0,39,10,7,16,3,56,12,6,1,0,0,0,0,0,0,0,22,12,4,64,8,0,0,0,0,0,0,0,0,12,6,10,7,15,2,10,5,10,4,56,13,13,6,10,5,68,8,11,7,15,3,10,4,11,6,56,14,11,5,11,4,18,2,56,15,2,8,3,0,0,34,49,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,11,2,12,4,46,11,4,17,5,12,6,11,0,15,1,12,9,10,9,15,2,10,6,12,5,46,11,5,56,7,32,4,27,5,31,11,9,1,7,0,39,10,9,15,3,10,7,56,16,12,8,11,9,15,2,10,6,10,7,56,13,11,8,10,6,68,8,11,6,11,7,18,2,56,15,2,9,3,0,0,36,73,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,10,2,12,4,46,11,4,17,3,12,9,10,7,10,9,33,4,19,5,23,11,0,1,7,5,39,10,0,11,2,12,5,46,11,5,17,5,12,10,11,0,15,1,12,12,10,12,15,3,11,9,56,16,12,11,10,11,46,65,8,6,2,0,0,0,0,0,0,0,38,4,45,5,51,11,12,1,11,11,1,7,2,39,10,11,14,10,12,6,46,11,6,56,17,12,8,1,11,12,15,2,10,10,56,18,1,11,11,11,8,56,19,1,11,10,11,7,18,3,56,20,2,0,2,0,1,1,0,1,1,0,28,0,37,0,38,0,50,0],"wormhole_adapter_core":[161,28,235,11,6,0,0,0,12,1,0,46,2,46,114,3,160,1,202,1,4,234,2,18,5,252,2,140,3,7,136,6,150,10,8,158,16,96,6,254,16,30,10,156,17,68,12,224,17,166,4,13,134,22,6,15,140,22,6,0,88,0,27,0,36,0,46,0,60,0,61,0,85,0,89,1,29,1,30,1,44,1,57,1,58,1,79,1,83,1,84,1,87,2,28,2,40,2,45,2,64,2,78,2,86,0,4,12,0,0,15,3,0,0,5,3,0,0,16,3,0,0,6,3,0,0,17,3,0,0,7,3,0,1,0,12,0,2,8,7,0,3,11,0,0,5,14,12,0,6,23,12,0,7,22,12,0,8,2,8,0,9,3,12,1,0,1,11,21,4,0,12,13,12,2,7,1,12,1,13,18,2,0,15,20,2,0,16,25,7,2,1,0,0,0,17,1,7,0,18,9,12,0,19,10,7,0,20,12,0,0,21,19,12,0,22,24,0,0,0,51,0,1,0,0,69,2,1,0,0,35,3,1,0,0,73,4,1,0,0,71,4,1,0,0,74,4,1,0,0,72,4,1,0,0,66,5,6,0,0,65,7,8,0,0,67,5,6,0,0,77,9,10,0,1,47,43,44,0,4,33,24,46,0,4,34,24,42,0,4,42,33,24,0,4,43,52,24,0,4,48,1,32,0,4,49,1,32,0,5,26,47,48,0,5,76,47,48,0,6,53,49,23,0,6,68,50,1,0,7,59,40,41,0,10,39,21,1,1,3,11,56,12,13,0,12,56,12,17,2,7,12,14,63,21,1,1,12,16,32,22,23,2,1,0,16,41,1,19,2,1,0,16,52,27,1,2,1,0,16,75,29,30,2,1,0,17,56,24,25,0,18,56,14,15,0,19,56,25,26,0,19,82,26,24,0,20,62,34,35,0,20,64,36,10,0,22,81,41,24,0,25,16,28,18,26,20,27,18,29,18,23,28,30,18,23,37,23,38,3,6,8,9,7,8,24,7,8,18,0,4,6,8,9,7,8,0,13,10,2,3,6,8,9,7,8,0,13,7,6,8,9,7,8,24,7,8,0,13,15,11,14,1,8,17,6,8,13,6,7,8,24,7,8,0,6,8,7,10,2,6,8,13,7,8,18,2,8,8,10,2,8,7,8,24,7,8,0,6,8,7,10,2,7,8,10,7,8,11,6,8,13,7,8,18,4,8,8,8,8,15,10,2,11,7,8,24,7,8,0,6,8,7,7,8,10,8,8,8,8,13,3,15,11,14,1,8,17,6,8,13,1,3,3,7,8,24,7,8,18,8,15,1,7,8,18,1,8,15,2,6,8,24,7,8,18,1,8,21,2,8,20,8,12,1,11,16,2,9,0,9,1,2,13,8,22,1,11,19,2,9,0,9,1,1,8,0,1,9,0,2,6,11,19,2,9,0,9,1,6,9,0,1,1,1,10,2,1,8,20,1,8,22,3,7,11,19,2,9,0,9,1,9,0,9,1,1,8,1,2,7,11,19,2,9,0,9,1,6,9,0,2,9,0,9,1,2,8,23,10,2,1,2,3,13,15,2,3,7,8,21,14,10,2,1,8,23,4,7,8,24,11,14,1,8,17,8,23,6,8,13,1,8,5,1,8,6,3,13,10,2,8,8,6,7,8,24,6,11,19,2,13,8,22,7,11,16,2,8,20,8,12,10,2,6,8,13,7,8,18,1,8,25,4,8,8,13,2,10,2,1,6,8,7,1,13,7,8,8,15,3,13,10,2,8,8,8,8,6,8,8,8,8,3,13,2,10,2,4,7,8,10,8,8,13,15,2,15,15,2,6,8,11,8,8,2,7,8,11,8,8,3,15,8,23,10,2,5,13,3,8,8,8,8,3,6,65,112,112,67,97,112,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,12,68,101,108,101,116,101,66,114,105,100,103,101,11,68,101,108,101,116,101,79,119,110,101,114,13,68,101,108,101,116,101,83,112,101,110,100,101,114,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,14,82,101,103,105,115,116,101,114,66,114,105,100,103,101,13,82,101,103,105,115,116,101,114,79,119,110,101,114,15,82,101,103,105,115,116,101,114,83,112,101,110,100,101,114,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,86,65,65,6,86,101,99,77,97,112,13,97,100,100,95,108,105,113,117,105,100,105,116,121,11,97,112,112,95,109,97,110,97,103,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,8,99,111,110,116,97,105,110,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,20,100,101,108,101,116,101,95,114,101,109,111,116,101,95,98,114,105,100,103,101,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,13,100,111,108,97,95,99,111,110,116,114,97,99,116,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,6,105,110,115,101,114,116,12,105,115,95,100,111,108,97,95,117,115,101,114,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,10,112,111,111,108,95,99,111,100,101,99,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,22,114,101,103,105,115,116,101,114,95,114,101,109,111,116,101,95,98,114,105,100,103,101,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,19,114,101,109,111,116,101,95,100,101,108,101,116,101,95,111,119,110,101,114,21,114,101,109,111,116,101,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,21,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,23,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,5,115,116,97,116,101,3,115,117,105,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,3,118,97,97,7,118,101,99,95,109,97,112,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,24,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,22,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,99,104,97,105,110,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,4,50,8,15,90,8,21,31,11,16,2,8,20,8,12,70,11,19,2,13,8,22,1,2,2,92,13,91,10,2,2,2,2,92,13,91,10,2,3,2,2,37,13,38,15,4,2,2,37,13,38,15,5,2,2,37,13,38,15,6,2,2,37,13,38,15,0,1,0,0,11,18,10,2,17,24,12,5,11,1,10,2,12,4,12,3,11,5,11,3,46,11,4,17,32,11,2,56,0,56,1,18,0,56,2,2,1,1,0,0,1,23,10,1,16,0,14,2,56,3,32,4,7,5,11,11,1,1,7,1,39,11,1,15,0,10,2,10,3,17,31,17,33,56,4,11,2,11,3,18,1,56,5,2,2,1,0,0,26,22,10,1,16,0,14,2,56,3,4,6,5,10,11,1,1,7,0,39,11,1,15,0,14,2,56,6,12,3,1,11,2,11,3,17,34,18,1,56,5,2,3,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,4,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,5,1,0,0,31,22,10,3,10,4,17,17,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,35,12,7,11,1,11,5,11,7,11,6,17,36,1,11,3,11,4,18,5,56,7,2,6,1,0,0,31,22,10,3,10,4,17,16,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,35,12,7,11,1,11,5,11,7,11,6,17,36,1,11,3,11,4,18,6,56,8,2,7,3,0,0,39,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,22,17,37,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,8,3,0,0,45,59,11,0,10,1,16,0,11,1,15,2,11,3,11,6,11,7,17,22,17,37,17,12,12,12,1,12,11,12,10,12,14,12,13,10,2,17,11,11,11,33,4,23,5,31,11,5,1,11,4,1,11,2,1,7,2,39,11,4,10,13,11,2,17,11,11,10,77,17,18,1,12,9,10,5,10,14,12,8,46,11,8,17,20,32,4,52,11,5,10,14,17,21,5,54,11,5,1,11,13,11,14,11,9,11,12,2,9,3,0,0,39,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,22,17,37,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,10,3,0,0,51,28,11,3,10,4,11,2,17,11,11,8,17,19,1,12,11,11,6,11,7,11,4,11,5,11,11,52,17,15,12,13,11,1,15,1,73,0,0,0,0,11,13,17,35,12,12,11,0,11,9,11,12,11,10,17,36,2,0,3,0,1,0,2,0,54,0,55,0,80,0],"wormhole_adapter_pool":[161,28,235,11,6,0,0,0,12,1,0,42,2,42,92,3,134,1,142,1,4,148,2,16,5,164,2,185,2,7,221,4,171,6,8,136,11,96,6,232,11,50,10,154,12,51,12,205,12,167,2,13,244,14,10,15,254,14,2,0,71,0,29,0,30,0,37,0,52,0,72,1,23,1,24,1,35,1,48,1,49,1,64,1,66,1,67,1,69,2,21,2,33,2,36,2,54,2,63,2,68,0,10,8,0,0,11,8,0,0,12,3,0,1,3,7,0,2,9,12,1,0,1,3,6,8,0,5,17,12,0,6,1,8,0,7,2,12,1,0,1,9,16,4,0,10,8,12,2,7,1,12,1,11,13,2,0,13,15,2,0,14,19,7,2,1,0,0,0,15,0,7,0,16,4,12,0,17,5,7,0,18,7,0,0,19,14,12,0,20,18,0,0,0,41,0,1,0,0,42,2,1,0,0,58,3,1,1,0,0,59,4,5,0,0,55,6,1,1,0,1,38,36,17,0,1,39,36,37,0,2,28,25,17,1,0,2,59,29,17,0,2,70,35,1,1,0,3,22,31,1,0,4,27,17,34,0,5,50,32,33,0,8,32,11,1,1,3,9,46,0,7,0,10,46,0,22,2,7,12,12,61,11,1,1,8,13,60,8,9,0,14,34,1,16,2,1,0,14,43,20,1,2,1,0,15,46,17,18,0,16,46,13,14,0,17,46,18,19,0,18,53,26,27,0,18,54,28,5,0,20,65,33,17,0,16,10,18,15,19,15,15,21,16,23,7,11,9,11,13,38,1,7,8,12,0,5,7,8,0,13,10,2,7,8,18,7,8,12,9,7,8,1,7,8,18,11,8,1,8,11,7,11,4,1,9,0,11,8,1,9,0,13,10,2,6,8,7,7,8,12,7,7,8,1,7,8,18,11,8,1,8,11,13,10,2,6,8,7,7,8,12,1,3,7,6,8,5,7,8,18,7,8,1,7,11,4,1,9,0,10,2,6,8,7,7,8,12,1,8,9,1,6,8,12,1,5,1,8,0,1,9,0,3,7,8,12,11,13,2,13,8,16,8,15,2,6,8,18,7,8,12,1,8,15,2,13,8,16,1,11,13,2,9,0,9,1,1,10,2,1,8,14,1,8,16,3,7,11,13,2,9,0,9,1,9,0,9,1,2,8,14,8,6,1,11,10,2,9,0,9,1,1,8,1,2,8,17,10,2,5,7,11,4,1,9,0,11,8,1,9,0,13,10,2,7,8,12,3,7,8,15,14,10,2,1,8,17,4,7,8,18,11,8,1,8,11,8,17,6,8,7,3,13,10,2,7,8,12,5,3,3,8,3,8,3,13,1,6,8,5,6,7,8,18,6,11,13,2,13,8,16,7,11,10,2,8,14,8,6,10,2,6,8,7,7,8,12,1,8,19,6,13,3,8,3,8,3,3,2,5,7,11,4,1,9,0,8,3,3,8,3,7,8,12,1,6,8,3,1,13,1,8,2,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,4,80,111,111,108,11,80,111,111,108,71,101,110,101,115,105,115,9,80,111,111,108,83,116,97,116,101,17,80,111,111,108,87,105,116,104,100,114,97,119,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,6,97,109,111,117,110,116,7,98,121,116,101,115,51,50,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,7,99,114,101,97,116,111,114,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,12,100,115,116,95,99,104,97,105,110,95,105,100,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,4,105,110,105,116,10,105,110,105,116,105,97,108,105,122,101,6,105,110,115,101,114,116,7,105,115,95,105,110,105,116,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,5,110,111,110,99,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,12,112,111,111,108,95,97,100,100,114,101,115,115,10,112,111,111,108,95,99,111,100,101,99,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,12,115,101,110,100,95,100,101,112,111,115,105,116,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,3,115,117,105,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,40,8,9,26,5,44,1,1,2,4,40,8,9,73,8,15,25,11,10,2,8,14,8,6,57,11,13,2,13,8,16,2,2,6,47,3,62,13,31,13,51,10,2,56,10,2,20,3,0,0,0,0,1,9,10,0,17,14,11,0,46,17,17,9,18,0,56,0,2,1,1,4,0,12,59,10,0,16,0,20,10,4,46,17,17,33,4,9,5,17,11,3,1,11,0,1,11,4,1,7,2,39,10,0,16,1,20,32,4,23,5,31,11,3,1,11,0,1,11,4,1,7,3,39,11,3,10,4,12,5,46,11,5,17,21,12,7,56,1,12,6,13,6,11,1,11,2,17,20,17,22,56,2,10,4,17,14,11,7,11,4,56,3,11,6,18,1,56,4,8,11,0,15,1,21,2,2,3,0,0,24,20,11,3,11,4,11,5,11,6,11,8,56,5,12,10,11,0,15,2,73,0,0,0,0,11,10,17,23,12,9,11,1,11,2,11,9,11,7,17,24,1,2,3,3,0,0,24,17,11,3,11,4,11,6,17,8,12,8,11,0,15,2,73,0,0,0,0,11,8,17,23,12,7,11,1,11,2,11,7,11,5,17,24,2,4,1,4,0,30,37,11,0,17,10,11,1,10,2,16,3,11,2,15,4,11,4,11,5,10,6,17,12,17,25,17,11,1,12,7,12,10,12,9,12,8,12,11,11,3,10,10,10,7,10,9,11,6,56,6,11,8,11,11,14,9,17,6,14,9,17,5,14,10,17,5,11,7,18,2,56,7,2,0,1,0,2,1,1,1,3,1,2,0,45,0],"wormhole_adapter_verify":[161,28,235,11,6,0,0,0,10,1,0,22,2,22,54,3,76,102,4,178,1,16,5,194,1,206,1,7,144,3,135,3,8,151,6,128,1,6,151,7,30,10,181,7,6,12,187,7,205,1,0,38,1,29,2,14,2,27,2,28,2,35,2,37,3,13,3,19,3,34,3,36,0,8,12,0,1,4,7,1,0,0,2,1,8,0,3,7,4,0,4,3,12,2,7,1,12,1,5,6,2,0,6,10,7,2,1,0,0,0,7,0,7,0,8,2,7,0,9,5,12,0,10,9,0,0,0,22,0,1,0,0,12,2,3,0,0,30,4,5,0,0,32,6,3,0,0,31,7,5,0,1,20,19,13,1,0,1,24,18,10,1,0,1,26,3,14,1,0,1,33,13,14,1,0,3,25,25,26,0,4,11,27,3,2,7,12,4,15,24,10,2,7,12,6,15,9,10,2,1,0,6,21,9,11,2,1,0,10,16,16,22,0,10,17,16,12,0,10,18,16,17,0,10,30,21,5,0,12,8,13,8,8,12,7,12,6,12,5,12,11,23,10,23,2,6,11,6,2,13,8,8,6,13,1,11,1,1,8,8,2,6,11,6,2,13,8,8,6,8,10,0,4,7,8,9,6,11,6,2,13,8,8,10,2,6,8,2,1,8,10,3,7,11,4,2,8,7,8,0,6,8,10,7,8,5,6,7,8,9,6,11,6,2,13,8,8,7,11,4,2,8,7,8,0,10,2,6,8,2,7,8,5,2,13,8,8,2,6,11,6,2,9,0,9,1,6,9,0,1,1,1,6,9,1,1,8,8,1,9,0,1,11,1,1,9,0,2,11,1,1,8,8,13,1,6,8,10,1,13,1,6,11,1,1,9,0,1,7,11,1,1,9,0,3,10,2,6,8,2,8,10,3,6,8,9,10,2,6,8,2,1,8,7,2,8,7,8,0,2,6,11,4,2,9,0,9,1,9,0,1,7,8,5,1,8,3,3,7,11,4,2,9,0,9,1,9,0,9,1,7,66,121,116,101,115,51,50,5,67,108,111,99,107,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,3,97,100,100,20,97,115,115,101,114,116,95,107,110,111,119,110,95,101,109,105,116,116,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,6,100,105,103,101,115,116,15,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,13,101,109,105,116,116,101,114,95,99,104,97,105,110,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,101,120,116,114,97,99,116,3,103,101,116,22,103,101,116,95,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,2,105,100,7,105,115,95,115,111,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,14,114,101,112,108,97,121,95,112,114,111,116,101,99,116,4,115,111,109,101,5,115,116,97,116,101,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,1,23,8,3,0,1,0,0,1,19,10,0,10,1,56,0,4,11,11,0,11,1,56,1,20,56,2,12,2,5,17,11,1,1,11,0,1,56,3,12,2,11,2,2,1,1,0,0,15,25,10,1,17,16,12,3,11,0,14,3,17,0,12,2,14,2,56,4,4,11,5,15,11,1,1,7,0,39,13,2,56,5,11,1,17,15,33,4,22,5,24,7,1,39,2,2,1,0,0,20,15,11,0,11,2,11,3,12,5,12,4,46,11,4,11,5,17,17,12,6,11,1,14,6,17,1,11,6,2,3,1,0,0,22,26,10,0,10,1,17,14,12,3,46,11,3,56,6,32,4,10,5,18,11,1,1,11,2,1,11,0,1,7,2,39,11,0,11,1,17,14,11,2,17,9,18,0,56,7,2,4,1,0,0,5,12,11,0,11,1,11,3,11,4,17,2,12,6,11,2,14,6,11,5,17,3,11,6,2,0]},"type_origin_table":[{"module_name":"dola_address","struct_name":"DolaAddress","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"Pool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"DepositPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"WithdrawPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_verify","struct_name":"Unit","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceManagerCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version_1_0_0","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version_1_0_1","package":"0xc5b2a5049cd71586362d0c6a38e34cfaae7ea9ce6d5401a350506a15f817bf72"},{"module_name":"app_manager","struct_name":"TotalAppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"app_manager","struct_name":"AppCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"UserInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ReserveData","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ScaledBalance","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"BorrowRateFactors","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"PriceOracle","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"Price","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"Liquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AddLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"RemoveLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_logic","struct_name":"LendingCoreExecuteEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserAddressCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"BindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UnbindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"CoreState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"LendingCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_wormhole_adapter","struct_name":"SystemCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolWithdrawEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":6},"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302":{"upgraded_id":"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302","upgraded_version":1},"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a":{"upgraded_id":"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a","upgraded_version":1}}}},"owner":"Immutable","previous_transaction":"6B3tXa5PpoaRUQiYcytsC1M9fkfzXUc49NsWgC335qC1","storage_rebate":551022800},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000001","version":2,"module_map":{"address":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,3,7,10,15,8,25,32,12,57,16,0,0,0,1,0,1,0,0,1,3,7,97,100,100,114,101,115,115,6,108,101,110,103,116,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,6,32,0,0,0,0,0,0,0,2,0],"ascii":[161,28,235,11,6,0,0,0,11,1,0,4,2,4,14,3,18,84,4,102,8,5,110,59,7,169,1,200,1,8,241,2,32,6,145,3,10,10,155,3,11,12,166,3,186,2,13,224,5,4,0,5,0,16,0,2,7,0,0,0,7,0,1,1,7,1,0,0,0,8,0,1,0,0,20,2,3,0,0,21,2,4,0,0,3,5,6,0,0,18,7,8,0,0,17,9,1,0,0,14,5,10,0,0,4,5,11,0,0,10,3,2,0,0,6,1,0,0,0,13,0,6,0,0,11,0,6,0,1,9,13,14,1,0,1,12,12,6,1,0,1,15,8,13,1,0,1,19,14,13,1,0,13,3,12,3,14,3,15,3,1,2,1,8,1,1,10,2,1,8,0,1,11,2,1,8,0,1,6,8,0,1,1,2,7,8,0,8,1,0,1,7,8,0,1,3,1,6,10,2,1,6,11,2,1,9,0,1,11,2,1,9,0,1,9,0,2,3,3,4,67,104,97,114,6,79,112,116,105,111,110,6,83,116,114,105,110,103,24,97,108,108,95,99,104,97,114,97,99,116,101,114,115,95,112,114,105,110,116,97,98,108,101,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,4,98,121,116,101,5,98,121,116,101,115,4,99,104,97,114,12,100,101,115,116,114,111,121,95,115,111,109,101,10,105,110,116,111,95,98,121,116,101,115,17,105,115,95,112,114,105,110,116,97,98,108,101,95,99,104,97,114,7,105,115,95,115,111,109,101,13,105,115,95,118,97,108,105,100,95,99,104,97,114,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,8,112,111,112,95,99,104,97,114,9,112,117,115,104,95,99,104,97,114,4,115,111,109,101,6,115,116,114,105,110,103,10,116,114,121,95,115,116,114,105,110,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,1,0,0,0,0,0,0,2,1,7,10,2,1,2,1,6,2,0,1,0,0,8,9,10,0,17,10,4,4,5,6,7,0,39,11,0,18,1,2,1,1,0,0,4,12,11,0,17,2,12,1,14,1,56,0,4,7,5,9,7,0,39,11,1,56,1,2,2,1,0,0,15,30,14,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,25,5,11,14,0,10,1,66,0,20,17,10,32,4,20,56,2,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,5,40,11,0,18,0,56,3,2,3,1,0,0,15,32,10,0,16,0,65,0,12,2,6,0,0,0,0,0,0,0,0,12,1,40,10,1,10,2,35,4,29,5,12,10,0,16,0,10,1,66,0,20,17,11,32,4,24,11,0,1,9,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,40,8,2,4,1,0,0,8,7,11,0,15,0,14,1,16,1,20,68,0,2,5,1,0,0,8,5,11,0,15,0,69,0,18,1,2,6,1,0,0,8,4,11,0,17,7,65,0,2,7,1,0,0,8,3,11,0,16,0,2,8,1,0,0,8,3,11,0,19,0,2,9,1,0,0,8,3,11,0,19,1,2,10,1,0,0,8,4,11,0,49,127,37,2,11,1,0,0,6,13,10,0,49,32,38,4,9,11,0,49,126,37,12,1,5,11,9,12,1,11,1,2,0,0,1,0,0],"bcs":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,7,7,15,13,8,28,32,12,60,4,0,0,0,1,0,1,1,0,1,6,9,0,1,10,2,3,98,99,115,8,116,111,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,0],"bit_vector":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,36,7,77,109,8,186,1,32,6,218,1,40,10,130,2,8,12,138,2,239,3,13,249,5,4,0,2,0,0,7,0,0,6,0,1,0,0,7,2,3,0,0,9,2,3,0,0,8,2,3,0,0,3,4,5,0,0,4,6,0,0,0,5,4,0,0,1,3,1,8,0,2,7,8,0,3,0,2,6,8,0,3,1,1,1,6,8,0,2,10,1,3,1,7,1,5,3,7,1,3,3,3,9,66,105,116,86,101,99,116,111,114,9,98,105,116,95,102,105,101,108,100,10,98,105,116,95,118,101,99,116,111,114,12,105,115,95,105,110,100,101,120,95,115,101,116,6,108,101,110,103,116,104,32,108,111,110,103,101,115,116,95,115,101,116,95,115,101,113,117,101,110,99,101,95,115,116,97,114,116,105,110,103,95,97,116,3,110,101,119,3,115,101,116,10,115,104,105,102,116,95,108,101,102,116,5,117,110,115,101,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,3,8,1,0,2,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,4,0,0,0,0,0,0,0,2,2,4,3,1,10,1,0,1,0,0,7,37,10,0,6,0,0,0,0,0,0,0,0,36,4,5,5,7,7,1,39,10,0,7,3,35,4,12,5,14,7,1,39,6,0,0,0,0,0,0,0,0,12,2,64,5,0,0,0,0,0,0,0,0,12,1,40,10,2,10,0,35,4,32,5,24,13,1,9,68,5,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,18,40,11,0,11,1,18,0,2,1,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,8,11,2,21,2,2,1,0,0,8,20,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,15,0,11,1,67,5,12,2,9,11,2,21,2,3,1,0,0,9,89,10,1,10,0,16,1,20,38,4,33,10,0,16,0,65,5,12,6,6,0,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,30,5,17,10,0,15,0,10,4,67,5,12,3,9,11,3,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,12,11,0,1,5,88,10,1,12,5,10,5,10,0,16,1,20,35,4,65,5,42,10,0,10,5,12,2,46,11,2,17,4,4,55,10,0,10,5,10,1,23,17,1,5,60,10,0,10,5,10,1,23,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,35,10,0,16,1,20,11,1,23,12,5,10,5,10,0,16,1,20,35,4,86,5,78,10,0,10,5,17,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,71,11,0,1,2,4,1,0,0,3,17,10,1,10,0,16,0,65,5,35,4,7,5,11,11,0,1,7,0,39,11,0,16,0,11,1,66,5,20,2,5,1,0,0,3,4,11,0,16,0,65,5,2,6,1,0,0,0,37,10,1,10,0,16,1,20,35,4,7,5,11,11,0,1,7,0,39,10,1,12,2,10,2,10,0,16,1,20,35,4,33,5,20,10,0,10,2,17,4,32,4,28,11,0,1,5,33,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,13,11,2,11,1,23,2,0,1,0,0,0],"debug":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,11,5,13,5,7,18,30,8,48,32,12,80,8,0,0,0,1,0,1,1,0,0,2,1,1,0,1,6,9,0,0,5,100,101,98,117,103,5,112,114,105,110,116,17,112,114,105,110,116,95,115,116,97,99,107,95,116,114,97,99,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"fixed_point32":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,30,5,36,22,7,58,122,8,180,1,32,6,212,1,68,10,152,2,5,12,157,2,137,2,13,166,4,2,0,4,0,0,7,0,0,7,0,1,0,0,3,0,1,0,0,1,2,3,0,0,2,1,3,0,0,5,3,1,0,0,6,3,4,0,2,3,8,0,1,3,2,3,3,1,8,0,1,1,1,4,4,1,4,4,4,0,12,70,105,120,101,100,80,111,105,110,116,51,50,20,99,114,101,97,116,101,95,102,114,111,109,95,114,97,116,105,111,110,97,108,21,99,114,101,97,116,101,95,102,114,111,109,95,114,97,119,95,118,97,108,117,101,10,100,105,118,105,100,101,95,117,54,52,13,102,105,120,101,100,95,112,111,105,110,116,51,50,13,103,101,116,95,114,97,119,95,118,97,108,117,101,7,105,115,95,122,101,114,111,12,109,117,108,116,105,112,108,121,95,117,54,52,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,16,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,3,8,1,0,1,0,0,0,0,0,3,8,2,0,2,0,0,0,0,0,3,8,3,0,2,0,0,0,0,0,3,8,4,0,1,0,0,0,0,0,3,8,5,0,2,0,0,0,0,0,0,2,1,8,3,0,1,0,0,5,20,11,0,53,14,1,16,0,20,53,24,49,32,48,12,2,10,2,7,0,37,4,15,5,17,7,3,39,11,2,52,2,1,1,0,0,5,29,14,1,16,0,20,6,0,0,0,0,0,0,0,0,34,4,7,5,9,7,4,39,11,0,53,49,32,47,14,1,16,0,20,53,26,12,2,10,2,7,0,37,4,24,5,26,7,2,39,11,2,52,2,2,1,0,0,6,48,10,0,53,49,64,47,12,5,11,1,53,49,32,47,12,4,10,4,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,15,5,17,7,1,39,11,5,11,4,26,12,3,10,3,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,8,12,2,5,32,11,0,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,35,5,37,7,5,39,10,3,7,0,37,4,42,5,44,7,5,39,11,3,52,18,0,2,3,1,0,0,7,3,11,0,18,0,2,4,1,0,0,7,4,14,0,16,0,20,2,5,1,0,0,7,6,14,0,16,0,20,6,0,0,0,0,0,0,0,0,33,2,0,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,3,7,15,23,8,38,32,12,70,8,0,0,0,1,0,0,0,0,2,0,0,0,1,10,2,4,104,97,115,104,8,115,104,97,50,95,50,53,54,8,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,1,2,0,0],"option":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,6,3,10,120,4,130,1,14,5,144,1,135,1,7,151,2,219,1,8,242,3,32,6,146,4,20,10,166,4,7,11,173,4,2,12,175,4,128,4,13,175,8,2,14,177,8,2,0,15,0,22,0,0,7,1,0,0,0,14,0,1,1,0,0,17,2,1,1,0,0,12,3,4,1,0,0,13,3,4,1,0,0,4,5,4,1,0,0,1,3,6,1,0,0,3,5,6,1,0,0,10,7,2,1,3,0,9,8,0,1,0,0,8,9,2,1,0,0,2,9,10,1,0,0,18,8,2,1,0,0,19,8,1,1,0,0,7,11,2,1,2,0,6,1,2,1,0,0,5,1,0,1,0,0,20,1,12,1,0,1,4,14,4,1,0,1,11,13,4,1,0,1,16,2,12,1,0,19,2,18,2,17,2,3,2,0,2,1,2,2,2,0,1,11,0,1,9,0,1,9,0,1,6,11,0,1,9,0,1,1,2,6,11,0,1,9,0,6,9,0,1,6,9,0,2,6,11,0,1,9,0,9,0,2,7,11,0,1,9,0,9,0,1,7,11,0,1,9,0,1,7,9,0,2,11,0,1,9,0,9,0,1,10,9,0,1,6,10,9,0,2,6,10,9,0,6,9,0,2,6,9,0,6,10,9,0,2,9,0,6,10,9,0,1,7,10,9,0,2,9,0,7,10,9,0,3,11,0,1,9,0,11,0,1,9,0,7,10,9,0,2,9,0,10,9,0,6,79,112,116,105,111,110,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,119,105,116,104,95,100,101,102,97,117,108,116,8,99,111,110,116,97,105,110,115,12,100,101,115,116,114,111,121,95,110,111,110,101,12,100,101,115,116,114,111,121,95,115,111,109,101,20,100,101,115,116,114,111,121,95,119,105,116,104,95,100,101,102,97,117,108,116,7,101,120,116,114,97,99,116,4,102,105,108,108,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,4,110,111,110,101,6,111,112,116,105,111,110,9,115,105,110,103,108,101,116,111,110,4,115,111,109,101,4,115,119,97,112,12,115,119,97,112,95,111,114,95,102,105,108,108,6,116,111,95,118,101,99,3,118,101,99,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,4,0,0,0,0,0,3,8,1,0,4,0,0,0,0,0,0,2,1,21,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,0,4,11,0,55,0,56,1,2,3,1,0,0,0,5,11,0,55,0,56,1,32,2,4,1,0,0,0,5,11,0,55,0,11,1,56,2,2,5,1,0,0,0,13,10,0,56,3,4,4,5,8,11,0,1,7,1,39,11,0,55,0,6,0,0,0,0,0,0,0,0,66,2,2,6,1,0,0,15,19,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,17,11,1,1,11,3,6,0,0,0,0,0,0,0,0,66,2,12,2,11,2,2,7,1,0,0,16,18,11,0,55,0,12,3,10,3,56,1,4,11,11,3,1,11,1,12,2,5,16,11,3,6,0,0,0,0,0,0,0,0,66,2,20,12,2,11,2,2,8,1,0,0,17,16,11,0,54,0,12,2,10,2,46,56,1,4,8,5,12,11,2,1,7,0,39,11,2,11,1,68,2,2,9,1,0,0,0,13,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,69,2,2,10,1,0,0,0,14,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,6,0,0,0,0,0,0,0,0,67,2,2,11,1,0,0,18,20,10,0,46,56,3,4,5,5,9,11,0,1,7,1,39,11,0,54,0,12,3,10,3,69,2,12,2,11,3,11,1,68,2,11,2,2,12,1,0,0,19,21,11,0,54,0,12,4,10,4,46,56,1,4,10,56,4,12,2,5,14,10,4,69,2,56,5,12,2,11,2,12,3,11,4,11,1,68,2,11,3,2,13,1,0,0,20,15,11,0,58,0,12,3,13,3,46,56,1,4,10,11,1,12,2,5,13,13,3,69,2,12,2,11,2,2,14,1,0,0,20,16,14,0,56,3,4,4,5,6,7,1,39,11,0,58,0,12,2,13,2,69,2,12,1,11,2,70,2,0,0,0,0,0,0,0,0,11,1,2,15,1,0,0,0,10,14,0,56,6,4,4,5,6,7,0,39,11,0,58,0,70,2,0,0,0,0,0,0,0,0,2,16,1,0,0,0,3,11,0,58,0,2,0,0,0,2,0],"string":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,14,3,22,114,4,136,1,8,5,144,1,123,7,139,2,248,1,8,131,4,32,6,163,4,20,10,183,4,6,12,189,4,133,3,13,194,7,2,0,19,0,4,0,17,0,24,0,1,7,0,1,1,7,0,2,0,7,1,0,0,0,23,0,1,0,0,6,2,1,0,0,21,1,2,0,0,22,0,3,0,0,5,4,5,0,0,14,4,6,0,0,15,4,7,0,0,2,8,9,0,0,3,10,9,0,0,8,11,9,0,0,20,12,1,0,0,7,13,7,0,0,9,5,6,0,0,11,14,6,0,0,12,15,0,0,0,10,16,7,0,1,13,2,0,0,1,19,0,2,0,2,16,9,18,1,0,2,18,17,18,1,0,3,2,21,9,1,0,3,14,20,6,1,0,19,1,18,1,21,19,20,19,1,10,2,1,8,0,1,8,1,1,11,2,1,8,0,1,6,8,0,1,6,10,2,1,1,1,3,2,7,8,0,8,0,0,2,7,8,0,10,2,3,7,8,0,3,8,0,3,6,8,0,3,3,2,6,8,0,6,8,0,2,6,10,2,3,3,6,10,2,3,3,2,6,10,2,6,10,2,1,9,0,1,11,2,1,9,0,1,2,1,6,10,9,0,2,7,10,9,0,10,9,0,8,1,3,3,3,6,10,2,8,0,8,0,3,5,1,1,1,6,10,2,3,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,97,112,112,101,110,100,11,97,112,112,101,110,100,95,117,116,102,56,5,97,115,99,105,105,5,98,121,116,101,115,10,102,114,111,109,95,97,115,99,105,105,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,19,105,110,116,101,114,110,97,108,95,99,104,101,99,107,95,117,116,102,56,17,105,110,116,101,114,110,97,108,95,105,110,100,101,120,95,111,102,25,105,110,116,101,114,110,97,108,95,105,115,95,99,104,97,114,95,98,111,117,110,100,97,114,121,19,105,110,116,101,114,110,97,108,95,115,117,98,95,115,116,114,105,110,103,10,105,110,116,111,95,98,121,116,101,115,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,4,110,111,110,101,6,111,112,116,105,111,110,4,115,111,109,101,6,115,116,114,105,110,103,10,115,117,98,95,115,116,114,105,110,103,8,116,111,95,97,115,99,105,105,8,116,114,121,95,117,116,102,56,4,117,116,102,56,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,5,10,2,0,1,0,0,9,9,14,0,17,12,4,4,5,6,7,0,39,11,0,18,0,2,1,1,0,0,9,4,11,0,17,16,18,0,2,2,1,0,0,9,4,11,0,19,0,17,17,2,3,1,0,0,3,12,14,0,17,12,4,8,11,0,18,0,56,0,12,1,5,10,56,1,12,1,11,1,2,4,1,0,0,9,3,11,0,16,0,2,5,1,0,0,9,4,11,0,16,0,56,2,2,6,1,0,0,9,4,11,0,16,0,65,19,2,7,1,0,0,9,7,11,0,15,0,14,1,16,0,20,56,3,2,8,1,0,0,9,5,11,0,11,1,17,0,17,7,2,9,1,0,0,22,56,10,0,16,0,12,7,10,1,10,7,65,19,37,4,13,11,7,10,1,17,13,12,3,5,17,11,7,1,9,12,3,11,3,4,20,5,24,11,0,1,7,1,39,10,0,46,17,6,12,10,10,0,10,1,12,4,46,6,0,0,0,0,0,0,0,0,11,4,17,10,12,9,10,0,11,1,11,10,12,6,12,5,46,11,5,11,6,17,10,12,8,13,9,11,2,17,7,13,9,11,8,17,7,11,9,11,0,21,2,10,1,0,0,23,48,11,0,16,0,12,6,10,6,65,19,12,7,10,2,11,7,37,4,15,10,1,10,2,37,12,3,5,17,9,12,3,11,3,4,24,10,6,10,1,17,13,12,4,5,26,9,12,4,11,4,4,33,10,6,10,2,17,13,12,5,5,35,9,12,5,11,5,4,38,5,42,11,6,1,7,1,39,11,6,11,1,11,2,17,14,18,0,2,11,1,0,0,9,6,11,0,16,0,11,1,16,0,17,15,2,12,0,2,0,13,0,2,0,14,0,2,0,15,0,2,0,0,0,0],"type_name":[161,28,235,11,6,0,0,0,10,1,0,6,2,6,8,3,14,47,5,61,44,7,105,143,1,8,248,1,32,6,152,2,7,10,159,2,6,12,165,2,215,1,13,252,3,2,0,14,0,2,0,4,0,1,7,0,2,0,7,0,0,6,0,1,1,0,0,9,0,1,1,0,0,5,2,3,0,0,7,2,4,0,0,8,2,4,0,0,10,1,4,0,1,11,0,6,0,2,3,3,7,0,2,13,9,4,0,0,1,8,0,1,6,8,0,1,6,8,1,1,8,1,4,10,2,3,3,6,10,2,1,3,1,6,10,2,1,2,1,10,2,5,2,6,2,3,10,2,6,10,2,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,8,97,115,95,98,121,116,101,115,5,97,115,99,105,105,13,98,111,114,114,111,119,95,115,116,114,105,110,103,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,11,105,110,116,111,95,115,116,114,105,110,103,6,108,101,110,103,116,104,4,110,97,109,101,6,115,116,114,105,110,103,9,116,121,112,101,95,110,97,109,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,58,10,2,1,0,0,2,1,12,8,1,0,1,2,0,1,1,2,0,2,1,0,0,0,3,11,0,16,0,2,3,1,0,0,5,33,17,6,6,2,0,0,0,0,0,0,0,24,12,3,11,0,16,0,17,7,12,4,7,1,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,28,5,17,13,1,10,4,10,2,66,8,20,68,8,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,4,1,11,1,17,8,2,4,1,0,0,10,39,17,6,6,2,0,0,0,0,0,0,0,24,6,2,0,0,0,0,0,0,0,22,12,3,11,0,16,0,17,7,12,5,7,1,12,4,10,5,10,3,66,8,12,2,7,0,12,1,10,2,14,1,34,4,32,5,23,13,4,11,2,20,68,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,12,11,5,1,11,2,1,11,4,17,8,2,5,1,0,0,0,4,14,0,16,0,20,2,0,0,0],"vector":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,102,4,104,4,5,108,97,7,205,1,154,1,8,231,2,32,6,135,3,10,12,145,3,216,4,0,17,0,5,0,1,1,0,0,9,2,3,1,0,0,1,4,5,1,0,0,11,6,0,1,0,0,2,7,8,1,0,0,10,9,10,1,0,0,4,1,0,1,0,0,15,11,0,1,0,0,14,10,1,1,0,0,13,9,0,1,0,0,0,12,0,1,0,0,8,2,13,1,0,0,3,14,13,1,0,0,6,14,15,1,0,0,12,7,10,1,0,0,7,16,0,1,0,0,16,7,10,1,0,9,10,11,10,0,1,10,9,0,1,6,10,9,0,1,3,2,6,10,9,0,3,1,6,9,0,2,7,10,9,0,9,0,2,7,10,9,0,3,1,7,9,0,1,7,10,9,0,1,9,0,3,7,10,9,0,3,3,2,7,10,9,0,10,9,0,1,1,2,6,10,9,0,6,9,0,2,1,3,3,7,10,9,0,9,0,3,3,3,3,3,2,3,3,3,3,7,10,9,0,3,6,97,112,112,101,110,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,5,101,109,112,116,121,8,105,110,100,101,120,95,111,102,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,7,114,101,118,101,114,115,101,9,115,105,110,103,108,101,116,111,110,4,115,119,97,112,11,115,119,97,112,95,114,101,109,111,118,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,2,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,2,0,4,1,2,0,5,1,2,0,6,1,2,0,7,1,2,0,8,1,0,0,1,7,64,10,0,0,0,0,0,0,0,0,12,1,13,1,11,0,68,10,11,1,2,9,1,0,0,17,38,10,0,46,65,10,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,2,6,0,0,0,0,0,0,0,0,12,2,11,3,6,1,0,0,0,0,0,0,0,23,12,1,10,2,10,1,35,4,35,5,22,10,0,10,2,10,1,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,1,6,1,0,0,0,0,0,0,0,23,12,1,5,17,11,0,1,2,10,1,0,0,0,17,13,1,56,0,14,1,56,1,32,4,12,5,7,10,0,13,1,69,10,68,10,5,2,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,11,1,0,0,0,5,11,0,65,10,6,0,0,0,0,0,0,0,0,33,2,12,1,0,0,18,33,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,27,5,10,10,0,10,2,66,10,10,1,33,4,22,11,0,1,11,1,1,8,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,2,13,1,0,0,18,35,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,3,10,2,10,3,35,4,28,5,10,10,0,10,2,66,10,10,1,33,4,23,11,0,1,11,1,1,8,11,2,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,9,6,0,0,0,0,0,0,0,0,2,14,1,0,0,19,37,10,0,46,65,10,12,4,10,1,10,4,38,4,12,11,0,1,7,0,39,11,4,6,1,0,0,0,0,0,0,0,23,12,4,10,1,10,4,35,4,34,5,21,10,0,12,3,10,1,12,2,11,1,6,1,0,0,0,0,0,0,0,22,12,1,11,3,11,2,10,1,71,10,5,16,11,0,69,10,2,15,1,0,0,3,32,10,0,46,65,10,12,3,10,2,10,3,36,4,12,11,0,1,7,0,39,10,0,11,1,68,10,10,2,10,3,35,4,29,5,20,10,0,10,2,10,3,71,10,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,2,16,1,0,0,3,23,10,0,46,56,1,32,4,6,5,10,11,0,1,7,0,39,10,0,46,65,10,6,1,0,0,0,0,0,0,0,23,12,2,10,0,11,1,11,2,71,10,11,0,69,10,2,0]},"type_origin_table":[{"module_name":"fixed_point32","struct_name":"FixedPoint32","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"option","struct_name":"Option","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"ascii","struct_name":"Char","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"bit_vector","struct_name":"BitVector","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"string","struct_name":"String","package":"0x0000000000000000000000000000000000000000000000000000000000000001"},{"module_name":"type_name","struct_name":"TypeName","package":"0x0000000000000000000000000000000000000000000000000000000000000001"}],"linkage_table":{}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000002","version":6,"module_map":{"address":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,8,3,18,61,4,79,2,5,81,20,7,101,129,1,8,230,1,64,6,166,2,54,12,220,2,69,0,1,1,2,1,3,1,11,0,8,1,0,7,0,3,0,7,0,0,15,0,1,0,0,7,1,0,0,0,6,2,0,0,0,13,0,2,0,0,12,0,3,0,0,14,0,4,0,0,9,5,6,0,0,10,5,1,0,1,11,2,3,0,2,13,7,2,1,0,3,5,3,4,0,4,4,2,2,0,9,0,1,5,1,15,1,10,2,1,8,0,1,8,1,0,1,3,1,6,9,0,6,83,116,114,105,110,103,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,6,101,110,99,111,100,101,10,102,114,111,109,95,97,115,99,105,105,10,102,114,111,109,95,98,121,116,101,115,9,102,114,111,109,95,117,50,53,54,3,104,101,120,6,108,101,110,103,116,104,3,109,97,120,6,115,116,114,105,110,103,15,116,111,95,97,115,99,105,105,95,115,116,114,105,110,103,8,116,111,95,98,121,116,101,115,9,116,111,95,115,116,114,105,110,103,7,116,111,95,117,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,32,0,0,0,0,0,0,0,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,3,8,0,0,0,0,0,0,0,0,0,1,2,0,1,1,2,0,2,1,2,0,3,1,0,0,5,3,14,0,56,0,2,4,1,0,0,5,5,11,0,17,3,17,11,17,8,2,5,1,0,0,5,4,11,0,17,4,17,10,2,6,1,0,0,5,2,7,0,2,7,1,0,0,5,2,7,1,2,0],"bag":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,112,4,132,1,12,5,144,1,82,7,226,1,185,1,8,155,3,32,6,187,3,10,10,197,3,8,12,205,3,230,1,13,179,5,4,0,4,0,11,0,18,0,21,0,0,12,0,2,2,4,0,3,1,2,0,0,17,0,1,0,0,3,2,3,2,7,4,0,5,4,5,2,7,4,0,6,6,7,2,7,4,0,19,6,8,2,7,4,0,7,4,9,1,7,0,8,4,9,2,7,4,0,16,10,11,0,0,15,10,9,0,0,10,1,3,0,1,3,14,3,2,7,4,1,5,15,5,2,7,4,1,6,16,7,2,7,4,1,12,15,9,1,7,1,13,15,9,2,7,4,1,19,16,8,2,7,4,2,9,12,3,0,2,17,0,12,0,10,13,11,13,12,13,15,13,13,17,14,13,1,7,8,2,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,1,9,0,2,8,1,3,3,66,97,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,3,98,97,103,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,14,8,1,20,3,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,18,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,0,0,0,1,0],"balance":[161,28,235,11,6,0,0,0,14,1,0,4,2,4,16,3,20,83,4,103,2,5,105,99,7,204,1,224,1,8,172,3,32,6,204,3,74,10,150,4,10,11,160,4,4,12,164,4,219,2,13,255,6,4,14,131,7,4,15,135,7,2,0,3,0,16,0,1,4,1,0,1,0,0,4,1,0,1,1,2,2,0,0,17,0,1,1,0,0,15,2,1,1,0,0,5,3,4,1,2,0,10,5,6,1,0,0,6,7,1,1,0,0,19,8,6,1,0,0,11,9,1,1,0,0,13,10,6,1,0,0,18,11,6,1,0,0,9,6,8,1,0,0,4,12,6,1,0,0,7,13,8,1,0,0,8,4,1,1,0,1,12,14,15,0,7,3,1,6,11,1,1,9,0,1,3,1,6,11,0,1,9,0,1,9,0,1,11,0,1,9,0,2,7,11,0,1,9,0,3,1,11,1,1,9,0,2,7,11,0,1,9,0,11,1,1,9,0,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,7,11,1,1,9,0,2,3,6,8,2,2,11,1,1,9,0,6,8,2,1,6,8,2,1,5,7,66,97,108,97,110,99,101,6,83,117,112,112,108,121,9,84,120,67,111,110,116,101,120,116,7,98,97,108,97,110,99,101,22,99,114,101,97,116,101,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,115,13,99,114,101,97,116,101,95,115,117,112,112,108,121,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,23,100,101,115,116,114,111,121,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,12,100,101,115,116,114,111,121,95,122,101,114,111,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,4,106,111,105,110,6,115,101,110,100,101,114,5,115,112,108,105,116,3,115,117,105,12,115,117,112,112,108,121,95,118,97,108,117,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,17,3,1,2,1,17,3,0,3,1,3,0,1,0,0,8,4,11,0,55,0,20,2,1,1,0,0,8,4,11,0,55,1,20,2,2,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,0,2,3,1,0,0,8,24,10,1,6,255,255,255,255,255,255,255,255,10,0,55,1,20,23,35,4,9,5,13,11,0,1,7,1,39,10,0,55,1,20,10,1,22,11,0,54,1,21,11,1,57,1,2,4,1,0,0,1,24,11,1,58,1,12,2,10,0,55,1,20,10,2,38,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,10,2,23,11,0,54,1,21,11,2,2,5,1,0,0,8,3,6,0,0,0,0,0,0,0,0,57,1,2,6,1,0,0,1,15,11,1,58,1,12,2,10,0,55,0,20,11,2,22,10,0,54,0,21,11,0,55,0,20,2,7,1,0,0,8,22,10,0,55,0,20,10,1,38,4,7,5,11,11,0,1,7,2,39,10,0,55,0,20,10,1,23,11,0,54,0,21,11,1,57,1,2,8,1,0,0,1,8,10,0,55,0,20,12,1,11,0,11,1,56,0,2,9,1,0,0,8,13,14,0,55,0,20,6,0,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,11,0,58,1,1,2,10,0,0,0,8,11,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,57,1,2,11,0,0,0,8,12,11,1,17,13,7,4,33,4,6,5,8,7,3,39,11,0,58,1,1,2,12,3,0,0,8,3,11,0,58,0,2,1,0,0,0,0,3,1,3,0,14,0],"bcs":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,10,3,20,135,1,4,155,1,24,5,179,1,131,1,7,182,2,222,2,8,148,5,64,6,212,5,55,10,139,6,6,12,145,6,203,8,13,220,14,2,0,3,1,3,1,10,1,31,0,2,0,0,7,0,2,1,7,1,0,0,0,30,0,1,1,0,0,8,1,2,0,0,6,2,1,0,0,11,3,4,0,0,12,3,5,0,0,20,3,6,0,0,19,3,7,0,0,18,3,8,0,0,23,3,7,0,0,21,3,9,0,0,22,3,10,0,0,26,3,1,0,0,27,3,11,0,0,25,3,12,0,0,24,3,13,0,0,13,3,14,0,0,14,3,15,0,0,17,3,16,0,0,16,3,17,0,0,15,3,18,0,1,30,0,1,1,0,2,9,19,33,1,0,2,29,20,33,1,0,3,28,21,19,1,0,4,5,1,4,0,4,7,19,7,0,20,20,23,6,22,4,21,4,22,5,21,5,22,6,21,6,22,7,21,7,22,8,21,8,1,6,9,0,1,10,2,1,8,0,1,7,8,0,1,5,1,1,1,2,1,3,1,4,1,10,5,1,10,1,1,10,10,2,1,10,3,1,10,4,1,11,1,1,5,1,11,1,1,1,1,11,1,1,2,1,11,1,1,3,1,11,1,1,4,0,1,9,0,1,7,10,9,0,2,10,2,3,2,1,2,3,3,2,3,3,4,2,4,4,3,3,2,3,3,3,3,10,5,3,3,3,10,1,3,3,3,10,2,3,3,3,10,10,2,3,3,3,10,3,3,3,3,10,4,1,11,1,1,9,0,3,66,67,83,6,79,112,116,105,111,110,7,97,100,100,114,101,115,115,3,98,99,115,5,98,121,116,101,115,10,102,114,111,109,95,98,121,116,101,115,20,105,110,116,111,95,114,101,109,97,105,110,100,101,114,95,98,121,116,101,115,6,108,101,110,103,116,104,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,12,112,101,101,108,95,97,100,100,114,101,115,115,9,112,101,101,108,95,98,111,111,108,19,112,101,101,108,95,111,112,116,105,111,110,95,97,100,100,114,101,115,115,16,112,101,101,108,95,111,112,116,105,111,110,95,98,111,111,108,16,112,101,101,108,95,111,112,116,105,111,110,95,117,49,50,56,15,112,101,101,108,95,111,112,116,105,111,110,95,117,54,52,14,112,101,101,108,95,111,112,116,105,111,110,95,117,56,9,112,101,101,108,95,117,49,50,56,8,112,101,101,108,95,117,54,52,7,112,101,101,108,95,117,56,16,112,101,101,108,95,118,101,99,95,97,100,100,114,101,115,115,13,112,101,101,108,95,118,101,99,95,98,111,111,108,15,112,101,101,108,95,118,101,99,95,108,101,110,103,116,104,13,112,101,101,108,95,118,101,99,95,117,49,50,56,12,112,101,101,108,95,118,101,99,95,117,54,52,11,112,101,101,108,95,118,101,99,95,117,56,15,112,101,101,108,95,118,101,99,95,118,101,99,95,117,56,7,114,101,118,101,114,115,101,4,115,111,109,101,8,116,111,95,98,121,116,101,115,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,10,5,1,0,10,1,1,0,10,2,1,0,10,10,2,1,0,10,3,1,0,10,4,1,0,0,2,1,4,10,2,0,1,0,0,19,3,11,0,56,0,2,1,1,0,0,19,5,13,0,56,1,11,0,18,0,2,2,1,0,0,1,7,11,0,19,0,12,1,13,1,56,1,11,1,2,3,1,0,0,22,35,10,0,16,0,65,6,17,25,38,4,7,5,11,11,0,1,7,0,39,64,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,12,2,12,1,10,2,17,25,35,4,30,5,20,13,1,10,0,15,0,69,6,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,0,1,11,1,17,24,2,4,1,0,0,23,21,11,0,17,5,12,2,10,2,49,0,33,4,10,9,12,1,5,19,11,2,49,1,33,4,15,5,17,7,1,39,8,12,1,11,1,2,5,1,0,0,19,15,10,0,16,0,65,6,6,1,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,11,0,15,0,69,6,2,6,1,0,0,24,40,10,0,16,0,65,6,6,8,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,6,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,64,35,4,36,5,20,10,0,15,0,69,6,52,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,7,1,0,0,25,40,10,0,16,0,65,6,6,16,0,0,0,0,0,0,0,38,4,7,5,11,11,0,1,7,0,39,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,0,12,2,12,3,10,2,49,128,35,4,36,5,20,10,0,15,0,69,6,53,12,1,11,3,11,1,10,2,47,22,12,3,11,2,49,8,22,12,2,5,15,11,0,1,11,3,2,8,1,0,0,26,48,6,0,0,0,0,0,0,0,0,49,0,6,0,0,0,0,0,0,0,0,12,2,12,3,12,4,10,2,6,4,0,0,0,0,0,0,0,37,4,11,5,15,11,0,1,7,2,39,10,0,15,0,69,6,52,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,11,4,10,1,6,127,0,0,0,0,0,0,0,28,10,3,47,27,12,4,11,1,6,128,0,0,0,0,0,0,0,28,6,0,0,0,0,0,0,0,0,33,4,39,5,44,11,3,49,7,22,12,3,5,6,11,0,1,11,4,2,9,1,0,0,27,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,3,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,3,68,4,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,10,1,0,0,28,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,4,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,4,68,5,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,11,1,0,0,29,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,5,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,5,68,6,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,12,1,0,0,30,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,6,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,11,68,1,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,13,1,0,0,31,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,7,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,6,68,7,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,14,1,0,0,32,25,10,0,17,8,6,0,0,0,0,0,0,0,0,7,8,12,3,12,1,12,2,10,1,10,2,35,4,21,5,12,13,3,10,0,17,7,68,8,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,15,1,0,0,14,14,10,0,17,4,4,8,11,0,17,3,56,2,12,1,5,12,11,0,1,56,3,12,1,11,1,2,16,1,0,0,15,14,10,0,17,4,4,8,11,0,17,4,56,4,12,1,5,12,11,0,1,56,5,12,1,11,1,2,17,1,0,0,16,14,10,0,17,4,4,8,11,0,17,5,56,6,12,1,5,12,11,0,1,56,7,12,1,11,1,2,18,1,0,0,17,14,10,0,17,4,4,8,11,0,17,6,56,8,12,1,5,12,11,0,1,56,9,12,1,11,1,2,19,1,0,0,18,14,10,0,17,4,4,8,11,0,17,7,56,10,12,1,5,12,11,0,1,56,11,12,1,11,1,2,0,0,0],"bls12381":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,12,7,24,56,8,80,32,12,112,8,0,0,0,2,0,1,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,8,98,108,115,49,50,51,56,49,22,98,108,115,49,50,51,56,49,95,109,105,110,95,112,107,95,118,101,114,105,102,121,23,98,108,115,49,50,51,56,49,95,109,105,110,95,115,105,103,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"borrow":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,24,3,32,59,4,91,10,5,101,83,7,184,1,158,1,8,214,2,64,6,150,3,20,10,170,3,19,11,189,3,2,12,191,3,125,13,188,4,4,14,192,4,4,0,5,1,15,0,14,0,19,0,3,4,1,12,0,0,0,0,0,1,2,7,1,0,0,2,1,7,0,3,4,2,0,0,12,0,1,1,12,0,5,2,3,1,12,0,16,4,5,1,12,0,6,1,6,1,12,1,7,9,6,1,0,1,8,11,6,1,0,1,9,15,5,1,0,1,18,6,9,1,0,2,11,12,13,1,8,3,10,7,8,0,7,6,5,6,8,6,6,6,4,6,2,9,0,7,8,4,1,11,0,1,9,0,1,7,11,0,1,9,0,2,9,0,8,1,3,7,11,0,1,9,0,9,0,8,1,0,1,9,0,1,7,8,4,1,5,1,11,2,1,9,0,2,8,3,9,0,1,7,11,2,1,9,0,1,6,9,0,1,8,3,2,8,3,5,2,7,11,2,1,9,0,9,0,6,66,111,114,114,111,119,2,73,68,6,79,112,116,105,111,110,8,82,101,102,101,114,101,110,116,9,84,120,67,111,110,116,101,120,116,6,98,111,114,114,111,119,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,7,101,120,116,114,97,99,116,4,102,105,108,108,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,3,111,98,106,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,117,116,95,98,97,99,107,3,114,101,102,4,115,111,109,101,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,2,11,5,20,11,2,1,9,0,1,2,2,17,5,13,8,3,0,6,0,1,0,0,5,6,11,1,17,9,11,0,56,0,57,0,2,1,1,0,0,10,14,10,0,54,0,56,1,12,2,14,2,56,2,12,1,11,2,11,0,55,1,20,11,1,18,1,2,2,1,0,0,14,30,11,2,19,1,12,3,12,4,14,1,56,2,11,3,33,4,10,5,14,11,0,1,7,1,39,10,0,55,1,20,11,4,33,4,21,5,25,11,0,1,7,0,39,11,0,54,0,11,1,56,3,2,3,1,0,0,9,7,11,0,58,0,12,1,1,11,1,56,4,2,0,1,0,0,0,6,1,6,0],"clock":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,12,3,20,31,4,51,2,5,53,30,7,83,122,8,205,1,32,6,237,1,44,10,153,2,8,12,161,2,79,13,240,2,2,0,3,0,7,0,11,0,12,0,0,8,0,1,2,4,0,3,1,2,0,0,10,0,1,0,0,5,2,3,0,0,4,4,3,0,1,3,3,6,0,2,9,8,3,1,8,3,8,2,5,0,4,7,1,6,8,0,1,3,1,6,8,2,0,3,7,8,0,3,6,8,2,1,5,1,8,1,1,8,0,1,9,0,5,67,108,111,99,107,9,84,120,67,111,110,116,101,120,116,3,85,73,68,5,99,108,111,99,107,25,99,111,110,115,101,110,115,117,115,95,99,111,109,109,105,116,95,112,114,111,108,111,103,117,101,6,99,114,101,97,116,101,2,105,100,6,111,98,106,101,99,116,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,1,10,3,0,1,0,0,3,4,11,0,16,0,20,2,1,0,0,0,3,13,11,0,17,5,7,1,33,4,6,5,8,7,0,39,17,3,6,0,0,0,0,0,0,0,0,18,0,56,0,2,2,0,0,0,3,15,11,2,17,5,7,1,33,4,6,5,10,11,0,1,7,0,39,11,1,11,0,15,0,21,2,0,1,0],"coin":[161,28,235,11,6,0,0,0,13,1,0,20,2,20,62,3,82,155,2,4,237,2,34,5,143,3,221,2,7,236,5,164,5,8,144,11,64,6,208,11,30,10,238,11,52,11,162,12,6,12,168,12,249,4,13,161,17,14,14,175,17,14,0,15,1,11,1,43,1,48,0,12,0,42,0,56,0,58,0,59,0,64,0,1,12,1,0,1,0,2,12,1,0,1,0,7,12,1,0,1,0,3,3,1,0,1,1,5,7,0,2,4,7,1,0,0,3,5,7,0,4,0,4,1,0,1,4,6,4,1,0,1,5,9,4,0,7,8,2,0,9,10,7,0,0,55,0,1,1,0,0,57,2,3,1,0,0,50,0,4,1,0,0,51,5,6,1,0,0,66,7,1,1,0,0,12,7,8,1,0,0,13,9,10,1,0,0,24,11,12,1,0,0,33,12,13,1,0,0,54,14,12,1,0,0,45,15,16,1,0,0,35,17,16,1,0,0,47,18,12,1,0,0,23,18,19,1,0,0,67,20,12,1,0,0,22,12,16,1,0,0,16,21,22,1,2,0,36,23,12,1,0,0,38,24,13,1,0,0,14,25,1,1,0,0,37,26,16,1,0,0,62,27,16,1,0,0,63,28,16,1,0,0,60,27,16,1,0,0,61,28,16,1,0,0,25,29,30,1,0,0,28,29,31,1,0,0,29,29,32,1,0,0,26,29,31,1,0,0,27,29,33,1,0,0,49,5,4,1,0,1,48,41,32,0,2,46,34,46,1,0,3,65,41,31,0,4,17,34,3,1,2,4,19,43,1,1,0,4,22,13,16,1,0,4,32,42,13,1,0,4,35,37,1,1,0,4,47,36,13,1,0,4,52,4,1,1,0,4,66,8,1,1,0,4,67,16,13,1,0,5,20,35,16,0,5,40,20,35,0,6,44,44,16,1,12,8,34,39,40,1,2,9,41,32,45,0,40,34,41,34,39,34,8,34,38,34,9,34,4,34,12,34,42,34,36,34,46,34,34,34,37,34,35,34,17,34,45,12,32,45,1,6,11,2,1,9,0,1,3,1,11,2,1,9,0,1,11,8,1,9,0,1,6,11,8,1,9,0,1,7,11,2,1,9,0,1,7,11,8,1,9,0,1,6,11,0,1,9,0,1,6,11,7,1,9,0,1,7,11,0,1,9,0,1,7,11,7,1,9,0,2,11,7,1,9,0,7,8,10,1,11,0,1,9,0,1,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,10,2,7,11,7,1,9,0,11,0,1,9,0,0,2,7,11,0,1,9,0,11,0,1,9,0,3,7,11,0,1,9,0,3,7,8,10,1,10,11,0,1,9,0,1,7,8,10,7,9,0,2,10,2,10,2,10,2,11,5,1,8,11,7,8,10,2,11,2,1,9,0,11,1,1,9,0,3,7,11,2,1,9,0,3,7,8,10,2,7,11,2,1,9,0,3,2,7,11,2,1,9,0,11,0,1,9,0,4,7,11,2,1,9,0,3,5,7,8,10,3,6,11,2,1,9,0,7,11,1,1,9,0,8,6,3,6,11,2,1,9,0,7,11,1,1,9,0,8,4,1,6,11,1,1,9,0,1,2,1,8,6,1,8,4,1,11,5,1,8,11,1,9,0,1,8,9,2,7,11,7,1,9,0,3,2,7,11,7,1,9,0,11,7,1,9,0,3,3,3,10,11,0,1,9,0,1,6,9,0,1,1,1,10,2,2,7,11,8,1,9,0,3,2,7,11,8,1,9,0,11,7,1,9,0,2,9,0,5,1,8,11,1,11,5,1,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,15,67,117,114,114,101,110,99,121,67,114,101,97,116,101,100,6,79,112,116,105,111,110,6,83,116,114,105,110,103,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,85,114,108,5,97,115,99,105,105,7,98,97,108,97,110,99,101,11,98,97,108,97,110,99,101,95,109,117,116,4,98,117,114,110,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,13,99,114,101,97,116,101,95,115,117,112,112,108,121,8,100,101,99,105,109,97,108,115,15,100,101,99,114,101,97,115,101,95,115,117,112,112,108,121,6,100,101,108,101,116,101,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,122,101,114,111,13,100,105,118,105,100,101,95,105,110,116,111,95,110,12,102,114,111,109,95,98,97,108,97,110,99,101,12,103,101,116,95,100,101,99,105,109,97,108,115,15,103,101,116,95,100,101,115,99,114,105,112,116,105,111,110,12,103,101,116,95,105,99,111,110,95,117,114,108,8,103,101,116,95,110,97,109,101,10,103,101,116,95,115,121,109,98,111,108,8,105,99,111,110,95,117,114,108,2,105,100,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,12,105,110,116,111,95,98,97,108,97,110,99,101,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,4,106,111,105,110,4,109,105,110,116,17,109,105,110,116,95,97,110,100,95,116,114,97,110,115,102,101,114,12,109,105,110,116,95,98,97,108,97,110,99,101,4,110,97,109,101,3,110,101,119,10,110,101,119,95,117,110,115,97,102,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,3,112,117,116,4,115,111,109,101,5,115,112,108,105,116,6,115,116,114,105,110,103,6,115,117,112,112,108,121,12,115,117,112,112,108,121,95,105,109,109,117,116,10,115,117,112,112,108,121,95,109,117,116,12,115,117,112,112,108,121,95,118,97,108,117,101,6,115,121,109,98,111,108,4,116,97,107,101,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,5,116,121,112,101,115,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,15,117,112,100,97,116,101,95,105,99,111,110,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,13,117,112,100,97,116,101,95,115,121,109,98,111,108,3,117,114,108,4,117,116,102,56,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,2,31,8,9,12,11,7,1,9,0,1,2,6,31,8,9,18,2,39,8,6,53,8,4,21,8,6,30,11,5,1,8,11,2,2,2,31,8,9,55,11,8,1,9,0,3,2,1,18,2,2,34,0,34,1,34,0,1,0,0,16,4,11,0,55,0,56,0,2,1,1,0,0,3,6,11,0,58,0,12,1,17,43,11,1,2,2,1,0,0,16,3,11,0,55,0,2,3,1,0,0,16,3,11,0,54,0,2,4,1,0,0,16,4,11,0,55,1,56,1,2,5,1,0,0,16,3,11,0,55,1,2,6,1,0,0,16,3,11,0,54,1,2,7,1,0,0,16,5,11,1,17,44,11,0,57,1,2,8,1,0,0,13,6,11,0,58,1,12,1,17,43,11,1,2,9,1,0,0,16,7,11,2,17,44,11,0,11,1,56,2,57,1,2,10,1,0,0,16,6,11,0,11,1,56,3,56,4,1,2,11,1,4,0,13,10,11,1,58,1,12,2,17,43,11,0,54,1,11,2,56,4,1,2,12,1,0,0,16,6,11,0,54,1,11,1,11,2,56,5,2,13,1,0,0,38,59,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,11,11,0,1,11,2,1,7,1,39,10,1,10,0,46,56,6,37,4,18,5,24,11,0,1,11,2,1,7,2,39,64,12,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,3,10,0,46,56,6,10,1,26,12,4,40,10,3,10,1,6,1,0,0,0,0,0,0,0,23,35,4,53,5,42,13,5,10,0,10,4,10,2,56,7,68,12,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,34,11,0,1,11,2,1,11,5,2,14,1,0,0,16,5,11,0,17,44,56,8,57,1,2,15,1,0,0,13,7,11,0,58,1,12,1,17,43,11,1,56,9,2,16,1,0,0,16,25,14,0,56,10,4,4,5,8,11,6,1,7,0,39,10,6,17,44,11,0,56,11,57,0,11,6,17,44,11,1,11,3,17,33,11,2,17,31,11,4,17,33,11,5,57,2,2,17,1,0,0,16,8,11,2,17,44,11,0,54,0,11,1,56,12,57,1,2,18,1,0,0,16,5,11,0,54,0,11,1,56,12,2,19,1,4,0,13,9,11,1,58,1,12,2,17,43,11,0,54,0,11,2,56,13,2,20,1,4,0,16,7,11,0,11,1,11,3,56,14,11,2,56,15,2,21,1,4,0,16,5,11,2,11,1,54,2,21,2,22,1,4,0,16,5,11,2,11,1,54,3,21,2,23,1,4,0,16,5,11,2,11,1,54,4,21,2,24,1,4,0,16,7,11,2,17,47,56,16,11,1,54,5,21,2,25,1,0,0,16,4,11,0,55,6,20,2,26,1,0,0,16,4,11,0,55,2,20,2,27,1,0,0,16,4,11,0,55,3,20,2,28,1,0,0,16,4,11,0,55,4,20,2,29,1,0,0,16,4,11,0,55,5,20,2,30,1,0,0,16,3,11,0,55,0,2,2,1,0,1,1,2,1,3,1,4,1,5,1,1,0,34,1,34,2,34,3,34,4,34,5,34,6,34,0],"display":[161,28,235,11,6,0,0,0,13,1,0,16,2,16,46,3,62,132,1,4,194,1,22,5,216,1,196,1,7,156,3,223,2,8,251,5,64,6,187,6,20,10,207,6,38,11,245,6,6,12,251,6,160,3,13,155,10,6,14,161,10,6,0,14,1,31,0,18,0,26,0,27,0,32,0,33,0,36,0,0,12,1,8,1,0,1,3,1,8,1,0,8,3,1,8,1,1,4,7,0,3,2,7,0,3,6,4,0,4,3,12,0,6,5,2,0,7,7,7,2,1,0,0,0,0,24,0,1,1,8,0,25,2,1,1,8,0,12,0,3,1,8,0,35,4,3,1,8,0,9,5,3,1,8,0,11,6,3,1,8,0,15,5,3,1,8,0,29,7,3,1,8,0,23,8,9,1,8,0,37,10,11,1,8,0,19,10,12,1,8,0,13,13,1,1,8,0,10,5,3,1,8,2,16,14,3,1,3,3,24,13,28,0,3,34,21,22,0,4,20,8,9,1,0,5,28,19,3,1,12,6,30,17,18,0,7,17,3,30,2,1,0,7,22,31,3,2,1,0,7,29,26,27,2,1,0,8,14,11,14,0,14,12,14,17,1,13,23,21,25,16,14,13,29,19,25,20,25,2,6,8,6,7,8,7,1,11,0,1,9,0,4,6,8,6,10,8,3,10,8,3,7,8,7,0,1,7,11,0,1,9,0,3,7,11,0,1,9,0,8,3,8,3,3,7,11,0,1,9,0,10,8,3,10,8,3,2,7,11,0,1,9,0,8,3,1,6,8,6,1,1,1,6,11,0,1,9,0,1,13,1,6,11,8,2,8,3,8,3,1,7,8,7,1,9,0,3,11,0,1,9,0,3,3,1,8,3,1,6,8,7,1,5,2,9,0,5,2,13,11,8,2,8,3,8,3,1,6,8,5,1,8,4,1,11,2,1,9,0,2,3,3,2,8,3,8,3,2,7,11,8,2,9,0,9,1,6,9,0,2,9,0,9,1,1,8,5,1,11,1,1,9,0,1,11,8,2,9,0,9,1,3,7,11,8,2,9,0,9,1,9,0,9,1,7,68,105,115,112,108,97,121,14,68,105,115,112,108,97,121,67,114,101,97,116,101,100,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,3,85,73,68,6,86,101,99,77,97,112,14,86,101,114,115,105,111,110,85,112,100,97,116,101,100,3,97,100,100,12,97,100,100,95,105,110,116,101,114,110,97,108,12,97,100,100,95,109,117,108,116,105,112,108,101,15,99,114,101,97,116,101,95,97,110,100,95,107,101,101,112,15,99,114,101,97,116,101,95,105,110,116,101,114,110,97,108,7,100,105,115,112,108,97,121,4,101,100,105,116,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,6,102,105,101,108,100,115,12,102,114,111,109,95,112,97,99,107,97,103,101,2,105,100,6,105,110,115,101,114,116,13,105,115,95,97,117,116,104,111,114,105,122,101,100,3,110,101,119,15,110,101,119,95,119,105,116,104,95,102,105,101,108,100,115,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,6,115,101,110,100,101,114,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,112,100,97,116,101,95,118,101,114,115,105,111,110,7,118,101,99,95,109,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,3,21,8,5,19,11,8,2,8,3,8,3,37,13,1,2,1,21,8,4,2,2,3,21,8,4,37,13,19,11,8,2,8,3,8,3,2,14,1,14,0,14,0,1,0,0,3,11,11,0,56,0,4,4,5,8,11,1,1,7,0,39,11,1,56,1,2,1,1,0,0,15,43,14,1,65,16,12,6,10,6,14,2,65,16,33,4,9,5,15,11,0,1,11,3,1,7,1,39,6,0,0,0,0,0,0,0,0,12,5,11,0,11,3,56,2,12,4,10,5,10,6,35,4,41,5,26,13,4,14,1,10,5,66,16,20,14,2,10,5,66,16,20,56,3,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,21,11,4,2,2,1,4,0,3,8,11,0,10,1,56,2,11,1,46,17,18,56,4,2,3,1,4,0,20,24,10,0,55,0,20,72,1,0,22,10,0,54,0,21,10,0,55,0,20,12,1,10,0,55,1,20,12,2,11,0,55,2,17,15,11,1,11,2,57,0,56,5,2,4,1,4,0,3,5,11,0,11,1,11,2,56,3,2,5,1,4,0,24,38,14,1,65,16,12,4,10,4,14,2,65,16,33,4,9,5,13,11,0,1,7,1,39,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,35,5,20,10,0,14,1,10,3,66,16,20,14,2,10,3,66,16,20,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,15,11,0,1,2,6,1,4,0,3,11,10,0,54,1,14,1,56,6,1,1,11,0,11,1,11,2,56,3,2,7,1,4,0,3,7,11,0,54,1,14,1,56,6,1,1,2,8,1,0,0,3,3,11,0,56,7,2,9,1,0,0,3,4,11,0,55,0,20,2,10,1,0,0,3,3,11,0,55,1,2,11,0,0,0,28,12,11,0,17,14,12,1,14,1,17,15,57,1,56,8,11,1,56,9,72,0,0,57,2,2,12,0,0,0,3,6,11,0,54,1,11,1,11,2,56,10,2,0,2,0,1,0,0,0,14,1,14,2,14,0],"dynamic_field":[161,28,235,11,6,0,0,0,14,1,0,6,2,6,22,3,28,133,1,4,161,1,24,5,185,1,168,1,7,225,2,129,3,8,226,5,64,6,162,6,40,10,202,6,12,11,214,6,2,12,216,6,235,2,13,195,9,6,14,201,9,8,15,209,9,2,0,11,1,26,0,25,0,0,8,2,7,0,4,0,1,2,7,1,0,0,2,1,7,0,2,3,4,0,0,4,0,1,2,7,4,0,6,2,3,2,7,4,0,9,4,5,2,7,4,0,27,4,6,2,7,4,0,13,2,7,1,7,0,29,4,8,2,7,4,0,14,2,7,2,7,4,0,15,2,9,1,7,0,16,4,10,1,7,0,19,11,12,1,7,0,5,11,1,1,8,0,7,9,13,1,8,0,8,10,14,1,8,0,28,15,16,1,8,0,17,15,7,0,0,18,15,7,1,8,1,24,1,24,1,0,1,30,16,24,1,0,2,10,19,1,0,2,21,28,12,0,2,23,12,19,0,2,31,18,12,0,9,16,10,21,11,21,12,21,13,21,4,16,3,20,17,6,16,6,15,21,11,26,12,26,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,9,1,2,6,8,3,5,2,7,8,3,5,2,5,9,0,1,5,1,6,9,0,1,7,9,0,2,5,5,1,9,0,3,11,0,2,9,0,9,1,5,5,1,6,8,3,1,8,3,2,9,0,9,1,1,11,0,2,9,0,9,1,3,5,5,9,1,2,9,0,11,1,1,9,1,1,11,1,1,9,0,4,6,11,0,2,9,0,8,2,5,6,8,3,6,8,2,1,11,0,2,9,0,8,2,2,9,0,8,2,1,6,8,2,4,7,11,0,2,9,0,8,2,5,7,8,3,7,8,2,5,70,105,101,108,100,2,73,68,6,79,112,116,105,111,110,3,85,73,68,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,6,100,101,108,101,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,16,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,17,104,97,115,104,95,116,121,112,101,95,97,110,100,95,107,101,121,2,105,100,13,105,100,95,116,111,95,97,100,100,114,101,115,115,4,110,97,109,101,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,3,20,8,3,22,9,0,32,9,1,0,20,0,1,0,0,17,26,11,0,46,17,21,12,5,10,5,10,1,56,0,12,4,10,5,10,4,17,14,32,4,14,5,16,7,0,39,11,4,17,20,11,1,11,2,57,0,12,3,11,5,11,3,56,1,2,1,1,0,0,12,10,10,0,17,21,11,1,56,0,12,2,11,0,11,2,56,2,55,0,2,2,1,0,0,12,11,10,0,46,17,21,11,1,56,0,12,2,11,0,11,2,56,3,54,0,2,3,1,0,0,22,17,11,0,46,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,4,58,0,12,4,1,17,18,11,4,2,4,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,17,14,2,5,1,0,0,23,19,10,0,10,1,12,2,46,11,2,56,5,4,13,11,0,11,1,56,6,56,7,12,3,5,17,11,0,1,56,8,12,3,11,3,2,6,1,0,0,15,11,11,0,17,21,12,3,10,3,11,1,56,0,12,2,11,3,11,2,56,9,2,7,3,0,0,25,22,10,0,17,21,11,1,56,0,12,3,11,0,11,3,56,10,12,2,10,2,55,1,12,4,10,2,55,2,1,11,2,55,3,12,5,11,4,11,5,17,19,2,8,3,0,0,29,24,10,0,46,17,21,11,1,56,0,12,3,11,0,11,3,56,11,12,2,10,2,54,1,12,4,10,2,54,2,1,11,2,54,3,12,5,11,4,11,5,46,17,19,2,9,3,2,0,10,3,2,0,11,3,2,0,12,3,2,0,13,3,2,0,14,3,2,0,15,3,2,0,0,2,0,0,0,1,0,20,1,27,2,27,0,27,0,12,0],"dynamic_object_field":[161,28,235,11,6,0,0,0,10,1,0,8,2,8,20,3,28,138,1,4,166,1,26,5,192,1,131,1,7,195,2,178,2,8,245,4,64,10,181,5,6,11,187,5,2,12,189,5,233,1,0,11,1,22,0,10,0,21,0,3,7,1,0,0,1,1,7,1,0,0,3,0,7,0,3,2,4,0,0,4,0,1,2,7,12,0,6,2,3,2,7,12,0,9,4,5,2,7,12,0,23,4,6,2,7,12,0,12,2,7,1,7,0,13,2,7,2,7,12,0,17,2,8,1,7,1,20,1,24,1,0,1,25,10,24,1,0,2,4,0,1,2,7,4,2,5,18,1,1,8,2,7,15,11,1,8,2,8,19,20,1,8,2,13,2,7,2,7,4,2,14,2,15,1,7,2,15,4,19,1,7,2,16,22,7,1,8,2,23,4,6,2,7,4,2,24,22,10,1,8,3,17,11,12,1,8,3,18,17,12,0,3,26,16,17,0,19,6,9,13,14,14,10,6,11,6,15,14,12,6,18,6,17,13,13,13,16,6,7,12,8,12,3,7,8,3,9,0,9,1,0,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,1,1,11,1,1,8,2,3,11,0,1,9,0,8,2,11,0,1,9,0,1,9,0,1,6,9,0,1,8,2,2,11,0,1,9,0,8,2,1,11,0,1,9,0,2,6,8,3,5,1,6,8,3,1,5,2,5,9,0,2,7,8,3,5,1,7,9,0,4,11,0,1,9,0,11,0,1,9,0,9,1,5,2,5,5,2,11,0,1,9,0,5,1,11,1,1,9,0,2,73,68,6,79,112,116,105,111,110,3,85,73,68,7,87,114,97,112,112,101,114,3,97,100,100,16,97,100,100,95,99,104,105,108,100,95,111,98,106,101,99,116,6,98,111,114,114,111,119,19,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,23,98,111,114,114,111,119,95,99,104,105,108,100,95,111,98,106,101,99,116,95,109,117,116,10,98,111,114,114,111,119,95,109,117,116,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,10,102,105,101,108,100,95,105,110,102,111,14,102,105,101,108,100,95,105,110,102,111,95,109,117,116,24,104,97,115,95,99,104,105,108,100,95,111,98,106,101,99,116,95,119,105,116,104,95,116,121,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,4,110,97,109,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,99,104,105,108,100,95,111,98,106,101,99,116,4,115,111,109,101,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,19,9,0,0,10,0,1,0,0,9,21,11,1,57,0,12,5,14,2,56,0,12,4,10,0,10,5,11,4,56,1,11,0,11,5,12,3,46,11,3,56,2,1,17,21,11,2,56,3,2,1,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,2,56,4,2,2,1,0,0,14,8,11,1,57,0,12,2,11,0,11,2,56,5,56,6,2,3,1,0,0,21,20,11,1,57,0,12,3,10,0,10,3,12,2,46,11,2,56,2,12,5,17,21,11,5,56,7,12,4,11,0,11,3,56,8,1,11,4,2,4,1,0,0,14,7,11,1,57,0,12,2,11,0,11,2,56,9,2,5,1,0,0,23,20,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,9,2,11,0,11,2,56,2,12,3,17,21,11,3,56,10,2,6,1,0,0,23,21,11,1,57,0,12,2,10,0,10,2,56,9,32,4,12,11,0,1,56,11,2,11,0,11,2,56,2,12,3,1,11,3,17,20,56,12,2,0],"ecdsa_k1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,15,5,17,28,7,45,64,8,109,32,6,141,1,26,12,167,1,12,0,1,0,2,0,1,0,0,0,2,1,0,0,3,3,4,0,3,6,10,2,6,10,2,2,1,10,2,1,6,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,17,100,101,99,111,109,112,114,101,115,115,95,112,117,98,107,101,121,8,101,99,100,115,97,95,107,49,19,115,101,99,112,50,53,54,107,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,107,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,2,1,2,0,0],"ecdsa_r1":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,10,5,12,24,7,36,46,8,82,32,6,114,26,12,140,1,8,0,0,0,1,0,1,0,0,2,2,3,0,3,6,10,2,6,10,2,2,1,10,2,4,6,10,2,6,10,2,6,10,2,2,1,1,8,101,99,100,115,97,95,114,49,19,115,101,99,112,50,53,54,114,49,95,101,99,114,101,99,111,118,101,114,16,115,101,99,112,50,53,54,114,49,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,2,0,1,1,2,0,0],"ecvrf":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,5,5,7,15,7,22,19,8,41,32,6,73,30,12,103,4,0,0,0,1,0,1,0,4,6,10,2,6,10,2,6,10,2,6,10,2,1,1,5,101,99,118,114,102,12,101,99,118,114,102,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,1,2,0,0],"ed25519":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,12,7,19,23,8,42,32,12,74,4,0,0,0,1,0,1,0,3,6,10,2,6,10,2,6,10,2,1,1,7,101,100,50,53,53,49,57,14,101,100,50,53,53,49,57,95,118,101,114,105,102,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"event":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,4,7,12,11,8,23,32,12,55,4,0,1,0,0,0,1,1,3,1,9,0,0,4,101,109,105,116,5,101,118,101,110,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"groth16":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,16,3,18,50,5,68,76,7,144,1,237,2,8,253,3,32,6,157,4,30,10,187,4,32,12,219,4,180,1,13,143,6,14,0,10,0,0,7,0,0,1,7,0,0,3,7,0,0,2,7,0,0,5,0,1,0,0,6,0,1,0,0,16,2,3,0,0,17,3,4,0,0,15,5,6,0,0,14,5,7,0,0,12,8,3,0,0,13,9,3,0,0,18,10,11,0,0,19,12,11,0,0,1,8,0,4,10,2,10,2,10,2,10,2,1,8,1,1,10,10,2,1,10,2,1,8,2,1,8,3,2,6,8,0,6,10,2,2,2,6,10,2,4,6,8,0,6,8,1,6,8,2,6,8,3,1,1,7,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,6,10,2,5,67,117,114,118,101,20,80,114,101,112,97,114,101,100,86,101,114,105,102,121,105,110,103,75,101,121,11,80,114,111,111,102,80,111,105,110,116,115,17,80,117,98,108,105,99,80,114,111,111,102,73,110,112,117,116,115,22,97,108,112,104,97,95,103,49,95,98,101,116,97,95,103,50,95,98,121,116,101,115,8,98,108,115,49,50,51,56,49,5,98,110,50,53,52,5,98,121,116,101,115,21,100,101,108,116,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,21,103,97,109,109,97,95,103,50,95,110,101,103,95,112,99,95,98,121,116,101,115,7,103,114,111,116,104,49,54,2,105,100,21,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,30,112,114,101,112,97,114,101,95,118,101,114,105,102,121,105,110,103,95,107,101,121,95,105,110,116,101,114,110,97,108,23,112,114,111,111,102,95,112,111,105,110,116,115,95,102,114,111,109,95,98,121,116,101,115,30,112,117,98,108,105,99,95,112,114,111,111,102,95,105,110,112,117,116,115,95,102,114,111,109,95,98,121,116,101,115,14,112,118,107,95,102,114,111,109,95,98,121,116,101,115,12,112,118,107,95,116,111,95,98,121,116,101,115,20,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,29,118,101,114,105,102,121,95,103,114,111,116,104,49,54,95,112,114,111,111,102,95,105,110,116,101,114,110,97,108,21,118,107,95,103,97,109,109,97,95,97,98,99,95,103,49,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,1,11,2,1,2,4,20,10,2,4,10,2,9,10,2,8,10,2,2,2,1,7,10,2,3,2,1,7,10,2,0,1,0,0,0,3,49,0,18,0,2,1,1,0,0,0,3,49,1,18,0,2,2,1,0,0,0,6,11,0,11,1,11,2,11,3,18,1,2,3,1,0,0,4,24,64,5,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,68,5,13,1,14,0,16,1,20,68,5,13,1,14,0,16,2,20,68,5,13,1,14,0,16,3,20,68,5,11,1,2,4,1,0,0,0,3,11,0,18,2,2,5,1,0,0,0,3,11,0,18,3,2,6,1,0,0,0,6,11,0,16,4,20,11,1,17,7,2,7,0,2,0,8,1,0,0,0,17,11,0,16,4,20,10,1,16,0,10,1,16,1,10,1,16,2,11,1,16,3,11,2,16,5,11,3,16,6,17,9,2,9,0,2,0,1,0,1,1,1,2,1,3,0,0,2,0,3,0,0],"hash":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,10,5,12,7,7,19,26,8,45,32,12,77,8,0,1,0,0,0,1,0,0,2,0,1,0,1,6,10,2,1,10,2,10,98,108,97,107,101,50,98,50,53,54,4,104,97,115,104,9,107,101,99,99,97,107,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,1,1,2,0,0],"hex":[161,28,235,11,6,0,0,0,8,1,0,4,3,4,21,4,25,2,5,27,37,7,64,44,8,108,64,6,172,1,159,6,12,203,7,194,2,0,4,1,5,0,3,0,0,0,0,1,0,0,0,0,2,1,1,0,1,0,3,4,1,0,3,1,1,10,2,1,2,5,10,10,2,7,10,2,3,3,10,2,2,7,10,9,0,10,9,0,0,4,2,3,3,10,2,5,1,1,1,2,2,6,97,112,112,101,110,100,6,100,101,99,111,100,101,11,100,101,99,111,100,101,95,98,121,116,101,6,101,110,99,111,100,101,3,104,101,120,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,10,10,2,130,6,128,2,2,48,48,2,48,49,2,48,50,2,48,51,2,48,52,2,48,53,2,48,54,2,48,55,2,48,56,2,48,57,2,48,97,2,48,98,2,48,99,2,48,100,2,48,101,2,48,102,2,49,48,2,49,49,2,49,50,2,49,51,2,49,52,2,49,53,2,49,54,2,49,55,2,49,56,2,49,57,2,49,97,2,49,98,2,49,99,2,49,100,2,49,101,2,49,102,2,50,48,2,50,49,2,50,50,2,50,51,2,50,52,2,50,53,2,50,54,2,50,55,2,50,56,2,50,57,2,50,97,2,50,98,2,50,99,2,50,100,2,50,101,2,50,102,2,51,48,2,51,49,2,51,50,2,51,51,2,51,52,2,51,53,2,51,54,2,51,55,2,51,56,2,51,57,2,51,97,2,51,98,2,51,99,2,51,100,2,51,101,2,51,102,2,52,48,2,52,49,2,52,50,2,52,51,2,52,52,2,52,53,2,52,54,2,52,55,2,52,56,2,52,57,2,52,97,2,52,98,2,52,99,2,52,100,2,52,101,2,52,102,2,53,48,2,53,49,2,53,50,2,53,51,2,53,52,2,53,53,2,53,54,2,53,55,2,53,56,2,53,57,2,53,97,2,53,98,2,53,99,2,53,100,2,53,101,2,53,102,2,54,48,2,54,49,2,54,50,2,54,51,2,54,52,2,54,53,2,54,54,2,54,55,2,54,56,2,54,57,2,54,97,2,54,98,2,54,99,2,54,100,2,54,101,2,54,102,2,55,48,2,55,49,2,55,50,2,55,51,2,55,52,2,55,53,2,55,54,2,55,55,2,55,56,2,55,57,2,55,97,2,55,98,2,55,99,2,55,100,2,55,101,2,55,102,2,56,48,2,56,49,2,56,50,2,56,51,2,56,52,2,56,53,2,56,54,2,56,55,2,56,56,2,56,57,2,56,97,2,56,98,2,56,99,2,56,100,2,56,101,2,56,102,2,57,48,2,57,49,2,57,50,2,57,51,2,57,52,2,57,53,2,57,54,2,57,55,2,57,56,2,57,57,2,57,97,2,57,98,2,57,99,2,57,100,2,57,101,2,57,102,2,97,48,2,97,49,2,97,50,2,97,51,2,97,52,2,97,53,2,97,54,2,97,55,2,97,56,2,97,57,2,97,97,2,97,98,2,97,99,2,97,100,2,97,101,2,97,102,2,98,48,2,98,49,2,98,50,2,98,51,2,98,52,2,98,53,2,98,54,2,98,55,2,98,56,2,98,57,2,98,97,2,98,98,2,98,99,2,98,100,2,98,101,2,98,102,2,99,48,2,99,49,2,99,50,2,99,51,2,99,52,2,99,53,2,99,54,2,99,55,2,99,56,2,99,57,2,99,97,2,99,98,2,99,99,2,99,100,2,99,101,2,99,102,2,100,48,2,100,49,2,100,50,2,100,51,2,100,52,2,100,53,2,100,54,2,100,55,2,100,56,2,100,57,2,100,97,2,100,98,2,100,99,2,100,100,2,100,101,2,100,102,2,101,48,2,101,49,2,101,50,2,101,51,2,101,52,2,101,53,2,101,54,2,101,55,2,101,56,2,101,57,2,101,97,2,101,98,2,101,99,2,101,100,2,101,101,2,101,102,2,102,48,2,102,49,2,102,50,2,102,51,2,102,52,2,102,53,2,102,54,2,102,55,2,102,56,2,102,57,2,102,97,2,102,98,2,102,99,2,102,100,2,102,101,2,102,102,10,2,1,0,0,1,0,0,2,33,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,4,12,5,12,3,10,3,10,4,35,4,31,5,12,13,5,12,2,7,2,12,1,11,2,14,1,14,0,10,3,66,1,20,52,66,0,20,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,5,2,1,1,0,0,5,47,6,0,0,0,0,0,0,0,0,7,3,14,0,65,1,12,3,12,4,12,2,10,3,6,2,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,14,5,16,7,0,39,10,2,10,3,35,4,45,5,21,14,0,10,2,66,1,20,17,2,49,16,24,14,0,10,2,6,1,0,0,0,0,0,0,0,22,66,1,20,17,2,22,12,1,13,4,11,1,68,1,11,2,6,2,0,0,0,0,0,0,0,22,12,2,5,16,11,4,2,2,0,0,0,6,64,49,48,10,0,37,4,9,10,0,49,58,35,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,5,5,62,49,65,10,0,37,4,27,10,0,49,71,35,12,2,5,29,9,12,2,11,2,4,38,49,10,11,0,22,49,65,23,12,4,5,60,49,97,10,0,37,4,47,10,0,49,103,35,12,3,5,49,9,12,3,11,3,4,52,5,54,7,1,39,49,10,11,0,22,49,97,23,12,4,11,4,12,5,11,5,2,0],"hmac":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,5,5,7,10,7,17,19,8,36,32,12,68,4,0,0,0,1,0,1,0,2,6,10,2,6,10,2,1,10,2,4,104,109,97,99,13,104,109,97,99,95,115,104,97,51,95,50,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"kiosk":[161,28,235,11,6,0,0,0,13,1,0,22,2,22,94,3,116,230,2,4,218,3,64,5,154,4,250,3,7,148,8,189,7,8,209,15,64,6,145,16,130,1,10,147,17,101,11,248,17,8,12,128,18,244,13,13,244,31,18,14,134,32,6,0,51,1,60,0,21,0,26,0,30,0,31,0,33,0,59,0,81,0,83,0,84,0,8,12,0,0,9,12,0,0,13,12,1,12,1,0,1,0,0,0,4,7,0,0,10,7,0,0,11,7,0,0,6,3,1,12,1,0,7,3,1,12,1,0,5,3,1,12,1,1,12,7,1,0,0,2,0,4,1,0,1,3,2,12,1,0,1,7,3,7,0,7,18,4,0,8,14,2,0,9,15,12,1,0,1,9,16,0,1,0,1,10,17,2,0,0,57,0,1,0,0,25,2,3,0,0,79,4,5,0,0,80,6,5,0,0,62,7,5,1,12,0,55,8,5,1,12,0,82,9,10,1,12,0,53,11,5,1,12,0,63,12,5,1,12,0,28,9,5,1,12,0,68,13,14,1,12,0,54,15,16,1,12,0,72,17,14,1,12,0,75,18,5,1,12,0,90,19,3,0,0,39,20,21,0,0,40,20,21,1,12,0,46,20,21,0,0,44,20,21,0,0,45,20,21,0,0,38,22,21,0,0,87,22,23,0,0,78,24,5,0,0,85,25,26,0,0,86,27,23,0,0,61,25,28,0,0,48,25,29,0,0,66,25,30,0,0,67,22,31,0,0,22,32,33,1,12,0,23,9,34,1,12,0,24,9,35,1,12,0,76,36,5,1,12,0,70,37,38,1,12,0,69,37,38,1,12,0,71,37,30,1,12,1,29,70,10,1,0,1,47,69,21,1,0,2,50,61,30,1,0,2,89,71,30,1,0,2,91,5,42,1,0,3,37,46,47,1,0,3,42,47,42,1,0,3,82,72,47,1,0,3,89,60,30,1,0,4,19,49,5,2,7,4,4,34,74,21,1,7,4,73,53,55,2,7,4,4,74,53,54,2,7,4,5,19,49,5,2,7,12,5,22,74,77,2,7,12,5,23,53,78,2,7,12,5,34,74,21,1,7,5,35,74,21,2,7,12,5,73,53,55,2,7,12,6,32,10,5,1,3,7,27,40,5,0,7,41,33,38,1,8,7,57,0,40,0,7,88,26,38,0,9,58,63,64,1,0,10,77,43,28,0,40,41,57,44,41,41,57,10,49,48,45,50,4,10,48,52,54,48,16,10,45,52,55,57,7,10,47,52,55,58,44,41,42,41,38,41,48,50,55,62,60,10,10,10,37,30,36,30,39,41,43,41,52,73,53,48,46,75,46,76,50,48,51,48,1,7,8,18,2,8,0,8,1,3,8,0,8,1,7,8,18,1,11,12,1,8,15,3,7,8,0,6,8,1,6,8,18,0,3,7,8,0,6,8,1,5,3,7,8,0,6,8,1,9,0,4,7,8,0,6,8,1,6,11,16,1,9,0,9,0,3,7,8,0,6,8,1,8,13,1,9,0,4,7,8,0,6,8,1,8,13,3,4,7,8,0,6,8,1,9,0,3,3,7,8,0,8,13,11,12,1,8,15,2,9,0,11,17,1,9,0,5,7,8,0,6,8,1,8,13,3,7,8,18,1,11,2,1,9,0,3,7,8,0,11,2,1,9,0,11,12,1,8,15,2,7,8,0,11,2,1,9,0,4,7,8,0,6,8,1,11,10,1,3,7,8,18,2,6,8,0,8,13,1,1,2,7,8,0,6,8,1,1,7,8,14,3,7,8,0,6,8,1,1,1,6,8,0,1,6,8,14,1,7,8,0,1,5,1,14,1,3,1,7,11,11,1,8,15,3,6,8,0,6,8,1,8,13,1,6,9,0,1,7,9,0,2,9,0,8,3,3,7,8,0,9,0,8,3,1,6,11,2,1,9,0,1,8,13,2,8,1,8,0,1,8,14,1,8,15,1,11,11,1,9,0,1,6,8,18,1,8,0,5,8,14,8,13,8,14,14,11,11,1,8,15,2,11,11,1,9,0,7,8,18,1,11,12,1,9,0,2,8,4,9,0,3,7,8,14,9,0,9,1,2,8,6,1,3,8,13,8,13,8,13,2,8,5,3,2,7,8,14,9,0,1,11,10,1,9,1,1,9,1,2,8,13,8,13,1,11,7,1,9,0,1,11,9,1,9,0,2,9,0,3,1,6,11,12,1,9,0,2,7,11,11,1,9,0,11,11,1,9,0,1,11,8,1,9,0,3,8,13,3,8,13,1,11,17,1,9,0,7,8,13,8,13,8,14,8,13,8,13,3,8,14,5,8,14,8,13,8,13,3,3,3,8,14,8,13,8,13,3,3,3,3,1,6,11,10,1,9,0,1,11,10,1,9,0,1,6,11,11,1,9,0,3,7,11,11,1,9,0,3,7,8,18,1,8,4,2,6,8,14,9,0,1,8,6,1,8,5,1,6,9,1,1,7,9,1,7,66,97,108,97,110,99,101,6,66,111,114,114,111,119,4,67,111,105,110,2,73,68,4,73,116,101,109,12,73,116,101,109,68,101,108,105,115,116,101,100,10,73,116,101,109,76,105,115,116,101,100,13,73,116,101,109,80,117,114,99,104,97,115,101,100,5,75,105,111,115,107,13,75,105,111,115,107,79,119,110,101,114,67,97,112,7,76,105,115,116,105,110,103,4,76,111,99,107,6,79,112,116,105,111,110,11,80,117,114,99,104,97,115,101,67,97,112,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,16,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,10,98,111,114,114,111,119,95,118,97,108,18,99,108,111,115,101,95,97,110,100,95,119,105,116,104,100,114,97,119,4,99,111,105,110,6,100,101,108,101,116,101,6,100,101,108,105,115,116,12,100,101,115,116,114,111,121,95,115,111,109,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,4,101,109,105,116,5,101,118,101,110,116,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,3,102,111,114,12,102,114,111,109,95,98,97,108,97,110,99,101,10,104,97,115,95,97,99,99,101,115,115,8,104,97,115,95,105,116,101,109,18,104,97,115,95,105,116,101,109,95,119,105,116,104,95,116,121,112,101,2,105,100,12,105,110,116,111,95,98,97,108,97,110,99,101,12,105,115,95,101,120,99,108,117,115,105,118,101,9,105,115,95,108,105,115,116,101,100,21,105,115,95,108,105,115,116,101,100,95,101,120,99,108,117,115,105,118,101,108,121,9,105,115,95,108,111,99,107,101,100,7,105,115,95,115,111,109,101,10,105,116,101,109,95,99,111,117,110,116,7,105,116,101,109,95,105,100,4,106,111,105,110,5,107,105,111,115,107,8,107,105,111,115,107,95,105,100,4,108,105,115,116,22,108,105,115,116,95,119,105,116,104,95,112,117,114,99,104,97,115,101,95,99,97,112,4,108,111,99,107,9,109,105,110,95,112,114,105,99,101,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,5,111,119,110,101,114,5,112,108,97,99,101,14,112,108,97,99,101,95,97,110,100,95,108,105,115,116,5,112,114,105,99,101,7,112,114,111,102,105,116,115,14,112,114,111,102,105,116,115,95,97,109,111,117,110,116,11,112,114,111,102,105,116,115,95,109,117,116,8,112,117,114,99,104,97,115,101,17,112,117,114,99,104,97,115,101,95,99,97,112,95,105,116,101,109,18,112,117,114,99,104,97,115,101,95,99,97,112,95,107,105,111,115,107,22,112,117,114,99,104,97,115,101,95,99,97,112,95,109,105,110,95,112,114,105,99,101,17,112,117,114,99,104,97,115,101,95,119,105,116,104,95,99,97,112,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,105,102,95,101,120,105,115,116,115,19,114,101,116,117,114,110,95,112,117,114,99,104,97,115,101,95,99,97,112,10,114,101,116,117,114,110,95,118,97,108,6,115,101,110,100,101,114,20,115,101,116,95,97,108,108,111,119,95,101,120,116,101,110,115,105,111,110,115,9,115,101,116,95,111,119,110,101,114,16,115,101,116,95,111,119,110,101,114,95,99,117,115,116,111,109,3,115,117,105,4,116,97,107,101,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,3,117,105,100,7,117,105,100,95,109,117,116,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,0,2,5,41,8,14,65,11,11,1,8,15,61,5,48,14,20,1,1,2,2,41,8,14,36,8,13,2,2,4,41,8,14,52,8,13,49,8,13,56,3,3,2,2,52,8,13,49,8,13,4,2,1,41,8,13,5,2,2,41,8,13,43,1,6,2,1,41,8,13,7,2,3,51,8,13,41,8,13,64,3,8,2,3,51,8,13,41,8,13,64,3,9,2,2,51,8,13,41,8,13,7,10,9,10,8,10,2,10,0,1,0,0,39,19,10,0,17,58,56,0,10,0,46,17,61,73,0,0,0,0,8,18,0,12,2,11,0,17,58,14,2,56,1,18,1,12,1,11,2,11,1,2,1,1,0,0,45,38,11,0,19,0,1,12,6,1,12,7,12,5,11,1,19,1,12,4,12,3,14,5,17,59,11,4,33,4,17,5,21,11,2,1,7,0,39,11,6,73,0,0,0,0,33,4,26,5,30,11,2,1,7,3,39,11,3,17,56,11,5,17,56,11,7,11,2,56,2,2,2,1,0,0,5,21,10,0,46,56,1,11,1,16,0,20,33,4,9,5,15,11,0,1,11,2,1,7,0,39,11,2,17,61,11,0,15,1,21,2,3,1,0,0,5,18,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,2,11,0,15,1,21,2,4,1,0,0,5,29,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,16,2,20,73,1,0,0,0,22,10,0,15,2,21,11,0,15,3,14,2,56,3,18,4,11,2,56,4,2,5,1,0,0,5,12,10,0,15,3,14,3,56,3,18,6,8,56,5,11,0,11,1,11,3,56,6,2,6,1,0,0,51,72,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,17,32,4,22,5,26,11,0,1,7,8,39,10,0,10,2,12,4,46,11,4,17,19,32,4,35,5,39,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,15,4,47,5,51,11,0,1,7,11,39,10,0,16,2,20,73,1,0,0,0,23,10,0,15,2,21,10,0,15,3,10,2,9,18,5,56,7,1,11,0,15,3,11,2,18,4,56,8,2,7,1,0,0,56,53,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,4,46,11,4,56,9,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,5,46,11,5,17,19,32,4,34,5,38,11,0,1,7,4,39,10,0,15,3,10,2,9,18,5,10,3,56,10,11,0,46,56,1,11,2,11,3,57,0,56,11,2,8,1,0,0,38,13,14,2,56,3,12,4,10,0,10,1,11,2,56,6,11,0,11,1,11,4,11,3,56,12,2,9,1,0,0,51,64,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,56,9,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,19,32,4,34,5,38,11,0,1,7,4,39,10,0,10,2,12,5,46,11,5,17,18,4,46,5,50,11,0,1,7,12,39,10,0,15,3,10,2,9,18,5,56,13,1,11,0,46,56,1,11,2,57,1,56,14,2,10,1,0,0,59,58,10,0,15,3,10,1,9,18,5,56,13,12,4,10,0,15,3,10,1,18,4,56,8,12,3,10,0,16,2,20,73,1,0,0,0,23,10,0,15,2,21,10,4,14,2,56,15,33,4,27,5,31,11,0,1,7,1,39,10,0,15,4,11,2,56,16,56,17,1,10,0,15,3,10,1,18,6,56,18,1,10,0,46,56,1,10,1,10,4,57,2,56,19,11,3,11,1,11,4,11,0,46,56,1,56,20,2,11,1,0,0,65,76,10,0,46,56,1,10,1,16,0,20,33,4,9,5,17,11,0,1,11,4,1,11,1,1,7,0,39,10,0,10,2,12,5,46,11,5,56,9,4,25,5,33,11,0,1,11,4,1,11,1,1,7,11,39,10,0,10,2,12,6,46,11,6,17,18,32,4,42,5,50,11,0,1,11,4,1,11,1,1,7,6,39,11,4,17,58,12,11,11,0,15,3,10,2,8,18,5,10,3,56,10,11,11,12,7,11,2,12,8,11,1,16,0,20,12,9,11,3,12,10,11,7,11,9,11,8,11,10,57,3,2,12,1,0,0,66,50,11,1,58,3,12,6,12,4,12,5,12,3,14,2,56,15,12,7,10,7,11,6,38,4,14,5,18,11,0,1,7,1,39,10,0,46,56,1,11,5,33,4,25,5,29,11,0,1,7,5,39,10,0,15,3,10,4,8,18,5,56,13,1,10,0,15,3,10,4,9,18,5,11,7,56,10,11,3,17,56,11,0,11,4,11,2,56,21,2,13,1,0,0,67,27,11,1,58,3,1,12,3,12,4,12,2,10,0,46,56,1,11,4,33,4,13,5,17,11,0,1,7,5,39,11,0,15,3,11,3,8,18,5,56,13,1,11,2,17,56,2,14,1,0,0,68,49,10,0,46,56,1,11,1,16,0,20,33,4,9,5,15,11,0,1,11,3,1,7,0,39,14,2,56,22,4,37,11,2,56,23,12,6,10,6,10,0,16,4,56,24,37,4,28,5,34,11,0,1,11,3,1,7,2,39,11,6,12,4,5,41,10,0,16,4,56,24,12,4,11,4,12,5,11,0,15,4,11,5,11,3,56,25,2,15,1,0,0,5,6,11,0,16,3,11,1,18,4,56,26,2,16,1,0,0,5,6,11,0,16,3,11,1,18,4,56,27,2,17,1,0,0,5,6,11,0,16,3,11,1,18,6,56,28,2,18,1,0,0,21,18,10,0,16,3,10,1,9,18,5,56,29,4,12,11,0,1,8,12,2,5,16,11,0,11,1,17,19,12,2,11,2,2,19,1,0,0,5,7,11,0,16,3,11,1,8,18,5,56,29,2,20,1,0,0,5,8,11,0,46,56,1,11,1,16,0,20,33,2,21,1,0,0,5,16,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,0,15,3,2,22,1,0,0,5,18,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,2,11,0,15,5,21,2,23,1,0,0,5,12,10,0,16,5,20,4,5,5,9,11,0,1,7,7,39,11,0,16,3,2,24,1,0,0,5,12,10,0,16,5,20,4,5,5,9,11,0,1,7,7,39,11,0,15,3,2,25,1,0,0,5,4,11,0,16,1,20,2,26,1,0,0,5,4,11,0,16,2,20,2,27,1,0,0,5,4,11,0,16,4,56,24,2,28,1,0,0,5,16,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,11,0,15,4,2,29,1,0,0,5,27,10,0,56,1,11,1,16,0,20,33,4,8,5,12,11,0,1,7,0,39,10,0,10,2,17,15,4,17,5,21,11,0,1,7,11,39,11,0,16,3,11,2,18,4,56,30,2,30,1,0,0,56,44,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,15,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,18,32,4,34,5,38,11,0,1,7,9,39,11,0,15,3,11,2,18,4,56,31,2,31,1,0,0,56,49,10,0,46,56,1,11,1,16,0,20,33,4,9,5,13,11,0,1,7,0,39,10,0,10,2,12,3,46,11,3,17,15,4,21,5,25,11,0,1,7,11,39,10,0,10,2,12,4,46,11,4,17,18,32,4,34,5,38,11,0,1,7,9,39,10,0,15,3,10,2,18,4,56,8,11,0,46,56,1,11,2,18,3,2,32,1,0,0,56,32,11,2,19,3,12,3,12,4,10,0,46,56,1,11,4,33,4,11,5,15,11,0,1,7,5,39,14,1,56,3,10,3,33,4,21,5,25,11,0,1,7,10,39,11,0,15,3,11,3,18,4,11,1,56,4,2,33,1,0,0,5,4,11,0,55,0,20,2,34,1,0,0,5,4,11,0,55,1,20,2,35,1,0,0,5,4,11,0,55,2,20,2,1,1,0,2,0,3,0,0,0,1,0,4,2,1,2,2,2,3,6,10,7,10,8,10,0],"linked_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,30,3,40,212,1,4,252,1,28,5,152,2,188,1,7,212,3,205,2,8,161,6,64,6,225,6,20,10,245,6,38,11,155,7,4,12,159,7,151,5,13,182,12,14,14,196,12,14,0,24,1,29,0,14,0,28,0,40,0,0,12,2,7,0,4,1,0,1,4,2,7,0,4,0,1,2,7,1,0,0,3,4,4,0,4,3,2,0,0,25,0,1,2,7,4,0,17,2,3,2,7,4,0,6,2,3,2,7,4,0,34,4,5,2,7,4,0,33,4,5,2,7,4,0,7,6,7,2,7,4,0,8,8,9,2,7,4,0,32,6,3,2,7,4,0,26,6,3,2,7,4,0,35,8,10,2,7,4,0,31,11,12,2,7,4,0,30,11,12,2,7,4,0,9,6,13,2,7,4,0,23,2,14,2,7,4,0,20,2,13,2,7,4,0,11,1,5,2,7,4,0,13,1,5,2,7,6,1,7,3,25,1,0,1,12,17,16,1,0,1,16,19,5,1,0,1,21,3,13,1,0,1,22,3,13,1,0,1,27,5,17,1,0,1,37,16,17,1,0,1,38,19,17,1,0,2,5,22,5,2,7,4,2,7,23,7,2,7,4,2,8,21,9,2,7,4,2,15,23,13,2,7,4,2,35,21,10,2,7,4,3,10,15,5,0,3,25,0,15,0,22,16,24,16,20,16,19,16,21,16,18,16,23,16,27,20,25,20,26,20,29,20,17,16,9,12,28,20,1,7,8,4,1,11,0,2,9,0,9,1,1,6,11,0,2,9,0,9,1,1,6,11,2,1,9,0,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,7,11,0,2,9,0,9,1,2,9,0,9,1,1,1,1,3,1,8,3,1,9,0,1,11,2,1,9,0,5,11,2,1,9,0,11,2,1,9,0,11,2,1,9,0,9,0,11,2,1,9,0,2,7,11,2,1,9,0,9,0,2,9,0,11,1,2,9,0,9,1,2,7,8,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,3,11,2,1,9,0,11,2,1,9,0,9,1,1,6,9,0,2,8,3,3,11,76,105,110,107,101,100,84,97,98,108,101,4,78,111,100,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,4,98,97,99,107,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,4,102,105,108,108,5,102,114,111,110,116,4,104,101,97,100,2,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,6,108,101,110,103,116,104,12,108,105,110,107,101,100,95,116,97,98,108,101,3,110,101,119,4,110,101,120,116,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,8,112,111,112,95,98,97,99,107,9,112,111,112,95,102,114,111,110,116,4,112,114,101,118,9,112,117,115,104,95,98,97,99,107,10,112,117,115,104,95,102,114,111,110,116,6,114,101,109,111,118,101,4,115,105,122,101,4,115,111,109,101,12,115,119,97,112,95,111,114,95,102,105,108,108,4,116,97,105,108,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,19,8,3,36,3,18,11,2,1,9,0,39,11,2,1,9,0,1,2,3,32,11,2,1,9,0,26,11,2,1,9,0,41,9,1,0,12,1,12,0,1,0,0,5,7,11,0,17,31,6,0,0,0,0,0,0,0,0,56,0,56,0,57,0,2,1,1,0,0,5,3,11,0,55,0,2,2,1,0,0,5,3,11,0,55,1,2,3,1,0,0,18,54,10,0,54,0,10,1,56,1,12,5,10,0,55,1,56,2,4,13,10,0,54,1,10,1,56,3,56,0,12,7,14,5,56,4,4,33,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,3,21,11,6,56,6,12,3,5,35,56,0,12,3,11,3,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,4,1,0,0,18,54,10,0,55,0,56,2,4,8,10,0,54,0,10,1,56,3,10,0,54,1,10,1,56,1,12,5,14,5,56,4,4,31,11,5,56,5,12,6,10,1,56,6,10,0,54,2,10,6,56,7,54,5,21,11,6,56,6,12,3,5,33,56,0,12,3,11,3,12,7,56,0,12,4,10,0,54,2,11,1,11,7,11,4,11,2,57,1,56,8,10,0,55,4,20,6,1,0,0,0,0,0,0,0,22,11,0,54,4,21,2,5,1,0,0,5,6,11,0,55,2,11,1,56,9,55,6,2,6,1,0,0,5,6,11,0,54,2,11,1,56,7,54,6,2,7,1,0,0,5,6,11,0,55,2,11,1,56,9,55,3,2,8,1,0,0,5,6,11,0,55,2,11,1,56,9,55,5,2,9,1,0,0,24,65,10,0,54,2,10,1,56,10,58,1,12,4,12,2,12,3,10,0,55,4,20,6,1,0,0,0,0,0,0,0,23,10,0,54,4,21,14,3,56,4,4,28,10,2,10,0,54,2,14,3,56,11,20,56,7,54,5,21,14,2,56,4,4,40,10,3,10,0,54,2,14,2,56,11,20,56,7,54,3,21,10,0,55,0,56,11,14,1,33,4,50,11,2,10,0,54,0,21,10,0,55,1,56,11,14,1,33,4,61,11,3,11,0,54,1,21,5,63,11,0,1,11,4,2,10,1,0,0,16,19,10,0,55,0,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,0,56,11,20,12,1,10,1,11,0,11,1,56,12,2,11,1,0,0,16,19,10,0,55,1,56,4,4,5,5,9,11,0,1,7,1,39,10,0,55,1,56,11,20,12,1,10,1,11,0,11,1,56,12,2,12,1,0,0,5,5,11,0,55,2,11,1,56,13,2,13,1,0,0,5,4,11,0,55,4,20,2,14,1,0,0,5,6,11,0,55,4,20,6,0,0,0,0,0,0,0,0,33,2,15,1,0,0,26,16,11,0,58,0,1,1,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,11,5,13,7,0,39,11,1,17,30,2,16,1,0,0,5,7,11,0,58,0,1,1,1,17,30,2,0,2,0,3,0,0,1,0,0,1,1,1,1,2,0,12,1,12,2,12,3,12,4,12,5,12,6,12,0],"math":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,35,5,37,18,7,55,57,8,112,32,12,144,1,249,3,0,2,0,3,0,1,0,0,4,0,1,0,0,0,0,1,0,0,5,2,1,0,0,6,1,1,0,0,7,3,3,0,0,1,0,1,0,2,3,3,1,3,2,3,2,1,4,3,4,4,4,3,15,15,15,4,100,105,102,102,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,4,109,97,116,104,3,109,97,120,3,109,105,110,3,112,111,119,4,115,113,114,116,9,115,113,114,116,95,117,49,50,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,1,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,2,1,0,0,1,15,10,0,10,1,36,4,9,11,0,11,1,23,12,2,5,13,11,1,11,0,23,12,2,11,2,2,3,1,0,0,1,33,6,1,0,0,0,0,0,0,0,12,2,10,1,49,1,38,4,31,5,7,10,1,49,2,25,49,0,33,4,22,10,0,11,0,24,12,0,11,1,49,2,26,12,1,5,30,11,2,10,0,24,12,2,11,1,49,1,23,12,1,5,2,11,2,2,4,1,0,0,4,43,50,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,12,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,53,12,3,10,1,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,52,2,5,1,0,0,5,43,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,11,0,77,12,3,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,40,5,12,10,3,10,2,10,1,22,38,4,31,11,3,10,2,10,1,22,23,12,3,11,2,49,1,48,10,1,22,12,2,5,35,11,2,49,1,48,12,2,11,1,49,2,48,12,1,5,7,11,2,53,2,6,1,0,0,1,19,10,0,10,1,25,6,0,0,0,0,0,0,0,0,33,4,11,11,0,11,1,26,12,2,5,17,11,0,11,1,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,2,0],"object":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,126,4,146,1,6,5,152,1,35,7,187,1,250,2,8,181,4,64,6,245,4,112,10,229,5,11,12,240,5,130,2,13,242,7,4,15,246,7,8,0,24,1,4,0,3,0,30,0,0,7,0,0,2,4,0,3,1,2,0,0,21,0,1,0,0,20,0,2,0,0,19,1,3,0,0,18,2,3,0,0,27,4,5,0,0,8,6,5,0,0,31,7,0,0,0,34,7,3,0,0,33,7,1,0,0,32,7,2,0,0,22,8,5,0,0,9,5,6,0,0,15,9,3,1,8,0,5,9,0,1,8,0,17,9,1,1,8,0,16,9,2,1,8,0,6,9,7,1,8,0,23,2,5,0,0,10,2,6,0,0,25,2,6,0,1,28,9,1,1,0,2,14,1,2,0,3,13,8,2,0,3,26,4,2,0,20,2,16,10,20,3,1,6,8,0,1,10,2,1,5,1,8,0,1,6,8,2,1,8,1,0,1,6,8,1,1,7,8,2,1,6,9,0,1,9,0,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,100,100,114,101,115,115,3,98,99,115,9,98,111,114,114,111,119,95,105,100,10,98,111,114,114,111,119,95,117,105,100,5,98,121,116,101,115,5,99,108,111,99,107,6,100,101,108,101,116,101,11,100,101,108,101,116,101,95,105,109,112,108,13,100,121,110,97,109,105,99,95,102,105,101,108,100,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,2,105,100,10,105,100,95,97,100,100,114,101,115,115,8,105,100,95,98,121,116,101,115,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,102,114,111,109,95,98,121,116,101,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,11,105,100,95,116,111,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,117,105,100,95,102,114,111,109,95,104,97,115,104,6,111,98,106,101,99,116,14,114,101,99,111,114,100,95,110,101,119,95,117,105,100,6,115,101,110,100,101,114,16,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,105,100,95,116,111,95,97,100,100,114,101,115,115,12,117,105,100,95,116,111,95,98,121,116,101,115,12,117,105,100,95,116,111,95,105,110,110,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,3,8,0,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,7,5,1,2,1,15,8,0,0,1,0,0,6,4,11,0,16,0,56,0,2,1,1,0,0,6,4,11,0,16,0,20,2,2,1,0,0,6,4,11,0,17,21,17,3,2,3,1,0,0,6,3,11,0,18,0,2,4,0,0,0,6,12,11,0,17,23,7,3,33,4,6,5,8,7,2,39,7,0,18,0,18,1,2,5,3,0,0,6,4,7,1,18,0,18,1,2,6,1,0,0,6,3,11,0,16,1,2,7,1,0,0,6,4,11,0,16,1,20,2,8,1,0,0,6,5,11,0,16,1,16,0,56,0,2,9,1,0,0,6,5,11,0,16,1,16,0,20,2,10,1,0,0,6,5,11,0,17,22,18,0,18,1,2,11,1,0,0,6,5,11,0,19,1,19,0,17,18,2,12,1,0,0,6,5,11,0,56,1,16,1,20,2,13,1,0,0,6,4,11,0,56,1,16,1,2,14,1,0,0,6,5,11,0,56,1,16,1,56,2,2,15,1,0,0,6,6,11,0,56,1,16,1,16,0,20,2,16,0,2,0,17,3,0,0,6,6,10,0,17,19,11,0,18,0,18,1,2,18,0,2,0,19,0,2,0,0,0,1,0,0,8,0,11,0,12,0,29,0],"object_bag":[161,28,235,11,6,0,0,0,11,1,0,10,2,10,22,3,32,124,4,156,1,14,5,170,1,88,7,130,2,231,1,8,233,3,64,6,169,4,10,10,179,4,8,12,187,4,245,1,13,176,6,4,0,20,1,21,0,12,0,19,0,24,0,1,12,0,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,18,0,1,0,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,22,6,8,2,7,12,0,8,4,9,1,7,0,9,4,9,2,7,12,0,17,10,11,0,0,16,10,9,0,0,11,1,3,0,0,25,4,12,1,7,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,13,16,9,1,7,2,14,16,9,2,7,12,2,15,16,12,1,7,2,22,17,8,2,7,12,3,10,13,3,0,3,18,0,13,0,11,14,12,14,13,14,17,14,14,18,15,14,16,18,1,7,8,4,1,8,0,3,7,8,0,9,0,9,1,0,2,6,8,0,9,0,1,6,9,1,2,7,8,0,9,0,1,7,9,1,1,9,1,1,1,1,6,8,0,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,9,79,98,106,101,99,116,66,97,103,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,18,99,111,110,116,97,105,110,115,95,119,105,116,104,95,116,121,112,101,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,10,111,98,106,101,99,116,95,98,97,103,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,15,8,3,23,3,0,1,0,0,3,5,11,0,17,19,6,0,0,0,0,0,0,0,0,18,0,2,1,1,0,0,3,14,10,0,15,0,11,1,11,2,56,0,10,0,16,1,20,6,1,0,0,0,0,0,0,0,22,11,0,15,1,21,2,2,1,0,0,3,5,11,0,16,0,11,1,56,1,2,3,1,0,0,3,5,11,0,15,0,11,1,56,2,2,4,1,0,0,8,15,10,0,15,0,11,1,56,3,12,2,10,0,16,1,20,6,1,0,0,0,0,0,0,0,23,11,0,15,1,21,11,2,2,5,1,0,0,3,5,11,0,16,0,11,1,56,4,2,6,1,0,0,3,5,11,0,16,0,11,1,56,5,2,7,1,0,0,3,4,11,0,16,1,20,2,8,1,0,0,3,6,11,0,16,1,20,6,0,0,0,0,0,0,0,0,33,2,9,1,0,0,19,14,11,0,19,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,18,2,10,1,0,0,3,5,11,0,16,0,11,1,56,6,2,0,0,0,1,0],"object_table":[161,28,235,11,6,0,0,0,13,1,0,10,2,10,26,3,36,120,4,156,1,12,5,168,1,113,7,153,2,199,1,8,224,3,64,6,160,4,10,10,170,4,8,11,178,4,2,12,180,4,230,1,13,154,6,4,14,158,6,4,0,18,1,19,0,11,0,17,0,22,0,1,12,2,7,1,12,1,1,2,7,1,0,0,3,0,7,0,3,4,4,0,4,3,2,0,0,16,0,1,2,7,12,0,5,2,3,2,7,12,0,6,4,5,2,7,12,0,7,6,7,2,7,12,0,20,6,8,2,7,12,0,8,4,9,2,7,12,0,15,10,11,2,7,12,0,14,10,9,2,7,12,0,10,1,3,2,7,12,0,23,4,12,2,7,12,2,5,15,3,2,7,12,2,6,16,5,2,7,12,2,7,17,7,2,7,12,2,12,16,9,1,7,2,13,16,12,1,7,2,20,17,8,2,7,12,3,9,13,3,0,3,16,0,13,0,10,14,11,14,12,14,15,14,13,18,14,18,1,7,8,4,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,11,1,1,8,2,1,8,3,2,9,0,9,1,3,7,8,3,9,0,9,1,2,6,8,3,9,0,2,7,8,3,9,0,1,9,0,2,8,3,3,2,73,68,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,20,100,121,110,97,109,105,99,95,111,98,106,101,99,116,95,102,105,101,108,100,7,101,120,105,115,116,115,95,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,4,115,105,122,101,10,116,120,95,99,111,110,116,101,120,116,8,118,97,108,117,101,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,0,2,2,13,8,3,21,3,0,14,0,1,0,0,3,5,11,0,17,17,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,19,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,16,2,9,1,0,0,3,5,11,0,55,0,11,1,56,5,2,0,0,0,1,0,14,1,14,0],"package":[161,28,235,11,6,0,0,0,11,1,0,14,2,14,36,3,50,183,1,4,233,1,10,5,243,1,118,7,233,2,144,5,8,249,7,64,6,185,8,93,10,150,9,48,12,198,9,129,4,13,199,13,20,0,36,1,10,1,50,0,33,0,48,0,49,0,51,0,1,12,0,0,6,12,0,0,8,0,0,0,7,0,0,1,2,7,0,2,4,7,0,3,0,7,0,3,5,4,0,5,3,2,0,0,14,0,1,1,2,0,15,0,2,1,2,0,12,1,2,0,0,22,3,4,1,0,0,21,3,4,1,0,0,39,3,5,0,0,40,3,5,0,0,52,6,7,0,0,54,6,8,0,0,53,6,9,0,0,46,10,7,0,0,47,10,9,0,0,41,11,7,0,0,42,11,7,0,0,45,10,12,0,0,17,2,9,0,0,9,2,9,0,0,19,2,9,0,0,34,13,2,0,0,35,13,2,0,0,30,14,2,0,0,11,15,16,0,0,16,17,2,0,0,43,18,2,0,2,23,24,25,0,2,24,24,25,0,2,25,2,19,1,0,3,18,23,2,0,3,26,21,7,1,8,3,27,27,7,0,3,28,31,27,0,3,32,22,23,0,4,38,28,2,1,12,5,44,26,27,0,6,29,21,4,1,2,34,20,26,20,0,20,32,1,28,14,2,9,0,7,8,8,1,8,0,0,1,6,8,0,1,1,1,6,8,4,1,6,8,1,1,8,6,1,3,1,2,1,6,8,2,1,6,8,3,1,6,10,2,1,7,8,1,1,8,1,3,7,8,1,2,10,2,1,8,2,2,7,8,1,8,3,2,7,8,1,2,1,8,5,1,9,0,1,6,9,0,1,7,8,8,1,8,7,1,6,8,5,1,8,4,1,6,8,8,1,5,2,9,0,5,2,1,8,5,2,8,6,8,6,1,6,8,6,2,73,68,9,80,117,98,108,105,115,104,101,114,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,15,97,100,100,105,116,105,118,101,95,112,111,108,105,99,121,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,14,98,117,114,110,95,112,117,98,108,105,115,104,101,114,3,99,97,112,5,99,108,97,105,109,14,99,108,97,105,109,95,97,110,100,95,107,101,101,112,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,17,99,111,109,112,97,116,105,98,108,101,95,112,111,108,105,99,121,6,100,101,108,101,116,101,15,100,101,112,95,111,110,108,121,95,112,111,108,105,99,121,6,100,105,103,101,115,116,11,102,114,111,109,95,109,111,100,117,108,101,12,102,114,111,109,95,112,97,99,107,97,103,101,11,103,101,116,95,97,100,100,114,101,115,115,10,103,101,116,95,109,111,100,117,108,101,21,103,101,116,95,119,105,116,104,95,111,114,105,103,105,110,97,108,95,105,100,115,2,105,100,15,105,100,95,102,114,111,109,95,97,100,100,114,101,115,115,13,105,100,95,116,111,95,97,100,100,114,101,115,115,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,14,109,97,107,101,95,105,109,109,117,116,97,98,108,101,11,109,111,100,117,108,101,95,110,97,109,101,3,110,101,119,6,111,98,106,101,99,116,22,111,110,108,121,95,97,100,100,105,116,105,118,101,95,117,112,103,114,97,100,101,115,17,111,110,108,121,95,100,101,112,95,117,112,103,114,97,100,101,115,7,112,97,99,107,97,103,101,6,112,111,108,105,99,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,16,112,117,98,108,105,115,104,101,100,95,109,111,100,117,108,101,17,112,117,98,108,105,115,104,101,100,95,112,97,99,107,97,103,101,11,114,101,99,101,105,112,116,95,99,97,112,15,114,101,99,101,105,112,116,95,112,97,99,107,97,103,101,8,114,101,115,116,114,105,99,116,6,115,101,110,100,101,114,13,116,105,99,107,101,116,95,100,105,103,101,115,116,14,116,105,99,107,101,116,95,112,97,99,107,97,103,101,13,116,105,99,107,101,116,95,112,111,108,105,99,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,5,116,121,112,101,115,15,117,112,103,114,97,100,101,95,112,97,99,107,97,103,101,14,117,112,103,114,97,100,101,95,112,111,108,105,99,121,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,2,1,0,2,1,128,2,1,192,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,26,8,7,36,8,4,31,8,4,1,2,4,26,8,7,36,8,6,54,3,37,2,2,2,4,13,8,6,36,8,6,37,2,20,10,2,3,2,2,13,8,6,36,8,6,0,1,0,0,19,18,14,0,56,0,4,4,5,8,11,1,1,7,0,39,56,1,12,2,11,1,17,31,14,2,17,24,14,2,17,25,18,0,2,1,1,0,0,2,8,11,0,10,1,56,2,11,1,46,17,33,56,3,2,2,1,0,0,2,6,11,0,19,0,1,1,17,27,2,3,1,0,0,19,9,56,1,12,1,14,1,17,24,11,0,16,0,20,33,2,4,1,0,0,29,23,56,1,12,2,14,2,17,24,10,0,16,0,20,33,4,17,14,2,17,25,11,0,16,1,20,33,12,1,5,21,11,0,1,9,12,1,11,1,2,5,1,0,0,2,3,11,0,16,1,2,6,1,0,0,2,3,11,0,16,0,2,7,1,0,0,2,4,11,0,16,2,20,2,8,1,0,0,2,4,11,0,16,3,20,2,9,1,0,0,2,4,11,0,16,4,20,2,10,1,0,0,2,4,11,0,16,5,20,2,11,1,0,0,2,4,11,0,16,6,20,2,12,1,0,0,2,4,11,0,16,7,20,2,13,1,0,0,2,4,11,0,16,8,20,2,14,1,0,0,2,3,11,0,16,9,2,15,1,0,0,2,2,7,5,2,16,1,0,0,2,2,7,6,2,17,1,0,0,2,2,7,7,2,18,1,4,0,2,4,11,0,7,6,17,23,2,19,1,4,0,2,4,11,0,7,7,17,23,2,20,1,4,0,2,7,11,0,19,1,1,1,1,17,27,2,21,1,0,0,30,41,7,8,17,29,12,3,10,0,16,2,20,10,3,34,4,10,5,14,11,0,1,7,2,39,10,1,10,0,16,4,20,38,4,21,5,25,11,0,1,7,1,39,10,0,16,2,20,12,4,11,3,10,0,15,2,21,11,0,46,56,4,11,4,11,1,11,2,18,2,2,22,1,0,0,30,39,11,1,19,3,12,3,12,2,10,0,46,56,4,11,2,33,4,11,5,15,11,0,1,7,4,39,10,0,16,2,17,30,7,8,33,4,22,5,26,11,0,1,7,3,39,11,3,10,0,15,2,21,10,0,16,3,20,6,1,0,0,0,0,0,0,0,22,11,0,15,3,21,2,23,0,0,0,2,16,10,0,16,4,20,10,1,37,4,7,5,11,11,0,1,7,1,39,11,1,11,0,15,4,21,2,0,1,0,2,1,1,1,2,1,3,2,1,2,2,3,0,3,1,2,3,0],"pay":[161,28,235,11,6,0,0,0,9,1,0,8,2,8,10,3,18,77,4,95,14,5,109,126,7,235,1,173,1,8,152,3,32,6,184,3,10,12,194,3,214,2,0,9,0,2,0,15,0,16,1,0,12,1,0,1,3,1,2,0,0,8,0,1,1,0,0,12,2,1,1,0,0,14,3,1,1,0,0,13,4,1,1,0,0,3,2,1,1,0,0,5,5,1,1,0,0,6,6,1,1,0,0,7,7,1,1,0,1,4,2,16,1,0,1,5,5,1,1,0,1,12,2,10,1,0,2,10,11,1,1,12,3,11,8,9,0,11,10,10,12,0,12,1,12,8,12,9,12,6,12,2,11,0,1,9,0,6,8,1,0,3,7,11,0,1,9,0,3,7,8,1,3,7,11,0,1,9,0,10,3,7,8,1,4,7,11,0,1,9,0,3,5,7,8,1,2,7,11,0,1,9,0,11,0,1,9,0,2,7,11,0,1,9,0,10,11,0,1,9,0,2,10,11,0,1,9,0,5,1,6,8,1,1,5,1,11,0,1,9,0,2,9,0,5,1,9,0,2,3,3,1,3,3,3,3,10,11,0,1,9,0,1,10,11,0,1,9,0,3,11,0,1,9,0,3,3,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,15,100,105,118,105,100,101,95,97,110,100,95,107,101,101,112,13,100,105,118,105,100,101,95,105,110,116,111,95,110,4,106,111,105,110,8,106,111,105,110,95,118,101,99,21,106,111,105,110,95,118,101,99,95,97,110,100,95,116,114,97,110,115,102,101,114,4,107,101,101,112,3,112,97,121,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,5,115,112,108,105,116,18,115,112,108,105,116,95,97,110,100,95,116,114,97,110,115,102,101,114,9,115,112,108,105,116,95,118,101,99,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,5,11,0,11,1,17,12,56,0,2,1,1,4,0,1,8,11,0,11,1,10,2,56,1,11,2,46,56,2,2,2,1,4,0,13,27,6,0,0,0,0,0,0,0,0,14,1,65,14,12,4,12,3,10,3,10,4,35,4,22,5,10,10,0,14,1,10,3,66,14,20,10,2,56,3,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,2,1,2,3,1,4,0,1,7,11,0,11,1,11,3,56,1,11,2,56,0,2,4,1,4,0,15,31,11,0,11,1,10,2,56,4,12,5,6,0,0,0,0,0,0,0,0,14,5,65,10,12,4,12,3,10,3,10,4,35,4,26,5,15,13,5,69,10,10,2,46,17,12,56,0,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,10,11,2,1,11,5,70,10,0,0,0,0,0,0,0,0,2,5,1,4,0,1,4,11,0,11,1,56,5,2,6,1,4,0,17,26,6,0,0,0,0,0,0,0,0,14,1,65,10,12,4,12,3,10,3,10,4,35,4,21,5,10,13,1,69,10,12,2,10,0,11,2,56,5,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,5,11,0,1,11,1,70,10,0,0,0,0,0,0,0,0,2,7,1,4,0,10,18,14,0,65,10,6,0,0,0,0,0,0,0,0,36,4,6,5,8,7,0,39,13,0,69,10,12,2,13,2,11,0,56,6,11,2,11,1,56,0,2,0],"priority_queue":[161,28,235,11,6,0,0,0,13,1,0,4,2,4,12,3,16,60,4,76,10,5,86,167,1,7,253,1,184,1,8,181,3,64,6,245,3,14,10,131,4,18,11,149,4,4,12,153,4,243,5,13,140,10,4,14,144,10,4,0,11,1,16,0,1,6,1,2,0,0,0,6,1,2,0,0,6,0,1,1,2,0,8,2,3,1,2,0,4,4,5,1,2,0,7,3,6,1,2,0,2,7,0,1,2,0,13,8,5,1,2,0,5,9,5,1,2,0,9,10,11,1,2,1,12,15,13,1,0,1,14,15,13,1,0,6,13,9,6,5,13,8,16,8,13,1,10,11,1,1,9,0,1,11,0,1,9,0,1,7,11,0,1,9,0,2,3,9,0,3,7,11,0,1,9,0,3,9,0,0,1,11,1,1,9,0,2,10,3,10,9,0,2,7,10,11,1,1,9,0,3,3,7,10,11,1,1,9,0,3,3,1,6,11,0,1,9,0,1,10,3,2,3,3,1,9,0,3,3,3,9,0,2,7,10,9,0,3,1,3,5,3,3,3,10,11,1,1,9,0,9,0,5,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,13,7,10,11,1,1,9,0,1,3,7,10,11,1,1,9,0,3,1,7,10,11,1,1,9,0,3,7,10,11,1,1,9,0,3,3,3,3,2,3,10,3,5,69,110,116,114,121,13,80,114,105,111,114,105,116,121,81,117,101,117,101,14,99,114,101,97,116,101,95,101,110,116,114,105,101,115,7,101,110,116,114,105,101,115,6,105,110,115,101,114,116,21,109,97,120,95,104,101,97,112,105,102,121,95,114,101,99,117,114,115,105,118,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,7,112,111,112,95,109,97,120,10,112,114,105,111,114,105,116,105,101,115,8,112,114,105,111,114,105,116,121,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,6,114,101,109,111,118,101,22,114,101,115,116,111,114,101,95,104,101,97,112,95,114,101,99,117,114,115,105,118,101,11,115,119,97,112,95,114,101,109,111,118,101,5,118,97,108,117,101,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,10,3,1,0,0,2,1,3,10,11,1,1,9,0,1,2,2,10,3,15,9,0,0,13,1,13,0,1,0,0,12,24,14,0,65,6,12,2,10,2,6,2,0,0,0,0,0,0,0,26,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,21,5,12,11,1,6,1,0,0,0,0,0,0,0,23,12,1,13,0,10,2,10,1,56,0,5,7,11,0,57,0,2,1,1,0,0,14,30,10,0,55,0,65,6,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,10,0,54,0,6,0,0,0,0,0,0,0,0,56,1,58,1,12,3,12,2,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,6,0,0,0,0,0,0,0,0,56,0,11,2,11,3,2,2,1,0,0,16,17,10,0,54,0,11,1,11,2,57,1,68,6,10,0,55,0,65,6,6,1,0,0,0,0,0,0,0,23,12,3,11,0,54,0,11,3,56,2,2,3,1,0,0,5,4,11,0,11,1,57,1,2,4,1,0,0,17,40,14,0,65,16,12,3,14,1,65,13,10,3,33,4,9,5,11,6,0,0,0,0,0,0,0,0,39,64,6,0,0,0,0,0,0,0,0,12,5,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,38,5,20,13,0,6,0,0,0,0,0,0,0,0,56,3,12,4,13,1,6,0,0,0,0,0,0,0,0,56,4,12,6,13,5,11,4,11,6,57,1,68,6,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,15,11,5,2,5,0,0,0,18,46,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,1,6,1,0,0,0,0,0,0,0,23,6,2,0,0,0,0,0,0,0,26,12,6,10,0,10,1,12,3,12,2,10,0,10,6,12,5,12,4,11,2,46,11,3,66,6,55,1,20,11,4,46,11,5,66,6,55,1,20,36,4,43,10,0,11,1,10,6,71,6,11,0,11,6,56,2,5,45,11,0,1,2,6,0,0,0,19,110,10,1,6,0,0,0,0,0,0,0,0,33,4,7,11,0,1,2,10,2,10,1,35,4,12,5,16,11,0,1,6,1,0,0,0,0,0,0,0,39,10,2,6,2,0,0,0,0,0,0,0,24,6,1,0,0,0,0,0,0,0,22,12,13,10,13,6,1,0,0,0,0,0,0,0,22,12,15,10,2,12,14,10,13,10,1,35,4,55,10,0,10,13,12,5,12,3,10,0,10,14,12,7,12,6,11,3,46,11,5,66,6,55,1,20,11,6,46,11,7,66,6,55,1,20,36,12,8,5,57,9,12,8,11,8,4,61,11,13,12,14,10,15,10,1,35,4,88,10,0,10,15,12,10,12,9,10,0,10,14,12,12,12,11,11,9,46,11,10,66,6,55,1,20,11,11,46,11,12,66,6,55,1,20,36,12,4,5,90,9,12,4,11,4,4,94,11,15,12,14,10,14,10,2,34,4,107,10,0,10,14,11,2,71,6,11,0,11,1,11,14,56,0,5,109,11,0,1,2,7,1,0,0,20,28,7,1,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,0,55,0,65,6,35,4,24,5,11,13,2,10,0,55,0,10,1,66,6,55,1,20,68,16,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,4,11,0,1,11,2,2,0,0,1,0,0,13,1,13,0],"prover":[161,28,235,11,6,0,0,0,4,1,0,2,7,2,7,8,9,32,6,41,30,0,0,6,112,114,111,118,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0],"sui":[161,28,235,11,6,0,0,0,10,1,0,14,2,14,48,3,62,62,4,124,14,5,138,1,133,1,7,143,2,129,2,8,144,4,64,6,208,4,102,10,182,5,5,12,187,5,109,0,22,1,18,0,9,0,10,0,23,0,25,0,26,0,4,2,0,1,3,7,1,0,0,2,0,4,1,0,1,2,5,4,1,0,1,3,1,12,1,0,1,3,2,12,1,0,1,3,6,12,1,0,1,5,7,2,0,6,8,7,0,0,16,0,1,0,0,23,2,3,0,1,17,3,9,1,0,2,12,16,7,1,0,2,15,17,18,1,0,3,11,11,12,1,2,3,24,15,16,1,0,4,19,14,3,1,12,4,20,20,3,1,12,5,14,5,7,0,5,21,5,6,0,2,8,5,10,7,13,6,10,4,10,3,10,8,19,1,7,8,7,1,11,2,1,8,0,2,11,4,1,8,0,5,0,4,11,5,1,8,0,11,3,1,8,0,11,2,1,8,0,11,6,1,8,0,1,6,8,7,1,5,1,3,1,8,8,1,11,1,1,9,0,1,8,0,7,9,0,2,10,2,10,2,10,2,11,1,1,8,8,7,8,7,2,11,6,1,9,0,11,5,1,9,0,1,11,5,1,8,0,1,9,0,1,11,6,1,9,0,1,11,3,1,9,0,2,7,11,3,1,9,0,3,1,11,2,1,9,0,1,11,4,1,8,0,2,9,0,5,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,6,83,117,112,112,108,121,11,84,114,101,97,115,117,114,121,67,97,112,9,84,120,67,111,110,116,101,120,116,3,85,114,108,7,98,97,108,97,110,99,101,4,99,111,105,110,15,99,114,101,97,116,101,95,99,117,114,114,101,110,99,121,14,100,101,115,116,114,111,121,95,115,117,112,112,108,121,11,100,117,109,109,121,95,102,105,101,108,100,5,101,112,111,99,104,15,105,110,99,114,101,97,115,101,95,115,117,112,112,108,121,3,110,101,119,4,110,111,110,101,6,111,112,116,105,111,110,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,3,115,117,105,8,116,114,97,110,115,102,101,114,20,116,114,101,97,115,117,114,121,95,105,110,116,111,95,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,228,11,84,2,0,0,0,3,8,0,0,232,137,4,35,199,138,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,2,4,3,83,85,73,10,2,4,3,83,117,105,10,2,1,0,0,2,1,13,1,0,0,0,0,4,47,10,0,46,17,10,7,5,33,4,7,5,11,11,0,1,7,1,39,10,0,46,17,9,6,0,0,0,0,0,0,0,0,33,4,18,5,22,11,0,1,7,0,39,9,18,0,49,9,7,6,7,7,7,8,56,0,11,0,56,1,12,1,12,4,11,1,56,2,11,4,56,3,12,2,13,2,7,4,56,4,12,3,11,2,56,5,1,11,3,2,1,1,4,0,3,4,11,0,11,1,56,6,2,0],"table":[161,28,235,11,6,0,0,0,13,1,0,8,2,8,16,3,24,115,4,139,1,10,5,149,1,104,7,253,1,167,1,8,164,3,32,6,196,3,10,10,206,3,8,11,214,3,2,12,216,3,229,1,13,189,5,4,14,193,5,4,0,19,0,10,0,16,0,20,0,0,12,2,7,1,4,1,2,2,4,0,3,1,2,0,0,15,0,1,2,7,4,0,3,2,3,2,7,4,0,4,4,5,2,7,4,0,5,6,7,2,7,4,0,17,6,8,2,7,4,0,6,4,9,2,7,4,0,14,10,11,2,7,4,0,13,10,9,2,7,4,0,8,1,3,2,7,4,0,9,1,3,2,7,6,1,3,14,3,2,7,4,1,4,15,5,2,7,4,1,5,16,7,2,7,4,1,11,15,9,2,7,4,1,17,16,8,2,7,4,2,7,12,3,0,2,15,0,12,0,10,13,11,13,12,13,14,13,13,13,1,7,8,2,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,0,2,6,11,0,2,9,0,9,1,9,0,1,6,9,1,2,7,11,0,2,9,0,9,1,9,0,1,7,9,1,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,1,8,1,2,9,0,9,1,3,7,8,1,9,0,9,1,2,6,8,1,9,0,2,7,8,1,9,0,2,8,1,3,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,2,105,100,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,6,114,101,109,111,118,101,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,1,18,3,0,13,0,1,0,0,3,5,11,0,17,16,6,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,3,14,10,0,54,0,11,1,11,2,56,0,10,0,55,1,20,6,1,0,0,0,0,0,0,0,22,11,0,54,1,21,2,2,1,0,0,3,5,11,0,55,0,11,1,56,1,2,3,1,0,0,3,5,11,0,54,0,11,1,56,2,2,4,1,0,0,8,15,10,0,54,0,11,1,56,3,12,2,10,0,55,1,20,6,1,0,0,0,0,0,0,0,23,11,0,54,1,21,11,2,2,5,1,0,0,3,5,11,0,55,0,11,1,56,4,2,6,1,0,0,3,4,11,0,55,1,20,2,7,1,0,0,3,6,11,0,55,1,20,6,0,0,0,0,0,0,0,0,33,2,8,1,0,0,17,14,11,0,58,0,12,2,12,1,11,2,6,0,0,0,0,0,0,0,0,33,4,9,5,11,7,0,39,11,1,17,15,2,9,1,0,0,3,5,11,0,58,0,1,17,15,2,0,0,0,1,0,13,1,13,0],"table_vec":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,18,3,24,103,4,127,20,5,147,1,138,1,7,157,2,159,1,8,188,3,32,6,220,3,20,10,240,3,10,11,250,3,2,12,252,3,245,1,13,241,5,2,14,243,5,2,0,17,0,16,0,18,0,1,4,1,4,1,1,0,12,2,7,1,4,1,2,2,2,0,0,8,0,1,1,4,0,15,2,1,1,4,0,10,3,4,1,4,0,9,3,5,1,4,0,4,6,7,1,4,0,13,8,9,1,4,0,5,10,11,1,4,0,12,12,13,1,4,0,7,1,9,1,4,1,3,19,9,2,7,4,1,4,17,18,2,7,4,1,5,20,21,2,7,4,1,7,15,9,2,7,4,1,10,16,4,2,7,4,1,11,0,15,2,7,4,1,14,20,22,2,7,4,14,14,0,13,5,13,13,14,2,13,10,14,9,14,11,14,15,14,12,14,1,7,8,2,1,11,0,1,9,0,2,9,0,7,8,2,1,6,11,0,1,9,0,1,3,1,1,2,6,11,0,1,9,0,3,1,6,9,0,2,7,11,0,1,9,0,9,0,0,2,7,11,0,1,9,0,3,1,7,9,0,1,7,11,0,1,9,0,1,9,0,2,3,9,0,1,11,1,2,9,0,9,1,1,6,11,1,2,9,0,9,1,2,6,11,1,2,9,0,9,1,9,0,1,6,9,1,3,7,11,1,2,9,0,9,1,9,0,9,1,2,7,11,1,2,9,0,9,1,9,0,1,7,9,1,1,9,1,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,5,101,109,112,116,121,8,105,115,95,101,109,112,116,121,6,108,101,110,103,116,104,3,110,101,119,8,112,111,112,95,98,97,99,107,9,112,117,115,104,95,98,97,99,107,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,10,116,120,95,99,111,110,116,101,120,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,6,11,1,2,3,9,0,0,13,0,1,0,0,9,4,11,0,56,0,57,0,2,1,1,0,0,1,8,11,1,56,1,12,2,13,2,11,0,56,2,11,2,2,2,1,0,0,9,4,11,0,55,0,56,3,2,3,1,0,0,9,5,11,0,56,4,6,0,0,0,0,0,0,0,0,33,2,4,1,0,0,9,15,10,0,56,4,10,1,36,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,5,2,5,1,0,0,4,10,10,0,46,56,4,12,2,11,0,54,0,11,2,11,1,56,6,2,6,1,0,0,9,16,10,0,46,56,4,10,1,36,4,7,5,11,11,0,1,7,0,39,11,0,54,0,11,1,56,7,2,7,1,0,0,4,20,10,0,46,56,4,12,1,10,1,6,0,0,0,0,0,0,0,0,36,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,6,1,0,0,0,0,0,0,0,23,56,8,2,8,1,0,0,9,12,14,0,56,4,6,0,0,0,0,0,0,0,0,33,4,6,5,8,7,1,39,11,0,58,0,56,9,2,0,0,0,13,0],"transfer":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,54,4,56,6,5,62,8,7,70,144,1,8,214,1,32,6,246,1,10,12,128,2,82,0,7,0,7,0,1,1,8,0,4,0,1,1,12,0,0,2,1,1,8,0,2,2,1,1,12,0,5,2,1,1,8,0,3,2,1,1,12,0,1,2,1,1,8,0,6,2,1,1,8,0,8,0,1,1,8,8,2,6,2,7,2,2,9,0,5,0,1,9,0,13,102,114,101,101,122,101,95,111,98,106,101,99,116,18,102,114,101,101,122,101,95,111,98,106,101,99,116,95,105,109,112,108,20,112,117,98,108,105,99,95,102,114,101,101,122,101,95,111,98,106,101,99,116,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,17,115,104,97,114,101,95,111,98,106,101,99,116,95,105,109,112,108,8,116,114,97,110,115,102,101,114,13,116,114,97,110,115,102,101,114,95,105,109,112,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,56,0,2,1,1,0,0,1,4,11,0,11,1,56,0,2,2,1,0,0,1,3,11,0,56,1,2,3,1,0,0,1,3,11,0,56,1,2,4,1,0,0,1,3,11,0,56,2,2,5,1,0,0,1,3,11,0,56,2,2,6,3,2,0,7,3,2,0,8,3,2,0,0],"transfer_policy":[161,28,235,11,6,0,0,0,13,1,0,24,2,24,78,3,102,255,1,4,229,2,44,5,145,3,176,3,7,193,6,229,4,8,166,11,64,6,230,11,60,10,162,12,55,11,217,12,10,12,227,12,252,4,13,223,17,16,14,239,17,16,0,59,1,47,1,61,0,19,0,21,0,28,0,31,0,46,0,48,0,57,0,60,0,66,0,10,0,1,0,1,0,7,12,1,0,1,0,8,12,1,0,1,0,9,3,1,0,1,0,5,7,1,2,1,1,3,7,1,0,0,2,12,7,0,3,0,4,1,0,1,4,1,12,1,0,1,7,2,7,0,7,13,4,0,8,4,12,0,9,6,2,0,10,11,2,0,11,14,7,1,3,0,0,45,0,1,1,0,0,44,2,3,1,0,0,67,4,5,1,0,0,25,6,5,1,0,0,22,7,0,1,0,0,17,8,9,3,0,2,6,0,37,10,11,3,0,2,6,0,18,12,9,2,0,2,0,16,13,9,2,0,2,0,38,14,15,2,0,2,0,54,16,9,3,0,2,6,0,62,14,17,1,0,0,63,16,18,1,0,0,55,14,19,1,0,0,43,20,21,1,0,0,49,20,22,1,0,0,33,20,21,1,0,1,26,37,25,1,0,1,42,36,15,1,0,2,36,9,23,1,0,3,65,38,22,1,0,3,68,9,32,1,0,4,34,42,40,1,0,4,51,54,9,1,0,4,58,39,40,1,0,5,15,50,9,2,7,4,5,20,52,53,2,7,4,5,32,52,15,1,7,5,53,57,48,2,7,4,6,29,25,9,1,3,7,24,29,9,0,7,39,35,21,1,8,7,44,28,29,0,7,64,17,21,0,8,35,27,15,1,0,11,23,46,15,1,3,11,30,9,24,1,3,11,40,51,9,1,3,11,41,24,44,1,3,11,53,58,9,1,3,11,56,45,22,1,3,36,23,34,25,29,30,21,31,31,34,18,22,17,22,20,31,24,31,22,31,38,23,40,23,35,23,9,47,25,49,19,48,37,23,26,49,23,31,27,55,28,49,39,23,3,8,9,3,8,9,1,11,0,1,9,0,2,6,8,11,7,8,13,2,11,1,1,9,0,11,2,1,9,0,4,7,11,1,1,9,0,6,11,2,1,9,0,11,5,1,3,7,8,13,1,11,8,1,8,12,3,11,1,1,9,0,11,2,1,9,0,7,8,13,2,6,11,1,1,9,0,11,0,1,9,0,4,9,1,7,11,1,1,9,0,6,11,2,1,9,0,9,2,0,2,9,1,6,11,1,1,9,0,1,6,9,2,3,9,1,7,11,1,1,9,0,11,8,1,8,12,2,9,1,7,11,0,1,9,0,1,6,11,1,1,9,0,1,1,2,7,11,1,1,9,0,6,11,2,1,9,0,1,6,8,10,1,7,8,10,1,6,11,14,1,8,6,1,6,11,0,1,9,0,1,8,9,1,3,1,8,6,1,11,14,1,9,0,1,9,0,5,8,10,11,14,1,8,6,11,7,1,8,12,8,10,8,9,1,6,8,11,1,7,8,13,1,8,10,1,11,3,1,9,0,1,8,12,1,11,7,1,9,0,3,3,3,3,1,11,1,1,9,0,1,6,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,1,6,11,7,1,9,0,3,7,11,7,1,9,0,3,7,8,13,1,11,8,1,9,0,2,11,7,1,8,12,8,10,2,11,7,1,9,0,7,8,13,7,10,8,6,8,9,8,9,3,11,14,1,8,6,8,6,3,1,10,9,0,1,6,11,14,1,9,0,2,6,11,14,1,9,0,6,9,0,2,9,0,9,1,1,9,1,2,11,4,1,9,1,9,2,3,7,8,10,9,0,9,1,2,7,11,14,1,9,0,9,0,2,6,8,10,9,0,1,6,9,1,2,7,11,7,1,9,0,11,8,1,9,0,1,11,4,1,9,1,2,8,6,7,11,14,1,8,6,2,7,8,10,9,0,2,7,11,14,1,9,0,6,9,0,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,9,80,117,98,108,105,115,104,101,114,7,82,117,108,101,75,101,121,3,83,85,73,14,84,114,97,110,115,102,101,114,80,111,108,105,99,121,17,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,97,112,21,84,114,97,110,115,102,101,114,80,111,108,105,99,121,67,114,101,97,116,101,100,15,84,114,97,110,115,102,101,114,82,101,113,117,101,115,116,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,6,86,101,99,83,101,116,3,97,100,100,11,97,100,100,95,114,101,99,101,105,112,116,8,97,100,100,95,114,117,108,101,14,97,100,100,95,116,111,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,4,99,111,105,110,15,99,111,110,102,105,114,109,95,114,101,113,117,101,115,116,8,99,111,110,116,97,105,110,115,6,100,101,108,101,116,101,20,100,101,115,116,114,111,121,95,97,110,100,95,119,105,116,104,100,114,97,119,12,100,101,115,116,114,111,121,95,115,111,109,101,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,4,101,109,105,116,5,101,109,112,116,121,5,101,118,101,110,116,7,101,120,105,115,116,115,95,4,102,114,111,109,12,102,114,111,109,95,98,97,108,97,110,99,101,12,102,114,111,109,95,112,97,99,107,97,103,101,3,103,101,116,8,103,101,116,95,114,117,108,101,8,104,97,115,95,114,117,108,101,2,105,100,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,7,105,115,95,115,111,109,101,4,105,116,101,109,3,110,101,119,11,110,101,119,95,114,101,113,117,101,115,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,4,112,97,105,100,9,112,111,108,105,99,121,95,105,100,3,112,117,116,8,114,101,99,101,105,112,116,115,6,114,101,109,111,118,101,11,114,101,109,111,118,101,95,114,117,108,101,5,114,117,108,101,115,4,115,105,122,101,3,115,117,105,4,116,97,107,101,15,116,114,97,110,115,102,101,114,95,112,111,108,105,99,121,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,3,117,105,100,16,117,105,100,95,109,117,116,95,97,115,95,111,119,110,101,114,12,117,105,100,95,116,111,95,105,110,110,101,114,5,118,97,108,117,101,7,118,101,99,95,115,101,116,8,119,105,116,104,100,114,97,119,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,4,43,8,9,49,3,33,8,9,52,11,14,1,8,6,1,2,3,39,8,10,19,11,7,1,8,12,55,11,14,1,8,6,2,2,2,39,8,10,50,8,9,3,2,1,39,8,9,4,2,1,27,1,0,25,3,25,1,25,2,25,4,48,0,1,0,0,9,6,11,0,11,1,11,2,56,0,57,0,2,1,1,0,0,26,32,11,0,56,1,4,4,5,8,11,1,1,6,0,0,0,0,0,0,0,0,39,10,1,17,32,12,5,14,5,17,33,12,6,10,6,57,1,56,2,11,5,12,2,56,0,12,3,56,3,12,4,11,2,11,4,11,3,57,2,11,1,17,32,11,6,57,3,2,2,1,0,0,33,49,10,0,46,56,4,11,1,55,0,20,33,4,9,5,15,11,0,1,11,3,1,7,4,39,14,2,56,5,4,37,11,2,56,6,12,6,10,6,10,0,55,1,56,7,37,4,28,5,34,11,0,1,11,3,1,7,5,39,11,6,12,4,5,41,10,0,55,1,56,7,12,4,11,4,12,5,11,0,54,1,11,5,11,3,56,8,2,3,1,0,0,41,27,14,0,56,4,14,1,55,0,20,33,4,8,5,12,11,2,1,7,4,39,11,1,58,3,1,12,4,11,0,58,2,1,12,3,17,30,11,4,17,30,11,3,11,2,56,9,2,4,1,0,0,43,52,11,1,58,0,12,6,12,3,12,5,12,4,11,6,56,10,12,2,14,2,65,23,12,8,10,8,10,0,55,2,56,11,33,4,19,5,23,11,0,1,7,0,39,10,8,6,0,0,0,0,0,0,0,0,36,4,46,5,28,13,2,69,23,12,7,10,0,55,2,14,7,56,12,4,37,5,41,11,0,1,7,1,39,11,8,6,1,0,0,0,0,0,0,0,23,12,8,5,23,11,0,1,11,4,11,5,11,3,2,5,1,0,0,9,34,10,1,46,56,4,11,2,55,0,20,33,4,9,5,13,11,1,1,7,4,39,10,1,46,56,13,32,4,19,5,23,11,1,1,7,3,39,10,1,54,3,9,57,4,11,3,56,14,11,1,54,2,56,15,56,16,2,6,1,0,0,9,6,11,1,55,3,9,57,4,56,17,2,7,1,0,0,9,14,10,1,46,56,13,4,5,5,9,11,1,1,7,2,39,11,1,54,1,11,2,56,18,2,8,1,0,0,9,5,11,1,54,4,56,15,56,16,2,9,1,0,0,9,6,11,0,55,3,9,57,4,56,19,2,10,1,0,0,56,28,10,0,46,56,4,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,10,0,54,3,9,57,4,56,20,1,11,0,54,2,12,3,56,15,12,2,11,3,14,2,56,21,2,11,1,0,0,9,3,11,0,55,3,2,12,1,0,0,9,16,10,0,46,56,4,11,1,55,0,20,33,4,9,5,13,11,0,1,7,4,39,11,0,54,3,2,13,1,0,0,9,3,11,0,55,2,2,14,1,0,0,9,4,11,0,55,5,20,2,15,1,0,0,9,4,11,0,55,6,20,2,16,1,0,0,9,4,11,0,55,7,20,2,2,1,1,1,1,2,1,0,0,3,0,0,0,1,0,2,0,25,1,25,2,25,3,25,4,25,5,25,6,25,7,25,0],"tx_context":[161,28,235,11,6,0,0,0,10,1,0,2,2,2,4,3,6,35,5,41,24,7,65,111,8,176,1,32,6,208,1,20,10,228,1,14,12,242,1,107,13,221,2,10,0,8,0,0,2,0,0,7,0,1,0,0,2,0,2,0,0,3,0,3,0,0,4,0,3,0,0,5,4,1,0,0,6,0,3,0,0,1,5,1,0,1,6,8,0,1,5,1,6,10,2,1,3,1,7,8,0,2,10,2,3,0,2,5,3,9,84,120,67,111,110,116,101,120,116,9,100,101,114,105,118,101,95,105,100,6,100,105,103,101,115,116,5,101,112,111,99,104,18,101,112,111,99,104,95,116,105,109,101,115,116,97,109,112,95,109,115,20,102,114,101,115,104,95,111,98,106,101,99,116,95,97,100,100,114,101,115,115,11,105,100,115,95,99,114,101,97,116,101,100,6,115,101,110,100,101,114,10,116,120,95,99,111,110,116,101,120,116,7,116,120,95,104,97,115,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,32,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,5,7,5,9,10,2,3,3,4,3,6,3,0,1,0,0,6,4,11,0,16,0,20,2,1,1,0,0,6,3,11,0,16,1,2,2,1,0,0,6,4,11,0,16,2,20,2,3,1,0,0,6,4,11,0,16,3,20,2,4,1,0,0,7,18,10,0,16,4,20,12,2,10,0,16,1,20,10,2,17,6,12,1,11,2,6,1,0,0,0,0,0,0,0,22,11,0,15,4,21,11,1,2,5,0,0,0,6,4,11,0,16,4,20,2,6,0,2,0,0,0,0,1,0,2,0,3,0,4,0],"types":[161,28,235,11,6,0,0,0,6,1,0,2,3,2,6,5,8,6,7,14,26,8,40,32,12,72,4,0,1,0,0,0,1,1,2,1,6,9,0,1,1,19,105,115,95,111,110,101,95,116,105,109,101,95,119,105,116,110,101,115,115,5,116,121,112,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,2,0,0],"url":[161,28,235,11,6,0,0,0,9,1,0,4,2,4,8,3,12,25,5,37,20,7,57,78,8,135,1,64,10,199,1,6,12,205,1,50,13,255,1,2,0,8,1,2,0,1,7,0,1,0,7,0,0,4,0,1,0,0,5,2,1,0,0,3,3,0,0,0,7,4,5,0,1,6,2,0,0,1,8,1,1,8,0,1,10,2,1,6,8,0,2,7,8,0,8,1,0,6,83,116,114,105,110,103,3,85,114,108,5,97,115,99,105,105,9,105,110,110,101,114,95,117,114,108,10,110,101,119,95,117,110,115,97,102,101,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,6,115,116,114,105,110,103,6,117,112,100,97,116,101,3,117,114,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,8,8,1,0,1,0,0,5,3,11,0,18,0,2,1,1,0,0,5,4,11,0,17,4,18,0,2,2,1,0,0,5,4,11,0,16,0,20,2,3,1,0,0,5,5,11,1,11,0,15,0,21,2,0,0,0],"vec_map":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,22,3,28,168,1,4,196,1,28,5,224,1,254,1,7,222,3,153,2,8,247,5,64,6,183,6,50,10,233,6,21,11,254,6,4,12,130,7,235,5,13,237,12,6,14,243,12,6,0,30,1,21,1,31,0,2,7,2,1,0,0,0,0,0,7,2,1,0,0,0,1,1,7,1,0,0,0,7,0,1,2,1,0,0,14,2,0,2,1,0,0,23,3,4,2,1,0,0,22,5,4,2,1,0,0,13,3,6,2,1,0,0,8,7,8,2,1,0,0,28,7,9,2,1,1,0,3,7,10,2,1,0,0,26,11,12,2,1,0,0,16,11,10,2,1,0,0,5,1,0,2,1,0,0,15,1,13,2,1,0,0,19,11,14,2,1,0,0,12,7,15,2,1,0,0,11,7,12,2,1,0,0,9,16,17,2,1,0,0,10,18,19,2,1,0,0,24,18,4,2,1,0,1,6,27,24,1,0,1,17,28,10,1,0,1,20,0,27,1,0,1,27,24,27,1,0,2,16,25,10,1,0,2,23,23,24,1,0,2,25,31,0,1,0,7,4,14,4,23,20,22,20,5,4,21,26,20,26,13,4,19,12,8,4,24,20,21,12,20,12,18,12,0,1,11,0,2,9,0,9,1,3,7,11,0,2,9,0,9,1,9,0,9,1,2,7,11,0,2,9,0,9,1,6,9,0,2,9,0,9,1,1,7,11,0,2,9,0,9,1,1,7,9,1,2,6,11,0,2,9,0,9,1,6,9,0,1,6,9,1,1,11,2,1,9,1,1,1,1,6,11,0,2,9,0,9,1,1,3,2,10,9,0,10,9,1,1,10,9,0,1,11,2,1,3,2,6,11,0,2,9,0,9,1,3,2,6,9,0,6,9,1,2,7,11,0,2,9,0,9,1,3,2,6,9,0,7,9,1,1,11,1,2,9,0,9,1,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,9,0,1,6,10,9,0,1,9,1,1,11,2,1,9,0,1,6,11,2,1,9,0,1,10,11,1,2,9,0,9,1,7,10,11,1,2,9,0,9,1,3,9,0,10,9,0,3,9,1,10,9,1,1,7,10,9,0,4,6,11,1,2,9,0,9,1,3,10,9,0,3,2,3,3,1,6,11,1,2,9,0,9,1,1,7,11,1,2,9,0,9,1,5,69,110,116,114,121,6,79,112,116,105,111,110,6,86,101,99,77,97,112,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,13,100,101,115,116,114,111,121,95,101,109,112,116,121,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,3,103,101,116,16,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,20,103,101,116,95,101,110,116,114,121,95,98,121,95,105,100,120,95,109,117,116,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,7,103,101,116,95,109,117,116,6,105,110,115,101,114,116,16,105,110,116,111,95,107,101,121,115,95,118,97,108,117,101,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,3,107,101,121,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,3,112,111,112,6,114,101,109,111,118,101,19,114,101,109,111,118,101,95,101,110,116,114,121,95,98,121,95,105,100,120,7,114,101,118,101,114,115,101,4,115,105,122,101,4,115,111,109,101,7,116,114,121,95,103,101,116,5,118,97,108,117,101,7,118,101,99,95,109,97,112,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,1,4,10,11,1,2,9,0,9,1,1,2,2,18,9,0,29,9,1,0,4,1,4,0,1,0,0,0,3,64,20,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,21,20,10,0,14,1,12,3,46,11,3,56,0,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,11,2,57,1,68,20,2,2,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,56,2,58,1,2,3,1,0,0,0,15,10,0,55,0,56,3,32,4,6,5,10,11,0,1,7,4,39,11,0,54,0,69,20,58,1,2,4,1,0,0,22,13,10,0,11,1,12,2,46,11,2,56,1,12,3,11,0,54,0,11,3,67,20,54,1,2,5,1,0,0,12,10,10,0,11,1,56,1,12,2,11,0,55,0,11,2,66,20,55,1,2,6,1,0,0,9,19,10,0,10,1,56,0,4,11,11,0,11,1,56,4,20,56,5,12,2,5,17,11,0,1,11,1,1,56,6,12,2,11,2,2,7,1,0,0,15,7,11,0,11,1,56,7,12,2,14,2,56,8,2,8,1,0,0,0,4,11,0,55,0,65,20,2,9,1,0,0,0,5,11,0,56,9,6,0,0,0,0,0,0,0,0,33,2,10,1,0,0,29,12,11,0,58,0,12,1,14,1,56,3,4,7,5,9,7,2,39,11,1,70,20,0,0,0,0,0,0,0,0,2,11,1,0,0,30,40,11,0,58,0,12,1,13,1,56,10,6,0,0,0,0,0,0,0,0,12,2,14,1,65,20,12,5,64,24,0,0,0,0,0,0,0,0,12,4,64,26,0,0,0,0,0,0,0,0,12,7,10,2,10,5,35,4,35,5,19,13,1,69,20,58,1,12,6,12,3,13,4,11,3,68,24,13,7,11,6,68,26,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,14,11,1,70,20,0,0,0,0,0,0,0,0,11,4,11,7,2,12,1,0,0,32,32,6,0,0,0,0,0,0,0,0,12,2,10,0,55,0,65,20,12,4,64,24,0,0,0,0,0,0,0,0,12,3,10,2,10,4,35,4,28,5,13,10,0,55,0,10,2,66,20,12,1,13,3,11,1,55,2,20,68,24,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,8,11,0,1,11,3,2,13,1,0,0,33,36,6,0,0,0,0,0,0,0,0,12,2,10,0,56,9,12,3,10,2,10,3,35,4,30,5,10,10,0,55,0,10,2,66,20,55,2,10,1,33,4,25,11,0,1,11,1,1,11,2,56,11,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,12,2,14,1,0,0,15,13,11,0,11,1,56,7,12,2,14,2,56,8,4,8,5,10,7,1,39,11,2,56,13,2,15,1,0,0,34,20,10,1,10,0,56,9,35,4,6,5,10,11,0,1,7,3,39,11,0,55,0,11,1,66,20,12,2,10,2,55,2,11,2,55,1,2,16,1,0,0,35,21,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,67,20,12,2,10,2,55,2,11,2,54,1,2,17,1,0,0,0,17,10,1,10,0,46,56,9,35,4,7,5,11,11,0,1,7,3,39,11,0,54,0,11,1,56,2,58,1,2,0,0,1,1,1,0,0,4,1,4,2,4,0],"vec_set":[161,28,235,11,6,0,0,0,13,1,0,6,2,6,12,3,18,102,4,120,20,5,140,1,95,7,235,1,164,1,8,143,3,64,6,207,3,20,10,227,3,7,11,234,3,2,12,236,3,156,2,13,136,6,2,14,138,6,2,0,19,1,14,1,20,0,1,7,1,3,0,1,0,7,1,0,0,0,5,0,1,1,3,0,16,2,1,1,3,0,8,3,0,1,3,0,15,4,0,1,3,0,2,5,6,1,3,0,17,7,8,1,3,0,10,7,6,1,3,0,9,1,9,1,3,0,12,7,10,1,3,0,7,5,11,1,3,0,6,5,8,1,3,1,4,17,2,1,0,1,11,15,6,1,0,1,13,0,17,1,0,1,18,2,17,1,0,2,15,14,2,1,0,2,16,2,9,1,0,16,2,4,2,10,2,15,2,9,2,12,8,5,2,14,8,13,8,11,8,0,1,11,0,1,9,0,1,9,0,2,7,11,0,1,9,0,9,0,2,7,11,0,1,9,0,6,9,0,2,6,11,0,1,9,0,6,9,0,1,1,1,6,11,0,1,9,0,1,3,1,10,9,0,1,6,10,9,0,1,11,1,1,3,1,6,9,0,2,6,9,0,3,2,7,10,9,0,3,1,6,11,1,1,9,0,2,3,3,1,11,1,1,9,0,6,79,112,116,105,111,110,6,86,101,99,83,101,116,8,99,111,110,116,97,105,110,115,8,99,111,110,116,101,110,116,115,12,100,101,115,116,114,111,121,95,115,111,109,101,5,101,109,112,116,121,7,103,101,116,95,105,100,120,11,103,101,116,95,105,100,120,95,111,112,116,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,107,101,121,115,4,110,111,110,101,6,111,112,116,105,111,110,6,114,101,109,111,118,101,9,115,105,110,103,108,101,116,111,110,4,115,105,122,101,4,115,111,109,101,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,3,10,9,0,0,2,0,1,0,0,0,3,64,2,0,0,0,0,0,0,0,0,57,0,2,1,1,0,0,0,4,11,0,56,0,57,0,2,2,1,0,0,12,18,10,0,14,1,12,2,46,11,2,56,1,32,4,9,5,13,11,0,1,7,0,39,11,0,54,0,11,1,68,2,2,3,1,0,0,13,13,10,0,11,1,12,2,46,11,2,56,2,12,3,11,0,54,0,11,3,56,3,1,2,4,1,0,0,11,7,11,0,11,1,56,4,12,2,14,2,56,5,2,5,1,0,0,0,4,11,0,55,0,65,2,2,6,1,0,0,0,5,11,0,56,6,6,0,0,0,0,0,0,0,0,33,2,7,1,0,0,0,3,11,0,58,0,2,8,1,0,0,0,3,11,0,55,0,2,9,0,0,0,16,35,6,0,0,0,0,0,0,0,0,12,2,10,0,56,6,12,3,10,2,10,3,35,4,29,5,10,10,0,55,0,10,2,66,2,10,1,33,4,24,11,0,1,11,1,1,11,2,56,7,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,11,1,1,56,8,2,10,0,0,0,11,13,11,0,11,1,56,4,12,2,14,2,56,5,4,8,5,10,7,1,39,11,2,56,9,2,0,0,0,2,0],"versioned":[161,28,235,11,6,0,0,0,11,1,0,8,2,8,20,3,28,85,4,113,10,5,123,97,7,220,1,236,1,8,200,3,32,6,232,3,10,10,242,3,16,12,130,4,197,1,13,199,5,4,0,23,0,11,0,16,0,20,0,4,12,0,0,3,0,0,2,0,7,0,2,2,4,0,3,1,2,0,0,8,0,1,1,4,0,22,2,3,0,0,13,2,4,1,4,0,14,5,6,1,4,0,19,5,7,1,4,0,21,8,9,1,4,0,10,1,10,1,4,1,5,14,9,2,7,4,1,6,15,16,2,7,4,1,7,17,18,2,7,4,1,18,17,19,2,7,4,2,9,12,9,0,2,12,4,20,1,8,2,15,11,12,0,7,13,8,13,9,13,10,13,12,1,3,3,9,0,7,8,4,1,8,0,1,6,8,0,1,3,1,6,9,0,1,7,8,0,1,7,9,0,2,9,0,8,1,4,7,8,0,3,9,0,8,1,0,1,9,0,1,7,8,4,1,8,3,2,3,9,0,3,7,8,3,9,0,9,1,2,6,8,3,9,0,1,6,9,1,2,7,8,3,9,0,1,7,9,1,1,9,1,1,8,2,3,8,3,9,0,3,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,16,86,101,114,115,105,111,110,67,104,97,110,103,101,67,97,112,9,86,101,114,115,105,111,110,101,100,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,13,100,121,110,97,109,105,99,95,102,105,101,108,100,2,105,100,10,108,111,97,100,95,118,97,108,117,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,3,110,101,119,6,111,98,106,101,99,116,11,111,108,100,95,118,101,114,115,105,111,110,6,114,101,109,111,118,101,24,114,101,109,111,118,101,95,118,97,108,117,101,95,102,111,114,95,117,112,103,114,97,100,101,10,116,120,95,99,111,110,116,101,120,116,7,117,112,103,114,97,100,101,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,12,118,101,114,115,105,111,110,101,100,95,105,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,2,12,8,3,22,3,1,2,2,24,8,2,17,3,0,1,0,0,1,12,11,2,17,13,10,0,18,0,12,3,13,3,15,0,11,0,11,1,56,0,11,3,2,1,1,0,0,9,4,11,0,16,1,20,2,2,1,0,0,9,7,10,0,16,0,11,0,16,1,20,56,1,2,3,1,0,0,9,7,10,0,15,0,11,0,16,1,20,56,2,2,4,1,0,0,9,14,10,0,15,0,10,0,16,1,20,56,3,10,0,46,56,4,11,0,16,1,20,18,1,2,5,1,0,0,3,32,11,3,19,1,12,4,10,0,46,56,4,33,4,9,5,13,11,0,1,7,0,39,11,4,10,1,35,4,18,5,22,11,0,1,7,0,39,10,0,15,0,10,1,11,2,56,0,11,1,11,0,15,1,21,2,6,1,0,0,21,12,11,0,19,0,12,3,12,1,13,1,11,3,56,3,12,2,11,1,17,11,11,2,2,0,0,0,1,0]},"type_origin_table":[{"module_name":"tx_context","struct_name":"TxContext","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"ID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object","struct_name":"UID","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_field","struct_name":"Field","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bag","struct_name":"Bag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Supply","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"balance","struct_name":"Balance","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"bcs","struct_name":"BCS","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Referent","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"borrow","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"clock","struct_name":"Clock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"url","struct_name":"Url","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"Coin","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CoinMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"TreasuryCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"coin","struct_name":"CurrencyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"VecMap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_map","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"Publisher","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeTicket","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"package","struct_name":"UpgradeReceipt","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"Display","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"DisplayCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"display","struct_name":"VersionUpdated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"dynamic_object_field","struct_name":"Wrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"Curve","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PreparedVerifyingKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"PublicProofInputs","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"groth16","struct_name":"ProofPoints","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"vec_set","struct_name":"VecSet","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"sui","struct_name":"SUI","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferRequest","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicy","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"TransferPolicyCreated","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"transfer_policy","struct_name":"RuleKey","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Kiosk","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"KioskOwnerCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"PurchaseCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Borrow","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Item","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Listing","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"Lock","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemListed","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemPurchased","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"kiosk","struct_name":"ItemDelisted","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"LinkedTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"linked_table","struct_name":"Node","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_bag","struct_name":"ObjectBag","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"object_table","struct_name":"ObjectTable","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"PriorityQueue","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"priority_queue","struct_name":"Entry","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table","struct_name":"Table","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"table_vec","struct_name":"TableVec","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"Versioned","package":"0x0000000000000000000000000000000000000000000000000000000000000002"},{"module_name":"versioned","struct_name":"VersionChangeCap","package":"0x0000000000000000000000000000000000000000000000000000000000000002"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Package":{"id":"0x0000000000000000000000000000000000000000000000000000000000000003","version":5,"module_map":{"genesis":[161,28,235,11,6,0,0,0,11,1,0,26,2,26,58,3,84,107,4,191,1,14,5,205,1,176,2,7,253,3,137,9,8,134,13,96,6,230,13,20,10,250,13,93,12,215,14,219,3,13,178,18,24,0,31,1,44,1,72,2,18,2,20,2,43,2,61,2,66,0,54,0,63,0,64,0,67,0,70,0,3,3,0,0,2,3,0,0,9,0,0,0,8,0,0,1,4,7,1,0,0,3,0,4,1,0,1,4,1,12,1,0,1,5,11,4,0,6,5,2,0,7,10,2,0,8,6,4,0,10,7,4,0,11,12,4,0,0,22,0,1,0,0,15,2,1,0,0,14,3,1,0,1,25,25,26,1,0,1,36,24,14,1,0,2,35,22,14,1,0,3,26,9,1,1,0,3,53,8,9,1,0,3,75,1,9,1,0,4,29,30,31,1,0,6,65,32,1,0,7,27,5,6,0,8,22,17,18,0,9,22,19,1,0,10,23,15,16,0,11,13,34,1,0,11,42,12,10,0,11,52,29,1,0,12,32,27,28,0,12,34,13,14,0,7,7,8,7,5,21,4,23,3,23,9,7,6,7,6,8,7,11,5,1,8,8,8,1,10,8,0,8,2,7,8,9,0,4,11,5,1,8,8,10,8,3,7,10,8,12,7,8,9,1,7,10,8,12,25,10,8,3,3,3,10,2,3,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,8,10,3,11,5,1,8,8,11,5,1,8,8,5,8,11,8,12,10,8,12,10,2,10,2,1,6,8,9,1,3,1,8,8,2,7,11,5,1,9,0,3,1,11,5,1,9,0,1,8,12,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,9,2,6,10,8,12,6,8,12,1,1,8,3,3,3,3,3,3,3,7,8,9,1,8,11,5,11,5,1,8,8,3,3,13,7,8,9,1,8,10,8,8,7,10,8,12,11,5,1,8,8,3,3,8,11,8,10,7,8,9,5,11,5,1,8,8,3,5,11,4,1,5,5,1,8,3,1,6,10,9,0,1,5,1,6,11,4,1,9,0,1,11,4,1,9,0,1,9,0,2,7,10,8,12,5,1,7,8,12,4,7,8,12,11,5,1,8,8,5,7,8,9,2,11,5,1,9,0,7,8,9,1,11,6,1,9,0,2,11,6,1,8,8,5,2,3,3,2,7,8,12,3,7,66,97,108,97,110,99,101,4,67,111,105,110,22,71,101,110,101,115,105,115,67,104,97,105,110,80,97,114,97,109,101,116,101,114,115,24,71,101,110,101,115,105,115,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,15,84,111,107,101,110,65,108,108,111,99,97,116,105,111,110,25,84,111,107,101,110,68,105,115,116,114,105,98,117,116,105,111,110,83,99,104,101,100,117,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,9,86,97,108,105,100,97,116,111,114,8,97,99,116,105,118,97,116,101,19,97,99,116,105,118,97,116,101,95,118,97,108,105,100,97,116,111,114,115,15,97,108,108,111,99,97,116,101,95,116,111,107,101,110,115,11,97,108,108,111,99,97,116,105,111,110,115,11,97,109,111,117,110,116,95,109,105,115,116,7,98,97,108,97,110,99,101,24,99,104,97,105,110,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,4,99,111,105,110,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,11,100,101,115,99,114,105,112,116,105,111,110,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,12,102,114,111,109,95,98,97,108,97,110,99,101,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,9,105,109,97,103,101,95,117,114,108,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,4,110,97,109,101,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,18,110,101,116,119,111,114,107,95,112,117,98,108,105,99,95,107,101,121,3,110,101,119,6,111,98,106,101,99,116,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,19,112,114,111,116,111,99,111,108,95,112,117,98,108,105,99,95,107,101,121,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,17,114,101,99,105,112,105,101,110,116,95,97,100,100,114,101,115,115,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,23,115,116,97,107,101,95,115,117,98,115,105,100,121,95,102,117,110,100,95,109,105,115,116,41,115,116,97,107,101,95,115,117,98,115,105,100,121,95,105,110,105,116,105,97,108,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,21,115,116,97,107,101,100,95,119,105,116,104,95,118,97,108,105,100,97,116,111,114,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,118,97,108,105,100,97,116,111,114,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,13,118,97,108,105,100,97,116,111,114,95,115,101,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,6,118,101,99,116,111,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,17,119,111,114,107,101,114,95,112,117,98,108,105,99,95,107,101,121,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,15,39,10,2,24,10,2,33,10,2,47,10,2,62,5,30,3,21,3,49,10,2,48,10,2,41,10,2,74,10,2,40,10,2,45,10,2,46,10,2,73,10,2,1,2,12,50,3,19,3,28,3,59,3,57,3,58,3,55,13,37,3,38,3,69,3,71,3,68,3,2,2,2,56,3,16,10,8,3,3,2,3,51,5,17,3,60,11,4,1,5,0,0,0,0,4,147,1,10,5,46,17,11,6,0,0,0,0,0,0,0,0,33,4,7,5,11,11,5,1,7,0,39,11,4,19,2,12,6,12,22,13,1,11,22,56,0,12,24,56,1,12,23,64,10,0,0,0,0,0,0,0,0,12,28,14,3,65,11,12,8,6,0,0,0,0,0,0,0,0,12,11,10,11,10,8,35,4,89,5,33,14,3,10,11,66,11,20,19,0,12,29,12,17,12,16,12,14,12,30,12,15,12,19,12,20,12,7,12,10,12,25,12,18,12,12,12,9,12,13,11,25,11,20,11,15,11,30,11,19,11,13,11,9,11,12,11,18,11,14,11,16,11,17,11,29,11,10,11,7,10,5,17,16,12,27,14,28,14,27,17,19,32,4,77,5,81,11,5,1,7,1,39,13,28,11,27,68,10,11,11,6,1,0,0,0,0,0,0,0,22,12,11,5,28,11,1,11,6,13,28,10,5,17,1,13,28,17,2,14,2,16,0,20,14,2,16,1,20,14,2,16,2,20,14,2,16,3,20,14,2,16,4,20,14,2,16,5,20,14,2,16,6,20,10,5,17,14,12,26,11,24,14,2,16,7,20,14,2,16,8,20,14,2,16,9,20,10,5,17,12,12,21,11,0,11,28,11,23,14,2,16,10,20,14,2,16,11,20,11,26,11,21,11,5,17,13,2,1,0,0,0,20,44,14,1,56,2,32,4,35,5,5,13,1,69,21,19,3,12,7,12,5,12,6,13,0,11,5,56,0,12,4,14,7,56,3,4,29,11,7,56,4,12,8,10,2,11,8,17,18,11,4,11,6,10,3,17,17,5,34,11,4,10,3,56,5,11,6,17,10,5,0,11,2,1,11,3,1,11,1,70,21,0,0,0,0,0,0,0,0,11,0,56,6,2,2,0,0,0,33,24,10,0,46,65,10,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,1,35,4,21,5,11,10,0,10,2,67,10,6,0,0,0,0,0,0,0,0,17,15,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,2,1,2,1,3,1,7,1,8,1,9,1,10,1,11,1,4,1,5,1,6,1,0,1,1,0],"stake_subsidy":[161,28,235,11,6,0,0,0,12,1,0,12,2,12,22,3,34,37,4,71,4,5,75,74,7,149,1,176,2,8,197,3,64,6,133,4,28,10,161,4,20,12,181,4,180,1,13,233,5,10,15,243,5,4,0,18,1,6,1,7,1,14,1,21,1,23,0,3,4,0,1,0,12,0,2,1,4,1,0,1,4,2,2,0,5,4,2,0,0,8,0,1,0,0,5,2,3,0,0,10,4,5,0,1,16,7,8,0,2,17,13,14,1,0,2,24,11,5,1,0,3,15,12,5,0,5,10,4,10,5,11,2,1,8,3,3,3,13,7,8,4,1,8,0,1,7,8,0,1,11,2,1,8,3,1,6,8,0,1,3,0,1,7,8,4,1,8,1,3,4,11,2,1,8,3,3,1,8,3,1,6,11,2,1,9,0,2,3,3,2,7,11,2,1,9,0,3,1,11,2,1,9,0,3,66,97,103,7,66,97,108,97,110,99,101,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,84,120,67,111,110,116,101,120,116,13,97,100,118,97,110,99,101,95,101,112,111,99,104,3,98,97,103,7,98,97,108,97,110,99,101,6,99,114,101,97,116,101,27,99,117,114,114,101,110,116,95,100,105,115,116,114,105,98,117,116,105,111,110,95,97,109,111,117,110,116,28,99,117,114,114,101,110,116,95,101,112,111,99,104,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,20,100,105,115,116,114,105,98,117,116,105,111,110,95,99,111,117,110,116,101,114,12,101,120,116,114,97,95,102,105,101,108,100,115,7,103,101,110,101,115,105,115,4,109,97,116,104,3,109,105,110,3,110,101,119,5,115,112,108,105,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,100,101,99,114,101,97,115,101,95,114,97,116,101,27,115,116,97,107,101,95,115,117,98,115,105,100,121,95,112,101,114,105,111,100,95,108,101,110,103,116,104,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,2,6,7,11,2,1,8,3,11,3,9,3,20,3,19,13,12,8,1,0,3,0,0,6,19,10,3,7,0,75,37,4,6,5,10,11,4,1,7,1,39,11,0,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,11,4,17,3,18,0,2,1,3,0,0,9,57,10,0,16,0,20,10,0,16,1,56,0,17,6,12,3,10,0,15,1,11,3,56,1,12,2,10,0,16,2,20,6,1,0,0,0,0,0,0,0,22,10,0,15,2,21,10,0,16,2,20,10,0,16,3,20,25,6,0,0,0,0,0,0,0,0,33,4,53,10,0,16,0,20,53,10,0,16,4,20,53,24,7,0,26,12,1,10,0,16,0,20,11,1,52,23,11,0,15,0,21,5,55,11,0,1,11,2,2,2,1,0,0,6,8,10,0,16,0,20,11,0,16,1,56,0,17,6,2,0,2,0,0,0,1,0,3,0,4,0,13,0,22,0],"staking_pool":[161,28,235,11,6,0,0,0,12,1,0,22,2,22,58,3,80,175,2,4,255,2,38,5,165,3,224,2,7,133,6,144,9,8,149,15,96,6,245,15,200,1,10,189,17,66,12,255,17,237,11,13,236,29,28,15,136,30,4,0,73,1,48,2,15,2,16,2,19,2,43,2,47,2,74,2,77,2,78,2,79,0,8,12,0,0,5,7,0,0,7,8,0,1,4,7,1,0,0,2,0,12,0,3,1,4,1,0,1,4,2,12,1,0,1,6,3,7,0,6,11,4,0,7,6,2,0,8,9,12,2,7,1,4,1,10,10,2,0,0,45,0,1,0,0,63,2,3,0,0,64,4,5,0,0,84,6,7,0,0,80,8,9,0,0,24,10,3,0,0,61,11,3,0,0,60,12,3,0,0,59,12,3,0,0,85,13,9,0,0,12,14,3,0,0,65,4,5,0,0,21,14,3,0,0,76,15,5,0,0,54,16,17,0,0,72,16,5,0,0,71,16,5,0,0,38,15,18,0,0,36,15,18,0,0,69,19,8,0,0,70,19,3,0,0,42,20,3,0,0,35,21,18,0,0,57,22,23,0,0,51,15,5,0,0,52,15,5,0,0,39,22,18,0,0,30,24,5,0,0,31,24,5,0,0,34,3,23,0,0,18,22,3,0,1,17,52,35,1,0,1,28,49,3,1,0,1,32,54,51,1,3,1,37,52,18,1,0,1,40,52,18,1,0,1,46,3,29,1,0,1,68,51,29,1,0,2,45,0,32,0,3,41,40,5,1,0,3,69,48,31,1,0,3,83,34,5,1,0,3,86,3,31,1,0,4,29,41,42,1,0,5,44,45,5,0,6,23,28,3,0,6,33,35,17,1,8,6,45,0,28,0,8,14,46,3,2,7,4,8,17,55,56,2,7,4,8,20,55,18,2,7,4,8,45,0,27,2,7,4,9,62,36,3,1,12,9,78,36,3,1,8,10,25,38,5,0,10,67,38,39,0,51,26,36,5,42,30,41,30,46,1,53,8,39,30,43,30,52,43,48,26,40,30,32,5,37,5,34,5,35,5,33,5,31,5,50,26,49,26,1,7,8,11,1,8,0,5,7,8,0,11,5,1,8,9,5,3,7,8,11,0,3,7,8,0,8,2,7,8,11,1,3,2,7,8,0,8,2,2,3,11,5,1,8,9,1,8,2,1,11,5,1,8,9,2,7,8,0,11,5,1,8,9,2,7,8,0,7,8,11,1,7,8,0,4,7,8,0,3,3,3,2,7,8,0,3,1,6,8,0,1,6,8,2,1,8,7,1,1,3,7,8,2,3,7,8,11,2,7,8,2,8,2,2,6,8,2,6,8,2,2,6,8,0,3,1,8,1,2,6,8,1,3,1,11,10,2,3,8,1,2,3,8,1,1,11,10,2,9,0,9,1,1,8,8,1,11,3,1,9,0,1,8,9,1,11,5,1,9,0,1,8,4,2,8,2,3,1,6,11,5,1,9,0,1,6,9,0,2,9,0,5,6,3,11,5,1,8,9,3,11,5,1,8,9,5,3,1,6,8,11,1,5,2,7,11,5,1,9,0,11,5,1,9,0,2,11,5,1,9,0,7,8,11,1,11,6,1,9,0,1,11,6,1,8,9,3,3,8,1,11,5,1,8,9,2,3,3,3,7,11,10,2,9,0,9,1,9,0,9,1,5,3,3,8,1,3,3,2,7,11,5,1,9,0,3,2,7,11,3,1,9,0,9,0,3,11,5,1,8,9,5,3,1,9,0,1,6,11,3,1,9,0,2,6,8,2,11,5,1,8,9,2,6,11,3,1,9,0,9,0,2,6,11,10,2,9,0,9,1,9,0,1,6,9,1,3,3,8,1,3,3,66,97,103,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,16,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,3,97,100,100,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,24,99,104,101,99,107,95,98,97,108,97,110,99,101,95,105,110,118,97,114,105,97,110,116,115,4,99,111,105,110,8,99,111,110,116,97,105,110,115,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,18,100,101,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,6,100,101,108,101,116,101,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,5,101,112,111,99,104,14,101,120,99,104,97,110,103,101,95,114,97,116,101,115,12,101,120,116,114,97,95,102,105,101,108,100,115,4,102,105,108,108,12,102,114,111,109,95,98,97,108,97,110,99,101,14,103,101,116,95,115,117,105,95,97,109,111,117,110,116,16,103,101,116,95,116,111,107,101,110,95,97,109,111,117,110,116,16,103,101,116,95,119,105,116,104,95,100,101,102,97,117,108,116,2,105,100,21,105,110,105,116,105,97,108,95,101,120,99,104,97,110,103,101,95,114,97,116,101,25,105,115,95,101,113,117,97,108,95,115,116,97,107,105,110,103,95,109,101,116,97,100,97,116,97,11,105,115,95,105,110,97,99,116,105,118,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,21,105,115,95,112,114,101,97,99,116,105,118,101,95,97,116,95,101,112,111,99,104,7,105,115,95,115,111,109,101,4,106,111,105,110,15,106,111,105,110,95,115,116,97,107,101,100,95,115,117,105,4,109,97,116,104,3,109,105,110,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,27,112,101,110,100,105,110,103,95,112,111,111,108,95,116,111,107,101,110,95,119,105,116,104,100,114,97,119,13,112,101,110,100,105,110,103,95,115,116,97,107,101,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,26,112,101,110,100,105,110,103,95,116,111,116,97,108,95,115,117,105,95,119,105,116,104,100,114,97,119,7,112,111,111,108,95,105,100,17,112,111,111,108,95,116,111,107,101,110,95,97,109,111,117,110,116,18,112,111,111,108,95,116,111,107,101,110,95,98,97,108,97,110,99,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,9,112,114,105,110,99,105,112,97,108,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,30,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,32,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,95,112,114,101,97,99,116,105,118,101,12,114,101,119,97,114,100,115,95,112,111,111,108,6,115,101,110,100,101,114,4,115,111,109,101,5,115,112,108,105,116,16,115,112,108,105,116,95,115,116,97,107,101,100,95,115,117,105,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,97,109,111,117,110,116,11,115,117,105,95,98,97,108,97,110,99,101,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,17,117,110,119,114,97,112,95,115,116,97,107,101,100,95,115,117,105,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,5,118,97,108,117,101,23,119,105,116,104,100,114,97,119,95,102,114,111,109,95,112,114,105,110,99,105,112,97,108,16,119,105,116,104,100,114,97,119,95,114,101,119,97,114,100,115,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,0,2,11,33,8,8,13,11,3,1,3,22,11,3,1,3,76,3,66,11,5,1,8,9,56,3,26,11,10,2,3,8,1,50,3,53,3,49,3,27,8,4,1,2,2,75,3,55,3,2,2,4,33,8,8,54,8,7,71,3,58,11,5,1,8,9,0,3,0,0,25,18,10,0,56,0,12,1,10,0,17,47,56,1,56,1,6,0,0,0,0,0,0,0,0,56,2,6,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,0,17,38,18,0,2,1,3,0,0,33,47,14,1,56,3,12,6,10,0,46,17,18,32,4,9,5,15,11,0,1,11,4,1,7,11,39,10,6,6,0,0,0,0,0,0,0,0,36,4,20,5,26,11,0,1,11,4,1,7,18,39,11,4,17,47,10,0,46,56,4,11,3,11,1,18,2,12,5,10,0,16,0,20,11,6,22,11,0,15,0,21,11,5,11,2,56,5,2,2,3,0,0,37,61,10,0,11,1,17,3,12,4,12,3,10,2,46,17,55,12,7,14,4,56,3,12,5,10,0,10,5,10,3,10,2,46,17,54,17,9,12,6,11,5,14,6,56,3,22,12,8,10,0,16,1,20,10,8,22,10,0,15,1,21,10,0,16,2,20,11,3,22,10,0,15,2,21,10,0,46,17,18,4,48,11,0,17,7,5,50,11,0,1,13,4,11,6,56,6,1,11,4,11,2,56,7,11,7,56,8,11,8,2,3,3,0,0,44,31,14,1,16,3,20,10,0,46,56,4,33,4,9,5,13,11,0,1,7,2,39,11,0,14,1,16,4,20,12,2,46,11,2,17,23,12,3,11,1,17,4,12,4,14,3,14,4,56,3,17,28,11,4,2,4,0,0,0,9,8,11,0,19,2,12,1,1,1,17,45,11,1,2,5,3,0,0,3,15,10,0,16,5,20,14,1,56,3,22,10,0,15,5,21,11,0,15,6,11,1,56,6,1,2,6,3,0,0,45,28,11,1,46,17,54,6,1,0,0,0,0,0,0,0,22,12,3,10,0,17,7,10,0,17,8,10,0,15,7,10,3,10,0,16,5,20,10,0,16,8,20,18,1,56,9,11,0,11,3,12,2,46,11,2,17,30,2,7,0,0,0,3,29,10,0,16,5,20,10,0,16,1,20,23,10,0,15,5,21,10,0,16,8,20,10,0,16,2,20,23,10,0,15,8,21,6,0,0,0,0,0,0,0,0,10,0,15,1,21,6,0,0,0,0,0,0,0,0,11,0,15,2,21,2,8,3,0,0,23,31,10,0,16,5,20,10,0,16,8,20,18,1,12,1,10,0,16,5,20,10,0,16,0,20,22,10,0,15,5,21,14,1,10,0,16,5,20,17,28,10,0,15,8,21,6,0,0,0,0,0,0,0,0,11,0,15,0,21,2,9,0,0,0,47,33,10,0,11,3,12,4,46,11,4,17,23,12,6,14,6,11,2,17,27,12,8,10,8,10,1,38,4,20,11,8,11,1,23,12,5,5,22,6,0,0,0,0,0,0,0,0,12,5,11,5,10,0,16,6,56,3,17,44,12,7,11,0,15,6,11,7,56,10,2,10,3,0,0,3,29,10,0,15,7,10,1,17,29,56,9,10,0,46,17,17,4,10,5,14,11,0,1,7,15,39,10,0,46,17,18,32,4,20,5,24,11,0,1,7,17,39,11,0,15,9,11,1,56,11,2,11,3,0,0,50,59,14,1,16,3,20,10,0,46,56,4,33,4,9,5,15,11,0,1,11,2,1,7,2,39,10,0,46,17,17,4,20,5,26,11,0,1,11,2,1,7,16,39,10,2,46,17,55,12,4,11,1,17,4,12,3,14,3,56,3,12,5,10,0,16,5,20,10,5,23,10,0,15,5,21,10,0,16,8,20,10,5,23,11,0,15,8,21,11,3,11,2,56,7,11,4,56,8,11,5,2,12,3,0,0,3,16,10,0,46,17,18,32,4,6,5,10,11,0,1,7,12,39,11,1,56,12,11,0,15,10,21,2,13,1,0,0,3,4,11,0,16,5,20,2,14,1,0,0,3,4,11,0,16,3,20,2,15,1,0,0,3,4,11,0,16,11,56,3,2,16,1,0,0,3,4,11,0,16,4,20,2,17,1,0,0,3,4,11,0,16,9,56,13,2,18,1,0,0,3,4,11,0,16,10,56,14,2,19,1,0,0,5,53,10,0,16,11,56,3,12,3,10,1,10,3,37,4,9,5,15,11,0,1,11,2,1,7,4,39,11,3,10,1,23,7,0,38,4,22,5,28,11,0,1,11,2,1,7,19,39,10,1,7,0,38,4,33,5,39,11,0,1,11,2,1,7,19,39,11,2,17,47,10,0,16,3,20,10,0,16,4,20,11,0,15,11,11,1,56,10,18,2,2,20,1,4,0,3,9,11,0,11,1,10,2,17,19,11,2,46,17,55,56,5,2,21,1,4,0,53,24,10,0,14,1,12,2,46,11,2,17,22,4,8,5,12,11,0,1,7,13,39,11,1,19,2,12,3,1,1,17,45,11,0,15,11,11,3,56,6,1,2,22,1,0,0,18,25,10,0,16,3,20,10,1,16,3,20,33,4,17,11,0,16,4,20,11,1,16,4,20,33,12,2,5,23,11,0,1,11,1,1,9,12,2,11,2,2,23,1,0,0,45,45,10,0,10,1,17,26,4,8,11,0,1,17,29,2,10,0,16,10,10,1,56,15,11,1,17,44,12,3,10,0,16,9,56,16,20,12,2,10,3,10,2,38,4,41,5,25,10,0,16,7,10,3,56,17,4,36,11,0,16,7,11,3,56,18,20,2,11,3,6,1,0,0,0,0,0,0,0,23,12,3,5,20,11,0,1,17,29,2,24,1,0,0,3,4,11,0,16,0,20,2,25,1,0,0,3,4,11,0,16,1,20,2,26,0,0,0,18,17,10,0,17,17,4,8,11,0,1,8,12,2,5,15,11,0,16,9,56,16,20,11,1,36,12,2,11,2,2,27,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,12,20,53,11,1,53,24,11,0,16,13,20,53,26,52,2,28,0,0,0,18,35,10,0,16,12,20,6,0,0,0,0,0,0,0,0,33,4,9,8,12,2,5,15,10,0,16,13,20,6,0,0,0,0,0,0,0,0,33,12,2,11,2,4,21,11,0,1,11,1,2,10,0,16,13,20,53,11,1,53,24,11,0,16,12,20,53,26,52,2,29,0,0,0,3,4,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,18,1,2,30,0,0,0,57,22,10,0,11,1,17,23,12,3,14,3,10,0,16,5,20,17,28,12,4,11,0,16,8,20,12,2,11,4,11,2,33,4,19,5,21,7,10,39,2,0,7,0,8,0,9,2,1,2,2,0,3,0,4,0,6,0,5,0,1,0,2,2,3,1,0,1,1,0,81,0,82,0],"storage_fund":[161,28,235,11,6,0,0,0,11,1,0,6,2,6,14,3,20,44,4,64,8,5,72,73,7,145,1,178,1,8,195,2,64,10,131,3,15,12,146,3,107,13,253,3,4,15,129,4,2,0,9,1,4,1,10,0,2,4,0,1,0,4,1,0,1,2,1,2,0,0,6,0,1,0,0,3,2,0,0,0,13,3,4,0,0,12,3,4,0,1,5,8,4,1,0,1,8,9,7,1,0,1,14,10,4,1,0,1,15,5,7,1,0,7,6,4,6,5,6,6,6,1,11,1,1,8,2,1,8,0,6,7,8,0,11,1,1,8,2,11,1,1,8,2,11,1,1,8,2,3,3,1,6,8,0,1,3,0,1,8,2,1,11,1,1,9,0,2,7,11,1,1,9,0,11,1,1,9,0,2,7,11,1,1,9,0,3,1,6,11,1,1,9,0,7,66,97,108,97,110,99,101,3,83,85,73,11,83,116,111,114,97,103,101,70,117,110,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,4,106,111,105,110,3,110,101,119,22,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,98,97,108,97,110,99,101,5,115,112,108,105,116,12,115,116,111,114,97,103,101,95,102,117,110,100,3,115,117,105,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,13,116,111,116,97,108,95,98,97,108,97,110,99,101,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,5,118,97,108,117,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,11,1,1,8,2,7,11,1,1,8,2,0,3,0,0,5,4,56,0,11,0,18,0,2,1,3,0,0,0,30,10,0,15,0,11,2,56,1,1,10,0,15,0,11,3,56,1,1,10,0,15,1,11,1,56,1,1,10,0,15,1,11,5,56,2,12,6,10,0,15,0,11,6,56,1,1,11,0,15,1,11,4,56,2,2,2,1,0,0,5,4,11,0,16,1,56,3,2,3,1,0,0,5,8,10,0,16,1,56,3,11,0,16,0,56,3,22,2,0,1,0,0,0,11,0],"sui_system":[161,28,235,11,6,0,0,0,12,1,0,28,2,28,62,3,90,146,3,4,236,3,10,5,246,3,158,3,7,148,7,191,12,8,211,19,96,6,179,20,54,10,233,20,8,12,241,20,166,6,13,151,27,4,15,155,27,2,0,48,1,28,2,16,2,18,2,20,2,27,2,47,2,51,2,52,0,45,0,46,0,49,0,73,0,74,0,6,8,0,1,2,7,1,0,0,2,0,4,1,0,1,3,1,12,1,0,1,5,11,4,0,6,3,2,0,8,10,2,0,9,4,4,0,10,5,8,0,11,7,4,0,11,8,4,0,11,9,4,0,12,13,4,0,13,12,12,0,0,19,0,1,0,0,34,2,1,0,0,36,3,1,0,0,33,3,1,0,0,35,3,1,0,0,38,4,1,0,0,43,4,1,0,0,37,5,1,0,0,42,5,1,0,0,31,6,1,0,0,32,7,1,0,0,39,8,1,0,0,30,9,1,0,0,53,9,1,0,0,40,3,1,0,0,63,10,1,0,0,61,10,1,0,0,62,10,1,0,0,71,10,1,0,0,64,10,1,0,0,54,10,1,0,0,66,10,1,0,0,56,10,1,0,0,67,10,1,0,0,57,10,1,0,0,69,10,1,0,0,59,10,1,0,0,68,11,1,0,0,58,11,1,0,0,70,10,1,0,0,60,10,1,0,0,65,10,1,0,0,55,10,1,0,0,15,12,13,0,0,25,14,15,0,0,26,14,16,0,0,24,14,16,0,4,14,22,1,2,7,4,4,17,39,43,2,7,4,4,29,39,40,2,7,4,7,44,24,1,1,8,8,41,35,36,0,11,15,37,13,0,11,19,18,19,0,11,22,1,20,0,11,30,32,1,0,11,31,29,1,0,11,32,30,1,0,11,33,26,1,0,11,34,25,1,0,11,35,26,1,0,11,36,26,1,0,11,37,28,1,0,11,38,27,1,0,11,39,31,1,0,11,40,26,1,0,11,42,28,1,0,11,43,27,1,0,11,50,15,20,0,11,53,32,1,0,11,54,33,1,0,11,55,33,1,0,11,56,33,1,0,11,57,33,1,0,11,58,34,1,0,11,59,33,1,0,11,60,33,1,0,11,61,33,1,0,11,62,33,1,0,11,63,33,1,0,11,64,33,1,0,11,65,33,1,0,11,66,33,1,0,11,67,33,1,0,11,68,34,1,0,11,69,33,1,0,11,70,33,1,0,11,71,33,1,0,11,72,19,41,0,37,21,40,23,39,21,37,42,38,42,8,8,4,10,8,12,11,2,1,8,5,3,3,8,11,8,7,7,8,6,0,16,7,8,0,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,6,2,7,8,0,7,8,6,3,7,8,0,6,8,13,3,3,7,8,0,3,7,8,6,4,7,8,0,11,3,1,8,5,5,7,8,6,5,7,8,0,10,11,3,1,8,5,11,1,1,3,5,7,8,6,3,7,8,0,8,8,7,8,6,3,7,8,0,6,8,13,5,3,7,8,0,10,2,6,8,6,4,7,8,0,10,2,10,2,6,8,6,11,11,2,1,8,5,11,2,1,8,5,7,8,0,3,3,3,3,3,3,3,7,8,6,1,11,2,1,8,5,1,7,8,0,1,6,8,10,1,7,8,10,3,8,0,8,9,3,7,10,8,12,11,2,1,8,5,3,3,8,11,8,7,7,8,6,1,8,9,1,3,2,3,8,9,3,7,8,4,9,0,9,1,1,8,0,1,9,0,16,7,8,10,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,6,2,7,8,10,7,8,6,3,7,8,10,6,8,13,3,3,7,8,10,3,7,8,6,4,7,8,10,11,3,1,8,5,5,7,8,6,5,7,8,10,10,11,3,1,8,5,11,1,1,3,5,7,8,6,3,7,8,10,8,8,7,8,6,3,7,8,10,6,8,13,5,3,7,8,10,10,2,6,8,6,4,7,8,10,10,2,10,2,6,8,6,1,6,8,6,1,5,11,7,8,10,3,3,11,2,1,8,5,11,2,1,8,5,3,3,3,3,3,7,8,6,2,7,8,10,8,10,2,7,8,4,9,0,1,9,1,1,8,10,2,3,8,10,1,7,9,1,7,66,97,108,97,110,99,101,4,67,111,105,110,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,14,83,117,105,83,121,115,116,101,109,83,116,97,116,101,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,3,97,100,100,13,97,100,118,97,110,99,101,95,101,112,111,99,104,7,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,4,99,111,105,110,6,99,114,101,97,116,101,13,100,121,110,97,109,105,99,95,102,105,101,108,100,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,2,105,100,24,108,111,97,100,95,105,110,110,101,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,17,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,21,108,111,97,100,95,115,121,115,116,101,109,95,115,116,97,116,101,95,109,117,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,6,115,101,110,100,101,114,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,13,115,116,97,107,101,95,115,117,98,115,105,100,121,12,115,116,97,107,105,110,103,95,112,111,111,108,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,7,118,101,114,115,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,23,8,4,75,3,0,3,0,0,17,23,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,43,12,9,17,44,12,10,11,0,10,10,18,0,12,8,13,8,15,0,11,10,11,9,56,0,11,8,56,1,2,1,1,4,0,1,19,11,0,17,35,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,11,15,17,49,2,2,1,4,0,1,5,11,0,17,35,11,1,17,51,2,3,1,4,0,1,5,11,0,17,35,11,1,17,48,2,4,1,4,0,1,5,11,0,17,35,11,1,17,50,2,5,1,4,0,1,6,11,0,17,35,11,1,11,2,17,53,2,6,1,4,0,1,6,11,0,17,35,11,1,11,2,17,57,2,7,1,4,0,1,6,11,0,17,35,11,1,11,2,17,52,2,8,1,4,0,1,6,11,0,17,35,11,1,11,2,17,56,2,9,1,4,0,1,7,11,0,17,35,11,1,11,2,11,3,17,46,2,10,1,4,0,1,8,11,0,17,35,11,1,11,2,11,3,11,4,17,47,2,11,1,4,0,1,6,11,0,17,35,11,1,11,2,17,54,2,12,1,4,0,1,6,11,0,17,35,11,1,11,2,17,45,2,13,1,4,0,1,6,11,0,17,35,11,1,11,2,17,59,2,14,1,4,0,1,5,11,0,17,35,11,1,17,55,2,15,1,4,0,1,6,11,0,17,35,11,1,11,2,17,69,2,16,1,4,0,1,6,11,0,17,35,11,1,11,2,17,67,2,17,1,4,0,1,6,11,0,17,35,11,1,11,2,17,68,2,18,1,4,0,1,6,11,0,17,35,11,1,11,2,17,77,2,19,1,4,0,1,6,11,0,17,35,11,1,11,2,17,70,2,20,1,4,0,1,6,11,0,17,35,11,1,11,2,17,60,2,21,1,4,0,1,6,11,0,17,35,11,1,11,2,17,72,2,22,1,4,0,1,6,11,0,17,35,11,1,11,2,17,62,2,23,1,4,0,1,6,11,0,17,35,11,1,11,2,17,73,2,24,1,4,0,1,6,11,0,17,35,11,1,11,2,17,63,2,25,1,4,0,1,6,11,0,17,35,11,1,11,2,17,75,2,26,1,4,0,1,6,11,0,17,35,11,1,11,2,17,65,2,27,1,4,0,1,7,11,0,17,35,11,1,11,2,11,3,17,74,2,28,1,4,0,1,7,11,0,17,35,11,1,11,2,11,3,17,64,2,29,1,4,0,1,6,11,0,17,35,11,1,11,2,17,76,2,30,1,4,0,1,6,11,0,17,35,11,1,11,2,17,66,2,31,1,4,0,1,6,11,0,17,35,11,1,11,2,17,71,2,32,1,4,0,1,6,11,0,17,35,11,1,11,2,17,61,2,33,0,0,0,16,29,11,2,17,35,12,11,10,10,46,17,41,7,2,33,4,10,5,16,11,11,1,11,10,1,7,0,39,11,11,11,3,11,4,11,0,11,1,11,5,11,6,11,7,11,8,11,9,11,10,17,42,2,34,0,0,0,1,4,11,0,17,36,46,2,35,0,0,0,1,3,11,0,17,36,2,36,0,0,0,38,47,10,0,16,1,20,6,1,0,0,0,0,0,0,0,33,4,25,10,0,15,0,10,0,16,1,20,56,2,17,78,12,2,6,2,0,0,0,0,0,0,0,10,0,15,1,21,10,0,15,0,10,0,16,1,20,11,2,56,3,10,0,15,0,10,0,16,1,20,56,4,12,1,10,1,46,17,58,11,0,16,1,20,33,4,41,5,45,11,1,1,7,1,39,11,1,2,0,0,0,1,0,21,0],"sui_system_state_inner":[161,28,235,11,6,0,0,0,12,1,0,45,2,45,104,3,149,1,212,5,4,233,6,50,5,155,7,251,6,7,150,14,188,29,8,210,43,96,6,178,44,117,10,167,45,189,1,12,228,46,229,17,13,201,64,46,15,247,64,4,0,112,1,68,2,25,2,26,2,27,2,39,2,67,2,70,2,110,2,114,2,120,2,121,2,174,1,2,175,1,0,100,0,103,0,106,0,161,1,0,162,1,0,166,1,0,12,4,0,0,13,4,0,0,9,4,0,0,10,4,0,0,11,3,0,1,4,7,1,0,0,2,0,12,0,3,1,4,1,0,1,4,2,12,1,0,1,6,3,7,0,8,5,2,0,9,14,12,2,7,1,4,1,11,15,2,0,12,20,7,2,1,0,0,0,13,21,7,1,3,0,14,6,4,0,15,7,8,0,16,8,4,0,17,17,4,0,18,16,12,0,18,18,2,0,19,19,4,0,0,29,0,1,0,0,30,2,3,0,0,160,1,1,4,0,0,80,5,6,0,0,82,7,6,0,0,79,7,6,0,0,81,7,6,0,0,84,8,6,0,0,96,8,6,0,0,83,9,6,0,0,95,9,6,0,0,77,10,6,0,0,78,11,6,0,0,85,12,6,0,0,75,13,6,0,0,122,13,6,0,0,76,14,6,0,0,123,14,6,0,0,86,7,6,0,0,151,1,15,6,0,0,149,1,15,6,0,0,150,1,15,6,0,0,159,1,15,6,0,0,152,1,15,6,0,0,129,1,15,6,0,0,154,1,15,6,0,0,131,1,15,6,0,0,155,1,15,6,0,0,132,1,15,6,0,0,157,1,15,6,0,0,134,1,15,6,0,0,156,1,16,6,0,0,133,1,16,6,0,0,158,1,15,6,0,0,135,1,15,6,0,0,153,1,15,6,0,0,130,1,15,6,0,0,23,17,18,0,0,36,19,20,0,0,71,19,20,0,0,113,19,20,0,0,44,6,20,0,0,38,19,20,0,0,167,1,21,20,0,0,168,1,21,22,0,0,169,1,19,23,0,0,47,21,24,0,0,49,19,20,0,0,48,19,20,0,0,41,25,18,0,1,32,94,64,1,0,1,57,93,59,1,0,2,64,35,36,0,3,33,34,6,1,0,3,58,81,20,1,0,3,98,85,34,1,0,3,173,1,83,20,1,0,3,178,1,80,34,1,0,3,179,1,6,34,1,0,4,42,95,54,1,0,4,54,54,34,1,0,5,34,64,6,1,3,7,59,92,6,1,0,10,72,96,6,1,12,11,36,39,20,0,11,92,39,40,0,12,28,63,59,2,1,0,12,35,6,32,2,1,0,12,45,63,89,2,1,0,12,46,67,68,2,1,0,12,53,66,6,2,1,0,12,74,67,73,2,1,0,13,28,69,59,1,3,13,35,6,65,1,3,13,53,70,6,1,3,13,56,72,59,1,3,13,74,71,6,1,3,13,97,64,65,1,3,14,23,84,18,0,15,99,56,20,0,16,23,87,18,0,16,64,18,30,0,16,115,82,20,0,16,117,82,20,0,17,64,41,38,0,17,65,74,6,0,17,84,50,6,0,17,93,53,6,0,17,94,50,6,0,17,124,75,6,0,17,125,75,6,0,17,126,75,6,0,17,127,75,6,0,17,128,1,78,6,0,17,136,1,75,6,0,17,137,1,75,6,0,17,138,1,75,6,0,17,139,1,75,6,0,17,140,1,75,6,0,17,141,1,75,6,0,17,142,1,75,6,0,17,143,1,75,6,0,17,144,1,75,6,0,17,145,1,78,6,0,17,146,1,75,6,0,17,147,1,75,6,0,17,148,1,75,6,0,18,176,1,61,62,0,19,22,29,45,0,19,23,86,6,0,19,24,77,6,0,19,31,29,20,0,19,50,52,49,0,19,51,52,49,0,19,52,48,49,0,19,55,58,59,0,19,64,27,28,0,19,66,29,20,0,19,77,55,6,0,19,79,44,6,0,19,80,42,6,0,19,81,43,6,0,19,82,43,6,0,19,83,51,6,0,19,85,57,6,0,19,104,29,23,0,19,118,29,20,0,19,168,1,58,22,0,19,170,1,58,20,0,19,177,1,47,46,0,67,31,58,33,60,33,66,31,77,40,70,31,69,31,72,40,74,40,76,40,75,40,71,31,57,33,54,33,56,33,55,33,61,88,68,31,73,40,62,33,51,20,50,20,59,33,63,91,53,33,7,10,8,18,11,7,1,8,10,3,3,8,0,8,15,7,8,12,1,8,2,8,3,3,3,3,3,3,3,7,8,12,1,8,0,1,8,3,16,7,8,3,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,0,2,7,8,3,7,8,12,3,7,8,3,6,8,19,3,3,7,8,3,3,7,8,12,4,7,8,3,11,8,1,8,10,5,7,8,12,5,7,8,3,10,11,8,1,8,10,11,5,1,3,5,7,8,12,3,7,8,3,8,16,7,8,12,3,7,8,3,6,8,19,5,3,8,20,5,7,11,13,2,5,11,14,1,5,3,7,8,3,10,2,6,8,12,4,7,8,3,10,2,10,2,6,8,12,11,7,8,3,3,3,11,7,1,8,10,11,7,1,8,10,3,3,3,3,3,7,8,12,1,11,7,1,8,10,1,6,8,3,1,3,2,6,8,3,5,1,8,9,1,6,11,11,2,8,9,5,1,11,14,1,5,3,10,11,8,1,8,10,11,5,1,3,7,8,12,2,3,8,21,2,10,8,18,7,8,12,1,8,21,1,6,8,21,1,8,17,2,5,11,14,1,5,1,11,13,2,9,0,9,1,1,8,10,1,11,7,1,9,0,1,7,8,12,1,8,6,23,3,3,3,3,3,8,6,8,0,3,3,1,11,7,1,8,10,3,3,11,7,1,8,10,8,15,3,8,6,8,17,3,3,11,13,2,5,11,14,1,5,3,8,21,1,8,18,1,6,8,12,1,5,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,12,3,7,8,21,8,18,7,8,12,2,7,8,21,7,8,12,3,7,8,21,3,7,8,12,1,6,10,8,18,1,8,20,3,7,8,21,6,8,19,2,3,7,8,21,6,8,20,1,1,7,8,18,3,7,8,18,8,20,3,3,7,8,21,3,6,8,12,2,7,8,21,6,8,12,2,7,8,18,3,1,11,8,1,9,0,4,7,8,21,5,11,7,1,8,10,7,8,12,1,6,8,16,3,7,8,21,8,16,7,8,12,2,6,8,21,5,1,1,4,6,5,6,5,5,7,11,14,1,5,1,6,8,20,1,6,5,2,6,11,13,2,9,0,9,1,6,9,0,1,9,0,1,11,14,1,9,0,3,7,11,13,2,9,0,9,1,9,0,9,1,2,7,11,13,2,9,0,9,1,6,9,0,1,7,9,1,2,6,11,14,1,9,0,6,9,0,2,7,11,14,1,9,0,9,0,2,7,11,14,1,9,0,6,9,0,1,6,11,14,1,9,0,2,9,0,9,1,2,7,8,18,7,8,12,2,7,8,18,10,2,2,7,8,18,6,8,18,2,6,8,21,6,8,18,3,7,8,18,10,2,10,2,44,1,3,3,3,3,3,3,1,1,1,11,7,1,8,10,3,3,3,3,3,3,3,3,4,3,3,3,11,7,1,8,10,3,3,3,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,3,11,7,1,8,10,4,11,7,1,8,10,4,3,3,3,3,4,3,1,7,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,1,6,8,17,1,6,11,7,1,9,0,1,7,8,15,2,7,11,7,1,9,0,3,9,7,8,21,7,11,7,1,8,10,7,11,7,1,8,10,7,11,13,2,5,11,14,1,5,3,3,3,3,7,8,12,6,7,8,17,11,7,1,8,10,11,7,1,8,10,11,7,1,8,10,3,3,1,8,4,1,6,9,1,5,11,7,1,8,10,3,11,7,1,8,10,11,8,1,8,10,11,7,1,8,10,1,11,8,1,8,10,2,7,11,8,1,9,0,10,11,8,1,9,0,1,6,11,5,1,9,0,1,11,5,1,9,0,2,11,7,1,9,0,7,8,12,2,9,0,5,3,66,97,103,7,66,97,108,97,110,99,101,4,67,111,105,110,2,73,68,6,79,112,116,105,111,110,3,83,85,73,12,83,116,97,107,101,83,117,98,115,105,100,121,9,83,116,97,107,101,100,83,117,105,11,83,116,111,114,97,103,101,70,117,110,100,19,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,21,83,117,105,83,121,115,116,101,109,83,116,97,116,101,73,110,110,101,114,86,50,20,83,121,115,116,101,109,69,112,111,99,104,73,110,102,111,69,118,101,110,116,16,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,18,83,121,115,116,101,109,80,97,114,97,109,101,116,101,114,115,86,50,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,6,86,101,99,77,97,112,6,86,101,99,83,101,116,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,3,98,97,103,7,98,97,108,97,110,99,101,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,24,99,114,101,97,116,101,95,115,121,115,116,101,109,95,112,97,114,97,109,101,116,101,114,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,5,101,109,112,116,121,5,101,112,111,99,104,17,101,112,111,99,104,95,100,117,114,97,116,105,111,110,95,109,115,24,101,112,111,99,104,95,115,116,97,114,116,95,116,105,109,101,115,116,97,109,112,95,109,115,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,20,101,120,116,114,97,99,116,95,99,111,105,110,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,28,103,101,110,101,115,105,115,95,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,3,103,101,116,7,103,101,116,95,109,117,116,16,103,101,116,95,114,101,112,111,114,116,101,114,115,95,111,102,31,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,111,98,106,101,99,116,95,114,101,98,97,116,101,115,30,103,101,116,95,115,116,111,114,97,103,101,95,102,117,110,100,95,116,111,116,97,108,95,98,97,108,97,110,99,101,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,6,105,110,115,101,114,116,12,105,110,116,111,95,98,97,108,97,110,99,101,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,8,105,115,95,101,109,112,116,121,7,105,115,95,115,111,109,101,4,106,111,105,110,8,106,111,105,110,95,118,101,99,28,108,101,102,116,111,118,101,114,95,115,116,111,114,97,103,101,95,102,117,110,100,95,105,110,102,108,111,119,19,109,97,120,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,19,109,105,110,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,27,109,105,110,95,118,97,108,105,100,97,116,111,114,95,106,111,105,110,105,110,103,95,115,116,97,107,101,3,110,101,119,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,114,97,109,101,116,101,114,115,3,112,97,121,16,112,114,111,116,111,99,111,108,95,118,101,114,115,105,111,110,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,19,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,6,114,101,109,111,118,101,16,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,21,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,26,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,109,117,108,95,99,111,105,110,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,20,114,111,116,97,116,101,95,111,112,101,114,97,116,105,111,110,95,99,97,112,9,115,97,102,101,95,109,111,100,101,29,115,97,102,101,95,109,111,100,101,95,99,111,109,112,117,116,97,116,105,111,110,95,114,101,119,97,114,100,115,36,115,97,102,101,95,109,111,100,101,95,110,111,110,95,114,101,102,117,110,100,97,98,108,101,95,115,116,111,114,97,103,101,95,102,101,101,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,25,115,97,102,101,95,109,111,100,101,95,115,116,111,114,97,103,101,95,114,101,119,97,114,100,115,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,39,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,33,115,101,116,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,103,97,115,95,112,114,105,99,101,9,115,105,110,103,108,101,116,111,110,5,115,112,108,105,116,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,13,115,116,97,107,101,95,115,117,98,115,105,100,121,20,115,116,97,107,101,95,115,117,98,115,105,100,121,95,97,109,111,117,110,116,25,115,116,97,107,101,95,115,117,98,115,105,100,121,95,115,116,97,114,116,95,101,112,111,99,104,12,115,116,97,107,105,110,103,95,112,111,111,108,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,14,115,116,111,114,97,103,101,95,99,104,97,114,103,101,12,115,116,111,114,97,103,101,95,102,117,110,100,20,115,116,111,114,97,103,101,95,102,117,110,100,95,98,97,108,97,110,99,101,25,115,116,111,114,97,103,101,95,102,117,110,100,95,114,101,105,110,118,101,115,116,109,101,110,116,14,115,116,111,114,97,103,101,95,114,101,98,97,116,101,3,115,117,105,10,115,117,105,95,115,121,115,116,101,109,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,20,115,121,115,116,101,109,95,115,116,97,116,101,95,118,101,114,115,105,111,110,5,116,97,98,108,101,13,116,111,116,97,108,95,98,97,108,97,110,99,101,14,116,111,116,97,108,95,103,97,115,95,102,101,101,115,28,116,111,116,97,108,95,111,98,106,101,99,116,95,115,116,111,114,97,103,101,95,114,101,98,97,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,31,116,111,116,97,108,95,115,116,97,107,101,95,114,101,119,97,114,100,115,95,100,105,115,116,114,105,98,117,116,101,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,21,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,26,117,110,100,111,95,114,101,112,111,114,116,95,118,97,108,105,100,97,116,111,114,95,105,109,112,108,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,38,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,50,112,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,41,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,40,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,119,111,114,107,101,114,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,100,101,115,99,114,105,112,116,105,111,110,26,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,105,109,97,103,101,95,117,114,108,21,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,97,109,101,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,39,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,43,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,42,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,41,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,112,114,111,106,101,99,116,95,117,114,108,8,118,49,95,116,111,95,118,50,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,32,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,103,114,97,99,101,95,112,101,114,105,111,100,29,118,97,108,105,100,97,116,111,114,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,24,118,97,108,105,100,97,116,111,114,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,31,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,34,118,97,108,105,100,97,116,111,114,95,118,101,114,121,95,108,111,119,95,115,116,97,107,101,95,116,104,114,101,115,104,111,108,100,10,118,97,108,105,100,97,116,111,114,115,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,119,105,116,104,100,114,97,119,95,97,108,108,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,3,8,1,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,8,37,3,102,3,61,3,63,3,164,1,3,171,1,3,163,1,3,40,8,6,1,2,9,37,3,102,3,62,3,61,3,63,3,164,1,3,171,1,3,163,1,3,40,8,6,2,2,16,36,3,71,3,113,3,172,1,8,21,106,8,17,69,8,0,73,3,165,1,11,13,2,5,11,14,1,5,100,8,15,87,1,91,11,7,1,8,10,88,11,7,1,8,10,90,3,89,3,38,3,40,8,6,3,2,16,36,3,71,3,113,3,172,1,8,21,106,8,17,69,8,1,73,3,165,1,11,13,2,5,11,14,1,5,100,8,15,87,1,91,11,7,1,8,10,88,11,7,1,8,10,90,3,89,3,38,3,40,8,6,4,2,12,36,3,71,3,73,3,118,3,108,3,105,3,109,3,107,3,101,3,116,3,119,3,60,3,0,3,0,0,26,27,11,0,10,6,17,116,12,8,14,8,17,111,12,7,6,0,0,0,0,0,0,0,0,11,2,17,41,11,8,11,1,17,81,11,4,11,7,56,0,11,5,9,56,1,56,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,11,3,11,6,17,52,18,2,2,1,3,0,0,6,11,11,0,11,1,11,2,11,3,11,4,11,5,11,6,11,7,17,52,18,0,2,2,3,0,0,37,55,11,0,19,2,12,17,12,3,12,12,12,13,12,11,12,14,12,10,12,15,12,21,12,9,12,7,12,18,12,23,1,12,8,12,1,11,7,19,0,12,6,12,19,12,22,12,20,12,5,12,4,12,16,12,2,11,1,11,8,6,2,0,0,0,0,0,0,0,11,23,11,18,11,2,11,16,6,4,0,0,0,0,0,0,0,11,4,11,5,11,20,11,22,11,19,11,6,18,1,11,9,11,21,11,15,11,10,11,14,11,11,11,13,11,12,11,3,11,17,18,3,2,3,3,0,0,38,26,10,15,46,17,65,11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12,11,13,11,14,10,15,17,84,12,16,11,0,15,0,11,16,11,15,17,120,2,4,3,0,0,6,5,11,0,15,0,11,1,17,122,2,5,3,0,0,6,25,10,0,16,0,17,117,10,0,16,1,16,2,20,35,4,10,5,16,11,0,1,11,1,1,7,3,39,10,0,15,0,11,0,16,1,16,3,20,11,1,17,119,2,6,3,0,0,6,31,10,0,16,0,17,108,65,38,10,0,16,1,16,4,20,38,4,26,10,0,16,0,17,117,10,0,16,1,16,4,20,36,4,20,5,26,11,0,1,11,1,1,7,3,39,11,0,15,0,11,1,17,121,2,7,3,0,0,46,15,10,0,15,0,11,1,7,1,17,129,1,12,3,11,0,15,0,14,3,9,17,114,11,3,11,2,17,86,2,8,3,0,0,46,15,10,0,15,0,11,1,7,2,17,129,1,12,3,11,0,15,0,14,3,8,17,114,11,3,11,2,17,88,2,9,3,0,0,6,7,11,0,15,0,11,1,11,2,46,17,123,2,10,3,0,0,6,8,11,0,15,0,11,2,46,17,113,11,1,17,87,2,11,3,0,0,6,8,11,0,15,0,11,2,11,1,56,2,11,3,17,118,2,12,3,0,0,18,12,11,1,11,2,10,4,17,49,12,5,11,0,15,0,11,3,11,5,11,4,17,118,2,13,3,0,0,6,20,14,1,17,79,10,2,46,17,64,37,4,8,5,14,11,0,1,11,2,1,7,9,39,11,0,15,0,11,1,11,2,17,124,2,14,3,0,0,6,22,10,0,16,0,10,2,17,115,4,6,5,12,11,0,1,11,1,1,7,4,39,10,0,15,0,11,1,7,0,17,129,1,11,2,11,0,15,5,17,16,2,15,3,0,0,6,10,10,0,15,0,11,1,7,0,17,129,1,11,2,11,0,15,5,17,17,2,16,0,0,0,60,46,14,0,17,107,20,12,5,10,5,10,1,34,4,9,5,13,11,2,1,7,6,39,10,2,14,1,12,3,46,11,3,56,3,32,4,27,11,2,11,1,11,5,56,4,56,5,5,45,11,2,14,1,56,6,12,6,10,6,14,5,12,4,46,11,4,56,7,32,4,43,11,6,11,5,56,8,5,45,11,6,1,2,17,0,0,0,60,50,10,2,14,1,12,3,46,11,3,56,3,4,8,5,12,11,2,1,7,7,39,10,2,14,1,56,6,12,6,14,0,17,107,20,12,5,10,6,14,5,12,4,46,11,4,56,7,4,28,5,34,11,2,1,11,6,1,7,7,39,10,6,14,5,56,9,11,6,46,56,10,4,47,11,2,14,1,56,11,1,1,5,49,11,2,1,2,18,3,0,0,6,8,11,0,15,0,10,1,46,17,113,11,1,17,85,2,19,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,98,2,20,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,96,2,21,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,97,2,22,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,106,2,23,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,99,11,3,46,12,4,11,0,16,0,11,4,17,110,2,24,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,89,2,25,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,101,11,3,46,12,4,11,0,16,0,11,4,17,110,2,26,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,91,2,27,3,0,0,6,7,11,0,15,0,11,2,17,112,11,1,17,102,2,28,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,92,2,29,3,0,0,6,7,11,0,15,0,11,2,17,112,11,1,17,104,2,30,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,94,2,31,3,0,0,76,17,10,0,15,0,11,3,17,112,12,4,10,4,11,1,11,2,17,103,11,4,46,12,5,11,0,16,0,11,5,17,110,2,32,3,0,0,6,8,11,0,15,0,11,3,17,113,11,1,11,2,17,93,2,33,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,105,11,3,46,12,4,11,0,16,0,11,4,17,110,2,34,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,95,2,35,3,0,0,76,16,10,0,15,0,11,2,17,112,12,3,10,3,11,1,17,100,11,3,46,12,4,11,0,16,0,11,4,17,110,2,36,3,0,0,6,7,11,0,15,0,11,2,17,113,11,1,17,90,2,37,3,0,0,79,220,2,10,0,16,6,20,12,37,10,9,10,0,15,6,21,7,12,52,12,28,10,7,10,28,37,4,20,10,8,11,28,37,12,11,5,22,9,12,11,11,11,4,25,5,31,11,0,1,11,10,1,7,8,39,10,0,16,1,16,7,20,6,0,0,0,0,0,0,0,0,36,4,43,6,20,0,0,0,0,0,0,0,10,0,15,1,15,7,21,10,0,15,8,56,12,12,40,13,3,11,40,56,13,1,10,0,15,9,56,12,12,39,13,4,11,39,56,13,1,11,5,10,0,16,10,20,22,12,5,6,0,0,0,0,0,0,0,0,10,0,15,10,21,11,6,10,0,16,11,20,22,12,6,6,0,0,0,0,0,0,0,0,10,0,15,11,21,10,0,16,0,17,126,12,54,10,0,16,12,17,82,12,44,10,44,11,54,22,12,52,14,3,56,14,12,43,14,4,56,14,12,29,10,10,46,17,64,10,0,16,1,16,7,20,38,4,116,11,9,11,37,10,0,16,1,16,13,20,22,38,12,20,5,118,9,12,20,11,20,4,125,10,0,15,14,17,78,12,21,5,127,56,1,12,21,11,21,12,41,14,41,56,14,12,42,13,4,11,41,56,13,1,11,52,53,12,53,10,29,53,12,30,11,44,53,11,30,24,11,53,26,12,48,13,4,10,48,52,56,15,12,47,11,48,11,7,53,24,7,12,26,12,46,13,47,10,46,52,56,15,12,45,10,0,16,15,20,6,1,0,0,0,0,0,0,0,22,10,0,15,15,21,11,1,10,0,16,15,20,33,4,181,1,5,187,1,11,0,1,11,10,1,7,11,39,14,4,56,14,12,32,14,47,56,14,12,50,10,0,15,0,13,4,13,47,10,0,15,5,11,8,10,0,16,1,16,16,20,10,0,16,1,16,17,20,10,0,16,1,16,18,20,11,10,17,109,10,0,16,0,17,126,12,36,14,4,56,14,12,31,14,47,56,14,12,49,11,32,11,31,23,12,33,11,50,11,49,23,12,51,11,2,10,0,15,19,21,10,0,16,0,17,111,10,0,15,20,21,11,47,12,34,13,34,11,4,56,13,1,14,34,56,14,12,35,10,0,15,12,11,3,11,45,11,34,10,5,11,6,17,80,12,38,10,0,16,15,20,12,22,10,0,16,19,20,12,23,10,0,16,20,20,12,24,11,36,12,25,11,43,12,26,11,46,52,12,27,11,5,12,12,10,0,16,12,17,82,12,13,11,42,12,14,11,29,12,15,11,33,11,51,22,12,16,11,35,12,17,11,22,11,23,11,24,11,25,11,27,11,26,11,12,11,13,11,14,11,15,11,16,11,17,18,4,56,16,9,10,0,15,21,21,10,0,16,10,20,6,0,0,0,0,0,0,0,0,33,4,198,2,10,0,16,8,56,14,6,0,0,0,0,0,0,0,0,33,12,18,5,200,2,9,12,18,11,18,4,209,2,11,0,16,9,56,14,6,0,0,0,0,0,0,0,0,33,12,19,5,213,2,11,0,1,9,12,19,11,19,4,216,2,5,218,2,7,10,39,11,38,2,38,3,0,0,6,4,11,0,16,15,20,2,39,3,0,0,6,4,11,0,16,19,20,2,40,3,0,0,6,4,11,0,16,22,20,2,41,3,0,0,6,2,7,3,2,42,3,0,0,6,4,11,0,16,6,20,2,43,3,0,0,6,5,11,0,16,0,11,1,17,128,1,2,44,3,0,0,6,5,11,0,16,0,11,1,17,127,2,45,3,0,0,6,4,11,0,16,0,17,125,2,46,3,0,0,24,18,10,0,16,5,14,1,56,3,4,12,11,0,16,5,14,1,56,17,20,12,2,5,16,11,0,1,56,18,12,2,11,2,2,47,3,0,0,6,4,11,0,16,12,17,82,2,48,3,0,0,6,4,11,0,16,12,17,83,2,49,0,0,0,90,45,13,0,69,91,12,6,13,6,11,0,56,19,11,6,56,2,12,7,14,1,56,20,4,39,11,1,56,21,12,4,13,7,11,4,56,15,12,5,14,7,56,14,6,0,0,0,0,0,0,0,0,36,4,32,11,7,10,2,56,22,11,2,46,17,65,56,23,5,36,11,2,1,11,7,56,24,11,5,12,3,5,43,11,2,1,11,7,12,3,11,3,2,3,3,3,5,1,3,1,4,1,2,3,7,3,14,1,1,3,10,3,11,3,12,3,13,3,4,1,0,3,8,3,0,1,5,1,6,1,7,3,1,3,6,3,9,3,2,0,43,0,111,0],"validator":[161,28,235,11,6,0,0,0,12,1,0,31,2,31,72,3,103,183,4,4,158,5,38,5,196,5,240,3,7,180,9,201,19,8,253,28,96,6,221,29,190,1,10,155,31,156,1,12,183,32,214,27,13,141,60,60,15,201,60,13,0,134,1,1,20,1,23,1,73,1,103,2,21,2,22,2,34,2,71,2,104,2,111,2,131,1,0,101,0,136,1,0,14,4,0,0,13,4,0,0,8,3,0,0,11,3,0,1,9,7,0,3,3,7,1,0,0,4,9,7,0,5,0,12,0,6,1,4,1,0,1,8,2,7,0,9,5,2,0,10,10,2,0,11,12,7,0,12,4,7,0,12,6,8,0,12,7,12,0,13,15,2,0,0,55,0,1,0,0,53,2,3,0,0,26,4,5,0,0,16,4,5,0,0,18,6,5,0,0,86,7,5,0,0,87,7,5,0,0,90,8,5,0,0,89,9,5,0,0,94,9,5,0,0,88,4,5,0,0,93,4,5,0,0,29,10,5,0,0,82,11,5,0,0,46,12,13,0,0,48,12,14,0,0,105,12,15,0,0,49,12,16,0,0,30,12,16,0,0,41,12,17,0,0,83,12,17,0,0,51,12,16,0,0,74,12,16,0,0,79,12,16,0,0,142,1,12,16,0,0,85,12,18,0,0,84,12,18,0,0,52,12,18,0,0,143,1,12,18,0,0,61,12,19,0,0,63,12,19,0,0,64,12,19,0,0,68,12,19,0,0,66,12,20,0,0,65,12,20,0,0,62,12,20,0,0,69,12,20,0,0,72,12,21,0,0,59,12,22,0,0,110,12,22,0,0,98,12,22,0,0,109,12,22,0,0,141,1,12,22,0,0,95,4,5,0,0,75,12,22,0,0,76,12,22,0,0,38,12,22,0,0,25,12,22,0,0,78,23,24,0,0,102,12,25,0,0,42,26,13,0,0,44,27,13,1,0,0,43,28,13,1,0,0,57,11,5,0,0,122,29,5,0,0,120,29,5,0,0,121,29,5,0,0,130,1,29,5,0,0,123,29,5,0,0,113,29,5,0,0,125,29,5,0,0,115,29,5,0,0,126,29,5,0,0,116,29,5,0,0,128,1,29,5,0,0,118,29,5,0,0,127,30,5,0,0,117,30,5,0,0,124,29,5,0,0,114,29,5,0,0,129,1,29,5,0,0,119,29,5,0,0,31,6,5,0,0,132,1,14,5,0,0,133,1,31,5,0,0,54,32,3,0,1,103,31,38,0,2,108,62,31,1,0,3,24,64,62,1,0,3,36,67,51,1,0,3,45,64,13,1,0,3,47,64,13,1,0,3,70,5,34,1,0,3,96,51,34,1,0,4,37,38,35,0,5,53,40,41,0,6,139,1,45,22,1,0,7,32,51,5,1,3,8,40,62,25,1,8,10,33,46,22,0,10,92,46,15,0,11,56,31,39,0,12,17,42,5,0,12,27,42,5,0,12,28,58,5,0,12,46,48,13,0,12,53,40,61,0,12,75,48,22,0,12,76,48,22,0,12,78,60,24,0,12,81,49,5,0,12,82,59,5,0,12,86,47,5,0,12,90,54,22,0,12,97,53,22,0,12,99,53,22,0,12,106,48,22,0,13,57,66,25,0,13,140,1,56,57,0,82,31,82,35,86,44,87,50,87,55,88,61,52,35,52,31,51,35,51,31,80,51,78,51,83,35,83,31,81,35,79,35,81,31,79,31,77,1,14,5,10,2,10,2,10,2,10,2,8,6,8,6,8,12,8,12,8,6,8,6,8,6,8,6,8,7,1,8,0,16,5,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,10,2,3,3,7,8,11,1,8,1,2,7,8,1,3,0,1,7,8,1,4,7,8,1,11,8,1,8,10,5,7,8,11,3,7,8,1,8,14,7,8,11,3,7,8,1,8,16,3,2,7,8,1,11,8,1,8,10,2,7,8,1,7,8,11,1,6,8,1,1,1,1,6,8,0,1,5,1,6,8,6,1,6,8,12,1,6,10,2,1,6,11,5,1,8,6,1,6,11,5,1,10,2,1,6,8,9,1,3,2,6,8,1,3,1,8,13,1,8,9,2,6,8,1,6,8,1,2,6,11,5,1,9,0,6,9,0,2,6,11,5,1,9,0,6,11,5,1,9,0,2,7,8,1,10,2,3,7,8,1,10,2,10,2,1,10,2,4,8,0,3,3,7,8,11,22,5,8,6,8,6,8,6,8,6,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,10,2,11,5,1,8,6,11,5,1,8,6,10,2,11,5,1,8,6,11,5,1,8,6,8,7,10,2,10,2,10,2,8,6,8,6,8,12,8,12,1,11,5,1,9,0,1,8,6,8,1,1,1,1,1,1,1,8,0,1,2,1,8,4,1,8,12,1,7,8,11,1,8,7,2,7,8,15,3,2,3,3,1,8,10,1,6,11,8,1,9,0,1,6,8,11,5,7,8,15,11,8,1,8,10,5,3,7,8,11,1,6,8,15,1,7,8,15,1,8,2,1,9,0,4,3,3,3,3,1,6,8,14,3,7,8,15,8,14,7,8,11,1,8,3,1,6,8,16,1,6,5,2,7,8,15,11,8,1,8,10,2,7,8,15,7,8,11,2,6,8,15,3,1,8,15,1,6,9,0,29,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,6,11,5,1,9,0,2,1,1,2,5,7,8,11,1,7,11,5,1,9,0,3,8,9,8,15,5,3,66,97,103,7,66,97,108,97,110,99,101,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,11,83,116,97,107,105,110,103,80,111,111,108,19,83,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,21,85,110,115,116,97,107,105,110,103,82,101,113,117,101,115,116,69,118,101,110,116,3,85,114,108,9,86,97,108,105,100,97,116,111,114,17,86,97,108,105,100,97,116,111,114,77,101,116,97,100,97,116,97,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,8,97,99,116,105,118,97,116,101,21,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,6,97,109,111,117,110,116,5,97,115,99,105,105,3,98,97,103,7,98,97,108,97,110,99,101,3,98,99,115,6,98,111,114,114,111,119,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,10,100,101,97,99,116,105,118,97,116,101,23,100,101,97,99,116,105,118,97,116,101,95,115,116,97,107,105,110,103,95,112,111,111,108,15,100,101,112,111,115,105,116,95,114,101,119,97,114,100,115,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,11,100,101,115,99,114,105,112,116,105,111,110,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,5,101,112,111,99,104,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,10,102,114,111,109,95,97,115,99,105,105,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,2,105,100,9,105,109,97,103,101,95,117,114,108,12,105,115,95,100,117,112,108,105,99,97,116,101,13,105,115,95,101,113,117,97,108,95,115,111,109,101,23,105,115,95,101,113,117,97,108,95,115,111,109,101,95,97,110,100,95,118,97,108,117,101,7,105,115,95,110,111,110,101,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,8,109,101,116,97,100,97,116,97,4,110,97,109,101,11,110,101,116,95,97,100,100,114,101,115,115,15,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,20,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,3,110,101,119,17,110,101,119,95,102,114,111,109,95,109,101,116,97,100,97,116,97,12,110,101,119,95,109,101,116,97,100,97,116,97,21,110,101,119,95,117,110,115,97,102,101,95,102,114,111,109,95,98,121,116,101,115,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,26,110,101,120,116,95,101,112,111,99,104,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,20,110,101,120,116,95,101,112,111,99,104,95,103,97,115,95,112,114,105,99,101,22,110,101,120,116,95,101,112,111,99,104,95,110,101,116,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,95,98,121,116,101,115,22,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,26,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,32,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,16,110,101,120,116,95,101,112,111,99,104,95,115,116,97,107,101,25,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,11,112,50,112,95,97,100,100,114,101,115,115,20,112,101,110,100,105,110,103,95,115,116,97,107,101,95,97,109,111,117,110,116,29,112,101,110,100,105,110,103,95,115,116,97,107,101,95,119,105,116,104,100,114,97,119,95,97,109,111,117,110,116,7,112,111,111,108,95,105,100,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,15,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,16,112,114,105,110,99,105,112,97,108,95,97,109,111,117,110,116,21,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,11,112,114,111,106,101,99,116,95,117,114,108,19,112,114,111,111,102,95,111,102,95,112,111,115,115,101,115,115,105,111,110,21,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,95,98,121,116,101,115,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,28,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,95,97,116,95,103,101,110,101,115,105,115,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,21,114,101,113,117,101,115,116,95,115,101,116,95,103,97,115,95,112,114,105,99,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,13,114,101,119,97,114,100,95,97,109,111,117,110,116,6,115,101,110,100,101,114,29,115,101,116,95,99,97,110,100,105,100,97,116,101,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,23,115,101,116,95,99,97,110,100,105,100,97,116,101,95,103,97,115,95,112,114,105,99,101,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,111,109,101,22,115,116,97,107,101,95,97,99,116,105,118,97,116,105,111,110,95,101,112,111,99,104,12,115,116,97,107,101,95,97,109,111,117,110,116,17,115,116,97,107,101,100,95,115,117,105,95,97,109,111,117,110,116,14,115,116,97,107,101,114,95,97,100,100,114,101,115,115,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,6,115,116,114,105,110,103,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,11,115,117,105,95,98,97,108,97,110,99,101,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,111,95,98,121,116,101,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,10,116,120,95,99,111,110,116,101,120,116,15,117,110,115,116,97,107,105,110,103,95,101,112,111,99,104,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,28,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,50,112,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,31,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,30,117,112,100,97,116,101,95,99,97,110,100,105,100,97,116,101,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,100,101,115,99,114,105,112,116,105,111,110,16,117,112,100,97,116,101,95,105,109,97,103,101,95,117,114,108,11,117,112,100,97,116,101,95,110,97,109,101,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,97,100,100,114,101,115,115,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,110,101,116,119,111,114,107,95,112,117,98,107,101,121,29,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,50,112,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,105,109,97,114,121,95,97,100,100,114,101,115,115,33,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,112,114,111,116,111,99,111,108,95,112,117,98,107,101,121,32,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,97,100,100,114,101,115,115,31,117,112,100,97,116,101,95,110,101,120,116,95,101,112,111,99,104,95,119,111,114,107,101,114,95,112,117,98,107,101,121,18,117,112,100,97,116,101,95,112,114,111,106,101,99,116,95,117,114,108,3,117,114,108,17,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,21,118,97,108,105,100,97,116,101,95,109,101,116,97,100,97,116,97,95,98,99,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,12,118,111,116,105,110,103,95,112,111,119,101,114,14,119,111,114,107,101,114,95,97,100,100,114,101,115,115,19,119,111,114,107,101,114,95,112,117,98,107,101,121,95,98,121,116,101,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,100,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,3,8,102,0,0,0,0,0,0,0,3,8,208,7,0,0,0,0,0,0,3,8,0,1,0,0,0,0,0,0,3,8,160,134,1,0,0,0,0,0,0,2,22,105,5,85,10,2,52,10,2,143,1,10,2,84,10,2,49,8,6,30,8,6,41,8,12,83,8,12,50,8,6,74,8,6,79,8,6,142,1,8,6,66,11,5,1,10,2,65,11,5,1,10,2,62,11,5,1,10,2,69,11,5,1,10,2,60,11,5,1,8,6,63,11,5,1,8,6,64,11,5,1,8,6,68,11,5,1,8,6,35,8,7,1,2,10,48,8,0,141,1,3,72,8,9,38,3,101,8,15,25,3,67,3,59,3,58,3,35,8,7,2,2,5,77,8,9,135,1,5,100,5,33,3,19,3,3,2,7,77,8,9,135,1,5,100,5,97,3,112,3,80,3,91,3,0,3,0,0,33,68,11,0,12,14,11,1,12,25,11,2,12,29,11,3,12,30,11,4,12,31,11,5,12,32,11,6,12,33,11,7,12,34,11,8,12,35,11,9,12,15,11,10,12,16,11,11,12,17,11,12,12,18,56,0,12,19,56,0,12,20,56,0,12,21,56,0,12,22,56,1,12,23,56,1,12,24,56,1,12,26,56,1,12,27,11,13,12,28,11,14,11,25,11,29,11,30,11,31,11,32,11,33,11,34,11,35,11,15,11,16,11,17,11,18,11,19,11,22,11,20,11,21,11,23,11,24,11,26,11,27,11,28,18,0,2,1,3,0,0,36,137,1,14,9,65,37,7,17,37,4,11,14,10,65,37,7,17,37,12,16,5,13,9,12,16,11,16,4,21,14,11,65,37,7,17,37,12,17,5,23,9,12,17,11,17,4,31,14,12,65,37,7,17,37,12,18,5,33,9,12,18,11,18,4,41,14,5,65,37,7,17,37,12,19,5,43,9,12,19,11,19,4,51,14,6,65,37,7,17,37,12,20,5,53,9,12,20,11,20,4,61,14,7,65,37,7,17,37,12,21,5,63,9,12,21,11,21,4,71,14,8,65,37,7,17,37,12,22,5,73,9,12,22,11,22,4,76,5,80,11,15,1,7,9,39,10,14,7,16,37,4,85,5,89,11,15,1,7,8,39,10,13,7,18,35,4,94,5,98,11,15,1,7,15,39,11,0,11,1,11,2,11,3,11,4,11,5,17,76,17,84,11,6,17,76,17,84,11,7,17,91,11,8,17,91,11,9,17,76,17,84,11,10,17,76,17,84,11,11,17,76,17,84,11,12,17,76,17,84,10,15,17,85,17,0,12,23,14,23,17,73,11,23,11,13,11,14,11,15,17,75,2,2,3,0,0,5,5,11,0,15,0,11,1,17,93,2,3,3,0,0,5,5,11,0,15,0,11,1,17,92,2,4,3,0,0,5,13,10,0,16,1,20,10,0,15,2,21,10,0,16,3,20,11,0,15,4,21,2,5,3,0,0,43,57,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,8,5,14,11,0,1,11,3,1,7,11,39,10,3,46,17,89,6,1,0,0,0,0,0,0,0,22,12,5,10,0,15,0,11,1,10,2,11,5,10,3,17,102,10,0,16,0,17,95,4,34,10,0,15,0,17,100,10,0,16,5,20,10,4,22,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,11,2,11,3,46,17,89,11,4,18,2,56,3,2,6,3,0,0,22,46,10,3,46,17,89,6,0,0,0,0,0,0,0,0,33,4,7,5,13,11,0,1,11,3,1,7,12,39,14,1,56,2,12,4,10,4,6,0,0,0,0,0,0,0,0,36,4,21,5,27,11,0,1,11,3,1,7,11,39,10,0,15,0,11,1,11,2,6,0,0,0,0,0,0,0,0,11,3,17,102,10,0,15,0,17,100,10,0,16,5,20,11,4,22,11,0,15,5,21,2,7,3,0,0,52,43,14,1,17,105,12,3,14,1,17,104,12,5,10,0,15,0,11,1,10,2,17,103,12,6,10,6,10,3,23,12,4,10,0,16,5,20,11,6,23,10,0,15,5,21,10,0,46,17,49,11,0,16,6,16,7,20,10,2,46,17,90,11,5,11,2,46,17,89,11,3,11,4,18,3,56,4,2,8,3,0,0,5,28,10,2,7,18,35,4,5,5,9,11,0,1,7,15,39,14,1,17,108,20,10,0,16,6,16,7,20,33,4,19,5,23,11,0,1,7,14,39,11,2,11,0,15,1,21,2,9,3,0,0,5,41,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,2,7,18,35,4,14,5,18,11,0,1,7,15,39,14,1,17,108,20,10,0,16,6,16,7,20,33,4,28,5,32,11,0,1,7,14,39,10,2,10,0,15,1,21,11,2,11,0,15,2,21,2,10,3,0,0,5,14,10,1,7,16,37,4,5,5,9,11,0,1,7,8,39,11,1,11,0,15,3,21,2,11,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,10,1,7,16,37,4,14,5,18,11,0,1,7,8,39,11,1,11,0,15,4,21,2,12,3,0,0,5,14,10,0,16,5,20,14,1,56,2,22,10,0,15,5,21,11,0,15,0,11,1,17,94,2,13,3,0,0,5,16,10,0,15,0,11,1,17,101,10,0,46,17,40,11,0,16,5,20,33,4,13,5,15,7,11,39,2,14,1,0,0,5,4,11,0,16,0,17,95,2,15,1,0,0,5,3,11,0,16,6,2,16,1,0,0,5,5,11,0,16,6,16,7,20,2,17,1,0,0,5,4,11,0,16,6,16,8,2,18,1,0,0,5,4,11,0,16,6,16,9,2,19,1,0,0,5,4,11,0,16,6,16,10,2,20,1,0,0,5,4,11,0,16,6,16,11,2,21,1,0,0,5,4,11,0,16,6,16,12,2,22,1,0,0,5,4,11,0,16,6,16,13,2,23,1,0,0,5,4,11,0,16,6,16,14,2,24,1,0,0,5,4,11,0,16,6,16,15,2,25,1,0,0,5,4,11,0,16,6,16,16,2,26,1,0,0,5,4,11,0,16,6,16,17,2,27,1,0,0,5,4,11,0,16,6,16,18,2,28,1,0,0,5,4,11,0,16,6,16,19,2,29,1,0,0,5,4,11,0,16,6,16,20,2,30,1,0,0,5,4,11,0,16,6,16,21,2,31,1,0,0,5,4,11,0,16,6,16,22,2,32,1,0,0,5,4,11,0,16,6,16,23,2,33,1,0,0,5,4,11,0,16,6,16,24,2,34,1,0,0,5,4,11,0,16,6,16,25,2,35,1,0,0,5,4,11,0,16,6,16,26,2,36,1,0,0,5,4,11,0,16,6,16,27,2,37,1,0,0,5,3,11,0,16,28,2,38,1,0,0,5,4,11,0,16,1,20,2,39,1,0,0,5,5,40,11,0,16,0,17,106,2,40,1,0,0,5,4,11,0,16,0,17,106,2,41,1,0,0,5,3,11,0,17,40,2,42,1,0,0,5,4,11,0,16,29,20,2,43,3,0,0,5,5,11,1,11,0,15,29,21,2,44,1,0,0,5,4,11,0,16,0,17,97,2,45,1,0,0,5,4,11,0,16,0,17,98,2,46,1,0,0,5,4,11,0,16,2,20,2,47,1,0,0,5,4,11,0,16,4,20,2,48,1,0,0,5,5,11,0,16,0,11,1,17,99,2,49,1,0,0,5,4,11,0,16,0,56,5,2,50,1,0,0,63,151,3,10,0,16,6,16,7,20,10,1,16,6,16,7,20,33,4,13,8,12,2,5,23,10,0,16,6,16,8,20,10,1,16,6,16,8,20,33,12,2,11,2,4,28,8,12,13,5,38,10,0,16,6,16,12,20,10,1,16,6,16,12,20,33,12,13,11,13,4,43,8,12,24,5,53,10,0,16,6,16,13,20,10,1,16,6,16,13,20,33,12,24,11,24,4,58,8,12,25,5,68,10,0,16,6,16,16,20,10,1,16,6,16,16,20,33,12,25,11,25,4,73,8,12,26,5,83,10,0,16,6,16,18,20,10,1,16,6,16,18,20,33,12,26,11,26,4,88,8,12,27,5,98,10,0,16,6,16,18,20,10,1,16,6,16,19,20,33,12,27,11,27,4,103,8,12,28,5,113,10,0,16,6,16,19,20,10,1,16,6,16,19,20,33,12,28,11,28,4,118,8,12,29,5,128,1,10,0,16,6,16,19,20,10,1,16,6,16,18,20,33,12,29,11,29,4,133,1,8,12,30,5,141,1,10,0,16,6,16,20,10,1,16,6,16,20,56,6,12,30,11,30,4,146,1,8,12,3,5,154,1,10,0,16,6,16,21,10,1,16,6,16,21,56,6,12,3,11,3,4,159,1,8,12,4,5,167,1,10,0,16,6,16,24,10,1,16,6,16,24,56,7,12,4,11,4,4,172,1,8,12,5,5,180,1,10,0,16,6,16,26,10,1,16,6,16,26,56,7,12,5,11,5,4,185,1,8,12,6,5,193,1,10,0,16,6,16,26,10,1,16,6,16,27,56,7,12,6,11,6,4,198,1,8,12,7,5,206,1,10,0,16,6,16,27,10,1,16,6,16,27,56,7,12,7,11,7,4,211,1,8,12,8,5,219,1,10,0,16,6,16,27,10,1,16,6,16,26,56,7,12,8,11,8,4,224,1,8,12,9,5,232,1,10,0,16,6,16,20,10,1,16,6,16,12,56,8,12,9,11,9,4,237,1,8,12,10,5,245,1,10,0,16,6,16,21,10,1,16,6,16,13,56,8,12,10,11,10,4,250,1,8,12,11,5,130,2,10,0,16,6,16,24,10,1,16,6,16,16,56,9,12,11,11,11,4,135,2,8,12,12,5,143,2,10,0,16,6,16,26,10,1,16,6,16,18,56,9,12,12,11,12,4,148,2,8,12,14,5,156,2,10,0,16,6,16,26,10,1,16,6,16,19,56,9,12,14,11,14,4,161,2,8,12,15,5,169,2,10,0,16,6,16,27,10,1,16,6,16,19,56,9,12,15,11,15,4,174,2,8,12,16,5,182,2,10,0,16,6,16,27,10,1,16,6,16,18,56,9,12,16,11,16,4,187,2,8,12,17,5,195,2,10,1,16,6,16,20,10,0,16,6,16,12,56,8,12,17,11,17,4,200,2,8,12,18,5,208,2,10,1,16,6,16,21,10,0,16,6,16,13,56,8,12,18,11,18,4,213,2,8,12,19,5,221,2,10,1,16,6,16,24,10,0,16,6,16,16,56,9,12,19,11,19,4,226,2,8,12,20,5,234,2,10,1,16,6,16,26,10,0,16,6,16,18,56,9,12,20,11,20,4,239,2,8,12,21,5,247,2,10,1,16,6,16,26,10,0,16,6,16,19,56,9,12,21,11,21,4,252,2,8,12,22,5,132,3,10,1,16,6,16,27,10,0,16,6,16,19,56,9,12,22,11,22,4,141,3,11,0,1,11,1,1,8,12,23,5,149,3,11,1,16,6,16,27,11,0,16,6,16,18,56,9,12,23,11,23,2,51,0,0,0,13,17,10,0,56,10,4,10,11,1,1,11,0,1,9,12,2,5,15,11,0,56,11,11,1,33,12,2,11,2,2,52,0,0,0,65,26,10,0,56,10,4,6,8,12,2,5,9,10,1,56,10,12,2,11,2,4,18,11,1,1,11,0,1,9,12,3,5,24,11,0,56,11,11,1,56,11,33,12,3,11,3,2,53,3,0,0,15,25,10,1,46,17,90,12,2,10,2,10,0,16,6,16,7,20,33,4,12,5,18,11,0,1,11,1,1,7,13,39,11,2,11,1,17,107,11,0,15,28,21,2,54,3,0,0,5,18,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,11,0,15,6,15,8,21,2,55,3,0,0,5,18,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,11,0,15,6,15,9,21,2,56,3,0,0,5,17,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,91,11,0,15,6,15,10,21,2,57,3,0,0,5,17,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,91,11,0,15,6,15,11,21,2,58,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,20,21,11,0,16,6,17,73,2,59,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,12,21,11,0,16,6,17,73,2,60,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,21,21,11,0,16,6,17,73,2,61,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,13,21,11,0,16,6,17,73,2,62,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,22,21,11,0,16,6,17,73,2,63,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,14,21,11,0,16,6,17,73,2,64,3,0,0,5,22,14,1,65,37,7,17,37,4,6,5,10,11,0,1,7,9,39,11,1,17,76,17,84,56,12,10,0,15,6,15,23,21,11,0,16,6,17,73,2,65,3,0,0,5,30,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,14,1,65,37,7,17,37,4,15,5,19,11,0,1,7,9,39,11,1,17,76,17,84,10,0,15,6,15,15,21,11,0,16,6,17,73,2,66,3,0,0,5,16,11,1,56,13,10,0,15,6,15,24,21,11,2,56,13,10,0,15,6,15,25,21,11,0,16,6,17,73,2,67,3,0,0,5,23,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,16,21,11,2,10,0,15,6,15,17,21,11,0,16,6,17,73,2,68,3,0,0,5,10,11,1,56,13,10,0,15,6,15,26,21,11,0,16,6,17,73,2,69,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,18,21,11,0,16,6,17,73,2,70,3,0,0,5,10,11,1,56,13,10,0,15,6,15,27,21,11,0,16,6,17,73,2,71,3,0,0,5,18,10,0,46,17,14,4,5,5,9,11,0,1,7,10,39,11,1,10,0,15,6,15,19,21,11,0,16,6,17,73,2,72,3,0,0,5,143,1,10,0,46,17,29,56,14,4,18,10,0,15,6,15,20,56,15,10,0,15,6,15,12,21,56,1,10,0,15,6,15,20,21,10,0,46,17,30,56,14,4,36,10,0,15,6,15,21,56,15,10,0,15,6,15,13,21,56,1,10,0,15,6,15,21,21,10,0,46,17,31,56,14,4,54,10,0,15,6,15,22,56,15,10,0,15,6,15,14,21,56,1,10,0,15,6,15,22,21,10,0,46,17,32,56,14,4,72,10,0,15,6,15,23,56,15,10,0,15,6,15,15,21,56,1,10,0,15,6,15,23,21,10,0,46,17,33,56,16,4,103,10,0,15,6,15,24,56,17,10,0,15,6,15,16,21,56,0,10,0,15,6,15,24,21,10,0,15,6,15,25,56,17,10,0,15,6,15,17,21,56,0,10,0,15,6,15,25,21,10,0,46,17,35,56,16,4,121,10,0,15,6,15,26,56,17,10,0,15,6,15,18,21,56,0,10,0,15,6,15,26,21,10,0,46,17,36,56,16,4,140,1,10,0,15,6,15,27,56,17,10,0,15,6,15,19,21,56,0,11,0,15,6,15,27,21,5,142,1,11,0,1,2,73,1,0,0,5,4,11,0,56,18,17,74,2,74,1,2,0,75,0,0,0,68,24,14,0,16,7,20,12,6,10,3,17,96,12,5,11,6,10,3,17,107,12,4,11,0,6,0,0,0,0,0,0,0,0,11,4,10,1,11,5,10,2,6,0,0,0,0,0,0,0,0,11,1,11,2,11,3,17,85,18,1,2,1,4,1,7,1,3,1,8,1,5,1,6,1,0,0,0,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,1,0,4,0,2,0,3,0,17,0,18,0,19,0,20,0,13,0,14,0,15,0,16,1,2,1,1,0,39,0,107,0,137,1,0,138,1,0,141,1,0],"validator_cap":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,20,3,28,42,4,70,4,5,74,54,7,128,1,226,2,8,226,3,64,6,162,4,34,10,196,4,13,12,209,4,112,13,193,5,4,15,197,5,6,0,18,1,10,1,14,1,15,0,3,12,0,0,4,2,0,1,0,7,0,1,2,4,0,3,1,2,0,0,16,0,1,0,0,20,2,1,0,0,9,3,4,0,0,8,0,5,0,1,6,13,4,1,8,1,7,10,11,0,2,11,14,6,1,12,3,12,8,9,0,4,12,6,12,1,6,8,0,1,6,5,1,6,8,1,2,5,7,8,4,1,8,2,1,8,1,0,4,1,8,0,8,2,5,1,6,8,4,1,5,1,7,8,4,1,8,3,1,8,0,1,6,9,0,2,9,0,5,2,73,68,9,84,120,67,111,110,116,101,120,116,3,85,73,68,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,28,97,117,116,104,111,114,105,122,101,114,95,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,2,105,100,3,110,101,119,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,51,110,101,119,95,117,110,118,101,114,105,102,105,101,100,95,118,97,108,105,100,97,116,111,114,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,110,100,95,116,114,97,110,115,102,101,114,6,111,98,106,101,99,116,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,115,101,110,100,101,114,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,6,8,3,5,5,1,2,1,5,5,0,3,0,0,6,3,11,0,16,0,2,1,3,0,0,6,3,11,0,16,1,2,2,3,0,0,7,35,10,1,46,17,7,12,5,10,5,7,0,33,4,11,8,12,2,5,15,11,5,10,0,33,12,2,11,2,4,18,5,22,11,1,1,6,0,0,0,0,0,0,0,0,39,11,1,17,5,10,0,18,0,12,3,14,3,56,0,12,4,11,3,11,0,56,1,11,4,2,3,3,0,0,6,5,11,0,16,0,20,18,1,2,0,1,1,0,0,13,0,17,0,19,0],"validator_set":[161,28,235,11,6,0,0,0,12,1,0,51,2,51,112,3,163,1,134,6,4,169,7,133,1,5,174,8,210,9,7,128,18,183,23,8,183,41,96,6,151,42,195,1,10,218,43,141,1,12,231,44,251,34,13,226,79,16,15,242,79,5,0,159,1,1,103,1,167,1,2,30,2,31,2,57,2,101,2,113,2,141,1,2,145,1,2,146,1,2,152,1,2,165,1,2,166,1,0,137,1,0,155,1,0,158,1,0,163,1,0,170,1,0,19,4,0,0,14,3,0,0,15,3,0,0,16,3,0,0,17,3,0,1,4,7,1,0,0,3,0,12,0,4,1,4,1,0,1,6,3,7,0,7,2,6,1,2,0,7,6,6,1,2,0,8,7,2,0,9,9,12,2,7,1,4,1,10,10,4,1,4,1,11,11,2,0,12,21,7,2,1,0,0,0,13,22,7,1,3,0,14,5,7,0,14,8,8,0,15,13,4,0,16,12,12,0,16,18,2,0,17,20,4,0,0,96,0,1,0,0,124,2,3,0,0,126,4,3,0,0,123,5,3,0,0,28,6,3,0,0,125,4,3,0,0,122,7,3,0,0,128,1,8,3,0,0,127,9,3,0,0,27,10,3,0,0,154,1,11,3,0,0,52,12,3,0,0,47,13,14,0,0,149,1,13,14,0,0,162,1,15,14,0,0,160,1,15,14,0,0,161,1,15,16,0,0,139,1,13,17,0,0,99,13,14,0,0,81,15,18,0,0,84,6,18,0,0,83,19,18,0,0,43,19,14,0,0,85,6,18,0,0,42,20,14,0,0,68,21,22,0,0,60,23,24,0,0,61,25,24,0,0,71,26,27,0,0,72,28,22,0,0,65,29,22,0,0,75,30,22,0,0,73,31,22,0,0,74,31,22,0,0,76,23,32,0,0,66,33,32,0,0,67,15,32,0,0,70,15,32,0,0,169,1,34,35,0,0,114,36,3,0,0,117,37,3,0,0,35,38,3,0,0,116,39,3,0,0,133,1,40,3,0,0,115,41,3,0,0,34,42,14,0,0,26,43,3,0,0,38,44,45,0,0,39,46,47,0,0,40,48,49,0,0,37,50,49,0,0,51,51,3,0,0,54,52,3,0,0,144,1,26,14,0,0,24,13,42,0,0,90,15,18,0,0,87,53,18,0,1,49,111,81,1,0,1,59,80,81,1,0,1,89,79,18,1,0,1,100,3,111,1,0,1,132,1,81,111,1,0,2,41,82,18,1,0,2,86,125,18,1,0,2,121,97,81,1,0,3,96,56,66,0,4,50,148,1,3,1,0,4,92,149,1,14,1,0,4,134,1,147,1,148,1,1,0,4,164,1,84,14,1,0,5,53,81,3,1,3,6,77,110,16,1,8,7,96,103,104,1,2,7,97,101,102,1,2,7,112,105,101,1,2,9,25,60,3,2,7,4,9,32,68,87,2,7,4,9,33,73,89,2,7,4,9,41,68,18,2,7,4,9,96,56,57,2,7,4,9,121,73,74,2,7,4,10,32,109,110,1,4,10,33,114,115,1,4,10,55,56,61,1,4,10,86,106,18,1,4,10,94,106,14,1,4,10,111,135,1,81,1,4,10,118,77,3,1,4,11,56,72,14,0,11,129,1,72,59,0,12,41,93,18,2,1,0,12,55,3,65,2,1,0,12,64,93,87,2,1,0,12,69,94,89,2,1,0,12,79,96,3,2,1,0,12,86,130,1,18,2,1,0,12,93,130,1,131,1,2,1,0,12,110,142,1,95,2,1,0,12,121,94,95,2,1,0,12,131,1,130,1,14,2,1,0,13,41,132,1,18,1,3,13,80,143,1,131,1,1,3,13,86,134,1,18,1,3,13,121,133,1,3,1,3,14,106,86,16,0,15,23,75,3,0,15,26,22,3,0,15,36,32,14,0,15,45,75,3,0,15,46,150,1,3,0,15,52,22,3,0,15,62,32,14,0,15,82,108,18,0,15,88,32,18,0,15,102,32,123,0,15,109,152,1,153,1,0,15,115,138,1,3,0,15,122,85,3,0,15,127,75,3,0,15,128,1,88,3,0,15,136,1,32,14,0,15,138,1,32,16,0,15,142,1,32,59,0,15,150,1,32,14,0,15,170,1,32,14,0,16,98,121,35,0,16,153,1,121,117,0,16,168,1,116,117,0,17,44,69,70,0,17,48,70,58,0,17,95,90,22,0,18,119,3,14,0,18,130,1,43,3,0,18,151,1,3,14,0,79,55,75,55,83,58,79,62,79,63,91,64,78,63,75,63,80,63,80,55,75,62,87,58,59,14,58,14,62,14,69,83,78,55,76,55,78,62,77,62,90,64,98,64,93,64,94,64,64,58,73,14,72,14,74,14,85,58,81,58,77,63,61,14,60,14,57,14,82,58,71,122,63,14,70,127,90,129,1,98,129,1,96,129,1,93,129,1,100,59,103,59,102,59,84,58,86,58,70,136,1,91,98,94,98,95,129,1,97,129,1,101,59,99,98,90,98,92,98,68,83,67,83,66,83,92,129,1,62,59,70,154,1,2,10,8,19,7,8,14,1,8,0,3,7,8,0,8,19,7,8,14,0,2,7,8,0,7,8,14,3,7,8,0,3,7,8,14,2,6,8,0,6,8,19,4,7,8,0,5,11,7,1,8,11,7,8,14,3,7,8,0,8,18,7,8,14,3,7,8,0,3,6,8,14,9,7,8,0,7,11,7,1,8,11,7,11,7,1,8,11,7,11,15,2,5,11,16,1,5,3,3,3,3,7,8,14,6,7,8,0,3,3,3,7,11,15,2,5,11,16,1,5,7,8,14,1,7,8,0,1,6,8,0,1,3,2,6,8,0,5,1,8,8,1,6,11,12,2,8,8,5,1,1,2,6,10,8,19,6,8,19,2,6,11,13,1,8,19,6,8,19,2,7,8,0,5,1,7,8,19,2,6,10,8,19,5,1,11,5,1,3,2,6,11,13,1,8,19,5,2,6,10,8,19,6,10,5,1,10,3,2,7,10,8,19,5,3,7,8,0,5,1,3,7,8,0,6,8,21,1,2,7,8,0,6,8,14,1,6,8,19,3,7,8,0,5,2,3,7,8,0,6,8,20,2,1,8,21,3,7,8,0,7,11,15,2,5,11,16,1,5,7,8,14,5,7,8,0,8,19,7,11,15,2,5,11,16,1,5,1,7,8,14,2,7,11,15,2,5,11,16,1,5,5,2,7,8,0,3,1,7,10,3,2,7,10,8,19,7,8,14,1,6,10,8,19,1,7,10,8,19,4,10,3,3,6,10,3,6,10,3,4,3,11,15,2,3,3,3,11,15,2,3,3,2,6,8,0,11,15,2,5,11,16,1,5,1,10,5,4,6,10,8,19,3,3,3,2,10,3,10,3,9,6,10,8,19,3,3,10,3,10,3,3,11,15,2,3,3,3,11,15,2,3,3,6,7,10,8,19,6,10,3,6,10,3,7,11,7,1,8,11,7,11,7,1,8,11,7,8,14,6,3,6,10,8,19,6,10,3,6,10,3,6,11,15,2,5,11,16,1,5,6,10,5,2,6,8,0,8,8,6,3,3,11,12,2,8,8,5,3,6,8,19,8,0,2,8,8,5,1,7,8,14,1,11,12,2,9,0,9,1,1,8,19,1,5,3,7,11,12,2,9,0,9,1,9,0,9,1,1,11,13,1,9,0,2,8,8,8,22,2,5,8,22,2,5,3,1,11,15,2,9,0,9,1,1,8,6,4,6,8,19,6,8,19,1,5,2,6,11,12,2,9,0,9,1,9,0,2,8,19,7,8,14,1,8,22,3,8,8,8,19,5,1,6,8,14,2,7,11,12,2,9,0,9,1,9,0,1,9,1,2,7,8,19,3,5,6,8,19,6,8,19,1,8,19,5,2,7,11,13,1,9,0,9,0,3,5,3,11,5,1,3,1,6,11,5,1,9,0,1,7,11,5,1,9,0,1,9,0,2,6,10,9,0,6,9,0,1,8,11,1,6,11,7,1,9,0,4,7,8,19,11,7,1,8,11,5,7,8,14,1,6,8,18,1,6,9,1,3,7,8,19,8,18,7,8,14,1,7,9,1,1,7,8,22,14,11,15,2,5,11,16,1,5,6,10,5,10,3,10,3,11,15,2,3,3,11,15,2,3,3,3,10,5,3,3,3,3,10,3,10,3,8,3,3,7,3,3,8,19,8,19,5,6,8,19,2,6,11,15,2,9,0,9,1,6,9,0,2,7,11,15,2,9,0,9,1,6,9,0,2,9,0,9,1,3,7,11,15,2,9,0,9,1,9,0,9,1,2,7,10,9,0,3,2,3,3,10,10,11,9,1,3,3,3,11,10,1,3,3,3,3,3,6,8,19,6,10,8,19,1,11,9,1,3,2,3,9,0,1,11,9,1,9,0,1,10,11,9,1,9,0,1,11,10,1,9,0,1,7,11,10,1,9,0,1,6,11,13,1,9,0,3,3,3,3,2,6,8,19,6,8,19,2,6,11,13,1,9,0,3,1,6,9,0,1,11,5,1,9,0,5,5,3,11,5,1,3,3,10,3,4,3,3,11,5,1,3,11,5,1,3,2,7,11,13,1,9,0,3,1,7,9,0,1,6,8,21,1,6,5,2,3,11,5,1,3,6,1,1,3,3,11,5,1,3,11,5,1,3,5,5,6,8,19,8,8,5,6,8,19,1,6,8,20,1,8,20,1,6,8,8,2,3,8,19,1,6,10,9,0,3,3,5,8,8,1,8,4,7,6,5,6,5,3,3,6,5,10,5,7,11,16,1,5,2,5,11,16,1,5,1,6,11,15,2,9,0,9,1,1,10,9,0,2,6,11,16,1,9,0,6,9,0,2,7,11,16,1,9,0,6,9,0,1,6,11,16,1,9,0,1,7,11,13,1,9,0,1,8,3,6,3,3,3,3,3,3,2,7,8,19,7,8,14,4,3,3,3,6,8,19,7,11,15,2,3,3,11,15,2,3,3,4,4,3,3,3,5,10,5,6,10,8,19,11,16,1,5,10,5,5,1,7,11,15,2,9,0,9,1,1,11,16,1,9,0,6,3,3,4,10,3,10,3,3,17,3,3,3,10,3,3,10,3,3,4,3,3,3,3,3,3,3,3,4,8,3,3,11,7,1,8,11,3,7,8,19,5,4,11,7,1,8,11,2,7,11,7,1,9,0,3,1,11,7,1,9,0,2,7,11,7,1,9,0,11,7,1,9,0,2,7,8,19,11,7,1,8,11,8,10,5,3,3,3,3,10,5,6,8,19,5,2,6,8,19,3,1,8,17,1,8,2,3,66,97,103,7,66,97,108,97,110,99,101,5,69,110,116,114,121,2,73,68,6,79,112,116,105,111,110,21,80,111,111,108,84,111,107,101,110,69,120,99,104,97,110,103,101,82,97,116,101,13,80,114,105,111,114,105,116,121,81,117,101,117,101,3,83,85,73,9,83,116,97,107,101,100,83,117,105,5,84,97,98,108,101,8,84,97,98,108,101,86,101,99,9,84,120,67,111,110,116,101,120,116,31,85,110,118,101,114,105,102,105,101,100,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,9,86,97,108,105,100,97,116,111,114,23,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,25,86,97,108,105,100,97,116,111,114,69,112,111,99,104,73,110,102,111,69,118,101,110,116,86,50,18,86,97,108,105,100,97,116,111,114,74,111,105,110,69,118,101,110,116,19,86,97,108,105,100,97,116,111,114,76,101,97,118,101,69,118,101,110,116,21,86,97,108,105,100,97,116,111,114,79,112,101,114,97,116,105,111,110,67,97,112,12,86,97,108,105,100,97,116,111,114,83,101,116,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,6,86,101,99,77,97,112,6,86,101,99,83,101,116,8,97,99,116,105,118,97,116,101,17,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,3,97,100,100,26,97,100,106,117,115,116,95,115,116,97,107,101,95,97,110,100,95,103,97,115,95,112,114,105,99,101,13,97,100,118,97,110,99,101,95,101,112,111,99,104,38,97,115,115,101,114,116,95,110,111,95,112,101,110,100,105,110,103,95,111,114,95,97,99,116,105,118,101,95,100,117,112,108,105,99,97,116,101,115,18,97,116,95,114,105,115,107,95,118,97,108,105,100,97,116,111,114,115,3,98,97,103,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,22,99,97,108,99,117,108,97,116,101,95,116,111,116,97,108,95,115,116,97,107,101,115,38,99,108,101,97,110,95,114,101,112,111,114,116,95,114,101,99,111,114,100,115,95,108,101,97,118,105,110,103,95,118,97,108,105,100,97,116,111,114,15,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,36,99,111,109,112,117,116,101,95,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,26,99,111,109,112,117,116,101,95,114,101,119,97,114,100,95,97,100,106,117,115,116,109,101,110,116,115,26,99,111,109,112,117,116,101,95,115,108,97,115,104,101,100,95,118,97,108,105,100,97,116,111,114,115,38,99,111,109,112,117,116,101,95,117,110,97,100,106,117,115,116,101,100,95,114,101,119,97,114,100,95,100,105,115,116,114,105,98,117,116,105,111,110,8,99,111,110,116,97,105,110,115,25,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,116,97,98,108,101,118,101,99,20,99,111,117,110,116,95,100,117,112,108,105,99,97,116,101,115,95,118,101,99,9,99,114,101,97,116,101,95,118,49,10,100,101,97,99,116,105,118,97,116,101,21,100,101,112,111,115,105,116,95,115,116,97,107,101,95,114,101,119,97,114,100,115,26,100,101,114,105,118,101,95,114,101,102,101,114,101,110,99,101,95,103,97,115,95,112,114,105,99,101,7,100,101,115,116,114,111,121,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,17,100,105,115,116,114,105,98,117,116,101,95,114,101,119,97,114,100,26,101,102,102,101,99,116,117,97,116,101,95,115,116,97,103,101,100,95,109,101,116,97,100,97,116,97,4,101,109,105,116,27,101,109,105,116,95,118,97,108,105,100,97,116,111,114,95,101,112,111,99,104,95,101,118,101,110,116,115,5,101,109,112,116,121,5,101,112,111,99,104,5,101,118,101,110,116,12,101,120,116,114,97,95,102,105,101,108,100,115,7,101,120,116,114,97,99,116,14,102,105,110,100,95,118,97,108,105,100,97,116,111,114,29,102,105,110,100,95,118,97,108,105,100,97,116,111,114,95,102,114,111,109,95,116,97,98,108,101,95,118,101,99,9,103,97,115,95,112,114,105,99,101,7,103,101,110,101,115,105,115,3,103,101,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,48,103,101,116,95,97,99,116,105,118,101,95,111,114,95,112,101,110,100,105,110,103,95,111,114,95,99,97,110,100,105,100,97,116,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,24,103,101,116,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,114,101,102,37,103,101,116,95,99,97,110,100,105,100,97,116,101,95,111,114,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,109,117,116,7,103,101,116,95,109,117,116,25,103,101,116,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,95,114,101,102,21,103,101,116,95,118,97,108,105,100,97,116,111,114,95,105,110,100,105,99,101,115,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,26,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,47,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,99,116,120,95,105,110,99,108,117,100,105,110,103,95,99,97,110,100,105,100,97,116,101,115,35,103,101,116,95,118,97,108,105,100,97,116,111,114,95,109,117,116,95,119,105,116,104,95,118,101,114,105,102,105,101,100,95,99,97,112,17,103,101,116,95,118,97,108,105,100,97,116,111,114,95,114,101,102,2,105,100,19,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,6,105,110,115,101,114,116,9,105,110,116,111,95,107,101,121,115,34,105,115,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,95,98,121,95,115,117,105,95,97,100,100,114,101,115,115,12,105,115,95,100,117,112,108,105,99,97,116,101,22,105,115,95,100,117,112,108,105,99,97,116,101,95,118,97,108,105,100,97,116,111,114,34,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,35,105,115,95,100,117,112,108,105,99,97,116,101,95,119,105,116,104,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,8,105,115,95,101,109,112,116,121,21,105,115,95,105,110,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,12,105,115,95,112,114,101,97,99,116,105,118,101,7,105,115,95,115,111,109,101,22,105,115,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,12,105,115,95,118,111,108,117,110,116,97,114,121,4,106,111,105,110,4,107,101,121,115,6,108,101,110,103,116,104,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,3,110,101,119,9,110,101,119,95,101,110,116,114,121,19,110,101,119,95,102,114,111,109,95,117,110,118,101,114,105,102,105,101,100,26,110,101,120,116,95,101,112,111,99,104,95,118,97,108,105,100,97,116,111,114,95,99,111,117,110,116,4,110,111,110,101,6,111,98,106,101,99,116,16,111,112,101,114,97,116,105,111,110,95,99,97,112,95,105,100,6,111,112,116,105,111,110,25,112,101,110,100,105,110,103,95,97,99,116,105,118,101,95,118,97,108,105,100,97,116,111,114,115,16,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,7,112,111,111,108,95,105,100,19,112,111,111,108,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,24,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,33,112,111,111,108,95,116,111,107,101,110,95,101,120,99,104,97,110,103,101,95,114,97,116,101,95,97,116,95,101,112,111,99,104,3,112,111,112,8,112,111,112,95,98,97,99,107,7,112,111,112,95,109,97,120,14,112,114,105,111,114,105,116,121,95,113,117,101,117,101,24,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,114,101,109,111,118,97,108,115,36,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,115,116,97,107,101,115,95,97,110,100,95,119,105,116,104,100,114,97,119,115,26,112,114,111,99,101,115,115,95,112,101,110,100,105,110,103,95,118,97,108,105,100,97,116,111,114,115,27,112,114,111,99,101,115,115,95,118,97,108,105,100,97,116,111,114,95,100,101,112,97,114,116,117,114,101,9,112,117,115,104,95,98,97,99,107,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,26,114,101,102,101,114,101,110,99,101,95,103,97,115,95,115,117,114,118,101,121,95,113,117,111,116,101,6,114,101,109,111,118,101,17,114,101,113,117,101,115,116,95,97,100,100,95,115,116,97,107,101,21,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,31,114,101,113,117,101,115,116,95,97,100,100,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,24,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,34,114,101,113,117,101,115,116,95,114,101,109,111,118,101,95,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,27,114,101,113,117,101,115,116,95,115,101,116,95,99,111,109,109,105,115,115,105,111,110,95,114,97,116,101,22,114,101,113,117,101,115,116,95,119,105,116,104,100,114,97,119,95,115,116,97,107,101,6,115,101,110,100,101,114,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,4,115,105,122,101,4,115,111,109,101,17,115,111,114,116,95,114,101,109,111,118,97,108,95,108,105,115,116,5,115,112,108,105,116,5,115,116,97,107,101,12,115,116,97,107,101,95,97,109,111,117,110,116,12,115,116,97,107,105,110,103,95,112,111,111,108,15,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,21,115,116,97,107,105,110,103,95,112,111,111,108,95,109,97,112,112,105,110,103,115,27,115,116,111,114,97,103,101,95,102,117,110,100,95,115,116,97,107,105,110,103,95,114,101,119,97,114,100,3,115,117,105,11,115,117,105,95,97,100,100,114,101,115,115,22,115,117,105,95,115,121,115,116,101,109,95,115,116,97,116,101,95,105,110,110,101,114,29,115,117,109,95,118,111,116,105,110,103,95,112,111,119,101,114,95,98,121,95,97,100,100,114,101,115,115,101,115,5,116,97,98,108,101,9,116,97,98,108,101,95,118,101,99,26,116,97,108,108,121,105,110,103,95,114,117,108,101,95,103,108,111,98,97,108,95,115,99,111,114,101,23,116,97,108,108,121,105,110,103,95,114,117,108,101,95,114,101,112,111,114,116,101,114,115,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,10,116,120,95,99,111,110,116,101,120,116,32,117,110,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,39,117,112,100,97,116,101,95,97,110,100,95,112,114,111,99,101,115,115,95,108,111,119,95,115,116,97,107,101,95,100,101,112,97,114,116,117,114,101,115,9,118,97,108,105,100,97,116,111,114,17,118,97,108,105,100,97,116,111,114,95,97,100,100,114,101,115,115,20,118,97,108,105,100,97,116,111,114,95,99,97,110,100,105,100,97,116,101,115,13,118,97,108,105,100,97,116,111,114,95,99,97,112,13,118,97,108,105,100,97,116,111,114,95,115,101,116,22,118,97,108,105,100,97,116,111,114,95,115,116,97,107,101,95,97,109,111,117,110,116,25,118,97,108,105,100,97,116,111,114,95,115,116,97,107,105,110,103,95,112,111,111,108,95,105,100,28,118,97,108,105,100,97,116,111,114,95,116,111,116,97,108,95,115,116,97,107,101,95,97,109,111,117,110,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,5,118,97,108,117,101,7,118,101,99,95,109,97,112,7,118,101,99,95,115,101,116,6,118,101,99,116,111,114,30,118,101,114,105,102,105,101,100,95,111,112,101,114,97,116,105,111,110,95,99,97,112,95,97,100,100,114,101,115,115,10,118,101,114,105,102,121,95,99,97,112,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,4,16,16,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,101,0,0,0,0,0,0,0,10,3,1,0,10,5,1,0,0,2,9,149,1,3,24,10,8,19,104,11,13,1,8,19,105,10,3,139,1,11,12,2,8,8,5,78,11,12,2,8,8,8,22,157,1,11,12,2,5,8,22,29,11,15,2,5,3,58,8,6,1,2,10,56,3,156,1,5,120,3,135,1,3,36,3,107,3,140,1,3,108,8,17,148,1,10,5,147,1,3,2,2,11,56,3,156,1,5,120,3,135,1,3,170,1,3,36,3,107,3,140,1,3,108,8,17,148,1,10,5,147,1,3,3,2,3,56,3,156,1,5,138,1,8,8,4,2,4,56,3,156,1,5,138,1,8,8,91,1,0,3,0,0,54,51,14,0,17,45,12,5,10,1,56,0,12,4,14,0,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,16,14,0,10,2,66,58,12,6,13,4,10,6,17,121,11,6,17,122,56,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,11,5,11,0,10,1,56,2,64,14,0,0,0,0,0,0,0,0,11,4,10,1,56,3,10,1,56,4,56,5,11,1,17,65,18,0,12,7,13,7,15,0,17,132,1,11,7,2,1,3,0,0,67,69,10,0,14,1,12,3,46,11,3,17,20,32,4,17,10,0,14,1,12,4,46,11,4,17,23,32,12,5,5,19,9,12,5,11,5,4,22,5,28,11,0,1,11,2,1,7,7,39,14,1,17,122,12,6,10,0,16,1,10,6,56,6,32,4,38,5,44,11,0,1,11,2,1,7,11,39,14,1,17,113,4,48,5,54,11,0,1,11,2,1,7,12,39,10,0,15,2,14,1,17,121,11,6,56,1,11,0,15,1,14,1,17,122,11,1,11,2,17,128,1,56,7,2,2,3,0,0,71,53,10,1,46,17,89,12,4,10,0,16,1,10,4,56,6,4,10,5,16,11,0,1,11,1,1,7,13,39,10,0,15,1,11,4,56,8,17,129,1,12,3,14,3,17,113,4,26,5,32,11,0,1,11,1,1,7,12,39,14,3,17,121,12,2,10,0,15,2,10,2,56,9,1,13,3,10,1,46,17,88,17,108,11,0,15,3,11,2,11,3,11,1,17,128,1,56,10,2,3,3,0,0,76,69,11,2,46,17,89,12,7,10,0,16,1,10,7,56,6,4,10,5,14,11,0,1,7,13,39,10,0,15,1,11,7,56,8,17,129,1,12,6,10,0,14,6,12,3,46,11,3,17,20,32,4,37,10,0,14,6,12,4,46,11,4,17,23,32,12,5,5,39,9,12,5,11,5,4,42,5,46,11,0,1,7,7,39,14,6,17,113,4,50,5,54,11,0,1,7,12,39,14,6,17,123,11,1,38,4,60,5,64,11,0,1,7,10,39,11,0,15,4,11,6,56,11,2,4,3,0,0,3,16,10,0,16,0,10,1,17,22,11,0,16,4,11,1,17,24,22,6,1,0,0,0,0,0,0,0,33,4,13,5,15,7,7,39,2,5,3,0,0,78,36,11,1,46,17,89,12,2,10,0,16,0,11,2,17,26,12,4,14,4,56,12,4,13,5,17,11,0,1,7,9,39,13,4,56,13,12,3,10,0,16,5,14,3,56,14,32,4,27,5,31,11,0,1,7,16,39,11,0,15,5,11,3,68,14,2,6,3,0,0,3,22,14,2,56,15,7,4,38,4,6,5,12,11,0,1,11,3,1,7,15,39,11,0,11,1,17,25,11,2,10,3,46,17,89,11,3,17,117,2,7,3,0,0,55,43,14,1,17,104,12,3,10,0,16,2,10,3,56,16,4,22,10,0,16,2,14,1,17,104,56,17,20,12,4,11,0,11,4,17,25,11,1,11,2,17,119,5,42,10,0,16,3,10,3,56,18,4,28,5,34,11,0,1,11,2,1,7,8,39,11,0,15,3,11,3,56,19,17,130,1,11,1,11,2,17,119,2,8,3,0,0,59,10,11,2,17,89,12,3,11,0,15,0,11,3,17,29,11,1,17,118,2,9,3,0,0,91,110,10,8,46,17,88,6,1,0,0,0,0,0,0,0,22,12,15,17,133,1,12,20,10,0,16,0,10,20,10,1,46,56,15,10,2,46,56,15,17,49,12,22,12,21,10,0,10,3,20,12,9,46,11,9,17,48,12,16,10,0,16,0,14,16,17,53,12,17,10,0,16,0,14,16,17,28,11,4,14,21,14,22,17,47,12,14,12,19,12,13,12,18,10,0,16,0,11,20,11,17,11,21,11,22,11,18,11,13,11,19,11,14,17,50,12,12,12,11,10,0,15,0,14,11,14,12,11,1,11,2,10,8,17,51,10,0,15,0,17,46,10,0,15,0,10,8,17,44,10,15,10,0,16,0,14,11,14,12,10,3,14,16,12,10,46,11,10,17,52,10,0,11,15,17,42,10,0,10,3,10,8,17,39,10,0,11,5,11,6,11,7,11,3,11,8,17,10,10,0,16,0,17,45,10,0,15,6,21,10,0,15,0,17,132,1,11,0,17,11,2,10,0,0,0,92,106,10,0,16,0,65,58,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,99,5,9,11,7,6,1,0,0,0,0,0,0,0,23,12,7,10,0,16,0,10,7,66,58,12,13,10,13,17,122,12,12,11,13,17,123,12,9,10,9,10,1,38,4,40,10,0,16,7,14,12,56,20,4,39,10,0,15,7,14,12,56,21,1,1,5,98,11,9,10,2,38,4,87,10,0,16,7,14,12,56,20,4,64,10,0,15,7,14,12,56,22,12,8,10,8,20,6,1,0,0,0,0,0,0,0,22,10,8,21,11,8,20,12,6,5,71,10,0,15,7,11,12,6,1,0,0,0,0,0,0,0,56,23,6,1,0,0,0,0,0,0,0,12,6,11,6,10,3,36,4,86,10,0,15,0,10,7,56,24,12,10,10,0,11,10,10,4,9,10,5,17,40,5,98,10,0,15,0,10,7,56,24,12,11,10,0,11,11,10,4,9,10,5,17,40,5,4,11,4,1,11,0,1,11,5,1,2,11,0,0,0,98,24,10,0,16,0,65,58,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,21,5,11,10,0,15,0,10,1,67,58,17,110,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,12,1,0,0,99,60,11,0,16,0,12,10,10,10,65,58,12,3,64,100,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,31,5,15,10,10,10,2,66,58,12,9,13,1,10,9,17,111,11,9,17,124,56,25,68,100,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,10,11,10,1,11,1,56,26,12,4,6,0,0,0,0,0,0,0,0,12,7,17,133,1,17,131,1,23,12,8,6,0,0,0,0,0,0,0,0,12,5,10,7,10,8,35,4,58,5,49,13,4,56,27,12,6,12,5,11,7,11,6,22,12,7,5,44,11,5,2,13,1,0,0,3,4,11,0,16,6,20,2,14,1,0,0,3,6,11,0,16,0,11,1,17,34,17,123,2,15,1,0,0,3,6,11,0,16,0,11,1,17,34,17,120,2,16,1,0,0,3,6,11,0,16,0,11,1,17,34,17,121,2,17,1,0,0,3,3,11,0,16,2,2,18,3,0,0,3,12,10,0,16,0,65,58,10,0,16,5,65,14,23,11,0,16,4,56,28,22,2,19,3,0,0,24,8,11,0,16,0,11,1,17,26,12,2,14,2,56,12,2,20,0,0,0,3,5,11,0,16,0,11,1,17,21,2,21,3,0,0,3,6,11,0,11,1,17,22,6,0,0,0,0,0,0,0,0,36,2,22,0,0,0,107,33,10,0,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,66,58,10,1,17,112,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,23,0,0,0,3,7,11,0,16,4,11,1,17,24,6,0,0,0,0,0,0,0,0,36,2,24,0,0,0,107,33,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,6,0,0,0,0,0,0,0,0,12,4,10,2,10,3,35,4,27,5,12,10,0,10,2,56,29,10,1,17,112,4,22,11,4,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,25,0,0,0,3,16,10,0,16,1,10,1,56,6,4,11,11,0,15,1,11,1,56,30,17,130,1,2,11,0,15,0,11,1,17,29,2,26,0,0,0,98,31,10,0,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,66,58,17,122,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,27,0,0,0,98,31,10,0,56,28,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,27,5,10,10,0,10,2,56,29,17,122,10,1,33,4,22,11,0,1,11,2,56,31,2,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,5,11,0,1,56,32,2,28,0,0,0,112,46,10,1,65,59,12,5,6,0,0,0,0,0,0,0,0,12,3,7,20,12,6,10,3,10,5,35,4,40,5,12,10,1,10,3,66,59,20,12,2,10,0,11,2,17,26,12,4,14,4,56,12,4,25,5,31,11,0,1,11,1,1,7,9,39,13,6,11,4,56,33,68,14,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,0,1,11,1,1,11,6,2,29,3,0,0,78,22,10,0,11,1,12,2,46,11,2,17,26,12,4,14,4,56,12,4,11,5,15,11,0,1,7,9,39,13,4,56,13,12,3,11,0,11,3,67,58,2,30,0,0,0,113,45,10,0,16,0,10,1,17,26,12,5,14,5,56,12,4,16,13,5,56,13,12,3,11,0,15,0,11,3,67,58,2,10,0,16,4,10,1,17,27,12,6,14,6,56,12,4,32,13,6,56,13,12,4,11,0,15,4,11,4,56,34,2,11,2,4,35,5,39,11,0,1,7,14,39,11,0,15,1,11,1,56,30,17,130,1,2,31,3,0,0,3,7,11,0,11,1,17,127,20,11,2,17,30,2,32,3,0,0,59,8,11,1,17,89,12,2,11,0,11,2,9,17,30,2,33,3,0,0,59,8,11,1,17,89,12,2,11,0,11,2,8,17,30,2,34,0,0,0,118,19,10,0,11,1,17,26,12,3,14,3,56,12,4,8,5,12,11,0,1,7,9,39,13,3,56,13,12,2,11,0,11,2,66,58,2,35,3,0,0,119,57,10,0,16,0,10,1,17,26,12,7,14,7,56,12,4,11,8,12,3,5,15,10,2,7,0,33,12,3,11,3,4,25,13,7,56,13,12,5,11,0,16,0,11,5,66,58,2,10,0,16,4,10,1,17,27,12,8,14,8,56,12,4,36,8,12,4,5,40,11,2,7,1,33,12,4,11,4,4,50,13,8,56,13,12,6,11,0,16,4,11,6,56,29,2,11,0,15,1,11,1,56,30,17,130,1,46,2,36,1,0,0,118,21,10,0,16,0,11,1,17,26,12,3,14,3,56,12,4,9,5,13,11,0,1,7,9,39,13,3,56,13,12,2,11,0,16,0,11,2,66,58,2,37,1,0,0,118,21,10,0,16,4,11,1,17,27,12,3,14,3,56,12,4,9,5,13,11,0,1,7,17,39,13,3,56,13,12,2,11,0,16,4,11,2,56,29,2,38,3,0,0,120,39,10,1,17,126,20,12,6,10,2,7,0,33,4,16,11,0,11,6,12,3,46,11,3,17,36,12,4,5,21,11,0,11,6,11,2,17,35,12,4,11,4,12,7,10,1,56,35,12,5,11,7,17,114,14,5,33,4,32,5,36,11,1,1,7,19,39,11,1,17,125,2,39,0,0,0,124,32,10,0,15,5,17,43,10,0,16,5,56,36,32,4,25,5,9,10,0,15,5,69,14,12,3,10,0,15,0,11,3,56,24,12,4,10,0,11,4,10,1,8,10,2,17,40,5,3,11,1,1,11,0,1,11,2,1,2,40,0,0,0,126,58,10,4,46,17,88,6,1,0,0,0,0,0,0,0,22,12,5,14,1,17,122,12,6,14,1,17,121,12,7,10,0,15,2,10,7,56,9,1,10,0,16,7,14,6,56,20,4,28,10,0,15,7,14,6,56,21,1,1,10,0,16,6,20,14,1,17,123,23,10,0,15,6,21,11,2,10,6,17,41,10,5,11,6,14,1,17,121,11,3,18,4,56,37,13,1,11,5,17,108,11,0,15,3,11,7,11,1,11,4,17,128,1,56,10,2,41,0,0,0,128,1,69,10,0,14,1,12,2,46,11,2,56,38,4,12,10,0,14,1,56,39,1,1,10,0,46,56,40,12,7,14,7,65,59,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,66,5,26,14,7,10,4,66,59,12,6,10,0,10,6,56,41,12,8,10,8,14,1,12,3,46,11,3,56,42,4,57,10,8,14,1,56,43,11,8,46,56,44,4,54,10,0,11,6,56,39,1,1,5,56,11,6,1,5,61,11,8,1,11,6,1,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,21,11,0,1,2,42,0,0,0,58,28,10,0,16,4,56,45,32,4,25,5,6,10,0,15,4,56,46,12,2,13,2,10,1,17,105,10,1,14,2,17,122,14,2,17,121,18,3,56,47,10,0,15,0,11,2,68,58,5,0,11,0,1,2,43,0,0,0,137,1,57,10,0,46,65,14,12,6,6,1,0,0,0,0,0,0,0,12,4,10,4,10,6,35,4,54,5,11,10,0,10,4,12,1,46,11,1,66,14,20,12,3,10,4,12,5,10,5,6,0,0,0,0,0,0,0,0,36,4,49,5,26,11,5,6,1,0,0,0,0,0,0,0,23,12,5,10,0,10,5,12,2,46,11,2,66,14,20,10,3,36,4,41,5,42,5,49,10,0,10,5,10,5,6,1,0,0,0,0,0,0,0,22,71,14,5,21,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,1,2,44,0,0,0,98,26,10,0,46,65,58,12,3,6,0,0,0,0,0,0,0,0,12,2,10,2,10,3,35,4,21,5,11,10,0,10,2,67,58,10,1,17,116,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,11,0,1,11,1,1,2,45,0,0,0,139,1,30,6,0,0,0,0,0,0,0,0,12,3,10,0,65,58,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,26,5,12,10,0,10,1,66,58,12,4,11,3,11,4,17,123,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,46,0,0,0,98,23,10,0,46,65,58,12,2,6,0,0,0,0,0,0,0,0,12,1,10,1,10,2,35,4,20,5,11,10,0,10,1,67,58,17,106,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,6,11,0,1,2,47,0,0,0,140,1,69,6,0,0,0,0,0,0,0,0,12,8,56,48,12,4,6,0,0,0,0,0,0,0,0,12,9,56,48,12,5,13,0,46,56,36,32,4,60,5,14,13,0,69,14,12,10,10,2,10,10,66,14,20,53,10,1,53,24,7,3,26,12,6,13,4,10,10,10,6,52,56,49,11,8,11,6,52,22,12,8,10,3,10,10,66,14,20,53,10,1,53,24,7,3,26,12,7,13,5,11,10,10,7,52,56,49,11,9,11,7,52,22,12,9,5,8,11,3,1,11,2,1,11,8,11,4,11,9,11,5,2,48,0,0,0,141,1,40,7,21,12,5,14,1,56,50,32,4,36,5,7,13,1,56,51,12,4,12,6,10,0,10,6,17,19,4,16,5,20,11,0,1,7,5,39,10,0,16,0,12,3,11,4,56,52,12,2,11,3,14,2,17,53,17,131,1,38,4,35,13,5,11,6,68,59,5,2,11,0,1,11,5,2,49,0,0,0,144,1,47,64,14,0,0,0,0,0,0,0,0,12,7,64,14,0,0,0,0,0,0,0,0,12,8,10,0,65,58,12,5,11,3,10,5,26,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,42,5,18,10,0,10,4,66,58,17,124,53,10,2,53,24,10,1,53,26,12,6,13,7,11,6,52,68,14,13,8,10,9,68,14,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,13,11,0,1,11,7,11,8,2,50,0,0,0,145,1,108,11,1,11,2,23,12,22,64,14,0,0,0,0,0,0,0,0,12,12,64,14,0,0,0,0,0,0,0,0,12,14,10,0,65,58,12,20,10,20,14,6,56,53,23,12,21,6,0,0,0,0,0,0,0,0,12,19,10,19,10,20,35,4,103,5,23,10,0,10,19,66,58,17,124,53,12,25,14,3,10,19,66,14,20,12,23,14,6,14,19,56,54,4,48,14,6,14,19,56,55,20,12,15,11,23,11,15,23,12,9,5,61,10,5,53,11,25,24,10,22,53,26,12,16,11,23,11,16,52,22,12,9,11,9,12,11,13,12,11,11,68,14,14,4,10,19,66,14,20,12,24,14,8,14,19,56,54,4,85,14,8,14,19,56,55,20,12,17,11,24,11,17,23,12,10,5,93,10,7,10,21,26,12,18,11,24,11,18,22,12,10,11,10,12,13,13,14,11,13,68,14,11,19,6,1,0,0,0,0,0,0,0,22,12,19,5,18,11,0,1,11,12,11,14,2,51,0,0,0,146,1,105,10,0,46,65,58,12,7,10,7,6,0,0,0,0,0,0,0,0,36,4,9,5,23,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,7,18,39,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,92,5,30,10,0,10,6,67,58,12,10,10,1,10,6,66,14,20,12,9,10,3,10,9,56,56,12,8,11,9,53,10,10,46,17,107,53,24,7,3,26,12,12,13,8,11,12,52,56,56,12,13,13,13,10,4,10,2,10,6,66,14,20,56,56,56,57,1,14,13,56,15,6,0,0,0,0,0,0,0,0,36,4,82,10,10,46,17,122,12,11,10,10,11,13,11,11,10,5,17,117,5,84,11,13,56,58,11,10,11,8,17,109,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,25,11,0,1,11,4,1,11,3,1,11,5,1,11,2,1,11,1,1,2,52,0,0,0,151,1,84,10,1,65,58,12,9,6,0,0,0,0,0,0,0,0,12,8,10,8,10,9,35,4,73,5,10,10,1,10,8,66,58,12,12,10,12,17,122,12,13,10,4,14,13,56,38,4,28,10,4,14,13,56,59,20,56,52,12,6,5,30,7,21,12,6,11,6,12,11,10,5,14,13,56,60,4,39,6,0,0,0,0,0,0,0,0,12,7,5,41,6,1,0,0,0,0,0,0,0,12,7,11,7,12,10,10,0,11,13,10,12,17,111,10,12,17,123,10,12,17,124,10,12,17,107,10,2,10,8,66,14,20,10,3,10,8,66,14,20,11,12,10,0,17,115,11,11,11,10,18,2,56,61,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,5,11,1,1,11,3,1,11,5,1,11,4,1,11,2,1,2,53,1,0,0,139,1,35,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,1,65,59,12,3,10,2,10,3,35,4,29,5,12,10,0,10,1,10,2,66,59,20,17,34,12,5,11,4,11,5,17,124,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,7,11,0,1,11,1,1,11,4,2,54,1,0,0,3,3,11,0,16,0,2,55,1,0,0,3,5,11,0,16,1,11,1,56,6,2,56,1,0,0,3,5,11,0,16,3,11,1,56,18,2,0,1,0,6,0,4,0,5,0,2,0,3,0,0,0,7,0,63,0,143,1,0],"validator_wrapper":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,16,3,24,48,4,72,6,5,78,52,7,130,1,211,1,8,213,2,64,6,149,3,10,10,159,3,6,12,165,3,100,13,137,4,2,15,139,4,2,0,14,1,10,1,16,0,12,0,2,4,0,1,0,2,0,2,3,12,0,3,1,4,0,0,5,0,1,0,0,8,2,3,0,0,6,1,4,0,0,11,2,5,0,0,15,6,7,0,2,4,8,9,1,4,2,6,9,12,1,4,2,9,10,11,1,4,2,15,13,7,0,5,4,7,4,6,4,2,8,3,7,8,1,1,8,0,1,7,8,0,1,7,8,3,1,8,3,0,1,6,8,0,1,3,3,3,9,0,7,8,1,1,8,2,1,7,8,2,1,7,9,0,1,9,0,1,6,8,2,9,84,120,67,111,110,116,101,120,116,9,86,97,108,105,100,97,116,111,114,16,86,97,108,105,100,97,116,111,114,87,114,97,112,112,101,114,9,86,101,114,115,105,111,110,101,100,6,99,114,101,97,116,101,9,99,114,101,97,116,101,95,118,49,7,100,101,115,116,114,111,121,5,105,110,110,101,114,28,108,111,97,100,95,118,97,108,105,100,97,116,111,114,95,109,97,121,98,101,95,117,112,103,114,97,100,101,14,108,111,97,100,95,118,97,108,117,101,95,109,117,116,10,116,120,95,99,111,110,116,101,120,116,17,117,112,103,114,97,100,101,95,116,111,95,108,97,116,101,115,116,9,118,97,108,105,100,97,116,111,114,13,118,97,108,105,100,97,116,111,114,95,115,101,116,17,118,97,108,105,100,97,116,111,114,95,119,114,97,112,112,101,114,7,118,101,114,115,105,111,110,9,118,101,114,115,105,111,110,101,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,0,2,1,7,8,2,0,3,0,0,5,6,6,1,0,0,0,0,0,0,0,11,0,11,1,56,0,18,0,2,1,3,0,0,5,6,10,0,17,3,11,0,15,0,56,1,2,2,3,0,0,5,6,13,0,17,3,11,0,19,0,56,2,2,3,0,0,0,5,10,11,0,46,17,4,6,1,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,2,4,0,0,0,5,4,11,0,16,0,17,8,2,0,0,0,13,0],"voting_power":[161,28,235,11,6,0,0,0,12,1,0,8,2,8,12,3,20,87,4,107,4,5,111,134,1,7,245,1,176,2,8,165,4,96,6,133,5,70,10,203,5,16,12,219,5,254,6,13,217,12,4,15,221,12,2,0,22,1,21,2,9,0,18,0,1,2,0,0,2,2,0,3,0,4,0,0,13,0,1,0,0,6,2,3,0,0,15,4,5,0,0,7,6,1,0,0,3,7,1,0,0,17,8,1,0,0,4,4,1,0,0,16,1,5,0,0,12,1,5,0,1,7,17,1,1,0,1,8,19,20,1,0,2,5,11,5,0,2,10,11,5,0,2,11,11,5,0,3,13,21,1,0,3,15,14,5,0,3,22,14,5,0,9,13,10,13,1,7,10,8,2,0,2,6,10,8,2,3,2,10,8,1,3,1,6,10,8,2,1,3,2,7,10,8,1,8,1,3,7,10,8,1,3,3,2,7,10,8,2,10,8,1,4,3,10,8,1,3,3,1,8,2,2,3,3,8,3,8,1,3,10,8,1,3,3,3,3,1,8,1,1,6,8,2,3,3,3,3,4,3,1,3,3,3,7,10,9,0,9,0,3,7,1,3,3,3,3,3,7,8,1,1,6,10,9,0,1,1,2,7,8,2,3,12,3,3,3,3,3,3,3,3,3,6,8,2,6,8,2,3,9,86,97,108,105,100,97,116,111,114,15,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,17,86,111,116,105,110,103,80,111,119,101,114,73,110,102,111,86,50,19,97,100,106,117,115,116,95,118,111,116,105,110,103,95,112,111,119,101,114,16,99,104,101,99,107,95,105,110,118,97,114,105,97,110,116,115,19,100,105,118,105,100,101,95,97,110,100,95,114,111,117,110,100,95,117,112,22,105,110,105,116,95,118,111,116,105,110,103,95,112,111,119,101,114,95,105,110,102,111,6,105,110,115,101,114,116,8,105,115,95,101,109,112,116,121,4,109,97,116,104,3,109,97,120,3,109,105,110,16,113,117,111,114,117,109,95,116,104,114,101,115,104,111,108,100,16,115,101,116,95,118,111,116,105,110,103,95,112,111,119,101,114,5,115,116,97,107,101,11,116,111,116,97,108,95,115,116,97,107,101,18,116,111,116,97,108,95,118,111,116,105,110,103,95,112,111,119,101,114,19,117,112,100,97,116,101,95,118,111,116,105,110,103,95,112,111,119,101,114,9,118,97,108,105,100,97,116,111,114,15,118,97,108,105,100,97,116,111,114,95,105,110,100,101,120,13,118,97,108,105,100,97,116,111,114,95,115,101,116,6,118,101,99,116,111,114,12,118,111,116,105,110,103,95,112,111,119,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,16,39,0,0,0,0,0,0,3,8,11,26,0,0,0,0,0,0,3,8,232,3,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,2,19,3,22,3,1,2,3,19,3,22,3,14,3,0,3,0,0,9,29,7,0,7,2,7,0,10,0,46,65,10,17,11,17,12,17,13,12,4,10,0,10,4,12,1,46,11,1,17,1,12,3,12,2,13,2,11,4,11,3,17,4,10,0,11,2,17,5,11,0,46,17,6,2,1,0,0,0,12,58,10,0,17,2,12,8,6,0,0,0,0,0,0,0,0,12,2,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,7,64,13,0,0,0,0,0,0,0,0,12,5,10,2,10,4,35,4,51,5,17,10,0,10,2,66,10,17,15,12,6,10,6,53,7,0,53,24,10,8,53,26,52,10,1,17,13,12,9,10,2,10,9,11,6,18,1,12,3,13,5,11,3,17,3,11,7,11,9,22,12,7,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,12,11,0,1,11,5,7,0,11,7,23,2,2,0,0,0,15,28,6,0,0,0,0,0,0,0,0,12,1,10,0,65,10,12,2,6,0,0,0,0,0,0,0,0,12,3,10,1,10,2,35,4,24,5,12,11,3,10,0,10,1,66,10,17,15,22,12,3,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,7,11,0,1,11,3,2,3,0,0,0,16,39,6,0,0,0,0,0,0,0,0,12,4,10,0,46,65,13,12,5,10,4,10,5,35,4,25,5,11,10,0,10,4,12,2,46,11,2,66,13,16,0,20,14,1,16,0,20,36,12,3,5,27,9,12,3,11,3,4,34,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,6,11,0,11,1,11,4,56,0,2,4,0,0,0,18,84,6,0,0,0,0,0,0,0,0,12,5,10,0,46,65,13,12,6,10,5,10,6,35,4,16,5,11,10,2,6,0,0,0,0,0,0,0,0,36,12,3,5,18,9,12,3,11,3,4,74,10,0,10,5,67,13,12,9,10,2,10,6,10,5,23,17,11,12,7,10,1,10,9,16,1,20,11,7,22,17,13,12,8,10,2,11,8,10,9,16,1,20,23,17,13,12,4,10,9,16,1,20,10,4,22,10,9,15,1,21,11,9,16,1,20,10,1,37,4,61,5,65,11,0,1,7,5,39,11,2,11,4,23,12,2,11,5,6,1,0,0,0,0,0,0,0,22,12,5,5,6,11,0,1,11,2,6,0,0,0,0,0,0,0,0,33,4,81,5,83,7,3,39,2,5,0,0,0,11,22,14,1,56,1,32,4,17,5,5,13,1,69,13,19,1,1,12,3,12,2,10,0,11,2,67,10,11,3,17,14,5,0,11,0,1,11,1,70,13,0,0,0,0,0,0,0,0,2,6,0,0,0,22,119,6,0,0,0,0,0,0,0,0,12,3,10,0,65,10,12,4,6,0,0,0,0,0,0,0,0,12,9,10,3,10,4,35,4,35,5,12,10,0,10,3,66,10,17,16,12,12,10,12,6,0,0,0,0,0,0,0,0,36,4,22,5,26,11,0,1,7,6,39,11,9,11,12,22,12,9,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,7,11,9,7,0,33,4,40,5,44,11,0,1,7,3,39,6,0,0,0,0,0,0,0,0,12,1,10,1,10,4,35,4,116,5,51,10,1,6,1,0,0,0,0,0,0,0,22,12,2,10,2,10,4,35,4,111,5,60,10,0,10,1,66,10,12,10,10,0,10,2,66,10,12,11,10,10,17,15,12,7,10,11,17,15,12,8,11,10,17,16,12,5,11,11,17,16,12,6,10,7,10,8,36,4,93,10,5,10,6,38,4,89,5,93,11,0,1,7,4,39,11,7,11,8,35,4,106,11,5,11,6,37,4,102,5,106,11,0,1,7,4,39,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,55,11,1,6,1,0,0,0,0,0,0,0,22,12,1,5,46,11,0,1,2,7,1,0,0,1,2,7,0,2,8,1,0,0,1,2,7,1,2,1,2,1,1,0,20,0]},"type_origin_table":[{"module_name":"validator_cap","struct_name":"UnverifiedValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_cap","struct_name":"ValidatorOperationCap","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakingPool","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"PoolTokenExchangeRate","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"staking_pool","struct_name":"StakedSui","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"ValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"Validator","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"StakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator","struct_name":"UnstakingRequestEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfo","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"voting_power","struct_name":"VotingPowerInfoV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_wrapper","struct_name":"ValidatorWrapper","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorSet","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorEpochInfoEventV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorJoinEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"validator_set","struct_name":"ValidatorLeaveEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"storage_fund","struct_name":"StorageFund","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"stake_subsidy","struct_name":"StakeSubsidy","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SystemParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SystemParametersV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SuiSystemStateInner","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SuiSystemStateInnerV2","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system_state_inner","struct_name":"SystemEpochInfoEvent","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"sui_system","struct_name":"SuiSystemState","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisValidatorMetadata","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"GenesisChainParameters","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenDistributionSchedule","package":"0x0000000000000000000000000000000000000000000000000000000000000003"},{"module_name":"genesis","struct_name":"TokenAllocation","package":"0x0000000000000000000000000000000000000000000000000000000000000003"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"DdYtSHED8qYakCvtPiThXfbiSHFJpFGJkYpbYfohRxxh","storage_rebate":0},{"data":{"Package":{"id":"0x000000000000000000000000000000000000000000000000000000000000dee9","version":5,"module_map":{"clob":[161,28,235,11,6,0,0,0,13,1,0,36,2,36,134,1,3,170,1,204,4,4,246,5,184,1,5,174,7,241,9,7,159,17,135,15,8,166,32,96,6,134,33,147,2,10,153,35,226,1,11,251,36,8,12,131,37,235,39,13,238,76,40,14,150,77,26,0,45,0,53,0,54,0,94,1,107,1,137,1,2,28,2,46,2,47,2,65,2,85,2,105,2,126,2,129,1,2,135,1,2,136,1,0,16,7,0,0,14,7,2,0,1,0,1,0,10,7,2,0,1,0,1,0,12,7,2,0,1,0,1,0,9,6,0,0,19,4,0,0,15,8,2,0,1,0,1,0,13,7,2,0,1,0,1,0,11,7,2,0,1,0,1,1,4,4,1,4,0,2,0,12,0,2,5,12,1,0,1,4,8,7,1,0,0,5,21,7,0,6,1,4,1,0,1,7,2,8,0,8,3,12,1,0,1,10,7,12,2,7,0,4,1,11,6,7,0,11,22,4,0,12,17,2,0,13,18,12,2,7,1,4,1,15,20,2,0,0,60,0,1,0,0,49,2,3,0,0,51,4,1,2,0,0,0,50,5,1,2,0,0,0,57,6,1,2,0,0,0,58,7,1,2,0,0,0,146,1,8,9,2,0,0,0,147,1,8,10,2,0,0,0,127,11,12,2,0,0,0,128,1,13,12,2,0,0,0,93,14,15,2,0,0,0,92,14,15,2,0,0,0,91,16,15,2,0,0,0,112,17,18,2,0,0,0,78,19,20,2,0,0,0,111,21,22,2,0,0,0,109,20,23,0,0,63,24,1,2,0,0,0,64,25,1,2,0,0,0,44,26,1,2,0,0,0,123,27,28,2,0,0,0,43,29,1,2,0,0,0,36,30,1,2,0,0,0,86,31,32,2,0,0,0,24,31,33,2,0,0,0,74,34,35,2,0,0,0,73,34,35,2,0,0,0,72,36,20,2,0,0,0,75,37,38,2,0,0,1,39,84,60,1,4,1,40,84,60,1,4,1,42,71,72,1,4,1,67,84,20,1,4,1,68,84,78,1,4,1,79,91,20,1,4,1,82,70,23,1,4,1,95,70,46,1,4,1,96,70,46,1,4,1,100,2,50,1,4,1,104,84,46,1,4,1,114,84,46,1,4,1,122,71,43,1,4,2,23,97,20,1,0,2,24,97,46,1,0,2,55,90,54,1,0,2,56,77,54,1,0,2,77,62,1,1,0,2,87,90,1,1,0,2,97,2,3,0,2,100,2,53,1,0,2,139,1,77,1,1,0,2,145,1,63,9,1,0,3,61,46,78,0,3,98,46,20,0,3,99,46,78,0,3,140,1,46,78,0,3,141,1,46,20,0,3,142,1,46,78,0,4,38,74,60,1,0,4,83,74,23,1,0,5,71,1,44,1,0,6,84,80,20,1,0,6,125,79,54,1,0,6,144,1,67,20,1,0,6,148,1,1,54,1,0,7,133,1,66,20,0,8,69,68,9,1,0,8,80,9,54,1,0,8,84,88,1,1,0,8,144,1,59,20,1,0,9,62,43,1,1,3,10,27,73,74,2,7,4,10,38,75,76,2,7,4,10,41,83,82,2,7,4,10,48,75,23,2,7,4,10,59,41,1,2,7,4,10,70,73,74,2,7,4,10,82,73,23,2,7,4,10,100,2,41,2,7,4,10,101,75,74,2,7,4,10,116,92,1,2,7,4,10,121,83,45,2,7,4,11,76,60,61,1,8,11,100,2,47,0,11,138,1,48,49,0,13,25,95,1,2,7,4,13,38,94,76,2,7,4,13,41,81,82,2,7,4,13,48,94,23,2,7,4,13,100,2,52,2,7,4,14,124,43,1,1,8,75,40,60,43,60,45,38,0,89,51,49,43,49,45,64,43,64,45,90,56,70,57,69,58,67,58,2,55,69,43,82,3,67,43,46,43,69,45,67,45,46,45,51,43,51,45,13,55,10,55,63,43,66,43,66,45,35,0,37,0,31,0,76,40,58,20,77,40,72,40,50,43,17,55,45,43,62,45,61,45,61,43,18,55,79,40,59,20,87,51,81,46,81,40,73,40,39,0,41,0,33,0,36,0,50,45,45,45,62,43,40,0,11,55,68,43,12,55,68,45,47,45,47,43,78,40,34,0,80,40,70,93,88,51,78,46,85,51,80,46,42,45,44,45,63,45,44,43,14,55,70,98,70,99,74,46,72,46,20,55,29,0,74,40,77,46,71,46,86,51,76,46,30,0,79,46,43,43,43,45,32,0,27,55,1,8,5,0,1,7,8,22,1,8,10,6,3,3,3,3,11,14,1,8,20,7,8,22,4,3,3,11,16,1,8,20,7,8,22,3,7,11,6,2,9,0,9,1,11,16,1,9,0,6,8,10,3,7,11,6,2,9,0,9,1,11,16,1,9,1,6,8,10,4,7,11,6,2,9,0,9,1,3,6,8,10,7,8,22,1,11,16,1,9,0,1,11,16,1,9,1,6,7,11,6,2,9,0,9,1,3,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,3,11,16,1,9,0,11,16,1,9,1,3,5,7,11,6,2,9,0,9,1,3,6,8,15,11,16,1,9,1,7,8,22,5,7,11,6,2,9,0,9,1,3,3,3,11,14,1,9,1,2,11,14,1,9,0,11,14,1,9,1,4,7,11,6,2,9,0,9,1,3,3,11,14,1,9,0,7,7,11,6,2,9,0,9,1,3,1,11,16,1,9,0,11,16,1,9,1,6,8,15,7,8,22,2,11,16,1,9,0,11,16,1,9,1,7,7,11,6,2,9,0,9,1,3,3,1,3,6,8,10,7,8,22,1,3,9,7,11,6,2,9,0,9,1,3,3,1,3,2,6,8,15,6,8,10,7,8,22,4,3,3,1,3,1,1,2,8,18,6,8,4,5,8,18,6,8,4,3,3,3,3,7,11,6,2,9,0,9,1,3,6,8,10,5,7,11,9,1,8,5,7,11,17,2,3,3,3,3,8,18,1,8,4,2,7,11,6,2,9,0,9,1,6,8,10,3,7,11,6,2,9,0,9,1,10,3,6,8,10,2,6,11,6,2,9,0,9,1,6,8,10,1,10,8,4,4,3,3,3,3,4,6,11,6,2,9,0,9,1,3,3,6,8,15,2,10,3,10,3,3,6,11,9,1,8,5,3,3,3,6,11,6,2,9,0,9,1,3,6,8,10,1,6,8,4,1,11,17,2,3,8,4,2,3,8,4,1,11,17,2,9,0,9,1,4,8,13,8,18,8,19,8,13,1,9,0,1,8,13,1,9,1,2,3,3,1,8,19,1,6,8,19,1,6,8,18,1,11,9,1,9,0,2,8,18,11,17,2,3,3,1,11,21,2,9,0,9,1,1,11,11,1,9,0,1,11,14,1,9,0,2,9,0,9,1,1,11,6,2,9,0,9,1,1,8,0,1,8,20,1,6,11,16,1,9,0,1,6,9,0,1,8,18,3,7,11,11,1,9,0,8,18,11,14,1,9,0,4,7,11,11,1,9,0,3,6,8,10,7,8,22,4,3,11,16,1,9,0,11,16,1,9,1,3,3,11,14,1,9,0,11,14,1,9,1,3,1,6,8,15,1,6,11,14,1,9,0,2,11,14,1,9,0,7,8,22,28,1,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,11,14,1,9,1,1,3,3,1,3,7,8,5,3,1,6,11,9,1,9,0,2,7,11,9,1,9,0,3,1,7,9,0,1,6,11,17,2,9,0,9,1,1,6,11,12,1,9,0,2,6,11,17,2,9,0,9,1,9,0,1,6,9,1,3,7,11,11,1,9,0,8,18,3,2,1,3,2,7,11,14,1,9,0,3,2,7,11,14,1,9,0,11,14,1,9,0,2,7,11,21,2,9,0,9,1,9,0,1,7,9,1,2,7,11,17,2,9,0,9,1,9,0,2,6,11,9,1,9,0,3,26,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,0,3,6,8,4,7,8,4,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,27,1,3,1,3,3,7,11,9,1,8,5,11,14,1,9,0,3,3,11,14,1,9,1,3,6,8,4,7,8,4,3,3,6,11,12,1,3,3,3,8,18,11,14,1,9,1,1,3,3,11,14,1,9,1,3,7,8,5,3,3,11,14,1,9,0,11,14,1,9,1,11,14,1,9,1,2,7,11,16,1,9,0,11,16,1,9,0,7,3,7,11,9,1,8,5,8,4,3,3,3,8,18,3,7,11,11,1,9,0,6,8,10,3,3,7,11,9,1,9,0,3,9,0,3,7,11,17,2,9,0,9,1,9,0,9,1,1,11,1,2,9,0,9,1,2,6,11,21,2,9,0,9,1,9,0,3,7,11,21,2,9,0,9,1,9,0,9,1,11,11,14,1,9,0,11,14,1,9,0,11,14,1,9,0,3,3,11,14,1,9,1,11,14,1,9,1,11,14,1,9,1,3,3,8,18,2,6,11,11,1,9,0,8,18,1,11,2,2,9,0,9,1,1,11,3,2,9,0,9,1,11,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,1,8,4,3,3,8,18,7,11,17,2,3,3,3,3,7,8,5,8,4,13,3,7,11,9,1,8,5,3,3,1,7,11,9,1,8,5,8,4,3,3,8,18,3,8,18,7,11,17,2,3,3,17,3,3,6,11,9,1,8,5,7,11,9,1,8,5,3,3,1,3,3,3,8,4,3,8,18,3,3,8,18,7,11,17,2,3,3,7,6,8,5,10,8,4,6,8,4,6,11,12,1,3,3,8,18,6,11,17,2,3,3,5,3,3,3,3,8,18,6,3,10,3,3,3,3,10,3,4,3,6,8,4,6,11,12,1,3,6,11,17,2,3,8,4,4,6,11,9,1,8,5,3,8,18,6,11,17,2,3,3,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,5,67,108,111,99,107,4,67,111,105,110,11,67,114,105,116,98,105,116,84,114,101,101,9,67,117,115,116,111,100,105,97,110,2,73,68,11,76,105,110,107,101,100,84,97,98,108,101,6,79,112,116,105,111,110,5,79,114,100,101,114,13,79,114,100,101,114,67,97,110,99,101,108,101,100,11,79,114,100,101,114,70,105,108,108,101,100,13,79,114,100,101,114,70,105,108,108,101,100,86,50,11,79,114,100,101,114,80,108,97,99,101,100,13,79,114,100,101,114,80,108,97,99,101,100,86,50,4,80,111,111,108,11,80,111,111,108,67,114,101,97,116,101,100,3,83,85,73,5,84,97,98,108,101,9,84,105,99,107,76,101,118,101,108,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,3,97,100,100,4,97,115,107,115,4,98,97,99,107,7,98,97,108,97,110,99,101,10,98,97,115,101,95,97,115,115,101,116,28,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,99,97,110,99,101,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,102,105,108,108,101,100,26,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,112,108,97,99,101,100,29,98,97,115,101,95,97,115,115,101,116,95,113,117,97,110,116,105,116,121,95,114,101,109,97,105,110,105,110,103,23,98,97,115,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,14,98,97,115,101,95,99,117,115,116,111,100,105,97,110,18,98,97,116,99,104,95,99,97,110,99,101,108,95,111,114,100,101,114,4,98,105,100,115,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,17,99,97,110,99,101,108,95,97,108,108,95,111,114,100,101,114,115,12,99,97,110,99,101,108,95,111,114,100,101,114,4,99,108,111,98,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,14,99,114,101,97,116,101,95,97,99,99,111,117,110,116,11,99,114,101,97,116,101,95,112,111,111,108,12,99,114,101,97,116,101,95,112,111,111,108,95,12,99,114,101,97,116,105,111,110,95,102,101,101,7,99,114,105,116,98,105,116,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,100,101,112,111,115,105,116,95,98,97,115,101,13,100,101,112,111,115,105,116,95,113,117,111,116,101,13,100,101,115,116,114,111,121,95,101,109,112,116,121,19,100,101,115,116,114,111,121,95,101,109,112,116,121,95,108,101,118,101,108,9,100,105,118,95,114,111,117,110,100,4,101,109,105,116,19,101,109,105,116,95,111,114,100,101,114,95,99,97,110,99,101,108,101,100,17,101,109,105,116,95,111,114,100,101,114,95,102,105,108,108,101,100,5,101,118,101,110,116,16,101,120,112,105,114,101,95,116,105,109,101,115,116,97,109,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,12,102,114,111,109,95,98,97,108,97,110,99,101,5,102,114,111,110,116,3,103,101,116,22,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,97,115,107,95,115,105,100,101,31,103,101,116,95,108,101,118,101,108,50,95,98,111,111,107,95,115,116,97,116,117,115,95,98,105,100,95,115,105,100,101,16,103,101,116,95,111,114,100,101,114,95,115,116,97,116,117,115,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,18,105,110,106,101,99,116,95,108,105,109,105,116,95,111,114,100,101,114,11,105,110,115,101,114,116,95,108,101,97,102,12,105,110,116,111,95,98,97,108,97,110,99,101,6,105,115,95,98,105,100,8,105,115,95,101,109,112,116,121,7,105,115,95,110,111,110,101,4,106,111,105,110,12,108,105,110,107,101,100,95,116,97,98,108,101,16,108,105,115,116,95,111,112,101,110,95,111,114,100,101,114,115,12,108,111,99,107,95,98,97,108,97,110,99,101,8,108,111,116,95,115,105,122,101,17,109,97,107,101,114,95,114,101,98,97,116,101,95,114,97,116,101,13,109,97,107,101,114,95,114,101,98,97,116,101,115,9,109,97,116,99,104,95,97,115,107,9,109,97,116,99,104,95,98,105,100,29,109,97,116,99,104,95,98,105,100,95,119,105,116,104,95,113,117,111,116,101,95,113,117,97,110,116,105,116,121,4,109,97,116,104,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,109,117,108,9,109,117,108,95,114,111,117,110,100,3,110,101,119,4,110,101,120,116,17,110,101,120,116,95,97,115,107,95,111,114,100,101,114,95,105,100,17,110,101,120,116,95,98,105,100,95,111,114,100,101,114,95,105,100,9,110,101,120,116,95,108,101,97,102,6,111,98,106,101,99,116,11,111,112,101,110,95,111,114,100,101,114,115,6,111,112,116,105,111,110,8,111,114,100,101,114,95,105,100,12,111,114,100,101,114,95,105,115,95,98,105,100,5,111,119,110,101,114,17,112,108,97,99,101,95,108,105,109,105,116,95,111,114,100,101,114,18,112,108,97,99,101,95,109,97,114,107,101,116,95,111,114,100,101,114,7,112,111,111,108,95,105,100,13,112,114,101,118,105,111,117,115,95,108,101,97,102,5,112,114,105,99,101,9,112,117,115,104,95,98,97,99,107,8,113,117,97,110,116,105,116,121,11,113,117,111,116,101,95,97,115,115,101,116,24,113,117,111,116,101,95,97,115,115,101,116,95,116,114,97,100,105,110,103,95,102,101,101,115,15,113,117,111,116,101,95,99,117,115,116,111,100,105,97,110,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,12,114,101,109,111,118,101,95,111,114,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,3,115,117,105,25,115,119,97,112,95,101,120,97,99,116,95,98,97,115,101,95,102,111,114,95,113,117,111,116,101,25,115,119,97,112,95,101,120,97,99,116,95,113,117,111,116,101,95,102,111,114,95,98,97,115,101,5,116,97,98,108,101,16,116,97,107,101,114,95,99,111,109,109,105,115,115,105,111,110,14,116,97,107,101,114,95,102,101,101,95,114,97,116,101,9,116,105,99,107,95,115,105,122,101,12,116,105,109,101,115,116,97,109,112,95,109,115,14,116,111,116,97,108,95,113,117,97,110,116,105,116,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,16,117,110,115,97,102,101,95,100,105,118,95,114,111,117,110,100,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,15,117,115,114,95,111,112,101,110,95,111,114,100,101,114,115,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,13,119,105,116,104,100,114,97,119,95,98,97,115,101,14,119,105,116,104,100,114,97,119,95,113,117,111,116,101,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,3,8,17,0,0,0,0,0,0,0,3,8,18,0,0,0,0,0,0,0,3,8,19,0,0,0,0,0,0,0,3,8,20,0,0,0,0,0,0,0,3,8,0,202,154,59,0,0,0,0,2,1,4,2,1,0,2,1,1,2,1,2,2,1,3,3,8,0,0,0,0,0,0,0,128,3,8,0,0,0,0,0,0,0,0,3,8,64,75,76,0,0,0,0,0,3,8,160,37,38,0,0,0,0,0,3,8,0,232,118,72,23,0,0,0,0,2,7,113,8,18,29,8,13,118,8,13,131,1,3,89,3,132,1,3,88,3,1,2,7,113,8,18,108,3,81,1,110,8,18,32,3,115,3,66,3,2,2,6,113,8,18,108,3,81,1,110,8,18,30,3,115,3,3,2,10,113,8,18,108,3,81,1,110,8,18,134,1,3,31,3,33,3,115,3,130,1,3,90,3,4,2,6,108,3,115,3,117,3,81,1,110,8,18,66,3,5,2,2,115,3,106,11,17,2,3,8,4,6,2,15,76,8,19,37,11,9,1,8,5,26,11,9,1,8,5,103,3,102,3,143,1,11,21,2,8,18,11,17,2,3,3,131,1,3,89,3,132,1,3,88,3,35,11,11,1,9,0,120,11,11,1,9,1,52,11,14,1,8,20,34,11,14,1,9,0,119,11,14,1,9,1,7,2,6,113,8,18,108,3,81,1,110,8,18,32,3,115,3,8,2,8,113,8,18,108,3,81,1,110,8,18,134,1,3,31,3,33,3,115,3,6,55,1,55,2,55,3,55,0,0,0,0,39,7,11,0,19,5,12,1,1,11,1,56,0,2,1,1,0,0,1,3,11,0,17,48,2,2,0,0,0,42,72,56,1,12,6,56,2,12,9,10,3,10,2,17,56,6,0,0,0,0,0,0,0,0,36,4,11,5,15,11,5,1,7,19,39,10,6,10,9,34,4,20,5,24,11,5,1,7,15,39,10,0,10,1,38,4,29,5,33,11,5,1,7,1,39,10,5,17,83,12,8,14,8,17,84,20,12,7,11,8,10,5,56,3,10,5,56,3,7,0,7,26,10,5,56,4,10,0,10,1,10,2,10,3,10,5,56,5,11,5,56,6,11,4,56,7,56,8,57,0,56,9,11,7,11,6,11,9,11,0,11,1,11,2,11,3,18,0,56,10,2,3,1,0,0,1,19,14,2,56,11,7,30,33,4,6,5,10,11,3,1,7,17,39,7,28,7,29,11,0,11,1,11,2,56,12,11,3,56,13,2,4,1,0,0,1,20,14,1,56,14,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,6,39,11,0,54,0,11,2,56,15,11,1,56,16,56,17,2,5,1,0,0,1,20,14,1,56,18,6,0,0,0,0,0,0,0,0,34,4,6,5,12,11,0,1,11,2,1,7,7,39,11,0,54,1,11,2,56,15,11,1,56,19,56,20,2,6,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,11,0,54,0,11,1,11,2,11,3,56,21,2,7,1,0,0,1,20,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,3,1,11,2,1,7,5,39,11,0,54,1,11,1,11,2,11,3,56,22,2,8,1,0,0,64,49,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,5,1,11,4,1,7,5,39,14,2,56,14,10,1,38,4,19,5,27,11,0,1,11,5,1,11,4,1,7,6,39,14,3,56,18,12,6,11,0,11,1,9,11,2,11,3,11,4,11,5,56,23,12,8,12,7,14,8,56,18,12,9,11,7,11,8,11,9,11,6,23,2,9,1,0,0,65,48,10,1,6,0,0,0,0,0,0,0,0,36,4,5,5,13,11,0,1,11,4,1,11,2,1,7,5,39,14,3,56,18,10,1,38,4,19,5,27,11,0,1,11,4,1,11,2,1,7,7,39,11,0,11,1,7,26,11,2,17,65,11,3,56,19,56,24,12,6,12,5,14,5,56,25,12,7,11,5,10,4,56,26,11,6,11,4,56,27,11,7,2,10,0,0,0,69,215,2,10,0,55,2,17,84,20,12,23,11,1,12,28,56,7,12,10,11,4,12,25,10,0,54,3,12,9,10,9,46,56,28,4,25,11,0,1,11,9,1,11,10,11,25,2,10,9,46,56,29,12,30,12,32,9,12,29,10,9,46,56,28,32,4,43,5,38,10,32,10,2,37,12,5,5,45,9,12,5,11,5,4,212,2,10,9,10,30,56,30,12,31,10,31,16,4,56,31,56,32,20,12,22,10,31,16,4,56,33,32,4,180,2,5,63,10,31,16,4,10,22,56,34,12,16,10,16,16,5,20,12,15,9,12,26,10,16,16,6,20,10,3,37,4,95,8,12,26,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,35,10,23,10,16,56,36,5,249,1,10,15,10,16,16,8,20,17,54,12,18,4,106,11,18,6,1,0,0,0,0,0,0,0,22,12,18,11,18,7,20,10,0,55,4,20,22,17,54,12,18,4,119,11,18,6,1,0,0,0,0,0,0,0,22,12,18,10,28,10,18,38,4,137,1,11,18,12,12,10,12,7,20,10,0,55,4,20,22,17,52,12,13,1,10,15,12,11,5,186,1,8,12,29,10,28,7,20,10,0,55,4,20,22,17,55,12,13,1,11,13,10,16,16,8,20,17,55,12,11,1,11,11,10,0,55,5,20,26,10,0,55,5,20,24,12,11,10,11,10,16,16,8,20,17,56,12,13,10,13,10,0,55,4,20,17,57,12,27,4,182,1,11,27,6,1,0,0,0,0,0,0,0,22,12,27,10,13,11,27,22,12,12,10,13,10,0,55,6,20,17,56,12,19,11,15,10,11,23,12,15,11,28,10,12,23,12,28,10,28,6,0,0,0,0,0,0,0,0,33,4,206,1,8,12,29,10,0,54,0,10,16,16,7,20,10,11,56,37,12,14,13,25,10,12,56,38,12,24,10,0,54,1,10,16,16,7,20,13,24,10,19,10,13,22,56,38,56,20,10,0,54,7,11,24,56,39,1,13,10,11,14,56,40,1,10,0,55,2,17,84,20,10,16,11,11,11,12,11,13,23,11,19,56,41,11,26,4,254,1,8,12,6,5,130,2,10,15,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,165,2,10,22,12,21,10,31,16,4,10,22,56,42,12,20,10,20,56,43,32,4,148,2,11,20,56,32,20,12,22,5,150,2,11,20,1,10,0,54,8,11,16,16,7,20,56,44,10,21,56,45,1,10,31,15,4,11,21,56,46,1,5,176,2,11,16,1,10,31,15,4,10,22,56,47,12,17,11,15,11,17,15,5,21,10,29,4,179,2,5,180,2,5,57,11,31,16,4,56,33,4,204,2,10,9,11,32,12,7,46,11,7,56,48,1,12,32,10,9,11,30,56,49,17,0,10,9,10,32,12,8,46,11,8,56,50,12,30,1,10,29,4,211,2,11,0,1,11,9,1,5,212,2,5,32,11,10,11,25,2,11,0,0,0,85,153,2,10,0,55,2,17,84,20,12,22,11,1,12,25,56,7,12,11,11,4,12,23,10,0,54,3,12,10,10,10,46,56,28,4,25,11,0,1,11,10,1,11,11,11,23,2,10,10,46,56,29,12,28,12,30,10,10,46,56,28,32,4,41,5,36,10,30,10,2,37,12,5,5,43,9,12,5,11,5,4,150,2,10,10,10,28,56,30,12,29,10,29,16,4,56,31,56,32,20,12,21,10,29,16,4,56,33,32,4,244,1,5,61,10,29,16,4,10,21,56,34,12,16,10,16,16,5,20,12,15,9,12,24,10,16,16,6,20,10,3,37,4,93,8,12,24,10,0,54,0,10,16,16,7,20,10,16,16,5,20,56,35,10,22,10,16,56,36,5,183,1,10,25,10,15,36,4,100,10,15,12,6,5,102,10,25,12,6,11,6,12,12,10,12,10,16,16,8,20,17,53,12,13,10,13,10,0,55,6,20,17,56,12,18,10,13,10,0,55,4,20,17,57,12,26,4,127,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,15,10,12,23,12,15,11,25,10,12,23,12,25,10,0,54,0,10,16,16,7,20,10,12,56,37,12,14,13,23,10,26,56,38,12,27,10,0,54,1,10,16,16,7,20,13,27,10,18,56,38,56,20,10,0,54,7,11,27,56,39,1,13,11,11,14,56,40,1,10,0,54,1,10,16,16,7,20,13,23,11,13,56,38,56,20,10,0,55,2,17,84,20,10,16,11,12,11,26,11,18,56,41,11,24,4,188,1,8,12,7,5,192,1,10,15,6,0,0,0,0,0,0,0,0,33,12,7,11,7,4,227,1,10,21,12,20,10,29,16,4,10,21,56,42,12,19,10,19,56,43,32,4,210,1,11,19,56,32,20,12,21,5,212,1,11,19,1,10,0,54,8,11,16,16,7,20,56,44,10,20,56,45,1,10,29,15,4,11,20,56,46,1,5,238,1,11,16,1,10,29,15,4,10,21,56,47,12,17,11,15,11,17,15,5,21,10,25,6,0,0,0,0,0,0,0,0,33,4,243,1,5,244,1,5,55,11,29,16,4,56,33,4,140,2,10,10,11,30,12,8,46,11,8,56,48,1,12,30,10,10,11,28,56,49,17,0,10,10,10,30,12,9,46,11,9,56,50,12,28,1,10,25,6,0,0,0,0,0,0,0,0,33,4,149,2,11,0,1,11,10,1,5,150,2,5,30,11,11,11,23,2,12,0,0,0,86,158,2,10,0,55,2,17,84,20,12,22,11,3,12,10,56,8,12,23,10,0,54,9,12,9,10,9,46,56,28,4,23,11,0,1,11,9,1,11,10,11,23,2,10,9,46,56,51,12,28,12,30,10,9,46,56,28,32,4,39,5,34,10,30,10,1,38,12,4,5,41,9,12,4,11,4,4,155,2,10,9,10,28,56,30,12,29,10,29,16,4,56,31,56,32,20,12,21,10,29,16,4,56,33,32,4,248,1,5,59,10,29,16,4,10,21,56,34,12,15,10,15,16,5,20,12,14,9,12,24,10,15,16,6,20,10,2,37,4,97,8,12,24,10,15,16,5,20,10,15,16,8,20,17,53,12,17,10,0,54,1,10,15,16,7,20,11,17,56,52,10,22,10,15,56,36,5,186,1,14,10,56,25,12,25,10,25,10,14,38,4,107,10,14,12,5,5,109,11,25,12,5,11,5,12,11,10,11,10,15,16,8,20,17,53,12,12,10,12,10,0,55,6,20,17,56,12,18,10,12,10,0,55,4,20,17,57,12,26,4,134,1,11,26,6,1,0,0,0,0,0,0,0,22,12,26,11,14,10,11,23,12,14,10,0,54,1,10,15,16,7,20,11,12,56,53,12,13,13,13,10,26,56,38,12,27,10,0,54,1,10,15,16,7,20,13,27,10,18,56,38,56,20,10,0,54,7,11,27,56,39,1,13,23,11,13,56,39,1,10,0,54,0,10,15,16,7,20,13,10,10,11,56,54,56,17,10,0,55,2,17,84,20,10,15,11,11,11,26,11,18,56,41,11,24,4,191,1,8,12,6,5,195,1,10,14,6,0,0,0,0,0,0,0,0,33,12,6,11,6,4,230,1,10,21,12,20,10,29,16,4,10,21,56,42,12,19,10,19,56,43,32,4,213,1,11,19,56,32,20,12,21,5,215,1,11,19,1,10,0,54,8,11,15,16,7,20,56,44,10,20,56,45,1,10,29,15,4,11,20,56,46,1,5,241,1,11,15,1,10,29,15,4,10,21,56,47,12,16,11,14,11,16,15,5,21,14,10,56,25,6,0,0,0,0,0,0,0,0,33,4,247,1,5,248,1,5,53,11,29,16,4,56,33,4,144,2,10,9,11,30,12,7,46,11,7,56,55,1,12,30,10,9,11,28,56,49,17,0,10,9,10,30,12,8,46,11,8,56,50,12,28,1,14,10,56,25,6,0,0,0,0,0,0,0,0,33,4,154,2,11,0,1,11,9,1,5,155,2,5,28,11,10,11,23,2,13,1,0,0,87,85,10,1,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,9,5,17,11,0,1,11,6,1,11,5,1,7,5,39,10,1,6,0,0,0,0,0,0,0,0,34,4,22,5,30,11,0,1,11,6,1,11,5,1,7,5,39,11,2,4,52,11,0,11,1,7,26,11,5,17,65,11,4,56,19,56,56,12,9,12,7,13,3,11,7,10,6,56,26,56,57,11,9,11,6,56,27,12,4,5,82,11,1,14,3,56,14,37,4,58,5,66,11,0,1,11,6,1,11,5,1,7,6,39,11,0,7,27,11,5,17,65,11,3,56,16,56,58,12,8,10,6,56,26,12,3,13,4,11,8,11,6,56,27,56,59,11,3,11,4,2,14,0,0,0,89,118,10,5,56,15,12,13,10,3,4,30,10,2,10,1,17,53,12,11,10,0,54,1,11,5,11,11,56,60,10,0,55,10,20,12,10,10,0,55,10,20,6,1,0,0,0,0,0,0,0,22,10,0,54,10,21,10,0,54,9,12,8,5,50,10,0,54,0,11,5,10,2,56,61,10,0,55,11,20,12,10,10,0,55,11,20,6,1,0,0,0,0,0,0,0,22,10,0,54,11,21,10,0,54,3,12,8,10,10,10,1,10,2,10,3,10,13,10,4,18,4,12,9,10,8,10,1,12,7,46,11,7,56,50,12,12,32,4,75,10,8,10,1,10,1,10,6,56,62,18,5,56,63,12,12,11,8,11,12,56,30,15,4,10,10,11,9,56,64,10,0,55,2,17,84,20,10,10,11,3,10,13,11,2,10,1,11,4,57,1,56,65,10,0,55,8,10,13,56,66,32,4,107,10,0,54,8,10,13,11,6,56,67,56,68,5,109,11,6,1,11,0,54,8,11,13,56,44,10,10,11,1,56,69,11,10,2,15,1,0,0,96,144,2,10,2,6,0,0,0,0,0,0,0,0,36,4,5,5,15,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,1,6,0,0,0,0,0,0,0,0,36,4,20,5,30,11,0,1,11,8,1,11,6,1,11,7,1,7,4,39,10,1,10,0,55,12,20,25,6,0,0,0,0,0,0,0,0,33,4,39,5,49,11,0,1,11,8,1,11,6,1,11,7,1,7,4,39,10,2,10,0,55,5,20,25,6,0,0,0,0,0,0,0,0,33,4,58,5,68,11,0,1,11,8,1,11,6,1,11,7,1,7,5,39,10,4,10,6,17,65,36,4,74,5,84,11,0,1,11,8,1,11,6,1,11,7,1,7,18,39,10,7,56,15,12,19,10,3,4,128,1,10,0,55,1,10,19,56,70,12,18,10,0,54,1,10,7,10,18,56,71,12,14,10,0,10,2,10,1,11,6,17,65,11,14,56,56,12,16,12,10,14,10,56,25,12,12,11,18,14,16,56,72,23,12,17,10,0,54,0,10,19,11,10,56,17,10,0,54,1,11,19,11,16,56,20,5,160,1,10,0,54,0,10,7,10,2,56,73,12,9,10,0,10,1,11,6,17,65,11,9,56,58,12,15,12,11,10,2,14,11,56,25,23,12,12,14,15,56,72,12,17,10,0,54,0,10,19,11,11,56,17,10,0,54,1,11,19,11,15,56,20,10,5,7,23,33,4,175,1,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,24,33,4,197,1,11,0,1,11,8,1,11,7,1,10,12,11,2,33,4,190,1,5,192,1,7,8,39,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,10,5,7,25,33,4,228,1,10,12,6,0,0,0,0,0,0,0,0,33,4,206,1,5,214,1,11,0,1,11,8,1,11,7,1,7,9,39,11,0,11,1,11,2,11,3,11,4,11,7,11,8,56,74,12,13,11,12,11,17,8,11,13,2,11,5,7,22,33,4,233,1,5,241,1,11,0,1,11,8,1,11,7,1,7,13,39,10,2,10,12,36,4,133,2,11,0,11,1,11,2,10,12,23,11,3,11,4,11,7,11,8,56,74,12,13,11,12,11,17,8,11,13,2,11,0,1,11,8,1,11,7,1,11,12,11,17,9,6,0,0,0,0,0,0,0,0,2,16,0,0,0,1,4,11,0,7,26,35,2,17,0,0,0,1,19,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,11,1,16,8,20,57,2,56,75,2,18,0,0,0,1,27,11,0,10,1,16,18,20,10,1,16,19,20,10,1,16,7,20,10,1,16,5,20,10,2,10,1,16,5,20,11,2,23,11,1,16,8,20,11,3,11,4,57,3,56,76,2,19,1,0,0,100,110,11,2,56,15,12,12,10,0,55,8,10,12,56,66,4,9,5,13,11,0,1,7,11,39,10,0,54,8,10,12,56,44,12,13,10,13,10,1,12,3,46,11,3,56,77,4,26,5,32,11,13,1,11,0,1,7,2,39,10,13,10,1,12,4,46,11,4,56,78,20,12,11,10,1,17,16,12,8,10,8,4,49,10,0,55,9,12,5,5,52,10,0,55,3,12,5,11,5,11,11,56,50,12,10,4,58,5,64,11,13,1,11,0,1,7,2,39,10,8,4,70,10,0,54,9,12,6,5,73,10,0,54,3,12,6,11,6,11,13,11,10,11,1,10,12,56,79,12,9,11,8,4,96,14,9,16,5,20,14,9,16,8,20,17,53,12,7,10,0,54,1,11,12,11,7,56,52,5,103,10,0,54,0,11,12,14,9,16,5,20,56,35,11,0,55,2,17,84,20,14,9,56,36,2,20,0,0,0,101,54,11,1,10,3,56,45,1,10,0,10,2,12,5,46,11,5,56,80,16,4,10,3,56,81,4,15,5,19,11,0,1,7,2,39,10,0,10,2,56,30,12,6,10,6,15,4,11,3,56,46,12,7,14,7,16,7,20,11,4,33,4,35,5,41,11,0,1,11,6,1,7,3,39,11,6,16,4,56,33,4,50,11,0,11,2,56,49,17,0,5,52,11,0,1,11,7,2,21,1,0,0,102,104,10,0,55,2,17,84,20,12,11,11,1,56,15,12,13,10,0,55,8,10,13,56,66,4,14,5,18,11,0,1,7,11,39,10,0,54,8,10,13,56,44,12,14,10,14,46,56,82,32,4,99,5,29,10,14,46,56,83,56,32,20,12,9,10,14,10,9,12,2,46,11,2,56,78,20,12,10,10,9,17,16,12,6,10,6,4,52,10,0,54,9,12,3,5,55,10,0,54,3,12,3,11,3,12,7,10,7,11,10,12,4,46,11,4,56,50,12,12,1,11,7,10,14,11,12,11,9,10,13,56,79,12,8,11,6,4,88,14,8,16,5,20,14,8,16,8,20,17,53,12,5,10,0,54,1,10,13,11,5,56,52,5,95,10,0,54,0,10,13,14,8,16,5,20,56,35,10,11,14,8,56,36,5,23,11,14,1,11,0,1,2,22,1,0,0,103,148,1,10,0,55,2,17,84,20,12,15,11,2,56,15,12,18,10,0,55,8,10,18,56,66,4,14,5,18,11,0,1,6,0,0,0,0,0,0,0,0,39,6,0,0,0,0,0,0,0,0,12,16,6,0,0,0,0,0,0,0,0,12,17,14,1,65,20,12,10,6,0,0,0,0,0,0,0,0,12,8,10,0,54,8,10,18,56,44,12,19,10,8,10,10,35,4,143,1,5,37,14,1,10,8,66,20,20,12,14,10,19,10,14,12,3,46,11,3,56,77,4,50,5,56,11,19,1,11,0,1,7,2,39,10,19,10,14,12,4,46,11,4,56,78,20,12,12,10,14,17,16,12,9,10,12,10,17,34,4,96,11,12,12,17,10,9,4,79,10,0,55,9,12,5,5,82,10,0,55,3,12,5,11,5,10,17,56,50,12,11,4,88,5,94,11,19,1,11,0,1,7,10,39,11,11,12,16,10,9,4,102,10,0,54,9,12,6,5,105,10,0,54,3,12,6,11,6,10,19,10,16,11,14,10,18,56,79,12,13,11,9,4,128,1,14,13,16,5,20,14,13,16,8,20,17,53,12,7,10,0,54,1,10,18,11,7,56,52,5,135,1,10,0,54,0,10,18,14,13,16,5,20,56,35,10,15,14,13,56,36,11,8,6,1,0,0,0,0,0,0,0,22,12,8,5,32,11,19,1,11,0,1,2,23,1,0,0,104,84,11,1,56,15,12,7,10,0,55,8,11,7,56,84,12,8,64,28,0,0,0,0,0,0,0,0,12,3,10,8,56,85,12,5,10,5,56,43,32,4,76,5,18,10,8,10,5,56,32,20,56,78,20,12,6,10,5,56,32,20,17,16,4,36,10,0,55,9,11,6,56,86,12,2,5,41,10,0,55,3,11,6,56,86,12,2,11,2,16,4,10,5,56,32,20,56,34,12,4,13,3,10,4,16,18,20,10,4,16,8,20,10,4,16,5,20,10,4,16,19,20,10,4,16,7,20,11,4,16,6,20,18,4,68,28,10,8,11,5,56,32,20,56,87,12,5,5,13,11,8,1,11,0,1,11,5,1,11,3,2,24,1,0,0,105,20,11,1,56,15,12,6,10,0,55,0,10,6,56,88,12,3,12,2,11,0,55,1,11,6,56,89,12,5,12,4,11,2,11,3,11,4,11,5,2,25,1,0,0,106,86,10,0,55,9,56,29,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,9,56,51,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,9,11,1,56,90,12,1,10,0,55,9,11,2,56,90,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,9,10,1,10,3,17,65,56,91,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,9,11,1,56,48,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,26,1,0,0,106,86,10,0,55,3,56,29,1,12,8,10,1,10,8,35,4,11,11,8,12,1,10,0,55,3,56,51,1,12,7,10,2,10,7,36,4,22,11,7,12,2,10,0,55,3,11,1,56,90,12,1,10,0,55,3,11,2,56,90,12,2,64,20,0,0,0,0,0,0,0,0,12,9,64,20,0,0,0,0,0,0,0,0,12,5,10,1,6,0,0,0,0,0,0,0,0,33,4,47,11,0,1,11,3,1,11,9,11,5,2,10,1,10,2,37,4,83,5,52,10,0,55,3,10,1,10,3,17,65,56,91,12,4,13,9,10,1,68,20,13,5,11,4,68,20,10,0,55,3,11,1,56,48,1,12,6,10,6,6,0,0,0,0,0,0,0,0,33,4,80,11,0,1,11,3,1,5,83,11,6,12,1,5,47,11,9,11,5,2,27,0,0,0,107,49,11,0,11,1,56,86,16,4,12,6,6,0,0,0,0,0,0,0,0,12,3,10,6,56,31,12,5,10,5,56,43,32,4,43,5,15,10,6,10,5,56,32,20,56,34,12,4,10,4,16,6,20,10,2,36,4,34,11,3,11,4,16,5,20,22,12,3,5,36,11,4,1,10,6,11,5,56,32,20,56,42,12,5,5,10,11,6,1,11,5,1,11,3,2,28,1,0,0,108,52,11,2,56,15,12,5,10,0,55,8,10,5,56,66,4,9,5,13,11,0,1,7,11,39,10,0,55,8,11,5,56,84,12,6,10,6,10,1,56,77,4,23,5,29,11,6,1,11,0,1,7,2,39,11,6,10,1,56,78,20,12,4,10,1,7,26,35,4,42,11,0,55,9,12,3,5,45,11,0,55,3,12,3,11,3,11,4,56,86,16,4,11,1,56,34,2,6,10,6,11,6,0,6,2,5,1,4,2,4,5,4,4,4,1,6,6,6,9,6,7,6,14,6,5,6,1,6,3,6,4,6,8,4,0,4,3,0,55,1,55,2,55,3,55,9,55,10,55,11,55,12,55,13,55,14,55,15,55,16,55,17,55,0],"critbit":[161,28,235,11,6,0,0,0,14,1,0,6,2,6,28,3,34,194,1,4,228,1,54,5,154,2,235,1,7,133,4,153,4,8,158,8,64,6,222,8,120,10,214,9,51,11,137,10,4,12,141,10,217,17,13,230,27,28,14,130,28,20,15,150,28,2,0,13,1,43,1,44,0,2,6,1,0,0,0,1,6,0,0,0,4,1,4,0,1,3,12,2,7,1,4,1,2,4,2,0,0,31,0,1,1,4,0,42,2,3,1,4,0,21,2,4,1,4,0,30,2,5,1,4,0,29,2,5,1,4,0,36,6,5,1,4,0,33,6,5,1,4,0,26,6,3,1,4,0,40,6,3,1,4,0,19,7,3,1,4,0,17,6,8,1,4,0,16,6,3,1,4,0,38,9,10,1,4,0,10,9,11,1,4,0,7,6,12,1,4,0,8,6,12,1,4,0,15,1,13,1,6,0,14,1,13,1,4,0,18,6,3,1,4,0,45,14,13,1,4,0,22,15,4,1,4,0,12,16,17,0,1,5,26,13,2,7,4,1,6,22,23,2,7,4,1,9,28,30,2,7,4,1,14,19,13,2,7,4,1,15,19,13,2,7,6,1,21,21,4,2,7,4,1,27,21,3,2,7,4,1,31,0,19,2,7,4,1,37,28,29,2,7,4,29,18,29,20,28,20,27,20,2,10,23,20,10,10,20,10,23,18,8,10,7,10,22,20,18,10,22,18,19,10,6,10,5,10,30,20,1,10,24,18,24,20,30,18,14,10,26,18,26,20,25,20,25,18,1,7,8,4,1,11,2,1,9,0,1,6,11,2,1,9,0,1,3,1,1,2,3,3,2,6,11,2,1,9,0,3,3,7,11,2,1,9,0,3,9,0,2,1,3,2,7,11,2,1,9,0,3,1,9,0,1,7,9,0,1,6,9,0,0,4,7,11,2,1,9,0,3,3,1,3,6,11,2,1,9,0,3,3,1,4,1,2,2,3,8,1,1,11,3,2,9,0,9,1,2,3,11,0,1,9,0,1,6,11,3,2,9,0,9,1,2,6,11,3,2,9,0,9,1,9,0,1,6,9,1,4,1,3,3,3,16,3,3,3,3,3,2,6,8,1,1,1,8,1,3,3,11,0,1,9,0,3,3,3,3,7,11,3,2,9,0,9,1,9,0,9,1,16,3,3,3,3,3,3,3,3,3,1,3,3,6,8,1,3,3,9,0,2,7,11,3,2,9,0,9,1,9,0,1,9,1,1,7,9,1,2,11,3,2,3,8,1,11,3,2,3,11,0,1,9,0,2,6,8,1,3,2,2,2,11,67,114,105,116,98,105,116,84,114,101,101,12,73,110,116,101,114,110,97,108,78,111,100,101,4,76,101,97,102,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,97,100,100,6,98,111,114,114,111,119,20,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,105,110,100,101,120,18,98,111,114,114,111,119,95,108,101,97,102,95,98,121,95,107,101,121,10,98,111,114,114,111,119,95,109,117,116,24,98,111,114,114,111,119,95,109,117,116,95,108,101,97,102,95,98,121,95,105,110,100,101,120,4,99,108,111,98,19,99,111,117,110,116,95,108,101,97,100,105,110,103,95,122,101,114,111,115,7,99,114,105,116,98,105,116,13,100,101,115,116,114,111,121,95,101,109,112,116,121,4,100,114,111,112,16,102,105,110,100,95,99,108,111,115,101,115,116,95,107,101,121,9,102,105,110,100,95,108,101,97,102,29,103,101,116,95,99,108,111,115,101,115,116,95,108,101,97,102,95,105,110,100,101,120,95,98,121,95,107,101,121,11,105,110,115,101,114,116,95,108,101,97,102,14,105,110,116,101,114,110,97,108,95,110,111,100,101,115,8,105,115,95,101,109,112,116,121,13,105,115,95,108,101,102,116,95,99,104,105,108,100,3,107,101,121,6,108,101,97,118,101,115,10,108,101,102,116,95,99,104,105,108,100,14,108,101,102,116,95,109,111,115,116,95,108,101,97,102,6,108,101,110,103,116,104,4,109,97,115,107,8,109,97,120,95,108,101,97,102,8,109,105,110,95,108,101,97,102,3,110,101,119,24,110,101,120,116,95,105,110,116,101,114,110,97,108,95,110,111,100,101,95,105,110,100,101,120,9,110,101,120,116,95,108,101,97,102,15,110,101,120,116,95,108,101,97,102,95,105,110,100,101,120,6,112,97,114,101,110,116,13,112,114,101,118,105,111,117,115,95,108,101,97,102,6,114,101,109,111,118,101,20,114,101,109,111,118,101,95,108,101,97,102,95,98,121,95,105,110,100,101,120,11,114,105,103,104,116,95,99,104,105,108,100,15,114,105,103,104,116,95,109,111,115,116,95,108,101,97,102,4,114,111,111,116,4,115,105,122,101,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,112,100,97,116,101,95,99,104,105,108,100,5,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,128,3,8,255,255,255,255,255,255,255,255,3,8,255,255,255,255,255,255,255,127,0,2,3,23,3,46,9,0,35,3,1,2,4,28,3,25,3,39,3,35,3,2,2,7,41,3,20,11,3,2,3,8,1,24,11,3,2,3,11,0,1,9,0,30,3,29,3,32,3,34,3,2,10,0,10,0,3,0,0,13,11,7,9,10,0,56,0,11,0,56,1,7,9,7,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,57,0,2,1,3,0,0,13,4,11,0,55,0,56,2,2,2,3,0,0,13,4,11,0,55,0,56,3,2,3,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,1,20,56,5,55,2,20,11,0,55,1,20,2,4,3,0,0,13,21,10,0,56,4,32,4,5,5,9,11,0,1,7,4,39,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,0,55,3,20,2,5,1,0,0,24,78,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,36,5,30,10,0,10,4,11,5,56,7,12,2,5,38,9,12,2,11,2,4,50,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,59,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,7,20,56,9,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,6,3,0,0,24,79,10,0,11,1,56,6,12,3,1,10,3,7,9,34,4,10,5,14,11,0,1,7,4,39,7,10,10,3,23,12,5,10,0,55,0,11,3,56,5,55,4,20,12,4,10,4,7,9,34,4,37,5,30,10,0,10,4,11,5,56,7,32,12,2,5,39,9,12,2,11,2,4,51,11,4,12,5,10,0,55,5,10,5,56,8,16,6,20,12,4,5,25,10,4,7,9,33,4,60,11,0,1,6,0,0,0,0,0,0,0,0,7,9,2,7,10,10,0,10,0,55,5,11,4,56,8,16,8,20,56,10,23,12,3,11,0,55,0,10,3,56,5,55,2,20,11,3,2,7,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,7,20,12,2,5,2,11,0,1,11,2,2,8,0,0,0,3,19,11,1,12,2,10,2,7,9,35,4,15,5,7,10,0,55,5,11,2,56,8,16,8,20,12,2,5,2,11,0,1,11,2,2,9,3,0,0,25,247,1,10,1,11,2,7,9,57,1,12,15,10,0,55,6,20,12,16,10,0,55,6,20,6,1,0,0,0,0,0,0,0,22,10,0,54,6,21,10,16,7,11,6,1,0,0,0,0,0,0,0,23,35,4,24,5,28,11,0,1,7,1,39,10,0,54,0,10,16,11,15,56,11,10,0,10,1,12,3,46,11,3,56,12,12,7,10,7,7,9,33,4,69,10,16,6,0,0,0,0,0,0,0,0,33,4,49,5,53,11,0,1,7,2,39,7,10,10,16,23,10,0,54,7,21,10,16,10,0,54,1,21,11,16,11,0,54,3,21,6,0,0,0,0,0,0,0,0,2,10,0,55,0,11,7,56,5,55,2,20,12,6,10,6,10,1,34,4,81,5,85,11,0,1,7,3,39,49,64,11,6,10,1,29,53,17,21,49,64,23,23,12,8,6,1,0,0,0,0,0,0,0,11,8,49,1,23,47,12,17,10,17,7,9,7,9,7,9,18,1,12,12,10,0,55,8,20,12,13,10,0,55,8,20,6,1,0,0,0,0,0,0,0,22,10,0,54,8,21,10,0,54,5,10,13,11,12,56,13,10,0,55,7,20,12,18,7,9,12,14,10,18,7,9,35,4,169,1,5,135,1,10,0,55,5,10,18,56,8,12,9,10,17,10,9,16,12,20,36,4,149,1,11,9,1,5,169,1,11,18,12,14,10,1,10,9,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,164,1,11,9,16,7,20,12,18,5,168,1,11,9,16,8,20,12,18,5,130,1,10,14,7,9,33,4,178,1,10,13,10,0,54,7,21,5,193,1,10,0,10,14,10,18,12,5,12,4,46,11,4,11,5,56,7,12,10,10,0,11,14,10,13,11,10,56,14,11,17,10,1,28,6,0,0,0,0,0,0,0,0,33,12,11,10,0,10,13,7,10,10,16,23,10,11,56,14,10,0,11,13,11,18,11,11,32,56,14,10,0,55,0,10,0,55,1,20,56,5,55,2,20,10,1,36,4,227,1,10,16,10,0,54,1,21,10,0,55,0,10,0,55,3,20,56,5,55,2,20,11,1,35,4,243,1,10,16,11,0,54,3,21,5,245,1,11,0,1,11,16,2,10,3,0,0,3,27,10,0,56,4,4,8,11,0,1,9,7,9,2,10,0,10,1,56,12,12,2,11,0,55,0,10,2,56,5,55,2,20,11,1,34,4,24,9,7,9,2,8,11,2,2,11,3,0,0,3,18,10,0,56,4,4,7,11,0,1,6,0,0,0,0,0,0,0,0,2,10,0,11,1,56,12,12,2,11,0,55,0,11,2,56,5,55,2,20,2,12,3,0,0,27,171,1,10,0,55,0,10,1,56,5,55,2,20,12,12,10,0,55,1,20,10,1,33,4,25,10,0,10,12,12,4,46,11,4,56,15,12,9,1,11,9,10,0,54,1,21,10,0,55,3,20,10,1,33,4,43,10,0,11,12,12,5,46,11,5,56,16,12,10,1,11,10,10,0,54,3,21,10,0,54,0,10,1,56,17,58,1,12,15,12,17,1,10,0,46,56,18,6,0,0,0,0,0,0,0,0,33,4,78,7,9,10,0,54,7,21,7,9,10,0,54,1,21,7,9,10,0,54,3,21,6,0,0,0,0,0,0,0,0,10,0,54,8,21,6,0,0,0,0,0,0,0,0,11,0,54,6,21,5,169,1,10,15,7,9,34,4,83,5,87,11,0,1,7,6,39,10,0,55,5,10,15,56,8,12,14,10,14,16,6,20,12,13,10,0,10,15,7,10,11,1,23,12,7,12,6,46,11,6,11,7,56,7,4,113,11,14,16,8,20,12,8,5,117,11,14,16,7,20,12,8,11,8,12,16,10,13,7,9,33,4,149,1,10,16,7,9,35,4,135,1,7,9,10,0,54,5,10,16,56,19,15,6,21,5,144,1,7,9,10,0,54,0,7,10,10,16,23,56,20,54,4,21,11,16,10,0,54,7,21,5,164,1,10,0,10,13,10,15,12,3,12,2,46,11,2,11,3,56,7,12,11,10,0,11,13,11,16,11,11,56,14,11,0,54,5,11,15,56,21,1,11,17,2,13,3,0,0,13,6,11,0,54,0,11,1,56,20,54,9,2,14,3,0,0,13,6,11,0,55,0,11,1,56,5,55,9,2,15,3,0,0,3,14,10,0,11,1,56,6,12,2,4,6,5,10,11,0,1,7,4,39,11,0,11,2,56,22,2,16,3,0,0,31,14,11,0,58,0,1,1,1,1,12,2,12,1,1,11,1,56,23,11,2,56,24,2,17,3,0,0,31,23,14,0,55,0,56,2,6,0,0,0,0,0,0,0,0,33,4,7,5,9,6,0,0,0,0,0,0,0,0,39,11,0,58,0,1,1,1,1,12,2,12,1,1,11,2,56,25,11,1,56,26,2,18,0,0,0,32,46,10,0,55,7,20,12,3,10,3,7,9,33,4,12,11,0,1,7,9,2,10,3,7,9,35,4,40,5,17,10,0,55,5,11,3,56,8,12,2,10,1,10,2,16,12,20,28,6,0,0,0,0,0,0,0,0,33,4,35,11,2,16,7,20,12,3,5,39,11,2,16,8,20,12,3,5,12,11,0,1,7,10,11,3,23,2,19,0,0,0,13,55,10,1,7,9,34,4,5,5,9,11,0,1,7,7,39,11,3,4,19,10,2,10,0,54,5,10,1,56,19,15,7,21,5,26,10,2,10,0,54,5,10,1,56,19,15,8,21,10,2,7,9,34,4,52,10,2,7,9,36,4,44,11,1,11,0,54,0,7,10,11,2,23,56,20,54,4,21,5,51,11,1,11,0,54,5,11,2,56,19,15,6,21,5,54,11,0,1,2,20,0,0,0,13,9,11,0,55,5,11,1,56,8,16,7,20,11,2,33,2,21,0,0,0,33,107,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,49,128,12,1,5,105,49,0,12,2,10,0,50,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,23,11,0,49,64,47,12,0,11,2,49,64,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,37,11,0,49,32,47,12,0,11,2,49,32,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,51,11,0,49,16,47,12,0,11,2,49,16,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,65,11,0,49,8,47,12,0,11,2,49,8,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,79,11,0,49,4,47,12,0,11,2,49,4,22,12,2,10,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,93,11,0,49,2,47,12,0,11,2,49,2,22,12,2,11,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,28,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,103,11,2,49,1,22,12,2,11,2,12,1,11,1,2,2,2,2,3,0,0,2,4,0,2,2,1,1,3,1,1,1,2,2,6,2,0,2,5,1,0,0,1,0,10,1,10,2,10,3,10,4,10,5,10,9,10,10,10,11,10,13,10,0,11,0],"custodian":[161,28,235,11,6,0,0,0,14,1,0,12,2,12,48,3,60,158,1,4,218,1,30,5,248,1,246,1,7,238,3,166,4,8,148,8,64,6,212,8,10,10,222,8,38,11,132,9,4,12,136,9,238,2,13,246,11,8,14,254,11,6,15,132,12,2,0,23,1,15,1,21,1,35,1,37,1,38,0,0,4,1,0,1,0,1,12,0,0,4,12,1,0,1,1,2,4,1,0,1,2,3,12,1,0,1,3,5,7,0,3,8,4,0,4,6,12,2,7,1,4,1,5,7,2,0,0,33,0,1,0,0,10,2,3,1,0,0,34,0,4,1,0,0,42,5,6,1,0,0,28,7,8,1,0,0,24,9,10,1,0,0,29,11,8,1,0,0,25,12,10,1,0,0,31,9,8,1,0,0,40,12,8,1,0,0,9,2,13,1,0,0,12,2,13,1,0,0,19,14,15,1,0,0,17,2,16,1,0,1,30,27,13,1,0,1,36,30,10,1,0,1,41,24,13,1,0,1,43,8,10,1,0,2,26,26,6,1,0,3,34,0,17,0,3,39,28,29,0,4,13,31,8,2,7,4,4,16,21,23,2,7,4,4,18,32,33,2,7,4,4,22,21,22,2,7,4,4,34,0,25,2,7,4,24,20,22,20,16,19,25,20,5,19,18,19,12,19,14,19,15,19,6,19,7,19,4,19,17,19,21,20,23,20,1,7,8,8,1,8,1,2,6,11,2,1,9,0,8,5,2,3,3,1,11,2,1,9,0,4,7,11,2,1,9,0,3,6,8,1,7,8,8,1,11,4,1,9,0,3,7,11,2,1,9,0,8,5,11,3,1,9,0,0,3,7,11,2,1,9,0,6,8,1,3,1,11,3,1,9,0,3,7,11,2,1,9,0,6,8,1,11,3,1,9,0,3,7,11,2,1,9,0,8,5,3,1,3,2,7,11,2,1,9,0,8,5,1,7,11,0,1,9,0,1,6,11,0,1,9,0,1,8,6,3,6,11,0,1,9,0,3,3,1,9,0,2,8,5,11,0,1,9,0,2,6,11,7,2,9,0,9,1,9,0,1,1,1,6,9,1,1,6,11,3,1,9,0,1,11,7,2,9,0,9,1,2,11,3,1,9,0,7,8,8,2,7,11,3,1,9,0,11,3,1,9,0,1,6,8,6,1,8,5,2,7,11,3,1,9,0,3,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,7,9,1,7,65,99,99,111,117,110,116,10,65,99,99,111,117,110,116,67,97,112,7,66,97,108,97,110,99,101,4,67,111,105,110,9,67,117,115,116,111,100,105,97,110,2,73,68,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,25,97,99,99,111,117,110,116,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,15,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,16,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,115,22,97,99,99,111,117,110,116,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,3,97,100,100,17,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,22,98,111,114,114,111,119,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,10,98,111,114,114,111,119,95,109,117,116,26,98,111,114,114,111,119,95,109,117,116,95,97,99,99,111,117,110,116,95,98,97,108,97,110,99,101,4,99,108,111,98,4,99,111,105,110,8,99,111,110,116,97,105,110,115,9,99,117,115,116,111,100,105,97,110,31,100,101,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,100,101,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,12,102,114,111,109,95,98,97,108,97,110,99,101,2,105,100,31,105,110,99,114,101,97,115,101,95,117,115,101,114,95,97,118,97,105,108,97,98,108,101,95,98,97,108,97,110,99,101,28,105,110,99,114,101,97,115,101,95,117,115,101,114,95,108,111,99,107,101,100,95,98,97,108,97,110,99,101,4,106,111,105,110,12,108,111,99,107,95,98,97,108,97,110,99,101,14,108,111,99,107,101,100,95,98,97,108,97,110,99,101,16,109,105,110,116,95,97,99,99,111,117,110,116,95,99,97,112,3,110,101,119,6,111,98,106,101,99,116,5,115,112,108,105,116,5,116,97,98,108,101,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,14,117,110,108,111,99,107,95,98,97,108,97,110,99,101,5,118,97,108,117,101,14,119,105,116,104,100,114,97,119,95,97,115,115,101,116,4,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,1,0,0,0,0,0,0,0,0,2,2,14,11,3,1,9,0,32,11,3,1,9,0,1,2,1,27,8,6,2,2,2,27,8,6,11,11,7,2,8,5,11,0,1,9,0,2,19,0,19,0,1,0,0,8,4,11,0,17,19,18,1,2,1,3,0,0,18,27,10,0,55,0,10,1,56,0,32,4,11,11,0,1,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,2,11,0,55,0,11,1,56,1,12,2,10,2,55,1,56,2,12,3,11,2,55,2,56,2,12,4,11,3,11,4,2,2,3,0,0,8,6,10,0,17,19,11,0,56,3,57,0,2,3,3,0,0,8,7,11,0,11,2,11,1,56,4,11,3,56,5,2,4,3,0,0,8,8,11,0,11,1,56,6,54,1,11,2,56,7,1,2,5,3,0,0,8,9,11,0,11,1,16,3,17,20,56,6,54,1,11,2,56,8,2,6,3,0,0,8,10,11,0,11,1,16,3,17,20,56,6,54,2,11,2,56,7,1,2,7,3,0,0,8,7,11,0,11,1,56,6,54,2,11,2,56,8,2,8,3,0,0,10,10,10,0,10,1,11,2,56,4,12,3,11,0,11,1,11,3,56,9,2,9,3,0,0,10,10,10,0,10,1,11,2,56,10,12,3,11,0,11,1,11,3,56,11,2,10,3,0,0,8,7,11,0,55,0,11,1,56,1,55,1,56,2,2,11,3,0,0,8,7,11,0,55,0,11,1,56,1,55,2,56,2,2,12,0,0,0,8,18,10,0,55,0,10,1,56,0,32,4,13,10,0,54,0,10,1,56,12,56,12,57,1,56,13,11,0,54,0,11,1,56,14,2,13,0,0,0,8,15,10,0,55,0,10,1,56,0,4,6,5,10,11,0,1,7,0,39,11,0,55,0,11,1,56,1,2,2,1,0,0,0,1,1,0,0,19,1,19,2,19,0,20,0],"math":[161,28,235,11,6,0,0,0,8,1,0,2,3,2,30,5,32,13,7,45,79,8,124,32,6,156,1,38,12,194,1,133,2,15,199,3,2,0,2,0,6,0,1,0,0,7,0,2,0,0,3,0,1,0,0,4,0,2,0,0,5,0,2,0,0,1,0,2,0,2,3,3,1,3,2,1,3,0,3,1,4,4,4,99,108,111,98,9,100,105,118,95,114,111,117,110,100,4,109,97,116,104,3,109,117,108,9,109,117,108,95,114,111,117,110,100,16,117,110,115,97,102,101,95,100,105,118,95,114,111,117,110,100,10,117,110,115,97,102,101,95,109,117,108,16,117,110,115,97,102,101,95,109,117,108,95,114,111,117,110,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,233,3,8,0,202,154,59,0,0,0,0,4,16,0,202,154,59,0,0,0,0,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,3,0,0,1,7,11,0,11,1,17,1,12,2,1,11,2,2,1,3,0,0,4,26,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,10,4,24,7,1,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,18,9,12,2,11,2,11,3,11,4,24,7,1,26,52,2,2,1,0,0,1,14,11,0,11,1,17,1,12,2,1,10,2,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,2,3,1,0,0,2,15,11,0,11,1,17,1,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,4,3,0,0,4,28,11,0,53,12,3,11,1,53,12,4,8,12,2,10,3,7,0,53,24,10,4,25,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,9,12,2,11,2,11,3,7,0,53,24,11,4,26,52,2,5,1,0,0,2,15,11,0,11,1,17,4,12,3,12,2,10,3,6,0,0,0,0,0,0,0,0,36,4,10,5,12,7,2,39,11,2,11,3,2,0,0,0]},"type_origin_table":[{"module_name":"custodian","struct_name":"Account","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"AccountCap","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"custodian","struct_name":"Custodian","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"Leaf","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"InternalNode","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"critbit","struct_name":"CritbitTree","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"PoolCreated","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlacedV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderCanceled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilledV2","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Order","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"TickLevel","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"Pool","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderPlaced","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"},{"module_name":"clob","struct_name":"OrderFilled","package":"0x000000000000000000000000000000000000000000000000000000000000dee9"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":0},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":0}}}},"owner":"Immutable","previous_transaction":"BEb8wBMP1GawREPj4XMmFC75VTmZL5U6aMLLo7122eWn","storage_rebate":0},{"data":{"Move":{"type_":"GasCoin","has_public_transfer":true,"version":4346051,"contents":[21,32,188,177,31,211,164,184,188,23,93,46,13,51,223,242,149,206,222,73,87,55,189,56,32,255,148,164,64,84,144,4,144,115,177,150,11,0,0,0]}},"owner":{"AddressOwner":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497"},"previous_transaction":"GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","storage_rebate":988000},{"data":{"Move":{"type_":{"Other":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"governance_v1","name":"Proposal","type_args":[{"struct":{"address":"7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d","module":"migrate_proposal","name":"Certificate","type_args":[]}}]}},"has_public_transfer":false,"version":4346051,"contents":[57,252,244,217,254,131,156,97,185,211,22,22,230,144,104,131,113,142,173,223,177,229,32,89,200,170,223,35,213,70,217,52,101,133,153,88,189,98,227,10,160,87,31,151,18,150,47,89,9,141,30,178,159,115,176,145,217,215,19,23,216,230,116,151,55,0,0,0,0,0,0,0,0,85,0,0,0,0,0,0,0,64,55,102,54,98,51,56,48,100,98,102,51,54,50,51,54,50,48,53,54,49,53,99,54,52,102,99,98,98,54,99,52,101,57,52,53,52,98,55,54,101,102,102,48,57,55,100,100,54,99,54,53,51,52,102,54,100,53,48,55,48,100,49,55,100,0,0,0,1]}},"owner":{"Shared":{"initial_shared_version":4346051}},"previous_transaction":"GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","storage_rebate":2728400},{"data":{"Move":{"type_":{"Other":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"genesis","name":"GovernanceGenesis","type_args":[]}},"has_public_transfer":false,"version":4346049,"contents":[66,239,144,6,110,100,146,21,230,171,145,57,154,131,225,165,70,127,215,204,67,110,139,131,173,184,116,58,14,251,166,33,4,81,180,29,10,30,207,114,139,134,133,233,172,144,221,93,63,141,97,190,62,113,16,212,34,139,152,136,114,24,131,222,197,178,165,4,156,215,21,134,54,45,12,106,56,227,76,250,174,126,169,206,109,84,1,163,80,80,106,21,248,23,191,114,2,0,0,0,0,0,0,0,0,1,254,147,243,188,197,217,213,55,232,158,184,214,115,240,234,207,29,60,135,22,250,128,58,250,46,171,68,79,42,167,134,211]}},"owner":{"Shared":{"initial_shared_version":3478819}},"previous_transaction":"6B3tXa5PpoaRUQiYcytsC1M9fkfzXUc49NsWgC335qC1","storage_rebate":2181200},{"data":{"Move":{"type_":{"Other":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"governance_v1","name":"GovernanceInfo","type_args":[]}},"has_public_transfer":false,"version":4346051,"contents":[121,215,16,110,161,131,115,252,117,66,176,132,157,94,190,252,58,157,175,139,102,74,79,130,217,179,91,189,12,34,4,45,1,254,147,243,188,197,217,213,55,232,158,184,214,115,240,234,207,29,60,135,22,250,128,58,250,46,171,68,79,42,167,134,211,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,0,0,0,0,0,0,0,1,101,133,153,88,189,98,227,10,160,87,31,151,18,150,47,89,9,141,30,178,159,115,176,145,217,215,19,23,216,230,116,151,0]}},"owner":{"Shared":{"initial_shared_version":3195547}},"previous_transaction":"GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","storage_rebate":2097600},{"data":{"Package":{"id":"0x7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d","version":1,"module_map":{"migrate_proposal":[161,28,235,11,6,0,0,0,10,1,0,10,2,10,40,3,50,68,4,118,14,5,132,1,130,1,7,134,2,192,2,8,198,4,128,1,6,198,5,20,10,218,5,5,12,223,5,118,0,19,3,14,3,16,1,21,2,22,0,0,6,0,1,1,0,0,1,2,8,0,1,7,7,0,1,8,7,0,2,3,8,0,2,5,8,1,6,0,3,4,7,1,0,0,4,6,2,0,0,9,0,1,0,0,23,2,1,0,0,20,3,1,0,1,15,1,16,0,1,20,18,1,2,6,6,2,9,6,1,1,6,2,10,9,1,0,2,24,8,7,1,6,3,11,12,1,1,0,3,13,14,15,1,0,3,17,10,11,1,0,3,18,10,11,1,0,5,5,7,5,10,9,8,9,11,9,9,9,4,17,2,7,8,5,7,8,8,0,3,6,8,5,7,11,6,1,8,0,7,8,8,4,6,8,5,7,11,6,1,8,0,7,8,2,7,8,8,1,7,8,8,1,8,0,3,6,8,5,9,0,7,8,8,1,11,7,1,8,1,5,6,8,5,9,0,7,11,6,1,9,0,1,7,8,8,1,8,1,1,6,11,7,1,9,0,1,1,1,11,7,1,9,0,3,8,1,11,7,1,8,1,8,4,1,7,11,7,1,9,0,1,9,0,1,8,4,2,8,3,8,4,3,6,8,1,7,8,2,9,1,11,67,101,114,116,105,102,105,99,97,116,101,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,9,84,120,67,111,110,116,101,120,116,13,86,101,114,115,105,111,110,95,49,95,48,95,48,13,86,101,114,115,105,111,110,95,49,95,48,95,49,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,12,100,101,115,116,114,111,121,95,110,111,110,101,11,100,117,109,109,121,95,102,105,101,108,100,7,101,120,116,114,97,99,116,7,103,101,110,101,115,105,115,17,103,101,116,95,118,101,114,115,105,111,110,95,49,95,48,95,49,13,103,111,118,101,114,110,97,110,99,101,95,118,49,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,16,109,105,103,114,97,116,101,95,112,114,111,112,111,115,97,108,15,109,105,103,114,97,116,101,95,118,101,114,115,105,111,110,6,111,112,116,105,111,110,10,116,120,95,99,111,110,116,101,120,116,13,118,111,116,101,95,112,111,114,112,111,115,97,108,13,118,111,116,101,95,112,114,111,112,111,115,97,108,127,107,56,13,191,54,35,98,5,97,92,100,252,187,108,78,148,84,183,110,255,9,125,214,198,83,79,109,80,112,209,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,1,12,1,0,1,4,0,4,9,11,0,11,1,12,2,46,9,18,0,11,2,56,0,2,1,1,4,0,7,17,11,0,9,18,0,11,1,8,11,2,56,1,12,3,14,3,56,2,4,12,5,14,7,1,39,11,3,56,3,2,2,1,0,0,13,30,11,0,9,18,0,11,1,8,11,3,56,1,12,5,14,5,56,4,4,12,5,16,11,2,1,7,0,39,13,5,56,5,12,4,17,3,12,6,14,4,11,2,11,6,56,6,11,4,17,6,11,5,56,3,2,0]},"type_origin_table":[{"module_name":"migrate_proposal","struct_name":"Certificate","package":"0x7f6b380dbf36236205615c64fcbb6c4e9454b76eff097dd6c6534f6d5070d17d"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":6},"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302":{"upgraded_id":"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302","upgraded_version":1},"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a":{"upgraded_id":"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a","upgraded_version":1},"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e":{"upgraded_id":"0xc5b2a5049cd71586362d0c6a38e34cfaae7ea9ce6d5401a350506a15f817bf72","upgraded_version":2}}}},"owner":"Immutable","previous_transaction":"5kWByxejQ95cxQ5zUCba3WyivedWBmtisRa4ZaWJuWpm","storage_rebate":10830000},{"data":{"Package":{"id":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","version":1,"module_map":{"app_manager":[161,28,235,11,6,0,0,0,10,1,0,10,2,10,24,3,34,46,4,80,2,5,82,54,7,136,1,228,1,8,236,2,64,10,172,3,18,12,190,3,106,13,168,4,4,0,8,0,11,1,16,1,20,1,21,0,3,12,0,0,0,12,0,1,1,0,0,2,2,7,0,2,5,4,0,4,4,2,0,0,14,0,1,0,0,17,2,3,0,0,18,4,3,0,0,12,5,6,0,0,10,3,1,0,2,9,7,1,0,2,15,0,7,0,2,22,12,8,0,3,19,10,1,1,8,8,9,1,7,8,5,0,2,7,8,0,7,8,5,1,8,1,3,6,8,2,7,8,0,7,8,5,1,6,8,1,1,13,1,8,4,1,8,3,1,8,0,1,9,0,3,8,1,8,3,8,4,1,6,8,4,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,2,73,68,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,97,112,112,95,99,97,112,115,6,97,112,112,95,105,100,11,97,112,112,95,109,97,110,97,103,101,114,6,100,101,108,101,116,101,15,100,101,115,116,114,111,121,95,97,112,112,95,99,97,112,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,2,105,100,4,105,110,105,116,3,110,101,119,6,111,98,106,101,99,116,12,114,101,103,105,115,116,101,114,95,97,112,112,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,8,4,6,10,8,3,1,2,2,13,8,4,7,13,0,0,0,0,1,6,11,0,17,6,64,8,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,11,19,11,1,17,6,12,4,14,4,17,7,12,3,11,4,10,0,16,0,65,8,75,18,1,12,2,11,0,15,0,11,3,68,8,11,2,2,2,1,0,0,1,4,11,1,11,2,17,1,2,3,1,0,0,1,4,11,0,16,1,20,2,4,1,0,0,1,5,11,0,19,1,1,17,5,2,0,1,1,1,0],"dola_address":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,12,3,24,109,4,133,1,6,5,139,1,78,7,217,1,191,3,8,152,5,96,6,248,5,14,10,134,6,8,12,142,6,151,2,13,165,8,4,0,13,0,23,1,4,1,27,2,3,2,5,0,0,7,0,2,1,7,0,3,2,7,0,0,20,0,1,0,0,19,2,1,0,0,18,2,3,0,0,29,4,5,0,0,28,6,5,0,0,10,7,5,0,0,6,8,5,0,0,7,5,8,0,0,9,0,5,1,0,0,8,5,3,0,0,15,5,3,0,0,11,3,5,0,1,12,19,1,0,1,24,14,0,0,1,25,15,0,0,1,30,17,18,1,1,2,21,13,3,0,3,17,0,12,1,0,3,22,12,13,0,4,16,3,8,0,5,26,9,3,1,0,20,8,17,11,15,10,0,1,13,1,6,8,0,1,10,2,2,8,0,13,1,8,0,2,8,0,10,2,2,13,10,2,1,5,1,6,9,0,1,2,1,9,0,1,8,2,1,8,1,2,7,10,2,13,2,7,10,2,10,2,6,10,2,3,10,2,13,3,3,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,11,68,111,108,97,65,100,100,114,101,115,115,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,112,111,111,108,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,19,117,112,100,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,13,2,0,0,0,2,2,14,13,13,10,2,0,1,0,0,0,2,7,1,2,1,1,0,0,0,4,11,0,16,0,20,2,2,1,0,0,0,4,11,0,16,1,20,2,3,1,0,0,0,6,11,1,13,0,15,0,21,11,0,2,4,1,0,0,0,6,11,1,13,0,15,1,21,11,0,2,5,1,0,0,0,4,11,0,11,1,18,0,2,6,1,0,0,0,5,7,1,14,0,56,0,18,0,2,7,1,0,0,0,14,14,0,16,1,65,10,6,32,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,14,0,16,1,20,17,19,2,8,1,0,0,3,8,56,1,17,18,17,16,12,0,7,1,11,0,18,0,2,9,1,0,0,0,4,14,0,16,1,20,2,10,1,0,0,3,14,64,10,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,17,13,13,1,14,0,16,1,20,17,14,11,1,2,11,1,0,0,16,30,14,0,65,10,12,6,6,0,0,0,0,0,0,0,0,12,5,6,2,0,0,0,0,0,0,0,12,2,14,0,10,5,10,5,10,2,22,56,2,12,1,14,1,17,12,12,4,11,5,11,2,22,12,5,14,0,11,5,11,6,56,2,12,3,11,4,11,3,18,0,2,0,0,0,1,0],"dola_pool":[161,28,235,11,6,0,0,0,14,1,0,22,2,22,52,3,74,173,1,4,247,1,32,5,151,2,211,1,7,234,3,168,5,8,146,9,96,6,242,9,50,10,164,10,34,11,198,10,2,12,200,10,222,2,13,166,13,4,14,170,13,4,15,174,13,4,0,23,0,22,0,45,1,12,1,54,2,13,2,14,2,27,2,43,2,52,2,53,0,5,12,1,0,1,0,3,3,0,0,10,3,0,1,4,7,0,3,6,7,0,4,8,7,0,5,0,4,1,0,1,6,1,12,1,0,1,6,2,12,1,0,1,8,9,4,0,10,7,2,0,0,30,0,1,1,0,0,19,2,3,1,0,0,16,4,5,0,0,42,6,5,1,0,0,55,6,5,1,0,0,21,7,8,1,0,0,57,9,3,1,0,0,48,10,8,0,1,15,19,21,0,1,17,21,19,0,1,18,3,21,1,0,1,32,30,8,0,1,33,30,29,0,1,34,3,29,0,2,25,22,8,0,2,26,35,8,0,3,37,26,8,0,4,29,3,25,1,0,4,38,25,26,0,5,39,24,5,1,0,5,51,31,15,1,0,5,59,3,15,1,0,6,28,32,23,1,0,6,31,12,1,1,0,6,36,23,15,1,0,6,56,20,5,1,0,7,24,11,3,1,3,8,41,13,14,0,9,46,34,3,1,12,9,50,11,3,1,8,10,49,18,19,0,23,11,21,11,29,16,0,11,25,11,3,11,10,11,24,11,19,11,17,11,26,27,4,11,20,11,22,11,26,33,28,23,1,6,11,0,1,9,0,1,2,2,6,11,8,1,9,0,7,8,10,0,3,3,2,2,1,3,2,6,11,0,1,9,0,3,5,7,11,0,1,9,0,11,7,1,9,0,13,10,2,7,8,10,1,10,2,5,7,11,0,1,9,0,8,3,3,8,3,7,8,10,3,13,10,2,7,8,10,1,9,0,1,6,11,8,1,9,0,1,7,8,10,1,8,9,1,11,6,1,9,0,1,11,0,1,9,0,6,3,3,3,10,2,5,8,3,1,6,8,10,1,5,1,6,11,7,1,9,0,1,8,3,5,8,3,8,3,3,13,10,2,1,11,7,1,9,0,2,7,11,6,1,9,0,11,6,1,9,0,1,8,5,1,8,4,1,8,1,3,3,11,7,1,9,0,5,1,13,1,6,8,3,2,7,11,6,1,9,0,3,2,11,6,1,9,0,7,8,10,1,8,2,2,9,0,5,3,8,3,13,10,2,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,11,68,101,112,111,115,105,116,80,111,111,108,11,68,111,108,97,65,100,100,114,101,115,115,4,80,111,111,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,12,87,105,116,104,100,114,97,119,80,111,111,108,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,11,99,114,101,97,116,101,95,112,111,111,108,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,4,101,109,105,116,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,12,103,101,116,95,100,101,99,105,109,97,108,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,12,105,110,116,111,95,98,97,108,97,110,99,101,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,10,112,111,111,108,95,99,111,100,101,99,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,35,8,9,13,11,6,1,9,0,20,2,1,2,3,44,8,4,49,5,11,3,2,2,3,44,8,4,47,5,11,3,0,11,0,1,0,0,3,4,11,0,55,0,20,2,1,1,0,0,1,10,11,0,56,0,12,2,11,1,17,27,56,1,11,2,57,0,56,2,2,2,1,0,0,3,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,3,1,0,0,1,8,11,0,56,3,12,2,11,1,11,2,49,8,17,2,2,4,1,0,0,1,8,11,0,56,3,12,2,11,1,49,8,11,2,17,2,2,5,3,0,0,17,38,11,4,46,17,30,12,9,14,1,56,4,12,7,10,0,10,7,12,5,46,11,5,56,5,12,6,10,9,17,8,12,10,56,6,11,10,11,6,11,2,11,3,17,14,12,8,11,0,54,1,11,1,56,7,56,8,1,56,9,17,18,11,9,11,7,18,1,56,10,11,8,2,6,3,0,0,28,53,17,13,14,3,17,12,33,4,6,5,12,11,0,1,11,4,1,7,4,39,14,3,17,11,56,9,17,18,17,16,33,4,20,5,26,11,0,1,11,4,1,7,0,39,11,1,17,9,12,7,10,0,11,2,12,5,46,11,5,56,11,12,2,11,0,54,1,10,2,56,12,11,4,56,13,12,6,56,9,17,18,10,7,11,2,18,2,56,14,11,6,11,7,56,15,2,7,3,0,0,3,8,11,2,46,17,30,17,8,11,0,11,1,17,15,2,0,2,0,1,0,11,1,11,0,40,0,58,0],"equilibrium_fee":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,50,5,54,29,7,83,174,1,8,129,2,32,12,161,2,197,5,0,4,0,10,0,2,0,1,0,0,3,2,1,0,0,0,3,1,0,0,1,3,1,0,1,5,0,1,0,1,6,4,1,0,1,7,0,1,0,1,8,4,1,0,1,9,1,1,0,1,11,0,1,0,2,15,15,1,15,3,15,15,15,6,15,15,15,15,15,15,0,4,1,15,15,15,6,1,15,15,15,15,15,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,27,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,112,101,114,99,101,110,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,1,13,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,11,11,1,11,0,17,6,12,2,11,2,2,1,1,0,0,1,17,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,15,11,0,11,1,17,6,11,2,17,6,17,5,17,4,12,3,11,3,2,2,1,0,0,5,93,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,1,10,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,2,23,10,0,10,2,23,10,3,17,1,10,4,36,4,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,10,4,36,4,50,10,1,10,0,10,4,17,9,10,3,17,9,23,17,5,10,4,10,3,17,9,23,17,6,12,7,5,52,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,12,9,10,2,10,9,23,10,5,17,5,10,4,10,3,17,9,23,17,9,24,10,4,10,3,17,9,26,12,8,10,0,11,1,23,11,5,17,7,17,9,24,10,0,11,9,23,11,0,11,2,23,17,6,17,8,17,9,11,4,11,3,17,9,26,11,8,23,2,3,1,0,0,6,51,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,12,7,11,1,10,2,22,11,0,10,2,22,11,3,17,1,11,7,23,12,9,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,4,11,5,17,6,24,12,11,11,2,11,11,17,6,17,5,17,4,12,10,11,9,11,10,17,4,12,8,11,4,11,8,17,9,2,0],"genesis":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,52,3,70,123,4,193,1,22,5,215,1,167,1,7,254,2,226,3,8,224,6,96,6,192,7,61,10,253,7,34,12,159,8,137,2,13,168,10,6,15,174,10,2,0,25,1,14,1,42,1,44,2,23,2,36,2,37,2,40,2,41,0,0,0,0,0,2,12,0,0,1,8,0,0,11,7,0,0,12,7,0,1,4,7,0,2,6,7,0,5,3,7,0,5,7,4,0,6,8,12,0,6,9,0,0,6,10,0,0,8,5,2,0,0,31,0,1,0,0,15,2,3,0,0,17,4,5,0,0,34,6,5,2,6,6,0,18,7,8,0,0,20,8,5,0,0,21,9,5,0,0,16,10,5,0,1,32,29,30,0,2,26,5,22,1,0,2,27,28,29,0,3,30,33,34,1,0,3,38,35,19,1,0,4,13,16,5,2,7,4,4,24,24,25,2,7,4,4,38,26,27,2,7,4,5,19,13,5,0,5,29,17,14,1,8,5,35,12,13,0,6,15,20,3,0,6,17,21,5,0,7,39,19,5,1,8,13,15,17,1,21,18,14,23,15,23,9,27,9,19,13,31,11,14,12,14,14,15,2,8,9,7,8,12,1,8,1,4,6,8,0,7,8,2,2,10,2,1,8,11,2,7,8,2,8,10,0,3,6,8,0,7,8,2,9,1,1,6,8,1,1,8,0,2,7,8,2,8,1,1,6,8,2,2,8,2,8,1,1,7,8,12,1,8,8,1,8,7,2,8,3,8,4,3,7,8,8,9,0,9,1,1,6,9,0,1,8,2,1,9,0,3,7,8,9,2,10,2,2,7,8,9,8,10,1,8,6,2,8,3,9,0,2,6,8,8,9,0,1,1,2,7,8,8,9,0,1,9,1,1,6,8,6,1,8,5,1,10,2,2,8,3,9,1,2,3,8,7,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,7,86,101,114,115,105,111,110,13,86,101,114,115,105,111,110,95,49,95,48,95,48,3,97,100,100,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,15,100,101,115,116,114,111,121,95,109,97,110,97,103,101,114,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,7,103,101,110,101,115,105,115,3,103,101,116,10,103,101,116,95,109,111,100,117,108,101,13,103,111,118,101,114,110,97,110,99,101,95,118,49,2,105,100,8,105,110,100,101,120,95,111,102,12,105,110,105,116,95,103,101,110,101,115,105,115,10,105,110,116,111,95,98,121,116,101,115,11,109,97,110,97,103,101,114,95,105,100,115,15,109,105,103,114,97,116,101,95,118,101,114,115,105,111,110,3,110,101,119,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,11,117,112,103,114,97,100,101,95,99,97,112,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,10,2,8,7,103,101,110,101,115,105,115,0,2,1,22,1,1,2,1,29,8,8,2,2,3,29,8,8,43,8,9,33,10,8,7,3,2,1,22,1,4,2,1,22,1,0,3,0,0,11,26,10,1,17,18,11,0,64,14,0,0,0,0,0,0,0,0,18,2,12,2,11,1,17,18,18,1,12,3,13,2,15,0,9,18,3,9,18,4,56,0,13,2,15,1,14,3,56,1,68,14,11,2,56,2,11,3,2,1,1,0,0,5,6,11,1,15,2,11,2,11,3,17,19,2,2,1,0,0,5,5,11,0,15,2,11,1,17,20,2,3,1,0,0,22,47,10,1,15,0,46,9,18,3,56,3,4,8,5,12,11,1,1,7,1,39,10,1,15,0,9,18,3,56,4,1,56,5,12,3,10,3,56,6,34,4,25,5,29,11,1,1,7,2,39,14,3,17,10,17,8,7,5,33,4,36,5,40,11,1,1,7,3,39,11,1,15,0,9,18,3,11,2,56,7,2,4,1,0,0,5,3,9,18,0,2,5,1,0,0,5,4,11,0,19,0,1,2,6,1,0,0,32,18,14,1,56,1,12,3,10,0,16,1,14,3,56,8,12,2,1,11,0,15,1,11,2,56,9,1,11,1,19,1,17,16,2,7,1,0,0,5,10,11,0,16,0,9,18,3,56,10,4,7,5,9,7,4,39,2,2,0,2,2,2,1,0,28,0],"governance_v1":[161,28,235,11,6,0,0,0,13,1,0,22,2,22,56,3,78,198,1,4,148,2,40,5,188,2,148,2,7,208,4,155,6,8,235,10,96,6,203,11,207,1,10,154,13,72,11,226,13,2,12,228,13,215,9,13,187,23,28,14,215,23,14,0,43,0,38,1,18,1,57,1,71,1,75,2,33,2,56,2,58,2,69,2,70,0,3,8,0,0,7,8,1,6,0,0,1,3,0,0,0,3,0,1,2,0,0,1,4,12,0,2,8,7,0,3,6,7,1,0,0,4,10,7,0,7,5,7,0,7,11,4,0,8,12,12,0,10,9,2,0,0,47,0,1,0,0,13,2,1,0,0,74,3,4,0,0,15,5,1,0,0,62,5,1,0,0,73,6,1,0,0,22,7,1,0,0,31,8,9,0,0,41,10,11,1,6,0,28,12,1,0,0,25,13,1,1,6,0,76,14,15,1,6,0,20,10,1,1,6,1,24,47,12,0,1,27,12,1,0,1,48,25,4,0,2,68,35,11,0,3,19,46,44,1,0,3,35,27,23,1,0,3,37,26,1,1,0,3,49,46,9,1,0,3,50,46,9,1,0,3,55,1,20,1,0,3,65,23,20,1,0,4,39,1,39,1,0,4,40,40,11,0,5,23,29,9,1,0,5,46,29,31,1,0,5,61,32,23,1,0,6,29,23,1,1,3,7,45,44,21,1,8,7,53,0,19,0,7,72,37,38,0,9,64,23,1,1,8,10,32,18,34,0,10,63,18,17,0,22,4,33,22,19,4,18,4,26,17,27,17,28,17,22,34,23,34,24,23,33,41,29,42,30,41,29,45,20,34,17,34,17,4,23,12,21,34,22,12,1,7,8,12,0,3,8,11,7,8,0,7,8,12,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,1,9,0,7,8,12,1,8,6,1,8,4,3,6,8,0,9,0,7,8,12,5,6,8,0,9,0,7,11,1,1,9,0,1,7,8,12,1,11,7,1,8,4,1,10,5,1,5,1,6,8,12,1,8,10,1,11,7,1,9,0,1,8,9,1,8,0,1,9,0,2,5,1,2,8,11,7,8,12,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,1,10,2,12,8,8,3,11,7,1,3,3,5,8,10,5,11,7,1,3,3,8,10,8,9,3,1,6,8,10,1,6,8,9,1,8,8,1,6,8,8,1,11,1,1,9,0,1,8,2,11,1,6,5,6,5,1,1,7,10,5,3,7,10,5,3,3,5,1,6,9,0,1,8,3,1,6,11,7,1,9,0,1,6,8,5,11,67,104,97,110,103,101,83,116,97,116,101,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,10,97,100,100,95,109,101,109,98,101,114,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,12,99,104,101,99,107,95,109,101,109,98,101,114,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,49,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,103,101,110,101,115,105,115,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,9,109,97,120,95,100,101,108,97,121,7,109,101,109,98,101,114,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,6,114,101,109,111,118,101,13,114,101,109,111,118,101,95,109,101,109,98,101,114,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,7,117,112,103,114,97,100,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,8,45,8,10,42,11,7,1,8,5,14,1,17,3,77,3,51,3,52,10,5,44,10,8,9,1,2,10,45,8,10,26,5,66,3,30,11,7,1,3,34,3,59,8,6,21,9,0,36,10,5,16,10,5,67,2,2,2,1,60,8,9,3,2,2,60,8,9,54,2,1,23,0,0,0,0,16,19,64,17,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,35,68,17,11,0,17,31,56,0,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,11,1,64,21,0,0,0,0,0,0,0,0,18,0,56,1,2,1,1,4,0,24,42,10,1,10,2,46,17,35,12,3,46,11,3,17,6,10,1,16,0,20,32,4,20,10,1,16,1,65,21,6,0,0,0,0,0,0,0,0,33,12,4,5,22,9,12,4,11,4,4,25,5,31,11,1,1,11,2,1,7,5,39,10,1,15,2,11,0,11,2,17,15,56,2,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,2,56,3,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,28,19,10,1,15,3,14,2,12,3,46,11,3,56,4,32,4,10,5,14,11,1,1,7,9,39,11,1,15,3,11,2,68,17,2,4,1,0,0,30,21,10,1,10,2,12,3,46,11,3,17,6,10,1,15,3,14,2,12,4,46,11,4,56,5,12,5,1,11,1,15,3,11,5,56,6,1,2,5,1,0,0,1,24,10,4,10,3,10,2,22,36,4,7,5,11,11,1,1,7,7,39,11,2,10,1,15,4,21,11,3,10,1,15,5,21,11,4,11,1,15,6,21,2,6,1,0,0,1,9,11,0,16,3,14,1,56,4,4,6,5,8,7,8,39,2,7,1,0,0,8,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,8,1,0,0,33,75,11,1,46,17,34,12,7,10,0,55,0,20,7,2,33,4,16,11,0,1,7,16,17,16,12,6,5,73,10,0,55,0,20,7,3,33,4,28,11,0,1,7,17,17,16,12,5,5,71,10,0,55,0,20,7,4,33,4,40,11,0,1,7,18,17,16,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,19,17,16,12,3,5,67,11,0,55,0,20,7,0,33,4,62,7,20,17,16,12,2,5,65,7,21,17,16,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,9,1,0,0,1,3,11,0,17,14,2,10,1,0,0,36,86,10,0,16,0,20,4,5,5,11,11,0,1,11,2,1,7,6,39,10,2,46,17,35,12,9,10,0,10,9,17,6,10,2,46,17,34,10,0,16,4,20,22,12,14,10,0,16,5,20,6,0,0,0,0,0,0,0,0,33,4,35,56,7,12,10,5,42,10,14,10,0,16,5,20,22,56,8,12,10,10,2,46,17,34,11,0,16,6,20,22,12,11,11,2,17,31,12,12,14,12,17,32,20,12,13,11,12,12,8,11,9,12,7,11,14,12,6,11,10,12,5,11,11,12,4,56,9,12,3,11,8,11,7,11,6,11,5,11,4,14,3,17,25,11,1,64,17,0,0,0,0,0,0,0,0,64,17,0,0,0,0,0,0,0,0,7,0,57,0,56,10,11,13,18,2,56,11,2,11,1,0,0,43,213,1,10,4,46,17,34,12,11,10,11,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,4,1,7,11,39,10,11,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,4,1,7,14,39,10,2,55,0,20,7,0,33,4,50,7,1,10,2,54,0,21,10,2,46,56,12,7,1,18,3,56,13,10,2,55,0,20,7,1,33,4,57,5,65,11,2,1,11,0,1,11,4,1,7,13,39,11,4,46,17,35,12,15,10,0,10,15,17,6,10,2,54,3,12,12,10,2,54,4,12,10,10,2,55,5,56,14,4,85,8,12,5,5,92,10,11,10,2,55,5,56,15,20,35,12,5,11,5,4,138,1,10,12,14,15,12,6,46,11,6,56,4,32,4,111,10,10,14,15,12,7,46,11,7,56,4,32,12,8,5,113,9,12,8,11,8,4,116,5,126,11,2,1,11,0,1,11,12,1,11,10,1,7,10,39,11,3,4,134,1,11,10,1,10,12,11,15,68,17,5,137,1,11,10,11,15,68,17,5,140,1,11,10,1,10,2,55,5,56,14,4,147,1,8,12,9,5,154,1,11,11,10,2,55,5,56,15,20,38,12,9,11,9,4,205,1,10,0,16,3,65,17,12,14,11,12,46,65,17,12,13,11,14,11,13,17,7,4,184,1,7,2,10,2,54,0,21,11,2,46,56,12,7,2,18,3,56,13,11,0,16,2,56,16,17,13,56,17,2,11,0,1,10,2,55,5,56,18,4,201,1,7,3,10,2,54,0,21,11,2,46,56,12,7,3,18,3,56,13,5,203,1,11,2,1,56,19,2,11,2,1,11,0,1,11,12,1,56,19,2,12,1,4,0,1,45,10,1,46,17,34,10,0,55,1,20,35,4,21,10,0,55,0,20,7,0,33,4,15,5,21,11,0,1,11,1,1,7,12,39,11,1,46,17,35,10,0,55,6,20,33,4,30,5,34,11,0,1,7,15,39,7,4,10,0,54,0,21,11,0,46,56,12,7,4,18,3,56,13,2,0,2,0,7,0,1,0,6,0,3,0,4,0,5,1,9,1,4,1,2,1,7,1,8,1,3,1,1,7,23,8,23,9,23,10,23,11,23,12,23,13,23,0],"governance_v2":[161,28,235,11,6,0,0,0,13,1,0,28,2,28,74,3,102,145,2,4,247,2,58,5,177,3,229,3,7,150,7,131,8,8,153,15,96,6,249,15,129,2,10,250,17,95,11,217,18,2,12,219,18,171,13,13,134,32,38,14,172,32,18,0,54,0,48,0,64,1,22,1,69,1,87,1,93,2,23,2,29,2,41,2,68,2,84,2,85,2,86,0,5,8,0,0,9,8,2,6,0,0,1,0,3,3,0,0,1,3,0,1,4,0,0,1,6,12,0,3,10,7,0,4,8,7,1,0,0,5,13,7,0,7,0,4,1,0,1,8,2,12,1,0,1,10,7,7,0,10,14,4,0,11,11,12,2,7,1,4,1,13,12,2,0,0,59,0,1,0,0,15,2,1,0,0,91,3,4,0,0,18,5,1,0,0,75,5,1,0,0,90,6,1,0,0,89,7,1,0,0,27,8,1,0,0,39,9,10,0,0,51,11,12,2,6,0,0,35,13,1,0,0,32,14,1,2,6,0,0,94,15,16,2,6,0,0,25,17,1,2,6,0,0,28,11,1,2,6,0,1,31,59,13,0,1,34,13,1,0,2,63,40,41,1,0,3,83,37,12,0,4,24,58,52,1,0,4,43,28,26,1,0,4,46,27,1,1,0,4,67,1,22,1,0,4,78,26,22,1,0,5,49,1,23,1,0,5,50,47,12,0,6,30,30,10,1,0,6,58,30,32,1,0,6,74,33,26,1,0,7,61,54,35,1,0,7,79,61,48,1,0,7,92,57,35,1,0,8,36,41,1,1,0,8,47,62,41,1,0,8,60,41,48,1,0,9,37,26,1,1,3,10,57,52,24,1,8,10,65,0,21,0,10,88,45,46,0,11,17,44,1,2,7,4,11,30,55,10,2,7,4,11,65,0,43,2,7,4,11,74,56,39,2,7,4,12,73,64,1,1,12,12,77,26,1,1,8,13,40,20,35,0,13,76,20,19,0,22,4,22,23,44,25,21,23,21,4,20,4,26,19,27,19,28,19,17,39,41,42,39,42,24,26,34,39,44,49,35,50,36,49,35,53,29,39,40,42,42,42,31,39,22,13,32,39,19,4,23,13,30,39,33,39,43,63,1,7,8,14,0,4,6,8,4,7,8,0,8,8,8,5,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,4,6,8,4,7,8,0,3,3,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,2,9,0,9,1,7,8,14,1,8,6,1,8,4,5,6,8,0,9,0,10,11,10,1,9,1,3,7,8,14,7,6,8,0,9,0,7,11,1,2,9,0,9,1,10,11,10,1,9,1,3,1,7,8,14,1,11,7,1,8,4,3,6,8,0,7,11,1,2,9,0,9,1,7,8,14,1,10,5,1,5,1,6,8,14,1,8,12,1,11,7,1,9,0,1,8,8,1,8,11,1,8,0,1,9,0,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,2,9,0,9,1,1,10,2,15,8,8,3,3,3,5,8,12,5,3,3,3,11,13,2,5,3,8,12,8,11,11,10,1,9,1,3,1,9,1,3,10,11,10,1,9,0,3,7,8,14,1,11,10,1,9,0,2,5,3,1,11,13,2,9,0,9,1,3,7,11,13,2,9,0,9,1,9,0,9,1,1,6,8,12,1,6,8,11,1,6,8,8,1,11,9,1,9,0,1,11,1,2,9,0,9,1,1,8,2,17,11,7,1,8,4,11,7,1,8,4,5,5,5,5,1,3,3,7,11,13,2,5,3,3,3,3,7,11,13,2,5,3,11,10,1,9,1,5,3,1,6,9,0,1,8,3,2,7,11,9,1,9,0,11,9,1,9,0,2,6,11,13,2,9,0,9,1,9,0,2,7,11,13,2,9,0,9,1,9,0,1,6,11,9,1,9,0,1,6,11,7,1,9,0,1,6,8,5,11,1,1,1,5,5,7,11,13,2,5,3,3,7,11,13,2,5,3,5,3,3,2,7,11,9,1,9,0,3,2,11,9,1,9,0,7,8,14,1,11,10,1,9,1,2,9,0,5,7,66,97,108,97,110,99,101,11,67,104,97,110,103,101,83,116,97,116,101,4,67,111,105,110,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,3,97,100,100,13,97,100,100,95,103,117,97,114,100,105,97,110,115,11,97,103,97,105,110,115,116,95,110,117,109,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,15,99,104,101,99,107,95,103,117,97,114,100,105,97,110,115,5,99,108,97,105,109,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,9,102,97,118,111,114,95,110,117,109,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,20,103,111,118,101,114,110,97,110,99,101,95,99,111,105,110,95,116,121,112,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,50,9,103,117,97,114,100,105,97,110,115,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,4,106,111,105,110,9,109,97,120,95,100,101,108,97,121,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,24,112,114,111,112,111,115,97,108,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,103,117,97,114,100,105,97,110,115,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,115,112,108,105,116,11,115,116,97,107,101,100,95,99,111,105,110,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,22,117,112,100,97,116,101,95,109,105,110,117,109,117,109,95,115,116,97,107,105,110,103,7,117,112,103,114,97,100,101,5,118,97,108,117,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,22,118,111,116,105,110,103,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,255,255,255,255,255,255,255,255,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,11,57,8,12,53,11,7,1,8,5,52,11,7,1,8,8,55,10,5,16,1,21,3,95,3,62,3,72,3,96,3,56,10,8,11,1,2,13,57,8,12,33,5,81,3,38,3,42,3,70,8,6,26,9,0,80,11,9,1,9,1,44,3,45,11,13,2,5,3,19,3,20,11,13,2,5,3,82,2,2,2,1,71,8,11,3,2,2,71,8,11,66,2,1,36,0,0,0,0,18,22,64,19,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,46,68,19,11,0,17,37,56,0,56,1,64,19,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,6,1,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,64,24,0,0,0,0,0,0,0,0,18,0,56,2,2,1,1,0,0,10,34,10,1,16,0,20,32,4,12,10,1,16,1,65,24,6,0,0,0,0,0,0,0,0,33,12,4,5,14,9,12,4,11,4,4,17,5,21,11,1,1,7,6,39,10,1,15,2,11,2,56,3,10,1,15,3,11,3,56,4,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,3,56,5,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,29,19,10,1,15,4,14,2,12,3,46,11,3,56,6,32,4,10,5,14,11,1,1,7,10,39,11,1,15,4,11,2,68,19,2,4,1,0,0,31,21,10,1,10,2,12,3,46,11,3,17,7,10,1,15,4,14,2,12,4,46,11,4,56,7,12,5,1,11,1,15,4,11,5,56,8,1,2,5,1,0,0,1,9,11,2,10,1,15,5,21,11,3,11,1,15,6,21,2,6,1,0,0,1,33,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,9,11,1,1,7,8,39,10,4,10,3,10,2,22,36,4,16,5,20,11,1,1,7,8,39,11,2,10,1,15,7,21,11,3,10,1,15,8,21,11,4,11,1,15,9,21,2,7,1,0,0,1,9,11,0,16,4,14,1,56,6,4,6,5,8,7,9,39,2,8,1,0,0,9,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,9,1,0,0,34,75,11,1,46,17,45,12,7,10,0,55,0,20,7,3,33,4,16,11,0,1,7,21,17,18,12,6,5,73,10,0,55,0,20,7,4,33,4,28,11,0,1,7,22,17,18,12,5,5,71,10,0,55,0,20,7,5,33,4,40,11,0,1,7,23,17,18,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,24,17,18,12,3,5,67,11,0,55,0,20,7,1,33,4,62,7,25,17,18,12,2,5,65,7,26,17,18,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,10,1,0,0,1,3,11,0,17,16,2,11,1,0,0,38,103,10,0,16,0,20,4,5,5,11,11,0,1,11,4,1,7,7,39,11,2,10,3,10,4,56,9,12,18,10,3,10,0,16,5,20,38,4,23,5,29,11,0,1,11,4,1,7,16,39,10,4,46,17,46,12,11,10,4,46,17,45,12,12,10,12,10,0,16,7,20,22,12,19,10,19,10,0,16,8,20,22,12,13,11,12,11,0,16,9,20,22,12,14,10,4,56,10,12,15,13,15,10,11,10,3,56,11,10,4,17,37,12,16,14,16,17,38,20,12,17,11,16,12,10,11,11,12,9,11,19,12,8,11,13,12,7,11,14,12,6,56,12,12,5,11,10,11,9,11,8,11,7,11,6,14,5,17,25,11,1,11,18,56,13,11,3,11,15,6,0,0,0,0,0,0,0,0,11,4,56,10,7,1,57,0,56,14,11,17,18,2,56,15,2,12,1,0,0,51,175,2,10,6,46,17,45,12,17,10,17,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,6,1,7,12,39,10,17,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,6,1,7,15,39,10,2,55,0,20,7,1,33,4,50,7,2,10,2,54,0,21,10,2,46,56,16,7,2,18,3,56,17,10,2,55,0,20,7,2,33,4,57,5,65,11,2,1,11,0,1,11,6,1,7,14,39,10,6,46,17,46,12,22,10,2,54,3,12,20,10,2,54,4,12,16,11,3,10,4,11,6,56,9,12,21,11,17,10,2,55,5,20,35,4,237,1,11,0,1,10,2,54,6,11,21,56,13,56,18,1,11,5,4,158,1,10,2,55,7,20,10,4,22,10,2,54,7,21,11,4,12,18,10,20,10,22,12,9,46,11,9,56,19,4,119,11,18,10,20,10,22,56,20,22,12,18,10,16,10,22,12,10,46,11,10,56,19,4,151,1,11,16,10,22,56,20,12,14,10,2,55,7,20,10,14,22,10,2,54,7,21,10,2,55,8,20,10,14,23,10,2,54,8,21,11,18,11,14,22,12,18,5,153,1,11,16,1,11,20,11,22,11,18,56,11,5,219,1,10,2,55,8,20,10,4,22,10,2,54,8,21,11,4,12,15,10,16,10,22,12,11,46,11,11,56,19,4,181,1,11,15,10,16,10,22,56,20,22,12,15,10,20,10,22,12,12,46,11,12,56,19,4,213,1,11,20,10,22,56,20,12,19,10,2,55,8,20,10,19,22,10,2,54,8,21,10,2,55,7,20,10,19,23,10,2,54,7,21,11,15,11,19,22,12,15,5,215,1,11,20,1,11,16,11,22,11,15,56,11,10,2,55,7,20,10,2,55,8,20,22,11,2,55,6,56,21,33,4,232,1,5,234,1,7,19,39,56,22,12,8,5,173,2,11,20,1,11,16,1,11,21,56,23,10,2,55,7,20,10,2,55,8,20,22,12,23,10,23,10,2,55,7,20,17,8,4,136,2,11,23,10,0,16,6,20,38,12,13,5,138,2,9,12,13,11,13,4,157,2,7,3,10,2,54,0,21,11,2,46,56,16,7,3,18,3,56,17,11,0,16,3,56,24,17,15,56,25,12,7,5,171,2,11,0,1,7,4,10,2,54,0,21,11,2,46,56,16,7,4,18,3,56,17,56,22,12,7,11,7,12,8,11,8,2,13,1,4,0,19,41,10,2,46,17,45,10,1,55,1,20,35,4,23,10,1,55,0,20,7,1,33,4,15,5,23,11,1,1,11,0,1,11,2,1,7,13,39,11,2,46,17,46,12,3,11,0,11,3,17,7,7,5,10,1,54,0,21,11,1,46,56,16,7,5,18,3,56,17,2,14,1,4,0,60,129,1,10,1,46,17,45,12,8,10,0,55,0,20,7,3,33,4,13,8,12,2,5,19,10,0,55,0,20,7,4,33,12,2,11,2,4,24,8,12,3,5,30,10,0,55,0,20,7,5,33,12,3,11,3,4,35,8,12,4,5,41,11,8,10,0,55,1,20,38,12,4,11,4,4,44,5,50,11,0,1,11,1,1,7,20,39,10,1,46,17,46,12,10,10,0,54,3,12,9,10,0,54,4,12,7,10,9,10,10,12,5,46,11,5,56,19,4,90,11,7,1,11,9,10,10,56,20,12,12,10,0,54,6,10,12,56,26,11,1,56,27,11,10,56,28,10,0,55,7,20,11,12,23,11,0,54,7,21,5,128,1,11,9,1,10,7,10,10,12,6,46,11,6,56,19,4,100,5,108,11,0,1,11,1,1,11,7,1,7,11,39,11,7,10,10,56,20,12,11,10,0,54,6,10,11,56,26,11,1,56,27,11,10,56,28,10,0,55,8,20,11,11,23,11,0,54,8,21,2,0,4,0,10,0,2,0,1,0,3,0,8,0,9,0,5,0,6,0,7,1,12,1,4,1,2,1,9,1,11,1,3,1,7,1,8,1,10,10,36,11,36,12,36,13,36,14,36,15,36,16,36,17,36,18,36,0],"lending_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,126,4,136,1,2,5,138,1,175,1,7,185,2,166,4,8,223,6,32,6,255,6,41,12,168,7,192,10,0,22,0,9,0,23,1,0,7,0,0,20,0,1,0,0,21,0,1,0,0,16,0,1,0,0,19,0,1,0,0,18,0,1,0,0,15,0,1,0,0,17,0,1,0,0,10,2,3,0,0,1,3,2,0,0,14,4,3,0,0,5,3,4,0,0,12,5,3,0,0,3,3,6,0,0,13,7,3,0,0,4,3,7,0,1,2,3,11,0,1,11,11,3,0,2,6,17,18,0,2,7,17,19,0,2,8,17,1,0,2,24,9,0,0,2,25,10,0,0,2,26,13,0,0,2,27,12,0,0,2,28,15,16,1,1,24,1,0,1,2,4,13,3,8,0,2,1,10,2,6,13,3,3,8,0,8,0,2,4,13,3,8,0,3,5,13,3,8,0,3,2,2,10,13,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,11,10,2,10,2,10,2,10,2,3,3,2,3,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,3,10,2,10,2,10,2,16,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,2,3,8,0,13,13,8,0,13,13,10,2,10,2,10,2,10,2,10,2,3,3,2,3,3,13,8,0,13,3,3,10,2,3,10,10,2,10,2,10,2,3,13,10,13,13,3,2,13,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,101,110,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,101,110,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,8,24,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,22,11,4,2,8,1,0,0,14,92,6,0,0,0,0,0,0,0,0,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,1,14,1,17,17,12,11,11,6,11,5,22,12,6,6,8,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,2,14,2,17,18,12,8,11,6,11,5,22,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,3,14,3,17,17,12,9,11,6,11,5,22,12,6,11,9,52,12,5,14,0,10,6,10,6,10,5,22,56,0,17,15,12,10,11,6,11,5,22,12,6,6,1,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,4,14,4,17,19,12,7,11,6,11,5,22,14,0,65,1,33,4,85,5,87,7,0,39,11,11,11,8,11,10,11,7,2,9,1,0,0,20,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,20,13,6,11,1,17,21,13,6,11,2,17,21,11,3,17,16,12,7,13,6,14,7,65,1,75,17,20,13,6,11,7,17,23,11,4,17,16,12,8,13,6,14,8,65,1,75,17,20,13,6,11,8,17,23,13,6,11,5,17,22,11,6,2,10,1,0,0,21,141,1,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,18,12,11,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,18,12,7,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,15,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,19,12,10,11,9,11,8,22,14,0,65,1,33,4,132,1,5,134,1,7,0,39,11,16,11,11,11,7,11,12,11,15,11,10,2,11,1,0,0,8,27,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,21,13,4,7,6,17,22,11,4,2,12,1,0,0,22,118,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,1,14,1,17,17,12,11,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,2,14,2,17,18,12,10,11,7,11,6,22,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,3,14,3,17,17,12,13,11,7,11,6,22,12,7,11,13,52,12,6,14,0,10,7,10,7,10,6,22,56,0,17,15,12,12,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,4,14,4,17,18,12,9,11,7,11,6,22,12,7,6,1,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,5,14,5,17,19,12,8,11,7,11,6,22,12,7,10,8,7,6,33,4,102,5,104,7,1,39,11,7,14,0,65,1,33,4,110,5,112,7,0,39,11,11,11,10,11,12,11,9,11,8,2,13,1,0,0,23,32,64,1,0,0,0,0,0,0,0,0,12,3,14,0,65,18,12,4,13,3,10,4,75,17,20,6,0,0,0,0,0,0,0,0,12,2,10,2,10,4,35,4,27,5,16,13,3,14,0,10,2,66,18,20,17,20,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,13,3,11,1,17,22,11,3,2,14,1,0,0,24,76,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,1,14,1,17,17,12,10,11,8,11,4,22,12,8,72,0,0,12,7,64,18,0,0,0,0,0,0,0,0,12,6,10,7,10,10,35,4,51,5,27,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,2,14,2,17,17,12,5,13,6,11,5,68,18,11,8,11,4,22,12,8,11,7,72,1,0,22,12,7,5,22,6,1,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,3,14,3,17,19,12,9,11,8,11,4,22,14,0,65,1,33,4,71,5,73,7,0,39,11,6,11,9,2,0],"lending_core_storage":[161,28,235,11,6,0,0,0,12,1,0,20,2,20,52,3,72,245,2,4,189,3,40,5,229,3,172,2,7,145,6,149,16,8,166,22,96,6,134,23,20,10,154,23,101,12,255,23,239,16,13,238,40,62,15,172,41,6,0,77,0,17,0,43,0,91,1,122,2,31,2,87,2,109,2,112,2,115,0,6,8,0,0,11,4,0,0,4,4,0,0,5,4,0,0,1,4,0,1,0,12,0,1,8,12,0,2,3,0,0,5,2,8,0,6,10,4,0,7,7,12,2,7,1,4,1,9,9,2,0,0,72,0,1,0,0,93,2,1,0,0,104,3,1,0,0,102,3,1,0,0,106,4,1,0,0,105,4,1,0,0,99,4,1,0,0,103,4,1,0,0,100,4,1,0,0,101,5,1,0,0,45,6,7,0,0,61,8,9,0,0,73,10,11,0,0,30,10,11,0,0,58,6,12,0,0,42,13,11,0,0,41,10,11,0,0,65,13,9,0,0,63,13,9,0,0,66,13,14,0,0,64,13,14,0,0,67,13,14,0,0,69,15,9,0,0,68,15,9,0,0,60,10,12,0,0,52,10,9,0,0,62,10,9,0,0,59,10,9,0,0,57,10,9,0,0,46,10,9,0,0,50,10,9,0,0,53,10,9,0,0,56,10,9,0,0,51,10,9,0,0,55,10,9,0,0,54,10,9,0,0,48,10,9,0,0,47,10,9,0,0,49,10,16,0,0,44,6,17,0,0,85,18,1,0,0,29,18,1,0,0,84,18,1,0,0,28,18,1,0,0,14,15,1,0,0,96,15,1,0,0,13,15,1,0,0,95,15,1,0,0,15,15,1,0,0,97,15,1,0,0,119,19,1,0,0,117,20,1,0,0,118,21,1,0,0,116,22,1,0,0,40,23,1,0,1,45,17,7,0,1,92,0,26,0,3,90,1,9,0,4,34,46,11,1,0,4,71,46,48,1,0,4,94,49,31,1,0,5,110,8,12,0,6,86,24,25,0,7,12,34,1,2,7,4,7,20,32,39,2,7,4,7,23,36,37,2,7,4,7,34,32,11,2,7,4,7,81,40,12,2,7,4,7,86,24,28,2,7,4,7,94,36,44,2,7,4,8,107,31,1,1,8,68,27,68,29,70,30,66,27,68,33,63,27,65,27,64,27,67,27,66,29,64,29,66,33,64,33,69,33,63,33,65,29,58,7,59,7,60,7,63,29,3,6,8,7,7,8,6,7,8,11,0,17,6,8,7,7,8,0,6,8,8,13,1,1,3,15,15,15,15,15,15,15,15,15,7,8,11,4,6,8,7,7,8,0,13,1,4,6,8,7,7,8,0,13,15,7,6,8,7,7,8,0,13,15,15,15,15,1,7,8,0,1,13,1,6,8,8,1,15,2,7,8,0,13,1,1,1,3,2,7,8,0,3,1,10,13,3,7,8,0,3,13,4,15,15,15,15,1,6,8,5,4,7,8,0,13,3,15,4,7,8,0,6,8,8,3,15,3,7,8,0,13,15,6,7,8,0,13,15,15,15,15,4,7,8,0,13,15,15,3,7,8,0,6,8,8,3,1,7,8,11,1,8,9,1,8,5,2,13,8,2,1,11,10,2,9,0,9,1,2,3,8,1,1,8,0,1,9,0,2,6,11,10,2,9,0,9,1,9,0,2,3,15,3,7,11,10,2,9,0,9,1,9,0,9,1,1,7,8,2,2,7,11,10,2,9,0,9,1,9,0,1,7,9,1,1,7,8,4,1,6,9,1,1,6,11,10,2,9,0,9,1,2,15,6,8,2,1,6,8,4,2,15,7,8,3,1,9,1,1,7,8,1,2,6,10,9,0,6,9,0,2,3,7,8,1,2,1,3,2,7,10,9,0,3,2,3,7,8,2,6,65,112,112,67,97,112,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,11,82,101,115,101,114,118,101,68,97,116,97,13,83,99,97,108,101,100,66,97,108,97,110,99,101,7,83,116,111,114,97,103,101,5,84,97,98,108,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,85,115,101,114,73,110,102,111,3,97,100,100,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,17,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,16,98,97,115,101,95,98,111,114,114,111,119,95,114,97,116,101,6,98,111,114,114,111,119,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,18,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,49,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,50,23,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,5,99,108,111,99,107,22,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,11,99,111,108,108,97,116,101,114,97,108,115,8,99,111,110,116,97,105,110,115,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,23,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,22,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,13,100,116,111,107,101,110,95,115,99,97,108,101,100,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,10,103,101,116,95,97,112,112,95,105,100,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,18,103,101,116,95,114,101,115,101,114,118,101,95,108,101,110,103,116,104,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,13,103,101,116,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,2,105,100,8,105,110,100,101,120,95,111,102,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,12,105,115,111,108,97,116,101,95,100,101,98,116,19,108,97,115,116,95,97,118,101,114,97,103,101,95,117,112,100,97,116,101,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,13,108,105,113,117,105,100,95,97,115,115,101,116,115,5,108,111,97,110,115,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,13,111,116,111,107,101,110,95,115,99,97,108,101,100,3,114,97,121,8,114,97,121,95,109,97,116,104,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,20,114,101,103,105,115,116,101,114,95,110,101,119,95,114,101,115,101,114,118,101,6,114,101,109,111,118,101,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,8,114,101,115,101,114,118,101,115,22,115,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,22,115,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,23,115,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,27,115,101,116,95,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,26,115,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,21,115,101,116,95,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,22,115,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,8,116,114,101,97,115,117,114,121,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,10,117,115,101,114,95,105,110,102,111,115,10,117,115,101,114,95,115,116,97,116,101,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,70,8,9,16,8,5,98,11,10,2,13,8,2,120,11,10,2,3,8,1,1,2,5,18,15,75,15,82,10,13,33,10,13,83,10,13,2,2,17,73,1,27,1,74,15,76,15,113,3,114,15,108,15,21,15,36,15,38,15,35,15,37,15,32,15,22,15,24,8,4,89,8,3,39,8,3,3,2,2,121,11,10,2,3,15,111,15,4,2,4,19,15,25,15,26,15,88,15,0,1,0,0,1,13,10,2,17,62,11,0,11,1,10,2,17,56,10,2,56,0,11,2,56,1,18,0,56,2,2,1,1,0,0,1,49,10,1,16,0,10,3,56,3,32,4,7,5,15,11,1,1,11,16,1,11,2,1,7,0,39,11,1,15,0,11,3,11,4,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,2,17,11,11,6,11,7,11,8,11,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,57,17,57,11,10,11,11,11,12,11,13,11,14,11,15,18,4,10,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,11,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,18,2,56,5,2,2,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,1,21,2,3,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,2,21,2,4,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,3,21,2,5,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,4,21,2,6,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,5,21,2,7,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,6,21,2,8,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,7,21,2,9,1,0,0,38,23,11,1,15,0,11,2,56,6,15,8,12,7,11,3,10,7,15,9,21,11,4,10,7,15,10,21,11,5,10,7,15,11,21,11,6,11,7,15,12,21,2,10,1,0,0,1,4,11,0,16,13,17,55,2,11,1,0,0,1,6,11,0,17,61,6,232,3,0,0,0,0,0,0,26,77,2,12,1,0,0,1,7,11,0,16,0,11,1,56,7,16,1,20,2,13,1,0,0,1,7,11,0,16,0,11,1,56,7,16,2,20,2,14,1,0,0,1,4,11,0,16,0,56,8,2,15,1,0,0,12,8,11,0,15,14,11,1,12,2,46,11,2,56,9,2,16,1,0,0,7,8,11,0,15,0,11,1,12,2,46,11,2,56,3,2,17,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,15,20,2,18,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,16,20,2,19,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,17,20,2,20,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,18,20,2,21,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,19,20,2,22,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,20,16,21,10,1,56,11,4,19,11,4,16,20,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,23,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,22,16,21,10,1,56,11,4,19,11,4,16,22,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,24,1,0,0,1,7,11,0,16,0,11,1,56,7,16,23,20,2,25,1,0,0,1,7,11,0,16,0,11,1,56,7,16,24,20,2,26,1,0,0,1,7,11,0,16,0,11,1,56,7,16,3,20,2,27,1,0,0,1,7,11,0,16,0,11,1,56,7,16,4,20,2,28,1,0,0,1,7,11,0,16,0,11,1,56,7,16,5,20,2,29,1,0,0,1,7,11,0,16,0,11,1,56,7,16,7,20,2,30,1,0,0,1,7,11,0,16,0,11,1,56,7,16,6,20,2,31,1,0,0,1,7,11,0,16,0,11,1,56,7,16,25,20,2,32,1,0,0,1,8,11,0,16,0,11,1,56,7,16,20,16,26,20,2,33,1,0,0,1,8,11,0,16,0,11,1,56,7,16,22,16,26,20,2,34,1,0,0,1,7,11,0,16,0,11,1,56,7,16,27,20,2,35,1,0,0,1,7,11,0,16,0,11,1,56,7,16,28,20,2,36,1,0,0,1,7,11,0,16,0,11,1,56,7,16,29,20,2,37,1,0,0,1,7,11,0,16,0,11,1,56,7,16,30,20,2,38,1,0,0,42,19,11,0,16,0,11,1,56,7,16,8,12,2,10,2,16,9,20,10,2,16,10,20,10,2,16,11,20,11,2,16,12,20,2,39,3,0,0,1,3,11,0,16,13,2,40,3,0,0,43,35,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,41,3,0,0,43,44,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,42,3,0,0,43,35,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,43,3,0,0,43,44,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,44,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,17,14,2,56,16,32,4,16,11,3,15,17,11,2,68,7,5,18,11,3,1,2,45,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,17,14,2,56,17,12,3,4,17,11,4,15,17,11,3,56,18,1,5,19,11,4,1,2,46,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,18,14,2,56,16,32,4,16,11,3,15,18,11,2,68,7,5,18,11,3,1,2,47,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,18,14,2,56,17,12,3,4,17,11,4,15,18,11,3,56,18,1,5,19,11,4,1,2,48,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,19,14,2,56,16,32,4,16,11,3,15,19,11,2,68,7,5,18,11,3,1,2,49,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,19,14,2,56,17,12,3,4,17,11,4,15,19,11,3,56,18,1,5,19,11,4,1,2,50,3,0,0,45,15,11,0,15,14,11,2,56,15,12,4,11,1,17,11,10,4,15,15,21,11,3,11,4,15,16,21,2,51,3,0,0,35,10,11,0,15,0,11,1,56,6,12,3,11,2,11,3,15,24,21,2,52,3,0,0,50,30,10,0,15,0,10,1,56,6,12,7,11,2,10,7,15,30,21,11,3,10,7,15,28,21,11,4,11,7,15,25,21,10,0,16,0,10,1,56,7,16,23,20,12,6,11,0,11,1,11,6,11,5,17,40,2,53,3,0,0,35,14,11,0,15,0,11,1,56,6,12,4,11,2,10,4,15,29,21,11,3,11,4,15,27,21,2,54,1,0,0,12,26,10,0,15,14,10,2,12,3,46,11,3,56,9,32,4,21,11,0,15,14,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,1,17,11,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,18,1,56,19,5,25,11,0,1,11,1,1,2,0,2,2,0,2,1,2,5,2,6,2,7,2,12,2,13,2,14,4,0,4,1,4,2,4,3,0,1,0,3,1,1,1,0,1,2,1,3,1,4,2,15,3,0,2,16,2,4,2,2,2,3,3,1,2,9,2,11,2,8,2,10,0,78,0,79,0,80,0],"lending_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,36,2,36,68,3,104,198,1,4,174,2,8,5,182,2,233,3,7,159,6,228,8,8,131,15,128,1,6,131,16,30,10,161,16,36,12,197,16,230,11,0,58,0,17,0,30,0,42,0,56,0,57,0,59,0,64,0,65,0,80,0,82,1,63,2,23,2,24,2,35,2,77,2,79,3,76,0,6,3,0,0,10,3,0,1,0,12,0,2,4,7,0,3,5,8,0,5,13,8,0,7,9,8,0,8,8,12,0,9,15,12,0,10,3,12,0,11,7,7,1,0,0,12,1,8,0,13,2,12,1,0,1,15,11,2,0,16,14,2,0,17,12,12,0,0,78,0,1,0,0,81,2,1,0,0,19,2,1,0,0,70,0,1,0,0,60,0,1,0,0,18,0,1,0,0,21,0,1,0,2,47,17,14,0,2,48,17,10,0,3,22,4,1,0,4,25,14,15,0,4,26,14,35,0,4,27,14,38,0,4,28,14,23,0,4,44,1,16,0,4,45,1,16,0,4,46,1,16,0,4,52,1,16,0,4,53,1,16,0,4,54,1,16,0,5,43,5,6,0,6,18,39,1,0,6,21,39,1,0,6,36,13,1,0,6,37,36,1,0,6,38,13,1,0,6,39,13,1,0,6,40,13,30,0,8,41,24,25,0,8,50,9,10,0,8,51,9,30,0,9,49,11,12,0,10,66,7,8,0,10,67,21,22,0,10,68,21,22,0,10,71,31,12,0,11,29,29,19,1,0,11,55,27,28,1,0,14,34,19,1,1,3,38,18,37,26,36,26,38,32,10,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,10,2,6,8,11,7,8,14,0,11,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,11,12,1,8,13,10,2,6,8,11,7,8,14,17,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,10,2,2,13,3,3,8,3,8,3,13,8,3,1,6,8,4,1,7,8,5,1,6,8,2,8,7,8,15,7,8,9,6,8,2,10,2,7,8,7,7,8,8,6,8,11,7,8,14,4,8,3,8,3,15,10,2,2,7,8,7,8,3,1,13,2,6,8,8,8,3,1,3,7,6,8,7,7,8,5,7,8,6,6,8,11,3,13,15,1,10,2,4,13,3,8,3,2,1,2,1,6,8,3,1,8,0,1,9,0,27,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,6,7,8,15,7,8,9,6,8,2,10,2,6,8,11,7,8,14,2,8,3,10,2,6,13,3,3,8,3,8,3,2,3,7,8,7,13,13,1,11,10,1,8,3,1,8,3,1,6,11,10,1,9,0,1,1,1,11,10,1,9,0,1,15,11,7,8,15,7,8,9,6,8,2,7,8,7,8,3,8,3,13,3,15,11,12,1,8,13,6,8,11,1,8,1,26,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,26,7,8,5,7,8,6,6,8,11,3,3,13,13,8,3,7,8,5,7,8,6,6,8,11,3,13,15,10,2,2,15,13,8,3,8,3,3,3,3,13,13,8,3,5,13,3,8,3,3,2,8,6,8,7,7,8,5,7,8,6,6,8,11,3,3,13,13,14,8,3,7,8,5,7,8,6,6,8,11,3,13,10,2,2,6,13,10,13,3,3,3,8,3,2,10,13,2,6,6,8,7,7,8,5,7,8,6,6,8,11,3,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,76,101,110,100,105,110,103,67,111,114,101,69,118,101,110,116,6,79,112,116,105,111,110,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,6,98,111,114,114,111,119,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,112,111,111,108,95,105,100,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,9,108,105,113,117,105,100,97,116,101,17,108,105,113,117,105,100,97,116,101,95,117,115,101,114,95,105,100,5,110,111,110,99,101,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,5,114,101,112,97,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,14,115,101,110,100,101,114,95,117,115,101,114,95,105,100,8,115,101,113,117,101,110,99,101,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,18,115,111,117,114,99,101,95,99,104,97,105,110,95,110,111,110,99,101,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,9,62,3,72,3,74,13,32,13,31,13,69,10,2,16,15,61,3,20,2,1,2,5,73,3,74,13,75,3,33,8,3,20,2,0,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,26,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,18,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,1,1,4,0,20,168,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,26,12,37,11,26,17,13,12,27,12,35,12,34,12,24,12,33,12,36,10,27,17,19,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,24,77,12,25,10,1,11,34,17,29,12,28,11,2,11,37,12,16,46,11,16,17,31,12,29,14,35,17,8,12,30,10,1,10,28,11,30,17,28,12,31,14,31,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,31,56,2,12,32,10,1,10,6,11,5,10,9,10,29,10,28,11,25,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,27,12,23,10,1,10,32,17,30,10,23,38,4,113,5,125,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,32,10,35,10,36,10,33,10,23,11,7,11,9,17,35,12,11,11,32,12,12,10,36,12,13,10,33,12,14,10,27,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,33,11,29,11,36,14,35,17,8,11,28,14,35,17,7,11,23,6,0,0,0,0,0,0,0,0,11,27,18,0,56,0,2,2,1,4,0,33,167,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,25,12,36,11,25,17,13,12,26,12,34,12,33,12,23,12,32,12,35,10,26,17,15,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,23,77,12,24,10,1,11,33,17,29,12,27,11,2,11,36,12,16,46,11,16,17,31,12,28,14,34,17,8,12,29,10,1,10,27,11,29,17,28,12,30,14,30,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,30,56,2,12,31,10,1,10,6,11,5,10,9,10,28,10,27,10,24,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,23,10,1,10,31,17,30,10,24,38,4,112,5,124,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,31,10,34,10,35,10,32,10,24,11,7,11,9,17,35,12,11,11,31,12,12,10,35,12,13,10,32,12,14,10,26,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,32,11,28,11,35,14,34,17,8,11,27,14,34,17,7,11,24,6,0,0,0,0,0,0,0,0,11,26,18,0,56,0,2,3,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,25,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,17,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,4,1,4,0,34,97,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,24,12,26,12,29,12,28,11,24,17,11,12,25,12,30,12,35,12,32,12,33,11,2,10,29,12,17,46,11,17,17,31,12,31,10,1,11,28,17,29,12,27,10,1,11,35,17,29,12,34,10,1,10,6,10,5,10,8,10,31,10,27,10,26,12,23,12,22,12,21,12,20,12,19,12,18,46,11,18,11,19,11,20,11,21,11,22,11,23,17,26,11,1,11,6,11,5,11,8,10,31,10,30,10,34,11,27,12,16,12,15,12,14,12,13,12,12,12,11,12,10,46,11,10,11,11,11,12,11,13,11,14,11,15,11,16,17,24,11,32,11,31,11,33,14,29,17,8,11,34,14,29,17,7,11,26,11,30,11,25,18,0,56,0,2,5,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,14,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,21,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,6,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,16,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,22,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,0],"lending_logic":[161,28,235,11,6,0,0,0,11,1,0,27,2,27,24,3,51,189,4,4,240,4,4,5,244,4,199,3,7,187,8,241,18,8,172,27,96,6,140,28,144,2,10,156,30,15,12,171,30,253,36,15,168,67,4,0,93,0,48,0,90,0,91,0,104,0,106,0,108,0,111,0,117,1,135,1,2,35,2,40,2,95,0,2,3,0,1,1,0,0,3,5,8,0,4,4,8,0,5,3,12,0,10,0,8,0,0,42,0,1,0,0,44,2,1,0,0,45,2,3,0,0,41,2,1,0,0,43,2,1,0,0,11,4,1,0,0,31,4,1,0,0,34,5,1,0,0,103,6,7,0,0,102,8,7,0,0,83,9,7,0,0,85,10,7,0,0,88,11,7,0,0,84,11,7,0,0,89,11,7,0,0,87,12,7,0,0,33,13,1,0,0,81,12,7,0,0,82,10,7,0,0,128,1,10,3,0,0,126,14,3,0,0,125,11,3,0,0,132,1,14,3,0,0,131,1,11,3,0,0,127,10,3,0,0,129,1,10,3,0,0,133,1,10,3,0,0,134,1,10,3,0,0,28,15,3,0,0,19,15,3,0,0,24,10,3,0,0,25,16,3,0,0,27,17,18,0,0,18,19,20,0,0,119,9,3,0,0,118,9,3,0,0,37,12,1,0,0,99,21,1,0,0,15,21,1,0,0,97,21,1,0,0,13,21,1,0,0,6,8,1,0,0,113,8,1,0,0,120,22,1,0,0,123,23,1,0,0,121,24,1,0,2,51,1,27,0,2,55,1,27,0,2,56,1,27,0,2,61,1,27,0,2,65,1,27,0,2,69,1,27,0,2,80,1,27,0,3,7,11,1,0,3,8,11,1,0,3,9,11,1,0,3,14,53,1,0,3,16,53,1,0,3,30,9,7,0,3,39,30,1,0,3,46,9,7,0,3,47,12,7,0,3,49,61,31,0,3,52,9,3,0,3,53,9,3,0,3,54,9,3,0,3,57,9,3,0,3,58,9,3,0,3,59,9,3,0,3,60,9,3,0,3,62,9,3,0,3,63,9,3,0,3,64,9,3,0,3,66,9,3,0,3,67,9,3,0,3,68,9,26,0,3,70,57,3,0,3,72,9,3,0,3,73,12,3,0,3,74,12,37,0,3,75,12,3,0,3,76,12,37,0,3,77,12,37,0,3,78,11,3,0,3,79,11,3,0,3,86,9,7,0,3,98,53,1,0,3,100,53,1,0,3,114,11,1,0,3,115,11,1,0,3,116,11,1,0,3,121,63,1,0,3,122,6,1,0,3,123,60,1,0,3,124,58,1,0,4,32,32,1,0,4,71,47,48,0,5,50,62,3,0,6,20,20,3,0,6,21,6,3,0,6,22,33,3,0,6,23,33,3,0,6,26,63,3,0,7,96,18,3,0,7,109,1,3,0,7,110,18,3,0,7,112,18,3,0,8,12,18,3,0,8,17,18,3,0,8,101,18,3,0,9,36,39,7,1,0,11,38,29,1,1,3,12,107,49,26,0,111,28,110,31,8,6,8,4,7,8,2,7,8,3,6,8,5,3,3,13,13,0,7,6,8,4,7,8,2,7,8,3,6,8,5,3,13,15,1,15,6,6,8,4,7,8,2,7,8,3,6,8,5,3,13,7,6,8,1,6,8,4,7,8,2,6,8,5,13,3,15,3,7,8,2,13,15,1,1,3,7,8,2,3,15,2,7,8,2,13,3,7,8,2,7,8,3,3,3,7,8,2,3,13,2,7,8,2,3,4,7,8,3,7,8,2,3,6,8,5,4,7,8,2,7,8,3,3,13,3,7,8,3,13,15,4,7,8,2,7,8,3,3,3,6,7,8,2,7,8,3,3,3,13,13,2,15,15,7,7,8,3,13,15,13,15,15,15,4,15,15,15,15,4,7,8,2,3,13,15,4,7,8,2,7,8,3,6,8,5,3,3,7,8,2,6,8,5,13,4,6,8,4,7,8,2,13,15,12,1,15,15,15,15,15,15,15,15,3,15,15,1,3,1,2,1,8,0,1,9,0,3,7,8,2,6,8,5,3,1,13,3,7,8,3,10,13,6,8,5,3,15,15,15,5,15,15,15,15,3,3,1,15,15,5,1,15,6,13,15,10,13,1,10,13,2,1,10,13,2,6,10,9,0,6,9,0,3,1,13,10,13,2,10,13,10,13,7,6,13,15,15,10,13,3,3,15,7,15,3,3,6,13,15,10,13,15,6,6,13,15,10,13,3,3,15,6,3,3,6,13,15,10,13,15,2,2,15,2,7,8,3,13,3,15,2,3,2,3,2,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,6,15,15,15,15,15,15,6,15,3,3,6,13,10,13,3,4,7,8,2,13,3,15,3,6,13,15,10,13,5,15,6,13,15,15,10,13,7,15,15,15,15,15,15,15,1,6,8,5,4,7,8,2,6,8,5,3,15,9,15,15,15,15,15,15,15,15,15,6,7,8,2,13,15,15,15,15,1,7,8,2,3,6,8,4,13,13,4,7,8,2,13,15,15,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,23,76,101,110,100,105,110,103,67,111,114,101,69,120,101,99,117,116,101,69,118,101,110,116,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,16,97,100,100,95,105,115,111,108,97,116,101,95,100,101,98,116,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,6,97,109,111,117,110,116,13,97,115,95,99,111,108,108,97,116,101,114,97,108,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,100,116,111,107,101,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,111,116,111,107,101,110,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,115,99,97,108,101,100,28,99,97,108,99,117,108,97,116,101,95,97,99,116,117,97,108,95,108,105,113,117,105,100,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,35,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,98,97,115,101,95,100,105,115,99,111,117,110,116,30,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,100,105,115,99,111,117,110,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,25,99,97,108,99,117,108,97,116,101,95,109,97,120,95,108,105,113,117,105,100,97,116,105,111,110,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,9,99,97,108,108,95,116,121,112,101,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,22,99,104,101,99,107,95,117,115,101,114,95,102,114,101,115,104,95,112,114,105,99,101,19,99,108,97,105,109,95,102,114,111,109,95,116,114,101,97,115,117,114,121,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,13,99,111,118,101,114,95,100,101,102,105,99,105,116,4,101,109,105,116,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,13,103,101,116,95,116,105,109,101,115,116,97,109,112,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,14,104,97,115,95,99,111,108,108,97,116,101,114,97,108,11,104,97,115,95,100,101,102,105,99,105,116,19,105,115,95,98,111,114,114,111,119,97,98,108,101,95,97,115,115,101,116,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,17,105,115,95,105,115,111,108,97,116,105,111,110,95,109,111,100,101,15,105,115,95,108,105,113,117,105,100,95,97,115,115,101,116,7,105,115,95,108,111,97,110,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,109,97,116,104,3,109,105,110,11,109,105,110,116,95,100,116,111,107,101,110,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,111,116,111,107,101,110,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,24,110,111,116,95,114,101,97,99,104,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,24,110,111,116,95,114,101,97,99,104,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,6,111,114,97,99,108,101,7,112,111,111,108,95,105,100,12,112,111,111,108,95,109,97,110,97,103,101,114,3,112,111,119,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,19,114,101,100,117,99,101,95,105,115,111,108,97,116,101,95,100,101,98,116,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,19,116,111,116,97,108,95,100,116,111,107,101,110,95,115,117,112,112,108,121,19,116,111,116,97,108,95,111,116,111,107,101,110,95,115,117,112,112,108,121,24,117,112,100,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,7,117,115,101,114,95,105,100,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,27,117,115,101,114,95,116,111,116,97,108,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,21,117,115,101,114,95,116,111,116,97,108,95,108,111,97,110,95,118,97,108,117,101,6,118,101,99,116,111,114,11,118,105,111,108,97,116,111,114,95,105,100,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,15,32,0,0,0,200,165,25,144,185,165,111,165,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,34,76,160,196,199,203,249,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,0,2,5,130,1,3,10,15,105,13,136,1,3,29,2,0,3,0,0,25,233,1,10,1,10,5,10,6,17,13,4,6,5,16,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,5,10,7,17,14,4,22,5,32,11,1,1,11,0,1,11,2,1,11,3,1,7,8,39,10,1,10,4,10,7,17,13,4,38,5,48,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,3,10,7,17,44,10,1,10,3,10,6,17,44,10,1,10,2,10,3,10,4,17,43,10,2,10,1,10,5,10,3,17,16,10,1,10,2,10,5,17,11,32,4,73,5,83,11,1,1,11,0,1,11,2,1,11,3,1,7,6,39,10,1,10,2,10,4,10,5,10,6,10,7,17,32,12,15,12,14,10,1,10,6,17,77,12,18,10,1,10,4,10,7,17,21,12,16,10,2,10,6,11,14,10,7,11,15,11,16,11,18,17,33,12,19,12,11,12,10,12,9,10,1,10,6,17,75,12,17,10,1,10,5,10,7,10,10,17,40,10,1,10,5,10,6,10,9,17,38,10,1,10,4,10,7,11,10,17,38,10,1,11,17,10,6,11,19,17,37,10,1,10,2,10,5,17,18,4,145,1,10,1,10,5,17,36,10,1,10,4,10,6,17,14,4,184,1,10,1,10,4,10,6,17,23,12,13,10,13,10,11,17,103,12,12,10,1,10,4,10,6,11,12,17,40,10,11,10,13,36,4,183,1,10,1,10,4,10,6,17,90,10,1,10,4,10,6,11,11,11,13,23,17,37,10,1,10,4,10,6,17,54,5,210,1,10,1,10,4,10,6,11,11,17,37,10,1,10,4,10,6,17,13,32,4,202,1,10,1,10,4,10,6,17,12,32,12,8,5,204,1,9,12,8,11,8,4,210,1,10,1,10,4,10,6,17,54,10,0,10,1,10,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,0,10,1,11,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,5,17,43,11,4,11,9,11,6,11,5,17,49,18,0,56,0,2,1,3,0,0,7,128,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,4,10,5,17,14,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,18,39,10,1,10,5,10,6,17,8,4,42,5,52,11,1,1,11,0,1,11,2,1,11,3,1,7,19,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,10,6,17,37,10,1,10,4,10,5,17,13,32,4,74,10,1,10,4,10,5,17,12,32,12,7,5,76,9,12,7,11,7,4,110,10,1,10,4,17,15,4,87,10,1,10,4,10,5,17,54,5,110,10,1,10,4,17,17,32,4,97,10,1,10,4,10,5,17,53,5,110,10,1,10,5,17,85,4,106,10,1,10,4,10,5,17,54,5,110,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,51,18,0,56,0,2,2,3,0,0,18,95,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,21,12,8,11,6,10,8,17,103,12,7,10,1,10,4,10,5,10,7,17,38,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,48,5,58,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,10,7,11,8,33,4,76,10,1,10,4,10,5,17,13,4,72,10,1,10,4,10,5,17,88,5,76,10,1,10,4,10,5,17,89,11,0,10,1,10,5,10,7,17,45,11,1,11,2,11,3,10,4,17,43,11,4,10,7,11,5,6,0,0,0,0,0,0,0,0,17,52,18,0,56,0,11,7,2,3,3,0,0,1,170,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,13,32,4,30,5,40,11,1,1,11,0,1,11,2,1,11,3,1,7,3,39,10,1,10,4,10,5,17,12,32,4,47,5,57,11,1,1,11,0,1,11,2,1,11,3,1,7,4,39,10,1,10,5,17,10,4,62,5,72,11,1,1,11,0,1,11,2,1,11,3,1,7,13,39,10,1,10,4,17,15,4,111,10,1,10,5,17,58,4,81,5,91,11,1,1,11,0,1,11,2,1,11,3,1,7,12,39,10,1,10,4,10,6,17,9,4,97,5,107,11,1,1,11,0,1,11,2,1,11,3,1,7,11,39,10,1,10,4,10,6,17,41,10,1,10,4,10,5,17,14,32,4,121,10,1,10,4,10,5,17,55,10,1,10,4,10,5,10,6,17,39,10,2,10,1,10,4,10,3,17,16,10,2,10,5,64,31,1,0,0,0,0,0,0,0,10,3,17,95,10,1,10,2,10,4,17,11,4,142,1,5,152,1,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,10,6,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,47,18,0,56,0,2,4,3,0,0,33,88,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,23,12,7,10,6,10,7,17,103,12,9,10,1,10,4,10,5,10,9,17,40,10,1,10,4,17,15,4,45,10,1,10,4,10,9,17,42,10,6,10,7,38,4,70,10,1,10,4,10,5,17,90,11,6,11,7,23,12,8,10,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,10,1,10,4,10,5,11,8,17,37,10,1,10,4,10,5,17,54,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,9,11,5,6,0,0,0,0,0,0,0,0,17,50,18,0,56,0,2,5,3,0,0,1,82,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,12,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,14,39,10,1,10,4,17,15,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,15,39,10,1,10,4,17,17,4,56,10,1,10,5,17,85,32,4,46,5,56,11,1,1,11,0,1,11,2,1,11,3,1,7,17,39,10,1,10,4,10,5,17,89,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,46,18,0,56,0,2,6,3,0,0,1,67,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,13,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,4,10,5,17,88,10,1,10,4,10,5,17,54,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,39,5,49,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,48,18,0,56,0,2,7,1,0,0,34,49,10,2,11,3,10,4,17,44,10,2,10,4,17,75,12,11,10,2,10,11,10,4,17,21,12,10,10,2,10,11,10,4,17,23,12,9,10,10,10,9,36,4,27,11,10,11,9,23,12,7,5,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,11,6,17,103,12,8,10,2,11,11,10,4,10,8,17,38,10,2,11,5,10,4,11,8,17,37,11,1,11,2,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,2,8,1,0,0,35,23,10,0,10,1,17,74,12,4,11,0,11,1,17,34,12,5,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,15,8,12,3,5,21,11,5,11,2,22,11,4,35,12,3,11,3,2,9,1,0,0,36,33,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,5,10,0,10,5,20,17,73,12,4,11,0,11,5,20,17,68,12,6,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,8,12,3,5,31,11,6,11,2,22,11,4,35,12,3,11,3,2,10,1,0,0,1,6,11,0,11,1,17,63,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,2,11,1,0,0,1,7,11,0,11,1,11,2,17,19,17,104,36,2,12,1,0,0,38,19,10,0,10,1,17,61,4,13,11,0,11,1,17,81,12,4,14,4,14,2,56,1,12,3,5,17,11,0,1,9,12,3,11,3,2,13,1,0,0,37,8,11,0,11,1,17,79,12,3,14,3,14,2,56,1,2,14,1,0,0,37,8,11,0,11,1,17,82,12,3,14,3,14,2,56,1,2,15,1,0,0,40,25,10,0,11,1,17,79,12,4,14,4,65,31,6,1,0,0,0,0,0,0,0,33,4,19,14,4,6,0,0,0,0,0,0,0,0,66,31,20,12,3,11,0,11,3,17,85,12,2,5,23,11,0,1,9,12,2,11,2,2,16,1,0,0,41,17,10,1,10,2,17,79,12,4,11,1,11,2,17,82,12,5,10,0,11,4,10,3,17,95,11,0,11,5,11,3,17,95,2,17,1,0,0,37,9,11,0,11,1,17,79,12,2,14,2,65,31,6,0,0,0,0,0,0,0,0,36,2,18,1,0,0,35,23,10,0,10,1,10,2,17,26,12,4,11,0,11,1,11,2,17,27,12,5,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,12,3,5,21,9,12,3,11,3,2,19,1,0,0,33,23,10,0,10,1,10,2,17,24,12,4,11,0,11,1,11,2,17,25,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,19,11,4,11,5,17,105,12,3,5,21,7,0,12,3,11,3,2,20,1,0,0,3,10,11,0,11,2,10,3,17,21,12,4,11,1,11,3,11,4,17,28,2,21,1,0,0,18,13,10,0,11,1,10,2,17,84,12,4,11,0,11,2,17,70,12,3,11,4,11,3,17,107,2,22,1,0,0,3,10,11,0,11,2,10,3,17,23,12,4,11,1,11,3,11,4,17,28,2,23,1,0,0,18,13,10,0,11,1,10,2,17,83,12,4,11,0,11,2,17,64,12,3,11,4,11,3,17,107,2,24,1,0,0,42,49,10,0,10,2,17,79,12,6,14,6,65,31,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,43,5,16,14,6,10,7,66,31,12,3,10,0,10,3,20,17,66,12,4,10,0,10,1,10,2,11,3,20,17,20,12,5,11,9,11,5,11,4,17,106,22,12,9,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,11,11,0,1,11,1,1,11,9,2,25,1,0,0,43,49,10,0,10,2,17,82,12,8,14,8,65,31,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,43,5,16,14,8,10,4,66,31,12,6,10,0,10,6,20,17,63,12,3,10,0,10,1,10,2,11,6,20,17,22,12,7,11,9,11,7,11,3,17,106,22,12,9,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,11,11,0,1,11,1,1,11,9,2,26,1,0,0,44,42,10,0,10,2,17,79,12,5,14,5,65,31,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,36,5,16,14,5,10,6,66,31,12,3,10,0,10,1,10,2,11,3,20,17,20,12,4,11,8,11,4,22,12,8,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,11,11,0,1,11,1,1,11,8,2,27,1,0,0,45,42,10,0,10,2,17,82,12,7,14,7,65,31,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,36,5,16,14,7,10,3,66,31,12,5,10,0,10,1,10,2,11,5,20,17,22,12,6,11,8,11,6,22,12,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,11,11,0,1,11,1,1,11,8,2,28,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,11,4,24,6,10,0,0,0,0,0,0,0,11,3,17,112,77,26,2,29,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,6,10,0,0,0,0,0,0,0,11,3,17,112,77,24,11,4,26,2,30,1,0,0,18,16,10,0,10,1,10,2,17,24,12,3,11,0,11,1,11,2,17,25,12,4,17,104,11,3,11,4,17,105,23,2,31,1,0,0,20,52,10,0,10,3,17,61,4,5,5,11,11,0,1,11,1,1,7,16,39,10,0,10,2,17,61,4,16,5,22,11,0,1,11,1,1,7,16,39,10,0,10,1,10,3,17,30,12,5,10,0,11,2,17,78,12,4,11,0,11,1,11,3,17,25,12,7,11,4,74,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,24,17,105,17,104,17,103,17,104,22,12,6,11,5,11,6,17,106,7,1,17,103,2,32,1,0,0,50,89,10,0,10,1,11,2,10,3,17,31,12,12,10,0,10,1,10,3,17,24,12,10,10,0,10,1,10,3,17,25,12,11,10,0,10,5,17,63,12,6,10,0,10,4,17,66,12,7,11,11,7,2,17,106,11,10,23,12,19,7,2,17,104,10,12,23,17,106,11,6,17,106,11,7,23,12,18,11,19,11,18,17,105,12,14,10,0,10,1,10,3,10,4,17,20,10,14,17,105,12,8,10,14,17,104,11,12,23,17,106,12,16,11,0,10,1,11,3,10,5,17,22,10,16,17,105,12,9,11,8,11,9,17,103,17,104,17,103,12,17,10,1,11,4,11,14,10,17,17,106,17,29,12,13,11,1,11,5,11,16,11,17,17,106,17,29,12,15,11,13,11,15,2,33,1,0,0,51,45,10,5,10,4,38,4,9,11,4,12,8,11,2,12,7,5,17,11,5,12,8,11,2,10,8,11,4,17,105,17,106,12,7,10,0,10,1,10,7,17,28,12,9,10,0,11,3,10,8,17,28,12,11,11,0,11,1,11,9,11,11,23,17,29,11,6,17,106,12,12,10,7,10,12,23,12,10,11,7,11,8,11,10,11,12,2,34,1,0,0,18,12,10,0,10,1,17,72,12,3,11,0,11,1,17,70,12,2,11,3,11,2,17,106,2,35,1,0,0,18,12,10,0,10,1,17,67,12,3,11,0,11,1,17,64,12,2,11,3,11,2,17,106,2,36,0,0,0,52,49,10,0,10,1,17,82,12,6,14,6,65,31,12,4,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,46,5,14,14,6,10,3,66,31,12,5,10,0,10,5,20,17,75,12,7,10,0,10,1,10,5,20,17,23,12,2,10,0,10,1,10,5,20,10,2,17,40,10,0,11,7,11,5,20,11,2,17,39,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,9,11,0,1,2,37,0,0,0,3,12,11,3,10,0,10,2,17,70,17,109,12,4,11,0,11,2,11,1,11,4,17,87,2,38,0,0,0,3,12,11,3,10,0,10,2,17,70,17,108,12,4,11,0,11,2,11,1,11,4,17,57,2,39,0,0,0,3,12,11,3,10,0,10,2,17,64,17,109,12,4,11,0,11,2,11,1,11,4,17,86,2,40,0,0,0,3,12,11,3,10,0,10,2,17,64,17,108,12,4,11,0,11,2,11,1,11,4,17,56,2,41,0,0,0,54,21,10,0,11,1,17,79,12,5,14,5,6,0,0,0,0,0,0,0,0,66,31,12,3,10,0,10,3,20,17,68,11,2,22,12,4,11,0,11,3,20,11,4,17,92,2,42,0,0,0,55,32,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,4,10,0,10,4,20,17,68,12,5,10,5,10,2,38,4,22,11,5,11,2,23,12,3,5,24,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,12,6,11,0,11,4,20,11,6,17,92,2,43,0,0,0,56,58,10,0,10,3,17,61,4,51,10,2,17,76,12,5,10,0,10,3,17,80,12,9,10,0,10,1,10,3,17,24,12,6,10,0,11,1,10,3,17,25,12,7,10,6,10,7,36,4,45,11,6,11,7,23,12,8,10,0,10,3,17,78,12,4,11,5,11,9,11,4,11,8,17,98,12,10,11,0,11,2,11,3,11,10,17,94,5,50,11,0,11,2,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,94,5,57,11,0,1,11,1,1,11,2,1,2,44,0,0,0,59,59,11,1,17,76,12,5,10,0,10,2,17,69,12,7,10,0,10,2,17,67,12,6,10,0,10,2,17,64,12,3,10,0,10,2,17,70,12,4,10,0,10,2,17,77,12,11,10,5,10,7,10,0,10,2,17,65,17,100,10,3,17,106,12,9,10,5,11,7,10,0,10,2,17,71,17,101,11,4,17,106,12,10,11,6,10,9,11,3,23,17,106,11,11,17,106,10,10,17,109,12,8,11,0,11,2,11,9,11,10,11,5,11,8,17,93,2,45,0,0,0,20,36,11,0,10,2,10,1,17,62,17,97,12,5,10,5,10,3,38,4,11,5,15,11,1,1,7,10,39,11,5,11,3,23,12,6,10,1,10,2,10,6,17,99,12,4,10,1,10,2,10,4,11,6,17,102,12,7,11,1,11,2,11,4,11,7,17,91,2,0,92,0,94,0],"lending_portal":[161,28,235,11,6,0,0,0,11,1,0,44,2,44,90,3,134,1,165,2,4,171,3,36,5,207,3,230,5,7,181,9,176,10,8,229,19,128,1,6,229,20,54,10,155,21,59,12,214,21,204,16,13,162,38,4,0,72,0,23,0,38,0,39,0,52,0,69,0,70,0,71,0,75,0,83,0,84,0,103,0,108,1,82,2,30,2,31,2,44,2,81,2,99,2,101,2,102,3,98,0,8,8,0,0,14,3,0,0,9,3,0,0,7,3,0,1,0,12,0,2,4,7,0,3,11,12,1,0,1,4,5,0,0,4,6,8,0,6,17,8,0,9,13,8,0,10,12,12,0,11,20,12,0,12,3,12,0,13,10,7,1,0,0,14,1,8,0,15,2,12,1,0,1,17,19,4,0,18,15,2,0,20,18,2,0,21,16,12,0,0,66,0,1,0,0,60,2,3,0,0,94,4,1,0,0,24,5,1,0,0,28,5,1,0,0,100,6,1,1,0,0,106,7,1,1,0,0,107,8,1,0,0,25,7,1,1,0,0,26,8,1,0,0,90,6,1,1,0,0,73,9,1,1,0,2,32,12,17,0,2,33,1,17,1,0,2,34,45,17,0,2,55,35,28,0,2,59,1,19,0,3,35,27,28,1,0,3,80,25,3,1,0,3,105,43,1,1,0,4,29,16,1,0,5,54,1,26,0,5,58,1,26,0,5,62,1,26,0,5,63,1,26,0,5,64,1,26,0,6,53,49,50,0,7,24,20,1,0,7,28,20,1,0,7,45,34,1,0,7,46,60,1,0,7,47,34,1,0,7,48,34,1,0,7,49,34,42,0,8,74,22,23,1,0,10,21,29,30,0,10,51,38,39,0,10,57,33,19,0,10,61,33,42,0,10,89,29,30,0,11,56,18,3,0,11,67,18,31,0,11,87,32,1,0,12,91,51,3,0,13,36,41,14,1,0,13,68,40,31,1,0,15,37,23,1,1,0,15,97,48,23,1,0,15,104,24,3,1,0,16,43,14,1,1,3,17,77,0,10,0,19,85,53,1,1,12,19,95,14,1,1,8,20,92,11,12,0,21,76,47,3,0,52,13,13,14,34,14,48,14,18,14,17,14,49,36,45,17,44,17,19,14,34,46,47,46,48,46,51,52,49,54,49,55,5,14,46,14,1,7,8,19,0,1,7,8,0,1,3,3,6,8,7,7,8,0,5,8,6,8,8,7,8,9,7,8,10,6,8,15,7,8,11,7,8,12,10,13,7,8,19,11,6,8,8,7,8,9,7,8,10,6,8,15,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,16,1,9,0,3,7,8,19,10,6,8,8,7,8,9,7,8,10,6,8,15,7,8,0,7,8,11,7,8,12,7,11,6,1,9,0,3,7,8,19,16,6,8,8,7,8,9,7,8,10,6,8,15,7,8,13,7,8,0,7,8,20,7,8,11,7,8,12,10,2,10,2,13,3,10,11,16,1,8,18,3,7,8,19,14,6,8,8,7,8,9,7,8,10,6,8,15,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,16,1,9,0,3,13,10,2,3,7,8,19,1,8,17,1,6,8,19,1,5,1,8,0,1,9,0,11,8,5,7,8,9,7,8,10,6,8,15,3,13,6,13,3,3,3,8,5,1,6,8,8,1,8,5,2,6,8,12,8,5,1,13,6,6,8,11,7,8,9,7,8,10,6,8,15,3,13,17,6,8,15,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,3,11,16,1,9,0,13,3,3,8,5,8,5,3,10,11,16,1,9,0,3,7,8,19,1,11,16,1,9,0,1,6,11,16,1,9,0,2,6,11,6,1,9,0,3,1,2,5,7,11,6,1,9,0,11,16,1,9,0,13,10,2,7,8,19,1,10,2,4,7,8,11,8,5,13,15,2,15,15,1,1,2,7,8,12,8,5,2,7,8,11,8,5,7,6,8,11,7,8,9,7,8,10,6,8,15,3,13,15,1,6,8,5,1,8,3,16,8,5,7,8,9,7,8,10,6,8,15,3,13,15,15,13,3,13,11,14,1,8,5,8,5,8,5,8,5,15,3,7,8,11,13,13,1,11,14,1,8,5,1,6,11,14,1,9,0,1,11,14,1,9,0,1,15,5,7,11,6,1,9,0,8,5,3,8,5,7,8,19,21,8,5,7,8,9,7,8,10,6,8,15,3,13,15,15,11,16,1,8,18,13,3,11,14,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,16,1,8,18,3,2,13,10,2,1,8,18,1,6,8,20,3,7,11,16,1,9,0,3,7,8,19,1,7,8,9,1,6,8,4,11,7,8,20,7,8,13,6,8,4,7,8,11,8,5,8,5,13,3,15,11,16,1,8,18,6,8,15,1,11,16,1,8,18,2,9,0,5,1,8,1,1,8,2,15,8,5,7,8,9,7,8,10,6,8,15,3,13,15,13,3,13,11,14,1,8,5,8,5,8,5,8,5,15,20,8,5,7,8,9,7,8,10,6,8,15,3,13,15,11,16,1,8,18,13,3,11,14,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,16,1,8,18,3,17,6,8,15,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,13,3,3,8,5,3,11,16,1,9,0,8,5,16,13,8,5,7,8,9,7,8,10,6,8,15,3,3,13,13,8,5,3,8,5,3,5,13,8,5,8,6,8,11,7,8,9,7,8,10,6,8,15,3,3,13,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,17,76,101,110,100,105,110,103,76,111,99,97,108,69,118,101,110,116,13,76,101,110,100,105,110,103,80,111,114,116,97,108,18,76,101,110,100,105,110,103,80,111,114,116,97,108,69,118,101,110,116,6,79,112,116,105,111,110,4,80,111,111,108,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,13,97,100,100,95,108,105,113,117,105,100,105,116,121,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,12,98,111,114,114,111,119,95,108,111,99,97,108,13,98,111,114,114,111,119,95,114,101,109,111,116,101,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,7,100,101,112,111,115,105,116,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,17,100,111,108,97,95,112,111,111,108,95,97,100,100,114,101,115,115,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,10,102,101,101,95,97,109,111,117,110,116,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,2,105,100,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,9,108,105,113,117,105,100,97,116,101,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,11,109,101,115,115,97,103,101,95,102,101,101,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,7,114,101,108,97,121,101,114,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,5,114,101,112,97,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,6,115,101,110,100,101,114,8,115,101,113,117,101,110,99,101,11,115,101,116,95,114,101,108,97,121,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,112,108,105,116,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,14,119,105,116,104,100,114,97,119,95,108,111,99,97,108,15,119,105,116,104,100,114,97,119,95,114,101,109,111,116,101,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,13,2,1,0,0,2,3,65,8,17,88,5,78,3,1,2,5,93,3,79,3,42,8,5,50,3,27,2,2,2,8,79,3,92,5,40,10,2,96,13,41,13,86,10,2,22,3,27,2,3,2,5,79,3,92,5,40,10,2,22,3,27,2,0,0,0,0,1,9,10,0,17,50,11,0,46,17,53,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,0,0,1,5,11,2,11,1,15,1,21,2,3,1,4,0,15,61,11,0,17,20,11,7,46,17,53,17,12,12,18,11,5,11,18,12,8,46,11,8,17,40,12,15,14,6,65,19,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,19,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,27,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,4,1,4,0,15,61,11,0,17,20,11,7,46,17,53,17,12,12,18,11,5,11,18,12,8,46,11,8,17,40,12,15,14,6,65,19,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,19,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,28,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,5,1,4,0,21,117,11,0,17,20,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,53,17,12,12,27,56,1,12,26,11,8,11,9,10,10,56,2,12,22,10,7,14,22,56,3,12,15,46,11,15,56,4,12,21,11,4,17,1,12,25,11,7,11,22,7,5,64,26,0,0,0,0,0,0,0,0,10,10,56,5,1,10,6,10,26,7,5,10,21,77,17,35,1,12,20,10,5,10,27,12,16,46,11,16,17,41,32,4,74,10,5,10,27,17,42,10,6,10,26,17,37,12,23,11,5,11,27,12,17,46,11,17,17,40,12,24,11,6,11,1,11,2,11,3,11,24,11,23,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,32,11,25,11,10,46,17,53,14,26,17,15,11,21,17,24,18,3,56,6,2,6,1,4,0,37,117,11,0,17,20,17,16,12,20,10,9,46,17,53,17,12,12,24,56,1,12,23,10,5,10,23,17,37,12,18,11,6,10,24,12,10,46,11,10,17,40,12,19,10,5,10,18,11,20,17,36,12,21,14,21,56,7,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,21,56,8,12,22,10,5,11,1,11,2,11,3,11,19,11,18,11,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,33,12,17,10,5,10,22,17,38,10,17,38,4,80,5,90,11,5,1,11,7,1,11,4,1,11,9,1,7,1,39,11,5,11,22,7,5,10,17,17,39,1,12,25,11,7,11,24,11,25,52,10,23,10,9,56,9,11,4,17,1,11,9,46,17,53,14,23,17,15,11,17,52,17,25,18,3,56,6,2,7,1,4,0,44,184,1,11,0,17,20,10,11,10,10,17,14,12,31,10,11,11,9,17,14,12,30,10,15,46,17,53,17,12,12,34,10,7,10,30,17,37,12,25,11,8,11,34,12,16,46,11,16,17,40,12,26,10,7,10,25,10,11,17,36,12,27,14,27,56,7,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,27,56,8,12,28,10,7,10,1,11,2,10,3,11,26,11,25,11,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,33,12,23,10,7,10,28,17,38,10,23,38,4,86,5,102,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,11,13,10,14,10,15,56,10,12,24,10,6,46,17,54,12,36,11,14,10,36,38,4,116,5,132,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,24,11,36,10,15,56,11,12,35,14,24,56,12,12,32,10,5,17,1,12,29,11,6,11,4,11,1,17,26,11,7,10,28,11,31,17,16,10,29,10,23,11,35,11,3,17,43,12,33,11,24,11,5,16,1,20,56,13,11,33,10,29,11,28,11,32,17,25,18,1,56,14,11,29,11,15,46,17,53,14,30,17,15,17,16,11,11,11,10,11,23,52,17,25,18,2,56,15,2,8,1,4,0,56,123,11,0,17,20,17,16,12,19,56,1,12,22,10,9,46,17,53,17,12,12,23,10,5,10,22,17,37,12,17,11,6,10,23,12,10,46,11,10,17,40,12,18,10,5,10,17,11,19,17,36,12,20,14,20,56,7,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,20,56,8,12,21,10,5,10,21,17,38,10,8,77,38,4,58,5,74,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,1,39,10,5,11,1,11,2,11,3,11,18,11,17,10,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,29,11,5,11,21,7,5,10,8,77,17,39,1,12,24,11,7,11,23,11,24,52,10,22,10,9,56,9,11,4,17,1,11,9,46,17,53,14,22,17,15,11,8,17,21,18,3,56,6,2,9,1,4,0,57,186,1,11,0,17,20,10,11,10,10,17,14,12,30,10,11,11,9,17,14,12,29,10,15,46,17,53,17,12,12,33,10,7,10,29,17,37,12,24,11,8,11,33,12,16,46,11,16,17,40,12,25,10,7,10,24,10,11,17,36,12,26,14,26,56,7,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,26,56,8,12,27,10,7,10,27,17,38,10,12,77,38,4,64,5,82,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,10,7,10,1,11,2,10,3,11,25,11,24,10,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,29,11,13,10,14,10,15,56,10,12,23,10,6,46,17,54,12,35,11,14,10,35,38,4,118,5,134,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,23,11,35,10,15,56,11,12,34,14,23,56,12,12,31,10,5,17,1,12,28,11,6,11,4,11,1,17,26,11,7,10,27,11,30,17,16,10,28,10,12,77,11,34,11,3,17,43,12,32,11,23,11,5,16,1,20,56,13,11,32,10,28,11,27,11,31,17,25,18,1,56,14,11,28,11,15,46,17,53,14,29,17,15,17,16,11,11,11,10,11,12,17,21,18,2,56,15,2,10,1,4,0,58,117,11,0,17,20,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,53,17,12,12,27,56,1,12,24,11,8,11,9,10,10,56,2,12,26,10,7,14,26,56,3,12,15,46,11,15,56,4,12,25,11,4,17,1,12,23,11,7,11,26,7,5,64,26,0,0,0,0,0,0,0,0,10,10,56,5,1,10,6,10,24,7,5,10,25,77,17,35,1,12,20,10,5,10,27,12,16,46,11,16,17,41,32,4,74,10,5,10,27,17,42,10,6,10,24,17,37,12,21,11,5,11,27,12,17,46,11,17,17,40,12,22,11,6,11,1,11,2,11,3,11,22,11,21,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,31,11,23,11,10,46,17,53,14,24,17,15,11,25,17,23,18,3,56,6,2,11,1,4,0,59,93,10,0,17,20,10,13,46,17,53,12,27,10,27,17,12,12,25,56,1,12,23,11,10,10,11,17,14,12,29,10,6,11,23,17,37,12,22,10,6,11,29,17,37,12,28,10,4,17,1,12,26,10,9,6,0,0,0,0,0,0,0,0,36,4,43,11,0,10,1,10,2,10,3,11,4,10,5,10,6,11,7,11,8,10,9,11,13,56,16,5,54,11,4,1,11,0,1,11,7,1,11,8,10,9,11,13,56,2,56,17,11,5,11,25,12,15,46,11,15,17,40,12,24,11,6,11,1,11,2,11,3,11,24,11,12,11,28,11,22,12,14,12,21,12,20,12,19,12,18,12,17,12,16,46,11,16,11,17,11,18,11,19,11,20,11,21,11,14,17,30,11,26,11,27,11,11,11,9,17,22,18,3,56,6,2,0,2,0,1,0],"merge_coins":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,10,3,20,53,4,73,14,5,87,102,7,189,1,132,1,8,193,2,96,6,161,3,30,12,191,3,189,1,0,6,1,14,2,2,2,11,2,12,2,0,12,1,0,1,4,1,2,0,0,5,0,1,1,0,1,3,5,6,1,0,1,8,3,4,1,0,2,4,8,4,1,0,2,10,11,1,1,0,2,13,9,10,1,0,2,15,15,1,1,0,3,7,14,4,1,12,4,9,12,13,0,2,1,1,1,3,7,5,7,4,7,7,1,6,7,3,10,11,0,1,9,0,3,7,8,1,1,11,0,1,9,0,6,11,0,1,9,0,11,0,1,9,0,11,0,1,9,0,3,11,0,1,9,0,3,1,7,10,9,0,0,1,6,10,9,0,1,1,1,9,0,2,7,11,0,1,9,0,11,0,1,9,0,1,6,11,0,1,9,0,1,3,3,7,11,0,1,9,0,3,7,8,1,1,6,8,1,1,5,2,9,0,5,1,7,8,1,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,8,105,115,95,101,109,112,116,121,4,106,111,105,110,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,7,114,101,118,101,114,115,101,6,115,101,110,100,101,114,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,118,101,99,116,111,114,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,255,255,255,255,255,255,255,255,0,1,0,0,2,83,14,0,65,1,6,0,0,0,0,0,0,0,0,36,4,67,13,0,56,0,13,0,69,1,12,5,14,0,56,1,32,4,20,5,15,13,5,13,0,69,1,56,2,5,10,11,0,70,1,0,0,0,0,0,0,0,0,14,5,56,3,12,8,10,1,12,6,11,1,7,2,33,4,33,10,8,12,6,11,8,10,6,38,4,38,5,42,11,2,1,7,0,39,14,5,56,3,10,6,36,4,60,13,5,11,6,10,2,56,4,12,7,11,5,11,2,46,17,8,56,5,11,7,12,3,5,64,11,2,1,11,5,12,3,11,3,12,4,5,81,11,0,70,1,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,33,4,74,5,78,11,2,1,7,1,39,11,2,56,6,12,4,11,4,2,0],"oracle":[161,28,235,11,6,0,0,0,11,1,0,36,2,36,84,3,120,157,1,4,149,2,22,5,171,2,231,2,7,146,5,231,6,8,249,11,128,1,6,249,12,70,10,191,13,33,12,224,13,232,5,13,200,19,14,0,47,0,31,2,40,2,41,2,49,2,52,2,54,2,56,2,61,1,23,1,24,1,46,1,62,1,63,1,65,1,66,3,61,3,68,0,10,8,0,0,6,4,0,1,2,0,0,1,3,8,0,2,4,0,1,3,0,3,5,7,0,4,6,7,0,5,7,7,0,6,8,7,0,6,9,12,0,8,12,12,0,9,0,8,0,10,1,12,1,0,1,11,15,4,0,12,11,2,0,13,13,12,2,7,1,4,1,15,14,2,0,16,12,12,0,17,16,0,0,0,43,0,1,0,0,39,2,3,0,0,59,4,1,0,0,58,4,1,0,0,57,5,1,0,0,20,6,1,0,0,21,6,1,0,0,29,7,1,0,1,22,27,1,0,2,28,40,1,1,3,3,33,43,23,0,3,34,43,23,0,4,32,41,42,0,4,35,41,42,0,5,30,19,20,0,6,36,30,20,0,6,37,28,29,0,7,26,33,34,0,7,38,38,39,0,7,67,35,34,0,9,64,22,23,0,11,45,0,8,0,13,17,21,1,2,7,4,13,18,15,17,2,7,4,13,19,36,37,2,7,4,13,25,15,16,2,7,4,13,45,0,10,2,7,4,14,60,13,1,1,8,17,48,31,32,0,26,9,26,11,27,12,25,11,23,11,25,9,22,9,22,11,23,9,24,11,9,29,1,7,8,16,0,2,7,8,0,13,3,15,2,3,3,6,8,2,7,8,0,3,7,6,8,2,7,8,0,10,2,13,15,2,6,8,11,3,7,8,0,10,13,6,8,11,9,6,8,3,7,8,17,7,8,10,7,8,9,7,8,0,13,10,2,6,8,11,11,12,1,8,14,1,8,13,2,13,8,7,1,11,15,2,9,0,9,1,2,13,8,1,1,8,0,1,9,0,4,13,13,6,8,1,7,11,15,2,13,8,1,2,6,11,15,2,9,0,9,1,9,0,1,1,1,6,9,1,5,13,13,8,7,7,11,15,2,13,8,7,7,11,15,2,13,8,1,1,10,2,1,8,7,3,7,11,15,2,9,0,9,1,9,0,9,1,1,6,8,11,1,3,6,13,3,6,13,3,6,8,1,7,11,15,2,13,8,1,1,13,23,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,6,8,11,13,10,2,6,8,11,10,8,18,6,8,11,3,8,5,3,11,4,1,8,8,7,8,1,6,8,7,8,8,11,4,1,8,8,8,5,3,8,6,8,7,8,18,1,6,8,3,1,6,8,9,1,8,8,1,6,8,8,3,6,8,17,10,2,6,8,11,1,8,18,3,6,8,10,10,8,18,6,8,11,1,11,4,1,8,8,5,6,8,10,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,2,7,11,15,2,9,0,9,1,9,0,1,7,9,1,3,6,8,9,6,8,11,3,1,8,6,1,11,4,1,9,0,1,6,8,6,1,8,5,1,6,8,5,5,67,108,111,99,107,4,67,111,105,110,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,15,72,111,116,80,111,116,97,116,111,86,101,99,116,111,114,3,73,54,52,5,80,114,105,99,101,15,80,114,105,99,101,73,100,101,110,116,105,102,105,101,114,9,80,114,105,99,101,73,110,102,111,15,80,114,105,99,101,73,110,102,111,79,98,106,101,99,116,11,80,114,105,99,101,79,114,97,99,108,101,3,83,85,73,5,83,116,97,116,101,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,86,65,65,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,17,99,104,101,99,107,95,103,117,97,114,100,95,112,114,105,99,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,29,99,114,101,97,116,101,95,112,114,105,99,101,95,105,110,102,111,115,95,104,111,116,95,112,111,116,97,116,111,7,100,101,99,105,109,97,108,7,100,101,115,116,114,111,121,24,102,101,101,100,95,116,111,107,101,110,95,112,114,105,99,101,95,98,121,95,112,121,116,104,13,102,114,111,109,95,98,121,116,101,95,118,101,99,7,103,101,110,101,115,105,115,8,103,101,116,95,101,120,112,111,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,110,101,103,97,116,105,118,101,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,112,111,115,105,116,105,118,101,9,103,101,116,95,112,114,105,99,101,20,103,101,116,95,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,37,103,101,116,95,112,114,105,99,101,95,105,110,102,111,95,102,114,111,109,95,112,114,105,99,101,95,105,110,102,111,95,111,98,106,101,99,116,23,103,101,116,95,112,114,105,99,101,95,110,111,95,111,108,100,101,114,95,116,104,97,110,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,17,104,111,116,95,112,111,116,97,116,111,95,118,101,99,116,111,114,3,105,54,52,2,105,100,4,105,110,105,116,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,3,110,101,119,6,111,98,106,101,99,116,6,111,114,97,99,108,101,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,5,112,114,105,99,101,16,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,16,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,16,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,17,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,115,10,112,114,105,99,101,95,105,110,102,111,13,112,114,105,99,101,95,111,114,97,99,108,101,115,4,112,121,116,104,20,114,101,103,105,115,116,101,114,95,116,111,107,101,110,95,112,114,105,99,101,20,115,101,116,95,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,20,115,101,116,95,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,116,97,116,101,3,115,117,105,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,24,117,112,100,97,116,101,95,115,105,110,103,108,101,95,112,114,105,99,101,95,102,101,101,100,3,118,97,97,5,118,97,108,117,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,181,59,15,65,116,16,134,39,251,238,114,226,73,139,88,214,162,113,76,222,213,63,172,83,112,52,194,32,210,99,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,60,0,0,0,0,0,0,0,3,8,16,14,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,5,42,8,13,51,3,50,3,53,11,15,2,13,8,7,55,11,15,2,13,8,1,1,2,3,69,15,27,2,44,3,0,0,0,0,1,11,10,0,17,21,7,1,7,0,10,0,56,0,11,0,56,1,18,0,56,2,2,1,1,0,0,14,32,11,0,15,0,12,5,10,5,10,1,12,2,46,11,2,56,3,4,11,5,15,11,5,1,7,2,39,11,5,11,1,12,3,46,11,3,56,4,12,4,10,4,16,1,20,10,4,16,2,20,11,4,16,3,20,2,2,1,0,0,1,5,11,2,11,1,15,4,21,2,3,1,0,0,1,5,11,2,11,1,15,5,21,2,4,1,0,0,18,58,10,1,15,0,12,11,10,11,10,3,12,7,46,11,7,56,3,32,4,12,5,20,11,11,1,11,1,1,11,6,1,7,3,39,11,2,17,14,12,9,11,1,15,6,12,10,10,10,10,3,12,8,46,11,8,56,5,32,4,35,5,43,11,11,1,11,10,1,11,6,1,7,3,39,11,10,10,3,11,9,56,6,11,11,11,3,11,4,11,5,11,6,17,20,6,232,3,0,0,0,0,0,0,26,18,1,56,7,2,5,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,5,20,35,4,39,5,45,11,8,1,11,0,1,7,4,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,6,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,4,20,35,4,39,5,45,11,8,1,11,0,1,7,5,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,7,1,0,0,26,136,1,11,0,17,8,10,4,16,6,10,5,56,5,4,8,5,20,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,2,39,10,4,15,6,10,5,12,14,46,11,14,56,8,12,24,10,3,46,17,16,12,25,14,25,17,15,12,30,11,24,14,30,33,4,40,5,52,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,6,39,11,1,11,6,10,7,12,16,12,15,46,11,15,11,16,17,28,12,31,10,2,11,31,64,32,1,0,0,0,0,0,0,0,10,7,12,18,12,17,46,11,17,11,18,17,17,12,26,11,2,11,26,10,3,11,8,10,7,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,17,19,12,22,10,7,17,20,6,232,3,0,0,0,0,0,0,26,12,19,11,4,15,0,11,5,56,9,12,23,11,3,11,7,12,13,46,11,13,7,0,17,18,12,29,11,22,56,10,14,29,17,13,12,27,14,27,17,11,12,28,14,29,17,12,12,20,14,20,17,10,12,21,11,28,77,10,23,15,1,21,11,21,51,10,23,15,2,21,11,19,11,23,15,3,21,2,0,4,1,0,1,1,1,2,0,1,0,2,0,3,0],"pool_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,136,1,4,146,1,2,5,148,1,208,1,7,228,2,205,4,8,177,7,32,6,209,7,41,12,250,7,133,12,0,23,0,10,0,24,1,0,7,0,0,18,0,1,0,0,22,0,1,0,0,21,0,1,0,0,19,0,1,0,0,20,0,1,0,0,16,0,1,0,0,17,0,1,0,0,11,2,3,0,0,1,3,4,0,0,15,5,3,0,0,5,3,6,0,0,14,7,3,0,0,4,3,8,0,0,13,9,3,0,0,3,3,9,0,1,2,3,12,0,1,12,12,3,0,2,6,19,20,0,2,7,19,27,0,2,8,19,21,0,2,9,19,1,0,2,25,11,0,0,2,26,25,0,0,2,27,14,0,0,2,28,15,0,0,2,29,13,0,0,2,30,17,18,1,1,26,1,0,1,2,5,8,0,8,0,3,13,10,2,1,10,2,6,8,0,8,0,3,13,2,10,2,5,13,3,8,0,8,0,3,6,13,3,8,0,8,0,3,2,3,8,0,13,10,2,4,8,0,13,2,10,2,3,13,15,2,3,10,2,10,2,10,2,2,7,10,2,13,1,8,0,2,7,10,2,10,2,2,7,10,2,3,2,7,10,2,2,18,10,2,10,2,10,2,10,2,10,2,10,2,3,13,10,2,13,3,3,3,8,0,2,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,17,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,3,3,8,0,2,13,13,8,0,13,2,10,2,10,2,13,10,2,10,2,10,2,10,2,13,10,2,13,3,3,3,2,8,0,13,2,7,10,2,15,9,10,2,10,2,10,2,3,13,15,3,3,2,1,15,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,100,101,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,21,103,101,116,95,100,101,108,101,116,101,95,111,119,110,101,114,95,116,121,112,101,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,16,103,101,116,95,100,101,112,111,115,105,116,95,116,121,112,101,23,103,101,116,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,21,103,101,116,95,115,101,110,100,95,109,101,115,115,97,103,101,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,10,112,111,111,108,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,10,48,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,3,17,21,11,0,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,1,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,2,17,23,13,6,7,2,17,24,14,4,65,1,6,0,0,0,0,0,0,0,0,36,4,46,13,6,14,4,65,1,75,17,21,13,6,11,4,17,25,11,6,2,8,1,0,0,16,172,1,14,0,65,1,12,13,6,0,0,0,0,0,0,0,0,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,1,14,1,17,17,12,8,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,2,14,2,17,17,12,16,11,12,11,11,22,12,12,11,16,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,14,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,3,14,3,17,17,12,18,11,12,11,11,22,12,12,11,18,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,17,11,12,11,11,22,12,12,6,8,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,4,14,4,17,19,12,7,11,12,11,11,22,12,12,6,1,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,5,14,5,17,20,12,15,11,12,11,11,22,12,12,64,1,0,0,0,0,0,0,0,0,12,9,10,13,10,12,36,4,151,1,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,6,14,6,17,17,12,10,11,12,11,11,22,12,12,11,10,52,12,11,14,0,10,12,10,12,10,11,22,56,0,12,9,11,12,11,11,22,12,12,10,15,7,2,33,4,156,1,5,158,1,7,1,39,11,13,11,12,33,4,163,1,5,165,1,7,0,39,11,14,11,17,11,7,11,8,11,15,11,9,2,9,1,0,0,10,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,21,13,6,11,1,17,23,11,2,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,3,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,4,17,23,13,6,7,3,17,24,11,6,2,10,1,0,0,22,152,1,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,15,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,19,12,11,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,17,11,9,11,8,22,12,9,11,17,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,19,12,7,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,20,12,13,11,9,11,8,22,12,9,10,13,7,3,33,4,136,1,5,138,1,7,1,39,11,10,11,9,33,4,143,1,5,145,1,7,0,39,11,15,11,11,11,12,11,16,11,7,11,13,2,11,1,0,0,23,34,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,1,17,21,11,0,17,16,12,4,13,3,14,4,65,1,75,17,21,13,3,11,4,17,25,13,3,7,4,17,24,14,2,65,1,6,0,0,0,0,0,0,0,0,36,4,32,13,3,14,2,65,1,75,17,21,13,3,11,2,17,25,11,3,2,12,1,0,0,24,123,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,5,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,20,12,11,11,9,11,8,22,12,9,64,1,0,0,0,0,0,0,0,0,12,6,10,10,10,9,36,4,104,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,7,11,9,11,8,22,12,9,11,7,52,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,11,9,11,8,22,12,9,10,11,7,4,33,4,109,5,111,7,1,39,11,10,11,9,33,4,116,5,118,7,0,39,11,12,11,5,11,11,11,6,2,13,1,0,0,3,13,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,0,17,21,13,3,11,1,17,22,13,3,11,2,17,24,11,3,2,14,1,0,0,26,64,14,0,65,1,12,8,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,1,14,1,17,17,12,5,11,7,11,4,22,12,7,6,32,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,2,14,2,17,18,12,6,11,7,11,4,22,12,7,6,1,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,3,14,3,17,20,12,9,11,7,11,4,22,12,7,11,8,11,7,33,4,58,5,60,7,0,39,11,5,11,6,11,9,2,0],"pool_manager":[161,28,235,11,6,0,0,0,12,1,0,22,2,22,66,3,88,199,1,4,159,2,62,5,221,2,206,2,7,171,5,144,8,8,187,13,96,6,155,14,138,1,10,165,15,108,12,145,16,154,13,13,171,29,32,15,203,29,4,0,62,0,28,0,30,0,36,1,21,1,58,2,32,2,57,2,74,2,76,2,77,0,9,12,0,0,1,4,0,0,7,4,0,0,4,4,0,0,8,4,0,0,6,4,0,0,0,3,0,0,10,3,0,1,2,7,0,3,3,0,0,4,11,7,0,5,5,7,1,0,0,7,14,4,0,8,12,12,2,7,1,4,1,10,13,2,0,0,51,0,1,0,0,66,2,1,0,0,65,3,1,0,0,71,4,1,0,0,69,5,1,0,0,70,4,1,0,0,47,6,7,0,0,41,8,9,0,0,44,6,10,0,0,37,11,12,0,0,48,6,12,0,0,43,8,12,0,0,42,8,12,0,0,45,6,12,0,0,46,8,12,0,0,38,1,12,0,0,39,1,12,0,0,35,13,14,0,0,34,15,16,0,0,33,17,16,0,0,81,1,18,0,0,16,19,20,0,0,67,19,20,0,1,40,46,9,0,2,24,49,12,0,2,25,49,12,0,2,26,20,12,0,5,56,1,47,1,0,5,73,28,47,1,0,6,29,28,1,1,3,7,55,0,21,0,8,15,31,1,2,7,4,8,22,41,42,2,7,4,8,23,35,36,2,7,4,8,27,41,16,2,7,4,8,55,0,23,2,7,4,9,72,28,1,1,8,35,22,35,24,35,25,35,26,36,27,35,30,31,24,31,26,35,33,31,22,31,25,33,26,33,24,31,30,33,30,32,26,32,25,32,24,32,22,34,33,32,33,32,30,28,32,27,32,34,24,34,25,33,22,31,33,33,33,29,50,29,51,1,7,8,14,0,5,6,8,9,7,8,0,8,10,13,7,8,14,4,6,8,9,7,8,0,8,8,13,4,6,8,9,7,8,0,8,8,15,4,6,8,9,7,8,0,13,15,2,7,8,0,13,1,10,8,8,2,7,8,0,8,8,1,13,1,8,10,3,6,8,0,13,13,1,15,3,7,8,0,13,13,1,11,11,1,8,8,2,6,8,0,13,1,1,2,6,8,0,8,8,1,8,3,4,7,8,0,8,8,13,15,2,15,15,1,8,12,2,13,8,1,1,11,13,2,9,0,9,1,2,13,8,2,2,8,8,13,2,13,10,8,8,1,8,0,1,9,0,8,13,8,10,8,3,11,13,2,8,8,8,4,8,1,7,11,13,2,13,8,1,8,2,7,11,13,2,13,8,2,2,8,8,8,4,3,7,11,13,2,9,0,9,1,9,0,9,1,1,8,8,2,13,8,3,3,13,8,8,7,8,5,2,7,11,13,2,9,0,9,1,9,0,1,7,9,1,4,8,8,13,7,8,2,7,8,4,2,13,7,8,2,3,8,8,13,7,8,4,2,13,13,2,6,11,13,2,9,0,9,1,9,0,1,6,9,1,2,8,8,8,8,2,15,6,11,13,2,13,8,3,4,8,8,3,3,10,8,8,1,6,8,8,1,11,11,1,9,0,9,8,8,13,15,7,11,13,2,13,8,3,7,8,3,13,15,7,8,2,7,8,4,6,15,15,15,15,15,15,1,8,6,1,8,7,12,65,100,100,76,105,113,117,105,100,105,116,121,7,65,112,112,73,110,102,111,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,9,76,105,113,117,105,100,105,116,121,6,79,112,116,105,111,110,11,80,111,111,108,67,97,116,97,108,111,103,8,80,111,111,108,73,110,102,111,13,80,111,111,108,76,105,113,117,105,100,105,116,121,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,15,82,101,109,111,118,101,76,105,113,117,105,100,105,116,121,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,13,97,100,100,95,108,105,113,117,105,100,105,116,121,7,97,108,112,104,97,95,49,6,97,109,111,117,110,116,9,97,112,112,95,105,110,102,111,115,13,97,112,112,95,108,105,113,117,105,100,105,116,121,5,97,115,99,105,105,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,5,101,118,101,110,116,18,101,120,105,115,116,95,99,101,114,116,97,105,110,95,112,111,111,108,13,101,120,105,115,116,95,112,111,111,108,95,105,100,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,100,101,102,97,117,108,116,95,97,108,112,104,97,95,49,20,103,101,116,95,100,101,102,97,117,108,116,95,108,97,109,98,100,97,95,49,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,24,103,101,116,95,112,111,111,108,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,112,111,111,108,95,110,97,109,101,95,98,121,95,105,100,21,103,101,116,95,112,111,111,108,95,116,111,116,97,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,115,95,98,121,95,105,100,19,103,101,116,95,116,111,107,101,110,95,108,105,113,117,105,100,105,116,121,2,105,100,11,105,100,95,116,111,95,112,111,111,108,115,4,105,110,105,116,8,108,97,109,98,100,97,95,49,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,110,97,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,12,112,111,111,108,95,97,100,100,114,101,115,115,12,112,111,111,108,95,99,97,116,97,108,111,103,10,112,111,111,108,95,105,110,102,111,115,12,112,111,111,108,95,109,97,110,97,103,101,114,10,112,111,111,108,95,116,111,95,105,100,5,112,111,111,108,115,13,114,101,103,105,115,116,101,114,95,112,111,111,108,16,114,101,103,105,115,116,101,114,95,112,111,111,108,95,105,100,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,7,114,101,115,101,114,118,101,21,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,97,108,112,104,97,22,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,108,97,109,98,100,97,15,115,101,116,95,112,111,111,108,95,119,101,105,103,104,116,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,116,97,98,108,101,12,116,111,116,97,108,95,119,101,105,103,104,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,119,101,105,103,104,116,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,14,122,101,114,111,95,108,105,113,117,105,100,105,116,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,0,88,241,76,176,44,241,78,240,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,37,164,0,10,139,202,34,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,0,2,4,49,8,12,19,11,13,2,13,8,1,61,11,13,2,13,8,2,60,8,5,1,2,1,20,11,13,2,13,8,3,2,2,5,54,8,10,68,8,3,17,15,75,15,64,11,13,2,8,8,8,4,3,2,1,78,15,4,2,4,78,15,52,15,30,15,79,15,5,2,2,63,11,13,2,8,8,13,50,11,13,2,13,10,8,8,6,2,3,59,8,8,18,15,31,15,7,2,3,59,8,8,18,15,30,15,0,0,0,0,1,14,10,0,17,30,10,0,56,0,10,0,56,1,10,0,56,2,11,0,56,3,18,5,18,0,56,4,2,1,1,0,0,29,54,10,1,10,3,12,5,46,11,5,17,18,32,4,9,5,15,11,1,1,11,4,1,7,2,39,10,1,15,0,12,12,11,2,12,6,17,20,12,7,10,4,56,5,12,8,11,6,11,7,7,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,8,18,2,12,11,11,12,10,3,11,11,56,6,10,1,15,1,15,2,10,3,64,32,0,0,0,0,0,0,0,0,56,7,11,1,15,3,12,10,11,4,56,8,18,1,12,9,11,10,11,3,11,9,56,9,2,2,1,0,0,34,52,10,1,10,3,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,10,1,10,2,12,5,46,11,5,17,19,32,4,21,5,25,11,1,1,7,4,39,10,1,15,1,12,6,10,6,15,4,10,2,10,3,56,10,11,6,15,2,10,3,56,11,10,2,68,32,11,1,15,0,11,3,56,12,15,5,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,4,56,13,2,3,1,0,0,37,43,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,12,6,10,6,15,5,11,2,56,14,12,7,10,6,16,6,20,10,7,16,7,20,23,10,3,22,11,6,15,6,21,11,3,11,7,15,7,21,2,4,1,0,0,38,22,10,1,10,2,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,11,1,15,0,11,2,56,12,12,5,11,3,11,5,15,8,21,2,5,1,0,0,39,29,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,15,5,11,2,56,14,12,6,11,3,11,6,15,9,21,2,6,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,1,15,2,11,1,12,3,46,11,3,56,15,20,2,7,1,0,0,43,22,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,11,0,15,1,15,4,11,1,12,3,46,11,3,56,16,20,2,8,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,0,11,1,12,3,46,11,3,56,17,16,10,20,2,9,1,0,0,44,32,10,0,10,1,17,18,4,5,5,9,11,0,1,7,3,39,11,0,16,3,11,1,56,18,16,11,12,4,10,4,10,2,56,19,4,26,11,4,11,2,56,20,16,12,20,12,3,5,30,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,10,1,0,0,9,20,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,13,16,12,20,2,11,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,14,20,2,12,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,15,20,2,13,1,0,0,9,19,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,6,20,2,14,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,7,20,2,15,1,0,0,1,2,7,0,2,16,1,0,0,1,2,7,1,2,17,1,0,0,45,34,11,0,11,1,17,6,12,6,14,6,65,32,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,32,5,14,14,6,10,4,66,32,20,12,3,14,3,17,23,10,2,33,4,27,11,3,56,22,2,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,9,56,23,2,18,1,0,0,1,5,11,0,16,0,11,1,56,24,2,19,1,0,0,1,6,11,0,16,1,16,4,11,1,56,25,2,20,1,0,0,1,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,2,21,3,0,0,48,119,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,12,16,15,20,10,12,16,9,20,17,25,12,10,10,3,10,10,22,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,32,4,73,11,7,11,2,10,6,18,3,56,27,5,85,11,7,11,2,56,28,12,8,10,8,16,12,20,10,6,22,11,8,15,12,21,10,11,16,13,16,12,20,10,3,22,11,11,15,13,15,12,21,10,12,16,14,20,10,3,22,10,12,15,14,21,10,12,16,15,20,10,10,23,11,12,15,15,21,11,1,11,3,10,10,18,6,56,29,11,6,11,10,2,22,3,0,0,48,151,1,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,12,16,14,20,10,3,38,4,33,5,41,11,0,1,11,12,1,11,11,1,7,8,39,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,11,16,8,20,10,12,16,9,20,17,24,12,10,10,3,10,10,23,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,4,82,5,90,11,12,1,11,11,1,11,7,1,7,6,39,11,7,11,2,56,28,12,8,10,8,16,12,20,10,3,38,4,101,5,109,11,12,1,11,11,1,11,8,1,7,7,39,10,8,16,12,20,10,3,23,11,8,15,12,21,10,11,16,13,16,12,20,10,6,23,11,11,15,13,15,12,21,10,12,16,14,20,10,6,23,10,12,15,14,21,10,12,16,15,20,10,10,22,11,12,15,15,21,11,1,11,3,10,10,18,7,56,30,11,6,11,10,2,0,2,0,3,5,1,0,1,5,0,2,4,2,3,4,3,2,2,4,1,2,0,1,0,3,0,2,1,4,0,4,2,0,53,0,80,0],"rates":[161,28,235,11,6,0,0,0,8,1,0,6,2,6,4,3,10,70,5,80,48,7,128,1,185,2,8,185,3,32,6,217,3,68,12,157,4,128,5,0,13,0,11,0,16,1,0,8,0,0,6,0,1,0,0,2,0,1,0,0,5,2,1,0,0,1,3,1,0,0,3,4,1,0,0,4,4,1,0,1,7,6,1,0,1,8,6,3,0,1,9,6,1,0,1,10,6,1,0,2,12,7,1,0,2,14,5,1,0,2,15,7,1,0,2,17,7,1,0,3,7,8,0,13,15,1,15,4,7,8,0,13,15,15,4,15,15,15,15,3,15,15,15,0,2,7,8,0,13,2,15,15,6,15,15,15,15,15,15,7,15,15,15,15,15,15,15,7,83,116,111,114,97,103,101,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,21,99,97,108,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,3,109,105,110,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,128,81,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,3,29,10,0,10,1,17,8,12,6,11,0,11,1,17,6,12,4,11,6,11,4,17,13,12,5,10,5,10,2,22,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,27,10,5,11,5,11,2,22,17,12,12,3,11,3,2,1,1,0,0,8,39,10,0,10,1,11,2,17,0,12,8,11,0,11,1,17,7,12,7,12,6,12,5,12,4,10,8,10,7,35,4,23,11,4,11,8,11,5,17,13,22,12,3,5,37,11,4,11,5,22,11,6,11,8,10,7,23,17,11,11,7,23,17,12,17,13,22,12,3,11,3,2,2,1,0,0,7,17,10,0,10,1,11,3,17,0,12,5,11,0,11,1,17,9,12,4,11,2,11,5,17,11,11,4,23,17,13,17,13,2,3,1,0,0,7,20,11,0,11,1,23,7,1,17,10,12,4,7,1,10,4,23,12,5,11,2,11,5,24,11,3,11,4,24,22,7,1,26,2,4,1,0,0,9,69,11,0,11,1,23,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,10,17,11,2,10,5,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,6,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,23,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,7,5,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,2,10,2,17,13,7,0,7,0,24,26,12,4,10,4,10,2,17,13,7,0,26,12,3,10,5,10,6,24,11,4,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,10,5,11,6,24,11,7,24,11,3,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,9,17,11,11,2,11,5,24,7,0,26,22,11,8,22,11,9,22,2,5,1,0,0,1,12,11,2,11,0,11,1,23,24,7,0,26,12,3,17,11,11,3,22,2,0],"ray_math":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,40,5,42,13,7,55,59,8,114,32,6,146,1,146,1,12,164,2,247,5,0,7,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,4,2,1,0,0,1,2,1,0,0,2,2,1,0,0,6,1,1,0,0,0,1,3,0,0,1,15,2,15,15,1,2,4,15,2,15,15,4,108,111,103,50,3,109,97,120,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,208,121,0,161,63,121,92,118,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,249,214,165,42,128,81,101,243,159,91,61,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,1,0,0,0,2,7,0,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,10,11,0,11,1,24,7,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,7,0,26,2,3,1,0,0,0,10,11,0,7,0,24,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,11,1,26,2,4,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,6,1,0,0,4,59,10,0,7,0,38,4,5,5,7,7,4,39,10,0,7,0,26,17,7,12,2,10,2,77,7,0,24,12,3,11,0,11,2,48,12,4,10,4,7,0,33,4,27,11,3,2,7,1,12,1,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,57,5,34,10,4,11,4,24,7,0,26,12,4,10,4,7,2,38,4,52,11,3,10,1,22,12,3,11,4,49,1,48,12,4,11,1,49,1,48,12,1,5,29,11,3,2,7,1,0,0,3,112,49,0,12,1,10,0,49,128,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,16,11,0,49,128,48,12,0,11,1,49,128,22,12,1,10,0,49,64,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,30,11,0,49,64,48,12,0,11,1,49,64,22,12,1,10,0,49,32,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,44,11,0,49,32,48,12,0,11,1,49,32,22,12,1,10,0,49,16,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,58,11,0,49,16,48,12,0,11,1,49,16,22,12,1,10,0,49,8,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,72,11,0,49,8,48,12,0,11,1,49,8,22,12,1,10,0,49,4,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,0,49,4,48,12,0,11,1,49,4,22,12,1,10,0,49,2,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,100,11,0,49,2,48,12,0,11,1,49,2,22,12,1,11,0,49,1,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,110,11,1,49,1,22,12,1,11,1,2,0],"scaled_balance":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,25,5,29,6,7,35,75,8,110,32,12,142,1,39,0,6,0,4,0,0,0,1,0,0,2,0,1,0,0,1,0,1,0,1,3,0,1,0,1,5,0,1,0,2,15,15,1,15,0,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,2,4,11,0,11,1,17,4,2,1,1,0,0,2,4,11,0,11,1,17,3,2,2,1,0,0,2,4,11,0,11,1,17,3,2,0],"serde":[161,28,235,11,6,0,0,0,9,1,0,12,2,12,8,3,20,167,1,4,187,1,12,5,199,1,148,1,7,219,2,211,4,8,174,7,96,6,142,8,20,12,162,8,157,35,0,23,1,4,1,6,1,36,1,37,2,2,1,0,7,0,3,1,7,0,0,32,0,1,0,0,28,2,1,0,0,31,3,1,0,0,26,4,1,0,0,29,5,1,0,0,19,6,6,0,0,5,6,6,0,0,27,4,1,0,0,30,5,1,0,0,33,7,1,0,0,24,8,1,0,0,25,9,1,1,0,0,34,7,1,0,0,14,10,6,0,0,10,10,11,0,0,13,10,12,0,0,8,10,13,0,0,11,10,14,0,0,9,10,13,0,0,12,10,14,0,0,7,10,15,0,0,18,10,12,0,0,15,10,16,0,0,38,17,18,1,1,0,39,19,20,1,3,1,20,28,16,0,2,35,27,16,1,0,3,17,1,30,1,0,3,21,30,28,0,4,3,25,1,1,0,4,22,24,1,1,0,5,16,16,15,0,30,6,29,6,26,15,27,29,23,6,23,29,2,7,10,2,2,0,2,7,10,2,13,2,7,10,2,3,2,7,10,2,4,2,7,10,2,15,1,2,2,7,10,2,10,2,2,7,10,2,5,1,7,10,2,1,6,10,2,1,13,1,3,1,4,1,15,1,5,1,10,2,3,6,10,9,0,3,3,1,10,9,0,2,6,10,9,0,9,0,1,10,10,9,0,2,1,2,3,1,1,2,2,4,10,2,1,7,10,9,0,2,7,10,9,0,10,9,0,2,15,10,2,1,6,9,0,1,8,0,1,9,0,1,8,1,2,4,3,2,15,3,3,10,2,3,3,3,1,3,10,9,0,3,3,10,10,9,0,3,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,6,97,112,112,101,110,100,5,97,115,99,105,105,16,97,115,99,105,105,95,116,111,95,104,101,120,95,115,116,114,3,98,99,115,19,100,101,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,16,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,29,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,29,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,30,100,101,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,17,103,101,116,95,118,101,99,116,111,114,95,108,101,110,103,116,104,16,104,101,120,95,115,116,114,95,116,111,95,97,115,99,105,105,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,7,114,101,118,101,114,115,101,5,115,101,114,100,101,17,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,14,115,101,114,105,97,108,105,122,101,95,116,121,112,101,14,115,101,114,105,97,108,105,122,101,95,117,49,50,56,27,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,27,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,28,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,6,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,12,118,101,99,116,111,114,95,115,112,108,105,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,68,6,2,1,1,0,0,1,15,10,0,10,1,49,8,48,72,255,0,28,51,17,0,11,0,11,1,72,255,0,28,51,17,0,2,2,1,0,0,1,63,10,0,10,1,49,56,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,6,255,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,6,255,0,0,0,0,0,0,0,28,51,17,0,2,3,1,0,0,1,127,10,0,10,1,49,120,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,4,1,0,0,1,255,1,10,0,10,1,49,248,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,240,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,232,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,224,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,216,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,208,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,200,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,192,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,184,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,176,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,168,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,160,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,152,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,144,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,136,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,128,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,120,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,5,1,0,0,21,31,10,0,49,0,38,4,9,10,0,49,9,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,22,12,2,5,29,10,0,49,15,37,4,23,5,25,7,1,39,11,0,49,87,22,12,2,11,2,2,6,1,0,0,22,40,10,0,49,48,38,4,9,10,0,49,57,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,3,5,38,10,0,49,97,38,4,27,10,0,49,102,37,12,2,5,29,9,12,2,11,2,4,32,5,34,7,1,39,11,0,49,87,23,12,3,11,3,2,7,1,0,0,23,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,8,1,0,0,26,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,9,1,0,0,1,4,11,0,11,1,56,1,2,10,1,0,0,16,17,14,1,56,2,12,2,14,2,65,6,6,32,0,0,0,0,0,0,0,33,4,9,5,13,11,0,1,7,0,39,11,0,11,2,56,1,2,11,1,0,0,28,8,56,3,17,28,12,1,11,0,11,1,17,25,17,9,2,12,1,0,0,12,17,14,1,65,6,12,2,10,2,6,0,0,0,0,0,0,0,0,33,4,10,11,0,1,2,10,0,11,2,17,2,11,0,11,1,17,9,2,13,1,0,0,1,15,10,0,65,6,6,1,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,6,0,0,0,0,0,0,0,0,66,6,20,2,14,1,0,0,1,24,10,0,65,6,6,2,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,75,49,8,47,11,0,6,1,0,0,0,0,0,0,0,66,6,20,75,22,2,15,1,0,0,1,72,10,0,65,6,6,8,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,52,49,56,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,52,49,48,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,52,49,40,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,52,49,32,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,52,49,24,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,52,49,16,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,52,49,8,47,22,11,0,6,7,0,0,0,0,0,0,0,66,6,20,52,22,2,16,1,0,0,1,136,1,10,0,65,6,6,16,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,53,49,120,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,53,49,112,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,53,49,104,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,53,49,96,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,53,49,88,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,53,49,80,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,53,49,72,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,53,49,64,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,53,49,56,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,53,49,48,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,53,49,40,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,53,49,32,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,53,49,24,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,53,49,16,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,53,49,8,47,22,11,0,6,15,0,0,0,0,0,0,0,66,6,20,53,22,2,17,1,0,0,1,136,2,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,77,49,248,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,77,49,240,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,77,49,232,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,77,49,224,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,77,49,216,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,77,49,208,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,77,49,200,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,77,49,192,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,77,49,184,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,77,49,176,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,77,49,168,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,77,49,160,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,77,49,152,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,77,49,144,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,77,49,136,47,22,10,0,6,15,0,0,0,0,0,0,0,66,6,20,77,49,128,47,22,10,0,6,16,0,0,0,0,0,0,0,66,6,20,77,49,120,47,22,10,0,6,17,0,0,0,0,0,0,0,66,6,20,77,49,112,47,22,10,0,6,18,0,0,0,0,0,0,0,66,6,20,77,49,104,47,22,10,0,6,19,0,0,0,0,0,0,0,66,6,20,77,49,96,47,22,10,0,6,20,0,0,0,0,0,0,0,66,6,20,77,49,88,47,22,10,0,6,21,0,0,0,0,0,0,0,66,6,20,77,49,80,47,22,10,0,6,22,0,0,0,0,0,0,0,66,6,20,77,49,72,47,22,10,0,6,23,0,0,0,0,0,0,0,66,6,20,77,49,64,47,22,10,0,6,24,0,0,0,0,0,0,0,66,6,20,77,49,56,47,22,10,0,6,25,0,0,0,0,0,0,0,66,6,20,77,49,48,47,22,10,0,6,26,0,0,0,0,0,0,0,66,6,20,77,49,40,47,22,10,0,6,27,0,0,0,0,0,0,0,66,6,20,77,49,32,47,22,10,0,6,28,0,0,0,0,0,0,0,66,6,20,77,49,24,47,22,10,0,6,29,0,0,0,0,0,0,0,66,6,20,77,49,16,47,22,10,0,6,30,0,0,0,0,0,0,0,66,6,20,77,49,8,47,22,11,0,6,31,0,0,0,0,0,0,0,66,6,20,77,22,2,18,1,0,0,31,29,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,53,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,19,1,0,0,32,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,77,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,20,1,0,0,1,14,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,20,17,31,2,21,1,0,0,16,8,11,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,2,22,1,0,0,33,46,10,0,65,6,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,64,6,0,0,0,0,0,0,0,0,2,10,3,6,8,0,0,0,0,0,0,0,36,4,16,5,20,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,12,2,11,3,10,2,6,8,0,0,0,0,0,0,0,22,33,4,35,5,39,11,0,1,7,0,39,11,0,6,8,0,0,0,0,0,0,0,11,2,6,8,0,0,0,0,0,0,0,22,56,4,2,23,1,0,0,34,43,10,1,10,2,35,4,10,10,2,10,0,65,29,37,12,3,5,12,9,12,3,11,3,4,15,5,19,11,0,1,7,0,39,64,29,0,0,0,0,0,0,0,0,12,5,11,1,12,4,10,4,10,2,35,4,39,5,28,13,5,10,0,10,4,66,29,20,68,29,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,23,11,0,1,11,5,2,24,1,0,0,35,53,64,18,0,0,0,0,0,0,0,0,12,3,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,29,35,4,38,5,12,10,0,10,2,66,29,20,10,1,33,4,33,10,4,10,2,35,4,29,13,3,10,0,11,4,10,2,56,5,68,18,10,2,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,10,4,10,2,35,4,49,13,3,11,0,11,4,11,2,56,5,68,18,5,51,11,0,1,11,3,2,0],"system_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,71,4,81,2,5,83,78,7,161,1,150,2,8,183,3,32,6,215,3,26,12,241,3,169,2,0,16,0,6,0,11,1,0,7,0,0,9,0,1,0,0,10,0,1,0,0,7,2,3,0,0,1,3,2,0,1,2,3,7,0,1,8,7,3,0,2,3,13,14,0,2,4,13,15,0,2,5,13,1,0,2,12,5,0,0,2,13,6,0,0,2,14,9,0,0,2,15,8,0,0,2,17,11,12,1,1,13,1,0,1,2,4,13,3,8,0,2,1,10,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,12,10,2,10,2,10,2,10,2,8,0,13,3,3,3,3,13,2,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,11,68,111,108,97,65,100,100,114,101,115,115,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,19,101,110,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,115,121,115,116,101,109,95,99,111,100,101,99,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,4,24,64,1,0,0,0,0,0,0,0,0,12,5,13,5,11,0,17,9,13,5,11,1,17,10,11,2,17,5,12,4,13,5,14,4,65,1,75,17,9,13,5,11,4,17,12,13,5,11,3,17,11,11,5,2,3,1,0,0,10,96,14,0,65,1,12,9,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,1,14,1,17,6,12,11,11,8,11,7,22,12,8,6,8,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,2,14,2,17,7,12,10,11,8,11,7,22,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,3,14,3,17,6,12,6,11,8,11,7,22,12,8,11,6,52,12,7,14,0,10,8,10,8,10,7,22,56,0,17,4,12,5,11,8,11,7,22,12,8,6,1,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,4,14,4,17,8,12,12,11,8,11,7,22,12,8,11,9,11,8,33,4,89,5,91,7,0,39,11,11,11,10,11,5,11,12,2,0],"system_core_storage":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,24,3,36,26,4,62,2,5,64,35,7,99,252,1,8,223,2,64,10,159,3,9,12,168,3,34,13,202,3,2,15,204,3,2,0,16,0,7,0,8,1,13,1,18,1,19,0,2,8,0,1,0,12,0,1,3,12,0,2,1,0,0,3,5,4,0,5,4,2,0,0,11,0,1,0,0,9,2,3,0,1,14,0,6,0,3,12,4,5,0,4,15,8,1,1,8,4,7,3,6,8,3,7,8,2,7,8,5,0,1,6,8,0,1,6,8,1,1,7,8,5,1,8,4,1,8,1,1,8,0,1,9,0,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,7,83,116,111,114,97,103,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,3,110,101,119,6,111,98,106,101,99,116,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,10,8,4,6,8,1,0,1,0,0,1,9,10,2,17,3,11,0,11,1,11,2,17,2,18,0,56,0,2,1,3,0,0,1,3,11,0,16,0,2,0,1,0,17,0],"system_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,24,2,24,40,3,64,71,4,135,1,2,5,137,1,117,7,254,1,155,4,8,153,6,96,6,249,6,10,10,131,7,17,12,148,7,191,1,0,33,0,10,0,16,0,19,0,31,0,32,0,38,0,39,1,14,1,18,1,34,2,30,0,7,3,0,1,0,12,0,2,3,7,0,3,4,8,0,5,6,8,0,6,9,12,0,7,2,12,0,8,1,8,0,10,8,2,0,11,5,12,0,0,11,0,1,0,0,35,0,1,0,2,22,13,8,0,2,23,13,14,0,3,13,3,1,0,4,15,8,9,0,4,21,1,10,0,4,24,1,10,0,5,20,4,5,0,6,11,12,1,0,6,27,11,1,0,6,35,12,1,0,7,26,6,7,0,9,17,16,1,1,3,13,15,8,6,8,3,7,8,5,7,8,9,7,8,6,6,8,4,10,2,6,8,7,7,8,8,0,6,10,2,8,2,2,3,8,2,13,1,6,8,3,1,6,8,4,1,6,8,1,6,7,8,9,7,8,6,6,8,1,10,2,6,8,7,7,8,8,2,8,2,10,2,1,10,2,4,13,3,8,2,2,1,2,2,7,8,5,8,2,3,7,8,5,8,2,8,2,1,6,8,2,1,13,1,8,0,1,9,0,6,10,2,2,3,8,2,13,8,2,6,65,112,112,67,97,112,5,67,108,111,99,107,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,5,83,116,97,116,101,7,83,116,111,114,97,103,101,15,83,121,115,116,101,109,67,111,114,101,69,118,101,110,116,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,11,97,112,112,95,109,97,110,97,103,101,114,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,110,111,110,99,101,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,12,115,121,115,116,101,109,95,99,111,100,101,99,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,0,2,6,25,3,28,10,2,29,13,37,13,36,10,2,12,2,0,1,4,0,2,51,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,12,11,8,17,5,12,10,12,9,12,11,12,13,10,10,17,6,33,4,23,5,27,11,1,1,7,0,39,10,12,10,9,33,4,35,11,1,10,12,17,10,5,39,11,1,10,12,10,9,17,9,11,11,14,12,17,2,11,13,14,9,17,3,14,9,17,2,11,10,18,0,56,0,2,1,1,4,0,17,43,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,11,11,8,17,5,12,9,12,13,12,10,12,12,10,9,17,7,33,4,23,5,27,11,1,1,7,0,39,11,1,10,11,10,13,17,11,11,10,14,11,17,2,11,12,14,13,17,3,14,13,17,2,11,9,18,0,56,0,2,0],"system_portal":[161,28,235,11,6,0,0,0,10,1,0,18,2,18,28,3,46,82,4,128,1,4,5,132,1,84,7,216,1,208,3,8,168,5,64,10,232,5,22,12,254,5,187,1,13,185,7,2,0,30,0,13,0,16,0,29,0,37,1,15,1,25,1,31,1,32,0,3,8,0,0,2,3,0,1,0,7,0,2,1,8,0,4,6,12,0,6,5,4,0,8,4,2,0,0,21,0,1,0,0,18,2,3,0,0,8,4,1,0,0,34,4,1,0,1,11,11,12,0,1,12,13,12,0,2,10,9,1,0,3,17,1,16,0,3,19,1,16,0,4,7,15,1,0,4,26,14,1,0,4,33,15,1,0,5,14,7,1,1,3,6,22,0,5,0,7,28,7,1,1,8,8,27,10,11,0,14,6,12,17,1,7,8,6,0,1,7,8,0,1,3,6,6,8,3,7,8,0,7,8,4,13,10,2,7,8,6,1,8,5,1,8,0,1,9,0,3,8,2,5,8,2,1,6,8,3,1,6,8,6,1,5,1,8,2,2,13,10,2,2,7,8,4,8,2,3,7,8,4,8,2,8,2,1,2,1,8,1,3,5,8,2,8,2,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,83,121,115,116,101,109,76,111,99,97,108,69,118,101,110,116,12,83,121,115,116,101,109,80,111,114,116,97,108,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,7,98,105,110,100,105,110,103,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,2,105,100,4,105,110,105,116,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,6,111,98,106,101,99,116,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,115,121,115,116,101,109,95,99,111,100,101,99,13,115,121,115,116,101,109,95,112,111,114,116,97,108,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,117,110,98,105,110,100,105,110,103,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,20,8,5,23,3,1,2,5,24,3,27,5,36,13,35,10,2,9,2,0,0,0,0,1,6,11,0,17,13,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,4,0,8,34,11,0,17,6,11,5,46,17,15,12,7,10,7,17,4,12,8,10,3,10,4,17,5,12,6,10,8,10,6,33,4,21,11,2,11,8,17,10,5,25,11,2,11,8,11,6,17,9,11,1,17,1,11,7,11,3,11,4,17,7,18,1,56,1,2,3,1,4,0,18,26,11,0,17,6,11,5,46,17,15,12,6,10,6,17,4,12,8,10,3,10,4,17,5,12,7,11,2,11,8,11,7,17,11,11,1,17,1,11,6,11,3,11,4,17,8,18,1,56,1,2,0,1,0],"user_manager":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,40,3,58,138,1,4,196,1,42,5,238,1,128,2,7,238,3,161,5,8,143,9,96,6,239,9,60,10,171,10,49,12,220,10,247,4,13,211,15,8,15,219,15,8,0,48,0,15,0,20,1,49,2,19,2,31,2,39,2,40,2,41,0,8,12,0,0,7,4,0,0,0,3,0,0,6,3,0,1,1,7,0,2,2,0,0,5,5,4,0,6,3,12,2,7,1,4,1,8,4,2,0,0,26,0,1,0,0,33,2,1,0,0,43,3,1,0,0,22,4,5,0,0,23,6,7,0,0,32,4,8,0,0,27,4,9,0,0,34,10,1,0,0,10,11,1,0,0,42,11,1,0,1,21,28,29,0,1,44,30,8,0,3,25,37,38,1,0,3,35,39,18,1,0,4,18,18,1,1,3,5,30,0,12,0,6,9,21,1,2,7,4,6,11,20,25,2,7,4,6,12,22,35,2,7,4,6,14,20,9,2,7,4,6,29,32,5,2,7,4,6,30,0,14,2,7,4,6,35,22,23,2,7,4,7,36,18,1,1,8,21,13,21,15,21,16,23,17,19,16,16,16,22,16,19,13,17,13,19,15,17,15,17,16,20,15,16,13,16,15,14,33,18,15,12,8,22,13,13,8,14,40,1,7,8,8,0,4,6,8,5,7,8,0,13,13,3,6,8,5,7,8,0,13,2,6,8,0,8,4,1,3,2,6,8,0,3,1,10,8,4,1,8,4,1,1,2,7,8,0,8,4,3,7,8,0,8,4,8,4,1,8,6,2,8,4,3,1,11,7,2,9,0,9,1,2,3,10,8,4,2,13,13,1,8,0,1,9,0,2,13,7,11,7,2,13,13,2,6,11,7,2,9,0,9,1,9,0,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,9,1,2,8,4,6,8,1,1,6,9,1,1,6,8,1,3,8,4,6,11,7,2,13,13,13,1,6,8,4,1,13,2,8,4,13,6,8,4,8,4,3,8,4,10,8,4,7,8,1,1,6,11,7,2,9,0,9,1,1,8,2,7,8,4,8,4,8,4,8,4,3,7,10,8,4,7,8,1,1,7,9,1,10,8,4,8,4,8,4,6,8,4,3,3,3,8,4,7,10,8,4,7,8,1,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,1,8,3,8,66,105,110,100,85,115,101,114,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,10,85,110,98,105,110,100,85,115,101,114,18,85,115,101,114,65,100,100,114,101,115,115,67,97,116,97,108,111,103,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,97,100,100,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,97,105,110,95,105,100,95,116,111,95,103,114,111,117,112,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,17,100,111,108,97,95,117,115,101,114,95,97,100,100,114,101,115,115,12,100,111,108,97,95,117,115,101,114,95,105,100,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,18,103,101,116,95,117,115,101,114,95,97,100,100,114,101,115,115,101,115,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,16,112,114,111,99,101,115,115,95,103,114,111,117,112,95,105,100,22,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,115,121,115,116,101,109,95,112,111,114,116,97,108,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,24,117,110,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,115,101,114,95,97,100,100,114,101,115,115,95,99,97,116,97,108,111,103,23,117,115,101,114,95,97,100,100,114,101,115,115,95,116,111,95,117,115,101,114,95,105,100,20,117,115,101,114,95,105,100,95,116,111,95,97,100,100,114,101,115,115,101,115,12,117,115,101,114,95,109,97,110,97,103,101,114,6,118,101,99,116,111,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,3,24,8,6,45,8,1,13,11,7,2,13,13,1,2,2,46,11,7,2,8,4,3,47,11,7,2,3,10,8,4,2,2,2,16,8,4,17,3,3,2,2,16,8,4,17,3,0,0,0,0,1,12,10,0,17,15,10,0,56,0,10,0,56,1,18,1,11,0,56,2,18,0,56,3,2,1,1,0,0,19,21,11,1,15,0,12,5,10,5,10,2,12,4,46,11,4,56,4,32,4,12,5,16,11,5,1,7,3,39,11,5,11,2,11,3,56,5,2,2,1,0,0,19,20,11,1,15,0,12,4,10,4,10,2,12,3,46,11,3,56,4,4,11,5,15,11,4,1,7,4,39,11,4,11,2,56,6,1,2,3,1,0,0,24,23,10,0,11,1,17,5,12,2,11,0,16,1,12,3,10,3,16,2,10,2,56,7,4,13,5,17,11,3,1,7,1,39,11,3,16,2,11,2,56,8,20,2,4,1,0,0,26,19,11,0,16,1,12,2,10,2,16,3,10,1,56,9,4,9,5,13,11,2,1,7,1,39,11,2,16,3,11,1,56,10,20,2,5,1,0,0,27,24,14,1,17,10,12,4,11,0,16,0,12,3,10,3,10,4,56,4,4,18,11,1,11,3,11,4,56,11,20,17,11,12,2,5,22,11,3,1,11,1,12,2,11,2,2,6,1,0,0,8,10,10,0,11,1,17,5,12,2,11,0,16,1,16,2,11,2,56,7,2,7,3,0,0,31,50,10,0,11,1,12,2,46,11,2,17,5,12,5,11,0,15,1,12,7,10,7,15,2,10,5,12,3,46,11,3,56,7,32,4,20,5,24,11,7,1,7,0,39,10,7,16,3,56,12,6,1,0,0,0,0,0,0,0,22,12,4,64,8,0,0,0,0,0,0,0,0,12,6,10,7,15,2,10,5,10,4,56,13,13,6,10,5,68,8,11,7,15,3,10,4,11,6,56,14,11,5,11,4,18,2,56,15,2,8,3,0,0,34,49,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,11,2,12,4,46,11,4,17,5,12,6,11,0,15,1,12,9,10,9,15,2,10,6,12,5,46,11,5,56,7,32,4,27,5,31,11,9,1,7,0,39,10,9,15,3,10,7,56,16,12,8,11,9,15,2,10,6,10,7,56,13,11,8,10,6,68,8,11,6,11,7,18,2,56,15,2,9,3,0,0,36,73,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,10,2,12,4,46,11,4,17,3,12,9,10,7,10,9,33,4,19,5,23,11,0,1,7,5,39,10,0,11,2,12,5,46,11,5,17,5,12,10,11,0,15,1,12,12,10,12,15,3,11,9,56,16,12,11,10,11,46,65,8,6,2,0,0,0,0,0,0,0,38,4,45,5,51,11,12,1,11,11,1,7,2,39,10,11,14,10,12,6,46,11,6,56,17,12,8,1,11,12,15,2,10,10,56,18,1,11,11,11,8,56,19,1,11,10,11,7,18,3,56,20,2,0,2,0,1,1,0,1,1,0,28,0,37,0,38,0,50,0],"wormhole_adapter_core":[161,28,235,11,6,0,0,0,12,1,0,46,2,46,114,3,160,1,212,1,4,244,2,22,5,138,3,146,3,7,156,6,196,10,8,224,16,96,6,192,17,30,10,222,17,68,12,162,18,236,4,13,142,23,6,15,148,23,6,0,90,0,27,0,36,0,46,0,62,0,63,0,87,0,91,1,29,1,30,1,44,1,59,1,60,1,81,1,85,1,86,1,89,2,28,2,40,2,45,2,66,2,80,2,88,0,4,12,0,0,15,3,0,0,5,3,0,0,16,3,0,0,6,3,0,0,17,3,0,0,7,3,0,1,0,12,0,2,8,7,0,3,11,0,0,5,14,12,0,6,23,12,0,7,22,12,0,8,2,8,0,9,3,12,1,0,1,11,21,4,0,12,13,12,2,7,1,12,1,13,18,2,0,15,20,2,0,16,25,7,2,1,0,0,0,17,1,7,0,18,9,12,0,19,10,7,0,20,12,0,0,21,19,12,0,22,24,0,0,0,53,0,1,0,0,71,2,1,0,0,35,3,1,0,0,75,4,1,0,0,76,4,1,0,0,73,4,1,0,0,74,4,1,0,0,68,5,6,0,0,67,7,8,0,0,69,5,6,0,0,79,9,10,0,1,47,45,46,0,4,33,24,48,0,4,34,24,44,0,4,42,33,24,0,4,43,54,24,0,4,48,1,32,0,4,49,1,32,0,4,50,1,32,0,4,51,1,32,0,5,26,49,50,0,5,78,49,50,0,6,55,51,23,0,6,70,52,1,0,7,61,42,43,0,10,39,21,1,1,3,11,58,12,13,0,12,58,12,17,2,7,12,14,65,21,1,1,12,16,32,22,23,2,1,0,16,41,1,19,2,1,0,16,54,27,1,2,1,0,16,77,29,30,2,1,0,17,58,24,25,0,18,58,14,15,0,19,58,25,26,0,19,84,26,24,0,20,64,34,35,0,20,66,36,10,0,22,83,43,24,0,27,16,30,18,28,20,29,18,31,18,25,28,32,18,25,37,25,38,25,39,25,40,3,6,8,9,7,8,24,7,8,18,0,4,6,8,9,7,8,0,13,10,2,3,6,8,9,7,8,0,13,7,6,8,9,7,8,24,7,8,0,13,15,11,14,1,8,17,6,8,13,6,7,8,24,7,8,0,6,8,7,10,2,6,8,13,7,8,18,2,8,8,10,2,8,7,8,24,7,8,0,6,8,7,10,2,7,8,10,7,8,11,6,8,13,7,8,18,4,8,8,8,8,15,10,2,11,7,8,24,7,8,0,6,8,7,7,8,10,8,8,8,8,13,3,15,11,14,1,8,17,6,8,13,1,3,3,7,8,24,7,8,18,8,15,1,7,8,18,1,8,15,2,6,8,24,7,8,18,1,8,21,2,8,20,8,12,1,11,16,2,9,0,9,1,2,13,8,22,1,11,19,2,9,0,9,1,1,8,0,1,9,0,2,6,11,19,2,9,0,9,1,6,9,0,1,1,1,10,2,1,8,20,1,8,22,3,7,11,19,2,9,0,9,1,9,0,9,1,1,8,1,2,7,11,19,2,9,0,9,1,6,9,0,2,9,0,9,1,2,8,23,10,2,1,2,3,13,15,2,3,7,8,21,14,10,2,1,8,23,4,7,8,24,11,14,1,8,17,8,23,6,8,13,1,8,3,1,8,5,1,8,4,1,8,6,3,13,10,2,8,8,6,7,8,24,6,11,19,2,13,8,22,7,11,16,2,8,20,8,12,10,2,6,8,13,7,8,18,1,8,25,4,8,8,13,2,10,2,1,6,8,7,1,13,7,8,8,15,3,13,10,2,8,8,8,8,6,8,8,8,8,3,13,2,10,2,4,7,8,10,8,8,13,15,2,15,15,2,6,8,11,8,8,2,7,8,11,8,8,3,15,8,23,10,2,5,13,3,8,8,8,8,3,6,65,112,112,67,97,112,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,12,68,101,108,101,116,101,66,114,105,100,103,101,11,68,101,108,101,116,101,79,119,110,101,114,13,68,101,108,101,116,101,83,112,101,110,100,101,114,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,14,82,101,103,105,115,116,101,114,66,114,105,100,103,101,13,82,101,103,105,115,116,101,114,79,119,110,101,114,15,82,101,103,105,115,116,101,114,83,112,101,110,100,101,114,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,86,65,65,6,86,101,99,77,97,112,13,97,100,100,95,108,105,113,117,105,100,105,116,121,11,97,112,112,95,109,97,110,97,103,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,8,99,111,110,116,97,105,110,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,20,100,101,108,101,116,101,95,114,101,109,111,116,101,95,98,114,105,100,103,101,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,13,100,111,108,97,95,99,111,110,116,114,97,99,116,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,21,103,101,116,95,100,101,108,101,116,101,95,111,119,110,101,114,95,116,121,112,101,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,23,103,101,116,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,6,105,110,115,101,114,116,12,105,115,95,100,111,108,97,95,117,115,101,114,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,10,112,111,111,108,95,99,111,100,101,99,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,22,114,101,103,105,115,116,101,114,95,114,101,109,111,116,101,95,98,114,105,100,103,101,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,19,114,101,109,111,116,101,95,100,101,108,101,116,101,95,111,119,110,101,114,21,114,101,109,111,116,101,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,21,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,23,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,5,115,116,97,116,101,3,115,117,105,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,3,118,97,97,7,118,101,99,95,109,97,112,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,24,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,22,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,99,104,97,105,110,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,4,52,8,15,92,8,21,31,11,16,2,8,20,8,12,72,11,19,2,13,8,22,1,2,2,94,13,93,10,2,2,2,2,94,13,93,10,2,3,2,2,37,13,38,15,4,2,2,37,13,38,15,5,2,2,37,13,38,15,6,2,2,37,13,38,15,0,1,0,0,11,18,10,2,17,26,12,5,11,1,10,2,12,4,12,3,11,5,11,3,46,11,4,17,34,11,2,56,0,56,1,18,0,56,2,2,1,1,0,0,1,23,10,1,16,0,14,2,56,3,32,4,7,5,11,11,1,1,7,1,39,11,1,15,0,10,2,10,3,17,33,17,35,56,4,11,2,11,3,18,1,56,5,2,2,1,0,0,26,22,10,1,16,0,14,2,56,3,4,6,5,10,11,1,1,7,0,39,11,1,15,0,14,2,56,6,12,3,1,11,2,11,3,17,36,18,1,56,5,2,3,1,0,0,31,22,10,3,10,4,17,18,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,3,56,7,2,4,1,0,0,31,22,10,3,10,4,17,19,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,5,56,8,2,5,1,0,0,31,22,10,3,10,4,17,16,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,4,56,9,2,6,1,0,0,31,22,10,3,10,4,17,17,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,37,12,7,11,1,11,5,11,7,11,6,17,38,1,11,3,11,4,18,6,56,10,2,7,3,0,0,41,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,24,17,39,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,8,3,0,0,47,59,11,0,10,1,16,0,11,1,15,2,11,3,11,6,11,7,17,24,17,39,17,12,12,12,1,12,11,12,10,12,14,12,13,10,2,17,11,11,11,33,4,23,5,31,11,5,1,11,4,1,11,2,1,7,2,39,11,4,10,13,11,2,17,11,11,10,77,17,20,1,12,9,10,5,10,14,12,8,46,11,8,17,22,32,4,52,11,5,10,14,17,23,5,54,11,5,1,11,13,11,14,11,9,11,12,2,9,3,0,0,41,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,24,17,39,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,10,3,0,0,53,28,11,3,10,4,11,2,17,11,11,8,17,21,1,12,11,11,6,11,7,11,4,11,5,11,11,52,17,15,12,13,11,1,15,1,73,0,0,0,0,11,13,17,37,12,12,11,0,11,9,11,12,11,10,17,38,2,0,3,0,1,0,2,0,56,0,57,0,82,0],"wormhole_adapter_pool":[161,28,235,11,6,0,0,0,11,1,0,42,2,42,92,3,134,1,142,1,4,148,2,16,5,164,2,185,2,7,221,4,156,6,8,249,10,96,6,217,11,50,10,139,12,51,12,190,12,168,2,13,230,14,10,0,70,0,29,0,30,0,37,0,51,0,71,1,23,1,24,1,35,1,47,1,48,1,63,1,65,1,66,1,68,2,21,2,33,2,36,2,53,2,62,2,67,0,10,8,0,0,11,8,0,0,12,3,0,1,3,7,0,2,9,12,1,0,1,3,6,8,0,5,17,12,0,6,1,8,0,7,2,12,1,0,1,9,16,4,0,10,8,12,2,7,1,12,1,11,13,2,0,13,15,2,0,14,19,7,2,1,0,0,0,15,0,7,0,16,4,12,0,17,5,7,0,18,7,0,0,19,14,12,0,20,18,0,0,0,41,0,1,0,0,42,2,1,0,0,57,3,1,1,0,0,58,4,1,0,0,54,5,1,1,0,1,38,36,16,0,1,39,36,37,0,2,28,24,16,1,0,2,58,29,16,0,2,69,35,1,1,0,3,22,31,1,0,4,27,16,34,0,5,49,32,33,0,8,32,10,1,1,3,9,45,0,6,0,10,45,0,21,2,7,12,12,60,10,1,1,8,13,59,7,8,0,14,34,1,15,2,1,0,14,43,19,1,2,1,0,15,45,16,17,0,16,45,12,13,0,17,45,17,18,0,18,52,25,26,0,18,53,27,28,0,20,64,33,16,0,16,9,18,14,19,14,15,20,16,22,7,10,9,10,13,38,1,7,8,12,0,5,7,8,0,13,10,2,7,8,18,7,8,12,9,7,8,1,7,8,18,11,8,1,8,11,7,11,4,1,9,0,11,8,1,9,0,13,10,2,6,8,7,7,8,12,7,7,8,1,7,8,18,11,8,1,8,11,13,10,2,6,8,7,7,8,12,7,6,8,5,7,8,18,7,8,1,7,11,4,1,9,0,10,2,6,8,7,7,8,12,1,8,9,1,6,8,12,1,5,1,8,0,1,9,0,3,7,8,12,11,13,2,13,8,16,8,15,2,6,8,18,7,8,12,1,8,15,2,13,8,16,1,11,13,2,9,0,9,1,1,10,2,1,8,14,1,8,16,3,7,11,13,2,9,0,9,1,9,0,9,1,2,8,14,8,6,1,11,10,2,9,0,9,1,1,8,1,2,8,17,10,2,5,7,11,4,1,9,0,11,8,1,9,0,13,10,2,7,8,12,3,7,8,15,14,10,2,1,8,17,4,7,8,18,11,8,1,8,11,8,17,6,8,7,1,3,3,13,10,2,7,8,12,5,3,3,8,3,8,3,13,1,6,8,5,6,7,8,18,6,11,13,2,13,8,16,7,11,10,2,8,14,8,6,10,2,6,8,7,7,8,12,1,8,19,6,13,3,8,3,8,3,3,2,5,7,11,4,1,9,0,8,3,3,8,3,7,8,12,1,6,8,3,1,13,1,8,2,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,4,80,111,111,108,11,80,111,111,108,71,101,110,101,115,105,115,9,80,111,111,108,83,116,97,116,101,17,80,111,111,108,87,105,116,104,100,114,97,119,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,6,97,109,111,117,110,116,7,98,121,116,101,115,51,50,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,7,99,114,101,97,116,111,114,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,12,100,115,116,95,99,104,97,105,110,95,105,100,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,4,105,110,105,116,10,105,110,105,116,105,97,108,105,122,101,6,105,110,115,101,114,116,7,105,115,95,105,110,105,116,3,110,101,119,5,110,111,110,99,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,12,112,111,111,108,95,97,100,100,114,101,115,115,10,112,111,111,108,95,99,111,100,101,99,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,12,115,101,110,100,95,100,101,112,111,115,105,116,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,3,115,117,105,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,40,8,9,26,5,44,1,1,2,4,40,8,9,72,8,15,25,11,10,2,8,14,8,6,56,11,13,2,13,8,16,2,2,6,46,3,61,13,31,13,50,10,2,55,10,2,20,3,0,0,0,0,1,9,10,0,17,14,11,0,46,17,17,9,18,0,56,0,2,1,1,4,0,11,59,10,0,16,0,20,10,4,46,17,17,33,4,9,5,17,11,3,1,11,0,1,11,4,1,7,2,39,10,0,16,1,20,32,4,23,5,31,11,3,1,11,0,1,11,4,1,7,3,39,11,3,10,4,12,5,46,11,5,17,21,12,7,56,1,12,6,13,6,11,1,11,2,17,20,17,22,56,2,10,4,17,14,11,7,11,4,56,3,11,6,18,1,56,4,8,11,0,15,1,21,2,2,3,0,0,23,20,11,3,11,4,11,5,11,6,11,8,56,5,12,10,11,0,15,2,73,0,0,0,0,11,10,17,23,12,9,11,1,11,2,11,9,11,7,17,24,1,2,3,3,0,0,23,18,11,3,11,4,11,6,17,8,12,8,11,0,15,2,73,0,0,0,0,11,8,17,23,12,7,11,1,11,2,11,7,11,5,17,24,1,2,4,1,4,0,30,37,11,0,17,10,11,1,10,2,16,3,11,2,15,4,11,4,11,5,10,6,17,12,17,25,17,11,1,12,7,12,10,12,9,12,8,12,11,11,3,10,10,10,7,10,9,11,6,56,6,11,8,11,11,14,9,17,6,14,9,17,5,14,10,17,5,11,7,18,2,56,7,2,0,1,0,2,1,1,1,3,1,2,0],"wormhole_adapter_verify":[161,28,235,11,6,0,0,0,10,1,0,22,2,22,54,3,76,102,4,178,1,16,5,194,1,206,1,7,144,3,135,3,8,151,6,128,1,6,151,7,30,10,181,7,6,12,187,7,205,1,0,38,1,29,2,14,2,27,2,28,2,35,2,37,3,13,3,19,3,34,3,36,0,8,12,0,1,4,7,1,0,0,2,1,8,0,3,7,4,0,4,3,12,2,7,1,12,1,5,6,2,0,6,10,7,2,1,0,0,0,7,0,7,0,8,2,7,0,9,5,12,0,10,9,0,0,0,22,0,1,0,0,12,2,3,0,0,30,4,5,0,0,32,6,3,0,0,31,7,5,0,1,20,19,13,1,0,1,24,18,10,1,0,1,26,3,14,1,0,1,33,13,14,1,0,3,25,25,26,0,4,11,27,3,2,7,12,4,15,24,10,2,7,12,6,15,9,10,2,1,0,6,21,9,11,2,1,0,10,16,16,22,0,10,17,16,12,0,10,18,16,17,0,10,30,21,5,0,12,8,13,8,8,12,7,12,6,12,5,12,11,23,10,23,2,6,11,6,2,13,8,8,6,13,1,11,1,1,8,8,2,6,11,6,2,13,8,8,6,8,10,0,4,7,8,9,6,11,6,2,13,8,8,10,2,6,8,2,1,8,10,3,7,11,4,2,8,7,8,0,6,8,10,7,8,5,6,7,8,9,6,11,6,2,13,8,8,7,11,4,2,8,7,8,0,10,2,6,8,2,7,8,5,2,13,8,8,2,6,11,6,2,9,0,9,1,6,9,0,1,1,1,6,9,1,1,8,8,1,9,0,1,11,1,1,9,0,2,11,1,1,8,8,13,1,6,8,10,1,13,1,6,11,1,1,9,0,1,7,11,1,1,9,0,3,10,2,6,8,2,8,10,3,6,8,9,10,2,6,8,2,1,8,7,2,8,7,8,0,2,6,11,4,2,9,0,9,1,9,0,1,7,8,5,1,8,3,3,7,11,4,2,9,0,9,1,9,0,9,1,7,66,121,116,101,115,51,50,5,67,108,111,99,107,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,3,97,100,100,20,97,115,115,101,114,116,95,107,110,111,119,110,95,101,109,105,116,116,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,6,100,105,103,101,115,116,15,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,13,101,109,105,116,116,101,114,95,99,104,97,105,110,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,101,120,116,114,97,99,116,3,103,101,116,22,103,101,116,95,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,2,105,100,7,105,115,95,115,111,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,14,114,101,112,108,97,121,95,112,114,111,116,101,99,116,4,115,111,109,101,5,115,116,97,116,101,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,1,23,8,3,0,1,0,0,1,19,10,0,10,1,56,0,4,11,11,0,11,1,56,1,20,56,2,12,2,5,17,11,1,1,11,0,1,56,3,12,2,11,2,2,1,1,0,0,15,25,10,1,17,16,12,3,11,0,14,3,17,0,12,2,14,2,56,4,4,11,5,15,11,1,1,7,0,39,13,2,56,5,11,1,17,15,33,4,22,5,24,7,1,39,2,2,1,0,0,20,15,11,0,11,2,11,3,12,5,12,4,46,11,4,11,5,17,17,12,6,11,1,14,6,17,1,11,6,2,3,1,0,0,22,26,10,0,10,1,17,14,12,3,46,11,3,56,6,32,4,10,5,18,11,1,1,11,2,1,11,0,1,7,2,39,11,0,11,1,17,14,11,2,17,9,18,0,56,7,2,4,1,0,0,5,12,11,0,11,1,11,3,11,4,17,2,12,6,11,2,14,6,11,5,17,3,11,6,2,0]},"type_origin_table":[{"module_name":"dola_address","struct_name":"DolaAddress","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"Pool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"DepositPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"WithdrawPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_verify","struct_name":"Unit","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceManagerCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version_1_0_0","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"app_manager","struct_name":"TotalAppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"app_manager","struct_name":"AppCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"UserInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ReserveData","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ScaledBalance","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"BorrowRateFactors","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"PriceOracle","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"Price","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"Liquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AddLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"RemoveLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_logic","struct_name":"LendingCoreExecuteEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserAddressCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"BindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UnbindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"CoreState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"LendingCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_wormhole_adapter","struct_name":"SystemCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolWithdrawEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":1},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":5},"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302":{"upgraded_id":"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302","upgraded_version":1},"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a":{"upgraded_id":"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a","upgraded_version":1}}}},"owner":"Immutable","previous_transaction":"BPLPMMmGBp3vAM6v31MEKfQLcUzKmgin9gBefQsnbg4m","storage_rebate":548454000},{"data":{"Move":{"type_":{"Other":{"address":"0000000000000000000000000000000000000000000000000000000000000002","module":"dynamic_field","name":"Field","type_args":[{"struct":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"genesis","name":"Version","type_args":[]}},{"struct":{"address":"826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e","module":"genesis","name":"Version_1_0_0","type_args":[]}}]}},"has_public_transfer":false,"version":3478819,"contents":[137,141,210,76,196,132,118,167,162,255,54,55,42,68,63,239,165,53,69,176,22,254,179,23,187,9,30,96,224,107,46,76,0,0]}},"owner":{"ObjectOwner":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621"},"previous_transaction":"McsTGPLu3V5rpv6CyPNv6rG5f4NAZMuVbWfadUqPjR2","storage_rebate":2150800},{"data":{"Package":{"id":"0xc5b2a5049cd71586362d0c6a38e34cfaae7ea9ce6d5401a350506a15f817bf72","version":2,"module_map":{"app_manager":[161,28,235,11,6,0,0,0,10,1,0,10,2,10,24,3,34,46,4,80,2,5,82,54,7,136,1,228,1,8,236,2,64,10,172,3,18,12,190,3,106,13,168,4,4,0,8,0,11,1,16,1,20,1,21,0,3,12,0,0,0,12,0,1,1,0,0,2,2,7,0,2,5,4,0,4,4,2,0,0,14,0,1,0,0,17,2,3,0,0,18,4,3,0,0,12,5,6,0,0,10,3,1,0,2,9,7,1,0,2,15,0,7,0,2,22,12,8,0,3,19,10,1,1,8,8,9,1,7,8,5,0,2,7,8,0,7,8,5,1,8,1,3,6,8,2,7,8,0,7,8,5,1,6,8,1,1,13,1,8,4,1,8,3,1,8,0,1,9,0,3,8,1,8,3,8,4,1,6,8,4,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,2,73,68,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,97,112,112,95,99,97,112,115,6,97,112,112,95,105,100,11,97,112,112,95,109,97,110,97,103,101,114,6,100,101,108,101,116,101,15,100,101,115,116,114,111,121,95,97,112,112,95,99,97,112,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,2,105,100,4,105,110,105,116,3,110,101,119,6,111,98,106,101,99,116,12,114,101,103,105,115,116,101,114,95,97,112,112,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,105,100,95,116,111,95,105,110,110,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,13,8,4,6,10,8,3,1,2,2,13,8,4,7,13,0,0,0,0,1,6,11,0,17,6,64,8,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,11,19,11,1,17,6,12,4,14,4,17,7,12,3,11,4,10,0,16,0,65,8,75,18,1,12,2,11,0,15,0,11,3,68,8,11,2,2,2,1,0,0,1,4,11,1,11,2,17,1,2,3,1,0,0,1,4,11,0,16,1,20,2,4,1,0,0,1,5,11,0,19,1,1,17,5,2,0,1,1,1,0],"dola_address":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,12,3,24,109,4,133,1,6,5,139,1,78,7,217,1,191,3,8,152,5,96,6,248,5,14,10,134,6,8,12,142,6,151,2,13,165,8,4,0,13,0,23,1,4,1,27,2,3,2,5,0,0,7,0,2,1,7,0,3,2,7,0,0,20,0,1,0,0,19,2,1,0,0,18,2,3,0,0,29,4,5,0,0,28,6,5,0,0,10,7,5,0,0,6,8,5,0,0,7,5,8,0,0,9,0,5,1,0,0,8,5,3,0,0,15,5,3,0,0,11,3,5,0,1,12,19,1,0,1,24,14,0,0,1,25,15,0,0,1,30,17,18,1,1,2,21,13,3,0,3,17,0,12,1,0,3,22,12,13,0,4,16,3,8,0,5,26,9,3,1,0,20,8,17,11,15,10,0,1,13,1,6,8,0,1,10,2,2,8,0,13,1,8,0,2,8,0,10,2,2,13,10,2,1,5,1,6,9,0,1,2,1,9,0,1,8,2,1,8,1,2,7,10,2,13,2,7,10,2,10,2,6,10,2,3,10,2,13,3,3,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,11,68,111,108,97,65,100,100,114,101,115,115,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,5,97,115,99,105,105,3,98,99,115,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,112,111,111,108,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,19,117,112,100,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,13,2,0,0,0,2,2,14,13,13,10,2,0,1,0,0,0,2,7,1,2,1,1,0,0,0,4,11,0,16,0,20,2,2,1,0,0,0,4,11,0,16,1,20,2,3,1,0,0,0,6,11,1,13,0,15,0,21,11,0,2,4,1,0,0,0,6,11,1,13,0,15,1,21,11,0,2,5,1,0,0,0,4,11,0,11,1,18,0,2,6,1,0,0,0,5,7,1,14,0,56,0,18,0,2,7,1,0,0,0,14,14,0,16,1,65,10,6,32,0,0,0,0,0,0,0,33,4,7,5,9,7,0,39,14,0,16,1,20,17,19,2,8,1,0,0,3,8,56,1,17,18,17,16,12,0,7,1,11,0,18,0,2,9,1,0,0,0,4,14,0,16,1,20,2,10,1,0,0,3,14,64,10,0,0,0,0,0,0,0,0,12,1,13,1,14,0,16,0,20,17,13,13,1,14,0,16,1,20,17,14,11,1,2,11,1,0,0,16,30,14,0,65,10,12,6,6,0,0,0,0,0,0,0,0,12,5,6,2,0,0,0,0,0,0,0,12,2,14,0,10,5,10,5,10,2,22,56,2,12,1,14,1,17,12,12,4,11,5,11,2,22,12,5,14,0,11,5,11,6,56,2,12,3,11,4,11,3,18,0,2,0,0,0,1,0],"dola_pool":[161,28,235,11,6,0,0,0,14,1,0,22,2,22,52,3,74,173,1,4,247,1,32,5,151,2,211,1,7,234,3,168,5,8,146,9,96,6,242,9,50,10,164,10,34,11,198,10,2,12,200,10,222,2,13,166,13,4,14,170,13,4,15,174,13,4,0,23,0,22,0,45,1,12,1,54,2,13,2,14,2,27,2,43,2,52,2,53,0,5,12,1,0,1,0,3,3,0,0,10,3,0,1,4,7,0,3,6,7,0,4,8,7,0,5,0,4,1,0,1,6,1,12,1,0,1,6,2,12,1,0,1,8,9,4,0,10,7,2,0,0,30,0,1,1,0,0,19,2,3,1,0,0,16,4,5,0,0,42,6,5,1,0,0,55,6,5,1,0,0,21,7,8,1,0,0,57,9,3,1,0,0,48,10,8,0,1,15,19,21,0,1,17,21,19,0,1,18,3,21,1,0,1,32,30,8,0,1,33,30,29,0,1,34,3,29,0,2,25,22,8,0,2,26,35,8,0,3,37,26,8,0,4,29,3,25,1,0,4,38,25,26,0,5,39,24,5,1,0,5,51,31,15,1,0,5,59,3,15,1,0,6,28,32,23,1,0,6,31,12,1,1,0,6,36,23,15,1,0,6,56,20,5,1,0,7,24,11,3,1,3,8,41,13,14,0,9,46,34,3,1,12,9,50,11,3,1,8,10,49,18,19,0,23,11,21,11,29,16,0,11,25,11,3,11,10,11,24,11,19,11,17,11,26,27,4,11,20,11,22,11,26,33,28,23,1,6,11,0,1,9,0,1,2,2,6,11,8,1,9,0,7,8,10,0,3,3,2,2,1,3,2,6,11,0,1,9,0,3,5,7,11,0,1,9,0,11,7,1,9,0,13,10,2,7,8,10,1,10,2,5,7,11,0,1,9,0,8,3,3,8,3,7,8,10,3,13,10,2,7,8,10,1,9,0,1,6,11,8,1,9,0,1,7,8,10,1,8,9,1,11,6,1,9,0,1,11,0,1,9,0,6,3,3,3,10,2,5,8,3,1,6,8,10,1,5,1,6,11,7,1,9,0,1,8,3,5,8,3,8,3,3,13,10,2,1,11,7,1,9,0,2,7,11,6,1,9,0,11,6,1,9,0,1,8,5,1,8,4,1,8,1,3,3,11,7,1,9,0,5,1,13,1,6,8,3,2,7,11,6,1,9,0,3,2,11,6,1,9,0,7,8,10,1,8,2,2,9,0,5,3,8,3,13,10,2,7,66,97,108,97,110,99,101,4,67,111,105,110,12,67,111,105,110,77,101,116,97,100,97,116,97,11,68,101,112,111,115,105,116,80,111,111,108,11,68,111,108,97,65,100,100,114,101,115,115,4,80,111,111,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,12,87,105,116,104,100,114,97,119,80,111,111,108,6,97,109,111,117,110,116,5,97,115,99,105,105,7,98,97,108,97,110,99,101,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,14,99,111,110,118,101,114,116,95,97,109,111,117,110,116,23,99,111,110,118,101,114,116,95,100,111,108,97,95,116,111,95,97,100,100,114,101,115,115,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,11,99,114,101,97,116,101,95,112,111,111,108,7,100,101,99,105,109,97,108,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,4,101,109,105,116,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,5,101,118,101,110,116,12,102,114,111,109,95,98,97,108,97,110,99,101,3,103,101,116,16,103,101,116,95,99,111,105,110,95,100,101,99,105,109,97,108,12,103,101,116,95,100,101,99,105,109,97,108,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,12,105,110,116,111,95,98,97,108,97,110,99,101,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,4,106,111,105,110,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,4,112,111,111,108,10,112,111,111,108,95,99,111,100,101,99,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,15,117,110,110,111,114,109,97,108,95,97,109,111,117,110,116,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,35,8,9,13,11,6,1,9,0,20,2,1,2,3,44,8,4,49,5,11,3,2,2,3,44,8,4,47,5,11,3,0,11,0,1,0,0,3,4,11,0,55,0,20,2,1,1,0,0,1,10,11,0,56,0,12,2,11,1,17,27,56,1,11,2,57,0,56,2,2,2,1,0,0,3,29,10,1,10,2,34,4,27,5,5,10,1,10,2,35,4,18,11,0,6,10,0,0,0,0,0,0,0,24,12,0,11,1,49,1,22,12,1,5,26,11,0,6,10,0,0,0,0,0,0,0,26,12,0,11,1,49,1,23,12,1,5,0,11,0,2,3,1,0,0,1,8,11,0,56,3,12,2,11,1,11,2,49,8,17,2,2,4,1,0,0,1,8,11,0,56,3,12,2,11,1,49,8,11,2,17,2,2,5,3,0,0,17,38,11,4,46,17,30,12,9,14,1,56,4,12,7,10,0,10,7,12,5,46,11,5,56,5,12,6,10,9,17,8,12,10,56,6,11,10,11,6,11,2,11,3,17,14,12,8,11,0,54,1,11,1,56,7,56,8,1,56,9,17,18,11,9,11,7,18,1,56,10,11,8,2,6,3,0,0,28,53,17,13,14,3,17,12,33,4,6,5,12,11,0,1,11,4,1,7,4,39,14,3,17,11,56,9,17,18,17,16,33,4,20,5,26,11,0,1,11,4,1,7,0,39,11,1,17,9,12,7,10,0,11,2,12,5,46,11,5,56,11,12,2,11,0,54,1,10,2,56,12,11,4,56,13,12,6,56,9,17,18,10,7,11,2,18,2,56,14,11,6,11,7,56,15,2,7,3,0,0,3,8,11,2,46,17,30,17,8,11,0,11,1,17,15,2,0,2,0,1,0,11,1,11,0,40,0,58,0],"equilibrium_fee":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,50,5,54,29,7,83,174,1,8,129,2,32,12,161,2,197,5,0,4,0,10,0,2,0,1,0,0,3,2,1,0,0,0,3,1,0,0,1,3,1,0,1,5,0,1,0,1,6,4,1,0,1,7,0,1,0,1,8,4,1,0,1,9,1,1,0,1,11,0,1,0,2,15,15,1,15,3,15,15,15,6,15,15,15,15,15,15,0,4,1,15,15,15,6,1,15,15,15,15,15,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,27,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,112,101,114,99,101,110,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,1,13,10,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,2,5,11,11,1,11,0,17,6,12,2,11,2,2,1,1,0,0,1,17,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,15,11,0,11,1,17,6,11,2,17,6,17,5,17,4,12,3,11,3,2,2,1,0,0,5,93,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,1,10,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,2,23,10,0,10,2,23,10,3,17,1,10,4,36,4,28,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,10,4,36,4,50,10,1,10,0,10,4,17,9,10,3,17,9,23,17,5,10,4,10,3,17,9,23,17,6,12,7,5,52,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,12,9,10,2,10,9,23,10,5,17,5,10,4,10,3,17,9,23,17,9,24,10,4,10,3,17,9,26,12,8,10,0,11,1,23,11,5,17,7,17,9,24,10,0,11,9,23,11,0,11,2,23,17,6,17,8,17,9,11,4,11,3,17,9,26,11,8,23,2,3,1,0,0,6,51,10,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,7,8,12,6,5,11,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,12,6,11,6,4,15,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,1,10,0,10,3,17,1,12,7,11,1,10,2,22,11,0,10,2,22,11,3,17,1,11,7,23,12,9,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,4,11,5,17,6,24,12,11,11,2,11,11,17,6,17,5,17,4,12,10,11,9,11,10,17,4,12,8,11,4,11,8,17,9,2,0],"genesis":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,56,3,74,128,1,4,202,1,22,5,224,1,175,1,7,143,3,130,4,8,145,7,96,6,241,7,61,10,174,8,39,12,213,8,147,2,13,232,10,6,15,238,10,2,0,26,1,15,1,44,1,46,2,24,2,38,2,39,2,42,2,43,0,0,0,0,0,2,12,0,0,1,8,0,0,11,7,0,0,12,7,0,0,13,7,0,1,4,7,0,2,6,7,0,5,3,7,0,5,7,4,0,6,8,12,0,6,9,0,0,6,10,0,0,8,5,2,0,0,29,0,1,0,0,17,2,0,0,0,33,3,4,0,0,16,5,6,0,0,18,7,0,0,0,36,8,0,2,6,6,0,19,9,10,0,0,21,10,0,0,0,22,11,0,0,1,34,31,32,0,2,27,0,26,1,0,2,28,30,31,0,3,32,35,36,1,0,3,40,37,23,1,0,4,14,20,0,2,7,4,4,25,13,14,2,7,4,4,40,28,29,2,7,4,5,20,17,0,0,5,31,21,18,1,8,5,37,16,17,0,6,16,24,6,0,6,18,25,0,0,7,41,23,0,1,8,15,12,14,19,18,4,22,22,15,27,16,27,10,29,10,23,14,33,12,18,13,18,0,1,8,5,1,6,8,2,2,8,10,7,8,13,1,8,1,4,6,8,0,7,8,2,2,10,2,1,8,12,2,7,8,2,8,11,3,6,8,0,7,8,2,9,1,1,6,8,1,1,8,0,2,7,8,2,8,1,2,8,3,8,5,2,6,8,9,9,0,1,1,2,8,2,8,1,1,7,8,13,1,8,9,1,8,8,2,8,3,8,4,3,7,8,9,9,0,9,1,1,6,9,0,1,8,2,1,9,0,3,7,8,10,2,10,2,2,7,8,10,8,11,1,8,7,2,8,3,9,0,2,7,8,9,9,0,1,9,1,1,6,8,7,1,8,6,1,10,2,2,8,3,9,1,2,3,8,8,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,14,85,112,103,114,97,100,101,82,101,99,101,105,112,116,13,85,112,103,114,97,100,101,84,105,99,107,101,116,7,86,101,114,115,105,111,110,13,86,101,114,115,105,111,110,95,49,95,48,95,48,13,86,101,114,115,105,111,110,95,49,95,48,95,49,3,97,100,100,5,97,115,99,105,105,17,97,117,116,104,111,114,105,122,101,95,117,112,103,114,97,100,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,14,99,111,109,109,105,116,95,117,112,103,114,97,100,101,6,99,114,101,97,116,101,6,100,101,108,101,116,101,7,100,101,115,116,114,111,121,15,100,101,115,116,114,111,121,95,109,97,110,97,103,101,114,11,100,117,109,109,121,95,102,105,101,108,100,13,100,121,110,97,109,105,99,95,102,105,101,108,100,16,101,120,105,115,116,115,95,119,105,116,104,95,116,121,112,101,7,103,101,110,101,115,105,115,3,103,101,116,10,103,101,116,95,109,111,100,117,108,101,17,103,101,116,95,118,101,114,115,105,111,110,95,49,95,48,95,49,13,103,111,118,101,114,110,97,110,99,101,95,118,49,2,105,100,8,105,110,100,101,120,95,111,102,12,105,110,105,116,95,103,101,110,101,115,105,115,10,105,110,116,111,95,98,121,116,101,115,11,109,97,110,97,103,101,114,95,105,100,115,15,109,105,103,114,97,116,101,95,118,101,114,115,105,111,110,3,110,101,119,6,111,98,106,101,99,116,7,112,97,99,107,97,103,101,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,11,117,112,103,114,97,100,101,95,99,97,112,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,10,2,8,7,103,101,110,101,115,105,115,0,2,1,23,1,1,2,1,31,8,9,2,2,3,31,8,9,45,8,10,35,10,8,8,3,2,1,23,1,4,2,1,23,1,5,2,1,23,1,0,1,0,0,0,3,9,18,5,2,1,1,0,0,0,10,11,0,16,0,9,18,3,56,0,4,7,5,9,7,4,39,2,2,3,0,0,15,26,10,1,17,19,11,0,64,18,0,0,0,0,0,0,0,0,18,2,12,2,11,1,17,19,18,1,12,3,13,2,15,0,9,18,3,9,18,4,56,1,13,2,15,1,14,3,56,2,68,18,11,2,56,3,11,3,2,3,1,0,0,0,6,11,1,15,2,11,2,11,3,17,20,2,4,1,0,0,0,5,11,0,15,2,11,1,17,21,2,5,1,0,0,26,47,10,1,15,0,46,9,18,3,56,4,4,8,5,12,11,1,1,7,1,39,10,1,15,0,9,18,3,56,5,1,56,6,12,3,10,3,56,7,34,4,25,5,29,11,1,1,7,2,39,14,3,17,11,17,9,7,5,33,4,36,5,40,11,1,1,7,3,39,11,1,15,0,9,18,3,11,2,56,8,2,6,1,0,0,0,3,9,18,0,2,7,1,0,0,0,4,11,0,19,0,1,2,8,1,0,0,34,18,14,1,56,2,12,3,10,0,16,1,14,3,56,9,12,2,1,11,0,15,1,11,2,56,10,1,11,1,19,1,17,17,2,2,0,2,2,2,1,0,30,0],"governance_v1":[161,28,235,11,6,0,0,0,13,1,0,22,2,22,56,3,78,198,1,4,148,2,40,5,188,2,148,2,7,208,4,155,6,8,235,10,96,6,203,11,207,1,10,154,13,72,11,226,13,2,12,228,13,215,9,13,187,23,28,14,215,23,14,0,43,0,38,1,18,1,57,1,71,1,75,2,33,2,56,2,58,2,69,2,70,0,3,8,0,0,7,8,1,6,0,0,1,3,0,0,0,3,0,1,2,0,0,1,4,12,0,2,8,7,0,3,6,7,1,0,0,4,10,7,0,7,5,7,0,7,11,4,0,8,12,12,0,10,9,2,0,0,47,0,1,0,0,13,2,1,0,0,74,3,4,0,0,15,5,1,0,0,62,5,1,0,0,73,6,1,0,0,22,7,1,0,0,31,8,9,0,0,41,10,11,1,6,0,28,12,1,0,0,25,13,1,1,6,0,76,14,15,1,6,0,20,10,1,1,6,1,24,47,12,0,1,27,12,1,0,1,48,25,4,0,2,68,35,11,0,3,19,46,44,1,0,3,35,27,23,1,0,3,37,26,1,1,0,3,49,46,9,1,0,3,50,46,9,1,0,3,55,1,20,1,0,3,65,23,20,1,0,4,39,1,39,1,0,4,40,40,11,0,5,23,29,9,1,0,5,46,29,31,1,0,5,61,32,23,1,0,6,29,23,1,1,3,7,45,44,21,1,8,7,53,0,19,0,7,72,37,38,0,9,64,23,1,1,8,10,32,18,34,0,10,63,18,17,0,22,4,33,22,19,4,18,4,26,17,27,17,28,17,22,34,23,34,24,23,33,41,29,42,30,41,29,45,20,34,17,34,17,4,23,12,21,34,22,12,1,7,8,12,0,3,8,11,7,8,0,7,8,12,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,1,9,0,7,8,12,1,8,6,1,8,4,3,6,8,0,9,0,7,8,12,5,6,8,0,9,0,7,11,1,1,9,0,1,7,8,12,1,11,7,1,8,4,1,10,5,1,5,1,6,8,12,1,8,10,1,11,7,1,9,0,1,8,9,1,8,0,1,9,0,2,5,1,2,8,11,7,8,12,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,1,10,2,12,8,8,3,11,7,1,3,3,5,8,10,5,11,7,1,3,3,8,10,8,9,3,1,6,8,10,1,6,8,9,1,8,8,1,6,8,8,1,11,1,1,9,0,1,8,2,11,1,6,5,6,5,1,1,7,10,5,3,7,10,5,3,3,5,1,6,9,0,1,8,3,1,6,11,7,1,9,0,1,6,8,5,11,67,104,97,110,103,101,83,116,97,116,101,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,10,85,112,103,114,97,100,101,67,97,112,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,10,97,100,100,95,109,101,109,98,101,114,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,12,99,104,101,99,107,95,109,101,109,98,101,114,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,49,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,105,116,95,103,101,110,101,115,105,115,7,105,115,95,110,111,110,101,7,105,115,95,115,111,109,101,9,109,97,120,95,100,101,108,97,121,7,109,101,109,98,101,114,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,7,112,97,99,107,97,103,101,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,6,114,101,109,111,118,101,13,114,101,109,111,118,101,95,109,101,109,98,101,114,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,7,117,112,103,114,97,100,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,8,45,8,10,42,11,7,1,8,5,14,1,17,3,77,3,51,3,52,10,5,44,10,8,9,1,2,10,45,8,10,26,5,66,3,30,11,7,1,3,34,3,59,8,6,21,9,0,36,10,5,16,10,5,67,2,2,2,1,60,8,9,3,2,2,60,8,9,54,2,1,23,0,0,0,0,16,19,64,17,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,35,68,17,11,0,17,31,56,0,9,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,11,1,64,21,0,0,0,0,0,0,0,0,18,0,56,1,2,1,1,4,0,24,42,10,1,10,2,46,17,35,12,3,46,11,3,17,6,10,1,16,0,20,32,4,20,10,1,16,1,65,21,6,0,0,0,0,0,0,0,0,33,12,4,5,22,9,12,4,11,4,4,25,5,31,11,1,1,11,2,1,7,5,39,10,1,15,2,11,0,11,2,17,15,56,2,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,2,56,3,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,28,19,10,1,15,3,14,2,12,3,46,11,3,56,4,32,4,10,5,14,11,1,1,7,9,39,11,1,15,3,11,2,68,17,2,4,1,0,0,30,21,10,1,10,2,12,3,46,11,3,17,6,10,1,15,3,14,2,12,4,46,11,4,56,5,12,5,1,11,1,15,3,11,5,56,6,1,2,5,1,0,0,1,24,10,4,10,3,10,2,22,36,4,7,5,11,11,1,1,7,7,39,11,2,10,1,15,4,21,11,3,10,1,15,5,21,11,4,11,1,15,6,21,2,6,1,0,0,1,9,11,0,16,3,14,1,56,4,4,6,5,8,7,8,39,2,7,1,0,0,8,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,8,1,0,0,33,75,11,1,46,17,34,12,7,10,0,55,0,20,7,2,33,4,16,11,0,1,7,16,17,16,12,6,5,73,10,0,55,0,20,7,3,33,4,28,11,0,1,7,17,17,16,12,5,5,71,10,0,55,0,20,7,4,33,4,40,11,0,1,7,18,17,16,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,19,17,16,12,3,5,67,11,0,55,0,20,7,0,33,4,62,7,20,17,16,12,2,5,65,7,21,17,16,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,9,1,0,0,1,3,11,0,17,14,2,10,1,0,0,36,86,10,0,16,0,20,4,5,5,11,11,0,1,11,2,1,7,6,39,10,2,46,17,35,12,9,10,0,10,9,17,6,10,2,46,17,34,10,0,16,4,20,22,12,14,10,0,16,5,20,6,0,0,0,0,0,0,0,0,33,4,35,56,7,12,10,5,42,10,14,10,0,16,5,20,22,56,8,12,10,10,2,46,17,34,11,0,16,6,20,22,12,11,11,2,17,31,12,12,14,12,17,32,20,12,13,11,12,12,8,11,9,12,7,11,14,12,6,11,10,12,5,11,11,12,4,56,9,12,3,11,8,11,7,11,6,11,5,11,4,14,3,17,25,11,1,64,17,0,0,0,0,0,0,0,0,64,17,0,0,0,0,0,0,0,0,7,0,57,0,56,10,11,13,18,2,56,11,2,11,1,0,0,43,213,1,10,4,46,17,34,12,11,10,11,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,4,1,7,11,39,10,11,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,4,1,7,14,39,10,2,55,0,20,7,0,33,4,50,7,1,10,2,54,0,21,10,2,46,56,12,7,1,18,3,56,13,10,2,55,0,20,7,1,33,4,57,5,65,11,2,1,11,0,1,11,4,1,7,13,39,11,4,46,17,35,12,15,10,0,10,15,17,6,10,2,54,3,12,12,10,2,54,4,12,10,10,2,55,5,56,14,4,85,8,12,5,5,92,10,11,10,2,55,5,56,15,20,35,12,5,11,5,4,138,1,10,12,14,15,12,6,46,11,6,56,4,32,4,111,10,10,14,15,12,7,46,11,7,56,4,32,12,8,5,113,9,12,8,11,8,4,116,5,126,11,2,1,11,0,1,11,12,1,11,10,1,7,10,39,11,3,4,134,1,11,10,1,10,12,11,15,68,17,5,137,1,11,10,11,15,68,17,5,140,1,11,10,1,10,2,55,5,56,14,4,147,1,8,12,9,5,154,1,11,11,10,2,55,5,56,15,20,38,12,9,11,9,4,205,1,10,0,16,3,65,17,12,14,11,12,46,65,17,12,13,11,14,11,13,17,7,4,184,1,7,2,10,2,54,0,21,11,2,46,56,12,7,2,18,3,56,13,11,0,16,2,56,16,17,13,56,17,2,11,0,1,10,2,55,5,56,18,4,201,1,7,3,10,2,54,0,21,11,2,46,56,12,7,3,18,3,56,13,5,203,1,11,2,1,56,19,2,11,2,1,11,0,1,11,12,1,56,19,2,12,1,4,0,1,45,10,1,46,17,34,10,0,55,1,20,35,4,21,10,0,55,0,20,7,0,33,4,15,5,21,11,0,1,11,1,1,7,12,39,11,1,46,17,35,10,0,55,6,20,33,4,30,5,34,11,0,1,7,15,39,7,4,10,0,54,0,21,11,0,46,56,12,7,4,18,3,56,13,2,0,2,0,7,0,1,0,6,0,3,0,4,0,5,1,9,1,4,1,2,1,7,1,8,1,3,1,1,7,23,8,23,9,23,10,23,11,23,12,23,13,23,0],"governance_v2":[161,28,235,11,6,0,0,0,13,1,0,28,2,28,74,3,102,145,2,4,247,2,58,5,177,3,229,3,7,150,7,131,8,8,153,15,96,6,249,15,129,2,10,250,17,95,11,217,18,2,12,219,18,171,13,13,134,32,38,14,172,32,18,0,54,0,48,0,64,1,22,1,69,1,87,1,93,2,23,2,29,2,41,2,68,2,84,2,85,2,86,0,5,8,0,0,9,8,2,6,0,0,1,0,3,3,0,0,1,3,0,1,4,0,0,1,6,12,0,3,10,7,0,4,8,7,1,0,0,5,13,7,0,7,0,4,1,0,1,8,2,12,1,0,1,10,7,7,0,10,14,4,0,11,11,12,2,7,1,4,1,13,12,2,0,0,59,0,1,0,0,15,2,1,0,0,91,3,4,0,0,18,5,1,0,0,75,5,1,0,0,90,6,1,0,0,89,7,1,0,0,27,8,1,0,0,39,9,10,0,0,51,11,12,2,6,0,0,35,13,1,0,0,32,14,1,2,6,0,0,94,15,16,2,6,0,0,25,17,1,2,6,0,0,28,11,1,2,6,0,1,31,59,13,0,1,34,13,1,0,2,63,40,41,1,0,3,83,37,12,0,4,24,58,52,1,0,4,43,28,26,1,0,4,46,27,1,1,0,4,67,1,22,1,0,4,78,26,22,1,0,5,49,1,23,1,0,5,50,47,12,0,6,30,30,10,1,0,6,58,30,32,1,0,6,74,33,26,1,0,7,61,54,35,1,0,7,79,61,48,1,0,7,92,57,35,1,0,8,36,41,1,1,0,8,47,62,41,1,0,8,60,41,48,1,0,9,37,26,1,1,3,10,57,52,24,1,8,10,65,0,21,0,10,88,45,46,0,11,17,44,1,2,7,4,11,30,55,10,2,7,4,11,65,0,43,2,7,4,11,74,56,39,2,7,4,12,73,64,1,1,12,12,77,26,1,1,8,13,40,20,35,0,13,76,20,19,0,22,4,22,23,44,25,21,23,21,4,20,4,26,19,27,19,28,19,17,39,41,42,39,42,24,26,34,39,44,49,35,50,36,49,35,53,29,39,40,42,42,42,31,39,22,13,32,39,19,4,23,13,30,39,33,39,43,63,1,7,8,14,0,4,6,8,4,7,8,0,8,8,8,5,2,6,8,4,7,8,0,1,8,5,3,6,8,4,7,8,0,5,4,6,8,4,7,8,0,3,3,5,6,8,4,7,8,0,3,3,3,2,6,8,0,5,2,3,3,1,1,2,7,11,1,2,9,0,9,1,7,8,14,1,8,6,1,8,4,5,6,8,0,9,0,10,11,10,1,9,1,3,7,8,14,7,6,8,0,9,0,7,11,1,2,9,0,9,1,10,11,10,1,9,1,3,1,7,8,14,1,11,7,1,8,4,3,6,8,0,7,11,1,2,9,0,9,1,7,8,14,1,10,5,1,5,1,6,8,14,1,8,12,1,11,7,1,9,0,1,8,8,1,8,11,1,8,0,1,9,0,2,7,11,7,1,9,0,9,0,1,7,11,7,1,9,0,1,6,5,2,6,10,9,0,6,9,0,3,5,6,5,3,2,1,3,2,7,10,9,0,3,6,8,6,8,6,8,6,8,6,8,6,3,1,3,2,9,0,9,1,1,10,2,15,8,8,3,3,3,5,8,12,5,3,3,3,11,13,2,5,3,8,12,8,11,11,10,1,9,1,3,1,9,1,3,10,11,10,1,9,0,3,7,8,14,1,11,10,1,9,0,2,5,3,1,11,13,2,9,0,9,1,3,7,11,13,2,9,0,9,1,9,0,9,1,1,6,8,12,1,6,8,11,1,6,8,8,1,11,9,1,9,0,1,11,1,2,9,0,9,1,1,8,2,17,11,7,1,8,4,11,7,1,8,4,5,5,5,5,1,3,3,7,11,13,2,5,3,3,3,3,7,11,13,2,5,3,11,10,1,9,1,5,3,1,6,9,0,1,8,3,2,7,11,9,1,9,0,11,9,1,9,0,2,6,11,13,2,9,0,9,1,9,0,2,7,11,13,2,9,0,9,1,9,0,1,6,11,9,1,9,0,1,6,11,7,1,9,0,1,6,8,5,11,1,1,1,5,5,7,11,13,2,5,3,3,7,11,13,2,5,3,5,3,3,2,7,11,9,1,9,0,3,2,11,9,1,9,0,7,8,14,1,11,10,1,9,1,2,9,0,5,7,66,97,108,97,110,99,101,11,67,104,97,110,103,101,83,116,97,116,101,4,67,111,105,110,14,67,114,101,97,116,101,80,114,111,112,111,115,97,108,13,71,111,118,101,114,110,97,110,99,101,67,97,112,14,71,111,118,101,114,110,97,110,99,101,73,110,102,111,20,71,111,118,101,114,110,97,110,99,101,77,97,110,97,103,101,114,67,97,112,2,73,68,6,79,112,116,105,111,110,8,80,114,111,112,111,115,97,108,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,8,84,121,112,101,78,97,109,101,3,85,73,68,19,97,99,116,105,118,97,116,101,95,103,111,118,101,114,110,97,110,99,101,6,97,99,116,105,118,101,3,97,100,100,13,97,100,100,95,103,117,97,114,100,105,97,110,115,11,97,103,97,105,110,115,116,95,110,117,109,13,97,103,97,105,110,115,116,95,118,111,116,101,115,14,97,110,110,111,117,110,99,101,95,100,101,108,97,121,5,97,115,99,105,105,7,98,97,108,97,110,99,101,6,98,111,114,114,111,119,15,99,97,110,99,101,108,95,112,114,111,112,111,115,97,108,11,99,101,114,116,105,102,105,99,97,116,101,15,99,104,101,99,107,95,103,117,97,114,100,105,97,110,115,5,99,108,97,105,109,4,99,111,105,110,8,99,111,110,116,97,105,110,115,6,99,114,101,97,116,101,15,99,114,101,97,116,101,95,112,114,111,112,111,115,97,108,7,99,114,101,97,116,111,114,7,100,101,115,116,114,111,121,22,100,101,115,116,114,111,121,95,103,111,118,101,114,110,97,110,99,101,95,99,97,112,12,100,101,115,116,114,111,121,95,122,101,114,111,4,101,109,105,116,8,101,110,100,95,118,111,116,101,17,101,110,115,117,114,101,95,116,119,111,95,116,104,105,114,100,115,5,101,112,111,99,104,5,101,118,101,110,116,7,101,120,112,105,114,101,100,7,101,120,116,114,97,99,116,9,102,97,118,111,114,95,110,117,109,11,102,97,118,111,114,95,118,111,116,101,115,4,102,105,108,108,12,102,114,111,109,95,98,97,108,97,110,99,101,7,103,101,110,101,115,105,115,3,103,101,116,11,103,101,116,95,97,100,100,114,101,115,115,18,103,101,116,95,112,114,111,112,111,115,97,108,95,115,116,97,116,101,20,103,111,118,101,114,110,97,110,99,101,95,99,111,105,110,95,116,121,112,101,22,103,111,118,101,114,110,97,110,99,101,95,109,97,110,97,103,101,114,95,99,97,112,13,103,111,118,101,114,110,97,110,99,101,95,118,50,9,103,117,97,114,100,105,97,110,115,12,104,105,115,95,112,114,111,112,111,115,97,108,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,110,116,111,95,98,97,108,97,110,99,101,4,106,111,105,110,9,109,97,120,95,100,101,108,97,121,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,3,110,101,119,9,110,101,119,95,115,116,97,116,101,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,10,112,97,99,107,97,103,101,95,105,100,11,112,114,111,112,111,115,97,108,95,105,100,24,112,114,111,112,111,115,97,108,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,103,117,97,114,100,105,97,110,115,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,115,112,108,105,116,11,115,116,97,107,101,100,95,99,111,105,110,10,115,116,97,114,116,95,118,111,116,101,5,115,116,97,116,101,6,115,116,114,105,110,103,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,9,116,121,112,101,95,110,97,109,101,12,117,105,100,95,97,115,95,105,110,110,101,114,12,117,112,100,97,116,101,95,100,101,108,97,121,22,117,112,100,97,116,101,95,109,105,110,117,109,117,109,95,115,116,97,107,105,110,103,7,117,112,103,114,97,100,101,5,118,97,108,117,101,6,118,101,99,116,111,114,13,118,111,116,101,95,112,114,111,112,111,115,97,108,12,118,111,116,105,110,103,95,100,101,108,97,121,22,118,111,116,105,110,103,95,109,105,110,105,109,117,109,95,115,116,97,107,105,110,103,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,255,255,255,255,255,255,255,255,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,10,2,8,7,83,85,67,67,69,83,83,10,2,5,4,70,65,73,76,10,2,7,6,67,65,78,67,69,76,10,2,8,7,69,88,80,73,82,69,68,10,2,21,20,65,78,78,79,85,78,67,69,77,69,78,84,95,80,69,78,68,73,78,71,10,2,15,14,86,79,84,73,78,71,95,80,69,78,68,73,78,71,0,2,11,57,8,12,53,11,7,1,8,5,52,11,7,1,8,8,55,10,5,16,1,21,3,95,3,62,3,72,3,96,3,56,10,8,11,1,2,13,57,8,12,33,5,81,3,38,3,42,3,70,8,6,26,9,0,80,11,9,1,9,1,44,3,45,11,13,2,5,3,19,3,20,11,13,2,5,3,82,2,2,2,1,71,8,11,3,2,2,71,8,11,66,2,1,36,0,0,0,0,18,22,64,19,0,0,0,0,0,0,0,0,12,1,13,1,10,0,46,17,46,68,19,11,0,17,37,56,0,56,1,64,19,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,6,1,0,0,0,0,0,0,0,6,30,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,64,24,0,0,0,0,0,0,0,0,18,0,56,2,2,1,1,0,0,10,34,10,1,16,0,20,32,4,12,10,1,16,1,65,24,6,0,0,0,0,0,0,0,0,33,12,4,5,14,9,12,4,11,4,4,17,5,21,11,1,1,7,6,39,10,1,15,2,11,2,56,3,10,1,15,3,11,3,56,4,8,11,1,15,0,21,2,2,1,0,0,4,10,10,1,15,3,56,5,12,2,9,11,1,15,0,21,11,2,2,3,1,0,0,29,19,10,1,15,4,14,2,12,3,46,11,3,56,6,32,4,10,5,14,11,1,1,7,10,39,11,1,15,4,11,2,68,19,2,4,1,0,0,31,21,10,1,10,2,12,3,46,11,3,17,7,10,1,15,4,14,2,12,4,46,11,4,56,7,12,5,1,11,1,15,4,11,5,56,8,1,2,5,1,0,0,1,9,11,2,10,1,15,5,21,11,3,11,1,15,6,21,2,6,1,0,0,1,33,10,3,6,0,0,0,0,0,0,0,0,36,4,5,5,9,11,1,1,7,8,39,10,4,10,3,10,2,22,36,4,16,5,20,11,1,1,7,8,39,11,2,10,1,15,7,21,11,3,10,1,15,8,21,11,4,11,1,15,9,21,2,7,1,0,0,1,9,11,0,16,4,14,1,56,6,4,6,5,8,7,9,39,2,8,1,0,0,9,27,10,0,6,3,0,0,0,0,0,0,0,25,6,0,0,0,0,0,0,0,0,33,4,13,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,12,2,5,21,11,0,6,2,0,0,0,0,0,0,0,24,6,3,0,0,0,0,0,0,0,26,6,1,0,0,0,0,0,0,0,22,12,2,11,2,12,3,11,1,11,3,38,2,9,1,0,0,34,75,11,1,46,17,45,12,7,10,0,55,0,20,7,3,33,4,16,11,0,1,7,21,17,18,12,6,5,73,10,0,55,0,20,7,4,33,4,28,11,0,1,7,22,17,18,12,5,5,71,10,0,55,0,20,7,5,33,4,40,11,0,1,7,23,17,18,12,4,5,69,11,7,10,0,55,1,20,38,4,52,11,0,1,7,24,17,18,12,3,5,67,11,0,55,0,20,7,1,33,4,62,7,25,17,18,12,2,5,65,7,26,17,18,12,2,11,2,12,3,11,3,12,4,11,4,12,5,11,5,12,6,11,6,2,10,1,0,0,1,3,11,0,17,16,2,11,1,0,0,38,103,10,0,16,0,20,4,5,5,11,11,0,1,11,4,1,7,7,39,11,2,10,3,10,4,56,9,12,18,10,3,10,0,16,5,20,38,4,23,5,29,11,0,1,11,4,1,7,16,39,10,4,46,17,46,12,11,10,4,46,17,45,12,12,10,12,10,0,16,7,20,22,12,19,10,19,10,0,16,8,20,22,12,13,11,12,11,0,16,9,20,22,12,14,10,4,56,10,12,15,13,15,10,11,10,3,56,11,10,4,17,37,12,16,14,16,17,38,20,12,17,11,16,12,10,11,11,12,9,11,19,12,8,11,13,12,7,11,14,12,6,56,12,12,5,11,10,11,9,11,8,11,7,11,6,14,5,17,25,11,1,11,18,56,13,11,3,11,15,6,0,0,0,0,0,0,0,0,11,4,56,10,7,1,57,0,56,14,11,17,18,2,56,15,2,12,1,0,0,51,175,2,10,6,46,17,45,12,17,10,17,10,2,55,2,20,38,4,11,5,19,11,2,1,11,0,1,11,6,1,7,12,39,10,17,10,2,55,1,20,35,4,26,5,34,11,2,1,11,0,1,11,6,1,7,15,39,10,2,55,0,20,7,1,33,4,50,7,2,10,2,54,0,21,10,2,46,56,16,7,2,18,3,56,17,10,2,55,0,20,7,2,33,4,57,5,65,11,2,1,11,0,1,11,6,1,7,14,39,10,6,46,17,46,12,22,10,2,54,3,12,20,10,2,54,4,12,16,11,3,10,4,11,6,56,9,12,21,11,17,10,2,55,5,20,35,4,237,1,11,0,1,10,2,54,6,11,21,56,13,56,18,1,11,5,4,158,1,10,2,55,7,20,10,4,22,10,2,54,7,21,11,4,12,18,10,20,10,22,12,9,46,11,9,56,19,4,119,11,18,10,20,10,22,56,20,22,12,18,10,16,10,22,12,10,46,11,10,56,19,4,151,1,11,16,10,22,56,20,12,14,10,2,55,7,20,10,14,22,10,2,54,7,21,10,2,55,8,20,10,14,23,10,2,54,8,21,11,18,11,14,22,12,18,5,153,1,11,16,1,11,20,11,22,11,18,56,11,5,219,1,10,2,55,8,20,10,4,22,10,2,54,8,21,11,4,12,15,10,16,10,22,12,11,46,11,11,56,19,4,181,1,11,15,10,16,10,22,56,20,22,12,15,10,20,10,22,12,12,46,11,12,56,19,4,213,1,11,20,10,22,56,20,12,19,10,2,55,8,20,10,19,22,10,2,54,8,21,10,2,55,7,20,10,19,23,10,2,54,7,21,11,15,11,19,22,12,15,5,215,1,11,20,1,11,16,11,22,11,15,56,11,10,2,55,7,20,10,2,55,8,20,22,11,2,55,6,56,21,33,4,232,1,5,234,1,7,19,39,56,22,12,8,5,173,2,11,20,1,11,16,1,11,21,56,23,10,2,55,7,20,10,2,55,8,20,22,12,23,10,23,10,2,55,7,20,17,8,4,136,2,11,23,10,0,16,6,20,38,12,13,5,138,2,9,12,13,11,13,4,157,2,7,3,10,2,54,0,21,11,2,46,56,16,7,3,18,3,56,17,11,0,16,3,56,24,17,15,56,25,12,7,5,171,2,11,0,1,7,4,10,2,54,0,21,11,2,46,56,16,7,4,18,3,56,17,56,22,12,7,11,7,12,8,11,8,2,13,1,4,0,19,41,10,2,46,17,45,10,1,55,1,20,35,4,23,10,1,55,0,20,7,1,33,4,15,5,23,11,1,1,11,0,1,11,2,1,7,13,39,11,2,46,17,46,12,3,11,0,11,3,17,7,7,5,10,1,54,0,21,11,1,46,56,16,7,5,18,3,56,17,2,14,1,4,0,60,129,1,10,1,46,17,45,12,8,10,0,55,0,20,7,3,33,4,13,8,12,2,5,19,10,0,55,0,20,7,4,33,12,2,11,2,4,24,8,12,3,5,30,10,0,55,0,20,7,5,33,12,3,11,3,4,35,8,12,4,5,41,11,8,10,0,55,1,20,38,12,4,11,4,4,44,5,50,11,0,1,11,1,1,7,20,39,10,1,46,17,46,12,10,10,0,54,3,12,9,10,0,54,4,12,7,10,9,10,10,12,5,46,11,5,56,19,4,90,11,7,1,11,9,10,10,56,20,12,12,10,0,54,6,10,12,56,26,11,1,56,27,11,10,56,28,10,0,55,7,20,11,12,23,11,0,54,7,21,5,128,1,11,9,1,10,7,10,10,12,6,46,11,6,56,19,4,100,5,108,11,0,1,11,1,1,11,7,1,7,11,39,11,7,10,10,56,20,12,11,10,0,54,6,10,11,56,26,11,1,56,27,11,10,56,28,10,0,55,8,20,11,11,23,11,0,54,8,21,2,0,4,0,10,0,2,0,1,0,3,0,8,0,9,0,5,0,6,0,7,1,12,1,4,1,2,1,9,1,11,1,3,1,7,1,8,1,10,10,36,11,36,12,36,13,36,14,36,15,36,16,36,17,36,18,36,0],"lending_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,126,4,136,1,2,5,138,1,175,1,7,185,2,166,4,8,223,6,32,6,255,6,41,12,168,7,192,10,0,22,0,9,0,23,1,0,7,0,0,20,0,1,0,0,21,0,1,0,0,16,0,1,0,0,19,0,1,0,0,18,0,1,0,0,15,0,1,0,0,17,0,1,0,0,10,2,3,0,0,1,3,2,0,0,14,4,3,0,0,5,3,4,0,0,12,5,3,0,0,3,3,6,0,0,13,7,3,0,0,4,3,7,0,1,2,3,11,0,1,11,11,3,0,2,6,17,18,0,2,7,17,19,0,2,8,17,1,0,2,24,9,0,0,2,25,10,0,0,2,26,13,0,0,2,27,12,0,0,2,28,15,16,1,1,24,1,0,1,2,4,13,3,8,0,2,1,10,2,6,13,3,3,8,0,8,0,2,4,13,3,8,0,3,5,13,3,8,0,3,2,2,10,13,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,11,10,2,10,2,10,2,10,2,3,3,2,3,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,3,10,2,10,2,10,2,16,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,2,3,8,0,13,13,8,0,13,13,10,2,10,2,10,2,10,2,10,2,3,3,2,3,3,13,8,0,13,3,3,10,2,3,10,10,2,10,2,10,2,3,13,10,13,13,3,2,13,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,24,101,110,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,101,110,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,8,24,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,22,11,4,2,8,1,0,0,14,92,6,0,0,0,0,0,0,0,0,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,1,14,1,17,17,12,11,11,6,11,5,22,12,6,6,8,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,2,14,2,17,18,12,8,11,6,11,5,22,12,6,6,2,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,3,14,3,17,17,12,9,11,6,11,5,22,12,6,11,9,52,12,5,14,0,10,6,10,6,10,5,22,56,0,17,15,12,10,11,6,11,5,22,12,6,6,1,0,0,0,0,0,0,0,12,5,14,0,10,6,10,6,10,5,22,56,0,12,4,14,4,17,19,12,7,11,6,11,5,22,14,0,65,1,33,4,85,5,87,7,0,39,11,11,11,8,11,10,11,7,2,9,1,0,0,20,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,20,13,6,11,1,17,21,13,6,11,2,17,21,11,3,17,16,12,7,13,6,14,7,65,1,75,17,20,13,6,11,7,17,23,11,4,17,16,12,8,13,6,14,8,65,1,75,17,20,13,6,11,8,17,23,13,6,11,5,17,22,11,6,2,10,1,0,0,21,141,1,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,18,12,11,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,18,12,7,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,15,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,19,12,10,11,9,11,8,22,14,0,65,1,33,4,132,1,5,134,1,7,0,39,11,16,11,11,11,7,11,12,11,15,11,10,2,11,1,0,0,8,27,64,1,0,0,0,0,0,0,0,0,12,4,13,4,11,0,17,20,13,4,11,1,17,21,11,2,17,16,12,5,13,4,14,5,65,1,75,17,20,13,4,11,5,17,23,13,4,11,3,17,21,13,4,7,6,17,22,11,4,2,12,1,0,0,22,118,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,1,14,1,17,17,12,11,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,2,14,2,17,18,12,10,11,7,11,6,22,12,7,6,2,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,3,14,3,17,17,12,13,11,7,11,6,22,12,7,11,13,52,12,6,14,0,10,7,10,7,10,6,22,56,0,17,15,12,12,11,7,11,6,22,12,7,6,8,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,4,14,4,17,18,12,9,11,7,11,6,22,12,7,6,1,0,0,0,0,0,0,0,12,6,14,0,10,7,10,7,10,6,22,56,0,12,5,14,5,17,19,12,8,11,7,11,6,22,12,7,10,8,7,6,33,4,102,5,104,7,1,39,11,7,14,0,65,1,33,4,110,5,112,7,0,39,11,11,11,10,11,12,11,9,11,8,2,13,1,0,0,23,32,64,1,0,0,0,0,0,0,0,0,12,3,14,0,65,18,12,4,13,3,10,4,75,17,20,6,0,0,0,0,0,0,0,0,12,2,10,2,10,4,35,4,27,5,16,13,3,14,0,10,2,66,18,20,17,20,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,11,13,3,11,1,17,22,11,3,2,14,1,0,0,24,76,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,1,14,1,17,17,12,10,11,8,11,4,22,12,8,72,0,0,12,7,64,18,0,0,0,0,0,0,0,0,12,6,10,7,10,10,35,4,51,5,27,6,2,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,2,14,2,17,17,12,5,13,6,11,5,68,18,11,8,11,4,22,12,8,11,7,72,1,0,22,12,7,5,22,6,1,0,0,0,0,0,0,0,12,4,14,0,10,8,10,8,10,4,22,56,0,12,3,14,3,17,19,12,9,11,8,11,4,22,14,0,65,1,33,4,71,5,73,7,0,39,11,6,11,9,2,0],"lending_core_storage":[161,28,235,11,6,0,0,0,12,1,0,20,2,20,52,3,72,245,2,4,189,3,40,5,229,3,172,2,7,145,6,149,16,8,166,22,96,6,134,23,20,10,154,23,101,12,255,23,239,16,13,238,40,62,15,172,41,6,0,77,0,17,0,43,0,91,1,122,2,31,2,87,2,109,2,112,2,115,0,6,8,0,0,11,4,0,0,4,4,0,0,5,4,0,0,1,4,0,1,0,12,0,1,8,12,0,2,3,0,0,5,2,8,0,6,10,4,0,7,7,12,2,7,1,4,1,9,9,2,0,0,72,0,1,0,0,93,2,1,0,0,104,3,1,0,0,102,3,1,0,0,106,4,1,0,0,105,4,1,0,0,99,4,1,0,0,103,4,1,0,0,100,4,1,0,0,101,5,1,0,0,45,6,7,0,0,61,8,9,0,0,73,10,11,0,0,30,10,11,0,0,58,6,12,0,0,42,13,11,0,0,41,10,11,0,0,65,13,9,0,0,63,13,9,0,0,66,13,14,0,0,64,13,14,0,0,67,13,14,0,0,69,15,9,0,0,68,15,9,0,0,60,10,12,0,0,52,10,9,0,0,62,10,9,0,0,59,10,9,0,0,57,10,9,0,0,46,10,9,0,0,50,10,9,0,0,53,10,9,0,0,56,10,9,0,0,51,10,9,0,0,55,10,9,0,0,54,10,9,0,0,48,10,9,0,0,47,10,9,0,0,49,10,16,0,0,44,6,17,0,0,85,18,1,0,0,29,18,1,0,0,84,18,1,0,0,28,18,1,0,0,14,15,1,0,0,96,15,1,0,0,13,15,1,0,0,95,15,1,0,0,15,15,1,0,0,97,15,1,0,0,119,19,1,0,0,117,20,1,0,0,118,21,1,0,0,116,22,1,0,0,40,23,1,0,1,45,17,7,0,1,92,0,26,0,3,90,1,9,0,4,34,46,11,1,0,4,71,46,48,1,0,4,94,49,31,1,0,5,110,8,12,0,6,86,24,25,0,7,12,34,1,2,7,4,7,20,32,39,2,7,4,7,23,36,37,2,7,4,7,34,32,11,2,7,4,7,81,40,12,2,7,4,7,86,24,28,2,7,4,7,94,36,44,2,7,4,8,107,31,1,1,8,68,27,68,29,70,30,66,27,68,33,63,27,65,27,64,27,67,27,66,29,64,29,66,33,64,33,69,33,63,33,65,29,58,7,59,7,60,7,63,29,3,6,8,7,7,8,6,7,8,11,0,17,6,8,7,7,8,0,6,8,8,13,1,1,3,15,15,15,15,15,15,15,15,15,7,8,11,4,6,8,7,7,8,0,13,1,4,6,8,7,7,8,0,13,15,7,6,8,7,7,8,0,13,15,15,15,15,1,7,8,0,1,13,1,6,8,8,1,15,2,7,8,0,13,1,1,1,3,2,7,8,0,3,1,10,13,3,7,8,0,3,13,4,15,15,15,15,1,6,8,5,4,7,8,0,13,3,15,4,7,8,0,6,8,8,3,15,3,7,8,0,13,15,6,7,8,0,13,15,15,15,15,4,7,8,0,13,15,15,3,7,8,0,6,8,8,3,1,7,8,11,1,8,9,1,8,5,2,13,8,2,1,11,10,2,9,0,9,1,2,3,8,1,1,8,0,1,9,0,2,6,11,10,2,9,0,9,1,9,0,2,3,15,3,7,11,10,2,9,0,9,1,9,0,9,1,1,7,8,2,2,7,11,10,2,9,0,9,1,9,0,1,7,9,1,1,7,8,4,1,6,9,1,1,6,11,10,2,9,0,9,1,2,15,6,8,2,1,6,8,4,2,15,7,8,3,1,9,1,1,7,8,1,2,6,10,9,0,6,9,0,2,3,7,8,1,2,1,3,2,7,10,9,0,3,2,3,7,8,2,6,65,112,112,67,97,112,17,66,111,114,114,111,119,82,97,116,101,70,97,99,116,111,114,115,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,11,82,101,115,101,114,118,101,68,97,116,97,13,83,99,97,108,101,100,66,97,108,97,110,99,101,7,83,116,111,114,97,103,101,5,84,97,98,108,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,8,85,115,101,114,73,110,102,111,3,97,100,100,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,17,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,16,98,97,115,101,95,98,111,114,114,111,119,95,114,97,116,101,6,98,111,114,114,111,119,18,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,18,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,10,98,111,114,114,111,119,95,109,117,116,19,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,49,18,98,111,114,114,111,119,95,114,97,116,101,95,115,108,111,112,101,50,23,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,5,99,108,111,99,107,22,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,11,99,111,108,108,97,116,101,114,97,108,115,8,99,111,110,116,97,105,110,115,20,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,105,110,100,101,120,19,99,117,114,114,101,110,116,95,98,111,114,114,111,119,95,114,97,116,101,23,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,22,99,117,114,114,101,110,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,13,100,116,111,107,101,110,95,115,99,97,108,101,100,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,10,103,101,116,95,97,112,112,95,105,100,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,18,103,101,116,95,114,101,115,101,114,118,101,95,108,101,110,103,116,104,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,13,103,101,116,95,116,105,109,101,115,116,97,109,112,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,2,105,100,8,105,110,100,101,120,95,111,102,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,12,105,115,111,108,97,116,101,95,100,101,98,116,19,108,97,115,116,95,97,118,101,114,97,103,101,95,117,112,100,97,116,101,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,13,108,105,113,117,105,100,95,97,115,115,101,116,115,5,108,111,97,110,115,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,3,110,101,119,6,111,98,106,101,99,116,19,111,112,116,105,109,97,108,95,117,116,105,108,105,122,97,116,105,111,110,13,111,116,111,107,101,110,95,115,99,97,108,101,100,3,114,97,121,8,114,97,121,95,109,97,116,104,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,20,114,101,103,105,115,116,101,114,95,110,101,119,95,114,101,115,101,114,118,101,6,114,101,109,111,118,101,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,8,114,101,115,101,114,118,101,115,22,115,101,116,95,98,111,114,114,111,119,95,99,97,112,95,99,101,105,108,105,110,103,22,115,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,23,115,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,27,115,101,116,95,98,111,114,114,111,119,97,98,108,101,95,105,110,95,105,115,111,108,97,116,105,111,110,26,115,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,21,115,101,116,95,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,22,115,101,116,95,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,19,115,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,12,115,104,97,114,101,95,111,98,106,101,99,116,18,115,117,112,112,108,121,95,99,97,112,95,99,101,105,108,105,110,103,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,12,116,111,116,97,108,95,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,8,116,114,101,97,115,117,114,121,15,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,10,116,120,95,99,111,110,116,101,120,116,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,10,117,115,101,114,95,105,110,102,111,115,10,117,115,101,114,95,115,116,97,116,101,6,118,101,99,116,111,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,2,4,70,8,9,16,8,5,98,11,10,2,13,8,2,120,11,10,2,3,8,1,1,2,5,18,15,75,15,82,10,13,33,10,13,83,10,13,2,2,17,73,1,27,1,74,15,76,15,113,3,114,15,108,15,21,15,36,15,38,15,35,15,37,15,32,15,22,15,24,8,4,89,8,3,39,8,3,3,2,2,121,11,10,2,3,15,111,15,4,2,4,19,15,25,15,26,15,88,15,0,1,0,0,1,13,10,2,17,62,11,0,11,1,10,2,17,56,10,2,56,0,11,2,56,1,18,0,56,2,2,1,1,0,0,1,49,10,1,16,0,10,3,56,3,32,4,7,5,15,11,1,1,11,16,1,11,2,1,7,0,39,11,1,15,0,11,3,11,4,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,2,17,11,11,6,11,7,11,8,11,9,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,57,17,57,11,10,11,11,11,12,11,13,11,14,11,15,18,4,10,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,11,16,56,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,18,2,56,5,2,2,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,1,21,2,3,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,2,21,2,4,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,3,21,2,5,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,4,21,2,6,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,5,21,2,7,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,6,21,2,8,1,0,0,35,10,11,1,15,0,11,2,56,6,12,4,11,3,11,4,15,7,21,2,9,1,0,0,38,23,11,1,15,0,11,2,56,6,15,8,12,7,11,3,10,7,15,9,21,11,4,10,7,15,10,21,11,5,10,7,15,11,21,11,6,11,7,15,12,21,2,10,1,0,0,1,4,11,0,16,13,17,55,2,11,1,0,0,1,6,11,0,17,61,6,232,3,0,0,0,0,0,0,26,77,2,12,1,0,0,1,7,11,0,16,0,11,1,56,7,16,1,20,2,13,1,0,0,1,7,11,0,16,0,11,1,56,7,16,2,20,2,14,1,0,0,1,4,11,0,16,0,56,8,2,15,1,0,0,12,8,11,0,15,14,11,1,12,2,46,11,2,56,9,2,16,1,0,0,7,8,11,0,15,0,11,1,12,2,46,11,2,56,3,2,17,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,15,20,2,18,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,16,20,2,19,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,17,20,2,20,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,18,20,2,21,1,0,0,12,10,11,0,15,14,11,1,12,2,46,11,2,56,10,16,19,20,2,22,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,20,16,21,10,1,56,11,4,19,11,4,16,20,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,23,1,0,0,41,25,11,0,16,0,11,2,56,7,12,4,10,4,16,22,16,21,10,1,56,11,4,19,11,4,16,22,16,21,11,1,56,12,20,12,3,5,23,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,24,1,0,0,1,7,11,0,16,0,11,1,56,7,16,23,20,2,25,1,0,0,1,7,11,0,16,0,11,1,56,7,16,24,20,2,26,1,0,0,1,7,11,0,16,0,11,1,56,7,16,3,20,2,27,1,0,0,1,7,11,0,16,0,11,1,56,7,16,4,20,2,28,1,0,0,1,7,11,0,16,0,11,1,56,7,16,5,20,2,29,1,0,0,1,7,11,0,16,0,11,1,56,7,16,7,20,2,30,1,0,0,1,7,11,0,16,0,11,1,56,7,16,6,20,2,31,1,0,0,1,7,11,0,16,0,11,1,56,7,16,25,20,2,32,1,0,0,1,8,11,0,16,0,11,1,56,7,16,20,16,26,20,2,33,1,0,0,1,8,11,0,16,0,11,1,56,7,16,22,16,26,20,2,34,1,0,0,1,7,11,0,16,0,11,1,56,7,16,27,20,2,35,1,0,0,1,7,11,0,16,0,11,1,56,7,16,28,20,2,36,1,0,0,1,7,11,0,16,0,11,1,56,7,16,29,20,2,37,1,0,0,1,7,11,0,16,0,11,1,56,7,16,30,20,2,38,1,0,0,42,19,11,0,16,0,11,1,56,7,16,8,12,2,10,2,16,9,20,10,2,16,10,20,10,2,16,11,20,11,2,16,12,20,2,39,3,0,0,1,3,11,0,16,13,2,40,3,0,0,43,35,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,41,3,0,0,43,44,11,0,15,0,11,1,56,6,15,20,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,42,3,0,0,43,35,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,5,15,21,11,2,10,3,11,4,22,56,14,10,5,16,26,20,11,3,22,11,5,15,26,21,2,43,3,0,0,43,44,11,0,15,0,11,1,56,6,15,22,12,5,10,5,16,21,10,2,56,11,4,17,10,5,15,21,10,2,56,13,12,4,5,19,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,10,4,10,3,38,4,24,5,28,11,5,1,7,1,39,10,5,15,21,11,2,11,4,10,3,23,56,14,10,5,16,26,20,11,3,23,11,5,15,26,21,2,44,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,17,14,2,56,16,32,4,16,11,3,15,17,11,2,68,7,5,18,11,3,1,2,45,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,17,14,2,56,17,12,3,4,17,11,4,15,17,11,3,56,18,1,5,19,11,4,1,2,46,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,18,14,2,56,16,32,4,16,11,3,15,18,11,2,68,7,5,18,11,3,1,2,47,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,18,14,2,56,17,12,3,4,17,11,4,15,18,11,3,56,18,1,5,19,11,4,1,2,48,3,0,0,45,19,11,0,15,14,11,1,56,15,12,3,10,3,16,19,14,2,56,16,32,4,16,11,3,15,19,11,2,68,7,5,18,11,3,1,2,49,3,0,0,47,20,11,0,15,14,11,1,56,15,12,4,10,4,16,19,14,2,56,17,12,3,4,17,11,4,15,19,11,3,56,18,1,5,19,11,4,1,2,50,3,0,0,45,15,11,0,15,14,11,2,56,15,12,4,11,1,17,11,10,4,15,15,21,11,3,11,4,15,16,21,2,51,3,0,0,35,10,11,0,15,0,11,1,56,6,12,3,11,2,11,3,15,24,21,2,52,3,0,0,50,30,10,0,15,0,10,1,56,6,12,7,11,2,10,7,15,30,21,11,3,10,7,15,28,21,11,4,11,7,15,25,21,10,0,16,0,10,1,56,7,16,23,20,12,6,11,0,11,1,11,6,11,5,17,40,2,53,3,0,0,35,14,11,0,15,0,11,1,56,6,12,4,11,2,10,4,15,29,21,11,3,11,4,15,27,21,2,54,1,0,0,12,26,10,0,15,14,10,2,12,3,46,11,3,56,9,32,4,21,11,0,15,14,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,1,17,11,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,64,7,0,0,0,0,0,0,0,0,18,1,56,19,5,25,11,0,1,11,1,1,2,0,2,2,0,2,1,2,5,2,6,2,7,2,12,2,13,2,14,4,0,4,1,4,2,4,3,0,1,0,3,1,1,1,0,1,2,1,3,1,4,2,15,3,0,2,16,2,4,2,2,2,3,3,1,2,9,2,11,2,8,2,10,0,78,0,79,0,80,0],"lending_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,36,2,36,68,3,104,198,1,4,174,2,8,5,182,2,233,3,7,159,6,228,8,8,131,15,128,1,6,131,16,30,10,161,16,36,12,197,16,230,11,0,58,0,17,0,30,0,42,0,56,0,57,0,59,0,64,0,65,0,80,0,82,1,63,2,23,2,24,2,35,2,77,2,79,3,76,0,6,3,0,0,10,3,0,1,0,12,0,2,4,7,0,3,5,8,0,5,13,8,0,7,9,8,0,8,8,12,0,9,15,12,0,10,3,12,0,11,7,7,1,0,0,12,1,8,0,13,2,12,1,0,1,15,11,2,0,16,14,2,0,17,12,12,0,0,78,0,1,0,0,81,2,1,0,0,19,2,1,0,0,70,0,1,0,0,60,0,1,0,0,18,0,1,0,0,21,0,1,0,2,47,17,14,0,2,48,17,10,0,3,22,4,1,0,4,25,14,15,0,4,26,14,35,0,4,27,14,38,0,4,28,14,23,0,4,44,1,16,0,4,45,1,16,0,4,46,1,16,0,4,52,1,16,0,4,53,1,16,0,4,54,1,16,0,5,43,5,6,0,6,18,39,1,0,6,21,39,1,0,6,36,13,1,0,6,37,36,1,0,6,38,13,1,0,6,39,13,1,0,6,40,13,30,0,8,41,24,25,0,8,50,9,10,0,8,51,9,30,0,9,49,11,12,0,10,66,7,8,0,10,67,21,22,0,10,68,21,22,0,10,71,31,12,0,11,29,29,19,1,0,11,55,27,28,1,0,14,34,19,1,1,3,38,18,37,26,36,26,38,32,10,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,10,2,6,8,11,7,8,14,0,11,6,8,4,7,8,7,7,8,8,7,8,15,7,8,9,7,8,6,7,8,5,11,12,1,8,13,10,2,6,8,11,7,8,14,17,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,10,2,2,13,3,3,8,3,8,3,13,8,3,1,6,8,4,1,7,8,5,1,6,8,2,8,7,8,15,7,8,9,6,8,2,10,2,7,8,7,7,8,8,6,8,11,7,8,14,4,8,3,8,3,15,10,2,2,7,8,7,8,3,1,13,2,6,8,8,8,3,1,3,7,6,8,7,7,8,5,7,8,6,6,8,11,3,13,15,1,10,2,4,13,3,8,3,2,1,2,1,6,8,3,1,8,0,1,9,0,27,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,6,7,8,15,7,8,9,6,8,2,10,2,6,8,11,7,8,14,2,8,3,10,2,6,13,3,3,8,3,8,3,2,3,7,8,7,13,13,1,11,10,1,8,3,1,8,3,1,6,11,10,1,9,0,1,1,1,11,10,1,9,0,1,15,11,7,8,15,7,8,9,6,8,2,7,8,7,8,3,8,3,13,3,15,11,12,1,8,13,6,8,11,1,8,1,26,3,8,3,13,3,2,8,3,7,8,5,7,8,6,6,8,11,3,13,15,3,15,10,2,2,13,3,13,11,10,1,8,3,8,3,3,8,3,8,3,13,8,3,26,7,8,5,7,8,6,6,8,11,3,3,13,13,8,3,7,8,5,7,8,6,6,8,11,3,13,15,10,2,2,15,13,8,3,8,3,3,3,3,13,13,8,3,5,13,3,8,3,3,2,8,6,8,7,7,8,5,7,8,6,6,8,11,3,3,13,13,14,8,3,7,8,5,7,8,6,6,8,11,3,13,10,2,2,6,13,10,13,3,3,3,8,3,2,10,13,2,6,6,8,7,7,8,5,7,8,6,6,8,11,3,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,76,101,110,100,105,110,103,67,111,114,101,69,118,101,110,116,6,79,112,116,105,111,110,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,6,98,111,114,114,111,119,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,24,100,101,99,111,100,101,95,108,105,113,117,105,100,97,116,101,95,112,97,121,108,111,97,100,32,100,101,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,112,111,111,108,95,105,100,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,9,108,105,113,117,105,100,97,116,101,17,108,105,113,117,105,100,97,116,101,95,117,115,101,114,95,105,100,5,110,111,110,99,101,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,5,114,101,112,97,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,14,115,101,110,100,101,114,95,117,115,101,114,95,105,100,8,115,101,113,117,101,110,99,101,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,18,115,111,117,114,99,101,95,99,104,97,105,110,95,110,111,110,99,101,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,9,62,3,72,3,74,13,32,13,31,13,69,10,2,16,15,61,3,20,2,1,2,5,73,3,74,13,75,3,33,8,3,20,2,0,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,26,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,18,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,1,1,4,0,20,168,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,26,12,37,11,26,17,13,12,27,12,35,12,34,12,24,12,33,12,36,10,27,17,19,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,24,77,12,25,10,1,11,34,17,29,12,28,11,2,11,37,12,16,46,11,16,17,31,12,29,14,35,17,8,12,30,10,1,10,28,11,30,17,28,12,31,14,31,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,31,56,2,12,32,10,1,10,6,11,5,10,9,10,29,10,28,11,25,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,27,12,23,10,1,10,32,17,30,10,23,38,4,113,5,125,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,32,10,35,10,36,10,33,10,23,11,7,11,9,17,35,12,11,11,32,12,12,10,36,12,13,10,33,12,14,10,27,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,33,11,29,11,36,14,35,17,8,11,28,14,35,17,7,11,23,6,0,0,0,0,0,0,0,0,11,27,18,0,56,0,2,2,1,4,0,33,167,1,11,0,17,9,10,3,10,4,10,6,17,20,11,8,10,9,11,10,17,34,12,25,12,36,11,25,17,13,12,26,12,34,12,33,12,23,12,32,12,35,10,26,17,15,33,4,25,5,41,11,3,1,11,2,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,1,39,11,23,77,12,24,10,1,11,33,17,29,12,27,11,2,11,36,12,16,46,11,16,17,31,12,28,14,34,17,8,12,29,10,1,10,27,11,29,17,28,12,30,14,30,56,1,4,67,5,81,11,3,1,11,6,1,11,1,1,11,5,1,11,4,1,11,9,1,7,2,39,11,30,56,2,12,31,10,1,10,6,11,5,10,9,10,28,10,27,10,24,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,23,10,1,10,31,17,30,10,24,38,4,112,5,124,11,3,1,11,6,1,11,1,1,11,4,1,11,9,1,7,0,39,11,3,11,4,11,6,17,20,11,1,10,31,10,34,10,35,10,32,10,24,11,7,11,9,17,35,12,11,11,31,12,12,10,35,12,13,10,32,12,14,10,26,12,15,11,11,11,13,11,14,11,12,11,15,18,1,56,3,11,32,11,28,11,35,14,34,17,8,11,27,14,34,17,7,11,24,6,0,0,0,0,0,0,0,0,11,26,18,0,56,0,2,3,1,4,0,3,75,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,18,12,17,12,26,12,23,10,1,11,23,17,29,12,20,11,2,11,26,12,10,46,11,10,17,31,12,21,11,1,11,6,11,5,11,8,10,21,10,20,10,17,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,25,11,18,17,10,12,19,12,24,12,22,12,25,10,19,17,17,33,4,59,5,61,7,1,39,11,22,11,21,11,25,14,24,17,8,11,20,14,24,17,7,11,17,6,0,0,0,0,0,0,0,0,11,19,18,0,56,0,2,4,1,4,0,34,97,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,1,10,2,10,8,11,9,17,32,12,24,12,26,12,29,12,28,11,24,17,11,12,25,12,30,12,35,12,32,12,33,11,2,10,29,12,17,46,11,17,17,31,12,31,10,1,11,28,17,29,12,27,10,1,11,35,17,29,12,34,10,1,10,6,10,5,10,8,10,31,10,27,10,26,12,23,12,22,12,21,12,20,12,19,12,18,46,11,18,11,19,11,20,11,21,11,22,11,23,17,26,11,1,11,6,11,5,11,8,10,31,10,30,10,34,11,27,12,16,12,15,12,14,12,13,12,12,12,11,12,10,46,11,10,11,11,11,12,11,13,11,14,11,15,11,16,17,24,11,32,11,31,11,33,14,29,17,8,11,34,14,29,17,7,11,26,11,30,11,25,18,0,56,0,2,5,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,14,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,21,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,6,1,4,0,37,87,11,0,17,9,11,3,11,4,10,6,17,20,11,7,10,8,11,9,17,33,12,16,12,23,11,16,17,12,12,17,12,19,11,17,17,16,33,4,21,5,33,11,2,1,11,6,1,11,1,1,11,5,1,11,8,1,7,1,39,11,2,11,23,12,10,46,11,10,17,31,12,20,14,19,65,10,12,22,6,0,0,0,0,0,0,0,0,12,21,10,21,10,22,35,4,78,5,50,14,19,10,21,66,10,12,18,10,1,10,6,10,5,10,8,10,20,11,18,20,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,17,22,11,21,6,1,0,0,0,0,0,0,0,22,12,21,5,45,11,6,1,11,1,1,11,5,1,11,8,1,2,0],"lending_logic":[161,28,235,11,6,0,0,0,11,1,0,27,2,27,24,3,51,189,4,4,240,4,4,5,244,4,199,3,7,187,8,241,18,8,172,27,96,6,140,28,144,2,10,156,30,15,12,171,30,196,36,15,239,66,4,0,93,0,48,0,90,0,91,0,104,0,106,0,108,0,111,0,117,1,135,1,2,35,2,40,2,95,0,2,3,0,1,1,0,0,3,5,8,0,4,4,8,0,5,3,12,0,10,0,8,0,0,42,0,1,0,0,44,2,1,0,0,45,2,3,0,0,41,2,1,0,0,43,2,1,0,0,11,4,1,0,0,31,4,1,0,0,34,5,1,0,0,103,6,7,0,0,102,8,7,0,0,83,9,7,0,0,85,10,7,0,0,88,11,7,0,0,84,11,7,0,0,89,11,7,0,0,87,12,7,0,0,33,13,1,0,0,81,12,7,0,0,82,10,7,0,0,128,1,10,3,0,0,126,14,3,0,0,125,11,3,0,0,132,1,14,3,0,0,131,1,11,3,0,0,127,10,3,0,0,129,1,10,3,0,0,133,1,10,3,0,0,134,1,10,3,0,0,28,15,3,0,0,19,15,3,0,0,24,10,3,0,0,25,16,3,0,0,27,17,18,0,0,18,19,20,0,0,119,9,3,0,0,118,9,3,0,0,37,12,1,0,0,99,21,1,0,0,15,21,1,0,0,97,21,1,0,0,13,21,1,0,0,6,8,1,0,0,113,8,1,0,0,120,22,1,0,0,123,23,1,0,0,121,24,1,0,2,51,1,27,0,2,55,1,27,0,2,56,1,27,0,2,61,1,27,0,2,65,1,27,0,2,69,1,27,0,2,80,1,27,0,3,7,11,1,0,3,8,11,1,0,3,9,11,1,0,3,14,53,1,0,3,16,53,1,0,3,30,9,7,0,3,39,30,1,0,3,46,9,7,0,3,47,12,7,0,3,49,61,31,0,3,52,9,3,0,3,53,9,3,0,3,54,9,3,0,3,57,9,3,0,3,58,9,3,0,3,59,9,3,0,3,60,9,3,0,3,62,9,3,0,3,63,9,3,0,3,64,9,3,0,3,66,9,3,0,3,67,9,3,0,3,68,9,26,0,3,70,57,3,0,3,72,9,3,0,3,73,12,3,0,3,74,12,37,0,3,75,12,3,0,3,76,12,37,0,3,77,12,37,0,3,78,11,3,0,3,79,11,3,0,3,86,9,7,0,3,98,53,1,0,3,100,53,1,0,3,114,11,1,0,3,115,11,1,0,3,116,11,1,0,3,121,63,1,0,3,122,6,1,0,3,123,60,1,0,3,124,58,1,0,4,32,32,1,0,4,71,47,48,0,5,50,62,3,0,6,20,20,3,0,6,21,6,3,0,6,22,33,3,0,6,23,33,3,0,6,26,63,3,0,7,96,18,3,0,7,109,1,3,0,7,110,18,3,0,7,112,18,3,0,8,12,18,3,0,8,17,18,3,0,8,101,18,3,0,9,36,39,7,1,0,11,38,29,1,1,3,12,107,49,26,0,111,28,110,31,8,6,8,4,7,8,2,7,8,3,6,8,5,3,3,13,13,0,7,6,8,4,7,8,2,7,8,3,6,8,5,3,13,15,1,15,6,6,8,4,7,8,2,7,8,3,6,8,5,3,13,7,6,8,1,6,8,4,7,8,2,6,8,5,13,3,15,3,7,8,2,13,15,1,1,3,7,8,2,3,15,2,7,8,2,13,3,7,8,2,7,8,3,3,3,7,8,2,3,13,2,7,8,2,3,4,7,8,3,7,8,2,3,6,8,5,4,7,8,2,7,8,3,3,13,3,7,8,3,13,15,4,7,8,2,7,8,3,3,3,6,7,8,2,7,8,3,3,3,13,13,2,15,15,7,7,8,3,13,15,13,15,15,15,4,15,15,15,15,4,7,8,2,3,13,15,4,7,8,2,7,8,3,6,8,5,3,3,7,8,2,6,8,5,13,4,6,8,4,7,8,2,13,15,12,1,15,15,15,15,15,15,15,15,3,15,15,1,3,1,2,1,8,0,1,9,0,3,7,8,2,6,8,5,3,1,13,3,7,8,3,10,13,6,8,5,3,15,15,15,5,15,15,15,15,3,3,1,15,15,5,1,15,6,13,15,10,13,1,10,13,2,1,10,13,2,6,10,9,0,6,9,0,3,1,13,10,13,2,10,13,10,13,7,6,13,15,15,10,13,3,3,15,7,15,3,3,6,13,15,10,13,15,6,6,13,15,10,13,3,3,15,6,3,3,6,13,15,10,13,15,2,2,15,2,7,8,3,13,3,15,2,3,2,3,2,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,6,15,15,15,15,15,15,6,15,3,3,6,13,10,13,3,4,7,8,2,13,3,15,3,6,13,15,10,13,5,15,6,13,15,15,10,13,7,15,15,15,15,15,15,15,1,6,8,5,4,7,8,2,6,8,5,3,15,9,15,15,15,15,15,15,15,15,15,6,7,8,2,13,15,15,15,15,1,7,8,2,3,6,8,4,13,13,4,7,8,2,13,15,15,5,67,108,111,99,107,13,71,111,118,101,114,110,97,110,99,101,67,97,112,23,76,101,110,100,105,110,103,67,111,114,101,69,120,101,99,117,116,101,69,118,101,110,116,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,11,80,114,105,99,101,79,114,97,99,108,101,7,83,116,111,114,97,103,101,16,97,100,100,95,105,115,111,108,97,116,101,95,100,101,98,116,19,97,100,100,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,21,97,100,100,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,13,97,100,100,95,117,115,101,114,95,108,111,97,110,6,97,109,111,117,110,116,13,97,115,95,99,111,108,108,97,116,101,114,97,108,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,100,116,111,107,101,110,18,98,117,114,110,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,111,116,111,107,101,110,18,98,117,114,110,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,98,117,114,110,95,115,99,97,108,101,100,28,99,97,108,99,117,108,97,116,101,95,97,99,116,117,97,108,95,108,105,113,117,105,100,97,116,105,111,110,16,99,97,108,99,117,108,97,116,101,95,97,109,111,117,110,116,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,35,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,98,97,115,101,95,100,105,115,99,111,117,110,116,30,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,97,116,105,111,110,95,100,105,115,99,111,117,110,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,25,99,97,108,99,117,108,97,116,101,95,109,97,120,95,108,105,113,117,105,100,97,116,105,111,110,15,99,97,108,99,117,108,97,116,101,95,118,97,108,117,101,9,99,97,108,108,95,116,121,112,101,23,99,97,110,95,98,111,114,114,111,119,95,105,110,95,105,115,111,108,97,116,105,111,110,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,22,99,104,101,99,107,95,117,115,101,114,95,102,114,101,115,104,95,112,114,105,99,101,19,99,108,97,105,109,95,102,114,111,109,95,116,114,101,97,115,117,114,121,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,13,99,111,118,101,114,95,100,101,102,105,99,105,116,4,101,109,105,116,22,101,110,115,117,114,101,95,117,115,101,114,95,105,110,102,111,95,101,120,105,115,116,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,13,101,120,105,115,116,95,114,101,115,101,114,118,101,15,101,120,105,115,116,95,117,115,101,114,95,105,110,102,111,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,22,103,101,116,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,22,103,101,116,95,98,111,114,114,111,119,95,99,111,101,102,102,105,99,105,101,110,116,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,15,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,26,103,101,116,95,99,111,108,108,97,116,101,114,97,108,95,99,111,101,102,102,105,99,105,101,110,116,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,16,103,101,116,95,105,115,111,108,97,116,101,95,100,101,98,116,25,103,101,116,95,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,19,103,101,116,95,108,105,113,117,105,100,105,116,121,95,105,110,100,101,120,18,103,101,116,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,30,103,101,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,26,103,101,116,95,114,101,115,101,114,118,101,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,26,103,101,116,95,114,101,115,101,114,118,101,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,20,103,101,116,95,114,101,115,101,114,118,101,95,116,114,101,97,115,117,114,121,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,13,103,101,116,95,116,105,109,101,115,116,97,109,112,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,26,103,101,116,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,103,101,116,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,115,23,103,101,116,95,117,115,101,114,95,108,97,115,116,95,116,105,109,101,115,116,97,109,112,22,103,101,116,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,115,14,103,101,116,95,117,115,101,114,95,108,111,97,110,115,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,100,116,111,107,101,110,22,103,101,116,95,117,115,101,114,95,115,99,97,108,101,100,95,111,116,111,107,101,110,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,14,104,97,115,95,99,111,108,108,97,116,101,114,97,108,11,104,97,115,95,100,101,102,105,99,105,116,19,105,115,95,98,111,114,114,111,119,97,98,108,101,95,97,115,115,101,116,13,105,115,95,99,111,108,108,97,116,101,114,97,108,9,105,115,95,104,101,97,108,116,104,17,105,115,95,105,115,111,108,97,116,101,100,95,97,115,115,101,116,17,105,115,95,105,115,111,108,97,116,105,111,110,95,109,111,100,101,15,105,115,95,108,105,113,117,105,100,95,97,115,115,101,116,7,105,115,95,108,111,97,110,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,109,97,116,104,3,109,105,110,11,109,105,110,116,95,100,116,111,107,101,110,18,109,105,110,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,111,116,111,107,101,110,18,109,105,110,116,95,111,116,111,107,101,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,24,110,111,116,95,114,101,97,99,104,95,98,111,114,114,111,119,95,99,101,105,108,105,110,103,24,110,111,116,95,114,101,97,99,104,95,115,117,112,112,108,121,95,99,101,105,108,105,110,103,6,111,114,97,99,108,101,7,112,111,111,108,95,105,100,12,112,111,111,108,95,109,97,110,97,103,101,114,3,112,111,119,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,19,114,101,100,117,99,101,95,105,115,111,108,97,116,101,95,100,101,98,116,22,114,101,109,111,118,101,95,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,24,114,101,109,111,118,101,95,117,115,101,114,95,108,105,113,117,105,100,95,97,115,115,101,116,16,114,101,109,111,118,101,95,117,115,101,114,95,108,111,97,110,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,19,116,111,116,97,108,95,100,116,111,107,101,110,95,115,117,112,112,108,121,19,116,111,116,97,108,95,111,116,111,107,101,110,95,115,117,112,112,108,121,24,117,112,100,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,20,117,112,100,97,116,101,95,105,110,116,101,114,101,115,116,95,114,97,116,101,19,117,112,100,97,116,101,95,105,115,111,108,97,116,101,95,100,101,98,116,12,117,112,100,97,116,101,95,115,116,97,116,101,29,117,112,100,97,116,101,95,117,115,101,114,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,23,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,98,97,108,97,110,99,101,21,117,115,101,114,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,28,117,115,101,114,95,104,101,97,108,116,104,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,18,117,115,101,114,95,104,101,97,108,116,104,95,102,97,99,116,111,114,22,117,115,101,114,95,104,101,97,108,116,104,95,108,111,97,110,95,118,97,108,117,101,7,117,115,101,114,95,105,100,17,117,115,101,114,95,108,111,97,110,95,98,97,108,97,110,99,101,15,117,115,101,114,95,108,111,97,110,95,118,97,108,117,101,27,117,115,101,114,95,116,111,116,97,108,95,99,111,108,108,97,116,101,114,97,108,95,118,97,108,117,101,21,117,115,101,114,95,116,111,116,97,108,95,108,111,97,110,95,118,97,108,117,101,6,118,101,99,116,111,114,11,118,105,111,108,97,116,111,114,95,105,100,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,15,32,0,0,0,200,165,25,144,185,165,111,165,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,34,76,160,196,199,203,249,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,3,8,7,0,0,0,0,0,0,0,3,8,8,0,0,0,0,0,0,0,3,8,9,0,0,0,0,0,0,0,3,8,10,0,0,0,0,0,0,0,3,8,11,0,0,0,0,0,0,0,3,8,12,0,0,0,0,0,0,0,3,8,13,0,0,0,0,0,0,0,3,8,14,0,0,0,0,0,0,0,3,8,15,0,0,0,0,0,0,0,3,8,16,0,0,0,0,0,0,0,0,2,5,130,1,3,10,15,105,13,136,1,3,29,2,0,3,0,0,25,233,1,10,1,10,5,10,6,17,13,4,6,5,16,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,5,10,7,17,14,4,22,5,32,11,1,1,11,0,1,11,2,1,11,3,1,7,8,39,10,1,10,4,10,7,17,13,4,38,5,48,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,3,10,7,17,44,10,1,10,3,10,6,17,44,10,1,10,2,10,3,10,4,17,43,10,2,10,1,10,5,10,3,17,16,10,1,10,2,10,5,17,11,32,4,73,5,83,11,1,1,11,0,1,11,2,1,11,3,1,7,6,39,10,1,10,2,10,4,10,5,10,6,10,7,17,32,12,15,12,14,10,1,10,6,17,77,12,18,10,1,10,4,10,7,17,21,12,16,10,2,10,6,11,14,10,7,11,15,11,16,11,18,17,33,12,19,12,11,12,10,12,9,10,1,10,6,17,75,12,17,10,1,10,5,10,7,10,10,17,40,10,1,10,5,10,6,10,9,17,38,10,1,10,4,10,7,11,10,17,38,10,1,11,17,10,6,11,19,17,37,10,1,10,2,10,5,17,18,4,145,1,10,1,10,5,17,36,10,1,10,4,10,6,17,14,4,184,1,10,1,10,4,10,6,17,23,12,13,10,13,10,11,17,103,12,12,10,1,10,4,10,6,11,12,17,40,10,11,10,13,36,4,183,1,10,1,10,4,10,6,17,90,10,1,10,4,10,6,11,11,11,13,23,17,37,10,1,10,4,10,6,17,54,5,210,1,10,1,10,4,10,6,11,11,17,37,10,1,10,4,10,6,17,13,32,4,202,1,10,1,10,4,10,6,17,12,32,12,8,5,204,1,9,12,8,11,8,4,210,1,10,1,10,4,10,6,17,54,10,0,10,1,10,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,0,10,1,11,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,5,17,43,11,4,11,9,11,6,11,5,17,49,18,0,56,0,2,1,3,0,0,7,128,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,4,10,5,17,14,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,18,39,10,1,10,5,10,6,17,8,4,42,5,52,11,1,1,11,0,1,11,2,1,11,3,1,7,19,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,10,6,17,37,10,1,10,4,10,5,17,13,32,4,74,10,1,10,4,10,5,17,12,32,12,7,5,76,9,12,7,11,7,4,110,10,1,10,4,17,15,4,87,10,1,10,4,10,5,17,54,5,110,10,1,10,4,17,17,32,4,97,10,1,10,4,10,5,17,53,5,110,10,1,10,5,17,85,4,106,10,1,10,4,10,5,17,54,5,110,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,51,18,0,56,0,2,2,3,0,0,18,95,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,21,12,8,11,6,10,8,17,103,12,7,10,1,10,4,10,5,10,7,17,38,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,48,5,58,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,10,7,11,8,33,4,76,10,1,10,4,10,5,17,13,4,72,10,1,10,4,10,5,17,88,5,76,10,1,10,4,10,5,17,89,11,0,10,1,10,5,10,7,17,45,11,1,11,2,11,3,10,4,17,43,11,4,10,7,11,5,6,0,0,0,0,0,0,0,0,17,52,18,0,56,0,11,7,2,3,3,0,0,1,137,1,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,5,17,85,32,4,29,5,39,11,1,1,11,0,1,11,2,1,11,3,1,7,13,39,10,1,10,4,17,15,4,78,10,1,10,5,17,58,4,48,5,58,11,1,1,11,0,1,11,2,1,11,3,1,7,12,39,10,1,10,4,10,6,17,9,4,64,5,74,11,1,1,11,0,1,11,2,1,11,3,1,7,11,39,10,1,10,4,10,6,17,41,10,1,10,4,10,5,17,14,32,4,88,10,1,10,4,10,5,17,55,10,1,10,4,10,5,10,6,17,39,10,2,10,1,10,4,10,3,17,16,10,2,10,5,64,31,1,0,0,0,0,0,0,0,10,3,17,95,10,1,10,2,10,4,17,11,4,109,5,119,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,10,6,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,6,11,5,6,0,0,0,0,0,0,0,0,17,47,18,0,56,0,2,4,3,0,0,33,88,10,1,10,3,10,4,17,59,10,1,10,5,17,60,4,9,5,19,11,1,1,11,0,1,11,2,1,11,3,1,7,9,39,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,23,12,7,10,6,10,7,17,103,12,9,10,1,10,4,10,5,10,9,17,40,10,1,10,4,17,15,4,45,10,1,10,4,10,9,17,42,10,6,10,7,38,4,70,10,1,10,4,10,5,17,90,11,6,11,7,23,12,8,10,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,70,10,1,10,4,10,5,11,8,17,37,10,1,10,4,10,5,17,54,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,11,9,11,5,6,0,0,0,0,0,0,0,0,17,50,18,0,56,0,2,5,3,0,0,1,82,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,12,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,14,39,10,1,10,4,17,15,32,4,26,5,36,11,1,1,11,0,1,11,2,1,11,3,1,7,15,39,10,1,10,4,17,17,4,56,10,1,10,5,17,85,32,4,46,5,56,11,1,1,11,0,1,11,2,1,11,3,1,7,17,39,10,1,10,4,10,5,17,89,10,1,10,4,10,5,17,53,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,46,18,0,56,0,2,6,3,0,0,1,67,10,1,10,3,10,5,17,44,10,1,10,4,10,5,17,13,4,10,5,20,11,1,1,11,0,1,11,2,1,11,3,1,7,7,39,10,1,10,4,10,5,17,88,10,1,10,4,10,5,17,54,10,2,10,1,10,4,10,3,17,16,10,1,10,2,10,4,17,11,4,39,5,49,11,1,1,11,0,1,11,2,1,11,3,1,7,5,39,11,0,10,1,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,11,1,11,2,11,3,10,4,17,43,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,5,6,0,0,0,0,0,0,0,0,17,48,18,0,56,0,2,7,1,0,0,34,49,10,2,11,3,10,4,17,44,10,2,10,4,17,75,12,11,10,2,10,11,10,4,17,21,12,10,10,2,10,11,10,4,17,23,12,9,10,10,10,9,36,4,27,11,10,11,9,23,12,7,5,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,11,7,11,6,17,103,12,8,10,2,11,11,10,4,10,8,17,38,10,2,11,5,10,4,11,8,17,37,11,1,11,2,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,45,2,8,1,0,0,35,23,10,0,10,1,17,74,12,4,11,0,11,1,17,34,12,5,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,15,8,12,3,5,21,11,5,11,2,22,11,4,35,12,3,11,3,2,9,1,0,0,36,33,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,5,10,0,10,5,20,17,73,12,4,11,0,11,5,20,17,68,12,6,10,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,25,8,12,3,5,31,11,6,11,2,22,11,4,35,12,3,11,3,2,10,1,0,0,1,6,11,0,11,1,17,63,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,2,11,1,0,0,1,7,11,0,11,1,11,2,17,19,17,104,36,2,12,1,0,0,38,19,10,0,10,1,17,61,4,13,11,0,11,1,17,81,12,4,14,4,14,2,56,1,12,3,5,17,11,0,1,9,12,3,11,3,2,13,1,0,0,37,8,11,0,11,1,17,79,12,3,14,3,14,2,56,1,2,14,1,0,0,37,8,11,0,11,1,17,82,12,3,14,3,14,2,56,1,2,15,1,0,0,40,25,10,0,11,1,17,79,12,4,14,4,65,31,6,1,0,0,0,0,0,0,0,33,4,19,14,4,6,0,0,0,0,0,0,0,0,66,31,20,12,3,11,0,11,3,17,85,12,2,5,23,11,0,1,9,12,2,11,2,2,16,1,0,0,41,17,10,1,10,2,17,79,12,4,11,1,11,2,17,82,12,5,10,0,11,4,10,3,17,95,11,0,11,5,11,3,17,95,2,17,1,0,0,37,9,11,0,11,1,17,79,12,2,14,2,65,31,6,0,0,0,0,0,0,0,0,36,2,18,1,0,0,35,23,10,0,10,1,10,2,17,26,12,4,11,0,11,1,11,2,17,27,12,5,11,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,19,11,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,12,3,5,21,9,12,3,11,3,2,19,1,0,0,33,23,10,0,10,1,10,2,17,24,12,4,11,0,11,1,11,2,17,25,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,19,11,4,11,5,17,105,12,3,5,21,7,0,12,3,11,3,2,20,1,0,0,3,10,11,0,11,2,10,3,17,21,12,4,11,1,11,3,11,4,17,28,2,21,1,0,0,18,13,10,0,11,1,10,2,17,84,12,4,11,0,11,2,17,70,12,3,11,4,11,3,17,107,2,22,1,0,0,3,10,11,0,11,2,10,3,17,23,12,4,11,1,11,3,11,4,17,28,2,23,1,0,0,18,13,10,0,11,1,10,2,17,83,12,4,11,0,11,2,17,64,12,3,11,4,11,3,17,107,2,24,1,0,0,42,49,10,0,10,2,17,79,12,6,14,6,65,31,12,8,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,7,10,7,10,8,35,4,43,5,16,14,6,10,7,66,31,12,3,10,0,10,3,20,17,66,12,4,10,0,10,1,10,2,11,3,20,17,20,12,5,11,9,11,5,11,4,17,106,22,12,9,11,7,6,1,0,0,0,0,0,0,0,22,12,7,5,11,11,0,1,11,1,1,11,9,2,25,1,0,0,43,49,10,0,10,2,17,82,12,8,14,8,65,31,12,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,9,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,43,5,16,14,8,10,4,66,31,12,6,10,0,10,6,20,17,63,12,3,10,0,10,1,10,2,11,6,20,17,22,12,7,11,9,11,7,11,3,17,106,22,12,9,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,11,11,0,1,11,1,1,11,9,2,26,1,0,0,44,42,10,0,10,2,17,79,12,5,14,5,65,31,12,7,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,6,10,6,10,7,35,4,36,5,16,14,5,10,6,66,31,12,3,10,0,10,1,10,2,11,3,20,17,20,12,4,11,8,11,4,22,12,8,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,11,11,0,1,11,1,1,11,8,2,27,1,0,0,45,42,10,0,10,2,17,82,12,7,14,7,65,31,12,4,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,8,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,36,5,16,14,7,10,3,66,31,12,5,10,0,10,1,10,2,11,5,20,17,22,12,6,11,8,11,6,22,12,8,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,11,11,0,1,11,1,1,11,8,2,28,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,11,4,24,6,10,0,0,0,0,0,0,0,11,3,17,112,77,26,2,29,1,0,0,46,15,11,0,11,1,17,96,1,12,3,12,4,11,2,6,10,0,0,0,0,0,0,0,11,3,17,112,77,24,11,4,26,2,30,1,0,0,18,16,10,0,10,1,10,2,17,24,12,3,11,0,11,1,11,2,17,25,12,4,17,104,11,3,11,4,17,105,23,2,31,1,0,0,20,52,10,0,10,3,17,61,4,5,5,11,11,0,1,11,1,1,7,16,39,10,0,10,2,17,61,4,16,5,22,11,0,1,11,1,1,7,16,39,10,0,10,1,10,3,17,30,12,5,10,0,11,2,17,78,12,4,11,0,11,1,11,3,17,25,12,7,11,4,74,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,24,17,105,17,104,17,103,17,104,22,12,6,11,5,11,6,17,106,7,1,17,103,2,32,1,0,0,50,89,10,0,10,1,11,2,10,3,17,31,12,12,10,0,10,1,10,3,17,24,12,10,10,0,10,1,10,3,17,25,12,11,10,0,10,5,17,63,12,6,10,0,10,4,17,66,12,7,11,11,7,2,17,106,11,10,23,12,19,7,2,17,104,10,12,23,17,106,11,6,17,106,11,7,23,12,18,11,19,11,18,17,105,12,14,10,0,10,1,10,3,10,4,17,20,10,14,17,105,12,8,10,14,17,104,11,12,23,17,106,12,16,11,0,10,1,11,3,10,5,17,22,10,16,17,105,12,9,11,8,11,9,17,103,17,104,17,103,12,17,10,1,11,4,11,14,10,17,17,106,17,29,12,13,11,1,11,5,11,16,11,17,17,106,17,29,12,15,11,13,11,15,2,33,1,0,0,51,45,10,5,10,4,38,4,9,11,4,12,8,11,2,12,7,5,17,11,5,12,8,11,2,10,8,11,4,17,105,17,106,12,7,10,0,10,1,10,7,17,28,12,9,10,0,11,3,10,8,17,28,12,11,11,0,11,1,11,9,11,11,23,17,29,11,6,17,106,12,12,10,7,10,12,23,12,10,11,7,11,8,11,10,11,12,2,34,1,0,0,18,12,10,0,10,1,17,72,12,3,11,0,11,1,17,70,12,2,11,3,11,2,17,106,2,35,1,0,0,18,12,10,0,10,1,17,67,12,3,11,0,11,1,17,64,12,2,11,3,11,2,17,106,2,36,0,0,0,52,49,10,0,10,1,17,82,12,6,14,6,65,31,12,4,6,0,0,0,0,0,0,0,0,12,3,10,3,10,4,35,4,46,5,14,14,6,10,3,66,31,12,5,10,0,10,5,20,17,75,12,7,10,0,10,1,10,5,20,17,23,12,2,10,0,10,1,10,5,20,10,2,17,40,10,0,11,7,11,5,20,11,2,17,39,11,3,6,1,0,0,0,0,0,0,0,22,12,3,5,9,11,0,1,2,37,0,0,0,3,12,11,3,10,0,10,2,17,70,17,109,12,4,11,0,11,2,11,1,11,4,17,87,2,38,0,0,0,3,12,11,3,10,0,10,2,17,70,17,108,12,4,11,0,11,2,11,1,11,4,17,57,2,39,0,0,0,3,12,11,3,10,0,10,2,17,64,17,109,12,4,11,0,11,2,11,1,11,4,17,86,2,40,0,0,0,3,12,11,3,10,0,10,2,17,64,17,108,12,4,11,0,11,2,11,1,11,4,17,56,2,41,0,0,0,54,21,10,0,11,1,17,79,12,5,14,5,6,0,0,0,0,0,0,0,0,66,31,12,3,10,0,10,3,20,17,68,11,2,22,12,4,11,0,11,3,20,11,4,17,92,2,42,0,0,0,55,32,10,0,11,1,17,79,12,7,14,7,6,0,0,0,0,0,0,0,0,66,31,12,4,10,0,10,4,20,17,68,12,5,10,5,10,2,38,4,22,11,5,11,2,23,12,3,5,24,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,12,6,11,0,11,4,20,11,6,17,92,2,43,0,0,0,56,58,10,0,10,3,17,61,4,51,10,2,17,76,12,5,10,0,10,3,17,80,12,9,10,0,10,1,10,3,17,24,12,6,10,0,11,1,10,3,17,25,12,7,10,6,10,7,36,4,45,11,6,11,7,23,12,8,10,0,10,3,17,78,12,4,11,5,11,9,11,4,11,8,17,98,12,10,11,0,11,2,11,3,11,10,17,94,5,50,11,0,11,2,11,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,94,5,57,11,0,1,11,1,1,11,2,1,2,44,0,0,0,59,59,11,1,17,76,12,5,10,0,10,2,17,69,12,7,10,0,10,2,17,67,12,6,10,0,10,2,17,64,12,3,10,0,10,2,17,70,12,4,10,0,10,2,17,77,12,11,10,5,10,7,10,0,10,2,17,65,17,100,10,3,17,106,12,9,10,5,11,7,10,0,10,2,17,71,17,101,11,4,17,106,12,10,11,6,10,9,11,3,23,17,106,11,11,17,106,10,10,17,109,12,8,11,0,11,2,11,9,11,10,11,5,11,8,17,93,2,45,0,0,0,20,36,11,0,10,2,10,1,17,62,17,97,12,5,10,5,10,3,38,4,11,5,15,11,1,1,7,10,39,11,5,11,3,23,12,6,10,1,10,2,10,6,17,99,12,4,10,1,10,2,10,4,11,6,17,102,12,7,11,1,11,2,11,4,11,7,17,91,2,0,92,0,94,0],"lending_portal":[161,28,235,11,6,0,0,0,11,1,0,46,2,46,94,3,140,1,185,2,4,197,3,36,5,233,3,172,6,7,149,10,184,11,8,205,21,128,1,6,205,22,88,10,165,23,59,12,224,23,204,17,13,172,41,4,0,76,0,24,0,40,0,41,0,55,0,73,0,74,0,75,0,79,0,87,0,88,0,108,0,113,0,114,1,86,2,32,2,33,2,47,2,85,2,104,2,106,2,107,3,103,0,8,8,0,0,15,3,0,0,9,3,0,0,7,3,0,1,0,12,0,2,4,7,0,3,11,12,1,0,1,4,5,0,0,4,6,8,0,6,18,8,0,9,14,8,0,10,12,12,0,11,21,12,0,12,3,12,0,13,13,8,0,14,10,7,1,0,0,15,1,8,0,16,2,12,1,0,1,18,20,4,0,19,16,2,0,21,19,2,0,22,17,12,0,0,70,0,1,0,0,64,2,3,0,0,99,4,1,0,0,25,5,1,0,0,29,5,1,0,0,30,6,1,0,0,105,7,1,1,0,0,111,8,1,1,0,0,112,9,1,0,0,26,8,1,1,0,0,27,9,1,0,0,94,7,1,1,0,0,77,10,1,1,0,2,34,13,18,0,2,35,1,18,1,0,2,36,55,18,0,2,59,45,31,0,2,63,1,20,0,3,37,38,31,1,0,3,84,37,3,1,0,3,110,53,1,1,0,4,31,17,1,0,5,46,30,31,0,5,57,1,29,0,5,58,1,29,0,5,62,1,29,0,5,66,1,29,0,5,67,1,29,0,5,68,1,29,0,6,56,56,57,0,7,25,21,1,0,7,29,21,1,0,7,48,44,1,0,7,49,64,1,0,7,50,44,1,0,7,51,44,1,0,7,52,44,52,0,8,78,24,25,1,0,10,22,39,40,0,10,54,48,49,0,10,61,43,20,0,10,65,43,52,0,10,93,39,40,0,11,60,19,3,0,11,71,19,41,0,11,91,42,1,0,12,96,58,3,0,13,95,32,3,0,14,38,51,15,1,0,14,72,50,41,1,0,16,39,25,1,1,0,16,102,27,25,1,0,16,109,28,3,1,0,17,45,15,1,1,3,18,81,0,11,0,20,89,34,1,1,12,20,100,15,1,1,8,21,97,12,13,0,22,80,26,3,0,56,14,37,23,51,23,52,23,55,33,53,35,14,15,37,15,52,15,19,15,18,15,53,46,49,18,48,18,20,15,53,59,6,15,50,15,1,7,8,20,0,1,7,8,0,1,3,3,6,8,7,7,8,0,5,8,6,8,8,7,8,9,7,8,10,6,8,16,7,8,11,7,8,12,10,13,7,8,20,9,6,8,8,6,8,16,7,8,14,7,8,0,7,8,21,10,13,10,11,17,1,8,19,3,7,8,20,11,6,8,8,7,8,9,7,8,10,6,8,16,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,17,1,9,0,3,7,8,20,10,6,8,8,7,8,9,7,8,10,6,8,16,7,8,0,7,8,11,7,8,12,7,11,6,1,9,0,3,7,8,20,16,6,8,8,7,8,9,7,8,10,6,8,16,7,8,13,7,8,0,7,8,21,7,8,11,7,8,12,10,2,10,2,13,3,10,11,17,1,8,19,3,7,8,20,14,6,8,8,7,8,9,7,8,10,6,8,16,7,8,0,7,8,12,7,8,11,7,11,6,1,9,0,10,11,17,1,9,0,3,13,10,2,3,7,8,20,1,8,18,1,6,8,20,1,5,1,8,0,1,9,0,11,8,5,7,8,9,7,8,10,6,8,16,3,13,6,13,3,3,3,8,5,1,6,8,8,1,8,5,2,6,8,12,8,5,1,13,6,6,8,11,7,8,9,7,8,10,6,8,16,3,13,7,11,17,1,8,19,3,10,2,3,3,11,17,1,8,19,3,1,8,19,3,10,11,17,1,9,0,3,7,8,20,1,11,17,1,9,0,1,6,8,21,3,7,11,17,1,9,0,3,7,8,20,1,6,11,17,1,9,0,1,2,2,10,13,2,1,10,2,7,7,8,14,7,8,21,11,17,1,8,19,13,10,2,6,8,16,7,8,20,1,11,17,1,8,19,2,9,0,5,1,8,1,17,6,8,16,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,3,11,17,1,9,0,13,3,3,8,5,8,5,2,6,11,6,1,9,0,3,5,7,11,6,1,9,0,11,17,1,9,0,13,10,2,7,8,20,4,7,8,11,8,5,13,15,2,15,15,1,1,2,7,8,12,8,5,2,7,8,11,8,5,7,6,8,11,7,8,9,7,8,10,6,8,16,3,13,15,1,6,8,5,1,8,3,16,8,5,7,8,9,7,8,10,6,8,16,3,13,15,15,13,3,13,11,15,1,8,5,8,5,8,5,8,5,15,3,7,8,11,13,13,1,11,15,1,8,5,1,6,11,15,1,9,0,1,11,15,1,9,0,1,15,5,7,11,6,1,9,0,8,5,3,8,5,7,8,20,21,8,5,7,8,9,7,8,10,6,8,16,3,13,15,15,11,17,1,8,19,13,3,11,15,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,17,1,8,19,3,2,13,10,2,1,7,8,9,1,6,8,4,11,7,8,21,7,8,13,6,8,4,7,8,11,8,5,8,5,13,3,15,11,17,1,8,19,6,8,16,1,8,2,15,8,5,7,8,9,7,8,10,6,8,16,3,13,15,13,3,13,11,15,1,8,5,8,5,8,5,8,5,15,20,8,5,7,8,9,7,8,10,6,8,16,3,13,15,11,17,1,8,19,13,3,11,15,1,8,5,8,5,3,8,5,8,5,3,3,8,5,11,17,1,8,19,3,17,6,8,16,3,13,15,3,8,5,8,5,7,8,9,7,8,10,15,13,3,3,8,5,3,11,17,1,9,0,8,5,16,13,8,5,7,8,9,7,8,10,6,8,16,3,3,13,13,8,5,3,8,5,3,5,13,8,5,8,6,8,11,7,8,9,7,8,10,6,8,16,3,3,13,13,6,65,112,112,67,97,112,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,17,76,101,110,100,105,110,103,76,111,99,97,108,69,118,101,110,116,13,76,101,110,100,105,110,103,80,111,114,116,97,108,18,76,101,110,100,105,110,103,80,111,114,116,97,108,69,118,101,110,116,6,79,112,116,105,111,110,4,80,111,111,108,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,9,80,111,111,108,83,116,97,116,101,11,80,114,105,99,101,79,114,97,99,108,101,10,82,101,108,97,121,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,7,83,116,111,114,97,103,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,13,97,100,100,95,108,105,113,117,105,100,105,116,121,6,97,109,111,117,110,116,11,97,112,112,95,109,97,110,97,103,101,114,13,97,115,95,99,111,108,108,97,116,101,114,97,108,12,98,111,114,114,111,119,95,108,111,99,97,108,13,98,111,114,114,111,119,95,114,101,109,111,116,101,9,99,97,108,108,95,116,121,112,101,20,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,27,99,97,110,99,101,108,95,97,115,95,99,111,108,108,97,116,101,114,97,108,95,114,101,109,111,116,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,20,99,111,110,118,101,114,116,95,112,111,111,108,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,7,100,101,112,111,115,105,116,12,100,101,115,116,114,111,121,95,115,111,109,101,12,100,101,115,116,114,111,121,95,122,101,114,111,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,17,100,111,108,97,95,112,111,111,108,95,97,100,100,114,101,115,115,12,100,115,116,95,99,104,97,105,110,95,105,100,8,100,115,116,95,112,111,111,108,4,101,109,105,116,32,101,110,99,111,100,101,95,109,97,110,97,103,101,95,99,111,108,108,97,116,101,114,97,108,95,112,97,121,108,111,97,100,5,101,118,101,110,116,14,101,120,101,99,117,116,101,95,98,111,114,114,111,119,17,101,120,101,99,117,116,101,95,108,105,113,117,105,100,97,116,101,13,101,120,101,99,117,116,101,95,114,101,112,97,121,14,101,120,101,99,117,116,101,95,115,117,112,112,108,121,16,101,120,101,99,117,116,101,95,119,105,116,104,100,114,97,119,10,102,101,101,95,97,109,111,117,110,116,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,15,103,101,116,95,98,111,114,114,111,119,95,116,121,112,101,29,103,101,116,95,99,97,110,99,101,108,95,97,115,95,99,111,108,108,101,116,101,114,97,108,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,18,103,101,116,95,108,105,113,117,105,100,97,116,101,95,116,121,112,101,24,103,101,116,95,110,97,116,105,118,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,14,103,101,116,95,114,101,112,97,121,95,116,121,112,101,15,103,101,116,95,115,117,112,112,108,121,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,2,105,100,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,7,105,115,95,115,111,109,101,13,108,101,110,100,105,110,103,95,99,111,100,101,99,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,13,108,101,110,100,105,110,103,95,108,111,103,105,99,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,9,108,105,113,117,105,100,97,116,101,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,11,109,101,115,115,97,103,101,95,102,101,101,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,13,110,111,114,109,97,108,95,97,109,111,117,110,116,6,111,98,106,101,99,116,6,111,112,116,105,111,110,6,111,114,97,99,108,101,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,8,114,101,99,101,105,118,101,114,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,7,114,101,108,97,121,101,114,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,5,114,101,112,97,121,12,115,101,110,100,95,109,101,115,115,97,103,101,13,115,101,110,100,95,119,105,116,104,100,114,97,119,6,115,101,110,100,101,114,8,115,101,113,117,101,110,99,101,11,115,101,116,95,114,101,108,97,121,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,112,108,105,116,5,115,116,97,116,101,3,115,117,105,6,115,117,112,112,108,121,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,5,118,97,108,117,101,8,119,105,116,104,100,114,97,119,14,119,105,116,104,100,114,97,119,95,108,111,99,97,108,15,119,105,116,104,100,114,97,119,95,114,101,109,111,116,101,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,13,2,1,0,5,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,69,8,18,92,5,82,3,1,2,5,98,3,83,3,44,8,5,53,3,28,2,2,2,8,83,3,97,5,42,10,2,101,13,43,13,90,10,2,23,3,28,2,3,2,5,83,3,97,5,42,10,2,23,3,28,2,0,0,0,0,1,9,10,0,17,54,11,0,46,17,57,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,0,0,1,5,11,2,11,1,15,1,21,2,3,1,4,0,16,61,11,0,17,21,11,7,46,17,57,17,13,12,18,11,5,11,18,12,8,46,11,8,17,43,12,15,14,6,65,20,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,20,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,30,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,4,1,4,0,16,61,11,0,17,21,11,7,46,17,57,17,13,12,18,11,5,11,18,12,8,46,11,8,17,43,12,15,14,6,65,20,12,17,6,0,0,0,0,0,0,0,0,12,16,10,16,10,17,35,4,52,5,24,14,6,10,16,66,20,12,14,10,4,10,1,10,2,10,3,10,15,11,14,20,12,13,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,11,13,17,31,11,16,6,1,0,0,0,0,0,0,0,22,12,16,5,19,11,1,1,11,4,1,11,2,1,11,3,1,2,5,0,4,0,22,66,11,0,17,21,11,6,10,7,10,8,56,1,12,9,10,4,46,17,58,12,15,11,7,10,15,38,4,16,5,28,11,4,1,11,2,1,11,3,1,11,8,1,11,1,1,7,3,39,13,9,11,15,10,8,56,2,12,14,14,9,56,3,12,12,11,5,17,24,17,22,12,11,10,3,17,1,12,10,11,2,11,4,11,14,7,5,11,11,11,1,11,8,17,47,12,13,11,9,11,3,16,1,20,56,4,11,13,11,10,7,6,17,13,11,12,17,24,18,1,56,5,2,6,1,4,0,36,117,11,0,17,21,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,57,17,13,12,27,56,6,12,26,11,8,11,9,10,10,56,7,12,22,10,7,14,22,56,8,12,15,46,11,15,56,9,12,21,11,4,17,1,12,25,11,7,11,22,7,5,64,29,0,0,0,0,0,0,0,0,10,10,56,10,1,10,6,10,26,7,5,10,21,77,17,38,1,12,20,10,5,10,27,12,16,46,11,16,17,44,32,4,74,10,5,10,27,17,45,10,6,10,26,17,40,12,23,11,5,11,27,12,17,46,11,17,17,43,12,24,11,6,11,1,11,2,11,3,11,24,11,23,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,35,11,25,11,10,46,17,57,14,26,17,16,11,21,17,27,18,3,56,11,2,7,1,4,0,47,117,11,0,17,21,17,17,12,20,10,9,46,17,57,17,13,12,24,56,6,12,23,10,5,10,23,17,40,12,18,11,6,10,24,12,10,46,11,10,17,43,12,19,10,5,10,18,11,20,17,39,12,21,14,21,56,12,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,21,56,13,12,22,10,5,11,1,11,2,11,3,11,19,11,18,11,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,36,12,17,10,5,10,22,17,41,10,17,38,4,80,5,90,11,5,1,11,7,1,11,4,1,11,9,1,7,1,39,11,5,11,22,7,5,10,17,17,42,1,12,25,11,7,11,24,11,25,52,10,23,10,9,56,14,11,4,17,1,11,9,46,17,57,14,23,17,16,11,17,52,17,28,18,3,56,11,2,8,1,4,0,54,184,1,11,0,17,21,10,11,10,10,17,15,12,31,10,11,11,9,17,15,12,30,10,15,46,17,57,17,13,12,34,10,7,10,30,17,40,12,25,11,8,11,34,12,16,46,11,16,17,43,12,26,10,7,10,25,10,11,17,39,12,27,14,27,56,12,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,27,56,13,12,28,10,7,10,1,11,2,10,3,11,26,11,25,11,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,36,12,23,10,7,10,28,17,41,10,23,38,4,86,5,102,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,11,13,10,14,10,15,56,1,12,24,10,6,46,17,58,12,36,11,14,10,36,38,4,116,5,132,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,24,11,36,10,15,56,2,12,35,14,24,56,3,12,32,10,5,17,1,12,29,11,6,11,4,11,1,17,29,11,7,10,28,11,31,17,17,10,29,10,23,11,35,11,3,17,46,12,33,11,24,11,5,16,1,20,56,4,11,33,10,29,11,28,11,32,17,28,18,1,56,5,11,29,11,15,46,17,57,14,30,17,16,17,17,11,11,11,10,11,23,52,17,28,18,2,56,15,2,9,1,4,0,60,123,11,0,17,21,17,17,12,19,56,6,12,22,10,9,46,17,57,17,13,12,23,10,5,10,22,17,40,12,17,11,6,10,23,12,10,46,11,10,17,43,12,18,10,5,10,17,11,19,17,39,12,20,14,20,56,12,4,31,5,47,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,0,39,11,20,56,13,12,21,10,5,10,21,17,41,10,8,77,38,4,58,5,74,11,1,1,11,5,1,11,7,1,11,2,1,11,4,1,11,9,1,11,3,1,7,1,39,10,5,11,1,11,2,11,3,11,18,11,17,10,8,77,12,16,12,15,12,14,12,13,12,12,12,11,46,11,11,11,12,11,13,11,14,11,15,11,16,17,32,11,5,11,21,7,5,10,8,77,17,42,1,12,24,11,7,11,23,11,24,52,10,22,10,9,56,14,11,4,17,1,11,9,46,17,57,14,22,17,16,11,8,17,23,18,3,56,11,2,10,1,4,0,61,186,1,11,0,17,21,10,11,10,10,17,15,12,30,10,11,11,9,17,15,12,29,10,15,46,17,57,17,13,12,33,10,7,10,29,17,40,12,24,11,8,11,33,12,16,46,11,16,17,43,12,25,10,7,10,24,10,11,17,39,12,26,14,26,56,12,4,35,5,53,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,0,39,11,26,56,13,12,27,10,7,10,27,17,41,10,12,77,38,4,64,5,82,11,6,1,11,1,1,11,7,1,11,2,1,11,5,1,11,15,1,11,4,1,11,3,1,7,1,39,10,7,10,1,11,2,10,3,11,25,11,24,10,12,77,12,22,12,21,12,20,12,19,12,18,12,17,46,11,17,11,18,11,19,11,20,11,21,11,22,17,32,11,13,10,14,10,15,56,1,12,23,10,6,46,17,58,12,35,11,14,10,35,38,4,118,5,134,1,11,6,1,11,1,1,11,7,1,11,5,1,11,15,1,11,4,1,11,3,1,7,3,39,13,23,11,35,10,15,56,2,12,34,14,23,56,3,12,31,10,5,17,1,12,28,11,6,11,4,11,1,17,29,11,7,10,27,11,30,17,17,10,28,10,12,77,11,34,11,3,17,46,12,32,11,23,11,5,16,1,20,56,4,11,32,10,28,11,27,11,31,17,28,18,1,56,5,11,28,11,15,46,17,57,14,29,17,16,17,17,11,11,11,10,11,12,17,23,18,2,56,15,2,11,1,4,0,62,117,11,0,17,21,10,9,6,0,0,0,0,0,0,0,0,36,4,7,5,25,11,5,1,11,1,1,11,6,1,11,7,1,11,2,1,11,4,1,11,10,1,11,3,1,7,4,39,10,10,46,17,57,17,13,12,27,56,6,12,24,11,8,11,9,10,10,56,7,12,26,10,7,14,26,56,8,12,15,46,11,15,56,9,12,25,11,4,17,1,12,23,11,7,11,26,7,5,64,29,0,0,0,0,0,0,0,0,10,10,56,10,1,10,6,10,24,7,5,10,25,77,17,38,1,12,20,10,5,10,27,12,16,46,11,16,17,44,32,4,74,10,5,10,27,17,45,10,6,10,24,17,40,12,21,11,5,11,27,12,17,46,11,17,17,43,12,22,11,6,11,1,11,2,11,3,11,22,11,21,11,20,12,14,12,13,12,12,12,11,12,19,12,18,46,11,18,11,19,11,11,11,12,11,13,11,14,17,34,11,23,11,10,46,17,57,14,24,17,16,11,25,17,26,18,3,56,11,2,12,1,4,0,63,93,10,0,17,21,10,13,46,17,57,12,27,10,27,17,13,12,25,56,6,12,23,11,10,10,11,17,15,12,29,10,6,11,23,17,40,12,22,10,6,11,29,17,40,12,28,10,4,17,1,12,26,10,9,6,0,0,0,0,0,0,0,0,36,4,43,11,0,10,1,10,2,10,3,11,4,10,5,10,6,11,7,11,8,10,9,11,13,56,16,5,54,11,4,1,11,0,1,11,7,1,11,8,10,9,11,13,56,7,56,17,11,5,11,25,12,15,46,11,15,17,43,12,24,11,6,11,1,11,2,11,3,11,24,11,12,11,28,11,22,12,14,12,21,12,20,12,19,12,18,12,17,12,16,46,11,16,11,17,11,18,11,19,11,20,11,21,11,14,17,33,11,26,11,27,11,11,11,9,17,25,18,3,56,11,2,0,2,0,1,0],"merge_coins":[161,28,235,11,6,0,0,0,9,1,0,10,2,10,10,3,20,53,4,73,14,5,87,102,7,189,1,132,1,8,193,2,96,6,161,3,30,12,191,3,189,1,0,6,1,14,2,2,2,11,2,12,2,0,12,1,0,1,4,1,2,0,0,5,0,1,1,0,1,3,5,6,1,0,1,8,3,4,1,0,2,4,8,4,1,0,2,10,11,1,1,0,2,13,9,10,1,0,2,15,15,1,1,0,3,7,14,4,1,12,4,9,12,13,0,2,1,1,1,3,7,5,7,4,7,7,1,6,7,3,10,11,0,1,9,0,3,7,8,1,1,11,0,1,9,0,6,11,0,1,9,0,11,0,1,9,0,11,0,1,9,0,3,11,0,1,9,0,3,1,7,10,9,0,0,1,6,10,9,0,1,1,1,9,0,2,7,11,0,1,9,0,11,0,1,9,0,1,6,11,0,1,9,0,1,3,3,7,11,0,1,9,0,3,7,8,1,1,6,8,1,1,5,2,9,0,5,1,7,8,1,4,67,111,105,110,9,84,120,67,111,110,116,101,120,116,4,99,111,105,110,8,105,115,95,101,109,112,116,121,4,106,111,105,110,10,109,101,114,103,101,95,99,111,105,110,11,109,101,114,103,101,95,99,111,105,110,115,15,112,117,98,108,105,99,95,116,114,97,110,115,102,101,114,7,114,101,118,101,114,115,101,6,115,101,110,100,101,114,5,115,112,108,105,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,118,101,99,116,111,114,4,122,101,114,111,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,255,255,255,255,255,255,255,255,0,1,0,0,2,83,14,0,65,1,6,0,0,0,0,0,0,0,0,36,4,67,13,0,56,0,13,0,69,1,12,5,14,0,56,1,32,4,20,5,15,13,5,13,0,69,1,56,2,5,10,11,0,70,1,0,0,0,0,0,0,0,0,14,5,56,3,12,8,10,1,12,6,11,1,7,2,33,4,33,10,8,12,6,11,8,10,6,38,4,38,5,42,11,2,1,7,0,39,14,5,56,3,10,6,36,4,60,13,5,11,6,10,2,56,4,12,7,11,5,11,2,46,17,8,56,5,11,7,12,3,5,64,11,2,1,11,5,12,3,11,3,12,4,5,81,11,0,70,1,0,0,0,0,0,0,0,0,11,1,6,0,0,0,0,0,0,0,0,33,4,74,5,78,11,2,1,7,1,39,11,2,56,6,12,4,11,4,2,0],"oracle":[161,28,235,11,6,0,0,0,11,1,0,36,2,36,84,3,120,157,1,4,149,2,22,5,171,2,231,2,7,146,5,231,6,8,249,11,128,1,6,249,12,70,10,191,13,33,12,224,13,232,5,13,200,19,14,0,47,0,31,2,40,2,41,2,49,2,52,2,54,2,56,2,61,1,23,1,24,1,46,1,62,1,63,1,65,1,66,3,61,3,68,0,10,8,0,0,6,4,0,1,2,0,0,1,3,8,0,2,4,0,1,3,0,3,5,7,0,4,6,7,0,5,7,7,0,6,8,7,0,6,9,12,0,8,12,12,0,9,0,8,0,10,1,12,1,0,1,11,15,4,0,12,11,2,0,13,13,12,2,7,1,4,1,15,14,2,0,16,12,12,0,17,16,0,0,0,43,0,1,0,0,39,2,3,0,0,59,4,1,0,0,58,4,1,0,0,57,5,1,0,0,20,6,1,0,0,21,6,1,0,0,29,7,1,0,1,22,27,1,0,2,28,40,1,1,3,3,33,43,23,0,3,34,43,23,0,4,32,41,42,0,4,35,41,42,0,5,30,19,20,0,6,36,30,20,0,6,37,28,29,0,7,26,33,34,0,7,38,38,39,0,7,67,35,34,0,9,64,22,23,0,11,45,0,8,0,13,17,21,1,2,7,4,13,18,15,17,2,7,4,13,19,36,37,2,7,4,13,25,15,16,2,7,4,13,45,0,10,2,7,4,14,60,13,1,1,8,17,48,31,32,0,26,9,26,11,27,12,25,11,23,11,25,9,22,9,22,11,23,9,24,11,9,29,1,7,8,16,0,2,7,8,0,13,3,15,2,3,3,6,8,2,7,8,0,3,7,6,8,2,7,8,0,10,2,13,15,2,6,8,11,3,7,8,0,10,13,6,8,11,9,6,8,3,7,8,17,7,8,10,7,8,9,7,8,0,13,10,2,6,8,11,11,12,1,8,14,1,8,13,2,13,8,7,1,11,15,2,9,0,9,1,2,13,8,1,1,8,0,1,9,0,4,13,13,6,8,1,7,11,15,2,13,8,1,2,6,11,15,2,9,0,9,1,9,0,1,1,1,6,9,1,5,13,13,8,7,7,11,15,2,13,8,7,7,11,15,2,13,8,1,1,10,2,1,8,7,3,7,11,15,2,9,0,9,1,9,0,9,1,1,6,8,11,1,3,6,13,3,6,13,3,6,8,1,7,11,15,2,13,8,1,1,13,23,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,6,8,11,13,10,2,6,8,11,10,8,18,6,8,11,3,8,5,3,11,4,1,8,8,7,8,1,6,8,7,8,8,11,4,1,8,8,8,5,3,8,6,8,7,8,18,1,6,8,3,1,6,8,9,1,8,8,1,6,8,8,3,6,8,17,10,2,6,8,11,1,8,18,3,6,8,10,10,8,18,6,8,11,1,11,4,1,8,8,5,6,8,10,11,4,1,8,8,7,8,9,11,12,1,8,14,6,8,11,2,7,11,15,2,9,0,9,1,9,0,1,7,9,1,3,6,8,9,6,8,11,3,1,8,6,1,11,4,1,9,0,1,6,8,6,1,8,5,1,6,8,5,5,67,108,111,99,107,4,67,111,105,110,13,71,111,118,101,114,110,97,110,99,101,67,97,112,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,15,72,111,116,80,111,116,97,116,111,86,101,99,116,111,114,3,73,54,52,5,80,114,105,99,101,15,80,114,105,99,101,73,100,101,110,116,105,102,105,101,114,9,80,114,105,99,101,73,110,102,111,15,80,114,105,99,101,73,110,102,111,79,98,106,101,99,116,11,80,114,105,99,101,79,114,97,99,108,101,3,83,85,73,5,83,116,97,116,101,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,86,65,65,3,97,100,100,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,101,99,107,95,102,114,101,115,104,95,112,114,105,99,101,17,99,104,101,99,107,95,103,117,97,114,100,95,112,114,105,99,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,8,99,111,110,116,97,105,110,115,29,99,114,101,97,116,101,95,112,114,105,99,101,95,105,110,102,111,115,95,104,111,116,95,112,111,116,97,116,111,7,100,101,99,105,109,97,108,7,100,101,115,116,114,111,121,24,102,101,101,100,95,116,111,107,101,110,95,112,114,105,99,101,95,98,121,95,112,121,116,104,13,102,114,111,109,95,98,121,116,101,95,118,101,99,7,103,101,110,101,115,105,115,8,103,101,116,95,101,120,112,111,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,110,101,103,97,116,105,118,101,25,103,101,116,95,109,97,103,110,105,116,117,100,101,95,105,102,95,112,111,115,105,116,105,118,101,9,103,101,116,95,112,114,105,99,101,20,103,101,116,95,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,37,103,101,116,95,112,114,105,99,101,95,105,110,102,111,95,102,114,111,109,95,112,114,105,99,101,95,105,110,102,111,95,111,98,106,101,99,116,23,103,101,116,95,112,114,105,99,101,95,110,111,95,111,108,100,101,114,95,116,104,97,110,15,103,101,116,95,116,111,107,101,110,95,112,114,105,99,101,17,104,111,116,95,112,111,116,97,116,111,95,118,101,99,116,111,114,3,105,54,52,2,105,100,4,105,110,105,116,21,108,97,115,116,95,117,112,100,97,116,101,95,116,105,109,101,115,116,97,109,112,3,110,101,119,6,111,98,106,101,99,116,6,111,114,97,99,108,101,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,5,112,114,105,99,101,16,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,16,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,16,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,17,112,114,105,99,101,95,105,100,101,110,116,105,102,105,101,114,115,10,112,114,105,99,101,95,105,110,102,111,13,112,114,105,99,101,95,111,114,97,99,108,101,115,4,112,121,116,104,20,114,101,103,105,115,116,101,114,95,116,111,107,101,110,95,112,114,105,99,101,20,115,101,116,95,112,114,105,99,101,95,102,114,101,115,104,95,116,105,109,101,20,115,101,116,95,112,114,105,99,101,95,103,117,97,114,100,95,116,105,109,101,12,115,104,97,114,101,95,111,98,106,101,99,116,5,115,116,97,116,101,3,115,117,105,5,116,97,98,108,101,12,116,105,109,101,115,116,97,109,112,95,109,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,24,117,112,100,97,116,101,95,115,105,110,103,108,101,95,112,114,105,99,101,95,102,101,101,100,3,118,97,97,5,118,97,108,117,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,181,59,15,65,116,16,134,39,251,238,114,226,73,139,88,214,162,113,76,222,213,63,172,83,112,52,194,32,210,99,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,60,0,0,0,0,0,0,0,3,8,16,14,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,5,42,8,13,51,3,50,3,53,11,15,2,13,8,7,55,11,15,2,13,8,1,1,2,3,69,15,27,2,44,3,0,0,0,0,1,11,10,0,17,21,7,1,7,0,10,0,56,0,11,0,56,1,18,0,56,2,2,1,1,0,0,14,32,11,0,15,0,12,5,10,5,10,1,12,2,46,11,2,56,3,4,11,5,15,11,5,1,7,2,39,11,5,11,1,12,3,46,11,3,56,4,12,4,10,4,16,1,20,10,4,16,2,20,11,4,16,3,20,2,2,1,0,0,1,5,11,2,11,1,15,4,21,2,3,1,0,0,1,5,11,2,11,1,15,5,21,2,4,1,0,0,18,58,10,1,15,0,12,11,10,11,10,3,12,7,46,11,7,56,3,32,4,12,5,20,11,11,1,11,1,1,11,6,1,7,3,39,11,2,17,14,12,9,11,1,15,6,12,10,10,10,10,3,12,8,46,11,8,56,5,32,4,35,5,43,11,11,1,11,10,1,11,6,1,7,3,39,11,10,10,3,11,9,56,6,11,11,11,3,11,4,11,5,11,6,17,20,6,232,3,0,0,0,0,0,0,26,18,1,56,7,2,5,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,5,20,35,4,39,5,45,11,8,1,11,0,1,7,4,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,6,1,0,0,24,55,10,0,15,0,12,8,11,2,17,20,6,232,3,0,0,0,0,0,0,26,12,4,6,0,0,0,0,0,0,0,0,12,6,10,6,14,1,65,25,35,4,50,5,16,14,1,10,6,66,25,12,5,10,8,11,5,20,12,3,46,11,3,56,4,12,7,10,4,11,7,16,3,20,23,10,0,16,4,20,35,4,39,5,45,11,8,1,11,0,1,7,5,39,11,6,6,1,0,0,0,0,0,0,0,22,12,6,5,10,11,8,1,11,0,1,2,7,1,0,0,26,136,1,11,0,17,8,10,4,16,6,10,5,56,5,4,8,5,20,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,2,39,10,4,15,6,10,5,12,14,46,11,14,56,8,12,24,10,3,46,17,16,12,25,14,25,17,15,12,30,11,24,14,30,33,4,40,5,52,11,1,1,11,2,1,11,4,1,11,3,1,11,7,1,7,6,39,11,1,11,6,10,7,12,16,12,15,46,11,15,11,16,17,28,12,31,10,2,11,31,64,32,1,0,0,0,0,0,0,0,10,7,12,18,12,17,46,11,17,11,18,17,17,12,26,11,2,11,26,10,3,11,8,10,7,12,12,12,11,12,10,12,9,46,11,9,11,10,11,11,11,12,17,19,12,22,10,7,17,20,6,232,3,0,0,0,0,0,0,26,12,19,11,4,15,0,11,5,56,9,12,23,11,3,11,7,12,13,46,11,13,7,0,17,18,12,29,11,22,56,10,14,29,17,13,12,27,14,27,17,11,12,28,14,29,17,12,12,20,14,20,17,10,12,21,11,28,77,10,23,15,1,21,11,21,51,10,23,15,2,21,11,19,11,23,15,3,21,2,0,4,1,0,1,1,1,2,0,1,0,2,0,3,0],"pool_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,136,1,4,146,1,2,5,148,1,208,1,7,228,2,205,4,8,177,7,32,6,209,7,41,12,250,7,133,12,0,23,0,10,0,24,1,0,7,0,0,18,0,1,0,0,22,0,1,0,0,21,0,1,0,0,19,0,1,0,0,20,0,1,0,0,16,0,1,0,0,17,0,1,0,0,11,2,3,0,0,1,3,4,0,0,15,5,3,0,0,5,3,6,0,0,14,7,3,0,0,4,3,8,0,0,13,9,3,0,0,3,3,9,0,1,2,3,12,0,1,12,12,3,0,2,6,19,20,0,2,7,19,27,0,2,8,19,21,0,2,9,19,1,0,2,25,11,0,0,2,26,25,0,0,2,27,14,0,0,2,28,15,0,0,2,29,13,0,0,2,30,17,18,1,1,26,1,0,1,2,5,8,0,8,0,3,13,10,2,1,10,2,6,8,0,8,0,3,13,2,10,2,5,13,3,8,0,8,0,3,6,13,3,8,0,8,0,3,2,3,8,0,13,10,2,4,8,0,13,2,10,2,3,13,15,2,3,10,2,10,2,10,2,2,7,10,2,13,1,8,0,2,7,10,2,10,2,2,7,10,2,3,2,7,10,2,2,18,10,2,10,2,10,2,10,2,10,2,10,2,3,13,10,2,13,3,3,3,8,0,2,13,8,0,13,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,17,10,2,10,2,10,2,10,2,10,2,10,2,3,3,3,3,3,8,0,2,13,13,8,0,13,2,10,2,10,2,13,10,2,10,2,10,2,10,2,13,10,2,13,3,3,3,2,8,0,13,2,7,10,2,15,9,10,2,10,2,10,2,3,13,15,3,3,2,1,15,11,68,111,108,97,65,100,100,114,101,115,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,100,101,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,22,101,110,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,27,101,110,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,21,103,101,116,95,100,101,108,101,116,101,95,111,119,110,101,114,95,116,121,112,101,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,16,103,101,116,95,100,101,112,111,115,105,116,95,116,121,112,101,23,103,101,116,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,21,103,101,116,95,115,101,110,100,95,109,101,115,115,97,103,101,95,116,121,112,101,17,103,101,116,95,119,105,116,104,100,114,97,119,95,116,121,112,101,10,112,111,111,108,95,99,111,100,101,99,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,2,1,2,2,1,3,2,1,4,2,1,5,2,1,6,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,2,7,4,2,3,1,0,0,0,2,7,5,2,4,1,0,0,0,2,7,6,2,5,1,0,0,0,2,7,7,2,6,1,0,0,0,2,7,8,2,7,1,0,0,10,48,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,3,17,21,11,0,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,1,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,2,17,23,13,6,7,2,17,24,14,4,65,1,6,0,0,0,0,0,0,0,0,36,4,46,13,6,14,4,65,1,75,17,21,13,6,11,4,17,25,11,6,2,8,1,0,0,16,172,1,14,0,65,1,12,13,6,0,0,0,0,0,0,0,0,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,1,14,1,17,17,12,8,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,2,14,2,17,17,12,16,11,12,11,11,22,12,12,11,16,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,14,11,12,11,11,22,12,12,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,3,14,3,17,17,12,18,11,12,11,11,22,12,12,11,18,52,12,11,14,0,10,12,10,12,10,11,22,56,0,17,15,12,17,11,12,11,11,22,12,12,6,8,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,4,14,4,17,19,12,7,11,12,11,11,22,12,12,6,1,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,5,14,5,17,20,12,15,11,12,11,11,22,12,12,64,1,0,0,0,0,0,0,0,0,12,9,10,13,10,12,36,4,151,1,6,2,0,0,0,0,0,0,0,12,11,14,0,10,12,10,12,10,11,22,56,0,12,6,14,6,17,17,12,10,11,12,11,11,22,12,12,11,10,52,12,11,14,0,10,12,10,12,10,11,22,56,0,12,9,11,12,11,11,22,12,12,10,15,7,2,33,4,156,1,5,158,1,7,1,39,11,13,11,12,33,4,163,1,5,165,1,7,0,39,11,14,11,17,11,7,11,8,11,15,11,9,2,9,1,0,0,10,38,64,1,0,0,0,0,0,0,0,0,12,6,13,6,11,0,17,21,13,6,11,1,17,23,11,2,17,16,12,5,13,6,14,5,65,1,75,17,21,13,6,11,5,17,25,11,3,17,16,12,7,13,6,14,7,65,1,75,17,21,13,6,11,7,17,25,13,6,11,4,17,23,13,6,7,3,17,24,11,6,2,10,1,0,0,22,152,1,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,15,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,19,12,11,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,17,12,14,11,9,11,8,22,12,9,11,14,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,17,11,9,11,8,22,12,9,11,17,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,16,11,9,11,8,22,12,9,6,8,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,5,14,5,17,19,12,7,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,14,6,17,20,12,13,11,9,11,8,22,12,9,10,13,7,3,33,4,136,1,5,138,1,7,1,39,11,10,11,9,33,4,143,1,5,145,1,7,0,39,11,15,11,11,11,12,11,16,11,7,11,13,2,11,1,0,0,23,34,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,1,17,21,11,0,17,16,12,4,13,3,14,4,65,1,75,17,21,13,3,11,4,17,25,13,3,7,4,17,24,14,2,65,1,6,0,0,0,0,0,0,0,0,36,4,32,13,3,14,2,65,1,75,17,21,13,3,11,2,17,25,11,3,2,12,1,0,0,24,123,14,0,65,1,12,10,6,0,0,0,0,0,0,0,0,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,1,14,1,17,17,12,5,11,9,11,8,22,12,9,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,2,14,2,17,17,12,13,11,9,11,8,22,12,9,11,13,52,12,8,14,0,10,9,10,9,10,8,22,56,0,17,15,12,12,11,9,11,8,22,12,9,6,1,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,3,14,3,17,20,12,11,11,9,11,8,22,12,9,64,1,0,0,0,0,0,0,0,0,12,6,10,10,10,9,36,4,104,6,2,0,0,0,0,0,0,0,12,8,14,0,10,9,10,9,10,8,22,56,0,12,4,14,4,17,17,12,7,11,9,11,8,22,12,9,11,7,52,12,8,14,0,10,9,10,9,10,8,22,56,0,12,6,11,9,11,8,22,12,9,10,11,7,4,33,4,109,5,111,7,1,39,11,10,11,9,33,4,116,5,118,7,0,39,11,12,11,5,11,11,11,6,2,13,1,0,0,3,13,64,1,0,0,0,0,0,0,0,0,12,3,13,3,11,0,17,21,13,3,11,1,17,22,13,3,11,2,17,24,11,3,2,14,1,0,0,26,64,14,0,65,1,12,8,6,0,0,0,0,0,0,0,0,12,7,6,2,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,1,14,1,17,17,12,5,11,7,11,4,22,12,7,6,32,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,2,14,2,17,18,12,6,11,7,11,4,22,12,7,6,1,0,0,0,0,0,0,0,12,4,14,0,10,7,10,7,10,4,22,56,0,12,3,14,3,17,20,12,9,11,7,11,4,22,12,7,11,8,11,7,33,4,58,5,60,7,0,39,11,5,11,6,11,9,2,0],"pool_manager":[161,28,235,11,6,0,0,0,12,1,0,22,2,22,66,3,88,199,1,4,159,2,62,5,221,2,206,2,7,171,5,144,8,8,187,13,96,6,155,14,138,1,10,165,15,108,12,145,16,154,13,13,171,29,32,15,203,29,4,0,62,0,28,0,30,0,36,1,21,1,58,2,32,2,57,2,74,2,76,2,77,0,9,12,0,0,1,4,0,0,7,4,0,0,4,4,0,0,8,4,0,0,6,4,0,0,0,3,0,0,10,3,0,1,2,7,0,3,3,0,0,4,11,7,0,5,5,7,1,0,0,7,14,4,0,8,12,12,2,7,1,4,1,10,13,2,0,0,51,0,1,0,0,66,2,1,0,0,65,3,1,0,0,71,4,1,0,0,69,5,1,0,0,70,4,1,0,0,47,6,7,0,0,41,8,9,0,0,44,6,10,0,0,37,11,12,0,0,48,6,12,0,0,43,8,12,0,0,42,8,12,0,0,45,6,12,0,0,46,8,12,0,0,38,1,12,0,0,39,1,12,0,0,35,13,14,0,0,34,15,16,0,0,33,17,16,0,0,81,1,18,0,0,16,19,20,0,0,67,19,20,0,1,40,46,9,0,2,24,49,12,0,2,25,49,12,0,2,26,20,12,0,5,56,1,47,1,0,5,73,28,47,1,0,6,29,28,1,1,3,7,55,0,21,0,8,15,31,1,2,7,4,8,22,41,42,2,7,4,8,23,35,36,2,7,4,8,27,41,16,2,7,4,8,55,0,23,2,7,4,9,72,28,1,1,8,35,22,35,24,35,25,35,26,36,27,35,30,31,24,31,26,35,33,31,22,31,25,33,26,33,24,31,30,33,30,32,26,32,25,32,24,32,22,34,33,32,33,32,30,28,32,27,32,34,24,34,25,33,22,31,33,33,33,29,50,29,51,1,7,8,14,0,5,6,8,9,7,8,0,8,10,13,7,8,14,4,6,8,9,7,8,0,8,8,13,4,6,8,9,7,8,0,8,8,15,4,6,8,9,7,8,0,13,15,2,7,8,0,13,1,10,8,8,2,7,8,0,8,8,1,13,1,8,10,3,6,8,0,13,13,1,15,3,7,8,0,13,13,1,11,11,1,8,8,2,6,8,0,13,1,1,2,6,8,0,8,8,1,8,3,4,7,8,0,8,8,13,15,2,15,15,1,8,12,2,13,8,1,1,11,13,2,9,0,9,1,2,13,8,2,2,8,8,13,2,13,10,8,8,1,8,0,1,9,0,8,13,8,10,8,3,11,13,2,8,8,8,4,8,1,7,11,13,2,13,8,1,8,2,7,11,13,2,13,8,2,2,8,8,8,4,3,7,11,13,2,9,0,9,1,9,0,9,1,1,8,8,2,13,8,3,3,13,8,8,7,8,5,2,7,11,13,2,9,0,9,1,9,0,1,7,9,1,4,8,8,13,7,8,2,7,8,4,2,13,7,8,2,3,8,8,13,7,8,4,2,13,13,2,6,11,13,2,9,0,9,1,9,0,1,6,9,1,2,8,8,8,8,2,15,6,11,13,2,13,8,3,4,8,8,3,3,10,8,8,1,6,8,8,1,11,11,1,9,0,9,8,8,13,15,7,11,13,2,13,8,3,7,8,3,13,15,7,8,2,7,8,4,6,15,15,15,15,15,15,1,8,6,1,8,7,12,65,100,100,76,105,113,117,105,100,105,116,121,7,65,112,112,73,110,102,111,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,9,76,105,113,117,105,100,105,116,121,6,79,112,116,105,111,110,11,80,111,111,108,67,97,116,97,108,111,103,8,80,111,111,108,73,110,102,111,13,80,111,111,108,76,105,113,117,105,100,105,116,121,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,15,82,101,109,111,118,101,76,105,113,117,105,100,105,116,121,6,83,116,114,105,110,103,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,3,97,100,100,13,97,100,100,95,108,105,113,117,105,100,105,116,121,7,97,108,112,104,97,95,49,6,97,109,111,117,110,116,9,97,112,112,95,105,110,102,111,115,13,97,112,112,95,108,105,113,117,105,100,105,116,121,5,97,115,99,105,105,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,25,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,28,99,97,108,99,117,108,97,116,101,95,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,24,99,97,108,99,117,108,97,116,101,95,101,120,112,101,99,116,101,100,95,114,97,116,105,111,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,15,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,101,113,117,105,108,105,98,114,105,117,109,95,114,101,119,97,114,100,5,101,118,101,110,116,18,101,120,105,115,116,95,99,101,114,116,97,105,110,95,112,111,111,108,13,101,120,105,115,116,95,112,111,111,108,95,105,100,18,102,105,110,100,95,112,111,111,108,95,98,121,95,99,104,97,105,110,7,103,101,110,101,115,105,115,17,103,101,116,95,97,112,112,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,100,101,102,97,117,108,116,95,97,108,112,104,97,95,49,20,103,101,116,95,100,101,102,97,117,108,116,95,108,97,109,98,100,97,95,49,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,14,103,101,116,95,105,100,95,98,121,95,112,111,111,108,24,103,101,116,95,112,111,111,108,95,101,113,117,105,108,105,98,114,105,117,109,95,102,101,101,18,103,101,116,95,112,111,111,108,95,108,105,113,117,105,100,105,116,121,19,103,101,116,95,112,111,111,108,95,110,97,109,101,95,98,121,95,105,100,21,103,101,116,95,112,111,111,108,95,116,111,116,97,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,95,119,101,105,103,104,116,15,103,101,116,95,112,111,111,108,115,95,98,121,95,105,100,19,103,101,116,95,116,111,107,101,110,95,108,105,113,117,105,100,105,116,121,2,105,100,11,105,100,95,116,111,95,112,111,111,108,115,4,105,110,105,116,8,108,97,109,98,100,97,95,49,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,4,110,97,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,6,111,112,116,105,111,110,12,112,111,111,108,95,97,100,100,114,101,115,115,12,112,111,111,108,95,99,97,116,97,108,111,103,10,112,111,111,108,95,105,110,102,111,115,12,112,111,111,108,95,109,97,110,97,103,101,114,10,112,111,111,108,95,116,111,95,105,100,5,112,111,111,108,115,13,114,101,103,105,115,116,101,114,95,112,111,111,108,16,114,101,103,105,115,116,101,114,95,112,111,111,108,95,105,100,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,7,114,101,115,101,114,118,101,21,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,97,108,112,104,97,22,115,101,116,95,101,113,117,105,108,105,98,114,105,117,109,95,108,97,109,98,100,97,15,115,101,116,95,112,111,111,108,95,119,101,105,103,104,116,12,115,104,97,114,101,95,111,98,106,101,99,116,4,115,111,109,101,5,116,97,98,108,101,12,116,111,116,97,108,95,119,101,105,103,104,116,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,5,118,97,108,117,101,6,119,101,105,103,104,116,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,14,122,101,114,111,95,108,105,113,117,105,100,105,116,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,15,32,0,0,0,88,241,76,176,44,241,78,240,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,37,164,0,10,139,202,34,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,3,8,6,0,0,0,0,0,0,0,0,2,4,49,8,12,19,11,13,2,13,8,1,61,11,13,2,13,8,2,60,8,5,1,2,1,20,11,13,2,13,8,3,2,2,5,54,8,10,68,8,3,17,15,75,15,64,11,13,2,8,8,8,4,3,2,1,78,15,4,2,4,78,15,52,15,30,15,79,15,5,2,2,63,11,13,2,8,8,13,50,11,13,2,13,10,8,8,6,2,3,59,8,8,18,15,31,15,7,2,3,59,8,8,18,15,30,15,0,0,0,0,1,14,10,0,17,30,10,0,56,0,10,0,56,1,10,0,56,2,11,0,56,3,18,5,18,0,56,4,2,1,1,0,0,29,54,10,1,10,3,12,5,46,11,5,17,18,32,4,9,5,15,11,1,1,11,4,1,7,2,39,10,1,15,0,12,12,11,2,12,6,17,20,12,7,10,4,56,5,12,8,11,6,11,7,7,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,8,18,2,12,11,11,12,10,3,11,11,56,6,10,1,15,1,15,2,10,3,64,32,0,0,0,0,0,0,0,0,56,7,11,1,15,3,12,10,11,4,56,8,18,1,12,9,11,10,11,3,11,9,56,9,2,2,1,0,0,34,52,10,1,10,3,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,10,1,10,2,12,5,46,11,5,17,19,32,4,21,5,25,11,1,1,7,4,39,10,1,15,1,12,6,10,6,15,4,10,2,10,3,56,10,11,6,15,2,10,3,56,11,10,2,68,32,11,1,15,0,11,3,56,12,15,5,11,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,4,56,13,2,3,1,0,0,37,43,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,12,6,10,6,15,5,11,2,56,14,12,7,10,6,16,6,20,10,7,16,7,20,23,10,3,22,11,6,15,6,21,11,3,11,7,15,7,21,2,4,1,0,0,38,22,10,1,10,2,12,4,46,11,4,17,18,4,8,5,12,11,1,1,7,3,39,11,1,15,0,11,2,56,12,12,5,11,3,11,5,15,8,21,2,5,1,0,0,39,29,10,1,10,2,12,4,46,11,4,17,19,4,8,5,12,11,1,1,7,5,39,10,1,10,2,17,7,12,5,11,1,15,0,11,5,56,12,15,5,11,2,56,14,12,6,11,3,11,6,15,9,21,2,6,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,1,15,2,11,1,12,3,46,11,3,56,15,20,2,7,1,0,0,43,22,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,11,0,15,1,15,4,11,1,12,3,46,11,3,56,16,20,2,8,1,0,0,40,22,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,15,0,11,1,12,3,46,11,3,56,17,16,10,20,2,9,1,0,0,44,32,10,0,10,1,17,18,4,5,5,9,11,0,1,7,3,39,11,0,16,3,11,1,56,18,16,11,12,4,10,4,10,2,56,19,4,26,11,4,11,2,56,20,16,12,20,12,3,5,30,11,4,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,11,3,2,10,1,0,0,9,20,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,13,16,12,20,2,11,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,14,20,2,12,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,15,20,2,13,1,0,0,9,19,10,0,10,1,12,2,46,11,2,17,18,4,8,5,12,11,0,1,7,3,39,11,0,16,0,11,1,56,17,16,6,20,2,14,1,0,0,25,26,10,0,10,1,12,2,46,11,2,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,3,11,0,16,0,11,3,56,17,16,5,11,1,56,21,16,7,20,2,15,1,0,0,1,2,7,0,2,16,1,0,0,1,2,7,1,2,17,1,0,0,45,34,11,0,11,1,17,6,12,6,14,6,65,32,12,5,6,0,0,0,0,0,0,0,0,12,4,10,4,10,5,35,4,32,5,14,14,6,10,4,66,32,20,12,3,14,3,17,23,10,2,33,4,27,11,3,56,22,2,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,9,56,23,2,18,1,0,0,1,5,11,0,16,0,11,1,56,24,2,19,1,0,0,1,6,11,0,16,1,16,4,11,1,56,25,2,20,1,0,0,1,3,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,3,2,21,3,0,0,48,119,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,12,16,15,20,10,12,16,9,20,17,25,12,10,10,3,10,10,22,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,32,4,73,11,7,11,2,10,6,18,3,56,27,5,85,11,7,11,2,56,28,12,8,10,8,16,12,20,10,6,22,11,8,15,12,21,10,11,16,13,16,12,20,10,3,22,11,11,15,13,15,12,21,10,12,16,14,20,10,3,22,10,12,15,14,21,10,12,16,15,20,10,10,23,11,12,15,15,21,11,1,11,3,10,10,18,6,56,29,11,6,11,10,2,22,3,0,0,48,151,1,10,0,10,1,12,4,46,11,4,17,19,4,8,5,12,11,0,1,7,5,39,10,0,10,1,17,7,12,9,10,0,15,0,10,9,56,12,12,11,10,11,15,5,10,1,56,14,12,12,10,12,16,14,20,10,3,38,4,33,5,41,11,0,1,11,12,1,11,11,1,7,8,39,10,11,16,13,16,12,20,10,12,16,14,20,10,3,10,11,16,6,20,10,12,16,7,20,17,26,10,11,16,8,20,10,12,16,9,20,17,24,12,10,10,3,10,10,23,12,6,11,0,15,3,11,9,56,26,15,11,12,7,10,7,10,2,12,5,46,11,5,56,19,4,82,5,90,11,12,1,11,11,1,11,7,1,7,6,39,11,7,11,2,56,28,12,8,10,8,16,12,20,10,3,38,4,101,5,109,11,12,1,11,11,1,11,8,1,7,7,39,10,8,16,12,20,10,3,23,11,8,15,12,21,10,11,16,13,16,12,20,10,6,23,11,11,15,13,15,12,21,10,12,16,14,20,10,6,23,10,12,15,14,21,10,12,16,15,20,10,10,22,11,12,15,15,21,11,1,11,3,10,10,18,7,56,30,11,6,11,10,2,0,2,0,3,5,1,0,1,5,0,2,4,2,3,4,3,2,2,4,1,2,0,1,0,3,0,2,1,4,0,4,2,0,53,0,80,0],"rates":[161,28,235,11,6,0,0,0,8,1,0,6,2,6,4,3,10,70,5,80,48,7,128,1,185,2,8,185,3,32,6,217,3,68,12,157,4,128,5,0,13,0,11,0,16,1,0,8,0,0,6,0,1,0,0,2,0,1,0,0,5,2,1,0,0,1,3,1,0,0,3,4,1,0,0,4,4,1,0,1,7,6,1,0,1,8,6,3,0,1,9,6,1,0,1,10,6,1,0,2,12,7,1,0,2,14,5,1,0,2,15,7,1,0,2,17,7,1,0,3,7,8,0,13,15,1,15,4,7,8,0,13,15,15,4,15,15,15,15,3,15,15,15,0,2,7,8,0,13,2,15,15,6,15,15,15,15,15,15,7,15,15,15,15,15,15,15,7,83,116,111,114,97,103,101,27,99,97,108,99,117,108,97,116,101,95,97,118,101,114,97,103,101,95,108,105,113,117,105,100,105,116,121,21,99,97,108,99,117,108,97,116,101,95,98,111,114,114,111,119,95,114,97,116,101,29,99,97,108,99,117,108,97,116,101,95,99,111,109,112,111,117,110,100,101,100,95,105,110,116,101,114,101,115,116,25,99,97,108,99,117,108,97,116,101,95,108,105,110,101,97,114,95,105,110,116,101,114,101,115,116,24,99,97,108,99,117,108,97,116,101,95,108,105,113,117,105,100,105,116,121,95,114,97,116,101,21,99,97,108,99,117,108,97,116,101,95,117,116,105,108,105,122,97,116,105,111,110,16,103,101,116,95,98,111,114,114,111,119,95,105,110,100,101,120,23,103,101,116,95,98,111,114,114,111,119,95,114,97,116,101,95,102,97,99,116,111,114,115,30,103,101,116,95,100,116,111,107,101,110,95,115,99,97,108,101,100,95,116,111,116,97,108,95,115,117,112,112,108,121,19,103,101,116,95,116,114,101,97,115,117,114,121,95,102,97,99,116,111,114,20,108,101,110,100,105,110,103,95,99,111,114,101,95,115,116,111,114,97,103,101,3,109,105,110,5,114,97,116,101,115,3,114,97,121,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,128,51,225,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,128,81,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,3,29,10,0,10,1,17,8,12,6,11,0,11,1,17,6,12,4,11,6,11,4,17,13,12,5,10,5,10,2,22,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,21,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,3,5,27,10,5,11,5,11,2,22,17,12,12,3,11,3,2,1,1,0,0,8,39,10,0,10,1,11,2,17,0,12,8,11,0,11,1,17,7,12,7,12,6,12,5,12,4,10,8,10,7,35,4,23,11,4,11,8,11,5,17,13,22,12,3,5,37,11,4,11,5,22,11,6,11,8,10,7,23,17,11,11,7,23,17,12,17,13,22,12,3,11,3,2,2,1,0,0,7,17,10,0,10,1,11,3,17,0,12,5,11,0,11,1,17,9,12,4,11,2,11,5,17,11,11,4,23,17,13,17,13,2,3,1,0,0,7,20,11,0,11,1,23,7,1,17,10,12,4,7,1,10,4,23,12,5,11,2,11,5,24,11,3,11,4,24,22,7,1,26,2,4,1,0,0,9,69,11,0,11,1,23,12,5,10,5,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,4,10,17,11,2,10,5,74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,6,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,23,10,5,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,12,7,5,25,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,10,2,10,2,17,13,7,0,7,0,24,26,12,4,10,4,10,2,17,13,7,0,26,12,3,10,5,10,6,24,11,4,24,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,8,10,5,11,6,24,11,7,24,11,3,24,74,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,12,9,17,11,11,2,11,5,24,7,0,26,22,11,8,22,11,9,22,2,5,1,0,0,1,12,11,2,11,0,11,1,23,24,7,0,26,12,3,17,11,11,3,22,2,0],"ray_math":[161,28,235,11,6,0,0,0,7,1,0,2,3,2,40,5,42,13,7,55,59,8,114,32,6,146,1,146,1,12,164,2,247,5,0,7,0,3,0,1,0,0,5,0,1,0,0,8,2,1,0,0,4,2,1,0,0,1,2,1,0,0,2,2,1,0,0,6,1,1,0,0,0,1,3,0,0,1,15,2,15,15,1,2,4,15,2,15,15,4,108,111,103,50,3,109,97,120,3,109,105,110,3,114,97,121,7,114,97,121,95,100,105,118,7,114,97,121,95,108,110,50,8,114,97,121,95,108,111,103,50,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,15,32,0,0,0,232,60,128,208,159,60,46,59,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,116,30,64,232,79,30,151,157,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,0,0,0,208,121,0,161,63,121,92,118,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,32,249,214,165,42,128,81,101,243,159,91,61,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,8,0,0,0,0,0,0,0,0,0,1,0,0,0,2,7,0,2,1,1,0,0,0,2,7,3,2,2,1,0,0,0,10,11,0,11,1,24,7,0,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,7,0,26,2,3,1,0,0,0,10,11,0,7,0,24,10,1,74,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,22,11,1,26,2,4,1,0,0,1,11,10,0,10,1,36,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,5,1,0,0,1,11,10,0,10,1,35,4,7,11,0,12,2,5,9,11,1,12,2,11,2,2,6,1,0,0,4,59,10,0,7,0,38,4,5,5,7,7,4,39,10,0,7,0,26,17,7,12,2,10,2,77,7,0,24,12,3,11,0,11,2,48,12,4,10,4,7,0,33,4,27,11,3,2,7,1,12,1,10,1,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,57,5,34,10,4,11,4,24,7,0,26,12,4,10,4,7,2,38,4,52,11,3,10,1,22,12,3,11,4,49,1,48,12,4,11,1,49,1,48,12,1,5,29,11,3,2,7,1,0,0,3,112,49,0,12,1,10,0,49,128,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,16,11,0,49,128,48,12,0,11,1,49,128,22,12,1,10,0,49,64,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,30,11,0,49,64,48,12,0,11,1,49,64,22,12,1,10,0,49,32,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,44,11,0,49,32,48,12,0,11,1,49,32,22,12,1,10,0,49,16,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,58,11,0,49,16,48,12,0,11,1,49,16,22,12,1,10,0,49,8,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,72,11,0,49,8,48,12,0,11,1,49,8,22,12,1,10,0,49,4,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,86,11,0,49,4,48,12,0,11,1,49,4,22,12,1,10,0,49,2,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,100,11,0,49,2,48,12,0,11,1,49,2,22,12,1,11,0,49,1,48,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,110,11,1,49,1,22,12,1,11,1,2,0],"scaled_balance":[161,28,235,11,6,0,0,0,6,1,0,4,3,4,25,5,29,6,7,35,75,8,110,32,12,142,1,39,0,6,0,4,0,0,0,1,0,0,2,0,1,0,0,1,0,1,0,1,3,0,1,0,1,5,0,1,0,2,15,15,1,15,0,10,98,97,108,97,110,99,101,95,111,102,11,98,117,114,110,95,115,99,97,108,101,100,11,109,105,110,116,95,115,99,97,108,101,100,7,114,97,121,95,100,105,118,8,114,97,121,95,109,97,116,104,7,114,97,121,95,109,117,108,14,115,99,97,108,101,100,95,98,97,108,97,110,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,1,0,0,2,4,11,0,11,1,17,4,2,1,1,0,0,2,4,11,0,11,1,17,3,2,2,1,0,0,2,4,11,0,11,1,17,3,2,0],"serde":[161,28,235,11,6,0,0,0,9,1,0,12,2,12,8,3,20,167,1,4,187,1,12,5,199,1,148,1,7,219,2,211,4,8,174,7,96,6,142,8,20,12,162,8,157,35,0,23,1,4,1,6,1,36,1,37,2,2,1,0,7,0,3,1,7,0,0,32,0,1,0,0,28,2,1,0,0,31,3,1,0,0,26,4,1,0,0,29,5,1,0,0,19,6,6,0,0,5,6,6,0,0,27,4,1,0,0,30,5,1,0,0,33,7,1,0,0,24,8,1,0,0,25,9,1,1,0,0,34,7,1,0,0,14,10,6,0,0,10,10,11,0,0,13,10,12,0,0,8,10,13,0,0,11,10,14,0,0,9,10,13,0,0,12,10,14,0,0,7,10,15,0,0,18,10,12,0,0,15,10,16,0,0,38,17,18,1,1,0,39,19,20,1,3,1,20,28,16,0,2,35,27,16,1,0,3,17,1,30,1,0,3,21,30,28,0,4,3,25,1,1,0,4,22,24,1,1,0,5,16,16,15,0,30,6,29,6,26,15,27,29,23,6,23,29,2,7,10,2,2,0,2,7,10,2,13,2,7,10,2,3,2,7,10,2,4,2,7,10,2,15,1,2,2,7,10,2,10,2,2,7,10,2,5,1,7,10,2,1,6,10,2,1,13,1,3,1,4,1,15,1,5,1,10,2,3,6,10,9,0,3,3,1,10,9,0,2,6,10,9,0,9,0,1,10,10,9,0,2,1,2,3,1,1,2,2,4,10,2,1,7,10,9,0,2,7,10,9,0,10,9,0,2,15,10,2,1,6,9,0,1,8,0,1,9,0,1,8,1,2,4,3,2,15,3,3,10,2,3,3,3,1,3,10,9,0,3,3,10,10,9,0,3,6,83,116,114,105,110,103,8,84,121,112,101,78,97,109,101,7,97,100,100,114,101,115,115,6,97,112,112,101,110,100,5,97,115,99,105,105,16,97,115,99,105,105,95,116,111,95,104,101,120,95,115,116,114,3,98,99,115,19,100,101,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,16,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,29,100,101,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,16,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,29,100,101,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,30,100,101,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,10,102,114,111,109,95,98,121,116,101,115,3,103,101,116,17,103,101,116,95,118,101,99,116,111,114,95,108,101,110,103,116,104,16,104,101,120,95,115,116,114,95,116,111,95,97,115,99,105,105,10,105,110,116,111,95,98,121,116,101,115,11,105,110,116,111,95,115,116,114,105,110,103,7,114,101,118,101,114,115,101,5,115,101,114,100,101,17,115,101,114,105,97,108,105,122,101,95,97,100,100,114,101,115,115,14,115,101,114,105,97,108,105,122,101,95,116,121,112,101,14,115,101,114,105,97,108,105,122,101,95,117,49,50,56,27,115,101,114,105,97,108,105,122,101,95,117,49,50,56,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,49,54,14,115,101,114,105,97,108,105,122,101,95,117,50,53,54,27,115,101,114,105,97,108,105,122,101,95,117,50,53,54,95,119,105,116,104,95,104,101,120,95,115,116,114,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,28,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,95,119,105,116,104,95,108,101,110,103,116,104,8,116,111,95,98,121,116,101,115,9,116,121,112,101,95,110,97,109,101,6,118,101,99,116,111,114,12,118,101,99,116,111,114,95,115,108,105,99,101,12,118,101,99,116,111,114,95,115,112,108,105,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,0,1,0,0,1,4,11,0,11,1,68,6,2,1,1,0,0,1,15,10,0,10,1,49,8,48,72,255,0,28,51,17,0,11,0,11,1,72,255,0,28,51,17,0,2,2,1,0,0,1,63,10,0,10,1,49,56,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,6,255,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,6,255,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,6,255,0,0,0,0,0,0,0,28,51,17,0,2,3,1,0,0,1,127,10,0,10,1,49,120,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,4,1,0,0,1,255,1,10,0,10,1,49,248,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,240,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,232,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,224,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,216,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,208,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,200,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,192,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,184,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,176,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,168,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,160,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,152,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,144,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,136,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,128,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,120,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,112,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,104,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,96,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,88,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,80,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,72,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,64,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,56,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,48,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,40,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,32,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,24,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,16,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,10,0,10,1,49,8,48,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,0,11,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,2,5,1,0,0,21,31,10,0,49,0,38,4,9,10,0,49,9,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,22,12,2,5,29,10,0,49,15,37,4,23,5,25,7,1,39,11,0,49,87,22,12,2,11,2,2,6,1,0,0,22,40,10,0,49,48,38,4,9,10,0,49,57,37,12,1,5,11,9,12,1,11,1,4,18,11,0,49,48,23,12,3,5,38,10,0,49,97,38,4,27,10,0,49,102,37,12,2,5,29,9,12,2,11,2,4,32,5,34,7,1,39,11,0,49,87,23,12,3,11,3,2,7,1,0,0,23,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,50,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,8,1,0,0,26,34,64,6,0,0,0,0,0,0,0,0,12,3,13,3,10,1,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,1,49,8,48,12,2,10,2,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,4,28,5,17,13,3,10,2,74,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,51,17,0,11,2,49,8,48,12,2,5,12,13,3,56,0,11,0,11,3,56,1,2,9,1,0,0,1,4,11,0,11,1,56,1,2,10,1,0,0,16,17,14,1,56,2,12,2,14,2,65,6,6,32,0,0,0,0,0,0,0,33,4,9,5,13,11,0,1,7,0,39,11,0,11,2,56,1,2,11,1,0,0,28,8,56,3,17,28,12,1,11,0,11,1,17,25,17,9,2,12,1,0,0,12,17,14,1,65,6,12,2,10,2,6,0,0,0,0,0,0,0,0,33,4,10,11,0,1,2,10,0,11,2,17,2,11,0,11,1,17,9,2,13,1,0,0,1,15,10,0,65,6,6,1,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,6,0,0,0,0,0,0,0,0,66,6,20,2,14,1,0,0,1,24,10,0,65,6,6,2,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,75,49,8,47,11,0,6,1,0,0,0,0,0,0,0,66,6,20,75,22,2,15,1,0,0,1,72,10,0,65,6,6,8,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,52,49,56,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,52,49,48,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,52,49,40,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,52,49,32,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,52,49,24,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,52,49,16,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,52,49,8,47,22,11,0,6,7,0,0,0,0,0,0,0,66,6,20,52,22,2,16,1,0,0,1,136,1,10,0,65,6,6,16,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,53,49,120,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,53,49,112,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,53,49,104,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,53,49,96,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,53,49,88,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,53,49,80,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,53,49,72,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,53,49,64,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,53,49,56,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,53,49,48,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,53,49,40,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,53,49,32,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,53,49,24,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,53,49,16,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,53,49,8,47,22,11,0,6,15,0,0,0,0,0,0,0,66,6,20,53,22,2,17,1,0,0,1,136,2,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,66,6,20,77,49,248,47,10,0,6,1,0,0,0,0,0,0,0,66,6,20,77,49,240,47,22,10,0,6,2,0,0,0,0,0,0,0,66,6,20,77,49,232,47,22,10,0,6,3,0,0,0,0,0,0,0,66,6,20,77,49,224,47,22,10,0,6,4,0,0,0,0,0,0,0,66,6,20,77,49,216,47,22,10,0,6,5,0,0,0,0,0,0,0,66,6,20,77,49,208,47,22,10,0,6,6,0,0,0,0,0,0,0,66,6,20,77,49,200,47,22,10,0,6,7,0,0,0,0,0,0,0,66,6,20,77,49,192,47,22,10,0,6,8,0,0,0,0,0,0,0,66,6,20,77,49,184,47,22,10,0,6,9,0,0,0,0,0,0,0,66,6,20,77,49,176,47,22,10,0,6,10,0,0,0,0,0,0,0,66,6,20,77,49,168,47,22,10,0,6,11,0,0,0,0,0,0,0,66,6,20,77,49,160,47,22,10,0,6,12,0,0,0,0,0,0,0,66,6,20,77,49,152,47,22,10,0,6,13,0,0,0,0,0,0,0,66,6,20,77,49,144,47,22,10,0,6,14,0,0,0,0,0,0,0,66,6,20,77,49,136,47,22,10,0,6,15,0,0,0,0,0,0,0,66,6,20,77,49,128,47,22,10,0,6,16,0,0,0,0,0,0,0,66,6,20,77,49,120,47,22,10,0,6,17,0,0,0,0,0,0,0,66,6,20,77,49,112,47,22,10,0,6,18,0,0,0,0,0,0,0,66,6,20,77,49,104,47,22,10,0,6,19,0,0,0,0,0,0,0,66,6,20,77,49,96,47,22,10,0,6,20,0,0,0,0,0,0,0,66,6,20,77,49,88,47,22,10,0,6,21,0,0,0,0,0,0,0,66,6,20,77,49,80,47,22,10,0,6,22,0,0,0,0,0,0,0,66,6,20,77,49,72,47,22,10,0,6,23,0,0,0,0,0,0,0,66,6,20,77,49,64,47,22,10,0,6,24,0,0,0,0,0,0,0,66,6,20,77,49,56,47,22,10,0,6,25,0,0,0,0,0,0,0,66,6,20,77,49,48,47,22,10,0,6,26,0,0,0,0,0,0,0,66,6,20,77,49,40,47,22,10,0,6,27,0,0,0,0,0,0,0,66,6,20,77,49,32,47,22,10,0,6,28,0,0,0,0,0,0,0,66,6,20,77,49,24,47,22,10,0,6,29,0,0,0,0,0,0,0,66,6,20,77,49,16,47,22,10,0,6,30,0,0,0,0,0,0,0,66,6,20,77,49,8,47,22,11,0,6,31,0,0,0,0,0,0,0,66,6,20,77,22,2,18,1,0,0,31,29,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,53,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,19,1,0,0,32,29,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,1,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,6,35,4,25,5,10,11,1,49,8,47,10,0,10,2,66,6,20,77,22,12,1,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,4,11,0,1,11,1,2,20,1,0,0,1,14,10,0,65,6,6,32,0,0,0,0,0,0,0,33,4,6,5,10,11,0,1,7,0,39,11,0,20,17,31,2,21,1,0,0,16,8,11,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,2,22,1,0,0,33,46,10,0,65,6,12,3,10,3,6,0,0,0,0,0,0,0,0,33,4,11,11,0,1,64,6,0,0,0,0,0,0,0,0,2,10,3,6,8,0,0,0,0,0,0,0,36,4,16,5,20,11,0,1,7,0,39,10,0,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,56,4,12,1,14,1,17,15,12,2,11,3,10,2,6,8,0,0,0,0,0,0,0,22,33,4,35,5,39,11,0,1,7,0,39,11,0,6,8,0,0,0,0,0,0,0,11,2,6,8,0,0,0,0,0,0,0,22,56,4,2,23,1,0,0,34,43,10,1,10,2,35,4,10,10,2,10,0,65,29,37,12,3,5,12,9,12,3,11,3,4,15,5,19,11,0,1,7,0,39,64,29,0,0,0,0,0,0,0,0,12,5,11,1,12,4,10,4,10,2,35,4,39,5,28,13,5,10,0,10,4,66,29,20,68,29,11,4,6,1,0,0,0,0,0,0,0,22,12,4,5,23,11,0,1,11,5,2,24,1,0,0,35,53,64,18,0,0,0,0,0,0,0,0,12,3,6,0,0,0,0,0,0,0,0,12,4,6,0,0,0,0,0,0,0,0,12,2,10,2,10,0,65,29,35,4,38,5,12,10,0,10,2,66,29,20,10,1,33,4,33,10,4,10,2,35,4,29,13,3,10,0,11,4,10,2,56,5,68,18,10,2,6,1,0,0,0,0,0,0,0,22,12,4,11,2,6,1,0,0,0,0,0,0,0,22,12,2,5,6,10,4,10,2,35,4,49,13,3,11,0,11,4,11,2,56,5,68,18,5,51,11,0,1,11,3,2,0],"system_codec":[161,28,235,11,6,0,0,0,9,1,0,6,2,6,4,3,10,71,4,81,2,5,83,78,7,161,1,150,2,8,183,3,32,6,215,3,26,12,241,3,169,2,0,16,0,6,0,11,1,0,7,0,0,9,0,1,0,0,10,0,1,0,0,7,2,3,0,0,1,3,2,0,1,2,3,7,0,1,8,7,3,0,2,3,13,14,0,2,4,13,15,0,2,5,13,1,0,2,12,5,0,0,2,13,6,0,0,2,14,9,0,0,2,15,8,0,0,2,17,11,12,1,1,13,1,0,1,2,4,13,3,8,0,2,1,10,2,2,10,2,10,2,2,7,10,2,13,2,7,10,2,3,1,8,0,2,7,10,2,10,2,2,7,10,2,2,12,10,2,10,2,10,2,10,2,8,0,13,3,3,3,3,13,2,3,6,10,9,0,3,3,1,10,9,0,1,6,10,2,1,13,1,3,11,68,111,108,97,65,100,100,114,101,115,115,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,100,101,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,15,100,101,115,101,114,105,97,108,105,122,101,95,117,49,54,15,100,101,115,101,114,105,97,108,105,122,101,95,117,54,52,14,100,101,115,101,114,105,97,108,105,122,101,95,117,56,12,100,111,108,97,95,97,100,100,114,101,115,115,19,101,110,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,19,101,110,99,111,100,101,95,100,111,108,97,95,97,100,100,114,101,115,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,115,101,114,100,101,13,115,101,114,105,97,108,105,122,101,95,117,49,54,13,115,101,114,105,97,108,105,122,101,95,117,54,52,12,115,101,114,105,97,108,105,122,101,95,117,56,16,115,101,114,105,97,108,105,122,101,95,118,101,99,116,111,114,12,115,121,115,116,101,109,95,99,111,100,101,99,12,118,101,99,116,111,114,95,115,108,105,99,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,2,1,0,2,1,1,0,1,0,0,0,2,7,2,2,1,1,0,0,0,2,7,3,2,2,1,0,0,4,24,64,1,0,0,0,0,0,0,0,0,12,5,13,5,11,0,17,9,13,5,11,1,17,10,11,2,17,5,12,4,13,5,14,4,65,1,75,17,9,13,5,11,4,17,12,13,5,11,3,17,11,11,5,2,3,1,0,0,10,96,14,0,65,1,12,9,6,0,0,0,0,0,0,0,0,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,1,14,1,17,6,12,11,11,8,11,7,22,12,8,6,8,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,2,14,2,17,7,12,10,11,8,11,7,22,12,8,6,2,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,3,14,3,17,6,12,6,11,8,11,7,22,12,8,11,6,52,12,7,14,0,10,8,10,8,10,7,22,56,0,17,4,12,5,11,8,11,7,22,12,8,6,1,0,0,0,0,0,0,0,12,7,14,0,10,8,10,8,10,7,22,56,0,12,4,14,4,17,8,12,12,11,8,11,7,22,12,8,11,9,11,8,33,4,89,5,91,7,0,39,11,11,11,10,11,5,11,12,2,0],"system_core_storage":[161,28,235,11,6,0,0,0,11,1,0,12,2,12,24,3,36,26,4,62,2,5,64,35,7,99,252,1,8,223,2,64,10,159,3,9,12,168,3,34,13,202,3,2,15,204,3,2,0,16,0,7,0,8,1,13,1,18,1,19,0,2,8,0,1,0,12,0,1,3,12,0,2,1,0,0,3,5,4,0,5,4,2,0,0,11,0,1,0,0,9,2,3,0,1,14,0,6,0,3,12,4,5,0,4,15,8,1,1,8,4,7,3,6,8,3,7,8,2,7,8,5,0,1,6,8,0,1,6,8,1,1,7,8,5,1,8,4,1,8,1,1,8,0,1,9,0,6,65,112,112,67,97,112,13,71,111,118,101,114,110,97,110,99,101,67,97,112,7,83,116,111,114,97,103,101,12,84,111,116,97,108,65,112,112,73,110,102,111,9,84,120,67,111,110,116,101,120,116,3,85,73,68,7,97,112,112,95,99,97,112,11,97,112,112,95,109,97,110,97,103,101,114,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,3,110,101,119,6,111,98,106,101,99,116,28,114,101,103,105,115,116,101,114,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,12,115,104,97,114,101,95,111,98,106,101,99,116,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,10,8,4,6,8,1,0,1,0,0,1,9,10,2,17,3,11,0,11,1,11,2,17,2,18,0,56,0,2,1,3,0,0,1,3,11,0,16,0,2,0,1,0,17,0],"system_core_wormhole_adapter":[161,28,235,11,6,0,0,0,10,1,0,24,2,24,40,3,64,71,4,135,1,2,5,137,1,117,7,254,1,155,4,8,153,6,96,6,249,6,10,10,131,7,17,12,148,7,191,1,0,33,0,10,0,16,0,19,0,31,0,32,0,38,0,39,1,14,1,18,1,34,2,30,0,7,3,0,1,0,12,0,2,3,7,0,3,4,8,0,5,6,8,0,6,9,12,0,7,2,12,0,8,1,8,0,10,8,2,0,11,5,12,0,0,11,0,1,0,0,35,0,1,0,2,22,13,8,0,2,23,13,14,0,3,13,3,1,0,4,15,8,9,0,4,21,1,10,0,4,24,1,10,0,5,20,4,5,0,6,11,12,1,0,6,27,11,1,0,6,35,12,1,0,7,26,6,7,0,9,17,16,1,1,3,13,15,8,6,8,3,7,8,5,7,8,9,7,8,6,6,8,4,10,2,6,8,7,7,8,8,0,6,10,2,8,2,2,3,8,2,13,1,6,8,3,1,6,8,4,1,6,8,1,6,7,8,9,7,8,6,6,8,1,10,2,6,8,7,7,8,8,2,8,2,10,2,1,10,2,4,13,3,8,2,2,1,2,2,7,8,5,8,2,3,7,8,5,8,2,8,2,1,6,8,2,1,13,1,8,0,1,9,0,6,10,2,2,3,8,2,13,8,2,6,65,112,112,67,97,112,5,67,108,111,99,107,9,67,111,114,101,83,116,97,116,101,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,5,83,116,97,116,101,7,83,116,111,114,97,103,101,15,83,121,115,116,101,109,67,111,114,101,69,118,101,110,116,9,84,120,67,111,110,116,101,120,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,11,97,112,112,95,109,97,110,97,103,101,114,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,19,100,101,99,111,100,101,95,98,105,110,100,95,112,97,121,108,111,97,100,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,11,103,101,116,95,97,112,112,95,99,97,112,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,5,110,111,110,99,101,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,12,115,121,115,116,101,109,95,99,111,100,101,99,19,115,121,115,116,101,109,95,99,111,114,101,95,115,116,111,114,97,103,101,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,0,2,6,25,3,28,10,2,29,13,37,13,36,10,2,12,2,0,1,4,0,2,51,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,12,11,8,17,5,12,10,12,9,12,11,12,13,10,10,17,6,33,4,23,5,27,11,1,1,7,0,39,10,12,10,9,33,4,35,11,1,10,12,17,10,5,39,11,1,10,12,10,9,17,9,11,11,14,12,17,2,11,13,14,9,17,3,14,9,17,2,11,10,18,0,56,0,2,1,1,4,0,17,43,11,0,17,4,11,2,11,3,11,4,17,8,11,5,11,6,11,7,17,12,12,8,12,11,11,8,17,5,12,9,12,13,12,10,12,12,10,9,17,7,33,4,23,5,27,11,1,1,7,0,39,11,1,10,11,10,13,17,11,11,10,14,11,17,2,11,12,14,13,17,3,14,13,17,2,11,9,18,0,56,0,2,0],"system_portal":[161,28,235,11,6,0,0,0,10,1,0,18,2,18,28,3,46,82,4,128,1,4,5,132,1,84,7,216,1,208,3,8,168,5,64,10,232,5,22,12,254,5,187,1,13,185,7,2,0,30,0,13,0,16,0,29,0,37,1,15,1,25,1,31,1,32,0,3,8,0,0,2,3,0,1,0,7,0,2,1,8,0,4,6,12,0,6,5,4,0,8,4,2,0,0,21,0,1,0,0,18,2,3,0,0,8,4,1,0,0,34,4,1,0,1,11,11,12,0,1,12,13,12,0,2,10,9,1,0,3,17,1,16,0,3,19,1,16,0,4,7,15,1,0,4,26,14,1,0,4,33,15,1,0,5,14,7,1,1,3,6,22,0,5,0,7,28,7,1,1,8,8,27,10,11,0,14,6,12,17,1,7,8,6,0,1,7,8,0,1,3,6,6,8,3,7,8,0,7,8,4,13,10,2,7,8,6,1,8,5,1,8,0,1,9,0,3,8,2,5,8,2,1,6,8,3,1,6,8,6,1,5,1,8,2,2,13,10,2,2,7,8,4,8,2,3,7,8,4,8,2,8,2,1,2,1,8,1,3,5,8,2,8,2,11,68,111,108,97,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,16,83,121,115,116,101,109,76,111,99,97,108,69,118,101,110,116,12,83,121,115,116,101,109,80,111,114,116,97,108,9,84,120,67,111,110,116,101,120,116,3,85,73,68,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,7,98,105,110,100,105,110,103,9,99,97,108,108,95,116,121,112,101,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,23,99,111,110,118,101,114,116,95,97,100,100,114,101,115,115,95,116,111,95,100,111,108,97,19,99,114,101,97,116,101,95,100,111,108,97,95,97,100,100,114,101,115,115,12,100,111,108,97,95,97,100,100,114,101,115,115,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,16,103,101,116,95,98,105,110,100,105,110,103,95,116,121,112,101,9,103,101,116,95,110,111,110,99,101,18,103,101,116,95,117,110,98,105,110,100,105,110,103,95,116,121,112,101,2,105,100,4,105,110,105,116,3,110,101,119,10,110,101,120,116,95,110,111,110,99,101,5,110,111,110,99,101,6,111,98,106,101,99,116,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,12,115,121,115,116,101,109,95,99,111,100,101,99,13,115,121,115,116,101,109,95,112,111,114,116,97,108,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,9,117,110,98,105,110,100,105,110,103,12,117,115,101,114,95,97,100,100,114,101,115,115,13,117,115,101,114,95,99,104,97,105,110,95,105,100,12,117,115,101,114,95,109,97,110,97,103,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,20,8,5,23,3,1,2,5,24,3,27,5,36,13,35,10,2,9,2,0,0,0,0,1,6,11,0,17,13,6,0,0,0,0,0,0,0,0,18,0,56,0,2,1,0,0,0,3,14,10,0,16,0,20,12,1,10,0,16,0,20,6,1,0,0,0,0,0,0,0,22,11,0,15,0,21,11,1,2,2,1,4,0,8,34,11,0,17,6,11,5,46,17,15,12,7,10,7,17,4,12,8,10,3,10,4,17,5,12,6,10,8,10,6,33,4,21,11,2,11,8,17,10,5,25,11,2,11,8,11,6,17,9,11,1,17,1,11,7,11,3,11,4,17,7,18,1,56,1,2,3,1,4,0,18,26,11,0,17,6,11,5,46,17,15,12,6,10,6,17,4,12,8,10,3,10,4,17,5,12,7,11,2,11,8,11,7,17,11,11,1,17,1,11,6,11,3,11,4,17,8,18,1,56,1,2,0,1,0],"user_manager":[161,28,235,11,6,0,0,0,12,1,0,18,2,18,40,3,58,138,1,4,196,1,42,5,238,1,128,2,7,238,3,161,5,8,143,9,96,6,239,9,60,10,171,10,49,12,220,10,247,4,13,211,15,8,15,219,15,8,0,48,0,15,0,20,1,49,2,19,2,31,2,39,2,40,2,41,0,8,12,0,0,7,4,0,0,0,3,0,0,6,3,0,1,1,7,0,2,2,0,0,5,5,4,0,6,3,12,2,7,1,4,1,8,4,2,0,0,26,0,1,0,0,33,2,1,0,0,43,3,1,0,0,22,4,5,0,0,23,6,7,0,0,32,4,8,0,0,27,4,9,0,0,34,10,1,0,0,10,11,1,0,0,42,11,1,0,1,21,28,29,0,1,44,30,8,0,3,25,37,38,1,0,3,35,39,18,1,0,4,18,18,1,1,3,5,30,0,12,0,6,9,21,1,2,7,4,6,11,20,25,2,7,4,6,12,22,35,2,7,4,6,14,20,9,2,7,4,6,29,32,5,2,7,4,6,30,0,14,2,7,4,6,35,22,23,2,7,4,7,36,18,1,1,8,21,13,21,15,21,16,23,17,19,16,16,16,22,16,19,13,17,13,19,15,17,15,17,16,20,15,16,13,16,15,14,33,18,15,12,8,22,13,13,8,14,40,1,7,8,8,0,4,6,8,5,7,8,0,13,13,3,6,8,5,7,8,0,13,2,6,8,0,8,4,1,3,2,6,8,0,3,1,10,8,4,1,8,4,1,1,2,7,8,0,8,4,3,7,8,0,8,4,8,4,1,8,6,2,8,4,3,1,11,7,2,9,0,9,1,2,3,10,8,4,2,13,13,1,8,0,1,9,0,2,13,7,11,7,2,13,13,2,6,11,7,2,9,0,9,1,9,0,3,7,11,7,2,9,0,9,1,9,0,9,1,2,7,11,7,2,9,0,9,1,9,0,1,9,1,2,8,4,6,8,1,1,6,9,1,1,6,8,1,3,8,4,6,11,7,2,13,13,13,1,6,8,4,1,13,2,8,4,13,6,8,4,8,4,3,8,4,10,8,4,7,8,1,1,6,11,7,2,9,0,9,1,1,8,2,7,8,4,8,4,8,4,8,4,3,7,10,8,4,7,8,1,1,7,9,1,10,8,4,8,4,8,4,6,8,4,3,3,3,8,4,7,10,8,4,7,8,1,2,6,10,9,0,6,9,0,2,1,3,2,7,10,9,0,3,1,8,3,8,66,105,110,100,85,115,101,114,11,68,111,108,97,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,5,84,97,98,108,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,10,85,110,98,105,110,100,85,115,101,114,18,85,115,101,114,65,100,100,114,101,115,115,67,97,116,97,108,111,103,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,97,100,100,17,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,6,98,111,114,114,111,119,10,98,111,114,114,111,119,95,109,117,116,17,99,104,97,105,110,95,105,100,95,116,111,95,103,114,111,117,112,8,99,111,110,116,97,105,110,115,12,100,111,108,97,95,97,100,100,114,101,115,115,17,100,111,108,97,95,117,115,101,114,95,97,100,100,114,101,115,115,12,100,111,108,97,95,117,115,101,114,95,105,100,4,101,109,105,116,5,101,118,101,110,116,7,103,101,110,101,115,105,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,16,103,101,116,95,100,111,108,97,95,117,115,101,114,95,105,100,18,103,101,116,95,117,115,101,114,95,97,100,100,114,101,115,115,101,115,2,105,100,8,105,110,100,101,120,95,111,102,4,105,110,105,116,12,105,115,95,100,111,108,97,95,117,115,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,6,108,101,110,103,116,104,3,110,101,119,6,111,98,106,101,99,116,16,112,114,111,99,101,115,115,95,103,114,111,117,112,95,105,100,22,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,6,114,101,109,111,118,101,12,115,104,97,114,101,95,111,98,106,101,99,116,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,13,115,121,115,116,101,109,95,112,111,114,116,97,108,5,116,97,98,108,101,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,19,117,110,98,105,110,100,95,117,115,101,114,95,97,100,100,114,101,115,115,24,117,110,114,101,103,105,115,116,101,114,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,112,100,97,116,101,95,100,111,108,97,95,99,104,97,105,110,95,105,100,20,117,115,101,114,95,97,100,100,114,101,115,115,95,99,97,116,97,108,111,103,23,117,115,101,114,95,97,100,100,114,101,115,115,95,116,111,95,117,115,101,114,95,105,100,20,117,115,101,114,95,105,100,95,116,111,95,97,100,100,114,101,115,115,101,115,12,117,115,101,114,95,109,97,110,97,103,101,114,6,118,101,99,116,111,114,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,3,8,5,0,0,0,0,0,0,0,0,2,3,24,8,6,45,8,1,13,11,7,2,13,13,1,2,2,46,11,7,2,8,4,3,47,11,7,2,3,10,8,4,2,2,2,16,8,4,17,3,3,2,2,16,8,4,17,3,0,0,0,0,1,12,10,0,17,15,10,0,56,0,10,0,56,1,18,1,11,0,56,2,18,0,56,3,2,1,1,0,0,19,21,11,1,15,0,12,5,10,5,10,2,12,4,46,11,4,56,4,32,4,12,5,16,11,5,1,7,3,39,11,5,11,2,11,3,56,5,2,2,1,0,0,19,20,11,1,15,0,12,4,10,4,10,2,12,3,46,11,3,56,4,4,11,5,15,11,4,1,7,4,39,11,4,11,2,56,6,1,2,3,1,0,0,24,23,10,0,11,1,17,5,12,2,11,0,16,1,12,3,10,3,16,2,10,2,56,7,4,13,5,17,11,3,1,7,1,39,11,3,16,2,11,2,56,8,20,2,4,1,0,0,26,19,11,0,16,1,12,2,10,2,16,3,10,1,56,9,4,9,5,13,11,2,1,7,1,39,11,2,16,3,11,1,56,10,20,2,5,1,0,0,27,24,14,1,17,10,12,4,11,0,16,0,12,3,10,3,10,4,56,4,4,18,11,1,11,3,11,4,56,11,20,17,11,12,2,5,22,11,3,1,11,1,12,2,11,2,2,6,1,0,0,8,10,10,0,11,1,17,5,12,2,11,0,16,1,16,2,11,2,56,7,2,7,3,0,0,31,50,10,0,11,1,12,2,46,11,2,17,5,12,5,11,0,15,1,12,7,10,7,15,2,10,5,12,3,46,11,3,56,7,32,4,20,5,24,11,7,1,7,0,39,10,7,16,3,56,12,6,1,0,0,0,0,0,0,0,22,12,4,64,8,0,0,0,0,0,0,0,0,12,6,10,7,15,2,10,5,10,4,56,13,13,6,10,5,68,8,11,7,15,3,10,4,11,6,56,14,11,5,11,4,18,2,56,15,2,8,3,0,0,34,49,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,11,2,12,4,46,11,4,17,5,12,6,11,0,15,1,12,9,10,9,15,2,10,6,12,5,46,11,5,56,7,32,4,27,5,31,11,9,1,7,0,39,10,9,15,3,10,7,56,16,12,8,11,9,15,2,10,6,10,7,56,13,11,8,10,6,68,8,11,6,11,7,18,2,56,15,2,9,3,0,0,36,73,10,0,11,1,12,3,46,11,3,17,3,12,7,10,0,10,2,12,4,46,11,4,17,3,12,9,10,7,10,9,33,4,19,5,23,11,0,1,7,5,39,10,0,11,2,12,5,46,11,5,17,5,12,10,11,0,15,1,12,12,10,12,15,3,11,9,56,16,12,11,10,11,46,65,8,6,2,0,0,0,0,0,0,0,38,4,45,5,51,11,12,1,11,11,1,7,2,39,10,11,14,10,12,6,46,11,6,56,17,12,8,1,11,12,15,2,10,10,56,18,1,11,11,11,8,56,19,1,11,10,11,7,18,3,56,20,2,0,2,0,1,1,0,1,1,0,28,0,37,0,38,0,50,0],"wormhole_adapter_core":[161,28,235,11,6,0,0,0,12,1,0,46,2,46,114,3,160,1,202,1,4,234,2,18,5,252,2,140,3,7,136,6,150,10,8,158,16,96,6,254,16,30,10,156,17,68,12,224,17,166,4,13,134,22,6,15,140,22,6,0,88,0,27,0,36,0,46,0,60,0,61,0,85,0,89,1,29,1,30,1,44,1,57,1,58,1,79,1,83,1,84,1,87,2,28,2,40,2,45,2,64,2,78,2,86,0,4,12,0,0,15,3,0,0,5,3,0,0,16,3,0,0,6,3,0,0,17,3,0,0,7,3,0,1,0,12,0,2,8,7,0,3,11,0,0,5,14,12,0,6,23,12,0,7,22,12,0,8,2,8,0,9,3,12,1,0,1,11,21,4,0,12,13,12,2,7,1,12,1,13,18,2,0,15,20,2,0,16,25,7,2,1,0,0,0,17,1,7,0,18,9,12,0,19,10,7,0,20,12,0,0,21,19,12,0,22,24,0,0,0,51,0,1,0,0,69,2,1,0,0,35,3,1,0,0,73,4,1,0,0,71,4,1,0,0,74,4,1,0,0,72,4,1,0,0,66,5,6,0,0,65,7,8,0,0,67,5,6,0,0,77,9,10,0,1,47,43,44,0,4,33,24,46,0,4,34,24,42,0,4,42,33,24,0,4,43,52,24,0,4,48,1,32,0,4,49,1,32,0,5,26,47,48,0,5,76,47,48,0,6,53,49,23,0,6,68,50,1,0,7,59,40,41,0,10,39,21,1,1,3,11,56,12,13,0,12,56,12,17,2,7,12,14,63,21,1,1,12,16,32,22,23,2,1,0,16,41,1,19,2,1,0,16,52,27,1,2,1,0,16,75,29,30,2,1,0,17,56,24,25,0,18,56,14,15,0,19,56,25,26,0,19,82,26,24,0,20,62,34,35,0,20,64,36,10,0,22,81,41,24,0,25,16,28,18,26,20,27,18,29,18,23,28,30,18,23,37,23,38,3,6,8,9,7,8,24,7,8,18,0,4,6,8,9,7,8,0,13,10,2,3,6,8,9,7,8,0,13,7,6,8,9,7,8,24,7,8,0,13,15,11,14,1,8,17,6,8,13,6,7,8,24,7,8,0,6,8,7,10,2,6,8,13,7,8,18,2,8,8,10,2,8,7,8,24,7,8,0,6,8,7,10,2,7,8,10,7,8,11,6,8,13,7,8,18,4,8,8,8,8,15,10,2,11,7,8,24,7,8,0,6,8,7,7,8,10,8,8,8,8,13,3,15,11,14,1,8,17,6,8,13,1,3,3,7,8,24,7,8,18,8,15,1,7,8,18,1,8,15,2,6,8,24,7,8,18,1,8,21,2,8,20,8,12,1,11,16,2,9,0,9,1,2,13,8,22,1,11,19,2,9,0,9,1,1,8,0,1,9,0,2,6,11,19,2,9,0,9,1,6,9,0,1,1,1,10,2,1,8,20,1,8,22,3,7,11,19,2,9,0,9,1,9,0,9,1,1,8,1,2,7,11,19,2,9,0,9,1,6,9,0,2,9,0,9,1,2,8,23,10,2,1,2,3,13,15,2,3,7,8,21,14,10,2,1,8,23,4,7,8,24,11,14,1,8,17,8,23,6,8,13,1,8,5,1,8,6,3,13,10,2,8,8,6,7,8,24,6,11,19,2,13,8,22,7,11,16,2,8,20,8,12,10,2,6,8,13,7,8,18,1,8,25,4,8,8,13,2,10,2,1,6,8,7,1,13,7,8,8,15,3,13,10,2,8,8,8,8,6,8,8,8,8,3,13,2,10,2,4,7,8,10,8,8,13,15,2,15,15,2,6,8,11,8,8,2,7,8,11,8,8,3,15,8,23,10,2,5,13,3,8,8,8,8,3,6,65,112,112,67,97,112,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,9,67,111,114,101,83,116,97,116,101,12,68,101,108,101,116,101,66,114,105,100,103,101,11,68,101,108,101,116,101,79,119,110,101,114,13,68,101,108,101,116,101,83,112,101,110,100,101,114,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,13,71,111,118,101,114,110,97,110,99,101,67,97,112,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,15,80,111,111,108,77,97,110,97,103,101,114,73,110,102,111,14,82,101,103,105,115,116,101,114,66,114,105,100,103,101,13,82,101,103,105,115,116,101,114,79,119,110,101,114,15,82,101,103,105,115,116,101,114,83,112,101,110,100,101,114,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,15,85,115,101,114,77,97,110,97,103,101,114,73,110,102,111,3,86,65,65,6,86,101,99,77,97,112,13,97,100,100,95,108,105,113,117,105,100,105,116,121,11,97,112,112,95,109,97,110,97,103,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,8,99,111,110,116,97,105,110,115,22,100,101,99,111,100,101,95,100,101,112,111,115,105,116,95,112,97,121,108,111,97,100,27,100,101,99,111,100,101,95,115,101,110,100,95,109,101,115,115,97,103,101,95,112,97,121,108,111,97,100,20,100,101,108,101,116,101,95,114,101,109,111,116,101,95,98,114,105,100,103,101,12,100,111,108,97,95,97,100,100,114,101,115,115,13,100,111,108,97,95,99,104,97,105,110,95,105,100,13,100,111,108,97,95,99,111,110,116,114,97,99,116,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,26,101,110,99,111,100,101,95,109,97,110,97,103,101,95,112,111,111,108,95,112,97,121,108,111,97,100,23,101,110,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,10,103,101,116,95,97,112,112,95,105,100,23,103,101,116,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,95,116,121,112,101,25,103,101,116,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,95,116,121,112,101,2,105,100,30,105,110,105,116,105,97,108,105,122,101,95,99,97,112,95,119,105,116,104,95,103,111,118,101,114,110,97,110,99,101,6,105,110,115,101,114,116,12,105,115,95,100,111,108,97,95,117,115,101,114,29,108,101,110,100,105,110,103,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,10,112,111,111,108,95,99,111,100,101,99,12,112,111,111,108,95,109,97,110,97,103,101,114,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,19,112,117,98,108,105,99,95,115,104,97,114,101,95,111,98,106,101,99,116,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,15,114,101,99,101,105,118,101,95,100,101,112,111,115,105,116,15,114,101,99,101,105,118,101,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,21,114,101,103,105,115,116,101,114,95,100,111,108,97,95,117,115,101,114,95,105,100,22,114,101,103,105,115,116,101,114,95,114,101,109,111,116,101,95,98,114,105,100,103,101,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,19,114,101,109,111,116,101,95,100,101,108,101,116,101,95,111,119,110,101,114,21,114,101,109,111,116,101,95,100,101,108,101,116,101,95,115,112,101,110,100,101,114,21,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,111,119,110,101,114,23,114,101,109,111,116,101,95,114,101,103,105,115,116,101,114,95,115,112,101,110,100,101,114,6,114,101,109,111,118,101,16,114,101,109,111,118,101,95,108,105,113,117,105,100,105,116,121,13,115,101,110,100,95,119,105,116,104,100,114,97,119,5,115,116,97,116,101,3,115,117,105,28,115,121,115,116,101,109,95,99,111,114,101,95,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,111,95,98,121,116,101,115,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,12,117,115,101,114,95,109,97,110,97,103,101,114,3,118,97,97,7,118,101,99,95,109,97,112,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,99,111,114,101,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,24,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,22,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,95,99,104,97,105,110,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,0,2,4,50,8,15,90,8,21,31,11,16,2,8,20,8,12,70,11,19,2,13,8,22,1,2,2,92,13,91,10,2,2,2,2,92,13,91,10,2,3,2,2,37,13,38,15,4,2,2,37,13,38,15,5,2,2,37,13,38,15,6,2,2,37,13,38,15,0,1,0,0,11,18,10,2,17,24,12,5,11,1,10,2,12,4,12,3,11,5,11,3,46,11,4,17,32,11,2,56,0,56,1,18,0,56,2,2,1,1,0,0,1,23,10,1,16,0,14,2,56,3,32,4,7,5,11,11,1,1,7,1,39,11,1,15,0,10,2,10,3,17,31,17,33,56,4,11,2,11,3,18,1,56,5,2,2,1,0,0,26,22,10,1,16,0,14,2,56,3,4,6,5,10,11,1,1,7,0,39,11,1,15,0,14,2,56,6,12,3,1,11,2,11,3,17,34,18,1,56,5,2,3,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,4,1,0,0,1,2,6,0,0,0,0,0,0,0,0,39,5,1,0,0,31,22,10,3,10,4,17,17,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,35,12,7,11,1,11,5,11,7,11,6,17,36,1,11,3,11,4,18,5,56,7,2,6,1,0,0,31,22,10,3,10,4,17,16,17,14,12,8,11,2,15,1,73,0,0,0,0,11,8,17,35,12,7,11,1,11,5,11,7,11,6,17,36,1,11,3,11,4,18,6,56,8,2,7,3,0,0,39,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,22,17,37,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,8,3,0,0,45,59,11,0,10,1,16,0,11,1,15,2,11,3,11,6,11,7,17,22,17,37,17,12,12,12,1,12,11,12,10,12,14,12,13,10,2,17,11,11,11,33,4,23,5,31,11,5,1,11,4,1,11,2,1,7,2,39,11,4,10,13,11,2,17,11,11,10,77,17,18,1,12,9,10,5,10,14,12,8,46,11,8,17,20,32,4,52,11,5,10,14,17,21,5,54,11,5,1,11,13,11,14,11,9,11,12,2,9,3,0,0,39,26,11,0,10,1,16,0,11,1,15,2,11,3,11,4,11,5,17,22,17,37,17,13,12,7,1,12,6,12,8,11,2,17,11,11,6,33,4,21,5,23,7,2,39,11,8,11,7,2,10,3,0,0,51,28,11,3,10,4,11,2,17,11,11,8,17,19,1,12,11,11,6,11,7,11,4,11,5,11,11,52,17,15,12,13,11,1,15,1,73,0,0,0,0,11,13,17,35,12,12,11,0,11,9,11,12,11,10,17,36,2,0,3,0,1,0,2,0,54,0,55,0,80,0],"wormhole_adapter_pool":[161,28,235,11,6,0,0,0,12,1,0,42,2,42,92,3,134,1,142,1,4,148,2,16,5,164,2,185,2,7,221,4,171,6,8,136,11,96,6,232,11,50,10,154,12,51,12,205,12,167,2,13,244,14,10,15,254,14,2,0,71,0,29,0,30,0,37,0,52,0,72,1,23,1,24,1,35,1,48,1,49,1,64,1,66,1,67,1,69,2,21,2,33,2,36,2,54,2,63,2,68,0,10,8,0,0,11,8,0,0,12,3,0,1,3,7,0,2,9,12,1,0,1,3,6,8,0,5,17,12,0,6,1,8,0,7,2,12,1,0,1,9,16,4,0,10,8,12,2,7,1,12,1,11,13,2,0,13,15,2,0,14,19,7,2,1,0,0,0,15,0,7,0,16,4,12,0,17,5,7,0,18,7,0,0,19,14,12,0,20,18,0,0,0,41,0,1,0,0,42,2,1,0,0,58,3,1,1,0,0,59,4,5,0,0,55,6,1,1,0,1,38,36,17,0,1,39,36,37,0,2,28,25,17,1,0,2,59,29,17,0,2,70,35,1,1,0,3,22,31,1,0,4,27,17,34,0,5,50,32,33,0,8,32,11,1,1,3,9,46,0,7,0,10,46,0,22,2,7,12,12,61,11,1,1,8,13,60,8,9,0,14,34,1,16,2,1,0,14,43,20,1,2,1,0,15,46,17,18,0,16,46,13,14,0,17,46,18,19,0,18,53,26,27,0,18,54,28,5,0,20,65,33,17,0,16,10,18,15,19,15,15,21,16,23,7,11,9,11,13,38,1,7,8,12,0,5,7,8,0,13,10,2,7,8,18,7,8,12,9,7,8,1,7,8,18,11,8,1,8,11,7,11,4,1,9,0,11,8,1,9,0,13,10,2,6,8,7,7,8,12,7,7,8,1,7,8,18,11,8,1,8,11,13,10,2,6,8,7,7,8,12,1,3,7,6,8,5,7,8,18,7,8,1,7,11,4,1,9,0,10,2,6,8,7,7,8,12,1,8,9,1,6,8,12,1,5,1,8,0,1,9,0,3,7,8,12,11,13,2,13,8,16,8,15,2,6,8,18,7,8,12,1,8,15,2,13,8,16,1,11,13,2,9,0,9,1,1,10,2,1,8,14,1,8,16,3,7,11,13,2,9,0,9,1,9,0,9,1,2,8,14,8,6,1,11,10,2,9,0,9,1,1,8,1,2,8,17,10,2,5,7,11,4,1,9,0,11,8,1,9,0,13,10,2,7,8,12,3,7,8,15,14,10,2,1,8,17,4,7,8,18,11,8,1,8,11,8,17,6,8,7,3,13,10,2,7,8,12,5,3,3,8,3,8,3,13,1,6,8,5,6,7,8,18,6,11,13,2,13,8,16,7,11,10,2,8,14,8,6,10,2,6,8,7,7,8,12,1,8,19,6,13,3,8,3,8,3,3,2,5,7,11,4,1,9,0,8,3,3,8,3,7,8,12,1,6,8,3,1,13,1,8,2,7,66,121,116,101,115,51,50,5,67,108,111,99,107,4,67,111,105,110,11,68,111,108,97,65,100,100,114,101,115,115,10,69,109,105,116,116,101,114,67,97,112,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,17,71,111,118,101,114,110,97,110,99,101,71,101,110,101,115,105,115,13,77,101,115,115,97,103,101,84,105,99,107,101,116,11,79,98,106,101,99,116,84,97,98,108,101,4,80,111,111,108,11,80,111,111,108,71,101,110,101,115,105,115,9,80,111,111,108,83,116,97,116,101,17,80,111,111,108,87,105,116,104,100,114,97,119,69,118,101,110,116,3,83,85,73,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,6,97,109,111,117,110,116,7,98,121,116,101,115,51,50,20,99,104,101,99,107,95,108,97,116,101,115,116,95,118,101,114,115,105,111,110,5,99,108,111,99,107,4,99,111,105,110,13,99,111,110,115,117,109,101,100,95,118,97,97,115,7,99,114,101,97,116,111,114,23,100,101,99,111,100,101,95,119,105,116,104,100,114,97,119,95,112,97,121,108,111,97,100,7,100,101,112,111,115,105,116,12,100,111,108,97,95,97,100,100,114,101,115,115,9,100,111,108,97,95,112,111,111,108,12,100,115,116,95,99,104,97,105,110,95,105,100,4,101,109,105,116,7,101,109,105,116,116,101,114,5,101,109,112,116,121,5,101,118,101,110,116,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,103,101,110,101,115,105,115,16,103,101,116,95,100,111,108,97,95,97,100,100,114,101,115,115,17,103,101,116,95,100,111,108,97,95,99,104,97,105,110,95,105,100,2,105,100,4,105,110,105,116,10,105,110,105,116,105,97,108,105,122,101,6,105,110,115,101,114,116,7,105,115,95,105,110,105,116,14,108,101,110,100,105,110,103,95,112,111,114,116,97,108,3,110,101,119,5,110,111,110,99,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,12,112,111,111,108,95,97,100,100,114,101,115,115,10,112,111,111,108,95,99,111,100,101,99,15,112,114,101,112,97,114,101,95,109,101,115,115,97,103,101,15,112,117,98,108,105,115,104,95,109,101,115,115,97,103,101,16,114,101,99,101,105,118,101,95,119,105,116,104,100,114,97,119,8,114,101,99,101,105,118,101,114,19,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,115,12,115,101,110,100,95,100,101,112,111,115,105,116,12,115,101,110,100,95,109,101,115,115,97,103,101,6,115,101,110,100,101,114,12,115,104,97,114,101,95,111,98,106,101,99,116,15,115,111,117,114,99,101,95,99,104,97,105,110,95,105,100,5,115,116,97,116,101,3,115,117,105,12,116,97,107,101,95,112,97,121,108,111,97,100,8,116,114,97,110,115,102,101,114,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,8,119,105,116,104,100,114,97,119,21,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,112,111,111,108,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,16,119,111,114,109,104,111,108,101,95,101,109,105,116,116,101,114,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,0,0,0,0,0,0,0,0,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,3,8,4,0,0,0,0,0,0,0,0,2,3,40,8,9,26,5,44,1,1,2,4,40,8,9,73,8,15,25,11,10,2,8,14,8,6,57,11,13,2,13,8,16,2,2,6,47,3,62,13,31,13,51,10,2,56,10,2,20,3,0,0,0,0,1,9,10,0,17,14,11,0,46,17,17,9,18,0,56,0,2,1,1,4,0,12,59,10,0,16,0,20,10,4,46,17,17,33,4,9,5,17,11,3,1,11,0,1,11,4,1,7,2,39,10,0,16,1,20,32,4,23,5,31,11,3,1,11,0,1,11,4,1,7,3,39,11,3,10,4,12,5,46,11,5,17,21,12,7,56,1,12,6,13,6,11,1,11,2,17,20,17,22,56,2,10,4,17,14,11,7,11,4,56,3,11,6,18,1,56,4,8,11,0,15,1,21,2,2,3,0,0,24,20,11,3,11,4,11,5,11,6,11,8,56,5,12,10,11,0,15,2,73,0,0,0,0,11,10,17,23,12,9,11,1,11,2,11,9,11,7,17,24,1,2,3,3,0,0,24,17,11,3,11,4,11,6,17,8,12,8,11,0,15,2,73,0,0,0,0,11,8,17,23,12,7,11,1,11,2,11,7,11,5,17,24,2,4,1,4,0,30,37,11,0,17,10,11,1,10,2,16,3,11,2,15,4,11,4,11,5,10,6,17,12,17,25,17,11,1,12,7,12,10,12,9,12,8,12,11,11,3,10,10,10,7,10,9,11,6,56,6,11,8,11,11,14,9,17,6,14,9,17,5,14,10,17,5,11,7,18,2,56,7,2,0,1,0,2,1,1,1,3,1,2,0,45,0],"wormhole_adapter_verify":[161,28,235,11,6,0,0,0,10,1,0,22,2,22,54,3,76,102,4,178,1,16,5,194,1,206,1,7,144,3,135,3,8,151,6,128,1,6,151,7,30,10,181,7,6,12,187,7,205,1,0,38,1,29,2,14,2,27,2,28,2,35,2,37,3,13,3,19,3,34,3,36,0,8,12,0,1,4,7,1,0,0,2,1,8,0,3,7,4,0,4,3,12,2,7,1,12,1,5,6,2,0,6,10,7,2,1,0,0,0,7,0,7,0,8,2,7,0,9,5,12,0,10,9,0,0,0,22,0,1,0,0,12,2,3,0,0,30,4,5,0,0,32,6,3,0,0,31,7,5,0,1,20,19,13,1,0,1,24,18,10,1,0,1,26,3,14,1,0,1,33,13,14,1,0,3,25,25,26,0,4,11,27,3,2,7,12,4,15,24,10,2,7,12,6,15,9,10,2,1,0,6,21,9,11,2,1,0,10,16,16,22,0,10,17,16,12,0,10,18,16,17,0,10,30,21,5,0,12,8,13,8,8,12,7,12,6,12,5,12,11,23,10,23,2,6,11,6,2,13,8,8,6,13,1,11,1,1,8,8,2,6,11,6,2,13,8,8,6,8,10,0,4,7,8,9,6,11,6,2,13,8,8,10,2,6,8,2,1,8,10,3,7,11,4,2,8,7,8,0,6,8,10,7,8,5,6,7,8,9,6,11,6,2,13,8,8,7,11,4,2,8,7,8,0,10,2,6,8,2,7,8,5,2,13,8,8,2,6,11,6,2,9,0,9,1,6,9,0,1,1,1,6,9,1,1,8,8,1,9,0,1,11,1,1,9,0,2,11,1,1,8,8,13,1,6,8,10,1,13,1,6,11,1,1,9,0,1,7,11,1,1,9,0,3,10,2,6,8,2,8,10,3,6,8,9,10,2,6,8,2,1,8,7,2,8,7,8,0,2,6,11,4,2,9,0,9,1,9,0,1,7,8,5,1,8,3,3,7,11,4,2,9,0,9,1,9,0,9,1,7,66,121,116,101,115,51,50,5,67,108,111,99,107,15,69,120,116,101,114,110,97,108,65,100,100,114,101,115,115,11,79,98,106,101,99,116,84,97,98,108,101,6,79,112,116,105,111,110,5,83,116,97,116,101,9,84,120,67,111,110,116,101,120,116,3,85,73,68,4,85,110,105,116,3,86,65,65,6,86,101,99,77,97,112,3,97,100,100,20,97,115,115,101,114,116,95,107,110,111,119,110,95,101,109,105,116,116,101,114,7,98,121,116,101,115,51,50,5,99,108,111,99,107,8,99,111,110,116,97,105,110,115,6,100,105,103,101,115,116,15,101,109,105,116,116,101,114,95,97,100,100,114,101,115,115,13,101,109,105,116,116,101,114,95,99,104,97,105,110,16,101,120,116,101,114,110,97,108,95,97,100,100,114,101,115,115,7,101,120,116,114,97,99,116,3,103,101,116,22,103,101,116,95,114,101,103,105,115,116,101,114,101,100,95,101,109,105,116,116,101,114,2,105,100,7,105,115,95,115,111,109,101,3,110,101,119,4,110,111,110,101,6,111,98,106,101,99,116,12,111,98,106,101,99,116,95,116,97,98,108,101,6,111,112,116,105,111,110,16,112,97,114,115,101,95,97,110,100,95,118,101,114,105,102,121,31,112,97,114,115,101,95,118,101,114,105,102,121,95,97,110,100,95,114,101,112,108,97,121,95,112,114,111,116,101,99,116,14,114,101,112,108,97,121,95,112,114,111,116,101,99,116,4,115,111,109,101,5,115,116,97,116,101,10,116,120,95,99,111,110,116,101,120,116,3,118,97,97,7,118,101,99,95,109,97,112,23,119,111,114,109,104,111,108,101,95,97,100,97,112,116,101,114,95,118,101,114,105,102,121,130,105,21,248,202,109,17,89,125,254,101,153,184,170,2,164,192,139,216,211,150,116,133,82,84,160,110,232,63,231,34,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,83,6,246,78,49,43,88,23,102,53,28,7,175,121,199,47,203,28,210,81,71,21,127,220,47,138,215,109,233,163,251,106,3,8,1,0,0,0,0,0,0,0,3,8,2,0,0,0,0,0,0,0,3,8,3,0,0,0,0,0,0,0,0,2,1,23,8,3,0,1,0,0,1,19,10,0,10,1,56,0,4,11,11,0,11,1,56,1,20,56,2,12,2,5,17,11,1,1,11,0,1,56,3,12,2,11,2,2,1,1,0,0,15,25,10,1,17,16,12,3,11,0,14,3,17,0,12,2,14,2,56,4,4,11,5,15,11,1,1,7,0,39,13,2,56,5,11,1,17,15,33,4,22,5,24,7,1,39,2,2,1,0,0,20,15,11,0,11,2,11,3,12,5,12,4,46,11,4,11,5,17,17,12,6,11,1,14,6,17,1,11,6,2,3,1,0,0,22,26,10,0,10,1,17,14,12,3,46,11,3,56,6,32,4,10,5,18,11,1,1,11,2,1,11,0,1,7,2,39,11,0,11,1,17,14,11,2,17,9,18,0,56,7,2,4,1,0,0,5,12,11,0,11,1,11,3,11,4,17,2,12,6,11,2,14,6,11,5,17,3,11,6,2,0]},"type_origin_table":[{"module_name":"dola_address","struct_name":"DolaAddress","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"Pool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"DepositPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"dola_pool","struct_name":"WithdrawPool","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_verify","struct_name":"Unit","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceManagerCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"GovernanceGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version_1_0_0","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"genesis","struct_name":"Version_1_0_1","package":"0xc5b2a5049cd71586362d0c6a38e34cfaae7ea9ce6d5401a350506a15f817bf72"},{"module_name":"app_manager","struct_name":"TotalAppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"app_manager","struct_name":"AppCap","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v1","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"GovernanceInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"Proposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"CreateProposal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"governance_v2","struct_name":"ChangeState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"UserInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ReserveData","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"ScaledBalance","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_storage","struct_name":"BorrowRateFactors","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"PriceOracle","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"oracle","struct_name":"Price","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AppInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"Liquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"PoolCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"AddLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"pool_manager","struct_name":"RemoveLiquidity","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_logic","struct_name":"LendingCoreExecuteEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_storage","struct_name":"Storage","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserManagerInfo","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UserAddressCatalog","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"BindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"user_manager","struct_name":"UnbindUser","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_portal","struct_name":"SystemLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"CoreState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteBridge","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteOwner","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"RegisterSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_core","struct_name":"DeleteSpender","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"LendingCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_core_wormhole_adapter","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"system_core_wormhole_adapter","struct_name":"SystemCoreEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolGenesis","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolState","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"wormhole_adapter_pool","struct_name":"PoolWithdrawEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortal","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"RelayEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingPortalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"},{"module_name":"lending_portal","struct_name":"LendingLocalEvent","package":"0x826915f8ca6d11597dfe6599b8aa02a4c08bd8d39674855254a06ee83fe7220e"}],"linkage_table":{"0x0000000000000000000000000000000000000000000000000000000000000001":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000001","upgraded_version":2},"0x0000000000000000000000000000000000000000000000000000000000000002":{"upgraded_id":"0x0000000000000000000000000000000000000000000000000000000000000002","upgraded_version":6},"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302":{"upgraded_id":"0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302","upgraded_version":1},"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a":{"upgraded_id":"0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a","upgraded_version":1}}}},"owner":"Immutable","previous_transaction":"6B3tXa5PpoaRUQiYcytsC1M9fkfzXUc49NsWgC335qC1","storage_rebate":551022800}],"local_exec_effects":{"messageVersion":"v1","status":{"status":"success"},"executedEpoch":"55","gasUsed":{"computationCost":"820000","storageCost":"8291600","storageRebate":"7967916","nonRefundableStorageFee":"80484"},"modifiedAtVersions":[{"objectId":"0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004","sequenceNumber":"4346051"},{"objectId":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","sequenceNumber":"4346051"},{"objectId":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","sequenceNumber":"4346049"},{"objectId":"0x898dd24cc48476a7a2ff36372a443fefa53545b016feb317bb091e60e06b2e4c","sequenceNumber":"3478819"}],"sharedObjects":[{"objectId":"0x79d7106ea18373fc7542b0849d5ebefc3a9daf8b664a4f82d9b35bbd0c22042d","version":4346051,"digest":"4KddCShzYaYA2QcVbNphjberckmHf3BQQ13QxTqWzqkh"},{"objectId":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","version":4346051,"digest":"4BbiRiXkVTtkgnXwJJM1Px9u9Pw8XcTYeoi8xCAe5AiH"},{"objectId":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","version":4346049,"digest":"Hbp9rYyMyeFxfGkw6EEUfFpmVrc85NfAyTs2mE6EcxHj"}],"transactionDigest":"ozN2rhczEUC39poaeVYxMN6b6TEAjiFX7jFSQFhbKmL","mutated":[{"owner":{"AddressOwner":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497"},"reference":{"objectId":"0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004","version":4346052,"digest":"3DSxmS55mjcxjp4zni3HqxtpNBchuuEz1HkdY2cSGvx4"}},{"owner":{"Shared":{"initial_shared_version":4346051}},"reference":{"objectId":"0x39fcf4d9fe839c61b9d31616e6906883718eaddfb1e52059c8aadf23d546d934","version":4346052,"digest":"EWBifxLP1W6RnLYEFEbsq5SrqCT28VBseSN6JDeBVB4g"}},{"owner":{"Shared":{"initial_shared_version":3478819}},"reference":{"objectId":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621","version":4346052,"digest":"97QWr9zmCmV9L7WJHmG6ynSLbwtXtqaxEvJPzCw5r7ZK"}},{"owner":{"ObjectOwner":"0x42ef90066e649215e6ab91399a83e1a5467fd7cc436e8b83adb8743a0efba621"},"reference":{"objectId":"0x898dd24cc48476a7a2ff36372a443fefa53545b016feb317bb091e60e06b2e4c","version":4346052,"digest":"39Twrdee3mTpzMUiccQdE2c5qYizZGmbGHsqycnCTA2j"}}],"gasObject":{"owner":{"AddressOwner":"0x65859958bd62e30aa0571f9712962f59098d1eb29f73b091d9d71317d8e67497"},"reference":{"objectId":"0x1520bcb11fd3a4b8bc175d2e0d33dff295cede495737bd3820ff94a440549004","version":4346052,"digest":"3DSxmS55mjcxjp4zni3HqxtpNBchuuEz1HkdY2cSGvx4"}},"eventsDigest":"J8u3bJn6FAMiadwesmkYjvm5kvNMKTNJecRQ9H5cndop","dependencies":["GM7WWYHAZdtngwYNv7o7o4TZHdJKuczMv2hxjjzXFY6","5kWByxejQ95cxQ5zUCba3WyivedWBmtisRa4ZaWJuWpm","6B3tXa5PpoaRUQiYcytsC1M9fkfzXUc49NsWgC335qC1"]},"pre_exec_diag":{"loaded_child_objects":[["0x898dd24cc48476a7a2ff36372a443fefa53545b016feb317bb091e60e06b2e4c",3478819]]}} \ No newline at end of file diff --git a/crates/sui-rest-api/Cargo.toml b/crates/sui-rest-api/Cargo.toml deleted file mode 100644 index cbc2c35e2e4..00000000000 --- a/crates/sui-rest-api/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "sui-rest-api" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" -publish = false - -[dependencies] -mime = "0.3.17" -anyhow.workspace = true -axum.workspace = true -bcs.workspace = true -rand.workspace = true -reqwest.workspace = true -serde.workspace = true -serde_json.workspace = true -serde_with.workspace = true -tap.workspace = true -thiserror.workspace = true - -fastcrypto.workspace = true -sui-types.workspace = true - -[dev-dependencies] -tokio.workspace = true diff --git a/crates/sui-rest-api/src/checkpoints.rs b/crates/sui-rest-api/src/checkpoints.rs deleted file mode 100644 index 710367ca724..00000000000 --- a/crates/sui-rest-api/src/checkpoints.rs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use axum::extract::{Path, State}; -use sui_types::{ - full_checkpoint_content::CheckpointData, - messages_checkpoint::{CertifiedCheckpointSummary, CheckpointDigest, CheckpointSequenceNumber}, - storage::ReadStore, -}; -use tap::Pipe; - -use crate::{ - accept::AcceptFormat, - response::{Bcs, ResponseContent}, - Result, -}; - -pub const GET_LATEST_CHECKPOINT_PATH: &str = "/checkpoints"; -pub const GET_CHECKPOINT_PATH: &str = "/checkpoints/:checkpoint"; -pub const GET_FULL_CHECKPOINT_PATH: &str = "/checkpoints/:checkpoint/full"; - -pub async fn get_full_checkpoint( - Path(checkpoint_id): Path, - accept: AcceptFormat, - State(state): State, -) -> Result> { - match accept { - AcceptFormat::Bcs => {} - _ => return Err(anyhow::anyhow!("invalid accept type").into()), - } - - let verified_summary = match checkpoint_id { - CheckpointId::SequenceNumber(s) => state.get_checkpoint_by_sequence_number(s), - CheckpointId::Digest(d) => state.get_checkpoint_by_digest(&d), - }? - .ok_or(CheckpointNotFoundError(checkpoint_id))?; - - let checkpoint_contents = state - .get_checkpoint_contents_by_digest(&verified_summary.content_digest)? - .ok_or(CheckpointNotFoundError(checkpoint_id))?; - - let checkpoint_data = state.get_checkpoint_data(verified_summary, checkpoint_contents)?; - - Ok(Bcs(checkpoint_data)) -} - -pub async fn get_latest_checkpoint( - accept: AcceptFormat, - State(state): State, -) -> Result> { - let summary = state.get_latest_checkpoint()?.into(); - - match accept { - AcceptFormat::Json => ResponseContent::Json(summary), - AcceptFormat::Bcs => ResponseContent::Bcs(summary), - } - .pipe(Ok) -} - -pub async fn get_checkpoint( - Path(checkpoint_id): Path, - accept: AcceptFormat, - State(state): State, -) -> Result> { - let summary = match checkpoint_id { - CheckpointId::SequenceNumber(s) => state.get_checkpoint_by_sequence_number(s), - CheckpointId::Digest(d) => state.get_checkpoint_by_digest(&d), - }? - .ok_or(CheckpointNotFoundError(checkpoint_id))? - .into(); - - match accept { - AcceptFormat::Json => ResponseContent::Json(summary), - AcceptFormat::Bcs => ResponseContent::Bcs(summary), - } - .pipe(Ok) -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum CheckpointId { - SequenceNumber(CheckpointSequenceNumber), - Digest(CheckpointDigest), -} - -impl<'de> serde::Deserialize<'de> for CheckpointId { - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - let raw = String::deserialize(deserializer)?; - - if let Ok(s) = raw.parse::() { - Ok(Self::SequenceNumber(s)) - } else if let Ok(d) = raw.parse::() { - Ok(Self::Digest(d)) - } else { - Err(serde::de::Error::custom(format!( - "unrecognized checkpoint-id {raw}" - ))) - } - } -} - -impl serde::Serialize for CheckpointId { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - match self { - CheckpointId::SequenceNumber(s) => serializer.serialize_str(&s.to_string()), - CheckpointId::Digest(d) => serializer.serialize_str(&d.to_string()), - } - } -} - -#[derive(Debug)] -pub struct CheckpointNotFoundError(CheckpointId); - -impl std::fmt::Display for CheckpointNotFoundError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Checkpoint ")?; - - match self.0 { - CheckpointId::SequenceNumber(n) => write!(f, "{n}")?, - CheckpointId::Digest(d) => write!(f, "{d}")?, - } - - write!(f, " not found") - } -} - -impl std::error::Error for CheckpointNotFoundError {} - -impl From for crate::RestError { - fn from(value: CheckpointNotFoundError) -> Self { - Self::new(axum::http::StatusCode::NOT_FOUND, value.to_string()) - } -} diff --git a/crates/sui-rest-api/src/error.rs b/crates/sui-rest-api/src/error.rs deleted file mode 100644 index fab15ac95d1..00000000000 --- a/crates/sui-rest-api/src/error.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use axum::http::StatusCode; - -pub type Result = std::result::Result; - -pub struct RestError { - status: StatusCode, - message: Option, -} - -impl RestError { - pub fn new(status: StatusCode, message: String) -> Self { - Self { - status, - message: Some(message), - } - } -} - -// Tell axum how to convert `AppError` into a response. -impl axum::response::IntoResponse for RestError { - fn into_response(self) -> axum::response::Response { - match self.message { - Some(message) => (self.status, message).into_response(), - None => self.status.into_response(), - } - } -} - -impl From for RestError { - fn from(value: sui_types::storage::error::Error) -> Self { - Self { - status: StatusCode::INTERNAL_SERVER_ERROR, - message: Some(value.to_string()), - } - } -} - -impl From for RestError { - fn from(value: anyhow::Error) -> Self { - Self { - status: StatusCode::INTERNAL_SERVER_ERROR, - message: Some(value.to_string()), - } - } -} diff --git a/crates/sui-rest-api/src/lib.rs b/crates/sui-rest-api/src/lib.rs deleted file mode 100644 index 8000b794813..00000000000 --- a/crates/sui-rest-api/src/lib.rs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use axum::{routing::get, Router}; - -pub mod accept; -mod checkpoints; -mod client; -mod error; -mod health; -mod info; -mod objects; -mod response; -pub mod types; - -pub use client::Client; -pub use error::{RestError, Result}; -pub use sui_types::full_checkpoint_content::{CheckpointData, CheckpointTransaction}; -use sui_types::storage::ReadStore; - -pub const TEXT_PLAIN_UTF_8: &str = "text/plain; charset=utf-8"; -pub const APPLICATION_BCS: &str = "application/bcs"; -pub const APPLICATION_JSON: &str = "application/json"; - -#[derive(Clone)] -pub struct RestService { - store: std::sync::Arc, - chain_id: sui_types::digests::ChainIdentifier, - software_version: &'static str, -} - -impl RestService { - pub fn new( - store: std::sync::Arc, - chain_id: sui_types::digests::ChainIdentifier, - software_version: &'static str, - ) -> Self { - Self { - store, - chain_id, - software_version, - } - } - - pub fn new_without_version( - store: std::sync::Arc, - chain_id: sui_types::digests::ChainIdentifier, - ) -> Self { - Self::new(store, chain_id, "unknown") - } - - pub fn chain_id(&self) -> sui_types::digests::ChainIdentifier { - self.chain_id - } - - pub fn software_version(&self) -> &'static str { - self.software_version - } - - pub fn into_router(self) -> Router { - rest_router(self.store.clone()) - .merge( - Router::new() - .route("/", get(info::node_info)) - .with_state(self.clone()), - ) - .layer(axum::middleware::map_response_with_state( - self, - response::append_info_headers, - )) - } - - pub async fn start_service(self, socket_address: std::net::SocketAddr, base: Option) { - let mut app = self.into_router(); - - if let Some(base) = base { - app = Router::new().nest(&base, app); - } - - axum::Server::bind(&socket_address) - .serve(app.into_make_service()) - .await - .unwrap(); - } -} - -fn rest_router(state: S) -> Router -where - S: ReadStore + Clone + Send + Sync + 'static, -{ - Router::new() - .route(health::HEALTH_PATH, get(health::health::)) - .route( - checkpoints::GET_FULL_CHECKPOINT_PATH, - get(checkpoints::get_full_checkpoint::), - ) - .route( - checkpoints::GET_CHECKPOINT_PATH, - get(checkpoints::get_checkpoint::), - ) - .route( - checkpoints::GET_LATEST_CHECKPOINT_PATH, - get(checkpoints::get_latest_checkpoint::), - ) - .route(objects::GET_OBJECT_PATH, get(objects::get_object::)) - .route( - objects::GET_OBJECT_WITH_VERSION_PATH, - get(objects::get_object_with_version::), - ) - .with_state(state) -} diff --git a/crates/sui-rest-api/src/objects.rs b/crates/sui-rest-api/src/objects.rs deleted file mode 100644 index 5c76dfab99b..00000000000 --- a/crates/sui-rest-api/src/objects.rs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use axum::extract::{Path, State}; -use sui_types::{ - base_types::{ObjectID, SequenceNumber}, - object::Object, - storage::ReadStore, -}; -use tap::Pipe; - -use crate::{accept::AcceptFormat, response::ResponseContent, types::JsonObject, Result}; - -pub const GET_OBJECT_PATH: &str = "/objects/:object_id"; - -pub async fn get_object( - Path(object_id): Path, - accept: AcceptFormat, - State(state): State, -) -> Result> { - let object = state - .get_object(&object_id)? - .ok_or_else(|| ObjectNotFoundError::new(object_id))?; - - match accept { - AcceptFormat::Json => ResponseContent::Json(JsonObject::from_object(&object)), - AcceptFormat::Bcs => ResponseContent::Bcs(object), - } - .pipe(Ok) -} - -pub const GET_OBJECT_WITH_VERSION_PATH: &str = "/objects/:object_id/version/:version"; - -pub async fn get_object_with_version( - Path((object_id, version)): Path<(ObjectID, SequenceNumber)>, - accept: AcceptFormat, - State(state): State, -) -> Result> { - let object = state - .get_object_by_key(&object_id, version)? - .ok_or_else(|| ObjectNotFoundError::new_with_version(object_id, version))?; - - match accept { - AcceptFormat::Json => ResponseContent::Json(JsonObject::from_object(&object)), - AcceptFormat::Bcs => ResponseContent::Bcs(object), - } - .pipe(Ok) -} - -#[derive(Debug)] -pub struct ObjectNotFoundError { - object_id: ObjectID, - version: Option, -} - -impl ObjectNotFoundError { - pub fn new(object_id: ObjectID) -> Self { - Self { - object_id, - version: None, - } - } - - pub fn new_with_version(object_id: ObjectID, version: SequenceNumber) -> Self { - Self { - object_id, - version: Some(version), - } - } -} - -impl std::fmt::Display for ObjectNotFoundError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Object {}", self.object_id)?; - - if let Some(version) = self.version { - write!(f, " with version {version}")?; - } - - write!(f, " not found") - } -} - -impl std::error::Error for ObjectNotFoundError {} - -impl From for crate::RestError { - fn from(value: ObjectNotFoundError) -> Self { - Self::new(axum::http::StatusCode::NOT_FOUND, value.to_string()) - } -} diff --git a/crates/sui-rest-api/src/response.rs b/crates/sui-rest-api/src/response.rs deleted file mode 100644 index 20317beea75..00000000000 --- a/crates/sui-rest-api/src/response.rs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use axum::{ - extract::State, - http::HeaderMap, - response::{IntoResponse, Response}, -}; -use reqwest::StatusCode; - -use crate::{ - types::{ - X_SUI_CHAIN_ID, X_SUI_CHECKPOINT_HEIGHT, X_SUI_EPOCH, X_SUI_OLDEST_CHECKPOINT_HEIGHT, - X_SUI_TIMESTAMP_MS, - }, - RestService, APPLICATION_BCS, TEXT_PLAIN_UTF_8, -}; - -pub struct Bcs(pub T); - -pub enum ResponseContent { - Bcs(T), - Json(J), -} - -impl axum::response::IntoResponse for Bcs -where - T: serde::Serialize, -{ - fn into_response(self) -> axum::response::Response { - match bcs::to_bytes(&self.0) { - Ok(buf) => ( - [( - axum::http::header::CONTENT_TYPE, - axum::http::HeaderValue::from_static(APPLICATION_BCS), - )], - buf, - ) - .into_response(), - Err(err) => ( - StatusCode::INTERNAL_SERVER_ERROR, - [( - axum::http::header::CONTENT_TYPE, - axum::http::HeaderValue::from_static(TEXT_PLAIN_UTF_8), - )], - err.to_string(), - ) - .into_response(), - } - } -} - -impl axum::response::IntoResponse for ResponseContent -where - T: serde::Serialize, - J: serde::Serialize, -{ - fn into_response(self) -> axum::response::Response { - match self { - ResponseContent::Bcs(inner) => Bcs(inner).into_response(), - ResponseContent::Json(inner) => axum::Json(inner).into_response(), - } - } -} - -pub async fn append_info_headers( - State(state): State, - response: Response, -) -> impl IntoResponse { - let latest_checkpoint = state.store.get_latest_checkpoint().unwrap(); - let oldest_checkpoint = state.store.get_lowest_available_checkpoint().unwrap(); - - let mut headers = HeaderMap::new(); - - headers.insert( - X_SUI_CHAIN_ID, - state.chain_id().to_string().try_into().unwrap(), - ); - headers.insert( - X_SUI_EPOCH, - latest_checkpoint.epoch().to_string().try_into().unwrap(), - ); - headers.insert( - X_SUI_CHECKPOINT_HEIGHT, - latest_checkpoint - .sequence_number() - .to_string() - .try_into() - .unwrap(), - ); - headers.insert( - X_SUI_TIMESTAMP_MS, - latest_checkpoint - .timestamp_ms - .to_string() - .try_into() - .unwrap(), - ); - headers.insert( - X_SUI_OLDEST_CHECKPOINT_HEIGHT, - oldest_checkpoint.to_string().try_into().unwrap(), - ); - - (headers, response) -} diff --git a/crates/sui-rest-api/src/types.rs b/crates/sui-rest-api/src/types.rs deleted file mode 100644 index 014b170aba3..00000000000 --- a/crates/sui-rest-api/src/types.rs +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use fastcrypto::encoding::Base64; -pub use fastcrypto::traits::KeyPair as KeypairTraits; -use serde::{Deserialize, Serialize}; -use serde_with::{serde_as, DisplayFromStr}; -use sui_types::{ - base_types::{ObjectID, ObjectType}, - digests::{ObjectDigest, TransactionDigest}, - move_package::{TypeOrigin, UpgradeInfo}, - object::{Object, Owner}, - sui_serde::BigInt, -}; - -#[serde_as] -#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] -pub struct JsonObject { - pub object_id: ObjectID, - /// Object version. - #[serde_as(as = "BigInt")] - pub version: u64, - /// Base64 string representing the object digest - pub digest: ObjectDigest, - // Default to be None because otherwise it will be repeated for the getOwnedObjects endpoint - /// The owner of this object. - pub owner: Owner, - /// The digest of the transaction that created or last mutated this object. - /// Default to be None unless SuiObjectDataOptions. - /// showPreviousTransaction is set to true - pub previous_transaction: TransactionDigest, - /// The amount of SUI we would rebate if this object gets deleted. - /// This number is re-calculated each time the object is mutated based on - /// the present storage gas price. - #[serde_as(as = "BigInt")] - pub storage_rebate: u64, - - /// The type of the object - #[serde_as(as = "DisplayFromStr")] - #[serde(rename = "type")] - pub type_: ObjectType, - /// Move object content or package content - pub data: JsonObjectData, -} - -#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum JsonObjectData { - Move(JsonMoveObject), - Package(JsonPackage), -} - -#[serde_as] -#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] -pub struct JsonPackage { - // TODO do we want to dissasemble this? - #[serde_as(as = "BTreeMap<_, Base64>")] - module_map: BTreeMap>, - - /// Maps struct/module to a package version where it was first defined, - /// stored as a vector for simple serialization and deserialization. - type_origin_table: Vec, - - // For each dependency, maps original package ID to the info about the (upgraded) dependency - // version that this package is using - linkage_table: BTreeMap, -} - -#[serde_as] -#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] -#[serde(rename_all = "kebab-case")] -pub struct JsonMoveObject { - /// DEPRECATED this field is no longer used to determine whether a tx can - /// transfer this object. Instead, it is always calculated from the - /// objects type when loaded in execution - has_public_transfer: bool, - - // TODO Do we want to spend the effort to render this? - // Move Struct rendered with type info - // fields: BTreeMap, - #[serde_as(as = "Base64")] - pub content: Vec, -} - -impl JsonObject { - pub fn from_object(object: &Object) -> Self { - let (type_, object_data) = match &object.data { - sui_types::object::Data::Move(struct_) => { - let s = JsonMoveObject { - has_public_transfer: struct_.has_public_transfer(), - content: struct_.contents().to_vec(), - }; - - ( - ObjectType::Struct(struct_.type_().clone()), - JsonObjectData::Move(s), - ) - } - sui_types::object::Data::Package(package) => { - let pkg = JsonPackage { - module_map: package.serialized_module_map().clone(), - type_origin_table: package.type_origin_table().clone(), - linkage_table: package.linkage_table().clone(), - }; - - (ObjectType::Package, JsonObjectData::Package(pkg)) - } - }; - - let version = object.version().value(); - let object_id = object.id(); - - Self { - object_id, - version, - digest: object.digest(), - owner: object.owner, - previous_transaction: object.previous_transaction, - storage_rebate: object.storage_rebate, - type_, - data: object_data, - } - } -} - -/// Chain ID of the current chain -pub const X_SUI_CHAIN_ID: &str = "x-sui-chain-id"; - -/// Current checkpoint height -pub const X_SUI_CHECKPOINT_HEIGHT: &str = "x-sui-checkpoint-height"; - -/// Oldest non-pruned checkpoint height -pub const X_SUI_OLDEST_CHECKPOINT_HEIGHT: &str = "x-sui-oldest-checkpoint-height"; - -/// Current epoch of the chain -pub const X_SUI_EPOCH: &str = "x-sui-epoch"; - -/// Cursor to be used for endpoints that support cursor-based pagination. Pass -/// this to the start field of the endpoint on the next call to get the next -/// page of results. -pub const X_SUI_CURSOR: &str = "x-sui-cursor"; - -/// Current timestamp of the chain - represented as number of milliseconds from -/// the Unix epoch -pub const X_SUI_TIMESTAMP_MS: &str = "x-sui-timestamp-ms"; diff --git a/crates/sui-rosetta/Cargo.toml b/crates/sui-rosetta/Cargo.toml deleted file mode 100644 index 78261ab4d81..00000000000 --- a/crates/sui-rosetta/Cargo.toml +++ /dev/null @@ -1,51 +0,0 @@ -[package] -name = "sui-rosetta" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -axum.workspace = true -axum-extra.workspace = true -anyhow.workspace = true -tracing.workspace = true -serde.workspace = true -serde_json.workspace = true -tokio.workspace = true -futures.workspace = true -once_cell.workspace = true -signature.workspace = true -bcs.workspace = true -hyper.workspace = true -strum.workspace = true -strum_macros.workspace = true -async-trait.workspace = true -clap.workspace = true -thiserror.workspace = true -eyre.workspace = true -typed-store.workspace = true -tempfile.workspace = true -fastcrypto.workspace = true -sui-swarm-config.workspace = true -sui-types.workspace = true -sui-sdk.workspace = true -sui-node.workspace = true -sui-config.workspace = true -sui-keys.workspace = true -sui-json-rpc-types.workspace = true -mysten-metrics.workspace = true -shared-crypto.workspace = true - -move-core-types.workspace = true - -telemetry-subscribers.workspace = true - -[dev-dependencies] -sui-sdk.workspace = true -sui-move-build.workspace = true -test-cluster.workspace = true -tempfile.workspace = true -rand.workspace = true -reqwest.workspace = true diff --git a/crates/sui-rosetta/README.md b/crates/sui-rosetta/README.md deleted file mode 100644 index 78ace49be66..00000000000 --- a/crates/sui-rosetta/README.md +++ /dev/null @@ -1,213 +0,0 @@ -# Rosetta API for Sui - -[Rosetta](https://www.rosetta-api.org/docs/welcome.html) is an open-source specification and set of tools for blockchain -integration. Rosetta’s goal is to make blockchain integration simpler, faster, and more reliable than using a native -integration. - -## Overview - -Sui-Rosetta is an implementation of the Rosetta API for the Sui network, the Sui-Rosetta server uses the Sui fullnode to -read and write transactions to the Sui network. - -## Local network quick start - -### Build from source -#### 0. Checkout and build Sui -Checkout the [Sui source code](https://github.com/MystenLabs/sui) and compile using `cargo build --release`, the binaries will be located in `target/release` directory. - -#### 1. Genesis - -`./sui genesis -f` -The Sui genesis process will create configs and coins for testing, the config files are stored in `~/.sui/sui_config` by -default. - -#### 2. Start local network - -`./sui start` - -#### 3. Start Rosetta Online server - -`./sui-rosetta start-online-server` - -#### 4. Start Rosetta Offline server - -`./sui-rosetta start-offline-server` - -#### 5. Generate configuration with prefunded accounts for rosetta-cli - -`./sui-rosetta generate-rosetta-cli-config` -This will generate the `rosetta-cli.json` and `sui.ros` file to be used by the [Rosetta-CLI](https://github.com/coinbase/rosetta-cli) - -### Build local test network using Docker Compose - -#### 1. CD into the Dockerfile directory - -```shell -cd /crate/sui-rosetta/docker/sui-rosetta-local -``` -#### 2. Build the image -```shell -./build.sh -``` -#### 3. Start the container - -```shell -docker-compose up -d -``` -Docker compose will start the rosetta-online and rosetta-offline containers, the ports for both rosetta server (9002, 9003 respectively) will be exposed to the host. - -#### 4. Enter the rosetta service shell - -```shell -docker-compose exec rosetta-online bash -``` - -#### 5. use the rosetta-cli to test the api -```shell -rosetta-cli --configuration-file rosetta-cli.json check:data -rosetta-cli --configuration-file rosetta-cli.json check:construction -``` - -### Start Rosetta servers using docker run -you can also start the individual server using docker run. -To start the rosetta-online server, run -```shell -docker run mysten/sui-rosetta-devnet sui-rosetta start-online-server -``` -Alternatively, to start the rosetta-offline server, run -```shell -docker run mysten/sui-rosetta-devnet sui-rosetta start-offline-server -``` - -## Supported APIs - -### Account - -| Method | Endpoint | Description | Sui Supported? | Server Type | -|--------|------------------|--------------------------------|:--------------:|:-------------:| -| POST | /account/balance | Get an Account's Balance | Yes | Online | -| POST | /account/coins | Get an Account's Unspent Coins | Yes | Online | - -### Block - -| Method | Endpoint | Description | Sui Supported? | Server Type | -|--------|--------------------|-------------------------|:-----------------------------------------------------------------------------------------:|:-------------:| -| POST | /block | Get a Block | Yes (One transaction per block in phase 1, will be replaced by Sui checkpoint in phase 2) | Online | -| POST | /block/transaction | Get a Block Transaction | Yes | Online | - -### Call - -| Method | Endpoint | Description | Sui Supported? | Server Type | -|--------|----------|----------------------------------------|:--------------:|:-----------:| -| POST | /call | Make a Network-Specific Procedure Call | No | -- | - -### Construction - -| Method | Endpoint | Description | Sui Supported? | Server Type | -|--------|--------------------------|-------------------------------------------------------|:--------------:|:-----------:| -| POST | /construction/combine | Create Network Transaction from Signatures | Yes | Offline | -| POST | /construction/derive | Derive an AccountIdentifier from a PublicKey | Yes | Offline | -| POST | /construction/hash | Get the Hash of a Signed Transaction | Yes | Offline | -| POST | /construction/metadata | Get Metadata for Transaction Construction | Yes | Online | -| POST | /construction/parse | Parse a Transaction | Yes | Offline | -| POST | /construction/payloads | Generate an Unsigned Transaction and Signing Payloads | Yes | Offline | -| POST | /construction/preprocess | Create a Request to Fetch Metadata | Yes | Offline | -| POST | /construction/submit | Submit a Signed Transaction | Yes | Online | - -### Events - -| Method | Endpoint | Description | Sui Supported? | Server Type | -|--------|----------------|--------------------------------------|:--------------:|:-----------:| -| POST | /events/blocks | [INDEXER] Get a range of BlockEvents | No | -- | - -### Mempool - -| Method | Endpoint | Description | Sui Supported? | Server Type | -|--------|----------------------|------------------------------|:--------------:|:-----------:| -| POST | /mempool | Get All Mempool Transactions | No | -- | -| POST | /mempool/transaction | Get a Mempool Transaction | No | -- | - -### Network - -| Method | Endpoint | Description | Sui Supported? | Server Type | -|--------|------------------|--------------------------------|:--------------:|:--------------:| -| POST | /network/list | Get List of Available Networks | Yes | Online/Offline | -| POST | /network/options | Get Network Options | Yes | Online/Offline | -| POST | /network/status | Get Network Status | Yes | Online | - -### Search - -| Method | Endpoint | Description | Sui Supported? | Server Type | -|--------|----------------------|-----------------------------------|:--------------:|:-----------:| -| POST | /search/transactions | [INDEXER] Search for Transactions | No | -- | - - -## Sui transaction <> Rosetta Operation conversion explained -There are 2 places we convert Sui's transaction to Rosetta's operations, -one is in the `/construction/parse` endpoint and another one in `/block/transaction endpoint`. -`/operation/parse` uses `Operation::from_data` to create the "intent" operations and `/block/transaction` uses `Operation::from_data_and_effect` to create the "confirmed" operations. -the `/construction/parse` endpoint is used for checking transaction correctness during transaction construction, in our case we only support `TransferSui` for now, the operations created looks like this (negative amount indicate sender): -```json -{ - "operation_identifier": { - "index": 0 - }, - "type": "TransferSUI", - "account": { - "address": "0xc4173a804406a365e69dfb297d4eaaf002546ebd" - }, - "amount": { - "value": "-100000", - "currency": { - "symbol": "SUI", - "decimals": 9 - } - }, - "coin_change": { - "coin_identifier": { - "identifier": "0x0dce9190d54cde842d39537bf94efe128181b8a6:5549" - }, - "coin_action": "coin_spent" - } -}, -{ - "operation_identifier": { - "index": 1 - }, - "type": "TransferSUI", - "account": { - "address": "0x96bc0b37b67103651d1f98c67b34df9558ea527a" - }, - "amount": { - "value": "100000", - "currency": { - "symbol": "SUI", - "decimals": 9 - } - } -}, -{ - "operation_identifier": { - "index": 2 - }, - "type": "GasBudget", - "account": { - "address": "0xc4173a804406a365e69dfb297d4eaaf002546ebd" - }, - "coin_change": { - "coin_identifier": { - "identifier": "0x0dce9190d54cde842d39537bf94efe128181b8a6:5549" - }, - "coin_action": "coin_spent" - }, - "metadata": { - "budget": 1000 - } -} -``` -The sender, recipients and transfer amounts are specified in the intent operations, -these data are being used to create TransactionData for signature. -After the tx is executed, the rosetta-cli compare the intent operations with the confirmed operations , -the confirmed operations must contain the intent operations (the confirmed operations can have more operations than the intent). -Since the intent operations of TransferSui contains all the balance change information(amount field) already, -we don't need to use the event to create the operations, also operation created by `get_coin_operation_from_event` will contain recipient's coin id, which will cause a mismatch. \ No newline at end of file diff --git a/crates/sui-rosetta/docker/sui-rosetta-devnet/Dockerfile b/crates/sui-rosetta/docker/sui-rosetta-devnet/Dockerfile deleted file mode 100644 index 30d9bab3a0a..00000000000 --- a/crates/sui-rosetta/docker/sui-rosetta-devnet/Dockerfile +++ /dev/null @@ -1,31 +0,0 @@ -FROM ubuntu:latest AS chef -WORKDIR sui -ARG GIT_REVISION -ENV GIT_REVISION=$GIT_REVISION -RUN apt-get update && apt-get install -y build-essential libssl-dev pkg-config curl cmake clang git ca-certificates -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y -ENV PATH="/root/.cargo/bin:${PATH}" - -FROM chef AS builder -RUN git clone https://github.com/MystenLabs/sui . -RUN git checkout devnet - -RUN curl -sSfL https://raw.githubusercontent.com/coinbase/rosetta-cli/master/scripts/install.sh | sh -s -RUN curl -fLJO https://github.com/MystenLabs/sui-genesis/raw/main/devnet/genesis.blob -RUN cargo build --release --bin sui --bin sui-rosetta --bin sui-node - -# Production Image -FROM ubuntu:latest AS runtime -WORKDIR sui -RUN apt-get update && apt-get install -y ca-certificates -COPY --from=builder /sui/target/release/sui /usr/local/bin -COPY --from=builder /sui/target/release/sui-node /usr/local/bin -COPY --from=builder /sui/target/release/sui-rosetta /usr/local/bin -COPY --from=builder /sui/bin/rosetta-cli /usr/local/bin -COPY --from=builder /sui/crates/sui-config/data/fullnode-template.yaml /sui/devnet/fullnode.yaml -COPY --from=builder /sui/genesis.blob /sui/devnet/genesis.blob -RUN /usr/local/bin/sui genesis - -ARG BUILD_DATE -LABEL build-date=$BUILD_DATE -LABEL git-revision=$GIT_REVISION diff --git a/crates/sui-rosetta/docker/sui-rosetta-devnet/build.sh b/crates/sui-rosetta/docker/sui-rosetta-devnet/build.sh deleted file mode 100755 index 32672917516..00000000000 --- a/crates/sui-rosetta/docker/sui-rosetta-devnet/build.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -# Copyright (c) Mysten Labs, Inc. -# SPDX-License-Identifier: Apache-2.0 - -# fast fail. -set -e - -DIR="$( cd "$( dirname "$0" )" && pwd )" -REPO_ROOT="$(git rev-parse --show-toplevel)" -DOCKERFILE="$DIR/Dockerfile" -GIT_REVISION="$(git describe --always --dirty --exclude '*')" -BUILD_DATE="$(date -u +'%Y-%m-%d')" - -echo -echo "Building sui-rosetta docker image" -echo "Dockerfile: \t$DOCKERFILE" -echo "docker context: $REPO_ROOT" -echo "build date: \t$BUILD_DATE" -echo "git revision: \t$GIT_REVISION" -echo - -docker build -f "$DOCKERFILE" "$REPO_ROOT" \ - -t mysten/sui-rosetta-devnet \ - --build-arg GIT_REVISION="$GIT_REVISION" \ - --build-arg BUILD_DATE="$BUILD_DATE" \ - "$@" diff --git a/crates/sui-rosetta/docker/sui-rosetta-devnet/docker-compose.yaml b/crates/sui-rosetta/docker/sui-rosetta-devnet/docker-compose.yaml deleted file mode 100644 index 7009b117990..00000000000 --- a/crates/sui-rosetta/docker/sui-rosetta-devnet/docker-compose.yaml +++ /dev/null @@ -1,36 +0,0 @@ ---- -version: "3.9" -services: - rosetta-online: - image: mysten/sui-rosetta-devnet - ports: - - "9002:9002" - expose: - - "9002" - volumes: - - data:/data:rw - working_dir: /sui/devnet - command: - - /bin/bash - - -c - - | - /usr/local/bin/sui-rosetta generate-rosetta-cli-config --env devnet & - /usr/local/bin/sui-rosetta start-online-server --env devnet --node-config fullnode.yaml - stdin_open: true - tty: true - rosetta-offline: - image: mysten/sui-rosetta-devnet - ports: - - "9003:9003" - expose: - - "9003" - working_dir: /sui/devnet - command: - - /bin/bash - - -c - - | - /usr/local/bin/sui-rosetta start-offline-server --env devnet - stdin_open: true - tty: true -volumes: - data: diff --git a/crates/sui-rosetta/docker/sui-rosetta-devnet/remote/docker-compose.yaml b/crates/sui-rosetta/docker/sui-rosetta-devnet/remote/docker-compose.yaml deleted file mode 100644 index 9b1733fbf42..00000000000 --- a/crates/sui-rosetta/docker/sui-rosetta-devnet/remote/docker-compose.yaml +++ /dev/null @@ -1,33 +0,0 @@ ---- -version: "3.9" -services: - rosetta-online: - image: mysten/sui-rosetta-devnet - ports: - - "9002:9002" - expose: - - "9002" - working_dir: /sui/devnet - command: - - /bin/bash - - -c - - | - /usr/local/bin/sui-rosetta generate-rosetta-cli-config --env devnet & - /usr/local/bin/sui-rosetta start-online-remote-server --env devnet --genesis-path genesis.blob --full-node-url https://fullnode.devnet.sui.io:443 - stdin_open: true - tty: true - rosetta-offline: - image: mysten/sui-rosetta-devnet - ports: - - "9003:9003" - expose: - - "9003" - working_dir: /sui/devnet - command: - - /bin/bash - - -c - - | - /usr/local/bin/sui-rosetta start-offline-server --env devnet - stdin_open: true - tty: true - diff --git a/crates/sui-rosetta/docker/sui-rosetta-local/Dockerfile b/crates/sui-rosetta/docker/sui-rosetta-local/Dockerfile deleted file mode 100644 index c9ab8d16c4f..00000000000 --- a/crates/sui-rosetta/docker/sui-rosetta-local/Dockerfile +++ /dev/null @@ -1,34 +0,0 @@ -FROM ubuntu:latest AS chef -WORKDIR sui -ARG GIT_REVISION -ENV GIT_REVISION=$GIT_REVISION -RUN apt-get update && apt-get install -y build-essential libssl-dev pkg-config curl cmake clang ca-certificates -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y -ENV PATH="/root/.cargo/bin:${PATH}" - -# Build application -FROM chef AS builder - -RUN curl -sSfL https://raw.githubusercontent.com/coinbase/rosetta-cli/master/scripts/install.sh | sh -s - -COPY Cargo.toml Cargo.lock ./ -COPY consensus consensus -COPY crates crates -COPY sui-execution sui-execution -COPY narwhal narwhal -COPY external-crates external-crates -RUN cargo build --release --bin sui --bin sui-rosetta - -# Production Image -FROM ubuntu:latest AS runtime -WORKDIR sui -RUN apt-get update && apt-get install -y ca-certificates -COPY --from=builder /sui/target/release/sui /usr/local/bin -COPY --from=builder /sui/target/release/sui-rosetta /usr/local/bin -COPY --from=builder /sui/bin/rosetta-cli /usr/local/bin -COPY --from=builder /sui/crates/sui-config/data/fullnode-template.yaml /sui/devnet/fullnode.yaml -RUN /usr/local/bin/sui genesis - -ARG BUILD_DATE -LABEL build-date=$BUILD_DATE -LABEL git-revision=$GIT_REVISION diff --git a/crates/sui-rosetta/docker/sui-rosetta-local/build.sh b/crates/sui-rosetta/docker/sui-rosetta-local/build.sh deleted file mode 100755 index ad005e9f747..00000000000 --- a/crates/sui-rosetta/docker/sui-rosetta-local/build.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -# Copyright (c) Mysten Labs, Inc. -# SPDX-License-Identifier: Apache-2.0 - -# fast fail. -set -e - -DIR="$( cd "$( dirname "$0" )" && pwd )" -REPO_ROOT="$(git rev-parse --show-toplevel)" -DOCKERFILE="$DIR/Dockerfile" -GIT_REVISION="$(git describe --always --dirty)" -BUILD_DATE="$(date -u +'%Y-%m-%d')" - -echo -echo "Building sui-rosetta docker image" -echo "Dockerfile: \t$DOCKERFILE" -echo "docker context: $REPO_ROOT" -echo "build date: \t$BUILD_DATE" -echo "git revision: \t$GIT_REVISION" -echo - -docker build -f "$DOCKERFILE" "$REPO_ROOT" \ - -t mysten/sui-rosetta-local \ - --build-arg GIT_REVISION="$GIT_REVISION" \ - --build-arg BUILD_DATE="$BUILD_DATE" \ - "$@" diff --git a/crates/sui-rosetta/docker/sui-rosetta-local/docker-compose.yaml b/crates/sui-rosetta/docker/sui-rosetta-local/docker-compose.yaml deleted file mode 100644 index 504bc1723d6..00000000000 --- a/crates/sui-rosetta/docker/sui-rosetta-local/docker-compose.yaml +++ /dev/null @@ -1,40 +0,0 @@ ---- -version: "3.9" -services: - sui-network: - image: mysten/sui-rosetta-local - ports: - - "9000:9000" - expose: - - "9000" - command: - - /bin/bash - - -c - - | - /usr/local/bin/sui start - rosetta-online: - image: mysten/sui-rosetta-local - ports: - - "9002:9002" - expose: - - "9002" - working_dir: /sui/localnet - command: - - /bin/bash - - -c - - | - /usr/local/bin/sui-rosetta generate-rosetta-cli-config & - /usr/local/bin/sui-rosetta start-online-remote-server --full-node-url http://sui-network:9000 - stdin_open: true - tty: true - rosetta-offline: - image: mysten/sui-rosetta-local - ports: - - "9003:9003" - expose: - - "9003" - command: - - /bin/bash - - -c - - | - /usr/local/bin/sui-rosetta start-offline-server \ No newline at end of file diff --git a/crates/sui-rosetta/resources/sui.ros b/crates/sui-rosetta/resources/sui.ros deleted file mode 100644 index 766e47f106e..00000000000 --- a/crates/sui-rosetta/resources/sui.ros +++ /dev/null @@ -1,44 +0,0 @@ -transfer(10){ - transfer{ - transfer.network = {"network":"{{sui.env}}", "blockchain":"sui"}; - currency = {"symbol":"SUI", "decimals":9}; - sender = find_balance({ - "minimum_balance":{ - "value": "100000", - "currency": {{currency}} - } - }); - recipient_amount = random_number({"minimum": "1", "maximum": "100000"}); - sender_amount = 0 - {{recipient_amount}}; - print_message({"recipient_amount":{{recipient_amount}}}); - - // Find recipient and construct operations - recipient = find_balance({ - "not_account_identifier":[{{sender.account_identifier}}], - "minimum_balance":{ - "value": "0", - "currency": {{currency}} - } - }); - transfer.confirmation_depth = "1"; - transfer.operations = [ - { - "operation_identifier":{"index":0}, - "type":"PaySui", - "account":{{recipient.account_identifier}}, - "amount":{ - "value":{{recipient_amount}}, - "currency":{{currency}} - } - }, - { - "operation_identifier":{"index":1}, - "type":"PaySui", - "account":{{sender.account_identifier}}, - "amount":{ - "value":{{sender_amount}}, - "currency":{{currency}} - } - }]; - } -} \ No newline at end of file diff --git a/crates/sui-rosetta/src/errors.rs b/crates/sui-rosetta/src/errors.rs deleted file mode 100644 index 1d5ddb042b7..00000000000 --- a/crates/sui-rosetta/src/errors.rs +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt::Debug; - -use axum::{ - extract::rejection::JsonRejection, - http::StatusCode, - response::{IntoResponse, Response}, - Json, -}; -use fastcrypto::error::FastCryptoError; -use serde::{Serialize, Serializer}; -use serde_json::{json, Value}; -use strum::{EnumProperty, IntoEnumIterator}; -use strum_macros::{Display, EnumDiscriminants, EnumIter}; -use sui_types::error::SuiError; -use thiserror::Error; -use typed_store::TypedStoreError; - -use crate::types::{BlockHash, OperationType, PublicKey, SuiEnv}; - -/// Sui-Rosetta specific error types. -/// This contains all the errors returns by the sui-rosetta server. -#[derive(Debug, Error, EnumDiscriminants, EnumProperty)] -#[strum_discriminants( - name(ErrorType), - derive(Display, EnumIter), - strum(serialize_all = "kebab-case") -)] -#[allow(clippy::enum_variant_names)] -pub enum Error { - #[error("Unsupported blockchain: {0}")] - UnsupportedBlockchain(String), - #[error("Unsupported network: {0:?}")] - UnsupportedNetwork(SuiEnv), - #[error("Invalid input: {0}")] - InvalidInput(String), - #[error("Missing input: {0}")] - MissingInput(String), - #[error("Missing metadata")] - MissingMetadata, - #[error("{0}")] - MalformedOperationError(String), - #[error("Unsupported operation: {0:?}")] - UnsupportedOperation(OperationType), - #[error("Data error: {0}")] - DataError(String), - #[error("Block not found, index: {index:?}, hash: {hash:?}")] - BlockNotFound { - index: Option, - hash: Option, - }, - #[error("Public key deserialization error: {0:?}")] - PublicKeyDeserializationError(PublicKey), - - #[error("Error executing transaction: {0}")] - TransactionExecutionError(String), - - #[error("{0}")] - TransactionDryRunError(String), - - #[error(transparent)] - InternalError(#[from] anyhow::Error), - #[error(transparent)] - BCSSerializationError(#[from] bcs::Error), - #[error(transparent)] - CryptoError(#[from] FastCryptoError), - #[error(transparent)] - SuiError(#[from] SuiError), - #[error(transparent)] - SuiRpcError(#[from] sui_sdk::error::Error), - #[error(transparent)] - EncodingError(#[from] eyre::Report), - #[error(transparent)] - DBError(#[from] TypedStoreError), - #[error(transparent)] - JsonExtractorRejection(#[from] JsonRejection), - - #[error("Retries exhausted while getting balance. try again.")] - #[strum(props(retriable = "true"))] - RetryExhausted(String), -} - -impl Serialize for ErrorType { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.json().serialize(serializer) - } -} - -trait CustomProperties { - fn retriable(&self) -> bool; -} - -impl CustomProperties for Error { - fn retriable(&self) -> bool { - matches!(self.get_str("retriable"), Some("true")) - } -} - -impl ErrorType { - fn json(&self) -> Value { - let retriable = false; - // Safe to unwrap - let error_code = ErrorType::iter().position(|e| &e == self).unwrap(); - let message = format!("{self}").replace('-', " "); - let message = message[0..1].to_uppercase() + &message[1..]; - - json![{ - "code": error_code, - "message": message, - "retriable": retriable, - }] - } -} - -impl Serialize for Error { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let type_: ErrorType = self.into(); - let mut json = type_.json(); - // Safe to unwrap, we know ErrorType must be an object. - let error = json.as_object_mut().unwrap(); - error.insert("details".into(), json!({ "error": format!("{self}") })); - error.insert("retriable".into(), json!(self.retriable())); - error.serialize(serializer) - } -} - -impl IntoResponse for Error { - fn into_response(self) -> Response { - (StatusCode::INTERNAL_SERVER_ERROR, Json(self)).into_response() - } -} diff --git a/crates/sui-rosetta/src/lib.rs b/crates/sui-rosetta/src/lib.rs deleted file mode 100644 index 89b10c2f25e..00000000000 --- a/crates/sui-rosetta/src/lib.rs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{net::SocketAddr, sync::Arc}; - -use axum::{routing::post, Extension, Router}; -use mysten_metrics::spawn_monitored_task; -use once_cell::sync::Lazy; -use sui_sdk::SuiClient; -use tokio::task::JoinHandle; -use tracing::info; - -use crate::{ - errors::Error, - state::{CheckpointBlockProvider, OnlineServerContext}, - types::{Currency, SuiEnv}, -}; - -/// This lib implements the Rosetta online and offline server defined by the [Rosetta API Spec](https://www.rosetta-api.org/docs/Reference.html) -mod account; -mod block; -mod construction; -mod errors; -mod network; -pub mod operations; -mod state; -pub mod types; - -pub static SUI: Lazy = Lazy::new(|| Currency { - symbol: "SUI".to_string(), - decimals: 9, -}); - -pub struct RosettaOnlineServer { - env: SuiEnv, - context: OnlineServerContext, -} - -impl RosettaOnlineServer { - pub fn new(env: SuiEnv, client: SuiClient) -> Self { - let blocks = Arc::new(CheckpointBlockProvider::new(client.clone())); - Self { - env, - context: OnlineServerContext::new(client, blocks), - } - } - - pub fn serve(self, addr: SocketAddr) -> JoinHandle> { - // Online endpoints - let app = Router::new() - .route("/account/balance", post(account::balance)) - .route("/account/coins", post(account::coins)) - .route("/block", post(block::block)) - .route("/block/transaction", post(block::transaction)) - .route("/construction/submit", post(construction::submit)) - .route("/construction/metadata", post(construction::metadata)) - .route("/network/status", post(network::status)) - .route("/network/list", post(network::list)) - .route("/network/options", post(network::options)) - .layer(Extension(self.env)) - .with_state(self.context); - let server = axum::Server::bind(&addr).serve(app.into_make_service()); - info!( - "Sui Rosetta online server listening on {}", - server.local_addr() - ); - spawn_monitored_task!(server) - } -} - -pub struct RosettaOfflineServer { - env: SuiEnv, -} - -impl RosettaOfflineServer { - pub fn new(env: SuiEnv) -> Self { - Self { env } - } - - pub fn serve(self, addr: SocketAddr) -> JoinHandle> { - // Online endpoints - let app = Router::new() - .route("/construction/derive", post(construction::derive)) - .route("/construction/payloads", post(construction::payloads)) - .route("/construction/combine", post(construction::combine)) - .route("/construction/preprocess", post(construction::preprocess)) - .route("/construction/hash", post(construction::hash)) - .route("/construction/parse", post(construction::parse)) - .route("/network/list", post(network::list)) - .route("/network/options", post(network::options)) - .layer(Extension(self.env)); - let server = axum::Server::bind(&addr).serve(app.into_make_service()); - info!( - "Sui Rosetta offline server listening on {}", - server.local_addr() - ); - spawn_monitored_task!(server) - } -} diff --git a/crates/sui-rosetta/src/main.rs b/crates/sui-rosetta/src/main.rs deleted file mode 100644 index 845d453d939..00000000000 --- a/crates/sui-rosetta/src/main.rs +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::BTreeMap, - fs, - fs::File, - io::BufReader, - net::SocketAddr, - path::{Path, PathBuf}, - time::Duration, -}; - -use anyhow::anyhow; -use clap::Parser; -use fastcrypto::{ - encoding::{Encoding, Hex}, - traits::EncodeDecodeBase64, -}; -use serde_json::{json, Value}; -use sui_config::{sui_config_dir, Config, NodeConfig, SUI_FULLNODE_CONFIG, SUI_KEYSTORE_FILENAME}; -use sui_node::SuiNode; -use sui_rosetta::{ - types::{CurveType, PrefundedAccount, SuiEnv}, - RosettaOfflineServer, RosettaOnlineServer, SUI, -}; -use sui_sdk::{SuiClient, SuiClientBuilder}; -use sui_types::{ - base_types::SuiAddress, - crypto::{KeypairTraits, SuiKeyPair, ToFromBytes}, -}; -use tracing::{info, log::warn}; - -#[derive(Parser)] -#[clap(name = "sui-rosetta", rename_all = "kebab-case", author, version)] -pub enum RosettaServerCommand { - GenerateRosettaCLIConfig { - #[clap(long)] - keystore_path: Option, - #[clap(long, default_value = "localnet")] - env: SuiEnv, - #[clap(long, default_value = "http://rosetta-online:9002")] - online_url: String, - #[clap(long, default_value = "http://rosetta-offline:9003")] - offline_url: String, - }, - StartOnlineRemoteServer { - #[clap(long, default_value = "localnet")] - env: SuiEnv, - #[clap(long, default_value = "0.0.0.0:9002")] - addr: SocketAddr, - #[clap(long)] - full_node_url: String, - #[clap(long, default_value = "/data")] - data_path: PathBuf, - }, - StartOnlineServer { - #[clap(long, default_value = "localnet")] - env: SuiEnv, - #[clap(long, default_value = "0.0.0.0:9002")] - addr: SocketAddr, - #[clap(long)] - node_config: Option, - #[clap(long, default_value = "/data")] - data_path: PathBuf, - }, - StartOfflineServer { - #[clap(long, default_value = "localnet")] - env: SuiEnv, - #[clap(long, default_value = "0.0.0.0:9003")] - addr: SocketAddr, - }, -} - -impl RosettaServerCommand { - async fn execute(self) -> Result<(), anyhow::Error> { - match self { - RosettaServerCommand::GenerateRosettaCLIConfig { - keystore_path, - env, - online_url, - offline_url, - } => { - let path = keystore_path - .unwrap_or_else(|| sui_config_dir().unwrap().join(SUI_KEYSTORE_FILENAME)); - - let prefunded_accounts = read_prefunded_account(&path)?; - - info!( - "Retrieved {} Sui address from keystore file {:?}", - prefunded_accounts.len(), - &path - ); - - let mut config: Value = - serde_json::from_str(include_str!("../resources/rosetta_cli.json"))?; - - config - .as_object_mut() - .unwrap() - .insert("online_url".into(), json!(online_url)); - - // Set network. - let network = config.pointer_mut("/network").ok_or_else(|| { - anyhow!("Cannot find construction config in default config file.") - })?; - network - .as_object_mut() - .unwrap() - .insert("network".into(), json!(env)); - - // Add prefunded accounts. - let construction = config.pointer_mut("/construction").ok_or_else(|| { - anyhow!("Cannot find construction config in default config file.") - })?; - - let construction = construction.as_object_mut().unwrap(); - construction.insert("prefunded_accounts".into(), json!(prefunded_accounts)); - construction.insert("offline_url".into(), json!(offline_url)); - - let config_path = PathBuf::from(".").join("rosetta_cli.json"); - fs::write(&config_path, serde_json::to_string_pretty(&config)?)?; - info!( - "Rosetta CLI configuration file is stored in {:?}", - config_path - ); - - let dsl_path = PathBuf::from(".").join("sui.ros"); - let dsl = include_str!("../resources/sui.ros"); - fs::write( - &dsl_path, - dsl.replace("{{sui.env}}", json!(env).as_str().unwrap()), - )?; - info!("Rosetta DSL file is stored in {:?}", dsl_path); - } - RosettaServerCommand::StartOfflineServer { env, addr } => { - info!("Starting Rosetta Offline Server."); - let server = RosettaOfflineServer::new(env); - server.serve(addr).await??; - } - RosettaServerCommand::StartOnlineRemoteServer { - env, - addr, - full_node_url, - data_path, - } => { - info!( - "Starting Rosetta Online Server with remove Sui full node [{full_node_url}]." - ); - let sui_client = wait_for_sui_client(full_node_url).await; - let rosetta_path = data_path.join("rosetta_db"); - info!("Rosetta db path : {rosetta_path:?}"); - let rosetta = RosettaOnlineServer::new(env, sui_client); - rosetta.serve(addr).await??; - } - - RosettaServerCommand::StartOnlineServer { - env, - addr, - node_config, - data_path, - } => { - info!("Starting Rosetta Online Server with embedded Sui full node."); - info!("Data directory path: {data_path:?}"); - - let node_config = node_config.unwrap_or_else(|| { - let path = sui_config_dir().unwrap().join(SUI_FULLNODE_CONFIG); - info!("Using default node config from {path:?}"); - path - }); - - let mut config = NodeConfig::load(&node_config)?; - config.db_path = data_path.join("sui_db"); - info!("Overriding Sui db path to : {:?}", config.db_path); - - let registry_service = - mysten_metrics::start_prometheus_server(config.metrics_address); - // Staring a full node for the rosetta server. - let rpc_address = format!("http://127.0.0.1:{}", config.json_rpc_address.port()); - let _node = SuiNode::start(config, registry_service, None).await?; - - let sui_client = wait_for_sui_client(rpc_address).await; - - let rosetta_path = data_path.join("rosetta_db"); - info!("Rosetta db path : {rosetta_path:?}"); - let rosetta = RosettaOnlineServer::new(env, sui_client); - rosetta.serve(addr).await??; - } - }; - Ok(()) - } -} - -async fn wait_for_sui_client(rpc_address: String) -> SuiClient { - loop { - match SuiClientBuilder::default() - .max_concurrent_requests(usize::MAX) - .build(&rpc_address) - .await - { - Ok(client) => return client, - Err(e) => { - warn!( - "Error connecting to Sui RPC server [{rpc_address}]: {e}, retrying in 5 seconds." - ); - tokio::time::sleep(Duration::from_millis(5000)).await; - } - } - } -} - -/// This method reads the keypairs from the Sui keystore to create the -/// PrefundedAccount objects, PrefundedAccount will be written to the -/// rosetta-cli config file for testing. -fn read_prefunded_account(path: &Path) -> Result, anyhow::Error> { - let reader = BufReader::new(File::open(path).unwrap()); - let kp_strings: Vec = serde_json::from_reader(reader).unwrap(); - let keys = kp_strings - .iter() - .map(|kpstr| { - let key = SuiKeyPair::decode_base64(kpstr); - key.map(|k| (SuiAddress::from(&k.public()), k)) - }) - .collect::, _>>() - .unwrap(); - - Ok(keys - .into_iter() - .map(|(address, key)| { - let (privkey, curve_type) = match key { - SuiKeyPair::Ed25519(k) => { - (Hex::encode(k.private().as_bytes()), CurveType::Edwards25519) - } - SuiKeyPair::Secp256k1(k) => { - (Hex::encode(k.private().as_bytes()), CurveType::Secp256k1) - } - SuiKeyPair::Secp256r1(k) => { - (Hex::encode(k.private().as_bytes()), CurveType::Secp256r1) - } - }; - PrefundedAccount { - privkey, - account_identifier: address.into(), - curve_type, - currency: SUI.clone(), - } - }) - .collect()) -} - -#[test] -fn test_read_keystore() { - use sui_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; - use sui_types::crypto::SignatureScheme; - - let temp_dir = tempfile::tempdir().unwrap(); - let path = temp_dir.path().join("sui.keystore"); - let mut ks = Keystore::from(FileBasedKeystore::new(&path).unwrap()); - let key1 = ks - .generate_and_add_new_key(SignatureScheme::ED25519, None, None, None) - .unwrap(); - let key2 = ks - .generate_and_add_new_key(SignatureScheme::Secp256k1, None, None, None) - .unwrap(); - - let accounts = read_prefunded_account(&path).unwrap(); - let acc_map = accounts - .into_iter() - .map(|acc| (acc.account_identifier.address, acc)) - .collect::>(); - - assert_eq!(2, acc_map.len()); - assert!(acc_map.contains_key(&key1.0)); - assert!(acc_map.contains_key(&key2.0)); - - let acc1 = acc_map[&key1.0].clone(); - let acc2 = acc_map[&key2.0].clone(); - - let schema1: SignatureScheme = acc1.curve_type.into(); - let schema2: SignatureScheme = acc2.curve_type.into(); - assert!(matches!(schema1, SignatureScheme::ED25519)); - assert!(matches!(schema2, SignatureScheme::Secp256k1)); -} - -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - let cmd: RosettaServerCommand = RosettaServerCommand::parse(); - - let (_guard, _) = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .init(); - - cmd.execute().await -} diff --git a/crates/sui-rosetta/src/types.rs b/crates/sui-rosetta/src/types.rs deleted file mode 100644 index 251fd2fbf64..00000000000 --- a/crates/sui-rosetta/src/types.rs +++ /dev/null @@ -1,967 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{fmt::Debug, str::FromStr}; - -use axum::{ - response::{IntoResponse, Response}, - Json, -}; -use fastcrypto::encoding::Hex; -use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer}; -use serde_json::Value; -use strum_macros::{EnumIter, EnumString}; -use sui_sdk::rpc_types::{SuiExecutionStatus, SuiTransactionBlockKind}; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress, TransactionDigest}, - crypto::{PublicKey as SuiPublicKey, SignatureScheme}, - governance::{ADD_STAKE_FUN_NAME, WITHDRAW_STAKE_FUN_NAME}, - messages_checkpoint::CheckpointDigest, - programmable_transaction_builder::ProgrammableTransactionBuilder, - sui_system_state::SUI_SYSTEM_MODULE_NAME, - transaction::{Argument, CallArg, Command, ObjectArg, TransactionData}, - SUI_SYSTEM_PACKAGE_ID, -}; - -use crate::{ - errors::{Error, ErrorType}, - operations::Operations, - SUI, -}; - -pub type BlockHeight = u64; - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct NetworkIdentifier { - pub blockchain: String, - pub network: SuiEnv, -} - -#[derive( - Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Debug, Clone, Copy, EnumString, -)] -#[strum(serialize_all = "lowercase")] -#[serde(rename_all = "lowercase")] -pub enum SuiEnv { - MainNet, - DevNet, - TestNet, - LocalNet, -} - -impl SuiEnv { - pub fn check_network_identifier( - &self, - network_identifier: &NetworkIdentifier, - ) -> Result<(), Error> { - if &network_identifier.blockchain != "sui" { - return Err(Error::UnsupportedBlockchain( - network_identifier.blockchain.clone(), - )); - } - if &network_identifier.network != self { - return Err(Error::UnsupportedNetwork(network_identifier.network)); - } - Ok(()) - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] -pub struct AccountIdentifier { - pub address: SuiAddress, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub sub_account: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] -pub struct SubAccount { - #[serde(rename = "address")] - pub account_type: SubAccountType, -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] -pub enum SubAccountType { - Stake, - PendingStake, - EstimatedReward, -} - -impl From for AccountIdentifier { - fn from(address: SuiAddress) -> Self { - AccountIdentifier { - address, - sub_account: None, - } - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] -pub struct Currency { - pub symbol: String, - pub decimals: u64, -} -#[derive(Serialize, Deserialize)] -pub struct AccountBalanceRequest { - pub network_identifier: NetworkIdentifier, - pub account_identifier: AccountIdentifier, - #[serde(default)] - pub block_identifier: PartialBlockIdentifier, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub currencies: Vec, -} -#[derive(Serialize, Deserialize, Debug)] -pub struct AccountBalanceResponse { - pub block_identifier: BlockIdentifier, - pub balances: Vec, -} - -impl IntoResponse for AccountBalanceResponse { - fn into_response(self) -> Response { - Json(self).into_response() - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, Copy)] -pub struct BlockIdentifier { - pub index: BlockHeight, - pub hash: BlockHash, -} - -pub type BlockHash = CheckpointDigest; - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] -pub struct Amount { - #[serde(with = "str_format")] - pub value: i128, - pub currency: Currency, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub metadata: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] -pub struct AmountMetadata { - pub sub_balances: Vec, -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] -pub struct SubBalance { - pub stake_id: ObjectID, - pub validator: SuiAddress, - #[serde(with = "str_format")] - pub value: i128, -} - -impl Amount { - pub fn new(value: i128) -> Self { - Self { - value, - currency: SUI.clone(), - metadata: None, - } - } - pub fn new_from_sub_balances(sub_balances: Vec) -> Self { - let value = sub_balances.iter().map(|b| b.value).sum(); - - Self { - value, - currency: SUI.clone(), - metadata: Some(AmountMetadata { sub_balances }), - } - } -} - -mod str_format { - use std::str::FromStr; - - use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; - - pub fn serialize(value: &i128, serializer: S) -> Result - where - S: Serializer, - { - value.to_string().serialize(serializer) - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - i128::from_str(&s).map_err(Error::custom) - } -} - -#[derive(Deserialize)] -pub struct AccountCoinsRequest { - pub network_identifier: NetworkIdentifier, - pub account_identifier: AccountIdentifier, - pub include_mempool: bool, -} -#[derive(Serialize)] -pub struct AccountCoinsResponse { - pub block_identifier: BlockIdentifier, - pub coins: Vec, -} -impl IntoResponse for AccountCoinsResponse { - fn into_response(self) -> Response { - Json(self).into_response() - } -} -#[derive(Serialize)] -pub struct Coin { - pub coin_identifier: CoinIdentifier, - pub amount: Amount, -} - -impl From for Coin { - fn from(coin: sui_sdk::rpc_types::Coin) -> Self { - Self { - coin_identifier: CoinIdentifier { - identifier: CoinID { - id: coin.coin_object_id, - version: coin.version, - }, - }, - amount: Amount { - value: coin.balance as i128, - currency: SUI.clone(), - metadata: None, - }, - } - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] -pub struct CoinIdentifier { - pub identifier: CoinID, -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct CoinID { - pub id: ObjectID, - pub version: SequenceNumber, -} - -impl Serialize for CoinID { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - format!("{}:{}", self.id, self.version.value()).serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for CoinID { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - - let (id, version) = s.split_at( - s.find(':') - .ok_or_else(|| D::Error::custom(format!("Malformed Coin id [{s}].")))?, - ); - let version = version.trim_start_matches(':'); - let id = ObjectID::from_hex_literal(id).map_err(D::Error::custom)?; - let version = SequenceNumber::from_u64(u64::from_str(version).map_err(D::Error::custom)?); - - Ok(Self { id, version }) - } -} - -#[test] -fn test_coin_id_serde() { - let id = ObjectID::random(); - let coin_id = CoinID { - id, - version: SequenceNumber::from_u64(10), - }; - let s = serde_json::to_string(&coin_id).unwrap(); - assert_eq!(format!("\"{}:{}\"", id, 10), s); - - let deserialized: CoinID = serde_json::from_str(&s).unwrap(); - - assert_eq!(id, deserialized.id); - assert_eq!(SequenceNumber::from_u64(10), deserialized.version) -} - -impl From for CoinID { - fn from((id, version, _): ObjectRef) -> Self { - Self { id, version } - } -} - -#[derive(Deserialize)] -pub struct MetadataRequest { - #[serde(default)] - pub metadata: Option, -} - -#[derive(Serialize)] -pub struct NetworkListResponse { - pub network_identifiers: Vec, -} - -impl IntoResponse for NetworkListResponse { - fn into_response(self) -> Response { - Json(self).into_response() - } -} - -#[derive(Deserialize)] -pub struct ConstructionDeriveRequest { - pub network_identifier: NetworkIdentifier, - pub public_key: PublicKey, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct PublicKey { - pub hex_bytes: Hex, - pub curve_type: CurveType, -} - -impl From for PublicKey { - fn from(pk: SuiPublicKey) -> Self { - match pk { - SuiPublicKey::Ed25519(k) => PublicKey { - hex_bytes: Hex::from_bytes(&k.0), - curve_type: CurveType::Edwards25519, - }, - SuiPublicKey::Secp256k1(k) => PublicKey { - hex_bytes: Hex::from_bytes(&k.0), - curve_type: CurveType::Secp256k1, - }, - SuiPublicKey::Secp256r1(k) => PublicKey { - hex_bytes: Hex::from_bytes(&k.0), - curve_type: CurveType::Secp256r1, - }, - SuiPublicKey::ZkLogin(k) => PublicKey { - hex_bytes: Hex::from_bytes(&k.0), - curve_type: CurveType::ZkLogin, // inaccurate but added for completeness. - }, - } - } -} - -impl TryInto for PublicKey { - type Error = Error; - - fn try_into(self) -> Result { - let key_bytes = self.hex_bytes.to_vec()?; - let pub_key = SuiPublicKey::try_from_bytes(self.curve_type.into(), &key_bytes)?; - Ok((&pub_key).into()) - } -} - -#[derive(Deserialize, Serialize, Copy, Clone, Debug)] -#[serde(rename_all = "lowercase")] -pub enum CurveType { - Secp256k1, - Edwards25519, - Secp256r1, - ZkLogin, -} - -impl From for SignatureScheme { - fn from(type_: CurveType) -> Self { - match type_ { - CurveType::Secp256k1 => SignatureScheme::Secp256k1, - CurveType::Edwards25519 => SignatureScheme::ED25519, - CurveType::Secp256r1 => SignatureScheme::Secp256r1, - CurveType::ZkLogin => SignatureScheme::ZkLoginAuthenticator, - } - } -} - -#[derive(Serialize)] -pub struct ConstructionDeriveResponse { - pub account_identifier: AccountIdentifier, -} - -impl IntoResponse for ConstructionDeriveResponse { - fn into_response(self) -> Response { - Json(self).into_response() - } -} - -#[derive(Serialize, Deserialize)] -pub struct ConstructionPayloadsRequest { - pub network_identifier: NetworkIdentifier, - pub operations: Operations, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub metadata: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub public_keys: Vec, -} - -#[derive(Deserialize, Serialize, Copy, Clone, Debug, EnumIter, Eq, PartialEq)] -pub enum OperationType { - // Balance changing operations from TransactionEffect - Gas, - SuiBalanceChange, - StakeReward, - StakePrinciple, - // sui-rosetta supported operation type - PaySui, - Stake, - WithdrawStake, - // All other Sui transaction types, readonly - EpochChange, - Genesis, - ConsensusCommitPrologue, - ProgrammableTransaction, - AuthenticatorStateUpdate, - RandomnessStateUpdate, - EndOfEpochTransaction, -} - -impl From<&SuiTransactionBlockKind> for OperationType { - fn from(tx: &SuiTransactionBlockKind) -> Self { - match tx { - SuiTransactionBlockKind::ChangeEpoch(_) => OperationType::EpochChange, - SuiTransactionBlockKind::Genesis(_) => OperationType::Genesis, - SuiTransactionBlockKind::ConsensusCommitPrologue(_) - | SuiTransactionBlockKind::ConsensusCommitPrologueV2(_) => { - OperationType::ConsensusCommitPrologue - } - SuiTransactionBlockKind::ProgrammableTransaction(_) => { - OperationType::ProgrammableTransaction - } - SuiTransactionBlockKind::AuthenticatorStateUpdate(_) => { - OperationType::AuthenticatorStateUpdate - } - SuiTransactionBlockKind::RandomnessStateUpdate(_) => { - OperationType::RandomnessStateUpdate - } - SuiTransactionBlockKind::EndOfEpochTransaction(_) => { - OperationType::EndOfEpochTransaction - } - } - } -} - -#[derive(Deserialize, Serialize, Clone, Debug, Default, Eq, PartialEq)] -pub struct OperationIdentifier { - index: u64, - #[serde(default, skip_serializing_if = "Option::is_none")] - network_index: Option, -} - -impl From for OperationIdentifier { - fn from(index: u64) -> Self { - OperationIdentifier { - index, - network_index: None, - } - } -} - -#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)] -pub struct CoinChange { - pub coin_identifier: CoinIdentifier, - pub coin_action: CoinAction, -} - -#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)] -#[serde(rename_all = "snake_case")] -pub enum CoinAction { - CoinCreated, - CoinSpent, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct ConstructionPayloadsResponse { - pub unsigned_transaction: Hex, - pub payloads: Vec, -} - -impl IntoResponse for ConstructionPayloadsResponse { - fn into_response(self) -> Response { - Json(self).into_response() - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct SigningPayload { - pub account_identifier: AccountIdentifier, - // Rosetta need the hex string without `0x`, cannot use fastcrypto's Hex - pub hex_bytes: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub signature_type: Option, -} - -#[derive(Deserialize, Serialize, Debug, Clone)] -#[serde(rename_all = "lowercase")] -pub enum SignatureType { - Ed25519, - Ecdsa, -} - -#[derive(Deserialize, Serialize)] -pub struct ConstructionCombineRequest { - pub network_identifier: NetworkIdentifier, - pub unsigned_transaction: Hex, - pub signatures: Vec, -} - -#[derive(Deserialize, Serialize)] -pub struct Signature { - pub signing_payload: SigningPayload, - pub public_key: PublicKey, - pub signature_type: SignatureType, - pub hex_bytes: Hex, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct ConstructionCombineResponse { - pub signed_transaction: Hex, -} - -impl IntoResponse for ConstructionCombineResponse { - fn into_response(self) -> Response { - Json(self).into_response() - } -} - -#[derive(Serialize, Deserialize)] -pub struct ConstructionSubmitRequest { - pub network_identifier: NetworkIdentifier, - pub signed_transaction: Hex, -} -#[derive(Serialize, Deserialize, Debug)] -pub struct TransactionIdentifierResponse { - pub transaction_identifier: TransactionIdentifier, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub metadata: Option, -} - -impl IntoResponse for TransactionIdentifierResponse { - fn into_response(self) -> Response { - Json(self).into_response() - } -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct TransactionIdentifier { - pub hash: TransactionDigest, -} - -#[derive(Serialize, Deserialize)] -pub struct ConstructionPreprocessRequest { - pub network_identifier: NetworkIdentifier, - pub operations: Operations, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub metadata: Option, -} - -#[derive(Serialize, Deserialize)] -pub struct PreprocessMetadata { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub budget: Option, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct ConstructionPreprocessResponse { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub options: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub required_public_keys: Vec, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct MetadataOptions { - pub internal_operation: InternalOperation, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub budget: Option, -} - -impl IntoResponse for ConstructionPreprocessResponse { - fn into_response(self) -> Response { - Json(self).into_response() - } -} -#[derive(Deserialize)] -pub struct ConstructionHashRequest { - pub network_identifier: NetworkIdentifier, - pub signed_transaction: Hex, -} - -#[derive(Serialize, Deserialize)] -pub struct ConstructionMetadataRequest { - pub network_identifier: NetworkIdentifier, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub options: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub public_keys: Vec, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct ConstructionMetadataResponse { - pub metadata: ConstructionMetadata, - #[serde(default)] - pub suggested_fee: Vec, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct ConstructionMetadata { - pub sender: SuiAddress, - pub coins: Vec, - pub objects: Vec, - pub total_coin_value: u64, - pub gas_price: u64, - pub budget: u64, -} - -impl IntoResponse for ConstructionMetadataResponse { - fn into_response(self) -> Response { - Json(self).into_response() - } -} - -#[derive(Deserialize)] -pub struct ConstructionParseRequest { - pub network_identifier: NetworkIdentifier, - pub signed: bool, - pub transaction: Hex, -} - -#[derive(Serialize)] -pub struct ConstructionParseResponse { - pub operations: Operations, - pub account_identifier_signers: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub metadata: Option, -} - -impl IntoResponse for ConstructionParseResponse { - fn into_response(self) -> Response { - Json(self).into_response() - } -} - -#[derive(Deserialize)] -pub struct NetworkRequest { - pub network_identifier: NetworkIdentifier, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub metadata: Option, -} - -#[derive(Serialize)] -pub struct NetworkStatusResponse { - pub current_block_identifier: BlockIdentifier, - pub current_block_timestamp: u64, - pub genesis_block_identifier: BlockIdentifier, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub oldest_block_identifier: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub sync_status: Option, - pub peers: Vec, -} - -impl IntoResponse for NetworkStatusResponse { - fn into_response(self) -> Response { - Json(self).into_response() - } -} - -#[derive(Serialize)] -pub struct SyncStatus { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub current_index: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub target_index: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub stage: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub synced: Option, -} -#[derive(Serialize)] -pub struct Peer { - pub peer_id: SuiAddress, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub metadata: Option, -} - -#[derive(Serialize)] -pub struct NetworkOptionsResponse { - pub version: Version, - pub allow: Allow, -} - -impl IntoResponse for NetworkOptionsResponse { - fn into_response(self) -> Response { - Json(self).into_response() - } -} - -#[derive(Serialize)] -pub struct Version { - pub rosetta_version: String, - pub node_version: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub middleware_version: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub metadata: Option, -} - -#[derive(Serialize)] -pub struct Allow { - pub operation_statuses: Vec, - pub operation_types: Vec, - pub errors: Vec, - pub historical_balance_lookup: bool, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub timestamp_start_index: Option, - pub call_methods: Vec, - pub balance_exemptions: Vec, - pub mempool_coins: bool, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub block_hash_case: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub transaction_hash_case: Option, -} - -#[derive(Copy, Clone, Deserialize, Serialize, Debug, Eq, PartialEq)] -#[serde(rename_all = "UPPERCASE")] -pub enum OperationStatus { - Success, - Failure, -} - -impl From for OperationStatus { - fn from(es: SuiExecutionStatus) -> Self { - match es { - SuiExecutionStatus::Success => OperationStatus::Success, - SuiExecutionStatus::Failure { .. } => OperationStatus::Failure, - } - } -} - -#[derive(Serialize)] -pub struct BalanceExemption { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub sub_account_address: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub currency: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub exemption_type: Option, -} - -#[derive(Serialize)] -#[serde(rename_all = "snake_case")] -#[allow(dead_code)] -pub enum ExemptionType { - GreaterOrEqual, - LessOrEqual, - Dynamic, -} - -#[derive(Serialize)] -#[serde(rename_all = "snake_case")] -#[allow(clippy::enum_variant_names, dead_code)] -pub enum Case { - UpperCase, - LowerCase, - CaseSensitive, - Null, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct Block { - pub block_identifier: BlockIdentifier, - pub parent_block_identifier: BlockIdentifier, - pub timestamp: u64, - pub transactions: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub metadata: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct Transaction { - pub transaction_identifier: TransactionIdentifier, - pub operations: Operations, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub related_transactions: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub metadata: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct RelatedTransaction { - network_identifier: NetworkIdentifier, - transaction_identifier: TransactionIdentifier, - direction: Direction, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "lowercase")] -#[allow(dead_code)] -pub enum Direction { - Forward, - Backward, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct BlockResponse { - pub block: Block, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub other_transactions: Vec, -} - -impl IntoResponse for BlockResponse { - fn into_response(self) -> Response { - Json(self).into_response() - } -} -#[derive(Serialize, Deserialize, Default, Debug)] -pub struct PartialBlockIdentifier { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub index: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub hash: Option, -} -#[derive(Deserialize)] -pub struct BlockRequest { - pub network_identifier: NetworkIdentifier, - #[serde(default)] - pub block_identifier: PartialBlockIdentifier, -} - -#[derive(Deserialize)] -pub struct BlockTransactionRequest { - pub network_identifier: NetworkIdentifier, - pub block_identifier: BlockIdentifier, - pub transaction_identifier: TransactionIdentifier, -} - -#[derive(Serialize)] -pub struct BlockTransactionResponse { - pub transaction: Transaction, -} - -impl IntoResponse for BlockTransactionResponse { - fn into_response(self) -> Response { - Json(self).into_response() - } -} - -#[derive(Serialize, Clone)] -pub struct PrefundedAccount { - pub privkey: String, - pub account_identifier: AccountIdentifier, - pub curve_type: CurveType, - pub currency: Currency, -} - -#[derive(Serialize, Deserialize, Debug)] -pub enum InternalOperation { - PaySui { - sender: SuiAddress, - recipients: Vec, - amounts: Vec, - }, - Stake { - sender: SuiAddress, - validator: SuiAddress, - amount: Option, - }, - WithdrawStake { - sender: SuiAddress, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - stake_ids: Vec, - }, -} - -impl InternalOperation { - pub fn sender(&self) -> SuiAddress { - match self { - InternalOperation::PaySui { sender, .. } - | InternalOperation::Stake { sender, .. } - | InternalOperation::WithdrawStake { sender, .. } => *sender, - } - } - /// Combine with ConstructionMetadata to form the TransactionData - pub fn try_into_data(self, metadata: ConstructionMetadata) -> Result { - let pt = match self { - Self::PaySui { - recipients, - amounts, - .. - } => { - let mut builder = ProgrammableTransactionBuilder::new(); - builder.pay_sui(recipients, amounts)?; - builder.finish() - } - InternalOperation::Stake { - validator, amount, .. - } => { - let mut builder = ProgrammableTransactionBuilder::new(); - - // [WORKAROUND] - this is a hack to work out if the staking ops is for a - // selected amount or None amount (whole wallet). if amount is - // none, validator input will be created after the system object input - let (validator, system_state, amount) = if let Some(amount) = amount { - let amount = builder.pure(amount)?; - let validator = builder.input(CallArg::Pure(bcs::to_bytes(&validator)?))?; - let state = builder.input(CallArg::SUI_SYSTEM_MUT)?; - (validator, state, amount) - } else { - let amount = builder.pure(metadata.total_coin_value - metadata.budget)?; - let state = builder.input(CallArg::SUI_SYSTEM_MUT)?; - let validator = builder.input(CallArg::Pure(bcs::to_bytes(&validator)?))?; - (validator, state, amount) - }; - let coin = builder.command(Command::SplitCoins(Argument::GasCoin, vec![amount])); - - let arguments = vec![system_state, coin, validator]; - - builder.command(Command::move_call( - SUI_SYSTEM_PACKAGE_ID, - SUI_SYSTEM_MODULE_NAME.to_owned(), - ADD_STAKE_FUN_NAME.to_owned(), - vec![], - arguments, - )); - builder.finish() - } - InternalOperation::WithdrawStake { stake_ids, .. } => { - let mut builder = ProgrammableTransactionBuilder::new(); - - for stake_id in metadata.objects { - // [WORKAROUND] - this is a hack to work out if the withdraw stake ops is for - // selected stake_ids or None (all stakes) using the index of the call args. - // if stake_ids is not empty, id input will be created after the system object - // input - let (system_state, id) = if !stake_ids.is_empty() { - let system_state = builder.input(CallArg::SUI_SYSTEM_MUT)?; - let id = builder.obj(ObjectArg::ImmOrOwnedObject(stake_id))?; - (system_state, id) - } else { - let id = builder.obj(ObjectArg::ImmOrOwnedObject(stake_id))?; - let system_state = builder.input(CallArg::SUI_SYSTEM_MUT)?; - (system_state, id) - }; - - let arguments = vec![system_state, id]; - builder.command(Command::move_call( - SUI_SYSTEM_PACKAGE_ID, - SUI_SYSTEM_MODULE_NAME.to_owned(), - WITHDRAW_STAKE_FUN_NAME.to_owned(), - vec![], - arguments, - )); - } - builder.finish() - } - }; - - Ok(TransactionData::new_programmable( - metadata.sender, - metadata.coins, - pt, - metadata.budget, - metadata.gas_price, - )) - } -} diff --git a/crates/sui-rosetta/src/unit_tests/operations_tests.rs b/crates/sui-rosetta/src/unit_tests/operations_tests.rs deleted file mode 100644 index b450a3bce04..00000000000 --- a/crates/sui-rosetta/src/unit_tests/operations_tests.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use move_core_types::annotated_value::MoveTypeLayout; -use sui_json_rpc_types::SuiCallArg; -use sui_types::{ - base_types::{ObjectDigest, ObjectID, SequenceNumber, SuiAddress}, - programmable_transaction_builder::ProgrammableTransactionBuilder, - transaction::{CallArg, TransactionData, TEST_ONLY_GAS_UNIT_FOR_TRANSFER}, -}; - -use crate::{operations::Operations, types::ConstructionMetadata}; - -#[tokio::test] -async fn test_operation_data_parsing() -> Result<(), anyhow::Error> { - let gas = ( - ObjectID::random(), - SequenceNumber::new(), - ObjectDigest::random(), - ); - - let sender = SuiAddress::random_for_testing_only(); - - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - builder - .pay_sui(vec![SuiAddress::random_for_testing_only()], vec![10000]) - .unwrap(); - builder.finish() - }; - let gas_price = 10; - let data = TransactionData::new_programmable( - sender, - vec![gas], - pt, - TEST_ONLY_GAS_UNIT_FOR_TRANSFER * gas_price, - gas_price, - ); - - let ops: Operations = data.clone().try_into()?; - let metadata = ConstructionMetadata { - sender, - coins: vec![gas], - objects: vec![], - total_coin_value: 0, - gas_price, - budget: TEST_ONLY_GAS_UNIT_FOR_TRANSFER * gas_price, - }; - let parsed_data = ops.into_internal()?.try_into_data(metadata)?; - assert_eq!(data, parsed_data); - - Ok(()) -} -#[tokio::test] -async fn test_sui_json() { - let arg1 = CallArg::Pure(bcs::to_bytes(&1000000u64).unwrap()); - let arg2 = CallArg::Pure(bcs::to_bytes(&30215u64).unwrap()); - let json1 = SuiCallArg::try_from(arg1, Some(&MoveTypeLayout::U64)).unwrap(); - let json2 = SuiCallArg::try_from(arg2, Some(&MoveTypeLayout::U64)).unwrap(); - println!("{:?}, {:?}", json1, json2); -} diff --git a/crates/sui-rpc-loadgen/Cargo.toml b/crates/sui-rpc-loadgen/Cargo.toml deleted file mode 100644 index 4047493b40f..00000000000 --- a/crates/sui-rpc-loadgen/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "sui-rpc-loadgen" -version.workspace = true -edition = "2021" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false - -[dependencies] -anyhow.workspace = true -async-trait.workspace = true -clap.workspace = true -tokio = { workspace = true, features = ["full"] } -tracing.workspace = true -serde.workspace = true -tonic.workspace = true -futures.workspace = true -dirs.workspace = true -dashmap.workspace = true -itertools.workspace = true - -shellexpand.workspace = true - -sui-types = { workspace = true, features = ["test-utils"]} -sui-keys.workspace = true -sui-sdk.workspace = true -telemetry-subscribers.workspace = true -sui-json-rpc.workspace = true -sui-json-rpc-types.workspace = true -strum.workspace = true -shared-crypto.workspace = true -serde_json.workspace = true -strum_macros.workspace = true - -[dev-dependencies] -test-cluster.workspace = true - - -[[bin]] -name = "sui-rpc-loadgen" -path = "src/main.rs" diff --git a/crates/sui-rpc-loadgen/README.md b/crates/sui-rpc-loadgen/README.md deleted file mode 100644 index 37b230b0162..00000000000 --- a/crates/sui-rpc-loadgen/README.md +++ /dev/null @@ -1,91 +0,0 @@ -# sui-rpc-loadgen: Load Generator for SUI RPC Servers - -`sui-rpc-loadgen` is a utility that facilitates the generation of read and write loads on single or multiple Sui RPC servers. Its primary functions include performance testing and data correctness verification. - -## Features - -- **Easily extendable** to support any read/write endpoint -- **Concurrent load generation** with multiple threads, making it suitable for load testing high-traffic RPC servers. -- **Cross-verifying** results across multiple RPC Servers, ensuring data consistency and accuracy. -- **Performance comparison** between vanilla Full node RPC and Enhanced Full node RPC - -## Getting Started - -Run the following command to see available commands: - -```bash -cargo run --bin sui-rpc-loadgen -- -h -``` - -To try this locally, refer to [sef](../sui-test-validator/README.md). Recommend setting `database-url` to an env variable. Note: run `RUST_LOG="consensus=off" cargo run sui-test-validator -- --with-indexer` to rebuild. - -### Example 1: Get All Checkpoints - -The following command initiates a single thread (num-threads == 1) to retrieve all checkpoints from the beginning (sequence 0) to the latest, executing the operation exactly once (repeat == 0): - -```bash -cargo run --bin sui-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9124" --num-threads 1 get-checkpoints --start 0 --repeat 0 --interval-in-ms 0 -``` - -This command is equivalent to the simplified version below: - -```bash -cargo run --bin sui-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9124" --num-threads 1 get-checkpoints -``` - -Both commands achieve the same outcome: fetching all checkpoints using one thread, without repeating the operation. - -By default, this command also verify all the transactions in the checkpoint, specify `--skip-verify-transactions` to disable fetching transactions. Note that this must used with `--skip-verify-objects` as we do need to fetch transactions to get objects for the checkpoint. - -**Note** you must put `--num-threads ` after the urls, otherwise the command will not be parsed correctly - -### Example 2: (WIP) Execute PaySui Transaction - -```bash -cargo run --bin sui-rpc-loadgen -- --urls "http://127.0.0.1:9000" --num-threads 1 pay-sui --repeat 100 -``` - -**NOTE**: right now `pay-sui` only supports 1 thread but multi-threading support can be added pretty easily by assigning different gas coins to different threads - -### Example 3: Query Transaction Blocks - -```bash -cargo run --bin sui-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9000" --num-threads 4 query-transaction-blocks --address-type from -``` - -### Multi Get Transaction Blocks -```bash -cargo run --bin sui-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9000" --num-threads 4 multi-get-transaction-blocks -``` - -### Multi Get Objects - -```bash -cargo run --bin sui-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9000" --num-threads 4 multi-get-objects -``` - -### Get Object -```bash -cargo run --bin sui-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9000" --num-threads 2 get-object --chunk-size 20 -``` - -### Get All Balances -```bash -cargo run --bin sui-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9000" --num-threads 2 get-all-balances --chunk-size 20 -``` - - -### Get Reference Gas Price -```bash -cargo run --bin sui-rpc-loadgen -- --urls "http://127.0.0.1:9000" "http://127.0.0.1:9000" --num-threads 2 get-reference-gas-price --num-chunks-per-thread 10 -``` - -# Useful commands - -```bash -cat sui-rpc-loadgen.b844f547-d354-4871-b958-1ea3fe23a0a8.log.2023-03-23 | awk '/Finished processing/{print $7}' | sort -n | uniq | awk 'BEGIN{last=0}{for(i=last+1;i<$1;i++) print i; last=$1} END{print last}' | tee missing_numbers.txt && wc -l missing_numbers.txt -``` - -Checks which checkpoints among threads have not been processed yet. The last one should be the largest checkpoint being processed. - -`wc -l missing_numbers.txt` - counts how many checkpoints to go diff --git a/crates/sui-rpc-loadgen/src/main.rs b/crates/sui-rpc-loadgen/src/main.rs deleted file mode 100644 index 68de8574824..00000000000 --- a/crates/sui-rpc-loadgen/src/main.rs +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod load_test; -mod payload; - -use std::{ - error::Error, - path::PathBuf, - time::{Duration, SystemTime, UNIX_EPOCH}, -}; - -use anyhow::Result; -use clap::Parser; -use payload::AddressQueryType; -use sui_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; -use sui_types::crypto::{EncodeDecodeBase64, SuiKeyPair}; -use tracing::info; - -use crate::{ - load_test::{LoadTest, LoadTestConfig}, - payload::{ - load_addresses_from_file, load_digests_from_file, load_objects_from_file, Command, - RpcCommandProcessor, SignerInfo, - }, -}; - -#[derive(Parser)] -#[clap( - name = "Sui RPC Load Generator", - version = "0.1", - about = "A load test application for Sui RPC" -)] -struct Opts { - // TODO(chris): support running multiple commands at once - #[clap(subcommand)] - pub command: ClapCommand, - #[clap(long, default_value_t = 1)] - pub num_threads: usize, - #[clap(long, default_value_t = true)] - pub cross_validate: bool, - #[clap(long, num_args(1..), default_value = "http://127.0.0.1:9000")] - pub urls: Vec, - /// the path to log file directory - #[clap(long, default_value = "~/.sui/sui_config/logs")] - logs_directory: String, - - #[clap(long, default_value = "~/.sui/loadgen/data")] - data_directory: String, -} - -#[derive(Parser)] -pub struct CommonOptions { - #[clap(short, long, default_value_t = 0)] - pub repeat: usize, - - #[clap(short, long, default_value_t = 0)] - pub interval_in_ms: u64, - - /// different chunks will be executed concurrently on the same thread - #[clap(long, default_value_t = 1)] - num_chunks_per_thread: usize, -} - -#[derive(Parser)] -pub enum ClapCommand { - #[clap(name = "dry-run")] - DryRun { - #[clap(flatten)] - common: CommonOptions, - }, - #[clap(name = "get-checkpoints")] - GetCheckpoints { - /// Default to start from checkpoint 0 - #[clap(short, long, default_value_t = 0)] - start: u64, - - /// inclusive, uses `getLatestCheckpointSequenceNumber` if `None` - #[clap(short, long)] - end: Option, - - #[clap(long)] - skip_verify_transactions: bool, - - #[clap(long)] - skip_verify_objects: bool, - - // Whether to record data from checkpoint - #[clap(long)] - skip_record: bool, - - #[clap(flatten)] - common: CommonOptions, - }, - #[clap(name = "pay-sui")] - PaySui { - // TODO(chris) customize recipients and amounts - #[clap(flatten)] - common: CommonOptions, - }, - #[clap(name = "query-transaction-blocks")] - QueryTransactionBlocks { - #[clap(long, ignore_case = true)] - address_type: AddressQueryType, - - #[clap(flatten)] - common: CommonOptions, - }, - #[clap(name = "multi-get-transaction-blocks")] - MultiGetTransactionBlocks { - #[clap(flatten)] - common: CommonOptions, - }, - #[clap(name = "multi-get-objects")] - MultiGetObjects { - #[clap(flatten)] - common: CommonOptions, - }, - #[clap(name = "get-object")] - GetObject { - #[clap(long)] - chunk_size: usize, - - #[clap(flatten)] - common: CommonOptions, - }, - #[clap(name = "get-all-balances")] - GetAllBalances { - #[clap(long)] - chunk_size: usize, - - #[clap(flatten)] - common: CommonOptions, - }, - #[clap(name = "get-reference-gas-price")] - GetReferenceGasPrice { - #[clap(flatten)] - common: CommonOptions, - }, -} - -fn get_keypair() -> Result { - // TODO(chris) allow pass in custom path for keystore - // Load keystore from ~/.sui/sui_config/sui.keystore - let keystore_path = get_sui_config_directory().join("sui.keystore"); - let keystore = Keystore::from(FileBasedKeystore::new(&keystore_path)?); - let active_address = keystore.addresses().pop().unwrap(); - let keypair: &SuiKeyPair = keystore.get_key(&active_address)?; - println!("using address {active_address} for signing"); - Ok(SignerInfo::new(keypair.encode_base64())) -} - -fn get_sui_config_directory() -> PathBuf { - match dirs::home_dir() { - Some(v) => v.join(".sui").join("sui_config"), - None => panic!("Cannot obtain home directory path"), - } -} - -pub fn expand_path(dir_path: &str) -> String { - shellexpand::full(&dir_path) - .map(|v| v.into_owned()) - .unwrap_or_else(|e| panic!("Failed to expand directory '{:?}': {}", dir_path, e)) -} - -fn get_log_file_path(dir_path: String) -> String { - let current_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); - let timestamp = current_time.as_secs(); - // use timestamp to signify which file is newer - let log_filename = format!("sui-rpc-loadgen.{}.log", timestamp); - - let dir_path = expand_path(&dir_path); - format!("{dir_path}/{log_filename}") -} - -#[tokio::main] -async fn main() -> Result<(), Box> { - let tracing_level = "debug"; - let network_tracing_level = "info"; - let log_filter = format!( - "{tracing_level},h2={network_tracing_level},tower={network_tracing_level},hyper={network_tracing_level},tonic::transport={network_tracing_level}" - ); - let opts = Opts::parse(); - - let log_filename = get_log_file_path(opts.logs_directory); - - // Initialize logger - let (_guard, _filter_handle) = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .with_log_level(&log_filter) - .with_log_file(&log_filename) - .init(); - - println!("Logging to {}", &log_filename); - info!("Running Load Gen with following urls {:?}", opts.urls); - - let (command, common, need_keystore) = match opts.command { - ClapCommand::DryRun { common } => (Command::new_dry_run(), common, false), - ClapCommand::PaySui { common } => (Command::new_pay_sui(), common, true), - ClapCommand::GetCheckpoints { - common, - start, - end, - skip_verify_transactions, - skip_verify_objects, - skip_record, - } => ( - Command::new_get_checkpoints( - start, - end, - !skip_verify_transactions, - !skip_verify_objects, - !skip_record, - ), - common, - false, - ), - ClapCommand::QueryTransactionBlocks { - common, - address_type, - } => { - let addresses = load_addresses_from_file(expand_path(&opts.data_directory)); - ( - Command::new_query_transaction_blocks(address_type, addresses), - common, - false, - ) - } - ClapCommand::MultiGetTransactionBlocks { common } => { - let digests = load_digests_from_file(expand_path(&opts.data_directory)); - ( - Command::new_multi_get_transaction_blocks(digests), - common, - false, - ) - } - ClapCommand::GetAllBalances { common, chunk_size } => { - let addresses = load_addresses_from_file(expand_path(&opts.data_directory)); - ( - Command::new_get_all_balances(addresses, chunk_size), - common, - false, - ) - } - ClapCommand::MultiGetObjects { common } => { - let objects = load_objects_from_file(expand_path(&opts.data_directory)); - (Command::new_multi_get_objects(objects), common, false) - } - ClapCommand::GetReferenceGasPrice { common } => { - let num_repeats = common.num_chunks_per_thread; - ( - Command::new_get_reference_gas_price(num_repeats), - common, - false, - ) - } - ClapCommand::GetObject { common, chunk_size } => { - let objects = load_objects_from_file(expand_path(&opts.data_directory)); - (Command::new_get_object(objects, chunk_size), common, false) - } - }; - - let signer_info = need_keystore.then_some(get_keypair()?); - - let command = command - .with_repeat_interval(Duration::from_millis(common.interval_in_ms)) - .with_repeat_n_times(common.repeat); - - let processor = RpcCommandProcessor::new(&opts.urls, expand_path(&opts.data_directory)).await; - - let load_test = LoadTest { - processor, - config: LoadTestConfig { - command, - num_threads: opts.num_threads, - // TODO: pass in from config - divide_tasks: true, - signer_info, - num_chunks_per_thread: common.num_chunks_per_thread, - max_repeat: common.repeat, - }, - }; - load_test.run().await?; - - Ok(()) -} diff --git a/crates/sui-rpc-loadgen/src/payload/mod.rs b/crates/sui-rpc-loadgen/src/payload/mod.rs deleted file mode 100644 index 5c506f7e544..00000000000 --- a/crates/sui-rpc-loadgen/src/payload/mod.rs +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod checkpoint_utils; -mod get_all_balances; -mod get_checkpoints; -mod get_object; -mod get_reference_gas_price; -mod multi_get_objects; -mod multi_get_transaction_blocks; -mod pay_sui; -mod query_transactions; -mod rpc_command_processor; -mod validation; -use core::default::Default; -use std::time::Duration; - -use anyhow::Result; -use async_trait::async_trait; -pub use rpc_command_processor::{ - load_addresses_from_file, load_digests_from_file, load_objects_from_file, RpcCommandProcessor, -}; -use strum_macros::EnumString; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, - digests::TransactionDigest, - messages_checkpoint::CheckpointSequenceNumber, -}; - -use crate::load_test::LoadTestConfig; - -#[derive(Default, Clone)] -pub struct SignerInfo { - pub encoded_keypair: String, - /// Different thread should use different gas_payment to avoid equivocation - pub gas_payment: Option>, - pub gas_budget: Option, -} - -impl SignerInfo { - pub fn new(encoded_keypair: String) -> Self { - Self { - encoded_keypair, - gas_payment: None, - gas_budget: None, - } - } -} - -#[derive(Clone, Default)] -pub struct Payload { - pub commands: Vec, - pub signer_info: Option, -} - -#[derive(Default, Clone)] -pub struct Command { - pub data: CommandData, - /// 0 means the command will be run once. Default to be 0 - pub repeat_n_times: usize, - /// how long to wait between the start of two subsequent repeats - /// If the previous command takes longer than `repeat_interval` to finish, - /// the next command will run as soon as the previous command finishes - /// Default to be 0 - pub repeat_interval: Duration, -} - -impl Command { - pub fn new_dry_run() -> Self { - Self { - data: CommandData::DryRun(DryRun {}), - ..Default::default() - } - } - - pub fn new_pay_sui() -> Self { - Self { - data: CommandData::PaySui(PaySui {}), - ..Default::default() - } - } - - pub fn new_get_checkpoints( - start: CheckpointSequenceNumber, - end: Option, - verify_transactions: bool, - verify_objects: bool, - record: bool, - ) -> Self { - Self { - data: CommandData::GetCheckpoints(GetCheckpoints { - start, - end, - verify_transactions, - verify_objects, - record, - }), - ..Default::default() - } - } - - pub fn new_query_transaction_blocks( - address_type: AddressQueryType, - addresses: Vec, - ) -> Self { - let query_transactions = QueryTransactionBlocks { - address_type, - addresses, - }; - Self { - data: CommandData::QueryTransactionBlocks(query_transactions), - ..Default::default() - } - } - - pub fn new_multi_get_transaction_blocks(digests: Vec) -> Self { - let multi_get_transaction_blocks = MultiGetTransactionBlocks { digests }; - Self { - data: CommandData::MultiGetTransactionBlocks(multi_get_transaction_blocks), - ..Default::default() - } - } - - pub fn new_multi_get_objects(object_ids: Vec) -> Self { - let multi_get_objects = MultiGetObjects { object_ids }; - Self { - data: CommandData::MultiGetObjects(multi_get_objects), - ..Default::default() - } - } - - pub fn new_get_object(object_ids: Vec, chunk_size: usize) -> Self { - let get_object = GetObject { - object_ids, - chunk_size, - }; - Self { - data: CommandData::GetObject(get_object), - ..Default::default() - } - } - - pub fn new_get_all_balances(addresses: Vec, chunk_size: usize) -> Self { - let get_all_balances = GetAllBalances { - addresses, - chunk_size, - }; - Self { - data: CommandData::GetAllBalances(get_all_balances), - ..Default::default() - } - } - - pub fn new_get_reference_gas_price(num_repeats: usize) -> Self { - let get_reference_gas_price = GetReferenceGasPrice { num_repeats }; - Self { - data: CommandData::GetReferenceGasPrice(get_reference_gas_price), - ..Default::default() - } - } - - pub fn with_repeat_n_times(mut self, num: usize) -> Self { - self.repeat_n_times = num; - self - } - - pub fn with_repeat_interval(mut self, duration: Duration) -> Self { - self.repeat_interval = duration; - self - } -} - -#[derive(Clone)] -#[allow(dead_code)] -pub enum CommandData { - DryRun(DryRun), - GetCheckpoints(GetCheckpoints), - PaySui(PaySui), - QueryTransactionBlocks(QueryTransactionBlocks), - MultiGetTransactionBlocks(MultiGetTransactionBlocks), - MultiGetObjects(MultiGetObjects), - GetObject(GetObject), - GetAllBalances(GetAllBalances), - GetReferenceGasPrice(GetReferenceGasPrice), -} - -impl Default for CommandData { - fn default() -> Self { - CommandData::DryRun(DryRun {}) - } -} - -#[derive(Clone)] -pub struct DryRun {} - -#[derive(Clone, Default)] -pub struct GetCheckpoints { - /// Default to start from 0 - pub start: CheckpointSequenceNumber, - /// If None, use `getLatestCheckpointSequenceNumber` - pub end: Option, - pub verify_transactions: bool, - pub verify_objects: bool, - pub record: bool, -} - -#[derive(Clone)] -pub struct PaySui {} - -#[derive(Clone, Default)] -pub struct QueryTransactionBlocks { - pub address_type: AddressQueryType, - pub addresses: Vec, -} - -#[derive(Clone)] -pub struct MultiGetTransactionBlocks { - pub digests: Vec, -} - -#[derive(Clone, EnumString, Default)] -#[strum(serialize_all = "lowercase")] -pub enum AddressQueryType { - #[default] - From, - To, - Both, -} - -#[derive(Clone)] -pub struct MultiGetObjects { - pub object_ids: Vec, -} - -#[derive(Clone)] -pub struct GetObject { - pub object_ids: Vec, - pub chunk_size: usize, -} - -#[derive(Clone)] -pub struct GetAllBalances { - pub addresses: Vec, - pub chunk_size: usize, -} - -#[derive(Clone)] -pub struct GetReferenceGasPrice { - num_repeats: usize, -} - -#[async_trait] -pub trait Processor { - /// process commands in order - async fn apply(&self, payload: &Payload) -> Result<()>; - - /// prepare payload for each thread according to LoadTestConfig - async fn prepare(&self, config: &LoadTestConfig) -> Result>; - - /// write results to file based on LoadTestConfig - fn dump_cache_to_file(&self, config: &LoadTestConfig); -} - -/// all payload should implement this trait -#[async_trait] -pub trait ProcessPayload<'a, T> { - async fn process(&'a self, op: T, signer_info: &Option) -> Result<()>; -} diff --git a/crates/sui-rpc-loadgen/src/payload/pay_sui.rs b/crates/sui-rpc-loadgen/src/payload/pay_sui.rs deleted file mode 100644 index 769f16fb4af..00000000000 --- a/crates/sui-rpc-loadgen/src/payload/pay_sui.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use async_trait::async_trait; -use futures::future::join_all; -use sui_types::{ - base_types::SuiAddress, - crypto::{EncodeDecodeBase64, SuiKeyPair}, - quorum_driver_types::ExecuteTransactionRequestType, - transaction::TransactionData, -}; -use tracing::debug; - -use crate::payload::{ - rpc_command_processor::DEFAULT_GAS_BUDGET, PaySui, ProcessPayload, RpcCommandProcessor, - SignerInfo, -}; - -#[async_trait] -impl<'a> ProcessPayload<'a, &'a PaySui> for RpcCommandProcessor { - async fn process( - &'a self, - _op: &'a PaySui, - signer_info: &Option, - ) -> anyhow::Result<()> { - let clients = self.get_clients().await?; - let SignerInfo { - encoded_keypair, - gas_budget, - gas_payment, - } = signer_info.clone().unwrap(); - let recipient = SuiAddress::random_for_testing_only(); - let amount = 1; - let gas_budget = gas_budget.unwrap_or(DEFAULT_GAS_BUDGET); - let gas_payments = gas_payment.unwrap(); - - let keypair = - SuiKeyPair::decode_base64(&encoded_keypair).expect("Decoding keypair should not fail"); - - debug!( - "Transfer Sui {} time to {recipient} with {amount} MIST with {gas_payments:?}", - gas_payments.len() - ); - - let sender = SuiAddress::from(&keypair.public()); - // TODO: For write operations, we usually just want to submit the transaction to - // fullnode Let's figure out what's the best way to support other mode - // later - let client = clients.first().unwrap(); - let gas_price = client - .governance_api() - .get_reference_gas_price() - .await - .expect("Unable to fetch gas price"); - join_all(gas_payments.iter().map(|gas| async { - let tx = TransactionData::new_transfer_sui( - recipient, - sender, - Some(amount), - self.get_object_ref(client, gas).await, - gas_budget, - gas_price, - ); - self.sign_and_execute( - client, - &keypair, - tx, - ExecuteTransactionRequestType::WaitForEffectsCert, - ) - .await - })) - .await; - - Ok(()) - } -} diff --git a/crates/sui-sdk/Cargo.toml b/crates/sui-sdk/Cargo.toml deleted file mode 100644 index c78b5c4e69f..00000000000 --- a/crates/sui-sdk/Cargo.toml +++ /dev/null @@ -1,86 +0,0 @@ -[package] -name = "sui-sdk" -version.workspace = true -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -async-trait.workspace = true -clap.workspace = true -colored.workspace = true -jsonrpsee.workspace = true -serde.workspace = true -serde_with.workspace = true -serde_json.workspace = true -futures-core.workspace = true -futures.workspace = true -tokio.workspace = true -bcs.workspace = true -thiserror.workspace = true -reqwest.workspace = true - -sui-json-rpc-api.workspace = true -sui-transaction-builder.workspace = true -sui-json-rpc-types.workspace = true -sui-types.workspace = true -sui-json.workspace = true -sui-keys.workspace = true -sui-config.workspace = true -shared-crypto.workspace = true -tracing.workspace = true -move-core-types.workspace = true -fastcrypto.workspace = true - -# NOTE: It's important to keep the above dependency list short. -# This and the sui-json-rpc-api crate are widely used to develop on Sui and it's valuable -# to not have to pull in the entire sui repo for it. - -[dev-dependencies] -clap.workspace = true -dirs.workspace = true -async-recursion.workspace = true -tempfile.workspace = true -futures-core.workspace = true -futures.workspace = true -rand.workspace = true - -[[example]] -name = "tic_tac_toe" -path = "examples/tic_tac_toe.rs" -test = false - -[[example]] -name = "coin_read_api" -path = "examples/coin_read_api.rs" - -[[example]] -name = "read_api" -path = "examples/read_api.rs" - -[[example]] -name = "event_api" -path = "examples/event_api.rs" - -[[example]] -name = "governance_api" -path = "examples/governance_api.rs" - -[[example]] -name = "programmable_transactions_api" -path = "examples/programmable_transactions_api.rs" - -[[example]] -name = "sui_client" -path = "examples/sui_client.rs" - -[[example]] -name = "sign_tx_guide" -path = "examples/sign_tx_guide.rs" - -[[example]] -name = "utils" -path = "examples/utils.rs" -crate-type = ["staticlib"] diff --git a/crates/sui-sdk/README.md b/crates/sui-sdk/README.md deleted file mode 100644 index 4679fce569b..00000000000 --- a/crates/sui-sdk/README.md +++ /dev/null @@ -1,183 +0,0 @@ -This crate provides the Sui Rust SDK, containing APIs to interact with the Sui network. - -## Getting started - -Add the `sui-sdk` dependency as following: - -```toml -sui-sdk = { git = "https://github.com/mystenlabs/sui", package = "sui-sdk"} -tokio = { version = "1.2", features = ["full"] } -anyhow = "1.0" -``` - -The main building block for the Sui Rust SDK is the `SuiClientBuilder`, which provides a simple and straightforward way of connecting to a Sui network and having access to the different available APIs. - -In the following example, the application connects to the Sui `testnet` and `devnet` networks and prints out their respective RPC API versions. - -```rust -use sui_sdk::SuiClientBuilder; - -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - // Sui testnet -- https://fullnode.testnet.sui.io:443 - let sui_testnet = SuiClientBuilder::default().build_testnet().await?; - println!("Sui testnet version: {}", sui_testnet.api_version()); - - // Sui devnet -- https://fullnode.devnet.sui.io:443 - let sui_devnet = SuiClientBuilder::default().build_devnet().await?; - println!("Sui devnet version: {}", sui_devnet.api_version()); - - Ok(()) -} - -``` - -## Documentation for sui-sdk crate - -[GitHub Pages](https://mystenlabs.github.io/sui/sui_sdk/index.html) hosts the generated documentation for all Rust crates in the Sui repository. - -### Building documentation locally - -You can also build the documentation locally. To do so, - -1. Clone the `sui` repo locally. Open a Terminal or Console and go to the `sui/crates/sui-sdk` directory. - -1. Run `cargo doc` to build the documentation into the `sui/target` directory. Take note of location of the generated file from the last line of the output, for example `Generated /Users/foo/sui/target/doc/sui_sdk/index.html`. - -1. Use a web browser, like Chrome, to open the `.../target/doc/sui_sdk/index.html` file at the location your console reported in the previous step. - -## Rust SDK examples - -The [examples](https://github.com/MystenLabs/sui/tree/main/crates/sui-sdk/examples) folder provides both basic and advanced examples. - -There are serveral files ending in `_api.rs` which provide code examples of the corresponding APIs and their methods. These showcase how to use the Sui Rust SDK, and can be run against the Sui testnet. Below are instructions on the prerequisites and how to run these examples. - -### Prerequisites - -Unless otherwise specified, most of these examples assume `Rust` and `cargo` are installed, and that there is an available internet connection. The examples connect to the Sui testnet (`https://fullnode.testnet.sui.io:443`) and execute different APIs using the active address from the local wallet. If there is no local wallet, it will create one, generate two addresses, set one of them to be active, and it will request 1 SUI from the testnet faucet for the active address. - -### Running the existing examples - -In the root folder of the `sui` repository (or in the `sui-sdk` crate folder), you can individually run examples using the command `cargo run --example filename` (without `.rs` extension). For example: -* `cargo run --example sui_client` -- this one requires a local Sui network running (see [here](#Connecting to Sui Network -)). If you do not have a local Sui network running, please skip this example. -* `cargo run --example coin_read_api` -* `cargo run --example event_api` -- note that this will subscribe to a stream and thus the program will not terminate unless forced (Ctrl+C) -* `cargo run --example governance_api` -* `cargo run --example read_api` -* `cargo run --example programmable_transactions_api` -* `cargo run --example sign_tx_guide` - -### Basic Examples - -#### Connecting to Sui Network -The `SuiClientBuilder` struct provides a connection to the JSON-RPC server that you use for all read-only operations. The default URLs to connect to the Sui network are: - -- Local: http://127.0.0.1:9000 -- Devnet: https://fullnode.devnet.sui.io:443 -- Testnet: https://fullnode.testnet.sui.io:443 -- Mainnet: https://fullnode.mainnet.sui.io:443 - -For all available servers, see [here](https://sui.io/networkinfo). - -For running a local Sui network, please follow [this guide](https://docs.sui.io/build/sui-local-network) for installing Sui and [this guide](https://docs.sui.io/build/sui-local-network#start-the-local-network) for starting the local Sui network. - - -```rust -use sui_sdk::SuiClientBuilder; - -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - let sui = SuiClientBuilder::default() - .build("http://127.0.0.1:9000") // local network address - .await?; - println!("Sui local network version: {}", sui.api_version()); - - // local Sui network, like the above one but using the dedicated function - let sui_local = SuiClientBuilder::default().build_localnet().await?; - println!("Sui local network version: {}", sui_local.api_version()); - - // Sui devnet -- https://fullnode.devnet.sui.io:443 - let sui_devnet = SuiClientBuilder::default().build_devnet().await?; - println!("Sui devnet version: {}", sui_devnet.api_version()); - - // Sui testnet -- https://fullnode.testnet.sui.io:443 - let sui_testnet = SuiClientBuilder::default().build_testnet().await?; - println!("Sui testnet version: {}", sui_testnet.api_version()); - - Ok(()) -} -``` - -#### Read the total coin balance for each coin type owned by this address -```rust -use std::str::FromStr; -use sui_sdk::types::base_types::SuiAddress; -use sui_sdk::{ SuiClientBuilder}; -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - - let sui_local = SuiClientBuilder::default().build_localnet().await?; - println!("Sui local network version: {}", sui_local.api_version()); - - let active_address = SuiAddress::from_str("")?; // change to your Sui address - - let total_balance = sui_local - .coin_read_api() - .get_all_balances(active_address) - .await?; - println!("The balances for all coins owned by address: {active_address} are {}", total_balance); - Ok(()) -} -``` - -## Advanced examples - -See the programmable transactions [example](https://github.com/MystenLabs/sui/blob/main/crates/sui-sdk/examples/programmable_transactions_api.rs). - -## Games examples - -### Tic Tac Toe quick start - -1. Prepare the environment - 1. Install `sui` binary following the [Sui installation](https://github.com/MystenLabs/sui/blob/main/docs/content/guides/developer/getting-started/sui-install.mdx) docs. - 1. [Connect to Sui Devnet](https://github.com/MystenLabs/sui/blob/main/docs/content/guides/developer/getting-started/connect.mdx). - 1. [Make sure you have two addresses with gas](https://github.com/MystenLabs/sui/blob/main/docs/content/guides/developer/getting-started/get-address.mdx) by using the `new-address` command to create new addresses: - ```shell - sui client new-address ed25519 - ``` - You must specify the key scheme, one of `ed25519` or `secp256k1` or `secp256r1`. - You can skip this step if you are going to play with a friend. :) - 1. [Request Sui tokens](https://github.com/MystenLabs/sui/blob/main/docs/content/guides/developer/getting-started/get-coins.mdx) for all addresses that will be used to join the game. - -2. Publish the move contract - 1. [Download the Sui source code](https://github.com/MystenLabs/sui/blob/main/docs/content/guides/developer/getting-started/sui-install.mdx). - 1. Publish the [`games` package](https://github.com/MystenLabs/sui/tree/main/sui_programmability/examples/games) - using the Sui client: - ```shell - sui client publish --path /path-to-sui-source-code/sui_programmability/examples/games --gas-budget 10000 - ``` - 1. Record the package object ID. - -3. Create a new tic-tac-toe game - 1. Run the following command in the Sui source code directory to start a new game, replacing the game package objects ID with the one you recorded: - ```shell - cargo run --example tic-tac-toe -- --game-package-id <> new-game - ``` - This will create a game for the first two addresses in your keystore by default. If you want to specify the identity of each player, - use the following command and replace the variables with the actual player's addresses: - ```shell - cargo run --example tic-tac-toe -- --game-package-id <> new-game --player-x <> --player-o <> - ``` - 1. Copy the game ID and pass it to your friend to join the game. - -4. Joining the game - - Run the following command in the Sui source code directory to join the game, replacing the game ID and address accordingly: - ```shell - cargo run --example tic-tac-toe -- --game-package-id <> join-game --my-identity <
    > --game-id <> - ``` - -## License - -[SPDX-License-Identifier: Apache-2.0](https://github.com/MystenLabs/sui/blob/main/LICENSE) diff --git a/crates/sui-sdk/examples/coin_read_api.rs b/crates/sui-sdk/examples/coin_read_api.rs deleted file mode 100644 index 66c5deb192c..00000000000 --- a/crates/sui-sdk/examples/coin_read_api.rs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod utils; -use futures::{future, stream::StreamExt}; -use utils::setup_for_read; - -// This example uses the coin read api to showcase the available -// functions to retrieve coin related information for a specific address. -// The example will use the active address in the wallet (if it exists or create -// one if it doesn't) check if it has coins and request coins from the faucet if -// there aren't any. If there is no wallet, it will create a wallet and two -// addresses, set one address as active, and add 1 SUI to the active address. -// By default, the example will use the Sui testnet network -// (fullnode.testnet.sui.io:443). - -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - let (sui, active_address) = setup_for_read().await?; - - // ************ COIN READ API ************ // - - // Get coins for this address. Coins can be filtered by `coin_type` - // (e.g., 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC) or - // use `None` for the default `Coin` which is represented as - // "0x2::sui::SUI" - let coin_type = Some("0x2::sui::SUI".to_string()); - let coins = sui - .coin_read_api() - .get_coins(active_address, coin_type.clone(), None, Some(5)) // get the first five coins - .await?; - println!(" *** Coins ***"); - println!("{:?}", coins); - println!(" *** Coins ***\n"); - - // Get all coins - // This function works very similar to the get_coins function, except it does - // not take a coin_type filter argument and it returns all coin types - // associated with this address - let all_coins = sui - .coin_read_api() - .get_all_coins(active_address, None, Some(5)) // get the first five coins - .await?; - println!(" *** All coins ***"); - println!("{:?}", all_coins); - println!(" *** All coins ***\n"); - - // Get coins as a stream - // Similar to the previous functions, except it returns the coins as a stream. - let coins_stream = sui.coin_read_api().get_coins_stream(active_address, None); - - println!(" *** Coins Stream ***"); - coins_stream - .for_each(|coin| { - println!("{:?}", coin); - future::ready(()) - }) - .await; - println!(" *** Coins Stream ***\n"); - - // Select coins based on the provided coin type (SUI in this example). Use - // `None` for the default Sui coin - let select_coins = sui - .coin_read_api() - .select_coins(active_address, coin_type, 1, vec![]) - .await?; - - println!(" *** Select Coins ***"); - println!("{:?}", select_coins); - println!(" *** Select Coins ***\n"); - - // Balance - // Returns the balance for the specified coin type for this address, - // or if None is passed, it will use Coin as the coin type - let balance = sui - .coin_read_api() - .get_balance(active_address, None) - .await?; - - // Total balance - // Returns the balance for each coin owned by this address - let total_balance = sui.coin_read_api().get_all_balances(active_address).await?; - println!(" *** Balance + Total Balance *** "); - println!("Balance: {:?}", balance); - println!("Total Balance: {:?}", total_balance); - println!(" *** Balance + Total Balance ***\n "); - - // Return the coin metadata for the Coin - let coin_metadata = sui - .coin_read_api() - .get_coin_metadata("0x2::sui::SUI".to_string()) - .await?; - - println!(" *** Coin Metadata *** "); - println!("{:?}", coin_metadata); - println!(" *** Coin Metadata ***\n "); - - // Total Supply - let total_supply = sui - .coin_read_api() - .get_total_supply("0x2::sui::SUI".to_string()) - .await?; - println!(" *** Total Supply *** "); - println!("{:?}", total_supply); - println!(" *** Total Supply ***\n "); - - // ************ END OF COIN READ API ************ // - Ok(()) -} diff --git a/crates/sui-sdk/examples/event_api.rs b/crates/sui-sdk/examples/event_api.rs deleted file mode 100644 index 615c7fe78cc..00000000000 --- a/crates/sui-sdk/examples/event_api.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod utils; -use futures::stream::StreamExt; -use sui_sdk::{rpc_types::EventFilter, SuiClientBuilder}; -use utils::{setup_for_write, split_coin_digest}; - -// This example showcases how to use the Event API. -// At the end of the program it subscribes to the events -// on the Sui testnet and prints every incoming event to -// the console. The program will loop until it is force -// stopped. - -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - let (sui, active_address, _second_address) = setup_for_write().await?; - - println!(" *** Get events *** "); - // for demonstration purposes, we set to make a transaction - let digest = split_coin_digest(&sui, &active_address).await?; - let events = sui.event_api().get_events(digest).await?; - println!("{:?}", events); - println!(" *** Get events ***\n "); - - let descending = true; - let query_events = sui - .event_api() - .query_events(EventFilter::All(vec![]), None, Some(5), descending) // query first 5 events in descending order - .await?; - println!(" *** Query events *** "); - println!("{:?}", query_events); - println!(" *** Query events ***\n "); - - let ws = SuiClientBuilder::default() - .ws_url("wss://rpc.testnet.sui.io:443") - .build("https://fullnode.testnet.sui.io:443") - .await?; - println!("WS version {:?}", ws.api_version()); - - let mut subscribe = ws - .event_api() - .subscribe_event(EventFilter::All(vec![])) - .await?; - - loop { - println!("{:?}", subscribe.next().await); - } -} diff --git a/crates/sui-sdk/examples/governance_api.rs b/crates/sui-sdk/examples/governance_api.rs deleted file mode 100644 index d372ad6482b..00000000000 --- a/crates/sui-sdk/examples/governance_api.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod utils; -use utils::setup_for_read; - -// This example connects to the Sui testnet -// and collects information about the stakes in the network, -// the committee information, -// lists all the validators' name, description, and sui address, -// and prints the reference gas price. - -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - let (sui, active_address) = setup_for_read().await?; - - // ************ GOVERNANCE API ************ // - - // Stakes - let stakes = sui.governance_api().get_stakes(active_address).await?; - - println!(" *** Stakes ***"); - println!("{:?}", stakes); - println!(" *** Stakes ***\n"); - - // Committee Info - let committee = sui.governance_api().get_committee_info(None).await?; // None defaults to the latest epoch - - println!(" *** Committee Info ***"); - println!("{:?}", committee); - println!(" *** Committee Info ***\n"); - - // Latest Sui System State - let sui_system_state = sui.governance_api().get_latest_sui_system_state().await?; - - println!(" *** Sui System State ***"); - println!("{:?}", sui_system_state); - println!(" *** Sui System State ***\n"); - - // List all active validators - - println!(" *** List active validators *** "); - sui_system_state - .active_validators - .into_iter() - .for_each(|validator| { - println!( - "Name: {}, Description: {}, SuiAddress: {:?}", - validator.name, validator.description, validator.sui_address - ) - }); - - println!(" *** List active validators ***\n"); - // Reference Gas Price - let reference_gas_price = sui.governance_api().get_reference_gas_price().await?; - - println!(" *** Reference Gas Price ***"); - println!("{:?}", reference_gas_price); - println!(" *** Reference Gas Price ***\n"); - - // ************ END OF GOVERNANCE API ************ // - Ok(()) -} diff --git a/crates/sui-sdk/examples/programmable_transactions_api.rs b/crates/sui-sdk/examples/programmable_transactions_api.rs deleted file mode 100644 index 56ae1eb0819..00000000000 --- a/crates/sui-sdk/examples/programmable_transactions_api.rs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod utils; -use shared_crypto::intent::Intent; -use sui_config::{sui_config_dir, SUI_KEYSTORE_FILENAME}; -use sui_keys::keystore::{AccountKeystore, FileBasedKeystore}; -use sui_sdk::{ - rpc_types::SuiTransactionBlockResponseOptions, - types::{ - programmable_transaction_builder::ProgrammableTransactionBuilder, - quorum_driver_types::ExecuteTransactionRequestType, - transaction::{Argument, Command, Transaction, TransactionData}, - }, -}; -use utils::setup_for_write; - -// This example shows how to use programmable transactions to chain multiple -// actions into one transaction. Specifically, the example retrieves two -// addresses from the local wallet, and then -// 1) finds a coin from the active address that has Sui, -// 2) splits the coin into one coin of 1000 MIST and the rest, -// 3 transfers the split coin to second Sui address, -// 4) signs the transaction, -// 5) executes it. -// For some of these actions it prints some output. -// Finally, at the end of the program it prints the number of coins for the -// Sui address that received the coin. -// If you run this program several times, you should see the number of coins -// for the recipient address increases. - -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - // 1) get the Sui client, the sender and recipient that we will use - // for the transaction, and find the coin we use as gas - let (sui, sender, recipient) = setup_for_write().await?; - - // we need to find the coin we will use as gas - let coins = sui - .coin_read_api() - .get_coins(sender, None, None, None) - .await?; - let coin = coins.data.into_iter().next().unwrap(); - - // programmable transactions allows the user to bundle a number of actions into - // one transaction - let mut ptb = ProgrammableTransactionBuilder::new(); - - // 2) split coin - // the amount we want in the new coin, 1000 MIST - let split_coint_amount = ptb.pure(1000u64)?; // note that we need to specify the u64 type - ptb.command(Command::SplitCoins( - Argument::GasCoin, - vec![split_coint_amount], - )); - - // 3) transfer the new coin to a different address - let argument_address = ptb.pure(recipient)?; - ptb.command(Command::TransferObjects( - vec![Argument::Result(0)], - argument_address, - )); - - // finish building the transaction block by calling finish on the ptb - let builder = ptb.finish(); - - let gas_budget = 5_000_000; - let gas_price = sui.read_api().get_reference_gas_price().await?; - // create the transaction data that will be sent to the network - let tx_data = TransactionData::new_programmable( - sender, - vec![coin.object_ref()], - builder, - gas_budget, - gas_price, - ); - - // 4) sign transaction - let keystore = FileBasedKeystore::new(&sui_config_dir()?.join(SUI_KEYSTORE_FILENAME))?; - let signature = keystore.sign_secure(&sender, &tx_data, Intent::sui_transaction())?; - - // 5) execute the transaction - print!("Executing the transaction..."); - let transaction_response = sui - .quorum_driver_api() - .execute_transaction_block( - Transaction::from_data(tx_data, vec![signature]), - SuiTransactionBlockResponseOptions::full_content(), - Some(ExecuteTransactionRequestType::WaitForLocalExecution), - ) - .await?; - print!("done\n Transaction information: "); - println!("{:?}", transaction_response); - - let coins = sui - .coin_read_api() - .get_coins(recipient, None, None, None) - .await?; - - println!( - "After the transfer, the recipient address {recipient} has {} coins", - coins.data.len() - ); - Ok(()) -} diff --git a/crates/sui-sdk/examples/read_api.rs b/crates/sui-sdk/examples/read_api.rs deleted file mode 100644 index f18617f55de..00000000000 --- a/crates/sui-sdk/examples/read_api.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod utils; -use sui_sdk::{ - rpc_types::{ - SuiGetPastObjectRequest, SuiObjectDataOptions, SuiTransactionBlockResponseOptions, - }, - types::base_types::ObjectID, -}; -use utils::{setup_for_write, split_coin_digest}; - -// This example uses the Read API to get owned objects of an address, -// the dynamic fields of an object, -// past objects, information about the chain -// and the protocol configuration, -// the transaction data after executing a transaction, -// and finally, the number of transaction blocks known to the server. - -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - let (sui, active_address, _) = setup_for_write().await?; - - // ************ READ API ************ // - println!("// ************ READ API ************ //\n"); - // Owned Objects - let owned_objects = sui - .read_api() - .get_owned_objects(active_address, None, None, Some(5)) - .await?; - println!(" *** Owned Objects ***"); - println!("{:?}", owned_objects); - println!(" *** Owned Objects ***\n"); - - // Dynamic Fields - let parent_object_id = ObjectID::from_address(active_address.into()); - let dynamic_fields = sui - .read_api() - .get_dynamic_fields(parent_object_id, None, None) - .await?; - println!(" *** Dynamic Fields ***"); - println!("{:?}", dynamic_fields); - println!(" *** Dynamic Fields ***\n"); - if let Some(dynamic_field_info) = dynamic_fields.data.into_iter().next() { - println!(" *** First Dynamic Field ***"); - let dynamic_field = sui - .read_api() - .get_dynamic_field_object(parent_object_id, dynamic_field_info.name) - .await?; - println!("{dynamic_field:?}"); - println!(" *** First Dynamic Field ***\n"); - } - - let object = owned_objects - .data - .first() - .unwrap_or_else(|| panic!("No object data for this address {}", active_address)); - let object_data = object - .data - .as_ref() - .unwrap_or_else(|| panic!("No object data for this SuiObjectResponse {:?}", object)); - let object_id = object_data.object_id; - let version = object_data.version; - - let sui_data_options = SuiObjectDataOptions { - show_type: true, - show_owner: true, - show_previous_transaction: true, - show_display: true, - show_content: true, - show_bcs: true, - show_storage_rebate: true, - }; - - let past_object = sui - .read_api() - .try_get_parsed_past_object(object_id, version, sui_data_options.clone()) - .await?; - println!(" *** Past Object *** "); - println!("{:?}", past_object); - println!(" *** Past Object ***\n"); - - let sui_get_past_object_request = past_object.clone().into_object()?; - let multi_past_object = sui - .read_api() - .try_multi_get_parsed_past_object( - vec![SuiGetPastObjectRequest { - object_id: sui_get_past_object_request.object_id, - version: sui_get_past_object_request.version, - }], - sui_data_options.clone(), - ) - .await?; - println!(" *** Multi Past Object *** "); - println!("{:?}", multi_past_object); - println!(" *** Multi Past Object ***\n"); - - // Object with options - let object_with_options = sui - .read_api() - .get_object_with_options(sui_get_past_object_request.object_id, sui_data_options) - .await?; - - println!(" *** Object with Options *** "); - println!("{:?}", object_with_options); - println!(" *** Object with Options ***\n"); - - println!(" *** Chain identifier *** "); - println!("{:?}", sui.read_api().get_chain_identifier().await?); - println!(" *** Chain identifier ***\n "); - - println!(" *** Protocol Config *** "); - println!("{:?}", sui.read_api().get_protocol_config(None).await?); - println!(" *** Protocol Config ***\n "); - - // we make a dummy transaction which returns a transaction digest - let tx_digest = split_coin_digest(&sui, &active_address).await?; - println!(" *** Transaction data *** "); - let tx_response = sui - .read_api() - .get_transaction_with_options( - tx_digest, - SuiTransactionBlockResponseOptions { - show_input: true, - show_raw_input: true, - show_effects: true, - show_events: true, - show_object_changes: true, - show_balance_changes: true, - show_raw_effects: true, - }, - ) - .await?; - println!("Transaction succeeded: {:?}\n\n", tx_response.status_ok()); - - println!("Transaction data: {:?}", tx_response); - - let tx_blocks = sui.read_api().get_total_transaction_blocks().await?; - println!("Total transaction blocks {tx_blocks}"); - // ************ END OF READ API ************ // - - Ok(()) -} diff --git a/crates/sui-sdk/examples/sign_tx_guide.rs b/crates/sui-sdk/examples/sign_tx_guide.rs deleted file mode 100644 index c3daeb191c5..00000000000 --- a/crates/sui-sdk/examples/sign_tx_guide.rs +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod utils; -use anyhow::anyhow; -use fastcrypto::{ - ed25519::Ed25519KeyPair, - encoding::{Base64, Encoding}, - hash::HashFunction, - secp256k1::Secp256k1KeyPair, - secp256r1::Secp256r1KeyPair, - traits::{EncodeDecodeBase64, KeyPair}, -}; -use rand::{rngs::StdRng, SeedableRng}; -use shared_crypto::intent::{Intent, IntentMessage}; -use sui_sdk::{ - rpc_types::SuiTransactionBlockResponseOptions, - types::{ - programmable_transaction_builder::ProgrammableTransactionBuilder, - transaction::TransactionData, - }, - SuiClientBuilder, -}; -use sui_types::{ - base_types::SuiAddress, - crypto::{get_key_pair_from_rng, Signer, SuiKeyPair, SuiSignature, ToFromBytes}, - signature::GenericSignature, -}; - -use crate::utils::request_tokens_from_faucet; - -/// This example walks through the Rust SDK use case described in -/// https://github.com/MystenLabs/sui/blob/main/docs/content/guides/developer/sui-101/sign-and-send-txn.mdx -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - // set up sui client for the desired network. - let sui_client = SuiClientBuilder::default().build_testnet().await?; - - // deterministically generate a keypair, testing only, do not use for mainnet, - // use the next section to randomly generate a keypair instead. - let skp_determ_0 = - SuiKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))); - let _skp_determ_1 = - SuiKeyPair::Secp256k1(Secp256k1KeyPair::generate(&mut StdRng::from_seed([0; 32]))); - let _skp_determ_2 = - SuiKeyPair::Secp256r1(Secp256r1KeyPair::generate(&mut StdRng::from_seed([0; 32]))); - - // randomly generate a keypair. - let _skp_rand_0 = SuiKeyPair::Ed25519(get_key_pair_from_rng(&mut rand::rngs::OsRng).1); - let _skp_rand_1 = SuiKeyPair::Secp256k1(get_key_pair_from_rng(&mut rand::rngs::OsRng).1); - let _skp_rand_2 = SuiKeyPair::Secp256r1(get_key_pair_from_rng(&mut rand::rngs::OsRng).1); - - // import a keypair from a base64 encoded 32-byte `private key` assuming scheme - // is Ed25519. - let _skp_import_no_flag_0 = SuiKeyPair::Ed25519(Ed25519KeyPair::from_bytes( - &Base64::decode("1GPhHHkVlF6GrCty2IuBkM+tj/e0jn64ksJ1pc8KPoI=") - .map_err(|_| anyhow!("Invalid base64"))?, - )?); - let _skp_import_no_flag_1 = SuiKeyPair::Ed25519(Ed25519KeyPair::from_bytes( - &Base64::decode("1GPhHHkVlF6GrCty2IuBkM+tj/e0jn64ksJ1pc8KPoI=") - .map_err(|_| anyhow!("Invalid base64"))?, - )?); - let _skp_import_no_flag_2 = SuiKeyPair::Ed25519(Ed25519KeyPair::from_bytes( - &Base64::decode("1GPhHHkVlF6GrCty2IuBkM+tj/e0jn64ksJ1pc8KPoI=") - .map_err(|_| anyhow!("Invalid base64"))?, - )?); - - // import a keypair from a base64 encoded 33-byte `flag || private key`. - // The signature scheme is determined by the flag. - let _skp_import_with_flag_0 = - SuiKeyPair::decode_base64("ANRj4Rx5FZRehqwrctiLgZDPrY/3tI5+uJLCdaXPCj6C") - .map_err(|_| anyhow!("Invalid base64"))?; - let _skp_import_with_flag_1 = - SuiKeyPair::decode_base64("AdRj4Rx5FZRehqwrctiLgZDPrY/3tI5+uJLCdaXPCj6C") - .map_err(|_| anyhow!("Invalid base64"))?; - let _skp_import_with_flag_2 = - SuiKeyPair::decode_base64("AtRj4Rx5FZRehqwrctiLgZDPrY/3tI5+uJLCdaXPCj6C") - .map_err(|_| anyhow!("Invalid base64"))?; - - // import a keypair from a Bech32 encoded 33-byte `flag || private key`. - // this is the format of a private key exported from Sui Wallet or sui.keystore. - let _skp_import_with_flag_0 = SuiKeyPair::decode( - "suiprivkey1qzdlfxn2qa2lj5uprl8pyhexs02sg2wrhdy7qaq50cqgnffw4c2477kg9h3", - ) - .map_err(|_| anyhow!("Invalid Bech32"))?; - let _skp_import_with_flag_1 = SuiKeyPair::decode( - "suiprivkey1qqesr6xhua2dkt840v9yefely578q5ad90znnpmhhgpekfvwtxke6ef2xyg", - ) - .map_err(|_| anyhow!("Invalid Bech32"))?; - let _skp_import_with_flag_2 = SuiKeyPair::decode( - "suiprivkey1qprzkcs823gcrk7n4hy8pzhntdxakpqk32qwjg9f2wyc3myj78egvtw3ecr", - ) - .map_err(|_| anyhow!("Invalid Bech32"))?; - - // replace `skp_determ_0` with the variable names above - let pk = skp_determ_0.public(); - let sender = SuiAddress::from(&pk); - println!("Sender: {:?}", sender); - - // make sure the sender has a gas coin as an example. - request_tokens_from_faucet(sender, &sui_client).await?; - let gas_coin = sui_client - .coin_read_api() - .get_coins(sender, None, None, None) - .await? - .data - .into_iter() - .next() - .ok_or(anyhow!("No coins found for sender"))?; - - // construct an example programmable transaction. - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - builder.pay_sui(vec![sender], vec![1])?; - builder.finish() - }; - - let gas_budget = 5_000_000; - let gas_price = sui_client.read_api().get_reference_gas_price().await?; - - // create the transaction data that will be sent to the network. - let tx_data = TransactionData::new_programmable( - sender, - vec![gas_coin.object_ref()], - pt, - gas_budget, - gas_price, - ); - - // derive the digest that the keypair should sign on, - // i.e. the blake2b hash of `intent || tx_data`. - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data); - let raw_tx = bcs::to_bytes(&intent_msg).expect("bcs should not fail"); - let mut hasher = sui_types::crypto::DefaultHash::default(); - hasher.update(raw_tx.clone()); - let digest = hasher.finalize().digest; - - // use SuiKeyPair to sign the digest. - let sui_sig = skp_determ_0.sign(&digest); - - // if you would like to verify the signature locally before submission, use this - // function. if it fails to verify locally, the transaction will fail to - // execute in Sui. - let res = sui_sig.verify_secure( - &intent_msg, - sender, - sui_types::crypto::SignatureScheme::ED25519, - ); - assert!(res.is_ok()); - - // execute the transaction. - let transaction_response = sui_client - .quorum_driver_api() - .execute_transaction_block( - sui_types::transaction::Transaction::from_generic_sig_data( - intent_msg.value, - vec![GenericSignature::Signature(sui_sig)], - ), - SuiTransactionBlockResponseOptions::default(), - None, - ) - .await?; - - println!( - "Transaction executed. Transaction digest: {}", - transaction_response.digest.base58_encode() - ); - println!("{transaction_response}"); - Ok(()) -} diff --git a/crates/sui-sdk/examples/sui_client.rs b/crates/sui-sdk/examples/sui_client.rs deleted file mode 100644 index 2d4a3c7d4c4..00000000000 --- a/crates/sui-sdk/examples/sui_client.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use sui_sdk::SuiClientBuilder; - -// This example shows the few basic ways to connect to a Sui network. -// There are several in-built methods for connecting to the -// Sui devnet, tesnet, and localnet (running locally), -// as well as a custom way for connecting to custom URLs. -// The example prints out the API versions of the different networks, -// and finally, it prints the list of available RPC methods -// and the list of subscriptions. -// Note that running this code will fail if there is no Sui network -// running locally on the default address: 127.0.0.1:9000 - -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - let sui = SuiClientBuilder::default() - .build("http://127.0.0.1:9000") // local network address - .await?; - println!("Sui local network version: {}", sui.api_version()); - - // local Sui network, like the above one but using the dedicated function - let sui_local = SuiClientBuilder::default().build_localnet().await?; - println!("Sui local network version: {}", sui_local.api_version()); - - // Sui devnet -- https://fullnode.devnet.sui.io:443 - let sui_devnet = SuiClientBuilder::default().build_devnet().await?; - println!("Sui devnet version: {}", sui_devnet.api_version()); - - // Sui testnet -- https://fullnode.testnet.sui.io:443 - let sui_testnet = SuiClientBuilder::default().build_testnet().await?; - println!("Sui testnet version: {}", sui_testnet.api_version()); - - println!("{:?}", sui_local.available_rpc_methods()); - println!("{:?}", sui_local.available_subscriptions()); - - Ok(()) -} diff --git a/crates/sui-sdk/examples/transaction_subscription.rs b/crates/sui-sdk/examples/transaction_subscription.rs deleted file mode 100644 index 836352a7f34..00000000000 --- a/crates/sui-sdk/examples/transaction_subscription.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use futures::stream::StreamExt; -use sui_json_rpc_types::TransactionFilter; -use sui_sdk::SuiClientBuilder; - -// This example showcases how to use the Read API to listen -// for transactions. It subscribes to the transactions that -// transfer SUI on the Sui testnet and prints every incoming -// transaction to the console. The program will loop until it -// is force stopped. - -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - let ws = SuiClientBuilder::default() - .ws_url("wss://rpc.testnet.sui.io:443") - .build("https://fullnode.testnet.sui.io:443") - .await?; - println!("WS version {:?}", ws.api_version()); - - let mut subscribe = ws - .read_api() - .subscribe_transaction(TransactionFilter::MoveFunction { - package: "0x2".parse()?, - module: Some("sui".to_owned()), - function: Some("transfer".to_owned()), - }) - .await?; - - loop { - println!("{:?}", subscribe.next().await); - } -} diff --git a/crates/sui-sdk/examples/utils.rs b/crates/sui-sdk/examples/utils.rs deleted file mode 100644 index 23527875982..00000000000 --- a/crates/sui-sdk/examples/utils.rs +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{str::FromStr, time::Duration}; - -use anyhow::bail; -use futures::{future, stream::StreamExt}; -use reqwest::Client; -use serde_json::json; -use shared_crypto::intent::Intent; -use sui_config::{ - sui_config_dir, Config, PersistedConfig, SUI_CLIENT_CONFIG, SUI_KEYSTORE_FILENAME, -}; -use sui_json_rpc_types::{Coin, SuiObjectDataOptions}; -use sui_keys::keystore::{AccountKeystore, FileBasedKeystore}; -use sui_sdk::{ - rpc_types::SuiTransactionBlockResponseOptions, - sui_client_config::{SuiClientConfig, SuiEnv}, - types::{ - base_types::{ObjectID, SuiAddress}, - crypto::SignatureScheme::ED25519, - digests::TransactionDigest, - programmable_transaction_builder::ProgrammableTransactionBuilder, - quorum_driver_types::ExecuteTransactionRequestType, - transaction::{Argument, Command, Transaction, TransactionData}, - }, - wallet_context::WalletContext, - SuiClient, SuiClientBuilder, -}; -use tracing::info; - -#[derive(serde::Deserialize)] -struct FaucetResponse { - task: String, - error: Option, -} - -// const SUI_FAUCET: &str = "https://faucet.devnet.sui.io/gas"; // devnet faucet - -pub const SUI_FAUCET: &str = "https://faucet.testnet.sui.io/v1/gas"; // testnet faucet - -// if you use the sui-test-validator and use the local network; if it does not -// work, try with port 5003. const SUI_FAUCET: &str = "http://127.0.0.1:9123/gas"; - -/// Return a sui client to interact with the APIs, -/// the active address of the local wallet, and another address that can be used -/// as a recipient. -/// -/// By default, this function will set up a wallet locally if there isn't any, -/// or reuse the existing one and its active address. This function should be -/// used when two addresses are needed, e.g., transferring objects from one -/// address to another. -pub async fn setup_for_write() -> Result<(SuiClient, SuiAddress, SuiAddress), anyhow::Error> { - let (client, active_address) = setup_for_read().await?; - // make sure we have some SUI (5_000_000 MIST) on this address - let coin = fetch_coin(&client, &active_address).await?; - if coin.is_none() { - request_tokens_from_faucet(active_address, &client).await?; - } - let wallet = retrieve_wallet()?; - let addresses = wallet.get_addresses(); - let addresses = addresses - .into_iter() - .filter(|address| address != &active_address) - .collect::>(); - let recipient = addresses - .first() - .expect("Cannot get the recipient address needed for writing operations. Aborting"); - - Ok((client, active_address, *recipient)) -} - -/// Return a sui client to interact with the APIs and an active address from the -/// local wallet. -/// -/// This function sets up a wallet in case there is no wallet locally, -/// and ensures that the active address of the wallet has SUI on it. -/// If there is no SUI owned by the active address, then it will request -/// SUI from the faucet. -pub async fn setup_for_read() -> Result<(SuiClient, SuiAddress), anyhow::Error> { - let client = SuiClientBuilder::default().build_testnet().await?; - println!("Sui testnet version is: {}", client.api_version()); - let mut wallet = retrieve_wallet()?; - assert!(wallet.get_addresses().len() >= 2); - let active_address = wallet.active_address()?; - - println!("Wallet active address is: {active_address}"); - Ok((client, active_address)) -} - -/// Request tokens from the Faucet for the given address -#[allow(unused_assignments)] -pub async fn request_tokens_from_faucet( - address: SuiAddress, - sui_client: &SuiClient, -) -> Result<(), anyhow::Error> { - let address_str = address.to_string(); - let json_body = json![{ - "FixedAmountRequest": { - "recipient": &address_str - } - }]; - - // make the request to the faucet JSON RPC API for coin - let client = Client::new(); - let resp = client - .post(SUI_FAUCET) - .header("Content-Type", "application/json") - .json(&json_body) - .send() - .await?; - println!( - "Faucet request for address {address_str} has status: {}", - resp.status() - ); - println!("Waiting for the faucet to complete the gas request..."); - let faucet_resp: FaucetResponse = resp.json().await?; - - let task_id = if let Some(err) = faucet_resp.error { - bail!("Faucet request was unsuccessful. Error is {err:?}") - } else { - faucet_resp.task - }; - - println!("Faucet request task id: {task_id}"); - - let json_body = json![{ - "GetBatchSendStatusRequest": { - "task_id": &task_id - } - }]; - - let mut coin_id = "".to_string(); - - // wait for the faucet to finish the batch of token requests - loop { - let resp = client - .get("https://faucet.testnet.sui.io/v1/status") - .header("Content-Type", "application/json") - .json(&json_body) - .send() - .await?; - let text = resp.text().await?; - if text.contains("SUCCEEDED") { - let resp_json: serde_json::Value = serde_json::from_str(&text).unwrap(); - - coin_id = <&str>::clone( - &resp_json - .pointer("/status/transferred_gas_objects/sent/0/id") - .unwrap() - .as_str() - .unwrap(), - ) - .to_string(); - - break; - } else { - tokio::time::sleep(Duration::from_secs(1)).await; - } - } - - // wait until the fullnode has the coin object, and check if it has the same - // owner - loop { - let owner = sui_client - .read_api() - .get_object_with_options( - ObjectID::from_str(&coin_id)?, - SuiObjectDataOptions::new().with_owner(), - ) - .await?; - - if owner.owner().is_some() { - let owner_address = owner.owner().unwrap().get_owner_address()?; - if owner_address == address { - break; - } - } else { - tokio::time::sleep(Duration::from_secs(1)).await; - } - } - Ok(()) -} - -/// Return the coin owned by the address that has at least 5_000_000 MIST, -/// otherwise returns None -pub async fn fetch_coin( - sui: &SuiClient, - sender: &SuiAddress, -) -> Result, anyhow::Error> { - let coin_type = "0x2::sui::SUI".to_string(); - let coins_stream = sui - .coin_read_api() - .get_coins_stream(*sender, Some(coin_type)); - - let mut coins = coins_stream - .skip_while(|c| future::ready(c.balance < 5_000_000)) - .boxed(); - let coin = coins.next().await; - Ok(coin) -} - -/// Return a transaction digest from a split coin + merge coins transaction -pub async fn split_coin_digest( - sui: &SuiClient, - sender: &SuiAddress, -) -> Result { - let coin = match fetch_coin(sui, sender).await? { - None => { - request_tokens_from_faucet(*sender, sui).await?; - fetch_coin(sui, sender) - .await? - .expect("Supposed to get a coin with SUI, but didn't. Aborting") - } - Some(c) => c, - }; - - println!( - "Address: {sender}. The selected coin for split is {} and has a balance of {}\n", - coin.coin_object_id, coin.balance - ); - - // set the maximum gas budget - let max_gas_budget = 5_000_000; - - // get the reference gas price from the network - let gas_price = sui.read_api().get_reference_gas_price().await?; - - // now we programmatically build the transaction through several commands - let mut ptb = ProgrammableTransactionBuilder::new(); - // first, we want to split the coin, and we specify how much SUI (in MIST) we - // want for the new coin - let split_coin_amount = ptb.pure(1000u64)?; // note that we need to specify the u64 type here - ptb.command(Command::SplitCoins( - Argument::GasCoin, - vec![split_coin_amount], - )); - // now we want to merge the coins (so that we don't have many coins with very - // small values) observe here that we pass Argument::Result(0), which - // instructs the PTB to get the result from the previous command - ptb.command(Command::MergeCoins( - Argument::GasCoin, - vec![Argument::Result(0)], - )); - - // we finished constructing our PTB and we need to call finish - let builder = ptb.finish(); - - // using the PTB that we just constructed, create the transaction data - // that we will submit to the network - let tx_data = TransactionData::new_programmable( - *sender, - vec![coin.object_ref()], - builder, - max_gas_budget, - gas_price, - ); - - // sign & execute the transaction - let keystore = FileBasedKeystore::new(&sui_config_dir()?.join(SUI_KEYSTORE_FILENAME))?; - let signature = keystore.sign_secure(sender, &tx_data, Intent::sui_transaction())?; - - let transaction_response = sui - .quorum_driver_api() - .execute_transaction_block( - Transaction::from_data(tx_data, vec![signature]), - SuiTransactionBlockResponseOptions::new(), - Some(ExecuteTransactionRequestType::WaitForLocalExecution), - ) - .await?; - Ok(transaction_response.digest) -} - -pub fn retrieve_wallet() -> Result { - let wallet_conf = sui_config_dir()?.join(SUI_CLIENT_CONFIG); - let keystore_path = sui_config_dir()?.join(SUI_KEYSTORE_FILENAME); - - // check if a wallet exists and if not, create a wallet and a sui client config - if !keystore_path.exists() { - let keystore = FileBasedKeystore::new(&keystore_path)?; - keystore.save()?; - } - - if !wallet_conf.exists() { - let keystore = FileBasedKeystore::new(&keystore_path)?; - let mut client_config = SuiClientConfig::new(keystore.into()); - - client_config.add_env(SuiEnv::testnet()); - client_config.add_env(SuiEnv::devnet()); - client_config.add_env(SuiEnv::localnet()); - - if client_config.active_env.is_none() { - client_config.active_env = client_config.envs.first().map(|env| env.alias.clone()); - } - - client_config.save(&wallet_conf)?; - info!("Client config file is stored in {:?}.", &wallet_conf); - } - - let mut keystore = FileBasedKeystore::new(&keystore_path)?; - let mut client_config: SuiClientConfig = PersistedConfig::read(&wallet_conf)?; - - let default_active_address = if let Some(address) = keystore.addresses().first() { - *address - } else { - keystore - .generate_and_add_new_key(ED25519, None, None, None)? - .0 - }; - - if keystore.addresses().len() < 2 { - keystore.generate_and_add_new_key(ED25519, None, None, None)?; - } - - client_config.active_address = Some(default_active_address); - client_config.save(&wallet_conf)?; - - let wallet = WalletContext::new(&wallet_conf, Some(std::time::Duration::from_secs(60)), None)?; - - Ok(wallet) -} - -// this function should not be used. It is only used to make clippy happy, -// and to reduce the number of allow(dead_code) annotations to just this one -#[allow(dead_code)] -async fn just_for_clippy() -> Result<(), anyhow::Error> { - let (sui, sender, _recipient) = setup_for_write().await?; - let _digest = split_coin_digest(&sui, &sender).await?; - Ok(()) -} diff --git a/crates/sui-sdk/src/apis.rs b/crates/sui-sdk/src/apis.rs deleted file mode 100644 index f414b9a2255..00000000000 --- a/crates/sui-sdk/src/apis.rs +++ /dev/null @@ -1,1289 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::BTreeMap, future, sync::Arc, time::Instant}; - -use fastcrypto::encoding::Base64; -use futures::{stream, StreamExt}; -use futures_core::Stream; -use jsonrpsee::core::client::Subscription; -use sui_json_rpc_api::{ - CoinReadApiClient, GovernanceReadApiClient, IndexerApiClient, MoveUtilsClient, ReadApiClient, - WriteApiClient, -}; -use sui_json_rpc_types::{ - Balance, Checkpoint, CheckpointId, CheckpointPage, Coin, CoinPage, DelegatedStake, - DevInspectArgs, DevInspectResults, DryRunTransactionBlockResponse, DynamicFieldPage, - EventFilter, EventPage, ObjectsPage, ProtocolConfigResponse, SuiCoinMetadata, SuiCommittee, - SuiData, SuiEvent, SuiGetPastObjectRequest, SuiLoadedChildObjectsResponse, - SuiMoveNormalizedModule, SuiObjectDataOptions, SuiObjectResponse, SuiObjectResponseQuery, - SuiPastObjectResponse, SuiTransactionBlockEffects, SuiTransactionBlockResponse, - SuiTransactionBlockResponseOptions, SuiTransactionBlockResponseQuery, TransactionBlocksPage, - TransactionFilter, -}; -use sui_types::{ - balance::Supply, - base_types::{ObjectID, SequenceNumber, SuiAddress, TransactionDigest}, - dynamic_field::DynamicFieldName, - event::EventID, - messages_checkpoint::CheckpointSequenceNumber, - quorum_driver_types::ExecuteTransactionRequestType, - sui_serde::BigInt, - sui_system_state::sui_system_state_summary::SuiSystemStateSummary, - transaction::{Transaction, TransactionData, TransactionKind}, -}; - -use crate::{ - error::{Error, SuiRpcResult}, - RpcClient, -}; - -const WAIT_FOR_LOCAL_EXECUTION_RETRY_COUNT: u8 = 3; - -/// The main read API structure with functions for retrieving data about -/// different objects and transactions -#[derive(Debug)] -pub struct ReadApi { - api: Arc, -} - -impl ReadApi { - pub(crate) fn new(api: Arc) -> Self { - Self { api } - } - /// Return a paginated response with the objects owned by the given address, - /// or an error upon failure. - /// - /// Note that if the address owns more than `QUERY_MAX_RESULT_LIMIT` objects - /// (default is 50), the pagination is not accurate, because previous - /// page may have been updated when the next page is fetched. - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::str::FromStr; - /// - /// use sui_sdk::SuiClientBuilder; - /// use sui_types::base_types::SuiAddress; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let address = SuiAddress::from_str("0x0000....0000")?; - /// let owned_objects = sui - /// .read_api() - /// .get_owned_objects(address, None, None, None) - /// .await?; - /// Ok(()) - /// } - /// ``` - pub async fn get_owned_objects( - &self, - address: SuiAddress, - query: Option, - cursor: Option, - limit: Option, - ) -> SuiRpcResult { - Ok(self - .api - .http - .get_owned_objects(address, query, cursor, limit) - .await?) - } - - /// Return a paginated response with the dynamic fields owned by the given - /// [ObjectID], or an error upon failure. - /// - /// The return type is a list of `DynamicFieldInfo` objects, where the field - /// name is always present, represented as a Move `Value`. - /// - /// If the field is a dynamic field, returns the ID of the Field object - /// (which contains both the name and the value). If the field is a - /// dynamic object field, it returns the ID of the Object (the value of the - /// field). - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::str::FromStr; - /// - /// use sui_sdk::SuiClientBuilder; - /// use sui_types::base_types::{ObjectID, SuiAddress}; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let address = SuiAddress::from_str("0x0000....0000")?; - /// let owned_objects = sui - /// .read_api() - /// .get_owned_objects(address, None, None, None) - /// .await?; - /// // this code example assumes that there are previous owned objects - /// let object = owned_objects - /// .data - /// .get(0) - /// .expect(&format!("No owned objects for this address {}", address)); - /// let object_data = object.data.as_ref().expect(&format!( - /// "No object data for this SuiObjectResponse {:?}", - /// object - /// )); - /// let object_id = object_data.object_id; - /// let dynamic_fields = sui - /// .read_api() - /// .get_dynamic_fields(object_id, None, None) - /// .await?; - /// Ok(()) - /// } - /// ``` - pub async fn get_dynamic_fields( - &self, - object_id: ObjectID, - cursor: Option, - limit: Option, - ) -> SuiRpcResult { - Ok(self - .api - .http - .get_dynamic_fields(object_id, cursor, limit) - .await?) - } - - /// Return the dynamic field object information for a specified object. - pub async fn get_dynamic_field_object( - &self, - parent_object_id: ObjectID, - name: DynamicFieldName, - ) -> SuiRpcResult { - Ok(self - .api - .http - .get_dynamic_field_object(parent_object_id, name) - .await?) - } - - /// Return a parsed past object for the provided [ObjectID] and version, or - /// an error upon failure. - /// - /// An object's version increases (though it is not guaranteed that it - /// increases always by 1) when the object is mutated. A past object can - /// be used to understand how the object changed over time, - /// i.e. what was the total balance at a specific version. - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::str::FromStr; - /// - /// use sui_json_rpc_types::SuiObjectDataOptions; - /// use sui_sdk::SuiClientBuilder; - /// use sui_types::base_types::{ObjectID, SuiAddress}; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let address = SuiAddress::from_str("0x0000....0000")?; - /// let owned_objects = sui - /// .read_api() - /// .get_owned_objects(address, None, None, None) - /// .await?; - /// // this code example assumes that there are previous owned objects - /// let object = owned_objects - /// .data - /// .get(0) - /// .expect(&format!("No owned objects for this address {}", address)); - /// let object_data = object.data.as_ref().expect(&format!( - /// "No object data for this SuiObjectResponse {:?}", - /// object - /// )); - /// let object_id = object_data.object_id; - /// let version = object_data.version; - /// let past_object = sui - /// .read_api() - /// .try_get_parsed_past_object( - /// object_id, - /// version, - /// SuiObjectDataOptions { - /// show_type: true, - /// show_owner: true, - /// show_previous_transaction: true, - /// show_display: true, - /// show_content: true, - /// show_bcs: true, - /// show_storage_rebate: true, - /// }, - /// ) - /// .await?; - /// Ok(()) - /// } - /// ``` - pub async fn try_get_parsed_past_object( - &self, - object_id: ObjectID, - version: SequenceNumber, - options: SuiObjectDataOptions, - ) -> SuiRpcResult { - Ok(self - .api - .http - .try_get_past_object(object_id, version, Some(options)) - .await?) - } - - /// Return a list of [SuiPastObjectResponse] objects, or an error upon - /// failure. - /// - /// See [this function](ReadApi::try_get_parsed_past_object) for more - /// details about past objects. - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::str::FromStr; - /// - /// use sui_json_rpc_types::{SuiGetPastObjectRequest, SuiObjectDataOptions}; - /// use sui_sdk::SuiClientBuilder; - /// use sui_types::base_types::{ObjectID, SuiAddress}; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let address = SuiAddress::from_str("0x0000....0000")?; - /// let owned_objects = sui - /// .read_api() - /// .get_owned_objects(address, None, None, None) - /// .await?; - /// // this code example assumes that there are previous owned objects - /// let object = owned_objects - /// .data - /// .get(0) - /// .expect(&format!("No owned objects for this address {}", address)); - /// let object_data = object.data.as_ref().expect(&format!( - /// "No object data for this SuiObjectResponse {:?}", - /// object - /// )); - /// let object_id = object_data.object_id; - /// let version = object_data.version; - /// let past_object = sui - /// .read_api() - /// .try_get_parsed_past_object( - /// object_id, - /// version, - /// SuiObjectDataOptions { - /// show_type: true, - /// show_owner: true, - /// show_previous_transaction: true, - /// show_display: true, - /// show_content: true, - /// show_bcs: true, - /// show_storage_rebate: true, - /// }, - /// ) - /// .await?; - /// let past_object = past_object.into_object()?; - /// let multi_past_object = sui - /// .read_api() - /// .try_multi_get_parsed_past_object( - /// vec![SuiGetPastObjectRequest { - /// object_id: past_object.object_id, - /// version: past_object.version, - /// }], - /// SuiObjectDataOptions { - /// show_type: true, - /// show_owner: true, - /// show_previous_transaction: true, - /// show_display: true, - /// show_content: true, - /// show_bcs: true, - /// show_storage_rebate: true, - /// }, - /// ) - /// .await?; - /// Ok(()) - /// } - /// ``` - pub async fn try_multi_get_parsed_past_object( - &self, - past_objects: Vec, - options: SuiObjectDataOptions, - ) -> SuiRpcResult> { - Ok(self - .api - .http - .try_multi_get_past_objects(past_objects, Some(options)) - .await?) - } - - /// Return a [SuiObjectResponse] based on the provided [ObjectID] and - /// [SuiObjectDataOptions], or an error upon failure. - /// - /// The [SuiObjectResponse] contains two fields: - /// 1) `data` for the object's data (see - /// [SuiObjectData](sui_json_rpc_types::SuiObjectData)), - /// 2) `error` for the error (if any) (see - /// [SuiObjectResponseError](sui_types::error::SuiObjectResponseError)). - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::str::FromStr; - /// - /// use sui_json_rpc_types::SuiObjectDataOptions; - /// use sui_sdk::SuiClientBuilder; - /// use sui_types::base_types::SuiAddress; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let address = SuiAddress::from_str("0x0000....0000")?; - /// let owned_objects = sui - /// .read_api() - /// .get_owned_objects(address, None, None, None) - /// .await?; - /// // this code example assumes that there are previous owned objects - /// let object = owned_objects - /// .data - /// .get(0) - /// .expect(&format!("No owned objects for this address {}", address)); - /// let object_data = object.data.as_ref().expect(&format!( - /// "No object data for this SuiObjectResponse {:?}", - /// object - /// )); - /// let object_id = object_data.object_id; - /// let object = sui - /// .read_api() - /// .get_object_with_options( - /// object_id, - /// SuiObjectDataOptions { - /// show_type: true, - /// show_owner: true, - /// show_previous_transaction: true, - /// show_display: true, - /// show_content: true, - /// show_bcs: true, - /// show_storage_rebate: true, - /// }, - /// ) - /// .await?; - /// Ok(()) - /// } - /// ``` - pub async fn get_object_with_options( - &self, - object_id: ObjectID, - options: SuiObjectDataOptions, - ) -> SuiRpcResult { - Ok(self.api.http.get_object(object_id, Some(options)).await?) - } - - /// Return a list of [SuiObjectResponse] from the given vector of - /// [ObjectID]s and [SuiObjectDataOptions], or an error upon failure. - /// - /// If only one object is needed, use the - /// [get_object_with_options](ReadApi::get_object_with_options) function - /// instead. - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::str::FromStr; - /// - /// use sui_json_rpc_types::SuiObjectDataOptions; - /// use sui_sdk::SuiClientBuilder; - /// use sui_types::base_types::SuiAddress; - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let address = SuiAddress::from_str("0x0000....0000")?; - /// let owned_objects = sui - /// .read_api() - /// .get_owned_objects(address, None, None, None) - /// .await?; - /// // this code example assumes that there are previous owned objects - /// let object = owned_objects - /// .data - /// .get(0) - /// .expect(&format!("No owned objects for this address {}", address)); - /// let object_data = object.data.as_ref().expect(&format!( - /// "No object data for this SuiObjectResponse {:?}", - /// object - /// )); - /// let object_id = object_data.object_id; - /// let object_ids = vec![object_id]; // and other object ids - /// let object = sui - /// .read_api() - /// .multi_get_object_with_options( - /// object_ids, - /// SuiObjectDataOptions { - /// show_type: true, - /// show_owner: true, - /// show_previous_transaction: true, - /// show_display: true, - /// show_content: true, - /// show_bcs: true, - /// show_storage_rebate: true, - /// }, - /// ) - /// .await?; - /// Ok(()) - /// } - /// ``` - pub async fn multi_get_object_with_options( - &self, - object_ids: Vec, - options: SuiObjectDataOptions, - ) -> SuiRpcResult> { - Ok(self - .api - .http - .multi_get_objects(object_ids, Some(options)) - .await?) - } - - /// Return An object's bcs content [`Vec`] based on the provided - /// [ObjectID], or an error upon failure. - pub async fn get_move_object_bcs(&self, object_id: ObjectID) -> SuiRpcResult> { - let resp = self - .get_object_with_options(object_id, SuiObjectDataOptions::default().with_bcs()) - .await? - .into_object() - .map_err(|e| { - Error::DataError(format!("Can't get bcs of object {:?}: {:?}", object_id, e)) - })?; - // unwrap: requested bcs data - let move_object = resp.bcs.unwrap(); - let raw_move_obj = move_object.try_into_move().ok_or(Error::DataError(format!( - "Object {:?} is not a MoveObject", - object_id - )))?; - Ok(raw_move_obj.bcs_bytes) - } - - /// Return the total number of transaction blocks known to server, or an - /// error upon failure. - /// - /// # Examples - /// - /// ```rust,no_run - /// use sui_sdk::SuiClientBuilder; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let total_transaction_blocks = sui.read_api().get_total_transaction_blocks().await?; - /// Ok(()) - /// } - /// ``` - pub async fn get_total_transaction_blocks(&self) -> SuiRpcResult { - Ok(*self.api.http.get_total_transaction_blocks().await?) - } - - /// Return a transaction and its effects in a [SuiTransactionBlockResponse] - /// based on its [TransactionDigest], or an error upon failure. - pub async fn get_transaction_with_options( - &self, - digest: TransactionDigest, - options: SuiTransactionBlockResponseOptions, - ) -> SuiRpcResult { - Ok(self - .api - .http - .get_transaction_block(digest, Some(options)) - .await?) - } - /// Return a list of [SuiTransactionBlockResponse] based on the given vector - /// of [TransactionDigest], or an error upon failure. - /// - /// If only one transaction data is needed, use the - /// [get_transaction_with_options](ReadApi::get_transaction_with_options) - /// function instead. - pub async fn multi_get_transactions_with_options( - &self, - digests: Vec, - options: SuiTransactionBlockResponseOptions, - ) -> SuiRpcResult> { - Ok(self - .api - .http - .multi_get_transaction_blocks(digests, Some(options)) - .await?) - } - - /// Return the [SuiCommittee] information for the provided `epoch`, or an - /// error upon failure. - /// - /// The [SuiCommittee] contains the validators list and their information - /// (name and stakes). - /// - /// The argument `epoch` is either a known epoch id or `None` for the - /// current epoch. - /// - /// # Examples - /// - /// ```rust,no_run - /// use sui_sdk::SuiClientBuilder; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let committee_info = sui.read_api().get_committee_info(None).await?; - /// Ok(()) - /// } - /// ``` - pub async fn get_committee_info( - &self, - epoch: Option>, - ) -> SuiRpcResult { - Ok(self.api.http.get_committee_info(epoch).await?) - } - - /// Return a paginated response with all transaction blocks information, or - /// an error upon failure. - pub async fn query_transaction_blocks( - &self, - query: SuiTransactionBlockResponseQuery, - cursor: Option, - limit: Option, - descending_order: bool, - ) -> SuiRpcResult { - Ok(self - .api - .http - .query_transaction_blocks(query, cursor, limit, Some(descending_order)) - .await?) - } - - /// Return the first four bytes of the chain's genesis checkpoint digest, or - /// an error upon failure. - pub async fn get_chain_identifier(&self) -> SuiRpcResult { - Ok(self.api.http.get_chain_identifier().await?) - } - - /// Return a checkpoint, or an error upon failure. - /// - /// A Sui checkpoint is a sequence of transaction sets that a quorum of - /// validators agree upon as having been executed within the Sui system. - pub async fn get_checkpoint(&self, id: CheckpointId) -> SuiRpcResult { - Ok(self.api.http.get_checkpoint(id).await?) - } - - /// Return a paginated list of checkpoints, or an error upon failure. - pub async fn get_checkpoints( - &self, - cursor: Option>, - limit: Option, - descending_order: bool, - ) -> SuiRpcResult { - Ok(self - .api - .http - .get_checkpoints(cursor, limit, descending_order) - .await?) - } - - /// Return the sequence number of the latest checkpoint that has been - /// executed, or an error upon failure. - pub async fn get_latest_checkpoint_sequence_number( - &self, - ) -> SuiRpcResult { - Ok(*self - .api - .http - .get_latest_checkpoint_sequence_number() - .await?) - } - - /// Return a stream of [SuiTransactionBlockResponse], or an error upon - /// failure. - pub fn get_transactions_stream( - &self, - query: SuiTransactionBlockResponseQuery, - cursor: Option, - descending_order: bool, - ) -> impl Stream + '_ { - stream::unfold( - (vec![], cursor, true, query), - move |(mut data, cursor, first, query)| async move { - if let Some(item) = data.pop() { - Some((item, (data, cursor, false, query))) - } else if (cursor.is_none() && first) || cursor.is_some() { - let page = self - .query_transaction_blocks( - query.clone(), - cursor, - Some(100), - descending_order, - ) - .await - .ok()?; - let mut data = page.data; - data.reverse(); - data.pop() - .map(|item| (item, (data, page.next_cursor, false, query))) - } else { - None - } - }, - ) - } - - /// Subscribe to a stream of transactions. - /// - /// This is only available through WebSockets. - pub async fn subscribe_transaction( - &self, - filter: TransactionFilter, - ) -> SuiRpcResult>> { - let Some(c) = &self.api.ws else { - return Err(Error::Subscription( - "Subscription only supported by WebSocket client.".to_string(), - )); - }; - let subscription: Subscription = - c.subscribe_transaction(filter).await?; - Ok(subscription.map(|item| Ok(item?))) - } - - /// Return a map consisting of the move package name and the normalized - /// module, or an error upon failure. - pub async fn get_normalized_move_modules_by_package( - &self, - package: ObjectID, - ) -> SuiRpcResult> { - Ok(self - .api - .http - .get_normalized_move_modules_by_package(package) - .await?) - } - - // TODO(devx): we can probably cache this given an epoch - /// Return the reference gas price, or an error upon failure. - pub async fn get_reference_gas_price(&self) -> SuiRpcResult { - Ok(*self.api.http.get_reference_gas_price().await?) - } - - /// Dry run a transaction block given the provided transaction data. Returns - /// an error upon failure. - /// - /// Simulate running the transaction, including all standard checks, without - /// actually running it. This is useful for estimating the gas fees of a - /// transaction before executing it. You can also use it to identify any - /// side-effects of a transaction before you execute it on the network. - pub async fn dry_run_transaction_block( - &self, - tx: TransactionData, - ) -> SuiRpcResult { - Ok(self - .api - .http - .dry_run_transaction_block(Base64::from_bytes(&bcs::to_bytes(&tx)?)) - .await?) - } - - /// Return the inspection of the transaction block, or an error upon - /// failure. - /// - /// Use this function to inspect the current state of the network by running - /// a programmable transaction block without committing its effects on - /// chain. Unlike - /// [dry_run_transaction_block](ReadApi::dry_run_transaction_block), - /// dev inspect will not validate whether the transaction block - /// would succeed or fail under normal circumstances, e.g.: - /// - /// - Transaction inputs are not checked for ownership (i.e. you can - /// construct calls involving objects you do not own). - /// - Calls are not checked for visibility (you can call private functions - /// on modules) - /// - Inputs of any type can be constructed and passed in, (including Coins - /// and other objects that would usually need to be constructed with a - /// move call). - /// - Function returns do not need to be used, even if they do not have - /// `drop`. - /// - /// Dev inspect's output includes a breakdown of results returned by every - /// transaction in the block, as well as the transaction's effects. - /// - /// To run an accurate simulation of a transaction and understand whether - /// it will successfully validate and run, - /// use the [dry_run_transaction_block](ReadApi::dry_run_transaction_block) - /// function instead. - pub async fn dev_inspect_transaction_block( - &self, - sender_address: SuiAddress, - tx: TransactionKind, - gas_price: Option>, - epoch: Option>, - additional_args: Option, - ) -> SuiRpcResult { - Ok(self - .api - .http - .dev_inspect_transaction_block( - sender_address, - Base64::from_bytes(&bcs::to_bytes(&tx)?), - gas_price, - epoch, - additional_args, - ) - .await?) - } - - /// Return the loaded child objects response for the provided digest, or an - /// error upon failure. - /// - /// Loaded child objects - /// ([SuiLoadedChildObject](sui_json_rpc_types::SuiLoadedChildObject)) are - /// the non-input objects that the transaction at the digest loaded - /// in response to dynamic field accesses. - pub async fn get_loaded_child_objects( - &self, - digest: TransactionDigest, - ) -> SuiRpcResult { - Ok(self.api.http.get_loaded_child_objects(digest).await?) - } - - /// Return the protocol config, or an error upon failure. - pub async fn get_protocol_config( - &self, - version: Option>, - ) -> SuiRpcResult { - Ok(self.api.http.get_protocol_config(version).await?) - } -} - -/// Coin Read API provides the functionality needed to get information from the -/// Sui network regarding the coins owned by an address. -#[derive(Debug, Clone)] -pub struct CoinReadApi { - api: Arc, -} - -impl CoinReadApi { - pub(crate) fn new(api: Arc) -> Self { - Self { api } - } - - /// Return a paginated response with the coins for the given address, or an - /// error upon failure. - /// - /// The coins can be filtered by `coin_type` (e.g., - /// 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC) - /// or use `None` for the default `Coin`. - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::str::FromStr; - /// - /// use sui_sdk::SuiClientBuilder; - /// use sui_types::base_types::SuiAddress; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let address = SuiAddress::from_str("0x0000....0000")?; - /// let coins = sui - /// .coin_read_api() - /// .get_coins(address, None, None, None) - /// .await?; - /// Ok(()) - /// } - /// ``` - pub async fn get_coins( - &self, - owner: SuiAddress, - coin_type: Option, - cursor: Option, - limit: Option, - ) -> SuiRpcResult { - Ok(self - .api - .http - .get_coins(owner, coin_type, cursor, limit) - .await?) - } - /// Return a paginated response with all the coins for the given address, or - /// an error upon failure. - /// - /// This function includes all coins. If needed to filter by coin type, use - /// the `get_coins` method instead. - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::str::FromStr; - /// - /// use sui_sdk::SuiClientBuilder; - /// use sui_types::base_types::SuiAddress; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let address = SuiAddress::from_str("0x0000....0000")?; - /// let coins = sui - /// .coin_read_api() - /// .get_all_coins(address, None, None) - /// .await?; - /// Ok(()) - /// } - /// ``` - pub async fn get_all_coins( - &self, - owner: SuiAddress, - cursor: Option, - limit: Option, - ) -> SuiRpcResult { - Ok(self.api.http.get_all_coins(owner, cursor, limit).await?) - } - - /// Return the coins for the given address as a stream. - /// - /// The coins can be filtered by `coin_type` (e.g., - /// 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC) - /// or use `None` for the default `Coin`. - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::str::FromStr; - /// - /// use sui_sdk::SuiClientBuilder; - /// use sui_types::base_types::SuiAddress; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let address = SuiAddress::from_str("0x0000....0000")?; - /// let coins = sui.coin_read_api().get_coins_stream(address, None); - /// Ok(()) - /// } - /// ``` - pub fn get_coins_stream( - &self, - owner: SuiAddress, - coin_type: Option, - ) -> impl Stream + '_ { - stream::unfold( - ( - vec![], - // cursor - None, - // has_next_page - true, - coin_type, - ), - move |(mut data, cursor, has_next_page, coin_type)| async move { - if let Some(item) = data.pop() { - Some((item, (data, cursor, /* has_next_page */ true, coin_type))) - } else if has_next_page { - let page = self - .get_coins(owner, coin_type.clone(), cursor, Some(100)) - .await - .ok()?; - let mut data = page.data; - data.reverse(); - data.pop().map(|item| { - ( - item, - (data, page.next_cursor, page.has_next_page, coin_type), - ) - }) - } else { - None - } - }, - ) - } - - /// Return a list of coins for the given address, or an error upon failure. - /// - /// Note that the function selects coins to meet or exceed the requested - /// `amount`. If that it is not possible, it will fail with an - /// insufficient fund error. - /// - /// The coins can be filtered by `coin_type` (e.g., - /// 0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC) - /// or use `None` to use the default `Coin`. - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::str::FromStr; - /// - /// use sui_sdk::SuiClientBuilder; - /// use sui_types::base_types::SuiAddress; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let address = SuiAddress::from_str("0x0000....0000")?; - /// let coins = sui - /// .coin_read_api() - /// .select_coins(address, None, 5, vec![]) - /// .await?; - /// Ok(()) - /// } - /// ``` - pub async fn select_coins( - &self, - address: SuiAddress, - coin_type: Option, - amount: u128, - exclude: Vec, - ) -> SuiRpcResult> { - let mut total = 0u128; - let coins = self - .get_coins_stream(address, coin_type) - .filter(|coin: &Coin| future::ready(!exclude.contains(&coin.coin_object_id))) - .take_while(|coin: &Coin| { - let ready = future::ready(total < amount); - total += coin.balance as u128; - ready - }) - .collect::>() - .await; - - if total < amount { - return Err(Error::InsufficientFund { address, amount }); - } - Ok(coins) - } - - /// Return the balance for the given coin type owned by address, or an error - /// upon failure. - /// - /// Note that this function sums up all the balances of all the coins - /// matching the given coin type. By default, if `coin_type` is set to - /// `None`, it will use the default `Coin`. - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::str::FromStr; - /// - /// use sui_sdk::SuiClientBuilder; - /// use sui_types::base_types::SuiAddress; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let address = SuiAddress::from_str("0x0000....0000")?; - /// let balance = sui.coin_read_api().get_balance(address, None).await?; - /// Ok(()) - /// } - /// ``` - pub async fn get_balance( - &self, - owner: SuiAddress, - coin_type: Option, - ) -> SuiRpcResult { - Ok(self.api.http.get_balance(owner, coin_type).await?) - } - - /// Return a list of balances for each coin type owned by the given address, - /// or an error upon failure. - /// - /// Note that this function groups the coins by coin type, and sums up all - /// their balances. - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::str::FromStr; - /// - /// use sui_sdk::SuiClientBuilder; - /// use sui_types::base_types::SuiAddress; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let address = SuiAddress::from_str("0x0000....0000")?; - /// let all_balances = sui.coin_read_api().get_all_balances(address).await?; - /// Ok(()) - /// } - /// ``` - pub async fn get_all_balances(&self, owner: SuiAddress) -> SuiRpcResult> { - Ok(self.api.http.get_all_balances(owner).await?) - } - - /// Return the coin metadata (name, symbol, description, decimals, etc.) for - /// a given coin type, or an error upon failure. - /// - /// # Examples - /// - /// ```rust,no_run - /// use sui_sdk::SuiClientBuilder; - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let coin_metadata = sui - /// .coin_read_api() - /// .get_coin_metadata("0x2::sui::SUI".to_string()) - /// .await?; - /// Ok(()) - /// } - /// ``` - pub async fn get_coin_metadata( - &self, - coin_type: String, - ) -> SuiRpcResult> { - Ok(self.api.http.get_coin_metadata(coin_type).await?) - } - - /// Return the total supply for a given coin type, or an error upon failure. - /// - /// # Examples - /// - /// ```rust,no_run - /// use sui_sdk::SuiClientBuilder; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let total_supply = sui - /// .coin_read_api() - /// .get_total_supply("0x2::sui::SUI".to_string()) - /// .await?; - /// Ok(()) - /// } - /// ``` - pub async fn get_total_supply(&self, coin_type: String) -> SuiRpcResult { - Ok(self.api.http.get_total_supply(coin_type).await?) - } -} - -/// Event API provides the functionality to fetch, query, or subscribe to events -/// on the Sui network. -#[derive(Clone)] -pub struct EventApi { - api: Arc, -} - -impl EventApi { - pub(crate) fn new(api: Arc) -> Self { - Self { api } - } - - /// Return a stream of events, or an error upon failure. - /// - /// Subscription is only possible via WebSockets. - /// For a list of possible event filters, see [EventFilter]. - /// - /// # Examples - /// - /// ```rust, no_run - /// use std::str::FromStr; - /// - /// use futures::StreamExt; - /// use sui_json_rpc_types::EventFilter; - /// use sui_sdk::SuiClientBuilder; - /// use sui_types::base_types::SuiAddress; - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default() - /// .ws_url("wss://rpc.mainnet.sui.io:443") - /// .build("https://fullnode.mainnet.sui.io:443") - /// .await?; - /// let mut subscribe_all = sui - /// .event_api() - /// .subscribe_event(EventFilter::All(vec![])) - /// .await?; - /// loop { - /// println!("{:?}", subscribe_all.next().await); - /// } - /// Ok(()) - /// } - /// ``` - pub async fn subscribe_event( - &self, - filter: EventFilter, - ) -> SuiRpcResult>> { - match &self.api.ws { - Some(c) => { - let subscription: Subscription = c.subscribe_event(filter).await?; - Ok(subscription.map(|item| Ok(item?))) - } - _ => Err(Error::Subscription( - "Subscription only supported by WebSocket client.".to_string(), - )), - } - } - - /// Return a list of events for the given transaction digest, or an error - /// upon failure. - pub async fn get_events(&self, digest: TransactionDigest) -> SuiRpcResult> { - Ok(self.api.http.get_events(digest).await?) - } - - /// Return a paginated response with events for the given event filter, or - /// an error upon failure. - /// - /// The ordering of the events can be set with the `descending_order` - /// argument. For a list of possible event filters, see [EventFilter]. - pub async fn query_events( - &self, - query: EventFilter, - cursor: Option, - limit: Option, - descending_order: bool, - ) -> SuiRpcResult { - Ok(self - .api - .http - .query_events(query, cursor, limit, Some(descending_order)) - .await?) - } - - /// Return a stream of events for the given event filter. - /// - /// The ordering of the events can be set with the `descending_order` - /// argument. For a list of possible event filters, see [EventFilter]. - pub fn get_events_stream( - &self, - query: EventFilter, - cursor: Option, - descending_order: bool, - ) -> impl Stream + '_ { - stream::unfold( - (vec![], cursor, true, query), - move |(mut data, cursor, first, query)| async move { - if let Some(item) = data.pop() { - Some((item, (data, cursor, false, query))) - } else if (cursor.is_none() && first) || cursor.is_some() { - let page = self - .query_events(query.clone(), cursor, Some(100), descending_order) - .await - .ok()?; - let mut data = page.data; - data.reverse(); - data.pop() - .map(|item| (item, (data, page.next_cursor, false, query))) - } else { - None - } - }, - ) - } -} - -/// Quorum API that provides functionality to execute a transaction block and -/// submit it to the fullnode(s). -#[derive(Clone)] -pub struct QuorumDriverApi { - api: Arc, -} - -impl QuorumDriverApi { - pub(crate) fn new(api: Arc) -> Self { - Self { api } - } - - /// Execute a transaction with a FullNode client. `request_type` - /// defaults to `ExecuteTransactionRequestType::WaitForLocalExecution`. - /// When `ExecuteTransactionRequestType::WaitForLocalExecution` is used, - /// but returned `confirmed_local_execution` is false, the client will - /// keep retry for WAIT_FOR_LOCAL_EXECUTION_RETRY_COUNT times. If it - /// still fails, it will return an error. - pub async fn execute_transaction_block( - &self, - tx: Transaction, - options: SuiTransactionBlockResponseOptions, - request_type: Option, - ) -> SuiRpcResult { - let (tx_bytes, signatures) = tx.to_tx_bytes_and_signatures(); - let request_type = request_type.unwrap_or_else(|| options.default_execution_request_type()); - let mut retry_count = 0; - let start = Instant::now(); - while retry_count < WAIT_FOR_LOCAL_EXECUTION_RETRY_COUNT { - let response: SuiTransactionBlockResponse = self - .api - .http - .execute_transaction_block( - tx_bytes.clone(), - signatures.clone(), - Some(options.clone()), - Some(request_type.clone()), - ) - .await?; - - match request_type { - ExecuteTransactionRequestType::WaitForEffectsCert => { - return Ok(response); - } - ExecuteTransactionRequestType::WaitForLocalExecution => { - if let Some(true) = response.confirmed_local_execution { - return Ok(response); - } else { - // If fullnode executed the cert in the network but did not confirm local - // execution, it must have timed out and hence we could retry. - retry_count += 1; - } - } - } - } - Err(Error::FailToConfirmTransactionStatus( - *tx.digest(), - start.elapsed().as_secs(), - )) - } -} - -/// Governance API provides the staking functionality. -#[derive(Debug, Clone)] -pub struct GovernanceApi { - api: Arc, -} - -impl GovernanceApi { - pub(crate) fn new(api: Arc) -> Self { - Self { api } - } - - /// Return a list of [DelegatedStake] objects for the given address, or an - /// error upon failure. - pub async fn get_stakes(&self, owner: SuiAddress) -> SuiRpcResult> { - Ok(self.api.http.get_stakes(owner).await?) - } - - /// Return the [SuiCommittee] information for the given `epoch`, or an error - /// upon failure. - /// - /// The argument `epoch` is the known epoch id or `None` for the current - /// epoch. - /// - /// # Examples - /// - /// ```rust,no_run - /// use sui_sdk::SuiClientBuilder; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// let committee_info = sui.governance_api().get_committee_info(None).await?; - /// Ok(()) - /// } - /// ``` - pub async fn get_committee_info( - &self, - epoch: Option>, - ) -> SuiRpcResult { - Ok(self.api.http.get_committee_info(epoch).await?) - } - - /// Return the latest SUI system state object on-chain, or an error upon - /// failure. - /// - /// Use this method to access system's information, such as the current - /// epoch, the protocol version, the reference gas price, the total - /// stake, active validators, and much more. See the - /// [SuiSystemStateSummary] for all the available fields. - pub async fn get_latest_sui_system_state(&self) -> SuiRpcResult { - Ok(self.api.http.get_latest_sui_system_state().await?) - } - - /// Return the reference gas price for the network, or an error upon - /// failure. - pub async fn get_reference_gas_price(&self) -> SuiRpcResult { - Ok(*self.api.http.get_reference_gas_price().await?) - } -} diff --git a/crates/sui-sdk/src/error.rs b/crates/sui-sdk/src/error.rs deleted file mode 100644 index f7ca2f8a98d..00000000000 --- a/crates/sui-sdk/src/error.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use sui_types::{ - base_types::{SuiAddress, TransactionDigest}, - error::UserInputError, -}; -use thiserror::Error; - -pub use crate::json_rpc_error::Error as JsonRpcError; - -pub type SuiRpcResult = Result; - -#[derive(Error, Debug)] -pub enum Error { - #[error(transparent)] - RpcError(#[from] jsonrpsee::core::Error), - #[error(transparent)] - JsonRpcError(JsonRpcError), - #[error(transparent)] - BcsSerialisationError(#[from] bcs::Error), - #[error(transparent)] - UserInputError(#[from] UserInputError), - #[error("Subscription error : {0}")] - Subscription(String), - #[error("Failed to confirm tx status for {0:?} within {1} seconds.")] - FailToConfirmTransactionStatus(TransactionDigest, u64), - #[error("Data error: {0}")] - DataError(String), - #[error( - "Client/Server api version mismatch, client api version : {client_version}, server api version : {server_version}" - )] - ServerVersionMismatch { - client_version: String, - server_version: String, - }, - #[error("Insufficient fund for address [{address}], requested amount: {amount}")] - InsufficientFund { address: SuiAddress, amount: u128 }, -} diff --git a/crates/sui-sdk/src/lib.rs b/crates/sui-sdk/src/lib.rs deleted file mode 100644 index 1a9c016d2cc..00000000000 --- a/crates/sui-sdk/src/lib.rs +++ /dev/null @@ -1,576 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//! The Sui Rust SDK -//! -//! It aims at providing a similar SDK functionality like the one existing for -//! [TypeScript](https://github.com/MystenLabs/sui/tree/main/sdk/typescript/). -//! Sui Rust SDK builds on top of the [JSON RPC API](https://docs.sui.io/sui-jsonrpc) -//! and therefore many of the return types are the ones specified in -//! [sui_types]. -//! -//! The API is split in several parts corresponding to different functionalities -//! as following: -//! * [CoinReadApi] - provides read-only functions to work with the coins -//! * [EventApi] - provides event related functions functions to -//! * [GovernanceApi] - provides functionality related to staking -//! * [QuorumDriverApi] - provides functionality to execute a transaction -//! block and submit it to the fullnode(s) -//! * [ReadApi] - provides functions for retrieving data about different -//! objects and transactions -//! * TransactionBuilder - -//! provides functions for building transactions -//! -//! # Usage -//! The main way to interact with the API is through the [SuiClientBuilder], -//! which returns a [SuiClient] object from which the user can access the -//! various APIs. -//! -//! ## Getting Started -//! Add the Rust SDK to the project by running `cargo add sui-sdk` in the root -//! folder of your Rust project. -//! -//! The main building block for the Sui Rust SDK is the [SuiClientBuilder], -//! which provides a simple and straightforward way of connecting to a Sui -//! network and having access to the different available APIs. -//! -//! A simple example that connects to a running Sui local network, -//! the Sui devnet, and the Sui testnet is shown below. -//! To successfully run this program, make sure to spin up a local -//! network with a local validator, a fullnode, and a faucet server -//! (see [here](https://github.com/stefan-mysten/sui/tree/rust_sdk_api_examples/crates/sui-sdk/examples#preqrequisites) for more information). -//! -//! ```rust,no_run -//! use sui_sdk::SuiClientBuilder; -//! -//! #[tokio::main] -//! async fn main() -> Result<(), anyhow::Error> { -//! let sui = SuiClientBuilder::default() -//! .build("http://127.0.0.1:9000") // provide the Sui network URL -//! .await?; -//! println!("Sui local network version: {:?}", sui.api_version()); -//! -//! // local Sui network, same result as above except using the dedicated function -//! let sui_local = SuiClientBuilder::default().build_localnet().await?; -//! println!("Sui local network version: {:?}", sui_local.api_version()); -//! -//! // Sui devnet running at `https://fullnode.devnet.io:443` -//! let sui_devnet = SuiClientBuilder::default().build_devnet().await?; -//! println!("Sui devnet version: {:?}", sui_devnet.api_version()); -//! -//! // Sui testnet running at `https://testnet.devnet.io:443` -//! let sui_testnet = SuiClientBuilder::default().build_testnet().await?; -//! println!("Sui testnet version: {:?}", sui_testnet.api_version()); -//! Ok(()) -//! } -//! ``` -//! -//! ## Examples -//! -//! For detailed examples, please check the APIs docs and the examples folder -//! in the [main repository](https://github.com/MystenLabs/sui/tree/main/crates/sui-sdk/examples). - -use std::{ - fmt::{Debug, Formatter}, - sync::Arc, - time::Duration, -}; - -use async_trait::async_trait; -use jsonrpsee::{ - core::client::ClientT, - http_client::{HeaderMap, HeaderValue, HttpClient, HttpClientBuilder}, - rpc_params, - ws_client::{WsClient, WsClientBuilder}, -}; -use move_core_types::language_storage::StructTag; -use serde_json::Value; -pub use sui_json as json; -use sui_json_rpc_api::{ - CLIENT_SDK_TYPE_HEADER, CLIENT_SDK_VERSION_HEADER, CLIENT_TARGET_API_VERSION_HEADER, -}; -pub use sui_json_rpc_types as rpc_types; -use sui_json_rpc_types::{ - ObjectsPage, SuiObjectDataFilter, SuiObjectDataOptions, SuiObjectResponse, - SuiObjectResponseQuery, -}; -use sui_transaction_builder::{DataReader, TransactionBuilder}; -pub use sui_types as types; -use sui_types::base_types::{ObjectID, ObjectInfo, SuiAddress}; - -use crate::{ - apis::{CoinReadApi, EventApi, GovernanceApi, QuorumDriverApi, ReadApi}, - error::{Error, SuiRpcResult}, -}; - -pub mod apis; -pub mod error; -pub mod json_rpc_error; -pub mod sui_client_config; -pub mod wallet_context; - -pub const SUI_COIN_TYPE: &str = "0x2::sui::SUI"; -pub const SUI_LOCAL_NETWORK_URL: &str = "http://127.0.0.1:9000"; -pub const SUI_LOCAL_NETWORK_GAS_URL: &str = "http://127.0.0.1:5003/gas"; -pub const SUI_DEVNET_URL: &str = "https://fullnode.devnet.sui.io:443"; -pub const SUI_TESTNET_URL: &str = "https://fullnode.testnet.sui.io:443"; - -/// A Sui client builder for connecting to the Sui network -/// -/// By default the `maximum concurrent requests` is set to 256 and -/// the `request timeout` is set to 60 seconds. These can be adjusted using the -/// `max_concurrent_requests` function, and the `request_timeout` function. -/// If you use the WebSocket, consider setting the `ws_ping_interval` field to a -/// value of your choice to prevent the inactive WS subscription being -/// disconnected due to proxy timeout. -/// -/// # Examples -/// -/// ```rust,no_run -/// use sui_sdk::SuiClientBuilder; -/// #[tokio::main] -/// async fn main() -> Result<(), anyhow::Error> { -/// let sui = SuiClientBuilder::default() -/// .build("http://127.0.0.1:9000") -/// .await?; -/// -/// println!("Sui local network version: {:?}", sui.api_version()); -/// Ok(()) -/// } -/// ``` -pub struct SuiClientBuilder { - request_timeout: Duration, - max_concurrent_requests: usize, - ws_url: Option, - ws_ping_interval: Option, -} - -impl Default for SuiClientBuilder { - fn default() -> Self { - Self { - request_timeout: Duration::from_secs(60), - max_concurrent_requests: 256, - ws_url: None, - ws_ping_interval: None, - } - } -} - -impl SuiClientBuilder { - /// Set the request timeout to the specified duration - pub fn request_timeout(mut self, request_timeout: Duration) -> Self { - self.request_timeout = request_timeout; - self - } - - /// Set the max concurrent requests allowed - pub fn max_concurrent_requests(mut self, max_concurrent_requests: usize) -> Self { - self.max_concurrent_requests = max_concurrent_requests; - self - } - - /// Set the WebSocket URL for the Sui network - pub fn ws_url(mut self, url: impl AsRef) -> Self { - self.ws_url = Some(url.as_ref().to_string()); - self - } - - /// Set the WebSocket ping interval - pub fn ws_ping_interval(mut self, duration: Duration) -> Self { - self.ws_ping_interval = Some(duration); - self - } - - /// Returns a [SuiClient] object connected to the Sui network running at the - /// URI provided. - /// - /// # Examples - /// - /// ```rust,no_run - /// use sui_sdk::SuiClientBuilder; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default() - /// .build("http://127.0.0.1:9000") - /// .await?; - /// - /// println!("Sui local version: {:?}", sui.api_version()); - /// Ok(()) - /// } - /// ``` - pub async fn build(self, http: impl AsRef) -> SuiRpcResult { - let client_version = env!("CARGO_PKG_VERSION"); - let mut headers = HeaderMap::new(); - headers.insert( - CLIENT_TARGET_API_VERSION_HEADER, - // in rust, the client version is the same as the target api version - HeaderValue::from_static(client_version), - ); - headers.insert( - CLIENT_SDK_VERSION_HEADER, - HeaderValue::from_static(client_version), - ); - headers.insert(CLIENT_SDK_TYPE_HEADER, HeaderValue::from_static("rust")); - - let ws = if let Some(url) = self.ws_url { - let mut builder = WsClientBuilder::default() - .max_request_body_size(2 << 30) - .max_concurrent_requests(self.max_concurrent_requests) - .set_headers(headers.clone()) - .request_timeout(self.request_timeout); - - if let Some(duration) = self.ws_ping_interval { - builder = builder.ping_interval(duration) - } - - Some(builder.build(url).await?) - } else { - None - }; - - let http = HttpClientBuilder::default() - .max_request_body_size(2 << 30) - .max_concurrent_requests(self.max_concurrent_requests) - .set_headers(headers.clone()) - .request_timeout(self.request_timeout) - .build(http)?; - - let info = Self::get_server_info(&http, &ws).await?; - - let rpc = RpcClient { http, ws, info }; - let api = Arc::new(rpc); - let read_api = Arc::new(ReadApi::new(api.clone())); - let quorum_driver_api = QuorumDriverApi::new(api.clone()); - let event_api = EventApi::new(api.clone()); - let transaction_builder = TransactionBuilder::new(read_api.clone()); - let coin_read_api = CoinReadApi::new(api.clone()); - let governance_api = GovernanceApi::new(api.clone()); - - Ok(SuiClient { - api, - transaction_builder, - read_api, - coin_read_api, - event_api, - quorum_driver_api, - governance_api, - }) - } - - /// Returns a [SuiClient] object that is ready to interact with the local - /// development network (by default it expects the Sui network to be - /// up and running at `127.0.0.1:9000`). - /// - /// For connecting to a custom URI, use the `build` function instead. - /// - /// # Examples - /// - /// ```rust,no_run - /// use sui_sdk::SuiClientBuilder; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_localnet().await?; - /// - /// println!("Sui local version: {:?}", sui.api_version()); - /// Ok(()) - /// } - /// ``` - pub async fn build_localnet(self) -> SuiRpcResult { - self.build(SUI_LOCAL_NETWORK_URL).await - } - - /// Returns a [SuiClient] object that is ready to interact with the Sui - /// devnet. - /// - /// For connecting to a custom URI, use the `build` function instead.. - /// - /// # Examples - /// - /// ```rust,no_run - /// use sui_sdk::SuiClientBuilder; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_devnet().await?; - /// - /// println!("{:?}", sui.api_version()); - /// Ok(()) - /// } - /// ``` - pub async fn build_devnet(self) -> SuiRpcResult { - self.build(SUI_DEVNET_URL).await - } - - /// Returns a [SuiClient] object that is ready to interact with the Sui - /// testnet. - /// - /// For connecting to a custom URI, use the `build` function instead. - /// - /// # Examples - /// - /// ```rust,no_run - /// use sui_sdk::SuiClientBuilder; - /// - /// #[tokio::main] - /// async fn main() -> Result<(), anyhow::Error> { - /// let sui = SuiClientBuilder::default().build_testnet().await?; - /// - /// println!("{:?}", sui.api_version()); - /// Ok(()) - /// } - /// ``` - pub async fn build_testnet(self) -> SuiRpcResult { - self.build(SUI_TESTNET_URL).await - } - - /// Return the server information as a `ServerInfo` structure. - /// - /// Fails with an error if it cannot call the RPC discover. - async fn get_server_info( - http: &HttpClient, - ws: &Option, - ) -> Result { - let rpc_spec: Value = http.request("rpc.discover", rpc_params![]).await?; - let version = rpc_spec - .pointer("/info/version") - .and_then(|v| v.as_str()) - .ok_or_else(|| { - Error::DataError("Fail parsing server version from rpc.discover endpoint.".into()) - })?; - let rpc_methods = Self::parse_methods(&rpc_spec)?; - - let subscriptions = if let Some(ws) = ws { - let rpc_spec: Value = ws.request("rpc.discover", rpc_params![]).await?; - Self::parse_methods(&rpc_spec)? - } else { - Vec::new() - }; - Ok(ServerInfo { - rpc_methods, - subscriptions, - version: version.to_string(), - }) - } - - fn parse_methods(server_spec: &Value) -> Result, Error> { - let methods = server_spec - .pointer("/methods") - .and_then(|methods| methods.as_array()) - .ok_or_else(|| { - Error::DataError( - "Fail parsing server information from rpc.discover endpoint.".into(), - ) - })?; - - Ok(methods - .iter() - .flat_map(|method| method["name"].as_str()) - .map(|s| s.into()) - .collect()) - } -} - -/// SuiClient is the basic type that provides all the necessary abstractions for -/// interacting with the Sui network. -/// -/// # Usage -/// -/// Use [SuiClientBuilder] to build a [SuiClient]. -/// -/// # Examples -/// -/// ```rust,no_run -/// use std::str::FromStr; -/// -/// use sui_sdk::{types::base_types::SuiAddress, SuiClientBuilder}; -/// -/// #[tokio::main] -/// async fn main() -> Result<(), anyhow::Error> { -/// let sui = SuiClientBuilder::default() -/// .build("http://127.0.0.1:9000") -/// .await?; -/// -/// println!("{:?}", sui.available_rpc_methods()); -/// println!("{:?}", sui.available_subscriptions()); -/// println!("{:?}", sui.api_version()); -/// -/// let address = SuiAddress::from_str("0x0000....0000")?; -/// let owned_objects = sui -/// .read_api() -/// .get_owned_objects(address, None, None, None) -/// .await?; -/// -/// println!("{:?}", owned_objects); -/// -/// Ok(()) -/// } -/// ``` -#[derive(Clone)] -pub struct SuiClient { - api: Arc, - transaction_builder: TransactionBuilder, - read_api: Arc, - coin_read_api: CoinReadApi, - event_api: EventApi, - quorum_driver_api: QuorumDriverApi, - governance_api: GovernanceApi, -} - -pub(crate) struct RpcClient { - http: HttpClient, - ws: Option, - info: ServerInfo, -} - -impl Debug for RpcClient { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "RPC client. Http: {:?}, Websocket: {:?}", - self.http, self.ws - ) - } -} - -/// ServerInfo contains all the useful information regarding the API version, -/// the available RPC calls, and subscriptions. -struct ServerInfo { - rpc_methods: Vec, - subscriptions: Vec, - version: String, -} - -impl SuiClient { - /// Returns a list of RPC methods supported by the node the client is - /// connected to. - pub fn available_rpc_methods(&self) -> &Vec { - &self.api.info.rpc_methods - } - - /// Returns a list of streaming/subscription APIs supported by the node the - /// client is connected to. - pub fn available_subscriptions(&self) -> &Vec { - &self.api.info.subscriptions - } - - /// Returns the API version information as a string. - /// - /// The format of this string is `..`, e.g., `1.6.0`, - /// and it is retrieved from the OpenRPC specification via the discover - /// service method. - pub fn api_version(&self) -> &str { - &self.api.info.version - } - - /// Verifies if the API version matches the server version and returns an - /// error if they do not match. - pub fn check_api_version(&self) -> SuiRpcResult<()> { - let server_version = self.api_version(); - let client_version = env!("CARGO_PKG_VERSION"); - if server_version != client_version { - return Err(Error::ServerVersionMismatch { - client_version: client_version.to_string(), - server_version: server_version.to_string(), - }); - }; - Ok(()) - } - - /// Returns a reference to the coin read API. - pub fn coin_read_api(&self) -> &CoinReadApi { - &self.coin_read_api - } - - /// Returns a reference to the event API. - pub fn event_api(&self) -> &EventApi { - &self.event_api - } - - /// Returns a reference to the governance API. - pub fn governance_api(&self) -> &GovernanceApi { - &self.governance_api - } - - /// Returns a reference to the quorum driver API. - pub fn quorum_driver_api(&self) -> &QuorumDriverApi { - &self.quorum_driver_api - } - - /// Returns a reference to the read API. - pub fn read_api(&self) -> &ReadApi { - &self.read_api - } - - /// Returns a reference to the transaction builder API. - pub fn transaction_builder(&self) -> &TransactionBuilder { - &self.transaction_builder - } - - /// Returns a reference to the underlying http client. - pub fn http(&self) -> &HttpClient { - &self.api.http - } - - /// Returns a reference to the underlying WebSocket client, if any. - pub fn ws(&self) -> Option<&WsClient> { - self.api.ws.as_ref() - } -} - -#[async_trait] -impl DataReader for ReadApi { - async fn get_owned_objects( - &self, - address: SuiAddress, - object_type: StructTag, - ) -> Result, anyhow::Error> { - let mut result = vec![]; - let query = Some(SuiObjectResponseQuery { - filter: Some(SuiObjectDataFilter::StructType(object_type)), - options: Some( - SuiObjectDataOptions::new() - .with_previous_transaction() - .with_type() - .with_owner(), - ), - }); - - let mut has_next = true; - let mut cursor = None; - - while has_next { - let ObjectsPage { - data, - next_cursor, - has_next_page, - } = self - .get_owned_objects(address, query.clone(), cursor, None) - .await?; - result.extend( - data.iter() - .map(|r| r.clone().try_into()) - .collect::, _>>()?, - ); - cursor = next_cursor; - has_next = has_next_page; - } - Ok(result) - } - - async fn get_object_with_options( - &self, - object_id: ObjectID, - options: SuiObjectDataOptions, - ) -> Result { - Ok(self.get_object_with_options(object_id, options).await?) - } - - /// Returns the reference gas price as a u64 or an error otherwise - async fn get_reference_gas_price(&self) -> Result { - Ok(self.get_reference_gas_price().await?) - } -} diff --git a/crates/sui-sdk/src/sui_client_config.rs b/crates/sui-sdk/src/sui_client_config.rs deleted file mode 100644 index 9eaf58f90b8..00000000000 --- a/crates/sui-sdk/src/sui_client_config.rs +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt::{Display, Formatter, Write}; - -use anyhow::anyhow; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -use sui_config::Config; -use sui_keys::keystore::{AccountKeystore, Keystore}; -use sui_types::base_types::*; - -use crate::{SuiClient, SuiClientBuilder, SUI_DEVNET_URL, SUI_LOCAL_NETWORK_URL, SUI_TESTNET_URL}; - -#[serde_as] -#[derive(Serialize, Deserialize)] -pub struct SuiClientConfig { - pub keystore: Keystore, - pub envs: Vec, - pub active_env: Option, - pub active_address: Option, -} - -impl SuiClientConfig { - pub fn new(keystore: Keystore) -> Self { - SuiClientConfig { - keystore, - envs: vec![], - active_env: None, - active_address: None, - } - } - - pub fn get_env(&self, alias: &Option) -> Option<&SuiEnv> { - if let Some(alias) = alias { - self.envs.iter().find(|env| &env.alias == alias) - } else { - self.envs.first() - } - } - - pub fn get_active_env(&self) -> Result<&SuiEnv, anyhow::Error> { - self.get_env(&self.active_env).ok_or_else(|| { - anyhow!( - "Environment configuration not found for env [{}]", - self.active_env.as_deref().unwrap_or("None") - ) - }) - } - - pub fn add_env(&mut self, env: SuiEnv) { - if !self - .envs - .iter() - .any(|other_env| other_env.alias == env.alias) - { - self.envs.push(env) - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct SuiEnv { - pub alias: String, - pub rpc: String, - pub ws: Option, -} - -impl SuiEnv { - pub async fn create_rpc_client( - &self, - request_timeout: Option, - max_concurrent_requests: Option, - ) -> Result { - let mut builder = SuiClientBuilder::default(); - if let Some(request_timeout) = request_timeout { - builder = builder.request_timeout(request_timeout); - } - if let Some(ws_url) = &self.ws { - builder = builder.ws_url(ws_url); - } - - if let Some(max_concurrent_requests) = max_concurrent_requests { - builder = builder.max_concurrent_requests(max_concurrent_requests as usize); - } - Ok(builder.build(&self.rpc).await?) - } - - pub fn devnet() -> Self { - Self { - alias: "devnet".to_string(), - rpc: SUI_DEVNET_URL.into(), - ws: None, - } - } - pub fn testnet() -> Self { - Self { - alias: "testnet".to_string(), - rpc: SUI_TESTNET_URL.into(), - ws: None, - } - } - - pub fn localnet() -> Self { - Self { - alias: "local".to_string(), - rpc: SUI_LOCAL_NETWORK_URL.into(), - ws: None, - } - } -} - -impl Display for SuiEnv { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let mut writer = String::new(); - writeln!(writer, "Active environment : {}", self.alias)?; - write!(writer, "RPC URL: {}", self.rpc)?; - if let Some(ws) = &self.ws { - writeln!(writer)?; - write!(writer, "Websocket URL: {ws}")?; - } - write!(f, "{}", writer) - } -} - -impl Config for SuiClientConfig {} - -impl Display for SuiClientConfig { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let mut writer = String::new(); - - writeln!( - writer, - "Managed addresses : {}", - self.keystore.addresses().len() - )?; - write!(writer, "Active address: ")?; - match self.active_address { - Some(r) => writeln!(writer, "{}", r)?, - None => writeln!(writer, "None")?, - }; - writeln!(writer, "{}", self.keystore)?; - if let Ok(env) = self.get_active_env() { - write!(writer, "{}", env)?; - } - write!(f, "{}", writer) - } -} diff --git a/crates/sui-sdk/tests/tests.rs b/crates/sui-sdk/tests/tests.rs deleted file mode 100644 index 86aa305de03..00000000000 --- a/crates/sui-sdk/tests/tests.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use sui_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; -use sui_types::crypto::{Ed25519SuiSignature, SignatureScheme, SuiSignatureInner}; -use tempfile::TempDir; -#[test] -fn mnemonic_test() { - let temp_dir = TempDir::new().unwrap(); - let keystore_path = temp_dir.path().join("sui.keystore"); - let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - let (address, phrase, scheme) = keystore - .generate_and_add_new_key(SignatureScheme::ED25519, None, None, None) - .unwrap(); - - let keystore_path_2 = temp_dir.path().join("sui2.keystore"); - let mut keystore2 = Keystore::from(FileBasedKeystore::new(&keystore_path_2).unwrap()); - let imported_address = keystore2 - .import_from_mnemonic(&phrase, SignatureScheme::ED25519, None) - .unwrap(); - assert_eq!(scheme.flag(), Ed25519SuiSignature::SCHEME.flag()); - assert_eq!(address, imported_address); -} - -#[test] -fn keystore_display_test() -> Result<(), anyhow::Error> { - let temp_dir = TempDir::new().unwrap(); - let keystore_path = temp_dir.path().join("sui.keystore"); - let keystore = Keystore::from(FileBasedKeystore::new(&keystore_path).unwrap()); - assert!(keystore.to_string().contains("sui.keystore")); - assert!(!keystore.to_string().contains("keys:")); - Ok(()) -} diff --git a/crates/sui-simulator/Cargo.toml b/crates/sui-simulator/Cargo.toml deleted file mode 100644 index 5d2f864250c..00000000000 --- a/crates/sui-simulator/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "sui-simulator" -version = "0.7.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -move-package.workspace = true - -sui-framework.workspace = true -sui-move-build.workspace = true -sui-types.workspace = true -tempfile.workspace = true -tracing.workspace = true -anemo.workspace = true -anemo-tower.workspace = true -narwhal-network.workspace = true -fastcrypto = { workspace = true, features = ["copy_key"] } -telemetry-subscribers.workspace = true -tower.workspace = true -lru.workspace = true -rand.workspace = true -serde.workspace = true -bcs.workspace = true - -[target.'cfg(msim)'.dependencies] -msim.workspace = true diff --git a/crates/sui-simulator/README.md b/crates/sui-simulator/README.md deleted file mode 100644 index 74e75ece526..00000000000 --- a/crates/sui-simulator/README.md +++ /dev/null @@ -1,277 +0,0 @@ - -# Sui Simulation Testing - -This document outlines what the simulator used by `cargo simtest` enables, how it works, how to write sim tests, -and outlines some future work. - -## What its for: - -Currently, the simulator: - -- Provides deterministic, randomized execution of an entire Sui network in a single process. -- Simulates network latency and packet loss as desired. - -This allows us to: - -- Run tests under adverse network conditions, including high latency, packet loss, and total partitions. -- Run many iterations of tests with different starting seeds, to attempt to expose rare bugs. -- Reproduce bugs easily, once found, by re-running the test with a given seed. - -## How it works: - -The code for the simulator itself lives in the https://github.com/MystenLabs/mysten-sim repository. -It has the following main components: - -1. A [runtime](https://github.com/MystenLabs/mysten-sim/blob/main/msim/src/sim/runtime/mod.rs) which provides: - - A "node" context for all running tasks. The node is a simulated machine, which can be killed, restarted, or paused. - - A randomized but deterministic executor. - - Simulated clock facilities, including timers, sleep(), etc. - - A global, seeded PRNG used to provide all random behavior throughout the simulator. - -1. A network simulator, which delivers network messages between nodes, and can inject latency and packet loss. - -1. An API-compatible replacement for tokio. - - Most facilities from `tokio::runtime` and `tokio::time` are delegated back to the simulator runtime. - - Custom implementations of the `tokio::net::Tcp*` structs are provided to interface with the network simulator. - - Most other pieces of tokio (e.g. `sync`) did not need to be re-implemented because they don't interface with the runtime or the network. These are simply re-exported as is. - - A minimal [fork of tokio](https://github.com/mystenmark/tokio-madsim-fork) is required in order to expose certain internals to the simulator. This fork has very few modifications, which were written to be easily rebaseable when new tokio releases come out. - -1. A library of interceptor functions which intercept various posix API calls in order to enforce determinism throughout the test. These include: - - `getrandom()`, `getentropy()` - intercepted and delegated to the simulator PRNG. - - Various [socket api calls](https://github.com/MystenLabs/mysten-sim/blob/main/msim/src/sim/net/mod.rs#L195), which intercept networking operations and route them through the network simulator. It was necessary to do this at a very low level because [Quinn](https://github.com/quinn-rs/quinn) does its UDP I/O via direct `libc::` calls rather than using `tokio::net::UdpSocket`. - - `mach_absolute_time()`, `clock_gettime()`: Intercepted to provide deterministic high-resolution timing behavior. - - TODO: `gettimeofday()`: We would like to intercept this to provide deterministic wall-clock operations (e.g. on dates, etc). However, intercepting this currently breaks RocksDB. - - This interception behavior is in effect only in threads that have explicitly enabled it, which generally includes the main test thread only. In other threads, the interceptors delegate the call to the system library implementation via `dlsym()`. See implementation [here](https://github.com/MystenLabs/mysten-sim/blob/main/msim/src/sim/intercept.rs#L34-L48). - -1. Procedural macros that replace `#[tokio::test]` and run test code inside a testing environment. These are `#[sui_test]` and `#[sim_test]` and are documented below. The test harness created by these macros initializes the simulator runtime with a starting seed, generates the simulator configuration, and runs the test inside a newly created thread. The test must be run in its own thread in order to provide each test case with fresh thread local storage. - - -## How to run sim tests - -First, you'll have to install the `simtest` sub-command by running: - - $ ./scripts/simtest/install.sh - -You can then run tests by doing: - - $ cargo simtest - -The simtest command calls `cargo nextest`, so you can add any valid `nextest` option to the command line. - -`cargo simtest` also reads the following environment variables: - -- `MSIM_TEST_SEED` - the random seed for the global PRNG. Must be a positive decimal integer that fits into a `u64`. The default value is `1`. - -- `MSIM_TEST_NUM` - the number of times to repeat each test. Each repetition of a test is done with a different random seed, starting from the value of `MSIM_TEST_SEED` for the first repetition. The next seed is computed using the following function: - - fn next_seed(seed: u64) -> u64 { - use rand::Rng; - rand::GlobalRng::new_with_seed(seed).gen::() - } - - This means that if you run these two commands: - - $ MSIM_TEST_SEED=1 MSIM_TEST_NUM=10 cargo simtest - $ MSIM_TEST_SEED=2 MSIM_TEST_NUM=10 cargo simtest - - No two iterations will have the same seed (with very high probability). - -- `MSIM_TEST_CHECK_DETERMINISM` - if set, the specified tests will be run twice, and the framework will verify that the test executes identically in both runs. (This check can also be done by defining a test case with: `#[sim_test(check_determinism)]`.). *Note: Many existing tests in sui do not pass this check, which runs the test case twice in the same process, although those same tests do execute identically if run twice in separate processes. This is a bug, is most likely due to tests sharing static storage or on-disk state, and will hopefully be fixed shortly.* - - -## How to write simulation tests: - -Simulation tests are declared in one of the following two ways: - - using sui_macros::*; - - #[sui_test] - async fn test1() { - // A test that will run using `#[tokio::test]` when run via `cargo nextest`, or - // else a simulator test when run via `cargo simtest`. - } - - #[sim_test] - async fn test2() { - // A test that will be ignored when run via `cargo nextest`, and only run - // via `cargo simtest`. - } - -The `#[sim_test]` proc macro also takes a number of arguments, described below. - -The easiest way to write tests that run in the simulation testing framework is to use [SwarmBuilder](https://github.com/MystenLabs/sui/blob/main/crates/sui-swarm/src/memory/swarm.rs#L47) to start your validators. -This is most often called indirectly via `start_test_network` in the test-utils crate. -Swarm will create one simulator node (i.e. a simulated machine) per validator, and each validator will have its own unique IP address. - -If you use Swarm, you usually will not have to write any code that is aware of the fact that it is running in the simulator. -However, the fact that the validators are running on unique simulator nodes means you will be able to add network latency, packet loss, and partitions to your test later on. - -### `SuiNodeHandle` - -Swarm assumes a level of encapsulation that reflects what client code would actually experience in production. -In other words, the only way to communicate with the validators when using Swarm is via the network. -However, we have many tests that create validators and manipulate them more directly. -https://github.com/MystenLabs/sui/blob/main/crates/sui/tests/checkpoints_tests.rs is a good example of this. - -In these tests, the test code is able to break the simulator abstraction and directly manipulate the state of remote validators. -Yet, the validators are still running on simulated nodes. -This can cause problems if the test code spawns a task on behalf of a remote validator. -The spawned task will appear to the simulator to be executing inside the client node rather than the validator node. -If that spawned task initiates a network connection, it will appear to originate from the client node rather than the validator node. - -To address this, most such test code launches validators via the `spawn_test_authorities` function in the `test-utils` carate, which returns `Vec` rather than `Vec`. -`SuiNodeHandle` hides the `SuiNode` from the test code. -It can only be accessed as follows: - - handle.with(|node| { - let state = node.state(); - do_stuff_to_state(state); - }); - -Or in the case of async code: - - handle.with_async(|node| async move { - let state = node.state(); - do_async_stuff_to_state(state).await; - }).await; - -(`with_mut` and `with_mut_async` are also available). - -`SuiNodeHandle` runs the provided callbacks/futures inside the context of the appropriate simulator node, so that network requests, spawned tasks, etc continue running in the correct context. - -Note that it is trivial to exfiltrate state from the remote node, e.g.: - - let node_state = handle.with(|node| { - node.state() - }); - - // Never do this! - spawn_task_on_state_in_client_node(node_state); - -It's not feasible to completely prevent this from happening - the API is just designed to make the correct thing as easy as possible. - -Also, the world will not end if you break this rule. You just might see confusing behavior in your tests. - -### The #[sim_test] macro - -`#[sim_test]` currently accepts two arguments: - -- `config = "config_expr"` - This argument accepts a string which will be evaluated as an expression that returns the configuration for the test. Generally, you should make this a function call, and then define the function to return the config. The function must return a type that can implements `Into` - the most common choice is `SimConfig`, but `Vec` and `Vec<(usize /* repeat count */, SimConfig)>` are also supported by default. See https://github.com/MystenLabs/mysten-sim/blob/main/msim/src/sim/config.rs for the `TestConfig` implementation. - -- `check_determinism` - If set, the framework will run the test twice, and verify that it executes identically each time. (It does this by keeping a log which contains an entry for every call to the PRNG. Each entry contains a hash of the value yielded by the PRNG at that point + the current time.). Tests with `check_determinism` are usually for testing the framework itself, so you probably won't need to use this. - -### Configuring the network: - -Network latency and packet loss can be configured using [SimConfig](https://github.com/MystenLabs/mysten-sim/blob/main/msim/src/sim/config.rs#L8), which is re-exported from this crate as `sui_simulator::config::SimConfig`. - -To configure a test, you write: - - fn my_config() -> SimConfig { - ... - } - - #[sim_test(config = "my_config()")] - async fn test_case() { - ... - } - -A vector a SimConfigs can also be returned, in order to run the same test under multiple configurations. -For instance, you might do: - - fn test_scenarios -> Vec { - vec![ - fast_network_config(), // low latency - slow_network_config(), // high latency - lossy_network_config(), // packet loss - ] - } - - #[sim_test(config = "test_scenarios()")] - async fn test_case() { - ... - } - -Documentation of network configuration is not finished yet, but reading the code for the [NetworkConfig](https://github.com/MystenLabs/mysten-sim/blob/main/msim/src/sim/net/config.rs#L221) should be very instructive. - -There is a small but growing library of functions for building network configs in [sui_simulator::configs](https://github.com/MystenLabs/sui/blob/main/crates/sui-simulator/src/lib.rs). - -There are also some examples of network configuration at https://github.com/MystenLabs/sui/blob/main/crates/sui-benchmark/tests/simtest.rs#L52. - -### The `nondeterministic!` macro - -Occasionally a test needs an escape hatch from its deterministic environment. -The most common such case is when creating a temporary directory. -For these situations, the `nondeterministic!` macro is provided. -It can be used to evaluate any expression in another thread, in which the system interceptor functions (e.g. `getrandom()`) are disabled. -For example: - - let path = dir.join(format!("DB_{:?}", nondeterministic!(ObjectID::random()))); - -Without the `nondeterministic!` macro, this code could generate the same path in two different tests (each test is started with the same seed). - -## Flaky tests - -One of the benefits of deterministic simulation is that it eliminates flaky tests. -However, that is a half truth: The simulator framework tries to guarantee that a given test binary will produce the exact same behavior when run twice with the same seed. -This means that in general, tests shouldn't be flaky in the usual sense. -If they fail once, retrying them won't help. -Similarly, if they pass once (at a given commit), they should never fail at that commit. - -However, tests may be "intrinsically flaky" - for instance they may be dependent on precise timing. -As a reductio, you could imagine a test that simply samples a random number at some point, and fails if is greater than a threshold. -This test will either fail or pass repeatably when run with the same seed at the same commit. -However, that test is obviously flaky by its nature. - -Further, the simulator framework is unavoidably very susceptible to butterfly effects - almost any event (e.g. spawning a new task, sending data over the network, sampling a random number) will cause every event that comes later to play out differently. -Network messages will have different delays, tasks will execute in a different order, random samples will change. - -This means that almost any code change could cause a totally unrelated flaky test to suddenly start failing due to butterfly effects. -In such cases, the blame goes to the test that started failing - it was clearly passing by chance only. -The good news is that because the system is deterministic, the flaky test can usually be debugged quickly. - -### How to fix a flaky test - -If you find a flaky test, here are some tips on how to start. -First, ascertain that the test fails repeatedly when run in isolation, e.g.: - - $ cargo simtest my_flaky_test - -If it fails when run *en masse*, but passes when run individually (or vice versa) then there may be a test isolation failure. -Test isolation failures are often due to filesystem or static memory access, or may be simulator bugs. - -Assuming that the test does fail repeatably in isolation, you can try the test with several different seeds: - - - $ MSIM_TEST_SEED=XXX cargo simtest my_flaky_test - -And see how often if passes/fails. -Note which seeds cause the test to pass, and which cause it to fail - it may be helpful to compare log output from passing and failing runs to see how they differ, and between pairs of passing or failing runs to see how they are alike. - -**Do not forget that the test may not be to blame!** -Your code may be just be buggy! -In other words, flaky code may also cause flaky tests. - -It's impossible to list every possible cause of flakiness in a document, but the best place to start looking is at anything timing related, especially hard-coded delays in the test. -n t -Once you have found the bug or the source of the flakiness, you can validator your fix by running: - - $ MSIM_TEST_NUM=20 cargo simtest my_flaky_test - -This will run your test 20 times with different seeds. -Feel free to increase this number - theoretically working code should work no matter how many times you repeat the test, but you probably don't have time for more than a few dozen iterations. - -(Soon, we will add a nightly workflow that runs all tests with a high iteration count in order to pro-actively find bugs and flaky tests.) - -## Reproducing failures - -The point of having a deterministic execution environment for tests is that failures can be reproduced easily once found. - -When tests fail, they print out a random seed that you can use to reproduce the failure. -In normal CI runs, this seed should always be `1` (the default value). -However, when a test is run with a higher iteration count, the reported seed will be some large random number. -Ideally you should be able to immediately reproduce the failure by running a single iteration of the test with the given seed. - -*Currently, this feature is in progress due to some isolation failures in the simulator framework that I am trying to track down.* - -**Linux vs Mac**: There is one big caveat here, which is that we don't have identical execution across different platforms. This may be impossible to achieve due to `#[cfg(target_os = xxx)]` attributes in our dependencies. Therefore, even once test re-execution is fully supported, it may be necessary to use linux (perhaps via a local docker container) to reproduce failures found on our CI machines. diff --git a/crates/sui-simulator/src/lib.rs b/crates/sui-simulator/src/lib.rs deleted file mode 100644 index 3988d10a49c..00000000000 --- a/crates/sui-simulator/src/lib.rs +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[cfg(msim)] -use std::hash::Hasher; -use std::sync::atomic::{AtomicUsize, Ordering}; - -// Re-export things used by sui-macros -pub use ::rand as rand_crate; -pub use anemo; -pub use anemo_tower; -pub use fastcrypto; -pub use lru; -pub use move_package; -#[cfg(msim)] -pub use msim::*; -pub use narwhal_network; -pub use sui_framework; -pub use sui_move_build; -pub use sui_types; -pub use telemetry_subscribers; -pub use tempfile; -pub use tower; - -#[cfg(msim)] -pub mod configs { - use std::{collections::HashMap, ops::Range, time::Duration}; - - use msim::*; - use tracing::info; - - fn ms_to_dur(range: Range) -> Range { - Duration::from_millis(range.start)..Duration::from_millis(range.end) - } - - /// A network with constant uniform latency. - pub fn constant_latency_ms(latency: u64) -> SimConfig { - uniform_latency_ms(latency..(latency + 1)) - } - - /// A network with latency sampled uniformly from a range. - pub fn uniform_latency_ms(range: Range) -> SimConfig { - let range = ms_to_dur(range); - SimConfig { - net: NetworkConfig { - latency: LatencyConfig { - default_latency: LatencyDistribution::uniform(range), - ..Default::default() - }, - ..Default::default() - }, - } - } - - /// A network with bimodal latency. - pub fn bimodal_latency_ms( - // The typical latency. - baseline: Range, - // The exceptional latency. - degraded: Range, - // The frequency (from 0.0 to 1.0) with which the exceptional distribution is sampled. - degraded_freq: f64, - ) -> SimConfig { - let baseline = ms_to_dur(baseline); - let degraded = ms_to_dur(degraded); - SimConfig { - net: NetworkConfig { - latency: LatencyConfig { - default_latency: LatencyDistribution::bimodal( - baseline, - degraded, - degraded_freq, - ), - ..Default::default() - }, - ..Default::default() - }, - } - } - - /// Select from among a number of configs using the SUI_SIM_CONFIG env var. - pub fn env_config( - // Config to use when SUI_SIM_CONFIG is not set. - default: SimConfig, - // List of (&str, SimConfig) pairs - the SimConfig associated with the value - // of the SUI_SIM_CONFIG var is chosen. - env_configs: impl IntoIterator, - ) -> SimConfig { - let mut env_configs = HashMap::<&'static str, SimConfig>::from_iter(env_configs); - if let Some(env) = std::env::var("SUI_SIM_CONFIG").ok() { - if let Some(cfg) = env_configs.remove(env.as_str()) { - info!("Using test config for SUI_SIM_CONFIG={}", env); - cfg - } else { - panic!( - "No config found for SUI_SIM_CONFIG={}. Available configs are: {:?}", - env, - env_configs.keys() - ); - } - } else { - info!("Using default test config"); - default - } - } -} - -thread_local! { - static NODE_COUNT: AtomicUsize = AtomicUsize::new(0); -} - -pub struct NodeLeakDetector(()); - -impl NodeLeakDetector { - pub fn new() -> Self { - NODE_COUNT.with(|c| c.fetch_add(1, Ordering::SeqCst)); - Self(()) - } - - pub fn get_current_node_count() -> usize { - NODE_COUNT.with(|c| c.load(Ordering::SeqCst)) - } -} - -impl Default for NodeLeakDetector { - fn default() -> Self { - Self::new() - } -} - -impl Drop for NodeLeakDetector { - fn drop(&mut self) { - NODE_COUNT.with(|c| c.fetch_sub(1, Ordering::SeqCst)); - } -} - -#[cfg(not(msim))] -#[macro_export] -macro_rules! return_if_killed { - () => {}; -} - -#[cfg(msim)] -pub fn current_simnode_id() -> msim::task::NodeId { - msim::runtime::NodeHandle::current().id() -} - -#[cfg(msim)] -pub mod random { - use std::{cell::RefCell, collections::HashSet, hash::Hash}; - - use rand_crate::{rngs::SmallRng, thread_rng, Rng, SeedableRng}; - use serde::Serialize; - - use super::*; - - /// Given a value, produce a random probability using the value as a seed, - /// with an additional seed that is constant only for the current test - /// thread. - pub fn deterministic_probability(value: T, chance: f32) -> bool { - thread_local! { - // a random seed that is shared by the whole test process, so that equal `value` - // inputs produce different outputs when the test seed changes - static SEED: u64 = thread_rng().gen(); - } - - chance - > SEED.with(|seed| { - let mut hasher = std::collections::hash_map::DefaultHasher::new(); - seed.hash(&mut hasher); - value.hash(&mut hasher); - let mut rng = SmallRng::seed_from_u64(hasher.finish()); - rng.gen_range(0.0..1.0) - }) - } - - /// Like deterministic_probability, but only returns true once for each - /// unique value. May eventually consume all memory if there are a large - /// number of unique, failing values. - pub fn deterministic_probability_once(value: T, chance: f32) -> bool { - thread_local! { - static FAILING_VALUES: RefCell)>> = RefCell::new(HashSet::new()); - } - - let bytes = bcs::to_bytes(&value).unwrap(); - let key = (current_simnode_id(), bytes); - - FAILING_VALUES.with(|failing_values| { - let mut failing_values = failing_values.borrow_mut(); - if failing_values.contains(&key) { - false - } else if deterministic_probability(value, chance) { - failing_values.insert(key); - true - } else { - false - } - }) - } -} diff --git a/crates/sui-single-node-benchmark/Cargo.toml b/crates/sui-single-node-benchmark/Cargo.toml deleted file mode 100644 index 54b80ec35b0..00000000000 --- a/crates/sui-single-node-benchmark/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -name = "sui-single-node-benchmark" -version = "0.1.0" -edition = "2021" -publish = false -license = "Apache-2.0" - -[dependencies] -move-binary-format.workspace = true -move-bytecode-utils.workspace = true -move-core-types.workspace = true -move-package.workspace = true -sui-config.workspace = true -sui-core = { workspace = true, features = ["test-utils"] } -sui-move-build.workspace = true -sui-test-transaction-builder.workspace = true -sui-transaction-checks.workspace = true -sui-types = { workspace = true, features = ["test-utils"] } -sui-storage.workspace = true - -async-trait.workspace = true -bcs.workspace = true -clap.workspace = true -fs_extra.workspace = true -futures.workspace = true -prometheus.workspace = true -once_cell.workspace = true -serde = { version = "1.0.190", features = ["derive"] } -serde_json.workspace = true -strum.workspace = true -strum_macros.workspace = true -telemetry-subscribers.workspace = true -tokio = { workspace = true, features = ["full", "tracing", "test-util"] } -tracing.workspace = true - -[dev-dependencies] -sui-macros.workspace = true -sui-protocol-config.workspace = true -sui-simulator.workspace = true diff --git a/crates/sui-single-node-benchmark/README.md b/crates/sui-single-node-benchmark/README.md deleted file mode 100644 index f9ad88eb77d..00000000000 --- a/crates/sui-single-node-benchmark/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# Sui Single Node Benchmark - -This crate contains a binary for performance benchmarking a single Sui node. -Upon running the binary, the node will instantiate a standalone `AuthorityState`, and submit -executable transactions to it in parallel. We then measure the time it takes for it to finish -executing all the transactions. - -## Usage -To run the benchmark, you can simply run the following command: -``` -cargo run --release --bin sui-single-node-benchmark -- ptb -``` -By default, it generates 50,0000 transactions, which can be changed using `--tx-count`. Each transaction will contain an empty PTB without any command (i.e. essentially a nop transaction). - -### PTB benchmark workloads -When running the PTB benchmark, one can adjust the workload to stress test different parts -of the execution engine: -- `--num-transfers`: this specifies number of transfers made per transaction. Default to 0. -- `--use-native-transfer`: this is false by default, which means we use Move call to transfer objects. When specified, we will use the native TransferObject command without invoking Move to transfer objects. -- `--num-dynamic-fields`: this specifies number of dynamic fields read by each transaction. Default to 0. -- `--computation`: this specifies computation intensity. An increase by 1 means 100 more loop iterations in Fibonacci computation. Default to 0. - -### Publish benchmark workloads -WIP (please refer to smoke_tests to see how its setup) - -### Components -By default, the benchmark will use the `AuthorityState::try_execute_immediately` entry function, -which includes the execution layer as well as the interaction with the DB. This is equivalent to running: -``` -cargo run --release --bin sui-single-node-benchmark -- --component baseline ptb -``` -The benchmark supports various component: -- `baseline`: this is the default component, which includes the execution layer as well as the interaction with the DB. -- `execution-only`: compared to baseline, this doesn't interact with RocksDB at all, and only does execution. -- `with-tx-manager`: on top of baseline, it schedules transactions into the transaction manager, instead of executing them immediately. It also goes through the execution driver. -- `validator-without-consensus`: in this mode, transactions are sent to the `handle_certificate` GRPC entry point of the validator service. On top of `with-tx-manager`, it also includes the verification of the certificate. -- `validator-with-fake-consensus`: in this mode, on top of `validator-without-consensus`, it also submits the transactions to a simple consensus layer, which sequences transactions in the order as it receives it directly back to the store. It covers part of the cost in consensus handler. The commit size can be controlled with `--checkpoint-size`. -- `txn-signing`: in this mode, instead of executing transactions, we only benchmark transactions signing. -- `checkpoint-executor`: in this mode, we benchmark how long it takes for the checkpoint executor to execute all checkpoints (i.e. all transactions in them) for the entire epoch. We first construct transactions and effects by actually executing them, and revert them as if they were never executed, construct checkpoints using the results, and then start the checkpoint executor. The size of checkpoints can be controlled with `--checkpoint-size`. - - -### Profiling -If you are interested in profiling Sui, you can start the benchmark, wait for it to print out "Started execution...", and then attach a profiler to the process. diff --git a/crates/sui-single-node-benchmark/move_package/Move.toml b/crates/sui-single-node-benchmark/move_package/Move.toml deleted file mode 100644 index b90da5866ef..00000000000 --- a/crates/sui-single-node-benchmark/move_package/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "MoveBenchmark" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../sui-framework/packages/sui-framework" } - -[addresses] -move_benchmark = "0x0" \ No newline at end of file diff --git a/crates/sui-single-node-benchmark/src/command.rs b/crates/sui-single-node-benchmark/src/command.rs deleted file mode 100644 index 06e37d779d9..00000000000 --- a/crates/sui-single-node-benchmark/src/command.rs +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::path::PathBuf; - -use clap::{Parser, Subcommand, ValueEnum}; -use strum_macros::EnumIter; - -#[derive(Parser)] -#[clap( - name = "sui-single-node-benchmark", - about = "Benchmark a single validator node", - rename_all = "kebab-case", - author, - version -)] -pub struct Command { - #[arg( - long, - default_value_t = 500000, - help = "Number of transactions to submit" - )] - pub tx_count: u64, - #[arg( - long, - default_value_t = 100, - help = "Number of transactions in a consensus commit/checkpoint" - )] - pub checkpoint_size: usize, - #[arg( - long, - help = "Whether to print out a sample transaction and effects that is going to be benchmarked on" - )] - pub print_sample_tx: bool, - #[arg( - long, - default_value_t = false, - help = "If true, skip signing on the validators, instead, creating certificates directly using validator secrets" - )] - pub skip_signing: bool, - #[arg( - long, - default_value = "baseline", - ignore_case = true, - help = "Which component to benchmark" - )] - pub component: Component, - #[clap(subcommand)] - pub workload: WorkloadKind, -} - -#[derive(Copy, Clone, EnumIter, ValueEnum)] -pub enum Component { - ExecutionOnly, - /// Baseline includes the execution and storage layer only. - Baseline, - /// On top of Baseline, this schedules transactions through the transaction - /// manager. - WithTxManager, - /// This goes through the `handle_certificate` entry point on - /// authority_server, which includes certificate verification, - /// transaction manager, as well as a noop consensus layer. The noop - /// consensus layer does absolutely nothing when receiving a transaction in - /// consensus. - ValidatorWithoutConsensus, - /// Similar to ValidatorWithNoopConsensus, but the consensus layer contains - /// a fake consensus protocol that basically sequences transactions in - /// order. It then verify the transaction and store the sequenced - /// transactions into the store. It covers the consensus-independent - /// portion of the code in consensus handler. - ValidatorWithFakeConsensus, - /// Benchmark only validator signing component: `handle_transaction`. - TxnSigning, - /// Benchmark the checkpoint executor by constructing a full epoch of - /// checkpoints, execute all transactions in them and measure time. - CheckpointExecutor, -} - -#[derive(Subcommand, Clone)] -pub enum WorkloadKind { - PTB { - #[arg( - long, - default_value_t = 0, - help = "Number of address owned input objects per transaction.\ - This represents the amount of DB reads per transaction prior to execution." - )] - num_transfers: u64, - #[arg( - long, - default_value_t = false, - help = "When transferring an object, whether to use native TransferObjecet command, or to use Move code for the transfer" - )] - use_native_transfer: bool, - #[arg( - long, - default_value_t = 0, - help = "Number of dynamic fields read per transaction.\ - This represents the amount of runtime DB reads per transaction during execution." - )] - num_dynamic_fields: u64, - #[arg( - long, - default_value_t = 0, - help = "Computation intensity per transaction.\ - The transaction computes the n-th Fibonacci number \ - specified by this parameter * 100." - )] - computation: u8, - }, - Publish { - #[arg( - long, - help = "Path to the manifest file that describe the package dependencies.\ - Follow examples in the tests directory to see how to set up the manifest file.\ - The manifest file is a json file that contains a list of dependent packages that need to\ - be published first, as well as the root package that will be benchmarked on. Each package\ - can be either in source code or bytecode form. If it is in source code form, the benchmark\ - will compile the package first before publishing it." - )] - manifest_file: PathBuf, - }, -} - -impl WorkloadKind { - pub(crate) fn gas_object_num_per_account(&self) -> u64 { - match self { - // Each transaction will always have 1 gas object, plus the number of owned objects that - // will be transferred. - WorkloadKind::PTB { num_transfers, .. } => *num_transfers + 1, - WorkloadKind::Publish { .. } => 1, - } - } -} diff --git a/crates/sui-single-node-benchmark/src/lib.rs b/crates/sui-single-node-benchmark/src/lib.rs deleted file mode 100644 index 1f3e2ed8542..00000000000 --- a/crates/sui-single-node-benchmark/src/lib.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use crate::{benchmark_context::BenchmarkContext, command::Component, workload::Workload}; - -pub(crate) mod benchmark_context; -pub mod command; -pub(crate) mod mock_account; -pub(crate) mod mock_consensus; -pub(crate) mod mock_storage; -pub(crate) mod single_node; -pub(crate) mod tx_generator; -pub mod workload; - -/// Benchmark a given workload on a specified component. -/// The different kinds of workloads and components can be found in command.rs. -/// \checkpoint_size represents both the size of a consensus commit, and size of -/// a checkpoint if we are benchmarking the checkpoint. -pub async fn run_benchmark( - workload: Workload, - component: Component, - checkpoint_size: usize, - print_sample_tx: bool, - skip_signing: bool, -) { - let mut ctx = BenchmarkContext::new( - workload.clone(), - component, - checkpoint_size, - print_sample_tx, - ) - .await; - let tx_generator = workload.create_tx_generator(&mut ctx).await; - let transactions = ctx.generate_transactions(tx_generator).await; - match component { - Component::TxnSigning => { - ctx.benchmark_transaction_signing(transactions, print_sample_tx) - .await; - } - Component::CheckpointExecutor => { - ctx.benchmark_checkpoint_executor(transactions, checkpoint_size) - .await; - } - Component::ExecutionOnly => { - ctx.benchmark_transaction_execution_in_memory(transactions, print_sample_tx) - .await; - } - _ => { - ctx.benchmark_transaction_execution(transactions, print_sample_tx, skip_signing) - .await; - } - } -} diff --git a/crates/sui-single-node-benchmark/src/main.rs b/crates/sui-single-node-benchmark/src/main.rs deleted file mode 100644 index ce1a21a095c..00000000000 --- a/crates/sui-single-node-benchmark/src/main.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use clap::Parser; -use sui_single_node_benchmark::{command::Command, run_benchmark, workload::Workload}; - -#[tokio::main] -async fn main() { - let _guard = telemetry_subscribers::TelemetryConfig::new() - .with_log_level("off,sui_single_node_benchmark=info") - .with_env() - .init(); - - let args = Command::parse(); - run_benchmark( - Workload::new(args.tx_count, args.workload), - args.component, - args.checkpoint_size, - args.print_sample_tx, - args.skip_signing, - ) - .await; - - if std::env::var("TRACE_FILTER").is_ok() { - println!("Sleeping for 60 seconds to allow tracing to flush."); - println!("You can ctrl-c to exit once you see trace data appearing in grafana"); - tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; - } -} diff --git a/crates/sui-single-node-benchmark/src/workload.rs b/crates/sui-single-node-benchmark/src/workload.rs deleted file mode 100644 index 29e194c93de..00000000000 --- a/crates/sui-single-node-benchmark/src/workload.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{path::PathBuf, sync::Arc}; - -use sui_test_transaction_builder::PublishData; - -use crate::{ - benchmark_context::BenchmarkContext, - command::WorkloadKind, - tx_generator::{MoveTxGenerator, PackagePublishTxGenerator, TxGenerator}, -}; - -#[derive(Clone)] -pub struct Workload { - pub tx_count: u64, - pub workload_kind: WorkloadKind, -} - -impl Workload { - pub fn new(tx_count: u64, workload_kind: WorkloadKind) -> Self { - Self { - tx_count, - workload_kind, - } - } - - pub(crate) fn num_accounts(&self) -> u64 { - self.tx_count - } - - pub(crate) fn gas_object_num_per_account(&self) -> u64 { - self.workload_kind.gas_object_num_per_account() - } - - pub(crate) async fn create_tx_generator( - &self, - ctx: &mut BenchmarkContext, - ) -> Arc { - match &self.workload_kind { - WorkloadKind::PTB { - num_transfers, - use_native_transfer, - num_dynamic_fields, - computation, - } => { - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.extend(["move_package"]); - let move_package = ctx.publish_package(PublishData::Source(path, false)).await; - let root_objects = ctx - .preparing_dynamic_fields(move_package.0, *num_dynamic_fields) - .await; - Arc::new(MoveTxGenerator::new( - move_package.0, - *num_transfers, - *use_native_transfer, - *computation, - root_objects, - )) - } - WorkloadKind::Publish { - manifest_file: manifest_path, - } => Arc::new(PackagePublishTxGenerator::new(ctx, manifest_path.clone()).await), - } - } -} diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_a/sources/a.move b/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_a/sources/a.move deleted file mode 100644 index bed730ebff8..00000000000 --- a/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_a/sources/a.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module a::a { - public fun a() {} -} \ No newline at end of file diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_b/sources/b.move b/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_b/sources/b.move deleted file mode 100644 index 1517292baab..00000000000 --- a/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_b/sources/b.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::b { - public fun b() {} -} \ No newline at end of file diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_c/sources/c.move b/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_c/sources/c.move deleted file mode 100644 index 6f84f751844..00000000000 --- a/crates/sui-single-node-benchmark/tests/data/package_publish_from_bytecode/package_c/sources/c.move +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module c::c { - use a::a; - use b::b; - - public fun c() { - a::a(); - b::b(); - } -} \ No newline at end of file diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_a/sources/a.move b/crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_a/sources/a.move deleted file mode 100644 index bed730ebff8..00000000000 --- a/crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_a/sources/a.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module a::a { - public fun a() {} -} \ No newline at end of file diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_b/sources/b.move b/crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_b/sources/b.move deleted file mode 100644 index 1517292baab..00000000000 --- a/crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_b/sources/b.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::b { - public fun b() {} -} \ No newline at end of file diff --git a/crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_c/sources/c.move b/crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_c/sources/c.move deleted file mode 100644 index 6f84f751844..00000000000 --- a/crates/sui-single-node-benchmark/tests/data/package_publish_from_source/package_c/sources/c.move +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module c::c { - use a::a; - use b::b; - - public fun c() { - a::a(); - b::b(); - } -} \ No newline at end of file diff --git a/crates/sui-single-node-benchmark/tests/smoke_tests.rs b/crates/sui-single-node-benchmark/tests/smoke_tests.rs deleted file mode 100644 index 3df8797b15e..00000000000 --- a/crates/sui-single-node-benchmark/tests/smoke_tests.rs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::path::PathBuf; - -use strum::IntoEnumIterator; -use sui_macros::sim_test; -use sui_single_node_benchmark::{ - command::{Component, WorkloadKind}, - run_benchmark, - workload::Workload, -}; - -#[sim_test] -async fn benchmark_non_move_transactions_smoke_test() { - for skip_signing in [true, false] { - for component in Component::iter() { - run_benchmark( - Workload::new( - 10, - WorkloadKind::PTB { - num_transfers: 2, - use_native_transfer: true, - num_dynamic_fields: 0, - computation: 0, - }, - ), - component, - 1000, - false, - skip_signing, - ) - .await; - } - } -} - -#[sim_test] -async fn benchmark_move_transactions_smoke_test() { - for skip_signing in [true, false] { - for component in Component::iter() { - run_benchmark( - Workload::new( - 10, - WorkloadKind::PTB { - num_transfers: 2, - use_native_transfer: false, - num_dynamic_fields: 1, - computation: 1, - }, - ), - component, - 1000, - false, - skip_signing, - ) - .await; - } - } -} - -#[sim_test] -async fn benchmark_publish_from_source() { - // This test makes sure that the benchmark runs. - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.extend([ - "tests", - "data", - "package_publish_from_source", - "manifest.json", - ]); - for component in Component::iter() { - run_benchmark( - Workload::new( - 10, - WorkloadKind::Publish { - manifest_file: path.clone(), - }, - ), - component, - 1000, - false, - false, - ) - .await; - } -} - -#[sim_test] -async fn benchmark_publish_from_bytecode() { - // This test makes sure that the benchmark runs. - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.extend([ - "tests", - "data", - "package_publish_from_bytecode", - "manifest.json", - ]); - for component in Component::iter() { - run_benchmark( - Workload::new( - 10, - WorkloadKind::Publish { - manifest_file: path.clone(), - }, - ), - component, - 1000, - false, - false, - ) - .await; - } -} diff --git a/crates/sui-snapshot/Cargo.toml b/crates/sui-snapshot/Cargo.toml deleted file mode 100644 index cdc3db01304..00000000000 --- a/crates/sui-snapshot/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = "sui-snapshot" -version = "0.1.0" -edition = "2021" -publish = false -license = "Apache-2.0" -authors = ["Mysten Labs "] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -integer-encoding.workspace = true -indicatif.workspace = true -anyhow.workspace = true -serde.workspace = true -bcs.workspace = true -byteorder.workspace = true -tracing.workspace = true -bytes.workspace = true -tokio-stream.workspace = true -num_enum.workspace = true -futures.workspace = true -object_store.workspace = true -prometheus.workspace = true -sui-types.workspace = true -sui-config.workspace = true -sui-core.workspace = true -sui-storage.workspace = true -sui-protocol-config.workspace = true -fastcrypto = { workspace = true, features = ["copy_key"] } -tokio = { workspace = true, features = ["full"] } -serde_json.workspace = true - -[dev-dependencies] -tempfile.workspace = true diff --git a/crates/sui-snapshot/src/lib.rs b/crates/sui-snapshot/src/lib.rs deleted file mode 100644 index 0ed943008ad..00000000000 --- a/crates/sui-snapshot/src/lib.rs +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -#![allow(dead_code)] - -#[cfg(test)] -mod tests; - -pub mod reader; -pub mod uploader; -mod writer; - -use std::{path::PathBuf, sync::Arc}; - -use anyhow::Result; -use num_enum::{IntoPrimitive, TryFromPrimitive}; -use object_store::path::Path; -use serde::{Deserialize, Serialize}; -use sui_core::{ - authority::{ - authority_store_tables::AuthorityPerpetualTables, - epoch_start_configuration::EpochStartConfiguration, - }, - checkpoints::CheckpointStore, - epoch::committee_store::CommitteeStore, -}; -use sui_storage::{ - compute_sha3_checksum, object_store::util::path_to_filesystem, FileCompression, SHA3_BYTES, -}; -use sui_types::{ - accumulator::Accumulator, - base_types::ObjectID, - sui_system_state::{ - epoch_start_sui_system_state::EpochStartSystemStateTrait, get_sui_system_state, - SuiSystemStateTrait, - }, -}; - -/// The following describes the format of an object file (*.obj) used for -/// persisting live sui objects. The maximum size per .obj file is 128MB. State -/// snapshot will be taken at the end of every epoch. Live object set is split -/// into and stored across multiple hash buckets. The hashing function used -/// for bucketing objects is the same as the one used to build the accumulator -/// tree for computing state root hash. Buckets are further subdivided into -/// partitions. A partition is a smallest storage unit which holds a subset of -/// objects in one bucket. Each partition is a single *.obj file where -/// objects are appended to in an append-only fashion. A new partition is -/// created once the size of current one reaches the max size i.e. 128MB. -/// Partitions allow a single hash bucket to be consumed in parallel. Partition -/// files are optionally compressed with the zstd compression format. Partition -/// filenames follows the format _.obj. Object -/// references for hash There is one single ref file per hash bucket. Object -/// references are written in an append-only manner as well. Finally, the -/// MANIFEST file contains per file metadata of every file in the snapshot -/// directory. current one reaches the max size i.e. 64MB. Partitions allow a -/// single hash bucket to be consumed in parallel. Partition files are -/// compressed with the zstd compression format. State Snapshot Directory Layout -/// - snapshot/ -/// - epoch_0/ -/// - 1_1.obj -/// - 1_2.obj -/// - 1_3.obj -/// - 2_1.obj -/// - ... -/// - 1000_1.obj -/// - REFERENCE-1 -/// - REFERENCE-2 -/// - ... -/// - REFERENCE-1000 -/// - MANIFEST -/// - epoch_1/ -/// - 1_1.obj -/// - ... -/// Object File Disk Format -/// ┌──────────────────────────────┐ -/// │ magic(0x00B7EC75) <4 byte> │ -/// ├──────────────────────────────┤ -/// │ ┌──────────────────────────┐ │ -/// │ │ Object 1 │ │ -/// │ ├──────────────────────────┤ │ -/// │ │ ... │ │ -/// │ ├──────────────────────────┤ │ -/// │ │ Object N │ │ -/// │ └──────────────────────────┘ │ -/// └──────────────────────────────┘ -/// Object -/// ┌───────────────┬───────────────────┬──────────────┐ -/// │ len │ encoding <1 byte> │ data │ -/// └───────────────┴───────────────────┴──────────────┘ -/// -/// REFERENCE File Disk Format -/// ┌──────────────────────────────┐ -/// │ magic(0x5EFE5E11) <4 byte> │ -/// ├──────────────────────────────┤ -/// │ ┌──────────────────────────┐ │ -/// │ │ ObjectRef 1 │ │ -/// │ ├──────────────────────────┤ │ -/// │ │ ... │ │ -/// │ ├──────────────────────────┤ │ -/// │ │ ObjectRef N │ │ -/// │ └──────────────────────────┘ │ -/// └──────────────────────────────┘ -/// ObjectRef (ObjectID, SequenceNumber, ObjectDigest) -/// ┌───────────────┬───────────────────┬──────────────┐ -/// │ data (<(address_len + 8 + 32) bytes>) │ -/// └───────────────┴───────────────────┴──────────────┘ -/// -/// MANIFEST File Disk Format -/// ┌──────────────────────────────┐ -/// │ magic(0x00C0FFEE) <4 byte> │ -/// ├──────────────────────────────┤ -/// │ serialized manifest │ -/// ├──────────────────────────────┤ -/// │ sha3 <32 bytes> │ -/// └──────────────────────────────┘ -const OBJECT_FILE_MAGIC: u32 = 0x00B7EC75; -const REFERENCE_FILE_MAGIC: u32 = 0xDEADBEEF; -const MANIFEST_FILE_MAGIC: u32 = 0x00C0FFEE; -const MAGIC_BYTES: usize = 4; -const SNAPSHOT_VERSION_BYTES: usize = 1; -const ADDRESS_LENGTH_BYTES: usize = 8; -const PADDING_BYTES: usize = 3; -const MANIFEST_FILE_HEADER_BYTES: usize = - MAGIC_BYTES + SNAPSHOT_VERSION_BYTES + ADDRESS_LENGTH_BYTES + PADDING_BYTES; -const FILE_MAX_BYTES: usize = 128 * 1024 * 1024; -const OBJECT_ID_BYTES: usize = ObjectID::LENGTH; -const SEQUENCE_NUM_BYTES: usize = 8; -const OBJECT_DIGEST_BYTES: usize = 32; -const OBJECT_REF_BYTES: usize = OBJECT_ID_BYTES + SEQUENCE_NUM_BYTES + OBJECT_DIGEST_BYTES; -const FILE_TYPE_BYTES: usize = 1; -const BUCKET_BYTES: usize = 4; -const BUCKET_PARTITION_BYTES: usize = 4; -const COMPRESSION_TYPE_BYTES: usize = 1; -const FILE_METADATA_BYTES: usize = - FILE_TYPE_BYTES + BUCKET_BYTES + BUCKET_PARTITION_BYTES + COMPRESSION_TYPE_BYTES + SHA3_BYTES; - -#[derive( - Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, TryFromPrimitive, IntoPrimitive, -)] -#[repr(u8)] -pub enum FileType { - Object = 0, - Reference, -} - -#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] -pub struct FileMetadata { - pub file_type: FileType, - pub bucket_num: u32, - pub part_num: u32, - pub file_compression: FileCompression, - pub sha3_digest: [u8; 32], -} - -impl FileMetadata { - pub fn file_path(&self, dir_path: &Path) -> Path { - match self.file_type { - FileType::Object => { - dir_path.child(&*format!("{}_{}.obj", self.bucket_num, self.part_num)) - } - FileType::Reference => { - dir_path.child(&*format!("{}_{}.ref", self.bucket_num, self.part_num)) - } - } - } - pub fn local_file_path(&self, root_path: &std::path::Path, dir_path: &Path) -> Result { - path_to_filesystem(root_path.to_path_buf(), &self.file_path(dir_path)) - } -} - -#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct ManifestV1 { - pub snapshot_version: u8, - pub address_length: u64, - pub file_metadata: Vec, - pub epoch: u64, -} - -#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] -pub enum Manifest { - V1(ManifestV1), -} - -impl Manifest { - pub fn snapshot_version(&self) -> u8 { - match self { - Self::V1(manifest) => manifest.snapshot_version, - } - } - pub fn address_length(&self) -> u64 { - match self { - Self::V1(manifest) => manifest.address_length, - } - } - pub fn file_metadata(&self) -> &Vec { - match self { - Self::V1(manifest) => &manifest.file_metadata, - } - } - pub fn epoch(&self) -> u64 { - match self { - Self::V1(manifest) => manifest.epoch, - } - } -} - -pub fn create_file_metadata( - file_path: &std::path::Path, - file_compression: FileCompression, - file_type: FileType, - bucket_num: u32, - part_num: u32, -) -> Result { - file_compression.compress(file_path)?; - let sha3_digest = compute_sha3_checksum(file_path)?; - let file_metadata = FileMetadata { - file_type, - bucket_num, - part_num, - file_compression, - sha3_digest, - }; - Ok(file_metadata) -} - -pub async fn setup_db_state( - epoch: u64, - accumulator: Accumulator, - perpetual_db: Arc, - checkpoint_store: Arc, - committee_store: Arc, -) -> Result<()> { - // This function should be called once state accumulator based hash verification - // is complete and live object set state is downloaded to local store - let system_state_object = get_sui_system_state(&perpetual_db)?; - let new_epoch_start_state = system_state_object.into_epoch_start_state(); - let next_epoch_committee = new_epoch_start_state.get_sui_committee(); - let last_checkpoint = checkpoint_store - .get_epoch_last_checkpoint(epoch) - .expect("Error loading last checkpoint for current epoch") - .expect("Could not load last checkpoint for current epoch"); - let epoch_start_configuration = EpochStartConfiguration::new( - new_epoch_start_state, - *last_checkpoint.digest(), - &perpetual_db, - None, - ) - .unwrap(); - perpetual_db.set_epoch_start_configuration(&epoch_start_configuration)?; - perpetual_db.insert_root_state_hash(epoch, last_checkpoint.sequence_number, accumulator)?; - perpetual_db.set_highest_pruned_checkpoint_without_wb(last_checkpoint.sequence_number)?; - committee_store.insert_new_committee(&next_epoch_committee)?; - checkpoint_store.update_highest_executed_checkpoint(&last_checkpoint)?; - - Ok(()) -} diff --git a/crates/sui-snapshot/src/reader.rs b/crates/sui-snapshot/src/reader.rs deleted file mode 100644 index 42bf4db7a7d..00000000000 --- a/crates/sui-snapshot/src/reader.rs +++ /dev/null @@ -1,610 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::BTreeMap, - fs, - fs::File, - io::{BufReader, Read, Seek, SeekFrom}, - num::NonZeroUsize, - path::PathBuf, - sync::{ - atomic::{AtomicU64, AtomicUsize, Ordering}, - Arc, - }, -}; - -use anyhow::{anyhow, Context, Result}; -use byteorder::{BigEndian, ReadBytesExt}; -use bytes::{Buf, Bytes}; -use fastcrypto::hash::{HashFunction, MultisetHash, Sha3_256}; -use futures::{ - future::{AbortRegistration, Abortable}, - StreamExt, TryStreamExt, -}; -use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; -use integer_encoding::VarIntReader; -use object_store::path::Path; -use sui_config::object_storage_config::ObjectStoreConfig; -use sui_core::authority::{ - authority_store_tables::{AuthorityPerpetualTables, LiveObject}, - AuthorityStore, -}; -use sui_storage::{ - blob::{Blob, BlobEncoding}, - object_store::{ - http::HttpDownloaderBuilder, - util::{copy_file, copy_files, path_to_filesystem}, - ObjectStoreGetExt, ObjectStorePutExt, - }, -}; -use sui_types::{ - accumulator::Accumulator, - base_types::{ObjectDigest, ObjectID, ObjectRef, SequenceNumber}, -}; -use tokio::{ - sync::Mutex, - task::JoinHandle, - time::{Duration, Instant}, -}; -use tracing::{error, info}; - -use crate::{ - FileMetadata, FileType, Manifest, MAGIC_BYTES, MANIFEST_FILE_MAGIC, OBJECT_FILE_MAGIC, - OBJECT_ID_BYTES, OBJECT_REF_BYTES, REFERENCE_FILE_MAGIC, SEQUENCE_NUM_BYTES, SHA3_BYTES, -}; - -pub type SnapshotChecksums = (DigestByBucketAndPartition, Accumulator); -pub type DigestByBucketAndPartition = BTreeMap>; -pub struct StateSnapshotReaderV1 { - epoch: u64, - local_staging_dir_root: PathBuf, - remote_object_store: Arc, - local_object_store: Arc, - ref_files: BTreeMap>, - object_files: BTreeMap>, - indirect_objects_threshold: usize, - m: MultiProgress, - concurrency: usize, -} - -impl StateSnapshotReaderV1 { - pub async fn new( - epoch: u64, - remote_store_config: &ObjectStoreConfig, - local_store_config: &ObjectStoreConfig, - indirect_objects_threshold: usize, - download_concurrency: NonZeroUsize, - m: MultiProgress, - ) -> Result { - let epoch_dir = format!("epoch_{}", epoch); - let remote_object_store = if remote_store_config.no_sign_request { - remote_store_config.make_http()? - } else { - remote_store_config.make().map(Arc::new)? - }; - let local_object_store: Arc = - local_store_config.make().map(Arc::new)?; - let local_staging_dir_root = local_store_config - .directory - .as_ref() - .context("No directory specified")? - .clone(); - let local_epoch_dir_path = local_staging_dir_root.join(&epoch_dir); - if local_epoch_dir_path.exists() { - fs::remove_dir_all(&local_epoch_dir_path)?; - } - fs::create_dir_all(&local_epoch_dir_path)?; - // Download MANIFEST first - let manifest_file_path = Path::from(epoch_dir.clone()).child("MANIFEST"); - copy_file( - &manifest_file_path, - &manifest_file_path, - &remote_object_store, - &local_object_store, - ) - .await?; - let manifest = Self::read_manifest(path_to_filesystem( - local_staging_dir_root.clone(), - &manifest_file_path, - )?)?; - let snapshot_version = manifest.snapshot_version(); - if snapshot_version != 1u8 { - return Err(anyhow!("Unexpected snapshot version: {}", snapshot_version)); - } - if manifest.address_length() as usize > ObjectID::LENGTH { - return Err(anyhow!( - "Max possible address length is: {}", - ObjectID::LENGTH - )); - } - if manifest.epoch() != epoch { - return Err(anyhow!("Download manifest is not for epoch: {}", epoch,)); - } - let mut object_files = BTreeMap::new(); - let mut ref_files = BTreeMap::new(); - for file_metadata in manifest.file_metadata() { - match file_metadata.file_type { - FileType::Object => { - let entry = object_files - .entry(file_metadata.bucket_num) - .or_insert_with(BTreeMap::new); - entry.insert(file_metadata.part_num, file_metadata.clone()); - } - FileType::Reference => { - let entry = ref_files - .entry(file_metadata.bucket_num) - .or_insert_with(BTreeMap::new); - entry.insert(file_metadata.part_num, file_metadata.clone()); - } - } - } - let epoch_dir_path = Path::from(epoch_dir); - let files: Vec = ref_files - .values() - .flat_map(|entry| { - let files: Vec<_> = entry - .values() - .map(|file_metadata| file_metadata.file_path(&epoch_dir_path)) - .collect(); - files - }) - .collect(); - - let progress_bar = m.add( - ProgressBar::new(files.len() as u64).with_style( - ProgressStyle::with_template( - "[{elapsed_precise}] {wide_bar} {pos} out of {len} .ref files done\n({msg})", - ) - .unwrap(), - ), - ); - copy_files( - &files, - &files, - &remote_object_store, - &local_object_store, - download_concurrency, - Some(progress_bar.clone()), - ) - .await?; - progress_bar.finish_with_message("ref files download complete"); - Ok(StateSnapshotReaderV1 { - epoch, - local_staging_dir_root, - remote_object_store, - local_object_store, - ref_files, - object_files, - indirect_objects_threshold, - m, - concurrency: download_concurrency.get(), - }) - } - - pub async fn read( - &mut self, - perpetual_db: &AuthorityPerpetualTables, - abort_registration: AbortRegistration, - sender: Option>, - ) -> Result<()> { - // This computes and stores the sha3 digest of object references in REFERENCE - // file for each bucket partition. When downloading objects, we will - // match sha3 digest of object references per *.obj file against this. - // We do this so during restore we can pre fetch object references and - // start building state accumulator and fail early if the state root hash - // doesn't match but we still need to ensure that objects match references - // exactly. - let sha3_digests: Arc> = - Arc::new(Mutex::new(BTreeMap::new())); - - let num_part_files = self - .ref_files - .values() - .map(|part_files| part_files.len()) - .sum::(); - - // Generate checksums - info!("Computing checksums"); - let checksum_progress_bar = self.m.add( - ProgressBar::new(num_part_files as u64).with_style( - ProgressStyle::with_template( - "[{elapsed_precise}] {wide_bar} {pos} out of {len} ref files checksummed ({msg})", - ) - .unwrap(), - ), - ); - - for (bucket, part_files) in self.ref_files.clone().iter() { - for (part, _part_file) in part_files.iter() { - let mut sha3_digests = sha3_digests.lock().await; - let ref_iter = self.ref_iter(*bucket, *part)?; - let mut hasher = Sha3_256::default(); - let mut empty = true; - self.object_files - .get(bucket) - .context(format!("No bucket exists for: {bucket}"))? - .get(part) - .context(format!("No part exists for bucket: {bucket}, part: {part}"))?; - for object_ref in ref_iter { - hasher.update(object_ref.2.inner()); - empty = false; - } - if !empty { - sha3_digests - .entry(*bucket) - .or_insert(BTreeMap::new()) - .entry(*part) - .or_insert(hasher.finalize().digest); - } - checksum_progress_bar.inc(1); - checksum_progress_bar.set_message(format!("Bucket: {}, Part: {}", bucket, part)); - } - } - checksum_progress_bar.finish_with_message("Checksumming complete"); - - let accum_handle = - sender.map(|sender| self.spawn_accumulation_tasks(sender, num_part_files)); - - self.sync_live_objects(perpetual_db, abort_registration, sha3_digests) - .await?; - - if let Some(handle) = accum_handle { - handle.await?; - } - Ok(()) - } - - fn spawn_accumulation_tasks( - &self, - sender: tokio::sync::mpsc::Sender, - num_part_files: usize, - ) -> JoinHandle<()> { - // Spawn accumulation progress bar - let concurrency = self.concurrency; - let accum_counter = Arc::new(AtomicU64::new(0)); - let cloned_accum_counter = accum_counter.clone(); - let accum_progress_bar = self.m.add( - ProgressBar::new(num_part_files as u64).with_style( - ProgressStyle::with_template( - "[{elapsed_precise}] {wide_bar} {pos} out of {len} ref files accumulated ({msg})", - ) - .unwrap(), - ), - ); - let cloned_accum_progress_bar = accum_progress_bar.clone(); - tokio::spawn(async move { - let a_instant = Instant::now(); - loop { - if cloned_accum_progress_bar.is_finished() { - break; - } - let num_partitions = cloned_accum_counter.load(Ordering::Relaxed); - let total_partitions_per_sec = - num_partitions as f64 / a_instant.elapsed().as_secs_f64(); - cloned_accum_progress_bar.set_position(num_partitions); - cloned_accum_progress_bar.set_message(format!( - "file partitions per sec: {}", - total_partitions_per_sec - )); - tokio::time::sleep(Duration::from_secs(1)).await; - } - }); - - // spawn accumualation task - let ref_files = self.ref_files.clone(); - let epoch_dir = self.epoch_dir(); - let local_staging_dir_root = self.local_staging_dir_root.clone(); - tokio::task::spawn(async move { - let local_staging_dir_root_clone = local_staging_dir_root.clone(); - let epoch_dir_clone = epoch_dir.clone(); - for (bucket, part_files) in ref_files.clone().iter() { - futures::stream::iter(part_files.iter()) - .map(|(part, _part_files)| { - // TODO depending on concurrency limit here, we may be - // materializing too many refs into memory at once. - // This is only done because ObjectRefIter is not Send - let obj_digests = { - let file_metadata = ref_files - .get(bucket) - .expect("No ref files found for bucket: {bucket_num}") - .get(part) - .expect( - "No ref files found for bucket: {bucket_num}, part: {part_num}", - ); - ObjectRefIter::new( - file_metadata, - local_staging_dir_root_clone.clone(), - epoch_dir_clone.clone(), - ) - .expect("Failed to create object ref iter") - } - .map(|obj_ref| obj_ref.2) - .collect::>(); - let sender_clone = sender.clone(); - tokio::spawn(async move { - let mut partial_acc = Accumulator::default(); - partial_acc.insert_all(obj_digests); - sender_clone - .send(partial_acc) - .await - .expect("Unable to send accumulator from snapshot reader"); - }) - }) - .boxed() - .buffer_unordered(concurrency) - .for_each(|result| { - result.expect("Failed to generate partial accumulator"); - accum_counter.fetch_add(1, Ordering::Relaxed); - futures::future::ready(()) - }) - .await; - } - accum_progress_bar.finish_with_message("Accumulation complete"); - }) - } - - async fn sync_live_objects( - &self, - perpetual_db: &AuthorityPerpetualTables, - abort_registration: AbortRegistration, - sha3_digests: Arc>, - ) -> Result<(), anyhow::Error> { - let epoch_dir = self.epoch_dir(); - let concurrency = self.concurrency; - let threshold = self.indirect_objects_threshold; - let remote_object_store = self.remote_object_store.clone(); - let input_files: Vec<_> = self - .object_files - .iter() - .flat_map(|(bucket, parts)| { - parts - .clone() - .into_iter() - .map(|entry| (bucket, entry)) - .collect::>() - }) - .collect(); - let obj_progress_bar = self.m.add( - ProgressBar::new(input_files.len() as u64).with_style( - ProgressStyle::with_template( - "[{elapsed_precise}] {wide_bar} {pos} out of {len} .obj files done\n({msg})", - ) - .unwrap(), - ), - ); - let obj_progress_bar_clone = obj_progress_bar.clone(); - let instant = Instant::now(); - let downloaded_bytes = AtomicUsize::new(0); - - let ret = Abortable::new( - async move { - futures::stream::iter(input_files.iter()) - .map(|(bucket, (part_num, file_metadata))| { - let epoch_dir = epoch_dir.clone(); - let file_path = file_metadata.file_path(&epoch_dir); - let remote_object_store = remote_object_store.clone(); - let sha3_digests_cloned = sha3_digests.clone(); - async move { - // Download object file with retries - let max_timeout = Duration::from_secs(30); - let mut timeout = Duration::from_secs(2); - timeout += timeout / 2; - timeout = std::cmp::min(max_timeout, timeout); - let mut attempts = 0usize; - let bytes = loop { - match remote_object_store.get_bytes(&file_path).await { - Ok(bytes) => { - break bytes; - } - Err(err) => { - error!( - "Obj {} .get failed (attempt {}): {}", - file_metadata.file_path(&epoch_dir), - attempts, - err, - ); - if timeout > max_timeout { - panic!( - "Failed to get obj file after {} attempts", - attempts - ); - } else { - attempts += 1; - tokio::time::sleep(timeout).await; - timeout += timeout / 2; - continue; - } - } - } - }; - - let sha3_digest = sha3_digests_cloned.lock().await; - let bucket_map = sha3_digest - .get(bucket) - .expect("Bucket not in digest map") - .clone(); - let sha3_digest = *bucket_map - .get(part_num) - .expect("sha3 digest not in bucket map"); - Ok::<(Bytes, FileMetadata, [u8; 32]), anyhow::Error>(( - bytes, - (*file_metadata).clone(), - sha3_digest, - )) - } - }) - .boxed() - .buffer_unordered(concurrency) - .try_for_each(|(bytes, file_metadata, sha3_digest)| { - let bytes_len = bytes.len(); - let result: Result<(), anyhow::Error> = - LiveObjectIter::new(&file_metadata, bytes).map(|obj_iter| { - AuthorityStore::bulk_insert_live_objects( - perpetual_db, - obj_iter, - threshold, - &sha3_digest, - ) - .expect("Failed to insert live objects"); - }); - downloaded_bytes.fetch_add(bytes_len, Ordering::Relaxed); - obj_progress_bar_clone.inc(1); - obj_progress_bar_clone.set_message(format!( - "Download speed: {} MiB/s", - downloaded_bytes.load(Ordering::Relaxed) as f64 - / (1024 * 1024) as f64 - / instant.elapsed().as_secs_f64(), - )); - futures::future::ready(result) - }) - .await - }, - abort_registration, - ) - .await?; - obj_progress_bar.finish_with_message("Objects download complete"); - ret - } - - pub fn ref_iter(&self, bucket_num: u32, part_num: u32) -> Result { - let file_metadata = self - .ref_files - .get(&bucket_num) - .context(format!("No ref files found for bucket: {bucket_num}"))? - .get(&part_num) - .context(format!( - "No ref files found for bucket: {bucket_num}, part: {part_num}" - ))?; - ObjectRefIter::new( - file_metadata, - self.local_staging_dir_root.clone(), - self.epoch_dir(), - ) - } - - fn buckets(&self) -> Result> { - Ok(self.ref_files.keys().copied().collect()) - } - - fn epoch_dir(&self) -> Path { - Path::from(format!("epoch_{}", self.epoch)) - } - - fn read_manifest(path: PathBuf) -> anyhow::Result { - let manifest_file = File::open(path)?; - let manifest_file_size = manifest_file.metadata()?.len() as usize; - let mut manifest_reader = BufReader::new(manifest_file); - manifest_reader.rewind()?; - let magic = manifest_reader.read_u32::()?; - if magic != MANIFEST_FILE_MAGIC { - return Err(anyhow!("Unexpected magic byte: {}", magic)); - } - manifest_reader.seek(SeekFrom::End(-(SHA3_BYTES as i64)))?; - let mut sha3_digest = [0u8; SHA3_BYTES]; - manifest_reader.read_exact(&mut sha3_digest)?; - manifest_reader.rewind()?; - let mut content_buf = vec![0u8; manifest_file_size - SHA3_BYTES]; - manifest_reader.read_exact(&mut content_buf)?; - let mut hasher = Sha3_256::default(); - hasher.update(&content_buf); - let computed_digest = hasher.finalize().digest; - if computed_digest != sha3_digest { - return Err(anyhow!( - "Checksum: {:?} don't match: {:?}", - computed_digest, - sha3_digest - )); - } - manifest_reader.rewind()?; - manifest_reader.seek(SeekFrom::Start(MAGIC_BYTES as u64))?; - let manifest = bcs::from_bytes(&content_buf[MAGIC_BYTES..])?; - Ok(manifest) - } -} - -/// An iterator over all object refs in a .ref file. -pub struct ObjectRefIter { - reader: Box, -} - -impl ObjectRefIter { - pub fn new(file_metadata: &FileMetadata, root_path: PathBuf, dir_path: Path) -> Result { - let file_path = file_metadata.local_file_path(&root_path, &dir_path)?; - let mut reader = file_metadata.file_compression.decompress(&file_path)?; - let magic = reader.read_u32::()?; - if magic != REFERENCE_FILE_MAGIC { - Err(anyhow!( - "Unexpected magic string in REFERENCE file: {:?}", - magic - )) - } else { - Ok(ObjectRefIter { reader }) - } - } - - fn next_ref(&mut self) -> Result { - let mut buf = [0u8; OBJECT_REF_BYTES]; - self.reader.read_exact(&mut buf)?; - let object_id = &buf[0..OBJECT_ID_BYTES]; - let sequence_number = &buf[OBJECT_ID_BYTES..OBJECT_ID_BYTES + SEQUENCE_NUM_BYTES] - .reader() - .read_u64::()?; - let sha3_digest = &buf[OBJECT_ID_BYTES + SEQUENCE_NUM_BYTES..OBJECT_REF_BYTES]; - let object_ref: ObjectRef = ( - ObjectID::from_bytes(object_id)?, - SequenceNumber::from_u64(*sequence_number), - ObjectDigest::try_from(sha3_digest)?, - ); - Ok(object_ref) - } -} - -impl Iterator for ObjectRefIter { - type Item = ObjectRef; - fn next(&mut self) -> Option { - self.next_ref().ok() - } -} - -/// An iterator over all objects in a *.obj file. -pub struct LiveObjectIter { - reader: Box, -} - -impl LiveObjectIter { - pub fn new(file_metadata: &FileMetadata, bytes: Bytes) -> Result { - let mut reader = file_metadata.file_compression.bytes_decompress(bytes)?; - let magic = reader.read_u32::()?; - if magic != OBJECT_FILE_MAGIC { - Err(anyhow!( - "Unexpected magic string in object file: {:?}", - magic - )) - } else { - Ok(LiveObjectIter { reader }) - } - } - - fn next_object(&mut self) -> Result { - let len = self.reader.read_varint::()? as usize; - if len == 0 { - return Err(anyhow!("Invalid object length of 0 in file")); - } - let encoding = self.reader.read_u8()?; - let mut data = vec![0u8; len]; - self.reader.read_exact(&mut data)?; - let blob = Blob { - data, - encoding: BlobEncoding::try_from(encoding)?, - }; - blob.decode() - } -} - -impl Iterator for LiveObjectIter { - type Item = LiveObject; - fn next(&mut self) -> Option { - self.next_object().ok() - } -} diff --git a/crates/sui-snapshot/src/tests.rs b/crates/sui-snapshot/src/tests.rs deleted file mode 100644 index 9d0db3f81c0..00000000000 --- a/crates/sui-snapshot/src/tests.rs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::HashSet, num::NonZeroUsize, sync::Arc}; - -use futures::future::AbortHandle; -use indicatif::MultiProgress; -use sui_config::object_storage_config::{ObjectStoreConfig, ObjectStoreType}; -use sui_core::authority::authority_store_tables::AuthorityPerpetualTables; -use sui_protocol_config::ProtocolConfig; -use sui_types::{base_types::ObjectID, object::Object}; -use tempfile::tempdir; - -use crate::{reader::StateSnapshotReaderV1, writer::StateSnapshotWriterV1, FileCompression}; - -fn temp_dir() -> std::path::PathBuf { - tempdir() - .expect("Failed to open temporary directory") - .into_path() -} - -pub fn insert_keys( - db: &AuthorityPerpetualTables, - total_unique_object_ids: u64, -) -> Result<(), anyhow::Error> { - let ids = ObjectID::in_range(ObjectID::ZERO, total_unique_object_ids)?; - for id in ids { - let object = Object::immutable_with_id_for_testing(id); - db.insert_object_test_only(object)?; - } - Ok(()) -} - -fn compare_live_objects( - db1: &AuthorityPerpetualTables, - db2: &AuthorityPerpetualTables, - include_wrapped_tombstone: bool, -) -> Result<(), anyhow::Error> { - let mut object_set_1 = HashSet::new(); - let mut object_set_2 = HashSet::new(); - for live_object in db1.iter_live_object_set(include_wrapped_tombstone) { - object_set_1.insert(live_object.object_reference()); - } - for live_object in db2.iter_live_object_set(include_wrapped_tombstone) { - object_set_2.insert(live_object.object_reference()); - } - assert_eq!(object_set_1, object_set_2); - Ok(()) -} - -#[tokio::test] -async fn test_snapshot_basic() -> Result<(), anyhow::Error> { - let db_path = temp_dir(); - let restored_db_path = temp_dir(); - let local = temp_dir().join("local_dir"); - let remote = temp_dir().join("remote_dir"); - let restored_local = temp_dir().join("local_dir_restore"); - let local_store_config = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(local), - ..Default::default() - }; - let remote_store_config = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(remote), - ..Default::default() - }; - - let snapshot_writer = StateSnapshotWriterV1::new( - &local_store_config, - &remote_store_config, - FileCompression::Zstd, - NonZeroUsize::new(1).unwrap(), - ) - .await?; - let perpetual_db = Arc::new(AuthorityPerpetualTables::open(&db_path, None)); - insert_keys(&perpetual_db, 1000)?; - snapshot_writer - .write_internal(0, true, perpetual_db.clone()) - .await?; - let local_store_restore_config = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(restored_local), - ..Default::default() - }; - let mut snapshot_reader = StateSnapshotReaderV1::new( - 0, - &remote_store_config, - &local_store_restore_config, - usize::MAX, - NonZeroUsize::new(1).unwrap(), - MultiProgress::new(), - ) - .await?; - let restored_perpetual_db = AuthorityPerpetualTables::open(&restored_db_path, None); - let (_abort_handle, abort_registration) = AbortHandle::new_pair(); - snapshot_reader - .read(&restored_perpetual_db, abort_registration, None) - .await?; - compare_live_objects(&perpetual_db, &restored_perpetual_db, true)?; - Ok(()) -} - -#[tokio::test] -async fn test_snapshot_empty_db() -> Result<(), anyhow::Error> { - let db_path = temp_dir(); - let restored_db_path = temp_dir(); - let local = temp_dir().join("local_dir"); - let remote = temp_dir().join("remote_dir"); - let restored_local = temp_dir().join("local_dir_restore"); - let local_store_config = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(local), - ..Default::default() - }; - let remote_store_config = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(remote), - ..Default::default() - }; - let include_wrapped_tombstone = - !ProtocolConfig::get_for_max_version_UNSAFE().simplified_unwrap_then_delete(); - let snapshot_writer = StateSnapshotWriterV1::new( - &local_store_config, - &remote_store_config, - FileCompression::Zstd, - NonZeroUsize::new(1).unwrap(), - ) - .await?; - let perpetual_db = Arc::new(AuthorityPerpetualTables::open(&db_path, None)); - snapshot_writer - .write_internal(0, true, perpetual_db.clone()) - .await?; - let local_store_restore_config = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(restored_local), - ..Default::default() - }; - let mut snapshot_reader = StateSnapshotReaderV1::new( - 0, - &remote_store_config, - &local_store_restore_config, - usize::MAX, - NonZeroUsize::new(1).unwrap(), - MultiProgress::new(), - ) - .await?; - let restored_perpetual_db = AuthorityPerpetualTables::open(&restored_db_path, None); - let (_abort_handle, abort_registration) = AbortHandle::new_pair(); - snapshot_reader - .read(&restored_perpetual_db, abort_registration, None) - .await?; - compare_live_objects( - &perpetual_db, - &restored_perpetual_db, - include_wrapped_tombstone, - )?; - Ok(()) -} diff --git a/crates/sui-snapshot/src/writer.rs b/crates/sui-snapshot/src/writer.rs deleted file mode 100644 index 80bfcb59fb3..00000000000 --- a/crates/sui-snapshot/src/writer.rs +++ /dev/null @@ -1,490 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -#![allow(dead_code)] - -use std::{ - collections::{hash_map::Entry::Vacant, HashMap}, - fs, - fs::{File, OpenOptions}, - io::{BufWriter, Seek, SeekFrom, Write}, - num::NonZeroUsize, - path::PathBuf, - sync::Arc, -}; - -use anyhow::{anyhow, Context, Result}; -use byteorder::{BigEndian, ByteOrder}; -use futures::StreamExt; -use integer_encoding::VarInt; -use object_store::{path::Path, DynObjectStore}; -use sui_config::object_storage_config::ObjectStoreConfig; -use sui_core::authority::{ - authority_store_tables::{AuthorityPerpetualTables, LiveObject}, - CHAIN_IDENTIFIER, -}; -use sui_protocol_config::{ProtocolConfig, ProtocolVersion}; -use sui_storage::{ - blob::{Blob, BlobEncoding, BLOB_ENCODING_BYTES}, - object_store::util::{copy_file, delete_recursively, path_to_filesystem}, -}; -use sui_types::{ - base_types::{ObjectID, ObjectRef}, - sui_system_state::{get_sui_system_state, SuiSystemStateTrait}, -}; -use tokio::{ - sync::{ - mpsc, - mpsc::{Receiver, Sender}, - }, - task::JoinHandle, -}; -use tokio_stream::wrappers::ReceiverStream; -use tracing::debug; - -use crate::{ - compute_sha3_checksum, create_file_metadata, FileCompression, FileMetadata, FileType, Manifest, - ManifestV1, FILE_MAX_BYTES, MAGIC_BYTES, MANIFEST_FILE_MAGIC, OBJECT_FILE_MAGIC, - OBJECT_REF_BYTES, REFERENCE_FILE_MAGIC, SEQUENCE_NUM_BYTES, -}; - -/// LiveObjectSetWriterV1 writes live object set. It creates multiple *.obj -/// files and *.ref file -struct LiveObjectSetWriterV1 { - dir_path: PathBuf, - bucket_num: u32, - current_part_num: u32, - wbuf: BufWriter, - ref_wbuf: BufWriter, - n: usize, - files: Vec, - sender: Option>, - file_compression: FileCompression, -} - -impl LiveObjectSetWriterV1 { - fn new( - dir_path: PathBuf, - bucket_num: u32, - file_compression: FileCompression, - sender: Sender, - ) -> Result { - let part_num = 1; - let (n, obj_file) = Self::object_file(dir_path.clone(), bucket_num, part_num)?; - let ref_file = Self::ref_file(dir_path.clone(), bucket_num, part_num)?; - Ok(LiveObjectSetWriterV1 { - dir_path, - bucket_num, - current_part_num: part_num, - wbuf: BufWriter::new(obj_file), - ref_wbuf: BufWriter::new(ref_file), - n, - files: vec![], - sender: Some(sender), - file_compression, - }) - } - pub fn write(&mut self, object: &LiveObject) -> Result<()> { - let object_reference = object.object_reference(); - self.write_object(object)?; - self.write_object_ref(&object_reference)?; - Ok(()) - } - pub fn done(mut self) -> Result> { - self.finalize()?; - self.finalize_ref()?; - self.sender = None; - Ok(self.files.clone()) - } - fn object_file(dir_path: PathBuf, bucket_num: u32, part_num: u32) -> Result<(usize, File)> { - let next_part_file_path = dir_path.join(format!("{bucket_num}_{part_num}.obj")); - let next_part_file_tmp_path = dir_path.join(format!("{bucket_num}_{part_num}.obj.tmp")); - let mut f = File::create(next_part_file_tmp_path.clone())?; - let mut metab = [0u8; MAGIC_BYTES]; - BigEndian::write_u32(&mut metab, OBJECT_FILE_MAGIC); - f.rewind()?; - let n = f.write(&metab)?; - drop(f); - fs::rename(next_part_file_tmp_path, next_part_file_path.clone())?; - let mut f = OpenOptions::new().append(true).open(next_part_file_path)?; - f.seek(SeekFrom::Start(n as u64))?; - Ok((n, f)) - } - fn ref_file(dir_path: PathBuf, bucket_num: u32, part_num: u32) -> Result { - let ref_path = dir_path.join(format!("{bucket_num}_{part_num}.ref")); - let ref_tmp_path = dir_path.join(format!("{bucket_num}_{part_num}.ref.tmp")); - let mut f = File::create(ref_tmp_path.clone())?; - f.rewind()?; - let mut metab = [0u8; MAGIC_BYTES]; - BigEndian::write_u32(&mut metab, REFERENCE_FILE_MAGIC); - let n = f.write(&metab)?; - drop(f); - fs::rename(ref_tmp_path, ref_path.clone())?; - let mut f = OpenOptions::new().append(true).open(ref_path)?; - f.seek(SeekFrom::Start(n as u64))?; - Ok(f) - } - fn finalize(&mut self) -> Result<()> { - self.wbuf.flush()?; - self.wbuf.get_ref().sync_data()?; - let off = self.wbuf.get_ref().stream_position()?; - self.wbuf.get_ref().set_len(off)?; - let file_path = self - .dir_path - .join(format!("{}_{}.obj", self.bucket_num, self.current_part_num)); - let file_metadata = create_file_metadata( - &file_path, - self.file_compression, - FileType::Object, - self.bucket_num, - self.current_part_num, - )?; - self.files.push(file_metadata.clone()); - if let Some(sender) = &self.sender { - sender.blocking_send(file_metadata)?; - } - Ok(()) - } - fn finalize_ref(&mut self) -> Result<()> { - self.ref_wbuf.flush()?; - self.ref_wbuf.get_ref().sync_data()?; - let off = self.ref_wbuf.get_ref().stream_position()?; - self.ref_wbuf.get_ref().set_len(off)?; - let file_path = self - .dir_path - .join(format!("{}_{}.ref", self.bucket_num, self.current_part_num)); - let file_metadata = create_file_metadata( - &file_path, - self.file_compression, - FileType::Reference, - self.bucket_num, - self.current_part_num, - )?; - self.files.push(file_metadata.clone()); - if let Some(sender) = &self.sender { - sender.blocking_send(file_metadata)?; - } - Ok(()) - } - fn cut(&mut self) -> Result<()> { - self.finalize()?; - let (n, f) = Self::object_file( - self.dir_path.clone(), - self.bucket_num, - self.current_part_num + 1, - )?; - self.n = n; - self.wbuf = BufWriter::new(f); - Ok(()) - } - fn cut_reference_file(&mut self) -> Result<()> { - self.finalize_ref()?; - let f = Self::ref_file( - self.dir_path.clone(), - self.bucket_num, - self.current_part_num + 1, - )?; - self.ref_wbuf = BufWriter::new(f); - Ok(()) - } - fn write_object(&mut self, object: &LiveObject) -> Result<()> { - let blob = Blob::encode(object, BlobEncoding::Bcs)?; - let mut blob_size = blob.data.len().required_space(); - blob_size += BLOB_ENCODING_BYTES; - blob_size += blob.data.len(); - let cut_new_part_file = (self.n + blob_size) > FILE_MAX_BYTES; - if cut_new_part_file { - self.cut()?; - self.cut_reference_file()?; - self.current_part_num += 1; - } - self.n += blob.write(&mut self.wbuf)?; - Ok(()) - } - fn write_object_ref(&mut self, object_ref: &ObjectRef) -> Result<()> { - let mut buf = [0u8; OBJECT_REF_BYTES]; - buf[0..ObjectID::LENGTH].copy_from_slice(object_ref.0.as_ref()); - BigEndian::write_u64( - &mut buf[ObjectID::LENGTH..OBJECT_REF_BYTES], - object_ref.1.value(), - ); - buf[ObjectID::LENGTH + SEQUENCE_NUM_BYTES..OBJECT_REF_BYTES] - .copy_from_slice(object_ref.2.as_ref()); - self.ref_wbuf.write_all(&buf)?; - Ok(()) - } -} - -/// StateSnapshotWriterV1 writes snapshot files to a local staging dir and -/// simultaneously uploads them to a remote object store -pub struct StateSnapshotWriterV1 { - local_staging_dir: PathBuf, - file_compression: FileCompression, - remote_object_store: Arc, - local_staging_store: Arc, - concurrency: usize, -} - -impl StateSnapshotWriterV1 { - pub async fn new_from_store( - local_staging_path: &std::path::Path, - local_staging_store: &Arc, - remote_object_store: &Arc, - file_compression: FileCompression, - concurrency: NonZeroUsize, - ) -> Result { - Ok(StateSnapshotWriterV1 { - file_compression, - local_staging_dir: local_staging_path.to_path_buf(), - remote_object_store: remote_object_store.clone(), - local_staging_store: local_staging_store.clone(), - concurrency: concurrency.get(), - }) - } - - pub async fn new( - local_store_config: &ObjectStoreConfig, - remote_store_config: &ObjectStoreConfig, - file_compression: FileCompression, - concurrency: NonZeroUsize, - ) -> Result { - let remote_object_store = remote_store_config.make()?; - let local_staging_store = local_store_config.make()?; - let local_staging_dir = local_store_config - .directory - .as_ref() - .context("No local directory specified")? - .clone(); - Ok(StateSnapshotWriterV1 { - local_staging_dir, - file_compression, - remote_object_store, - local_staging_store, - concurrency: concurrency.get(), - }) - } - - pub async fn write( - self, - epoch: u64, - perpetual_db: Arc, - ) -> Result<()> { - let system_state_object = get_sui_system_state(&perpetual_db)?; - - let protocol_version = system_state_object.protocol_version(); - let chain_identifier = CHAIN_IDENTIFIER - .get() - .ok_or(anyhow!("No chain identifier found"))?; - let protocol_config = ProtocolConfig::get_for_version( - ProtocolVersion::new(protocol_version), - chain_identifier.chain(), - ); - let include_wrapped_tombstone = !protocol_config.simplified_unwrap_then_delete(); - self.write_internal(epoch, include_wrapped_tombstone, perpetual_db) - .await - } - - pub(crate) async fn write_internal( - mut self, - epoch: u64, - include_wrapped_tombstone: bool, - perpetual_db: Arc, - ) -> Result<()> { - self.setup_epoch_dir(epoch).await?; - - let manifest_file_path = self.epoch_dir(epoch).child("MANIFEST"); - let local_staging_dir = self.local_staging_dir.clone(); - let local_object_store = self.local_staging_store.clone(); - let remote_object_store = self.remote_object_store.clone(); - - let (sender, receiver) = mpsc::channel::(1000); - let upload_handle = self.start_upload(epoch, receiver)?; - let write_handler = tokio::task::spawn_blocking(move || { - self.write_live_object_set( - epoch, - perpetual_db, - sender, - Self::bucket_func, - include_wrapped_tombstone, - ) - }); - write_handler.await?.context(format!( - "Failed to write state snapshot for epoch: {}", - &epoch - ))?; - - upload_handle.await?.context(format!( - "Failed to upload state snapshot for epoch: {}", - &epoch - ))?; - - Self::sync_file_to_remote( - local_staging_dir, - manifest_file_path, - local_object_store, - remote_object_store, - ) - .await?; - Ok(()) - } - - fn start_upload( - &self, - epoch: u64, - receiver: Receiver, - ) -> Result, anyhow::Error>>> { - let remote_object_store = self.remote_object_store.clone(); - let local_staging_store = self.local_staging_store.clone(); - let local_dir_path = self.local_staging_dir.clone(); - let epoch_dir = self.epoch_dir(epoch); - let upload_concurrency = self.concurrency; - let join_handle = tokio::spawn(async move { - let results: Vec> = ReceiverStream::new(receiver) - .map(|file_metadata| { - let file_path = file_metadata.file_path(&epoch_dir); - let remote_object_store = remote_object_store.clone(); - let local_object_store = local_staging_store.clone(); - let local_dir_path = local_dir_path.clone(); - async move { - Self::sync_file_to_remote( - local_dir_path.clone(), - file_path.clone(), - local_object_store.clone(), - remote_object_store.clone(), - ) - .await?; - Ok(()) - } - }) - .boxed() - .buffer_unordered(upload_concurrency) - .collect() - .await; - results - .into_iter() - .collect::, anyhow::Error>>() - }); - Ok(join_handle) - } - - fn write_live_object_set( - &mut self, - epoch: u64, - perpetual_db: Arc, - sender: Sender, - bucket_func: F, - include_wrapped_tombstone: bool, - ) -> Result<()> - where - F: Fn(&LiveObject) -> u32, - { - let mut object_writers: HashMap = HashMap::new(); - let local_staging_dir_path = - path_to_filesystem(self.local_staging_dir.clone(), &self.epoch_dir(epoch))?; - for object in perpetual_db.iter_live_object_set(include_wrapped_tombstone) { - let bucket_num = bucket_func(&object); - if let Vacant(entry) = object_writers.entry(bucket_num) { - entry.insert(LiveObjectSetWriterV1::new( - local_staging_dir_path.clone(), - bucket_num, - self.file_compression, - sender.clone(), - )?); - } - let writer = object_writers - .get_mut(&bucket_num) - .context("Unexpected missing bucket writer")?; - writer.write(&object)?; - } - let mut files = vec![]; - for (_, writer) in object_writers.into_iter() { - files.extend(writer.done()?); - } - self.write_manifest(epoch, files)?; - Ok(()) - } - - fn write_manifest(&mut self, epoch: u64, file_metadata: Vec) -> Result<()> { - let (f, manifest_file_path) = self.manifest_file(epoch)?; - let mut wbuf = BufWriter::new(f); - let manifest: Manifest = Manifest::V1(ManifestV1 { - snapshot_version: 1, - address_length: ObjectID::LENGTH as u64, - file_metadata, - epoch, - }); - let serialized_manifest = bcs::to_bytes(&manifest)?; - wbuf.write_all(&serialized_manifest)?; - wbuf.flush()?; - wbuf.get_ref().sync_data()?; - let sha3_digest = compute_sha3_checksum(&manifest_file_path)?; - wbuf.write_all(&sha3_digest)?; - wbuf.flush()?; - wbuf.get_ref().sync_data()?; - let off = wbuf.get_ref().stream_position()?; - wbuf.get_ref().set_len(off)?; - Ok(()) - } - - fn manifest_file(&mut self, epoch: u64) -> Result<(File, PathBuf)> { - let manifest_file_path = path_to_filesystem( - self.local_staging_dir.clone(), - &self.epoch_dir(epoch).child("MANIFEST"), - )?; - let manifest_file_tmp_path = path_to_filesystem( - self.local_staging_dir.clone(), - &self.epoch_dir(epoch).child("MANIFEST.tmp"), - )?; - let mut f = File::create(manifest_file_tmp_path.clone())?; - let mut metab = vec![0u8; MAGIC_BYTES]; - BigEndian::write_u32(&mut metab, MANIFEST_FILE_MAGIC); - f.rewind()?; - f.write_all(&metab)?; - drop(f); - fs::rename(manifest_file_tmp_path, manifest_file_path.clone())?; - let mut f = OpenOptions::new() - .append(true) - .open(manifest_file_path.clone())?; - f.seek(SeekFrom::Start(MAGIC_BYTES as u64))?; - Ok((f, manifest_file_path)) - } - - fn bucket_func(_object: &LiveObject) -> u32 { - // TODO: Use the hash bucketing function used for accumulator tree if there is - // one - 1u32 - } - - fn epoch_dir(&self, epoch: u64) -> Path { - Path::from(format!("epoch_{}", epoch)) - } - - async fn setup_epoch_dir(&self, epoch: u64) -> Result<()> { - let epoch_dir = self.epoch_dir(epoch); - // Delete remote epoch dir if it exists - delete_recursively( - &epoch_dir, - &self.remote_object_store, - NonZeroUsize::new(self.concurrency).unwrap(), - ) - .await?; - // Delete local staging epoch dir if it exists - let local_epoch_dir_path = self.local_staging_dir.join(format!("epoch_{}", epoch)); - if local_epoch_dir_path.exists() { - fs::remove_dir_all(&local_epoch_dir_path)?; - } - fs::create_dir_all(&local_epoch_dir_path)?; - Ok(()) - } - - async fn sync_file_to_remote( - local_path: PathBuf, - path: Path, - from: Arc, - to: Arc, - ) -> Result<()> { - debug!("Syncing snapshot file to remote: {:?}", path); - copy_file(&path, &path, &from, &to).await?; - fs::remove_file(path_to_filesystem(local_path, &path)?)?; - Ok(()) - } -} diff --git a/crates/sui-source-validation-service/Cargo.toml b/crates/sui-source-validation-service/Cargo.toml deleted file mode 100644 index 52687c81aab..00000000000 --- a/crates/sui-source-validation-service/Cargo.toml +++ /dev/null @@ -1,54 +0,0 @@ -[package] -name = "sui-source-validation-service" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[lib] -path = "src/lib.rs" - -[[bin]] -path = "src/main.rs" -name = "sui-source-validation-service" - -[dependencies] -anyhow = { version = "1.0.64", features = ["backtrace"] } -clap.workspace = true -hyper = "0.14" -jsonrpsee.workspace = true -tempfile = "3.3.0" -tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } -toml = { version = "0.7.4", features = ["preserve_order"] } -tracing = "0.1.36" -serde = { version = "1.0.144", features = ["derive"] } -url = "2.3.1" - -sui-move.workspace = true -sui-move-build.workspace = true -sui-sdk.workspace = true -sui-source-validation.workspace = true - -axum.workspace = true -const-str.workspace = true -git-version.workspace = true -move-package.workspace = true -move-compiler.workspace = true -move-core-types.workspace = true -move-symbol-pool.workspace = true -mysten-metrics.workspace = true -prometheus.workspace = true -telemetry-subscribers.workspace = true -tower.workspace = true -tower-http.workspace = true - -[dev-dependencies] -expect-test = "1.4.0" -fs_extra = "1.3.0" -reqwest = { version = "0.11", default-features = false, features = ["rustls-tls"] } - -sui.workspace = true -sui-move = { workspace = true, features = ["all"] } -sui-json-rpc-types.workspace = true -test-cluster.workspace = true diff --git a/crates/sui-source-validation-service/README.md b/crates/sui-source-validation-service/README.md deleted file mode 100644 index c7417b20f29..00000000000 --- a/crates/sui-source-validation-service/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# Sui Source Validation Service - -This document describes the Sui Source Validation Service. It is engineering documentation primarily for engineers who may want to build, extend, configure, or understand the service. - -The Source Validation Service is a server that returns Move source code associated with on-chain Move bytecode. It fetches and builds Move source code for a repository, and then verifies that the built artifact matches the on-chain bytecode. - -The default configuration limits scope to Sui framework packages in `crates/sui-framework/packages`: - -- `move-stdlib` — [address `0x1`](https://suiexplorer.com/object/0x1) -- `sui-framework` — [address `0x2`](https://suiexplorer.com/object/0x2) -- `sui-system` — [address `0x3`](https://suiexplorer.com/object/0x2) -- `deepbook` — [address `0xdee9`](https://suiexplorer.com/object/0xdee9) - -See examples below for requesting source from the server. - -## Build and Run - -``` -cargo run --release --bin sui-source-validation-service crates/sui-source-validation-service/config.toml -``` - -See [`config.toml` in this directory](config.toml). - -## Configuring - -A sample configuration entry is as follows: - -```toml -[[packages]] -source = "Repository" -[packages.values] -repository = "https://github.com/mystenlabs/sui" -branch = "framework/mainnet" -network = "mainnet" -packages = [ - { path = "crates/sui-framework/packages/deepbook", watch = "0xdee9" }, - { path = "crates/sui-framework/packages/move-stdlib", watch = "0x1" }, - { path = "crates/sui-framework/packages/sui-framework", watch = "0x2" }, - { path = "crates/sui-framework/packages/sui-system", watch = "0x3" }, -] -``` - -It specifies the `repository` and `branch` for one or more move `packages`. `network` specifies the on-chain network to verify the source against. It can be one of `mainnet`, `testnet`, `devnet`, or `localnet`. - -A package `path` specifies the path of the package in the repository (where the `Move.toml` is). -The `watch` field is optional, and specifies the address of an object that the server should monitor for on-chain changes if a package is upgraded. For example, Sui framework packages mutate their on-chain address when upgraded. -Non-framework packages may mutate an `UpgradeCap` or an object wrapping the `UpgradeCap` (in which case, `watch` should be set to the `UpgradeCap` object ID or wrapped object ID respectively). - -Currently the `watch` field intends only to invalidate and evict the source code if on-chain code changes via upgrades. Due to current limitations, it does not automatically attempt to find and reprocess the latest source code. To reprocess the latest source code, restart the server, which will download and verify the source code afresh. - -The `HOST_PORT` environment variable sets the server host and port. The default is `0.0.0.0:8000`. - -## Usage - -After running `cargo run --bin sui-source-validation-service crates/sui-source-validation-service/config.toml` locally, try: - -``` -curl 'http://0.0.0.0:8000/api?address=0x2&module=coin&network=mainnet' --header 'X-Sui-Source-Validation-Version: 0.1' -``` - -This returns the source code for module `coin` on `mainnet` where the package `address` is `0x2` in JSON, e.g., `{"source":"..."}`. - -For errors, or if the source code does not exist, an error encoded in JSON returns, e.g., `{"error":"..."}`. - -The URL parameters `address`, `module`, and `network` are required. - -Although not required, it is good practice to set the `X-Sui-Source-Validation-Version` header. diff --git a/crates/sui-source-validation-service/config.toml b/crates/sui-source-validation-service/config.toml deleted file mode 100644 index 488a17e9229..00000000000 --- a/crates/sui-source-validation-service/config.toml +++ /dev/null @@ -1,73 +0,0 @@ -[[packages]] -source = "Repository" -[packages.values] -repository = "https://github.com/mystenlabs/sui" -network = "mainnet" -[[packages.values.branches]] -branch = "framework/mainnet" -paths = [ - { path = "crates/sui-framework/packages/deepbook", watch = "0xdee9" }, - { path = "crates/sui-framework/packages/move-stdlib", watch = "0x1" }, - { path = "crates/sui-framework/packages/sui-framework", watch = "0x2" }, - { path = "crates/sui-framework/packages/sui-system", watch = "0x3" } -] - -[[packages]] -source = "Repository" -[packages.values] -repository = "https://github.com/mystenlabs/sui" -network = "testnet" -[[packages.values.branches]] -branch = "framework/testnet" -paths = [ - { path = "crates/sui-framework/packages/deepbook", watch = "0xdee9" }, - { path = "crates/sui-framework/packages/move-stdlib", watch = "0x1" }, - { path = "crates/sui-framework/packages/sui-framework", watch = "0x2" }, - { path = "crates/sui-framework/packages/sui-system", watch = "0x3" } -] - -[[packages]] -source = "Repository" -[packages.values] -repository = "https://github.com/mystenlabs/sui" -network = "devnet" -[[packages.values.branches]] -branch = "framework/devnet" -paths = [ - { path = "crates/sui-framework/packages/deepbook", watch = "0xdee9" }, - { path = "crates/sui-framework/packages/move-stdlib", watch = "0x1" }, - { path = "crates/sui-framework/packages/sui-framework", watch = "0x2" }, - { path = "crates/sui-framework/packages/sui-system", watch = "0x3" } -] - -[[packages]] -source = "Repository" -[packages.values] -repository = "https://github.com/mystenlabs/apps" -network = "mainnet" -[[packages.values.branches]] -branch = "main" -paths = [ - { path = "kiosk" }, -] - -[[packages]] -source = "Repository" -[packages.values] -repository = "https://github.com/mystenlabs/apps" -network = "testnet" -[[packages.values.branches]] -branch = "testnet" -paths = [ - { path = "kiosk" }, -] - -# [[packages]] -# source = "Repository" -# [packages.values] -# repository = "https://github.com/kunalabs-io/sui-smart-contracts" -# [[packages.values.branches]] -# branch = "master" -# paths = [ -# { path = "kai-finance" } -# ] \ No newline at end of file diff --git a/crates/sui-source-validation-service/src/lib.rs b/crates/sui-source-validation-service/src/lib.rs deleted file mode 100644 index 4bee710c59d..00000000000 --- a/crates/sui-source-validation-service/src/lib.rs +++ /dev/null @@ -1,715 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::BTreeMap, - ffi::OsString, - fmt, fs, - net::TcpListener, - path::{Path, PathBuf}, - process::Command, - sync::{Arc, RwLock}, - time::Duration, -}; - -use anyhow::{anyhow, bail}; -use axum::{ - extract::{Query, State}, - middleware::{self, Next}, - response::{IntoResponse, Response}, - routing::{get, IntoMakeService}, - Extension, Json, Router, Server, -}; -use hyper::{ - http::{HeaderName, HeaderValue, Method}, - server::conn::AddrIncoming, - HeaderMap, StatusCode, -}; -use jsonrpsee::{ - core::{ - client::{Subscription, SubscriptionClientT}, - params::ArrayParams, - }, - ws_client::{WsClient, WsClientBuilder}, -}; -use move_core_types::account_address::AccountAddress; -use move_package::{BuildConfig as MoveBuildConfig, LintFlag}; -use move_symbol_pool::Symbol; -use mysten_metrics::RegistryService; -use prometheus::{register_int_counter_with_registry, IntCounter, Registry}; -use serde::{Deserialize, Serialize}; -use sui_move::build::resolve_lock_file_path; -use sui_move_build::{BuildConfig, SuiPackageHooks}; -use sui_sdk::{ - rpc_types::{SuiTransactionBlockEffects, TransactionFilter}, - types::base_types::ObjectID, - SuiClientBuilder, -}; -use sui_source_validation::{BytecodeSourceVerifier, SourceMode}; -use tokio::sync::oneshot::Sender; -use tower::ServiceBuilder; -use tracing::{debug, error, info}; -use url::Url; - -pub const HOST_PORT_ENV: &str = "HOST_PORT"; -pub const SUI_SOURCE_VALIDATION_VERSION_HEADER: &str = "x-sui-source-validation-version"; -pub const SUI_SOURCE_VALIDATION_VERSION: &str = "0.1"; - -pub const MAINNET_URL: &str = "https://fullnode.mainnet.sui.io:443"; -pub const TESTNET_URL: &str = "https://fullnode.testnet.sui.io:443"; -pub const DEVNET_URL: &str = "https://fullnode.devnet.sui.io:443"; -pub const LOCALNET_URL: &str = "http://127.0.0.1:9000"; - -pub const MAINNET_WS_URL: &str = "wss://rpc.mainnet.sui.io:443"; -pub const TESTNET_WS_URL: &str = "wss://rpc.testnet.sui.io:443"; -pub const DEVNET_WS_URL: &str = "wss://rpc.devnet.sui.io:443"; -pub const LOCALNET_WS_URL: &str = "ws://127.0.0.1:9000"; - -pub const WS_PING_INTERVAL: Duration = Duration::from_millis(20_000); - -pub const METRICS_ROUTE: &str = "/metrics"; -pub const METRICS_HOST_PORT: &str = "0.0.0.0:9184"; - -pub fn host_port() -> String { - match option_env!("HOST_PORT") { - Some(v) => v.to_string(), - None => String::from("0.0.0.0:8000"), - } -} - -#[derive(Clone, Deserialize, Debug)] -pub struct Config { - pub packages: Vec, -} - -#[derive(Clone, Deserialize, Debug)] -#[serde(tag = "source", content = "values")] -pub enum PackageSource { - Repository(RepositorySource), - Directory(DirectorySource), -} - -#[derive(Clone, Deserialize, Debug)] -pub struct RepositorySource { - pub repository: String, - pub network: Option, - pub branches: Vec, -} - -#[derive(Clone, Deserialize, Debug)] -pub struct Branch { - pub branch: String, - pub paths: Vec, -} - -#[derive(Clone, Deserialize, Debug)] -pub struct DirectorySource { - pub paths: Vec, - pub network: Option, -} - -#[derive(Clone, Deserialize, Debug)] -pub struct Package { - pub path: String, - /// Optional object ID to watch for upgrades. For framework packages, this - /// is an address like 0x2. For non-framework packages this is an - /// upgrade cap (possibly wrapped). - pub watch: Option, -} - -#[derive(Clone, Serialize, Debug)] -pub struct SourceInfo { - pub path: PathBuf, - #[serde(skip_serializing_if = "Option::is_none")] - // Is Some when content is hydrated from disk. - pub source: Option, -} - -#[derive(Eq, PartialEq, Clone, Default, Serialize, Deserialize, Debug, Ord, PartialOrd)] -#[serde(rename_all = "lowercase")] -pub enum Network { - #[default] - #[serde(alias = "Mainnet")] - Mainnet, - #[serde(alias = "Testnet")] - Testnet, - #[serde(alias = "Devnet")] - Devnet, - #[serde(alias = "Localnet")] - Localnet, -} - -impl fmt::Display for Network { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match self { - Network::Mainnet => "mainnet", - Network::Testnet => "testnet", - Network::Devnet => "devnet", - Network::Localnet => "localnet", - } - ) - } -} - -/// Map module name to verified source info. -pub type SourceLookup = BTreeMap; -/// Map addresses to module names and sources. -pub type AddressLookup = BTreeMap; -/// Top-level lookup that maps network to sources for corresponding on-chain -/// networks. -pub type NetworkLookup = BTreeMap; - -pub async fn verify_package( - network: &Network, - package_path: impl AsRef, -) -> anyhow::Result<(Network, AddressLookup)> { - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); - let mut config = resolve_lock_file_path( - MoveBuildConfig::default(), - Some(package_path.as_ref().to_path_buf()), - )?; - config.lint_flag = LintFlag::LEVEL_NONE; - config.silence_warnings = true; - let build_config = BuildConfig { - config, - run_bytecode_verifier: false, // no need to run verifier if code is on-chain - print_diags_to_stderr: false, - }; - let compiled_package = build_config.build(package_path.as_ref().to_path_buf())?; - - let network_url = match network { - Network::Mainnet => MAINNET_URL, - Network::Testnet => TESTNET_URL, - Network::Devnet => DEVNET_URL, - Network::Localnet => LOCALNET_URL, - }; - let client = SuiClientBuilder::default().build(network_url).await?; - BytecodeSourceVerifier::new(client.read_api()) - .verify_package( - &compiled_package, - // verify_deps - false, - SourceMode::Verify, - ) - .await - .map_err(|e| anyhow!("Network {network}: {e}"))?; - - let mut address_map = AddressLookup::new(); - let address = compiled_package - .published_at - .as_ref() - .map(|id| **id) - .map_err(|_| anyhow!("could not resolve published-at field in package manifest"))?; - info!("verifying {} at {address}", package_path.as_ref().display()); - for v in &compiled_package.package.root_compiled_units { - let path = v.source_path.to_path_buf(); - let source = Some(fs::read_to_string(path.as_path())?); - let name = v.unit.name; - if let Some(existing) = address_map.get_mut(&address) { - existing.insert(name, SourceInfo { path, source }); - } else { - let mut source_map = SourceLookup::new(); - source_map.insert(name, SourceInfo { path, source }); - address_map.insert(address, source_map); - } - } - Ok((network.clone(), address_map)) -} - -pub fn parse_config(config_path: impl AsRef) -> anyhow::Result { - let contents = fs::read_to_string(config_path)?; - Ok(toml::from_str(&contents)?) -} - -pub fn repo_name_from_url(url: &str) -> anyhow::Result { - let repo_url = Url::parse(url)?; - let mut components = repo_url - .path_segments() - .ok_or_else(|| anyhow!("Could not discover repository path in url {url}"))?; - let repo_name = components - .next_back() - .ok_or_else(|| anyhow!("Could not discover repository name in url {url}"))?; - Ok(repo_name.to_string()) -} - -#[derive(Debug)] -/// Represents a sequence of git commands to clone a repository and sparsely -/// checkout Move packages within. -pub struct CloneCommand { - /// git args - args: Vec>, - /// report repository url in error messages - repo_url: String, -} - -impl CloneCommand { - pub fn new(p: &RepositorySource, b: &Branch, dest: &Path) -> anyhow::Result { - let repo_name = repo_name_from_url(&p.repository)?; - let network = p.network.clone().unwrap_or_default().to_string(); - let sanitized_branch = b.branch.replace('/', "__"); - let dest = dest - .join(network) - .join(format!("{repo_name}__{sanitized_branch}")) - .into_os_string(); - - macro_rules! ostr { - ($arg:expr) => { - OsString::from($arg) - }; - } - - let mut args = vec![]; - // Args to clone empty repository - let cmd_args: Vec = vec![ - ostr!("clone"), - ostr!("--no-checkout"), - ostr!("--depth=1"), // implies --single-branch - ostr!("--filter=tree:0"), - ostr!(format!("--branch={}", b.branch)), - ostr!(&p.repository), - ostr!(dest.clone()), - ]; - args.push(cmd_args); - - // Args to sparse checkout the package set - let mut cmd_args: Vec = vec![ - ostr!("-C"), - dest.clone(), - ostr!("sparse-checkout"), - ostr!("set"), - ostr!("--no-cone"), - ]; - let path_args: Vec = b - .paths - .iter() - .map(|p| OsString::from(p.path.clone())) - .collect(); - cmd_args.extend_from_slice(&path_args); - args.push(cmd_args); - - // Args to checkout the default branch. - let cmd_args: Vec = vec![ostr!("-C"), dest, ostr!("checkout")]; - args.push(cmd_args); - - Ok(Self { - args, - repo_url: p.repository.clone(), - }) - } - - pub async fn run(&self) -> anyhow::Result<()> { - for args in &self.args { - let result = Command::new("git").args(args).output().map_err(|_| { - anyhow!( - "Error cloning {} with command `git {:#?}`", - self.repo_url, - args - ) - })?; - if !result.status.success() { - bail!( - "Nonzero exit status when cloning {} with command `git {:#?}`. \ - Stderr: {}", - self.repo_url, - args, - String::from_utf8_lossy(&result.stderr) - ) - } - } - Ok(()) - } -} - -/// Clones repositories and checks out packages as per `config` at the directory -/// `dir`. -pub async fn clone_repositories(repos: Vec<&RepositorySource>, dir: &Path) -> anyhow::Result<()> { - let mut tasks = vec![]; - for p in &repos { - for b in &p.branches { - let command = CloneCommand::new(p, b, dir)?; - info!( - "cloning {}:{} to {}", - &p.repository, - &b.branch, - dir.display() - ); - let t = tokio::spawn(async move { command.run().await }); - tasks.push(t); - } - } - - for t in tasks { - t.await.unwrap()?; - } - Ok(()) -} - -pub async fn initialize( - config: &Config, - dir: &Path, -) -> anyhow::Result<(NetworkLookup, NetworkLookup)> { - let mut repos = vec![]; - for s in &config.packages { - match s { - PackageSource::Repository(r) => repos.push(r), - PackageSource::Directory(_) => (), // skip cloning - } - } - clone_repositories(repos, dir).await?; - let sources = verify_packages(config, dir).await?; - let sources_list = sources_list(&sources).await; - Ok((sources, sources_list)) -} - -pub async fn sources_list(sources: &NetworkLookup) -> NetworkLookup { - let mut sources_list = NetworkLookup::new(); - for (network, addresses) in sources { - let mut address_map = AddressLookup::new(); - for (address, symbols) in addresses { - let mut symbol_map = SourceLookup::new(); - for (symbol, source_info) in symbols { - symbol_map.insert( - *symbol, - SourceInfo { - path: source_info.path.file_name().unwrap().into(), - source: None, - }, - ); - } - address_map.insert(*address, symbol_map); - } - sources_list.insert(network.clone(), address_map); - } - sources_list -} - -pub async fn verify_packages(config: &Config, dir: &Path) -> anyhow::Result { - let mut tasks = vec![]; - for p in &config.packages { - match p { - PackageSource::Repository(r) => { - let repo_name = repo_name_from_url(&r.repository)?; - let network_name = r.network.clone().unwrap_or_default().to_string(); - for b in &r.branches { - for p in &b.paths { - let sanitized_branch = b.branch.replace('/', "__"); - let package_path = dir - .join(network_name.clone()) - .join(format!("{repo_name}__{sanitized_branch}")) - .join(p.path.clone()) - .clone(); - let network = r.network.clone().unwrap_or_default(); - let t = - tokio::spawn( - async move { verify_package(&network, package_path).await }, - ); - tasks.push(t) - } - } - } - PackageSource::Directory(packages_dir) => { - for p in &packages_dir.paths { - let package_path = PathBuf::from(p.path.clone()); - let network = packages_dir.network.clone().unwrap_or_default(); - let t = - tokio::spawn(async move { verify_package(&network, package_path).await }); - tasks.push(t) - } - } - } - } - - let mut mainnet_lookup = AddressLookup::new(); - let mut testnet_lookup = AddressLookup::new(); - let mut devnet_lookup = AddressLookup::new(); - let mut localnet_lookup = AddressLookup::new(); - for t in tasks { - let (network, new_lookup) = t.await.unwrap()?; - match network { - Network::Mainnet => mainnet_lookup.extend(new_lookup), - Network::Testnet => testnet_lookup.extend(new_lookup), - Network::Devnet => devnet_lookup.extend(new_lookup), - Network::Localnet => localnet_lookup.extend(new_lookup), - } - } - let mut lookup = NetworkLookup::new(); - lookup.insert(Network::Mainnet, mainnet_lookup); - lookup.insert(Network::Testnet, testnet_lookup); - lookup.insert(Network::Devnet, devnet_lookup); - lookup.insert(Network::Localnet, localnet_lookup); - Ok(lookup) -} - -// A thread that monitors on-chain transactions for package upgrades. `config` -// specifies which packages to watch. `app_state` contains the map of sources -// returned by the server. In particular, `watch_for_upgrades` invalidates -// (i.e., clears) the sources returned by the serve when we observe a package -// upgrade, so that we do not falsely report outdated sources for a package. -// Pass an optional `channel` to observe the upgrade transaction(s). -// The `channel` parameter exists for testing. -pub async fn watch_for_upgrades( - packages: Vec, - app_state: Arc>, - network: Network, - channel: Option>, -) -> anyhow::Result<()> { - let mut watch_ids = ArrayParams::new(); - let mut num_packages = 0; - for s in packages { - let branches = match s { - PackageSource::Repository(RepositorySource { branches, .. }) => branches, - PackageSource::Directory(DirectorySource { paths, .. }) => vec![Branch { - branch: "".into(), // Unused. - paths, - }], - }; - for b in branches { - for p in b.paths { - if let Some(id) = p.watch { - num_packages += 1; - watch_ids.insert(TransactionFilter::ChangedObject(id))? - } - } - } - } - - let websocket_url = match network { - Network::Mainnet => MAINNET_WS_URL, - Network::Testnet => TESTNET_WS_URL, - Network::Devnet => DEVNET_WS_URL, - Network::Localnet => LOCALNET_WS_URL, - }; - - let client: WsClient = WsClientBuilder::default() - .ping_interval(WS_PING_INTERVAL) - .build(websocket_url) - .await?; - let mut subscription: Subscription = client - .subscribe( - "suix_subscribeTransaction", - watch_ids, - "suix_unsubscribeTransaction", - ) - .await - .map_err(|e| anyhow!("Failed to open websocket connection for {}: {}", network, e))?; - - info!("Listening for upgrades on {num_packages} package(s) on {websocket_url}..."); - loop { - let result: Option> = subscription.next().await; - match result { - Some(Ok(result)) => { - // We see an upgrade transaction. Clear all sources since all of part of these - // may now be invalid. Currently we need to restart the server - // within some time delta of this observation to resume - // returning source. Restarting revalidates the latest release sources per - // repositories in the config file. Restarting is a manual - // side-effect outside of this server because we need to ensure that sources in - // the repositories _actually contain_ the latest source - // corresponding to on-chain data (which is subject to - // manual syncing itself currently). - info!("Saw upgrade txn: {:?}", result); - let mut app_state = app_state.write().unwrap(); - app_state.sources = NetworkLookup::new(); // Clear all sources. - app_state.sources_list = NetworkLookup::new(); // Clear all listed sources. - if let Some(channel) = channel { - channel.send(result).unwrap(); - break Ok(()); - } - info!("Shutting down server (resync performed on restart)"); - std::process::exit(1) - } - Some(_) => { - info!("Saw failed transaction when listening to upgrades.") - } - None => { - error!( - "Fatal: WebSocket connection lost while listening for upgrades. Shutting down server." - ); - std::process::exit(1) - } - } - } -} - -pub struct AppState { - pub sources: NetworkLookup, - pub metrics: Option, - pub sources_list: NetworkLookup, -} - -pub fn serve( - app_state: Arc>, -) -> anyhow::Result>> { - let app = Router::new() - .route("/api", get(api_route)) - .route("/api/list", get(list_route)) - .layer( - ServiceBuilder::new() - .layer( - tower_http::cors::CorsLayer::new() - .allow_methods([Method::GET]) - .allow_origin(tower_http::cors::Any), - ) - .layer(middleware::from_fn(check_version_header)), - ) - .with_state(app_state); - let listener = TcpListener::bind(host_port())?; - Ok(Server::from_tcp(listener)?.serve(app.into_make_service())) -} - -#[derive(Deserialize)] -pub struct Request { - #[serde(default)] - network: Network, - address: String, - module: String, -} - -#[derive(Serialize, Deserialize)] -pub struct SourceResponse { - pub source: String, -} - -#[derive(Serialize, Deserialize)] -pub struct ErrorResponse { - pub error: String, -} - -async fn api_route( - State(app_state): State>>, - Query(Request { - network, - address, - module, - }): Query, -) -> impl IntoResponse { - debug!("request network={network}&address={address}&module={module}"); - let symbol = Symbol::from(module); - let Ok(address) = AccountAddress::from_hex_literal(&address) else { - let error = format!("Invalid hex address {address}"); - return ( - StatusCode::BAD_REQUEST, - Json(ErrorResponse { error }).into_response(), - ); - }; - - let app_state = app_state.read().unwrap(); - if let Some(metrics) = &app_state.metrics { - metrics.total_requests_received.inc(); - } - let source_result = app_state - .sources - .get(&network) - .and_then(|n| n.get(&address)) - .and_then(|a| a.get(&symbol)); - if let Some(SourceInfo { - source: Some(source), - .. - }) = source_result - { - ( - StatusCode::OK, - Json(SourceResponse { - source: source.to_owned(), - }) - .into_response(), - ) - } else { - ( - StatusCode::NOT_FOUND, - Json(ErrorResponse { - error: format!( - "No source found for {symbol} at address {address} on network {network}" - ), - }) - .into_response(), - ) - } -} - -async fn check_version_header( - headers: HeaderMap, - req: hyper::Request, - next: Next, -) -> Response { - let version = headers - .get(SUI_SOURCE_VALIDATION_VERSION_HEADER) - .as_ref() - .and_then(|h| h.to_str().ok()) - .map(|s| s.to_string()); - - match version { - Some(v) if v != SUI_SOURCE_VALIDATION_VERSION => { - let error = format!( - "Unsupported version '{v}' specified in header \ - {SUI_SOURCE_VALIDATION_VERSION_HEADER}" - ); - let mut headers = HeaderMap::new(); - headers.insert( - HeaderName::from_static(SUI_SOURCE_VALIDATION_VERSION_HEADER), - HeaderValue::from_static(SUI_SOURCE_VALIDATION_VERSION), - ); - return ( - StatusCode::BAD_REQUEST, - headers, - Json(ErrorResponse { error }).into_response(), - ) - .into_response(); - } - _ => (), - } - let mut response = next.run(req).await; - response.headers_mut().insert( - HeaderName::from_static(SUI_SOURCE_VALIDATION_VERSION_HEADER), - HeaderValue::from_static(SUI_SOURCE_VALIDATION_VERSION), - ); - response -} - -async fn list_route(State(app_state): State>>) -> impl IntoResponse { - let app_state = app_state.read().unwrap(); - ( - StatusCode::OK, - Json(app_state.sources_list.clone()).into_response(), - ) -} - -pub struct SourceServiceMetrics { - pub total_requests_received: IntCounter, -} - -impl SourceServiceMetrics { - pub fn new(registry: &Registry) -> Self { - Self { - total_requests_received: register_int_counter_with_registry!( - "total_requests", - "Total number of requests received by Source Service", - registry - ) - .unwrap(), - } - } -} - -pub fn start_prometheus_server(addr: TcpListener) -> RegistryService { - let registry = Registry::new(); - - let registry_service = RegistryService::new(registry); - - let app = Router::new() - .route(METRICS_ROUTE, get(mysten_metrics::metrics)) - .layer(Extension(registry_service.clone())); - - tokio::spawn(async move { - axum::Server::from_tcp(addr) - .unwrap() - .serve(app.into_make_service()) - .await - .unwrap(); - }); - - registry_service -} diff --git a/crates/sui-source-validation-service/src/main.rs b/crates/sui-source-validation-service/src/main.rs deleted file mode 100644 index caaf7e7e8ce..00000000000 --- a/crates/sui-source-validation-service/src/main.rs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - path::PathBuf, - sync::{Arc, RwLock}, -}; - -use clap::Parser; -use sui_source_validation_service::{ - host_port, initialize, parse_config, serve, start_prometheus_server, watch_for_upgrades, - AppState, DirectorySource, Network, PackageSource, RepositorySource, SourceServiceMetrics, - METRICS_HOST_PORT, -}; -use telemetry_subscribers::TelemetryConfig; -use tracing::info; - -#[derive(Parser, Debug)] -struct Args { - config_path: PathBuf, -} - -const GIT_REVISION: &str = { - if let Some(revision) = option_env!("GIT_REVISION") { - revision - } else { - git_version::git_version!( - args = ["--always", "--dirty", "--exclude", "*"], - fallback = "DIRTY" - ) - } -}; - -pub const VERSION: &str = const_str::concat!(env!("CARGO_PKG_VERSION"), "-", GIT_REVISION); - -#[tokio::main] -pub async fn main() -> anyhow::Result<()> { - let args = Args::parse(); - let _logging_guard = TelemetryConfig::new().with_env().init(); - let package_config = parse_config(args.config_path)?; - let tmp_dir = tempfile::tempdir()?; - let start = tokio::time::Instant::now(); - let (sources, sources_list) = initialize(&package_config, tmp_dir.path()).await?; - info!("verification complete in {:?}", start.elapsed()); - - let metrics_listener = std::net::TcpListener::bind(METRICS_HOST_PORT)?; - let registry_service = start_prometheus_server(metrics_listener); - let prometheus_registry = registry_service.default_registry(); - let metrics = SourceServiceMetrics::new(&prometheus_registry); - - let app_state = Arc::new(RwLock::new(AppState { - sources, - metrics: Some(metrics), - sources_list, - })); - let mut threads = vec![]; - let networks_to_watch = vec![ - Network::Mainnet, - Network::Testnet, - Network::Devnet, - Network::Localnet, - ]; - // spawn a watcher thread for upgrades for each network - for network in networks_to_watch { - let app_state_copy = app_state.clone(); - let packages: Vec<_> = package_config - .clone() - .packages - .into_iter() - .filter(|p| { - matches!( - p, - PackageSource::Repository(RepositorySource { - network: Some(n), - .. - }) | PackageSource::Directory(DirectorySource { - network: Some(n), - .. - }) if *n == network, - ) - }) - .collect(); - if packages.is_empty() { - continue; - } - let watcher = tokio::spawn(async move { - watch_for_upgrades(packages, app_state_copy, network, None).await - }); - threads.push(watcher); - } - - let app_state_copy = app_state.clone(); - let server = tokio::spawn(async { serve(app_state_copy)?.await.map_err(anyhow::Error::from) }); - threads.push(server); - info!("serving on {}", host_port()); - for t in threads { - t.await.unwrap()?; - } - Ok(()) -} diff --git a/crates/sui-source-validation-service/tests/fixture/custom/sources/custom.move b/crates/sui-source-validation-service/tests/fixture/custom/sources/custom.move deleted file mode 100644 index 2689f5f172c..00000000000 --- a/crates/sui-source-validation-service/tests/fixture/custom/sources/custom.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module custom::foo { - public fun id(): u64 { - 0 - } -} diff --git a/crates/sui-source-validation-service/tests/fixture/sui__main/move-stdlib/sources/address.move b/crates/sui-source-validation-service/tests/fixture/sui__main/move-stdlib/sources/address.move deleted file mode 100644 index ebc9f0fef17..00000000000 --- a/crates/sui-source-validation-service/tests/fixture/sui__main/move-stdlib/sources/address.move +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Dummy module for testing -module std::address {} diff --git a/crates/sui-source-validation-service/tests/tests.rs b/crates/sui-source-validation-service/tests/tests.rs deleted file mode 100644 index 6bb80323aed..00000000000 --- a/crates/sui-source-validation-service/tests/tests.rs +++ /dev/null @@ -1,543 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[cfg(not(target_os = "windows"))] -use std::os::unix::fs::FileExt; -#[cfg(target_os = "windows")] -use std::os::windows::fs::FileExt; -use std::{ - fs, - io::Read, - path::PathBuf, - sync::{Arc, RwLock}, -}; - -use expect_test::expect; -use move_core_types::account_address::AccountAddress; -use move_symbol_pool::Symbol; -use reqwest::Client; -use sui::client_commands::{SuiClientCommandResult, SuiClientCommands}; -use sui_json_rpc_types::{SuiTransactionBlockEffects, SuiTransactionBlockEffectsAPI}; -use sui_move_build::{BuildConfig, SuiPackageHooks}; -use sui_sdk::{ - rpc_types::{ - OwnedObjectRef, SuiObjectDataOptions, SuiObjectResponseQuery, SuiTransactionBlockEffectsV1, - }, - types::{base_types::ObjectID, object::Owner, transaction::TEST_ONLY_GAS_UNIT_FOR_PUBLISH}, - wallet_context::WalletContext, -}; -use sui_source_validation_service::{ - host_port, initialize, serve, start_prometheus_server, verify_packages, watch_for_upgrades, - AddressLookup, AppState, Branch, CloneCommand, Config, DirectorySource, ErrorResponse, Network, - NetworkLookup, Package, PackageSource, RepositorySource, SourceInfo, SourceLookup, - SourceResponse, SourceServiceMetrics, METRICS_HOST_PORT, SUI_SOURCE_VALIDATION_VERSION_HEADER, -}; -use test_cluster::TestClusterBuilder; -use tokio::sync::oneshot; - -const LOCALNET_PORT: u16 = 9000; -const TEST_FIXTURES_DIR: &str = "tests/fixture"; - -#[allow(clippy::await_holding_lock)] -#[tokio::test] -async fn test_end_to_end() -> anyhow::Result<()> { - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); - let mut test_cluster = TestClusterBuilder::new() - .with_fullnode_rpc_port(LOCALNET_PORT) - .build() - .await; - - /////////////////////////// - // Test watch_for_upgrades - ////////////////////////// - let rgp = test_cluster.get_reference_gas_price().await; - let address = test_cluster.get_address_0(); - let context = &mut test_cluster.wallet; - let client = context.get_client().await?; - let object_refs = client - .read_api() - .get_owned_objects( - address, - Some(SuiObjectResponseQuery::new_with_options( - SuiObjectDataOptions::new() - .with_type() - .with_owner() - .with_previous_transaction(), - )), - None, - None, - ) - .await? - .data; - - let gas_obj_id = object_refs.first().unwrap().object().unwrap().object_id; - let mut package_path = PathBuf::from(TEST_FIXTURES_DIR); - package_path.push("custom"); - - // Publish and get upgrade capability to monitor. - let effects = run_publish(package_path.clone(), context, gas_obj_id, rgp).await?; - let cap = effects - .created() - .iter() - .find(|refe| matches!(refe.owner, Owner::AddressOwner(_))) - .unwrap(); - - // Set up source service config to watch the upgrade cap. - let config = Config { - packages: vec![PackageSource::Directory(DirectorySource { - paths: vec![Package { - path: "unused".into(), - watch: Some(cap.reference.object_id), // watch the upgrade cap - }], - network: Some(Network::Localnet), - })], - }; - // Start watching for upgrades. - let mut sources = NetworkLookup::new(); - sources.insert(Network::Localnet, AddressLookup::new()); - - let mut sources_list = NetworkLookup::new(); - sources_list.insert(Network::Localnet, AddressLookup::new()); - let app_state = Arc::new(RwLock::new(AppState { - sources, - metrics: None, - sources_list, - })); - let app_state_ref = app_state.clone(); - let (tx, rx) = oneshot::channel(); - tokio::spawn(async move { - watch_for_upgrades(config.packages, app_state, Network::Localnet, Some(tx)).await - }); - - // Set up to upgrade package. - let package = effects - .created() - .iter() - .find(|refe| matches!(refe.owner, Owner::Immutable)) - .unwrap(); - let package_id = package.reference.object_id; - let tmp_dir = tempfile::tempdir().unwrap(); - let upgrade_pkg_path = - copy_with_published_at_manifest(&package_path, &tmp_dir.path().to_path_buf(), package_id); - // Run the upgrade. - run_upgrade(upgrade_pkg_path, cap, context, gas_obj_id, rgp).await?; - - // Test expects to observe an upgrade transaction. - let Ok(SuiTransactionBlockEffects::V1(effects)) = rx.await else { - panic!("No upgrade transaction observed") - }; - assert!(effects.status.is_ok()); - // Test expects `sources` of server state to be empty / cleared on upgrade. - let app_state_ref = app_state_ref.read().unwrap(); - assert!(app_state_ref.sources.is_empty()); - - /////////////////////////// - // Test verify_packages - ////////////////////////// - let config = Config { - packages: vec![PackageSource::Repository(RepositorySource { - repository: "https://github.com/mystenlabs/sui".into(), - branches: vec![Branch { - branch: "main".into(), - paths: vec![Package { - path: "move-stdlib".into(), - watch: None, - }], - }], - network: Some(Network::Localnet), - })], - }; - - let fixtures = tempfile::tempdir()?; - fs::create_dir(fixtures.path().join("localnet"))?; - fs_extra::dir::copy( - PathBuf::from(TEST_FIXTURES_DIR).join("sui__main"), - fixtures.path().join("localnet"), - &fs_extra::dir::CopyOptions::default(), - )?; - let result = verify_packages(&config, fixtures.path()).await; - let truncated_error_message = &result - .unwrap_err() - .to_string() - .lines() - .take(3) - .map(|s| s.into()) - .collect::>() - .join("\n"); - let expected = expect![ - r#" -Network localnet: Multiple source verification errors found: - -- Local dependency did not match its on-chain version at 0000000000000000000000000000000000000000000000000000000000000001::MoveStdlib::address"# - ]; - expected.assert_eq(truncated_error_message); - Ok(()) -} - -async fn run_publish( - package_path: PathBuf, - context: &mut WalletContext, - gas_obj_id: ObjectID, - rgp: u64, -) -> anyhow::Result { - let build_config = BuildConfig::new_for_testing().config; - let resp = SuiClientCommands::Publish { - package_path: package_path.clone(), - build_config, - gas: Some(gas_obj_id), - gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, - skip_dependency_verification: false, - with_unpublished_dependencies: false, - serialize_unsigned_transaction: false, - serialize_signed_transaction: false, - } - .execute(context) - .await?; - - let SuiClientCommandResult::Publish(response) = resp else { - unreachable!("Invalid response"); - }; - let SuiTransactionBlockEffects::V1(effects) = response.effects.unwrap(); - assert!(effects.status.is_ok()); - Ok(effects) -} - -async fn run_upgrade( - upgrade_pkg_path: PathBuf, - cap: &OwnedObjectRef, - context: &mut WalletContext, - gas_obj_id: ObjectID, - rgp: u64, -) -> anyhow::Result<()> { - let build_config = BuildConfig::new_for_testing().config; - let resp = SuiClientCommands::Upgrade { - package_path: upgrade_pkg_path, - upgrade_capability: cap.reference.object_id, - build_config, - gas: Some(gas_obj_id), - gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, - skip_dependency_verification: false, - with_unpublished_dependencies: false, - serialize_unsigned_transaction: false, - serialize_signed_transaction: false, - } - .execute(context) - .await?; - - let SuiClientCommandResult::Upgrade(response) = resp else { - unreachable!("Invalid upgrade response"); - }; - let SuiTransactionBlockEffects::V1(effects) = response.effects.unwrap(); - assert!(effects.status.is_ok()); - Ok(()) -} - -/// Copy the package and set `published-at` in the Move toml file. The need for -/// this will be subsumed by automated address management. -fn copy_with_published_at_manifest( - source_path: &PathBuf, - dest_path: &PathBuf, - package_id: ObjectID, -) -> PathBuf { - fs_extra::dir::copy( - source_path, - dest_path, - &fs_extra::dir::CopyOptions::default(), - ) - .unwrap(); - let mut upgrade_pkg_path = dest_path.clone(); - upgrade_pkg_path.extend(["custom", "Move.toml"]); - let mut move_toml = std::fs::File::options() - .read(true) - .write(true) - .open(&upgrade_pkg_path) - .unwrap(); - upgrade_pkg_path.pop(); - - let mut buf = String::new(); - move_toml.read_to_string(&mut buf).unwrap(); - - // Add a `published-at = "0x"` to the Move manifest. - let mut lines: Vec = buf.split('\n').map(|x| x.to_string()).collect(); - let idx = lines.iter().position(|s| s == "[package]").unwrap(); - lines.insert( - idx + 1, - format!("published-at = \"{}\"", package_id.to_hex_uncompressed()), - ); - let new = lines.join("\n"); - - #[cfg(target_os = "windows")] - move_toml.seek_write(new.as_bytes(), 0).unwrap(); - - #[cfg(not(target_os = "windows"))] - move_toml.write_at(new.as_bytes(), 0).unwrap(); - - upgrade_pkg_path -} - -#[tokio::test] -async fn test_api_route() -> anyhow::Result<()> { - let config = Config { packages: vec![] }; - let tmp_dir = tempfile::tempdir()?; - initialize(&config, tmp_dir.path()).await?; - - // set up sample lookup to serve - let fixtures = tempfile::tempdir()?; - fs_extra::dir::copy( - PathBuf::from(TEST_FIXTURES_DIR).join("sui__main"), - fixtures.path(), - &fs_extra::dir::CopyOptions::default(), - )?; - - let address = "0x2"; - let module = "address"; - let source_path = fixtures - .into_path() - .join("sui/move-stdlib/sources/address.move"); - - let mut source_lookup = SourceLookup::new(); - source_lookup.insert( - Symbol::from(module), - SourceInfo { - path: source_path, - source: Some("module address {...}".to_owned()), - }, - ); - let mut address_lookup = AddressLookup::new(); - let account_address = AccountAddress::from_hex_literal(address).unwrap(); - address_lookup.insert(account_address, source_lookup); - let mut sources = NetworkLookup::new(); - sources.insert(Network::Localnet, address_lookup); - let mut sources_list = NetworkLookup::new(); - sources_list.insert(Network::Localnet, AddressLookup::new()); - let app_state = Arc::new(RwLock::new(AppState { - sources, - metrics: None, - sources_list, - })); - tokio::spawn(serve(app_state).expect("Cannot start service.")); - - let client = Client::new(); - - // check that serve returns expected sample code - let json = client - .get(format!( - "http://{}/api?address={address}&module={module}&network=localnet", - host_port() - )) - .send() - .await - .expect("Request failed.") - .json::() - .await?; - - let expected = expect!["module address {...}"]; - expected.assert_eq(&json.source); - - // check /list route - let response = client - .get(format!("http://{}/api/list", host_port())) - .send() - .await? - .text() - .await?; - - let expected = expect![[r#"{"localnet":{}}"#]]; - expected.assert_eq(response.as_str()); - - // check server rejects bad version header - let json = client - .get(format!( - "http://{}/api?address={address}&module={module}&network=localnet", - host_port() - )) - .header(SUI_SOURCE_VALIDATION_VERSION_HEADER, "bogus") - .send() - .await - .expect("Request failed.") - .json::() - .await?; - - let expected = - expect!["Unsupported version 'bogus' specified in header x-sui-source-validation-version"]; - expected.assert_eq(&json.error); - - Ok(()) -} - -#[tokio::test] -async fn test_metrics_route() -> anyhow::Result<()> { - // Start metrics server - let metrics_listener = std::net::TcpListener::bind(METRICS_HOST_PORT)?; - let registry_service = start_prometheus_server(metrics_listener); - let prometheus_registry = registry_service.default_registry(); - SourceServiceMetrics::new(&prometheus_registry); - - let client = Client::new(); - let response = client - .get(format!("http://{METRICS_HOST_PORT}/metrics")) - .send() - .await - .expect("Request failed.") - .text() - .await?; - - let expected = expect![[r#" - # HELP total_requests Total number of requests received by Source Service - # TYPE total_requests counter - total_requests 0 - "#]]; - expected.assert_eq(response.as_str()); - Ok(()) -} - -#[test] -fn test_parse_package_config() -> anyhow::Result<()> { - let config = r#" -[[packages]] -source = "Repository" -[packages.values] -repository = "https://github.com/mystenlabs/sui" -network = "mainnet" -[[packages.values.branches]] -branch = "framework/mainnet" -paths = [ - { path = "crates/sui-framework/packages/deepbook", watch = "0xdee9" }, - { path = "crates/sui-framework/packages/move-stdlib", watch = "0x1" }, - { path = "crates/sui-framework/packages/sui-framework", watch = "0x2" }, - { path = "crates/sui-framework/packages/sui-system", watch = "0x3" } -] - - [[packages]] - source = "Directory" - [packages.values] - paths = [ - { path = "home/user/some/upgradeable-package", watch = "0x1234" }, - { path = "home/user/some/immutable-package" }, - ] -"#; - - let config: Config = toml::from_str(config).unwrap(); - let expect = expect![[r#" - Config { - packages: [ - Repository( - RepositorySource { - repository: "https://github.com/mystenlabs/sui", - network: Some( - Mainnet, - ), - branches: [ - Branch { - branch: "framework/mainnet", - paths: [ - Package { - path: "crates/sui-framework/packages/deepbook", - watch: Some( - 0x000000000000000000000000000000000000000000000000000000000000dee9, - ), - }, - Package { - path: "crates/sui-framework/packages/move-stdlib", - watch: Some( - 0x0000000000000000000000000000000000000000000000000000000000000001, - ), - }, - Package { - path: "crates/sui-framework/packages/sui-framework", - watch: Some( - 0x0000000000000000000000000000000000000000000000000000000000000002, - ), - }, - Package { - path: "crates/sui-framework/packages/sui-system", - watch: Some( - 0x0000000000000000000000000000000000000000000000000000000000000003, - ), - }, - ], - }, - ], - }, - ), - Directory( - DirectorySource { - paths: [ - Package { - path: "home/user/some/upgradeable-package", - watch: Some( - 0x0000000000000000000000000000000000000000000000000000000000001234, - ), - }, - Package { - path: "home/user/some/immutable-package", - watch: None, - }, - ], - network: None, - }, - ), - ], - }"#]]; - expect.assert_eq(&format!("{:#?}", config)); - Ok(()) -} - -#[test] -fn test_clone_command() -> anyhow::Result<()> { - let source = RepositorySource { - repository: "https://github.com/user/repo".into(), - branches: vec![Branch { - branch: "main".into(), - paths: vec![ - Package { - path: "a".into(), - watch: None, - }, - Package { - path: "b".into(), - watch: None, - }, - ], - }], - network: Some(Network::Localnet), - }; - - let command = CloneCommand::new( - &source, - &source.branches[0], - PathBuf::from("/foo").as_path(), - )?; - let expect = expect![ - r#"CloneCommand { - args: [ - [ - "clone", - "--no-checkout", - "--depth=1", - "--filter=tree:0", - "--branch=main", - "https://github.com/user/repo", - "/foo/localnet/repo__main", - ], - [ - "-C", - "/foo/localnet/repo__main", - "sparse-checkout", - "set", - "--no-cone", - "a", - "b", - ], - [ - "-C", - "/foo/localnet/repo__main", - "checkout", - ], - ], - repo_url: "https://github.com/user/repo", -}"# - ]; - expect.assert_eq(&format!("{:#?}", command)); - Ok(()) -} diff --git a/crates/sui-source-validation/Cargo.toml b/crates/sui-source-validation/Cargo.toml deleted file mode 100644 index a1b1918889e..00000000000 --- a/crates/sui-source-validation/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -[package] -name = "sui-source-validation" -version.workspace = true -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[lib] -path = "src/lib.rs" - -[dependencies] -anyhow.workspace = true -colored.workspace = true -thiserror.workspace = true -tracing.workspace = true -futures.workspace = true - -sui-json-rpc-types.workspace = true -sui-types.workspace = true -sui-sdk.workspace = true -sui-move-build.workspace = true - -move-binary-format.workspace = true -move-bytecode-source-map.workspace = true -move-command-line-common.workspace = true -move-compiler.workspace = true -move-core-types.workspace = true -move-package.workspace = true -move-symbol-pool.workspace = true - -tar.workspace = true -tempfile.workspace = true -flate2.workspace = true -ureq.workspace = true - - -[dev-dependencies] - -expect-test.workspace = true -rand.workspace = true -tempfile.workspace = true -tokio = { workspace = true, features = ["macros", "test-util"] } -tracing.workspace = true - -sui-test-transaction-builder.workspace = true -test-cluster.workspace = true diff --git a/crates/sui-source-validation/fixture/a/sources/a.move b/crates/sui-source-validation/fixture/a/sources/a.move deleted file mode 100644 index 20b1701b6ed..00000000000 --- a/crates/sui-source-validation/fixture/a/sources/a.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module a::a { - use b::b::b; - use b::c::c; - - public fun a(): u64 { - let var = 123; - let _ = var + 4; - b() + c() - } -} diff --git a/crates/sui-source-validation/fixture/b-v2/sources/b.move b/crates/sui-source-validation/fixture/b-v2/sources/b.move deleted file mode 100644 index 1ffd27a1b91..00000000000 --- a/crates/sui-source-validation/fixture/b-v2/sources/b.move +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::b { - public fun b(): u64 { - 42 - } - - public fun c(): u64 { - b() + 1 - } -} diff --git a/crates/sui-source-validation/fixture/b-v2/sources/c.move b/crates/sui-source-validation/fixture/b-v2/sources/c.move deleted file mode 100644 index fab61c011c9..00000000000 --- a/crates/sui-source-validation/fixture/b-v2/sources/c.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::c { - public fun c(): u64 { - 43 - } -} diff --git a/crates/sui-source-validation/fixture/b-v2/sources/d.move b/crates/sui-source-validation/fixture/b-v2/sources/d.move deleted file mode 100644 index afda18d7d3f..00000000000 --- a/crates/sui-source-validation/fixture/b-v2/sources/d.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::d { - public fun d(): u64 { - 44 - } -} diff --git a/crates/sui-source-validation/fixture/b/sources/b.move b/crates/sui-source-validation/fixture/b/sources/b.move deleted file mode 100644 index 5e504e52cce..00000000000 --- a/crates/sui-source-validation/fixture/b/sources/b.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::b { - public fun b(): u64 { - 42 - } -} diff --git a/crates/sui-source-validation/fixture/b/sources/c.move b/crates/sui-source-validation/fixture/b/sources/c.move deleted file mode 100644 index fab61c011c9..00000000000 --- a/crates/sui-source-validation/fixture/b/sources/c.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::c { - public fun c(): u64 { - 43 - } -} diff --git a/crates/sui-source-validation/fixture/b/sources/d.move b/crates/sui-source-validation/fixture/b/sources/d.move deleted file mode 100644 index afda18d7d3f..00000000000 --- a/crates/sui-source-validation/fixture/b/sources/d.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::d { - public fun d(): u64 { - 44 - } -} diff --git a/crates/sui-source-validation/fixture/c/sources/b.move b/crates/sui-source-validation/fixture/c/sources/b.move deleted file mode 100644 index 9af2b2dd2a2..00000000000 --- a/crates/sui-source-validation/fixture/c/sources/b.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module c::b { - public fun b(): u64 { - 42 - } -} diff --git a/crates/sui-source-validation/fixture/c/sources/c.move b/crates/sui-source-validation/fixture/c/sources/c.move deleted file mode 100644 index 03f9c506f19..00000000000 --- a/crates/sui-source-validation/fixture/c/sources/c.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module c::c { - public fun c(): u64 { - 43 - } -} diff --git a/crates/sui-source-validation/fixture/c/sources/d.move b/crates/sui-source-validation/fixture/c/sources/d.move deleted file mode 100644 index 830f9c0d6a0..00000000000 --- a/crates/sui-source-validation/fixture/c/sources/d.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module c::d { - public fun d(): u64 { - 44 - } -} diff --git a/crates/sui-source-validation/fixture/d/sources/a.move b/crates/sui-source-validation/fixture/d/sources/a.move deleted file mode 100644 index 0b15099d2d9..00000000000 --- a/crates/sui-source-validation/fixture/d/sources/a.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module d::d { - use b::b::b; - use c::c::c; - - public fun d(): u64 { - let var = 123; - let _ = var + 4; - b() + c() - } -} diff --git a/crates/sui-source-validation/fixture/versioned-a-depends-on-b/sources/a.move b/crates/sui-source-validation/fixture/versioned-a-depends-on-b/sources/a.move deleted file mode 100644 index 11a8793f137..00000000000 --- a/crates/sui-source-validation/fixture/versioned-a-depends-on-b/sources/a.move +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module a::a { - use b::b::b; - use b::b::c; - - public fun a() : u64 { - b() + c() - } -} diff --git a/crates/sui-source-validation/fixture/versioned-b/Move.lock b/crates/sui-source-validation/fixture/versioned-b/Move.lock deleted file mode 100644 index 1a4025d6561..00000000000 --- a/crates/sui-source-validation/fixture/versioned-b/Move.lock +++ /dev/null @@ -1,11 +0,0 @@ -# @generated by Move, please check-in and do not edit manually. - -[move] -version = 0 -manifest_digest = "C70E0438875A0C3B10FA5995F317F701134E629D1B2E5F3DCA3621E50034F809" -deps_digest = "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855" - -[move.toolchain-version] -compiler-version = "$COMPILER_VERSION" -edition = "legacy" -flavor = "sui" diff --git a/crates/sui-source-validation/fixture/versioned-b/sources/b.move b/crates/sui-source-validation/fixture/versioned-b/sources/b.move deleted file mode 100644 index 1ffd27a1b91..00000000000 --- a/crates/sui-source-validation/fixture/versioned-b/sources/b.move +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::b { - public fun b(): u64 { - 42 - } - - public fun c(): u64 { - b() + 1 - } -} diff --git a/crates/sui-source-validation/fixture/versioned-b/sources/c.move b/crates/sui-source-validation/fixture/versioned-b/sources/c.move deleted file mode 100644 index fab61c011c9..00000000000 --- a/crates/sui-source-validation/fixture/versioned-b/sources/c.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::c { - public fun c(): u64 { - 43 - } -} diff --git a/crates/sui-source-validation/fixture/versioned-b/sources/d.move b/crates/sui-source-validation/fixture/versioned-b/sources/d.move deleted file mode 100644 index afda18d7d3f..00000000000 --- a/crates/sui-source-validation/fixture/versioned-b/sources/d.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module b::d { - public fun d(): u64 { - 44 - } -} diff --git a/crates/sui-source-validation/fixture/z/Move.toml b/crates/sui-source-validation/fixture/z/Move.toml deleted file mode 100644 index 4de4afb7a0b..00000000000 --- a/crates/sui-source-validation/fixture/z/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "z" -version = "0.0.1" -published-at = "$STORAGE_ID" - -[dependencies] -Sui = { local = "$REPO_ROOT/crates/sui-framework/packages/sui-framework" } - -[addresses] -z = "$RUNTIME_ID" diff --git a/crates/sui-source-validation/fixture/z/sources/a.move b/crates/sui-source-validation/fixture/z/sources/a.move deleted file mode 100644 index 53da12ac17e..00000000000 --- a/crates/sui-source-validation/fixture/z/sources/a.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module z::a { - public fun bar(x: u64): u64 { - z::b::foo(sui::math::max(x, 42)) - } -} diff --git a/crates/sui-source-validation/fixture/z/sources/b.move b/crates/sui-source-validation/fixture/z/sources/b.move deleted file mode 100644 index 1e2776361a4..00000000000 --- a/crates/sui-source-validation/fixture/z/sources/b.move +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module z::b { - public fun foo(x: u64): u64 { - x - } -} diff --git a/crates/sui-source-validation/src/lib.rs b/crates/sui-source-validation/src/lib.rs deleted file mode 100644 index 769b1253abb..00000000000 --- a/crates/sui-source-validation/src/lib.rs +++ /dev/null @@ -1,834 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use core::fmt; -use std::{ - collections::HashMap, - ffi::OsStr, - fmt::Debug, - fs::File, - io::{self, Seek}, - path::{Path, PathBuf}, - process::Command, -}; - -use anyhow::{anyhow, bail, ensure}; -use colored::Colorize; -use futures::future; -use move_binary_format::{access::ModuleAccess, CompiledModule}; -use move_bytecode_source_map::utils::source_map_from_file; -use move_command_line_common::{ - env::MOVE_HOME, - files::{ - extension_equals, find_filenames, MOVE_COMPILED_EXTENSION, MOVE_EXTENSION, - SOURCE_MAP_EXTENSION, - }, -}; -use move_compiler::{ - compiled_unit::NamedCompiledModule, - editions::{Edition, Flavor}, - shared::NumericalAddress, -}; -use move_core_types::account_address::AccountAddress; -use move_package::{ - compilation::{ - compiled_package::{CompiledPackage as MoveCompiledPackage, CompiledUnitWithSource}, - package_layout::CompiledPackageLayout, - }, - lock_file::schema::{Header, ToolchainVersion}, - source_package::{ - layout::SourcePackageLayout, - parsed_manifest::{FileName, PackageName}, - }, -}; -use move_symbol_pool::Symbol; -use sui_move_build::CompiledPackage; -use sui_sdk::{ - apis::ReadApi, - error::Error, - rpc_types::{SuiObjectDataOptions, SuiRawData, SuiRawMoveObject, SuiRawMovePackage}, -}; -use sui_types::{base_types::ObjectID, error::SuiObjectResponseError}; -use tar::Archive; -use tempfile::TempDir; -use thiserror::Error; -use tracing::{debug, info}; - -#[cfg(test)] -mod tests; - -const CURRENT_COMPILER_VERSION: &str = env!("CARGO_PKG_VERSION"); -const LEGACY_COMPILER_VERSION: &str = CURRENT_COMPILER_VERSION; // TODO: update this when Move 2024 is released -const PRE_TOOLCHAIN_MOVE_LOCK_VERSION: u64 = 0; // Used to detect lockfiles pre-toolchain versioning support -const CANONICAL_UNIX_BINARY_NAME: &str = "sui"; -const CANONICAL_WIN_BINARY_NAME: &str = "sui.exe"; - -#[derive(Debug, Error)] -pub enum SourceVerificationError { - #[error("Could not read a dependency's on-chain object: {0:?}")] - DependencyObjectReadFailure(Error), - - #[error("Dependency object does not exist or was deleted: {0:?}")] - SuiObjectRefFailure(SuiObjectResponseError), - - #[error("Dependency ID contains a Sui object, not a Move package: {0}")] - ObjectFoundWhenPackageExpected(ObjectID, SuiRawMoveObject), - - #[error("On-chain version of dependency {package}::{module} was not found.")] - OnChainDependencyNotFound { package: Symbol, module: Symbol }, - - #[error("Could not deserialize on-chain dependency {address}::{module}.")] - OnChainDependencyDeserializationError { - address: AccountAddress, - module: Symbol, - }, - - #[error("Local version of dependency {address}::{module} was not found.")] - LocalDependencyNotFound { - address: AccountAddress, - module: Symbol, - }, - - #[error( - "Local dependency did not match its on-chain version at {address}::{package}::{module}" - )] - ModuleBytecodeMismatch { - address: AccountAddress, - package: Symbol, - module: Symbol, - }, - - #[error("Cannot check local module for {package}: {message}")] - CannotCheckLocalModules { package: Symbol, message: String }, - - #[error("On-chain address cannot be zero")] - ZeroOnChainAddresSpecifiedFailure, - - #[error("Invalid module {name} with error: {message}")] - InvalidModuleFailure { name: String, message: String }, -} - -#[derive(Debug, Error)] -pub struct AggregateSourceVerificationError(Vec); - -impl From for AggregateSourceVerificationError { - fn from(error: SourceVerificationError) -> Self { - AggregateSourceVerificationError(vec![error]) - } -} - -impl fmt::Display for AggregateSourceVerificationError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let AggregateSourceVerificationError(errors) = self; - match &errors[..] { - [] => unreachable!("Aggregate error with no errors"), - [error] => write!(f, "{}", error)?, - errors => { - writeln!(f, "Multiple source verification errors found:")?; - for error in errors { - write!(f, "\n- {}", error)?; - } - return Ok(()); - } - }; - Ok(()) - } -} - -/// How to handle package source during bytecode verification. -#[derive(PartialEq, Eq)] -pub enum SourceMode { - /// Don't verify source. - Skip, - - /// Verify source at the address specified in its manifest. - Verify, - - /// Verify source at an overridden address (only works if the package is not - /// published) - VerifyAt(AccountAddress), -} - -pub struct BytecodeSourceVerifier<'a> { - rpc_client: &'a ReadApi, -} - -/// Map package addresses and module names to package names and bytecode. -type LocalModules = HashMap<(AccountAddress, Symbol), (Symbol, CompiledModule)>; -/// Map package addresses and modules names to bytecode (package names are gone -/// in the on-chain representation). -type OnChainModules = HashMap<(AccountAddress, Symbol), CompiledModule>; - -impl<'a> BytecodeSourceVerifier<'a> { - pub fn new(rpc_client: &'a ReadApi) -> Self { - BytecodeSourceVerifier { rpc_client } - } - - /// Helper wrapper to verify that all local Move package dependencies' and - /// root bytecode matches the bytecode at the address specified on the - /// Sui network we are publishing to. - pub async fn verify_package_root_and_deps( - &self, - compiled_package: &CompiledPackage, - root_on_chain_address: AccountAddress, - ) -> Result<(), AggregateSourceVerificationError> { - self.verify_package( - compiled_package, - // verify_deps - true, - SourceMode::VerifyAt(root_on_chain_address), - ) - .await - } - - /// Helper wrapper to verify that all local Move package root bytecode - /// matches the bytecode at the address specified on the Sui network we - /// are publishing to. - pub async fn verify_package_root( - &self, - compiled_package: &CompiledPackage, - root_on_chain_address: AccountAddress, - ) -> Result<(), AggregateSourceVerificationError> { - self.verify_package( - compiled_package, - // verify_deps - false, - SourceMode::VerifyAt(root_on_chain_address), - ) - .await - } - - /// Helper wrapper to verify that all local Move package dependencies' - /// matches the bytecode at the address specified on the Sui network we - /// are publishing to. - pub async fn verify_package_deps( - &self, - compiled_package: &CompiledPackage, - ) -> Result<(), AggregateSourceVerificationError> { - self.verify_package( - compiled_package, - // verify_deps - true, - SourceMode::Skip, - ) - .await - } - - /// Verify that all local Move package dependencies' and/or root bytecode - /// matches the bytecode at the address specified on the Sui network we - /// are publishing to. If `verify_deps` is true, the dependencies are - /// verified. If `root_on_chain_address` is specified, the root is - /// verified against a package at `root_on_chain_address`. - pub async fn verify_package( - &self, - compiled_package: &CompiledPackage, - verify_deps: bool, - source_mode: SourceMode, - ) -> Result<(), AggregateSourceVerificationError> { - let mut on_chain_pkgs = vec![]; - match &source_mode { - SourceMode::Skip => (), - // On-chain address for matching root package cannot be zero - SourceMode::VerifyAt(AccountAddress::ZERO) => { - return Err(SourceVerificationError::ZeroOnChainAddresSpecifiedFailure.into()); - } - SourceMode::VerifyAt(root_address) => on_chain_pkgs.push(*root_address), - SourceMode::Verify => { - on_chain_pkgs.extend(compiled_package.published_at.as_ref().map(|id| **id)) - } - }; - - if verify_deps { - on_chain_pkgs.extend( - compiled_package - .dependency_ids - .published - .values() - .map(|id| **id), - ); - } - - let local_modules = local_modules(&compiled_package.package, verify_deps, source_mode)?; - let mut on_chain_modules = self.on_chain_modules(on_chain_pkgs.into_iter()).await?; - - let mut errors = Vec::new(); - for ((address, module), (package, local_module)) in local_modules { - let Some(on_chain_module) = on_chain_modules.remove(&(address, module)) else { - errors.push(SourceVerificationError::OnChainDependencyNotFound { package, module }); - continue; - }; - - // compare local bytecode to on-chain bytecode to ensure integrity of our - // dependencies - if local_module != on_chain_module { - errors.push(SourceVerificationError::ModuleBytecodeMismatch { - address, - package, - module, - }); - } - } - - if let Some(((address, module), _)) = on_chain_modules.into_iter().next() { - errors.push(SourceVerificationError::LocalDependencyNotFound { address, module }); - } - - if !errors.is_empty() { - return Err(AggregateSourceVerificationError(errors)); - } - - Ok(()) - } - - async fn pkg_for_address( - &self, - addr: AccountAddress, - ) -> Result { - // Move packages are specified with an AccountAddress, but are - // fetched from a sui network via sui_getObject, which takes an object ID - let obj_id = ObjectID::from(addr); - - // fetch the Sui object at the address specified for the package in the local - // resolution table if future packages with a large set of dependency - // packages prove too slow to verify, batched object fetching should be - // added to the ReadApi & used here - let obj_read = self - .rpc_client - .get_object_with_options(obj_id, SuiObjectDataOptions::new().with_bcs()) - .await - .map_err(SourceVerificationError::DependencyObjectReadFailure)?; - - let obj = obj_read - .into_object() - .map_err(SourceVerificationError::SuiObjectRefFailure)? - .bcs - .ok_or_else(|| { - SourceVerificationError::DependencyObjectReadFailure(Error::DataError( - "Bcs field is not found".to_string(), - )) - })?; - - match obj { - SuiRawData::Package(pkg) => Ok(pkg), - SuiRawData::MoveObject(move_obj) => Err( - SourceVerificationError::ObjectFoundWhenPackageExpected(obj_id, move_obj), - ), - } - } - - async fn on_chain_modules( - &self, - addresses: impl Iterator + Clone, - ) -> Result { - let resp = future::join_all(addresses.clone().map(|addr| self.pkg_for_address(addr))).await; - let mut map = OnChainModules::new(); - let mut err = vec![]; - - for (storage_id, pkg) in addresses.zip(resp) { - let SuiRawMovePackage { module_map, .. } = pkg?; - for (name, bytes) in module_map { - let Ok(module) = CompiledModule::deserialize_with_defaults(&bytes) else { - err.push( - SourceVerificationError::OnChainDependencyDeserializationError { - address: storage_id, - module: name.into(), - }, - ); - continue; - }; - - let runtime_id = *module.self_id().address(); - map.insert((runtime_id, Symbol::from(name)), module); - } - } - - if !err.is_empty() { - return Err(AggregateSourceVerificationError(err)); - } - - Ok(map) - } -} - -fn substitute_root_address( - named_module: &NamedCompiledModule, - root: AccountAddress, -) -> Result { - let mut module = named_module.module.clone(); - let address_idx = module.self_handle().address; - - let Some(addr) = module.address_identifiers.get_mut(address_idx.0 as usize) else { - return Err(SourceVerificationError::InvalidModuleFailure { - name: named_module.name.to_string(), - message: "Self address field missing".into(), - }); - }; - - if *addr != AccountAddress::ZERO { - return Err(SourceVerificationError::InvalidModuleFailure { - name: named_module.name.to_string(), - message: "Self address already populated".to_string(), - }); - } - - *addr = root; - Ok(module) -} - -fn local_modules( - compiled_package: &MoveCompiledPackage, - include_deps: bool, - source_mode: SourceMode, -) -> Result { - let mut map = LocalModules::new(); - - if include_deps { - // Compile dependencies with prior compilers if needed. - let deps_compiled_units = units_for_toolchain(&compiled_package.deps_compiled_units) - .map_err(|e| SourceVerificationError::CannotCheckLocalModules { - package: compiled_package.compiled_package_info.package_name, - message: e.to_string(), - })?; - - for (package, local_unit) in deps_compiled_units { - let m = &local_unit.unit; - let module = m.name; - let address = m.address.into_inner(); - if address == AccountAddress::ZERO { - continue; - } - - map.insert((address, module), (package, m.module.clone())); - } - } - - let root_package = compiled_package.compiled_package_info.package_name; - match source_mode { - SourceMode::Skip => { /* nop */ } - - // Include the root compiled units, at their current addresses. - SourceMode::Verify => { - // Compile root modules with prior compiler if needed. - let root_compiled_units = { - let root_compiled_units = compiled_package - .root_compiled_units - .iter() - .map(|u| ("root".into(), u.clone())) - .collect::>(); - - units_for_toolchain(&root_compiled_units).map_err(|e| { - SourceVerificationError::CannotCheckLocalModules { - package: compiled_package.compiled_package_info.package_name, - message: e.to_string(), - } - })? - }; - - for (_, local_unit) in root_compiled_units { - let m = &local_unit.unit; - - let module = m.name; - let address = m.address.into_inner(); - if address == AccountAddress::ZERO { - return Err(SourceVerificationError::InvalidModuleFailure { - name: module.to_string(), - message: "Can't verify unpublished source".to_string(), - }); - } - - map.insert((address, module), (root_package, m.module.clone())); - } - } - - // Include the root compiled units, and any unpublished dependencies with their - // addresses substituted - SourceMode::VerifyAt(root_address) => { - // Compile root modules with prior compiler if needed. - let root_compiled_units = { - let root_compiled_units = compiled_package - .root_compiled_units - .iter() - .map(|u| ("root".into(), u.clone())) - .collect::>(); - - units_for_toolchain(&root_compiled_units).map_err(|e| { - SourceVerificationError::CannotCheckLocalModules { - package: compiled_package.compiled_package_info.package_name, - message: e.to_string(), - } - })? - }; - - for (_, local_unit) in root_compiled_units { - let m = &local_unit.unit; - - let module = m.name; - map.insert( - (root_address, module), - (root_package, substitute_root_address(m, root_address)?), - ); - } - - for (package, local_unit) in &compiled_package.deps_compiled_units { - let m = &local_unit.unit; - let module = m.name; - let address = m.address.into_inner(); - if address != AccountAddress::ZERO { - continue; - } - - map.insert( - (root_address, module), - (*package, substitute_root_address(m, root_address)?), - ); - } - } - } - - Ok(map) -} - -fn current_toolchain() -> ToolchainVersion { - ToolchainVersion { - compiler_version: CURRENT_COMPILER_VERSION.into(), - edition: Edition::LEGACY, // does not matter, unused for current_toolchain - flavor: Flavor::Sui, // does not matter, unused for current_toolchain - } -} - -fn legacy_toolchain() -> ToolchainVersion { - ToolchainVersion { - compiler_version: LEGACY_COMPILER_VERSION.into(), - edition: Edition::LEGACY, - flavor: Flavor::Sui, - } -} - -/// Ensures `compiled_units` are compiled with the right compiler version, based -/// on Move.lock contents. This works by detecting if a compiled unit requires a -/// prior compiler version: -/// - If so, download the compiler, recompile the unit, and return that unit in -/// the result. -/// - If not, simply keep the current compiled unit. -fn units_for_toolchain( - compiled_units: &Vec<(PackageName, CompiledUnitWithSource)>, -) -> anyhow::Result> { - if std::env::var("SUI_RUN_TOOLCHAIN_BUILD").is_err() { - return Ok(compiled_units.clone()); - } - let mut package_version_map: HashMap)> = - HashMap::new(); - // First iterate over packages, mapping the required version for each package in - // `package_version_map`. - for (package, local_unit) in compiled_units { - if let Some((_, units)) = package_version_map.get_mut(package) { - // We've processed this package's required version. - units.push(local_unit.clone()); - continue; - } - - if sui_types::is_system_package(local_unit.unit.address.into_inner()) { - // System packages are always compiled with the current compiler. - package_version_map.insert(*package, (current_toolchain(), vec![local_unit.clone()])); - continue; - } - - let package_root = SourcePackageLayout::try_find_root(&local_unit.source_path)?; - let lock_file = package_root.join(SourcePackageLayout::Lock.path()); - if !lock_file.exists() { - // No lock file implies current compiler for this package. - package_version_map.insert(*package, (current_toolchain(), vec![local_unit.clone()])); - continue; - } - - let mut lock_file = File::open(lock_file)?; - let lock_version = Header::read(&mut lock_file)?.version; - if lock_version == PRE_TOOLCHAIN_MOVE_LOCK_VERSION { - // No need to attempt reading lock file toolchain - debug!("{package} on legacy compiler",); - package_version_map.insert(*package, (legacy_toolchain(), vec![local_unit.clone()])); - continue; - } - - // Read lock file toolchain info - lock_file.rewind()?; - let toolchain_version = ToolchainVersion::read(&mut lock_file)?; - match toolchain_version { - // No ToolchainVersion and new Move.lock version implies current compiler. - None => { - debug!("{package} on current compiler @ {CURRENT_COMPILER_VERSION}",); - package_version_map - .insert(*package, (current_toolchain(), vec![local_unit.clone()])); - } - // This dependency uses the current compiler. - Some(ToolchainVersion { - compiler_version, .. - }) if compiler_version == CURRENT_COMPILER_VERSION => { - debug!("{package} on current compiler @ {CURRENT_COMPILER_VERSION}",); - package_version_map - .insert(*package, (current_toolchain(), vec![local_unit.clone()])); - } - // This dependency needs a prior compiler. Mark it and compile. - Some(toolchain_version) => { - println!( - "{} {package} compiler @ {}", - "REQUIRE".bold().green(), - toolchain_version.compiler_version.yellow(), - ); - package_version_map.insert(*package, (toolchain_version, vec![local_unit.clone()])); - } - } - } - - let mut units = vec![]; - // Iterate over compiled units, and check if they need to be recompiled and - // replaced by a prior compiler's output. - for (package, (toolchain_version, local_units)) in package_version_map { - if toolchain_version.compiler_version == CURRENT_COMPILER_VERSION { - let local_units: Vec<_> = local_units.iter().map(|u| (package, u.clone())).collect(); - units.extend(local_units); - continue; - } - - if local_units.is_empty() { - bail!("Expected one or more modules, but none found"); - } - let package_root = SourcePackageLayout::try_find_root(&local_units[0].source_path)?; - let install_dir = tempfile::tempdir()?; // place compiled packages in this temp dir, don't pollute this packages build dir - download_and_compile( - package_root.clone(), - &install_dir, - &toolchain_version, - &package, - )?; - - let compiled_unit_paths = vec![package_root.clone()]; - let compiled_units = find_filenames(&compiled_unit_paths, |path| { - extension_equals(path, MOVE_COMPILED_EXTENSION) - })?; - let build_path = install_dir - .path() - .join(CompiledPackageLayout::path(&CompiledPackageLayout::Root)) - .join(package.as_str()); - debug!("build path is {}", build_path.display()); - - // Add all units compiled with the previous compiler. - for bytecode_path in compiled_units { - info!("bytecode path {bytecode_path}, {package}"); - let local_unit = decode_bytecode_file(build_path.clone(), &package, &bytecode_path)?; - units.push((package, local_unit)) - } - } - Ok(units) -} - -fn download_and_compile( - root: PathBuf, - install_dir: &TempDir, - ToolchainVersion { - compiler_version, - edition, - flavor, - }: &ToolchainVersion, - dep_name: &Symbol, -) -> anyhow::Result<()> { - let dest_dir = PathBuf::from_iter([&*MOVE_HOME, "binaries"]); // E.g., ~/.move/binaries - let dest_version = dest_dir.join(compiler_version); - let mut dest_canonical_path = dest_version.clone(); - dest_canonical_path.extend(["target", "release"]); - let mut dest_canonical_binary = dest_canonical_path.clone(); - - let platform = detect_platform(&root, compiler_version, &dest_canonical_path)?; - if platform == "windows-x86_64" { - dest_canonical_binary.push(CANONICAL_WIN_BINARY_NAME); - } else { - dest_canonical_binary.push(CANONICAL_UNIX_BINARY_NAME); - } - - if !dest_canonical_binary.exists() { - // Check the platform and proceed if we can download a binary. If not, the user - // should follow error instructions to sideload the binary. Download if - // binary does not exist. - let mainnet_url = format!( - "https://github.com/MystenLabs/sui/releases/download/mainnet-v{compiler_version}/sui-mainnet-v{compiler_version}-{platform}.tgz", - ); - - println!( - "{} mainnet compiler @ {} (this may take a while)", - "DOWNLOADING".bold().green(), - compiler_version.yellow() - ); - - let mut response = match ureq::get(&mainnet_url).call() { - Ok(response) => response, - Err(ureq::Error::Status(404, _)) => { - println!( - "{} sui mainnet compiler {} not available, attempting to download testnet compiler release...", - "WARNING".bold().yellow(), - compiler_version.yellow() - ); - println!( - "{} testnet compiler @ {} (this may take a while)", - "DOWNLOADING".bold().green(), - compiler_version.yellow() - ); - let testnet_url = format!("https://github.com/MystenLabs/sui/releases/download/testnet-v{compiler_version}/sui-testnet-v{compiler_version}-{platform}.tgz"); - ureq::get(&testnet_url).call()? - } - Err(e) => return Err(e.into()), - }.into_reader(); - - let dest_tarball = dest_version.join(format!("{}.tgz", compiler_version)); - debug!("tarball destination: {} ", dest_tarball.display()); - if let Some(parent) = dest_tarball.parent() { - std::fs::create_dir_all(parent) - .map_err(|e| anyhow!("failed to create directory for tarball: {e}"))?; - } - let mut dest_file = File::create(&dest_tarball)?; - io::copy(&mut response, &mut dest_file)?; - - // Extract the tarball using the tar crate - let tar_gz = File::open(&dest_tarball)?; - let tar = flate2::read::GzDecoder::new(tar_gz); - let mut archive = Archive::new(tar); - archive - .unpack(&dest_version) - .map_err(|e| anyhow!("failed to untar compiler binary: {e}"))?; - - let mut dest_binary = dest_version.clone(); - dest_binary.extend(["target", "release"]); - if platform == "windows-x86_64" { - dest_binary.push(&format!("sui-{platform}.exe")); - } else { - dest_binary.push(&format!("sui-{platform}")); - } - let dest_binary_os = OsStr::new(dest_binary.as_path()); - set_executable_permission(dest_binary_os)?; - std::fs::rename(dest_binary_os, dest_canonical_binary.clone())?; - } - - debug!( - "{} move build --default-move-edition {} --default-move-flavor {} -p {} --install-dir {}", - dest_canonical_binary.display(), - edition.to_string().as_str(), - flavor.to_string().as_str(), - root.display(), - install_dir.path().display(), - ); - info!( - "{} {} (compiler @ {})", - "BUILDING".bold().green(), - dep_name.as_str(), - compiler_version.yellow() - ); - Command::new(dest_canonical_binary) - .args([ - OsStr::new("move"), - OsStr::new("build"), - OsStr::new("--default-move-edition"), - OsStr::new(edition.to_string().as_str()), - OsStr::new("--default-move-flavor"), - OsStr::new(flavor.to_string().as_str()), - OsStr::new("-p"), - OsStr::new(root.as_path()), - OsStr::new("--install-dir"), - OsStr::new(install_dir.path()), - ]) - .output() - .map_err(|e| { - anyhow!("failed to build package from compiler binary {compiler_version}: {e}",) - })?; - Ok(()) -} - -fn detect_platform( - package_path: &Path, - compiler_version: &String, - dest_dir: &Path, -) -> anyhow::Result { - let s = match (std::env::consts::OS, std::env::consts::ARCH) { - ("macos", "aarch64") => "macos-arm64", - ("macos", "x86_64") => "macos-x86_64", - ("linux", "x86_64") => "ubuntu-x86_64", - ("windows", "x86_64") => "windows-x86_64", - (os, arch) => { - let mut binary_name = CANONICAL_UNIX_BINARY_NAME; - if os == "windows" { - binary_name = CANONICAL_WIN_BINARY_NAME; - }; - bail!( - "The package {} needs to be built with sui compiler version {compiler_version} but there \ - is no binary release available to download for your platform:\n\ - Operating System: {os}\n\ - Architecture: {arch}\n\ - You can manually put a {binary_name} binary for your platform in {} and rerun your command to continue.", - package_path.display(), - dest_dir.display(), - ) - } - }; - Ok(s.into()) -} - -#[cfg(unix)] -fn set_executable_permission(path: &OsStr) -> anyhow::Result<()> { - use std::{fs, os::unix::prelude::PermissionsExt}; - let mut perms = fs::metadata(path)?.permissions(); - perms.set_mode(0o755); - fs::set_permissions(path, perms)?; - Ok(()) -} - -#[cfg(not(unix))] -fn set_executable_permission(path: &OsStr) -> anyhow::Result<()> { - Command::new("icacls") - .args([path, OsStr::new("/grant"), OsStr::new("Everyone:(RX)")]) - .status()?; - Ok(()) -} - -fn decode_bytecode_file( - root_path: PathBuf, - package_name: &Symbol, - bytecode_path_str: &str, -) -> anyhow::Result { - let package_name_opt = Some(*package_name); - let bytecode_path = Path::new(bytecode_path_str); - let path_to_file = CompiledPackageLayout::path_to_file_after_category(bytecode_path); - let bytecode_bytes = std::fs::read(bytecode_path)?; - let source_map = source_map_from_file( - &root_path - .join(CompiledPackageLayout::SourceMaps.path()) - .join(&path_to_file) - .with_extension(SOURCE_MAP_EXTENSION), - )?; - let source_path = &root_path - .join(CompiledPackageLayout::Sources.path()) - .join(path_to_file) - .with_extension(MOVE_EXTENSION); - ensure!( - source_path.is_file(), - "Error decoding package: Unable to find corresponding source file for '{bytecode_path_str}' in package {package_name}" - ); - let module = CompiledModule::deserialize_with_defaults(&bytecode_bytes)?; - let (address_bytes, module_name) = { - let id = module.self_id(); - let parsed_addr = NumericalAddress::new( - id.address().into_bytes(), - move_compiler::shared::NumberFormat::Hex, - ); - let module_name = FileName::from(id.name().as_str()); - (parsed_addr, module_name) - }; - let unit = NamedCompiledModule { - package_name: package_name_opt, - address: address_bytes, - name: module_name, - module, - source_map, - }; - Ok(CompiledUnitWithSource { - unit, - source_path: source_path.clone(), - }) -} diff --git a/crates/sui-source-validation/src/tests.rs b/crates/sui-source-validation/src/tests.rs deleted file mode 100644 index 605708e7b75..00000000000 --- a/crates/sui-source-validation/src/tests.rs +++ /dev/null @@ -1,762 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::HashMap, - fs, io, - path::{Path, PathBuf}, - str, -}; - -use expect_test::expect; -use move_core_types::account_address::AccountAddress; -use sui_json_rpc_types::{ - get_new_package_obj_from_response, get_new_package_upgrade_cap_from_response, -}; -use sui_move_build::{BuildConfig, CompiledPackage, SuiPackageHooks}; -use sui_sdk::wallet_context::WalletContext; -use sui_test_transaction_builder::{make_publish_transaction, make_publish_transaction_with_deps}; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress, TransactionDigest}, - move_package::UpgradePolicy, - transaction::TEST_ONLY_GAS_UNIT_FOR_PUBLISH, - SUI_SYSTEM_STATE_OBJECT_ID, -}; -use test_cluster::TestClusterBuilder; - -use crate::{BytecodeSourceVerifier, SourceMode, CURRENT_COMPILER_VERSION}; - -#[tokio::test] -async fn successful_verification() -> anyhow::Result<()> { - let mut cluster = TestClusterBuilder::new().build().await; - let context = &mut cluster.wallet; - - let b_ref_fixtures = tempfile::tempdir()?; - let b_ref = { - let b_src = copy_published_package(&b_ref_fixtures, "b", SuiAddress::ZERO).await?; - publish_package(context, b_src).await.0 - }; - - let b_pkg_fixtures = tempfile::tempdir()?; - let b_pkg = { - let b_src = copy_published_package(&b_pkg_fixtures, "b", b_ref.0.into()).await?; - compile_package(b_src) - }; - - let a_fixtures = tempfile::tempdir()?; - let (a_pkg, a_ref) = { - copy_published_package(&a_fixtures, "b", b_ref.0.into()).await?; - let a_src = copy_published_package(&a_fixtures, "a", SuiAddress::ZERO).await?; - ( - compile_package(a_src.clone()), - publish_package(context, a_src).await.0, - ) - }; - - let client = context.get_client().await?; - let verifier = BytecodeSourceVerifier::new(client.read_api()); - - // Skip deps and root - verifier - .verify_package(&a_pkg, /* verify_deps */ false, SourceMode::Skip) - .await - .unwrap(); - - // Verify root without updating the address - verifier - .verify_package(&b_pkg, /* verify_deps */ false, SourceMode::Verify) - .await - .unwrap(); - - // Verify deps but skip root - verifier.verify_package_deps(&a_pkg).await.unwrap(); - - // Skip deps but verify root - verifier - .verify_package_root(&a_pkg, a_ref.0.into()) - .await - .unwrap(); - - // Verify both deps and root - verifier - .verify_package_root_and_deps(&a_pkg, a_ref.0.into()) - .await - .unwrap(); - - Ok(()) -} - -#[tokio::test] -async fn successful_verification_unpublished_deps() -> anyhow::Result<()> { - let mut cluster = TestClusterBuilder::new().build().await; - let context = &mut cluster.wallet; - let fixtures = tempfile::tempdir()?; - - let a_src = { - copy_published_package(&fixtures, "b", SuiAddress::ZERO).await?; - copy_published_package(&fixtures, "a", SuiAddress::ZERO).await? - }; - - let a_pkg = compile_package(a_src.clone()); - let a_ref = publish_package_and_deps(context, a_src).await; - - let client = context.get_client().await?; - let verifier = BytecodeSourceVerifier::new(client.read_api()); - - // Verify the root package which now includes dependency modules - verifier - .verify_package_root(&a_pkg, a_ref.0.into()) - .await - .unwrap(); - - Ok(()) -} - -#[tokio::test] -async fn successful_verification_module_ordering() -> anyhow::Result<()> { - let mut cluster = TestClusterBuilder::new().build().await; - let context = &mut cluster.wallet; - - // This package contains a module that refers to itself, and also to the sui - // framework. Its self-address is `0x0` (i.e. compares lower than the - // framework's `0x2`) before publishing, and will be greater after - // publishing. - // - // This is a regression test for a source validation bug related to module order - // instability where the on-chain package (which is compiled with - // self-address = 0x0, and later substituted) orders module handles - // (references to other modules) differently to the package compiled as a - // dependency with its self-address already set as its published address. - let z_ref_fixtures = tempfile::tempdir()?; - let z_ref = { - let z_src = copy_published_package(&z_ref_fixtures, "z", SuiAddress::ZERO).await?; - publish_package(context, z_src).await.0 - }; - - let z_pkg_fixtures = tempfile::tempdir()?; - let z_pkg = { - let z_src = copy_published_package(&z_pkg_fixtures, "z", z_ref.0.into()).await?; - compile_package(z_src) - }; - - let client = context.get_client().await?; - let verifier = BytecodeSourceVerifier::new(client.read_api()); - - let verify_deps = false; - verifier - .verify_package(&z_pkg, verify_deps, SourceMode::Verify) - .await - .unwrap(); - - Ok(()) -} - -#[tokio::test] -async fn successful_verification_upgrades() -> anyhow::Result<()> { - let mut cluster = TestClusterBuilder::new().build().await; - let context = &mut cluster.wallet; - - let b_v1_fixtures = tempfile::tempdir()?; - let (b_v1, b_cap) = { - let b_src = copy_published_package(&b_v1_fixtures, "b", SuiAddress::ZERO).await?; - publish_package(context, b_src).await - }; - - let b_v2_fixtures = tempfile::tempdir()?; - let b_v2 = { - let b_src = copy_published_package(&b_v2_fixtures, "b-v2", SuiAddress::ZERO).await?; - upgrade_package(context, b_v1.0, b_cap.0, b_src).await - }; - - let b_fixtures = tempfile::tempdir()?; - let (b_pkg, e_pkg) = { - let b_src = - copy_upgraded_package(&b_fixtures, "b-v2", b_v2.0.into(), b_v1.0.into()).await?; - let e_src = copy_published_package(&b_fixtures, "e", SuiAddress::ZERO).await?; - (compile_package(b_src), compile_package(e_src)) - }; - - let client = context.get_client().await?; - let verifier = BytecodeSourceVerifier::new(client.read_api()); - - // Verify the upgraded package b-v2 as the root. - let verify_deps = false; - verifier - .verify_package(&b_pkg, verify_deps, SourceMode::Verify) - .await - .unwrap(); - - // Verify the upgraded package b-v2 as a dep of e. - verifier.verify_package_deps(&e_pkg).await.unwrap(); - - Ok(()) -} - -#[tokio::test] -async fn fail_verification_bad_address() -> anyhow::Result<()> { - let mut cluster = TestClusterBuilder::new().build().await; - let context = &mut cluster.wallet; - - let b_ref_fixtures = tempfile::tempdir()?; - let b_ref = { - let b_src = copy_published_package(&b_ref_fixtures, "b", SuiAddress::ZERO).await?; - publish_package(context, b_src).await.0 - }; - - let a_pkg_fixtures = tempfile::tempdir()?; - let a_pkg = { - copy_published_package(&a_pkg_fixtures, "b", b_ref.0.into()).await?; - let a_src = copy_published_package(&a_pkg_fixtures, "a", SuiAddress::ZERO).await?; - publish_package(context, a_src.clone()).await; - compile_package(a_src) - }; - - let client = context.get_client().await?; - let verifier = BytecodeSourceVerifier::new(client.read_api()); - - let expected = expect!["On-chain address cannot be zero"]; - expected.assert_eq( - &verifier - .verify_package_root_and_deps(&a_pkg, AccountAddress::ZERO) - .await - .unwrap_err() - .to_string(), - ); - - Ok(()) -} - -#[tokio::test] -async fn fail_to_verify_unpublished_root() -> anyhow::Result<()> { - let mut cluster = TestClusterBuilder::new().build().await; - let context = &mut cluster.wallet; - - let b_pkg_fixtures = tempfile::tempdir()?; - let b_pkg = { - let b_src = copy_published_package(&b_pkg_fixtures, "b", SuiAddress::ZERO).await?; - compile_package(b_src) - }; - - let client = context.get_client().await?; - let verifier = BytecodeSourceVerifier::new(client.read_api()); - - // Trying to verify the root package, which hasn't been published -- this is - // going to fail because there is no on-chain package to verify against. - let expected = expect!["Invalid module b with error: Can't verify unpublished source"]; - expected.assert_eq( - &verifier - .verify_package(&b_pkg, /* verify_deps */ false, SourceMode::Verify) - .await - .unwrap_err() - .to_string(), - ); - - Ok(()) -} - -#[tokio::test] -async fn rpc_call_failed_during_verify() -> anyhow::Result<()> { - let mut cluster = TestClusterBuilder::new().build().await; - let context = &mut cluster.wallet; - - let b_ref_fixtures = tempfile::tempdir()?; - let b_ref = { - let b_src = copy_published_package(&b_ref_fixtures, "b", SuiAddress::ZERO).await?; - publish_package(context, b_src).await.0 - }; - - let a_ref_fixtures = tempfile::tempdir()?; - let a_ref = { - copy_published_package(&a_ref_fixtures, "b", b_ref.0.into()).await?; - let a_src = copy_published_package(&a_ref_fixtures, "a", SuiAddress::ZERO).await?; - publish_package(context, a_src).await.0 - }; - let _a_addr: SuiAddress = a_ref.0.into(); - - let client = context.get_client().await?; - let _verifier = BytecodeSourceVerifier::new(client.read_api()); - - // TODO: Dropping cluster no longer stops the network. Need to look into this - // and see what we want to do with it. - // Stop the network, so future RPC requests fail. - // drop(cluster); - // - // assert!(matches!( - // verifier.verify_package_deps(&a_pkg).await, - // Err(SourceVerificationError::DependencyObjectReadFailure(_)), - // ),); - // - // assert!(matches!( - // verifier - // .verify_package_root_and_deps(&a_pkg, a_addr.into()) - // .await, - // Err(SourceVerificationError::DependencyObjectReadFailure(_)), - // ),); - // - // assert!(matches!( - // verifier - // .verify_package_root(&a_pkg, a_addr.into()) - // .await, - // Err(SourceVerificationError::DependencyObjectReadFailure(_)), - // ),); - // - - Ok(()) -} - -#[tokio::test] -async fn package_not_found() -> anyhow::Result<()> { - let mut cluster = TestClusterBuilder::new().build().await; - let context = &mut cluster.wallet; - let mut stable_addrs = HashMap::new(); - - let a_pkg_fixtures = tempfile::tempdir()?; - let a_pkg = { - let b_id = SuiAddress::random_for_testing_only(); - stable_addrs.insert(b_id, ""); - copy_published_package(&a_pkg_fixtures, "b", b_id).await?; - let a_src = copy_published_package(&a_pkg_fixtures, "a", SuiAddress::ZERO).await?; - compile_package(a_src) - }; - - let client = context.get_client().await?; - let verifier = BytecodeSourceVerifier::new(client.read_api()); - - let Err(err) = verifier.verify_package_deps(&a_pkg).await else { - panic!("Expected verification to fail"); - }; - - let expected = - expect!["Dependency object does not exist or was deleted: NotExists { object_id: 0x }"]; - expected.assert_eq(&sanitize_id(err.to_string(), &stable_addrs)); - - let package_root = AccountAddress::random(); - stable_addrs.insert(SuiAddress::from(package_root), ""); - let Err(err) = verifier - .verify_package_root_and_deps(&a_pkg, package_root) - .await - else { - panic!("Expected verification to fail"); - }; - - // below may refer to either the package_root or dependent package `b` - // (the check reports the first missing object nondeterministically) - let expected = - expect!["Dependency object does not exist or was deleted: NotExists { object_id: 0x }"]; - expected.assert_eq(&sanitize_id(err.to_string(), &stable_addrs)); - - let package_root = AccountAddress::random(); - stable_addrs.insert(SuiAddress::from(package_root), ""); - let Err(err) = verifier.verify_package_root(&a_pkg, package_root).await else { - panic!("Expected verification to fail"); - }; - - let expected = - expect!["Dependency object does not exist or was deleted: NotExists { object_id: 0x }"]; - expected.assert_eq(&sanitize_id(err.to_string(), &stable_addrs)); - - Ok(()) -} - -#[tokio::test] -async fn dependency_is_an_object() -> anyhow::Result<()> { - let mut cluster = TestClusterBuilder::new().build().await; - let context = &mut cluster.wallet; - - let a_pkg_fixtures = tempfile::tempdir()?; - let a_pkg = { - let b_id = SUI_SYSTEM_STATE_OBJECT_ID.into(); - copy_published_package(&a_pkg_fixtures, "b", b_id).await?; - let a_src = copy_published_package(&a_pkg_fixtures, "a", SuiAddress::ZERO).await?; - compile_package(a_src) - }; - let client = context.get_client().await?; - let verifier = BytecodeSourceVerifier::new(client.read_api()); - - let expected = expect![ - "Dependency ID contains a Sui object, not a Move package: 0x0000000000000000000000000000000000000000000000000000000000000005" - ]; - expected.assert_eq( - &verifier - .verify_package_deps(&a_pkg) - .await - .unwrap_err() - .to_string(), - ); - - Ok(()) -} - -#[tokio::test] -async fn module_not_found_on_chain() -> anyhow::Result<()> { - let mut cluster = TestClusterBuilder::new().build().await; - let context = &mut cluster.wallet; - - let b_ref_fixtures = tempfile::tempdir()?; - let b_ref = { - let b_src = copy_published_package(&b_ref_fixtures, "b", SuiAddress::ZERO).await?; - tokio::fs::remove_file(b_src.join("sources").join("c.move")).await?; - publish_package(context, b_src).await.0 - }; - - let a_pkg_fixtures = tempfile::tempdir()?; - let a_pkg = { - copy_published_package(&a_pkg_fixtures, "b", b_ref.0.into()).await?; - let a_src = copy_published_package(&a_pkg_fixtures, "a", SuiAddress::ZERO).await?; - compile_package(a_src) - }; - let client = context.get_client().await?; - let verifier = BytecodeSourceVerifier::new(client.read_api()); - - let Err(err) = verifier.verify_package_deps(&a_pkg).await else { - panic!("Expected verification to fail"); - }; - - let expected = expect!["On-chain version of dependency b::c was not found."]; - expected.assert_eq(&err.to_string()); - - Ok(()) -} - -#[tokio::test] -async fn module_not_found_locally() -> anyhow::Result<()> { - let mut cluster = TestClusterBuilder::new().build().await; - let context = &mut cluster.wallet; - let mut stable_addrs = HashMap::new(); - - let b_ref_fixtures = tempfile::tempdir()?; - let b_ref = { - let b_src = copy_published_package(&b_ref_fixtures, "b", SuiAddress::ZERO).await?; - publish_package(context, b_src).await.0 - }; - - let a_pkg_fixtures = tempfile::tempdir()?; - let a_pkg = { - let b_id = b_ref.0.into(); - stable_addrs.insert(b_id, "b_id"); - let b_src = copy_published_package(&a_pkg_fixtures, "b", b_id).await?; - let a_src = copy_published_package(&a_pkg_fixtures, "a", SuiAddress::ZERO).await?; - tokio::fs::remove_file(b_src.join("sources").join("d.move")).await?; - compile_package(a_src) - }; - - let client = context.get_client().await?; - let verifier = BytecodeSourceVerifier::new(client.read_api()); - - let Err(err) = verifier.verify_package_deps(&a_pkg).await else { - panic!("Expected verification to fail"); - }; - - let expected = expect!["Local version of dependency b_id::d was not found."]; - expected.assert_eq(&sanitize_id(err.to_string(), &stable_addrs)); - - Ok(()) -} - -#[tokio::test] -async fn module_bytecode_mismatch() -> anyhow::Result<()> { - let mut cluster = TestClusterBuilder::new().build().await; - let context = &mut cluster.wallet; - let mut stable_addrs = HashMap::new(); - - let b_ref_fixtures = tempfile::tempdir()?; - let b_ref = { - let b_src = copy_published_package(&b_ref_fixtures, "b", SuiAddress::ZERO).await?; - - // Modify a module before publishing - let c_path = b_src.join("sources").join("c.move"); - let c_file = tokio::fs::read_to_string(&c_path) - .await? - .replace("43", "44"); - tokio::fs::write(&c_path, c_file).await?; - - publish_package(context, b_src).await.0 - }; - - let a_fixtures = tempfile::tempdir()?; - let (a_pkg, a_ref) = { - let b_id = b_ref.0.into(); - stable_addrs.insert(b_id, ""); - copy_published_package(&a_fixtures, "b", b_id).await?; - let a_src = copy_published_package(&a_fixtures, "a", SuiAddress::ZERO).await?; - - let compiled = compile_package(a_src.clone()); - // Modify a module before publishing - let c_path = a_src.join("sources").join("a.move"); - let c_file = tokio::fs::read_to_string(&c_path) - .await? - .replace("123", "1234"); - tokio::fs::write(&c_path, c_file).await?; - - (compiled, publish_package(context, a_src).await.0) - }; - let a_addr: SuiAddress = a_ref.0.into(); - stable_addrs.insert(a_addr, ""); - - let client = context.get_client().await?; - let verifier = BytecodeSourceVerifier::new(client.read_api()); - - let Err(err) = verifier.verify_package_deps(&a_pkg).await else { - panic!("Expected verification to fail"); - }; - - let expected = expect!["Local dependency did not match its on-chain version at ::b::c"]; - expected.assert_eq(&sanitize_id(err.to_string(), &stable_addrs)); - - let Err(err) = verifier.verify_package_root(&a_pkg, a_addr.into()).await else { - panic!("Expected verification to fail"); - }; - - let expected = expect!["Local dependency did not match its on-chain version at ::a::a"]; - expected.assert_eq(&sanitize_id(err.to_string(), &stable_addrs)); - - Ok(()) -} - -#[tokio::test] -async fn multiple_failures() -> anyhow::Result<()> { - let mut cluster = TestClusterBuilder::new().build().await; - let context = &mut cluster.wallet; - let mut stable_addrs = HashMap::new(); - - // Publish package `b::b` on-chain without c.move. - let b_ref_fixtures = tempfile::tempdir()?; - let b_ref = { - let b_src = copy_published_package(&b_ref_fixtures, "b", SuiAddress::ZERO).await?; - tokio::fs::remove_file(b_src.join("sources").join("c.move")).await?; - publish_package(context, b_src).await.0 - }; - - // Publish package `c::c` on-chain, unmodified. - let c_ref_fixtures = tempfile::tempdir()?; - let c_ref = { - let c_src = copy_published_package(&c_ref_fixtures, "c", SuiAddress::ZERO).await?; - publish_package(context, c_src).await.0 - }; - - // Compile local package `d` that references: - // - `b::b` (c.move exists locally but not on chain => error) - // - `c::c` (d.move exists on-chain but we delete it locally before compiling => - // error) - let d_pkg_fixtures = tempfile::tempdir()?; - let d_pkg = { - let b_id = b_ref.0.into(); - let c_id = c_ref.0.into(); - stable_addrs.insert(b_id, ""); - stable_addrs.insert(c_id, ""); - copy_published_package(&d_pkg_fixtures, "b", b_id).await?; - let c_src = copy_published_package(&d_pkg_fixtures, "c", c_id).await?; - let d_src = copy_published_package(&d_pkg_fixtures, "d", SuiAddress::ZERO).await?; - tokio::fs::remove_file(c_src.join("sources").join("d.move")).await?; // delete local module in `c` - compile_package(d_src) - }; - - let client = context.get_client().await?; - let verifier = BytecodeSourceVerifier::new(client.read_api()); - - let Err(err) = verifier.verify_package_deps(&d_pkg).await else { - panic!("Expected verification to fail"); - }; - - let expected = expect![[r#" - Multiple source verification errors found: - - - On-chain version of dependency b::c was not found. - - Local version of dependency ::d was not found."#]]; - expected.assert_eq(&sanitize_id(err.to_string(), &stable_addrs)); - - Ok(()) -} - -#[tokio::test] -async fn successful_versioned_dependency_verification() -> anyhow::Result<()> { - let mut cluster = TestClusterBuilder::new().build().await; - let context = &mut cluster.wallet; - - let b_ref_fixtures = tempfile::tempdir()?; - let b_ref = { - let b_src = - copy_published_package(&b_ref_fixtures, "versioned-b", SuiAddress::ZERO).await?; - publish_package(context, b_src).await.0 - }; - - let a_fixtures = tempfile::tempdir()?; - let a_pkg = { - copy_published_package(&a_fixtures, "versioned-b", b_ref.0.into()).await?; - let a_src = - copy_published_package(&a_fixtures, "versioned-a-depends-on-b", SuiAddress::ZERO) - .await?; - compile_package(a_src.clone()) - }; - - let client = context.get_client().await?; - let verifier = BytecodeSourceVerifier::new(client.read_api()); - - // Verify versioned dependency - verifier.verify_package_deps(&a_pkg).await.unwrap(); - - Ok(()) -} - -/// Compile the package at absolute path `package`. -fn compile_package(package: impl AsRef) -> CompiledPackage { - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); - BuildConfig::new_for_testing() - .build(package.as_ref().to_path_buf()) - .unwrap() -} - -fn sanitize_id(mut message: String, m: &HashMap) -> String { - for (addr, label) in m { - message = message.replace(format!("{addr}").strip_prefix("0x").unwrap(), label); - } - message -} - -/// Compile and publish package at absolute path `package` to chain. -async fn publish_package(context: &WalletContext, package: PathBuf) -> (ObjectRef, ObjectRef) { - let txn = make_publish_transaction(context, package).await; - let response = context.execute_transaction_must_succeed(txn).await; - let package = get_new_package_obj_from_response(&response).unwrap(); - let cap = get_new_package_upgrade_cap_from_response(&response).unwrap(); - (package, cap) -} - -async fn upgrade_package( - context: &WalletContext, - package_id: ObjectID, - upgrade_cap: ObjectID, - package: impl AsRef, -) -> ObjectRef { - let package = compile_package(package); - let with_unpublished_deps = false; - let package_bytes = package.get_package_bytes(with_unpublished_deps); - let package_digest = package.get_package_digest(with_unpublished_deps).to_vec(); - let package_deps = package.dependency_ids.published.into_values().collect(); - - upgrade_package_with_wallet( - context, - package_id, - upgrade_cap, - package_bytes, - package_deps, - package_digest, - ) - .await - .0 -} - -/// Compile and publish package at absolute path `package` to chain, along with -/// its unpublished dependencies. -async fn publish_package_and_deps(context: &WalletContext, package: PathBuf) -> ObjectRef { - let txn = make_publish_transaction_with_deps(context, package).await; - let response = context.execute_transaction_must_succeed(txn).await; - get_new_package_obj_from_response(&response).unwrap() -} - -/// Copy `package` from fixtures into `directory`, setting its named address in -/// the copied package's `Move.toml` to `address`. (A fixture's self-address is -/// assumed to match its package name). -async fn copy_published_package<'s>( - directory: impl AsRef, - package: &str, - address: SuiAddress, -) -> io::Result { - copy_upgraded_package(directory, package, address, address).await -} - -async fn copy_upgraded_package<'s>( - directory: impl AsRef, - package: &str, - storage_id: SuiAddress, - runtime_id: SuiAddress, -) -> io::Result { - let cargo_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let repo_root = { - let mut path = cargo_root.clone(); - path.pop(); // sui-source-validation - path.pop(); // crates - path - }; - - let dst = directory.as_ref().join(package); - let src = { - let mut buf = cargo_root.clone(); - buf.push("fixture"); - buf.push(package); - buf - }; - - // Create destination directory - tokio::fs::create_dir(&dst).await?; - - // Copy TOML, performing replacements - let mut toml = tokio::fs::read_to_string(src.join("Move.toml")).await?; - toml = toml.replace("$REPO_ROOT", &repo_root.to_string_lossy()); - toml = toml.replace("$STORAGE_ID", &storage_id.to_string()); - toml = toml.replace("$RUNTIME_ID", &runtime_id.to_string()); - tokio::fs::write(dst.join("Move.toml"), toml).await?; - - // Copy Move.lock file if it exists, performing replacements - let lock_file = src.join("Move.lock"); - if lock_file.exists() { - let mut toml = tokio::fs::read_to_string(lock_file).await?; - toml = toml.replace("$COMPILER_VERSION", CURRENT_COMPILER_VERSION); - tokio::fs::write(dst.join("Move.lock"), toml).await?; - } - - // Make destination source directory - tokio::fs::create_dir(dst.join("sources")).await?; - - // Copy source files - for entry in fs::read_dir(src.join("sources"))? { - let entry = entry?; - assert!(entry.file_type()?.is_file()); - - let src_abs = entry.path(); - let src_rel = src_abs.strip_prefix(&src).unwrap(); - let dst_abs = dst.join(src_rel); - tokio::fs::copy(src_abs, dst_abs).await?; - } - - Ok(dst) -} - -pub async fn upgrade_package_with_wallet( - context: &WalletContext, - package_id: ObjectID, - upgrade_cap: ObjectID, - all_module_bytes: Vec>, - dep_ids: Vec, - digest: Vec, -) -> (ObjectRef, TransactionDigest) { - let sender = context.get_addresses()[0]; - let client = context.get_client().await.unwrap(); - let gas_price = context.get_reference_gas_price().await.unwrap(); - let transaction = { - let data = client - .transaction_builder() - .upgrade( - sender, - package_id, - all_module_bytes, - dep_ids, - upgrade_cap, - UpgradePolicy::COMPATIBLE, - digest, - None, - TEST_ONLY_GAS_UNIT_FOR_PUBLISH * 2 * gas_price, - ) - .await - .unwrap(); - - context.sign_transaction(&data) - }; - - let resp = context.execute_transaction_must_succeed(transaction).await; - - ( - get_new_package_obj_from_response(&resp).unwrap(), - resp.digest, - ) -} diff --git a/crates/sui-storage/Cargo.toml b/crates/sui-storage/Cargo.toml deleted file mode 100644 index 77a34512daf..00000000000 --- a/crates/sui-storage/Cargo.toml +++ /dev/null @@ -1,67 +0,0 @@ -[package] -name = "sui-storage" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -integer-encoding.workspace = true -async-trait.workspace = true -futures.workspace = true -num_enum.workspace = true -serde.workspace = true -serde_json.workspace = true -tokio = { workspace = true, features = ["full", "tracing"] } -rocksdb.workspace = true -tracing.workspace = true -byteorder.workspace = true -anyhow.workspace = true -tempfile.workspace = true -tap.workspace = true -reqwest.workspace = true -percent-encoding = "2.2.0" -chrono.workspace = true -object_store.workspace = true -backoff.workspace = true -bytes.workspace = true -parking_lot.workspace = true -bcs.workspace = true -prometheus.workspace = true -itertools.workspace = true -zstd.workspace = true -url.workspace = true -fastcrypto.workspace = true -clap = "4.3.2" -hyper.workspace = true -hyper-rustls.workspace = true -base64-url.workspace = true -telemetry-subscribers.workspace = true -indicatif.workspace = true - -sui-types.workspace = true -mysten-metrics.workspace = true -move-core-types.workspace = true -sui-json-rpc-types.workspace = true -sui-protocol-config.workspace = true -sui-config.workspace = true -typed-store.workspace = true -typed-store-derive.workspace = true -eyre.workspace = true -lru.workspace = true - -move-binary-format.workspace = true -move-bytecode-utils.workspace = true - -[dev-dependencies] -anyhow.workspace = true -criterion.workspace = true -tempfile.workspace = true -num_cpus.workspace = true -pretty_assertions.workspace = true -once_cell.workspace = true -sui-test-transaction-builder.workspace = true -sui-types = { workspace = true, features = ["test-utils"] } -sui-macros = { workspace = true } -sui-simulator = { workspace = true } diff --git a/crates/sui-storage/src/blob.rs b/crates/sui-storage/src/blob.rs deleted file mode 100644 index aeca6daea76..00000000000 --- a/crates/sui-storage/src/blob.rs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - io::{Read, Write}, - marker::PhantomData, -}; - -use anyhow::{anyhow, Result}; -use byteorder::ReadBytesExt; -use integer_encoding::{VarInt, VarIntReader}; -use num_enum::{IntoPrimitive, TryFromPrimitive}; -use serde::{de::DeserializeOwned, Serialize}; - -pub const MAX_VARINT_LENGTH: usize = 10; -pub const BLOB_ENCODING_BYTES: usize = 1; - -#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] -#[repr(u8)] -pub enum BlobEncoding { - Bcs = 1, -} - -pub struct Blob { - pub data: Vec, - pub encoding: BlobEncoding, -} - -impl Blob { - pub fn encode(value: &T, encoding: BlobEncoding) -> Result { - let value_buf = bcs::to_bytes(value)?; - let (data, encoding) = match encoding { - BlobEncoding::Bcs => (value_buf, encoding), - }; - Ok(Blob { data, encoding }) - } - pub fn decode(self) -> Result { - let data = match &self.encoding { - BlobEncoding::Bcs => self.data, - }; - let res = bcs::from_bytes(&data)?; - Ok(res) - } - pub fn read(rbuf: &mut R) -> Result { - let len = rbuf.read_varint::()? as usize; - if len == 0 { - return Err(anyhow!("Invalid object length of 0 in file")); - } - let encoding = rbuf.read_u8()?; - let mut data = vec![0u8; len]; - rbuf.read_exact(&mut data)?; - let blob = Blob { - data, - encoding: BlobEncoding::try_from(encoding)?, - }; - Ok(blob) - } - pub fn write(&self, wbuf: &mut W) -> Result { - let mut buf = [0u8; MAX_VARINT_LENGTH]; - let mut counter = 0; - let n = (self.data.len() as u64).encode_var(&mut buf); - wbuf.write_all(&buf[0..n])?; - counter += n; - buf[0] = self.encoding.into(); - wbuf.write_all(&buf[0..BLOB_ENCODING_BYTES])?; - counter += 1; - wbuf.write_all(&self.data)?; - counter += self.data.len(); - Ok(counter) - } - pub fn size(&self) -> usize { - let mut blob_size = self.data.len().required_space(); - blob_size += BLOB_ENCODING_BYTES; - blob_size += self.data.len(); - blob_size - } - pub fn to_bytes(&self) -> Vec { - [vec![self.encoding.into()], self.data.clone()].concat() - } - pub fn from_bytes(bytes: &[u8]) -> Result { - let (encoding, data) = bytes.split_first().ok_or(anyhow!("empty bytes"))?; - Blob { - data: data.to_vec(), - encoding: BlobEncoding::try_from(*encoding)?, - } - .decode() - } -} - -/// An iterator over blobs in a blob file. -pub struct BlobIter { - reader: Box, - _phantom: PhantomData, -} - -impl BlobIter { - pub fn new(reader: Box) -> Self { - Self { - reader, - _phantom: PhantomData, - } - } - fn next_blob(&mut self) -> Result { - let blob = Blob::read(&mut self.reader)?; - blob.decode() - } -} - -impl Iterator for BlobIter { - type Item = T; - fn next(&mut self) -> Option { - self.next_blob().ok() - } -} diff --git a/crates/sui-storage/src/lib.rs b/crates/sui-storage/src/lib.rs deleted file mode 100644 index 93f84781aa1..00000000000 --- a/crates/sui-storage/src/lib.rs +++ /dev/null @@ -1,394 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -#![allow(dead_code)] - -pub mod indexes; - -use std::{ - fs, - fs::File, - io, - io::{BufReader, Read, Write}, - ops::Range, - path::{Path, PathBuf}, - sync::{ - atomic::{AtomicU64, Ordering}, - Arc, - }, -}; - -use anyhow::{anyhow, Result}; -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; -use bytes::{Buf, Bytes}; -use fastcrypto::hash::{HashFunction, Sha3_256}; -use futures::StreamExt; -pub use indexes::{IndexStore, IndexStoreTables}; -use itertools::Itertools; -use num_enum::{IntoPrimitive, TryFromPrimitive}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use sui_types::{ - committee::Committee, - messages_checkpoint::{ - CertifiedCheckpointSummary, CheckpointSequenceNumber, VerifiedCheckpoint, - }, - storage::WriteStore, -}; -use tracing::debug; - -use crate::blob::BlobIter; - -pub mod blob; -pub mod http_key_value_store; -pub mod key_value_store; -pub mod key_value_store_metrics; -pub mod mutex_table; -pub mod object_store; -pub mod package_object_cache; -pub mod sharded_lru; -pub mod write_path_pending_tx_log; - -pub const SHA3_BYTES: usize = 32; - -#[derive( - Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, TryFromPrimitive, IntoPrimitive, -)] -#[repr(u8)] -pub enum StorageFormat { - Blob = 0, -} - -#[derive( - Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, TryFromPrimitive, IntoPrimitive, -)] -#[repr(u8)] -pub enum FileCompression { - None = 0, - Zstd, -} - -impl FileCompression { - pub fn zstd_compress(reader: &mut R, writer: &mut W) -> io::Result<()> { - // TODO: Add zstd compression level as function argument - let mut encoder = zstd::Encoder::new(writer, 1)?; - io::copy(reader, &mut encoder)?; - encoder.finish()?; - Ok(()) - } - pub fn compress(&self, source: &std::path::Path) -> io::Result<()> { - match self { - FileCompression::Zstd => { - let mut input = File::open(source)?; - let tmp_file_name = source.with_extension("tmp"); - let mut output = File::create(&tmp_file_name)?; - Self::zstd_compress(&mut input, &mut output)?; - fs::rename(tmp_file_name, source)?; - } - FileCompression::None => {} - } - Ok(()) - } - pub fn decompress(&self, source: &PathBuf) -> Result> { - let file = File::open(source)?; - let res: Box = match self { - FileCompression::Zstd => Box::new(zstd::stream::Decoder::new(file)?), - FileCompression::None => Box::new(BufReader::new(file)), - }; - Ok(res) - } - pub fn bytes_decompress(&self, bytes: Bytes) -> Result> { - let res: Box = match self { - FileCompression::Zstd => Box::new(zstd::stream::Decoder::new(bytes.reader())?), - FileCompression::None => Box::new(BufReader::new(bytes.reader())), - }; - Ok(res) - } -} - -pub fn compute_sha3_checksum_for_bytes(bytes: Bytes) -> Result<[u8; 32]> { - let mut hasher = Sha3_256::default(); - io::copy(&mut bytes.reader(), &mut hasher)?; - Ok(hasher.finalize().digest) -} - -pub fn compute_sha3_checksum_for_file(file: &mut File) -> Result<[u8; 32]> { - let mut hasher = Sha3_256::default(); - io::copy(file, &mut hasher)?; - Ok(hasher.finalize().digest) -} - -pub fn compute_sha3_checksum(source: &std::path::Path) -> Result<[u8; 32]> { - let mut file = fs::File::open(source)?; - compute_sha3_checksum_for_file(&mut file) -} - -pub fn compress(reader: &mut R, writer: &mut W) -> Result<()> { - let magic = reader.read_u32::()?; - writer.write_u32::(magic)?; - let storage_format = reader.read_u8()?; - writer.write_u8(storage_format)?; - let file_compression = FileCompression::try_from(reader.read_u8()?)?; - writer.write_u8(file_compression.into())?; - match file_compression { - FileCompression::Zstd => { - FileCompression::zstd_compress(reader, writer)?; - } - FileCompression::None => {} - } - Ok(()) -} - -pub fn read( - expected_magic: u32, - mut reader: R, -) -> Result<(Box, StorageFormat)> { - let magic = reader.read_u32::()?; - if magic != expected_magic { - Err(anyhow!( - "Unexpected magic string in file: {:?}, expected: {:?}", - magic, - expected_magic - )) - } else { - let storage_format = StorageFormat::try_from(reader.read_u8()?)?; - let file_compression = FileCompression::try_from(reader.read_u8()?)?; - let reader: Box = match file_compression { - FileCompression::Zstd => Box::new(zstd::stream::Decoder::new(reader)?), - FileCompression::None => Box::new(BufReader::new(reader)), - }; - Ok((reader, storage_format)) - } -} - -pub fn make_iterator( - expected_magic: u32, - reader: R, -) -> Result> { - let (reader, storage_format) = read(expected_magic, reader)?; - match storage_format { - StorageFormat::Blob => Ok(BlobIter::new(reader)), - } -} - -pub fn verify_checkpoint_with_committee( - committee: Arc, - current: &VerifiedCheckpoint, - checkpoint: CertifiedCheckpointSummary, -) -> Result { - assert_eq!( - *checkpoint.sequence_number(), - current.sequence_number().checked_add(1).unwrap() - ); - - if Some(*current.digest()) != checkpoint.previous_digest { - debug!( - current_checkpoint_seq = current.sequence_number(), - current_digest =% current.digest(), - checkpoint_seq = checkpoint.sequence_number(), - checkpoint_digest =% checkpoint.digest(), - checkpoint_previous_digest =? checkpoint.previous_digest, - "checkpoint not on same chain" - ); - return Err(checkpoint); - } - - let current_epoch = current.epoch(); - if checkpoint.epoch() != current_epoch - && checkpoint.epoch() != current_epoch.checked_add(1).unwrap() - { - debug!( - checkpoint_seq = checkpoint.sequence_number(), - checkpoint_epoch = checkpoint.epoch(), - current_checkpoint_seq = current.sequence_number(), - current_epoch = current_epoch, - "cannot verify checkpoint with too high of an epoch", - ); - return Err(checkpoint); - } - - if checkpoint.epoch() == current_epoch.checked_add(1).unwrap() - && current.next_epoch_committee().is_none() - { - debug!( - checkpoint_seq = checkpoint.sequence_number(), - checkpoint_epoch = checkpoint.epoch(), - current_checkpoint_seq = current.sequence_number(), - current_epoch = current_epoch, - "next checkpoint claims to be from the next epoch but the latest verified \ - checkpoint does not indicate that it is the last checkpoint of an epoch" - ); - return Err(checkpoint); - } - - checkpoint - .verify_authority_signatures(&committee) - .map_err(|e| { - debug!("error verifying checkpoint: {e}"); - checkpoint.clone() - })?; - Ok(VerifiedCheckpoint::new_unchecked(checkpoint)) -} - -pub fn verify_checkpoint( - current: &VerifiedCheckpoint, - store: S, - checkpoint: CertifiedCheckpointSummary, -) -> Result -where - S: WriteStore, -{ - let committee = store - .get_committee(checkpoint.epoch()) - .expect("store operation should not fail") - .unwrap_or_else(|| { - panic!( - "BUG: should have committee for epoch {} before we try to verify checkpoint {}", - checkpoint.epoch(), - checkpoint.sequence_number() - ) - }); - - verify_checkpoint_with_committee(committee, current, checkpoint) -} - -pub async fn verify_checkpoint_range( - checkpoint_range: Range, - store: S, - checkpoint_counter: Arc, - max_concurrency: usize, -) where - S: WriteStore + Clone, -{ - let range_clone = checkpoint_range.clone(); - futures::stream::iter(range_clone.into_iter().tuple_windows()) - .map(|(a, b)| { - let current = store - .get_checkpoint_by_sequence_number(a) - .expect("store operation should not fail") - .unwrap_or_else(|| { - panic!( - "Checkpoint {} should exist in store after summary sync but does not", - a - ); - }); - let next = store - .get_checkpoint_by_sequence_number(b) - .expect("store operation should not fail") - .unwrap_or_else(|| { - panic!( - "Checkpoint {} should exist in store after summary sync but does not", - a - ); - }); - let committee = store - .get_committee(next.epoch()) - .expect("store operation should not fail") - .unwrap_or_else(|| { - panic!( - "BUG: should have committee for epoch {} before we try to verify checkpoint {}", - next.epoch(), - next.sequence_number() - ) - }); - tokio::spawn(async move { - verify_checkpoint_with_committee(committee, ¤t, next.clone().into()) - .expect("Checkpoint verification failed"); - }) - }) - .buffer_unordered(max_concurrency) - .for_each(|result| { - result.expect("Checkpoint verification task failed"); - checkpoint_counter.fetch_add(1, Ordering::Relaxed); - futures::future::ready(()) - }) - .await; - let last = checkpoint_range - .last() - .expect("Received empty checkpoint range"); - let final_checkpoint = store - .get_checkpoint_by_sequence_number(last) - .expect("Failed to fetch checkpoint") - .expect("Expected end of checkpoint range to exist in store"); - store - .update_highest_verified_checkpoint(&final_checkpoint) - .expect("Failed to update highest verified checkpoint"); -} - -fn hard_link(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { - fs::create_dir_all(&dst)?; - for entry in fs::read_dir(src)? { - let entry = entry?; - let ty = entry.file_type()?; - if ty.is_dir() { - hard_link(entry.path(), dst.as_ref().join(entry.file_name()))?; - } else { - fs::hard_link(entry.path(), dst.as_ref().join(entry.file_name()))?; - } - } - Ok(()) -} - -#[cfg(test)] -mod tests { - use tempfile::TempDir; - use typed_store::{ - reopen, - rocks::{open_cf, DBMap, MetricConf, ReadWriteOptions}, - Map, - }; - - use crate::hard_link; - - #[tokio::test] - pub async fn test_db_hard_link() -> anyhow::Result<()> { - let input = TempDir::new()?; - let input_path = input.path(); - - let output = TempDir::new()?; - let output_path = output.path(); - - const FIRST_CF: &str = "First_CF"; - const SECOND_CF: &str = "Second_CF"; - - let db_a = open_cf( - input_path, - None, - MetricConf::new("test_db_hard_link_1"), - &[FIRST_CF, SECOND_CF], - ) - .unwrap(); - - let (db_map_1, db_map_2) = reopen!(&db_a, FIRST_CF;, SECOND_CF;); - - let keys_vals_cf1 = (1..100).map(|i| (i, i.to_string())); - let keys_vals_cf2 = (1..100).map(|i| (i, i.to_string())); - - assert!(db_map_1.multi_insert(keys_vals_cf1).is_ok()); - assert!(db_map_2.multi_insert(keys_vals_cf2).is_ok()); - - // set up db hard link - hard_link(input_path, output_path)?; - let db_b = open_cf( - output_path, - None, - MetricConf::new("test_db_hard_link_2"), - &[FIRST_CF, SECOND_CF], - ) - .unwrap(); - - let (db_map_1, db_map_2) = reopen!(&db_b, FIRST_CF;, SECOND_CF;); - for i in 1..100 { - assert!( - db_map_1 - .contains_key(&i) - .expect("Failed to call contains key") - ); - assert!( - db_map_2 - .contains_key(&i) - .expect("Failed to call contains key") - ); - } - - Ok(()) - } -} diff --git a/crates/sui-storage/src/object_store/http/mod.rs b/crates/sui-storage/src/object_store/http/mod.rs deleted file mode 100644 index 5418c1d7040..00000000000 --- a/crates/sui-storage/src/object_store/http/mod.rs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod gcs; -mod local; -mod s3; - -use std::sync::Arc; - -use anyhow::{anyhow, Context, Result}; -use chrono::{DateTime, Utc}; -use futures::{StreamExt, TryStreamExt}; -use object_store::{path::Path, Error, GetResult, GetResultPayload, ObjectMeta}; -use reqwest::{ - header::{HeaderMap, CONTENT_LENGTH, ETAG, LAST_MODIFIED}, - Client, Method, -}; -use sui_config::object_storage_config::{ObjectStoreConfig, ObjectStoreType}; - -use crate::object_store::{ - http::{gcs::GoogleCloudStorage, local::LocalStorage, s3::AmazonS3}, - ObjectStoreGetExt, -}; - -// http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html -// -// Do not URI-encode any of the unreserved characters that RFC 3986 defines: -// A-Z, a-z, 0-9, hyphen ( - ), underscore ( _ ), period ( . ), and tilde ( ~ ). -pub(crate) const STRICT_ENCODE_SET: percent_encoding::AsciiSet = percent_encoding::NON_ALPHANUMERIC - .remove(b'-') - .remove(b'.') - .remove(b'_') - .remove(b'~'); -const STRICT_PATH_ENCODE_SET: percent_encoding::AsciiSet = STRICT_ENCODE_SET.remove(b'/'); -static DEFAULT_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),); - -pub trait HttpDownloaderBuilder { - fn make_http(&self) -> Result>; -} - -impl HttpDownloaderBuilder for ObjectStoreConfig { - fn make_http(&self) -> Result> { - match self.object_store { - Some(ObjectStoreType::File) => { - Ok(LocalStorage::new(self.directory.as_ref().unwrap()).map(Arc::new)?) - } - Some(ObjectStoreType::S3) => { - let bucket_endpoint = if let Some(endpoint) = &self.aws_endpoint { - if self.aws_virtual_hosted_style_request { - endpoint.clone() - } else { - let bucket = self.bucket.as_ref().unwrap(); - format!("{endpoint}/{bucket}") - } - } else { - let bucket = self.bucket.as_ref().unwrap(); - let region = self.aws_region.as_ref().unwrap(); - if self.aws_virtual_hosted_style_request { - format!("https://{bucket}.s3.{region}.amazonaws.com") - } else { - format!("https://s3.{region}.amazonaws.com/{bucket}") - } - }; - Ok(AmazonS3::new(&bucket_endpoint).map(Arc::new)?) - } - Some(ObjectStoreType::GCS) => { - Ok(GoogleCloudStorage::new(self.bucket.as_ref().unwrap()).map(Arc::new)?) - } - _ => Err(anyhow!("At least one storage backend should be provided")), - } - } -} - -async fn get( - url: &str, - store: &'static str, - location: &Path, - client: &Client, -) -> Result { - let request = client.request(Method::GET, url); - let response = request.send().await.context("failed to get")?; - let meta = header_meta(location, response.headers()).context("Failed to get header")?; - let stream = response - .bytes_stream() - .map_err(|source| Error::Generic { - store, - source: Box::new(source), - }) - .boxed(); - Ok(GetResult { - range: 0..meta.size, - payload: GetResultPayload::Stream(stream), - meta, - }) -} - -fn header_meta(location: &Path, headers: &HeaderMap) -> Result { - let last_modified = headers - .get(LAST_MODIFIED) - .context("Missing last modified")?; - - let content_length = headers - .get(CONTENT_LENGTH) - .context("Missing content length")?; - - let last_modified = last_modified.to_str().context("bad header")?; - let last_modified = DateTime::parse_from_rfc2822(last_modified) - .context("invalid last modified")? - .with_timezone(&Utc); - - let content_length = content_length.to_str().context("bad header")?; - let content_length = content_length.parse().context("invalid content length")?; - - let e_tag = headers.get(ETAG).context("missing etag")?; - let e_tag = e_tag.to_str().context("bad header")?; - - Ok(ObjectMeta { - location: location.clone(), - last_modified, - size: content_length, - e_tag: Some(e_tag.to_string()), - }) -} - -#[cfg(test)] -mod tests { - use std::fs; - - use object_store::path::Path; - use sui_config::object_storage_config::{ObjectStoreConfig, ObjectStoreType}; - use tempfile::TempDir; - - use crate::object_store::http::HttpDownloaderBuilder; - - #[tokio::test] - pub async fn test_local_download() -> anyhow::Result<()> { - let input = TempDir::new()?; - let input_path = input.path(); - let child = input_path.join("child"); - fs::create_dir(&child)?; - let file1 = child.join("file1"); - fs::write(file1, b"Lorem ipsum")?; - let grandchild = child.join("grand_child"); - fs::create_dir(&grandchild)?; - let file2 = grandchild.join("file2"); - fs::write(file2, b"Lorem ipsum")?; - - let input_store = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(input_path.to_path_buf()), - ..Default::default() - } - .make_http()?; - - let downloaded = input_store.get_bytes(&Path::from("child/file1")).await?; - assert_eq!(downloaded.to_vec(), b"Lorem ipsum"); - Ok(()) - } -} diff --git a/crates/sui-storage/src/object_store/mod.rs b/crates/sui-storage/src/object_store/mod.rs deleted file mode 100644 index e2f81fda891..00000000000 --- a/crates/sui-storage/src/object_store/mod.rs +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::sync::Arc; - -use anyhow::{anyhow, Result}; -use async_trait::async_trait; -use bytes::Bytes; -use futures::stream::BoxStream; -use object_store::{path::Path, DynObjectStore, ObjectMeta}; - -pub mod http; -pub mod util; - -#[async_trait] -pub trait ObjectStoreGetExt: std::fmt::Display + Send + Sync + 'static { - /// Return the bytes at given path in object store - async fn get_bytes(&self, src: &Path) -> Result; -} - -macro_rules! as_ref_get_ext_impl { - ($type:ty) => { - #[async_trait] - impl ObjectStoreGetExt for $type { - async fn get_bytes(&self, src: &Path) -> Result { - self.as_ref().get_bytes(src).await - } - } - }; -} - -as_ref_get_ext_impl!(Arc); -as_ref_get_ext_impl!(Box); - -#[async_trait] -impl ObjectStoreGetExt for Arc { - async fn get_bytes(&self, src: &Path) -> Result { - self.get(src) - .await? - .bytes() - .await - .map_err(|e| anyhow!("Failed to get file: {} with error: {}", src, e.to_string())) - } -} - -#[async_trait] -pub trait ObjectStoreListExt: Send + Sync + 'static { - /// List the objects at the given path in object store - async fn list_objects( - &self, - src: Option<&Path>, - ) -> object_store::Result>>; -} - -macro_rules! as_ref_list_ext_impl { - ($type:ty) => { - #[async_trait] - impl ObjectStoreListExt for $type { - async fn list_objects( - &self, - src: Option<&Path>, - ) -> object_store::Result>> { - self.as_ref().list_objects(src).await - } - } - }; -} - -as_ref_list_ext_impl!(Arc); -as_ref_list_ext_impl!(Box); - -#[async_trait] -impl ObjectStoreListExt for Arc { - async fn list_objects( - &self, - src: Option<&Path>, - ) -> object_store::Result>> { - self.list(src).await - } -} - -#[async_trait] -pub trait ObjectStorePutExt: Send + Sync + 'static { - /// Write the bytes at the given location in object store - async fn put_bytes(&self, src: &Path, bytes: Bytes) -> Result<()>; -} - -macro_rules! as_ref_put_ext_impl { - ($type:ty) => { - #[async_trait] - impl ObjectStorePutExt for $type { - async fn put_bytes(&self, src: &Path, bytes: Bytes) -> Result<()> { - self.as_ref().put_bytes(src, bytes).await - } - } - }; -} - -as_ref_put_ext_impl!(Arc); -as_ref_put_ext_impl!(Box); - -#[async_trait] -impl ObjectStorePutExt for Arc { - async fn put_bytes(&self, src: &Path, bytes: Bytes) -> Result<()> { - self.put(src, bytes).await?; - Ok(()) - } -} - -#[async_trait] -pub trait ObjectStoreDeleteExt: Send + Sync + 'static { - /// Delete the object at the given location in object store - async fn delete_object(&self, src: &Path) -> Result<()>; -} - -macro_rules! as_ref_delete_ext_impl { - ($type:ty) => { - #[async_trait] - impl ObjectStoreDeleteExt for $type { - async fn delete_object(&self, src: &Path) -> Result<()> { - self.as_ref().delete_object(src).await - } - } - }; -} - -as_ref_delete_ext_impl!(Arc); -as_ref_delete_ext_impl!(Box); - -#[async_trait] - -impl ObjectStoreDeleteExt for Arc { - async fn delete_object(&self, src: &Path) -> Result<()> { - self.delete(src).await?; - Ok(()) - } -} diff --git a/crates/sui-storage/src/object_store/util.rs b/crates/sui-storage/src/object_store/util.rs deleted file mode 100644 index b00098f90cf..00000000000 --- a/crates/sui-storage/src/object_store/util.rs +++ /dev/null @@ -1,557 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::BTreeMap, num::NonZeroUsize, ops::Range, path::PathBuf, sync::Arc, time::Duration, -}; - -use anyhow::{anyhow, Context, Result}; -use backoff::future::retry; -use bytes::Bytes; -use futures::{StreamExt, TryStreamExt}; -use indicatif::ProgressBar; -use itertools::Itertools; -use object_store::{path::Path, DynObjectStore, Error, ObjectStore}; -use serde::{Deserialize, Serialize}; -use tokio::time::Instant; -use tracing::{error, warn}; -use url::Url; - -use crate::object_store::{ - ObjectStoreDeleteExt, ObjectStoreGetExt, ObjectStoreListExt, ObjectStorePutExt, -}; - -pub const MANIFEST_FILENAME: &str = "MANIFEST"; - -#[derive(Serialize, Deserialize)] - -pub struct Manifest { - pub available_epochs: Vec, -} - -impl Manifest { - pub fn new(available_epochs: Vec) -> Self { - Manifest { available_epochs } - } - - pub fn epoch_exists(&self, epoch: u64) -> bool { - self.available_epochs.contains(&epoch) - } -} - -#[derive(Debug, Clone)] -pub struct PerEpochManifest { - pub lines: Vec, -} - -impl PerEpochManifest { - pub fn new(lines: Vec) -> Self { - PerEpochManifest { lines } - } - - pub fn serialize_as_newline_delimited(&self) -> String { - self.lines.join("\n") - } - - pub fn deserialize_from_newline_delimited(s: &str) -> PerEpochManifest { - PerEpochManifest { - lines: s.lines().map(String::from).collect(), - } - } - - // Method to filter lines by a given prefix - pub fn filter_by_prefix(&self, prefix: &str) -> PerEpochManifest { - let filtered_lines = self - .lines - .iter() - .filter(|line| line.starts_with(prefix)) - .cloned() - .collect(); - - PerEpochManifest { - lines: filtered_lines, - } - } -} - -pub async fn get(store: &S, src: &Path) -> Result { - let bytes = retry(backoff::ExponentialBackoff::default(), || async { - store.get_bytes(src).await.map_err(|e| { - error!("Failed to read file from object store with error: {:?}", &e); - backoff::Error::transient(e) - }) - }) - .await?; - Ok(bytes) -} - -pub async fn exists(store: &S, src: &Path) -> bool { - store.get_bytes(src).await.is_ok() -} - -pub async fn put(store: &S, src: &Path, bytes: Bytes) -> Result<()> { - retry(backoff::ExponentialBackoff::default(), || async { - if !bytes.is_empty() { - store.put_bytes(src, bytes.clone()).await.map_err(|e| { - error!("Failed to write file to object store with error: {:?}", &e); - backoff::Error::transient(e) - }) - } else { - warn!("Not copying empty file: {:?}", src); - Ok(()) - } - }) - .await?; - Ok(()) -} - -pub async fn copy_file( - src: &Path, - dest: &Path, - src_store: &S, - dest_store: &D, -) -> Result<()> { - let bytes = get(src_store, src).await?; - if !bytes.is_empty() { - put(dest_store, dest, bytes).await - } else { - warn!("Not copying empty file: {:?}", src); - Ok(()) - } -} - -pub async fn copy_files( - src: &[Path], - dest: &[Path], - src_store: &S, - dest_store: &D, - concurrency: NonZeroUsize, - progress_bar: Option, -) -> Result> { - let mut instant = Instant::now(); - let progress_bar_clone = progress_bar.clone(); - let results = futures::stream::iter(src.iter().zip(dest.iter())) - .map(|(path_in, path_out)| async move { - let ret = copy_file(path_in, path_out, src_store, dest_store).await; - Ok((path_out.clone(), ret)) - }) - .boxed() - .buffer_unordered(concurrency.get()) - .try_for_each(|(path, ret)| { - if let Some(progress_bar_clone) = &progress_bar_clone { - progress_bar_clone.inc(1); - progress_bar_clone.set_message(format!("file: {}", path)); - instant = Instant::now(); - } - futures::future::ready(ret) - }) - .await; - Ok(results.into_iter().collect()) -} - -pub async fn copy_recursively( - dir: &Path, - src_store: &S, - dest_store: &D, - concurrency: NonZeroUsize, -) -> Result> { - let mut input_paths = vec![]; - let mut output_paths = vec![]; - let mut paths = src_store.list_objects(Some(dir)).await?; - while let Some(res) = paths.next().await { - if let Ok(object_metadata) = res { - input_paths.push(object_metadata.location.clone()); - output_paths.push(object_metadata.location); - } else { - return Err(res.err().unwrap().into()); - } - } - copy_files( - &input_paths, - &output_paths, - src_store, - dest_store, - concurrency, - None, - ) - .await -} - -pub async fn delete_files( - files: &[Path], - store: &S, - concurrency: NonZeroUsize, -) -> Result> { - let results: Vec> = futures::stream::iter(files) - .map(|f| { - retry(backoff::ExponentialBackoff::default(), || async { - store.delete_object(f).await.map_err(|e| { - error!("Failed to delete file on object store with error: {:?}", &e); - backoff::Error::transient(e) - }) - }) - }) - .boxed() - .buffer_unordered(concurrency.get()) - .collect() - .await; - results.into_iter().collect() -} - -pub async fn delete_recursively( - path: &Path, - store: &S, - concurrency: NonZeroUsize, -) -> Result> { - let mut paths_to_delete = vec![]; - let mut paths = store.list_objects(Some(path)).await?; - while let Some(res) = paths.next().await { - if let Ok(object_metadata) = res { - paths_to_delete.push(object_metadata.location); - } else { - return Err(res.err().unwrap().into()); - } - } - delete_files(&paths_to_delete, store, concurrency).await -} - -pub fn path_to_filesystem(local_dir_path: PathBuf, location: &Path) -> anyhow::Result { - // Convert an `object_store::path::Path` to `std::path::PathBuf` - let path = std::fs::canonicalize(local_dir_path)?; - let mut url = Url::from_file_path(&path) - .map_err(|_| anyhow!("Failed to parse input path: {}", path.display()))?; - url.path_segments_mut() - .map_err(|_| anyhow!("Failed to get path segments: {}", path.display()))? - .pop_if_empty() - .extend(location.parts()); - let new_path = url - .to_file_path() - .map_err(|_| anyhow!("Failed to convert url to path: {}", url.as_str()))?; - Ok(new_path) -} - -/// This function will find all child directories in the input store which are -/// of the form "epoch_num" and return a map of epoch number to the directory -/// path -pub async fn find_all_dirs_with_epoch_prefix( - store: &Arc, - prefix: Option<&Path>, -) -> anyhow::Result> { - let mut dirs = BTreeMap::new(); - let entries = store.list_with_delimiter(prefix).await?; - for entry in entries.common_prefixes { - if let Some(filename) = entry.filename() { - if !filename.starts_with("epoch_") { - continue; - } - let epoch = filename - .split_once('_') - .context("Failed to split dir name") - .map(|(_, epoch)| epoch.parse::())??; - dirs.insert(epoch, entry); - } - } - Ok(dirs) -} - -pub async fn list_all_epochs(object_store: Arc) -> Result> { - let remote_epoch_dirs = find_all_dirs_with_epoch_prefix(&object_store, None).await?; - let mut out = vec![]; - let mut success_marker_found = false; - for (epoch, path) in remote_epoch_dirs.iter().sorted() { - let success_marker = path.child("_SUCCESS"); - let get_result = object_store.get(&success_marker).await; - match get_result { - Err(_) => { - if !success_marker_found { - error!("No success marker found for epoch: {epoch}"); - } - } - Ok(_) => { - out.push(*epoch); - success_marker_found = true; - } - } - } - Ok(out) -} - -pub async fn run_manifest_update_loop( - store: Arc, - mut recv: tokio::sync::broadcast::Receiver<()>, -) -> Result<()> { - let mut update_interval = tokio::time::interval(Duration::from_secs(300)); - loop { - tokio::select! { - _now = update_interval.tick() => { - if let Ok(epochs) = list_all_epochs(store.clone()).await { - let manifest_path = Path::from(MANIFEST_FILENAME); - let manifest = Manifest::new(epochs); - let bytes = serde_json::to_string(&manifest)?; - put(&store, &manifest_path, Bytes::from(bytes)).await?; - } - }, - _ = recv.recv() => break, - } - } - Ok(()) -} - -/// This function will find all child directories in the input store which are -/// of the form "epoch_num" and return a map of epoch number to the directory -/// path -pub async fn find_all_files_with_epoch_prefix( - store: &Arc, - prefix: Option<&Path>, -) -> anyhow::Result>> { - let mut ranges = Vec::new(); - let entries = store.list_with_delimiter(prefix).await?; - for entry in entries.objects { - let checkpoint_seq_range = entry - .location - .filename() - .ok_or(anyhow!("Illegal file name"))? - .split_once('.') - .context("Failed to split dir name")? - .0 - .split_once('_') - .context("Failed to split dir name") - .map(|(start, end)| Range { - start: start.parse::().unwrap(), - end: end.parse::().unwrap(), - })?; - - ranges.push(checkpoint_seq_range); - } - Ok(ranges) -} - -/// This function will find missing epoch directories in the input store and -/// return a list of such epoch numbers. If the highest epoch directory in the -/// store is `epoch_N` then it is expected that the store will have all epoch -/// directories from `epoch_0` to `epoch_N`. Additionally, any epoch directory -/// should have the passed in marker file present or else that epoch number is -/// already considered as missing -pub async fn find_missing_epochs_dirs( - store: &Arc, - success_marker: &str, -) -> anyhow::Result> { - let remote_checkpoints_by_epoch = find_all_dirs_with_epoch_prefix(store, None).await?; - let mut dirs: Vec<_> = remote_checkpoints_by_epoch.iter().collect(); - dirs.sort_by_key(|(epoch_num, _path)| *epoch_num); - let mut candidate_epoch: u64 = 0; - let mut missing_epochs = Vec::new(); - for (epoch_num, path) in dirs { - while candidate_epoch < *epoch_num { - // The whole epoch directory is missing - missing_epochs.push(candidate_epoch); - candidate_epoch += 1; - continue; - } - let success_marker = path.child(success_marker); - let get_result = store.get(&success_marker).await; - match get_result { - Err(Error::NotFound { .. }) => { - error!("No success marker found in db checkpoint for epoch: {epoch_num}"); - missing_epochs.push(*epoch_num); - } - Err(_) => { - // Probably a transient error - warn!( - "Failed while trying to read success marker in db checkpoint for epoch: {epoch_num}" - ); - } - Ok(_) => { - // Nothing to do - } - } - candidate_epoch += 1 - } - missing_epochs.push(candidate_epoch); - Ok(missing_epochs) -} - -pub fn get_path(prefix: &str) -> Path { - Path::from(prefix) -} - -// Snapshot MANIFEST file is very simple. Just a newline delimited list of all -// paths in the snapshot directory this simplicty enables easy parsing for -// scripts to download snapshots -pub async fn write_snapshot_manifest( - dir: &Path, - store: &S, - epoch_prefix: String, -) -> Result<()> { - let mut file_names = vec![]; - let mut paths = store.list_objects(Some(dir)).await?; - while let Some(res) = paths.next().await { - if let Ok(object_metadata) = res { - // trim the "epoch_XX/" dir prefix here - let mut path_str = object_metadata.location.to_string(); - if path_str.starts_with(&epoch_prefix) { - path_str = String::from(&path_str[epoch_prefix.len()..]); - file_names.push(path_str); - } else { - warn!("{path_str}, should be coming from the files in the {epoch_prefix} dir",) - } - } else { - return Err(res.err().unwrap().into()); - } - } - - let epoch_manifest = PerEpochManifest::new(file_names); - let bytes = Bytes::from(epoch_manifest.serialize_as_newline_delimited()); - put( - store, - &Path::from(format!("{}/{}", dir, MANIFEST_FILENAME)), - bytes, - ) - .await?; - - Ok(()) -} - -#[cfg(test)] -mod tests { - use std::{fs, num::NonZeroUsize}; - - use object_store::path::Path; - use sui_config::object_storage_config::{ObjectStoreConfig, ObjectStoreType}; - use tempfile::TempDir; - - use crate::object_store::util::{ - copy_recursively, delete_recursively, write_snapshot_manifest, MANIFEST_FILENAME, - }; - - #[tokio::test] - pub async fn test_copy_recursively() -> anyhow::Result<()> { - let input = TempDir::new()?; - let input_path = input.path(); - let child = input_path.join("child"); - fs::create_dir(&child)?; - let file1 = child.join("file1"); - fs::write(file1, b"Lorem ipsum")?; - let grandchild = child.join("grand_child"); - fs::create_dir(&grandchild)?; - let file2 = grandchild.join("file2"); - fs::write(file2, b"Lorem ipsum")?; - - let output = TempDir::new()?; - let output_path = output.path(); - - let input_store = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(input_path.to_path_buf()), - ..Default::default() - } - .make()?; - - let output_store = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(output_path.to_path_buf()), - ..Default::default() - } - .make()?; - - copy_recursively( - &Path::from("child"), - &input_store, - &output_store, - NonZeroUsize::new(1).unwrap(), - ) - .await?; - - assert!(output_path.join("child").exists()); - assert!(output_path.join("child").join("file1").exists()); - assert!(output_path.join("child").join("grand_child").exists()); - assert!( - output_path - .join("child") - .join("grand_child") - .join("file2") - .exists() - ); - let content = fs::read_to_string(output_path.join("child").join("file1"))?; - assert_eq!(content, "Lorem ipsum"); - let content = - fs::read_to_string(output_path.join("child").join("grand_child").join("file2"))?; - assert_eq!(content, "Lorem ipsum"); - Ok(()) - } - - #[tokio::test] - pub async fn test_write_snapshot_manifest() -> anyhow::Result<()> { - let input = TempDir::new()?; - let input_path = input.path(); - let epoch_0 = input_path.join("epoch_0"); - fs::create_dir(&epoch_0)?; - let file1 = epoch_0.join("file1"); - fs::write(file1, b"Lorem ipsum")?; - let file2 = epoch_0.join("file2"); - fs::write(file2, b"Lorem ipsum")?; - let grandchild = epoch_0.join("grand_child"); - fs::create_dir(&grandchild)?; - let file3 = grandchild.join("file2.tar.gz"); - fs::write(file3, b"Lorem ipsum")?; - - let input_store = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(input_path.to_path_buf()), - ..Default::default() - } - .make()?; - - write_snapshot_manifest( - &Path::from("epoch_0"), - &input_store, - String::from("epoch_0/"), - ) - .await?; - - assert!(input_path.join("epoch_0").join(MANIFEST_FILENAME).exists()); - let content = fs::read_to_string(input_path.join("epoch_0").join(MANIFEST_FILENAME))?; - assert!(content.contains("file2")); - assert!(content.contains("file1")); - assert!(content.contains("grand_child/file2.tar.gz")); - Ok(()) - } - - #[tokio::test] - pub async fn test_delete_recursively() -> anyhow::Result<()> { - let input = TempDir::new()?; - let input_path = input.path(); - let child = input_path.join("child"); - fs::create_dir(&child)?; - let file1 = child.join("file1"); - fs::write(file1, b"Lorem ipsum")?; - let grandchild = child.join("grand_child"); - fs::create_dir(&grandchild)?; - let file2 = grandchild.join("file2"); - fs::write(file2, b"Lorem ipsum")?; - - let input_store = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(input_path.to_path_buf()), - ..Default::default() - } - .make()?; - - delete_recursively( - &Path::from("child"), - &input_store, - NonZeroUsize::new(1).unwrap(), - ) - .await?; - - assert!(!input_path.join("child").join("file1").exists()); - assert!( - !input_path - .join("child") - .join("grand_child") - .join("file2") - .exists() - ); - Ok(()) - } -} diff --git a/crates/sui-surfer/Cargo.toml b/crates/sui-surfer/Cargo.toml deleted file mode 100644 index 94f9d597507..00000000000 --- a/crates/sui-surfer/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -name = "sui-surfer" -version.workspace = true -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -sui-core.workspace = true -sui-swarm-config.workspace = true -sui-json-rpc-types.workspace = true -sui-move-build.workspace = true -sui-protocol-config.workspace = true -sui-types.workspace = true -test-cluster.workspace = true - -async-trait.workspace = true -bcs.workspace = true -clap.workspace = true -futures.workspace = true -indexmap.workspace = true -rand.workspace = true -tokio = { workspace = true, features = ["full", "tracing", "test-util"] } -tracing.workspace = true - -move-binary-format.workspace = true -move-core-types.workspace = true -telemetry-subscribers.workspace = true - -[dev-dependencies] -prometheus.workspace = true -sui-macros.workspace = true -sui-simulator.workspace = true - -move-package.workspace = true diff --git a/crates/sui-surfer/src/lib.rs b/crates/sui-surfer/src/lib.rs deleted file mode 100644 index d2bed2d48f1..00000000000 --- a/crates/sui-surfer/src/lib.rs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{path::PathBuf, sync::Arc, time::Duration}; - -use futures::future::join_all; -use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng}; -use sui_swarm_config::genesis_config::{AccountConfig, DEFAULT_GAS_AMOUNT}; -use surf_strategy::SurfStrategy; -use test_cluster::TestClusterBuilder; -use tokio::sync::watch; -use tracing::info; - -use crate::{surfer_state::SurfStatistics, surfer_task::SurferTask}; - -pub mod default_surf_strategy; -mod surf_strategy; -mod surfer_state; -mod surfer_task; - -const VALIDATOR_COUNT: usize = 7; - -const ACCOUNT_NUM: usize = 20; -const GAS_OBJECT_COUNT: usize = 3; - -pub async fn run( - run_duration: Duration, - epoch_duration: Duration, - package_paths: Vec, -) -> SurfStatistics { - let cluster = Arc::new( - TestClusterBuilder::new() - .with_num_validators(VALIDATOR_COUNT) - .with_epoch_duration_ms(epoch_duration.as_millis() as u64) - .with_accounts(vec![ - AccountConfig { - address: None, - gas_amounts: vec![DEFAULT_GAS_AMOUNT; GAS_OBJECT_COUNT], - }; - ACCOUNT_NUM - ]) - .build() - .await, - ); - info!( - "Started cluster with {} validators and epoch duration of {:?}ms", - VALIDATOR_COUNT, - epoch_duration.as_millis() - ); - - let seed = rand::thread_rng().gen::(); - info!("Initial Seed: {:?}", seed); - let mut rng = StdRng::seed_from_u64(seed); - let (exit_sender, exit_rcv) = watch::channel(()); - - let mut tasks = - SurferTask::create_surfer_tasks::(cluster.clone(), rng.gen::(), exit_rcv).await; - info!("Created {} surfer tasks", tasks.len()); - - for path in package_paths { - tasks - .choose_mut(&mut rng) - .unwrap() - .state - .publish_package(path) - .await; - } - - let mut handles = vec![]; - for task in tasks { - handles.push(tokio::task::spawn(task.surf())); - } - tokio::time::sleep(run_duration).await; - exit_sender.send(()).unwrap(); - let all_stats: Result, _> = join_all(handles).await.into_iter().collect(); - SurfStatistics::aggregate(all_stats.unwrap()) - - // TODO: Right now it will panic here complaining about dropping a tokio - // runtime inside of another tokio runtime. Reason unclear. -} diff --git a/crates/sui-surfer/src/main.rs b/crates/sui-surfer/src/main.rs deleted file mode 100644 index cf84823ad2d..00000000000 --- a/crates/sui-surfer/src/main.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{path::PathBuf, time::Duration}; - -use clap::Parser; -use sui_surfer::default_surf_strategy::DefaultSurfStrategy; -use tracing::info; - -#[derive(Parser)] -#[clap(rename_all = "kebab-case")] -struct Args { - #[clap(long, help = "Number of seconds to surf, default to 30")] - pub run_duration: Option, - - #[clap(long, help = "Number of seconds per epoch, default to 15")] - pub epoch_duration: Option, - - #[clap(long, help = "List of package paths to surf")] - packages: Vec, -} - -const DEFAULT_RUN_DURATION: u64 = 30; -const DEFAULT_EPOCH_DURATION: u64 = 15; - -#[tokio::main] -async fn main() { - let args = Args::parse(); - if args.packages.is_empty() { - eprintln!("At least one package is required"); - return; - } - - let _guard = telemetry_subscribers::TelemetryConfig::new() - .with_log_level("off,sui_surfer=info") - .with_env() - .init(); - - let results = sui_surfer::run::( - Duration::from_secs(args.run_duration.unwrap_or(DEFAULT_RUN_DURATION)), - Duration::from_secs(args.run_duration.unwrap_or(DEFAULT_EPOCH_DURATION)), - args.packages, - ) - .await; - results.print_stats(); - info!("Finished surfing"); -} diff --git a/crates/sui-surfer/tests/move_building_blocks/Move.toml b/crates/sui-surfer/tests/move_building_blocks/Move.toml deleted file mode 100644 index 45df78b7420..00000000000 --- a/crates/sui-surfer/tests/move_building_blocks/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "MoveBuildingBlocks" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../sui-framework/packages/sui-framework" } - -[addresses] -move_building_blocks = "0x0" \ No newline at end of file diff --git a/crates/sui-surfer/tests/random/Move.toml b/crates/sui-surfer/tests/random/Move.toml deleted file mode 100644 index c724bf024b3..00000000000 --- a/crates/sui-surfer/tests/random/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "Random" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../sui-framework/packages/sui-framework" } - -[addresses] -random = "0x0" diff --git a/crates/sui-surfer/tests/random/sources/random.move b/crates/sui-surfer/tests/random/sources/random.move deleted file mode 100644 index 9576cf4d9fc..00000000000 --- a/crates/sui-surfer/tests/random/sources/random.move +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module random::random_test { - use sui::object::UID; - use sui::object; - use sui::tx_context::TxContext; - use sui::transfer; - use sui::random; - - - // Test transactions that use the same shared object, sometimes with Random and sometimes without. - - struct SharedObject has key, store { - id: UID, - value: u256, - } - - fun init(ctx: &mut TxContext) { - let object = SharedObject { - id: object::new(ctx), - value: 123, - }; - transfer::share_object(object); - } - - // Update the shared object using Random. - entry fun mutate_with_random(obj: &mut SharedObject, r: &random::Random, n: u8, ctx: &mut TxContext) { - let gen = random::new_generator(r, ctx); - let _b = random::generate_bytes(&mut gen, (n as u16)); - obj.value = random::generate_u256(&mut gen); - assert!(obj.value > 0, 0); // very low probability - } - - // Update the shared object without using Random. - entry fun mutate_without(obj: &mut SharedObject) { - obj.value = obj.value % 27; - } - - - // Test transactions that use Random without a shared object. - entry fun generate(r: &random::Random, ctx: &mut TxContext): u64 { - let _gen1 = random::new_generator(r, ctx); - let _gen2 = random::new_generator(r, ctx); - let gen3 = random::new_generator(r, ctx); - random::generate_u64(&mut gen3) - } -} diff --git a/crates/sui-surfer/tests/smoke_tests.rs b/crates/sui-surfer/tests/smoke_tests.rs deleted file mode 100644 index 4438956e766..00000000000 --- a/crates/sui-surfer/tests/smoke_tests.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{path::PathBuf, time::Duration}; - -use sui_macros::sim_test; -use sui_surfer::default_surf_strategy::DefaultSurfStrategy; - -#[sim_test] -async fn smoke_test() { - // This test makes sure that the sui surfer runs. - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.extend(["tests", "move_building_blocks"]); - let results = sui_surfer::run::( - Duration::from_secs(30), - Duration::from_secs(15), - vec![path], - ) - .await; - assert!(results.num_successful_transactions > 0); - assert!(!results.unique_move_functions_called.is_empty()); -} diff --git a/crates/sui-swarm-config/Cargo.toml b/crates/sui-swarm-config/Cargo.toml deleted file mode 100644 index a2823f51cb0..00000000000 --- a/crates/sui-swarm-config/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "sui-swarm-config" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anemo.workspace = true -anyhow.workspace = true -fastcrypto.workspace = true -rand.workspace = true -serde.workspace = true -serde_with.workspace = true -serde_yaml.workspace = true -tempfile.workspace = true -tracing.workspace = true -prometheus.workspace = true - -move-bytecode-utils.workspace = true -narwhal-config.workspace = true -shared-crypto.workspace = true -sui-config.workspace = true -sui-macros.workspace = true -sui-protocol-config.workspace = true -sui-types.workspace = true -sui-genesis-builder.workspace = true - -[target.'cfg(msim)'.dependencies] -sui-simulator.workspace = true - -[dev-dependencies] -insta.workspace = true -tempfile.workspace = true - -sui-execution.workspace = true diff --git a/crates/sui-swarm-config/src/lib.rs b/crates/sui-swarm-config/src/lib.rs deleted file mode 100644 index 1f2e9e5c115..00000000000 --- a/crates/sui-swarm-config/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod genesis_config; -pub mod network_config; -pub mod network_config_builder; -pub mod node_config_builder; -pub mod test_utils; diff --git a/crates/sui-swarm-config/src/test_utils.rs b/crates/sui-swarm-config/src/test_utils.rs deleted file mode 100644 index 8b283f50d29..00000000000 --- a/crates/sui-swarm-config/src/test_utils.rs +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::HashMap; - -use shared_crypto::intent::{Intent, IntentMessage, IntentScope}; -use sui_types::{ - base_types::AuthorityName, - committee::{Committee, EpochId, StakeUnit}, - crypto::{ - AuthorityKeyPair, AuthoritySignInfo, AuthoritySignature, KeypairTraits, - SuiAuthoritySignature, - }, - messages_checkpoint::{ - CertifiedCheckpointSummary, CheckpointDigest, CheckpointSequenceNumber, CheckpointSummary, - EndOfEpochData, FullCheckpointContents, VerifiedCheckpoint, VerifiedCheckpointContents, - }, -}; - -use crate::network_config::NetworkConfig; - -pub struct CommitteeFixture { - epoch: EpochId, - validators: HashMap, - committee: Committee, -} - -type MakeCheckpointResults = ( - Vec, - Vec, - HashMap, - HashMap, -); - -impl CommitteeFixture { - pub fn generate( - mut rng: R, - epoch: EpochId, - committee_size: usize, - ) -> Self { - let validators = (0..committee_size) - .map(|_| sui_types::crypto::get_key_pair_from_rng::(&mut rng).1) - .map(|keypair| (keypair.public().into(), (keypair, 1))) - .collect::>(); - - let committee = Committee::new_for_testing_with_normalized_voting_power( - epoch, - validators - .iter() - .map(|(name, (_, stake))| (*name, *stake)) - .collect(), - ); - - Self { - epoch, - validators, - committee, - } - } - - pub fn from_network_config(network_config: &NetworkConfig) -> Self { - let committee = network_config.genesis.committee().unwrap(); - Self { - epoch: committee.epoch, - validators: committee - .members() - .map(|(name, stake)| { - ( - *name, - ( - network_config - .validator_configs() - .iter() - .find(|config| config.protocol_public_key() == *name) - .unwrap() - .protocol_key_pair() - .copy(), - *stake, - ), - ) - }) - .collect(), - committee, - } - } - - pub fn committee(&self) -> &Committee { - &self.committee - } - - fn create_root_checkpoint(&self) -> (VerifiedCheckpoint, VerifiedCheckpointContents) { - assert_eq!(self.epoch, 0, "root checkpoint must be epoch 0"); - let checkpoint = CheckpointSummary { - epoch: 0, - sequence_number: 0, - network_total_transactions: 0, - content_digest: *empty_contents() - .into_inner() - .into_checkpoint_contents() - .digest(), - previous_digest: None, - epoch_rolling_gas_cost_summary: Default::default(), - end_of_epoch_data: None, - timestamp_ms: 0, - version_specific_data: Vec::new(), - checkpoint_commitments: Default::default(), - }; - - ( - self.create_certified_checkpoint(checkpoint), - empty_contents(), - ) - } - - fn create_certified_checkpoint(&self, checkpoint: CheckpointSummary) -> VerifiedCheckpoint { - let signatures = self - .validators - .iter() - .map(|(name, (key, _))| { - let intent_msg = IntentMessage::new( - Intent::sui_app(IntentScope::CheckpointSummary), - checkpoint.clone(), - ); - let signature = AuthoritySignature::new_secure(&intent_msg, &checkpoint.epoch, key); - AuthoritySignInfo { - epoch: checkpoint.epoch, - authority: *name, - signature, - } - }) - .collect(); - - let checkpoint = CertifiedCheckpointSummary::new(checkpoint, signatures, self.committee()) - .unwrap() - .verify(self.committee()) - .unwrap(); - - checkpoint - } - - pub fn make_random_checkpoints( - &self, - number_of_checkpoints: usize, - previous_checkpoint: Option, - ) -> MakeCheckpointResults { - self.make_checkpoints(number_of_checkpoints, previous_checkpoint, random_contents) - } - - pub fn make_empty_checkpoints( - &self, - number_of_checkpoints: usize, - previous_checkpoint: Option, - ) -> MakeCheckpointResults { - self.make_checkpoints(number_of_checkpoints, previous_checkpoint, empty_contents) - } - - fn make_checkpoints VerifiedCheckpointContents>( - &self, - number_of_checkpoints: usize, - previous_checkpoint: Option, - content_generator: F, - ) -> MakeCheckpointResults { - // Only skip the first one if it was supplied - let skip = previous_checkpoint.is_some() as usize; - let first = previous_checkpoint - .map(|c| (c, empty_contents())) - .unwrap_or_else(|| self.create_root_checkpoint()); - - let (ordered_checkpoints, contents): (Vec<_>, Vec<_>) = - std::iter::successors(Some(first), |prev| { - let contents = content_generator(); - let contents_digest = *contents - .clone() - .into_inner() - .into_checkpoint_contents() - .digest(); - let summary = CheckpointSummary { - epoch: self.epoch, - sequence_number: prev.0.sequence_number + 1, - network_total_transactions: prev.0.network_total_transactions - + contents.num_of_transactions() as u64, - content_digest: contents_digest, - previous_digest: Some(*prev.0.digest()), - epoch_rolling_gas_cost_summary: Default::default(), - end_of_epoch_data: None, - timestamp_ms: 0, - version_specific_data: Vec::new(), - checkpoint_commitments: Default::default(), - }; - - let checkpoint = self.create_certified_checkpoint(summary); - - Some((checkpoint, contents)) - }) - .skip(skip) - .take(number_of_checkpoints) - .unzip(); - - let (sequence_number_to_digest, checkpoints) = ordered_checkpoints - .iter() - .cloned() - .map(|checkpoint| { - let digest = *checkpoint.digest(); - ((checkpoint.sequence_number, digest), (digest, checkpoint)) - }) - .unzip(); - - ( - ordered_checkpoints, - contents, - sequence_number_to_digest, - checkpoints, - ) - } - - pub fn make_end_of_epoch_checkpoint( - &self, - previous_checkpoint: VerifiedCheckpoint, - end_of_epoch_data: Option, - ) -> ( - CheckpointSequenceNumber, - CheckpointDigest, - VerifiedCheckpoint, - ) { - let summary = CheckpointSummary { - epoch: self.epoch, - sequence_number: previous_checkpoint.sequence_number + 1, - network_total_transactions: 0, - content_digest: *empty_contents() - .into_inner() - .into_checkpoint_contents() - .digest(), - previous_digest: Some(*previous_checkpoint.digest()), - epoch_rolling_gas_cost_summary: Default::default(), - end_of_epoch_data, - timestamp_ms: 0, - version_specific_data: Vec::new(), - checkpoint_commitments: Default::default(), - }; - - let checkpoint = self.create_certified_checkpoint(summary); - - (checkpoint.sequence_number, *checkpoint.digest(), checkpoint) - } -} - -pub fn empty_contents() -> VerifiedCheckpointContents { - VerifiedCheckpointContents::new_unchecked( - FullCheckpointContents::new_with_causally_ordered_transactions(std::iter::empty()), - ) -} - -pub fn random_contents() -> VerifiedCheckpointContents { - VerifiedCheckpointContents::new_unchecked(FullCheckpointContents::random_for_testing()) -} diff --git a/crates/sui-swarm-config/tests/snapshot_tests.rs b/crates/sui-swarm-config/tests/snapshot_tests.rs deleted file mode 100644 index ddedaaca389..00000000000 --- a/crates/sui-swarm-config/tests/snapshot_tests.rs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// This file contains tests that detect changes in Sui configs. -// If a PR breaks one or more tests here, the PR probably has a real impact -// on a production configuration file. When test failure happens, the PR should -// be marked as a breaking change and reviewers should be aware of this. -// -// Owners and operators of production configuration files can add themselves to -// .github/CODEOWNERS for the corresponding snapshot tests, so they can get -// notified of changes. PRs that modifies snapshot files should wait for reviews -// from code owners (if any) before merging. -// -// To review snapshot changes, and fix snapshot differences, -// 0. Install cargo-insta -// 1. Run `cargo insta test --review` under `./sui-config`. -// 2. Review, accept or reject changes. - -use std::num::NonZeroUsize; - -use fastcrypto::traits::KeyPair; -use insta::assert_yaml_snapshot; -use rand::{rngs::StdRng, SeedableRng}; -use sui_config::{ - genesis::{GenesisCeremonyParameters, TokenDistributionScheduleBuilder}, - node::{DEFAULT_COMMISSION_RATE, DEFAULT_VALIDATOR_GAS_PRICE}, -}; -use sui_genesis_builder::{validator_info::ValidatorInfo, Builder}; -use sui_swarm_config::genesis_config::GenesisConfig; -use sui_types::{ - base_types::SuiAddress, - crypto::{ - generate_proof_of_possession, get_key_pair_from_rng, AccountKeyPair, AuthorityKeyPair, - NetworkKeyPair, SuiKeyPair, - }, - multiaddr::Multiaddr, -}; - -#[test] -#[cfg_attr(msim, ignore)] -fn genesis_config_snapshot_matches() { - let ed_kp1: SuiKeyPair = - SuiKeyPair::Ed25519(get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1); - let fake_addr: SuiAddress = (&ed_kp1.public()).into(); - - let mut genesis_config = GenesisConfig::for_local_testing(); - genesis_config.parameters.chain_start_timestamp_ms = 0; - for account in &mut genesis_config.accounts { - account.address = Some(fake_addr); - } - assert_yaml_snapshot!(genesis_config); -} - -#[test] -fn populated_genesis_snapshot_matches() { - let genesis_config = GenesisConfig::for_local_testing(); - let (_account_keys, allocations) = genesis_config - .generate_accounts(StdRng::from_seed([0; 32])) - .unwrap(); - let mut rng = StdRng::from_seed([0; 32]); - let key: AuthorityKeyPair = get_key_pair_from_rng(&mut rng).1; - let worker_key: NetworkKeyPair = get_key_pair_from_rng(&mut rng).1; - let network_key: NetworkKeyPair = get_key_pair_from_rng(&mut rng).1; - let account_key: AccountKeyPair = get_key_pair_from_rng(&mut rng).1; - let validator = ValidatorInfo { - name: "0".into(), - protocol_key: key.public().into(), - worker_key: worker_key.public().clone(), - account_address: SuiAddress::from(account_key.public()), - network_key: network_key.public().clone(), - gas_price: DEFAULT_VALIDATOR_GAS_PRICE, - commission_rate: DEFAULT_COMMISSION_RATE, - network_address: "/ip4/127.0.0.1/tcp/80".parse().unwrap(), - p2p_address: "/ip4/127.0.0.1/udp/80".parse().unwrap(), - narwhal_primary_address: "/ip4/127.0.0.1/udp/80".parse().unwrap(), - narwhal_worker_address: "/ip4/127.0.0.1/udp/80".parse().unwrap(), - description: String::new(), - image_url: String::new(), - project_url: String::new(), - }; - let pop = generate_proof_of_possession(&key, account_key.public().into()); - - let token_distribution_schedule = { - let mut builder = TokenDistributionScheduleBuilder::new(); - for allocation in allocations { - builder.add_allocation(allocation); - } - builder.default_allocation_for_validators(Some(validator.account_address)); - builder.build() - }; - - let genesis = Builder::new() - .with_token_distribution_schedule(token_distribution_schedule) - .add_validator(validator, pop) - .with_parameters(GenesisCeremonyParameters { - chain_start_timestamp_ms: 10, - ..GenesisCeremonyParameters::new() - }) - .add_validator_signature(&key) - .build(); - assert_yaml_snapshot!(genesis.sui_system_wrapper_object()); - assert_yaml_snapshot!( - genesis - .sui_system_object() - .into_genesis_version_for_tooling() - ); - assert_yaml_snapshot!(genesis.clock()); - // Serialized `genesis` is not static and cannot be snapshot tested. -} - -#[test] -#[cfg_attr(msim, ignore)] -fn network_config_snapshot_matches() { - use std::{ - net::{IpAddr, Ipv4Addr, SocketAddr}, - path::PathBuf, - }; - - use sui_swarm_config::network_config_builder::ConfigBuilder; - - let temp_dir = tempfile::tempdir().unwrap(); - let committee_size = 7; - let rng = StdRng::from_seed([0; 32]); - let mut network_config = ConfigBuilder::new(temp_dir) - .committee_size(NonZeroUsize::new(committee_size).unwrap()) - .rng(rng) - .build(); - // TODO: Inject static temp path and port numbers, instead of clearing them. - for validator_config in &mut network_config.validator_configs { - validator_config.db_path = PathBuf::from("/tmp/foo/"); - validator_config.network_address = Multiaddr::empty(); - let fake_socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 1); - validator_config.json_rpc_address = fake_socket; - validator_config.metrics_address = fake_socket; - validator_config.p2p_config.listen_address = fake_socket; - validator_config.p2p_config.external_address = None; - validator_config.admin_interface_port = 8888; - let metrics_addr: Multiaddr = "/ip4/127.0.0.1/tcp/1234".parse().unwrap(); - let primary_network_admin_server_port = 5678; - let worker_network_admin_server_base_port = 8765; - if let Some(consensus_config) = validator_config.consensus_config.as_mut() { - consensus_config.address = Multiaddr::empty(); - consensus_config.db_path = PathBuf::from("/tmp/foo/"); - consensus_config.internal_worker_address = Some(Multiaddr::empty()); - consensus_config - .narwhal_config - .prometheus_metrics - .socket_addr = metrics_addr; - consensus_config - .narwhal_config - .network_admin_server - .primary_network_admin_server_port = primary_network_admin_server_port; - consensus_config - .narwhal_config - .network_admin_server - .worker_network_admin_server_base_port = worker_network_admin_server_base_port; - } - } - assert_yaml_snapshot!(network_config, { - ".genesis" => "[fake genesis]", - ".validator_configs[].genesis.genesis" => "[fake genesis]", - }); -} diff --git a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-3.snap b/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-3.snap deleted file mode 100644 index 3ea9b3874c5..00000000000 --- a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-3.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: crates/sui-swarm-config/tests/snapshot_tests.rs -expression: genesis.clock() ---- -id: - id: "0x0000000000000000000000000000000000000000000000000000000000000006" -timestamp_ms: 10 - diff --git a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-4.snap b/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-4.snap deleted file mode 100644 index 2a2a5aac6f2..00000000000 --- a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-4.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: crates/sui-config/tests/snapshot_tests.rs -expression: genesis.clock() ---- -id: - id: "0x0000000000000000000000000000000000000000000000000000000000000006" -timestamp_ms: 0 - diff --git a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches.snap b/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches.snap deleted file mode 100644 index a134c3e912b..00000000000 --- a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: crates/sui-config/tests/snapshot_tests.rs -expression: genesis.sui_system_wrapper_object() ---- -id: - id: "0x0000000000000000000000000000000000000000000000000000000000000005" -version: 1 - diff --git a/crates/sui-swarm/Cargo.toml b/crates/sui-swarm/Cargo.toml deleted file mode 100644 index b67f22a3094..00000000000 --- a/crates/sui-swarm/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "sui-swarm" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -rand.workspace = true -tracing.workspace = true -tokio = { workspace = true, features = ["full"] } -futures.workspace = true -tempfile.workspace = true -tonic-health.workspace = true -tap.workspace = true -prometheus.workspace = true - -sui-config.workspace = true -sui-swarm-config.workspace = true -sui-macros.workspace = true -sui-node.workspace = true -sui-protocol-config.workspace = true -sui-types.workspace = true -mysten-metrics.workspace = true -mysten-network.workspace = true -telemetry-subscribers.workspace = true - -[target.'cfg(msim)'.dependencies] -sui-simulator.workspace = true - diff --git a/crates/sui-swarm/README.md b/crates/sui-swarm/README.md deleted file mode 100644 index a9ea35a039a..00000000000 --- a/crates/sui-swarm/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# sui-swarm - -This crate contains a collection of utilities for managing complete Sui -networks. The intended use for these utilities is for performing end-to-end -testing and benchmarking. In the future, the expectation is that we'll have -support for a number of different "backends" for how the network is operated. -Today the only supplied backend is the `memory` backend, although in the future -we should be able to support a multi-process and even a Kubernetes (k8s) backend. - -## Backends - -### memory - -An `in-memory`, or rather `in-process`, backend for building and managing Sui -networks that all run inside the same process. Nodes are isolated from one -another by each being run on their own separate thread within their own `tokio` -runtime. This enables the ability to properly shut down a single node and -ensure that all of its running tasks are also shut down, something that is -extremely difficult or down right impossible to do if all the nodes are running -on the same runtime. diff --git a/crates/sui-swarm/src/lib.rs b/crates/sui-swarm/src/lib.rs deleted file mode 100644 index f3e87d275da..00000000000 --- a/crates/sui-swarm/src/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod memory; diff --git a/crates/sui-swarm/src/memory/mod.rs b/crates/sui-swarm/src/memory/mod.rs deleted file mode 100644 index 1f4c865d524..00000000000 --- a/crates/sui-swarm/src/memory/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//! An `in-memory`, or rather `in-process`, backend for building and managing -//! Sui Networks that all run inside the same process. Nodes are isolated from -//! one another by each being run on their own separate thread within their own -//! `tokio` runtime. This enables the ability to properly shut down a single -//! node and ensure that all of its running tasks are also shut down, something -//! that is extremely difficult or down right impossible to do if all the nodes -//! are running on the same runtime. - -mod node; -pub use node::{Node, RuntimeType}; - -mod swarm; -pub use swarm::{Swarm, SwarmBuilder}; - -#[cfg(msim)] -#[path = "./container-sim.rs"] -mod container; - -#[cfg(not(msim))] -#[path = "./container.rs"] -mod container; diff --git a/crates/sui-swarm/src/memory/node.rs b/crates/sui-swarm/src/memory/node.rs deleted file mode 100644 index 16c8c064700..00000000000 --- a/crates/sui-swarm/src/memory/node.rs +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::sync::Mutex; - -use anyhow::{anyhow, Result}; -use sui_config::NodeConfig; -use sui_node::SuiNodeHandle; -use sui_types::base_types::{AuthorityName, ConciseableName}; -use tap::TapFallible; -use tracing::{error, info}; - -use super::container::Container; - -/// A handle to an in-memory Sui Node. -/// -/// Each Node is attempted to run in isolation from each other by running them -/// in their own tokio runtime in a separate thread. By doing this we can ensure -/// that all asynchronous tasks associated with a Node are able to be stopped -/// when desired (either when a Node is dropped or explicitly stopped by calling -/// [`Node::stop`]) by simply dropping that Node's runtime. -#[derive(Debug)] -pub struct Node { - container: Mutex>, - pub config: NodeConfig, - runtime_type: RuntimeType, -} - -impl Node { - /// Create a new Node from the provided `NodeConfig`. - /// - /// The Node is returned without being started. See [`Node::spawn`] or - /// [`Node::start`] for how to start the node. - /// - /// [`NodeConfig`]: sui_config::NodeConfig - pub fn new(config: NodeConfig) -> Self { - Self { - container: Default::default(), - config, - runtime_type: RuntimeType::SingleThreaded, - } - } - - /// Return the `name` of this Node - pub fn name(&self) -> AuthorityName { - self.config.protocol_public_key() - } - - pub fn json_rpc_address(&self) -> std::net::SocketAddr { - self.config.json_rpc_address - } - - /// Start this Node - pub async fn spawn(&self) -> Result<()> { - info!(name =% self.name().concise(), "starting in-memory node"); - *self.container.lock().unwrap() = - Some(Container::spawn(self.config.clone(), self.runtime_type).await); - Ok(()) - } - - /// Start this Node, waiting until its completely started up. - pub async fn start(&self) -> Result<()> { - self.spawn().await - } - - /// Stop this Node - pub fn stop(&self) { - info!(name =% self.name().concise(), "stopping in-memory node"); - *self.container.lock().unwrap() = None; - } - - /// If this Node is currently running - pub fn is_running(&self) -> bool { - self.container - .lock() - .unwrap() - .as_ref() - .map_or(false, |c| c.is_alive()) - } - - pub fn get_node_handle(&self) -> Option { - self.container - .lock() - .unwrap() - .as_ref() - .and_then(|c| c.get_node_handle()) - } - - /// Perform a health check on this Node by: - /// * Checking that the node is running - /// * Calling the Node's gRPC Health service if it's a validator. - pub async fn health_check(&self, is_validator: bool) -> Result<(), HealthCheckError> { - { - let lock = self.container.lock().unwrap(); - let container = lock.as_ref().ok_or(HealthCheckError::NotRunning)?; - if !container.is_alive() { - return Err(HealthCheckError::NotRunning); - } - } - - if is_validator { - let channel = mysten_network::client::connect(self.config.network_address()) - .await - .map_err(|err| anyhow!(err.to_string())) - .map_err(HealthCheckError::Failure) - .tap_err(|e| error!("error connecting to {}: {e}", self.name().concise()))?; - - let mut client = tonic_health::pb::health_client::HealthClient::new(channel); - client - .check(tonic_health::pb::HealthCheckRequest::default()) - .await - .map_err(|e| HealthCheckError::Failure(e.into())) - .tap_err(|e| { - error!( - "error performing health check on {}: {e}", - self.name().concise() - ) - })?; - } - - Ok(()) - } -} - -#[derive(Debug)] -pub enum HealthCheckError { - NotRunning, - Failure(anyhow::Error), - Unknown(anyhow::Error), -} - -impl std::fmt::Display for HealthCheckError { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl std::error::Error for HealthCheckError {} - -/// The type of tokio runtime that should be used for a particular Node -#[derive(Clone, Copy, Debug)] -pub enum RuntimeType { - SingleThreaded, - MultiThreaded, -} - -#[cfg(test)] -mod test { - use crate::memory::Swarm; - - #[tokio::test] - async fn start_and_stop() { - telemetry_subscribers::init_for_testing(); - let swarm = Swarm::builder().build(); - - let validator = swarm.validator_nodes().next().unwrap(); - - validator.start().await.unwrap(); - validator.health_check(true).await.unwrap(); - validator.stop(); - validator.health_check(true).await.unwrap_err(); - - validator.start().await.unwrap(); - validator.health_check(true).await.unwrap(); - } -} diff --git a/crates/sui-telemetry/Cargo.toml b/crates/sui-telemetry/Cargo.toml deleted file mode 100644 index 1feb6270b7c..00000000000 --- a/crates/sui-telemetry/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "sui-telemetry" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -serde.workspace = true -reqwest.workspace = true -tracing.workspace = true - -sui-core.workspace = true - diff --git a/crates/sui-telemetry/src/lib.rs b/crates/sui-telemetry/src/lib.rs deleted file mode 100644 index 6d9c4113dea..00000000000 --- a/crates/sui-telemetry/src/lib.rs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::BTreeMap, - sync::Arc, - time::{SystemTime, UNIX_EPOCH}, -}; - -use serde::{Deserialize, Serialize}; -use sui_core::authority::AuthorityState; -use tracing::trace; - -pub(crate) const GA_API_SECRET: &str = "zeq-aYEzS0aGdRJ8kNZTEg"; -pub(crate) const GA_EVENT_NAME: &str = "node_telemetry_event"; -pub(crate) const GA_MEASUREMENT_ID: &str = "G-96DM59YK2F"; -pub(crate) const GA_URL: &str = "https://www.google-analytics.com/mp/collect"; -// need this hardcoded client ID as only existing client is valid. -// see below for details: -// https://developers.google.com/analytics/devguides/collection/protocol/ga4/verify-implementation?client_type=gtag -pub(crate) const HARDCODED_CLIENT_ID: &str = "1871165366.1648333069"; -pub(crate) const IPLOOKUP_URL: &str = "https://api.ipify.org?format=json"; -pub(crate) const UNKNOWN_STRING: &str = "UNKNOWN"; - -#[derive(Debug, Serialize, Deserialize)] -struct TelemetryEvent { - name: String, - params: BTreeMap, -} - -// The payload needs to meet this requirement in -// https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference?client_type=gtag#payload_post_body -#[derive(Debug, Serialize, Deserialize)] -struct TelemetryPayload { - client_id: String, - events: Vec, -} - -#[derive(Debug, Serialize, Deserialize)] -struct IpResponse { - ip: String, -} - -pub async fn send_telemetry_event(state: Arc, is_validator: bool) { - let git_rev = env!("CARGO_PKG_VERSION").to_string(); - let ip_address = get_ip().await; - let chain_identifier = match state.get_chain_identifier() { - Some(chain_identifier) => chain_identifier.to_string(), - None => "Unknown".to_string(), - }; - let since_the_epoch = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("Now should be later than epoch!"); - let telemetry_event = TelemetryEvent { - name: GA_EVENT_NAME.into(), - params: BTreeMap::from([ - ("chain_identifier".into(), chain_identifier), - ("node_address".into(), ip_address), - ( - "node_type".into(), - if is_validator { - "validator".into() - } else { - "full_node".into() - }, - ), - ("git_rev".into(), git_rev), - ( - "seconds_since_epoch".into(), - since_the_epoch.as_secs().to_string(), - ), - ]), - }; - - let telemetry_payload = TelemetryPayload { - client_id: HARDCODED_CLIENT_ID.into(), - events: vec![telemetry_event], - }; - - send_telemetry_event_impl(telemetry_payload).await -} - -async fn get_ip() -> String { - let resp = reqwest::get(IPLOOKUP_URL).await; - match resp { - Ok(json) => match json.json::().await { - Ok(ip_json) => ip_json.ip, - Err(_) => UNKNOWN_STRING.into(), - }, - Err(_) => UNKNOWN_STRING.into(), - } -} - -async fn send_telemetry_event_impl(telemetry_payload: TelemetryPayload) { - let client = reqwest::Client::new(); - let response_result = client - .post(format!( - "{}?&measurement_id={}&api_secret={}", - GA_URL, GA_MEASUREMENT_ID, GA_API_SECRET - )) - .json::(&telemetry_payload) - .send() - .await; - - match response_result { - Ok(response) => { - let status = response.status().as_u16(); - if (200..299).contains(&status) { - trace!("SUCCESS: Sent telemetry event: {:?}", &telemetry_payload,); - } else { - trace!( - "FAIL: Sending telemetry event failed with status: {} and response {:?}.", - response.status(), - response - ); - } - } - Err(error) => { - trace!( - "FAIL: Sending telemetry event failed with error: {:?}", - error - ); - } - } -} diff --git a/crates/sui-test-transaction-builder/Cargo.toml b/crates/sui-test-transaction-builder/Cargo.toml deleted file mode 100644 index bface31fc59..00000000000 --- a/crates/sui-test-transaction-builder/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "sui-test-transaction-builder" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -bcs.workspace = true - -shared-crypto.workspace = true -sui-genesis-builder.workspace = true -sui-move-build.workspace = true -sui-sdk.workspace = true -sui-types.workspace = true - -move-core-types.workspace = true diff --git a/crates/sui-test-transaction-builder/src/lib.rs b/crates/sui-test-transaction-builder/src/lib.rs deleted file mode 100644 index e4c4cb7194f..00000000000 --- a/crates/sui-test-transaction-builder/src/lib.rs +++ /dev/null @@ -1,671 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::path::PathBuf; - -use move_core_types::ident_str; -use shared_crypto::intent::{Intent, IntentMessage}; -use sui_genesis_builder::validator_info::GenesisValidatorMetadata; -use sui_move_build::{BuildConfig, CompiledPackage}; -use sui_sdk::{ - rpc_types::{ - get_new_package_obj_from_response, SuiTransactionBlockEffectsAPI, - SuiTransactionBlockResponse, - }, - wallet_context::WalletContext, -}; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress}, - crypto::{get_key_pair, AccountKeyPair, Signature, Signer}, - digests::TransactionDigest, - multisig::{BitmapUnit, MultiSig, MultiSigPublicKey}, - multisig_legacy::{MultiSigLegacy, MultiSigPublicKeyLegacy}, - object::Owner, - signature::GenericSignature, - sui_system_state::SUI_SYSTEM_MODULE_NAME, - transaction::{ - CallArg, ObjectArg, ProgrammableTransaction, Transaction, TransactionData, - DEFAULT_VALIDATOR_GAS_PRICE, TEST_ONLY_GAS_UNIT_FOR_HEAVY_COMPUTATION_STORAGE, - TEST_ONLY_GAS_UNIT_FOR_TRANSFER, - }, - TypeTag, SUI_SYSTEM_PACKAGE_ID, -}; - -pub struct TestTransactionBuilder { - test_data: TestTransactionData, - sender: SuiAddress, - gas_object: ObjectRef, - gas_price: u64, -} - -impl TestTransactionBuilder { - pub fn new(sender: SuiAddress, gas_object: ObjectRef, gas_price: u64) -> Self { - Self { - test_data: TestTransactionData::Empty, - sender, - gas_object, - gas_price, - } - } - - pub fn sender(&self) -> SuiAddress { - self.sender - } - - pub fn gas_object(&self) -> ObjectRef { - self.gas_object - } - - // Use `with_type_args` below to provide type args if any - pub fn move_call( - mut self, - package_id: ObjectID, - module: &'static str, - function: &'static str, - args: Vec, - ) -> Self { - assert!(matches!(self.test_data, TestTransactionData::Empty)); - self.test_data = TestTransactionData::Move(MoveData { - package_id, - module, - function, - args, - type_args: vec![], - }); - self - } - - pub fn with_type_args(mut self, type_args: Vec) -> Self { - if let TestTransactionData::Move(data) = &mut self.test_data { - assert!(data.type_args.is_empty()); - data.type_args = type_args; - } else { - panic!("Cannot set type args for non-move call"); - } - self - } - - pub fn call_counter_create(self, package_id: ObjectID) -> Self { - self.move_call(package_id, "counter", "create", vec![]) - } - - pub fn call_counter_increment( - self, - package_id: ObjectID, - counter_id: ObjectID, - counter_initial_shared_version: SequenceNumber, - ) -> Self { - self.move_call( - package_id, - "counter", - "increment", - vec![CallArg::Object(ObjectArg::SharedObject { - id: counter_id, - initial_shared_version: counter_initial_shared_version, - mutable: true, - })], - ) - } - - pub fn call_counter_read( - self, - package_id: ObjectID, - counter_id: ObjectID, - counter_initial_shared_version: SequenceNumber, - ) -> Self { - self.move_call( - package_id, - "counter", - "value", - vec![CallArg::Object(ObjectArg::SharedObject { - id: counter_id, - initial_shared_version: counter_initial_shared_version, - mutable: false, - })], - ) - } - - pub fn call_counter_delete( - self, - package_id: ObjectID, - counter_id: ObjectID, - counter_initial_shared_version: SequenceNumber, - ) -> Self { - self.move_call( - package_id, - "counter", - "delete", - vec![CallArg::Object(ObjectArg::SharedObject { - id: counter_id, - initial_shared_version: counter_initial_shared_version, - mutable: true, - })], - ) - } - - pub fn call_nft_create(self, package_id: ObjectID) -> Self { - self.move_call( - package_id, - "devnet_nft", - "mint", - vec![ - CallArg::Pure(bcs::to_bytes("example_nft_name").unwrap()), - CallArg::Pure(bcs::to_bytes("example_nft_description").unwrap()), - CallArg::Pure( - bcs::to_bytes("https://sui.io/_nuxt/img/sui-logo.8d3c44e.svg").unwrap(), - ), - ], - ) - } - - pub fn call_nft_delete(self, package_id: ObjectID, nft_to_delete: ObjectRef) -> Self { - self.move_call( - package_id, - "devnet_nft", - "burn", - vec![CallArg::Object(ObjectArg::ImmOrOwnedObject(nft_to_delete))], - ) - } - - pub fn call_staking(self, stake_coin: ObjectRef, validator: SuiAddress) -> Self { - self.move_call( - SUI_SYSTEM_PACKAGE_ID, - SUI_SYSTEM_MODULE_NAME.as_str(), - "request_add_stake", - vec![ - CallArg::SUI_SYSTEM_MUT, - CallArg::Object(ObjectArg::ImmOrOwnedObject(stake_coin)), - CallArg::Pure(bcs::to_bytes(&validator).unwrap()), - ], - ) - } - - pub fn call_request_add_validator(self) -> Self { - self.move_call( - SUI_SYSTEM_PACKAGE_ID, - SUI_SYSTEM_MODULE_NAME.as_str(), - "request_add_validator", - vec![CallArg::SUI_SYSTEM_MUT], - ) - } - - pub fn call_request_add_validator_candidate( - self, - validator: &GenesisValidatorMetadata, - ) -> Self { - self.move_call( - SUI_SYSTEM_PACKAGE_ID, - SUI_SYSTEM_MODULE_NAME.as_str(), - "request_add_validator_candidate", - vec![ - CallArg::SUI_SYSTEM_MUT, - CallArg::Pure(bcs::to_bytes(&validator.protocol_public_key).unwrap()), - CallArg::Pure(bcs::to_bytes(&validator.network_public_key).unwrap()), - CallArg::Pure(bcs::to_bytes(&validator.worker_public_key).unwrap()), - CallArg::Pure(bcs::to_bytes(&validator.proof_of_possession).unwrap()), - CallArg::Pure(bcs::to_bytes(validator.name.as_bytes()).unwrap()), - CallArg::Pure(bcs::to_bytes(validator.description.as_bytes()).unwrap()), - CallArg::Pure(bcs::to_bytes(validator.image_url.as_bytes()).unwrap()), - CallArg::Pure(bcs::to_bytes(validator.project_url.as_bytes()).unwrap()), - CallArg::Pure(bcs::to_bytes(&validator.network_address).unwrap()), - CallArg::Pure(bcs::to_bytes(&validator.p2p_address).unwrap()), - CallArg::Pure(bcs::to_bytes(&validator.primary_address).unwrap()), - CallArg::Pure(bcs::to_bytes(&validator.worker_address).unwrap()), - CallArg::Pure(bcs::to_bytes(&DEFAULT_VALIDATOR_GAS_PRICE).unwrap()), // gas_price - CallArg::Pure(bcs::to_bytes(&0u64).unwrap()), // commission_rate - ], - ) - } - - pub fn call_request_remove_validator(self) -> Self { - self.move_call( - SUI_SYSTEM_PACKAGE_ID, - SUI_SYSTEM_MODULE_NAME.as_str(), - "request_remove_validator", - vec![CallArg::SUI_SYSTEM_MUT], - ) - } - - pub fn transfer(mut self, object: ObjectRef, recipient: SuiAddress) -> Self { - self.test_data = TestTransactionData::Transfer(TransferData { object, recipient }); - self - } - - pub fn transfer_sui(mut self, amount: Option, recipient: SuiAddress) -> Self { - self.test_data = TestTransactionData::TransferSui(TransferSuiData { amount, recipient }); - self - } - - pub fn publish(mut self, path: PathBuf) -> Self { - assert!(matches!(self.test_data, TestTransactionData::Empty)); - self.test_data = TestTransactionData::Publish(PublishData::Source(path, false)); - self - } - - pub fn publish_with_deps(mut self, path: PathBuf) -> Self { - assert!(matches!(self.test_data, TestTransactionData::Empty)); - self.test_data = TestTransactionData::Publish(PublishData::Source(path, true)); - self - } - - pub fn publish_with_data(mut self, data: PublishData) -> Self { - assert!(matches!(self.test_data, TestTransactionData::Empty)); - self.test_data = TestTransactionData::Publish(data); - self - } - - pub fn publish_examples(self, subpath: &'static str) -> Self { - let path = if let Ok(p) = std::env::var("MOVE_EXAMPLES_DIR") { - let mut path = PathBuf::from(p); - path.extend([subpath]); - path - } else { - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - path.extend(["..", "..", "sui_programmability", "examples", subpath]); - path - }; - self.publish(path) - } - - pub fn programmable(mut self, programmable: ProgrammableTransaction) -> Self { - self.test_data = TestTransactionData::Programmable(programmable); - self - } - - pub fn build(self) -> TransactionData { - match self.test_data { - TestTransactionData::Move(data) => TransactionData::new_move_call( - self.sender, - data.package_id, - ident_str!(data.module).to_owned(), - ident_str!(data.function).to_owned(), - data.type_args, - self.gas_object, - data.args, - self.gas_price * TEST_ONLY_GAS_UNIT_FOR_HEAVY_COMPUTATION_STORAGE, - self.gas_price, - ) - .unwrap(), - TestTransactionData::Transfer(data) => TransactionData::new_transfer( - data.recipient, - data.object, - self.sender, - self.gas_object, - self.gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, - self.gas_price, - ), - TestTransactionData::TransferSui(data) => TransactionData::new_transfer_sui( - data.recipient, - self.sender, - data.amount, - self.gas_object, - self.gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, - self.gas_price, - ), - TestTransactionData::Publish(data) => { - let (all_module_bytes, dependencies) = match data { - PublishData::Source(path, with_unpublished_deps) => { - let compiled_package = BuildConfig::new_for_testing().build(path).unwrap(); - let all_module_bytes = - compiled_package.get_package_bytes(with_unpublished_deps); - let dependencies = compiled_package.get_dependency_original_package_ids(); - (all_module_bytes, dependencies) - } - PublishData::ModuleBytes(bytecode) => (bytecode, vec![]), - PublishData::CompiledPackage(compiled_package) => { - let all_module_bytes = compiled_package.get_package_bytes(false); - let dependencies = compiled_package.get_dependency_original_package_ids(); - (all_module_bytes, dependencies) - } - }; - - TransactionData::new_module( - self.sender, - self.gas_object, - all_module_bytes, - dependencies, - self.gas_price * TEST_ONLY_GAS_UNIT_FOR_HEAVY_COMPUTATION_STORAGE, - self.gas_price, - ) - } - TestTransactionData::Programmable(pt) => TransactionData::new_programmable( - self.sender, - vec![self.gas_object], - pt, - self.gas_price * TEST_ONLY_GAS_UNIT_FOR_HEAVY_COMPUTATION_STORAGE, - self.gas_price, - ), - TestTransactionData::Empty => { - panic!("Cannot build empty transaction"); - } - } - } - - pub fn build_and_sign(self, signer: &dyn Signer) -> Transaction { - Transaction::from_data_and_signer(self.build(), vec![signer]) - } - - pub fn build_and_sign_multisig( - self, - multisig_pk: MultiSigPublicKey, - signers: &[&dyn Signer], - bitmap: BitmapUnit, - ) -> Transaction { - let data = self.build(); - let intent_msg = IntentMessage::new(Intent::sui_transaction(), data.clone()); - - let mut signatures = Vec::with_capacity(signers.len()); - for signer in signers { - signatures.push( - GenericSignature::from(Signature::new_secure(&intent_msg, *signer)) - .to_compressed() - .unwrap(), - ); - } - - let multisig = - GenericSignature::MultiSig(MultiSig::insecure_new(signatures, bitmap, multisig_pk)); - - Transaction::from_generic_sig_data(data, vec![multisig]) - } - - pub fn build_and_sign_multisig_legacy( - self, - multisig_pk: MultiSigPublicKeyLegacy, - signers: &[&dyn Signer], - ) -> Transaction { - let data = self.build(); - let intent = Intent::sui_transaction(); - let intent_msg = IntentMessage::new(intent.clone(), data.clone()); - - let mut signatures = Vec::with_capacity(signers.len()); - for signer in signers { - signatures.push(Signature::new_secure(&intent_msg, *signer).into()); - } - - let multisig = GenericSignature::MultiSigLegacy( - MultiSigLegacy::combine(signatures, multisig_pk).unwrap(), - ); - - Transaction::from_generic_sig_data(data, vec![multisig]) - } -} - -enum TestTransactionData { - Move(MoveData), - Transfer(TransferData), - TransferSui(TransferSuiData), - Publish(PublishData), - Programmable(ProgrammableTransaction), - Empty, -} - -struct MoveData { - package_id: ObjectID, - module: &'static str, - function: &'static str, - args: Vec, - type_args: Vec, -} - -pub enum PublishData { - /// Path to source code directory and with_unpublished_deps. - /// with_unpublished_deps indicates whether to publish unpublished - /// dependencies in the same transaction or not. - Source(PathBuf, bool), - ModuleBytes(Vec>), - CompiledPackage(CompiledPackage), -} - -struct TransferData { - object: ObjectRef, - recipient: SuiAddress, -} - -struct TransferSuiData { - amount: Option, - recipient: SuiAddress, -} - -/// A helper function to make Transactions with controlled accounts in -/// WalletContext. Particularly, the wallet needs to own gas objects for -/// transactions. However, if this function is called multiple times without any -/// "sync" actions on gas object management, txns may fail and objects may be -/// locked. -/// -/// The param is called `max_txn_num` because it does not always return the -/// exact same amount of Transactions, for example when there are not enough gas -/// objects controlled by the WalletContext. Caller should rely on the return -/// value to check the count. -pub async fn batch_make_transfer_transactions( - context: &WalletContext, - max_txn_num: usize, -) -> Vec { - let recipient = get_key_pair::().0; - let accounts_and_objs = context.get_all_accounts_and_gas_objects().await.unwrap(); - let mut res = Vec::with_capacity(max_txn_num); - - let gas_price = context.get_reference_gas_price().await.unwrap(); - for (address, objs) in accounts_and_objs { - for obj in objs { - if res.len() >= max_txn_num { - return res; - } - let data = TransactionData::new_transfer_sui( - recipient, - address, - Some(2), - obj, - gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER, - gas_price, - ); - let tx = context.sign_transaction(&data); - res.push(tx); - } - } - res -} - -pub async fn make_transfer_sui_transaction( - context: &WalletContext, - recipient: Option, - amount: Option, -) -> Transaction { - let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); - let gas_price = context.get_reference_gas_price().await.unwrap(); - context.sign_transaction( - &TestTransactionBuilder::new(sender, gas_object, gas_price) - .transfer_sui(amount, recipient.unwrap_or(sender)) - .build(), - ) -} - -pub async fn make_staking_transaction( - context: &WalletContext, - validator_address: SuiAddress, -) -> Transaction { - let accounts_and_objs = context.get_all_accounts_and_gas_objects().await.unwrap(); - let sender = accounts_and_objs[0].0; - let gas_object = accounts_and_objs[0].1[0]; - let stake_object = accounts_and_objs[0].1[1]; - let gas_price = context.get_reference_gas_price().await.unwrap(); - context.sign_transaction( - &TestTransactionBuilder::new(sender, gas_object, gas_price) - .call_staking(stake_object, validator_address) - .build(), - ) -} - -pub async fn make_publish_transaction(context: &WalletContext, path: PathBuf) -> Transaction { - let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); - let gas_price = context.get_reference_gas_price().await.unwrap(); - context.sign_transaction( - &TestTransactionBuilder::new(sender, gas_object, gas_price) - .publish(path) - .build(), - ) -} - -pub async fn make_publish_transaction_with_deps( - context: &WalletContext, - path: PathBuf, -) -> Transaction { - let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); - let gas_price = context.get_reference_gas_price().await.unwrap(); - context.sign_transaction( - &TestTransactionBuilder::new(sender, gas_object, gas_price) - .publish_with_deps(path) - .build(), - ) -} - -pub async fn publish_package(context: &WalletContext, path: PathBuf) -> ObjectRef { - let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); - let gas_price = context.get_reference_gas_price().await.unwrap(); - let txn = context.sign_transaction( - &TestTransactionBuilder::new(sender, gas_object, gas_price) - .publish(path) - .build(), - ); - let resp = context.execute_transaction_must_succeed(txn).await; - get_new_package_obj_from_response(&resp).unwrap() -} - -/// Executes a transaction to publish the `basics` package and returns the -/// package object ref. -pub async fn publish_basics_package(context: &WalletContext) -> ObjectRef { - let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); - let gas_price = context.get_reference_gas_price().await.unwrap(); - let txn = context.sign_transaction( - &TestTransactionBuilder::new(sender, gas_object, gas_price) - .publish_examples("basics") - .build(), - ); - let resp = context.execute_transaction_must_succeed(txn).await; - get_new_package_obj_from_response(&resp).unwrap() -} - -/// Executes a transaction to publish the `basics` package and another one to -/// create a counter. Returns the package object ref and the counter object ref. -pub async fn publish_basics_package_and_make_counter( - context: &WalletContext, -) -> (ObjectRef, ObjectRef) { - let package_ref = publish_basics_package(context).await; - let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); - let gas_price = context.get_reference_gas_price().await.unwrap(); - let counter_creation_txn = context.sign_transaction( - &TestTransactionBuilder::new(sender, gas_object, gas_price) - .call_counter_create(package_ref.0) - .build(), - ); - let resp = context - .execute_transaction_must_succeed(counter_creation_txn) - .await; - let counter_ref = resp - .effects - .unwrap() - .created() - .iter() - .find(|obj_ref| matches!(obj_ref.owner, Owner::Shared { .. })) - .unwrap() - .reference - .to_object_ref(); - (package_ref, counter_ref) -} - -/// Executes a transaction to increment a counter object. -/// Must be called after calling `publish_basics_package_and_make_counter`. -pub async fn increment_counter( - context: &WalletContext, - sender: SuiAddress, - gas_object_id: Option, - package_id: ObjectID, - counter_id: ObjectID, - initial_shared_version: SequenceNumber, -) -> SuiTransactionBlockResponse { - let gas_object = if let Some(gas_object_id) = gas_object_id { - context.get_object_ref(gas_object_id).await.unwrap() - } else { - context - .get_one_gas_object_owned_by_address(sender) - .await - .unwrap() - .unwrap() - }; - let rgp = context.get_reference_gas_price().await.unwrap(); - let txn = context.sign_transaction( - &TestTransactionBuilder::new(sender, gas_object, rgp) - .call_counter_increment(package_id, counter_id, initial_shared_version) - .build(), - ); - context.execute_transaction_must_succeed(txn).await -} - -/// Executes a transaction to publish the `nfts` package and returns the package -/// id, id of the gas object used, and the digest of the transaction. -pub async fn publish_nfts_package( - context: &WalletContext, -) -> (ObjectID, ObjectID, TransactionDigest) { - let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); - let gas_id = gas_object.0; - let gas_price = context.get_reference_gas_price().await.unwrap(); - let txn = context.sign_transaction( - &TestTransactionBuilder::new(sender, gas_object, gas_price) - .publish_examples("nfts") - .build(), - ); - let resp = context.execute_transaction_must_succeed(txn).await; - let package_id = get_new_package_obj_from_response(&resp).unwrap().0; - (package_id, gas_id, resp.digest) -} - -/// Pre-requisite: `publish_nfts_package` must be called before this function. -/// Executes a transaction to create an NFT and returns the sender address, the -/// object id of the NFT, and the digest of the transaction. -pub async fn create_devnet_nft( - context: &WalletContext, - package_id: ObjectID, -) -> (SuiAddress, ObjectID, TransactionDigest) { - let (sender, gas_object) = context.get_one_gas_object().await.unwrap().unwrap(); - let rgp = context.get_reference_gas_price().await.unwrap(); - - let txn = context.sign_transaction( - &TestTransactionBuilder::new(sender, gas_object, rgp) - .call_nft_create(package_id) - .build(), - ); - let resp = context.execute_transaction_must_succeed(txn).await; - - let object_id = resp - .effects - .as_ref() - .unwrap() - .created() - .first() - .unwrap() - .reference - .object_id; - - (sender, object_id, resp.digest) -} - -/// Executes a transaction to delete the given NFT. -pub async fn delete_devnet_nft( - context: &WalletContext, - sender: SuiAddress, - package_id: ObjectID, - nft_to_delete: ObjectRef, -) -> SuiTransactionBlockResponse { - let gas = context - .get_one_gas_object_owned_by_address(sender) - .await - .unwrap() - .unwrap_or_else(|| panic!("Expect {sender} to have at least one gas object")); - let rgp = context.get_reference_gas_price().await.unwrap(); - let txn = context.sign_transaction( - &TestTransactionBuilder::new(sender, gas, rgp) - .call_nft_delete(package_id, nft_to_delete) - .build(), - ); - context.execute_transaction_must_succeed(txn).await -} diff --git a/crates/sui-test-validator/Cargo.toml b/crates/sui-test-validator/Cargo.toml deleted file mode 100644 index 9b2e11ec4e8..00000000000 --- a/crates/sui-test-validator/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "sui-test-validator" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -clap.workspace = true -tokio = { workspace = true, features = ["full"] } -axum.workspace = true -tower.workspace = true -tower-http.workspace = true -http.workspace = true -uuid.workspace = true - -sui-faucet.workspace = true -sui-cluster-test.workspace = true -telemetry-subscribers.workspace = true diff --git a/crates/sui-test-validator/README.md b/crates/sui-test-validator/README.md deleted file mode 100644 index 696b353a62d..00000000000 --- a/crates/sui-test-validator/README.md +++ /dev/null @@ -1,21 +0,0 @@ -The sui-test-validator starts a local network that includes a Sui Full node, a Sui validator, a Sui faucet and (optionally) -an indexer. - -## Guide - -Refer to [sui-local-network.md](../../docs/content/guides/developer/getting-started/local-network.mdx) - -## Experimental Feature - Running with Indexer - -**Note** Similar to the fullnode db, all state will be wiped upon restart - -1. Follow the [Prerequisites section](../../crates/sui-indexer/README.md#prerequisites) in the `sui-indexer` README to set up the postgresdb on your local machine -2. Make sure the `Posgresdb` starts on your local machine -3. run `RUST_LOG="consensus=off" ./target/debug/sui-test-validator --with-indexer` -4. To check your local db, if you use the default db url `postgres://postgres:postgres@localhost:5432/sui_indexer`, you can login to the `postgres` database and run `\dt` to show all tables. - -## Run with a persisted state -You can combine this with indexer runs as well to save a persisted state on local development. - -1. Generate a config to store db and genesis configs `sui genesis -f --with-faucet --working-dir=[some-directory]` -2. `sui-test-validator --config-dir [some-directory]` diff --git a/crates/sui-test-validator/src/main.rs b/crates/sui-test-validator/src/main.rs deleted file mode 100644 index e54cfed6a63..00000000000 --- a/crates/sui-test-validator/src/main.rs +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{net::SocketAddr, sync::Arc}; - -use anyhow::Result; -use axum::{ - extract::Path, - response::IntoResponse, - routing::{get, post}, - Extension, Json, Router, -}; -use clap::Parser; -use http::{Method, StatusCode}; -use sui_cluster_test::{ - cluster::{Cluster, LocalNewCluster}, - config::{ClusterTestOpt, Env}, - faucet::{FaucetClient, FaucetClientFactory}, -}; -use sui_faucet::{ - BatchFaucetResponse, BatchStatusFaucetResponse, FaucetError, FaucetRequest, FaucetResponse, - FixedAmountRequest, -}; -use tower::ServiceBuilder; -use tower_http::cors::{Any, CorsLayer}; -use uuid::Uuid; - -/// Start a Sui validator and fullnode for easy testing. -#[derive(Parser, Debug)] -#[clap(author, version, about, long_about = None)] -struct Args { - /// Config directory that will be used to store network config, node db, - /// keystore sui genesis -f --with-faucet generates a genesis config - /// that can be used to start this process. Example: sui-test-validator - /// --config-dir ~/.sui/sui_config We can use any config dir that is - /// generated by the sui genesis. - #[clap(short, long)] - config_dir: Option, - /// Port to start the Fullnode RPC server on - #[clap(long, default_value = "9000")] - fullnode_rpc_port: u16, - - /// Port to start the Sui faucet on - #[clap(long, default_value = "9123")] - faucet_port: u16, - - /// Host to start the GraphQl server on - #[clap(long, default_value = "127.0.0.1")] - graphql_host: String, - - /// Port to start the GraphQl server on - /// Explicitly setting this enables the server - #[clap(long)] - graphql_port: Option, - - /// Port to start the Indexer RPC server on - #[clap(long, default_value = "9124")] - indexer_rpc_port: u16, - - /// Port for the Indexer Postgres DB - /// 5432 is the default port for postgres on Mac - #[clap(long, default_value = "5432")] - pg_port: u16, - - /// Hostname for the Indexer Postgres DB - #[clap(long, default_value = "localhost")] - pg_host: String, - - /// DB name for the Indexer Postgres DB - #[clap(long, default_value = "sui_indexer")] - pg_db_name: String, - - /// DB username for the Indexer Postgres DB - #[clap(long, default_value = "postgres")] - pg_user: String, - - /// DB password for the Indexer Postgres DB - #[clap(long, default_value = "postgrespw")] - pg_password: String, - - /// The duration for epochs (defaults to one minute) - #[clap(long, default_value = "60000")] - epoch_duration_ms: u64, - - /// if we should run indexer - #[clap(long)] - pub with_indexer: bool, -} - -#[tokio::main] -async fn main() -> Result<()> { - let (_guard, _filter_handle) = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .init(); - - let args = Args::parse(); - let Args { - config_dir, - fullnode_rpc_port, - graphql_host, - graphql_port, - indexer_rpc_port, - pg_port, - pg_host, - pg_db_name, - pg_user, - pg_password, - epoch_duration_ms, - faucet_port, - with_indexer, - } = args; - - // We don't pass epoch duration if we have a genesis config. - let epoch_duration_ms = if config_dir.is_some() { - None - } else { - Some(epoch_duration_ms) - }; - - if graphql_port.is_none() { - println!("Graphql port not provided. Graphql service will not run.") - } - if !with_indexer { - println!("`with_indexer` flag unset. Indexer service will not run.") - } - - let cluster_config = ClusterTestOpt { - env: Env::NewLocal, - - fullnode_address: Some(format!("0.0.0.0:{}", fullnode_rpc_port)), - indexer_address: with_indexer.then_some(format!("0.0.0.0:{}", indexer_rpc_port)), - pg_address: Some(format!( - "postgres://{pg_user}:{pg_password}@{pg_host}:{pg_port}/{pg_db_name}" - )), - faucet_address: Some(format!("127.0.0.1:{}", faucet_port)), - epoch_duration_ms, - config_dir, - graphql_address: graphql_port.map(|p| format!("{}:{}", graphql_host, p)), - }; - - println!("Starting Sui validator with config: {:#?}", cluster_config); - let cluster = LocalNewCluster::start(&cluster_config).await?; - - println!("Fullnode RPC URL: {}", cluster.fullnode_url()); - - if with_indexer { - println!( - "Indexer RPC URL: {}", - cluster.indexer_url().clone().unwrap_or_default() - ); - } - - start_faucet(&cluster, faucet_port).await?; - - Ok(()) -} - -struct AppState { - faucet: Arc, -} - -async fn start_faucet(cluster: &LocalNewCluster, port: u16) -> Result<()> { - let faucet = FaucetClientFactory::new_from_cluster(cluster).await; - - let app_state = Arc::new(AppState { faucet }); - - let cors = CorsLayer::new() - .allow_methods(vec![Method::GET, Method::POST]) - .allow_headers(Any) - .allow_origin(Any); - - let app = Router::new() - .route("/", get(health)) - .route("/gas", post(faucet_request)) - .route("/v1/gas", post(faucet_batch_request)) - .route("/v1/status/:task_id", get(request_status)) - .layer( - ServiceBuilder::new() - .layer(cors) - .layer(Extension(app_state)) - .into_inner(), - ); - - let addr = SocketAddr::from(([0, 0, 0, 0], port)); - - println!("Faucet URL: http://{}", addr); - - axum::Server::bind(&addr) - .serve(app.into_make_service()) - .await?; - - Ok(()) -} - -/// basic handler that responds with a static string -async fn health() -> &'static str { - "OK" -} - -async fn faucet_request( - Extension(state): Extension>, - Json(payload): Json, -) -> impl IntoResponse { - let result = match payload { - FaucetRequest::FixedAmountRequest(FixedAmountRequest { recipient }) => { - state.faucet.request_sui_coins(recipient).await - } - _ => { - return ( - StatusCode::BAD_REQUEST, - Json(FaucetResponse::from(FaucetError::Internal( - "Input Error.".to_string(), - ))), - ); - } - }; - - if !result.transferred_gas_objects.is_empty() { - (StatusCode::CREATED, Json(result)) - } else { - (StatusCode::INTERNAL_SERVER_ERROR, Json(result)) - } -} - -async fn faucet_batch_request( - Extension(state): Extension>, - Json(payload): Json, -) -> impl IntoResponse { - let result = match payload { - FaucetRequest::FixedAmountRequest(FixedAmountRequest { recipient }) => { - state.faucet.batch_request_sui_coins(recipient).await - } - _ => { - return ( - StatusCode::BAD_REQUEST, - Json(BatchFaucetResponse::from(FaucetError::Internal( - "Input Error.".to_string(), - ))), - ); - } - }; - if result.task.is_some() { - (StatusCode::CREATED, Json(result)) - } else { - (StatusCode::INTERNAL_SERVER_ERROR, Json(result)) - } -} - -async fn request_status( - Extension(state): Extension>, - Path(id): Path, -) -> impl IntoResponse { - match Uuid::parse_str(&id) { - Ok(task_id) => { - let status = state.faucet.get_batch_send_status(task_id).await; - (StatusCode::CREATED, Json(status)) - } - Err(e) => ( - StatusCode::INTERNAL_SERVER_ERROR, - Json(BatchStatusFaucetResponse::from(FaucetError::Internal( - e.to_string(), - ))), - ), - } -} diff --git a/crates/sui-tls/Cargo.toml b/crates/sui-tls/Cargo.toml deleted file mode 100644 index 4f1eaea2447..00000000000 --- a/crates/sui-tls/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "sui-tls" -version = "0.0.0" -license = "Apache-2.0" -authors = ["Brandon Williams "] -description = "tools for rustls-based certificate generation and verification" -edition = "2021" -publish = false - -[dependencies] -anyhow.workspace = true -ed25519.workspace = true -pkcs8.workspace = true -rcgen.workspace = true -rustls.workspace = true -webpki.workspace = true -x509-parser.workspace = true - -fastcrypto.workspace = true - -# reqwest support -reqwest.workspace = true - -# Axum support -axum.workspace = true -axum-server.workspace = true -tokio-rustls.workspace = true -tower-layer.workspace = true -tokio.workspace = true - -[dev-dependencies] -rand.workspace = true diff --git a/crates/sui-tls/src/lib.rs b/crates/sui-tls/src/lib.rs deleted file mode 100644 index 71c4e3a4eab..00000000000 --- a/crates/sui-tls/src/lib.rs +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod acceptor; -mod certgen; -mod verifier; - -pub const SUI_VALIDATOR_SERVER_NAME: &str = "sui"; - -pub use acceptor::{TlsAcceptor, TlsConnectionInfo}; -pub use certgen::SelfSignedCertificate; -pub use rustls; -pub use verifier::{AllowAll, Allower, CertVerifier, HashSetAllow, ValidatorAllowlist}; - -#[cfg(test)] -mod tests { - use fastcrypto::{ed25519::Ed25519KeyPair, traits::KeyPair}; - use rustls::server::ClientCertVerifier; - - use super::*; - - #[test] - fn verify_allowall() { - let mut rng = rand::thread_rng(); - let allowed = Ed25519KeyPair::generate(&mut rng); - let disallowed = Ed25519KeyPair::generate(&mut rng); - let random_cert_bob = - SelfSignedCertificate::new(allowed.private(), SUI_VALIDATOR_SERVER_NAME); - let random_cert_alice = - SelfSignedCertificate::new(disallowed.private(), SUI_VALIDATOR_SERVER_NAME); - - let verifier = CertVerifier::new(AllowAll); - - // The bob passes validation - verifier - .verify_client_cert( - &random_cert_bob.rustls_certificate(), - &[], - std::time::SystemTime::now(), - ) - .unwrap(); - - // The alice passes validation - verifier - .verify_client_cert( - &random_cert_alice.rustls_certificate(), - &[], - std::time::SystemTime::now(), - ) - .unwrap(); - } - - #[test] - fn verify_hashset() { - let mut rng = rand::thread_rng(); - let allowed = Ed25519KeyPair::generate(&mut rng); - let disallowed = Ed25519KeyPair::generate(&mut rng); - - let allowed_public_key = allowed.public().to_owned(); - let allowed_cert = SelfSignedCertificate::new(allowed.private(), SUI_VALIDATOR_SERVER_NAME); - - let disallowed_cert = - SelfSignedCertificate::new(disallowed.private(), SUI_VALIDATOR_SERVER_NAME); - - let mut allowlist = HashSetAllow::new(); - let verifier = CertVerifier::new(allowlist.clone()); - - // Add our public key to the allower - allowlist - .inner_mut() - .write() - .unwrap() - .insert(allowed_public_key); - - // The allowed cert passes validation - verifier - .verify_client_cert( - &allowed_cert.rustls_certificate(), - &[], - std::time::SystemTime::now(), - ) - .unwrap(); - - // The disallowed cert fails validation - verifier - .verify_client_cert( - &disallowed_cert.rustls_certificate(), - &[], - std::time::SystemTime::now(), - ) - .unwrap_err(); - - // After removing the allowed public key from the set it now fails validation - allowlist.inner_mut().write().unwrap().clear(); - verifier - .verify_client_cert( - &allowed_cert.rustls_certificate(), - &[], - std::time::SystemTime::now(), - ) - .unwrap_err(); - } - - #[test] - fn invalid_server_name() { - let mut rng = rand::thread_rng(); - let keypair = Ed25519KeyPair::generate(&mut rng); - let public_key = keypair.public().to_owned(); - let cert = SelfSignedCertificate::new(keypair.private(), "not-sui"); - - let mut allowlist = HashSetAllow::new(); - let verifier = CertVerifier::new(allowlist.clone()); - - // Add our public key to the allower - allowlist.inner_mut().write().unwrap().insert(public_key); - - // Allowed public key but the server-name in the cert is not the required "sui" - verifier - .verify_client_cert( - &cert.rustls_certificate(), - &[], - std::time::SystemTime::now(), - ) - .unwrap_err(); - } - - #[tokio::test] - async fn axum_acceptor() { - use fastcrypto::{ed25519::Ed25519KeyPair, traits::KeyPair}; - - let mut rng = rand::thread_rng(); - let client_keypair = Ed25519KeyPair::generate(&mut rng); - let client_public_key = client_keypair.public().to_owned(); - let client_certificate = - SelfSignedCertificate::new(client_keypair.private(), SUI_VALIDATOR_SERVER_NAME); - let server_keypair = Ed25519KeyPair::generate(&mut rng); - let server_certificate = SelfSignedCertificate::new(server_keypair.private(), "localhost"); - - let client = reqwest::Client::builder() - .add_root_certificate(server_certificate.reqwest_certificate()) - .identity(client_certificate.reqwest_identity()) - .https_only(true) - .build() - .unwrap(); - - let mut allowlist = HashSetAllow::new(); - let tls_config = CertVerifier::new(allowlist.clone()) - .rustls_server_config( - vec![server_certificate.rustls_certificate()], - server_certificate.rustls_private_key(), - ) - .unwrap(); - - async fn handler(tls_info: axum::Extension) -> String { - tls_info.public_key().unwrap().to_string() - } - - let app = axum::Router::new().route("/", axum::routing::get(handler)); - let listener = std::net::TcpListener::bind("localhost:0").unwrap(); - let server_address = listener.local_addr().unwrap(); - let acceptor = TlsAcceptor::new(tls_config); - let _server = tokio::spawn(async move { - axum_server::Server::from_tcp(listener) - .acceptor(acceptor) - .serve(app.into_make_service()) - .await - .unwrap() - }); - - let server_url = format!("https://localhost:{}", server_address.port()); - // Client request is rejected because it isn't in the allowlist - client.get(&server_url).send().await.unwrap_err(); - - // Insert the client's public key into the allowlist and verify the request is - // successful - allowlist - .inner_mut() - .write() - .unwrap() - .insert(client_public_key.clone()); - - let res = client.get(&server_url).send().await.unwrap(); - let body = res.text().await.unwrap(); - assert_eq!(client_public_key.to_string(), body); - } -} diff --git a/crates/sui-tls/src/verifier.rs b/crates/sui-tls/src/verifier.rs deleted file mode 100644 index d79d7b3ee7a..00000000000 --- a/crates/sui-tls/src/verifier.rs +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::HashSet, - sync::{Arc, RwLock}, -}; - -use fastcrypto::{ed25519::Ed25519PublicKey, traits::ToFromBytes}; - -static SUPPORTED_SIG_ALGS: &[&webpki::SignatureAlgorithm] = &[&webpki::ED25519]; - -pub type ValidatorAllowlist = Arc>>; - -/// The Allower trait provides an interface for callers to inject decsions -/// whether to allow a cert to be verified or not. This does not prform actual -/// cert validation it only acts as a gatekeeper to decide if we should even -/// try. For example, we may want to filter our actions to well known public -/// keys. -pub trait Allower: Send + Sync { - fn allowed(&self, key: &Ed25519PublicKey) -> bool; -} - -/// AllowAll will allow all public certificates to be validated, it fails open -#[derive(Clone, Default)] -pub struct AllowAll; - -impl Allower for AllowAll { - fn allowed(&self, _: &Ed25519PublicKey) -> bool { - true - } -} - -/// HashSetAllow restricts keys to those that are found in the member set. -/// non-members will not be allowed. -#[derive(Clone, Default)] -pub struct HashSetAllow { - inner: ValidatorAllowlist, -} - -impl HashSetAllow { - pub fn new() -> Self { - let inner = Arc::new(RwLock::new(HashSet::new())); - Self { inner } - } - /// Get a reference to the inner service - pub fn inner(&self) -> &ValidatorAllowlist { - &self.inner - } - - /// Get a mutable reference to the inner service - pub fn inner_mut(&mut self) -> &mut ValidatorAllowlist { - &mut self.inner - } -} - -impl Allower for HashSetAllow { - fn allowed(&self, key: &Ed25519PublicKey) -> bool { - self.inner.read().unwrap().contains(key) - } -} - -/// A `rustls::server::ClientCertVerifier` that will ensure that every client -/// provides a valid, expected certificate and that the client's public key is -/// in the validator set. -#[derive(Clone, Debug)] -pub struct CertVerifier { - allower: A, -} - -impl CertVerifier { - pub fn new(allower: A) -> Self { - Self { allower } - } -} - -impl CertVerifier { - pub fn rustls_server_config( - self, - certificates: Vec, - private_key: rustls::PrivateKey, - ) -> Result { - let mut config = rustls::ServerConfig::builder() - .with_safe_defaults() - .with_client_cert_verifier(std::sync::Arc::new(self)) - .with_single_cert(certificates, private_key)?; - config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; - - Ok(config) - } -} - -impl rustls::server::ClientCertVerifier for CertVerifier { - fn offer_client_auth(&self) -> bool { - true - } - - fn client_auth_mandatory(&self) -> bool { - true - } - - fn client_auth_root_subjects(&self) -> &[rustls::DistinguishedName] { - // Since we're relying on self-signed certificates and not on CAs, continue the - // handshake without passing a list of CA DNs - &[] - } - - // Verifies this is a valid ed25519 self-signed certificate - // 1. we prepare arguments for webpki's certificate verification (following the - // rustls implementation) placing the public key at the root of the - // certificate chain (as it should be for a self-signed certificate) - // 2. we call webpki's certificate verification - fn verify_client_cert( - &self, - end_entity: &rustls::Certificate, - intermediates: &[rustls::Certificate], - now: std::time::SystemTime, - ) -> Result { - // Step 1: Check this matches the key we expect - let public_key = public_key_from_certificate(end_entity)?; - - if !self.allower.allowed(&public_key) { - return Err(rustls::Error::General(format!( - "invalid certificate: {:?} is not in the validator set", - public_key, - ))); - } - - // We now check we're receiving correctly signed data with the expected key - // Step 1: prepare arguments - let (cert, chain, trustroots) = prepare_for_self_signed(end_entity, intermediates)?; - let now = webpki::Time::try_from(now).map_err(|_| rustls::Error::FailedToGetCurrentTime)?; - - // Step 2: call verification from webpki - let cert = cert - .verify_for_usage( - SUPPORTED_SIG_ALGS, - &trustroots, - &chain, - now, - webpki::KeyUsage::client_auth(), - &[], - ) - .map_err(pki_error) - .map(|_| cert)?; - - // Ensure the cert is valid for the network name - let dns_nameref = - webpki::SubjectNameRef::try_from_ascii_str(crate::SUI_VALIDATOR_SERVER_NAME) - .map_err(|_| rustls::Error::UnsupportedNameType)?; - cert.verify_is_valid_for_subject_name(dns_nameref) - .map_err(pki_error) - .map(|_| rustls::server::ClientCertVerified::assertion()) - } -} - -type CertChainAndRoots<'a> = ( - webpki::EndEntityCert<'a>, - Vec<&'a [u8]>, - Vec>, -); - -// This prepares arguments for webpki, including a trust anchor which is the end -// entity of the certificate (which embodies a self-signed certificate by -// definition) -fn prepare_for_self_signed<'a>( - end_entity: &'a rustls::Certificate, - intermediates: &'a [rustls::Certificate], -) -> Result, rustls::Error> { - // EE cert must appear first. - let cert = webpki::EndEntityCert::try_from(end_entity.0.as_ref()).map_err(pki_error)?; - - let intermediates: Vec<&'a [u8]> = intermediates.iter().map(|cert| cert.0.as_ref()).collect(); - - // reinterpret the certificate as a root, materializing the self-signed policy - let root = webpki::TrustAnchor::try_from_cert_der(end_entity.0.as_ref()).map_err(pki_error)?; - - Ok((cert, intermediates, vec![root])) -} - -fn pki_error(error: webpki::Error) -> rustls::Error { - use webpki::Error::*; - match error { - BadDer | BadDerTime => { - rustls::Error::InvalidCertificate(rustls::CertificateError::BadEncoding) - } - InvalidSignatureForPublicKey - | UnsupportedSignatureAlgorithm - | UnsupportedSignatureAlgorithmForPublicKey => { - rustls::Error::InvalidCertificate(rustls::CertificateError::BadSignature) - } - e => rustls::Error::General(format!("invalid peer certificate: {e}")), - } -} - -pub(crate) fn public_key_from_certificate( - certificate: &rustls::Certificate, -) -> Result { - use x509_parser::{certificate::X509Certificate, prelude::FromDer}; - - let cert = X509Certificate::from_der(certificate.0.as_ref()) - .map_err(|e| rustls::Error::General(e.to_string()))?; - let spki = cert.1.public_key(); - let public_key_bytes = - ::from_public_key_der(spki.raw) - .map_err(|e| rustls::Error::General(format!("invalid ed25519 public key: {e}")))?; - - let public_key = Ed25519PublicKey::from_bytes(public_key_bytes.as_ref()) - .map_err(|e| rustls::Error::General(format!("invalid ed25519 public key: {e}")))?; - Ok(public_key) -} diff --git a/crates/sui-tool/Cargo.toml b/crates/sui-tool/Cargo.toml deleted file mode 100644 index 6ca6d54fbf1..00000000000 --- a/crates/sui-tool/Cargo.toml +++ /dev/null @@ -1,55 +0,0 @@ -[package] -name = "sui-tool" -version.workspace = true -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -num_cpus.workspace = true -bcs.workspace = true -clap = { version = "4.1.4", features = ["derive"] } -colored.workspace = true -comfy-table.workspace = true -diesel.workspace = true -eyre.workspace = true -futures.workspace = true -hex.workspace = true -move-core-types.workspace = true -itertools.workspace = true -rocksdb.workspace = true -ron.workspace = true -serde.workspace = true -serde_json.workspace = true -strum.workspace = true -strum_macros.workspace = true -tempfile.workspace = true -tracing.workspace = true -prometheus.workspace = true -object_store.workspace = true -indicatif.workspace = true - -anemo-cli.workspace = true -anemo.workspace = true -telemetry-subscribers.workspace = true -tokio = { workspace = true, features = ["full"] } -typed-store.workspace = true -fastcrypto.workspace = true - -narwhal-storage.workspace = true -narwhal-types.workspace = true -sui-config.workspace = true -sui-core.workspace = true -sui-indexer.workspace = true -sui-network.workspace = true -sui-snapshot.workspace = true -sui-protocol-config.workspace = true -sui-replay.workspace = true -sui-sdk.workspace = true -sui-storage.workspace = true -sui-types.workspace = true -sui-archival.workspace = true -git-version.workspace = true -const-str = "0.5.6" diff --git a/crates/sui-tool/README.md b/crates/sui-tool/README.md deleted file mode 100644 index d0d63b382a7..00000000000 --- a/crates/sui-tool/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# sui-tool - -`sui-tool` contains assorted debugging utilities for Sui. - -You can build and run `sui-tool` from source with: -```sh -cargo run --bin sui-tool -- -``` - -## `anemo` tools - -You can use the anemo CLI tools to ping or call an RPC on an Anemo server. Note that (for now) this uses randomly generated keys, so a server or method that restricts access to allowlisted peers will reject connections from this tool. - -Anemo networks are identified by a "server name" that the client must match. Server names you may want to use: -- Narwhal primary and worker: `narwhal` -- Sui discovery and state sync: `sui` - -### ping - -Example command to ping an anemo server: - -```sh -SERVER_NAME="sui"; \ -ADDRESS="1.2.3.4:5678"; \ -cargo run --bin sui-tool -- anemo ping --server-name "$SERVER_NAME" "$ADDRESS" -``` - -### call - -`sui-tool` has been preconfigured to support RPC calls using [RON (Rusty Object Notation)](https://crates.io/crates/ron) for the following servivces: -- Narwhal: `PrimaryToPrimary` and `WorkerToWorker` -- Sui: `Discovery` and `StateSync` - -Example command to send an RPC: - -```sh -SERVER_NAME="sui"; \ -ADDRESS="1.2.3.4:5678"; \ -SERVICE_NAME="StateSync"; \ -METHOD_NAME="GetCheckpointSummary"; \ -REQUEST="BySequenceNumber(123)"; \ -cargo run --bin sui-tool -- \ - anemo call --server-name "$SERVER_NAME" "$ADDRESS" "$SERVICE_NAME" "$METHOD_NAME" "$REQUEST" -``` diff --git a/crates/sui-tool/src/commands.rs b/crates/sui-tool/src/commands.rs deleted file mode 100644 index 0a0ef82d458..00000000000 --- a/crates/sui-tool/src/commands.rs +++ /dev/null @@ -1,990 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{env, path::PathBuf}; - -use anyhow::Result; -use clap::*; -use fastcrypto::encoding::Encoding; -use sui_archival::{read_manifest_as_json, write_manifest_from_json}; -use sui_config::{ - genesis::Genesis, - object_storage_config::{ObjectStoreConfig, ObjectStoreType}, - Config, -}; -use sui_core::{authority_aggregator::AuthorityAggregatorBuilder, authority_client::AuthorityAPI}; -use sui_protocol_config::Chain; -use sui_replay::{execute_replay_command, ReplayToolCommand}; -use sui_types::{ - base_types::*, - messages_checkpoint::{CheckpointRequest, CheckpointResponse, CheckpointSequenceNumber}, - object::Owner, - transaction::{SenderSignedData, Transaction}, -}; -use telemetry_subscribers::TracingHandle; - -use crate::{ - check_completed_snapshot, - db_tool::{execute_db_tool_command, print_db_all_tables, DbToolCommand}, - download_db_snapshot, download_formal_snapshot, dump_checkpoints_from_archive, - get_latest_available_epoch, get_object, get_transaction_block, make_clients, pkg_dump, - restore_from_db_checkpoint, verify_archive, verify_archive_by_checksum, ConciseObjectOutput, - GroupedObjectOutput, VerboseObjectOutput, -}; - -#[derive(Parser, Clone, ValueEnum)] -pub enum Verbosity { - Grouped, - Concise, - Verbose, -} -const GIT_REVISION: &str = { - if let Some(revision) = option_env!("GIT_REVISION") { - revision - } else { - let version = git_version::git_version!( - args = ["--always", "--abbrev=12", "--dirty", "--exclude", "*"], - fallback = "" - ); - - if version.is_empty() { - panic!("unable to query git revision"); - } - version - } -}; -const VERSION: &str = const_str::concat!(env!("CARGO_PKG_VERSION"), "-", GIT_REVISION); - -#[derive(Parser)] -#[command( - name = "sui-tool", - about = "Debugging utilities for sui", - rename_all = "kebab-case", - author, - version = VERSION, -)] -pub enum ToolCommand { - /// Fetch the same object from all validators - #[command(name = "fetch-object")] - FetchObject { - #[arg(long, help = "The object ID to fetch")] - id: ObjectID, - - #[arg(long, help = "Fetch object at a specific sequence")] - version: Option, - - #[arg( - long, - help = "Validator to fetch from - if not specified, all validators are queried" - )] - validator: Option, - - // At least one of genesis or fullnode_rpc_url must be provided - #[arg(long = "genesis")] - genesis: Option, - - // At least one of genesis or fullnode_rpc_url must be provided - // RPC address to provide the up-to-date committee info - #[arg(long = "fullnode-rpc-url")] - fullnode_rpc_url: Option, - - /// Concise mode groups responses by results. - /// prints tabular output suitable for processing with unix tools. For - /// instance, to quickly check that all validators agree on the history - /// of an object: ```text - /// $ sui-tool fetch-object --id - /// 0x260efde76ebccf57f4c5e951157f5c361cde822c \ --genesis - /// $HOME/.sui/sui_config/genesis.blob \ --verbosity - /// concise --concise-no-header ``` - #[arg( - value_enum, - long = "verbosity", - default_value = "grouped", - ignore_case = true - )] - verbosity: Verbosity, - - #[arg( - long = "concise-no-header", - help = "don't show header in concise output" - )] - concise_no_header: bool, - }, - - /// Fetch the effects association with transaction `digest` - #[command(name = "fetch-transaction")] - FetchTransaction { - // At least one of genesis or fullnode_rpc_url must be provided - #[arg(long = "genesis")] - genesis: Option, - - // At least one of genesis or fullnode_rpc_url must be provided - // RPC address to provide the up-to-date committee info - #[arg(long = "fullnode-rpc-url")] - fullnode_rpc_url: Option, - - #[arg(long, help = "The transaction ID to fetch")] - digest: TransactionDigest, - - /// If true, show the input transaction as well as the effects - #[arg(long = "show-tx")] - show_input_tx: bool, - }, - - /// Tool to read validator & node db. - #[command(name = "db-tool")] - DbTool { - /// Path of the DB to read - #[arg(long = "db-path")] - db_path: String, - #[command(subcommand)] - cmd: Option, - }, - - /// Tool to verify the archive store - #[command(name = "verify-archive")] - VerifyArchive { - #[arg(long = "genesis")] - genesis: PathBuf, - #[command(flatten)] - object_store_config: ObjectStoreConfig, - #[arg(default_value_t = 5)] - download_concurrency: usize, - }, - - /// Tool to print the archive manifest - #[command(name = "print-archive-manifest")] - PrintArchiveManifest { - #[command(flatten)] - object_store_config: ObjectStoreConfig, - }, - /// Tool to update the archive manifest - #[command(name = "update-archive-manifest")] - UpdateArchiveManifest { - #[command(flatten)] - object_store_config: ObjectStoreConfig, - #[arg(long = "archive-path")] - archive_json_path: PathBuf, - }, - /// Tool to verify the archive store by comparing file checksums - #[command(name = "verify-archive-from-checksums")] - VerifyArchiveByChecksum { - #[command(flatten)] - object_store_config: ObjectStoreConfig, - #[arg(default_value_t = 5)] - download_concurrency: usize, - }, - - /// Tool to print archive contents in checkpoint range - #[command(name = "dump-archive")] - DumpArchiveByChecksum { - #[command(flatten)] - object_store_config: ObjectStoreConfig, - #[arg(default_value_t = 0)] - start: u64, - end: u64, - #[arg(default_value_t = 80)] - max_content_length: usize, - }, - - /// Download all packages to the local filesystem from an indexer database. - /// Each package gets its own sub-directory, named for its ID on-chain, - /// containing two metadata files (linkage.json and origins.json) as - /// well as a file for every module it contains. Each module - /// file is named for its module name, with a .mv suffix, and contains Move - /// bytecode (suitable for passing into a disassembler). - #[command(name = "dump-packages")] - DumpPackages { - /// Connection information for the Indexer's Postgres DB. - #[clap(long, short)] - db_url: String, - - /// Path to a non-existent directory that can be created and filled with - /// package information. - #[clap(long, short)] - output_dir: PathBuf, - - /// If false (default), log level will be overridden to "off", and - /// output will be reduced to necessary status information. - #[clap(short, long = "verbose")] - verbose: bool, - }, - - #[command(name = "dump-validators")] - DumpValidators { - #[arg(long = "genesis")] - genesis: PathBuf, - - #[arg( - long = "concise", - help = "show concise output - name, protocol key and network address" - )] - concise: bool, - }, - - #[command(name = "dump-genesis")] - DumpGenesis { - #[arg(long = "genesis")] - genesis: PathBuf, - }, - - /// Fetch authenticated checkpoint information at a specific sequence - /// number. If sequence number is not specified, get the latest - /// authenticated checkpoint. - #[command(name = "fetch-checkpoint")] - FetchCheckpoint { - // At least one of genesis or fullnode_rpc_url must be provided - #[arg(long = "genesis")] - genesis: Option, - - // At least one of genesis or fullnode_rpc_url must be provided - // RPC address to provide the up-to-date committee info - #[arg(long = "fullnode-rpc-url")] - fullnode_rpc_url: Option, - - #[arg(long, help = "Fetch checkpoint at a specific sequence number")] - sequence_number: Option, - }, - - #[command(name = "anemo")] - Anemo { - #[command(next_help_heading = "foo", flatten)] - args: anemo_cli::Args, - }, - - #[command(name = "restore-db")] - RestoreFromDBCheckpoint { - #[arg(long = "config-path")] - config_path: PathBuf, - #[arg(long = "db-checkpoint-path")] - db_checkpoint_path: PathBuf, - }, - - #[clap( - name = "download-db-snapshot", - about = "Downloads the legacy database snapshot via cloud object store, outputs to local disk" - )] - DownloadDBSnapshot { - #[clap(long = "epoch")] - epoch: Option, - #[clap(long = "path", default_value = "/tmp")] - path: PathBuf, - /// skip downloading indexes dir - #[clap(long = "skip-indexes")] - skip_indexes: bool, - /// Number of parallel downloads to perform. Defaults to a reasonable - /// value based on number of available logical cores. - #[clap(long = "num-parallel-downloads")] - num_parallel_downloads: Option, - /// Network to download snapshot for. Defaults to "mainnet". - /// If `--snapshot-bucket` or `--archive-bucket` is not specified, - /// the value of this flag is used to construct default bucket names. - #[clap(long = "network", default_value = "mainnet")] - network: Chain, - /// Snapshot bucket name. If not specified, defaults are - /// based on value of `--network` flag. - #[clap(long = "snapshot-bucket")] - snapshot_bucket: Option, - /// Snapshot bucket type - #[clap( - long = "snapshot-bucket-type", - help = "Required if --no-sign-request is not set" - )] - snapshot_bucket_type: Option, - /// Path to snapshot directory on local filesystem. - /// Only applicable if `--snapshot-bucket-type` is "file". - #[clap( - long = "snapshot-path", - help = "only used for testing, when --snapshot-bucket-type=FILE" - )] - snapshot_path: Option, - /// If true, no authentication is needed for snapshot restores - #[clap( - long = "no-sign-request", - help = "if set, --snapshot-bucket and --snapshot-bucket-type are ignored" - )] - no_sign_request: bool, - /// Download snapshot of the latest available epoch. - /// If `--epoch` is specified, then this flag gets ignored. - #[clap(long = "latest")] - latest: bool, - /// If false (default), log level will be overridden to "off", - /// and output will be reduced to necessary status information. - #[clap(long = "verbose")] - verbose: bool, - }, - - // Restore from formal (slim, DB agnostic) snapshot. Note that this is only supported - /// for protocol versions supporting `commit_root_state_digest`. For - /// mainnet, this is epoch 20+, and for testnet this is epoch 12+ - #[clap( - name = "download-formal-snapshot", - about = "Downloads formal database snapshot via cloud object store, outputs to local disk" - )] - DownloadFormalSnapshot { - #[clap(long = "epoch")] - epoch: Option, - #[clap(long = "genesis")] - genesis: PathBuf, - #[clap(long = "path", default_value = "/tmp")] - path: PathBuf, - /// Number of parallel downloads to perform. Defaults to a reasonable - /// value based on number of available logical cores. - #[clap(long = "num-parallel-downloads")] - num_parallel_downloads: Option, - /// If true, perform snapshot and checkpoint summary verification. - /// Defaults to true. - #[clap(long = "verify")] - verify: Option, - /// Network to download snapshot for. Defaults to "mainnet". - /// If `--snapshot-bucket` or `--archive-bucket` is not specified, - /// the value of this flag is used to construct default bucket names. - #[clap(long = "network", default_value = "mainnet")] - network: Chain, - /// Snapshot bucket name. If not specified, defaults are - /// based on value of `--network` flag. - #[clap(long = "snapshot-bucket")] - snapshot_bucket: Option, - /// Snapshot bucket type - #[clap( - long = "snapshot-bucket-type", - help = "Required if --no-sign-request is not set" - )] - snapshot_bucket_type: Option, - /// Path to snapshot directory on local filesystem. - /// Only applicable if `--snapshot-bucket-type` is "file". - #[clap(long = "snapshot-path")] - snapshot_path: Option, - /// Archival bucket name. If not specified, defaults are - /// based on value of `--network` flag. - #[clap(long = "archive-bucket")] - archive_bucket: Option, - #[clap(long = "archive-bucket-type", default_value = "s3")] - archive_bucket_type: ObjectStoreType, - /// If true, no authentication is needed for snapshot restores - #[clap( - long = "no-sign-request", - help = "if set, --snapshot-bucket and --snapshot-bucket-type are ignored" - )] - no_sign_request: bool, - /// Download snapshot of the latest available epoch. - /// If `--epoch` is specified, then this flag gets ignored. - #[clap(long = "latest")] - latest: bool, - /// If false (default), log level will be overridden to "off", - /// and output will be reduced to necessary status information. - #[clap(long = "verbose")] - verbose: bool, - }, - - #[clap(name = "replay")] - Replay { - #[arg(long = "rpc")] - rpc_url: Option, - #[arg(long = "safety-checks")] - safety_checks: bool, - #[arg(long = "authority")] - use_authority: bool, - #[arg(long = "cfg-path", short)] - cfg_path: Option, - #[command(subcommand)] - cmd: ReplayToolCommand, - }, - - /// Ask all validators to sign a transaction through AuthorityAggregator. - #[command(name = "sign-transaction")] - SignTransaction { - #[arg(long = "genesis")] - genesis: PathBuf, - - #[arg( - long, - help = "The Base64-encoding of the bcs bytes of SenderSignedData" - )] - sender_signed_data: String, - }, -} - -trait OptionDebug { - fn opt_debug(&self, def_str: &str) -> String; -} -trait OptionDisplay { - fn opt_display(&self, def_str: &str) -> String; -} - -impl OptionDebug for Option -where - T: std::fmt::Debug, -{ - fn opt_debug(&self, def_str: &str) -> String { - match self { - None => def_str.to_string(), - Some(t) => format!("{:?}", t), - } - } -} - -impl OptionDisplay for Option -where - T: std::fmt::Display, -{ - fn opt_display(&self, def_str: &str) -> String { - match self { - None => def_str.to_string(), - Some(t) => format!("{}", t), - } - } -} - -struct OwnerOutput(Owner); - -// grep/awk-friendly output for Owner -impl std::fmt::Display for OwnerOutput { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &self.0 { - Owner::AddressOwner(address) => { - write!(f, "address({})", address) - } - Owner::ObjectOwner(address) => { - write!(f, "object({})", address) - } - Owner::Immutable => { - write!(f, "immutable") - } - Owner::Shared { .. } => { - write!(f, "shared") - } - } - } -} - -impl ToolCommand { - #[allow(clippy::format_in_format_args)] - pub async fn execute(self, tracing_handle: TracingHandle) -> Result<(), anyhow::Error> { - match self { - ToolCommand::FetchObject { - id, - validator, - genesis, - version, - fullnode_rpc_url, - verbosity, - concise_no_header, - } => { - let output = get_object(id, version, validator, genesis, fullnode_rpc_url).await?; - - match verbosity { - Verbosity::Grouped => { - println!("{}", GroupedObjectOutput(output)); - } - Verbosity::Verbose => { - println!("{}", VerboseObjectOutput(output)); - } - Verbosity::Concise => { - if !concise_no_header { - println!("{}", ConciseObjectOutput::header()); - } - println!("{}", ConciseObjectOutput(output)); - } - } - } - ToolCommand::FetchTransaction { - genesis, - digest, - show_input_tx, - fullnode_rpc_url, - } => { - print!( - "{}", - get_transaction_block(digest, genesis, show_input_tx, fullnode_rpc_url).await? - ); - } - ToolCommand::DbTool { db_path, cmd } => { - let path = PathBuf::from(db_path); - match cmd { - Some(c) => execute_db_tool_command(path, c).await?, - None => print_db_all_tables(path)?, - } - } - ToolCommand::DumpPackages { - db_url, - output_dir, - verbose, - } => { - if !verbose { - tracing_handle - .update_log("off") - .expect("Failed to update log level"); - } - - pkg_dump::dump(db_url, output_dir).await?; - } - ToolCommand::DumpValidators { genesis, concise } => { - let genesis = Genesis::load(genesis).unwrap(); - if !concise { - println!("{:#?}", genesis.validator_set_for_tooling()); - } else { - for (i, val_info) in genesis.validator_set_for_tooling().iter().enumerate() { - let metadata = val_info.verified_metadata(); - println!( - "#{:<2} {:<20} {:?} {:?} {}", - i, - metadata.name, - metadata.sui_pubkey_bytes().concise(), - metadata.net_address, - anemo::PeerId(metadata.network_pubkey.0.to_bytes()), - ) - } - } - } - ToolCommand::DumpGenesis { genesis } => { - let genesis = Genesis::load(genesis)?; - println!("{:#?}", genesis); - } - ToolCommand::FetchCheckpoint { - genesis, - sequence_number, - fullnode_rpc_url, - } => { - let clients = make_clients(genesis, fullnode_rpc_url).await?; - - for (name, (_, client)) in clients { - let resp = client - .handle_checkpoint(CheckpointRequest { - sequence_number, - request_content: true, - }) - .await - .unwrap(); - let CheckpointResponse { - checkpoint, - contents, - } = resp; - println!("Validator: {:?}\n", name.concise()); - println!("Checkpoint: {:?}\n", checkpoint); - println!("Content: {:?}\n", contents); - } - } - ToolCommand::Anemo { args } => { - let config = crate::make_anemo_config(); - anemo_cli::run(config, args).await - } - ToolCommand::RestoreFromDBCheckpoint { - config_path, - db_checkpoint_path, - } => { - let config = sui_config::NodeConfig::load(config_path)?; - restore_from_db_checkpoint(&config, &db_checkpoint_path).await?; - } - ToolCommand::DownloadFormalSnapshot { - epoch, - genesis, - path, - num_parallel_downloads, - verify, - network, - snapshot_bucket, - snapshot_bucket_type, - snapshot_path, - archive_bucket, - archive_bucket_type, - no_sign_request, - latest, - verbose, - } => { - if !verbose { - tracing_handle - .update_log("off") - .expect("Failed to update log level"); - } - let num_parallel_downloads = num_parallel_downloads.unwrap_or_else(|| { - num_cpus::get() - .checked_sub(1) - .expect("Failed to get number of CPUs") - }); - let snapshot_bucket = - snapshot_bucket.or_else(|| match (network, no_sign_request) { - (Chain::Mainnet, false) => Some( - env::var("MAINNET_FORMAL_SIGNED_BUCKET") - .unwrap_or("mysten-mainnet-formal".to_string()), - ), - (Chain::Mainnet, true) => env::var("MAINNET_FORMAL_UNSIGNED_BUCKET").ok(), - (Chain::Testnet, true) => env::var("TESTNET_FORMAL_UNSIGNED_BUCKET").ok(), - (Chain::Testnet, _) => Some( - env::var("TESTNET_FORMAL_SIGNED_BUCKET") - .unwrap_or("mysten-testnet-formal".to_string()), - ), - (Chain::Unknown, _) => { - panic!("Cannot generate default snapshot bucket for unknown network"); - } - }); - - let aws_endpoint = env::var("AWS_SNAPSHOT_ENDPOINT").ok().or_else(|| { - if no_sign_request { - if network == Chain::Mainnet { - Some("https://formal-snapshot.mainnet.sui.io".to_string()) - } else if network == Chain::Testnet { - Some("https://formal-snapshot.testnet.sui.io".to_string()) - } else { - None - } - } else { - None - } - }); - - let snapshot_bucket_type = if no_sign_request { - ObjectStoreType::S3 - } else { - snapshot_bucket_type - .expect("--snapshot-bucket-type must be set if not using --no-sign-request") - }; - let snapshot_store_config = match snapshot_bucket_type { - ObjectStoreType::S3 => ObjectStoreConfig { - object_store: Some(ObjectStoreType::S3), - bucket: snapshot_bucket.filter(|s| !s.is_empty()), - aws_access_key_id: env::var("AWS_SNAPSHOT_ACCESS_KEY_ID").ok(), - aws_secret_access_key: env::var("AWS_SNAPSHOT_SECRET_ACCESS_KEY").ok(), - aws_region: env::var("AWS_SNAPSHOT_REGION").ok(), - aws_endpoint: aws_endpoint.filter(|s| !s.is_empty()), - aws_virtual_hosted_style_request: env::var( - "AWS_SNAPSHOT_VIRTUAL_HOSTED_REQUESTS", - ) - .ok() - .and_then(|b| b.parse().ok()) - .unwrap_or(no_sign_request), - object_store_connection_limit: 200, - no_sign_request, - ..Default::default() - }, - ObjectStoreType::GCS => ObjectStoreConfig { - object_store: Some(ObjectStoreType::GCS), - bucket: snapshot_bucket, - google_service_account: env::var("GCS_SNAPSHOT_SERVICE_ACCOUNT_FILE_PATH") - .ok(), - object_store_connection_limit: 200, - no_sign_request, - ..Default::default() - }, - ObjectStoreType::Azure => ObjectStoreConfig { - object_store: Some(ObjectStoreType::Azure), - bucket: snapshot_bucket, - azure_storage_account: env::var("AZURE_SNAPSHOT_STORAGE_ACCOUNT").ok(), - azure_storage_access_key: env::var("AZURE_SNAPSHOT_STORAGE_ACCESS_KEY") - .ok(), - object_store_connection_limit: 200, - no_sign_request, - ..Default::default() - }, - ObjectStoreType::File => { - if snapshot_path.is_some() { - ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: snapshot_path, - ..Default::default() - } - } else { - panic!( - "--snapshot-path must be specified for --snapshot-bucket-type=file" - ); - } - } - }; - - let archive_bucket = archive_bucket.or_else(|| match network { - Chain::Mainnet => Some( - env::var("MAINNET_ARCHIVE_BUCKET") - .unwrap_or("mysten-mainnet-archives".to_string()), - ), - Chain::Testnet => Some( - env::var("TESTNET_ARCHIVE_BUCKET") - .unwrap_or("mysten-testnet-archives".to_string()), - ), - Chain::Unknown => { - panic!("Cannot generate default archive bucket for unknown network"); - } - }); - let aws_region = - Some(env::var("AWS_ARCHIVE_REGION").unwrap_or("us-west-2".to_string())); - let archive_store_config = match archive_bucket_type { - ObjectStoreType::S3 => ObjectStoreConfig { - object_store: Some(ObjectStoreType::S3), - bucket: archive_bucket.filter(|s| !s.is_empty()), - aws_access_key_id: env::var("AWS_ARCHIVE_ACCESS_KEY_ID").ok(), - aws_secret_access_key: env::var("AWS_ARCHIVE_SECRET_ACCESS_KEY").ok(), - aws_region: aws_region.filter(|s| !s.is_empty()), - aws_endpoint: env::var("AWS_ARCHIVE_ENDPOINT").ok(), - aws_virtual_hosted_style_request: env::var( - "AWS_ARCHIVE_VIRTUAL_HOSTED_REQUESTS", - ) - .ok() - .and_then(|b| b.parse().ok()) - .unwrap_or(false), - object_store_connection_limit: 200, - no_sign_request, - ..Default::default() - }, - ObjectStoreType::GCS => ObjectStoreConfig { - object_store: Some(ObjectStoreType::GCS), - bucket: archive_bucket, - google_service_account: env::var("GCS_ARCHIVE_SERVICE_ACCOUNT_FILE_PATH") - .ok(), - object_store_connection_limit: 200, - no_sign_request, - ..Default::default() - }, - ObjectStoreType::Azure => ObjectStoreConfig { - object_store: Some(ObjectStoreType::Azure), - bucket: archive_bucket, - azure_storage_account: env::var("AZURE_ARCHIVE_STORAGE_ACCOUNT").ok(), - azure_storage_access_key: env::var("AZURE_ARCHIVE_STORAGE_ACCESS_KEY").ok(), - object_store_connection_limit: 200, - no_sign_request, - ..Default::default() - }, - ObjectStoreType::File => { - panic!("Download from local filesystem is not supported") - } - }; - let latest_available_epoch = - latest.then_some(get_latest_available_epoch(&snapshot_store_config).await?); - let epoch_to_download = epoch.or(latest_available_epoch).expect( - "Either pass epoch with --epoch or use latest with --latest", - ); - - if let Err(e) = - check_completed_snapshot(&snapshot_store_config, epoch_to_download).await - { - panic!( - "Aborting snapshot restore: {}, snapshot may not be uploaded yet", - e - ); - } - - let verify = verify.unwrap_or(true); - download_formal_snapshot( - &path, - epoch_to_download, - &genesis, - snapshot_store_config, - archive_store_config, - num_parallel_downloads, - network, - verify, - ) - .await?; - } - ToolCommand::DownloadDBSnapshot { - epoch, - path, - skip_indexes, - num_parallel_downloads, - network, - snapshot_bucket, - snapshot_bucket_type, - snapshot_path, - no_sign_request, - latest, - verbose, - } => { - if !verbose { - tracing_handle - .update_log("off") - .expect("Failed to update log level"); - } - let num_parallel_downloads = num_parallel_downloads.unwrap_or_else(|| { - num_cpus::get() - .checked_sub(1) - .expect("Failed to get number of CPUs") - }); - let snapshot_bucket = - snapshot_bucket.or_else(|| match (network, no_sign_request) { - (Chain::Mainnet, false) => Some( - env::var("MAINNET_DB_SIGNED_BUCKET") - .unwrap_or("mysten-mainnet-snapshots".to_string()), - ), - (Chain::Mainnet, true) => env::var("MAINNET_DB_UNSIGNED_BUCKET").ok(), - (Chain::Testnet, true) => env::var("TESTNET_DB_UNSIGNED_BUCKET").ok(), - (Chain::Testnet, _) => Some( - env::var("TESTNET_DB_SIGNED_BUCKET") - .unwrap_or("mysten-testnet-snapshots".to_string()), - ), - (Chain::Unknown, _) => { - panic!("Cannot generate default snapshot bucket for unknown network"); - } - }); - - let aws_endpoint = env::var("AWS_SNAPSHOT_ENDPOINT").ok(); - let snapshot_bucket_type = if no_sign_request { - ObjectStoreType::S3 - } else { - snapshot_bucket_type - .expect("--snapshot-bucket-type must be set if not using --no-sign-request") - }; - let snapshot_store_config = if no_sign_request { - let aws_endpoint = env::var("AWS_SNAPSHOT_ENDPOINT").ok().or_else(|| { - if network == Chain::Mainnet { - Some("https://db-snapshot.mainnet.sui.io".to_string()) - } else if network == Chain::Testnet { - Some("https://db-snapshot.testnet.sui.io".to_string()) - } else { - None - } - }); - ObjectStoreConfig { - object_store: Some(ObjectStoreType::S3), - aws_endpoint: aws_endpoint.filter(|s| !s.is_empty()), - aws_virtual_hosted_style_request: env::var( - "AWS_SNAPSHOT_VIRTUAL_HOSTED_REQUESTS", - ) - .ok() - .and_then(|b| b.parse().ok()) - .unwrap_or(no_sign_request), - object_store_connection_limit: 200, - no_sign_request, - ..Default::default() - } - } else { - match snapshot_bucket_type { - ObjectStoreType::S3 => ObjectStoreConfig { - object_store: Some(ObjectStoreType::S3), - bucket: snapshot_bucket.filter(|s| !s.is_empty()), - aws_access_key_id: env::var("AWS_SNAPSHOT_ACCESS_KEY_ID").ok(), - aws_secret_access_key: env::var("AWS_SNAPSHOT_SECRET_ACCESS_KEY").ok(), - aws_region: env::var("AWS_SNAPSHOT_REGION").ok(), - aws_endpoint: aws_endpoint.filter(|s| !s.is_empty()), - aws_virtual_hosted_style_request: env::var( - "AWS_SNAPSHOT_VIRTUAL_HOSTED_REQUESTS", - ) - .ok() - .and_then(|b| b.parse().ok()) - .unwrap_or(no_sign_request), - object_store_connection_limit: 200, - no_sign_request, - ..Default::default() - }, - ObjectStoreType::GCS => ObjectStoreConfig { - object_store: Some(ObjectStoreType::GCS), - bucket: snapshot_bucket, - google_service_account: env::var( - "GCS_SNAPSHOT_SERVICE_ACCOUNT_FILE_PATH", - ) - .ok(), - google_project_id: env::var("GCS_SNAPSHOT_SERVICE_ACCOUNT_PROJECT_ID") - .ok(), - object_store_connection_limit: 200, - no_sign_request, - ..Default::default() - }, - ObjectStoreType::Azure => ObjectStoreConfig { - object_store: Some(ObjectStoreType::Azure), - bucket: snapshot_bucket, - azure_storage_account: env::var("AZURE_SNAPSHOT_STORAGE_ACCOUNT").ok(), - azure_storage_access_key: env::var("AZURE_SNAPSHOT_STORAGE_ACCESS_KEY") - .ok(), - object_store_connection_limit: 200, - no_sign_request, - ..Default::default() - }, - ObjectStoreType::File => { - if snapshot_path.is_some() { - ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: snapshot_path, - ..Default::default() - } - } else { - panic!( - "--snapshot-path must be specified for --snapshot-bucket-type=file" - ); - } - } - } - }; - - let latest_available_epoch = - latest.then_some(get_latest_available_epoch(&snapshot_store_config).await?); - let epoch_to_download = epoch.or(latest_available_epoch).expect( - "Either pass epoch with --epoch or use latest with --latest", - ); - - if let Err(e) = - check_completed_snapshot(&snapshot_store_config, epoch_to_download).await - { - panic!( - "Aborting snapshot restore: {}, snapshot may not be uploaded yet", - e - ); - } - download_db_snapshot( - &path, - epoch_to_download, - snapshot_store_config, - skip_indexes, - num_parallel_downloads, - ) - .await?; - } - ToolCommand::Replay { - rpc_url, - safety_checks, - cmd, - use_authority, - cfg_path, - } => { - execute_replay_command(rpc_url, safety_checks, use_authority, cfg_path, cmd) - .await?; - } - ToolCommand::VerifyArchive { - genesis, - object_store_config, - download_concurrency, - } => { - verify_archive(&genesis, object_store_config, download_concurrency, true).await?; - } - ToolCommand::PrintArchiveManifest { - object_store_config, - } => { - println!("{}", read_manifest_as_json(object_store_config).await?); - } - ToolCommand::UpdateArchiveManifest { - object_store_config, - archive_json_path, - } => { - write_manifest_from_json(object_store_config, archive_json_path).await?; - } - ToolCommand::VerifyArchiveByChecksum { - object_store_config, - download_concurrency, - } => { - verify_archive_by_checksum(object_store_config, download_concurrency).await?; - } - ToolCommand::DumpArchiveByChecksum { - object_store_config, - start, - end, - max_content_length, - } => { - dump_checkpoints_from_archive(object_store_config, start, end, max_content_length) - .await?; - } - ToolCommand::SignTransaction { - genesis, - sender_signed_data, - } => { - let genesis = Genesis::load(genesis)?; - let sender_signed_data = bcs::from_bytes::( - &fastcrypto::encoding::Base64::decode(sender_signed_data.as_str()).unwrap(), - ) - .unwrap(); - let transaction = Transaction::new(sender_signed_data); - let (agg, _) = AuthorityAggregatorBuilder::from_genesis(&genesis) - .build() - .unwrap(); - let result = agg.process_transaction(transaction).await; - println!("{:?}", result); - } - }; - Ok(()) - } -} diff --git a/crates/sui-tool/src/db_tool/mod.rs b/crates/sui-tool/src/db_tool/mod.rs deleted file mode 100644 index 7cb7717f78e..00000000000 --- a/crates/sui-tool/src/db_tool/mod.rs +++ /dev/null @@ -1,541 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::path::{Path, PathBuf}; - -use anyhow::{anyhow, bail}; -use clap::Parser; -use narwhal_storage::NodeStorage; -use sui_core::{ - authority::{ - authority_per_epoch_store::AuthorityEpochTables, - authority_store_tables::AuthorityPerpetualTables, - }, - checkpoints::CheckpointStore, -}; -use sui_types::{ - base_types::{EpochId, ObjectID}, - digests::{CheckpointContentsDigest, TransactionDigest}, - effects::TransactionEffectsAPI, - messages_checkpoint::{CheckpointDigest, CheckpointSequenceNumber}, - storage::ObjectStore, -}; -use typed_store::rocks::MetricConf; - -use self::{ - db_dump::{dump_table, duplicate_objects_summary, list_tables, table_summary, StoreName}, - index_search::{search_index, SearchRange}, -}; -use crate::db_tool::db_dump::{compact, print_table_metadata, prune_checkpoints, prune_objects}; -pub mod db_dump; -mod index_search; - -#[derive(Parser)] -#[command(rename_all = "kebab-case")] -pub enum DbToolCommand { - ListTables, - Dump(Options), - IndexSearchKeyRange(IndexSearchKeyRangeOptions), - IndexSearchCount(IndexSearchCountOptions), - TableSummary(Options), - DuplicatesSummary, - ListDBMetadata(Options), - PrintLastConsensusIndex, - PrintConsensusCommit(PrintConsensusCommitOptions), - PrintTransaction(PrintTransactionOptions), - PrintObject(PrintObjectOptions), - PrintCheckpoint(PrintCheckpointOptions), - PrintCheckpointContent(PrintCheckpointContentOptions), - ResetDB, - RewindCheckpointExecution(RewindCheckpointExecutionOptions), - Compact, - PruneObjects, - PruneCheckpoints, - SetCheckpointWatermark(SetCheckpointWatermarkOptions), -} - -#[derive(Parser)] -#[command(rename_all = "kebab-case")] -pub struct IndexSearchKeyRangeOptions { - #[arg(long = "table-name", short = 't')] - table_name: String, - #[arg(long = "start", short = 's')] - start: String, - #[arg(long = "end", short = 'e')] - end_key: String, -} - -#[derive(Parser)] -#[command(rename_all = "kebab-case")] -pub struct IndexSearchCountOptions { - #[arg(long = "table-name", short = 't')] - table_name: String, - #[arg(long = "start", short = 's')] - start: String, - #[arg(long = "count", short = 'c')] - count: u64, -} - -#[derive(Parser)] -#[command(rename_all = "kebab-case")] -pub struct Options { - /// The type of store to dump - #[arg(long = "store", short = 's', value_enum)] - store_name: StoreName, - /// The name of the table to dump - #[arg(long = "table-name", short = 't')] - table_name: String, - /// The size of page to dump. This is a u16 - #[arg(long = "page-size", short = 'p')] - page_size: u16, - /// The page number to dump - #[arg(long = "page-num", short = 'n')] - page_number: usize, - - // TODO: We should load this automatically from the system object in AuthorityPerpetualTables. - // This is very difficult to do right now because you can't share code between - // AuthorityPerpetualTables and AuthorityEpochTablesReadonly. - /// The epoch to use when loading AuthorityEpochTables. - #[arg(long = "epoch", short = 'e')] - epoch: Option, -} - -#[derive(Parser)] -#[command(rename_all = "kebab-case")] -pub struct PrintConsensusCommitOptions { - #[arg(long, help = "Sequence number of the consensus commit")] - seqnum: u64, -} - -#[derive(Parser)] -#[command(rename_all = "kebab-case")] -pub struct PrintTransactionOptions { - #[arg(long, help = "The transaction digest to print")] - digest: TransactionDigest, -} - -#[derive(Parser)] -#[command(rename_all = "kebab-case")] -pub struct PrintObjectOptions { - #[arg(long, help = "The object id to print")] - id: ObjectID, - #[arg(long, help = "The object version to print")] - version: Option, -} - -#[derive(Parser)] -#[command(rename_all = "kebab-case")] -pub struct PrintCheckpointOptions { - #[arg(long, help = "The checkpoint digest to print")] - digest: CheckpointDigest, -} - -#[derive(Parser)] -#[command(rename_all = "kebab-case")] -pub struct PrintCheckpointContentOptions { - #[arg( - long, - help = "The checkpoint content digest (NOT the checkpoint digest)" - )] - digest: CheckpointContentsDigest, -} - -#[derive(Parser)] -#[command(rename_all = "kebab-case")] -pub struct RemoveTransactionOptions { - #[arg(long, help = "The transaction digest to remove")] - digest: TransactionDigest, - - #[arg(long)] - confirm: bool, - - /// The epoch to use when loading AuthorityEpochTables. - /// Defaults to the current epoch. - #[arg(long = "epoch", short = 'e')] - epoch: Option, -} - -#[derive(Parser)] -#[command(rename_all = "kebab-case")] -pub struct RemoveObjectLockOptions { - #[arg(long, help = "The object ID to remove")] - id: ObjectID, - - #[arg(long, help = "The object version to remove")] - version: u64, - - #[arg(long)] - confirm: bool, -} - -#[derive(Parser)] -#[command(rename_all = "kebab-case")] -pub struct RewindCheckpointExecutionOptions { - #[arg(long = "epoch")] - epoch: EpochId, - - #[arg(long = "checkpoint-sequence-number")] - checkpoint_sequence_number: u64, -} - -#[derive(Parser)] -#[command(rename_all = "kebab-case")] -pub struct SetCheckpointWatermarkOptions { - #[arg(long)] - highest_verified: Option, - - #[arg(long)] - highest_synced: Option, -} - -pub async fn execute_db_tool_command(db_path: PathBuf, cmd: DbToolCommand) -> anyhow::Result<()> { - match cmd { - DbToolCommand::ListTables => print_db_all_tables(db_path), - DbToolCommand::Dump(d) => print_all_entries( - d.store_name, - d.epoch, - db_path, - &d.table_name, - d.page_size, - d.page_number, - ), - DbToolCommand::TableSummary(d) => { - print_db_table_summary(d.store_name, d.epoch, db_path, &d.table_name) - } - DbToolCommand::DuplicatesSummary => print_db_duplicates_summary(db_path), - DbToolCommand::ListDBMetadata(d) => { - print_table_metadata(d.store_name, d.epoch, db_path, &d.table_name) - } - DbToolCommand::PrintLastConsensusIndex => print_last_consensus_index(&db_path), - DbToolCommand::PrintConsensusCommit(d) => print_consensus_commit(&db_path, d), - DbToolCommand::PrintTransaction(d) => print_transaction(&db_path, d), - DbToolCommand::PrintObject(o) => print_object(&db_path, o), - DbToolCommand::PrintCheckpoint(d) => print_checkpoint(&db_path, d), - DbToolCommand::PrintCheckpointContent(d) => print_checkpoint_content(&db_path, d), - DbToolCommand::ResetDB => reset_db_to_genesis(&db_path), - DbToolCommand::RewindCheckpointExecution(d) => { - rewind_checkpoint_execution(&db_path, d.epoch, d.checkpoint_sequence_number) - } - DbToolCommand::Compact => compact(db_path), - DbToolCommand::PruneObjects => prune_objects(db_path).await, - DbToolCommand::PruneCheckpoints => prune_checkpoints(db_path).await, - DbToolCommand::IndexSearchKeyRange(rg) => { - let res = search_index( - db_path, - rg.table_name, - rg.start, - SearchRange::ExclusiveLastKey(rg.end_key), - )?; - for (k, v) in res { - println!("{}: {}", k, v); - } - Ok(()) - } - DbToolCommand::IndexSearchCount(sc) => { - let res = search_index( - db_path, - sc.table_name, - sc.start, - SearchRange::Count(sc.count), - )?; - for (k, v) in res { - println!("{}: {}", k, v); - } - Ok(()) - } - DbToolCommand::SetCheckpointWatermark(d) => set_checkpoint_watermark(&db_path, d), - } -} - -pub fn print_db_all_tables(db_path: PathBuf) -> anyhow::Result<()> { - list_tables(db_path)?.iter().for_each(|t| println!("{}", t)); - Ok(()) -} - -pub fn print_db_duplicates_summary(db_path: PathBuf) -> anyhow::Result<()> { - let (total_count, duplicate_count, total_bytes, duplicated_bytes) = - duplicate_objects_summary(db_path); - println!( - "Total objects = {}, duplicated objects = {}, total bytes = {}, duplicated bytes = {}", - total_count, duplicate_count, total_bytes, duplicated_bytes - ); - Ok(()) -} - -pub fn print_last_consensus_index(path: &Path) -> anyhow::Result<()> { - let epoch_tables = AuthorityEpochTables::open_tables_read_write( - path.to_path_buf(), - MetricConf::default(), - None, - None, - ); - let last_index = epoch_tables.get_last_consensus_index()?; - println!("Last consensus index is {:?}", last_index); - Ok(()) -} - -pub fn print_consensus_commit(path: &Path, opt: PrintConsensusCommitOptions) -> anyhow::Result<()> { - let consensus_db = NodeStorage::reopen(path, None); - let consensus_commit = consensus_db - .consensus_store - .read_consensus_commit(&opt.seqnum)?; - match consensus_commit { - Some(commit) => println!("Consensus commit at {} is {:?}", opt.seqnum, commit), - None => println!("Consensus commit at {} is not found!", opt.seqnum), - } - Ok(()) -} - -pub fn print_transaction(path: &Path, opt: PrintTransactionOptions) -> anyhow::Result<()> { - let perpetual_db = AuthorityPerpetualTables::open(&path.join("store"), None); - if let Some((epoch, checkpoint_seq_num)) = - perpetual_db.get_checkpoint_sequence_number(&opt.digest)? - { - println!( - "Transaction {:?} executed in epoch {} checkpoint {}", - opt.digest, epoch, checkpoint_seq_num - ); - }; - if let Some(effects) = perpetual_db.get_effects(&opt.digest)? { - println!( - "Transaction {:?} dependencies: {:#?}", - opt.digest, - effects.dependencies(), - ); - }; - Ok(()) -} - -pub fn print_object(path: &Path, opt: PrintObjectOptions) -> anyhow::Result<()> { - let perpetual_db = AuthorityPerpetualTables::open(&path.join("store"), None); - - let obj = if let Some(version) = opt.version { - perpetual_db.get_object_by_key(&opt.id, version.into())? - } else { - perpetual_db.get_object(&opt.id)? - }; - - if let Some(obj) = obj { - println!("Object {:?}:\n{:#?}", opt.id, obj); - } else { - println!("Object {:?} not found", opt.id); - } - - Ok(()) -} - -pub fn print_checkpoint(path: &Path, opt: PrintCheckpointOptions) -> anyhow::Result<()> { - let checkpoint_store = CheckpointStore::new(&path.join("checkpoints")); - let checkpoint = checkpoint_store - .get_checkpoint_by_digest(&opt.digest)? - .ok_or(anyhow!( - "Checkpoint digest {:?} not found in checkpoint store", - opt.digest - ))?; - println!("Checkpoint: {:?}", checkpoint); - drop(checkpoint_store); - print_checkpoint_content( - path, - PrintCheckpointContentOptions { - digest: checkpoint.content_digest, - }, - ) -} - -pub fn print_checkpoint_content( - path: &Path, - opt: PrintCheckpointContentOptions, -) -> anyhow::Result<()> { - let checkpoint_store = CheckpointStore::new(&path.join("checkpoints")); - let contents = checkpoint_store - .get_checkpoint_contents(&opt.digest)? - .ok_or(anyhow!( - "Checkpoint content digest {:?} not found in checkpoint store", - opt.digest - ))?; - println!("Checkpoint content: {:?}", contents); - Ok(()) -} - -pub fn reset_db_to_genesis(path: &Path) -> anyhow::Result<()> { - // Follow the below steps to test: - // - // Get a db snapshot. Either generate one by running stress locally and enabling - // db checkpoints or download one from S3 bucket (pretty big in size though). - // Download the snapshot for the epoch you want to restore to the local disk. - // You will find one snapshot per epoch in the S3 bucket. We need to place the - // snapshot in the dir where config is pointing to. If db-config in - // fullnode.yaml is /opt/sui/db/authorities_db and we want to restore from epoch - // 10, we want to copy the snapshot to /opt/sui/db/authorities_dblike this: - // aws s3 cp s3://myBucket/dir /opt/sui/db/authorities_db/ --recursive —exclude - // “*” —include “epoch_10*” Mark downloaded snapshot as live: mv - // /opt/sui/db/authorities_db/epoch_10 /opt/sui/db/authorities_db/live - // Reset the downloaded db to execute from genesis with: cargo run --package - // sui-tool -- db-tool --db-path /opt/sui/db/authorities_db/live reset-db - // Start the sui full node: cargo run --release --bin sui-node -- --config-path - // ~/db_checkpoints/fullnode.yaml A sample fullnode.yaml config would be: - // --- - // db-path: /opt/sui/db/authorities_db - // network-address: /ip4/0.0.0.0/tcp/8080/http - // json-rpc-address: "0.0.0.0:9000" - // websocket-address: "0.0.0.0:9001" - // metrics-address: "0.0.0.0:9184" - // admin-interface-port: 1337 - // enable-event-processing: true - // grpc-load-shed: ~ - // grpc-concurrency-limit: ~ - // p2p-config: - // listen-address: "0.0.0.0:8084" - // genesis: - // genesis-file-location: - // authority-store-pruning-config: - // num-latest-epoch-dbs-to-retain: 3 - // epoch-db-pruning-period-secs: 3600 - // num-epochs-to-retain: 18446744073709551615 - // max-checkpoints-in-batch: 10 - // max-transactions-in-batch: 1000 - let perpetual_db = AuthorityPerpetualTables::open_tables_read_write( - path.join("store").join("perpetual"), - MetricConf::default(), - None, - None, - ); - perpetual_db.reset_db_for_execution_since_genesis()?; - - let checkpoint_db = CheckpointStore::open_tables_read_write( - path.join("checkpoints"), - MetricConf::default(), - None, - None, - ); - checkpoint_db.reset_db_for_execution_since_genesis()?; - - let epoch_db = AuthorityEpochTables::open_tables_read_write( - path.join("store"), - MetricConf::default(), - None, - None, - ); - epoch_db.reset_db_for_execution_since_genesis()?; - - Ok(()) -} - -/// Force sets the highest executed checkpoint. -/// NOTE: Does not force re-execution of transactions. -/// Run with: cargo run --package sui-tool -- db-tool --db-path -/// /opt/sui/db/authorities_db/live rewind-checkpoint-execution --epoch 3 -/// --checkpoint-sequence-number 300000 -pub fn rewind_checkpoint_execution( - path: &Path, - epoch: EpochId, - checkpoint_sequence_number: u64, -) -> anyhow::Result<()> { - let checkpoint_db = CheckpointStore::open_tables_read_write( - path.join("checkpoints"), - MetricConf::default(), - None, - None, - ); - let Some(checkpoint) = - checkpoint_db.get_checkpoint_by_sequence_number(checkpoint_sequence_number)? - else { - bail!("Checkpoint {checkpoint_sequence_number} not found!"); - }; - if epoch != checkpoint.epoch() { - bail!( - "Checkpoint {checkpoint_sequence_number} is in epoch {} not {epoch}!", - checkpoint.epoch() - ); - } - let highest_executed_sequence_number = checkpoint_db - .get_highest_executed_checkpoint_seq_number()? - .unwrap_or_default(); - if checkpoint_sequence_number > highest_executed_sequence_number { - bail!( - "Must rewind checkpoint execution to be not later than highest executed ({} > {})!", - checkpoint_sequence_number, - highest_executed_sequence_number - ); - } - checkpoint_db.set_highest_executed_checkpoint_subtle(&checkpoint)?; - Ok(()) -} - -pub fn print_db_table_summary( - store: StoreName, - epoch: Option, - path: PathBuf, - table_name: &str, -) -> anyhow::Result<()> { - let summary = table_summary(store, epoch, path, table_name)?; - let quantiles = [25, 50, 75, 90, 99]; - println!( - "Total num keys = {}, total key bytes = {}, total value bytes = {}", - summary.num_keys, summary.key_bytes_total, summary.value_bytes_total - ); - println!("Key size distribution:\n"); - quantiles.iter().for_each(|q| { - println!( - "p{:?} -> {:?} bytes\n", - q, - summary.key_hist.value_at_quantile(*q as f64 / 100.0) - ); - }); - println!("Value size distribution:\n"); - quantiles.iter().for_each(|q| { - println!( - "p{:?} -> {:?} bytes\n", - q, - summary.value_hist.value_at_quantile(*q as f64 / 100.0) - ); - }); - Ok(()) -} - -pub fn print_all_entries( - store: StoreName, - epoch: Option, - path: PathBuf, - table_name: &str, - page_size: u16, - page_number: usize, -) -> anyhow::Result<()> { - for (k, v) in dump_table(store, epoch, path, table_name, page_size, page_number)? { - println!("{:>100?}: {:?}", k, v); - } - Ok(()) -} - -/// Force sets state sync checkpoint watermarks. -/// Run with (for example): -/// cargo run --package sui-tool -- db-tool --db-path -/// /opt/sui/db/authorities_db/live set_checkpoint_watermark --highest-synced -/// 300000 -pub fn set_checkpoint_watermark( - path: &Path, - options: SetCheckpointWatermarkOptions, -) -> anyhow::Result<()> { - let checkpoint_db = CheckpointStore::open_tables_read_write( - path.join("checkpoints"), - MetricConf::default(), - None, - None, - ); - - if let Some(highest_verified) = options.highest_verified { - let Some(checkpoint) = checkpoint_db.get_checkpoint_by_sequence_number(highest_verified)? - else { - bail!("Checkpoint {highest_verified} not found"); - }; - checkpoint_db.update_highest_verified_checkpoint(&checkpoint)?; - } - if let Some(highest_synced) = options.highest_synced { - let Some(checkpoint) = checkpoint_db.get_checkpoint_by_sequence_number(highest_synced)? - else { - bail!("Checkpoint {highest_synced} not found"); - }; - checkpoint_db.update_highest_synced_checkpoint(&checkpoint)?; - } - Ok(()) -} diff --git a/crates/sui-tool/src/lib.rs b/crates/sui-tool/src/lib.rs deleted file mode 100644 index 251414aa771..00000000000 --- a/crates/sui-tool/src/lib.rs +++ /dev/null @@ -1,1196 +0,0 @@ -// Copyright (c) 2021, Facebook, Inc. and its affiliates -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::BTreeMap, - fmt::Write, - fs, io, - num::NonZeroUsize, - ops::Range, - path::{Path, PathBuf}, - sync::{ - atomic::{AtomicU64, AtomicUsize, Ordering}, - Arc, - }, - time::Duration, -}; - -use anyhow::{anyhow, Result}; -use eyre::ContextCompat; -use fastcrypto::{hash::MultisetHash, traits::ToFromBytes}; -use futures::{ - future::{join_all, AbortHandle}, - StreamExt, TryStreamExt, -}; -use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; -use itertools::Itertools; -use prometheus::Registry; -use sui_archival::{ - reader::{ArchiveReader, ArchiveReaderMetrics}, - verify_archive_with_checksums, verify_archive_with_genesis_config, -}; -use sui_config::{ - genesis::Genesis, - node::ArchiveReaderConfig, - object_storage_config::{ObjectStoreConfig, ObjectStoreType}, - NodeConfig, -}; -use sui_core::{ - authority::{authority_store_tables::AuthorityPerpetualTables, AuthorityStore}, - authority_client::{AuthorityAPI, NetworkAuthorityClient}, - checkpoints::CheckpointStore, - epoch::committee_store::CommitteeStore, - execution_cache::ExecutionCache, - storage::RocksDbStore, -}; -use sui_network::default_mysten_network_config; -use sui_protocol_config::Chain; -use sui_sdk::SuiClientBuilder; -use sui_snapshot::{reader::StateSnapshotReaderV1, setup_db_state}; -use sui_storage::{ - object_store::{ - http::HttpDownloaderBuilder, - util::{copy_file, exists, get_path, Manifest, PerEpochManifest, MANIFEST_FILENAME}, - ObjectStoreGetExt, - }, - verify_checkpoint_range, -}; -use sui_types::{ - accumulator::Accumulator, - base_types::*, - crypto::AuthorityPublicKeyBytes, - messages_checkpoint::{CheckpointCommitment, ECMHLiveObjectSetDigest}, - messages_grpc::{ - LayoutGenerationOption, ObjectInfoRequest, ObjectInfoRequestKind, ObjectInfoResponse, - TransactionInfoRequest, TransactionStatus, - }, - multiaddr::Multiaddr, - object::Owner, - storage::{ReadStore, SharedInMemoryStore}, -}; -use tokio::{sync::mpsc, task::JoinHandle, time::Instant}; -use tracing::info; -use typed_store::rocks::MetricConf; - -pub mod commands; -pub mod db_tool; -pub mod pkg_dump; - -// This functions requires at least one of genesis or fullnode_rpc to be `Some`. -async fn make_clients( - genesis: Option, - fullnode_rpc: Option, -) -> Result> { - let mut net_config = default_mysten_network_config(); - net_config.connect_timeout = Some(Duration::from_secs(5)); - let mut authority_clients = BTreeMap::new(); - - if let Some(fullnode_rpc) = fullnode_rpc { - let sui_client = SuiClientBuilder::default().build(fullnode_rpc).await?; - let active_validators = sui_client - .governance_api() - .get_latest_sui_system_state() - .await? - .active_validators; - - for validator in active_validators { - let net_addr = Multiaddr::try_from(validator.net_address).unwrap(); - let channel = net_config - .connect_lazy(&net_addr) - .map_err(|err| anyhow!(err.to_string()))?; - let client = NetworkAuthorityClient::new(channel); - let public_key_bytes = - AuthorityPublicKeyBytes::from_bytes(&validator.protocol_pubkey_bytes)?; - authority_clients.insert(public_key_bytes, (net_addr.clone(), client)); - } - } else { - if genesis.is_none() { - return Err(anyhow!("Either genesis or fullnode_rpc must be specified")); - } - let genesis = Genesis::load(genesis.unwrap())?; - for validator in genesis.validator_set_for_tooling() { - let metadata = validator.verified_metadata(); - let channel = net_config - .connect_lazy(&metadata.net_address) - .map_err(|err| anyhow!(err.to_string()))?; - let client = NetworkAuthorityClient::new(channel); - let public_key_bytes = metadata.sui_pubkey_bytes(); - authority_clients.insert(public_key_bytes, (metadata.net_address.clone(), client)); - } - } - - Ok(authority_clients) -} - -type ObjectVersionResponses = Vec<(Option, Result, f64)>; -pub struct ObjectData { - requested_id: ObjectID, - responses: Vec<(AuthorityName, Multiaddr, ObjectVersionResponses)>, -} - -trait OptionDebug { - fn opt_debug(&self, def_str: &str) -> String; -} -trait OptionDisplay { - fn opt_display(&self, def_str: &str) -> String; -} - -impl OptionDebug for Option -where - T: std::fmt::Debug, -{ - fn opt_debug(&self, def_str: &str) -> String { - match self { - None => def_str.to_string(), - Some(t) => format!("{:?}", t), - } - } -} - -impl OptionDisplay for Option -where - T: std::fmt::Display, -{ - fn opt_display(&self, def_str: &str) -> String { - match self { - None => def_str.to_string(), - Some(t) => format!("{}", t), - } - } -} - -struct OwnerOutput(Owner); - -// grep/awk-friendly output for Owner -impl std::fmt::Display for OwnerOutput { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &self.0 { - Owner::AddressOwner(address) => { - write!(f, "address({})", address) - } - Owner::ObjectOwner(address) => { - write!(f, "object({})", address) - } - Owner::Immutable => { - write!(f, "immutable") - } - Owner::Shared { .. } => { - write!(f, "shared") - } - } - } -} - -pub struct GroupedObjectOutput(pub ObjectData); - -#[allow(clippy::format_in_format_args)] -impl std::fmt::Display for GroupedObjectOutput { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let responses = self - .0 - .responses - .iter() - .flat_map(|(name, multiaddr, resp)| { - resp.iter().map(|(seq_num, r, timespent)| { - ( - *name, - multiaddr.clone(), - seq_num, - r, - timespent, - r.as_ref().err(), - ) - }) - }) - .sorted_by(|a, b| { - Ord::cmp(&b.2, &a.2) - .then_with(|| Ord::cmp(&format!("{:?}", &b.5), &format!("{:?}", &a.5))) - }) - .group_by(|(_, _, seq_num, _r, _ts, _)| **seq_num); - for (seq_num, group) in &responses { - writeln!(f, "seq num: {}", seq_num.opt_debug("latest-seq-num"))?; - let cur_version_resp = group.group_by(|(_, _, _, r, _, _)| match r { - Ok(result) => { - let parent_tx_digest = result.object.previous_transaction; - let obj_digest = result.object.compute_object_reference().2; - let lock = result - .lock_for_debugging - .as_ref() - .map(|lock| *lock.digest()); - let owner = result.object.owner; - Some((parent_tx_digest, obj_digest, lock, owner)) - } - Err(_) => None, - }); - for (result, group) in &cur_version_resp { - match result { - Some((parent_tx_digest, obj_digest, lock, owner)) => { - let lock = lock.opt_debug("no-known-lock"); - writeln!(f, "obj ref: {obj_digest}")?; - writeln!(f, "parent tx: {parent_tx_digest}")?; - writeln!(f, "owner: {owner}")?; - writeln!(f, "lock: {lock}")?; - for (i, (name, multiaddr, _, _, timespent, _)) in group.enumerate() { - writeln!( - f, - " {:<4} {:<20} {:<56} ({:.3}s)", - i, - name.concise(), - format!("{}", multiaddr), - timespent - )?; - } - } - None => { - writeln!(f, "ERROR")?; - for (i, (name, multiaddr, _, resp, timespent, _)) in group.enumerate() { - writeln!( - f, - " {:<4} {:<20} {:<56} ({:.3}s) {:?}", - i, - name.concise(), - format!("{}", multiaddr), - timespent, - resp - )?; - } - } - }; - writeln!(f, "{:<100}\n", "-".repeat(100))?; - } - } - Ok(()) - } -} - -struct ConciseObjectOutput(ObjectData); - -impl ConciseObjectOutput { - fn header() -> String { - format!( - "{:<20} {:<8} {:<66} {:<45} {}", - "validator", "version", "digest", "parent_cert", "owner" - ) - } -} - -impl std::fmt::Display for ConciseObjectOutput { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for (name, _multi_addr, versions) in &self.0.responses { - for (version, resp, _time_elapsed) in versions { - write!( - f, - "{:<20} {:<8}", - format!("{:?}", name.concise()), - version.map(|s| s.value()).opt_debug("-") - )?; - match resp { - Err(_) => writeln!( - f, - "{:<66} {:<45} {:<51}", - "object-fetch-failed", "no-cert-available", "no-owner-available" - )?, - Ok(resp) => { - let obj_digest = resp.object.compute_object_reference().2; - let parent = resp.object.previous_transaction; - let owner = resp.object.owner; - write!(f, " {:<66} {:<45} {:<51}", obj_digest, parent, owner)?; - } - } - writeln!(f)?; - } - } - Ok(()) - } -} - -struct VerboseObjectOutput(ObjectData); - -impl std::fmt::Display for VerboseObjectOutput { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f, "Object: {}", self.0.requested_id)?; - - for (name, multiaddr, versions) in &self.0.responses { - writeln!(f, "validator: {:?}, addr: {:?}", name.concise(), multiaddr)?; - - for (version, resp, timespent) in versions { - writeln!( - f, - "-- version: {} ({:.3}s)", - version.opt_debug(""), - timespent, - )?; - - match resp { - Err(e) => writeln!(f, "Error fetching object: {}", e)?, - Ok(resp) => { - writeln!( - f, - " -- object digest: {}", - resp.object.compute_object_reference().2 - )?; - if resp.object.is_package() { - writeln!(f, " -- object: ")?; - } else if let Some(layout) = &resp.layout { - writeln!( - f, - " -- object: Move Object: {}", - resp.object - .data - .try_as_move() - .unwrap() - .to_move_struct(layout) - .unwrap() - )?; - } - writeln!(f, " -- owner: {}", resp.object.owner)?; - writeln!( - f, - " -- locked by: {}", - resp.lock_for_debugging.opt_debug("") - )?; - } - } - } - } - Ok(()) - } -} - -pub async fn get_object( - obj_id: ObjectID, - version: Option, - validator: Option, - genesis: Option, - fullnode_rpc: Option, -) -> Result { - let clients = make_clients(genesis, fullnode_rpc).await?; - - let responses = join_all( - clients - .iter() - .filter(|(name, _)| { - if let Some(v) = validator { - v == **name - } else { - true - } - }) - .map(|(name, (address, client))| async { - let object_versions = get_object_impl(client, obj_id, version).await; - (*name, address.clone(), object_versions) - }), - ) - .await; - - Ok(ObjectData { - requested_id: obj_id, - responses, - }) -} - -pub async fn get_transaction_block( - tx_digest: TransactionDigest, - genesis: Option, - show_input_tx: bool, - fullnode_rpc: Option, -) -> Result { - let clients = make_clients(genesis, fullnode_rpc).await?; - let timer = Instant::now(); - let responses = join_all(clients.iter().map(|(name, (address, client))| async { - let result = client - .handle_transaction_info_request(TransactionInfoRequest { - transaction_digest: tx_digest, - }) - .await; - ( - *name, - address.clone(), - result, - timer.elapsed().as_secs_f64(), - ) - })) - .await; - - // Grab one validator that return Some(TransactionInfoResponse) - let validator_aware_of_tx = responses.iter().find(|r| r.2.is_ok()); - - let responses = responses - .iter() - .map(|r| { - let key = - r.2.as_ref() - .map(|ok_result| match &ok_result.status { - TransactionStatus::Signed(_) => None, - TransactionStatus::Executed(_, effects, _) => Some(effects.digest()), - }) - .ok(); - let err = r.2.as_ref().err(); - (key, err, r) - }) - .sorted_by(|(k1, err1, _), (k2, err2, _)| { - Ord::cmp(k1, k2).then_with(|| Ord::cmp(err1, err2)) - }) - .group_by(|(_, _err, r)| { - r.2.as_ref().map(|ok_result| match &ok_result.status { - TransactionStatus::Signed(_) => None, - TransactionStatus::Executed(_, effects, _) => Some(( - ok_result.transaction.transaction_data(), - effects.data(), - effects.digest(), - )), - }) - }); - let mut s = String::new(); - for (i, (key, group)) in responses.into_iter().enumerate() { - match key { - Ok(Some((tx, effects, effects_digest))) => { - writeln!( - &mut s, - "#{:<2} tx_digest: {:<68?} effects_digest: {:?}", - i, tx_digest, effects_digest, - )?; - writeln!(&mut s, "{:#?}", effects)?; - if show_input_tx { - writeln!(&mut s, "{:#?}", tx)?; - } - } - Ok(None) => { - writeln!( - &mut s, - "#{:<2} tx_digest: {:<68?} Signed but not executed", - i, tx_digest - )?; - if show_input_tx { - // In this case, we expect at least one validator knows about this tx - let validator_aware_of_tx = validator_aware_of_tx.unwrap(); - let client = &clients.get(&validator_aware_of_tx.0).unwrap().1; - let tx_info = client.handle_transaction_info_request(TransactionInfoRequest { - transaction_digest: tx_digest, - }).await.unwrap_or_else(|e| panic!("Validator {:?} should have known about tx_digest: {:?}, got error: {:?}", validator_aware_of_tx.0, tx_digest, e)); - writeln!(&mut s, "{:#?}", tx_info)?; - } - } - other => { - writeln!(&mut s, "#{:<2} {:#?}", i, other)?; - } - } - for (j, (_, _, res)) in group.enumerate() { - writeln!( - &mut s, - " {:<4} {:<20} {:<56} ({:.3}s)", - j, - res.0.concise(), - format!("{}", res.1), - res.3 - )?; - } - writeln!(&mut s, "{:<100}\n", "-".repeat(100))?; - } - Ok(s) -} - -// Keep the return type a vector in case we need support for lamport versions in -// the near future -async fn get_object_impl( - client: &NetworkAuthorityClient, - id: ObjectID, - version: Option, -) -> Vec<(Option, Result, f64)> { - let mut ret = Vec::new(); - - let start = Instant::now(); - let resp = client - .handle_object_info_request(ObjectInfoRequest { - object_id: id, - generate_layout: LayoutGenerationOption::Generate, - request_kind: match version { - None => ObjectInfoRequestKind::LatestObjectInfo, - Some(v) => ObjectInfoRequestKind::PastObjectInfoDebug(SequenceNumber::from_u64(v)), - }, - }) - .await - .map_err(anyhow::Error::from); - let elapsed = start.elapsed().as_secs_f64(); - - let resp_version = resp.as_ref().ok().map(|r| r.object.version().value()); - ret.push((resp_version.map(SequenceNumber::from), resp, elapsed)); - - ret -} - -pub(crate) fn make_anemo_config() -> anemo_cli::Config { - use narwhal_types::*; - use sui_network::{discovery::*, state_sync::*}; - - // TODO: implement `ServiceInfo` generation in anemo-build and use here. - anemo_cli::Config::new() - // Narwhal primary-to-primary - .add_service( - "PrimaryToPrimary", - anemo_cli::ServiceInfo::new() - .add_method( - "SendCertificate", - anemo_cli::ron_method!( - PrimaryToPrimaryClient, - send_certificate, - SendCertificateRequest - ), - ) - .add_method( - "RequestVote", - anemo_cli::ron_method!( - PrimaryToPrimaryClient, - request_vote, - RequestVoteRequest - ), - ) - .add_method( - "FetchCertificates", - anemo_cli::ron_method!( - PrimaryToPrimaryClient, - fetch_certificates, - FetchCertificatesRequest - ), - ), - ) - // Narwhal worker-to-worker - .add_service( - "WorkerToWorker", - anemo_cli::ServiceInfo::new() - .add_method( - "ReportBatch", - anemo_cli::ron_method!(WorkerToWorkerClient, report_batch, WorkerBatchMessage), - ) - .add_method( - "RequestBatches", - anemo_cli::ron_method!( - WorkerToWorkerClient, - request_batches, - RequestBatchesRequest - ), - ), - ) - // Sui discovery - .add_service( - "Discovery", - anemo_cli::ServiceInfo::new().add_method( - "GetKnownPeers", - anemo_cli::ron_method!(DiscoveryClient, get_known_peers, ()), - ), - ) - // Sui state sync - .add_service( - "StateSync", - anemo_cli::ServiceInfo::new() - .add_method( - "PushCheckpointSummary", - anemo_cli::ron_method!( - StateSyncClient, - push_checkpoint_summary, - sui_types::messages_checkpoint::CertifiedCheckpointSummary - ), - ) - .add_method( - "GetCheckpointSummary", - anemo_cli::ron_method!( - StateSyncClient, - get_checkpoint_summary, - GetCheckpointSummaryRequest - ), - ) - .add_method( - "GetCheckpointContents", - anemo_cli::ron_method!( - StateSyncClient, - get_checkpoint_contents, - sui_types::messages_checkpoint::CheckpointContentsDigest - ), - ) - .add_method( - "GetCheckpointAvailability", - anemo_cli::ron_method!(StateSyncClient, get_checkpoint_availability, ()), - ), - ) -} - -fn copy_dir_all( - src: impl AsRef, - dst: impl AsRef, - skip: Vec, -) -> io::Result<()> { - fs::create_dir_all(&dst)?; - for entry in fs::read_dir(src)? { - let entry = entry?; - let ty = entry.file_type()?; - if skip.contains(&entry.path()) { - continue; - } - if ty.is_dir() { - copy_dir_all( - entry.path(), - dst.as_ref().join(entry.file_name()), - skip.clone(), - )?; - } else { - fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; - } - } - Ok(()) -} - -pub async fn restore_from_db_checkpoint( - config: &NodeConfig, - db_checkpoint_path: &Path, -) -> Result<(), anyhow::Error> { - copy_dir_all(db_checkpoint_path, config.db_path(), vec![])?; - Ok(()) -} - -fn start_summary_sync( - perpetual_db: Arc, - committee_store: Arc, - checkpoint_store: Arc, - m: MultiProgress, - genesis: Genesis, - archive_store_config: ObjectStoreConfig, - epoch: u64, - num_parallel_downloads: usize, - verify: bool, -) -> JoinHandle> { - tokio::spawn(async move { - info!("Starting summary sync"); - let store = - AuthorityStore::open_no_genesis(perpetual_db, usize::MAX, false, &Registry::default())?; - let state_sync_store = RocksDbStore::new( - Arc::new(ExecutionCache::new_for_tests(store, &Registry::default())), - committee_store, - checkpoint_store.clone(), - ); - // Only insert the genesis checkpoint if the DB is empty and doesn't have it - // already - if checkpoint_store - .get_checkpoint_by_digest(genesis.checkpoint().digest()) - .unwrap() - .is_none() - { - checkpoint_store.insert_checkpoint_contents(genesis.checkpoint_contents().clone())?; - checkpoint_store.insert_verified_checkpoint(&genesis.checkpoint())?; - checkpoint_store.update_highest_synced_checkpoint(&genesis.checkpoint())?; - } - // set up download of checkpoint summaries - let config = ArchiveReaderConfig { - remote_store_config: archive_store_config, - download_concurrency: NonZeroUsize::new(num_parallel_downloads).unwrap(), - use_for_pruning_watermark: false, - }; - let metrics = ArchiveReaderMetrics::new(&Registry::default()); - let archive_reader = ArchiveReader::new(config, &metrics)?; - archive_reader.sync_manifest_once().await?; - let manifest = archive_reader.get_manifest().await?; - - let last_checkpoint = manifest.next_checkpoint_after_epoch(epoch) - 1; - let sync_progress_bar = m.add( - ProgressBar::new(last_checkpoint).with_style( - ProgressStyle::with_template("[{elapsed_precise}] {wide_bar} {pos}/{len}({msg})") - .unwrap(), - ), - ); - let cloned_progress_bar = sync_progress_bar.clone(); - let sync_checkpoint_counter = Arc::new(AtomicU64::new(0)); - let s_instant = Instant::now(); - - let cloned_counter = sync_checkpoint_counter.clone(); - let latest_synced = checkpoint_store - .get_highest_synced_checkpoint()? - .map(|c| c.sequence_number) - .unwrap_or(0); - let s_start = latest_synced - .checked_add(1) - .context("Checkpoint overflow") - .map_err(|_| anyhow!("Failed to increment checkpoint"))?; - tokio::spawn(async move { - loop { - if cloned_progress_bar.is_finished() { - break; - } - let num_summaries = cloned_counter.load(Ordering::Relaxed); - let total_checkpoints_per_sec = - num_summaries as f64 / s_instant.elapsed().as_secs_f64(); - cloned_progress_bar.set_position(s_start + num_summaries); - cloned_progress_bar.set_message(format!( - "checkpoints synced per sec: {}", - total_checkpoints_per_sec - )); - tokio::time::sleep(Duration::from_secs(1)).await; - } - }); - - let sync_range = s_start..last_checkpoint + 1; - archive_reader - .read_summaries( - state_sync_store.clone(), - sync_range.clone(), - sync_checkpoint_counter, - // rather than blocking on verify, sync all summaries first, then verify later - false, - ) - .await?; - sync_progress_bar.finish_with_message("Checkpoint summary sync is complete"); - - // verify checkpoint summaries - if verify { - let v_start = s_start; - // update highest verified to be highest synced. We will move back - // iff parallel verification succeeds - let latest_verified = checkpoint_store - .get_checkpoint_by_sequence_number(latest_synced) - .expect("Failed to get checkpoint") - .expect("Expected checkpoint to exist after summary sync"); - checkpoint_store - .update_highest_verified_checkpoint(&latest_verified) - .expect("Failed to update highest verified checkpoint"); - let verify_progress_bar = m.add( - ProgressBar::new(last_checkpoint).with_style( - ProgressStyle::with_template( - "[{elapsed_precise}] {wide_bar} {pos}/{len}({msg})", - ) - .unwrap(), - ), - ); - let cloned_verify_progress_bar = verify_progress_bar.clone(); - let verify_checkpoint_counter = Arc::new(AtomicU64::new(0)); - let cloned_verify_counter = verify_checkpoint_counter.clone(); - let v_instant = Instant::now(); - - tokio::spawn(async move { - loop { - if cloned_verify_progress_bar.is_finished() { - break; - } - let num_summaries = cloned_verify_counter.load(Ordering::Relaxed); - let total_checkpoints_per_sec = - num_summaries as f64 / v_instant.elapsed().as_secs_f64(); - cloned_verify_progress_bar.set_position(v_start + num_summaries); - cloned_verify_progress_bar.set_message(format!( - "checkpoints verified per sec: {}", - total_checkpoints_per_sec - )); - tokio::time::sleep(Duration::from_secs(1)).await; - } - }); - - let verify_range = v_start..last_checkpoint + 1; - verify_checkpoint_range( - verify_range, - state_sync_store, - verify_checkpoint_counter, - num_parallel_downloads, - ) - .await; - verify_progress_bar.finish_with_message("Checkpoint summary verification is complete"); - } - - let checkpoint = checkpoint_store - .get_checkpoint_by_sequence_number(last_checkpoint)? - .ok_or(anyhow!("Failed to read last checkpoint"))?; - - checkpoint_store.update_highest_verified_checkpoint(&checkpoint)?; - checkpoint_store.update_highest_synced_checkpoint(&checkpoint)?; - checkpoint_store.update_highest_executed_checkpoint(&checkpoint)?; - checkpoint_store.update_highest_pruned_checkpoint(&checkpoint)?; - Ok::<(), anyhow::Error>(()) - }) -} - -pub async fn get_latest_available_epoch( - snapshot_store_config: &ObjectStoreConfig, -) -> Result { - let remote_object_store = if snapshot_store_config.no_sign_request { - snapshot_store_config.make_http()? - } else { - snapshot_store_config.make().map(Arc::new)? - }; - let manifest_contents = remote_object_store - .get_bytes(&get_path(MANIFEST_FILENAME)) - .await?; - let root_manifest: Manifest = serde_json::from_slice(&manifest_contents) - .map_err(|err| anyhow!("Error parsing MANIFEST from bytes: {}", err))?; - let epoch = root_manifest - .available_epochs - .iter() - .max() - .ok_or(anyhow!("No snapshot found in manifest"))?; - Ok(*epoch) -} - -pub async fn check_completed_snapshot( - snapshot_store_config: &ObjectStoreConfig, - epoch: EpochId, -) -> Result<(), anyhow::Error> { - let success_marker = format!("epoch_{}/_SUCCESS", epoch); - let remote_object_store = if snapshot_store_config.no_sign_request { - snapshot_store_config.make_http()? - } else { - snapshot_store_config.make().map(Arc::new)? - }; - if exists(&remote_object_store, &get_path(success_marker.as_str())).await { - Ok(()) - } else { - Err(anyhow!( - "missing success marker at {}/{}", - snapshot_store_config.bucket.as_ref().unwrap_or( - &snapshot_store_config - .clone() - .aws_endpoint - .unwrap_or("unknown_bucket".to_string()) - ), - success_marker - )) - } -} - -pub async fn download_formal_snapshot( - path: &Path, - epoch: EpochId, - genesis: &Path, - snapshot_store_config: ObjectStoreConfig, - archive_store_config: ObjectStoreConfig, - num_parallel_downloads: usize, - network: Chain, - verify: bool, -) -> Result<(), anyhow::Error> { - eprintln!( - "Beginning formal snapshot restore to end of epoch {}, network: {:?}", - epoch, network, - ); - let path = path.join("staging").to_path_buf(); - if path.exists() { - fs::remove_dir_all(path.clone())?; - } - let perpetual_db = Arc::new(AuthorityPerpetualTables::open(&path.join("store"), None)); - let genesis = Genesis::load(genesis).unwrap(); - let genesis_committee = genesis.committee()?; - let committee_store = Arc::new(CommitteeStore::new( - path.join("epochs"), - &genesis_committee, - None, - )); - let checkpoint_store = Arc::new(CheckpointStore::open_tables_read_write( - path.join("checkpoints"), - MetricConf::default(), - None, - None, - )); - - let m = MultiProgress::new(); - let summaries_handle = start_summary_sync( - perpetual_db.clone(), - committee_store.clone(), - checkpoint_store.clone(), - m.clone(), - genesis.clone(), - archive_store_config.clone(), - epoch, - num_parallel_downloads, - verify, - ); - let (_abort_handle, abort_registration) = AbortHandle::new_pair(); - let perpetual_db_clone = perpetual_db.clone(); - let snapshot_dir = path.parent().unwrap().join("snapshot"); - if snapshot_dir.exists() { - fs::remove_dir_all(snapshot_dir.clone())?; - } - let snapshot_dir_clone = snapshot_dir.clone(); - - // TODO if verify is false, we should skip generating these and - // not pass in a channel to the reader - let (sender, mut receiver) = mpsc::channel(num_parallel_downloads); - - let snapshot_handle = tokio::spawn(async move { - let local_store_config = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(snapshot_dir_clone.to_path_buf()), - ..Default::default() - }; - let mut reader = StateSnapshotReaderV1::new( - epoch, - &snapshot_store_config, - &local_store_config, - usize::MAX, - NonZeroUsize::new(num_parallel_downloads).unwrap(), - m, - ) - .await - .unwrap_or_else(|err| panic!("Failed to create reader: {}", err)); - reader - .read(&perpetual_db_clone, abort_registration, Some(sender)) - .await - .unwrap_or_else(|err| panic!("Failed during read: {}", err)); - Ok::<(), anyhow::Error>(()) - }); - let mut root_accumulator = Accumulator::default(); - while let Some(partial_acc) = receiver.recv().await { - root_accumulator.union(&partial_acc); - } - summaries_handle - .await - .expect("Task join failed") - .expect("Summaries task failed"); - - let last_checkpoint = checkpoint_store - .get_highest_verified_checkpoint()? - .expect("Expected nonempty checkpoint store"); - - // Perform snapshot state verification - if verify { - assert_eq!( - last_checkpoint.epoch(), - epoch, - "Expected highest verified checkpoint ({}) to be for epoch {} but was for epoch {}", - last_checkpoint.sequence_number, - epoch, - last_checkpoint.epoch() - ); - let commitment = last_checkpoint - .end_of_epoch_data - .as_ref() - .expect("Expected highest verified checkpoint to have end of epoch data") - .epoch_commitments - .last() - .expect( - "End of epoch has no commitments. This likely means that the epoch \ - you are attempting to restore from does not support end of epoch state \ - digest commitment. If restoring from mainnet, `--epoch` must be > 20, \ - and for testnet, `--epoch` must be > 12.", - ); - match commitment { - CheckpointCommitment::ECMHLiveObjectSetDigest(consensus_digest) => { - let local_digest: ECMHLiveObjectSetDigest = root_accumulator.digest().into(); - assert_eq!( - *consensus_digest, local_digest, - "End of epoch {} root state digest {} does not match \ - local root state hash {} after restoring from formal snapshot", - epoch, consensus_digest.digest, local_digest.digest, - ); - eprintln!("Formal snapshot state verification completed successfully!"); - } - }; - } else { - eprintln!( - "WARNING: Skipping snapshot verification! \ - This is highly discouraged unless you fully trust the source of this snapshot and its contents. - If this was unintentional, rerun with `--verify` set to `true`" - ); - } - - snapshot_handle - .await - .expect("Task join failed") - .expect("Snapshot restore task failed"); - - // TODO we should ensure this map is being updated for all end of epoch - // checkpoints during summary sync. This happens in - // `insert_{verified|certified}_checkpoint` in checkpoint store, but not in - // the corresponding functions in ObjectStore trait - checkpoint_store.insert_epoch_last_checkpoint(epoch, &last_checkpoint)?; - - setup_db_state( - epoch, - root_accumulator, - perpetual_db, - checkpoint_store, - committee_store, - ) - .await?; - - let new_path = path.parent().unwrap().join("live"); - if new_path.exists() { - fs::remove_dir_all(new_path.clone())?; - } - fs::rename(&path, &new_path)?; - fs::remove_dir_all(snapshot_dir.clone())?; - info!( - "Successfully restored state from snapshot at end of epoch {}", - epoch - ); - - Ok(()) -} - -pub async fn download_db_snapshot( - path: &Path, - epoch: u64, - snapshot_store_config: ObjectStoreConfig, - skip_indexes: bool, - num_parallel_downloads: usize, -) -> Result<(), anyhow::Error> { - let remote_store = if snapshot_store_config.no_sign_request { - snapshot_store_config.make_http()? - } else { - snapshot_store_config.make().map(Arc::new)? - }; - - // We rely on the top level MANIFEST file which contains all valid epochs - let manifest_contents = remote_store.get_bytes(&get_path(MANIFEST_FILENAME)).await?; - let root_manifest: Manifest = serde_json::from_slice(&manifest_contents) - .map_err(|err| anyhow!("Error parsing MANIFEST from bytes: {}", err))?; - - if !root_manifest.epoch_exists(epoch) { - return Err(anyhow!( - "Epoch dir {} doesn't exist on the remote store", - epoch - )); - } - - let epoch_path = format!("epoch_{}", epoch); - let epoch_dir = get_path(&epoch_path); - - let manifest_file = epoch_dir.child(MANIFEST_FILENAME); - let epoch_manifest_contents = - String::from_utf8(remote_store.get_bytes(&manifest_file).await?.to_vec()) - .map_err(|err| anyhow!("Error parsing {}/MANIFEST from bytes: {}", epoch_path, err))?; - - let epoch_manifest = - PerEpochManifest::deserialize_from_newline_delimited(&epoch_manifest_contents); - - let mut files: Vec = vec![]; - files.extend(epoch_manifest.filter_by_prefix("store/perpetual").lines); - files.extend(epoch_manifest.filter_by_prefix("epochs").lines); - files.extend(epoch_manifest.filter_by_prefix("checkpoints").lines); - if !skip_indexes { - files.extend(epoch_manifest.filter_by_prefix("indexes").lines) - } - let local_store = ObjectStoreConfig { - object_store: Some(ObjectStoreType::File), - directory: Some(path.to_path_buf()), - ..Default::default() - } - .make()?; - let m = MultiProgress::new(); - let path = path.to_path_buf(); - let snapshot_handle = tokio::spawn(async move { - let progress_bar = m.add( - ProgressBar::new(files.len() as u64).with_style( - ProgressStyle::with_template( - "[{elapsed_precise}] {wide_bar} {pos} out of {len} files done\n({msg})", - ) - .unwrap(), - ), - ); - let cloned_progress_bar = progress_bar.clone(); - let file_counter = Arc::new(AtomicUsize::new(0)); - futures::stream::iter(files.iter()) - .map(|file| { - let local_store = local_store.clone(); - let remote_store = remote_store.clone(); - let counter_cloned = file_counter.clone(); - async move { - counter_cloned.fetch_add(1, Ordering::Relaxed); - let file_path = get_path(format!("epoch_{}/{}", epoch, file).as_str()); - copy_file(&file_path, &file_path, &remote_store, &local_store).await?; - Ok::<::object_store::path::Path, anyhow::Error>(file_path.clone()) - } - }) - .boxed() - .buffer_unordered(num_parallel_downloads) - .try_for_each(|path| { - file_counter.fetch_sub(1, Ordering::Relaxed); - cloned_progress_bar.inc(1); - cloned_progress_bar.set_message(format!( - "Downloading file: {}, #downloads_in_progress: {}", - path, - file_counter.load(Ordering::Relaxed) - )); - futures::future::ready(Ok(())) - }) - .await?; - progress_bar.finish_with_message("Snapshot file download is complete"); - Ok::<(), anyhow::Error>(()) - }); - - let tasks: Vec<_> = vec![Box::pin(snapshot_handle)]; - join_all(tasks) - .await - .into_iter() - .collect::, _>>()? - .into_iter() - .for_each(|result| result.expect("Task failed")); - - let store_dir = path.join("store"); - if store_dir.exists() { - fs::remove_dir_all(&store_dir)?; - } - let epochs_dir = path.join("epochs"); - if epochs_dir.exists() { - fs::remove_dir_all(&epochs_dir)?; - } - Ok(()) -} - -pub async fn verify_archive( - genesis: &Path, - remote_store_config: ObjectStoreConfig, - concurrency: usize, - interactive: bool, -) -> Result<()> { - verify_archive_with_genesis_config(genesis, remote_store_config, concurrency, interactive, 10) - .await -} - -pub async fn dump_checkpoints_from_archive( - remote_store_config: ObjectStoreConfig, - start_checkpoint: u64, - end_checkpoint: u64, - max_content_length: usize, -) -> Result<()> { - let metrics = ArchiveReaderMetrics::new(&Registry::default()); - let config = ArchiveReaderConfig { - remote_store_config, - download_concurrency: NonZeroUsize::new(1).unwrap(), - use_for_pruning_watermark: false, - }; - let store = SharedInMemoryStore::default(); - let archive_reader = ArchiveReader::new(config, &metrics)?; - archive_reader.sync_manifest_once().await?; - let checkpoint_counter = Arc::new(AtomicU64::new(0)); - let txn_counter = Arc::new(AtomicU64::new(0)); - archive_reader - .read( - store.clone(), - Range { - start: start_checkpoint, - end: end_checkpoint, - }, - txn_counter, - checkpoint_counter, - false, - ) - .await?; - for key in store - .inner() - .checkpoints() - .values() - .sorted_by(|a, b| a.sequence_number().cmp(&b.sequence_number)) - { - let mut content = serde_json::to_string( - &store - .get_full_checkpoint_contents_by_sequence_number(key.sequence_number)? - .unwrap(), - )?; - content.truncate(max_content_length); - info!( - "{}:{}:{:?}", - key.sequence_number, key.content_digest, content - ); - } - Ok(()) -} - -pub async fn verify_archive_by_checksum( - remote_store_config: ObjectStoreConfig, - concurrency: usize, -) -> Result<()> { - verify_archive_with_checksums(remote_store_config, concurrency).await -} diff --git a/crates/sui-tool/src/main.rs b/crates/sui-tool/src/main.rs deleted file mode 100644 index 2585d5dfc7c..00000000000 --- a/crates/sui-tool/src/main.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -extern crate core; - -use clap::*; -use colored::Colorize; -use sui_tool::commands::ToolCommand; -use sui_types::exit_main; - -#[tokio::main] -async fn main() { - #[cfg(windows)] - colored::control::set_virtual_terminal(true).unwrap(); - - let cmd: ToolCommand = ToolCommand::parse(); - let (_guards, handle) = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .init(); - - exit_main!(cmd.execute(handle).await); -} diff --git a/crates/sui-transaction-builder/Cargo.toml b/crates/sui-transaction-builder/Cargo.toml deleted file mode 100644 index 3f20d5f405e..00000000000 --- a/crates/sui-transaction-builder/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "sui-transaction-builder" -version = "0.0.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow.workspace = true -async-trait.workspace = true -futures.workspace = true -bcs.workspace = true - -move-binary-format.workspace = true -sui-json-rpc-types.workspace = true -sui-types.workspace = true -sui-json.workspace = true -sui-protocol-config.workspace = true - -move-core-types.workspace = true diff --git a/crates/sui-transaction-builder/src/lib.rs b/crates/sui-transaction-builder/src/lib.rs deleted file mode 100644 index 89eb4ab69b4..00000000000 --- a/crates/sui-transaction-builder/src/lib.rs +++ /dev/null @@ -1,888 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::BTreeMap, result::Result, str::FromStr, sync::Arc}; - -use anyhow::{anyhow, bail, ensure, Ok}; -use async_trait::async_trait; -use futures::future::join_all; -use move_binary_format::{ - binary_config::BinaryConfig, binary_views::BinaryIndexedView, file_format::SignatureToken, -}; -use move_core_types::{ - identifier::Identifier, - language_storage::{StructTag, TypeTag}, -}; -use sui_json::{is_receiving_argument, resolve_move_function_args, ResolvedCallArg, SuiJsonValue}; -use sui_json_rpc_types::{ - RPCTransactionRequestParams, SuiData, SuiObjectDataOptions, SuiObjectResponse, SuiRawData, - SuiTypeTag, -}; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ - base_types::{ObjectID, ObjectInfo, ObjectRef, ObjectType, SuiAddress}, - coin, - error::UserInputError, - fp_ensure, - gas_coin::GasCoin, - governance::{ADD_STAKE_MUL_COIN_FUN_NAME, WITHDRAW_STAKE_FUN_NAME}, - move_package::MovePackage, - object::{Object, Owner}, - programmable_transaction_builder::ProgrammableTransactionBuilder, - sui_system_state::SUI_SYSTEM_MODULE_NAME, - timelock::timelocked_staking::{ - ADD_TIMELOCKED_STAKE_FUN_NAME, TIMELOCKED_STAKING_MODULE_NAME, - WITHDRAW_TIMELOCKED_STAKE_FUN_NAME, - }, - transaction::{ - Argument, CallArg, Command, InputObjectKind, ObjectArg, TransactionData, TransactionKind, - }, - SUI_FRAMEWORK_PACKAGE_ID, SUI_SYSTEM_PACKAGE_ID, TIMELOCK_PACKAGE_ID, -}; - -#[async_trait] -pub trait DataReader { - async fn get_owned_objects( - &self, - address: SuiAddress, - object_type: StructTag, - ) -> Result, anyhow::Error>; - - async fn get_object_with_options( - &self, - object_id: ObjectID, - options: SuiObjectDataOptions, - ) -> Result; - - async fn get_reference_gas_price(&self) -> Result; -} - -#[derive(Clone)] -pub struct TransactionBuilder(Arc); - -impl TransactionBuilder { - pub fn new(data_reader: Arc) -> Self { - Self(data_reader) - } - - async fn select_gas( - &self, - signer: SuiAddress, - input_gas: Option, - budget: u64, - input_objects: Vec, - gas_price: u64, - ) -> Result { - if budget < gas_price { - bail!( - "Gas budget {budget} is less than the reference gas price {gas_price}. The gas budget must be at least the current reference gas price of {gas_price}." - ) - } - if let Some(gas) = input_gas { - self.get_object_ref(gas).await - } else { - let gas_objs = self.0.get_owned_objects(signer, GasCoin::type_()).await?; - - for obj in gas_objs { - let response = self - .0 - .get_object_with_options(obj.object_id, SuiObjectDataOptions::new().with_bcs()) - .await?; - let obj = response.object()?; - let gas: GasCoin = bcs::from_bytes( - &obj.bcs - .as_ref() - .ok_or_else(|| anyhow!("bcs field is unexpectedly empty"))? - .try_as_move() - .ok_or_else(|| anyhow!("Cannot parse move object to gas object"))? - .bcs_bytes, - )?; - if !input_objects.contains(&obj.object_id) && gas.value() >= budget { - return Ok(obj.object_ref()); - } - } - Err(anyhow!( - "Cannot find gas coin for signer address [{signer}] with amount sufficient for the required gas amount [{budget}]." - )) - } - } - - pub async fn transfer_object( - &self, - signer: SuiAddress, - object_id: ObjectID, - gas: Option, - gas_budget: u64, - recipient: SuiAddress, - ) -> anyhow::Result { - let mut builder = ProgrammableTransactionBuilder::new(); - self.single_transfer_object(&mut builder, object_id, recipient) - .await?; - let gas_price = self.0.get_reference_gas_price().await?; - let gas = self - .select_gas(signer, gas, gas_budget, vec![object_id], gas_price) - .await?; - - Ok(TransactionData::new( - TransactionKind::programmable(builder.finish()), - signer, - gas, - gas_budget, - gas_price, - )) - } - - async fn single_transfer_object( - &self, - builder: &mut ProgrammableTransactionBuilder, - object_id: ObjectID, - recipient: SuiAddress, - ) -> anyhow::Result<()> { - builder.transfer_object(recipient, self.get_object_ref(object_id).await?)?; - Ok(()) - } - - pub async fn transfer_sui( - &self, - signer: SuiAddress, - sui_object_id: ObjectID, - gas_budget: u64, - recipient: SuiAddress, - amount: Option, - ) -> anyhow::Result { - let object = self.get_object_ref(sui_object_id).await?; - let gas_price = self.0.get_reference_gas_price().await?; - Ok(TransactionData::new_transfer_sui( - recipient, signer, amount, object, gas_budget, gas_price, - )) - } - - pub async fn pay( - &self, - signer: SuiAddress, - input_coins: Vec, - recipients: Vec, - amounts: Vec, - gas: Option, - gas_budget: u64, - ) -> anyhow::Result { - if let Some(gas) = gas { - if input_coins.contains(&gas) { - return Err(anyhow!( - "Gas coin is in input coins of Pay transaction, use PaySui transaction instead!" - )); - } - } - - let handles: Vec<_> = input_coins - .iter() - .map(|id| self.get_object_ref(*id)) - .collect(); - let coin_refs = join_all(handles) - .await - .into_iter() - .collect::>>()?; - let gas_price = self.0.get_reference_gas_price().await?; - let gas = self - .select_gas(signer, gas, gas_budget, input_coins, gas_price) - .await?; - - TransactionData::new_pay( - signer, coin_refs, recipients, amounts, gas, gas_budget, gas_price, - ) - } - - pub async fn pay_sui( - &self, - signer: SuiAddress, - input_coins: Vec, - recipients: Vec, - amounts: Vec, - gas_budget: u64, - ) -> anyhow::Result { - fp_ensure!( - !input_coins.is_empty(), - UserInputError::EmptyInputCoins.into() - ); - - let handles: Vec<_> = input_coins - .into_iter() - .map(|id| self.get_object_ref(id)) - .collect(); - let mut coin_refs = join_all(handles) - .await - .into_iter() - .collect::>>()?; - // [0] is safe because input_coins is non-empty and coins are of same length as - // input_coins. - let gas_object_ref = coin_refs.remove(0); - let gas_price = self.0.get_reference_gas_price().await?; - TransactionData::new_pay_sui( - signer, - coin_refs, - recipients, - amounts, - gas_object_ref, - gas_budget, - gas_price, - ) - } - - pub async fn pay_all_sui( - &self, - signer: SuiAddress, - input_coins: Vec, - recipient: SuiAddress, - gas_budget: u64, - ) -> anyhow::Result { - fp_ensure!( - !input_coins.is_empty(), - UserInputError::EmptyInputCoins.into() - ); - - let handles: Vec<_> = input_coins - .into_iter() - .map(|id| self.get_object_ref(id)) - .collect(); - - let mut coin_refs = join_all(handles) - .await - .into_iter() - .collect::>>()?; - // [0] is safe because input_coins is non-empty and coins are of same length as - // input_coins. - let gas_object_ref = coin_refs.remove(0); - let gas_price = self.0.get_reference_gas_price().await?; - Ok(TransactionData::new_pay_all_sui( - signer, - coin_refs, - recipient, - gas_object_ref, - gas_budget, - gas_price, - )) - } - - pub async fn move_call( - &self, - signer: SuiAddress, - package_object_id: ObjectID, - module: &str, - function: &str, - type_args: Vec, - call_args: Vec, - gas: Option, - gas_budget: u64, - gas_price: Option, - ) -> anyhow::Result { - let mut builder = ProgrammableTransactionBuilder::new(); - self.single_move_call( - &mut builder, - package_object_id, - module, - function, - type_args, - call_args, - ) - .await?; - let pt = builder.finish(); - let input_objects = pt - .input_objects()? - .iter() - .flat_map(|obj| match obj { - InputObjectKind::ImmOrOwnedMoveObject((id, _, _)) => Some(*id), - _ => None, - }) - .collect(); - let gas_price = if let Some(gas_price) = gas_price { - gas_price - } else { - self.0.get_reference_gas_price().await? - }; - let gas = self - .select_gas(signer, gas, gas_budget, input_objects, gas_price) - .await?; - - Ok(TransactionData::new( - TransactionKind::programmable(pt), - signer, - gas, - gas_budget, - gas_price, - )) - } - - pub async fn single_move_call( - &self, - builder: &mut ProgrammableTransactionBuilder, - package: ObjectID, - module: &str, - function: &str, - type_args: Vec, - call_args: Vec, - ) -> anyhow::Result<()> { - let module = Identifier::from_str(module)?; - let function = Identifier::from_str(function)?; - - let type_args = type_args - .into_iter() - .map(|ty| ty.try_into()) - .collect::, _>>()?; - - let call_args = self - .resolve_and_checks_json_args( - builder, package, &module, &function, &type_args, call_args, - ) - .await?; - - builder.command(Command::move_call( - package, module, function, type_args, call_args, - )); - Ok(()) - } - - async fn get_object_arg( - &self, - id: ObjectID, - objects: &mut BTreeMap, - is_mutable_ref: bool, - view: &BinaryIndexedView<'_>, - arg_type: &SignatureToken, - ) -> Result { - let response = self - .0 - .get_object_with_options(id, SuiObjectDataOptions::bcs_lossless()) - .await?; - - let obj: Object = response.into_object()?.try_into()?; - let obj_ref = obj.compute_object_reference(); - let owner = obj.owner; - objects.insert(id, obj); - if is_receiving_argument(view, arg_type) { - return Ok(ObjectArg::Receiving(obj_ref)); - } - Ok(match owner { - Owner::Shared { - initial_shared_version, - } => ObjectArg::SharedObject { - id, - initial_shared_version, - mutable: is_mutable_ref, - }, - Owner::AddressOwner(_) | Owner::ObjectOwner(_) | Owner::Immutable => { - ObjectArg::ImmOrOwnedObject(obj_ref) - } - }) - } - - async fn resolve_and_checks_json_args( - &self, - builder: &mut ProgrammableTransactionBuilder, - package_id: ObjectID, - module: &Identifier, - function: &Identifier, - type_args: &[TypeTag], - json_args: Vec, - ) -> Result, anyhow::Error> { - let object = self - .0 - .get_object_with_options(package_id, SuiObjectDataOptions::bcs_lossless()) - .await? - .into_object()?; - let Some(SuiRawData::Package(package)) = object.bcs else { - bail!( - "Bcs field in object [{}] is missing or not a package.", - package_id - ); - }; - let package: MovePackage = MovePackage::new( - package.id, - object.version, - package.module_map, - ProtocolConfig::get_for_min_version().max_move_package_size(), - package.type_origin_table, - package.linkage_table, - )?; - - let json_args_and_tokens = resolve_move_function_args( - &package, - module.clone(), - function.clone(), - type_args, - json_args, - )?; - - let mut args = Vec::new(); - let mut objects = BTreeMap::new(); - let module = package.deserialize_module(module, &BinaryConfig::standard())?; - let view = BinaryIndexedView::Module(&module); - for (arg, expected_type) in json_args_and_tokens { - args.push(match arg { - ResolvedCallArg::Pure(p) => builder.input(CallArg::Pure(p)), - - ResolvedCallArg::Object(id) => builder.input(CallArg::Object( - self.get_object_arg( - id, - &mut objects, - // Is mutable if passed by mutable reference or by value - matches!(expected_type, SignatureToken::MutableReference(_)) - || !expected_type.is_reference(), - &view, - &expected_type, - ) - .await?, - )), - - ResolvedCallArg::ObjVec(v) => { - let mut object_ids = vec![]; - for id in v { - object_ids.push( - self.get_object_arg( - id, - &mut objects, - // is_mutable_ref - false, - &view, - &expected_type, - ) - .await?, - ) - } - builder.make_obj_vec(object_ids) - } - }?); - } - - Ok(args) - } - - pub async fn publish( - &self, - sender: SuiAddress, - compiled_modules: Vec>, - dep_ids: Vec, - gas: Option, - gas_budget: u64, - ) -> anyhow::Result { - let gas_price = self.0.get_reference_gas_price().await?; - let gas = self - .select_gas(sender, gas, gas_budget, vec![], gas_price) - .await?; - Ok(TransactionData::new_module( - sender, - gas, - compiled_modules, - dep_ids, - gas_budget, - gas_price, - )) - } - - pub async fn upgrade( - &self, - sender: SuiAddress, - package_id: ObjectID, - compiled_modules: Vec>, - dep_ids: Vec, - upgrade_capability: ObjectID, - upgrade_policy: u8, - digest: Vec, - gas: Option, - gas_budget: u64, - ) -> anyhow::Result { - let gas_price = self.0.get_reference_gas_price().await?; - let gas = self - .select_gas(sender, gas, gas_budget, vec![], gas_price) - .await?; - let upgrade_cap = self - .0 - .get_object_with_options(upgrade_capability, SuiObjectDataOptions::new().with_owner()) - .await? - .into_object()?; - let cap_owner = upgrade_cap - .owner - .ok_or_else(|| anyhow!("Unable to determine ownership of upgrade capability"))?; - TransactionData::new_upgrade( - sender, - gas, - package_id, - compiled_modules, - dep_ids, - (upgrade_cap.object_ref(), cap_owner), - upgrade_policy, - digest, - gas_budget, - gas_price, - ) - } - - // TODO: consolidate this with Pay transactions - pub async fn split_coin( - &self, - signer: SuiAddress, - coin_object_id: ObjectID, - split_amounts: Vec, - gas: Option, - gas_budget: u64, - ) -> anyhow::Result { - let coin = self - .0 - .get_object_with_options(coin_object_id, SuiObjectDataOptions::bcs_lossless()) - .await? - .into_object()?; - let coin_object_ref = coin.object_ref(); - let coin: Object = coin.try_into()?; - let type_args = vec![coin.get_move_template_type()?]; - let gas_price = self.0.get_reference_gas_price().await?; - let gas = self - .select_gas(signer, gas, gas_budget, vec![coin_object_id], gas_price) - .await?; - - TransactionData::new_move_call( - signer, - SUI_FRAMEWORK_PACKAGE_ID, - coin::PAY_MODULE_NAME.to_owned(), - coin::PAY_SPLIT_VEC_FUNC_NAME.to_owned(), - type_args, - gas, - vec![ - CallArg::Object(ObjectArg::ImmOrOwnedObject(coin_object_ref)), - CallArg::Pure(bcs::to_bytes(&split_amounts)?), - ], - gas_budget, - gas_price, - ) - } - - // TODO: consolidate this with Pay transactions - pub async fn split_coin_equal( - &self, - signer: SuiAddress, - coin_object_id: ObjectID, - split_count: u64, - gas: Option, - gas_budget: u64, - ) -> anyhow::Result { - let coin = self - .0 - .get_object_with_options(coin_object_id, SuiObjectDataOptions::bcs_lossless()) - .await? - .into_object()?; - let coin_object_ref = coin.object_ref(); - let coin: Object = coin.try_into()?; - let type_args = vec![coin.get_move_template_type()?]; - let gas_price = self.0.get_reference_gas_price().await?; - let gas = self - .select_gas(signer, gas, gas_budget, vec![coin_object_id], gas_price) - .await?; - - TransactionData::new_move_call( - signer, - SUI_FRAMEWORK_PACKAGE_ID, - coin::PAY_MODULE_NAME.to_owned(), - coin::PAY_SPLIT_N_FUNC_NAME.to_owned(), - type_args, - gas, - vec![ - CallArg::Object(ObjectArg::ImmOrOwnedObject(coin_object_ref)), - CallArg::Pure(bcs::to_bytes(&split_count)?), - ], - gas_budget, - gas_price, - ) - } - - // TODO: consolidate this with Pay transactions - pub async fn merge_coins( - &self, - signer: SuiAddress, - primary_coin: ObjectID, - coin_to_merge: ObjectID, - gas: Option, - gas_budget: u64, - ) -> anyhow::Result { - let coin = self - .0 - .get_object_with_options(primary_coin, SuiObjectDataOptions::bcs_lossless()) - .await? - .into_object()?; - let primary_coin_ref = coin.object_ref(); - let coin_to_merge_ref = self.get_object_ref(coin_to_merge).await?; - let coin: Object = coin.try_into()?; - let type_args = vec![coin.get_move_template_type()?]; - let gas_price = self.0.get_reference_gas_price().await?; - let gas = self - .select_gas( - signer, - gas, - gas_budget, - vec![primary_coin, coin_to_merge], - gas_price, - ) - .await?; - - TransactionData::new_move_call( - signer, - SUI_FRAMEWORK_PACKAGE_ID, - coin::PAY_MODULE_NAME.to_owned(), - coin::PAY_JOIN_FUNC_NAME.to_owned(), - type_args, - gas, - vec![ - CallArg::Object(ObjectArg::ImmOrOwnedObject(primary_coin_ref)), - CallArg::Object(ObjectArg::ImmOrOwnedObject(coin_to_merge_ref)), - ], - gas_budget, - gas_price, - ) - } - - pub async fn batch_transaction( - &self, - signer: SuiAddress, - single_transaction_params: Vec, - gas: Option, - gas_budget: u64, - ) -> anyhow::Result { - fp_ensure!( - !single_transaction_params.is_empty(), - UserInputError::InvalidBatchTransaction { - error: "Batch Transaction cannot be empty".to_owned(), - } - .into() - ); - let mut builder = ProgrammableTransactionBuilder::new(); - for param in single_transaction_params { - match param { - RPCTransactionRequestParams::TransferObjectRequestParams(param) => { - self.single_transfer_object(&mut builder, param.object_id, param.recipient) - .await? - } - RPCTransactionRequestParams::MoveCallRequestParams(param) => { - self.single_move_call( - &mut builder, - param.package_object_id, - ¶m.module, - ¶m.function, - param.type_arguments, - param.arguments, - ) - .await? - } - }; - } - let pt = builder.finish(); - let all_inputs = pt.input_objects()?; - let inputs = all_inputs - .iter() - .flat_map(|obj| match obj { - InputObjectKind::ImmOrOwnedMoveObject((id, _, _)) => Some(*id), - _ => None, - }) - .collect(); - let gas_price = self.0.get_reference_gas_price().await?; - let gas = self - .select_gas(signer, gas, gas_budget, inputs, gas_price) - .await?; - - Ok(TransactionData::new( - TransactionKind::programmable(pt), - signer, - gas, - gas_budget, - gas_price, - )) - } - - pub async fn request_add_stake( - &self, - signer: SuiAddress, - mut coins: Vec, - amount: Option, - validator: SuiAddress, - gas: Option, - gas_budget: u64, - ) -> anyhow::Result { - let gas_price = self.0.get_reference_gas_price().await?; - let gas = self - .select_gas(signer, gas, gas_budget, coins.clone(), gas_price) - .await?; - - let mut obj_vec = vec![]; - let coin = coins - .pop() - .ok_or_else(|| anyhow!("Coins input should contain at lease one coin object."))?; - let (oref, coin_type) = self.get_object_ref_and_type(coin).await?; - - let ObjectType::Struct(type_) = &coin_type else { - return Err(anyhow!("Provided object [{coin}] is not a move object.")); - }; - ensure!( - type_.is_coin(), - "Expecting either Coin input coin objects. Received [{type_}]" - ); - - for coin in coins { - let (oref, type_) = self.get_object_ref_and_type(coin).await?; - ensure!( - type_ == coin_type, - "All coins should be the same type, expecting {coin_type}, got {type_}." - ); - obj_vec.push(ObjectArg::ImmOrOwnedObject(oref)) - } - obj_vec.push(ObjectArg::ImmOrOwnedObject(oref)); - - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - let arguments = vec![ - builder.input(CallArg::SUI_SYSTEM_MUT).unwrap(), - builder.make_obj_vec(obj_vec)?, - builder - .input(CallArg::Pure(bcs::to_bytes(&amount)?)) - .unwrap(), - builder - .input(CallArg::Pure(bcs::to_bytes(&validator)?)) - .unwrap(), - ]; - builder.command(Command::move_call( - SUI_SYSTEM_PACKAGE_ID, - SUI_SYSTEM_MODULE_NAME.to_owned(), - ADD_STAKE_MUL_COIN_FUN_NAME.to_owned(), - vec![], - arguments, - )); - builder.finish() - }; - Ok(TransactionData::new_programmable( - signer, - vec![gas], - pt, - gas_budget, - gas_price, - )) - } - - pub async fn request_withdraw_stake( - &self, - signer: SuiAddress, - staked_sui: ObjectID, - gas: Option, - gas_budget: u64, - ) -> anyhow::Result { - let staked_sui = self.get_object_ref(staked_sui).await?; - let gas_price = self.0.get_reference_gas_price().await?; - let gas = self - .select_gas(signer, gas, gas_budget, vec![], gas_price) - .await?; - TransactionData::new_move_call( - signer, - SUI_SYSTEM_PACKAGE_ID, - SUI_SYSTEM_MODULE_NAME.to_owned(), - WITHDRAW_STAKE_FUN_NAME.to_owned(), - vec![], - gas, - vec![ - CallArg::SUI_SYSTEM_MUT, - CallArg::Object(ObjectArg::ImmOrOwnedObject(staked_sui)), - ], - gas_budget, - gas_price, - ) - } - - pub async fn request_add_timelocked_stake( - &self, - signer: SuiAddress, - locked_balance: ObjectID, - validator: SuiAddress, - gas: ObjectID, - gas_budget: u64, - ) -> anyhow::Result { - let gas_price = self.0.get_reference_gas_price().await?; - let gas = self - .select_gas(signer, Some(gas), gas_budget, vec![], gas_price) - .await?; - - let (oref, locked_balance_type) = self.get_object_ref_and_type(locked_balance).await?; - - let ObjectType::Struct(type_) = &locked_balance_type else { - anyhow::bail!("Provided object [{locked_balance}] is not a move object."); - }; - ensure!( - type_.is_timelocked_balance(), - "Expecting either TimeLock> input objects. Received [{type_}]" - ); - - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - let arguments = vec![ - builder.input(CallArg::SUI_SYSTEM_MUT)?, - builder.input(CallArg::Object(ObjectArg::ImmOrOwnedObject(oref)))?, - builder.input(CallArg::Pure(bcs::to_bytes(&validator)?))?, - ]; - builder.command(Command::move_call( - TIMELOCK_PACKAGE_ID, - TIMELOCKED_STAKING_MODULE_NAME.to_owned(), - ADD_TIMELOCKED_STAKE_FUN_NAME.to_owned(), - vec![], - arguments, - )); - builder.finish() - }; - Ok(TransactionData::new_programmable( - signer, - vec![gas], - pt, - gas_budget, - gas_price, - )) - } - - pub async fn request_withdraw_timelocked_stake( - &self, - signer: SuiAddress, - timelocked_staked_sui: ObjectID, - gas: ObjectID, - gas_budget: u64, - ) -> anyhow::Result { - let timelocked_staked_sui = self.get_object_ref(timelocked_staked_sui).await?; - let gas_price = self.0.get_reference_gas_price().await?; - let gas = self - .select_gas(signer, Some(gas), gas_budget, vec![], gas_price) - .await?; - TransactionData::new_move_call( - signer, - TIMELOCK_PACKAGE_ID, - TIMELOCKED_STAKING_MODULE_NAME.to_owned(), - WITHDRAW_TIMELOCKED_STAKE_FUN_NAME.to_owned(), - vec![], - gas, - vec![ - CallArg::SUI_SYSTEM_MUT, - CallArg::Object(ObjectArg::ImmOrOwnedObject(timelocked_staked_sui)), - ], - gas_budget, - gas_price, - ) - } - - // TODO: we should add retrial to reduce the transaction building error rate - pub async fn get_object_ref(&self, object_id: ObjectID) -> anyhow::Result { - self.get_object_ref_and_type(object_id) - .await - .map(|(oref, _)| oref) - } - - async fn get_object_ref_and_type( - &self, - object_id: ObjectID, - ) -> anyhow::Result<(ObjectRef, ObjectType)> { - let object = self - .0 - .get_object_with_options(object_id, SuiObjectDataOptions::new().with_type()) - .await? - .into_object()?; - - Ok((object.object_ref(), object.object_type()?)) - } -} diff --git a/crates/sui-transaction-checks/Cargo.toml b/crates/sui-transaction-checks/Cargo.toml deleted file mode 100644 index 37f28002176..00000000000 --- a/crates/sui-transaction-checks/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "sui-transaction-checks" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -once_cell.workspace = true -sui-macros.workspace = true -sui-config.workspace = true -sui-protocol-config.workspace = true -sui-types.workspace = true -tracing.workspace = true -sui-execution.workspace = true -fastcrypto-zkp.workspace = true diff --git a/crates/sui-transaction-checks/src/lib.rs b/crates/sui-transaction-checks/src/lib.rs deleted file mode 100644 index 58f606b1543..00000000000 --- a/crates/sui-transaction-checks/src/lib.rs +++ /dev/null @@ -1,609 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod deny; - -pub use checked::*; - -#[sui_macros::with_checked_arithmetic] -mod checked { - use std::{ - collections::{BTreeMap, HashSet}, - sync::Arc, - }; - - use sui_protocol_config::ProtocolConfig; - use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress}, - error::{SuiError, SuiResult, UserInputError, UserInputResult}, - executable_transaction::VerifiedExecutableTransaction, - fp_bail, fp_ensure, - gas::SuiGasStatus, - metrics::BytecodeVerifierMetrics, - object::{Object, Owner}, - transaction::{ - CheckedInputObjects, InputObjectKind, InputObjects, ObjectReadResult, - ObjectReadResultKind, ReceivingObjectReadResult, ReceivingObjects, TransactionData, - TransactionDataAPI, TransactionKind, VersionedProtocolMessage as _, - }, - SUI_AUTHENTICATOR_STATE_OBJECT_ID, SUI_CLOCK_OBJECT_ID, SUI_CLOCK_OBJECT_SHARED_VERSION, - SUI_RANDOMNESS_STATE_OBJECT_ID, - }; - use tracing::{error, instrument}; - - trait IntoChecked { - fn into_checked(self) -> CheckedInputObjects; - } - - impl IntoChecked for InputObjects { - fn into_checked(self) -> CheckedInputObjects { - CheckedInputObjects::new_with_checked_transaction_inputs(self) - } - } - - // Entry point for all checks related to gas. - // Called on both signing and execution. - // On success the gas part of the transaction (gas data and gas coins) - // is verified and good to go - pub fn get_gas_status( - objects: &InputObjects, - gas: &[ObjectRef], - protocol_config: &ProtocolConfig, - reference_gas_price: u64, - transaction: &TransactionData, - ) -> SuiResult { - check_gas( - objects, - protocol_config, - reference_gas_price, - gas, - transaction.gas_budget(), - transaction.gas_price(), - transaction.kind(), - ) - } - - #[instrument(level = "trace", skip_all)] - pub fn check_transaction_input( - protocol_config: &ProtocolConfig, - reference_gas_price: u64, - transaction: &TransactionData, - input_objects: InputObjects, - receiving_objects: &ReceivingObjects, - metrics: &Arc, - ) -> SuiResult<(SuiGasStatus, CheckedInputObjects)> { - let gas_status = check_transaction_input_inner( - protocol_config, - reference_gas_price, - transaction, - &input_objects, - &[], - )?; - check_receiving_objects(&input_objects, receiving_objects)?; - // Runs verifier, which could be expensive. - check_non_system_packages_to_be_published(transaction, protocol_config, metrics)?; - - Ok((gas_status, input_objects.into_checked())) - } - - pub fn check_transaction_input_with_given_gas( - protocol_config: &ProtocolConfig, - reference_gas_price: u64, - transaction: &TransactionData, - mut input_objects: InputObjects, - receiving_objects: ReceivingObjects, - gas_object: Object, - metrics: &Arc, - ) -> SuiResult<(SuiGasStatus, CheckedInputObjects)> { - let gas_object_ref = gas_object.compute_object_reference(); - input_objects.push(ObjectReadResult::new_from_gas_object(&gas_object)); - - let gas_status = check_transaction_input_inner( - protocol_config, - reference_gas_price, - transaction, - &input_objects, - &[gas_object_ref], - )?; - check_receiving_objects(&input_objects, &receiving_objects)?; - // Runs verifier, which could be expensive. - check_non_system_packages_to_be_published(transaction, protocol_config, metrics)?; - - Ok((gas_status, input_objects.into_checked())) - } - - // Since the purpose of this function is to audit certified transactions, - // the checks here should be a strict subset of the checks in - // check_transaction_input(). For checks not performed in this function but - // in check_transaction_input(), we should add a comment calling out the - // difference. - #[instrument(level = "trace", skip_all)] - pub fn check_certificate_input( - cert: &VerifiedExecutableTransaction, - input_objects: InputObjects, - protocol_config: &ProtocolConfig, - reference_gas_price: u64, - ) -> SuiResult<(SuiGasStatus, CheckedInputObjects)> { - let transaction = cert.data().transaction_data(); - let gas_status = check_transaction_input_inner( - protocol_config, - reference_gas_price, - transaction, - &input_objects, - &[], - )?; - // NB: We do not check receiving objects when executing. Only at signing time do - // we check. NB: move verifier is only checked at signing time, not at - // execution. - - Ok((gas_status, input_objects.into_checked())) - } - - /// WARNING! This should only be used for the dev-inspect transaction. This - /// transaction type bypasses many of the normal object checks - pub fn check_dev_inspect_input( - config: &ProtocolConfig, - kind: &TransactionKind, - input_objects: InputObjects, - // TODO: check ReceivingObjects for dev inspect? - _receiving_objects: ReceivingObjects, - ) -> SuiResult { - kind.validity_check(config)?; - if kind.is_system_tx() { - return Err(UserInputError::Unsupported(format!( - "Transaction kind {} is not supported in dev-inspect", - kind - )) - .into()); - } - let mut used_objects: HashSet = HashSet::new(); - for input_object in input_objects.iter() { - let Some(object) = input_object.as_object() else { - // object was deleted - continue; - }; - - if !object.is_immutable() { - fp_ensure!( - used_objects.insert(object.id().into()), - UserInputError::MutableObjectUsedMoreThanOnce { - object_id: object.id() - } - .into() - ); - } - } - - Ok(input_objects.into_checked()) - } - - // Common checks performed for transactions and certificates. - fn check_transaction_input_inner( - protocol_config: &ProtocolConfig, - reference_gas_price: u64, - transaction: &TransactionData, - input_objects: &InputObjects, - // Overrides the gas objects in the transaction. - gas_override: &[ObjectRef], - ) -> SuiResult { - // Cheap validity checks that is ok to run multiple times during processing. - transaction.check_version_supported(protocol_config)?; - let gas = if gas_override.is_empty() { - transaction.validity_check(protocol_config)?; - transaction.gas() - } else { - transaction.validity_check_no_gas_check(protocol_config)?; - gas_override - }; - - let gas_status = get_gas_status( - input_objects, - gas, - protocol_config, - reference_gas_price, - transaction, - )?; - check_objects(transaction, input_objects)?; - - Ok(gas_status) - } - - fn check_receiving_objects( - input_objects: &InputObjects, - receiving_objects: &ReceivingObjects, - ) -> Result<(), SuiError> { - let mut objects_in_txn: HashSet<_> = input_objects - .object_kinds() - .map(|x| x.object_id()) - .collect(); - - // Since we're at signing we check that every object reference that we are - // receiving is the most recent version of that object. If it's been - // received at the version specified we let it through to allow the - // transaction to run and fail to unlock any other objects in - // the transaction. Otherwise, we return an error. - // - // If there are any object IDs in common (either between receiving objects and - // input objects) we return an error. - for ReceivingObjectReadResult { - object_ref: (object_id, version, object_digest), - object, - } in receiving_objects.iter() - { - fp_ensure!( - *version < SequenceNumber::MAX, - UserInputError::InvalidSequenceNumber.into() - ); - - let Some(object) = object.as_object() else { - // object was previously received - continue; - }; - - if !(object.owner.is_address_owned() - && object.version() == *version - && object.digest() == *object_digest) - { - // Version mismatch - fp_ensure!( - object.version() == *version, - UserInputError::ObjectVersionUnavailableForConsumption { - provided_obj_ref: (*object_id, *version, *object_digest), - current_version: object.version(), - } - .into() - ); - - // Tried to receive a package - fp_ensure!( - !object.is_package(), - UserInputError::MovePackageAsObject { - object_id: *object_id - } - .into() - ); - - // Digest mismatch - let expected_digest = object.digest(); - fp_ensure!( - expected_digest == *object_digest, - UserInputError::InvalidObjectDigest { - object_id: *object_id, - expected_digest - } - .into() - ); - - match object.owner { - Owner::AddressOwner(_) => { - debug_assert!( - false, - "Receiving object {:?} is invalid but we expect it should be valid. {:?}", - (*object_id, *version, *object_id), - object - ); - error!( - "Receiving object {:?} is invalid but we expect it should be valid. {:?}", - (*object_id, *version, *object_id), - object - ); - // We should never get here, but if for some reason we do just default to - // object not found and reject signing the transaction. - fp_bail!( - UserInputError::ObjectNotFound { - object_id: *object_id, - version: Some(*version), - } - .into() - ) - } - Owner::ObjectOwner(owner) => { - fp_bail!( - UserInputError::InvalidChildObjectArgument { - child_id: object.id(), - parent_id: owner.into(), - } - .into() - ) - } - Owner::Shared { .. } => fp_bail!(UserInputError::NotSharedObjectError.into()), - Owner::Immutable => fp_bail!( - UserInputError::MutableParameterExpected { - object_id: *object_id - } - .into() - ), - }; - } - - fp_ensure!( - !objects_in_txn.contains(object_id), - UserInputError::DuplicateObjectRefInput.into() - ); - - objects_in_txn.insert(*object_id); - } - Ok(()) - } - - /// Check transaction gas data/info and gas coins consistency. - /// Return the gas status to be used for the lifecycle of the transaction. - #[instrument(level = "trace", skip_all)] - fn check_gas( - objects: &InputObjects, - protocol_config: &ProtocolConfig, - reference_gas_price: u64, - gas: &[ObjectRef], - gas_budget: u64, - gas_price: u64, - tx_kind: &TransactionKind, - ) -> SuiResult { - if tx_kind.is_system_tx() { - Ok(SuiGasStatus::new_unmetered()) - } else { - let gas_status = - SuiGasStatus::new(gas_budget, gas_price, reference_gas_price, protocol_config)?; - - // check balance and coins consistency - // load all gas coins - let objects: BTreeMap<_, _> = objects.iter().map(|o| (o.id(), o)).collect(); - let mut gas_objects = vec![]; - for obj_ref in gas { - let obj = objects.get(&obj_ref.0); - let obj = *obj.ok_or(UserInputError::ObjectNotFound { - object_id: obj_ref.0, - version: Some(obj_ref.1), - })?; - gas_objects.push(obj); - } - gas_status.check_gas_balance(&gas_objects, gas_budget)?; - Ok(gas_status) - } - } - - /// Check all the objects used in the transaction against the database, and - /// ensure that they are all the correct version and number. - #[instrument(level = "trace", skip_all)] - fn check_objects(transaction: &TransactionData, objects: &InputObjects) -> UserInputResult<()> { - // We require that mutable objects cannot show up more than once. - let mut used_objects: HashSet = HashSet::new(); - for object in objects.iter() { - if object.is_mutable() { - fp_ensure!( - used_objects.insert(object.id().into()), - UserInputError::MutableObjectUsedMoreThanOnce { - object_id: object.id() - } - ); - } - } - - if !transaction.is_genesis_tx() && objects.is_empty() { - return Err(UserInputError::ObjectInputArityViolation); - } - - let gas_coins: HashSet = - HashSet::from_iter(transaction.gas().iter().map(|obj_ref| obj_ref.0)); - for object in objects.iter() { - let input_object_kind = object.input_object_kind; - - match &object.object { - ObjectReadResultKind::Object(object) => { - // For Gas Object, we check the object is owned by gas owner - let owner_address = if gas_coins.contains(&object.id()) { - transaction.gas_owner() - } else { - transaction.sender() - }; - // Check if the object contents match the type of lock we need for - // this object. - let system_transaction = transaction.is_system_tx(); - check_one_object( - &owner_address, - input_object_kind, - object, - system_transaction, - )?; - } - // We skip checking a deleted shared object because it no longer exists - ObjectReadResultKind::DeletedSharedObject(_, _) => (), - } - } - - Ok(()) - } - - /// Check one object against a reference - fn check_one_object( - owner: &SuiAddress, - object_kind: InputObjectKind, - object: &Object, - system_transaction: bool, - ) -> UserInputResult { - match object_kind { - InputObjectKind::MovePackage(package_id) => { - fp_ensure!( - object.data.try_as_package().is_some(), - UserInputError::MoveObjectAsPackage { - object_id: package_id - } - ); - } - InputObjectKind::ImmOrOwnedMoveObject((object_id, sequence_number, object_digest)) => { - fp_ensure!( - !object.is_package(), - UserInputError::MovePackageAsObject { object_id } - ); - fp_ensure!( - sequence_number < SequenceNumber::MAX, - UserInputError::InvalidSequenceNumber - ); - - // This is an invariant - we just load the object with the given ID and version. - assert_eq!( - object.version(), - sequence_number, - "The fetched object version {} does not match the requested version {}, object id: {}", - object.version(), - sequence_number, - object.id(), - ); - - // Check the digest matches - user could give a mismatched ObjectDigest - let expected_digest = object.digest(); - fp_ensure!( - expected_digest == object_digest, - UserInputError::InvalidObjectDigest { - object_id, - expected_digest - } - ); - - match object.owner { - Owner::Immutable => { - // Nothing else to check for Immutable. - } - Owner::AddressOwner(actual_owner) => { - // Check the owner is correct. - fp_ensure!( - owner == &actual_owner, - UserInputError::IncorrectUserSignature { - error: format!( - "Object {:?} is owned by account address {:?}, but given owner/signer address is {:?}", - object_id, actual_owner, owner - ), - } - ); - } - Owner::ObjectOwner(owner) => { - return Err(UserInputError::InvalidChildObjectArgument { - child_id: object.id(), - parent_id: owner.into(), - }); - } - Owner::Shared { .. } => { - // This object is a mutable shared object. However the transaction - // specifies it as an owned object. This is inconsistent. - return Err(UserInputError::NotSharedObjectError); - } - }; - } - InputObjectKind::SharedMoveObject { - id: SUI_CLOCK_OBJECT_ID, - initial_shared_version: SUI_CLOCK_OBJECT_SHARED_VERSION, - mutable: true, - } => { - // Only system transactions can accept the Clock - // object as a mutable parameter. - if system_transaction { - return Ok(()); - } else { - return Err(UserInputError::ImmutableParameterExpectedError { - object_id: SUI_CLOCK_OBJECT_ID, - }); - } - } - InputObjectKind::SharedMoveObject { - id: SUI_AUTHENTICATOR_STATE_OBJECT_ID, - .. - } => { - if system_transaction { - return Ok(()); - } else { - return Err(UserInputError::InaccessibleSystemObject { - object_id: SUI_AUTHENTICATOR_STATE_OBJECT_ID, - }); - } - } - InputObjectKind::SharedMoveObject { - id: SUI_RANDOMNESS_STATE_OBJECT_ID, - mutable: true, - .. - } => { - // Only system transactions can accept the Random - // object as a mutable parameter. - if system_transaction { - return Ok(()); - } else { - return Err(UserInputError::ImmutableParameterExpectedError { - object_id: SUI_RANDOMNESS_STATE_OBJECT_ID, - }); - } - } - InputObjectKind::SharedMoveObject { - initial_shared_version: input_initial_shared_version, - .. - } => { - fp_ensure!( - object.version() < SequenceNumber::MAX, - UserInputError::InvalidSequenceNumber - ); - - match object.owner { - Owner::AddressOwner(_) | Owner::ObjectOwner(_) | Owner::Immutable => { - // When someone locks an object as shared it must be shared already. - return Err(UserInputError::NotSharedObjectError); - } - Owner::Shared { - initial_shared_version: actual_initial_shared_version, - } => { - fp_ensure!( - input_initial_shared_version == actual_initial_shared_version, - UserInputError::SharedObjectStartingVersionMismatch - ) - } - } - } - }; - Ok(()) - } - - /// Check package verification timeout - #[instrument(level = "trace", skip_all)] - pub fn check_non_system_packages_to_be_published( - transaction: &TransactionData, - protocol_config: &ProtocolConfig, - metrics: &Arc, - ) -> UserInputResult<()> { - // Only meter non-system programmable transaction blocks - if transaction.is_system_tx() { - return Ok(()); - } - - let TransactionKind::ProgrammableTransaction(pt) = transaction.kind() else { - return Ok(()); - }; - - // We use a custom config with metering enabled - let is_metered = true; - // Use the same verifier and meter for all packages - let mut verifier = sui_execution::verifier(protocol_config, is_metered, metrics); - - // Measure time for verifying all packages in the PTB - let shared_meter_verifier_timer = metrics - .verifier_runtime_per_ptb_success_latency - .start_timer(); - - let verifier_status = pt - .non_system_packages_to_be_published() - .try_for_each(|module_bytes| verifier.meter_module_bytes(protocol_config, module_bytes)) - .map_err(|e| UserInputError::PackageVerificationTimedout { err: e.to_string() }); - - match verifier_status { - Ok(_) => { - // Success: stop and record the success timer - shared_meter_verifier_timer.stop_and_record(); - } - Err(err) => { - // Failure: redirect the success timers output to the failure timer and - // discard the success timer - metrics - .verifier_runtime_per_ptb_timeout_latency - .observe(shared_meter_verifier_timer.stop_and_discard()); - return Err(err); - } - }; - - Ok(()) - } -} diff --git a/crates/sui-transactional-test-runner/Cargo.toml b/crates/sui-transactional-test-runner/Cargo.toml deleted file mode 100644 index dc7ded4a21f..00000000000 --- a/crates/sui-transactional-test-runner/Cargo.toml +++ /dev/null @@ -1,58 +0,0 @@ -[package] -name = "sui-transactional-test-runner" -version = "0.1.0" -edition = "2021" -authors = ["Mysten Labs "] -description = "Move framework for Sui platform" -license = "Apache-2.0" -publish = false - -[dependencies] -anyhow.workspace = true -bcs.workspace = true -bimap.workspace = true -clap.workspace = true -eyre.workspace = true -once_cell.workspace = true -rand.workspace = true -regex.workspace = true -tempfile.workspace = true -async-trait.workspace = true -tokio.workspace = true -serde_json.workspace = true -futures.workspace = true -criterion.workspace = true - -fastcrypto.workspace = true -move-binary-format.workspace = true -move-bytecode-utils.workspace = true -move-command-line-common.workspace = true -move-compiler.workspace = true -move-core-types.workspace = true -move-symbol-pool.workspace = true -move-transactional-test-runner.workspace = true -telemetry-subscribers.workspace = true - -move-stdlib = { path = "../../external-crates/move/crates/move-stdlib" } -move-vm-runtime = { path = "../../external-crates/move/crates/move-vm-runtime" } - -rocksdb.workspace = true -simulacrum.workspace = true -sui-graphql-rpc.workspace = true -sui-rest-api.workspace = true -sui-swarm-config.workspace = true -sui-config.workspace = true -sui-core = { workspace = true, features = ["test-utils"] } -sui-framework.workspace = true -sui-protocol-config.workspace = true -sui-types = { workspace = true, features = ["test-utils"]} -sui-json-rpc-types.workspace = true -sui-json-rpc.workspace = true -sui-json-rpc-api.workspace = true -sui-framework-snapshot.workspace = true -sui-storage.workspace = true -typed-store.workspace = true -typed-store-derive.workspace = true - -[target.'cfg(msim)'.dependencies] -msim.workspace = true diff --git a/crates/sui-transactional-test-runner/src/args.rs b/crates/sui-transactional-test-runner/src/args.rs deleted file mode 100644 index 3a1470a1e6e..00000000000 --- a/crates/sui-transactional-test-runner/src/args.rs +++ /dev/null @@ -1,622 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use anyhow::{bail, ensure}; -use clap::{self, Args, Parser}; -use move_command_line_common::{ - parser::{parse_u256, parse_u64, Parser as MoveCLParser}, - values::{ParsableValue, ParsedValue, ValueToken}, -}; -use move_compiler::editions::Flavor; -use move_core_types::{ - runtime_value::{MoveStruct, MoveValue}, - u256::U256, -}; -use move_symbol_pool::Symbol; -use move_transactional_test_runner::tasks::{RunCommand, SyntaxChoice}; -use sui_types::{ - base_types::{SequenceNumber, SuiAddress}, - move_package::UpgradePolicy, - object::{Object, Owner}, - programmable_transaction_builder::ProgrammableTransactionBuilder, - transaction::{Argument, CallArg, ObjectArg}, -}; - -use crate::test_adapter::{FakeID, SuiTestAdapter}; - -pub const SUI_ARGS_LONG: &str = "sui-args"; - -#[derive(Clone, Debug, clap::Parser)] -pub struct SuiRunArgs { - #[clap(long = "sender")] - pub sender: Option, - #[clap(long = "gas-price")] - pub gas_price: Option, - #[clap(long = "summarize")] - pub summarize: bool, -} - -#[derive(Debug, clap::Parser, Default)] -pub struct SuiPublishArgs { - #[clap(long = "sender")] - pub sender: Option, - #[clap(long = "upgradeable", action = clap::ArgAction::SetTrue)] - pub upgradeable: bool, - #[clap(long = "dependencies", num_args(1..))] - pub dependencies: Vec, - #[clap(long = "gas-price")] - pub gas_price: Option, -} - -#[derive(Debug, clap::Parser)] -pub struct SuiInitArgs { - #[clap(long = "accounts", num_args(1..))] - pub accounts: Option>, - #[clap(long = "protocol-version")] - pub protocol_version: Option, - #[clap(long = "max-gas")] - pub max_gas: Option, - #[clap(long = "shared-object-deletion")] - pub shared_object_deletion: Option, - #[clap(long = "simulator")] - pub simulator: bool, - #[clap(long = "custom-validator-account")] - pub custom_validator_account: bool, - #[clap(long = "reference-gas-price")] - pub reference_gas_price: Option, - #[clap(long = "default-gas-price")] - pub default_gas_price: Option, - #[clap(long = "object-snapshot-min-checkpoint-lag")] - pub object_snapshot_min_checkpoint_lag: Option, - #[clap(long = "object-snapshot-max-checkpoint-lag")] - pub object_snapshot_max_checkpoint_lag: Option, - #[clap(long = "flavor")] - pub flavor: Option, -} - -#[derive(Debug, clap::Parser)] -pub struct ViewObjectCommand { - #[clap(value_parser = parse_fake_id)] - pub id: FakeID, -} - -#[derive(Debug, clap::Parser)] -pub struct TransferObjectCommand { - #[clap(value_parser = parse_fake_id)] - pub id: FakeID, - #[clap(long = "recipient")] - pub recipient: String, - #[clap(long = "sender")] - pub sender: Option, - #[clap(long = "gas-budget")] - pub gas_budget: Option, - #[clap(long = "gas-price")] - pub gas_price: Option, -} - -#[derive(Debug, clap::Parser)] -pub struct ConsensusCommitPrologueCommand { - #[clap(long = "timestamp-ms")] - pub timestamp_ms: u64, -} - -#[derive(Debug, clap::Parser)] -pub struct ProgrammableTransactionCommand { - #[clap(long = "sender")] - pub sender: Option, - #[clap(long = "gas-budget")] - pub gas_budget: Option, - #[clap(long = "gas-price")] - pub gas_price: Option, - #[clap(long = "dev-inspect")] - pub dev_inspect: bool, - #[clap( - long = "inputs", - value_parser = ParsedValue::::parse, - num_args(1..), - action = clap::ArgAction::Append, - )] - pub inputs: Vec>, -} - -#[derive(Debug, clap::Parser)] -pub struct UpgradePackageCommand { - #[clap(long = "package")] - pub package: String, - #[clap(long = "upgrade-capability", value_parser = parse_fake_id)] - pub upgrade_capability: FakeID, - #[clap(long = "dependencies", num_args(1..))] - pub dependencies: Vec, - #[clap(long = "sender")] - pub sender: String, - #[clap(long = "gas-budget")] - pub gas_budget: Option, - #[clap(long = "syntax")] - pub syntax: Option, - #[clap(long = "policy", default_value="compatible", value_parser = parse_policy)] - pub policy: u8, - #[clap(long = "gas-price")] - pub gas_price: Option, -} - -#[derive(Debug, clap::Parser)] -pub struct StagePackageCommand { - #[clap(long = "syntax")] - pub syntax: Option, - #[clap(long = "dependencies", num_args(1..))] - pub dependencies: Vec, -} - -#[derive(Debug, clap::Parser)] -pub struct SetAddressCommand { - pub address: String, - #[clap(value_parser = ParsedValue::::parse)] - pub input: ParsedValue, -} - -#[derive(Debug, clap::Parser)] -pub struct AdvanceClockCommand { - #[clap(long = "duration-ns")] - pub duration_ns: u64, -} - -#[derive(Debug, clap::Parser)] -pub struct RunGraphqlCommand { - #[clap(long = "show-usage")] - pub show_usage: bool, - #[clap(long = "show-headers")] - pub show_headers: bool, - #[clap(long = "show-service-version")] - pub show_service_version: bool, - #[clap(long, num_args(1..))] - pub cursors: Vec, -} - -#[derive(Debug, clap::Parser)] -pub struct ForceObjectSnapshotCatchup { - #[clap(long = "start-cp")] - pub start_cp: u64, - #[clap(long = "end-cp")] - pub end_cp: u64, -} - -#[derive(Debug, clap::Parser)] -pub struct CreateCheckpointCommand { - pub count: Option, -} - -#[derive(Debug, clap::Parser)] -pub struct AdvanceEpochCommand { - pub count: Option, - #[clap(long = "create-random-state")] - pub create_random_state: bool, -} - -#[derive(Debug, clap::Parser)] -pub struct SetRandomStateCommand { - #[clap(long = "randomness-round")] - pub randomness_round: u64, - #[clap(long = "random-bytes")] - pub random_bytes: String, - #[clap(long = "randomness-initial-version")] - pub randomness_initial_version: u64, -} - -#[derive(Debug)] -pub enum SuiSubcommand { - ViewObject(ViewObjectCommand), - TransferObject(TransferObjectCommand), - ConsensusCommitPrologue(ConsensusCommitPrologueCommand), - ProgrammableTransaction(ProgrammableTransactionCommand), - UpgradePackage(UpgradePackageCommand), - StagePackage(StagePackageCommand), - SetAddress(SetAddressCommand), - CreateCheckpoint(CreateCheckpointCommand), - AdvanceEpoch(AdvanceEpochCommand), - AdvanceClock(AdvanceClockCommand), - SetRandomState(SetRandomStateCommand), - ViewCheckpoint, - RunGraphql(RunGraphqlCommand), - ForceObjectSnapshotCatchup(ForceObjectSnapshotCatchup), - Bench(RunCommand, ExtraRunArgs), -} - -impl clap::FromArgMatches - for SuiSubcommand -{ - fn from_arg_matches(matches: &clap::ArgMatches) -> Result { - Ok(match matches.subcommand() { - Some(("view-object", matches)) => { - SuiSubcommand::ViewObject(ViewObjectCommand::from_arg_matches(matches)?) - } - Some(("transfer-object", matches)) => { - SuiSubcommand::TransferObject(TransferObjectCommand::from_arg_matches(matches)?) - } - Some(("consensus-commit-prologue", matches)) => SuiSubcommand::ConsensusCommitPrologue( - ConsensusCommitPrologueCommand::from_arg_matches(matches)?, - ), - Some(("programmable", matches)) => SuiSubcommand::ProgrammableTransaction( - ProgrammableTransactionCommand::from_arg_matches(matches)?, - ), - Some(("upgrade", matches)) => { - SuiSubcommand::UpgradePackage(UpgradePackageCommand::from_arg_matches(matches)?) - } - Some(("stage-package", matches)) => { - SuiSubcommand::StagePackage(StagePackageCommand::from_arg_matches(matches)?) - } - Some(("set-address", matches)) => { - SuiSubcommand::SetAddress(SetAddressCommand::from_arg_matches(matches)?) - } - Some(("create-checkpoint", matches)) => { - SuiSubcommand::CreateCheckpoint(CreateCheckpointCommand::from_arg_matches(matches)?) - } - Some(("advance-epoch", matches)) => { - SuiSubcommand::AdvanceEpoch(AdvanceEpochCommand::from_arg_matches(matches)?) - } - Some(("advance-clock", matches)) => { - SuiSubcommand::AdvanceClock(AdvanceClockCommand::from_arg_matches(matches)?) - } - Some(("set-random-state", matches)) => { - SuiSubcommand::SetRandomState(SetRandomStateCommand::from_arg_matches(matches)?) - } - Some(("view-checkpoint", _)) => SuiSubcommand::ViewCheckpoint, - Some(("run-graphql", matches)) => { - SuiSubcommand::RunGraphql(RunGraphqlCommand::from_arg_matches(matches)?) - } - Some(("force-object-snapshot-catchup", matches)) => { - SuiSubcommand::ForceObjectSnapshotCatchup( - ForceObjectSnapshotCatchup::from_arg_matches(matches)?, - ) - } - Some(("bench", matches)) => SuiSubcommand::Bench( - RunCommand::from_arg_matches(matches)?, - ExtraRunArgs::from_arg_matches(matches)?, - ), - _ => { - return Err(clap::Error::raw( - clap::error::ErrorKind::InvalidSubcommand, - "Invalid submcommand", - )); - } - }) - } - - fn update_from_arg_matches(&mut self, matches: &clap::ArgMatches) -> Result<(), clap::Error> { - *self = Self::from_arg_matches(matches)?; - Ok(()) - } -} - -impl clap::CommandFactory - for SuiSubcommand -{ - fn command() -> clap::Command { - clap::Command::new("sui_sub_command") - .subcommand(ViewObjectCommand::command().name("view-object")) - .subcommand(TransferObjectCommand::command().name("transfer-object")) - .subcommand(ConsensusCommitPrologueCommand::command().name("consensus-commit-prologue")) - .subcommand(ProgrammableTransactionCommand::command().name("programmable")) - .subcommand(UpgradePackageCommand::command().name("upgrade")) - .subcommand(StagePackageCommand::command().name("stage-package")) - .subcommand(SetAddressCommand::command().name("set-address")) - .subcommand(CreateCheckpointCommand::command().name("create-checkpoint")) - .subcommand(AdvanceEpochCommand::command().name("advance-epoch")) - .subcommand(AdvanceClockCommand::command().name("advance-clock")) - .subcommand(SetRandomStateCommand::command().name("set-random-state")) - .subcommand(clap::Command::new("view-checkpoint")) - .subcommand(RunGraphqlCommand::command().name("run-graphql")) - .subcommand(ForceObjectSnapshotCatchup::command().name("force-object-snapshot-catchup")) - .subcommand( - RunCommand::::augment_args(ExtraRunArgs::command()).name("bench"), - ) - } - - fn command_for_update() -> clap::Command { - todo!() - } -} - -impl clap::Parser - for SuiSubcommand -{ -} - -#[derive(Clone, Debug)] -pub enum SuiExtraValueArgs { - Object(FakeID, Option), - Digest(String), - Receiving(FakeID, Option), - ImmShared(FakeID, Option), -} - -#[derive(Clone)] -pub enum SuiValue { - MoveValue(MoveValue), - Object(FakeID, Option), - ObjVec(Vec<(FakeID, Option)>), - Digest(String), - Receiving(FakeID, Option), - ImmShared(FakeID, Option), -} - -impl SuiExtraValueArgs { - fn parse_object_value<'a, I: Iterator>( - parser: &mut MoveCLParser<'a, ValueToken, I>, - ) -> anyhow::Result { - let (fake_id, version) = Self::parse_receiving_or_object_value(parser, "object")?; - Ok(SuiExtraValueArgs::Object(fake_id, version)) - } - - fn parse_receiving_value<'a, I: Iterator>( - parser: &mut MoveCLParser<'a, ValueToken, I>, - ) -> anyhow::Result { - let (fake_id, version) = Self::parse_receiving_or_object_value(parser, "receiving")?; - Ok(SuiExtraValueArgs::Receiving(fake_id, version)) - } - - fn parse_read_shared_value<'a, I: Iterator>( - parser: &mut MoveCLParser<'a, ValueToken, I>, - ) -> anyhow::Result { - let (fake_id, version) = Self::parse_receiving_or_object_value(parser, "immshared")?; - Ok(SuiExtraValueArgs::ImmShared(fake_id, version)) - } - - fn parse_digest_value<'a, I: Iterator>( - parser: &mut MoveCLParser<'a, ValueToken, I>, - ) -> anyhow::Result { - let contents = parser.advance(ValueToken::Ident)?; - ensure!(contents == "digest"); - parser.advance(ValueToken::LParen)?; - let package = parser.advance(ValueToken::Ident)?; - parser.advance(ValueToken::RParen)?; - Ok(SuiExtraValueArgs::Digest(package.to_owned())) - } - - fn parse_receiving_or_object_value<'a, I: Iterator>( - parser: &mut MoveCLParser<'a, ValueToken, I>, - ident_name: &str, - ) -> anyhow::Result<(FakeID, Option)> { - let contents = parser.advance(ValueToken::Ident)?; - ensure!(contents == ident_name); - parser.advance(ValueToken::LParen)?; - let i_str = parser.advance(ValueToken::Number)?; - let (i, _) = parse_u256(i_str)?; - let fake_id = if let Some(ValueToken::Comma) = parser.peek_tok() { - parser.advance(ValueToken::Comma)?; - let j_str = parser.advance(ValueToken::Number)?; - let (j, _) = parse_u64(j_str)?; - if i > U256::from(u64::MAX) { - bail!("Object ID too large") - } - FakeID::Enumerated(i.unchecked_as_u64(), j) - } else { - let mut u256_bytes = i.to_le_bytes().to_vec(); - u256_bytes.reverse(); - let address: SuiAddress = SuiAddress::from_bytes(&u256_bytes).unwrap(); - FakeID::Known(address.into()) - }; - parser.advance(ValueToken::RParen)?; - let version = if let Some(ValueToken::AtSign) = parser.peek_tok() { - parser.advance(ValueToken::AtSign)?; - let v_str = parser.advance(ValueToken::Number)?; - let (v, _) = parse_u64(v_str)?; - Some(SequenceNumber::from_u64(v)) - } else { - None - }; - Ok((fake_id, version)) - } -} - -impl SuiValue { - fn assert_move_value(self) -> MoveValue { - match self { - SuiValue::MoveValue(v) => v, - SuiValue::Object(_, _) => panic!("unexpected nested Sui object in args"), - SuiValue::ObjVec(_) => panic!("unexpected nested Sui object vector in args"), - SuiValue::Digest(_) => panic!("unexpected nested Sui package digest in args"), - SuiValue::Receiving(_, _) => panic!("unexpected nested Sui receiving object in args"), - SuiValue::ImmShared(_, _) => panic!("unexpected nested Sui shared object in args"), - } - } - - fn assert_object(self) -> (FakeID, Option) { - match self { - SuiValue::MoveValue(_) => panic!("unexpected nested non-object value in args"), - SuiValue::Object(id, version) => (id, version), - SuiValue::ObjVec(_) => panic!("unexpected nested Sui object vector in args"), - SuiValue::Digest(_) => panic!("unexpected nested Sui package digest in args"), - SuiValue::Receiving(_, _) => panic!("unexpected nested Sui receiving object in args"), - SuiValue::ImmShared(_, _) => panic!("unexpected nested Sui shared object in args"), - } - } - - fn resolve_object( - fake_id: FakeID, - version: Option, - test_adapter: &SuiTestAdapter, - ) -> anyhow::Result { - let id = match test_adapter.fake_to_real_object_id(fake_id) { - Some(id) => id, - None => bail!("INVALID TEST. Unknown object, object({})", fake_id), - }; - let obj_res = if let Some(v) = version { - sui_types::storage::ObjectStore::get_object_by_key(&*test_adapter.executor, &id, v) - } else { - sui_types::storage::ObjectStore::get_object(&*test_adapter.executor, &id) - }; - let obj = match obj_res { - Ok(Some(obj)) => obj, - Err(_) | Ok(None) => bail!("INVALID TEST. Could not load object argument {}", id), - }; - Ok(obj) - } - - fn receiving_arg( - fake_id: FakeID, - version: Option, - test_adapter: &SuiTestAdapter, - ) -> anyhow::Result { - let obj = Self::resolve_object(fake_id, version, test_adapter)?; - Ok(ObjectArg::Receiving(obj.compute_object_reference())) - } - - fn read_shared_arg( - fake_id: FakeID, - version: Option, - test_adapter: &SuiTestAdapter, - ) -> anyhow::Result { - let obj = Self::resolve_object(fake_id, version, test_adapter)?; - let id = obj.id(); - if let Owner::Shared { - initial_shared_version, - } = obj.owner - { - Ok(ObjectArg::SharedObject { - id, - initial_shared_version, - mutable: false, - }) - } else { - bail!("{fake_id} is not a shared object.") - } - } - - fn object_arg( - fake_id: FakeID, - version: Option, - test_adapter: &SuiTestAdapter, - ) -> anyhow::Result { - let obj = Self::resolve_object(fake_id, version, test_adapter)?; - let id = obj.id(); - match obj.owner { - Owner::Shared { - initial_shared_version, - } => Ok(ObjectArg::SharedObject { - id, - initial_shared_version, - mutable: true, - }), - Owner::AddressOwner(_) | Owner::ObjectOwner(_) | Owner::Immutable => { - let obj_ref = obj.compute_object_reference(); - Ok(ObjectArg::ImmOrOwnedObject(obj_ref)) - } - } - } - - pub(crate) fn into_call_arg(self, test_adapter: &SuiTestAdapter) -> anyhow::Result { - Ok(match self { - SuiValue::Object(fake_id, version) => { - CallArg::Object(Self::object_arg(fake_id, version, test_adapter)?) - } - SuiValue::MoveValue(v) => CallArg::Pure(v.simple_serialize().unwrap()), - SuiValue::Receiving(fake_id, version) => { - CallArg::Object(Self::receiving_arg(fake_id, version, test_adapter)?) - } - SuiValue::ImmShared(fake_id, version) => { - CallArg::Object(Self::read_shared_arg(fake_id, version, test_adapter)?) - } - SuiValue::ObjVec(_) => bail!("obj vec is not supported as an input"), - SuiValue::Digest(pkg) => { - let pkg = Symbol::from(pkg); - let Some(staged) = test_adapter.staged_modules.get(&pkg) else { - bail!("Unbound staged package '{pkg}'") - }; - CallArg::Pure(bcs::to_bytes(&staged.digest).unwrap()) - } - }) - } - - pub(crate) fn into_argument( - self, - builder: &mut ProgrammableTransactionBuilder, - test_adapter: &SuiTestAdapter, - ) -> anyhow::Result { - match self { - SuiValue::ObjVec(vec) => builder.make_obj_vec( - vec.iter() - .map(|(fake_id, version)| Self::object_arg(*fake_id, *version, test_adapter)) - .collect::, _>>()?, - ), - value => { - let call_arg = value.into_call_arg(test_adapter)?; - builder.input(call_arg) - } - } - } -} - -impl ParsableValue for SuiExtraValueArgs { - type ConcreteValue = SuiValue; - - fn parse_value<'a, I: Iterator>( - parser: &mut MoveCLParser<'a, ValueToken, I>, - ) -> Option> { - match parser.peek()? { - (ValueToken::Ident, "object") => Some(Self::parse_object_value(parser)), - (ValueToken::Ident, "digest") => Some(Self::parse_digest_value(parser)), - (ValueToken::Ident, "receiving") => Some(Self::parse_receiving_value(parser)), - (ValueToken::Ident, "immshared") => Some(Self::parse_read_shared_value(parser)), - _ => None, - } - } - - fn move_value_into_concrete(v: MoveValue) -> anyhow::Result { - Ok(SuiValue::MoveValue(v)) - } - - fn concrete_vector(elems: Vec) -> anyhow::Result { - if !elems.is_empty() && matches!(elems[0], SuiValue::Object(_, _)) { - Ok(SuiValue::ObjVec( - elems.into_iter().map(SuiValue::assert_object).collect(), - )) - } else { - Ok(SuiValue::MoveValue(MoveValue::Vector( - elems.into_iter().map(SuiValue::assert_move_value).collect(), - ))) - } - } - - fn concrete_struct(values: Vec) -> anyhow::Result { - Ok(SuiValue::MoveValue(MoveValue::Struct(MoveStruct( - values.into_iter().map(|v| v.assert_move_value()).collect(), - )))) - } - - fn into_concrete_value( - self, - _mapping: &impl Fn(&str) -> Option, - ) -> anyhow::Result { - match self { - SuiExtraValueArgs::Object(id, version) => Ok(SuiValue::Object(id, version)), - SuiExtraValueArgs::Digest(pkg) => Ok(SuiValue::Digest(pkg)), - SuiExtraValueArgs::Receiving(id, version) => Ok(SuiValue::Receiving(id, version)), - SuiExtraValueArgs::ImmShared(id, version) => Ok(SuiValue::ImmShared(id, version)), - } - } -} - -fn parse_fake_id(s: &str) -> anyhow::Result { - Ok(if let Some((s1, s2)) = s.split_once(',') { - let (i, _) = parse_u64(s1)?; - let (j, _) = parse_u64(s2)?; - FakeID::Enumerated(i, j) - } else { - let (i, _) = parse_u256(s)?; - let mut u256_bytes = i.to_le_bytes().to_vec(); - u256_bytes.reverse(); - let address: SuiAddress = SuiAddress::from_bytes(&u256_bytes).unwrap(); - FakeID::Known(address.into()) - }) -} - -fn parse_policy(x: &str) -> anyhow::Result { - Ok(match x { - "compatible" => UpgradePolicy::COMPATIBLE, - "additive" => UpgradePolicy::ADDITIVE, - "dep_only" => UpgradePolicy::DEP_ONLY, - _ => bail!( - "Invalid upgrade policy {x}. Policy must be one of 'compatible', 'additive', or 'dep_only'" - ), - }) -} diff --git a/crates/sui-transactional-test-runner/src/lib.rs b/crates/sui-transactional-test-runner/src/lib.rs deleted file mode 100644 index acf86ad1d65..00000000000 --- a/crates/sui-transactional-test-runner/src/lib.rs +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//! This module contains the transactional test runner instantiation for the Sui -//! adapter - -pub mod args; -pub mod programmable_transaction_test_parser; -mod simulator_persisted_store; -pub mod test_adapter; - -use std::{path::Path, sync::Arc}; - -pub use move_transactional_test_runner::framework::run_test_impl; -use rand::rngs::StdRng; -use simulacrum::{Simulacrum, SimulatorStore}; -use simulator_persisted_store::PersistedStore; -use sui_core::authority::{ - authority_test_utils::send_and_confirm_transaction_with_execution_error, AuthorityState, -}; -use sui_json_rpc::authority_state::StateRead; -use sui_json_rpc_types::{DevInspectResults, EventFilter}; -use sui_storage::key_value_store::TransactionKeyValueStore; -use sui_types::{ - base_types::{ObjectID, SuiAddress, VersionNumber}, - digests::{TransactionDigest, TransactionEventsDigest}, - effects::{TransactionEffects, TransactionEvents}, - error::{ExecutionError, SuiError, SuiResult}, - event::Event, - executable_transaction::{ExecutableTransaction, VerifiedExecutableTransaction}, - messages_checkpoint::{CheckpointContentsDigest, VerifiedCheckpoint}, - object::Object, - storage::{ObjectStore, ReadStore}, - sui_system_state::{ - epoch_start_sui_system_state::EpochStartSystemStateTrait, SuiSystemStateTrait, - }, - transaction::{InputObjects, Transaction, TransactionDataAPI, TransactionKind}, -}; -use test_adapter::{SuiTestAdapter, PRE_COMPILED}; - -#[cfg_attr(not(msim), tokio::main)] -#[cfg_attr(msim, msim::main)] -pub async fn run_test(path: &Path) -> Result<(), Box> { - let (_guard, _filter_handle) = telemetry_subscribers::TelemetryConfig::new() - .with_env() - .init(); - run_test_impl::(path, Some(std::sync::Arc::new(PRE_COMPILED.clone()))).await?; - Ok(()) -} - -pub struct ValidatorWithFullnode { - pub validator: Arc, - pub fullnode: Arc, - pub kv_store: Arc, -} - -#[allow(unused_variables)] -/// TODO: better name? -#[async_trait::async_trait] -pub trait TransactionalAdapter: Send + Sync + ReadStore { - async fn execute_txn( - &mut self, - transaction: Transaction, - ) -> anyhow::Result<(TransactionEffects, Option)>; - - async fn read_input_objects(&self, transaction: Transaction) -> SuiResult; - - fn prepare_txn( - &self, - transaction: Transaction, - input_objects: InputObjects, - ) -> anyhow::Result<(TransactionEffects, Option)>; - - async fn create_checkpoint(&mut self) -> anyhow::Result; - - async fn advance_clock( - &mut self, - duration: std::time::Duration, - ) -> anyhow::Result; - - async fn advance_epoch(&mut self, create_random_state: bool) -> anyhow::Result<()>; - - async fn request_gas( - &mut self, - address: SuiAddress, - amount: u64, - ) -> anyhow::Result; - - async fn dev_inspect_transaction_block( - &self, - sender: SuiAddress, - transaction_kind: TransactionKind, - gas_price: Option, - ) -> SuiResult; - - async fn query_tx_events_asc( - &self, - tx_digest: &TransactionDigest, - limit: usize, - ) -> SuiResult>; - - async fn get_active_validator_addresses(&self) -> SuiResult>; -} - -#[async_trait::async_trait] -impl TransactionalAdapter for ValidatorWithFullnode { - async fn execute_txn( - &mut self, - transaction: Transaction, - ) -> anyhow::Result<(TransactionEffects, Option)> { - let with_shared = transaction - .data() - .intent_message() - .value - .contains_shared_object(); - let (_, effects, execution_error) = send_and_confirm_transaction_with_execution_error( - &self.validator, - Some(&self.fullnode), - transaction, - with_shared, - ) - .await?; - Ok((effects.into_data(), execution_error)) - } - - async fn read_input_objects(&self, transaction: Transaction) -> SuiResult { - let tx = VerifiedExecutableTransaction::new_unchecked( - ExecutableTransaction::new_from_data_and_sig( - transaction.data().clone(), - sui_types::executable_transaction::CertificateProof::Checkpoint(0, 0), - ), - ); - - let epoch_store = self.validator.load_epoch_store_one_call_per_task().clone(); - self.validator - .read_objects_for_benchmarking(&tx, &epoch_store) - .await - } - - fn prepare_txn( - &self, - transaction: Transaction, - input_objects: InputObjects, - ) -> anyhow::Result<(TransactionEffects, Option)> { - let tx = VerifiedExecutableTransaction::new_unchecked( - ExecutableTransaction::new_from_data_and_sig( - transaction.data().clone(), - sui_types::executable_transaction::CertificateProof::Checkpoint(0, 0), - ), - ); - - let epoch_store = self.validator.load_epoch_store_one_call_per_task().clone(); - let (_, effects, error) = - self.validator - .prepare_certificate_for_benchmark(&tx, input_objects, &epoch_store)?; - Ok((effects, error)) - } - - async fn dev_inspect_transaction_block( - &self, - sender: SuiAddress, - transaction_kind: TransactionKind, - gas_price: Option, - ) -> SuiResult { - self.fullnode - .dev_inspect_transaction_block( - sender, - transaction_kind, - gas_price, - None, - None, - None, - None, - None, - ) - .await - } - - async fn query_tx_events_asc( - &self, - tx_digest: &TransactionDigest, - limit: usize, - ) -> SuiResult> { - Ok(self - .validator - .query_events( - &self.kv_store, - EventFilter::Transaction(*tx_digest), - None, - limit, - false, - ) - .await - .unwrap_or_default() - .into_iter() - .map(|sui_event| sui_event.into()) - .collect()) - } - - async fn create_checkpoint(&mut self) -> anyhow::Result { - unimplemented!("create_checkpoint not supported") - } - - async fn advance_clock( - &mut self, - _duration: std::time::Duration, - ) -> anyhow::Result { - unimplemented!("advance_clock not supported") - } - - async fn advance_epoch(&mut self, _create_random_state: bool) -> anyhow::Result<()> { - unimplemented!("advance_epoch not supported") - } - - async fn request_gas( - &mut self, - _address: SuiAddress, - _amount: u64, - ) -> anyhow::Result { - unimplemented!("request_gas not supported") - } - - async fn get_active_validator_addresses(&self) -> SuiResult> { - Ok(self - .fullnode - .get_system_state() - .map_err(|e| { - SuiError::SuiSystemStateReadError(format!( - "Failed to get system state from fullnode: {}", - e - )) - })? - .into_sui_system_state_summary() - .active_validators - .iter() - .map(|x| x.sui_address) - .collect::>()) - } -} - -impl ReadStore for ValidatorWithFullnode { - fn get_committee( - &self, - _epoch: sui_types::committee::EpochId, - ) -> sui_types::storage::error::Result>> { - todo!() - } - - fn get_latest_checkpoint(&self) -> sui_types::storage::error::Result { - let sequence_number = self - .validator - .get_latest_checkpoint_sequence_number() - .unwrap(); - self.get_checkpoint_by_sequence_number(sequence_number) - .map(|c| c.unwrap()) - } - - fn get_highest_verified_checkpoint( - &self, - ) -> sui_types::storage::error::Result { - todo!() - } - - fn get_highest_synced_checkpoint( - &self, - ) -> sui_types::storage::error::Result { - todo!() - } - - fn get_lowest_available_checkpoint( - &self, - ) -> sui_types::storage::error::Result - { - todo!() - } - - fn get_checkpoint_by_digest( - &self, - _digest: &sui_types::messages_checkpoint::CheckpointDigest, - ) -> sui_types::storage::error::Result> { - todo!() - } - - fn get_checkpoint_by_sequence_number( - &self, - sequence_number: sui_types::messages_checkpoint::CheckpointSequenceNumber, - ) -> sui_types::storage::error::Result> { - self.validator - .get_checkpoint_store() - .get_checkpoint_by_sequence_number(sequence_number) - .map_err(sui_types::storage::error::Error::custom) - } - - fn get_checkpoint_contents_by_digest( - &self, - digest: &CheckpointContentsDigest, - ) -> sui_types::storage::error::Result> - { - self.validator - .get_checkpoint_store() - .get_checkpoint_contents(digest) - .map_err(sui_types::storage::error::Error::custom) - } - - fn get_checkpoint_contents_by_sequence_number( - &self, - _sequence_number: sui_types::messages_checkpoint::CheckpointSequenceNumber, - ) -> sui_types::storage::error::Result> - { - todo!() - } - - fn get_transaction( - &self, - tx_digest: &TransactionDigest, - ) -> sui_types::storage::error::Result>> - { - self.validator - .get_cache_reader() - .get_transaction_block(tx_digest) - .map_err(sui_types::storage::error::Error::custom) - } - - fn get_transaction_effects( - &self, - tx_digest: &TransactionDigest, - ) -> sui_types::storage::error::Result> { - self.validator - .get_cache_reader() - .get_executed_effects(tx_digest) - .map_err(sui_types::storage::error::Error::custom) - } - - fn get_events( - &self, - event_digest: &TransactionEventsDigest, - ) -> sui_types::storage::error::Result> { - self.validator - .get_cache_reader() - .get_events(event_digest) - .map_err(sui_types::storage::error::Error::custom) - } - - fn get_full_checkpoint_contents_by_sequence_number( - &self, - _sequence_number: sui_types::messages_checkpoint::CheckpointSequenceNumber, - ) -> sui_types::storage::error::Result< - Option, - > { - todo!() - } - - fn get_full_checkpoint_contents( - &self, - _digest: &CheckpointContentsDigest, - ) -> sui_types::storage::error::Result< - Option, - > { - todo!() - } -} - -impl ObjectStore for ValidatorWithFullnode { - fn get_object( - &self, - object_id: &ObjectID, - ) -> Result, sui_types::storage::error::Error> { - self.validator.get_object_store().get_object(object_id) - } - - fn get_object_by_key( - &self, - object_id: &ObjectID, - version: VersionNumber, - ) -> Result, sui_types::storage::error::Error> { - self.validator - .get_object_store() - .get_object_by_key(object_id, version) - } -} - -#[async_trait::async_trait] -impl TransactionalAdapter for Simulacrum { - async fn execute_txn( - &mut self, - transaction: Transaction, - ) -> anyhow::Result<(TransactionEffects, Option)> { - Ok(self.execute_transaction(transaction)?) - } - - async fn read_input_objects(&self, _transaction: Transaction) -> SuiResult { - unimplemented!("read_input_objects not supported in simulator mode") - } - - fn prepare_txn( - &self, - _transaction: Transaction, - _input_objects: InputObjects, - ) -> anyhow::Result<(TransactionEffects, Option)> { - unimplemented!("prepare_txn not supported in simulator mode") - } - - async fn dev_inspect_transaction_block( - &self, - _sender: SuiAddress, - _transaction_kind: TransactionKind, - _gas_price: Option, - ) -> SuiResult { - unimplemented!("dev_inspect_transaction_block not supported in simulator mode") - } - - async fn query_tx_events_asc( - &self, - tx_digest: &TransactionDigest, - _limit: usize, - ) -> SuiResult> { - Ok(self - .store() - .get_transaction_events_by_tx_digest(tx_digest) - .map(|x| x.data) - .unwrap_or_default()) - } - - async fn create_checkpoint(&mut self) -> anyhow::Result { - Ok(self.create_checkpoint()) - } - - async fn advance_clock( - &mut self, - duration: std::time::Duration, - ) -> anyhow::Result { - Ok(self.advance_clock(duration)) - } - - async fn advance_epoch(&mut self, create_random_state: bool) -> anyhow::Result<()> { - self.advance_epoch(create_random_state); - Ok(()) - } - - async fn request_gas( - &mut self, - address: SuiAddress, - amount: u64, - ) -> anyhow::Result { - self.request_gas(address, amount) - } - - async fn get_active_validator_addresses(&self) -> SuiResult> { - // TODO: this is a hack to get the validator addresses. Currently using start - // state but we should have a better way to get this information - // after reconfig - Ok(self.epoch_start_state().get_validator_addresses()) - } -} diff --git a/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/mod.rs b/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/mod.rs deleted file mode 100644 index e2c9d57dc37..00000000000 --- a/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod parser; -pub mod token; diff --git a/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/parser.rs b/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/parser.rs deleted file mode 100644 index 6ab0e682be3..00000000000 --- a/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/parser.rs +++ /dev/null @@ -1,410 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{borrow::BorrowMut, marker::PhantomData, str::FromStr}; - -use anyhow::{bail, Context, Result}; -use move_command_line_common::{ - parser::{Parser, Token}, - types::{ParsedType, TypeToken}, -}; -use move_core_types::{account_address::AccountAddress, identifier::Identifier}; -use sui_types::{ - base_types::ObjectID, - transaction::{Argument, Command, ProgrammableMoveCall}, -}; - -use super::token::CommandToken; -use crate::programmable_transaction_test_parser::token::{ - GAS_COIN, INPUT, MAKE_MOVE_VEC, MERGE_COINS, NESTED_RESULT, PUBLISH, RESULT, SPLIT_COINS, - TRANSFER_OBJECTS, UPGRADE, -}; - -/// A small parser used for parsing programmable transaction commands for -/// transactional tests -pub struct CommandParser< - 'a, - I: Iterator, - P: BorrowMut>, -> { - inner: P, - _a: PhantomData<&'a ()>, - _i: PhantomData, -} - -#[derive(Debug, Clone)] -pub struct ParsedMoveCall { - pub package: Identifier, - pub module: Identifier, - pub function: Identifier, - pub type_arguments: Vec, - pub arguments: Vec, -} - -#[derive(Debug, Clone)] -pub enum ParsedCommand { - MoveCall(Box), - TransferObjects(Vec, Argument), - SplitCoins(Argument, Vec), - MergeCoins(Argument, Vec), - MakeMoveVec(Option, Vec), - Publish(String, Vec), - Upgrade(String, Vec, String, Argument), -} - -impl<'a, I: Iterator> - CommandParser<'a, I, Parser<'a, CommandToken, I>> -{ - pub fn new>(v: T) -> Self { - Self::from_parser(Parser::new(v)) - } -} - -impl<'a, I, P> CommandParser<'a, I, P> -where - I: Iterator, - P: BorrowMut>, -{ - pub fn from_parser(inner: P) -> Self { - Self { - inner, - _a: PhantomData, - _i: PhantomData, - } - } - - pub fn parse_commands(&mut self) -> Result> { - let commands = self.inner().parse_list( - |p| CommandParser::from_parser(p).parse_command_start(), - CommandToken::Semi, - // not checked - CommandToken::Void, - // allow_trailing_delim - true, - )?; - let commands = commands - .into_iter() - .enumerate() - .map(|(actual, (annotated, c))| { - if let Some(annotated) = annotated { - if actual != annotated { - anyhow::bail!( - "Actual command index of {actual} \ - does not match annotated index {annotated}", - ); - } - } - Ok(c) - }) - .collect::>()?; - Ok(commands) - } - - pub fn parse_command_start(&mut self) -> Result<(Option, ParsedCommand)> { - self.inner().advance(CommandToken::CommandStart)?; - let idx = if let Some(CommandToken::Number) = self.inner().peek_tok() { - let num = self.inner().advance(CommandToken::Number)?; - let idx = usize::from_str(num).context("Invalid command index annotation")?; - self.inner().advance(CommandToken::Colon)?; - Some(idx) - } else { - None - }; - let cmd = self.parse_command()?; - Ok((idx, cmd)) - } - - pub fn parse_command(&mut self) -> Result { - use super::token::CommandToken as Tok; - Ok(match self.inner().advance_any()? { - (Tok::Ident, TRANSFER_OBJECTS) => { - self.inner().advance(Tok::LParen)?; - let args = self.parse_command_args(Tok::LBracket, Tok::RBracket)?; - self.inner().advance(Tok::Comma)?; - let arg = self.parse_command_arg()?; - self.maybe_trailing_comma()?; - self.inner().advance(Tok::RParen)?; - ParsedCommand::TransferObjects(args, arg) - } - (Tok::Ident, SPLIT_COINS) => { - self.inner().advance(Tok::LParen)?; - let coin = self.parse_command_arg()?; - self.inner().advance(Tok::Comma)?; - let amts = self.parse_command_args(Tok::LBracket, Tok::RBracket)?; - self.maybe_trailing_comma()?; - self.inner().advance(Tok::RParen)?; - ParsedCommand::SplitCoins(coin, amts) - } - (Tok::Ident, MERGE_COINS) => { - self.inner().advance(Tok::LParen)?; - let target = self.parse_command_arg()?; - self.inner().advance(Tok::Comma)?; - let coins = self.parse_command_args(Tok::LBracket, Tok::RBracket)?; - self.maybe_trailing_comma()?; - self.inner().advance(Tok::RParen)?; - ParsedCommand::MergeCoins(target, coins) - } - (Tok::Ident, MAKE_MOVE_VEC) => { - let type_opt = self.parse_type_arg_opt()?; - self.inner().advance(Tok::LParen)?; - let args = self.parse_command_args(Tok::LBracket, Tok::RBracket)?; - self.maybe_trailing_comma()?; - self.inner().advance(Tok::RParen)?; - ParsedCommand::MakeMoveVec(type_opt, args) - } - (Tok::Ident, PUBLISH) => { - self.inner().advance(Tok::LParen)?; - let staged_package = self.inner().advance(Tok::Ident)?; - self.inner().advance(Tok::Comma)?; - self.inner().advance(Tok::LBracket)?; - let dependencies = self.inner().parse_list( - |p| Ok(p.advance(Tok::Ident)?.to_owned()), - CommandToken::Comma, - Tok::RBracket, - // allow_trailing_delim - true, - )?; - self.inner().advance(Tok::RBracket)?; - self.maybe_trailing_comma()?; - self.inner().advance(Tok::RParen)?; - ParsedCommand::Publish(staged_package.to_owned(), dependencies) - } - (Tok::Ident, UPGRADE) => { - self.inner().advance(Tok::LParen)?; - let staged_package = self.inner().advance(Tok::Ident)?; - self.inner().advance(Tok::Comma)?; - self.inner().advance(Tok::LBracket)?; - let dependencies = self.inner().parse_list( - |p| Ok(p.advance(Tok::Ident)?.to_owned()), - CommandToken::Comma, - Tok::RBracket, - // allow_trailing_delim - true, - )?; - self.inner().advance(Tok::RBracket)?; - self.inner().advance(Tok::Comma)?; - let upgraded_package = self.inner().advance(Tok::Ident)?; - self.inner().advance(Tok::Comma)?; - let upgrade_ticket = self.parse_command_arg()?; - self.maybe_trailing_comma()?; - self.inner().advance(Tok::RParen)?; - ParsedCommand::Upgrade( - staged_package.to_owned(), - dependencies, - upgraded_package.to_owned(), - upgrade_ticket, - ) - } - (Tok::Ident, contents) => { - let package = Identifier::new(contents)?; - self.inner().advance(Tok::ColonColon)?; - let module = Identifier::new(self.inner().advance(Tok::Ident)?)?; - self.inner().advance(Tok::ColonColon)?; - let function = Identifier::new(self.inner().advance(Tok::Ident)?)?; - let type_arguments = self.parse_type_args_opt()?.unwrap_or_default(); - let arguments = self.parse_command_args(Tok::LParen, Tok::RParen)?; - let call = ParsedMoveCall { - package, - module, - function, - type_arguments, - arguments, - }; - ParsedCommand::MoveCall(Box::new(call)) - } - - (tok, _) => bail!("unexpected token {}, expected command identifier", tok), - }) - } - - pub fn maybe_trailing_comma(&mut self) -> Result<()> { - if let Some(CommandToken::Comma) = self.inner().peek_tok() { - self.inner().advance(CommandToken::Comma)?; - } - Ok(()) - } - - pub fn parse_command_args( - &mut self, - start: CommandToken, - end: CommandToken, - ) -> Result> { - self.inner().advance(start)?; - let args = self.inner().parse_list( - |p| CommandParser::from_parser(p).parse_command_arg(), - CommandToken::Comma, - end, - // allow_trailing_delim - true, - )?; - self.inner().advance(end)?; - Ok(args) - } - - pub fn parse_command_arg(&mut self) -> Result { - use super::token::CommandToken as Tok; - Ok(match self.inner().advance_any()? { - (Tok::Ident, GAS_COIN) => Argument::GasCoin, - (Tok::Ident, INPUT) => { - self.inner().advance(Tok::LParen)?; - let num = self.parse_u16()?; - self.maybe_trailing_comma()?; - self.inner().advance(Tok::RParen)?; - Argument::Input(num) - } - (Tok::Ident, RESULT) => { - self.inner().advance(Tok::LParen)?; - let num = self.parse_u16()?; - self.maybe_trailing_comma()?; - self.inner().advance(Tok::RParen)?; - Argument::Result(num) - } - (Tok::Ident, NESTED_RESULT) => { - self.inner().advance(Tok::LParen)?; - let i = self.parse_u16()?; - self.inner().advance(Tok::Comma)?; - let j = self.parse_u16()?; - self.maybe_trailing_comma()?; - self.inner().advance(Tok::RParen)?; - Argument::NestedResult(i, j) - } - (tok, _) => bail!("unexpected token {}, expected argument identifier", tok), - }) - } - - pub fn parse_u16(&mut self) -> Result { - let contents = self.inner().advance(CommandToken::Number)?; - u16::from_str(contents).context("Expected u16 for Argument") - } - - pub fn parse_type_arg_opt(&mut self) -> Result> { - match self.parse_type_args_opt()? { - None => Ok(None), - Some(v) if v.len() != 1 => bail!( - "unexpected multiple type arguments. Expected 1 type argument but got {}", - v.len() - ), - Some(mut v) => Ok(Some(v.pop().unwrap())), - } - } - - pub fn parse_type_args_opt(&mut self) -> Result>> { - if !matches!(self.inner().peek_tok(), Some(CommandToken::TypeArgString)) { - return Ok(None); - } - let contents = self.inner().advance(CommandToken::TypeArgString)?; - let type_tokens: Vec<_> = TypeToken::tokenize(contents)? - .into_iter() - .filter(|(tok, _)| !tok.is_whitespace()) - .collect(); - let mut parser = Parser::new(type_tokens); - parser.advance(TypeToken::Lt)?; - let res = parser.parse_list(|p| p.parse_type(), TypeToken::Comma, TypeToken::Gt, true)?; - parser.advance(TypeToken::Gt)?; - if let Ok((_, contents)) = parser.advance_any() { - bail!("Expected end of token stream. Got: {}", contents) - } - Ok(Some(res)) - } - - pub fn inner(&mut self) -> &mut Parser<'a, CommandToken, I> { - self.inner.borrow_mut() - } -} - -impl ParsedCommand { - pub fn parse_vec(s: &str) -> Result> { - let tokens: Vec<_> = CommandToken::tokenize(s)? - .into_iter() - .filter(|(tok, _)| !tok.is_whitespace()) - .collect(); - let mut parser = CommandParser::new(tokens); - let res = parser.parse_commands()?; - if let Ok((_, contents)) = parser.inner().advance_any() { - bail!("Expected end of token stream. Got: {}", contents) - } - Ok(res) - } - - pub fn into_command( - self, - staged_packages: &impl Fn(&str) -> Option>>, - address_mapping: &impl Fn(&str) -> Option, - ) -> Result { - Ok(match self { - ParsedCommand::MoveCall(c) => { - Command::MoveCall(Box::new(c.into_move_call(address_mapping)?)) - } - ParsedCommand::TransferObjects(objs, recipient) => { - Command::TransferObjects(objs, recipient) - } - ParsedCommand::SplitCoins(coin, amts) => Command::SplitCoins(coin, amts), - ParsedCommand::MergeCoins(target, coins) => Command::MergeCoins(target, coins), - ParsedCommand::MakeMoveVec(ty_opt, args) => Command::MakeMoveVec( - ty_opt - .map(|t| t.into_type_tag(address_mapping)) - .transpose()?, - args, - ), - ParsedCommand::Publish(staged_package, dependencies) => { - let Some(package_contents) = staged_packages(&staged_package) else { - bail!("No staged package '{staged_package}'"); - }; - let dependencies = dependencies - .into_iter() - .map(|d| match address_mapping(&d) { - Some(a) => Ok(a.into()), - None => bail!("Unbound dependency '{d}"), - }) - .collect::>>()?; - Command::Publish(package_contents, dependencies) - } - ParsedCommand::Upgrade(staged_package, dependencies, upgraded_package, ticket) => { - let Some(package_contents) = staged_packages(&staged_package) else { - bail!("No staged package '{staged_package}'"); - }; - let dependencies = dependencies - .into_iter() - .map(|d| match address_mapping(&d) { - Some(a) => Ok(a.into()), - None => bail!("Unbound dependency '{d}"), - }) - .collect::>>()?; - let Some(upgraded_package) = address_mapping(&upgraded_package) else { - bail!("Unbound upgraded package '{upgraded_package}'"); - }; - let upgraded_package = upgraded_package.into(); - Command::Upgrade(package_contents, dependencies, upgraded_package, ticket) - } - }) - } -} - -impl ParsedMoveCall { - pub fn into_move_call( - self, - address_mapping: &impl Fn(&str) -> Option, - ) -> Result { - let Self { - package, - module, - function, - type_arguments, - arguments, - } = self; - let Some(package) = address_mapping(package.as_str()) else { - bail!("Unable to resolve package {}", package) - }; - let type_arguments = type_arguments - .into_iter() - .map(|t| t.into_type_tag(address_mapping)) - .collect::>()?; - Ok(ProgrammableMoveCall { - package: package.into(), - module, - function, - type_arguments, - arguments, - }) - } -} diff --git a/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/token.rs b/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/token.rs deleted file mode 100644 index 145bc5347c4..00000000000 --- a/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/token.rs +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt::{self, Display}; - -use anyhow::bail; -use move_command_line_common::parser::Token; -use move_core_types::identifier; - -#[derive(Eq, PartialEq, Debug, Clone, Copy)] -pub enum CommandToken { - // any whitespace - Whitespace, - // // or /* */ - Comment, - // //> - CommandStart, - // alpha numeric - Ident, - // digits - Number, - // :: - ColonColon, - // : - Colon, - // , - Comma, - // ; - Semi, - // [ - LBracket, - // ] - RBracket, - // ( - LParen, - // ) - RParen, - // <...> - // eats the whole string, including the < and >, to pass to a different parser - TypeArgString, - // uninhabited token - Void, -} - -pub const TRANSFER_OBJECTS: &str = "TransferObjects"; -pub const SPLIT_COINS: &str = "SplitCoins"; -pub const MERGE_COINS: &str = "MergeCoins"; -pub const MAKE_MOVE_VEC: &str = "MakeMoveVec"; -pub const PUBLISH: &str = "Publish"; -pub const UPGRADE: &str = "Upgrade"; -pub const GAS_COIN: &str = "Gas"; -pub const INPUT: &str = "Input"; -pub const RESULT: &str = "Result"; -pub const NESTED_RESULT: &str = "NestedResult"; - -impl Display for CommandToken { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - let s = match *self { - CommandToken::Whitespace => "[whitespace]", - CommandToken::Comment => "[comment]", - CommandToken::Ident => "[identifier]", - CommandToken::Number => "[num]", - CommandToken::CommandStart => "//>", - CommandToken::ColonColon => "::", - CommandToken::Colon => ":", - CommandToken::Comma => ",", - CommandToken::Semi => ";", - CommandToken::LBracket => "[", - CommandToken::RBracket => "]", - CommandToken::LParen => "(", - CommandToken::RParen => ")", - CommandToken::TypeArgString => "<...>", - CommandToken::Void => "[void]", - }; - fmt::Display::fmt(s, formatter) - } -} - -impl Token for CommandToken { - fn is_whitespace(&self) -> bool { - matches!(self, Self::Whitespace | Self::Comment | Self::Void) - } - - fn next_token(s: &str) -> anyhow::Result> { - // parses a string where start matches end. - // performs simple matching for start/end pairs - - // type arguments get delegated to a different parser - if s.starts_with('<') { - let len = parse_sub_token_string(s, "<", ">")?; - return Ok(Some((Self::TypeArgString, len))); - } - // start of a command - if s.starts_with("//>") { - return Ok(Some((Self::CommandStart, 3))); - } - // comments - if let Some(after) = s.strip_prefix("//") { - let mut n = 2; - let mut in_whitespace_from_start = true; - for c in after.chars() { - n += 1; - if c == '\n' { - break; - } - if in_whitespace_from_start && c == '>' { - bail!("Remove whitespace between // and > to start a command"); - } - if !c.is_whitespace() { - in_whitespace_from_start = false; - } - } - return Ok(Some((Self::Comment, n))); - } - if s.starts_with("/*") { - let end = parse_sub_token_string(s, "/*", "*/")?; - return Ok(Some((Self::Comment, end))); - } - - // other tokens - let mut chars = s.chars().peekable(); - let c = match chars.next() { - None => return Ok(None), - Some(c) => c, - }; - Ok(Some(match c { - '(' => (Self::LParen, 1), - ')' => (Self::RParen, 1), - '[' => (Self::LBracket, 1), - ']' => (Self::RBracket, 1), - ',' => (Self::Comma, 1), - ';' => (Self::Semi, 1), - ':' if matches!(chars.peek(), Some(':')) => (Self::ColonColon, 2), - ':' => (Self::Colon, 1), - c if c.is_ascii_whitespace() => { - // c + remaining - let len = 1 + chars.take_while(char::is_ascii_whitespace).count(); - (Self::Whitespace, len) - } - c if c.is_ascii_digit() => { - // c + remaining - let len = 1 + chars - .take_while(|c| char::is_ascii_digit(c) || *c == '_') - .count(); - (CommandToken::Number, len) - } - c if c.is_ascii_alphabetic() || c == '_' => { - // c + remaining - let len = 1 + chars - .take_while(|c| identifier::is_valid_identifier_char(*c)) - .count(); - (Self::Ident, len) - } - _ => bail!("unrecognized token: {}", s), - })) - } -} - -fn parse_sub_token_string(mut s: &str, start: &str, end: &str) -> anyhow::Result { - // the length of the string until the matching end - let mut len = 0; - let start_len = start.len(); - let end_len = end.len(); - // the count of number of active start/end pairs - let mut count = 0i32; - loop { - s = if s.is_empty() { - bail!("Unexpected end of string after '{start}'. Expected matching '{end}'") - } else if let Some(next) = s.strip_prefix(start) { - len += start_len; - // new start - count += 1; - next - } else if let Some(next) = s.strip_prefix(end) { - len += end_len; - // an end - count -= 1; - if count == 0 { - // end found - break; - } - next - } else { - len += 1; - &s[1..] - } - } - Ok(len) -} diff --git a/crates/sui-types/Cargo.toml b/crates/sui-types/Cargo.toml deleted file mode 100644 index fc365544237..00000000000 --- a/crates/sui-types/Cargo.toml +++ /dev/null @@ -1,90 +0,0 @@ -[package] -name = "sui-types" -version = "0.1.0" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anemo.workspace = true -anyhow.workspace = true -bincode.workspace = true -bcs.workspace = true -byteorder.workspace = true -consensus-config.workspace = true -im.workspace = true -itertools.workspace = true -nonempty.workspace = true -once_cell.workspace = true -prometheus.workspace = true -rand.workspace = true -serde.workspace = true -serde-name.workspace = true -thiserror.workspace = true -tracing.workspace = true -serde_json.workspace = true -serde_with.workspace = true -signature.workspace = true -static_assertions.workspace = true -schemars.workspace = true -tap.workspace = true -tonic.workspace = true -strum.workspace = true -strum_macros.workspace = true -roaring.workspace = true -enum_dispatch.workspace = true -eyre.workspace = true -indexmap.workspace = true -derivative.workspace = true -move-binary-format.workspace = true -move-bytecode-utils.workspace = true -move-command-line-common.workspace = true -move-core-types.workspace = true -move-disassembler.workspace = true -move-ir-types.workspace = true -move-vm-test-utils.workspace = true -move-vm-types.workspace = true -move-vm-profiler.workspace = true -num-traits = "0.2.18" -num-bigint = { version = "0.4", default-features = false, features = ["rand"] } - -narwhal-config.workspace = true -narwhal-crypto.workspace = true -sui-protocol-config.workspace = true -shared-crypto.workspace = true -mysten-network.workspace = true -mysten-metrics.workspace = true -sui-macros.workspace = true -sui-enum-compat-util.workspace = true - -fastcrypto = { workspace = true, features = ["copy_key"] } -fastcrypto-tbls.workspace = true -fastcrypto-zkp.workspace = true - -typed-store-error.workspace = true -derive_more.workspace = true -proptest.workspace = true -proptest-derive.workspace = true - -[dev-dependencies] -bincode.workspace = true -criterion.workspace = true -proptest.workspace = true -proptest-derive.workspace = true -serde_yaml.workspace = true -expect-test.workspace = true - -[[bench]] -name = "accumulator_bench" -harness = false - -[features] -default = [] -test-utils = [] -gas-profiler = [ - "move-vm-profiler/gas-profiler", - "move-vm-types/gas-profiler", - "move-vm-test-utils/gas-profiler", -] -fuzzing = ["move-core-types/fuzzing"] diff --git a/crates/sui-types/src/README.md b/crates/sui-types/src/README.md deleted file mode 100644 index 429d160fe68..00000000000 --- a/crates/sui-types/src/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# sui-types README - -Note: this README file currently covers cryptography-related structs and methods. - -Currently, three files are equipped with signature and hashing functionality (`crypto.rs`, `signature_seed` and -`messages.rs`). See [Sui Signatures](https://github.com/MystenLabs/sui/blob/main/docs/content/concepts/cryptography/transaction-auth/signatures.mdx) for supported signature schemes and its requirments for user and authority signatures. See [fastcrypto](https://github.com/MystenLabs/fastcrypto) for concrete implementation of various cryptography libraries. - -## Quick links - -- [crypto.rs](crypto.rs), the main library for cryptography (sign/verify/hash) structs and functions. -- [signature_seed.rs](signature_seed.rs), deterministic signer using a seed, domain and some key identifier. Potential - usage includes custodial services, in which user keys are not deterministically derived from BIP44/BIP32, but from their - username (i.e., email address). -- [messages.rs](messages.rs), functionality for adding/verifying signatures to transactions (for both account holders - and validators). - -## Tests - -Unit tests exist under the `unit_tests` folder, in particular - -- `messages_tests`: to handle signed values, aggregation and certificates. -- `signature_seed_tests`: for deterministic key derivation functionality. diff --git a/crates/sui-types/src/balance.rs b/crates/sui-types/src/balance.rs deleted file mode 100644 index bf9b25af3b6..00000000000 --- a/crates/sui-types/src/balance.rs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use move_core_types::{ - annotated_value::{MoveFieldLayout, MoveStructLayout, MoveTypeLayout}, - ident_str, - identifier::IdentStr, - language_storage::{StructTag, TypeTag}, -}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; - -use crate::{ - error::{ExecutionError, ExecutionErrorKind}, - sui_serde::{BigInt, Readable}, - SUI_FRAMEWORK_ADDRESS, -}; -pub const BALANCE_MODULE_NAME: &IdentStr = ident_str!("balance"); -pub const BALANCE_STRUCT_NAME: &IdentStr = ident_str!("Balance"); -pub const BALANCE_CREATE_REWARDS_FUNCTION_NAME: &IdentStr = ident_str!("create_staking_rewards"); -pub const BALANCE_DESTROY_REBATES_FUNCTION_NAME: &IdentStr = ident_str!("destroy_storage_rebates"); - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, JsonSchema)] -pub struct Supply { - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub value: u64, -} - -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema, Eq, PartialEq)] -pub struct Balance { - value: u64, -} - -impl Balance { - pub fn new(value: u64) -> Self { - Self { value } - } - - pub fn type_(type_param: TypeTag) -> StructTag { - StructTag { - address: SUI_FRAMEWORK_ADDRESS, - module: BALANCE_MODULE_NAME.to_owned(), - name: BALANCE_STRUCT_NAME.to_owned(), - type_params: vec![type_param], - } - } - - pub fn is_balance(s: &StructTag) -> bool { - s.address == SUI_FRAMEWORK_ADDRESS - && s.module.as_ident_str() == BALANCE_MODULE_NAME - && s.name.as_ident_str() == BALANCE_STRUCT_NAME - } - - pub fn withdraw(&mut self, amount: u64) -> Result<(), ExecutionError> { - fp_ensure!( - self.value >= amount, - ExecutionError::new_with_source( - ExecutionErrorKind::InsufficientCoinBalance, - format!("balance: {} required: {}", self.value, amount) - ) - ); - self.value -= amount; - Ok(()) - } - - pub fn deposit_for_safe_mode(&mut self, amount: u64) { - self.value += amount; - } - - pub fn value(&self) -> u64 { - self.value - } - - pub fn to_bcs_bytes(&self) -> Vec { - bcs::to_bytes(&self).unwrap() - } - - pub fn layout(type_param: TypeTag) -> MoveStructLayout { - MoveStructLayout { - type_: Self::type_(type_param), - fields: vec![MoveFieldLayout::new( - ident_str!("value").to_owned(), - MoveTypeLayout::U64, - )], - } - } -} diff --git a/crates/sui-types/src/bridge.rs b/crates/sui-types/src/bridge.rs deleted file mode 100644 index dce224b429f..00000000000 --- a/crates/sui-types/src/bridge.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use move_core_types::{ident_str, identifier::IdentStr}; - -use crate::{ - base_types::SequenceNumber, error::SuiResult, object::Owner, storage::ObjectStore, - SUI_BRIDGE_OBJECT_ID, -}; - -pub const BRIDGE_MODULE_NAME: &IdentStr = ident_str!("bridge"); -pub const BRIDGE_CREATE_FUNCTION_NAME: &IdentStr = ident_str!("create"); - -pub const BRIDGE_SUPPORTED_ASSET: &[&str] = &["btc", "eth", "usdc", "usdt"]; - -pub fn get_bridge_obj_initial_shared_version( - object_store: &dyn ObjectStore, -) -> SuiResult> { - Ok(object_store - .get_object(&SUI_BRIDGE_OBJECT_ID)? - .map(|obj| match obj.owner { - Owner::Shared { - initial_shared_version, - } => initial_shared_version, - _ => unreachable!("Bridge object must be shared"), - })) -} diff --git a/crates/sui-types/src/coin.rs b/crates/sui-types/src/coin.rs deleted file mode 100644 index 1cb58e42e29..00000000000 --- a/crates/sui-types/src/coin.rs +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use move_core_types::{ - annotated_value::{MoveFieldLayout, MoveStructLayout, MoveTypeLayout}, - ident_str, - identifier::IdentStr, - language_storage::{StructTag, TypeTag}, -}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; - -use crate::{ - balance::{Balance, Supply}, - base_types::ObjectID, - error::{ExecutionError, ExecutionErrorKind, SuiError}, - id::UID, - object::{Data, Object}, - SUI_FRAMEWORK_ADDRESS, -}; - -pub const COIN_MODULE_NAME: &IdentStr = ident_str!("coin"); -pub const COIN_STRUCT_NAME: &IdentStr = ident_str!("Coin"); -pub const COIN_METADATA_STRUCT_NAME: &IdentStr = ident_str!("CoinMetadata"); -pub const COIN_TREASURE_CAP_NAME: &IdentStr = ident_str!("TreasuryCap"); - -pub const PAY_MODULE_NAME: &IdentStr = ident_str!("pay"); -pub const PAY_JOIN_FUNC_NAME: &IdentStr = ident_str!("join"); -pub const PAY_SPLIT_N_FUNC_NAME: &IdentStr = ident_str!("divide_and_keep"); -pub const PAY_SPLIT_VEC_FUNC_NAME: &IdentStr = ident_str!("split_vec"); - -// Rust version of the Move sui::coin::Coin type -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema, Eq, PartialEq)] -pub struct Coin { - pub id: UID, - pub balance: Balance, -} - -impl Coin { - pub fn new(id: UID, value: u64) -> Self { - Self { - id, - balance: Balance::new(value), - } - } - - pub fn type_(type_param: TypeTag) -> StructTag { - StructTag { - address: SUI_FRAMEWORK_ADDRESS, - name: COIN_STRUCT_NAME.to_owned(), - module: COIN_MODULE_NAME.to_owned(), - type_params: vec![type_param], - } - } - - /// Is this other StructTag representing a Coin? - pub fn is_coin(other: &StructTag) -> bool { - other.address == SUI_FRAMEWORK_ADDRESS - && other.module.as_ident_str() == COIN_MODULE_NAME - && other.name.as_ident_str() == COIN_STRUCT_NAME - } - - /// Create a coin from BCS bytes - pub fn from_bcs_bytes(content: &[u8]) -> Result { - bcs::from_bytes(content) - } - - /// If the given object is a Coin, deserialize its contents and extract the - /// balance Ok(Some(u64)). If it's not a Coin, return Ok(None). - /// The cost is 2 comparisons if not a coin, and deserialization if its a - /// Coin. - pub fn extract_balance_if_coin(object: &Object) -> Result, bcs::Error> { - match &object.data { - Data::Move(move_obj) => { - if !move_obj.is_coin() { - return Ok(None); - } - - let coin = Self::from_bcs_bytes(move_obj.contents())?; - Ok(Some(coin.value())) - } - _ => Ok(None), // package - } - } - - pub fn id(&self) -> &ObjectID { - self.id.object_id() - } - - pub fn value(&self) -> u64 { - self.balance.value() - } - - pub fn to_bcs_bytes(&self) -> Vec { - bcs::to_bytes(&self).unwrap() - } - - pub fn layout(type_param: TypeTag) -> MoveStructLayout { - MoveStructLayout { - type_: Self::type_(type_param.clone()), - fields: vec![ - MoveFieldLayout::new( - ident_str!("id").to_owned(), - MoveTypeLayout::Struct(UID::layout()), - ), - MoveFieldLayout::new( - ident_str!("balance").to_owned(), - MoveTypeLayout::Struct(Balance::layout(type_param)), - ), - ], - } - } - - /// Add balance to this coin, erroring if the new total balance exceeds the - /// maximum - pub fn add(&mut self, balance: Balance) -> Result<(), ExecutionError> { - let Some(new_value) = self.value().checked_add(balance.value()) else { - return Err(ExecutionError::from_kind( - ExecutionErrorKind::CoinBalanceOverflow, - )); - }; - self.balance = Balance::new(new_value); - Ok(()) - } - - // Split amount out of this coin to a new coin. - // Related coin objects need to be updated in temporary_store to persist the - // changes, including creating the coin object related to the newly created - // coin. - pub fn split(&mut self, amount: u64, new_coin_id: UID) -> Result { - self.balance.withdraw(amount)?; - Ok(Coin::new(new_coin_id, amount)) - } -} - -// Rust version of the Move sui::coin::TreasuryCap type -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, JsonSchema)] -pub struct TreasuryCap { - pub id: UID, - pub total_supply: Supply, -} - -impl TreasuryCap { - pub fn is_treasury_type(other: &StructTag) -> bool { - other.address == SUI_FRAMEWORK_ADDRESS - && other.module.as_ident_str() == COIN_MODULE_NAME - && other.name.as_ident_str() == COIN_TREASURE_CAP_NAME - } - - /// Create a TreasuryCap from BCS bytes - pub fn from_bcs_bytes(content: &[u8]) -> Result { - bcs::from_bytes(content).map_err(|err| SuiError::ObjectDeserializationError { - error: format!("Unable to deserialize TreasuryCap object: {}", err), - }) - } - - pub fn type_(type_param: StructTag) -> StructTag { - StructTag { - address: SUI_FRAMEWORK_ADDRESS, - name: COIN_TREASURE_CAP_NAME.to_owned(), - module: COIN_MODULE_NAME.to_owned(), - type_params: vec![TypeTag::Struct(Box::new(type_param))], - } - } -} - -impl TryFrom for TreasuryCap { - type Error = SuiError; - fn try_from(object: Object) -> Result { - match &object.data { - Data::Move(o) => { - if o.type_().is_treasury_cap() { - return TreasuryCap::from_bcs_bytes(o.contents()); - } - } - Data::Package(_) => {} - } - - Err(SuiError::TypeError { - error: format!("Object type is not a TreasuryCap: {:?}", object), - }) - } -} - -// Rust version of the Move sui::coin::CoinMetadata type -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema, Eq, PartialEq)] -pub struct CoinMetadata { - pub id: UID, - /// Number of decimal places the coin uses. - pub decimals: u8, - /// Name for the token - pub name: String, - /// Symbol for the token - pub symbol: String, - /// Description of the token - pub description: String, - /// URL for the token logo - pub icon_url: Option, -} - -impl CoinMetadata { - /// Is this other StructTag representing a CoinMetadata? - pub fn is_coin_metadata(other: &StructTag) -> bool { - other.address == SUI_FRAMEWORK_ADDRESS - && other.module.as_ident_str() == COIN_MODULE_NAME - && other.name.as_ident_str() == COIN_METADATA_STRUCT_NAME - } - - /// Create a coin from BCS bytes - pub fn from_bcs_bytes(content: &[u8]) -> Result { - bcs::from_bytes(content).map_err(|err| SuiError::ObjectDeserializationError { - error: format!("Unable to deserialize CoinMetadata object: {}", err), - }) - } - - pub fn type_(type_param: StructTag) -> StructTag { - StructTag { - address: SUI_FRAMEWORK_ADDRESS, - name: COIN_METADATA_STRUCT_NAME.to_owned(), - module: COIN_MODULE_NAME.to_owned(), - type_params: vec![TypeTag::Struct(Box::new(type_param))], - } - } -} - -impl TryFrom for CoinMetadata { - type Error = SuiError; - fn try_from(object: Object) -> Result { - TryFrom::try_from(&object) - } -} - -impl TryFrom<&Object> for CoinMetadata { - type Error = SuiError; - fn try_from(object: &Object) -> Result { - match &object.data { - Data::Move(o) => { - if o.type_().is_coin_metadata() { - return CoinMetadata::from_bcs_bytes(o.contents()); - } - } - Data::Package(_) => {} - } - - Err(SuiError::TypeError { - error: format!("Object type is not a CoinMetadata: {:?}", object), - }) - } -} diff --git a/crates/sui-types/src/crypto.rs b/crates/sui-types/src/crypto.rs deleted file mode 100644 index 2c5c613fe3f..00000000000 --- a/crates/sui-types/src/crypto.rs +++ /dev/null @@ -1,1770 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -use std::{ - collections::BTreeMap, - fmt::{self, Debug, Display, Formatter}, - hash::{Hash, Hasher}, - str::FromStr, -}; - -use anyhow::{anyhow, Error}; -use derive_more::{AsMut, AsRef, From}; -pub use enum_dispatch::enum_dispatch; -use eyre::eyre; -pub use fastcrypto::traits::{ - AggregateAuthenticator, Authenticator, EncodeDecodeBase64, KeyPair as KeypairTraits, Signer, - SigningKey, ToFromBytes, VerifyingKey, -}; -use fastcrypto::{ - bls12381::min_sig::{ - BLS12381AggregateSignature, BLS12381AggregateSignatureAsBytes, BLS12381KeyPair, - BLS12381PrivateKey, BLS12381PublicKey, BLS12381Signature, - }, - ed25519::{ - Ed25519KeyPair, Ed25519PrivateKey, Ed25519PublicKey, Ed25519PublicKeyAsBytes, - Ed25519Signature, Ed25519SignatureAsBytes, - }, - encoding::{Base64, Bech32, Encoding, Hex}, - error::FastCryptoError, - hash::{Blake2b256, HashFunction}, - secp256k1::{ - Secp256k1KeyPair, Secp256k1PublicKey, Secp256k1PublicKeyAsBytes, Secp256k1Signature, - Secp256k1SignatureAsBytes, - }, - secp256r1::{ - Secp256r1KeyPair, Secp256r1PublicKey, Secp256r1PublicKeyAsBytes, Secp256r1Signature, - Secp256r1SignatureAsBytes, - }, -}; -use fastcrypto_zkp::{bn254::zk_login::ZkLoginInputs, zk_login_utils::Bn254FrElement}; -use rand::{ - rngs::{OsRng, StdRng}, - SeedableRng, -}; -use roaring::RoaringBitmap; -use schemars::JsonSchema; -use serde::{ser::Serializer, Deserialize, Deserializer, Serialize}; -use serde_with::{serde_as, Bytes}; -use shared_crypto::intent::{Intent, IntentMessage, IntentScope}; -use strum::EnumString; -use tracing::{instrument, warn}; - -use crate::{ - base_types::{AuthorityName, ConciseableName, SuiAddress}, - committee::{Committee, CommitteeTrait, EpochId, StakeUnit}, - error::{SuiError, SuiResult}, - signature::GenericSignature, - sui_serde::{Readable, SuiBitmap}, -}; - -#[cfg(test)] -#[path = "unit_tests/crypto_tests.rs"] -mod crypto_tests; - -#[cfg(test)] -#[cfg(feature = "test-utils")] -#[path = "unit_tests/intent_tests.rs"] -mod intent_tests; - -// Authority Objects -pub type AuthorityKeyPair = BLS12381KeyPair; -pub type AuthorityPublicKey = BLS12381PublicKey; -pub type AuthorityPrivateKey = BLS12381PrivateKey; -pub type AuthoritySignature = BLS12381Signature; -pub type AggregateAuthoritySignature = BLS12381AggregateSignature; -pub type AggregateAuthoritySignatureAsBytes = BLS12381AggregateSignatureAsBytes; - -// TODO(joyqvq): prefix these types with Default, DefaultAccountKeyPair etc -pub type AccountKeyPair = Ed25519KeyPair; -pub type AccountPublicKey = Ed25519PublicKey; -pub type AccountPrivateKey = Ed25519PrivateKey; - -pub type NetworkKeyPair = Ed25519KeyPair; -pub type NetworkPublicKey = Ed25519PublicKey; -pub type NetworkPrivateKey = Ed25519PrivateKey; - -pub type DefaultHash = Blake2b256; - -pub const DEFAULT_EPOCH_ID: EpochId = 0; -pub const SUI_PRIV_KEY_PREFIX: &str = "suiprivkey"; - -/// Creates a proof of that the authority account address is owned by the -/// holder of authority protocol key, and also ensures that the authority -/// protocol public key exists. A proof of possession is an authority -/// signature committed over the intent message `intent || message || epoch` -/// (See more at [struct IntentMessage] and [struct Intent]) where the message -/// is constructed as `authority_pubkey_bytes || authority_account_address`. -pub fn generate_proof_of_possession( - keypair: &AuthorityKeyPair, - address: SuiAddress, -) -> AuthoritySignature { - let mut msg: Vec = Vec::new(); - msg.extend_from_slice(keypair.public().as_bytes()); - msg.extend_from_slice(address.as_ref()); - AuthoritySignature::new_secure( - &IntentMessage::new(Intent::sui_app(IntentScope::ProofOfPossession), msg), - &DEFAULT_EPOCH_ID, - keypair, - ) -} - -/// Verify proof of possession against the expected intent message, -/// consisting of the protocol pubkey and the authority account address. -pub fn verify_proof_of_possession( - pop: &narwhal_crypto::Signature, - protocol_pubkey: &narwhal_crypto::PublicKey, - sui_address: SuiAddress, -) -> Result<(), SuiError> { - protocol_pubkey - .validate() - .map_err(|_| SuiError::InvalidSignature { - error: "Fail to validate pubkey".to_string(), - })?; - let mut msg = protocol_pubkey.as_bytes().to_vec(); - msg.extend_from_slice(sui_address.as_ref()); - pop.verify_secure( - &IntentMessage::new(Intent::sui_app(IntentScope::ProofOfPossession), msg), - DEFAULT_EPOCH_ID, - protocol_pubkey.into(), - ) -} -/////////////////////////////////////////////// -/// Account Keys -/// -/// * The following section defines the keypairs that are used by -/// * accounts to interact with Sui. -/// * Currently we support eddsa and ecdsa on Sui. - -#[allow(clippy::large_enum_variant)] -#[derive(Debug, From, PartialEq, Eq)] -pub enum SuiKeyPair { - Ed25519(Ed25519KeyPair), - Secp256k1(Secp256k1KeyPair), - Secp256r1(Secp256r1KeyPair), -} - -impl SuiKeyPair { - pub fn public(&self) -> PublicKey { - match self { - SuiKeyPair::Ed25519(kp) => PublicKey::Ed25519(kp.public().into()), - SuiKeyPair::Secp256k1(kp) => PublicKey::Secp256k1(kp.public().into()), - SuiKeyPair::Secp256r1(kp) => PublicKey::Secp256r1(kp.public().into()), - } - } -} - -impl Signer for SuiKeyPair { - fn sign(&self, msg: &[u8]) -> Signature { - match self { - SuiKeyPair::Ed25519(kp) => kp.sign(msg), - SuiKeyPair::Secp256k1(kp) => kp.sign(msg), - SuiKeyPair::Secp256r1(kp) => kp.sign(msg), - } - } -} - -impl EncodeDecodeBase64 for SuiKeyPair { - fn encode_base64(&self) -> String { - Base64::encode(self.to_bytes()) - } - - fn decode_base64(value: &str) -> Result { - let bytes = Base64::decode(value).map_err(|e| eyre!("{}", e.to_string()))?; - Self::from_bytes(&bytes) - } -} -impl SuiKeyPair { - pub fn to_bytes(&self) -> Vec { - let mut bytes: Vec = Vec::new(); - bytes.push(self.public().flag()); - - match self { - SuiKeyPair::Ed25519(kp) => { - bytes.extend_from_slice(kp.as_bytes()); - } - SuiKeyPair::Secp256k1(kp) => { - bytes.extend_from_slice(kp.as_bytes()); - } - SuiKeyPair::Secp256r1(kp) => { - bytes.extend_from_slice(kp.as_bytes()); - } - } - bytes - } - - pub fn from_bytes(bytes: &[u8]) -> Result { - match SignatureScheme::from_flag_byte(bytes.first().ok_or_else(|| eyre!("Invalid length"))?) - { - Ok(x) => match x { - SignatureScheme::ED25519 => Ok(SuiKeyPair::Ed25519(Ed25519KeyPair::from_bytes( - bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?, - )?)), - SignatureScheme::Secp256k1 => { - Ok(SuiKeyPair::Secp256k1(Secp256k1KeyPair::from_bytes( - bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?, - )?)) - } - SignatureScheme::Secp256r1 => { - Ok(SuiKeyPair::Secp256r1(Secp256r1KeyPair::from_bytes( - bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?, - )?)) - } - _ => Err(eyre!("Invalid flag byte")), - }, - _ => Err(eyre!("Invalid bytes")), - } - } - /// Encode a SuiKeyPair as `flag || privkey` in Bech32 starting with - /// "suiprivkey" to a string. Note that the pubkey is not encoded. - pub fn encode(&self) -> Result { - Bech32::encode(self.to_bytes(), SUI_PRIV_KEY_PREFIX) - } - - /// Decode a SuiKeyPair from `flag || privkey` in Bech32 starting with - /// "suiprivkey" to SuiKeyPair. The public key is computed directly from the - /// private key bytes. - pub fn decode(value: &str) -> Result { - let bytes = Bech32::decode(value, SUI_PRIV_KEY_PREFIX)?; - Self::from_bytes(&bytes) - } -} - -impl Serialize for SuiKeyPair { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let s = self.encode_base64(); - serializer.serialize_str(&s) - } -} - -impl<'de> Deserialize<'de> for SuiKeyPair { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - use serde::de::Error; - let s = String::deserialize(deserializer)?; - SuiKeyPair::decode_base64(&s).map_err(|e| Error::custom(e.to_string())) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, Serialize, Deserialize)] -pub enum PublicKey { - Ed25519(Ed25519PublicKeyAsBytes), - Secp256k1(Secp256k1PublicKeyAsBytes), - Secp256r1(Secp256r1PublicKeyAsBytes), - ZkLogin(ZkLoginPublicIdentifier), -} - -/// A wrapper struct to retrofit in [enum PublicKey] for zkLogin. -/// Useful to construct [struct MultiSigPublicKey]. -#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, Serialize, Deserialize)] -pub struct ZkLoginPublicIdentifier(#[schemars(with = "Base64")] pub Vec); - -impl ZkLoginPublicIdentifier { - /// Consists of iss_bytes_len || iss_bytes || padded_32_byte_address_seed. - pub fn new(iss: &str, address_seed: &Bn254FrElement) -> SuiResult { - let mut bytes = Vec::new(); - let iss_bytes = iss.as_bytes(); - bytes.extend([iss_bytes.len() as u8]); - bytes.extend(iss_bytes); - bytes.extend(address_seed.padded()); - - Ok(Self(bytes)) - } -} -impl AsRef<[u8]> for PublicKey { - fn as_ref(&self) -> &[u8] { - match self { - PublicKey::Ed25519(pk) => &pk.0, - PublicKey::Secp256k1(pk) => &pk.0, - PublicKey::Secp256r1(pk) => &pk.0, - PublicKey::ZkLogin(z) => &z.0, - } - } -} - -impl EncodeDecodeBase64 for PublicKey { - fn encode_base64(&self) -> String { - let mut bytes: Vec = Vec::new(); - bytes.extend_from_slice(&[self.flag()]); - bytes.extend_from_slice(self.as_ref()); - Base64::encode(&bytes[..]) - } - - fn decode_base64(value: &str) -> Result { - let bytes = Base64::decode(value).map_err(|e| eyre!("{}", e.to_string()))?; - match bytes.first() { - Some(x) => { - if x == &SignatureScheme::ED25519.flag() { - let pk: Ed25519PublicKey = Ed25519PublicKey::from_bytes( - bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?, - )?; - Ok(PublicKey::Ed25519((&pk).into())) - } else if x == &SignatureScheme::Secp256k1.flag() { - let pk = Secp256k1PublicKey::from_bytes( - bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?, - )?; - Ok(PublicKey::Secp256k1((&pk).into())) - } else if x == &SignatureScheme::Secp256r1.flag() { - let pk = Secp256r1PublicKey::from_bytes( - bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?, - )?; - Ok(PublicKey::Secp256r1((&pk).into())) - } else { - Err(eyre!("Invalid flag byte")) - } - } - _ => Err(eyre!("Invalid bytes")), - } - } -} - -impl PublicKey { - pub fn flag(&self) -> u8 { - self.scheme().flag() - } - - pub fn try_from_bytes( - curve: SignatureScheme, - key_bytes: &[u8], - ) -> Result { - match curve { - SignatureScheme::ED25519 => Ok(PublicKey::Ed25519( - (&Ed25519PublicKey::from_bytes(key_bytes)?).into(), - )), - SignatureScheme::Secp256k1 => Ok(PublicKey::Secp256k1( - (&Secp256k1PublicKey::from_bytes(key_bytes)?).into(), - )), - SignatureScheme::Secp256r1 => Ok(PublicKey::Secp256r1( - (&Secp256r1PublicKey::from_bytes(key_bytes)?).into(), - )), - _ => Err(eyre!("Unsupported curve")), - } - } - - pub fn scheme(&self) -> SignatureScheme { - match self { - PublicKey::Ed25519(_) => Ed25519SuiSignature::SCHEME, - PublicKey::Secp256k1(_) => Secp256k1SuiSignature::SCHEME, - PublicKey::Secp256r1(_) => Secp256r1SuiSignature::SCHEME, - PublicKey::ZkLogin(_) => SignatureScheme::ZkLoginAuthenticator, - } - } - - pub fn from_zklogin_inputs(inputs: &ZkLoginInputs) -> SuiResult { - Ok(PublicKey::ZkLogin(ZkLoginPublicIdentifier::new( - inputs.get_iss(), - inputs.get_address_seed(), - )?)) - } -} - -/// Defines the compressed version of the public key that we pass around -/// in Sui -#[serde_as] -#[derive( - Copy, - Clone, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - Serialize, - Deserialize, - schemars::JsonSchema, - AsRef, -)] -#[as_ref(forward)] -pub struct AuthorityPublicKeyBytes( - #[schemars(with = "Base64")] - #[serde_as(as = "Readable")] - pub [u8; AuthorityPublicKey::LENGTH], -); - -impl AuthorityPublicKeyBytes { - fn fmt_impl(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - let s = Hex::encode(self.0); - write!(f, "k#{}", s)?; - Ok(()) - } -} - -impl<'a> ConciseableName<'a> for AuthorityPublicKeyBytes { - type ConciseTypeRef = ConciseAuthorityPublicKeyBytesRef<'a>; - type ConciseType = ConciseAuthorityPublicKeyBytes; - - /// Get a ConciseAuthorityPublicKeyBytesRef. Usage: - /// - /// debug!(name = ?authority.concise()); - /// format!("{:?}", authority.concise()); - fn concise(&'a self) -> ConciseAuthorityPublicKeyBytesRef<'a> { - ConciseAuthorityPublicKeyBytesRef(self) - } - - fn concise_owned(&self) -> ConciseAuthorityPublicKeyBytes { - ConciseAuthorityPublicKeyBytes(*self) - } -} - -/// A wrapper around AuthorityPublicKeyBytes that provides a concise Debug impl. -pub struct ConciseAuthorityPublicKeyBytesRef<'a>(&'a AuthorityPublicKeyBytes); - -impl Debug for ConciseAuthorityPublicKeyBytesRef<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - let s = Hex::encode(self.0.0.get(0..4).ok_or(std::fmt::Error)?); - write!(f, "k#{}..", s) - } -} - -impl Display for ConciseAuthorityPublicKeyBytesRef<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - Debug::fmt(self, f) - } -} - -/// A wrapper around AuthorityPublicKeyBytes but owns it. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, schemars::JsonSchema)] -pub struct ConciseAuthorityPublicKeyBytes(AuthorityPublicKeyBytes); - -impl Debug for ConciseAuthorityPublicKeyBytes { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - let s = Hex::encode(self.0.0.get(0..4).ok_or(std::fmt::Error)?); - write!(f, "k#{}..", s) - } -} - -impl Display for ConciseAuthorityPublicKeyBytes { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - Debug::fmt(self, f) - } -} - -impl TryFrom for AuthorityPublicKey { - type Error = FastCryptoError; - - fn try_from(bytes: AuthorityPublicKeyBytes) -> Result { - AuthorityPublicKey::from_bytes(bytes.as_ref()) - } -} - -impl From<&AuthorityPublicKey> for AuthorityPublicKeyBytes { - fn from(pk: &AuthorityPublicKey) -> AuthorityPublicKeyBytes { - AuthorityPublicKeyBytes::from_bytes(pk.as_ref()).unwrap() - } -} - -impl Debug for AuthorityPublicKeyBytes { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - self.fmt_impl(f) - } -} - -impl Display for AuthorityPublicKeyBytes { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - self.fmt_impl(f) - } -} - -impl ToFromBytes for AuthorityPublicKeyBytes { - fn from_bytes(bytes: &[u8]) -> Result { - let bytes: [u8; AuthorityPublicKey::LENGTH] = bytes - .try_into() - .map_err(|_| fastcrypto::error::FastCryptoError::InvalidInput)?; - Ok(AuthorityPublicKeyBytes(bytes)) - } -} - -impl AuthorityPublicKeyBytes { - pub const ZERO: Self = Self::new([0u8; AuthorityPublicKey::LENGTH]); - - /// This ensures it's impossible to construct an instance with other than - /// registered lengths - pub const fn new(bytes: [u8; AuthorityPublicKey::LENGTH]) -> AuthorityPublicKeyBytes -where { - AuthorityPublicKeyBytes(bytes) - } -} - -impl FromStr for AuthorityPublicKeyBytes { - type Err = Error; - - fn from_str(s: &str) -> Result { - let value = Hex::decode(s).map_err(|e| anyhow!(e))?; - Self::from_bytes(&value[..]).map_err(|e| anyhow!(e)) - } -} - -impl Default for AuthorityPublicKeyBytes { - fn default() -> Self { - Self::ZERO - } -} - -// Add helper calls for Authority Signature -// - -pub trait SuiAuthoritySignature { - fn verify_secure( - &self, - value: &IntentMessage, - epoch_id: EpochId, - author: AuthorityPublicKeyBytes, - ) -> Result<(), SuiError> - where - T: Serialize; - - fn new_secure( - value: &IntentMessage, - epoch_id: &EpochId, - secret: &dyn Signer, - ) -> Self - where - T: Serialize; -} - -impl SuiAuthoritySignature for AuthoritySignature { - #[instrument(level = "trace", skip_all)] - fn new_secure(value: &IntentMessage, epoch: &EpochId, secret: &dyn Signer) -> Self - where - T: Serialize, - { - let mut intent_msg_bytes = - bcs::to_bytes(&value).expect("Message serialization should not fail"); - epoch.write(&mut intent_msg_bytes); - secret.sign(&intent_msg_bytes) - } - - #[instrument(level = "trace", skip_all)] - fn verify_secure( - &self, - value: &IntentMessage, - epoch: EpochId, - author: AuthorityPublicKeyBytes, - ) -> Result<(), SuiError> - where - T: Serialize, - { - let mut message = bcs::to_bytes(&value).expect("Message serialization should not fail"); - epoch.write(&mut message); - - let public_key = AuthorityPublicKey::try_from(author).map_err(|_| { - SuiError::KeyConversionError( - "Failed to serialize public key bytes to valid public key".to_string(), - ) - })?; - public_key - .verify(&message[..], self) - .map_err(|e| SuiError::InvalidSignature { - error: format!( - "Fail to verify auth sig {} epoch: {} author: {}", - e, - epoch, - author.concise() - ), - }) - } -} - -// TODO: get_key_pair() and get_key_pair_from_bytes() should return KeyPair -// only. TODO: rename to random_key_pair -pub fn get_key_pair() -> (SuiAddress, KP) -where - ::PubKey: SuiPublicKey, -{ - get_key_pair_from_rng(&mut OsRng) -} - -/// Generate a random committee key pairs with a given committee size -pub fn random_committee_key_pairs_of_size(size: usize) -> Vec { - let mut rng = StdRng::from_seed([0; 32]); - (0..size) - .map(|_| { - // TODO: We are generating the keys 4 times to match exactly as how we generate - // keys in ConfigBuilder::build (sui-config/src/network_config_builder). This is - // because we are using these key generation functions as fixtures - // and we call them independently in different paths and exact the - // results to be the same. We should eliminate them. - let key_pair = get_key_pair_from_rng::(&mut rng); - get_key_pair_from_rng::(&mut rng); - get_key_pair_from_rng::(&mut rng); - get_key_pair_from_rng::(&mut rng); - key_pair.1 - }) - .collect() -} - -pub fn deterministic_random_account_key() -> (SuiAddress, AccountKeyPair) { - let mut rng = StdRng::from_seed([0; 32]); - get_key_pair_from_rng(&mut rng) -} - -pub fn get_account_key_pair() -> (SuiAddress, AccountKeyPair) { - get_key_pair() -} - -pub fn get_authority_key_pair() -> (SuiAddress, AuthorityKeyPair) { - get_key_pair() -} - -/// Generate a keypair from the specified RNG (useful for testing with seedable -/// rngs). -pub fn get_key_pair_from_rng(csprng: &mut R) -> (SuiAddress, KP) -where - R: rand::CryptoRng + rand::RngCore, - ::PubKey: SuiPublicKey, -{ - let kp = KP::generate(&mut StdRng::from_rng(csprng).unwrap()); - (kp.public().into(), kp) -} - -// TODO: C-GETTER -pub fn get_key_pair_from_bytes(bytes: &[u8]) -> SuiResult<(SuiAddress, KP)> -where - ::PubKey: SuiPublicKey, -{ - let priv_length = ::PrivKey::LENGTH; - let pub_key_length = ::PubKey::LENGTH; - if bytes.len() != priv_length + pub_key_length { - return Err(SuiError::KeyConversionError(format!( - "Invalid input byte length, expected {}: {}", - priv_length, - bytes.len() - ))); - } - let sk = ::PrivKey::from_bytes( - bytes - .get(..priv_length) - .ok_or(SuiError::InvalidPrivateKey)?, - ) - .map_err(|_| SuiError::InvalidPrivateKey)?; - let kp: KP = sk.into(); - Ok((kp.public().into(), kp)) -} - -// Account Signatures -// - -// Enums for signature scheme signatures -#[enum_dispatch] -#[derive(Clone, JsonSchema, Debug, PartialEq, Eq, Hash)] -pub enum Signature { - Ed25519SuiSignature, - Secp256k1SuiSignature, - Secp256r1SuiSignature, -} - -impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let bytes = self.as_ref(); - - if serializer.is_human_readable() { - let s = Base64::encode(bytes); - serializer.serialize_str(&s) - } else { - serializer.serialize_bytes(bytes) - } - } -} - -impl<'de> Deserialize<'de> for Signature { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - use serde::de::Error; - - let bytes = if deserializer.is_human_readable() { - let s = String::deserialize(deserializer)?; - Base64::decode(&s).map_err(|e| Error::custom(e.to_string()))? - } else { - let data: Vec = Vec::deserialize(deserializer)?; - data - }; - - Self::from_bytes(&bytes).map_err(|e| Error::custom(e.to_string())) - } -} - -impl Signature { - /// The messaged passed in is already hashed form. - pub fn new_hashed(hashed_msg: &[u8], secret: &dyn Signer) -> Self { - Signer::sign(secret, hashed_msg) - } - - pub fn new_secure(value: &IntentMessage, secret: &dyn Signer) -> Self - where - T: Serialize, - { - let mut hasher = DefaultHash::default(); - hasher.update(&bcs::to_bytes(&value).expect("Message serialization should not fail")); - Signer::sign(secret, &hasher.finalize().digest) - } -} - -impl AsRef<[u8]> for Signature { - fn as_ref(&self) -> &[u8] { - match self { - Signature::Ed25519SuiSignature(sig) => sig.as_ref(), - Signature::Secp256k1SuiSignature(sig) => sig.as_ref(), - Signature::Secp256r1SuiSignature(sig) => sig.as_ref(), - } - } -} -impl AsMut<[u8]> for Signature { - fn as_mut(&mut self) -> &mut [u8] { - match self { - Signature::Ed25519SuiSignature(sig) => sig.as_mut(), - Signature::Secp256k1SuiSignature(sig) => sig.as_mut(), - Signature::Secp256r1SuiSignature(sig) => sig.as_mut(), - } - } -} - -impl ToFromBytes for Signature { - fn from_bytes(bytes: &[u8]) -> Result { - match bytes.first() { - Some(x) => { - if x == &Ed25519SuiSignature::SCHEME.flag() { - Ok(::from_bytes(bytes)?.into()) - } else if x == &Secp256k1SuiSignature::SCHEME.flag() { - Ok(::from_bytes(bytes)?.into()) - } else if x == &Secp256r1SuiSignature::SCHEME.flag() { - Ok(::from_bytes(bytes)?.into()) - } else { - Err(FastCryptoError::InvalidInput) - } - } - _ => Err(FastCryptoError::InvalidInput), - } - } -} - -// BLS Port -// - -impl SuiPublicKey for BLS12381PublicKey { - const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::BLS12381; -} - -// Ed25519 Sui Signature port -// - -#[serde_as] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)] -#[as_ref(forward)] -#[as_mut(forward)] -pub struct Ed25519SuiSignature( - #[schemars(with = "Base64")] - #[serde_as(as = "Readable")] - [u8; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1], -); - -// Implementation useful for simplify testing when mock signature is needed -impl Default for Ed25519SuiSignature { - fn default() -> Self { - Self([0; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1]) - } -} - -impl SuiSignatureInner for Ed25519SuiSignature { - type Sig = Ed25519Signature; - type PubKey = Ed25519PublicKey; - type KeyPair = Ed25519KeyPair; - const LENGTH: usize = Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1; -} - -impl SuiPublicKey for Ed25519PublicKey { - const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::ED25519; -} - -impl ToFromBytes for Ed25519SuiSignature { - fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != Self::LENGTH { - return Err(FastCryptoError::InputLengthWrong(Self::LENGTH)); - } - let mut sig_bytes = [0; Self::LENGTH]; - sig_bytes.copy_from_slice(bytes); - Ok(Self(sig_bytes)) - } -} - -impl Signer for Ed25519KeyPair { - fn sign(&self, msg: &[u8]) -> Signature { - Ed25519SuiSignature::new(self, msg).into() - } -} - -// Secp256k1 Sui Signature port -// -#[serde_as] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)] -#[as_ref(forward)] -#[as_mut(forward)] -pub struct Secp256k1SuiSignature( - #[schemars(with = "Base64")] - #[serde_as(as = "Readable")] - [u8; Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1], -); - -impl SuiSignatureInner for Secp256k1SuiSignature { - type Sig = Secp256k1Signature; - type PubKey = Secp256k1PublicKey; - type KeyPair = Secp256k1KeyPair; - const LENGTH: usize = Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1; -} - -impl SuiPublicKey for Secp256k1PublicKey { - const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256k1; -} - -impl ToFromBytes for Secp256k1SuiSignature { - fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != Self::LENGTH { - return Err(FastCryptoError::InputLengthWrong(Self::LENGTH)); - } - let mut sig_bytes = [0; Self::LENGTH]; - sig_bytes.copy_from_slice(bytes); - Ok(Self(sig_bytes)) - } -} - -impl Signer for Secp256k1KeyPair { - fn sign(&self, msg: &[u8]) -> Signature { - Secp256k1SuiSignature::new(self, msg).into() - } -} - -// Secp256r1 Sui Signature port -// -#[serde_as] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)] -#[as_ref(forward)] -#[as_mut(forward)] -pub struct Secp256r1SuiSignature( - #[schemars(with = "Base64")] - #[serde_as(as = "Readable")] - [u8; Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1], -); - -impl SuiSignatureInner for Secp256r1SuiSignature { - type Sig = Secp256r1Signature; - type PubKey = Secp256r1PublicKey; - type KeyPair = Secp256r1KeyPair; - const LENGTH: usize = Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1; -} - -impl SuiPublicKey for Secp256r1PublicKey { - const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256r1; -} - -impl ToFromBytes for Secp256r1SuiSignature { - fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != Self::LENGTH { - return Err(FastCryptoError::InputLengthWrong(Self::LENGTH)); - } - let mut sig_bytes = [0; Self::LENGTH]; - sig_bytes.copy_from_slice(bytes); - Ok(Self(sig_bytes)) - } -} - -impl Signer for Secp256r1KeyPair { - fn sign(&self, msg: &[u8]) -> Signature { - Secp256r1SuiSignature::new(self, msg).into() - } -} - -// This struct exists due to the limitations of the `enum_dispatch` library. -// -pub trait SuiSignatureInner: Sized + ToFromBytes + PartialEq + Eq + Hash { - type Sig: Authenticator; - type PubKey: VerifyingKey + SuiPublicKey; - type KeyPair: KeypairTraits; - - const LENGTH: usize = Self::Sig::LENGTH + Self::PubKey::LENGTH + 1; - const SCHEME: SignatureScheme = Self::PubKey::SIGNATURE_SCHEME; - - /// Returns the deserialized signature and deserialized pubkey. - fn get_verification_inputs(&self) -> SuiResult<(Self::Sig, Self::PubKey)> { - let pk = Self::PubKey::from_bytes(self.public_key_bytes()) - .map_err(|_| SuiError::KeyConversionError("Invalid public key".to_string()))?; - - // deserialize the signature - let signature = Self::Sig::from_bytes(self.signature_bytes()).map_err(|_| { - SuiError::InvalidSignature { - error: "Fail to get pubkey and sig".to_string(), - } - })?; - - Ok((signature, pk)) - } - - fn new(kp: &Self::KeyPair, message: &[u8]) -> Self { - let sig = Signer::sign(kp, message); - - let mut signature_bytes: Vec = Vec::new(); - signature_bytes - .extend_from_slice(&[::SIGNATURE_SCHEME.flag()]); - signature_bytes.extend_from_slice(sig.as_ref()); - signature_bytes.extend_from_slice(kp.public().as_ref()); - Self::from_bytes(&signature_bytes[..]) - .expect("Serialized signature did not have expected size") - } -} - -pub trait SuiPublicKey: VerifyingKey { - const SIGNATURE_SCHEME: SignatureScheme; -} - -#[enum_dispatch(Signature)] -pub trait SuiSignature: Sized + ToFromBytes { - fn signature_bytes(&self) -> &[u8]; - fn public_key_bytes(&self) -> &[u8]; - fn scheme(&self) -> SignatureScheme; - - fn verify_secure( - &self, - value: &IntentMessage, - author: SuiAddress, - scheme: SignatureScheme, - ) -> SuiResult<()> - where - T: Serialize; -} - -impl SuiSignature for S { - fn signature_bytes(&self) -> &[u8] { - // Access array slice is safe because the array bytes is initialized as - // flag || signature || pubkey with its defined length. - &self.as_ref()[1..1 + S::Sig::LENGTH] - } - - fn public_key_bytes(&self) -> &[u8] { - // Access array slice is safe because the array bytes is initialized as - // flag || signature || pubkey with its defined length. - &self.as_ref()[S::Sig::LENGTH + 1..] - } - - fn scheme(&self) -> SignatureScheme { - S::PubKey::SIGNATURE_SCHEME - } - - fn verify_secure( - &self, - value: &IntentMessage, - author: SuiAddress, - scheme: SignatureScheme, - ) -> Result<(), SuiError> - where - T: Serialize, - { - let mut hasher = DefaultHash::default(); - hasher.update(&bcs::to_bytes(&value).expect("Message serialization should not fail")); - let digest = hasher.finalize().digest; - - let (sig, pk) = &self.get_verification_inputs()?; - match scheme { - SignatureScheme::ZkLoginAuthenticator => {} // Pass this check because zk login does - // not derive address from pubkey. - _ => { - let address = SuiAddress::from(pk); - if author != address { - return Err(SuiError::IncorrectSigner { - error: format!( - "Incorrect signer, expected {:?}, got {:?}", - author, address - ), - }); - } - } - } - - pk.verify(&digest, sig) - .map_err(|e| SuiError::InvalidSignature { - error: format!("Fail to verify user sig {}", e), - }) - } -} - -/// AuthoritySignInfoTrait is a trait used specifically for a few structs in -/// messages.rs to template on whether the struct is signed by an authority. We -/// want to limit how those structs can be instantiated on, hence the sealed -/// trait. TODO: We could also add the aggregated signature as another impl of -/// the trait. This will make CertifiedTransaction also an instance of the -/// same struct. -pub trait AuthoritySignInfoTrait: private::SealedAuthoritySignInfoTrait { - fn verify_secure( - &self, - data: &T, - intent: Intent, - committee: &Committee, - ) -> SuiResult; - - fn add_to_verification_obligation<'a>( - &self, - committee: &'a Committee, - obligation: &mut VerificationObligation<'a>, - message_index: usize, - ) -> SuiResult<()>; -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct EmptySignInfo {} -impl AuthoritySignInfoTrait for EmptySignInfo { - fn verify_secure( - &self, - _data: &T, - _intent: Intent, - _committee: &Committee, - ) -> SuiResult { - Ok(()) - } - - fn add_to_verification_obligation<'a>( - &self, - _committee: &'a Committee, - _obligation: &mut VerificationObligation<'a>, - _message_index: usize, - ) -> SuiResult<()> { - Ok(()) - } -} - -#[derive(Clone, Debug, Eq, Serialize, Deserialize)] -pub struct AuthoritySignInfo { - pub epoch: EpochId, - pub authority: AuthorityName, - pub signature: AuthoritySignature, -} - -impl AuthoritySignInfoTrait for AuthoritySignInfo { - fn verify_secure( - &self, - data: &T, - intent: Intent, - committee: &Committee, - ) -> SuiResult<()> { - let mut obligation = VerificationObligation::default(); - let idx = obligation.add_message(data, self.epoch, intent); - self.add_to_verification_obligation(committee, &mut obligation, idx)?; - obligation.verify_all()?; - Ok(()) - } - - fn add_to_verification_obligation<'a>( - &self, - committee: &'a Committee, - obligation: &mut VerificationObligation<'a>, - message_index: usize, - ) -> SuiResult<()> { - fp_ensure!( - self.epoch == committee.epoch(), - SuiError::WrongEpoch { - expected_epoch: committee.epoch(), - actual_epoch: self.epoch, - } - ); - let weight = committee.weight(&self.authority); - fp_ensure!( - weight > 0, - SuiError::UnknownSigner { - signer: Some(self.authority.concise().to_string()), - index: None, - committee: Box::new(committee.clone()) - } - ); - - obligation - .public_keys - .get_mut(message_index) - .ok_or(SuiError::InvalidAddress)? - .push(committee.public_key(&self.authority)?); - obligation - .signatures - .get_mut(message_index) - .ok_or(SuiError::InvalidAddress)? - .add_signature(self.signature.clone()) - .map_err(|_| SuiError::InvalidSignature { - error: "Fail to aggregator auth sig".to_string(), - })?; - Ok(()) - } -} - -impl AuthoritySignInfo { - pub fn new( - epoch: EpochId, - value: &T, - intent: Intent, - name: AuthorityName, - secret: &dyn Signer, - ) -> Self - where - T: Serialize, - { - Self { - epoch, - authority: name, - signature: AuthoritySignature::new_secure( - &IntentMessage::new(intent, value), - &epoch, - secret, - ), - } - } -} - -impl Hash for AuthoritySignInfo { - fn hash(&self, state: &mut H) { - self.epoch.hash(state); - self.authority.hash(state); - } -} - -impl Display for AuthoritySignInfo { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "AuthoritySignInfo {{ epoch: {:?}, authority: {} }}", - self.epoch, self.authority, - ) - } -} - -impl PartialEq for AuthoritySignInfo { - fn eq(&self, other: &Self) -> bool { - // We do not compare the signature, because there can be multiple - // valid signatures for the same epoch and authority. - self.epoch == other.epoch && self.authority == other.authority - } -} - -/// Represents at least a quorum (could be more) of authority signatures. -/// STRONG_THRESHOLD indicates whether to use the quorum threshold for quorum -/// check. When STRONG_THRESHOLD is true, the quorum is valid when the total -/// stake is at least the quorum threshold (2f+1) of the committee; when -/// STRONG_THRESHOLD is false, the quorum is valid when the total stake is at -/// least the validity threshold (f+1) of the committee. -#[serde_as] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct AuthorityQuorumSignInfo { - pub epoch: EpochId, - #[schemars(with = "Base64")] - pub signature: AggregateAuthoritySignature, - #[schemars(with = "Base64")] - #[serde_as(as = "SuiBitmap")] - pub signers_map: RoaringBitmap, -} - -pub type AuthorityStrongQuorumSignInfo = AuthorityQuorumSignInfo; - -// Variant of [AuthorityStrongQuorumSignInfo] but with a serialized signature, -// to be used in external APIs. -#[serde_as] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct SuiAuthorityStrongQuorumSignInfo { - pub epoch: EpochId, - pub signature: AggregateAuthoritySignatureAsBytes, - #[schemars(with = "Base64")] - #[serde_as(as = "SuiBitmap")] - pub signers_map: RoaringBitmap, -} - -impl From<&AuthorityStrongQuorumSignInfo> for SuiAuthorityStrongQuorumSignInfo { - fn from(info: &AuthorityStrongQuorumSignInfo) -> Self { - Self { - epoch: info.epoch, - signature: (&info.signature).into(), - signers_map: info.signers_map.clone(), - } - } -} - -impl TryFrom<&SuiAuthorityStrongQuorumSignInfo> for AuthorityStrongQuorumSignInfo { - type Error = FastCryptoError; - - fn try_from(info: &SuiAuthorityStrongQuorumSignInfo) -> Result { - Ok(Self { - epoch: info.epoch, - signature: (&info.signature).try_into()?, - signers_map: info.signers_map.clone(), - }) - } -} - -// Note: if you meet an error due to this line it may be because you need an Eq -// implementation for `CertifiedTransaction`, or one of the structs that include -// it, i.e. `ConfirmationTransaction`, `TransactionInfoResponse` or -// `ObjectInfoResponse`. -// -// Please note that any such implementation must be agnostic to the exact set of -// signatures in the certificate, as clients are allowed to equivocate on the -// exact nature of valid certificates they send to the system. This assertion is -// a simple tool to make sure certificates are accounted for correctly - should -// you remove it, you're on your own to maintain the invariant that valid -// certificates with distinct signatures are equivalent, but yet-unchecked -// certificates that differ on signers aren't. -// -// see also https://github.com/MystenLabs/sui/issues/266 -static_assertions::assert_not_impl_any!(AuthorityStrongQuorumSignInfo: Hash, Eq, PartialEq); - -impl AuthoritySignInfoTrait - for AuthorityQuorumSignInfo -{ - fn verify_secure( - &self, - data: &T, - intent: Intent, - committee: &Committee, - ) -> SuiResult { - let mut obligation = VerificationObligation::default(); - let idx = obligation.add_message(data, self.epoch, intent); - self.add_to_verification_obligation(committee, &mut obligation, idx)?; - obligation.verify_all()?; - Ok(()) - } - - fn add_to_verification_obligation<'a>( - &self, - committee: &'a Committee, - obligation: &mut VerificationObligation<'a>, - message_index: usize, - ) -> SuiResult<()> { - // Check epoch - fp_ensure!( - self.epoch == committee.epoch(), - SuiError::WrongEpoch { - expected_epoch: committee.epoch(), - actual_epoch: self.epoch, - } - ); - - let mut weight = 0; - - // Create obligations for the committee signatures - obligation - .signatures - .get_mut(message_index) - .ok_or(SuiError::InvalidAuthenticator)? - .add_aggregate(self.signature.clone()) - .map_err(|_| SuiError::InvalidSignature { - error: "Signature Aggregation failed".to_string(), - })?; - - let selected_public_keys = obligation - .public_keys - .get_mut(message_index) - .ok_or(SuiError::InvalidAuthenticator)?; - - for authority_index in self.signers_map.iter() { - let authority = committee - .authority_by_index(authority_index) - .ok_or_else(|| SuiError::UnknownSigner { - signer: None, - index: Some(authority_index), - committee: Box::new(committee.clone()), - })?; - - // Update weight. - let voting_rights = committee.weight(authority); - fp_ensure!( - voting_rights > 0, - SuiError::UnknownSigner { - signer: Some(authority.concise().to_string()), - index: Some(authority_index), - committee: Box::new(committee.clone()), - } - ); - weight += voting_rights; - - selected_public_keys.push(committee.public_key(authority)?); - } - - fp_ensure!( - weight >= Self::quorum_threshold(committee), - SuiError::CertificateRequiresQuorum - ); - - Ok(()) - } -} - -impl AuthorityQuorumSignInfo { - pub fn new_from_auth_sign_infos( - auth_sign_infos: Vec, - committee: &Committee, - ) -> SuiResult { - fp_ensure!( - auth_sign_infos.iter().all(|a| a.epoch == committee.epoch), - SuiError::InvalidSignature { - error: "All signatures must be from the same epoch as the committee".to_string() - } - ); - let total_stake: StakeUnit = auth_sign_infos - .iter() - .map(|a| committee.weight(&a.authority)) - .sum(); - fp_ensure!( - total_stake >= Self::quorum_threshold(committee), - SuiError::InvalidSignature { - error: "Signatures don't have enough stake to form a quorum".to_string() - } - ); - - let signatures: BTreeMap<_, _> = auth_sign_infos - .into_iter() - .map(|a| (a.authority, a.signature)) - .collect(); - let mut map = RoaringBitmap::new(); - for pk in signatures.keys() { - map.insert( - committee - .authority_index(pk) - .ok_or_else(|| SuiError::UnknownSigner { - signer: Some(pk.concise().to_string()), - index: None, - committee: Box::new(committee.clone()), - })?, - ); - } - let sigs: Vec = signatures.into_values().collect(); - - Ok(AuthorityQuorumSignInfo { - epoch: committee.epoch, - signature: AggregateAuthoritySignature::aggregate(&sigs).map_err(|e| { - SuiError::InvalidSignature { - error: e.to_string(), - } - })?, - signers_map: map, - }) - } - - pub fn authorities<'a>( - &'a self, - committee: &'a Committee, - ) -> impl Iterator> { - self.signers_map.iter().map(|i| { - committee - .authority_by_index(i) - .ok_or(SuiError::InvalidAuthenticator) - }) - } - - pub fn quorum_threshold(committee: &Committee) -> StakeUnit { - committee.threshold::() - } - - pub fn len(&self) -> u64 { - self.signers_map.len() - } - - pub fn is_empty(&self) -> bool { - self.signers_map.is_empty() - } -} - -impl Display for AuthorityQuorumSignInfo { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - writeln!( - f, - "{} {{ epoch: {:?}, signers_map: {:?} }}", - if S { - "AuthorityStrongQuorumSignInfo" - } else { - "AuthorityWeakQuorumSignInfo" - }, - self.epoch, - self.signers_map, - )?; - Ok(()) - } -} - -mod private { - pub trait SealedAuthoritySignInfoTrait {} - impl SealedAuthoritySignInfoTrait for super::EmptySignInfo {} - impl SealedAuthoritySignInfoTrait for super::AuthoritySignInfo {} - impl SealedAuthoritySignInfoTrait for super::AuthorityQuorumSignInfo {} -} - -/// Something that we know how to hash and sign. -pub trait Signable { - fn write(&self, writer: &mut W); -} - -pub trait SignableBytes -where - Self: Sized, -{ - fn from_signable_bytes(bytes: &[u8]) -> Result; -} - -/// Activate the blanket implementation of `Signable` based on serde and BCS. -/// * We use `serde_name` to extract a seed from the name of structs and enums. -/// * We use `BCS` to generate canonical bytes suitable for hashing and signing. -/// -/// # Safety -/// We protect the access to this marker trait through a "sealed trait" pattern: -/// impls must be add added here (nowehre else) which lets us note those impls -/// MUST be on types that comply with the `serde_name` machinery -/// for the below implementations not to panic. One way to check they work is to -/// write a unit test for serialization to / deserialization from signable -/// bytes. -mod bcs_signable { - - pub trait BcsSignable: serde::Serialize + serde::de::DeserializeOwned {} - impl BcsSignable for crate::committee::Committee {} - impl BcsSignable for crate::messages_checkpoint::CheckpointSummary {} - impl BcsSignable for crate::messages_checkpoint::CheckpointContents {} - - impl BcsSignable for crate::effects::TransactionEffects {} - impl BcsSignable for crate::effects::TransactionEvents {} - impl BcsSignable for crate::transaction::TransactionData {} - impl BcsSignable for crate::transaction::SenderSignedData {} - impl BcsSignable for crate::object::ObjectInner {} - - impl BcsSignable for crate::accumulator::Accumulator {} - - impl BcsSignable for super::bcs_signable_test::Foo {} - #[cfg(test)] - impl BcsSignable for super::bcs_signable_test::Bar {} -} - -impl Signable for T -where - T: bcs_signable::BcsSignable, - W: std::io::Write, -{ - fn write(&self, writer: &mut W) { - let name = serde_name::trace_name::().expect("Self must be a struct or an enum"); - // Note: This assumes that names never contain the separator `::`. - write!(writer, "{}::", name).expect("Hasher should not fail"); - bcs::serialize_into(writer, &self).expect("Message serialization should not fail"); - } -} - -impl Signable for EpochId -where - W: std::io::Write, -{ - fn write(&self, writer: &mut W) { - bcs::serialize_into(writer, &self).expect("Message serialization should not fail"); - } -} - -impl SignableBytes for T -where - T: bcs_signable::BcsSignable, -{ - fn from_signable_bytes(bytes: &[u8]) -> Result { - // Remove name tag before deserialization using BCS - let name = serde_name::trace_name::().expect("Self should be a struct or an enum"); - let name_byte_len = format!("{}::", name).bytes().len(); - Ok(bcs::from_bytes(bytes.get(name_byte_len..).ok_or_else( - || anyhow!("Failed to deserialize to {name}."), - )?)?) - } -} - -fn hash, H: HashFunction, const DIGEST_SIZE: usize>( - signable: &S, -) -> [u8; DIGEST_SIZE] { - let mut digest = H::default(); - signable.write(&mut digest); - let hash = digest.finalize(); - hash.into() -} - -pub fn default_hash>(signable: &S) -> [u8; 32] { - hash::(signable) -} - -#[derive(Default)] -pub struct VerificationObligation<'a> { - pub messages: Vec>, - pub signatures: Vec, - pub public_keys: Vec>, -} - -impl<'a> VerificationObligation<'a> { - pub fn new() -> VerificationObligation<'a> { - VerificationObligation::default() - } - - /// Add a new message to the list of messages to be verified. - /// Returns the index of the message. - pub fn add_message(&mut self, message_value: &T, epoch: EpochId, intent: Intent) -> usize - where - T: Serialize, - { - let intent_msg = IntentMessage::new(intent, message_value); - let mut intent_msg_bytes = - bcs::to_bytes(&intent_msg).expect("Message serialization should not fail"); - epoch.write(&mut intent_msg_bytes); - self.signatures.push(AggregateAuthoritySignature::default()); - self.public_keys.push(Vec::new()); - self.messages.push(intent_msg_bytes); - self.messages.len() - 1 - } - - // Attempts to add signature and public key to the obligation. If this fails, - // ensure to call `verify` manually. - pub fn add_signature_and_public_key( - &mut self, - signature: &AuthoritySignature, - public_key: &'a AuthorityPublicKey, - idx: usize, - ) -> SuiResult<()> { - self.public_keys - .get_mut(idx) - .ok_or(SuiError::InvalidAuthenticator)? - .push(public_key); - self.signatures - .get_mut(idx) - .ok_or(SuiError::InvalidAuthenticator)? - .add_signature(signature.clone()) - .map_err(|_| SuiError::InvalidSignature { - error: "Failed to add signature to obligation".to_string(), - })?; - Ok(()) - } - - pub fn verify_all(self) -> SuiResult<()> { - let mut pks = Vec::with_capacity(self.public_keys.len()); - for pk in self.public_keys.clone() { - pks.push(pk.into_iter()); - } - AggregateAuthoritySignature::batch_verify( - &self.signatures.iter().collect::>()[..], - pks, - &self.messages.iter().map(|x| &x[..]).collect::>()[..], - ) - .map_err(|e| { - let message = format!( - "pks: {:?}, messages: {:?}, sigs: {:?}", - &self.public_keys, - self.messages - .iter() - .map(Base64::encode) - .collect::>(), - &self - .signatures - .iter() - .map(|s| Base64::encode(s.as_ref())) - .collect::>() - ); - - let chunk_size = 2048; - - // This error message may be very long, so we print out the error in chunks of - // to avoid hitting a max log line length on the system. - for (i, chunk) in message - .as_bytes() - .chunks(chunk_size) - .map(std::str::from_utf8) - .enumerate() - { - warn!( - "Failed to batch verify aggregated auth sig: {} (chunk {}): {}", - e, - i, - chunk.unwrap() - ); - } - - SuiError::InvalidSignature { - error: format!("Failed to batch verify aggregated auth sig: {}", e), - } - })?; - Ok(()) - } -} - -pub mod bcs_signable_test { - use serde::{Deserialize, Serialize}; - - #[derive(Clone, Serialize, Deserialize)] - pub struct Foo(pub String); - - #[cfg(test)] - #[derive(Serialize, Deserialize)] - pub struct Bar(pub String); - - #[cfg(test)] - use super::VerificationObligation; - - #[cfg(test)] - pub fn get_obligation_input(value: &T) -> (VerificationObligation<'_>, usize) - where - T: super::bcs_signable::BcsSignable, - { - use shared_crypto::intent::{Intent, IntentScope}; - - let mut obligation = VerificationObligation::default(); - // Add the obligation of the authority signature verifications. - let idx = obligation.add_message( - value, - 0, - Intent::sui_app(IntentScope::SenderSignedTransaction), - ); - (obligation, idx) - } -} - -#[derive( - Clone, Copy, Deserialize, Serialize, JsonSchema, Debug, EnumString, strum_macros::Display, -)] -#[strum(serialize_all = "lowercase")] -pub enum SignatureScheme { - ED25519, - Secp256k1, - Secp256r1, - BLS12381, // This is currently not supported for user Sui Address. - MultiSig, - ZkLoginAuthenticator, -} - -impl SignatureScheme { - pub fn flag(&self) -> u8 { - match self { - SignatureScheme::ED25519 => 0x00, - SignatureScheme::Secp256k1 => 0x01, - SignatureScheme::Secp256r1 => 0x02, - SignatureScheme::MultiSig => 0x03, - SignatureScheme::BLS12381 => 0x04, // This is currently not supported for user Sui - // Address. - SignatureScheme::ZkLoginAuthenticator => 0x05, - } - } - - /// Takes as input an hasher and updates it with a flag byte if the input - /// scheme is not ED25519; it does nothing otherwise. - pub fn update_hasher_with_flag(&self, hasher: &mut DefaultHash) { - match self { - SignatureScheme::ED25519 => (), - _ => hasher.update([self.flag()]), - }; - } - - pub fn from_flag(flag: &str) -> Result { - let byte_int = flag - .parse::() - .map_err(|_| SuiError::KeyConversionError("Invalid key scheme".to_string()))?; - Self::from_flag_byte(&byte_int) - } - - pub fn from_flag_byte(byte_int: &u8) -> Result { - match byte_int { - 0x00 => Ok(SignatureScheme::ED25519), - 0x01 => Ok(SignatureScheme::Secp256k1), - 0x02 => Ok(SignatureScheme::Secp256r1), - 0x03 => Ok(SignatureScheme::MultiSig), - 0x04 => Ok(SignatureScheme::BLS12381), - 0x05 => Ok(SignatureScheme::ZkLoginAuthenticator), - _ => Err(SuiError::KeyConversionError( - "Invalid key scheme".to_string(), - )), - } - } -} -/// Unlike [enum Signature], [enum CompressedSignature] does not contain public -/// key. -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] -pub enum CompressedSignature { - Ed25519(Ed25519SignatureAsBytes), - Secp256k1(Secp256k1SignatureAsBytes), - Secp256r1(Secp256r1SignatureAsBytes), - ZkLogin(ZkLoginAuthenticatorAsBytes), -} -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] -pub struct ZkLoginAuthenticatorAsBytes(#[schemars(with = "Base64")] pub Vec); - -impl AsRef<[u8]> for CompressedSignature { - fn as_ref(&self) -> &[u8] { - match self { - CompressedSignature::Ed25519(sig) => &sig.0, - CompressedSignature::Secp256k1(sig) => &sig.0, - CompressedSignature::Secp256r1(sig) => &sig.0, - CompressedSignature::ZkLogin(sig) => &sig.0, - } - } -} - -impl FromStr for Signature { - type Err = eyre::Report; - fn from_str(s: &str) -> Result { - Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string())) - } -} - -impl FromStr for PublicKey { - type Err = eyre::Report; - fn from_str(s: &str) -> Result { - Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string())) - } -} - -impl FromStr for GenericSignature { - type Err = eyre::Report; - fn from_str(s: &str) -> Result { - Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string())) - } -} - -// Types for randomness generation -// -pub type RandomnessSignature = fastcrypto_tbls::types::Signature; -pub type RandomnessPartialSignature = fastcrypto_tbls::tbls::PartialSignature; -pub type RandomnessPrivateKey = - fastcrypto_tbls::ecies::PrivateKey; - -/// Round number of generated randomness. -#[derive(Clone, Copy, Hash, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct RandomnessRound(pub u64); - -impl Display for RandomnessRound { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl std::ops::Add for RandomnessRound { - type Output = Self; - fn add(self, other: Self) -> Self { - Self(self.0 + other.0) - } -} - -impl std::ops::Add for RandomnessRound { - type Output = Self; - fn add(self, other: u64) -> Self { - Self(self.0 + other) - } -} - -impl RandomnessRound { - pub fn new(round: u64) -> Self { - Self(round) - } - - pub fn checked_add(self, rhs: u64) -> Option { - self.0.checked_add(rhs).map(Self) - } - - pub fn signature_message(&self) -> Vec { - "random_beacon round " - .as_bytes() - .iter() - .cloned() - .chain(bcs::to_bytes(&self.0).expect("serialization should not fail")) - .collect() - } -} diff --git a/crates/sui-types/src/display.rs b/crates/sui-types/src/display.rs deleted file mode 100644 index 3a276f05229..00000000000 --- a/crates/sui-types/src/display.rs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; -use serde::Deserialize; - -use crate::{ - collection_types::VecMap, - event::Event, - id::{ID, UID}, - SUI_FRAMEWORK_ADDRESS, -}; - -pub const DISPLAY_MODULE_NAME: &IdentStr = ident_str!("display"); -pub const DISPLAY_CREATED_EVENT_NAME: &IdentStr = ident_str!("DisplayCreated"); -pub const DISPLAY_VERSION_UPDATED_EVENT_NAME: &IdentStr = ident_str!("VersionUpdated"); - -// TODO: add tests to keep in sync -/// Rust version of the Move sui::display::Display type -#[derive(Debug, Deserialize, Clone, Eq, PartialEq)] -pub struct DisplayObject { - pub id: UID, - pub fields: VecMap, - pub version: u16, -} - -#[derive(Deserialize, Debug)] -/// The event that is emitted when a `Display` version is "released". -/// Serves for Display versioning. -pub struct DisplayVersionUpdatedEvent { - pub id: ID, - pub version: u16, - pub fields: VecMap, -} - -impl DisplayVersionUpdatedEvent { - pub fn type_(inner: &StructTag) -> StructTag { - StructTag { - address: SUI_FRAMEWORK_ADDRESS, - name: DISPLAY_VERSION_UPDATED_EVENT_NAME.to_owned(), - module: DISPLAY_MODULE_NAME.to_owned(), - type_params: vec![inner.clone().into()], - } - } - - // Checks if the provided `StructTag` is a DisplayVersionUpdatedEvent - pub fn is_display_updated_event(inner: &StructTag) -> bool { - inner.address == SUI_FRAMEWORK_ADDRESS - && inner.module.as_ident_str() == DISPLAY_MODULE_NAME - && inner.name.as_ident_str() == DISPLAY_VERSION_UPDATED_EVENT_NAME - } - - // Checks if the provided `StructTag` is a DisplayVersionUpdatedEvent and - // returns a reference to the inner type T if so. - pub fn inner_type(inner: &StructTag) -> Option<&StructTag> { - use move_core_types::language_storage::TypeTag; - - if !Self::is_display_updated_event(inner) { - return None; - } - - match &inner.type_params[..] { - [TypeTag::Struct(struct_type)] => Some(struct_type), - _ => None, - } - } - - pub fn try_from_event(event: &Event) -> Option<(&StructTag, Self)> { - let inner_type = Self::inner_type(&event.type_)?; - - bcs::from_bytes(&event.contents) - .ok() - .map(|event| (inner_type, event)) - } -} - -#[derive(Deserialize, Debug)] -pub struct DisplayCreatedEvent { - // The Object ID of Display Object - pub id: ID, -} - -impl DisplayCreatedEvent { - pub fn type_(inner: &StructTag) -> StructTag { - StructTag { - address: SUI_FRAMEWORK_ADDRESS, - name: DISPLAY_CREATED_EVENT_NAME.to_owned(), - module: DISPLAY_MODULE_NAME.to_owned(), - type_params: vec![inner.clone().into()], - } - } -} diff --git a/crates/sui-types/src/dynamic_field.rs b/crates/sui-types/src/dynamic_field.rs deleted file mode 100644 index f35a8669f5f..00000000000 --- a/crates/sui-types/src/dynamic_field.rs +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - fmt, - fmt::{Display, Formatter}, -}; - -use fastcrypto::{encoding::Base58, hash::HashFunction}; -use move_core_types::{ - annotated_value::{MoveStruct, MoveValue}, - ident_str, - identifier::IdentStr, - language_storage::{StructTag, TypeTag}, -}; -use schemars::JsonSchema; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use serde_json::Value; -use serde_with::{serde_as, DisplayFromStr}; -use shared_crypto::intent::HashingIntentScope; - -use crate::{ - base_types::{ObjectDigest, SuiAddress}, - crypto::DefaultHash, - error::{SuiError, SuiResult}, - id::UID, - object::Object, - storage::ObjectStore, - sui_serde::{Readable, SuiTypeTag}, - MoveTypeTagTrait, ObjectID, SequenceNumber, SUI_FRAMEWORK_ADDRESS, -}; - -const DYNAMIC_FIELD_MODULE_NAME: &IdentStr = ident_str!("dynamic_field"); -const DYNAMIC_FIELD_FIELD_STRUCT_NAME: &IdentStr = ident_str!("Field"); - -const DYNAMIC_OBJECT_FIELD_MODULE_NAME: &IdentStr = ident_str!("dynamic_object_field"); -const DYNAMIC_OBJECT_FIELD_WRAPPER_STRUCT_NAME: &IdentStr = ident_str!("Wrapper"); - -/// Rust version of the Move sui::dynamic_field::Field type -#[derive(Clone, Serialize, Deserialize, Debug)] -pub struct Field { - pub id: UID, - pub name: N, - pub value: V, -} - -#[serde_as] -#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)] -#[serde(rename_all = "camelCase")] -pub struct DynamicFieldInfo { - pub name: DynamicFieldName, - #[schemars(with = "Base58")] - #[serde_as(as = "Readable")] - pub bcs_name: Vec, - pub type_: DynamicFieldType, - pub object_type: String, - pub object_id: ObjectID, - pub version: SequenceNumber, - pub digest: ObjectDigest, -} - -#[serde_as] -#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)] -#[serde(rename_all = "camelCase")] -pub struct DynamicFieldName { - #[schemars(with = "String")] - #[serde_as(as = "Readable")] - pub type_: TypeTag, - // Bincode does not like serde_json::Value, rocksdb will not insert the value without - // serializing value as string. TODO: investigate if this can be removed after switch to - // BCS. - #[schemars(with = "Value")] - #[serde_as(as = "Readable<_, DisplayFromStr>")] - pub value: Value, -} - -impl Display for DynamicFieldName { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {}", self.type_, self.value) - } -} - -#[derive(Clone, Serialize, Deserialize, JsonSchema, Ord, PartialOrd, Eq, PartialEq, Debug)] -pub enum DynamicFieldType { - #[serde(rename_all = "camelCase")] - DynamicField, - DynamicObject, -} - -impl Display for DynamicFieldType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - DynamicFieldType::DynamicField => write!(f, "DynamicField"), - DynamicFieldType::DynamicObject => write!(f, "DynamicObject"), - } - } -} - -impl DynamicFieldInfo { - pub fn is_dynamic_field(tag: &StructTag) -> bool { - tag.address == SUI_FRAMEWORK_ADDRESS - && tag.module.as_ident_str() == DYNAMIC_FIELD_MODULE_NAME - && tag.name.as_ident_str() == DYNAMIC_FIELD_FIELD_STRUCT_NAME - } - - pub fn is_dynamic_object_field_wrapper(tag: &StructTag) -> bool { - tag.address == SUI_FRAMEWORK_ADDRESS - && tag.module.as_ident_str() == DYNAMIC_OBJECT_FIELD_MODULE_NAME - && tag.name.as_ident_str() == DYNAMIC_OBJECT_FIELD_WRAPPER_STRUCT_NAME - } - - pub fn dynamic_field_type(key: TypeTag, value: TypeTag) -> StructTag { - StructTag { - address: SUI_FRAMEWORK_ADDRESS, - name: DYNAMIC_FIELD_FIELD_STRUCT_NAME.to_owned(), - module: DYNAMIC_FIELD_MODULE_NAME.to_owned(), - type_params: vec![key, value], - } - } - - pub fn dynamic_object_field_wrapper(key: TypeTag) -> StructTag { - StructTag { - address: SUI_FRAMEWORK_ADDRESS, - module: DYNAMIC_OBJECT_FIELD_MODULE_NAME.to_owned(), - name: DYNAMIC_OBJECT_FIELD_WRAPPER_STRUCT_NAME.to_owned(), - type_params: vec![key], - } - } - - pub fn try_extract_field_name(tag: &StructTag, type_: &DynamicFieldType) -> SuiResult { - match (type_, tag.type_params.first()) { - (DynamicFieldType::DynamicField, Some(name_type)) => Ok(name_type.clone()), - (DynamicFieldType::DynamicObject, Some(TypeTag::Struct(s))) => Ok(s - .type_params - .first() - .ok_or_else(|| SuiError::ObjectDeserializationError { - error: format!("Error extracting dynamic object name from object: {tag}"), - })? - .clone()), - _ => Err(SuiError::ObjectDeserializationError { - error: format!("Error extracting dynamic object name from object: {tag}"), - }), - } - } - - pub fn try_extract_field_value(tag: &StructTag) -> SuiResult { - match tag.type_params.last() { - Some(value_type) => Ok(value_type.clone()), - None => Err(SuiError::ObjectDeserializationError { - error: format!("Error extracting dynamic object value from object: {tag}"), - }), - } - } - - pub fn parse_move_object( - move_struct: &MoveStruct, - ) -> SuiResult<(MoveValue, DynamicFieldType, ObjectID)> { - let name = extract_field_from_move_struct(move_struct, "name").ok_or_else(|| { - SuiError::ObjectDeserializationError { - error: "Cannot extract [name] field from sui::dynamic_field::Field".to_string(), - } - })?; - - let value = extract_field_from_move_struct(move_struct, "value").ok_or_else(|| { - SuiError::ObjectDeserializationError { - error: "Cannot extract [value] field from sui::dynamic_field::Field".to_string(), - } - })?; - - Ok(if is_dynamic_object(move_struct) { - let name = match name { - MoveValue::Struct(name_struct) => { - extract_field_from_move_struct(name_struct, "name") - } - _ => None, - } - .ok_or_else(|| SuiError::ObjectDeserializationError { - error: "Cannot extract [name] field from sui::dynamic_object_field::Wrapper." - .to_string(), - })?; - // ID extracted from the wrapper object - let object_id = - extract_id_value(value).ok_or_else(|| SuiError::ObjectDeserializationError { - error: format!( - "Cannot extract dynamic object's object id from \ - sui::dynamic_field::Field, {value:?}" - ), - })?; - (name.clone(), DynamicFieldType::DynamicObject, object_id) - } else { - // ID of the Field object - let object_id = extract_object_id(move_struct).ok_or_else(|| { - SuiError::ObjectDeserializationError { - error: format!( - "Cannot extract dynamic object's object id from \ - sui::dynamic_field::Field, {move_struct:?}", - ), - } - })?; - (name.clone(), DynamicFieldType::DynamicField, object_id) - }) - } -} - -pub fn extract_field_from_move_struct<'a>( - move_struct: &'a MoveStruct, - field_name: &str, -) -> Option<&'a MoveValue> { - move_struct.fields.iter().find_map(|(id, value)| { - if id.to_string() == field_name { - Some(value) - } else { - None - } - }) -} - -fn extract_object_id(value: &MoveStruct) -> Option { - // id:UID is the first value in an object - let uid_value = &value.fields.first()?.1; - - // id is the first value in UID - let id_value = match uid_value { - MoveValue::Struct(MoveStruct { fields, .. }) => &fields.first()?.1, - _ => return None, - }; - extract_id_value(id_value) -} - -fn extract_id_value(id_value: &MoveValue) -> Option { - // the id struct has a single bytes field - let id_bytes_value = match id_value { - MoveValue::Struct(MoveStruct { fields, .. }) => &fields.first()?.1, - _ => return None, - }; - // the bytes field should be an address - match id_bytes_value { - MoveValue::Address(addr) => Some(ObjectID::from(*addr)), - _ => None, - } -} - -pub fn is_dynamic_object(move_struct: &MoveStruct) -> bool { - matches!( - &move_struct.type_.type_params[0], - TypeTag::Struct(tag) if DynamicFieldInfo::is_dynamic_object_field_wrapper(tag) - ) -} - -pub fn derive_dynamic_field_id( - parent: T, - key_type_tag: &TypeTag, - key_bytes: &[u8], -) -> Result -where - T: Into, -{ - let parent: SuiAddress = parent.into(); - let k_tag_bytes = bcs::to_bytes(key_type_tag)?; - tracing::trace!( - "Deriving dynamic field ID for parent={:?}, key={:?}, key_type_tag={:?}", - parent, - key_bytes, - key_type_tag, - ); - - // hash(parent || len(key) || key || key_type_tag) - let mut hasher = DefaultHash::default(); - hasher.update([HashingIntentScope::ChildObjectId as u8]); - hasher.update(parent); - hasher.update(key_bytes.len().to_le_bytes()); - hasher.update(key_bytes); - hasher.update(k_tag_bytes); - let hash = hasher.finalize(); - - // truncate into an ObjectID and return - // OK to access slice because digest should never be shorter than - // ObjectID::LENGTH. - let id = ObjectID::try_from(&hash.as_ref()[0..ObjectID::LENGTH]).unwrap(); - tracing::trace!("derive_dynamic_field_id result: {:?}", id); - Ok(id) -} - -/// Given a parent object ID (e.g. a table), and a `key`, retrieve the -/// corresponding dynamic field object from the `object_store`. The key type `K` -/// must implement `MoveTypeTagTrait` which has an associated function that -/// returns the Move type tag. Note that this function returns the Field object -/// itself, not the value in the field. -pub fn get_dynamic_field_object_from_store( - object_store: &dyn ObjectStore, - parent_id: ObjectID, - key: &K, -) -> Result -where - K: MoveTypeTagTrait + Serialize + DeserializeOwned + fmt::Debug, -{ - let id = derive_dynamic_field_id(parent_id, &K::get_type_tag(), &bcs::to_bytes(key).unwrap()) - .map_err(|err| SuiError::DynamicFieldReadError(err.to_string()))?; - let object = object_store.get_object(&id)?.ok_or_else(|| { - SuiError::DynamicFieldReadError(format!( - "Dynamic field with key={:?} and ID={:?} not found on parent {:?}", - key, id, parent_id - )) - })?; - Ok(object) -} - -/// Similar to `get_dynamic_field_object_from_store`, but returns the value in -/// the field instead of the Field object itself. -pub fn get_dynamic_field_from_store( - object_store: &dyn ObjectStore, - parent_id: ObjectID, - key: &K, -) -> Result -where - K: MoveTypeTagTrait + Serialize + DeserializeOwned + fmt::Debug, - V: Serialize + DeserializeOwned, -{ - let object = get_dynamic_field_object_from_store(object_store, parent_id, key)?; - let move_object = object.data.try_as_move().ok_or_else(|| { - SuiError::DynamicFieldReadError(format!( - "Dynamic field {:?} is not a Move object", - object.id() - )) - })?; - Ok(bcs::from_bytes::>(move_object.contents()) - .map_err(|err| SuiError::DynamicFieldReadError(err.to_string()))? - .value) -} diff --git a/crates/sui-types/src/effects/mod.rs b/crates/sui-types/src/effects/mod.rs deleted file mode 100644 index ecfda6f916d..00000000000 --- a/crates/sui-types/src/effects/mod.rs +++ /dev/null @@ -1,464 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use effects_v1::TransactionEffectsV1; -pub use effects_v2::UnchangedSharedKind; -use enum_dispatch::enum_dispatch; -pub use object_change::{EffectsObjectChange, ObjectIn, ObjectOut}; -use serde::{Deserialize, Serialize}; -use shared_crypto::intent::IntentScope; -use sui_protocol_config::ProtocolConfig; -pub use test_effects_builder::TestEffectsBuilder; - -use self::effects_v2::TransactionEffectsV2; -use crate::{ - base_types::{ExecutionDigests, ObjectID, ObjectRef, SequenceNumber}, - committee::EpochId, - crypto::{default_hash, AuthoritySignInfo, AuthorityStrongQuorumSignInfo, EmptySignInfo}, - digests::{ObjectDigest, TransactionDigest, TransactionEffectsDigest, TransactionEventsDigest}, - error::{SuiError, SuiResult}, - event::Event, - execution::SharedInput, - execution_status::ExecutionStatus, - gas::GasCostSummary, - message_envelope::{ - Envelope, Message, TrustedEnvelope, UnauthenticatedMessage, VerifiedEnvelope, - }, - object::Owner, - storage::WriteKind, - transaction::VersionedProtocolMessage, -}; - -mod effects_v1; -mod effects_v2; -mod object_change; -mod test_effects_builder; - -// Since `std::mem::size_of` may not be stable across platforms, we use rough -// constants We need these for estimating effects sizes -// Approximate size of `ObjectRef` type in bytes -pub const APPROX_SIZE_OF_OBJECT_REF: usize = 80; -// Approximate size of `ExecutionStatus` type in bytes -pub const APPROX_SIZE_OF_EXECUTION_STATUS: usize = 120; -// Approximate size of `EpochId` type in bytes -pub const APPROX_SIZE_OF_EPOCH_ID: usize = 10; -// Approximate size of `GasCostSummary` type in bytes -pub const APPROX_SIZE_OF_GAS_COST_SUMMARY: usize = 40; -// Approximate size of `Option` type in bytes -pub const APPROX_SIZE_OF_OPT_TX_EVENTS_DIGEST: usize = 40; -// Approximate size of `TransactionDigest` type in bytes -pub const APPROX_SIZE_OF_TX_DIGEST: usize = 40; -// Approximate size of `Owner` type in bytes -pub const APPROX_SIZE_OF_OWNER: usize = 48; - -/// The response from processing a transaction or a certified transaction -#[enum_dispatch(TransactionEffectsAPI)] -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -#[allow(clippy::large_enum_variant)] -pub enum TransactionEffects { - V1(TransactionEffectsV1), - V2(TransactionEffectsV2), -} - -impl VersionedProtocolMessage for TransactionEffects { - fn message_version(&self) -> Option { - Some(match self { - Self::V1(_) => 1, - Self::V2(_) => 2, - }) - } - - fn check_version_supported(&self, protocol_config: &ProtocolConfig) -> SuiResult { - match self { - Self::V1(_) => Ok(()), - Self::V2(_) => { - if protocol_config.enable_effects_v2() { - Ok(()) - } else { - Err(SuiError::WrongMessageVersion { - error: format!( - "TransactionEffectsV2 is not supported at protocol {:?}.", - protocol_config.version - ), - }) - } - } - } - } -} - -impl Message for TransactionEffects { - type DigestType = TransactionEffectsDigest; - const SCOPE: IntentScope = IntentScope::TransactionEffects; - - fn digest(&self) -> Self::DigestType { - TransactionEffectsDigest::new(default_hash(self)) - } - - fn verify_user_input(&self) -> SuiResult { - Ok(()) - } - - fn verify_epoch(&self, _: EpochId) -> SuiResult { - // Authorities are allowed to re-sign effects from prior epochs, so we do not - // verify the epoch here. - Ok(()) - } -} - -impl UnauthenticatedMessage for TransactionEffects {} - -// TODO: Get rid of this and use TestEffectsBuilder instead. -impl Default for TransactionEffects { - fn default() -> Self { - TransactionEffects::V2(Default::default()) - } -} - -pub enum ObjectRemoveKind { - Delete, - Wrap, -} - -impl TransactionEffects { - /// Creates a TransactionEffects message from the results of execution, - /// choosing the correct format for the current protocol version. - pub fn new_from_execution_v1( - status: ExecutionStatus, - executed_epoch: EpochId, - gas_used: GasCostSummary, - modified_at_versions: Vec<(ObjectID, SequenceNumber)>, - shared_objects: Vec, - transaction_digest: TransactionDigest, - created: Vec<(ObjectRef, Owner)>, - mutated: Vec<(ObjectRef, Owner)>, - unwrapped: Vec<(ObjectRef, Owner)>, - deleted: Vec, - unwrapped_then_deleted: Vec, - wrapped: Vec, - gas_object: (ObjectRef, Owner), - events_digest: Option, - dependencies: Vec, - ) -> Self { - Self::V1(TransactionEffectsV1::new( - status, - executed_epoch, - gas_used, - modified_at_versions, - shared_objects, - transaction_digest, - created, - mutated, - unwrapped, - deleted, - unwrapped_then_deleted, - wrapped, - gas_object, - events_digest, - dependencies, - )) - } - - /// Creates a TransactionEffects message from the results of execution, - /// choosing the correct format for the current protocol version. - pub fn new_from_execution_v2( - status: ExecutionStatus, - executed_epoch: EpochId, - gas_used: GasCostSummary, - shared_objects: Vec, - transaction_digest: TransactionDigest, - lamport_version: SequenceNumber, - changed_objects: BTreeMap, - gas_object: Option, - events_digest: Option, - dependencies: Vec, - ) -> Self { - Self::V2(TransactionEffectsV2::new( - status, - executed_epoch, - gas_used, - shared_objects, - transaction_digest, - lamport_version, - changed_objects, - gas_object, - events_digest, - dependencies, - )) - } - - pub fn execution_digests(&self) -> ExecutionDigests { - ExecutionDigests { - transaction: *self.transaction_digest(), - effects: self.digest(), - } - } - - pub fn estimate_effects_size_upperbound_v1( - num_writes: usize, - num_mutables: usize, - num_deletes: usize, - num_deps: usize, - ) -> usize { - let fixed_sizes = APPROX_SIZE_OF_EXECUTION_STATUS - + APPROX_SIZE_OF_EPOCH_ID - + APPROX_SIZE_OF_GAS_COST_SUMMARY - + APPROX_SIZE_OF_OPT_TX_EVENTS_DIGEST; - - // Each write or delete contributes at roughly this amount because: - // Each write can be a mutation which can show up in `mutated` and - // `modified_at_versions` `num_delete` is added for padding - let approx_change_entry_size = 1_000 - + (APPROX_SIZE_OF_OWNER + APPROX_SIZE_OF_OBJECT_REF) * num_writes - + (APPROX_SIZE_OF_OBJECT_REF * num_mutables) - + (APPROX_SIZE_OF_OBJECT_REF * num_deletes); - - let deps_size = 1_000 + APPROX_SIZE_OF_TX_DIGEST * num_deps; - - fixed_sizes + approx_change_entry_size + deps_size - } - - pub fn estimate_effects_size_upperbound_v2( - num_writes: usize, - num_modifies: usize, - num_deps: usize, - ) -> usize { - let fixed_sizes = APPROX_SIZE_OF_EXECUTION_STATUS - + APPROX_SIZE_OF_EPOCH_ID - + APPROX_SIZE_OF_GAS_COST_SUMMARY - + APPROX_SIZE_OF_OPT_TX_EVENTS_DIGEST; - - // We store object ref and owner for both old objects and new objects. - let approx_change_entry_size = 1_000 - + (APPROX_SIZE_OF_OWNER + APPROX_SIZE_OF_OBJECT_REF) * num_writes - + (APPROX_SIZE_OF_OWNER + APPROX_SIZE_OF_OBJECT_REF) * num_modifies; - - let deps_size = 1_000 + APPROX_SIZE_OF_TX_DIGEST * num_deps; - - fixed_sizes + approx_change_entry_size + deps_size - } - - /// Return an iterator that iterates through all changed objects, including - /// mutated, created and unwrapped objects. In other words, all objects - /// that still exist in the object state after this transaction. - /// It doesn't include deleted/wrapped objects. - pub fn all_changed_objects(&self) -> Vec<(ObjectRef, Owner, WriteKind)> { - self.mutated() - .into_iter() - .map(|(r, o)| (r, o, WriteKind::Mutate)) - .chain( - self.created() - .into_iter() - .map(|(r, o)| (r, o, WriteKind::Create)), - ) - .chain( - self.unwrapped() - .into_iter() - .map(|(r, o)| (r, o, WriteKind::Unwrap)), - ) - .collect() - } - - /// Return all objects that existed in the state prior to the transaction - /// but no longer exist in the state after the transaction. - /// It includes deleted and wrapped objects, but does not include - /// unwrapped_then_deleted objects. - pub fn all_removed_objects(&self) -> Vec<(ObjectRef, ObjectRemoveKind)> { - self.deleted() - .iter() - .map(|obj_ref| (*obj_ref, ObjectRemoveKind::Delete)) - .chain( - self.wrapped() - .iter() - .map(|obj_ref| (*obj_ref, ObjectRemoveKind::Wrap)), - ) - .collect() - } - - /// Returns all objects that will become a tombstone after this transaction. - /// This includes deleted, unwrapped_then_deleted and wrapped objects. - pub fn all_tombstones(&self) -> Vec<(ObjectID, SequenceNumber)> { - self.deleted() - .into_iter() - .chain(self.unwrapped_then_deleted()) - .chain(self.wrapped()) - .map(|obj_ref| (obj_ref.0, obj_ref.1)) - .collect() - } - - /// Return an iterator of mutated objects, but excluding the gas object. - pub fn mutated_excluding_gas(&self) -> Vec<(ObjectRef, Owner)> { - self.mutated() - .into_iter() - .filter(|o| o != &self.gas_object()) - .collect() - } - - pub fn summary_for_debug(&self) -> TransactionEffectsDebugSummary { - TransactionEffectsDebugSummary { - bcs_size: bcs::serialized_size(self).unwrap(), - status: self.status().clone(), - gas_used: self.gas_cost_summary().clone(), - transaction_digest: *self.transaction_digest(), - created_object_count: self.created().len(), - mutated_object_count: self.mutated().len(), - unwrapped_object_count: self.unwrapped().len(), - deleted_object_count: self.deleted().len(), - wrapped_object_count: self.wrapped().len(), - dependency_count: self.dependencies().len(), - } - } -} - -#[derive(Eq, PartialEq, Clone, Debug)] -pub enum InputSharedObject { - Mutate(ObjectRef), - ReadOnly(ObjectRef), - ReadDeleted(ObjectID, SequenceNumber), - MutateDeleted(ObjectID, SequenceNumber), -} - -impl InputSharedObject { - pub fn id_and_version(&self) -> (ObjectID, SequenceNumber) { - let oref = self.object_ref(); - (oref.0, oref.1) - } - - pub fn object_ref(&self) -> ObjectRef { - match self { - InputSharedObject::Mutate(oref) | InputSharedObject::ReadOnly(oref) => *oref, - InputSharedObject::ReadDeleted(id, version) - | InputSharedObject::MutateDeleted(id, version) => { - (*id, *version, ObjectDigest::OBJECT_DIGEST_DELETED) - } - } - } -} - -#[enum_dispatch] -pub trait TransactionEffectsAPI { - fn status(&self) -> &ExecutionStatus; - fn into_status(self) -> ExecutionStatus; - fn executed_epoch(&self) -> EpochId; - fn modified_at_versions(&self) -> Vec<(ObjectID, SequenceNumber)>; - - /// The version assigned to all output objects (apart from packages). - fn lamport_version(&self) -> SequenceNumber; - - /// Metadata of objects prior to modification. This includes any object that - /// exists in the store prior to this transaction and is modified in - /// this transaction. It includes objects that are mutated, wrapped and - /// deleted. This API is only available on effects v2 and above. - fn old_object_metadata(&self) -> Vec<(ObjectRef, Owner)>; - /// Returns the list of shared objects used in the input, with full object - /// reference and use kind. This is needed in effects because in - /// transaction we only have object ID for shared objects. Their version - /// and digest can only be figured out after sequencing. Also provides - /// the use kind to indicate whether the object was mutated or read-only. - /// Down the road it could also indicate use-of-deleted. - fn input_shared_objects(&self) -> Vec; - fn created(&self) -> Vec<(ObjectRef, Owner)>; - fn mutated(&self) -> Vec<(ObjectRef, Owner)>; - fn unwrapped(&self) -> Vec<(ObjectRef, Owner)>; - fn deleted(&self) -> Vec; - fn unwrapped_then_deleted(&self) -> Vec; - fn wrapped(&self) -> Vec; - - fn object_changes(&self) -> Vec; - - // TODO: We should consider having this function to return Option. - // When the gas object is not available (i.e. system transaction), we currently - // return dummy object ref and owner. This is not ideal. - fn gas_object(&self) -> (ObjectRef, Owner); - - fn events_digest(&self) -> Option<&TransactionEventsDigest>; - fn dependencies(&self) -> &[TransactionDigest]; - - fn transaction_digest(&self) -> &TransactionDigest; - - fn gas_cost_summary(&self) -> &GasCostSummary; - - fn deleted_mutably_accessed_shared_objects(&self) -> Vec { - self.input_shared_objects() - .into_iter() - .filter_map(|kind| match kind { - InputSharedObject::MutateDeleted(id, _) => Some(id), - InputSharedObject::Mutate(..) - | InputSharedObject::ReadOnly(..) - | InputSharedObject::ReadDeleted(..) => None, - }) - .collect() - } - - // All of these should be #[cfg(test)], but they are used by tests in other - // crates, and dependencies don't get built with cfg(test) set as far as I - // can tell. - fn status_mut_for_testing(&mut self) -> &mut ExecutionStatus; - fn gas_cost_summary_mut_for_testing(&mut self) -> &mut GasCostSummary; - fn transaction_digest_mut_for_testing(&mut self) -> &mut TransactionDigest; - fn dependencies_mut_for_testing(&mut self) -> &mut Vec; - fn unsafe_add_input_shared_object_for_testing(&mut self, kind: InputSharedObject); - - // Adding an old version of a live object. - fn unsafe_add_deleted_live_object_for_testing(&mut self, obj_ref: ObjectRef); - - // Adding a tombstone for a deleted object. - fn unsafe_add_object_tombstone_for_testing(&mut self, obj_ref: ObjectRef); -} - -#[derive(Clone)] -pub struct ObjectChange { - pub id: ObjectID, - pub input_version: Option, - pub input_digest: Option, - pub output_version: Option, - pub output_digest: Option, - pub id_operation: IDOperation, -} - -#[derive(Eq, PartialEq, Copy, Clone, Debug, Serialize, Deserialize)] -pub enum IDOperation { - None, - Created, - Deleted, -} - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Default)] -pub struct TransactionEvents { - pub data: Vec, -} - -impl TransactionEvents { - pub fn digest(&self) -> TransactionEventsDigest { - TransactionEventsDigest::new(default_hash(self)) - } -} - -#[derive(Debug)] -pub struct TransactionEffectsDebugSummary { - /// Size of bcs serialized byets of the effects. - pub bcs_size: usize, - pub status: ExecutionStatus, - pub gas_used: GasCostSummary, - pub transaction_digest: TransactionDigest, - pub created_object_count: usize, - pub mutated_object_count: usize, - pub unwrapped_object_count: usize, - pub deleted_object_count: usize, - pub wrapped_object_count: usize, - pub dependency_count: usize, - // TODO: Add deleted_and_unwrapped_object_count and event digest. -} - -pub type TransactionEffectsEnvelope = Envelope; -pub type UnsignedTransactionEffects = TransactionEffectsEnvelope; -pub type SignedTransactionEffects = TransactionEffectsEnvelope; -pub type CertifiedTransactionEffects = TransactionEffectsEnvelope; - -pub type TrustedSignedTransactionEffects = TrustedEnvelope; -pub type VerifiedTransactionEffectsEnvelope = VerifiedEnvelope; -pub type VerifiedSignedTransactionEffects = VerifiedTransactionEffectsEnvelope; -pub type VerifiedCertifiedTransactionEffects = - VerifiedTransactionEffectsEnvelope; diff --git a/crates/sui-types/src/effects/object_change.rs b/crates/sui-types/src/effects/object_change.rs deleted file mode 100644 index b4b88091200..00000000000 --- a/crates/sui-types/src/effects/object_change.rs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use serde::{Deserialize, Serialize}; - -use super::IDOperation; -use crate::{ - base_types::VersionDigest, - digests::ObjectDigest, - object::{Object, Owner}, -}; - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -pub struct EffectsObjectChange { - // input_state and output_state are the core fields that's required by - // the protocol as it tells how an object changes on-chain. - /// State of the object in the store prior to this transaction. - pub(crate) input_state: ObjectIn, - /// State of the object in the store after this transaction. - pub(crate) output_state: ObjectOut, - - /// Whether this object ID is created or deleted in this transaction. - /// This information isn't required by the protocol but is useful for - /// providing more detailed semantics on object changes. - pub(crate) id_operation: IDOperation, -} - -impl EffectsObjectChange { - pub fn new( - modified_at: Option<(VersionDigest, Owner)>, - written: Option<&Object>, - id_created: bool, - id_deleted: bool, - ) -> Self { - debug_assert!( - !id_created || !id_deleted, - "Object ID can't be created and deleted at the same time." - ); - Self { - input_state: modified_at.map_or(ObjectIn::NotExist, ObjectIn::Exist), - output_state: written.map_or(ObjectOut::NotExist, |o| { - if o.is_package() { - ObjectOut::PackageWrite((o.version(), o.digest())) - } else { - ObjectOut::ObjectWrite((o.digest(), o.owner)) - } - }), - id_operation: if id_created { - IDOperation::Created - } else if id_deleted { - IDOperation::Deleted - } else { - IDOperation::None - }, - } - } -} - -/// If an object exists (at root-level) in the store prior to this transaction, -/// it should be Exist, otherwise it's NonExist, e.g. wrapped objects should be -/// NonExist. -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -pub enum ObjectIn { - NotExist, - /// The old version, digest and owner. - Exist((VersionDigest, Owner)), -} - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -pub enum ObjectOut { - /// Same definition as in ObjectIn. - NotExist, - /// Any written object, including all of mutated, created, unwrapped today. - ObjectWrite((ObjectDigest, Owner)), - /// Packages writes need to be tracked separately with version because - /// we don't use lamport version for package publish and upgrades. - PackageWrite(VersionDigest), -} diff --git a/crates/sui-types/src/error.rs b/crates/sui-types/src/error.rs deleted file mode 100644 index 31532a2ba34..00000000000 --- a/crates/sui-types/src/error.rs +++ /dev/null @@ -1,939 +0,0 @@ -// Copyright (c) 2021, Facebook, Inc. and its affiliates -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::BTreeMap, fmt::Debug}; - -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use strum_macros::{AsRefStr, IntoStaticStr}; -use thiserror::Error; -use tonic::Status; -use typed_store_error::TypedStoreError; - -use crate::{ - base_types::*, - committee::{Committee, EpochId, StakeUnit}, - digests::CheckpointContentsDigest, - execution_status::CommandArgumentError, - messages_checkpoint::CheckpointSequenceNumber, - object::Owner, -}; - -pub const TRANSACTION_NOT_FOUND_MSG_PREFIX: &str = "Could not find the referenced transaction"; -pub const TRANSACTIONS_NOT_FOUND_MSG_PREFIX: &str = "Could not find the referenced transactions"; - -#[macro_export] -macro_rules! fp_bail { - ($e:expr) => { - return Err($e) - }; -} - -#[macro_export(local_inner_macros)] -macro_rules! fp_ensure { - ($cond:expr, $e:expr) => { - if !($cond) { - fp_bail!($e); - } - }; -} -pub(crate) use fp_ensure; - -use crate::{ - digests::TransactionEventsDigest, - execution_status::{CommandIndex, ExecutionFailureStatus}, -}; - -#[macro_export] -macro_rules! exit_main { - ($result:expr) => { - match $result { - Ok(_) => (), - Err(err) => { - let err = format!("{:?}", err); - println!("{}", err.bold().red()); - std::process::exit(1); - } - } - }; -} - -#[macro_export] -macro_rules! make_invariant_violation { - ($($args:expr),* $(,)?) => {{ - if cfg!(debug_assertions) { - panic!($($args),*) - } - ExecutionError::invariant_violation(format!($($args),*)) - }} -} - -#[macro_export] -macro_rules! invariant_violation { - ($($args:expr),* $(,)?) => { - return Err(make_invariant_violation!($($args),*).into()) - }; -} - -#[macro_export] -macro_rules! assert_invariant { - ($cond:expr, $($args:expr),* $(,)?) => {{ - if !$cond { - invariant_violation!($($args),*) - } - }}; -} - -#[derive( - Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Error, Hash, AsRefStr, IntoStaticStr, -)] -pub enum UserInputError { - #[error("Mutable object {object_id} cannot appear more than one in one transaction.")] - MutableObjectUsedMoreThanOnce { object_id: ObjectID }, - #[error("Wrong number of parameters for the transaction.")] - ObjectInputArityViolation, - #[error( - "Could not find the referenced object {:?} at version {:?}.", - object_id, - version - )] - ObjectNotFound { - object_id: ObjectID, - version: Option, - }, - #[error( - "Object {provided_obj_ref:?} is not available for consumption, its current version: {current_version:?}." - )] - ObjectVersionUnavailableForConsumption { - provided_obj_ref: ObjectRef, - current_version: SequenceNumber, - }, - #[error("Package verification failed: {err:?}")] - PackageVerificationTimedout { err: String }, - #[error("Dependent package not found on-chain: {package_id:?}")] - DependentPackageNotFound { package_id: ObjectID }, - #[error("Mutable parameter provided, immutable parameter expected.")] - ImmutableParameterExpectedError { object_id: ObjectID }, - #[error("Size limit exceeded: {limit} is {value}")] - SizeLimitExceeded { limit: String, value: String }, - #[error( - "Object {child_id:?} is owned by object {parent_id:?}. \ - Objects owned by other objects cannot be used as input arguments." - )] - InvalidChildObjectArgument { - child_id: ObjectID, - parent_id: ObjectID, - }, - #[error( - "Invalid Object digest for object {object_id:?}. Expected digest : {expected_digest:?}." - )] - InvalidObjectDigest { - object_id: ObjectID, - expected_digest: ObjectDigest, - }, - #[error("Sequence numbers above the maximal value are not usable for transfers.")] - InvalidSequenceNumber, - #[error("A move object is expected, instead a move package is passed: {object_id}")] - MovePackageAsObject { object_id: ObjectID }, - #[error("A move package is expected, instead a move object is passed: {object_id}")] - MoveObjectAsPackage { object_id: ObjectID }, - #[error("Transaction was not signed by the correct sender: {}", error)] - IncorrectUserSignature { error: String }, - - #[error("Object used as shared is not shared.")] - NotSharedObjectError, - #[error("The transaction inputs contain duplicated ObjectRef's")] - DuplicateObjectRefInput, - - // Gas related errors - #[error("Transaction gas payment missing.")] - MissingGasPayment, - #[error("Gas object is not an owned object with owner: {:?}.", owner)] - GasObjectNotOwnedObject { owner: Owner }, - #[error("Gas budget: {:?} is higher than max: {:?}.", gas_budget, max_budget)] - GasBudgetTooHigh { gas_budget: u64, max_budget: u64 }, - #[error("Gas budget: {:?} is lower than min: {:?}.", gas_budget, min_budget)] - GasBudgetTooLow { gas_budget: u64, min_budget: u64 }, - #[error( - "Balance of gas object {:?} is lower than the needed amount: {:?}.", - gas_balance, - needed_gas_amount - )] - GasBalanceTooLow { - gas_balance: u128, - needed_gas_amount: u128, - }, - #[error("Transaction kind does not support Sponsored Transaction")] - UnsupportedSponsoredTransactionKind, - #[error( - "Gas price {:?} under reference gas price (RGP) {:?}", - gas_price, - reference_gas_price - )] - GasPriceUnderRGP { - gas_price: u64, - reference_gas_price: u64, - }, - #[error("Gas price cannot exceed {:?} mist", max_gas_price)] - GasPriceTooHigh { max_gas_price: u64 }, - #[error("Object {object_id} is not a gas object")] - InvalidGasObject { object_id: ObjectID }, - #[error("Gas object does not have enough balance to cover minimal gas spend")] - InsufficientBalanceToCoverMinimalGas, - - #[error( - "Could not find the referenced object {:?} as the asked version {:?} is higher than the latest {:?}", - object_id, - asked_version, - latest_version - )] - ObjectSequenceNumberTooHigh { - object_id: ObjectID, - asked_version: SequenceNumber, - latest_version: SequenceNumber, - }, - #[error("Object deleted at reference {:?}.", object_ref)] - ObjectDeleted { object_ref: ObjectRef }, - #[error("Invalid Batch Transaction: {}", error)] - InvalidBatchTransaction { error: String }, - #[error("This Move function is currently disabled and not available for call")] - BlockedMoveFunction, - #[error("Empty input coins for Pay related transaction")] - EmptyInputCoins, - - #[error( - "SUI payment transactions use first input coin for gas payment, but found a different gas object." - )] - UnexpectedGasPaymentObject, - - #[error("Wrong initial version given for shared object")] - SharedObjectStartingVersionMismatch, - - #[error( - "Attempt to transfer object {object_id} that does not have public transfer. Object transfer must be done instead using a distinct Move function call." - )] - TransferObjectWithoutPublicTransferError { object_id: ObjectID }, - - #[error( - "TransferObjects, MergeCoin, and Publish cannot have empty arguments. \ - If MakeMoveVec has empty arguments, it must have a type specified" - )] - EmptyCommandInput, - - #[error("Transaction is denied: {}", error)] - TransactionDenied { error: String }, - - #[error("Feature is not supported: {0}")] - Unsupported(String), - - #[error("Query transactions with move function input error: {0}")] - MoveFunctionInputError(String), - - #[error("Verified checkpoint not found for sequence number: {0}")] - VerifiedCheckpointNotFound(CheckpointSequenceNumber), - - #[error("Verified checkpoint not found for digest: {0}")] - VerifiedCheckpointDigestNotFound(String), - - #[error("Latest checkpoint sequence number not found")] - LatestCheckpointSequenceNumberNotFound, - - #[error("Checkpoint contents not found for digest: {0}")] - CheckpointContentsNotFound(CheckpointContentsDigest), - - #[error("Genesis transaction not found")] - GenesisTransactionNotFound, - - #[error("Transaction {0} not found")] - TransactionCursorNotFound(u64), - - #[error( - "Object {:?} is a system object and cannot be accessed by user transactions.", - object_id - )] - InaccessibleSystemObject { object_id: ObjectID }, - #[error( - "{max_publish_commands} max publish/upgrade commands allowed, {publish_count} provided" - )] - MaxPublishCountExceeded { - max_publish_commands: u64, - publish_count: u64, - }, - - #[error("Immutable parameter provided, mutable parameter expected.")] - MutableParameterExpected { object_id: ObjectID }, - - #[error("Address {address:?} is denied for coin {coin_type}")] - AddressDeniedForCoin { - address: SuiAddress, - coin_type: String, - }, - - #[error("Commands following a command with Random can only be TransferObjects or MergeCoins")] - PostRandomCommandRestrictions, -} - -#[derive( - Eq, - PartialEq, - Clone, - Debug, - Serialize, - Deserialize, - Hash, - AsRefStr, - IntoStaticStr, - JsonSchema, - Error, -)] -#[serde(tag = "code", rename = "ObjectResponseError", rename_all = "camelCase")] -pub enum SuiObjectResponseError { - #[error("Object {:?} does not exist.", object_id)] - NotExists { object_id: ObjectID }, - #[error("Cannot find dynamic field for parent object {:?}.", parent_object_id)] - DynamicFieldNotFound { parent_object_id: ObjectID }, - #[error( - "Object has been deleted object_id: {:?} at version: {:?} in digest {:?}", - object_id, - version, - digest - )] - Deleted { - object_id: ObjectID, - /// Object version. - version: SequenceNumber, - /// Base64 string representing the object digest - digest: ObjectDigest, - }, - #[error("Unknown Error.")] - Unknown, - #[error("Display Error: {:?}", error)] - DisplayError { error: String }, - // TODO: also integrate SuiPastObjectResponse (VersionNotFound, VersionTooHigh) -} - -/// Custom error type for Sui. -#[derive( - Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Error, Hash, AsRefStr, IntoStaticStr, -)] -pub enum SuiError { - #[error("Error checking transaction input objects: {:?}", error)] - UserInputError { error: UserInputError }, - - #[error("Error checking transaction object: {:?}", error)] - SuiObjectResponseError { error: SuiObjectResponseError }, - - #[error("Expecting a single owner, shared ownership found")] - UnexpectedOwnerType, - - #[error("There are already {queue_len} transactions pending, above threshold of {threshold}")] - TooManyTransactionsPendingExecution { queue_len: usize, threshold: usize }, - - #[error("There are too many transactions pending in consensus")] - TooManyTransactionsPendingConsensus, - - #[error( - "Input {object_id} already has {queue_len} transactions pending, above threshold of {threshold}" - )] - TooManyTransactionsPendingOnObject { - object_id: ObjectID, - queue_len: usize, - threshold: usize, - }, - - #[error( - "Input {object_id} has a transaction {txn_age_sec} seconds old pending, above threshold of {threshold} seconds" - )] - TooOldTransactionPendingOnObject { - object_id: ObjectID, - txn_age_sec: u64, - threshold: u64, - }, - - // Signature verification - #[error("Signature is not valid: {}", error)] - InvalidSignature { error: String }, - #[error("Required Signature from {expected} is absent {:?}.", actual)] - SignerSignatureAbsent { - expected: String, - actual: Vec, - }, - #[error("Expect {expected} signer signatures but got {actual}.")] - SignerSignatureNumberMismatch { expected: usize, actual: usize }, - #[error("Value was not signed by the correct sender: {}", error)] - IncorrectSigner { error: String }, - #[error( - "Value was not signed by a known authority. signer: {:?}, index: {:?}, committee: {committee}", - signer, - index - )] - UnknownSigner { - signer: Option, - index: Option, - committee: Box, - }, - #[error( - "Validator {:?} responded multiple signatures for the same message, conflicting: {:?}", - signer, - conflicting_sig - )] - StakeAggregatorRepeatedSigner { - signer: AuthorityName, - conflicting_sig: bool, - }, - // TODO: Used for distinguishing between different occurrences of invalid signatures, to allow - // retries in some cases. - #[error( - "Signature is not valid, but a retry may result in a valid one: {}", - error - )] - PotentiallyTemporarilyInvalidSignature { error: String }, - - // Certificate verification and execution - #[error( - "Signature or certificate from wrong epoch, expected {expected_epoch}, got {actual_epoch}" - )] - WrongEpoch { - expected_epoch: EpochId, - actual_epoch: EpochId, - }, - #[error("Signatures in a certificate must form a quorum")] - CertificateRequiresQuorum, - #[error("Transaction certificate processing failed: {err}")] - ErrorWhileProcessingCertificate { err: String }, - #[error( - "Failed to get a quorum of signed effects when processing transaction: {effects_map:?}" - )] - QuorumFailedToGetEffectsQuorumWhenProcessingTransaction { - effects_map: BTreeMap, StakeUnit)>, - }, - #[error( - "Failed to verify Tx certificate with executed effects, error: {error:?}, validator: {validator_name:?}" - )] - FailedToVerifyTxCertWithExecutedEffects { - validator_name: AuthorityName, - error: String, - }, - #[error("Transaction is already finalized but with different user signatures")] - TxAlreadyFinalizedWithDifferentUserSigs, - #[error("System Transaction not accepted")] - InvalidSystemTransaction, - - // Account access - #[error("Invalid authenticator")] - InvalidAuthenticator, - #[error("Invalid address")] - InvalidAddress, - #[error("Invalid transaction digest.")] - InvalidTransactionDigest, - - #[error("Invalid digest length. Expected {expected}, got {actual}")] - InvalidDigestLength { expected: usize, actual: usize }, - - #[error("Unexpected message.")] - UnexpectedMessage, - - // Move module publishing related errors - #[error("Failed to verify the Move module, reason: {error:?}.")] - ModuleVerificationFailure { error: String }, - #[error("Failed to deserialize the Move module, reason: {error:?}.")] - ModuleDeserializationFailure { error: String }, - #[error("Failed to publish the Move module(s), reason: {error}")] - ModulePublishFailure { error: String }, - #[error("Failed to build Move modules: {error}.")] - ModuleBuildFailure { error: String }, - - // Move call related errors - #[error("Function resolution failure: {error:?}.")] - FunctionNotFound { error: String }, - #[error("Module not found in package: {module_name:?}.")] - ModuleNotFound { module_name: String }, - #[error("Type error while binding function arguments: {error:?}.")] - TypeError { error: String }, - #[error("Circular object ownership detected")] - CircularObjectOwnership, - - // Internal state errors - #[error("Attempt to re-initialize a transaction lock for objects {:?}.", refs)] - ObjectLockAlreadyInitialized { refs: Vec }, - #[error( - "Object {obj_ref:?} already locked by a different transaction: {pending_transaction:?}" - )] - ObjectLockConflict { - obj_ref: ObjectRef, - pending_transaction: TransactionDigest, - }, - #[error( - "Objects {obj_refs:?} are already locked by a transaction from a future epoch {locked_epoch:?}), attempt to override with a transaction from epoch {new_epoch:?}" - )] - ObjectLockedAtFutureEpoch { - obj_refs: Vec, - locked_epoch: EpochId, - new_epoch: EpochId, - locked_by_tx: TransactionDigest, - }, - #[error("{TRANSACTION_NOT_FOUND_MSG_PREFIX} [{:?}].", digest)] - TransactionNotFound { digest: TransactionDigest }, - #[error("{TRANSACTIONS_NOT_FOUND_MSG_PREFIX} [{:?}].", digests)] - TransactionsNotFound { digests: Vec }, - #[error("Could not find the referenced transaction events [{digest:?}].")] - TransactionEventsNotFound { digest: TransactionEventsDigest }, - #[error( - "Attempt to move to `Executed` state an transaction that has already been executed: {:?}.", - digest - )] - TransactionAlreadyExecuted { digest: TransactionDigest }, - #[error("Object ID did not have the expected type")] - BadObjectType { error: String }, - #[error("Fail to retrieve Object layout for {st}")] - FailObjectLayout { st: String }, - - #[error("Execution invariant violated")] - ExecutionInvariantViolation, - #[error("Validator {authority:?} is faulty in a Byzantine manner: {reason:?}")] - ByzantineAuthoritySuspicion { - authority: AuthorityName, - reason: String, - }, - #[allow(non_camel_case_types)] - #[serde(rename = "StorageError")] - #[error("DEPRECATED")] - DEPRECATED_StorageError, - #[allow(non_camel_case_types)] - #[serde(rename = "GenericStorageError")] - #[error("DEPRECATED")] - DEPRECATED_GenericStorageError, - #[error( - "Attempted to access {object} through parent {given_parent}, \ - but it's actual parent is {actual_owner}" - )] - InvalidChildObjectAccess { - object: ObjectID, - given_parent: ObjectID, - actual_owner: Owner, - }, - - #[allow(non_camel_case_types)] - #[serde(rename = "StorageMissingFieldError")] - #[error("DEPRECATED")] - DEPRECATED_StorageMissingFieldError, - #[allow(non_camel_case_types)] - #[serde(rename = "StorageCorruptedFieldError")] - #[error("DEPRECATED")] - DEPRECATED_StorageCorruptedFieldError, - - #[error("Authority Error: {error:?}")] - GenericAuthorityError { error: String }, - - #[error("Failed to dispatch subscription: {error:?}")] - FailedToDispatchSubscription { error: String }, - - #[error("Failed to serialize Owner: {error:?}")] - OwnerFailedToSerialize { error: String }, - - #[error("Failed to deserialize fields into JSON: {error:?}")] - ExtraFieldFailedToDeserialize { error: String }, - - #[error("Failed to execute transaction locally by Orchestrator: {error:?}")] - TransactionOrchestratorLocalExecutionError { error: String }, - - // Errors returned by authority and client read API's - #[error("Failure serializing transaction in the requested format: {:?}", error)] - TransactionSerializationError { error: String }, - #[error("Failure serializing object in the requested format: {:?}", error)] - ObjectSerializationError { error: String }, - #[error("Failure deserializing object in the requested format: {:?}", error)] - ObjectDeserializationError { error: String }, - #[error("Event store component is not active on this node")] - NoEventStore, - - // Client side error - #[error("Too many authority errors were detected for {}: {:?}", action, errors)] - TooManyIncorrectAuthorities { - errors: Vec<(AuthorityName, SuiError)>, - action: String, - }, - #[error("Invalid transaction range query to the fullnode: {:?}", error)] - FullNodeInvalidTxRangeQuery { error: String }, - - // Errors related to the authority-consensus interface. - #[error("Failed to submit transaction to consensus: {0}")] - FailedToSubmitToConsensus(String), - #[error("Failed to connect with consensus node: {0}")] - ConsensusConnectionBroken(String), - #[error("Failed to execute handle_consensus_transaction on Sui: {0}")] - HandleConsensusTransactionFailure(String), - - // Cryptography errors. - #[error("Signature key generation error: {0}")] - SignatureKeyGenError(String), - #[error("Key Conversion Error: {0}")] - KeyConversionError(String), - #[error("Invalid Private Key provided")] - InvalidPrivateKey, - - // Unsupported Operations on Fullnode - #[error("Fullnode does not support handle_certificate")] - FullNodeCantHandleCertificate, - - // Epoch related errors. - #[error("Validator temporarily stopped processing transactions due to epoch change")] - ValidatorHaltedAtEpochEnd, - #[error("Validator has stopped operations for this epoch")] - EpochEnded, - #[error("Error when advancing epoch: {:?}", error)] - AdvanceEpochError { error: String }, - - #[error("Transaction Expired")] - TransactionExpired, - - // These are errors that occur when an RPC fails and is simply the utf8 message sent in a - // Tonic::Status - #[error("{1} - {0}")] - RpcError(String, String), - - #[error("Use of disabled feature: {:?}", error)] - UnsupportedFeatureError { error: String }, - - #[error("Unable to communicate with the Quorum Driver channel: {:?}", error)] - QuorumDriverCommunicationError { error: String }, - - #[error("Operation timed out")] - TimeoutError, - - #[error("Error executing {0}")] - ExecutionError(String), - - #[error("Invalid committee composition")] - InvalidCommittee(String), - - #[error("Missing committee information for epoch {0}")] - MissingCommitteeAtEpoch(EpochId), - - #[error("Index store not available on this Fullnode.")] - IndexStoreNotAvailable, - - #[error("Failed to read dynamic field from table in the object store: {0}")] - DynamicFieldReadError(String), - - #[error("Failed to read or deserialize system state related data structures on-chain: {0}")] - SuiSystemStateReadError(String), - - #[error("Unexpected version error: {0}")] - UnexpectedVersion(String), - - #[error("Message version is not supported at the current protocol version: {error}")] - WrongMessageVersion { error: String }, - - #[error("unknown error: {0}")] - Unknown(String), - - #[error("Failed to perform file operation: {0}")] - FileIOError(String), - - #[error("Failed to get JWK")] - JWKRetrievalError, - - #[error("Storage error: {0}")] - Storage(String), - - #[error( - "Validator cannot handle the request at the moment. Please retry after at least {retry_after_secs} seconds." - )] - ValidatorOverloadedRetryAfter { retry_after_secs: u64 }, -} - -#[repr(u64)] -#[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] -/// Sub-status codes for the `UNKNOWN_VERIFICATION_ERROR` VM Status Code which -/// provides more context TODO: add more Vm Status errors. We use -/// `UNKNOWN_VERIFICATION_ERROR` as a catchall for now. -pub enum VMMVerifierErrorSubStatusCode { - MULTIPLE_RETURN_VALUES_NOT_ALLOWED = 0, - INVALID_OBJECT_CREATION = 1, -} - -#[repr(u64)] -#[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] -/// Sub-status codes for the `MEMORY_LIMIT_EXCEEDED` VM Status Code which -/// provides more context -pub enum VMMemoryLimitExceededSubStatusCode { - EVENT_COUNT_LIMIT_EXCEEDED = 0, - EVENT_SIZE_LIMIT_EXCEEDED = 1, - NEW_ID_COUNT_LIMIT_EXCEEDED = 2, - DELETED_ID_COUNT_LIMIT_EXCEEDED = 3, - TRANSFER_ID_COUNT_LIMIT_EXCEEDED = 4, - OBJECT_RUNTIME_CACHE_LIMIT_EXCEEDED = 5, - OBJECT_RUNTIME_STORE_LIMIT_EXCEEDED = 6, - TOTAL_EVENT_SIZE_LIMIT_EXCEEDED = 7, -} - -pub type SuiResult = Result; -pub type UserInputResult = Result; - -impl From for SuiError { - fn from(error: sui_protocol_config::Error) -> Self { - SuiError::WrongMessageVersion { error: error.0 } - } -} - -impl From for SuiError { - fn from(error: ExecutionError) -> Self { - SuiError::ExecutionError(error.to_string()) - } -} - -impl From for SuiError { - fn from(status: Status) -> Self { - let result = bcs::from_bytes::(status.details()); - if let Ok(sui_error) = result { - sui_error - } else { - Self::RpcError( - status.message().to_owned(), - status.code().description().to_owned(), - ) - } - } -} - -impl From for SuiError { - fn from(e: TypedStoreError) -> Self { - Self::Storage(e.to_string()) - } -} - -impl From for SuiError { - fn from(e: crate::storage::error::Error) -> Self { - Self::Storage(e.to_string()) - } -} - -impl From for Status { - fn from(error: SuiError) -> Self { - let bytes = bcs::to_bytes(&error).unwrap(); - Status::with_details(tonic::Code::Internal, error.to_string(), bytes.into()) - } -} - -impl From for SuiError { - fn from(kind: ExecutionErrorKind) -> Self { - ExecutionError::from_kind(kind).into() - } -} - -impl From<&str> for SuiError { - fn from(error: &str) -> Self { - SuiError::GenericAuthorityError { - error: error.to_string(), - } - } -} - -impl TryFrom for UserInputError { - type Error = anyhow::Error; - - fn try_from(err: SuiError) -> Result { - match err { - SuiError::UserInputError { error } => Ok(error), - other => anyhow::bail!("error {:?} is not UserInputError", other), - } - } -} - -impl From for SuiError { - fn from(error: UserInputError) -> Self { - SuiError::UserInputError { error } - } -} - -impl From for SuiError { - fn from(error: SuiObjectResponseError) -> Self { - SuiError::SuiObjectResponseError { error } - } -} - -impl SuiError { - pub fn individual_error_indicates_epoch_change(&self) -> bool { - matches!( - self, - SuiError::ValidatorHaltedAtEpochEnd | SuiError::MissingCommitteeAtEpoch(_) - ) - } - - /// Returns if the error is retryable and if the error's retryability is - /// explicitly categorized. - /// There should be only a handful of retryable errors. For now we list - /// common non-retryable error below to help us find more retryable - /// errors in logs. - pub fn is_retryable(&self) -> (bool, bool) { - let retryable = match self { - // Network error - SuiError::RpcError { .. } => true, - - // Reconfig error - SuiError::ValidatorHaltedAtEpochEnd => true, - SuiError::MissingCommitteeAtEpoch(..) => true, - SuiError::WrongEpoch { .. } => true, - - SuiError::UserInputError { error } => { - match error { - // Only ObjectNotFound and DependentPackageNotFound is potentially retryable - UserInputError::ObjectNotFound { .. } => true, - UserInputError::DependentPackageNotFound { .. } => true, - _ => false, - } - } - - SuiError::PotentiallyTemporarilyInvalidSignature { .. } => true, - - // Overload errors - SuiError::TooManyTransactionsPendingExecution { .. } => true, - SuiError::TooManyTransactionsPendingOnObject { .. } => true, - SuiError::TooOldTransactionPendingOnObject { .. } => true, - SuiError::TooManyTransactionsPendingConsensus => true, - SuiError::ValidatorOverloadedRetryAfter { .. } => true, - - // Non retryable error - SuiError::ExecutionError(..) => false, - SuiError::ByzantineAuthoritySuspicion { .. } => false, - SuiError::QuorumFailedToGetEffectsQuorumWhenProcessingTransaction { .. } => false, - SuiError::TxAlreadyFinalizedWithDifferentUserSigs => false, - SuiError::FailedToVerifyTxCertWithExecutedEffects { .. } => false, - SuiError::ObjectLockConflict { .. } => false, - - // For all un-categorized errors, return here with categorized = false. - _ => return (false, false), - }; - - (retryable, true) - } - - pub fn is_object_or_package_not_found(&self) -> bool { - match self { - SuiError::UserInputError { error } => { - matches!( - error, - UserInputError::ObjectNotFound { .. } - | UserInputError::DependentPackageNotFound { .. } - ) - } - _ => false, - } - } - - pub fn is_overload(&self) -> bool { - matches!( - self, - SuiError::TooManyTransactionsPendingExecution { .. } - | SuiError::TooManyTransactionsPendingOnObject { .. } - | SuiError::TooOldTransactionPendingOnObject { .. } - | SuiError::TooManyTransactionsPendingConsensus - ) - } - - pub fn is_retryable_overload(&self) -> bool { - matches!(self, SuiError::ValidatorOverloadedRetryAfter { .. }) - } -} - -impl Ord for SuiError { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - Ord::cmp(self.as_ref(), other.as_ref()) - } -} - -impl PartialOrd for SuiError { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -type BoxError = Box; - -pub type ExecutionErrorKind = ExecutionFailureStatus; - -#[derive(Debug)] -pub struct ExecutionError { - inner: Box, -} - -#[derive(Debug)] -struct ExecutionErrorInner { - kind: ExecutionErrorKind, - source: Option, - command: Option, -} - -impl ExecutionError { - pub fn new(kind: ExecutionErrorKind, source: Option) -> Self { - Self { - inner: Box::new(ExecutionErrorInner { - kind, - source, - command: None, - }), - } - } - - pub fn new_with_source>(kind: ExecutionErrorKind, source: E) -> Self { - Self::new(kind, Some(source.into())) - } - - pub fn invariant_violation>(source: E) -> Self { - Self::new_with_source(ExecutionFailureStatus::InvariantViolation, source) - } - - pub fn with_command_index(mut self, command: CommandIndex) -> Self { - self.inner.command = Some(command); - self - } - - pub fn from_kind(kind: ExecutionErrorKind) -> Self { - Self::new(kind, None) - } - - pub fn kind(&self) -> &ExecutionErrorKind { - &self.inner.kind - } - - pub fn command(&self) -> Option { - self.inner.command - } - - pub fn source(&self) -> &Option { - &self.inner.source - } - - pub fn to_execution_status(&self) -> (ExecutionFailureStatus, Option) { - (self.kind().clone(), self.command()) - } -} - -impl std::fmt::Display for ExecutionError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "ExecutionError: {:?}", self) - } -} - -impl std::error::Error for ExecutionError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.inner.source.as_ref().map(|e| &**e as _) - } -} - -impl From for ExecutionError { - fn from(kind: ExecutionErrorKind) -> Self { - Self::from_kind(kind) - } -} - -pub fn command_argument_error(e: CommandArgumentError, arg_idx: usize) -> ExecutionError { - ExecutionError::from_kind(ExecutionErrorKind::command_argument_error( - e, - arg_idx as u16, - )) -} diff --git a/crates/sui-types/src/event.rs b/crates/sui-types/src/event.rs deleted file mode 100755 index 397e86193b5..00000000000 --- a/crates/sui-types/src/event.rs +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::str::FromStr; - -use anyhow::ensure; -use move_core_types::{ - account_address::AccountAddress, - annotated_value::{MoveStruct, MoveStructLayout}, - ident_str, - identifier::{IdentStr, Identifier}, - language_storage::StructTag, -}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use serde_with::{serde_as, Bytes}; - -use crate::{ - base_types::{ObjectID, SuiAddress, TransactionDigest}, - error::{SuiError, SuiResult}, - object::bounded_visitor::BoundedVisitor, - sui_serde::{BigInt, Readable}, - SUI_SYSTEM_ADDRESS, -}; - -/// A universal Sui event type encapsulating different types of events -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct EventEnvelope { - /// UTC timestamp in milliseconds since epoch (1/1/1970) - pub timestamp: u64, - /// Transaction digest of associated transaction - pub tx_digest: TransactionDigest, - /// Consecutive per-tx counter assigned to this event. - pub event_num: u64, - /// Specific event type - pub event: Event, - /// Move event's json value - pub parsed_json: Value, -} -/// Unique ID of a Sui Event, the ID is a combination of tx seq number and event -/// seq number, the ID is local to this particular fullnode and will be -/// different from other fullnode. -#[serde_as] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Hash)] -#[serde(rename_all = "camelCase")] -pub struct EventID { - pub tx_digest: TransactionDigest, - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub event_seq: u64, -} - -impl From<(TransactionDigest, u64)> for EventID { - fn from((tx_digest_num, event_seq_number): (TransactionDigest, u64)) -> Self { - Self { - tx_digest: tx_digest_num as TransactionDigest, - event_seq: event_seq_number, - } - } -} - -impl From for String { - fn from(id: EventID) -> Self { - format!("{:?}:{}", id.tx_digest, id.event_seq) - } -} - -impl TryFrom for EventID { - type Error = anyhow::Error; - - fn try_from(value: String) -> Result { - let values = value.split(':').collect::>(); - ensure!(values.len() == 2, "Malformed EventID : {value}"); - Ok(( - TransactionDigest::from_str(values[0])?, - u64::from_str(values[1])?, - ) - .into()) - } -} - -impl EventEnvelope { - pub fn new( - timestamp: u64, - tx_digest: TransactionDigest, - event_num: u64, - event: Event, - move_struct_json_value: Value, - ) -> Self { - Self { - timestamp, - tx_digest, - event_num, - event, - parsed_json: move_struct_json_value, - } - } -} - -/// Specific type of event -#[serde_as] -#[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)] -pub struct Event { - pub package_id: ObjectID, - pub transaction_module: Identifier, - pub sender: SuiAddress, - pub type_: StructTag, - #[serde_as(as = "Bytes")] - pub contents: Vec, -} - -impl Event { - pub fn new( - package_id: &AccountAddress, - module: &IdentStr, - sender: SuiAddress, - type_: StructTag, - contents: Vec, - ) -> Self { - Self { - package_id: ObjectID::from(*package_id), - transaction_module: Identifier::from(module), - sender, - type_, - contents, - } - } - pub fn move_event_to_move_struct( - contents: &[u8], - layout: MoveStructLayout, - ) -> SuiResult { - BoundedVisitor::deserialize_struct(contents, &layout).map_err(|e| { - SuiError::ObjectSerializationError { - error: e.to_string(), - } - }) - } - - pub fn is_system_epoch_info_event(&self) -> bool { - self.type_.address == SUI_SYSTEM_ADDRESS - && self.type_.module.as_ident_str() == ident_str!("sui_system_state_inner") - && self.type_.name.as_ident_str() == ident_str!("SystemEpochInfoEvent") - } -} - -impl Event { - pub fn random_for_testing() -> Self { - Self { - package_id: ObjectID::random(), - transaction_module: Identifier::new("test").unwrap(), - sender: AccountAddress::random().into(), - type_: StructTag { - address: AccountAddress::random(), - module: Identifier::new("test").unwrap(), - name: Identifier::new("test").unwrap(), - type_params: vec![], - }, - contents: vec![], - } - } -} - -// Event emitted in move code `fun advance_epoch` -#[derive(Deserialize)] -pub struct SystemEpochInfoEvent { - pub epoch: u64, - pub protocol_version: u64, - pub reference_gas_price: u64, - pub total_stake: u64, - pub storage_fund_reinvestment: u64, - pub storage_charge: u64, - pub storage_rebate: u64, - pub storage_fund_balance: u64, - pub stake_subsidy_amount: u64, - pub total_gas_fees: u64, - pub total_stake_rewards_distributed: u64, - pub leftover_storage_fund_inflow: u64, -} diff --git a/crates/sui-types/src/execution.rs b/crates/sui-types/src/execution.rs deleted file mode 100644 index 1b132a2f196..00000000000 --- a/crates/sui-types/src/execution.rs +++ /dev/null @@ -1,489 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::{BTreeMap, BTreeSet, HashSet}; - -use move_binary_format::file_format::AbilitySet; -use move_core_types::{identifier::IdentStr, resolver::ResourceResolver}; -use move_vm_types::loaded_data::runtime_types::Type; -use once_cell::sync::Lazy; -use serde::{Deserialize, Serialize}; - -use crate::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress}, - coin::Coin, - digests::{ObjectDigest, TransactionDigest}, - error::{ExecutionError, ExecutionErrorKind, SuiError}, - event::Event, - execution_status::CommandArgumentError, - is_system_package, - object::{Data, Object, Owner}, - storage::{BackingPackageStore, ChildObjectResolver, ObjectChange, StorageView}, - transfer::Receiving, -}; - -pub trait SuiResolver: ResourceResolver + BackingPackageStore { - fn as_backing_package_store(&self) -> &dyn BackingPackageStore; -} - -/// A type containing all of the information needed to work with a deleted -/// shared object in execution and when committing the execution effects of the -/// transaction. This holds: -/// 0. The object ID of the deleted shared object. -/// 1. The version of the shared object. -/// 2. Whether the object appeared as mutable (or owned) in the transaction, or -/// as a read-only shared object. -/// 3. The transaction digest of the previous transaction that used this shared -/// object mutably or took it by value. -pub type DeletedSharedObjectInfo = (ObjectID, SequenceNumber, bool, TransactionDigest); - -/// A sequence of information about deleted shared objects in the transaction's -/// inputs. -pub type DeletedSharedObjects = Vec; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum SharedInput { - Existing(ObjectRef), - Deleted(DeletedSharedObjectInfo), -} - -impl SuiResolver for T -where - T: ResourceResolver, - T: BackingPackageStore, -{ - fn as_backing_package_store(&self) -> &dyn BackingPackageStore { - self - } -} - -/// Interface with the store necessary to execute a programmable transaction -pub trait ExecutionState: StorageView + SuiResolver { - fn as_sui_resolver(&self) -> &dyn SuiResolver; - fn as_child_resolver(&self) -> &dyn ChildObjectResolver; -} - -impl ExecutionState for T -where - T: StorageView, - T: SuiResolver, -{ - fn as_sui_resolver(&self) -> &dyn SuiResolver { - self - } - - fn as_child_resolver(&self) -> &dyn ChildObjectResolver { - self - } -} - -/// View of the store necessary to produce the layouts of types. -pub trait TypeLayoutStore: BackingPackageStore {} -impl TypeLayoutStore for T where T: BackingPackageStore {} - -#[derive(Debug)] -pub enum ExecutionResults { - V1(ExecutionResultsV1), - V2(ExecutionResultsV2), -} - -#[derive(Debug)] -pub struct ExecutionResultsV1 { - pub object_changes: BTreeMap, - pub user_events: Vec, -} - -/// Used by sui-execution v1 and above, to capture the execution results from -/// Move. The results represent the primitive information that can then be used -/// to construct both transaction effects V1 and V2. -#[derive(Debug, Default)] -pub struct ExecutionResultsV2 { - /// All objects written regardless of whether they were mutated, created, or - /// unwrapped. - pub written_objects: BTreeMap, - /// All objects that existed prior to this transaction, and are modified in - /// this transaction. This includes any type of modification, including - /// mutated, wrapped and deleted objects. - pub modified_objects: BTreeSet, - /// All object IDs created in this transaction. - pub created_object_ids: BTreeSet, - /// All object IDs deleted in this transaction. - /// No object ID should be in both created_object_ids and - /// deleted_object_ids. - pub deleted_object_ids: BTreeSet, - /// All Move events emitted in this transaction. - pub user_events: Vec, -} - -impl ExecutionResultsV2 { - pub fn drop_writes(&mut self) { - self.written_objects.clear(); - self.modified_objects.clear(); - self.created_object_ids.clear(); - self.deleted_object_ids.clear(); - self.user_events.clear(); - } - - pub fn merge_results(&mut self, new_results: Self) { - self.written_objects.extend(new_results.written_objects); - self.modified_objects.extend(new_results.modified_objects); - self.created_object_ids - .extend(new_results.created_object_ids); - self.deleted_object_ids - .extend(new_results.deleted_object_ids); - self.user_events.extend(new_results.user_events); - } - - pub fn update_version_and_previous_tx( - &mut self, - lamport_version: SequenceNumber, - prev_tx: TransactionDigest, - ) { - for (id, obj) in self.written_objects.iter_mut() { - // TODO: We can now get rid of the following logic by passing in lamport version - // into the execution layer, and create new objects using the lamport version - // directly. - - // Update the version for the written object. - match &mut obj.data { - Data::Move(obj) => { - // Move objects all get the transaction's lamport timestamp - obj.increment_version_to(lamport_version); - } - - Data::Package(pkg) => { - // Modified packages get their version incremented (this is a special case that - // only applies to system packages). All other packages can only be created, - // and they are left alone. - if self.modified_objects.contains(id) { - debug_assert!(is_system_package(*id)); - pkg.increment_version(); - } - } - } - - // Record the version that the shared object was created at in its owner field. - // Note, this only works because shared objects must be created as - // shared (not created as owned in one transaction and later - // converted to shared in another). - if let Owner::Shared { - initial_shared_version, - } = &mut obj.owner - { - if self.created_object_ids.contains(id) { - assert_eq!( - *initial_shared_version, - SequenceNumber::new(), - "Initial version should be blank before this point for {id:?}", - ); - *initial_shared_version = lamport_version; - } - } - - obj.previous_transaction = prev_tx; - } - } -} - -#[derive(Clone, Debug)] -pub enum InputObjectMetadata { - Receiving { - id: ObjectID, - version: SequenceNumber, - }, - InputObject { - id: ObjectID, - is_mutable_input: bool, - owner: Owner, - version: SequenceNumber, - }, -} - -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct DynamicallyLoadedObjectMetadata { - pub version: SequenceNumber, - pub digest: ObjectDigest, - pub owner: Owner, - pub storage_rebate: u64, - pub previous_transaction: TransactionDigest, -} - -#[derive(Clone, Debug)] -pub struct InputValue { - /// Used to remember the object ID and owner even if the value is taken - pub object_metadata: Option, - pub inner: ResultValue, -} - -#[derive(Clone, Debug)] -pub struct ResultValue { - /// This is used primarily for values that have `copy` but not `drop` as - /// they must have been copied after the last borrow, otherwise we - /// cannot consider the last "copy" to be instead a "move" of the value. - pub last_usage_kind: Option, - pub value: Option, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum UsageKind { - BorrowImm, - BorrowMut, - ByValue, -} - -#[derive(Debug, Clone)] -pub enum Value { - Object(ObjectValue), - Raw(RawValueType, Vec), - Receiving(ObjectID, SequenceNumber, Option), -} - -#[derive(Debug, Clone)] -pub struct ObjectValue { - pub type_: Type, - pub has_public_transfer: bool, - // true if it has been used in a public, non-entry Move call - // In other words, false if all usages have been with non-Move commands or - // entry Move functions - pub used_in_non_entry_move_call: bool, - pub contents: ObjectContents, -} - -#[derive(Debug, Clone)] -pub enum ObjectContents { - Coin(Coin), - Raw(Vec), -} - -#[derive(Debug, Clone)] -pub enum RawValueType { - Any, - Loaded { - ty: Type, - abilities: AbilitySet, - used_in_non_entry_move_call: bool, - }, -} - -#[derive(Clone, Copy)] -pub enum CommandKind<'a> { - MoveCall { - package: ObjectID, - module: &'a IdentStr, - function: &'a IdentStr, - }, - MakeMoveVec, - TransferObjects, - SplitCoins, - MergeCoins, - Publish, - Upgrade, -} - -impl InputObjectMetadata { - pub fn id(&self) -> ObjectID { - match self { - InputObjectMetadata::Receiving { id, .. } => *id, - InputObjectMetadata::InputObject { id, .. } => *id, - } - } - - pub fn version(&self) -> SequenceNumber { - match self { - InputObjectMetadata::Receiving { version, .. } => *version, - InputObjectMetadata::InputObject { version, .. } => *version, - } - } -} - -impl InputValue { - pub fn new_object(object_metadata: InputObjectMetadata, value: ObjectValue) -> Self { - InputValue { - object_metadata: Some(object_metadata), - inner: ResultValue::new(Value::Object(value)), - } - } - - pub fn new_raw(ty: RawValueType, value: Vec) -> Self { - InputValue { - object_metadata: None, - inner: ResultValue::new(Value::Raw(ty, value)), - } - } - - pub fn new_receiving_object(id: ObjectID, version: SequenceNumber) -> Self { - InputValue { - object_metadata: Some(InputObjectMetadata::Receiving { id, version }), - inner: ResultValue::new(Value::Receiving(id, version, None)), - } - } -} - -impl ResultValue { - pub fn new(value: Value) -> Self { - Self { - last_usage_kind: None, - value: Some(value), - } - } -} - -impl Value { - pub fn is_copyable(&self) -> bool { - match self { - Value::Object(_) => false, - Value::Raw(RawValueType::Any, _) => true, - Value::Raw(RawValueType::Loaded { abilities, .. }, _) => abilities.has_copy(), - Value::Receiving(_, _, _) => false, - } - } - - pub fn write_bcs_bytes(&self, buf: &mut Vec) { - match self { - Value::Object(obj_value) => obj_value.write_bcs_bytes(buf), - Value::Raw(_, bytes) => buf.extend(bytes), - Value::Receiving(id, version, _) => { - buf.extend(Receiving::new(*id, *version).to_bcs_bytes()) - } - } - } - - pub fn was_used_in_non_entry_move_call(&self) -> bool { - match self { - Value::Object(obj) => obj.used_in_non_entry_move_call, - // Any is only used for Pure inputs, and if it was used by &mut it would have switched - // to Loaded - Value::Raw(RawValueType::Any, _) => false, - Value::Raw( - RawValueType::Loaded { - used_in_non_entry_move_call, - .. - }, - _, - ) => *used_in_non_entry_move_call, - // Only thing you can do with a `Receiving` is consume it, so once it's used it - // can't be used again. - Value::Receiving(_, _, _) => false, - } - } -} - -impl ObjectValue { - /// # Safety - /// We must have the Type is the coin type, but we are unable to check it at - /// this spot - pub unsafe fn coin(type_: Type, coin: Coin) -> Self { - Self { - type_, - has_public_transfer: true, - used_in_non_entry_move_call: false, - contents: ObjectContents::Coin(coin), - } - } - - pub fn ensure_public_transfer_eligible(&self) -> Result<(), ExecutionError> { - if !self.has_public_transfer { - return Err(ExecutionErrorKind::InvalidTransferObject.into()); - } - Ok(()) - } - - pub fn write_bcs_bytes(&self, buf: &mut Vec) { - match &self.contents { - ObjectContents::Raw(bytes) => buf.extend(bytes), - ObjectContents::Coin(coin) => buf.extend(coin.to_bcs_bytes()), - } - } -} - -pub trait TryFromValue: Sized { - fn try_from_value(value: Value) -> Result; -} - -impl TryFromValue for Value { - fn try_from_value(value: Value) -> Result { - Ok(value) - } -} - -impl TryFromValue for ObjectValue { - fn try_from_value(value: Value) -> Result { - match value { - Value::Object(o) => Ok(o), - Value::Raw(RawValueType::Any, _) => Err(CommandArgumentError::TypeMismatch), - Value::Raw(RawValueType::Loaded { .. }, _) => Err(CommandArgumentError::TypeMismatch), - Value::Receiving(_, _, _) => Err(CommandArgumentError::TypeMismatch), - } - } -} - -impl TryFromValue for SuiAddress { - fn try_from_value(value: Value) -> Result { - try_from_value_prim(&value, Type::Address) - } -} - -impl TryFromValue for u64 { - fn try_from_value(value: Value) -> Result { - try_from_value_prim(&value, Type::U64) - } -} - -fn try_from_value_prim<'a, T: Deserialize<'a>>( - value: &'a Value, - expected_ty: Type, -) -> Result { - match value { - Value::Object(_) => Err(CommandArgumentError::TypeMismatch), - Value::Receiving(_, _, _) => Err(CommandArgumentError::TypeMismatch), - Value::Raw(RawValueType::Any, bytes) => { - bcs::from_bytes(bytes).map_err(|_| CommandArgumentError::InvalidBCSBytes) - } - Value::Raw(RawValueType::Loaded { ty, .. }, bytes) => { - if ty != &expected_ty { - return Err(CommandArgumentError::TypeMismatch); - } - bcs::from_bytes(bytes).map_err(|_| CommandArgumentError::InvalidBCSBytes) - } - } -} - -/// If a transaction digest shows up in this list, when executing such -/// transaction, we will always return `ExecutionError::CertificateDenied` -/// without executing it (but still do gas smashing). Because this list is not -/// gated by protocol version, there are a few important criteria for adding a -/// digest to this list: -/// 1. The certificate must be causing all validators to either panic or hang -/// forever deterministically. -/// 2. If we ever ship a fix to make it no longer panic or hang when executing -/// such transaction, -/// we must make sure the transaction is already in this list. Otherwise nodes -/// running the newer version without these transactions in the list will -/// generate forked result. Below is a scenario of when we need to use this -/// list: -/// 1. We detect that a specific transaction is causing all validators to either -/// panic or hang forever deterministically. -/// 2. We push a CertificateDenyConfig to deny such transaction to all -/// validators asap. -/// 3. To make sure that all fullnodes are able to sync to the latest version, -/// we need to add the transaction digest -/// to this list as well asap, and ship this binary to all fullnodes, so that -/// they can sync past this transaction. -/// 4. We then can start fixing the issue, and ship the fix to all nodes. -/// 5. Unfortunately, we can't remove the transaction digest from this list, -/// because if we do so, any future -/// node that sync from genesis will fork on this transaction. We may be able to -/// remove it once we have stable snapshots and the binary has a minimum -/// supported protocol version past the epoch. -pub fn get_denied_certificates() -> &'static HashSet { - static DENIED_CERTIFICATES: Lazy> = Lazy::new(|| HashSet::from([])); - Lazy::force(&DENIED_CERTIFICATES) -} - -pub fn is_certificate_denied( - transaction_digest: &TransactionDigest, - certificate_deny_set: &HashSet, -) -> bool { - certificate_deny_set.contains(transaction_digest) - || get_denied_certificates().contains(transaction_digest) -} diff --git a/crates/sui-types/src/gas.rs b/crates/sui-types/src/gas.rs deleted file mode 100644 index a9e649f479f..00000000000 --- a/crates/sui-types/src/gas.rs +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright (c) 2021, Facebook, Inc. and its affiliates -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub use checked::*; - -#[sui_macros::with_checked_arithmetic] -pub mod checked { - - use enum_dispatch::enum_dispatch; - use itertools::MultiUnzip; - use schemars::JsonSchema; - use serde::{Deserialize, Serialize}; - use serde_with::serde_as; - use sui_protocol_config::ProtocolConfig; - - use crate::{ - effects::{TransactionEffects, TransactionEffectsAPI}, - error::{ExecutionError, SuiResult, UserInputError, UserInputResult}, - gas_model::{ - gas_predicates::gas_price_too_high, gas_v2::SuiGasStatus as SuiGasStatusV2, - tables::GasStatus, - }, - object::Object, - sui_serde::{BigInt, Readable}, - transaction::ObjectReadResult, - ObjectID, - }; - - #[enum_dispatch] - pub trait SuiGasStatusAPI { - fn is_unmetered(&self) -> bool; - fn move_gas_status(&self) -> &GasStatus; - fn move_gas_status_mut(&mut self) -> &mut GasStatus; - fn bucketize_computation(&mut self) -> Result<(), ExecutionError>; - fn summary(&self) -> GasCostSummary; - fn gas_budget(&self) -> u64; - fn storage_gas_units(&self) -> u64; - fn storage_rebate(&self) -> u64; - fn unmetered_storage_rebate(&self) -> u64; - fn gas_used(&self) -> u64; - fn reset_storage_cost_and_rebate(&mut self); - fn charge_storage_read(&mut self, size: usize) -> Result<(), ExecutionError>; - fn charge_publish_package(&mut self, size: usize) -> Result<(), ExecutionError>; - fn track_storage_mutation( - &mut self, - object_id: ObjectID, - new_size: usize, - storage_rebate: u64, - ) -> u64; - fn charge_storage_and_rebate(&mut self) -> Result<(), ExecutionError>; - fn adjust_computation_on_out_of_gas(&mut self); - } - - /// Version aware enum for gas status. - #[enum_dispatch(SuiGasStatusAPI)] - #[derive(Debug)] - pub enum SuiGasStatus { - // V1 does not exists any longer as it was a pre mainnet version. - // So we start the enum from V2 - V2(SuiGasStatusV2), - } - - impl SuiGasStatus { - pub fn new( - gas_budget: u64, - gas_price: u64, - reference_gas_price: u64, - config: &ProtocolConfig, - ) -> SuiResult { - // Common checks. We may pull them into version specific status as needed, but - // they are unlikely to change. - - // gas price must be bigger or equal to reference gas price - if gas_price < reference_gas_price { - return Err(UserInputError::GasPriceUnderRGP { - gas_price, - reference_gas_price, - } - .into()); - } - if gas_price_too_high(config.gas_model_version()) && gas_price >= config.max_gas_price() - { - return Err(UserInputError::GasPriceTooHigh { - max_gas_price: config.max_gas_price(), - } - .into()); - } - - Ok(Self::V2(SuiGasStatusV2::new_with_budget( - gas_budget, - gas_price, - reference_gas_price, - config, - ))) - } - - pub fn new_unmetered() -> Self { - Self::V2(SuiGasStatusV2::new_unmetered()) - } - - // This is the only public API on SuiGasStatus, all other gas related operations - // should go through `GasCharger` - pub fn check_gas_balance( - &self, - gas_objs: &[&ObjectReadResult], - gas_budget: u64, - ) -> UserInputResult { - match self { - Self::V2(status) => status.check_gas_balance(gas_objs, gas_budget), - } - } - } - - /// Summary of the charges in a transaction. - /// Storage is charged independently of computation. - /// There are 3 parts to the storage charges: - /// `storage_cost`: it is the charge of storage at the time the transaction - /// is executed. The cost of storage is the number of - /// bytes of the objects being mutated multiplied by a - /// variable storage cost per byte `storage_rebate`: this is the amount - /// a user gets back when manipulating an object. The - /// `storage_rebate` is the `storage_cost` for an object minus fees. - /// `non_refundable_storage_fee`: not all the value of the object storage - /// cost is given back to user and there - /// is a small fraction that is kept by - /// the system. This value tracks that charge. - /// - /// When looking at a gas cost summary the amount charged to the user is - /// `computation_cost + storage_cost - storage_rebate` - /// and that is the amount that is deducted from the gas coins. - /// `non_refundable_storage_fee` is collected from the objects being - /// mutated/deleted and it is tracked by the system in storage funds. - /// - /// Objects deleted, including the older versions of objects mutated, have - /// the storage field on the objects added up to a pool of "potential - /// rebate". This rebate then is reduced by the "nonrefundable rate" - /// such that: `potential_rebate(storage cost of deleted/mutated - /// objects) = storage_rebate + non_refundable_storage_fee` - - #[serde_as] - #[derive(Eq, PartialEq, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] - #[serde(rename_all = "camelCase")] - pub struct GasCostSummary { - /// Cost of computation/execution - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub computation_cost: u64, - /// Storage cost, it's the sum of all storage cost for all objects - /// created or mutated. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub storage_cost: u64, - /// The amount of storage cost refunded to the user for all objects - /// deleted or mutated in the transaction. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub storage_rebate: u64, - /// The fee for the rebate. The portion of the storage rebate kept by - /// the system. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub non_refundable_storage_fee: u64, - } - - impl GasCostSummary { - pub fn new( - computation_cost: u64, - storage_cost: u64, - storage_rebate: u64, - non_refundable_storage_fee: u64, - ) -> GasCostSummary { - GasCostSummary { - computation_cost, - storage_cost, - storage_rebate, - non_refundable_storage_fee, - } - } - - pub fn gas_used(&self) -> u64 { - self.computation_cost + self.storage_cost - } - - /// Portion of the storage rebate that gets passed on to the transaction - /// sender. The remainder will be burned, then re-minted + added - /// to the storage fund at the next epoch change - pub fn sender_rebate(&self, storage_rebate_rate: u64) -> u64 { - // we round storage rebate such that `>= x.5` goes to x+1 (rounds up) and - // `< x.5` goes to x (truncates). We replicate `f32/64::round()` - const BASIS_POINTS: u128 = 10000; - (((self.storage_rebate as u128 * storage_rebate_rate as u128) - + (BASIS_POINTS / 2)) // integer rounding adds half of the BASIS_POINTS (denominator) - / BASIS_POINTS) as u64 - } - - /// Get net gas usage, positive number means used gas; negative number - /// means refund. - pub fn net_gas_usage(&self) -> i64 { - self.gas_used() as i64 - self.storage_rebate as i64 - } - - pub fn new_from_txn_effects<'a>( - transactions: impl Iterator, - ) -> GasCostSummary { - let (storage_costs, computation_costs, storage_rebates, non_refundable_storage_fee): ( - Vec, - Vec, - Vec, - Vec, - ) = transactions - .map(|e| { - ( - e.gas_cost_summary().storage_cost, - e.gas_cost_summary().computation_cost, - e.gas_cost_summary().storage_rebate, - e.gas_cost_summary().non_refundable_storage_fee, - ) - }) - .multiunzip(); - - GasCostSummary { - storage_cost: storage_costs.iter().sum(), - computation_cost: computation_costs.iter().sum(), - storage_rebate: storage_rebates.iter().sum(), - non_refundable_storage_fee: non_refundable_storage_fee.iter().sum(), - } - } - } - - impl std::fmt::Display for GasCostSummary { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "computation_cost: {}, storage_cost: {}, storage_rebate: {}, non_refundable_storage_fee: {}", - self.computation_cost, - self.storage_cost, - self.storage_rebate, - self.non_refundable_storage_fee, - ) - } - } - - impl std::ops::AddAssign<&Self> for GasCostSummary { - fn add_assign(&mut self, other: &Self) { - self.computation_cost += other.computation_cost; - self.storage_cost += other.storage_cost; - self.storage_rebate += other.storage_rebate; - self.non_refundable_storage_fee += other.non_refundable_storage_fee; - } - } - - impl std::ops::AddAssign for GasCostSummary { - fn add_assign(&mut self, other: Self) { - self.add_assign(&other) - } - } - - // Helper functions to deal with gas coins operations. - // - - pub fn deduct_gas(gas_object: &mut Object, charge_or_rebate: i64) { - // The object must be a gas coin as we have checked in transaction handle phase. - let gas_coin = gas_object.data.try_as_move_mut().unwrap(); - let balance = gas_coin.get_coin_value_unsafe(); - let new_balance = if charge_or_rebate < 0 { - balance + (-charge_or_rebate as u64) - } else { - assert!(balance >= charge_or_rebate as u64); - balance - charge_or_rebate as u64 - }; - gas_coin.set_coin_value_unsafe(new_balance) - } - - pub fn get_gas_balance(gas_object: &Object) -> UserInputResult { - if let Some(move_obj) = gas_object.data.try_as_move() { - if !move_obj.type_().is_gas_coin() { - return Err(UserInputError::InvalidGasObject { - object_id: gas_object.id(), - }); - } - Ok(move_obj.get_coin_value_unsafe()) - } else { - Err(UserInputError::InvalidGasObject { - object_id: gas_object.id(), - }) - } - } -} diff --git a/crates/sui-types/src/gas_model/mod.rs b/crates/sui-types/src/gas_model/mod.rs deleted file mode 100644 index 85981522524..00000000000 --- a/crates/sui-types/src/gas_model/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod gas_predicates; -pub mod gas_v2; -pub mod tables; -pub mod units_types; diff --git a/crates/sui-types/src/gas_model/tables.rs b/crates/sui-types/src/gas_model/tables.rs deleted file mode 100644 index 5847663f7f6..00000000000 --- a/crates/sui-types/src/gas_model/tables.rs +++ /dev/null @@ -1,937 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use move_binary_format::errors::{PartialVMError, PartialVMResult}; -use move_core_types::{ - gas_algebra::{AbstractMemorySize, InternalGas, NumArgs, NumBytes}, - language_storage::ModuleId, - vm_status::StatusCode, -}; -use move_vm_profiler::GasProfiler; -use move_vm_types::{ - gas::{GasMeter, SimpleInstruction}, - loaded_data::runtime_types::Type, - views::{TypeView, ValueView}, -}; -use once_cell::sync::Lazy; - -use super::gas_predicates::{charge_input_as_memory, use_legacy_abstract_size}; -use crate::gas_model::units_types::{CostTable, Gas, GasCost}; - -/// VM flat fee -pub const VM_FLAT_FEE: Gas = Gas::new(8_000); - -/// The size in bytes for a non-string or address constant on the stack -pub const CONST_SIZE: AbstractMemorySize = AbstractMemorySize::new(16); - -/// The size in bytes for a reference on the stack -pub const REFERENCE_SIZE: AbstractMemorySize = AbstractMemorySize::new(8); - -/// The size of a struct in bytes -pub const STRUCT_SIZE: AbstractMemorySize = AbstractMemorySize::new(2); - -/// The size of a vector (without its containing data) in bytes -pub const VEC_SIZE: AbstractMemorySize = AbstractMemorySize::new(8); - -/// For exists checks on data that doesn't exists this is the multiplier that is -/// used. -pub const MIN_EXISTS_DATA_SIZE: AbstractMemorySize = AbstractMemorySize::new(100); - -pub static ZERO_COST_SCHEDULE: Lazy = Lazy::new(zero_cost_schedule); - -pub static INITIAL_COST_SCHEDULE: Lazy = Lazy::new(initial_cost_schedule_v1); - -/// The Move VM implementation of state for gas metering. -/// -/// Initialize with a `CostTable` and the gas provided to the transaction. -/// Provide all the proper guarantees about gas metering in the Move VM. -/// -/// Every client must use an instance of this type to interact with the Move VM. -#[allow(dead_code)] -#[derive(Debug)] -pub struct GasStatus { - pub gas_model_version: u64, - cost_table: CostTable, - gas_left: InternalGas, - gas_price: u64, - initial_budget: InternalGas, - charge: bool, - - // The current height of the operand stack, and the maximal height that it has reached. - stack_height_high_water_mark: u64, - stack_height_current: u64, - stack_height_next_tier_start: Option, - stack_height_current_tier_mult: u64, - - // The current (abstract) size of the operand stack and the maximal size that it has reached. - stack_size_high_water_mark: u64, - stack_size_current: u64, - stack_size_next_tier_start: Option, - stack_size_current_tier_mult: u64, - - // The total number of bytecode instructions that have been executed in the transaction. - instructions_executed: u64, - instructions_next_tier_start: Option, - instructions_current_tier_mult: u64, - - profiler: Option, -} - -impl GasStatus { - /// Initialize the gas state with metering enabled. - /// - /// Charge for every operation and fail when there is no more gas to pay for - /// operations. This is the instantiation that must be used when - /// executing a user script. - - pub fn new(cost_table: CostTable, budget: u64, gas_price: u64, gas_model_version: u64) -> Self { - assert!(gas_price > 0, "gas price cannot be 0"); - let budget_in_unit = budget / gas_price; - let gas_left = Self::to_internal_units(budget_in_unit); - let (stack_height_current_tier_mult, stack_height_next_tier_start) = - cost_table.stack_height_tier(0); - let (stack_size_current_tier_mult, stack_size_next_tier_start) = - cost_table.stack_size_tier(0); - let (instructions_current_tier_mult, instructions_next_tier_start) = - cost_table.instruction_tier(0); - Self { - gas_model_version, - gas_left, - gas_price, - initial_budget: gas_left, - cost_table, - charge: true, - stack_height_high_water_mark: 0, - stack_height_current: 0, - stack_size_high_water_mark: 0, - stack_size_current: 0, - instructions_executed: 0, - stack_height_current_tier_mult, - stack_size_current_tier_mult, - instructions_current_tier_mult, - stack_height_next_tier_start, - stack_size_next_tier_start, - instructions_next_tier_start, - profiler: None, - } - } - - /// Initialize the gas state with metering disabled. - /// - /// It should be used by clients in very specific cases and when executing - /// system code that does not have to charge the user. - pub fn new_unmetered() -> Self { - Self { - gas_model_version: 4, - gas_left: InternalGas::new(0), - gas_price: 1, - initial_budget: InternalGas::new(0), - cost_table: ZERO_COST_SCHEDULE.clone(), - charge: false, - stack_height_high_water_mark: 0, - stack_height_current: 0, - stack_size_high_water_mark: 0, - stack_size_current: 0, - instructions_executed: 0, - stack_height_current_tier_mult: 0, - stack_size_current_tier_mult: 0, - instructions_current_tier_mult: 0, - stack_height_next_tier_start: None, - stack_size_next_tier_start: None, - instructions_next_tier_start: None, - profiler: None, - } - } - - const INTERNAL_UNIT_MULTIPLIER: u64 = 1000; - - fn to_internal_units(val: u64) -> InternalGas { - InternalGas::new(val * Self::INTERNAL_UNIT_MULTIPLIER) - } - - #[allow(dead_code)] - fn to_mist(&self, val: InternalGas) -> u64 { - let gas: Gas = InternalGas::to_unit_round_down(val); - u64::from(gas) * self.gas_price - } - - pub fn push_stack(&mut self, pushes: u64) -> PartialVMResult<()> { - match self.stack_height_current.checked_add(pushes) { - // We should never hit this. - None => return Err(PartialVMError::new(StatusCode::ARITHMETIC_OVERFLOW)), - Some(new_height) => { - if new_height > self.stack_height_high_water_mark { - self.stack_height_high_water_mark = new_height; - } - self.stack_height_current = new_height; - } - } - - if let Some(stack_height_tier_next) = self.stack_height_next_tier_start { - if self.stack_height_current > stack_height_tier_next { - let (next_mul, next_tier) = - self.cost_table.stack_height_tier(self.stack_height_current); - self.stack_height_current_tier_mult = next_mul; - self.stack_height_next_tier_start = next_tier; - } - } - - Ok(()) - } - - pub fn pop_stack(&mut self, pops: u64) { - self.stack_height_current = self.stack_height_current.saturating_sub(pops); - } - - pub fn increase_instruction_count(&mut self, amount: u64) -> PartialVMResult<()> { - match self.instructions_executed.checked_add(amount) { - None => return Err(PartialVMError::new(StatusCode::PC_OVERFLOW)), - Some(new_pc) => { - self.instructions_executed = new_pc; - } - } - - if let Some(instr_tier_next) = self.instructions_next_tier_start { - if self.instructions_executed > instr_tier_next { - let (instr_cost, next_tier) = - self.cost_table.instruction_tier(self.instructions_executed); - self.instructions_current_tier_mult = instr_cost; - self.instructions_next_tier_start = next_tier; - } - } - - Ok(()) - } - - pub fn increase_stack_size(&mut self, size_amount: u64) -> PartialVMResult<()> { - match self.stack_size_current.checked_add(size_amount) { - None => return Err(PartialVMError::new(StatusCode::ARITHMETIC_OVERFLOW)), - Some(new_size) => { - if new_size > self.stack_size_high_water_mark { - self.stack_size_high_water_mark = new_size; - } - self.stack_size_current = new_size; - } - } - - if let Some(stack_size_tier_next) = self.stack_size_next_tier_start { - if self.stack_size_current > stack_size_tier_next { - let (next_mul, next_tier) = - self.cost_table.stack_size_tier(self.stack_size_current); - self.stack_size_current_tier_mult = next_mul; - self.stack_size_next_tier_start = next_tier; - } - } - - Ok(()) - } - - pub fn decrease_stack_size(&mut self, size_amount: u64) { - let new_size = self.stack_size_current.saturating_sub(size_amount); - if new_size > self.stack_size_high_water_mark { - self.stack_size_high_water_mark = new_size; - } - self.stack_size_current = new_size; - } - - /// Given: pushes + pops + increase + decrease in size for an instruction - /// charge for the execution of the instruction. - pub fn charge( - &mut self, - num_instructions: u64, - pushes: u64, - pops: u64, - incr_size: u64, - _decr_size: u64, - ) -> PartialVMResult<()> { - self.push_stack(pushes)?; - self.increase_instruction_count(num_instructions)?; - self.increase_stack_size(incr_size)?; - - self.deduct_gas( - GasCost::new( - self.instructions_current_tier_mult - .checked_mul(num_instructions) - .ok_or_else(|| PartialVMError::new(StatusCode::ARITHMETIC_OVERFLOW))?, - self.stack_size_current_tier_mult - .checked_mul(incr_size) - .ok_or_else(|| PartialVMError::new(StatusCode::ARITHMETIC_OVERFLOW))?, - self.stack_height_current_tier_mult - .checked_mul(pushes) - .ok_or_else(|| PartialVMError::new(StatusCode::ARITHMETIC_OVERFLOW))?, - ) - .total_internal(), - )?; - - // self.decrease_stack_size(decr_size); - self.pop_stack(pops); - Ok(()) - } - - /// Return the `CostTable` behind this `GasStatus`. - pub fn cost_table(&self) -> &CostTable { - &self.cost_table - } - - /// Return the gas left. - pub fn remaining_gas(&self) -> Gas { - self.gas_left.to_unit_round_down() - } - - /// Charge a given amount of gas and fail if not enough gas units are left. - pub fn deduct_gas(&mut self, amount: InternalGas) -> PartialVMResult<()> { - if !self.charge { - return Ok(()); - } - - match self.gas_left.checked_sub(amount) { - Some(gas_left) => { - self.gas_left = gas_left; - Ok(()) - } - None => { - self.gas_left = InternalGas::new(0); - Err(PartialVMError::new(StatusCode::OUT_OF_GAS)) - } - } - } - - // Deduct the amount provided with no conversion, as if it was InternalGasUnit - fn deduct_units(&mut self, amount: u64) -> PartialVMResult<()> { - self.deduct_gas(InternalGas::new(amount)) - } - - pub fn set_metering(&mut self, enabled: bool) { - self.charge = enabled - } - - // The amount of gas used, it does not include the multiplication for the gas - // price - pub fn gas_used_pre_gas_price(&self) -> u64 { - let gas: Gas = match self.initial_budget.checked_sub(self.gas_left) { - Some(val) => InternalGas::to_unit_round_down(val), - None => InternalGas::to_unit_round_down(self.initial_budget), - }; - u64::from(gas) - } - - // Charge the number of bytes with the cost per byte value - // As more bytes are read throughout the computation the cost per bytes is - // increased. - pub fn charge_bytes(&mut self, size: usize, cost_per_byte: u64) -> PartialVMResult<()> { - let computation_cost = if charge_input_as_memory(self.gas_model_version) { - self.increase_stack_size(size as u64)?; - self.stack_size_current_tier_mult * size as u64 * cost_per_byte - } else { - size as u64 * cost_per_byte - }; - self.deduct_units(computation_cost) - } - - fn abstract_memory_size(&self, val: impl ValueView) -> AbstractMemorySize { - if use_legacy_abstract_size(self.gas_model_version) { - val.legacy_abstract_memory_size() - } else { - val.abstract_memory_size() - } - } - - pub fn gas_price(&self) -> u64 { - self.gas_price - } - - pub fn stack_height_high_water_mark(&self) -> u64 { - self.stack_height_high_water_mark - } - - pub fn stack_size_high_water_mark(&self) -> u64 { - self.stack_size_high_water_mark - } - - pub fn instructions_executed(&self) -> u64 { - self.instructions_executed - } -} - -/// Returns a tuple of (, , , -/// ) -fn get_simple_instruction_stack_change( - instr: SimpleInstruction, -) -> (u64, u64, AbstractMemorySize, AbstractMemorySize) { - use SimpleInstruction::*; - - match instr { - // NB: The `Ret` pops are accounted for in `Call` instructions, so we say `Ret` has no pops. - Nop | Ret => (0, 0, 0.into(), 0.into()), - BrTrue | BrFalse => (1, 0, Type::Bool.size(), 0.into()), - Branch => (0, 0, 0.into(), 0.into()), - LdU8 => (0, 1, 0.into(), Type::U8.size()), - LdU16 => (0, 1, 0.into(), Type::U16.size()), - LdU32 => (0, 1, 0.into(), Type::U32.size()), - LdU64 => (0, 1, 0.into(), Type::U64.size()), - LdU128 => (0, 1, 0.into(), Type::U128.size()), - LdU256 => (0, 1, 0.into(), Type::U256.size()), - LdTrue | LdFalse => (0, 1, 0.into(), Type::Bool.size()), - FreezeRef => (1, 1, REFERENCE_SIZE, REFERENCE_SIZE), - ImmBorrowLoc | MutBorrowLoc => (0, 1, 0.into(), REFERENCE_SIZE), - ImmBorrowField | MutBorrowField | ImmBorrowFieldGeneric | MutBorrowFieldGeneric => { - (1, 1, REFERENCE_SIZE, REFERENCE_SIZE) - } - // Since we don't have the size of the value being cast here we take a conservative - // over-approximation: it is _always_ getting cast from the smallest integer type. - CastU8 => (1, 1, Type::U8.size(), Type::U8.size()), - CastU16 => (1, 1, Type::U8.size(), Type::U16.size()), - CastU32 => (1, 1, Type::U8.size(), Type::U32.size()), - CastU64 => (1, 1, Type::U8.size(), Type::U64.size()), - CastU128 => (1, 1, Type::U8.size(), Type::U128.size()), - CastU256 => (1, 1, Type::U8.size(), Type::U256.size()), - // NB: We don't know the size of what integers we're dealing with, so we conservatively - // over-approximate by popping the smallest integers, and push the largest. - Add | Sub | Mul | Mod | Div => (2, 1, Type::U8.size() + Type::U8.size(), Type::U256.size()), - BitOr | BitAnd | Xor => (2, 1, Type::U8.size() + Type::U8.size(), Type::U256.size()), - Shl | Shr => (2, 1, Type::U8.size() + Type::U8.size(), Type::U256.size()), - Or | And => ( - 2, - 1, - Type::Bool.size() + Type::Bool.size(), - Type::Bool.size(), - ), - Lt | Gt | Le | Ge => (2, 1, Type::U8.size() + Type::U8.size(), Type::Bool.size()), - Not => (1, 1, Type::Bool.size(), Type::Bool.size()), - Abort => (1, 0, Type::U64.size(), 0.into()), - } -} - -impl GasMeter for GasStatus { - /// Charge an instruction and fail if not enough gas units are left. - fn charge_simple_instr(&mut self, instr: SimpleInstruction) -> PartialVMResult<()> { - let (pops, pushes, pop_size, push_size) = get_simple_instruction_stack_change(instr); - self.charge(1, pushes, pops, push_size.into(), pop_size.into()) - } - - fn charge_pop(&mut self, popped_val: impl ValueView) -> PartialVMResult<()> { - self.charge(1, 0, 1, 0, self.abstract_memory_size(popped_val).into()) - } - - fn charge_native_function( - &mut self, - amount: InternalGas, - ret_vals: Option>, - ) -> PartialVMResult<()> { - // Charge for the number of pushes on to the stack that the return of this - // function is going to cause. - let pushes = ret_vals - .as_ref() - .map(|ret_vals| ret_vals.len()) - .unwrap_or(0) as u64; - // Calculate the number of bytes that are getting pushed onto the stack. - let size_increase = ret_vals - .map(|ret_vals| { - ret_vals.fold(AbstractMemorySize::zero(), |acc, elem| { - acc + self.abstract_memory_size(elem) - }) - }) - .unwrap_or_else(AbstractMemorySize::zero); - // Charge for the stack operations. We don't count this as an "instruction" - // since we already accounted for the `Call` instruction in the - // `charge_native_function_before_execution` call. - self.charge(0, pushes, 0, size_increase.into(), 0)?; - // Now charge the gas that the native function told us to charge. - self.deduct_gas(amount) - } - - fn charge_native_function_before_execution( - &mut self, - _ty_args: impl ExactSizeIterator, - args: impl ExactSizeIterator, - ) -> PartialVMResult<()> { - // Determine the number of pops that are going to be needed for this function - // call, and charge for them. - let pops = args.len() as u64; - // Calculate the size decrease of the stack from the above pops. - let stack_reduction_size = args.fold(AbstractMemorySize::new(pops), |acc, elem| { - acc + self.abstract_memory_size(elem) - }); - // Track that this is going to be popping from the operand stack. We also - // increment the instruction count as we need to account for the `Call` - // bytecode that initiated this native call. - self.charge(1, 0, pops, 0, stack_reduction_size.into()) - } - - fn charge_call( - &mut self, - _module_id: &ModuleId, - _func_name: &str, - args: impl ExactSizeIterator, - _num_locals: NumArgs, - ) -> PartialVMResult<()> { - // We will have to perform this many pops for the call. - let pops = args.len() as u64; - // Size stays the same -- we're just moving it from the operand stack to the - // locals. But the size on the operand stack is reduced by sum_{args} - // arg.size(). - let stack_reduction_size = args.fold(AbstractMemorySize::new(0), |acc, elem| { - acc + self.abstract_memory_size(elem) - }); - self.charge(1, 0, pops, 0, stack_reduction_size.into()) - } - - fn charge_call_generic( - &mut self, - _module_id: &ModuleId, - _func_name: &str, - _ty_args: impl ExactSizeIterator, - args: impl ExactSizeIterator, - _num_locals: NumArgs, - ) -> PartialVMResult<()> { - // We have to perform this many pops from the operand stack for this function - // call. - let pops = args.len() as u64; - // Calculate the size reduction on the operand stack. - let stack_reduction_size = args.fold(AbstractMemorySize::new(0), |acc, elem| { - acc + self.abstract_memory_size(elem) - }); - // Charge for the pops, no pushes, and account for the stack size decrease. Also - // track the `CallGeneric` instruction we must have encountered for - // this. - self.charge(1, 0, pops, 0, stack_reduction_size.into()) - } - - fn charge_ld_const(&mut self, size: NumBytes) -> PartialVMResult<()> { - // Charge for the load from the locals onto the stack. - self.charge(1, 1, 0, u64::from(size), 0) - } - - fn charge_ld_const_after_deserialization( - &mut self, - _val: impl ValueView, - ) -> PartialVMResult<()> { - // We already charged for this based on the bytes that we're loading so don't - // charge again. - Ok(()) - } - - fn charge_copy_loc(&mut self, val: impl ValueView) -> PartialVMResult<()> { - // Charge for the copy of the local onto the stack. - self.charge(1, 1, 0, self.abstract_memory_size(val).into(), 0) - } - - fn charge_move_loc(&mut self, val: impl ValueView) -> PartialVMResult<()> { - // Charge for the move of the local on to the stack. Note that we charge here - // since we aren't tracking the local size (at least not yet). If we - // were, this should be a net-zero operation in terms of memory usage. - self.charge(1, 1, 0, self.abstract_memory_size(val).into(), 0) - } - - fn charge_store_loc(&mut self, val: impl ValueView) -> PartialVMResult<()> { - // Charge for the storing of the value on the stack into a local. Note here that - // if we were also accounting for the size of the locals that this would - // be a net-zero operation in terms of memory. - self.charge(1, 0, 1, 0, self.abstract_memory_size(val).into()) - } - - fn charge_pack( - &mut self, - _is_generic: bool, - args: impl ExactSizeIterator, - ) -> PartialVMResult<()> { - // We perform `num_fields` number of pops. - let num_fields = args.len() as u64; - // The actual amount of memory on the stack is staying the same with the - // addition of some extra size for the struct, so the size doesn't - // really change much. - self.charge(1, 1, num_fields, STRUCT_SIZE.into(), 0) - } - - fn charge_unpack( - &mut self, - _is_generic: bool, - args: impl ExactSizeIterator, - ) -> PartialVMResult<()> { - // We perform `num_fields` number of pushes. - let num_fields = args.len() as u64; - self.charge(1, num_fields, 1, 0, STRUCT_SIZE.into()) - } - - fn charge_read_ref(&mut self, ref_val: impl ValueView) -> PartialVMResult<()> { - // We read the reference so we are decreasing the size of the stack by the size - // of the reference, and adding to it the size of the value that has - // been read from that reference. - self.charge( - 1, - 1, - 1, - self.abstract_memory_size(ref_val).into(), - REFERENCE_SIZE.into(), - ) - } - - fn charge_write_ref( - &mut self, - new_val: impl ValueView, - old_val: impl ValueView, - ) -> PartialVMResult<()> { - // TODO(tzakian): We should account for this elsewhere as the owner of data the - // the reference points to won't be on the stack. For now though, we - // treat it as adding to the stack size. - self.charge( - 1, - 1, - 2, - self.abstract_memory_size(new_val).into(), - self.abstract_memory_size(old_val).into(), - ) - } - - fn charge_eq(&mut self, lhs: impl ValueView, rhs: impl ValueView) -> PartialVMResult<()> { - let size_reduction = self.abstract_memory_size(lhs) + self.abstract_memory_size(rhs); - self.charge( - 1, - 1, - 2, - (Type::Bool.size() + size_reduction).into(), - size_reduction.into(), - ) - } - - fn charge_neq(&mut self, lhs: impl ValueView, rhs: impl ValueView) -> PartialVMResult<()> { - let size_reduction = self.abstract_memory_size(lhs) + self.abstract_memory_size(rhs); - self.charge(1, 1, 2, Type::Bool.size().into(), size_reduction.into()) - } - - fn charge_vec_pack<'a>( - &mut self, - _ty: impl TypeView + 'a, - args: impl ExactSizeIterator, - ) -> PartialVMResult<()> { - // We will perform `num_args` number of pops. - let num_args = args.len() as u64; - // The amount of data on the stack stays constant except we have some extra - // metadata for the vector to hold the length of the vector. - self.charge(1, 1, num_args, VEC_SIZE.into(), 0) - } - - fn charge_vec_len(&mut self, _ty: impl TypeView) -> PartialVMResult<()> { - self.charge(1, 1, 1, Type::U64.size().into(), REFERENCE_SIZE.into()) - } - - fn charge_vec_borrow( - &mut self, - _is_mut: bool, - _ty: impl TypeView, - _is_success: bool, - ) -> PartialVMResult<()> { - self.charge( - 1, - 1, - 2, - REFERENCE_SIZE.into(), - (REFERENCE_SIZE + Type::U64.size()).into(), - ) - } - - fn charge_vec_push_back( - &mut self, - _ty: impl TypeView, - _val: impl ValueView, - ) -> PartialVMResult<()> { - // The value was already on the stack, so we aren't increasing the number of - // bytes on the stack. - self.charge(1, 0, 2, 0, REFERENCE_SIZE.into()) - } - - fn charge_vec_pop_back( - &mut self, - _ty: impl TypeView, - _val: Option, - ) -> PartialVMResult<()> { - self.charge(1, 1, 1, 0, REFERENCE_SIZE.into()) - } - - fn charge_vec_unpack( - &mut self, - _ty: impl TypeView, - expect_num_elements: NumArgs, - _elems: impl ExactSizeIterator, - ) -> PartialVMResult<()> { - // Charge for the pushes - let pushes = u64::from(expect_num_elements); - // The stack size stays pretty much the same modulo the additional vector size - self.charge(1, pushes, 1, 0, VEC_SIZE.into()) - } - - fn charge_vec_swap(&mut self, _ty: impl TypeView) -> PartialVMResult<()> { - let size_decrease = REFERENCE_SIZE + Type::U64.size() + Type::U64.size(); - self.charge(1, 1, 1, 0, size_decrease.into()) - } - - fn charge_drop_frame( - &mut self, - _locals: impl Iterator, - ) -> PartialVMResult<()> { - Ok(()) - } - - fn remaining_gas(&self) -> InternalGas { - if !self.charge { - return InternalGas::new(u64::MAX); - } - self.gas_left - } - - fn get_profiler_mut(&mut self) -> Option<&mut GasProfiler> { - self.profiler.as_mut() - } - - fn set_profiler(&mut self, profiler: GasProfiler) { - self.profiler = Some(profiler); - } -} - -pub fn zero_cost_schedule() -> CostTable { - let mut zero_tier = BTreeMap::new(); - zero_tier.insert(0, 0); - CostTable { - instruction_tiers: zero_tier.clone(), - stack_size_tiers: zero_tier.clone(), - stack_height_tiers: zero_tier, - } -} - -pub fn unit_cost_schedule() -> CostTable { - let mut unit_tier = BTreeMap::new(); - unit_tier.insert(0, 1); - CostTable { - instruction_tiers: unit_tier.clone(), - stack_size_tiers: unit_tier.clone(), - stack_height_tiers: unit_tier, - } -} - -pub fn initial_cost_schedule_v1() -> CostTable { - let instruction_tiers: BTreeMap = vec![ - (0, 1), - (3000, 2), - (6000, 3), - (8000, 5), - (9000, 9), - (9500, 16), - (10000, 29), - (10500, 50), - ] - .into_iter() - .collect(); - - let stack_height_tiers: BTreeMap = vec![ - (0, 1), - (400, 2), - (800, 3), - (1200, 5), - (1500, 9), - (1800, 16), - (2000, 29), - (2200, 50), - ] - .into_iter() - .collect(); - - let stack_size_tiers: BTreeMap = vec![ - (0, 1), - (2000, 2), - (5000, 3), - (8000, 5), - (10000, 9), - (11000, 16), - (11500, 29), - (11500, 50), - ] - .into_iter() - .collect(); - - CostTable { - instruction_tiers, - stack_size_tiers, - stack_height_tiers, - } -} - -pub fn initial_cost_schedule_v2() -> CostTable { - let instruction_tiers: BTreeMap = vec![ - (0, 1), - (3000, 2), - (6000, 3), - (8000, 5), - (9000, 9), - (9500, 16), - (10000, 29), - (10500, 50), - (12000, 150), - (15000, 250), - ] - .into_iter() - .collect(); - - let stack_height_tiers: BTreeMap = vec![ - (0, 1), - (400, 2), - (800, 3), - (1200, 5), - (1500, 9), - (1800, 16), - (2000, 29), - (2200, 50), - (3000, 150), - (5000, 250), - ] - .into_iter() - .collect(); - - let stack_size_tiers: BTreeMap = vec![ - (0, 1), - (2000, 2), - (5000, 3), - (8000, 5), - (10000, 9), - (11000, 16), - (11500, 29), - (11500, 50), - (15000, 150), - (20000, 250), - ] - .into_iter() - .collect(); - - CostTable { - instruction_tiers, - stack_size_tiers, - stack_height_tiers, - } -} - -pub fn initial_cost_schedule_v3() -> CostTable { - let instruction_tiers: BTreeMap = vec![ - (0, 1), - (3000, 2), - (6000, 3), - (8000, 5), - (9000, 9), - (9500, 16), - (10000, 29), - (10500, 50), - (15000, 100), - ] - .into_iter() - .collect(); - - let stack_height_tiers: BTreeMap = vec![ - (0, 1), - (400, 2), - (800, 3), - (1200, 5), - (1500, 9), - (1800, 16), - (2000, 29), - (2200, 50), - (5000, 100), - ] - .into_iter() - .collect(); - - let stack_size_tiers: BTreeMap = vec![ - (0, 1), - (2000, 2), - (5000, 3), - (8000, 5), - (10000, 9), - (11000, 16), - (11500, 29), - (11500, 50), - (20000, 100), - ] - .into_iter() - .collect(); - - CostTable { - instruction_tiers, - stack_size_tiers, - stack_height_tiers, - } -} - -pub fn initial_cost_schedule_v4() -> CostTable { - let instruction_tiers: BTreeMap = vec![ - (0, 1), - (20_000, 2), - (50_000, 10), - (100_000, 50), - (200_000, 100), - ] - .into_iter() - .collect(); - - let stack_height_tiers: BTreeMap = - vec![(0, 1), (1_000, 2), (10_000, 10)].into_iter().collect(); - - let stack_size_tiers: BTreeMap = vec![ - (0, 1), - (100_000, 2), // ~100K - (500_000, 5), // ~500K - (1_000_000, 100), // ~1M - ] - .into_iter() - .collect(); - - CostTable { - instruction_tiers, - stack_size_tiers, - stack_height_tiers, - } -} - -pub fn initial_cost_schedule_v5() -> CostTable { - let instruction_tiers: BTreeMap = vec![ - (0, 1), - (20_000, 2), - (50_000, 10), - (100_000, 50), - (200_000, 100), - (10_000_000, 1000), - ] - .into_iter() - .collect(); - - let stack_height_tiers: BTreeMap = - vec![(0, 1), (1_000, 2), (10_000, 10)].into_iter().collect(); - - let stack_size_tiers: BTreeMap = vec![ - (0, 1), - (100_000, 2), // ~100K - (500_000, 5), // ~500K - (1_000_000, 100), // ~1M - (100_000_000, 1000), // ~100M - ] - .into_iter() - .collect(); - - CostTable { - instruction_tiers, - stack_size_tiers, - stack_height_tiers, - } -} - -// Convert from our representation of gas costs to the type that the MoveVM -// expects for unit tests. We don't want our gas depending on the MoveVM test -// utils and we don't want to fix our representation to whatever is there, so -// instead we perform this translation from our gas units and cost schedule to -// the one expected by the Move unit tests. -pub fn initial_cost_schedule_for_unit_tests() -> move_vm_test_utils::gas_schedule::CostTable { - let table = initial_cost_schedule_v5(); - move_vm_test_utils::gas_schedule::CostTable { - instruction_tiers: table.instruction_tiers.into_iter().collect(), - stack_height_tiers: table.stack_height_tiers.into_iter().collect(), - stack_size_tiers: table.stack_size_tiers.into_iter().collect(), - } -} diff --git a/crates/sui-types/src/governance.rs b/crates/sui-types/src/governance.rs deleted file mode 100644 index 0a3dac8e8db..00000000000 --- a/crates/sui-types/src/governance.rs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; -use serde::{Deserialize, Serialize}; - -use crate::{ - balance::Balance, - base_types::ObjectID, - committee::EpochId, - error::SuiError, - gas_coin::MIST_PER_SUI, - id::{ID, UID}, - object::{Data, Object}, - SUI_SYSTEM_ADDRESS, -}; - -/// Maximum number of active validators at any moment. -/// We do not allow the number of validators in any epoch to go above this. -pub const MAX_VALIDATOR_COUNT: u64 = 150; - -/// Lower-bound on the amount of stake required to become a validator. -/// -/// 30 million SUI -pub const MIN_VALIDATOR_JOINING_STAKE_MIST: u64 = 30_000_000 * MIST_PER_SUI; - -/// Validators with stake amount below `validator_low_stake_threshold` are -/// considered to have low stake and will be escorted out of the validator set -/// after being below this threshold for more than -/// `validator_low_stake_grace_period` number of epochs. -/// -/// 20 million SUI -pub const VALIDATOR_LOW_STAKE_THRESHOLD_MIST: u64 = 20_000_000 * MIST_PER_SUI; - -/// Validators with stake below `validator_very_low_stake_threshold` will be -/// removed immediately at epoch change, no grace period. -/// -/// 15 million SUI -pub const VALIDATOR_VERY_LOW_STAKE_THRESHOLD_MIST: u64 = 15_000_000 * MIST_PER_SUI; - -/// A validator can have stake below `validator_low_stake_threshold` -/// for this many epochs before being kicked out. -pub const VALIDATOR_LOW_STAKE_GRACE_PERIOD: u64 = 7; - -pub const STAKING_POOL_MODULE_NAME: &IdentStr = ident_str!("staking_pool"); -pub const STAKED_SUI_STRUCT_NAME: &IdentStr = ident_str!("StakedSui"); - -pub const ADD_STAKE_MUL_COIN_FUN_NAME: &IdentStr = ident_str!("request_add_stake_mul_coin"); -pub const ADD_STAKE_FUN_NAME: &IdentStr = ident_str!("request_add_stake"); -pub const WITHDRAW_STAKE_FUN_NAME: &IdentStr = ident_str!("request_withdraw_stake"); - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct StakedSui { - id: UID, - pool_id: ID, - stake_activation_epoch: u64, - principal: Balance, -} - -impl StakedSui { - pub fn type_() -> StructTag { - StructTag { - address: SUI_SYSTEM_ADDRESS, - module: STAKING_POOL_MODULE_NAME.to_owned(), - name: STAKED_SUI_STRUCT_NAME.to_owned(), - type_params: vec![], - } - } - - pub fn is_staked_sui(s: &StructTag) -> bool { - s.address == SUI_SYSTEM_ADDRESS - && s.module.as_ident_str() == STAKING_POOL_MODULE_NAME - && s.name.as_ident_str() == STAKED_SUI_STRUCT_NAME - && s.type_params.is_empty() - } - - pub fn id(&self) -> ObjectID { - self.id.id.bytes - } - - pub fn pool_id(&self) -> ObjectID { - self.pool_id.bytes - } - - pub fn activation_epoch(&self) -> EpochId { - self.stake_activation_epoch - } - - pub fn request_epoch(&self) -> EpochId { - // TODO: this might change when we implement warm up period. - self.stake_activation_epoch.saturating_sub(1) - } - - pub fn principal(&self) -> u64 { - self.principal.value() - } -} - -impl TryFrom<&Object> for StakedSui { - type Error = SuiError; - fn try_from(object: &Object) -> Result { - match &object.data { - Data::Move(o) => { - if o.type_().is_staked_sui() { - return bcs::from_bytes(o.contents()).map_err(|err| SuiError::TypeError { - error: format!("Unable to deserialize StakedSui object: {:?}", err), - }); - } - } - Data::Package(_) => {} - } - - Err(SuiError::TypeError { - error: format!("Object type is not a StakedSui: {:?}", object), - }) - } -} diff --git a/crates/sui-types/src/lib.rs b/crates/sui-types/src/lib.rs deleted file mode 100644 index 6be35afef96..00000000000 --- a/crates/sui-types/src/lib.rs +++ /dev/null @@ -1,566 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 -#![warn( - future_incompatible, - nonstandard_style, - rust_2018_idioms, - rust_2021_compatibility -)] - -use base_types::{ObjectID, SequenceNumber, SuiAddress}; -use move_binary_format::{ - binary_views::BinaryIndexedView, - file_format::{AbilitySet, SignatureToken}, -}; -use move_bytecode_utils::resolve_struct; -use move_core_types::{ - account_address::AccountAddress, - language_storage::{ModuleId, StructTag}, -}; -pub use move_core_types::{identifier::Identifier, language_storage::TypeTag}; -pub use mysten_network::multiaddr; -use object::OBJECT_START_VERSION; - -use crate::{ - base_types::{RESOLVED_ASCII_STR, RESOLVED_STD_OPTION, RESOLVED_UTF8_STR}, - id::RESOLVED_SUI_ID, -}; - -#[macro_use] -pub mod error; - -pub mod accumulator; -pub mod authenticator_state; -pub mod balance; -pub mod base_types; -pub mod bridge; -pub mod clock; -pub mod coin; -pub mod collection_types; -pub mod committee; -pub mod crypto; -pub mod deny_list; -pub mod digests; -pub mod display; -pub mod dynamic_field; -pub mod effects; -pub mod epoch_data; -pub mod event; -pub mod executable_transaction; -pub mod execution; -pub mod execution_config_utils; -pub mod execution_mode; -pub mod execution_status; -pub mod full_checkpoint_content; -pub mod gas; -pub mod gas_coin; -pub mod gas_model; -pub mod governance; -pub mod id; -pub mod in_memory_storage; -pub mod inner_temporary_store; -pub mod message_envelope; -pub mod messages_checkpoint; -pub mod messages_consensus; -pub mod messages_grpc; -pub mod messages_safe_client; -pub mod metrics; -pub mod mock_checkpoint_builder; -pub mod move_package; -pub mod multisig; -pub mod multisig_legacy; -pub mod object; -pub mod programmable_transaction_builder; -pub mod quorum_driver_types; -pub mod randomness_state; -pub mod signature; -pub mod storage; -pub mod sui_serde; -pub mod sui_system_state; -pub mod timelock; -pub mod transaction; -pub mod transfer; -pub mod type_resolver; -pub mod versioned; -pub mod zk_login_authenticator; -pub mod zk_login_util; - -#[cfg(any(test, feature = "test-utils"))] -#[path = "./unit_tests/utils.rs"] -pub mod utils; - -/// 0x1-- account address where Move stdlib modules are stored -/// Same as the ObjectID -pub const MOVE_STDLIB_ADDRESS: AccountAddress = AccountAddress::ONE; -pub const MOVE_STDLIB_PACKAGE_ID: ObjectID = ObjectID::from_address(MOVE_STDLIB_ADDRESS); - -/// 0x2-- account address where sui framework modules are stored -/// Same as the ObjectID -pub const SUI_FRAMEWORK_ADDRESS: AccountAddress = address_from_single_byte(2); -pub const SUI_FRAMEWORK_PACKAGE_ID: ObjectID = ObjectID::from_address(SUI_FRAMEWORK_ADDRESS); - -/// 0x3-- account address where sui system modules are stored -/// Same as the ObjectID -pub const SUI_SYSTEM_ADDRESS: AccountAddress = address_from_single_byte(3); -pub const SUI_SYSTEM_PACKAGE_ID: ObjectID = ObjectID::from_address(SUI_SYSTEM_ADDRESS); - -/// 0xdee9-- account address where DeepBook modules are stored -/// Same as the ObjectID -pub const DEEPBOOK_ADDRESS: AccountAddress = deepbook_addr(); -pub const DEEPBOOK_PACKAGE_ID: ObjectID = ObjectID::from_address(DEEPBOOK_ADDRESS); - -/// 0x107a-- account address where Stardust modules are stored -/// Same as the ObjectID -pub const STARDUST_ADDRESS: AccountAddress = stardust_addr(); -pub const STARDUST_PACKAGE_ID: ObjectID = ObjectID::from_address(STARDUST_ADDRESS); - -/// 0x10cf-- account address where Timelock modules are stored -/// Same as the ObjectID -pub const TIMELOCK_ADDRESS: AccountAddress = timelock_addr(); -pub const TIMELOCK_PACKAGE_ID: ObjectID = ObjectID::from_address(TIMELOCK_ADDRESS); - -/// 0xb-- account address where Bridge modules are stored -/// Same as the ObjectID -pub const BRIDGE_ADDRESS: AccountAddress = address_from_single_byte(11); -pub const BRIDGE_PACKAGE_ID: ObjectID = ObjectID::from_address(BRIDGE_ADDRESS); - -/// 0x5: hardcoded object ID for the singleton sui system state object. -pub const SUI_SYSTEM_STATE_ADDRESS: AccountAddress = address_from_single_byte(5); -pub const SUI_SYSTEM_STATE_OBJECT_ID: ObjectID = ObjectID::from_address(SUI_SYSTEM_STATE_ADDRESS); -pub const SUI_SYSTEM_STATE_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION; - -/// 0x6: hardcoded object ID for the singleton clock object. -pub const SUI_CLOCK_ADDRESS: AccountAddress = address_from_single_byte(6); -pub const SUI_CLOCK_OBJECT_ID: ObjectID = ObjectID::from_address(SUI_CLOCK_ADDRESS); -pub const SUI_CLOCK_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION; - -/// 0x7: hardcode object ID for the singleton authenticator state object. -pub const SUI_AUTHENTICATOR_STATE_ADDRESS: AccountAddress = address_from_single_byte(7); -pub const SUI_AUTHENTICATOR_STATE_OBJECT_ID: ObjectID = - ObjectID::from_address(SUI_AUTHENTICATOR_STATE_ADDRESS); -pub const SUI_AUTHENTICATOR_STATE_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION; - -/// 0x8: hardcode object ID for the singleton randomness state object. -pub const SUI_RANDOMNESS_STATE_ADDRESS: AccountAddress = address_from_single_byte(8); -pub const SUI_RANDOMNESS_STATE_OBJECT_ID: ObjectID = - ObjectID::from_address(SUI_RANDOMNESS_STATE_ADDRESS); - -/// 0x403: hardcode object ID for the singleton DenyList object. -pub const SUI_DENY_LIST_ADDRESS: AccountAddress = deny_list_addr(); -pub const SUI_DENY_LIST_OBJECT_ID: ObjectID = ObjectID::from_address(SUI_DENY_LIST_ADDRESS); - -/// 0x9: hardcode object ID for the singleton bridge object. -pub const SUI_BRIDGE_ADDRESS: AccountAddress = address_from_single_byte(9); -pub const SUI_BRIDGE_OBJECT_ID: ObjectID = ObjectID::from_address(SUI_BRIDGE_ADDRESS); - -/// Return `true` if `addr` is a special system package that can be upgraded at -/// epoch boundaries. All new system package ID's must be added here. -pub fn is_system_package(addr: impl Into) -> bool { - matches!( - addr.into(), - MOVE_STDLIB_ADDRESS - | SUI_FRAMEWORK_ADDRESS - | SUI_SYSTEM_ADDRESS - | DEEPBOOK_ADDRESS - | STARDUST_ADDRESS - | TIMELOCK_ADDRESS - | BRIDGE_ADDRESS - ) -} - -const fn address_from_single_byte(b: u8) -> AccountAddress { - let mut addr = [0u8; AccountAddress::LENGTH]; - addr[AccountAddress::LENGTH - 1] = b; - AccountAddress::new(addr) -} - -/// return 0x0...dee9 -const fn deepbook_addr() -> AccountAddress { - let mut addr = [0u8; AccountAddress::LENGTH]; - addr[AccountAddress::LENGTH - 2] = 0xde; - addr[AccountAddress::LENGTH - 1] = 0xe9; - AccountAddress::new(addr) -} - -/// return 0x0...107a -const fn stardust_addr() -> AccountAddress { - let mut addr = [0u8; AccountAddress::LENGTH]; - addr[AccountAddress::LENGTH - 2] = 0x10; - addr[AccountAddress::LENGTH - 1] = 0x7a; - AccountAddress::new(addr) -} - -/// return 0x0...10cf -const fn timelock_addr() -> AccountAddress { - let mut addr = [0u8; AccountAddress::LENGTH]; - addr[AccountAddress::LENGTH - 2] = 0x10; - addr[AccountAddress::LENGTH - 1] = 0xcf; - AccountAddress::new(addr) -} - -/// return 0x0...403 -const fn deny_list_addr() -> AccountAddress { - let mut addr = [0u8; AccountAddress::LENGTH]; - addr[AccountAddress::LENGTH - 2] = 4; - addr[AccountAddress::LENGTH - 1] = 3; - AccountAddress::new(addr) -} - -pub fn sui_framework_address_concat_string(suffix: &str) -> String { - format!("{}{suffix}", SUI_FRAMEWORK_ADDRESS.to_hex_literal()) -} - -/// Parses `s` as an address. Valid formats for addresses are: -/// -/// - A 256bit number, encoded in decimal, or hexadecimal with a leading "0x" -/// prefix. -/// - One of a number of pre-defined named addresses: std, sui, sui_system, -/// deepbook. -/// -/// Parsing succeeds if and only if `s` matches one of these formats exactly, -/// with no remaining suffix. This function is intended for use within the -/// authority codebases. -pub fn parse_sui_address(s: &str) -> anyhow::Result { - use move_command_line_common::address::ParsedAddress; - Ok(ParsedAddress::parse(s)? - .into_account_address(&resolve_address)? - .into()) -} - -/// Parse `s` as a Module ID: An address (see `parse_sui_address`), followed by -/// `::`, and then a module name (an identifier). Parsing succeeds if and only -/// if `s` matches this format exactly, with no remaining input. This function -/// is intended for use within the authority codebases. -pub fn parse_sui_module_id(s: &str) -> anyhow::Result { - use move_command_line_common::types::ParsedModuleId; - ParsedModuleId::parse(s)?.into_module_id(&resolve_address) -} - -/// Parse `s` as a fully-qualified name: A Module ID (see -/// `parse_sui_module_id`), followed by `::`, and then an identifier (for the -/// module member). Parsing succeeds if and only if `s` matches this -/// format exactly, with no remaining input. This function is intended for use -/// within the authority codebases. -pub fn parse_sui_fq_name(s: &str) -> anyhow::Result<(ModuleId, String)> { - use move_command_line_common::types::ParsedFqName; - ParsedFqName::parse(s)?.into_fq_name(&resolve_address) -} - -/// Parse `s` as a struct type: A fully-qualified name, optionally followed by a -/// list of type parameters (types -- see `parse_sui_type_tag`, separated by -/// commas, surrounded by angle brackets). Parsing succeeds if and only if `s` -/// matches this format exactly, with no remaining input. This function is -/// intended for use within the authority codebase. -pub fn parse_sui_struct_tag(s: &str) -> anyhow::Result { - use move_command_line_common::types::ParsedStructType; - ParsedStructType::parse(s)?.into_struct_tag(&resolve_address) -} - -/// Parse `s` as a type: Either a struct type (see `parse_sui_struct_tag`), a -/// primitive type, or a vector with a type parameter. Parsing succeeds if and -/// only if `s` matches this format exactly, with no remaining input. This -/// function is intended for use within the authority codebase. -pub fn parse_sui_type_tag(s: &str) -> anyhow::Result { - use move_command_line_common::types::ParsedType; - ParsedType::parse(s)?.into_type_tag(&resolve_address) -} - -/// Resolve well-known named addresses into numeric addresses. -pub fn resolve_address(addr: &str) -> Option { - match addr { - "deepbook" => Some(DEEPBOOK_ADDRESS), - "std" => Some(MOVE_STDLIB_ADDRESS), - "sui" => Some(SUI_FRAMEWORK_ADDRESS), - "sui_system" => Some(SUI_SYSTEM_ADDRESS), - "stardust" => Some(STARDUST_ADDRESS), - "timelock" => Some(TIMELOCK_ADDRESS), - "bridge" => Some(BRIDGE_ADDRESS), - _ => None, - } -} - -pub trait MoveTypeTagTrait { - fn get_type_tag() -> TypeTag; -} - -impl MoveTypeTagTrait for u8 { - fn get_type_tag() -> TypeTag { - TypeTag::U8 - } -} - -impl MoveTypeTagTrait for u64 { - fn get_type_tag() -> TypeTag { - TypeTag::U64 - } -} - -impl MoveTypeTagTrait for ObjectID { - fn get_type_tag() -> TypeTag { - TypeTag::Address - } -} - -impl MoveTypeTagTrait for SuiAddress { - fn get_type_tag() -> TypeTag { - TypeTag::Address - } -} - -impl MoveTypeTagTrait for Vec { - fn get_type_tag() -> TypeTag { - TypeTag::Vector(Box::new(T::get_type_tag())) - } -} - -pub fn is_primitive( - view: &BinaryIndexedView<'_>, - function_type_args: &[AbilitySet], - s: &SignatureToken, -) -> bool { - use SignatureToken as S; - match s { - S::Bool | S::U8 | S::U16 | S::U32 | S::U64 | S::U128 | S::U256 | S::Address => true, - S::Signer => false, - // optimistic, but no primitive has key - S::TypeParameter(idx) => !function_type_args[*idx as usize].has_key(), - - S::Struct(idx) => [RESOLVED_SUI_ID, RESOLVED_ASCII_STR, RESOLVED_UTF8_STR] - .contains(&resolve_struct(view, *idx)), - - S::StructInstantiation(s) => { - let (idx, targs) = &**s; - let resolved_struct = resolve_struct(view, *idx); - // option is a primitive - resolved_struct == RESOLVED_STD_OPTION - && targs.len() == 1 - && is_primitive(view, function_type_args, &targs[0]) - } - - S::Vector(inner) => is_primitive(view, function_type_args, inner), - S::Reference(_) | S::MutableReference(_) => false, - } -} - -pub fn is_object( - view: &BinaryIndexedView<'_>, - function_type_args: &[AbilitySet], - t: &SignatureToken, -) -> Result { - use SignatureToken as S; - match t { - S::Reference(inner) | S::MutableReference(inner) => { - is_object(view, function_type_args, inner) - } - _ => is_object_struct(view, function_type_args, t), - } -} - -pub fn is_object_vector( - view: &BinaryIndexedView<'_>, - function_type_args: &[AbilitySet], - t: &SignatureToken, -) -> Result { - use SignatureToken as S; - match t { - S::Vector(inner) => is_object_struct(view, function_type_args, inner), - _ => is_object_struct(view, function_type_args, t), - } -} - -fn is_object_struct( - view: &BinaryIndexedView<'_>, - function_type_args: &[AbilitySet], - s: &SignatureToken, -) -> Result { - use SignatureToken as S; - match s { - S::Bool - | S::U8 - | S::U16 - | S::U32 - | S::U64 - | S::U128 - | S::U256 - | S::Address - | S::Signer - | S::Vector(_) - | S::Reference(_) - | S::MutableReference(_) => Ok(false), - S::TypeParameter(idx) => Ok(function_type_args - .get(*idx as usize) - .map(|abs| abs.has_key()) - .unwrap_or(false)), - S::Struct(_) | S::StructInstantiation(_) => { - let abilities = view - .abilities(s, function_type_args) - .map_err(|vm_err| vm_err.to_string())?; - Ok(abilities.has_key()) - } - } -} - -#[cfg(test)] -mod tests { - use expect_test::expect; - - use super::*; - - #[test] - fn test_parse_sui_numeric_address() { - let result = parse_sui_address("0x2").expect("should not error"); - - let expected = - expect!["0x0000000000000000000000000000000000000000000000000000000000000002"]; - expected.assert_eq(&result.to_string()); - } - - #[test] - fn test_parse_sui_named_address() { - let result = parse_sui_address("sui").expect("should not error"); - - let expected = - expect!["0x0000000000000000000000000000000000000000000000000000000000000002"]; - expected.assert_eq(&result.to_string()); - } - - #[test] - fn test_parse_sui_module_id() { - let result = parse_sui_module_id("0x2::sui").expect("should not error"); - let expected = - expect!["0x0000000000000000000000000000000000000000000000000000000000000002::sui"]; - expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); - } - - #[test] - fn test_parse_sui_fq_name() { - let (module, name) = parse_sui_fq_name("0x2::object::new").expect("should not error"); - let expected = expect![ - "0x0000000000000000000000000000000000000000000000000000000000000002::object::new" - ]; - expected.assert_eq(&format!( - "{}::{name}", - module.to_canonical_display(/* with_prefix */ true) - )); - } - - #[test] - fn test_parse_sui_struct_tag_short_account_addr() { - let result = parse_sui_struct_tag("0x2::sui::SUI").expect("should not error"); - - let expected = expect!["0x2::sui::SUI"]; - expected.assert_eq(&result.to_string()); - - let expected = - expect!["0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"]; - expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); - } - - #[test] - fn test_parse_sui_struct_tag_long_account_addr() { - let result = parse_sui_struct_tag( - "0x00000000000000000000000000000000000000000000000000000000000000002::sui::SUI", - ) - .expect("should not error"); - - let expected = expect!["0x2::sui::SUI"]; - expected.assert_eq(&result.to_string()); - - let expected = - expect!["0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"]; - expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); - } - - #[test] - fn test_parse_sui_struct_with_type_param_short_addr() { - let result = - parse_sui_struct_tag("0x2::coin::COIN<0x2::sui::SUI>").expect("should not error"); - - let expected = expect!["0x2::coin::COIN<0x2::sui::SUI>"]; - expected.assert_eq(&result.to_string()); - - let expected = expect![ - "0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" - ]; - expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); - } - - #[test] - fn test_parse_sui_struct_with_type_param_long_addr() { - let result = parse_sui_struct_tag("0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>") - .expect("should not error"); - - let expected = expect!["0x2::coin::COIN<0x2::sui::SUI>"]; - expected.assert_eq(&result.to_string()); - - let expected = expect![ - "0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>" - ]; - expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); - } - - #[test] - fn test_complex_struct_tag_with_short_addr() { - let result = - parse_sui_struct_tag("0xe7::vec_coin::VecCoin>>") - .expect("should not error"); - - let expected = expect!["0xe7::vec_coin::VecCoin>>"]; - expected.assert_eq(&result.to_string()); - - let expected = expect![ - "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin>>" - ]; - expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); - } - - #[test] - fn test_complex_struct_tag_with_long_addr() { - let result = parse_sui_struct_tag("0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin>>") - .expect("should not error"); - - let expected = expect!["0xe7::vec_coin::VecCoin>>"]; - expected.assert_eq(&result.to_string()); - - let expected = expect![ - "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin>>" - ]; - expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); - } - - #[test] - fn test_dynamic_field_short_addr() { - let result = parse_sui_struct_tag( - "0x2::dynamic_field::Field>", - ) - .expect("should not error"); - - let expected = expect![ - "0x2::dynamic_field::Field>" - ]; - expected.assert_eq(&result.to_string()); - - let expected = expect![ - "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field>" - ]; - expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); - } - - #[test] - fn test_dynamic_field_long_addr() { - let result = parse_sui_struct_tag( - "0x2::dynamic_field::Field>", - ) - .expect("should not error"); - - let expected = expect![ - "0x2::dynamic_field::Field>" - ]; - expected.assert_eq(&result.to_string()); - - let expected = expect![ - "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field>" - ]; - expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true)); - } -} diff --git a/crates/sui-types/src/metrics.rs b/crates/sui-types/src/metrics.rs deleted file mode 100644 index 99c6d7d2c62..00000000000 --- a/crates/sui-types/src/metrics.rs +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use prometheus::{ - register_histogram_with_registry, register_int_counter_vec_with_registry, Histogram, - IntCounterVec, -}; - -pub struct LimitsMetrics { - /// Execution limits metrics - pub excessive_estimated_effects_size: IntCounterVec, - pub excessive_written_objects_size: IntCounterVec, - pub excessive_new_move_object_ids: IntCounterVec, - pub excessive_deleted_move_object_ids: IntCounterVec, - pub excessive_transferred_move_object_ids: IntCounterVec, - pub excessive_object_runtime_cached_objects: IntCounterVec, - pub excessive_object_runtime_store_entries: IntCounterVec, -} - -impl LimitsMetrics { - pub fn new(registry: &prometheus::Registry) -> LimitsMetrics { - Self { - excessive_estimated_effects_size: register_int_counter_vec_with_registry!( - "excessive_estimated_effects_size", - "Number of transactions with estimated effects size exceeding the limit", - &["metered", "limit_type"], - registry, - ) - .unwrap(), - excessive_written_objects_size: register_int_counter_vec_with_registry!( - "excessive_written_objects_size", - "Number of transactions with written objects size exceeding the limit", - &["metered", "limit_type"], - registry, - ) - .unwrap(), - excessive_new_move_object_ids: register_int_counter_vec_with_registry!( - "excessive_new_move_object_ids_size", - "Number of transactions with new move object ID count exceeding the limit", - &["metered", "limit_type"], - registry, - ) - .unwrap(), - excessive_deleted_move_object_ids: register_int_counter_vec_with_registry!( - "excessive_deleted_move_object_ids_size", - "Number of transactions with deleted move object ID count exceeding the limit", - &["metered", "limit_type"], - registry, - ) - .unwrap(), - excessive_transferred_move_object_ids: register_int_counter_vec_with_registry!( - "excessive_transferred_move_object_ids_size", - "Number of transactions with transferred move object ID count exceeding the limit", - &["metered", "limit_type"], - registry, - ) - .unwrap(), - excessive_object_runtime_cached_objects: register_int_counter_vec_with_registry!( - "excessive_object_runtime_cached_objects_size", - "Number of transactions with object runtime cached object count exceeding the limit", - &["metered", "limit_type"], - registry, - ) - .unwrap(), - excessive_object_runtime_store_entries: register_int_counter_vec_with_registry!( - "excessive_object_runtime_store_entries_size", - "Number of transactions with object runtime store entry count exceeding the limit", - &["metered", "limit_type"], - registry, - ) - .unwrap(), - } - } -} - -pub struct BytecodeVerifierMetrics { - /// Bytecode verifier metrics timeout counter - pub verifier_timeout_metrics: IntCounterVec, - /// Bytecode verifier runtime latency for each module successfully verified - pub verifier_runtime_per_module_success_latency: Histogram, - /// Bytecode verifier runtime latency for each programmable transaction - /// block successfully verified - pub verifier_runtime_per_ptb_success_latency: Histogram, - /// Bytecode verifier runtime latency for each module which timed out - pub verifier_runtime_per_module_timeout_latency: Histogram, - /// Bytecode verifier runtime latency for each programmable transaction - /// block which timed out - pub verifier_runtime_per_ptb_timeout_latency: Histogram, -} - -impl BytecodeVerifierMetrics { - pub const MOVE_VERIFIER_TAG: &'static str = "move_verifier"; - pub const SUI_VERIFIER_TAG: &'static str = "sui_verifier"; - pub const OVERALL_TAG: &'static str = "overall"; - pub const SUCCESS_TAG: &'static str = "success"; - pub const TIMEOUT_TAG: &'static str = "failed"; - const LATENCY_SEC_BUCKETS: &'static [f64] = &[ - 0.000_010, 0.000_025, 0.000_050, 0.000_100, // sub 100 micros - 0.000_250, 0.000_500, 0.001_000, 0.002_500, 0.005_000, 0.010_000, // sub 10 ms: p99 - 0.025_000, 0.050_000, 0.100_000, 0.250_000, 0.500_000, 1.000_000, // sub 1 s - 10.000_000, 20.000_000, 50.000_000, 100.0, // We should almost never get here - ]; - pub fn new(registry: &prometheus::Registry) -> Self { - Self { - verifier_timeout_metrics: register_int_counter_vec_with_registry!( - "verifier_timeout_metrics", - "Number of timeouts in bytecode verifier", - &["verifier_meter", "status"], - registry, - ) - .unwrap(), - verifier_runtime_per_module_success_latency: register_histogram_with_registry!( - "verifier_runtime_per_module_success_latency", - "Time spent running bytecode verifier to completion at `run_metered_move_bytecode_verifier_impl`", - Self::LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - verifier_runtime_per_ptb_success_latency: register_histogram_with_registry!( - "verifier_runtime_per_ptb_success_latency", - "Time spent running bytecode verifier to completion over the entire PTB at `transaction_input_checker::check_non_system_packages_to_be_published`", - Self::LATENCY_SEC_BUCKETS.to_vec(), - registry - ).unwrap(), - verifier_runtime_per_module_timeout_latency: register_histogram_with_registry!( - "verifier_runtime_per_module_timeout_latency", - "Time spent running bytecode verifier to timeout at `run_metered_move_bytecode_verifier_impl`", - Self::LATENCY_SEC_BUCKETS.to_vec(), - registry - ) - .unwrap(), - verifier_runtime_per_ptb_timeout_latency: register_histogram_with_registry!( - "verifier_runtime_per_ptb_timeout_latency", - "Time spent running bytecode verifier to timeout over the entire PTB at `transaction_input_checker::check_non_system_packages_to_be_published`", - Self::LATENCY_SEC_BUCKETS.to_vec(), - registry - ).unwrap(), - } - } -} diff --git a/crates/sui-types/src/move_package.rs b/crates/sui-types/src/move_package.rs deleted file mode 100644 index fa2414e36ef..00000000000 --- a/crates/sui-types/src/move_package.rs +++ /dev/null @@ -1,755 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::{BTreeMap, BTreeSet}; - -use derive_more::Display; -use fastcrypto::hash::HashFunction; -use move_binary_format::{ - access::ModuleAccess, binary_config::BinaryConfig, binary_views::BinaryIndexedView, - file_format::CompiledModule, normalized, -}; -use move_core_types::{ - account_address::AccountAddress, - ident_str, - identifier::{IdentStr, Identifier}, - language_storage::{ModuleId, StructTag}, -}; -use move_disassembler::disassembler::Disassembler; -use move_ir_types::location::Spanned; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use serde_with::{serde_as, Bytes}; -use sui_protocol_config::ProtocolConfig; - -use crate::{ - base_types::{ObjectID, SequenceNumber}, - crypto::DefaultHash, - error::{ExecutionError, ExecutionErrorKind, SuiError, SuiResult}, - execution_status::PackageUpgradeError, - id::{ID, UID}, - object::OBJECT_START_VERSION, - SUI_FRAMEWORK_ADDRESS, -}; - -// TODO: robust MovePackage tests -// #[cfg(test)] -// #[path = "unit_tests/move_package.rs"] -// mod base_types_tests; - -pub const PACKAGE_MODULE_NAME: &IdentStr = ident_str!("package"); -pub const UPGRADECAP_STRUCT_NAME: &IdentStr = ident_str!("UpgradeCap"); -pub const UPGRADETICKET_STRUCT_NAME: &IdentStr = ident_str!("UpgradeTicket"); -pub const UPGRADERECEIPT_STRUCT_NAME: &IdentStr = ident_str!("UpgradeReceipt"); - -#[derive(Clone, Debug)] -/// Additional information about a function -pub struct FnInfo { - /// If true, it's a function involved in testing (`[test]`, `[test_only]`, - /// `[expected_failure]`) - pub is_test: bool, -} - -#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] -/// Uniquely identifies a function in a module -pub struct FnInfoKey { - pub fn_name: String, - pub mod_addr: AccountAddress, -} - -/// A map from function info keys to function info -pub type FnInfoMap = BTreeMap; - -/// Identifies a struct and the module it was defined in -#[derive( - Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize, Hash, JsonSchema, -)] -pub struct TypeOrigin { - pub module_name: String, - pub struct_name: String, - pub package: ObjectID, -} - -/// Upgraded package info for the linkage table -#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash, JsonSchema)] -pub struct UpgradeInfo { - /// ID of the upgraded packages - pub upgraded_id: ObjectID, - /// Version of the upgraded package - pub upgraded_version: SequenceNumber, -} - -// serde_bytes::ByteBuf is an analog of Vec with built-in fast -// serialization. -#[serde_as] -#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)] -pub struct MovePackage { - id: ObjectID, - /// Most move packages are uniquely identified by their ID (i.e. there is - /// only one version per ID), but the version is still stored because - /// one package may be an upgrade of another (at a different ID), in - /// which case its version will be one greater than the version of the - /// upgraded package. - /// - /// Framework packages are an exception to this rule -- all versions of the - /// framework packages exist at the same ID, at increasing versions. - /// - /// In all cases, packages are referred to by move calls using just their - /// ID, and they are always loaded at their latest version. - version: SequenceNumber, - // TODO use session cache - #[serde_as(as = "BTreeMap<_, Bytes>")] - module_map: BTreeMap>, - - /// Maps struct/module to a package version where it was first defined, - /// stored as a vector for simple serialization and deserialization. - type_origin_table: Vec, - - // For each dependency, maps original package ID to the info about the (upgraded) dependency - // version that this package is using - linkage_table: BTreeMap, -} - -// NB: do _not_ add `Serialize` or `Deserialize` to this enum. Convert to u8 -// first or use the associated constants before storing in any serialization -// setting. -/// Rust representation of upgrade policy constants in `sui::package`. -#[repr(u8)] -#[derive(Display, Debug, Clone, Copy)] -pub enum UpgradePolicy { - #[display(fmt = "COMPATIBLE")] - Compatible = 0, - #[display(fmt = "ADDITIVE")] - Additive = 128, - #[display(fmt = "DEP_ONLY")] - DepOnly = 192, -} - -impl UpgradePolicy { - /// Convenience accessors to the upgrade policies as u8s. - pub const COMPATIBLE: u8 = Self::Compatible as u8; - pub const ADDITIVE: u8 = Self::Additive as u8; - pub const DEP_ONLY: u8 = Self::DepOnly as u8; - - pub fn is_valid_policy(policy: &u8) -> bool { - Self::try_from(*policy).is_ok() - } -} - -impl TryFrom for UpgradePolicy { - type Error = (); - fn try_from(value: u8) -> Result { - match value { - x if x == Self::Compatible as u8 => Ok(Self::Compatible), - x if x == Self::Additive as u8 => Ok(Self::Additive), - x if x == Self::DepOnly as u8 => Ok(Self::DepOnly), - _ => Err(()), - } - } -} - -/// Rust representation of `sui::package::UpgradeCap`. -#[derive(Debug, Serialize, Deserialize)] -pub struct UpgradeCap { - pub id: UID, - pub package: ID, - pub version: u64, - pub policy: u8, -} - -/// Rust representation of `sui::package::UpgradeTicket`. -#[derive(Debug, Serialize, Deserialize)] -pub struct UpgradeTicket { - pub cap: ID, - pub package: ID, - pub policy: u8, - pub digest: Vec, -} - -/// Rust representation of `sui::package::UpgradeReceipt`. -#[derive(Debug, Serialize, Deserialize)] -pub struct UpgradeReceipt { - pub cap: ID, - pub package: ID, -} - -impl MovePackage { - /// Create a package with all required data (including serialized modules, - /// type origin and linkage tables) already supplied. - pub fn new( - id: ObjectID, - version: SequenceNumber, - module_map: BTreeMap>, - max_move_package_size: u64, - type_origin_table: Vec, - linkage_table: BTreeMap, - ) -> Result { - let pkg = Self { - id, - version, - module_map, - type_origin_table, - linkage_table, - }; - let object_size = pkg.size() as u64; - if object_size > max_move_package_size { - return Err(ExecutionErrorKind::MovePackageTooBig { - object_size, - max_object_size: max_move_package_size, - } - .into()); - } - Ok(pkg) - } - - pub fn digest(&self, hash_modules: bool) -> [u8; 32] { - Self::compute_digest_for_modules_and_deps( - self.module_map.values(), - self.linkage_table - .values() - .map(|UpgradeInfo { upgraded_id, .. }| upgraded_id), - hash_modules, - ) - } - - /// It is important that this function is shared across both the calculation - /// of the digest for the package, and the calculation of the digest - /// on-chain. - pub fn compute_digest_for_modules_and_deps<'a>( - modules: impl IntoIterator>, - object_ids: impl IntoIterator, - hash_modules: bool, - ) -> [u8; 32] { - let mut module_digests: Vec<[u8; 32]>; - let mut components: Vec<&[u8]> = vec![]; - if !hash_modules { - for module in modules { - components.push(module.as_ref()) - } - } else { - module_digests = vec![]; - for module in modules { - let mut digest = DefaultHash::default(); - digest.update(module); - module_digests.push(digest.finalize().digest); - } - components.extend(module_digests.iter().map(|d| d.as_ref())) - } - - components.extend(object_ids.into_iter().map(|o| o.as_ref())); - // NB: sorting so the order of the modules and the order of the dependencies - // does not matter. - components.sort(); - - let mut digest = DefaultHash::default(); - for c in components { - digest.update(c); - } - digest.finalize().digest - } - - /// Create an initial version of the package along with this version's type - /// origin and linkage tables. - pub fn new_initial<'p>( - modules: &[CompiledModule], - max_move_package_size: u64, - transitive_dependencies: impl IntoIterator, - ) -> Result { - let module = modules - .first() - .expect("Tried to build a Move package from an empty iterator of Compiled modules"); - let runtime_id = ObjectID::from(*module.address()); - let storage_id = runtime_id; - let type_origin_table = build_initial_type_origin_table(modules); - Self::from_module_iter_with_type_origin_table( - storage_id, - runtime_id, - OBJECT_START_VERSION, - modules, - max_move_package_size, - type_origin_table, - transitive_dependencies, - ) - } - - /// Create an upgraded version of the package along with this version's type - /// origin and linkage tables. - pub fn new_upgraded<'p>( - &self, - storage_id: ObjectID, - modules: &[CompiledModule], - protocol_config: &ProtocolConfig, - transitive_dependencies: impl IntoIterator, - ) -> Result { - let module = modules - .first() - .expect("Tried to build a Move package from an empty iterator of Compiled modules"); - let runtime_id = ObjectID::from(*module.address()); - let type_origin_table = - build_upgraded_type_origin_table(self, modules, storage_id, protocol_config)?; - let mut new_version = self.version(); - new_version.increment(); - Self::from_module_iter_with_type_origin_table( - storage_id, - runtime_id, - new_version, - modules, - protocol_config.max_move_package_size(), - type_origin_table, - transitive_dependencies, - ) - } - - pub fn new_system( - version: SequenceNumber, - modules: &[CompiledModule], - dependencies: impl IntoIterator, - ) -> Self { - let module = modules - .first() - .expect("Tried to build a Move package from an empty iterator of Compiled modules"); - - let storage_id = ObjectID::from(*module.address()); - let type_origin_table = build_initial_type_origin_table(modules); - - let linkage_table = BTreeMap::from_iter(dependencies.into_iter().map(|dep| { - let info = UpgradeInfo { - upgraded_id: dep, - // The upgraded version is used by other packages that transitively depend on this - // system package, to make sure that if they choose a different version to depend on - // compared to their dependencies, they pick a greater version. - // - // However, in the case of system packages, although they can be upgraded, unlike - // other packages, only one version can be in use on the network at any given time, - // so it is not possible for a package to require a different system package version - // compared to its dependencies. - // - // This reason, coupled with the fact that system packages can only depend on each - // other, mean that their own linkage tables always report a version of zero. - upgraded_version: SequenceNumber::new(), - }; - (dep, info) - })); - - let module_map = BTreeMap::from_iter(modules.iter().map(|module| { - let name = module.name().to_string(); - let mut bytes = Vec::new(); - module.serialize(&mut bytes).unwrap(); - (name, bytes) - })); - - Self::new( - storage_id, - version, - module_map, - u64::MAX, // System packages are not subject to the size limit - type_origin_table, - linkage_table, - ) - .expect("System packages are not subject to a size limit") - } - - fn from_module_iter_with_type_origin_table<'p>( - storage_id: ObjectID, - self_id: ObjectID, - version: SequenceNumber, - modules: &[CompiledModule], - max_move_package_size: u64, - type_origin_table: Vec, - transitive_dependencies: impl IntoIterator, - ) -> Result { - let mut module_map = BTreeMap::new(); - let mut immediate_dependencies = BTreeSet::new(); - - for module in modules { - let name = module.name().to_string(); - - immediate_dependencies.extend( - module - .immediate_dependencies() - .into_iter() - .map(|dep| ObjectID::from(*dep.address())), - ); - - let mut bytes = Vec::new(); - module.serialize(&mut bytes).unwrap(); - module_map.insert(name, bytes); - } - - immediate_dependencies.remove(&self_id); - let linkage_table = build_linkage_table(immediate_dependencies, transitive_dependencies)?; - Self::new( - storage_id, - version, - module_map, - max_move_package_size, - type_origin_table, - linkage_table, - ) - } - - // Retrieve the module with `ModuleId` in the given package. - // The module must be the `storage_id` or the call will return `None`. - // Check if the address of the module is the same of the package - // and return `None` if that is not the case. - // All modules in a package share the address with the package. - pub fn get_module(&self, storage_id: &ModuleId) -> Option<&Vec> { - if self.id != ObjectID::from(*storage_id.address()) { - None - } else { - self.module_map.get(&storage_id.name().to_string()) - } - } - - /// Return the size of the package in bytes - pub fn size(&self) -> usize { - let module_map_size = self - .module_map - .iter() - .map(|(name, module)| name.len() + module.len()) - .sum::(); - let type_origin_table_size = self - .type_origin_table - .iter() - .map( - |TypeOrigin { - module_name, - struct_name, - .. - }| module_name.len() + struct_name.len() + ObjectID::LENGTH, - ) - .sum::(); - - let linkage_table_size = self.linkage_table.len() - * (ObjectID::LENGTH - + ( - ObjectID::LENGTH + 8 - // SequenceNumber - )); - - 8 /* SequenceNumber */ + module_map_size + type_origin_table_size + linkage_table_size - } - - pub fn id(&self) -> ObjectID { - self.id - } - - pub fn version(&self) -> SequenceNumber { - self.version - } - - pub fn decrement_version(&mut self) { - self.version.decrement(); - } - - pub fn increment_version(&mut self) { - self.version.increment(); - } - - /// Approximate size of the package in bytes. This is used for gas metering. - pub fn object_size_for_gas_metering(&self) -> usize { - self.size() - } - - pub fn serialized_module_map(&self) -> &BTreeMap> { - &self.module_map - } - - pub fn type_origin_table(&self) -> &Vec { - &self.type_origin_table - } - - pub fn type_origin_map(&self) -> BTreeMap<(String, String), ObjectID> { - self.type_origin_table - .iter() - .map( - |TypeOrigin { - module_name, - struct_name, - package, - }| { ((module_name.clone(), struct_name.clone()), *package) }, - ) - .collect() - } - - pub fn linkage_table(&self) -> &BTreeMap { - &self.linkage_table - } - - /// The ObjectID that this package's modules believe they are from, at - /// runtime (can differ from `MovePackage::id()` in the case of package - /// upgrades). - pub fn original_package_id(&self) -> ObjectID { - let bytes = self.module_map.values().next().expect("Empty module map"); - let module = CompiledModule::deserialize_with_defaults(bytes) - .expect("A Move package contains a module that cannot be deserialized"); - (*module.address()).into() - } - - pub fn deserialize_module( - &self, - module: &Identifier, - binary_config: &BinaryConfig, - ) -> SuiResult { - // TODO use the session's cache - let bytes = self - .serialized_module_map() - .get(module.as_str()) - .ok_or_else(|| SuiError::ModuleNotFound { - module_name: module.to_string(), - })?; - CompiledModule::deserialize_with_config(bytes, binary_config).map_err(|error| { - SuiError::ModuleDeserializationFailure { - error: error.to_string(), - } - }) - } - - pub fn disassemble(&self) -> SuiResult> { - disassemble_modules(self.module_map.values()) - } - - pub fn normalize( - &self, - binary_config: &BinaryConfig, - ) -> SuiResult> { - normalize_modules(self.module_map.values(), binary_config) - } -} - -impl UpgradeCap { - pub fn type_() -> StructTag { - StructTag { - address: SUI_FRAMEWORK_ADDRESS, - module: PACKAGE_MODULE_NAME.to_owned(), - name: UPGRADECAP_STRUCT_NAME.to_owned(), - type_params: vec![], - } - } - - /// Create an `UpgradeCap` for the newly published package at `package_id`, - /// and associate it with the fresh `uid`. - pub fn new(uid: ObjectID, package_id: ObjectID) -> Self { - UpgradeCap { - id: UID::new(uid), - package: ID::new(package_id), - version: 1, - policy: UpgradePolicy::COMPATIBLE, - } - } -} - -impl UpgradeTicket { - pub fn type_() -> StructTag { - StructTag { - address: SUI_FRAMEWORK_ADDRESS, - module: PACKAGE_MODULE_NAME.to_owned(), - name: UPGRADETICKET_STRUCT_NAME.to_owned(), - type_params: vec![], - } - } -} - -impl UpgradeReceipt { - pub fn type_() -> StructTag { - StructTag { - address: SUI_FRAMEWORK_ADDRESS, - module: PACKAGE_MODULE_NAME.to_owned(), - name: UPGRADERECEIPT_STRUCT_NAME.to_owned(), - type_params: vec![], - } - } - - /// Create an `UpgradeReceipt` for the upgraded package at `package_id` - /// using the `UpgradeTicket` and newly published package id. - pub fn new(upgrade_ticket: UpgradeTicket, upgraded_package_id: ObjectID) -> Self { - UpgradeReceipt { - cap: upgrade_ticket.cap, - package: ID::new(upgraded_package_id), - } - } -} - -/// Checks if a function is annotated with one of the test-related annotations -pub fn is_test_fun(name: &IdentStr, module: &CompiledModule, fn_info_map: &FnInfoMap) -> bool { - let fn_name = name.to_string(); - let mod_handle = module.self_handle(); - let mod_addr = *module.address_identifier_at(mod_handle.address); - let fn_info_key = FnInfoKey { fn_name, mod_addr }; - match fn_info_map.get(&fn_info_key) { - Some(fn_info) => fn_info.is_test, - None => false, - } -} - -pub fn disassemble_modules<'a, I>(modules: I) -> SuiResult> -where - I: Iterator>, -{ - let mut disassembled = BTreeMap::new(); - for bytecode in modules { - // this function is only from JSON RPC - it is OK to deserialize with max Move - // binary version - let module = CompiledModule::deserialize_with_defaults(bytecode).map_err(|error| { - SuiError::ModuleDeserializationFailure { - error: error.to_string(), - } - })?; - let view = BinaryIndexedView::Module(&module); - let d = Disassembler::from_view(view, Spanned::unsafe_no_loc(()).loc).map_err(|e| { - SuiError::ObjectSerializationError { - error: e.to_string(), - } - })?; - let bytecode_str = d - .disassemble() - .map_err(|e| SuiError::ObjectSerializationError { - error: e.to_string(), - })?; - disassembled.insert(module.name().to_string(), Value::String(bytecode_str)); - } - Ok(disassembled) -} - -pub fn normalize_modules<'a, I>( - modules: I, - binary_config: &BinaryConfig, -) -> SuiResult> -where - I: Iterator>, -{ - let mut normalized_modules = BTreeMap::new(); - for bytecode in modules { - let module = - CompiledModule::deserialize_with_config(bytecode, binary_config).map_err(|error| { - SuiError::ModuleDeserializationFailure { - error: error.to_string(), - } - })?; - let normalized_module = normalized::Module::new(&module); - normalized_modules.insert(normalized_module.name.to_string(), normalized_module); - } - Ok(normalized_modules) -} - -pub fn normalize_deserialized_modules<'a, I>(modules: I) -> BTreeMap -where - I: Iterator, -{ - let mut normalized_modules = BTreeMap::new(); - for module in modules { - let normalized_module = normalized::Module::new(module); - normalized_modules.insert(normalized_module.name.to_string(), normalized_module); - } - normalized_modules -} - -fn build_linkage_table<'p>( - mut immediate_dependencies: BTreeSet, - transitive_dependencies: impl IntoIterator, -) -> Result, ExecutionError> { - let mut linkage_table = BTreeMap::new(); - let mut dep_linkage_tables = vec![]; - - for transitive_dep in transitive_dependencies.into_iter() { - // original_package_id will deserialize a module but only for the purpose of - // obtaining "original ID" of the package containing it so using max - // Move binary version during deserialization is OK - let original_id = transitive_dep.original_package_id(); - - if immediate_dependencies.remove(&original_id) { - // Found an immediate dependency, mark it as seen, and stash a reference to its - // linkage table to check later. - dep_linkage_tables.push(&transitive_dep.linkage_table); - } - - linkage_table.insert( - original_id, - UpgradeInfo { - upgraded_id: transitive_dep.id, - upgraded_version: transitive_dep.version, - }, - ); - } - // (1) Every dependency is represented in the transitive dependencies - if !immediate_dependencies.is_empty() { - return Err(ExecutionErrorKind::PublishUpgradeMissingDependency.into()); - } - - // (2) Every dependency's linkage table is superseded by this linkage table - for dep_linkage_table in dep_linkage_tables { - for (original_id, dep_info) in dep_linkage_table { - let Some(our_info) = linkage_table.get(original_id) else { - return Err(ExecutionErrorKind::PublishUpgradeMissingDependency.into()); - }; - - if our_info.upgraded_version < dep_info.upgraded_version { - return Err(ExecutionErrorKind::PublishUpgradeDependencyDowngrade.into()); - } - } - } - - Ok(linkage_table) -} - -fn build_initial_type_origin_table(modules: &[CompiledModule]) -> Vec { - modules - .iter() - .flat_map(|m| { - m.struct_defs().iter().map(|struct_def| { - let struct_handle = m.struct_handle_at(struct_def.struct_handle); - let module_name = m.name().to_string(); - let struct_name = m.identifier_at(struct_handle.name).to_string(); - let package: ObjectID = (*m.self_id().address()).into(); - TypeOrigin { - module_name, - struct_name, - package, - } - }) - }) - .collect() -} - -fn build_upgraded_type_origin_table( - predecessor: &MovePackage, - modules: &[CompiledModule], - storage_id: ObjectID, - protocol_config: &ProtocolConfig, -) -> Result, ExecutionError> { - let mut new_table = vec![]; - let mut existing_table = predecessor.type_origin_map(); - for m in modules { - for struct_def in m.struct_defs() { - let struct_handle = m.struct_handle_at(struct_def.struct_handle); - let module_name = m.name().to_string(); - let struct_name = m.identifier_at(struct_handle.name).to_string(); - let mod_key = (module_name.clone(), struct_name.clone()); - // if id exists in the predecessor's table, use it, otherwise use the id of the - // upgraded module - let package = existing_table.remove(&mod_key).unwrap_or(storage_id); - new_table.push(TypeOrigin { - module_name, - struct_name, - package, - }); - } - } - - if !existing_table.is_empty() { - if protocol_config.missing_type_is_compatibility_error() { - Err(ExecutionError::from_kind( - ExecutionErrorKind::PackageUpgradeError { - upgrade_error: PackageUpgradeError::IncompatibleUpgrade, - }, - )) - } else { - Err(ExecutionError::invariant_violation( - "Package upgrade missing type from previous version.", - )) - } - } else { - Ok(new_table) - } -} diff --git a/crates/sui-types/src/object.rs b/crates/sui-types/src/object.rs deleted file mode 100644 index 6cac15adf57..00000000000 --- a/crates/sui-types/src/object.rs +++ /dev/null @@ -1,1291 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::BTreeMap, - convert::TryFrom, - fmt::{Debug, Display, Formatter}, - mem::size_of, - sync::Arc, -}; - -use move_binary_format::CompiledModule; -use move_bytecode_utils::{layout::TypeLayoutBuilder, module_cache::GetModule}; -use move_core_types::{ - annotated_value::{MoveStruct, MoveStructLayout, MoveTypeLayout}, - language_storage::{StructTag, TypeTag}, -}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_with::{serde_as, Bytes}; -use sui_protocol_config::ProtocolConfig; - -use self::{balance_traversal::BalanceTraversal, bounded_visitor::BoundedVisitor}; -use crate::{ - base_types::{ - MoveObjectType, ObjectDigest, ObjectID, ObjectIDParseError, ObjectRef, SequenceNumber, - SuiAddress, TransactionDigest, - }, - coin::{Coin, CoinMetadata, TreasuryCap}, - crypto::{default_hash, deterministic_random_account_key}, - error::{ - ExecutionError, ExecutionErrorKind, SuiError, SuiResult, UserInputError, UserInputResult, - }, - gas_coin::{GasCoin, GAS}, - is_system_package, - move_package::MovePackage, - type_resolver::LayoutResolver, -}; - -mod balance_traversal; -pub mod bounded_visitor; - -pub const GAS_VALUE_FOR_TESTING: u64 = 300_000_000_000_000; -pub const OBJECT_START_VERSION: SequenceNumber = SequenceNumber::from_u64(1); - -#[serde_as] -#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)] -pub struct MoveObject { - /// The type of this object. Immutable - type_: MoveObjectType, - /// DEPRECATED this field is no longer used to determine whether a tx can - /// transfer this object. Instead, it is always calculated from the - /// objects type when loaded in execution - has_public_transfer: bool, - /// Number that increases each time a tx takes this object as a mutable - /// input This is a lamport timestamp, not a sequentially increasing - /// version - version: SequenceNumber, - /// BCS bytes of a Move struct value - #[serde_as(as = "Bytes")] - contents: Vec, -} - -/// Index marking the end of the object's ID + the beginning of its version -pub const ID_END_INDEX: usize = ObjectID::LENGTH; - -impl MoveObject { - /// Creates a new Move object of type `type_` with BCS encoded bytes in - /// `contents` `has_public_transfer` is determined by the abilities of - /// the `type_`, but resolving the abilities requires the compiled - /// modules of the `type_: StructTag`. In other words, - /// `has_public_transfer` will be the same for all objects of the same - /// `type_`. - /// - /// # Safety - /// - /// This function should ONLY be called if has_public_transfer has been - /// determined by the type_. Yes, this is a bit of an abuse of the - /// `unsafe` marker, but bad things will happen if this is inconsistent - pub unsafe fn new_from_execution( - type_: MoveObjectType, - has_public_transfer: bool, - version: SequenceNumber, - contents: Vec, - protocol_config: &ProtocolConfig, - ) -> Result { - Self::new_from_execution_with_limit( - type_, - has_public_transfer, - version, - contents, - protocol_config.max_move_object_size(), - ) - } - - /// # Safety - /// This function should ONLY be called if has_public_transfer has been - /// determined by the type_ - pub unsafe fn new_from_execution_with_limit( - type_: MoveObjectType, - has_public_transfer: bool, - version: SequenceNumber, - contents: Vec, - max_move_object_size: u64, - ) -> Result { - // coins should always have public transfer, as they always should have store. - // Thus, type_ == GasCoin::type_() ==> has_public_transfer - // TODO: think this can be generalized to is_coin - debug_assert!(!type_.is_gas_coin() || has_public_transfer); - if contents.len() as u64 > max_move_object_size { - return Err(ExecutionError::from_kind( - ExecutionErrorKind::MoveObjectTooBig { - object_size: contents.len() as u64, - max_object_size: max_move_object_size, - }, - )); - } - Ok(Self { - type_, - has_public_transfer, - version, - contents, - }) - } - - pub fn new_gas_coin(version: SequenceNumber, id: ObjectID, value: u64) -> Self { - // unwrap safe because coins are always smaller than the max object size - unsafe { - Self::new_from_execution_with_limit( - GasCoin::type_().into(), - true, - version, - GasCoin::new(id, value).to_bcs_bytes(), - 256, - ) - .unwrap() - } - } - - pub fn new_coin( - coin_type: MoveObjectType, - version: SequenceNumber, - id: ObjectID, - value: u64, - ) -> Self { - // unwrap safe because coins are always smaller than the max object size - unsafe { - Self::new_from_execution_with_limit( - coin_type, - true, - version, - GasCoin::new(id, value).to_bcs_bytes(), - 256, - ) - .unwrap() - } - } - - pub fn type_(&self) -> &MoveObjectType { - &self.type_ - } - - pub fn is_type(&self, s: &StructTag) -> bool { - self.type_.is(s) - } - - pub fn has_public_transfer(&self) -> bool { - self.has_public_transfer - } - - pub fn id(&self) -> ObjectID { - Self::id_opt(&self.contents).unwrap() - } - - pub fn id_opt(contents: &[u8]) -> Result { - if ID_END_INDEX > contents.len() { - return Err(ObjectIDParseError::TryFromSliceError); - } - ObjectID::try_from(&contents[0..ID_END_INDEX]) - } - - /// Return the `value: u64` field of a `Coin` type. - /// Useful for reading the coin without deserializing the object into a Move - /// value It is the caller's responsibility to check that `self` is a - /// coin--this function may panic or do something unexpected otherwise. - pub fn get_coin_value_unsafe(&self) -> u64 { - debug_assert!(self.type_.is_coin()); - // 32 bytes for object ID, 8 for balance - debug_assert!(self.contents.len() == 40); - - // unwrap safe because we checked that it is a coin - u64::from_le_bytes(<[u8; 8]>::try_from(&self.contents[ID_END_INDEX..]).unwrap()) - } - - /// Update the `value: u64` field of a `Coin` type. - /// Useful for updating the coin without deserializing the object into a - /// Move value It is the caller's responsibility to check that `self` is - /// a coin--this function may panic or do something unexpected - /// otherwise. - pub fn set_coin_value_unsafe(&mut self, value: u64) { - debug_assert!(self.type_.is_coin()); - // 32 bytes for object ID, 8 for balance - debug_assert!(self.contents.len() == 40); - - self.contents.splice(ID_END_INDEX.., value.to_le_bytes()); - } - - /// Update the `timestamp_ms: u64` field of the `Clock` type. - /// - /// Panics if the object isn't a `Clock`. - pub fn set_clock_timestamp_ms_unsafe(&mut self, timestamp_ms: u64) { - assert!(self.is_clock()); - // 32 bytes for object ID, 8 for timestamp - assert!(self.contents.len() == 40); - - self.contents - .splice(ID_END_INDEX.., timestamp_ms.to_le_bytes()); - } - - pub fn is_coin(&self) -> bool { - self.type_.is_coin() - } - - pub fn is_staked_sui(&self) -> bool { - self.type_.is_staked_sui() - } - - pub fn is_clock(&self) -> bool { - self.type_.is(&crate::clock::Clock::type_()) - } - - pub fn version(&self) -> SequenceNumber { - self.version - } - - /// Contents of the object that are specific to its type--i.e., not its ID - /// and version, which all objects have For example if the object was - /// declared as `struct S has key { id: ID, f1: u64, f2: bool }, - /// this returns the slice containing `f1` and `f2`. - #[cfg(test)] - pub fn type_specific_contents(&self) -> &[u8] { - &self.contents[ID_END_INDEX..] - } - - /// Update the contents of this object but does not increment its version - pub fn update_contents( - &mut self, - new_contents: Vec, - protocol_config: &ProtocolConfig, - ) -> Result<(), ExecutionError> { - self.update_contents_with_limit(new_contents, protocol_config.max_move_object_size()) - } - - fn update_contents_with_limit( - &mut self, - new_contents: Vec, - max_move_object_size: u64, - ) -> Result<(), ExecutionError> { - if new_contents.len() as u64 > max_move_object_size { - return Err(ExecutionError::from_kind( - ExecutionErrorKind::MoveObjectTooBig { - object_size: new_contents.len() as u64, - max_object_size: max_move_object_size, - }, - )); - } - - #[cfg(debug_assertions)] - let old_id = self.id(); - self.contents = new_contents; - - // Update should not modify ID - #[cfg(debug_assertions)] - debug_assert_eq!(self.id(), old_id); - - Ok(()) - } - - /// Sets the version of this object to a new value which is assumed to be - /// higher (and checked to be higher in debug). - pub fn increment_version_to(&mut self, next: SequenceNumber) { - self.version.increment_to(next); - } - - pub fn decrement_version_to(&mut self, prev: SequenceNumber) { - self.version.decrement_to(prev); - } - - pub fn contents(&self) -> &[u8] { - &self.contents - } - - pub fn into_contents(self) -> Vec { - self.contents - } - - pub fn into_type(self) -> MoveObjectType { - self.type_ - } - - pub fn into_inner(self) -> (MoveObjectType, Vec) { - (self.type_, self.contents) - } - - /// Get a `MoveStructLayout` for `self`. - /// The `resolver` value must contain the module that declares `self.type_` - /// and the (transitive) dependencies of `self.type_` in order for this - /// to succeed. Failure will result in an `ObjectSerializationError` - pub fn get_layout(&self, resolver: &impl GetModule) -> Result { - Self::get_layout_from_struct_tag(self.type_().clone().into(), resolver) - } - - pub fn get_layout_from_struct_tag( - struct_tag: StructTag, - resolver: &impl GetModule, - ) -> Result { - let type_ = TypeTag::Struct(Box::new(struct_tag)); - let layout = TypeLayoutBuilder::build_with_types(&type_, resolver).map_err(|e| { - SuiError::ObjectSerializationError { - error: e.to_string(), - } - })?; - match layout { - MoveTypeLayout::Struct(l) => Ok(l), - _ => unreachable!( - "We called build_with_types on Struct type, should get a struct layout" - ), - } - } - - /// Convert `self` to the JSON representation dictated by `layout`. - pub fn to_move_struct(&self, layout: &MoveStructLayout) -> Result { - BoundedVisitor::deserialize_struct(&self.contents, layout).map_err(|e| { - SuiError::ObjectSerializationError { - error: e.to_string(), - } - }) - } - - /// Convert `self` to the JSON representation dictated by `layout`. - pub fn to_move_struct_with_resolver( - &self, - resolver: &impl GetModule, - ) -> Result { - self.to_move_struct(&self.get_layout(resolver)?) - } - - pub fn to_rust<'de, T: Deserialize<'de>>(&'de self) -> Option { - bcs::from_bytes(self.contents()).ok() - } - - /// Approximate size of the object in bytes. This is used for gas metering. - /// For the type tag field, we serialize it on the spot to get the accurate - /// size. This should not be very expensive since the type tag is - /// usually simple, and we only do this once per object being mutated. - pub fn object_size_for_gas_metering(&self) -> usize { - let serialized_type_tag_size = - bcs::serialized_size(&self.type_).expect("Serializing type tag should not fail"); - // + 1 for 'has_public_transfer' - // + 8 for `version` - self.contents.len() + serialized_type_tag_size + 1 + 8 - } - - /// Get the total amount of SUI embedded in `self`. Intended for testing - /// purposes - pub fn get_total_sui(&self, layout_resolver: &mut dyn LayoutResolver) -> Result { - let balances = self.get_coin_balances(layout_resolver)?; - Ok(balances.get(&GAS::type_tag()).copied().unwrap_or(0)) - } -} - -// Helpers for extracting Coin balances for all T -impl MoveObject { - /// Get the total balances for all `Coin` embedded in `self`. - pub fn get_coin_balances( - &self, - layout_resolver: &mut dyn LayoutResolver, - ) -> Result, SuiError> { - // Fast path without deserialization. - if let Some(type_tag) = self.type_.coin_type_maybe() { - let balance = self.get_coin_value_unsafe(); - Ok(if balance > 0 { - BTreeMap::from([(type_tag.clone(), balance)]) - } else { - BTreeMap::default() - }) - } else { - let layout = layout_resolver.get_annotated_layout(&self.type_().clone().into())?; - - let mut traversal = BalanceTraversal::default(); - MoveStruct::visit_deserialize(&self.contents, &layout, &mut traversal).map_err( - |e| SuiError::ObjectSerializationError { - error: e.to_string(), - }, - )?; - - Ok(traversal.finish()) - } - } -} - -#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)] -#[allow(clippy::large_enum_variant)] -pub enum Data { - /// An object whose governing logic lives in a published Move module - Move(MoveObject), - /// Map from each module name to raw serialized Move module bytes - Package(MovePackage), - // ... Sui "native" types go here -} - -impl Data { - pub fn try_as_move(&self) -> Option<&MoveObject> { - use Data::*; - match self { - Move(m) => Some(m), - Package(_) => None, - } - } - - pub fn try_as_move_mut(&mut self) -> Option<&mut MoveObject> { - use Data::*; - match self { - Move(m) => Some(m), - Package(_) => None, - } - } - - pub fn try_as_package(&self) -> Option<&MovePackage> { - use Data::*; - match self { - Move(_) => None, - Package(p) => Some(p), - } - } - - pub fn try_as_package_mut(&mut self) -> Option<&mut MovePackage> { - use Data::*; - match self { - Move(_) => None, - Package(p) => Some(p), - } - } - - pub fn try_into_package(self) -> Option { - use Data::*; - match self { - Move(_) => None, - Package(p) => Some(p), - } - } - - pub fn type_(&self) -> Option<&MoveObjectType> { - use Data::*; - match self { - Move(m) => Some(m.type_()), - Package(_) => None, - } - } - - pub fn struct_tag(&self) -> Option { - use Data::*; - match self { - Move(m) => Some(m.type_().clone().into()), - Package(_) => None, - } - } - - pub fn id(&self) -> ObjectID { - match self { - Self::Move(v) => v.id(), - Self::Package(m) => m.id(), - } - } -} - -#[derive( - Eq, PartialEq, Debug, Clone, Copy, Deserialize, Serialize, Hash, JsonSchema, Ord, PartialOrd, -)] -#[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))] -pub enum Owner { - /// Object is exclusively owned by a single address, and is mutable. - AddressOwner(SuiAddress), - /// Object is exclusively owned by a single object, and is mutable. - /// The object ID is converted to SuiAddress as SuiAddress is universal. - ObjectOwner(SuiAddress), - /// Object is shared, can be used by any address, and is mutable. - Shared { - /// The version at which the object became shared - initial_shared_version: SequenceNumber, - }, - /// Object is immutable, and hence ownership doesn't matter. - Immutable, -} - -impl Owner { - // NOTE: only return address of AddressOwner, otherwise return error, - // ObjectOwner's address is converted from object id, thus we will skip it. - pub fn get_address_owner_address(&self) -> SuiResult { - match self { - Self::AddressOwner(address) => Ok(*address), - Self::Shared { .. } | Self::Immutable | Self::ObjectOwner(_) => { - Err(SuiError::UnexpectedOwnerType) - } - } - } - - // NOTE: this function will return address of both AddressOwner and ObjectOwner, - // address of ObjectOwner is converted from object id, even though the type is - // SuiAddress. - pub fn get_owner_address(&self) -> SuiResult { - match self { - Self::AddressOwner(address) | Self::ObjectOwner(address) => Ok(*address), - Self::Shared { .. } | Self::Immutable => Err(SuiError::UnexpectedOwnerType), - } - } - - pub fn is_immutable(&self) -> bool { - matches!(self, Owner::Immutable) - } - - pub fn is_address_owned(&self) -> bool { - matches!(self, Owner::AddressOwner(_)) - } - - pub fn is_child_object(&self) -> bool { - matches!(self, Owner::ObjectOwner(_)) - } - - pub fn is_shared(&self) -> bool { - matches!(self, Owner::Shared { .. }) - } -} - -impl PartialEq for Owner { - fn eq(&self, other: &SuiAddress) -> bool { - match self { - Self::AddressOwner(address) => address == other, - Self::ObjectOwner(_) | Self::Shared { .. } | Self::Immutable => false, - } - } -} - -impl PartialEq for Owner { - fn eq(&self, other: &ObjectID) -> bool { - let other_id: SuiAddress = (*other).into(); - match self { - Self::ObjectOwner(id) => id == &other_id, - Self::AddressOwner(_) | Self::Shared { .. } | Self::Immutable => false, - } - } -} - -impl Display for Owner { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Self::AddressOwner(address) => { - write!(f, "Account Address ( {} )", address) - } - Self::ObjectOwner(address) => { - write!(f, "Object ID: ( {} )", address) - } - Self::Immutable => { - write!(f, "Immutable") - } - Self::Shared { .. } => { - write!(f, "Shared") - } - } - } -} - -#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)] -#[serde(rename = "Object")] -pub struct ObjectInner { - /// The meat of the object - pub data: Data, - /// The owner that unlocks this object - pub owner: Owner, - /// The digest of the transaction that created or last mutated this object - pub previous_transaction: TransactionDigest, - /// The amount of SUI we would rebate if this object gets deleted. - /// This number is re-calculated each time the object is mutated based on - /// the present storage gas price. - pub storage_rebate: u64, -} - -#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)] -pub struct Object(Arc); - -impl From for Object { - fn from(inner: ObjectInner) -> Self { - Self(Arc::new(inner)) - } -} - -impl Object { - pub fn into_inner(self) -> ObjectInner { - match Arc::try_unwrap(self.0) { - Ok(inner) => inner, - Err(inner_arc) => (*inner_arc).clone(), - } - } - - pub fn as_inner(&self) -> &ObjectInner { - &self.0 - } - - pub fn new_from_genesis( - data: Data, - owner: Owner, - previous_transaction: TransactionDigest, - ) -> Self { - ObjectInner { - data, - owner, - previous_transaction, - storage_rebate: 0, - } - .into() - } - - /// Create a new Move object - pub fn new_move(o: MoveObject, owner: Owner, previous_transaction: TransactionDigest) -> Self { - ObjectInner { - data: Data::Move(o), - owner, - previous_transaction, - storage_rebate: 0, - } - .into() - } - - pub fn new_package_from_data(data: Data, previous_transaction: TransactionDigest) -> Self { - ObjectInner { - data, - owner: Owner::Immutable, - previous_transaction, - storage_rebate: 0, - } - .into() - } - - // Note: this will panic if `modules` is empty - pub fn new_from_package(package: MovePackage, previous_transaction: TransactionDigest) -> Self { - Self::new_package_from_data(Data::Package(package), previous_transaction) - } - - pub fn new_package<'p>( - modules: &[CompiledModule], - previous_transaction: TransactionDigest, - max_move_package_size: u64, - dependencies: impl IntoIterator, - ) -> Result { - Ok(Self::new_package_from_data( - Data::Package(MovePackage::new_initial( - modules, - max_move_package_size, - dependencies, - )?), - previous_transaction, - )) - } - - pub fn new_upgraded_package<'p>( - previous_package: &MovePackage, - new_package_id: ObjectID, - modules: &[CompiledModule], - previous_transaction: TransactionDigest, - protocol_config: &ProtocolConfig, - dependencies: impl IntoIterator, - ) -> Result { - Ok(Self::new_package_from_data( - Data::Package(previous_package.new_upgraded( - new_package_id, - modules, - protocol_config, - dependencies, - )?), - previous_transaction, - )) - } - - pub fn new_package_for_testing( - modules: &[CompiledModule], - previous_transaction: TransactionDigest, - dependencies: impl IntoIterator, - ) -> Result { - let dependencies: Vec<_> = dependencies.into_iter().collect(); - Self::new_package( - modules, - previous_transaction, - ProtocolConfig::get_for_max_version_UNSAFE().max_move_package_size(), - &dependencies, - ) - } - - /// Create a system package which is not subject to size limits. Panics if - /// the object ID is not a known system package. - pub fn new_system_package( - modules: &[CompiledModule], - version: SequenceNumber, - dependencies: Vec, - previous_transaction: TransactionDigest, - ) -> Self { - let ret = Self::new_package_from_data( - Data::Package(MovePackage::new_system(version, modules, dependencies)), - previous_transaction, - ); - - #[cfg(not(msim))] - assert!(ret.is_system_package()); - - ret - } -} - -impl std::ops::Deref for Object { - type Target = ObjectInner; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl std::ops::DerefMut for Object { - fn deref_mut(&mut self) -> &mut Self::Target { - Arc::make_mut(&mut self.0) - } -} - -impl ObjectInner { - /// Returns true if the object is a system package. - pub fn is_system_package(&self) -> bool { - self.is_package() && is_system_package(self.id()) - } - - pub fn is_immutable(&self) -> bool { - self.owner.is_immutable() - } - - pub fn is_address_owned(&self) -> bool { - self.owner.is_address_owned() - } - - pub fn is_child_object(&self) -> bool { - self.owner.is_child_object() - } - - pub fn is_shared(&self) -> bool { - self.owner.is_shared() - } - - pub fn get_single_owner(&self) -> Option { - self.owner.get_owner_address().ok() - } - - // It's a common pattern to retrieve both the owner and object ID - // together, if it's owned by a singler owner. - pub fn get_owner_and_id(&self) -> Option<(Owner, ObjectID)> { - Some((self.owner, self.id())) - } - - /// Return true if this object is a Move package, false if it is a Move - /// value - pub fn is_package(&self) -> bool { - matches!(&self.data, Data::Package(_)) - } - - pub fn compute_object_reference(&self) -> ObjectRef { - (self.id(), self.version(), self.digest()) - } - - pub fn digest(&self) -> ObjectDigest { - ObjectDigest::new(default_hash(self)) - } - - pub fn id(&self) -> ObjectID { - use Data::*; - - match &self.data { - Move(v) => v.id(), - Package(m) => m.id(), - } - } - - pub fn version(&self) -> SequenceNumber { - use Data::*; - - match &self.data { - Move(o) => o.version(), - Package(p) => p.version(), - } - } - - pub fn type_(&self) -> Option<&MoveObjectType> { - self.data.type_() - } - - pub fn struct_tag(&self) -> Option { - self.data.struct_tag() - } - - pub fn is_coin(&self) -> bool { - if let Some(move_object) = self.data.try_as_move() { - move_object.type_().is_coin() - } else { - false - } - } - - pub fn is_gas_coin(&self) -> bool { - if let Some(move_object) = self.data.try_as_move() { - move_object.type_().is_gas_coin() - } else { - false - } - } - - // TODO: use `MoveObj::get_balance_unsafe` instead. - // context: https://github.com/MystenLabs/sui/pull/10679#discussion_r1165877816 - pub fn as_coin_maybe(&self) -> Option { - if let Some(move_object) = self.data.try_as_move() { - let coin: Coin = bcs::from_bytes(move_object.contents()).ok()?; - Some(coin) - } else { - None - } - } - - pub fn coin_type_maybe(&self) -> Option { - if let Some(move_object) = self.data.try_as_move() { - move_object.type_().coin_type_maybe() - } else { - None - } - } - - /// Return the `value: u64` field of a `Coin` type. - /// Useful for reading the coin without deserializing the object into a Move - /// value It is the caller's responsibility to check that `self` is a - /// coin--this function may panic or do something unexpected otherwise. - pub fn get_coin_value_unsafe(&self) -> u64 { - self.data.try_as_move().unwrap().get_coin_value_unsafe() - } - - /// Approximate size of the object in bytes. This is used for gas metering. - /// This will be slgihtly different from the serialized size, but - /// we also don't want to serialize the object just to get the size. - /// This approximation should be good enough for gas metering. - pub fn object_size_for_gas_metering(&self) -> usize { - let meta_data_size = size_of::() + size_of::() + size_of::(); - let data_size = match &self.data { - Data::Move(m) => m.object_size_for_gas_metering(), - Data::Package(p) => p.object_size_for_gas_metering(), - }; - meta_data_size + data_size - } - - /// Change the owner of `self` to `new_owner`. - pub fn transfer(&mut self, new_owner: SuiAddress) { - self.owner = Owner::AddressOwner(new_owner); - } - - /// Get a `MoveStructLayout` for `self`. - /// The `resolver` value must contain the module that declares `self.type_` - /// and the (transitive) dependencies of `self.type_` in order for this - /// to succeed. Failure will result in an `ObjectSerializationError` - pub fn get_layout( - &self, - resolver: &impl GetModule, - ) -> Result, SuiError> { - match &self.data { - Data::Move(m) => Ok(Some(m.get_layout(resolver)?)), - Data::Package(_) => Ok(None), - } - } - - /// Treat the object type as a Move struct with one type parameter, - /// like this: `S`. - /// Returns the inner parameter type `T`. - pub fn get_move_template_type(&self) -> SuiResult { - let move_struct = self.data.struct_tag().ok_or_else(|| SuiError::TypeError { - error: "Object must be a Move object".to_owned(), - })?; - fp_ensure!( - move_struct.type_params.len() == 1, - SuiError::TypeError { - error: "Move object struct must have one type parameter".to_owned() - } - ); - // Index access safe due to checks above. - let type_tag = move_struct.type_params[0].clone(); - Ok(type_tag) - } - - pub fn to_rust<'de, T: Deserialize<'de>>(&'de self) -> Option { - self.data.try_as_move().and_then(|data| data.to_rust()) - } -} - -// Testing-related APIs. -impl Object { - /// Get the total amount of SUI embedded in `self`, including both Move - /// objects and the storage rebate - pub fn get_total_sui(&self, layout_resolver: &mut dyn LayoutResolver) -> Result { - Ok(self.storage_rebate - + match &self.data { - Data::Move(m) => m.get_total_sui(layout_resolver)?, - Data::Package(_) => 0, - }) - } - - pub fn immutable_with_id_for_testing(id: ObjectID) -> Self { - let data = Data::Move(MoveObject { - type_: GasCoin::type_().into(), - has_public_transfer: true, - version: OBJECT_START_VERSION, - contents: GasCoin::new(id, GAS_VALUE_FOR_TESTING).to_bcs_bytes(), - }); - ObjectInner { - owner: Owner::Immutable, - data, - previous_transaction: TransactionDigest::genesis_marker(), - storage_rebate: 0, - } - .into() - } - - pub fn immutable_for_testing() -> Self { - thread_local! { - static IMMUTABLE_OBJECT_ID: ObjectID = ObjectID::random(); - } - - Self::immutable_with_id_for_testing(IMMUTABLE_OBJECT_ID.with(|id| *id)) - } - - /// make a test shared object. - pub fn shared_for_testing() -> Object { - thread_local! { - static SHARED_OBJECT_ID: ObjectID = ObjectID::random(); - } - - let obj = - MoveObject::new_gas_coin(OBJECT_START_VERSION, SHARED_OBJECT_ID.with(|id| *id), 10); - let owner = Owner::Shared { - initial_shared_version: obj.version(), - }; - Object::new_move(obj, owner, TransactionDigest::genesis_marker()) - } - - pub fn with_id_owner_gas_for_testing(id: ObjectID, owner: SuiAddress, gas: u64) -> Self { - let data = Data::Move(MoveObject { - type_: GasCoin::type_().into(), - has_public_transfer: true, - version: OBJECT_START_VERSION, - contents: GasCoin::new(id, gas).to_bcs_bytes(), - }); - ObjectInner { - owner: Owner::AddressOwner(owner), - data, - previous_transaction: TransactionDigest::genesis_marker(), - storage_rebate: 0, - } - .into() - } - - pub fn treasury_cap_for_testing(struct_tag: StructTag, treasury_cap: TreasuryCap) -> Self { - let data = Data::Move(MoveObject { - type_: TreasuryCap::type_(struct_tag).into(), - has_public_transfer: true, - version: OBJECT_START_VERSION, - contents: bcs::to_bytes(&treasury_cap).expect("Failed to serialize"), - }); - ObjectInner { - owner: Owner::Immutable, - data, - previous_transaction: TransactionDigest::genesis_marker(), - storage_rebate: 0, - } - .into() - } - - pub fn coin_metadata_for_testing(struct_tag: StructTag, metadata: CoinMetadata) -> Self { - let data = Data::Move(MoveObject { - type_: CoinMetadata::type_(struct_tag).into(), - has_public_transfer: true, - version: OBJECT_START_VERSION, - contents: bcs::to_bytes(&metadata).expect("Failed to serialize"), - }); - ObjectInner { - owner: Owner::Immutable, - data, - previous_transaction: TransactionDigest::genesis_marker(), - storage_rebate: 0, - } - .into() - } - - pub fn with_object_owner_for_testing(id: ObjectID, owner: ObjectID) -> Self { - let data = Data::Move(MoveObject { - type_: GasCoin::type_().into(), - has_public_transfer: true, - version: OBJECT_START_VERSION, - contents: GasCoin::new(id, GAS_VALUE_FOR_TESTING).to_bcs_bytes(), - }); - ObjectInner { - owner: Owner::ObjectOwner(owner.into()), - data, - previous_transaction: TransactionDigest::genesis_marker(), - storage_rebate: 0, - } - .into() - } - - pub fn with_id_owner_for_testing(id: ObjectID, owner: SuiAddress) -> Self { - // For testing, we provide sufficient gas by default. - Self::with_id_owner_gas_for_testing(id, owner, GAS_VALUE_FOR_TESTING) - } - - pub fn with_id_owner_version_for_testing( - id: ObjectID, - version: SequenceNumber, - owner: SuiAddress, - ) -> Self { - let data = Data::Move(MoveObject { - type_: GasCoin::type_().into(), - has_public_transfer: true, - version, - contents: GasCoin::new(id, GAS_VALUE_FOR_TESTING).to_bcs_bytes(), - }); - ObjectInner { - owner: Owner::AddressOwner(owner), - data, - previous_transaction: TransactionDigest::genesis_marker(), - storage_rebate: 0, - } - .into() - } - - pub fn with_owner_for_testing(owner: SuiAddress) -> Self { - Self::with_id_owner_for_testing(ObjectID::random(), owner) - } - - /// Generate a new gas coin worth `value` with a random object ID and owner - /// For testing purposes only - pub fn new_gas_with_balance_and_owner_for_testing(value: u64, owner: SuiAddress) -> Self { - let obj = MoveObject::new_gas_coin(OBJECT_START_VERSION, ObjectID::random(), value); - Object::new_move( - obj, - Owner::AddressOwner(owner), - TransactionDigest::genesis_marker(), - ) - } - - /// Generate a new gas coin object with default balance and random owner. - pub fn new_gas_for_testing() -> Self { - let gas_object_id = ObjectID::random(); - let (owner, _) = deterministic_random_account_key(); - Object::with_id_owner_for_testing(gas_object_id, owner) - } -} - -/// Make a few test gas objects (all with the same random owner). -pub fn generate_test_gas_objects() -> Vec { - thread_local! { - static GAS_OBJECTS: Vec = (0..50) - .map(|_| { - let gas_object_id = ObjectID::random(); - let (owner, _) = deterministic_random_account_key(); - Object::with_id_owner_for_testing(gas_object_id, owner) - }) - .collect(); - } - - GAS_OBJECTS.with(|v| v.clone()) -} - -#[allow(clippy::large_enum_variant)] -#[derive(Serialize, Deserialize, Debug)] -#[serde(tag = "status", content = "details")] -pub enum ObjectRead { - NotExists(ObjectID), - Exists(ObjectRef, Object, Option), - Deleted(ObjectRef), -} - -impl ObjectRead { - /// Returns the object value if there is any, otherwise an Err if - /// the object does not exist or is deleted. - pub fn into_object(self) -> UserInputResult { - match self { - Self::Deleted(oref) => Err(UserInputError::ObjectDeleted { object_ref: oref }), - Self::NotExists(id) => Err(UserInputError::ObjectNotFound { - object_id: id, - version: None, - }), - Self::Exists(_, o, _) => Ok(o), - } - } - - pub fn object(&self) -> UserInputResult<&Object> { - match self { - Self::Deleted(oref) => Err(UserInputError::ObjectDeleted { object_ref: *oref }), - Self::NotExists(id) => Err(UserInputError::ObjectNotFound { - object_id: *id, - version: None, - }), - Self::Exists(_, o, _) => Ok(o), - } - } - - pub fn object_id(&self) -> ObjectID { - match self { - Self::Deleted(oref) => oref.0, - Self::NotExists(id) => *id, - Self::Exists(oref, _, _) => oref.0, - } - } -} - -impl Display for ObjectRead { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Self::Deleted(oref) => { - write!(f, "ObjectRead::Deleted ({:?})", oref) - } - Self::NotExists(id) => { - write!(f, "ObjectRead::NotExists ({:?})", id) - } - Self::Exists(oref, _, _) => { - write!(f, "ObjectRead::Exists ({:?})", oref) - } - } - } -} - -#[allow(clippy::large_enum_variant)] -#[derive(Serialize, Deserialize, Debug)] -#[serde(tag = "status", content = "details")] -pub enum PastObjectRead { - /// The object does not exist - ObjectNotExists(ObjectID), - /// The object is found to be deleted with this version - ObjectDeleted(ObjectRef), - /// The object exists and is found with this version - VersionFound(ObjectRef, Object, Option), - /// The object exists but not found with this version - VersionNotFound(ObjectID, SequenceNumber), - /// The asked object version is higher than the latest - VersionTooHigh { - object_id: ObjectID, - asked_version: SequenceNumber, - latest_version: SequenceNumber, - }, -} - -impl PastObjectRead { - /// Returns the object value if there is any, otherwise an Err - pub fn into_object(self) -> UserInputResult { - match self { - Self::ObjectDeleted(oref) => Err(UserInputError::ObjectDeleted { object_ref: oref }), - Self::ObjectNotExists(id) => Err(UserInputError::ObjectNotFound { - object_id: id, - version: None, - }), - Self::VersionFound(_, o, _) => Ok(o), - Self::VersionNotFound(object_id, version) => Err(UserInputError::ObjectNotFound { - object_id, - version: Some(version), - }), - Self::VersionTooHigh { - object_id, - asked_version, - latest_version, - } => Err(UserInputError::ObjectSequenceNumberTooHigh { - object_id, - asked_version, - latest_version, - }), - } - } -} - -impl Display for PastObjectRead { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Self::ObjectDeleted(oref) => { - write!(f, "PastObjectRead::ObjectDeleted ({:?})", oref) - } - Self::ObjectNotExists(id) => { - write!(f, "PastObjectRead::ObjectNotExists ({:?})", id) - } - Self::VersionFound(oref, _, _) => { - write!(f, "PastObjectRead::VersionFound ({:?})", oref) - } - Self::VersionNotFound(object_id, version) => { - write!( - f, - "PastObjectRead::VersionNotFound ({:?}, asked sequence number {:?})", - object_id, version - ) - } - Self::VersionTooHigh { - object_id, - asked_version, - latest_version, - } => { - write!( - f, - "PastObjectRead::VersionTooHigh ({:?}, asked sequence number {:?}, latest sequence number {:?})", - object_id, asked_version, latest_version - ) - } - } - } -} - -// Ensure that object digest computation and bcs serialized format are not -// inadvertently changed. -#[test] -fn test_object_digest_and_serialized_format() { - let g = GasCoin::new_for_testing_with_id(ObjectID::ZERO, 123).to_object(OBJECT_START_VERSION); - let o = Object::new_move( - g, - Owner::AddressOwner(SuiAddress::ZERO), - TransactionDigest::ZERO, - ); - let bytes = bcs::to_bytes(&o).unwrap(); - - assert_eq!( - bytes, - [ - 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] - ); - - let objref = format!("{:?}", o.compute_object_reference()); - assert_eq!( - objref, - "(0x0000000000000000000000000000000000000000000000000000000000000000, SequenceNumber(1), o#59tZq65HVqZjUyNtD7BCGLTD87N5cpayYwEFrtwR4aMz)" - ); -} - -#[test] -fn test_get_coin_value_unsafe() { - fn test_for_value(v: u64) { - let g = GasCoin::new_for_testing(v).to_object(OBJECT_START_VERSION); - assert_eq!(g.get_coin_value_unsafe(), v); - assert_eq!(GasCoin::try_from(&g).unwrap().value(), v); - } - - test_for_value(0); - test_for_value(1); - test_for_value(8); - test_for_value(9); - test_for_value(u8::MAX as u64); - test_for_value(u8::MAX as u64 + 1); - test_for_value(u16::MAX as u64); - test_for_value(u16::MAX as u64 + 1); - test_for_value(u32::MAX as u64); - test_for_value(u32::MAX as u64 + 1); - test_for_value(u64::MAX); -} - -#[test] -fn test_set_coin_value_unsafe() { - fn test_for_value(v: u64) { - let mut g = GasCoin::new_for_testing(u64::MAX).to_object(OBJECT_START_VERSION); - g.set_coin_value_unsafe(v); - assert_eq!(g.get_coin_value_unsafe(), v); - assert_eq!(GasCoin::try_from(&g).unwrap().value(), v); - assert_eq!(g.version(), OBJECT_START_VERSION); - assert_eq!(g.contents().len(), 40); - } - - test_for_value(0); - test_for_value(1); - test_for_value(8); - test_for_value(9); - test_for_value(u8::MAX as u64); - test_for_value(u8::MAX as u64 + 1); - test_for_value(u16::MAX as u64); - test_for_value(u16::MAX as u64 + 1); - test_for_value(u32::MAX as u64); - test_for_value(u32::MAX as u64 + 1); - test_for_value(u64::MAX); -} diff --git a/crates/sui-types/src/randomness_state.rs b/crates/sui-types/src/randomness_state.rs deleted file mode 100644 index be5a55bcf76..00000000000 --- a/crates/sui-types/src/randomness_state.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use move_binary_format::{binary_views::BinaryIndexedView, file_format::SignatureToken}; -use move_bytecode_utils::resolve_struct; -use move_core_types::{account_address::AccountAddress, ident_str, identifier::IdentStr}; - -use crate::{ - base_types::SequenceNumber, error::SuiResult, object::Owner, storage::ObjectStore, - SUI_FRAMEWORK_ADDRESS, SUI_RANDOMNESS_STATE_OBJECT_ID, -}; - -pub const RANDOMNESS_MODULE_NAME: &IdentStr = ident_str!("random"); -pub const RANDOMNESS_STATE_STRUCT_NAME: &IdentStr = ident_str!("Random"); -pub const RANDOMNESS_STATE_UPDATE_FUNCTION_NAME: &IdentStr = ident_str!("update_randomness_state"); -pub const RANDOMNESS_STATE_CREATE_FUNCTION_NAME: &IdentStr = ident_str!("create"); -pub const RESOLVED_SUI_RANDOMNESS_STATE: (&AccountAddress, &IdentStr, &IdentStr) = ( - &SUI_FRAMEWORK_ADDRESS, - RANDOMNESS_MODULE_NAME, - RANDOMNESS_STATE_STRUCT_NAME, -); - -pub fn get_randomness_state_obj_initial_shared_version( - object_store: &dyn ObjectStore, -) -> SuiResult> { - Ok(object_store - .get_object(&SUI_RANDOMNESS_STATE_OBJECT_ID)? - .map(|obj| match obj.owner { - Owner::Shared { - initial_shared_version, - } => initial_shared_version, - _ => unreachable!("Randomness state object must be shared"), - })) -} - -pub fn is_mutable_random(view: &BinaryIndexedView<'_>, s: &SignatureToken) -> bool { - match s { - SignatureToken::MutableReference(inner) => is_mutable_random(view, inner), - SignatureToken::Struct(idx) => resolve_struct(view, *idx) == RESOLVED_SUI_RANDOMNESS_STATE, - _ => false, - } -} diff --git a/crates/sui-types/src/storage/error.rs b/crates/sui-types/src/storage/error.rs deleted file mode 100644 index a69437f8a74..00000000000 --- a/crates/sui-types/src/storage/error.rs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use typed_store_error::TypedStoreError; - -pub type Result = ::std::result::Result; - -#[derive(Debug)] -pub struct Error { - inner: Box, -} - -type BoxError = Box; - -#[derive(Debug)] -struct Inner { - kind: Kind, - source: Option, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Kind { - Serialization, - Missing, - Custom, -} - -impl Error { - fn new>(kind: Kind, source: Option) -> Self { - Self { - inner: Box::new(Inner { - kind, - source: source.map(Into::into), - }), - } - } - - pub fn serialization>(e: E) -> Self { - Self::new(Kind::Serialization, Some(e)) - } - - pub fn missing>(e: E) -> Self { - Self::new(Kind::Missing, Some(e)) - } - - pub fn custom>(e: E) -> Self { - Self::new(Kind::Custom, Some(e)) - } - - pub fn kind(&self) -> Kind { - self.inner.kind - } -} - -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.inner.source.as_ref().map(|e| &**e as _) - } -} - -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // TODO: change output based on kind? - write!(f, "{:?}", self) - } -} - -impl From for Error { - fn from(e: TypedStoreError) -> Self { - Self::custom(e) - } -} diff --git a/crates/sui-types/src/storage/mod.rs b/crates/sui-types/src/storage/mod.rs deleted file mode 100644 index 210a9d53f1d..00000000000 --- a/crates/sui-types/src/storage/mod.rs +++ /dev/null @@ -1,539 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod error; -mod object_store_trait; -mod read_store; -mod shared_in_memory_store; -mod write_store; - -use std::{ - collections::BTreeMap, - fmt::{Display, Formatter}, - sync::Arc, -}; - -use itertools::Itertools; -use move_binary_format::CompiledModule; -use move_core_types::language_storage::ModuleId; -pub use object_store_trait::ObjectStore; -pub use read_store::ReadStore; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; -pub use shared_in_memory_store::{SharedInMemoryStore, SingleCheckpointSharedInMemoryStore}; -pub use write_store::WriteStore; - -use crate::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, TransactionDigest, VersionNumber}, - committee::EpochId, - error::{SuiError, SuiResult}, - execution::{DynamicallyLoadedObjectMetadata, ExecutionResults}, - move_package::MovePackage, - object::Object, - transaction::{SenderSignedData, TransactionDataAPI, TransactionKey}, -}; - -/// A potential input to a transaction. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum InputKey { - VersionedObject { - id: ObjectID, - version: SequenceNumber, - }, - Package { - id: ObjectID, - }, -} - -impl InputKey { - pub fn id(&self) -> ObjectID { - match self { - InputKey::VersionedObject { id, .. } => *id, - InputKey::Package { id } => *id, - } - } - - pub fn version(&self) -> Option { - match self { - InputKey::VersionedObject { version, .. } => Some(*version), - InputKey::Package { .. } => None, - } - } -} - -impl From<&Object> for InputKey { - fn from(obj: &Object) -> Self { - if obj.is_package() { - InputKey::Package { id: obj.id() } - } else { - InputKey::VersionedObject { - id: obj.id(), - version: obj.version(), - } - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] -pub enum WriteKind { - /// The object was in storage already but has been modified - Mutate, - /// The object was created in this transaction - Create, - /// The object was previously wrapped in another object, but has been - /// restored to storage - Unwrap, -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] -pub enum DeleteKind { - /// An object is provided in the call input, and gets deleted. - Normal, - /// An object is not provided in the call input, but gets unwrapped - /// from another object, and then gets deleted. - UnwrapThenDelete, - /// An object is provided in the call input, and gets wrapped into another - /// object. - Wrap, -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] -pub enum MarkerValue { - /// An object was received at the given version in the transaction and is no - /// longer able to be received at that version in subequent - /// transactions. - Received, - /// An owned object was deleted (or wrapped) at the given version, and is no - /// longer able to be accessed or used in subsequent transactions. - OwnedDeleted, - /// A shared object was deleted by the transaction and is no longer able to - /// be accessed or used in subsequent transactions. - SharedDeleted(TransactionDigest), -} - -/// DeleteKind together with the old sequence number prior to the deletion, if -/// available. For normal deletion and wrap, we always will consult the object -/// store to obtain the old sequence number. For UnwrapThenDelete however, in -/// the old protocol where simplified_unwrap_then_delete is false, -/// we will consult the object store to obtain the old sequence number, which -/// latter will be put in modified_at_versions; in the new protocol where -/// simplified_unwrap_then_delete is true, we will not consult the object store, -/// and hence won't have the old sequence number. -#[derive(Debug)] -pub enum DeleteKindWithOldVersion { - Normal(SequenceNumber), - // This variant will be deprecated when we turn on simplified_unwrap_then_delete. - UnwrapThenDeleteDEPRECATED(SequenceNumber), - UnwrapThenDelete, - Wrap(SequenceNumber), -} - -impl DeleteKindWithOldVersion { - pub fn old_version(&self) -> Option { - match self { - DeleteKindWithOldVersion::Normal(version) - | DeleteKindWithOldVersion::UnwrapThenDeleteDEPRECATED(version) - | DeleteKindWithOldVersion::Wrap(version) => Some(*version), - DeleteKindWithOldVersion::UnwrapThenDelete => None, - } - } - - pub fn to_delete_kind(&self) -> DeleteKind { - match self { - DeleteKindWithOldVersion::Normal(_) => DeleteKind::Normal, - DeleteKindWithOldVersion::UnwrapThenDeleteDEPRECATED(_) - | DeleteKindWithOldVersion::UnwrapThenDelete => DeleteKind::UnwrapThenDelete, - DeleteKindWithOldVersion::Wrap(_) => DeleteKind::Wrap, - } - } -} - -#[derive(Debug)] -pub enum ObjectChange { - Write(Object, WriteKind), - // DeleteKind together with the old sequence number prior to the deletion, if available. - Delete(DeleteKindWithOldVersion), -} - -pub trait StorageView: Storage + ParentSync + ChildObjectResolver {} -impl StorageView for T {} - -/// An abstraction of the (possibly distributed) store for objects. This -/// API only allows for the retrieval of objects, not any state changes -pub trait ChildObjectResolver { - /// `child` must have an `ObjectOwner` ownership equal to `owner`. - fn read_child_object( - &self, - parent: &ObjectID, - child: &ObjectID, - child_version_upper_bound: SequenceNumber, - ) -> SuiResult>; - - /// `receiving_object_id` must have an `AddressOwner` ownership equal to - /// `owner`. `get_object_received_at_version` must be the exact version - /// at which the object will be received, and it cannot have been - /// previously received at that version. NB: An object not existing at - /// that version, and not having valid access to the object will be treated - /// exactly the same and `Ok(None)` must be returned. - fn get_object_received_at_version( - &self, - owner: &ObjectID, - receiving_object_id: &ObjectID, - receive_object_at_version: SequenceNumber, - epoch_id: EpochId, - ) -> SuiResult>; -} - -/// An abstraction of the (possibly distributed) store for objects, and (soon) -/// events and transactions -pub trait Storage { - fn reset(&mut self); - - fn read_object(&self, id: &ObjectID) -> Option<&Object>; - - fn record_execution_results(&mut self, results: ExecutionResults); - - fn save_loaded_runtime_objects( - &mut self, - loaded_runtime_objects: BTreeMap, - ); - - fn save_wrapped_object_containers( - &mut self, - wrapped_object_containers: BTreeMap, - ); -} - -pub type PackageFetchResults = Result, Vec>; - -#[derive(Clone, Debug)] -pub struct PackageObject { - package_object: Object, -} - -impl PackageObject { - pub fn new(package_object: Object) -> Self { - assert!(package_object.is_package()); - Self { package_object } - } - - pub fn object(&self) -> &Object { - &self.package_object - } - - pub fn move_package(&self) -> &MovePackage { - self.package_object.data.try_as_package().unwrap() - } -} - -impl From for Object { - fn from(package_object_arc: PackageObject) -> Self { - package_object_arc.package_object - } -} - -pub trait BackingPackageStore { - fn get_package_object(&self, package_id: &ObjectID) -> SuiResult>; -} - -impl BackingPackageStore for Arc { - fn get_package_object(&self, package_id: &ObjectID) -> SuiResult> { - BackingPackageStore::get_package_object(self.as_ref(), package_id) - } -} - -impl BackingPackageStore for &S { - fn get_package_object(&self, package_id: &ObjectID) -> SuiResult> { - BackingPackageStore::get_package_object(*self, package_id) - } -} - -impl BackingPackageStore for &mut S { - fn get_package_object(&self, package_id: &ObjectID) -> SuiResult> { - BackingPackageStore::get_package_object(*self, package_id) - } -} - -pub fn load_package_object_from_object_store( - store: &impl ObjectStore, - package_id: &ObjectID, -) -> SuiResult> { - let package = store.get_object(package_id)?; - if let Some(obj) = &package { - fp_ensure!( - obj.is_package(), - SuiError::BadObjectType { - error: format!("Package expected, Move object found: {package_id}"), - } - ); - } - Ok(package.map(PackageObject::new)) -} - -/// Returns Ok() if all -/// package IDs in `package_id` were found. If any package in `package_ids` was -/// not found it returns a list of any package ids that are unable to be -/// found>). -pub fn get_package_objects<'a>( - store: &impl BackingPackageStore, - package_ids: impl IntoIterator, -) -> SuiResult> { - let packages: Vec> = package_ids - .into_iter() - .map(|id| match store.get_package_object(id) { - Ok(None) => Ok(Err(*id)), - Ok(Some(o)) => Ok(Ok(o)), - Err(x) => Err(x), - }) - .collect::>()?; - - let (fetched, failed_to_fetch): (Vec<_>, Vec<_>) = packages.into_iter().partition_result(); - if !failed_to_fetch.is_empty() { - Ok(Err(failed_to_fetch)) - } else { - Ok(Ok(fetched)) - } -} - -pub fn get_module( - store: S, - module_id: &ModuleId, -) -> Result>, SuiError> { - Ok(store - .get_package_object(&ObjectID::from(*module_id.address()))? - .and_then(|package| { - package - .move_package() - .serialized_module_map() - .get(module_id.name().as_str()) - .cloned() - })) -} - -pub fn get_module_by_id( - store: S, - id: &ModuleId, -) -> anyhow::Result, SuiError> { - Ok(get_module(store, id)? - .map(|bytes| CompiledModule::deserialize_with_defaults(&bytes).unwrap())) -} - -pub trait ParentSync { - /// This function is only called by older protocol versions. - /// It creates an explicit dependency to tombstones, which is not desired. - fn get_latest_parent_entry_ref_deprecated( - &self, - object_id: ObjectID, - ) -> SuiResult>; -} - -impl ParentSync for std::sync::Arc { - fn get_latest_parent_entry_ref_deprecated( - &self, - object_id: ObjectID, - ) -> SuiResult> { - ParentSync::get_latest_parent_entry_ref_deprecated(self.as_ref(), object_id) - } -} - -impl ParentSync for &S { - fn get_latest_parent_entry_ref_deprecated( - &self, - object_id: ObjectID, - ) -> SuiResult> { - ParentSync::get_latest_parent_entry_ref_deprecated(*self, object_id) - } -} - -impl ParentSync for &mut S { - fn get_latest_parent_entry_ref_deprecated( - &self, - object_id: ObjectID, - ) -> SuiResult> { - ParentSync::get_latest_parent_entry_ref_deprecated(*self, object_id) - } -} - -impl ChildObjectResolver for std::sync::Arc { - fn read_child_object( - &self, - parent: &ObjectID, - child: &ObjectID, - child_version_upper_bound: SequenceNumber, - ) -> SuiResult> { - ChildObjectResolver::read_child_object( - self.as_ref(), - parent, - child, - child_version_upper_bound, - ) - } - fn get_object_received_at_version( - &self, - owner: &ObjectID, - receiving_object_id: &ObjectID, - receive_object_at_version: SequenceNumber, - epoch_id: EpochId, - ) -> SuiResult> { - ChildObjectResolver::get_object_received_at_version( - self.as_ref(), - owner, - receiving_object_id, - receive_object_at_version, - epoch_id, - ) - } -} - -impl ChildObjectResolver for &S { - fn read_child_object( - &self, - parent: &ObjectID, - child: &ObjectID, - child_version_upper_bound: SequenceNumber, - ) -> SuiResult> { - ChildObjectResolver::read_child_object(*self, parent, child, child_version_upper_bound) - } - fn get_object_received_at_version( - &self, - owner: &ObjectID, - receiving_object_id: &ObjectID, - receive_object_at_version: SequenceNumber, - epoch_id: EpochId, - ) -> SuiResult> { - ChildObjectResolver::get_object_received_at_version( - *self, - owner, - receiving_object_id, - receive_object_at_version, - epoch_id, - ) - } -} - -impl ChildObjectResolver for &mut S { - fn read_child_object( - &self, - parent: &ObjectID, - child: &ObjectID, - child_version_upper_bound: SequenceNumber, - ) -> SuiResult> { - ChildObjectResolver::read_child_object(*self, parent, child, child_version_upper_bound) - } - fn get_object_received_at_version( - &self, - owner: &ObjectID, - receiving_object_id: &ObjectID, - receive_object_at_version: SequenceNumber, - epoch_id: EpochId, - ) -> SuiResult> { - ChildObjectResolver::get_object_received_at_version( - *self, - owner, - receiving_object_id, - receive_object_at_version, - epoch_id, - ) - } -} - -// The primary key type for object storage. -#[serde_as] -#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)] -pub struct ObjectKey(pub ObjectID, pub VersionNumber); - -impl ObjectKey { - pub const ZERO: ObjectKey = ObjectKey(ObjectID::ZERO, VersionNumber::MIN); - - pub fn max_for_id(id: &ObjectID) -> Self { - Self(*id, VersionNumber::MAX) - } - - pub fn min_for_id(id: &ObjectID) -> Self { - Self(*id, VersionNumber::MIN) - } -} - -impl From for ObjectKey { - fn from(object_ref: ObjectRef) -> Self { - ObjectKey::from(&object_ref) - } -} - -impl From<&ObjectRef> for ObjectKey { - fn from(object_ref: &ObjectRef) -> Self { - Self(object_ref.0, object_ref.1) - } -} - -pub enum ObjectOrTombstone { - Object(Object), - Tombstone(ObjectRef), -} - -impl From for ObjectOrTombstone { - fn from(object: Object) -> Self { - ObjectOrTombstone::Object(object) - } -} - -/// Fetch the `ObjectKey`s (IDs and versions) for non-shared input objects. -/// Includes owned, and immutable objects as well as the gas objects, but not -/// move packages or shared objects. -pub fn transaction_input_object_keys(tx: &SenderSignedData) -> SuiResult> { - use crate::transaction::InputObjectKind as I; - Ok(tx - .intent_message() - .value - .input_objects()? - .into_iter() - .filter_map(|object| match object { - I::MovePackage(_) | I::SharedMoveObject { .. } => None, - I::ImmOrOwnedMoveObject(obj) => Some(obj.into()), - }) - .collect()) -} - -pub fn transaction_receiving_object_keys(tx: &SenderSignedData) -> Vec { - tx.intent_message() - .value - .receiving_objects() - .into_iter() - .map(|oref| oref.into()) - .collect() -} - -impl Display for DeleteKind { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - DeleteKind::Wrap => write!(f, "Wrap"), - DeleteKind::Normal => write!(f, "Normal"), - DeleteKind::UnwrapThenDelete => write!(f, "UnwrapThenDelete"), - } - } -} - -pub trait BackingStore: - BackingPackageStore + ChildObjectResolver + ObjectStore + ParentSync -{ - fn as_object_store(&self) -> &dyn ObjectStore; -} - -impl BackingStore for T -where - T: BackingPackageStore, - T: ChildObjectResolver, - T: ObjectStore, - T: ParentSync, -{ - fn as_object_store(&self) -> &dyn ObjectStore { - self - } -} - -pub trait GetSharedLocks: Send + Sync { - fn get_shared_locks( - &self, - key: &TransactionKey, - ) -> Result, SuiError>; -} diff --git a/crates/sui-types/src/sui_serde.rs b/crates/sui-types/src/sui_serde.rs deleted file mode 100644 index 5abe1edcbe1..00000000000 --- a/crates/sui-types/src/sui_serde.rs +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - fmt, - fmt::{Debug, Display, Formatter, Write}, - marker::PhantomData, - ops::Deref, - str::FromStr, -}; - -use fastcrypto::encoding::Hex; -use move_core_types::{ - account_address::AccountAddress, - language_storage::{StructTag, TypeTag}, -}; -use schemars::JsonSchema; -use serde::{ - self, - de::{Deserializer, Error}, - ser::{Error as SerError, Serializer}, - Deserialize, Serialize, -}; -use serde_with::{serde_as, Bytes, DeserializeAs, DisplayFromStr, SerializeAs}; -use sui_protocol_config::ProtocolVersion; - -use crate::{ - parse_sui_struct_tag, parse_sui_type_tag, DEEPBOOK_ADDRESS, STARDUST_ADDRESS, - SUI_CLOCK_ADDRESS, SUI_FRAMEWORK_ADDRESS, SUI_SYSTEM_ADDRESS, SUI_SYSTEM_STATE_ADDRESS, - TIMELOCK_ADDRESS, -}; - -#[inline] -fn to_custom_error<'de, D, E>(e: E) -> D::Error -where - E: Debug, - D: Deserializer<'de>, -{ - Error::custom(format!("byte deserialization failed, cause by: {:?}", e)) -} - -#[inline] -fn to_custom_ser_error(e: E) -> S::Error -where - E: Debug, - S: Serializer, -{ - S::Error::custom(format!("byte serialization failed, cause by: {:?}", e)) -} - -/// Use with serde_as to control serde for human-readable serialization and -/// deserialization `H` : serde_as SerializeAs/DeserializeAs delegation for -/// human readable in/output `R` : serde_as SerializeAs/DeserializeAs delegation -/// for non-human readable in/output -/// -/// # Example: -/// -/// ```text -/// #[serde_as] -/// #[derive(Deserialize, Serialize)] -/// struct Example(#[serde_as(as = "Readable")] [u8; 20]); -/// ``` -/// -/// The above example will delegate human-readable serde to `DisplayFromStr` -/// and array tuple (default) for non-human-readable serializer. -pub struct Readable { - human_readable: PhantomData, - non_human_readable: PhantomData, -} - -impl SerializeAs for Readable -where - H: SerializeAs, - R: SerializeAs, -{ - fn serialize_as(value: &T, serializer: S) -> Result - where - S: Serializer, - { - if serializer.is_human_readable() { - H::serialize_as(value, serializer) - } else { - R::serialize_as(value, serializer) - } - } -} - -impl<'de, R, H, T> DeserializeAs<'de, T> for Readable -where - H: DeserializeAs<'de, T>, - R: DeserializeAs<'de, T>, -{ - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - if deserializer.is_human_readable() { - H::deserialize_as(deserializer) - } else { - R::deserialize_as(deserializer) - } - } -} - -/// custom serde for AccountAddress -pub struct HexAccountAddress; - -impl SerializeAs for HexAccountAddress { - fn serialize_as(value: &AccountAddress, serializer: S) -> Result - where - S: Serializer, - { - Hex::serialize_as(value, serializer) - } -} - -impl<'de> DeserializeAs<'de, AccountAddress> for HexAccountAddress { - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - if s.starts_with("0x") { - AccountAddress::from_hex_literal(&s) - } else { - AccountAddress::from_hex(&s) - } - .map_err(to_custom_error::<'de, D, _>) - } -} - -/// Serializes a bitmap according to the roaring bitmap on-disk standard. -/// -pub struct SuiBitmap; - -impl SerializeAs for SuiBitmap { - fn serialize_as(source: &roaring::RoaringBitmap, serializer: S) -> Result - where - S: Serializer, - { - let mut bytes = vec![]; - - source - .serialize_into(&mut bytes) - .map_err(to_custom_ser_error::)?; - Bytes::serialize_as(&bytes, serializer) - } -} - -impl<'de> DeserializeAs<'de, roaring::RoaringBitmap> for SuiBitmap { - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let bytes: Vec = Bytes::deserialize_as(deserializer)?; - roaring::RoaringBitmap::deserialize_from(&bytes[..]).map_err(to_custom_error::<'de, D, _>) - } -} - -pub struct SuiStructTag; - -impl SerializeAs for SuiStructTag { - fn serialize_as(value: &StructTag, serializer: S) -> Result - where - S: Serializer, - { - let f = to_sui_struct_tag_string(value).map_err(S::Error::custom)?; - f.serialize(serializer) - } -} - -const SUI_ADDRESSES: [AccountAddress; 9] = [ - AccountAddress::ZERO, - AccountAddress::ONE, - SUI_FRAMEWORK_ADDRESS, - SUI_SYSTEM_ADDRESS, - STARDUST_ADDRESS, - TIMELOCK_ADDRESS, - DEEPBOOK_ADDRESS, - SUI_SYSTEM_STATE_ADDRESS, - SUI_CLOCK_ADDRESS, -]; -/// Serialize StructTag as a string, retaining the leading zeros in the address. -pub fn to_sui_struct_tag_string(value: &StructTag) -> Result { - let mut f = String::new(); - // trim leading zeros if address is in SUI_ADDRESSES - let address = if SUI_ADDRESSES.contains(&value.address) { - value.address.short_str_lossless() - } else { - value.address.to_canonical_string(/* with_prefix */ false) - }; - - write!(f, "0x{}::{}::{}", address, value.module, value.name)?; - if let Some(first_ty) = value.type_params.first() { - write!(f, "<")?; - write!(f, "{}", to_sui_type_tag_string(first_ty)?)?; - for ty in value.type_params.iter().skip(1) { - write!(f, ", {}", to_sui_type_tag_string(ty)?)?; - } - write!(f, ">")?; - } - Ok(f) -} - -fn to_sui_type_tag_string(value: &TypeTag) -> Result { - match value { - TypeTag::Vector(t) => Ok(format!("vector<{}>", to_sui_type_tag_string(t)?)), - TypeTag::Struct(s) => to_sui_struct_tag_string(s), - _ => Ok(value.to_string()), - } -} - -impl<'de> DeserializeAs<'de, StructTag> for SuiStructTag { - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - parse_sui_struct_tag(&s).map_err(D::Error::custom) - } -} - -pub struct SuiTypeTag; - -impl SerializeAs for SuiTypeTag { - fn serialize_as(value: &TypeTag, serializer: S) -> Result - where - S: Serializer, - { - let s = to_sui_type_tag_string(value).map_err(S::Error::custom)?; - s.serialize(serializer) - } -} - -impl<'de> DeserializeAs<'de, TypeTag> for SuiTypeTag { - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - parse_sui_type_tag(&s).map_err(D::Error::custom) - } -} - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy, JsonSchema)] -pub struct BigInt( - #[schemars(with = "String")] - #[serde_as(as = "DisplayFromStr")] - T, -) -where - T: Display + FromStr, - ::Err: Display; - -impl BigInt -where - T: Display + FromStr, - ::Err: Display, -{ - pub fn into_inner(self) -> T { - self.0 - } -} - -impl SerializeAs for BigInt -where - T: Display + FromStr + Copy, - ::Err: Display, -{ - fn serialize_as(value: &T, serializer: S) -> Result - where - S: Serializer, - { - BigInt(*value).serialize(serializer) - } -} - -impl<'de, T> DeserializeAs<'de, T> for BigInt -where - T: Display + FromStr + Copy, - ::Err: Display, -{ - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Ok(*BigInt::deserialize(deserializer)?) - } -} - -impl From for BigInt -where - T: Display + FromStr, - ::Err: Display, -{ - fn from(v: T) -> BigInt { - BigInt(v) - } -} - -impl Deref for BigInt -where - T: Display + FromStr, - ::Err: Display, -{ - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Display for BigInt -where - T: Display + FromStr, - ::Err: Display, -{ - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy, JsonSchema)] -pub struct SequenceNumber(#[schemars(with = "BigInt")] u64); - -impl SerializeAs for SequenceNumber { - fn serialize_as( - value: &crate::base_types::SequenceNumber, - serializer: S, - ) -> Result - where - S: Serializer, - { - let s = value.value().to_string(); - s.serialize(serializer) - } -} - -impl<'de> DeserializeAs<'de, crate::base_types::SequenceNumber> for SequenceNumber { - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let b = BigInt::deserialize(deserializer)?; - Ok(crate::base_types::SequenceNumber::from_u64(*b)) - } -} - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy, JsonSchema)] -#[serde(rename = "ProtocolVersion")] -pub struct AsProtocolVersion(#[schemars(with = "BigInt")] u64); - -impl SerializeAs for AsProtocolVersion { - fn serialize_as(value: &ProtocolVersion, serializer: S) -> Result - where - S: Serializer, - { - let s = value.as_u64().to_string(); - s.serialize(serializer) - } -} - -impl<'de> DeserializeAs<'de, ProtocolVersion> for AsProtocolVersion { - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let b = BigInt::::deserialize(deserializer)?; - Ok(ProtocolVersion::from(*b)) - } -} diff --git a/crates/sui-types/src/sui_system_state/epoch_start_sui_system_state.rs b/crates/sui-types/src/sui_system_state/epoch_start_sui_system_state.rs deleted file mode 100644 index d94ea245164..00000000000 --- a/crates/sui-types/src/sui_system_state/epoch_start_sui_system_state.rs +++ /dev/null @@ -1,414 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::{BTreeMap, HashMap}; - -use anemo::{ - types::{PeerAffinity, PeerInfo}, - PeerId, -}; -use consensus_config::{ - Authority, AuthorityPublicKey, Committee as ConsensusCommittee, NetworkPublicKey, - ProtocolPublicKey, -}; -use enum_dispatch::enum_dispatch; -use narwhal_config::{Committee as NarwhalCommittee, CommitteeBuilder, WorkerCache, WorkerIndex}; -use serde::{Deserialize, Serialize}; -use sui_protocol_config::ProtocolVersion; -use tracing::{error, warn}; - -use crate::{ - base_types::{AuthorityName, EpochId, SuiAddress}, - committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata, StakeUnit}, - multiaddr::Multiaddr, -}; - -#[enum_dispatch] -pub trait EpochStartSystemStateTrait { - fn epoch(&self) -> EpochId; - fn protocol_version(&self) -> ProtocolVersion; - fn reference_gas_price(&self) -> u64; - fn safe_mode(&self) -> bool; - fn epoch_start_timestamp_ms(&self) -> u64; - fn epoch_duration_ms(&self) -> u64; - fn get_validator_addresses(&self) -> Vec; - fn get_sui_committee(&self) -> Committee; - fn get_sui_committee_with_network_metadata(&self) -> CommitteeWithNetworkMetadata; - fn get_narwhal_committee(&self) -> NarwhalCommittee; - fn get_mysticeti_committee(&self) -> ConsensusCommittee; - fn get_validator_as_p2p_peers(&self, excluding_self: AuthorityName) -> Vec; - fn get_authority_names_to_peer_ids(&self) -> HashMap; - fn get_authority_names_to_hostnames(&self) -> HashMap; - fn get_narwhal_worker_cache(&self, transactions_address: &Multiaddr) -> WorkerCache; -} - -/// This type captures the minimum amount of information from SuiSystemState -/// needed by a validator to run the protocol. This allows us to decouple from -/// the actual SuiSystemState type, and hence do not need to evolve it when we -/// upgrade the SuiSystemState type. Evolving EpochStartSystemState is also a -/// lot easier in that we could add optional fields and fill them with None for -/// older versions. When we absolutely must delete fields, we could also add new -/// db tables to store the new version. This is OK because we only store one -/// copy of this as part of EpochStartConfiguration for the most recent epoch in -/// the db. -#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] -#[enum_dispatch(EpochStartSystemStateTrait)] -pub enum EpochStartSystemState { - V1(EpochStartSystemStateV1), -} - -impl EpochStartSystemState { - pub fn new_v1( - epoch: EpochId, - protocol_version: u64, - reference_gas_price: u64, - safe_mode: bool, - epoch_start_timestamp_ms: u64, - epoch_duration_ms: u64, - active_validators: Vec, - ) -> Self { - Self::V1(EpochStartSystemStateV1 { - epoch, - protocol_version, - reference_gas_price, - safe_mode, - epoch_start_timestamp_ms, - epoch_duration_ms, - active_validators, - }) - } - - pub fn new_for_testing_with_epoch(epoch: EpochId) -> Self { - Self::V1(EpochStartSystemStateV1::new_for_testing_with_epoch(epoch)) - } -} - -#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] -pub struct EpochStartSystemStateV1 { - epoch: EpochId, - protocol_version: u64, - reference_gas_price: u64, - safe_mode: bool, - epoch_start_timestamp_ms: u64, - epoch_duration_ms: u64, - active_validators: Vec, -} - -impl EpochStartSystemStateV1 { - pub fn new_for_testing() -> Self { - Self::new_for_testing_with_epoch(0) - } - - pub fn new_for_testing_with_epoch(epoch: EpochId) -> Self { - Self { - epoch, - protocol_version: ProtocolVersion::MAX.as_u64(), - reference_gas_price: crate::transaction::DEFAULT_VALIDATOR_GAS_PRICE, - safe_mode: false, - epoch_start_timestamp_ms: 0, - epoch_duration_ms: 1000, - active_validators: vec![], - } - } -} - -impl EpochStartSystemStateTrait for EpochStartSystemStateV1 { - fn epoch(&self) -> EpochId { - self.epoch - } - - fn protocol_version(&self) -> ProtocolVersion { - ProtocolVersion::new(self.protocol_version) - } - - fn reference_gas_price(&self) -> u64 { - self.reference_gas_price - } - - fn safe_mode(&self) -> bool { - self.safe_mode - } - - fn epoch_start_timestamp_ms(&self) -> u64 { - self.epoch_start_timestamp_ms - } - - fn epoch_duration_ms(&self) -> u64 { - self.epoch_duration_ms - } - - fn get_validator_addresses(&self) -> Vec { - self.active_validators - .iter() - .map(|validator| validator.sui_address) - .collect() - } - - fn get_sui_committee_with_network_metadata(&self) -> CommitteeWithNetworkMetadata { - let (voting_rights, network_metadata) = self - .active_validators - .iter() - .map(|validator| { - ( - (validator.authority_name(), validator.voting_power), - ( - validator.authority_name(), - NetworkMetadata { - network_address: validator.sui_net_address.clone(), - narwhal_primary_address: validator.narwhal_primary_address.clone(), - }, - ), - ) - }) - .unzip(); - - CommitteeWithNetworkMetadata { - committee: Committee::new(self.epoch, voting_rights), - network_metadata, - } - } - - fn get_sui_committee(&self) -> Committee { - let voting_rights = self - .active_validators - .iter() - .map(|validator| (validator.authority_name(), validator.voting_power)) - .collect(); - Committee::new(self.epoch, voting_rights) - } - - fn get_narwhal_committee(&self) -> NarwhalCommittee { - let mut committee_builder = CommitteeBuilder::new(self.epoch as narwhal_config::Epoch); - - for validator in self.active_validators.iter() { - committee_builder = committee_builder.add_authority( - validator.protocol_pubkey.clone(), - validator.voting_power as narwhal_config::Stake, - validator.narwhal_primary_address.clone(), - validator.narwhal_network_pubkey.clone(), - validator.hostname.clone(), - ); - } - - committee_builder.build() - } - - fn get_mysticeti_committee(&self) -> ConsensusCommittee { - let mut authorities = vec![]; - for validator in self.active_validators.iter() { - authorities.push(Authority { - stake: validator.voting_power as consensus_config::Stake, - // TODO(mysticeti): Add EpochStartValidatorInfoV2 with new field for mysticeti - // address. - address: validator.narwhal_primary_address.clone(), - hostname: validator.hostname.clone(), - authority_key: AuthorityPublicKey::new(validator.protocol_pubkey.clone()), - protocol_key: ProtocolPublicKey::new(validator.narwhal_worker_pubkey.clone()), - network_key: NetworkPublicKey::new(validator.narwhal_network_pubkey.clone()), - }); - } - - // Sort the authorities by their protocol (public) key in ascending order, same - // as the order in the Sui committee returned from get_sui_committee(). - authorities.sort_by(|a1, a2| a1.authority_key.cmp(&a2.authority_key)); - - for ((i, mysticeti_authority), sui_authority_name) in authorities - .iter() - .enumerate() - .zip(self.get_sui_committee().names()) - { - if sui_authority_name.0 != mysticeti_authority.authority_key.to_bytes() { - error!( - "Mismatched authority order between Sui and Mysticeti! Index {}, Mysticeti authority {:?}\nSui authority name {}", - i, mysticeti_authority, sui_authority_name - ); - } - } - - ConsensusCommittee::new(self.epoch as consensus_config::Epoch, authorities) - } - - fn get_validator_as_p2p_peers(&self, excluding_self: AuthorityName) -> Vec { - self.active_validators - .iter() - .filter(|validator| validator.authority_name() != excluding_self) - .map(|validator| { - let address = validator - .p2p_address - .to_anemo_address() - .into_iter() - .collect::>(); - let peer_id = PeerId(validator.narwhal_network_pubkey.0.to_bytes()); - if address.is_empty() { - warn!( - ?peer_id, - "Peer has invalid p2p address: {}", &validator.p2p_address - ); - } - PeerInfo { - peer_id, - affinity: PeerAffinity::High, - address, - } - }) - .collect() - } - - fn get_authority_names_to_peer_ids(&self) -> HashMap { - self.active_validators - .iter() - .map(|validator| { - let name = validator.authority_name(); - let peer_id = PeerId(validator.narwhal_network_pubkey.0.to_bytes()); - - (name, peer_id) - }) - .collect() - } - - fn get_authority_names_to_hostnames(&self) -> HashMap { - self.active_validators - .iter() - .map(|validator| { - let name = validator.authority_name(); - let hostname = validator.hostname.clone(); - - (name, hostname) - }) - .collect() - } - - #[allow(clippy::mutable_key_type)] - fn get_narwhal_worker_cache(&self, transactions_address: &Multiaddr) -> WorkerCache { - let workers: BTreeMap = self - .active_validators - .iter() - .map(|validator| { - let workers = [( - 0, - narwhal_config::WorkerInfo { - name: validator.narwhal_worker_pubkey.clone(), - transactions: transactions_address.clone(), - worker_address: validator.narwhal_worker_address.clone(), - }, - )] - .into_iter() - .collect(); - let worker_index = WorkerIndex(workers); - - (validator.protocol_pubkey.clone(), worker_index) - }) - .collect(); - WorkerCache { - workers, - epoch: self.epoch, - } - } -} - -#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] -pub struct EpochStartValidatorInfoV1 { - pub sui_address: SuiAddress, - pub protocol_pubkey: narwhal_crypto::PublicKey, - pub narwhal_network_pubkey: narwhal_crypto::NetworkPublicKey, - pub narwhal_worker_pubkey: narwhal_crypto::NetworkPublicKey, - pub sui_net_address: Multiaddr, - pub p2p_address: Multiaddr, - pub narwhal_primary_address: Multiaddr, - pub narwhal_worker_address: Multiaddr, - pub voting_power: StakeUnit, - pub hostname: String, -} - -impl EpochStartValidatorInfoV1 { - pub fn authority_name(&self) -> AuthorityName { - (&self.protocol_pubkey).into() - } -} - -#[cfg(test)] -mod test { - use fastcrypto::traits::KeyPair; - use mysten_network::Multiaddr; - use narwhal_crypto::NetworkKeyPair; - use rand::thread_rng; - use sui_protocol_config::ProtocolVersion; - - use crate::{ - base_types::SuiAddress, - committee::CommitteeTrait, - crypto::{get_key_pair, AuthorityKeyPair}, - sui_system_state::epoch_start_sui_system_state::{ - EpochStartSystemStateTrait, EpochStartSystemStateV1, EpochStartValidatorInfoV1, - }, - }; - - #[test] - fn test_sui_and_mysticeti_committee_are_same() { - // GIVEN - let mut active_validators = vec![]; - - for i in 0..10 { - let (sui_address, protocol_key): (SuiAddress, AuthorityKeyPair) = get_key_pair(); - let narwhal_network_key = NetworkKeyPair::generate(&mut thread_rng()); - - active_validators.push(EpochStartValidatorInfoV1 { - sui_address, - protocol_pubkey: protocol_key.public().clone(), - narwhal_network_pubkey: narwhal_network_key.public().clone(), - narwhal_worker_pubkey: narwhal_network_key.public().clone(), - sui_net_address: Multiaddr::empty(), - p2p_address: Multiaddr::empty(), - narwhal_primary_address: Multiaddr::empty(), - narwhal_worker_address: Multiaddr::empty(), - voting_power: 1_000, - hostname: format!("host-{i}").to_string(), - }) - } - - let state = EpochStartSystemStateV1 { - epoch: 10, - protocol_version: ProtocolVersion::MAX.as_u64(), - reference_gas_price: 0, - safe_mode: false, - epoch_start_timestamp_ms: 0, - epoch_duration_ms: 0, - active_validators, - }; - - // WHEN - let sui_committee = state.get_sui_committee(); - let mysticeti_committee = state.get_mysticeti_committee(); - - // THEN - // assert the validators details - assert_eq!(sui_committee.num_members(), 10); - assert_eq!(sui_committee.num_members(), mysticeti_committee.size()); - assert_eq!( - sui_committee.validity_threshold(), - mysticeti_committee.validity_threshold() - ); - assert_eq!( - sui_committee.quorum_threshold(), - mysticeti_committee.quorum_threshold() - ); - assert_eq!(state.epoch, mysticeti_committee.epoch()); - - for (authority_index, mysticeti_authority) in mysticeti_committee.authorities() { - let sui_authority_name = sui_committee - .authority_by_index(authority_index.value() as u32) - .unwrap(); - - assert_eq!( - mysticeti_authority.authority_key.to_bytes(), - sui_authority_name.0, - "Mysten & SUI committee member of same index correspond to different public key" - ); - assert_eq!( - mysticeti_authority.stake, - sui_committee.weight(sui_authority_name), - "Mysten & SUI committee member stake differs" - ); - } - } -} diff --git a/crates/sui-types/src/sui_system_state/mod.rs b/crates/sui-types/src/sui_system_state/mod.rs deleted file mode 100644 index dfd6f0705c7..00000000000 --- a/crates/sui-types/src/sui_system_state/mod.rs +++ /dev/null @@ -1,486 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt; - -use anyhow::Result; -use enum_dispatch::enum_dispatch; -use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use sui_protocol_config::{ProtocolConfig, ProtocolVersion}; - -use self::{ - sui_system_state_inner_v1::{SuiSystemStateInnerV1, ValidatorV1}, - sui_system_state_summary::{SuiSystemStateSummary, SuiValidatorSummary}, -}; -use crate::{ - base_types::ObjectID, - committee::CommitteeWithNetworkMetadata, - dynamic_field::{get_dynamic_field_from_store, get_dynamic_field_object_from_store, Field}, - error::SuiError, - id::UID, - object::{MoveObject, Object}, - storage::ObjectStore, - sui_system_state::{ - epoch_start_sui_system_state::EpochStartSystemState, - sui_system_state_inner_v2::SuiSystemStateInnerV2, - }, - versioned::Versioned, - MoveTypeTagTrait, SUI_SYSTEM_ADDRESS, SUI_SYSTEM_STATE_OBJECT_ID, -}; - -pub mod epoch_start_sui_system_state; -pub mod sui_system_state_inner_v1; -pub mod sui_system_state_inner_v2; -pub mod sui_system_state_summary; - -#[cfg(msim)] -mod simtest_sui_system_state_inner; -#[cfg(msim)] -use self::simtest_sui_system_state_inner::{ - SimTestSuiSystemStateInnerDeepV2, SimTestSuiSystemStateInnerShallowV2, - SimTestSuiSystemStateInnerV1, SimTestValidatorDeepV2, SimTestValidatorV1, -}; - -const SUI_SYSTEM_STATE_WRAPPER_STRUCT_NAME: &IdentStr = ident_str!("SuiSystemState"); - -pub const SUI_SYSTEM_MODULE_NAME: &IdentStr = ident_str!("sui_system"); -pub const ADVANCE_EPOCH_FUNCTION_NAME: &IdentStr = ident_str!("advance_epoch"); -pub const ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME: &IdentStr = ident_str!("advance_epoch_safe_mode"); - -#[cfg(msim)] -pub const SUI_SYSTEM_STATE_SIM_TEST_V1: u64 = 18446744073709551605; // u64::MAX - 10 -#[cfg(msim)] -pub const SUI_SYSTEM_STATE_SIM_TEST_SHALLOW_V2: u64 = 18446744073709551606; // u64::MAX - 9 -#[cfg(msim)] -pub const SUI_SYSTEM_STATE_SIM_TEST_DEEP_V2: u64 = 18446744073709551607; // u64::MAX - 8 - -/// Rust version of the Move sui::sui_system::SuiSystemState type -/// This repreents the object with 0x5 ID. -/// In Rust, this type should be rarely used since it's just a thin -/// wrapper used to access the inner object. -/// Within this module, we use it to determine the current version of the system -/// state inner object type, so that we could deserialize the inner object -/// correctly. Outside of this module, we only use it in genesis snapshot and -/// testing. -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct SuiSystemStateWrapper { - pub id: UID, - pub version: u64, -} - -impl SuiSystemStateWrapper { - pub fn type_() -> StructTag { - StructTag { - address: SUI_SYSTEM_ADDRESS, - name: SUI_SYSTEM_STATE_WRAPPER_STRUCT_NAME.to_owned(), - module: SUI_SYSTEM_MODULE_NAME.to_owned(), - type_params: vec![], - } - } - - /// Advances epoch in safe mode natively in Rust, without involking Move. - /// This ensures that there cannot be any failure from Move and is - /// guaranteed to succeed. Returns the old and new inner system state - /// object. - pub fn advance_epoch_safe_mode( - &self, - params: &AdvanceEpochParams, - object_store: &dyn ObjectStore, - protocol_config: &ProtocolConfig, - ) -> (Object, Object) { - let id = self.id.id.bytes; - let old_field_object = get_dynamic_field_object_from_store(object_store, id, &self.version) - .expect("Dynamic field object of wrapper should always be present in the object store"); - let mut new_field_object = old_field_object.clone(); - let move_object = new_field_object - .data - .try_as_move_mut() - .expect("Dynamic field object must be a Move object"); - match self.version { - 1 => { - Self::advance_epoch_safe_mode_impl::( - move_object, - params, - protocol_config, - ); - } - 2 => { - Self::advance_epoch_safe_mode_impl::( - move_object, - params, - protocol_config, - ); - } - #[cfg(msim)] - SUI_SYSTEM_STATE_SIM_TEST_V1 => { - Self::advance_epoch_safe_mode_impl::( - move_object, - params, - protocol_config, - ); - } - #[cfg(msim)] - SUI_SYSTEM_STATE_SIM_TEST_SHALLOW_V2 => { - Self::advance_epoch_safe_mode_impl::( - move_object, - params, - protocol_config, - ); - } - #[cfg(msim)] - SUI_SYSTEM_STATE_SIM_TEST_DEEP_V2 => { - Self::advance_epoch_safe_mode_impl::( - move_object, - params, - protocol_config, - ); - } - _ => unreachable!(), - } - (old_field_object, new_field_object) - } - - fn advance_epoch_safe_mode_impl( - move_object: &mut MoveObject, - params: &AdvanceEpochParams, - protocol_config: &ProtocolConfig, - ) where - T: Serialize + DeserializeOwned + SuiSystemStateTrait, - { - let mut field: Field = - bcs::from_bytes(move_object.contents()).expect("bcs deserialization should never fail"); - tracing::info!( - "Advance epoch safe mode: current epoch: {}, protocol_version: {}, system_state_version: {}", - field.value.epoch(), - field.value.protocol_version(), - field.value.system_state_version() - ); - field.value.advance_epoch_safe_mode(params); - tracing::info!( - "Safe mode activated. New epoch: {}, protocol_version: {}, system_state_version: {}", - field.value.epoch(), - field.value.protocol_version(), - field.value.system_state_version() - ); - let new_contents = bcs::to_bytes(&field).expect("bcs serialization should never fail"); - move_object - .update_contents(new_contents, protocol_config) - .expect("Update sui system object content cannot fail since it should be small"); - } -} - -/// This is the standard API that all inner system state object type should -/// implement. -#[enum_dispatch] -pub trait SuiSystemStateTrait { - fn epoch(&self) -> u64; - fn reference_gas_price(&self) -> u64; - fn protocol_version(&self) -> u64; - fn system_state_version(&self) -> u64; - fn epoch_start_timestamp_ms(&self) -> u64; - fn epoch_duration_ms(&self) -> u64; - fn safe_mode(&self) -> bool; - fn advance_epoch_safe_mode(&mut self, params: &AdvanceEpochParams); - fn get_current_epoch_committee(&self) -> CommitteeWithNetworkMetadata; - fn get_pending_active_validators( - &self, - object_store: &S, - ) -> Result, SuiError>; - fn into_epoch_start_state(self) -> EpochStartSystemState; - fn into_sui_system_state_summary(self) -> SuiSystemStateSummary; -} - -/// SuiSystemState provides an abstraction over multiple versions of the inner -/// SuiSystemStateInner object. This should be the primary interface to the -/// system state object in Rust. We use enum dispatch to dispatch all methods -/// defined in SuiSystemStateTrait to the actual implementation in the inner -/// types. -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -#[enum_dispatch(SuiSystemStateTrait)] -pub enum SuiSystemState { - V1(SuiSystemStateInnerV1), - V2(SuiSystemStateInnerV2), - #[cfg(msim)] - SimTestV1(SimTestSuiSystemStateInnerV1), - #[cfg(msim)] - SimTestShallowV2(SimTestSuiSystemStateInnerShallowV2), - #[cfg(msim)] - SimTestDeepV2(SimTestSuiSystemStateInnerDeepV2), -} - -/// This is the fixed type used by genesis. -pub type SuiSystemStateInnerGenesis = SuiSystemStateInnerV1; -pub type SuiValidatorGenesis = ValidatorV1; - -impl SuiSystemState { - /// Always return the version that we will be using for genesis. - /// Genesis always uses this version regardless of the current version. - /// Note that since it's possible for the actual genesis of the network to - /// diverge from the genesis of the latest Rust code, it's important - /// that we only use this for tooling purposes. - pub fn into_genesis_version_for_tooling(self) -> SuiSystemStateInnerGenesis { - match self { - SuiSystemState::V1(inner) => inner, - _ => unreachable!(), - } - } - - pub fn version(&self) -> u64 { - self.system_state_version() - } -} - -pub fn get_sui_system_state_wrapper( - object_store: &dyn ObjectStore, -) -> Result { - let wrapper = object_store - .get_object(&SUI_SYSTEM_STATE_OBJECT_ID)? - // Don't panic here on None because object_store is a generic store. - .ok_or_else(|| { - SuiError::SuiSystemStateReadError("SuiSystemStateWrapper object not found".to_owned()) - })?; - let move_object = wrapper.data.try_as_move().ok_or_else(|| { - SuiError::SuiSystemStateReadError( - "SuiSystemStateWrapper object must be a Move object".to_owned(), - ) - })?; - let result = bcs::from_bytes::(move_object.contents()) - .map_err(|err| SuiError::SuiSystemStateReadError(err.to_string()))?; - Ok(result) -} - -pub fn get_sui_system_state(object_store: &dyn ObjectStore) -> Result { - let wrapper = get_sui_system_state_wrapper(object_store)?; - let id = wrapper.id.id.bytes; - match wrapper.version { - 1 => { - let result: SuiSystemStateInnerV1 = - get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err( - |err| { - SuiError::DynamicFieldReadError(format!( - "Failed to load sui system state inner object with ID {:?} and version {:?}: {:?}", - id, wrapper.version, err - )) - }, - )?; - Ok(SuiSystemState::V1(result)) - } - 2 => { - let result: SuiSystemStateInnerV2 = - get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err( - |err| { - SuiError::DynamicFieldReadError(format!( - "Failed to load sui system state inner object with ID {:?} and version {:?}: {:?}", - id, wrapper.version, err - )) - }, - )?; - Ok(SuiSystemState::V2(result)) - } - #[cfg(msim)] - SUI_SYSTEM_STATE_SIM_TEST_V1 => { - let result: SimTestSuiSystemStateInnerV1 = - get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err( - |err| { - SuiError::DynamicFieldReadError(format!( - "Failed to load sui system state inner object with ID {:?} and version {:?}: {:?}", - id, wrapper.version, err - )) - }, - )?; - Ok(SuiSystemState::SimTestV1(result)) - } - #[cfg(msim)] - SUI_SYSTEM_STATE_SIM_TEST_SHALLOW_V2 => { - let result: SimTestSuiSystemStateInnerShallowV2 = - get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err( - |err| { - SuiError::DynamicFieldReadError(format!( - "Failed to load sui system state inner object with ID {:?} and version {:?}: {:?}", - id, wrapper.version, err - )) - }, - )?; - Ok(SuiSystemState::SimTestShallowV2(result)) - } - #[cfg(msim)] - SUI_SYSTEM_STATE_SIM_TEST_DEEP_V2 => { - let result: SimTestSuiSystemStateInnerDeepV2 = - get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err( - |err| { - SuiError::DynamicFieldReadError(format!( - "Failed to load sui system state inner object with ID {:?} and version {:?}: {:?}", - id, wrapper.version, err - )) - }, - )?; - Ok(SuiSystemState::SimTestDeepV2(result)) - } - _ => Err(SuiError::SuiSystemStateReadError(format!( - "Unsupported SuiSystemState version: {}", - wrapper.version - ))), - } -} - -/// Given a system state type version, and the ID of the table, along with a -/// key, retrieve the dynamic field as a Validator type. We need the version to -/// determine which inner type to use for the Validator type. This is assuming -/// that the validator is stored in the table as ValidatorWrapper type. -pub fn get_validator_from_table( - object_store: &dyn ObjectStore, - table_id: ObjectID, - key: &K, -) -> Result -where - K: MoveTypeTagTrait + Serialize + DeserializeOwned + fmt::Debug, -{ - let field: ValidatorWrapper = get_dynamic_field_from_store(object_store, table_id, key) - .map_err(|err| { - SuiError::SuiSystemStateReadError(format!( - "Failed to load validator wrapper from table: {:?}", - err - )) - })?; - let versioned = field.inner; - let version = versioned.version; - match version { - 1 => { - let validator: ValidatorV1 = - get_dynamic_field_from_store(object_store, versioned.id.id.bytes, &version) - .map_err(|err| { - SuiError::SuiSystemStateReadError(format!( - "Failed to load inner validator from the wrapper: {:?}", - err - )) - })?; - Ok(validator.into_sui_validator_summary()) - } - #[cfg(msim)] - SUI_SYSTEM_STATE_SIM_TEST_V1 => { - let validator: SimTestValidatorV1 = - get_dynamic_field_from_store(object_store, versioned.id.id.bytes, &version) - .map_err(|err| { - SuiError::SuiSystemStateReadError(format!( - "Failed to load inner validator from the wrapper: {:?}", - err - )) - })?; - Ok(validator.into_sui_validator_summary()) - } - #[cfg(msim)] - SUI_SYSTEM_STATE_SIM_TEST_DEEP_V2 => { - let validator: SimTestValidatorDeepV2 = - get_dynamic_field_from_store(object_store, versioned.id.id.bytes, &version) - .map_err(|err| { - SuiError::SuiSystemStateReadError(format!( - "Failed to load inner validator from the wrapper: {:?}", - err - )) - })?; - Ok(validator.into_sui_validator_summary()) - } - _ => Err(SuiError::SuiSystemStateReadError(format!( - "Unsupported Validator version: {}", - version - ))), - } -} - -pub fn get_validators_from_table_vec( - object_store: &S, - table_id: ObjectID, - table_size: u64, -) -> Result, SuiError> -where - S: ObjectStore + ?Sized, - ValidatorType: Serialize + DeserializeOwned, -{ - let mut validators = vec![]; - for i in 0..table_size { - let validator: ValidatorType = get_dynamic_field_from_store(&object_store, table_id, &i) - .map_err(|err| { - SuiError::SuiSystemStateReadError(format!( - "Failed to load validator from table: {:?}", - err - )) - })?; - validators.push(validator); - } - Ok(validators) -} - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Default)] -pub struct PoolTokenExchangeRate { - sui_amount: u64, - pool_token_amount: u64, -} - -impl PoolTokenExchangeRate { - /// Rate of the staking pool, pool token amount : Sui amount - pub fn rate(&self) -> f64 { - if self.sui_amount == 0 { - 1_f64 - } else { - self.pool_token_amount as f64 / self.sui_amount as f64 - } - } -} - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct ValidatorWrapper { - pub inner: Versioned, -} - -#[derive(Debug)] -pub struct AdvanceEpochParams { - pub epoch: u64, - pub next_protocol_version: ProtocolVersion, - pub storage_charge: u64, - pub computation_charge: u64, - pub storage_rebate: u64, - pub non_refundable_storage_fee: u64, - pub storage_fund_reinvest_rate: u64, - pub reward_slashing_rate: u64, - pub epoch_start_timestamp_ms: u64, -} - -#[cfg(msim)] -pub mod advance_epoch_result_injection { - use std::cell::RefCell; - - use crate::{ - committee::EpochId, - error::{ExecutionError, ExecutionErrorKind}, - }; - - thread_local! { - /// Override the result of advance_epoch in the range [start, end). - static OVERRIDE: RefCell> = RefCell::new(None); - } - - /// Override the result of advance_epoch transaction if new epoch is in the - /// provided range [start, end). - pub fn set_override(value: Option<(EpochId, EpochId)>) { - OVERRIDE.with(|o| *o.borrow_mut() = value); - } - - /// This function is used to modify the result of advance_epoch transaction - /// for testing. If the override is set, the result will be an execution - /// error, otherwise the original result will be returned. - pub fn maybe_modify_result( - result: Result<(), ExecutionError>, - current_epoch: EpochId, - ) -> Result<(), ExecutionError> { - if let Some((start, end)) = OVERRIDE.with(|o| *o.borrow()) { - if current_epoch >= start && current_epoch < end { - return Err::<(), ExecutionError>(ExecutionError::new( - ExecutionErrorKind::FunctionNotFound, - None, - )); - } - } - result - } -} diff --git a/crates/sui-types/src/sui_system_state/simtest_sui_system_state_inner.rs b/crates/sui-types/src/sui_system_state/simtest_sui_system_state_inner.rs deleted file mode 100644 index dedb55a71a7..00000000000 --- a/crates/sui-types/src/sui_system_state/simtest_sui_system_state_inner.rs +++ /dev/null @@ -1,486 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use fastcrypto::traits::ToFromBytes; -use mysten_network::Multiaddr; -use once_cell::sync::OnceCell; -use serde::{Deserialize, Serialize}; - -use crate::{ - balance::Balance, - base_types::SuiAddress, - collection_types::{Bag, Table}, - committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata}, - crypto::AuthorityPublicKeyBytes, - error::SuiError, - storage::ObjectStore, - sui_system_state::{ - epoch_start_sui_system_state::{EpochStartSystemState, EpochStartValidatorInfoV1}, - sui_system_state_summary::{SuiSystemStateSummary, SuiValidatorSummary}, - AdvanceEpochParams, SuiSystemStateTrait, - }, -}; - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct SimTestSuiSystemStateInnerV1 { - pub epoch: u64, - pub protocol_version: u64, - pub system_state_version: u64, - pub validators: SimTestValidatorSetV1, - pub storage_fund: Balance, - pub parameters: SimTestSystemParametersV1, - pub reference_gas_price: u64, - pub safe_mode: bool, - pub epoch_start_timestamp_ms: u64, - pub extra_fields: Bag, -} - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct SimTestSystemParametersV1 { - pub epoch_duration_ms: u64, - pub extra_fields: Bag, -} - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct SimTestValidatorSetV1 { - pub active_validators: Vec, - pub inactive_validators: Table, - pub extra_fields: Bag, -} - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct SimTestValidatorV1 { - metadata: SimTestValidatorMetadataV1, - #[serde(skip)] - verified_metadata: OnceCell, - pub voting_power: u64, - pub stake: Balance, - pub extra_fields: Bag, -} - -impl SimTestValidatorV1 { - pub fn verified_metadata(&self) -> &VerifiedSimTestValidatorMetadataV1 { - self.verified_metadata - .get_or_init(|| self.metadata.verify()) - } - - pub fn into_sui_validator_summary(self) -> SuiValidatorSummary { - SuiValidatorSummary::default() - } -} - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct SimTestValidatorMetadataV1 { - pub sui_address: SuiAddress, - pub protocol_pubkey_bytes: Vec, - pub network_pubkey_bytes: Vec, - pub worker_pubkey_bytes: Vec, - pub net_address: String, - pub p2p_address: String, - pub primary_address: String, - pub worker_address: String, - pub extra_fields: Bag, -} - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct VerifiedSimTestValidatorMetadataV1 { - pub sui_address: SuiAddress, - pub protocol_pubkey: narwhal_crypto::PublicKey, - pub network_pubkey: narwhal_crypto::NetworkPublicKey, - pub worker_pubkey: narwhal_crypto::NetworkPublicKey, - pub net_address: Multiaddr, - pub p2p_address: Multiaddr, - pub primary_address: Multiaddr, - pub worker_address: Multiaddr, -} - -impl SimTestValidatorMetadataV1 { - pub fn verify(&self) -> VerifiedSimTestValidatorMetadataV1 { - let protocol_pubkey = - narwhal_crypto::PublicKey::from_bytes(self.protocol_pubkey_bytes.as_ref()).unwrap(); - let network_pubkey = - narwhal_crypto::NetworkPublicKey::from_bytes(self.network_pubkey_bytes.as_ref()) - .unwrap(); - let worker_pubkey = - narwhal_crypto::NetworkPublicKey::from_bytes(self.worker_pubkey_bytes.as_ref()) - .unwrap(); - let net_address = Multiaddr::try_from(self.net_address.clone()).unwrap(); - let p2p_address = Multiaddr::try_from(self.p2p_address.clone()).unwrap(); - let primary_address = Multiaddr::try_from(self.primary_address.clone()).unwrap(); - let worker_address = Multiaddr::try_from(self.worker_address.clone()).unwrap(); - VerifiedSimTestValidatorMetadataV1 { - sui_address: self.sui_address, - protocol_pubkey, - network_pubkey, - worker_pubkey, - net_address, - p2p_address, - primary_address, - worker_address, - } - } -} - -impl VerifiedSimTestValidatorMetadataV1 { - pub fn sui_pubkey_bytes(&self) -> AuthorityPublicKeyBytes { - (&self.protocol_pubkey).into() - } -} - -impl SuiSystemStateTrait for SimTestSuiSystemStateInnerV1 { - fn epoch(&self) -> u64 { - self.epoch - } - - fn reference_gas_price(&self) -> u64 { - self.reference_gas_price - } - - fn protocol_version(&self) -> u64 { - self.protocol_version - } - - fn system_state_version(&self) -> u64 { - self.system_state_version - } - - fn epoch_start_timestamp_ms(&self) -> u64 { - self.epoch_start_timestamp_ms - } - - fn epoch_duration_ms(&self) -> u64 { - self.parameters.epoch_duration_ms - } - - fn safe_mode(&self) -> bool { - self.safe_mode - } - - fn advance_epoch_safe_mode(&mut self, params: &AdvanceEpochParams) { - self.epoch = params.epoch; - self.safe_mode = true; - self.epoch_start_timestamp_ms = params.epoch_start_timestamp_ms; - self.protocol_version = params.next_protocol_version.as_u64(); - } - - fn get_current_epoch_committee(&self) -> CommitteeWithNetworkMetadata { - let mut voting_rights = BTreeMap::new(); - let mut network_metadata = BTreeMap::new(); - for validator in &self.validators.active_validators { - let verified_metadata = validator.verified_metadata(); - let name = verified_metadata.sui_pubkey_bytes(); - voting_rights.insert(name, validator.voting_power); - network_metadata.insert( - name, - NetworkMetadata { - network_address: verified_metadata.net_address.clone(), - narwhal_primary_address: verified_metadata.primary_address.clone(), - }, - ); - } - CommitteeWithNetworkMetadata { - committee: Committee::new(self.epoch, voting_rights), - network_metadata, - } - } - - fn get_pending_active_validators( - &self, - _object_store: &S, - ) -> Result, SuiError> { - Ok(vec![]) - } - - fn into_epoch_start_state(self) -> EpochStartSystemState { - EpochStartSystemState::new_v1( - self.epoch, - self.protocol_version, - self.reference_gas_price, - self.safe_mode, - self.epoch_start_timestamp_ms, - self.parameters.epoch_duration_ms, - self.validators - .active_validators - .iter() - .map(|validator| { - let metadata = validator.verified_metadata(); - EpochStartValidatorInfoV1 { - sui_address: metadata.sui_address, - protocol_pubkey: metadata.protocol_pubkey.clone(), - narwhal_network_pubkey: metadata.network_pubkey.clone(), - narwhal_worker_pubkey: metadata.worker_pubkey.clone(), - sui_net_address: metadata.net_address.clone(), - p2p_address: metadata.p2p_address.clone(), - narwhal_primary_address: metadata.primary_address.clone(), - narwhal_worker_address: metadata.worker_address.clone(), - voting_power: validator.voting_power, - hostname: "".to_string(), - } - }) - .collect(), - ) - } - - fn into_sui_system_state_summary(self) -> SuiSystemStateSummary { - SuiSystemStateSummary::default() - } -} - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct SimTestSuiSystemStateInnerShallowV2 { - pub new_dummy_field: u64, - pub epoch: u64, - pub protocol_version: u64, - pub system_state_version: u64, - pub validators: SimTestValidatorSetV1, - pub storage_fund: Balance, - pub parameters: SimTestSystemParametersV1, - pub reference_gas_price: u64, - pub safe_mode: bool, - pub epoch_start_timestamp_ms: u64, - pub extra_fields: Bag, -} - -impl SuiSystemStateTrait for SimTestSuiSystemStateInnerShallowV2 { - fn epoch(&self) -> u64 { - self.epoch - } - - fn reference_gas_price(&self) -> u64 { - self.reference_gas_price - } - - fn protocol_version(&self) -> u64 { - self.protocol_version - } - - fn system_state_version(&self) -> u64 { - self.system_state_version - } - - fn epoch_start_timestamp_ms(&self) -> u64 { - self.epoch_start_timestamp_ms - } - - fn epoch_duration_ms(&self) -> u64 { - self.parameters.epoch_duration_ms - } - - fn safe_mode(&self) -> bool { - self.safe_mode - } - - fn advance_epoch_safe_mode(&mut self, params: &AdvanceEpochParams) { - self.epoch = params.epoch; - self.safe_mode = true; - self.epoch_start_timestamp_ms = params.epoch_start_timestamp_ms; - self.protocol_version = params.next_protocol_version.as_u64(); - } - - fn get_current_epoch_committee(&self) -> CommitteeWithNetworkMetadata { - let mut voting_rights = BTreeMap::new(); - let mut network_metadata = BTreeMap::new(); - for validator in &self.validators.active_validators { - let verified_metadata = validator.verified_metadata(); - let name = verified_metadata.sui_pubkey_bytes(); - voting_rights.insert(name, validator.voting_power); - network_metadata.insert( - name, - NetworkMetadata { - network_address: verified_metadata.net_address.clone(), - narwhal_primary_address: verified_metadata.primary_address.clone(), - }, - ); - } - CommitteeWithNetworkMetadata { - committee: Committee::new(self.epoch, voting_rights), - network_metadata, - } - } - - fn get_pending_active_validators( - &self, - _object_store: &S, - ) -> Result, SuiError> { - Ok(vec![]) - } - - fn into_epoch_start_state(self) -> EpochStartSystemState { - EpochStartSystemState::new_v1( - self.epoch, - self.protocol_version, - self.reference_gas_price, - self.safe_mode, - self.epoch_start_timestamp_ms, - self.parameters.epoch_duration_ms, - self.validators - .active_validators - .iter() - .map(|validator| { - let metadata = validator.verified_metadata(); - EpochStartValidatorInfoV1 { - sui_address: metadata.sui_address, - protocol_pubkey: metadata.protocol_pubkey.clone(), - narwhal_network_pubkey: metadata.network_pubkey.clone(), - narwhal_worker_pubkey: metadata.worker_pubkey.clone(), - sui_net_address: metadata.net_address.clone(), - p2p_address: metadata.p2p_address.clone(), - narwhal_primary_address: metadata.primary_address.clone(), - narwhal_worker_address: metadata.worker_address.clone(), - voting_power: validator.voting_power, - hostname: "".to_string(), - } - }) - .collect(), - ) - } - - fn into_sui_system_state_summary(self) -> SuiSystemStateSummary { - SuiSystemStateSummary::default() - } -} - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct SimTestValidatorSetDeepV2 { - pub active_validators: Vec, - pub inactive_validators: Table, - pub extra_fields: Bag, -} - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct SimTestValidatorDeepV2 { - pub new_dummy_field: u64, - metadata: SimTestValidatorMetadataV1, - #[serde(skip)] - verified_metadata: OnceCell, - pub voting_power: u64, - pub stake: Balance, - pub extra_fields: Bag, -} - -impl SimTestValidatorDeepV2 { - pub fn verified_metadata(&self) -> &VerifiedSimTestValidatorMetadataV1 { - self.verified_metadata - .get_or_init(|| self.metadata.verify()) - } - - pub fn into_sui_validator_summary(self) -> SuiValidatorSummary { - SuiValidatorSummary::default() - } -} - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct SimTestSuiSystemStateInnerDeepV2 { - pub new_dummy_field: u64, - pub epoch: u64, - pub protocol_version: u64, - pub system_state_version: u64, - pub validators: SimTestValidatorSetDeepV2, - pub storage_fund: Balance, - pub parameters: SimTestSystemParametersV1, - pub reference_gas_price: u64, - pub safe_mode: bool, - pub epoch_start_timestamp_ms: u64, - pub extra_fields: Bag, -} - -impl SuiSystemStateTrait for SimTestSuiSystemStateInnerDeepV2 { - fn epoch(&self) -> u64 { - self.epoch - } - - fn reference_gas_price(&self) -> u64 { - self.reference_gas_price - } - - fn protocol_version(&self) -> u64 { - self.protocol_version - } - - fn system_state_version(&self) -> u64 { - self.system_state_version - } - - fn epoch_start_timestamp_ms(&self) -> u64 { - self.epoch_start_timestamp_ms - } - - fn epoch_duration_ms(&self) -> u64 { - self.parameters.epoch_duration_ms - } - - fn safe_mode(&self) -> bool { - self.safe_mode - } - - fn advance_epoch_safe_mode(&mut self, params: &AdvanceEpochParams) { - self.epoch = params.epoch; - self.safe_mode = true; - self.epoch_start_timestamp_ms = params.epoch_start_timestamp_ms; - self.protocol_version = params.next_protocol_version.as_u64(); - } - - fn get_current_epoch_committee(&self) -> CommitteeWithNetworkMetadata { - let mut voting_rights = BTreeMap::new(); - let mut network_metadata = BTreeMap::new(); - for validator in &self.validators.active_validators { - let verified_metadata = validator.verified_metadata(); - let name = verified_metadata.sui_pubkey_bytes(); - voting_rights.insert(name, validator.voting_power); - network_metadata.insert( - name, - NetworkMetadata { - network_address: verified_metadata.net_address.clone(), - narwhal_primary_address: verified_metadata.primary_address.clone(), - }, - ); - } - CommitteeWithNetworkMetadata { - committee: Committee::new(self.epoch, voting_rights), - network_metadata, - } - } - - fn get_pending_active_validators( - &self, - _object_store: &S, - ) -> Result, SuiError> { - Ok(vec![]) - } - - fn into_epoch_start_state(self) -> EpochStartSystemState { - EpochStartSystemState::new_v1( - self.epoch, - self.protocol_version, - self.reference_gas_price, - self.safe_mode, - self.epoch_start_timestamp_ms, - self.parameters.epoch_duration_ms, - self.validators - .active_validators - .iter() - .map(|validator| { - let metadata = validator.verified_metadata(); - EpochStartValidatorInfoV1 { - sui_address: metadata.sui_address, - protocol_pubkey: metadata.protocol_pubkey.clone(), - narwhal_network_pubkey: metadata.network_pubkey.clone(), - narwhal_worker_pubkey: metadata.worker_pubkey.clone(), - sui_net_address: metadata.net_address.clone(), - p2p_address: metadata.p2p_address.clone(), - narwhal_primary_address: metadata.primary_address.clone(), - narwhal_worker_address: metadata.worker_address.clone(), - voting_power: validator.voting_power, - hostname: "".to_string(), - } - }) - .collect(), - ) - } - - fn into_sui_system_state_summary(self) -> SuiSystemStateSummary { - SuiSystemStateSummary::default() - } -} diff --git a/crates/sui-types/src/sui_system_state/sui_system_state_inner_v1.rs b/crates/sui-types/src/sui_system_state/sui_system_state_inner_v1.rs deleted file mode 100644 index 08c991e89ea..00000000000 --- a/crates/sui-types/src/sui_system_state/sui_system_state_inner_v1.rs +++ /dev/null @@ -1,755 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use anyhow::Result; -use fastcrypto::traits::ToFromBytes; -use once_cell::sync::OnceCell; -use serde::{Deserialize, Serialize}; - -use super::{ - epoch_start_sui_system_state::EpochStartValidatorInfoV1, - get_validators_from_table_vec, - sui_system_state_summary::{SuiSystemStateSummary, SuiValidatorSummary}, - AdvanceEpochParams, SuiSystemStateTrait, -}; -use crate::{ - balance::Balance, - base_types::{ObjectID, SuiAddress}, - collection_types::{Bag, Table, TableVec, VecMap, VecSet}, - committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata}, - crypto::{verify_proof_of_possession, AuthorityPublicKeyBytes}, - error::SuiError, - id::ID, - multiaddr::Multiaddr, - storage::ObjectStore, - sui_system_state::epoch_start_sui_system_state::EpochStartSystemState, -}; - -const E_METADATA_INVALID_POP: u64 = 0; -const E_METADATA_INVALID_PUBKEY: u64 = 1; -const E_METADATA_INVALID_NET_PUBKEY: u64 = 2; -const E_METADATA_INVALID_WORKER_PUBKEY: u64 = 3; -const E_METADATA_INVALID_NET_ADDR: u64 = 4; -const E_METADATA_INVALID_P2P_ADDR: u64 = 5; -const E_METADATA_INVALID_PRIMARY_ADDR: u64 = 6; -const E_METADATA_INVALID_WORKER_ADDR: u64 = 7; - -/// Rust version of the Move sui::sui_system::SystemParameters type -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct SystemParametersV1 { - /// The duration of an epoch, in milliseconds. - pub epoch_duration_ms: u64, - - /// The starting epoch in which stake subsidies start being paid out - pub stake_subsidy_start_epoch: u64, - - /// Maximum number of active validators at any moment. - /// We do not allow the number of validators in any epoch to go above this. - pub max_validator_count: u64, - - /// Lower-bound on the amount of stake required to become a validator. - pub min_validator_joining_stake: u64, - - /// Validators with stake amount below `validator_low_stake_threshold` are - /// considered to have low stake and will be escorted out of the - /// validator set after being below this threshold for more than - /// `validator_low_stake_grace_period` number of epochs. - pub validator_low_stake_threshold: u64, - - /// Validators with stake below `validator_very_low_stake_threshold` will be - /// removed immediately at epoch change, no grace period. - pub validator_very_low_stake_threshold: u64, - - /// A validator can have stake below `validator_low_stake_threshold` - /// for this many epochs before being kicked out. - pub validator_low_stake_grace_period: u64, - - pub extra_fields: Bag, -} - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct ValidatorMetadataV1 { - pub sui_address: SuiAddress, - pub protocol_pubkey_bytes: Vec, - pub network_pubkey_bytes: Vec, - pub worker_pubkey_bytes: Vec, - pub proof_of_possession_bytes: Vec, - pub name: String, - pub description: String, - pub image_url: String, - pub project_url: String, - pub net_address: String, - pub p2p_address: String, - pub primary_address: String, - pub worker_address: String, - pub next_epoch_protocol_pubkey_bytes: Option>, - pub next_epoch_proof_of_possession: Option>, - pub next_epoch_network_pubkey_bytes: Option>, - pub next_epoch_worker_pubkey_bytes: Option>, - pub next_epoch_net_address: Option, - pub next_epoch_p2p_address: Option, - pub next_epoch_primary_address: Option, - pub next_epoch_worker_address: Option, - pub extra_fields: Bag, -} - -#[derive(derivative::Derivative, Clone, Eq, PartialEq)] -#[derivative(Debug)] -pub struct VerifiedValidatorMetadataV1 { - pub sui_address: SuiAddress, - pub protocol_pubkey: narwhal_crypto::PublicKey, - pub network_pubkey: narwhal_crypto::NetworkPublicKey, - pub worker_pubkey: narwhal_crypto::NetworkPublicKey, - #[derivative(Debug = "ignore")] - pub proof_of_possession_bytes: Vec, - pub name: String, - pub description: String, - pub image_url: String, - pub project_url: String, - pub net_address: Multiaddr, - pub p2p_address: Multiaddr, - pub primary_address: Multiaddr, - pub worker_address: Multiaddr, - pub next_epoch_protocol_pubkey: Option, - pub next_epoch_proof_of_possession: Option>, - pub next_epoch_network_pubkey: Option, - pub next_epoch_worker_pubkey: Option, - pub next_epoch_net_address: Option, - pub next_epoch_p2p_address: Option, - pub next_epoch_primary_address: Option, - pub next_epoch_worker_address: Option, -} - -impl VerifiedValidatorMetadataV1 { - pub fn sui_pubkey_bytes(&self) -> AuthorityPublicKeyBytes { - (&self.protocol_pubkey).into() - } -} - -impl ValidatorMetadataV1 { - /// Verify validator metadata and return a verified version (on success) or - /// error code (on failure) - pub fn verify(&self) -> Result { - let protocol_pubkey = - narwhal_crypto::PublicKey::from_bytes(self.protocol_pubkey_bytes.as_ref()) - .map_err(|_| E_METADATA_INVALID_PUBKEY)?; - - // Verify proof of possession for the protocol key - let pop = narwhal_crypto::Signature::from_bytes(self.proof_of_possession_bytes.as_ref()) - .map_err(|_| E_METADATA_INVALID_POP)?; - verify_proof_of_possession(&pop, &protocol_pubkey, self.sui_address) - .map_err(|_| E_METADATA_INVALID_POP)?; - - let network_pubkey = - narwhal_crypto::NetworkPublicKey::from_bytes(self.network_pubkey_bytes.as_ref()) - .map_err(|_| E_METADATA_INVALID_NET_PUBKEY)?; - let worker_pubkey = - narwhal_crypto::NetworkPublicKey::from_bytes(self.worker_pubkey_bytes.as_ref()) - .map_err(|_| E_METADATA_INVALID_WORKER_PUBKEY)?; - if worker_pubkey == network_pubkey { - return Err(E_METADATA_INVALID_WORKER_PUBKEY); - } - - let net_address = Multiaddr::try_from(self.net_address.clone()) - .map_err(|_| E_METADATA_INVALID_NET_ADDR)?; - - // Ensure p2p, primary, and worker addresses are both Multiaddr's and valid - // anemo addresses - let p2p_address = Multiaddr::try_from(self.p2p_address.clone()) - .map_err(|_| E_METADATA_INVALID_P2P_ADDR)?; - p2p_address - .to_anemo_address() - .map_err(|_| E_METADATA_INVALID_P2P_ADDR)?; - - let primary_address = Multiaddr::try_from(self.primary_address.clone()) - .map_err(|_| E_METADATA_INVALID_PRIMARY_ADDR)?; - primary_address - .to_anemo_address() - .map_err(|_| E_METADATA_INVALID_PRIMARY_ADDR)?; - - let worker_address = Multiaddr::try_from(self.worker_address.clone()) - .map_err(|_| E_METADATA_INVALID_WORKER_ADDR)?; - worker_address - .to_anemo_address() - .map_err(|_| E_METADATA_INVALID_WORKER_ADDR)?; - - let next_epoch_protocol_pubkey = match self.next_epoch_protocol_pubkey_bytes.clone() { - None => Ok::, u64>(None), - Some(bytes) => Ok(Some( - narwhal_crypto::PublicKey::from_bytes(bytes.as_ref()) - .map_err(|_| E_METADATA_INVALID_PUBKEY)?, - )), - }?; - - let next_epoch_pop = match self.next_epoch_proof_of_possession.clone() { - None => Ok::, u64>(None), - Some(bytes) => Ok(Some( - narwhal_crypto::Signature::from_bytes(bytes.as_ref()) - .map_err(|_| E_METADATA_INVALID_POP)?, - )), - }?; - // Verify proof of possession for the next epoch protocol key - if let Some(ref next_epoch_protocol_pubkey) = next_epoch_protocol_pubkey { - match next_epoch_pop { - Some(next_epoch_pop) => { - verify_proof_of_possession( - &next_epoch_pop, - next_epoch_protocol_pubkey, - self.sui_address, - ) - .map_err(|_| E_METADATA_INVALID_POP)?; - } - None => { - return Err(E_METADATA_INVALID_POP); - } - } - } - - let next_epoch_network_pubkey = match self.next_epoch_network_pubkey_bytes.clone() { - None => Ok::, u64>(None), - Some(bytes) => Ok(Some( - narwhal_crypto::NetworkPublicKey::from_bytes(bytes.as_ref()) - .map_err(|_| E_METADATA_INVALID_NET_PUBKEY)?, - )), - }?; - - let next_epoch_worker_pubkey: Option = - match self.next_epoch_worker_pubkey_bytes.clone() { - None => Ok::, u64>(None), - Some(bytes) => Ok(Some( - narwhal_crypto::NetworkPublicKey::from_bytes(bytes.as_ref()) - .map_err(|_| E_METADATA_INVALID_WORKER_PUBKEY)?, - )), - }?; - if next_epoch_network_pubkey.is_some() - && next_epoch_network_pubkey == next_epoch_worker_pubkey - { - return Err(E_METADATA_INVALID_WORKER_PUBKEY); - } - - let next_epoch_net_address = match self.next_epoch_net_address.clone() { - None => Ok::, u64>(None), - Some(address) => Ok(Some( - Multiaddr::try_from(address).map_err(|_| E_METADATA_INVALID_NET_ADDR)?, - )), - }?; - - let next_epoch_p2p_address = match self.next_epoch_p2p_address.clone() { - None => Ok::, u64>(None), - Some(address) => { - let address = - Multiaddr::try_from(address).map_err(|_| E_METADATA_INVALID_P2P_ADDR)?; - address - .to_anemo_address() - .map_err(|_| E_METADATA_INVALID_P2P_ADDR)?; - - Ok(Some(address)) - } - }?; - - let next_epoch_primary_address = match self.next_epoch_primary_address.clone() { - None => Ok::, u64>(None), - Some(address) => { - let address = - Multiaddr::try_from(address).map_err(|_| E_METADATA_INVALID_PRIMARY_ADDR)?; - address - .to_anemo_address() - .map_err(|_| E_METADATA_INVALID_PRIMARY_ADDR)?; - - Ok(Some(address)) - } - }?; - - let next_epoch_worker_address = match self.next_epoch_worker_address.clone() { - None => Ok::, u64>(None), - Some(address) => { - let address = - Multiaddr::try_from(address).map_err(|_| E_METADATA_INVALID_WORKER_ADDR)?; - address - .to_anemo_address() - .map_err(|_| E_METADATA_INVALID_WORKER_ADDR)?; - - Ok(Some(address)) - } - }?; - - Ok(VerifiedValidatorMetadataV1 { - sui_address: self.sui_address, - protocol_pubkey, - network_pubkey, - worker_pubkey, - proof_of_possession_bytes: self.proof_of_possession_bytes.clone(), - name: self.name.clone(), - description: self.description.clone(), - image_url: self.image_url.clone(), - project_url: self.project_url.clone(), - net_address, - p2p_address, - primary_address, - worker_address, - next_epoch_protocol_pubkey, - next_epoch_proof_of_possession: self.next_epoch_proof_of_possession.clone(), - next_epoch_network_pubkey, - next_epoch_worker_pubkey, - next_epoch_net_address, - next_epoch_p2p_address, - next_epoch_primary_address, - next_epoch_worker_address, - }) - } -} - -/// Rust version of the Move sui::validator::Validator type -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct ValidatorV1 { - metadata: ValidatorMetadataV1, - #[serde(skip)] - verified_metadata: OnceCell, - - pub voting_power: u64, - pub operation_cap_id: ID, - pub gas_price: u64, - pub staking_pool: StakingPoolV1, - pub commission_rate: u64, - pub next_epoch_stake: u64, - pub next_epoch_gas_price: u64, - pub next_epoch_commission_rate: u64, - pub extra_fields: Bag, -} - -impl ValidatorV1 { - pub fn verified_metadata(&self) -> &VerifiedValidatorMetadataV1 { - self.verified_metadata.get_or_init(|| { - self.metadata - .verify() - .expect("Validity of metadata should be verified on-chain") - }) - } - - pub fn into_sui_validator_summary(self) -> SuiValidatorSummary { - let Self { - metadata: - ValidatorMetadataV1 { - sui_address, - protocol_pubkey_bytes, - network_pubkey_bytes, - worker_pubkey_bytes, - proof_of_possession_bytes, - name, - description, - image_url, - project_url, - net_address, - p2p_address, - primary_address, - worker_address, - next_epoch_protocol_pubkey_bytes, - next_epoch_proof_of_possession, - next_epoch_network_pubkey_bytes, - next_epoch_worker_pubkey_bytes, - next_epoch_net_address, - next_epoch_p2p_address, - next_epoch_primary_address, - next_epoch_worker_address, - extra_fields: _, - }, - verified_metadata: _, - voting_power, - operation_cap_id, - gas_price, - staking_pool: - StakingPoolV1 { - id: staking_pool_id, - activation_epoch: staking_pool_activation_epoch, - deactivation_epoch: staking_pool_deactivation_epoch, - sui_balance: staking_pool_sui_balance, - rewards_pool, - pool_token_balance, - exchange_rates: - Table { - id: exchange_rates_id, - size: exchange_rates_size, - }, - pending_stake, - pending_total_sui_withdraw, - pending_pool_token_withdraw, - extra_fields: _, - }, - commission_rate, - next_epoch_stake, - next_epoch_gas_price, - next_epoch_commission_rate, - extra_fields: _, - } = self; - SuiValidatorSummary { - sui_address, - protocol_pubkey_bytes, - network_pubkey_bytes, - worker_pubkey_bytes, - proof_of_possession_bytes, - name, - description, - image_url, - project_url, - net_address, - p2p_address, - primary_address, - worker_address, - next_epoch_protocol_pubkey_bytes, - next_epoch_proof_of_possession, - next_epoch_network_pubkey_bytes, - next_epoch_worker_pubkey_bytes, - next_epoch_net_address, - next_epoch_p2p_address, - next_epoch_primary_address, - next_epoch_worker_address, - voting_power, - operation_cap_id: operation_cap_id.bytes, - gas_price, - staking_pool_id, - staking_pool_activation_epoch, - staking_pool_deactivation_epoch, - staking_pool_sui_balance, - rewards_pool: rewards_pool.value(), - pool_token_balance, - exchange_rates_id, - exchange_rates_size, - pending_stake, - pending_total_sui_withdraw, - pending_pool_token_withdraw, - commission_rate, - next_epoch_stake, - next_epoch_gas_price, - next_epoch_commission_rate, - } - } -} - -/// Rust version of the Move sui_system::staking_pool::StakingPool type -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct StakingPoolV1 { - pub id: ObjectID, - pub activation_epoch: Option, - pub deactivation_epoch: Option, - pub sui_balance: u64, - pub rewards_pool: Balance, - pub pool_token_balance: u64, - pub exchange_rates: Table, - pub pending_stake: u64, - pub pending_total_sui_withdraw: u64, - pub pending_pool_token_withdraw: u64, - pub extra_fields: Bag, -} - -/// Rust version of the Move sui_system::validator_set::ValidatorSet type -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct ValidatorSetV1 { - pub total_stake: u64, - pub active_validators: Vec, - pub pending_active_validators: TableVec, - pub pending_removals: Vec, - pub staking_pool_mappings: Table, - pub inactive_validators: Table, - pub validator_candidates: Table, - pub at_risk_validators: VecMap, - pub extra_fields: Bag, -} - -/// Rust version of the Move sui_system::storage_fund::StorageFund type -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct StorageFundV1 { - pub total_object_storage_rebates: Balance, - pub non_refundable_balance: Balance, -} - -/// Rust version of the Move sui_system::sui_system::SuiSystemStateInner type -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct SuiSystemStateInnerV1 { - pub epoch: u64, - pub protocol_version: u64, - pub system_state_version: u64, - pub validators: ValidatorSetV1, - pub storage_fund: StorageFundV1, - pub parameters: SystemParametersV1, - pub reference_gas_price: u64, - pub validator_report_records: VecMap>, - pub stake_subsidy: StakeSubsidyV1, - pub safe_mode: bool, - pub safe_mode_storage_rewards: Balance, - pub safe_mode_computation_rewards: Balance, - pub safe_mode_storage_rebates: u64, - pub safe_mode_non_refundable_storage_fee: u64, - pub epoch_start_timestamp_ms: u64, - pub extra_fields: Bag, - // TODO: Use getters instead of all pub. -} - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct StakeSubsidyV1 { - /// Balance of SUI set aside for stake subsidies that will be drawn down - /// over time. - pub balance: Balance, - - /// Count of the number of times stake subsidies have been distributed. - pub distribution_counter: u64, - - /// The amount of stake subsidy to be drawn down per distribution. - /// This amount decays and decreases over time. - pub current_distribution_amount: u64, - - /// Number of distributions to occur before the distribution amount decays. - pub stake_subsidy_period_length: u64, - - /// The rate at which the distribution amount decays at the end of each - /// period. Expressed in basis points. - pub stake_subsidy_decrease_rate: u16, - - pub extra_fields: Bag, -} - -impl SuiSystemStateTrait for SuiSystemStateInnerV1 { - fn epoch(&self) -> u64 { - self.epoch - } - - fn reference_gas_price(&self) -> u64 { - self.reference_gas_price - } - - fn protocol_version(&self) -> u64 { - self.protocol_version - } - - fn system_state_version(&self) -> u64 { - self.system_state_version - } - - fn epoch_start_timestamp_ms(&self) -> u64 { - self.epoch_start_timestamp_ms - } - - fn epoch_duration_ms(&self) -> u64 { - self.parameters.epoch_duration_ms - } - - fn safe_mode(&self) -> bool { - self.safe_mode - } - - fn advance_epoch_safe_mode(&mut self, params: &AdvanceEpochParams) { - self.epoch = params.epoch; - self.safe_mode = true; - self.safe_mode_storage_rewards - .deposit_for_safe_mode(params.storage_charge); - self.safe_mode_storage_rebates += params.storage_rebate; - self.safe_mode_computation_rewards - .deposit_for_safe_mode(params.computation_charge); - self.safe_mode_non_refundable_storage_fee += params.non_refundable_storage_fee; - self.epoch_start_timestamp_ms = params.epoch_start_timestamp_ms; - self.protocol_version = params.next_protocol_version.as_u64(); - } - - fn get_current_epoch_committee(&self) -> CommitteeWithNetworkMetadata { - let mut voting_rights = BTreeMap::new(); - let mut network_metadata = BTreeMap::new(); - for validator in &self.validators.active_validators { - let verified_metadata = validator.verified_metadata(); - let name = verified_metadata.sui_pubkey_bytes(); - voting_rights.insert(name, validator.voting_power); - network_metadata.insert( - name, - NetworkMetadata { - network_address: verified_metadata.net_address.clone(), - narwhal_primary_address: verified_metadata.primary_address.clone(), - }, - ); - } - CommitteeWithNetworkMetadata { - committee: Committee::new(self.epoch, voting_rights), - network_metadata, - } - } - - fn get_pending_active_validators( - &self, - object_store: &S, - ) -> Result, SuiError> { - let table_id = self.validators.pending_active_validators.contents.id; - let table_size = self.validators.pending_active_validators.contents.size; - let validators: Vec = - get_validators_from_table_vec(object_store, table_id, table_size)?; - Ok(validators - .into_iter() - .map(|v| v.into_sui_validator_summary()) - .collect()) - } - - fn into_epoch_start_state(self) -> EpochStartSystemState { - EpochStartSystemState::new_v1( - self.epoch, - self.protocol_version, - self.reference_gas_price, - self.safe_mode, - self.epoch_start_timestamp_ms, - self.parameters.epoch_duration_ms, - self.validators - .active_validators - .iter() - .map(|validator| { - let metadata = validator.verified_metadata(); - EpochStartValidatorInfoV1 { - sui_address: metadata.sui_address, - protocol_pubkey: metadata.protocol_pubkey.clone(), - narwhal_network_pubkey: metadata.network_pubkey.clone(), - narwhal_worker_pubkey: metadata.worker_pubkey.clone(), - sui_net_address: metadata.net_address.clone(), - p2p_address: metadata.p2p_address.clone(), - narwhal_primary_address: metadata.primary_address.clone(), - narwhal_worker_address: metadata.worker_address.clone(), - voting_power: validator.voting_power, - hostname: metadata.name.clone(), - } - }) - .collect(), - ) - } - - fn into_sui_system_state_summary(self) -> SuiSystemStateSummary { - // If you are making any changes to SuiSystemStateV1 or any of its dependent - // types before mainnet, please also update SuiSystemStateSummary and - // its corresponding TS type. Post-mainnet, we will need to introduce a - // new version. - let Self { - epoch, - protocol_version, - system_state_version, - validators: - ValidatorSetV1 { - total_stake, - active_validators, - pending_active_validators: - TableVec { - contents: - Table { - id: pending_active_validators_id, - size: pending_active_validators_size, - }, - }, - pending_removals, - staking_pool_mappings: - Table { - id: staking_pool_mappings_id, - size: staking_pool_mappings_size, - }, - inactive_validators: - Table { - id: inactive_pools_id, - size: inactive_pools_size, - }, - validator_candidates: - Table { - id: validator_candidates_id, - size: validator_candidates_size, - }, - at_risk_validators: - VecMap { - contents: at_risk_validators, - }, - extra_fields: _, - }, - storage_fund, - parameters: - SystemParametersV1 { - stake_subsidy_start_epoch, - epoch_duration_ms, - max_validator_count, - min_validator_joining_stake, - validator_low_stake_threshold, - validator_very_low_stake_threshold, - validator_low_stake_grace_period, - extra_fields: _, - }, - reference_gas_price, - validator_report_records: - VecMap { - contents: validator_report_records, - }, - stake_subsidy: - StakeSubsidyV1 { - balance: stake_subsidy_balance, - distribution_counter: stake_subsidy_distribution_counter, - current_distribution_amount: stake_subsidy_current_distribution_amount, - stake_subsidy_period_length, - stake_subsidy_decrease_rate, - extra_fields: _, - }, - safe_mode, - safe_mode_storage_rewards, - safe_mode_computation_rewards, - safe_mode_storage_rebates, - safe_mode_non_refundable_storage_fee, - epoch_start_timestamp_ms, - extra_fields: _, - } = self; - SuiSystemStateSummary { - epoch, - protocol_version, - system_state_version, - storage_fund_total_object_storage_rebates: storage_fund - .total_object_storage_rebates - .value(), - storage_fund_non_refundable_balance: storage_fund.non_refundable_balance.value(), - reference_gas_price, - safe_mode, - safe_mode_storage_rewards: safe_mode_storage_rewards.value(), - safe_mode_computation_rewards: safe_mode_computation_rewards.value(), - safe_mode_storage_rebates, - safe_mode_non_refundable_storage_fee, - epoch_start_timestamp_ms, - stake_subsidy_start_epoch, - epoch_duration_ms, - stake_subsidy_distribution_counter, - stake_subsidy_balance: stake_subsidy_balance.value(), - stake_subsidy_current_distribution_amount, - total_stake, - active_validators: active_validators - .into_iter() - .map(|v| v.into_sui_validator_summary()) - .collect(), - pending_active_validators_id, - pending_active_validators_size, - pending_removals, - staking_pool_mappings_id, - staking_pool_mappings_size, - inactive_pools_id, - inactive_pools_size, - validator_candidates_id, - validator_candidates_size, - at_risk_validators: at_risk_validators - .into_iter() - .map(|e| (e.key, e.value)) - .collect(), - validator_report_records: validator_report_records - .into_iter() - .map(|e| (e.key, e.value.contents)) - .collect(), - max_validator_count, - min_validator_joining_stake, - validator_low_stake_threshold, - validator_very_low_stake_threshold, - validator_low_stake_grace_period, - stake_subsidy_period_length, - stake_subsidy_decrease_rate, - } - } -} - -/// Rust version of the Move -/// sui_system::validator_cap::UnverifiedValidatorOperationCap type -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct UnverifiedValidatorOperationCapV1 { - pub id: ObjectID, - pub authorizer_validator_address: SuiAddress, -} diff --git a/crates/sui-types/src/sui_system_state/sui_system_state_inner_v2.rs b/crates/sui-types/src/sui_system_state/sui_system_state_inner_v2.rs deleted file mode 100644 index fb8f0fd4bc8..00000000000 --- a/crates/sui-types/src/sui_system_state/sui_system_state_inner_v2.rs +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use serde::{Deserialize, Serialize}; - -use super::{ - epoch_start_sui_system_state::EpochStartValidatorInfoV1, - sui_system_state_inner_v1::ValidatorV1, - sui_system_state_summary::{SuiSystemStateSummary, SuiValidatorSummary}, - AdvanceEpochParams, SuiSystemStateTrait, -}; -use crate::{ - balance::Balance, - base_types::SuiAddress, - collection_types::{Bag, Table, TableVec, VecMap, VecSet}, - committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata}, - error::SuiError, - storage::ObjectStore, - sui_system_state::{ - epoch_start_sui_system_state::EpochStartSystemState, - get_validators_from_table_vec, - sui_system_state_inner_v1::{StakeSubsidyV1, StorageFundV1, ValidatorSetV1}, - }, -}; - -/// Rust version of the Move sui::sui_system::SystemParametersV2 type -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct SystemParametersV2 { - /// The duration of an epoch, in milliseconds. - pub epoch_duration_ms: u64, - - /// The starting epoch in which stake subsidies start being paid out - pub stake_subsidy_start_epoch: u64, - - /// Minimum number of active validators at any moment. - pub min_validator_count: u64, - - /// Maximum number of active validators at any moment. - /// We do not allow the number of validators in any epoch to go above this. - pub max_validator_count: u64, - - /// Lower-bound on the amount of stake required to become a validator. - pub min_validator_joining_stake: u64, - - /// Validators with stake amount below `validator_low_stake_threshold` are - /// considered to have low stake and will be escorted out of the - /// validator set after being below this threshold for more than - /// `validator_low_stake_grace_period` number of epochs. - pub validator_low_stake_threshold: u64, - - /// Validators with stake below `validator_very_low_stake_threshold` will be - /// removed immediately at epoch change, no grace period. - pub validator_very_low_stake_threshold: u64, - - /// A validator can have stake below `validator_low_stake_threshold` - /// for this many epochs before being kicked out. - pub validator_low_stake_grace_period: u64, - - pub extra_fields: Bag, -} - -/// Rust version of the Move sui_system::sui_system::SuiSystemStateInnerV2 type -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct SuiSystemStateInnerV2 { - pub epoch: u64, - pub protocol_version: u64, - pub system_state_version: u64, - pub validators: ValidatorSetV1, - pub storage_fund: StorageFundV1, - pub parameters: SystemParametersV2, - pub reference_gas_price: u64, - pub validator_report_records: VecMap>, - pub stake_subsidy: StakeSubsidyV1, - pub safe_mode: bool, - pub safe_mode_storage_rewards: Balance, - pub safe_mode_computation_rewards: Balance, - pub safe_mode_storage_rebates: u64, - pub safe_mode_non_refundable_storage_fee: u64, - pub epoch_start_timestamp_ms: u64, - pub extra_fields: Bag, - // TODO: Use getters instead of all pub. -} - -impl SuiSystemStateTrait for SuiSystemStateInnerV2 { - fn epoch(&self) -> u64 { - self.epoch - } - - fn reference_gas_price(&self) -> u64 { - self.reference_gas_price - } - - fn protocol_version(&self) -> u64 { - self.protocol_version - } - - fn system_state_version(&self) -> u64 { - self.system_state_version - } - - fn epoch_start_timestamp_ms(&self) -> u64 { - self.epoch_start_timestamp_ms - } - - fn epoch_duration_ms(&self) -> u64 { - self.parameters.epoch_duration_ms - } - - fn safe_mode(&self) -> bool { - self.safe_mode - } - - fn advance_epoch_safe_mode(&mut self, params: &AdvanceEpochParams) { - self.epoch = params.epoch; - self.safe_mode = true; - self.safe_mode_storage_rewards - .deposit_for_safe_mode(params.storage_charge); - self.safe_mode_storage_rebates += params.storage_rebate; - self.safe_mode_computation_rewards - .deposit_for_safe_mode(params.computation_charge); - self.safe_mode_non_refundable_storage_fee += params.non_refundable_storage_fee; - self.epoch_start_timestamp_ms = params.epoch_start_timestamp_ms; - self.protocol_version = params.next_protocol_version.as_u64(); - } - - fn get_current_epoch_committee(&self) -> CommitteeWithNetworkMetadata { - let mut voting_rights = BTreeMap::new(); - let mut network_metadata = BTreeMap::new(); - for validator in &self.validators.active_validators { - let verified_metadata = validator.verified_metadata(); - let name = verified_metadata.sui_pubkey_bytes(); - voting_rights.insert(name, validator.voting_power); - network_metadata.insert( - name, - NetworkMetadata { - network_address: verified_metadata.net_address.clone(), - narwhal_primary_address: verified_metadata.primary_address.clone(), - }, - ); - } - CommitteeWithNetworkMetadata { - committee: Committee::new(self.epoch, voting_rights), - network_metadata, - } - } - - fn get_pending_active_validators( - &self, - object_store: &S, - ) -> Result, SuiError> { - let table_id = self.validators.pending_active_validators.contents.id; - let table_size = self.validators.pending_active_validators.contents.size; - let validators: Vec = - get_validators_from_table_vec(&object_store, table_id, table_size)?; - Ok(validators - .into_iter() - .map(|v| v.into_sui_validator_summary()) - .collect()) - } - - fn into_epoch_start_state(self) -> EpochStartSystemState { - EpochStartSystemState::new_v1( - self.epoch, - self.protocol_version, - self.reference_gas_price, - self.safe_mode, - self.epoch_start_timestamp_ms, - self.parameters.epoch_duration_ms, - self.validators - .active_validators - .iter() - .map(|validator| { - let metadata = validator.verified_metadata(); - EpochStartValidatorInfoV1 { - sui_address: metadata.sui_address, - protocol_pubkey: metadata.protocol_pubkey.clone(), - narwhal_network_pubkey: metadata.network_pubkey.clone(), - narwhal_worker_pubkey: metadata.worker_pubkey.clone(), - sui_net_address: metadata.net_address.clone(), - p2p_address: metadata.p2p_address.clone(), - narwhal_primary_address: metadata.primary_address.clone(), - narwhal_worker_address: metadata.worker_address.clone(), - voting_power: validator.voting_power, - hostname: metadata.name.clone(), - } - }) - .collect(), - ) - } - - fn into_sui_system_state_summary(self) -> SuiSystemStateSummary { - // If you are making any changes to SuiSystemStateV1 or any of its dependent - // types before mainnet, please also update SuiSystemStateSummary and - // its corresponding TS type. Post-mainnet, we will need to introduce a - // new version. - let Self { - epoch, - protocol_version, - system_state_version, - validators: - ValidatorSetV1 { - total_stake, - active_validators, - pending_active_validators: - TableVec { - contents: - Table { - id: pending_active_validators_id, - size: pending_active_validators_size, - }, - }, - pending_removals, - staking_pool_mappings: - Table { - id: staking_pool_mappings_id, - size: staking_pool_mappings_size, - }, - inactive_validators: - Table { - id: inactive_pools_id, - size: inactive_pools_size, - }, - validator_candidates: - Table { - id: validator_candidates_id, - size: validator_candidates_size, - }, - at_risk_validators: - VecMap { - contents: at_risk_validators, - }, - extra_fields: _, - }, - storage_fund, - parameters: - SystemParametersV2 { - stake_subsidy_start_epoch, - epoch_duration_ms, - min_validator_count: _, // TODO: Add it to RPC layer in the future. - max_validator_count, - min_validator_joining_stake, - validator_low_stake_threshold, - validator_very_low_stake_threshold, - validator_low_stake_grace_period, - extra_fields: _, - }, - reference_gas_price, - validator_report_records: - VecMap { - contents: validator_report_records, - }, - stake_subsidy: - StakeSubsidyV1 { - balance: stake_subsidy_balance, - distribution_counter: stake_subsidy_distribution_counter, - current_distribution_amount: stake_subsidy_current_distribution_amount, - stake_subsidy_period_length, - stake_subsidy_decrease_rate, - extra_fields: _, - }, - safe_mode, - safe_mode_storage_rewards, - safe_mode_computation_rewards, - safe_mode_storage_rebates, - safe_mode_non_refundable_storage_fee, - epoch_start_timestamp_ms, - extra_fields: _, - } = self; - SuiSystemStateSummary { - epoch, - protocol_version, - system_state_version, - storage_fund_total_object_storage_rebates: storage_fund - .total_object_storage_rebates - .value(), - storage_fund_non_refundable_balance: storage_fund.non_refundable_balance.value(), - reference_gas_price, - safe_mode, - safe_mode_storage_rewards: safe_mode_storage_rewards.value(), - safe_mode_computation_rewards: safe_mode_computation_rewards.value(), - safe_mode_storage_rebates, - safe_mode_non_refundable_storage_fee, - epoch_start_timestamp_ms, - stake_subsidy_start_epoch, - epoch_duration_ms, - stake_subsidy_distribution_counter, - stake_subsidy_balance: stake_subsidy_balance.value(), - stake_subsidy_current_distribution_amount, - total_stake, - active_validators: active_validators - .into_iter() - .map(|v| v.into_sui_validator_summary()) - .collect(), - pending_active_validators_id, - pending_active_validators_size, - pending_removals, - staking_pool_mappings_id, - staking_pool_mappings_size, - inactive_pools_id, - inactive_pools_size, - validator_candidates_id, - validator_candidates_size, - at_risk_validators: at_risk_validators - .into_iter() - .map(|e| (e.key, e.value)) - .collect(), - validator_report_records: validator_report_records - .into_iter() - .map(|e| (e.key, e.value.contents)) - .collect(), - max_validator_count, - min_validator_joining_stake, - validator_low_stake_threshold, - validator_very_low_stake_threshold, - validator_low_stake_grace_period, - stake_subsidy_period_length, - stake_subsidy_decrease_rate, - } - } -} diff --git a/crates/sui-types/src/sui_system_state/sui_system_state_summary.rs b/crates/sui-types/src/sui_system_state/sui_system_state_summary.rs deleted file mode 100644 index 4fa54132847..00000000000 --- a/crates/sui-types/src/sui_system_state/sui_system_state_summary.rs +++ /dev/null @@ -1,478 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use fastcrypto::{encoding::Base64, traits::ToFromBytes}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; - -use super::{SuiSystemState, SuiSystemStateTrait}; -use crate::{ - base_types::{AuthorityName, ObjectID, SuiAddress}, - committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata}, - dynamic_field::get_dynamic_field_from_store, - error::SuiError, - id::ID, - multiaddr::Multiaddr, - storage::ObjectStore, - sui_serde::{BigInt, Readable}, - sui_system_state::get_validator_from_table, -}; - -/// This is the JSON-RPC type for the SUI system state object. -/// It flattens all fields to make them top-level fields such that it as minimum -/// dependencies to the internal data structures of the SUI system state type. - -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct SuiSystemStateSummary { - /// The current epoch ID, starting from 0. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub epoch: u64, - /// The current protocol version, starting from 1. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub protocol_version: u64, - /// The current version of the system state data structure type. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub system_state_version: u64, - /// The storage rebates of all the objects on-chain stored in the storage - /// fund. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub storage_fund_total_object_storage_rebates: u64, - /// The non-refundable portion of the storage fund coming from storage - /// reinvestment, non-refundable storage rebates and any leftover - /// staking rewards. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub storage_fund_non_refundable_balance: u64, - /// The reference gas price for the current epoch. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub reference_gas_price: u64, - /// Whether the system is running in a downgraded safe mode due to a - /// non-recoverable bug. This is set whenever we failed to execute - /// advance_epoch, and ended up executing advance_epoch_safe_mode. - /// It can be reset once we are able to successfully execute advance_epoch. - pub safe_mode: bool, - /// Amount of storage rewards accumulated (and not yet distributed) during - /// safe mode. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub safe_mode_storage_rewards: u64, - /// Amount of computation rewards accumulated (and not yet distributed) - /// during safe mode. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub safe_mode_computation_rewards: u64, - /// Amount of storage rebates accumulated (and not yet burned) during safe - /// mode. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub safe_mode_storage_rebates: u64, - /// Amount of non-refundable storage fee accumulated during safe mode. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub safe_mode_non_refundable_storage_fee: u64, - /// Unix timestamp of the current epoch start - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub epoch_start_timestamp_ms: u64, - - // System parameters - /// The duration of an epoch, in milliseconds. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub epoch_duration_ms: u64, - - /// The starting epoch in which stake subsidies start being paid out - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub stake_subsidy_start_epoch: u64, - - /// Maximum number of active validators at any moment. - /// We do not allow the number of validators in any epoch to go above this. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub max_validator_count: u64, - - /// Lower-bound on the amount of stake required to become a validator. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub min_validator_joining_stake: u64, - - /// Validators with stake amount below `validator_low_stake_threshold` are - /// considered to have low stake and will be escorted out of the - /// validator set after being below this threshold for more than - /// `validator_low_stake_grace_period` number of epochs. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub validator_low_stake_threshold: u64, - - /// Validators with stake below `validator_very_low_stake_threshold` will be - /// removed immediately at epoch change, no grace period. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub validator_very_low_stake_threshold: u64, - - /// A validator can have stake below `validator_low_stake_threshold` - /// for this many epochs before being kicked out. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub validator_low_stake_grace_period: u64, - - // Stake subsidy information - /// Balance of SUI set aside for stake subsidies that will be drawn down - /// over time. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub stake_subsidy_balance: u64, - /// This counter may be different from the current epoch number if - /// in some epochs we decide to skip the subsidy. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub stake_subsidy_distribution_counter: u64, - /// The amount of stake subsidy to be drawn down per epoch. - /// This amount decays and decreases over time. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub stake_subsidy_current_distribution_amount: u64, - /// Number of distributions to occur before the distribution amount decays. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub stake_subsidy_period_length: u64, - /// The rate at which the distribution amount decays at the end of each - /// period. Expressed in basis points. - pub stake_subsidy_decrease_rate: u16, - - // Validator set - /// Total amount of stake from all active validators at the beginning of the - /// epoch. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub total_stake: u64, - /// The list of active validators in the current epoch. - pub active_validators: Vec, - /// ID of the object that contains the list of new validators that will join - /// at the end of the epoch. - pub pending_active_validators_id: ObjectID, - /// Number of new validators that will join at the end of the epoch. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub pending_active_validators_size: u64, - /// Removal requests from the validators. Each element is an index - /// pointing to `active_validators`. - #[schemars(with = "Vec>")] - #[serde_as(as = "Vec, _>>")] - pub pending_removals: Vec, - /// ID of the object that maps from staking pool's ID to the sui address of - /// a validator. - pub staking_pool_mappings_id: ObjectID, - /// Number of staking pool mappings. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub staking_pool_mappings_size: u64, - /// ID of the object that maps from a staking pool ID to the inactive - /// validator that has that pool as its staking pool. - pub inactive_pools_id: ObjectID, - /// Number of inactive staking pools. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub inactive_pools_size: u64, - /// ID of the object that stores preactive validators, mapping their - /// addresses to their `Validator` structs. - pub validator_candidates_id: ObjectID, - /// Number of preactive validators. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub validator_candidates_size: u64, - /// Map storing the number of epochs for which each validator has been below - /// the low stake threshold. - #[schemars(with = "Vec<(SuiAddress, BigInt)>")] - #[serde_as(as = "Vec<(_, Readable, _>)>")] - pub at_risk_validators: Vec<(SuiAddress, u64)>, - /// A map storing the records of validator reporting each other. - pub validator_report_records: Vec<(SuiAddress, Vec)>, -} - -impl SuiSystemStateSummary { - pub fn get_sui_committee_for_benchmarking(&self) -> CommitteeWithNetworkMetadata { - let mut voting_rights = BTreeMap::new(); - let mut network_metadata = BTreeMap::new(); - for validator in &self.active_validators { - let name = AuthorityName::from_bytes(&validator.protocol_pubkey_bytes).unwrap(); - voting_rights.insert(name, validator.voting_power); - network_metadata.insert( - name, - NetworkMetadata { - network_address: Multiaddr::try_from(validator.net_address.clone()).unwrap(), - narwhal_primary_address: Multiaddr::try_from(validator.primary_address.clone()) - .unwrap(), - }, - ); - } - CommitteeWithNetworkMetadata { - committee: Committee::new(self.epoch, voting_rights), - network_metadata, - } - } -} - -/// This is the JSON-RPC type for the SUI validator. It flattens all inner -/// structures to top-level fields so that they are decoupled from the internal -/// definitions. -#[serde_as] -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct SuiValidatorSummary { - // Metadata - pub sui_address: SuiAddress, - #[schemars(with = "Base64")] - #[serde_as(as = "Base64")] - pub protocol_pubkey_bytes: Vec, - #[schemars(with = "Base64")] - #[serde_as(as = "Base64")] - pub network_pubkey_bytes: Vec, - #[schemars(with = "Base64")] - #[serde_as(as = "Base64")] - pub worker_pubkey_bytes: Vec, - #[schemars(with = "Base64")] - #[serde_as(as = "Base64")] - pub proof_of_possession_bytes: Vec, - pub name: String, - pub description: String, - pub image_url: String, - pub project_url: String, - pub net_address: String, - pub p2p_address: String, - pub primary_address: String, - pub worker_address: String, - #[schemars(with = "Option")] - #[serde_as(as = "Option")] - pub next_epoch_protocol_pubkey_bytes: Option>, - #[schemars(with = "Option")] - #[serde_as(as = "Option")] - pub next_epoch_proof_of_possession: Option>, - #[schemars(with = "Option")] - #[serde_as(as = "Option")] - pub next_epoch_network_pubkey_bytes: Option>, - #[schemars(with = "Option")] - #[serde_as(as = "Option")] - pub next_epoch_worker_pubkey_bytes: Option>, - pub next_epoch_net_address: Option, - pub next_epoch_p2p_address: Option, - pub next_epoch_primary_address: Option, - pub next_epoch_worker_address: Option, - - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub voting_power: u64, - pub operation_cap_id: ObjectID, - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub gas_price: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub commission_rate: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub next_epoch_stake: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub next_epoch_gas_price: u64, - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub next_epoch_commission_rate: u64, - - // Staking pool information - /// ID of the staking pool object. - pub staking_pool_id: ObjectID, - /// The epoch at which this pool became active. - #[schemars(with = "Option>")] - #[serde_as(as = "Option, _>>")] - pub staking_pool_activation_epoch: Option, - /// The epoch at which this staking pool ceased to be active. `None` = - /// {pre-active, active}, - #[schemars(with = "Option>")] - #[serde_as(as = "Option, _>>")] - pub staking_pool_deactivation_epoch: Option, - /// The total number of SUI tokens in this pool. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub staking_pool_sui_balance: u64, - /// The epoch stake rewards will be added here at the end of each epoch. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub rewards_pool: u64, - /// Total number of pool tokens issued by the pool. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub pool_token_balance: u64, - /// Pending stake amount for this epoch. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub pending_stake: u64, - /// Pending stake withdrawn during the current epoch, emptied at epoch - /// boundaries. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub pending_total_sui_withdraw: u64, - /// Pending pool token withdrawn during the current epoch, emptied at epoch - /// boundaries. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub pending_pool_token_withdraw: u64, - /// ID of the exchange rate table object. - pub exchange_rates_id: ObjectID, - /// Number of exchange rates in the table. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub exchange_rates_size: u64, -} - -impl Default for SuiSystemStateSummary { - fn default() -> Self { - Self { - epoch: 0, - protocol_version: 1, - system_state_version: 1, - storage_fund_total_object_storage_rebates: 0, - storage_fund_non_refundable_balance: 0, - reference_gas_price: 1, - safe_mode: false, - safe_mode_storage_rewards: 0, - safe_mode_computation_rewards: 0, - safe_mode_storage_rebates: 0, - safe_mode_non_refundable_storage_fee: 0, - epoch_start_timestamp_ms: 0, - epoch_duration_ms: 0, - stake_subsidy_start_epoch: 0, - max_validator_count: 0, - min_validator_joining_stake: 0, - validator_low_stake_threshold: 0, - validator_very_low_stake_threshold: 0, - validator_low_stake_grace_period: 0, - stake_subsidy_balance: 0, - stake_subsidy_distribution_counter: 0, - stake_subsidy_current_distribution_amount: 0, - stake_subsidy_period_length: 0, - stake_subsidy_decrease_rate: 0, - total_stake: 0, - active_validators: vec![], - pending_active_validators_id: ObjectID::ZERO, - pending_active_validators_size: 0, - pending_removals: vec![], - staking_pool_mappings_id: ObjectID::ZERO, - staking_pool_mappings_size: 0, - inactive_pools_id: ObjectID::ZERO, - inactive_pools_size: 0, - validator_candidates_id: ObjectID::ZERO, - validator_candidates_size: 0, - at_risk_validators: vec![], - validator_report_records: vec![], - } - } -} - -impl Default for SuiValidatorSummary { - fn default() -> Self { - Self { - sui_address: SuiAddress::default(), - protocol_pubkey_bytes: vec![], - network_pubkey_bytes: vec![], - worker_pubkey_bytes: vec![], - proof_of_possession_bytes: vec![], - name: String::new(), - description: String::new(), - image_url: String::new(), - project_url: String::new(), - net_address: String::new(), - p2p_address: String::new(), - primary_address: String::new(), - worker_address: String::new(), - next_epoch_protocol_pubkey_bytes: None, - next_epoch_proof_of_possession: None, - next_epoch_network_pubkey_bytes: None, - next_epoch_worker_pubkey_bytes: None, - next_epoch_net_address: None, - next_epoch_p2p_address: None, - next_epoch_primary_address: None, - next_epoch_worker_address: None, - voting_power: 0, - operation_cap_id: ObjectID::ZERO, - gas_price: 0, - commission_rate: 0, - next_epoch_stake: 0, - next_epoch_gas_price: 0, - next_epoch_commission_rate: 0, - staking_pool_id: ObjectID::ZERO, - staking_pool_activation_epoch: None, - staking_pool_deactivation_epoch: None, - staking_pool_sui_balance: 0, - rewards_pool: 0, - pool_token_balance: 0, - pending_stake: 0, - pending_total_sui_withdraw: 0, - pending_pool_token_withdraw: 0, - exchange_rates_id: ObjectID::ZERO, - exchange_rates_size: 0, - } - } -} - -/// Given the staking pool id of a validator, return the validator's -/// `SuiValidatorSummary`, works for validator candidates, active validators, as -/// well as inactive validators. -pub fn get_validator_by_pool_id( - object_store: &S, - system_state: &SuiSystemState, - system_state_summary: &SuiSystemStateSummary, - pool_id: ObjectID, -) -> Result -where - S: ObjectStore + ?Sized, -{ - // First try to find in active validator set. - let active_validator = system_state_summary - .active_validators - .iter() - .find(|v| v.staking_pool_id == pool_id); - if let Some(active) = active_validator { - return Ok(active.clone()); - } - // Then try to find in pending active validator set. - let pending_active_validators = system_state.get_pending_active_validators(object_store)?; - let pending_active = pending_active_validators - .iter() - .find(|v| v.staking_pool_id == pool_id); - if let Some(pending) = pending_active { - return Ok(pending.clone()); - } - // After that try to find in inactive pools. - let inactive_table_id = system_state_summary.inactive_pools_id; - if let Ok(inactive) = - get_validator_from_table(&object_store, inactive_table_id, &ID::new(pool_id)) - { - return Ok(inactive); - } - // Finally look up the candidates pool. - let candidate_address: SuiAddress = get_dynamic_field_from_store( - &object_store, - system_state_summary.staking_pool_mappings_id, - &ID::new(pool_id), - ) - .map_err(|err| { - SuiError::SuiSystemStateReadError(format!( - "Failed to load candidate address from pool mappings: {:?}", - err - )) - })?; - let candidate_table_id = system_state_summary.validator_candidates_id; - get_validator_from_table(&object_store, candidate_table_id, &candidate_address) -} diff --git a/crates/sui-types/src/timelock/mod.rs b/crates/sui-types/src/timelock/mod.rs deleted file mode 100644 index 89f7a1a5f0c..00000000000 --- a/crates/sui-types/src/timelock/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -#[allow(clippy::module_inception)] -pub mod timelock; -pub mod timelocked_staked_sui; -pub mod timelocked_staking; diff --git a/crates/sui-types/src/timelock/timelock.rs b/crates/sui-types/src/timelock/timelock.rs deleted file mode 100644 index 4f4de7d9da1..00000000000 --- a/crates/sui-types/src/timelock/timelock.rs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use move_core_types::{ - // annotated_value::{MoveFieldLayout, MoveStructLayout, MoveTypeLayout}, - ident_str, - identifier::IdentStr, - language_storage::{StructTag, TypeTag}, -}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; - -use crate::{balance::Balance, base_types::ObjectID, id::UID, TIMELOCK_ADDRESS}; - -#[cfg(test)] -#[path = "../unit_tests/timelock/timelock_tests.rs"] -mod timelock_tests; - -pub const TIMELOCK_MODULE_NAME: &IdentStr = ident_str!("timelock"); -pub const TIMELOCK_STRUCT_NAME: &IdentStr = ident_str!("TimeLock"); - -/// Rust version of the Move stardust::timelock::TimeLock type. -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema, Eq, PartialEq)] -pub struct TimeLock { - pub id: UID, - /// The locked object. - pub locked: T, - /// This is the epoch time stamp of when the lock expires. - pub expiration_timestamp_ms: u64, -} - -impl TimeLock { - /// Constructor. - pub fn new(id: UID, locked: T, expiration_timestamp_ms: u64) -> Self { - Self { - id, - locked, - expiration_timestamp_ms, - } - } - - /// Get the TimeLock's `type`. - pub fn type_(type_param: TypeTag) -> StructTag { - StructTag { - address: TIMELOCK_ADDRESS, - module: TIMELOCK_MODULE_NAME.to_owned(), - name: TIMELOCK_STRUCT_NAME.to_owned(), - type_params: vec![type_param], - } - } - - /// Get the TimeLock's `id`. - pub fn id(&self) -> &ObjectID { - self.id.object_id() - } - - /// Get the TimeLock's `locked` object. - pub fn locked(&self) -> &T { - &self.locked - } - - /// Get the TimeLock's `expiration_timestamp_ms`. - pub fn expiration_timestamp_ms(&self) -> u64 { - self.expiration_timestamp_ms - } -} - -impl<'de, T> TimeLock -where - T: Serialize + Deserialize<'de>, -{ - /// Create a `TimeLock` from BCS bytes. - pub fn from_bcs_bytes(content: &'de [u8]) -> Result { - bcs::from_bytes(content) - } - - /// Serialize a `TimeLock` as a `Vec` of BCS. - pub fn to_bcs_bytes(&self) -> Vec { - bcs::to_bytes(&self).unwrap() - } -} - -/// Is this other StructTag representing a TimeLock? -pub fn is_timelock(other: &StructTag) -> bool { - other.address == TIMELOCK_ADDRESS - && other.module.as_ident_str() == TIMELOCK_MODULE_NAME - && other.name.as_ident_str() == TIMELOCK_STRUCT_NAME -} - -/// Is this other StructTag representing a TimeLock>? -pub fn is_timelocked_balance(other: &StructTag) -> bool { - if !is_timelock(other) { - return false; - } - - if other.type_params.len() != 1 { - return false; - } - - match &other.type_params[0] { - TypeTag::Struct(tag) => Balance::is_balance(tag), - _ => false, - } -} diff --git a/crates/sui-types/src/timelock/timelocked_staked_sui.rs b/crates/sui-types/src/timelock/timelocked_staked_sui.rs deleted file mode 100644 index 8c2ff28e8ef..00000000000 --- a/crates/sui-types/src/timelock/timelocked_staked_sui.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag}; -use serde::{Deserialize, Serialize}; - -use crate::{ - base_types::ObjectID, - committee::EpochId, - error::SuiError, - governance::StakedSui, - id::UID, - object::{Data, Object}, - TIMELOCK_ADDRESS, -}; - -pub const TIMELOCKED_STAKED_SUI_MODULE_NAME: &IdentStr = ident_str!("timelocked_staked_sui"); -pub const TIMELOCKED_STAKED_SUI_STRUCT_NAME: &IdentStr = ident_str!("TimelockedStakedSui"); - -/// Rust version of the Move -/// stardust::timelocked_staked_sui::TimelockedStakedSui type. -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct TimelockedStakedSui { - id: UID, - /// A self-custodial object holding the staked SUI tokens. - staked_sui: StakedSui, - /// This is the epoch time stamp of when the lock expires. - expiration_timestamp_ms: u64, -} - -impl TimelockedStakedSui { - /// Get the TimeLock's `type`. - pub fn type_() -> StructTag { - StructTag { - address: TIMELOCK_ADDRESS, - module: TIMELOCKED_STAKED_SUI_MODULE_NAME.to_owned(), - name: TIMELOCKED_STAKED_SUI_STRUCT_NAME.to_owned(), - type_params: vec![], - } - } - - /// Is this other StructTag representing a TimelockedStakedSui? - pub fn is_timelocked_staked_sui(s: &StructTag) -> bool { - s.address == TIMELOCK_ADDRESS - && s.module.as_ident_str() == TIMELOCKED_STAKED_SUI_MODULE_NAME - && s.name.as_ident_str() == TIMELOCKED_STAKED_SUI_STRUCT_NAME - && s.type_params.is_empty() - } - - /// Get the TimelockedStakedSui's `id`. - pub fn id(&self) -> ObjectID { - self.id.id.bytes - } - - /// Get the wrapped StakedSui's `pool_id`. - pub fn pool_id(&self) -> ObjectID { - self.staked_sui.pool_id() - } - - /// Get the wrapped StakedSui's `activation_epoch`. - pub fn activation_epoch(&self) -> EpochId { - self.staked_sui.activation_epoch() - } - - /// Get the wrapped StakedSui's `request_epoch`. - pub fn request_epoch(&self) -> EpochId { - // TODO: this might change when we implement warm up period. - self.staked_sui.activation_epoch().saturating_sub(1) - } - - /// Get the wrapped StakedSui's `principal`. - pub fn principal(&self) -> u64 { - self.staked_sui.principal() - } - - /// Get the TimelockedStakedSui's `expiration_timestamp_ms`. - pub fn expiration_timestamp_ms(&self) -> u64 { - self.expiration_timestamp_ms - } -} - -impl TryFrom<&Object> for TimelockedStakedSui { - type Error = SuiError; - fn try_from(object: &Object) -> Result { - match &object.data { - Data::Move(o) => { - if o.type_().is_timelocked_staked_sui() { - return bcs::from_bytes(o.contents()).map_err(|err| SuiError::TypeError { - error: format!( - "Unable to deserialize TimelockedStakedSui object: {:?}", - err - ), - }); - } - } - Data::Package(_) => {} - } - - Err(SuiError::TypeError { - error: format!("Object type is not a TimelockedStakedSui: {:?}", object), - }) - } -} diff --git a/crates/sui-types/src/transfer.rs b/crates/sui-types/src/transfer.rs deleted file mode 100644 index 8afbd6bdb73..00000000000 --- a/crates/sui-types/src/transfer.rs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use move_binary_format::{binary_views::BinaryIndexedView, file_format::SignatureToken}; -use move_bytecode_utils::resolve_struct; -use move_core_types::{ - account_address::AccountAddress, - ident_str, - identifier::IdentStr, - language_storage::{StructTag, TypeTag}, -}; -use serde::{Deserialize, Serialize}; - -use crate::{ - base_types::{ObjectID, SequenceNumber}, - id::ID, - SUI_FRAMEWORK_ADDRESS, -}; - -const TRANSFER_MODULE_NAME: &IdentStr = ident_str!("transfer"); -const RECEIVING_STRUCT_NAME: &IdentStr = ident_str!("Receiving"); - -pub const RESOLVED_RECEIVING_STRUCT: (&AccountAddress, &IdentStr, &IdentStr) = ( - &SUI_FRAMEWORK_ADDRESS, - TRANSFER_MODULE_NAME, - RECEIVING_STRUCT_NAME, -); - -/// Rust version of the Move sui::transfer::Receiving type -#[derive(Clone, Serialize, Deserialize, Debug)] -pub struct Receiving { - pub id: ID, - pub version: SequenceNumber, -} - -impl Receiving { - pub fn new(id: ObjectID, version: SequenceNumber) -> Self { - Self { - id: ID::new(id), - version, - } - } - - pub fn to_bcs_bytes(&self) -> Vec { - bcs::to_bytes(self).expect("Value representation is owned and should always serialize") - } - - pub fn struct_tag() -> StructTag { - StructTag { - address: SUI_FRAMEWORK_ADDRESS, - module: TRANSFER_MODULE_NAME.to_owned(), - name: RECEIVING_STRUCT_NAME.to_owned(), - // TODO: this should really include the type parameters eventually when we add type - // parameters to the other polymorphic types like this. - type_params: vec![], - } - } - - pub fn type_tag() -> TypeTag { - TypeTag::Struct(Box::new(Self::struct_tag())) - } - - pub fn is_receiving(view: &BinaryIndexedView<'_>, s: &SignatureToken) -> bool { - use SignatureToken as S; - match s { - S::MutableReference(inner) | S::Reference(inner) => Self::is_receiving(view, inner), - S::StructInstantiation(s) => { - let (idx, type_args) = &**s; - let struct_tag = resolve_struct(view, *idx); - struct_tag == RESOLVED_RECEIVING_STRUCT && type_args.len() == 1 - } - _ => false, - } - } -} diff --git a/crates/sui-types/src/unit_tests/multisig_tests.rs b/crates/sui-types/src/unit_tests/multisig_tests.rs deleted file mode 100644 index 69cfdb0fea7..00000000000 --- a/crates/sui-types/src/unit_tests/multisig_tests.rs +++ /dev/null @@ -1,513 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::str::FromStr; - -use fastcrypto::{ - ed25519::Ed25519KeyPair, - encoding::{Base64, Encoding}, - traits::ToFromBytes, -}; -use fastcrypto_zkp::{ - bn254::{ - zk_login::{parse_jwks, JwkId, OIDCProvider, ZkLoginInputs, JWK}, - zk_login_api::ZkLoginEnv, - }, - zk_login_utils::Bn254FrElement, -}; -use im::hashmap::HashMap as ImHashMap; -use once_cell::sync::OnceCell; -use rand::{rngs::StdRng, SeedableRng}; -use roaring::RoaringBitmap; -use shared_crypto::intent::{Intent, IntentMessage, PersonalMessage}; - -use super::{MultiSigPublicKey, ThresholdUnit, WeightUnit}; -use crate::{ - base_types::SuiAddress, - crypto::{ - get_key_pair, get_key_pair_from_rng, Ed25519SuiSignature, PublicKey, Signature, SuiKeyPair, - SuiSignatureInner, ZkLoginPublicIdentifier, - }, - multisig::{as_indices, MultiSig, MAX_SIGNER_IN_MULTISIG}, - multisig_legacy::bitmap_to_u16, - signature::{AuthenticatorTrait, GenericSignature, VerifyParams}, - utils::{ - keys, load_test_vectors, make_transaction_data, make_zklogin_tx, DEFAULT_ADDRESS_SEED, - SHORT_ADDRESS_SEED, - }, - zk_login_authenticator::ZkLoginAuthenticator, - zk_login_util::DEFAULT_JWK_BYTES, -}; -#[test] -fn test_combine_sigs() { - let kp1: SuiKeyPair = SuiKeyPair::Ed25519(get_key_pair().1); - let kp2: SuiKeyPair = SuiKeyPair::Secp256k1(get_key_pair().1); - let kp3: SuiKeyPair = SuiKeyPair::Secp256r1(get_key_pair().1); - - let pk1 = kp1.public(); - let pk2 = kp2.public(); - - let multisig_pk = MultiSigPublicKey::new(vec![pk1, pk2], vec![1, 1], 2).unwrap(); - - let msg = IntentMessage::new( - Intent::sui_transaction(), - PersonalMessage { - message: "Hello".as_bytes().to_vec(), - }, - ); - let sig1: GenericSignature = Signature::new_secure(&msg, &kp1).into(); - let sig2 = Signature::new_secure(&msg, &kp2).into(); - let sig3 = Signature::new_secure(&msg, &kp3).into(); - - // MultiSigPublicKey contains only 2 public key but 3 signatures are passed, - // fails to combine. - assert!(MultiSig::combine(vec![sig1.clone(), sig2, sig3], multisig_pk.clone()).is_err()); - - // Cannot create malformed MultiSig. - assert!(MultiSig::combine(vec![], multisig_pk.clone()).is_err()); - assert!(MultiSig::combine(vec![sig1.clone(), sig1], multisig_pk).is_err()); -} -#[test] -fn test_serde_roundtrip() { - let msg = IntentMessage::new( - Intent::sui_transaction(), - PersonalMessage { - message: "Hello".as_bytes().to_vec(), - }, - ); - - for kp in keys() { - let pk = kp.public(); - let multisig_pk = MultiSigPublicKey::new(vec![pk], vec![1], 1).unwrap(); - let sig = Signature::new_secure(&msg, &kp).into(); - let multisig = MultiSig::combine(vec![sig], multisig_pk).unwrap(); - let plain_bytes = bcs::to_bytes(&multisig).unwrap(); - - let generic_sig = GenericSignature::MultiSig(multisig); - let generic_sig_bytes = generic_sig.as_bytes(); - let generic_sig_roundtrip = GenericSignature::from_bytes(generic_sig_bytes).unwrap(); - assert_eq!(generic_sig, generic_sig_roundtrip); - - // A MultiSig flag 0x03 is appended before the bcs serialized bytes. - assert_eq!(plain_bytes.len() + 1, generic_sig_bytes.len()); - assert_eq!(generic_sig_bytes.first().unwrap(), &0x03); - } - - // Malformed multisig cannot be deserialized - let multisig_pk = MultiSigPublicKey { - pk_map: vec![(keys()[0].public(), 1)], - threshold: 1, - }; - let multisig = MultiSig { - sigs: vec![], // No sigs - bitmap: 0, - multisig_pk, - bytes: OnceCell::new(), - }; - - let generic_sig = GenericSignature::MultiSig(multisig); - let generic_sig_bytes = generic_sig.as_bytes(); - assert!(GenericSignature::from_bytes(generic_sig_bytes).is_err()); - - // Malformed multisig_pk cannot be deserialized - let multisig_pk_1 = MultiSigPublicKey { - pk_map: vec![], - threshold: 0, - }; - - let multisig_1 = MultiSig { - sigs: vec![], - bitmap: 0, - multisig_pk: multisig_pk_1, - bytes: OnceCell::new(), - }; - - let generic_sig_1 = GenericSignature::MultiSig(multisig_1); - let generic_sig_bytes = generic_sig_1.as_bytes(); - assert!(GenericSignature::from_bytes(generic_sig_bytes).is_err()); - - // Single sig serialization unchanged. - let sig = Ed25519SuiSignature::default(); - let single_sig = GenericSignature::Signature(sig.clone().into()); - let single_sig_bytes = single_sig.as_bytes(); - let single_sig_roundtrip = GenericSignature::from_bytes(single_sig_bytes).unwrap(); - assert_eq!(single_sig, single_sig_roundtrip); - assert_eq!(single_sig_bytes.len(), Ed25519SuiSignature::LENGTH); - assert_eq!( - single_sig_bytes.first().unwrap(), - &Ed25519SuiSignature::SCHEME.flag() - ); - assert_eq!(sig.as_bytes().len(), single_sig_bytes.len()); -} - -#[test] -fn test_multisig_pk_new() { - let keys = keys(); - let pk1 = keys[0].public(); - let pk2 = keys[1].public(); - let pk3 = keys[2].public(); - - // Fails on weight 0. - assert!( - MultiSigPublicKey::new( - vec![pk1.clone(), pk2.clone(), pk3.clone()], - vec![0, 1, 1], - 2 - ) - .is_err() - ); - - // Fails on threshold 0. - assert!( - MultiSigPublicKey::new( - vec![pk1.clone(), pk2.clone(), pk3.clone()], - vec![1, 1, 1], - 0 - ) - .is_err() - ); - - // Fails on incorrect array length. - assert!( - MultiSigPublicKey::new(vec![pk1.clone(), pk2.clone(), pk3.clone()], vec![1], 2).is_err() - ); - - // Fails on empty array length. - assert!(MultiSigPublicKey::new(vec![pk1.clone(), pk2, pk3], vec![], 2).is_err()); - - // Fails on dup pks. - assert!( - MultiSigPublicKey::new(vec![pk1.clone(), pk1.clone(), pk1], vec![1, 2, 3], 4,).is_err() - ); -} - -#[test] -fn test_multisig_address() { - // Pin an hardcoded multisig address generation here. If this fails, the address - // generation logic may have changed. If this is intended, update the hardcoded - // value below. - let keys = keys(); - let pk1 = keys[0].public(); - let pk2 = keys[1].public(); - let pk3 = keys[2].public(); - - let threshold: ThresholdUnit = 2; - let w1: WeightUnit = 1; - let w2: WeightUnit = 2; - let w3: WeightUnit = 3; - - let multisig_pk = - MultiSigPublicKey::new(vec![pk1, pk2, pk3], vec![w1, w2, w3], threshold).unwrap(); - let address: SuiAddress = (&multisig_pk).into(); - assert_eq!( - SuiAddress::from_str("0xe35c69eb504de34afdbd9f307fb3ca152646c92d549fea00065d26fc422109ea") - .unwrap(), - address - ); -} - -#[test] -fn test_max_sig() { - let msg = IntentMessage::new( - Intent::sui_transaction(), - PersonalMessage { - message: "Hello".as_bytes().to_vec(), - }, - ); - let mut seed = StdRng::from_seed([0; 32]); - let mut keys = Vec::new(); - let mut pks = Vec::new(); - - for _ in 0..11 { - let k = SuiKeyPair::Ed25519(get_key_pair_from_rng(&mut seed).1); - pks.push(k.public()); - keys.push(k); - } - - // multisig_pk with larger that max number of pks fails. - assert!( - MultiSigPublicKey::new( - pks.clone(), - vec![WeightUnit::MAX; MAX_SIGNER_IN_MULTISIG + 1], - ThresholdUnit::MAX - ) - .is_err() - ); - - // multisig_pk with unreachable threshold fails. - assert!(MultiSigPublicKey::new(pks.clone()[..5].to_vec(), vec![3; 5], 16).is_err()); - - // multisig_pk with max weights for each pk and max reachable threshold is ok. - let res = MultiSigPublicKey::new( - pks.clone()[..10].to_vec(), - vec![WeightUnit::MAX; MAX_SIGNER_IN_MULTISIG], - (WeightUnit::MAX as ThresholdUnit) * (MAX_SIGNER_IN_MULTISIG as ThresholdUnit), - ); - assert!(res.is_ok()); - - // multisig_pk with unreachable threshold fails. - let res = MultiSigPublicKey::new( - pks.clone()[..10].to_vec(), - vec![WeightUnit::MAX; MAX_SIGNER_IN_MULTISIG], - (WeightUnit::MAX as ThresholdUnit) * (MAX_SIGNER_IN_MULTISIG as ThresholdUnit) + 1, - ); - assert!(res.is_err()); - - // multisig_pk with max weights for each pk with threshold is 1x max weight - // validates ok. - let low_threshold_pk = MultiSigPublicKey::new( - pks.clone()[..10].to_vec(), - vec![WeightUnit::MAX; 10], - WeightUnit::MAX.into(), - ) - .unwrap(); - let sig = Signature::new_secure(&msg, &keys[0]).into(); - assert!( - MultiSig::combine(vec![sig; 1], low_threshold_pk) - .unwrap() - .init_and_validate() - .is_ok() - ); -} - -#[test] -fn test_to_from_indices() { - assert!(as_indices(0b11111111110).is_err()); - assert_eq!(as_indices(0b0000010110).unwrap(), vec![1, 2, 4]); - assert_eq!( - as_indices(0b1111111111).unwrap(), - vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - ); - - let mut bitmap = RoaringBitmap::new(); - bitmap.insert(1); - bitmap.insert(2); - bitmap.insert(4); - assert_eq!(bitmap_to_u16(bitmap.clone()).unwrap(), 0b0000010110); - bitmap.insert(11); - assert!(bitmap_to_u16(bitmap).is_err()); -} - -#[test] -fn multisig_get_pk() { - let keys = keys(); - let pk1 = keys[0].public(); - let pk2 = keys[1].public(); - - let multisig_pk = MultiSigPublicKey::new(vec![pk1, pk2], vec![1, 1], 2).unwrap(); - let msg = IntentMessage::new( - Intent::sui_transaction(), - PersonalMessage { - message: "Hello".as_bytes().to_vec(), - }, - ); - let sig1: GenericSignature = Signature::new_secure(&msg, &keys[0]).into(); - let sig2: GenericSignature = Signature::new_secure(&msg, &keys[1]).into(); - - let multi_sig = - MultiSig::combine(vec![sig1.clone(), sig2.clone()], multisig_pk.clone()).unwrap(); - - assert!(multi_sig.get_pk().clone() == multisig_pk); - assert!( - *multi_sig.get_sigs() == vec![sig1.to_compressed().unwrap(), sig2.to_compressed().unwrap()] - ); -} - -#[test] -fn multisig_get_indices() { - let keys = keys(); - let pk1 = keys[0].public(); - let pk2 = keys[1].public(); - let pk3 = keys[2].public(); - - let multisig_pk = MultiSigPublicKey::new(vec![pk1, pk2, pk3], vec![1, 1, 1], 2).unwrap(); - let msg = IntentMessage::new( - Intent::sui_transaction(), - PersonalMessage { - message: "Hello".as_bytes().to_vec(), - }, - ); - let sig1: GenericSignature = Signature::new_secure(&msg, &keys[0]).into(); - let sig2: GenericSignature = Signature::new_secure(&msg, &keys[1]).into(); - let sig3: GenericSignature = Signature::new_secure(&msg, &keys[2]).into(); - - let multi_sig1 = - MultiSig::combine(vec![sig2.clone(), sig3.clone()], multisig_pk.clone()).unwrap(); - - let multi_sig2 = MultiSig::combine( - vec![sig1.clone(), sig2.clone(), sig3.clone()], - multisig_pk.clone(), - ) - .unwrap(); - - let invalid_multisig = MultiSig::combine(vec![sig3, sig2, sig1], multisig_pk).unwrap(); - - // Indexes of public keys in multisig public key instance according to the - // combined sigs. - assert!(multi_sig1.get_indices().unwrap() == vec![1, 2]); - assert!(multi_sig2.get_indices().unwrap() == vec![0, 1, 2]); - assert!(invalid_multisig.get_indices().unwrap() == vec![0, 1, 2]); -} - -#[test] -fn multisig_zklogin_scenarios() { - // consistency test with - // sui/sdk/typescript/test/unit/cryptography/multisig.test.ts - let mut seed = StdRng::from_seed([0; 32]); - let kp: Ed25519KeyPair = get_key_pair_from_rng(&mut seed).1; - let skp: SuiKeyPair = SuiKeyPair::Ed25519(kp); - let pk1 = skp.public(); - - let (_, _, inputs) = &load_test_vectors("./src/unit_tests/zklogin_test_vectors.json")[0]; - // pk consistent with the one in make_zklogin_tx - let pk2 = PublicKey::ZkLogin( - ZkLoginPublicIdentifier::new( - &OIDCProvider::Twitch.get_config().iss, - inputs.get_address_seed(), - ) - .unwrap(), - ); - - // set up 1-out-of-2 multisig with one zklogin public identifier and one - // traditional public key. - let multisig_pk = MultiSigPublicKey::new(vec![pk1, pk2], vec![1, 1], 1).unwrap(); - let multisig_addr = SuiAddress::from(&multisig_pk); - assert_eq!( - multisig_addr, - SuiAddress::from_str("0xb9c0780a3943cde13a2409bf1a6f06ae60b0dff2b2f373260cf627aa4f43a588") - .unwrap() - ); - - let (_, envelop, zklogin_sig) = make_zklogin_tx(multisig_addr, false); - let binding = envelop.into_data(); - let tx = binding.transaction_data(); - assert_eq!(Base64::encode(bcs::to_bytes(tx).unwrap()), "AAABACACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgEBAQABAAC5wHgKOUPN4TokCb8abwauYLDf8rLzcyYM9ieqT0OliAGbB4FfBEl+LgXSLKw6oGFBCyCGjMYZFUxCocYb6ZAnFwEAAAAAAAAAIJZw7UpW1XHubORIOaY8d2+WyBNwoJ+FEAxlsa7h7JHrucB4CjlDzeE6JAm/Gm8GrmCw3/Ky83MmDPYnqk9DpYgBAAAAAAAAABAnAAAAAAAAAA==".to_string()); - - let intent_msg = &IntentMessage::new(Intent::sui_transaction(), tx.clone()); - assert_eq!(Base64::encode(zklogin_sig.as_ref()), "BQNNMTczMTgwODkxMjU5NTI0MjE3MzYzNDIyNjM3MTc5MzI3MTk0Mzc3MTc4NDQyODI0MTAxODc5NTc5ODQ3NTE5Mzk5NDI4OTgyNTEyNTBNMTEzNzM5NjY2NDU0NjkxMjI1ODIwNzQwODIyOTU5ODUzODgyNTg4NDA2ODE2MTgyNjg1OTM5NzY2OTczMjU4OTIyODA5MTU2ODEyMDcBMQMCTDU5Mzk4NzExNDczNDg4MzQ5OTczNjE3MjAxMjIyMzg5ODAxNzcxNTIzMDMyNzQzMTEwNDcyNDk5MDU5NDIzODQ5MTU3Njg2OTA4OTVMNDUzMzU2ODI3MTEzNDc4NTI3ODczMTIzNDU3MDM2MTQ4MjY1MTk5Njc0MDc5MTg4ODI4NTg2NDk2Njg4NDAzMjcxNzA0OTgxMTcwOAJNMTA1NjQzODcyODUwNzE1NTU0Njk3NTM5OTA2NjE0MTA4NDAxMTg2MzU5MjU0NjY1OTcwMzcwMTgwNTg3NzAwNDEzNDc1MTg0NjEzNjhNMTI1OTczMjM1NDcyNzc1NzkxNDQ2OTg0OTYzNzIyNDI2MTUzNjgwODU4MDEzMTMzNDMxNTU3MzU1MTEzMzAwMDM4ODQ3Njc5NTc4NTQCATEBMANNMTU3OTE1ODk0NzI1NTY4MjYyNjMyMzE2NDQ3Mjg4NzMzMzc2MjkwMTUyNjk5ODQ2OTk0MDQwNzM2MjM2MDMzNTI1Mzc2Nzg4MTMxNzFMNDU0Nzg2NjQ5OTI0ODg4MTQ0OTY3NjE2MTE1ODAyNDc0ODA2MDQ4NTM3MzI1MDAyOTQyMzkwNDExMzAxNzQyMjUzOTAzNzE2MjUyNwExMXdpYVhOeklqb2lhSFIwY0hNNkx5OXBaQzUwZDJsMFkyZ3VkSFl2YjJGMWRHZ3lJaXcCMmV5SmhiR2NpT2lKU1V6STFOaUlzSW5SNWNDSTZJa3BYVkNJc0ltdHBaQ0k2SWpFaWZRTTIwNzk0Nzg4NTU5NjIwNjY5NTk2MjA2NDU3MDIyOTY2MTc2OTg2Njg4NzI3ODc2MTI4MjIzNjI4MTEzOTE2MzgwOTI3NTAyNzM3OTExCgAAAAAAAABhABHpkQ5JvxqbqCKtqh9M0U5c3o3l62B6ALVOxMq6nsc0y3JlY8Gf1ZoPA976dom6y3JGBUTsry6axfqHcVrtRAy5xu4WMO8+cRFEpkjbBruyKE9ydM++5T/87lA8waSSAA==".to_string()); - - let single_sig = GenericSignature::Signature(Signature::new_secure(intent_msg, &skp)); - let multisig = GenericSignature::MultiSig( - MultiSig::combine(vec![single_sig, zklogin_sig], multisig_pk.clone()).unwrap(), - ); - assert_eq!(Base64::encode(multisig.as_ref()), "AwIAcAEsWrZtlsE3AdGUKJAPag8Tu6HPfMW7gEemeneO9fmNGiJP/rDZu/tL75lr8A22eFDx9K2G1DL4v8XlmuTtCgOaBwUDTTE3MzE4MDg5MTI1OTUyNDIxNzM2MzQyMjYzNzE3OTMyNzE5NDM3NzE3ODQ0MjgyNDEwMTg3OTU3OTg0NzUxOTM5OTQyODk4MjUxMjUwTTExMzczOTY2NjQ1NDY5MTIyNTgyMDc0MDgyMjk1OTg1Mzg4MjU4ODQwNjgxNjE4MjY4NTkzOTc2Njk3MzI1ODkyMjgwOTE1NjgxMjA3ATEDAkw1OTM5ODcxMTQ3MzQ4ODM0OTk3MzYxNzIwMTIyMjM4OTgwMTc3MTUyMzAzMjc0MzExMDQ3MjQ5OTA1OTQyMzg0OTE1NzY4NjkwODk1TDQ1MzM1NjgyNzExMzQ3ODUyNzg3MzEyMzQ1NzAzNjE0ODI2NTE5OTY3NDA3OTE4ODgyODU4NjQ5NjY4ODQwMzI3MTcwNDk4MTE3MDgCTTEwNTY0Mzg3Mjg1MDcxNTU1NDY5NzUzOTkwNjYxNDEwODQwMTE4NjM1OTI1NDY2NTk3MDM3MDE4MDU4NzcwMDQxMzQ3NTE4NDYxMzY4TTEyNTk3MzIzNTQ3Mjc3NTc5MTQ0Njk4NDk2MzcyMjQyNjE1MzY4MDg1ODAxMzEzMzQzMTU1NzM1NTExMzMwMDAzODg0NzY3OTU3ODU0AgExATADTTE1NzkxNTg5NDcyNTU2ODI2MjYzMjMxNjQ0NzI4ODczMzM3NjI5MDE1MjY5OTg0Njk5NDA0MDczNjIzNjAzMzUyNTM3Njc4ODEzMTcxTDQ1NDc4NjY0OTkyNDg4ODE0NDk2NzYxNjExNTgwMjQ3NDgwNjA0ODUzNzMyNTAwMjk0MjM5MDQxMTMwMTc0MjI1MzkwMzcxNjI1MjcBMTF3aWFYTnpJam9pYUhSMGNITTZMeTlwWkM1MGQybDBZMmd1ZEhZdmIyRjFkR2d5SWl3AjJleUpoYkdjaU9pSlNVekkxTmlJc0luUjVjQ0k2SWtwWFZDSXNJbXRwWkNJNklqRWlmUU0yMDc5NDc4ODU1OTYyMDY2OTU5NjIwNjQ1NzAyMjk2NjE3Njk4NjY4ODcyNzg3NjEyODIyMzYyODExMzkxNjM4MDkyNzUwMjczNzkxMQoAAAAAAAAAYQAR6ZEOSb8am6giraofTNFOXN6N5etgegC1TsTKup7HNMtyZWPBn9WaDwPe+naJustyRgVE7K8umsX6h3Fa7UQMucbuFjDvPnERRKZI2wa7sihPcnTPvuU//O5QPMGkkgADAAIADX2rNYyNrapO+gBJp1sHQ2VVsQo2ghm7aA9wVxNJ13UBAzwbaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyLflu6Eag/zG3tLd5CtZRYx9p1t34RovVSn/+uHFiYfcBAQA=".to_string()); -} - -#[test] -fn zklogin_in_multisig_works_with_both_addresses() { - let mut seed = StdRng::from_seed([0; 32]); - let kp: Ed25519KeyPair = get_key_pair_from_rng(&mut seed).1; - let skp: SuiKeyPair = SuiKeyPair::Ed25519(kp); - - // create a new multisig address based on pk1 and pk2 where pk1 is a zklogin - // public identifier, with a crafted unpadded bytes. - let mut bytes = Vec::new(); - let binding = OIDCProvider::Twitch.get_config(); - let iss_bytes = binding.iss.as_bytes(); - bytes.extend([iss_bytes.len() as u8]); - bytes.extend(iss_bytes); - // length here is 31 bytes and left unpadded. - let address_seed = Bn254FrElement::from_str(SHORT_ADDRESS_SEED).unwrap(); - bytes.extend(address_seed.unpadded()); - - let pk1 = PublicKey::ZkLogin(ZkLoginPublicIdentifier(bytes)); - let pk2 = skp.public(); - let multisig_pk = MultiSigPublicKey::new(vec![pk1, pk2.clone()], vec![1; 2], 1).unwrap(); - let multisig_address = SuiAddress::from(&multisig_pk); - - let (kp, _pk, input) = &load_test_vectors("./src/unit_tests/zklogin_test_vectors.json")[0]; - let intent_msg = &IntentMessage::new( - Intent::sui_transaction(), - make_transaction_data(multisig_address), - ); - let user_signature = Signature::new_secure(intent_msg, kp); - - let modified_inputs = - ZkLoginInputs::from_json(&serde_json::to_string(input).unwrap(), SHORT_ADDRESS_SEED) - .unwrap(); - let zklogin_sig = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( - modified_inputs.clone(), - 10, - user_signature, - )); - let multisig = - MultiSig::insecure_new(vec![zklogin_sig.to_compressed().unwrap()], 1, multisig_pk); - - let parsed: ImHashMap = parse_jwks(DEFAULT_JWK_BYTES, &OIDCProvider::Twitch) - .unwrap() - .into_iter() - .collect(); - - let aux_verify_data = VerifyParams::new(parsed, vec![], ZkLoginEnv::Test, true, true); - let res = multisig.verify_claims(intent_msg, multisig_address, &aux_verify_data); - // since the zklogin inputs is crafted, it is expected that the proof verify - // failed, but all checks before passes. - assert!( - matches!(res, Err(crate::error::SuiError::InvalidSignature { error }) if error.contains("General cryptographic error: Groth16 proof verify failed")) - ); - - // initialize zklogin pk (pk1_padd) with padded address seed - let pk1_padded = PublicKey::ZkLogin( - ZkLoginPublicIdentifier::new( - &OIDCProvider::Twitch.get_config().iss, - &Bn254FrElement::from_str(SHORT_ADDRESS_SEED).unwrap(), - ) - .unwrap(), - ); - let multisig_pk_padded = MultiSigPublicKey::new(vec![pk1_padded, pk2], vec![1; 2], 1).unwrap(); - let multisig_address_padded = SuiAddress::from(&multisig_pk_padded); - let modified_inputs_padded = - ZkLoginInputs::from_json(&serde_json::to_string(input).unwrap(), SHORT_ADDRESS_SEED) - .unwrap(); - let intent_msg_padded = &IntentMessage::new( - Intent::sui_transaction(), - make_transaction_data(multisig_address_padded), - ); - let user_signature_padded = Signature::new_secure(intent_msg_padded, kp); - let zklogin_sig_padded = GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new( - modified_inputs_padded.clone(), - 10, - user_signature_padded, - )); - let multisig_padded = MultiSig::insecure_new( - vec![zklogin_sig_padded.to_compressed().unwrap()], - 1, - multisig_pk_padded, - ); - - let res = - multisig_padded.verify_claims(intent_msg_padded, multisig_address_padded, &aux_verify_data); - assert!( - matches!(res, Err(crate::error::SuiError::InvalidSignature { error }) if error.contains("General cryptographic error: Groth16 proof verify failed")) - ); -} - -#[test] -fn test_derive_multisig_address() { - // consistency test with typescript: - // /sdk/typescript/test/unit/cryptography/multisig.test.ts - let pk1 = PublicKey::ZkLogin( - ZkLoginPublicIdentifier::new( - &OIDCProvider::Twitch.get_config().iss, - &Bn254FrElement::from_str(DEFAULT_ADDRESS_SEED).unwrap(), - ) - .unwrap(), - ); - // address seed here is padded with leading 0 to 32 bytes. - let pk2 = PublicKey::ZkLogin( - ZkLoginPublicIdentifier::new( - &OIDCProvider::Twitch.get_config().iss, - &Bn254FrElement::from_str(SHORT_ADDRESS_SEED).unwrap(), - ) - .unwrap(), - ); - assert_eq!(pk1.as_ref().len(), pk2.as_ref().len()); - - let multisig_pk = MultiSigPublicKey::new(vec![pk1, pk2], vec![1, 1], 1).unwrap(); - let multisig_addr = SuiAddress::from(&multisig_pk); - assert_eq!( - multisig_addr, - SuiAddress::from_str("0x77a9fbf3c695d78dd83449a81a9e70aa79a77dbfd6fb72037bf09201c12052cd") - .unwrap() - ); -} diff --git a/crates/sui-types/src/unit_tests/utils.rs b/crates/sui-types/src/unit_tests/utils.rs deleted file mode 100644 index 9efb52356d9..00000000000 --- a/crates/sui-types/src/unit_tests/utils.rs +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use fastcrypto::{ed25519::Ed25519KeyPair, hash::HashFunction, traits::KeyPair as KeypairTraits}; -use rand::{rngs::StdRng, SeedableRng}; -use serde::Deserialize; -use shared_crypto::intent::{Intent, IntentMessage}; - -use crate::{ - base_types::{dbg_addr, ExecutionDigests, ObjectID}, - committee::Committee, - crypto::{ - get_key_pair, get_key_pair_from_rng, AccountKeyPair, AuthorityKeyPair, - AuthorityPublicKeyBytes, DefaultHash, Signature, SignatureScheme, Signer, SuiKeyPair, - }, - gas::GasCostSummary, - messages_checkpoint::{ - CertifiedCheckpointSummary, CheckpointContents, CheckpointSummary, SignedCheckpointSummary, - }, - multisig::{MultiSig, MultiSigPublicKey}, - object::Object, - programmable_transaction_builder::ProgrammableTransactionBuilder, - signature::GenericSignature, - transaction::{ - SenderSignedData, Transaction, TransactionData, TEST_ONLY_GAS_UNIT_FOR_TRANSFER, - }, - zk_login_authenticator::ZkLoginAuthenticator, - SuiAddress, -}; - -#[derive(Deserialize)] -pub struct TestData { - pub zklogin_inputs: String, - pub kp: String, - pub pk_bigint: String, - pub salt: String, - pub address_seed: String, -} - -pub fn make_committee_key(rand: &mut R) -> (Vec, Committee) -where - R: rand::CryptoRng + rand::RngCore, -{ - make_committee_key_num(4, rand) -} - -pub fn make_committee_key_num(num: usize, rand: &mut R) -> (Vec, Committee) -where - R: rand::CryptoRng + rand::RngCore, -{ - let mut authorities: BTreeMap = BTreeMap::new(); - let mut keys = Vec::new(); - - for _ in 0..num { - let (_, inner_authority_key): (_, AuthorityKeyPair) = get_key_pair_from_rng(rand); - authorities.insert( - // address - AuthorityPublicKeyBytes::from(inner_authority_key.public()), - // voting right - 1, - ); - keys.push(inner_authority_key); - } - - let committee = Committee::new_for_testing_with_normalized_voting_power(0, authorities); - (keys, committee) -} - -// Creates a fake sender-signed transaction for testing. This transaction will -// not actually work. -pub fn create_fake_transaction() -> Transaction { - let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); - let recipient = dbg_addr(2); - let object_id = ObjectID::random(); - let object = Object::immutable_with_id_for_testing(object_id); - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - builder.transfer_sui(recipient, None); - builder.finish() - }; - let data = TransactionData::new_programmable( - sender, - vec![object.compute_object_reference()], - pt, - TEST_ONLY_GAS_UNIT_FOR_TRANSFER, // gas price is 1 - 1, - ); - to_sender_signed_transaction(data, &sender_key) -} - -pub fn make_transaction_data(sender: SuiAddress) -> TransactionData { - let object = Object::immutable_with_id_for_testing(ObjectID::random_from_rng( - &mut StdRng::from_seed([0; 32]), - )); - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - builder.transfer_sui(dbg_addr(2), None); - builder.finish() - }; - TransactionData::new_programmable( - sender, - vec![object.compute_object_reference()], - pt, - TEST_ONLY_GAS_UNIT_FOR_TRANSFER, // gas price is 1 - 1, - ) -} - -/// Make a user signed transaction with the given sender and its keypair. This -/// is not verified or signed by authority. -pub fn make_transaction(sender: SuiAddress, kp: &SuiKeyPair) -> Transaction { - let data = make_transaction_data(sender); - Transaction::from_data_and_signer(data, vec![kp]) -} - -// This is used to sign transaction with signer using default Intent. -pub fn to_sender_signed_transaction( - data: TransactionData, - signer: &dyn Signer, -) -> Transaction { - to_sender_signed_transaction_with_multi_signers(data, vec![signer]) -} - -pub fn to_sender_signed_transaction_with_multi_signers( - data: TransactionData, - signers: Vec<&dyn Signer>, -) -> Transaction { - Transaction::from_data_and_signer(data, signers) -} - -pub fn mock_certified_checkpoint<'a>( - keys: impl Iterator, - committee: Committee, - seq_num: u64, -) -> CertifiedCheckpointSummary { - let contents = - CheckpointContents::new_with_digests_only_for_tests([ExecutionDigests::random()]); - - let summary = CheckpointSummary::new( - committee.epoch, - seq_num, - 0, - &contents, - None, - GasCostSummary::default(), - None, - 0, - ); - - let sign_infos: Vec<_> = keys - .map(|k| { - let name = k.public().into(); - - SignedCheckpointSummary::sign(committee.epoch, &summary, k, name) - }) - .collect(); - - CertifiedCheckpointSummary::new(summary, sign_infos, &committee).expect("Cert is OK") -} - -mod zk_login { - use fastcrypto_zkp::bn254::zk_login::ZkLoginInputs; - use shared_crypto::intent::PersonalMessage; - - use super::*; - use crate::{crypto::PublicKey, zk_login_util::get_zklogin_inputs}; - pub static DEFAULT_ADDRESS_SEED: &str = - "20794788559620669596206457022966176986688727876128223628113916380927502737911"; - pub static SHORT_ADDRESS_SEED: &str = - "380704556853533152350240698167704405529973457670972223618755249929828551006"; - - pub fn load_test_vectors(path: &str) -> Vec<(SuiKeyPair, PublicKey, ZkLoginInputs)> { - // read in test files that has a list of matching zklogin_inputs and its - // ephemeral private keys. - let file = std::fs::File::open(path).expect("Unable to open file"); - - let test_datum: Vec = serde_json::from_reader(file).unwrap(); - let mut res = vec![]; - for test in test_datum { - let kp = SuiKeyPair::decode(&test.kp).unwrap(); - let inputs = - ZkLoginInputs::from_json(&test.zklogin_inputs, &test.address_seed).unwrap(); - let pk_zklogin = PublicKey::from_zklogin_inputs(&inputs).unwrap(); - res.push((kp, pk_zklogin, inputs)); - } - res - } - - pub fn get_zklogin_user_address() -> SuiAddress { - thread_local! { - static USER_ADDRESS: SuiAddress = { - // Derive user address manually: Blake2b_256 hash of [zklogin_flag || iss_bytes_length || iss_bytes || address seed in bytes]) - let mut hasher = DefaultHash::default(); - hasher.update([SignatureScheme::ZkLoginAuthenticator.flag()]); - let inputs = get_zklogin_inputs(); - let iss_bytes = inputs.get_iss().as_bytes(); - hasher.update([iss_bytes.len() as u8]); - hasher.update(iss_bytes); - hasher.update(inputs.get_address_seed().unpadded()); - SuiAddress::from_bytes(hasher.finalize().digest).unwrap() - }; - } - USER_ADDRESS.with(|a| *a) - } - - fn get_zklogin_user_key() -> SuiKeyPair { - SuiKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))) - } - - fn get_inputs_with_bad_address_seed() -> ZkLoginInputs { - thread_local! { - static ZKLOGIN_INPUTS: ZkLoginInputs = ZkLoginInputs::from_json("{\"proofPoints\":{\"a\":[\"17276311605393076686048412951904952585208929623427027497902331765285829154985\",\"2195957390349729412627479867125563520760023859523358729791332629632025124364\",\"1\"],\"b\":[[\"10285059021604767951039627893758482248204478992077021270802057708215366770814\",\"20086937595807139308592304218494658586282197458549968652049579308384943311509\"],[\"7481123765095657256931104563876569626157448050870256177668773471703520958615\",\"11912752790863530118410797223176516777328266521602785233083571774104055633375\"],[\"1\",\"0\"]],\"c\":[\"15742763887654796666500488588763616323599882100448686869458326409877111249163\",\"6112916537574993759490787691149241262893771114597679488354854987586060572876\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", SHORT_ADDRESS_SEED).unwrap(); } - ZKLOGIN_INPUTS.with(|a| a.clone()) - } - - pub fn get_legacy_zklogin_user_address() -> SuiAddress { - thread_local! { - static USER_ADDRESS: SuiAddress = { - let inputs = get_inputs_with_bad_address_seed(); - SuiAddress::from(&PublicKey::from_zklogin_inputs(&inputs).unwrap()) - }; - } - USER_ADDRESS.with(|a| *a) - } - - pub fn sign_zklogin_personal_msg(data: PersonalMessage) -> (SuiAddress, GenericSignature) { - let inputs = get_zklogin_inputs(); - let msg = IntentMessage::new(Intent::personal_message(), data); - let s = Signature::new_secure(&msg, &get_zklogin_user_key()); - let authenticator = - GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new(inputs, 10, s)); - let address = get_zklogin_user_address(); - (address, authenticator) - } - - pub fn sign_zklogin_tx_with_default_proof( - data: TransactionData, - legacy: bool, - ) -> (SuiAddress, Transaction, GenericSignature) { - let inputs = if legacy { - get_inputs_with_bad_address_seed() - } else { - get_zklogin_inputs() - }; - - sign_zklogin_tx(&get_zklogin_user_key(), inputs, data) - } - - pub fn sign_zklogin_tx( - user_key: &SuiKeyPair, - proof: ZkLoginInputs, - data: TransactionData, - ) -> (SuiAddress, Transaction, GenericSignature) { - let tx = Transaction::from_data_and_signer(data.clone(), vec![user_key]); - - let s = match tx.inner().tx_signatures.first().unwrap() { - GenericSignature::Signature(s) => s, - _ => panic!("Expected a signature"), - }; - - // Construct the authenticator with all user submitted components. - let authenticator = - GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new(proof, 10, s.clone())); - - let tx = Transaction::new(SenderSignedData::new( - tx.transaction_data().clone(), - Intent::sui_transaction(), - vec![authenticator.clone()], - )); - (data.execution_parts().1, tx, authenticator) - } - - pub fn make_zklogin_tx( - address: SuiAddress, - legacy: bool, - ) -> (SuiAddress, Transaction, GenericSignature) { - let data = make_transaction_data(address); - sign_zklogin_tx_with_default_proof(data, legacy) - } - - pub fn keys() -> Vec { - let mut seed = StdRng::from_seed([0; 32]); - let kp1: SuiKeyPair = SuiKeyPair::Ed25519(get_key_pair_from_rng(&mut seed).1); - let kp2: SuiKeyPair = SuiKeyPair::Secp256k1(get_key_pair_from_rng(&mut seed).1); - let kp3: SuiKeyPair = SuiKeyPair::Secp256r1(get_key_pair_from_rng(&mut seed).1); - vec![kp1, kp2, kp3] - } - - pub fn make_upgraded_multisig_tx() -> Transaction { - let keys = keys(); - let pk1 = &keys[0].public(); - let pk2 = &keys[1].public(); - let pk3 = &keys[2].public(); - - let multisig_pk = MultiSigPublicKey::new( - vec![pk1.clone(), pk2.clone(), pk3.clone()], - vec![1, 1, 1], - 2, - ) - .unwrap(); - let addr = SuiAddress::from(&multisig_pk); - let tx = make_transaction(addr, &keys[0]); - - let msg = IntentMessage::new(Intent::sui_transaction(), tx.transaction_data().clone()); - let sig1 = Signature::new_secure(&msg, &keys[0]).into(); - let sig2 = Signature::new_secure(&msg, &keys[1]).into(); - - // Any 2 of 3 signatures verifies ok. - let multi_sig1 = MultiSig::combine(vec![sig1, sig2], multisig_pk).unwrap(); - Transaction::new(SenderSignedData::new( - tx.transaction_data().clone(), - Intent::sui_transaction(), - vec![GenericSignature::MultiSig(multi_sig1)], - )) - } -} -pub use zk_login::*; diff --git a/crates/sui-types/src/versioned.rs b/crates/sui-types/src/versioned.rs deleted file mode 100644 index 558ab71987c..00000000000 --- a/crates/sui-types/src/versioned.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use serde::{Deserialize, Serialize}; - -use crate::id::UID; - -/// Rust version of the Move sui::versioned::Versioned type. -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct Versioned { - pub id: UID, - pub version: u64, -} diff --git a/crates/sui-types/tests/serde_tests.rs b/crates/sui-types/tests/serde_tests.rs deleted file mode 100644 index af5b1440e21..00000000000 --- a/crates/sui-types/tests/serde_tests.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::str::FromStr; - -use move_core_types::language_storage::StructTag; -use serde::Serialize; -use serde_json::Value; -use serde_with::serde_as; -use sui_types::{base_types::ObjectType, parse_sui_struct_tag, sui_serde::SuiStructTag}; - -#[test] -fn test_struct_tag_serde() { - let tag = parse_sui_struct_tag("0x7f89cdffd8968affa0b47bef91adc5314e19509080470c45bfd434cd83a766b::suifrens::SuiFren<0x7f89cdffd8968affa0b47bef91adc5314e19509080470c45bfd434cd83a766b::capy::Capy>").unwrap(); - #[serde_as] - #[derive(Serialize)] - struct TestStructTag(#[serde_as(as = "SuiStructTag")] StructTag); - - // serialize to json should not trim the leading 0 - let Value::String(json) = serde_json::to_value(&TestStructTag(tag.clone())).unwrap() else { - panic!() - }; - assert_eq!( - json, - "0x07f89cdffd8968affa0b47bef91adc5314e19509080470c45bfd434cd83a766b::suifrens::SuiFren<0x07f89cdffd8968affa0b47bef91adc5314e19509080470c45bfd434cd83a766b::capy::Capy>" - ); - - let tag2 = parse_sui_struct_tag(&json).unwrap(); - assert_eq!(tag, tag2); -} - -#[test] -fn test_object_type_to_string() { - let object_type = ObjectType::from_str( - "0x1a1aa18691be519899bf5187f5ce80af629407dd4f68d4175b99f4dc09497c1::custodian::AccountCap", - ) - .unwrap(); - assert_eq!( - object_type.to_string(), - "0x01a1aa18691be519899bf5187f5ce80af629407dd4f68d4175b99f4dc09497c1::custodian::AccountCap" - ); -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/Cargo.toml b/crates/sui-upgrade-compatibility-transactional-tests/Cargo.toml deleted file mode 100644 index 976ecbeb8f4..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "sui-upgrade-compatibility-transactional-tests" -version = "0.1.0" -authors = ["Mysten Labs "] -description = "Transactional tests for package upgrade compatibility checking" -license = "Apache-2.0" -publish = false -edition = "2021" - -[dev-dependencies] -anyhow.workspace = true -datatest-stable.workspace = true -insta.workspace = true -move-compiler.workspace = true -move-package.workspace = true -move-binary-format.workspace = true -move-command-line-common.workspace = true -sui-move-build.workspace = true - -[[test]] -name = "tests" -harness = false - -[dependencies] diff --git a/crates/sui-upgrade-compatibility-transactional-tests/src/lib.rs b/crates/sui-upgrade-compatibility-transactional-tests/src/lib.rs deleted file mode 100644 index 07fe81c224d..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#![forbid(unsafe_code)] - -// Empty src/lib.rs to get rusty-tags working. diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_name_change/base/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_name_change/base/sources/base.move deleted file mode 100644 index b53c3036449..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_name_change/base/sources/base.move +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - - const A: u64 = 0; - - struct X { - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { A } - fun private_fun(): u64 { A } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_name_change/upgraded/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_name_change/upgraded/sources/base.move deleted file mode 100644 index 60720a571e4..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_name_change/upgraded/sources/base.move +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - - const B: u64 = 0; - - struct X { - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { B } - fun private_fun(): u64 { B } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_value_changed/base/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_value_changed/base/sources/base.move deleted file mode 100644 index b53c3036449..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_value_changed/base/sources/base.move +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - - const A: u64 = 0; - - struct X { - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { A } - fun private_fun(): u64 { A } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_value_changed/upgraded/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_value_changed/upgraded/sources/base.move deleted file mode 100644 index ef254a19c1c..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/constant_value_changed/upgraded/sources/base.move +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - - const A: u64 = 1; - - struct X { - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { A } - fun private_fun(): u64 { A } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/sources/base.move deleted file mode 100644 index 276e235b15d..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/sources/base.move +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - friend base::friend_module; - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } - public(friend) entry fun friend_fun(): u64 { 0 } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/sources/friend.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/sources/friend.move deleted file mode 100644 index 707e2ae8c4e..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/base/sources/friend.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::friend_module { - public fun call_friend(): u64 { base::base_module::friend_fun() } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/sources/base.move deleted file mode 100644 index d709b3b78ce..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/sources/base.move +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - friend base::friend_module; - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } - public(friend) fun friend_fun(): u64 { 0 } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/sources/friend.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/sources/friend.move deleted file mode 100644 index 707e2ae8c4e..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_entry_changed/upgraded/sources/friend.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::friend_module { - public fun call_friend(): u64 { base::base_module::friend_fun() } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/sources/base.move deleted file mode 100644 index d709b3b78ce..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/sources/base.move +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - friend base::friend_module; - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } - public(friend) fun friend_fun(): u64 { 0 } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/sources/friend.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/sources/friend.move deleted file mode 100644 index 707e2ae8c4e..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/base/sources/friend.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::friend_module { - public fun call_friend(): u64 { base::base_module::friend_fun() } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/sources/base.move deleted file mode 100644 index f4a014f9745..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/sources/base.move +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - friend base::friend_module; - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } - public(friend) fun friend_fun(x: u64): u64 { x } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/sources/friend.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/sources/friend.move deleted file mode 100644 index 4968d92e0b7..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/friend_function_change/upgraded/sources/friend.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::friend_module { - public fun call_friend(): u64 { base::base_module::friend_fun(0) } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/base/Move.toml b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/base/Move.toml deleted file mode 100644 index 4c1902a9dcd..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/base/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "base" -version = "0.0.1" - -[dependencies] -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -base = "0x0" -std = "0x1" diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/base/sources/ascii.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/base/sources/ascii.move deleted file mode 100644 index 505721eb7ec..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/base/sources/ascii.move +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// The `ASCII` module defines basic string and char newtypes in Move that verify -/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. -module base::ascii { - use std::vector; - use std::option::{Self, Option}; - - /// An invalid ASCII character was encountered when creating an ASCII string. - const EINVALID_ASCII_CHARACTER: u64 = 0x10000; - - /// The `String` struct holds a vector of bytes that all represent - /// valid ASCII characters. Note that these ASCII characters may not all - /// be printable. To determine if a `String` contains only "printable" - /// characters you should use the `all_characters_printable` predicate - /// defined in this module. - struct String has copy, drop, store { - bytes: vector, - } - - /// An ASCII character. - struct Char has copy, drop, store { - byte: u8, - } - - /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. - public fun char(byte: u8): Char { - assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); - Char { byte } - } - - /// Convert a vector of bytes `bytes` into an `String`. Aborts if - /// `bytes` contains non-ASCII characters. - public fun string(bytes: vector): String { - let x = try_string(bytes); - assert!( - option::is_some(&x), - EINVALID_ASCII_CHARACTER - ); - option::destroy_some(x) - } - /// Convert a vector of bytes `bytes` into an `String`. Returns - /// `Some()` if the `bytes` contains all valid ASCII - /// characters. Otherwise returns `None`. - public fun try_string(bytes: vector): Option { - let len = vector::length(&bytes); - let i = 0; - while (i < len) { - let possible_byte = *vector::borrow(&bytes, i); - if (!is_valid_char(possible_byte)) return option::none(); - i = i + 1; - }; - option::some(String { bytes }) - } - - /// Returns `true` if all characters in `string` are printable characters - /// Returns `false` otherwise. Not all `String`s are printable strings. - public fun all_characters_printable(string: &String): bool { - let len = vector::length(&string.bytes); - let i = 0; - while (i < len) { - let byte = *vector::borrow(&string.bytes, i); - if (!is_printable_char(byte)) return false; - i = i + 1; - }; - true - } - - public fun push_char(string: &mut String, char: Char) { - vector::push_back(&mut string.bytes, char.byte); - } - - public fun pop_char(string: &mut String): Char { - Char { byte: vector::pop_back(&mut string.bytes) } - } - - public fun length(string: &String): u64 { - vector::length(as_bytes(string)) - } - - /// Get the inner bytes of the `string` as a reference - public fun as_bytes(string: &String): &vector { - &string.bytes - } - - /// Unpack the `string` to get its backing bytes - public fun into_bytes(string: String): vector { - let String { bytes } = string; - bytes - } - - /// Unpack the `char` into its underlying byte. - public fun byte(char: Char): u8 { - let Char { byte } = char; - byte - } - - /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. - public fun is_valid_char(b: u8): bool { - b <= 0x7F - } - - /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. - public fun is_printable_char(byte: u8): bool { - byte >= 0x20 && // Disallow metacharacters - byte <= 0x7E // Don't allow DEL metacharacter - } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/upgraded/Move.toml b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/upgraded/Move.toml deleted file mode 100644 index 4c1902a9dcd..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/upgraded/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "base" -version = "0.0.1" - -[dependencies] -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -base = "0x0" -std = "0x1" diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/upgraded/sources/ascii.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/upgraded/sources/ascii.move deleted file mode 100644 index 70d68ade0d7..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check/upgraded/sources/ascii.move +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// The `ASCII` module defines basic string and char newtypes in Move that verify -/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. -module base::ascii { - use std::option::{Option, Self}; - use std::vector; - - /// An ASCII character. - struct Char has copy, drop, store { - byte: u8, - } - - /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. - public fun char(byte: u8): Char { - assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); - Char { byte } - } - - /// Returns `true` if all characters in `string` are printable characters - /// Returns `false` otherwise. Not all `String`s are printable strings. - public fun all_characters_printable(string: &String): bool { - let len = vector::length(&string.bytes); - let i = 0; - while (i < len) { - let byte = *vector::borrow(&string.bytes, i); - if (!is_printable_char(byte)) return false; - i = i + 1; - }; - true - } - - /// Convert a vector of bytes `bytes` into an `String`. Returns - /// `Some()` if the `bytes` contains all valid ASCII - /// characters. Otherwise returns `None`. - public fun try_string(bytes: vector): Option { - let len = vector::length(&bytes); - let i = 0; - while (i < len) { - let possible_byte = *vector::borrow(&bytes, i); - if (!is_valid_char(possible_byte)) return option::none(); - i = i + 1; - }; - option::some(String { bytes }) - } - - public fun push_char(string: &mut String, char: Char) { - vector::push_back(&mut string.bytes, char.byte); - } - - /// The `String` struct holds a vector of bytes that all represent - /// valid ASCII characters. Note that these ASCII characters may not all - /// be printable. To determine if a `String` contains only "printable" - /// characters you should use the `all_characters_printable` predicate - /// defined in this module. - struct String has copy, drop, store { - bytes: vector, - } - - /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. - public fun is_printable_char(byte: u8): bool { - byte >= 0x20 && // Disallow metacharacters - byte <= 0x7E // Don't allow DEL metacharacter - } - - public fun pop_char(string: &mut String): Char { - Char { byte: vector::pop_back(&mut string.bytes) } - } - - /// Convert a vector of bytes `bytes` into an `String`. Aborts if - /// `bytes` contains non-ASCII characters. - public fun string(bytes: vector): String { - let x = try_string(bytes); - assert!( - option::is_some(&x), - EINVALID_ASCII_CHARACTER - ); - option::destroy_some(x) - } - - public fun length(string: &String): u64 { - vector::length(as_bytes(string)) - } - - /// Get the inner bytes of the `string` as a reference - public fun as_bytes(string: &String): &vector { - &string.bytes - } - - /// Unpack the `string` to get its backing bytes - public fun into_bytes(string: String): vector { - let String { bytes } = string; - bytes - } - - /// Unpack the `char` into its underlying byte. - public fun byte(char: Char): u8 { - let Char { byte } = char; - byte - } - - /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. - public fun is_valid_char(b: u8): bool { - b <= 0x7F - } - - /// An invalid ASCII character was encountered when creating an ASCII string. - const EINVALID_ASCII_CHARACTER: u64 = 0x10000; -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/base/Move.toml b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/base/Move.toml deleted file mode 100644 index 4c1902a9dcd..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/base/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "base" -version = "0.0.1" - -[dependencies] -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -base = "0x0" -std = "0x1" diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/base/sources/ascii.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/base/sources/ascii.move deleted file mode 100644 index 9c0956624d0..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/base/sources/ascii.move +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// The `ASCII` module defines basic string and char newtypes in Move that verify -/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. -module base::ascii { - use std::vector; - use std::option::{Self, Option}; - - /// An invalid ASCII character was encountered when creating an ASCII string. - const EINVALID_ASCII_CHARACTER: u64 = 0x10000; - - /// The `String` struct holds a vector of bytes that all represent - /// valid ASCII characters. Note that these ASCII characters may not all - /// be printable. To determine if a `String` contains only "printable" - /// characters you should use the `all_characters_printable` predicate - /// defined in this module. - struct String has copy, drop, store { - bytes: vector, - } - - /// An ASCII character. - struct Char has copy, drop, store { - byte: u8, - } - - /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. - public fun char(byte: u8): Char { - assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); - Char { byte } - } - - /// Convert a vector of bytes `bytes` into an `String`. Aborts if - /// `bytes` contains non-ASCII characters. - public fun string(bytes: vector): String { - let x = try_string(bytes); - assert!( - option::is_some(&x), - EINVALID_ASCII_CHARACTER - ); - option::destroy_some(x) - } - - /// Convert a vector of bytes `bytes` into an `String`. Returns - /// `Some()` if the `bytes` contains all valid ASCII - /// characters. Otherwise returns `None`. - public fun try_string(bytes: vector): Option { - let len = vector::length(&bytes); - let i = 0; - while (i < len) { - let possible_byte = *vector::borrow(&bytes, i); - if (!is_valid_char(possible_byte)) return option::none(); - i = i + 1; - }; - option::some(String { bytes }) - } - - /// Returns `true` if all characters in `string` are printable characters - /// Returns `false` otherwise. Not all `String`s are printable strings. - public fun all_characters_printable(string: &String): bool { - let len = vector::length(&string.bytes); - let i = 0; - while (i < len) { - let byte = *vector::borrow(&string.bytes, i); - if (!is_printable_char(byte)) return false; - i = i + 1; - }; - true - } - - public fun push_char(string: &mut String, char: Char) { - vector::push_back(&mut string.bytes, char.byte); - } - - public fun pop_char(string: &mut String): Char { - Char { byte: vector::pop_back(&mut string.bytes) } - } - - public fun length(string: &String): u64 { - vector::length(as_bytes(string)) - } - - /// Get the inner bytes of the `string` as a reference - public fun as_bytes(string: &String): &vector { - &string.bytes - } - - /// Unpack the `string` to get its backing bytes - public fun into_bytes(string: String): vector { - let String { bytes } = string; - bytes - } - - /// Unpack the `char` into its underlying byte. - public fun byte(char: Char): u8 { - let Char { byte } = char; - byte - } - - /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. - public fun is_valid_char(b: u8): bool { - b <= 0x7F - } - - /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. - public fun is_printable_char(byte: u8): bool { - byte >= 0x20 && // Disallow metacharacters - byte <= 0x7E // Don't allow DEL metacharacter - } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/upgraded/Move.toml b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/upgraded/Move.toml deleted file mode 100644 index 4c1902a9dcd..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/upgraded/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "base" -version = "0.0.1" - -[dependencies] -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -base = "0x0" -std = "0x1" diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/upgraded/sources/ascii.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/upgraded/sources/ascii.move deleted file mode 100644 index ec3f8b50823..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_alpha_rename/upgraded/sources/ascii.move +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// The `ASCII` module defines basic string and char newtypes in Move that verify -/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. -module base::ascii { - use std::option::{Option, Self}; - use std::vector; - - /// An ASCII character. - struct Char has copy, drop, store { - byte: u8, - } - - /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. - public fun char(byte: u8): Char { - assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); - Char { byte } - } - - /// Returns `true` if all characters in `string` are printable characters - /// Returns `false` otherwise. Not all `String`s are printable strings. - public fun all_characters_printable(my_string: &String): bool { // !!!! <<<<<<<< This has been renamed from "string" to "my_string" - let length = vector::length(&my_string.bytes); // !!!! <<<<<<<< This has been renamed from "len" to "length" - let i = 0; - while (i < length) { - let byte = *vector::borrow(&my_string.bytes, i); - if (!is_printable_char(byte)) return false; - i = i + 1; - }; - true - } - - /// Convert a vector of bytes `bytes` into an `String`. Returns - /// `Some()` if the `bytes` contains all valid ASCII - /// characters. Otherwise returns `None`. - public fun try_string(bytes: vector): Option { - let len = vector::length(&bytes); - let i = 0; - while (i < len) { - let possible_byte = *vector::borrow(&bytes, i); - if (!is_valid_char(possible_byte)) return option::none(); - i = i + 1; - }; - option::some(String { bytes }) - } - - public fun push_char(string: &mut String, char: Char) { - vector::push_back(&mut string.bytes, char.byte); - } - - /// The `String` struct holds a vector of bytes that all represent - /// valid ASCII characters. Note that these ASCII characters may not all - /// be printable. To determine if a `String` contains only "printable" - /// characters you should use the `all_characters_printable` predicate - /// defined in this module. - struct String has copy, drop, store { - bytes: vector, - } - - /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. - public fun is_printable_char(byte: u8): bool { - byte >= 0x20 && // Disallow metacharacters - byte <= 0x7E // Don't allow DEL metacharacter - } - - public fun pop_char(string: &mut String): Char { - Char { byte: vector::pop_back(&mut string.bytes) } - } - - /// Convert a vector of bytes `bytes` into an `String`. Aborts if - /// `bytes` contains non-ASCII characters. - public fun string(bytes: vector): String { - let x = try_string(bytes); - assert!( - option::is_some(&x), - EINVALID_ASCII_CHARACTER - ); - option::destroy_some(x) - } - - public fun length(string: &String): u64 { - vector::length(as_bytes(string)) - } - - /// Get the inner bytes of the `string` as a reference - public fun as_bytes(string: &String): &vector { - &string.bytes - } - - /// Unpack the `string` to get its backing bytes - public fun into_bytes(string: String): vector { - let String { bytes } = string; - bytes - } - - /// Unpack the `char` into its underlying byte. - public fun byte(char: Char): u8 { - let Char { byte } = char; - byte - } - - /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. - public fun is_valid_char(b: u8): bool { - b <= 0x7F - } - - /// An invalid ASCII character was encountered when creating an ASCII string. - const EINVALID_ASCII_CHARACTER: u64 = 0x10000; -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/base/Move.toml b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/base/Move.toml deleted file mode 100644 index 4c1902a9dcd..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/base/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "base" -version = "0.0.1" - -[dependencies] -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -base = "0x0" -std = "0x1" diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/base/sources/ascii.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/base/sources/ascii.move deleted file mode 100644 index 9c0956624d0..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/base/sources/ascii.move +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// The `ASCII` module defines basic string and char newtypes in Move that verify -/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. -module base::ascii { - use std::vector; - use std::option::{Self, Option}; - - /// An invalid ASCII character was encountered when creating an ASCII string. - const EINVALID_ASCII_CHARACTER: u64 = 0x10000; - - /// The `String` struct holds a vector of bytes that all represent - /// valid ASCII characters. Note that these ASCII characters may not all - /// be printable. To determine if a `String` contains only "printable" - /// characters you should use the `all_characters_printable` predicate - /// defined in this module. - struct String has copy, drop, store { - bytes: vector, - } - - /// An ASCII character. - struct Char has copy, drop, store { - byte: u8, - } - - /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. - public fun char(byte: u8): Char { - assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); - Char { byte } - } - - /// Convert a vector of bytes `bytes` into an `String`. Aborts if - /// `bytes` contains non-ASCII characters. - public fun string(bytes: vector): String { - let x = try_string(bytes); - assert!( - option::is_some(&x), - EINVALID_ASCII_CHARACTER - ); - option::destroy_some(x) - } - - /// Convert a vector of bytes `bytes` into an `String`. Returns - /// `Some()` if the `bytes` contains all valid ASCII - /// characters. Otherwise returns `None`. - public fun try_string(bytes: vector): Option { - let len = vector::length(&bytes); - let i = 0; - while (i < len) { - let possible_byte = *vector::borrow(&bytes, i); - if (!is_valid_char(possible_byte)) return option::none(); - i = i + 1; - }; - option::some(String { bytes }) - } - - /// Returns `true` if all characters in `string` are printable characters - /// Returns `false` otherwise. Not all `String`s are printable strings. - public fun all_characters_printable(string: &String): bool { - let len = vector::length(&string.bytes); - let i = 0; - while (i < len) { - let byte = *vector::borrow(&string.bytes, i); - if (!is_printable_char(byte)) return false; - i = i + 1; - }; - true - } - - public fun push_char(string: &mut String, char: Char) { - vector::push_back(&mut string.bytes, char.byte); - } - - public fun pop_char(string: &mut String): Char { - Char { byte: vector::pop_back(&mut string.bytes) } - } - - public fun length(string: &String): u64 { - vector::length(as_bytes(string)) - } - - /// Get the inner bytes of the `string` as a reference - public fun as_bytes(string: &String): &vector { - &string.bytes - } - - /// Unpack the `string` to get its backing bytes - public fun into_bytes(string: String): vector { - let String { bytes } = string; - bytes - } - - /// Unpack the `char` into its underlying byte. - public fun byte(char: Char): u8 { - let Char { byte } = char; - byte - } - - /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. - public fun is_valid_char(b: u8): bool { - b <= 0x7F - } - - /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. - public fun is_printable_char(byte: u8): bool { - byte >= 0x20 && // Disallow metacharacters - byte <= 0x7E // Don't allow DEL metacharacter - } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/upgraded/Move.toml b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/upgraded/Move.toml deleted file mode 100644 index 4c1902a9dcd..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/upgraded/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "base" -version = "0.0.1" - -[dependencies] -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -base = "0x0" -std = "0x1" diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/upgraded/sources/ascii.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/upgraded/sources/ascii.move deleted file mode 100644 index 6ad64af7cad..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_equality_check_local_shuffle/upgraded/sources/ascii.move +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// The `ASCII` module defines basic string and char newtypes in Move that verify -/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. -module base::ascii { - use std::option::{Option, Self}; - use std::vector; - - /// An ASCII character. - struct Char has copy, drop, store { - byte: u8, - } - - /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. - public fun char(byte: u8): Char { - assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); - Char { byte } - } - - /// Returns `true` if all characters in `string` are printable characters - /// Returns `false` otherwise. Not all `String`s are printable strings. - public fun all_characters_printable(string: &String): bool { - let i = 0; - let len = vector::length(&string.bytes); - while (i < len) { - let byte = *vector::borrow(&string.bytes, i); - if (!is_printable_char(byte)) return false; - i = i + 1; - }; - true - } - - /// Convert a vector of bytes `bytes` into an `String`. Returns - /// `Some()` if the `bytes` contains all valid ASCII - /// characters. Otherwise returns `None`. - public fun try_string(bytes: vector): Option { - let i = 0; - let len = vector::length(&bytes); - while (i < len) { - let possible_byte = *vector::borrow(&bytes, i); - if (!is_valid_char(possible_byte)) return option::none(); - i = i + 1; - }; - option::some(String { bytes }) - } - - public fun push_char(string: &mut String, char: Char) { - vector::push_back(&mut string.bytes, char.byte); - } - - /// The `String` struct holds a vector of bytes that all represent - /// valid ASCII characters. Note that these ASCII characters may not all - /// be printable. To determine if a `String` contains only "printable" - /// characters you should use the `all_characters_printable` predicate - /// defined in this module. - struct String has copy, drop, store { - bytes: vector, - } - - /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. - public fun is_printable_char(byte: u8): bool { - byte >= 0x20 && // Disallow metacharacters - byte <= 0x7E // Don't allow DEL metacharacter - } - - public fun pop_char(string: &mut String): Char { - Char { byte: vector::pop_back(&mut string.bytes) } - } - - /// Convert a vector of bytes `bytes` into an `String`. Aborts if - /// `bytes` contains non-ASCII characters. - public fun string(bytes: vector): String { - let x = try_string(bytes); - assert!( - option::is_some(&x), - EINVALID_ASCII_CHARACTER - ); - option::destroy_some(x) - } - - public fun length(string: &String): u64 { - vector::length(as_bytes(string)) - } - - /// Get the inner bytes of the `string` as a reference - public fun as_bytes(string: &String): &vector { - &string.bytes - } - - /// Unpack the `string` to get its backing bytes - public fun into_bytes(string: String): vector { - let String { bytes } = string; - bytes - } - - /// Unpack the `char` into its underlying byte. - public fun byte(char: Char): u8 { - let Char { byte } = char; - byte - } - - /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. - public fun is_valid_char(b: u8): bool { - b <= 0x7F - } - - /// An invalid ASCII character was encountered when creating an ASCII string. - const EINVALID_ASCII_CHARACTER: u64 = 0x10000; -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/base/Move.toml b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/base/Move.toml deleted file mode 100644 index 4c1902a9dcd..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/base/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "base" -version = "0.0.1" - -[dependencies] -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -base = "0x0" -std = "0x1" diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/base/sources/ascii.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/base/sources/ascii.move deleted file mode 100644 index 9c0956624d0..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/base/sources/ascii.move +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// The `ASCII` module defines basic string and char newtypes in Move that verify -/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. -module base::ascii { - use std::vector; - use std::option::{Self, Option}; - - /// An invalid ASCII character was encountered when creating an ASCII string. - const EINVALID_ASCII_CHARACTER: u64 = 0x10000; - - /// The `String` struct holds a vector of bytes that all represent - /// valid ASCII characters. Note that these ASCII characters may not all - /// be printable. To determine if a `String` contains only "printable" - /// characters you should use the `all_characters_printable` predicate - /// defined in this module. - struct String has copy, drop, store { - bytes: vector, - } - - /// An ASCII character. - struct Char has copy, drop, store { - byte: u8, - } - - /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. - public fun char(byte: u8): Char { - assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); - Char { byte } - } - - /// Convert a vector of bytes `bytes` into an `String`. Aborts if - /// `bytes` contains non-ASCII characters. - public fun string(bytes: vector): String { - let x = try_string(bytes); - assert!( - option::is_some(&x), - EINVALID_ASCII_CHARACTER - ); - option::destroy_some(x) - } - - /// Convert a vector of bytes `bytes` into an `String`. Returns - /// `Some()` if the `bytes` contains all valid ASCII - /// characters. Otherwise returns `None`. - public fun try_string(bytes: vector): Option { - let len = vector::length(&bytes); - let i = 0; - while (i < len) { - let possible_byte = *vector::borrow(&bytes, i); - if (!is_valid_char(possible_byte)) return option::none(); - i = i + 1; - }; - option::some(String { bytes }) - } - - /// Returns `true` if all characters in `string` are printable characters - /// Returns `false` otherwise. Not all `String`s are printable strings. - public fun all_characters_printable(string: &String): bool { - let len = vector::length(&string.bytes); - let i = 0; - while (i < len) { - let byte = *vector::borrow(&string.bytes, i); - if (!is_printable_char(byte)) return false; - i = i + 1; - }; - true - } - - public fun push_char(string: &mut String, char: Char) { - vector::push_back(&mut string.bytes, char.byte); - } - - public fun pop_char(string: &mut String): Char { - Char { byte: vector::pop_back(&mut string.bytes) } - } - - public fun length(string: &String): u64 { - vector::length(as_bytes(string)) - } - - /// Get the inner bytes of the `string` as a reference - public fun as_bytes(string: &String): &vector { - &string.bytes - } - - /// Unpack the `string` to get its backing bytes - public fun into_bytes(string: String): vector { - let String { bytes } = string; - bytes - } - - /// Unpack the `char` into its underlying byte. - public fun byte(char: Char): u8 { - let Char { byte } = char; - byte - } - - /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. - public fun is_valid_char(b: u8): bool { - b <= 0x7F - } - - /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. - public fun is_printable_char(byte: u8): bool { - byte >= 0x20 && // Disallow metacharacters - byte <= 0x7E // Don't allow DEL metacharacter - } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/upgraded/Move.toml b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/upgraded/Move.toml deleted file mode 100644 index 4c1902a9dcd..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/upgraded/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "base" -version = "0.0.1" - -[dependencies] -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -base = "0x0" -std = "0x1" diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/upgraded/sources/ascii.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/upgraded/sources/ascii.move deleted file mode 100644 index 7409a056835..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_inclusion_check/upgraded/sources/ascii.move +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// The `ASCII` module defines basic string and char newtypes in Move that verify -/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. -module base::ascii { - use std::option::{Option, Self}; - use std::vector; - - /// An ASCII character. - struct Char has copy, drop, store { - byte: u8, - } - - /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. - public fun char(byte: u8): Char { - assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); - Char { byte } - } - - fun additional_function() { } - - /// Returns `true` if all characters in `string` are printable characters - /// Returns `false` otherwise. Not all `String`s are printable strings. - public fun all_characters_printable(string: &String): bool { - let len = vector::length(&string.bytes); - let i = 0; - while (i < len) { - let byte = *vector::borrow(&string.bytes, i); - if (!is_printable_char(byte)) return false; - i = i + 1; - }; - true - } - - /// Convert a vector of bytes `bytes` into an `String`. Returns - /// `Some()` if the `bytes` contains all valid ASCII - /// characters. Otherwise returns `None`. - public fun try_string(bytes: vector): Option { - let len = vector::length(&bytes); - let i = 0; - while (i < len) { - let possible_byte = *vector::borrow(&bytes, i); - if (!is_valid_char(possible_byte)) return option::none(); - i = i + 1; - }; - option::some(String { bytes }) - } - - public fun push_char(string: &mut String, char: Char) { - vector::push_back(&mut string.bytes, char.byte); - } - - /// The `String` struct holds a vector of bytes that all represent - /// valid ASCII characters. Note that these ASCII characters may not all - /// be printable. To determine if a `String` contains only "printable" - /// characters you should use the `all_characters_printable` predicate - /// defined in this module. - struct String has copy, drop, store { - bytes: vector, - } - - /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. - public fun is_printable_char(byte: u8): bool { - byte >= 0x20 && // Disallow metacharacters - byte <= 0x7E // Don't allow DEL metacharacter - } - - public fun pop_char(string: &mut String): Char { - Char { byte: vector::pop_back(&mut string.bytes) } - } - - /// Convert a vector of bytes `bytes` into an `String`. Aborts if - /// `bytes` contains non-ASCII characters. - public fun string(bytes: vector): String { - let x = try_string(bytes); - assert!( - option::is_some(&x), - EINVALID_ASCII_CHARACTER - ); - option::destroy_some(x) - } - - public fun length(string: &String): u64 { - vector::length(as_bytes(string)) - } - - /// Get the inner bytes of the `string` as a reference - public fun as_bytes(string: &String): &vector { - &string.bytes - } - - /// Unpack the `string` to get its backing bytes - public fun into_bytes(string: String): vector { - let String { bytes } = string; - bytes - } - - /// Unpack the `char` into its underlying byte. - public fun byte(char: Char): u8 { - let Char { byte } = char; - byte - } - - /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. - public fun is_valid_char(b: u8): bool { - b <= 0x7F - } - - /// An invalid ASCII character was encountered when creating an ASCII string. - const EINVALID_ASCII_CHARACTER: u64 = 0x10000; -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/base/Move.toml b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/base/Move.toml deleted file mode 100644 index 4c1902a9dcd..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/base/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "base" -version = "0.0.1" - -[dependencies] -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -base = "0x0" -std = "0x1" diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/base/sources/ascii.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/base/sources/ascii.move deleted file mode 100644 index fee7fbc228c..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/base/sources/ascii.move +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// The `ASCII` module defines basic string and char newtypes in Move that verify -/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. -module base::ascii { - use std::vector; - use std::option::{Self, Option}; - - /// An invalid ASCII character was encountered when creating an ASCII string. - const EINVALID_ASCII_CHARACTER: u64 = 0x10000; - - /// The `String` struct holds a vector of bytes that all represent - /// valid ASCII characters. Note that these ASCII characters may not all - /// be printable. To determine if a `String` contains only "printable" - /// characters you should use the `all_characters_printable` predicate - /// defined in this module. - struct String has copy, drop, store { - bytes: vector, - } - - /// An ASCII character. - struct Char has copy, drop, store { - byte: u8, - } - - /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. - public fun char(byte: u8): Char { - assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); - Char { byte } - } - - /// Convert a vector of bytes `bytes` into an `String`. Aborts if - /// `bytes` contains non-ASCII characters. - public fun string(bytes: vector): String { - let x = try_string(bytes); - assert!( - option::is_some(&x), - EINVALID_ASCII_CHARACTER - ); - option::destroy_some(x) - } - - /// Convert a vector of bytes `bytes` into an `String`. Returns - /// `Some()` if the `bytes` contains all valid ASCII - /// characters. Otherwise returns `None`. - public fun try_string(bytes: vector): Option { - let len = vector::length(&bytes); - let i = 0; - while (i < len) { - let possible_byte = *vector::borrow(&bytes, i); - if (!is_valid_char(possible_byte)) return option::none(); - i = i + 1; - }; - option::some(String { bytes }) - } - - /// Returns `true` if all characters in `string` are printable characters - /// Returns `false` otherwise. Not all `String`s are printable strings. - public fun all_characters_printable(string: &String): bool { - let len = vector::length(&string.bytes); - let i = 0; - while (i < len) { - let byte = *vector::borrow(&string.bytes, i); - if (!is_printable_char(byte)) return false; - i = i + 1; - }; - true - } - - public fun push_char(string: &mut String, char: Char) { - vector::push_back(&mut string.bytes, char.byte); - } - - public fun pop_char(string: &mut String): Char { - Char { byte: vector::pop_back(&mut string.bytes) } - } - - public fun length(string: &String): u64 { - vector::length(as_bytes(string)) - } - - /// Get the inner bytes of the `string` as a reference - public fun as_bytes(string: &String): &vector { - &string.bytes - } - - /// Unpack the `string` to get its backing bytes - public fun into_bytes(string: String): vector { - let String { bytes } = string; - bytes - } - - /// Unpack the `char` into its underlying byte. - public fun byte(char: Char): u8 { - let Char { byte } = char; - byte - } - - /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. - public fun is_valid_char(b: u8): bool { - b <= 0x7F - } - - /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. - public fun is_printable_char(byte: u8): bool { - byte >= 0x20 && // Disallow metacharacters - byte <= 0x7E // Don't allow DEL metacharacter - } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/upgraded/Move.toml b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/upgraded/Move.toml deleted file mode 100644 index 4c1902a9dcd..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/upgraded/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "base" -version = "0.0.1" - -[dependencies] -MoveStdlib = { local = "../../../../sui-framework/packages/move-stdlib" } - -[addresses] -base = "0x0" -std = "0x1" diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/upgraded/sources/ascii.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/upgraded/sources/ascii.move deleted file mode 100644 index c114592ab1a..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/large_package_invalid_equality_inclusion_check/upgraded/sources/ascii.move +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// The `ASCII` module defines basic string and char newtypes in Move that verify -/// that characters are valid ASCII, and that strings consist of only valid ASCII characters. -module base::ascii { - use std::vector; - use std::option::{Self, Option}; - - /// An invalid ASCII character was encountered when creating an ASCII string. - const EINVALID_ASCII_CHARACTER: u64 = 0x10000; - - /// The `String` struct holds a vector of bytes that all represent - /// valid ASCII characters. Note that these ASCII characters may not all - /// be printable. To determine if a `String` contains only "printable" - /// characters you should use the `all_characters_printable` predicate - /// defined in this module. - struct String has copy, drop, store { - bytes: vector, - } - - /// An ASCII character. - struct Char has copy, drop, store { - byte: u8, - } - - /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII. - public fun char(byte: u8): Char { - assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER); - Char { byte } - } - - /// Convert a vector of bytes `bytes` into an `String`. Aborts if - /// `bytes` contains non-ASCII characters. - public fun string(bytes: vector): String { - let x = try_string(bytes); - assert!( - option::is_some(&x), - EINVALID_ASCII_CHARACTER + 1 // !!!!!!! <<<<<< Addition here! - ); - option::destroy_some(x) - } - - /// Convert a vector of bytes `bytes` into an `String`. Returns - /// `Some()` if the `bytes` contains all valid ASCII - /// characters. Otherwise returns `None`. - public fun try_string(bytes: vector): Option { - let len = vector::length(&bytes); - let i = 0; - while (i < len) { - let possible_byte = *vector::borrow(&bytes, i); - if (!is_valid_char(possible_byte)) return option::none(); - i = i + 1; - }; - option::some(String { bytes }) - } - - /// Returns `true` if all characters in `string` are printable characters - /// Returns `false` otherwise. Not all `String`s are printable strings. - public fun all_characters_printable(string: &String): bool { - let len = vector::length(&string.bytes); - let i = 0; - while (i < len) { - let byte = *vector::borrow(&string.bytes, i); - if (!is_printable_char(byte)) return false; - i = i + 1; - }; - true - } - - public fun push_char(string: &mut String, char: Char) { - vector::push_back(&mut string.bytes, char.byte); - } - - public fun pop_char(string: &mut String): Char { - Char { byte: vector::pop_back(&mut string.bytes) } - } - - public fun length(string: &String): u64 { - vector::length(as_bytes(string)) - } - - /// Get the inner bytes of the `string` as a reference - public fun as_bytes(string: &String): &vector { - &string.bytes - } - - /// Unpack the `string` to get its backing bytes - public fun into_bytes(string: String): vector { - let String { bytes } = string; - bytes - } - - /// Unpack the `char` into its underlying byte. - public fun byte(char: Char): u8 { - let Char { byte } = char; - byte - } - - /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise. - public fun is_valid_char(b: u8): bool { - b <= 0x7F - } - - /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise. - public fun is_printable_char(byte: u8): bool { - byte >= 0x20 && // Disallow metacharacters - byte <= 0x7E // Don't allow DEL metacharacter - } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/sources/base.move deleted file mode 100644 index d709b3b78ce..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/sources/base.move +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - friend base::friend_module; - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } - public(friend) fun friend_fun(): u64 { 0 } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/sources/friend.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/sources/friend.move deleted file mode 100644 index 707e2ae8c4e..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/base/sources/friend.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::friend_module { - public fun call_friend(): u64 { base::base_module::friend_fun() } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/sources/base.move deleted file mode 100644 index b7e0ceda761..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/sources/base.move +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - friend base::friend_module; - - public fun public_fun(): u64 { 0 } - fun private_fun(x: u64): u64 { x } - fun private_entry_fun(_x: u64) { } - public(friend) fun friend_fun(x: u64): u64 { x } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/sources/friend.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/sources/friend.move deleted file mode 100644 index 4968d92e0b7..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_and_friend_changes/upgraded/sources/friend.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::friend_module { - public fun call_friend(): u64 { base::base_module::friend_fun(0) } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/sources/base.move deleted file mode 100644 index d709b3b78ce..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/sources/base.move +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - friend base::friend_module; - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } - public(friend) fun friend_fun(): u64 { 0 } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/sources/friend.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/sources/friend.move deleted file mode 100644 index 707e2ae8c4e..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/base/sources/friend.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::friend_module { - public fun call_friend(): u64 { base::base_module::friend_fun() } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/sources/base.move deleted file mode 100644 index d02be5d960f..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/sources/base.move +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - friend base::friend_module; - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - fun private_entry_fun(_x: u64) { } - public(friend) fun friend_fun(): u64 { 0 } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/sources/friend.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/sources/friend.move deleted file mode 100644 index 707e2ae8c4e..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/private_entry_fun_entry_removed/upgraded/sources/friend.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::friend_module { - public fun call_friend(): u64 { base::base_module::friend_fun() } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/base/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/base/sources/base.move deleted file mode 100644 index 5157f98761a..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/base/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - public fun public_fun(x: u64, y: u64): u64 { x + y } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/upgraded/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/upgraded/sources/base.move deleted file mode 100644 index 7e33ee61a12..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_alpha_rename/upgraded/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - public fun public_fun(y: u64, x: u64): u64 { y + x } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/base/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/base/sources/base.move deleted file mode 100644 index 5157f98761a..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/base/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - public fun public_fun(x: u64, y: u64): u64 { x + y } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/upgraded/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/upgraded/sources/base.move deleted file mode 100644 index 249f61d1c17..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_param_permute/upgraded/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - public fun public_fun(y: u64, x: u64): u64 { x + y } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_rename/base/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_rename/base/sources/base.move deleted file mode 100644 index 425b93f31dd..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_rename/base/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_rename/upgraded/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_rename/upgraded/sources/base.move deleted file mode 100644 index cdc96e2cd3f..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/public_fun_rename/upgraded/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - public fun renamed_public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/base/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/base/sources/base.move deleted file mode 100644 index 425b93f31dd..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/base/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/upgraded/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/upgraded/sources/base.move deleted file mode 100644 index 1f15c3b1e35..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_name_change/upgraded/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field2: u64, - field1: u64, - } - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/base/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/base/sources/base.move deleted file mode 100644 index 519fe791158..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/base/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: bool, - } - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/upgraded/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/upgraded/sources/base.move deleted file mode 100644 index 36b2cbb0307..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder/upgraded/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field1: bool, - field0: u64, - } - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/base/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/base/sources/base.move deleted file mode 100644 index 519fe791158..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/base/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: bool, - } - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/upgraded/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/upgraded/sources/base.move deleted file mode 100644 index 6e59c824422..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_field_reorder_no_name_change/upgraded/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: bool, - field1: u64, - } - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_layout_change/base/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_layout_change/base/sources/base.move deleted file mode 100644 index 425b93f31dd..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_layout_change/base/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_layout_change/upgraded/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_layout_change/upgraded/sources/base.move deleted file mode 100644 index f69c05e7c9a..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_layout_change/upgraded/sources/base.move +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - extra_field: u64, - } - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_name_change/base/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_name_change/base/sources/base.move deleted file mode 100644 index 425b93f31dd..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_name_change/base/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct X { - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_name_change/upgraded/sources/base.move b/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_name_change/upgraded/sources/base.move deleted file mode 100644 index 7c6b6fd1903..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/struct_name_change/upgraded/sources/base.move +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module base::base_module { - struct Y { - field0: u64, - field1: u64, - } - - public fun public_fun(): u64 { 0 } - fun private_fun(): u64 { 0 } - entry fun private_entry_fun(_x: u64) { } -} diff --git a/crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs b/crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs deleted file mode 100644 index 70028ae00f2..00000000000 --- a/crates/sui-upgrade-compatibility-transactional-tests/tests/tests.rs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::path::{Path, PathBuf}; - -use move_binary_format::{ - compatibility::{Compatibility, InclusionCheck}, - file_format::AbilitySet, - normalized, CompiledModule, -}; -use sui_move_build::{BuildConfig, SuiPackageHooks}; - -pub const TEST_DIR: &str = "tests"; - -fn run_test(path: &Path) -> datatest_stable::Result<()> { - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); - let mut pathbuf = path.to_path_buf(); - pathbuf.pop(); - pathbuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(pathbuf); - let mut base_path = pathbuf.clone(); - let mut upgraded_path = pathbuf.clone(); - - base_path.push("base"); - upgraded_path.push("upgraded"); - - let base = compile(base_path)?; - let base_normalized = normalize(&base); - - let upgraded = compile(upgraded_path)?; - let upgraded_normalized = normalize(&upgraded); - - check_all_compatibilities( - base_normalized, - upgraded_normalized, - pathbuf.file_name().unwrap().to_string_lossy().to_string(), - ) -} - -fn compile(path: PathBuf) -> anyhow::Result> { - Ok(BuildConfig::new_for_testing() - .build(path) - .unwrap() - .into_modules()) -} - -fn normalize(modules: &[CompiledModule]) -> Vec { - modules.iter().map(normalized::Module::new).collect() -} - -fn check_all_compatibilities( - base: Vec, - upgraded: Vec, - name: String, -) -> datatest_stable::Result<()> { - assert_eq!(base.len(), upgraded.len()); - - let compatibility_types = [ - Compatibility::full_check(), - // Full compat but allow private entry functions to change - Compatibility { - check_struct_and_pub_function_linking: true, - check_struct_layout: true, - check_friend_linking: true, - check_private_entry_linking: false, - disallowed_new_abilities: AbilitySet::ALL, - disallow_change_struct_type_params: true, - }, - // Full compat but allow private entry functions and friends to change - Compatibility { - check_struct_and_pub_function_linking: true, - check_struct_layout: true, - check_friend_linking: false, - check_private_entry_linking: false, - disallowed_new_abilities: AbilitySet::ALL, - disallow_change_struct_type_params: true, - }, - // Full compat but allow friends to change - Compatibility { - check_struct_and_pub_function_linking: true, - check_struct_layout: true, - check_friend_linking: false, - check_private_entry_linking: true, - disallowed_new_abilities: AbilitySet::ALL, - disallow_change_struct_type_params: true, - }, - Compatibility::no_check(), - ]; - - let mut results = compatibility_types - .iter() - .map(|compat| { - let compatibility_checks: Vec<_> = base - .iter() - .zip(upgraded.iter()) - .map(|(base, upgraded)| { - format!( - "{}::{}:\n\tbase->upgrade: {}\n\tupgrade->base: {}", - base.address, - base.name, - compat.check(base, upgraded).is_ok(), - compat.check(upgraded, base).is_ok() - ) - }) - .collect(); - - format!( - "====\n{:?}\n{}\n====", - compat, - compatibility_checks.join("\n") - ) - }) - .collect::>() - .join("\n"); - - let inclusion_results = [InclusionCheck::Equal, InclusionCheck::Subset] - .iter() - .map(|compat| { - let compatibility_checks: Vec<_> = base - .iter() - .zip(upgraded.iter()) - .map(|(base, upgraded)| { - format!( - "{}::{}:\n\tbase->upgrade: {}\n\tupgrade->base: {}", - base.address, - base.name, - compat.check(base, upgraded).is_ok(), - compat.check(upgraded, base).is_ok() - ) - }) - .collect(); - - format!( - "====\n{:?}\n{}\n====", - compat, - compatibility_checks.join("\n") - ) - }) - .collect::>() - .join("\n"); - - results.push_str(&inclusion_results); - insta::assert_display_snapshot!(name, results); - Ok(()) -} - -datatest_stable::harness!(run_test, TEST_DIR, r".*\.package$"); diff --git a/crates/sui-verifier-transactional-tests/Cargo.toml b/crates/sui-verifier-transactional-tests/Cargo.toml deleted file mode 100644 index 12d9944ec1e..00000000000 --- a/crates/sui-verifier-transactional-tests/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "sui-verifier-transactional-tests" -version = "0.1.0" -authors = ["Mysten Labs "] -description = "Transactional tests for Sui Verifier" -license = "Apache-2.0" -publish = false -edition = "2021" - -[dev-dependencies] -datatest-stable.workspace = true -sui-transactional-test-runner.workspace = true - -[[test]] -name = "tests" -harness = false - -[dependencies] diff --git a/crates/sui-verifier-transactional-tests/src/lib.rs b/crates/sui-verifier-transactional-tests/src/lib.rs deleted file mode 100644 index 07fe81c224d..00000000000 --- a/crates/sui-verifier-transactional-tests/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#![forbid(unsafe_code)] - -// Empty src/lib.rs to get rusty-tags working. diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/clock_mut.exp b/crates/sui-verifier-transactional-tests/tests/entry_points/clock_mut.exp deleted file mode 100644 index 062fd7f66d6..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/clock_mut.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-14: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Clock must be passed by immutable reference. got: &mut sui::clock::Clock"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/clock_val.exp b/crates/sui-verifier-transactional-tests/tests/entry_points/clock_val.exp deleted file mode 100644 index ea2be198f7c..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/clock_val.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-14: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Clock must be passed by immutable reference. got: sui::clock::Clock"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_obj_mut_ref_vector.exp b/crates/sui-verifier-transactional-tests/tests/entry_points/generic_obj_mut_ref_vector.exp deleted file mode 100644 index 4383f758f9b..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_obj_mut_ref_vector.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-15: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &mut vector"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_obj_ref_vector.exp b/crates/sui-verifier-transactional-tests/tests/entry_points/generic_obj_ref_vector.exp deleted file mode 100644 index 698692cb731..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_obj_ref_vector.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-15: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &vector"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_with_key_invalid.exp b/crates/sui-verifier-transactional-tests/tests/entry_points/generic_with_key_invalid.exp deleted file mode 100644 index a21164f585b..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/generic_with_key_invalid.exp +++ /dev/null @@ -1,9 +0,0 @@ -processed 2 tasks - -task 0 'publish'. lines 6-16: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: std::option::Option"), command: Some(0) } } - -task 1 'publish'. lines 18-28: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: vector>"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/nested_key_generic_vector_param.exp b/crates/sui-verifier-transactional-tests/tests/entry_points/nested_key_generic_vector_param.exp deleted file mode 100644 index 4e4aa08e379..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/nested_key_generic_vector_param.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 4-13: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: vector>"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct.exp b/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct.exp deleted file mode 100644 index 264f0814a12..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-17: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: _::m::S"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_generic.exp b/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_generic.exp deleted file mode 100644 index 00b05ad2f80..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_generic.exp +++ /dev/null @@ -1,9 +0,0 @@ -processed 2 tasks - -task 0 'publish'. lines 6-21: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: _::m::Obj<_::m::NoStore>"), command: Some(0) } } - -task 1 'publish'. lines 23-35: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: _::m::Obj"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_vector.exp b/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_vector.exp deleted file mode 100644 index 686b6db528a..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/non_key_struct_vector.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-17: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: vector<_::m::S>"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/obj_mut_ref_vector.exp b/crates/sui-verifier-transactional-tests/tests/entry_points/obj_mut_ref_vector.exp deleted file mode 100644 index c855225ab45..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/obj_mut_ref_vector.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-18: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &mut vector<_::m::S>"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/obj_ref_vector.exp b/crates/sui-verifier-transactional-tests/tests/entry_points/obj_ref_vector.exp deleted file mode 100644 index afe4f2e49ff..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/obj_ref_vector.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-18: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Expected primitive or object type. Got: &vector<_::m::S>"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/ok.mvir b/crates/sui-verifier-transactional-tests/tests/entry_points/ok.mvir deleted file mode 100644 index 732fc2bbb76..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/ok.mvir +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# publish -module 0x0.m { - import 0x2.tx_context; - public entry t(arg: &tx_context.TxContext) { - label l0: - abort 0; - } -} - -//# publish -module 0x0.m { - import 0x2.tx_context; - public entry t(arg: &mut tx_context.TxContext) { - label l0: - abort 0; - } -} diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/random_mut.exp b/crates/sui-verifier-transactional-tests/tests/entry_points/random_mut.exp deleted file mode 100644 index b47cea42e62..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/random_mut.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-14: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Random must be passed by immutable reference. got: &mut sui::random::Random"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/random_val.exp b/crates/sui-verifier-transactional-tests/tests/entry_points/random_val.exp deleted file mode 100644 index 9f2e8220f9f..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/random_val.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-14: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point parameter type. Random must be passed by immutable reference. got: sui::random::Random"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/return_values.mvir b/crates/sui-verifier-transactional-tests/tests/entry_points/return_values.mvir deleted file mode 100644 index ff8bd780d6b..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/return_values.mvir +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// return values from entry functions must have drop - -//# publish -module 0x0.m { - import 0x2.tx_context; - public entry foo(ctx: &mut tx_context.TxContext): u64 { - label l0: - abort 0; - } -} - -//# publish -module 0x0.m { - import 0x2.tx_context; - public entry foo(ctx: &mut tx_context.TxContext): u64 * u8 { - label l0: - abort 0; - } -} - -//# publish -module 0x0.m { - import 0x2.tx_context; - public entry foo(ctx: &mut tx_context.TxContext): vector { - label l0: - abort 0; - } -} - -//# publish -module 0x0.m { - import 0x2.tx_context; - struct Droppable has drop { flag: bool } - public entry foo(ctx: &mut tx_context.TxContext): Self.Droppable { - label l0: - abort 0; - } -} - -//# publish -module 0x0.m { - import 0x2.tx_context; - struct Droppable has drop { flag: bool } - public entry foo(ctx: &mut tx_context.TxContext): vector * u64 { - label l0: - abort 0; - } -} diff --git a/crates/sui-verifier-transactional-tests/tests/entry_points/return_values_invalid.exp b/crates/sui-verifier-transactional-tests/tests/entry_points/return_values_invalid.exp deleted file mode 100644 index 3de6284c20a..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/entry_points/return_values_invalid.exp +++ /dev/null @@ -1,25 +0,0 @@ -processed 6 tasks - -task 0 'publish'. lines 6-13: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point return type. Expected a non reference type."), command: Some(0) } } - -task 1 'publish'. lines 15-22: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point return type. Expected a non reference type."), command: Some(0) } } - -task 2 'publish'. lines 24-31: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point return type. Expected a non reference type."), command: Some(0) } } - -task 3 'publish'. lines 33-41: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point return type. The specified return type does not have the 'drop' ability: _::m::Copyable"), command: Some(0) } } - -task 4 'publish'. lines 43-52: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point return type. The specified return type does not have the 'drop' ability: _::m::Obj"), command: Some(0) } } - -task 5 'publish'. lines 54-63: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Invalid entry point return type. The specified return type does not have the 'drop' ability: vector<_::m::Obj>"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/indirect_leak_through_call.exp b/crates/sui-verifier-transactional-tests/tests/id_leak/indirect_leak_through_call.exp deleted file mode 100644 index 7b5c3cd0467..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/indirect_leak_through_call.exp +++ /dev/null @@ -1,10 +0,0 @@ -processed 2 tasks - -task 0 'publish'. lines 4-26: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("PartialVMError with status UNKNOWN_VERIFICATION_ERROR with sub status 1 and message Invalid object creation in _::m::foo. Object created without a newly created UID. The UID must come directly from sui::object::new. Or for tests, it can come from sui::test_scenario::new_object"), command: Some(0) } } - -task 1 'publish'. lines 28-50: -created: object(2,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 4590400, storage_rebate: 978120, non_refundable_storage_fee: 9880 diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/through_call_with_borrow_field.exp b/crates/sui-verifier-transactional-tests/tests/id_leak/through_call_with_borrow_field.exp deleted file mode 100644 index 0772f31c75e..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/through_call_with_borrow_field.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 4-34: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("PartialVMError with status UNKNOWN_VERIFICATION_ERROR with sub status 1 and message Invalid object creation in _::m::new. Object created without a newly created UID. The UID must come directly from sui::object::new. Or for tests, it can come from sui::test_scenario::new_object"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/through_indirect_return.exp b/crates/sui-verifier-transactional-tests/tests/id_leak/through_indirect_return.exp deleted file mode 100644 index 8b1e684d353..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/through_indirect_return.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 4-20: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("PartialVMError with status UNKNOWN_VERIFICATION_ERROR with sub status 1 and message Invalid object creation in _::m::foo. Object created without a newly created UID. The UID must come directly from sui::object::new. Or for tests, it can come from sui::test_scenario::new_object"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/through_pack.exp b/crates/sui-verifier-transactional-tests/tests/id_leak/through_pack.exp deleted file mode 100644 index 1c266848e9a..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/through_pack.exp +++ /dev/null @@ -1,10 +0,0 @@ -processed 2 tasks - -task 0 'publish'. lines 4-37: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("PartialVMError with status UNKNOWN_VERIFICATION_ERROR with sub status 1 and message Invalid object creation in _::test::test. Object created without a newly created UID. The UID must come directly from sui::object::new. Or for tests, it can come from sui::test_scenario::new_object"), command: Some(0) } } - -task 1 'publish'. lines 39-62: -created: object(2,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 4902000, storage_rebate: 978120, non_refundable_storage_fee: 9880 diff --git a/crates/sui-verifier-transactional-tests/tests/id_leak/transmute.exp b/crates/sui-verifier-transactional-tests/tests/id_leak/transmute.exp deleted file mode 100644 index a3b6af960c4..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/id_leak/transmute.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 4-28: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("PartialVMError with status UNKNOWN_VERIFICATION_ERROR with sub status 1 and message Invalid object creation in _::m::transmute. Object created without a newly created UID. The UID must come directly from sui::object::new. Or for tests, it can come from sui::test_scenario::new_object"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/init/cannot_call_init.exp b/crates/sui-verifier-transactional-tests/tests/init/cannot_call_init.exp deleted file mode 100644 index 238ab4f2a8d..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/init/cannot_call_init.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 4-17: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::init at offset 1. Cannot call a module's 'init' function from another Move function"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/init/must_have_txn_context.exp b/crates/sui-verifier-transactional-tests/tests/init/must_have_txn_context.exp deleted file mode 100644 index 32aaeb56c0d..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/init/must_have_txn_context.exp +++ /dev/null @@ -1,9 +0,0 @@ -processed 2 tasks - -task 0 'publish'. lines 4-11: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Expected at least one and at most two parameters for _::m::init"), command: Some(0) } } - -task 1 'publish'. lines 14-21: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Expected last (and at most second) parameter for _::m::init to be &mut sui::tx_context::TxContext or &sui::tx_context::TxContext; optional first parameter must be of one-time witness type whose name is the same as the capitalized module name (_::m::M) and which has no fields or a single field of type bool"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/init/not_generic.exp b/crates/sui-verifier-transactional-tests/tests/init/not_generic.exp deleted file mode 100644 index ac404897e25..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/init/not_generic.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 4-11: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m. 'init' function cannot have type parameters"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/init/not_private.exp b/crates/sui-verifier-transactional-tests/tests/init/not_private.exp deleted file mode 100644 index ce749355ccd..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/init/not_private.exp +++ /dev/null @@ -1,13 +0,0 @@ -processed 3 tasks - -task 0 'publish'. lines 4-11: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m. 'init' function must be private"), command: Some(0) } } - -task 1 'publish'. lines 13-20: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m. 'init' function must be private"), command: Some(0) } } - -task 2 'publish'. lines 22-29: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m. 'init' function must be private"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/init/not_txn_context.exp b/crates/sui-verifier-transactional-tests/tests/init/not_txn_context.exp deleted file mode 100644 index 1e783b68886..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/init/not_txn_context.exp +++ /dev/null @@ -1,13 +0,0 @@ -processed 3 tasks - -task 0 'publish'. lines 4-11: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Expected last parameter for _::m::init to be &mut sui::tx_context::TxContext or &sui::tx_context::TxContext, but found u64"), command: Some(0) } } - -task 1 'publish'. lines 13-20: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Expected last parameter for _::tx_context::init to be &mut sui::tx_context::TxContext or &sui::tx_context::TxContext, but found _::tx_context::TxContext"), command: Some(0) } } - -task 2 'publish'. lines 22-29: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Expected last parameter for _::m::init to be &mut sui::tx_context::TxContext or &sui::tx_context::TxContext, but found sui::tx_context::TxContext"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/init/ok.mvir b/crates/sui-verifier-transactional-tests/tests/init/ok.mvir deleted file mode 100644 index 2d3d3dbd790..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/init/ok.mvir +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# publish -module 0x0.m { - import 0x2.tx_context; - init(ctx: &mut tx_context.TxContext) { - label l0: - abort 0; - } -} diff --git a/crates/sui-verifier-transactional-tests/tests/init/return_values.exp b/crates/sui-verifier-transactional-tests/tests/init/return_values.exp deleted file mode 100644 index f1633348cd7..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/init/return_values.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 4-11: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m, 'init' function cannot have return values"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/init/return_values.mvir b/crates/sui-verifier-transactional-tests/tests/init/return_values.mvir deleted file mode 100644 index 5690b7f8aab..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/init/return_values.mvir +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//# publish -module 0x0.m { - import 0x2.tx_context; - init(ctx: &mut tx_context.TxContext): u64 { - label l0: - abort 0; - } -} diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/instantiate.exp b/crates/sui-verifier-transactional-tests/tests/one_time_witness/instantiate.exp deleted file mode 100644 index 0eb4d2faf77..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/instantiate.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-24: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("one-time witness type _::m::M is instantiated in the _::m::pack function and must never be"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/many_fields_invalid.exp b/crates/sui-verifier-transactional-tests/tests/one_time_witness/many_fields_invalid.exp deleted file mode 100644 index d1192077c78..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/many_fields_invalid.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-16: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Expected last (and at most second) parameter for _::m::init to be &mut sui::tx_context::TxContext or &sui::tx_context::TxContext; optional first parameter must be of one-time witness type whose name is the same as the capitalized module name (_::m::M) and which has no fields or a single field of type bool"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/more_abilities.exp b/crates/sui-verifier-transactional-tests/tests/one_time_witness/more_abilities.exp deleted file mode 100644 index 7dbc7510cd9..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/more_abilities.exp +++ /dev/null @@ -1,13 +0,0 @@ -processed 4 tasks - -task 1 'publish'. lines 8-19: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("one-time witness type candidate _::m::M must have a single ability: drop"), command: Some(0) } } - -task 2 'publish'. lines 21-32: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("one-time witness type candidate _::m::M must have a single ability: drop"), command: Some(0) } } - -task 3 'publish'. lines 34-45: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("one-time witness type candidate _::m::M must have a single ability: drop"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/no_drop.exp b/crates/sui-verifier-transactional-tests/tests/one_time_witness/no_drop.exp deleted file mode 100644 index 00064d635ef..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/no_drop.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-18: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("one-time witness type candidate _::m::M must have a single ability: drop"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/no_init_arg.exp b/crates/sui-verifier-transactional-tests/tests/one_time_witness/no_init_arg.exp deleted file mode 100644 index 8b6834a6bd3..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/no_init_arg.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-16: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("init function of a module containing one-time witness type candidate must have _::m::M as the first parameter (a struct which has no fields or a single field of type bool)"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/other_mod_def.exp b/crates/sui-verifier-transactional-tests/tests/one_time_witness/other_mod_def.exp deleted file mode 100644 index a8edae68a81..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/other_mod_def.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-16: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Expected last (and at most second) parameter for _::n::init to be &mut sui::tx_context::TxContext or &sui::tx_context::TxContext; optional first parameter must be of one-time witness type whose name is the same as the capitalized module name (_::n::N) and which has no fields or a single field of type bool"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/other_mod_def.mvir b/crates/sui-verifier-transactional-tests/tests/one_time_witness/other_mod_def.mvir deleted file mode 100644 index 0b62354f3bf..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/other_mod_def.mvir +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// invalid, one-time witness type candidate used in a different module - -//# publish -module 0x0.n { - import 0x2.sui; - import 0x2.tx_context; - - init(_otw: sui.SUI, _ctx: &mut tx_context.TxContext) { - label l0: - return; - } - -} diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/type_param.exp b/crates/sui-verifier-transactional-tests/tests/one_time_witness/type_param.exp deleted file mode 100644 index 16763ddbb2a..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/type_param.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-16: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m. 'init' function cannot have type parameters"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_field_type_with_init.exp b/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_field_type_with_init.exp deleted file mode 100644 index d1192077c78..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_field_type_with_init.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-16: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Expected last (and at most second) parameter for _::m::init to be &mut sui::tx_context::TxContext or &sui::tx_context::TxContext; optional first parameter must be of one-time witness type whose name is the same as the capitalized module name (_::m::M) and which has no fields or a single field of type bool"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_init_type.exp b/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_init_type.exp deleted file mode 100644 index ee419ce792b..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_init_type.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-17: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("init function of a module containing one-time witness type candidate must have _::m::M as the first parameter (a struct which has no fields or a single field of type bool)"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_name.exp b/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_name.exp deleted file mode 100644 index d1192077c78..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_name.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-16: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Expected last (and at most second) parameter for _::m::init to be &mut sui::tx_context::TxContext or &sui::tx_context::TxContext; optional first parameter must be of one-time witness type whose name is the same as the capitalized module name (_::m::M) and which has no fields or a single field of type bool"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_name_format.exp b/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_name_format.exp deleted file mode 100644 index 0218df59fe4..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/one_time_witness/wrong_name_format.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 6-16: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("Expected last (and at most second) parameter for _::mod::init to be &mut sui::tx_context::TxContext or &sui::tx_context::TxContext; optional first parameter must be of one-time witness type whose name is the same as the capitalized module name (_::mod::MOD) and which has no fields or a single field of type bool"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer.exp b/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer.exp deleted file mode 100644 index bb703b587ed..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer.exp +++ /dev/null @@ -1,17 +0,0 @@ -processed 4 tasks - -task 0 'publish'. lines 6-16: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::transfer' on an object of type 'sui::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_transfer'"), command: Some(0) } } - -task 1 'publish'. lines 18-28: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::freeze_object' on an object of type 'sui::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_freeze_object'"), command: Some(0) } } - -task 2 'publish'. lines 30-40: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::share_object' on an object of type 'sui::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_share_object'"), command: Some(0) } } - -task 3 'publish'. lines 42-54: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::receive' on an object of type 'sui::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_receive'"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_generic.exp b/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_generic.exp deleted file mode 100644 index 9b2776838c1..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_generic.exp +++ /dev/null @@ -1,17 +0,0 @@ -processed 4 tasks - -task 0 'publish'. lines 8-17: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::transfer' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_transfer'"), command: Some(0) } } - -task 1 'publish'. lines 19-28: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::freeze_object' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_freeze_object'"), command: Some(0) } } - -task 2 'publish'. lines 30-39: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::share_object' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_share_object'"), command: Some(0) } } - -task 3 'publish'. lines 41-52: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::receive' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_receive'"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_store.exp b/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_store.exp deleted file mode 100644 index bb703b587ed..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_store.exp +++ /dev/null @@ -1,17 +0,0 @@ -processed 4 tasks - -task 0 'publish'. lines 6-16: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::transfer' on an object of type 'sui::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_transfer'"), command: Some(0) } } - -task 1 'publish'. lines 18-28: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::freeze_object' on an object of type 'sui::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_freeze_object'"), command: Some(0) } } - -task 2 'publish'. lines 30-40: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::share_object' on an object of type 'sui::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_share_object'"), command: Some(0) } } - -task 3 'publish'. lines 42-54: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::receive' on an object of type 'sui::coin::Coin'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_receive'"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_store_generic.exp b/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_store_generic.exp deleted file mode 100644 index d0c31ec28d7..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/private_generics/no_public_transfer_store_generic.exp +++ /dev/null @@ -1,17 +0,0 @@ -processed 5 tasks - -task 1 'publish'. lines 10-19: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::transfer' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_transfer'"), command: Some(0) } } - -task 2 'publish'. lines 21-30: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::freeze_object' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_freeze_object'"), command: Some(0) } } - -task 3 'publish'. lines 32-41: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::share_object' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_share_object'"), command: Some(0) } } - -task 4 'publish'. lines 43-54: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::receive' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_receive'"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/private_event_emit.exp b/crates/sui-verifier-transactional-tests/tests/private_generics/private_event_emit.exp deleted file mode 100644 index 81effb2749b..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/private_generics/private_event_emit.exp +++ /dev/null @@ -1,17 +0,0 @@ -processed 4 tasks - -task 0 'publish'. lines 6-16: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::event::emit' with an event type 'sui::coin::CurrencyCreated'. The event's type must be defined in the current module"), command: Some(0) } } - -task 1 'publish'. lines 18-27: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::event::emit' with an event type 'T0'. The event's type must be defined in the current module"), command: Some(0) } } - -task 2 'publish'. lines 29-38: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::event::emit' with an event type 'u64'. The event's type must be defined in the current module"), command: Some(0) } } - -task 3 'publish'. lines 40-53: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::event::emit' with an event type 'vector<_::m::X>'. The event's type must be defined in the current module"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/private_generics/receive_with_and_without_store.exp b/crates/sui-verifier-transactional-tests/tests/private_generics/receive_with_and_without_store.exp deleted file mode 100644 index 8a4d196fbe6..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/private_generics/receive_with_and_without_store.exp +++ /dev/null @@ -1,19 +0,0 @@ -processed 4 tasks - -task 0 'publish'. lines 1-12: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::receive_bad. Invalid call to 'sui::transfer::receive' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_receive'"), command: Some(0) } } - -task 1 'publish'. lines 14-25: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m1::receive_bad. Invalid call to 'sui::transfer::receive' on an object of type 'T0'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_receive'"), command: Some(0) } } - -task 2 'publish'. lines 27-41: -created: object(3,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 4848800, storage_rebate: 978120, non_refundable_storage_fee: 9880 - -task 3 'publish'. lines 43-54: -created: object(4,0) -mutated: object(0,0) -gas summary: computation_cost: 1000000, storage_cost: 4430800, storage_rebate: 978120, non_refundable_storage_fee: 9880 diff --git a/crates/sui-verifier-transactional-tests/tests/private_transfer/transfer_invalid.exp b/crates/sui-verifier-transactional-tests/tests/private_transfer/transfer_invalid.exp deleted file mode 100644 index d640a917846..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/private_transfer/transfer_invalid.exp +++ /dev/null @@ -1,17 +0,0 @@ -processed 4 tasks - -task 0 'publish'. lines 6-16: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::transfer' on an object of type 'sui::clock::Clock'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_transfer'"), command: Some(0) } } - -task 1 'publish'. lines 18-28: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::share_object' on an object of type 'sui::clock::Clock'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_share_object'"), command: Some(0) } } - -task 2 'publish'. lines 30-40: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::freeze_object' on an object of type 'sui::clock::Clock'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_freeze_object'"), command: Some(0) } } - -task 3 'publish'. lines 42-54: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("_::m::t. Invalid call to 'sui::transfer::receive' on an object of type 'sui::clock::Clock'. The transferred object's type must be defined in the current module. If the object has the 'store' type ability, you can use the non-internal variant instead, i.e. 'sui::transfer::public_receive'"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_first_field_not_id.exp b/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_first_field_not_id.exp deleted file mode 100644 index 194de04b782..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_first_field_not_id.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 4-10: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("First field of struct S must be 'id', flag found"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_address.exp b/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_address.exp deleted file mode 100644 index d51f08b1dd9..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_address.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 4-11: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("First field of struct S must be of type sui::object::UID, _::object::UID type found"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_name.exp b/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_name.exp deleted file mode 100644 index f4d446e2fc4..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_struct_name.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 4-10: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("First field of struct S must be of type sui::object::UID, sui::object::ID type found"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_type.exp b/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_type.exp deleted file mode 100644 index 4c74efb0d9e..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_id_field_incorrect_type.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 4-10: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("First field of struct S must be of type sui::object::UID, Bool type found"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_second_field_id.exp b/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_second_field_id.exp deleted file mode 100644 index 4770e8e9c6d..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/struct_with_key/key_struct_second_field_id.exp +++ /dev/null @@ -1,5 +0,0 @@ -processed 1 task - -task 0 'publish'. lines 4-11: -Error: Transaction Effects Status: Sui Move Bytecode Verification Error. Please run the Sui Move Verifier for more information. -Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: SuiMoveVerificationError, source: Some("First field of struct S must be 'id', flag found"), command: Some(0) } } diff --git a/crates/sui-verifier-transactional-tests/tests/tests.rs b/crates/sui-verifier-transactional-tests/tests/tests.rs deleted file mode 100644 index 7b67b8d382f..00000000000 --- a/crates/sui-verifier-transactional-tests/tests/tests.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub const TEST_DIR: &str = "tests"; -use sui_transactional_test_runner::run_test; - -datatest_stable::harness!(run_test, TEST_DIR, r".*\.(mvir|move)$"); diff --git a/crates/sui/Cargo.toml b/crates/sui/Cargo.toml deleted file mode 100644 index 45eca0f3338..00000000000 --- a/crates/sui/Cargo.toml +++ /dev/null @@ -1,115 +0,0 @@ -[package] -name = "sui" -version.workspace = true -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -json_to_table.workspace = true -tabled.workspace = true -anemo.workspace = true -anyhow.workspace = true -serde.workspace = true -serde_json.workspace = true -serde_yaml.workspace = true -signature.workspace = true -camino.workspace = true -tokio = { workspace = true, features = ["full"] } -async-trait.workspace = true -tracing.workspace = true -bcs.workspace = true -clap.workspace = true -bip32.workspace = true -rand.workspace = true -tap.workspace = true -inquire.workspace = true -rusoto_core.workspace = true -rusoto_kms.workspace = true -prometheus.workspace = true -git-version.workspace = true -const-str.workspace = true -num-bigint.workspace = true -regex.workspace = true -reqwest.workspace = true -im.workspace = true -async-recursion.workspace = true -thiserror.workspace = true -miette.workspace = true -datatest-stable.workspace = true -insta.workspace = true -shlex.workspace = true - -sui-config.workspace = true -sui-execution = { path = "../../sui-execution" } -sui-swarm-config.workspace = true -sui-genesis-builder.workspace = true -sui-types.workspace = true -sui-json.workspace = true -sui-swarm.workspace = true -sui-json-rpc-types.workspace = true -sui-sdk.workspace = true -sui-keys.workspace = true -sui-source-validation.workspace = true -sui-move = { workspace = true, features = ["all"] } -sui-move-build.workspace = true -sui-protocol-config.workspace = true -shared-crypto.workspace = true -sui-replay.workspace = true -sui-transaction-builder.workspace = true -move-binary-format.workspace = true - -fastcrypto.workspace = true -fastcrypto-zkp.workspace = true - -rustyline.workspace = true -rustyline-derive.workspace = true -colored.workspace = true -unescape.workspace = true -shell-words.workspace = true - -tempfile.workspace = true -telemetry-subscribers.workspace = true - -move-core-types.workspace = true -move-package.workspace = true -csv.workspace = true -move-vm-profiler.workspace = true -move-command-line-common.workspace = true - -[target.'cfg(not(target_env = "msvc"))'.dependencies] -jemalloc-ctl.workspace = true - -[dev-dependencies] -prometheus.workspace = true -fs_extra.workspace = true -expect-test.workspace = true -assert_cmd.workspace = true - -test-cluster.workspace = true -sui-macros.workspace = true -sui-simulator.workspace = true -sui-test-transaction-builder.workspace = true -serde_json.workspace = true - -[target.'cfg(msim)'.dependencies] -msim.workspace = true - -[package.metadata.cargo-udeps.ignore] -normal = ["jemalloc-ctl"] - -[[example]] -name = "generate-genesis-checkpoint" -path = "src/generate_genesis_checkpoint.rs" -test = false - -[[test]] -name = "ptb_files_tests" -harness = false - -[features] -gas-profiler = [ - "sui-types/gas-profiler", - "sui-execution/gas-profiler", -] diff --git a/crates/sui/genesis.md b/crates/sui/genesis.md deleted file mode 100644 index 09faed91297..00000000000 --- a/crates/sui/genesis.md +++ /dev/null @@ -1,105 +0,0 @@ -# Genesis Ceremony - -This document lays out the step-by-step process for orchestrating a Sui Genesis Ceremony. - -## Prerequisites - -Each validator participating in the ceremony will need the following: - -- Ed25519 Public key -- Sui network address // WAN -- Narwhal_primary_to_primary network address // WAN -- Narwhal_worker_to_primary network address // LAN -- Narwhal_primary_to_worker network address // LAN -- Narwhal_worker_to_worker network address // WAN -- Narwhal_consensus_address network address // LAN - -Note: -- Network addresses should be Multiaddrs in the form of `/dns/{dns name}/tcp/{port}/http` and -only the addresses marked WAN need to be publicly accessible by the wider internet. -- An Ed25519 key can be created using `sui keytool generate` - -## Ceremony - -1. Creation of a shared workspace - -To start, you'll need to create a shared workspace where all validators will be able to share their -information. For these instructions, we'll assume that such a shared workspace is created and managed -using a git repository hosted on git hosting provider. - -The MC (Master of Ceremony) will create a new git repository and initialize the directory: - -``` -$ git init genesis && cd genesis -$ sui genesis-ceremony -$ git add . -$ git commit -m "init genesis" -$ git push -``` - -2. Contribute Validator information - -Once the shared workspace has been initialized, each validator can contribute their information: - -``` -$ git clone && cd genesis -$ sui genesis-ceremony add-validator \ - --name \ - --key-file \ - --network-address \ - --narwhal-primary-to-primary \ - --narwhal-worker-to-primary \ - --narwhal-primary-to-worker \ - --narwhal-worker-to-worker \ - --narwhal-consensus-address - -$ git add . -$ git commit -m "add validator 's information" -$ git push # either to the shared workspace or another branch followed by a PR -``` - -3. Add Initial Gas Objects - -Add configuration for any initial gas objects that should be created at genesis. - -``` -$ sui genesis-ceremony add-gas-object \ - --address \ - --object-id \ - --valud <# of sui coins> -$ git add . -$ git commit -m "add gas object" -$ git push -``` - -4. Build Genesis - -Once all validators and gas objects have been added, the MC can build the genesis object: - -``` -$ sui genesis-ceremony build -$ git add . -$ git commit -m "build genesis" -$ git push -``` - -5. Verify and Sign Genesis - -Once genesis is built each validator will need to verify and sign genesis: - -``` -$ sui genesis-ceremony verify-and-sign \ - --key-file -$ git add . -$ git commit -m "sign genesis" -$ git push -``` - -6. Finalize Genesis - -Once all validators have successfully verified and signed genesis, the MC can finalize the ceremony -and then the genesis state can be distributed: - -``` -$ sui genesis-ceremony finalize -``` diff --git a/crates/sui/src/client_ptb/builder.rs b/crates/sui/src/client_ptb/builder.rs deleted file mode 100644 index 04b72e7d590..00000000000 --- a/crates/sui/src/client_ptb/builder.rs +++ /dev/null @@ -1,1134 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{collections::BTreeMap, path::PathBuf}; - -use anyhow::Result; -use async_recursion::async_recursion; -use async_trait::async_trait; -use miette::Severity; -use move_binary_format::{ - access::ModuleAccess, binary_config::BinaryConfig, binary_views::BinaryIndexedView, - file_format::SignatureToken, -}; -use move_command_line_common::{ - address::{NumericalAddress, ParsedAddress}, - parser::NumberFormat, -}; -use move_core_types::{account_address::AccountAddress, ident_str, runtime_value::MoveValue}; -use move_package::BuildConfig; -use sui_json::{is_receiving_argument, primitive_type}; -use sui_json_rpc_types::{SuiObjectData, SuiObjectDataOptions, SuiRawData}; -use sui_protocol_config::{Chain, ProtocolConfig}; -use sui_sdk::apis::ReadApi; -use sui_types::{ - base_types::{is_primitive_type_tag, ObjectID, TxContext, TxContextKind}, - digests::{get_mainnet_chain_identifier, get_testnet_chain_identifier}, - move_package::MovePackage, - object::Owner, - programmable_transaction_builder::ProgrammableTransactionBuilder, - resolve_address, - transaction::{self as Tx, ObjectArg}, - Identifier, TypeTag, SUI_FRAMEWORK_PACKAGE_ID, -}; - -use super::ast::{ModuleAccess as PTBModuleAccess, ParsedPTBCommand, Program}; -use crate::{ - client_commands::{compile_package, upgrade_package}, - client_ptb::{ - ast::{Argument as PTBArg, ASSIGN, GAS_BUDGET}, - error::{PTBError, PTBResult, Span, Spanned}, - }, - err, error, sp, -}; - -// =========================================================================== -// Object Resolution -// =========================================================================== -// We need to resolve the same argument in different ways depending on the -// context in which that argument is used. For example, if we are using an -// object ID as an argument to a move call that expects an object argument in -// that position, the object ID should be resolved to an object, whereas if we -// are using the same object ID as an argument to a pure value, it should be -// resolved to a pure value (e.g., the object ID itself). The different ways of -// resolving this is the purpose of the `Resolver` trait -- different contexts -// will implement this trait in different ways. - -/// A resolver is used to resolve arguments to a PTB. Depending on the context, -/// we may resolve object IDs in different ways -- e.g., in a pure context they -/// should be resolved to a pure value, whereas in an object context they should -/// be resolved to the appropriate object argument. -#[async_trait] -trait Resolver<'a>: Send { - /// Resolve a pure value. This should almost always resolve to a pure value. - async fn pure( - &mut self, - builder: &mut PTBBuilder<'a>, - loc: Span, - val: MoveValue, - ) -> PTBResult { - builder.ptb.pure(val).map_err(|e| err!(loc, "{e}")) - } - - async fn resolve_object_id( - &mut self, - builder: &mut PTBBuilder<'a>, - loc: Span, - obj_id: ObjectID, - ) -> PTBResult; - - fn re_resolve(&self) -> bool { - false - } -} - -/// A resolver that resolves object IDs to object arguments. -/// * If `is_receiving` is true, then the object argument will be resolved to a -/// receiving object argument. -/// * If `is_mut` is true, then the object argument will be resolved to a -/// mutable object argument. -struct ToObject { - is_receiving: bool, - is_mut: bool, -} - -impl Default for ToObject { - fn default() -> Self { - Self { - is_receiving: false, - is_mut: true, - } - } -} - -impl ToObject { - fn new(is_receiving: bool, is_mut: bool) -> Self { - Self { - is_receiving, - is_mut, - } - } -} - -#[async_trait] -impl<'a> Resolver<'a> for ToObject { - async fn resolve_object_id( - &mut self, - builder: &mut PTBBuilder<'a>, - loc: Span, - obj_id: ObjectID, - ) -> PTBResult { - // Get the object from the reader to get metadata about the object. - let obj = builder.get_object(obj_id, loc).await?; - let owner = obj - .owner - .ok_or_else(|| err!(loc, "Unable to get owner info for object {obj_id}"))?; - let object_ref = obj.object_ref(); - // Depending on the ownership of the object, we resolve it to different types of - // object arguments for the transaction. - let obj_arg = match owner { - Owner::AddressOwner(_) if self.is_receiving => ObjectArg::Receiving(object_ref), - Owner::Immutable | Owner::AddressOwner(_) => ObjectArg::ImmOrOwnedObject(object_ref), - Owner::Shared { - initial_shared_version, - } => ObjectArg::SharedObject { - id: object_ref.0, - initial_shared_version, - mutable: self.is_mut, - }, - Owner::ObjectOwner(_) => { - error!(loc => help: { - "{obj_id} is an object-owned object, you can only use immutable, shared, or owned objects here." - }, "Cannot use an object-owned object as an argument") - } - }; - // Insert the correct object arg that we built above into the transaction. - builder.ptb.obj(obj_arg).map_err(|e| err!(loc, "{e}")) - } - - // We always re-resolve object IDs to object arguments if we need it mutably -- - // we could have added it earlier as an immutable argument. - fn re_resolve(&self) -> bool { - self.is_mut - } -} - -/// A resolver that resolves object IDs that it encounters to pure PTB values. -struct ToPure; - -#[async_trait] -impl<'a> Resolver<'a> for ToPure { - async fn resolve_object_id( - &mut self, - builder: &mut PTBBuilder<'a>, - loc: Span, - obj_id: ObjectID, - ) -> PTBResult { - builder.ptb.pure(obj_id).map_err(|e| err!(loc, "{e}")) - } -} - -// =========================================================================== -// PTB Builder and PTB Creation -// =========================================================================== - -/// The PTBBuilder struct is the main workhorse that transforms a sequence of -/// `ParsedPTBCommand`s into an actual PTB that can be run. The main things to -/// keep in mind are that this contains: -/// - A way to handle identifiers -- note that we "lazily" resolve identifiers -/// to arguments, so that the first usage of the identifier determines what it -/// is resolved to. If an identifier is used in multiple positions at -/// different resolutions (e.g., in one place as an object argument, and in -/// another as a pure value), this will result in an error. This error can be -/// avoided by creating another identifier for the second usage. -/// - A way to resolve arguments -- this is done by calling `resolve` on a -/// `PTBArg` and passing in appropriate context. The context is used to -/// determine how to resolve the argument -- e.g., if an object ID should be -/// resolved to a pure value or an object argument. -/// - A way to bind the result of a command to an identifier. -pub struct PTBBuilder<'a> { - /// A map from identifiers to addresses. This is used to support address - /// resolution, and also supports external address sources (e.g., - /// keystore). - addresses: BTreeMap, - /// A map from identifiers to the file scopes in which they were declared. - /// This is used for reporting shadowing warnings. - identifiers: BTreeMap>, - /// The arguments that we need to resolve. This is a map from identifiers to - /// the argument values -- they haven't been resolved to a transaction - /// argument yet. - arguments_to_resolve: BTreeMap, - /// The arguments that we have resolved. This is a map from identifiers to - /// the actual transaction arguments. - resolved_arguments: BTreeMap, - /// Read API for reading objects from chain. Needed for object resolution. - reader: &'a ReadApi, - /// The last command that we have added. This is used to support assignment - /// commands. - last_command: Option, - /// The actual PTB that we are building up. - ptb: ProgrammableTransactionBuilder, - /// The list of errors that we have built up while processing commands. We - /// do not report errors eagerly but instead wait until we have - /// processed all commands to report any errors. - errors: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -enum ResolvedAccess { - ResultAccess(u16), - DottedString(String), -} - -/// Hold a PTB argument, always remembering its most recent state even if it's -/// already been resolved. -#[derive(Debug)] -enum ArgWithHistory { - Resolved(Spanned), - Unresolved(Spanned), -} - -impl ArgWithHistory { - fn get_unresolved(&self) -> Option<&Spanned> { - match self { - ArgWithHistory::Resolved(_) => None, - ArgWithHistory::Unresolved(x) => Some(x), - } - } - - fn get(&self) -> &Spanned { - match self { - ArgWithHistory::Resolved(x) => x, - ArgWithHistory::Unresolved(x) => x, - } - } - - fn resolve(&mut self) { - *self = match self { - ArgWithHistory::Resolved(x) => ArgWithHistory::Resolved(x.clone()), - ArgWithHistory::Unresolved(x) => ArgWithHistory::Resolved(x.clone()), - } - } - - fn is_resolved(&self) -> bool { - matches!(self, ArgWithHistory::Resolved(_)) - } -} - -impl<'a> PTBBuilder<'a> { - pub fn new(starting_env: BTreeMap, reader: &'a ReadApi) -> Self { - Self { - addresses: starting_env, - identifiers: BTreeMap::new(), - arguments_to_resolve: BTreeMap::new(), - resolved_arguments: BTreeMap::new(), - ptb: ProgrammableTransactionBuilder::new(), - reader, - last_command: None, - errors: Vec::new(), - } - } - - /// Finalize a PTB. If there were errors during the construction of the PTB - /// these are returned now. Otherwise, the PTB is finalized and - /// returned. If the warn_on_shadowing flag was set, then we will print - /// warnings for any shadowed variables that we encountered during the - /// building of the PTB. - pub fn finish( - self, - warn_on_shadowing: bool, - ) -> ( - Result>, - Vec, - ) { - let mut warnings = vec![]; - if warn_on_shadowing { - for (ident, commands) in self.identifiers.iter() { - if commands.len() == 1 { - continue; - } - - for (i, command_loc) in commands.iter().enumerate() { - if i == 0 { - warnings.push(PTBError { - message: format!("Variable '{}' first declared here", ident), - span: *command_loc, - help: None, - severity: Severity::Warning, - }); - } else { - warnings.push(PTBError { - message: format!( - "Variable '{}' used again here (shadowed) for the {} time.", - ident, to_ordinal_contraction(i + 1) - ), - span: *command_loc, - help: Some("You can either rename this variable, or do not \ - pass the `warn-shadows` flag to ignore these types of errors.".to_string()), - severity: Severity::Warning, - }); - } - } - } - } - - if !self.errors.is_empty() { - return (Err(self.errors), warnings); - } - - let ptb = self.ptb.finish(); - (Ok(ptb), warnings) - } - - pub async fn build( - mut self, - program: Program, - ) -> ( - Result>, - Vec, - ) { - for command in program.commands.into_iter() { - self.handle_command(command).await; - } - self.finish(program.warn_shadows_set) - } - - /// Add a single PTB command to the PTB that we are building up. - /// Errors are added to the `errors` field of the PTBBuilder. - async fn handle_command(&mut self, sp!(span, command): Spanned) { - if let Err(e) = self.handle_command_(span, command).await { - self.errors.push(e); - } - } - - // =========================================================================== - // Declaring and handling identifiers and variables - // =========================================================================== - - /// Declare an identifier. This is used to support shadowing warnings. - fn declare_identifier(&mut self, ident: String, ident_loc: Span) { - let e = self.identifiers.entry(ident).or_default(); - e.push(ident_loc); - } - - /// Declare a possible address binding. This is used to support address - /// resolution. If the `possible_addr` is not an address, then this is a - /// no-op. - fn declare_possible_address_binding(&mut self, ident: String, possible_addr: &Spanned) { - match possible_addr.value { - PTBArg::Address(addr) => { - self.addresses.insert(ident, addr.into_inner()); - } - PTBArg::Identifier(ref i) => { - // We do a one-hop resolution here to see if we can resolve the identifier to an - // externally-bound address (i.e., one coming in through the initial - // environment). This will also handle direct aliasing of - // addresses throughout the ptb. Note that we don't do this - // recursively so no need to worry about loops/cycles. - if let Some(addr) = self.addresses.get(i) { - self.addresses.insert(ident, *addr); - } - } - // If we encounter a dotted string e.g., "foo.0" or "sui.io" or something like that - // this see if we can find an address for it in the environment and bind to it. - PTBArg::VariableAccess(ref head, ref fields) => { - let key = format!( - "{}.{}", - head.value, - fields - .iter() - .map(|f| f.value.clone()) - .collect::>() - .join(".") - ); - if let Some(addr) = self.addresses.get(&key) { - self.addresses.insert(ident, *addr); - } - } - _ => (), - } - } - - async fn get_protocol_config(&self, loc: Span) -> PTBResult { - let config = self - .reader - .get_protocol_config(None) - .await - .map_err(|e| err!(loc, "{e}"))?; - let chain_id = self - .reader - .get_chain_identifier() - .await - .map_err(|e| err!(loc, "{e}"))?; - Ok(if chain_id == get_mainnet_chain_identifier().to_string() { - ProtocolConfig::get_for_version(config.protocol_version, Chain::Mainnet) - } else if chain_id == get_testnet_chain_identifier().to_string() { - ProtocolConfig::get_for_version(config.protocol_version, Chain::Testnet) - } else { - ProtocolConfig::get_for_version(config.protocol_version, Chain::Unknown) - }) - } - - /// Resolve an object ID to a Move package. - async fn resolve_to_package( - &mut self, - package_id: ObjectID, - loc: Span, - ) -> PTBResult { - let object = self - .reader - .get_object_with_options(package_id, SuiObjectDataOptions::bcs_lossless()) - .await - .map_err(|e| err!(loc, "{e}"))? - .into_object() - .map_err(|e| err!(loc, "{e}"))?; - let Some(SuiRawData::Package(package)) = object.bcs else { - error!( - loc, - "BCS field in object '{}' is missing or not a package.", package_id - ); - }; - let protocol_config = self.get_protocol_config(loc).await?; - let package: MovePackage = MovePackage::new( - package.id, - object.version, - package.module_map, - protocol_config.max_move_package_size(), - package.type_origin_table, - package.linkage_table, - ) - .map_err(|e| err!(loc, "{e}"))?; - Ok(package) - } - - /// Resolves the argument to the move call based on the type information of - /// the function being called. - async fn resolve_move_call_arg( - &mut self, - view: &BinaryIndexedView<'_>, - ty_args: &[TypeTag], - sp!(loc, arg): Spanned, - param: &SignatureToken, - ) -> PTBResult { - let (is_primitive, _) = primitive_type(view, ty_args, param); - - // If it's a primitive value, see if we've already resolved this argument. - // Otherwise, we need to resolve it. - if is_primitive { - return self.resolve(loc.wrap(arg), ToPure).await; - } - - // Otherwise it's ambiguous what the value should be, and we need to turn to the - // signature to determine it. - let mut is_receiving = false; - // A value is mutable by default. - let mut is_mutable = true; - - // traverse the types in the signature to see if the argument is an object - // argument or not, and also determine if it's a receiving argument or - // not. - for tok in param.preorder_traversal() { - match tok { - SignatureToken::Struct(..) | SignatureToken::StructInstantiation(..) => { - is_receiving |= is_receiving_argument(view, tok); - } - SignatureToken::TypeParameter(idx) => { - if *idx as usize >= ty_args.len() { - error!(loc, "Not enough type parameters supplied for Move call"); - } - } - SignatureToken::Reference(_) => { - is_mutable = false; - } - SignatureToken::MutableReference(_) => { - // Not strictly needed, but for clarity - is_mutable = true; - } - SignatureToken::Bool - | SignatureToken::U8 - | SignatureToken::U64 - | SignatureToken::U128 - | SignatureToken::Address - | SignatureToken::Signer - | SignatureToken::Vector(_) - | SignatureToken::U16 - | SignatureToken::U32 - | SignatureToken::U256 => { - is_mutable = false; - } - } - } - - // Note: need to re-resolve an argument possibly since it may be used immutably - // first, and then mutably. - self.resolve(loc.wrap(arg), ToObject::new(is_receiving, is_mutable)) - .await - } - - /// Resolve the arguments to a Move call based on the type information about - /// the function being called. - async fn resolve_move_call_args( - &mut self, - package: MovePackage, - sp!(mloc, module_name): &Spanned, - sp!(floc, function_name): &Spanned, - ty_args: &[TypeTag], - args: Vec>, - package_name_loc: Span, - ) -> PTBResult> { - let module = package - .deserialize_module(module_name, &BinaryConfig::standard()) - .map_err(|e| { - let help_message = if package.serialized_module_map().is_empty() { - Some("No modules found in this package".to_string()) - } else { - display_did_you_mean(find_did_you_means( - module_name.as_str(), - package - .serialized_module_map() - .iter() - .map(|(x, _)| x.as_str()), - )) - }; - let e = err!(*mloc, "{e}"); - if let Some(help_message) = help_message { - e.with_help(help_message) - } else { - e - } - })?; - let fdef = module - .function_defs - .iter() - .find(|fdef| { - module.identifier_at(module.function_handle_at(fdef.function).name) - == function_name.as_ident_str() - }) - .ok_or_else(|| { - let e = err!( - *floc, - "Could not resolve function '{}' in module '{}'", - function_name, - module_name - ); - if let Some(help_message) = display_did_you_mean(find_did_you_means( - function_name.as_str(), - module.function_defs.iter().map(|fdef| { - module - .identifier_at(module.function_handle_at(fdef.function).name) - .as_str() - }), - )) { - e.with_help(help_message) - } else { - e - } - })?; - let function_signature = module.function_handle_at(fdef.function); - let view = BinaryIndexedView::Module(&module); - let parameters: Vec<_> = module - .signature_at(function_signature.parameters) - .0 - .clone() - .into_iter() - .filter(|tok| matches!(TxContext::kind(&view, tok), TxContextKind::None)) - .collect(); - - if parameters.len() != args.len() { - let loc = if args.is_empty() { - package_name_loc.widen(*mloc).widen(*floc) - } else { - args[0].span.widen_opt(args.last().map(|x| x.span)) - }; - error!( - loc, - "Expected {} argument{}, but got {}", - parameters.len(), - if parameters.len() == 1 { "" } else { "s" }, - args.len() - ); - } - - let mut call_args = vec![]; - for (param, arg) in parameters.iter().zip(args.into_iter()) { - let call_arg = self - .resolve_move_call_arg(&view, ty_args, arg, param) - .await?; - call_args.push(call_arg); - } - Ok(call_args) - } - - fn resolve_variable_access( - &self, - head: &Spanned, - fields: Vec>, - ) -> Spanned { - if fields.len() == 1 { - // Get the span and value of the field zero'th field. Safe since we just checked - // the length above. Since the length is 1, we know that the field - // is non-empty. - let sp!(field_loc, field) = &fields[0]; - if let Ok(n) = field.parse::() { - return field_loc.wrap(ResolvedAccess::ResultAccess(n)); - } - } - let tl_loc = head.span.widen_opt(fields.last().map(|x| x.span)); - tl_loc.wrap(ResolvedAccess::DottedString(format!( - "{}.{}", - head.value, - fields - .into_iter() - .map(|f| f.value) - .collect::>() - .join(".") - ))) - } - - /// Resolve an argument based on the argument value, and the `resolver` that - /// is passed in. - #[async_recursion] - async fn resolve( - &mut self, - sp!(arg_loc, arg): Spanned, - mut ctx: impl Resolver<'a> + 'async_recursion, - ) -> PTBResult { - match arg { - a @ (PTBArg::Bool(_) - | PTBArg::U8(_) - | PTBArg::U16(_) - | PTBArg::U32(_) - | PTBArg::U64(_) - | PTBArg::U128(_) - | PTBArg::U256(_) - | PTBArg::String(_) - | PTBArg::Option(_) - | PTBArg::Vector(_)) => { - ctx.pure(self, arg_loc, a.to_pure_move_value(arg_loc)?) - .await - } - PTBArg::Gas => Ok(Tx::Argument::GasCoin), - // NB: the ordering of these lines is important so that shadowing is properly - // supported. - // If we encounter an identifier that we have not already resolved, then we resolve the - // value and return it. - PTBArg::Identifier(i) - if self - .arguments_to_resolve - .get(&i) - .is_some_and(|arg_hist| !arg_hist.is_resolved()) => - { - let arg_hist = self.arguments_to_resolve.get(&i).unwrap(); - let arg = arg_hist.get().clone(); - let resolved = self.resolve(arg, ctx).await?; - self.arguments_to_resolve.get_mut(&i).unwrap().resolve(); - self.resolved_arguments.insert(i, resolved); - Ok(resolved) - } - // If the identifier does not need to be resolved, but has already been resolved, then - // we return the resolved value. - PTBArg::Identifier(i) if self.resolved_arguments.contains_key(&i) => { - if ctx.re_resolve() && self.arguments_to_resolve.contains_key(&i) { - self.resolve(self.arguments_to_resolve[&i].get().clone(), ctx) - .await - } else { - Ok(self.resolved_arguments[&i]) - } - } - // Lastly -- look to see if this is an address that has been either declared in scope, - // or that is coming from an external source (e.g., the keystore). - PTBArg::Identifier(i) if self.addresses.contains_key(&i) => { - // We now have a location for this address (which may have come from the - // keystore so we didnt' have an address for it before), so we - // tag it with its first usage location put it in the arguments - // to resolve and resolve away. - let addr = self.addresses[&i]; - let arg = arg_loc.wrap(PTBArg::Address(NumericalAddress::new( - addr.into_bytes(), - NumberFormat::Hex, - ))); - self.arguments_to_resolve - .insert(i.clone(), ArgWithHistory::Unresolved(arg.clone())); - self.resolve(arg_loc.wrap(PTBArg::Identifier(i)), ctx).await - } - PTBArg::Address(addr) => { - let object_id = ObjectID::from_address(addr.into_inner()); - ctx.resolve_object_id(self, arg_loc, object_id).await - } - PTBArg::VariableAccess(head, fields) => { - // Since keystore aliases can contain dots, we need to resolve - // these/disambiguate them as best as possible here. - // First: See if structurally we know whether this is a dotted access or a - // string(alias) containing dot(s). If there is more than one dotted access, or - // if the field(s) are not all numbers, then we assume it's a alias. - match self.resolve_variable_access(&head, fields) { - sp!(l, ResolvedAccess::DottedString(string)) => { - self.resolve(l.wrap(PTBArg::Identifier(string)), ctx).await - } - sp!(_, ResolvedAccess::ResultAccess(access)) => { - match self.resolved_arguments.get(&head.value) { - Some(Tx::Argument::Result(u)) => { - Ok(Tx::Argument::NestedResult(*u, access)) - } - // Tried to access into a nested result, input, or gascoin - Some( - x @ (Tx::Argument::NestedResult(..) - | Tx::Argument::Input(..) - | Tx::Argument::GasCoin), - ) => { - error!( - arg_loc, - "Tried to access a nested result, input, or gascoin {}: {}", - head.value, - x, - ); - } - // Unable to resolve, so now see if we can resolve it to an alias, i.e., - // handle a alias that looks something like `foo.0` - None => { - let formatted_access = format!("{}.{}", head.value, access); - if !self.addresses.contains_key(&formatted_access) - && !self.identifiers.contains_key(&formatted_access) - { - match self.did_you_mean_identifier(&head.value) { - Some(similars) => { - error!( - head.span => help: { "{}", similars }, - "Tried to access an unresolved identifier: {}", head.value - ); - } - None => { - error!( - head.span, - "Tried to access an unresolved identifier: {}", - head.value - ); - } - } - } - self.resolve( - arg_loc.wrap(PTBArg::Identifier(formatted_access.clone())), - ctx, - ) - .await - } - } - } - } - } - // Unable to resolve an identifer to anything at this point -- error and see if we can - // find a similar identifier to suggest. - PTBArg::Identifier(i) => match self.did_you_mean_identifier(&i) { - Some(similars) => { - error!(arg_loc => help: { "{}", similars }, "Unresolved identifier: '{}'", i) - } - None => error!(arg_loc, "Unresolved identifier: '{}'", i), - }, - } - } - - /// Fetch the `SuiObjectData` for an object ID -- this is used for object - /// resolution. - async fn get_object(&self, object_id: ObjectID, obj_loc: Span) -> PTBResult { - let res = self - .reader - .get_object_with_options( - object_id, - SuiObjectDataOptions::new().with_type().with_owner(), - ) - .await - .map_err(|e| err!(obj_loc, "{e}"))? - .into_object() - .map_err(|e| err!(obj_loc, "{e}"))?; - Ok(res) - } - - /// Create a "did you mean" message for an identifier with the context of - /// our different binding environments. - fn did_you_mean_identifier(&self, ident: &str) -> Option { - let did_you_means = find_did_you_means( - ident, - self.resolved_arguments - .keys() - .chain(self.arguments_to_resolve.keys()) - .chain(self.addresses.keys()) - .map(|x| x.as_str()), - ); - display_did_you_mean(did_you_means) - } - - /// Add a single PTB command to the PTB that we are building up. This is the - /// workhorse of it all. - async fn handle_command_( - &mut self, - cmd_span: Span, - command: ParsedPTBCommand, - ) -> PTBResult<()> { - // let sp!(cmd_span, tok) = &command.name; - match command { - ParsedPTBCommand::TransferObjects(obj_args, to_address) => { - let to_arg = self.resolve(to_address, ToPure).await?; - let mut transfer_args = vec![]; - for o in obj_args.value.into_iter() { - let arg = self.resolve(o, ToObject::default()).await?; - transfer_args.push(arg); - } - self.last_command = Some( - self.ptb - .command(Tx::Command::TransferObjects(transfer_args, to_arg)), - ); - } - ParsedPTBCommand::Assign(sp!(ident_loc, i), None) => { - let Some(prev_ptb_arg) = self.last_command.take() else { - error!( - ident_loc => help: { - "This is most likely because the previous command did not \ - produce a result. E.g., '{ASSIGN}' or '{GAS_BUDGET}' commands do not produce results." - - }, - "Cannot assign a value to this variable." - ); - }; - self.declare_identifier(i.clone(), ident_loc); - self.resolved_arguments.insert(i, prev_ptb_arg); - } - ParsedPTBCommand::Assign(sp!(ident_loc, i), Some(arg_w_loc)) => { - self.declare_identifier(i.clone(), ident_loc); - self.declare_possible_address_binding(i.clone(), &arg_w_loc); - self.arguments_to_resolve - .insert(i, ArgWithHistory::Unresolved(arg_w_loc)); - } - ParsedPTBCommand::MakeMoveVec(sp!(ty_loc, ty_arg), sp!(_, args)) => { - let ty_arg = ty_arg - .into_type_tag(&resolve_address) - .map_err(|e| err!(ty_loc, "{e}"))?; - let mut vec_args: Vec = vec![]; - if is_primitive_type_tag(&ty_arg) { - for arg in args.into_iter() { - let arg = self.resolve(arg, ToPure).await?; - vec_args.push(arg); - } - } else { - for arg in args.into_iter() { - let arg = self.resolve(arg, ToObject::default()).await?; - vec_args.push(arg); - } - } - let res = self - .ptb - .command(Tx::Command::MakeMoveVec(Some(ty_arg), vec_args)); - self.last_command = Some(res); - } - ParsedPTBCommand::SplitCoins(pre_coin, sp!(_, amounts)) => { - let coin = self.resolve(pre_coin, ToObject::default()).await?; - let mut args = vec![]; - for arg in amounts.into_iter() { - let arg = self.resolve(arg, ToPure).await?; - args.push(arg); - } - let res = self.ptb.command(Tx::Command::SplitCoins(coin, args)); - self.last_command = Some(res); - } - ParsedPTBCommand::MergeCoins(pre_coin, sp!(_, coins)) => { - let coin = self.resolve(pre_coin, ToObject::default()).await?; - let mut args = vec![]; - for arg in coins.into_iter() { - let arg = self.resolve(arg, ToObject::default()).await?; - args.push(arg); - } - let res = self.ptb.command(Tx::Command::MergeCoins(coin, args)); - self.last_command = Some(res); - } - ParsedPTBCommand::MoveCall( - sp!( - mod_access_loc, - PTBModuleAccess { - address, - module_name, - function_name, - } - ), - in_ty_args, - args, - ) => { - let mut ty_args = vec![]; - - if let Some(sp!(ty_loc, in_ty_args)) = in_ty_args { - for t in in_ty_args.into_iter() { - ty_args.push( - t.into_type_tag(&resolve_address) - .map_err(|e| err!(ty_loc, "{e}"))?, - ) - } - } - - let resolved_address = address.value.clone().into_account_address(&|s| { - self.addresses.get(s).cloned().or_else(|| resolve_address(s)) - }).map_err(|e| { - let e = err!(address.span, "{e}"); - if let ParsedAddress::Named(name) = address.value { - e.with_help( - format!("This is most likely because the named address '{name}' is not in scope. \ - You can either bind a variable to the address that you want to use or use the address in the command.")) - } else { - e - } - })?; - - let package_id = ObjectID::from_address(resolved_address); - let package = self.resolve_to_package(package_id, address.span).await?; - let args = self - .resolve_move_call_args( - package, - &module_name, - &function_name, - &ty_args, - args, - mod_access_loc, - ) - .await?; - let move_call = Tx::ProgrammableMoveCall { - package: package_id, - module: module_name.value, - function: function_name.value, - type_arguments: ty_args, - arguments: args, - }; - let res = self.ptb.command(Tx::Command::MoveCall(Box::new(move_call))); - self.last_command = Some(res); - } - ParsedPTBCommand::Publish(sp!(pkg_loc, package_path)) => { - let (dependencies, compiled_modules, _, _) = compile_package( - self.reader, - BuildConfig::default(), - PathBuf::from(package_path), - false, // with_unpublished_dependencies - false, // skip_dependency_verification - ) - .await - .map_err(|e| err!(pkg_loc, "{e}"))?; - - let res = self.ptb.publish_upgradeable( - compiled_modules, - dependencies.published.into_values().collect(), - ); - self.last_command = Some(res); - } - // Update this command to not do as many things. It should result in a single command. - ParsedPTBCommand::Upgrade(sp!(path_loc, package_path), mut arg) => { - if let sp!(loc, PTBArg::Identifier(id)) = arg { - arg = self - .arguments_to_resolve - .get(&id) - .and_then(|x| x.get_unresolved()) - .ok_or_else(|| err!(loc, "Unable to find object ID argument"))? - .clone(); - } - let (cap_loc, upgrade_cap_id) = match arg { - sp!(loc, PTBArg::Address(id)) => (loc, id), - sp!(loc, _) => { - error!(loc, "Expected upgrade capability object ID"); - } - }; - - let upgrade_cap_arg = self - .resolve( - cap_loc.wrap(PTBArg::Address(upgrade_cap_id)), - ToObject::default(), - ) - .await?; - - let (package_id, compiled_modules, dependencies, package_digest, upgrade_policy) = - upgrade_package( - self.reader, - BuildConfig::default(), - PathBuf::from(package_path), - ObjectID::from_address(upgrade_cap_id.into_inner()), - false, // with_unpublished_dependencies - false, // skip_dependency_verification - ) - .await - .map_err(|e| err!(path_loc, "{e}"))?; - - let upgrade_arg = self - .ptb - .pure(upgrade_policy) - .map_err(|e| err!(cmd_span, "{e}"))?; - let digest_arg = self - .ptb - .pure(package_digest) - .map_err(|e| err!(cmd_span, "{e}"))?; - let upgrade_ticket = - self.ptb - .command(Tx::Command::MoveCall(Box::new(Tx::ProgrammableMoveCall { - package: SUI_FRAMEWORK_PACKAGE_ID, - module: ident_str!("package").to_owned(), - function: ident_str!("authorize_upgrade").to_owned(), - type_arguments: vec![], - arguments: vec![upgrade_cap_arg, upgrade_arg, digest_arg], - }))); - let upgrade_receipt = self.ptb.upgrade( - package_id, - upgrade_ticket, - dependencies.published.into_values().collect(), - compiled_modules, - ); - let res = - self.ptb - .command(Tx::Command::MoveCall(Box::new(Tx::ProgrammableMoveCall { - package: SUI_FRAMEWORK_PACKAGE_ID, - module: ident_str!("package").to_owned(), - function: ident_str!("commit_upgrade").to_owned(), - type_arguments: vec![], - arguments: vec![upgrade_cap_arg, upgrade_receipt], - }))); - self.last_command = Some(res); - } - ParsedPTBCommand::WarnShadows => {} - ParsedPTBCommand::Preview => {} - } - Ok(()) - } -} - -// =========================================================================== -// Helper methods -// =========================================================================== -pub fn to_ordinal_contraction(num: usize) -> String { - let suffix = match num % 100 { - // exceptions - 11..=13 => "th", - _ => match num % 10 { - 1 => "st", - 2 => "nd", - 3 => "rd", - _ => "th", - }, - }; - format!("{}{}", num, suffix) -} - -pub(crate) fn find_did_you_means<'a>( - needle: &str, - haystack: impl IntoIterator, -) -> Vec<&'a str> { - let mut results = Vec::new(); - let mut best_distance = usize::MAX; - - for item in haystack { - let distance = edit_distance(needle, item); - - match distance.cmp(&best_distance) { - std::cmp::Ordering::Less => { - best_distance = distance; - results.clear(); - results.push(item); - } - std::cmp::Ordering::Equal => { - results.push(item); - } - std::cmp::Ordering::Greater => {} - } - } - - results -} - -pub(crate) fn display_did_you_mean + std::fmt::Display>( - possibles: Vec, -) -> Option { - if possibles.is_empty() { - return None; - } - - let mut strs = vec![]; - - let preposition = if possibles.len() == 1 { - "Did you mean " - } else { - "Did you mean one of " - }; - - let len = possibles.len(); - for (i, possible) in possibles.into_iter().enumerate() { - if i == len - 1 && len > 1 { - strs.push(format!("or '{}'", possible)); - } else { - strs.push(format!("'{}'", possible)); - } - } - - Some(format!("{preposition}{}?", strs.join(", "))) -} - -// This lint is is disabled because it's not good and doesn't look at what -// you're actually iterating over. This seems to be a common problem with this -// lint. See e.g., https://github.com/rust-lang/rust-clippy/issues/6075 -#[allow(clippy::needless_range_loop)] -fn edit_distance(a: &str, b: &str) -> usize { - let mut cache = vec![vec![0; b.len() + 1]; a.len() + 1]; - - for i in 0..=a.len() { - cache[i][0] = i; - } - - for j in 0..=b.len() { - cache[0][j] = j; - } - - for (i, char_a) in a.chars().enumerate().map(|(i, c)| (i + 1, c)) { - for (j, char_b) in b.chars().enumerate().map(|(j, c)| (j + 1, c)) { - if char_a == char_b { - cache[i][j] = cache[i - 1][j - 1]; - } else { - let insert = cache[i][j - 1]; - let delete = cache[i - 1][j]; - let replace = cache[i - 1][j - 1]; - - cache[i][j] = 1 + std::cmp::min(insert, std::cmp::min(delete, replace)); - } - } - } - - cache[a.len()][b.len()] -} diff --git a/crates/sui/src/client_ptb/displays/mod.rs b/crates/sui/src/client_ptb/displays/mod.rs deleted file mode 100644 index 4b62a94e03d..00000000000 --- a/crates/sui/src/client_ptb/displays/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod gas_cost_summary; -mod ptb_preview; -mod status; -mod summary; - -pub struct Pretty<'a, T>(pub &'a T); diff --git a/crates/sui/src/client_ptb/displays/status.rs b/crates/sui/src/client_ptb/displays/status.rs deleted file mode 100644 index 136cd1db1b4..00000000000 --- a/crates/sui/src/client_ptb/displays/status.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt::{Display, Formatter}; - -use sui_json_rpc_types::SuiExecutionStatus::{self, Failure, Success}; - -use crate::client_ptb::displays::Pretty; - -impl<'a> Display for Pretty<'a, SuiExecutionStatus> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Pretty(status) = self; - - let output = match status { - Success => "success".to_string(), - Failure { error } => format!("failed due to {error}"), - }; - - write!(f, "{}", output) - } -} diff --git a/crates/sui/src/client_ptb/error.rs b/crates/sui/src/client_ptb/error.rs deleted file mode 100644 index 9ba8c97d537..00000000000 --- a/crates/sui/src/client_ptb/error.rs +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt; - -use miette::{miette, LabeledSpan, Severity}; -use thiserror::Error; - -pub type PTBResult = Result; - -/// Represents the location of a range of text in the PTB source. -#[derive(Debug, Clone, PartialEq, Eq, Copy)] -pub struct Span { - pub start: usize, - pub end: usize, -} - -/// A value that has an associated location in source code. -pub struct Spanned { - pub span: Span, - pub value: T, -} - -/// An error with a message, a location in the source code, and an optional help -/// message. -#[derive(Debug, Clone, Error)] -#[error("{message}")] -pub struct PTBError { - pub message: String, - pub span: Span, - pub help: Option, - pub severity: Severity, -} - -#[macro_export] -macro_rules! sp { - (_, $value:pat) => { - $crate::client_ptb::error::Spanned { value: $value, .. } - }; - ($loc:pat, _) => { - $crate::client_ptb::error::Spanned { span: $loc, .. } - }; - ($loc:pat, $value:pat) => { - $crate::client_ptb::error::Spanned { - span: $loc, - value: $value, - } - }; -} - -#[macro_export] -macro_rules! error { - ($l:expr, $($arg:tt)*) => { - return Err($crate::err!($l, $($arg)*)) - }; - ($l:expr => help: { $($h:expr),* }, $($arg:tt)*) => { - return Err($crate::err!($l => help: { $($h),* }, $($arg)*)) - }; -} - -#[macro_export] -macro_rules! err { - ($l:expr, $($arg:tt)*) => { - $crate::client_ptb::error::PTBError { - message: format!($($arg)*), - span: $l, - help: None, - severity: miette::Severity::Error, - } - }; - ($l:expr => help: { $($h:expr),* }, $($arg:tt)*) => { - $crate::client_ptb::error::PTBError { - message: format!($($arg)*), - span: $l, - help: Some(format!($($h),*)), - severity: miette::Severity::Error, - } - }; -} - -pub use sp; - -impl PTBError { - /// Add a help message to an error. - pub fn with_help(self, help: String) -> Self { - let PTBError { - message, - span, - help: _, - severity, - } = self; - PTBError { - message, - span, - help: Some(help), - severity, - } - } -} - -impl Span { - /// Wrap a value with a span. - pub fn wrap(self, value: T) -> Spanned { - Spanned { span: self, value } - } - - /// Widen the span to include another span. The resulting span will start at - /// the minimum of the two start positions and end at the maximum of the - /// two end positions. - pub fn widen(self, other: Span) -> Span { - Span { - start: self.start.min(other.start), - end: self.end.max(other.end), - } - } - - /// Widen the span to include another if it is Some, otherwise return the - /// original span. - pub fn widen_opt(self, other: Option) -> Span { - other.map_or(self, |other| self.widen(other)) - } - - /// Create a span that points to the end of the file/string contents. - pub fn eof_span() -> Span { - Self { - start: usize::MAX, - end: usize::MAX, - } - } -} - -impl Spanned { - /// Apply a function `f` to the underlying value, returning a new `Spanned` - /// with the same span. - pub fn map(self, f: impl FnOnce(T) -> U) -> Spanned { - Spanned { - span: self.span, - value: f(self.value), - } - } - - /// Widen the span to include another span. The resulting span will start at - /// the minimum of the two start positions and end at the maximum of the - /// two end positions. - pub fn widen(self, other: Spanned) -> Spanned { - self.widen_span(other.span) - } - - /// Widen the span to include another span. The resulting span will start at - /// the minimum of the two start positions and end at the maximum of the - /// two end positions. - pub fn widen_span(self, other: Span) -> Spanned { - Spanned { - span: self.span.widen(other), - value: self.value, - } - } -} - -impl fmt::Debug for Spanned { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Spanned") - .field("span", &self.span) - .field("value", &self.value) - .finish() - } -} - -impl Clone for Spanned { - fn clone(&self) -> Self { - Spanned { - span: self.span, - value: self.value.clone(), - } - } -} - -impl Copy for Spanned {} - -fn build_error_report(file_string: &str, error: PTBError) -> miette::Report { - let PTBError { - span, - message, - help, - severity, - } = error; - let clamp = |x: usize| x.min(file_string.len() - 1); - let label = LabeledSpan::at(clamp(span.start)..clamp(span.end), message.clone()); - let error_string = match severity { - Severity::Advice => "Advice found when processing PTB".to_string(), - Severity::Warning => "Warning when processing PTB".to_string(), - Severity::Error => "Error when processing PTB".to_string(), - }; - match help { - Some(help_msg) => miette!(labels = vec![label], help = help_msg, "{}", error_string), - None => miette!( - labels = vec![label], - severity = severity, - "{}", - error_string - ), - } - .with_source_code(file_string.to_string()) -} - -pub fn build_error_reports(source_string: &str, errors: Vec) -> Vec { - errors - .into_iter() - .map(|e| build_error_report(source_string, e)) - .collect() -} diff --git a/crates/sui/src/client_ptb/mod.rs b/crates/sui/src/client_ptb/mod.rs deleted file mode 100644 index e30fdc40093..00000000000 --- a/crates/sui/src/client_ptb/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod ast; -pub mod builder; -pub mod displays; -pub mod error; -pub mod lexer; -pub mod parser; -pub mod ptb; -pub mod token; diff --git a/crates/sui/src/client_ptb/parser.rs b/crates/sui/src/client_ptb/parser.rs deleted file mode 100644 index 459a7697615..00000000000 --- a/crates/sui/src/client_ptb/parser.rs +++ /dev/null @@ -1,1031 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::iter::Peekable; - -use move_command_line_common::{ - address::{NumericalAddress, ParsedAddress}, - parser::{parse_u128, parse_u16, parse_u256, parse_u32, parse_u64, parse_u8}, - types::{ParsedFqName, ParsedModuleId, ParsedStructType, ParsedType}, -}; -use sui_types::{base_types::ObjectID, Identifier}; - -use super::{ - ast::{self as A, is_keyword, Argument, ModuleAccess, ParsedPTBCommand, ParsedProgram}, - error::{PTBError, PTBResult, Span, Spanned}, - lexer::Lexer, - token::{Lexeme, Token}, -}; -use crate::{ - client_ptb::{ - ast::{all_keywords, COMMANDS}, - builder::{display_did_you_mean, find_did_you_means}, - }, - err, error, sp, -}; - -/// Parse a program -pub struct ProgramParser<'a, I: Iterator> { - tokens: Peekable>, - state: ProgramParsingState, -} - -struct ProgramParsingState { - parsed: Vec>, - errors: Vec, - preview_set: bool, - summary_set: bool, - warn_shadows_set: bool, - serialize_unsigned_set: bool, - serialize_signed_set: bool, - json_set: bool, - gas_object_id: Option>, - gas_budget: Option>, -} - -impl<'a, I: Iterator> ProgramParser<'a, I> { - /// Create a PTB program parser from a sequence of string. - pub fn new(tokens: I) -> PTBResult { - let Some(tokens) = Lexer::new(tokens) else { - error!(Span { start: 0, end: 0 }, "No tokens") - }; - Ok(Self { - tokens: tokens.peekable(), - state: ProgramParsingState { - parsed: Vec::new(), - errors: Vec::new(), - preview_set: false, - summary_set: false, - warn_shadows_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - json_set: false, - gas_object_id: None, - gas_budget: None, - }, - }) - } - - /// Parse the sequence of strings into a PTB program. We continue to parse - /// even if an error is raised, and return the errors at the end. If no - /// errors are raised, we return the parsed PTB program along with the - /// metadata that we have parsed (e.g., json output, summary). - pub fn parse(mut self) -> Result> { - use Lexeme as L; - use Token as T; - - while let Some(sp!(sp, lexeme)) = self.tokens.next() { - macro_rules! try_ { - ($expr: expr) => { - match $expr { - Ok(arg) => arg, - Err(err) => { - self.state.errors.push(err); - self.fast_forward_to_next_command(); - continue; - } - } - }; - } - - macro_rules! command { - ($args:expr) => {{ - let sp!(sp_args, value) = try_!($args); - let cmd = sp.widen(sp_args).wrap(value); - self.state.parsed.push(cmd); - }}; - } - - macro_rules! flag { - ($flag:ident) => {{ - self.state.$flag = true; - }}; - } - - match lexeme { - L(T::Command, A::SERIALIZE_UNSIGNED) => flag!(serialize_unsigned_set), - L(T::Command, A::SERIALIZE_SIGNED) => flag!(serialize_signed_set), - L(T::Command, A::SUMMARY) => flag!(summary_set), - L(T::Command, A::JSON) => flag!(json_set), - L(T::Command, A::PREVIEW) => flag!(preview_set), - L(T::Command, A::WARN_SHADOWS) => flag!(warn_shadows_set), - L(T::Command, A::GAS_COIN) => { - let specifier = try_!(self.parse_gas_specifier()); - self.state.gas_object_id = Some(specifier); - } - L(T::Command, A::GAS_BUDGET) => { - let budget = try_!(self.parse_gas_budget()).widen_span(sp); - if let Some(other) = self.state.gas_budget.replace(budget) { - self.state.errors.extend([ - err!( - other.span, - "Multiple gas budgets found. Gas budget first set here.", - ), - err!(budget.span => help: { - "PTBs must have exactly one gas budget set." - },"Budget set again here."), - ]); - self.fast_forward_to_next_command(); - } - } - - L(T::Command, A::TRANSFER_OBJECTS) => command!(self.parse_transfer_objects()), - L(T::Command, A::SPLIT_COINS) => command!(self.parse_split_coins()), - L(T::Command, A::MERGE_COINS) => command!(self.parse_merge_coins()), - L(T::Command, A::ASSIGN) => command!(self.parse_assign()), - L(T::Command, A::MAKE_MOVE_VEC) => command!(self.parse_make_move_vec()), - L(T::Command, A::MOVE_CALL) => command!(self.parse_move_call()), - - L(T::Publish, src) => command!({ - let src = sp.wrap(src.to_owned()); - Ok(sp.wrap(ParsedPTBCommand::Publish(src))) - }), - - L(T::Upgrade, src) => command!({ - let src = sp.wrap(src.to_owned()); - let cap = try_!(self.parse_argument()); - Ok(cap.span.wrap(ParsedPTBCommand::Upgrade(src, cap))) - }), - - L(T::Command, s) => { - let possibles = find_did_you_means(s, COMMANDS.iter().copied()) - .into_iter() - .map(|s| format!("--{s}")) - .collect(); - let err = if let Some(suggestion) = display_did_you_mean(possibles) { - err!( - sp => help: { "{suggestion}" }, - "Unknown {lexeme}", - ) - } else { - err!(sp, "Unknown {lexeme}") - }; - self.state.errors.push(err); - self.fast_forward_to_next_command(); - } - - L(T::Eof, _) => break, - - unexpected => { - let err = err!( - sp => help: { "Expected to find a command here" }, - "Unexpected {unexpected}", - ); - - self.state.errors.push(err); - if unexpected.is_terminal() { - break; - } else { - self.fast_forward_to_next_command(); - } - } - } - } - - let sp!(sp, tok) = self.peek(); - - if !tok.is_terminal() { - self.state - .errors - .push(err!(sp, "Trailing {tok} found after the last command",)); - } - - let Some(gas_budget) = self.state.gas_budget else { - self.state.errors.push(err!( - sp => help: { "Use --gas-budget to set a gas budget" }, - "Gas budget not set." - )); - return Err(self.state.errors); - }; - - if self.state.errors.is_empty() { - Ok(( - A::Program { - commands: self.state.parsed, - warn_shadows_set: self.state.warn_shadows_set, - }, - A::ProgramMetadata { - preview_set: self.state.preview_set, - summary_set: self.state.summary_set, - serialize_unsigned_set: self.state.serialize_unsigned_set, - serialize_signed_set: self.state.serialize_signed_set, - gas_object_id: self.state.gas_object_id, - json_set: self.state.json_set, - gas_budget, - }, - )) - } else { - Err(self.state.errors) - } - } -} - -/// Iterator convenience methods over tokens -impl<'a, I: Iterator> ProgramParser<'a, I> { - /// Advance the iterator and return the next lexeme. If the next lexeme's - /// token is not the expected one, return an error, and don't advance - /// the token stream. - fn expect(&mut self, expected: Token) -> PTBResult>> { - let result @ sp!(sp, lexeme@Lexeme(token, _)) = self.peek(); - Ok(if token == expected { - self.bump(); - result - } else { - error!(sp, "Expected {expected} but found {lexeme}"); - }) - } - - /// Peek at the next token without advancing the iterator. - fn peek(&mut self) -> Spanned> { - *self - .tokens - .peek() - .expect("Lexer returns an infinite stream") - } - - /// Unconditionally advance the next token. It is always safe to do this, - /// because the underlying token stream is "infinite" (the lexer will - /// repeatedly return its terminal token). - fn bump(&mut self) { - self.tokens.next(); - } - - /// Fast forward to the next command token (if any). - fn fast_forward_to_next_command(&mut self) { - loop { - let sp!(_, lexeme) = self.peek(); - if lexeme.is_command_end() { - break; - } - self.bump(); - } - } -} - -/// Methods for parsing commands -impl<'a, I: Iterator> ProgramParser<'a, I> { - /// Parse a transfer-objects command. - /// The expected format is: `--transfer-objects [, ...] ` - fn parse_transfer_objects(&mut self) -> PTBResult> { - let transfer_froms = self.parse_array()?; - let transfer_to = self.parse_argument()?; - let sp = transfer_to.span.widen(transfer_froms.span); - Ok(sp.wrap(ParsedPTBCommand::TransferObjects( - transfer_froms, - transfer_to, - ))) - } - - /// Parse a split-coins command. - /// The expected format is: `--split-coins [, ...]` - fn parse_split_coins(&mut self) -> PTBResult> { - let split_from = self.parse_argument()?; - let splits = self.parse_array()?; - let sp = split_from.span.widen(splits.span); - Ok(sp.wrap(ParsedPTBCommand::SplitCoins(split_from, splits))) - } - - /// Parse a merge-coins command. - /// The expected format is: `--merge-coins [, ...]` - fn parse_merge_coins(&mut self) -> PTBResult> { - let merge_into = self.parse_argument()?; - let coins = self.parse_array()?; - let sp = merge_into.span.widen(coins.span); - Ok(sp.wrap(ParsedPTBCommand::MergeCoins(merge_into, coins))) - } - - /// Parse an assign command. - /// The expected format is: `--assign ()?` - fn parse_assign(&mut self) -> PTBResult> { - use Lexeme as L; - let sp!(sp, L(_, contents)) = self.expect(Token::Ident)?; - if is_keyword(contents) { - error!(sp => help: { - "Variable names cannot be {}.", - all_keywords() - }, - "Expected a variable name but found reserved word '{contents}'."); - } - - let ident = sp.wrap(contents.to_owned()); - - Ok(if self.peek().value.is_command_end() { - ident.span.wrap(ParsedPTBCommand::Assign(ident, None)) - } else { - let value = self.parse_argument()?; - let sp = ident.span.widen(value.span); - sp.wrap(ParsedPTBCommand::Assign(ident, Some(value))) - }) - } - - /// Parse a make-move-vec command - /// The expected format is: `--make-move-vec [, ...]` - fn parse_make_move_vec(&mut self) -> PTBResult> { - use Token as T; - - let sp!(start_sp, _) = self.expect(T::LAngle)?; - let type_ = self.parse_type()?; - self.expect(T::RAngle)?; - - let elems = self.parse_array()?; - - let sp = start_sp.widen(elems.span); - Ok(sp.wrap(ParsedPTBCommand::MakeMoveVec(type_, elems))) - } - - /// Parse a move-call command - /// The expected format is: `--move-call
    :::: - /// (<, ...>)? ...` - fn parse_move_call(&mut self) -> PTBResult> { - use Lexeme as L; - use Token as T; - - let function = self.parse_module_access()?; - let mut end_sp = function.span; - - let ty_args = if let sp!(_, L(T::LAngle, _)) = self.peek() { - let type_args = self.parse_type_args()?; - end_sp = type_args.span; - Some(type_args) - } else { - None - }; - - let mut args = vec![]; - while !self.peek().value.is_command_end() { - let arg = self.parse_argument()?; - end_sp = arg.span; - args.push(arg); - } - - let sp = function.span.widen(end_sp); - Ok(sp.wrap(ParsedPTBCommand::MoveCall(function, ty_args, args))) - } - - /// Parse a gas-budget command. - /// The expected format is: `--gas-budget ` - fn parse_gas_budget(&mut self) -> PTBResult> { - Ok(match self.parse_argument()? { - sp!(sp, Argument::U64(u)) => sp.wrap(u), - sp!(sp, _) => error!(sp, "Expected a u64 value"), - }) - } - - /// Parse a gas specifier. - /// The expected format is: `--gas-coin
    ` - fn parse_gas_specifier(&mut self) -> PTBResult> { - Ok(self - .parse_address_literal()? - .map(|a| ObjectID::from(a.into_inner()))) - } -} - -/// Methods for parsing arguments and types in commands -impl<'a, I: Iterator> ProgramParser<'a, I> { - /// Parse a single PTB argument from the beginning of the token stream. - fn parse_argument(&mut self) -> PTBResult> { - use Argument as V; - use Lexeme as L; - use Token as T; - - let sp!(sp, lexeme) = self.peek(); - Ok(match lexeme { - L(T::Ident, "true") => { - self.bump(); - sp.wrap(V::Bool(true)) - } - - L(T::Ident, "false") => { - self.bump(); - sp.wrap(V::Bool(false)) - } - - L(T::Ident, A::GAS) => { - self.bump(); - sp.wrap(V::Gas) - } - - L(T::Number | T::HexNumber, number) => { - let number = if lexeme.0 == T::HexNumber { - format!("0x{number}") - } else { - number.to_owned() - }; - - self.bump(); - self.parse_number(sp.wrap(&number))? - } - - L(T::At, _) => self.parse_address_literal()?.map(V::Address), - - L(T::Ident, A::NONE) => { - self.bump(); - sp.wrap(V::Option(sp.wrap(None))) - } - - L(T::Ident, A::SOME) => { - self.bump(); - self.expect(T::LParen)?; - let sp!(arg_sp, arg) = self.parse_argument()?; - let sp!(end_sp, _) = self.expect(T::RParen)?; - - let sp = sp.widen(end_sp); - sp.wrap(V::Option(arg_sp.wrap(Some(Box::new(arg))))) - } - - L(T::Ident, A::VECTOR) => { - self.bump(); - self.parse_array()?.map(V::Vector).widen_span(sp) - } - - L(T::Ident, _) => self.parse_variable()?, - - L(T::String, contents) => { - self.bump(); - sp.wrap(V::String(contents.to_owned())) - } - - unexpected => error!( - sp => help: { "Expected an argument here" }, - "Unexpected {unexpected}", - ), - }) - } - - /// Parse a type. - fn parse_type(&mut self) -> PTBResult> { - use Lexeme as L; - use Token as T; - - let sp!(sp, lexeme) = self.peek(); - - macro_rules! type_ { - ($ty: expr) => {{ - self.bump(); - sp.wrap($ty) - }}; - } - - Ok(match lexeme { - L(T::Ident, A::U8) => type_!(ParsedType::U8), - L(T::Ident, A::U16) => type_!(ParsedType::U16), - L(T::Ident, A::U32) => type_!(ParsedType::U32), - L(T::Ident, A::U64) => type_!(ParsedType::U64), - L(T::Ident, A::U128) => type_!(ParsedType::U128), - L(T::Ident, A::U256) => type_!(ParsedType::U256), - L(T::Ident, A::BOOL) => type_!(ParsedType::Bool), - L(T::Ident, A::ADDRESS) => type_!(ParsedType::Address), - - L(T::Ident, A::VECTOR) => { - self.bump(); - self.expect(T::LAngle)?; - let sp!(_, ty) = self.parse_type()?; - let sp!(end_sp, _) = self.expect(T::RAngle)?; - - let sp = sp.widen(end_sp); - sp.wrap(ParsedType::Vector(Box::new(ty))) - } - - L(T::Ident | T::Number | T::HexNumber, _) => 'fq: { - let sp!(_, module_access) = self.parse_module_access()?; - let sp!(_, address) = module_access.address; - let sp!(_, module_name) = module_access.module_name; - let sp!(fun_sp, function_name) = module_access.function_name; - - let module = ParsedModuleId { - address, - name: module_name.to_string(), - }; - - let name = function_name.to_string(); - let fq_name = ParsedFqName { module, name }; - - let sp!(_, L(T::LAngle, _)) = self.peek() else { - let sp = sp.widen(fun_sp); - break 'fq sp.wrap(ParsedType::Struct(ParsedStructType { - fq_name, - type_args: vec![], - })); - }; - - let sp!(tys_sp, type_args) = self.parse_type_args()?; - - let sp = sp.widen(tys_sp); - sp.wrap(ParsedType::Struct(ParsedStructType { fq_name, type_args })) - } - - unexpected => error!( - sp => help: { "Expected a type here" }, - "Unexpected {unexpected}", - ), - }) - } - - /// Parse a fully-qualified name, corresponding to accessing a function or - /// type from a module. - fn parse_module_access(&mut self) -> PTBResult> { - use Lexeme as L; - use Token as T; - - let address = self.parse_address()?; - - self.expect(T::ColonColon)?; - let sp!(mod_sp, L(_, module_name)) = self.expect(T::Ident)?; - let module_name = Identifier::new(module_name) - .map_err(|_| err!(mod_sp, "Invalid module name {module_name:?}"))?; - - self.expect(T::ColonColon)?; - let sp!(fun_sp, L(_, function_name)) = self.expect(T::Ident)?; - let function_name = Identifier::new(function_name) - .map_err(|_| err!(fun_sp, "Invalid function name {function_name:?}"))?; - - let sp = address.span.widen(fun_sp); - Ok(sp.wrap(ModuleAccess { - address, - module_name: mod_sp.wrap(module_name), - function_name: fun_sp.wrap(function_name), - })) - } - - /// Parse a list of type arguments, surrounded by angle brackets, and - /// separated by commas. - fn parse_type_args(&mut self) -> PTBResult>> { - use Lexeme as L; - use Token as T; - - let sp!(start_sp, _) = self.expect(T::LAngle)?; - - let mut type_args = vec![]; - loop { - type_args.push(self.parse_type()?.value); - - let sp!(sp, lexeme) = self.peek(); - match lexeme { - L(T::Comma, _) => self.bump(), - L(T::RAngle, _) => break, - unexpected => error!( - sp => help: { "Expected {} or {}", T::Comma, T::RAngle }, - "Unexpected {unexpected}", - ), - } - } - - let sp!(end_sp, _) = self.expect(T::RAngle)?; - Ok(start_sp.widen(end_sp).wrap(type_args)) - } - - /// Parse a variable access (a non-empty chain of identifiers, separated by - /// '.') - fn parse_variable(&mut self) -> PTBResult> { - use Lexeme as L; - use Token as T; - - let sp!(start_sp, L(_, ident)) = self.expect(T::Ident)?; - let ident = start_sp.wrap(ident.to_owned()); - - let sp!(_, L(T::Dot, _)) = self.peek() else { - return Ok(start_sp.wrap(Argument::Identifier(ident.value))); - }; - - self.bump(); - let mut fields = vec![]; - loop { - // A field can be any non-terminal token (identifier, number, etc). - let sp!(sp, lexeme@L(_, field)) = self.peek(); - if lexeme.is_terminal() { - error!(sp, "Expected a field name after '.'"); - } - - self.bump(); - fields.push(sp.wrap(field.to_owned())); - - if let sp!(_, L(T::Dot, _)) = self.peek() { - self.bump(); - } else { - break; - } - } - - let end_sp = fields.last().map(|f| f.span).unwrap_or(start_sp); - let sp = start_sp.widen(end_sp); - Ok(sp.wrap(Argument::VariableAccess(ident, fields))) - } - - /// Parse a decimal or hexadecimal number, optionally followed by a type - /// suffix. - fn parse_number(&mut self, contents: Spanned<&str>) -> PTBResult> { - use Argument as V; - use Lexeme as L; - use Token as T; - - let sp!(sp, suffix) = self.peek(); - - macro_rules! parse_num { - ($fn: ident, $ty: expr) => {{ - self.bump(); - let sp = sp.widen(contents.span); - match $fn(contents.value) { - Ok((value, _)) => sp.wrap($ty(value)), - Err(e) => error!(sp, "{e}"), - } - }}; - } - - Ok(match suffix { - L(T::Ident, A::U8) => parse_num!(parse_u8, V::U8), - L(T::Ident, A::U16) => parse_num!(parse_u16, V::U16), - L(T::Ident, A::U32) => parse_num!(parse_u32, V::U32), - L(T::Ident, A::U64) => parse_num!(parse_u64, V::U64), - L(T::Ident, A::U128) => parse_num!(parse_u128, V::U128), - L(T::Ident, A::U256) => parse_num!(parse_u256, V::U256), - - // If there's no suffix, assume u64, and don't consume the peeked character. - _ => match parse_u64(contents.value) { - Ok((value, _)) => contents.span.wrap(V::U64(value)), - Err(e) => error!(contents.span, "{e}"), - }, - }) - } - - /// Parse a numerical or named address. - fn parse_address(&mut self) -> PTBResult> { - use Lexeme as L; - use Token as T; - - let sp!(sp, lexeme) = self.peek(); - let addr = match lexeme { - L(T::Ident, name) => { - self.bump(); - ParsedAddress::Named(name.to_owned()) - } - - L(T::Number, number) => { - self.bump(); - NumericalAddress::parse_str(number) - .map_err(|e| err!(sp, "Failed to parse address {number:?}: {e}")) - .map(ParsedAddress::Numerical)? - } - - L(T::HexNumber, number) => { - self.bump(); - let number = format!("0x{number}"); - NumericalAddress::parse_str(&number) - .map_err(|e| err!(sp, "Failed to parse address {number:?}: {e}")) - .map(ParsedAddress::Numerical)? - } - - unexpected => error!( - sp => help: { - "Value addresses can either be a variable in-scope, or a numerical address, \ - e.g., 0xc0ffee" - }, - "Unexpected {unexpected}", - ), - }; - - Ok(sp.wrap(addr)) - } - - /// Parse a numeric addres literal (must be prefixed by an `@` symbol). - fn parse_address_literal(&mut self) -> PTBResult> { - let sp!(sp, _) = self.expect(Token::At).map_err(|e| { - err!(e.span => help: { - "Addresses or object IDs require the character '@' in front" - }, "Expected an address") - })?; - - Ok(match self.parse_address()?.widen_span(sp) { - sp!(sp, ParsedAddress::Numerical(n)) => sp.wrap(n), - sp!(sp, ParsedAddress::Named(n)) => error!( - sp, - "Expected a numerical address but got a named address '{n}'", - ), - }) - } - - // Parse an array of arguments. Each element of the array is separated by a - // comma. - fn parse_array(&mut self) -> PTBResult>>> { - use Lexeme as L; - use Token as T; - let sp!(start_sp, _) = self.expect(T::LBracket)?; - - let mut values = vec![]; - loop { - let sp!(sp, lexeme) = self.peek(); - if lexeme.is_terminal() { - error!( - sp => help: { "Expected an array here" }, - "Unexpected {lexeme}" - ); - } else if let L(T::RBracket, _) = lexeme { - break; - } - - values.push(self.parse_argument()?); - - let sp!(sp, lexeme) = self.peek(); - match lexeme { - L(T::RBracket, _) => break, - L(T::Comma, _) => self.bump(), - unexpected => error!( - sp => help: { "Expected {} or {}", T::RBracket, T::Comma }, - "Unexpected {unexpected}", - ), - } - } - - let sp!(end_sp, _) = self.expect(T::RBracket)?; - Ok(start_sp.widen(end_sp).wrap(values)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parse() { - let input = "--transfer-objects [b, c] a"; - let mut x = shlex::split(input).unwrap(); - x.push("--gas-budget 1".to_owned()); - let parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); - let result = parser.parse(); - assert!(result.is_ok()); - } - - #[test] - fn test_parse_unexpected_top_level() { - let input = "\"0x\" "; - let x = shlex::split(input).unwrap(); - let parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); - let result = parser.parse(); - insta::assert_debug_snapshot!(result.unwrap_err()); - } - - #[test] - fn test_parse_publish() { - let inputs = vec!["--publish \"foo/bar\"", "--publish foo/bar"]; - let mut parsed = Vec::new(); - for input in inputs { - let mut x = shlex::split(input).unwrap(); - x.push("--gas-budget 1".to_owned()); - let parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); - let result = parser.parse().unwrap(); - parsed.push(result); - } - insta::assert_debug_snapshot!(parsed); - } - - #[test] - fn test_parse_args() { - let inputs = vec![ - // Bools - "true", - "false", - // Integers - "1", - "1_000", - "100_000_000", - "100_000u64", - "1u8", - "1_u128", - "0x1", - "0x1_000", - "0x100_000_000", - "0x100_000u64", - "0x1u8", - "0x1_u128", - // Addresses - "@0x1", - "@0x1_000", - "@0x100_000_000", - "@0x100_000u64", - "@0x1u8", - "@0x1_u128", - // Option - "none", - "some(1)", - "some(0x1)", - "some(some(some(some(1u128))))", - // vector - "vector[]", - "vector[1, 2, 3]", - "vector[1, 2, 3,]", - // Dotted access - "foo.bar", - "foo.bar.baz", - "foo.bar.baz.qux", - "foo.0", - "foo.0.1", - ]; - let mut parsed = Vec::new(); - for input in inputs { - let mut x = shlex::split(input).unwrap(); - x.push("--gas-budget 1".to_owned()); - let mut parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); - let result = parser - .parse_argument() - .unwrap_or_else(|e| panic!("Failed on {input:?}: {e:?}")); - parsed.push(result); - } - insta::assert_debug_snapshot!(parsed); - } - - #[test] - fn test_parse_args_invalid() { - let inputs = vec![ - // Integers - "0xfffu8", // addresses - "@n", // options - "some", - "some(", - "some(1", - // vectors - "vector", - "vector[", - "vector[1,", - "vector[1 2]", - "vector[,]", - // Dotted access - "foo.", - ".", - ]; - let mut parsed = Vec::new(); - for input in inputs { - let x = shlex::split(input).unwrap(); - let mut parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); - let result = parser.parse_argument().unwrap_err(); - parsed.push(result); - } - insta::assert_debug_snapshot!(parsed); - } - - #[test] - fn test_parse_types() { - let inputs = vec![ - // Primitives - "u8", - "u16", - "u32", - "u64", - "u128", - "u256", - "bool", - "address", - "vector", - // Structs - "sui::object::ID", - "0x2::object::UID", - "3::staking_pool::StakedSui", - // Generic types - "0x2::coin::Coin<2::sui::SUI>", - "sui::table::Table>>", - ]; - let mut parsed = Vec::new(); - for input in inputs { - let mut x = shlex::split(input).unwrap(); - x.push("--gas-budget 1".to_owned()); - let mut parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); - let result = parser - .parse_type() - .unwrap_or_else(|e| panic!("Failed on {input:?}: {e:?}")); - parsed.push(result); - } - insta::assert_debug_snapshot!(parsed); - } - - #[test] - fn test_parse_types_invalid() { - let inputs = vec![ - "signer", - "not-an-identifier", - "vector", - "foo::", - "foo::bar", - "foo::bar::Baz<", - "foo::bar::Baz []", - "--make-move-vec [1u8, 2u8]", - // Move Call - "--move-call 0x3::sui_system::request_add_stake system coins.0 validator", - "--move-call std::option::is_none p", - "--move-call std::option::is_some q", - // Assign - "--assign a", - "--assign a b.1", - "--assign a 1u8", - "--assign a @0x1", - "--assign a vector[1, 2, 3]", - "--assign a none", - "--assign a some(1)", - // Gas-coin - "--gas-coin @0x1", - "--summary", - "--json", - "--preview", - "--warn-shadows", - ]; - let mut parsed = Vec::new(); - for input in inputs { - let mut x = shlex::split(input).unwrap(); - x.push("--gas-budget 1".to_owned()); - let parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); - let result = parser - .parse() - .unwrap_or_else(|e| panic!("Failed on {input:?}: {e:?}")); - parsed.push(result); - } - insta::assert_debug_snapshot!(parsed); - } - - #[test] - fn test_parse_commands_invalid() { - let inputs = vec![ - // Publish - "--publish", - // Upgrade - "--upgrade", - "--upgrade 1", - // Transfer objects - "--transfer-objects a", - "--transfer-objects [b]", - "--transfer-objects", - "--transfer-objects [a] [b]", - // Split coins - "--split-coins a", - "--split-coins [b]", - "--split-coins", - "--split-coins a b c", - "--split-coins a [b] c", - // Merge coins - "--merge-coins a", - "--merge-coins [b]", - "--merge-coins", - "--merge-coins a b c", - "--merge-coins a [b] c", - // Make Move Vec - "--make-move-vec", - "--make-move-vec [1, 2, 3]", - "--make-move-vec ", - // Move Call - "--move-call", - "--move-call 0x1::option::is_none []", - // Assign - "--assign", - "--assign a b c", - "--assign none b", - "--assign some none", - "--assign a.3 1u8", - // Gas budget - "--gas-budget 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "--gas-budget [1]", - "--gas-budget @0x1", - "--gas-budget woah", - // Gas-coin - "--gas-coin nope", - "--gas-coin", - "--gas-coin @0x1 @0x2", - "--gas-coin 1", - ]; - let mut parsed = Vec::new(); - for input in inputs { - let x = shlex::split(input).unwrap(); - let parser = ProgramParser::new(x.iter().map(|x| x.as_str())).unwrap(); - let result = parser.parse().unwrap_err(); - parsed.push(result); - } - insta::assert_debug_snapshot!(parsed); - } -} diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__dotted_idents.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__dotted_idents.snap deleted file mode 100644 index e31f25436a9..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__dotted_idents.snap +++ /dev/null @@ -1,266 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: lex(idents) ---- -[ - Spanned { - span: Span { - start: 0, - end: 1, - }, - value: Lexeme( - Ident, - "a", - ), - }, - Spanned { - span: Span { - start: 2, - end: 3, - }, - value: Lexeme( - Ident, - "a", - ), - }, - Spanned { - span: Span { - start: 3, - end: 4, - }, - value: Lexeme( - Dot, - ".", - ), - }, - Spanned { - span: Span { - start: 4, - end: 5, - }, - value: Lexeme( - Ident, - "b", - ), - }, - Spanned { - span: Span { - start: 6, - end: 7, - }, - value: Lexeme( - Ident, - "a", - ), - }, - Spanned { - span: Span { - start: 7, - end: 8, - }, - value: Lexeme( - Dot, - ".", - ), - }, - Spanned { - span: Span { - start: 8, - end: 9, - }, - value: Lexeme( - Ident, - "b", - ), - }, - Spanned { - span: Span { - start: 9, - end: 10, - }, - value: Lexeme( - Dot, - ".", - ), - }, - Spanned { - span: Span { - start: 10, - end: 11, - }, - value: Lexeme( - Ident, - "c", - ), - }, - Spanned { - span: Span { - start: 12, - end: 13, - }, - value: Lexeme( - Ident, - "a", - ), - }, - Spanned { - span: Span { - start: 13, - end: 14, - }, - value: Lexeme( - Dot, - ".", - ), - }, - Spanned { - span: Span { - start: 14, - end: 15, - }, - value: Lexeme( - Ident, - "b", - ), - }, - Spanned { - span: Span { - start: 15, - end: 16, - }, - value: Lexeme( - Dot, - ".", - ), - }, - Spanned { - span: Span { - start: 16, - end: 17, - }, - value: Lexeme( - Ident, - "c", - ), - }, - Spanned { - span: Span { - start: 17, - end: 18, - }, - value: Lexeme( - Dot, - ".", - ), - }, - Spanned { - span: Span { - start: 18, - end: 19, - }, - value: Lexeme( - Ident, - "d", - ), - }, - Spanned { - span: Span { - start: 20, - end: 21, - }, - value: Lexeme( - Ident, - "a", - ), - }, - Spanned { - span: Span { - start: 21, - end: 22, - }, - value: Lexeme( - Dot, - ".", - ), - }, - Spanned { - span: Span { - start: 22, - end: 23, - }, - value: Lexeme( - Ident, - "b", - ), - }, - Spanned { - span: Span { - start: 23, - end: 24, - }, - value: Lexeme( - Dot, - ".", - ), - }, - Spanned { - span: Span { - start: 24, - end: 25, - }, - value: Lexeme( - Ident, - "c", - ), - }, - Spanned { - span: Span { - start: 25, - end: 26, - }, - value: Lexeme( - Dot, - ".", - ), - }, - Spanned { - span: Span { - start: 26, - end: 27, - }, - value: Lexeme( - Ident, - "d", - ), - }, - Spanned { - span: Span { - start: 27, - end: 28, - }, - value: Lexeme( - Dot, - ".", - ), - }, - Spanned { - span: Span { - start: 28, - end: 29, - }, - value: Lexeme( - Ident, - "e", - ), - }, - Spanned { - span: Span { - start: 29, - end: 29, - }, - value: Lexeme( - Eof, - "", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__functions.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__functions.snap deleted file mode 100644 index 397eccfe61c..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__functions.snap +++ /dev/null @@ -1,376 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: lex(funs) ---- -[ - Spanned { - span: Span { - start: 0, - end: 3, - }, - value: Lexeme( - HexNumber, - "2", - ), - }, - Spanned { - span: Span { - start: 3, - end: 5, - }, - value: Lexeme( - ColonColon, - "::", - ), - }, - Spanned { - span: Span { - start: 5, - end: 13, - }, - value: Lexeme( - Ident, - "transfer", - ), - }, - Spanned { - span: Span { - start: 13, - end: 15, - }, - value: Lexeme( - ColonColon, - "::", - ), - }, - Spanned { - span: Span { - start: 15, - end: 30, - }, - value: Lexeme( - Ident, - "public_transfer", - ), - }, - Spanned { - span: Span { - start: 30, - end: 31, - }, - value: Lexeme( - LAngle, - "<", - ), - }, - Spanned { - span: Span { - start: 31, - end: 35, - }, - value: Lexeme( - HexNumber, - "42", - ), - }, - Spanned { - span: Span { - start: 35, - end: 37, - }, - value: Lexeme( - ColonColon, - "::", - ), - }, - Spanned { - span: Span { - start: 37, - end: 40, - }, - value: Lexeme( - Ident, - "foo", - ), - }, - Spanned { - span: Span { - start: 40, - end: 42, - }, - value: Lexeme( - ColonColon, - "::", - ), - }, - Spanned { - span: Span { - start: 42, - end: 45, - }, - value: Lexeme( - Ident, - "Bar", - ), - }, - Spanned { - span: Span { - start: 45, - end: 46, - }, - value: Lexeme( - RAngle, - ">", - ), - }, - Spanned { - span: Span { - start: 47, - end: 50, - }, - value: Lexeme( - Ident, - "std", - ), - }, - Spanned { - span: Span { - start: 50, - end: 52, - }, - value: Lexeme( - ColonColon, - "::", - ), - }, - Spanned { - span: Span { - start: 52, - end: 58, - }, - value: Lexeme( - Ident, - "option", - ), - }, - Spanned { - span: Span { - start: 58, - end: 60, - }, - value: Lexeme( - ColonColon, - "::", - ), - }, - Spanned { - span: Span { - start: 60, - end: 67, - }, - value: Lexeme( - Ident, - "is_none", - ), - }, - Spanned { - span: Span { - start: 67, - end: 68, - }, - value: Lexeme( - LAngle, - "<", - ), - }, - Spanned { - span: Span { - start: 68, - end: 71, - }, - value: Lexeme( - Ident, - "u64", - ), - }, - Spanned { - span: Span { - start: 71, - end: 72, - }, - value: Lexeme( - RAngle, - ">", - ), - }, - Spanned { - span: Span { - start: 73, - end: 76, - }, - value: Lexeme( - HexNumber, - "1", - ), - }, - Spanned { - span: Span { - start: 76, - end: 78, - }, - value: Lexeme( - ColonColon, - "::", - ), - }, - Spanned { - span: Span { - start: 78, - end: 84, - }, - value: Lexeme( - Ident, - "option", - ), - }, - Spanned { - span: Span { - start: 84, - end: 86, - }, - value: Lexeme( - ColonColon, - "::", - ), - }, - Spanned { - span: Span { - start: 86, - end: 93, - }, - value: Lexeme( - Ident, - "is_some", - ), - }, - Spanned { - span: Span { - start: 94, - end: 95, - }, - value: Lexeme( - LAngle, - "<", - ), - }, - Spanned { - span: Span { - start: 95, - end: 98, - }, - value: Lexeme( - Ident, - "u64", - ), - }, - Spanned { - span: Span { - start: 98, - end: 99, - }, - value: Lexeme( - RAngle, - ">", - ), - }, - Spanned { - span: Span { - start: 100, - end: 103, - }, - value: Lexeme( - HexNumber, - "1", - ), - }, - Spanned { - span: Span { - start: 103, - end: 105, - }, - value: Lexeme( - ColonColon, - "::", - ), - }, - Spanned { - span: Span { - start: 105, - end: 111, - }, - value: Lexeme( - Ident, - "option", - ), - }, - Spanned { - span: Span { - start: 111, - end: 113, - }, - value: Lexeme( - ColonColon, - "::", - ), - }, - Spanned { - span: Span { - start: 113, - end: 120, - }, - value: Lexeme( - Ident, - "is_none", - ), - }, - Spanned { - span: Span { - start: 121, - end: 122, - }, - value: Lexeme( - LAngle, - "<", - ), - }, - Spanned { - span: Span { - start: 122, - end: 125, - }, - value: Lexeme( - Ident, - "u64", - ), - }, - Spanned { - span: Span { - start: 125, - end: 126, - }, - value: Lexeme( - RAngle, - ">", - ), - }, - Spanned { - span: Span { - start: 126, - end: 126, - }, - value: Lexeme( - Eof, - "", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__gas.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__gas.snap deleted file mode 100644 index 099db545f6e..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__gas.snap +++ /dev/null @@ -1,26 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: lex(gas) ---- -[ - Spanned { - span: Span { - start: 0, - end: 3, - }, - value: Lexeme( - Ident, - "gas", - ), - }, - Spanned { - span: Span { - start: 3, - end: 3, - }, - value: Lexeme( - Eof, - "", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_address.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_address.snap deleted file mode 100644 index 776b12ac0e1..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_address.snap +++ /dev/null @@ -1,166 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: lex(addrs) ---- -[ - Spanned { - span: Span { - start: 0, - end: 1, - }, - value: Lexeme( - At, - "@", - ), - }, - Spanned { - span: Span { - start: 1, - end: 4, - }, - value: Lexeme( - HexNumber, - "1", - ), - }, - Spanned { - span: Span { - start: 5, - end: 6, - }, - value: Lexeme( - At, - "@", - ), - }, - Spanned { - span: Span { - start: 6, - end: 13, - }, - value: Lexeme( - HexNumber, - "1_000", - ), - }, - Spanned { - span: Span { - start: 14, - end: 15, - }, - value: Lexeme( - At, - "@", - ), - }, - Spanned { - span: Span { - start: 15, - end: 28, - }, - value: Lexeme( - HexNumber, - "100_000_000", - ), - }, - Spanned { - span: Span { - start: 29, - end: 30, - }, - value: Lexeme( - At, - "@", - ), - }, - Spanned { - span: Span { - start: 30, - end: 39, - }, - value: Lexeme( - HexNumber, - "100_000", - ), - }, - Spanned { - span: Span { - start: 39, - end: 42, - }, - value: Lexeme( - Ident, - "u64", - ), - }, - Spanned { - span: Span { - start: 43, - end: 44, - }, - value: Lexeme( - At, - "@", - ), - }, - Spanned { - span: Span { - start: 44, - end: 47, - }, - value: Lexeme( - HexNumber, - "1", - ), - }, - Spanned { - span: Span { - start: 47, - end: 49, - }, - value: Lexeme( - Ident, - "u8", - ), - }, - Spanned { - span: Span { - start: 50, - end: 51, - }, - value: Lexeme( - At, - "@", - ), - }, - Spanned { - span: Span { - start: 51, - end: 55, - }, - value: Lexeme( - HexNumber, - "1_", - ), - }, - Spanned { - span: Span { - start: 55, - end: 59, - }, - value: Lexeme( - Ident, - "u128", - ), - }, - Spanned { - span: Span { - start: 59, - end: 59, - }, - value: Lexeme( - Eof, - "", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_args.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_args.snap deleted file mode 100644 index 363b348c283..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_args.snap +++ /dev/null @@ -1,796 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: lex(args) ---- -[ - Spanned { - span: Span { - start: 0, - end: 1, - }, - value: Lexeme( - At, - "@", - ), - }, - Spanned { - span: Span { - start: 1, - end: 4, - }, - value: Lexeme( - HexNumber, - "1", - ), - }, - Spanned { - span: Span { - start: 5, - end: 6, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 7, - end: 8, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 8, - end: 10, - }, - value: Lexeme( - Ident, - "u8", - ), - }, - Spanned { - span: Span { - start: 11, - end: 13, - }, - value: Lexeme( - Number, - "1_", - ), - }, - Spanned { - span: Span { - start: 13, - end: 17, - }, - value: Lexeme( - Ident, - "u128", - ), - }, - Spanned { - span: Span { - start: 18, - end: 23, - }, - value: Lexeme( - Number, - "1_000", - ), - }, - Spanned { - span: Span { - start: 24, - end: 35, - }, - value: Lexeme( - Number, - "100_000_000", - ), - }, - Spanned { - span: Span { - start: 36, - end: 43, - }, - value: Lexeme( - Number, - "100_000", - ), - }, - Spanned { - span: Span { - start: 43, - end: 46, - }, - value: Lexeme( - Ident, - "u64", - ), - }, - Spanned { - span: Span { - start: 47, - end: 48, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 49, - end: 50, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 50, - end: 51, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 51, - end: 52, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 53, - end: 54, - }, - value: Lexeme( - Number, - "2", - ), - }, - Spanned { - span: Span { - start: 54, - end: 55, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 56, - end: 57, - }, - value: Lexeme( - Number, - "3", - ), - }, - Spanned { - span: Span { - start: 57, - end: 58, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 59, - end: 60, - }, - value: Lexeme( - Number, - "4", - ), - }, - Spanned { - span: Span { - start: 60, - end: 61, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 62, - end: 63, - }, - value: Lexeme( - Number, - "5", - ), - }, - Spanned { - span: Span { - start: 63, - end: 64, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 65, - end: 66, - }, - value: Lexeme( - Number, - "6", - ), - }, - Spanned { - span: Span { - start: 66, - end: 67, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 68, - end: 69, - }, - value: Lexeme( - Number, - "7", - ), - }, - Spanned { - span: Span { - start: 69, - end: 70, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 71, - end: 72, - }, - value: Lexeme( - Number, - "8", - ), - }, - Spanned { - span: Span { - start: 72, - end: 73, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 74, - end: 75, - }, - value: Lexeme( - Number, - "9", - ), - }, - Spanned { - span: Span { - start: 75, - end: 76, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 77, - end: 79, - }, - value: Lexeme( - Number, - "10", - ), - }, - Spanned { - span: Span { - start: 79, - end: 80, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 81, - end: 87, - }, - value: Lexeme( - Ident, - "vector", - ), - }, - Spanned { - span: Span { - start: 87, - end: 88, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 88, - end: 89, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 90, - end: 96, - }, - value: Lexeme( - Ident, - "vector", - ), - }, - Spanned { - span: Span { - start: 96, - end: 97, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 97, - end: 98, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 98, - end: 99, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 99, - end: 100, - }, - value: Lexeme( - Number, - "2", - ), - }, - Spanned { - span: Span { - start: 100, - end: 101, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 101, - end: 102, - }, - value: Lexeme( - Number, - "3", - ), - }, - Spanned { - span: Span { - start: 102, - end: 103, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 104, - end: 110, - }, - value: Lexeme( - Ident, - "vector", - ), - }, - Spanned { - span: Span { - start: 110, - end: 111, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 111, - end: 112, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 112, - end: 113, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 114, - end: 118, - }, - value: Lexeme( - Ident, - "some", - ), - }, - Spanned { - span: Span { - start: 118, - end: 119, - }, - value: Lexeme( - LParen, - "(", - ), - }, - Spanned { - span: Span { - start: 119, - end: 120, - }, - value: Lexeme( - At, - "@", - ), - }, - Spanned { - span: Span { - start: 120, - end: 123, - }, - value: Lexeme( - HexNumber, - "1", - ), - }, - Spanned { - span: Span { - start: 123, - end: 124, - }, - value: Lexeme( - RParen, - ")", - ), - }, - Spanned { - span: Span { - start: 125, - end: 129, - }, - value: Lexeme( - Ident, - "none", - ), - }, - Spanned { - span: Span { - start: 130, - end: 134, - }, - value: Lexeme( - Ident, - "some", - ), - }, - Spanned { - span: Span { - start: 134, - end: 135, - }, - value: Lexeme( - LParen, - "(", - ), - }, - Spanned { - span: Span { - start: 135, - end: 141, - }, - value: Lexeme( - Ident, - "vector", - ), - }, - Spanned { - span: Span { - start: 141, - end: 142, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 142, - end: 143, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 143, - end: 144, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 144, - end: 145, - }, - value: Lexeme( - Number, - "2", - ), - }, - Spanned { - span: Span { - start: 145, - end: 146, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 146, - end: 147, - }, - value: Lexeme( - Number, - "3", - ), - }, - Spanned { - span: Span { - start: 147, - end: 148, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 148, - end: 149, - }, - value: Lexeme( - RParen, - ")", - ), - }, - Spanned { - span: Span { - start: 150, - end: 158, - }, - value: Lexeme( - Command, - "assign", - ), - }, - Spanned { - span: Span { - start: 159, - end: 177, - }, - value: Lexeme( - Command, - "transfer-objects", - ), - }, - Spanned { - span: Span { - start: 178, - end: 191, - }, - value: Lexeme( - Command, - "split-coins", - ), - }, - Spanned { - span: Span { - start: 192, - end: 205, - }, - value: Lexeme( - Command, - "merge-coins", - ), - }, - Spanned { - span: Span { - start: 206, - end: 221, - }, - value: Lexeme( - Command, - "make-move-vec", - ), - }, - Spanned { - span: Span { - start: 222, - end: 233, - }, - value: Lexeme( - Command, - "move-call", - ), - }, - Spanned { - span: Span { - start: 234, - end: 243, - }, - value: Lexeme( - Command, - "preview", - ), - }, - Spanned { - span: Span { - start: 244, - end: 258, - }, - value: Lexeme( - Command, - "warn-shadows", - ), - }, - Spanned { - span: Span { - start: 259, - end: 276, - }, - value: Lexeme( - Command, - "pick-gas-budget", - ), - }, - Spanned { - span: Span { - start: 277, - end: 289, - }, - value: Lexeme( - Command, - "gas-budget", - ), - }, - Spanned { - span: Span { - start: 290, - end: 299, - }, - value: Lexeme( - Command, - "summary", - ), - }, - Spanned { - span: Span { - start: 300, - end: 319, - }, - value: Lexeme( - Publish, - "package-a", - ), - }, - Spanned { - span: Span { - start: 320, - end: 339, - }, - value: Lexeme( - Upgrade, - "package-b", - ), - }, - Spanned { - span: Span { - start: 339, - end: 339, - }, - value: Lexeme( - Eof, - "", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_array.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_array.snap deleted file mode 100644 index 716f3dae732..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_array.snap +++ /dev/null @@ -1,246 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: lex(arrays) ---- -[ - Spanned { - span: Span { - start: 0, - end: 1, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 1, - end: 2, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 2, - end: 3, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 3, - end: 4, - }, - value: Lexeme( - Number, - "2", - ), - }, - Spanned { - span: Span { - start: 4, - end: 5, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 5, - end: 6, - }, - value: Lexeme( - Number, - "3", - ), - }, - Spanned { - span: Span { - start: 6, - end: 7, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 8, - end: 9, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 9, - end: 10, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 10, - end: 11, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 12, - end: 13, - }, - value: Lexeme( - Number, - "2", - ), - }, - Spanned { - span: Span { - start: 13, - end: 14, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 15, - end: 16, - }, - value: Lexeme( - Number, - "3", - ), - }, - Spanned { - span: Span { - start: 16, - end: 17, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 18, - end: 19, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 19, - end: 20, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 21, - end: 22, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 22, - end: 23, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 23, - end: 24, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 25, - end: 26, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 26, - end: 27, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 27, - end: 28, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 28, - end: 29, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 29, - end: 29, - }, - value: Lexeme( - Eof, - "", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_commands.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_commands.snap deleted file mode 100644 index 34157e16e77..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_commands.snap +++ /dev/null @@ -1,46 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: lex(cmds) ---- -[ - Spanned { - span: Span { - start: 0, - end: 5, - }, - value: Lexeme( - Command, - "f00", - ), - }, - Spanned { - span: Span { - start: 6, - end: 15, - }, - value: Lexeme( - Command, - "Bar_baz", - ), - }, - Spanned { - span: Span { - start: 16, - end: 25, - }, - value: Lexeme( - Command, - "qux-quy", - ), - }, - Spanned { - span: Span { - start: 25, - end: 25, - }, - value: Lexeme( - Eof, - "", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_flags.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_flags.snap deleted file mode 100644 index 7664175a206..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_flags.snap +++ /dev/null @@ -1,56 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: lex(flags) ---- -[ - Spanned { - span: Span { - start: 0, - end: 2, - }, - value: Lexeme( - Flag, - "h", - ), - }, - Spanned { - span: Span { - start: 3, - end: 5, - }, - value: Lexeme( - Flag, - "a", - ), - }, - Spanned { - span: Span { - start: 6, - end: 8, - }, - value: Lexeme( - Flag, - "Z", - ), - }, - Spanned { - span: Span { - start: 9, - end: 11, - }, - value: Lexeme( - Flag, - "1", - ), - }, - Spanned { - span: Span { - start: 11, - end: 11, - }, - value: Lexeme( - Eof, - "", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_num.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_num.snap deleted file mode 100644 index dd32905842a..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_num.snap +++ /dev/null @@ -1,196 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: lex(nums) ---- -[ - Spanned { - span: Span { - start: 0, - end: 1, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 2, - end: 7, - }, - value: Lexeme( - Number, - "1_000", - ), - }, - Spanned { - span: Span { - start: 8, - end: 19, - }, - value: Lexeme( - Number, - "100_000_000", - ), - }, - Spanned { - span: Span { - start: 20, - end: 27, - }, - value: Lexeme( - Number, - "100_000", - ), - }, - Spanned { - span: Span { - start: 27, - end: 30, - }, - value: Lexeme( - Ident, - "u64", - ), - }, - Spanned { - span: Span { - start: 31, - end: 32, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 32, - end: 34, - }, - value: Lexeme( - Ident, - "u8", - ), - }, - Spanned { - span: Span { - start: 35, - end: 37, - }, - value: Lexeme( - Number, - "1_", - ), - }, - Spanned { - span: Span { - start: 37, - end: 41, - }, - value: Lexeme( - Ident, - "u128", - ), - }, - Spanned { - span: Span { - start: 42, - end: 45, - }, - value: Lexeme( - HexNumber, - "1", - ), - }, - Spanned { - span: Span { - start: 46, - end: 53, - }, - value: Lexeme( - HexNumber, - "1_000", - ), - }, - Spanned { - span: Span { - start: 54, - end: 67, - }, - value: Lexeme( - HexNumber, - "100_000_000", - ), - }, - Spanned { - span: Span { - start: 68, - end: 77, - }, - value: Lexeme( - HexNumber, - "100_000", - ), - }, - Spanned { - span: Span { - start: 77, - end: 80, - }, - value: Lexeme( - Ident, - "u64", - ), - }, - Spanned { - span: Span { - start: 81, - end: 84, - }, - value: Lexeme( - HexNumber, - "1", - ), - }, - Spanned { - span: Span { - start: 84, - end: 86, - }, - value: Lexeme( - Ident, - "u8", - ), - }, - Spanned { - span: Span { - start: 87, - end: 91, - }, - value: Lexeme( - HexNumber, - "1_", - ), - }, - Spanned { - span: Span { - start: 91, - end: 95, - }, - value: Lexeme( - Ident, - "u128", - ), - }, - Spanned { - span: Span { - start: 95, - end: 95, - }, - value: Lexeme( - Eof, - "", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_vector.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_vector.snap deleted file mode 100644 index 5f7b6b07f07..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__tokenize_vector.snap +++ /dev/null @@ -1,296 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: lex(vecs) ---- -[ - Spanned { - span: Span { - start: 0, - end: 6, - }, - value: Lexeme( - Ident, - "vector", - ), - }, - Spanned { - span: Span { - start: 6, - end: 7, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 7, - end: 8, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 8, - end: 9, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 9, - end: 10, - }, - value: Lexeme( - Number, - "2", - ), - }, - Spanned { - span: Span { - start: 10, - end: 11, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 11, - end: 12, - }, - value: Lexeme( - Number, - "3", - ), - }, - Spanned { - span: Span { - start: 12, - end: 13, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 14, - end: 20, - }, - value: Lexeme( - Ident, - "vector", - ), - }, - Spanned { - span: Span { - start: 20, - end: 21, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 21, - end: 22, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 22, - end: 23, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 24, - end: 25, - }, - value: Lexeme( - Number, - "2", - ), - }, - Spanned { - span: Span { - start: 25, - end: 26, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 27, - end: 28, - }, - value: Lexeme( - Number, - "3", - ), - }, - Spanned { - span: Span { - start: 28, - end: 29, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 30, - end: 36, - }, - value: Lexeme( - Ident, - "vector", - ), - }, - Spanned { - span: Span { - start: 36, - end: 37, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 37, - end: 38, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 39, - end: 45, - }, - value: Lexeme( - Ident, - "vector", - ), - }, - Spanned { - span: Span { - start: 45, - end: 46, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 46, - end: 47, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 47, - end: 48, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 49, - end: 55, - }, - value: Lexeme( - Ident, - "vector", - ), - }, - Spanned { - span: Span { - start: 55, - end: 56, - }, - value: Lexeme( - LBracket, - "[", - ), - }, - Spanned { - span: Span { - start: 56, - end: 57, - }, - value: Lexeme( - Number, - "1", - ), - }, - Spanned { - span: Span { - start: 57, - end: 58, - }, - value: Lexeme( - Comma, - ",", - ), - }, - Spanned { - span: Span { - start: 58, - end: 59, - }, - value: Lexeme( - RBracket, - "]", - ), - }, - Spanned { - span: Span { - start: 59, - end: 59, - }, - value: Lexeme( - Eof, - "", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_0x.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_0x.snap deleted file mode 100644 index 5ce79f22d07..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_0x.snap +++ /dev/null @@ -1,16 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: tokens ---- -[ - Spanned { - span: Span { - start: 0, - end: 2, - }, - value: Lexeme( - Unexpected, - "0x", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_colon.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_colon.snap deleted file mode 100644 index e58cbd530ec..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_colon.snap +++ /dev/null @@ -1,26 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: tokens ---- -[ - Spanned { - span: Span { - start: 0, - end: 5, - }, - value: Lexeme( - Ident, - "hello", - ), - }, - Spanned { - span: Span { - start: 5, - end: 6, - }, - value: Lexeme( - Unexpected, - ":", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_dash.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_dash.snap deleted file mode 100644 index 8c3ddf830aa..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_dash.snap +++ /dev/null @@ -1,16 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: tokens ---- -[ - Spanned { - span: Span { - start: 0, - end: 1, - }, - value: Lexeme( - Unexpected, - "-", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_dash_dash.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_dash_dash.snap deleted file mode 100644 index acb3b599ebe..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_dash_dash.snap +++ /dev/null @@ -1,16 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: lex(unexpected) ---- -[ - Spanned { - span: Span { - start: 0, - end: 1, - }, - value: Lexeme( - Unexpected, - "-", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_publish_trailing.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_publish_trailing.snap deleted file mode 100644 index 05a02f1d822..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_publish_trailing.snap +++ /dev/null @@ -1,16 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: tokens ---- -[ - Spanned { - span: Span { - start: 9, - end: 10, - }, - value: Lexeme( - Unexpected, - " ", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_random_chars.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_random_chars.snap deleted file mode 100644 index f883c4c4790..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_random_chars.snap +++ /dev/null @@ -1,26 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: tokens ---- -[ - Spanned { - span: Span { - start: 0, - end: 1, - }, - value: Lexeme( - Number, - "4", - ), - }, - Spanned { - span: Span { - start: 2, - end: 3, - }, - value: Lexeme( - Unexpected, - "*", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_upgrade_eof.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_upgrade_eof.snap deleted file mode 100644 index db2d46bf910..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__lexer__tests__unexpected_upgrade_eof.snap +++ /dev/null @@ -1,16 +0,0 @@ ---- -source: crates/sui/src/client_ptb/lexer.rs -expression: tokens ---- -[ - Spanned { - span: Span { - start: 9, - end: 9, - }, - value: Lexeme( - EarlyEof, - "", - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_args.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_args.snap deleted file mode 100644 index ae7627ae60c..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_args.snap +++ /dev/null @@ -1,519 +0,0 @@ ---- -source: crates/sui/src/client_ptb/parser.rs -expression: parsed ---- -[ - Spanned { - span: Span { - start: 0, - end: 4, - }, - value: Bool( - true, - ), - }, - Spanned { - span: Span { - start: 0, - end: 5, - }, - value: Bool( - false, - ), - }, - Spanned { - span: Span { - start: 0, - end: 1, - }, - value: U64( - 1, - ), - }, - Spanned { - span: Span { - start: 0, - end: 5, - }, - value: U64( - 1000, - ), - }, - Spanned { - span: Span { - start: 0, - end: 11, - }, - value: U64( - 100000000, - ), - }, - Spanned { - span: Span { - start: 0, - end: 10, - }, - value: U64( - 100000, - ), - }, - Spanned { - span: Span { - start: 0, - end: 3, - }, - value: U8( - 1, - ), - }, - Spanned { - span: Span { - start: 0, - end: 6, - }, - value: U128( - 1, - ), - }, - Spanned { - span: Span { - start: 0, - end: 3, - }, - value: U64( - 1, - ), - }, - Spanned { - span: Span { - start: 0, - end: 7, - }, - value: U64( - 4096, - ), - }, - Spanned { - span: Span { - start: 0, - end: 13, - }, - value: U64( - 4294967296, - ), - }, - Spanned { - span: Span { - start: 0, - end: 12, - }, - value: U64( - 1048576, - ), - }, - Spanned { - span: Span { - start: 0, - end: 5, - }, - value: U8( - 1, - ), - }, - Spanned { - span: Span { - start: 0, - end: 8, - }, - value: U128( - 1, - ), - }, - Spanned { - span: Span { - start: 0, - end: 4, - }, - value: Address( - 0x1, - ), - }, - Spanned { - span: Span { - start: 0, - end: 8, - }, - value: Address( - 0x1000, - ), - }, - Spanned { - span: Span { - start: 0, - end: 14, - }, - value: Address( - 0x100000000, - ), - }, - Spanned { - span: Span { - start: 0, - end: 10, - }, - value: Address( - 0x100000, - ), - }, - Spanned { - span: Span { - start: 0, - end: 4, - }, - value: Address( - 0x1, - ), - }, - Spanned { - span: Span { - start: 0, - end: 5, - }, - value: Address( - 0x1, - ), - }, - Spanned { - span: Span { - start: 0, - end: 4, - }, - value: Option( - Spanned { - span: Span { - start: 0, - end: 4, - }, - value: None, - }, - ), - }, - Spanned { - span: Span { - start: 0, - end: 7, - }, - value: Option( - Spanned { - span: Span { - start: 5, - end: 6, - }, - value: Some( - U64( - 1, - ), - ), - }, - ), - }, - Spanned { - span: Span { - start: 0, - end: 9, - }, - value: Option( - Spanned { - span: Span { - start: 5, - end: 8, - }, - value: Some( - U64( - 1, - ), - ), - }, - ), - }, - Spanned { - span: Span { - start: 0, - end: 29, - }, - value: Option( - Spanned { - span: Span { - start: 5, - end: 28, - }, - value: Some( - Option( - Spanned { - span: Span { - start: 10, - end: 27, - }, - value: Some( - Option( - Spanned { - span: Span { - start: 15, - end: 26, - }, - value: Some( - Option( - Spanned { - span: Span { - start: 20, - end: 25, - }, - value: Some( - U128( - 1, - ), - ), - }, - ), - ), - }, - ), - ), - }, - ), - ), - }, - ), - }, - Spanned { - span: Span { - start: 0, - end: 8, - }, - value: Vector( - [], - ), - }, - Spanned { - span: Span { - start: 0, - end: 15, - }, - value: Vector( - [ - Spanned { - span: Span { - start: 7, - end: 8, - }, - value: U64( - 1, - ), - }, - Spanned { - span: Span { - start: 10, - end: 11, - }, - value: U64( - 2, - ), - }, - Spanned { - span: Span { - start: 13, - end: 14, - }, - value: U64( - 3, - ), - }, - ], - ), - }, - Spanned { - span: Span { - start: 0, - end: 16, - }, - value: Vector( - [ - Spanned { - span: Span { - start: 7, - end: 8, - }, - value: U64( - 1, - ), - }, - Spanned { - span: Span { - start: 10, - end: 11, - }, - value: U64( - 2, - ), - }, - Spanned { - span: Span { - start: 13, - end: 14, - }, - value: U64( - 3, - ), - }, - ], - ), - }, - Spanned { - span: Span { - start: 0, - end: 7, - }, - value: VariableAccess( - Spanned { - span: Span { - start: 0, - end: 3, - }, - value: "foo", - }, - [ - Spanned { - span: Span { - start: 4, - end: 7, - }, - value: "bar", - }, - ], - ), - }, - Spanned { - span: Span { - start: 0, - end: 11, - }, - value: VariableAccess( - Spanned { - span: Span { - start: 0, - end: 3, - }, - value: "foo", - }, - [ - Spanned { - span: Span { - start: 4, - end: 7, - }, - value: "bar", - }, - Spanned { - span: Span { - start: 8, - end: 11, - }, - value: "baz", - }, - ], - ), - }, - Spanned { - span: Span { - start: 0, - end: 15, - }, - value: VariableAccess( - Spanned { - span: Span { - start: 0, - end: 3, - }, - value: "foo", - }, - [ - Spanned { - span: Span { - start: 4, - end: 7, - }, - value: "bar", - }, - Spanned { - span: Span { - start: 8, - end: 11, - }, - value: "baz", - }, - Spanned { - span: Span { - start: 12, - end: 15, - }, - value: "qux", - }, - ], - ), - }, - Spanned { - span: Span { - start: 0, - end: 5, - }, - value: VariableAccess( - Spanned { - span: Span { - start: 0, - end: 3, - }, - value: "foo", - }, - [ - Spanned { - span: Span { - start: 4, - end: 5, - }, - value: "0", - }, - ], - ), - }, - Spanned { - span: Span { - start: 0, - end: 7, - }, - value: VariableAccess( - Spanned { - span: Span { - start: 0, - end: 3, - }, - value: "foo", - }, - [ - Spanned { - span: Span { - start: 4, - end: 5, - }, - value: "0", - }, - Spanned { - span: Span { - start: 6, - end: 7, - }, - value: "1", - }, - ], - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_args_invalid.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_args_invalid.snap deleted file mode 100644 index 7facd1462f1..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_args_invalid.snap +++ /dev/null @@ -1,126 +0,0 @@ ---- -source: crates/sui/src/client_ptb/parser.rs -expression: parsed ---- -[ - PTBError { - message: "number too large to fit in target type", - span: Span { - start: 0, - end: 7, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Expected a numerical address but got a named address 'n'", - span: Span { - start: 0, - end: 2, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Expected '(' but found end of input", - span: Span { - start: 4, - end: 4, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Unexpected end of input", - span: Span { - start: 5, - end: 5, - }, - help: Some( - "Expected an argument here", - ), - severity: Error, - }, - PTBError { - message: "Expected ')' but found end of input", - span: Span { - start: 6, - end: 6, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Expected '[' but found end of input", - span: Span { - start: 6, - end: 6, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Unexpected end of input", - span: Span { - start: 7, - end: 7, - }, - help: Some( - "Expected an array here", - ), - severity: Error, - }, - PTBError { - message: "Unexpected end of input", - span: Span { - start: 9, - end: 9, - }, - help: Some( - "Expected an array here", - ), - severity: Error, - }, - PTBError { - message: "Unexpected number '2'", - span: Span { - start: 9, - end: 10, - }, - help: Some( - "Expected ']' or ','", - ), - severity: Error, - }, - PTBError { - message: "Unexpected ','", - span: Span { - start: 7, - end: 8, - }, - help: Some( - "Expected an argument here", - ), - severity: Error, - }, - PTBError { - message: "Expected a field name after '.'", - span: Span { - start: 4, - end: 4, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Unexpected '.'", - span: Span { - start: 0, - end: 1, - }, - help: Some( - "Expected an argument here", - ), - severity: Error, - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_commands.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_commands.snap deleted file mode 100644 index d8ac25d236e..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_commands.snap +++ /dev/null @@ -1,1449 +0,0 @@ ---- -source: crates/sui/src/client_ptb/parser.rs -expression: parsed ---- -[ - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 17, - }, - value: Publish( - Spanned { - span: Span { - start: 0, - end: 17, - }, - value: "foo/bar", - }, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 18, - end: 32, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 21, - }, - value: Publish( - Spanned { - span: Span { - start: 0, - end: 21, - }, - value: "foo/bar.ptb", - }, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 22, - end: 36, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 18, - }, - value: Upgrade( - Spanned { - span: Span { - start: 0, - end: 13, - }, - value: "foo", - }, - Spanned { - span: Span { - start: 14, - end: 18, - }, - value: Address( - 0x1, - ), - }, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 19, - end: 33, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 27, - }, - value: TransferObjects( - Spanned { - span: Span { - start: 19, - end: 25, - }, - value: [ - Spanned { - span: Span { - start: 20, - end: 21, - }, - value: Identifier( - "b", - ), - }, - Spanned { - span: Span { - start: 23, - end: 24, - }, - value: Identifier( - "c", - ), - }, - ], - }, - Spanned { - span: Span { - start: 26, - end: 27, - }, - value: Identifier( - "a", - ), - }, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 28, - end: 42, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 24, - }, - value: TransferObjects( - Spanned { - span: Span { - start: 19, - end: 22, - }, - value: [ - Spanned { - span: Span { - start: 20, - end: 21, - }, - value: Identifier( - "b", - ), - }, - ], - }, - Spanned { - span: Span { - start: 23, - end: 24, - }, - value: Identifier( - "a", - ), - }, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 25, - end: 39, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 26, - }, - value: TransferObjects( - Spanned { - span: Span { - start: 19, - end: 22, - }, - value: [ - Spanned { - span: Span { - start: 20, - end: 21, - }, - value: Identifier( - "b", - ), - }, - ], - }, - Spanned { - span: Span { - start: 23, - end: 26, - }, - value: VariableAccess( - Spanned { - span: Span { - start: 23, - end: 24, - }, - value: "a", - }, - [ - Spanned { - span: Span { - start: 25, - end: 26, - }, - value: "0", - }, - ], - ), - }, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 27, - end: 41, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 22, - }, - value: SplitCoins( - Spanned { - span: Span { - start: 14, - end: 15, - }, - value: Identifier( - "a", - ), - }, - Spanned { - span: Span { - start: 16, - end: 22, - }, - value: [ - Spanned { - span: Span { - start: 17, - end: 18, - }, - value: Identifier( - "b", - ), - }, - Spanned { - span: Span { - start: 20, - end: 21, - }, - value: Identifier( - "c", - ), - }, - ], - }, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 23, - end: 37, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 19, - }, - value: SplitCoins( - Spanned { - span: Span { - start: 14, - end: 15, - }, - value: Identifier( - "a", - ), - }, - Spanned { - span: Span { - start: 16, - end: 19, - }, - value: [ - Spanned { - span: Span { - start: 17, - end: 18, - }, - value: Identifier( - "c", - ), - }, - ], - }, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 20, - end: 34, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 22, - }, - value: MergeCoins( - Spanned { - span: Span { - start: 14, - end: 15, - }, - value: Identifier( - "a", - ), - }, - Spanned { - span: Span { - start: 16, - end: 22, - }, - value: [ - Spanned { - span: Span { - start: 17, - end: 18, - }, - value: Identifier( - "b", - ), - }, - Spanned { - span: Span { - start: 20, - end: 21, - }, - value: Identifier( - "c", - ), - }, - ], - }, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 23, - end: 37, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 19, - }, - value: MergeCoins( - Spanned { - span: Span { - start: 14, - end: 15, - }, - value: Identifier( - "a", - ), - }, - Spanned { - span: Span { - start: 16, - end: 19, - }, - value: [ - Spanned { - span: Span { - start: 17, - end: 18, - }, - value: Identifier( - "c", - ), - }, - ], - }, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 20, - end: 34, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 24, - }, - value: MakeMoveVec( - Spanned { - span: Span { - start: 17, - end: 20, - }, - value: U64, - }, - Spanned { - span: Span { - start: 22, - end: 24, - }, - value: [], - }, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 25, - end: 39, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 31, - }, - value: MakeMoveVec( - Spanned { - span: Span { - start: 17, - end: 19, - }, - value: U8, - }, - Spanned { - span: Span { - start: 21, - end: 31, - }, - value: [ - Spanned { - span: Span { - start: 22, - end: 25, - }, - value: U8( - 1, - ), - }, - Spanned { - span: Span { - start: 27, - end: 30, - }, - value: U8( - 2, - ), - }, - ], - }, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 32, - end: 46, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 71, - }, - value: MoveCall( - Spanned { - span: Span { - start: 12, - end: 46, - }, - value: ModuleAccess { - address: Spanned { - span: Span { - start: 12, - end: 15, - }, - value: Numerical( - 0x3, - ), - }, - module_name: Spanned { - span: Span { - start: 17, - end: 27, - }, - value: Identifier( - "sui_system", - ), - }, - function_name: Spanned { - span: Span { - start: 29, - end: 46, - }, - value: Identifier( - "request_add_stake", - ), - }, - }, - }, - None, - [ - Spanned { - span: Span { - start: 47, - end: 53, - }, - value: Identifier( - "system", - ), - }, - Spanned { - span: Span { - start: 54, - end: 61, - }, - value: VariableAccess( - Spanned { - span: Span { - start: 54, - end: 59, - }, - value: "coins", - }, - [ - Spanned { - span: Span { - start: 60, - end: 61, - }, - value: "0", - }, - ], - ), - }, - Spanned { - span: Span { - start: 62, - end: 71, - }, - value: Identifier( - "validator", - ), - }, - ], - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 72, - end: 86, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 40, - }, - value: MoveCall( - Spanned { - span: Span { - start: 12, - end: 32, - }, - value: ModuleAccess { - address: Spanned { - span: Span { - start: 12, - end: 15, - }, - value: Named( - "std", - ), - }, - module_name: Spanned { - span: Span { - start: 17, - end: 23, - }, - value: Identifier( - "option", - ), - }, - function_name: Spanned { - span: Span { - start: 25, - end: 32, - }, - value: Identifier( - "is_none", - ), - }, - }, - }, - Some( - Spanned { - span: Span { - start: 33, - end: 38, - }, - value: [ - U64, - ], - }, - ), - [ - Spanned { - span: Span { - start: 39, - end: 40, - }, - value: Identifier( - "p", - ), - }, - ], - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 41, - end: 55, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 39, - }, - value: MoveCall( - Spanned { - span: Span { - start: 12, - end: 32, - }, - value: ModuleAccess { - address: Spanned { - span: Span { - start: 12, - end: 15, - }, - value: Named( - "std", - ), - }, - module_name: Spanned { - span: Span { - start: 17, - end: 23, - }, - value: Identifier( - "option", - ), - }, - function_name: Spanned { - span: Span { - start: 25, - end: 32, - }, - value: Identifier( - "is_some", - ), - }, - }, - }, - Some( - Spanned { - span: Span { - start: 32, - end: 37, - }, - value: [ - U32, - ], - }, - ), - [ - Spanned { - span: Span { - start: 38, - end: 39, - }, - value: Identifier( - "q", - ), - }, - ], - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 40, - end: 54, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 10, - }, - value: Assign( - Spanned { - span: Span { - start: 9, - end: 10, - }, - value: "a", - }, - None, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 11, - end: 25, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 14, - }, - value: Assign( - Spanned { - span: Span { - start: 9, - end: 10, - }, - value: "a", - }, - Some( - Spanned { - span: Span { - start: 11, - end: 14, - }, - value: VariableAccess( - Spanned { - span: Span { - start: 11, - end: 12, - }, - value: "b", - }, - [ - Spanned { - span: Span { - start: 13, - end: 14, - }, - value: "1", - }, - ], - ), - }, - ), - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 15, - end: 29, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 14, - }, - value: Assign( - Spanned { - span: Span { - start: 9, - end: 10, - }, - value: "a", - }, - Some( - Spanned { - span: Span { - start: 11, - end: 14, - }, - value: U8( - 1, - ), - }, - ), - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 15, - end: 29, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 15, - }, - value: Assign( - Spanned { - span: Span { - start: 9, - end: 10, - }, - value: "a", - }, - Some( - Spanned { - span: Span { - start: 11, - end: 15, - }, - value: Address( - 0x1, - ), - }, - ), - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 16, - end: 30, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 26, - }, - value: Assign( - Spanned { - span: Span { - start: 9, - end: 10, - }, - value: "a", - }, - Some( - Spanned { - span: Span { - start: 11, - end: 26, - }, - value: Vector( - [ - Spanned { - span: Span { - start: 18, - end: 19, - }, - value: U64( - 1, - ), - }, - Spanned { - span: Span { - start: 21, - end: 22, - }, - value: U64( - 2, - ), - }, - Spanned { - span: Span { - start: 24, - end: 25, - }, - value: U64( - 3, - ), - }, - ], - ), - }, - ), - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 27, - end: 41, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 15, - }, - value: Assign( - Spanned { - span: Span { - start: 9, - end: 10, - }, - value: "a", - }, - Some( - Spanned { - span: Span { - start: 11, - end: 15, - }, - value: Option( - Spanned { - span: Span { - start: 11, - end: 15, - }, - value: None, - }, - ), - }, - ), - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 16, - end: 30, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 18, - }, - value: Assign( - Spanned { - span: Span { - start: 9, - end: 10, - }, - value: "a", - }, - Some( - Spanned { - span: Span { - start: 11, - end: 18, - }, - value: Option( - Spanned { - span: Span { - start: 16, - end: 17, - }, - value: Some( - U64( - 1, - ), - ), - }, - ), - }, - ), - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 19, - end: 33, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: Some( - Spanned { - span: Span { - start: 11, - end: 15, - }, - value: 0x0000000000000000000000000000000000000000000000000000000000000001, - }, - ), - json_set: false, - gas_budget: Spanned { - span: Span { - start: 16, - end: 30, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: true, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 10, - end: 24, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: true, - gas_budget: Spanned { - span: Span { - start: 7, - end: 21, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: true, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 10, - end: 24, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [], - warn_shadows_set: true, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 15, - end: 29, - }, - value: 1, - }, - }, - ), -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_commands_invalid.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_commands_invalid.snap deleted file mode 100644 index 42e38b74777..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_commands_invalid.snap +++ /dev/null @@ -1,820 +0,0 @@ ---- -source: crates/sui/src/client_ptb/parser.rs -expression: parsed ---- -[ - [ - PTBError { - message: "Unexpected end of input", - span: Span { - start: 9, - end: 9, - }, - help: Some( - "Expected to find a command here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 9, - end: 9, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected end of input", - span: Span { - start: 9, - end: 9, - }, - help: Some( - "Expected to find a command here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 9, - end: 9, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected end of input", - span: Span { - start: 11, - end: 11, - }, - help: Some( - "Expected an argument here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 11, - end: 11, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected '[' but found identifier 'a'", - span: Span { - start: 19, - end: 20, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 20, - end: 20, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected end of input", - span: Span { - start: 22, - end: 22, - }, - help: Some( - "Expected an argument here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 22, - end: 22, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected '[' but found end of input", - span: Span { - start: 18, - end: 18, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 18, - end: 18, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected '['", - span: Span { - start: 23, - end: 24, - }, - help: Some( - "Expected an argument here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 26, - end: 26, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected '[' but found end of input", - span: Span { - start: 15, - end: 15, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 15, - end: 15, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected '['", - span: Span { - start: 14, - end: 15, - }, - help: Some( - "Expected an argument here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 17, - end: 17, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected end of input", - span: Span { - start: 13, - end: 13, - }, - help: Some( - "Expected an argument here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 13, - end: 13, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected '[' but found identifier 'b'", - span: Span { - start: 16, - end: 17, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 19, - end: 19, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected identifier 'c'", - span: Span { - start: 20, - end: 21, - }, - help: Some( - "Expected to find a command here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 21, - end: 21, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected '[' but found end of input", - span: Span { - start: 15, - end: 15, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 15, - end: 15, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected '['", - span: Span { - start: 14, - end: 15, - }, - help: Some( - "Expected an argument here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 17, - end: 17, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected end of input", - span: Span { - start: 13, - end: 13, - }, - help: Some( - "Expected an argument here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 13, - end: 13, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected '[' but found identifier 'b'", - span: Span { - start: 16, - end: 17, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 19, - end: 19, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected identifier 'c'", - span: Span { - start: 20, - end: 21, - }, - help: Some( - "Expected to find a command here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 21, - end: 21, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected '<' but found end of input", - span: Span { - start: 15, - end: 15, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 15, - end: 15, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected '<' but found '['", - span: Span { - start: 16, - end: 17, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 25, - end: 25, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected '[' but found end of input", - span: Span { - start: 21, - end: 21, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 21, - end: 21, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected end of input", - span: Span { - start: 11, - end: 11, - }, - help: Some( - "Value addresses can either be a variable in-scope, or a numerical address, e.g., 0xc0ffee", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 11, - end: 11, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected '['", - span: Span { - start: 37, - end: 38, - }, - help: Some( - "Expected an argument here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 39, - end: 39, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected an identifier but found end of input", - span: Span { - start: 8, - end: 8, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 8, - end: 8, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected identifier 'c'", - span: Span { - start: 13, - end: 14, - }, - help: Some( - "Expected to find a command here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 14, - end: 14, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected a variable name but found reserved word 'none'.", - span: Span { - start: 9, - end: 13, - }, - help: Some( - "Variable names cannot be 'address', 'bool', 'vector', 'some', 'none', 'gas', 'u8', 'u16', 'u32', 'u64', 'u128', or 'u256'.", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 15, - end: 15, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected a variable name but found reserved word 'some'.", - span: Span { - start: 9, - end: 13, - }, - help: Some( - "Variable names cannot be 'address', 'bool', 'vector', 'some', 'none', 'gas', 'u8', 'u16', 'u32', 'u64', 'u128', or 'u256'.", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 18, - end: 18, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected '.'", - span: Span { - start: 10, - end: 11, - }, - help: Some( - "Expected an argument here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 16, - end: 16, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "number too large to fit in target type", - span: Span { - start: 13, - end: 75, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 75, - end: 75, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected '['", - span: Span { - start: 13, - end: 14, - }, - help: Some( - "Expected an argument here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 16, - end: 16, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected a u64 value", - span: Span { - start: 13, - end: 17, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 17, - end: 17, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected a u64 value", - span: Span { - start: 13, - end: 17, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 17, - end: 17, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected an address", - span: Span { - start: 11, - end: 15, - }, - help: Some( - "Addresses or object IDs require the character '@' in front", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 15, - end: 15, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected an address", - span: Span { - start: 10, - end: 10, - }, - help: Some( - "Addresses or object IDs require the character '@' in front", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 10, - end: 10, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Unexpected '@'", - span: Span { - start: 16, - end: 17, - }, - help: Some( - "Expected to find a command here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 20, - end: 20, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], - [ - PTBError { - message: "Expected an address", - span: Span { - start: 11, - end: 12, - }, - help: Some( - "Addresses or object IDs require the character '@' in front", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 12, - end: 12, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, - ], -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_publish.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_publish.snap deleted file mode 100644 index e4ac714c42b..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_publish.snap +++ /dev/null @@ -1,80 +0,0 @@ ---- -source: crates/sui/src/client_ptb/parser.rs -expression: parsed ---- -[ - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 17, - }, - value: Publish( - Spanned { - span: Span { - start: 0, - end: 17, - }, - value: "foo/bar", - }, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 18, - end: 32, - }, - value: 1, - }, - }, - ), - ( - Program { - commands: [ - Spanned { - span: Span { - start: 0, - end: 17, - }, - value: Publish( - Spanned { - span: Span { - start: 0, - end: 17, - }, - value: "foo/bar", - }, - ), - }, - ], - warn_shadows_set: false, - }, - ProgramMetadata { - preview_set: false, - summary_set: false, - serialize_unsigned_set: false, - serialize_signed_set: false, - gas_object_id: None, - json_set: false, - gas_budget: Spanned { - span: Span { - start: 18, - end: 32, - }, - value: 1, - }, - }, - ), -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_types.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_types.snap deleted file mode 100644 index d09ddcd01ab..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_types.snap +++ /dev/null @@ -1,219 +0,0 @@ ---- -source: crates/sui/src/client_ptb/parser.rs -expression: parsed ---- -[ - Spanned { - span: Span { - start: 0, - end: 2, - }, - value: U8, - }, - Spanned { - span: Span { - start: 0, - end: 3, - }, - value: U16, - }, - Spanned { - span: Span { - start: 0, - end: 3, - }, - value: U32, - }, - Spanned { - span: Span { - start: 0, - end: 3, - }, - value: U64, - }, - Spanned { - span: Span { - start: 0, - end: 4, - }, - value: U128, - }, - Spanned { - span: Span { - start: 0, - end: 4, - }, - value: U256, - }, - Spanned { - span: Span { - start: 0, - end: 4, - }, - value: Bool, - }, - Spanned { - span: Span { - start: 0, - end: 7, - }, - value: Address, - }, - Spanned { - span: Span { - start: 0, - end: 10, - }, - value: Vector( - U8, - ), - }, - Spanned { - span: Span { - start: 0, - end: 15, - }, - value: Struct( - ParsedStructType { - fq_name: ParsedFqName { - module: ParsedModuleId { - address: Named( - "sui", - ), - name: "object", - }, - name: "ID", - }, - type_args: [], - }, - ), - }, - Spanned { - span: Span { - start: 0, - end: 16, - }, - value: Struct( - ParsedStructType { - fq_name: ParsedFqName { - module: ParsedModuleId { - address: Numerical( - 0x2, - ), - name: "object", - }, - name: "UID", - }, - type_args: [], - }, - ), - }, - Spanned { - span: Span { - start: 0, - end: 26, - }, - value: Struct( - ParsedStructType { - fq_name: ParsedFqName { - module: ParsedModuleId { - address: Numerical( - 3, - ), - name: "staking_pool", - }, - name: "StakedSui", - }, - type_args: [], - }, - ), - }, - Spanned { - span: Span { - start: 0, - end: 28, - }, - value: Struct( - ParsedStructType { - fq_name: ParsedFqName { - module: ParsedModuleId { - address: Numerical( - 0x2, - ), - name: "coin", - }, - name: "Coin", - }, - type_args: [ - Struct( - ParsedStructType { - fq_name: ParsedFqName { - module: ParsedModuleId { - address: Numerical( - 2, - ), - name: "sui", - }, - name: "SUI", - }, - type_args: [], - }, - ), - ], - }, - ), - }, - Spanned { - span: Span { - start: 0, - end: 68, - }, - value: Struct( - ParsedStructType { - fq_name: ParsedFqName { - module: ParsedModuleId { - address: Named( - "sui", - ), - name: "table", - }, - name: "Table", - }, - type_args: [ - Struct( - ParsedStructType { - fq_name: ParsedFqName { - module: ParsedModuleId { - address: Named( - "sui", - ), - name: "object", - }, - name: "ID", - }, - type_args: [], - }, - ), - Vector( - Struct( - ParsedStructType { - fq_name: ParsedFqName { - module: ParsedModuleId { - address: Numerical( - 0x1, - ), - name: "option", - }, - name: "Option", - }, - type_args: [ - U32, - ], - }, - ), - ), - ], - }, - ), - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_types_invalid.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_types_invalid.snap deleted file mode 100644 index c8fee0cb4f4..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_types_invalid.snap +++ /dev/null @@ -1,84 +0,0 @@ ---- -source: crates/sui/src/client_ptb/parser.rs -expression: parsed ---- -[ - PTBError { - message: "Expected '::' but found end of input", - span: Span { - start: 6, - end: 6, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Expected '::' but found end of input", - span: Span { - start: 17, - end: 17, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Expected '>' but found ','", - span: Span { - start: 9, - end: 10, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Expected an identifier but found end of input", - span: Span { - start: 5, - end: 5, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Expected '::' but found end of input", - span: Span { - start: 8, - end: 8, - }, - help: None, - severity: Error, - }, - PTBError { - message: "Unexpected end of input", - span: Span { - start: 14, - end: 14, - }, - help: Some( - "Expected a type here", - ), - severity: Error, - }, - PTBError { - message: "Unexpected end of input", - span: Span { - start: 16, - end: 16, - }, - help: Some( - "Expected ',' or '>'", - ), - severity: Error, - }, - PTBError { - message: "Unexpected end of input", - span: Span { - start: 17, - end: 17, - }, - help: Some( - "Expected a type here", - ), - severity: Error, - }, -] diff --git a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_unexpected_top_level.snap b/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_unexpected_top_level.snap deleted file mode 100644 index a8c8904dade..00000000000 --- a/crates/sui/src/client_ptb/snapshots/sui__client_ptb__parser__tests__parse_unexpected_top_level.snap +++ /dev/null @@ -1,28 +0,0 @@ ---- -source: crates/sui/src/client_ptb/parser.rs -expression: result.unwrap_err() ---- -[ - PTBError { - message: "Unexpected input \"0x\"", - span: Span { - start: 0, - end: 2, - }, - help: Some( - "Expected to find a command here", - ), - severity: Error, - }, - PTBError { - message: "Gas budget not set.", - span: Span { - start: 0, - end: 2, - }, - help: Some( - "Use --gas-budget to set a gas budget", - ), - severity: Error, - }, -] diff --git a/crates/sui/src/client_ptb/token.rs b/crates/sui/src/client_ptb/token.rs deleted file mode 100644 index 6989135586d..00000000000 --- a/crates/sui/src/client_ptb/token.rs +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt; - -#[derive(Clone, Copy, Debug)] -pub struct Lexeme<'t>( - /// The kind of lexeme. - pub Token, - /// Slice from source that identifies this lexeme (among other instances of - /// this token). - pub &'t str, -); - -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum Token { - /// --[a-zA-Z0-9_-]+ - Command, - /// -[a-zA-Z0-9] - Flag, - /// [a-zA-Z_][a-zA-Z0-9_-]* - Ident, - /// [1-9][0-9_]* - Number, - /// 0x[0-9a-fA-F][0-9a-fA-F_]* - HexNumber, - /// "..." | '...' - String, - /// :: - ColonColon, - /// , - Comma, - /// [ - LBracket, - /// ] - RBracket, - /// ( - LParen, - /// ) - RParen, - /// < - LAngle, - /// > - RAngle, - /// @ - At, - /// . - Dot, - - /// End of input. - Eof, - - /// Special tokens for unexpected lexer states that the parser should error - /// on. - Unexpected, - UnfinishedString, - EarlyEof, - - // The following tokens are special -- they consume multiple shell tokens, to ensure we - // capture the path for a publish or an upgrade command. - /// --publish \ - Publish, - /// --upgraded \ - Upgrade, -} - -impl<'l> Lexeme<'l> { - /// Returns true if this lexeme corresponds to a special error token. - pub fn is_error(&self) -> bool { - use Token as T; - matches!(self.0, T::Unexpected | T::UnfinishedString | T::EarlyEof) - } - - /// Returns true if this is the kind of lexeme that finishes the token - /// stream. - pub fn is_terminal(&self) -> bool { - self.is_error() || self.0 == Token::Eof - } - - /// Returns true if this lexeme signifies the end of the current command. - pub fn is_command_end(&self) -> bool { - self.is_terminal() || [Token::Command, Token::Publish, Token::Upgrade].contains(&self.0) - } -} - -impl<'a> fmt::Display for Lexeme<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use Token as T; - - match self.0 { - T::Command => write!(f, "command '--{}'", self.1), - T::Flag => write!(f, "flag '-{}'", self.1), - T::Ident => write!(f, "identifier '{}'", self.1), - T::Number => write!(f, "number '{}'", self.1), - T::HexNumber => write!(f, "hexadecimal number '0x{}'", self.1), - T::String => write!(f, "string {:?}", self.1), - T::ColonColon => write!(f, "'::'"), - T::Comma => write!(f, "','"), - T::LBracket => write!(f, "'['"), - T::RBracket => write!(f, "']'"), - T::LParen => write!(f, "'('"), - T::RParen => write!(f, "')'"), - T::LAngle => write!(f, "'<'"), - T::RAngle => write!(f, "'>'"), - T::At => write!(f, "'@'"), - T::Dot => write!(f, "'.'"), - T::Unexpected => write!(f, "input {:?}", self.1), - T::UnfinishedString => write!(f, "unfinished string {:?}", format!("{}...", self.1)), - T::EarlyEof | T::Eof => write!(f, "end of input"), - T::Publish => write!(f, "command '--publish {:?}'", self.1), - T::Upgrade => write!(f, "command '--upgrade {:?}'", self.1), - } - } -} - -impl fmt::Display for Token { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use Token as T; - match self { - T::Command => write!(f, "a command"), - T::Flag => write!(f, "a flag"), - T::Ident => write!(f, "an identifier"), - T::Number => write!(f, "a number"), - T::HexNumber => write!(f, "a hexadecimal number"), - T::String => write!(f, "a string"), - T::ColonColon => write!(f, "'::'"), - T::Comma => write!(f, "','"), - T::LBracket => write!(f, "'['"), - T::RBracket => write!(f, "']'"), - T::LParen => write!(f, "'('"), - T::RParen => write!(f, "')'"), - T::LAngle => write!(f, "'<'"), - T::RAngle => write!(f, "'>'"), - T::At => write!(f, "'@'"), - T::Dot => write!(f, "'.'"), - T::Eof => write!(f, "end of input"), - T::Unexpected => write!(f, "unexpected input"), - T::UnfinishedString => write!(f, "an unfinished string"), - T::EarlyEof => write!(f, "unexpected end of input"), - T::Publish => write!(f, "a '--publish' command"), - T::Upgrade => write!(f, "an '--upgrade' command"), - } - } -} diff --git a/crates/sui/src/fire_drill.rs b/crates/sui/src/fire_drill.rs deleted file mode 100644 index c30802c9582..00000000000 --- a/crates/sui/src/fire_drill.rs +++ /dev/null @@ -1,388 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -//! A tool to semi automate fire drills. It still requires some manual work -//! today. For example, -//! 1. update iptables for new tpc/udp ports -//! 2. restart the node in a new epoch when config file will be reloaded and -//! take effects -//! -//! Example usage: -//! sui fire-drill metadata-rotation \ -//! --sui-node-config-path validator.yaml \ -//! --account-key-path account.key \ -//! --fullnode-rpc-url http://fullnode-my-local-net:9000 - -use std::path::{Path, PathBuf}; - -use anyhow::bail; -use clap::*; -use fastcrypto::{ - ed25519::Ed25519KeyPair, - traits::{KeyPair, ToFromBytes}, -}; -use move_core_types::ident_str; -use sui_config::{ - local_ip_utils, - node::{AuthorityKeyPairWithPath, KeyPairWithPath}, - Config, NodeConfig, PersistedConfig, -}; -use sui_json_rpc_types::{SuiExecutionStatus, SuiTransactionBlockResponseOptions}; -use sui_keys::keypair_file::read_keypair_from_file; -use sui_sdk::{rpc_types::SuiTransactionBlockEffectsAPI, SuiClient, SuiClientBuilder}; -use sui_types::{ - base_types::{ObjectRef, SuiAddress}, - committee::EpochId, - crypto::{generate_proof_of_possession, get_authority_key_pair, get_key_pair, SuiKeyPair}, - multiaddr::{Multiaddr, Protocol}, - transaction::{CallArg, Transaction, TransactionData, TEST_ONLY_GAS_UNIT_FOR_GENERIC}, - SUI_SYSTEM_PACKAGE_ID, -}; -use tracing::info; - -#[derive(Parser)] -pub enum FireDrill { - MetadataRotation(MetadataRotation), -} - -#[derive(Parser)] -pub struct MetadataRotation { - /// Path to sui node config. - #[clap(long = "sui-node-config-path")] - sui_node_config_path: PathBuf, - /// Path to account key file. - #[clap(long = "account-key-path")] - account_key_path: PathBuf, - /// Jsonrpc url for a reliable fullnode. - #[clap(long = "fullnode-rpc-url")] - fullnode_rpc_url: String, -} - -pub async fn run_fire_drill(fire_drill: FireDrill) -> anyhow::Result<()> { - match fire_drill { - FireDrill::MetadataRotation(metadata_rotation) => { - run_metadata_rotation(metadata_rotation).await?; - } - } - Ok(()) -} - -async fn run_metadata_rotation(metadata_rotation: MetadataRotation) -> anyhow::Result<()> { - let MetadataRotation { - sui_node_config_path, - account_key_path, - fullnode_rpc_url, - } = metadata_rotation; - let account_key = read_keypair_from_file(&account_key_path)?; - let config: NodeConfig = PersistedConfig::read(&sui_node_config_path).map_err(|err| { - err.context(format!( - "Cannot open Sui Node Config file at {:?}", - sui_node_config_path - )) - })?; - - let sui_client = SuiClientBuilder::default().build(fullnode_rpc_url).await?; - let sui_address = SuiAddress::from(&account_key.public()); - let starting_epoch = current_epoch(&sui_client).await?; - info!( - "Running Metadata Rotation fire drill for validator address {sui_address} in epoch {starting_epoch}." - ); - - // Prepare new metadata for next epoch - let new_config_path = - update_next_epoch_metadata(&sui_node_config_path, &config, &sui_client, &account_key) - .await?; - - let current_epoch = current_epoch(&sui_client).await?; - if current_epoch > starting_epoch { - bail!("Epoch already advanced to {current_epoch}"); - } - let target_epoch = starting_epoch + 1; - wait_for_next_epoch(&sui_client, target_epoch).await?; - info!("Just advanced to epoch {target_epoch}"); - - // Replace new config - std::fs::rename(new_config_path, sui_node_config_path)?; - info!("Updated Sui Node config."); - - Ok(()) -} - -// TODO move this to a shared lib -pub async fn get_gas_obj_ref( - sui_address: SuiAddress, - sui_client: &SuiClient, - minimal_gas_balance: u64, -) -> anyhow::Result { - let coins = sui_client - .coin_read_api() - .get_coins(sui_address, Some("0x2::sui::SUI".into()), None, None) - .await? - .data; - let gas_obj = coins.iter().find(|c| c.balance >= minimal_gas_balance); - if gas_obj.is_none() { - bail!("Validator doesn't have enough Sui coins to cover transaction fees."); - } - Ok(gas_obj.unwrap().object_ref()) -} - -async fn update_next_epoch_metadata( - sui_node_config_path: &Path, - config: &NodeConfig, - sui_client: &SuiClient, - account_key: &SuiKeyPair, -) -> anyhow::Result { - // Save backup config just in case - let mut backup_config_path = sui_node_config_path.to_path_buf(); - backup_config_path.pop(); - backup_config_path.push("node_config_backup.yaml"); - let backup_config = config.clone(); - backup_config.persisted(&backup_config_path).save()?; - - let sui_address = SuiAddress::from(&account_key.public()); - - let mut new_config = config.clone(); - - // protocol key - let new_protocol_key_pair = get_authority_key_pair().1; - let new_protocol_key_pair_copy = new_protocol_key_pair.copy(); - let pop = generate_proof_of_possession(&new_protocol_key_pair, sui_address); - new_config.protocol_key_pair = AuthorityKeyPairWithPath::new(new_protocol_key_pair); - - // network key - let new_network_key_pair: Ed25519KeyPair = get_key_pair().1; - let new_network_key_pair_copy = new_network_key_pair.copy(); - new_config.network_key_pair = KeyPairWithPath::new(SuiKeyPair::Ed25519(new_network_key_pair)); - - // worker key - let new_worker_key_pair: Ed25519KeyPair = get_key_pair().1; - let new_worker_key_pair_copy = new_worker_key_pair.copy(); - new_config.worker_key_pair = KeyPairWithPath::new(SuiKeyPair::Ed25519(new_worker_key_pair)); - - let validators = sui_client - .governance_api() - .get_latest_sui_system_state() - .await? - .active_validators; - let self_validator = validators - .iter() - .find(|v| v.sui_address == sui_address) - .unwrap(); - - // Network address - let mut new_network_address = Multiaddr::try_from(self_validator.net_address.clone()).unwrap(); - info!("Current network address: {:?}", new_network_address); - let http = new_network_address.pop().unwrap(); - // pop out tcp - new_network_address.pop().unwrap(); - let localhost = local_ip_utils::localhost_for_testing(); - let new_port = local_ip_utils::get_available_port(&localhost); - new_network_address.push(Protocol::Tcp(new_port)); - new_network_address.push(http); - info!("New network address: {:?}", new_network_address); - new_config.network_address = new_network_address.clone(); - - // p2p address - let mut new_external_address = config.p2p_config.external_address.clone().unwrap(); - info!("Current P2P external address: {:?}", new_external_address); - // pop out udp - new_external_address.pop().unwrap(); - let new_port = local_ip_utils::get_available_port(&localhost); - new_external_address.push(Protocol::Udp(new_port)); - info!("New P2P external address: {:?}", new_external_address); - new_config.p2p_config.external_address = Some(new_external_address.clone()); - - let mut new_listen_address = config.p2p_config.listen_address; - info!("Current P2P local listen address: {:?}", new_listen_address); - new_listen_address.set_port(new_port); - info!("New P2P local listen address: {:?}", new_listen_address); - new_config.p2p_config.listen_address = new_listen_address; - - // primary address - let mut new_primary_addresses = - Multiaddr::try_from(self_validator.primary_address.clone()).unwrap(); - info!("Current primary address: {:?}", new_primary_addresses); - // pop out udp - new_primary_addresses.pop().unwrap(); - let new_port = local_ip_utils::get_available_port(&localhost); - new_primary_addresses.push(Protocol::Udp(new_port)); - info!("New primary address: {:?}", new_primary_addresses); - - // worker address - let mut new_worker_addresses = Multiaddr::try_from( - validators - .iter() - .find(|v| v.sui_address == sui_address) - .unwrap() - .worker_address - .clone(), - ) - .unwrap(); - info!("Current worker address: {:?}", new_worker_addresses); - // pop out udp - new_worker_addresses.pop().unwrap(); - let new_port = local_ip_utils::get_available_port(&localhost); - new_worker_addresses.push(Protocol::Udp(new_port)); - info!("New worker address:: {:?}", new_worker_addresses); - - // Save new config - let mut new_config_path = sui_node_config_path.to_path_buf(); - new_config_path.pop(); - new_config_path.push( - String::from(sui_node_config_path.file_name().unwrap().to_str().unwrap()) + ".next_epoch", - ); - new_config.persisted(&new_config_path).save()?; - - // update protocol pubkey on chain - update_metadata_on_chain( - account_key, - "update_validator_next_epoch_protocol_pubkey", - vec![ - CallArg::Pure( - bcs::to_bytes(&new_protocol_key_pair_copy.public().as_bytes().to_vec()).unwrap(), - ), - CallArg::Pure(bcs::to_bytes(&pop.as_bytes().to_vec()).unwrap()), - ], - sui_client, - ) - .await?; - - // update network pubkey on chain - update_metadata_on_chain( - account_key, - "update_validator_next_epoch_network_pubkey", - vec![CallArg::Pure( - bcs::to_bytes(&new_network_key_pair_copy.public().as_bytes().to_vec()).unwrap(), - )], - sui_client, - ) - .await?; - - // update worker pubkey on chain - update_metadata_on_chain( - account_key, - "update_validator_next_epoch_worker_pubkey", - vec![CallArg::Pure( - bcs::to_bytes(&new_worker_key_pair_copy.public().as_bytes().to_vec()).unwrap(), - )], - sui_client, - ) - .await?; - - // update network address - update_metadata_on_chain( - account_key, - "update_validator_next_epoch_network_address", - vec![CallArg::Pure(bcs::to_bytes(&new_network_address).unwrap())], - sui_client, - ) - .await?; - - // update p2p address - update_metadata_on_chain( - account_key, - "update_validator_next_epoch_p2p_address", - vec![CallArg::Pure(bcs::to_bytes(&new_external_address).unwrap())], - sui_client, - ) - .await?; - - // update primary address - update_metadata_on_chain( - account_key, - "update_validator_next_epoch_primary_address", - vec![CallArg::Pure( - bcs::to_bytes(&new_primary_addresses).unwrap(), - )], - sui_client, - ) - .await?; - - // update worker address - update_metadata_on_chain( - account_key, - "update_validator_next_epoch_worker_address", - vec![CallArg::Pure(bcs::to_bytes(&new_worker_addresses).unwrap())], - sui_client, - ) - .await?; - - Ok(new_config_path) -} - -async fn update_metadata_on_chain( - account_key: &SuiKeyPair, - function: &'static str, - call_args: Vec, - sui_client: &SuiClient, -) -> anyhow::Result<()> { - let sui_address = SuiAddress::from(&account_key.public()); - let gas_obj_ref = get_gas_obj_ref(sui_address, sui_client, 10000 * 100).await?; - let rgp = sui_client - .governance_api() - .get_reference_gas_price() - .await?; - let mut args = vec![CallArg::SUI_SYSTEM_MUT]; - args.extend(call_args); - let tx_data = TransactionData::new_move_call( - sui_address, - SUI_SYSTEM_PACKAGE_ID, - ident_str!("sui_system").to_owned(), - ident_str!(function).to_owned(), - vec![], - gas_obj_ref, - args, - rgp * TEST_ONLY_GAS_UNIT_FOR_GENERIC, - rgp, - ) - .unwrap(); - execute_tx(account_key, sui_client, tx_data, function).await?; - tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; - Ok(()) -} - -async fn execute_tx( - account_key: &SuiKeyPair, - sui_client: &SuiClient, - tx_data: TransactionData, - action: &str, -) -> anyhow::Result<()> { - let tx = Transaction::from_data_and_signer(tx_data, vec![account_key]); - info!("Executing {:?}", tx.digest()); - let tx_digest = *tx.digest(); - let resp = sui_client - .quorum_driver_api() - .execute_transaction_block( - tx, - SuiTransactionBlockResponseOptions::full_content(), - Some(sui_types::quorum_driver_types::ExecuteTransactionRequestType::WaitForLocalExecution), - ) - .await - .unwrap(); - if *resp.effects.unwrap().status() != SuiExecutionStatus::Success { - anyhow::bail!("Tx to update metadata {:?} failed", tx_digest); - } - info!("{action} succeeded"); - Ok(()) -} - -async fn wait_for_next_epoch(sui_client: &SuiClient, target_epoch: EpochId) -> anyhow::Result<()> { - loop { - let epoch_id = current_epoch(sui_client).await?; - if epoch_id > target_epoch { - bail!( - "Current epoch ID {} is higher than target {}, likely something is off.", - epoch_id, - target_epoch - ); - } - if epoch_id == target_epoch { - return Ok(()); - } - tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; - } -} - -async fn current_epoch(sui_client: &SuiClient) -> anyhow::Result { - Ok(sui_client.read_api().get_committee_info(None).await?.epoch) -} diff --git a/crates/sui/src/genesis_inspector.rs b/crates/sui/src/genesis_inspector.rs deleted file mode 100644 index 37d1f4823c2..00000000000 --- a/crates/sui/src/genesis_inspector.rs +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::collections::BTreeMap; - -use inquire::Select; -use sui_config::genesis::UnsignedGenesis; -use sui_types::{ - base_types::ObjectID, - coin::CoinMetadata, - gas_coin::{GasCoin, MIST_PER_SUI, TOTAL_SUPPLY_MIST}, - governance::StakedSui, - move_package::MovePackage, - object::{MoveObject, Owner}, - sui_system_state::SuiValidatorGenesis, -}; - -const STR_ALL: &str = "All"; -const STR_EXIT: &str = "Exit"; -const STR_SUI: &str = "Sui"; -const STR_STAKED_SUI: &str = "StakedSui"; -const STR_PACKAGE: &str = "Package"; -const STR_COIN_METADATA: &str = "CoinMetadata"; -const STR_OTHER: &str = "Other"; -const STR_SUI_DISTRIBUTION: &str = "Sui Distribution"; -const STR_OBJECTS: &str = "Objects"; -const STR_VALIDATORS: &str = "Validators"; - -#[allow(clippy::or_fun_call)] -pub(crate) fn examine_genesis_checkpoint(genesis: UnsignedGenesis) { - let system_object = genesis - .sui_system_object() - .into_genesis_version_for_tooling(); - - // Prepare Validator info - let validator_set = &system_object.validators.active_validators; - let validator_map = validator_set - .iter() - .map(|v| (v.verified_metadata().name.as_str(), v)) - .collect::>(); - let validator_pool_id_map = validator_set - .iter() - .map(|v| (v.staking_pool.id, v)) - .collect::>(); - - let mut validator_options: Vec<_> = validator_map.keys().copied().collect(); - validator_options.extend_from_slice(&[STR_ALL, STR_EXIT]); - println!("Total Number of Validators: {}", validator_set.len()); - - // Prepare Sui distribution info - let mut sui_distribution = BTreeMap::new(); - let entry = sui_distribution - .entry("Sui System".to_string()) - .or_insert(BTreeMap::new()); - entry.insert( - "Storage Fund".to_string(), - ( - STR_SUI, - system_object.storage_fund.non_refundable_balance.value(), - ), - ); - entry.insert( - "Stake Subsidy".to_string(), - (STR_SUI, system_object.stake_subsidy.balance.value()), - ); - - // Prepare Object Info - let mut owner_map = BTreeMap::new(); - let mut package_map = BTreeMap::new(); - let mut sui_map = BTreeMap::new(); - let mut staked_sui_map = BTreeMap::new(); - let mut coin_metadata_map = BTreeMap::new(); - let mut other_object_map = BTreeMap::new(); - - for object in genesis.objects() { - let object_id = object.id(); - let object_id_str = object_id.to_string(); - assert_eq!(object.storage_rebate, 0); - owner_map.insert(object.id(), object.owner); - - match &object.data { - sui_types::object::Data::Move(move_object) => { - if let Ok(gas) = GasCoin::try_from(object) { - let entry = sui_distribution - .entry(object.owner.to_string()) - .or_default(); - entry.insert(object_id_str.clone(), (STR_SUI, gas.value())); - sui_map.insert(object.id(), gas); - } else if let Ok(coin_metadata) = CoinMetadata::try_from(object) { - coin_metadata_map.insert(object.id(), coin_metadata); - } else if let Ok(staked_sui) = StakedSui::try_from(object) { - let entry = sui_distribution - .entry(object.owner.to_string()) - .or_default(); - entry.insert(object_id_str, (STR_STAKED_SUI, staked_sui.principal())); - // Assert pool id is associated with a knonw validator. - let validator = validator_pool_id_map.get(&staked_sui.pool_id()).unwrap(); - assert_eq!(validator.staking_pool.id, staked_sui.pool_id()); - - staked_sui_map.insert(object.id(), staked_sui); - } else { - other_object_map.insert(object.id(), move_object); - } - } - sui_types::object::Data::Package(p) => { - package_map.insert(object.id(), p); - } - } - } - println!( - "Total Number of Objects/Pacakges: {}", - genesis.objects().len() - ); - - // Always check the Total Supply - examine_total_supply(&sui_distribution, false); - - // Main loop for inspection - let main_options: Vec<&str> = vec![STR_SUI_DISTRIBUTION, STR_VALIDATORS, STR_OBJECTS, STR_EXIT]; - loop { - let ans = Select::new( - "Select one main category to examine ('Exit' to exit the program):", - main_options.clone(), - ) - .prompt(); - match ans { - Ok(name) if name == STR_SUI_DISTRIBUTION => { - examine_total_supply(&sui_distribution, true) - } - Ok(name) if name == STR_VALIDATORS => { - examine_validators(&validator_options, &validator_map); - } - Ok(name) if name == STR_OBJECTS => { - println!("Examine Objects (total: {})", genesis.objects().len()); - examine_object( - &owner_map, - &validator_pool_id_map, - &package_map, - &sui_map, - &staked_sui_map, - &coin_metadata_map, - &other_object_map, - ); - } - Ok(name) if name == STR_EXIT => break, - Ok(_) => (), - Err(err) => { - println!("Error: {err}"); - break; - } - } - } -} - -#[allow(clippy::ptr_arg)] -fn examine_validators( - validator_options: &Vec<&str>, - validator_map: &BTreeMap<&str, &SuiValidatorGenesis>, -) { - loop { - let ans = Select::new("Select one validator to examine ('All' to display all Validators, 'Exit' to return to Main):", validator_options.clone()).prompt(); - match ans { - Ok(name) if name == STR_ALL => { - for validator in validator_map.values() { - display_validator(validator); - } - } - Ok(name) if name == STR_EXIT => break, - Ok(name) => { - let validator = validator_map.get(name).unwrap(); - display_validator(validator); - } - Err(err) => { - println!("Error: {err}"); - break; - } - } - } - print_divider("Validator"); -} - -fn examine_object( - owner_map: &BTreeMap, - validator_pool_id_map: &BTreeMap, - package_map: &BTreeMap, - sui_map: &BTreeMap, - staked_sui_map: &BTreeMap, - coin_metadata_map: &BTreeMap, - other_object_map: &BTreeMap, -) { - let object_options: Vec<&str> = vec![ - STR_SUI, - STR_STAKED_SUI, - STR_COIN_METADATA, - STR_PACKAGE, - STR_OTHER, - STR_EXIT, - ]; - loop { - let ans = Select::new( - "Select one object category to examine ('Exit' to return to Main):", - object_options.clone(), - ) - .prompt(); - match ans { - Ok(name) if name == STR_EXIT => break, - Ok(name) if name == STR_SUI => { - for gas_coin in sui_map.values() { - display_sui(gas_coin, owner_map); - } - print_divider("Sui"); - } - Ok(name) if name == STR_STAKED_SUI => { - for staked_sui_coin in staked_sui_map.values() { - display_staked_sui(staked_sui_coin, validator_pool_id_map, owner_map); - } - print_divider(STR_STAKED_SUI); - } - Ok(name) if name == STR_PACKAGE => { - for package in package_map.values() { - println!("Package ID: {}", package.id()); - println!("Version: {}", package.version()); - println!("Modules: {:?}\n", package.serialized_module_map().keys()); - } - print_divider("Package"); - } - Ok(name) if name == STR_OTHER => { - for other_obj in other_object_map.values() { - println!("{:#?}", other_obj.type_()); - println!("{:?}", other_obj.version()); - println!("Has Public Transfer: {}\n", other_obj.has_public_transfer()); - } - print_divider("Other"); - } - Ok(name) if name == STR_COIN_METADATA => { - for coin_metadata in coin_metadata_map.values() { - println!("{:#?}\n", coin_metadata); - } - print_divider("CoinMetadata"); - } - Ok(_) => (), - Err(err) => { - println!("Error: {err}"); - break; - } - } - } - print_divider("Object"); -} - -fn examine_total_supply( - sui_distribution: &BTreeMap>, - print: bool, -) { - let mut total_sui = 0; - let mut total_staked_sui = 0; - for (owner, coins) in sui_distribution { - let mut amount_sum = 0; - for (owner, value) in coins.values() { - amount_sum += value; - if *owner == STR_STAKED_SUI { - total_staked_sui += value; - } - } - total_sui += amount_sum; - if print { - println!("Owner {:?}", owner); - println!( - "Total Amount of Sui/StakedSui Owned: {amount_sum} MIST or {} SUI:", - amount_sum / MIST_PER_SUI - ); - println!("{:#?}\n", coins); - } - } - assert_eq!(total_sui, TOTAL_SUPPLY_MIST); - // Always print this. - println!( - "Total Supply of Sui: {total_sui} MIST or {} SUI", - total_sui / MIST_PER_SUI - ); - println!( - "Total Amount of StakedSui: {total_staked_sui} MIST or {} SUI\n", - total_staked_sui / MIST_PER_SUI - ); - if print { - print_divider("Sui Distribution"); - } -} - -fn display_validator(validator: &SuiValidatorGenesis) { - let metadata = validator.verified_metadata(); - println!("Validator name: {}", metadata.name); - println!("{:#?}", metadata); - println!("Voting Power: {}", validator.voting_power); - println!("Gas Price: {}", validator.gas_price); - println!("Next Epoch Gas Price: {}", validator.next_epoch_gas_price); - println!("Commission Rate: {}", validator.commission_rate); - println!( - "Next Epoch Commission Rate: {}", - validator.next_epoch_commission_rate - ); - println!("Next Epoch Stake: {}", validator.next_epoch_stake); - println!("Staking Pool ID: {}", validator.staking_pool.id); - println!( - "Staking Pool Activation Epoch: {:?}", - validator.staking_pool.activation_epoch - ); - println!( - "Staking Pool Deactivation Epoch: {:?}", - validator.staking_pool.deactivation_epoch - ); - println!( - "Staking Pool Sui Balance: {:?}", - validator.staking_pool.sui_balance - ); - println!( - "Rewards Pool: {}", - validator.staking_pool.rewards_pool.value() - ); - println!( - "Pool Token Balance: {}", - validator.staking_pool.pool_token_balance - ); - println!( - "Pending Delegation: {}", - validator.staking_pool.pending_stake - ); - println!( - "Pending Total Sui Withdraw: {}", - validator.staking_pool.pending_total_sui_withdraw - ); - println!( - "Pendign Pool Token Withdraw: {}", - validator.staking_pool.pending_pool_token_withdraw - ); - println!( - "Exchange Rates ID: {}", - validator.staking_pool.exchange_rates.id - ); - println!( - "Exchange Rates Size: {}", - validator.staking_pool.exchange_rates.size - ); - print_divider(&metadata.name); -} - -fn display_sui(gas_coin: &GasCoin, owner_map: &BTreeMap) { - println!("ID: {}", gas_coin.id()); - println!("Balance: {}", gas_coin.value()); - println!("Owner: {}\n", owner_map.get(gas_coin.id()).unwrap()); -} - -fn display_staked_sui( - staked_sui: &StakedSui, - validator_pool_id_map: &BTreeMap, - owner_map: &BTreeMap, -) { - let validator = validator_pool_id_map.get(&staked_sui.pool_id()).unwrap(); - println!("{:#?}", staked_sui); - println!( - "Staked to Validator: {}", - validator.verified_metadata().name - ); - println!("Owner: {}\n", owner_map.get(&staked_sui.id()).unwrap()); -} - -fn print_divider(title: &str) { - let title = format!("End of {title}"); - let divider_length = 80; - let left_divider_length = 10; - assert!(title.len() <= divider_length - left_divider_length * 2); - let divider_op = "-"; - let divider = divider_op.repeat(divider_length); - let left_divider = divider_op.repeat(left_divider_length); - let margin_length = (divider_length - left_divider_length * 2 - title.len()) / 2; - let margin = " ".repeat(margin_length); - println!(); - println!("{divider}"); - println!("{left_divider}{margin}{title}{margin}{left_divider}"); - println!("{divider}"); - println!(); -} diff --git a/crates/sui/src/lib.rs b/crates/sui/src/lib.rs deleted file mode 100644 index 14811233404..00000000000 --- a/crates/sui/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2021, Facebook, Inc. and its affiliates -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod client_commands; -#[macro_use] -pub mod client_ptb; -pub mod console; -pub mod fire_drill; -pub mod genesis_ceremony; -pub mod genesis_inspector; -pub mod key_identity; -pub mod keytool; -pub mod shell; -pub mod sui_commands; -pub mod validator_commands; -pub mod zklogin_commands_util; diff --git a/crates/sui/src/main.rs b/crates/sui/src/main.rs deleted file mode 100644 index 1c7091fc37d..00000000000 --- a/crates/sui/src/main.rs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use clap::*; -use colored::Colorize; -use sui::{ - client_commands::SuiClientCommands::{ProfileTransaction, ReplayTransaction}, - sui_commands::SuiCommand, -}; -use sui_types::exit_main; -use tracing::debug; - -const GIT_REVISION: &str = { - if let Some(revision) = option_env!("GIT_REVISION") { - revision - } else { - let version = git_version::git_version!( - args = ["--always", "--dirty", "--exclude", "*"], - fallback = "" - ); - version - } -}; - -const VERSION: &str = { - if GIT_REVISION.is_empty() { - env!("CARGO_PKG_VERSION") - } else { - const_str::concat!(env!("CARGO_PKG_VERSION"), "-", GIT_REVISION) - } -}; - -#[derive(Parser)] -#[clap( - name = env!("CARGO_BIN_NAME"), - about = "A Byzantine fault tolerant chain with low-latency finality and high throughput", - rename_all = "kebab-case", - author, - version = VERSION, - propagate_version = true, -)] -struct Args { - #[clap(subcommand)] - command: SuiCommand, -} - -#[tokio::main] -async fn main() { - #[cfg(windows)] - colored::control::set_virtual_terminal(true).unwrap(); - - let args = Args::parse(); - let _guard = match args.command { - SuiCommand::Console { .. } | SuiCommand::KeyTool { .. } | SuiCommand::Move { .. } => { - telemetry_subscribers::TelemetryConfig::new() - .with_log_level("error") - .with_env() - .init() - } - - SuiCommand::Client { - cmd: Some(ReplayTransaction { - gas_info, ptb_info, .. - }), - .. - } => { - let mut config = telemetry_subscribers::TelemetryConfig::new() - .with_log_level("info") - .with_env(); - if gas_info { - config = config.with_trace_target("replay_gas_info"); - } - if ptb_info { - config = config.with_trace_target("replay_ptb_info"); - } - config.init() - } - SuiCommand::Client { - cmd: Some(ProfileTransaction { .. }), - .. - } => { - // enable full logging for ProfileTransaction and ReplayTransaction - telemetry_subscribers::TelemetryConfig::new() - .with_env() - .init() - } - - _ => telemetry_subscribers::TelemetryConfig::new() - .with_log_level("error") - .with_env() - .init(), - }; - debug!("Sui CLI version: {VERSION}"); - exit_main!(args.command.execute().await); -} diff --git a/crates/sui/src/sui_commands.rs b/crates/sui/src/sui_commands.rs deleted file mode 100644 index 4611dd2ffc1..00000000000 --- a/crates/sui/src/sui_commands.rs +++ /dev/null @@ -1,675 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - fs, io, - io::{stderr, stdout, Write}, - num::NonZeroUsize, - path::{Path, PathBuf}, -}; - -use anyhow::{anyhow, bail}; -use clap::*; -use fastcrypto::traits::KeyPair; -use move_package::BuildConfig; -use rand::rngs::OsRng; -use sui_config::{ - node::Genesis, p2p::SeedPeer, sui_config_dir, Config, PersistedConfig, FULL_NODE_DB_PATH, - SUI_BENCHMARK_GENESIS_GAS_KEYSTORE_FILENAME, SUI_CLIENT_CONFIG, SUI_FULLNODE_CONFIG, - SUI_GENESIS_FILENAME, SUI_KEYSTORE_FILENAME, SUI_NETWORK_CONFIG, -}; -use sui_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; -use sui_move::{self, execute_move_command}; -use sui_move_build::SuiPackageHooks; -use sui_sdk::{ - sui_client_config::{SuiClientConfig, SuiEnv}, - wallet_context::WalletContext, -}; -use sui_swarm::memory::Swarm; -use sui_swarm_config::{ - genesis_config::{GenesisConfig, DEFAULT_NUMBER_OF_AUTHORITIES}, - network_config::NetworkConfig, - network_config_builder::ConfigBuilder, - node_config_builder::FullnodeConfigBuilder, -}; -use sui_types::crypto::{SignatureScheme, SuiKeyPair}; -use tracing::info; - -use crate::{ - client_commands::SuiClientCommands, - console::start_console, - fire_drill::{run_fire_drill, FireDrill}, - genesis_ceremony::{run, Ceremony}, - keytool::KeyToolCommand, - validator_commands::SuiValidatorCommand, -}; - -#[allow(clippy::large_enum_variant)] -#[derive(Parser)] -#[clap(rename_all = "kebab-case")] -pub enum SuiCommand { - /// Start sui network. - #[clap(name = "start")] - Start { - #[clap(long = "network.config")] - config: Option, - #[clap(long = "no-full-node")] - no_full_node: bool, - }, - #[clap(name = "network")] - Network { - #[clap(long = "network.config")] - config: Option, - #[clap(short, long, help = "Dump the public keys of all authorities")] - dump_addresses: bool, - }, - /// Bootstrap and initialize a new sui network - #[clap(name = "genesis")] - Genesis { - #[clap(long, help = "Start genesis with a given config file")] - from_config: Option, - #[clap( - long, - help = "Build a genesis config, write it to the specified path, and exit" - )] - write_config: Option, - #[clap(long)] - working_dir: Option, - #[clap(short, long, help = "Forces overwriting existing configuration")] - force: bool, - #[clap(long = "epoch-duration-ms")] - epoch_duration_ms: Option, - #[clap( - long, - value_name = "ADDR", - num_args(1..), - value_delimiter = ',', - help = "A list of ip addresses to generate a genesis suitable for benchmarks" - )] - benchmark_ips: Option>, - #[clap( - long, - help = "Creates an extra faucet configuration for sui-test-validator persisted runs." - )] - with_faucet: bool, - }, - GenesisCeremony(Ceremony), - /// Sui keystore tool. - #[clap(name = "keytool")] - KeyTool { - #[clap(long)] - keystore_path: Option, - /// Return command outputs in json format - #[clap(long, global = true)] - json: bool, - /// Subcommands. - #[clap(subcommand)] - cmd: KeyToolCommand, - }, - /// Start Sui interactive console. - #[clap(name = "console")] - Console { - /// Sets the file storing the state of our user accounts (an empty one - /// will be created if missing) - #[clap(long = "client.config")] - config: Option, - }, - /// Client for interacting with the Sui network. - #[clap(name = "client")] - Client { - /// Sets the file storing the state of our user accounts (an empty one - /// will be created if missing) - #[clap(long = "client.config")] - config: Option, - #[clap(subcommand)] - cmd: Option, - /// Return command outputs in json format. - #[clap(long, global = true)] - json: bool, - #[clap(short = 'y', long = "yes")] - accept_defaults: bool, - }, - /// A tool for validators and validator candidates. - #[clap(name = "validator")] - Validator { - /// Sets the file storing the state of our user accounts (an empty one - /// will be created if missing) - #[clap(long = "client.config")] - config: Option, - #[clap(subcommand)] - cmd: Option, - /// Return command outputs in json format. - #[clap(long, global = true)] - json: bool, - #[clap(short = 'y', long = "yes")] - accept_defaults: bool, - }, - - /// Tool to build and test Move applications. - #[clap(name = "move")] - Move { - /// Path to a package which the command should be run with respect to. - #[clap(long = "path", short = 'p', global = true)] - package_path: Option, - /// Package build options - #[clap(flatten)] - build_config: BuildConfig, - /// Subcommands. - #[clap(subcommand)] - cmd: sui_move::Command, - }, - - /// Tool for Fire Drill - FireDrill { - #[clap(subcommand)] - fire_drill: FireDrill, - }, -} - -impl SuiCommand { - pub async fn execute(self) -> Result<(), anyhow::Error> { - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); - match self { - SuiCommand::Start { - config, - no_full_node, - } => { - // Auto genesis if path is none and sui directory doesn't exists. - if config.is_none() && !sui_config_dir()?.join(SUI_NETWORK_CONFIG).exists() { - genesis(None, None, None, false, None, None, false).await?; - } - - // Load the config of the Sui authority. - let network_config_path = config - .clone() - .unwrap_or(sui_config_dir()?.join(SUI_NETWORK_CONFIG)); - let network_config: NetworkConfig = PersistedConfig::read(&network_config_path) - .map_err(|err| { - err.context(format!( - "Cannot open Sui network config file at {:?}", - network_config_path - )) - })?; - let mut swarm_builder = Swarm::builder() - .dir(sui_config_dir()?) - .with_network_config(network_config); - if no_full_node { - swarm_builder = swarm_builder.with_fullnode_count(0); - } else { - swarm_builder = swarm_builder - .with_fullnode_count(1) - .with_fullnode_rpc_addr(sui_config::node::default_json_rpc_address()); - } - let mut swarm = swarm_builder.build(); - swarm.launch().await?; - - let mut interval = tokio::time::interval(std::time::Duration::from_secs(3)); - let mut unhealthy_cnt = 0; - loop { - for node in swarm.validator_nodes() { - if let Err(err) = node.health_check(true).await { - unhealthy_cnt += 1; - if unhealthy_cnt > 3 { - // The network could temporarily go down during reconfiguration. - // If we detect a failed validator 3 times in a row, give up. - return Err(err.into()); - } - // Break the inner loop so that we could retry latter. - break; - } else { - unhealthy_cnt = 0; - } - } - - interval.tick().await; - } - } - SuiCommand::Network { - config, - dump_addresses, - } => { - let config_path = config.unwrap_or(sui_config_dir()?.join(SUI_NETWORK_CONFIG)); - let config: NetworkConfig = PersistedConfig::read(&config_path).map_err(|err| { - err.context(format!( - "Cannot open Sui network config file at {:?}", - config_path - )) - })?; - - if dump_addresses { - for validator in config.validator_configs() { - println!( - "{} - {}", - validator.network_address(), - validator.protocol_key_pair().public(), - ); - } - } - Ok(()) - } - SuiCommand::Genesis { - working_dir, - force, - from_config, - write_config, - epoch_duration_ms, - benchmark_ips, - with_faucet, - } => { - genesis( - from_config, - write_config, - working_dir, - force, - epoch_duration_ms, - benchmark_ips, - with_faucet, - ) - .await - } - SuiCommand::GenesisCeremony(cmd) => run(cmd), - SuiCommand::KeyTool { - keystore_path, - json, - cmd, - } => { - let keystore_path = - keystore_path.unwrap_or(sui_config_dir()?.join(SUI_KEYSTORE_FILENAME)); - let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path)?); - cmd.execute(&mut keystore).await?.print(!json); - Ok(()) - } - SuiCommand::Console { config } => { - let config = config.unwrap_or(sui_config_dir()?.join(SUI_CLIENT_CONFIG)); - prompt_if_no_config(&config, false).await?; - let context = WalletContext::new(&config, None, None)?; - start_console(context, &mut stdout(), &mut stderr()).await - } - SuiCommand::Client { - config, - cmd, - json, - accept_defaults, - } => { - let config_path = config.unwrap_or(sui_config_dir()?.join(SUI_CLIENT_CONFIG)); - prompt_if_no_config(&config_path, accept_defaults).await?; - let mut context = WalletContext::new(&config_path, None, None)?; - if let Some(cmd) = cmd { - cmd.execute(&mut context).await?.print(!json); - } else { - // Print help - let mut app: Command = SuiCommand::command(); - app.build(); - app.find_subcommand_mut("client").unwrap().print_help()?; - } - Ok(()) - } - SuiCommand::Validator { - config, - cmd, - json, - accept_defaults, - } => { - let config_path = config.unwrap_or(sui_config_dir()?.join(SUI_CLIENT_CONFIG)); - prompt_if_no_config(&config_path, accept_defaults).await?; - let mut context = WalletContext::new(&config_path, None, None)?; - if let Some(cmd) = cmd { - cmd.execute(&mut context).await?.print(!json); - } else { - // Print help - let mut app: Command = SuiCommand::command(); - app.build(); - app.find_subcommand_mut("validator").unwrap().print_help()?; - } - Ok(()) - } - SuiCommand::Move { - package_path, - build_config, - cmd, - } => execute_move_command(package_path, build_config, cmd), - SuiCommand::FireDrill { fire_drill } => run_fire_drill(fire_drill).await, - } - } -} - -async fn genesis( - from_config: Option, - write_config: Option, - working_dir: Option, - force: bool, - epoch_duration_ms: Option, - benchmark_ips: Option>, - with_faucet: bool, -) -> Result<(), anyhow::Error> { - let sui_config_dir = &match working_dir { - // if a directory is specified, it must exist (it - // will not be created) - Some(v) => v, - // create default Sui config dir if not specified - // on the command line and if it does not exist - // yet - None => { - let config_path = sui_config_dir()?; - fs::create_dir_all(&config_path)?; - config_path - } - }; - - // if Sui config dir is not empty then either clean it - // up (if --force/-f option was specified or report an - // error - let dir = sui_config_dir.read_dir().map_err(|err| { - anyhow!(err).context(format!("Cannot open Sui config dir {:?}", sui_config_dir)) - })?; - let files = dir.collect::, _>>()?; - - let client_path = sui_config_dir.join(SUI_CLIENT_CONFIG); - let keystore_path = sui_config_dir.join(SUI_KEYSTORE_FILENAME); - - if write_config.is_none() && !files.is_empty() { - if force { - // check old keystore and client.yaml is compatible - let is_compatible = FileBasedKeystore::new(&keystore_path).is_ok() - && PersistedConfig::::read(&client_path).is_ok(); - // Keep keystore and client.yaml if they are compatible - if is_compatible { - for file in files { - let path = file.path(); - if path != client_path && path != keystore_path { - if path.is_file() { - fs::remove_file(path) - } else { - fs::remove_dir_all(path) - } - .map_err(|err| { - anyhow!(err).context(format!("Cannot remove file {:?}", file.path())) - })?; - } - } - } else { - fs::remove_dir_all(sui_config_dir).map_err(|err| { - anyhow!(err) - .context(format!("Cannot remove Sui config dir {:?}", sui_config_dir)) - })?; - fs::create_dir(sui_config_dir).map_err(|err| { - anyhow!(err) - .context(format!("Cannot create Sui config dir {:?}", sui_config_dir)) - })?; - } - } else if files.len() != 2 || !client_path.exists() || !keystore_path.exists() { - bail!( - "Cannot run genesis with non-empty Sui config directory {}, please use the --force/-f option to remove the existing configuration", - sui_config_dir.to_str().unwrap() - ); - } - } - - let network_path = sui_config_dir.join(SUI_NETWORK_CONFIG); - let genesis_path = sui_config_dir.join(SUI_GENESIS_FILENAME); - - let mut genesis_conf = match from_config { - Some(path) => PersistedConfig::read(&path)?, - None => { - if let Some(ips) = benchmark_ips { - // Make a keystore containing the key for the genesis gas object. - let path = sui_config_dir.join(SUI_BENCHMARK_GENESIS_GAS_KEYSTORE_FILENAME); - let mut keystore = FileBasedKeystore::new(&path)?; - for gas_key in GenesisConfig::benchmark_gas_keys(ips.len()) { - keystore.add_key(None, gas_key)?; - } - keystore.save()?; - - // Make a new genesis config from the provided ip addresses. - GenesisConfig::new_for_benchmarks(&ips) - } else if keystore_path.exists() { - let existing_keys = FileBasedKeystore::new(&keystore_path)?.addresses(); - GenesisConfig::for_local_testing_with_addresses(existing_keys) - } else { - GenesisConfig::for_local_testing() - } - } - }; - - // Adds an extra faucet account to the genesis - if with_faucet { - info!("Adding faucet account in genesis config..."); - genesis_conf = genesis_conf.add_faucet_account(); - } - - if let Some(path) = write_config { - let persisted = genesis_conf.persisted(&path); - persisted.save()?; - return Ok(()); - } - - let validator_info = genesis_conf.validator_config_info.take(); - let ssfn_info = genesis_conf.ssfn_config_info.take(); - - let builder = ConfigBuilder::new(sui_config_dir); - if let Some(epoch_duration_ms) = epoch_duration_ms { - genesis_conf.parameters.epoch_duration_ms = epoch_duration_ms; - } - let mut network_config = if let Some(validators) = validator_info { - builder - .with_genesis_config(genesis_conf) - .with_validators(validators) - .build() - } else { - builder - .committee_size(NonZeroUsize::new(DEFAULT_NUMBER_OF_AUTHORITIES).unwrap()) - .with_genesis_config(genesis_conf) - .build() - }; - - let mut keystore = FileBasedKeystore::new(&keystore_path)?; - for key in &network_config.account_keys { - keystore.add_key(None, SuiKeyPair::Ed25519(key.copy()))?; - } - let active_address = keystore.addresses().pop(); - - network_config.genesis.save(&genesis_path)?; - for validator in &mut network_config.validator_configs { - validator.genesis = sui_config::node::Genesis::new_from_file(&genesis_path); - } - - info!("Network genesis completed."); - network_config.save(&network_path)?; - info!("Network config file is stored in {:?}.", network_path); - - info!("Client keystore is stored in {:?}.", keystore_path); - - let fullnode_config = FullnodeConfigBuilder::new() - .with_config_directory(FULL_NODE_DB_PATH.into()) - .with_rpc_addr(sui_config::node::default_json_rpc_address()) - .build(&mut OsRng, &network_config); - - fullnode_config.save(sui_config_dir.join(SUI_FULLNODE_CONFIG))?; - let mut ssfn_nodes = vec![]; - if let Some(ssfn_info) = ssfn_info { - for (i, ssfn) in ssfn_info.into_iter().enumerate() { - let path = - sui_config_dir.join(sui_config::ssfn_config_file(ssfn.p2p_address.clone(), i)); - // join base fullnode config with each SsfnGenesisConfig entry - let ssfn_config = FullnodeConfigBuilder::new() - .with_config_directory(FULL_NODE_DB_PATH.into()) - .with_p2p_external_address(ssfn.p2p_address) - .with_network_key_pair(ssfn.network_key_pair) - .with_p2p_listen_address("0.0.0.0:8084".parse().unwrap()) - .with_db_path(PathBuf::from("/opt/sui/db/authorities_db/full_node_db")) - .with_network_address("/ip4/0.0.0.0/tcp/8080/http".parse().unwrap()) - .with_metrics_address("0.0.0.0:9184".parse().unwrap()) - .with_admin_interface_port(1337) - .with_json_rpc_address("0.0.0.0:9000".parse().unwrap()) - .with_genesis(Genesis::new_from_file("/opt/sui/config/genesis.blob")) - .build(&mut OsRng, &network_config); - ssfn_nodes.push(ssfn_config.clone()); - ssfn_config.save(path)?; - } - - let ssfn_seed_peers: Vec = ssfn_nodes - .iter() - .map(|config| SeedPeer { - peer_id: Some(anemo::PeerId( - config.network_key_pair().public().0.to_bytes(), - )), - address: config.p2p_config.external_address.clone().unwrap(), - }) - .collect(); - - for (i, mut validator) in network_config - .into_validator_configs() - .into_iter() - .enumerate() - { - let path = sui_config_dir.join(sui_config::validator_config_file( - validator.network_address.clone(), - i, - )); - let mut val_p2p = validator.p2p_config.clone(); - val_p2p.seed_peers = ssfn_seed_peers.clone(); - validator.p2p_config = val_p2p; - validator.save(path)?; - } - } else { - for (i, validator) in network_config - .into_validator_configs() - .into_iter() - .enumerate() - { - let path = sui_config_dir.join(sui_config::validator_config_file( - validator.network_address.clone(), - i, - )); - validator.save(path)?; - } - } - - let mut client_config = if client_path.exists() { - PersistedConfig::read(&client_path)? - } else { - SuiClientConfig::new(keystore.into()) - }; - - if client_config.active_address.is_none() { - client_config.active_address = active_address; - } - client_config.add_env(SuiEnv { - alias: "localnet".to_string(), - rpc: format!("http://{}", fullnode_config.json_rpc_address), - ws: None, - }); - client_config.add_env(SuiEnv::devnet()); - - if client_config.active_env.is_none() { - client_config.active_env = client_config.envs.first().map(|env| env.alias.clone()); - } - - client_config.save(&client_path)?; - info!("Client config file is stored in {:?}.", client_path); - - Ok(()) -} - -async fn prompt_if_no_config( - wallet_conf_path: &Path, - accept_defaults: bool, -) -> Result<(), anyhow::Error> { - // Prompt user for connect to devnet fullnode if config does not exist. - if !wallet_conf_path.exists() { - let env = match std::env::var_os("SUI_CONFIG_WITH_RPC_URL") { - Some(v) => Some(SuiEnv { - alias: "custom".to_string(), - rpc: v.into_string().unwrap(), - ws: None, - }), - None => { - if accept_defaults { - print!( - "Creating config file [{:?}] with default (devnet) Full node server and ed25519 key scheme.", - wallet_conf_path - ); - } else { - print!( - "Config file [{:?}] doesn't exist, do you want to connect to a Sui Full node server [y/N]?", - wallet_conf_path - ); - } - if accept_defaults - || matches!(read_line(), Ok(line) if line.trim().to_lowercase() == "y") - { - let url = if accept_defaults { - String::new() - } else { - print!( - "Sui Full node server URL (Defaults to Sui Devnet if not specified) : " - ); - read_line()? - }; - Some(if url.trim().is_empty() { - SuiEnv::devnet() - } else { - print!("Environment alias for [{url}] : "); - let alias = read_line()?; - let alias = if alias.trim().is_empty() { - "custom".to_string() - } else { - alias - }; - SuiEnv { - alias, - rpc: url, - ws: None, - } - }) - } else { - None - } - } - }; - - if let Some(env) = env { - let keystore_path = wallet_conf_path - .parent() - .unwrap_or(&sui_config_dir()?) - .join(SUI_KEYSTORE_FILENAME); - let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path)?); - let key_scheme = if accept_defaults { - SignatureScheme::ED25519 - } else { - println!( - "Select key scheme to generate keypair (0 for ed25519, 1 for secp256k1, 2: for secp256r1):" - ); - match SignatureScheme::from_flag(read_line()?.trim()) { - Ok(s) => s, - Err(e) => return Err(anyhow!("{e}")), - } - }; - let (new_address, phrase, scheme) = - keystore.generate_and_add_new_key(key_scheme, None, None, None)?; - let alias = keystore.get_alias_by_address(&new_address)?; - println!( - "Generated new keypair and alias for address with scheme {:?} [{alias}: {new_address}]", - scheme.to_string() - ); - println!("Secret Recovery Phrase : [{phrase}]"); - let alias = env.alias.clone(); - SuiClientConfig { - keystore, - envs: vec![env], - active_address: Some(new_address), - active_env: Some(alias), - } - .persisted(wallet_conf_path) - .save()?; - } - } - Ok(()) -} - -fn read_line() -> Result { - let mut s = String::new(); - let _ = stdout().flush(); - io::stdin().read_line(&mut s)?; - Ok(s.trim_end().to_string()) -} diff --git a/crates/sui/src/unit_tests/validator_tests.rs b/crates/sui/src/unit_tests/validator_tests.rs deleted file mode 100644 index 2dd80d2315f..00000000000 --- a/crates/sui/src/unit_tests/validator_tests.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use anyhow::Ok; -use fastcrypto::encoding::{Base64, Encoding}; -use shared_crypto::intent::{Intent, IntentMessage}; -use sui_types::{ - base_types::SuiAddress, - crypto::{Signature, SuiKeyPair}, - transaction::{Transaction, TransactionData}, -}; -use test_cluster::TestClusterBuilder; - -use crate::validator_commands::{ - get_validator_summary, SuiValidatorCommand, SuiValidatorCommandResponse, -}; - -#[tokio::test] -async fn test_print_raw_rgp_txn() -> Result<(), anyhow::Error> { - let test_cluster = TestClusterBuilder::new().build().await; - let keypair: &SuiKeyPair = test_cluster - .swarm - .config() - .validator_configs - .first() - .unwrap() - .account_key_pair - .keypair(); - let validator_address: SuiAddress = SuiAddress::from(&keypair.public()); - let mut context = test_cluster.wallet; - let sui_client = context.get_client().await?; - let (_, summary) = get_validator_summary(&sui_client, validator_address) - .await? - .unwrap(); - let operation_cap_id = summary.operation_cap_id; - - // Execute the command and get the serialized transaction data. - let response = SuiValidatorCommand::DisplayGasPriceUpdateRawTxn { - sender_address: validator_address, - new_gas_price: 42, - operation_cap_id, - gas_budget: None, - } - .execute(&mut context) - .await?; - let SuiValidatorCommandResponse::DisplayGasPriceUpdateRawTxn { - data, - serialized_data, - } = response - else { - panic!("Expected DisplayGasPriceUpdateRawTxn"); - }; - - // Construct the signed transaction and execute it. - let deserialized_data = - bcs::from_bytes::(&Base64::decode(&serialized_data).unwrap())?; - let signature = Signature::new_secure( - &IntentMessage::new(Intent::sui_transaction(), deserialized_data), - keypair, - ); - let txn = Transaction::from_data(data, vec![signature]); - context.execute_transaction_must_succeed(txn).await; - let (_, summary) = get_validator_summary(&sui_client, validator_address) - .await? - .unwrap(); - - // Check that the gas price is updated correctly. - assert_eq!(summary.next_epoch_gas_price, 42); - Ok(()) -} diff --git a/crates/sui/tests/data/dummy_modules_publish/Move.toml b/crates/sui/tests/data/dummy_modules_publish/Move.toml deleted file mode 100644 index 1a80243f9c9..00000000000 --- a/crates/sui/tests/data/dummy_modules_publish/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "Examples" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../sui-framework/packages/sui-framework" } - -[addresses] -examples = "0x0" diff --git a/crates/sui/tests/data/dummy_modules_publish/sources/trusted_coin.move b/crates/sui/tests/data/dummy_modules_publish/sources/trusted_coin.move deleted file mode 100644 index 840e81911a1..00000000000 --- a/crates/sui/tests/data/dummy_modules_publish/sources/trusted_coin.move +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Example coin with a trusted owner responsible for minting/burning (e.g., a stablecoin) -module examples::trusted_coin { - use std::option; - use sui::coin::{Self, TreasuryCap}; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; - - /// Name of the coin - struct TRUSTED_COIN has drop {} - - /// Register the trusted currency to acquire its `TreasuryCap`. Because - /// this is a module initializer, it ensures the currency only gets - /// registered once. - fun init(witness: TRUSTED_COIN, ctx: &mut TxContext) { - // Get a treasury cap for the coin and give it to the transaction - // sender - let (treasury_cap, metadata) = coin::create_currency(witness, 2, b"TRUSTED", b"", b"", option::none(), ctx); - transfer::public_freeze_object(metadata); - transfer::public_transfer(treasury_cap, tx_context::sender(ctx)) - } - - public entry fun mint(treasury_cap: &mut TreasuryCap, amount: u64, ctx: &mut TxContext) { - let coin = coin::mint(treasury_cap, amount, ctx); - transfer::public_transfer(coin, tx_context::sender(ctx)); - } - - public entry fun transfer(treasury_cap: TreasuryCap, recipient: address) { - transfer::public_transfer(treasury_cap, recipient); - } - - #[test_only] - /// Wrapper of module initializer for testing - public fun test_init(ctx: &mut TxContext) { - init(TRUSTED_COIN {}, ctx) - } -} diff --git a/crates/sui/tests/data/dummy_modules_upgrade/sources/trusted_coin.move b/crates/sui/tests/data/dummy_modules_upgrade/sources/trusted_coin.move deleted file mode 100644 index 9501b9f5928..00000000000 --- a/crates/sui/tests/data/dummy_modules_upgrade/sources/trusted_coin.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module examples::trusted_coin { - public fun f() { } -} diff --git a/crates/sui/tests/data/linter/Move.toml b/crates/sui/tests/data/linter/Move.toml deleted file mode 100644 index a771bd82968..00000000000 --- a/crates/sui/tests/data/linter/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "linter" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../sui-framework/packages/sui-framework" } - -[addresses] -linter = "0x0" diff --git a/crates/sui/tests/data/module_dependency_invalid/sources/invalid.move b/crates/sui/tests/data/module_dependency_invalid/sources/invalid.move deleted file mode 100644 index 521ce00981e..00000000000 --- a/crates/sui/tests/data/module_dependency_invalid/sources/invalid.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module invalid::invalid { - public entry fun main() {} -} diff --git a/crates/sui/tests/data/module_dependency_nonexistent/sources/nonexistent.move b/crates/sui/tests/data/module_dependency_nonexistent/sources/nonexistent.move deleted file mode 100644 index d01eb571334..00000000000 --- a/crates/sui/tests/data/module_dependency_nonexistent/sources/nonexistent.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module nonexistent::nonexistent { - public entry fun main() {} -} diff --git a/crates/sui/tests/data/module_dependency_unpublished/sources/invalid.move b/crates/sui/tests/data/module_dependency_unpublished/sources/invalid.move deleted file mode 100644 index 521ce00981e..00000000000 --- a/crates/sui/tests/data/module_dependency_unpublished/sources/invalid.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module invalid::invalid { - public entry fun main() {} -} diff --git a/crates/sui/tests/data/module_dependency_unpublished_non_zero_address/sources/non_zero.move b/crates/sui/tests/data/module_dependency_unpublished_non_zero_address/sources/non_zero.move deleted file mode 100644 index 061abd71738..00000000000 --- a/crates/sui/tests/data/module_dependency_unpublished_non_zero_address/sources/non_zero.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module non_zero::non_zero { - public entry fun main() {} -} diff --git a/crates/sui/tests/data/module_publish_failure_invalid/Move.toml b/crates/sui/tests/data/module_publish_failure_invalid/Move.toml deleted file mode 100644 index a24db20d1ca..00000000000 --- a/crates/sui/tests/data/module_publish_failure_invalid/Move.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "Examples" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../sui-framework/packages/sui-framework" } -Invalid = { local = "../module_dependency_invalid" } -Unpublished = { local = "../module_dependency_unpublished" } - -[addresses] -examples = "0x0" diff --git a/crates/sui/tests/data/module_publish_failure_invalid/sources/main.move b/crates/sui/tests/data/module_publish_failure_invalid/sources/main.move deleted file mode 100644 index 9b1b50ea005..00000000000 --- a/crates/sui/tests/data/module_publish_failure_invalid/sources/main.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module examples::main { - public entry fun main() {} -} diff --git a/crates/sui/tests/data/module_publish_with_nonexistent_dependency/Move.toml b/crates/sui/tests/data/module_publish_with_nonexistent_dependency/Move.toml deleted file mode 100644 index 7e1b103e514..00000000000 --- a/crates/sui/tests/data/module_publish_with_nonexistent_dependency/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "Examples" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../sui-framework/packages/sui-framework" } -Nonexistent = { local = "../module_dependency_nonexistent" } - -[addresses] -examples = "0x0" diff --git a/crates/sui/tests/data/module_publish_with_nonexistent_dependency/sources/main.move b/crates/sui/tests/data/module_publish_with_nonexistent_dependency/sources/main.move deleted file mode 100644 index 9b1b50ea005..00000000000 --- a/crates/sui/tests/data/module_publish_with_nonexistent_dependency/sources/main.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module examples::main { - public entry fun main() {} -} diff --git a/crates/sui/tests/data/module_publish_with_unpublished_dependency/Move.toml b/crates/sui/tests/data/module_publish_with_unpublished_dependency/Move.toml deleted file mode 100644 index 9b849aed666..00000000000 --- a/crates/sui/tests/data/module_publish_with_unpublished_dependency/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "Examples" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../sui-framework/packages/sui-framework" } -Unpublished = { local = "../module_dependency_unpublished" } - -[addresses] -examples = "0x0" diff --git a/crates/sui/tests/data/module_publish_with_unpublished_dependency/sources/main.move b/crates/sui/tests/data/module_publish_with_unpublished_dependency/sources/main.move deleted file mode 100644 index 9b1b50ea005..00000000000 --- a/crates/sui/tests/data/module_publish_with_unpublished_dependency/sources/main.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module examples::main { - public entry fun main() {} -} diff --git a/crates/sui/tests/data/module_publish_with_unpublished_dependency_with_non_zero_address/Move.toml b/crates/sui/tests/data/module_publish_with_unpublished_dependency_with_non_zero_address/Move.toml deleted file mode 100644 index dcae7c0cdef..00000000000 --- a/crates/sui/tests/data/module_publish_with_unpublished_dependency_with_non_zero_address/Move.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "Examples" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../sui-framework/packages/sui-framework" } -UnpublishedNonZeroAddress = { local = "../module_dependency_unpublished_non_zero_address" } - -[addresses] -examples = "0x0" diff --git a/crates/sui/tests/data/module_publish_with_unpublished_dependency_with_non_zero_address/sources/main.move b/crates/sui/tests/data/module_publish_with_unpublished_dependency_with_non_zero_address/sources/main.move deleted file mode 100644 index 9b1b50ea005..00000000000 --- a/crates/sui/tests/data/module_publish_with_unpublished_dependency_with_non_zero_address/sources/main.move +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module examples::main { - public entry fun main() {} -} diff --git a/crates/sui/tests/data/move_call_args_linter/Move.toml b/crates/sui/tests/data/move_call_args_linter/Move.toml deleted file mode 100644 index 1a80243f9c9..00000000000 --- a/crates/sui/tests/data/move_call_args_linter/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "Examples" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../sui-framework/packages/sui-framework" } - -[addresses] -examples = "0x0" diff --git a/crates/sui/tests/data/move_call_args_linter/sources/object_basics.move b/crates/sui/tests/data/move_call_args_linter/sources/object_basics.move deleted file mode 100644 index e2f4502eb24..00000000000 --- a/crates/sui/tests/data/move_call_args_linter/sources/object_basics.move +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -/// Test CTURD object basics (create, transfer, update, read, delete) -module examples::object_basics { - use sui::event; - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer; - - struct Object has key, store { - id: UID, - value: u64, - } - - struct Wrapper has key { - id: UID, - o: Object - } - - struct NewValueEvent has copy, drop { - new_value: u64 - } - - public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) { - transfer::public_transfer( - Object { id: object::new(ctx), value }, - recipient - ) - } - - public entry fun transfer(o: Object, recipient: address) { - transfer::public_transfer(o, recipient) - } - - public entry fun freeze_object(o: Object) { - transfer::public_freeze_object(o) - } - - public entry fun set_value(o: &mut Object, value: u64) { - o.value = value; - } - - // test that reading o2 and updating o1 works - public entry fun update(o1: &mut Object, o2: &Object) { - o1.value = o2.value; - // emit an event so the world can see the new value - event::emit(NewValueEvent { new_value: o2.value }) - } - - public entry fun delete(o: Object) { - let Object { id, value: _ } = o; - object::delete(id); - } - - public entry fun wrap(o: Object, ctx: &mut TxContext) { - transfer::transfer(Wrapper { id: object::new(ctx), o }, tx_context::sender(ctx)) - } - - public entry fun unwrap(w: Wrapper, ctx: &mut TxContext) { - let Wrapper { id, o } = w; - object::delete(id); - transfer::public_transfer(o, tx_context::sender(ctx)) - } -} diff --git a/crates/sui/tests/data/ptb_complex_args_test_functions/Move.toml b/crates/sui/tests/data/ptb_complex_args_test_functions/Move.toml deleted file mode 100644 index 69c7f593c1c..00000000000 --- a/crates/sui/tests/data/ptb_complex_args_test_functions/Move.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "test_functions" - -[dependencies] -Sui = { local = "../../../../sui-framework/packages/sui-framework" } - -[addresses] -test_functions = "0x0" diff --git a/crates/sui/tests/data/ptb_complex_args_test_functions/sources/test_module.move b/crates/sui/tests/data/ptb_complex_args_test_functions/sources/test_module.move deleted file mode 100644 index f2fab4f42c6..00000000000 --- a/crates/sui/tests/data/ptb_complex_args_test_functions/sources/test_module.move +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module test_functions::test_module { - use sui::object::{Self, UID}; - use sui::tx_context::TxContext; - use sui::transfer; - use std::ascii::String as AS; - use std::string::String as US; - - struct Shared has key, store { - id: UID, - } - - public fun new_shared(ctx: &mut TxContext) { - transfer::share_object(Shared { id: object::new(ctx) }) - } - - public fun use_immut(_: &Shared) { - // do nothing - } - - public fun use_mut(_: &mut Shared) { - // do nothing - } - - public fun use_ascii_string(_: AS) { - // do nothing - } - - public fun use_utf8_string(_: US) { - // do nothing - } - - public fun delete_shared_object(shared: Shared) { - let Shared { id } = shared; - object::delete(id); - } -} diff --git a/crates/sui/tests/data/sod/Move.toml b/crates/sui/tests/data/sod/Move.toml deleted file mode 100644 index ccc7146c868..00000000000 --- a/crates/sui/tests/data/sod/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "sod" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../sui-framework/packages/sui-framework" } - -[addresses] -sod = "0x0" diff --git a/crates/sui/tests/data/sod/sources/sod.move b/crates/sui/tests/data/sod/sources/sod.move deleted file mode 100644 index 097f2d4fb85..00000000000 --- a/crates/sui/tests/data/sod/sources/sod.move +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sod::sod { - use sui::object::{Self, UID}; - use sui::tx_context::TxContext; - use sui::transfer; - - struct A has key, store { - id: UID, - } - - public fun start(ctx: &mut TxContext) { - let a = A { id: object::new(ctx) }; - transfer::public_share_object(a); - } - - public entry fun delete(a: A) { - let A { id } = a; - object::delete(id); - } -} diff --git a/crates/sui/tests/data/tto/Move.toml b/crates/sui/tests/data/tto/Move.toml deleted file mode 100644 index 310a863195d..00000000000 --- a/crates/sui/tests/data/tto/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "tto" -version = "0.0.1" - -[dependencies] -Sui = { local = "../../../../sui-framework/packages/sui-framework" } - -[addresses] -tto = "0x0" diff --git a/crates/sui/tests/data/tto/sources/tto1.move b/crates/sui/tests/data/tto/sources/tto1.move deleted file mode 100644 index 1c4e9951a63..00000000000 --- a/crates/sui/tests/data/tto/sources/tto1.move +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module tto::tto { - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; - use sui::transfer::{Self, Receiving}; - - struct A has key, store { - id: UID, - } - - struct B has key, store { - id: UID, - } - - public fun start(ctx: &mut TxContext) { - let a = A { id: object::new(ctx) }; - let a_address = object::id_address(&a); - let b = B { id: object::new(ctx) }; - transfer::public_transfer(a, tx_context::sender(ctx)); - transfer::public_transfer(b, a_address); - } - - public entry fun receiver(parent: &mut A, x: Receiving) { - let b = transfer::receive(&mut parent.id, x); - transfer::public_transfer(b, @tto); - } - - public fun invalid_call_immut_ref(_parent: &mut A, _x: &Receiving) { } - public fun invalid_call_mut_ref(_parent: &mut A, _x: &mut Receiving) { } -} diff --git a/crates/sui/tests/ptb_files/parsing/whitespace_handling.ptb b/crates/sui/tests/ptb_files/parsing/whitespace_handling.ptb deleted file mode 100644 index 4357e8c0248..00000000000 --- a/crates/sui/tests/ptb_files/parsing/whitespace_handling.ptb +++ /dev/null @@ -1,17 +0,0 @@ -# Note: Yes, it looks messed up -- it should so don't try and format this nicely! - -# Make sure we handle weird spacing inside vectors and arrays ---assign x vector[1, 2, 3,4 ] ---assign x "vector[1, 2, 3,4 ]" ---assign x "vector['1', '2, 3','',\"4 \"]" ---assign x "vector['1', '2, 3','',\"4 - \"]" - -# Same tests but with arrays ---make-move-vec [1, 2, 3,4 ] ---make-move-vec "[1, 2, 3,4 ]" ---make-move-vec "['1', '2, 3','',\"4 \"]" ---make-move-vec "['1', '2, 3','',\"4 - \"]" - ---gas-budget 100 diff --git a/crates/sui/tests/ptb_files/publish/test_pkg/sources/a.move b/crates/sui/tests/ptb_files/publish/test_pkg/sources/a.move deleted file mode 100644 index 5b0dff62030..00000000000 --- a/crates/sui/tests/ptb_files/publish/test_pkg/sources/a.move +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module test_pkg::a { } diff --git a/crates/sui/tests/ptb_files/split_coins/split_coins_valid.ptb b/crates/sui/tests/ptb_files/split_coins/split_coins_valid.ptb deleted file mode 100644 index aed6dd83666..00000000000 --- a/crates/sui/tests/ptb_files/split_coins/split_coins_valid.ptb +++ /dev/null @@ -1,12 +0,0 @@ -# Split off from gas ---split-coins gas [0,1,2,3] ---assign coins ---move-call sui::coin::destroy_zero coins.0 -# Can further split a split coin (and through variable bindings/result accesses) ---split-coins coins.1 [0,0] ---assign zcoins ---move-call sui::coin::destroy_zero zcoins.0 ---move-call sui::coin::destroy_zero zcoins.1 -# Can merge the split coins back ---merge-coins gas [coins.1, coins.2, coins.3] ---gas-budget 10000000 diff --git a/crates/suins-indexer/Cargo.toml b/crates/suins-indexer/Cargo.toml deleted file mode 100644 index 8b26edc19b5..00000000000 --- a/crates/suins-indexer/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -name = "suins-indexer" -authors = ["Mysten Labs "] -license = "Apache-2.0" -publish = false -edition = "2021" -version = "0.1.0" - -[dependencies] -diesel = { version = "2.1.4", features = ["postgres", "r2d2", "serde_json"] } -sui-data-ingestion-core.workspace = true -anyhow.workspace = true -async-trait.workspace = true -backoff.workspace = true -base64-url.workspace = true -bcs.workspace = true -bytes.workspace = true -futures.workspace = true -mysten-metrics.workspace = true -notify.workspace = true -object_store.workspace = true -serde.workspace = true -serde_json.workspace = true -serde_yaml.workspace = true -prometheus.workspace = true -telemetry-subscribers.workspace = true -tokio = { workspace = true, features = ["full"] } -tracing.workspace = true -sui-storage.workspace = true -sui-types.workspace = true -url.workspace = true -sui-json-rpc.workspace = true -dotenvy = "0.15" -move-core-types.workspace = true - -[dev-dependencies] -rand.workspace = true -tempfile.workspace = true -sui-types = { workspace = true, features = ["test-utils"] } diff --git a/crates/suins-indexer/src/indexer.rs b/crates/suins-indexer/src/indexer.rs deleted file mode 100644 index dc205276a23..00000000000 --- a/crates/suins-indexer/src/indexer.rs +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - collections::{HashMap, HashSet}, - str::FromStr, -}; - -use move_core_types::language_storage::StructTag; -use sui_json_rpc::name_service::{Domain, NameRecord, SubDomainRegistration}; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, - dynamic_field::Field, - full_checkpoint_content::{CheckpointData, CheckpointTransaction}, - object::Object, -}; - -use crate::models::VerifiedDomain; - -const REGISTRY_TABLE_ID: &str = - "0xe64cd9db9f829c6cc405d9790bd71567ae07259855f4fba6f02c84f52298c106"; -/// TODO(manos): Hardcode mainnet once we publish the subdomains package. -const SUBDOMAIN_REGISTRATION_TYPE: &str = - "0xPackageIdTBD::subdomain_registration::SubDomainRegistration"; - -#[derive(Debug, Clone)] -pub struct NameRecordChange(Field); - -pub struct SuinsIndexer { - registry_table_id: SuiAddress, - subdomain_wrapper_type: StructTag, -} - -impl std::default::Default for SuinsIndexer { - fn default() -> Self { - Self::new( - REGISTRY_TABLE_ID.to_owned(), - SUBDOMAIN_REGISTRATION_TYPE.to_owned(), - ) - } -} - -impl SuinsIndexer { - /// Create a new config by passing the table ID + subdomain wrapper type. - /// Useful for testing or custom environments. - pub fn new(registry_address: String, wrapper_type: String) -> Self { - let registry_table_id = SuiAddress::from_str(®istry_address).unwrap(); - let subdomain_wrapper_type = StructTag::from_str(&wrapper_type).unwrap(); - - Self { - registry_table_id, - subdomain_wrapper_type, - } - } - - /// Checks if the object referenced is a subdomain wrapper. - /// For subdomain wrappers, we're saving the ID of the wrapper object, - /// to make it easy to locate the NFT (since the base NFT gets wrapped and - /// indexing won't work there). - pub fn is_subdomain_wrapper(&self, object: &Object) -> bool { - object - .struct_tag() - .is_some_and(|tag| tag == self.subdomain_wrapper_type) - } - - // Filter by owner. - // Owner has to be the TABLE of the registry. - // A table of that type can only have `Field as a child so - // that check is enough to make sure we're dealing with a registry change. - pub fn is_name_record(&self, object: &Object) -> bool { - object - .get_single_owner() - .is_some_and(|owner| owner == self.registry_table_id) - } - - /// Processes a checkpoint and produces a list of `updates` and a list of - /// `removals` - /// - /// We can then use these to execute our DB bulk insertions + bulk - /// deletions. - /// - /// Returns - /// - `Vec`: A list of NameRecord updates for the database - /// (including sequence number) - /// - `Vec`: A list of IDs to be deleted from the database - /// (`field_id` is the matching column) - pub fn process_checkpoint(&self, data: &CheckpointData) -> (Vec, Vec) { - let mut checkpoint = SuinsIndexerCheckpoint::new(data.checkpoint_summary.sequence_number); - - // loop through all the transactions in the checkpoint - // Since the transactions are sequenced inside the checkpoint, we can safely - // assume that we have the latest data for each name record in the end - // of the loop. - for transaction in &data.transactions { - // Add all name record changes to the name_records HashMap. - // Remove any removals that got re-created. - checkpoint.parse_record_changes(self, &transaction.output_objects); - - // Gather all removals from the transaction, - // and delete any name records from the name_records if it got deleted. - checkpoint.parse_record_deletions(self, transaction); - } - - ( - // Convert our name_records & wrappers into a list of updates for the DB. - checkpoint.prepare_db_updates(), - checkpoint - .removals - .into_iter() - .map(|id| id.to_string()) - .collect(), - ) - } -} - -pub struct SuinsIndexerCheckpoint { - /// A list of name records that have been updated in the checkpoint. - name_records: HashMap, - /// A list of subdomain wrappers that have been created in the checkpoint. - subdomain_wrappers: HashMap, - /// A list of name records that have been deleted in the checkpoint. - removals: HashSet, - /// The sequence number of the checkpoint. - checkpoint_sequence_number: u64, -} - -impl SuinsIndexerCheckpoint { - pub fn new(checkpoint_sequence_number: u64) -> Self { - Self { - name_records: HashMap::new(), - subdomain_wrappers: HashMap::new(), - removals: HashSet::new(), - checkpoint_sequence_number, - } - } - - /// Parses the name record changes + subdomain wraps. - /// and pushes them into the supplied vector + hashmap. - /// - /// It is implemented in a way to do just a single iteration over the - /// objects. - pub fn parse_record_changes(&mut self, config: &SuinsIndexer, objects: &[Object]) { - for object in objects { - // Parse all the changes to a `NameRecord` - if config.is_name_record(object) { - let name_record: Field = object - .to_rust() - .unwrap_or_else(|| panic!("Failed to parse name record for {:?}", object)); - - let id = object.id(); - - // Remove from the removals list if it's there. - // The reason it might have been there is that the same name record might have - // been deleted in a previous transaction in the same - // checkpoint, and now it got re-created. - self.removals.remove(&id); - - self.name_records.insert(id, NameRecordChange(name_record)); - } - // Parse subdomain wrappers and save them in our hashmap. - // Later, we'll save the id of the wrapper in the name record. - // NameRecords & their equivalent SubdomainWrappers are always created in the - // same PTB, so we can safely assume that the wrapper will be - // created on the same checkpoint as the name record and vice versa. - if config.is_subdomain_wrapper(object) { - let sub_domain: SubDomainRegistration = object.to_rust().unwrap(); - self.subdomain_wrappers.insert( - sub_domain.nft.domain_name, - sub_domain.id.id.bytes.to_string(), - ); - }; - } - } - - /// Parses a list of the deletions in the checkpoint and adds them to the - /// removals list. Also removes any name records from the updates, if - /// they ended up being deleted in the same checkpoint. - pub fn parse_record_deletions( - &mut self, - config: &SuinsIndexer, - transaction: &CheckpointTransaction, - ) { - // a list of all the deleted objects in the transaction. - let deleted_objects: HashSet<_> = transaction - .effects - .all_tombstones() - .into_iter() - .map(|(id, _)| id) - .collect(); - - for input in transaction.input_objects.iter() { - if config.is_name_record(input) && deleted_objects.contains(&input.id()) { - // since this record was deleted, we need to remove it from the name_records - // hashmap. that catches a case where a name record was edited - // on a previous transaction in the checkpoint and deleted from - // a different tx later in the checkpoint. - self.name_records.remove(&input.id()); - - // add it in the list of removals - self.removals.insert(input.id()); - } - } - } - - /// Prepares a vector of `VerifiedDomain`s to be inserted into the DB, - /// taking in account the list of subdomain wrappers created as well as - /// the checkpoint's sequence number. - pub fn prepare_db_updates(&self) -> Vec { - let mut updates: Vec = vec![]; - - for (field_id, name_record_change) in self.name_records.iter() { - let name_record = &name_record_change.0; - - let parent = name_record.name.parent().to_string(); - let nft_id = name_record.value.nft_id.bytes.to_string(); - - updates.push(VerifiedDomain { - field_id: field_id.to_string(), - name: name_record.name.to_string(), - parent, - expiration_timestamp_ms: name_record.value.expiration_timestamp_ms as i64, - nft_id, - target_address: if name_record.value.target_address.is_some() { - Some(SuiAddress::to_string( - &name_record.value.target_address.unwrap(), - )) - } else { - None - }, - // unwrapping must be safe as `value.data` is an on-chain value with - // VecMap type. - data: serde_json::to_value(&name_record.value.data).unwrap(), - last_checkpoint_updated: self.checkpoint_sequence_number as i64, - subdomain_wrapper_id: self - .subdomain_wrappers - .get(&name_record.name.to_string()) - .cloned(), - }); - } - - updates - } -} - -/// Allows us to format a SuiNS specific query for updating the DB entries -/// only if the checkpoint is newer than the last checkpoint we have in the DB. -/// Doing that, we do not care about the order of execution and we can use -/// multiple threads to commit from later checkpoints to the DB. -/// -/// WARNING: This can easily be SQL-injected, so make sure to use it only with -/// trusted inputs. -pub fn format_update_field_query(field: &str) -> String { - format!( - "CASE WHEN excluded.last_checkpoint_updated > domains.last_checkpoint_updated THEN excluded.{field} ELSE domains.{field} END" - ) -} - -/// Update the subdomain wrapper ID only if it is part of the checkpoint. -pub fn format_update_subdomain_wrapper_query() -> String { - "CASE WHEN excluded.subdomain_wrapper_id IS NOT NULL THEN excluded.subdomain_wrapper_id ELSE domains.subdomain_wrapper_id END".to_string() -} diff --git a/crates/suins-indexer/src/lib.rs b/crates/suins-indexer/src/lib.rs deleted file mode 100644 index e39572a2e37..00000000000 --- a/crates/suins-indexer/src/lib.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod indexer; -pub mod models; -pub mod schema; - -use std::env; - -use diesel::{ - pg::PgConnection, - r2d2::{ConnectionManager, Pool}, -}; -use dotenvy::dotenv; - -pub type PgConnectionPool = diesel::r2d2::Pool>; -pub type PgPoolConnection = diesel::r2d2::PooledConnection>; - -pub fn get_connection_pool() -> PgConnectionPool { - dotenv().ok(); - - let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); - let manager = ConnectionManager::::new(database_url); - - Pool::builder() - .test_on_check_out(true) - .build(manager) - .expect("Could not build Postgres DB connection pool") -} diff --git a/crates/suins-indexer/src/main.rs b/crates/suins-indexer/src/main.rs deleted file mode 100644 index 5cf65ed5e47..00000000000 --- a/crates/suins-indexer/src/main.rs +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{env, path::PathBuf}; - -use anyhow::Result; -use async_trait::async_trait; -use diesel::{dsl::sql, BoolExpressionMethods, Connection, ExpressionMethods, RunQueryDsl}; -use dotenvy::dotenv; -use prometheus::Registry; -use sui_data_ingestion_core::{ - DataIngestionMetrics, FileProgressStore, IndexerExecutor, ReaderOptions, Worker, WorkerPool, -}; -use sui_types::full_checkpoint_content::CheckpointData; -use suins_indexer::{ - get_connection_pool, - indexer::{format_update_field_query, format_update_subdomain_wrapper_query, SuinsIndexer}, - models::VerifiedDomain, - schema::domains, - PgConnectionPool, -}; -use tokio::sync::oneshot; - -struct SuinsIndexerWorker { - pg_pool: PgConnectionPool, - indexer: SuinsIndexer, -} - -impl SuinsIndexerWorker { - /// Creates a transcation that upserts the given name record updates, - /// and deletes the given name record deletions. - /// - /// This is done using 1 or 2 queries, depending on whether there are any - /// deletions/updates in the checkpoint. - /// - /// - The first query is a bulk insert of all updates, with an upsert on - /// conflict. - /// - The second query is a bulk delete of all deletions. - /// - /// You can safely call this with empty updates/deletions as it will return - /// Ok. - fn commit_to_db( - &self, - updates: &[VerifiedDomain], - removals: &[String], - checkpoint_seq_num: u64, - ) -> Result<()> { - if updates.is_empty() && removals.is_empty() { - return Ok(()); - } - - let connection = &mut self.pg_pool.get().unwrap(); - - connection.transaction(|tx| { - if !updates.is_empty() { - // Bulk insert all updates and override with data. - diesel::insert_into(domains::table) - .values(updates) - .on_conflict(domains::name) - .do_update() - .set(( - domains::expiration_timestamp_ms - .eq(sql(&format_update_field_query("expiration_timestamp_ms"))), - domains::nft_id.eq(sql(&format_update_field_query("nft_id"))), - domains::target_address - .eq(sql(&format_update_field_query("target_address"))), - domains::data.eq(sql(&format_update_field_query("data"))), - domains::last_checkpoint_updated - .eq(sql(&format_update_field_query("last_checkpoint_updated"))), - domains::field_id.eq(sql(&format_update_field_query("field_id"))), - // We always want to respect the subdomain_wrapper re-assignment, even if - // the checkpoint is older. That prevents a - // scenario where we first process a later checkpoint that did an update to - // the name record (e..g change target address), - // without first executing the checkpoint that created the subdomain - // wrapper. Since wrapper re-assignment can only - // happen every 2 days, we can't write invalid data here. - domains::subdomain_wrapper_id - .eq(sql(&format_update_subdomain_wrapper_query())), - )) - .execute(tx) - .unwrap_or_else(|_| panic!("Failed to process updates: {:?}", updates)); - } - - if !removals.is_empty() { - // We want to remove from the database all name records that were removed in the - // checkpoint but only if the checkpoint is newer than the last - // time the name record was updated. - diesel::delete(domains::table) - .filter( - domains::field_id - .eq_any(removals) - .and(domains::last_checkpoint_updated.le(checkpoint_seq_num as i64)), - ) - .execute(tx) - .unwrap_or_else(|_| panic!("Failed to process deletions: {:?}", removals)); - } - - Ok(()) - }) - } -} - -#[async_trait] -impl Worker for SuinsIndexerWorker { - async fn process_checkpoint(&self, checkpoint: CheckpointData) -> Result<()> { - let checkpoint_seq_number = checkpoint.checkpoint_summary.sequence_number; - let (updates, removals) = self.indexer.process_checkpoint(&checkpoint); - - self.commit_to_db(&updates, &removals, checkpoint_seq_number)?; - Ok(()) - } -} - -#[tokio::main] -async fn main() -> Result<()> { - dotenv().ok(); - let (remote_storage, registry_id, subdomain_wrapper_type) = ( - env::var("REMOTE_STORAGE").ok(), - env::var("REGISTRY_ID").ok(), - env::var("SUBDOMAIN_WRAPPER_TYPE").ok(), - ); - let backfill_progress_file_path = - env::var("BACKFILL_PROGRESS_FILE_PATH").unwrap_or("/tmp/backfill_progress".to_string()); - let checkpoints_dir = env::var("CHECKPOINTS_DIR").unwrap_or("/tmp/checkpoints".to_string()); - - println!("Starting indexer with checkpoints dir: {}", checkpoints_dir); - - let (_exit_sender, exit_receiver) = oneshot::channel(); - let progress_store = FileProgressStore::new(PathBuf::from(backfill_progress_file_path)); - let metrics = DataIngestionMetrics::new(&Registry::new()); - let mut executor = IndexerExecutor::new(progress_store, 1, metrics); - - let indexer_setup = if let (Some(registry_id), Some(subdomain_wrapper_type)) = - (registry_id, subdomain_wrapper_type) - { - SuinsIndexer::new(registry_id, subdomain_wrapper_type) - } else { - SuinsIndexer::default() - }; - - let worker_pool = WorkerPool::new( - SuinsIndexerWorker { - pg_pool: get_connection_pool(), - indexer: indexer_setup, - }, - "suins_indexing".to_string(), // task name used as a key in the progress store - 100, // concurrency - ); - executor.register(worker_pool).await?; - - executor - .run( - PathBuf::from(checkpoints_dir), // directory should exist but can be empty - remote_storage, // remote_read_endpoint: If set - vec![], // aws credentials - ReaderOptions::default(), // remote_read_batch_size - exit_receiver, - ) - .await?; - Ok(()) -} diff --git a/crates/suins-indexer/src/schema.rs b/crates/suins-indexer/src/schema.rs deleted file mode 100644 index 9484c1f813e..00000000000 --- a/crates/suins-indexer/src/schema.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -// @generated automatically by Diesel CLI. - -diesel::table! { - domains (name) { - name -> Varchar, - parent -> Varchar, - expiration_timestamp_ms -> Int8, - nft_id -> Varchar, - field_id -> Varchar, - target_address -> Nullable, - data -> Json, - last_checkpoint_updated -> Int8, - subdomain_wrapper_id -> Nullable, - } -} diff --git a/crates/suiop-cli/Cargo.toml b/crates/suiop-cli/Cargo.toml deleted file mode 100644 index 400654cd080..00000000000 --- a/crates/suiop-cli/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -[package] -authors = [ - "Jk Jensen ", - "Mysten Labs ", -] -edition = "2021" -license = "Apache-2.0" -name = "suiop-cli" -publish = false -version = "0.1.9" - -[lib] -name = "suioplib" -path = "src/lib.rs" - -[[bin]] -name = "suiop" -path = "src/main.rs" - -[dependencies] -anyhow.workspace = true -chrono.workspace = true -clap.workspace = true -colored.workspace = true -docker-api.workspace = true -field_names.workspace = true -include_dir.workspace = true -inquire.workspace = true -prettytable-rs.workspace = true -regex.workspace = true -reqwest = { workspace = true, features = [ - "rustls-tls", - "json", -], default-features = false } -semver.workspace = true -serde = { workspace = true, features = ["derive"] } -serde_json.workspace = true -serde_yaml.workspace = true -spinners.workspace = true -strum.workspace = true -tokio = { workspace = true, features = ["full"] } -toml_edit.workspace = true -tracing-subscriber.workspace = true -tracing.workspace = true - -[dev-dependencies] -tempfile.workspace = true diff --git a/crates/suiop-cli/src/cli/incidents/mod.rs b/crates/suiop-cli/src/cli/incidents/mod.rs deleted file mode 100644 index 357f874ec2b..00000000000 --- a/crates/suiop-cli/src/cli/incidents/mod.rs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod jira; -mod pd; - -use std::path::PathBuf; - -use anyhow::Result; -use clap::Parser; -use jira::generate_follow_up_tasks; -use pd::print_recent_incidents; - -#[derive(Parser, Debug, Clone)] -pub struct IncidentsArgs { - #[command(subcommand)] - action: IncidentsAction, -} - -#[derive(clap::Subcommand, Debug, Clone)] -pub enum IncidentsAction { - /// show recent incident details - #[command(name = "recent", aliases=["r", "recent_incidents"])] - GetRecentIncidents { - /// extended output with additional fields - #[arg(short, long)] - long: bool, - /// the max number of incidents to show - #[arg(long, default_value = "500")] - limit: usize, - /// the days to go back - #[arg(short, long, default_value = "7")] - days: usize, - }, - /// generate Jira tasks for incident follow ups - #[command(name = "generate follow up tasks", aliases=["g", "gen", "generate"])] - GenerateFollowUpTasks { - /// filename with tasks to add. should be named {incident number}.txt - #[arg(short, long)] - input_filename: PathBuf, - }, -} - -pub async fn incidents_cmd(args: &IncidentsArgs) -> Result<()> { - match &args.action { - IncidentsAction::GetRecentIncidents { long, limit, days } => { - print_recent_incidents(*long, *limit, *days).await? - } - IncidentsAction::GenerateFollowUpTasks { input_filename } => { - generate_follow_up_tasks(input_filename).await? - } - } - Ok(()) -} diff --git a/crates/suiop-cli/src/cli/mod.rs b/crates/suiop-cli/src/cli/mod.rs deleted file mode 100644 index 71523c90107..00000000000 --- a/crates/suiop-cli/src/cli/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod incidents; -pub mod pulumi; -mod service; - -pub use incidents::{incidents_cmd, IncidentsArgs}; -pub use pulumi::{pulumi_cmd, PulumiArgs}; -pub use service::{service_cmd, ServiceArgs}; diff --git a/crates/suiop-cli/src/cli/pulumi/init.rs b/crates/suiop-cli/src/cli/pulumi/init.rs deleted file mode 100644 index d94b962db03..00000000000 --- a/crates/suiop-cli/src/cli/pulumi/init.rs +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{fs, path::PathBuf}; - -use anyhow::{anyhow, Context, Result}; -use colored::Colorize; -use inquire::Text; -use serde::{Deserialize, Serialize}; -use tracing::{debug, error, info, warn}; - -use crate::{command::CommandOptions, run_cmd}; - -pub enum ProjectType { - App, - Service, - Basic, - CronJob, -} - -const KEYRING: &str = "pulumi-kms-automation-f22939d"; - -impl ProjectType { - pub fn create_project(&self, use_kms: &bool, project_name: Option) -> Result<()> { - // make sure we're in suiops - ensure_in_suiops_repo()?; - // inquire params from user - let project_name = project_name.unwrap_or_else(|| { - Text::new("project name:") - .prompt() - .expect("couldn't get project name") - }); - // create dir - let project_subdir = match self { - Self::App | Self::CronJob => "apps".to_owned(), - Self::Service => "services".to_owned(), - Self::Basic => Text::new("project subdir (under sui-operations/pulumi/):") - .prompt() - .expect("couldn't get subdir"), - }; - let project_dir = get_pulumi_dir()?.join(project_subdir).join(&project_name); - let mut project_opts = vec![]; - if *use_kms { - let encryption_key_id = get_encryption_key_id(&project_name)?; - project_opts.push(format!("--secrets-provider=gcpkms://{}", encryption_key_id)); - } - if project_dir.exists() { - Err(anyhow!( - "{} already exists. Please use a project name that doesn't already exist", - project_dir - .to_str() - .expect("project dir to str") - .bright_purple() - )) - } else { - match self { - Self::App | Self::Service => { - info!("creating k8s containerized application/service"); - create_mysten_k8s_project( - &project_name, - &project_dir, - Self::App, - &project_opts, - )?; - } - Self::Basic => { - info!("creating basic pulumi project"); - create_basic_project(&project_name, &project_dir, &project_opts)?; - } - Self::CronJob => { - info!("creating k8s cronjob project"); - create_mysten_k8s_project( - &project_name, - &project_dir, - Self::CronJob, - &project_opts, - )?; - } - } - info!("your new project is ready to go!"); - Ok(()) - } - } -} - -fn ensure_in_suiops_repo() -> Result<()> { - let remote_stdout = run_cmd( - vec!["git", "config", "--get", "remote.origin.url"], - Some(CommandOptions::new(false, false)), - ) - .context("run this command within the sui-operations repository")? - .stdout; - let in_suiops = String::from_utf8_lossy(&remote_stdout) - .trim() - .contains("sui-operations"); - if !in_suiops { - Err(anyhow!( - "please run this command from within the sui-operations repository" - )) - } else { - Ok(()) - } -} - -fn get_pulumi_dir() -> Result { - let suiops_dir_stdout = run_cmd( - vec!["git", "rev-parse", "--show-toplevel"], - Some(CommandOptions::new(false, false)), - ) - .context("run this command from within the sui-operations repository")? - .stdout; - let suiops_dir = PathBuf::from(String::from_utf8_lossy(&suiops_dir_stdout).trim()); - Ok(suiops_dir.join("pulumi")) -} - -fn run_pulumi_new( - project_name: &str, - project_dir_str: &str, - project_opts: &[String], -) -> Result<()> { - info!( - "creating new pulumi project in {}", - project_dir_str.bright_purple() - ); - let opts = project_opts.join(" "); - info!("extra pulumi options added: {}", &opts.bright_purple()); - run_cmd( - vec![ - "bash", - "-c", - &format!( - r#"pulumi new go --dir {0} -d "pulumi project for {1}" --name "{1}" --stack mysten/dev --yes {2}"#, - project_dir_str, project_name, opts - ), - ], - None, - )?; - Ok(()) -} - -fn run_pulumi_new_from_template( - project_name: &str, - project_dir_str: &str, - project_type: ProjectType, - project_opts: &[String], -) -> Result<()> { - info!( - "creating new pulumi project in {}", - project_dir_str.bright_purple() - ); - let template_dir = match project_type { - ProjectType::App | ProjectType::Service => "app-go", - ProjectType::CronJob => "cronjob-go", - _ => "app-go", - }; - let opts = project_opts.join(" "); - info!("extra pulumi options added: {}", &opts.bright_purple()); - let cmd = &format!( - r#"pulumi new {3}/templates/{2} --dir {0} -d "pulumi project for {1}" --name "{1}" --stack mysten/dev {4}"#, - project_dir_str, - project_name, - template_dir, - get_pulumi_dir()? - .to_str() - .expect("getting pulumi dir for template"), - opts, - ); - info!("running command: {}", cmd.bright_purple()); - - run_cmd( - vec!["bash", "-c", cmd], - Some(CommandOptions::new(true, false)), - )?; - Ok(()) -} - -fn run_go_mod_tidy(project_dir_str: &str) -> Result<()> { - let cmd = &format!("cd {} && go mod tidy", project_dir_str); - info!( - "running `{}` to make sure all Golang dependencies are installed.", - cmd - ); - run_cmd(vec!["bash", "-c", cmd], None)?; - Ok(()) -} - -fn run_pulumi_preview(project_dir_str: &str) -> Result<()> { - info!("running pulumi preview to make sure everything is functional"); - run_cmd( - vec![ - "bash", - "-c", - &format!("pulumi preview -C {}", project_dir_str), - ], - None, - )?; - Ok(()) -} - -fn remove_project_dir(project_dir: &PathBuf) -> Result<()> { - fs::remove_dir_all(project_dir).context("removing project dir") -} - -#[derive(Serialize, Deserialize)] -struct PulumiBackendURL { - url: String, -} - -fn get_current_backend() -> Result { - debug!("running pulumi whoami -v -j to get the Backend URL"); - let output = run_cmd(vec!["bash", "-c", "pulumi whoami -v -j"], None)?; - let stdout_str = std::str::from_utf8(&output.stdout)?; - let val: PulumiBackendURL = serde_json::from_str(stdout_str)?; - let mut parts = val.url.split("com/"); - if let Some(answer) = parts.nth(1) { - if !answer.is_empty() { - let ret = answer.trim().to_string(); - debug!("Backend URL is pointing to: {ret}"); - Ok(ret) - } else { - Err(anyhow!("Backend URL is incomplete")) - } - } else { - Err(anyhow!("Backend URL is incomplete")) - } -} - -fn remove_stack(backend: &str, project_name: &str, stack_name: &str) -> Result<()> { - let stack_str = format!("{}/{}/{}", backend, project_name, stack_name); - debug!("cleaning up {}...", &stack_str); - run_cmd( - vec![ - "bash", - "-c", - &format!("pulumi stack rm {} --yes", stack_str), - ], - None, - )?; - warn!( - "{} cleaned up successfully, you'll have a clean start next time.", - &stack_str.bright_purple() - ); - Ok(()) -} - -fn create_basic_project( - project_name: &str, - project_dir: &PathBuf, - project_opts: &[String], -) -> Result<()> { - let project_dir_str = project_dir.to_str().expect("project dir to str"); - info!( - "creating project directory at {}", - project_dir_str.bright_purple() - ); - fs::create_dir_all(project_dir).context("failed to create project directory")?; - // initialize pulumi project - run_pulumi_new(project_name, project_dir_str, project_opts).map_err(|e| { - remove_project_dir(project_dir).unwrap(); - let backend = get_current_backend().unwrap(); - remove_stack(&backend, project_name, "mysten/dev").unwrap(); - e - })?; - // run go mod tidy to make sure all dependencies are installed - run_go_mod_tidy(project_dir_str)?; - // try a pulumi preview to make sure it's good - run_pulumi_preview(project_dir_str) -} - -fn create_mysten_k8s_project( - project_name: &str, - project_dir: &PathBuf, - project_type: ProjectType, - project_opts: &[String], -) -> Result<()> { - let project_dir_str = project_dir.to_str().expect("project dir to str"); - info!( - "creating project directory at {}", - project_dir_str.bright_purple() - ); - fs::create_dir_all(project_dir).context("failed to create project directory")?; - // initialize pulumi project - run_pulumi_new_from_template(project_name, project_dir_str, project_type, project_opts) - .map_err(|e| { - remove_project_dir(project_dir).unwrap(); - let backend = get_current_backend().unwrap(); - remove_stack(&backend, project_name, "mysten/dev").unwrap(); - e - })?; - // run go mod tidy to make sure all dependencies are installed - run_go_mod_tidy(project_dir_str) - // we don't run preview for templated apps because the user - // has to give the repo dir (improvements to this coming soon) -} - -#[derive(Serialize, Deserialize)] -struct KMSKeyPrimary { - state: String, - algorithm: String, -} -#[derive(Serialize, Deserialize)] -struct KMSKey { - name: String, - primary: KMSKeyPrimary, -} -fn get_encryption_key_id(project_name: &str) -> Result { - let output = run_cmd( - vec![ - "bash", - "-c", - &format!( - "gcloud kms keys list --location=global --keyring={} --format json", - KEYRING - ), - ], - None, - ) - .map_err(|e| { - error!( - "Cannot list KMS keys, please add your Google account to {}", - "pulumi/meta/gcp-iam-automation/config.toml".bright_yellow() - ); - e - })?; - let stdout_str = String::from_utf8(output.stdout)?; - let keys: Vec = serde_json::from_str(&stdout_str)?; - for key in keys { - let key_id = key.name; - if let Some((_, key_name)) = key_id.rsplit_once('/') { - if key_name.starts_with(project_name) - && key.primary.state == "ENABLED" - && key.primary.algorithm == "GOOGLE_SYMMETRIC_ENCRYPTION" - { - return Ok(key_id); - } - } - } - error!( - "Cannot find encryption key matching project name: {0}.\n - Please add a new entry {1} to {2}, create a PR then land it.\n - A Github workflow will be triggered automatically to create a key for this pulumi project.", - project_name.bright_purple(), - format!("[kms.{}]", project_name).bright_purple(), - "pulumi/meta/gcp-iam-automation/config.toml".bright_yellow() - ); - Err(anyhow!("Missing encryption key")) -} diff --git a/crates/suiop-cli/src/cli/pulumi/mod.rs b/crates/suiop-cli/src/cli/pulumi/mod.rs deleted file mode 100644 index 3356bce232d..00000000000 --- a/crates/suiop-cli/src/cli/pulumi/mod.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod init; -mod setup; - -use anyhow::Result; -use clap::Parser; -use init::ProjectType; -use setup::{ensure_gcloud, ensure_setup}; - -#[derive(Parser, Debug, Clone)] -pub struct PulumiArgs { - #[command(subcommand)] - action: PulumiAction, -} - -#[derive(clap::Subcommand, Debug, Clone)] -pub enum PulumiAction { - /// initialize a new pulumi project - #[command(name = "init", aliases=["i"])] - InitProject { - /// initialize app project - #[arg(short, long, group = "type")] - app: bool, - - #[arg(short, long, group = "type")] - service: bool, - - /// initialize barebones project (default) - #[arg(short, long, group = "type")] - basic: bool, - - /// initialize cronjob project - #[arg(short, long, group = "type")] - cronjob: bool, - - /// use GCP KMS as encryption provider - #[arg(short, long, group = "feature")] - kms: bool, - - /// the name of the project to be created - #[arg(long, aliases = ["name"])] - project_name: Option, - }, -} - -pub async fn pulumi_cmd(args: &PulumiArgs) -> Result<()> { - ensure_setup()?; - match &args.action { - PulumiAction::InitProject { - app, - service, - basic, - cronjob, - kms, - project_name, - } => { - if *kms { - ensure_gcloud()?; - } - let project_type = match (app, service, basic, cronjob) { - (false, true, false, false) => ProjectType::Service, - (true, false, false, false) => ProjectType::App, - (false, false, false, true) => ProjectType::CronJob, - (_, _, _, _) => ProjectType::Basic, - }; - project_type.create_project(kms, project_name.clone()) - } - } -} diff --git a/crates/suiop-cli/src/cli/service/init.rs b/crates/suiop-cli/src/cli/service/init.rs deleted file mode 100644 index 0162c67ec56..00000000000 --- a/crates/suiop-cli/src/cli/service/init.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::{ - fs, - fs::{create_dir_all, File}, - io::prelude::*, - path::Path, -}; - -use anyhow::{Context, Result}; -use clap::{Parser, ValueEnum}; -use include_dir::{include_dir, Dir}; -use tracing::{debug, info}; - -// include the boilerplate code in this binary - -// hardcode the 'boilerplate' symlink in the Windows compilation for now -#[cfg(target_os = "windows")] -static PROJECT_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/../mysten-service-boilerplate"); -#[cfg(not(target_os = "windows"))] -static PROJECT_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/boilerplate"); - -#[derive(ValueEnum, Parser, Debug, Clone)] -pub enum ServiceLanguage { - Rust, - Typescript, -} - -pub fn bootstrap_service(lang: &ServiceLanguage, path: &Path) -> Result<()> { - match lang { - ServiceLanguage::Rust => create_rust_service(path), - ServiceLanguage::Typescript => todo!(), - } -} - -/// Add the new service to the sui-services dockerfile in the sui repository -fn add_to_sui_dockerfile(path: &Path) -> Result<()> { - let path = path.canonicalize().context("canonicalizing service path")?; - let crates_dir = path.parent().unwrap(); - if !crates_dir.ends_with("sui/crates") { - panic!("directory wasn't in the sui repo"); - } - let sui_services_dockerfile_path = &crates_dir.join("../docker/sui-services/Dockerfile"); - // read the dockerfile - let dockerfile = fs::read_to_string(sui_services_dockerfile_path) - .context("reading sui-services dockerfile")?; - - // find the line with the build cmd - let build_line = dockerfile - .lines() - .enumerate() - .find(|(_, line)| line.contains("RUN cargo build --release \\")) - .expect("couldn't find build line in sui-services dockerfile") - .0; - // update with the new service - let mut final_dockerfile = dockerfile.lines().collect::>(); - let bin_str = format!( - " --bin {} \\", - path.file_name() - .expect("getting the project name from the given path") - .to_str() - .unwrap() - ); - final_dockerfile.insert(build_line + 1, &bin_str); - // write the file back - fs::write(sui_services_dockerfile_path, final_dockerfile.join("\n")) - .context("writing sui-services dockerfile after modifying it")?; - - Ok(()) -} - -fn add_member_to_workspace(path: &Path) -> Result<()> { - // test - let path = path.canonicalize().context("canonicalizing service path")?; - let crates_dir = path.parent().unwrap(); - if !crates_dir.ends_with("sui/crates") { - panic!("directory wasn't in the sui repo"); - } - let workspace_toml_path = &crates_dir.join("../Cargo.toml"); - // read the workspace toml - let toml_content = fs::read_to_string(workspace_toml_path)?; - let mut toml = toml_content.parse::()?; - toml["workspace"]["members"] - .as_array_mut() - .unwrap() - .push_formatted(toml_edit::Value::String(toml_edit::Formatted::new( - Path::new("crates/") - .join( - path.file_name() - .expect("getting the project name from the given path"), - ) - .to_str() - .expect("converting the path to a str") - .to_string(), - ))); - fs::write(workspace_toml_path, toml.to_string()) - .context("failed to write workspace Cargo.toml back after update")?; - Ok(()) -} - -fn create_rust_service(path: &Path) -> Result<()> { - info!("creating rust service in {}", path.to_string_lossy()); - // create the dir to ensure we can canonicalize any relative paths - create_dir_all(path)?; - let is_sui_service = path - // expand relative paths and symlinks - .canonicalize() - .context("canonicalizing service path")? - .to_string_lossy() - .contains("sui/crates"); - debug!("sui service: {:?}", is_sui_service); - let cargo_toml_path = if is_sui_service { - "Cargo.toml" - } else { - "Cargo-external.toml" - }; - let cargo_toml = PROJECT_DIR.get_file(cargo_toml_path).unwrap(); - let main_rs = PROJECT_DIR.get_file("src/main.rs").unwrap(); - let main_body = main_rs.contents(); - let cargo_body = std::str::from_utf8(cargo_toml.contents())?; - let mut toml_content = cargo_body.parse::()?; - toml_content["package"]["name"] = toml_edit::value(path.file_name().unwrap().to_str().unwrap()); - create_dir_all(path.join("src"))?; - let mut main_file = File::create(path.join("src/main.rs"))?; - main_file.write_all(main_body)?; - let mut cargo_file = File::create(path.join("Cargo.toml"))?; - cargo_file.write_all(toml_content.to_string().as_bytes())?; - - // add the project as a member of the cargo workspace - if is_sui_service { - add_member_to_workspace(path)?; - } - // now that the source directory works, let's update/add a dockerfile - if is_sui_service { - // update sui-services dockerfile - add_to_sui_dockerfile(path)?; - } else { - // TODO: create a new dockerfile where the user designates - } - - Ok(()) -} diff --git a/crates/suiop-cli/src/cli/service/mod.rs b/crates/suiop-cli/src/cli/service/mod.rs deleted file mode 100644 index d8ec25012b4..00000000000 --- a/crates/suiop-cli/src/cli/service/mod.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -mod init; - -use std::path::PathBuf; - -use anyhow::Result; -use clap::Parser; -pub use init::bootstrap_service; -use init::ServiceLanguage; - -#[derive(Parser, Debug, Clone)] -pub struct ServiceArgs { - #[command(subcommand)] - action: ServiceAction, -} - -#[derive(clap::Subcommand, Debug, Clone)] -pub enum ServiceAction { - /// initialize new service boilerplate - #[command(name = "init", aliases=["i"])] - InitService { - /// service boilerplate language - #[arg(value_enum, short, long, default_value_t = ServiceLanguage::Rust)] - lang: ServiceLanguage, - - /// directory to create service boilerplate in - #[arg(short, long)] - path: PathBuf, - }, -} - -pub async fn service_cmd(args: &ServiceArgs) -> Result<()> { - match &args.action { - ServiceAction::InitService { lang, path } => bootstrap_service(lang, path), - } -} diff --git a/crates/suiop-cli/src/command.rs b/crates/suiop-cli/src/command.rs deleted file mode 100644 index 220f31322f1..00000000000 --- a/crates/suiop-cli/src/command.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use std::process::{Command, Output, Stdio}; - -use anyhow::{anyhow, Context, Result}; -use spinners::{Spinner, Spinners}; -use tracing::debug; -const SPINNER: Spinners = Spinners::Dots12; - -#[derive(Debug, Clone)] -pub struct CommandOptions { - shared_stdio: bool, - show_spinner: bool, -} - -impl CommandOptions { - pub fn new(shared_stdio: bool, show_spinner: bool) -> Self { - CommandOptions { - shared_stdio, - show_spinner, - } - } -} - -impl Default for CommandOptions { - fn default() -> Self { - CommandOptions { - shared_stdio: false, - show_spinner: true, - } - } -} - -pub fn run_cmd(cmd_in: Vec<&str>, options: Option) -> Result { - debug!("attempting to run {}", cmd_in.join(" ")); - let opts = if let Some(opts) = options { - opts - } else { - CommandOptions::default() - }; - - let mut cmd = Command::new(cmd_in[0]); - // add extra args - let cmd = if cmd_in.len() > 1 { - cmd.args(cmd_in[1..].iter()) - } else { - &mut cmd - }; - // add stdio - let cmd = if opts.shared_stdio { - debug!("stdio will be shared between parent shell and command process"); - cmd.stdout(Stdio::inherit()).stdin(Stdio::inherit()) - } else { - cmd - }; - let res = if opts.show_spinner { - let mut sp = Spinner::new(SPINNER, "".into()); - let result = cmd.output().context(format!( - "failed to run command with spinner {}", - cmd_in.join(" ") - ))?; - sp.stop(); - print!("\r"); - result - } else { - cmd.output() - .context(format!("failed to run command {}", cmd_in.join(" ")))? - }; - - if !res.status.success() { - Err(anyhow!( - "command failed to run: {}", - std::str::from_utf8(&res.stderr)? - )) - } else { - Ok(res) - } -} diff --git a/crates/suiop-cli/src/lib.rs b/crates/suiop-cli/src/lib.rs deleted file mode 100644 index e3accd63a91..00000000000 --- a/crates/suiop-cli/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -pub mod cli; -pub mod command; -pub use command::run_cmd; diff --git a/crates/suiop-cli/src/main.rs b/crates/suiop-cli/src/main.rs deleted file mode 100644 index 718779430f0..00000000000 --- a/crates/suiop-cli/src/main.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use anyhow::Result; -use clap::Parser; -use suioplib::cli::{ - incidents_cmd, pulumi_cmd, service_cmd, IncidentsArgs, PulumiArgs, ServiceArgs, -}; -use tracing_subscriber::{ - filter::{EnvFilter, LevelFilter}, - FmtSubscriber, -}; - -#[derive(Parser, Debug)] -#[command(author="build@mystenlabs.com", version, about, long_about = None)] -pub(crate) struct SuiOpArgs { - /// The resource type we're operating on. - #[command(subcommand)] - resource: Resource, -} - -#[derive(clap::Subcommand, Debug)] -pub(crate) enum Resource { - #[clap(aliases = ["inc", "i"])] - Incidents(IncidentsArgs), - #[clap(aliases = ["p"])] - Pulumi(PulumiArgs), - #[clap(aliases = ["s", "svc"])] - Service(ServiceArgs), -} - -#[tokio::main(flavor = "current_thread")] -async fn main() -> Result<()> { - let subscriber = FmtSubscriber::builder() - .with_env_filter( - EnvFilter::builder() - .with_default_directive(LevelFilter::INFO.into()) - .from_env_lossy(), - ) - .finish(); - - tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed"); - - let args = SuiOpArgs::parse(); - match args.resource { - Resource::Incidents(args) => { - incidents_cmd(&args).await?; - } - Resource::Pulumi(args) => { - pulumi_cmd(&args).await?; - } - Resource::Service(args) => { - service_cmd(&args).await?; - } - } - - Ok(()) -} diff --git a/crates/telemetry-subscribers/README.md b/crates/telemetry-subscribers/README.md index d3487671fee..223d94012a3 100644 --- a/crates/telemetry-subscribers/README.md +++ b/crates/telemetry-subscribers/README.md @@ -50,9 +50,9 @@ NOTE: JSON output requires the `json` crate feature to be enabled. #### Tracing locally: 1. In `docker/grafana-local` run `docker compose up` to start a local grafana instance. -2. Set `TRACE_FILTER=` - for local use `TRACE_FILTER=sui=trace,info` is a good place to start. -3. Start the sui-node or other process. -4. Go to http://localhost:3000 (or [http://localhost:3000/ with traces already filtered to sui-node](http://localhost:3000/explore?panes=%7B%22iHz%22:%7B%22datasource%22:%22tempo%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22tempo%22%7D,%22queryType%22:%22traceqlSearch%22,%22limit%22:20,%22filters%22:%5B%7B%22id%22:%22service-name%22,%22tag%22:%22service.name%22,%22operator%22:%22%3D%22,%22scope%22:%22resource%22,%22value%22:%5B%22sui-node%22%5D,%22valueType%22:%22string%22%7D,%7B%22id%22:%22span-name%22,%22tag%22:%22name%22,%22operator%22:%22%3D%22,%22scope%22:%22span%22,%22value%22:%5B%5D,%22valueType%22:%22string%22%7D,%7B%22id%22:%224f3681c5%22,%22operator%22:%22%3D%22,%22scope%22:%22span%22%7D%5D%7D%5D,%22range%22:%7B%22from%22:%22now-5m%22,%22to%22:%22now%22%7D%7D%7D&schemaVersion=1&orgId=1) +2. Set `TRACE_FILTER=` - for local use `TRACE_FILTER=iota=trace,info` is a good place to start. +3. Start the iota-node or other process. +4. Go to http://localhost:3000 (or [http://localhost:3000/ with traces already filtered to iota-node](http://localhost:3000/explore?panes=%7B%22iHz%22:%7B%22datasource%22:%22tempo%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22tempo%22%7D,%22queryType%22:%22traceqlSearch%22,%22limit%22:20,%22filters%22:%5B%7B%22id%22:%22service-name%22,%22tag%22:%22service.name%22,%22operator%22:%22%3D%22,%22scope%22:%22resource%22,%22value%22:%5B%22iota-node%22%5D,%22valueType%22:%22string%22%7D,%7B%22id%22:%22span-name%22,%22tag%22:%22name%22,%22operator%22:%22%3D%22,%22scope%22:%22span%22,%22value%22:%5B%5D,%22valueType%22:%22string%22%7D,%7B%22id%22:%224f3681c5%22,%22operator%22:%22%3D%22,%22scope%22:%22span%22%7D%5D%7D%5D,%22range%22:%7B%22from%22:%22now-5m%22,%22to%22:%22now%22%7D%7D%7D&schemaVersion=1&orgId=1) 5. Select `Tempo` as the data source. #### Tracing in production: @@ -63,7 +63,7 @@ Because tracing is expensive, it is not enabled by default. To enable trace expo 2. Using the filter expression and duration of your choice, run: - $ curl -X POST 'http://127.0.0.1:1337/enable-tracing?filter=sui-node=trace,info&duration=10s' + $ curl -X POST 'http://127.0.0.1:1337/enable-tracing?filter=iota-node=trace,info&duration=10s' Tracing will automatically be disabled after the specified duration has elapsed, in order to avoid leaving tracing on unintentionally. diff --git a/crates/telemetry-subscribers/examples/easy-init.rs b/crates/telemetry-subscribers/examples/easy-init.rs index 8c4c1acd898..d6776c5c0be 100644 --- a/crates/telemetry-subscribers/examples/easy-init.rs +++ b/crates/telemetry-subscribers/examples/easy-init.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use tracing::{debug, info, warn}; diff --git a/crates/telemetry-subscribers/src/bin/import-trace.rs b/crates/telemetry-subscribers/src/bin/import-trace.rs index 0d5c4c52440..20a9d9e224c 100644 --- a/crates/telemetry-subscribers/src/bin/import-trace.rs +++ b/crates/telemetry-subscribers/src/bin/import-trace.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::io::{self, Cursor, Read}; @@ -53,7 +54,7 @@ async fn main() { .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_secs(); - format!("sui-node-{}", timestamp) + format!("iota-node-{}", timestamp) }); println!("importing trace with service name {:?}", service_name); diff --git a/crates/telemetry-subscribers/src/file_exporter.rs b/crates/telemetry-subscribers/src/file_exporter.rs index ea15e5acf64..5cf343fb157 100644 --- a/crates/telemetry-subscribers/src/file_exporter.rs +++ b/crates/telemetry-subscribers/src/file_exporter.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/telemetry-subscribers/src/lib.rs b/crates/telemetry-subscribers/src/lib.rs index cf08315a0c8..036a93fa47b 100644 --- a/crates/telemetry-subscribers/src/lib.rs +++ b/crates/telemetry-subscribers/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -391,7 +392,7 @@ impl TelemetryConfig { let config = sdk::trace::config() .with_resource(Resource::new(vec![opentelemetry::KeyValue::new( "service.name", - "sui-node", + "iota-node", )])) .with_sampler(Sampler::ParentBased(Box::new(sampler.clone()))); @@ -408,7 +409,7 @@ impl TelemetryConfig { .with_span_processor(processor) .build(); - let tracer = p.tracer("sui-node"); + let tracer = p.tracer("iota-node"); provider = Some(p); tracing_opentelemetry::layer().with_tracer(tracer) diff --git a/crates/telemetry-subscribers/src/span_latency_prom.rs b/crates/telemetry-subscribers/src/span_latency_prom.rs index 57fb0dd0504..e06ab31d9a0 100644 --- a/crates/telemetry-subscribers/src/span_latency_prom.rs +++ b/crates/telemetry-subscribers/src/span_latency_prom.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! This is a module that records Tokio-tracing [span](https://docs.rs/tracing/latest/tracing/span/index.html) diff --git a/crates/telemetry-subscribers/tests/reload.rs b/crates/telemetry-subscribers/tests/reload.rs index dff33b1f522..3bca8499eff 100644 --- a/crates/telemetry-subscribers/tests/reload.rs +++ b/crates/telemetry-subscribers/tests/reload.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{env, fs}; diff --git a/crates/test-cluster/Cargo.toml b/crates/test-cluster/Cargo.toml index cbb98e51e22..b173a774c5c 100644 --- a/crates/test-cluster/Cargo.toml +++ b/crates/test-cluster/Cargo.toml @@ -13,27 +13,27 @@ tracing.workspace = true jsonrpsee.workspace = true tokio = { workspace = true, features = ["full", "tracing", "test-util"] } rand.workspace = true -sui-config.workspace = true -sui-core = { workspace = true, features = ["test-utils"] } -sui-framework.workspace = true -sui-swarm-config.workspace = true -sui-json-rpc.workspace = true -sui-json-rpc-types.workspace = true -sui-node.workspace = true -sui-protocol-config.workspace = true -sui-swarm.workspace = true -sui-types = { workspace = true, features = ["test-utils"] } +iota-config.workspace = true +iota-core = { workspace = true, features = ["test-utils"] } +iota-framework.workspace = true +iota-swarm-config.workspace = true +iota-json-rpc.workspace = true +iota-json-rpc-types.workspace = true +iota-node.workspace = true +iota-protocol-config.workspace = true +iota-swarm.workspace = true +iota-types = { workspace = true, features = ["test-utils"] } prometheus.workspace = true -sui-keys.workspace = true -sui-sdk.workspace = true -sui-test-transaction-builder.workspace = true +iota-keys.workspace = true +iota-sdk.workspace = true +iota-test-transaction-builder.workspace = true move-binary-format.workspace = true [target.'cfg(msim)'.dependencies] -sui-simulator.workspace = true +iota-simulator.workspace = true fastcrypto-zkp.workspace = true [dev-dependencies] -sui-json-rpc-api.workspace = true -sui-macros.workspace = true +iota-json-rpc-api.workspace = true +iota-macros.workspace = true diff --git a/crates/test-cluster/src/lib.rs b/crates/test-cluster/src/lib.rs index 603371f02df..30d76eda2d8 100644 --- a/crates/test-cluster/src/lib.rs +++ b/crates/test-cluster/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ @@ -11,55 +12,55 @@ use std::{ }; use futures::{future::join_all, StreamExt}; -use jsonrpsee::{ - http_client::{HttpClient, HttpClientBuilder}, - ws_client::{WsClient, WsClientBuilder}, -}; -use rand::{distributions::*, rngs::OsRng, seq::SliceRandom}; -use sui_config::{ +use iota_config::{ node::{AuthorityOverloadConfig, DBCheckpointConfig, RunWithRange}, - Config, NodeConfig, PersistedConfig, SUI_CLIENT_CONFIG, SUI_KEYSTORE_FILENAME, - SUI_NETWORK_CONFIG, + Config, NodeConfig, PersistedConfig, IOTA_CLIENT_CONFIG, IOTA_KEYSTORE_FILENAME, + IOTA_NETWORK_CONFIG, }; -use sui_core::{ +use iota_core::{ authority_aggregator::AuthorityAggregator, authority_client::NetworkAuthorityClient, }; -use sui_json_rpc_types::{ - SuiTransactionBlockEffectsAPI, SuiTransactionBlockResponse, TransactionFilter, +use iota_json_rpc_types::{ + IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponse, TransactionFilter, }; -use sui_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; -use sui_node::SuiNodeHandle; -use sui_protocol_config::{ProtocolVersion, SupportedProtocolVersions}; -use sui_sdk::{ - sui_client_config::{SuiClientConfig, SuiEnv}, +use iota_keys::keystore::{AccountKeystore, FileBasedKeystore, Keystore}; +use iota_node::IotaNodeHandle; +use iota_protocol_config::{ProtocolVersion, SupportedProtocolVersions}; +use iota_sdk::{ + iota_client_config::{IotaClientConfig, IotaEnv}, wallet_context::WalletContext, - SuiClient, SuiClientBuilder, + IotaClient, IotaClientBuilder, }; -use sui_swarm::memory::{Swarm, SwarmBuilder}; -use sui_swarm_config::{ +use iota_swarm::memory::{Swarm, SwarmBuilder}; +use iota_swarm_config::{ genesis_config::{AccountConfig, GenesisConfig, ValidatorGenesisConfig, DEFAULT_GAS_AMOUNT}, network_config::NetworkConfig, network_config_builder::{ProtocolVersionsConfig, SupportedProtocolVersionsCallback}, node_config_builder::{FullnodeConfigBuilder, ValidatorConfigBuilder}, }; -use sui_test_transaction_builder::TestTransactionBuilder; -use sui_types::{ - base_types::{AuthorityName, ConciseableName, ObjectID, ObjectRef, SuiAddress}, +use iota_test_transaction_builder::TestTransactionBuilder; +use iota_types::{ + base_types::{AuthorityName, ConciseableName, IotaAddress, ObjectID, ObjectRef}, committee::{Committee, CommitteeTrait, EpochId}, - crypto::{KeypairTraits, SuiKeyPair}, + crypto::{IotaKeyPair, KeypairTraits}, effects::{TransactionEffects, TransactionEvents}, - error::SuiResult, - governance::MIN_VALIDATOR_JOINING_STAKE_MIST, + error::IotaResult, + governance::MIN_VALIDATOR_JOINING_STAKE_MICROS, + iota_system_state::{ + epoch_start_iota_system_state::EpochStartSystemStateTrait, IotaSystemState, + IotaSystemStateTrait, + }, message_envelope::Message, object::Object, - sui_system_state::{ - epoch_start_sui_system_state::EpochStartSystemStateTrait, SuiSystemState, - SuiSystemStateTrait, - }, transaction::{ CertifiedTransaction, Transaction, TransactionData, TransactionDataAPI, TransactionKind, }, }; +use jsonrpsee::{ + http_client::{HttpClient, HttpClientBuilder}, + ws_client::{WsClient, WsClientBuilder}, +}; +use rand::{distributions::*, rngs::OsRng, seq::SliceRandom}; use tokio::{ task::JoinHandle, time::{sleep, timeout, Instant}, @@ -69,24 +70,24 @@ use tracing::{error, info}; const NUM_VALIDATOR: usize = 4; pub struct FullNodeHandle { - pub sui_node: SuiNodeHandle, - pub sui_client: SuiClient, + pub iota_node: IotaNodeHandle, + pub iota_client: IotaClient, pub rpc_client: HttpClient, pub rpc_url: String, pub ws_url: String, } impl FullNodeHandle { - pub async fn new(sui_node: SuiNodeHandle, json_rpc_address: SocketAddr) -> Self { + pub async fn new(iota_node: IotaNodeHandle, json_rpc_address: SocketAddr) -> Self { let rpc_url = format!("http://{}", json_rpc_address); let rpc_client = HttpClientBuilder::default().build(&rpc_url).unwrap(); let ws_url = format!("ws://{}", json_rpc_address); - let sui_client = SuiClientBuilder::default().build(&rpc_url).await.unwrap(); + let iota_client = IotaClientBuilder::default().build(&rpc_url).await.unwrap(); Self { - sui_node, - sui_client, + iota_node, + iota_client, rpc_client, rpc_url, ws_url, @@ -112,8 +113,8 @@ impl TestCluster { &self.fullnode_handle.rpc_client } - pub fn sui_client(&self) -> &SuiClient { - &self.fullnode_handle.sui_client + pub fn iota_client(&self) -> &IotaClient { + &self.fullnode_handle.iota_client } pub fn rpc_url(&self) -> &str { @@ -124,22 +125,22 @@ impl TestCluster { &mut self.wallet } - pub fn get_addresses(&self) -> Vec { + pub fn get_addresses(&self) -> Vec { self.wallet.get_addresses() } // Helper function to get the 0th address in WalletContext - pub fn get_address_0(&self) -> SuiAddress { + pub fn get_address_0(&self) -> IotaAddress { self.get_addresses()[0] } // Helper function to get the 1st address in WalletContext - pub fn get_address_1(&self) -> SuiAddress { + pub fn get_address_1(&self) -> IotaAddress { self.get_addresses()[1] } // Helper function to get the 2nd address in WalletContext - pub fn get_address_2(&self) -> SuiAddress { + pub fn get_address_2(&self) -> IotaAddress { self.get_addresses()[2] } @@ -149,7 +150,7 @@ impl TestCluster { pub fn committee(&self) -> Arc { self.fullnode_handle - .sui_node + .iota_node .with(|node| node.state().epoch_store_for_testing().committee().clone()) } @@ -168,14 +169,14 @@ impl TestCluster { FullNodeHandle::new(node, json_rpc_address).await } - pub fn all_node_handles(&self) -> Vec { + pub fn all_node_handles(&self) -> Vec { self.swarm .all_nodes() .map(|n| n.get_node_handle().unwrap()) .collect() } - pub fn all_validator_handles(&self) -> Vec { + pub fn all_validator_handles(&self) -> Vec { self.swarm .validator_nodes() .map(|n| n.get_node_handle().unwrap()) @@ -218,7 +219,7 @@ impl TestCluster { pub async fn spawn_new_validator( &mut self, genesis_config: ValidatorGenesisConfig, - ) -> SuiNodeHandle { + ) -> IotaNodeHandle { let node_config = ValidatorConfigBuilder::new() .build(genesis_config, self.swarm.config().genesis.clone()); self.swarm.spawn_new_node(node_config).await @@ -229,7 +230,7 @@ impl TestCluster { } pub async fn get_reference_gas_price(&self) -> u64 { - self.sui_client() + self.iota_client() .governance_api() .get_reference_gas_price() .await @@ -238,7 +239,7 @@ impl TestCluster { pub async fn get_object_from_fullnode_store(&self, object_id: &ObjectID) -> Option { self.fullnode_handle - .sui_node + .iota_node .with_async(|node| async { node.state().get_object(object_id).await.unwrap() }) .await } @@ -255,7 +256,7 @@ impl TestCluster { object_id: ObjectID, ) -> ObjectRef { self.fullnode_handle - .sui_node + .iota_node .state() .get_cache_reader() .get_latest_object_ref_or_tombstone(object_id) @@ -270,7 +271,7 @@ impl TestCluster { /// If target_epoch is None, wait until the cluster reaches the next epoch. /// Note that this function does not guarantee that every node is at the /// target epoch. - pub async fn wait_for_epoch(&self, target_epoch: Option) -> SuiSystemState { + pub async fn wait_for_epoch(&self, target_epoch: Option) -> IotaSystemState { self.wait_for_epoch_with_timeout(target_epoch, Duration::from_secs(60)) .await } @@ -279,10 +280,10 @@ impl TestCluster { &self, target_epoch: Option, timeout_dur: Duration, - ) -> SuiSystemState { + ) -> IotaSystemState { let mut epoch_rx = self .fullnode_handle - .sui_node + .iota_node .with(|node| node.subscribe_to_epoch_change()); let mut state = Option::None; timeout(timeout_dur, async { @@ -321,7 +322,7 @@ impl TestCluster { ) -> Option { let mut shutdown_channel_rx = self .fullnode_handle - .sui_node + .iota_node .with(|node| node.subscribe_to_shutdown_channel()); timeout(timeout_dur, async move { @@ -332,7 +333,7 @@ impl TestCluster { Ok(Some(run_with_range)) => Some(run_with_range), Ok(None) => None, Err(e) => { - error!("failed recv from sui-node shutdown channel: {}", e); + error!("failed recv from iota-node shutdown channel: {}", e); None }, } @@ -340,13 +341,13 @@ impl TestCluster { } }) .await - .expect("Timed out waiting for cluster to hit target epoch and recv shutdown signal from sui-node") + .expect("Timed out waiting for cluster to hit target epoch and recv shutdown signal from iota-node") } pub async fn wait_for_protocol_version( &self, target_protocol_version: ProtocolVersion, - ) -> SuiSystemState { + ) -> IotaSystemState { self.wait_for_protocol_version_with_timeout( target_protocol_version, Duration::from_secs(60), @@ -358,7 +359,7 @@ impl TestCluster { &self, target_protocol_version: ProtocolVersion, timeout_dur: Duration, - ) -> SuiSystemState { + ) -> IotaSystemState { timeout(timeout_dur, async move { loop { let system_state = self.wait_for_epoch(None).await; @@ -381,7 +382,7 @@ impl TestCluster { // Close epoch on 2f+1 validators. let cur_committee = self .fullnode_handle - .sui_node + .iota_node .with(|node| node.state().clone_committee_for_testing()); let mut cur_stake = 0; for node in self.swarm.active_validators() { @@ -486,26 +487,30 @@ impl TestCluster { pub async fn wait_for_authenticator_state_update(&self) { timeout( Duration::from_secs(60), - self.fullnode_handle.sui_node.with_async(|node| async move { - let mut txns = node.state().subscription_handler.subscribe_transactions( - TransactionFilter::ChangedObject(ObjectID::from_hex_literal("0x7").unwrap()), - ); - let state = node.state(); - - while let Some(tx) = txns.next().await { - let digest = *tx.transaction_digest(); - let tx = state - .get_cache_reader() - .get_transaction_block(&digest) - .unwrap() - .unwrap(); - match &tx.data().intent_message().value.kind() { - TransactionKind::EndOfEpochTransaction(_) => (), - TransactionKind::AuthenticatorStateUpdate(_) => break, - _ => panic!("{:?}", tx), + self.fullnode_handle + .iota_node + .with_async(|node| async move { + let mut txns = node.state().subscription_handler.subscribe_transactions( + TransactionFilter::ChangedObject( + ObjectID::from_hex_literal("0x7").unwrap(), + ), + ); + let state = node.state(); + + while let Some(tx) = txns.next().await { + let digest = *tx.transaction_digest(); + let tx = state + .get_cache_reader() + .get_transaction_block(&digest) + .unwrap() + .unwrap(); + match &tx.data().intent_message().value.kind() { + TransactionKind::EndOfEpochTransaction(_) => (), + TransactionKind::AuthenticatorStateUpdate(_) => break, + _ => panic!("{:?}", tx), + } } - } - }), + }), ) .await .expect("Timed out waiting for authenticator state update"); @@ -519,7 +524,7 @@ impl TestCluster { pub async fn test_transaction_builder_with_sender( &self, - sender: SuiAddress, + sender: IotaAddress, ) -> TestTransactionBuilder { let gas = self .wallet @@ -533,7 +538,7 @@ impl TestCluster { pub async fn test_transaction_builder_with_gas_object( &self, - sender: SuiAddress, + sender: IotaAddress, gas: ObjectRef, ) -> TestTransactionBuilder { let rgp = self.get_reference_gas_price().await; @@ -547,7 +552,7 @@ impl TestCluster { pub async fn sign_and_execute_transaction( &self, tx_data: &TransactionData, - ) -> SuiTransactionBlockResponse { + ) -> IotaTransactionBlockResponse { let tx = self.wallet.sign_transaction(tx_data); self.execute_transaction(tx).await } @@ -556,7 +561,7 @@ impl TestCluster { /// the rpc fullnode. Also expects the effects status to be /// ExecutionStatus::Success. This function is recommended for /// transaction execution since it most resembles the production path. - pub async fn execute_transaction(&self, tx: Transaction) -> SuiTransactionBlockResponse { + pub async fn execute_transaction(&self, tx: Transaction) -> IotaTransactionBlockResponse { self.wallet.execute_transaction_must_succeed(tx).await } @@ -583,7 +588,7 @@ impl TestCluster { pub fn authority_aggregator(&self) -> Arc> { self.fullnode_handle - .sui_node + .iota_node .with(|node| node.clone_authority_aggregator().unwrap()) } @@ -638,7 +643,7 @@ impl TestCluster { break replies; } }; - let replies: SuiResult> = replies.into_iter().collect(); + let replies: IotaResult> = replies.into_iter().collect(); let replies = replies?; let mut all_effects = HashMap::new(); let mut all_events = HashMap::new(); @@ -663,13 +668,13 @@ impl TestCluster { &self, rgp: u64, amount: Option, - funding_address: SuiAddress, + funding_address: IotaAddress, ) -> ObjectRef { let context = &self.wallet; let (sender, gas) = context.get_one_gas_object().await.unwrap().unwrap(); let tx = context.sign_transaction( &TestTransactionBuilder::new(sender, gas, rgp) - .transfer_sui(amount, funding_address) + .transfer_iota(amount, funding_address) .build(), ); context.execute_transaction_must_succeed(tx).await; @@ -910,13 +915,13 @@ impl TestClusterBuilder { pub fn with_validator_candidates( mut self, - addresses: impl IntoIterator, + addresses: impl IntoIterator, ) -> Self { self.get_or_init_genesis_config() .accounts .extend(addresses.into_iter().map(|address| AccountConfig { address: Some(address), - gas_amounts: vec![DEFAULT_GAS_AMOUNT, MIN_VALIDATOR_JOINING_STAKE_MIST], + gas_amounts: vec![DEFAULT_GAS_AMOUNT, MIN_VALIDATOR_JOINING_STAKE_MICROS], })); self } @@ -958,7 +963,7 @@ impl TestClusterBuilder { // supply valid JWKs as well. #[cfg(msim)] if !self.default_jwks { - sui_node::set_jwk_injector(Arc::new(|_authority, provider| { + iota_node::set_jwk_injector(Arc::new(|_authority, provider| { use fastcrypto_zkp::bn254::zk_login::{JwkId, JWK}; use rand::Rng; @@ -985,15 +990,15 @@ impl TestClusterBuilder { let swarm = self.start_swarm().await.unwrap(); let working_dir = swarm.dir(); - let mut wallet_conf: SuiClientConfig = - PersistedConfig::read(&working_dir.join(SUI_CLIENT_CONFIG)).unwrap(); + let mut wallet_conf: IotaClientConfig = + PersistedConfig::read(&working_dir.join(IOTA_CLIENT_CONFIG)).unwrap(); let fullnode = swarm.fullnodes().next().unwrap(); let json_rpc_address = fullnode.config.json_rpc_address; let fullnode_handle = FullNodeHandle::new(fullnode.get_node_handle().unwrap(), json_rpc_address).await; - wallet_conf.envs.push(SuiEnv { + wallet_conf.envs.push(IotaEnv { alias: "localnet".to_string(), rpc: fullnode_handle.rpc_url.clone(), ws: Some(fullnode_handle.ws_url.clone()), @@ -1001,11 +1006,11 @@ impl TestClusterBuilder { wallet_conf.active_env = Some("localnet".to_string()); wallet_conf - .persisted(&working_dir.join(SUI_CLIENT_CONFIG)) + .persisted(&working_dir.join(IOTA_CLIENT_CONFIG)) .save() .unwrap(); - let wallet_conf = swarm.dir().join(SUI_CLIENT_CONFIG); + let wallet_conf = swarm.dir().join(IOTA_CLIENT_CONFIG); let wallet = WalletContext::new(&wallet_conf, None, None).unwrap(); TestCluster { @@ -1071,20 +1076,20 @@ impl TestClusterBuilder { let dir = swarm.dir(); - let network_path = dir.join(SUI_NETWORK_CONFIG); - let wallet_path = dir.join(SUI_CLIENT_CONFIG); - let keystore_path = dir.join(SUI_KEYSTORE_FILENAME); + let network_path = dir.join(IOTA_NETWORK_CONFIG); + let wallet_path = dir.join(IOTA_CLIENT_CONFIG); + let keystore_path = dir.join(IOTA_KEYSTORE_FILENAME); swarm.config().save(network_path)?; let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path)?); for key in &swarm.config().account_keys { - keystore.add_key(None, SuiKeyPair::Ed25519(key.copy()))?; + keystore.add_key(None, IotaKeyPair::Ed25519(key.copy()))?; } let active_address = keystore.addresses().first().cloned(); // Create wallet config with stated authorities port - SuiClientConfig { + IotaClientConfig { keystore: Keystore::from(FileBasedKeystore::new(&keystore_path)?), envs: Default::default(), active_address, diff --git a/crates/test-cluster/tests/network_tests.rs b/crates/test-cluster/tests/network_tests.rs index 14d28075748..f3fee28a131 100644 --- a/crates/test-cluster/tests/network_tests.rs +++ b/crates/test-cluster/tests/network_tests.rs @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use move_binary_format::access::ModuleAccess; -use sui_framework::BuiltInFramework; -use sui_json_rpc_api::ReadApiClient; -use sui_json_rpc_types::SuiObjectResponse; -use sui_macros::sim_test; -use sui_types::{ - base_types::ObjectID, digests::TransactionDigest, object::Object, MOVE_STDLIB_PACKAGE_ID, - SUI_FRAMEWORK_PACKAGE_ID, SUI_SYSTEM_ADDRESS, SUI_SYSTEM_PACKAGE_ID, +use iota_framework::BuiltInFramework; +use iota_json_rpc_api::ReadApiClient; +use iota_json_rpc_types::IotaObjectResponse; +use iota_macros::sim_test; +use iota_types::{ + base_types::ObjectID, digests::TransactionDigest, object::Object, IOTA_FRAMEWORK_PACKAGE_ID, + IOTA_SYSTEM_ADDRESS, IOTA_SYSTEM_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID, }; +use move_binary_format::access::ModuleAccess; use test_cluster::TestClusterBuilder; #[sim_test] @@ -23,7 +24,7 @@ async fn test_additional_objects() { let client = cluster.rpc_client(); let resp = client.get_object(id, None).await.unwrap(); - assert!(matches!(resp, SuiObjectResponse { data: Some(_), .. })); + assert!(matches!(resp, IotaObjectResponse { data: Some(_), .. })); } #[sim_test] @@ -33,7 +34,7 @@ async fn test_package_override() { let default_cluster = TestClusterBuilder::new().build().await; let client = default_cluster.rpc_client(); let obj = client - .get_object(SUI_SYSTEM_PACKAGE_ID, None) + .get_object(IOTA_SYSTEM_PACKAGE_ID, None) .await .unwrap(); @@ -45,17 +46,17 @@ async fn test_package_override() { }; let modified_ref = { - let mut framework_modules = BuiltInFramework::get_package_by_id(&SUI_SYSTEM_PACKAGE_ID) + let mut framework_modules = BuiltInFramework::get_package_by_id(&IOTA_SYSTEM_PACKAGE_ID) .modules() .to_vec(); - // Create an empty module that is pretending to be part of the sui framework. + // Create an empty module that is pretending to be part of the iota framework. let mut test_module = move_binary_format::file_format::empty_module(); let address_idx = test_module.self_handle().address.0 as usize; - test_module.address_identifiers[address_idx] = SUI_SYSTEM_ADDRESS; + test_module.address_identifiers[address_idx] = IOTA_SYSTEM_ADDRESS; - // Add the dummy module to the rest of the sui-frameworks. We can't replace the - // framework entirely because we will call into it for genesis. + // Add the dummy module to the rest of the iota-frameworks. We can't replace + // the framework entirely because we will call into it for genesis. framework_modules.push(test_module); let package_override = Object::new_package_for_testing( @@ -63,7 +64,7 @@ async fn test_package_override() { TransactionDigest::genesis_marker(), [ BuiltInFramework::get_package_by_id(&MOVE_STDLIB_PACKAGE_ID).genesis_move_package(), - BuiltInFramework::get_package_by_id(&SUI_FRAMEWORK_PACKAGE_ID) + BuiltInFramework::get_package_by_id(&IOTA_FRAMEWORK_PACKAGE_ID) .genesis_move_package(), ], ) @@ -76,7 +77,7 @@ async fn test_package_override() { let client = modified_cluster.rpc_client(); let obj = client - .get_object(SUI_SYSTEM_PACKAGE_ID, None) + .get_object(IOTA_SYSTEM_PACKAGE_ID, None) .await .unwrap(); diff --git a/crates/transaction-fuzzer/Cargo.toml b/crates/transaction-fuzzer/Cargo.toml index 15fe64e0735..64a125b1f88 100644 --- a/crates/transaction-fuzzer/Cargo.toml +++ b/crates/transaction-fuzzer/Cargo.toml @@ -16,13 +16,13 @@ tokio = { workspace = true, features = ["full"] } tracing.workspace = true once_cell.workspace = true -sui-core.workspace = true -sui-protocol-config.workspace = true -sui-types = { workspace = true, features = ["fuzzing"] } -sui-move-build.workspace = true +iota-core.workspace = true +iota-protocol-config.workspace = true +iota-types = { workspace = true, features = ["fuzzing"] } +iota-move-build.workspace = true [dev-dependencies] -sui-core = { workspace = true, features = ["test-utils"] } -sui-protocol-config.workspace = true -sui-types = { workspace = true, features = ["test-utils"] } +iota-core = { workspace = true, features = ["test-utils"] } +iota-protocol-config.workspace = true +iota-types = { workspace = true, features = ["test-utils"] } diff --git a/crates/transaction-fuzzer/data/coin_factory/Move.toml b/crates/transaction-fuzzer/data/coin_factory/Move.toml index 53505137269..91c09e39942 100644 --- a/crates/transaction-fuzzer/data/coin_factory/Move.toml +++ b/crates/transaction-fuzzer/data/coin_factory/Move.toml @@ -2,8 +2,8 @@ name = "coin_factory" version = "0.0.1" -[dependencies.Sui] -local = "../../../sui-framework/packages/sui-framework" +[dependencies.Iota] +local = "../../../iota-framework/packages/iota-framework" [addresses] coiner = "0x0" diff --git a/crates/transaction-fuzzer/data/coin_factory/sources/coin_factory.move b/crates/transaction-fuzzer/data/coin_factory/sources/coin_factory.move index df773e1be93..4bd50c0f039 100644 --- a/crates/transaction-fuzzer/data/coin_factory/sources/coin_factory.move +++ b/crates/transaction-fuzzer/data/coin_factory/sources/coin_factory.move @@ -1,11 +1,12 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module coiner::coin_factory { use std::option; - use sui::coin::{Self, Coin, TreasuryCap}; - use sui::transfer; + use iota::coin::{Self, Coin, TreasuryCap}; + use iota::transfer; use std::vector; - use sui::tx_context::{Self, TxContext}; + use iota::tx_context::{Self, TxContext}; struct COIN_FACTORY has drop {} diff --git a/crates/transaction-fuzzer/data/type_factory/sources/type_factory.move b/crates/transaction-fuzzer/data/type_factory/sources/type_factory.move index 1f8b5172938..62bd032d89c 100644 --- a/crates/transaction-fuzzer/data/type_factory/sources/type_factory.move +++ b/crates/transaction-fuzzer/data/type_factory/sources/type_factory.move @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module typer::type_factory { diff --git a/crates/transaction-fuzzer/scripts/coin_factory_gen.py b/crates/transaction-fuzzer/scripts/coin_factory_gen.py index 7822ee531c8..aa15793e567 100755 --- a/crates/transaction-fuzzer/scripts/coin_factory_gen.py +++ b/crates/transaction-fuzzer/scripts/coin_factory_gen.py @@ -14,12 +14,15 @@ f.write("// Copyright (c) Mysten Labs, Inc.\n") f.write("// SPDX-License-Identifier: Apache-2.0\n") + f.write("// Modifications Copyright (c) 2024 IOTA Stiftung + f.write("// SPDX-License-Identifier: Apache-2.0 + f.write("module coiner::coin_factory {\n") f.write(" use std::option;\n") - f.write(" use sui::coin::{Self, Coin, TreasuryCap};\n") - f.write(" use sui::transfer;\n") + f.write(" use iota::coin::{Self, Coin, TreasuryCap};\n") + f.write(" use iota::transfer;\n") f.write(" use std::vector;\n"); - f.write(" use sui::tx_context::{Self, TxContext};\n") + f.write(" use iota::tx_context::{Self, TxContext};\n") f.write("\n") f.write(" struct COIN_FACTORY has drop {}\n") f.write("\n") diff --git a/crates/transaction-fuzzer/src/account_universe.rs b/crates/transaction-fuzzer/src/account_universe.rs index f580e51dd76..65a5d73d47e 100644 --- a/crates/transaction-fuzzer/src/account_universe.rs +++ b/crates/transaction-fuzzer/src/account_universe.rs @@ -2,13 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) The Diem Core Contributors +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fmt, sync::Arc}; +use iota_types::{storage::ObjectStore, transaction::Transaction}; use once_cell::sync::Lazy; use proptest::{prelude::*, strategy::Union}; -use sui_types::{storage::ObjectStore, transaction::Transaction}; use crate::executor::{ExecutionResult, Executor}; @@ -141,15 +142,15 @@ pub fn assert_accounts_match( for (idx, account) in universe.accounts().iter().enumerate() { for (balance_idx, acc_object) in account.current_coins.iter().enumerate() { let object = object_store.get_object(&acc_object.id()).unwrap().unwrap(); - let total_sui_value = - object.get_total_sui(layout_resolver.as_mut()).unwrap() - object.storage_rebate; + let total_iota_value = + object.get_total_iota(layout_resolver.as_mut()).unwrap() - object.storage_rebate; let account_balance_i = account.current_balances[balance_idx]; prop_assert_eq!( account_balance_i, - total_sui_value, + total_iota_value, "account {} should have correct balance {} for object {} but got {}", idx, - total_sui_value, + total_iota_value, acc_object.id(), account_balance_i ); diff --git a/crates/transaction-fuzzer/src/account_universe/account.rs b/crates/transaction-fuzzer/src/account_universe/account.rs index 10f45eed5ac..fe0d37c914b 100644 --- a/crates/transaction-fuzzer/src/account_universe/account.rs +++ b/crates/transaction-fuzzer/src/account_universe/account.rs @@ -2,16 +2,17 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) The Diem Core Contributors +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; -use proptest::prelude::*; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, +use iota_types::{ + base_types::{IotaAddress, ObjectID}, crypto::{get_key_pair, AccountKeyPair}, object::Object, }; +use proptest::prelude::*; use crate::executor::Executor; @@ -21,7 +22,7 @@ pub const NUM_GAS_OBJECTS: usize = 1; #[derive(Debug)] pub struct Account { - pub address: SuiAddress, + pub address: IotaAddress, pub key: AccountKeyPair, } diff --git a/crates/transaction-fuzzer/src/account_universe/helpers.rs b/crates/transaction-fuzzer/src/account_universe/helpers.rs index 3644d4259a1..acec9a0b5ac 100644 --- a/crates/transaction-fuzzer/src/account_universe/helpers.rs +++ b/crates/transaction-fuzzer/src/account_universe/helpers.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) The Diem Core Contributors +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/transaction-fuzzer/src/account_universe/transfer_gen.rs b/crates/transaction-fuzzer/src/account_universe/transfer_gen.rs index 856785420ea..c677cc147fb 100644 --- a/crates/transaction-fuzzer/src/account_universe/transfer_gen.rs +++ b/crates/transaction-fuzzer/src/account_universe/transfer_gen.rs @@ -2,23 +2,24 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) The Diem Core Contributors +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; -use once_cell::sync::Lazy; -use proptest::prelude::*; -use proptest_derive::Arbitrary; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ - base_types::{ObjectRef, SuiAddress}, - error::{SuiError, UserInputError}, +use iota_protocol_config::ProtocolConfig; +use iota_types::{ + base_types::{IotaAddress, ObjectRef}, + error::{IotaError, UserInputError}, execution_status::{ExecutionFailureStatus, ExecutionStatus}, object::Object, programmable_transaction_builder::ProgrammableTransactionBuilder, transaction::{GasData, Transaction, TransactionData, TransactionKind}, utils::{to_sender_signed_transaction, to_sender_signed_transaction_with_multi_signers}, }; +use once_cell::sync::Lazy; +use proptest::prelude::*; +use proptest_derive::Arbitrary; use crate::{ account_universe::{ @@ -130,7 +131,7 @@ impl TransactionSponsorship { accounts: &mut AccountTriple, exec: &mut Executor, gas_coins: u32, - ) -> (Vec, (u64, Object), SuiAddress) { + ) -> (Vec, (u64, Object), IotaAddress) { match self { TransactionSponsorship::None => { let gas_object = accounts.account_1.new_gas_object(exec); @@ -407,10 +408,10 @@ impl AUTransactionGen for P2PTransferGenRandomGasRandomPriceRandomSponsorship { account_2: recipient, .. } = &account_triple; - // construct a p2p transfer of a random amount of SUI + // construct a p2p transfer of a random amount of IOTA let txn = { let mut builder = ProgrammableTransactionBuilder::new(); - builder.transfer_sui(recipient.initial_data.account.address, Some(self.amount)); + builder.transfer_iota(recipient.initial_data.account.address, Some(self.amount)); builder.finish() }; let sender_address = sender.initial_data.account.address; @@ -450,7 +451,7 @@ impl AUTransactionGen for P2PTransferGenRandomGasRandomPriceRandomSponsorship { RunInfo { too_many_gas_coins: true, .. - } => Err(SuiError::UserInputError { + } => Err(IotaError::UserInputError { error: UserInputError::SizeLimitExceeded { limit: "maximum number of gas payment objects".to_string(), value: "256".to_string(), @@ -459,7 +460,7 @@ impl AUTransactionGen for P2PTransferGenRandomGasRandomPriceRandomSponsorship { RunInfo { gas_price_too_low: true, .. - } => Err(SuiError::UserInputError { + } => Err(IotaError::UserInputError { error: UserInputError::GasPriceUnderRGP { gas_price: self.gas_price, reference_gas_price: exec.get_reference_gas_price(), @@ -468,7 +469,7 @@ impl AUTransactionGen for P2PTransferGenRandomGasRandomPriceRandomSponsorship { RunInfo { gas_price_too_high: true, .. - } => Err(SuiError::UserInputError { + } => Err(IotaError::UserInputError { error: UserInputError::GasPriceTooHigh { max_gas_price: PROTOCOL_CONFIG.max_gas_price(), }, @@ -476,7 +477,7 @@ impl AUTransactionGen for P2PTransferGenRandomGasRandomPriceRandomSponsorship { RunInfo { gas_budget_too_low: true, .. - } => Err(SuiError::UserInputError { + } => Err(IotaError::UserInputError { error: UserInputError::GasBudgetTooLow { gas_budget: self.gas, min_budget: PROTOCOL_CONFIG.base_tx_cost_fixed() * self.gas_price, @@ -485,7 +486,7 @@ impl AUTransactionGen for P2PTransferGenRandomGasRandomPriceRandomSponsorship { RunInfo { gas_budget_too_high: true, .. - } => Err(SuiError::UserInputError { + } => Err(IotaError::UserInputError { error: UserInputError::GasBudgetTooHigh { gas_budget: self.gas, max_budget: PROTOCOL_CONFIG.max_tx_gas(), @@ -494,7 +495,7 @@ impl AUTransactionGen for P2PTransferGenRandomGasRandomPriceRandomSponsorship { RunInfo { enough_max_gas: false, .. - } => Err(SuiError::UserInputError { + } => Err(IotaError::UserInputError { error: UserInputError::GasBalanceTooLow { gas_balance: gas_balance as u128, needed_gas_amount: self.gas as u128, @@ -503,7 +504,7 @@ impl AUTransactionGen for P2PTransferGenRandomGasRandomPriceRandomSponsorship { RunInfo { wrong_gas_owner: true, .. - } => Err(SuiError::UserInputError { + } => Err(IotaError::UserInputError { error: UserInputError::IncorrectUserSignature { error: format!( "Object {} is owned by account address {}, but given owner/signer address is {}", diff --git a/crates/transaction-fuzzer/src/account_universe/universe.rs b/crates/transaction-fuzzer/src/account_universe/universe.rs index 483de4e4354..f5059d00a84 100644 --- a/crates/transaction-fuzzer/src/account_universe/universe.rs +++ b/crates/transaction-fuzzer/src/account_universe/universe.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) The Diem Core Contributors +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use proptest::{ diff --git a/crates/transaction-fuzzer/src/config_fuzzer.rs b/crates/transaction-fuzzer/src/config_fuzzer.rs index 7a24866e034..6032dc29e3a 100644 --- a/crates/transaction-fuzzer/src/config_fuzzer.rs +++ b/crates/transaction-fuzzer/src/config_fuzzer.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use crate::{ diff --git a/crates/transaction-fuzzer/src/executor.rs b/crates/transaction-fuzzer/src/executor.rs index 1eef2234f7f..60f29bcba05 100644 --- a/crates/transaction-fuzzer/src/executor.rs +++ b/crates/transaction-fuzzer/src/executor.rs @@ -2,19 +2,20 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) The Diem Core Contributors +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fmt::Debug, path::PathBuf, sync::Arc}; -use sui_core::{ +use iota_core::{ authority::{test_authority_builder::TestAuthorityBuilder, AuthorityState}, test_utils::send_and_confirm_transaction, }; -use sui_move_build::BuildConfig; -use sui_types::{ +use iota_move_build::BuildConfig; +use iota_types::{ base_types::ObjectID, effects::{TransactionEffects, TransactionEffectsAPI}, - error::SuiError, + error::IotaError, execution_status::{ExecutionFailureStatus, ExecutionStatus}, object::Object, transaction::{Transaction, TransactionData}, @@ -24,7 +25,7 @@ use tokio::runtime::Runtime; use crate::account_universe::{AccountCurrent, PUBLISH_BUDGET}; -pub type ExecutionResult = Result; +pub type ExecutionResult = Result; fn build_test_modules(test_dir: &str) -> (Vec, Vec>) { let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); diff --git a/crates/transaction-fuzzer/src/lib.rs b/crates/transaction-fuzzer/src/lib.rs index 78f72aca3b8..1d9b7034015 100644 --- a/crates/transaction-fuzzer/src/lib.rs +++ b/crates/transaction-fuzzer/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 pub mod account_universe; @@ -11,17 +12,17 @@ pub mod type_arg_fuzzer; use std::fmt::Debug; use executor::Executor; -use proptest::{collection::vec, prelude::*, test_runner::TestRunner}; -use rand::{rngs::StdRng, SeedableRng}; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ - base_types::{ObjectID, SuiAddress}, +use iota_protocol_config::ProtocolConfig; +use iota_types::{ + base_types::{IotaAddress, ObjectID}, crypto::{get_key_pair, AccountKeyPair}, digests::TransactionDigest, - gas_coin::TOTAL_SUPPLY_MIST, + gas_coin::TOTAL_SUPPLY_MICROS, object::{MoveObject, Object, Owner, OBJECT_START_VERSION}, transaction::GasData, }; +use proptest::{collection::vec, prelude::*, test_runner::TestRunner}; +use rand::{rngs::StdRng, SeedableRng}; fn new_gas_coin_with_balance_and_owner(balance: u64, owner: Owner) -> Object { Object::new_move( @@ -39,12 +40,12 @@ fn generate_random_gas_data( * obj-owned too */ owned_by_sender: bool, // whether to set owned gas coins to be owned by the sender ) -> GasDataWithObjects { - let (sender, sender_key): (SuiAddress, AccountKeyPair) = get_key_pair(); + let (sender, sender_key): (IotaAddress, AccountKeyPair) = get_key_pair(); let mut rng = StdRng::from_seed(seed); let mut gas_objects = vec![]; let mut object_refs = vec![]; - let max_gas_balance = TOTAL_SUPPLY_MIST; + let max_gas_balance = TOTAL_SUPPLY_MICROS; let total_gas_balance = rng.gen_range(0..=max_gas_balance); let mut remaining_gas_balance = total_gas_balance; diff --git a/crates/transaction-fuzzer/src/programmable_transaction_gen.rs b/crates/transaction-fuzzer/src/programmable_transaction_gen.rs index 3a5b3908646..d9dd71e583b 100644 --- a/crates/transaction-fuzzer/src/programmable_transaction_gen.rs +++ b/crates/transaction-fuzzer/src/programmable_transaction_gen.rs @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{cmp, str::FromStr}; -use move_core_types::identifier::Identifier; -use once_cell::sync::Lazy; -use proptest::{collection::vec, prelude::*}; -use sui_protocol_config::ProtocolConfig; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SuiAddress}, +use iota_protocol_config::ProtocolConfig; +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef}, programmable_transaction_builder::ProgrammableTransactionBuilder, transaction::{Argument, CallArg, Command, ProgrammableTransaction}, }; +use move_core_types::identifier::Identifier; +use once_cell::sync::Lazy; +use proptest::{collection::vec, prelude::*}; static PROTOCOL_CONFIG: Lazy = Lazy::new(ProtocolConfig::get_for_max_version_UNSAFE); @@ -185,7 +186,7 @@ pub fn arg_len_strategy_input_match() -> impl Strategy { } prop_compose! { - pub fn gen_many_input_match(recipient: SuiAddress, package: ObjectID, cap: ObjectRef) + pub fn gen_many_input_match(recipient: IotaAddress, package: ObjectID, cap: ObjectRef) (mut command_sketches in vec(gen_command_input_match(), 1..=MAX_COMMANDS_INPUT_MATCH)) -> ProgrammableTransaction { let mut builder = ProgrammableTransactionBuilder::new(); let mut prev_cmd_num = -1; @@ -210,7 +211,7 @@ fn gen_input( prev_command: Option<&CommandSketch>, cmd: &CommandSketch, prev_cmd_num: i64, - recipient: SuiAddress, + recipient: IotaAddress, package: ObjectID, cap: ObjectRef, ) -> (Command, i64) { @@ -241,7 +242,7 @@ pub fn gen_transfer_input( prev_command: Option<&CommandSketch>, cmd: &CommandSketch, prev_cmd_num: i64, - recipient: SuiAddress, + recipient: IotaAddress, package: ObjectID, cap: ObjectRef, ) -> (Command, i64) { diff --git a/crates/transaction-fuzzer/src/transaction_data_gen.rs b/crates/transaction-fuzzer/src/transaction_data_gen.rs index 0c6d56fff36..e0f54271016 100644 --- a/crates/transaction-fuzzer/src/transaction_data_gen.rs +++ b/crates/transaction-fuzzer/src/transaction_data_gen.rs @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use move_core_types::account_address::AccountAddress; -use proptest::{arbitrary::*, collection::vec, prelude::*}; -use sui_types::{ - base_types::{ObjectID, ObjectRef, SequenceNumber, SuiAddress}, +use iota_types::{ + base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber}, digests::ObjectDigest, transaction::{ GasData, TransactionData, TransactionDataV1, TransactionExpiration, TransactionKind, }, }; +use move_core_types::account_address::AccountAddress; +use proptest::{arbitrary::*, collection::vec, prelude::*}; use crate::{ account_universe::{gas_budget_selection_strategy, gas_price_selection_strategy}, @@ -45,7 +46,7 @@ pub fn gen_object_ref() -> impl Strategy { }) } -pub fn gen_gas_data(sender: SuiAddress) -> impl Strategy { +pub fn gen_gas_data(sender: IotaAddress) -> impl Strategy { ( vec(gen_object_ref(), 0..MAX_NUM_GAS_OBJS), gas_price_selection_strategy(), @@ -65,7 +66,7 @@ pub fn gen_transaction_kind() -> impl Strategy { .prop_map(TransactionKind::ProgrammableTransaction) } -pub fn transaction_data_gen(sender: SuiAddress) -> impl Strategy { +pub fn transaction_data_gen(sender: IotaAddress) -> impl Strategy { TransactionDataGenBuilder::new(sender) .kind(gen_transaction_kind()) .gas_data(gen_gas_data(sender)) @@ -79,7 +80,7 @@ pub struct TransactionDataGenBuilder< E: Strategy, > { pub kind: Option, - pub sender: SuiAddress, + pub sender: IotaAddress, pub gas_data: Option, pub expiration: Option, } @@ -90,7 +91,7 @@ impl< E: Strategy, > TransactionDataGenBuilder { - pub fn new(sender: SuiAddress) -> Self { + pub fn new(sender: IotaAddress) -> Self { Self { kind: None, sender, diff --git a/crates/transaction-fuzzer/src/type_arg_fuzzer.rs b/crates/transaction-fuzzer/src/type_arg_fuzzer.rs index a1ee8ba5708..939b58d268a 100644 --- a/crates/transaction-fuzzer/src/type_arg_fuzzer.rs +++ b/crates/transaction-fuzzer/src/type_arg_fuzzer.rs @@ -1,20 +1,21 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use move_core_types::{ - account_address::AccountAddress, identifier::Identifier, language_storage::StructTag, -}; -use proptest::{arbitrary::*, prelude::*}; -use sui_core::test_utils::send_and_confirm_transaction; -use sui_types::{ +use iota_core::test_utils::send_and_confirm_transaction; +use iota_types::{ base_types::ObjectID, effects::{TransactionEffects, TransactionEffectsAPI}, - error::SuiError, + error::IotaError, programmable_transaction_builder::ProgrammableTransactionBuilder, transaction::{ProgrammableTransaction, TransactionData, TransactionKind}, utils::to_sender_signed_transaction, - TypeTag, SUI_FRAMEWORK_PACKAGE_ID, + TypeTag, IOTA_FRAMEWORK_PACKAGE_ID, }; +use move_core_types::{ + account_address::AccountAddress, identifier::Identifier, language_storage::StructTag, +}; +use proptest::{arbitrary::*, prelude::*}; use crate::{ account_universe::AccountCurrent, @@ -140,7 +141,7 @@ pub fn pt_for_tags(type_tags: Vec) -> ProgrammableTransaction { let mut builder = ProgrammableTransactionBuilder::new(); builder .move_call( - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, Identifier::new("random_type_tag_fuzzing").unwrap(), Identifier::new("random_type_tag_fuzzing_fn").unwrap(), type_tags, @@ -160,7 +161,7 @@ pub fn run_pt_effects( account: &mut AccountCurrent, exec: &mut Executor, pt: ProgrammableTransaction, -) -> Result { +) -> Result { let gas_object = account.new_gas_object(exec); let gas_object_ref = gas_object.compute_object_reference(); let kind = TransactionKind::ProgrammableTransaction(pt); diff --git a/crates/transaction-fuzzer/tests/gas_data_tests.rs b/crates/transaction-fuzzer/tests/gas_data_tests.rs index 8db92892249..51347ed7ead 100644 --- a/crates/transaction-fuzzer/tests/gas_data_tests.rs +++ b/crates/transaction-fuzzer/tests/gas_data_tests.rs @@ -1,18 +1,19 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use proptest::{arbitrary::*, test_runner::TestCaseError}; -use sui_types::{ +use iota_types::{ base_types::dbg_addr, crypto::KeypairTraits, programmable_transaction_builder::ProgrammableTransactionBuilder, transaction::{TransactionData, TransactionKind}, utils::to_sender_signed_transaction, }; +use proptest::{arbitrary::*, test_runner::TestCaseError}; use tracing::debug; use transaction_fuzzer::{executor::Executor, run_proptest, GasDataGenConfig, GasDataWithObjects}; -/// Send transfer sui txn with provided random gas data and gas objects to an +/// Send transfer iota txn with provided random gas data and gas objects to an /// authority. fn test_with_random_gas_data( gas_data_test: GasDataWithObjects, @@ -27,7 +28,7 @@ fn test_with_random_gas_data( let pt = { let mut builder = ProgrammableTransactionBuilder::new(); let recipient = dbg_addr(2); - builder.transfer_sui(recipient, None); + builder.transfer_iota(recipient, None); builder.finish() }; let kind = TransactionKind::ProgrammableTransaction(pt); diff --git a/crates/transaction-fuzzer/tests/p2p_fuzz.rs b/crates/transaction-fuzzer/tests/p2p_fuzz.rs index 0d422ac7963..fc8364667ce 100644 --- a/crates/transaction-fuzzer/tests/p2p_fuzz.rs +++ b/crates/transaction-fuzzer/tests/p2p_fuzz.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) The Diem Core Contributors +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use proptest::{arbitrary::*, collection::vec, prelude::*}; diff --git a/crates/transaction-fuzzer/tests/pt_fuzz.rs b/crates/transaction-fuzzer/tests/pt_fuzz.rs index df53b87ef76..8ab7709a338 100644 --- a/crates/transaction-fuzzer/tests/pt_fuzz.rs +++ b/crates/transaction-fuzzer/tests/pt_fuzz.rs @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use proptest::{prelude::*, strategy::ValueTree}; -use sui_types::{ +use iota_types::{ base_types::ObjectRef, effects::TransactionEffectsAPI, execution_status::{ExecutionFailureStatus, ExecutionStatus}, object::Owner, transaction::{CallArg, ObjectArg, ProgrammableTransaction}, - MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, MOVE_STDLIB_PACKAGE_ID, }; +use proptest::{prelude::*, strategy::ValueTree}; use transaction_fuzzer::{ account_universe::{AccountCurrent, AccountData}, executor::Executor, @@ -38,7 +39,7 @@ fn publish_coin_factory( ) -> (ObjectRef, ObjectRef) { let effects = exec.publish( "coin_factory", - vec![MOVE_STDLIB_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID], + vec![MOVE_STDLIB_PACKAGE_ID, IOTA_FRAMEWORK_PACKAGE_ID], account, ); let package = effects diff --git a/crates/transaction-fuzzer/tests/rgp_fuzz.rs b/crates/transaction-fuzzer/tests/rgp_fuzz.rs index 56a22e0db8a..eb5e3b76b83 100644 --- a/crates/transaction-fuzzer/tests/rgp_fuzz.rs +++ b/crates/transaction-fuzzer/tests/rgp_fuzz.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use proptest::{collection::vec, prelude::*, proptest}; diff --git a/crates/transaction-fuzzer/tests/transaction_data_fuzz.rs b/crates/transaction-fuzzer/tests/transaction_data_fuzz.rs index e53b31155ac..66a1df34962 100644 --- a/crates/transaction-fuzzer/tests/transaction_data_fuzz.rs +++ b/crates/transaction-fuzzer/tests/transaction_data_fuzz.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_types::utils::to_sender_signed_transaction; use proptest::{prelude::*, strategy::ValueTree}; -use sui_types::utils::to_sender_signed_transaction; use transaction_fuzzer::{ account_universe::{AccountCurrent, AccountData}, executor::{assert_is_acceptable_result, Executor}, diff --git a/crates/transaction-fuzzer/tests/type_arg_fuzzer.rs b/crates/transaction-fuzzer/tests/type_arg_fuzzer.rs index 78ea80ddd90..f8378689b4e 100644 --- a/crates/transaction-fuzzer/tests/type_arg_fuzzer.rs +++ b/crates/transaction-fuzzer/tests/type_arg_fuzzer.rs @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use iota_types::{base_types::ObjectRef, effects::TransactionEffectsAPI, object::Owner}; use proptest::{collection::vec, prelude::*, strategy::ValueTree}; -use sui_types::{base_types::ObjectRef, effects::TransactionEffectsAPI, object::Owner}; use transaction_fuzzer::{ account_universe::{AccountCurrent, AccountData}, executor::Executor, diff --git a/crates/typed-store-derive/src/lib.rs b/crates/typed-store-derive/src/lib.rs index 4a3c6e3acf3..c31c4d1cdd9 100644 --- a/crates/typed-store-derive/src/lib.rs +++ b/crates/typed-store-derive/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::{BTreeMap, HashSet}; diff --git a/crates/typed-store-error/src/errors.rs b/crates/typed-store-error/src/errors.rs index 6444b2ac840..5af49e1f1dd 100644 --- a/crates/typed-store-error/src/errors.rs +++ b/crates/typed-store-error/src/errors.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use serde::{Deserialize, Serialize}; diff --git a/crates/typed-store-error/src/lib.rs b/crates/typed-store-error/src/lib.rs index d368a795c7b..e24fad7bba8 100644 --- a/crates/typed-store-error/src/lib.rs +++ b/crates/typed-store-error/src/lib.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #![warn( future_incompatible, diff --git a/crates/typed-store/Cargo.toml b/crates/typed-store/Cargo.toml index b345928c802..cbc15236349 100644 --- a/crates/typed-store/Cargo.toml +++ b/crates/typed-store/Cargo.toml @@ -24,7 +24,7 @@ thiserror.workspace = true tokio = { workspace = true, features = ["full", "test-util"] } tracing.workspace = true typed-store-error.workspace = true -sui-macros.workspace = true +iota-macros.workspace = true ouroboros.workspace = true rand.workspace = true async-trait.workspace = true @@ -41,7 +41,7 @@ syn.workspace = true typed-store-derive.workspace = true uint.workspace = true -# Most packages should depend on sui-simulator instead of directly on msim, but for typed-store +# Most packages should depend on iota-simulator instead of directly on msim, but for typed-store # that creates a circular dependency. [target.'cfg(msim)'.dependencies] msim.workspace = true diff --git a/crates/typed-store/src/lib.rs b/crates/typed-store/src/lib.rs index cf4e4538669..a1ade438c76 100644 --- a/crates/typed-store/src/lib.rs +++ b/crates/typed-store/src/lib.rs @@ -1,5 +1,6 @@ // Copyright (c) 2021, Facebook, Inc. and its affiliates // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #![warn( future_incompatible, diff --git a/crates/typed-store/src/metrics.rs b/crates/typed-store/src/metrics.rs index 2d42cd4da77..b4376b9032f 100644 --- a/crates/typed-store/src/metrics.rs +++ b/crates/typed-store/src/metrics.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ cell::RefCell, diff --git a/crates/typed-store/src/rocks/errors.rs b/crates/typed-store/src/rocks/errors.rs index ac4fc6c8fed..2dbce48f1d5 100644 --- a/crates/typed-store/src/rocks/errors.rs +++ b/crates/typed-store/src/rocks/errors.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{fmt, fmt::Display}; diff --git a/crates/typed-store/src/rocks/iter.rs b/crates/typed-store/src/rocks/iter.rs index 483382a0433..19c2897bc26 100644 --- a/crates/typed-store/src/rocks/iter.rs +++ b/crates/typed-store/src/rocks/iter.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{marker::PhantomData, sync::Arc}; diff --git a/crates/typed-store/src/rocks/keys.rs b/crates/typed-store/src/rocks/keys.rs index 49b0a95f5bb..aaad63f062b 100644 --- a/crates/typed-store/src/rocks/keys.rs +++ b/crates/typed-store/src/rocks/keys.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::marker::PhantomData; diff --git a/crates/typed-store/src/rocks/mod.rs b/crates/typed-store/src/rocks/mod.rs index 79ca2c1de54..c52a2b6e70c 100644 --- a/crates/typed-store/src/rocks/mod.rs +++ b/crates/typed-store/src/rocks/mod.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 pub mod errors; pub(crate) mod iter; @@ -21,6 +22,7 @@ use std::{ use bincode::Options; use collectable::TryExtend; +use iota_macros::{fail_point, nondeterministic}; use itertools::Itertools; use prometheus::{Histogram, HistogramTimer}; use rocksdb::{ @@ -31,7 +33,6 @@ use rocksdb::{ Transaction, WriteBatch, WriteBatchWithTransaction, WriteOptions, }; use serde::{de::DeserializeOwned, Serialize}; -use sui_macros::{fail_point, nondeterministic}; use tap::TapFallible; use tokio::sync::oneshot; use tracing::{debug, error, info, instrument, warn}; @@ -2276,7 +2277,7 @@ impl Default for ReadWriteOptions { fn default() -> Self { Self { ignore_range_deletions: true, - sync_to_disk: std::env::var("SUI_DB_SYNC_TO_DISK").map_or(false, |v| v != "0"), + sync_to_disk: std::env::var("IOTA_DB_SYNC_TO_DISK").map_or(false, |v| v != "0"), } } } @@ -2435,7 +2436,7 @@ pub fn default_db_options() -> DBOptions { .unwrap(), ); - // Sui uses multiple RocksDB in a node, so total sizes of write buffers and WAL + // Iota uses multiple RocksDB in a node, so total sizes of write buffers and WAL // can be higher than the limits below. // // RocksDB also exposes the option to configure total write buffer size across @@ -2445,7 +2446,7 @@ pub fn default_db_options() -> DBOptions { // // The environment variables are only meant to be emergency overrides. They may // go away in future. If you need to modify an option, either update the - // default value, or override the option in Sui / Narwhal. + // default value, or override the option in Iota / Narwhal. opt.set_db_write_buffer_size( read_size_from_env(ENV_VAR_DB_WRITE_BUFFER_SIZE).unwrap_or(DEFAULT_DB_WRITE_BUFFER_SIZE) * 1024 diff --git a/crates/typed-store/src/rocks/safe_iter.rs b/crates/typed-store/src/rocks/safe_iter.rs index 07c44ef5ee8..444fd393153 100644 --- a/crates/typed-store/src/rocks/safe_iter.rs +++ b/crates/typed-store/src/rocks/safe_iter.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{marker::PhantomData, sync::Arc}; diff --git a/crates/typed-store/src/rocks/tests.rs b/crates/typed-store/src/rocks/tests.rs index c542305654c..eedb9f5b286 100644 --- a/crates/typed-store/src/rocks/tests.rs +++ b/crates/typed-store/src/rocks/tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use rstest::rstest; use serde::Deserialize; diff --git a/crates/typed-store/src/rocks/util.rs b/crates/typed-store/src/rocks/util.rs index 1c3903111bb..f23228b7134 100644 --- a/crates/typed-store/src/rocks/util.rs +++ b/crates/typed-store/src/rocks/util.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::cmp::Ordering; diff --git a/crates/typed-store/src/rocks/values.rs b/crates/typed-store/src/rocks/values.rs index 46d9ad01b61..0f4e090d65c 100644 --- a/crates/typed-store/src/rocks/values.rs +++ b/crates/typed-store/src/rocks/values.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::marker::PhantomData; diff --git a/crates/typed-store/src/sally/mod.rs b/crates/typed-store/src/sally/mod.rs index 2d1622a81e1..babf0c606ed 100644 --- a/crates/typed-store/src/sally/mod.rs +++ b/crates/typed-store/src/sally/mod.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! Storage Atomicity Layer Library (aka Sally) is a wrapper around pluggable diff --git a/crates/typed-store/src/test_db.rs b/crates/typed-store/src/test_db.rs index a36a4e6c1e8..6321532a779 100644 --- a/crates/typed-store/src/test_db.rs +++ b/crates/typed-store/src/test_db.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #![allow(clippy::await_holding_lock)] diff --git a/crates/typed-store/src/traits.rs b/crates/typed-store/src/traits.rs index f1b2652a901..d406b88b1c3 100644 --- a/crates/typed-store/src/traits.rs +++ b/crates/typed-store/src/traits.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{borrow::Borrow, collections::BTreeMap, error::Error, ops::RangeBounds}; diff --git a/crates/typed-store/tests/macro_tests.rs b/crates/typed-store/tests/macro_tests.rs index 172e202ee8b..a2d43800bcb 100644 --- a/crates/typed-store/tests/macro_tests.rs +++ b/crates/typed-store/tests/macro_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #![allow(dead_code)] diff --git a/crates/x/src/external_crates_tests.rs b/crates/x/src/external_crates_tests.rs index dbbef040e0c..f0fe8c4d4b7 100644 --- a/crates/x/src/external_crates_tests.rs +++ b/crates/x/src/external_crates_tests.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::{ diff --git a/crates/x/src/main.rs b/crates/x/src/main.rs index f44a7602b55..45443e264a6 100644 --- a/crates/x/src/main.rs +++ b/crates/x/src/main.rs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; diff --git a/dapps/README.md b/dapps/README.md index 7802c318791..83dbc24aa9e 100644 --- a/dapps/README.md +++ b/dapps/README.md @@ -1,6 +1,6 @@ -## Decentralized apps built on Sui +## Decentralized apps built on Iota -This folder enlists full implementations of example Sui dapps, including smart contracts, UIs and any related services +This folder enlists full implementations of example Iota dapps, including smart contracts, UIs and any related services (i.e. game server, ticketing engine etc). - [2-player Optimistic Satoshi Coin-Flip](https://github.com/MystenLabs/satoshi-coin-flip) diff --git a/dapps/kiosk-cli/index.js b/dapps/kiosk-cli/index.js index 7d45d2b3346..04f90a967ee 100644 --- a/dapps/kiosk-cli/index.js +++ b/dapps/kiosk-cli/index.js @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /* eslint-disable eqeqeq */ @@ -27,27 +28,27 @@ import { formatAddress, - isValidSuiAddress, - isValidSuiObjectId, - MIST_PER_SUI, -} from '@mysten/sui.js/utils'; -import { bcs } from '@mysten/sui.js/bcs'; + isValidIotaAddress, + isValidIotaObjectId, + MICROS_PER_IOTA, +} from '@iota/iota.js/utils'; +import { bcs } from '@iota/iota.js/bcs'; import { program } from 'commander'; -import { KIOSK_LISTING, KioskClient, KioskTransaction, Network } from '@mysten/kiosk'; -import { SuiClient, getFullnodeUrl } from '@mysten/sui.js/client'; -import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519'; -import { TransactionBlock } from '@mysten/sui.js/transactions'; +import { KIOSK_LISTING, KioskClient, KioskTransaction, Network } from '@iota/kiosk'; +import { IotaClient, getFullnodeUrl } from '@iota/iota.js/client'; +import { Ed25519Keypair } from '@iota/iota.js/keypairs/ed25519'; +import { TransactionBlock } from '@iota/iota.js/transactions'; /** * List of known types for shorthand search in the `search` command. */ const KNOWN_TYPES = { - suifren: - '0x80d7de9c4a56194087e0ba0bf59492aa8e6a5ee881606226930827085ddf2332::suifrens::SuiFren<0x80d7de9c4a56194087e0ba0bf59492aa8e6a5ee881606226930827085ddf2332::capy::Capy>', + iotafren: + '0x80d7de9c4a56194087e0ba0bf59492aa8e6a5ee881606226930827085ddf2332::iotafrens::IotaFren<0x80d7de9c4a56194087e0ba0bf59492aa8e6a5ee881606226930827085ddf2332::capy::Capy>', }; /** JsonRpcProvider for the Testnet */ -const client = new SuiClient({ url: getFullnodeUrl('testnet') }); +const client = new IotaClient({ url: getFullnodeUrl('testnet') }); const kioskClient = new KioskClient({ client, @@ -115,9 +116,9 @@ program program .command('list') - .description('list an item in the Kiosk for the specified amount of SUI') + .description('list an item in the Kiosk for the specified amount of IOTA') .argument('', 'The ID of the item to list') - .argument('', 'The amount of SUI to list the item for') + .argument('', 'The amount of IOTA to list the item for') .action(listItem); program @@ -139,13 +140,13 @@ program program .command('search') .description('search open listings in Kiosks') - .argument('', 'The type of the item to search for. \nAvailable aliases: "suifren", "test"') + .argument('', 'The type of the item to search for. \nAvailable aliases: "iotafren", "test"') .action(searchType); program .command('policy') .description('search for a TransferPolicy for the specified type') - .argument('', 'The type of the item to search for. \nAvailable aliases: "suifren", "test"') + .argument('', 'The type of the item to search for. \nAvailable aliases: "iotafren", "test"') .action(searchPolicy); program @@ -165,7 +166,7 @@ program.parse(process.argv); * Description: creates and shares a Kiosk */ async function newKiosk() { - const sender = keypair.getPublicKey().toSuiAddress(); + const sender = keypair.getPublicKey().toIotaAddress(); const kioskCap = await findKioskCap().catch(() => null); if (kioskCap !== null) { @@ -187,10 +188,10 @@ async function newKiosk() { * Description: view the inventory of the sender (or a specified address) */ async function showInventory({ address, onlyDisplay, cursor, filter }) { - const owner = address || keypair.getPublicKey().toSuiAddress(); + const owner = address || keypair.getPublicKey().toIotaAddress(); - if (!isValidSuiAddress(owner)) { - throw new Error(`Invalid SUI address: "${owner}"`); + if (!isValidIotaAddress(owner)) { + throw new Error(`Invalid IOTA address: "${owner}"`); } const options = { @@ -239,16 +240,16 @@ async function showKioskContents({ id, address }) { let kioskId = null; if (id) { - if (!isValidSuiObjectId(id)) { + if (!isValidIotaObjectId(id)) { throw new Error(`Invalid Kiosk ID: "${id}"`); } kioskId = id; } else { - const sender = address || keypair.getPublicKey().toSuiAddress(); + const sender = address || keypair.getPublicKey().toIotaAddress(); - if (!isValidSuiAddress(sender)) { - throw new Error(`Invalid SUI address: "${sender}"`); + if (!isValidIotaAddress(sender)) { + throw new Error(`Invalid IOTA address: "${sender}"`); } const kioskCap = await findKioskCap(sender).catch(() => null); @@ -289,7 +290,7 @@ async function showKioskContents({ id, address }) { isLocked: item.isLocked, listed: !!item.listing, isPublic: (item.listing && !item.listing.isExclusive) || false, - 'price (SUI)': item.listing ? formatAmount(item.listing.price) : 'N/A', + 'price (IOTA)': item.listing ? formatAmount(item.listing.price) : 'N/A', })) .sort((a, b) => a.listed - b.listed); @@ -302,13 +303,13 @@ async function showKioskContents({ id, address }) { */ async function placeItem(itemId) { const kioskCap = await findKioskCap().catch(() => null); - const owner = keypair.getPublicKey().toSuiAddress(); + const owner = keypair.getPublicKey().toIotaAddress(); if (kioskCap === null) { throw new Error('No Kiosk found for sender; use `new` to create one'); } - if (!isValidSuiObjectId(itemId)) { + if (!isValidIotaObjectId(itemId)) { throw new Error('Invalid Item ID: "%s"', itemId); } @@ -344,13 +345,13 @@ async function placeItem(itemId) { */ async function lockItem(itemId) { const cap = await findKioskCap().catch(() => null); - const owner = keypair.getPublicKey().toSuiAddress(); + const owner = keypair.getPublicKey().toIotaAddress(); if (cap === null) { throw new Error('No Kiosk found for sender; use `new` to create one'); } - if (!isValidSuiObjectId(itemId)) { + if (!isValidIotaObjectId(itemId)) { throw new Error('Invalid Item ID: "%s"', itemId); } @@ -394,13 +395,13 @@ async function lockItem(itemId) { */ async function takeItem(itemId, { address }) { const cap = await findKioskCap().catch(() => null); - const receiver = address || keypair.getPublicKey().toSuiAddress(); + const receiver = address || keypair.getPublicKey().toIotaAddress(); - if (!isValidSuiAddress(receiver)) { + if (!isValidIotaAddress(receiver)) { throw new Error('Invalid receiver address: "%s"', receiver); } - if (!isValidSuiObjectId(itemId)) { + if (!isValidIotaObjectId(itemId)) { throw new Error('Invalid Item ID: "%s"', itemId); } @@ -429,7 +430,7 @@ async function takeItem(itemId, { address }) { /** * Command: `list` - * Description: Lists an item in the Kiosk for the specified amount of SUI + * Description: Lists an item in the Kiosk for the specified amount of IOTA */ async function listItem(itemId, price) { const cap = await findKioskCap().catch(() => null); @@ -438,7 +439,7 @@ async function listItem(itemId, price) { throw new Error('No Kiosk found for sender; use `new` to create one'); } - if (!isValidSuiObjectId(itemId)) { + if (!isValidIotaObjectId(itemId)) { throw new Error('Invalid Item ID: "%s"', itemId); } @@ -472,7 +473,7 @@ async function delistItem(itemId) { throw new Error('No Kiosk found for sender; use `new` to create one'); } - if (!isValidSuiObjectId(itemId)) { + if (!isValidIotaObjectId(itemId)) { throw new Error('Invalid Item ID: "%s"', itemId); } @@ -504,11 +505,11 @@ async function delistItem(itemId) { async function purchaseItem(itemId, opts) { const { kiosk: inputKioskId } = opts; - if (inputKioskId && !isValidSuiObjectId(inputKioskId)) { + if (inputKioskId && !isValidIotaObjectId(inputKioskId)) { throw new Error('Invalid Kiosk ID: "%s"', inputKioskId); } - if (!isValidSuiObjectId(itemId)) { + if (!isValidIotaObjectId(itemId)) { throw new Error('Invalid Item ID: "%s"', itemId); } @@ -660,7 +661,7 @@ async function searchPolicy(type) { * Description: Withdraws funds from the Kiosk and send them to sender. */ async function withdrawAll() { - const sender = keypair.getPublicKey().toSuiAddress(); + const sender = keypair.getPublicKey().toIotaAddress(); const cap = await findKioskCap(sender).catch(() => null); if (cap === null) { throw new Error('No Kiosk found for sender; use `new` to create one'); @@ -678,7 +679,7 @@ async function withdrawAll() { * Description: Shows the Publisher objects of the current user. */ async function showPublisher() { - const sender = keypair.getPublicKey().toSuiAddress(); + const sender = keypair.getPublicKey().toIotaAddress(); const result = await client.getOwnedObjects({ owner: sender, filter: { StructType: '0x2::package::Publisher' }, @@ -713,9 +714,9 @@ async function showPublisher() { * and sets it on the kioskClient instance. */ async function findKioskCap(address) { - const sender = address || keypair.getPublicKey().toSuiAddress(); + const sender = address || keypair.getPublicKey().toIotaAddress(); - if (!isValidSuiAddress(sender)) { + if (!isValidIotaAddress(sender)) { throw new Error(`Invalid address "${sender}"`); } @@ -763,7 +764,7 @@ async function sendTx(txb) { console.log('Storage rebate: %s', gas.storageRebate); console.log('NonRefundable Storage Fee: %s', gas.nonRefundableStorageFee); console.log( - 'Total Gas: %s SUI (%s MIST)', + 'Total Gas: %s IOTA (%s MICROS)', formatAmount(total), total.toString(), ); @@ -791,15 +792,15 @@ function formatType(type) { } /** - * Formats the MIST into SUI. + * Formats the MICROS into IOTA. */ function formatAmount(amount) { if (!amount) { return null; } - if (amount <= MIST_PER_SUI) { - return Number(amount) / Number(MIST_PER_SUI); + if (amount <= MICROS_PER_IOTA) { + return Number(amount) / Number(MICROS_PER_IOTA); } let len = amount.toString().length; diff --git a/dapps/kiosk-cli/package.json b/dapps/kiosk-cli/package.json index d85c21d4cce..a7e12c8cdef 100644 --- a/dapps/kiosk-cli/package.json +++ b/dapps/kiosk-cli/package.json @@ -15,8 +15,8 @@ "trailingComma": "all" }, "dependencies": { - "@mysten/kiosk": "workspace:*", - "@mysten/sui.js": "workspace:*", + "@iota/kiosk": "workspace:*", + "@iota/iota.js": "workspace:*", "commander": "^11.0.0" } } diff --git a/dapps/kiosk/.eslintignore b/dapps/kiosk/.eslintignore deleted file mode 100644 index 0294f93acd5..00000000000 --- a/dapps/kiosk/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -tailwind.config.js \ No newline at end of file diff --git a/dapps/kiosk/README.md b/dapps/kiosk/README.md index bb626290fb3..dd478feb4a4 100644 --- a/dapps/kiosk/README.md +++ b/dapps/kiosk/README.md @@ -38,7 +38,7 @@ If the connected address doesn't own a Kiosk (missing kioskOwnerCap), the purcha ### Transfer Policy Rules supported Currently, the demo supports the following Transfer Policy cases: -(based on the [`@mysten/kiosk`](https://github.com/MystenLabs/sui/tree/main/sdk/kiosk) SDK) +(based on the [`@iota/kiosk`](https://github.com/iotaledger/iota/tree/main/sdk/kiosk) SDK) 1. No rules 2. Royalty rule (soft royalties) diff --git a/dapps/kiosk/package.json b/dapps/kiosk/package.json index ab516be8b78..292c6cac838 100644 --- a/dapps/kiosk/package.json +++ b/dapps/kiosk/package.json @@ -17,9 +17,9 @@ }, "dependencies": { "@headlessui/react": "^1.7.15", - "@mysten/dapp-kit": "workspace:*", - "@mysten/kiosk": "workspace:*", - "@mysten/sui.js": "workspace:*", + "@iota/dapp-kit": "workspace:*", + "@iota/kiosk": "workspace:*", + "@iota/iota.js": "workspace:*", "@tanstack/react-query": "^5.0.0", "clsx": "^2.0.0", "react": "^18.2.0", diff --git a/dapps/kiosk/postcss.config.cjs b/dapps/kiosk/postcss.config.cjs index 5b5696cafbb..23af4016123 100644 --- a/dapps/kiosk/postcss.config.cjs +++ b/dapps/kiosk/postcss.config.cjs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module.exports = { diff --git a/dapps/kiosk/src/Root.tsx b/dapps/kiosk/src/Root.tsx index 23c400f9e5e..3507655cccc 100644 --- a/dapps/kiosk/src/Root.tsx +++ b/dapps/kiosk/src/Root.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiClientProvider, WalletProvider } from '@mysten/dapp-kit'; -import { getFullnodeUrl } from '@mysten/sui.js/client'; +import { IotaClientProvider, WalletProvider } from '@iota/dapp-kit'; +import { getFullnodeUrl } from '@iota/iota.js/client'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { Toaster } from 'react-hot-toast'; import { Outlet } from 'react-router-dom'; @@ -15,7 +16,7 @@ const queryClient = new QueryClient(); export default function Root() { return ( - @@ -31,7 +32,7 @@ export default function Root() { - + ); } diff --git a/dapps/kiosk/src/components/Base/Button.tsx b/dapps/kiosk/src/components/Base/Button.tsx index c6a56c96011..27314d2e302 100644 --- a/dapps/kiosk/src/components/Base/Button.tsx +++ b/dapps/kiosk/src/components/Base/Button.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import classNames from 'clsx'; diff --git a/dapps/kiosk/src/components/Base/ExplorerLink.tsx b/dapps/kiosk/src/components/Base/ExplorerLink.tsx index 6397363e92b..f1f2a45c86b 100644 --- a/dapps/kiosk/src/components/Base/ExplorerLink.tsx +++ b/dapps/kiosk/src/components/Base/ExplorerLink.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useState } from 'react'; @@ -12,8 +13,8 @@ export function ExplorerLink(opts: LinkOptions) { const [copied, setCopied] = useState(false); const link = 'address' in opts - ? `https://suiexplorer.com/address/${opts.address}?network=testnet` - : `https://suiexplorer.com/object/${opts.object}?network=testnet`; + ? `https://iotaexplorer.com/address/${opts.address}?network=testnet` + : `https://iotaexplorer.com/object/${opts.object}?network=testnet`; const copyToClipboard = async () => { await navigator.clipboard.writeText('address' in opts ? opts.address : opts.object); diff --git a/dapps/kiosk/src/components/Base/Header.tsx b/dapps/kiosk/src/components/Base/Header.tsx index eaaca3f7298..ae79b580f3a 100644 --- a/dapps/kiosk/src/components/Base/Header.tsx +++ b/dapps/kiosk/src/components/Base/Header.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import classNames from 'clsx'; @@ -6,7 +7,7 @@ import { useLocation, useNavigate } from 'react-router-dom'; import FindKiosk from '../Kiosk/FindKiosk'; import { Button } from './Button'; -import { SuiConnectButton } from './SuiConnectButton'; +import { IotaConnectButton } from './IotaConnectButton'; export function Header() { const navigate = useNavigate(); @@ -48,7 +49,7 @@ export function Header() {
    - +
    diff --git a/dapps/kiosk/src/components/Base/IotaConnectButton.tsx b/dapps/kiosk/src/components/Base/IotaConnectButton.tsx new file mode 100644 index 00000000000..43325d8670e --- /dev/null +++ b/dapps/kiosk/src/components/Base/IotaConnectButton.tsx @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { ConnectButton } from '@iota/dapp-kit'; + +export function IotaConnectButton() { + return ; +} diff --git a/dapps/kiosk/src/components/Base/Loading.tsx b/dapps/kiosk/src/components/Base/Loading.tsx index 84ecabdac44..24f2d3fbdcb 100644 --- a/dapps/kiosk/src/components/Base/Loading.tsx +++ b/dapps/kiosk/src/components/Base/Loading.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export function Loading() { diff --git a/dapps/kiosk/src/components/Base/Spinner.tsx b/dapps/kiosk/src/components/Base/Spinner.tsx index 4f3002e684e..7d6ee20b7cb 100644 --- a/dapps/kiosk/src/components/Base/Spinner.tsx +++ b/dapps/kiosk/src/components/Base/Spinner.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export function Spinner() { diff --git a/dapps/kiosk/src/components/Base/SuiConnectButton.tsx b/dapps/kiosk/src/components/Base/SuiConnectButton.tsx deleted file mode 100644 index bbff2e814ef..00000000000 --- a/dapps/kiosk/src/components/Base/SuiConnectButton.tsx +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import { ConnectButton } from '@mysten/dapp-kit'; - -export function SuiConnectButton() { - return ; -} diff --git a/dapps/kiosk/src/components/Base/WalletNotConnected.tsx b/dapps/kiosk/src/components/Base/WalletNotConnected.tsx index 4930243bba8..d9542aebfc9 100644 --- a/dapps/kiosk/src/components/Base/WalletNotConnected.tsx +++ b/dapps/kiosk/src/components/Base/WalletNotConnected.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiConnectButton } from './SuiConnectButton'; +import { IotaConnectButton } from './IotaConnectButton'; export function WalletNotConnected() { return ( @@ -17,7 +18,7 @@ export function WalletNotConnected() { purchase from other kiosks.

    - + diff --git a/dapps/kiosk/src/components/DisplayObject.tsx b/dapps/kiosk/src/components/DisplayObject.tsx index 30865b3bebc..bb37144d3ee 100644 --- a/dapps/kiosk/src/components/DisplayObject.tsx +++ b/dapps/kiosk/src/components/DisplayObject.tsx @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useCurrentAccount } from '@mysten/dapp-kit'; -import { KioskListing } from '@mysten/kiosk'; +import { useCurrentAccount } from '@iota/dapp-kit'; +import { KioskListing } from '@iota/kiosk'; import { ReactNode } from 'react'; import { DEFAULT_IMAGE } from '../utils/constants'; -import { formatSui, mistToSui } from '../utils/utils'; +import { formatIota, microsToIota } from '../utils/utils'; import { OwnedObjectType } from './Inventory/OwnedObjects'; import { ItemLockedBadge } from './Kiosk/ItemLockedBadge'; @@ -19,7 +20,7 @@ export interface DisplayObject { export function DisplayObject({ item, listing = null, children }: DisplayObject) { const currentAccount = useCurrentAccount(); - const price = formatSui(mistToSui(listing?.price)); + const price = formatIota(microsToIota(listing?.price)); return (
    @@ -48,7 +49,7 @@ export function DisplayObject({ item, listing = null, children }: DisplayObject) {listing && listing.price && (
    - {price} SUI + {price} IOTA
    )} diff --git a/dapps/kiosk/src/components/DisplayObjectThumbnail.tsx b/dapps/kiosk/src/components/DisplayObjectThumbnail.tsx index b3315fb17ad..e2ac93ace94 100644 --- a/dapps/kiosk/src/components/DisplayObjectThumbnail.tsx +++ b/dapps/kiosk/src/components/DisplayObjectThumbnail.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { DEFAULT_IMAGE } from '../utils/constants'; diff --git a/dapps/kiosk/src/components/Inventory/OwnedObject.tsx b/dapps/kiosk/src/components/Inventory/OwnedObject.tsx index 7fe729533d9..3c81d18d635 100644 --- a/dapps/kiosk/src/components/Inventory/OwnedObject.tsx +++ b/dapps/kiosk/src/components/Inventory/OwnedObject.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { KioskFnType } from '../../hooks/kiosk'; diff --git a/dapps/kiosk/src/components/Inventory/OwnedObjects.tsx b/dapps/kiosk/src/components/Inventory/OwnedObjects.tsx index 66e76359419..5618012216e 100644 --- a/dapps/kiosk/src/components/Inventory/OwnedObjects.tsx +++ b/dapps/kiosk/src/components/Inventory/OwnedObjects.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { KioskItem } from '@mysten/kiosk'; +import { KioskItem } from '@iota/kiosk'; import { useState } from 'react'; import { toast } from 'react-hot-toast'; diff --git a/dapps/kiosk/src/components/Kiosk/FindKiosk.tsx b/dapps/kiosk/src/components/Kiosk/FindKiosk.tsx index ac563b0fd0d..36b74d55a22 100644 --- a/dapps/kiosk/src/components/Kiosk/FindKiosk.tsx +++ b/dapps/kiosk/src/components/Kiosk/FindKiosk.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { normalizeSuiAddress } from '@mysten/sui.js/utils'; +import { normalizeIotaAddress } from '@iota/iota.js/utils'; import classnames from 'clsx'; import { ChangeEvent, FormEvent, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; @@ -16,7 +17,7 @@ export default function FindKiosk() { if (!searchKiosk || viewingSearchKiosk) return; e?.preventDefault(); - const id = normalizeSuiAddress(searchKiosk); + const id = normalizeIotaAddress(searchKiosk); navigate(`/kiosk/${id}`); setSearchKioskId(id); }; @@ -43,7 +44,7 @@ export default function FindKiosk() { className="bg-gray-100 border lg:min-w-[600px] text-gray-900 placeholder:text-gray-500 text-sm rounded rounded-r-none focus:ring-transparent focus:border-primary block w-full p-2.5 outline-primary" - placeholder="Enter an address or a Sui Kiosk ID to search for a kiosk..." + placeholder="Enter an address or a Iota Kiosk ID to search for a kiosk..." required />
    diff --git a/dapps/kiosk/src/components/Kiosk/ItemLockedBadge.tsx b/dapps/kiosk/src/components/Kiosk/ItemLockedBadge.tsx index cc70fd88930..6f578d15e78 100644 --- a/dapps/kiosk/src/components/Kiosk/ItemLockedBadge.tsx +++ b/dapps/kiosk/src/components/Kiosk/ItemLockedBadge.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export function ItemLockedBadge() { diff --git a/dapps/kiosk/src/components/Kiosk/KioskCreation.tsx b/dapps/kiosk/src/components/Kiosk/KioskCreation.tsx index cb01edef786..fcddfadacdd 100644 --- a/dapps/kiosk/src/components/Kiosk/KioskCreation.tsx +++ b/dapps/kiosk/src/components/Kiosk/KioskCreation.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { toast } from 'react-hot-toast'; @@ -17,18 +18,18 @@ export function KioskCreation({ onCreate }: { onCreate: () => void }) { return (
    -

    Create a Sui Kiosk

    +

    Create a Iota Kiosk

    There’s no kiosk for your address yet. Create a kiosk to store - your digital assets and list them for sale on the Sui network. Anyone can view + your digital assets and list them for sale on the Iota network. Anyone can view your kiosk and the assets you place in it.

    - The demo app works only on Sui Testnet. Make sure that your - wallet connects to Testnet and that you have at least 1 SUI to cover gas fees. - You can get test SUI tokens using{' '} + The demo app works only on Iota Testnet. Make sure that your + wallet connects to Testnet and that you have at least 1 IOTA to cover gas fees. + You can get test IOTA tokens using{' '} ; return ( @@ -51,7 +52,7 @@ export function KioskData({ kioskId }: { kioskId: string }) {

    Items Count: {kiosk.itemCount}
    - Profits: {profits} SUI + Profits: {profits} IOTA {Number(kiosk.profits) > 0 && (
    - + setPrice(e.target.value)} >
    @@ -49,7 +50,7 @@ export function ListPrice({ item, onSuccess, closeModal, listAndPlace, kioskId } onClick={() => placeAndListToKioskMutation.mutate({ item, - price: (Number(price) * Number(MIST_PER_SUI)).toString(), + price: (Number(price) * Number(MICROS_PER_IOTA)).toString(), shouldPlace: listAndPlace, kioskId, }) diff --git a/dapps/kiosk/src/context/KioskClientContext.tsx b/dapps/kiosk/src/context/KioskClientContext.tsx index e07f2d9a9b8..00622ce7da1 100644 --- a/dapps/kiosk/src/context/KioskClientContext.tsx +++ b/dapps/kiosk/src/context/KioskClientContext.tsx @@ -1,21 +1,22 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClient } from '@mysten/dapp-kit'; -import { KioskClient, Network } from '@mysten/kiosk'; +import { useIotaClient } from '@iota/dapp-kit'; +import { KioskClient, Network } from '@iota/kiosk'; import { createContext, ReactNode, useContext, useMemo } from 'react'; export const KioskClientContext = createContext(undefined); export function KisokClientProvider({ children }: { children: ReactNode }) { - const suiClient = useSuiClient(); + const iotaClient = useIotaClient(); const kioskClient = useMemo( () => new KioskClient({ - client: suiClient, + client: iotaClient, network: Network.TESTNET, }), - [suiClient], + [iotaClient], ); return ( diff --git a/dapps/kiosk/src/hooks/kiosk.ts b/dapps/kiosk/src/hooks/kiosk.ts index 06195030f8d..a031088a2bf 100644 --- a/dapps/kiosk/src/hooks/kiosk.ts +++ b/dapps/kiosk/src/hooks/kiosk.ts @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /* eslint-disable @tanstack/query/exhaustive-deps */ -import { useSuiClient } from '@mysten/dapp-kit'; +import { useIotaClient } from '@iota/dapp-kit'; import { getKioskObject, Kiosk, @@ -10,8 +11,8 @@ import { KioskItem, KioskListing, KioskOwnerCap, -} from '@mysten/kiosk'; -import { SuiObjectResponse } from '@mysten/sui.js/client'; +} from '@iota/kiosk'; +import { IotaObjectResponse } from '@iota/iota.js/client'; import { useQuery } from '@tanstack/react-query'; import { OwnedObjectType } from '../components/Inventory/OwnedObjects'; @@ -64,7 +65,7 @@ export function useKiosk(kioskId: string | undefined | null) { queryKey: [TANSTACK_KIOSK_KEY, kioskId], queryFn: async (): Promise<{ kioskData: KioskData | null; - items: SuiObjectResponse[]; + items: IotaObjectResponse[]; }> => { if (!kioskId) return { kioskData: null, items: [] }; const res = await kioskClient.getKiosk({ @@ -116,7 +117,7 @@ export function useKiosk(kioskId: string | undefined | null) { * A hook to fetch a kiosk's details. */ export function useKioskDetails(kioskId: string | undefined | null) { - const client = useSuiClient(); + const client = useIotaClient(); return useQuery({ queryKey: [TANSTACK_KIOSK_DATA_KEY, kioskId], diff --git a/dapps/kiosk/src/hooks/useKioskSelector.ts b/dapps/kiosk/src/hooks/useKioskSelector.ts index cc1d2aa322c..6cf489e6895 100644 --- a/dapps/kiosk/src/hooks/useKioskSelector.ts +++ b/dapps/kiosk/src/hooks/useKioskSelector.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { KioskOwnerCap } from '@mysten/kiosk'; +import { KioskOwnerCap } from '@iota/kiosk'; import { useEffect, useState } from 'react'; import { useOwnedKiosk } from './kiosk'; diff --git a/dapps/kiosk/src/hooks/useOwnedObjects.ts b/dapps/kiosk/src/hooks/useOwnedObjects.ts index 066772520da..535b2675978 100644 --- a/dapps/kiosk/src/hooks/useOwnedObjects.ts +++ b/dapps/kiosk/src/hooks/useOwnedObjects.ts @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /* eslint-disable @tanstack/query/exhaustive-deps */ -import { useSuiClient } from '@mysten/dapp-kit'; -import { PaginatedObjectsResponse } from '@mysten/sui.js/client'; +import { useIotaClient } from '@iota/dapp-kit'; +import { PaginatedObjectsResponse } from '@iota/iota.js/client'; import { useQuery } from '@tanstack/react-query'; import { TANSTACK_OWNED_OBJECTS_KEY } from '../utils/constants'; @@ -18,7 +19,7 @@ export function useOwnedObjects({ cursor?: string; limit?: number; }) { - const provider = useSuiClient(); + const provider = useIotaClient(); return useQuery({ queryKey: [TANSTACK_OWNED_OBJECTS_KEY, address], diff --git a/dapps/kiosk/src/hooks/useTransactionExecution.ts b/dapps/kiosk/src/hooks/useTransactionExecution.ts index 66e50f096a7..5e1f9c2a2d4 100644 --- a/dapps/kiosk/src/hooks/useTransactionExecution.ts +++ b/dapps/kiosk/src/hooks/useTransactionExecution.ts @@ -1,15 +1,16 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSignTransactionBlock, useSuiClient } from '@mysten/dapp-kit'; -import { SuiTransactionBlockResponseOptions } from '@mysten/sui.js/client'; -import { TransactionBlock } from '@mysten/sui.js/transactions'; +import { useSignTransactionBlock, useIotaClient } from '@iota/dapp-kit'; +import { IotaTransactionBlockResponseOptions } from '@iota/iota.js/client'; +import { TransactionBlock } from '@iota/iota.js/transactions'; // A helper to execute transactions by: // 1. Signing them using the wallet // 2. Executing them using the rpc provider export function useTransactionExecution() { - const provider = useSuiClient(); + const provider = useIotaClient(); // sign transaction from the wallet const { mutateAsync: signTransactionBlock } = useSignTransactionBlock(); @@ -20,7 +21,7 @@ export function useTransactionExecution() { options = { showEffects: true }, }: { tx: TransactionBlock; - options?: SuiTransactionBlockResponseOptions | undefined; + options?: IotaTransactionBlockResponseOptions | undefined; }) => { // @ts-expect-error: This is an issue with type references not working together: const signedTx = await signTransactionBlock({ transactionBlock: tx }); diff --git a/dapps/kiosk/src/main.tsx b/dapps/kiosk/src/main.tsx index 55917c4c8ee..86e6a917088 100644 --- a/dapps/kiosk/src/main.tsx +++ b/dapps/kiosk/src/main.tsx @@ -1,10 +1,11 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import React from 'react'; import ReactDOM from 'react-dom/client'; -import '@mysten/dapp-kit/dist/index.css'; +import '@iota/dapp-kit/dist/index.css'; import './index.css'; import { RouterProvider } from 'react-router-dom'; diff --git a/dapps/kiosk/src/mutations/kiosk.ts b/dapps/kiosk/src/mutations/kiosk.ts index 5c8960df037..73b9e7dafeb 100644 --- a/dapps/kiosk/src/mutations/kiosk.ts +++ b/dapps/kiosk/src/mutations/kiosk.ts @@ -1,9 +1,10 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useCurrentAccount } from '@mysten/dapp-kit'; -import { Kiosk, KioskTransaction } from '@mysten/kiosk'; -import { TransactionBlock } from '@mysten/sui.js/transactions'; +import { useCurrentAccount } from '@iota/dapp-kit'; +import { Kiosk, KioskTransaction } from '@iota/kiosk'; +import { TransactionBlock } from '@iota/iota.js/transactions'; import { useMutation } from '@tanstack/react-query'; import { toast } from 'react-hot-toast'; diff --git a/dapps/kiosk/src/routes/Home.tsx b/dapps/kiosk/src/routes/Home.tsx index 1b53d17b0de..18affc047ad 100644 --- a/dapps/kiosk/src/routes/Home.tsx +++ b/dapps/kiosk/src/routes/Home.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useCurrentAccount } from '@mysten/dapp-kit'; +import { useCurrentAccount } from '@iota/dapp-kit'; import { Loading } from '../components/Base/Loading'; import { WalletNotConnected } from '../components/Base/WalletNotConnected'; diff --git a/dapps/kiosk/src/routes/SingleKiosk.tsx b/dapps/kiosk/src/routes/SingleKiosk.tsx index 2d5798eb01b..d703ea86f0a 100644 --- a/dapps/kiosk/src/routes/SingleKiosk.tsx +++ b/dapps/kiosk/src/routes/SingleKiosk.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useParams } from 'react-router-dom'; diff --git a/dapps/kiosk/src/routes/index.tsx b/dapps/kiosk/src/routes/index.tsx index a2484d637e6..4fd2c96a0c8 100644 --- a/dapps/kiosk/src/routes/index.tsx +++ b/dapps/kiosk/src/routes/index.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { createBrowserRouter } from 'react-router-dom'; diff --git a/dapps/kiosk/src/utils/constants.ts b/dapps/kiosk/src/utils/constants.ts index a790f0fb318..975f25e5029 100644 --- a/dapps/kiosk/src/utils/constants.ts +++ b/dapps/kiosk/src/utils/constants.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export const TANSTACK_OWNED_KIOSK_KEY = 'TANSTACK_OWNED_KIOSK_KEY'; diff --git a/dapps/kiosk/src/utils/utils.ts b/dapps/kiosk/src/utils/utils.ts index ccd98a1c729..cca37a41487 100644 --- a/dapps/kiosk/src/utils/utils.ts +++ b/dapps/kiosk/src/utils/utils.ts @@ -1,17 +1,18 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { KioskListing, KioskOwnerCap } from '@mysten/kiosk'; -import { SuiObjectResponse } from '@mysten/sui.js/client'; -import { MIST_PER_SUI, normalizeSuiAddress } from '@mysten/sui.js/utils'; +import { KioskListing, KioskOwnerCap } from '@iota/kiosk'; +import { IotaObjectResponse } from '@iota/iota.js/client'; +import { MICROS_PER_IOTA, normalizeIotaAddress } from '@iota/iota.js/utils'; // Parse the display of a list of objects into a simple {object_id: display} map // to use throughout the app. export const parseObjectDisplays = ( - data: SuiObjectResponse[], + data: IotaObjectResponse[], ): Record | undefined> => { return data.reduce | undefined>>( - (acc, item: SuiObjectResponse) => { + (acc, item: IotaObjectResponse) => { const display = item.data?.display?.data; const id = item.data?.objectId; acc[id] = display || undefined; @@ -31,12 +32,12 @@ export const processKioskListings = (data: KioskListing[]): Record { - if (!mist) return 0; - return Number(mist || 0) / Number(MIST_PER_SUI); +export const microsToIota = (micros: bigint | string | undefined) => { + if (!micros) return 0; + return Number(micros || 0) / Number(MICROS_PER_IOTA); }; -export const formatSui = (amount: number) => { +export const formatIota = (amount: number) => { return new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 5, @@ -51,5 +52,5 @@ export const findActiveCap = ( caps: KioskOwnerCap[] = [], kioskId: string, ): KioskOwnerCap | undefined => { - return caps.find((x) => normalizeSuiAddress(x.kioskId) === normalizeSuiAddress(kioskId)); + return caps.find((x) => normalizeIotaAddress(x.kioskId) === normalizeIotaAddress(kioskId)); }; diff --git a/dapps/kiosk/src/vite-env.d.ts b/dapps/kiosk/src/vite-env.d.ts index bbce1f8fff1..2dc9d172db6 100644 --- a/dapps/kiosk/src/vite-env.d.ts +++ b/dapps/kiosk/src/vite-env.d.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// diff --git a/dapps/kiosk/tailwind.config.js b/dapps/kiosk/tailwind.config.js index b70dba9cfe7..b3b6ef1b7a4 100644 --- a/dapps/kiosk/tailwind.config.js +++ b/dapps/kiosk/tailwind.config.js @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /** @type {import('tailwindcss').Config} */ diff --git a/dapps/kiosk/vite.config.ts b/dapps/kiosk/vite.config.ts index 10f208fe4ad..fed2a824467 100644 --- a/dapps/kiosk/vite.config.ts +++ b/dapps/kiosk/vite.config.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import react from '@vitejs/plugin-react'; diff --git a/dapps/multisig-toolkit/index.html b/dapps/multisig-toolkit/index.html index 8400f014ab2..c04fc4ec0d6 100644 --- a/dapps/multisig-toolkit/index.html +++ b/dapps/multisig-toolkit/index.html @@ -3,7 +3,7 @@ - Sui Multisig Toolkit + Iota Multisig Toolkit
    diff --git a/dapps/multisig-toolkit/package.json b/dapps/multisig-toolkit/package.json index 5afc6fbe7cb..416de7f5d2b 100644 --- a/dapps/multisig-toolkit/package.json +++ b/dapps/multisig-toolkit/package.json @@ -39,8 +39,8 @@ "zod": "^3.21.4" }, "devDependencies": { - "@mysten/dapp-kit": "workspace:*", - "@mysten/sui.js": "workspace:*", + "@iota/dapp-kit": "workspace:*", + "@iota/iota.js": "workspace:*", "@tailwindcss/forms": "^0.5.4", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", diff --git a/dapps/multisig-toolkit/postcss.config.cjs b/dapps/multisig-toolkit/postcss.config.cjs index 5b5696cafbb..23af4016123 100644 --- a/dapps/multisig-toolkit/postcss.config.cjs +++ b/dapps/multisig-toolkit/postcss.config.cjs @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module.exports = { diff --git a/dapps/multisig-toolkit/src/components/connect.tsx b/dapps/multisig-toolkit/src/components/connect.tsx index 6896469d1d6..6a6a848ff14 100644 --- a/dapps/multisig-toolkit/src/components/connect.tsx +++ b/dapps/multisig-toolkit/src/components/connect.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { @@ -7,8 +8,8 @@ import { useCurrentAccount, useDisconnectWallet, useSwitchAccount, -} from '@mysten/dapp-kit'; -import { formatAddress } from '@mysten/sui.js/utils'; +} from '@iota/dapp-kit'; +import { formatAddress } from '@iota/iota.js/utils'; import { Check, ChevronsUpDown } from 'lucide-react'; import { useState } from 'react'; diff --git a/dapps/multisig-toolkit/src/components/header.tsx b/dapps/multisig-toolkit/src/components/header.tsx index c8b996d0040..ead0df23e4a 100644 --- a/dapps/multisig-toolkit/src/components/header.tsx +++ b/dapps/multisig-toolkit/src/components/header.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { KeyRound } from 'lucide-react'; @@ -18,7 +19,7 @@ export function Header() {

    - Sui MultiSig Toolkit + Iota MultiSig Toolkit

    diff --git a/dapps/multisig-toolkit/src/components/preview-effects/EffectsPreview.tsx b/dapps/multisig-toolkit/src/components/preview-effects/EffectsPreview.tsx index 6f345aba4e1..465ea08dcf8 100644 --- a/dapps/multisig-toolkit/src/components/preview-effects/EffectsPreview.tsx +++ b/dapps/multisig-toolkit/src/components/preview-effects/EffectsPreview.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { DryRunTransactionBlockResponse } from '@mysten/sui.js/src/client'; +import { DryRunTransactionBlockResponse } from '@iota/iota.js/src/client'; import * as Tabs from '@radix-ui/react-tabs'; import { useState } from 'react'; diff --git a/dapps/multisig-toolkit/src/components/preview-effects/ObjectLink.tsx b/dapps/multisig-toolkit/src/components/preview-effects/ObjectLink.tsx index 0c9af2ce66b..5d8e383b1da 100644 --- a/dapps/multisig-toolkit/src/components/preview-effects/ObjectLink.tsx +++ b/dapps/multisig-toolkit/src/components/preview-effects/ObjectLink.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClientContext } from '@mysten/dapp-kit'; -import { ObjectOwner, SuiObjectChange } from '@mysten/sui.js/src/client'; +import { useIotaClientContext } from '@iota/dapp-kit'; +import { ObjectOwner, IotaObjectChange } from '@iota/iota.js/src/client'; import { CheckIcon, CopyIcon } from 'lucide-react'; import { useState } from 'react'; import toast from 'react-hot-toast'; @@ -27,12 +28,12 @@ export function ObjectLink({ inputObject?: string; type?: string; owner?: ObjectOwner; - object?: SuiObjectChange; + object?: IotaObjectChange; } & React.HTMLAttributes & React.ComponentPropsWithoutRef<'a'>) { const [copied, setCopied] = useState(false); - const { network } = useSuiClientContext(); + const { network } = useIotaClientContext(); let objectId: string | undefined; let display: string | undefined; @@ -70,7 +71,7 @@ export function ObjectLink({ } const link = objectId - ? `https://suiexplorer.com/${ownerDisplay ? 'address' : 'object'}/${objectId}?network=${ + ? `https://iotaexplorer.com/${ownerDisplay ? 'address' : 'object'}/${objectId}?network=${ network.split(':')[1] }` : undefined; diff --git a/dapps/multisig-toolkit/src/components/preview-effects/PreviewCard.tsx b/dapps/multisig-toolkit/src/components/preview-effects/PreviewCard.tsx index e73c3cce22d..ba855d8613f 100644 --- a/dapps/multisig-toolkit/src/components/preview-effects/PreviewCard.tsx +++ b/dapps/multisig-toolkit/src/components/preview-effects/PreviewCard.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ObjectOwner } from '@mysten/sui.js/src/client'; +import { ObjectOwner } from '@iota/iota.js/src/client'; import { ReactNode } from 'react'; import { ObjectLink } from './ObjectLink'; diff --git a/dapps/multisig-toolkit/src/components/preview-effects/partials/BalanceChanges.tsx b/dapps/multisig-toolkit/src/components/preview-effects/partials/BalanceChanges.tsx index 590af4ac5d2..2b4d4304db7 100644 --- a/dapps/multisig-toolkit/src/components/preview-effects/partials/BalanceChanges.tsx +++ b/dapps/multisig-toolkit/src/components/preview-effects/partials/BalanceChanges.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClientQuery } from '@mysten/dapp-kit'; -import { type BalanceChange } from '@mysten/sui.js/src/client'; +import { useIotaClientQuery } from '@iota/dapp-kit'; +import { type BalanceChange } from '@iota/iota.js/src/client'; import { PreviewCard } from '../PreviewCard'; import { onChainAmountToFloat } from '../utils'; @@ -18,7 +19,7 @@ export function BalanceChanges({ changes }: { changes: BalanceChange[] }) { } function ChangedBalance({ change }: { change: BalanceChange }) { - const { data: coinMetadata } = useSuiClientQuery('getCoinMetadata', { + const { data: coinMetadata } = useIotaClientQuery('getCoinMetadata', { coinType: change.coinType, }); diff --git a/dapps/multisig-toolkit/src/components/preview-effects/partials/Events.tsx b/dapps/multisig-toolkit/src/components/preview-effects/partials/Events.tsx index ef85a880587..8fe1cd3871d 100644 --- a/dapps/multisig-toolkit/src/components/preview-effects/partials/Events.tsx +++ b/dapps/multisig-toolkit/src/components/preview-effects/partials/Events.tsx @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SuiEvent } from '@mysten/sui.js/src/client'; +import { IotaEvent } from '@iota/iota.js/src/client'; import { ReactNode } from 'react'; import { Textarea } from '@/components/ui/textarea'; @@ -9,7 +10,7 @@ import { Textarea } from '@/components/ui/textarea'; import { ObjectLink } from '../ObjectLink'; import { PreviewCard } from '../PreviewCard'; -export function Events({ events }: { events: SuiEvent[] }) { +export function Events({ events }: { events: IotaEvent[] }) { if (events.length === 0) { return
    No events were emitted.
    ; } @@ -23,7 +24,7 @@ export function Events({ events }: { events: SuiEvent[] }) { ); } -export function Event({ event }: { event: SuiEvent }) { +export function Event({ event }: { event: IotaEvent }) { const fields: Record = { 'Package ID': , Sender: , diff --git a/dapps/multisig-toolkit/src/components/preview-effects/partials/ObjectChanges.tsx b/dapps/multisig-toolkit/src/components/preview-effects/partials/ObjectChanges.tsx index 6fb99741251..63ef38f7c39 100644 --- a/dapps/multisig-toolkit/src/components/preview-effects/partials/ObjectChanges.tsx +++ b/dapps/multisig-toolkit/src/components/preview-effects/partials/ObjectChanges.tsx @@ -1,7 +1,7 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -import { SuiObjectChange } from '@mysten/sui.js/src/client'; +import { IotaObjectChange } from '@iota/iota.js/src/client'; import { ObjectLink } from '../ObjectLink'; import { PreviewCard } from '../PreviewCard'; @@ -30,8 +30,9 @@ const objectTypes: Record> = { transferred: {}, }; +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -export function ObjectChanges({ objects }: { objects: SuiObjectChange[] }) { +export function ObjectChanges({ objects }: { objects: IotaObjectChange[] }) { return (
    {objects.map((object, index) => ( @@ -41,7 +42,7 @@ export function ObjectChanges({ objects }: { objects: SuiObjectChange[] }) { ); } -function ChangedObject({ object }: { object: SuiObjectChange }) { +function ChangedObject({ object }: { object: IotaObjectChange }) { const objectType = objectTypes[object.type]; return ( diff --git a/dapps/multisig-toolkit/src/components/preview-effects/partials/Overview.tsx b/dapps/multisig-toolkit/src/components/preview-effects/partials/Overview.tsx index 6b1e029f413..3a549de34f1 100644 --- a/dapps/multisig-toolkit/src/components/preview-effects/partials/Overview.tsx +++ b/dapps/multisig-toolkit/src/components/preview-effects/partials/Overview.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { useSuiClientContext } from '@mysten/dapp-kit'; -import { DryRunTransactionBlockResponse, GasCostSummary } from '@mysten/sui.js/src/client'; +import { useIotaClientContext } from '@iota/dapp-kit'; +import { DryRunTransactionBlockResponse, GasCostSummary } from '@iota/iota.js/src/client'; import { ReactNode } from 'react'; import { ObjectLink } from '../ObjectLink'; @@ -22,7 +23,7 @@ const calculateGas = (gas: GasCostSummary): string => { }; export function Overview({ output }: { output: DryRunTransactionBlockResponse }) { - const { network } = useSuiClientContext(); + const { network } = useIotaClientContext(); const metadata: Record = { network, status: @@ -42,7 +43,7 @@ export function Overview({ output }: { output: DryRunTransactionBlockResponse }) ), epoch: output.effects.executedEpoch, - gas: calculateGas(output.effects.gasUsed) + ' SUI', + gas: calculateGas(output.effects.gasUsed) + ' IOTA', }; return ( diff --git a/dapps/multisig-toolkit/src/components/preview-effects/partials/Transactions.tsx b/dapps/multisig-toolkit/src/components/preview-effects/partials/Transactions.tsx index 6f74f0c848d..a7205a0629c 100644 --- a/dapps/multisig-toolkit/src/components/preview-effects/partials/Transactions.tsx +++ b/dapps/multisig-toolkit/src/components/preview-effects/partials/Transactions.tsx @@ -1,12 +1,13 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { - SuiArgument, - SuiCallArg, - SuiTransaction, + IotaArgument, + IotaCallArg, + IotaTransaction, TransactionBlockData, -} from '@mysten/sui.js/src/client'; +} from '@iota/iota.js/src/client'; import { ReactNode } from 'react'; import { ObjectLink } from '../ObjectLink'; @@ -24,7 +25,7 @@ export function Transactions({ inputs }: { inputs: TransactionBlockData }) { ); } -const getCallArgDisplay = (argument: SuiCallArg | undefined) => { +const getCallArgDisplay = (argument: IotaCallArg | undefined) => { if (!argument) return null; if (typeof argument === 'string') return argument; @@ -53,7 +54,7 @@ const getCallArgDisplay = (argument: SuiCallArg | undefined) => { ); }; -const getSuiArgumentDisplay = (argument: SuiArgument, inputs: SuiCallArg[]) => { +const getIotaArgumentDisplay = (argument: IotaArgument, inputs: IotaCallArg[]) => { if (typeof argument === 'string') return argument; if ('Input' in argument) { @@ -67,12 +68,12 @@ const getSuiArgumentDisplay = (argument: SuiArgument, inputs: SuiCallArg[]) => { ); }; -const renderArguments = (callArgs: SuiArgument[], inputs: SuiCallArg[]) => { +const renderArguments = (callArgs: IotaArgument[], inputs: IotaCallArg[]) => { return (
    {callArgs.map((arg, index) => (
    - {getSuiArgumentDisplay(arg, inputs)} + {getIotaArgumentDisplay(arg, inputs)}
    ))}
    @@ -104,7 +105,7 @@ function Transaction({ inputs, index, }: { - transaction: SuiTransaction; + transaction: IotaTransaction; inputs: TransactionBlockData; index: number; }) { diff --git a/dapps/multisig-toolkit/src/components/preview-effects/utils.ts b/dapps/multisig-toolkit/src/components/preview-effects/utils.ts index 290c43a99cc..e0712a25dff 100644 --- a/dapps/multisig-toolkit/src/components/preview-effects/utils.ts +++ b/dapps/multisig-toolkit/src/components/preview-effects/utils.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 export const onChainAmountToFloat = (amount: string, decimals: number) => { const total = parseFloat(amount); diff --git a/dapps/multisig-toolkit/src/components/ui/alert.tsx b/dapps/multisig-toolkit/src/components/ui/alert.tsx index 4cd4b401096..0f2a8223f44 100644 --- a/dapps/multisig-toolkit/src/components/ui/alert.tsx +++ b/dapps/multisig-toolkit/src/components/ui/alert.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { cva, type VariantProps } from 'class-variance-authority'; import * as React from 'react'; diff --git a/dapps/multisig-toolkit/src/components/ui/button.tsx b/dapps/multisig-toolkit/src/components/ui/button.tsx index ac9b96dabb6..a6177ce76a7 100644 --- a/dapps/multisig-toolkit/src/components/ui/button.tsx +++ b/dapps/multisig-toolkit/src/components/ui/button.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { Slot } from '@radix-ui/react-slot'; import { cva, type VariantProps } from 'class-variance-authority'; diff --git a/dapps/multisig-toolkit/src/components/ui/card.tsx b/dapps/multisig-toolkit/src/components/ui/card.tsx index 6215b6811a0..1ab3887192b 100644 --- a/dapps/multisig-toolkit/src/components/ui/card.tsx +++ b/dapps/multisig-toolkit/src/components/ui/card.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import * as React from 'react'; diff --git a/dapps/multisig-toolkit/src/components/ui/command.tsx b/dapps/multisig-toolkit/src/components/ui/command.tsx index 4d3d23cdd23..f84f94f45fc 100644 --- a/dapps/multisig-toolkit/src/components/ui/command.tsx +++ b/dapps/multisig-toolkit/src/components/ui/command.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { DialogProps } from '@radix-ui/react-dialog'; import { Command as CommandPrimitive } from 'cmdk'; diff --git a/dapps/multisig-toolkit/src/components/ui/dialog.tsx b/dapps/multisig-toolkit/src/components/ui/dialog.tsx index 18655827300..e353681178c 100644 --- a/dapps/multisig-toolkit/src/components/ui/dialog.tsx +++ b/dapps/multisig-toolkit/src/components/ui/dialog.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import * as DialogPrimitive from '@radix-ui/react-dialog'; import { X } from 'lucide-react'; diff --git a/dapps/multisig-toolkit/src/components/ui/form.tsx b/dapps/multisig-toolkit/src/components/ui/form.tsx index 8f73c2ed35b..55614d7e723 100644 --- a/dapps/multisig-toolkit/src/components/ui/form.tsx +++ b/dapps/multisig-toolkit/src/components/ui/form.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import * as LabelPrimitive from '@radix-ui/react-label'; import { Slot } from '@radix-ui/react-slot'; diff --git a/dapps/multisig-toolkit/src/components/ui/label.tsx b/dapps/multisig-toolkit/src/components/ui/label.tsx index 02ed9066e9f..06d5a82fb76 100644 --- a/dapps/multisig-toolkit/src/components/ui/label.tsx +++ b/dapps/multisig-toolkit/src/components/ui/label.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import * as LabelPrimitive from '@radix-ui/react-label'; import { cva, type VariantProps } from 'class-variance-authority'; diff --git a/dapps/multisig-toolkit/src/components/ui/popover.tsx b/dapps/multisig-toolkit/src/components/ui/popover.tsx index 66158007974..b91f0e5a024 100644 --- a/dapps/multisig-toolkit/src/components/ui/popover.tsx +++ b/dapps/multisig-toolkit/src/components/ui/popover.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import * as PopoverPrimitive from '@radix-ui/react-popover'; import * as React from 'react'; diff --git a/dapps/multisig-toolkit/src/components/ui/tabs.tsx b/dapps/multisig-toolkit/src/components/ui/tabs.tsx index 4d534bbd66c..f699b65df8b 100644 --- a/dapps/multisig-toolkit/src/components/ui/tabs.tsx +++ b/dapps/multisig-toolkit/src/components/ui/tabs.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import * as TabsPrimitive from '@radix-ui/react-tabs'; import * as React from 'react'; diff --git a/dapps/multisig-toolkit/src/components/ui/textarea.tsx b/dapps/multisig-toolkit/src/components/ui/textarea.tsx index 115d0fd1523..24373bee495 100644 --- a/dapps/multisig-toolkit/src/components/ui/textarea.tsx +++ b/dapps/multisig-toolkit/src/components/ui/textarea.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import * as React from 'react'; diff --git a/dapps/multisig-toolkit/src/components/warning.tsx b/dapps/multisig-toolkit/src/components/warning.tsx index f55700a5022..10b43a8a220 100644 --- a/dapps/multisig-toolkit/src/components/warning.tsx +++ b/dapps/multisig-toolkit/src/components/warning.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { useState } from 'react'; diff --git a/dapps/multisig-toolkit/src/lib/queryClient.ts b/dapps/multisig-toolkit/src/lib/queryClient.ts index 912e8053c4c..b4afd801ce3 100644 --- a/dapps/multisig-toolkit/src/lib/queryClient.ts +++ b/dapps/multisig-toolkit/src/lib/queryClient.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { QueryClient } from '@tanstack/react-query'; diff --git a/dapps/multisig-toolkit/src/lib/utils.ts b/dapps/multisig-toolkit/src/lib/utils.ts index ef94e4d8dab..86b0579c9e5 100644 --- a/dapps/multisig-toolkit/src/lib/utils.ts +++ b/dapps/multisig-toolkit/src/lib/utils.ts @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { clsx, type ClassValue } from 'clsx'; diff --git a/dapps/multisig-toolkit/src/main.tsx b/dapps/multisig-toolkit/src/main.tsx index 198d88c04c0..573b90f8c7d 100644 --- a/dapps/multisig-toolkit/src/main.tsx +++ b/dapps/multisig-toolkit/src/main.tsx @@ -1,13 +1,14 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import '@mysten/dapp-kit/dist/index.css'; +import '@iota/dapp-kit/dist/index.css'; import './index.css'; import '@fontsource-variable/inter'; import '@fontsource-variable/red-hat-mono'; -import { SuiClientProvider, WalletProvider } from '@mysten/dapp-kit'; -import { getFullnodeUrl } from '@mysten/sui.js/client'; +import { IotaClientProvider, WalletProvider } from '@iota/dapp-kit'; +import { getFullnodeUrl } from '@iota/iota.js/client'; import { QueryClientProvider } from '@tanstack/react-query'; import React from 'react'; import ReactDOM from 'react-dom/client'; @@ -19,18 +20,18 @@ import { router } from './routes'; ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( - - + , ); diff --git a/dapps/multisig-toolkit/src/routes/combine-sigs.tsx b/dapps/multisig-toolkit/src/routes/combine-sigs.tsx index 5e9883fcab6..11b653a387d 100644 --- a/dapps/multisig-toolkit/src/routes/combine-sigs.tsx +++ b/dapps/multisig-toolkit/src/routes/combine-sigs.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { PublicKey, SerializedSignature } from '@mysten/sui.js/cryptography'; -import { MultiSigPublicKey, publicKeyFromSuiBytes } from '@mysten/sui.js/multisig'; +import { PublicKey, SerializedSignature } from '@iota/iota.js/cryptography'; +import { MultiSigPublicKey, publicKeyFromIotaBytes } from '@iota/iota.js/multisig'; import { useState } from 'react'; import { FieldValues, useFieldArray, useForm } from 'react-hook-form'; @@ -14,7 +15,7 @@ export default function MultiSigCombineSignatureGenerator() { const [msSignature, setMSSignature] = useState(''); const { register, control, handleSubmit } = useForm({ defaultValues: { - pubKeys: [{ pubKey: 'Sui Pubkey', weight: '', signature: 'Sui Signature' }], + pubKeys: [{ pubKey: 'Iota Pubkey', weight: '', signature: 'Iota Signature' }], threshold: 1, }, }); @@ -29,7 +30,7 @@ export default function MultiSigCombineSignatureGenerator() { const pks: { publicKey: PublicKey; weight: number }[] = []; const sigs: SerializedSignature[] = []; data.pubKeys.forEach((item: Record) => { - const pk = publicKeyFromSuiBytes(item.pubKey as string); + const pk = publicKeyFromIotaBytes(item.pubKey as string); pks.push({ publicKey: pk, weight: item.weight as number }); if (item.signature) { sigs.push(item.signature as string); @@ -39,8 +40,8 @@ export default function MultiSigCombineSignatureGenerator() { threshold: data.threshold, publicKeys: pks, }); - const multisigSuiAddress = multiSigPublicKey.toSuiAddress(); - setMSAddress(multisigSuiAddress); + const multisigIotaAddress = multiSigPublicKey.toIotaAddress(); + setMSAddress(multisigIotaAddress); const multisigCombinedSig = multiSigPublicKey.combinePartialSignatures(sigs); setMSSignature(multisigCombinedSig); }; @@ -52,11 +53,11 @@ export default function MultiSigCombineSignatureGenerator() { -

    The following demo allow you to create Sui MultiSig Combined Signatures.

    -

    Sui Pubkeys, weights, signatures for testing/playing with:

    +

    The following demo allow you to create Iota MultiSig Combined Signatures.

    +

    Iota Pubkeys, weights, signatures for testing/playing with:

    -
    Sui Pubkeys
    +
    Iota Pubkeys
    Weights
    Signatures
    @@ -119,9 +120,9 @@ export default function MultiSigCombineSignatureGenerator() { type="button" onClick={() => { append({ - pubKey: 'Sui Pubkey', + pubKey: 'Iota Pubkey', weight: '', - signature: 'Sui Signature', + signature: 'Iota Signature', }); }} > @@ -144,9 +145,9 @@ export default function MultiSigCombineSignatureGenerator() { {msAddress && ( - Sui MultiSig Address + Iota MultiSig Address - https://docs.sui.io/testnet/learn/cryptography/sui-multisig + https://docs.iota.io/testnet/learn/cryptography/iota-multisig @@ -161,9 +162,9 @@ export default function MultiSigCombineSignatureGenerator() { {msSignature && ( - Sui MultiSig Combined Address + Iota MultiSig Combined Address - https://docs.sui.io/testnet/learn/cryptography/sui-multisig + https://docs.iota.io/testnet/learn/cryptography/iota-multisig @@ -180,7 +181,7 @@ export default function MultiSigCombineSignatureGenerator() { } /* -sui keytool multi-sig-combine-partial-sig \ +iota keytool multi-sig-combine-partial-sig \ --pks \ ACaY7TW0MnPu+fr/Z2qH5YRybHsj80qfwfqiuduT4czi \ ABr818VXt+6PLPRoA7QnsHBfRpKJdWZPjt7ppiTl6Fkq \ diff --git a/dapps/multisig-toolkit/src/routes/execute-transaction.tsx b/dapps/multisig-toolkit/src/routes/execute-transaction.tsx index 16aac4a27be..200065b8f50 100644 --- a/dapps/multisig-toolkit/src/routes/execute-transaction.tsx +++ b/dapps/multisig-toolkit/src/routes/execute-transaction.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { getFullnodeUrl, SuiClient } from '@mysten/sui.js/client'; -import { parseSerializedSignature } from '@mysten/sui.js/cryptography'; +import { getFullnodeUrl, IotaClient } from '@iota/iota.js/client'; +import { parseSerializedSignature } from '@iota/iota.js/cryptography'; import { useMutation } from '@tanstack/react-query'; import { AlertCircle } from 'lucide-react'; import { useState } from 'react'; @@ -23,10 +24,10 @@ export default function ExecuteTransaction() { const [signature, setSignature] = useState(''); const rpcUrl = getFullnodeUrl(network); - const client = new SuiClient({ + const client = new IotaClient({ url: rpcUrl, }); - //const client = useSuiClient(); + //const client = useIotaClient(); const { mutate, @@ -122,14 +123,14 @@ export default function ExecuteTransaction() { - Sui Transaction Digest + Iota Transaction Digest View TX Digest on{' '}
    - Sui Explorer + Iota Explorer diff --git a/dapps/multisig-toolkit/src/routes/index.tsx b/dapps/multisig-toolkit/src/routes/index.tsx index 3ddddb1a463..e4bfaaabf40 100644 --- a/dapps/multisig-toolkit/src/routes/index.tsx +++ b/dapps/multisig-toolkit/src/routes/index.tsx @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { createBrowserRouter, Navigate } from 'react-router-dom'; diff --git a/dapps/multisig-toolkit/src/routes/multisig-address.tsx b/dapps/multisig-toolkit/src/routes/multisig-address.tsx index 2ed8f7f7c5f..7da79c6ea15 100644 --- a/dapps/multisig-toolkit/src/routes/multisig-address.tsx +++ b/dapps/multisig-toolkit/src/routes/multisig-address.tsx @@ -1,8 +1,9 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { PublicKey } from '@mysten/sui.js/cryptography'; -import { MultiSigPublicKey, publicKeyFromSuiBytes } from '@mysten/sui.js/multisig'; +import { PublicKey } from '@iota/iota.js/cryptography'; +import { MultiSigPublicKey, publicKeyFromIotaBytes } from '@iota/iota.js/multisig'; import { useState } from 'react'; import { FieldValues, useFieldArray, useForm } from 'react-hook-form'; @@ -19,7 +20,7 @@ export default function MultiSigAddressGenerator() { const [msAddress, setMSAddress] = useState(''); const { register, control, handleSubmit } = useForm({ defaultValues: { - pubKeys: [{ pubKey: 'Sui Pubkey', weight: '' }], + pubKeys: [{ pubKey: 'Iota Pubkey', weight: '' }], threshold: 1, }, }); @@ -32,15 +33,15 @@ export default function MultiSigAddressGenerator() { const onSubmit = (data: FieldValues) => { const pks: { publicKey: PublicKey; weight: number }[] = []; data.pubKeys.forEach((item: Record) => { - const pk = publicKeyFromSuiBytes(item.pubKey as string); + const pk = publicKeyFromIotaBytes(item.pubKey as string); pks.push({ publicKey: pk, weight: item.weight as number }); }); const multiSigPublicKey = MultiSigPublicKey.fromPublicKeys({ threshold: data.threshold, publicKeys: pks, }); - const multisigSuiAddress = multiSigPublicKey.toSuiAddress(); - setMSAddress(multisigSuiAddress); + const multisigIotaAddress = multiSigPublicKey.toIotaAddress(); + setMSAddress(multisigIotaAddress); }; // if you want to control your fields with watch @@ -57,9 +58,9 @@ export default function MultiSigAddressGenerator() { -

    The following demo allow you to create Sui MultiSig addresses.

    +

    The following demo allow you to create Iota MultiSig addresses.

    - Sui Pubkeys for playing with + Iota Pubkeys for playing with

    ABr818VXt+6PLPRoA7QnsHBfRpKJdWZPjt7ppiTl6Fkq

    ANRdB4M6Hj73R+gRM4N6zUPNidLuatB9uccOzHBc/0bP

    @@ -103,7 +104,7 @@ export default function MultiSigAddressGenerator() {
    - + ))} ); @@ -707,7 +708,7 @@ The UI has a place for users to discover, create, and execute trades. The code o ### Requested escrows -Let's take a look at the **Requested Escrows** tab by examining `src/components/escrows/EscrowList.tsx`. This time, the data is retrieved by using `useInfiniteQuery` directly from `react-query`. Fetch the data by calling the API service that you already implemented in the [Escrow Indexing and API Service Guide](./indexer-api.mdx). Call the `/escrows` endpoint to fetch all the escrows requested to you. The rationale behind using an API service to fetch the data is because the indexed data includes additional information that allows query efficiency and flexibility. You can fetch specific escrows satisfying different configured query clauses rather than limited query features of Sui blockchain RPC endpoints. +Let's take a look at the **Requested Escrows** tab by examining `src/components/escrows/EscrowList.tsx`. This time, the data is retrieved by using `useInfiniteQuery` directly from `react-query`. Fetch the data by calling the API service that you already implemented in the [Escrow Indexing and API Service Guide](./indexer-api.mdx). Call the `/escrows` endpoint to fetch all the escrows requested to you. The rationale behind using an API service to fetch the data is because the indexed data includes additional information that allows query efficiency and flexibility. You can fetch specific escrows satisfying different configured query clauses rather than limited query features of Iota blockchain RPC endpoints. ```ts title='src/components/escrows/EscrowList.tsx' import { constructUrlSearchParams, getNextPageParam } from '@/utils/helpers'; @@ -734,7 +735,7 @@ const { data, fetchNextPage, hasNextPage, isLoading, isFetchingNextPage } = useI The `Escrow` component renders the details of an escrow by providing `ApiEscrowObject` as a rendering property. There is some data you need to fetch to gather necessary escrow information for display in the UI: -- Query the escrowed item object directly from Sui blockchain by using `useSuiClientQuery('getObject')` as this is the only way to have its Object Display metadata. +- Query the escrowed item object directly from Iota blockchain by using `useIotaClientQuery('getObject')` as this is the only way to have its Object Display metadata. - Fetch the `ApiLockedObject` corresponding to the escrow's key ID from the API service as this is the most efficient way to fetch the locked object in a complex query. - Fetch the on-chain `Locked` object corresponding to the returned `ApiLockedObject` to pass it onto ``. @@ -746,7 +747,7 @@ export function Escrow({ escrow }: { escrow: ApiEscrowObject }) { const { mutate: cancelEscrowMutation, isPending: pendingCancellation } = useCancelEscrowMutation(); - const suiObject = useSuiClientQuery('getObject', { + const iotaObject = useIotaClientQuery('getObject', { id: escrow?.itemId, options: { showDisplay: true, @@ -764,7 +765,7 @@ export function Escrow({ escrow }: { escrow: ApiEscrowObject }) { enabled: !escrow.cancelled, }); - const { data: suiLockedObject } = useGetLockedObject({ + const { data: iotaLockedObject } = useGetLockedObject({ lockedId: lockedData.data?.objectId, }); @@ -776,7 +777,7 @@ As the last step, reuse the `accept` and `cancel` escrow mutations in correspond ### Browse locked objects -The `src/components/locked/ApiLockedList.tsx` component renders all the on-chain locked objects based on the `LockedListingQuery` property. Call the API service to fetch the `ApiLockedObject` data using the provided query parameters. One caveat around the API service is that the `creator` field of the `ApiLockedObject` could be stale because the `Locked` object has the `store` ability. This means that the object can be transferred freely, hence, the ownership might not be correctly tracked by the API service. That's why you still fetch from the Sui blockchain as an additional step to define the object with latest on-chain information to ensure its data correctness in regards to ownership. +The `src/components/locked/ApiLockedList.tsx` component renders all the on-chain locked objects based on the `LockedListingQuery` property. Call the API service to fetch the `ApiLockedObject` data using the provided query parameters. One caveat around the API service is that the `creator` field of the `ApiLockedObject` could be stale because the `Locked` object has the `store` ability. This means that the object can be transferred freely, hence, the ownership might not be correctly tracked by the API service. That's why you still fetch from the Iota blockchain as an additional step to define the object with latest on-chain information to ensure its data correctness in regards to ownership. ```ts title='src/components/locked/ApiLockedList.tsx' const { data, fetchNextPage, hasNextPage, isLoading, isFetchingNextPage } = useInfiniteQuery({ @@ -795,7 +796,7 @@ const { data, fetchNextPage, hasNextPage, isLoading, isFetchingNextPage } = useI ) ).json(); - const objects = await suiClient.multiGetObjects({ + const objects = await iotaClient.multiGetObjects({ ids: data.data.map((x: ApiLockedObject) => x.objectId), options: { showOwner: true, @@ -804,7 +805,7 @@ const { data, fetchNextPage, hasNextPage, isLoading, isFetchingNextPage } = useI }); return { - suiObjects: objects.map((x) => x.data), + iotaObjects: objects.map((x) => x.data), api: data, }; }, diff --git a/docs/content/guides/developer/app-examples/trustless-token-swap/indexer-api.mdx b/docs/content/guides/developer/app-examples/trustless-token-swap/indexer-api.mdx index b01bb7e4ab0..ab6c553810f 100644 --- a/docs/content/guides/developer/app-examples/trustless-token-swap/indexer-api.mdx +++ b/docs/content/guides/developer/app-examples/trustless-token-swap/indexer-api.mdx @@ -7,7 +7,7 @@ import AppExamplesSwapSource from "../../../../_snippets/app-examples-swap-sourc :::note Multi-Page Guide -This is the second in a [three-part guide](../trustless-token-swap.mdx) on how to build a trustless atomic swap on Sui. +This is the second in a [three-part guide](../trustless-token-swap.mdx) on how to build a trustless atomic swap on Iota. ::: @@ -23,10 +23,10 @@ Before getting started, make sure you: - Understand [the mechanism behind the Trading backend](../trustless-token-swap.mdx). - Install [`pnpm` through this guide](https://pnpm.io/installation) as this example uses it as the package manager. -- Check out the [indexer's README](https://github.com/MystenLabs/sui/tree/main/examples/trading/api) to setup the development environment. +- Check out the [indexer's README](https://github.com/iotaledger/iota/tree/main/examples/trading/api) to setup the development environment. - Check out [Prisma](https://www.prisma.io/) to get an overall sense of the technology that facilitates all the database interactions. - Check out [Express](https://expressjs.com/) to learn how to set up a web server application in Node.js. This server bootstraps your API service. -- Check out [Sui TypeScript SDK](https://sdk.mystenlabs.com/typescript) for basic usage on how to interact with Sui with TypeScript. +- Check out [Iota TypeScript SDK](https://sdk.mystenlabs.com/typescript) for basic usage on how to interact with Iota with TypeScript. ## Indexing service @@ -94,36 +94,36 @@ Let's first examine `event-indexer.ts`: #### Imports ```ts title='event-indexer.ts' -import { EventId, SuiClient, SuiEvent, SuiEventFilter } from '@mysten/sui.js/client'; +import { EventId, IotaClient, IotaEvent, IotaEventFilter } from '@iota/iota.js/client'; import { CONFIG } from '../config'; import { prisma } from '../db'; -import { getClient } from '../sui-utils'; +import { getClient } from '../iota-utils'; import { handleEscrowObjects } from './escrow-handler'; import { handleLockObjects } from './locked-handler'; ``` -These lines import the necessary modules and dependencies for the script. The `EventId`, `SuiClient`, `SuiEvent`, and `SuiEventFilter` types are imported from the `@mysten/sui.js/client` package. The `CONFIG` constant is imported from the local `config` module, `prisma` from the local `db` module, `getClient` from the local `sui-utils` module, and the `handleEscrowObjects` and `handleLockObjects` functions from the local `escrow-handler` and `locked-handler` modules respectively. +These lines import the necessary modules and dependencies for the script. The `EventId`, `IotaClient`, `IotaEvent`, and `IotaEventFilter` types are imported from the `@iota/iota.js/client` package. The `CONFIG` constant is imported from the local `config` module, `prisma` from the local `db` module, `getClient` from the local `iota-utils` module, and the `handleEscrowObjects` and `handleLockObjects` functions from the local `escrow-handler` and `locked-handler` modules respectively. #### Type definitions ```ts title='event-indexer.ts' -type SuiEventsCursor = EventId | null | undefined; +type IotaEventsCursor = EventId | null | undefined; type EventExecutionResult = { - cursor: SuiEventsCursor; + cursor: IotaEventsCursor; hasNextPage: boolean; }; type EventTracker = { // The module that defines the type, with format `package::module` type: string; - filter: SuiEventFilter; - callback: (events: SuiEvent[], type: string) => any; + filter: IotaEventFilter; + callback: (events: IotaEvent[], type: string) => any; }; ``` -Three custom types are defined here: `SuiEventsCursor`, `EventExecutionResult`, and `EventTracker`. `SuiEventsCursor` is a type alias for `EventId | null | undefined`, representing the possible states of a cursor pointing to events on the Sui network. `EventExecutionResult` represents the result of executing an event job, including the updated cursor and a flag indicating whether there are more pages of events to process. `EventTracker` represents an event tracker, which includes the type of the event, a filter for the event, and a callback function to handle the event. +Three custom types are defined here: `IotaEventsCursor`, `EventExecutionResult`, and `EventTracker`. `IotaEventsCursor` is a type alias for `EventId | null | undefined`, representing the possible states of a cursor pointing to events on the Iota network. `EventExecutionResult` represents the result of executing an event job, including the updated cursor and a flag indicating whether there are more pages of events to process. `EventTracker` represents an event tracker, which includes the type of the event, a filter for the event, and a callback function to handle the event. #### Constants @@ -158,9 +158,9 @@ The `EVENTS_TO_TRACK` constant is an array of `EventTracker` objects. Each `Even ```ts title='event-indexer.ts' const executeEventJob = async ( - client: SuiClient, + client: IotaClient, tracker: EventTracker, - cursor: SuiEventsCursor, + cursor: IotaEventsCursor, ): Promise => { try { // Get the events from the chain. @@ -195,10 +195,10 @@ const executeEventJob = async ( }; ``` -This function executes an event job. It takes a `SuiClient`, an `EventTracker`, and a `SuiEventsCursor` as arguments, and returns a promise that resolves to an `EventExecutionResult`. The function tries to get the events from the chain according to the filter defined in the `EventTracker`. If successful, it handles the data transformations defined for each event and updates the cursor if there were changes. If an error occurs during execution, it logs the error and returns the original cursor without updating it. +This function executes an event job. It takes a `IotaClient`, an `EventTracker`, and a `IotaEventsCursor` as arguments, and returns a promise that resolves to an `EventExecutionResult`. The function tries to get the events from the chain according to the filter defined in the `EventTracker`. If successful, it handles the data transformations defined for each event and updates the cursor if there were changes. If an error occurs during execution, it logs the error and returns the original cursor without updating it. ```ts title='event-indexer.ts' -const runEventJob = async (client: SuiClient, tracker: EventTracker, cursor: SuiEventsCursor) => { +const runEventJob = async (client: IotaClient, tracker: EventTracker, cursor: IotaEventsCursor) => { const result = await executeEventJob(client, tracker, cursor); // Trigger a timeout. Depending on the result, we either wait 0ms or the polling interval. @@ -211,7 +211,7 @@ const runEventJob = async (client: SuiClient, tracker: EventTracker, cursor: Sui }; ``` -This function runs an event job. It takes a `SuiClient`, an `EventTracker`, and a `SuiEventsCursor` as arguments. It calls `executeEventJob` and schedules another call to `runEventJob` based on the result of the execution. If there are more pages of events to process, it waits for the polling interval defined in `CONFIG.POLLING_INTERVAL_MS` before making the next call. Otherwise, it makes the call immediately. +This function runs an event job. It takes a `IotaClient`, an `EventTracker`, and a `IotaEventsCursor` as arguments. It calls `executeEventJob` and schedules another call to `runEventJob` based on the result of the execution. If there are more pages of events to process, it waits for the polling interval defined in `CONFIG.POLLING_INTERVAL_MS` before making the next call. Otherwise, it makes the call immediately. ```ts title='event-indexer.ts' const getLatestCursor = async (tracker: EventTracker) => { @@ -244,7 +244,7 @@ const saveLatestCursor = async (tracker: EventTracker, cursor: EventId) => { }; ``` -This function saves the latest cursor for an event tracker to the database. It takes an `EventTracker` and a `SuiEventsCursor` as arguments and returns a promise that resolves to the saved cursor. If the cursor already exists in the database, it updates the existing entry. Otherwise, it creates a new entry. +This function saves the latest cursor for an event tracker to the database. It takes an `EventTracker` and a `IotaEventsCursor` as arguments and returns a promise that resolves to the saved cursor. If the cursor already exists in the database, it updates the existing entry. Otherwise, it creates a new entry. ```ts title='event-indexer.ts' export const setupListeners = async () => { @@ -254,7 +254,7 @@ export const setupListeners = async () => { }; ``` -This function sets up all the listeners for the events to track. It iterates over the `EVENTS_TO_TRACK` array and calls `runEventJob` for each event tracker, passing the `SuiClient`, the event tracker, and the latest cursor for the event tracker as arguments. +This function sets up all the listeners for the events to track. It iterates over the `EVENTS_TO_TRACK` array and calls `runEventJob` for each event tracker, passing the `IotaClient`, the event tracker, and the latest cursor for the event tracker as arguments. Now let’s take a look at `escrow-handler.ts`: @@ -263,13 +263,13 @@ Now let’s take a look at `escrow-handler.ts`: #### Imports ```ts title='escrow-handler.ts' -import { SuiEvent } from '@mysten/sui.js/client'; +import { IotaEvent } from '@iota/iota.js/client'; import { Prisma } from '@prisma/client'; import { prisma } from '../db'; ``` -These lines import the necessary modules and dependencies for the script. The `SuiEvent` type is imported from the `@mysten/sui.js/client` package. The `Prisma` namespace is imported from the `@prisma/client package`. The `prisma` instance is imported from the local `db` module. +These lines import the necessary modules and dependencies for the script. The `IotaEvent` type is imported from the `@iota/iota.js/client` package. The `Prisma` namespace is imported from the `@prisma/client package`. The `prisma` instance is imported from the local `db` module. #### Type definitions @@ -298,7 +298,7 @@ Four custom types are defined here: `EscrowEvent`, `EscrowCreated`, `EscrowSwapp #### Functions ```ts title='escrow-handler.ts' -export const handleEscrowObjects = async (events: SuiEvent[], type: string) => { +export const handleEscrowObjects = async (events: IotaEvent[], type: string) => { const updates: Record = {}; for (const event of events) { @@ -351,20 +351,20 @@ export const handleEscrowObjects = async (events: SuiEvent[], type: string) => { }; ``` -This function handles all events emitted by the `escrow` module. It takes an array of `SuiEvent` objects and a string representing the type of the events as arguments. The function processes each event and updates the corresponding escrow object in the database accordingly. If an event indicates that an escrow was canceled or swapped, the function marks the corresponding escrow object as canceled or swapped. If an event indicates that an escrow was created, the function creates a new escrow object with the details from the event. +This function handles all events emitted by the `escrow` module. It takes an array of `IotaEvent` objects and a string representing the type of the events as arguments. The function processes each event and updates the corresponding escrow object in the database accordingly. If an event indicates that an escrow was canceled or swapped, the function marks the corresponding escrow object as canceled or swapped. If an event indicates that an escrow was created, the function creates a new escrow object with the details from the event. ### `locked-handler.ts` #### Imports ```ts title='locked-handler.ts' -import { SuiEvent } from '@mysten/sui.js/client'; +import { IotaEvent } from '@iota/iota.js/client'; import { Prisma } from '@prisma/client'; import { prisma } from '../db'; ``` -These lines import the necessary modules and dependencies for the script. The `SuiEvent` type is imported from the `@mysten/sui.js/client` package. The `Prisma` namespace is imported from the `@prisma/client package`. The `prisma` instance is imported from the local `db` module. +These lines import the necessary modules and dependencies for the script. The `IotaEvent` type is imported from the `@iota/iota.js/client` package. The `Prisma` namespace is imported from the `@prisma/client package`. The `prisma` instance is imported from the local `db` module. #### Type definitions @@ -388,7 +388,7 @@ Three custom types are defined here: `LockEvent`, `LockCreated`, and `LockDestro #### Functions ```ts title='locked-handler.ts' -export const handleLockObjects = async (events: SuiEvent[], type: string) => { +export const handleLockObjects = async (events: IotaEvent[], type: string) => { const updates: Record = {}; for (const event of events) { @@ -433,7 +433,7 @@ export const handleLockObjects = async (events: SuiEvent[], type: string) => { }; ``` -This function handles all events emitted by the `lock` module. It takes an array of `SuiEvent` objects and a string representing the type of the events as arguments. The function processes each event and updates the corresponding locked object in the database accordingly. If an event indicates that a lock was destroyed, the function marks the corresponding locked object as deleted. If an event indicates that a lock was created, the function creates a new locked object with the details from the event. +This function handles all events emitted by the `lock` module. It takes an array of `IotaEvent` objects and a string representing the type of the events as arguments. The function processes each event and updates the corresponding locked object in the database accordingly. If an event indicates that a lock was destroyed, the function marks the corresponding locked object as deleted. If an event indicates that a lock was created, the function creates a new locked object with the details from the event. ## API service diff --git a/docs/content/guides/developer/app-examples/weather-oracle.mdx b/docs/content/guides/developer/app-examples/weather-oracle.mdx index cda01d9c5ee..79e15210581 100644 --- a/docs/content/guides/developer/app-examples/weather-oracle.mdx +++ b/docs/content/guides/developer/app-examples/weather-oracle.mdx @@ -1,43 +1,44 @@ --- -title: Sui Weather Oracle +title: Iota Weather Oracle description: Write a module (smart contract) in Move that fetches the weather data from the OpenWeather API every 10 minutes and updates the weather conditions for over 1,000 locations around the world. --- -import InitializeSuiClientCli from "../../../_snippets/initialize-sui-client-cli.mdx"; +import InitializeIotaClientCli from "../../../_snippets/initialize-iota-client-cli.mdx"; import PublishToDevnetWithCoins from "../../../_snippets/publish-to-devnet-with-coins.mdx"; -This guide demonstrates writing a module (smart contract) in Move, deploying it on Devnet, and adding a backend, which fetches the weather data from the OpenWeather API every 10 minutes and updates the weather conditions for each city. The dApp created in this guide is called Sui Weather Oracle and it provides real-time weather data for over 1,000 locations around the world. +This guide demonstrates writing a module (smart contract) in Move, deploying it on Devnet, and adding a backend, which fetches the weather data from the OpenWeather API every 10 minutes and updates the weather conditions for each city. The dApp created in this guide is called Iota Weather Oracle and it provides real-time weather data for over 1,000 locations around the world. -You can access and use the weather data from the OpenWeather API for various applications, such as randomness, betting, gaming, insurance, travel, education, or research. You can also mint a weather NFT based on the weather data of a city, using the `mint` function of the SUI Weather Oracle smart contract. +You can access and use the weather data from the OpenWeather API for various applications, such as randomness, betting, gaming, insurance, travel, education, or research. You can also mint a weather NFT based on the weather data of a city, using the `mint` function of the IOTA Weather Oracle smart contract. -This guide assumes you have [installed Sui](../getting-started/sui-install.mdx) and understand Sui fundamentals. +This guide assumes you have [installed Iota](../getting-started/iota-install.mdx) and understand Iota fundamentals. ## Move smart contract -As with all Sui dApps, a Move package on chain powers the logic of Sui Weather Oracle. The following instruction walks you through creating and publishing the module. +As with all Iota dApps, a Move package on chain powers the logic of Iota Weather Oracle. The following instruction walks you through creating and publishing the module. ### Weather Oracle module Before you get started, you must initialize a Move package. Open a terminal or console in the directory you want to store the example and run the following command to create an empty package with the name `weather_oracle`: ```bash -sui move new weather_oracle +iota move new weather_oracle ``` With that done, it's time to jump into some code. Create a new file in the `sources` directory with the name `weather.move` and populate the file with the following code: ```rust title='weather.move' // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module oracle::weather { use std::option::{Self, Option}; use std::string::{Self, String}; - use sui::dynamic_object_field as dof; - use sui::object::{Self, UID}; - use sui::package; - use sui::transfer::{Self}; - use sui::tx_context::{Self, TxContext}; + use iota::dynamic_object_field as dof; + use iota::object::{Self, UID}; + use iota::package; + use iota::transfer::{Self}; + use iota::tx_context::{Self, TxContext}; } ``` @@ -94,17 +95,17 @@ fun init(otw: WEATHER, ctx: &mut TxContext) { transfer::share_object(WeatherOracle { id: object::new(ctx), address: tx_context::sender(ctx), - name: string::utf8(b"SuiMeteo"), + name: string::utf8(b"IotaMeteo"), description: string::utf8(b"A weather oracle."), }); transfer::public_transfer(cap, tx_context::sender(ctx)); // Transfer the admin capability to the sender. } ``` -- The first struct, `AdminCap`, is a [capability](concepts/sui-move-concepts/patterns/capabilities.mdx). -- The second struct, `WEATHER`, is a [one-time witness](concepts/sui-move-concepts/one-time-witness.mdx) that ensures only a single instance of this `Weather` ever exists. +- The first struct, `AdminCap`, is a [capability](concepts/iota-move-concepts/patterns/capabilities.mdx). +- The second struct, `WEATHER`, is a [one-time witness](concepts/iota-move-concepts/one-time-witness.mdx) that ensures only a single instance of this `Weather` ever exists. - The `WeatherOracle` struct works as a registry and stores the `geoname_id`s of the `CityWeatherOracle`s as [dynamic fields](concepts/dynamic-fields.mdx). -- The [`init` function](concepts/sui-move-concepts/init.mdx) creates and sends the `Publisher` and `AdminCap` objects to the sender. Also, it creates a [shared object](concepts/object-ownership/shared.mdx) for all the `CityWeatherOracle`s. +- The [`init` function](concepts/iota-move-concepts/init.mdx) creates and sends the `Publisher` and `AdminCap` objects to the sender. Also, it creates a [shared object](concepts/object-ownership/shared.mdx) for all the `CityWeatherOracle`s. So far, you've set up the data structures within the module. Now, create a function that initializes a `CityWeatherOracle` and adds it as [dynamic fields](concepts/dynamic-fields.mdx) to the `WeatherOracle` object: @@ -147,9 +148,9 @@ public fun add_city( } ``` -The `add_city` function is a public function that allows the owner of the `AdminCap` of the Sui Weather Oracle smart contract to add a new `CityWeatherOracle`. The function requires the admin to provide a capability object that proves their permission to add a city. The function also requires a mutable reference to the oracle object, which is the main object that stores the weather data on the blockchain. The function takes several parameters that describe the city, such as the geoname ID, name, country, latitude, longitude, and positive latitude and longitude. The function then creates a new city weather oracle object, which is a sub-object that stores and updates the weather data for a specific city. The function initializes the city weather oracle object with the parameters provided by the admin, and sets the weather data to be zero or none. The function then adds a new dynamic object field to the oracle object, using the geoname ID as the key and the city weather oracle object as the value. This way, the function adds a new city to the oracle, and makes it ready to receive and update the weather data from the backend service. +The `add_city` function is a public function that allows the owner of the `AdminCap` of the Iota Weather Oracle smart contract to add a new `CityWeatherOracle`. The function requires the admin to provide a capability object that proves their permission to add a city. The function also requires a mutable reference to the oracle object, which is the main object that stores the weather data on the blockchain. The function takes several parameters that describe the city, such as the geoname ID, name, country, latitude, longitude, and positive latitude and longitude. The function then creates a new city weather oracle object, which is a sub-object that stores and updates the weather data for a specific city. The function initializes the city weather oracle object with the parameters provided by the admin, and sets the weather data to be zero or none. The function then adds a new dynamic object field to the oracle object, using the geoname ID as the key and the city weather oracle object as the value. This way, the function adds a new city to the oracle, and makes it ready to receive and update the weather data from the backend service. -If you want to delete a city from the Sui Weather Oracle, call the `remove_city` function of the smart contract. The `remove_city` function allows the admin of the smart contract to remove a city from the oracle. The function requires the admin to provide a capability object that proves their permission to remove a city. The function also requires a mutable reference to the oracle object, which is the main object that stores and updates the weather data on the blockchain. The function takes the geoname ID of the city as a parameter, and deletes the city weather oracle object for the city. The function also removes the dynamic object field for the city from the oracle object. This way, the function deletes a city from the oracle, and frees up some storage space on the blockchain. +If you want to delete a city from the Iota Weather Oracle, call the `remove_city` function of the smart contract. The `remove_city` function allows the admin of the smart contract to remove a city from the oracle. The function requires the admin to provide a capability object that proves their permission to remove a city. The function also requires a mutable reference to the oracle object, which is the main object that stores and updates the weather data on the blockchain. The function takes the geoname ID of the city as a parameter, and deletes the city weather oracle object for the city. The function also removes the dynamic object field for the city from the oracle object. This way, the function deletes a city from the oracle, and frees up some storage space on the blockchain. ```rust title='weather.move' public fun remove_city( @@ -180,7 +181,7 @@ public fun remove_city( } ``` -Now that you have implemented the `add_city` and `remove_city` functions, you can move on to the next step, which is to see how you can update the weather data for each city. The backend service fetches the weather data from the OpenWeather API every 10 minutes, and then passes the data to the `update` function of the Sui Weather Oracle smart contract. The `update` function takes the geoname ID and the new weather data of the city as parameters, and updates the city weather oracle object with the new data. This way, the weather data on the blockchain is always up to date and accurate. +Now that you have implemented the `add_city` and `remove_city` functions, you can move on to the next step, which is to see how you can update the weather data for each city. The backend service fetches the weather data from the OpenWeather API every 10 minutes, and then passes the data to the `update` function of the Iota Weather Oracle smart contract. The `update` function takes the geoname ID and the new weather data of the city as parameters, and updates the city weather oracle object with the new data. This way, the weather data on the blockchain is always up to date and accurate. ```rust title='weather.move' public fun update( @@ -212,7 +213,7 @@ public fun update( } ``` -You have defined the data structure of the Sui Weather Oracle smart contract, but you need some functions to access and manipulate the data. Now, add some helper functions that read and return the weather data for a `WeatherOracle` object. These functions allow you to get the weather data for a specific city in the oracle. These functions also allow you to format and display the weather data in a user-friendly way. +You have defined the data structure of the Iota Weather Oracle smart contract, but you need some functions to access and manipulate the data. Now, add some helper functions that read and return the weather data for a `WeatherOracle` object. These functions allow you to get the weather data for a specific city in the oracle. These functions also allow you to format and display the weather data in a user-friendly way. ```rust title='weather.move' // --------------- Read-only References --------------- @@ -404,19 +405,19 @@ And with that, your `weather.move` code is complete. ## Deployment - + ## Backend -You have successfully deployed the Sui Weather Oracle smart contract on the blockchain. Now, it's time to create an Express backend that can interact with it. The Express backend performs the following tasks: +You have successfully deployed the Iota Weather Oracle smart contract on the blockchain. Now, it's time to create an Express backend that can interact with it. The Express backend performs the following tasks: - Initialize the smart contract with 1,000 cities using the `add_city` function of the smart contract. The backend passes the geoname ID, name, country, latitude, longitude, and positive latitude and longitude of each city as parameters to the function. - Fetch the weather data for each city from the OpenWeather API every 10 minutes, using the API key that you obtained from the website. The backend parses the JSON response and extracts the weather data for each city, such as the weather ID, temperature, pressure, humidity, visibility, wind speed, wind degree, wind gust, clouds, and timestamp. - Update the weather data for each city on the blockchain, using the `update` function of the smart contract. The backend passes the geoname ID and the new weather data of each city as parameters to the function. -The Express backend uses the [Sui Typescript SDK](https://sdk.mystenlabs.com/typescript), a TypeScript library that enables you to interact with the Sui blockchain and smart contracts. With the Sui Typescript SDK, you can connect to the Sui network, sign and submit transactions, and query the state of the smart contract. You also use the OpenWeather API to fetch the weather data for each city and update the smart contract every 10 minutes. Additionally, you can mint weather NFTs, if you want to explore that feature of the smart contract. +The Express backend uses the [Iota Typescript SDK](https://sdk.mystenlabs.com/typescript), a TypeScript library that enables you to interact with the Iota blockchain and smart contracts. With the Iota Typescript SDK, you can connect to the Iota network, sign and submit transactions, and query the state of the smart contract. You also use the OpenWeather API to fetch the weather data for each city and update the smart contract every 10 minutes. Additionally, you can mint weather NFTs, if you want to explore that feature of the smart contract. ### Initialize the project @@ -424,9 +425,9 @@ First, initialize your backend project. To do this, you need to follow these ste - Create a new folder named `weather-oracle-backend` and navigate to it in your terminal. - Run `npm init -y` to create a package.json file with default values. - Run `npm install express --save` to install Express as a dependency and save it to your package.json file. -- Run `npm install @mysten/bcs @mysten/sui.js axios csv-parse csv-parser dotenv pino retry-axios --save` to install the other dependencies and save them to your package.json file. These dependencies are: - - **@mysten/bcs**: a library for blockchain services. - - **@mysten/sui.js**: a library for smart user interfaces. +- Run `npm install @iota/bcs @iota/iota.js axios csv-parse csv-parser dotenv pino retry-axios --save` to install the other dependencies and save them to your package.json file. These dependencies are: + - **@iota/bcs**: a library for blockchain services. + - **@iota/iota.js**: a library for smart user interfaces. - **axios**: a library for making HTTP requests. - **csv-parse**: a library for parsing CSV data. - **csv-parser**: a library for transforming CSV data into JSON objects. @@ -442,7 +443,7 @@ import { JsonRpcProvider, RawSigner, TransactionBlock, -} from "@mysten/sui.js"; +} from "@iota/iota.js"; import * as dotenv from "dotenv"; import { City } from "./city"; import { get1000Geonameids } from "./filter-cities"; @@ -562,7 +563,7 @@ import { JsonRpcProvider, RawSigner, TransactionBlock, -} from "@mysten/sui.js"; +} from "@iota/iota.js"; import * as dotenv from "dotenv"; import { City } from "./city"; import { @@ -704,4 +705,4 @@ The code in index.ts does the following: - Calls another async function called `getWeatherOracleDynamicFields`, which takes the package id, the module name, and the signer as arguments, and returns an array of weather oracle dynamic field objects that contain information such as name and object id. - Calls the `performUpdates` function with the cities and weather oracle dynamic fields arrays as arguments. -Congratulations, you completed the Sui Weather Oracle tutorial. You can carry the lessons learned here forward when building your next Sui project. +Congratulations, you completed the Iota Weather Oracle tutorial. You can carry the lessons learned here forward when building your next Iota project. diff --git a/docs/content/guides/developer/cryptography.mdx b/docs/content/guides/developer/cryptography.mdx index 459fbe54b9c..3d5fd819d81 100644 --- a/docs/content/guides/developer/cryptography.mdx +++ b/docs/content/guides/developer/cryptography.mdx @@ -2,13 +2,13 @@ title: Cryptography --- -Effective use of cryptography keeps your smart contract transactions secure on the Sui blockchain. +Effective use of cryptography keeps your smart contract transactions secure on the Iota blockchain. ## Signature verification -Move contracts in Sui support verifications for several on-chain signature schemes. Not all signatures supported in on-chain verification are supported as user signature verification. See [Signatures](../../concepts/cryptography/transaction-auth/signatures.mdx) for valid signature schemes for transaction authorization. +Move contracts in Iota support verifications for several on-chain signature schemes. Not all signatures supported in on-chain verification are supported as user signature verification. See [Signatures](../../concepts/cryptography/transaction-auth/signatures.mdx) for valid signature schemes for transaction authorization. -Go to [Sui On-Chain Signatures Verification in Move](./cryptography/signing.mdx). +Go to [Iota On-Chain Signatures Verification in Move](./cryptography/signing.mdx). ## Groth16 @@ -30,4 +30,4 @@ Go to [ECVRF](./cryptography/ecvrf.mdx). ## Related links -- [Cryptography concepts](../../concepts/cryptography.mdx): Before you use the guides, you might want to learn about the concepts behind the use of cryptography on Sui. \ No newline at end of file +- [Cryptography concepts](../../concepts/cryptography.mdx): Before you use the guides, you might want to learn about the concepts behind the use of cryptography on Iota. \ No newline at end of file diff --git a/docs/content/guides/developer/cryptography/ecvrf.mdx b/docs/content/guides/developer/cryptography/ecvrf.mdx index 4bb55dac4b0..38fad6d2b86 100644 --- a/docs/content/guides/developer/cryptography/ecvrf.mdx +++ b/docs/content/guides/developer/cryptography/ecvrf.mdx @@ -8,9 +8,9 @@ A verifiable random function (VRF) is a cryptographic primitive that enables you ## VRF construction -The VRF used in the Move API in Sui is an elliptic curve VRF (ECVRF) following the [CFRG VRF draft specifications version 15](https://datatracker.ietf.org/doc/draft-irtf-cfrg-vrf/15/). It uses [Ristretto255](https://ristretto.group) elliptic curve group construction with the SHA-512 hash function. The nonce is generated according to [RFC6979](https://www.rfc-editor.org/info/rfc6979). +The VRF used in the Move API in Iota is an elliptic curve VRF (ECVRF) following the [CFRG VRF draft specifications version 15](https://datatracker.ietf.org/doc/draft-irtf-cfrg-vrf/15/). It uses [Ristretto255](https://ristretto.group) elliptic curve group construction with the SHA-512 hash function. The nonce is generated according to [RFC6979](https://www.rfc-editor.org/info/rfc6979). -Any implementation following the same specifications with suite string `sui_vrf` (see section 5 in the [VRF specs](https://datatracker.ietf.org/doc/draft-irtf-cfrg-vrf/15/)) can be used to compute VRF output and generate proofs. +Any implementation following the same specifications with iotate string `iota_vrf` (see section 5 in the [VRF specs](https://datatracker.ietf.org/doc/draft-irtf-cfrg-vrf/15/)) can be used to compute VRF output and generate proofs. The [fastcrypto](https://github.com/MystenLabs/fastcrypto) library provides a CLI tool for such an implementation and is used in the following example. @@ -44,12 +44,12 @@ Output: 2b7e45821d80567761e8bb3fc519efe5ad80cdb4423227289f960319bbcf6eea1aef30c0 ### Verify proof -You can verify the proof and output in a smart contract using `sui::ecvrf::ecvrf_verify` from the Sui Move framework: +You can verify the proof and output in a smart contract using `iota::ecvrf::ecvrf_verify` from the Iota Move framework: ```move module math::ecvrf_test { - use sui::ecvrf; - use sui::event; + use iota::ecvrf; + use iota::event; /// Event on whether the output is verified struct VerifiedEvent has copy, drop { diff --git a/docs/content/guides/developer/cryptography/groth16.mdx b/docs/content/guides/developer/cryptography/groth16.mdx index 328a64e87aa..cc014ae1223 100644 --- a/docs/content/guides/developer/cryptography/groth16.mdx +++ b/docs/content/guides/developer/cryptography/groth16.mdx @@ -6,7 +6,7 @@ A zero-knowledge proof allows a prover to validate that a statement is true with Zero-knowledge succinct non-interactive argument of knowledge (zk-SNARKs) are a family of zero-knowledge proofs that are non-interactive, have succinct proof size and efficient verification time. An important and widely used variant of them is pairing-based zk-SNARKs like the [Groth16](https://eprint.iacr.org/2016/260.pdf) proof system, which is one of the most efficient and widely used. -The Move API in Sui enables you to verify any statement that can be expressed in a NP-complete language efficiently using Groth16 zk-SNARKs over either the BN254 or BLS12-381 elliptic curve constructions. +The Move API in Iota enables you to verify any statement that can be expressed in a NP-complete language efficiently using Groth16 zk-SNARKs over either the BN254 or BLS12-381 elliptic curve constructions. There are high-level languages for expressing these statements, such as [Circom](https://docs.circom.io), used in the following example. @@ -14,7 +14,7 @@ Groth16 requires a trusted setup for each circuit to generate the verification k ## Usage -The following example demonstrates how to create a Groth16 proof from a statement written in Circom and then verify it using the Sui Move API. The API currently supports up to eight public inputs. +The following example demonstrates how to create a Groth16 proof from a statement written in Circom and then verify it using the Iota Move API. The API currently supports up to eight public inputs. ### Create circuit @@ -42,7 +42,7 @@ This outputs the constraints in R1CS format and the circuit in Wasm format. ### Generate proof -To generate a proof verifiable in Sui, you need to generate a witness. This example uses Arkworks' [ark-circom](https://github.com/gakonst/ark-circom) Rust library. The code constructs a witness for the circuit and generates a proof for it for a given input. Finally, it verifies that the proof is correct. +To generate a proof verifiable in Iota, you need to generate a witness. This example uses Arkworks' [ark-circom](https://github.com/gakonst/ark-circom) Rust library. The code constructs a witness for the circuit and generates a proof for it for a given input. Finally, it verifies that the proof is correct. ```rust use ark_bn254::Bn254; @@ -84,9 +84,9 @@ fn main() { ``` The proof shows that an input (7) which, when hashed with the Poseidon hash function, gives a certain output (which in this case is `inputs[0] = 7061949393491957813657776856458368574501817871421526214197139795307327923534`). -### Verification in Sui +### Verification in Iota -The API in Sui for verifying a proof expects a special processed verification key, where only a subset of the values are used. Ideally, computation for this prepared verification key happens only once per circuit. You can perform this processing using the `sui::groth16::prepare_verifying_key` method of the Sui Move API with a serialization of the `params.vk` value used previously. +The API in Iota for verifying a proof expects a special processed verification key, where only a subset of the values are used. Ideally, computation for this prepared verification key happens only once per circuit. You can perform this processing using the `iota::groth16::prepare_verifying_key` method of the Iota Move API with a serialization of the `params.vk` value used previously. The output of the `prepare_verifying_key` function is a vector with four byte arrays, which corresponds to the `vk_gamma_abc_g1_bytes`, `alpha_g1_beta_g2_bytes`, `gamma_g2_neg_pc_bytes`, `delta_g2_neg_pc_bytes`. @@ -106,8 +106,8 @@ The following example smart contract prepares a verification key and verifies th ```rust module test::groth16_test { - use sui::groth16; - use sui::event; + use iota::groth16; + use iota::event; /// Event on whether the proof is verified struct VerifiedEvent has copy, drop { diff --git a/docs/content/guides/developer/cryptography/hashing.mdx b/docs/content/guides/developer/cryptography/hashing.mdx index 000e00378cc..69f231bfa24 100644 --- a/docs/content/guides/developer/cryptography/hashing.mdx +++ b/docs/content/guides/developer/cryptography/hashing.mdx @@ -1,16 +1,16 @@ --- title: Hashing -description: Sui supports SHA2-256, SHA3-256, Keccak256, Blake2b-256 cryptographic hash functions. +description: Iota supports SHA2-256, SHA3-256, Keccak256, Blake2b-256 cryptographic hash functions. --- A cryptographic hash function is a widely used cryptographic primitive that maps an arbitrary length input to a fixed length output, the hash value. The hash function is designed to be a one-way function, which means that it is infeasible to invert the function to find the input data from a given hash value, and to be collision resistant, which means that it is infeasible to find two different inputs that map to the same hash value. -The Sui Move API supports the following cryptographic hash functions: +The Iota Move API supports the following cryptographic hash functions: * SHA2-256 as `std::hash::sha2_256` * SHA3-256 as `std::hash::sha3_256` -* Keccak256 as `sui::hash::keccak256` -* Blake2b-256 as `sui::hash::blake2b256` +* Keccak256 as `iota::hash::keccak256` +* Blake2b-256 as `iota::hash::blake2b256` ## Usage @@ -19,9 +19,9 @@ The SHA2-256 and SHA3-256 hash functions are available in the Move Standard Libr ```move module test::hashing_std { use std::hash; - use sui::object::{Self, UID}; - use sui::tx_context::TxContext; - use sui::transfer; + use iota::object::{Self, UID}; + use iota::tx_context::TxContext; + use iota::transfer; use std::vector; /// Object that holds the output hash value. @@ -41,14 +41,14 @@ module test::hashing_std { } ``` -The Keccak256 and Blake2b-256 hash functions are available through the `sui::hash` module in the Sui Move Library. An example of how to use the Keccak256 hash function in a smart contract is shown below. Notice that here, the input to the hash function is given as a reference. This is the case for both Keccak256 and Blake2b-256. +The Keccak256 and Blake2b-256 hash functions are available through the `iota::hash` module in the Iota Move Library. An example of how to use the Keccak256 hash function in a smart contract is shown below. Notice that here, the input to the hash function is given as a reference. This is the case for both Keccak256 and Blake2b-256. ```move -module test::hashing_sui { - use sui::hash; - use sui::object::{Self, UID}; - use sui::tx_context::TxContext; - use sui::transfer; +module test::hashing_iota { + use iota::hash; + use iota::object::{Self, UID}; + use iota::tx_context::TxContext; + use iota::transfer; use std::vector; /// Object that holds the output hash value. diff --git a/docs/content/guides/developer/cryptography/signing.mdx b/docs/content/guides/developer/cryptography/signing.mdx index 8a1dc1b1849..28390771845 100644 --- a/docs/content/guides/developer/cryptography/signing.mdx +++ b/docs/content/guides/developer/cryptography/signing.mdx @@ -1,8 +1,8 @@ --- -title: Sui On-Chain Signatures Verification in Move +title: Iota On-Chain Signatures Verification in Move --- -Move contracts in Sui support verifications for several signature schemes on-chain. Not all signatures supported in on-chain verification are supported as user signature verification. See [Sui Signatures](/concepts/cryptography/transaction-auth/signatures.mdx#user-signature) for valid signature schemes for transaction authorization. +Move contracts in Iota support verifications for several signature schemes on-chain. Not all signatures supported in on-chain verification are supported as user signature verification. See [Iota Signatures](/concepts/cryptography/transaction-auth/signatures.mdx#user-signature) for valid signature schemes for transaction authorization. This topic covers: 1. How to use [fastcrypto](https://github.com/MystenLabs/fastcrypto)'s CLI tool to create a signature of a given scheme. For testing and debugging only, DO NOT use in production. @@ -47,7 +47,7 @@ Public key in hex: $PK 2. Call the verify method in Move. All inputs are represented in bytes in hex format: ```move - use sui::ed25519; + use iota::ed25519; let msg = x"$MSG"; let pk = x"$PK"; @@ -74,7 +74,7 @@ Public key in hex: $PK 2. Call the verify method in Move. ```move - use sui::ecdsa_k1; + use iota::ecdsa_k1; let msg = x"$MSG"; let pk = x"$PK"; @@ -101,7 +101,7 @@ Public key in hex: $PK 2. Call the ecrecover method in Move and check equality. ```move - use sui::ecdsa_k1; + use iota::ecdsa_k1; let msg = x"$MSG"; let pk = x"$PK"; @@ -129,7 +129,7 @@ Public key in hex: $PK 2. Call the verify method in Move. ```move - use sui::ecdsa_r1; + use iota::ecdsa_r1; let msg = x"$MSG"; let pk = x"$PK"; @@ -157,7 +157,7 @@ Public key in hex: $PK 2. Call the ecrecover method in Move and check equality. ```move - use sui::ecdsa_r1; + use iota::ecdsa_r1; let msg = x"$MSG"; let pk = x"$PK"; @@ -185,7 +185,7 @@ Public key in hex: $PK 2. Call the verify method in Move. ```move - use sui::bls12381; + use iota::bls12381; let msg = x"$MSG"; let pk = x"$PK"; @@ -212,7 +212,7 @@ Public key in hex: $PK 2. Call the verify method in Move. ```move - use sui::bls12381; + use iota::bls12381; let msg = x"$MSG"; let pk = x"$PK"; diff --git a/docs/content/guides/developer/dev-cheat-sheet.mdx b/docs/content/guides/developer/dev-cheat-sheet.mdx index 4e3d1bba6ac..10b064115a6 100644 --- a/docs/content/guides/developer/dev-cheat-sheet.mdx +++ b/docs/content/guides/developer/dev-cheat-sheet.mdx @@ -1,9 +1,9 @@ --- -title: Sui Developer Cheat Sheet +title: Iota Developer Cheat Sheet sidebar_label: Dev Cheat Sheet --- -Quick reference on best practices for Sui Network developers. +Quick reference on best practices for Iota Network developers. ## Move @@ -12,14 +12,14 @@ Quick reference on best practices for Sui Network developers. - Read about package upgrades and write upgrade-friendly code: - Packages are immutable, so buggy package code can be called forever. Add protections at the object level instead. - If you upgrade a package `P` to `P'`, other packages and clients that depend on `P` will continue using `P`, not auto-update to `P'`. Both dependent packages and client code must be explicitly updated to point at `P'`. - - Packages that expect to be extended by dependent packages can avoid breaking their extensions with each upgrade by providing a standard (unchanging) interface that all versions conform to. See this example for [message sending](https://github.com/wormhole-foundation/wormhole/blob/74dea3bf22f0e27628b432c3e9eac05c85786a99/sui/wormhole/sources/publish_message.move) across a bridge from Wormhole. Extension packages that produce messages to send can use [`prepare_message`](https://github.com/wormhole-foundation/wormhole/blob/74dea3bf22f0e27628b432c3e9eac05c85786a99/sui/wormhole/sources/publish_message.move#L68-L90) from any version of the Wormhole package to produce a [`MessageTicket`](https://github.com/wormhole-foundation/wormhole/blob/74dea3bf22f0e27628b432c3e9eac05c85786a99/sui/wormhole/sources/publish_message.move#L52-L66) while client code to send the message must pass that `MessageTicket` into [`publish_message`](https://github.com/wormhole-foundation/wormhole/blob/74dea3bf22f0e27628b432c3e9eac05c85786a99/sui/wormhole/sources/publish_message.move#L92-L152) in the latest version of the package. + - Packages that expect to be extended by dependent packages can avoid breaking their extensions with each upgrade by providing a standard (unchanging) interface that all versions conform to. See this example for [message sending](https://github.com/wormhole-foundation/wormhole/blob/74dea3bf22f0e27628b432c3e9eac05c85786a99/iota/wormhole/sources/publish_message.move) across a bridge from Wormhole. Extension packages that produce messages to send can use [`prepare_message`](https://github.com/wormhole-foundation/wormhole/blob/74dea3bf22f0e27628b432c3e9eac05c85786a99/iota/wormhole/sources/publish_message.move#L68-L90) from any version of the Wormhole package to produce a [`MessageTicket`](https://github.com/wormhole-foundation/wormhole/blob/74dea3bf22f0e27628b432c3e9eac05c85786a99/iota/wormhole/sources/publish_message.move#L52-L66) while client code to send the message must pass that `MessageTicket` into [`publish_message`](https://github.com/wormhole-foundation/wormhole/blob/74dea3bf22f0e27628b432c3e9eac05c85786a99/iota/wormhole/sources/publish_message.move#L92-L152) in the latest version of the package. - `public` function signatures cannot be deleted or changed, but `public(friend)` functions can. Use `public(friend)` or private visibility liberally unless you are exposing library functions that will live forever. - It is not possible to delete `struct` types, add new fields (though you can add dynamic fields), or add new [abilities](https://move-language.github.io/move/abilities.html) via an upgrade. Introduce new types carefully—they will live forever! - Use `vector`-backed collections (`vector`, `VecSet`, `VecMap`, `PriorityQueue`) with a **known** maximum size of ≤ 1000 items. - Use dynamic field-backed collections (`Table`, `Bag`, `ObjectBag`, `ObjectTable`, `LinkedTable`) for any collection that allows third-party addition, larger collections, and collections of unknown size. - Move objects have a maximum size of 250KB—any attempt to create a larger object leads to an aborted transaction. Ensure that your objects do not have an ever-growing `vector`-backed collection. -- If your function `f` needs a payment in (e.g.) SUI from the caller, use `fun f(payment: Coin)` not `fun f(payment: &mut Coin, amount: u64)`. This is safer for callers—they know exactly how much they are paying, and do not need to trust `f` to extract the right amount. -- Don't micro-optimize gas usage. Sui computation costs are rounded up to the closest _bucket_, so only very drastic changes will make a difference. In particular, if your transaction is already in the lowest cost bucket, it can't get any cheaper. +- If your function `f` needs a payment in (e.g.) IOTA from the caller, use `fun f(payment: Coin)` not `fun f(payment: &mut Coin, amount: u64)`. This is safer for callers—they know exactly how much they are paying, and do not need to trust `f` to extract the right amount. +- Don't micro-optimize gas usage. Iota computation costs are rounded up to the closest _bucket_, so only very drastic changes will make a difference. In particular, if your transaction is already in the lowest cost bucket, it can't get any cheaper. - Follow the [Move coding conventions](https://move-language.github.io/move/coding-conventions.html) for consistent style. ### Composability @@ -29,23 +29,23 @@ Quick reference on best practices for Sui Network developers. ### Testing -- Use [`sui::test_scenario`](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-framework/sources/test/test_scenario.move) to mimic multi-transaction, multi-sender test scenarios. -- Use the [`sui::test_utils`](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-framework/sources/test/test_utils.move#L5) module for better test error messages via `assert_eq`, debug printing via `print`, and test-only destruction via `destroy`. -- Use `sui move test --coverage` to compute code coverage information for your tests, and `sui move coverage source --module ` to see uncovered lines highlighted in red. Push coverage all the way to 100% if feasible. +- Use [`iota::test_scenario`](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/packages/iota-framework/sources/test/test_scenario.move) to mimic multi-transaction, multi-sender test scenarios. +- Use the [`iota::test_utils`](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/packages/iota-framework/sources/test/test_utils.move#L5) module for better test error messages via `assert_eq`, debug printing via `print`, and test-only destruction via `destroy`. +- Use `iota move test --coverage` to compute code coverage information for your tests, and `iota move coverage source --module ` to see uncovered lines highlighted in red. Push coverage all the way to 100% if feasible. ## Apps -- For optimal performance and data consistency, apps should submit writes and reads for the same full node. In the TS SDK, this means that apps should use the wallet's [`signTransactionBlock`](https://sdk.mystenlabs.com/dapp-kit) API, then submit the transaction via a call to [`execute_transactionBlock`](/sui-api-ref#sui_executetransactionblock) on the app's full node, _not_ use the wallet's `signAndExecuteTransactionBlock` API. This ensures read-after-write-consistency--reads from the app's full node will reflect writes from the transaction right away instead of waiting for a checkpoint. -- For lower latency, use [`executeTransactionBlock`](/sui-api-ref#sui_executetransactionblock) with `"showEffects": false` and `"showEvents": false` if your app needs to know that a transaction was confirmed, but does not immediately need to see the transaction effects or read the objects/events written by the transaction. +- For optimal performance and data consistency, apps should submit writes and reads for the same full node. In the TS SDK, this means that apps should use the wallet's [`signTransactionBlock`](https://sdk.mystenlabs.com/dapp-kit) API, then submit the transaction via a call to [`execute_transactionBlock`](/iota-api-ref#iota_executetransactionblock) on the app's full node, _not_ use the wallet's `signAndExecuteTransactionBlock` API. This ensures read-after-write-consistency--reads from the app's full node will reflect writes from the transaction right away instead of waiting for a checkpoint. +- For lower latency, use [`executeTransactionBlock`](/iota-api-ref#iota_executetransactionblock) with `"showEffects": false` and `"showEvents": false` if your app needs to know that a transaction was confirmed, but does not immediately need to see the transaction effects or read the objects/events written by the transaction. - Apps should implement a local cache for frequently read data rather than over-fetching from the full node. - Whenever possible, use programmable transaction blocks to compose existing on-chain functionality rather than publishing new smart contract code. Programmable transaction blocks allow large-scale batching and heterogeneous composition, driving already-low gas fees down even further. - Apps should leave gas budget, gas price, and coin selection to the wallet. This gives wallets more flexibility, and it's the wallet's responsibility to dry run a transaction to ensure it doesn't fail. ## Signing -- **Never** sign two concurrent transactions that are touching the same owned object. Either use independent owned objects, or wait for one transaction to conclude before sending the next one. Violating this rule might lead to client [equivocation](/references/sui-glossary.mdx#equivocation), which locks up the owned objects involved in the two transactions until the end of the current epoch. -- Any `sui client` command that crafts a transaction (e.g., `sui client publish`, `sui client call`) can accept the `--serialize-output` flag to output a base64 transaction to be signed. -- Sui supports several signature schemes for transaction signing, including native multisig. +- **Never** sign two concurrent transactions that are touching the same owned object. Either use independent owned objects, or wait for one transaction to conclude before sending the next one. Violating this rule might lead to client [equivocation](/references/iota-glossary.mdx#equivocation), which locks up the owned objects involved in the two transactions until the end of the current epoch. +- Any `iota client` command that crafts a transaction (e.g., `iota client publish`, `iota client call`) can accept the `--serialize-output` flag to output a base64 transaction to be signed. +- Iota supports several signature schemes for transaction signing, including native multisig. ## zkLogin diff --git a/docs/content/guides/developer/evm-to-move/creating-nft.mdx b/docs/content/guides/developer/evm-to-move/creating-nft.mdx index 18ea5606650..47d3bb0d4f0 100644 --- a/docs/content/guides/developer/evm-to-move/creating-nft.mdx +++ b/docs/content/guides/developer/evm-to-move/creating-nft.mdx @@ -44,7 +44,7 @@ IOTA Move is based on objects instead of a global storage like EVM. Objects in I ```move title="examples/Examplenft.move" module example::examplenft { use std::string; - use sui::event; + use iota::event; /// An example NFT that can be minted by anybody public struct ExampleNFT has key, store { diff --git a/docs/content/guides/developer/evm-to-move/creating-token.mdx b/docs/content/guides/developer/evm-to-move/creating-token.mdx index d3e628d0936..e636588c1d3 100644 --- a/docs/content/guides/developer/evm-to-move/creating-token.mdx +++ b/docs/content/guides/developer/evm-to-move/creating-token.mdx @@ -37,9 +37,9 @@ The initial creation of `Coin` takes place by minting these coins. This is usual ```move title="examples/Exampletoken.move" module examples::exampletoken { use std::option; - use sui::coin; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; + use iota::coin; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; /// One-Time-Witness of kind: `Coin` struct EXAMPLETOKEN has drop {} @@ -66,7 +66,7 @@ module examples::exampletoken { There's a lot to unpack here; let's look at it piece by piece. In IOTA Move, there is no 'compiler version' defined within the module itself, like in Solidity. -A `module` is defined (`exampletoken`) as part of the `examples` package (modules always reside in packages; a package can have one or more modules in one file or spread out over several files). Within the `module,` we first alias the functionality we wish to use from other modules with `use.` If you don't do this, you would have to explicitly call other modules through their full package path, which would be very verbose and cumbersome. We import an `option` module from the `std` package and some modules from the `sui` package. The `std` and `sui` names are actually mappings as well to other modules defined in the `Move.toml` file of the package as described in the [documentation](../../../guides/developer/first-app/write-package.mdx). +A `module` is defined (`exampletoken`) as part of the `examples` package (modules always reside in packages; a package can have one or more modules in one file or spread out over several files). Within the `module,` we first alias the functionality we wish to use from other modules with `use.` If you don't do this, you would have to explicitly call other modules through their full package path, which would be very verbose and cumbersome. We import an `option` module from the `std` package and some modules from the `iota` package. The `std` and `iota` names are actually mappings as well to other modules defined in the `Move.toml` file of the package as described in the [documentation](../../../guides/developer/first-app/write-package.mdx). After the aliases, we see an empty struct defined: @@ -74,7 +74,7 @@ After the aliases, we see an empty struct defined: struct EXAMPLETOKEN has drop {} ``` -This is the definition of the so-called [One-Time-Witness](../../../concepts/sui-move-concepts/one-time-witness.mdx). Together with the `init` function definition, this ensures that this `Coin` will only be created once and never more on this chain. +This is the definition of the so-called [One-Time-Witness](../../../concepts/iota-move-concepts/one-time-witness.mdx). Together with the `init` function definition, this ensures that this `Coin` will only be created once and never more on this chain. The `init` function is called automatically when a package is published for every module. The One-Time-Witness and a `TxContext` object containing more information about the function call itself, like the address deploying the package (sender), are passed automatically. @@ -95,7 +95,7 @@ The standard implementation of using `Coin`, `TreasuryCap`, and `Metadata` is pr We recommend new tokens to abstract the management of the token with the `CoinManager` to provide a more transparent and trustworthy token while retaining administrative power and gaining usable functionality. You can do this by simply creating a `CoinManager` within the `init` function of your module, creating your token by passing in the non-transferred/frozen `TreasuryCap` and `Metadata` objects: ```move title="examples/Exampletoken.move" -use sui::coin_manager; +use iota::coin_manager; fun init(witness: EXAMPLETOKEN, ctx: &mut TxContext) { let (treasurycap, metadata) = coin::create_currency( @@ -138,7 +138,7 @@ To sum up the most important differences between the two approaches: | Tokens as a contract | Tokens as (owned) objects | | All state within the same contract | State spread out over various objects (`TreasuryCap`, `Metadata`, and various `Coin` objects) | | Native token and ERC-20 are implemented differently | Both the chain native asset and custom tokens are `Coin` objects and work the same. | -| Token logic is usually abstracted in externally imported libraries | Token logic is part of the `sui-framework` `Coin` module | +| Token logic is usually abstracted in externally imported libraries | Token logic is part of the `iota-framework` `Coin` module | | Admin functionality like minting is implemented in the contract itself and is fully customizable. | Admin functionality is standardized using a `TreasuryCap`, which can be used, transferred, or burned predictably. | | Token balances can only be found if you have the smart contract address of the tokens you want to know the balance for | All tokens are known and available in your wallet, given they are transferred to you as objects. | | Modifications can all take place within the smart contract itself | Modification to logic, with things like restricting if a `Coin` can be transferred, needs a different approach where the `Coin` is wrapped inside another object that limits the standard functionality of `Coin` based on conditions defined in that wrapper object. | diff --git a/docs/content/guides/developer/evm-to-move/why-move.mdx b/docs/content/guides/developer/evm-to-move/why-move.mdx index 391de3fa5dc..9773995ba31 100644 --- a/docs/content/guides/developer/evm-to-move/why-move.mdx +++ b/docs/content/guides/developer/evm-to-move/why-move.mdx @@ -12,7 +12,7 @@ While EVM/Solidity is the most significant right now when it comes to Smart Cont IOTA Move is here to learn from these downsides and come up with a better alternative addressing these issues: * **Performance, scaling, and cost:** Given that IOTA Move is based on the object model (similar to UTXO's) and not a globally shared state, transactions can be executed in parallel, resulting in a much higher (potential) throughput over a traditional blockchain with shared state. This results in a lot less congestion and, thus, lower fees on an actively used network. -* **Security:** Move was designed with security in mind. The language itself is based on Rust and is very strict regarding its typing system. You really have to try to make a mistake that the compiler won't catch before deploying. There's no such thing as re-entry, and given the object-based approach of Move, Assets residing in your account can't be touched at all by the smart contract itself without access to your account keys. +* **Security:** Move was designed with security in mind. The language itself is based on Rust and is very strict regarding its typing system. You really have to try to make a microsake that the compiler won't catch before deploying. There's no such thing as re-entry, and given the object-based approach of Move, Assets residing in your account can't be touched at all by the smart contract itself without access to your account keys. * **Tokens:** In IOTA Move, there is no difference between the IOTA token (`Coin`) and a custom token (`Coin`), not in terms of use or implementation. These objects reside in your own account and can thus easily be found without needing to know a Smart Contract address (this goes for any other type of owned object as well). There's no strange `approve()` functionality, and you keep control over your own owned assets. * **Developer Experience:** While Move is more challenging to get started with over Solidity, the safety of the language and excellent developer experience when it comes to finding and resolving issues in your code make up for that. With Move, it's not so scary anymore to write complex logic from scratch, given most mistakes (apart from obvious implementation logic, doing things 'as intended') are caught directly by the compiler. This allows for more innovation, fewer value-destroying bugs, and a more excellent developer experience, fueling the next generation of smart contracts. diff --git a/docs/content/guides/developer/first-app.mdx b/docs/content/guides/developer/first-app.mdx index 2bcb436fa15..75c65436f4a 100644 --- a/docs/content/guides/developer/first-app.mdx +++ b/docs/content/guides/developer/first-app.mdx @@ -1,27 +1,27 @@ --- -title: Your First Sui dApp -description: Build your first dApp and publish it on chain. These guides demonstrate the basics you need to know to start your development journey on Sui. +title: Your First Iota dApp +description: Build your first dApp and publish it on chain. These guides demonstrate the basics you need to know to start your development journey on Iota. --- -Before you can create your first dApp, you must have [Sui installed](./getting-started/sui-install.mdx). +Before you can create your first dApp, you must have [Iota installed](./getting-started/iota-install.mdx). -You use Move to write packages that live on chain, meaning they exist on the Sui network you publish them to. The instructions in this section walk you through writing a basic package, debugging and testing your code, and publishing. You need to follow these instructions in order to complete the exercise. +You use Move to write packages that live on chain, meaning they exist on the Iota network you publish them to. The instructions in this section walk you through writing a basic package, debugging and testing your code, and publishing. You need to follow these instructions in order to complete the exercise. -You use the `move` Sui CLI command for some instructions. The Sui CLI installs with the binaries, so you have it on your system if you follow the install instructions. To verify you have it installed, run the following command in a terminal or console. +You use the `move` Iota CLI command for some instructions. The Iota CLI installs with the binaries, so you have it on your system if you follow the install instructions. To verify you have it installed, run the following command in a terminal or console. ```shell -$ sui --version +$ iota --version ``` -If the console does not respond with a version number similar to the following, see the instructions to install Sui. +If the console does not respond with a version number similar to the following, see the instructions to install Iota. ```shell -$ sui 1.xx.x-abc123xyz +$ iota 1.xx.x-abc123xyz ``` ## Connecting to a network -After installing Sui, you can connect to a network. Sui has three public networks (Devnet, Testnet, Mainnet), and you can also run and connect to a local Sui network. For each network, you need an on-chain address specific to that network. The address is an object with a unique ID in the form `0x8bd4613c004aac53d06bb7ceb7f46832c9ae69bdc105dfc5fcac225d2061fcac`. In addition to that address, you need SUI to pay for the gas fees associated with your on-chain activity, like publishing packages and making Move calls to those packages. For all networks besides Mainnet, you can get free SUI coins for your account to facilitate package development. For the purposes of this example, connect to the Testnet network. +After installing Iota, you can connect to a network. Iota has three public networks (Devnet, Testnet, Mainnet), and you can also run and connect to a local Iota network. For each network, you need an on-chain address specific to that network. The address is an object with a unique ID in the form `0x8bd4613c004aac53d06bb7ceb7f46832c9ae69bdc105dfc5fcac225d2061fcac`. In addition to that address, you need IOTA to pay for the gas fees associated with your on-chain activity, like publishing packages and making Move calls to those packages. For all networks besides Mainnet, you can get free IOTA coins for your account to facilitate package development. For the purposes of this example, connect to the Testnet network. ### Connect to Testnet @@ -29,28 +29,28 @@ If you already have a network config set up, switch your active environment to T 1. In your terminal or console, use the following command to begin the configuration: ```shell - $ sui client + $ iota client ``` -1. At the prompt, type y and press Enter to connect to a Sui Full node server. -1. At the following prompt, type the address of the Testnet server (`https://fullnode.testnet.sui.io:443`) and press Enter. +1. At the prompt, type y and press Enter to connect to a Iota Full node server. +1. At the following prompt, type the address of the Testnet server (`https://fullnode.testnet.iota.io:443`) and press Enter. 1. At the following prompt, type `testnet` to give the network an alias and press Enter. You can use the alias in subsequent commands instead of typing the complete URL. 1. At the following prompt, type `0` and press Enter. The selection creates an address in the `ed25519` signing scheme. 1. The response provides an alias for your address, the actual address ID, and a secret recovery phrase. Be sure to save this information for later reference. Because this is on the Testnet network, the security of this information is not as important as if it were on Mainnet. -1. In your terminal or console, use the following command to get SUI for your account. +1. In your terminal or console, use the following command to get IOTA for your account. ```shell - $ sui client faucet + $ iota client faucet ``` -1. You can confirm that you received SUI by using the following command. There may be a delay in receiving coins depending on the activity of the network. +1. You can confirm that you received IOTA by using the following command. There may be a delay in receiving coins depending on the activity of the network. ```shell - $ sui client gas + $ iota client gas ``` -You are now connected to the Sui Testnet network and should have an account with available SUI. +You are now connected to the Iota Testnet network and should have an account with available IOTA. ## Related links - [Write a Move Package](./first-app/write-package.mdx): Continue this example by creating the necessary Move code for your package. -- [Connect to a Sui Network](./getting-started/connect.mdx): Connect to an available Sui network. -- [Connect to a Local Network](./getting-started/local-network.mdx): Start and connect to a local Sui network. -- [Get Sui Address](./getting-started/get-address.mdx): Get an address for the current Sui network. -- [Get SUI Tokens](./getting-started/get-coins.mdx): Get SUI for the active address on Devnet, Testnet, or a local network. \ No newline at end of file +- [Connect to a Iota Network](./getting-started/connect.mdx): Connect to an available Iota network. +- [Connect to a Local Network](./getting-started/local-network.mdx): Start and connect to a local Iota network. +- [Get Iota Address](./getting-started/get-address.mdx): Get an address for the current Iota network. +- [Get IOTA Tokens](./getting-started/get-coins.mdx): Get IOTA for the active address on Devnet, Testnet, or a local network. \ No newline at end of file diff --git a/docs/content/guides/developer/first-app/build-test.mdx b/docs/content/guides/developer/first-app/build-test.mdx index b72f946d24c..a429a78f1d0 100644 --- a/docs/content/guides/developer/first-app/build-test.mdx +++ b/docs/content/guides/developer/first-app/build-test.mdx @@ -9,14 +9,14 @@ If you followed [Write a Move Package](./write-package.mdx), you have a basic mo Make sure your terminal or console is in the directory that contains your package (`my_first_package` if you're following along). Use the following command to build your package: ```shell -$ sui move build +$ iota move build ``` A successful build returns a response similar to the following: ```shell -UPDATING GIT DEPENDENCY https://github.com/MystenLabs/sui.git -INCLUDING DEPENDENCY Sui +UPDATING GIT DEPENDENCY https://github.com/iotaledger/iota.git +INCLUDING DEPENDENCY Iota INCLUDING DEPENDENCY MoveStdlib BUILDING my_first_package ``` @@ -27,18 +27,18 @@ Now that you have designed your asset and its accessor functions, it's time to t ## Testing a package {#testing-a-package} -Sui includes support for the Move testing framework. Using the framework, you can write unit tests that analyze Move code much like test frameworks for other languages, such as the built-in Rust testing framework or the JUnit framework for Java. +Iota includes support for the Move testing framework. Using the framework, you can write unit tests that analyze Move code much like test frameworks for other languages, such as the built-in Rust testing framework or the JUnit framework for Java. -An individual Move unit test is encapsulated in a public function that has no parameters, no return values, and has the `#[test]` annotation. The testing framework executes such functions when you call the `sui move test` command from the package root (`my_move_package` directory as per the current running example): +An individual Move unit test is encapsulated in a public function that has no parameters, no return values, and has the `#[test]` annotation. The testing framework executes such functions when you call the `iota move test` command from the package root (`my_move_package` directory as per the current running example): ```shell -$ sui move test +$ iota move test ``` If you execute this command for the package created in [Write a Package](./write-package.mdx), you see the following output. Unsurprisingly, the test result has an `OK` status because there are no tests written yet to fail. ```shell -BUILDING Sui +BUILDING Iota BUILDING MoveStdlib BUILDING my_first_package Running Move unit tests @@ -73,7 +73,7 @@ The function passes the dummy context, `ctx`, to the `object::new` function as a Now that you have a test function, run the test command again: ```shell -$ sui move test +$ iota move test ``` After running the `test` command, however, you get a compilation error instead of a test result: @@ -107,7 +107,7 @@ One of the solutions (as suggested in the error message), is to add the `drop` a To get the test to work, add the following line to the beginning of the testing function to import the `Transfer` module: ```move -use sui::transfer; +use iota::transfer; ``` With the `Transfer` module imported, add the following lines to the end of the test function (after the `!assert` call) to transfer ownership of the `sword` to a freshly created dummy address: @@ -122,7 +122,7 @@ Run the test command again. Now the output shows a single successful test has ru ```shell BUILDING MoveStdlib -BUILDING Sui +BUILDING Iota BUILDING my_first_package Running Move unit tests [ PASS ] 0x0::my_module::test_sword_create @@ -131,14 +131,14 @@ Test result: OK. Total tests: 1; passed: 1; failed: 0 :::tip -Use a filter string to run only a matching subset of the unit tests. With a filter string provided, the `sui move test` checks the fully qualified (`
    ::::`) name for a match. +Use a filter string to run only a matching subset of the unit tests. With a filter string provided, the `iota move test` checks the fully qualified (`
    ::::`) name for a match. ::: Example: ```shell -$ sui move test sword +$ iota move test sword ``` The previous command runs all tests whose name contains `sword`. @@ -146,20 +146,20 @@ The previous command runs all tests whose name contains `sword`. You can discover more testing options through: ```shell -$ sui move test -h +$ iota move test -h ``` -## Sui-specific testing +## Iota-specific testing -The previous testing example uses Move but isn't specific to Sui beyond using some Sui packages, such as `sui::tx_context` and `sui::transfer`. While this style of testing is already useful for writing Move code for Sui, you might also want to test additional Sui-specific features. In particular, a Move call in Sui is encapsulated in a Sui transaction, and you might want to test interactions between different transactions within a single test (for example, one transaction creating an object and the other one transferring it). +The previous testing example uses Move but isn't specific to Iota beyond using some Iota packages, such as `iota::tx_context` and `iota::transfer`. While this style of testing is already useful for writing Move code for Iota, you might also want to test additional Iota-specific features. In particular, a Move call in Iota is encapsulated in a Iota transaction, and you might want to test interactions between different transactions within a single test (for example, one transaction creating an object and the other one transferring it). -Sui-specific testing is supported through the `test_scenario` module that provides Sui-related testing functionality otherwise unavailable in pure Move and its testing framework. +Iota-specific testing is supported through the `test_scenario` module that provides Iota-related testing functionality otherwise unavailable in pure Move and its testing framework. -The `test_scenario` module provides a scenario that emulates a series of Sui transactions, each with a potentially different user executing them. A test using this module typically starts the first transaction using the `test_scenario::begin` function. This function takes an address of the user executing the transaction as its argument and returns an instance of the `Scenario` struct representing a scenario. +The `test_scenario` module provides a scenario that emulates a series of Iota transactions, each with a potentially different user executing them. A test using this module typically starts the first transaction using the `test_scenario::begin` function. This function takes an address of the user executing the transaction as its argument and returns an instance of the `Scenario` struct representing a scenario. -An instance of the `Scenario` struct contains a per-address object pool emulating Sui object storage, with helper functions provided to manipulate objects in the pool. After the first transaction finishes, subsequent test transactions start with the `test_scenario::next_tx` function. This function takes an instance of the `Scenario` struct representing the current scenario and an address of a user as arguments. +An instance of the `Scenario` struct contains a per-address object pool emulating Iota object storage, with helper functions provided to manipulate objects in the pool. After the first transaction finishes, subsequent test transactions start with the `test_scenario::next_tx` function. This function takes an instance of the `Scenario` struct representing the current scenario and an address of a user as arguments. -Update your `my_module.move` file to include entry functions callable from Sui that implement `sword` creation and transfer. With these in place, you can then add a multi-transaction test that uses the `test_scenario` module to test these new capabilities. Put these functions after the accessors (Part 5 in comments). +Update your `my_module.move` file to include entry functions callable from Iota that implement `sword` creation and transfer. With these in place, you can then add a multi-transaction test that uses the `test_scenario` module to test these new capabilities. Put these functions after the accessors (Part 5 in comments). ```move public fun sword_create(magic: u64, strength: u64, recipient: address, ctx: &mut TxContext) { @@ -183,14 +183,14 @@ public fun sword_transfer(sword: Sword, recipient: address, _ctx: &mut TxContext } ``` -The code of the new functions uses struct creation and Sui-internal modules (`TxContext` and `Transfer`) in a way similar to what you have seen in the previous sections. The important part is for the entry functions to have correct signatures. +The code of the new functions uses struct creation and Iota-internal modules (`TxContext` and `Transfer`) in a way similar to what you have seen in the previous sections. The important part is for the entry functions to have correct signatures. With the new entry functions included, add another test function to make sure they behave as expected. ```move #[test] fun test_sword_transactions() { - use sui::test_scenario; + use iota::test_scenario; // create test addresses representing users let admin = @0xBABE; @@ -236,7 +236,7 @@ With the new entry functions included, add another test function to make sure th There are some details of the new testing function to pay attention to. The first thing the code does is create some addresses that represent users participating in the testing scenario. The assumption is that there is one game administrator user and two regular users representing players. The test then creates a scenario by starting the first transaction on behalf of the administrator address. The administrator executes the second transaction. The transaction creates a `sword` where the `initial_owner` is the receiver. -The initial owner then executes the third transaction (passed as an argument to the `test_scenario::next_tx` function), who then transfers the `sword` they now own to the final owner. In pure Move there is no notion of Sui storage; consequently, there is no easy way for the emulated Sui transaction to retrieve it from storage. This is where the `test_scenario` module helps - its `take_from_sender` function allows an address-owned object of a given type (`Sword`) executing the current transaction to be available for Move code manipulation. For now, assume that there is only one such object. In this case, the test transfers the object it retrieves from storage to another address. +The initial owner then executes the third transaction (passed as an argument to the `test_scenario::next_tx` function), who then transfers the `sword` they now own to the final owner. In pure Move there is no notion of Iota storage; consequently, there is no easy way for the emulated Iota transaction to retrieve it from storage. This is where the `test_scenario` module helps - its `take_from_sender` function allows an address-owned object of a given type (`Sword`) executing the current transaction to be available for Move code manipulation. For now, assume that there is only one such object. In this case, the test transfers the object it retrieves from storage to another address. :::tip @@ -246,12 +246,12 @@ Transaction effects, such as object creation and transfer become visible only af The final owner executes the fourth and final transaction that retrieves the `sword` object from storage and checks if it has the expected properties. Remember, as described in [Testing a package](#testing-a-package), in the pure Move testing scenario, after an object is available in Move code (after creation or retrieval from emulated storage), it cannot simply disappear. -In the pure Move testing function, the function transfers the `sword` object to the fake address to handle the disappearing problem. The `test_scenario` package provides a more elegant solution, however, which is closer to what happens when Move code actually executes in the context of Sui - the package simply returns the `sword` to the object pool using the `test_scenario::return_to_sender` function. For scenarios where returning to the sender is not desirable or if you would like to simply destroy the object, the `test_utils` module also provides the generic `destroy` function, that can be used on any type `T` regardless of its ability. It is advisable to check out other useful functions in the [`test_scenario`](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-framework/sources/test/test_scenario.move) and [`test_utils`](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-framework/sources/test/test_utils.move) modules as well. +In the pure Move testing function, the function transfers the `sword` object to the fake address to handle the disappearing problem. The `test_scenario` package provides a more elegant solution, however, which is closer to what happens when Move code actually executes in the context of Iota - the package simply returns the `sword` to the object pool using the `test_scenario::return_to_sender` function. For scenarios where returning to the sender is not desirable or if you would like to simply destroy the object, the `test_utils` module also provides the generic `destroy` function, that can be used on any type `T` regardless of its ability. It is advisable to check out other useful functions in the [`test_scenario`](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/packages/iota-framework/sources/test/test_scenario.move) and [`test_utils`](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/packages/iota-framework/sources/test/test_utils.move) modules as well. Run the test command again to see two successful tests for our module: ```shell -BUILDING Sui +BUILDING Iota BUILDING MoveStdlib BUILDING my_first_package Running Move unit tests @@ -277,7 +277,7 @@ For example, the following `init` functions are all valid: - `fun init(otw: EXAMPLE, ctx: &TxContext)` - `fun init(otw: EXAMPLE, ctx: &mut TxContext)` -While the `sui move` command does not support publishing explicitly, you can still test module initializers using the testing framework by dedicating the first transaction to executing the initializer function. +While the `iota move` command does not support publishing explicitly, you can still test module initializers using the testing framework by dedicating the first transaction to executing the initializer function. The `init` function for the module in the running example creates a `Forge` object. @@ -316,7 +316,7 @@ The tests you have so far call the `init` function, but the initializer function Now, create a function to test the module initialization: ```move -#[test_only] use sui::test_scenario as ts; +#[test_only] use iota::test_scenario as ts; #[test_only] const ADMIN: address = @0xAD; @@ -351,9 +351,9 @@ public fun test_module_init() { As the new test function shows, the first transaction (explicitly) calls the initializer. The next transaction checks if the `Forge` object has been created and properly initialized. -You can refer to the source code for the package (with all the tests and functions properly adjusted) in the [first_package](https://github.com/MystenLabs/sui/tree/main/examples/move/first_package/sources/example.move) module in the `sui/examples` directory. +You can refer to the source code for the package (with all the tests and functions properly adjusted) in the [first_package](https://github.com/iotaledger/iota/tree/main/examples/move/first_package/sources/example.move) module in the `iota/examples` directory. ## Related links -- [Publish a Package](./publish.mdx): Continue the example by publishing your package to the Sui network. -- [Package Upgrades](../../../concepts/sui-move-concepts/packages.mdx): Upgrading packages published on the Sui network. +- [Publish a Package](./publish.mdx): Continue the example by publishing your package to the Iota network. +- [Package Upgrades](../../../concepts/iota-move-concepts/packages.mdx): Upgrading packages published on the Iota network. diff --git a/docs/content/guides/developer/first-app/client-tssdk.mdx b/docs/content/guides/developer/first-app/client-tssdk.mdx index 8d88a7d6fd0..cb20729bdd6 100644 --- a/docs/content/guides/developer/first-app/client-tssdk.mdx +++ b/docs/content/guides/developer/first-app/client-tssdk.mdx @@ -1,32 +1,32 @@ --- -title: Client App with Sui TypeScript SDK +title: Client App with Iota TypeScript SDK --- import InfoPnpmRequired from "../../../_snippets/info-pnpm-required.mdx"; -This exercise diverges from the example built in the previous topics in this section. Rather than adding a frontend to the running example, the instruction walks you through setting up dApp Kit in a React App, allowing you to connect to wallets, and query data from Sui RPC nodes to display in your app. You can use it to create your own frontend for the example used previously, but if you want to get a fully functional app up and running quickly, run the following command in a terminal or console to scaffold a new app with all steps in this exercise already implemented: +This exercise diverges from the example built in the previous topics in this section. Rather than adding a frontend to the running example, the instruction walks you through setting up dApp Kit in a React App, allowing you to connect to wallets, and query data from Iota RPC nodes to display in your app. You can use it to create your own frontend for the example used previously, but if you want to get a fully functional app up and running quickly, run the following command in a terminal or console to scaffold a new app with all steps in this exercise already implemented: ```bash -pnpm create @mysten/dapp --template react-client-dapp +pnpm create @iota/dapp --template react-client-dapp ``` or ```bash -yarn create @mysten/dapp --template react-client-dapp +yarn create @iota/dapp --template react-client-dapp ``` -## What is the Sui TypeScript SDK? +## What is the Iota TypeScript SDK? -The Sui TypeScript SDK (@mysten/sui.js) provides all the low-level functionality needed to interact with Sui ecosystem from TypeScript. You can use it in any TypeScript or JavaScript project, including web apps, Node.js apps, or mobile apps written with tools like React Native that support TypeScript. +The Iota TypeScript SDK (@iota/iota.js) provides all the low-level functionality needed to interact with Iota ecosystem from TypeScript. You can use it in any TypeScript or JavaScript project, including web apps, Node.js apps, or mobile apps written with tools like React Native that support TypeScript. -For more information on the Sui TypeScript SDK, see the [Sui TypeScript SDK documentation](https://sdk.mystenlabs.com/typescript). +For more information on the Iota TypeScript SDK, see the [Iota TypeScript SDK documentation](https://sdk.mystenlabs.com/typescript). ## What is dApp Kit? -dApp Kit (@mysten/dapp-kit) is a collection of React hooks, components, and utilities that make building dApps on Sui straightforward. For more information on dApp Kit, see the [dApp Kit documentation](https://sdk.mystenlabs.com/dapp-kit). +dApp Kit (@iota/dapp-kit) is a collection of React hooks, components, and utilities that make building dApps on Iota straightforward. For more information on dApp Kit, see the [dApp Kit documentation](https://sdk.mystenlabs.com/dapp-kit). ## Installing dependencies @@ -41,7 +41,7 @@ npm init vite Now that you have a React app, you can install the necessary dependencies to use dApp Kit: ```bash npm2yarn -npm install @mysten/sui.js @mysten/dapp-kit @tanstack/react-query +npm install @iota/iota.js @iota/dapp-kit @tanstack/react-query ``` ## Setting up Provider components @@ -66,11 +66,11 @@ ReactDOM.createRoot(document.getElementById('root')!).render( ); ``` -Next, set up the `SuiClientProvider`. This `Provider` delivers a `SuiClient` instance from `@mysten/sui.js` to all the hooks in dApp Kit. This provider manages which network dApp Kit connects to, and can accept configuration for multiple networks. This exercise connects to `devnet`. +Next, set up the `IotaClientProvider`. This `Provider` delivers a `IotaClient` instance from `@iota/iota.js` to all the hooks in dApp Kit. This provider manages which network dApp Kit connects to, and can accept configuration for multiple networks. This exercise connects to `devnet`. ```ts -import { SuiClientProvider } from '@mysten/dapp-kit'; -import { getFullnodeUrl } from '@mysten/sui.js/client'; +import { IotaClientProvider } from '@iota/dapp-kit'; +import { getFullnodeUrl } from '@iota/iota.js/client'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; const queryClient = new QueryClient(); @@ -82,21 +82,21 @@ const networks = { ReactDOM.createRoot(document.getElementById('root')!).render( - + - + , ); ``` -Finally, set up the `WalletProvider` from `@mysten/dapp-kit`, and import styles for the `dapp-kit` components. +Finally, set up the `WalletProvider` from `@iota/dapp-kit`, and import styles for the `dapp-kit` components. ```ts -import '@mysten/dapp-kit/dist/index.css'; +import '@iota/dapp-kit/dist/index.css'; -import { SuiClientProvider, WalletProvider } from '@mysten/dapp-kit'; -import { getFullnodeUrl } from '@mysten/sui.js/client'; +import { IotaClientProvider, WalletProvider } from '@iota/dapp-kit'; +import { getFullnodeUrl } from '@iota/iota.js/client'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; const queryClient = new QueryClient(); @@ -108,11 +108,11 @@ const networks = { ReactDOM.createRoot(document.getElementById('root')!).render( - + - + , ); @@ -123,7 +123,7 @@ ReactDOM.createRoot(document.getElementById('root')!).render( With all `Providers` set up, you can use dApp Kit hooks and components. To allow users to connect their wallets to your dApp, add a `ConnectButton`. ```ts -import { ConnectButton } from '@mysten/dapp-kit'; +import { ConnectButton } from '@iota/dapp-kit'; function App() { return ( @@ -143,7 +143,7 @@ The `ConnectButton` component displays a button that opens a modal on click, ena Now that you have a way for users to connect their wallets, you can start using the `useCurrentAccount` hook to get details about the connected wallet account. ```ts -import { ConnectButton, useCurrentAccount } from '@mysten/dapp-kit'; +import { ConnectButton, useCurrentAccount } from '@iota/dapp-kit'; function App() { return ( @@ -168,12 +168,12 @@ function ConnectedAccount() { } ``` -## Querying data from Sui RPC nodes +## Querying data from Iota RPC nodes Now that you have the account to connect to, you can query for objects the connected account owns: ```ts -import { useCurrentAccount, useSuiClientQuery } from '@mysten/dapp-kit'; +import { useCurrentAccount, useIotaClientQuery } from '@iota/dapp-kit'; function ConnectedAccount() { const account = useCurrentAccount(); @@ -191,7 +191,7 @@ function ConnectedAccount() { } function OwnedObjects({ address }: { address: string }) { - const { data } = useSuiClientQuery('getOwnedObjects', { + const { data } = useIotaClientQuery('getOwnedObjects', { owner: address, }); if (!data) { @@ -219,5 +219,5 @@ You now have a dApp connected to wallets and can query data from RPC nodes. The next step from here is to start interacting with Move modules, constructing transaction blocks, and making Move calls. This exercise continues in the Counter end-to-end example. - [End-to-End Example](../app-examples/e2e-counter.mdx): Continue this exercise by creating an app. -- [Sui 101](../sui-101.mdx): Learn the basics of the Sui network and how to interact with on-chain objects using Move. -- [Sui Move CLI](/references/cli/move.mdx): The `move` commands in the Sui CLI provide console or terminal interaction with the Move VM. +- [Iota 101](../iota-101.mdx): Learn the basics of the Iota network and how to interact with on-chain objects using Move. +- [Iota Move CLI](/references/cli/move.mdx): The `move` commands in the Iota CLI provide console or terminal interaction with the Move VM. diff --git a/docs/content/guides/developer/first-app/debug.mdx b/docs/content/guides/developer/first-app/debug.mdx index e1b96874c9b..2e01758b4d4 100644 --- a/docs/content/guides/developer/first-app/debug.mdx +++ b/docs/content/guides/developer/first-app/debug.mdx @@ -55,13 +55,13 @@ public fun new_sword( To see the results, run the module's tests. ```shell -$ sui move test +$ iota move test ``` The response prints out the expected results as the test calls the `new_sword` function. ```shell -INCLUDING DEPENDENCY Sui +INCLUDING DEPENDENCY Iota INCLUDING DEPENDENCY MoveStdlib BUILDING my_first_package Running Move unit tests @@ -109,4 +109,4 @@ Test result: OK. Total tests: 2; passed: 2; failed: 0 ## Related links -- [Publish a Package](./publish.mdx): Publish the example to the Sui network. \ No newline at end of file +- [Publish a Package](./publish.mdx): Publish the example to the Iota network. \ No newline at end of file diff --git a/docs/content/guides/developer/first-app/publish.mdx b/docs/content/guides/developer/first-app/publish.mdx index 83e77c1e980..04b0372180b 100644 --- a/docs/content/guides/developer/first-app/publish.mdx +++ b/docs/content/guides/developer/first-app/publish.mdx @@ -4,12 +4,12 @@ title: Publish a Package import AddressPrefix from "../../../_snippets/address-prefix.mdx"; -Before you can call functions in a Move package (beyond an emulated Sui execution scenario), that package must be available on the Sui network. When you publish a package, you are actually creating an immutable Sui object on the network that anyone can access. +Before you can call functions in a Move package (beyond an emulated Iota execution scenario), that package must be available on the Iota network. When you publish a package, you are actually creating an immutable Iota object on the network that anyone can access. -To publish your package to the Sui network, use the `publish` CLI command in the root of your package. Use the `--gas-budget` flag to set a value for the maximum amount of gas the transaction can cost. If the cost of the transaction is more than the budget you set, the transaction fails and your package doesn't publish. +To publish your package to the Iota network, use the `publish` CLI command in the root of your package. Use the `--gas-budget` flag to set a value for the maximum amount of gas the transaction can cost. If the cost of the transaction is more than the budget you set, the transaction fails and your package doesn't publish. ```shell -$ sui client publish --gas-budget 5000000 +$ iota client publish --gas-budget 5000000 ``` If the publish transaction is successful, your terminal or console responds with the details of the publish transaction separated into sections, including transaction data, transaction effects, transaction block events, object changes, and balance changes. @@ -36,10 +36,10 @@ In the **Object Changes** table, you can find the information about the package ╰─────────────────────────────────────────────────────────────────────╯ ``` -Your currently active address now has three objects (or more, if you had objects prior to this example). Assuming you are using a new address, running the `sui objects` command reveals what those objects are. +Your currently active address now has three objects (or more, if you had objects prior to this example). Assuming you are using a new address, running the `iota objects` command reveals what those objects are. ``` -$ sui client objects +$ iota client objects ╭───────────────────────────────────────────────────────────────────────────────────────╮ │ ╭────────────┬──────────────────────────────────────────────────────────────────────╮ │ @@ -72,7 +72,7 @@ The `objectId` field is the unique identifier of each object. ```mermaid flowchart TB - subgraph Sui Blockchain + subgraph Iota Blockchain direction TB address --> Forge address --> UpgradeCap @@ -82,26 +82,26 @@ flowchart TB ### Interact with the package -Now that the package is on chain, you can call its functions to interact with the package. You can use the `sui move call` command to make individual calls to package functions, or you can construct more advanced blocks of transactions using the `sui client ptb` command. The `ptb` part of the command stands for [programmable transaction blocks](../../../concepts/transactions/prog-txn-blocks.mdx). In basic terms, PTBs allow you to group commands together in a single transaction for more efficient and cost-effective network activity. +Now that the package is on chain, you can call its functions to interact with the package. You can use the `iota move call` command to make individual calls to package functions, or you can construct more advanced blocks of transactions using the `iota client ptb` command. The `ptb` part of the command stands for [programmable transaction blocks](../../../concepts/transactions/prog-txn-blocks.mdx). In basic terms, PTBs allow you to group commands together in a single transaction for more efficient and cost-effective network activity. ```mermaid flowchart TB my_module["my_module::new_sword(&Forge, strength, magic)"] - Sui_client["Sui client"] + Iota_client["Iota client"] - subgraph Sui Blockchain + subgraph Iota Blockchain my_module my_module --Sword--> address end - Sui_client --"PTB"--> my_module + Iota_client --"PTB"--> my_module ``` For example, you can create a new `Sword` object defined in the package by calling the `new_sword` function in the `my_module` package, and then transfer the `Sword` object to any address: ```shell -$ sui client ptb \ +$ iota client ptb \ --assign forge @ \ --assign to_address @ \ --move-call ::my_module::new_sword forge 3 3 \ @@ -118,7 +118,7 @@ $ sui client ptb \ Make sure to replace ``, ``, and `` with the actual `objectId` of the `Forge` object, the address of the recipient (your address in this case), and the `packageID` of the package, respectively. -After the transaction executes, you can check the status of the `Sword` object by using the `sui client objects` command again. Provided you used your address as the ``, you should now see a total of four objects: +After the transaction executes, you can check the status of the `Sword` object by using the `iota client objects` command again. Provided you used your address as the ``, you should now see a total of four objects: ``` ╭───────────────────────────────────────────────────────────────────────────────────────╮ @@ -149,13 +149,13 @@ After the transaction executes, you can check the status of the `Sword` object b ╰───────────────────────────────────────────────────────────────────────────────────────╯ ``` -Congratulations! You have successfully published a package to the Sui network and modified the blockchain state by using a programmable transaction block. +Congratulations! You have successfully published a package to the Iota network and modified the blockchain state by using a programmable transaction block. ## Related links - [Debugging](./debug.mdx): Print values to aid in logic debugging. -- [Package Upgrades](../../../concepts/sui-move-concepts/packages.mdx): Upgrading packages published on the Sui network. +- [Package Upgrades](../../../concepts/iota-move-concepts/packages.mdx): Upgrading packages published on the Iota network. - [Publish a Move Package](../../../references/cli/client.mdx#publish-a-move-package): More details about using the CLI to publish a package. - [Programmable Transaction Blocks](../../../concepts/transactions/prog-txn-blocks.mdx): PTBs are collections of transactions that are executed together. -- [Sui Client PTB CLI](../../../references/cli/ptb.mdx): The `client ptb` command allows you to specify the transactions for execution in a programmable transaction block directly from your CLI or through bash scripts. +- [Iota Client PTB CLI](../../../references/cli/ptb.mdx): The `client ptb` command allows you to specify the transactions for execution in a programmable transaction block directly from your CLI or through bash scripts. - [App Examples](../app-examples.mdx): End-to-end examples that include smart contract logic and frontend code. diff --git a/docs/content/guides/developer/first-app/write-package.mdx b/docs/content/guides/developer/first-app/write-package.mdx index bdbb8704d82..516690a7d65 100644 --- a/docs/content/guides/developer/first-app/write-package.mdx +++ b/docs/content/guides/developer/first-app/write-package.mdx @@ -3,10 +3,10 @@ title: Write a Move Package description: The first step in getting a package on chain is to write the Move code that defines the logic of your package. The structure of a Move package is similar to those in Rust. --- -To begin, open a terminal or console at the location you plan to store your package. Use the `sui move new` command to create an empty Move package with the name `my_first_package`: +To begin, open a terminal or console at the location you plan to store your package. Use the `iota move new` command to create an empty Move package with the name `my_first_package`: ```shell -$ sui move new my_first_package +$ iota move new my_first_package ``` Running the previous command creates a directory with the name you provide (`my_first_package` in this case). The command populates the new directory with a skeleton Move project that consists of a `sources` directory and a `Move.toml` manifest file. Open the manifest with a text editor to review its contents: @@ -20,7 +20,7 @@ name = "my_first_package" # authors = ["..."] # e.g., ["Joe Smith (joesmith@noemail.com)", "John Snow (johnsnow@noemail.com)"] [dependencies] -Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet" } +Iota = { git = "https://github.com/iotaledger/iota.git", subdir = "crates/iota-framework/packages/iota-framework", rev = "framework/testnet" } # For remote import, use the `{ git = "...", subdir = "...", rev = "..." }`. # Revision can be a branch, a tag, and a commit hash. @@ -53,9 +53,9 @@ my_first_package = "0x0" The manifest file contents include available sections of the manifest and comments that provide additional information. In Move, you prepend the hash mark (`#`) to a line to denote a comment. -- **[package]:** Contains metadata for the package. By default, the `sui move new` command populates only the `name` value of the metadata. In this case, the example passes `my_first_package` to the command, which becomes the name of the package. You can delete the first `#` of subsequent lines of the `[package]` section to provide values for the other available metadata fields. -- **[dependencies]:** Lists the other packages that your package depends on to run. By default, the `sui move new` command lists the `Sui` package on GitHub (Testnet version) as the lone dependency. -- **[addresses]:** Declares named addresses that your package uses. By default, the section includes the package you create with the `sui move new` command and an address of `0x0`. The publish process replaces the `0x0` address with an actual on-chain address. +- **[package]:** Contains metadata for the package. By default, the `iota move new` command populates only the `name` value of the metadata. In this case, the example passes `my_first_package` to the command, which becomes the name of the package. You can delete the first `#` of subsequent lines of the `[package]` section to provide values for the other available metadata fields. +- **[dependencies]:** Lists the other packages that your package depends on to run. By default, the `iota move new` command lists the `Iota` package on GitHub (Testnet version) as the lone dependency. +- **[addresses]:** Declares named addresses that your package uses. By default, the section includes the package you create with the `iota move new` command and an address of `0x0`. The publish process replaces the `0x0` address with an actual on-chain address. - **[dev-dependencies]:** Includes only comments that describe the section. - **[dev-addresses]:** Includes only comments that describe the section. @@ -73,9 +73,9 @@ Populate the `my_module.move` file with the following code: module my_first_package::my_module { // Part 1: Imports - use sui::object::{Self, UID}; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; + use iota::object::{Self, UID}; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; // Part 2: Struct definitions struct Sword has key, store { @@ -121,9 +121,9 @@ module my_first_package::my_module { The comments in the preceding code highlight different parts of a typical Move source file. -- **Part 1: Imports** - Code reuse is a necessity in modern programming. Move supports this concept with imports that allow your module to use types and functions declared in other modules. In this example, the module imports from `object`, `transfer`, and `tx_context` modules. These modules are available to the package because the `Move.toml` file defines the Sui dependency (along with the `sui` named address) where they are defined. +- **Part 1: Imports** - Code reuse is a necessity in modern programming. Move supports this concept with imports that allow your module to use types and functions declared in other modules. In this example, the module imports from `object`, `transfer`, and `tx_context` modules. These modules are available to the package because the `Move.toml` file defines the Iota dependency (along with the `iota` named address) where they are defined. -- **Part 2: Struct declarations** - Structs define types that a module can create or destroy. Struct definitions can include abilities provided with the `has` keyword. The structs in this example, for instance, have the `key` ability, which indicates that these structs are Sui objects that you can transfer between addresses. The `store` ability on the structs provides the ability to appear in other struct fields and be transferred freely. +- **Part 2: Struct declarations** - Structs define types that a module can create or destroy. Struct definitions can include abilities provided with the `has` keyword. The structs in this example, for instance, have the `key` ability, which indicates that these structs are Iota objects that you can transfer between addresses. The `store` ability on the structs provides the ability to appear in other struct fields and be transferred freely. - **Part 3: Module initializer** - A special function that is invoked exactly once when the module publishes. @@ -134,4 +134,4 @@ After you save the file, you have a complete Move package. ## Related links - [Build and Test Packages](./build-test.mdx): Continue this example to build and test your package to get it ready for publishing. -- [Sui Move CLI](../../../references/cli/move.mdx): Available Move commands the CLI provides. \ No newline at end of file +- [Iota Move CLI](../../../references/cli/move.mdx): Available Move commands the CLI provides. \ No newline at end of file diff --git a/docs/content/guides/developer/getting-started.mdx b/docs/content/guides/developer/getting-started.mdx index 3b1580e800a..a0cc68d8c25 100644 --- a/docs/content/guides/developer/getting-started.mdx +++ b/docs/content/guides/developer/getting-started.mdx @@ -2,33 +2,33 @@ title: Getting Started --- -Sui is the first internet-scale programmable blockchain platform. That might read like marketing speak, but as you peruse the documentation to understand the technology, you will discover that Sui addresses many of the problems that hold blockchains back from mass adoption. +Iota is the first internet-scale programmable blockchain platform. That might read like marketing speak, but as you peruse the documentation to understand the technology, you will discover that Iota addresses many of the problems that hold blockchains back from mass adoption. -Before you can get started developing on Sui, you need to understand the code repository and install its binaries. Consequently, the first two topics you need are: +Before you can get started developing on Iota, you need to understand the code repository and install its binaries. Consequently, the first two topics you need are: -- [Sui Environment Setup](./getting-started/sui-environment.mdx) -- [Install Sui](./getting-started/sui-install.mdx) +- [Iota Environment Setup](./getting-started/iota-environment.mdx) +- [Install Iota](./getting-started/iota-install.mdx) -## After installing Sui +## After installing Iota -After you have Sui installed on your system, you can begin to connect with a network and publish smart contracts. +After you have Iota installed on your system, you can begin to connect with a network and publish smart contracts. -- [Connect to a Sui Network](./getting-started/connect.mdx) +- [Connect to a Iota Network](./getting-started/connect.mdx) - [Connect to a Local Network](./getting-started/local-network.mdx) -- [Get Sui Address](./getting-started/get-address.mdx) -- [Get SUI Coins](./getting-started/get-coins.mdx) +- [Get Iota Address](./getting-started/get-address.mdx) +- [Get IOTA Coins](./getting-started/get-coins.mdx) ## GraphQL queries -Use the GraphQL service for Sui RPC to interact with on-chain data. +Use the GraphQL service for Iota RPC to interact with on-chain data. -Go to [Query Sui RPC with GraphQL](./getting-started/graphql-rpc.mdx). +Go to [Query Iota RPC with GraphQL](./getting-started/graphql-rpc.mdx). ## Related links -After installing Sui and setting up your development environment, use the information in the following sections to continue your development journey. +After installing Iota and setting up your development environment, use the information in the following sections to continue your development journey. - [App Examples](./app-examples.mdx): A mix of end-to-end examples that you can draw inspiration from in your own projects. -- [Sui 101](./sui-101.mdx): Topics that you should know when just starting out to develop on Sui. +- [Iota 101](./iota-101.mdx): Topics that you should know when just starting out to develop on Iota. - [Advanced Topics](./advanced.mdx): Topics that you might not find beneficial until you start solving more complex problems. - [Cryptography](./cryptography.mdx): Leverage cryptography functions to provide security for your smart contract actions. diff --git a/docs/content/guides/developer/getting-started/connect.mdx b/docs/content/guides/developer/getting-started/connect.mdx index 5288f9aff4b..f457c742ea5 100644 --- a/docs/content/guides/developer/getting-started/connect.mdx +++ b/docs/content/guides/developer/getting-started/connect.mdx @@ -1,25 +1,25 @@ --- -title: Connect to a Sui Network -description: Besides Mainnet, Sui offers Testnet, Devnet, and local networks that you can connect to for development. You can also configure a custom RPC endpoint. +title: Connect to a Iota Network +description: Besides Mainnet, Iota offers Testnet, Devnet, and local networks that you can connect to for development. You can also configure a custom RPC endpoint. --- import DataWipe from "../../../_snippets/data-wipe.mdx"; -Sui has Mainnet, Devnet, and Testnet networks available. You can use one of the test networks, Devnet or Testnet, to experiment with the version of Sui running on that network. You can also spin up a [local Sui network](./local-network.mdx) for local development. +Iota has Mainnet, Devnet, and Testnet networks available. You can use one of the test networks, Devnet or Testnet, to experiment with the version of Iota running on that network. You can also spin up a [local Iota network](./local-network.mdx) for local development. -The Sui Testnet and Devnet networks consist of four validator nodes operated by Mysten Labs. Clients send transactions and read requests via this endpoint: `https://fullnode..sui.io:443` using [JSON-RPC](/references/sui-api/json-rpc-format.mdx). +The Iota Testnet and Devnet networks consist of four validator nodes operated by Mysten Labs. Clients send transactions and read requests via this endpoint: `https://fullnode..iota.io:443` using [JSON-RPC](/references/iota-api/json-rpc-format.mdx). -You can [request test SUI tokens](#request-test-tokens) through the Sui [devnet-faucet](https://discordapp.com/channels/916379725201563759/971488439931392130) and [testnet-faucet](https://discord.com/channels/916379725201563759/1037811694564560966) Discord channels, depending on which version of the network you use. If connected to Localnet, use cURL to request tokens from your [local faucet](./local-network.mdx#use-the-local-faucet). The coins on these networks have no financial value. There is no faucet service for Mainnet. +You can [request test IOTA tokens](#request-test-tokens) through the Iota [devnet-faucet](https://discordapp.com/channels/916379725201563759/971488439931392130) and [testnet-faucet](https://discord.com/channels/916379725201563759/1037811694564560966) Discord channels, depending on which version of the network you use. If connected to Localnet, use cURL to request tokens from your [local faucet](./local-network.mdx#use-the-local-faucet). The coins on these networks have no financial value. There is no faucet service for Mainnet. -See announcements about Sui in the [#announcements](https://discord.com/channels/916379725201563759/925109817834631189) Discord channel. +See announcements about Iota in the [#announcements](https://discord.com/channels/916379725201563759/925109817834631189) Discord channel. -See the [terms of service](https://sui.io/terms/) for using Sui networks. +See the [terms of service](https://iota.io/terms/) for using Iota networks. -## Sui CLI +## Iota CLI -Sui provides [Sui command line interface (CLI)](/references/cli/client.mdx) to interact with Sui networks: +Iota provides [Iota command line interface (CLI)](/references/cli/client.mdx) to interact with Iota networks: - Create and manage your private keys - Create example NFTs @@ -28,43 +28,43 @@ Sui provides [Sui command line interface (CLI)](/references/cli/client.mdx) to i ## Environment set up -First, [Install Sui](./sui-install.mdx#install-binaries). After you install Sui, [request SUI test tokens](#request-gas-tokens) through Discord for the network you are using: [Devnet](https://discordapp.com/channels/916379725201563759/971488439931392130) or [Testnet](https://discord.com/channels/916379725201563759/1037811694564560966). If connected to Localnet, use cURL to request tokens from your [local faucet](./local-network.mdx#use-the-local-faucet). +First, [Install Iota](./iota-install.mdx#install-binaries). After you install Iota, [request IOTA test tokens](#request-gas-tokens) through Discord for the network you are using: [Devnet](https://discordapp.com/channels/916379725201563759/971488439931392130) or [Testnet](https://discord.com/channels/916379725201563759/1037811694564560966). If connected to Localnet, use cURL to request tokens from your [local faucet](./local-network.mdx#use-the-local-faucet). -To check whether Sui is already installed, run the following command: +To check whether Iota is already installed, run the following command: ```shell -which sui +which iota ``` -If Sui is installed, the command returns the path to the Sui binary. If Sui is not installed, it returns `sui not found`. +If Iota is installed, the command returns the path to the Iota binary. If Iota is not installed, it returns `iota not found`. -See the [Sui Releases](https://github.com/MystenLabs/sui/releases) page to view the changes in each Sui release. +See the [Iota Releases](https://github.com/iotaledger/iota/releases) page to view the changes in each Iota release. -## Configure Sui client +## Configure Iota client -If you previously ran `sui genesis` to create a local network, it created a Sui client configuration file (client.yaml) that connects to `localhost` at `http://0.0.0.0:9000`. See [Connect to a custom RPC endpoint](#connect-to-a-custom-rpc-endpoint) to update the client.yaml file. +If you previously ran `iota genesis` to create a local network, it created a Iota client configuration file (client.yaml) that connects to `localhost` at `http://0.0.0.0:9000`. See [Connect to a custom RPC endpoint](#connect-to-a-custom-rpc-endpoint) to update the client.yaml file. -To connect the Sui client to a network, run the following command: +To connect the Iota client to a network, run the following command: ```shell -sui client +iota client ``` -If you receive the `sui-client` help output in the console, you already have a client.yaml file. See [Connect to a custom RPC endpoint](#connect-to-a-custom-rpc-endpoint) to add a new environment alias or to switch the currently active network. +If you receive the `iota-client` help output in the console, you already have a client.yaml file. See [Connect to a custom RPC endpoint](#connect-to-a-custom-rpc-endpoint) to add a new environment alias or to switch the currently active network. -The first time you start Sui client without having a client.yaml file, the console displays the following message: +The first time you start Iota client without having a client.yaml file, the console displays the following message: ``` -Config file ["/client.yaml"] doesn't exist, do you want to connect to a Sui Full node server [y/N]? +Config file ["/client.yaml"] doesn't exist, do you want to connect to a Iota Full node server [y/N]? ``` Press **y** and then press **Enter**. The process then requests the RPC server URL: ``` -Sui Full node server URL (Defaults to Sui Devnet if not specified) : +Iota Full node server URL (Defaults to Iota Devnet if not specified) : ``` -Press **Enter** to connect to Sui Devnet. To use a custom RPC server, Sui Testnet, or Sui Mainnet, enter the URL to the correct RPC endpoint and then press **Enter**. +Press **Enter** to connect to Iota Devnet. To use a custom RPC server, Iota Testnet, or Iota Mainnet, enter the URL to the correct RPC endpoint and then press **Enter**. If you enter a URL, the process prompts for an alias for the environment: @@ -79,7 +79,7 @@ Select key scheme to generate keypair (0 for ed25519, 1 for secp256k1, 2 for sec Press **0**, **1**, or **2** to select a key scheme and the press **Enter**. -Sui returns a message similar to the following (depending on the key scheme you selected) that includes the address and 12-word recovery phrase for the address: +Iota returns a message similar to the following (depending on the key scheme you selected) that includes the address and 12-word recovery phrase for the address: ``` Generated new keypair for address with scheme "ed25519" [0xb9c83a8b40d3263c9ba40d551514fbac1f8c12e98a4005a0dac072d3549c2442] @@ -88,32 +88,32 @@ Secret Recovery Phrase : [cap wheat many line human lazy few solid bored proud s ### Connect to a custom RPC endpoint -If you previously used `sui genesis` with the force option (`-f` or `--force`), your client.yaml file already includes two RPC endpoints: `localnet` at `http://0.0.0.0:9000` and `devnet` at `https://fullnode.devnet.sui.io:443`. You can view the defined environments with the `sui client envs` command, and switch between them with the `sui client switch` command. +If you previously used `iota genesis` with the force option (`-f` or `--force`), your client.yaml file already includes two RPC endpoints: `localnet` at `http://0.0.0.0:9000` and `devnet` at `https://fullnode.devnet.iota.io:443`. You can view the defined environments with the `iota client envs` command, and switch between them with the `iota client switch` command. -If you previously installed a Sui client that connected to a Sui network, or created a local network, you can modify your existing client.yaml file to change the configured RPC endpoint. The `sui client` commands that relate to environments read from and write to the client.yaml file. +If you previously installed a Iota client that connected to a Iota network, or created a local network, you can modify your existing client.yaml file to change the configured RPC endpoint. The `iota client` commands that relate to environments read from and write to the client.yaml file. To check currently available environment aliases, run the following command: ```sh -sui client envs +iota client envs ``` The command outputs the available environment aliases, with `(active)` denoting the currently active network. ```sh localnet => http://0.0.0.0:9000 (active) -devnet => https://fullnode.devnet.sui.io:443 +devnet => https://fullnode.devnet.iota.io:443 ``` To add a new alias for a custom RPC endpoint, run the following command. Replace values in `<` `>` with values for your installation: ```shell -sui client new-env --alias --rpc +iota client new-env --alias --rpc ``` To switch the active network, run the following command: ```shell -sui client switch --env +iota client switch --env ``` -If you encounter an issue, delete the Sui configuration directory (`~/.sui/sui_config`) and reinstall the latest [Sui binaries](./sui-install.mdx#install-sui-binaries). +If you encounter an issue, delete the Iota configuration directory (`~/.iota/iota_config`) and reinstall the latest [Iota binaries](./iota-install.mdx#install-iota-binaries). diff --git a/docs/content/guides/developer/getting-started/get-address.mdx b/docs/content/guides/developer/getting-started/get-address.mdx index f034d38e1bc..4d948110177 100644 --- a/docs/content/guides/developer/getting-started/get-address.mdx +++ b/docs/content/guides/developer/getting-started/get-address.mdx @@ -1,44 +1,44 @@ --- -title: Get Sui Address -description: You need an address on the Sui network before you can start trading NFTs, purchase SUI tokens, or perform other transactions. +title: Get Iota Address +description: You need an address on the Iota network before you can start trading NFTs, purchase IOTA tokens, or perform other transactions. --- -An address is a way to uniquely and anonymously identify an account that exists on the Sui blockchain network. In other words, an address is a way for a user to store and use tokens on the Sui network, without providing any personally identifying information (such as email address, phone number, and so on). For example, if you want to purchase a number of SUI tokens to play a game, you must specify an address where these tokens are to be deposited. +An address is a way to uniquely and anonymously identify an account that exists on the Iota blockchain network. In other words, an address is a way for a user to store and use tokens on the Iota network, without providing any personally identifying information (such as email address, phone number, and so on). For example, if you want to purchase a number of IOTA tokens to play a game, you must specify an address where these tokens are to be deposited. -The Sui address is unique, similarly to the way a social security number or a personal identification number is unique to one person. However, in Sui you can create and own multiple addresses, all of which are unique. +The Iota address is unique, similarly to the way a social security number or a personal identification number is unique to one person. However, in Iota you can create and own multiple addresses, all of which are unique. -In Sui, an address is 32 bytes and is often encoded in base58 with `0x` prefix. For example, this is a valid Sui address: `0x02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331`. You can use the a Sui network explorer to find more information about this address and the objects it owns. +In Iota, an address is 32 bytes and is often encoded in base58 with `0x` prefix. For example, this is a valid Iota address: `0x02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331`. You can use the a Iota network explorer to find more information about this address and the objects it owns. -If you'd like to understand how a Sui address is derived from private keys and other cryptography related topics, see the [Keys and Addresses](/concepts/cryptography/transaction-auth/keys-addresses.mdx) topic. +If you'd like to understand how a Iota address is derived from private keys and other cryptography related topics, see the [Keys and Addresses](/concepts/cryptography/transaction-auth/keys-addresses.mdx) topic. -## How to obtain a Sui address +## How to obtain a Iota address -Sui provides multiple ways to obtain a Sui address. The following are the two most common. +Iota provides multiple ways to obtain a Iota address. The following are the two most common. -### Sui Wallet +### Iota Wallet -One of the most straightforward ways to obtain a Sui address for first-time users is through the [Sui Wallet Chrome browser extension](https://chrome.google.com/webstore/detail/sui-wallet/opcgpfmipidbgpenhmajoajpbobppdil). After you install the extension, there are several ways to create an address. +One of the most straightforward ways to obtain a Iota address for first-time users is through the [Iota Wallet Chrome browser extension](https://chrome.google.com/webstore/detail/iota-wallet/opcgpfmipidbgpenhmajoajpbobppdil). After you install the extension, there are several ways to create an address. -Open the Chrome Sui Wallet browser extension and then: +Open the Chrome Iota Wallet browser extension and then: - Use your gmail/twitch/facebook account (ZkLogin) and follow the on-screen instructions - Click **More Options** → **Create a new passphrase account**. Then follow the on-screen instructions. -For more information on the Sui Wallet and how to keep it secure, see the [Sui Wallet documentation](https://mysten-docs-site.vercel.app/wallet). +For more information on the Iota Wallet and how to keep it secure, see the [Iota Wallet documentation](https://mysten-docs-site.vercel.app/wallet). ### Command line interface -If you are using the Sui command line interface (CLI) to interact with the Sui network, you can use the `sui client` command to generate a new address. By default, when the Sui CLI runs for the first time it will prompt you to set up your local wallet, and then it generates one Sui address and the associated secret recovery phrase. Make sure you write down the secret recovery phrase and store it in a safe place. +If you are using the Iota command line interface (CLI) to interact with the Iota network, you can use the `iota client` command to generate a new address. By default, when the Iota CLI runs for the first time it will prompt you to set up your local wallet, and then it generates one Iota address and the associated secret recovery phrase. Make sure you write down the secret recovery phrase and store it in a safe place. -To generate a new Sui address use `sui client new-address ed25519`, which specifies the keypair scheme flag to be of type `ed25519`. +To generate a new Iota address use `iota client new-address ed25519`, which specifies the keypair scheme flag to be of type `ed25519`. -For more information, see the [Sui Client CLI](../../../references/cli/client.mdx) documentation. +For more information, see the [Iota Client CLI](../../../references/cli/client.mdx) documentation. -To see all the generated addresses in the local wallet on your machine, run `sui keytool list`. For more information about the keytool options, see the [Sui Keytool CLI](../../../references/cli/keytool.mdx) documentation. +To see all the generated addresses in the local wallet on your machine, run `iota keytool list`. For more information about the keytool options, see the [Iota Keytool CLI](../../../references/cli/keytool.mdx) documentation. :::danger -The private keys associated with the Sui addresses are stored locally on the machine where the CLI is installed, in the `~/.sui/sui_config/sui.keystore` file. Make sure you do not expose this to anyone, as they can use it to get access to your account. +The private keys associated with the Iota addresses are stored locally on the machine where the CLI is installed, in the `~/.iota/iota_config/iota.keystore` file. Make sure you do not expose this to anyone, as they can use it to get access to your account. ::: diff --git a/docs/content/guides/developer/getting-started/get-coins.mdx b/docs/content/guides/developer/getting-started/get-coins.mdx index 710eeeb2b14..dcda895819d 100644 --- a/docs/content/guides/developer/getting-started/get-coins.mdx +++ b/docs/content/guides/developer/getting-started/get-coins.mdx @@ -1,63 +1,63 @@ --- -title: Get SUI Tokens +title: Get IOTA Tokens --- -Sui faucet is a helpful tool where Sui developers can get free test SUI tokens to deploy and interact with their programs on Sui's Devnet and Testnet networks. There is no faucet for Sui Mainnet. +Iota faucet is a helpful tool where Iota developers can get free test IOTA tokens to deploy and interact with their programs on Iota's Devnet and Testnet networks. There is no faucet for Iota Mainnet. ## Prerequisites -To request tokens from the faucet, you must own a wallet address that can receive the SUI tokens. See the [Get Sui Address](./get-address.mdx) topic if you don't already have an address or need to create a new one. +To request tokens from the faucet, you must own a wallet address that can receive the IOTA tokens. See the [Get Iota Address](./get-address.mdx) topic if you don't already have an address or need to create a new one. ## Request test tokens via the CLI -If you are using the Devnet or Testnet networks, or you spun up a local network, you can use the [Sui CLI](../../../references/cli/client.mdx) to request tokens for your address. The `sui client faucet` uses the active network and active address that is currently set in the Sui CLI by default, but you can specify custom data through the following two arguments: +If you are using the Devnet or Testnet networks, or you spun up a local network, you can use the [Iota CLI](../../../references/cli/client.mdx) to request tokens for your address. The `iota client faucet` uses the active network and active address that is currently set in the Iota CLI by default, but you can specify custom data through the following two arguments: - `--address` argument to provide a specific address (or its alias), - `--url` argument to provide a custom faucet endpoint. ## Request test tokens through Discord -1. Join [Discord](https://discord.gg/sui). - If you try to join the Sui Discord channel using a newly created Discord account, you may need to wait a few days for validation. -1. Request test SUI tokens in the Sui [#devnet-faucet](https://discord.com/channels/916379725201563759/971488439931392130) or [#testnet-faucet](https://discord.com/channels/916379725201563759/1037811694564560966) Discord channels. Send the following message to the channel with your client address: +1. Join [Discord](https://discord.gg/iota). + If you try to join the Iota Discord channel using a newly created Discord account, you may need to wait a few days for validation. +1. Request test IOTA tokens in the Iota [#devnet-faucet](https://discord.com/channels/916379725201563759/971488439931392130) or [#testnet-faucet](https://discord.com/channels/916379725201563759/1037811694564560966) Discord channels. Send the following message to the channel with your client address: `!faucet ` ## Request test tokens through wallet -You can request test tokens within [Sui Wallet](https://github.com/MystenLabs/mysten-app-docs/blob/main/mysten-sui-wallet.md#add-sui-tokens-to-your-sui-wallet). +You can request test tokens within [Iota Wallet](https://github.com/MystenLabs/mysten-app-docs/blob/main/mysten-iota-wallet.md#add-iota-tokens-to-your-iota-wallet). ## Request test tokens through cURL Use the following cURL command to request tokens directly from the faucet server: ``` -curl --location --request POST 'https://faucet.devnet.sui.io/gas' \ +curl --location --request POST 'https://faucet.devnet.iota.io/gas' \ --header 'Content-Type: application/json' \ --data-raw '{ "FixedAmountRequest": { - "recipient": "" + "recipient": "" } }' ``` -If you're working with a local network, replace `'https://faucet.devnet.sui.io/gas'` with the appropriate value based on which package runs your network: +If you're working with a local network, replace `'https://faucet.devnet.iota.io/gas'` with the appropriate value based on which package runs your network: -- `sui-faucet`: `http://127.0.0.1:5003/gas` -- `sui-test-validator`: `http://127.0.0.1:9123/gas` +- `iota-faucet`: `http://127.0.0.1:5003/gas` +- `iota-test-validator`: `http://127.0.0.1:9123/gas` ## Request test tokens through TypeScript SDK -You can also access the faucet using the Sui TypeScript-SDK. +You can also access the faucet using the Iota TypeScript-SDK. ```typescript -import { requestSuiFromFaucetV0, getFaucetHost } from '@mysten/sui.js/faucet'; +import { requestIotaFromFaucetV0, getFaucetHost } from '@iota/iota.js/faucet'; // get tokens from the Devnet faucet server -await requestSuiFromFaucetV0({ +await requestIotaFromFaucetV0({ // connect to Devnet host: getFaucetHost('devnet'), - recipient: '', + recipient: '', }); ``` ## Test tokens on a local network -If you are running a local Sui network, you can get tokens from your local faucet. See the [Connect to a Local Network](./local-network.mdx#use-the-local-faucet) topic for details. +If you are running a local Iota network, you can get tokens from your local faucet. See the [Connect to a Local Network](./local-network.mdx#use-the-local-faucet) topic for details. diff --git a/docs/content/guides/developer/getting-started/graphql-rpc.mdx b/docs/content/guides/developer/getting-started/graphql-rpc.mdx index 1807c7e206d..ffeb4041a0e 100644 --- a/docs/content/guides/developer/getting-started/graphql-rpc.mdx +++ b/docs/content/guides/developer/getting-started/graphql-rpc.mdx @@ -1,18 +1,18 @@ --- -title: Querying Sui RPC with GraphQL -description: Intoductory guide to making queries of the Sui RPC using the GraphQL service. +title: Querying Iota RPC with GraphQL +description: Intoductory guide to making queries of the Iota RPC using the GraphQL service. --- -The quickest way to access the GraphQL service for Sui RPC is through the online IDE that provides a complete toolbox for fetching data and executing transactions on the network. The online IDE provides features such as auto-completion (use Ctrl+Space or just start typing), built-in documentation (Book icon, top-left), multi-tabs, and more. +The quickest way to access the GraphQL service for Iota RPC is through the online IDE that provides a complete toolbox for fetching data and executing transactions on the network. The online IDE provides features such as auto-completion (use Ctrl+Space or just start typing), built-in documentation (Book icon, top-left), multi-tabs, and more. -The online IDE is available for [Mainnet](https://sui-mainnet.mystenlabs.com/graphql) and [Testnet](https://sui-testnet.mystenlabs.com/graphql). This guide contains various queries that you can try directly in the IDE. +The online IDE is available for [Mainnet](https://iota-mainnet.mystenlabs.com/graphql) and [Testnet](https://iota-testnet.mystenlabs.com/graphql). This guide contains various queries that you can try directly in the IDE. :::info - Any existing addresses/object IDs in these examples refer to `mainnet` data only. -- Both [mainnet](https://sui-mainnet.mystenlabs.com/graphql) and [testnet](https://sui-testnet.mystenlabs.com/graphql) services are rate-limited to keep network throughput optimized. +- Both [mainnet](https://iota-mainnet.mystenlabs.com/graphql) and [testnet](https://iota-testnet.mystenlabs.com/graphql) services are rate-limited to keep network throughput optimized. ::: -For more details about some concepts used in the examples below, please see the [GraphQL concepts](../../../concepts/graphql-rpc.mdx) page, and consult the [reference](../../../references/sui-graphql.mdx) for full documentation on the supported schema. +For more details about some concepts used in the examples below, please see the [GraphQL concepts](../../../concepts/graphql-rpc.mdx) page, and consult the [reference](../../../references/iota-graphql.mdx) for full documentation on the supported schema. ## Discovering the schema @@ -99,14 +99,14 @@ query { ## Finding all transactions that touched a given object -This example finds all the transactions that touched (modified/transferred/deleted) a given object. This is useful for when we want to trace the flow of a Coin/StakeSui/NFT. +This example finds all the transactions that touched (modified/transferred/deleted) a given object. This is useful for when we want to trace the flow of a Coin/StakeIota/NFT. :::info This example uses GraphQL [variables](../../../concepts/graphql-rpc.mdx#variables) and [pagination](../../../concepts/graphql-rpc.mdx#pagination). When using the online IDE, copy the variables JSON to the "Variables" window, below the main editor. ::: ```graphql -query ($objectID: SuiAddress!) { +query ($objectID: IotaAddress!) { transactionBlocks(filter: {changedObject: $objectID}) { nodes { sender { @@ -158,9 +158,9 @@ This example makes usage of the filter `last`, which indicates that the user onl This example finds the balance changes of all the transactions where a given address called a staking-related function. This is useful when you want to get your staking or unstaking history. ```graphql -query ($address: SuiAddress!) { +query ($address: IotaAddress!) { transactionBlocks(filter: { - function: "0x3::sui_system::request_add_stake" + function: "0x3::iota_system::request_add_stake" signAddress: $address }) { nodes { @@ -242,14 +242,14 @@ fragment MoveValueFields on MoveValue { ## Fetching all dynamic fields on an object -This query can be used to paginate over the dynamic fields of an object. This works even when the object in question is [wrapped](../../../concepts/object-ownership/wrapped.mdx), by using the owner query, so can be used for iterating over the elements of on-chain data structures, like [Tables and Bags](../../../concepts/dynamic-fields/tables-bags.mdx). +This query can be used to paginate over the dynamic fields of an object. This works even when the object in question is [wrapped](../../../concepts/object-ownership/wrapped.mdx), by using the owner query, so can be used for iterating over the elements of on-chain data structures, like [Tables and Bags](../../../concepts/dynamic-fields/tables-bags.mdx). :::info This example uses [fragments](../../../concepts/graphql-rpc.mdx#fragments) and [variables](../../../concepts/graphql-rpc.mdx#variables). ::: ```graphql -query ($id: SuiAddress!) { +query ($id: IotaAddress!) { owner(address: $id) { dynamicFields { nodes { @@ -328,7 +328,7 @@ This example uses GraphQL [variables](../../../concepts/graphql-rpc.mdx#variable ## Executing a transaction -Transaction execution takes in two arguments, `txBytes` and `signatures`. `txBytes` is the serialized unsigned transaction data, which can be generated when using the Sui CLI's `client call` [command](../../../references/cli/client.mdx), to call a Move function by passing the `--serialize-unsigned-transaction` flag. The `signatures` can be generated using Sui CLI's [keytool](../../../references/cli/keytool.mdx) command `sui keytool sign`. More information on Sui CLI can be found [here](/references/cli). +Transaction execution takes in two arguments, `txBytes` and `signatures`. `txBytes` is the serialized unsigned transaction data, which can be generated when using the Iota CLI's `client call` [command](../../../references/cli/client.mdx), to call a Move function by passing the `--serialize-unsigned-transaction` flag. The `signatures` can be generated using Iota CLI's [keytool](../../../references/cli/keytool.mdx) command `iota keytool sign`. More information on Iota CLI can be found [here](/references/cli). ```graphql mutation ($tx: String!, $sigs: [String!]!) { @@ -361,14 +361,14 @@ mutation ($tx: String!, $sigs: [String!]!) { ## Other examples -You can find other examples in the [repository](https://github.com/MystenLabs/sui/tree/releases/sui-graphql-rpc-v2024.1.0-release/crates/sui-graphql-rpc/examples), grouped into sub-directories. For example, there are directories for [transaction block effects](https://github.com/MystenLabs/sui/tree/releases/sui-graphql-rpc-v2024.1.0-release/crates/sui-graphql-rpc/examples/transaction_block_effects), [protocol configs](https://github.com/MystenLabs/sui/tree/releases/sui-graphql-rpc-v2024.1.0-release/crates/sui-graphql-rpc/examples/protocol_configs), [stake connection](https://github.com/MystenLabs/sui/tree/releases/sui-graphql-rpc-v2024.1.0-release/crates/sui-graphql-rpc/examples/stake_connection), and more. +You can find other examples in the [repository](https://github.com/iotaledger/iota/tree/releases/iota-graphql-rpc-v2024.1.0-release/crates/iota-graphql-rpc/examples), grouped into sub-directories. For example, there are directories for [transaction block effects](https://github.com/iotaledger/iota/tree/releases/iota-graphql-rpc-v2024.1.0-release/crates/iota-graphql-rpc/examples/transaction_block_effects), [protocol configs](https://github.com/iotaledger/iota/tree/releases/iota-graphql-rpc-v2024.1.0-release/crates/iota-graphql-rpc/examples/protocol_configs), [stake connection](https://github.com/iotaledger/iota/tree/releases/iota-graphql-rpc-v2024.1.0-release/crates/iota-graphql-rpc/examples/stake_connection), and more. :::info -Examples in the repository are designed to work with the version of GraphQL built at the same revision. The links above point to examples intended for [GraphQL v2024.1](https://github.com/MystenLabs/sui/tree/releases/sui-graphql-rpc-v2024.1.0-release), the latest production version at the time of writing. +Examples in the repository are designed to work with the version of GraphQL built at the same revision. The links above point to examples intended for [GraphQL v2024.1](https://github.com/iotaledger/iota/tree/releases/iota-graphql-rpc-v2024.1.0-release), the latest production version at the time of writing. ::: ## Related links -- [GraphQL migration](../advanced/graphql-migration.mdx): Migrating to GraphQL guides you through migrating Sui RPC projects from JSON-RPC to GraphQL. -- [GraphQL concepts](../../../concepts/graphql-rpc.mdx): GraphQL for Sui RPC examines the elements of GraphQL that you should know to get the most from the service. -- [GraphQL reference](../../../references/sui-graphql.mdx): Auto-generated GraphQL reference for Sui RPC. \ No newline at end of file +- [GraphQL migration](../advanced/graphql-migration.mdx): Migrating to GraphQL guides you through migrating Iota RPC projects from JSON-RPC to GraphQL. +- [GraphQL concepts](../../../concepts/graphql-rpc.mdx): GraphQL for Iota RPC examines the elements of GraphQL that you should know to get the most from the service. +- [GraphQL reference](../../../references/iota-graphql.mdx): Auto-generated GraphQL reference for Iota RPC. \ No newline at end of file diff --git a/docs/content/guides/developer/getting-started/iota-environment.mdx b/docs/content/guides/developer/getting-started/iota-environment.mdx new file mode 100644 index 00000000000..87b9eaa33a1 --- /dev/null +++ b/docs/content/guides/developer/getting-started/iota-environment.mdx @@ -0,0 +1,101 @@ +--- +title: Iota Environment Setup +description: Get the background information you need before you start developing on Iota. Learn the layout of the Iota monorepository and the suggested development environment for working with Move. +--- + +Before you start developing with Iota and Move, you should familiarize yourself with how to contribute to Iota, how Iota is structured, what tools and SDKs exist, and what plugins are available to use in your IDE. + +## Fork the Iota repository {#fork} + +The recommended way to contribute to the Iota repository is to fork the project, make changes on your fork, then submit a pull request (PR). The Iota repository is available on GitHub: https://github.com/iotaledger/iota. + +To create a local Iota repository: + +1. Go to the [Iota repository](https://github.com/iotaledger/iota) on GitHub. +1. Click the **Fork** button to create a copy of the repository in your account. + + ![Fork Iota repo](./images/fork.png) + +1. In your forked repository on GitHub, click the green `Code <>` button and copy the **HTTPS** URL GitHub provides. + + ![Copy URL](./images/gh-url.png) + +1. Open a terminal or console on your system at the location you want to save the repository locally. Type `git clone ` and paste the URL you copied in the previous step and press `Enter`. +1. Type `cd iota` to make `iota` the active directory. + +You can use any [branching strategy](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-and-deleting-branches-within-your-repository) you prefer on your Iota fork. Make your changes locally and push to your repository, submitting PRs to the official Iota repository from your fork as needed. + +:::tip + +Be sure to synchronize your fork frequently to keep it up-to-date with active development. + +::: + + +## Using Iota from command line + +You can interact with the Iota network through two official SDKs (TypeScript SDK and Rust SDK), and by using the Iota CLI. For more details about using the Iota CLI, see [Install Iota](./iota-install.mdx) and the [Iota CLI](/references/cli.mdx) reference. + +## Move IDEs and plugins + +The recommended IDE for Move development is Visual Studio Code with the `move-analyzer` extension. Follow the Visual Studio Marketplace instructions to install the move-analyzer extension, then install the `move-analyzer` language server passing `address32` using the `--features` flag and passing `iota-move` to the branch flag: + +```shell +cargo install --git https://github.com/move-language/move move-analyzer --branch iota-move --features "address32" +``` + +See more [IDE options](https://github.com/MystenLabs/awesome-move#ides) in the [Awesome Move](https://github.com/MystenLabs/awesome-move) documentation. + +After you install VS Code and the `move-analyzer` extension, check out the [Move code examples](https://github.com/iotaledger/iota/tree/main/examples/move). + +To test or run a Move example on Iota, use the `iota move` command from the Iota CLI. + +## Iota repository and how to contribute + +The Iota repo is a monorepo, containing all the source code that is used to build and run the Iota network, as well as this documentation. + +The root folder of the Iota monorepo has the following top-level folders: + +- [apps](https://github.com/iotaledger/iota/tree/main/apps): Contains the source code for the main web applications that Mysten Labs runs, `Iota Wallet`. +- [crates](https://github.com/iotaledger/iota/tree/main/crates): Contains all the Rust crates that are part of the Iota system. +- [dapps](https://github.com/iotaledger/iota/tree/main/dapps): Contains some examples of decentralized applications built on top of Iota, such as Kiosk or Sponsored Transactions. +- [dashboards](https://github.com/iotaledger/iota/tree/main/dashboards): Currently empty. +- [doc](https://github.com/iotaledger/iota/tree/main/doc): Contains deprecated documentation related to Move and Iota. +- [docker](https://github.com/iotaledger/iota/tree/main/docker): Contains the docker files needed to spin up a node, an indexer, a Full node or other services. +- [docs](https://github.com/iotaledger/iota/tree/main/docs): Contains this documentation and the source for this site. +- [examples](https://github.com/iotaledger/iota/tree/main/examples): Contains examples of apps written for Iota and smart contracts written in Move. +- [external-crates](https://github.com/iotaledger/iota/tree/main/external-crates): Contains the source code for the Move programming language. +- [kiosk](https://github.com/iotaledger/iota/tree/main/kiosk): Contains the source code of the Mysten Labs Kiosk extensions and rules, as well as examples. +- [narwhal](https://github.com/iotaledger/iota/tree/main/narwhal): Contains the source code of Narwhal and partially synchronous Bullshark, a DAG-based mempool, and efficient BFT consensus. +- [nre](https://github.com/iotaledger/iota/tree/main/nre): Contains information about node and network reliability engineering. +- [scripts](https://github.com/iotaledger/iota/tree/main/scripts): Contains a number of scripts that are used internally. +- [sdk](https://github.com/iotaledger/iota/tree/main/sdk): Contains the source code for different tools and SDKs, such as the Iota TypeScript SDK, Kiosk SDK, BCS, zkLogin, dApp kit, and others. +- [iota-execution](https://github.com/iotaledger/iota/tree/main/iota-execution): Contains the source code responsible for abstracting access to the execution layer. + +The following primary directories offer a good starting point for exploring the Iota codebase: + +- [move](https://github.com/iotaledger/iota/tree/main/external-crates/move) - Move VM, compiler, and tools. +- [narwhal](https://github.com/iotaledger/iota/tree/main/narwhal) - Mempool and consensus. +- [typescript-sdk](https://github.com/iotaledger/iota/tree/main/sdk/typescript/) - the Iota TypeScript SDK. +- [wallet](https://github.com/iotaledger/iota/tree/main/apps/wallet) - Chrome extension wallet for Iota. +- [iota](https://github.com/iotaledger/iota/tree/main/crates/iota) - the Iota command line tool. +- [iota-core](https://github.com/iotaledger/iota/tree/main/crates/iota-core) - Core Iota components. +- [iota-execution](https://github.com/iotaledger/iota/tree/main/iota-execution) - Execution Layer (programmable transactions, execution integration). +- [iota-framework](https://github.com/iotaledger/iota/tree/main/crates/iota-framework) - Move system packages (0x1, 0x2, 0x3, 0xdee9). +- [iota-network](https://github.com/iotaledger/iota/tree/main/crates/iota-network) - Networking interfaces. +- [iota-node](https://github.com/iotaledger/iota/tree/main/crates/iota-node) - Validator and Full node software. +- [iota-protocol-config](https://github.com/iotaledger/iota/tree/main/crates/iota-protocol-config) - On-chain system configuration and limits. +- [iota-sdk](https://github.com/iotaledger/iota/tree/main/crates/iota-sdk) - The Iota Rust SDK. +- [iota-types](https://github.com/iotaledger/iota/tree/main/crates/iota-types) - Iota object types, such as coins and gas. + +## Development branches + +The Iota repository includes four primary branches: `devnet`, `testnet`, `mainnet`, and `main`. + +The `devnet` branch includes the latest stable build of Iota. Choose the `devnet` branch if you want to build or test on Iota Devnet. If you encounter an issue or find a bug, it may already be fixed in the `main` branch. To submit a PR, you should push commits to your fork of the `main` branch. + +The `testnet` branch includes the code running on the Iota Testnet network. + +The `mainnet` branch includes the code running on the Iota Mainnet network. + +The `main` branch includes the most recent changes and updates. Use the `main` branch if you want to contribute to the Iota project or to experiment with cutting-edge functionality. The `main` branch might include unreleased changes and experimental features, so use it at your own risk. diff --git a/docs/content/guides/developer/getting-started/iota-install.mdx b/docs/content/guides/developer/getting-started/iota-install.mdx new file mode 100644 index 00000000000..6949f52ba6b --- /dev/null +++ b/docs/content/guides/developer/getting-started/iota-install.mdx @@ -0,0 +1,377 @@ +--- +title: Install Iota +description: Install the Iota framework and required prerequisites on your system, including the Iota command line interface to interact with the Iota network. +--- + +import MacosDeps from "../../../_snippets/macos-deps.mdx"; +import LinuxDeps from "../../../_snippets/linux-deps.mdx"; + +The quickest way to install Iota is using the binaries delivered with every release. If you require more control over the install process, you can install from source. To take advantage of containerization, you can utilize the Docker images in the `docker` folder of the iota repository. + +## Supported operating systems {#supported-operating-systems} + +Iota supports the following operating systems: + +- Linux - Ubuntu version 20.04 (Bionic Beaver) +- macOS - macOS Monterey +- Microsoft Windows - Windows 10 and 11 + +## Quick install using Homebrew or Chocolatey {#install-homebrew} + +Use one of the following commands for [Homebrew](https://brew.sh/) (MacOS, Linux, or Windows Subsystem for Linux) or [Chocolatey](https://chocolatey.org/) (Windows) to install Iota. + + + + + +```bash +brew install iota +``` + + + + + +```shell +choco install iota +``` + +Find more [versions of Iota for Windows](https://community.chocolatey.org/packages/iota) on the Chocolatey community website. + + + + + +## Install from binaries {#install-binaries} + +Each Iota release provides a set of binaries for several operating systems. You can download these binaries from GitHub and use them to install Iota. + +1. Go to https://github.com/iotaledger/iota. +1. In the right pane, find the **Releases** section. + + ![Iota releases in GitHub](./images/releases.png) +1. Click the release tagged **Latest** to open the release's page. +1. In the **Assets** section of the release, select the .tgz compressed file that corresponds to your operating system. +1. Double-click the downloaded file. If the file doesn't automatically expand, manually unzip the file. +1. Open the expanded folder and double-click the appropriate binary to install, beginning with iota-``-``: + + - iota-faucet-``-``: Local faucet to mint coins on local network. + - iota-indexer-``-``: An indexer for a local Iota network. + - iota-``-``: Main Iota binary. + - iota-node-``-``: Run a local node. + - iota-test-validator-``-``: Run test validators on a local network for development. + - iota-tool-``-``: Provides utilities for Iota. + + The Iota binary takes several minutes to download and install files, so make sure you allocate enough time for it to complete. Actual time to complete depends on your network connection and computer specifications. + + +### Confirm the installation {#confirm-the-installation} + +To confirm that Iota installed correctly, type `iota` and press Enter. You should see a message about the Iota version installed and help for using Iota commands. + +## Install from source + +Follow the instructions in this topic to install the Rust crates (packages) required to interact with Iota networks, including the Iota CLI. + +To install Iota from source, you first need to install its [prerequisites](#prerequisites) for your operating system. After installing the supporting technologies, you can install [Iota binaries from source](#install-iota-binaries-from-source). + +You can also download the [source code](./iota-environment) to have local access to files. + +## Prerequisites {#prerequisites} + +Your system needs the following prerequisites available to successfully install Iota. + +### Rust and Cargo {#rust-and-cargo} + +Iota requires Rust and Cargo (Rust's package manager) on all supported operating systems. The suggested method to install Rust is with `rustup` using cURL. + +Some other commands in the installation instructions also require cURL to run. If you can't run the cURL command to install Rust, see the instructions to install cURL for your operating system in the following section before you install Rust. + +Use the following command to install Rust and Cargo on macOS or Linux: + +```bash +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + +If you use Windows 11, see information about using the [Rust installer](https://www.rust-lang.org/tools/install) on the Rust website. The installer checks for C++ build tools and prompts you to install them if necessary. Select the option that best defines your environment and follow the instructions in the install wizard. + +For additional installation options, see [Install Rust](https://www.rust-lang.org/tools/install). + +Iota uses the latest version of Cargo to build and manage dependencies. See the [Cargo installation](https://doc.rust-lang.org/cargo/getting-started/installation.html) page on the Rust website for more information. + +Use the following command to update Rust with `rustup`: + +```bash +rustup update stable +``` +### Additional prerequisites by operating system + +Select the appropriate tab to view the requirements for your system. + + + + + +The prerequisites needed for the Linux operating system include: + +- cURL +- Rust and Cargo +- Git CLI +- CMake +- GCC +- libssl-dev +- libclang-dev +- libpq-dev +- build-essential + +:::info + +The Linux instructions assume a distribution that uses the APT package manager. You might need to adjust the instructions to use other package managers. + +::: + +Install the prerequisites listed in this section. Use the following command to update `apt-get`: + +```bash +sudo apt-get update +``` + +#### All Linux prerequisites + +Reference the relevant sections that follow to install each prerequisite individually, or run the following to install them all at once: + + + +#### cURL {#curl} + +Install cURL with the following command: + +```bash +sudo apt-get install curl +``` + +Verify that cURL installed correctly with the following command: + +```bash +curl --version +``` + +#### Git CLI {#git-cli} + +Run the following command to install Git, including the [Git CLI](https://cli.github.com/): + +```bash +sudo apt-get install git-all +``` + +For more information, see [Install Git on Linux](https://github.com/git-guides/install-git#install-git-on-linux) on the GitHub website. + +#### CMake {#cmake} + +Use the following command to install CMake. + +```bash +sudo apt-get install cmake +``` + +To customize the installation, see [Installing CMake](https://cmake.org/install/) on the CMake website. + +#### GCC {#gcc} + +Use the following command to install the GNU Compiler Collection, `gcc`: + +```bash +sudo apt-get install gcc +``` + +#### libssl-dev {#libssl-dev} + +Use the following command to install `libssl-dev`: + +```bash +sudo apt-get install libssl-dev +``` + +If the version of Linux you use doesn't support `libssl-dev`, find an equivalent package for it on the [ROS Index](https://index.ros.org/d/libssl-dev/). + +(Optional) If you have OpenSSL you might also need to also install `pkg-config`: + +```bash +sudo apt-get install pkg-config +``` + +#### libclang-dev {#libclang-dev} + +Use the following command to install `libclang-dev`: + +```bash +sudo apt-get install libclang-dev +``` + +If the version of Linux you use doesn't support `libclang-dev`, find an equivalent package for it on the [ROS Index](https://index.ros.org/d/libclang-dev/). + +#### libpq-dev {#libpq-dev} + +Use the following command to install `libpq-dev`: + +```bash +sudo apt-get install libpq-dev +``` + +If the version of Linux you use doesn't support `libpq-dev`, find an equivalent package for it on the [ROS Index](https://index.ros.org/d/libpq-dev/). + +#### build-essential {#build-essential} + +Use the following command to install `build-essential`: + +```bash +sudo apt-get install build-essential +``` + + + + + +The prerequisites needed for the macOS operating system include: + +- Rust and Cargo +- Homebrew +- cURL +- CMake +- libpq +- Git CLI + +macOS includes a version of cURL you can use to install Homebrew. Use Homebrew to install other tools, including a newer version of cURL. + +#### Homebrew {#brew} + +Use the following command to install [Homebrew](https://brew.sh/): + +```bash +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` + +:::info + +If you used the commands in the [Install using Homebrew](#install-homebrew) section, you do not need to install anything else. + +::: + +#### All macOS prerequisites + +With Homebrew installed, you can install individual prerequisites from the following sections or install them all at once with this command: + + + + +#### cURL {#curl-1} + +Use the following command to update the default [cURL](https://curl.se) on macOS: + +```bash +brew install curl +``` + +#### CMake {#cmake-1} + +Use the following command to install CMake: + +```bash +brew install cmake +``` + +To customize the installation, see [Installing CMake](https://cmake.org/install/) on the CMake website. + +#### libpq {#libpq-1} +Use the following command to install libpq: +```bash +brew install libpq +``` + +#### Git CLI {#git-cli-1} + +Use the following command to install Git: + +```bash +brew install git +``` + +After installing Git, download and install the [Git command line interface](https://git-scm.com/download/). + + + + + +The prerequisites needed for the Windows 11 operating system include: + +- cURL +- Rust and Cargo +- Git CLI +- CMake +- C++ build tools +- LLVM compiler + +#### cURL {#curl-2} + +Windows 11 ships with a Microsoft version of [cURL](https://curl.se/windows/microsoft.html) already installed. If you want to use the curl project version instead, download and install it from [https://curl.se/windows/](https://curl.se/windows/). + +#### Git CLI {#git-cli-2} + +Download and install the [Git command line interface](https://git-scm.com/download/). + +#### CMake {#cmake-2} + +Download and install [CMake](https://cmake.org/download/) from the CMake website. + +#### Protocol Buffers {#protocol-buffers} + +Download [Protocol Buffers](https://github.com/protocolbuffers/protobuf/releases) (protoc-xx.x-win32.zip or protoc-xx.x-win64.zip) and add the \bin directory to your Windows PATH environment variable. + +#### Additional tools for Windows {#additional-tools-windows} + +Iota requires the following additional tools on computers running Windows. + +- For Windows on ARM64 only - [Visual Studio 2022 Preview](https://visualstudio.microsoft.com/vs/preview/). +- [C++ build tools](https://visualstudio.microsoft.com/downloads/) is required to [install Rust](#rust-and-cargo). +- The [LLVM Compiler Infrastructure](https://releases.llvm.org/). Look for a file with a name similar to LLVM-15.0.7-win64.exe for 64-bit Windows, or LLVM-15.0.7-win32.exe for 32-bit Windows. + +**Known issue** - The `iota console` command does not work in PowerShell. + + + + + +## Install Iota binaries from source {#install-iota-binaries-from-source} + +Run the following command to install Iota binaries from the `testnet` branch: + +```shell +cargo install --locked --git https://github.com/iotaledger/iota.git --branch testnet iota +``` + +The install process can take a while to complete. You can monitor installation progress in the terminal. If you encounter an error, make sure to install the latest version of all prerequisites and then try the command again. + +To update to the latest stable version of Rust: + +```shell +rustup update stable +``` + +The command installs Iota components in the `~/.cargo/bin` folder. + +## Upgrade Iota binaries + +If you previously installed the Iota binaries, you can update them to the most recent release with the same command you used to install them: + +```shell +cargo install --locked --git https://github.com/iotaledger/iota.git --branch testnet iota +``` + +## Next steps {#next-steps} + +Now that you have Iota installed, it's time to start developing. Check out the following topics to start working with Iota: + +- Read about the [Iota CLI](/references/cli.mdx), the most straightforward way to start exploring Iota networks. +- [Learn about the available networks](./connect.mdx) and connect to one. +- [Get some coins](./get-coins.mdx) on a development network. +- [Build your first dApp](../first-app.mdx) to start your on-chain journey. diff --git a/docs/content/guides/developer/getting-started/local-network.mdx b/docs/content/guides/developer/getting-started/local-network.mdx index fbb7c9625b8..cf9bfadfd07 100644 --- a/docs/content/guides/developer/getting-started/local-network.mdx +++ b/docs/content/guides/developer/getting-started/local-network.mdx @@ -2,24 +2,24 @@ title: Connect to a Local Network --- -Use a Sui local network to test your dApps against the latest changes to Sui, and to prepare for the next Sui release to the Devnet or Testnet network. To set up a local network, Sui provides the `sui-test-validator` binary. The `sui-test-validator` starts a local network that includes a Sui Full node, a Sui validator, and a Sui faucet. You can use the included faucet to get test SUI to use on the local network. +Use a Iota local network to test your dApps against the latest changes to Iota, and to prepare for the next Iota release to the Devnet or Testnet network. To set up a local network, Iota provides the `iota-test-validator` binary. The `iota-test-validator` starts a local network that includes a Iota Full node, a Iota validator, and a Iota faucet. You can use the included faucet to get test IOTA to use on the local network. -If you haven't already, you need to [install Sui](./sui-install.mdx) on your system. +If you haven't already, you need to [install Iota](./iota-install.mdx) on your system. ## Start the local network -To start the local network, run the following command from your `sui` root folder. +To start the local network, run the following command from your `iota` root folder. ```bash -RUST_LOG="off,sui_node=info" cargo run --bin sui-test-validator +RUST_LOG="off,iota_node=info" cargo run --bin iota-test-validator ``` -The command starts the `sui-test-validator`. The `RUST_LOG`=`off,sui_node=info` turns off logging for all components except -sui-node. If you want to see more detailed logs, you can remove `RUST_LOG` from the command. +The command starts the `iota-test-validator`. The `RUST_LOG`=`off,iota_node=info` turns off logging for all components except +iota-node. If you want to see more detailed logs, you can remove `RUST_LOG` from the command. -**Important:** Each time you start the `sui-test-validator`, the network starts as a new network with no previous data. The local network is not persistent. +**Important:** Each time you start the `iota-test-validator`, the network starts as a new network with no previous data. The local network is not persistent. -To customize your local Sui network, such as changing the port used, include additional parameters in the command to start `sui-test-validator`: +To customize your local Iota network, such as changing the port used, include additional parameters in the command to start `iota-test-validator`: ``` OPTIONS: @@ -27,13 +27,13 @@ OPTIONS: The duration for epochs (defaults to one minute) [default: 60000] --faucet-port - Port to start the Sui faucet on [default: 9123] + Port to start the Iota faucet on [default: 9123] --fullnode-rpc-port Port to start the Fullnode RPC server on [default: 9000] ``` -Use `sui-test-validator --help` to see these options in your console. +Use `iota-test-validator --help` to see these options in your console. ### Access your local Full node @@ -45,7 +45,7 @@ curl --location --request POST 'http://127.0.0.1:9000' \ --data-raw '{ "jsonrpc": "2.0", "id": 1, - "method": "sui_getTotalTransactionBlocks", + "method": "iota_getTotalTransactionBlocks", "params": [] }' ``` @@ -60,18 +60,18 @@ If successful, the response resembles the following: } ``` -## Connect the Sui Client CLI to your local network +## Connect the Iota Client CLI to your local network -You can use the Sui Client CLI with any Sui network. By default it connects to Sui Devnet. To connect to your local network, create a new environment alias named `local` that sets the RPC URL the client uses to your local network. +You can use the Iota Client CLI with any Iota network. By default it connects to Iota Devnet. To connect to your local network, create a new environment alias named `local` that sets the RPC URL the client uses to your local network. ```shell -sui client new-env --alias local --rpc http://127.0.0.1:9000 +iota client new-env --alias local --rpc http://127.0.0.1:9000 ``` Next, use the following command to set the active environment to the new `local` environment you created. ``` -sui client switch --env local +iota client switch --env local ``` The command returns: @@ -81,7 +81,7 @@ The command returns: You can check the current active environment with the following command: ```bash -sui client active-env +iota client active-env ``` The command returns: @@ -90,28 +90,28 @@ The command returns: ## Show the current active address -The Sui Client CLI uses the active address for command if you don't specify one. Use the following command to show the active address on your local network. +The Iota Client CLI uses the active address for command if you don't specify one. Use the following command to show the active address on your local network. ``` -sui client active-address +iota client active-address ``` The command returns an address: `0xbc33e6e4818f9f2ef77d020b35c24be738213e64d9e58839ee7b4222029610de` -Use the active address to get test SUI to use on your local network. Use the `sui client addresses` command to see all of the addresses on your local network. +Use the active address to get test IOTA to use on your local network. Use the `iota client addresses` command to see all of the addresses on your local network. **Note:** The address returned when you run the command is unique and does not match the one used in this example. ## Use the local faucet {#use-the-local-faucet} -Transactions on your local network require SUI coins to pay for gas fees just like other networks. To send coins to a Sui Wallet connected to your local network, see [Set up a local Sui Wallet](#set-up-a-local-sui-wallet). You can use the address for the local Sui Wallet with the faucet. +Transactions on your local network require IOTA coins to pay for gas fees just like other networks. To send coins to a Iota Wallet connected to your local network, see [Set up a local Iota Wallet](#set-up-a-local-iota-wallet). You can use the address for the local Iota Wallet with the faucet. -Sui CLI provides the `sui client faucet` command to get coins from the faucet. In the most basic case, run `sui client faucet` and wait up to 60 seconds for the coins to reach your wallet. Use `sui client gas` to check for the new coins. +Iota CLI provides the `iota client faucet` command to get coins from the faucet. In the most basic case, run `iota client faucet` and wait up to 60 seconds for the coins to reach your wallet. Use `iota client gas` to check for the new coins. :::info -The `faucet` command uses the active address and the active network environment by default. If you need to pass in a different address or faucet server URL, check the `help` menu. If you're using a different network than a local network or the public ones (fullnode.network.sui.io), you will have to pass the URL to the faucet server. +The `faucet` command uses the active address and the active network environment by default. If you need to pass in a different address or faucet server URL, check the `help` menu. If you're using a different network than a local network or the public ones (fullnode.network.iota.io), you will have to pass the URL to the faucet server. ::: @@ -120,7 +120,7 @@ The `faucet` command uses the active address and the active network environment After you get coins from the faucet, use the following command to view the coin objects for the address: ```shell -sui client gas +iota client gas ``` The response resembles the following, but with different IDs: @@ -137,7 +137,7 @@ The response resembles the following, but with different IDs: ╰────────────────────────────────────────────────────────────────────┴────────────╯ ``` -## Install Sui Wallet locally +## Install Iota Wallet locally To install and use the apps locally, you must first install [pnpm](https://pnpm.io/installation). Use the instructions appropriate for your operating system. @@ -147,7 +147,7 @@ After you install `pnpm`, use the following command to install the required depe pnpm install ``` -After the installation completes, run the following command to install Sui Wallet: +After the installation completes, run the following command to install Iota Wallet: ```shell pnpm turbo build @@ -155,29 +155,29 @@ pnpm turbo build If you encounter an error from turbo build, confirm that there is no `package-lock.json`. If the file exists, remove it and then run the command again. -## Set up a local Sui Wallet +## Set up a local Iota Wallet -You can also use a local Sui Wallet to test with your local network. +You can also use a local Iota Wallet to test with your local network. -**Note:** To run the command you must have `pnpm` installed. See [Install Sui Wallet locally](#install-sui-wallet-locally) for details. +**Note:** To run the command you must have `pnpm` installed. See [Install Iota Wallet locally](#install-iota-wallet-locally) for details. -Before you start the Sui Wallet app, update its default environment to point to your local network. To do so, first make a copy of `sui/apps/wallet/configs/environment/.env.defaults` and rename it to `.env` in the same directory. In your `.env` file, edit the first line to read `API_ENV=local` and then save the file. +Before you start the Iota Wallet app, update its default environment to point to your local network. To do so, first make a copy of `iota/apps/wallet/configs/environment/.env.defaults` and rename it to `.env` in the same directory. In your `.env` file, edit the first line to read `API_ENV=local` and then save the file. -Run the following command from the `sui` root folder to start Sui Wallet on your local network: +Run the following command from the `iota` root folder to start Iota Wallet on your local network: ```bash pnpm wallet dev ``` -### Add local Sui Wallet to Chrome +### Add local Iota Wallet to Chrome -After you build your local version of Sui Wallet, you can add the extension to Chrome: +After you build your local version of Iota Wallet, you can add the extension to Chrome: 1. Open a Chrome browser to `chrome://extensions`. 1. Click the **Developer mode** toggle to enable, if it's not already on. -1. Click the **Load unpacked** button and select your `sui/apps/wallet/dist` directory. +1. Click the **Load unpacked** button and select your `iota/apps/wallet/dist` directory. -Consult the Sui Wallet [Readme](https://github.com/MystenLabs/sui/blob/main/apps/wallet/README.md#install-the-extension-to-chrome) for more information on working with a locally built wallet on Chrome. +Consult the Iota Wallet [Readme](https://github.com/iotaledger/iota/blob/main/apps/wallet/README.md#install-the-extension-to-chrome) for more information on working with a locally built wallet on Chrome. ## Generate example data @@ -185,13 +185,13 @@ Use the TypeScript SDK to add example data to your network. **Note:** To run the command you must complete the `Pre-requisites for Building Apps locally` section first. -Run the following command from the `sui` root folder: +Run the following command from the `iota` root folder: ```bash -pnpm --filter @mysten/sui.js test:e2e +pnpm --filter @iota/iota.js test:e2e ``` -For additional information about example data for testing, see [https://github.com/MystenLabs/sui/tree/main/sdk/typescript#testing](https://github.com/MystenLabs/sui/tree/main/sdk/typescript#testing). +For additional information about example data for testing, see [https://github.com/iotaledger/iota/tree/main/sdk/typescript#testing](https://github.com/iotaledger/iota/tree/main/sdk/typescript#testing). ## Troubleshooting @@ -201,6 +201,6 @@ If you do not use [Node.js 18](https://nodejs.org/de/blog/announcements/v18-rele To resolve this, switch or update to Node.js 18 and then try again. -## Test with the Sui TypeScript SDK +## Test with the Iota TypeScript SDK -The published version of the Sui TypeScript SDK might be an earlier version than the version of Sui you installed for your local network. To make sure you're using the latest version of the SDK, use the `experimental`-tagged version (for example, `0.0.0-experimental-20230317184920`) in the [Current Tags](https://www.npmjs.com/package/@mysten/sui.js/v/0.0.0-experimental-20230127130009?activeTab=versions) section of the Sui NPM registry. +The published version of the Iota TypeScript SDK might be an earlier version than the version of Iota you installed for your local network. To make sure you're using the latest version of the SDK, use the `experimental`-tagged version (for example, `0.0.0-experimental-20230317184920`) in the [Current Tags](https://www.npmjs.com/package/@iota/iota.js/v/0.0.0-experimental-20230127130009?activeTab=versions) section of the Iota NPM registry. diff --git a/docs/content/guides/developer/getting-started/sui-environment.mdx b/docs/content/guides/developer/getting-started/sui-environment.mdx deleted file mode 100644 index 6019102e398..00000000000 --- a/docs/content/guides/developer/getting-started/sui-environment.mdx +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: Sui Environment Setup -description: Get the background information you need before you start developing on Sui. Learn the layout of the Sui monorepository and the suggested development environment for working with Move. ---- - -Before you start developing with Sui and Move, you should familiarize yourself with how to contribute to Sui, how Sui is structured, what tools and SDKs exist, and what plugins are available to use in your IDE. - -## Fork the Sui repository {#fork} - -The recommended way to contribute to the Sui repository is to fork the project, make changes on your fork, then submit a pull request (PR). The Sui repository is available on GitHub: https://github.com/MystenLabs/sui. - -To create a local Sui repository: - -1. Go to the [Sui repository](https://github.com/MystenLabs/sui) on GitHub. -1. Click the **Fork** button to create a copy of the repository in your account. - - ![Fork Sui repo](./images/fork.png) - -1. In your forked repository on GitHub, click the green `Code <>` button and copy the **HTTPS** URL GitHub provides. - - ![Copy URL](./images/gh-url.png) - -1. Open a terminal or console on your system at the location you want to save the repository locally. Type `git clone ` and paste the URL you copied in the previous step and press `Enter`. -1. Type `cd sui` to make `sui` the active directory. - -You can use any [branching strategy](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-and-deleting-branches-within-your-repository) you prefer on your Sui fork. Make your changes locally and push to your repository, submitting PRs to the official Sui repository from your fork as needed. - -:::tip - -Be sure to synchronize your fork frequently to keep it up-to-date with active development. - -::: - - -## Using Sui from command line - -You can interact with the Sui network through two official SDKs (TypeScript SDK and Rust SDK), and by using the Sui CLI. For more details about using the Sui CLI, see [Install Sui](./sui-install.mdx) and the [Sui CLI](/references/cli.mdx) reference. - -## Move IDEs and plugins - -The recommended IDE for Move development is Visual Studio Code with the `move-analyzer` extension. Follow the Visual Studio Marketplace instructions to install the move-analyzer extension, then install the `move-analyzer` language server passing `address32` using the `--features` flag and passing `sui-move` to the branch flag: - -```shell -cargo install --git https://github.com/move-language/move move-analyzer --branch sui-move --features "address32" -``` - -See more [IDE options](https://github.com/MystenLabs/awesome-move#ides) in the [Awesome Move](https://github.com/MystenLabs/awesome-move) documentation. - -After you install VS Code and the `move-analyzer` extension, check out the [Move code examples](https://github.com/MystenLabs/sui/tree/main/examples/move). - -To test or run a Move example on Sui, use the `sui move` command from the Sui CLI. - -## Sui repository and how to contribute - -The Sui repo is a monorepo, containing all the source code that is used to build and run the Sui network, as well as this documentation. - -The root folder of the Sui monorepo has the following top-level folders: - -- [apps](https://github.com/MystenLabs/sui/tree/main/apps): Contains the source code for the main web applications that Mysten Labs runs, `Sui Wallet`. -- [crates](https://github.com/MystenLabs/sui/tree/main/crates): Contains all the Rust crates that are part of the Sui system. -- [dapps](https://github.com/MystenLabs/sui/tree/main/dapps): Contains some examples of decentralized applications built on top of Sui, such as Kiosk or Sponsored Transactions. -- [dashboards](https://github.com/MystenLabs/sui/tree/main/dashboards): Currently empty. -- [doc](https://github.com/MystenLabs/sui/tree/main/doc): Contains deprecated documentation related to Move and Sui. -- [docker](https://github.com/MystenLabs/sui/tree/main/docker): Contains the docker files needed to spin up a node, an indexer, a Full node or other services. -- [docs](https://github.com/MystenLabs/sui/tree/main/docs): Contains this documentation and the source for this site. -- [examples](https://github.com/MystenLabs/sui/tree/main/examples): Contains examples of apps written for Sui and smart contracts written in Move. -- [external-crates](https://github.com/MystenLabs/sui/tree/main/external-crates): Contains the source code for the Move programming language. -- [kiosk](https://github.com/MystenLabs/sui/tree/main/kiosk): Contains the source code of the Mysten Labs Kiosk extensions and rules, as well as examples. -- [narwhal](https://github.com/MystenLabs/sui/tree/main/narwhal): Contains the source code of Narwhal and partially synchronous Bullshark, a DAG-based mempool, and efficient BFT consensus. -- [nre](https://github.com/MystenLabs/sui/tree/main/nre): Contains information about node and network reliability engineering. -- [scripts](https://github.com/MystenLabs/sui/tree/main/scripts): Contains a number of scripts that are used internally. -- [sdk](https://github.com/MystenLabs/sui/tree/main/sdk): Contains the source code for different tools and SDKs, such as the Sui TypeScript SDK, Kiosk SDK, BCS, zkLogin, dApp kit, and others. -- [sui-execution](https://github.com/MystenLabs/sui/tree/main/sui-execution): Contains the source code responsible for abstracting access to the execution layer. - -The following primary directories offer a good starting point for exploring the Sui codebase: - -- [move](https://github.com/MystenLabs/sui/tree/main/external-crates/move) - Move VM, compiler, and tools. -- [narwhal](https://github.com/MystenLabs/sui/tree/main/narwhal) - Mempool and consensus. -- [typescript-sdk](https://github.com/MystenLabs/sui/tree/main/sdk/typescript/) - the Sui TypeScript SDK. -- [wallet](https://github.com/MystenLabs/sui/tree/main/apps/wallet) - Chrome extension wallet for Sui. -- [sui](https://github.com/MystenLabs/sui/tree/main/crates/sui) - the Sui command line tool. -- [sui-core](https://github.com/MystenLabs/sui/tree/main/crates/sui-core) - Core Sui components. -- [sui-execution](https://github.com/MystenLabs/sui/tree/main/sui-execution) - Execution Layer (programmable transactions, execution integration). -- [sui-framework](https://github.com/MystenLabs/sui/tree/main/crates/sui-framework) - Move system packages (0x1, 0x2, 0x3, 0xdee9). -- [sui-network](https://github.com/MystenLabs/sui/tree/main/crates/sui-network) - Networking interfaces. -- [sui-node](https://github.com/MystenLabs/sui/tree/main/crates/sui-node) - Validator and Full node software. -- [sui-protocol-config](https://github.com/MystenLabs/sui/tree/main/crates/sui-protocol-config) - On-chain system configuration and limits. -- [sui-sdk](https://github.com/MystenLabs/sui/tree/main/crates/sui-sdk) - The Sui Rust SDK. -- [sui-types](https://github.com/MystenLabs/sui/tree/main/crates/sui-types) - Sui object types, such as coins and gas. - -## Development branches - -The Sui repository includes four primary branches: `devnet`, `testnet`, `mainnet`, and `main`. - -The `devnet` branch includes the latest stable build of Sui. Choose the `devnet` branch if you want to build or test on Sui Devnet. If you encounter an issue or find a bug, it may already be fixed in the `main` branch. To submit a PR, you should push commits to your fork of the `main` branch. - -The `testnet` branch includes the code running on the Sui Testnet network. - -The `mainnet` branch includes the code running on the Sui Mainnet network. - -The `main` branch includes the most recent changes and updates. Use the `main` branch if you want to contribute to the Sui project or to experiment with cutting-edge functionality. The `main` branch might include unreleased changes and experimental features, so use it at your own risk. diff --git a/docs/content/guides/developer/getting-started/sui-install.mdx b/docs/content/guides/developer/getting-started/sui-install.mdx deleted file mode 100644 index 3107d8e0934..00000000000 --- a/docs/content/guides/developer/getting-started/sui-install.mdx +++ /dev/null @@ -1,377 +0,0 @@ ---- -title: Install Sui -description: Install the Sui framework and required prerequisites on your system, including the Sui command line interface to interact with the Sui network. ---- - -import MacosDeps from "../../../_snippets/macos-deps.mdx"; -import LinuxDeps from "../../../_snippets/linux-deps.mdx"; - -The quickest way to install Sui is using the binaries delivered with every release. If you require more control over the install process, you can install from source. To take advantage of containerization, you can utilize the Docker images in the `docker` folder of the sui repository. - -## Supported operating systems {#supported-operating-systems} - -Sui supports the following operating systems: - -- Linux - Ubuntu version 20.04 (Bionic Beaver) -- macOS - macOS Monterey -- Microsoft Windows - Windows 10 and 11 - -## Quick install using Homebrew or Chocolatey {#install-homebrew} - -Use one of the following commands for [Homebrew](https://brew.sh/) (MacOS, Linux, or Windows Subsystem for Linux) or [Chocolatey](https://chocolatey.org/) (Windows) to install Sui. - - - - - -```bash -brew install sui -``` - - - - - -```shell -choco install sui -``` - -Find more [versions of Sui for Windows](https://community.chocolatey.org/packages/sui) on the Chocolatey community website. - - - - - -## Install from binaries {#install-binaries} - -Each Sui release provides a set of binaries for several operating systems. You can download these binaries from GitHub and use them to install Sui. - -1. Go to https://github.com/MystenLabs/sui. -1. In the right pane, find the **Releases** section. - - ![Sui releases in GitHub](./images/releases.png) -1. Click the release tagged **Latest** to open the release's page. -1. In the **Assets** section of the release, select the .tgz compressed file that corresponds to your operating system. -1. Double-click the downloaded file. If the file doesn't automatically expand, manually unzip the file. -1. Open the expanded folder and double-click the appropriate binary to install, beginning with sui-``-``: - - - sui-faucet-``-``: Local faucet to mint coins on local network. - - sui-indexer-``-``: An indexer for a local Sui network. - - sui-``-``: Main Sui binary. - - sui-node-``-``: Run a local node. - - sui-test-validator-``-``: Run test validators on a local network for development. - - sui-tool-``-``: Provides utilities for Sui. - - The Sui binary takes several minutes to download and install files, so make sure you allocate enough time for it to complete. Actual time to complete depends on your network connection and computer specifications. - - -### Confirm the installation {#confirm-the-installation} - -To confirm that Sui installed correctly, type `sui` and press Enter. You should see a message about the Sui version installed and help for using Sui commands. - -## Install from source - -Follow the instructions in this topic to install the Rust crates (packages) required to interact with Sui networks, including the Sui CLI. - -To install Sui from source, you first need to install its [prerequisites](#prerequisites) for your operating system. After installing the supporting technologies, you can install [Sui binaries from source](#install-sui-binaries-from-source). - -You can also download the [source code](./sui-environment) to have local access to files. - -## Prerequisites {#prerequisites} - -Your system needs the following prerequisites available to successfully install Sui. - -### Rust and Cargo {#rust-and-cargo} - -Sui requires Rust and Cargo (Rust's package manager) on all supported operating systems. The suggested method to install Rust is with `rustup` using cURL. - -Some other commands in the installation instructions also require cURL to run. If you can't run the cURL command to install Rust, see the instructions to install cURL for your operating system in the following section before you install Rust. - -Use the following command to install Rust and Cargo on macOS or Linux: - -```bash -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -``` - -If you use Windows 11, see information about using the [Rust installer](https://www.rust-lang.org/tools/install) on the Rust website. The installer checks for C++ build tools and prompts you to install them if necessary. Select the option that best defines your environment and follow the instructions in the install wizard. - -For additional installation options, see [Install Rust](https://www.rust-lang.org/tools/install). - -Sui uses the latest version of Cargo to build and manage dependencies. See the [Cargo installation](https://doc.rust-lang.org/cargo/getting-started/installation.html) page on the Rust website for more information. - -Use the following command to update Rust with `rustup`: - -```bash -rustup update stable -``` -### Additional prerequisites by operating system - -Select the appropriate tab to view the requirements for your system. - - - - - -The prerequisites needed for the Linux operating system include: - -- cURL -- Rust and Cargo -- Git CLI -- CMake -- GCC -- libssl-dev -- libclang-dev -- libpq-dev -- build-essential - -:::info - -The Linux instructions assume a distribution that uses the APT package manager. You might need to adjust the instructions to use other package managers. - -::: - -Install the prerequisites listed in this section. Use the following command to update `apt-get`: - -```bash -sudo apt-get update -``` - -#### All Linux prerequisites - -Reference the relevant sections that follow to install each prerequisite individually, or run the following to install them all at once: - - - -#### cURL {#curl} - -Install cURL with the following command: - -```bash -sudo apt-get install curl -``` - -Verify that cURL installed correctly with the following command: - -```bash -curl --version -``` - -#### Git CLI {#git-cli} - -Run the following command to install Git, including the [Git CLI](https://cli.github.com/): - -```bash -sudo apt-get install git-all -``` - -For more information, see [Install Git on Linux](https://github.com/git-guides/install-git#install-git-on-linux) on the GitHub website. - -#### CMake {#cmake} - -Use the following command to install CMake. - -```bash -sudo apt-get install cmake -``` - -To customize the installation, see [Installing CMake](https://cmake.org/install/) on the CMake website. - -#### GCC {#gcc} - -Use the following command to install the GNU Compiler Collection, `gcc`: - -```bash -sudo apt-get install gcc -``` - -#### libssl-dev {#libssl-dev} - -Use the following command to install `libssl-dev`: - -```bash -sudo apt-get install libssl-dev -``` - -If the version of Linux you use doesn't support `libssl-dev`, find an equivalent package for it on the [ROS Index](https://index.ros.org/d/libssl-dev/). - -(Optional) If you have OpenSSL you might also need to also install `pkg-config`: - -```bash -sudo apt-get install pkg-config -``` - -#### libclang-dev {#libclang-dev} - -Use the following command to install `libclang-dev`: - -```bash -sudo apt-get install libclang-dev -``` - -If the version of Linux you use doesn't support `libclang-dev`, find an equivalent package for it on the [ROS Index](https://index.ros.org/d/libclang-dev/). - -#### libpq-dev {#libpq-dev} - -Use the following command to install `libpq-dev`: - -```bash -sudo apt-get install libpq-dev -``` - -If the version of Linux you use doesn't support `libpq-dev`, find an equivalent package for it on the [ROS Index](https://index.ros.org/d/libpq-dev/). - -#### build-essential {#build-essential} - -Use the following command to install `build-essential`: - -```bash -sudo apt-get install build-essential -``` - - - - - -The prerequisites needed for the macOS operating system include: - -- Rust and Cargo -- Homebrew -- cURL -- CMake -- libpq -- Git CLI - -macOS includes a version of cURL you can use to install Homebrew. Use Homebrew to install other tools, including a newer version of cURL. - -#### Homebrew {#brew} - -Use the following command to install [Homebrew](https://brew.sh/): - -```bash -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -``` - -:::info - -If you used the commands in the [Install using Homebrew](#install-homebrew) section, you do not need to install anything else. - -::: - -#### All macOS prerequisites - -With Homebrew installed, you can install individual prerequisites from the following sections or install them all at once with this command: - - - - -#### cURL {#curl-1} - -Use the following command to update the default [cURL](https://curl.se) on macOS: - -```bash -brew install curl -``` - -#### CMake {#cmake-1} - -Use the following command to install CMake: - -```bash -brew install cmake -``` - -To customize the installation, see [Installing CMake](https://cmake.org/install/) on the CMake website. - -#### libpq {#libpq-1} -Use the following command to install libpq: -```bash -brew install libpq -``` - -#### Git CLI {#git-cli-1} - -Use the following command to install Git: - -```bash -brew install git -``` - -After installing Git, download and install the [Git command line interface](https://git-scm.com/download/). - - - - - -The prerequisites needed for the Windows 11 operating system include: - -- cURL -- Rust and Cargo -- Git CLI -- CMake -- C++ build tools -- LLVM compiler - -#### cURL {#curl-2} - -Windows 11 ships with a Microsoft version of [cURL](https://curl.se/windows/microsoft.html) already installed. If you want to use the curl project version instead, download and install it from [https://curl.se/windows/](https://curl.se/windows/). - -#### Git CLI {#git-cli-2} - -Download and install the [Git command line interface](https://git-scm.com/download/). - -#### CMake {#cmake-2} - -Download and install [CMake](https://cmake.org/download/) from the CMake website. - -#### Protocol Buffers {#protocol-buffers} - -Download [Protocol Buffers](https://github.com/protocolbuffers/protobuf/releases) (protoc-xx.x-win32.zip or protoc-xx.x-win64.zip) and add the \bin directory to your Windows PATH environment variable. - -#### Additional tools for Windows {#additional-tools-windows} - -Sui requires the following additional tools on computers running Windows. - -- For Windows on ARM64 only - [Visual Studio 2022 Preview](https://visualstudio.microsoft.com/vs/preview/). -- [C++ build tools](https://visualstudio.microsoft.com/downloads/) is required to [install Rust](#rust-and-cargo). -- The [LLVM Compiler Infrastructure](https://releases.llvm.org/). Look for a file with a name similar to LLVM-15.0.7-win64.exe for 64-bit Windows, or LLVM-15.0.7-win32.exe for 32-bit Windows. - -**Known issue** - The `sui console` command does not work in PowerShell. - - - - - -## Install Sui binaries from source {#install-sui-binaries-from-source} - -Run the following command to install Sui binaries from the `testnet` branch: - -```shell -cargo install --locked --git https://github.com/MystenLabs/sui.git --branch testnet sui -``` - -The install process can take a while to complete. You can monitor installation progress in the terminal. If you encounter an error, make sure to install the latest version of all prerequisites and then try the command again. - -To update to the latest stable version of Rust: - -```shell -rustup update stable -``` - -The command installs Sui components in the `~/.cargo/bin` folder. - -## Upgrade Sui binaries - -If you previously installed the Sui binaries, you can update them to the most recent release with the same command you used to install them: - -```shell -cargo install --locked --git https://github.com/MystenLabs/sui.git --branch testnet sui -``` - -## Next steps {#next-steps} - -Now that you have Sui installed, it's time to start developing. Check out the following topics to start working with Sui: - -- Read about the [Sui CLI](/references/cli.mdx), the most straightforward way to start exploring Sui networks. -- [Learn about the available networks](./connect.mdx) and connect to one. -- [Get some coins](./get-coins.mdx) on a development network. -- [Build your first dApp](../first-app.mdx) to start your on-chain journey. diff --git a/docs/content/guides/developer/iota-101.mdx b/docs/content/guides/developer/iota-101.mdx new file mode 100644 index 00000000000..6e862eda157 --- /dev/null +++ b/docs/content/guides/developer/iota-101.mdx @@ -0,0 +1,37 @@ +--- +title: Iota 101 +description: Collection of core Iota concepts that developers use to create objects and interact with them on the Iota blockchain. +--- + +In many education systems, 101-level classes are those that teach core competencies to build a foundation for the more advanced topics that are to come. The topics in this section provide the same experience for the Iota blockchain. They examine the core Iota development concepts that you use to build apps on Iota. As you start developing more advanced solutions, knowledge of these topics provides a good base for understanding the more advanced concepts you will employ. + +## Creating coins and NFTs on Iota + +Everything on the Iota blockchain is an object. These topics use code examples to demonstrate how to create these specific types of objects. + +- [Create Coins](./iota-101/create-coin.mdx) +- [Create NFTs](./iota-101/create-nft.mdx) + +## Working with PTBs + +You can create programmable transaction blocks (PTBs) on Iota to perform multiple commands in a single transaction. The Working with PTBs topics demonstrate how to build efficient PTBs using the Iota TypeScript SDK. + +Go to [Working with PTBs](./iota-101/working-with-ptbs.mdx). + +## Using Events + +You can emit events from your published packages on the Iota network. Using Events demonstrates how to emit events from your on-chain packages and monitor the activity of other objects emitting events. + +Go to [Using Events](./iota-101/using-events.mdx). + +## Shared versus Owned Objects + +Objects on Iota, unlike other blockchains, can be owned as well as shared. You can create transactions that leverage either type or both. Shared versus Owned Objects examines the differences and what considerations you should account for when deciding how to structure your on-chain app. + +Go to [Shared versus Owned Objects](./iota-101/shared-owned.mdx). + +## Access On-Chain Time + +Iota provides a `Clock` module you can use to get network-based time. Access On-Chain Time examines the `Clock` module and the behavior of the available methods that affect transaction processing speed and the temporal exactness of the data you receive. + +Go to [Access On-Chain Time](./iota-101/access-time.mdx). \ No newline at end of file diff --git a/docs/content/guides/developer/iota-101/access-time.mdx b/docs/content/guides/developer/iota-101/access-time.mdx new file mode 100644 index 00000000000..83150381329 --- /dev/null +++ b/docs/content/guides/developer/iota-101/access-time.mdx @@ -0,0 +1,121 @@ +--- +title: Access On-Chain Time +description: Access network-based time for your transactions. Iota provides a Clock module to capture near-real time or epoch time in your Iota packages. +--- + +You have options when needing to access network-based time for your transactions. If you need a near real-time measurement (within a few seconds), use the immutable reference of time provided by the `Clock` module in Move. The reference value from this module updates with every network checkpoint. If you don't need as current a time slice, use the `epoch_timestamp_ms` function to capture the precise moment the current epoch started. + +## The iota::clock::Clock module + +To access a prompt timestamp, you must pass a read-only reference of `iota::clock::Clock` as an entry function parameter in your transactions. An instance of `Clock` is provided at address `0x6`, no new instances can be created. + +Extract a unix timestamp in milliseconds from an instance of `Clock` using + +```move +module iota::clock { + public fun timestamp_ms(clock: &Clock): u64; +} +``` + +The example below demonstrates an entry function that emits an event containing a timestamp from the `Clock`: + +```move +module example::clock { + use iota::clock::{Self, Clock}; + use iota::event; + + struct TimeEvent has copy, drop, store { + timestamp_ms: u64 + } + + entry fun access(clock: &Clock) { + event::emit(TimeEvent { + timestamp_ms: clock::timestamp_ms(clock), + }); + } +} +``` + +A call to the previous entry function takes the following form, passing `0x6` as the address for the `Clock` parameter: + +```shell +iota client call --package --module 'clock' --function 'access' --args '0x6' --gas-budget +``` + +Expect the `Clock` timestamp to change **every 2 to 3 seconds**, at the rate the network commits checkpoints. + +Successive calls to `iota::clock::timestamp_ms` in the same transaction always produce the same result (transactions are considered to take effect instantly), but timestamps from `Clock` are otherwise monotonic across transactions that touch the same shared objects: Successive transactions seeing a greater or equal timestamp to their predecessors. + +Any transaction that requires access to a `Clock` must go through consensus because the only available instance is a shared object. As a result, this technique is not suitable for transactions that must use the single-owner fastpath (see Epoch timestamps for a single-owner-compatible source of timestamps). + +Transactions that use the clock must accept it as an **immutable reference** (not a mutable reference or value). This prevents contention, as transactions that access the `Clock` can only read it, so do not need to be sequenced relative to each other. Validators refuse to sign transactions that do not meet this requirement and packages that include entry functions that accept a `Clock` or `&mut Clock` fail to publish. + +The following functions test `Clock`-dependent code by manually creating a `Clock` object and manipulating its timestamp. This is possible only in test code: + +```move +module iota::clock { + #[test_only] + public fun create_for_testing(ctx: &mut TxContext); + + #[test_only] + public fun share_for_testing(clock: Clock); + + #[test_only] + public fun increment_for_testing(clock: &mut Clock, tick: u64); + + #[test_only] + public fun set_for_testing(clock: &mut Clock, timestamp_ms: u64); + + #[test_only] + public fun destroy_for_testing(clock: Clock); +} +``` + +The next example presents a simple test that creates a Clock, increments it, and then checks its value: + +```move +module example::clock_tests { + use iota::clock::{Self, Clock}; + use iota::tx_context; + + #[test] + fun creating_a_clock_and_incrementing_it() { + let ctx = tx_context::dummy(); + let clock = clock::create_for_testing(&mut ctx); + + clock::increment_for_testing(&mut clock, 42); + assert!(clock::timestamp_ms(&clock) == 42, 1); + + clock::set_for_testing(&mut clock, 50); + assert!(clock::timestamp_ms(&clock) == 50, 1); + + clock::destroy_for_testing(clock); + } +} +``` + +## Epoch timestamps + +You can use the following function to access the timestamp for the start of the current epoch for all transactions (including ones that do not go through consensus): + +```move +module iota::tx_context { + public fun epoch_timestamp_ms(ctx: &TxContext): u64; +} +``` + +The preceding function returns the point in time when the current epoch started, as a millisecond granularity unix timestamp in a u64. This value changes roughly **once every 24 hours**, when the epoch changes. + +Tests based on `iota::test_scenario` can use `later_epoch` (following code), to exercise time-sensitive code that uses `epoch_timestamp_ms` (previous code): + +```move +module iota::test_scenario { + public fun later_epoch( + scenario: &mut Scenario, + delta_ms: u64, + sender: address, + ): TransactionEffects; +} +``` + +`later_epoch` behaves like `iota::test_scenario::next_epoch` (finishes the current transaction and epoch in the test scenario), but also increments the timestamp by `delta_ms` milliseconds to simulate the progress of time. diff --git a/docs/content/guides/developer/sui-101/building-ptb.mdx b/docs/content/guides/developer/iota-101/building-ptb.mdx similarity index 81% rename from docs/content/guides/developer/sui-101/building-ptb.mdx rename to docs/content/guides/developer/iota-101/building-ptb.mdx index 15045a281dd..0e4122f6b33 100644 --- a/docs/content/guides/developer/sui-101/building-ptb.mdx +++ b/docs/content/guides/developer/iota-101/building-ptb.mdx @@ -1,14 +1,14 @@ --- title: Building Programmable Transaction Blocks -description: Using the Sui TypeScript SDK, you can create programmable transaction blocks to perform multiple commands in a single transaction. +description: Using the Iota TypeScript SDK, you can create programmable transaction blocks to perform multiple commands in a single transaction. --- -This guide explores creating a programmable transaction block (PTB) on Sui using the TypeScript SDK. For an overview of what a PTB is, see [Programmable Transaction Blocks](/concepts/transactions/prog-txn-blocks.mdx) in the Concepts section. If you don't already have the Sui TypeScript SDK, follow the [install instructions](https://sdk.mystenlabs.com/typescript/install) on the Sui TypeScript SDK site. +This guide explores creating a programmable transaction block (PTB) on Iota using the TypeScript SDK. For an overview of what a PTB is, see [Programmable Transaction Blocks](/concepts/transactions/prog-txn-blocks.mdx) in the Concepts section. If you don't already have the Iota TypeScript SDK, follow the [install instructions](https://sdk.mystenlabs.com/typescript/install) on the Iota TypeScript SDK site. -This example starts by constructing a PTB to send Sui. If you are familiar with the legacy Sui transaction types, this is similar to a `paySui` transaction. To construct transactions, import the `TransactionBlock` class, and construct it: +This example starts by constructing a PTB to send Iota. If you are familiar with the legacy Iota transaction types, this is similar to a `payIota` transaction. To construct transactions, import the `TransactionBlock` class, and construct it: ```ts -import { TransactionBlock } from "@mysten/sui.js"; +import { TransactionBlock } from "@iota/iota.js"; const txb = new TransactionBlock(); ``` @@ -20,7 +20,7 @@ Using this, you can then add transactions to this PTB. const [coin] = txb.splitCoins(txb.gas, [txb.pure(100)]); // Transfer the split coin to a specific address. -txb.transferObjects([coin], txb.pure("0xSomeSuiAddress")); +txb.transferObjects([coin], txb.pure("0xSomeIotaAddress")); ``` You can attach multiple transaction commands of the same type to a PTB as well. For example, to get a list of transfers, and iterate over them to transfer coins to each of them: @@ -31,7 +31,7 @@ interface Transfer { amount: number; } -// Procure a list of some Sui transfers to make: +// Procure a list of some Iota transfers to make: const transfers: Transfer[] = getTransfers(); const txb = new TransactionBlock(); @@ -56,7 +56,7 @@ signer.signAndExecuteTransactionBlock({ transactionBlock: txb }); ## Constructing inputs -Inputs are how you provide external values to PTBs. For example, defining an amount of Sui to transfer, or which object to pass into a Move call, or a shared object. +Inputs are how you provide external values to PTBs. For example, defining an amount of Iota to transfer, or which object to pass into a Move call, or a shared object. There are currently two ways to define inputs: @@ -67,7 +67,7 @@ There are currently two ways to define inputs: ## Available transactions -Sui supports following transaction commands: +Iota supports following transaction commands: - `txb.splitCoins(coin, amounts)`: Creates new coins with the defined amounts, split from the provided coin. Returns the coins so that it can be used in subsequent transactions. - Example: `txb.splitCoins(txb.gas, [txb.pure(100), txb.pure(200)])` @@ -75,7 +75,7 @@ Sui supports following transaction commands: - Example: `txb.mergeCoins(txb.object(coin1), [txb.object(coin2), txb.object(coin3)])` - `txb.transferObjects(objects, address)`: Transfers a list of objects to the specified address. - Example: `txb.transferObjects([txb.object(thing1), txb.object(thing2)], txb.pure(myAddress))` -- `txb.moveCall({ target, arguments, typeArguments })`: Executes a Move call. Returns whatever the Sui Move call returns. +- `txb.moveCall({ target, arguments, typeArguments })`: Executes a Move call. Returns whatever the Iota Move call returns. - Example: `txb.moveCall({ target: '0x2::devnet_nft::mint', arguments: [txb.pure(name), txb.pure(description), txb.pure(image)] })` - `txb.makeMoveVec({ type, objects })`: Constructs a vector of objects that can be passed into a moveCall. This is required as there's no other way to define a vector as an input. - Example: `txb.makeMoveVec({ objects: [txb.object(id1), txb.object(id2)] })` @@ -106,7 +106,7 @@ txb.transferObjects([mintMany[0], mintMany[1]], txb.pure(address)); ## Use the gas coin -With PTBs, you can use the gas payment coin to construct coins with a set balance using `splitCoin`. This is useful for Sui payments, and avoids the need for up-front coin selection. You can use `txb.gas` to access the gas coin in a PTB, and it is valid as input for any arguments; with the exception of `transferObjects`, `txb.gas` must be used by-reference. Practically speaking, this means you can also add to the gas coin with `mergeCoins` or borrow it for Move functions with `moveCall`. +With PTBs, you can use the gas payment coin to construct coins with a set balance using `splitCoin`. This is useful for Iota payments, and avoids the need for up-front coin selection. You can use `txb.gas` to access the gas coin in a PTB, and it is valid as input for any arguments; with the exception of `transferObjects`, `txb.gas` must be used by-reference. Practically speaking, this means you can also add to the gas coin with `mergeCoins` or borrow it for Move functions with `moveCall`. You can also transfer the gas coin using `transferObjects`, in the event that you want to transfer all of your coin balance to another address. @@ -142,7 +142,7 @@ const txb = TransactionBlock.from(bytes); In the event that you want to build a PTB offline (as in with no `provider` required), you need to fully define all of your input values, and gas configuration (see the following example). For pure values, you can provide a `Uint8Array` which is used directly in the transaction. For objects, you can use the `Inputs` helper to construct an object reference. ```ts -import { Inputs } from "@mysten/sui.js"; +import { Inputs } from "@iota/iota.js"; // For pure values: txb.pure(pureValueAsBytes); @@ -174,7 +174,7 @@ By default, the gas budget is automatically derived by executing a dry-run of th :::info -The gas budget is represented in Sui, and should take the gas price of the PTB into account. +The gas budget is represented in Iota, and should take the gas price of the PTB into account. ::: @@ -198,7 +198,7 @@ txb.setGasPayment([coin1, coin2]); The Wallet Standard interface has been updated to support the `TransactionBlock` kind directly. All `signTransaction` and `signAndExecuteTransaction` calls from dApps into wallets is expected to provide a `TransactionBlock` class. This PTB class can then be serialized and sent to your wallet for execution. -To serialize a PTB for sending to a wallet, Sui recommends using the `txb.serialize()` function, which returns an opaque string representation of the PTB that can be passed from the wallet standard dApp context to your wallet. This can then be converted back into a `TransactionBlock` using `TransactionBlock.from()`. +To serialize a PTB for sending to a wallet, Iota recommends using the `txb.serialize()` function, which returns an opaque string representation of the PTB that can be passed from the wallet standard dApp context to your wallet. This can then be converted back into a `TransactionBlock` using `TransactionBlock.from()`. :::tip diff --git a/docs/content/guides/developer/iota-101/coin-mgt.mdx b/docs/content/guides/developer/iota-101/coin-mgt.mdx new file mode 100644 index 00000000000..14ce3a1dfe6 --- /dev/null +++ b/docs/content/guides/developer/iota-101/coin-mgt.mdx @@ -0,0 +1,40 @@ +--- +title: Coin Management +description: Because Iota uses Coins as owned objects for transactions, you need to explicitly manage them in your programmable transaction block development. +--- + +A key concept when programming on Iota is that of owned objects. Address-owned objects are important in that they allow for highly parallelizable transactions. And they also logically map to assets or resources that someone exclusively owns. Coins are a typical case of owned object usage, with cash being a real-life reference. The owned objects paradigm, however, and particularly as related to coins, is somewhat of a divergence from other blockchains which have a concept of balance. In other words, in other systems, especially account based systems, coins are held in a single location (field) which can be thought of as a balance in a bank account. + +Because Iota uses owned objects instead of a balance, it is common to own a number of coins, at times even a significant number of them. Some scenarios necessitate merging some or all of those coins into a single object. At times, merging coins together might even be required because the amount necessary to execute a transaction is more than any single coin the sender owns, thus making merging an inevitable step. + +## SDK usage + +The Iota SDKs ([TypeScript](https://sdk.mystenlabs.com/typescript) and [Rust](/references/rust-sdk.mdx)) manage coins on your behalf, removing the overhead of having to deal with coin management manually. The SDKs attempt to merge coins whenever possible and assume that transactions are executed in sequence. That's a reasonable assumption with wallet-based transactions and for common scenarios in general. Iota recommends relying on this feature if you do not have a need for heavy parallel or concurrent execution. + +## Gas Smashing + +When executing a transaction Iota allows you to provide a number of coins as payment. In other words, the payment can be a vector of coins rather than a single coin. That feature, known as gas smashing, performs merging of coins automatically, and presents the PTBs you write with a single gas coin that can be used for other purposes besides just gas. + +Basically, you can provide as many coins as you want (with a max limit defined in the protocol configuration) and have all of them merged (smashed) into the first coin provided as payment. That coin, minus the gas budget, is then available inside the transaction and can be used in any command. If the coin is unused it is returned to the user. + +Gas smashing is an important feature - and a key concept to understand - to have for the optimal management of coins. See [Gas Smashing](/concepts/transactions/gas-smashing.mdx) for more details. + +## Generic coins + +Gas smashing works well for `Coin` objects, which is the only coin type that can be used for gas payment. + +Any other coin type requires explicit management from users. PTBs offer a `mergeCoins` command that you can use to combine multiple coins into a single one. And a `splitCoins` as the complementary operation to break them up. + +From a cost perspective, those are very cheap transactions, however they require a user to be aware of their coin distribution and their own needs. + +## Concurrency + +Merging coins, and particularly `Coin`, into a single coin or a very small number of coins might prove problematic in scenarios where heavy or high concurrency is required. + +If you merge all `Coin` into a single one, you would need to sequentially submit every transaction. The coin - being an owned object - would have to be provided with a version and it would be locked by the system when signing a transaction, effectively making it impossible to use it in any other transaction until the one that locked it was executed. Moreover, an attempt to sign multiple transactions with the same coin might result in equivocation and the coin being unusable and locked until the end of the epoch. + +So when you require heavy concurrency, you should first split a coin into as many coins as the number of transactions to execute concurrently. Alternatively, you could provide multiple and different coins (gas smashing) to the different transactions. It is critically important that the set of coins you use in the different transactions has no intersection at all. + +The possible pitfalls in dealing with heavy concurrency are many. Concurrency in transaction execution is not the only performance bottleneck. In creating and submitting a transaction, several round trips with a Full node might be required to discover and fetch the right objects, and to dry run a transaction. Those round trips might affect performance significantly. + +Concurrency is a difficult subject and is beyond the scope of this documentation. You must take maximum care when dealing with coin management in the face of concurrency, and the right strategy is often tied to the specific scenario, rather than universally available. diff --git a/docs/content/guides/developer/iota-101/create-coin.mdx b/docs/content/guides/developer/iota-101/create-coin.mdx new file mode 100644 index 00000000000..3db41fa906e --- /dev/null +++ b/docs/content/guides/developer/iota-101/create-coin.mdx @@ -0,0 +1,100 @@ +--- +title: Create Coins and Tokens +--- + +Coins and tokens on Iota are similar. In practice, the terms are used interchangeably, but there are some differences in their implementation. You can learn about these differences in the respective standard documentation, [Closed-Loop Token](../../../standards/closed-loop-token.mdx) and [Coin](../../../standards/coin.mdx). + +Publishing a coin on Iota is nearly as straightforward as publishing a new type. The main difference is the requirement of a [one-time witness](/concepts/iota-move-concepts/one-time-witness.mdx) when creating a coin. + +```move +module examples::mycoin { + use std::option; + use iota::coin::{Self, Coin, TreasuryCap}; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; + + /// The type identifier of coin. The coin will have a type + /// tag of kind: `Coin` + /// Make sure that the name of the type matches the module's name. + struct MYCOIN has drop {} + + /// Module initializer is called once on module publish. A treasury + /// cap is sent to the publisher, who then controls minting and burning + fun init(witness: MYCOIN, ctx: &mut TxContext) { + let (treasury, metadata) = coin::create_currency(witness, 6, b"MYCOIN", b"", b"", option::none(), ctx); + transfer::public_freeze_object(metadata); + transfer::public_transfer(treasury, tx_context::sender(ctx)) + } +} +``` + +The `Coin` is a generic implementation of a coin on Iota. Access to the `TreasuryCap` provides control over the minting and burning of coins. Further transactions can be sent directly to the `iota::coin::Coin` with `TreasuryCap` object as authorization. + +Extending the example further, add a `mint` function to the module. Use the `mint` function of the `Coin` module to create (mint) a coin and then transfer it to an address. + +```move +public fun mint( + treasury_cap: &mut TreasuryCap, + amount: u64, + recipient: address, + ctx: &mut TxContext, +) { + let coin = coin::mint(treasury_cap, amount, ctx); + transfer::public_transfer(coin, recipient) +} +``` + +### Iota CLI + +If you published the previous example to a Iota network, you can use the `iota client call` command to mint coins and deliver them to the address you provide. See [Iota CLI](../../../references/cli.mdx) for more information on the command line interface. + +```shell +iota client call --function mint --module mycoin --package --args --gas-budget +``` + +If the call is successful your console displays the result, which includes a **Balance Changes** section with the following information included: + +```shell +... + +Owner: Account Address ( ) +CoinType: ::mycoin::MYCOIN +Amount: + +... +``` + +## DenyList + +The Iota framework provides a `DenyList` singleton, shared object that the bearer of a `DenyCap` can access to specify a list of addresses that are unable to use a Iota core type. The initial use case for `DenyList`, however, focuses on limiting access to coins of a specified type. This is useful, for example, when creating a regulated coin on Iota that requires the ability to block certain addresses from using it as inputs to transactions. Regulated coins on Iota satisfy any regulations that require the ability to prevent known bad actors from having access to those coins. + +:::info + +The `DenyList` object is a system object that has the address `0x403`. You cannot create it yourself. + +::: + +## Create regulated coin + +If you need the ability to deny specific addresses from having access to your coin, you can use the `create_regulated_currency` function (instead of `create_currency`) to create it. + +Behind the scenes, `create_regulated_currency` uses the `create_currency` function to create the coin, but also produces a `DenyCap` object that allows its bearer to control access to the coin's deny list in a `DenyList` object. Consequently, the way to create a coin using `create_regulated_currency` is similar to the previous example, with the addition of a transfer of the `DenyCap` object to the module publisher. + +## Create tokens + +Tokens reuse the `TreasuryCap` defined in the `iota::coin` module and therefore have the same initialization process. The `coin::create_currency` function guarantees the uniqueness of the `TreasuryCap` and forces the creation of a `CoinMetadata` object. + +Coin-like functions perform the minting and burning of tokens. Both require the `TreasuryCap`: + +- `token::mint` - mint a token +- `token::burn` - burn a token + +See [Closed-Loop Token](../../../standards/closed-loop-token.mdx) standard for complete details of working with tokens. + +## Examples + +See the following topics for examples of some common use cases for coin and token creation. + +- [Regulated Coin and Deny List](./create-coin/regulated.mdx): Create a regulated coin and add or remove names from the deny list. +- [Loyalty Token](./create-coin/loyalty.mdx): Create a token to reward user loyalty. +- [In-Game Token](./create-coin/in-game-token.mdx): Create tokens that can be used only within a mobile game. diff --git a/docs/content/guides/developer/iota-101/create-coin/in-game-token.mdx b/docs/content/guides/developer/iota-101/create-coin/in-game-token.mdx new file mode 100644 index 00000000000..5174fe7cf36 --- /dev/null +++ b/docs/content/guides/developer/iota-101/create-coin/in-game-token.mdx @@ -0,0 +1,140 @@ +--- +title: In-Game Currency +--- + +Using the Iota [Closed-Loop Token](../../../../standards/closed-loop-token.mdx) standard, you can create in-game currency (such as gems or diamonds in mobile games) that you can grant to players for their actions or make available to purchase. You mint the tokens on Iota, but players can only use the tokens within the economy of the game itself. These types of tokens are usually not transferrable and you would typically mint them in predefined amounts to maintain scarcity and game balance. + +The following example creates an in-game currency called a GEM, which represents a certain number of IOTA. In the example, the user can buy fungible GEMs using IOTA, which can then be used as currency within the game. Use the code comments to follow the logic of the example. + +```move title="iota/examples/move/token/sources/gems.move" +/// This is a simple example of a permissionless module for an imaginary game +/// that sells swords for Gems. Gems are an in-game currency that can be bought +/// with IOTA. +module examples::sword { + use iota::tx_context::TxContext; + use iota::object::{Self, UID}; + + use iota::token::{Self, Token, ActionRequest}; + use examples::gem::GEM; + + /// Trying to purchase a sword with an incorrect amount. + const EWrongAmount: u64 = 0; + + /// The price of a sword in Gems. + const SWORD_PRICE: u64 = 10; + + /// A game item that can be purchased with Gems. + struct Sword has key, store { id: UID } + + /// Purchase a sword with Gems. + public fun buy_sword( + gems: Token, ctx: &mut TxContext + ): (Sword, ActionRequest) { + assert!(SWORD_PRICE == token::value(&gems), EWrongAmount); + ( + Sword { id: object::new(ctx) }, + token::spend(gems, ctx) + ) + } +} + +/// Module that defines the in-game currency: GEMs which can be purchased with +/// IOTA and used to buy swords (in the `sword` module). +module examples::gem { + use std::option::none; + use std::string::{Self, String}; + use iota::iota::IOTA; + use iota::transfer; + use iota::object::{Self, UID}; + use iota::balance::{Self, Balance}; + use iota::tx_context::{sender, TxContext}; + use iota::coin::{Self, Coin, TreasuryCap}; + + use iota::token::{Self, Token, ActionRequest}; + + /// Trying to purchase Gems with an unexpected amount. + const EUnknownAmount: u64 = 0; + + /// 10 IOTA is the price of a small bundle of Gems. + const SMALL_BUNDLE: u64 = 10_000_000_000; + const SMALL_AMOUNT: u64 = 100; + + /// 100 IOTA is the price of a medium bundle of Gems. + const MEDIUM_BUNDLE: u64 = 100_000_000_000; + const MEDIUM_AMOUNT: u64 = 5_000; + + /// 1000 IOTA is the price of a large bundle of Gems. + /// This is the best deal. + const LARGE_BUNDLE: u64 = 1_000_000_000_000; + const LARGE_AMOUNT: u64 = 100_000; + + #[allow(lint(coin_field))] + /// Gems can be purchased through the `Store`. + struct GemStore has key { + id: UID, + /// Profits from selling Gems. + profits: Balance, + /// The Treasury Cap for the in-game currency. + gem_treasury: TreasuryCap, + } + + /// The OTW to create the in-game currency. + struct GEM has drop {} + + // In the module initializer we create the in-game currency and define the + // rules for different types of actions. + fun init(otw: GEM, ctx: &mut TxContext) { + let (treasury_cap, coin_metadata) = coin::create_currency( + otw, 0, b"GEM", b"Capy Gems", // otw, decimal, symbol, name + b"In-game currency for Capy Miners", none(), // description, url + ctx + ); + + // create a `TokenPolicy` for GEMs + let (policy, cap) = token::new_policy(&treasury_cap, ctx); + + token::allow(&mut policy, &cap, buy_action(), ctx); + token::allow(&mut policy, &cap, token::spend_action(), ctx); + + // create and share the GemStore + transfer::share_object(GemStore { + id: object::new(ctx), + gem_treasury: treasury_cap, + profits: balance::zero() + }); + + // deal with `TokenPolicy`, `CoinMetadata` and `TokenPolicyCap` + transfer::public_freeze_object(coin_metadata); + transfer::public_transfer(cap, sender(ctx)); + token::share_policy(policy); + } + + /// Purchase Gems from the GemStore. Very silly value matching against module + /// constants... + public fun buy_gems( + self: &mut GemStore, payment: Coin, ctx: &mut TxContext + ): (Token, ActionRequest) { + let amount = coin::value(&payment); + let purchased = if (amount == SMALL_BUNDLE) { + SMALL_AMOUNT + } else if (amount == MEDIUM_BUNDLE) { + MEDIUM_AMOUNT + } else if (amount == LARGE_BUNDLE) { + LARGE_AMOUNT + } else { + abort EUnknownAmount + }; + + coin::put(&mut self.profits, payment); + + // create custom request and mint some Gems + let gems = token::mint(&mut self.gem_treasury, purchased, ctx); + let req = token::new_request(buy_action(), purchased, none(), none(), ctx); + + (gems, req) + } + + /// The name of the `buy` action in the `GemStore`. + public fun buy_action(): String { string::utf8(b"buy") } +} +``` \ No newline at end of file diff --git a/docs/content/guides/developer/sui-101/create-coin/loyalty.mdx b/docs/content/guides/developer/iota-101/create-coin/loyalty.mdx similarity index 88% rename from docs/content/guides/developer/sui-101/create-coin/loyalty.mdx rename to docs/content/guides/developer/iota-101/create-coin/loyalty.mdx index 6912243e31f..dee51744f37 100644 --- a/docs/content/guides/developer/sui-101/create-coin/loyalty.mdx +++ b/docs/content/guides/developer/iota-101/create-coin/loyalty.mdx @@ -2,7 +2,7 @@ title: Loyalty Tokens --- -Using the Sui [Closed-Loop Token](../../../../standards/closed-loop-token.mdx) standard, you can create tokens that are valid only for a specific service, like an airline that wants to grant tokens to frequent flyers to purchase tickets or upgrades. +Using the Iota [Closed-Loop Token](../../../../standards/closed-loop-token.mdx) standard, you can create tokens that are valid only for a specific service, like an airline that wants to grant tokens to frequent flyers to purchase tickets or upgrades. The following example demonstrates the creation of a loyalty token that bearers can use to make purchases in a digital gift shop. Use the comments in the code to follow the logic of the example. @@ -16,12 +16,12 @@ The following example demonstrates the creation of a loyalty token that bearers /// - spend - spend the token in the shop module examples::loyalty { use std::option; - use sui::transfer; - use sui::object::{Self, UID}; - use sui::coin::{Self, TreasuryCap}; - use sui::tx_context::{Self, TxContext}; + use iota::transfer; + use iota::object::{Self, UID}; + use iota::coin::{Self, TreasuryCap}; + use iota::tx_context::{Self, TxContext}; - use sui::token::{Self, ActionRequest, Token}; + use iota::token::{Self, ActionRequest, Token}; /// Token amount does not match the `GIFT_PRICE`. const EIncorrectAmount: u64 = 0; diff --git a/docs/content/guides/developer/iota-101/create-coin/regulated.mdx b/docs/content/guides/developer/iota-101/create-coin/regulated.mdx new file mode 100644 index 00000000000..98abd4bfd22 --- /dev/null +++ b/docs/content/guides/developer/iota-101/create-coin/regulated.mdx @@ -0,0 +1,130 @@ +--- +title: Regulated Coin and Deny List +description: You can create regulated coins on Iota, such as stablecoins. These coins are similar to other coins like IOTA, but include the ability to control access to the coin using a deny list. +--- + +The Iota [Coin](../../../../standards/coin.mdx) standard provides a `create_regulated_currency` function to create coins. This function is different than `create_currency` in that it generates a coin that you can block certain addresses from being able to use those coins in transactions. This ability is a requirement for assets like stablecoins. + +Behind the scenes, `create_regulated_currency` uses the `create_currency` function to create the coin, but also produces a `DenyCap` object that allows its bearer to control access to the coin's deny list in a `DenyList` object. Consequently, the way to create a coin using `create_regulated_currency` is similar to the previous example, with the addition of a transfer of the `DenyCap` object to the module publisher. + +```move title="regcoin.move" +module examples::regcoin { + use std::option; + use iota::coin; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; + + struct REGCOIN has drop {} + + fun init(witness: REGCOIN, ctx: &mut TxContext) { + let (treasury, deny_cap, metadata) = coin::create_regulated_currency(witness, 6, b"REGCOIN", b"", b"", option::none(), ctx); + transfer::public_freeze_object(metadata); + transfer::public_transfer(treasury, tx_context::sender(ctx)); + transfer::public_transfer(deny_cap, tx_context::sender(ctx)) + } +} +``` + +When you deploy the previous module using `iota client publish`, the console responds with transaction effects, including the creation of the following objects: + +```shell +... + +Object Changes + +Created Objects: + + ObjectID: + Sender: + Owner: Immutable + ObjectType: 0x2::coin::CoinMetadata<::regcoin::REGCOIN> + Version: + Digest: + + ObjectID: + Sender: + Owner: Account Address ( + Digest: + + ObjectID: + Sender: + Owner: Immutable + ObjectType: 0x2::coin::RegulatedCoinMetadata<::regcoin::REGCOIN> + Version: + Digest: + + ObjectID: + Sender: + Owner: Account Address ( ::regcoin::REGCOIN> + Version: + Digest: + + + ObjectID: + Sender: + Owner: Account Address ( ::regcoin::REGCOIN> + Version: + Digest: + +... +``` + +As you might have noticed, the publish action creates a `RegulatedCoinMetadata` object along with the standard `CoinMetadata` object. You don't need to explicitly call the `freeze_object` on the `RegulatedCoinMetadata` object, however, because `create_regulated_currency` automatically performs this action. + +The output also shows the three objects that the publisher now owns: `UpgradeCap` for [package upgrades](../../../../concepts/iota-move-concepts/packages/upgrade.mdx), `TreasuryCap` for minting or burning coins, and the `DenyCap` for adding or removing addresses to or from the deny list for this coin. + +## DenyList + +The Iota framework provides a `DenyList` singleton, shared object that the bearer of a `DenyCap` can access to specify a list of addresses that are unable to use a Iota core type. The initial use case for `DenyList`, however, focuses on limiting access to coins of a specified type. This is useful, for example, when creating a regulated coin on Iota that requires the ability to block certain addresses from using it as inputs to transactions. Regulated coins on Iota satisfy any regulations that require the ability to prevent known bad actors from having access to those coins. + +:::info + +The `DenyList` object is a system object that has the address `0x403`. You cannot create it yourself. + +::: + + +### Manipulate deny list + +For the ability to manipulate the addresses assigned to the deny list for your coin, you must add a few functions to the previous example. + +```move +public fun add_addr_from_deny_list(denylist: &mut DenyList, denycap: &mut DenyCap, denyaddy: address, ctx: &mut TxContext){ + coin::deny_list_add(denylist, denycap, denyaddy, ctx ); +} + +public fun remove_addr_from_deny_list(denylist: &mut DenyList, denycap: &mut DenyCap, denyaddy: address, ctx: &mut TxContext){ + coin::deny_list_remove(denylist, denycap, denyaddy, ctx ); +} +``` + +To use these functions, you pass the `DenyList` object (`0x403`), your `DenyCap` object ID, and the address you want to either add or remove. Using the Iota CLI, you could use `iota client call` with the required information: + +```shell +iota client call --function add_addr_from_deny_list --module regcoin --package --args --gas-budget +Transaction Digest: +``` + +The console displays the response from the network, where you can verify the `DenyList` object is mutated. + +```shell +... + +MutatedObjects: + + ObjectID: 0x0...403 + Sender: + Owner: Shared + ObjectType: 0x2::deny_list::DenyList + Version: + Digest: + +... + +``` + +For all `Coin` functions available, see the Iota framework [`coin` module documentation](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/docs/iota-framework/coin.md). \ No newline at end of file diff --git a/docs/content/guides/developer/sui-101/create-nft.mdx b/docs/content/guides/developer/iota-101/create-nft.mdx similarity index 86% rename from docs/content/guides/developer/sui-101/create-nft.mdx rename to docs/content/guides/developer/iota-101/create-nft.mdx index e72efbf9b30..61dc77f5fe5 100644 --- a/docs/content/guides/developer/sui-101/create-nft.mdx +++ b/docs/content/guides/developer/iota-101/create-nft.mdx @@ -2,16 +2,16 @@ title: Create a Non-Fungible Token --- -On Sui, everything is an object. Moreover, in Sui, everything is a non-fungible token (NFT) as its objects are unique, non-fungible, and owned. So technically, a basic type publishing is enough to create a specific NFT. +On Iota, everything is an object. Moreover, in Iota, everything is a non-fungible token (NFT) as its objects are unique, non-fungible, and owned. So technically, a basic type publishing is enough to create a specific NFT. ```move module examples::devnet_nft { - use sui::url::{Self, Url}; + use iota::url::{Self, Url}; use std::string; - use sui::object::{Self, ID, UID}; - use sui::event; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; + use iota::object::{Self, ID, UID}; + use iota::event; + use iota::transfer; + use iota::tx_context::{Self, TxContext}; /// An example NFT that can be minted by anybody struct DevNetNFT has key, store { diff --git a/docs/content/guides/developer/sui-101/shared-owned.mdx b/docs/content/guides/developer/iota-101/shared-owned.mdx similarity index 91% rename from docs/content/guides/developer/sui-101/shared-owned.mdx rename to docs/content/guides/developer/iota-101/shared-owned.mdx index db643e70642..3dde8bd811c 100644 --- a/docs/content/guides/developer/sui-101/shared-owned.mdx +++ b/docs/content/guides/developer/iota-101/shared-owned.mdx @@ -1,9 +1,9 @@ --- title: Shared versus Owned Objects -description: On Sui, you can use shared objects, owned objects, or both in your transactions. Weigh the benefits of each to decide the best approach for your project. +description: On Iota, you can use shared objects, owned objects, or both in your transactions. Weigh the benefits of each to decide the best approach for your project. --- -Objects on Sui can be shared (accessible for reads and writes by any transaction) or owned (accessible for reads and writes by transactions signed by their owner). Many applications can be built using a solution that either uses shared objects or only owned objects, with trade-offs for each that need to be weighed. +Objects on Iota can be shared (accessible for reads and writes by any transaction) or owned (accessible for reads and writes by transactions signed by their owner). Many applications can be built using a solution that either uses shared objects or only owned objects, with trade-offs for each that need to be weighed. Transactions that use only owned objects benefit from very low latency to finality, because they do not need to go through consensus. On the other hand, the fact that only the owner of the object can access it complicates processes that need to work with objects owned by multiple parties, and access to very hot objects needs to be coordinated off-chain. @@ -13,14 +13,14 @@ Transactions that access multiple shared objects, or particularly popular object To summarize, applications that are extremely sensitive to latency or gas costs, that do not need to handle complex multi-party transactions, or that already require an off-chain service could benefit from a design that only uses owned objects. Applications that require coordination between multiple parties will likely benefit from using shared objects. -For more information on the types of objects that Sui supports, see [Object Ownership](/concepts/object-ownership.mdx). +For more information on the types of objects that Iota supports, see [Object Ownership](/concepts/object-ownership.mdx). ## Example: Escrow The Escrow example demonstrates the trade-offs between shared objects and owned objects by implementing the same application in both styles. It implements a service that allows two addresses to perform a trustless swap of objects with each other (a "trade") with the service holding their objects in escrow. ### `Locked` and `Key` -[Code Sample](https://github.com/MystenLabs/sui/blob/93e6b4845a481300ed4a56ab4ac61c5ccb6aa008/examples/move/escrow/sources/lock.move) +[Code Sample](https://github.com/iotaledger/iota/blob/93e6b4845a481300ed4a56ab4ac61c5ccb6aa008/examples/move/escrow/sources/lock.move) Both implementations use a primitive for locking values, which offers the following interface: @@ -37,7 +37,7 @@ The important property that this interface provides is that locked values cannot ### Owned objects -[Code Sample](https://github.com/MystenLabs/sui/blob/93e6b4845a481300ed4a56ab4ac61c5ccb6aa008/examples/move/escrow/sources/owned.move) +[Code Sample](https://github.com/iotaledger/iota/blob/93e6b4845a481300ed4a56ab4ac61c5ccb6aa008/examples/move/escrow/sources/owned.move) The protocol for swapping via escrow implemented using owned objects starts with both parties locking their respective objects. @@ -179,7 +179,7 @@ The `swap` function checks that senders and recipients match and that each party ### Shared objects -[Code Sample](https://github.com/MystenLabs/sui/blob/93e6b4845a481300ed4a56ab4ac61c5ccb6aa008/examples/move/escrow/sources/shared.move) +[Code Sample](https://github.com/iotaledger/iota/blob/93e6b4845a481300ed4a56ab4ac61c5ccb6aa008/examples/move/escrow/sources/shared.move) The protocol in the shared object case is less symmetric, but still starts with the first party locking the object they want to swap. ```mermaid diff --git a/docs/content/guides/developer/iota-101/sign-and-send-txn.mdx b/docs/content/guides/developer/iota-101/sign-and-send-txn.mdx new file mode 100644 index 00000000000..b289c7ae67f --- /dev/null +++ b/docs/content/guides/developer/iota-101/sign-and-send-txn.mdx @@ -0,0 +1,261 @@ +--- +title: Signing and Sending Transactions +--- + +Transactions in Iota represent calls to specific functionality (like calling a smart contract function) that execute on inputs to define the result of the transaction. + +Inputs can either be an object reference (either to an owned object, an immutable object, or a shared object), or an encoded value (for example, a vector of bytes used as an argument to a Move call). After a transaction is constructed, usually through using [programmable transaction blocks](./building-ptb) (PTBs), the user signs the transaction and submits it to be executed on chain. + +The signature is provided with the private key owned by the wallet, and its public key must be consistent with the transaction sender's Iota address. + +Iota uses a `IotaKeyPair` to produce the signature, which commits to the Blake2b hash digest of the intent message (`intent || bcs bytes of tx_data`). The signature schemes currently supported are `Ed25519 Pure`, `ECDSA Secp256k1`, `ECDSA Secp256r1`, `Multisig`, and `zkLogin`. + +You can instantiate `Ed25519 Pure`, `ECDSA Secp256k1`, and `ECDSA Secp256r1` using `IotaKeyPair` and use it to sign transactions. Note that this guide does not apply to `Multisig` and `zkLogin`, please refer to their own pages ([Multisig](/concepts/cryptography/transaction-auth/multisig) and [zkLogin](https://docs.iota.io/concepts/cryptography/zklogin) respectively) for instructions. + +With a signature and the transaction bytes, a transaction can be submitted to be executed. + +## Workflow + +The following high-level process describes the overall workflow for constructing, signing and executing an on-chain transaction: + +- Construct the transaction data by creating a `TransactionBlock` where multiple transactions are chained. See [Building Programmable Transaction Blocks](./building-ptb.mdx) for more information. +- The SDK's built-in gas estimation and coin selection picks the gas coin. +- Sign the transaction to generate a [signature](/concepts/cryptography/transaction-auth/signatures#user-signature). +- Submit the `TransactionBlock` and its signature for on-chain execution. + +:::info + +If you want to use a specific gas coin, first find the gas coin object ID to be used to pay for gas, and explicitly use that in the PTB. If there is no gas coin object, use the [splitCoin](./building-ptb#available-transactions) transaction to create a gas coin object. The split coin transaction should be the first transaction call in the PTB. + +::: + +## Examples + +The following examples demonstrate how to sign and execute transactions using Rust, TypeScript, or the Iota CLI. + + + + + +There are various ways to instantiate a key pair and to derive its public key and Iota address using the Iota TypeScript SDK. + +```tsx +import { fromHEX } from '@iota/bcs'; +import { getFullnodeUrl, IotaClient } from '@iota/iota.js/client'; +import { type Keypair } from '@iota/iota.js/cryptography'; +import { Ed25519Keypair } from '@iota/iota.js/keypairs/ed25519'; +import { Secp256k1Keypair } from '@iota/iota.js/keypairs/secp256k1'; +import { Secp256r1Keypair } from '@iota/iota.js/keypairs/secp256r1'; +import { TransactionBlock } from '@iota/iota.js/transactions'; + +const kp_rand_0 = new Ed25519Keypair(); +const kp_rand_1 = new Secp256k1Keypair(); +const kp_rand_2 = new Secp256r1Keypair(); + +const kp_import_0 = Ed25519Keypair.fromSecretKey( + fromHex('0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82'), +); +const kp_import_1 = Secp256k1Keypair.fromSecretKey( + fromHex('0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82'), +); +const kp_import_2 = Secp256r1Keypair.fromSecretKey( + fromHex('0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82'), +); + +// $MNEMONICS refers to 12/15/18/21/24 words from the wordlist, e.g. "retire skin goose will hurry this field stadium drastic label husband venture cruel toe wire". Refer to [Keys and Addresses](/concepts/cryptography/transaction-auth/keys-addresses.mdx) for more. +const kp_derive_0 = Ed25519Keypair.deriveKeypair('$MNEMONICS'); +const kp_derive_1 = Secp256k1Keypair.deriveKeypair('$MNEMONICS'); +const kp_derive_2 = Secp256r1Keypair.deriveKeypair('$MNEMONICS'); + +const kp_derive_with_path_0 = Ed25519Keypair.deriveKeypair('$MNEMONICS', "m/44'/4218'/1'/0'/0'"); +const kp_derive_with_path_1 = Secp256k1Keypair.deriveKeypair('$MNEMONICS', "m/54'/4218'/1'/0/0"); +const kp_derive_with_path_2 = Secp256r1Keypair.deriveKeypair('$MNEMONICS', "m/74'/4218'/1'/0/0"); + +// replace `kp_rand_0` with the variable names above. +const pk = kp_rand_0.getPublicKey(); +const sender = pk.toIotaAddress(); + +// create an example transaction block. +const txb = new TransactionBlock(); +txb.setSender(sender); +txb.setGasPrice(5); +txb.setGasBudget(100); +const bytes = await txb.build(); +const serializedSignature = (await keypair.signTransactionBlock(bytes)).signature; + +// verify the signature locally +expect(await keypair.getPublicKey().verifyTransactionBlock(bytes, serializedSignature)).toEqual( + true, +); + +// define iota client for the desired network. +const client = new IotaClient({ url: getFullnodeUrl('testnet') }); + +// execute transaction. +let res = client.executeTransactionBlock({ + transactionBlock: bytes, + signature: serializedSignature, +}); +console.log(res); +``` + + + + + +The full code example below can be found under [crates/iota-sdk](https://github.com/iotaledger/iota/blob/main/crates/iota-sdk/examples/sign_tx_guide.rs). + +There are various ways to instantiate a `IotaKeyPair` and to derive its public key and Iota address using the Iota Rust SDK. + +```rust + // deterministically generate a keypair, testing only, do not use for mainnet, use the next section to randomly generate a keypair instead. + let skp_determ_0 = + IotaKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))); + let _skp_determ_1 = + IotaKeyPair::Secp256k1(Secp256k1KeyPair::generate(&mut StdRng::from_seed([0; 32]))); + let _skp_determ_2 = + IotaKeyPair::Secp256r1(Secp256r1KeyPair::generate(&mut StdRng::from_seed([0; 32]))); + + // randomly generate a keypair. + let _skp_rand_0 = IotaKeyPair::Ed25519(get_key_pair_from_rng(&mut rand::rngs::OsRng).1); + let _skp_rand_1 = IotaKeyPair::Secp256k1(get_key_pair_from_rng(&mut rand::rngs::OsRng).1); + let _skp_rand_2 = IotaKeyPair::Secp256r1(get_key_pair_from_rng(&mut rand::rngs::OsRng).1); + + // import a keypair from a base64 encoded 32-byte `private key`. + let _skp_import_no_flag_0 = IotaKeyPair::Ed25519(Ed25519KeyPair::from_bytes( + &Base64::decode("1GPhHHkVlF6GrCty2IuBkM+tj/e0jn64ksJ1pc8KPoI=") + .map_err(|_| anyhow!("Invalid base64"))?, + )?); + let _skp_import_no_flag_1 = IotaKeyPair::Ed25519(Ed25519KeyPair::from_bytes( + &Base64::decode("1GPhHHkVlF6GrCty2IuBkM+tj/e0jn64ksJ1pc8KPoI=") + .map_err(|_| anyhow!("Invalid base64"))?, + )?); + let _skp_import_no_flag_2 = IotaKeyPair::Ed25519(Ed25519KeyPair::from_bytes( + &Base64::decode("1GPhHHkVlF6GrCty2IuBkM+tj/e0jn64ksJ1pc8KPoI=") + .map_err(|_| anyhow!("Invalid base64"))?, + )?); + + // import a keypair from a base64 encoded 33-byte `flag || private key`. The signature scheme is determined by the flag. + let _skp_import_with_flag_0 = + IotaKeyPair::decode_base64("ANRj4Rx5FZRehqwrctiLgZDPrY/3tI5+uJLCdaXPCj6C") + .map_err(|_| anyhow!("Invalid base64"))?; + let _skp_import_with_flag_1 = + IotaKeyPair::decode_base64("AdRj4Rx5FZRehqwrctiLgZDPrY/3tI5+uJLCdaXPCj6C") + .map_err(|_| anyhow!("Invalid base64"))?; + let _skp_import_with_flag_2 = + IotaKeyPair::decode_base64("AtRj4Rx5FZRehqwrctiLgZDPrY/3tI5+uJLCdaXPCj6C") + .map_err(|_| anyhow!("Invalid base64"))?; + + // replace `skp_determ_0` with the variable names above + let pk = skp_determ_0.public(); + let sender = IotaAddress::from(&pk); +``` + +Next, sign transaction data constructed using an example programmable transaction block with default gas coin, gas budget, and gas price. See [Building Programmable Transaction Blocks](./building-ptb.mdx) for more information. + +```rust + // construct an example programmable transaction. + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + builder.pay_iota(vec![sender], vec![1])?; + builder.finish() + }; + + let gas_budget = 5_000_000; + let gas_price = iota_client.read_api().get_reference_gas_price().await?; + + // create the transaction data that will be sent to the network. + let tx_data = TransactionData::new_programmable( + sender, + vec![gas_coin.object_ref()], + pt, + gas_budget, + gas_price, + ); +``` + +Commit a signature to the Blake2b hash digest of the intent message (`intent || bcs bytes of tx_data`). + +```rust + // derive the digest that the keypair should sign on, i.e. the blake2b hash of `intent || tx_data`. + let intent_msg = IntentMessage::new(Intent::iota_transaction(), tx_data); + let raw_tx = bcs::to_bytes(&intent_msg).expect("bcs should not fail"); + let mut hasher = iota_types::crypto::DefaultHash::default(); + hasher.update(raw_tx.clone()); + let digest = hasher.finalize().digest; + + // use IotaKeyPair to sign the digest. + let iota_sig = skp_determ_0.sign(&digest); + + // if you would like to verify the signature locally before submission, use this function. if it fails to verify locally, the transaction will fail to execute in Iota. + let res = iota_sig.verify_secure( + &intent_msg, + sender, + iota_types::crypto::SignatureScheme::ED25519, + ); + assert!(res.is_ok()); +``` + +Finally, submit the transaction with the signature. + +```rust + let transaction_response = iota_client + .quorum_driver_api() + .execute_transaction_block( + iota_types::transaction::Transaction::from_generic_sig_data( + intent_msg.value, + Intent::iota_transaction(), + vec![GenericSignature::Signature(iota_sig)], + ), + IotaTransactionBlockResponseOptions::default(), + None, + ) + .await?; +``` + + + + + +When using the [Iota CLI](/references/cli.mdx) for the first time, it creates a local file in `~/.iota/keystore` on your machine with a list of private keys (encoded as Base64 encoded `flag || 32-byte-private-key`). You can use any key to sign transactions by specifying its address. Use `iota keytool list` to see a list of addresses. + +There are three ways to initialize a key: + +```shell +# generate randomly. +iota client new-address ed25519 +iota client new-address secp256k1 +iota client new-address secp256r1 + +# import the 32-byte private key to keystore. +iota keytool import "0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82" ed25519 +iota keytool import "0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82" secp256k1 +iota keytool import "0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82" secp256r1 + +# import the mnemonics (recovery phrase) with derivation path to keystore. +# $MNEMONICS refers to 12/15/18/21/24 words from the wordlist, e.g. "retire skin goose will hurry this field stadium drastic label husband venture cruel toe wire". Refer to [Keys and Addresses](/concepts/cryptography/transaction-auth/keys-addresses.mdx) for more. + +iota keytool import "$MNEMONICS" ed25519 +iota keytool import "$MNEMONICS" secp256k1 +iota keytool import "$MNEMONICS" secp256r1 +``` + +Create a transfer transaction in CLI. Set the $IOTA_ADDRESS to the one corresponding to the keypair used to sign. $GAS_COIN_ID refers to the object ID that is owned by the sender to be used as gas. $GAS_BUDGET refers to the budget used to execute transaction. Then sign with the private key corresponding to the sender address. $MNEMONICS refers to 12/15/18/21/24 words from the wordlist, e.g. "retire skin goose will hurry this field stadium drastic label husband venture cruel toe wire". Refer to [Keys and Addresses](/concepts/cryptography/transaction-auth/keys-addresses.mdx) for more. + +```shell +iota client gas +iota client transfer-iota --to $IOTA_ADDRESS --iota-coin-object-id $GAS_COIN_ID --gas-budget $GAS_BUDGET --serialize-unsigned-transaction +iota keytool sign --address $IOTA_ADDRESS --data $TX_BYTES +iota client execute-signed-tx --tx-bytes $TX_BYTES --signatures $SERIALIZED_SIGNATURE +``` + + + + +### Notes + +1. This guide demonstrates how to sign with a single private key. Refer to [Multisig](/concepts/cryptography/transaction-auth/multisig.mdx) when it is preferred to set up more complex signing policies. +2. Similarly, native zkLogin does not follow the above steps, see [the docs](/concepts/cryptography/zklogin.mdx) to understand how to derive a zkLogin address, and produce a zkLogin signature with an ephemeral key pair. +3. If you decide to implement your own signing mechanisms instead of using the previous tools, see the [Signatures](/concepts/cryptography/transaction-auth/signatures.mdx) doc on the accepted signature specifications for each scheme. +4. Flag is one byte that differentiates signature schemes. See supported schemes and its flag in [Signatures](/concepts/cryptography/transaction-auth/signatures.mdx). +5. The `execute_transaction_block` endpoint takes a list of signatures, so it should contain exactly one user signature, unless you are using sponsored transaction that a second signature for the gas object can be provided. See [Sponsored Transactions](/concepts/transactions/sponsored-transactions.mdx) for more information. diff --git a/docs/content/guides/developer/sui-101/simulating-refs.mdx b/docs/content/guides/developer/iota-101/simulating-refs.mdx similarity index 79% rename from docs/content/guides/developer/sui-101/simulating-refs.mdx rename to docs/content/guides/developer/iota-101/simulating-refs.mdx index 38ba065d639..d48c2088f48 100644 --- a/docs/content/guides/developer/sui-101/simulating-refs.mdx +++ b/docs/content/guides/developer/iota-101/simulating-refs.mdx @@ -1,11 +1,11 @@ --- title: Simulating References -description: Use the borrow module in the Sui framework to include objects by reference in your programmable transaction blocks. +description: Use the borrow module in the Iota framework to include objects by reference in your programmable transaction blocks. --- -Everything on the Sui blockchain is an object. When you develop Move packages for the Sui network, you're typically manipulating or using on-chain objects in some way through functionality available in the Sui API. For most API functions, you provide an object by reference. +Everything on the Iota blockchain is an object. When you develop Move packages for the Iota network, you're typically manipulating or using on-chain objects in some way through functionality available in the Iota API. For most API functions, you provide an object by reference. -References are a key construct when programming in Move and on Sui. Most of the functionality available in the Sui API takes objects by reference. +References are a key construct when programming in Move and on Iota. Most of the functionality available in the Iota API takes objects by reference. There are two ways to use an object: - **by value:** When you use an object by value, you have full control over that object. You can destroy it (if the functionality is available), wrap it (if it has the `store` ability), or transfer it to an address. @@ -17,7 +17,7 @@ Programmable transaction blocks (PTBs) do not currently allow the use of object ## The borrow module -The Sui framework includes a [borrow](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/docs/borrow.md) module that offers a solution to the reference problem. The module provides access to an object by value but builds a model that makes it impossible to destroy, transfer, or wrap the object retrieved. The borrow module exposes a `Referent` object that wraps another object (the object you want to reference). The module uses the [hot potato pattern](/concepts/sui-move-concepts/patterns/hot-potato.mdx) (via a `Borrow` instance) to allow retrieval of the wrapped object by value. Within the same PTB, the module then forces the object to be returned to the `Referent`. The `Borrow` instance guarantees that the object returned is the same that was retrieved. +The Iota framework includes a [borrow](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/docs/borrow.md) module that offers a solution to the reference problem. The module provides access to an object by value but builds a model that makes it impossible to destroy, transfer, or wrap the object retrieved. The borrow module exposes a `Referent` object that wraps another object (the object you want to reference). The module uses the [hot potato pattern](/concepts/iota-move-concepts/patterns/hot-potato.mdx) (via a `Borrow` instance) to allow retrieval of the wrapped object by value. Within the same PTB, the module then forces the object to be returned to the `Referent`. The `Borrow` instance guarantees that the object returned is the same that was retrieved. As an example, consider the following module stub that exposes an object (`Asset`) and a function (`use_asset`) to use that object. diff --git a/docs/content/guides/developer/sui-101/sponsor-txn.mdx b/docs/content/guides/developer/iota-101/sponsor-txn.mdx similarity index 85% rename from docs/content/guides/developer/sui-101/sponsor-txn.mdx rename to docs/content/guides/developer/iota-101/sponsor-txn.mdx index 94317917653..bb8e7e881fa 100644 --- a/docs/content/guides/developer/sui-101/sponsor-txn.mdx +++ b/docs/content/guides/developer/iota-101/sponsor-txn.mdx @@ -2,10 +2,10 @@ title: Sponsored Transaction --- -Sponsored transactions are a primitive on the Sui blockchain that enable the execution of a transaction without a user paying the gas. It also discusses the roles in Sponsored Transaction, and a few common use cases. Then it discusses the flow of Sponsored Transaction, mostly for developers who are interested in building a Gas Station or integrate with one. Finally it talks about risk considerations of Sponsored Transaction. +Sponsored transactions are a primitive on the Iota blockchain that enable the execution of a transaction without a user paying the gas. It also discusses the roles in Sponsored Transaction, and a few common use cases. Then it discusses the flow of Sponsored Transaction, mostly for developers who are interested in building a Gas Station or integrate with one. Finally it talks about risk considerations of Sponsored Transaction. # Overview -A transaction on Sui takes a payment to execute. The payment, also known as gas, is a list of `0x2::coin::Coin<0x2::sui::Sui>` objects, and paid to Sui validators to secure the network. Although gas is a critical piece in Sui tokenomics, it sometimes adds challenges when new users start to navigate on Sui, especially for web 2.0 users. +A transaction on Iota takes a payment to execute. The payment, also known as gas, is a list of `0x2::coin::Coin<0x2::iota::Iota>` objects, and paid to Iota validators to secure the network. Although gas is a critical piece in Iota tokenomics, it sometimes adds challenges when new users start to navigate on Iota, especially for web 2.0 users. Sponsored transactions can reduce the onboarding friction for users because the feature streamlines the process for end users. Using sponsored transactions, you can execute a transaction without requiring the user to pay it themselves. Instead, you can act as a sponsor of the transaction, offering your own payment gas objects for the transaction. @@ -60,14 +60,14 @@ pub struct SenderSignedTransaction { pub struct TransactionDataV1 { // <-- A variant of `TransactionData` pub kind: TransactionKind, // <-- This is the actual transaction details - pub sender: SuiAddress, + pub sender: IotaAddress, pub gas_data: GasData, pub expiration: TransactionExpiration, } pub struct GasData { pub payment: Vec, - pub owner: SuiAddress, + pub owner: IotaAddress, pub price: u64, pub budget: u64, } @@ -112,7 +112,7 @@ Because at least two stakeholders are involved in a sponsored transaction, you s ### Client equivocation risk -Client equivocation happens when more than one legit transaction that shares at least one owned object (such as a gas coin object) at a certain version are submitted to the network simultaneously. On Sui, before a transaction is executed, owned objects in this transaction are locked on validators at specific versions. An honest validator only accepts one transaction and rejects others. Depending on the order validators receive these transactions, validators might accept different transactions. In the event of no single transaction getting accepted by at least 2/3rds of validators, the owned object is locked until end of the epoch. +Client equivocation happens when more than one legit transaction that shares at least one owned object (such as a gas coin object) at a certain version are submitted to the network simultaneously. On Iota, before a transaction is executed, owned objects in this transaction are locked on validators at specific versions. An honest validator only accepts one transaction and rejects others. Depending on the order validators receive these transactions, validators might accept different transactions. In the event of no single transaction getting accepted by at least 2/3rds of validators, the owned object is locked until end of the epoch. Practically speaking, client equivocation is rare, mostly caused by buggy client software. After all, no one has incentives to lock their own objects. However, sponsored transactions come with counterparty risks. For example, a malicious user could equivocate the gas station's gas coin object by submitting another transaction that uses one owned object in the gas station signed transaction at the same version. Similarly, a Byzantine gas station could do the same to the user owned objects. diff --git a/docs/content/guides/developer/sui-101/using-events.mdx b/docs/content/guides/developer/iota-101/using-events.mdx similarity index 80% rename from docs/content/guides/developer/sui-101/using-events.mdx rename to docs/content/guides/developer/iota-101/using-events.mdx index eb0f565f95c..4ead2ee26ea 100644 --- a/docs/content/guides/developer/sui-101/using-events.mdx +++ b/docs/content/guides/developer/iota-101/using-events.mdx @@ -1,20 +1,20 @@ --- title: Using Events -description: Monitor Sui on-chain activity by subscribing to events that Move packages published on Sui emit. +description: Monitor Iota on-chain activity by subscribing to events that Move packages published on Iota emit. --- -The Sui network stores countless objects on chain where Move code can perform actions using those objects. Tracking this activity is often desired, for example, to discover how many times a module mints an NFT or to tally the amount of SUI in transactions that a smart contract generates. +The Iota network stores countless objects on chain where Move code can perform actions using those objects. Tracking this activity is often desired, for example, to discover how many times a module mints an NFT or to tally the amount of IOTA in transactions that a smart contract generates. -To support activity monitoring, Move provides a structure to emit events on the Sui network. When you establish a connection with the Sui network, you create a two-way interactive communication session between your client and a Sui network node. With an open session, you can subscribe to specific events that the Sui network adds to the stream to create real-time monitoring of events. +To support activity monitoring, Move provides a structure to emit events on the Iota network. When you establish a connection with the Iota network, you create a two-way interactive communication session between your client and a Iota network node. With an open session, you can subscribe to specific events that the Iota network adds to the stream to create real-time monitoring of events. ## Move event structure -An event object in Sui consists of the following attributes: +An event object in Iota consists of the following attributes: - `id`: JSON object containing the transaction digest ID and event sequence. - `packageId`: The object ID of the package that emits the event. - `transactionModule`: The module that performs the transaction. -- `sender`: The Sui network address that triggered the event. +- `sender`: The Iota network address that triggered the event. - `type`: The type of event being emitted. - `parsedJson`: JSON object describing the event. - `bcs`: Binary canonical serialization value. @@ -22,7 +22,7 @@ An event object in Sui consists of the following attributes: ## Discovering events -If you want to subscribe to events on chain, you first need to know what events are available. You typically know or can discover the events your own code emits, but it's not as straightforward when you need to subscribe to on-chain events from packages you don't own. The Sui RPC provides a [queryEvents](/sui-api-ref#suix_queryEvents) method to query on-chain packages and return available events that you can subscribe to. +If you want to subscribe to events on chain, you first need to know what events are available. You typically know or can discover the events your own code emits, but it's not as straightforward when you need to subscribe to on-chain events from packages you don't own. The Iota RPC provides a [queryEvents](/iota-api-ref#iotax_queryEvents) method to query on-chain packages and return available events that you can subscribe to. ## Filter events @@ -30,13 +30,13 @@ You can filter the events your code targets for either querying or subscribing. ## Emit events in Move -To create an event in your Move modules, add the `sui::event` dependency. +To create an event in your Move modules, add the `iota::event` dependency. ```move -use sui::event; +use iota::event; ``` -With the dependency added, you can use the `emit` function to fire an event whenever the action you want to monitor fires. For example, the following code is part of an example application using digital donuts. The `collect_profits` function handles the collection of SUI and emits an event whenever the function is called. To act on that event, you need to subscribe to it. +With the dependency added, you can use the `emit` function to fire an event whenever the action you want to monitor fires. For example, the following code is part of an example application using digital donuts. The `collect_profits` function handles the collection of IOTA and emits an event whenever the function is called. To act on that event, you need to subscribe to it. ```move /// Take coin from `DonutShop` and transfer it to tx sender. @@ -52,9 +52,9 @@ public fun collect_profits( _: &ShopOwnerCap, shop: &mut DonutShop, ctx: &mut Tx ## Subscribe to events in Move -Firing events is not very useful in a vacuum. You also need the ability to listen for those events so that you can act on them. In Sui, you subscribe to those events and provide logic that triggers when the event fires. +Firing events is not very useful in a vacuum. You also need the ability to listen for those events so that you can act on them. In Iota, you subscribe to those events and provide logic that triggers when the event fires. -Sui Full nodes support subscribe functionality using JSON-RPC notifications transmitted through the WebSocket API. You can interact with the RPC directly ([suix_subscribeEvent](/sui-api-ref#suix_subscribeEvent), [suix_subscribeTransaction](/sui-api-ref#suix_subscribeTransaction)) or you can use an SDK like the Sui TypeScript SDK. The following excerpt from one of the examples uses the TypeScript SDK to create an asynchronous subscription to the filter identified in the filter. +Iota Full nodes support subscribe functionality using JSON-RPC notifications transmitted through the WebSocket API. You can interact with the RPC directly ([iotax_subscribeEvent](/iota-api-ref#iotax_subscribeEvent), [iotax_subscribeTransaction](/iota-api-ref#iotax_subscribeTransaction)) or you can use an SDK like the Iota TypeScript SDK. The following excerpt from one of the examples uses the TypeScript SDK to create an asynchronous subscription to the filter identified in the filter. ```move let unsubscribe = await provider.subscribeEvent({ @@ -76,7 +76,7 @@ Move smart contracts can call other smart contracts that emit events. For exampl "packageId": "0x158f2027f60c89bb91526d9bf08831d27f5a0fcb0f74e6698b9f0e1fb2be5d05", "transactionModule": "deepbook_utils", "sender": "0x4419ae182ac112bb065bda2146136ed02524ee2611478bfe8ca5d3835bee4af6", - "type": "0xdee9::clob_v2::OrderPlaced<0x2::sui::SUI, 0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN>", + "type": "0xdee9::clob_v2::OrderPlaced<0x2::iota::IOTA, 0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN>", "parsedJson": { "base_asset_quantity_placed": "1000000000", "client_order_id": "20082022", @@ -121,14 +121,14 @@ Move smart contracts can call other smart contracts that emit events. For exampl ## Subscribe to event -This example leverages the Sui TypeScript SDK to subscribe to events the package with ID `` emits. Each time the event fires, the code displays the response to the console. +This example leverages the Iota TypeScript SDK to subscribe to events the package with ID `` emits. Each time the event fires, the code displays the response to the console. ### TypeScript -To create the event subscription, you can use a basic Node.js app. You need the Sui TypeScript SDK, so install the module using `npm install @mysten/sui.js` at the root of your project. In your TypeScript code, import `JsonRpcProvider` and a connection from the library. +To create the event subscription, you can use a basic Node.js app. You need the Iota TypeScript SDK, so install the module using `npm install @iota/iota.js` at the root of your project. In your TypeScript code, import `JsonRpcProvider` and a connection from the library. ```ts -import { JsonRpcProvider, testnetConnection } from '@mysten/sui.js'; +import { JsonRpcProvider, testnetConnection } from '@iota/iota.js'; // Package is on Testnet. const provider = new JsonRpcProvider(testnetConnection); @@ -188,17 +188,17 @@ subscribeEvent { ```rust use futures::StreamExt; -use sui_sdk::rpc_types::EventFilter; -use sui_sdk::SuiClientBuilder; +use iota_sdk::rpc_types::EventFilter; +use iota_sdk::IotaClientBuilder; use anyhow::Result; #[tokio::main] async fn main() -> Result<()> { - let sui = SuiClientBuilder::default() - .ws_url("wss://fullnode.mainnet.sui.io:443") - .build("https://fullnode.mainnet.sui.io:443") + let iota = IotaClientBuilder::default() + .ws_url("wss://fullnode.mainnet.iota.io:443") + .build("https://fullnode.mainnet.iota.io:443") .await.unwrap(); - let mut subscribe_all = sui.event_api().subscribe_event(EventFilter::All(vec![])).await?; + let mut subscribe_all = iota.event_api().subscribe_event(EventFilter::All(vec![])).await?; loop { println!("{:?}", subscribe_all.next().await); } diff --git a/docs/content/guides/developer/iota-101/working-with-ptbs.mdx b/docs/content/guides/developer/iota-101/working-with-ptbs.mdx new file mode 100644 index 00000000000..fe83f9e101c --- /dev/null +++ b/docs/content/guides/developer/iota-101/working-with-ptbs.mdx @@ -0,0 +1,32 @@ +--- +title: Working with Programmable Transaction Blocks +--- + +Programmable transaction blocks (PTBs) are key elements of the Iota ecosystem. Understanding PTBs and using them correctly are key fundamentals to creating efficient and cost-effective smart contracts. See [Programmable Transaction Blocks](../../../concepts/transactions/prog-txn-blocks.mdx) to learn about the structure of PTBs on Iota. + +The topics in this section focus on effectively utilizing PTBs in your smart contracts. + +## Building Programmable Transaction Blocks + +To fully appreciate the possibilities PTBs offer, you must build them. Using tools like the [Iota TypeScript SDK](https://sdk.mystenlabs.com/typescript), you can begin to understand the power and flexibility they provide. + +Go to [Building Programmable Transaction Blocks](./building-ptb.mdx). + +## Coin Management + +`Coin` objects on Iota are different than other blockchains in that they are [owned objects](../../../concepts/object-ownership/address-owned.mdx). Whether you need your smart contract to utilize IOTA for gas payments or deal with generic coins, understanding coin management is crucial. Smart contracts use common patterns to accept coins and the PTBs you create must provide the correct interface to those smart contracts to facilitate successful transactions. + +Go to [Coin Management](./coin-mgt.mdx). + +## Simulating References + +The [`borrow` module](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/docs/iota-framework/borrow.md) of the Iota framework offers some features you can use when your PTBs use objects by reference. + +Go to [Simulating References](./simulating-refs.mdx). + +## Related links + +Review this content for a complete picture of PTBs on Iota. + +- [Programmable Transaction Blocks](../../../concepts/transactions/prog-txn-blocks.mdx): Conceptual overview of the PTB architecture. +- [Life of a Transaction](../../../concepts/iota-architecture/transaction-lifecycle.mdx): Discover the life of a transaction from inception to finality. \ No newline at end of file diff --git a/docs/content/guides/developer/sui-101.mdx b/docs/content/guides/developer/sui-101.mdx deleted file mode 100644 index 3fb905975ae..00000000000 --- a/docs/content/guides/developer/sui-101.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Sui 101 -description: Collection of core Sui concepts that developers use to create objects and interact with them on the Sui blockchain. ---- - -In many education systems, 101-level classes are those that teach core competencies to build a foundation for the more advanced topics that are to come. The topics in this section provide the same experience for the Sui blockchain. They examine the core Sui development concepts that you use to build apps on Sui. As you start developing more advanced solutions, knowledge of these topics provides a good base for understanding the more advanced concepts you will employ. - -## Creating coins and NFTs on Sui - -Everything on the Sui blockchain is an object. These topics use code examples to demonstrate how to create these specific types of objects. - -- [Create Coins](./sui-101/create-coin.mdx) -- [Create NFTs](./sui-101/create-nft.mdx) - -## Working with PTBs - -You can create programmable transaction blocks (PTBs) on Sui to perform multiple commands in a single transaction. The Working with PTBs topics demonstrate how to build efficient PTBs using the Sui TypeScript SDK. - -Go to [Working with PTBs](./sui-101/working-with-ptbs.mdx). - -## Using Events - -You can emit events from your published packages on the Sui network. Using Events demonstrates how to emit events from your on-chain packages and monitor the activity of other objects emitting events. - -Go to [Using Events](./sui-101/using-events.mdx). - -## Shared versus Owned Objects - -Objects on Sui, unlike other blockchains, can be owned as well as shared. You can create transactions that leverage either type or both. Shared versus Owned Objects examines the differences and what considerations you should account for when deciding how to structure your on-chain app. - -Go to [Shared versus Owned Objects](./sui-101/shared-owned.mdx). - -## Access On-Chain Time - -Sui provides a `Clock` module you can use to get network-based time. Access On-Chain Time examines the `Clock` module and the behavior of the available methods that affect transaction processing speed and the temporal exactness of the data you receive. - -Go to [Access On-Chain Time](./sui-101/access-time.mdx). \ No newline at end of file diff --git a/docs/content/guides/developer/sui-101/access-time.mdx b/docs/content/guides/developer/sui-101/access-time.mdx deleted file mode 100644 index 984e8030501..00000000000 --- a/docs/content/guides/developer/sui-101/access-time.mdx +++ /dev/null @@ -1,121 +0,0 @@ ---- -title: Access On-Chain Time -description: Access network-based time for your transactions. Sui provides a Clock module to capture near-real time or epoch time in your Sui packages. ---- - -You have options when needing to access network-based time for your transactions. If you need a near real-time measurement (within a few seconds), use the immutable reference of time provided by the `Clock` module in Move. The reference value from this module updates with every network checkpoint. If you don't need as current a time slice, use the `epoch_timestamp_ms` function to capture the precise moment the current epoch started. - -## The sui::clock::Clock module - -To access a prompt timestamp, you must pass a read-only reference of `sui::clock::Clock` as an entry function parameter in your transactions. An instance of `Clock` is provided at address `0x6`, no new instances can be created. - -Extract a unix timestamp in milliseconds from an instance of `Clock` using - -```move -module sui::clock { - public fun timestamp_ms(clock: &Clock): u64; -} -``` - -The example below demonstrates an entry function that emits an event containing a timestamp from the `Clock`: - -```move -module example::clock { - use sui::clock::{Self, Clock}; - use sui::event; - - struct TimeEvent has copy, drop, store { - timestamp_ms: u64 - } - - entry fun access(clock: &Clock) { - event::emit(TimeEvent { - timestamp_ms: clock::timestamp_ms(clock), - }); - } -} -``` - -A call to the previous entry function takes the following form, passing `0x6` as the address for the `Clock` parameter: - -```shell -sui client call --package --module 'clock' --function 'access' --args '0x6' --gas-budget -``` - -Expect the `Clock` timestamp to change **every 2 to 3 seconds**, at the rate the network commits checkpoints. - -Successive calls to `sui::clock::timestamp_ms` in the same transaction always produce the same result (transactions are considered to take effect instantly), but timestamps from `Clock` are otherwise monotonic across transactions that touch the same shared objects: Successive transactions seeing a greater or equal timestamp to their predecessors. - -Any transaction that requires access to a `Clock` must go through consensus because the only available instance is a shared object. As a result, this technique is not suitable for transactions that must use the single-owner fastpath (see Epoch timestamps for a single-owner-compatible source of timestamps). - -Transactions that use the clock must accept it as an **immutable reference** (not a mutable reference or value). This prevents contention, as transactions that access the `Clock` can only read it, so do not need to be sequenced relative to each other. Validators refuse to sign transactions that do not meet this requirement and packages that include entry functions that accept a `Clock` or `&mut Clock` fail to publish. - -The following functions test `Clock`-dependent code by manually creating a `Clock` object and manipulating its timestamp. This is possible only in test code: - -```move -module sui::clock { - #[test_only] - public fun create_for_testing(ctx: &mut TxContext); - - #[test_only] - public fun share_for_testing(clock: Clock); - - #[test_only] - public fun increment_for_testing(clock: &mut Clock, tick: u64); - - #[test_only] - public fun set_for_testing(clock: &mut Clock, timestamp_ms: u64); - - #[test_only] - public fun destroy_for_testing(clock: Clock); -} -``` - -The next example presents a simple test that creates a Clock, increments it, and then checks its value: - -```move -module example::clock_tests { - use sui::clock::{Self, Clock}; - use sui::tx_context; - - #[test] - fun creating_a_clock_and_incrementing_it() { - let ctx = tx_context::dummy(); - let clock = clock::create_for_testing(&mut ctx); - - clock::increment_for_testing(&mut clock, 42); - assert!(clock::timestamp_ms(&clock) == 42, 1); - - clock::set_for_testing(&mut clock, 50); - assert!(clock::timestamp_ms(&clock) == 50, 1); - - clock::destroy_for_testing(clock); - } -} -``` - -## Epoch timestamps - -You can use the following function to access the timestamp for the start of the current epoch for all transactions (including ones that do not go through consensus): - -```move -module sui::tx_context { - public fun epoch_timestamp_ms(ctx: &TxContext): u64; -} -``` - -The preceding function returns the point in time when the current epoch started, as a millisecond granularity unix timestamp in a u64. This value changes roughly **once every 24 hours**, when the epoch changes. - -Tests based on `sui::test_scenario` can use `later_epoch` (following code), to exercise time-sensitive code that uses `epoch_timestamp_ms` (previous code): - -```move -module sui::test_scenario { - public fun later_epoch( - scenario: &mut Scenario, - delta_ms: u64, - sender: address, - ): TransactionEffects; -} -``` - -`later_epoch` behaves like `sui::test_scenario::next_epoch` (finishes the current transaction and epoch in the test scenario), but also increments the timestamp by `delta_ms` milliseconds to simulate the progress of time. diff --git a/docs/content/guides/developer/sui-101/coin-mgt.mdx b/docs/content/guides/developer/sui-101/coin-mgt.mdx deleted file mode 100644 index 1d9a68e4dd4..00000000000 --- a/docs/content/guides/developer/sui-101/coin-mgt.mdx +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Coin Management -description: Because Sui uses Coins as owned objects for transactions, you need to explicitly manage them in your programmable transaction block development. ---- - -A key concept when programming on Sui is that of owned objects. Address-owned objects are important in that they allow for highly parallelizable transactions. And they also logically map to assets or resources that someone exclusively owns. Coins are a typical case of owned object usage, with cash being a real-life reference. The owned objects paradigm, however, and particularly as related to coins, is somewhat of a divergence from other blockchains which have a concept of balance. In other words, in other systems, especially account based systems, coins are held in a single location (field) which can be thought of as a balance in a bank account. - -Because Sui uses owned objects instead of a balance, it is common to own a number of coins, at times even a significant number of them. Some scenarios necessitate merging some or all of those coins into a single object. At times, merging coins together might even be required because the amount necessary to execute a transaction is more than any single coin the sender owns, thus making merging an inevitable step. - -## SDK usage - -The Sui SDKs ([TypeScript](https://sdk.mystenlabs.com/typescript) and [Rust](/references/rust-sdk.mdx)) manage coins on your behalf, removing the overhead of having to deal with coin management manually. The SDKs attempt to merge coins whenever possible and assume that transactions are executed in sequence. That's a reasonable assumption with wallet-based transactions and for common scenarios in general. Sui recommends relying on this feature if you do not have a need for heavy parallel or concurrent execution. - -## Gas Smashing - -When executing a transaction Sui allows you to provide a number of coins as payment. In other words, the payment can be a vector of coins rather than a single coin. That feature, known as gas smashing, performs merging of coins automatically, and presents the PTBs you write with a single gas coin that can be used for other purposes besides just gas. - -Basically, you can provide as many coins as you want (with a max limit defined in the protocol configuration) and have all of them merged (smashed) into the first coin provided as payment. That coin, minus the gas budget, is then available inside the transaction and can be used in any command. If the coin is unused it is returned to the user. - -Gas smashing is an important feature - and a key concept to understand - to have for the optimal management of coins. See [Gas Smashing](/concepts/transactions/gas-smashing.mdx) for more details. - -## Generic coins - -Gas smashing works well for `Coin` objects, which is the only coin type that can be used for gas payment. - -Any other coin type requires explicit management from users. PTBs offer a `mergeCoins` command that you can use to combine multiple coins into a single one. And a `splitCoins` as the complementary operation to break them up. - -From a cost perspective, those are very cheap transactions, however they require a user to be aware of their coin distribution and their own needs. - -## Concurrency - -Merging coins, and particularly `Coin`, into a single coin or a very small number of coins might prove problematic in scenarios where heavy or high concurrency is required. - -If you merge all `Coin` into a single one, you would need to sequentially submit every transaction. The coin - being an owned object - would have to be provided with a version and it would be locked by the system when signing a transaction, effectively making it impossible to use it in any other transaction until the one that locked it was executed. Moreover, an attempt to sign multiple transactions with the same coin might result in equivocation and the coin being unusable and locked until the end of the epoch. - -So when you require heavy concurrency, you should first split a coin into as many coins as the number of transactions to execute concurrently. Alternatively, you could provide multiple and different coins (gas smashing) to the different transactions. It is critically important that the set of coins you use in the different transactions has no intersection at all. - -The possible pitfalls in dealing with heavy concurrency are many. Concurrency in transaction execution is not the only performance bottleneck. In creating and submitting a transaction, several round trips with a Full node might be required to discover and fetch the right objects, and to dry run a transaction. Those round trips might affect performance significantly. - -Concurrency is a difficult subject and is beyond the scope of this documentation. You must take maximum care when dealing with coin management in the face of concurrency, and the right strategy is often tied to the specific scenario, rather than universally available. diff --git a/docs/content/guides/developer/sui-101/create-coin.mdx b/docs/content/guides/developer/sui-101/create-coin.mdx deleted file mode 100644 index 89b883eba08..00000000000 --- a/docs/content/guides/developer/sui-101/create-coin.mdx +++ /dev/null @@ -1,100 +0,0 @@ ---- -title: Create Coins and Tokens ---- - -Coins and tokens on Sui are similar. In practice, the terms are used interchangeably, but there are some differences in their implementation. You can learn about these differences in the respective standard documentation, [Closed-Loop Token](../../../standards/closed-loop-token.mdx) and [Coin](../../../standards/coin.mdx). - -Publishing a coin on Sui is nearly as straightforward as publishing a new type. The main difference is the requirement of a [one-time witness](/concepts/sui-move-concepts/one-time-witness.mdx) when creating a coin. - -```move -module examples::mycoin { - use std::option; - use sui::coin::{Self, Coin, TreasuryCap}; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; - - /// The type identifier of coin. The coin will have a type - /// tag of kind: `Coin` - /// Make sure that the name of the type matches the module's name. - struct MYCOIN has drop {} - - /// Module initializer is called once on module publish. A treasury - /// cap is sent to the publisher, who then controls minting and burning - fun init(witness: MYCOIN, ctx: &mut TxContext) { - let (treasury, metadata) = coin::create_currency(witness, 6, b"MYCOIN", b"", b"", option::none(), ctx); - transfer::public_freeze_object(metadata); - transfer::public_transfer(treasury, tx_context::sender(ctx)) - } -} -``` - -The `Coin` is a generic implementation of a coin on Sui. Access to the `TreasuryCap` provides control over the minting and burning of coins. Further transactions can be sent directly to the `sui::coin::Coin` with `TreasuryCap` object as authorization. - -Extending the example further, add a `mint` function to the module. Use the `mint` function of the `Coin` module to create (mint) a coin and then transfer it to an address. - -```move -public fun mint( - treasury_cap: &mut TreasuryCap, - amount: u64, - recipient: address, - ctx: &mut TxContext, -) { - let coin = coin::mint(treasury_cap, amount, ctx); - transfer::public_transfer(coin, recipient) -} -``` - -### Sui CLI - -If you published the previous example to a Sui network, you can use the `sui client call` command to mint coins and deliver them to the address you provide. See [Sui CLI](../../../references/cli.mdx) for more information on the command line interface. - -```shell -sui client call --function mint --module mycoin --package --args --gas-budget -``` - -If the call is successful your console displays the result, which includes a **Balance Changes** section with the following information included: - -```shell -... - -Owner: Account Address ( ) -CoinType: ::mycoin::MYCOIN -Amount: - -... -``` - -## DenyList - -The Sui framework provides a `DenyList` singleton, shared object that the bearer of a `DenyCap` can access to specify a list of addresses that are unable to use a Sui core type. The initial use case for `DenyList`, however, focuses on limiting access to coins of a specified type. This is useful, for example, when creating a regulated coin on Sui that requires the ability to block certain addresses from using it as inputs to transactions. Regulated coins on Sui satisfy any regulations that require the ability to prevent known bad actors from having access to those coins. - -:::info - -The `DenyList` object is a system object that has the address `0x403`. You cannot create it yourself. - -::: - -## Create regulated coin - -If you need the ability to deny specific addresses from having access to your coin, you can use the `create_regulated_currency` function (instead of `create_currency`) to create it. - -Behind the scenes, `create_regulated_currency` uses the `create_currency` function to create the coin, but also produces a `DenyCap` object that allows its bearer to control access to the coin's deny list in a `DenyList` object. Consequently, the way to create a coin using `create_regulated_currency` is similar to the previous example, with the addition of a transfer of the `DenyCap` object to the module publisher. - -## Create tokens - -Tokens reuse the `TreasuryCap` defined in the `sui::coin` module and therefore have the same initialization process. The `coin::create_currency` function guarantees the uniqueness of the `TreasuryCap` and forces the creation of a `CoinMetadata` object. - -Coin-like functions perform the minting and burning of tokens. Both require the `TreasuryCap`: - -- `token::mint` - mint a token -- `token::burn` - burn a token - -See [Closed-Loop Token](../../../standards/closed-loop-token.mdx) standard for complete details of working with tokens. - -## Examples - -See the following topics for examples of some common use cases for coin and token creation. - -- [Regulated Coin and Deny List](./create-coin/regulated.mdx): Create a regulated coin and add or remove names from the deny list. -- [Loyalty Token](./create-coin/loyalty.mdx): Create a token to reward user loyalty. -- [In-Game Token](./create-coin/in-game-token.mdx): Create tokens that can be used only within a mobile game. diff --git a/docs/content/guides/developer/sui-101/create-coin/in-game-token.mdx b/docs/content/guides/developer/sui-101/create-coin/in-game-token.mdx deleted file mode 100644 index 26b6c2e5814..00000000000 --- a/docs/content/guides/developer/sui-101/create-coin/in-game-token.mdx +++ /dev/null @@ -1,140 +0,0 @@ ---- -title: In-Game Currency ---- - -Using the Sui [Closed-Loop Token](../../../../standards/closed-loop-token.mdx) standard, you can create in-game currency (such as gems or diamonds in mobile games) that you can grant to players for their actions or make available to purchase. You mint the tokens on Sui, but players can only use the tokens within the economy of the game itself. These types of tokens are usually not transferrable and you would typically mint them in predefined amounts to maintain scarcity and game balance. - -The following example creates an in-game currency called a GEM, which represents a certain number of SUI. In the example, the user can buy fungible GEMs using SUI, which can then be used as currency within the game. Use the code comments to follow the logic of the example. - -```move title="sui/examples/move/token/sources/gems.move" -/// This is a simple example of a permissionless module for an imaginary game -/// that sells swords for Gems. Gems are an in-game currency that can be bought -/// with SUI. -module examples::sword { - use sui::tx_context::TxContext; - use sui::object::{Self, UID}; - - use sui::token::{Self, Token, ActionRequest}; - use examples::gem::GEM; - - /// Trying to purchase a sword with an incorrect amount. - const EWrongAmount: u64 = 0; - - /// The price of a sword in Gems. - const SWORD_PRICE: u64 = 10; - - /// A game item that can be purchased with Gems. - struct Sword has key, store { id: UID } - - /// Purchase a sword with Gems. - public fun buy_sword( - gems: Token, ctx: &mut TxContext - ): (Sword, ActionRequest) { - assert!(SWORD_PRICE == token::value(&gems), EWrongAmount); - ( - Sword { id: object::new(ctx) }, - token::spend(gems, ctx) - ) - } -} - -/// Module that defines the in-game currency: GEMs which can be purchased with -/// SUI and used to buy swords (in the `sword` module). -module examples::gem { - use std::option::none; - use std::string::{Self, String}; - use sui::sui::SUI; - use sui::transfer; - use sui::object::{Self, UID}; - use sui::balance::{Self, Balance}; - use sui::tx_context::{sender, TxContext}; - use sui::coin::{Self, Coin, TreasuryCap}; - - use sui::token::{Self, Token, ActionRequest}; - - /// Trying to purchase Gems with an unexpected amount. - const EUnknownAmount: u64 = 0; - - /// 10 SUI is the price of a small bundle of Gems. - const SMALL_BUNDLE: u64 = 10_000_000_000; - const SMALL_AMOUNT: u64 = 100; - - /// 100 SUI is the price of a medium bundle of Gems. - const MEDIUM_BUNDLE: u64 = 100_000_000_000; - const MEDIUM_AMOUNT: u64 = 5_000; - - /// 1000 SUI is the price of a large bundle of Gems. - /// This is the best deal. - const LARGE_BUNDLE: u64 = 1_000_000_000_000; - const LARGE_AMOUNT: u64 = 100_000; - - #[allow(lint(coin_field))] - /// Gems can be purchased through the `Store`. - struct GemStore has key { - id: UID, - /// Profits from selling Gems. - profits: Balance, - /// The Treasury Cap for the in-game currency. - gem_treasury: TreasuryCap, - } - - /// The OTW to create the in-game currency. - struct GEM has drop {} - - // In the module initializer we create the in-game currency and define the - // rules for different types of actions. - fun init(otw: GEM, ctx: &mut TxContext) { - let (treasury_cap, coin_metadata) = coin::create_currency( - otw, 0, b"GEM", b"Capy Gems", // otw, decimal, symbol, name - b"In-game currency for Capy Miners", none(), // description, url - ctx - ); - - // create a `TokenPolicy` for GEMs - let (policy, cap) = token::new_policy(&treasury_cap, ctx); - - token::allow(&mut policy, &cap, buy_action(), ctx); - token::allow(&mut policy, &cap, token::spend_action(), ctx); - - // create and share the GemStore - transfer::share_object(GemStore { - id: object::new(ctx), - gem_treasury: treasury_cap, - profits: balance::zero() - }); - - // deal with `TokenPolicy`, `CoinMetadata` and `TokenPolicyCap` - transfer::public_freeze_object(coin_metadata); - transfer::public_transfer(cap, sender(ctx)); - token::share_policy(policy); - } - - /// Purchase Gems from the GemStore. Very silly value matching against module - /// constants... - public fun buy_gems( - self: &mut GemStore, payment: Coin, ctx: &mut TxContext - ): (Token, ActionRequest) { - let amount = coin::value(&payment); - let purchased = if (amount == SMALL_BUNDLE) { - SMALL_AMOUNT - } else if (amount == MEDIUM_BUNDLE) { - MEDIUM_AMOUNT - } else if (amount == LARGE_BUNDLE) { - LARGE_AMOUNT - } else { - abort EUnknownAmount - }; - - coin::put(&mut self.profits, payment); - - // create custom request and mint some Gems - let gems = token::mint(&mut self.gem_treasury, purchased, ctx); - let req = token::new_request(buy_action(), purchased, none(), none(), ctx); - - (gems, req) - } - - /// The name of the `buy` action in the `GemStore`. - public fun buy_action(): String { string::utf8(b"buy") } -} -``` \ No newline at end of file diff --git a/docs/content/guides/developer/sui-101/create-coin/regulated.mdx b/docs/content/guides/developer/sui-101/create-coin/regulated.mdx deleted file mode 100644 index f2124713a6a..00000000000 --- a/docs/content/guides/developer/sui-101/create-coin/regulated.mdx +++ /dev/null @@ -1,130 +0,0 @@ ---- -title: Regulated Coin and Deny List -description: You can create regulated coins on Sui, such as stablecoins. These coins are similar to other coins like SUI, but include the ability to control access to the coin using a deny list. ---- - -The Sui [Coin](../../../../standards/coin.mdx) standard provides a `create_regulated_currency` function to create coins. This function is different than `create_currency` in that it generates a coin that you can block certain addresses from being able to use those coins in transactions. This ability is a requirement for assets like stablecoins. - -Behind the scenes, `create_regulated_currency` uses the `create_currency` function to create the coin, but also produces a `DenyCap` object that allows its bearer to control access to the coin's deny list in a `DenyList` object. Consequently, the way to create a coin using `create_regulated_currency` is similar to the previous example, with the addition of a transfer of the `DenyCap` object to the module publisher. - -```move title="regcoin.move" -module examples::regcoin { - use std::option; - use sui::coin; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; - - struct REGCOIN has drop {} - - fun init(witness: REGCOIN, ctx: &mut TxContext) { - let (treasury, deny_cap, metadata) = coin::create_regulated_currency(witness, 6, b"REGCOIN", b"", b"", option::none(), ctx); - transfer::public_freeze_object(metadata); - transfer::public_transfer(treasury, tx_context::sender(ctx)); - transfer::public_transfer(deny_cap, tx_context::sender(ctx)) - } -} -``` - -When you deploy the previous module using `sui client publish`, the console responds with transaction effects, including the creation of the following objects: - -```shell -... - -Object Changes - -Created Objects: - - ObjectID: - Sender: - Owner: Immutable - ObjectType: 0x2::coin::CoinMetadata<::regcoin::REGCOIN> - Version: - Digest: - - ObjectID: - Sender: - Owner: Account Address ( - Digest: - - ObjectID: - Sender: - Owner: Immutable - ObjectType: 0x2::coin::RegulatedCoinMetadata<::regcoin::REGCOIN> - Version: - Digest: - - ObjectID: - Sender: - Owner: Account Address ( ::regcoin::REGCOIN> - Version: - Digest: - - - ObjectID: - Sender: - Owner: Account Address ( ::regcoin::REGCOIN> - Version: - Digest: - -... -``` - -As you might have noticed, the publish action creates a `RegulatedCoinMetadata` object along with the standard `CoinMetadata` object. You don't need to explicitly call the `freeze_object` on the `RegulatedCoinMetadata` object, however, because `create_regulated_currency` automatically performs this action. - -The output also shows the three objects that the publisher now owns: `UpgradeCap` for [package upgrades](../../../../concepts/sui-move-concepts/packages/upgrade.mdx), `TreasuryCap` for minting or burning coins, and the `DenyCap` for adding or removing addresses to or from the deny list for this coin. - -## DenyList - -The Sui framework provides a `DenyList` singleton, shared object that the bearer of a `DenyCap` can access to specify a list of addresses that are unable to use a Sui core type. The initial use case for `DenyList`, however, focuses on limiting access to coins of a specified type. This is useful, for example, when creating a regulated coin on Sui that requires the ability to block certain addresses from using it as inputs to transactions. Regulated coins on Sui satisfy any regulations that require the ability to prevent known bad actors from having access to those coins. - -:::info - -The `DenyList` object is a system object that has the address `0x403`. You cannot create it yourself. - -::: - - -### Manipulate deny list - -For the ability to manipulate the addresses assigned to the deny list for your coin, you must add a few functions to the previous example. - -```move -public fun add_addr_from_deny_list(denylist: &mut DenyList, denycap: &mut DenyCap, denyaddy: address, ctx: &mut TxContext){ - coin::deny_list_add(denylist, denycap, denyaddy, ctx ); -} - -public fun remove_addr_from_deny_list(denylist: &mut DenyList, denycap: &mut DenyCap, denyaddy: address, ctx: &mut TxContext){ - coin::deny_list_remove(denylist, denycap, denyaddy, ctx ); -} -``` - -To use these functions, you pass the `DenyList` object (`0x403`), your `DenyCap` object ID, and the address you want to either add or remove. Using the Sui CLI, you could use `sui client call` with the required information: - -```shell -sui client call --function add_addr_from_deny_list --module regcoin --package --args --gas-budget -Transaction Digest: -``` - -The console displays the response from the network, where you can verify the `DenyList` object is mutated. - -```shell -... - -MutatedObjects: - - ObjectID: 0x0...403 - Sender: - Owner: Shared - ObjectType: 0x2::deny_list::DenyList - Version: - Digest: - -... - -``` - -For all `Coin` functions available, see the Sui framework [`coin` module documentation](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/docs/sui-framework/coin.md). \ No newline at end of file diff --git a/docs/content/guides/developer/sui-101/sign-and-send-txn.mdx b/docs/content/guides/developer/sui-101/sign-and-send-txn.mdx deleted file mode 100644 index a36ae245899..00000000000 --- a/docs/content/guides/developer/sui-101/sign-and-send-txn.mdx +++ /dev/null @@ -1,261 +0,0 @@ ---- -title: Signing and Sending Transactions ---- - -Transactions in Sui represent calls to specific functionality (like calling a smart contract function) that execute on inputs to define the result of the transaction. - -Inputs can either be an object reference (either to an owned object, an immutable object, or a shared object), or an encoded value (for example, a vector of bytes used as an argument to a Move call). After a transaction is constructed, usually through using [programmable transaction blocks](./building-ptb) (PTBs), the user signs the transaction and submits it to be executed on chain. - -The signature is provided with the private key owned by the wallet, and its public key must be consistent with the transaction sender's Sui address. - -Sui uses a `SuiKeyPair` to produce the signature, which commits to the Blake2b hash digest of the intent message (`intent || bcs bytes of tx_data`). The signature schemes currently supported are `Ed25519 Pure`, `ECDSA Secp256k1`, `ECDSA Secp256r1`, `Multisig`, and `zkLogin`. - -You can instantiate `Ed25519 Pure`, `ECDSA Secp256k1`, and `ECDSA Secp256r1` using `SuiKeyPair` and use it to sign transactions. Note that this guide does not apply to `Multisig` and `zkLogin`, please refer to their own pages ([Multisig](/concepts/cryptography/transaction-auth/multisig) and [zkLogin](https://docs.sui.io/concepts/cryptography/zklogin) respectively) for instructions. - -With a signature and the transaction bytes, a transaction can be submitted to be executed. - -## Workflow - -The following high-level process describes the overall workflow for constructing, signing and executing an on-chain transaction: - -- Construct the transaction data by creating a `TransactionBlock` where multiple transactions are chained. See [Building Programmable Transaction Blocks](./building-ptb.mdx) for more information. -- The SDK's built-in gas estimation and coin selection picks the gas coin. -- Sign the transaction to generate a [signature](/concepts/cryptography/transaction-auth/signatures#user-signature). -- Submit the `TransactionBlock` and its signature for on-chain execution. - -:::info - -If you want to use a specific gas coin, first find the gas coin object ID to be used to pay for gas, and explicitly use that in the PTB. If there is no gas coin object, use the [splitCoin](./building-ptb#available-transactions) transaction to create a gas coin object. The split coin transaction should be the first transaction call in the PTB. - -::: - -## Examples - -The following examples demonstrate how to sign and execute transactions using Rust, TypeScript, or the Sui CLI. - - - - - -There are various ways to instantiate a key pair and to derive its public key and Sui address using the Sui TypeScript SDK. - -```tsx -import { fromHEX } from '@mysten/bcs'; -import { getFullnodeUrl, SuiClient } from '@mysten/sui.js/client'; -import { type Keypair } from '@mysten/sui.js/cryptography'; -import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519'; -import { Secp256k1Keypair } from '@mysten/sui.js/keypairs/secp256k1'; -import { Secp256r1Keypair } from '@mysten/sui.js/keypairs/secp256r1'; -import { TransactionBlock } from '@mysten/sui.js/transactions'; - -const kp_rand_0 = new Ed25519Keypair(); -const kp_rand_1 = new Secp256k1Keypair(); -const kp_rand_2 = new Secp256r1Keypair(); - -const kp_import_0 = Ed25519Keypair.fromSecretKey( - fromHex('0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82'), -); -const kp_import_1 = Secp256k1Keypair.fromSecretKey( - fromHex('0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82'), -); -const kp_import_2 = Secp256r1Keypair.fromSecretKey( - fromHex('0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82'), -); - -// $MNEMONICS refers to 12/15/18/21/24 words from the wordlist, e.g. "retire skin goose will hurry this field stadium drastic label husband venture cruel toe wire". Refer to [Keys and Addresses](/concepts/cryptography/transaction-auth/keys-addresses.mdx) for more. -const kp_derive_0 = Ed25519Keypair.deriveKeypair('$MNEMONICS'); -const kp_derive_1 = Secp256k1Keypair.deriveKeypair('$MNEMONICS'); -const kp_derive_2 = Secp256r1Keypair.deriveKeypair('$MNEMONICS'); - -const kp_derive_with_path_0 = Ed25519Keypair.deriveKeypair('$MNEMONICS', "m/44'/4218'/1'/0'/0'"); -const kp_derive_with_path_1 = Secp256k1Keypair.deriveKeypair('$MNEMONICS', "m/54'/4218'/1'/0/0"); -const kp_derive_with_path_2 = Secp256r1Keypair.deriveKeypair('$MNEMONICS', "m/74'/4218'/1'/0/0"); - -// replace `kp_rand_0` with the variable names above. -const pk = kp_rand_0.getPublicKey(); -const sender = pk.toSuiAddress(); - -// create an example transaction block. -const txb = new TransactionBlock(); -txb.setSender(sender); -txb.setGasPrice(5); -txb.setGasBudget(100); -const bytes = await txb.build(); -const serializedSignature = (await keypair.signTransactionBlock(bytes)).signature; - -// verify the signature locally -expect(await keypair.getPublicKey().verifyTransactionBlock(bytes, serializedSignature)).toEqual( - true, -); - -// define sui client for the desired network. -const client = new SuiClient({ url: getFullnodeUrl('testnet') }); - -// execute transaction. -let res = client.executeTransactionBlock({ - transactionBlock: bytes, - signature: serializedSignature, -}); -console.log(res); -``` - - - - - -The full code example below can be found under [crates/sui-sdk](https://github.com/MystenLabs/sui/blob/main/crates/sui-sdk/examples/sign_tx_guide.rs). - -There are various ways to instantiate a `SuiKeyPair` and to derive its public key and Sui address using the Sui Rust SDK. - -```rust - // deterministically generate a keypair, testing only, do not use for mainnet, use the next section to randomly generate a keypair instead. - let skp_determ_0 = - SuiKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))); - let _skp_determ_1 = - SuiKeyPair::Secp256k1(Secp256k1KeyPair::generate(&mut StdRng::from_seed([0; 32]))); - let _skp_determ_2 = - SuiKeyPair::Secp256r1(Secp256r1KeyPair::generate(&mut StdRng::from_seed([0; 32]))); - - // randomly generate a keypair. - let _skp_rand_0 = SuiKeyPair::Ed25519(get_key_pair_from_rng(&mut rand::rngs::OsRng).1); - let _skp_rand_1 = SuiKeyPair::Secp256k1(get_key_pair_from_rng(&mut rand::rngs::OsRng).1); - let _skp_rand_2 = SuiKeyPair::Secp256r1(get_key_pair_from_rng(&mut rand::rngs::OsRng).1); - - // import a keypair from a base64 encoded 32-byte `private key`. - let _skp_import_no_flag_0 = SuiKeyPair::Ed25519(Ed25519KeyPair::from_bytes( - &Base64::decode("1GPhHHkVlF6GrCty2IuBkM+tj/e0jn64ksJ1pc8KPoI=") - .map_err(|_| anyhow!("Invalid base64"))?, - )?); - let _skp_import_no_flag_1 = SuiKeyPair::Ed25519(Ed25519KeyPair::from_bytes( - &Base64::decode("1GPhHHkVlF6GrCty2IuBkM+tj/e0jn64ksJ1pc8KPoI=") - .map_err(|_| anyhow!("Invalid base64"))?, - )?); - let _skp_import_no_flag_2 = SuiKeyPair::Ed25519(Ed25519KeyPair::from_bytes( - &Base64::decode("1GPhHHkVlF6GrCty2IuBkM+tj/e0jn64ksJ1pc8KPoI=") - .map_err(|_| anyhow!("Invalid base64"))?, - )?); - - // import a keypair from a base64 encoded 33-byte `flag || private key`. The signature scheme is determined by the flag. - let _skp_import_with_flag_0 = - SuiKeyPair::decode_base64("ANRj4Rx5FZRehqwrctiLgZDPrY/3tI5+uJLCdaXPCj6C") - .map_err(|_| anyhow!("Invalid base64"))?; - let _skp_import_with_flag_1 = - SuiKeyPair::decode_base64("AdRj4Rx5FZRehqwrctiLgZDPrY/3tI5+uJLCdaXPCj6C") - .map_err(|_| anyhow!("Invalid base64"))?; - let _skp_import_with_flag_2 = - SuiKeyPair::decode_base64("AtRj4Rx5FZRehqwrctiLgZDPrY/3tI5+uJLCdaXPCj6C") - .map_err(|_| anyhow!("Invalid base64"))?; - - // replace `skp_determ_0` with the variable names above - let pk = skp_determ_0.public(); - let sender = SuiAddress::from(&pk); -``` - -Next, sign transaction data constructed using an example programmable transaction block with default gas coin, gas budget, and gas price. See [Building Programmable Transaction Blocks](./building-ptb.mdx) for more information. - -```rust - // construct an example programmable transaction. - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - builder.pay_sui(vec![sender], vec![1])?; - builder.finish() - }; - - let gas_budget = 5_000_000; - let gas_price = sui_client.read_api().get_reference_gas_price().await?; - - // create the transaction data that will be sent to the network. - let tx_data = TransactionData::new_programmable( - sender, - vec![gas_coin.object_ref()], - pt, - gas_budget, - gas_price, - ); -``` - -Commit a signature to the Blake2b hash digest of the intent message (`intent || bcs bytes of tx_data`). - -```rust - // derive the digest that the keypair should sign on, i.e. the blake2b hash of `intent || tx_data`. - let intent_msg = IntentMessage::new(Intent::sui_transaction(), tx_data); - let raw_tx = bcs::to_bytes(&intent_msg).expect("bcs should not fail"); - let mut hasher = sui_types::crypto::DefaultHash::default(); - hasher.update(raw_tx.clone()); - let digest = hasher.finalize().digest; - - // use SuiKeyPair to sign the digest. - let sui_sig = skp_determ_0.sign(&digest); - - // if you would like to verify the signature locally before submission, use this function. if it fails to verify locally, the transaction will fail to execute in Sui. - let res = sui_sig.verify_secure( - &intent_msg, - sender, - sui_types::crypto::SignatureScheme::ED25519, - ); - assert!(res.is_ok()); -``` - -Finally, submit the transaction with the signature. - -```rust - let transaction_response = sui_client - .quorum_driver_api() - .execute_transaction_block( - sui_types::transaction::Transaction::from_generic_sig_data( - intent_msg.value, - Intent::sui_transaction(), - vec![GenericSignature::Signature(sui_sig)], - ), - SuiTransactionBlockResponseOptions::default(), - None, - ) - .await?; -``` - - - - - -When using the [Sui CLI](/references/cli.mdx) for the first time, it creates a local file in `~/.sui/keystore` on your machine with a list of private keys (encoded as Base64 encoded `flag || 32-byte-private-key`). You can use any key to sign transactions by specifying its address. Use `sui keytool list` to see a list of addresses. - -There are three ways to initialize a key: - -```shell -# generate randomly. -sui client new-address ed25519 -sui client new-address secp256k1 -sui client new-address secp256r1 - -# import the 32-byte private key to keystore. -sui keytool import "0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82" ed25519 -sui keytool import "0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82" secp256k1 -sui keytool import "0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82" secp256r1 - -# import the mnemonics (recovery phrase) with derivation path to keystore. -# $MNEMONICS refers to 12/15/18/21/24 words from the wordlist, e.g. "retire skin goose will hurry this field stadium drastic label husband venture cruel toe wire". Refer to [Keys and Addresses](/concepts/cryptography/transaction-auth/keys-addresses.mdx) for more. - -sui keytool import "$MNEMONICS" ed25519 -sui keytool import "$MNEMONICS" secp256k1 -sui keytool import "$MNEMONICS" secp256r1 -``` - -Create a transfer transaction in CLI. Set the $SUI_ADDRESS to the one corresponding to the keypair used to sign. $GAS_COIN_ID refers to the object ID that is owned by the sender to be used as gas. $GAS_BUDGET refers to the budget used to execute transaction. Then sign with the private key corresponding to the sender address. $MNEMONICS refers to 12/15/18/21/24 words from the wordlist, e.g. "retire skin goose will hurry this field stadium drastic label husband venture cruel toe wire". Refer to [Keys and Addresses](/concepts/cryptography/transaction-auth/keys-addresses.mdx) for more. - -```shell -sui client gas -sui client transfer-sui --to $SUI_ADDRESS --sui-coin-object-id $GAS_COIN_ID --gas-budget $GAS_BUDGET --serialize-unsigned-transaction -sui keytool sign --address $SUI_ADDRESS --data $TX_BYTES -sui client execute-signed-tx --tx-bytes $TX_BYTES --signatures $SERIALIZED_SIGNATURE -``` - - - - -### Notes - -1. This guide demonstrates how to sign with a single private key. Refer to [Multisig](/concepts/cryptography/transaction-auth/multisig.mdx) when it is preferred to set up more complex signing policies. -2. Similarly, native zkLogin does not follow the above steps, see [the docs](/concepts/cryptography/zklogin.mdx) to understand how to derive a zkLogin address, and produce a zkLogin signature with an ephemeral key pair. -3. If you decide to implement your own signing mechanisms instead of using the previous tools, see the [Signatures](/concepts/cryptography/transaction-auth/signatures.mdx) doc on the accepted signature specifications for each scheme. -4. Flag is one byte that differentiates signature schemes. See supported schemes and its flag in [Signatures](/concepts/cryptography/transaction-auth/signatures.mdx). -5. The `execute_transaction_block` endpoint takes a list of signatures, so it should contain exactly one user signature, unless you are using sponsored transaction that a second signature for the gas object can be provided. See [Sponsored Transactions](/concepts/transactions/sponsored-transactions.mdx) for more information. diff --git a/docs/content/guides/developer/sui-101/working-with-ptbs.mdx b/docs/content/guides/developer/sui-101/working-with-ptbs.mdx deleted file mode 100644 index 035d005006a..00000000000 --- a/docs/content/guides/developer/sui-101/working-with-ptbs.mdx +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: Working with Programmable Transaction Blocks ---- - -Programmable transaction blocks (PTBs) are key elements of the Sui ecosystem. Understanding PTBs and using them correctly are key fundamentals to creating efficient and cost-effective smart contracts. See [Programmable Transaction Blocks](../../../concepts/transactions/prog-txn-blocks.mdx) to learn about the structure of PTBs on Sui. - -The topics in this section focus on effectively utilizing PTBs in your smart contracts. - -## Building Programmable Transaction Blocks - -To fully appreciate the possibilities PTBs offer, you must build them. Using tools like the [Sui TypeScript SDK](https://sdk.mystenlabs.com/typescript), you can begin to understand the power and flexibility they provide. - -Go to [Building Programmable Transaction Blocks](./building-ptb.mdx). - -## Coin Management - -`Coin` objects on Sui are different than other blockchains in that they are [owned objects](../../../concepts/object-ownership/address-owned.mdx). Whether you need your smart contract to utilize SUI for gas payments or deal with generic coins, understanding coin management is crucial. Smart contracts use common patterns to accept coins and the PTBs you create must provide the correct interface to those smart contracts to facilitate successful transactions. - -Go to [Coin Management](./coin-mgt.mdx). - -## Simulating References - -The [`borrow` module](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/docs/sui-framework/borrow.md) of the Sui framework offers some features you can use when your PTBs use objects by reference. - -Go to [Simulating References](./simulating-refs.mdx). - -## Related links - -Review this content for a complete picture of PTBs on Sui. - -- [Programmable Transaction Blocks](../../../concepts/transactions/prog-txn-blocks.mdx): Conceptual overview of the PTB architecture. -- [Life of a Transaction](../../../concepts/sui-architecture/transaction-lifecycle.mdx): Discover the life of a transaction from inception to finality. \ No newline at end of file diff --git a/docs/content/guides/operator.mdx b/docs/content/guides/operator.mdx index d9326de7d37..e0c607ab5bc 100644 --- a/docs/content/guides/operator.mdx +++ b/docs/content/guides/operator.mdx @@ -1,25 +1,25 @@ --- title: Operator Guides -description: Guides for operators on the Sui network. Whether you are running a Full node for your dApp or operating as a validator on the Sui network, these guides help you set up your environment and operate your network. +description: Guides for operators on the Iota network. Whether you are running a Full node for your dApp or operating as a validator on the Iota network, these guides help you set up your environment and operate your network. --- -Operator guides demonstrate how to run Full nodes on Sui, whether as a validator or operator of a Full node to support your dApp, as well as how to integrate SUI into an exchange. +Operator guides demonstrate how to run Full nodes on Iota, whether as a validator or operator of a Full node to support your dApp, as well as how to integrate IOTA into an exchange. -## Sui Full node operators +## Iota Full node operators Guides that inform Full node operators include: -- [Sui Full Node Configuration](./operator/sui-full-node.mdx) +- [Iota Full Node Configuration](./operator/iota-full-node.mdx) -## Sui validators +## Iota validators -Guides that inform validators how to operate on Sui include: +Guides that inform validators how to operate on Iota include: - [Validator Committee](./operator/validator-committee.mdx) - [Validator Configuration](./operator/validator-config.mdx) - [Validator Tasks](./operator/validator-tasks.mdx) -## Sui Full node operators and validators +## Iota Full node operators and validators Guides that benefit both Full node operators and validators include: @@ -30,4 +30,4 @@ Guides that benefit both Full node operators and validators include: ## Exchange integration guide -The [Sui Exchange Integration Guide](./operator/exchange-integration.mdx) provides step-by-step instructions on how to integrate SUI into a cryptocurrency exchange. \ No newline at end of file +The [Iota Exchange Integration Guide](./operator/exchange-integration.mdx) provides step-by-step instructions on how to integrate IOTA into a cryptocurrency exchange. \ No newline at end of file diff --git a/docs/content/guides/operator/archives.mdx b/docs/content/guides/operator/archives.mdx index 8a0a2e1e25a..a30cfc09605 100644 --- a/docs/content/guides/operator/archives.mdx +++ b/docs/content/guides/operator/archives.mdx @@ -1,15 +1,15 @@ --- -title: Sui Archives -description: The archive is a historical record of all transactions on Sui. Enable archiving on your Full nodes as a best practice. +title: Iota Archives +description: The archive is a historical record of all transactions on Iota. Enable archiving on your Full nodes as a best practice. --- -A Sui archive is a history of all transaction data on Sui, trailing behind the latest checkpoint by 10 minutes. As a Sui node operator, you can write this history to an object store like S3, GCS, or similar for safe keeping. Saving this archive data is considered a best practice because Sui prunes transactions on Full nodes to remove historical transactions and their effects. Peer nodes, for example, might not catch up with all transactions and effects through synchronization if they lag behind the current epoch by more than the latest few epochs. Instead of relying on synchronization, peer nodes can fallback to downloading this information from an archive. +A Iota archive is a history of all transaction data on Iota, trailing behind the latest checkpoint by 10 minutes. As a Iota node operator, you can write this history to an object store like S3, GCS, or similar for safe keeping. Saving this archive data is considered a best practice because Iota prunes transactions on Full nodes to remove historical transactions and their effects. Peer nodes, for example, might not catch up with all transactions and effects through synchronization if they lag behind the current epoch by more than the latest few epochs. Instead of relying on synchronization, peer nodes can fallback to downloading this information from an archive. -Sui Archival nodes (Full nodes that write to an archive) don't store historical state on local storage and don't help query historical data. They serve the purpose of enabling peer nodes to catch up to the latest checkpoint and are useful for auditing and verifying the complete history of all transactions on the network. +Iota Archival nodes (Full nodes that write to an archive) don't store historical state on local storage and don't help query historical data. They serve the purpose of enabling peer nodes to catch up to the latest checkpoint and are useful for auditing and verifying the complete history of all transactions on the network. ## Create an Archival node -To start storing transaction history as an archive, you need to modify your node configuration. Open your fullnode.yaml file and add the following configuration. By default, the fullnode.yaml file is located in your `~/.sui/sui_config` directory. +To start storing transaction history as an archive, you need to modify your node configuration. Open your fullnode.yaml file and add the following configuration. By default, the fullnode.yaml file is located in your `~/.iota/iota_config` directory. ```yaml state-archive-write-config: diff --git a/docs/content/guides/operator/data-management.mdx b/docs/content/guides/operator/data-management.mdx index 8e0ab64da87..9119a03fc69 100644 --- a/docs/content/guides/operator/data-management.mdx +++ b/docs/content/guides/operator/data-management.mdx @@ -1,58 +1,58 @@ --- title: Data Management -description: A high-level description of data management on the Sui network that you can use to optimize your Sui Full node configuration. +description: A high-level description of data management on the Iota network that you can use to optimize your Iota Full node configuration. --- -Managing the data on your Sui Full node is critical to ensuring a healthy Sui network. This topic provides a high-level description of data management on Sui Full nodes that you can use to optimize your Full node configuration. For more information about Sui Full nodes, such as pruning policies and archival settings, see [Run a Sui Full Node](./sui-full-node.mdx). +Managing the data on your Iota Full node is critical to ensuring a healthy Iota network. This topic provides a high-level description of data management on Iota Full nodes that you can use to optimize your Full node configuration. For more information about Iota Full nodes, such as pruning policies and archival settings, see [Run a Iota Full Node](./iota-full-node.mdx). -## Basic Sui Full node functionality +## Basic Iota Full node functionality -The minimal version of a Sui Full node executes all of the transactions Sui validators commit. Sui Full nodes also orchestrate the submitting of new transactions to the system: +The minimal version of a Iota Full node executes all of the transactions Iota validators commit. Iota Full nodes also orchestrate the submitting of new transactions to the system: -![Basic Sui Full node functionality](./images/fn-basic-functionality.png "A diagram that shows the operations of a basic Sui Full node.") +![Basic Iota Full node functionality](./images/fn-basic-functionality.png "A diagram that shows the operations of a basic Iota Full node.") The preceding image shows how data flows through a Full node: -1. **`State sync` protocol:** A Sui Full node performs the following to achieve state synchronization: +1. **`State sync` protocol:** A Iota Full node performs the following to achieve state synchronization: - Retrieves the information about the committed checkpoints via the p2p gossip-like protocol - Executes the transactions locally to verify that effects match the effects certified by the quorum of the validators - Updates the local state with the latest object values accordingly. -2. **RPCs:** A Sui Full node exposes Sui RPC endpoints for querying the latest state of the system, including both the latest state metadata (such as, `sui_getProtocolConfig`), and the latest state object data (`sui_getObject)`. -3. **Transaction submission:** Each Sui Full node orchestrates transaction submission to the quorum of the Sui Validators, and, optionally if configured, locally executes the finalized transactions (called fast path execution), which circumvents the wait for checkpoint synchronization. +2. **RPCs:** A Iota Full node exposes Iota RPC endpoints for querying the latest state of the system, including both the latest state metadata (such as, `iota_getProtocolConfig`), and the latest state object data (`iota_getObject)`. +3. **Transaction submission:** Each Iota Full node orchestrates transaction submission to the quorum of the Iota Validators, and, optionally if configured, locally executes the finalized transactions (called fast path execution), which circumvents the wait for checkpoint synchronization. -## Sui Full node Data and RPC types +## Iota Full node Data and RPC types -A Sui Full Node stores multiple categories of data in its permanent store. +A Iota Full Node stores multiple categories of data in its permanent store. :::info -The per-epoch Sui store is beyond the scope of this topic. Sui uses the per-epoch store (resets at the start of each epoch) internally for authority and consensus operations. +The per-epoch Iota store is beyond the scope of this topic. Iota uses the per-epoch store (resets at the start of each epoch) internally for authority and consensus operations. ::: -Sui Full nodes store the following types of data: +Iota Full nodes store the following types of data: -1. **Transactions with associated effects and events:** Sui uses a unique transaction digest to retrieve information about a transaction, including its effects and emitted events. Sui Full nodes don't require the historic transaction information for basic Full node operations. To conserve drive space, you can enable pruning to remove this historical data. -2. **Checkpoints:** Sui groups committed transactions in checkpoints, and then uses those checkpoints to achieve state synchronization. Checkpoints keep transaction digests that contain additional integrity metadata. -Sui Full nodes don't require data from checkpoints to execute and submit transactions, so you can configure pruning for this data as well. -3. **Objects:** Transactions that mutate objects create new object versions. Each object has a unique pair of `(objectId, version)` used to identify the object. Sui Full nodes don't require historic object versions to execute and submit transactions, so you can configure your Full node to also prune this data. +1. **Transactions with associated effects and events:** Iota uses a unique transaction digest to retrieve information about a transaction, including its effects and emitted events. Iota Full nodes don't require the historic transaction information for basic Full node operations. To conserve drive space, you can enable pruning to remove this historical data. +2. **Checkpoints:** Iota groups committed transactions in checkpoints, and then uses those checkpoints to achieve state synchronization. Checkpoints keep transaction digests that contain additional integrity metadata. +Iota Full nodes don't require data from checkpoints to execute and submit transactions, so you can configure pruning for this data as well. +3. **Objects:** Transactions that mutate objects create new object versions. Each object has a unique pair of `(objectId, version)` used to identify the object. Iota Full nodes don't require historic object versions to execute and submit transactions, so you can configure your Full node to also prune this data. 4. **Indexing information:** A Full node default configuration is to post-process the committed transactions: it indexes the committed information to enable efficient aggregation and filtering queries. For example, the indexing can be useful for retrieving all the historic transactions of a given sender, or finding all the objects owned by an address. -Sui Full nodes support more than 40 RPC types that includes the following categories: +Iota Full nodes support more than 40 RPC types that includes the following categories: -* **General metadata**, such as `sui_getProtocolConfig` and `sui_getChainIdentier`. These requests don't depend on additional indexing and don't require historic data to process. -* **Direct lookups**, such as `sui_getObject`, `sui_getEvents`. These requests don't depend on additional indexing, but require historic data in some cases, such as `sui_tryGetPastObject` and `sui_getTransactionBlock`. -* **Accumulation and filtering queries**,such as `suix_getOwnedObjects` and `suix_getCoins`. These requests depend on additional indexing, and require historic data in some cases, such as `suix_queryTransactionBlocks`. +* **General metadata**, such as `iota_getProtocolConfig` and `iota_getChainIdentier`. These requests don't depend on additional indexing and don't require historic data to process. +* **Direct lookups**, such as `iota_getObject`, `iota_getEvents`. These requests don't depend on additional indexing, but require historic data in some cases, such as `iota_tryGetPastObject` and `iota_getTransactionBlock`. +* **Accumulation and filtering queries**,such as `iotax_getOwnedObjects` and `iotax_getCoins`. These requests depend on additional indexing, and require historic data in some cases, such as `iotax_queryTransactionBlocks`. :::info -Sui plans to migrate the RPC endpoints that require additional indexing away from Sui Full nodes in the near future. This plan decouples the storage that is backing transaction execution from the storage that is better suited for data indexing. +Iota plans to migrate the RPC endpoints that require additional indexing away from Iota Full nodes in the near future. This plan decouples the storage that is backing transaction execution from the storage that is better iotated for data indexing. ::: -## Sui Archival data +## Iota Archival data -A Sui archive instance stores the full Sui transaction history since genesis in a database agnostic format. This includes information about transactions (with client authentication), effects, events, and checkpoints. As such, archival storage can be used for data auditing and for replaying historic transactions. +A Iota archive instance stores the full Iota transaction history since genesis in a database agnostic format. This includes information about transactions (with client authentication), effects, events, and checkpoints. As such, archival storage can be used for data auditing and for replaying historic transactions. :::info @@ -60,21 +60,21 @@ The current archival storage format doesn't include historic object versions. ::: -As a Full node operator, you can [enable archival fallback for your Full node](./sui-full-node.mdx#set-up-archival-fallback) by specifying the URL to upload archival data. Currently, Mysten Labs manages a Sui archive and stores it in AWS S3. To ensure a healthy network, we encourage the Sui community to set up additional archives to ensure archival data availability across the network. In a typical configuration, an archive trails behind the latest checkpoint by approximately 10 minutes. +As a Full node operator, you can [enable archival fallback for your Full node](./iota-full-node.mdx#set-up-archival-fallback) by specifying the URL to upload archival data. Currently, Mysten Labs manages a Iota archive and stores it in AWS S3. To ensure a healthy network, we encourage the Iota community to set up additional archives to ensure archival data availability across the network. In a typical configuration, an archive trails behind the latest checkpoint by approximately 10 minutes. -A Full Node that starts from scratch can replay (and thus re-verify) transactions that occurred since Sui genesis from the given archive via [configuring Archival Fallback](./sui-full-node.mdx#archival-fallback) in the `fullnode.yaml` configuration file to point to the S3 bucket that stores the archive. +A Full Node that starts from scratch can replay (and thus re-verify) transactions that occurred since Iota genesis from the given archive via [configuring Archival Fallback](./iota-full-node.mdx#archival-fallback) in the `fullnode.yaml` configuration file to point to the S3 bucket that stores the archive. -A Sui Full node that fails to retrieve checkpoints from its peers via state sync protocol falls back to downloading the missing checkpoints from its pre-configured archive. This fallback enables a Full node to catch up with the rest of the system regardless of the pruning policies of its peers. +A Iota Full node that fails to retrieve checkpoints from its peers via state sync protocol falls back to downloading the missing checkpoints from its pre-configured archive. This fallback enables a Full node to catch up with the rest of the system regardless of the pruning policies of its peers. -## Sui Full node pruning policies +## Iota Full node pruning policies -As described previously, sustainable disk usage requires Sui Full nodes to prune the information about historic object versions as well as historic transactions with the corresponding effects and events, including old checkpoint data. +As described previously, sustainable disk usage requires Iota Full nodes to prune the information about historic object versions as well as historic transactions with the corresponding effects and events, including old checkpoint data. Both transaction and object pruners run in the background. The logical deletion of entries from RocksDB ultimately triggers the physical compaction of data on disk, which is governed by RocksDB background jobs: the pruning effect on disk usage is not immediate and might take multiple days. -To learn more about object pruning policies, see [Object pruning](./sui-full-node.mdx#object-pruning). You can configure the pruner in two modes: -* **aggressive pruning** (`num-epochs-to-retain: 0`): Preferred option. Sui prunes old object versions as soon as possible. -* **epoch-based pruning** (`num-epochs-to-retain: X`): Sui prunes old object versions after X epochs. +To learn more about object pruning policies, see [Object pruning](./iota-full-node.mdx#object-pruning). You can configure the pruner in two modes: +* **aggressive pruning** (`num-epochs-to-retain: 0`): Preferred option. Iota prunes old object versions as soon as possible. +* **epoch-based pruning** (`num-epochs-to-retain: X`): Iota prunes old object versions after X epochs. :::tip @@ -82,29 +82,29 @@ Testing indicates that aggressive pruning results in more efficient Full Node op ::: -To learn more about transaction pruning policies, see [Transaction pruning](./sui-full-node.mdx#transaction-pruning). To configure transaction pruning, specify the `num-epochs-to-retain-for-checkpoints: X` config option. The checkpoints, including their transactions, effects and events are pruned up to X epochs ago. We suggest setting transaction pruning to 2 epochs. +To learn more about transaction pruning policies, see [Transaction pruning](./iota-full-node.mdx#transaction-pruning). To configure transaction pruning, specify the `num-epochs-to-retain-for-checkpoints: X` config option. The checkpoints, including their transactions, effects and events are pruned up to X epochs ago. We suggest setting transaction pruning to 2 epochs. ### Set an archiving watermark -In case your Full node is configured to upload committed information to an archive, you should ensure that pruning doesn't occur until after the corresponding data is uploaded. To do so, set the `use-for-pruning-watermark: true` in the Fullnode.yaml file as described in [Archival fallback](./sui-full-node.mdx#archival-fallback). +In case your Full node is configured to upload committed information to an archive, you should ensure that pruning doesn't occur until after the corresponding data is uploaded. To do so, set the `use-for-pruning-watermark: true` in the Fullnode.yaml file as described in [Archival fallback](./iota-full-node.mdx#archival-fallback). -## Sui Full node key-value store backup +## Iota Full node key-value store backup -To enable historic data queries for the Sui Full nodes that prune old transactional data, Full node RPC implementation is configured to fallback for querying missing transactional data from a remote store. +To enable historic data queries for the Iota Full nodes that prune old transactional data, Full node RPC implementation is configured to fallback for querying missing transactional data from a remote store. If the information about the transaction digest, effects, events, or checkpoints is not available locally, a Full node automatically retrieves the historical data from a cloud-based key-value store (currently managed by MystenLabs). Note that the current key-value store implementation keeps historic transactional data only: we plan to provide support for a similar setup for retrieving the historic object versions in a future release. ## Pruning policy examples -Use the examples in this section to configure your Sui Full node. You can copy the examples, and then, optionally, modify the values as appropriate for your environment. +Use the examples in this section to configure your Iota Full node. You can copy the examples, and then, optionally, modify the values as appropriate for your environment. ### Minimal Full node This configuration keeps disk usage to a minimum. A Full node with this configuration cannot answer queries that require indexing or historic data. ```yaml -# Do not generate or maintain indexing of Sui data on the node +# Do not generate or maintain indexing of Iota data on the node enable-index-processing: false authority-store-pruning-config: @@ -126,10 +126,10 @@ authority-store-pruning-config: This setup manages secondary indexing in addition to the latest state, but aggressively prunes historic data. A Full node with this configuration: -- Answers RPC queries that require indexing, like `suix_getBalance()`. -- Answers RPC queries that require historic transactions via a fallback to retrieve the data from a remote key-value store: `sui_getTransactionBlock()`. -- Cannot answer RPC queries that require historic object versions: `sui_tryGetPastObject()`. - - The `showBalanceChanges` filter of `sui_getTransactionBlock()` query relies on historic object versions, so it can't work with this configuration. +- Answers RPC queries that require indexing, like `iotax_getBalance()`. +- Answers RPC queries that require historic transactions via a fallback to retrieve the data from a remote key-value store: `iota_getTransactionBlock()`. +- Cannot answer RPC queries that require historic object versions: `iota_tryGetPastObject()`. + - The `showBalanceChanges` filter of `iota_getTransactionBlock()` query relies on historic object versions, so it can't work with this configuration. ```yaml authority-store-pruning-config: @@ -149,7 +149,7 @@ authority-store-pruning-config: ### Full Node with full object history but pruned transaction history -This configuration manages the full object history while still pruning historic transactions. A Full node with this configuration can answer all historic and indexing queries (using the transaction query fallback for transactional data), including the ones that require historic objects such as the `showBalanceChanges` filter of `sui_getTransactionBlock()`. +This configuration manages the full object history while still pruning historic transactions. A Full node with this configuration can answer all historic and indexing queries (using the transaction query fallback for transactional data), including the ones that require historic objects such as the `showBalanceChanges` filter of `iota_getTransactionBlock()`. The main caveat is that the current setup enables **transaction pruner** to go ahead of **object pruner**. The object pruner might not be able to properly clean up the objects modified by the transactions that have been already pruned. You should closely monitor the disk space growth on a Full node with this configuration. diff --git a/docs/content/guides/operator/exchange-integration.mdx b/docs/content/guides/operator/exchange-integration.mdx index c37fb0b5f46..bfeb2534bcc 100644 --- a/docs/content/guides/operator/exchange-integration.mdx +++ b/docs/content/guides/operator/exchange-integration.mdx @@ -1,32 +1,32 @@ --- -title: Sui Exchange Integration Guide -description: Learn the primary tasks necessary to integrate SUI, the token native to the Sui network, into a cryptocurrency exchange. +title: Iota Exchange Integration Guide +description: Learn the primary tasks necessary to integrate IOTA, the token native to the Iota network, into a cryptocurrency exchange. --- -This topic describes how to integrate SUI, the token native to the Sui network, into a cryptocurrency exchange. The specific requirements and processes to implement an integration vary between exchanges. Rather than provide a step-by-step guide, this topic provides information about the primary tasks necessary to complete an integration. After the guidance about how to configure an integration, you can also find information and code samples related to staking on the Sui network. +This topic describes how to integrate IOTA, the token native to the Iota network, into a cryptocurrency exchange. The specific requirements and processes to implement an integration vary between exchanges. Rather than provide a step-by-step guide, this topic provides information about the primary tasks necessary to complete an integration. After the guidance about how to configure an integration, you can also find information and code samples related to staking on the Iota network. -## Requirements to configure a SUI integration +## Requirements to configure a IOTA integration -The requirements to configure a SUI integration include: - - A Sui Full node. You can operate your own Sui Full node or use a Full node from a node operator. - - Suggested hardware requirements to run a Sui Full node: +The requirements to configure a IOTA integration include: + - A Iota Full node. You can operate your own Iota Full node or use a Full node from a node operator. + - Suggested hardware requirements to run a Iota Full node: - CPU: 8 physical cores / 16 vCPUs - RAM: 128 GB - Storage (SSD): 4 TB NVMe drive -For best results, run Sui Full nodes on Linux. Sui supports the Ubuntu and Debian distributions. You can also fun a Full node on macOS. +For best results, run Iota Full nodes on Linux. Iota supports the Ubuntu and Debian distributions. You can also fun a Full node on macOS. -## Configure a Sui Full node +## Configure a Iota Full node -You can set up and configure a [Sui Full node](./sui-full-node.mdx) using Docker or directly from source code in the Sui GitHub repository. +You can set up and configure a [Iota Full node](./iota-full-node.mdx) using Docker or directly from source code in the Iota GitHub repository. -## Set up Sui addresses +## Set up Iota addresses -Sui addresses do not require on-chain initialization, you can spend from an address if it corresponds to your private key. You can derive a 32-byte Sui address by hashing the signature scheme flag byte concatenated with public key bytes `flag || pubkey` using the [BLAKE2b](https://www.blake2.net/) (256 bits output) hashing function. +Iota addresses do not require on-chain initialization, you can spend from an address if it corresponds to your private key. You can derive a 32-byte Iota address by hashing the signature scheme flag byte concatenated with public key bytes `flag || pubkey` using the [BLAKE2b](https://www.blake2.net/) (256 bits output) hashing function. -Currently, Sui address supports these signature schemes: pure Ed25519, Secp256k1, Secp256r1 and multisig. The corresponding flag bytes are 0x00, 0x01, 0x02, 0x03 respectively. +Currently, Iota address supports these signature schemes: pure Ed25519, Secp256k1, Secp256r1 and multisig. The corresponding flag bytes are 0x00, 0x01, 0x02, 0x03 respectively. -The following code sample demonstrates how to derive a Sui address in Rust: +The following code sample demonstrates how to derive a Iota address in Rust: ```rust let flag = 0x00; // 0x00 = ED25519, 0x01 = Secp256k1, 0x02 = Secp256r1, 0x03 = multiSig @@ -35,23 +35,23 @@ let mut hasher = DefaultHash::default(); hasher.update([flag]); hasher.update(pk); let arr = hasher.finalize(); -let sui_address_string = hex::encode(arr); +let iota_address_string = hex::encode(arr); ``` ## Displaying addresses -Sui supports both addresses with and without a `0x` prefix. Sui recommends that you always include the `0x` prefix in API calls and when you display user addresses. +Iota supports both addresses with and without a `0x` prefix. Iota recommends that you always include the `0x` prefix in API calls and when you display user addresses. ## Track balance changes for an address -You can track balance changes by calling `sui_getBalance` at predefined intervals. This call returns the total balance for an address. The total includes any coin or token type, but this document focuses on SUI. You can track changes in the total balance for an address between subsequent `sui_getBalance` requests. +You can track balance changes by calling `iota_getBalance` at predefined intervals. This call returns the total balance for an address. The total includes any coin or token type, but this document focuses on IOTA. You can track changes in the total balance for an address between subsequent `iota_getBalance` requests. -The following bash example demonstrates how to use `sui_getBalance` for address `0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3`. If you use a network other than Devnet, replace the value for `rpc` with the URL to the appropriate Full node. +The following bash example demonstrates how to use `iota_getBalance` for address `0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3`. If you use a network other than Devnet, replace the value for `rpc` with the URL to the appropriate Full node. ```bash -rpc="https://fullnode.devnet.sui.io:443" +rpc="https://fullnode.devnet.iota.io:443" address="0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3" -data="{\"jsonrpc\": \"2.0\", \"method\": \"sui_getBalance\", \"id\": 1, \"params\": [\"$address\"]}" +data="{\"jsonrpc\": \"2.0\", \"method\": \"iota_getBalance\", \"id\": 1, \"params\": [\"$address\"]}" curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc ``` @@ -60,7 +60,7 @@ The response is a JSON object that includes the `totalBalance` for the address: { "jsonrpc":"2.0", "result":{ - "coinType":"0x2::sui::SUI", + "coinType":"0x2::iota::IOTA", "coinObjectCount":40, "totalBalance":10000000000, "lockedBalance":{ @@ -71,20 +71,20 @@ The response is a JSON object that includes the `totalBalance` for the address: } ``` -The following example demonstrates using `sui_getBalance` in Rust: +The following example demonstrates using `iota_getBalance` in Rust: ```rust use std::str::FromStr; -use sui_sdk::types::base_types::SuiAddress; -use sui_sdk::{SuiClient, SuiClientBuilder}; +use iota_sdk::types::base_types::IotaAddress; +use iota_sdk::{IotaClient, IotaClientBuilder}; #[tokio::main] async fn main() -> Result<(), anyhow::Error> { - let sui = SuiClientBuilder::default().build( - "https://fullnode.devnet.sui.io:443", + let iota = IotaClientBuilder::default().build( + "https://fullnode.devnet.iota.io:443", ).await.unwrap(); - let address = SuiAddress::from_str("0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3")?; - let objects = sui.read_api().get_balance(address).await?; + let address = IotaAddress::from_str("0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3")?; + let objects = iota.read_api().get_balance(address).await?; println!("{:?}", objects); Ok(()) } @@ -92,13 +92,13 @@ async fn main() -> Result<(), anyhow::Error> { ## Use events to track balance changes for an address -You can also track the balance for an address by subscribing to all of the events emitted from it. Use a filter to include only the events related to SUI coins, such as when the address acquires a coin or pays for a gas fee. +You can also track the balance for an address by subscribing to all of the events emitted from it. Use a filter to include only the events related to IOTA coins, such as when the address acquires a coin or pays for a gas fee. The following example demonstrates how to filter events for an address using bash and cURL: ```bash -rpc="https://fullnode.devnet.sui.io:443" +rpc="https://fullnode.devnet.iota.io:443" address="0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3" -data="{\"jsonrpc\": \"2.0\", \"id\":1, \"method\": \"sui_getEvents\", \"params\": [{\"Recipient\": {\"AddressOwner\": \"0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3\"}}, null, null, true ]}" +data="{\"jsonrpc\": \"2.0\", \"id\":1, \"method\": \"iota_getEvents\", \"params\": [{\"Recipient\": {\"AddressOwner\": \"0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3\"}}, null, null, true ]}" curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc ``` @@ -123,76 +123,76 @@ nextCursor : {"txDigest": "GZQN9pE3Zr9ZfLzBK1BfVCXtbjx5xKMxPSEKaHDvL3E2","eventS ## Blocks vs checkpoints -Sui is a DAG-based blockchain and uses checkpoints for node synchronization and global transaction ordering. Checkpoints differ from blocks in the following ways: - - Sui creates checkpoints and adds finalized transactions. Note that transactions are finalized even before they are included in a checkpoint +Iota is a DAG-based blockchain and uses checkpoints for node synchronization and global transaction ordering. Checkpoints differ from blocks in the following ways: + - Iota creates checkpoints and adds finalized transactions. Note that transactions are finalized even before they are included in a checkpoint - Checkpoints do not fork, roll back, or reorganize. - - Sui creates one checkpoint about every 3 seconds. + - Iota creates one checkpoint about every 3 seconds. ### Checkpoint API operations -Sui Checkpoint API operations include: - - [sui_getCheckpoint](/sui-api-ref#sui_getCheckpoint) - Retrieves the specified checkpoint. - - [sui_getLatestCheckpointSequenceNumber](/sui-api-ref#sui_getLatestCheckpointSequenceNumber) - Retrieves the sequence number of the most recently executed checkpoint. - - [sui_getCheckpoints](/sui-api-ref#sui_getCheckpoints) - Retrieves a paginated list of checkpoints that occurred during the specified interval. Pending a future release. +Iota Checkpoint API operations include: + - [iota_getCheckpoint](/iota-api-ref#iota_getCheckpoint) - Retrieves the specified checkpoint. + - [iota_getLatestCheckpointSequenceNumber](/iota-api-ref#iota_getLatestCheckpointSequenceNumber) - Retrieves the sequence number of the most recently executed checkpoint. + - [iota_getCheckpoints](/iota-api-ref#iota_getCheckpoints) - Retrieves a paginated list of checkpoints that occurred during the specified interval. Pending a future release. -## SUI balance transfer +## IOTA balance transfer -To transfer a specific amount of SUI between addresses, you need a SUI token object with that specific value. In Sui, everything is an object, including SUI tokens. The amount of SUI in each SUI token object varies. For example, an address could own 3 SUI tokens with different values: one of 0.1 SUI, a second of 1.0 SUI, and a third with 0.005 SUI. The total balance for the address equals the sum of the values of the individual SUI token objects, in this case, 1.105 SUI. +To transfer a specific amount of IOTA between addresses, you need a IOTA token object with that specific value. In Iota, everything is an object, including IOTA tokens. The amount of IOTA in each IOTA token object varies. For example, an address could own 3 IOTA tokens with different values: one of 0.1 IOTA, a second of 1.0 IOTA, and a third with 0.005 IOTA. The total balance for the address equals the sum of the values of the individual IOTA token objects, in this case, 1.105 IOTA. -You can merge and split SUI token objects to create token objects with specific values. To create a SUI token worth .6 SUI, split the token worth 1 SUI into two token objects worth .6 SUI and .4 SUI. +You can merge and split IOTA token objects to create token objects with specific values. To create a IOTA token worth .6 IOTA, split the token worth 1 IOTA into two token objects worth .6 IOTA and .4 IOTA. -To transfer a specific amount of SUI, you need a SUI token worth that specific amount. To get a SUI token with that specific value, you might need to split or merge existing SUI tokens. Sui supports several methods to accomplish this, including some that do not require you to manually split or merge coins. +To transfer a specific amount of IOTA, you need a IOTA token worth that specific amount. To get a IOTA token with that specific value, you might need to split or merge existing IOTA tokens. Iota supports several methods to accomplish this, including some that do not require you to manually split or merge coins. -## Sui API operations for transfers +## Iota API operations for transfers -Sui supports the following API operations related to transferring SUI between addresses: +Iota supports the following API operations related to transferring IOTA between addresses: - - [sui_transferObject](/sui-api-ref#sui_transferObject) - Because SUI tokens are objects, you can transfer SUI tokens just like any other object. This method requires a gas token, and is useful in niche cases only. + - [iota_transferObject](/iota-api-ref#iota_transferObject) + Because IOTA tokens are objects, you can transfer IOTA tokens just like any other object. This method requires a gas token, and is useful in niche cases only. - - [sui_payAllSui](/sui-api-ref#sui_payAllSui) - This method accepts an array of SUI token IDs. It merges all existing tokens into one, deducts the gas fee, then sends the merged token to the recipient address. + - [iota_payAllIota](/iota-api-ref#iota_payAllIota) + This method accepts an array of IOTA token IDs. It merges all existing tokens into one, deducts the gas fee, then sends the merged token to the recipient address. - The method is especially useful if you want to transfer all SUI from an address. To merge together all coins for an address, set the recipient as the same address. This is a native Sui method so is not considered a transaction in Sui. + The method is especially useful if you want to transfer all IOTA from an address. To merge together all coins for an address, set the recipient as the same address. This is a native Iota method so is not considered a transaction in Iota. - - [sui_paySui](/sui-api-ref#sui_paySui) - This operation accepts an array of SUI token IDs, an array of amounts, and an array of recipient addresses. + - [iota_payIota](/iota-api-ref#iota_payIota) + This operation accepts an array of IOTA token IDs, an array of amounts, and an array of recipient addresses. The amounts and recipients array map one to one. Even if you use only one recipient address, you must include it for each amount in the amount array. - The operation merges all of the tokens provided into one token object and settles the gas fees. It then splits the token according to the amounts in the amounts array and sends the first token to the first recipient, the second token to the second recipient, and so on. Any remaining SUI on the token stays in the source address. + The operation merges all of the tokens provided into one token object and settles the gas fees. It then splits the token according to the amounts in the amounts array and sends the first token to the first recipient, the second token to the second recipient, and so on. Any remaining IOTA on the token stays in the source address. - The benefits of this method include: no gas fees for merging or splitting tokens, and the abstracted token merge and split. The `sui_paySui` operation is a native function, so the merge and split operations are not considered Sui transactions. The gas fees for them match typical transactions on Sui.You can use this operation to split coins in your own address by setting the recipient as your own address. Note that the total value of the input coins must be greater than the total value of the amounts to send. + The benefits of this method include: no gas fees for merging or splitting tokens, and the abstracted token merge and split. The `iota_payIota` operation is a native function, so the merge and split operations are not considered Iota transactions. The gas fees for them match typical transactions on Iota.You can use this operation to split coins in your own address by setting the recipient as your own address. Note that the total value of the input coins must be greater than the total value of the amounts to send. - - [sui_pay](/sui-api-ref#sui_pay) - This method is similar to sui_paySui, but it accepts any kind of coin or token instead of only SUI. You must include a gas token, and all of the coins or tokens must be the same type. + - [iota_pay](/iota-api-ref#iota_pay) + This method is similar to iota_payIota, but it accepts any kind of coin or token instead of only IOTA. You must include a gas token, and all of the coins or tokens must be the same type. - - [sui_transferSui](/sui-api-ref#sui_transferSui) - This method accepts only one SUI token object and an amount to send to the recipient. It uses the same token for gas fees, so the amount to transfer must be strictly less than the value of the SUI token used. + - [iota_transferIota](/iota-api-ref#iota_transferIota) + This method accepts only one IOTA token object and an amount to send to the recipient. It uses the same token for gas fees, so the amount to transfer must be strictly less than the value of the IOTA token used. ## Signing transactions -Refer to [Sui Signatures](/concepts/cryptography/transaction-auth/signatures.mdx) for more details on signature validity requirements. +Refer to [Iota Signatures](/concepts/cryptography/transaction-auth/signatures.mdx) for more details on signature validity requirements. -## SUI Staking +## IOTA Staking -The Sui blockchain uses a Delegated Proof-of-Stake mechanism (DPoS). This allows SUI token holders to stake their SUI tokens to any validator of their choice. When someone stakes their SUI tokens, it means those tokens are locked for the entire epoch. Users can withdraw their stake at any time, but new staking requests become active only at the start of the next epoch. +The Iota blockchain uses a Delegated Proof-of-Stake mechanism (DPoS). This allows IOTA token holders to stake their IOTA tokens to any validator of their choice. When someone stakes their IOTA tokens, it means those tokens are locked for the entire epoch. Users can withdraw their stake at any time, but new staking requests become active only at the start of the next epoch. -SUI holders who stake their tokens to validators earn rewards for helping secure the Sui network. Sui determines rewards for staking based on stake rewards on the network, and distributes them at the end of each epoch. +IOTA holders who stake their tokens to validators earn rewards for helping secure the Iota network. Iota determines rewards for staking based on stake rewards on the network, and distributes them at the end of each epoch. -The total voting power in the Sui Network is always 10,000. The voting power of each individual validator is similar to basis points. For example, a voting power of 101 = 1.01%. Sui's quorum threshold (number of votes needed to confirm a transaction) is 6,667 (which is greater than 2/3). The voting power for a single validator is capped at 1,000 (10%) regardless of how much stake the validator has. +The total voting power in the Iota Network is always 10,000. The voting power of each individual validator is similar to basis points. For example, a voting power of 101 = 1.01%. Iota's quorum threshold (number of votes needed to confirm a transaction) is 6,667 (which is greater than 2/3). The voting power for a single validator is capped at 1,000 (10%) regardless of how much stake the validator has. ## Staking functions -Sui supports the following API operations related to staking. You can find the source code in the [sui_system](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-system/sources/sui_system.move) module. +Iota supports the following API operations related to staking. You can find the source code in the [iota_system](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/packages/iota-system/sources/iota_system.move) module. - `request_add_stake` Add user stake to a validator's staking pool. ```move public fun request_add_stake( - self: &mut SuiSystemState, - stake: Coin, + self: &mut IotaSystemState, + stake: Coin, validator_address: address, ctx: &mut TxContext, ) { @@ -211,8 +211,8 @@ public fun request_add_stake( ```move public fun request_add_stake_mul_coin( - self: &mut SuiSystemState, - delegate_stakes: vector>, + self: &mut IotaSystemState, + delegate_stakes: vector>, stake_amount: option::Option, validator_address: address, ctx: &mut TxContext, @@ -223,12 +223,12 @@ public fun request_add_stake_mul_coin( ``` - `request_add_stake_with_locked_coin` - Add user stake to a validator's staking pool using a locked SUI coin. + Add user stake to a validator's staking pool using a locked IOTA coin. ```move public fun request_add_stake_with_locked_coin( - self: &mut SuiSystemState, - stake: LockedCoin, + self: &mut IotaSystemState, + stake: LockedCoin, validator_address: address, ctx: &mut TxContext, ) { @@ -242,16 +242,16 @@ public fun request_add_stake_with_locked_coin( ```move public fun request_withdraw_stake( - self: &mut SuiSystemState, + self: &mut IotaSystemState, delegation: &mut Delegation, - staked_sui: &mut StakedSui, + staked_iota: &mut StakedIota, principal_withdraw_amount: u64, ctx: &mut TxContext, ) { validator_set::request_withdraw_stake( &mut self.validators, delegation, - staked_sui, + staked_iota, principal_withdraw_amount, ctx, ); diff --git a/docs/content/guides/operator/genesis.mdx b/docs/content/guides/operator/genesis.mdx index 7cd4a7810fd..d91e3e290ec 100644 --- a/docs/content/guides/operator/genesis.mdx +++ b/docs/content/guides/operator/genesis.mdx @@ -2,10 +2,10 @@ title: Genesis --- -Genesis is the initial state of the Sui blockchain. To launch a network, the initial committee of validators collaborate by providing their validator information (public keys, network addresses, and so on) to a shared workspace. After all of the initial validators have contributed their information, Sui generates the initial, unsigned genesis checkpoint (checkpoint with sequence number 0) and each validator provides their signature. Sui aggregates these signatures to form a certificate on the genesis checkpoint. Sui bundles this checkpoint, as well as the initial objects, together into a single genesis.blob file that is used to initialize the state when running the `sui-node` binary for both validators and Full nodes. +Genesis is the initial state of the Iota blockchain. To launch a network, the initial committee of validators collaborate by providing their validator information (public keys, network addresses, and so on) to a shared workspace. After all of the initial validators have contributed their information, Iota generates the initial, unsigned genesis checkpoint (checkpoint with sequence number 0) and each validator provides their signature. Iota aggregates these signatures to form a certificate on the genesis checkpoint. Iota bundles this checkpoint, as well as the initial objects, together into a single genesis.blob file that is used to initialize the state when running the `iota-node` binary for both validators and Full nodes. ## Genesis blob locations -The genesis.blob files for each network are in the [sui-genesis](https://github.com/mystenlabs/sui-genesis) repository. +The genesis.blob files for each network are in the [iota-genesis](https://github.com/iotaledger/iota-genesis) repository. -See [Sui Full Node](./sui-full-node.mdx#set-up-from-source) for how to get the genesis.blob file for each network. +See [Iota Full Node](./iota-full-node.mdx#set-up-from-source) for how to get the genesis.blob file for each network. diff --git a/docs/content/guides/operator/iota-full-node.mdx b/docs/content/guides/operator/iota-full-node.mdx new file mode 100644 index 00000000000..2d115ee7124 --- /dev/null +++ b/docs/content/guides/operator/iota-full-node.mdx @@ -0,0 +1,338 @@ +--- +title: Iota Full Node Configuration +description: Operate a Iota Full node to validate blockchain activities, like transactions, checkpoints, and epoch changes. +--- + +:::info + +These instructions are for advanced users. If you just need a local development environment, you should instead follow the instructions in [Create a Local Iota Network](../developer/getting-started/local-network.mdx) to create a local Full node, validators, and faucet. + +::: + +Iota Full nodes validate blockchain activities, including transactions, checkpoints, and epoch changes. Each Full node stores and services the queries for the blockchain state and history. + +This role enables validators to focus on servicing and processing transactions. When a validator commits a new set of transactions (or a block of transactions), the validator pushes that block to all connected Full nodes that then service the queries from clients. + +## Features + +Iota Full nodes: +- Track and verify the state of the blockchain, independently and locally. +- Serve read requests from clients. + +## State synchronization +Iota Full nodes sync with validators to receive new transactions on the network. + +A transaction requires a few round trips to 2f+1 validators to form a transaction certificate (TxCert). + +This synchronization process includes: + +1. Following 2f+1 validators and listening for newly committed transactions. +1. Making sure that 2f+1 validators recognize the transaction and that it reaches finality. +1. Executing the transaction locally and updating the local DB. + +This synchronization process requires listening to at a minimum 2f+1 validators to ensure that a Full node has properly processed all new transactions. Iota will improve the synchronization process with the introduction of checkpoints and the ability to synchronize with other Full nodes. + +## Architecture + +A Iota Full node is essentially a read-only view of the network state. Unlike validator nodes, Full nodes cannot sign transactions, although they can validate the integrity of the chain by re-executing transactions that a quorum of validators previously committed. + +Today, a Iota Full node maintains the full history of the chain. + +Validator nodes store only the latest transactions on the frontier of the object graph (for example, transactions with >0 unspent output objects). + +## Full node setup + +Follow the instructions here to run your own Iota Full. + +### Hardware requirements + +Suggested minimum hardware to run a Iota Full node: + +- CPUs: 8 physical cores / 16 vCPUs +- RAM: 128 GB +- Storage (SSD): 4 TB NVMe drive + +### Software requirements + +Iota recommends running Iota Full nodes on Linux. Iota supports the Ubuntu and Debian distributions. You can also run a Iota Full node on macOS. + +Make sure to [update Rust](https://doc.rust-lang.org/book/ch01-01-installation.html#updating-and-uninstalling). + +Use the following command to install additional Linux dependencies. + +```shell +sudo apt-get update \ +&& sudo apt-get install -y --no-install-recommends \ +tzdata \ +libprotobuf-dev \ +ca-certificates \ +build-essential \ +libssl-dev \ +libclang-dev \ +libpq-dev \ +pkg-config \ +openssl \ +protobuf-compiler \ +git \ +clang \ +cmake +``` + +## Configure a Full node + +You can configure a Iota Full node either using Docker or by building from source. + +### Using Docker Compose + +Follow the instructions in the [Full node Docker Readme](https://github.com/iotaledger/iota/tree/main/docker/fullnode#readme) to run a Iota Full node using Docker, including [resetting the environment](https://github.com/iotaledger/iota/tree/main/docker/fullnode#reset-the-environment). + +### Setting up a local Iota repository + +You must get the latest source files from the Iota GitHub repository. +1. Set up your fork of the Iota repository: + 1. Go to the [Iota repository](https://github.com/iotaledger/iota) on GitHub and click the Fork button in the top right-hand corner of the screen. + 1. Clone your personal fork of the Iota repository to your local machine (ensure that you insert your GitHub username into the URL): + `git clone https://github.com//iota.git` +1. `cd` into your `iota` repository: + `cd iota` +1. Set up the Iota repository as a git remote: + `git remote add upstream https://github.com/iotaledger/iota` +1. Sync your fork: + `git fetch upstream` +1. Check out the branch associated with the network version you want to run (for example, `devnet` to run a Devnet Full node): + `git checkout --track upstream/` + +### Setting up a Full node from source {#set-up-from-source} + +Open a terminal or console to the `iota` directory you downloaded in the previous steps to complete the following: +1. Install the required prerequisites. +1. Make a copy of the [Full node YAML template](https://github.com/iotaledger/iota/blob/main/crates/iota-config/data/fullnode-template.yaml): + `cp crates/iota-config/data/fullnode-template.yaml fullnode.yaml` +1. Download the genesis blob for the network to use: + - [Devnet genesis blob](https://github.com/iotaledger/iota-genesis/raw/main/devnet/genesis.blob): + `curl -fLJO https://github.com/iotaledger/iota-genesis/raw/main/devnet/genesis.blob` + - [Testnet genesis blob](https://github.com/iotaledger/iota-genesis/raw/main/testnet/genesis.blob): + `curl -fLJO https://github.com/iotaledger/iota-genesis/raw/main/testnet/genesis.blob` + - [Mainnet genesis blob](https://github.com/iotaledger/iota-genesis/raw/main/mainnet/genesis.blob): + `curl -fLJO https://github.com/iotaledger/iota-genesis/raw/main/mainnet/genesis.blob` +1. For Testnet or Mainnet: Edit the `fullnode.yaml` file to include peer nodes for state synchronization. Append the following to the end of the current configuration: + + + + + + ```shell + p2p-config: + seed-peers: + - address: /dns/mel-00.mainnet.iota.io/udp/8084 + peer-id: d32b55bdf1737ec415df8c88b3bf91e194b59ee3127e3f38ea46fd88ba2e7849 + - address: /dns/ewr-00.mainnet.iota.io/udp/8084 + peer-id: c7bf6cb93ca8fdda655c47ebb85ace28e6931464564332bf63e27e90199c50ee + - address: /dns/ewr-01.mainnet.iota.io/udp/8084 + peer-id: 3227f8a05f0faa1a197c075d31135a366a1c6f3d4872cb8af66c14dea3e0eb66 + - address: /dns/lhr-00.mainnet.iota.io/udp/8084 + peer-id: c619a5e0f8f36eac45118c1f8bda28f0f508e2839042781f1d4a9818043f732c + - address: /dns/iota-mainnet-ssfn-1.nodeinfra.com/udp/8084 + peer-id: 0c52ca8d2b9f51be4a50eb44ace863c05aadc940a7bd15d4d3f498deb81d7fc6 + - address: /dns/iota-mainnet-ssfn-2.nodeinfra.com/udp/8084 + peer-id: 1dbc28c105aa7eb9d1d3ac07ae663ea638d91f2b99c076a52bbded296bd3ed5c + - address: /dns/iota-mainnet-ssfn-ashburn-na.overclock.run/udp/8084 + peer-id: 5ff8461ab527a8f241767b268c7aaf24d0312c7b923913dd3c11ee67ef181e45 + - address: /dns/iota-mainnet-ssfn-dallas-na.overclock.run/udp/8084 + peer-id: e1a4f40d66f1c89559a195352ba9ff84aec28abab1d3aa1c491901a252acefa6 + - address: /dns/ssn01.mainnet.iota.rpcpool.com/udp/8084 + peer-id: fadb7ccb0b7fc99223419176e707f5122fef4ea686eb8e80d1778588bf5a0bcd + - address: /dns/ssn02.mainnet.iota.rpcpool.com/udp/8084 + peer-id: 13783584a90025b87d4604f1991252221e5fd88cab40001642f4b00111ae9b7e + ``` + + + + + ```shell + p2p-config: + seed-peers: + - address: /dns/yto-tnt-ssfn-01.testnet.iota.io/udp/8084 + peer-id: 2ed53564d5581ded9b6773970ac2f1c84d39f9edf01308ff5a1ffe09b1add7b3 + - address: /dns/yto-tnt-ssfn-00.testnet.iota.io/udp/8084 + peer-id: 6563732e5ab33b4ae09c73a98fd37499b71b8f03c27b5cc51acc26934974aff2 + - address: /dns/nrt-tnt-ssfn-00.testnet.iota.io/udp/8084 + peer-id: 23a1f7cd901b6277cbedaa986b3fc183f171d800cabba863d48f698f518967e1 + - address: /dns/ewr-tnt-ssfn-00.testnet.iota.io/udp/8084 + peer-id: df8a8d128051c249e224f95fcc463f518a0ebed8986bbdcc11ed751181fecd38 + - address: /dns/lax-tnt-ssfn-00.testnet.iota.io/udp/8084 + peer-id: f9a72a0a6c17eed09c27898eab389add704777c03e135846da2428f516a0c11d + - address: /dns/lhr-tnt-ssfn-00.testnet.iota.io/udp/8084 + peer-id: 9393d6056bb9c9d8475a3cf3525c747257f17c6a698a7062cbbd1875bc6ef71e + - address: /dns/mel-tnt-ssfn-00.testnet.iota.io/udp/8084 + peer-id: c88742f46e66a11cb8c84aca488065661401ef66f726cb9afeb8a5786d83456e + ``` + + + + + +1. Optional: Skip this step to accept the default paths to resources. Edit the fullnode.yaml file to use custom paths. +1. Update the `db-path` field with the path to the Full node database. + `db-path: "/db-files/iota-fullnode"` +1. Update the `genesis-file-location` with the path to genesis.blob. + ```shell + genesis: + genesis-file-location: "/iota-fullnode/genesis.blob" + ``` + +### Starting services + +At this point, your Iota Full node is ready to connect to the Iota network. + +1. Open a terminal or console to the iota directory. +1. Start the Iota Full node: + `cargo run --release --bin iota-node -- --config-path fullnode.yaml` +1. Optional: Publish/subscribe to notifications using JSON-RPC via websocket. + +If your setup is successful, your Iota Full node is now connected to the appropriate network. + +Your Full node serves the read endpoints of the Iota JSON-RPC API at: `http://127.0.0.1:9000`. + +### Troubleshooting +If you receive a `cannot find -lpq` error, you are missing the `libpq` library. Use `sudo apt-get install libpq-dev` to install on Linux, or `brew install libpq` on MacOS. After you install on MacOS, create a Homebrew link using `brew link --force libpq`. For further context, reference the [issue on Stack Overflow](https://stackoverflow.com/questions/70313347/ld-library-not-found-for-lpq-when-build-rust-in-macos?rq=1). + +If you receive the following error: + +```shell +panicked at error binding to 0.0.0.0:9184: error creating server listener: Address already in use (os error 98) +``` + +Then update the metrics address in your fullnode.yaml file to use port `9180`. + +```shell +metrics-address: "0.0.0.0:9180" +``` + +## Monitoring + +Monitor your Full node using the instructions at Logging, Tracing, Metrics, and Observability. + +The default metrics port is `9184`. To change the port, edit your fullnode.yaml file. + +## Update your Full node + +Whenever Iota releases a new version, you must update your Full node with the release to ensure compatibility with the network it connects to. For example, if you use Iota Testnet you should install the version of Iota running on Iota Testnet. + +### Update with Docker Compose + +Follow the instructions to [reset the environment](https://github.com/iotaledger/iota/tree/main/docker/fullnode#reset-the-environment), namely by running the command: + +```shell +docker-compose down --volumes +``` + +### Update from source + +If you followed the instructions for Building from Source, use the following steps to update your Full node: + +1. Shut down your running Full node. +1. `cd` into your local Iota repository: + ```shell + cd iota + ``` +1. Remove the database and 'genesis.blob' file: + ```shell + rm -r iotadb genesis.blob + ``` +1. Fetch the source from the latest release: + ```shell + git fetch upstream + ``` +1. Reset your branch: + ```shell + git checkout -B --track upstream/ + ``` +1. Download the latest genesis blob: + - [Devnet genesis blob](https://github.com/iotaledger/iota-genesis/raw/main/devnet/genesis.blob): + ```shell + curl -fLJO https://github.com/iotaledger/iota-genesis/raw/main/devnet/genesis.blob + ``` + - [Testnet genesis blob](https://github.com/iotaledger/iota-genesis/raw/main/testnet/genesis.blob): + ```shell + curl -fLJO https://github.com/iotaledger/iota-genesis/raw/main/testnet/genesis.blob + ``` +1. Update your fullnode.yaml configuration file, if needed. +1. Restart your Iota Full node: + ```shell + cargo run --release --bin iota-node -- --config-path fullnode.yaml + ``` + +Your Full node starts on: http://127.0.0.1:9000. + +## Object pruning {#object-pruning} + +Iota adds new object versions to the database as part of transaction execution. This makes previous versions ready for +garbage collection. However, without pruning, this can result in database performance degradation and requires large +amounts of storage space. Iota identifies the objects that are eligible for pruning in each checkpoint, and then performs +the pruning in the background. + +You can enable pruning for a Iota node by adding the `authority-store-pruning-config` config to `fullnode.yaml` file: +```yaml +authority-store-pruning-config: + # Number of epoch dbs to keep + # Not relevant for object pruning + num-latest-epoch-dbs-to-retain: 3 + # The amount of time, in seconds, between running the object pruning task. + # Not relevant for object pruning + epoch-db-pruning-period-secs: 3600 + # Number of epochs to wait before performing object pruning. + # When set to 0, Iota prunes old object versions as soon + # as possible. This is also called *aggressive pruning*, and results in the most effective + # garbage collection method with the lowest disk usage possible. + # This is the recommended setting for Iota Validator nodes since older object versions aren't + # necessary to execute transactions. + # When set to 1, Iota prunes only object versions from transaction checkpoints + # previous to the current epoch. In general, when set to N (where N >= 1), Iota prunes + # only object versions from checkpoints up to `current - N` epoch. + # It is therefore possible to have multiple versions of an object present + # in the database. This setting is recommended for Iota Full nodes as they might need to serve + # RPC requests that require looking up objects by ID and Version (rather than just latest + # version). However, if your Full node does not serve RPC requests you should then also enable + # aggressive pruning. + num-epochs-to-retain: 0 + # Advanced setting: Maximum number of checkpoints to prune in a batch. The default + # settings are appropriate for most use cases. + max-checkpoints-in-batch: 10 + # Advanced setting: Maximum number of transactions in one batch of pruning run. The default + # settings are appropriate for most use cases. + max-transactions-in-batch: 1000 +``` +## Transaction pruning {#transaction-pruning} + +Transaction pruning removes previous transactions and effects from the database. +Iota periodically creates checkpoints. Each checkpoint contains the transactions that occurred during the checkpoint and their associated effects. + +Iota performs transaction pruning in the background after checkpoints complete. + +You can enable transaction pruning for your Full node or Validator node by adding `num-epochs-to-retain-for-checkpoints` +to the `authority-store-pruning-config` config for the node: + +```yaml +authority-store-pruning-config: + num-latest-epoch-dbs-to-retain: 3 + epoch-db-pruning-period-secs: 3600 + num-epochs-to-retain: 0 + max-checkpoints-in-batch: 10 + max-transactions-in-batch: 1000 + # Number of epochs to wait before performing transaction pruning. + # When this is N (where N >= 2), Iota prunes transactions and effects from + # checkpoints up to the `current - N` epoch. Iota never prunes transactions and effects from the current and + # immediately prior epoch. N = 2 is a recommended setting for Iota Validator nodes and Iota Full nodes that don't + # serve RPC requests. + num-epochs-to-retain-for-checkpoints: 2 + # Ensures that individual database files periodically go through the compaction process. + # This helps reclaim disk space and avoid fragmentation issues + periodic-compaction-threshold-days: 1 +``` + +:::info + +If you prune transactions, Archival nodes can help ensure lagging peer nodes don't lose any information. For more information, see [Iota Archives](./archives.mdx). + +::: diff --git a/docs/content/guides/operator/node-tools.mdx b/docs/content/guides/operator/node-tools.mdx index d880274cba4..82235646947 100644 --- a/docs/content/guides/operator/node-tools.mdx +++ b/docs/content/guides/operator/node-tools.mdx @@ -2,7 +2,7 @@ title: Node Tools --- -This guide focuses on using the Sui CLI `validator` commands. +This guide focuses on using the Iota CLI `validator` commands. :::info @@ -12,64 +12,64 @@ This tool only supports pending validators and active validators at the moment. ## Preparation -1. Make sure you have completed all the [prerequisites](../developer/getting-started/sui-install.mdx#prerequisites). +1. Make sure you have completed all the [prerequisites](../developer/getting-started/iota-install.mdx#prerequisites). -2. Build the `sui` binary, which you need for the genesis ceremony. This step can be done on any machine you like. It does not have to be done on the machine on which you will run the validator. +2. Build the `iota` binary, which you need for the genesis ceremony. This step can be done on any machine you like. It does not have to be done on the machine on which you will run the validator. 1. Clone the git repo: - `git clone git@github.com:MystenLabs/sui.git && cd sui` + `git clone git@github.com:iotaledger/iota.git && cd iota` 2. Check out the commit to use for the testnet: `git checkout testnet` - 3. Build sui binary + 3. Build iota binary - `cargo build --bin sui` + `cargo build --bin iota` 4. Remember the path to your binary: - `export SUI_BINARY="$(pwd)/target/debug/sui"` + `export IOTA_BINARY="$(pwd)/target/debug/iota"` -3. Run the following command to set up your Sui account and CLI environment. +3. Run the following command to set up your Iota account and CLI environment. - 1. If this is the first time running this program, it will ask you to provide a Sui Fullnode Server URL and a meaningful environment alias. It will also generate a random key pair in `sui.keystore` and a config `client.yaml`. Swap in your validator account key if you already have one. + 1. If this is the first time running this program, it will ask you to provide a Iota Fullnode Server URL and a meaningful environment alias. It will also generate a random key pair in `iota.keystore` and a config `client.yaml`. Swap in your validator account key if you already have one. 2. If you already set it up, simply make sure a. `rpc` is correct in `client.yaml`. b. `active_address` is correct in `client.yaml`. - b. `sui.keystore` contains your account key pair. + b. `iota.keystore` contains your account key pair. - If at this point you can't find where `client.yaml` or `sui.keystore` is or have other questions, read [Sui Client CLI tutorial](/references/cli/client.mdx). + If at this point you can't find where `client.yaml` or `iota.keystore` is or have other questions, read [Iota Client CLI tutorial](/references/cli/client.mdx). ``` bash - $ sui client + $ iota client ``` 4. To test you are connected to the network and configured your config correctly, run the following command to display your validator info. ``` bash -$ sui validator display-metadata +$ iota validator display-metadata ``` -## Using Sui CLI +## Using Iota CLI #### Print help info ``` bash -$ sui validator --help +$ iota validator --help ``` #### Display validator metadata ``` bash -$ sui validator display-metadata +$ iota validator display-metadata ``` or ``` bash -$ sui validator display-metadata +$ iota validator display-metadata ``` to print another validator's information. @@ -78,7 +78,7 @@ to print another validator's information. Run the following to see how to update validator metadata. Read description carefully about when the change will take effect. ``` bash -$ sui validator update-metadata --help +$ iota validator update-metadata --help ``` You can update the following on-chain metadata: @@ -101,7 +101,7 @@ If you change any metadata from points 5 to 11, they will be changed only after Run the following to see how to update each metadata. ``` bash -$ sui validator update-metadata --help +$ iota validator update-metadata --help ``` #### Operation cap @@ -115,13 +115,13 @@ The Operation Cap holder (either the valdiator itself or the delegatee) updates To update Gas Price, run ```bash -$ sui validator update-gas-price +$ iota validator update-gas-price ``` if the account itself is a validator and holds the Operation Cap. Or ```bash -$ sui validator update-gas-price --operation-cap-id +$ iota validator update-gas-price --operation-cap-id ``` if the account is a delegatee. @@ -131,7 +131,7 @@ if the account is a delegatee. To report validators peers, run ```bash -$ sui validator report-validator +$ iota validator report-validator ``` Add `--undo-report false` if it intents to undo an existing report. @@ -141,7 +141,7 @@ Similarly, if the account is a delegatee, add `--operation-cap-id +$ iota validator update-gas-price --operation-cap-id ``` if the account is a delegatee. @@ -152,18 +152,18 @@ if the account is a delegatee. To become a validator candidate, first run ```bash -$ sui validator make-validator-info +$ iota validator make-validator-info ``` This will generate a `validator.info` file and key pair files. The output of this command includes: 1. Four key pair files (Read [more here](./validator-tasks.mdx#key-management)). ==Set their permissions with the minimal visibility (chmod 600, for example) and store them securely==. They are needed when running the validator node as covered below. - a. If you follow this guide thoroughly, this key pair is actually copied from your `sui.keystore` file. + a. If you follow this guide thoroughly, this key pair is actually copied from your `iota.keystore` file. 2. `validator.info` file that contains your validator info. **Double check all information is correct**. Then run ``` bash -$ sui validator become-candidate {path-to}validator.info +$ iota validator become-candidate {path-to}validator.info ``` to submit an on-chain transaction to become a validator candidate. The parameter is the file path to the validator.info generated in the previous step. **Make sure the transaction succeeded (printed in the output).** @@ -175,7 +175,7 @@ At this point you are validator candidate and can start to accept self staking a Once you collect enough staking amount, run ``` bash -$ sui validator join-committee +$ iota validator join-committee ``` to become a pending validator. A pending validator will become active and join the committee starting from next epoch. @@ -186,7 +186,7 @@ to become a pending validator. A pending validator will become active and join t To leave committee, run ``` bash -$ sui validator leave-committee +$ iota validator leave-committee ``` Then you will be removed from committee starting from next epoch. @@ -196,6 +196,6 @@ Then you will be removed from committee starting from next epoch. Serialize the payload that is used to generate Proof of Possession. This is allows the signer to take the payload offline for an Authority protocol BLS keypair to sign. ``` bash -$ sui validator serialize-payload-pop --account-address $ACCOUNT_ADDRESS --protocol-public-key $BLS_PUBKEY +$ iota validator serialize-payload-pop --account-address $ACCOUNT_ADDRESS --protocol-public-key $BLS_PUBKEY Serialized payload: $PAYLOAD_TO_SIGN ``` \ No newline at end of file diff --git a/docs/content/guides/operator/observability.mdx b/docs/content/guides/operator/observability.mdx index df85f245db8..d6de65107dc 100644 --- a/docs/content/guides/operator/observability.mdx +++ b/docs/content/guides/operator/observability.mdx @@ -4,19 +4,19 @@ sidebar_label: Observability draft: true --- -Good observability capabilities are key to the development and growth of Sui. This is made more challenging by the distributed and asynchronous nature of Sui, with multiple client and validator processes distributed over a potentially global network. +Good observability capabilities are key to the development and growth of Iota. This is made more challenging by the distributed and asynchronous nature of Iota, with multiple client and validator processes distributed over a potentially global network. -The observability stack in Sui is based on the [Tokio tracing](https://tokio.rs/blog/2019-08-tracing) library. The rest of this document highlights specific aspects of achieving good observability through structured logging and metrics in Sui. +The observability stack in Iota is based on the [Tokio tracing](https://tokio.rs/blog/2019-08-tracing) library. The rest of this document highlights specific aspects of achieving good observability through structured logging and metrics in Iota. :::info -The output here is largely for the consumption of Sui operators, administrators, and developers. The content of logs and traces do not represent the authoritative, certified output of validators and are subject to potentially byzantine behavior. +The output here is largely for the consumption of Iota operators, administrators, and developers. The content of logs and traces do not represent the authoritative, certified output of validators and are subject to potentially byzantine behavior. ::: ## Contexts, scopes, and tracing transaction flow {#context-scope-trace} -In a distributed and asynchronous system like Sui, one cannot rely on looking at individual logs over time in a single thread. To solve this problem, use the approach of structured logging. Structured logging offers a way to tie together logs, events, and blocks of functionality across threads and process boundaries. +In a distributed and asynchronous system like Iota, one cannot rely on looking at individual logs over time in a single thread. To solve this problem, use the approach of structured logging. Structured logging offers a way to tie together logs, events, and blocks of functionality across threads and process boundaries. ### Spans and events {#spans-and-events} @@ -72,7 +72,7 @@ For more details, see the [EnvFilter](https://docs.rs/tracing-subscriber/latest/ ## Metrics {#metrics} -Sui includes Prometheus-based metrics: +Iota includes Prometheus-based metrics: - `rpc_requests_by_route` and related for RPC Server API metrics and latencies (see `rpc-server.rs`) - Validator transaction metrics (see `AuthorityMetrics` in `authority.rs`) @@ -95,19 +95,19 @@ You can configure `RUST_LOG` for custom logging output, including filtering - se ### Tracing and span output {#tracing-and-span-output} -To generate detailed span start and end logs, define the `SUI_JSON_SPAN_LOGS` environment variable. This causes all output to be in JSON format, which is not as human-readable, so it is not enabled by default. +To generate detailed span start and end logs, define the `IOTA_JSON_SPAN_LOGS` environment variable. This causes all output to be in JSON format, which is not as human-readable, so it is not enabled by default. You can send this output to a tool or service for indexing, alerts, aggregation, and analysis. The following example output shows certificate processing in the authority with span logging. Note the `START` and `END` annotations, and notice how `DB_UPDATE_STATE` which is nested is embedded within `PROCESS_CERT`. Also notice `elapsed_milliseconds`, which logs the duration of each span. ```bash -{"v":0,"name":"sui","msg":"[PROCESS_CERT - START]","level":20,"hostname":"Evan-MLbook.lan","pid":51425,"time":"2022-03-08T22:48:11.241421Z","target":"sui_core::authority_server","line":67,"file":"sui_core/src/authority_server.rs","tx_digest":"t#d1385064287c2ad67e4019dd118d487a39ca91a40e0fd8e678dbc32e112a1493"} -{"v":0,"name":"sui","msg":"[PROCESS_CERT - EVENT] Read inputs for transaction from DB","level":20,"hostname":"Evan-MLbook.lan","pid":51425,"time":"2022-03-08T22:48:11.246688Z","target":"sui_core::authority","line":393,"file":"sui_core/src/authority.rs","num_inputs":2,"tx_digest":"t#d1385064287c2ad67e4019dd118d487a39ca91a40e0fd8e678dbc32e112a1493"} -{"v":0,"name":"sui","msg":"[PROCESS_CERT - EVENT] Finished execution of transaction with status Success { gas_used: 18 }","level":20,"hostname":"Evan-MLbook.lan","pid":51425,"time":"2022-03-08T22:48:11.246759Z","target":"sui_core::authority","line":409,"file":"sui_core/src/authority.rs","gas_used":18,"tx_digest":"t#d1385064287c2ad67e4019dd118d487a39ca91a40e0fd8e678dbc32e112a1493"} -{"v":0,"name":"sui","msg":"[DB_UPDATE_STATE - START]","level":20,"hostname":"Evan-MLbook.lan","pid":51425,"time":"2022-03-08T22:48:11.247888Z","target":"sui_core::authority","line":430,"file":"sui_core/src/authority.rs","tx_digest":"t#d1385064287c2ad67e4019dd118d487a39ca91a40e0fd8e678dbc32e112a1493"} -{"v":0,"name":"sui","msg":"[DB_UPDATE_STATE - END]","level":20,"hostname":"Evan-MLbook.lan","pid":51425,"time":"2022-03-08T22:48:11.248114Z","target":"sui_core::authority","line":430,"file":"sui_core/src/authority.rs","tx_digest":"t#d1385064287c2ad67e4019dd118d487a39ca91a40e0fd8e678dbc32e112a1493","elapsed_milliseconds":0} -{"v":0,"name":"sui","msg":"[PROCESS_CERT - END]","level":20,"hostname":"Evan-MLbook.lan","pid":51425,"time":"2022-03-08T22:48:11.248688Z","target":"sui_core::authority_server","line":67,"file":"sui_core/src/authority_server.rs","tx_digest":"t#d1385064287c2ad67e4019dd118d487a39ca91a40e0fd8e678dbc32e112a1493","elapsed_milliseconds":2} +{"v":0,"name":"iota","msg":"[PROCESS_CERT - START]","level":20,"hostname":"Evan-MLbook.lan","pid":51425,"time":"2022-03-08T22:48:11.241421Z","target":"iota_core::authority_server","line":67,"file":"iota_core/src/authority_server.rs","tx_digest":"t#d1385064287c2ad67e4019dd118d487a39ca91a40e0fd8e678dbc32e112a1493"} +{"v":0,"name":"iota","msg":"[PROCESS_CERT - EVENT] Read inputs for transaction from DB","level":20,"hostname":"Evan-MLbook.lan","pid":51425,"time":"2022-03-08T22:48:11.246688Z","target":"iota_core::authority","line":393,"file":"iota_core/src/authority.rs","num_inputs":2,"tx_digest":"t#d1385064287c2ad67e4019dd118d487a39ca91a40e0fd8e678dbc32e112a1493"} +{"v":0,"name":"iota","msg":"[PROCESS_CERT - EVENT] Finished execution of transaction with status Success { gas_used: 18 }","level":20,"hostname":"Evan-MLbook.lan","pid":51425,"time":"2022-03-08T22:48:11.246759Z","target":"iota_core::authority","line":409,"file":"iota_core/src/authority.rs","gas_used":18,"tx_digest":"t#d1385064287c2ad67e4019dd118d487a39ca91a40e0fd8e678dbc32e112a1493"} +{"v":0,"name":"iota","msg":"[DB_UPDATE_STATE - START]","level":20,"hostname":"Evan-MLbook.lan","pid":51425,"time":"2022-03-08T22:48:11.247888Z","target":"iota_core::authority","line":430,"file":"iota_core/src/authority.rs","tx_digest":"t#d1385064287c2ad67e4019dd118d487a39ca91a40e0fd8e678dbc32e112a1493"} +{"v":0,"name":"iota","msg":"[DB_UPDATE_STATE - END]","level":20,"hostname":"Evan-MLbook.lan","pid":51425,"time":"2022-03-08T22:48:11.248114Z","target":"iota_core::authority","line":430,"file":"iota_core/src/authority.rs","tx_digest":"t#d1385064287c2ad67e4019dd118d487a39ca91a40e0fd8e678dbc32e112a1493","elapsed_milliseconds":0} +{"v":0,"name":"iota","msg":"[PROCESS_CERT - END]","level":20,"hostname":"Evan-MLbook.lan","pid":51425,"time":"2022-03-08T22:48:11.248688Z","target":"iota_core::authority_server","line":67,"file":"iota_core/src/authority_server.rs","tx_digest":"t#d1385064287c2ad67e4019dd118d487a39ca91a40e0fd8e678dbc32e112a1493","elapsed_milliseconds":2} ``` ### Jaeger (seeing distributed traces) {#jaeger} @@ -120,14 +120,14 @@ To see nested spans visualized with [Jaeger](https://www.jaegertracing.io), do t docker run -d -p6831:6831/udp -p6832:6832/udp -p16686:16686 jaegertracing/all-in-one:latest ``` -1. Run Sui like this (trace enables the most detailed spans): +1. Run Iota like this (trace enables the most detailed spans): ```bash -SUI_TRACING_ENABLE=1 RUST_LOG="info,sui_core=trace" ./sui start +IOTA_TRACING_ENABLE=1 RUST_LOG="info,iota_core=trace" ./iota start ``` -1. Run some transfers with Sui CLI client, or run the benchmarking tool. -1. Browse to `http://localhost:16686/` and select Sui as the service. +1. Run some transfers with Iota CLI client, or run the benchmarking tool. +1. Browse to `http://localhost:16686/` and select Iota as the service. :::info @@ -139,22 +139,22 @@ Separate spans (that are not nested) are not connected as a single trace for now [Tokio-console](https://github.com/tokio-rs/console) is an awesome CLI tool designed to analyze and help debug Rust apps using Tokio, in real time! It relies on a special subscriber. -1. Build Sui using a special flag: `RUSTFLAGS="--cfg tokio_unstable" cargo build`. -1. Start Sui with `SUI_TOKIO_CONSOLE` set to 1. +1. Build Iota using a special flag: `RUSTFLAGS="--cfg tokio_unstable" cargo build`. +1. Start Iota with `IOTA_TOKIO_CONSOLE` set to 1. 1. Clone the console repo and `cargo run` to launch the console. :::tip -Adding Tokio-console support might significantly slow down Sui validators/gateways. +Adding Tokio-console support might significantly slow down Iota validators/gateways. ::: ### Memory profiling {#memory-profiling} -Sui uses the [jemalloc memory allocator](https://jemalloc.net/) by default on most platforms, and there is code that enables automatic memory profiling using jemalloc's sampling profiler, which is very lightweight and designed for production use. The profiling code spits out profiles at most every 5 minutes, and only when total memory has increased by a default 20%. Profiling files are named `jeprof..MB.prof` so that it is easy to +Iota uses the [jemalloc memory allocator](https://jemalloc.net/) by default on most platforms, and there is code that enables automatic memory profiling using jemalloc's sampling profiler, which is very lightweight and designed for production use. The profiling code spits out profiles at most every 5 minutes, and only when total memory has increased by a default 20%. Profiling files are named `jeprof..MB.prof` so that it is easy to correlate to metrics and incidents, for ease of debugging. -For the memory profiling to work, you need to set the environment variable `_RJEM_MALLOC_CONF=prof:true`. If you use the [Docker image](https://hub.docker.com/r/mysten/sui-node) they are set automatically. +For the memory profiling to work, you need to set the environment variable `_RJEM_MALLOC_CONF=prof:true`. If you use the [Docker image](https://hub.docker.com/r/mysten/iota-node) they are set automatically. Running some allocator-based heap profilers such as [Bytehound](https://github.com/koute/bytehound) will essentially disable automatic jemalloc profiling, because they interfere with or don't implement `jemalloc_ctl` stats APIs. @@ -162,8 +162,8 @@ To view the profile files, one needs to do the following, on the same platform a 1. Install `libunwind`, the `dot` utility from graphviz, and jeprof. On Debian: `apt-get install libjemalloc-dev libunwind-dev graphviz`. 1. Build with debug symbols: `cargo build --profile bench-profiling` -1. cd to `$SUI_REPO/target/bench-profiling` -1. Run `jeprof --svg sui-node jeprof.xxyyzz.heap` - select the heap profile based on +1. cd to `$IOTA_REPO/target/bench-profiling` +1. Run `jeprof --svg iota-node jeprof.xxyyzz.heap` - select the heap profile based on timestamp and memory size in the filename. :::tip diff --git a/docs/content/guides/operator/snapshots.mdx b/docs/content/guides/operator/snapshots.mdx index f3b60d56d1a..9e70f0fa4b3 100644 --- a/docs/content/guides/operator/snapshots.mdx +++ b/docs/content/guides/operator/snapshots.mdx @@ -1,20 +1,20 @@ --- title: Database Snapshots -description: Database snapshots of the Sui network enable Full node operators a way to bootstrap a Full node without having to execute all the transactions that occurred after genesis. +description: Database snapshots of the Iota network enable Full node operators a way to bootstrap a Full node without having to execute all the transactions that occurred after genesis. --- -Database snapshots provide a point-in-time view of a database's store. In Sui, the database snapshot captures a running database's view of the Sui network from a particular node at the end of an epoch. While validators can enable snapshots, they are typically most valuable for Full node operators. +Database snapshots provide a point-in-time view of a database's store. In Iota, the database snapshot captures a running database's view of the Iota network from a particular node at the end of an epoch. While validators can enable snapshots, they are typically most valuable for Full node operators. -Snapshots of the Sui network enable Full node operators a way to bootstrap a Full node without having to execute all the transactions that occurred after genesis. You can upload snapshots to remote object stores like S3, Google Cloud Storage, Azure Blob Storage, and similar services. These services typically run the export process in the background so there is no degradation in performance for your Full node. With snapshots stored in the cloud, you're more easily able to recover quickly from catastrophic failures in your system or hardware. +Snapshots of the Iota network enable Full node operators a way to bootstrap a Full node without having to execute all the transactions that occurred after genesis. You can upload snapshots to remote object stores like S3, Google Cloud Storage, Azure Blob Storage, and similar services. These services typically run the export process in the background so there is no degradation in performance for your Full node. With snapshots stored in the cloud, you're more easily able to recover quickly from catastrophic failures in your system or hardware. -To maintain a healthy Sui network, Sui encourages the Sui community to bring up additional snapshots to ensure stronger data availability across the network. +To maintain a healthy Iota network, Iota encourages the Iota community to bring up additional snapshots to ensure stronger data availability across the network. ## Supported snapshot types -Sui supports two types of snapshots: +Iota supports two types of snapshots: - **RocksDB snapshots** are a point-in-time view of a database store. This means that the snapshot keeps the state of the system at the moment it generates the snapshot, including non-pruned data, additional indices, and other data. -- **Formal snapshots** are database agnostic with a minimalistic format, in other words they contain only the data necessary to restore a node to a valid state at the specified epoch, thus they have a much smaller storage footprint and are generally faster to restore from when compared to database snapshots. Formal snapshots are also supported natively by the Sui protocol. In this context, this means that we can cryptographically verify the contents of the formal snapshot against a commitment from the committee at the epoch we are restoring to. This verification happens automatically and by default during a Formal snapshot restore (unless explicitly bypassed). +- **Formal snapshots** are database agnostic with a minimalistic format, in other words they contain only the data necessary to restore a node to a valid state at the specified epoch, thus they have a much smaller storage footprint and are generally faster to restore from when compared to database snapshots. Formal snapshots are also supported natively by the Iota protocol. In this context, this means that we can cryptographically verify the contents of the formal snapshot against a commitment from the committee at the epoch we are restoring to. This verification happens automatically and by default during a Formal snapshot restore (unless explicitly bypassed). :::info @@ -29,9 +29,9 @@ A single Full node can generate RocksDB snapshots, Formal snapshots, or both. Formal snapshots provide a mechanism for a node to restore to a canonical state (the state of a full pruned and compacted node at the end of an epoch) at some prior point in time without having to execute all the transactions that have occurred since genesis. Unlike existing database snapshots, these formal snapshots have the following properties: -1. **Minimalism:** Formal snapshots currently contain only the end of epoch live object set (the set of all object versions eligible for use as input objects for future transactions). Sui syncs all other critical chain information from the chain or derives it. Thus, formal snapshots contain only the necessary data required for a node to startup at epoch boundary and participate in the network. +1. **Minimalism:** Formal snapshots currently contain only the end of epoch live object set (the set of all object versions eligible for use as input objects for future transactions). Iota syncs all other critical chain information from the chain or derives it. Thus, formal snapshots contain only the necessary data required for a node to startup at epoch boundary and participate in the network. 1. **Agnosticism:** Formal snapshots are by nature agnostic to the underlying database choice or implementation of the protocol. As the live object set is protocol defined, so is the formal snapshot. -1. **Verifiability:** Formal snapshots have first-class support in the core Sui protocol. As such, they must be trustless/verifiable by the node operator upon download. To support this, the protocol signs a commitment to the live object state at end of epoch, which formal snapshots are checked against at restore time. If this verification fails, the node state is moved back to the state before the snapshot restore attempt. +1. **Verifiability:** Formal snapshots have first-class support in the core Iota protocol. As such, they must be trustless/verifiable by the node operator upon download. To support this, the protocol signs a commitment to the live object state at end of epoch, which formal snapshots are checked against at restore time. If this verification fails, the node state is moved back to the state before the snapshot restore attempt. Because these snapshots do not contain indexes, they are most immediately useful for validators and state sync Full nodes (SSFNs). You can upload snapshots to remote object stores like S3, Google Cloud Storage, Azure Blob Storage, and similar services. These services typically run the export process in the background so there is no degradation in performance for your Full node. With snapshots stored in the cloud, you can recover from catastrophic failures in your system or hardware more efficiently. @@ -88,14 +88,14 @@ Add an entry to the config file for `db-checkpoint-config`. Using Amazon's S3 se To restore from a RocksDB snapshot, follow these steps: 1. Download the snapshot for the epoch you want to restore to your local disk. There is one snapshot per epoch in s3 bucket. -1. Place the snapshot into the directory that the `db-config` value points to in your fullnode.yaml file. For example, if the `db-config` value points to `/opt/sui/db/authorities_db/full_node_db` and you want to restore from epoch 10, then copy the snapshot to the directory with this command: +1. Place the snapshot into the directory that the `db-config` value points to in your fullnode.yaml file. For example, if the `db-config` value points to `/opt/iota/db/authorities_db/full_node_db` and you want to restore from epoch 10, then copy the snapshot to the directory with this command: You can use the aws cli (provided you have credentials to associate with the download): - `aws s3 cp s3:///epoch_10 /opt/sui/db/authorities_db/full_node_db/live --recursive`. + `aws s3 cp s3:///epoch_10 /opt/iota/db/authorities_db/full_node_db/live --recursive`. - An alternative is to use `sui-tool` to copy the files: + An alternative is to use `iota-tool` to copy the files: ``` - sui-tool download-db-snapshot --epoch "" \ + iota-tool download-db-snapshot --epoch "" \ --network --snapshot-bucket \ --snapshot-bucket-type --path \ --num-parallel-downloads 25 \ @@ -115,27 +115,27 @@ To restore from a RocksDB snapshot, follow these steps: * *GCS*: `GCS_SNAPSHOT_SERVICE_ACCOUNT_FILE_PATH` * *AZURE*: `AZURE_SNAPSHOT_STORAGE_ACCOUNT`, `AZURE_SNAPSHOT_STORAGE_ACCESS_KEY` -1. Make sure you update the ownership of the downloaded directory to the sui user (whichever linux user you run `sui-node` as) - `sudo chown -R sui:sui /opt/sui/db/authorities_db/full_node_db/live`. -1. Start the Sui node. +1. Make sure you update the ownership of the downloaded directory to the iota user (whichever linux user you run `iota-node` as) + `sudo chown -R iota:iota /opt/iota/db/authorities_db/full_node_db/live`. +1. Start the Iota node. :::info -When you restore a Full node from a snapshot, write it to the path `/opt/sui/db/authorities_db/full_node_db/live`. To restore a Validator node, use the path `/opt/sui/db/authorities_db/live`. +When you restore a Full node from a snapshot, write it to the path `/opt/iota/db/authorities_db/full_node_db/live`. To restore a Validator node, use the path `/opt/iota/db/authorities_db/live`. ::: ### Restoring using Formal snapshots -To restore using a Formal snapshot, use the `sui-tool` binary. `sui-tool` can be downloaded along with other sui binaries. -See [Install Sui](../developer/getting-started/sui-install.mdx) for more details. +To restore using a Formal snapshot, use the `iota-tool` binary. `iota-tool` can be downloaded along with other iota binaries. +See [Install Iota](../developer/getting-started/iota-install.mdx) for more details. The following steps can be used to restore a node from a Formal snapshot: 1. If it's running, stop the node. 2. Run the command: ``` - sui-tool download-formal-snapshot --epoch "" --genesis "" \ + iota-tool download-formal-snapshot --epoch "" --genesis "" \ --network --snapshot-bucket --snapshot-bucket-type \ --path --num-parallel-downloads 50 --no-sign-request ``` diff --git a/docs/content/guides/operator/sui-full-node.mdx b/docs/content/guides/operator/sui-full-node.mdx deleted file mode 100644 index 447f4835539..00000000000 --- a/docs/content/guides/operator/sui-full-node.mdx +++ /dev/null @@ -1,338 +0,0 @@ ---- -title: Sui Full Node Configuration -description: Operate a Sui Full node to validate blockchain activities, like transactions, checkpoints, and epoch changes. ---- - -:::info - -These instructions are for advanced users. If you just need a local development environment, you should instead follow the instructions in [Create a Local Sui Network](../developer/getting-started/local-network.mdx) to create a local Full node, validators, and faucet. - -::: - -Sui Full nodes validate blockchain activities, including transactions, checkpoints, and epoch changes. Each Full node stores and services the queries for the blockchain state and history. - -This role enables validators to focus on servicing and processing transactions. When a validator commits a new set of transactions (or a block of transactions), the validator pushes that block to all connected Full nodes that then service the queries from clients. - -## Features - -Sui Full nodes: -- Track and verify the state of the blockchain, independently and locally. -- Serve read requests from clients. - -## State synchronization -Sui Full nodes sync with validators to receive new transactions on the network. - -A transaction requires a few round trips to 2f+1 validators to form a transaction certificate (TxCert). - -This synchronization process includes: - -1. Following 2f+1 validators and listening for newly committed transactions. -1. Making sure that 2f+1 validators recognize the transaction and that it reaches finality. -1. Executing the transaction locally and updating the local DB. - -This synchronization process requires listening to at a minimum 2f+1 validators to ensure that a Full node has properly processed all new transactions. Sui will improve the synchronization process with the introduction of checkpoints and the ability to synchronize with other Full nodes. - -## Architecture - -A Sui Full node is essentially a read-only view of the network state. Unlike validator nodes, Full nodes cannot sign transactions, although they can validate the integrity of the chain by re-executing transactions that a quorum of validators previously committed. - -Today, a Sui Full node maintains the full history of the chain. - -Validator nodes store only the latest transactions on the frontier of the object graph (for example, transactions with >0 unspent output objects). - -## Full node setup - -Follow the instructions here to run your own Sui Full. - -### Hardware requirements - -Suggested minimum hardware to run a Sui Full node: - -- CPUs: 8 physical cores / 16 vCPUs -- RAM: 128 GB -- Storage (SSD): 4 TB NVMe drive - -### Software requirements - -Sui recommends running Sui Full nodes on Linux. Sui supports the Ubuntu and Debian distributions. You can also run a Sui Full node on macOS. - -Make sure to [update Rust](https://doc.rust-lang.org/book/ch01-01-installation.html#updating-and-uninstalling). - -Use the following command to install additional Linux dependencies. - -```shell -sudo apt-get update \ -&& sudo apt-get install -y --no-install-recommends \ -tzdata \ -libprotobuf-dev \ -ca-certificates \ -build-essential \ -libssl-dev \ -libclang-dev \ -libpq-dev \ -pkg-config \ -openssl \ -protobuf-compiler \ -git \ -clang \ -cmake -``` - -## Configure a Full node - -You can configure a Sui Full node either using Docker or by building from source. - -### Using Docker Compose - -Follow the instructions in the [Full node Docker Readme](https://github.com/MystenLabs/sui/tree/main/docker/fullnode#readme) to run a Sui Full node using Docker, including [resetting the environment](https://github.com/MystenLabs/sui/tree/main/docker/fullnode#reset-the-environment). - -### Setting up a local Sui repository - -You must get the latest source files from the Sui GitHub repository. -1. Set up your fork of the Sui repository: - 1. Go to the [Sui repository](https://github.com/MystenLabs/sui) on GitHub and click the Fork button in the top right-hand corner of the screen. - 1. Clone your personal fork of the Sui repository to your local machine (ensure that you insert your GitHub username into the URL): - `git clone https://github.com//sui.git` -1. `cd` into your `sui` repository: - `cd sui` -1. Set up the Sui repository as a git remote: - `git remote add upstream https://github.com/MystenLabs/sui` -1. Sync your fork: - `git fetch upstream` -1. Check out the branch associated with the network version you want to run (for example, `devnet` to run a Devnet Full node): - `git checkout --track upstream/` - -### Setting up a Full node from source {#set-up-from-source} - -Open a terminal or console to the `sui` directory you downloaded in the previous steps to complete the following: -1. Install the required prerequisites. -1. Make a copy of the [Full node YAML template](https://github.com/MystenLabs/sui/blob/main/crates/sui-config/data/fullnode-template.yaml): - `cp crates/sui-config/data/fullnode-template.yaml fullnode.yaml` -1. Download the genesis blob for the network to use: - - [Devnet genesis blob](https://github.com/MystenLabs/sui-genesis/raw/main/devnet/genesis.blob): - `curl -fLJO https://github.com/MystenLabs/sui-genesis/raw/main/devnet/genesis.blob` - - [Testnet genesis blob](https://github.com/MystenLabs/sui-genesis/raw/main/testnet/genesis.blob): - `curl -fLJO https://github.com/MystenLabs/sui-genesis/raw/main/testnet/genesis.blob` - - [Mainnet genesis blob](https://github.com/MystenLabs/sui-genesis/raw/main/mainnet/genesis.blob): - `curl -fLJO https://github.com/MystenLabs/sui-genesis/raw/main/mainnet/genesis.blob` -1. For Testnet or Mainnet: Edit the `fullnode.yaml` file to include peer nodes for state synchronization. Append the following to the end of the current configuration: - - - - - - ```shell - p2p-config: - seed-peers: - - address: /dns/mel-00.mainnet.sui.io/udp/8084 - peer-id: d32b55bdf1737ec415df8c88b3bf91e194b59ee3127e3f38ea46fd88ba2e7849 - - address: /dns/ewr-00.mainnet.sui.io/udp/8084 - peer-id: c7bf6cb93ca8fdda655c47ebb85ace28e6931464564332bf63e27e90199c50ee - - address: /dns/ewr-01.mainnet.sui.io/udp/8084 - peer-id: 3227f8a05f0faa1a197c075d31135a366a1c6f3d4872cb8af66c14dea3e0eb66 - - address: /dns/lhr-00.mainnet.sui.io/udp/8084 - peer-id: c619a5e0f8f36eac45118c1f8bda28f0f508e2839042781f1d4a9818043f732c - - address: /dns/sui-mainnet-ssfn-1.nodeinfra.com/udp/8084 - peer-id: 0c52ca8d2b9f51be4a50eb44ace863c05aadc940a7bd15d4d3f498deb81d7fc6 - - address: /dns/sui-mainnet-ssfn-2.nodeinfra.com/udp/8084 - peer-id: 1dbc28c105aa7eb9d1d3ac07ae663ea638d91f2b99c076a52bbded296bd3ed5c - - address: /dns/sui-mainnet-ssfn-ashburn-na.overclock.run/udp/8084 - peer-id: 5ff8461ab527a8f241767b268c7aaf24d0312c7b923913dd3c11ee67ef181e45 - - address: /dns/sui-mainnet-ssfn-dallas-na.overclock.run/udp/8084 - peer-id: e1a4f40d66f1c89559a195352ba9ff84aec28abab1d3aa1c491901a252acefa6 - - address: /dns/ssn01.mainnet.sui.rpcpool.com/udp/8084 - peer-id: fadb7ccb0b7fc99223419176e707f5122fef4ea686eb8e80d1778588bf5a0bcd - - address: /dns/ssn02.mainnet.sui.rpcpool.com/udp/8084 - peer-id: 13783584a90025b87d4604f1991252221e5fd88cab40001642f4b00111ae9b7e - ``` - - - - - ```shell - p2p-config: - seed-peers: - - address: /dns/yto-tnt-ssfn-01.testnet.sui.io/udp/8084 - peer-id: 2ed53564d5581ded9b6773970ac2f1c84d39f9edf01308ff5a1ffe09b1add7b3 - - address: /dns/yto-tnt-ssfn-00.testnet.sui.io/udp/8084 - peer-id: 6563732e5ab33b4ae09c73a98fd37499b71b8f03c27b5cc51acc26934974aff2 - - address: /dns/nrt-tnt-ssfn-00.testnet.sui.io/udp/8084 - peer-id: 23a1f7cd901b6277cbedaa986b3fc183f171d800cabba863d48f698f518967e1 - - address: /dns/ewr-tnt-ssfn-00.testnet.sui.io/udp/8084 - peer-id: df8a8d128051c249e224f95fcc463f518a0ebed8986bbdcc11ed751181fecd38 - - address: /dns/lax-tnt-ssfn-00.testnet.sui.io/udp/8084 - peer-id: f9a72a0a6c17eed09c27898eab389add704777c03e135846da2428f516a0c11d - - address: /dns/lhr-tnt-ssfn-00.testnet.sui.io/udp/8084 - peer-id: 9393d6056bb9c9d8475a3cf3525c747257f17c6a698a7062cbbd1875bc6ef71e - - address: /dns/mel-tnt-ssfn-00.testnet.sui.io/udp/8084 - peer-id: c88742f46e66a11cb8c84aca488065661401ef66f726cb9afeb8a5786d83456e - ``` - - - - - -1. Optional: Skip this step to accept the default paths to resources. Edit the fullnode.yaml file to use custom paths. -1. Update the `db-path` field with the path to the Full node database. - `db-path: "/db-files/sui-fullnode"` -1. Update the `genesis-file-location` with the path to genesis.blob. - ```shell - genesis: - genesis-file-location: "/sui-fullnode/genesis.blob" - ``` - -### Starting services - -At this point, your Sui Full node is ready to connect to the Sui network. - -1. Open a terminal or console to the sui directory. -1. Start the Sui Full node: - `cargo run --release --bin sui-node -- --config-path fullnode.yaml` -1. Optional: Publish/subscribe to notifications using JSON-RPC via websocket. - -If your setup is successful, your Sui Full node is now connected to the appropriate network. - -Your Full node serves the read endpoints of the Sui JSON-RPC API at: `http://127.0.0.1:9000`. - -### Troubleshooting -If you receive a `cannot find -lpq` error, you are missing the `libpq` library. Use `sudo apt-get install libpq-dev` to install on Linux, or `brew install libpq` on MacOS. After you install on MacOS, create a Homebrew link using `brew link --force libpq`. For further context, reference the [issue on Stack Overflow](https://stackoverflow.com/questions/70313347/ld-library-not-found-for-lpq-when-build-rust-in-macos?rq=1). - -If you receive the following error: - -```shell -panicked at error binding to 0.0.0.0:9184: error creating server listener: Address already in use (os error 98) -``` - -Then update the metrics address in your fullnode.yaml file to use port `9180`. - -```shell -metrics-address: "0.0.0.0:9180" -``` - -## Monitoring - -Monitor your Full node using the instructions at Logging, Tracing, Metrics, and Observability. - -The default metrics port is `9184`. To change the port, edit your fullnode.yaml file. - -## Update your Full node - -Whenever Sui releases a new version, you must update your Full node with the release to ensure compatibility with the network it connects to. For example, if you use Sui Testnet you should install the version of Sui running on Sui Testnet. - -### Update with Docker Compose - -Follow the instructions to [reset the environment](https://github.com/MystenLabs/sui/tree/main/docker/fullnode#reset-the-environment), namely by running the command: - -```shell -docker-compose down --volumes -``` - -### Update from source - -If you followed the instructions for Building from Source, use the following steps to update your Full node: - -1. Shut down your running Full node. -1. `cd` into your local Sui repository: - ```shell - cd sui - ``` -1. Remove the database and 'genesis.blob' file: - ```shell - rm -r suidb genesis.blob - ``` -1. Fetch the source from the latest release: - ```shell - git fetch upstream - ``` -1. Reset your branch: - ```shell - git checkout -B --track upstream/ - ``` -1. Download the latest genesis blob: - - [Devnet genesis blob](https://github.com/MystenLabs/sui-genesis/raw/main/devnet/genesis.blob): - ```shell - curl -fLJO https://github.com/MystenLabs/sui-genesis/raw/main/devnet/genesis.blob - ``` - - [Testnet genesis blob](https://github.com/MystenLabs/sui-genesis/raw/main/testnet/genesis.blob): - ```shell - curl -fLJO https://github.com/MystenLabs/sui-genesis/raw/main/testnet/genesis.blob - ``` -1. Update your fullnode.yaml configuration file, if needed. -1. Restart your Sui Full node: - ```shell - cargo run --release --bin sui-node -- --config-path fullnode.yaml - ``` - -Your Full node starts on: http://127.0.0.1:9000. - -## Object pruning {#object-pruning} - -Sui adds new object versions to the database as part of transaction execution. This makes previous versions ready for -garbage collection. However, without pruning, this can result in database performance degradation and requires large -amounts of storage space. Sui identifies the objects that are eligible for pruning in each checkpoint, and then performs -the pruning in the background. - -You can enable pruning for a Sui node by adding the `authority-store-pruning-config` config to `fullnode.yaml` file: -```yaml -authority-store-pruning-config: - # Number of epoch dbs to keep - # Not relevant for object pruning - num-latest-epoch-dbs-to-retain: 3 - # The amount of time, in seconds, between running the object pruning task. - # Not relevant for object pruning - epoch-db-pruning-period-secs: 3600 - # Number of epochs to wait before performing object pruning. - # When set to 0, Sui prunes old object versions as soon - # as possible. This is also called *aggressive pruning*, and results in the most effective - # garbage collection method with the lowest disk usage possible. - # This is the recommended setting for Sui Validator nodes since older object versions aren't - # necessary to execute transactions. - # When set to 1, Sui prunes only object versions from transaction checkpoints - # previous to the current epoch. In general, when set to N (where N >= 1), Sui prunes - # only object versions from checkpoints up to `current - N` epoch. - # It is therefore possible to have multiple versions of an object present - # in the database. This setting is recommended for Sui Full nodes as they might need to serve - # RPC requests that require looking up objects by ID and Version (rather than just latest - # version). However, if your Full node does not serve RPC requests you should then also enable - # aggressive pruning. - num-epochs-to-retain: 0 - # Advanced setting: Maximum number of checkpoints to prune in a batch. The default - # settings are appropriate for most use cases. - max-checkpoints-in-batch: 10 - # Advanced setting: Maximum number of transactions in one batch of pruning run. The default - # settings are appropriate for most use cases. - max-transactions-in-batch: 1000 -``` -## Transaction pruning {#transaction-pruning} - -Transaction pruning removes previous transactions and effects from the database. -Sui periodically creates checkpoints. Each checkpoint contains the transactions that occurred during the checkpoint and their associated effects. - -Sui performs transaction pruning in the background after checkpoints complete. - -You can enable transaction pruning for your Full node or Validator node by adding `num-epochs-to-retain-for-checkpoints` -to the `authority-store-pruning-config` config for the node: - -```yaml -authority-store-pruning-config: - num-latest-epoch-dbs-to-retain: 3 - epoch-db-pruning-period-secs: 3600 - num-epochs-to-retain: 0 - max-checkpoints-in-batch: 10 - max-transactions-in-batch: 1000 - # Number of epochs to wait before performing transaction pruning. - # When this is N (where N >= 2), Sui prunes transactions and effects from - # checkpoints up to the `current - N` epoch. Sui never prunes transactions and effects from the current and - # immediately prior epoch. N = 2 is a recommended setting for Sui Validator nodes and Sui Full nodes that don't - # serve RPC requests. - num-epochs-to-retain-for-checkpoints: 2 - # Ensures that individual database files periodically go through the compaction process. - # This helps reclaim disk space and avoid fragmentation issues - periodic-compaction-threshold-days: 1 -``` - -:::info - -If you prune transactions, Archival nodes can help ensure lagging peer nodes don't lose any information. For more information, see [Sui Archives](./archives.mdx). - -::: diff --git a/docs/content/guides/operator/validator-committee.mdx b/docs/content/guides/operator/validator-committee.mdx index b564124c659..b54325483c8 100644 --- a/docs/content/guides/operator/validator-committee.mdx +++ b/docs/content/guides/operator/validator-committee.mdx @@ -1,23 +1,23 @@ --- title: Validator Committee -description: Sui has a committee of validators to verify on-chain transactions. Epochs, quorums, transactions, certificates, and consensus are touch points for this committee. +description: Iota has a committee of validators to verify on-chain transactions. Epochs, quorums, transactions, certificates, and consensus are touch points for this committee. --- -A set of independent validators participate on the Sui network, each running its own instance of the Sui software on a separate machine (or a sharded cluster of machines the same entity operates). Each validator handles read and write requests sent by clients, verifying transactions and updating on-chain information. +A set of independent validators participate on the Iota network, each running its own instance of the Iota software on a separate machine (or a sharded cluster of machines the same entity operates). Each validator handles read and write requests sent by clients, verifying transactions and updating on-chain information. -To learn how to set up and run a Sui Validator node, including how staking and rewards work, see [Sui Validator Node Configuration](./validator-config.mdx). +To learn how to set up and run a Iota Validator node, including how staking and rewards work, see [Iota Validator Node Configuration](./validator-config.mdx). -Sui uses Delegated Proof-of-Stake (DPoS) to determine which validators operate the network and their voting power. Validators are incentivized to participate in good faith via a share of transaction fees, staking rewards, and slashing stake and staking rewards in case of misbehavior. +Iota uses Delegated Proof-of-Stake (DPoS) to determine which validators operate the network and their voting power. Validators are incentivized to participate in good faith via a share of transaction fees, staking rewards, and slashing stake and staking rewards in case of misbehavior. ## Epochs -Operation of the Sui network is temporally partitioned into non-overlapping, approximate fixed-duration (~24-hour) epochs. During a particular epoch, the set of validators participating in the network and their voting power is fixed. At an epoch boundary, reconfiguration might occur and can change the set of validators participating in the network and their voting power. Conceptually, reconfiguration starts a new instance of the Sui protocol with the previous epoch's final state as [genesis](./genesis.mdx) and the new set of validators as the operators. Besides validator set changes, tokenomics operations such as staking/un-staking, and distribution of staking rewards are also processed at epoch boundaries. +Operation of the Iota network is temporally partitioned into non-overlapping, approximate fixed-duration (~24-hour) epochs. During a particular epoch, the set of validators participating in the network and their voting power is fixed. At an epoch boundary, reconfiguration might occur and can change the set of validators participating in the network and their voting power. Conceptually, reconfiguration starts a new instance of the Iota protocol with the previous epoch's final state as [genesis](./genesis.mdx) and the new set of validators as the operators. Besides validator set changes, tokenomics operations such as staking/un-staking, and distribution of staking rewards are also processed at epoch boundaries. ## Quorums -A quorum is a set of validators whose combined voting power is greater than two-thirds (>2/3) of the total during a particular epoch. For example, in a Sui instance operated by four validators that all have the same voting power, any group containing three validators is a quorum. +A quorum is a set of validators whose combined voting power is greater than two-thirds (>2/3) of the total during a particular epoch. For example, in a Iota instance operated by four validators that all have the same voting power, any group containing three validators is a quorum. -The quorum size of >2/3 ensures Byzantine fault tolerance (BFT). A validator commits a transaction (durably store the transaction and update its internal state with the effects of the transaction) only if it is accompanied by cryptographic signatures from a quorum. Sui calls the combination of the transaction and the quorum signatures on its bytes a *certificate*. The policy of committing only certificates ensures Byzantine fault tolerance: if >2/3 of the validators faithfully follow the protocol, they are guaranteed to eventually agree on both the set of committed certificates and their effects. +The quorum size of >2/3 ensures Byzantine fault tolerance (BFT). A validator commits a transaction (durably store the transaction and update its internal state with the effects of the transaction) only if it is accompanied by cryptographic signatures from a quorum. Iota calls the combination of the transaction and the quorum signatures on its bytes a *certificate*. The policy of committing only certificates ensures Byzantine fault tolerance: if >2/3 of the validators faithfully follow the protocol, they are guaranteed to eventually agree on both the set of committed certificates and their effects. ## Write requests @@ -40,13 +40,13 @@ If a client collects a quorum of signatures on the effects of the transaction, t ## The role of Narwhal and Bullshark -Sui takes advantage of Narwhal and Bullshark as its mempool and consensus engines. Narwhal/Bullshark (N/B) is also implemented in Sui so that when Byzantine agreement is required it uses a high-throughput DAG-based consensus to manage shared locks while execution on different shared objects is parallelized. +Iota takes advantage of Narwhal and Bullshark as its mempool and consensus engines. Narwhal/Bullshark (N/B) is also implemented in Iota so that when Byzantine agreement is required it uses a high-throughput DAG-based consensus to manage shared locks while execution on different shared objects is parallelized. -Narwhal enables the parallel ordering of transactions into batches that are collected into concurrently proposed blocks, and Bullshark defines an algorithm for executing the DAG that these blocks form. N/B combined builds a DAG of blocks, concurrently proposed, and creates an order between those blocks as a byproduct of the building of the DAG. But that order is overlaid on top of the causal order of Sui transactions (the "payload" of Narwhal/Bullshark here), and does not substitute for it: +Narwhal enables the parallel ordering of transactions into batches that are collected into concurrently proposed blocks, and Bullshark defines an algorithm for executing the DAG that these blocks form. N/B combined builds a DAG of blocks, concurrently proposed, and creates an order between those blocks as a byproduct of the building of the DAG. But that order is overlaid on top of the causal order of Iota transactions (the "payload" of Narwhal/Bullshark here), and does not substitute for it: - N/B operates in OX, rather than XO mode (O = order, X = execute); the execution occurs after the Narwhal/Bullshark ordering. - The output of N/B is therefore a sequence of transactions, with interdependencies stored in the transaction data itself. -Consensus sequences certificates of transactions. These represent transactions that have already been presented to 2/3 of validators that checked that all their owned objects are available to be operated on and signed the transaction. Upon a certificate being sequenced, Sui sets the lock of the shared objects at the next available version to map to the execution of that certificate. So for example if you have a shared object X at version 2, and you sequence certificate T, Sui stores T -> [(X, 2)]. That is all you do when Sui reaches consensus, and as a result Sui can ingest a lot of sequenced transactions. +Consensus sequences certificates of transactions. These represent transactions that have already been presented to 2/3 of validators that checked that all their owned objects are available to be operated on and signed the transaction. Upon a certificate being sequenced, Iota sets the lock of the shared objects at the next available version to map to the execution of that certificate. So for example if you have a shared object X at version 2, and you sequence certificate T, Iota stores T -> [(X, 2)]. That is all you do when Iota reaches consensus, and as a result Iota can ingest a lot of sequenced transactions. -Now, after this is done Sui can execute all certificates that have their locks set, on one or multiple cores. Obviously, transactions for earlier versions of objects need to be processed first (causally), and that reduces the degree of concurrency. The read and write set of the transaction can be statically determined from its versioned object inputs--execution can only read/write an object that was an input to the transaction, or that was created by the transaction. \ No newline at end of file +Now, after this is done Iota can execute all certificates that have their locks set, on one or multiple cores. Obviously, transactions for earlier versions of objects need to be processed first (causally), and that reduces the degree of concurrency. The read and write set of the transaction can be statically determined from its versioned object inputs--execution can only read/write an object that was an input to the transaction, or that was created by the transaction. \ No newline at end of file diff --git a/docs/content/guides/operator/validator-config.mdx b/docs/content/guides/operator/validator-config.mdx index 8917186a612..5cbfb06213d 100644 --- a/docs/content/guides/operator/validator-config.mdx +++ b/docs/content/guides/operator/validator-config.mdx @@ -1,21 +1,21 @@ --- -title: Sui Validator Node Configuration -description: Learn how to set up, configure, and manage a Sui Validator node, including staking, reference gas price, and tallying rules. +title: Iota Validator Node Configuration +description: Learn how to set up, configure, and manage a Iota Validator node, including staking, reference gas price, and tallying rules. --- import StakingPoolReqs from "../../_snippets/staking-pool-reqs.mdx"; -Validators on the Sui network run special nodes and have additional tasks and responsibilities beyond those of Full node operators. +Validators on the Iota network run special nodes and have additional tasks and responsibilities beyond those of Full node operators. -## Requirements to run a validator on Sui +## Requirements to run a validator on Iota -To run a Sui validator, you must set up and configure a Sui Validator node. After you have a running node, you must have a minimum of 30 million SUI in your staking pool to join the validator set on the Sui network. +To run a Iota validator, you must set up and configure a Iota Validator node. After you have a running node, you must have a minimum of 30 million IOTA in your staking pool to join the validator set on the Iota network. -To learn how to set up and configure a Sui Validator node, see [Sui for Node Operators](https://github.com/MystenLabs/sui/blob/main/nre/sui_for_node_operators.md) on GitHub. The guide includes all of the information you need to configure your Validator node. It also provides guidance on the tasks you must perform after you join the validator set. +To learn how to set up and configure a Iota Validator node, see [Iota for Node Operators](https://github.com/iotaledger/iota/blob/main/nre/iota_for_node_operators.md) on GitHub. The guide includes all of the information you need to configure your Validator node. It also provides guidance on the tasks you must perform after you join the validator set. Specific steps you must take include: -- Install and configure Sui +- Install and configure Iota - Configure Port and Protocol settings - Key management - Storage configuration @@ -28,7 +28,7 @@ Specific steps you must take include: ## Hardware requirements to run a Validator node -Suggested minimum hardware specifications to run a Sui Validator node: +Suggested minimum hardware specifications to run a Iota Validator node: - CPU: 24 physical cores (or 48 virtual cores) - Memory: 128 GB @@ -37,15 +37,15 @@ Suggested minimum hardware specifications to run a Sui Validator node: ## Validator consensus and voting power -The total voting power on Sui is always 10,000, regardless of the amount staked. Therefore, the quorum threshold is 6,667. There is no limit to the amount of SUI users can stake with a validator. Each validator has consensus voting power proportional to SUI in its staking pool, with one exception: the voting power of an individual validator is capped at 1,000 (10% of the total). If a validator accumulates more than 10% of total stake, the validator's voting power remains fixed at 10%, and the remaining voting power is spread across the rest of the validator set. +The total voting power on Iota is always 10,000, regardless of the amount staked. Therefore, the quorum threshold is 6,667. There is no limit to the amount of IOTA users can stake with a validator. Each validator has consensus voting power proportional to IOTA in its staking pool, with one exception: the voting power of an individual validator is capped at 1,000 (10% of the total). If a validator accumulates more than 10% of total stake, the validator's voting power remains fixed at 10%, and the remaining voting power is spread across the rest of the validator set. ### User staking and withdrawals -When users stake SUI tokens, these SUI objects are wrapped into StakedSUI objects. The calculation to determine each user's relative ownership of the staking pool is done directly with the timestamp of the StakedSUI object (which determines the moment at which the deposit took place) and the change in the exchange rates between the deposit epoch and the withdrawal epoch. Each staking pool's data structure contains a time series with that pool's exchange rates. These exchange rates can be used to determine the withdrawals of any of the pool's stakers. +When users stake IOTA tokens, these IOTA objects are wrapped into StakedIOTA objects. The calculation to determine each user's relative ownership of the staking pool is done directly with the timestamp of the StakedIOTA object (which determines the moment at which the deposit took place) and the change in the exchange rates between the deposit epoch and the withdrawal epoch. Each staking pool's data structure contains a time series with that pool's exchange rates. These exchange rates can be used to determine the withdrawals of any of the pool's stakers. Stake withdrawals are processed immediately with the exchange rate prevailing at the previous epoch's exchange rate. Withdrawals do not have to wait for the current epoch to close. Withdrawals include both the original stake the user deposited and all the stake rewards accumulated up to the previous epoch. Stakers do not earn the rewards accruing to their stake during the epoch at which they withdraw. Since there is no way to know how many stake rewards will be accumulated during the current epoch until the epoch closes, these cannot be included in the withdrawal. Hence, any user can withdraw their stake immediately and receive: -SUI withdrawn at E' = ( SUI deposited at E ) * ( Exchange Rate at E'-1 / Exchange Rate at E ) +IOTA withdrawn at E' = ( IOTA deposited at E ) * ( Exchange Rate at E'-1 / Exchange Rate at E ) ### Find the exchange rate @@ -53,38 +53,38 @@ Each epoch change emits a `0x2::validator_set::ValidatorEpochInfo` event per val ## Staking rewards -Within a given validator staking pool, all stakers receive the same proportion of rewards through the pool's exchange rate appreciation. In addition, since validators earn commissions over the stake they manage, validators receive additional `StakedSUI` objects at the end of each epoch in proportion to the amount of commissions their staking pool earns. +Within a given validator staking pool, all stakers receive the same proportion of rewards through the pool's exchange rate appreciation. In addition, since validators earn commissions over the stake they manage, validators receive additional `StakedIOTA` objects at the end of each epoch in proportion to the amount of commissions their staking pool earns. Staking rewards are funded by transaction gas fees collected during the current epoch and by stake subsidies released at the end of the epoch. StakeRewards = StakeSubsidies + GasFees -Stake subsidies are intended to subsidize the network during its early phases and are funded by a 10% allocation of SUI tokens. After this allocation depletes, the entirety of stake rewards will be made up of gas fees collected through regular network operations. +Stake subsidies are intended to subsidize the network during its early phases and are funded by a 10% allocation of IOTA tokens. After this allocation depletes, the entirety of stake rewards will be made up of gas fees collected through regular network operations. Stake rewards are made up of gas fees and stake subsidies. The total amount distributed throughout each epoch is determined as follows: - **Stake Subsidies:** The amount distributed in each epoch is determined prior to the beginning of the epoch according to a predefined schedule. -- **Gas Fees:** Each epoch's amount depends on the total gas fees collected throughout the epoch. Each Sui transaction pays gas fees depending on two variables, the amount of executed gas units and the gas price: +- **Gas Fees:** Each epoch's amount depends on the total gas fees collected throughout the epoch. Each Iota transaction pays gas fees depending on two variables, the amount of executed gas units and the gas price: _GasFee = GasPrice _ GasUnits* The total amount of gas fees collected corresponds to the sum of gas fees across all transactions processed in the epoch. During regular market conditions, the vast majority of transactions should have a `GasPrice` equal to the `ReferenceGasPrice`. ### User staking and rewards -A stake deposit request goes into a pending state immediately in the staking pool as soon as it is made. Sui Wallet reflects any pending stake deposit requests for the user's account. However, pending stake deposit requests do not take effect until the end of the epoch during which the request is made. +A stake deposit request goes into a pending state immediately in the staking pool as soon as it is made. Iota Wallet reflects any pending stake deposit requests for the user's account. However, pending stake deposit requests do not take effect until the end of the epoch during which the request is made. -A withdrawal (un-stake) request is processed immediately as soon as it is received. The staker obtains the originally deposited SUI together with all accrued stake rewards up to the previous epoch boundary – in other words, they do not include stake rewards for the current epoch. +A withdrawal (un-stake) request is processed immediately as soon as it is received. The staker obtains the originally deposited IOTA together with all accrued stake rewards up to the previous epoch boundary – in other words, they do not include stake rewards for the current epoch. -Users can't withdraw a portion of their active stake. They must withdraw all staked SUI at the same time. Users can, however, stake using multiple `StakedSui` objects by splitting their SUI into multiple coins. They can then perform a partial withdrawal from a validator by un-staking only some of the `StakedSUI` objects. +Users can't withdraw a portion of their active stake. They must withdraw all staked IOTA at the same time. Users can, however, stake using multiple `StakedIota` objects by splitting their IOTA into multiple coins. They can then perform a partial withdrawal from a validator by un-staking only some of the `StakedIOTA` objects. ## Reference gas price -Sui is designed such that end-users can expect the gas price to be stable and predictable during regular network operations. This is achieved by having validators set the network's reference gas price at the beginning of each epoch. +Iota is designed such that end-users can expect the gas price to be stable and predictable during regular network operations. This is achieved by having validators set the network's reference gas price at the beginning of each epoch. Operationally this is achieved through a gas price survey that occurs as follows: - During each epoch E, each validator submits what they think the optimal reference gas price should be for the next epoch E+1. -- At the epoch boundary, when Sui transitions from epoch E to epoch E+1, the network observes the gas price quotes across the validator set and sets the 2/3 percentile weighted by stake as the epoch's reference gas price. Hence the reference gas price is constant throughout each epoch and is only updated when the epoch changes. +- At the epoch boundary, when Iota transitions from epoch E to epoch E+1, the network observes the gas price quotes across the validator set and sets the 2/3 percentile weighted by stake as the epoch's reference gas price. Hence the reference gas price is constant throughout each epoch and is only updated when the epoch changes. For example, assume that there are seven validators with equal stake, and the price quotes they submit are `{15, 1, 4, 2, 8, 3, 23}`. The protocol sets the reference gas price at 8. @@ -93,21 +93,21 @@ In practice, the process for submitting a gas price quote for the Gas Price Surv For example, to set the price quote for the next epoch to 42, run: ```shell -sui client call --package --module sui_system --function request_set_gas_price --args 0x5 \"42\" --gas-budget +iota client call --package --module iota_system --function request_set_gas_price --args 0x5 \"42\" --gas-budget ``` Importantly, the gas object's value persists across epochs so that a validator who does not update and submit a new quote uses the same quote from the previous epoch. Hence, a validator seeking to optimize its own operations should update its quote every epoch in response to changes in network operations and market conditions. ## Validator slashing and tallying rule -Sui is designed to encourage and enforce community monitoring of the validator set. This is done through the Tallying Rule by which each validator monitors and scores every other validator in order to ensure that everyone is operating efficiently and in the network's best interest. Validators that receive a low score can be penalized with slashed stake rewards. +Iota is designed to encourage and enforce community monitoring of the validator set. This is done through the Tallying Rule by which each validator monitors and scores every other validator in order to ensure that everyone is operating efficiently and in the network's best interest. Validators that receive a low score can be penalized with slashed stake rewards. The protocol only computes the global Tallying Rule score at the epoch boundary and so relies on validators monitoring actively and changing their individual scores whenever they detect changes in other validator behavior. In general, the Tallying Rule default option should always be a score of one for all validators and only be changed to zero upon determining bad operations. In practice, the Tallying Rule consists of a set of objects each validator owns that default to scores of one and thus a validator will generally be passive and only update the object corresponding to another validator's score whenever needed. -For example, to report a validator whose Sui address is `0x44840a79dd5cf1f5efeff1379f5eece04c72db13512a2e31e8750f5176285446` as bad or non-performant, run: +For example, to report a validator whose Iota address is `0x44840a79dd5cf1f5efeff1379f5eece04c72db13512a2e31e8750f5176285446` as bad or non-performant, run: ```shell -sui client call --package --module sui_system --function report_validator --args 0x5 0x44840a79dd5cf1f5efeff1379f5eece04c72db13512a2e31e8750f5176285446 --gas-budget +iota client call --package --module iota_system --function report_validator --args 0x5 0x44840a79dd5cf1f5efeff1379f5eece04c72db13512a2e31e8750f5176285446 --gas-budget ``` The Tallying Rule should be implemented through a social equilibrium. The validator set should actively monitor itself and if one validator is clearly non-performant, then the other validators should score that validator with a 0 and slash its rewards. Community members can launch public dashboards tracking validator performance and that can be used as further signal into a validator's operations. There is no limit on the number of validators that can receive a 0 tallying score in an epoch. diff --git a/docs/content/guides/operator/validator-tasks.mdx b/docs/content/guides/operator/validator-tasks.mdx index d685a1f378a..2bfefa5c470 100644 --- a/docs/content/guides/operator/validator-tasks.mdx +++ b/docs/content/guides/operator/validator-tasks.mdx @@ -1,13 +1,13 @@ --- title: Validator Tasks -description: As a validator on Sui, there are some processes you need to perform to ensure your nodes are always optimized. +description: As a validator on Iota, there are some processes you need to perform to ensure your nodes are always optimized. --- -This guide focuses on running the Sui node software as a validator. +This guide focuses on running the Iota node software as a validator. ## Requirements -To run a Sui Validator a machine with the following is required: +To run a Iota Validator a machine with the following is required: - CPU: 24 physical cores (or 48 virtual cores) - Memory: 128 GB - Storage: 4 TB NVME @@ -15,52 +15,52 @@ To run a Sui Validator a machine with the following is required: ## Deployment -You can deploy Sui node in a number of ways. +You can deploy Iota node in a number of ways. -There are pre-built container images available in [Docker Hub](https://hub.docker.com/r/mysten/sui-node/tags). +There are pre-built container images available in [Docker Hub](https://hub.docker.com/r/mysten/iota-node/tags). And pre built `linux/amd64` binaries available in S3 that you can can fetch using one of the following methods: ```shell -wget https://releases.sui.io/$SUI_SHA/sui-node +wget https://releases.iota.io/$IOTA_SHA/iota-node ``` ```shell -curl https://releases.sui.io/$SUI_SHA/sui-node -o sui-node +curl https://releases.iota.io/$IOTA_SHA/iota-node -o iota-node ``` To build directly from source: ```shell -git clone https://github.com/MystenLabs/sui.git && cd sui +git clone https://github.com/iotaledger/iota.git && cd iota git checkout [SHA|BRANCH|TAG] -cargo build --release --bin sui-node +cargo build --release --bin iota-node ``` Configuration and guides are available for the following deployment options: -- [Systemd](https://github.com/MystenLabs/sui/blob/main/nre/systemd/README.md) -- [Ansible](https://github.com/MystenLabs/sui/blob/main/nre/ansible/README.md) -- [Docker Compose](https://github.com/MystenLabs/sui/blob/main/nre/docker/README.md) +- [Systemd](https://github.com/iotaledger/iota/blob/main/nre/systemd/README.md) +- [Ansible](https://github.com/iotaledger/iota/blob/main/nre/ansible/README.md) +- [Docker Compose](https://github.com/iotaledger/iota/blob/main/nre/docker/README.md) ## Configuration -Sui node runs with a single configuration file provided as an argument, example: +Iota node runs with a single configuration file provided as an argument, example: -`./sui-node --config-path /opt/sui/config/validator.yaml`. +`./iota-node --config-path /opt/iota/config/validator.yaml`. -See [Validator](https://github.com/MystenLabs/sui/blob/main/nre/config/validator.yaml) for configuration templates. +See [Validator](https://github.com/iotaledger/iota/blob/main/nre/config/validator.yaml) for configuration templates. ## Connectivity -Sui node uses the following ports by default: +Iota node uses the following ports by default: | protocol/port | reachability | purpose | | ------------- | ---------------- | --------------------------------- | | TCP/8080 | inbound | protocol/transaction interface | | UDP/8081 | inbound/outbound | narwhal primary interface | | UDP/8082 | inbound/outbound | narwhal worker interface | -| TCP/8083 | localhost | sui -> narwhal interface | +| TCP/8083 | localhost | iota -> narwhal interface | | UDP/8084 | inbound/outbound | peer to peer state sync interface | | TCP/8443 | outbound | metrics pushing | | TCP/9184 | localhost | metrics scraping | @@ -69,49 +69,49 @@ To run a validator successfully, it is critical that ports 8080-8084 are open as ## Storage -All Sui node related data is stored by default under `/opt/sui/db/`. This is controlled in the Sui node configuration file. +All Iota node related data is stored by default under `/opt/iota/db/`. This is controlled in the Iota node configuration file. ```shell -$ cat /opt/sui/config/validator.yaml | grep db-path - db-path: /opt/sui/db/authorities_db - db-path: /opt/sui/db/consensus_db +$ cat /opt/iota/config/validator.yaml | grep db-path + db-path: /opt/iota/db/authorities_db + db-path: /opt/iota/db/consensus_db ``` Ensure that you have an appropriately sized disk mounted for the database to write to. -- To check the size of the local Sui node databases: +- To check the size of the local Iota node databases: ```shell -du -sh /opt/sui/db/ -du -sh /opt/sui/db/authorities_db -du -sh /opt/sui/db/consensus_db +du -sh /opt/iota/db/ +du -sh /opt/iota/db/authorities_db +du -sh /opt/iota/db/consensus_db ``` -- To delete the local Sui node databases: +- To delete the local Iota node databases: ```shell -sudo systemctl stop sui-node -sudo rm -rf /opt/sui/db/authorities_db /opt/sui/db/consensus_db +sudo systemctl stop iota-node +sudo rm -rf /opt/iota/db/authorities_db /opt/iota/db/consensus_db ``` ## Key management -The following keys are used by Sui node: +The following keys are used by Iota node: | key | scheme | purpose | | ------------ | -------- | ------------------------------- | | protocol.key | bls12381 | transactions, narwhal consensus | | account.key | ed25519 | controls assets for staking | -| network.key | ed25519 | narwhal primary, sui state sync | +| network.key | ed25519 | narwhal primary, iota state sync | | worker.key | ed25519 | validate narwhal workers | -These are configured in the [Sui node configuration file](#configuration). +These are configured in the [Iota node configuration file](#configuration). ## Monitoring ### Metrics -Sui node exposes metrics via a local HTTP interface. These can be scraped for use in a central monitoring system as well as viewed directly from the node. +Iota node exposes metrics via a local HTTP interface. These can be scraped for use in a central monitoring system as well as viewed directly from the node. - View all metrics: @@ -125,7 +125,7 @@ curl -s http://localhost:9184/metrics curl http://localhost:9184/metrics | grep ``` -Sui node also pushes metrics to a central Sui metrics proxy. +Iota node also pushes metrics to a central Iota metrics proxy. ### Logs @@ -135,23 +135,23 @@ The `RUST_LOG_JSON=1` environment variable can optionally be set to enable loggi Depending on your deployment method, these are configured in the following places: -- [Ansible](https://github.com/MystenLabs/sui/blob/main/nre/ansible/roles/sui-node/files/sui-node.service) -- [Native systemd](https://github.com/MystenLabs/sui/blob/main/nre/systemd/sui-node.service) -- [Docker Compose](https://github.com/MystenLabs/sui/blob/main/nre/docker/docker-compose.yaml) +- [Ansible](https://github.com/iotaledger/iota/blob/main/nre/ansible/roles/iota-node/files/iota-node.service) +- [Native systemd](https://github.com/iotaledger/iota/blob/main/nre/systemd/iota-node.service) +- [Docker Compose](https://github.com/iotaledger/iota/blob/main/nre/docker/docker-compose.yaml) -To view and follow the Sui node logs: +To view and follow the Iota node logs: ```shell -journalctl -u sui-node -f +journalctl -u iota-node -f ``` To search for a particular match ```shell -journalctl -u sui-node -g +journalctl -u iota-node -g ``` -- If using Docker Compose, look at the examples in the [README](https://github.com/MystenLabs/sui/blob/main/nre/docker/README.md#logs). +- If using Docker Compose, look at the examples in the [README](https://github.com/iotaledger/iota/blob/main/nre/docker/README.md#logs). It is possible to change the logging configuration while a node is running using the admin interface. @@ -171,24 +171,24 @@ curl localhost:1337/logging -d "info" Public dashboard for network wide visibility: -- [Sui Testnet Validators](https://metrics.sui.io/public-dashboards/9b841d63c9bf43fe8acec4f0fa991f5e) +- [Iota Testnet Validators](https://metrics.iota.io/public-dashboards/9b841d63c9bf43fe8acec4f0fa991f5e) ## Software updates -When an update is required to the Sui node software the following process can be used. Follow the relevant Systemd or Docker Compose runbook depending on your deployment type. It is highly unlikely that you will want to restart with a clean database. +When an update is required to the Iota node software the following process can be used. Follow the relevant Systemd or Docker Compose runbook depending on your deployment type. It is highly unlikely that you will want to restart with a clean database. -- [Systemd](https://github.com/MystenLabs/sui/blob/main/nre/systemd/README.md#updates) -- [Docker Compose](https://github.com/MystenLabs/sui/blob/main/nre/docker/README.md#updates) +- [Systemd](https://github.com/iotaledger/iota/blob/main/nre/systemd/README.md#updates) +- [Docker Compose](https://github.com/iotaledger/iota/blob/main/nre/docker/README.md#updates) ## State sync -Checkpoints in Sui contain the permanent history of the network. They are comparable to blocks in other blockchains with one big difference being that they are lagging instead of leading. All transactions are final and executed prior to being included in a checkpoint. +Checkpoints in Iota contain the permanent history of the network. They are comparable to blocks in other blockchains with one big difference being that they are lagging instead of leading. All transactions are final and executed prior to being included in a checkpoint. These checkpoints are synchronized between validators and fullnodes via a dedicated peer to peer state sync interface. Inter-validator state sync is always permitted however there are controls available to limit what fullnodes are allowed to sync from a specific validator. -The default and recommended `max-concurrent-connections: 0` configuration does not affect inter-validator state sync, but will restrict all fullnodes from syncing. The Sui node [configuration](#configuration) can be modified to allow a known fullnode to sync from a validator: +The default and recommended `max-concurrent-connections: 0` configuration does not affect inter-validator state sync, but will restrict all fullnodes from syncing. The Iota node [configuration](#configuration) can be modified to allow a known fullnode to sync from a validator: ```shell p2p-config: @@ -203,23 +203,23 @@ p2p-config: ## Chain operations -The following chain operations are executed using the `sui` CLI. This binary is built and provided as a release similar to `sui-node`, examples: +The following chain operations are executed using the `iota` CLI. This binary is built and provided as a release similar to `iota-node`, examples: ```shell -wget https://releases.sui.io/$SUI_SHA/sui -chmod +x sui +wget https://releases.iota.io/$IOTA_SHA/iota +chmod +x iota ``` ```shell -curl https://releases.sui.io/$SUI_SHA/sui -o sui -chmod +x sui +curl https://releases.iota.io/$IOTA_SHA/iota -o iota +chmod +x iota ``` -It is recommended and often required that the `sui` binary release/version matches that of the deployed network. +It is recommended and often required that the `iota` binary release/version matches that of the deployed network. ### Updating on-chain metadata -You can leverage [Validator Tool](https://github.com/MystenLabs/sui/blob/main/nre/validator_tool.md) to perform majority of the following tasks. +You can leverage [Validator Tool](https://github.com/iotaledger/iota/blob/main/nre/validator_tool.md) to perform majority of the following tasks. An active/pending validator can update its on-chain metadata by submitting a transaction. Some metadata changes take effect immediately, including: @@ -232,84 +232,84 @@ Other metadata (keys, addresses, and so on) only come into effect at the next ep To update metadata, a validator makes a MoveCall transaction that interacts with the System Object. For example: -1. to update name to `new_validator_name`, use the Sui Client CLI to call `sui_system::update_validator_name`: +1. to update name to `new_validator_name`, use the Iota Client CLI to call `iota_system::update_validator_name`: ```bash -sui client call --package 0x3 --module sui_system --function update_validator_name --args 0x5 \"new_validator_name\" --gas-budget 10000 +iota client call --package 0x3 --module iota_system --function update_validator_name --args 0x5 \"new_validator_name\" --gas-budget 10000 ``` -2. to update p2p address starting from next epoch to `/ip4/192.168.1.1`, use the Sui Client CLI to call `sui_system::update_validator_next_epoch_p2p_address`: +2. to update p2p address starting from next epoch to `/ip4/192.168.1.1`, use the Iota Client CLI to call `iota_system::update_validator_next_epoch_p2p_address`: ```bash -sui client call --package 0x3 --module sui_system --function update_validator_next_epoch_p2p_address --args 0x5 "[4, 192, 168, 1, 1]" --gas-budget 10000 +iota client call --package 0x3 --module iota_system --function update_validator_next_epoch_p2p_address --args 0x5 "[4, 192, 168, 1, 1]" --gas-budget 10000 ``` -See the [full list of metadata update functions here](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-system/sources/sui_system.move#L267-L444). +See the [full list of metadata update functions here](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/packages/iota-system/sources/iota_system.move#L267-L444). ### Operation cap To avoid touching account keys too often and allowing them to be stored off-line, validators can delegate the operation ability to another address. This address can then update the reference gas price and tallying rule on behalf of the validator. -Upon creating a `Validator`, an `UnverifiedValidatorOperationCap` is created as well and transferred to the validator address. The holder of this `Cap` object (short for "Capability") therefore could perform operational actions for this validator. To authorize another address to conduct these operations, a validator transfers the object to another address that they control. The transfer can be done by using Sui Client CLI: `sui client transfer`. +Upon creating a `Validator`, an `UnverifiedValidatorOperationCap` is created as well and transferred to the validator address. The holder of this `Cap` object (short for "Capability") therefore could perform operational actions for this validator. To authorize another address to conduct these operations, a validator transfers the object to another address that they control. The transfer can be done by using Iota Client CLI: `iota client transfer`. -To rotate the delegatee address or revoke the authorization, the current holder of `Cap` transfers it to another address. In the event of compromised or lost keys, the validator could create a new `Cap` object to invalidate the incumbent one. This is done by calling `sui_system::rotate_operation_cap`: +To rotate the delegatee address or revoke the authorization, the current holder of `Cap` transfers it to another address. In the event of compromised or lost keys, the validator could create a new `Cap` object to invalidate the incumbent one. This is done by calling `iota_system::rotate_operation_cap`: ```bash -sui client call --package 0x3 --module sui_system --function rotate_operation_cap --args 0x5 --gas-budget 10000 +iota client call --package 0x3 --module iota_system --function rotate_operation_cap --args 0x5 --gas-budget 10000 ``` By default the new `Cap` object is transferred to the validator address, which then could be transferred to the new delegatee address. At this point, the old `Cap` becomes invalidated and no longer represents eligibility. -To get the current valid `Cap` object's ID of a validator, use the Sui Client CLI `sui client objects` command after setting the holder as the active address. +To get the current valid `Cap` object's ID of a validator, use the Iota Client CLI `iota client objects` command after setting the holder as the active address. ### Updating the gas price survey quote -To update the gas price survey quote of a validator, which is used to calculate the reference gas price at the end of the epoch, the sender needs to hold a valid [`UnverifiedValidatorOperationCap`](#operation-cap). The sender could be the validator itself, or a trusted delegatee. To do so, call `sui_system::request_set_gas_price`: +To update the gas price survey quote of a validator, which is used to calculate the reference gas price at the end of the epoch, the sender needs to hold a valid [`UnverifiedValidatorOperationCap`](#operation-cap). The sender could be the validator itself, or a trusted delegatee. To do so, call `iota_system::request_set_gas_price`: ```bash -sui client call --package 0x3 --module sui_system --function request_set_gas_price --args 0x5 {cap_object_id} {new_gas_price} --gas-budget 10000 +iota client call --package 0x3 --module iota_system --function request_set_gas_price --args 0x5 {cap_object_id} {new_gas_price} --gas-budget 10000 ``` ### Reporting/un-reporting validators -To report a validator or undo an existing reporting, the sender needs to hold a valid [`UnverifiedValidatorOperationCap`](#operation-cap). The sender could be the validator itself, or a trusted delegatee. To do so, call `sui_system::report_validator/undo_report_validator`: +To report a validator or undo an existing reporting, the sender needs to hold a valid [`UnverifiedValidatorOperationCap`](#operation-cap). The sender could be the validator itself, or a trusted delegatee. To do so, call `iota_system::report_validator/undo_report_validator`: ```bash -sui client call --package 0x3 --module sui_system --function report_validator/undo_report_validator --args 0x5 {cap_object_id} {reportee_address} --gas-budget 10000 +iota client call --package 0x3 --module iota_system --function report_validator/undo_report_validator --args 0x5 {cap_object_id} {reportee_address} --gas-budget 10000 ``` After a validator is reported by `2f + 1` other validators by voting power, their staking rewards will be slashed. ### Joining the validator set -In order for a Sui address to join the validator set, they need to first sign up as a validator candidate by calling `sui_system::request_add_validator_candidate` with their metadata and initial configs: +In order for a Iota address to join the validator set, they need to first sign up as a validator candidate by calling `iota_system::request_add_validator_candidate` with their metadata and initial configs: ```bash -sui client call --package 0x3 --module sui_system --function request_add_validator_candidate --args 0x5 {protocol_pubkey_bytes} {network_pubkey_bytes} {worker_pubkey_bytes} {proof_of_possession} {name} {description} {image_url} {project_url} {net_address} {p2p_address} {primary_address} {worker_address} {gas_price} {commission_rate} --gas-budget 10000 +iota client call --package 0x3 --module iota_system --function request_add_validator_candidate --args 0x5 {protocol_pubkey_bytes} {network_pubkey_bytes} {worker_pubkey_bytes} {proof_of_possession} {name} {description} {image_url} {project_url} {net_address} {p2p_address} {primary_address} {worker_address} {gas_price} {commission_rate} --gas-budget 10000 ``` -After an address becomes a validator candidate, any address (including the candidate address itself) can start staking with the candidate's staking pool. Refer to our dedicated staking FAQ on how staking works. Once a candidate's staking pool has accumulated at least `sui_system::MIN_VALIDATOR_JOINING_STAKE` amount of stake, the candidate can call `sui_system::request_add_validator` to officially add themselves to next epoch's active validator set: +After an address becomes a validator candidate, any address (including the candidate address itself) can start staking with the candidate's staking pool. Refer to our dedicated staking FAQ on how staking works. Once a candidate's staking pool has accumulated at least `iota_system::MIN_VALIDATOR_JOINING_STAKE` amount of stake, the candidate can call `iota_system::request_add_validator` to officially add themselves to next epoch's active validator set: ```bash -sui client call --package 0x3 --module sui_system --function request_add_validator --args 0x5 --gas-budget 10000000 +iota client call --package 0x3 --module iota_system --function request_add_validator --args 0x5 --gas-budget 10000000 ``` ### Leaving the validator set -To leave the validator set starting next epoch, the sender needs to be an active validator in the current epoch and should call `sui_system::request_remove_validator`: +To leave the validator set starting next epoch, the sender needs to be an active validator in the current epoch and should call `iota_system::request_remove_validator`: ```bash -sui client call --package 0x3 --module sui_system --function request_remove_validator --args 0x5 --gas-budget 10000 +iota client call --package 0x3 --module iota_system --function request_remove_validator --args 0x5 --gas-budget 10000 ``` After the validator is removed at the next epoch change, the staking pool will become inactive and stakes can only be withdrawn from an inactive pool. ## Private security fixes -There might be instances where urgent security fixes need to be rolled out before publicly announcing it's presence (issues affecting liveliness, invariants such as SUI supply, governance, and so on). To not be actively exploited, Mysten Labs will release signed security binaries incorporating such fixes with a delay in publishing the source code until a large percentage of our validators have patched the vulnerability. +There might be instances where urgent security fixes need to be rolled out before publicly announcing it's presence (issues affecting liveliness, invariants such as IOTA supply, governance, and so on). To not be actively exploited, Mysten Labs will release signed security binaries incorporating such fixes with a delay in publishing the source code until a large percentage of our validators have patched the vulnerability. This release process is different and we expect us to announce the directory for such binaries out of band. -Our public key to verify these binaries would be stored [here](https://sui-private.s3.us-west-2.amazonaws.com/sui_security_release.pem) +Our public key to verify these binaries would be stored [here](https://iota-private.s3.us-west-2.amazonaws.com/iota_security_release.pem) There is also a script available that downloads all the necessary signed binaries and docker artifacts incorporating the security fixes. diff --git a/docs/content/references.mdx b/docs/content/references.mdx index b30eab5dd8e..b9d8ff0adb4 100644 --- a/docs/content/references.mdx +++ b/docs/content/references.mdx @@ -3,54 +3,54 @@ title: References Overview sidebar_label: Overview --- -Already familiar with Sui? Use these valuable resources to continue your development journey. +Already familiar with Iota? Use these valuable resources to continue your development journey. -## Sui RPC +## Iota RPC -Reference the Sui framework and Sui RPC documentation for details of the code that powers the Sui blockchain. +Reference the Iota framework and Iota RPC documentation for details of the code that powers the Iota blockchain. - - -Use GraphQL for the Sui RPC for new projects. Use the JSON-RPC reference for legacy projects that have not migrated to GraphQL yet. + + +Use GraphQL for the Iota RPC for new projects. Use the JSON-RPC reference for legacy projects that have not migrated to GraphQL yet. ## Move -Move powers smart contract logic for the Sui blockchain. Use these resources to learn Move or refresh your memory. +Move powers smart contract logic for the Iota blockchain. Use these resources to learn Move or refresh your memory. - + Documentation for the Move programming language on GitHub. -## Sui CLI +## Iota CLI -Interact directly with Sui networks and its features using the Sui command line interface (CLI). The CLI is divided into separate base commands that target a specific set of features. +Interact directly with Iota networks and its features using the Iota command line interface (CLI). The CLI is divided into separate base commands that target a specific set of features. - -Create a client on a Sui network to generate addresses, access networks, and more with the Sui Client CLI. + +Create a client on a Iota network to generate addresses, access networks, and more with the Iota Client CLI. - -Build, preview, and execute programmable transaction blocks directly from your terminal with the Sui Client PTB CLI. + +Build, preview, and execute programmable transaction blocks directly from your terminal with the Iota Client PTB CLI. - -Access Sui Move functions on chain using the Sui Move CLI. + +Access Iota Move functions on chain using the Iota Move CLI. -## Sui software development kits +## Iota software development kits -Official software development kits (SDKs) available for Sui include the TypeScript SDK and Rust SDK. +Official software development kits (SDKs) available for Iota include the TypeScript SDK and Rust SDK. - -The Sui TypeScript SDK has its own microsite. Click this box to go there. + +The Iota TypeScript SDK has its own microsite. Click this box to go there. - + diff --git a/docs/content/references/cli.mdx b/docs/content/references/cli.mdx index 3de7cf20289..9fce93667a2 100644 --- a/docs/content/references/cli.mdx +++ b/docs/content/references/cli.mdx @@ -1,31 +1,31 @@ --- -title: Sui CLI -description: Sui provides command line tools to interact with the network, its features, and the Move programming language. Individual command groups are referred to as Sui Client CLI, Sui Console CLI, Sui Keytool CLI, Sui Move CLI, and Sui Validator CLI. +title: Iota CLI +description: Iota provides command line tools to interact with the network, its features, and the Move programming language. Individual command groups are referred to as Iota Client CLI, Iota Console CLI, Iota Keytool CLI, Iota Move CLI, and Iota Validator CLI. --- import CliCheckInstall from "../_snippets/cli-check-install.mdx"; -Sui provides a command line interface (CLI) tool to interact with the Sui network, its features, and the Move programming language. The complete suite of tools is called the Sui CLI, with commands grouped together by feature. Each group of commands is commonly referred to by its top-level command: Sui Client CLI, Sui Console CLI, Sui Keytool CLI, Sui Move CLI, and Sui Validator CLI. +Iota provides a command line interface (CLI) tool to interact with the Iota network, its features, and the Move programming language. The complete iotate of tools is called the Iota CLI, with commands grouped together by feature. Each group of commands is commonly referred to by its top-level command: Iota Client CLI, Iota Console CLI, Iota Keytool CLI, Iota Move CLI, and Iota Validator CLI. ## Update CLI -To get the latest version of the CLI, you can run the following command from a terminal or console. Be sure to replace `` with `main`, `devnet`, `testnet`, or `mainnet` to get the desired version. For more information on the branches available, see [Sui Environment Setup](/guides/developer/getting-started/sui-environment.mdx). +To get the latest version of the CLI, you can run the following command from a terminal or console. Be sure to replace `` with `main`, `devnet`, `testnet`, or `mainnet` to get the desired version. For more information on the branches available, see [Iota Environment Setup](/guides/developer/getting-started/iota-environment.mdx). ```shell -cargo install --locked --git https://github.com/MystenLabs/sui.git --branch --features gas-profiler sui +cargo install --locked --git https://github.com/iotaledger/iota.git --branch --features gas-profiler iota ``` -## Sui CLI commands +## Iota CLI commands -There are a number of top-level commands available, but the five most useful to users are the following. Use the `help` flag for the commands that are not documented yet. For example, `sui validator --help`. +There are a number of top-level commands available, but the five most useful to users are the following. Use the `help` flag for the commands that are not documented yet. For example, `iota validator --help`. -- **[Sui Client CLI](./cli/client.mdx):** Use the `sui client` commands to interact with the Sui network. -- **[Sui Client PTB CLI](./cli/ptb.mdx):** Use the `sui client ptb` command to build and execute PTBs. -- **[Sui Console CLI](./cli/console.mdx):** Use `sui console` to open an interactive console with the currently active network. -- **[Sui Keytool CLI](./cli/keytool.mdx):** Use the `sui keytool` commands to access cryptography utilities. -- **[Sui Move CLI](./cli/move.mdx):** Use the `sui move` commands to work with the Move programming language. -- **[Sui Validator CLI](./cli/validator.mdx):** Use the `sui validator` commands to access tools useful for Sui validators. +- **[Iota Client CLI](./cli/client.mdx):** Use the `iota client` commands to interact with the Iota network. +- **[Iota Client PTB CLI](./cli/ptb.mdx):** Use the `iota client ptb` command to build and execute PTBs. +- **[Iota Console CLI](./cli/console.mdx):** Use `iota console` to open an interactive console with the currently active network. +- **[Iota Keytool CLI](./cli/keytool.mdx):** Use the `iota keytool` commands to access cryptography utilities. +- **[Iota Move CLI](./cli/move.mdx):** Use the `iota move` commands to work with the Move programming language. +- **[Iota Validator CLI](./cli/validator.mdx):** Use the `iota validator` commands to access tools useful for Iota validators. diff --git a/docs/content/references/cli/client.mdx b/docs/content/references/cli/client.mdx index e3210e25988..e8b0f85d137 100644 --- a/docs/content/references/cli/client.mdx +++ b/docs/content/references/cli/client.mdx @@ -1,20 +1,20 @@ --- -title: Sui Client CLI -description: The Sui Client CLI provides command-level access to interact with the Sui network. +title: Iota Client CLI +description: The Iota Client CLI provides command-level access to interact with the Iota network. --- import CliCheckInstall from "../../_snippets/cli-check-install.mdx"; -The Sui CLI `client` command provides command-level access to interact with the Sui network. Typical uses for `sui client` include publishing Move smart contracts, getting the information of an object, executing transactions, or managing addresses. +The Iota CLI `client` command provides command-level access to interact with the Iota network. Typical uses for `iota client` include publishing Move smart contracts, getting the information of an object, executing transactions, or managing addresses. ## Commands -The following list itemizes all the available subcommands for the `sui client` command. +The following list itemizes all the available subcommands for the `iota client` command. ``` -Usage: sui client [OPTIONS] [COMMAND] +Usage: iota client [OPTIONS] [COMMAND] Commands: active-address Default address used for commands when none specified @@ -24,7 +24,7 @@ Commands: call Call Move function chain-identifier Query the chain identifier from the rpc endpoint dynamic-field Query a dynamic field by its address - envs List all Sui environments + envs List all Iota environments execute-signed-tx Execute a Signed Transaction. This is useful when the user prefers to sign elsewhere and use this command to execute execute-combined-signed-tx Execute a combined serialized SenderSignedData string faucet Request gas coin from faucet. By default, it will use the active address and the active network @@ -32,19 +32,19 @@ Commands: merge-coin Merge two coin objects into one coin new-address Generate new address and keypair with keypair scheme flag {ed25519 | secp256k1 | secp256r1} with optional derivation path, default to m/44'/4218'/0'/0'/0' for ed25519 or m/54'/4218'/0'/0/0 for secp256k1 or m/74'/4218'/0'/0/0 for secp256r1. Word length can be { word12 | word15 | word18 | word21 | word24} default to word12 if not specified - new-env Add new Sui environment + new-env Add new Iota environment object Get object info objects Obtain all objects owned by the address. It also accepts an address by its alias pay Pay coins to recipients following specified amounts, with input coins. Length of recipients must be the same as that of amounts - pay-all-sui Pay all residual SUI coins to the recipient with input coins, after deducting the gas cost. The input coins also include the coin for gas payment, so no extra gas coin is required - pay-sui Pay SUI coins to recipients following following specified amounts, with input coins. Length of recipients must be the same as that of amounts. The input coins also include the coin for + pay-all-iota Pay all residual IOTA coins to the recipient with input coins, after deducting the gas cost. The input coins also include the coin for gas payment, so no extra gas coin is required + pay-iota Pay IOTA coins to recipients following following specified amounts, with input coins. Length of recipients must be the same as that of amounts. The input coins also include the coin for gas payment, so no extra gas coin is required publish Publish Move modules split-coin Split a coin object into multiple coins switch Switch active address and network(e.g., devnet, local rpc server) tx-block Get the effects of executing the given transaction block transfer Transfer object - transfer-sui Transfer SUI, and pay gas with the same SUI coin object. If amount is specified, only the amount is transferred; otherwise the entire object is transferred + transfer-iota Transfer IOTA, and pay gas with the same IOTA coin object. If amount is specified, only the amount is transferred; otherwise the entire object is transferred upgrade Upgrade Move modules verify-bytecode-meter Run the bytecode verifier on the package verify-source Verify local Move packages against on-chain packages, and optionally their dependencies @@ -64,7 +64,7 @@ Options: ## JSON output -Append the `--json` flag to commands to format responses in JSON instead of the more human-friendly default Sui CLI output. This can be useful for extremely large datasets, for example, as those results can have a troublesome display on smaller screens. In these cases, the `--json` flag is useful. +Append the `--json` flag to commands to format responses in JSON instead of the more human-friendly default Iota CLI output. This can be useful for extremely large datasets, for example, as those results can have a troublesome display on smaller screens. In these cases, the `--json` flag is useful. ## Examples @@ -72,53 +72,53 @@ The following examples demonstrate some of the most often used commands. ### List available network environments -Use the `sui client envs` command to find the network environments set up in the CLI. The information for these environments is also stored in the client.yaml file in the Sui configuration directory (`~/.sui/sui_config`). +Use the `iota client envs` command to find the network environments set up in the CLI. The information for these environments is also stored in the client.yaml file in the Iota configuration directory (`~/.iota/iota_config`). ```shell ╭────────┬────────────────────────────────────┬────────╮ │ alias │ url │ active │ ├────────┼────────────────────────────────────┼────────┤ -│ devnet │ https://fullnode.devnet.sui.io:443 │ * │ +│ devnet │ https://fullnode.devnet.iota.io:443 │ * │ ╰────────┴────────────────────────────────────┴────────╯ ``` ### Create network environment -Use `client new-env` to add details for a new network environment. This example creates an environment pointer to Sui Mainnet. Setting the `alias` value makes referencing the environment less prone to typographical errors. After running this command, Sui updates your client.yaml file in `~/.sui/sui_config` with the new information. +Use `client new-env` to add details for a new network environment. This example creates an environment pointer to Iota Mainnet. Setting the `alias` value makes referencing the environment less prone to typographical errors. After running this command, Iota updates your client.yaml file in `~/.iota/iota_config` with the new information. ``` -$ sui client new-env --alias=mainnet --rpc https://fullnode.mainnet.sui.io:443 +$ iota client new-env --alias=mainnet --rpc https://fullnode.mainnet.iota.io:443 -Added new Sui env [mainnet] to config. +Added new Iota env [mainnet] to config. ``` ### Set current environment -Use the `sui client switch` command to change the current network. This example switches the current network to `mainnet`. +Use the `iota client switch` command to change the current network. This example switches the current network to `mainnet`. ```shell -$ sui client switch --env mainnet +$ iota client switch --env mainnet Active environment switched to [mainnet] ``` -If you run `sui client envs` after this command, you see the asterisk in the `active` column on the `mainnet` row of the table. +If you run `iota client envs` after this command, you see the asterisk in the `active` column on the `mainnet` row of the table. ### Get current active address -Use the `sui client active-address` command to reveal the current address. The CLI uses the current active address to execute address-specific CLI commands (like `sui client objects`) when you don't provide them with a Sui address value. +Use the `iota client active-address` command to reveal the current address. The CLI uses the current active address to execute address-specific CLI commands (like `iota client objects`) when you don't provide them with a Iota address value. ```shell -$ sui client active-address +$ iota client active-address 0x514692f08249c3e9951234ce29074695840422564bff85e424b56de462913e0d ``` ### Get objects owned by an address -Use `sui client objects` to list summary information about the objects the current active address owns. You can provide a Sui address value to the command to list objects for a particular address. This example lists objects for the current active address. +Use `iota client objects` to list summary information about the objects the current active address owns. You can provide a Iota address value to the command to list objects for a particular address. This example lists objects for the current active address. ``` -$ sui client objects 0x36df11369cf00ecf0be68d6ba965b0abe2e883bc5245911e3a29ebfa0aaf6b69 +$ iota client objects 0x36df11369cf00ecf0be68d6ba965b0abe2e883bc5245911e3a29ebfa0aaf6b69 ╭───────────────────────────────────────────────────────────────────────────────────────╮ | ╭────────────┬──────────────────────────────────────────────────────────────────────╮ │ @@ -138,21 +138,21 @@ $ sui client objects 0x36df11369cf00ecf0be68d6ba965b0abe2e883bc5245911e3a29ebfa0 ### Get complete object information -Use `sui client object ` to list object information for the ID you provide. This example displays the information for a Coin object. +Use `iota client object ` to list object information for the ID you provide. This example displays the information for a Coin object. ``` -$ sui client object 0xfffbb30ccb631f15f6cd36700589fc9c31cb04af28a95f3ed26d62daf3acb57f +$ iota client object 0xfffbb30ccb631f15f6cd36700589fc9c31cb04af28a95f3ed26d62daf3acb57f ╭───────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ objectId │ 0xfffbb30ccb631f15f6cd36700589fc9c31cb04af28a95f3ed26d62daf3acb57f │ │ version │ 33363559 │ │ digest │ 3FzvXJVVVcXb9H6dEXdARaY9EmxXyyNFduet3X4eYV4x │ -│ objType │ 0x2::coin::Coin<0x2::sui::SUI> │ +│ objType │ 0x2::coin::Coin<0x2::iota::IOTA> │ │ ownerType │ AddressOwner │ │ prevTx │ ES2RQThjRE5u8rwiUEnhcnMoLA3cHeEGYJ8Pq98tmyAc │ │ storageRebate │ 988000 │ │ content │ ╭───────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────╮ │ │ │ │ dataType │ moveObject │ │ -│ │ │ type │ 0x2::coin::Coin<0x2::sui::SUI> │ │ +│ │ │ type │ 0x2::coin::Coin<0x2::iota::IOTA> │ │ │ │ │ hasPublicTransfer │ true │ │ │ │ │ fields │ ╭─────────┬───────────────────────────────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ balance │ 530076676 │ │ │ @@ -166,10 +166,10 @@ $ sui client object 0xfffbb30ccb631f15f6cd36700589fc9c31cb04af28a95f3ed26d62daf3 ### Get dynamic fields of an object -Use the `sui client dynamic-field ` command to list the details of the dynamic field with the ID you provide. +Use the `iota client dynamic-field ` command to list the details of the dynamic field with the ID you provide. ``` -$ sui client dynamic-field 0x5 +$ iota client dynamic-field 0x5 ╭─────────────┬───────────────────────────────────────────────────────────────────────────────────────────╮ │ hasNextPage │ false │ │ nextCursor │ 0x5b890eaf2abcfa2ab90b77b8e6f3d5d8609586c3e583baf3dccd5af17edf48d1 │ @@ -181,7 +181,7 @@ $ sui client dynamic-field 0x5 │ │ │ │ │ ╰───────┴───────╯ │ │ │ │ │ │ │ bcsName │ LQM2cdzDY3 │ │ │ │ │ │ │ type │ DynamicField │ │ │ -│ │ │ │ objectType │ 0x3::sui_system_state_inner::SuiSystemStateInnerV2 │ │ │ +│ │ │ │ objectType │ 0x3::iota_system_state_inner::IotaSystemStateInnerV2 │ │ │ │ │ │ │ objectId │ 0x5b890eaf2abcfa2ab90b77b8e6f3d5d8609586c3e583baf3dccd5af17edf48d1 │ │ │ │ │ │ │ version │ 112 │ │ │ │ │ │ │ digest │ HMrm1KNKjq3GfB1cWTRdvRo8gk7auhgvoZXaVoyEHqUR │ │ │ @@ -192,7 +192,7 @@ $ sui client dynamic-field 0x5 ### Replay a transaction -Use the `sui client replay-transaction --tx-digest ` to re-execute a transaction locally and show the transaction effects. +Use the `iota client replay-transaction --tx-digest ` to re-execute a transaction locally and show the transaction effects. This command will fetch the transaction dependencies from the fullnode specified in the client env. For transactions that happened quite far in the past, it is advised to set the client fullnode to one that has non-pruned chain data for that transaction. This will also verify that the resulting effects from the locally executed transaction match the effects of the transaction stored on-chain. @@ -200,7 +200,7 @@ This will also verify that the resulting effects from the locally executed trans You can add additional flags `--gas-info` and `--ptb-info` to this command to see more information about the transaction. ``` -$ sui client replay-transaction --tx-digest 51MzJP2Uesvza8vXGpPCGbfLrY6UCfdvdoErN1z4oXPW +$ iota client replay-transaction --tx-digest 51MzJP2Uesvza8vXGpPCGbfLrY6UCfdvdoErN1z4oXPW ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Transaction Effects │ ├───────────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -243,20 +243,20 @@ $ sui client replay-transaction --tx-digest 51MzJP2Uesvza8vXGpPCGbfLrY6UCfdvdoEr Execution finished successfully. Local and on-chain effects match. ``` -Use `sui client replay-batch --path ` to replay several transactions listed in a newline-separated file. This +Use `iota client replay-batch --path ` to replay several transactions listed in a newline-separated file. This will verify that all transactions local execution results match the effects on-chain. ### Profile a transaction -Use the `sui client profile-transaction --tx-digest ` command to re-execute a transaction locally +Use the `iota client profile-transaction --tx-digest ` command to re-execute a transaction locally and produce a gas profile. Similar to the `replay` command, this command fetches the transaction dependencies from the Full node specified in the client environment that are needed to execute the transaction. During the local execution of the transaction, this command records all the Move function invocations and the gas cost breakdown for each invocation. -To enable the profiler, you must either install or build the Sui Client binary locally with the `--features gas-profiler` flag. +To enable the profiler, you must either install or build the Iota Client binary locally with the `--features gas-profiler` flag. ```shell -cargo install --locked --git https://github.com/MystenLabs/sui.git --branch --features gas-profiler sui +cargo install --locked --git https://github.com/iotaledger/iota.git --branch --features gas-profiler iota ``` The command outputs a profile to the current working directory in the format `gas_profile_{tx_digest}_{unix_timestamp}.json`. @@ -294,30 +294,30 @@ your published smart contract, and finally run the profiler on the transaction t ## Publish a Move package -One of the main uses of the `sui client` command is to publish smart contracts on the Sui network. This example switches the current environment to the Devnet network, then builds, tests, and publishes one of the existing Move examples available in the Sui repository: [sui/examples/move](https://github.com/MystenLabs/sui/tree/main/examples/move) +One of the main uses of the `iota client` command is to publish smart contracts on the Iota network. This example switches the current environment to the Devnet network, then builds, tests, and publishes one of the existing Move examples available in the Iota repository: [iota/examples/move](https://github.com/iotaledger/iota/tree/main/examples/move) -This example also makes use of `sui move` commands. To learn more about those commands, see [Sui Move CLI](./move.mdx). +This example also makes use of `iota move` commands. To learn more about those commands, see [Iota Move CLI](./move.mdx). -1. Open a terminal or console to the root of your local Sui repository and navigate to the `move_tutorial` example. +1. Open a terminal or console to the root of your local Iota repository and navigate to the `move_tutorial` example. ```shell cd examples/move cd first_package ``` -1. Switch to the Devnet network. This command uses an alias, so the `devnet` value might be different for you, depending on the alias name set in your configuration (use `sui client envs` for a list of your defined networks and their aliases). +1. Switch to the Devnet network. This command uses an alias, so the `devnet` value might be different for you, depending on the alias name set in your configuration (use `iota client envs` for a list of your defined networks and their aliases). ```shell - sui client switch --env devnet + iota client switch --env devnet ``` -1. Use `sui move build` to build the package. You must run this command at the same level as the package manifest file ([Move.toml](/references/move/move-toml.mdx)). The console responds with the status of the build. +1. Use `iota move build` to build the package. You must run this command at the same level as the package manifest file ([Move.toml](/references/move/move-toml.mdx)). The console responds with the status of the build. ```shell - sui move build - INCLUDING DEPENDENCY Sui + iota move build + INCLUDING DEPENDENCY Iota INCLUDING DEPENDENCY MoveStdlib BUILDING first_package ``` -1. Use `sui move test` to run the unit tests. The console responds with updates of its progress. +1. Use `iota move test` to run the unit tests. The console responds with updates of its progress. ```shell - sui move test - INCLUDING DEPENDENCY Sui + iota move test + INCLUDING DEPENDENCY Iota INCLUDING DEPENDENCY MoveStdlib BUILDING first_package Running Move unit tests @@ -325,9 +325,9 @@ This example also makes use of `sui move` commands. To learn more about those co [ PASS ] 0x0::example::test_sword_transactions Test result: OK. Total tests: 2; passed: 2; failed: 0 ``` -1. Use the `sui client verify-bytecode-meter` to check if the module passes the bytecode meter. The console responds with the maximum allowed values, as well as the amount the package uses. +1. Use the `iota client verify-bytecode-meter` to check if the module passes the bytecode meter. The console responds with the maximum allowed values, as well as the amount the package uses. ```shell - $ sui client verify-bytecode-meter + $ iota client verify-bytecode-meter Running bytecode verifier for 1 modules ╭──────────────────────────────────╮ │ Module will pass metering check! │ @@ -337,35 +337,35 @@ This example also makes use of `sui move` commands. To learn more about those co │ Used │ 4565 │ 4565 │ ╰────────┴────────────┴────────────╯ ``` -1. Use `sui client gas` to verify that the active address has a gas coin for paying gas. In the case of this example, the console responds with the information that the address is coinless. +1. Use `iota client gas` to verify that the active address has a gas coin for paying gas. In the case of this example, the console responds with the information that the address is coinless. ```shell - $ sui client gas + $ iota client gas No gas coins are owned by this address ``` -1. If you need coins, use `sui client faucet` (not available for Mainnet). For more information on getting gas tokens, see [Get Sui Tokens](/guides/developer/getting-started/get-coins.mdx). +1. If you need coins, use `iota client faucet` (not available for Mainnet). For more information on getting gas tokens, see [Get Iota Tokens](/guides/developer/getting-started/get-coins.mdx). ```shell - $ sui client faucet + $ iota client faucet ``` -1. Use `sui client gas` to verify the current active address received the coins. +1. Use `iota client gas` to verify the current active address received the coins. ```shell - $ sui client gas + $ iota client gas ╭────────────────────────────────────────────────────────────────────┬─────────────╮ │ gasCoinId │ gasBalance │ ├────────────────────────────────────────────────────────────────────┼─────────────┤ │ 0x01b2795ba5800c8f7cb7d7c56abe19e24c656ed6764f3ccc5e66da3de52402a8 │ 10000000000 │ ╰────────────────────────────────────────────────────────────────────┴─────────────╯ ``` -1. Use `sui client publish` to publish the package, being sure to set an appropriate value for the `gas-budget` flag. The console responds with the details of the publish. You can use `sui client object ` to check the details of any of the objects from the process. +1. Use `iota client publish` to publish the package, being sure to set an appropriate value for the `gas-budget` flag. The console responds with the details of the publish. You can use `iota client object ` to check the details of any of the objects from the process. ```shell - $ sui client publish --gas-budget 100000000 . + $ iota client publish --gas-budget 100000000 . Transaction Digest: ABPd7v8BxLkcyHvX8Jt1SbneQRwzE9WzcEoptT2RDNVF ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Transaction Data │ ├──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ Sender: 0x0fe375fff0ee40d20c54a7f2478b9b5c7eaa3625b7611f9661ec5faefb4a6fea │ │ Gas Owner: 0x0fe375fff0ee40d20c54a7f2478b9b5c7eaa3625b7611f9661ec5faefb4a6fea │ - │ Gas Budget: 5000000000 MIST │ - │ Gas Price: 1000 MIST │ + │ Gas Budget: 5000000000 MICROS │ + │ Gas Price: 1000 MICROS │ │ Gas Payment: │ │ ┌── │ │ │ ID: 0x01b2795ba5800c8f7cb7d7c56abe19e24c656ed6764f3ccc5e66da3de52402a8 │ @@ -479,7 +479,7 @@ This example also makes use of `sui move` commands. To learn more about those co │ │ ObjectID: 0x01b2795ba5800c8f7cb7d7c56abe19e24c656ed6764f3ccc5e66da3de52402a8 │ │ │ Sender: 0x0fe375fff0ee40d20c54a7f2478b9b5c7eaa3625b7611f9661ec5faefb4a6fea │ │ │ Owner: Account Address ( 0x0fe375fff0ee40d20c54a7f2478b9b5c7eaa3625b7611f9661ec5faefb4a6fea ) │ - │ │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI> │ + │ │ ObjectType: 0x2::coin::Coin<0x2::iota::IOTA> │ │ │ Version: 3 │ │ │ Digest: 46rvdbXkw5qqsBYbUGChzgFatJAYPmarPmFHgRRJiiU9 │ │ └── │ @@ -496,7 +496,7 @@ This example also makes use of `sui move` commands. To learn more about those co ├───────────────────────────────────────────────────────────────────────────────────────────────────┤ │ ┌── │ │ │ Owner: Account Address ( 0x0fe375fff0ee40d20c54a7f2478b9b5c7eaa3625b7611f9661ec5faefb4a6fea ) │ - │ │ CoinType: 0x2::sui::SUI │ + │ │ CoinType: 0x2::iota::IOTA │ │ │ Amount: -10000680 │ │ └── │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────╯ @@ -504,12 +504,12 @@ This example also makes use of `sui move` commands. To learn more about those co ## Help -Each command has its own help section. For example, `sui client call --help` displays the following prompt: +Each command has its own help section. For example, `iota client call --help` displays the following prompt: ``` Call Move function -Usage: sui client call [OPTIONS] --package --module --function --gas-budget +Usage: iota client call [OPTIONS] --package --module --function --gas-budget Options: --package Object ID of the package, which contains the module @@ -520,9 +520,9 @@ Options: --gas ID of the gas object for gas payment, in 20 bytes Hex string If not provided, a gas object with at least gas_budget value will be selected --gas-budget Gas budget for this call --serialize-unsigned-transaction Instead of executing the transaction, serialize the bcs bytes of the unsigned transaction data (TransactionData) using base64 encoding, and print out - the string . The string can be used to execute transaction with `sui client execute-signed-tx --tx-bytes `. + the string . The string can be used to execute transaction with `iota client execute-signed-tx --tx-bytes `. --serialize-signed-transaction Instead of executing the transaction, serialize the bcs bytes of the signed transaction data (SenderSignedData) using base64 encoding, and print out the - string . The string can be used to execute transaction with `sui client execute-combined-signed-tx --signed-tx-bytes `. + string . The string can be used to execute transaction with `iota client execute-combined-signed-tx --signed-tx-bytes `. --json Return command outputs in json format -h, --help Print help ``` diff --git a/docs/content/references/cli/console.mdx b/docs/content/references/cli/console.mdx index 954a7dc55aa..3f4a7253254 100644 --- a/docs/content/references/cli/console.mdx +++ b/docs/content/references/cli/console.mdx @@ -1,51 +1,51 @@ --- -title: Sui Console CLI -description: The Sui Console CLI provides command-level access to interact with the Sui network by wrapping the Sui Client CLI command. +title: Iota Console CLI +description: The Iota Console CLI provides command-level access to interact with the Iota network by wrapping the Iota Client CLI command. --- import CliCheckInstall from "../../_snippets/cli-check-install.mdx"; -The Sui CLI `console` command provides command-level access to interact with the Sui network by wrapping the Sui Client CLI command in a shell-like functionality. This command spins up a new process and provides the user an environment for running all the available Sui Client CLI commands. In addition, it also offers command history support. +The Iota CLI `console` command provides command-level access to interact with the Iota network by wrapping the Iota Client CLI command in a shell-like functionality. This command spins up a new process and provides the user an environment for running all the available Iota Client CLI commands. In addition, it also offers command history support. ## Commands -For all available commands, consult the [Sui Client CLI docs](./client.mdx). To start the Sui Console, type `sui console`, which displays some information similar to the following: +For all available commands, consult the [Iota Client CLI docs](./client.mdx). To start the Iota Console, type `iota console`, which displays some information similar to the following: ```shell -🚀 ~ % sui console +🚀 ~ % iota console _____ _ ______ __ / ___/__ __(_) / ____/___ ____ _________ / /__ \__ \/ / / / / / / / __ \/ __ \/ ___/ __ \/ / _ \ ___/ / /_/ / / / /___/ /_/ / / / (__ ) /_/ / / __/ /____/\__,_/_/ \____/\____/_/ /_/____/\____/_/\___/ ---- Sui Console 1.14.0 --- +--- Iota Console 1.14.0 --- Managed addresses : 2 Active address: 0x3...235 Keystore Type : File -Keystore Path : Some("/Users/user/.sui/sui_config/sui.keystore") +Keystore Path : Some("/Users/user/.iota/iota_config/iota.keystore") Active environment : testnet -RPC URL: https://fullnode.testnet.sui.io:443 +RPC URL: https://fullnode.testnet.iota.io:443 [warn] Client/Server api version mismatch, client api version : 1.14.0, server api version : 1.13.0 -Connecting to Sui full node. API version 1.13.0 - -Available RPC methods: ["sui_devInspectTransactionBlock", "sui_dryRunTransactionBlock", "sui_executeTransactionBlock", -"sui_getChainIdentifier", "sui_getCheckpoint", "sui_getCheckpoints", "sui_getEvents", "sui_getLatestCheckpointSequenceNumber", -"sui_getLoadedChildObjects", "sui_getMoveFunctionArgTypes", "sui_getNormalizedMoveFunction", "sui_getNormalizedMoveModule", -"sui_getNormalizedMoveModulesByPackage", "sui_getNormalizedMoveStruct", "sui_getObject", "sui_getProtocolConfig", -"sui_getTotalTransactionBlocks", "sui_getTransactionBlock", "sui_multiGetObjects", "sui_multiGetTransactionBlocks", -"sui_tryGetPastObject", "sui_tryMultiGetPastObjects", "suix_getAllBalances", "suix_getAllCoins", "suix_getBalance", -"suix_getCoinMetadata", "suix_getCoins", "suix_getCommitteeInfo", "suix_getDynamicFieldObject", "suix_getDynamicFields", -"suix_getLatestSuiSystemState", "suix_getOwnedObjects", "suix_getReferenceGasPrice", "suix_getStakes", "suix_getStakesByIds", -"suix_getTotalSupply", "suix_getValidatorsApy", "suix_queryEvents", "suix_queryTransactionBlocks", "suix_resolveNameServiceAddress", -"suix_resolveNameServiceNames", "suix_subscribeEvent", "suix_subscribeTransaction", "unsafe_batchTransaction", "unsafe_mergeCoins", -"unsafe_moveCall", "unsafe_pay", "unsafe_payAllSui", "unsafe_paySui", "unsafe_publish", "unsafe_requestAddStake", -"unsafe_requestWithdrawStake", "unsafe_splitCoin", "unsafe_splitCoinEqual", "unsafe_transferObject", "unsafe_transferSui"] - -Welcome to the Sui interactive console. - -sui>-$ +Connecting to Iota full node. API version 1.13.0 + +Available RPC methods: ["iota_devInspectTransactionBlock", "iota_dryRunTransactionBlock", "iota_executeTransactionBlock", +"iota_getChainIdentifier", "iota_getCheckpoint", "iota_getCheckpoints", "iota_getEvents", "iota_getLatestCheckpointSequenceNumber", +"iota_getLoadedChildObjects", "iota_getMoveFunctionArgTypes", "iota_getNormalizedMoveFunction", "iota_getNormalizedMoveModule", +"iota_getNormalizedMoveModulesByPackage", "iota_getNormalizedMoveStruct", "iota_getObject", "iota_getProtocolConfig", +"iota_getTotalTransactionBlocks", "iota_getTransactionBlock", "iota_multiGetObjects", "iota_multiGetTransactionBlocks", +"iota_tryGetPastObject", "iota_tryMultiGetPastObjects", "iotax_getAllBalances", "iotax_getAllCoins", "iotax_getBalance", +"iotax_getCoinMetadata", "iotax_getCoins", "iotax_getCommitteeInfo", "iotax_getDynamicFieldObject", "iotax_getDynamicFields", +"iotax_getLatestIotaSystemState", "iotax_getOwnedObjects", "iotax_getReferenceGasPrice", "iotax_getStakes", "iotax_getStakesByIds", +"iotax_getTotalSupply", "iotax_getValidatorsApy", "iotax_queryEvents", "iotax_queryTransactionBlocks", "iotax_resolveNameServiceAddress", +"iotax_resolveNameServiceNames", "iotax_subscribeEvent", "iotax_subscribeTransaction", "unsafe_batchTransaction", "unsafe_mergeCoins", +"unsafe_moveCall", "unsafe_pay", "unsafe_payAllIota", "unsafe_payIota", "unsafe_publish", "unsafe_requestAddStake", +"unsafe_requestWithdrawStake", "unsafe_splitCoin", "unsafe_splitCoinEqual", "unsafe_transferObject", "unsafe_transferIota"] + +Welcome to the Iota interactive console. + +iota>-$ ``` diff --git a/docs/content/references/cli/keytool.mdx b/docs/content/references/cli/keytool.mdx index 2be3a76855f..a05ee0b45e3 100644 --- a/docs/content/references/cli/keytool.mdx +++ b/docs/content/references/cli/keytool.mdx @@ -1,56 +1,56 @@ --- -title: Sui Keytool CLI -description: The Sui Keytool CLI has commands for managing and generating addresses, working with private keys, signatures, or zkLogin. +title: Iota Keytool CLI +description: The Iota Keytool CLI has commands for managing and generating addresses, working with private keys, signatures, or zkLogin. --- import CliCheckInstall from "../../_snippets/cli-check-install.mdx"; -The Sui CLI `keytool` command provides several command-level access for the management and generation of addresses, as well as working with private keys, signatures, or zkLogin. For example, a user could export a private key from the Sui Wallet and import it into the local Sui CLI wallet using the `sui keytool import [...]` command. +The Iota CLI `keytool` command provides several command-level access for the management and generation of addresses, as well as working with private keys, signatures, or zkLogin. For example, a user could export a private key from the Iota Wallet and import it into the local Iota CLI wallet using the `iota keytool import [...]` command. ## Commands ``` -Usage: sui keytool [OPTIONS] +Usage: iota keytool [OPTIONS] Commands: - convert Convert private key from legacy formats (e.g. Hex or Base64) to Bech32 encoded 33 byte `flag || private key` begins with `suiprivkey` + convert Convert private key from legacy formats (e.g. Hex or Base64) to Bech32 encoded 33 byte `flag || private key` begins with `iotaprivkey` decode-or-verify-tx Given a Base64 encoded transaction bytes, decode its components. If a signature is provided, verify the signature against the transaction and output the result. decode-multi-sig Given a Base64 encoded MultiSig signature, decode its components. If tx_bytes is passed in, verify the multisig generate Generate a new keypair with key scheme flag {ed25519 | secp256k1 | secp256r1} with optional derivation path, default to m/44'/4218'/0'/0'/0' for ed25519 or m/54'/4218'/0'/0/0 for secp256k1 or m/74'/4218'/0'/0/0 for secp256r1. Word length can be { word12 | word15 | word18 | word21 | word24} default to word12 if not specified - import Add a new key to sui.keystore using either the input mnemonic phrase or a private key (from the Wallet), the key scheme flag {ed25519 | + import Add a new key to iota.keystore using either the input mnemonic phrase or a private key (from the Wallet), the key scheme flag {ed25519 | secp256k1 | secp256r1} and an optional derivation path, default to m/44'/4218'/0'/0'/0' for ed25519 or m/54'/4218'/0'/0/0 for secp256k1 or m/74'/4218'/0'/0/0 for secp256r1. Supports mnemonic phrase of word length 12, 15, 18`, 21, 24 - list List all keys by its Sui address, Base64 encoded public key, key scheme name in sui.keystore - load-keypair This reads the content at the provided file path. The accepted format can be [enum SuiKeyPair] (Base64 encoded of 33-byte `flag || + list List all keys by its Iota address, Base64 encoded public key, key scheme name in iota.keystore + load-keypair This reads the content at the provided file path. The accepted format can be [enum IotaKeyPair] (Base64 encoded of 33-byte `flag || privkey`) or `type AuthorityKeyPair` (Base64 encoded `privkey`). This prints out the account keypair as Base64 encoded `flag || privkey`, the network keypair, worker keypair, protocol keypair as Base64 encoded `privkey` - multi-sig-address To MultiSig Sui Address. Pass in a list of all public keys `flag || pk` in Base64. See `keytool list` for example public keys + multi-sig-address To MultiSig Iota Address. Pass in a list of all public keys `flag || pk` in Base64. See `keytool list` for example public keys multi-sig-combine-partial-sig Provides a list of participating signatures (`flag || sig || pk` encoded in Base64), threshold, a list of all public keys and a list of their weights that define the MultiSig address. Returns a valid MultiSig signature and its sender address. The result can be used as - signature field for `sui client execute-signed-tx`. The sum of weights of all signatures must be >= the threshold + signature field for `iota client execute-signed-tx`. The sum of weights of all signatures must be >= the threshold multi-sig-combine-partial-sig-legacy - show Read the content at the provided file path. The accepted format can be [enum SuiKeyPair] (Base64 encoded of 33-byte `flag || privkey`) + show Read the content at the provided file path. The accepted format can be [enum IotaKeyPair] (Base64 encoded of 33-byte `flag || privkey`) or `type AuthorityKeyPair` (Base64 encoded `privkey`). It prints its Base64 encoded public key and the key scheme flag - sign Create signature using the private key for for the given address in sui keystore. Any signature commits to a [struct IntentMessage] + sign Create signature using the private key for for the given address in iota keystore. Any signature commits to a [struct IntentMessage] consisting of the Base64 encoded of the BCS serialized transaction bytes itself and its intent. If intent is absent, default will be used sign-kms Creates a signature by leveraging AWS KMS. Pass in a key-id to leverage Amazon KMS to sign a message and the base64 pubkey. Generate PubKey from pem using MystenLabs/base64pemkey Any signature commits to a [struct IntentMessage] consisting of the Base64 encoded of the BCS serialized transaction bytes itself and its intent. If intent is absent, default will be used - unpack This takes [enum SuiKeyPair] of Base64 encoded of 33-byte `flag || privkey`). It outputs the keypair into a file at the current - directory where the address is the filename, and prints out its Sui address, Base64 encoded public key, the key scheme, and the key + unpack This takes [enum IotaKeyPair] of Base64 encoded of 33-byte `flag || privkey`). It outputs the keypair into a file at the current + directory where the address is the filename, and prints out its Iota address, Base64 encoded public key, the key scheme, and the key scheme flag zk-login-sign-and-execute-tx Given the max_epoch, generate an OAuth url, ask user to paste the redirect with id_token, call salt server, then call the prover server, create a test transaction, use the ephemeral key to sign and execute it by assembling to a serialized zkLogin signature zk-login-enter-token A workaround to the above command because sometimes token pasting does not work. All the inputs required here are printed from the command above zk-login-sig-verify Given a zkLogin signature, parse it if valid. If tx_bytes provided, it verifies the zkLogin signature based on provider and its latest - JWK fetched. Example request: sui keytool zk-login-sig-verify --sig $SERIALIZED_ZKLOGIN_SIG --tx-bytes $TX_BYTES --provider Google + JWK fetched. Example request: iota keytool zk-login-sig-verify --sig $SERIALIZED_ZKLOGIN_SIG --tx-bytes $TX_BYTES --provider Google --curr-epoch 10 help Print this message or the help of the given subcommand(s) @@ -62,7 +62,7 @@ Options: ## JSON output -Append the `--json` flag to commands to format responses in JSON instead of the more human friendly default Sui CLI output. This can be useful for extremely large datasets, for example, as those results can have a troublesome display on smaller screens. In these cases, the `--json` flag is useful. +Append the `--json` flag to commands to format responses in JSON instead of the more human friendly default Iota CLI output. This can be useful for extremely large datasets, for example, as those results can have a troublesome display on smaller screens. In these cases, the `--json` flag is useful. ## Examples @@ -70,20 +70,20 @@ The following examples demonstrate some of the most often used commands. ### List the key pairs in the local wallet -Use the `sui keytool list` command to output all the Sui addresses that exist in the `~/.sui/sui_config/sui.keystore` file in a readable format. +Use the `iota keytool list` command to output all the Iota addresses that exist in the `~/.iota/iota_config/iota.keystore` file in a readable format. ```shell -$ sui keytool list +$ iota keytool list ╭────────────────────────────────────────────────────────────────────────────────────────────╮ │ ╭─────────────────┬──────────────────────────────────────────────────────────────────────╮ │ -│ │ suiAddress │ 0x3047f142a84297a42a65fb0a8c7a716d9d1b0bd0413d6bfa5ddfec45df175235 │ │ +│ │ iotaAddress │ 0x3047f142a84297a42a65fb0a8c7a716d9d1b0bd0413d6bfa5ddfec45df175235 │ │ │ │ publicBase64Key │ AHsXwcxaWNaNtCIIszwu7V2G6HO8aNM1598w/8y0zI5q │ │ │ │ keyScheme │ ed25519 │ │ │ │ flag │ 0 │ │ │ │ peerId │ 7b17c1cc5a58d68db42208b33c2eed5d86e873bc68d335e7df30ffccb4cc8e6a │ │ │ ╰─────────────────┴──────────────────────────────────────────────────────────────────────╯ │ │ ╭─────────────────┬──────────────────────────────────────────────────────────────────────╮ │ -│ │ suiAddress │ 0x514692f08249c3e9957799ce29074695840422564bff85e424b56de462913e0d │ │ +│ │ iotaAddress │ 0x514692f08249c3e9957799ce29074695840422564bff85e424b56de462913e0d │ │ │ │ publicBase64Key │ AKJCGi8R8TslhYdO2OHIjI6rbr+to1eR+vlOjigLY6SX │ │ │ │ keyScheme │ ed25519 │ │ │ │ flag │ 0 │ │ @@ -94,12 +94,12 @@ $ sui keytool list ### Generate a new key pair and store it in a file -To generate a new key pair with the `ed25519` scheme, use the `sui keytool generate ed25519` command. For other schemes, see `sui keytool generate –help`. The key pair file is saved to the current directory with its filename being the address. The content of the file is a Base64 encoded string of 33-byte `flag || privkey`. +To generate a new key pair with the `ed25519` scheme, use the `iota keytool generate ed25519` command. For other schemes, see `iota keytool generate –help`. The key pair file is saved to the current directory with its filename being the address. The content of the file is a Base64 encoded string of 33-byte `flag || privkey`. ```shell -$ sui keytool generate ed25519 +$ iota keytool generate ed25519 ╭─────────────────┬───────────────────────────────────────────────────────────────────────────────────╮ -│ suiAddress │ 0x5d8aa70f17d9343813d3ba6a59ecf5e8a23ffb487938e860999a722989eaef25 │ +│ iotaAddress │ 0x5d8aa70f17d9343813d3ba6a59ecf5e8a23ffb487938e860999a722989eaef25 │ │ publicBase64Key │ AKTAGf9iv0JqeLXXlsr4PUzBXb9VY8lK7xiZMS50GSu6 │ │ keyScheme │ ed25519 │ │ flag │ 0 │ @@ -110,12 +110,12 @@ $ sui keytool generate ed25519 ### Show the key pair data from a file -Use `sui keytool show [filename]` to show the key pair data that is stored in a file. For example, the previous command generated a file named `0x5d8aa70f17d9343813d3ba6a59ecf5e8a23ffb487938e860999a722989eaef25.key`. +Use `iota keytool show [filename]` to show the key pair data that is stored in a file. For example, the previous command generated a file named `0x5d8aa70f17d9343813d3ba6a59ecf5e8a23ffb487938e860999a722989eaef25.key`. ```shell -$ sui keytool show 0x5d8aa70f17d9343813d3ba6a59ecf5e8a23ffb487938e860999a722989eaef25.key +$ iota keytool show 0x5d8aa70f17d9343813d3ba6a59ecf5e8a23ffb487938e860999a722989eaef25.key ╭─────────────────┬──────────────────────────────────────────────────────────────────────╮ -│ suiAddress │ 0x5d8aa70f17d9343813d3ba6a59ecf5e8a23ffb487938e860999a722989eaef25 │ +│ iotaAddress │ 0x5d8aa70f17d9343813d3ba6a59ecf5e8a23ffb487938e860999a722989eaef25 │ │ publicBase64Key │ AC+AKTAGf9iv0JqeLXXlsr4PUzBXb9VY8lK7xiZMS50GSu6 │ │ keyScheme │ ed25519 │ │ flag │ 0 │ @@ -126,10 +126,10 @@ $ sui keytool show 0x5d8aa70f17d9343813d3ba6a59ecf5e8a23ffb487938e860999a722989e ### Sign a transaction ```shell -$ sui keytool sign --data AAABACBRRpLwgknD6ZV3mc4pB0aVhAQiVkv/heQktW3kYpE+DQEBAQABAAAwR/FCqEKXpCpl+wqMenFtnRsL0EE9a/pd3+xF3xdSNQEaEUeErlBmGWxz3Bh+9BZh2mzayodzsri7xIZNDHRA3wIAAAAAAAAAILsR2d1FIZ5+ADDYZtJ2e9CWlpAxsGd4Y2rZrjlyTUF1MEfxQqhCl6QqZfsKjHpxbZ0bC9BBPWv6Xd/sRd8XUjXoAwAAAAAAAICWmAAAAAAAAA== --address 0x3047f142a84297a42a65fb0a8c7a716d9d1b0bd0413d6bfa5ddfec45df175235 +$ iota keytool sign --data AAABACBRRpLwgknD6ZV3mc4pB0aVhAQiVkv/heQktW3kYpE+DQEBAQABAAAwR/FCqEKXpCpl+wqMenFtnRsL0EE9a/pd3+xF3xdSNQEaEUeErlBmGWxz3Bh+9BZh2mzayodzsri7xIZNDHRA3wIAAAAAAAAAILsR2d1FIZ5+ADDYZtJ2e9CWlpAxsGd4Y2rZrjlyTUF1MEfxQqhCl6QqZfsKjHpxbZ0bC9BBPWv6Xd/sRd8XUjXoAwAAAAAAAICWmAAAAAAAAA== --address 0x3047f142a84297a42a65fb0a8c7a716d9d1b0bd0413d6bfa5ddfec45df175235 ╭──────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ suiAddress │ 0x3047f142a84297a42a65fb0a8c7a716d9d1b0bd0413d6bfa5ddfec45df175235 │ +│ iotaAddress │ 0x3047f142a84297a42a65fb0a8c7a716d9d1b0bd0413d6bfa5ddfec45df175235 │ │ rawTxData │ AAABACBRRpLwgknD6ZV3mc4pB0aVhAQiVkv/heQktW3kYpE+DQEBAQABAAAwR/FCqEKXpCpl+wqMenFtnRsL0EE9a/pd3+xF3xdSNQEaEUeErlBmGWxz3Bh+9BZh2mzayodzsri7xIZNDHRA3wIAAAAAAAAAILsR │ │ │ 2d1FIZ5+ADDYZtJ2e9CWlpAxsGd4Y2rZrjlyTUF1MEfxQqhCl6QqZfsKjHpxbZ0bC9BBPWv6Xd/sRd8XUjXoAwAAAAAAAICWmAAAAAAAAA== │ │ intent │ ╭─────────┬─────╮ │ @@ -140,20 +140,20 @@ $ sui keytool sign --data AAABACBRRpLwgknD6ZV3mc4pB0aVhAQiVkv/heQktW3kYpE+DQEBAQ │ rawIntentMsg │ AAAAAAABACBRRpLwgknD6ZV3mc4pB0aVhAQiVkv/heQktW3kYpE+DQEBAQABAAAwR/FCqEKXpCpl+wqMenFtnRsL0EE9a/pd3+xF3xdSNQEaEUeErlBmGWxz3Bh+9BZh2mzayodzsri7xIZNDHRA3wIAAAAAAAAA │ │ │ ILsR2d1FIZ5+ADDYZtJ2e9CWlpAxsGd4Y2rZrjlyTUF1MEfxQqhCl6QqZfsKjHpxbZ0bC9BBPWv6Xd/sRd8XUjXoAwAAAAAAAICWmAAAAAAAAA== │ │ digest │ +B8Cbr16HfOVT50DoN/QF8HB0+oznm8KAYy8Rm+TQFo= │ -│ suiSignature │ ANucBEl9TIE0uv+w965DvOjlfDUll7NUtIpJgRhPc3D3y3EtZ4cvaNbm8i5pc7TNIov/qI0FhzIYf2J6PbqoNQ57F8HMWljWjbQiCLM8Lu1dhuhzvGjTNeffMP/MtMyOag== │ +│ iotaSignature │ ANucBEl9TIE0uv+w965DvOjlfDUll7NUtIpJgRhPc3D3y3EtZ4cvaNbm8i5pc7TNIov/qI0FhzIYf2J6PbqoNQ57F8HMWljWjbQiCLM8Lu1dhuhzvGjTNeffMP/MtMyOag== │ ╰──────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ``` ## Help -Each command has its own help section. For example `sui keytool sign –help` displays the following prompt: +Each command has its own help section. For example `iota keytool sign –help` displays the following prompt: ```shell -$ sui keytool sign --help -Create signature using the private key for for the given address in sui keystore. Any signature commits to a [struct IntentMessage] consisting of the Base64 encoded of the BCS serialized +$ iota keytool sign --help +Create signature using the private key for for the given address in iota keystore. Any signature commits to a [struct IntentMessage] consisting of the Base64 encoded of the BCS serialized transaction bytes itself and its intent. If intent is absent, default will be used -Usage: sui keytool sign [OPTIONS] --address
    --data +Usage: iota keytool sign [OPTIONS] --address
    --data Options: --address
    diff --git a/docs/content/references/cli/move.mdx b/docs/content/references/cli/move.mdx index 03ab9ebf834..7a04e9855b3 100644 --- a/docs/content/references/cli/move.mdx +++ b/docs/content/references/cli/move.mdx @@ -1,20 +1,20 @@ --- -title: Sui Move CLI -description: The Sui CLI move command provides commands for working with Move source code directly from a terminal or console. +title: Iota Move CLI +description: The Iota CLI move command provides commands for working with Move source code directly from a terminal or console. --- import CliCheckInstall from "../../_snippets/cli-check-install.mdx"; -The Sui CLI `move` command provides several commands for working with Move source code. A typical usage of `sui move` is to compile and test the Move code, or to generate a new Move project by using `sui move new project_name`, which creates the needed directories and the `Move.toml` file. +The Iota CLI `move` command provides several commands for working with Move source code. A typical usage of `iota move` is to compile and test the Move code, or to generate a new Move project by using `iota move new project_name`, which creates the needed directories and the `Move.toml` file. ## Commands -Typing `sui move --help` into your terminal or console displays the following information on available commands. +Typing `iota move --help` into your terminal or console displays the following information on available commands. ``` -Usage: sui move [OPTIONS] +Usage: iota move [OPTIONS] Commands: build @@ -50,10 +50,10 @@ The following examples demonstrate some of the most often used commands. ### Create a new Move project -To create a new Move project that automatically adds the necessary dependencies in a `Move.toml` file, run `sui move new []`. +To create a new Move project that automatically adds the necessary dependencies in a `Move.toml` file, run `iota move new []`. ```shell -$ sui move new smart_contract_test +$ iota move new smart_contract_test $ ls -l smart_contract_test Move.toml Sources @@ -65,7 +65,7 @@ name = "smart_contract_test" version = "0.0.1" [dependencies] -Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet" } +Iota = { git = "https://github.com/iotaledger/iota.git", subdir = "crates/iota-framework/packages/iota-framework", rev = "framework/testnet" } [addresses] smart_contract_test = "0x0" @@ -73,24 +73,24 @@ smart_contract_test = "0x0" ### Build a Move project -Use `sui move build` at the root of your Move project to build the package. +Use `iota move build` at the root of your Move project to build the package. ```shell -$ sui move build -UPDATING GIT DEPENDENCY https://github.com/MystenLabs/sui.git -INCLUDING DEPENDENCY Sui +$ iota move build +UPDATING GIT DEPENDENCY https://github.com/iotaledger/iota.git +INCLUDING DEPENDENCY Iota INCLUDING DEPENDENCY MoveStdlib BUILDING smart_contract_test ``` ### Run tests in a Move project -Use `sui move test` to run the tests in a Move package. +Use `iota move test` to run the tests in a Move package. ```shell -$ sui move test -UPDATING GIT DEPENDENCY https://github.com/MystenLabs/sui.git -INCLUDING DEPENDENCY Sui +$ iota move test +UPDATING GIT DEPENDENCY https://github.com/iotaledger/iota.git +INCLUDING DEPENDENCY Iota INCLUDING DEPENDENCY MoveStdlib BUILDING smart_contract_test Running Move unit tests @@ -107,13 +107,13 @@ This command currently only works on debug builds of the CLI. Please build the ::: -This example uses [`first_package`](https://github.com/MystenLabs/sui/tree/main/examples/move/first_package) Move package. +This example uses [`first_package`](https://github.com/iotaledger/iota/tree/main/examples/move/first_package) Move package. -To get the a summary of the test coverage, you must first run the `sui move test --coverage` command, and then the `sui move coverage summary --test` to get a summary of the test coverage in the example project. +To get the a summary of the test coverage, you must first run the `iota move test --coverage` command, and then the `iota move coverage summary --test` to get a summary of the test coverage in the example project. ```shell -$ sui move test --coverage -INCLUDING DEPENDENCY Sui +$ iota move test --coverage +INCLUDING DEPENDENCY Iota INCLUDING DEPENDENCY MoveStdlib BUILDING first_package Running Move unit tests @@ -121,7 +121,7 @@ Running Move unit tests [ PASS ] 0x0::example::test_sword_transactions Test result: OK. Total tests: 2; passed: 2; failed: 0 -$ sui move coverage summary --test +$ iota move coverage summary --test +-------------------------+ | Move Coverage Summary | +-------------------------+ @@ -134,11 +134,11 @@ Module 0000000000000000000000000000000000000000000000000000000000000000::example ## Help -Each command has its own help section. For example `sui move build –help` displays the following prompt: +Each command has its own help section. For example `iota move build –help` displays the following prompt: ```shell -$ sui move build --help -Usage: sui move build [OPTIONS] +$ iota move build --help +Usage: iota move build [OPTIONS] Options: -p, --path Path to a package which the command should be run with respect to diff --git a/docs/content/references/cli/ptb.mdx b/docs/content/references/cli/ptb.mdx index 7001c683984..5799093c463 100644 --- a/docs/content/references/cli/ptb.mdx +++ b/docs/content/references/cli/ptb.mdx @@ -1,6 +1,6 @@ --- -title: Sui Client PTB CLI -description: The Sui Client PTB CLI enables a user to construct a PTB and execute it from the command line or a file. +title: Iota Client PTB CLI +description: The Iota Client PTB CLI enables a user to construct a PTB and execute it from the command line or a file. --- import AddressPrefix from "../../_snippets/address-prefix.mdx"; @@ -9,17 +9,17 @@ The `client ptb` command allows you to specify the transactions for execution in ## Commands -The following list itemizes all the available args for the `sui client ptb` command. Use the `--help` for a long help version that includes some examples on how to use this command. +The following list itemizes all the available args for the `iota client ptb` command. Use the `--help` for a long help version that includes some examples on how to use this command. ``` Build, preview, and execute PTBs. Depending on your shell, you might have to use quotes around arrays or other passed values. Use --help to see examples for how to use the core functionality of this command. -Usage: sui client ptb [OPTIONS] +Usage: iota client ptb [OPTIONS] Options: --assign Assign a value to a variable name to use later in the PTB. --gas-coin The object ID of the gas coin to use. If not specified, it will try to use the first gas coin that it finds that has at least the requested gas-budget balance. - --gas-budget The gas budget for the transaction, in MIST. + --gas-budget The gas budget for the transaction, in MICROS. --make-move-vec <[VALUES]> Given n-values of the same type, it constructs a vector. For non objects or an empty vector, the type tag must be specified. --merge-coins <[COIN OBJECTS]> Merge N coins into the provided coin. --move-call Make a move call to a function. @@ -53,7 +53,7 @@ All the following examples were tested using a `bash` shell environment and your Here are some examples for `transfer-objects` and `gas-coin`: ```bash -sui client ptb transfer-objects [ARRAY_OF_OBJECTS] @0x02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331 --gas-coin @0x00002819ee07a66e53800495ccf5eeade8a02054a2e0827546c70e4b226f0495 +iota client ptb transfer-objects [ARRAY_OF_OBJECTS] @0x02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331 --gas-coin @0x00002819ee07a66e53800495ccf5eeade8a02054a2e0827546c70e4b226f0495 ``` ### Assign @@ -66,7 +66,7 @@ Use the `--assign` argument to bind values to variables. There are two ways you Let's look at the first case where you assign a value to a variable. You want to check if some variable's value is `none`. Call the `0x1::option::is_none` function from the Move standard library, and pass in the variable name: ```bash -sui client ptb \ +iota client ptb \ --assign my_variable none \ --move-call 0x1::option::is_none "" my_variable \ --gas-budget 50000000 @@ -74,14 +74,14 @@ sui client ptb \ :::tip -CLI PTB uses name resolution for common packages like `sui`, `std`, `deepbook`, so you can use them directly instead of their addresses: `0x2`, `0x1`, or `0xdee9`. +CLI PTB uses name resolution for common packages like `iota`, `std`, `deepbook`, so you can use them directly instead of their addresses: `0x2`, `0x1`, or `0xdee9`. ::: -In the second case, if a previous command outputs some result, you can bound it to a variable for later access. Let's see an example where you want a new coin with 1000 MIST, which you can achieve by using the `split-coins` command. After you do that, you want to transfer the new coin to another address. Without the `--assign` argument, you couldn't instruct the CLI to transfer that new coin object as you would not have a way to refer to it. +In the second case, if a previous command outputs some result, you can bound it to a variable for later access. Let's see an example where you want a new coin with 1000 MICROS, which you can achieve by using the `split-coins` command. After you do that, you want to transfer the new coin to another address. Without the `--assign` argument, you couldn't instruct the CLI to transfer that new coin object as you would not have a way to refer to it. ```bash -sui client ptb \ +iota client ptb \ --split-coins gas [1000] \ --assign coin \ --transfer-objects [coin] @recipient_address \ @@ -106,7 +106,7 @@ When a PTB is executed, the output contains all the relevant information (transa ### Move call -When needing to execute a Move call, use the `--move-call` transaction to call a specific function from a package. The CLI PTB supports name resolution for common packages like `sui`, `std`, `deepbook`, so you can use both `0x1::option::is_none` as well as `std::option::is_none` for passing the function name. +When needing to execute a Move call, use the `--move-call` transaction to call a specific function from a package. The CLI PTB supports name resolution for common packages like `iota`, `std`, `deepbook`, so you can use both `0x1::option::is_none` as well as `std::option::is_none` for passing the function name. ```bash --assign A none @@ -121,11 +121,11 @@ To call a specific function from a specific package, you can use the following c ### Publish -Publishing a package is one of the most important commands you need when working with Sui. While the CLI has a standalone `publish` command, PTBs also support publishing and upgrading packages. One main difference is that with `sui client ptb`, you must explicitly transfer the `UpgradeCap` object that is returned when creating a package, or destroy it with a call to [`make_immutable`](/concepts/sui-move-concepts/packages.mdx). Here is an example on how to publish a Move project on chain using the `sui client ptb` command. It makes a call to the `sui::tx_context::sender` to acquire the sender and assigns the result of that call to the `sender` variable, and then calls the publish command. The result of `publish` is bounded to `upgrade_cap` variable, and then this object is transferred to the sender. +Publishing a package is one of the most important commands you need when working with Iota. While the CLI has a standalone `publish` command, PTBs also support publishing and upgrading packages. One main difference is that with `iota client ptb`, you must explicitly transfer the `UpgradeCap` object that is returned when creating a package, or destroy it with a call to [`make_immutable`](/concepts/iota-move-concepts/packages.mdx). Here is an example on how to publish a Move project on chain using the `iota client ptb` command. It makes a call to the `iota::tx_context::sender` to acquire the sender and assigns the result of that call to the `sender` variable, and then calls the publish command. The result of `publish` is bounded to `upgrade_cap` variable, and then this object is transferred to the sender. ```bash -sui client ptb \ ---move-call sui::tx_context::sender \ +iota client ptb \ +--move-call iota::tx_context::sender \ --assign sender \ --publish "." \ --assign upgrade_cap \ @@ -135,19 +135,19 @@ sui client ptb \ ### Split, destroy, and merge coins -The following example showcases how to split a gas coin into multiple coins, make a move call to destroy one or more of the new coins, and finally merge the coins that were not destroyed back into the gas coin. It also showcases how to use framework name resolution (for example, `sui::coin` instead of `0x2::coin`) and how to refer to different values in an array using the `.` syntax. +The following example showcases how to split a gas coin into multiple coins, make a move call to destroy one or more of the new coins, and finally merge the coins that were not destroyed back into the gas coin. It also showcases how to use framework name resolution (for example, `iota::coin` instead of `0x2::coin`) and how to refer to different values in an array using the `.` syntax. ```bash # Split off from gas --split-coins gas [0,1,2,3] --assign coins ---move-call sui::coin::destroy_zero coins.0 +--move-call iota::coin::destroy_zero coins.0 # Can further split a split coin (and through variable bindings/result accesses) --split-coins coins.1 [0,0] --assign zcoins # Destroy both new coins ---move-call sui::coin::destroy_zero zcoins.0 ---move-call sui::coin::destroy_zero zcoins.1 +--move-call iota::coin::destroy_zero zcoins.0 +--move-call iota::coin::destroy_zero zcoins.1 # Can merge the split coins back --merge-coins gas [coins.1, coins.2, coins.3] --gas-budget 10000000 @@ -190,4 +190,4 @@ You cannot use the following words for variable names: ## JSON output -Append the `--json` flag to commands to format responses in JSON instead of the more human-friendly default Sui CLI output. This can be useful for extremely large datasets, for example, as those results can have a troublesome display on smaller screens. In these cases, the `--json` flag is useful. +Append the `--json` flag to commands to format responses in JSON instead of the more human-friendly default Iota CLI output. This can be useful for extremely large datasets, for example, as those results can have a troublesome display on smaller screens. In these cases, the `--json` flag is useful. diff --git a/docs/content/references/cli/validator.mdx b/docs/content/references/cli/validator.mdx index e21d9393f5c..d059e7ff277 100644 --- a/docs/content/references/cli/validator.mdx +++ b/docs/content/references/cli/validator.mdx @@ -1,15 +1,15 @@ --- -title: Sui Validator CLI +title: Iota Validator CLI --- -The Sui CLI `validator` command provides command-level access to validator features of the Sui network. +The Iota CLI `validator` command provides command-level access to validator features of the Iota network. ## Commands -Typing `sui validator --help` into your terminal or console displays the following information on available commands. +Typing `iota validator --help` into your terminal or console displays the following information on available commands. ```shell -Usage: sui validator [OPTIONS] [COMMAND] +Usage: iota validator [OPTIONS] [COMMAND] Commands: make-validator-info @@ -39,7 +39,7 @@ The following examples demonstrate some of the most often used commands. ### Update gas price for next epoch ```shell -$ sui validator update-gas-price 500 +$ iota validator update-gas-price 500 ``` @@ -58,8 +58,8 @@ A8z83EqjmgwRNFV6sme6A5tTTTQPjiLgiW76neyvhLud ├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ Sender: 0xf...3d9 │ │ Gas Owner: 0xf...3d9 │ -│ Gas Budget: 200000000 MIST │ -│ Gas Price: 1000 MIST │ +│ Gas Budget: 200000000 MICROS │ +│ Gas Price: 1000 MICROS │ │ Gas Payment: │ │ ┌── │ │ │ ID: 0x8...19e │ @@ -68,9 +68,9 @@ A8z83EqjmgwRNFV6sme6A5tTTTQPjiLgiW76neyvhLud │ └── │ │ │ │ Transaction Kind : Programmable │ -│ Inputs: [Object(SharedObject { object_id: 0x0...005, initial_shared_version: SequenceNumber(1), mutable: true }), Object(ImmOrOwnedObject { object_id: 0x4...dbe, version: SequenceNumber(1), digest: o#82z9UUX9iD2Mq9zvciD56kmmDYqjF3iwaFadi3Mk16eJ }), Pure(SuiPureValue { value_type: Some(U64), value: "500" })] │ +│ Inputs: [Object(SharedObject { object_id: 0x0...005, initial_shared_version: SequenceNumber(1), mutable: true }), Object(ImmOrOwnedObject { object_id: 0x4...dbe, version: SequenceNumber(1), digest: o#82z9UUX9iD2Mq9zvciD56kmmDYqjF3iwaFadi3Mk16eJ }), Pure(IotaPureValue { value_type: Some(U64), value: "500" })] │ │ Commands: [ │ -│ MoveCall(0x0...003::sui_system::request_set_gas_price(Input(0),Input(1),Input(2))), │ +│ MoveCall(0x0...003::iota_system::request_set_gas_price(Input(0),Input(1),Input(2))), │ │ ] │ │ │ │ │ @@ -145,13 +145,13 @@ A8z83EqjmgwRNFV6sme6A5tTTTQPjiLgiW76neyvhLud ### Set gas price for the next epoch ```shell -$ sui validator request_set_gas_price --args 0x5 \"42\" --gas-budget GAS-BUDGET-AMOUNT> +$ iota validator request_set_gas_price --args 0x5 \"42\" --gas-budget GAS-BUDGET-AMOUNT> ``` ### Display the validator information ```shell -$ sui validator display-metadata 0x3...de5 +$ iota validator display-metadata 0x3...de5 ``` @@ -162,8 +162,8 @@ $ sui validator display-metadata 0x3...de5 ```shell 0x3...de5's valdiator status: Active -SuiValidatorSummary { - sui_address: 0x3...de5, +IotaValidatorSummary { + iota_address: 0x3...de5, protocol_pubkey_bytes: [ 167, 93, @@ -384,10 +384,10 @@ SuiValidatorSummary { description: "The leading provider of staking infrastructure", image_url: "https://avatars.githubusercontent.com/u/38704373", project_url: "https://staked.us/", - net_address: "/dns/sui-mainnet.prod-eks-eu-west-1.staked.cloud/tcp/8080/http", - p2p_address: "/dns/sui-mainnet-udp.prod-eks-eu-west-1.staked.cloud/udp/8084", - primary_address: "/dns/sui-mainnet-udp.prod-eks-eu-west-1.staked.cloud/udp/8081", - worker_address: "/dns/sui-mainnet-udp.prod-eks-eu-west-1.staked.cloud/udp/8082", + net_address: "/dns/iota-mainnet.prod-eks-eu-west-1.staked.cloud/tcp/8080/http", + p2p_address: "/dns/iota-mainnet-udp.prod-eks-eu-west-1.staked.cloud/udp/8084", + primary_address: "/dns/iota-mainnet-udp.prod-eks-eu-west-1.staked.cloud/udp/8081", + worker_address: "/dns/iota-mainnet-udp.prod-eks-eu-west-1.staked.cloud/udp/8082", next_epoch_protocol_pubkey_bytes: None, next_epoch_proof_of_possession: None, next_epoch_network_pubkey_bytes: None, @@ -408,11 +408,11 @@ SuiValidatorSummary { 0, ), staking_pool_deactivation_epoch: None, - staking_pool_sui_balance: 42926894529549497, + staking_pool_iota_balance: 42926894529549497, rewards_pool: 1047712965206377, pool_token_balance: 41704322845739375, pending_stake: 0, - pending_total_sui_withdraw: 703345959058032, + pending_total_iota_withdraw: 703345959058032, pending_pool_token_withdraw: 683314441220777, exchange_rates_id: 0x5...65d, exchange_rates_size: 231, @@ -422,7 +422,7 @@ SuiValidatorSummary { ### Report a bad / non-performant validator ```shell -$ sui validator report-validator 0xf...3d9 +$ iota validator report-validator 0xf...3d9 ``` @@ -442,8 +442,8 @@ $ sui validator report-validator 0xf...3d9 ├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ Sender: 0xf...3d9 │ │ Gas Owner: 0xf...3d9 │ -│ Gas Budget: 200000000 MIST │ -│ Gas Price: 1000 MIST │ +│ Gas Budget: 200000000 MICROS │ +│ Gas Price: 1000 MICROS │ │ Gas Payment: │ │ ┌── │ │ │ ID: 0x8...19e │ @@ -452,9 +452,9 @@ $ sui validator report-validator 0xf...3d9 │ └── │ │ │ │ Transaction Kind : Programmable │ -│ Inputs: [Object(SharedObject { object_id: 0x0...005, initial_shared_version: SequenceNumber(1), mutable: true }), Object(ImmOrOwnedObject { object_id: 0x4...dbe, version: SequenceNumber(16), digest: o#4yDkecsKPe8SnacWdECmq1yVDt7MzvpXCxbRGs74PGaB }), Pure(SuiPureValue { value_type: Some(Address), value: "0xf...3d9" })] │ +│ Inputs: [Object(SharedObject { object_id: 0x0...005, initial_shared_version: SequenceNumber(1), mutable: true }), Object(ImmOrOwnedObject { object_id: 0x4...dbe, version: SequenceNumber(16), digest: o#4yDkecsKPe8SnacWdECmq1yVDt7MzvpXCxbRGs74PGaB }), Pure(IotaPureValue { value_type: Some(Address), value: "0xf...3d9" })] │ │ Commands: [ │ -│ MoveCall(0x0...003::sui_system::report_validator(Input(0),Input(1),Input(2))), │ +│ MoveCall(0x0...003::iota_system::report_validator(Input(0),Input(1),Input(2))), │ │ ] │ │ │ │ │ @@ -467,7 +467,7 @@ $ sui validator report-validator 0xf...3d9 │ Transaction Effects │ ├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ Digest: 8jVYrpuRBmdSLP37MsQGRqUqE3kE2m8XiSS4TG4aJwXf │ -│ Status: Failure { error: "MoveAbort(MoveLocation { module: ModuleId { address: 0000000000000000000000000000000000000000000000000000000000000003, name: Identifier(\"sui_system_state_inner\") }, function: 16, instruction: 12, function_name: Some(\"report_validator_impl\") }, 3) in command 0" } │ +│ Status: Failure { error: "MoveAbort(MoveLocation { module: ModuleId { address: 0000000000000000000000000000000000000000000000000000000000000003, name: Identifier(\"iota_system_state_inner\") }, function: 16, instruction: 12, function_name: Some(\"report_validator_impl\") }, 3) in command 0" } │ │ Executed Epoch: 8 │ │ │ │ Mutated Objects: │ @@ -523,16 +523,16 @@ $ sui validator report-validator 0xf...3d9 ## Help -Each command has its own help section. For example `sui validator report-validator --help` will display the following prompt: +Each command has its own help section. For example `iota validator report-validator --help` will display the following prompt: ```shell -$ sui validator report-validator --help +$ iota validator report-validator --help Report or un-report a validator -Usage: sui validator report-validator [OPTIONS] +Usage: iota validator report-validator [OPTIONS] Arguments: - The Sui Address of the validator is being reported or un-reported + The Iota Address of the validator is being reported or un-reported Options: --operation-cap-id Optional when sender is reporter validator itself and it holds the Cap object. Required when sender is not the reporter validator itself. diff --git a/docs/content/references/contribute/code-of-conduct.mdx b/docs/content/references/contribute/code-of-conduct.mdx index 2010acaa0fa..4ddc79bbb3c 100644 --- a/docs/content/references/contribute/code-of-conduct.mdx +++ b/docs/content/references/contribute/code-of-conduct.mdx @@ -1,12 +1,12 @@ --- -title: Sui Contributor Covenant Code of Conduct +title: Iota Contributor Covenant Code of Conduct sidebar_label: Code of Conduct slug: /code-of-conduct --- -Sui, as an open-source project, encourages free discussion rooted in respect. +Iota, as an open-source project, encourages free discussion rooted in respect. We endeavor to always be mindful of others' perspectives and ask all -fellow contributors to do the same. We welcome you to the Sui platform +fellow contributors to do the same. We welcome you to the Iota platform and ask you to help us grow it with relevant, on-point contributions. ## Our pledge {#our-pledge} diff --git a/docs/content/references/contribute/contribute-to-iota-repos.mdx b/docs/content/references/contribute/contribute-to-iota-repos.mdx new file mode 100644 index 00000000000..a1486b6fea2 --- /dev/null +++ b/docs/content/references/contribute/contribute-to-iota-repos.mdx @@ -0,0 +1,25 @@ +--- +title: Contribute to Iota Repositories +slug: /contribute-to-iota-repos +--- + +This page describes how to contribute to Iota, and provides additional information about participating in the Iota community. + +## Join the community {#join-the-community} + +To connect with the Iota community, join our [Discord](https://discord.gg/iota). + +## Open issues {#open-issues} + +To report an issue with Iota, [create an issue](https://github.com/iotaledger/iota/issues/new/choose) in the GitHub repo. Click **Get started** to open a template for the type of issue to create. + +## Fork Iota to contribute {#fork-iota-contribute} + +To contribute to Iota source code or documentation, you need only a GitHub account. You can commit updates and then submit a PR directly from the Github website, or create a fork of the repo to your local environment and use your favorite tools to make changes. Always submit PRs to the `main` branch. + +See [Iota Environment Setup](/guides/developer/getting-started/iota-environment.mdx) for instructions on forking the Iota repository, if necessary. + +## Contribute via the Iota Improvement Proposal (SIP) process {#SIP} + +The Iota Network is an open-source, decentralized, and permissionless protocol that welcomes community contributions. If you have an idea regarding a core protocol upgrade, the best way to make your voice heard is via submitting a Iota Improvement Proposal (SIP). For more information on SIPs, see [Contribute to Iota through SIPs](https://blog.iota.io/iota-improvement-proposals-sips/). + diff --git a/docs/content/references/contribute/contribute-to-sui-repos.mdx b/docs/content/references/contribute/contribute-to-sui-repos.mdx deleted file mode 100644 index 5663dfc8868..00000000000 --- a/docs/content/references/contribute/contribute-to-sui-repos.mdx +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: Contribute to Sui Repositories -slug: /contribute-to-sui-repos ---- - -This page describes how to contribute to Sui, and provides additional information about participating in the Sui community. - -## Join the community {#join-the-community} - -To connect with the Sui community, join our [Discord](https://discord.gg/sui). - -## Open issues {#open-issues} - -To report an issue with Sui, [create an issue](https://github.com/MystenLabs/sui/issues/new/choose) in the GitHub repo. Click **Get started** to open a template for the type of issue to create. - -## Fork Sui to contribute {#fork-sui-contribute} - -To contribute to Sui source code or documentation, you need only a GitHub account. You can commit updates and then submit a PR directly from the Github website, or create a fork of the repo to your local environment and use your favorite tools to make changes. Always submit PRs to the `main` branch. - -See [Sui Environment Setup](/guides/developer/getting-started/sui-environment.mdx) for instructions on forking the Sui repository, if necessary. - -## Contribute via the Sui Improvement Proposal (SIP) process {#SIP} - -The Sui Network is an open-source, decentralized, and permissionless protocol that welcomes community contributions. If you have an idea regarding a core protocol upgrade, the best way to make your voice heard is via submitting a Sui Improvement Proposal (SIP). For more information on SIPs, see [Contribute to Sui through SIPs](https://blog.sui.io/sui-improvement-proposals-sips/). - diff --git a/docs/content/references/contribute/contribution-process.mdx b/docs/content/references/contribute/contribution-process.mdx index c0b17c088ef..01718ff0bc7 100644 --- a/docs/content/references/contribute/contribution-process.mdx +++ b/docs/content/references/contribute/contribution-process.mdx @@ -1,16 +1,16 @@ --- -title: Contribute to Sui Documentation +title: Contribute to Iota Documentation sidebar_label: Docs Contribution -description: Help the Sui community through documentation contributions. Whether its to fix errors or add new content, the entire Sui community benefits from your contributions. +description: Help the Iota community through documentation contributions. Whether its to fix errors or add new content, the entire Iota community benefits from your contributions. --- -As open source software, Sui depends on community contributions. This page covers the process for contributing to Sui's documentation. +As open source software, Iota depends on community contributions. This page covers the process for contributing to Iota's documentation. -To make changes to the documentation, you can fork and clone the Sui repository to your local machine and make changes from your preferred IDE of choice, or by the web interface on GitHub. This guide covers both scenarios. +To make changes to the documentation, you can fork and clone the Iota repository to your local machine and make changes from your preferred IDE of choice, or by the web interface on GitHub. This guide covers both scenarios. ## Style guide compliance -All changes to the documentation must follow the [style guide](./style-guide.mdx), as well as the review process and information on the editors throughout the process. Do not be offended by the number of change requests your docs PR might receive. This is not a reflection on your writing abilities, but an effort to keep a consistent tone across the documentation set. Depending on reviewer and workload, some reviews are more thorough than others. After your PR merges, your content might be changed at a later date to align better with Sui writing standards. +All changes to the documentation must follow the [style guide](./style-guide.mdx), as well as the review process and information on the editors throughout the process. Do not be offended by the number of change requests your docs PR might receive. This is not a reflection on your writing abilities, but an effort to keep a consistent tone across the documentation set. Depending on reviewer and workload, some reviews are more thorough than others. After your PR merges, your content might be changed at a later date to align better with Iota writing standards. To create more engaging content, be sure to follow these rules in particular: @@ -20,7 +20,7 @@ To create more engaging content, be sure to follow these rules in particular: ## Set up local environment {#local-environment} -Cloning the documentation locally is recommended when you are creating larger, more significant changes to the docs. See [Sui Environment Setup](/guides/developer/getting-started/sui-environment.mdx) for instructions on forking the Sui repository, if necessary. The documentation is in the `docs/content` directory. +Cloning the documentation locally is recommended when you are creating larger, more significant changes to the docs. See [Iota Environment Setup](/guides/developer/getting-started/iota-environment.mdx) for instructions on forking the Iota repository, if necessary. The documentation is in the `docs/content` directory. 1. If you are using the recommended Visual Studio Code IDE, install [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) to ensure that your formatting is consistent. 1. After you make all your changes, stage all files with changes (`git add .` to add all modified files), create a local commit (`git commit -m “message”`), and then push all your changes to your forked repository (`git push`). @@ -40,4 +40,4 @@ To change an existing page, navigate to the file you want to edit, click on the ## Review process {#review-process} -When you are finished creating your changes in your own fork or using the web interface, submit a PR to the Sui repository. When you do so, you can view the deployment on Vercel and double-check that everything behaves the way you intend. For every unique commit in a PR, Vercel generates a new preview. A reviewer then takes responsibility for providing clear and actionable feedback to your PR. As the owner of the PR, it is your responsibility to modify your PR to address the feedback that has been provided to you by the reviewer. Keep in mind that you may receive feedback from multiple reviewers. After a reviewer has approved your PR, it is merged into `main` and your contributions are made public. +When you are finished creating your changes in your own fork or using the web interface, submit a PR to the Iota repository. When you do so, you can view the deployment on Vercel and double-check that everything behaves the way you intend. For every unique commit in a PR, Vercel generates a new preview. A reviewer then takes responsibility for providing clear and actionable feedback to your PR. As the owner of the PR, it is your responsibility to modify your PR to address the feedback that has been provided to you by the reviewer. Keep in mind that you may receive feedback from multiple reviewers. After a reviewer has approved your PR, it is merged into `main` and your contributions are made public. diff --git a/docs/content/references/contribute/localize-iota-docs.mdx b/docs/content/references/contribute/localize-iota-docs.mdx new file mode 100644 index 00000000000..54d63743f60 --- /dev/null +++ b/docs/content/references/contribute/localize-iota-docs.mdx @@ -0,0 +1,6 @@ +--- +title: Localize Iota Documentation +slug: /localize-iota-docs +--- + +The Iota documentation can be localized (translated) into any language of your choosing. The localization platform utilized is Crowdin. For more information regarding the localization process please see [here](https://support.crowdin.com/crowdin-intro/). diff --git a/docs/content/references/contribute/localize-sui-docs.mdx b/docs/content/references/contribute/localize-sui-docs.mdx deleted file mode 100644 index b93137839a6..00000000000 --- a/docs/content/references/contribute/localize-sui-docs.mdx +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Localize Sui Documentation -slug: /localize-sui-docs ---- - -The Sui documentation can be localized (translated) into any language of your choosing. The localization platform utilized is Crowdin. For more information regarding the localization process please see [here](https://support.crowdin.com/crowdin-intro/). diff --git a/docs/content/references/contribute/style-guide.mdx b/docs/content/references/contribute/style-guide.mdx index db8bc01e53f..7ebede5f1aa 100644 --- a/docs/content/references/contribute/style-guide.mdx +++ b/docs/content/references/contribute/style-guide.mdx @@ -6,7 +6,7 @@ toc_max_heading_level: 2 # Style Guide -This document defines the styles, word and term usage, and content formatting for Sui documentation. Entries are in alphabetical order. A style guide is never finished. Expect continued iterations to add additional styles, additional information to existing styles, and infrequently a change to an existing style. +This document defines the styles, word and term usage, and content formatting for Iota documentation. Entries are in alphabetical order. A style guide is never finished. Expect continued iterations to add additional styles, additional information to existing styles, and infrequently a change to an existing style. ## Accessibility {#accessibility} @@ -37,7 +37,7 @@ Spell out a term or phrase on first use in a topic, followed by the acronym in p **Example** -> You can mint non-fungible tokens (NFTs) using your Sui Wallet. To view an NFT after you mint it, click the NFTs tab of your wallet. +> You can mint non-fungible tokens (NFTs) using your Iota Wallet. To view an NFT after you mint it, click the NFTs tab of your wallet. ## Alerts {#alerts} @@ -199,7 +199,7 @@ Initiate a codeblock in markdown with three backticks (\`\`\`). **Example** ``` -module sui::display { +module iota::display { /// Sets multiple fields at once public fun add*multiple( self: &mut Display, @@ -238,9 +238,9 @@ Use imperative verbs for tasks, procedures, and instructions. **Example** -- **Indicative –** Sui network explorers display transactions on the network. -- **Imperative –** Open a Sui network explorer to view transactions on the network. -- **Subjunctive –** We suggest that you view your transaction in a Sui network explorer after you complete a transfer. +- **Indicative –** Iota network explorers display transactions on the network. +- **Imperative –** Open a Iota network explorer to view transactions on the network. +- **Subjunctive –** We suggest that you view your transaction in a Iota network explorer after you complete a transfer. ### Person {#person} @@ -248,11 +248,11 @@ Use second person in most cases. **Example** -> You used to could view transaction history in Sui Explorer. +> You used to could view transaction history in Iota Explorer. **Rather than:** -> We used to could view transaction history in Sui Explorer. +> We used to could view transaction history in Iota Explorer. ### Present tense {#present-tense} @@ -292,7 +292,7 @@ Do use serial commas. **Example** -> You must install Cargo, Rust, Docker, and the Sui CLI to create a Sui node. +> You must install Cargo, Rust, Docker, and the Iota CLI to create a Iota node. ## Headings and titles {#headings-titles} @@ -306,7 +306,7 @@ Use enough words in headings and titles to make it easy to know which link to cl Users search for information to complete a specific task, so help them identify the topic that helps them by using descriptive titles. For example, _Get Started_. Get started with what? If there are multiple products or programs available it could be anything. -_Get Started with Sui_ is better, but users want to get started with a specific task or user journey with Sui. Instead of _Get Started with Sui_, describe the specific task or journey, such as _Create a Sui Full Node_ or _Sui Validator Guide_. Use Get Started as a heading on the Documentation landing page to categorize tasks for new users. +_Get Started with Iota_ is better, but users want to get started with a specific task or user journey with Iota. Instead of _Get Started with Iota_, describe the specific task or journey, such as _Create a Iota Full Node_ or _Iota Validator Guide_. Use Get Started as a heading on the Documentation landing page to categorize tasks for new users. @@ -377,17 +377,17 @@ Use a list for a series of items or steps instead of writing them as a sentence. **Instead of:** -The Build section of the documentation includes topics about: Building with Sui, Using the CLI to Start a Network, Creating Smart Contracts, Sui Tutorial, and Sui Examples. +The Build section of the documentation includes topics about: Building with Iota, Using the CLI to Start a Network, Creating Smart Contracts, Iota Tutorial, and Iota Examples. **Use:** The Build section of the documentation includes the following topics: -- Building with Sui +- Building with Iota - Using the CLI to Start a Network - Creating Smart Contracts -- Sui Tutorial -- Sui Examples +- Iota Tutorial +- Iota Examples ### Numbered or ordered lists {#numbered-ordered-lists} @@ -401,7 +401,7 @@ Use a numbered list when: 1. Create a fork of the repo. 1. Clone your fork of the repo. -1. Install Sui. +1. Install Iota. @@ -410,7 +410,7 @@ Use a numbered list when: 1. Create a fork of the repo. 1. Clone your fork of the repo. -1. Install Sui. +1. Install Iota. ``` @@ -424,7 +424,7 @@ Use bulleted lists to list more than two pieces of related information, such as -Sui Explorer used to support the following browsers: +Iota Explorer used to support the following browsers: - Firefox version X or later - Chrome version X or later @@ -435,7 +435,7 @@ Sui Explorer used to support the following browsers: ``` -Sui Explorer used to support the following browsers: +Iota Explorer used to support the following browsers: - Firefox version X or later - Chrome version X or later @@ -556,7 +556,7 @@ Measurements should be written as numerals. ## Links {#links} -Always use relative links when linking to topics on docs.sui.io. +Always use relative links when linking to topics on docs.iota.io. Include the `.mdx` extension when creating internal links so that they also work from the source file in GitHub. @@ -565,13 +565,13 @@ Use the topic title of the target topic as the link text for the link in a list -> To learn more, see [Examples of Sui Smart Contracts](/guides/developer/app-examples.mdx). +> To learn more, see [Examples of Iota Smart Contracts](/guides/developer/app-examples.mdx). ```markdown -To learn more, see [Examples of Sui Smart Contracts](/guides/developer/app-examples.mdx). +To learn more, see [Examples of Iota Smart Contracts](/guides/developer/app-examples.mdx). ``` @@ -583,14 +583,14 @@ Use keywords from the target topic title when using links inline. -> Before you install Sui, make sure to install the [prerequisites](/guides/developer/getting-started/sui-install.mdx#prerequisites). +> Before you install Iota, make sure to install the [prerequisites](/guides/developer/getting-started/iota-install.mdx#prerequisites). ``` -Before you install Sui, make sure to install the [prerequisites](/guides/developer/getting-started/sui-install.mdx#prerequisites). +Before you install Iota, make sure to install the [prerequisites](/guides/developer/getting-started/iota-install.mdx#prerequisites). ``` @@ -604,22 +604,22 @@ Introduce a procedure with an infinitive verb. Format procedures using a numbere -To get the latest version of the Sui Wallet extension: +To get the latest version of the Iota Wallet extension: 1. Open Google Chrome. 1. Click **Extensions**, then click **Manage Extensions**. -1. Click **Details** for the Sui Wallet extension, then click **View in Chrome Web Store**. +1. Click **Details** for the Iota Wallet extension, then click **View in Chrome Web Store**. ``` -To get the latest version of the Sui Wallet extension: +To get the latest version of the Iota Wallet extension: 1. Open Google Chrome. 1. Click **Extensions**, then click **Manage Extensions**. -1. Click **Details** for the Sui Wallet extension, then click **View in Chrome Web Store**. +1. Click **Details** for the Iota Wallet extension, then click **View in Chrome Web Store**. ``` @@ -645,11 +645,11 @@ Proper nouns include: **Example** -> Sui Wallet +> Iota Wallet ## Product names {#product-names} -Product names are proper nouns. Capitalize all words of a product name. When referring to a product, use only the product name without “the”. When referring specifically to a Sui wallet, use Sui Wallet or Ethos Wallet and not just wallet. Users likely have multiple wallets, and we want to make it clear which wallet. Use wallet generically when referring to the concept of a wallet. +Product names are proper nouns. Capitalize all words of a product name. When referring to a product, use only the product name without “the”. When referring specifically to a Iota wallet, use Iota Wallet or Ethos Wallet and not just wallet. Users likely have multiple wallets, and we want to make it clear which wallet. Use wallet generically when referring to the concept of a wallet. **Example** @@ -657,19 +657,19 @@ Product names are proper nouns. Capitalize all words of a product name. When ref > Never share the recovery passphrase for your wallet with anyone. -> The Sui network supports the following wallets: +> The Iota network supports the following wallets: -- Sui Wallet +- Iota Wallet - Ethos Wallet - Coinbase Wallet **Example** -> Sui Wallet +> Iota Wallet **Example** -> You can mint an NFT directly from your Sui Wallet. +> You can mint an NFT directly from your Iota Wallet. ## Slashes {#slashes} @@ -764,7 +764,7 @@ Refer to pages in the documentation set as “topic”s. A “guide” can compr :::info -You can also just refer to a topic by title where it makes sense. See Installing Sui for more information. +You can also just refer to a topic by title where it makes sense. See Installing Iota for more information. ::: @@ -812,7 +812,7 @@ Indented example for the section. (Roboto Mono Light) - [SUSE Style Guide](https://documentation.suse.com/en-us/style/current/single-html/docu_styleguide/#sec-techwriting) - [Microsoft Style Guide](https://docs.microsoft.com/en-us/style-guide/welcome/) - [Google Developer Style Guide](https://developers.google.com/style) -- [CDN Language and Style Reference](http://cdn.static-economist.com/sites/default/files/pdfs/style_guide_12.pdf) +- [CDN Language and Style Reference](http://cdn.static-economicros.com/sites/default/files/pdfs/style_guide_12.pdf) ``` diff --git a/docs/content/references/event-query-and-subscription.mdx b/docs/content/references/event-query-and-subscription.mdx index 388eab33a8e..e00fc24f3cb 100644 --- a/docs/content/references/event-query-and-subscription.mdx +++ b/docs/content/references/event-query-and-subscription.mdx @@ -2,13 +2,13 @@ title: Event Query and Subscription --- -Sui Full nodes support publish/subscribe using JSON-RPC notifications via the WebSocket API. You can use this service with Sui client to filter and subscribe to a real-time event stream generated from Move or from the Sui network. +Iota Full nodes support publish/subscribe using JSON-RPC notifications via the WebSocket API. You can use this service with Iota client to filter and subscribe to a real-time event stream generated from Move or from the Iota network. -The client provides an [event filter](#event-filters) to limit the scope of events. Sui returns a notification with the event data and subscription ID for each event that matches the filter. +The client provides an [event filter](#event-filters) to limit the scope of events. Iota returns a notification with the event data and subscription ID for each event that matches the filter. # Event types -A Sui node emits the following types of events: +A Iota node emits the following types of events: - [Move event](#move-event) - [Publish event](#publish-event) @@ -19,7 +19,7 @@ A Sui node emits the following types of events: ## Move event {#move-event} -Move calls emit Move events. You can [define custom events](https://examples.sui.io/basics/events.html) in Move contracts. +Move calls emit Move events. You can [define custom events](https://examples.iota.io/basics/events.html) in Move contracts. ### Attributes {#attributes} @@ -193,9 +193,9 @@ None, Checkpoint events do not have any attributes. The event includes the Check } ``` -## Sui event query criteria {#sui-event-query-criteria} +## Iota event query criteria {#iota-event-query-criteria} -You can use the `EventQuery` criteria object to query a Sui node and retrieve events that match query criteria. +You can use the `EventQuery` criteria object to query a Iota node and retrieve events that match query criteria. | Query | Description | JSON-RPC Parameter Example | | ----------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | @@ -225,7 +225,7 @@ curl --location --request POST '127.0.0.1:9000' \ --data-raw '{ "jsonrpc": "2.0", "id": 1, - "method": "sui_getEvents", + "method": "iota_getEvents", "params": [ {"MoveModule":{"package":"", "module":"nft"}}, null, @@ -341,7 +341,7 @@ curl --location --request POST '127.0.0.1:9000' \ --data-raw '{ "jsonrpc": "2.0", "id": 1, - "method": "sui_getEvents", + "method": "iota_getEvents", "params": [ {"MoveEvent":"::nft::MintNFTEvent"}, null, @@ -419,7 +419,7 @@ curl --location --request POST '127.0.0.1:9000' \ --data-raw '{ "jsonrpc": "2.0", "id": 1, - "method": "sui_getEvents", + "method": "iota_getEvents", "params": [ "All", null, @@ -484,7 +484,7 @@ curl --location --request POST '127.0.0.1:9000' \ } ``` -## Subscribe to Sui events {#subscribe-events} +## Subscribe to Iota events {#subscribe-events} When you subscribe to the events described in the preceding sections, you can apply event filters to match the events you want to filter. @@ -506,7 +506,7 @@ You can use `EventFilter` to filter the events included in your subscription to ### Combining filters {#combining-filters} -Sui provides a few operators for combining filters: +Iota provides a few operators for combining filters: | Operator | Description | JSON-RPC Parameter Example | | -------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | @@ -520,13 +520,13 @@ Sui provides a few operators for combining filters: The following example demonstrates how to subscribe to Move events (`MoveEvent`) that a `::nft` package emits: ```bash ->> {"jsonrpc":"2.0", "id": 1, "method": "sui_subscribeEvent", "params": [{"All":[{"EventType":"MoveEvent"}, {"Package":""}, {"Module":"nft"}]}]} +>> {"jsonrpc":"2.0", "id": 1, "method": "iota_subscribeEvent", "params": [{"All":[{"EventType":"MoveEvent"}, {"Package":""}, {"Module":"nft"}]}]} << {"jsonrpc":"2.0","result":3121662727959200,"id":1} ``` To unsubscribe from this stream, use: ```bash ->> {"jsonrpc":"2.0", "id": 1, "method": "sui_unsubscribeEvent", "params": [3121662727959200]} +>> {"jsonrpc":"2.0", "id": 1, "method": "iota_unsubscribeEvent", "params": [3121662727959200]} << {"jsonrpc":"2.0","result":true,"id":1} ``` diff --git a/docs/content/references/exchange-integration-guide.mdx b/docs/content/references/exchange-integration-guide.mdx index b75f75dc96b..1735e1509ad 100644 --- a/docs/content/references/exchange-integration-guide.mdx +++ b/docs/content/references/exchange-integration-guide.mdx @@ -4,27 +4,27 @@ sidebar_label: Exchange Integration slug: /exchange-integration-guide --- -This topic describes how to integrate SUI, the token native to the Sui network, into a cryptocurrency exchange. The specific requirements and processes to implement an integration vary between exchanges. Rather than provide a step-by-step guide, this topic provides information about the primary tasks necessary to complete an integration. After the guidance about how to configure an integration, you can also find information and code samples related to staking on the Sui network. +This topic describes how to integrate IOTA, the token native to the Iota network, into a cryptocurrency exchange. The specific requirements and processes to implement an integration vary between exchanges. Rather than provide a step-by-step guide, this topic provides information about the primary tasks necessary to complete an integration. After the guidance about how to configure an integration, you can also find information and code samples related to staking on the Iota network. -## Requirements to configure a SUI integration {#requirements-sui-integration} +## Requirements to configure a IOTA integration {#requirements-iota-integration} -The requirements to configure a SUI integration include: +The requirements to configure a IOTA integration include: -- A Sui Full node. You can operate your own Sui Full node or use a Full node from a node operator. -- Suggested minimum hardware to run a Sui Full node: +- A Iota Full node. You can operate your own Iota Full node or use a Full node from a node operator. +- Suggested minimum hardware to run a Iota Full node: - CPUs: 8 physical cores / 16 vCPUs - RAM: 128 GB - Storage (SSD): 4 TB NVMe drive -For best results, run Sui Full nodes on Linux. Sui supports the Ubuntu and Debian distributions. You can also fun a Full node on macOS. +For best results, run Iota Full nodes on Linux. Iota supports the Ubuntu and Debian distributions. You can also fun a Full node on macOS. -## Configure a Sui Full node {#configure-full-node} +## Configure a Iota Full node {#configure-full-node} -You can set up and configure a Sui Full node using Docker or directly from source code in the Sui GitHub repository. +You can set up and configure a Iota Full node using Docker or directly from source code in the Iota GitHub repository. -### Install a Sui Full node using Docker {#full-node-docker} +### Install a Iota Full node using Docker {#full-node-docker} -Run the command in this section using the same branch of the repository for each. Replace `branch-name` with the branch you use. For example, use `devnet` to use the Sui Devnet network, or use `testnet` to use the Sui Testnet network. You must download all files to, and run all commands from, the same folder location. +Run the command in this section using the same branch of the repository for each. Replace `branch-name` with the branch you use. For example, use `devnet` to use the Iota Devnet network, or use `testnet` to use the Iota Testnet network. You must download all files to, and run all commands from, the same folder location. 1. Install [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/). Docker Desktop version installs Docker Compose. 1. Install dependencies for Linux: @@ -39,59 +39,59 @@ Run the command in this section using the same branch of the repository for each ``` 1. Download the docker-compose.yaml file: ```bash - wget https://github.com/MystenLabs/sui/blob/branch-name/docker/fullnode/docker-compose.yaml + wget https://github.com/iotaledger/iota/blob/branch-name/docker/fullnode/docker-compose.yaml ``` 1. Download the fullnode-template.yaml file: ```bash - wget https://github.com/MystenLabs/sui/raw/branch-name/crates/sui-config/data/fullnode-template.yaml + wget https://github.com/iotaledger/iota/raw/branch-name/crates/iota-config/data/fullnode-template.yaml ``` 1. Download the genesis.blob file: ```bash - wget https://github.com/MystenLabs/sui-genesis/raw/main/branch-name/genesis.blob + wget https://github.com/iotaledger/iota-genesis/raw/main/branch-name/genesis.blob ``` 1. Start the Full node. The -d switch starts it in the background (detached mode). ```bash docker-compose up -d ``` -## Install a Sui Full node from source {#install-full-node-source} +## Install a Iota Full node from source {#install-full-node-source} -Use the steps in this section to install and configure a Sui Full node directly from the Sui GitHub repository. These steps use [Cargo](https://doc.rust-lang.org/cargo/), the Rust package manager. +Use the steps in this section to install and configure a Iota Full node directly from the Iota GitHub repository. These steps use [Cargo](https://doc.rust-lang.org/cargo/), the Rust package manager. -1. Install prerequisites for Sui. -1. Clone the Sui repository: +1. Install prerequisites for Iota. +1. Clone the Iota repository: ```bash - git clone https://github.com/MystenLabs/sui.git -b branch-name + git clone https://github.com/iotaledger/iota.git -b branch-name ``` Replace `branch-name` with the branch to use. You should use the same branch for all commands. -1. Change directories to /sui: +1. Change directories to /iota: ```bash - cd sui + cd iota ``` 1. Copy the fullnode.yaml template: ```bash - cp crates/sui-config/data/fullnode-template.yaml fullnode.yaml + cp crates/iota-config/data/fullnode-template.yaml fullnode.yaml ``` 1. Download the genesis.blob file: ```bash - wget https://github.com/MystenLabs/sui-genesis/raw/main/branch-name/genesis.blob + wget https://github.com/iotaledger/iota-genesis/raw/main/branch-name/genesis.blob ``` Change branch-name to the same branch you used for previous commands. -1. Optionally, if you installed Sui to a path other than the default, modify the fullnode.yaml file to use the path you used. Update the path to the folder where you installed sui-fullnode for the `db-path` and `genesis-file-location` as appropriate: - `db-path: "/db-files/sui-fullnode-folder"` - `genesis-file-location: "/sui-fullnode-folder/genesis.blob"` -1. Start you Sui Full node: +1. Optionally, if you installed Iota to a path other than the default, modify the fullnode.yaml file to use the path you used. Update the path to the folder where you installed iota-fullnode for the `db-path` and `genesis-file-location` as appropriate: + `db-path: "/db-files/iota-fullnode-folder"` + `genesis-file-location: "/iota-fullnode-folder/genesis.blob"` +1. Start you Iota Full node: ```bash - cargo run --release --bin sui-node -- --config-path fullnode.yaml + cargo run --release --bin iota-node -- --config-path fullnode.yaml ``` -## Set up Sui addresses {#setup-sui-addresses} +## Set up Iota addresses {#setup-iota-addresses} -Sui addresses do not require on-chain initialization, you can spend from an address if it corresponds to your private key. You can derive a 32-byte Sui address by hashing the signature scheme flag byte concatenated with public key bytes `flag || pubkey` using the [BLAKE2b](https://www.blake2.net/) (256 bits output) hashing function. +Iota addresses do not require on-chain initialization, you can spend from an address if it corresponds to your private key. You can derive a 32-byte Iota address by hashing the signature scheme flag byte concatenated with public key bytes `flag || pubkey` using the [BLAKE2b](https://www.blake2.net/) (256 bits output) hashing function. -Currently, Sui address supports these signature schemes: pure Ed25519, Secp256k1, Secp256r1 and Multisig. The corresponding flag bytes are 0x00, 0x01, 0x02, 0x03 respectively. +Currently, Iota address supports these signature schemes: pure Ed25519, Secp256k1, Secp256r1 and Multisig. The corresponding flag bytes are 0x00, 0x01, 0x02, 0x03 respectively. -The following code sample demonstrates how to derive a Sui address in Rust: +The following code sample demonstrates how to derive a Iota address in Rust: ```rust let flag = 0x00; // 0x00 = ED25519, 0x01 = Secp256k1, 0x02 = Secp256r1, 0x03 = MultiSig @@ -100,23 +100,23 @@ let mut hasher = DefaultHash::default(); hasher.update([flag]); hasher.update(pk); let arr = hasher.finalize(); -let sui_address_string = hex::encode(arr); +let iota_address_string = hex::encode(arr); ``` ## Displaying addresses {#displaying-addresses} -Sui supports both addresses with and without a 0x prefix. Sui recommends that you always include the 0x prefix in API calls and when you display user addresses. +Iota supports both addresses with and without a 0x prefix. Iota recommends that you always include the 0x prefix in API calls and when you display user addresses. ## Track balance changes for an address {#track-balance-changes} -You can track balance changes by calling `sui_getBalance` at predefined intervals. This call returns the total balance for an address. The total includes any coin or token type, but this document focuses on SUI. You can track changes in the total balance for an address between subsequent `sui_getBalance` requests. +You can track balance changes by calling `iota_getBalance` at predefined intervals. This call returns the total balance for an address. The total includes any coin or token type, but this document focuses on IOTA. You can track changes in the total balance for an address between subsequent `iota_getBalance` requests. -The following bash example demonstrates how to use `sui_getBalance` for address 0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3. If you use a network other than Devnet, replace the value for `rpc` with the URL to the appropriate Full node. +The following bash example demonstrates how to use `iota_getBalance` for address 0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3. If you use a network other than Devnet, replace the value for `rpc` with the URL to the appropriate Full node. ```bash -rpc="https://fullnode.devnet.sui.io:443" +rpc="https://fullnode.devnet.iota.io:443" address="0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3" -data="{\"jsonrpc\": \"2.0\", \"method\": \"sui_getBalance\", \"id\": 1, \"params\": [\"$address\"]}" +data="{\"jsonrpc\": \"2.0\", \"method\": \"iota_getBalance\", \"id\": 1, \"params\": [\"$address\"]}" curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc ``` @@ -126,7 +126,7 @@ The response is a JSON object that includes the totalBalance for the address: { "jsonrpc": "2.0", "result": { - "coinType": "0x2::sui::SUI", + "coinType": "0x2::iota::IOTA", "coinObjectCount": 40, "totalBalance": 10000000000, "lockedBalance": {} @@ -135,21 +135,21 @@ The response is a JSON object that includes the totalBalance for the address: } ``` -The following example demonstrates using sui_getBalance in Rust: +The following example demonstrates using iota_getBalance in Rust: ```rust use std::str::FromStr; -use sui_sdk::types::base_types::SuiAddress; -use sui_sdk::{SuiClient, SuiClientBuilder}; +use iota_sdk::types::base_types::IotaAddress; +use iota_sdk::{IotaClient, IotaClientBuilder}; #[tokio::main] async fn main() -> Result<(), anyhow::Error> { - let sui = SuiClientBuilder::default().build( - "https://fullnode.devnet.sui.io:443", + let iota = IotaClientBuilder::default().build( + "https://fullnode.devnet.iota.io:443", ).await.unwrap(); - let address = SuiAddress::from_str("0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3")?; - let objects = sui.read_api().get_balance(address).await?; + let address = IotaAddress::from_str("0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3")?; + let objects = iota.read_api().get_balance(address).await?; println!("{:?}", objects); Ok(()) } @@ -157,13 +157,13 @@ async fn main() -> Result<(), anyhow::Error> { ## Use events to track balance changes for an address {#events-balance-changes} -You can also track the balance for an address by subscribing to all of the events emitted from it. Use a filter to include only the events related to SUI coins, such as when the address acquires a coin or pays for a gas fee. +You can also track the balance for an address by subscribing to all of the events emitted from it. Use a filter to include only the events related to IOTA coins, such as when the address acquires a coin or pays for a gas fee. The following example demonstrates how to filter events for an address using bash and cURL: ```bash -rpc="https://fullnode.devnet.sui.io:443" +rpc="https://fullnode.devnet.iota.io:443" address="0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3" -data="{\"jsonrpc\": \"2.0\", \"id\":1, \"method\": \"sui_getEvents\", \"params\": [{\"Recipient\": {\"AddressOwner\": \"0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3\"}}, null, null, true ]}" +data="{\"jsonrpc\": \"2.0\", \"id\":1, \"method\": \"iota_getEvents\", \"params\": [{\"Recipient\": {\"AddressOwner\": \"0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3\"}}, null, null, true ]}" curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc ``` @@ -188,78 +188,78 @@ nextCursor : {"txDigest": "GZQN9pE3Zr9ZfLzBK1BfVCXtbjx5xKMxPSEKaHDvL3E2","eventS ## Blocks vs Checkpoints {#blocks-vs-checkpoints} -Sui is a DAG-based blockchain and uses checkpoints for node synchronization and global transaction ordering. Checkpoints differ from blocks in the following ways: +Iota is a DAG-based blockchain and uses checkpoints for node synchronization and global transaction ordering. Checkpoints differ from blocks in the following ways: -- Sui creates checkpoints and adds finalized transactions. Note that transactions are finalized even before they are included in a checkpoint +- Iota creates checkpoints and adds finalized transactions. Note that transactions are finalized even before they are included in a checkpoint - Checkpoints do not fork, roll back, or reorganize. -- Sui creates one checkpoint about every 3 seconds. +- Iota creates one checkpoint about every 3 seconds. ### Checkpoint API operations {#checkpoint-api-operations} -Sui Checkpoint API operations include: +Iota Checkpoint API operations include: -- [sui_getCheckpoint](/sui-api-ref#sui_getCheckpoint) - Retrieves the specified checkpoint. -- [sui_getLatestCheckpointSequenceNumber](/sui-api-ref#sui_getLatestCheckpointSequenceNumber) - Retrieves the sequence number of the most recently executed checkpoint. -- sui_getCheckpoints - Retrieves a paginated list of checkpoints that occurred during the specified interval. Pending a future release. +- [iota_getCheckpoint](/iota-api-ref#iota_getCheckpoint) - Retrieves the specified checkpoint. +- [iota_getLatestCheckpointSequenceNumber](/iota-api-ref#iota_getLatestCheckpointSequenceNumber) - Retrieves the sequence number of the most recently executed checkpoint. +- iota_getCheckpoints - Retrieves a paginated list of checkpoints that occurred during the specified interval. Pending a future release. -## SUI Balance transfer {#sui-balance-transfer} +## IOTA Balance transfer {#iota-balance-transfer} -To transfer a specific amount of SUI between addresses, you need a SUI token object with that specific value. In Sui, everything is an object, including SUI tokens. The amount of SUI in each SUI token object varies. For example, an address could own 3 SUI tokens with different values: one of 0.1 SUI, a second of 1.0 SUI, and a third with 0.005 SUI. The total balance for the address equals the sum of the values of the individual SUI token objects, in this case, 1.105 SUI. +To transfer a specific amount of IOTA between addresses, you need a IOTA token object with that specific value. In Iota, everything is an object, including IOTA tokens. The amount of IOTA in each IOTA token object varies. For example, an address could own 3 IOTA tokens with different values: one of 0.1 IOTA, a second of 1.0 IOTA, and a third with 0.005 IOTA. The total balance for the address equals the sum of the values of the individual IOTA token objects, in this case, 1.105 IOTA. -You can merge and split SUI token objects to create token objects with specific values. To create a SUI token worth .6 SUI, split the token worth 1 SUI into two token objects worth .6 SUI and .4 SUI. +You can merge and split IOTA token objects to create token objects with specific values. To create a IOTA token worth .6 IOTA, split the token worth 1 IOTA into two token objects worth .6 IOTA and .4 IOTA. -To transfer a specific amount of SUI, you need a SUI token worth that specific amount. To get a SUI token with that specific value, you might need to split or merge existing SUI tokens. Sui supports several methods to accomplish this, including some that do not require you to manually split or merge coins. +To transfer a specific amount of IOTA, you need a IOTA token worth that specific amount. To get a IOTA token with that specific value, you might need to split or merge existing IOTA tokens. Iota supports several methods to accomplish this, including some that do not require you to manually split or merge coins. -## Sui API operations for transfers {#api-operations-transfers} +## Iota API operations for transfers {#api-operations-transfers} -Sui supports the following API operations related to transferring SUI between addresses: +Iota supports the following API operations related to transferring IOTA between addresses: -- [sui_transferObject](/sui-api-ref#sui_transferObject) - Because SUI tokens are objects, you can transfer SUI tokens just like any other object. This method requires a gas token, and is useful in niche cases only. +- [iota_transferObject](/iota-api-ref#iota_transferObject) + Because IOTA tokens are objects, you can transfer IOTA tokens just like any other object. This method requires a gas token, and is useful in niche cases only. -- [sui_payAllSui](/sui-api-ref#sui_payAllSui) - This method accepts an array of SUI token IDs. It merges all existing tokens into one, deducts the gas fee, then sends the merged token to the recipient address. +- [iota_payAllIota](/iota-api-ref#iota_payAllIota) + This method accepts an array of IOTA token IDs. It merges all existing tokens into one, deducts the gas fee, then sends the merged token to the recipient address. - The method is especially useful if you want to transfer all SUI from an address. To merge together all coins for an address, set the recipient as the same address. This is a native Sui method so is not considered a transaction in Sui. + The method is especially useful if you want to transfer all IOTA from an address. To merge together all coins for an address, set the recipient as the same address. This is a native Iota method so is not considered a transaction in Iota. -- [sui_paySui](/sui-api-ref#sui_paySui) - This operation accepts an array of SUI token IDs, an array of amounts, and an array of recipient addresses. +- [iota_payIota](/iota-api-ref#iota_payIota) + This operation accepts an array of IOTA token IDs, an array of amounts, and an array of recipient addresses. The amounts and recipients array map one to one. Even if you use only one recipient address, you must include it for each amount in the amount array. - The operation merges all of the tokens provided into one token object and settles the gas fees. It then splits the token according to the amounts in the amounts array and sends the first token to the first recipient, the second token to the second recipient, and so on. Any remaining SUI on the token stays in the source address. + The operation merges all of the tokens provided into one token object and settles the gas fees. It then splits the token according to the amounts in the amounts array and sends the first token to the first recipient, the second token to the second recipient, and so on. Any remaining IOTA on the token stays in the source address. - The benefits of this method include: no gas fees for merging or splitting tokens, and the abstracted token merge and split. The `sui_paySui` operation is a native function, so the merge and split operations are not considered Sui transactions. The gas fees for them match typical transactions on Sui.You can use this operation to split coins in your own address by setting the recipient as your own address. Note that the total value of the input coins must be greater than the total value of the amounts to send. + The benefits of this method include: no gas fees for merging or splitting tokens, and the abstracted token merge and split. The `iota_payIota` operation is a native function, so the merge and split operations are not considered Iota transactions. The gas fees for them match typical transactions on Iota.You can use this operation to split coins in your own address by setting the recipient as your own address. Note that the total value of the input coins must be greater than the total value of the amounts to send. -- [sui_pay](/sui-api-ref#sui_pay) - This method is similar to sui_paySui, but it accepts any kind of coin or token instead of only SUI. You must include a gas token, and all of the coins or tokens must be the same type. +- [iota_pay](/iota-api-ref#iota_pay) + This method is similar to iota_payIota, but it accepts any kind of coin or token instead of only IOTA. You must include a gas token, and all of the coins or tokens must be the same type. -- [sui_transferSui](/sui-api-ref#sui_transferSui) - This method accepts only one SUI token object and an amount to send to the recipient. It uses the same token for gas fees, so the amount to transfer must be strictly less than the value of the SUI token used. +- [iota_transferIota](/iota-api-ref#iota_transferIota) + This method accepts only one IOTA token object and an amount to send to the recipient. It uses the same token for gas fees, so the amount to transfer must be strictly less than the value of the IOTA token used. ## Signing Transactions {#signing-transactions} -Please refer to Sui Signatures for more details on signature validity requirements. +Please refer to Iota Signatures for more details on signature validity requirements. -## SUI Staking {#sui-staking} +## IOTA Staking {#iota-staking} -The Sui blockchain uses a Delegated Proof-of-Stake mechanism (DPoS). This allows SUI token holders to stake their SUI tokens to any validator of their choice. When someone stakes their SUI tokens, it means those tokens are locked for the entire epoch. Users can withdraw their stake at any time, but new staking requests become active only at the start of the next epoch. +The Iota blockchain uses a Delegated Proof-of-Stake mechanism (DPoS). This allows IOTA token holders to stake their IOTA tokens to any validator of their choice. When someone stakes their IOTA tokens, it means those tokens are locked for the entire epoch. Users can withdraw their stake at any time, but new staking requests become active only at the start of the next epoch. -SUI holders who stake their tokens to validators earn rewards for helping secure the Sui network. Sui determines rewards for staking based on stake rewards on the network, and distributes them at the end of each epoch. +IOTA holders who stake their tokens to validators earn rewards for helping secure the Iota network. Iota determines rewards for staking based on stake rewards on the network, and distributes them at the end of each epoch. -The total voting power in the Sui Network is always 10,000. The voting power of each individual validator is similar to basis points. For example, a voting power of 101 = 1.01%. Sui's quorum threshold (number of votes needed to confirm a transaction) is 6,667 (which is greater than 2/3). The voting power for a single validator is capped at 1,000 (10%) regardless of how much stake the validator has. +The total voting power in the Iota Network is always 10,000. The voting power of each individual validator is similar to basis points. For example, a voting power of 101 = 1.01%. Iota's quorum threshold (number of votes needed to confirm a transaction) is 6,667 (which is greater than 2/3). The voting power for a single validator is capped at 1,000 (10%) regardless of how much stake the validator has. ## Staking functions {#staking-functions} -Sui supports the following API operations related to staking. You can find the source code in the [sui_system](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-system/sources/sui_system.move) module. +Iota supports the following API operations related to staking. You can find the source code in the [iota_system](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/packages/iota-system/sources/iota_system.move) module. - `request_add_stake` Add user stake to a validator's staking pool. ```move public fun request_add_stake( - self: &mut SuiSystemState, - stake: Coin, + self: &mut IotaSystemState, + stake: Coin, validator_address: address, ctx: &mut TxContext, ) { @@ -278,8 +278,8 @@ public fun request_add_stake( ```move public fun request_add_stake_mul_coin( - self: &mut SuiSystemState, - delegate_stakes: vector>, + self: &mut IotaSystemState, + delegate_stakes: vector>, stake_amount: option::Option, validator_address: address, ctx: &mut TxContext, @@ -290,12 +290,12 @@ public fun request_add_stake_mul_coin( ``` - `request_add_stake_with_locked_coin` - Add user stake to a validator's staking pool using a locked SUI coin. + Add user stake to a validator's staking pool using a locked IOTA coin. ```move public fun request_add_stake_with_locked_coin( - self: &mut SuiSystemState, - stake: LockedCoin, + self: &mut IotaSystemState, + stake: LockedCoin, validator_address: address, ctx: &mut TxContext, ) { @@ -309,16 +309,16 @@ public fun request_add_stake_with_locked_coin( ```move public fun request_withdraw_stake( - self: &mut SuiSystemState, + self: &mut IotaSystemState, delegation: &mut Delegation, - staked_sui: &mut StakedSui, + staked_iota: &mut StakedIota, principal_withdraw_amount: u64, ctx: &mut TxContext, ) { validator_set::request_withdraw_stake( &mut self.validators, delegation, - staked_sui, + staked_iota, principal_withdraw_amount, ctx, ); diff --git a/docs/content/references/framework.mdx b/docs/content/references/framework.mdx index 5bc9c405fdc..3cd88b113ee 100644 --- a/docs/content/references/framework.mdx +++ b/docs/content/references/framework.mdx @@ -1,6 +1,6 @@ --- -title: Sui Framework -description: The Sui framework libraries include Move modules that provide the logic for Sui and its standards. A Rust process creates the documentation for the modules directly from comments in the code. +title: Iota Framework +description: The Iota framework libraries include Move modules that provide the logic for Iota and its standards. A Rust process creates the documentation for the modules directly from comments in the code. --- import DocCardList from '@theme/DocCardList'; @@ -15,19 +15,19 @@ The child pages to this topic describe the module members for the following libr ## Source code -You can find the source code for these Move modules in the [crates/sui-framework/packages](https://github.com/MystenLabs/sui/tree/main/crates/sui-framework/packages) directory in the `sui` repository on GitHub. As previously mentioned, the comments included in the code provide context for the logic defined. +You can find the source code for these Move modules in the [crates/iota-framework/packages](https://github.com/iotaledger/iota/tree/main/crates/iota-framework/packages) directory in the `iota` repository on GitHub. As previously mentioned, the comments included in the code provide context for the logic defined. ## Crate documentation -You can review the raw `cargo doc` output of the following documentation in the `sui` repository. The .md files are located in the `crates/sui-framework/docs` directory. Online, they are located at https://github.com/MystenLabs/sui/tree/main/crates/sui-framework/docs. +You can review the raw `cargo doc` output of the following documentation in the `iota` repository. The .md files are located in the `crates/iota-framework/docs` directory. Online, they are located at https://github.com/iotaledger/iota/tree/main/crates/iota-framework/docs. ## Build documentation locally -The most recent documentation is always available in the `main` branch of the `sui` repository. You shouldn't need to build the documentation locally, but if the need arises you can: +The most recent documentation is always available in the `main` branch of the `iota` repository. You shouldn't need to build the documentation locally, but if the need arises you can: -1. Open a terminal or console to the `sui/crates/sui-framework` directory. -1. Run `cargo doc --workspace --exclude "sui-benchmark" --no-deps`. -1. The docs are built to `crates/sui-framework/docs` into their respective subdirectories. +1. Open a terminal or console to the `iota/crates/iota-framework` directory. +1. Run `cargo doc --workspace --exclude "iota-benchmark" --no-deps`. +1. The docs are built to `crates/iota-framework/docs` into their respective subdirectories. :::info diff --git a/docs/content/references/iota-api.mdx b/docs/content/references/iota-api.mdx new file mode 100644 index 00000000000..b58f4256c45 --- /dev/null +++ b/docs/content/references/iota-api.mdx @@ -0,0 +1,49 @@ +--- +title: Iota RPC +--- + +:::info + +The Iota RPC is upgrading from JSON-RPC to GraphQL. See [GraphQL for Iota RPC](../concepts/graphql-rpc.mdx) for more information. + +::: + +_IotaJSON_ is a JSON-based format with restrictions that allow Iota to align JSON inputs more closely with Move call arguments. + +This table shows the restrictions placed on JSON types to make them IotaJSON compatible: + +| JSON | IotaJSON Restrictions | Move Type Mapping | +| ------- | -------------------------------------------- | ---------------------------------------------------------------------------------------- | +| Number | Must be unsigned integer | u8, u6, u32, u64 (encoded as String), u128 (encoded as String), u256 (encoded as String) | +| String | No restrictions | Vector``, Address, ObjectID, TypeTag, Identifier, Unsigned integer (256 bit max) | +| Boolean | No restrictions | Bool | +| Array | Must be homogeneous JSON and of IotaJSON type | Vector | +| Null | Not allowed | N/A | +| Object | Not allowed | N/A | + +## Type coercion reasoning {#type-coercion-reasoning} + +Due to the loosely typed nature of JSON/IotaJSON and the strongly typed nature of Move types, you sometimes need to overload IotaJSON types to represent multiple Move types. + +For example `IotaJSON::Number` can represent both _u8_ and _u32_. This means you have to coerce and sometimes convert types. + +Which type you coerce depends on the expected Move type. For example, if the Move function expects a u8, you must have received a `IotaJSON::Number` with a value less than 256. More importantly, you have no way to easily express Move addresses in JSON, so you encode them as hex strings prefixed by `0x`. + +Additionally, Move supports u128 and u256 but JSON doesn't. As a result Iota allows encoding numbers as strings. + +## Type coercion rules {#type-coercion-rules} + +| Move Type | IotaJSON Representations | Valid Examples | Invalid Examples | +| :-----------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| Bool | Bool | true, false | | +| u8 | Supports 3 formats: Unsigned number < 256. Decimal string with value < 256. One byte hex string prefixed with 0x. | 7 "70" "0x43" | -5: negative not allowed 3.9: float not allowed NaN: not allowed 300: U8 must be less than 256 " 9": Spaces not allowed in string "9A": Hex num must be prefixed with 0x "0x09CD": Too large for U8 | +| u16 | Three formats are supported Unsigned number < 65536. Decimal string with value < 65536. Two byte hex string prefixed with 0x. | 712 "570" "0x423" | -5: negative not allowed 3.9: float not allowed NaN: not allowed 98342300: U16 must be less than 65536 " 19": Spaces not allowed in string "9EA": Hex num must be prefixed with 0x "0x049C1D": Too large for U16 | +| u32 | Three formats are supported Unsigned number < 4294967296. Decimal string with value < 4294967296. One byte hex string prefixed with 0x. | 9823247 "987120" "0x4BADE93" | -5: negative not allowed 3.9: float not allowed NaN: not allowed 123456789123456: U32 must be less than 4294967296 " 9": Spaces not allowed in string "9A": Hex num must be prefixed with 0x "0x3FF1FF9FFDEFF": Too large for U32 | +| u64 | Supports two formats Decimal string with value < U64::MAX. Up to 8 byte hex string prefixed with 0x. | "747944370" "0x2B1A39A15E" | 123434: Although this is a valid U64 number, it must be encoded as a string | +| u128 | Two formats are supported Decimal string with value < U128::MAX. Up to 16 byte hex string prefixed with 0x. | "74794734937420002470" "0x2B1A39A1514E1D8A7CE" | 34: Although this is a valid U128 number, it must be encoded as a string | +| u256 | Two formats are supported Decimal string with value < U256::MAX. Up to 32 byte hex string prefixed with 0x. | "747947349374200024707479473493742000247" "0x2B1762FECADA39753FCAB2A1514E1D8A7CE" | 123434: Although this is a valid U256 number, it must be encoded as a string 0xbc33e6e4818f9f2ef77d020b35c24be738213e64d9e58839ee7b4222029610de | +| Address | 32 byte hex string prefixed with 0x | "0xbc33e6e4818f9f2ef77d020b35c24be738213e64d9e58839ee7b4222029610de" | 0xbc33: string too short bc33e6e4818f9f2ef77d020b35c24be738213e64d9e58839ee7b4222029610de: missing 0x prefix 0xG2B1A39A1514E1D8A7CE45919CFEB4FEE70B4E01: invalid hex char G | +| ObjectID | 32 byte hex string prefixed with 0x | "0x1b879f00b03357c95a908b7fb568712f5be862c5cb0a5894f62d06e9098de6dc" | Similar to above | +| Identifier | Typically used for module and function names. Encoded as one of the following: A String whose first character is a letter and the remaining characters are letters, digits or underscore. A String whose first character is an underscore, and there is at least one further letter, digit or underscore | "function", "\_function", "some_name", "\_\_\_\_some_name", "Another" | "\_": missing trailing underscore, digit or letter, "8name": cannot start with digit, ".function": cannot start with period, " ": cannot be empty space, "func name": cannot have spaces | +| Vector`` | Homogeneous vector of aforementioned types including nested vectors of primitive types (only "flat" vectors of ObjectIDs are allowed) | [1,2,3,4]: simple U8 vector [[3,600],[],[0,7,4]]: nested U32 vector ["0x2B1A39A1514E1D8A7CE45919CFEB4FEE", "0x2B1A39A1514E1D8A7CE45919CFEB4FEF"]: ObjectID vector | [1,2,3,false]: not homogeneous JSON [1,2,null,4]: invalid elements [1,2,"7"]: although Iota allows encoding numbers as strings meaning this array can evaluate to [1,2,7], the array is still ambiguous so it fails the homogeneity check. | +| Vector`` | For convenience, Iota allows: U8 vectors represented as UTF-8 (and ASCII) strings. | "√®ˆbo72 √∂†∆˚–œ∑π2ie": UTF-8 "abcdE738-2 \_=?": ASCII | | diff --git a/docs/content/references/sui-api/json-rpc-format.mdx b/docs/content/references/iota-api/json-rpc-format.mdx similarity index 84% rename from docs/content/references/sui-api/json-rpc-format.mdx rename to docs/content/references/iota-api/json-rpc-format.mdx index 643a3c2f869..d584c73e1c3 100644 --- a/docs/content/references/sui-api/json-rpc-format.mdx +++ b/docs/content/references/iota-api/json-rpc-format.mdx @@ -2,32 +2,32 @@ title: JSON-RPC API Format --- -_SuiJSON_ is a JSON-based format with restrictions that allow Sui to align JSON inputs more closely with Move call arguments. +_IotaJSON_ is a JSON-based format with restrictions that allow Iota to align JSON inputs more closely with Move call arguments. -This table shows the restrictions placed on JSON types to make them SuiJSON compatible: +This table shows the restrictions placed on JSON types to make them IotaJSON compatible: -| JSON | SuiJSON Restrictions | Move Type Mapping | +| JSON | IotaJSON Restrictions | Move Type Mapping | | ------- | -------------------------------------------- | ---------------------------------------------------------------------------------------- | | Number | Must be unsigned integer | u8, u6, u32, u64 (encoded as String), u128 (encoded as String), u256 (encoded as String) | | String | No restrictions | Vector``, Address, ObjectID, TypeTag, Identifier, Unsigned integer (256 bit max) | | Boolean | No restrictions | Bool | -| Array | Must be homogeneous JSON and of SuiJSON type | Vector | +| Array | Must be homogeneous JSON and of IotaJSON type | Vector | | Null | Not allowed | N/A | | Object | Not allowed | N/A | ## Type coercion reasoning {#type-coercion-reasoning} -Due to the loosely typed nature of JSON/SuiJSON and the strongly typed nature of Move types, you sometimes need to overload SuiJSON types to represent multiple Move types. +Due to the loosely typed nature of JSON/IotaJSON and the strongly typed nature of Move types, you sometimes need to overload IotaJSON types to represent multiple Move types. -For example `SuiJSON::Number` can represent both _u8_ and _u32_. This means you have to coerce and sometimes convert types. +For example `IotaJSON::Number` can represent both _u8_ and _u32_. This means you have to coerce and sometimes convert types. -Which type you coerce depends on the expected Move type. For example, if the Move function expects a u8, you must have received a `SuiJSON::Number` with a value less than 256. More importantly, you have no way to easily express Move addresses in JSON, so you encode them as hex strings prefixed by `0x`. +Which type you coerce depends on the expected Move type. For example, if the Move function expects a u8, you must have received a `IotaJSON::Number` with a value less than 256. More importantly, you have no way to easily express Move addresses in JSON, so you encode them as hex strings prefixed by `0x`. -Additionally, Move supports u128 and u256 but JSON doesn't. As a result Sui allows encoding numbers as strings. +Additionally, Move supports u128 and u256 but JSON doesn't. As a result Iota allows encoding numbers as strings. ## Type coercion rules {#type-coercion-rules} -| Move Type | SuiJSON Representations | Valid Examples | Invalid Examples | +| Move Type | IotaJSON Representations | Valid Examples | Invalid Examples | | :-----------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | Bool | Bool | true, false | | | u8 | Supports 3 formats: Unsigned number < 256. Decimal string with value < 256. One byte hex string prefixed with 0x. | 7 "70" "0x43" | -5: negative not allowed 3.9: float not allowed NaN: not allowed 300: U8 must be less than 256 " 9": Spaces not allowed in string "9A": Hex num must be prefixed with 0x "0x09CD": Too large for U8 | @@ -39,5 +39,5 @@ Additionally, Move supports u128 and u256 but JSON doesn't. As a result Sui allo | Address | 32 byte hex string prefixed with 0x | "0xbc33e6e4818f9f2ef77d020b35c24be738213e64d9e58839ee7b4222029610de" | 0xbc33: string too short bc33e6e4818f9f2ef77d020b35c24be738213e64d9e58839ee7b4222029610de: missing 0x prefix 0xG2B1A39A1514E1D8A7CE45919CFEB4FEE70B4E01: invalid hex char G | | ObjectID | 32 byte hex string prefixed with 0x | "0x1b879f00b03357c95a908b7fb568712f5be862c5cb0a5894f62d06e9098de6dc" | Similar to above | | Identifier | Typically used for module and function names. Encoded as one of the following: A String whose first character is a letter and the remaining characters are letters, digits or underscore. A String whose first character is an underscore, and there is at least one further letter, digit or underscore | "function", "\_function", "some_name", "\_\_\_\_some_name", "Another" | "\_": missing trailing underscore, digit or letter, "8name": cannot start with digit, ".function": cannot start with period, " ": cannot be empty space, "func name": cannot have spaces | -| Vector`` | Homogeneous vector of aforementioned types including nested vectors of primitive types (only "flat" vectors of ObjectIDs are allowed) | [1,2,3,4]: simple U8 vector [[3,600],[],[0,7,4]]: nested U32 vector ["0x2B1A39A1514E1D8A7CE45919CFEB4FEE", "0x2B1A39A1514E1D8A7CE45919CFEB4FEF"]: ObjectID vector | [1,2,3,false]: not homogeneous JSON [1,2,null,4]: invalid elements [1,2,"7"]: although Sui allows encoding numbers as strings meaning this array can evaluate to [1,2,7], the array is still ambiguous so it fails the homogeneity check. | -| Vector`` | For convenience, Sui allows: U8 vectors represented as UTF-8 (and ASCII) strings. | "√®ˆbo72 √∂†∆˚–œ∑π2ie": UTF-8 "abcdE738-2 \_=?": ASCII | | +| Vector`` | Homogeneous vector of aforementioned types including nested vectors of primitive types (only "flat" vectors of ObjectIDs are allowed) | [1,2,3,4]: simple U8 vector [[3,600],[],[0,7,4]]: nested U32 vector ["0x2B1A39A1514E1D8A7CE45919CFEB4FEE", "0x2B1A39A1514E1D8A7CE45919CFEB4FEF"]: ObjectID vector | [1,2,3,false]: not homogeneous JSON [1,2,null,4]: invalid elements [1,2,"7"]: although Iota allows encoding numbers as strings meaning this array can evaluate to [1,2,7], the array is still ambiguous so it fails the homogeneity check. | +| Vector`` | For convenience, Iota allows: U8 vectors represented as UTF-8 (and ASCII) strings. | "√®ˆbo72 √∂†∆˚–œ∑π2ie": UTF-8 "abcdE738-2 \_=?": ASCII | | diff --git a/docs/content/references/sui-api/rpc-best-practices.mdx b/docs/content/references/iota-api/rpc-best-practices.mdx similarity index 81% rename from docs/content/references/sui-api/rpc-best-practices.mdx rename to docs/content/references/iota-api/rpc-best-practices.mdx index e8a1e88a624..2a4f89ca6b0 100644 --- a/docs/content/references/sui-api/rpc-best-practices.mdx +++ b/docs/content/references/iota-api/rpc-best-practices.mdx @@ -4,7 +4,7 @@ title: RPC Best Practices import WarnMlRpcs from "../../_snippets/warn-ml-rpcs.mdx"; -This topic provides some best practices for configuring your RPC settings to ensure a reliable infrastructure for your projects and services built on Sui. +This topic provides some best practices for configuring your RPC settings to ensure a reliable infrastructure for your projects and services built on Iota. @@ -16,5 +16,5 @@ Consider the following when working with a provider: - **Onboarding call:** Always do an onboarding call with the provider you select to ensure they can provide service that meets your needs. If you have a high-traffic event, such as an NFT mint coming up, notify your RPC provider with the expected traffic increase at least 48 hours in advance. - **Redundancy:** It is important for high-traffic and time-sensitive apps, like NFT marketplaces and DeFi protocols, to ensure they don't rely on just one provider for RPCs. Many projects default to just using a single provider, but that's extremely risky and you should use other providers to provide redundancy. - **Traffic estimate:** You should have a good idea about the amount and type of traffic you expect, and you should communicate that information in advance with your RPC provider. During high-traffic events (such as NFT mints), request increased capacity from your RPC provider in advance. -Bot mitigation - As Sui matures, a lot of bots will emerge on the network. Sui dApp builders should think about bot mitigation at the infrastructure level. This depends heavily on use cases. For NFT minting, bots are undesirable. However, for certain DeFi use cases, bots are necessary. Think about the implications and prepare your infrastructure accordingly. +Bot mitigation - As Iota matures, a lot of bots will emerge on the network. Iota dApp builders should think about bot mitigation at the infrastructure level. This depends heavily on use cases. For NFT minting, bots are undesirable. However, for certain DeFi use cases, bots are necessary. Think about the implications and prepare your infrastructure accordingly. - **Provisioning notice:** Make RPC provisioning requests at least one week in advance. This gives operators and providers advance notice so they can arrange for the configure hardware/servers as necessary. If there’s a sudden, unexpected demand, please reach out to us so we can help set you up with providers that have capacity for urgent situations. diff --git a/docs/content/references/iota-compared.mdx b/docs/content/references/iota-compared.mdx new file mode 100644 index 00000000000..0058e3240ad --- /dev/null +++ b/docs/content/references/iota-compared.mdx @@ -0,0 +1,131 @@ +--- +title: Comparison +slug: /iota-compared +--- + +This page summarizes how Iota compares with existing blockchains and is intended for potential adopters of Iota to decide whether it fits their use cases. See How Iota Works for an introduction to the Iota architecture. + +Here are Iota's key features: + +- [Causal order vs. total order](#causal-order-vs-total-order) enables massively parallel execution +- Iota's variant of Move and its object-centric data model make composable objects/NFTs possible +- The blockchain-oriented [Move programming language](https://github.com/MystenLabs/awesome-move) eases the developer experience + +## Traditional blockchains {#traditional-blockchains} + +Traditional blockchain validators collectively build a shared accumulator: a cryptographically binding representation of the state of the blockchain, a chain to which they add increments over time, called blocks. In blockchains that offer deterministic finality, every time validators want to make an incremental addition to the blockchain, i.e., a block proposal, they sequence the proposal. This protocol lets them form an agreement over the current state of the chain, whether the proposed increment is valid, and what the state of the chain will be after the new addition. + +This method of maintaining common state over time has known practical success over the last 14 years or so, using a wealth of theory from the last 50 years of research in the field of Byzantine Fault Tolerant distributed systems. + +Yet it is inherently sequential: increments to the chain are added one at a time, like pearls on a string. In practice, this approach pauses the influx of transactions (often stored in a "mempool"), while the current block is under consideration. + +## Iota's approach to validating new transactions {#validating} + +A large number transactions do not have complex interdependencies with each other, since they operate on disconnected parts of the state. Often financial users just want to send an asset to a recipient, and the only data required to gauge whether this simple transaction is admissible is a fresh view of the sender's address. Hence Iota takes the approach of only taking a lock - or "stopping the world" - for the relevant piece of data rather than the whole chain -- in this case, the address of the sender, which can only send one transaction at a time. + +Iota further expands this approach to more involved transactions that may explicitly depend on multiple elements under their sender's control, using an object model and leveraging Move's strong ownership model. By requiring that dependencies be explicit, Iota applies a "multi-lane" approach to transaction validation, making sure those independent transaction flows can progress without impediment from the others. + +This doesn't mean that Iota as a platform never orders transactions with respect to each other, or that it allows owners to affect only their owned microcosm of objects. Iota also processes transactions that have an effect on some shared state in a rigorous, consensus-ordered manner. They're just not the default use case. See the [State-of-the-art consensus](#state-of-the-art-consensus) section for details on the Narwhal and Bullshark consensus engine. + +## A collaborative approach to transaction submission {#tx-submission} + +Iota validates transactions individually, rather than batching them in the traditional blocks. The key advantage of this approach is low latency; each successful transaction quickly obtains a certificate of finality that proves to anyone that the transaction will persists its effects on the Iota network. + +But the process of submitting a transaction is a bit more involved. That little more work occurs on the network. (With bandwidth getting cheaper, this is less of a concern.) Whereas a usual blockchain can accept a bunch of transactions from the same author in a fire-and-forget mode, Iota transaction submission follows these steps: + +1. Sender broadcasts a transaction to all Iota validators. +1. Iota validators send individual votes on this transaction to the sender. +1. Each vote has a certain weight since each validator has weight based upon the rules of [Proof of Stake](https://en.wikipedia.org/wiki/Proof_of_work). +1. Sender collects a Byzantine-resistant-majority of these votes into a _certificate_ and broadcasts it to all Iota validators. +1. The validators execute the transaction and sign the results. When the client receives a Byzantine-resistant-majority of the results _finality_ is reached, ie., assurance the transaction will not be dropped (revoked). +1. Optionally, the sender assembles the votes to a certificate detailing the effects of the transaction. + +While those steps demand more of the sender, performing them efficiently can still yield a cryptographic proof of finality with minimum latency. Aside from crafting the original transaction itself, the session management for a transaction does not require access to any private keys and can be delegated to a third party. + +## A different approach to state {#state} + +Because Iota focuses on managing specific objects rather than a single aggregate of state, it also reports on them in a unique way: + +- Every object in Iota has a unique version number. +- Every new version is created from a transaction that may involve several dependencies, themselves versioned objects. + +As a consequence, a Iota Validator can exhibit a causal history of an object, showing its history since genesis. Iota explicitly makes the bet that in many cases, the ordering of that causal history with the causal history of another object is irrelevant; and in the few cases where this information is relevant, Iota makes this relationship explicit in the data. + +## Causal order vs. total order {#causal-order-vs-total-order} + +Unlike most existing blockchain systems (and as the reader may have guessed from the description of write requests above), Iota does not always impose a total order on the transactions submitted by clients, with shared objects being the exception. Instead, many transactions are _causally_ ordered--if a transaction `T1` produces output objects `O1` that are used as input objects in a transaction `T2`, a validator must execute `T1` before it executes `T2`. Note that `T2` need not use these objects directly for a causal relationship to exist--e.g., `T1` might produce output objects which are then used by `T3`, and `T2` might use `T3`'s output objects. However, transactions with no causal relationship can be processed by Iota validators in any order. + +## State-of-the-art consensus {#state-of-the-art-consensus} + +Narwhal and Bullshark represent the latest variant of decades of work on multi-proposer, high-throughput consensus algorithms that reaches throughputs more than 130,000 transactions per second on a WAN, with production cryptography, permanent storage, and a scaled-out primary-worker architecture. + +The [Narwhal mempool](https://github.com/MystenLabs/narwhal) offers a high-throughput data availability engine and a scaled architecture, splitting the disk I/O and networking requirements across several workers. And Bullshark is a zero-message overhead consensus algorithm, leveraging graph traversals. + +## Where Iota excels {#where-iota-excels} + +This section summarizes the main advantages of Iota with respect to traditional blockchains. + +### High performance {#high-performance} + +Iota's main selling point is its unprecedented performance. The following bullet points summarize the main performance benefits of Iota with respect to traditional blockchains: + +- Iota forgoes consensus for many transactions while other blockchains always totally order them. Causally ordering transactions allows Iota to massively parallelize the execution of many transactions; this reduces latency and allows validators to take advantage of all their CPU cores. +- Iota pushes the complexity at the edges: the client is involved in a number of protocol steps. This minimizes the interactions between validators and keeps their code simpler and more efficient. Iota always gives the possibility to offload most of the client's workload to a Iota Gateway service for better user experience. In contrast, traditional blockchains follow a fire-and-forget model where clients monitor the blockchain state to assess the success of their transaction submission. +- Iota operates at network speed without waiting for system timeouts between protocol steps. This significantly reduces latency when the network is good and not under attack. In contrast, the security of a number of traditional blockchains (including most proof-of-work based blockchains) need to wait for predefined timeouts before committing transactions. +- Iota can take advantage of more machines per validator to increase its performance. Traditional blockchains are often designed to run on a single machine per validator (or even on a single CPU). + +### Performance under faults {#performance-under-faults} + +Iota runs a leaderless protocol to process simple transactions (i.e. containing only owned objects). As a result, faulty validators do not impact performance in any significant way. For transactions involving shared objects, Iota employs a state-of-the-art consensus protocol requiring no [view-change sub-protocol](https://pmg.csail.mit.edu/papers/osdi99.pdf) and thus experiences only slight performance degradations. In contrast, most leader-based blockchains experiencing even a single validator's crash see their throughput fall and their latency increase (often by more than one order of magnitude). + +### Security assumptions {#security-assumptions} + +Contrary to many traditional blockchains, Iota does not make strong synchrony assumptions on the network. This means that Iota maintains its security properties under bad network conditions (even excessively bad), network splits/partitions, or even powerful DoS attacks targeted on the validators. Sustained network attacks on synchronous blockchains (i.e., most proof-of-work based blockchains) can lead to double-spend of resources and deadlocks. + +### Efficient local read operations {#local-read-operations} + +The reading process of Iota enormously differs from other blockchains. Users interested in only a handful of objects and their history perform authenticated reads at a low granularity and low latency. Iota creates a narrow family tree of objects starting from the genesis, allowing it to read only objects tied to the sender of the transaction. Users requiring a global view of the system (e.g., to audit the system) can take advantage of checkpoints to improve performance. + +In traditional blockchains, families are ordered with respect to each other to totally order transactions. This then requires querying a massive blob for the precise information needed. Disk I/O can become a performance bottleneck. + +### Easier developer experience {#easier-developer-experience} + +Iota provides these benefits to developers: + +- Move and object-centric data model (enables composable objects/NFTs) +- Asset-centric programming model +- Easier developer experience + +## Engineering trade-offs {#engineering-trade-offs} + +This section presents the main disadvantages of Iota with respect to traditional blockchains. + +### Design complexity {#design-complexity} + +While traditional blockchains require implementing only a single consensus protocol, Iota requires two protocols: (i) a protocol based on Byzantine Consistent Broadcast to handle simple transactions, and (ii) a consensus protocol to handle transactions with shared objects. This means the Iota team needs to maintain a much larger codebase. + +Transactions involving shared objects require a little overhead (adding two extra round trips - 200ms for well-connected clients using a Iota Gateway service) before submitting it to the consensus protocol. This overhead is required to securely compose the two protocols described above. Other blockchains can instead directly submit the transaction to the consensus protocol. Note the finality for shared object transactions is still in the 2-3 second range even with this overhead. + +Building an efficient synchronizer is harder in Iota than in traditional blockchains. The synchronizer sub-protocol allows validators to update each other by sharing data, and it allows slow validators to catch up. Building an efficient synchronizer for traditional blockchains is no easy task, but still simpler than in Iota. + +### Sequential writes in the simple case {#sequential-writes} + +Traditional blockchains totally order all client transactions with respect to each other. This design requires reaching consensus across validators, which is effective but slow. + +As mentioned in previous sections, Iota forgoes consensus for many transactions to reduce their latency. In this manner, Iota enables multi-lane processing and eliminates head-of-line blocking. All other transactions no longer need to wait for the completion of the first transaction's increment in a single lane. Iota provides a lane of the appropriate breadth for each transaction. Simple transactions require viewing only the sender address, which greatly improves the system's capacity. + +The downside of allowing head-of-line blocking on the sender for these simple transactions is that the sender can send only one transaction at a time. As a result, it is imperative the transactions finalize quickly. + +### Complex total queries {#complex-total-queries} + +Iota can make total queries more difficult than in traditional blockchains since it does not always impose total order of transactions. Total queries are fairly rare with respect to local reads (see above) but useful in some scenarios. For example, a new validator joins the network and needs to download the total state to disk, or an auditor wishes to audit the entire blockchain. + +Iota mitigates this with checkpoints. A checkpoint is established every time an increment is added to a blockchain resulting from a certified transaction. Checkpoints work much like a [write ahead log](https://en.wikipedia.org/wiki/Write-ahead_logging) that stores state prior to full execution of a program. The calls in that program represent a smart contract in a blockchain. A checkpoint contains not only the transactions but also commitments to the state of the blockchain before and after the transactions. + +Iota uses the state commitment that arrives upon epoch change. Iota requires a single answer from the multiple validators and leverages an accessory protocol to derive the hash representing the state of the blockchain. This protocol consumes little bandwidth and does not impede the ingestion of transactions. Validators produce checkpoints at every epoch change. Iota requires the validators to also produce checkpoints even more frequently. So users may use these checkpoints to audit the blockchain with some effort. + +## Conclusion {#conclusion} + +In summary, Iota offers many performance and usability gains at the cost of some complexity in less simple use cases. Direct sender transactions excel in Iota. And complex smart contracts may benefit from shared objects where more than one user can mutate those objects (following smart contract specific rules). In this case, Iota totally orders all transactions involving shared objects using a consensus protocol. + +Iota uses a novel peer-reviewed consensus protocol based on [Narwhal and Bullshark](https://github.com/MystenLabs/narwhal), which provides a DAG-based mempool and efficient Byzantine Fault Tolerant (BFT) consensus. This is state-of-the-art in terms of both performance and robustness. diff --git a/docs/content/references/iota-framework-reference.mdx b/docs/content/references/iota-framework-reference.mdx new file mode 100644 index 00000000000..e72c5206491 --- /dev/null +++ b/docs/content/references/iota-framework-reference.mdx @@ -0,0 +1,6 @@ +--- +title: Iota Framework Reference +slug: /iota-framework-reference +--- + +The Iota Framework includes the core on-chain libraries for Move developers. You can view the [Iota Framework Reference docs](https://github.com/iotaledger/iota/tree/main/crates/iota-framework/docs) in Markdown format in the Iota GitHub repo. diff --git a/docs/content/references/iota-glossary.mdx b/docs/content/references/iota-glossary.mdx new file mode 100644 index 00000000000..254bac94c86 --- /dev/null +++ b/docs/content/references/iota-glossary.mdx @@ -0,0 +1,101 @@ +--- +title: Glossary +slug: /iota-glossary +--- + +Find terms used in Iota defined below. + +### Causal history {#causal-history} + +Causal history is the relationship between an object in Iota and its direct predecessors and successors. This history is essential to the causal order Iota uses to process transactions. In contrast, other blockchains read the entire state of their world for each transaction, +introducing latency. + +### Causal order {#causal-order} + +[Causal order](https://www.scattered-thoughts.net/writing/causal-ordering/) is a representation of the relationship between transactions and the objects they produce, laid out as dependencies. Validators cannot execute a transaction dependent on objects created by a prior transaction that has not finished. Rather than total order, Iota uses causal order (a partial order). + +### Certificate {#certificate} + +A certificate is the mechanism proving a transaction was approved or certified. Validators vote on transactions, and aggregators collect a Byzantine-resistant-majority of these votes into a certificate and broadcasts it to all Iota validators, thereby ensuring finality. + +### Epoch {#epoch} + +Operation of the Iota network is temporally partitioned into non-overlapping, fixed-duration epochs. During a particular epoch, the set of validators participating in the network is fixed. + +### Equivocation {#equivocation} + +Equivocation in blockchains is the malicious action of dishonest actors giving conflicting information for the same message, such as inconsistent or duplicate voting. + +### Eventual consistency {#eventual-consistency} + +[Eventual consistency](https://en.wikipedia.org/wiki/Eventual_consistency) is the consensus model employed by Iota; if one honest validator +certifies the transaction, all of the other honest validators will too eventually. + +### Finality {#finality} + +[Finality](https://medium.com/mechanism-labs/finality-in-blockchain-consensus-d1f83c120a9a) is the assurance a transaction will not be revoked. This stage is considered closure for an exchange or other blockchain transaction. + +### Gas {#gas} + +[Gas](https://ethereum.org/en/developers/docs/gas/) refers to the computational effort required for executing operations on the Iota network. In Iota, gas is paid with the network's native currency IOTA. The cost of executing a transaction in IOTA units is referred to as the transaction fee. + +### Genesis {#genesis} + +Genesis is the initial act of creating accounts and gas objects for a Iota network. Iota provides a `genesis` command that allows users to create and inspect the genesis object setting up the network for operation. + +### Multi-writer objects {#multi-writer-objects} + +Multi-writer objects are objects that are owned by more than one address. Transactions affecting multi-writer objects require consensus in Iota. This contrasts with transactions affecting only single-writer objects, which require only a confirmation of the owner's address contents. + +### Object {#object} + +The basic unit of storage in Iota is object. In contrast to many other blockchains, where storage is centered around address and each address contains a key-value store, Iota's storage is centered around objects. Iota objects have one of the following primary states: + +- _Immutable_ - the object cannot be modified. +- _Mutable_ - the object can be changed. + +Further, mutable objects are divided into these categories: + +- _Owned_ - the object can be modified only by its owner. +- _Shared_ - the object can be modified by anyone. + +Immutable objects do not need this distinction because they have no owner. + +### Proof-of-stake {#proof-of-stake} + +[Proof-of-stake](https://en.wikipedia.org/wiki/Proof_of_stake) is a blockchain consensus mechanism where the voting weights of validators or validators is proportional to a bonded amount of the network's native currency (called their stake in the network). This mitigates [Sybil attacks](https://en.wikipedia.org/wiki/Sybil_attack) by forcing bad actors to gain a large stake in the blockchain first. + +### Single-writer objects {#single-writer-objects} + +Single-writer objects are owned by one address. In Iota, transactions affecting only single-writer objects owned by the same address may proceed with only a verification of the sender's address, greatly speeding transaction times. These are _simple transactions_. See Single-Writer Apps for example applications of this simple transaction model. + +### Smart contract {#smart-contract} + +A [smart contract](https://en.wikipedia.org/wiki/Smart_contract) is an agreement based upon the protocol for conducting transactions in a blockchain. In Iota, smart contracts are written in the [Move](https://github.com/MystenLabs/awesome-move) programming language. + +### Iota {#iota} + +Iota refers to the Iota blockchain, and the [Iota open source project](https://github.com/iotaledger/iota/) as a whole. + +### IOTA {#iota-1} + +IOTA is the native token to the Iota network. + +### Total order {#total-order} + +[Total order](https://en.wikipedia.org/wiki/Total_order) refers to the ordered presentation of the history of all transactions processed by a traditional blockchain up to a given time. This is maintained by many blockchain systems, as the only way to process transactions. In contrast, Iota uses a causal (partial) order wherever possible and safe. + +### Transaction {#transaction} + +A transaction in Iota is a change to the blockchain. This may be a _simple transaction_ affecting only single-writer, single-address objects, such as minting an NFT or transferring an NFT or another token. These transactions may bypass the consensus protocol in Iota. + +More _complex transactions_ affecting objects that are shared or owned by multiple addresses, such as asset management and other DeFi use cases, go through the [Narwhal and Bullshark](https://github.com/MystenLabs/narwhal) DAG-based mempool and efficient Byzantine Fault Tolerant (BFT) consensus. + +### Transfer {#transfer} + +A transfer is switching the owner address of a token to a new one via command in Iota. This is accomplished via the Iota CLI client command line interface. It is one of the more common of many commands available in the CLI client. + +### Validator {#validator} + +A validator in Iota plays a passive role analogous to the more active role of validators and minors in other blockchains. In Iota, validators do not continuously participate in the consensus protocol but are called into action only when receiving a transaction or +certificate. diff --git a/docs/content/references/iota-graphql.mdx b/docs/content/references/iota-graphql.mdx new file mode 100644 index 00000000000..be3a11b572a --- /dev/null +++ b/docs/content/references/iota-graphql.mdx @@ -0,0 +1,24 @@ +--- +title: GraphQL for Iota RPC +description: GraphQL is a public service for the Iota RPC that enables you to efficiently interact with the Iota network. +--- + +GraphQL for the Iota RPC is a public service that enables interacting with the Iota [network](https://iota.io/networkinfo). + +To get started with GraphQL for the Iota RPC, check out the [Getting Started](../guides/developer/getting-started/graphql-rpc.mdx) guide. If you'd like to learn more about the concepts used in the GraphQL service, check out the [GraphQL](../concepts/graphql-rpc.mdx) for Iota RPC concepts page. + +## Key Types + +All GraphQL API elements are accessible via the left sidebar, the following are good starting points to explore from. + +- "Queries" lists all top-level queries for reading the chain state, from reading details about addresses and objects to dryRunTransactionBlock, which has an execution-like interface but does not modify the chain. +- "Mutations" lists operations that can modify chain state, like executeTransactionBlock. +- Object is the type representing all on-chain objects (Move values and packages). +- Address corresponds to account addresses (derived from the public keys of signatures that sign transactions) and can be used to query the objects owned by these accounts and the transactions they have signed or been affected by. +- Owner represents any entity that can own a MoveObject to handle cases where it is not known whether the owner is an Object or an Address (for example, from the perspective of a Move object looking at its owner). + +## Related links + +- [GraphQL migration](../guides/developer/advanced/graphql-migration.mdx): Migrating to GraphQL guides you through migrating Iota RPC projects from JSON-RPC to GraphQL. +- [GraphQL quick-start](../guides/developer/getting-started/graphql-rpc.mdx): Querying Iota RPC with GraphQL gets you started using GraphQL to query the Iota RPC for on-chain data. +- [GraphQL concepts](../concepts/graphql-rpc.mdx): GraphQL for Iota RPC examines the elements of GraphQL that you should know to get the most from the service. diff --git a/docs/content/references/sui-move.mdx b/docs/content/references/iota-move.mdx similarity index 100% rename from docs/content/references/sui-move.mdx rename to docs/content/references/iota-move.mdx diff --git a/docs/content/references/iota-sdks.mdx b/docs/content/references/iota-sdks.mdx new file mode 100644 index 00000000000..5b9f0b87654 --- /dev/null +++ b/docs/content/references/iota-sdks.mdx @@ -0,0 +1,30 @@ +--- +title: Iota SDKs +--- + +Iota provides developer kits that act as wrappers for the Iota API. + +## Iota dApp Kit + +[Iota dApp Kit](https://sdk.mystenlabs.com/dapp-kit) is a web frontend SDK that interacts with the Iota API. It is available as an NPM package. + +## Iota Go SDK + +For those that like gophers, see [Go SDK](https://github.com/block-vision/iota-go-sdk). + +## Iota Python SDK + +For snake lovers, see [Python SDK](https://github.com/FrankC01/pyiota). + +## Iota Rust SDK + +See [Rust SDK](./rust-sdk.mdx) for SDK configuration and examples of using the Iota API with Rust. + +## Iota TypeScript SDK + +The Iota TypeScript SDK documentation is available in its own microsite: [Iota Typescript SDK](https://sdk.mystenlabs.com/typescript). + + +### Crate documentation + +[GitHub Pages](https://mystenlabs.github.io/iota/iota_sdk/index.html) hosts the generated documentation for Rust crates in the Iota repository. diff --git a/docs/content/references/move/move-toml.mdx b/docs/content/references/move/move-toml.mdx index 8e7354b68cf..65b82dbe938 100644 --- a/docs/content/references/move/move-toml.mdx +++ b/docs/content/references/move/move-toml.mdx @@ -3,55 +3,55 @@ title: Move.toml File description: Get the details for a Move package manifest. --- -Every Move package has a `Move.toml` file as a manifest for the package. The Sui Move compiler creates the `Move.toml` file for you when you create a new package, but you might need to update the file throughout the lifespan of your package. +Every Move package has a `Move.toml` file as a manifest for the package. The Iota Move compiler creates the `Move.toml` file for you when you create a new package, but you might need to update the file throughout the lifespan of your package. The manifest contains information divided into three sections: * `[package]`: Your package metadata, such as name and version. -* `[dependencies]`: List of packages that your package depends on. Initially, the Sui Framework is the only dependency, but you add third-party dependencies to this section as needed. +* `[dependencies]`: List of packages that your package depends on. Initially, the Iota Framework is the only dependency, but you add third-party dependencies to this section as needed. * `[addresses]`: A list of *named addresses*. You can use the names listed as convenient aliases for the given addresses in the source code. ## [package] section The `[package]` section contains the following information: -* `name`: The name of your package. Created by Sui Move compiler. -* `version`: The current version of your package. The Sui Move compiler creates the first value. -* `published-at`: The published address of the package. The Sui Move compiler does not automatically create this entry. +* `name`: The name of your package. Created by Iota Move compiler. +* `version`: The current version of your package. The Iota Move compiler creates the first value. +* `published-at`: The published address of the package. The Iota Move compiler does not automatically create this entry. ### The published-at property -Package dependencies in `Move.toml` must include a `published-at` field that specifies the published address of the dependency. For example, the Sui framework is published at address `0x2`, so its `Move.toml` file includes the `published-at` entry: +Package dependencies in `Move.toml` must include a `published-at` field that specifies the published address of the dependency. For example, the Iota framework is published at address `0x2`, so its `Move.toml` file includes the `published-at` entry: ```toml published-at = "0x2" ``` -If your package depends on another package, like the Sui framework, the network links your package against the `published-at` address specified by the on-chain dependency after you publish your package. When publishing, the compiler resolves all package (transitive) dependencies to link against. Consequently, you should only publish packages where all dependencies have a `published-at` address in their manifest. By default, the publish command fails if this is not the case. If necessary, you can use the `--with-unpublished-dependencies` flag with the publish command to bypass the requirement that all dependencies require a `published-at` address. When using `--with-unpublished-dependencies`, all unpublished dependencies are treated as if they are part of your package. +If your package depends on another package, like the Iota framework, the network links your package against the `published-at` address specified by the on-chain dependency after you publish your package. When publishing, the compiler resolves all package (transitive) dependencies to link against. Consequently, you should only publish packages where all dependencies have a `published-at` address in their manifest. By default, the publish command fails if this is not the case. If necessary, you can use the `--with-unpublished-dependencies` flag with the publish command to bypass the requirement that all dependencies require a `published-at` address. When using `--with-unpublished-dependencies`, all unpublished dependencies are treated as if they are part of your package. ## [dependencies] section -The Sui Move compiler creates the `[dependencies]` section for you with a single entry for the GitHub address of the Sui network. If you need to use a local version of the network, you can edit the address to point to the local version. For example, +The Iota Move compiler creates the `[dependencies]` section for you with a single entry for the GitHub address of the Iota network. If you need to use a local version of the network, you can edit the address to point to the local version. For example, ```toml -Sui = { local = "../crates/sui-framework" } +Iota = { local = "../crates/iota-framework" } ``` You place each additional dependency your package has on a new line directly below the previous one. ## [addresses] section -The Sui Move compiler creates the `[addresses]` section for you with an entry for your package and one for the Sui network. +The Iota Move compiler creates the `[addresses]` section for you with an entry for your package and one for the Iota network. ```toml [addresses] your_package_name = "0x0" -sui = "0000000000000000000000000000000000000000000000000000000000000002" +iota = "0000000000000000000000000000000000000000000000000000000000000002" ``` -The aliases defined in `[addresses]` enable you to reference the shortened name instead of the actual address. For example, when you import from Sui in a module, you can write: +The aliases defined in `[addresses]` enable you to reference the shortened name instead of the actual address. For example, when you import from Iota in a module, you can write: ```move -use sui::transfer +use iota::transfer ``` Without the alias, you have to write: diff --git a/docs/content/references/rust-sdk.mdx b/docs/content/references/rust-sdk.mdx index 3df818ee76f..e8cc6204fc5 100644 --- a/docs/content/references/rust-sdk.mdx +++ b/docs/content/references/rust-sdk.mdx @@ -1,10 +1,10 @@ --- -title: Sui Rust SDK -description: The Sui Rust SDK provides Rust wrappers around the Sui API. Using the SDK, you can interact with Sui networks using the Rust programming language. +title: Iota Rust SDK +description: The Iota Rust SDK provides Rust wrappers around the Iota API. Using the SDK, you can interact with Iota networks using the Rust programming language. --- -import README from "../../../crates/sui-sdk/README.md"; +import README from "../../../crates/iota-sdk/README.md"; -The Sui Rust SDK crate is in the [**crates\sui-sdk** directory](https://github.com/MystenLabs/sui/tree/main/crates/sui-sdk) of the Sui repository. +The Iota Rust SDK crate is in the [**crates\iota-sdk** directory](https://github.com/iotaledger/iota/tree/main/crates/iota-sdk) of the Iota repository. diff --git a/docs/content/references/sui-api.mdx b/docs/content/references/sui-api.mdx deleted file mode 100644 index d170660d07c..00000000000 --- a/docs/content/references/sui-api.mdx +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: Sui RPC ---- - -:::info - -The Sui RPC is upgrading from JSON-RPC to GraphQL. See [GraphQL for Sui RPC](../concepts/graphql-rpc.mdx) for more information. - -::: - -_SuiJSON_ is a JSON-based format with restrictions that allow Sui to align JSON inputs more closely with Move call arguments. - -This table shows the restrictions placed on JSON types to make them SuiJSON compatible: - -| JSON | SuiJSON Restrictions | Move Type Mapping | -| ------- | -------------------------------------------- | ---------------------------------------------------------------------------------------- | -| Number | Must be unsigned integer | u8, u6, u32, u64 (encoded as String), u128 (encoded as String), u256 (encoded as String) | -| String | No restrictions | Vector``, Address, ObjectID, TypeTag, Identifier, Unsigned integer (256 bit max) | -| Boolean | No restrictions | Bool | -| Array | Must be homogeneous JSON and of SuiJSON type | Vector | -| Null | Not allowed | N/A | -| Object | Not allowed | N/A | - -## Type coercion reasoning {#type-coercion-reasoning} - -Due to the loosely typed nature of JSON/SuiJSON and the strongly typed nature of Move types, you sometimes need to overload SuiJSON types to represent multiple Move types. - -For example `SuiJSON::Number` can represent both _u8_ and _u32_. This means you have to coerce and sometimes convert types. - -Which type you coerce depends on the expected Move type. For example, if the Move function expects a u8, you must have received a `SuiJSON::Number` with a value less than 256. More importantly, you have no way to easily express Move addresses in JSON, so you encode them as hex strings prefixed by `0x`. - -Additionally, Move supports u128 and u256 but JSON doesn't. As a result Sui allows encoding numbers as strings. - -## Type coercion rules {#type-coercion-rules} - -| Move Type | SuiJSON Representations | Valid Examples | Invalid Examples | -| :-----------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -| Bool | Bool | true, false | | -| u8 | Supports 3 formats: Unsigned number < 256. Decimal string with value < 256. One byte hex string prefixed with 0x. | 7 "70" "0x43" | -5: negative not allowed 3.9: float not allowed NaN: not allowed 300: U8 must be less than 256 " 9": Spaces not allowed in string "9A": Hex num must be prefixed with 0x "0x09CD": Too large for U8 | -| u16 | Three formats are supported Unsigned number < 65536. Decimal string with value < 65536. Two byte hex string prefixed with 0x. | 712 "570" "0x423" | -5: negative not allowed 3.9: float not allowed NaN: not allowed 98342300: U16 must be less than 65536 " 19": Spaces not allowed in string "9EA": Hex num must be prefixed with 0x "0x049C1D": Too large for U16 | -| u32 | Three formats are supported Unsigned number < 4294967296. Decimal string with value < 4294967296. One byte hex string prefixed with 0x. | 9823247 "987120" "0x4BADE93" | -5: negative not allowed 3.9: float not allowed NaN: not allowed 123456789123456: U32 must be less than 4294967296 " 9": Spaces not allowed in string "9A": Hex num must be prefixed with 0x "0x3FF1FF9FFDEFF": Too large for U32 | -| u64 | Supports two formats Decimal string with value < U64::MAX. Up to 8 byte hex string prefixed with 0x. | "747944370" "0x2B1A39A15E" | 123434: Although this is a valid U64 number, it must be encoded as a string | -| u128 | Two formats are supported Decimal string with value < U128::MAX. Up to 16 byte hex string prefixed with 0x. | "74794734937420002470" "0x2B1A39A1514E1D8A7CE" | 34: Although this is a valid U128 number, it must be encoded as a string | -| u256 | Two formats are supported Decimal string with value < U256::MAX. Up to 32 byte hex string prefixed with 0x. | "747947349374200024707479473493742000247" "0x2B1762FECADA39753FCAB2A1514E1D8A7CE" | 123434: Although this is a valid U256 number, it must be encoded as a string 0xbc33e6e4818f9f2ef77d020b35c24be738213e64d9e58839ee7b4222029610de | -| Address | 32 byte hex string prefixed with 0x | "0xbc33e6e4818f9f2ef77d020b35c24be738213e64d9e58839ee7b4222029610de" | 0xbc33: string too short bc33e6e4818f9f2ef77d020b35c24be738213e64d9e58839ee7b4222029610de: missing 0x prefix 0xG2B1A39A1514E1D8A7CE45919CFEB4FEE70B4E01: invalid hex char G | -| ObjectID | 32 byte hex string prefixed with 0x | "0x1b879f00b03357c95a908b7fb568712f5be862c5cb0a5894f62d06e9098de6dc" | Similar to above | -| Identifier | Typically used for module and function names. Encoded as one of the following: A String whose first character is a letter and the remaining characters are letters, digits or underscore. A String whose first character is an underscore, and there is at least one further letter, digit or underscore | "function", "\_function", "some_name", "\_\_\_\_some_name", "Another" | "\_": missing trailing underscore, digit or letter, "8name": cannot start with digit, ".function": cannot start with period, " ": cannot be empty space, "func name": cannot have spaces | -| Vector`` | Homogeneous vector of aforementioned types including nested vectors of primitive types (only "flat" vectors of ObjectIDs are allowed) | [1,2,3,4]: simple U8 vector [[3,600],[],[0,7,4]]: nested U32 vector ["0x2B1A39A1514E1D8A7CE45919CFEB4FEE", "0x2B1A39A1514E1D8A7CE45919CFEB4FEF"]: ObjectID vector | [1,2,3,false]: not homogeneous JSON [1,2,null,4]: invalid elements [1,2,"7"]: although Sui allows encoding numbers as strings meaning this array can evaluate to [1,2,7], the array is still ambiguous so it fails the homogeneity check. | -| Vector`` | For convenience, Sui allows: U8 vectors represented as UTF-8 (and ASCII) strings. | "√®ˆbo72 √∂†∆˚–œ∑π2ie": UTF-8 "abcdE738-2 \_=?": ASCII | | diff --git a/docs/content/references/sui-compared.mdx b/docs/content/references/sui-compared.mdx deleted file mode 100644 index a2530b8c284..00000000000 --- a/docs/content/references/sui-compared.mdx +++ /dev/null @@ -1,131 +0,0 @@ ---- -title: Comparison -slug: /sui-compared ---- - -This page summarizes how Sui compares with existing blockchains and is intended for potential adopters of Sui to decide whether it fits their use cases. See How Sui Works for an introduction to the Sui architecture. - -Here are Sui's key features: - -- [Causal order vs. total order](#causal-order-vs-total-order) enables massively parallel execution -- Sui's variant of Move and its object-centric data model make composable objects/NFTs possible -- The blockchain-oriented [Move programming language](https://github.com/MystenLabs/awesome-move) eases the developer experience - -## Traditional blockchains {#traditional-blockchains} - -Traditional blockchain validators collectively build a shared accumulator: a cryptographically binding representation of the state of the blockchain, a chain to which they add increments over time, called blocks. In blockchains that offer deterministic finality, every time validators want to make an incremental addition to the blockchain, i.e., a block proposal, they sequence the proposal. This protocol lets them form an agreement over the current state of the chain, whether the proposed increment is valid, and what the state of the chain will be after the new addition. - -This method of maintaining common state over time has known practical success over the last 14 years or so, using a wealth of theory from the last 50 years of research in the field of Byzantine Fault Tolerant distributed systems. - -Yet it is inherently sequential: increments to the chain are added one at a time, like pearls on a string. In practice, this approach pauses the influx of transactions (often stored in a "mempool"), while the current block is under consideration. - -## Sui's approach to validating new transactions {#validating} - -A large number transactions do not have complex interdependencies with each other, since they operate on disconnected parts of the state. Often financial users just want to send an asset to a recipient, and the only data required to gauge whether this simple transaction is admissible is a fresh view of the sender's address. Hence Sui takes the approach of only taking a lock - or "stopping the world" - for the relevant piece of data rather than the whole chain -- in this case, the address of the sender, which can only send one transaction at a time. - -Sui further expands this approach to more involved transactions that may explicitly depend on multiple elements under their sender's control, using an object model and leveraging Move's strong ownership model. By requiring that dependencies be explicit, Sui applies a "multi-lane" approach to transaction validation, making sure those independent transaction flows can progress without impediment from the others. - -This doesn't mean that Sui as a platform never orders transactions with respect to each other, or that it allows owners to affect only their owned microcosm of objects. Sui also processes transactions that have an effect on some shared state in a rigorous, consensus-ordered manner. They're just not the default use case. See the [State-of-the-art consensus](#state-of-the-art-consensus) section for details on the Narwhal and Bullshark consensus engine. - -## A collaborative approach to transaction submission {#tx-submission} - -Sui validates transactions individually, rather than batching them in the traditional blocks. The key advantage of this approach is low latency; each successful transaction quickly obtains a certificate of finality that proves to anyone that the transaction will persists its effects on the Sui network. - -But the process of submitting a transaction is a bit more involved. That little more work occurs on the network. (With bandwidth getting cheaper, this is less of a concern.) Whereas a usual blockchain can accept a bunch of transactions from the same author in a fire-and-forget mode, Sui transaction submission follows these steps: - -1. Sender broadcasts a transaction to all Sui validators. -1. Sui validators send individual votes on this transaction to the sender. -1. Each vote has a certain weight since each validator has weight based upon the rules of [Proof of Stake](https://en.wikipedia.org/wiki/Proof_of_work). -1. Sender collects a Byzantine-resistant-majority of these votes into a _certificate_ and broadcasts it to all Sui validators. -1. The validators execute the transaction and sign the results. When the client receives a Byzantine-resistant-majority of the results _finality_ is reached, ie., assurance the transaction will not be dropped (revoked). -1. Optionally, the sender assembles the votes to a certificate detailing the effects of the transaction. - -While those steps demand more of the sender, performing them efficiently can still yield a cryptographic proof of finality with minimum latency. Aside from crafting the original transaction itself, the session management for a transaction does not require access to any private keys and can be delegated to a third party. - -## A different approach to state {#state} - -Because Sui focuses on managing specific objects rather than a single aggregate of state, it also reports on them in a unique way: - -- Every object in Sui has a unique version number. -- Every new version is created from a transaction that may involve several dependencies, themselves versioned objects. - -As a consequence, a Sui Validator can exhibit a causal history of an object, showing its history since genesis. Sui explicitly makes the bet that in many cases, the ordering of that causal history with the causal history of another object is irrelevant; and in the few cases where this information is relevant, Sui makes this relationship explicit in the data. - -## Causal order vs. total order {#causal-order-vs-total-order} - -Unlike most existing blockchain systems (and as the reader may have guessed from the description of write requests above), Sui does not always impose a total order on the transactions submitted by clients, with shared objects being the exception. Instead, many transactions are _causally_ ordered--if a transaction `T1` produces output objects `O1` that are used as input objects in a transaction `T2`, a validator must execute `T1` before it executes `T2`. Note that `T2` need not use these objects directly for a causal relationship to exist--e.g., `T1` might produce output objects which are then used by `T3`, and `T2` might use `T3`'s output objects. However, transactions with no causal relationship can be processed by Sui validators in any order. - -## State-of-the-art consensus {#state-of-the-art-consensus} - -Narwhal and Bullshark represent the latest variant of decades of work on multi-proposer, high-throughput consensus algorithms that reaches throughputs more than 130,000 transactions per second on a WAN, with production cryptography, permanent storage, and a scaled-out primary-worker architecture. - -The [Narwhal mempool](https://github.com/MystenLabs/narwhal) offers a high-throughput data availability engine and a scaled architecture, splitting the disk I/O and networking requirements across several workers. And Bullshark is a zero-message overhead consensus algorithm, leveraging graph traversals. - -## Where Sui excels {#where-sui-excels} - -This section summarizes the main advantages of Sui with respect to traditional blockchains. - -### High performance {#high-performance} - -Sui's main selling point is its unprecedented performance. The following bullet points summarize the main performance benefits of Sui with respect to traditional blockchains: - -- Sui forgoes consensus for many transactions while other blockchains always totally order them. Causally ordering transactions allows Sui to massively parallelize the execution of many transactions; this reduces latency and allows validators to take advantage of all their CPU cores. -- Sui pushes the complexity at the edges: the client is involved in a number of protocol steps. This minimizes the interactions between validators and keeps their code simpler and more efficient. Sui always gives the possibility to offload most of the client's workload to a Sui Gateway service for better user experience. In contrast, traditional blockchains follow a fire-and-forget model where clients monitor the blockchain state to assess the success of their transaction submission. -- Sui operates at network speed without waiting for system timeouts between protocol steps. This significantly reduces latency when the network is good and not under attack. In contrast, the security of a number of traditional blockchains (including most proof-of-work based blockchains) need to wait for predefined timeouts before committing transactions. -- Sui can take advantage of more machines per validator to increase its performance. Traditional blockchains are often designed to run on a single machine per validator (or even on a single CPU). - -### Performance under faults {#performance-under-faults} - -Sui runs a leaderless protocol to process simple transactions (i.e. containing only owned objects). As a result, faulty validators do not impact performance in any significant way. For transactions involving shared objects, Sui employs a state-of-the-art consensus protocol requiring no [view-change sub-protocol](https://pmg.csail.mit.edu/papers/osdi99.pdf) and thus experiences only slight performance degradations. In contrast, most leader-based blockchains experiencing even a single validator's crash see their throughput fall and their latency increase (often by more than one order of magnitude). - -### Security assumptions {#security-assumptions} - -Contrary to many traditional blockchains, Sui does not make strong synchrony assumptions on the network. This means that Sui maintains its security properties under bad network conditions (even excessively bad), network splits/partitions, or even powerful DoS attacks targeted on the validators. Sustained network attacks on synchronous blockchains (i.e., most proof-of-work based blockchains) can lead to double-spend of resources and deadlocks. - -### Efficient local read operations {#local-read-operations} - -The reading process of Sui enormously differs from other blockchains. Users interested in only a handful of objects and their history perform authenticated reads at a low granularity and low latency. Sui creates a narrow family tree of objects starting from the genesis, allowing it to read only objects tied to the sender of the transaction. Users requiring a global view of the system (e.g., to audit the system) can take advantage of checkpoints to improve performance. - -In traditional blockchains, families are ordered with respect to each other to totally order transactions. This then requires querying a massive blob for the precise information needed. Disk I/O can become a performance bottleneck. - -### Easier developer experience {#easier-developer-experience} - -Sui provides these benefits to developers: - -- Move and object-centric data model (enables composable objects/NFTs) -- Asset-centric programming model -- Easier developer experience - -## Engineering trade-offs {#engineering-trade-offs} - -This section presents the main disadvantages of Sui with respect to traditional blockchains. - -### Design complexity {#design-complexity} - -While traditional blockchains require implementing only a single consensus protocol, Sui requires two protocols: (i) a protocol based on Byzantine Consistent Broadcast to handle simple transactions, and (ii) a consensus protocol to handle transactions with shared objects. This means the Sui team needs to maintain a much larger codebase. - -Transactions involving shared objects require a little overhead (adding two extra round trips - 200ms for well-connected clients using a Sui Gateway service) before submitting it to the consensus protocol. This overhead is required to securely compose the two protocols described above. Other blockchains can instead directly submit the transaction to the consensus protocol. Note the finality for shared object transactions is still in the 2-3 second range even with this overhead. - -Building an efficient synchronizer is harder in Sui than in traditional blockchains. The synchronizer sub-protocol allows validators to update each other by sharing data, and it allows slow validators to catch up. Building an efficient synchronizer for traditional blockchains is no easy task, but still simpler than in Sui. - -### Sequential writes in the simple case {#sequential-writes} - -Traditional blockchains totally order all client transactions with respect to each other. This design requires reaching consensus across validators, which is effective but slow. - -As mentioned in previous sections, Sui forgoes consensus for many transactions to reduce their latency. In this manner, Sui enables multi-lane processing and eliminates head-of-line blocking. All other transactions no longer need to wait for the completion of the first transaction's increment in a single lane. Sui provides a lane of the appropriate breadth for each transaction. Simple transactions require viewing only the sender address, which greatly improves the system's capacity. - -The downside of allowing head-of-line blocking on the sender for these simple transactions is that the sender can send only one transaction at a time. As a result, it is imperative the transactions finalize quickly. - -### Complex total queries {#complex-total-queries} - -Sui can make total queries more difficult than in traditional blockchains since it does not always impose total order of transactions. Total queries are fairly rare with respect to local reads (see above) but useful in some scenarios. For example, a new validator joins the network and needs to download the total state to disk, or an auditor wishes to audit the entire blockchain. - -Sui mitigates this with checkpoints. A checkpoint is established every time an increment is added to a blockchain resulting from a certified transaction. Checkpoints work much like a [write ahead log](https://en.wikipedia.org/wiki/Write-ahead_logging) that stores state prior to full execution of a program. The calls in that program represent a smart contract in a blockchain. A checkpoint contains not only the transactions but also commitments to the state of the blockchain before and after the transactions. - -Sui uses the state commitment that arrives upon epoch change. Sui requires a single answer from the multiple validators and leverages an accessory protocol to derive the hash representing the state of the blockchain. This protocol consumes little bandwidth and does not impede the ingestion of transactions. Validators produce checkpoints at every epoch change. Sui requires the validators to also produce checkpoints even more frequently. So users may use these checkpoints to audit the blockchain with some effort. - -## Conclusion {#conclusion} - -In summary, Sui offers many performance and usability gains at the cost of some complexity in less simple use cases. Direct sender transactions excel in Sui. And complex smart contracts may benefit from shared objects where more than one user can mutate those objects (following smart contract specific rules). In this case, Sui totally orders all transactions involving shared objects using a consensus protocol. - -Sui uses a novel peer-reviewed consensus protocol based on [Narwhal and Bullshark](https://github.com/MystenLabs/narwhal), which provides a DAG-based mempool and efficient Byzantine Fault Tolerant (BFT) consensus. This is state-of-the-art in terms of both performance and robustness. diff --git a/docs/content/references/sui-framework-reference.mdx b/docs/content/references/sui-framework-reference.mdx deleted file mode 100644 index 1452542f267..00000000000 --- a/docs/content/references/sui-framework-reference.mdx +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Sui Framework Reference -slug: /sui-framework-reference ---- - -The Sui Framework includes the core on-chain libraries for Move developers. You can view the [Sui Framework Reference docs](https://github.com/MystenLabs/sui/tree/main/crates/sui-framework/docs) in Markdown format in the Sui GitHub repo. diff --git a/docs/content/references/sui-glossary.mdx b/docs/content/references/sui-glossary.mdx deleted file mode 100644 index b2816ab15ac..00000000000 --- a/docs/content/references/sui-glossary.mdx +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: Glossary -slug: /sui-glossary ---- - -Find terms used in Sui defined below. - -### Causal history {#causal-history} - -Causal history is the relationship between an object in Sui and its direct predecessors and successors. This history is essential to the causal order Sui uses to process transactions. In contrast, other blockchains read the entire state of their world for each transaction, -introducing latency. - -### Causal order {#causal-order} - -[Causal order](https://www.scattered-thoughts.net/writing/causal-ordering/) is a representation of the relationship between transactions and the objects they produce, laid out as dependencies. Validators cannot execute a transaction dependent on objects created by a prior transaction that has not finished. Rather than total order, Sui uses causal order (a partial order). - -### Certificate {#certificate} - -A certificate is the mechanism proving a transaction was approved or certified. Validators vote on transactions, and aggregators collect a Byzantine-resistant-majority of these votes into a certificate and broadcasts it to all Sui validators, thereby ensuring finality. - -### Epoch {#epoch} - -Operation of the Sui network is temporally partitioned into non-overlapping, fixed-duration epochs. During a particular epoch, the set of validators participating in the network is fixed. - -### Equivocation {#equivocation} - -Equivocation in blockchains is the malicious action of dishonest actors giving conflicting information for the same message, such as inconsistent or duplicate voting. - -### Eventual consistency {#eventual-consistency} - -[Eventual consistency](https://en.wikipedia.org/wiki/Eventual_consistency) is the consensus model employed by Sui; if one honest validator -certifies the transaction, all of the other honest validators will too eventually. - -### Finality {#finality} - -[Finality](https://medium.com/mechanism-labs/finality-in-blockchain-consensus-d1f83c120a9a) is the assurance a transaction will not be revoked. This stage is considered closure for an exchange or other blockchain transaction. - -### Gas {#gas} - -[Gas](https://ethereum.org/en/developers/docs/gas/) refers to the computational effort required for executing operations on the Sui network. In Sui, gas is paid with the network's native currency SUI. The cost of executing a transaction in SUI units is referred to as the transaction fee. - -### Genesis {#genesis} - -Genesis is the initial act of creating accounts and gas objects for a Sui network. Sui provides a `genesis` command that allows users to create and inspect the genesis object setting up the network for operation. - -### Multi-writer objects {#multi-writer-objects} - -Multi-writer objects are objects that are owned by more than one address. Transactions affecting multi-writer objects require consensus in Sui. This contrasts with transactions affecting only single-writer objects, which require only a confirmation of the owner's address contents. - -### Object {#object} - -The basic unit of storage in Sui is object. In contrast to many other blockchains, where storage is centered around address and each address contains a key-value store, Sui's storage is centered around objects. Sui objects have one of the following primary states: - -- _Immutable_ - the object cannot be modified. -- _Mutable_ - the object can be changed. - -Further, mutable objects are divided into these categories: - -- _Owned_ - the object can be modified only by its owner. -- _Shared_ - the object can be modified by anyone. - -Immutable objects do not need this distinction because they have no owner. - -### Proof-of-stake {#proof-of-stake} - -[Proof-of-stake](https://en.wikipedia.org/wiki/Proof_of_stake) is a blockchain consensus mechanism where the voting weights of validators or validators is proportional to a bonded amount of the network's native currency (called their stake in the network). This mitigates [Sybil attacks](https://en.wikipedia.org/wiki/Sybil_attack) by forcing bad actors to gain a large stake in the blockchain first. - -### Single-writer objects {#single-writer-objects} - -Single-writer objects are owned by one address. In Sui, transactions affecting only single-writer objects owned by the same address may proceed with only a verification of the sender's address, greatly speeding transaction times. These are _simple transactions_. See Single-Writer Apps for example applications of this simple transaction model. - -### Smart contract {#smart-contract} - -A [smart contract](https://en.wikipedia.org/wiki/Smart_contract) is an agreement based upon the protocol for conducting transactions in a blockchain. In Sui, smart contracts are written in the [Move](https://github.com/MystenLabs/awesome-move) programming language. - -### Sui {#sui} - -Sui refers to the Sui blockchain, and the [Sui open source project](https://github.com/MystenLabs/sui/) as a whole. - -### SUI {#sui-1} - -SUI is the native token to the Sui network. - -### Total order {#total-order} - -[Total order](https://en.wikipedia.org/wiki/Total_order) refers to the ordered presentation of the history of all transactions processed by a traditional blockchain up to a given time. This is maintained by many blockchain systems, as the only way to process transactions. In contrast, Sui uses a causal (partial) order wherever possible and safe. - -### Transaction {#transaction} - -A transaction in Sui is a change to the blockchain. This may be a _simple transaction_ affecting only single-writer, single-address objects, such as minting an NFT or transferring an NFT or another token. These transactions may bypass the consensus protocol in Sui. - -More _complex transactions_ affecting objects that are shared or owned by multiple addresses, such as asset management and other DeFi use cases, go through the [Narwhal and Bullshark](https://github.com/MystenLabs/narwhal) DAG-based mempool and efficient Byzantine Fault Tolerant (BFT) consensus. - -### Transfer {#transfer} - -A transfer is switching the owner address of a token to a new one via command in Sui. This is accomplished via the Sui CLI client command line interface. It is one of the more common of many commands available in the CLI client. - -### Validator {#validator} - -A validator in Sui plays a passive role analogous to the more active role of validators and minors in other blockchains. In Sui, validators do not continuously participate in the consensus protocol but are called into action only when receiving a transaction or -certificate. diff --git a/docs/content/references/sui-graphql.mdx b/docs/content/references/sui-graphql.mdx deleted file mode 100644 index 70245582957..00000000000 --- a/docs/content/references/sui-graphql.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: GraphQL for Sui RPC -description: GraphQL is a public service for the Sui RPC that enables you to efficiently interact with the Sui network. ---- - -GraphQL for the Sui RPC is a public service that enables interacting with the Sui [network](https://sui.io/networkinfo). - -To get started with GraphQL for the Sui RPC, check out the [Getting Started](../guides/developer/getting-started/graphql-rpc.mdx) guide. If you'd like to learn more about the concepts used in the GraphQL service, check out the [GraphQL](../concepts/graphql-rpc.mdx) for Sui RPC concepts page. - -## Key Types - -All GraphQL API elements are accessible via the left sidebar, the following are good starting points to explore from. - -- "Queries" lists all top-level queries for reading the chain state, from reading details about addresses and objects to dryRunTransactionBlock, which has an execution-like interface but does not modify the chain. -- "Mutations" lists operations that can modify chain state, like executeTransactionBlock. -- Object is the type representing all on-chain objects (Move values and packages). -- Address corresponds to account addresses (derived from the public keys of signatures that sign transactions) and can be used to query the objects owned by these accounts and the transactions they have signed or been affected by. -- Owner represents any entity that can own a MoveObject to handle cases where it is not known whether the owner is an Object or an Address (for example, from the perspective of a Move object looking at its owner). - -## Related links - -- [GraphQL migration](../guides/developer/advanced/graphql-migration.mdx): Migrating to GraphQL guides you through migrating Sui RPC projects from JSON-RPC to GraphQL. -- [GraphQL quick-start](../guides/developer/getting-started/graphql-rpc.mdx): Querying Sui RPC with GraphQL gets you started using GraphQL to query the Sui RPC for on-chain data. -- [GraphQL concepts](../concepts/graphql-rpc.mdx): GraphQL for Sui RPC examines the elements of GraphQL that you should know to get the most from the service. diff --git a/docs/content/references/sui-sdks.mdx b/docs/content/references/sui-sdks.mdx deleted file mode 100644 index 5aa5e69713f..00000000000 --- a/docs/content/references/sui-sdks.mdx +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: Sui SDKs ---- - -Sui provides developer kits that act as wrappers for the Sui API. - -## Sui dApp Kit - -[Sui dApp Kit](https://sdk.mystenlabs.com/dapp-kit) is a web frontend SDK that interacts with the Sui API. It is available as an NPM package. - -## Sui Go SDK - -For those that like gophers, see [Go SDK](https://github.com/block-vision/sui-go-sdk). - -## Sui Python SDK - -For snake lovers, see [Python SDK](https://github.com/FrankC01/pysui). - -## Sui Rust SDK - -See [Rust SDK](./rust-sdk.mdx) for SDK configuration and examples of using the Sui API with Rust. - -## Sui TypeScript SDK - -The Sui TypeScript SDK documentation is available in its own microsite: [Sui Typescript SDK](https://sdk.mystenlabs.com/typescript). - - -### Crate documentation - -[GitHub Pages](https://mystenlabs.github.io/sui/sui_sdk/index.html) hosts the generated documentation for Rust crates in the Sui repository. diff --git a/docs/content/sidebars/concepts.js b/docs/content/sidebars/concepts.js index c5e4a4cf2c3..7db366be038 100644 --- a/docs/content/sidebars/concepts.js +++ b/docs/content/sidebars/concepts.js @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 const concepts = [ @@ -62,24 +63,24 @@ const concepts = [ label: 'Move Overview', link: { type: 'doc', - id: 'concepts/sui-move-concepts', + id: 'concepts/iota-move-concepts', }, items: [ - 'concepts/sui-move-concepts/strings', - 'concepts/sui-move-concepts/collections', - 'concepts/sui-move-concepts/init', - 'concepts/sui-move-concepts/entry-functions', - 'concepts/sui-move-concepts/one-time-witness', + 'concepts/iota-move-concepts/strings', + 'concepts/iota-move-concepts/collections', + 'concepts/iota-move-concepts/init', + 'concepts/iota-move-concepts/entry-functions', + 'concepts/iota-move-concepts/one-time-witness', { type: 'category', label: 'Package Upgrades', link: { type: 'doc', - id: 'concepts/sui-move-concepts/packages', + id: 'concepts/iota-move-concepts/packages', }, items: [ - 'concepts/sui-move-concepts/packages/upgrade', - 'concepts/sui-move-concepts/packages/custom-policies', + 'concepts/iota-move-concepts/packages/upgrade', + 'concepts/iota-move-concepts/packages/custom-policies', ], }, { @@ -87,18 +88,18 @@ const concepts = [ label: 'Patterns', link: { type: 'doc', - id: 'concepts/sui-move-concepts/patterns', + id: 'concepts/iota-move-concepts/patterns', }, items: [ - 'concepts/sui-move-concepts/patterns/capabilities', - 'concepts/sui-move-concepts/patterns/witness', - 'concepts/sui-move-concepts/patterns/transferrable-witness', - 'concepts/sui-move-concepts/patterns/hot-potato', - 'concepts/sui-move-concepts/patterns/id-pointer', - 'concepts/sui-move-concepts/patterns/app-extensions', + 'concepts/iota-move-concepts/patterns/capabilities', + 'concepts/iota-move-concepts/patterns/witness', + 'concepts/iota-move-concepts/patterns/transferrable-witness', + 'concepts/iota-move-concepts/patterns/hot-potato', + 'concepts/iota-move-concepts/patterns/id-pointer', + 'concepts/iota-move-concepts/patterns/app-extensions', ], }, - 'concepts/sui-move-concepts/conventions', + 'concepts/iota-move-concepts/conventions', ], }, { @@ -166,21 +167,21 @@ const concepts = [ }, { type: 'category', - label: 'Sui Architecture', + label: 'Iota Architecture', link: { type: 'doc', - id: 'concepts/sui-architecture', + id: 'concepts/iota-architecture', }, items: [ - 'concepts/sui-architecture/high-level', - 'concepts/sui-architecture/sui-security', - 'concepts/sui-architecture/transaction-lifecycle', - 'concepts/sui-architecture/consensus', - 'concepts/sui-architecture/indexer-functions', - 'concepts/sui-architecture/epochs', - 'concepts/sui-architecture/protocol-upgrades', - 'concepts/sui-architecture/data-management-things', - 'concepts/sui-architecture/staking-rewards', + 'concepts/iota-architecture/high-level', + 'concepts/iota-architecture/iota-security', + 'concepts/iota-architecture/transaction-lifecycle', + 'concepts/iota-architecture/consensus', + 'concepts/iota-architecture/indexer-functions', + 'concepts/iota-architecture/epochs', + 'concepts/iota-architecture/protocol-upgrades', + 'concepts/iota-architecture/data-management-things', + 'concepts/iota-architecture/staking-rewards', ], }, { @@ -194,11 +195,11 @@ const concepts = [ 'concepts/tokenomics/proof-of-stake', 'concepts/tokenomics/validators-staking', 'concepts/tokenomics/staking-unstaking', - 'concepts/tokenomics/sui-coin', - 'concepts/tokenomics/sui-bridging', + 'concepts/tokenomics/iota-coin', + 'concepts/tokenomics/iota-bridging', 'concepts/tokenomics/storage-fund', 'concepts/tokenomics/gas-pricing', - 'concepts/tokenomics/gas-in-sui', + 'concepts/tokenomics/gas-in-iota', ], }, 'concepts/research-papers', diff --git a/docs/content/sidebars/guides.js b/docs/content/sidebars/guides.js index a7ada597510..86a438d64e8 100644 --- a/docs/content/sidebars/guides.js +++ b/docs/content/sidebars/guides.js @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 const guides = [ @@ -25,8 +26,8 @@ const guides = [ id: 'guides/developer/getting-started', }, items: [ - 'guides/developer/getting-started/sui-environment', - 'guides/developer/getting-started/sui-install', + 'guides/developer/getting-started/iota-environment', + 'guides/developer/getting-started/iota-install', 'guides/developer/getting-started/connect', 'guides/developer/getting-started/local-network', 'guides/developer/getting-started/get-address', @@ -51,7 +52,7 @@ const guides = [ }, { type: 'category', - label: 'Your First Sui dApp', + label: 'Your First Iota dApp', link: { type: 'doc', id: 'guides/developer/first-app', @@ -66,38 +67,38 @@ const guides = [ }, { type: 'category', - label: 'Sui 101', + label: 'Iota 101', link: { type: 'doc', - id: 'guides/developer/sui-101', + id: 'guides/developer/iota-101', }, items: [ - 'guides/developer/sui-101/shared-owned', + 'guides/developer/iota-101/shared-owned', { type: 'category', label: 'Create Coins and Tokens', link: { type: 'doc', - id: 'guides/developer/sui-101/create-coin', + id: 'guides/developer/iota-101/create-coin', }, items: [ - 'guides/developer/sui-101/create-coin/regulated', - 'guides/developer/sui-101/create-coin/in-game-token', - 'guides/developer/sui-101/create-coin/loyalty', + 'guides/developer/iota-101/create-coin/regulated', + 'guides/developer/iota-101/create-coin/in-game-token', + 'guides/developer/iota-101/create-coin/loyalty', ], }, - 'guides/developer/sui-101/create-nft', - 'guides/developer/sui-101/using-events', - 'guides/developer/sui-101/access-time', - 'guides/developer/sui-101/sign-and-send-txn', - 'guides/developer/sui-101/sponsor-txn', + 'guides/developer/iota-101/create-nft', + 'guides/developer/iota-101/using-events', + 'guides/developer/iota-101/access-time', + 'guides/developer/iota-101/sign-and-send-txn', + 'guides/developer/iota-101/sponsor-txn', { type: 'category', label: 'Working with PTBs', items: [ - 'guides/developer/sui-101/building-ptb', - 'guides/developer/sui-101/coin-mgt', - 'guides/developer/sui-101/simulating-refs', + 'guides/developer/iota-101/building-ptb', + 'guides/developer/iota-101/coin-mgt', + 'guides/developer/iota-101/simulating-refs', ], }, ], @@ -196,7 +197,7 @@ const guides = [ id: 'guides/operator', }, items: [ - 'guides/operator/sui-full-node', + 'guides/operator/iota-full-node', 'guides/operator/validator-config', 'guides/operator/data-management', 'guides/operator/snapshots', diff --git a/docs/content/sidebars/references.js b/docs/content/sidebars/references.js index 4a3bcace49f..c08e0cf46b3 100644 --- a/docs/content/sidebars/references.js +++ b/docs/content/sidebars/references.js @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 const references = [ @@ -9,11 +10,11 @@ const references = [ }, { type: 'category', - label: 'Sui RPC', + label: 'Iota RPC', collapsed: false, link: { type: 'doc', - id: 'references/sui-api', + id: 'references/iota-api', }, items: [ { @@ -21,26 +22,26 @@ const references = [ label: 'GraphQL', link: { type: 'doc', - id: 'references/sui-graphql', + id: 'references/iota-graphql', }, items: [ { type: 'autogenerated', - dirName: 'references/sui-api/sui-graphql/reference', + dirName: 'references/iota-api/iota-graphql/reference', }, ], }, { type: 'link', label: 'JSON-RPC', - href: '/sui-api-ref', + href: '/iota-api-ref', }, - 'references/sui-api/rpc-best-practices', + 'references/iota-api/rpc-best-practices', ], }, { type: 'category', - label: 'Sui CLI', + label: 'Iota CLI', collapsed: false, link: { type: 'doc', @@ -57,11 +58,11 @@ const references = [ }, { type: 'category', - label: 'Sui SDKs', + label: 'Iota SDKs', collapsed: false, link: { type: 'doc', - id: 'references/sui-sdks', + id: 'references/iota-sdks', }, items: [ { @@ -71,18 +72,18 @@ const references = [ }, { type: 'link', - label: 'Sui Go SDK', - href: 'https://github.com/block-vision/sui-go-sdk', + label: 'Iota Go SDK', + href: 'https://github.com/block-vision/iota-go-sdk', }, { type: 'link', - label: 'Sui Python SDK', - href: 'https://github.com/FrankC01/pysui', + label: 'Iota Python SDK', + href: 'https://github.com/FrankC01/pyiota', }, 'references/rust-sdk', { type: 'link', - label: 'Sui TypeScript SDK', + label: 'Iota TypeScript SDK', href: 'https://sdk.mystenlabs.com/typescript', }, ], @@ -93,7 +94,7 @@ const references = [ collapsed: false, link: { type: 'doc', - id: 'references/sui-move', + id: 'references/iota-move', }, items: [ { @@ -114,7 +115,7 @@ const references = [ }, ], }, - 'references/sui-glossary', + 'references/iota-glossary', { type: 'category', label: 'Contribute', @@ -124,13 +125,13 @@ const references = [ }, items: [ 'references/contribute/contribution-process', - 'references/contribute/contribute-to-sui-repos', + 'references/contribute/contribute-to-iota-repos', { type: 'link', label: 'Submit a SIP', - href: 'https://sips.sui.io', + href: 'https://sips.iota.io', }, - 'references/contribute/localize-sui-docs', + 'references/contribute/localize-iota-docs', 'references/contribute/code-of-conduct', 'references/contribute/style-guide', ], diff --git a/docs/content/sidebars/standards.js b/docs/content/sidebars/standards.js index 43e8537fdbf..dcbdc259e19 100644 --- a/docs/content/sidebars/standards.js +++ b/docs/content/sidebars/standards.js @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 const standards = [ diff --git a/docs/content/standards.mdx b/docs/content/standards.mdx index 65f8399938d..b2187c92af4 100644 --- a/docs/content/standards.mdx +++ b/docs/content/standards.mdx @@ -1,9 +1,9 @@ --- -title: Sui Standards Overview +title: Iota Standards Overview sidebar_label: Overview --- -Standards on the Sui blockchain are features, frameworks, or apps that you can extend or customize. +Standards on the Iota blockchain are features, frameworks, or apps that you can extend or customize. @@ -11,6 +11,6 @@ Standards on the Sui blockchain are features, frameworks, or apps that you can e - + diff --git a/docs/content/standards/closed-loop-token.mdx b/docs/content/standards/closed-loop-token.mdx index 8c5b13285aa..bc66be37b56 100644 --- a/docs/content/standards/closed-loop-token.mdx +++ b/docs/content/standards/closed-loop-token.mdx @@ -2,11 +2,11 @@ title: Closed-Loop Token --- -Using the Closed-Loop Token standard, you can limit the applications that can use the token and set up custom policies for transfers, spends, and conversions. The [`sui::token` module](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/docs/sui-framework/token.md) in the Sui framework defines the standard. +Using the Closed-Loop Token standard, you can limit the applications that can use the token and set up custom policies for transfers, spends, and conversions. The [`iota::token` module](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/docs/iota-framework/token.md) in the Iota framework defines the standard. ## Background and use cases -The [Coin standard](./coin.mdx) on Sui is an example of an open-loop system - coins are free-flowing, [wrappable](/concepts/object-ownership/wrapped.mdx), [freely transferable](/concepts/transfers/custom-rules.mdx#the-store-ability-and-transfer-rules) and you can store them in any application. The best real world analogy would be cash - hardly regulated and can be freely used and passed. +The [Coin standard](./coin.mdx) on Iota is an example of an open-loop system - coins are free-flowing, [wrappable](/concepts/object-ownership/wrapped.mdx), [freely transferable](/concepts/transfers/custom-rules.mdx#the-store-ability-and-transfer-rules) and you can store them in any application. The best real world analogy would be cash - hardly regulated and can be freely used and passed. Some applications, however, require constraining the scope of the token to a specific purpose. For example, some applications might need a token that you can only use for a specific service, or that an authorized account can only use, or a token that you can block certain accounts from using. A real-world analogy would be a bank account - regulated, bank-controlled, and compliant with certain rules and policies. @@ -51,10 +51,10 @@ flowchart LR Unlike Coin, which has `key + store` abilities and thus supports wrapping and public transfers, Token has only the `key` ability and cannot be wrapped, stored as a dynamic field, or freely transferred (unless there's a custom policy for that). Due to this restriction, Token **can only be owned by an account** and can't be stored in an application (however, it can be "spent" - see [Spending section](./closed-loop-token/spending.mdx) section). ```move -// defined in `sui::coin` +// defined in `iota::coin` struct Coin has key, store { id: UID, balance: Balance } -// defined in `sui::token` +// defined in `iota::token` struct Token has key { id: UID, balance: Balance } ``` diff --git a/docs/content/standards/closed-loop-token/action-request.mdx b/docs/content/standards/closed-loop-token/action-request.mdx index c8f69d7a796..924f0e315f3 100644 --- a/docs/content/standards/closed-loop-token/action-request.mdx +++ b/docs/content/standards/closed-loop-token/action-request.mdx @@ -17,7 +17,7 @@ Tokens have four protected actions that create an `ActionRequest`: ## ActionRequest structure -`ActionRequest` is defined in the `sui::token` module and contains the following fields: +`ActionRequest` is defined in the `iota::token` module and contains the following fields: - `name`: Name of the performed action, standard ones are `transfer`, `spend`, `to_coin` and `from_coin`, and you can create custom actions. - `amount`: The amount of the token that is being transferred, spent, converted, and so on. @@ -30,7 +30,7 @@ Rules can use these fields to determine whether the action should be allowed or An example of a function creating an `ActionRequest`: ```move -// module: sui::token +// module: iota::token public fun transfer( t: Token, recipient: address, ctx: &mut TxContext ): ActionRequest; @@ -57,7 +57,7 @@ Use the `TreasuryCap` to confirm any action request for the token. It's useful f The signature for the `token::confirm_with_treasury_cap` function is: ```move -// module: sui::token +// module: iota::token public fun confirm_with_treasury_cap( treasury_cap: &mut TreasuryCap, request: ActionRequest, @@ -65,7 +65,7 @@ public fun confirm_with_treasury_cap( ): (String, u64, address, Option
    ); ``` -An example of a transaction implemented in TypeScript with sui.js, confirming an action request with a `TreasuryCap`. Here the admin account owns the `TreasuryCap`, which is used to mint and confirm the transfer request for the token: +An example of a transaction implemented in TypeScript with iota.js, confirming an action request with a `TreasuryCap`. Here the admin account owns the `TreasuryCap`, which is used to mint and confirm the transfer request for the token: ```js let tx = new TransactionBlock(); @@ -104,7 +104,7 @@ tx.moveCall({ The signature for the `token::confirm_request` function is: ```move -// module: sui::token +// module: iota::token public fun confirm_request( treasury_cap: &TokenPolicy, request: ActionRequest, @@ -155,7 +155,7 @@ You can't use `TokenPolicyCap` to confirm `spend` requests. ::: ```move -// module: sui::token +// module: iota::token public fun confirm_with_policy_cap( token_policy_cap: &TokenPolicyCap, @@ -197,7 +197,7 @@ tx.moveCall({ The signature for the `token::add_approval` function is: ```move -// module: sui::token +// module: iota::token public fun add_approval( _t: W, request: &mut ActionRequest, _ctx: &mut TxContext ); diff --git a/docs/content/standards/closed-loop-token/rules.mdx b/docs/content/standards/closed-loop-token/rules.mdx index c9177bd7828..d9c1511bc27 100644 --- a/docs/content/standards/closed-loop-token/rules.mdx +++ b/docs/content/standards/closed-loop-token/rules.mdx @@ -25,8 +25,8 @@ A rule module is a regular module with a `verify`-like function that typically t ```move module example::pass_rule { - use sui::tx_context; - use sui::token::{Self, ActionRequest, TokenPolicy}; + use iota::tx_context; + use iota::token::{Self, ActionRequest, TokenPolicy}; /// The Rule type struct Pass has drop {} @@ -64,14 +64,14 @@ The only attack vector available to the rule creator is upgrading the module and ## Configuration API -The `sui::token` module defines the configuration API and has the following set of functions. +The `iota::token` module defines the configuration API and has the following set of functions. ### Add new configuration A rule must approve new configurations (the rule witness) and the `TokenPolicy` owner. The type of the configuration can be any as long as it has the `store` ability. ```move -// module: sui::token +// module: iota::token public fun add_rule_config( _rule: Rule, policy: &mut TokenPolicy, @@ -86,7 +86,7 @@ public fun add_rule_config( Rules can read the configuration stored in the `TokenPolicy`. ```move -// module: sui::token +// module: iota::token public fun rule_config( _rule: Rule, policy: &TokenPolicy ): &Config; @@ -97,7 +97,7 @@ public fun rule_config( A rule must approve configuration modifications (the rule witness) as well as the `TokenPolicy` owner. ```move -// module: sui::token +// module: iota::token public fun rule_config_mut( _rule: Rule, policy: &mut TokenPolicy, policy_cap: &TokenPolicyCap ): &mut Config; @@ -108,7 +108,7 @@ public fun rule_config_mut( A good practice for rules is to provide a method to remove the configuration, as a rule can use a custom type for it. However, a token owner can always call the `remove_rule_config` function to remove the configuration. ```move -// module: sui::token +// module: iota::token public fun remove_rule_config( policy: &mut TokenPolicy, policy_cap: &TokenPolicyCap, diff --git a/docs/content/standards/closed-loop-token/spending.mdx b/docs/content/standards/closed-loop-token/spending.mdx index 6e4f77ff4e7..ab80eebeeb2 100644 --- a/docs/content/standards/closed-loop-token/spending.mdx +++ b/docs/content/standards/closed-loop-token/spending.mdx @@ -9,7 +9,7 @@ Because `Token` types do not have the `store` ability, it is impossible to store Tokens can be spent by calling the `spend` method. It takes the following arguments: ```move -// module sui::token +// module iota::token public fun spend(token: Token, ctx: &mut TxContext): ActionRequest; ``` diff --git a/docs/content/standards/closed-loop-token/token-policy.mdx b/docs/content/standards/closed-loop-token/token-policy.mdx index 54b352d9c29..124057d8b3b 100644 --- a/docs/content/standards/closed-loop-token/token-policy.mdx +++ b/docs/content/standards/closed-loop-token/token-policy.mdx @@ -9,7 +9,7 @@ title: Token Policy You create a new `TokenPolicy` using the `token::new_policy` function. The function takes the `TreasuryCap` as an argument and returns a `TokenPolicy` object and a managing capability. ```move -// module: sui::token +// module: iota::token public fun new_policy( treasury_cap: &TreasuryCap, ctx: &mut TxContext @@ -23,7 +23,7 @@ You must use the `token::share_policy` function to share the `TokenPolicy` objec To allow methods without any conditions, use the `token::allow` function. The function takes a `TokenPolicy` and `TokenPolicyCap` as arguments. If allowed, the action can be confirmed in the `TokenPolicy` using the `token::confirm_request` function (see [`ActionRequest`](./action-request.mdx#confirming-with-tokenpolicy)). ```move -// module sui::token +// module iota::token public fun allow( policy: &mut TokenPolicy, policy_cap: &TokenPolicyCap, @@ -56,7 +56,7 @@ TokenPolicy To add a rule for an action, use the `token::add_rule_for_action` function. The function takes a `TokenPolicy` and `TokenPolicyCap` as arguments. The rule is specified by its type (for example, `0x0...::denylist::Denylist`). ```move -// module: sui::token +// module: iota::token public fun add_rule_for_action( policy: &mut TokenPolicy, policy_cap: &TokenPolicyCap, @@ -72,7 +72,7 @@ Signature for the reverse operation `token::remove_rule_for_action` is symmetric Spent balance can be consumed from the `TokenPolicy` using the `token::flush` function. It requires a `TreasuryCap`. ```move -// module sui::token +// module iota::token public fun flush( policy: &mut TokenPolicy, treasury_cap: &mut TreasuryCap, diff --git a/docs/content/standards/coin.mdx b/docs/content/standards/coin.mdx index c19bdb7fbf9..22dd5edb8d9 100644 --- a/docs/content/standards/coin.mdx +++ b/docs/content/standards/coin.mdx @@ -1,30 +1,30 @@ --- title: Coin Standard -description: The Sui Coin standard enables you to create a broad range of fungible tokens on the Sui network to satisfy a number of use cases. The Coin standed on Sui is equivalent to the ERC-20 technical standard on Ethereum. +description: The Iota Coin standard enables you to create a broad range of fungible tokens on the Iota network to satisfy a number of use cases. The Coin standed on Iota is equivalent to the ERC-20 technical standard on Ethereum. sidebar_label: Coin --- -The Coin standard is the technical standard used for smart contracts on Sui for creating coins on the Sui blockchain. The standardization of coin creation on Sui means that wallets, exchanges, and other smart contracts can manage coins created on Sui the same as they manage SUI, without any additional processing logic. +The Coin standard is the technical standard used for smart contracts on Iota for creating coins on the Iota blockchain. The standardization of coin creation on Iota means that wallets, exchanges, and other smart contracts can manage coins created on Iota the same as they manage IOTA, without any additional processing logic. -See [Sui Tokenomics](../concepts/tokenomics.mdx) to learn more about the SUI native coin and its use on the Sui network. +See [Iota Tokenomics](../concepts/tokenomics.mdx) to learn more about the IOTA native coin and its use on the Iota network. -Although coins on Sui follow the Coin standard, they can offer specialized abilities. For example, you can create a regulated token that allows its creator to add specific addresses to a deny list, so that the identified addresses cannot use the token as inputs to transactions. +Although coins on Iota follow the Coin standard, they can offer specialized abilities. For example, you can create a regulated token that allows its creator to add specific addresses to a deny list, so that the identified addresses cannot use the token as inputs to transactions. -See the [coin module](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/docs/sui-framework/coin.md) documentation for all available options when creating a coin-type token on Sui. +See the [coin module](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/docs/iota-framework/coin.md) documentation for all available options when creating a coin-type token on Iota. ## Fungible tokens -In the Sui blockchain ecosystem, the `Coin` type represents open-loop fungible tokens (see `Token` for closed-loop tokens). Coins are denominated by their type parameter, `T`, which is also associated with metadata (like name, symbol, decimal precision, and so on) that applies to all instances of `Coin`. The `sui::coin` module exposes an interface over `Coin` that treats it as fungible, meaning that a unit of `T` held in one instance of `Coin` is interchangeable with any other unit of `T`, much like how traditional fiat currencies operate. +In the Iota blockchain ecosystem, the `Coin` type represents open-loop fungible tokens (see `Token` for closed-loop tokens). Coins are denominated by their type parameter, `T`, which is also associated with metadata (like name, symbol, decimal precision, and so on) that applies to all instances of `Coin`. The `iota::coin` module exposes an interface over `Coin` that treats it as fungible, meaning that a unit of `T` held in one instance of `Coin` is interchangeable with any other unit of `T`, much like how traditional fiat currencies operate. :::info -The documentation refers to fungible tokens created on Sui using the Coin standard as "coins". For fungible tokens created on Sui using the [Closed-Loop Token standard](./closed-loop-token.mdx), the documentation uses the term "tokens". In practice, the terms for both these objects are often interchangeable. +The documentation refers to fungible tokens created on Iota using the Coin standard as "coins". For fungible tokens created on Iota using the [Closed-Loop Token standard](./closed-loop-token.mdx), the documentation uses the term "tokens". In practice, the terms for both these objects are often interchangeable. ::: ## Treasury capability -When you create a coin using the `coin::create_currency` function, the publisher of the smart contract that creates the coin receives a `TreasuryCap` object. The `TreasuryCap` object is required to mint new coins or to burn current ones. Consequently, only addresses that have access to this object are able to maintain the coin supply on the Sui network. +When you create a coin using the `coin::create_currency` function, the publisher of the smart contract that creates the coin receives a `TreasuryCap` object. The `TreasuryCap` object is required to mint new coins or to burn current ones. Consequently, only addresses that have access to this object are able to maintain the coin supply on the Iota network. The `TreasuryCap` object is transferable, so a third party can take over the management of a coin that you create if you transfer the `TreasuryCap`. After transferring the capability, however, you are no longer able to mint and burn tokens yourself. @@ -57,7 +57,7 @@ The fields of the metadata objects include the following: | `id` | The object ID of the metadata for the token. | | `decimals` | The number of decimals the token uses. If you set this field to `3`, then a token of value `1000` would display as `1.000`. | | `name` | Name of the coin. | -| `symbol` | Symbol for the coin. This might be the same as `name`, but is typically fewer than five all capital letters. For example, `SUI` is the `symbol` for the native coin on Sui but its `name` is also `SUI`. | +| `symbol` | Symbol for the coin. This might be the same as `name`, but is typically fewer than five all capital letters. For example, `IOTA` is the `symbol` for the native coin on Iota but its `name` is also `IOTA`. | | `description` | A short description to describe the token. | | `icon_url` | The URL for the token's icon, used for display in wallets, explorers, and other apps. | @@ -71,7 +71,7 @@ The fields of the metadata objects include the following: ## Minting and burning coins -The `coin` module provides the logic for creating and destroying coins on the Sui network (as long as you own the associated `TreasuryCap`). These functions are the same for all coins and each requires the `TreasuryCap` as an input. +The `coin` module provides the logic for creating and destroying coins on the Iota network (as long as you own the associated `TreasuryCap`). These functions are the same for all coins and each requires the `TreasuryCap` as an input. ### Mint @@ -148,7 +148,7 @@ const txb = new TransactionBlock(); txb.moveCall({ target: `0x2::coin::deny_list_add`, arguments: [ - txb.object(), + txb.object(), txb.object(), txb.pure.address(options.address), ], @@ -156,7 +156,7 @@ txb.moveCall({ }); ``` -- `` is `"0x403"` +- `` is `"0x403"` - `` is the object of type `DenyCap` we received from publishing the contract - `options.address` is the address to ban - `` is ``${PACKAGE-ID}::${MODULE-NAME}::${COIN-NAME}``, which is ``${PACKAGE-ID}::regulated_coin::REGULATED_COIN`` based on the example. @@ -176,7 +176,7 @@ let deny_list = ptb.obj(ObjectArg::SharedObject { let deny_cap = ptb.obj(ObjectArg::ImmOrOwnedObject(deny_cap))?; let address = ptb.pure(cmd.address())?; ptb.command(Command::move_call( - SUI_FRAMEWORK_PACKAGE_ID, + IOTA_FRAMEWORK_PACKAGE_ID, Identifier::from(COIN_MODULE_NAME), Identifier::from_str("deny_list_add".to_string())?, vec![], @@ -191,7 +191,7 @@ let builder = ptb.finish(); - `SequenceNumber` is the `initial_shared_version` of the `DenyList` singleton. - `deny_cap` is the `ObjectRef` (`(ObjectID, SequenceNumber, ObjectDigest)`) of the `DenyCap` the publisher has received. - `otw_type` is the `TypeTag` created from `::regulated_coin::REGULATED_COIN` type. -- `cmd.address()` returns the address to ban as a `SuiAddress`. +- `cmd.address()` returns the address to ban as a `IotaAddress`. @@ -262,10 +262,10 @@ public entry fun ( ## Related links -Check out the following content for more information about coins and tokens on Sui: +Check out the following content for more information about coins and tokens on Iota: -- [Create a Coin](../guides/developer/sui-101/create-coin.mdx): Guide for creating coins and regulated coins in your smart contracts. -- [Closed-Loop Token Standard](./closed-loop-token.mdx): Details the Token standard on Sui. -- [`coin` module rustdoc documentation](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/docs/sui-framework/coin.md): Automated documentation output for the Sui framework `coin` module. -- [`token` module rustdoc documentation](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/docs/sui-framework/token.md): Automated documentation output for the Sui framework `token` module. -- [Tokenomics](../concepts/tokenomics.mdx): Discover the Sui ecosystem and where SUI coins fit within it. \ No newline at end of file +- [Create a Coin](../guides/developer/iota-101/create-coin.mdx): Guide for creating coins and regulated coins in your smart contracts. +- [Closed-Loop Token Standard](./closed-loop-token.mdx): Details the Token standard on Iota. +- [`coin` module rustdoc documentation](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/docs/iota-framework/coin.md): Automated documentation output for the Iota framework `coin` module. +- [`token` module rustdoc documentation](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/docs/iota-framework/token.md): Automated documentation output for the Iota framework `token` module. +- [Tokenomics](../concepts/tokenomics.mdx): Discover the Iota ecosystem and where IOTA coins fit within it. \ No newline at end of file diff --git a/docs/content/standards/deepbook.mdx b/docs/content/standards/deepbook.mdx index 6d4bed9fd75..5bcc8ff9a96 100644 --- a/docs/content/standards/deepbook.mdx +++ b/docs/content/standards/deepbook.mdx @@ -1,19 +1,19 @@ --- title: DeepBook -description: A central limit order book that offers features and functionality for marketplaces on Sui. Token exchanges leveraging the layer can feature transparency, a full range of trading options, and customer privacy. +description: A central limit order book that offers features and functionality for marketplaces on Iota. Token exchanges leveraging the layer can feature transparency, a full range of trading options, and customer privacy. --- -As Sui's first native liquidity layer, DeepBook provides token trading activity. Token exchanges leveraging the layer can feature transparency, a full range of trading options, and customer privacy. DeepBook operates as a decentralized and permissionless environment to support token trades. +As Iota's first native liquidity layer, DeepBook provides token trading activity. Token exchanges leveraging the layer can feature transparency, a full range of trading options, and customer privacy. DeepBook operates as a decentralized and permissionless environment to support token trades. -DeepBook is open for community development. You can use the [Sui Improvement Proposals](https://github.com/sui-foundation/sips?ref=blog.sui.io) (SIPs) process to suggest changes to make DeepBook better. +DeepBook is open for community development. You can use the [Iota Improvement Proposals](https://github.com/iota-foundation/sips?ref=blog.iota.io) (SIPs) process to suggest changes to make DeepBook better. DeepBook does not include an end-user interface for token trading. Rather, it offers built-in trading functionality that can support token trades from decentralized exchanges, wallets, or other apps. You can leverage its SDK to build functionality for token trades and price queries. ## Liquidity support -Similar to order books for other market places, DeepBook's central limit order book (CLOB) architecture enables you to enter market and limit orders. You can sell SUI tokens, referred to as an "ask," can set your price, referred to as a limit order, or sell at the market's going rate. If you are seeking to buy SUI, referred to as a "bid," you can pay the current market price or set a limit amount you're willing to pay. Limit orders only get fulfilled if the CLOB finds a match between a buyer and seller. +Similar to order books for other market places, DeepBook's central limit order book (CLOB) architecture enables you to enter market and limit orders. You can sell IOTA tokens, referred to as an "ask," can set your price, referred to as a limit order, or sell at the market's going rate. If you are seeking to buy IOTA, referred to as a "bid," you can pay the current market price or set a limit amount you're willing to pay. Limit orders only get fulfilled if the CLOB finds a match between a buyer and seller. -If you put in a limit order for 1,000 SUI, and no single seller is currently offering that quantity of tokens, DeepBook automatically pools the current asks to meet the quantity of your bid. +If you put in a limit order for 1,000 IOTA, and no single seller is currently offering that quantity of tokens, DeepBook automatically pools the current asks to meet the quantity of your bid. ## Transparency and privacy diff --git a/docs/content/standards/deepbook/design.mdx b/docs/content/standards/deepbook/design.mdx index c60ba598617..af72f1eca9e 100644 --- a/docs/content/standards/deepbook/design.mdx +++ b/docs/content/standards/deepbook/design.mdx @@ -6,7 +6,7 @@ slug: /deepbook-design ## Pools {#pools} -At the center of DeepBook is a hyper-efficient per-current pair shared-object pool structure. This architecture maximally utilizes Sui's Narwhal and Bullshark engine to minimize contention and achieve high throughput. +At the center of DeepBook is a hyper-efficient per-current pair shared-object pool structure. This architecture maximally utilizes Iota's Narwhal and Bullshark engine to minimize contention and achieve high throughput. For each base and quote asset trading pair, a globally shared pool is created to bookkeep open orders on the order book and handle placement, cancellation, and settlement of orders. Under this architecture, you can parallelize transactions involving different trading pairs to maximize throughput. @@ -63,7 +63,7 @@ struct Order has store, drop { // For each pool, order id is incremental and unique for each opening order. // Orders that are submitted earlier have lower order ids. // 64 bits are sufficient for order ids, whereas 32 bits are not. - // Assuming a maximum TPS of 100K/s of Sui chain, it would take (1<<63) / 100000 / 3600 / 24 / 365 = 2924712 years to reach the full capacity. + // Assuming a maximum TPS of 100K/s of Iota chain, it would take (1<<63) / 100000 / 3600 / 24 / 365 = 2924712 years to reach the full capacity. // The highest bit of the order id denotes the order type, 0 for bid, 1 for ask. order_id: u64, // Only used for limit orders. @@ -85,7 +85,7 @@ Order matching occurs when a taker order is submitted to the Central Limit Order ### Order tracking {#order-tracking} -DeepBook supports efficient tracking of maker orders. Each unfilled maker order is associated with a unique u64 order id, and users can query the order status using the order id together with the Sui RPC call. Users can also subscribe to the event stream emitted by DeepBook related to changes in order status. DeepBook currently supports the following events, `OrderPlaced`, `OrderFilled`, and `OrderCanceled`. +DeepBook supports efficient tracking of maker orders. Each unfilled maker order is associated with a unique u64 order id, and users can query the order status using the order id together with the Iota RPC call. Users can also subscribe to the event stream emitted by DeepBook related to changes in order status. DeepBook currently supports the following events, `OrderPlaced`, `OrderFilled`, and `OrderCanceled`. ```move /// Emitted when a maker order is injected into the order book. diff --git a/docs/content/standards/deepbook/orders.mdx b/docs/content/standards/deepbook/orders.mdx index c0cc7822dc6..f1745dbed02 100644 --- a/docs/content/standards/deepbook/orders.mdx +++ b/docs/content/standards/deepbook/orders.mdx @@ -16,7 +16,7 @@ struct Order has store, drop { // For each pool, order id is incremental and unique for each opening order. // Orders that are submitted earlier have lower order ids. // 64 bits are sufficient for order ids, whereas 32 bits are not. - // Assuming a maximum TPS of 100K/s of Sui chain, it would take (1<<63) / 100000 / 3600 / 24 / 365 = 2924712 years to reach the full capacity. + // Assuming a maximum TPS of 100K/s of Iota chain, it would take (1<<63) / 100000 / 3600 / 24 / 365 = 2924712 years to reach the full capacity. // The highest bit of the order id denotes the order type, 0 for bid, 1 for ask. order_id: u64, // Only used for limit orders. @@ -36,7 +36,7 @@ Order matching occurs when a taker order is submitted to the CLOB without a cent ## Order tracking {#order-tracking} -DeepBook supports efficient tracking of maker orders. Each unfilled maker order is associated with a unique u64 order id, and users can query the order status using the order id together with the Sui RPC call. Users can also subscribe to the event stream emitted by DeepBook related to changes in order status. DeepBook currently supports the following events, `OrderPlaced`, `OrderFilled` and `OrderCanceled`. +DeepBook supports efficient tracking of maker orders. Each unfilled maker order is associated with a unique u64 order id, and users can query the order status using the order id together with the Iota RPC call. Users can also subscribe to the event stream emitted by DeepBook related to changes in order status. DeepBook currently supports the following events, `OrderPlaced`, `OrderFilled` and `OrderCanceled`. ```move /// Emitted when a maker order is injected into the order book. @@ -69,10 +69,10 @@ struct OrderFilled has copy, store, drop } ``` -The following example uses the [Sui TypeScript SDK](https://sdk.mystenlabs.com/typescript) to connect via websocket to listen to events. +The following example uses the [Iota TypeScript SDK](https://sdk.mystenlabs.com/typescript) to connect via websocket to listen to events. ```javascript -const local_client = new SuiClient({ url: 'https://fullnode.mainnet.sui.io:443/' }); +const local_client = new IotaClient({ url: 'https://fullnode.mainnet.iota.io:443/' }); const deepbook_client = new DeepBookClient(local_client); const deepbook = '0x000000000000000000000000000000000000000000000000000000000000dee9'; @@ -96,7 +96,7 @@ const poolFilter = { }, }; -deepbook_client.suiClient.subscribeEvent({ +deepbook_client.iotaClient.subscribeEvent({ filter: moveEventsFilter, onMessage(event) { console.log(event); diff --git a/docs/content/standards/deepbook/pools.mdx b/docs/content/standards/deepbook/pools.mdx index bc833df6147..5833e9911ab 100644 --- a/docs/content/standards/deepbook/pools.mdx +++ b/docs/content/standards/deepbook/pools.mdx @@ -3,7 +3,7 @@ title: DeepBook Pools slug: /deepbook-pools --- -At the center of DeepBook is a hyper-efficient per-current pair shared-object `Pool` structure. This architecture maximally utilizes Sui's Narwhal and Bullshark engine to minimize contention and achieve high throughput. +At the center of DeepBook is a hyper-efficient per-current pair shared-object `Pool` structure. This architecture maximally utilizes Iota's Narwhal and Bullshark engine to minimize contention and achieve high throughput. For each base and quote asset trading pair, a globally shared `Pool` is created to bookkeep open orders on the order book and handle placement, cancellation, and settlement of orders. Under this architecture, transactions involving different trading pairs can be easily parallelized to maximize throughput. diff --git a/docs/content/standards/deepbook/routing-a-swap.mdx b/docs/content/standards/deepbook/routing-a-swap.mdx index 8f52e667051..91205aa32d6 100644 --- a/docs/content/standards/deepbook/routing-a-swap.mdx +++ b/docs/content/standards/deepbook/routing-a-swap.mdx @@ -132,7 +132,7 @@ public async placeMarketOrderWithSmartRouting( arguments: [ overrides.txb.object(String(poolInfo.clob)), _amount, - overrides.txb.object(normalizeSuiObjectId(this.configs.clock)), + overrides.txb.object(normalizeIotaObjectId(this.configs.clock)), _tokenOut, ], }); @@ -146,7 +146,7 @@ public async placeMarketOrderWithSmartRouting( _amount, _tokenIn, _tokenOut, - overrides.txb.object(normalizeSuiObjectId(this.configs.clock)), + overrides.txb.object(normalizeIotaObjectId(this.configs.clock)), ], }); } diff --git a/docs/content/standards/deepbook/trade-and-swap.mdx b/docs/content/standards/deepbook/trade-and-swap.mdx index 6db8575d1ac..7b5f7d11927 100644 --- a/docs/content/standards/deepbook/trade-and-swap.mdx +++ b/docs/content/standards/deepbook/trade-and-swap.mdx @@ -7,7 +7,7 @@ This section shows how to construct and execute a trade on the DeepBook protocol ## Create a pool {#create-pool} -When you create a pool in DeepBook, you need to specify the `BaseAsset`, `QuoteAsset`, `tick_size`, and `lot_size`. You also need to pay a transaction fee (in SUI) to create a pool. +When you create a pool in DeepBook, you need to specify the `BaseAsset`, `QuoteAsset`, `tick_size`, and `lot_size`. You also need to pay a transaction fee (in IOTA) to create a pool. **Function signature for `create_pool` in Move contract** @@ -17,14 +17,14 @@ When you create a pool in DeepBook, you need to specify the `BaseAsset`, `QuoteA /// 0. `[registry]` Object ID refers to the pool registry /// 1. `[tick_size]` Minimal Price Change Accuracy of this pool /// 2. `[lot_size]` Minimal lot Change Accuracy of this pool -/// 3. `[coin]` Object ID of the sui coin, to pay fee for create pool (100 MIST sui charged) +/// 3. `[coin]` Object ID of the iota coin, to pay fee for create pool (100 MICROS iota charged) /// Returns the AccountCap -public fun create_pool( +public fun create_pool( registry: &mut Registry, tick_size: u64, lot_size: u64, - coin: Coin, + coin: Coin, ctx: &mut TxContext, ) ``` @@ -50,10 +50,10 @@ public createPool( ): TransactionBlock { const coinType1 = convertToTokenType(token1, this.records); const coinType2 = convertToTokenType(token2, this.records); - // we have to split sui as a param into the code + // we have to split iota as a param into the code const [coin] = overrides.txb.splitCoins(overrides.txb.gas, [overrides.txb.pure(200000000)]); overrides.txb.moveCall({ - typeArguments: [coinType1, coinType2, '0x2::sui::SUI'], + typeArguments: [coinType1, coinType2, '0x2::iota::IOTA'], target: `${this.configs.swapPackageId}::clob::create_pool`, arguments: [ overrides.txb.object(String(this.configs.registryId)), @@ -75,15 +75,15 @@ For limit order, you need to create a custodian account the first time you inter ### Scaling precision {#scaling-precision} -Tokens are created with different decimal precision. For example, SUI has nine decimals of precision, while the wormhole wrapped ethereum USDC has +Tokens are created with different decimal precision. For example, IOTA has nine decimals of precision, while the wormhole wrapped ethereum USDC has six decimals of precision. To accommodate proper pricing within DeepBook, every decimal is scaled with 10^9 precision. All the decimals in DeepBook meet the equation: `10^9 \* (priceInRealWorld/priceInDeepBook) = (10^baseAssetDecimal) / (10^quoteAssetDecimal)`. -Let's walk through an example between SUI/USDC. For this example, assume Sui price is $1.10 and is the base asset -of the SUI/USDC trading pair. +Let's walk through an example between IOTA/USDC. For this example, assume Iota price is $1.10 and is the base asset +of the IOTA/USDC trading pair. -Thus, the calculation is `10^9 \* (1.10/ P_d) = 1000`, where `P_d` should be the price of sui in the DeepBook SUI/USDC trading pair. You can solve for `P_d = 1100000`, -so if the user wants to sell SUI at the market price in DeepBook, they should enter a price with six decimal points of precision. +Thus, the calculation is `10^9 \* (1.10/ P_d) = 1000`, where `P_d` should be the price of iota in the DeepBook IOTA/USDC trading pair. You can solve for `P_d = 1100000`, +so if the user wants to sell IOTA at the market price in DeepBook, they should enter a price with six decimal points of precision. ### Limit order {#limit-order} @@ -114,13 +114,13 @@ Before placing a limit order, traders need to host a custodian account with asse ```mermaid flowchart LR A((user_address\n0x1234\ncustodian_cap_address\n0xABCD)) - subgraph Sui_blockchain + subgraph Iota_blockchain direction TB B["account_balances: Table<address, Account<T>>"] - C("
    0xABCD5 SUI
    0xBCDE12 SUI
    ......
    ") + C("
    0xABCD5 IOTA
    0xBCDE12 IOTA
    ......
    ") end - A ----> Sui_blockchain + A ----> Iota_blockchain ``` **Function signature for `create_account` in Move contract** @@ -353,7 +353,7 @@ public placeLimitOrder( overrides.txb.pure(isBid), overrides.txb.pure(Math.floor(expireTimestamp)), overrides.txb.pure(restriction), - overrides.txb.object(normalizeSuiObjectId(this.configs.clock)), + overrides.txb.object(normalizeIotaObjectId(this.configs.clock)), typeof accountCap == "string" ? overrides.txb.object(accountCap) : accountCap, ], }); @@ -445,7 +445,7 @@ public async placeMarketOrder( arguments: [ overrides.txb.object(String(poolInfo.clob)), _amount, - overrides.txb.object(normalizeSuiObjectId(this.configs.clock)), + overrides.txb.object(normalizeIotaObjectId(this.configs.clock)), _tokenOut, ], }); @@ -462,7 +462,7 @@ public async placeMarketOrder( _amount, _tokenIn, _tokenOut, - overrides.txb.object(normalizeSuiObjectId(this.configs.clock)), + overrides.txb.object(normalizeIotaObjectId(this.configs.clock)), ], }); } diff --git a/docs/content/standards/display.mdx b/docs/content/standards/display.mdx index 302fb2fe2e2..e46a64bcb16 100644 --- a/docs/content/standards/display.mdx +++ b/docs/content/standards/display.mdx @@ -1,15 +1,15 @@ --- -title: Sui Object Display -description: The Sui Object Display standard is a template engine that enables on-chain management of off-chain representation (display) for a type. +title: Iota Object Display +description: The Iota Object Display standard is a template engine that enables on-chain management of off-chain representation (display) for a type. --- -The Sui Object Display standard is a template engine that enables on-chain management of off-chain representation (display) for a type. With it, you can substitute data for an object into a template string. The standard doesn’t limit the fields you can set. You can use the `{property}` syntax to access all object properties, and then insert them as a part of the template string. +The Iota Object Display standard is a template engine that enables on-chain management of off-chain representation (display) for a type. With it, you can substitute data for an object into a template string. The standard doesn’t limit the fields you can set. You can use the `{property}` syntax to access all object properties, and then insert them as a part of the template string. -Use a `Publisher` object that you own to set `sui::display` for a type. For more information about `Publisher` objects, see [Publisher](https://examples.sui.io/basics/publisher.html) topic in *Sui Move by Example*. +Use a `Publisher` object that you own to set `iota::display` for a type. For more information about `Publisher` objects, see [Publisher](https://examples.iota.io/basics/publisher.html) topic in *Iota Move by Example*. -In Sui Move, `Display` represents an object that specifies a set of named templates for the type `T`. For example, for a type `0x2::capy::Capy` the display syntax is: `Display<0x2::capy::Capy>`. +In Iota Move, `Display` represents an object that specifies a set of named templates for the type `T`. For example, for a type `0x2::capy::Capy` the display syntax is: `Display<0x2::capy::Capy>`. -Sui Full nodes process all objects of the type `T` by matching the `Display` definition, and return the processed result when you query an object with the `{ showDisplay: true }` setting in the query. +Iota Full nodes process all objects of the type `T` by matching the `Display` definition, and return the processed result when you query an object with the `{ showDisplay: true }` setting in the query. ## Display properties @@ -24,35 +24,35 @@ The basic set of properties suggested includes: - `creator` - A string that indicates the object creator. -### An example Sui Hero module +### An example Iota Hero module The following code sample demonstrates how the `Display` for an example `Hero` module varies based on the `name`, `id`, and `image_url` properties of the type `Hero`. The following represents the template the `init` function defines: ```json { "name": "{name}", - "link": "https://sui-heroes.io/hero/{id}", + "link": "https://iota-heroes.io/hero/{id}", "image_url": "ipfs://{image_url}", - "description": "A true Hero of the Sui ecosystem!", - "project_url": "https://sui-heroes.io", - "creator": "Unknown Sui Fan" + "description": "A true Hero of the Iota ecosystem!", + "project_url": "https://iota-heroes.io", + "creator": "Unknown Iota Fan" } ``` ```move -/// Example of an unlimited "Sui Hero" collection - anyone can +/// Example of an unlimited "Iota Hero" collection - anyone can /// mint their Hero. Shows how to initialize the `Publisher` and how /// to use it to get the `Display` object - a way to describe a /// type for the ecosystem. module examples::my_hero { - use sui::tx_context::{sender, TxContext}; + use iota::tx_context::{sender, TxContext}; use std::string::{utf8, String}; - use sui::transfer; - use sui::object::{Self, UID}; + use iota::transfer; + use iota::object::{Self, UID}; // The creator bundle: these two packages often go together. - use sui::package; - use sui::display; + use iota::package; + use iota::display; /// The Hero - an outstanding collection of digital art. struct Hero has key, store { @@ -85,15 +85,15 @@ module examples::my_hero { // For `name` one can use the `Hero.name` property utf8(b"{name}"), // For `link` one can build a URL using an `id` property - utf8(b"https://sui-heroes.io/hero/{id}"), + utf8(b"https://iota-heroes.io/hero/{id}"), // For `image_url` use an IPFS template + `image_url` property. utf8(b"ipfs://{image_url}"), // Description is static for all `Hero` objects. - utf8(b"A true Hero of the Sui ecosystem!"), + utf8(b"A true Hero of the Iota ecosystem!"), // Project URL is usually static - utf8(b"https://sui-heroes.io"), + utf8(b"https://iota-heroes.io"), // Creator field can be any - utf8(b"Unknown Sui Fan") + utf8(b"Unknown Iota Fan") ]; // Claim the `Publisher` for the package! @@ -125,7 +125,7 @@ The `display::new` call creates a `Display`, either in a custom function or m The following code sample demonstrates how to create a `Display`: ```move -module sui::display { +module iota::display { /// Get a new Display object for the `T`. /// Publisher must be the publisher of the T, `from_package` /// check is performed. @@ -136,7 +136,7 @@ module sui::display { After you create the `Display`, you can modify it. The following code sample demonstrates how to modify a `Display`: ```move -module sui::display { +module iota::display { /// Sets multiple fields at once public fun add_multiple( self: &mut Display, @@ -157,15 +157,15 @@ Next, the `update_version` call applies the changes and sets the `Display` for t The following code sample demonstrates how to use the `update_version` call: ```move -module sui::display { +module iota::display { /// Update the version of Display and emit an event public fun update_version(self: &mut Display) { /* ... */ } } ``` -## Sui utility objects +## Iota utility objects -In Sui, utility objects enable authorization for capabilities. Almost all modules have features that can be accessed only with the required capability. Generic modules allow one capability per application, such as a marketplace. Some capabilities mark ownership of a shared object on-chain, or access the shared data from another account. +In Iota, utility objects enable authorization for capabilities. Almost all modules have features that can be accessed only with the required capability. Generic modules allow one capability per application, such as a marketplace. Some capabilities mark ownership of a shared object on-chain, or access the shared data from another account. With capabilities, it is important to provide a meaningful description of objects to facilitate user interface implementation. This helps avoid accidentally transferring the wrong object when objects are similar. It also provides a user-friendly description of items that users see. The following example demonstrates how to create a capy capability: @@ -199,7 +199,7 @@ module capy::capy_items { ## Unique objects with dynamic representation -Sui Capys use dynamic image generation. When a Capy is born, its attributes determine the Capy’s appearance, such as color or pattern. When a user puts an item on a Capy, the Capy’s appearance changes. When users put multiple items on a Capy, there’s a chance of a bonus for a combination of items. +Iota Capys use dynamic image generation. When a Capy is born, its attributes determine the Capy’s appearance, such as color or pattern. When a user puts an item on a Capy, the Capy’s appearance changes. When users put multiple items on a Capy, there’s a chance of a bonus for a combination of items. To implement this, the Capys game API service refreshes the image in response to a user-initiated change. The URL for a Capy is a template with the `capy.id`. But storing the full URL - as well as other fields in the Capy object due to their diverse population - also leads to users paying for excess storage and increased gas fees. @@ -222,7 +222,7 @@ module capy::capy { This is the simplest scenario - an object represents everything itself. It is very easy to apply a metadata standard to an object of this kind, especially if the object stays immutable forever. However, if the metadata standard evolves and some ecosystem projects add new features for some properties, this object always stays in its original form and might require backward-compatible changes. ```move -module sui::devnet_nft { +module iota::devnet_nft { /// A Collectible with a static data. URL, name, description are /// set only once on a mint event struct DevNetNFT has key, store { diff --git a/docs/content/standards/kiosk-apps.mdx b/docs/content/standards/kiosk-apps.mdx index aad201d7784..2cf66d1dd92 100644 --- a/docs/content/standards/kiosk-apps.mdx +++ b/docs/content/standards/kiosk-apps.mdx @@ -1,9 +1,9 @@ --- title: Kiosk Apps -description: Kiosk apps are a way to extend the functionality of Sui Kiosk while keeping the core functionality intact. You can develop apps to add new features to a kiosk without having to modify the core code or move the assets elsewhere. +description: Kiosk apps are a way to extend the functionality of Iota Kiosk while keeping the core functionality intact. You can develop apps to add new features to a kiosk without having to modify the core code or move the assets elsewhere. --- -Kiosk apps are a way to extend the functionality of Sui Kiosk while keeping the core functionality intact. You can develop apps to add new features to a kiosk without having to modify the core code or move the assets elsewhere. +Kiosk apps are a way to extend the functionality of Iota Kiosk while keeping the core functionality intact. You can develop apps to add new features to a kiosk without having to modify the core code or move the assets elsewhere. There are two types of apps: @@ -16,7 +16,7 @@ Basic Kiosk apps do not require Kiosk Apps API to function. They usually serve t ### UID access via the uid_mut -Kiosk has an `id: UID` field like all objects on Sui, which allows this object to be uniquely identified and carry custom dynamic fields and dynamic object fields. The Kiosk itself is built around dynamic fields and features like place and list are built around dynamic object fields. +Kiosk has an `id: UID` field like all objects on Iota, which allows this object to be uniquely identified and carry custom dynamic fields and dynamic object fields. The Kiosk itself is built around dynamic fields and features like place and list are built around dynamic object fields. ### The uid_mut_as_owner function @@ -39,8 +39,8 @@ You can attach custom dynamic fields to your kiosks that anyone can then read (b module examples::kiosk_name_ext { use std::string::String; use std::option::{Self, Option}; - use sui::dynamic_field as df; - use sui::kiosk::{Self, Kiosk, KioskOwnerCap}; + use iota::dynamic_field as df; + use iota::kiosk::{Self, Kiosk, KioskOwnerCap}; /// The dynamic field key for the Kiosk Name Extension struct KioskName has copy, store, drop {} @@ -68,7 +68,7 @@ Permissioned apps use the Kiosk Apps API to perform actions in the kiosk. They u Just having access to the `uid` is often not enough to build an app due to the security limitations. Only the owner of a kiosk has full access to the `uid`, which means that an app involving a third party would require involvement from the kiosk owner in every step of the process. -In addition to limited and constrained access to storage, app permissions are also owner dependent. In the default setup, no party can place or lock items in a kiosk without its owner's consent. As a result, some cases such as collection bidding (offering X SUI for any item in a collection) requires the kiosk owner to approve the bid. +In addition to limited and constrained access to storage, app permissions are also owner dependent. In the default setup, no party can place or lock items in a kiosk without its owner's consent. As a result, some cases such as collection bidding (offering X IOTA for any item in a collection) requires the kiosk owner to approve the bid. ## kiosk_extension module @@ -76,7 +76,7 @@ The `kiosk_extension` module addresses concerns over owner bottlenecks and provi ```move module example::my_extension { - use sui::kiosk_extension; + use iota::kiosk_extension; // ... } @@ -84,7 +84,7 @@ module example::my_extension { ## App lifecycle -These are the key points in the lifecycle of a Sui Kiosk app: +These are the key points in the lifecycle of a Iota Kiosk app: - You can only install an app with an explicit call in the `kiosk_extension` module. - A kiosk owner can revoke permissions of an app at any time by calling the `disable` function. @@ -133,7 +133,7 @@ Permissions are represented as a `u128` integer storing a bitmap. Each of the bi :::info -Currently, Sui Kiosk has only two permissions: `place` (first bit) and `lock` and `place` (second bit). The remaining bits are reserved for future use. +Currently, Iota Kiosk has only two permissions: `place` (first bit) and `lock` and `place` (second bit). The remaining bits are reserved for future use. ::: diff --git a/docs/content/standards/kiosk.mdx b/docs/content/standards/kiosk.mdx index d3e6d2de3cc..39ba5c32f31 100644 --- a/docs/content/standards/kiosk.mdx +++ b/docs/content/standards/kiosk.mdx @@ -1,15 +1,15 @@ --- -title: Sui Kiosk -description: Kiosk is a decentralized system for commerce applications on Sui. Kiosk is a part of the Sui framework, native to the system, and available to everyone. +title: Iota Kiosk +description: Kiosk is a decentralized system for commerce applications on Iota. Kiosk is a part of the Iota framework, native to the system, and available to everyone. --- -Kiosk is a decentralized system for commerce applications on Sui. It consists of Kiosks - shared objects owned by individual parties that store assets and allow listing them for sale as well as utilize custom trading functionality - for example, an auction. While being highly decentralized, Kiosk provides a set of strong guarantees: +Kiosk is a decentralized system for commerce applications on Iota. It consists of Kiosks - shared objects owned by individual parties that store assets and allow listing them for sale as well as utilize custom trading functionality - for example, an auction. While being highly decentralized, Kiosk provides a set of strong guarantees: * Kiosk owners retain ownership of their assets to the moment of purchase. * Creators set custom policies - sets of rules applied to every trade (such as pay royalty fee or do some arbitrary action X). * Marketplaces can index events the Kiosk emits and subscribe to a single feed for on-chain asset trading. -Practically, Kiosk is a part of the Sui framework, and it is native to the system and available to everyone out of the box. +Practically, Kiosk is a part of the Iota framework, and it is native to the system and available to everyone out of the box. :::info @@ -17,11 +17,11 @@ See the [Kiosk SDK documentation](https://sdk.mystenlabs.com/kiosk) for examples ::: -## Sui Kiosk owners +## Iota Kiosk owners -Anyone can create a Sui Kiosk. Ownership of a kiosk is determined by the owner of the `KioskOwnerCap`, a special object that grants full access to a single kiosk. As the owner, you can sell any asset with a type (T) that has a shared `TransferPolicy` available, or you can use a kiosk to store assets even without a shared policy. You can’t sell or transfer any assets from your kiosk that do not have an associated transfer policy available. +Anyone can create a Iota Kiosk. Ownership of a kiosk is determined by the owner of the `KioskOwnerCap`, a special object that grants full access to a single kiosk. As the owner, you can sell any asset with a type (T) that has a shared `TransferPolicy` available, or you can use a kiosk to store assets even without a shared policy. You can’t sell or transfer any assets from your kiosk that do not have an associated transfer policy available. -To sell an item, if there is an existing transfer policy for the type (T), you just add your assets to your kiosk and then list them. You specify an offer amount when you list an item. Anyone can then purchase the item for the amount of SUI specified in the listing. The associated transfer policy determines what the buyer can do with the purchased asset. +To sell an item, if there is an existing transfer policy for the type (T), you just add your assets to your kiosk and then list them. You specify an offer amount when you list an item. Anyone can then purchase the item for the amount of IOTA specified in the listing. The associated transfer policy determines what the buyer can do with the purchased asset. A Kiosk owner can: * Place and take items @@ -31,7 +31,7 @@ A Kiosk owner can: * Borrow and mutate owned assets * Access the full set of trading tools, such as auctions, lotteries, and collection bidding -## Sui Kiosk for buyers +## Iota Kiosk for buyers A buyer is a party that purchases (or - more generally - receives) items from Kiosks, anyone on the network can be a Buyer (and, for example, a Kiosk Owner at the same time). @@ -47,15 +47,15 @@ A buyer is a party that purchases (or - more generally - receives) items from Ki **Guarantees:** * When using a custom trading logic such as an Auction, the items are guaranteed to be unchanged until the trade is complete -## Sui Kiosk for marketplaces +## Iota Kiosk for marketplaces -As a marketplace operator, you can implement Sui Kiosk to watch for offers made in a collection of kiosks and display them on a marketplace site. You can also implement a custom system using Kiosk extensions (created by the community or third-parties). For example, marketplaces can use a `TransferPolicyCap` to implement application-specific transfer rules. +As a marketplace operator, you can implement Iota Kiosk to watch for offers made in a collection of kiosks and display them on a marketplace site. You can also implement a custom system using Kiosk extensions (created by the community or third-parties). For example, marketplaces can use a `TransferPolicyCap` to implement application-specific transfer rules. -## Sui Kiosk for creators +## Iota Kiosk for creators -As a creator, Sui Kiosk supports strong enforcement for transfer policies and associated rules to protect assets and enforce asset ownership. Sui Kiosk gives creators more control over their creations, and puts creators and owners in control of how their works can be used. +As a creator, Iota Kiosk supports strong enforcement for transfer policies and associated rules to protect assets and enforce asset ownership. Iota Kiosk gives creators more control over their creations, and puts creators and owners in control of how their works can be used. -Creator is a party that creates and controls the TransferPolicy for a single type. For example, the authors of SuiFrens are the Creators of the `SuiFren` type and act as creators in the Kiosk ecosystem. Creators set the policy, but they might also be the first sellers of their assets through a Kiosk. +Creator is a party that creates and controls the TransferPolicy for a single type. For example, the authors of IotaFrens are the Creators of the `IotaFren` type and act as creators in the Kiosk ecosystem. Creators set the policy, but they might also be the first sellers of their assets through a Kiosk. **Creators can:** * Set any rules for trades @@ -70,12 +70,12 @@ All of the above is effective immediately and globally. * Take or modify items stored in someone else's Kiosk * Restrict taking items from Kiosks if the "locking" rule was not set in the policy -## Sui Kiosk guarantees +## Iota Kiosk guarantees -Sui Kiosk provides a set of guarantees that Sui enforces through smart contracts. +Iota Kiosk provides a set of guarantees that Iota enforces through smart contracts. These guarantees include: -* Every trade in Sui Kiosk requires a `TransferPolicy` resolution. This gives creators control over how their assets can be traded. -* True Ownership, which means that only a kiosk owner can take, list, borrow, or modify the assets added to their kiosk. This is similar to how single-owner objects work on Sui. +* Every trade in Iota Kiosk requires a `TransferPolicy` resolution. This gives creators control over how their assets can be traded. +* True Ownership, which means that only a kiosk owner can take, list, borrow, or modify the assets added to their kiosk. This is similar to how single-owner objects work on Iota. * Strong policy enforcement, for example Royalty policies, that lets creators enable or disable policies at any time that applies to all trades on the platform for objects with that policy attached. * Changes to a `TransferPolicy` apply instantly and globally. @@ -86,9 +86,9 @@ In practice, these guarantees mean that: * You can disable any extension at any time (as the owner). * The state of an extension state is always accessible to the extension. -### Asset states in Sui Kiosk {#asset-states} +### Asset states in Iota Kiosk {#asset-states} -Sui Kiosk is a shared object that can store heterogeneous values, such as different sets of asset collectibles. When you add an asset to your kiosk, it has one of the following states: +Iota Kiosk is a shared object that can store heterogeneous values, such as different sets of asset collectibles. When you add an asset to your kiosk, it has one of the following states: * PLACED - an item placed in the kiosk using the `kiosk::place` function. The Kiosk Owner can withdraw it and use it directly, borrow it (mutably or immutably), or list an item for sale. * LOCKED - an item placed in the kiosk using the `kiosk::lock` function. You can’t withdraw a Locked item from a kiosk, but you can borrow it mutably and list it for sale. Any item placed in a kiosk that has an associated Kiosk Lock policy have a LOCKED state. * LISTED - an item in the kiosk that is listed for sale using the `kiosk::list` or `kiosk::place_and_list` functions. You can’t modify an item while listed, but you can borrow it immutably or delist it, which returns it to its previous state. @@ -96,11 +96,11 @@ Sui Kiosk is a shared object that can store heterogeneous values, such as differ When someone purchases an asset from a kiosk, the asset leaves the kiosk and ownership transfers to the buyer’s address. -## Open a Sui Kiosk +## Open a Iota Kiosk -To use a Sui Kiosk, you must create one and have the `KioskOwnerCap` that matches the `Kiosk` object. You can create a new kiosk using a single transaction by calling the `kiosk::default` function. The function creates and shares a `Kiosk`, and transfers the `KioskOwnerCap` to your address. +To use a Iota Kiosk, you must create one and have the `KioskOwnerCap` that matches the `Kiosk` object. You can create a new kiosk using a single transaction by calling the `kiosk::default` function. The function creates and shares a `Kiosk`, and transfers the `KioskOwnerCap` to your address. -### Create a Sui Kiosk using programmable transaction blocks +### Create a Iota Kiosk using programmable transaction blocks ```javascript let tx = new TransactionBlock(); @@ -109,22 +109,22 @@ tx.moveCall({ }); ``` -### Create a Sui Kiosk using the Sui CLI +### Create a Iota Kiosk using the Iota CLI ```shell -sui client call \ +iota client call \ --package 0x2 \ --module kiosk \ --function default \ --gas-budget 1000000000 ``` -### Create a Sui Kiosk with advanced options +### Create a Iota Kiosk with advanced options For more advanced use cases, when you want to choose the storage model or perform an action right away, you can use the programmable transaction block (PTB) friendly function kiosk::new. -Kiosk is designed to be shared. If you choose a different storage model, such as owned, your kiosk might not function as intended or not be accessible to other users. You can make sure your Kiosk works by testing it on Sui Testnet. +Kiosk is designed to be shared. If you choose a different storage model, such as owned, your kiosk might not function as intended or not be accessible to other users. You can make sure your Kiosk works by testing it on Iota Testnet. -### Create a Sui Kiosk with advanced options using programmable transaction blocks +### Create a Iota Kiosk with advanced options using programmable transaction blocks ```javascript let tx = new TransactionBlock(); @@ -140,19 +140,19 @@ tx.moveCall({ }) ``` -### Create a Sui Kiosk with advanced options using the SUI CLI +### Create a Iota Kiosk with advanced options using the IOTA CLI -Sui CLI does not support PTBs and transaction chaining yet. You can use the `kiosk::default` function instead. +Iota CLI does not support PTBs and transaction chaining yet. You can use the `kiosk::default` function instead. ## Place items in and take items from your kiosk -As a kiosk owner, you can place any assets into your Sui Kiosk. You can take any item from your kiosk that is not currently listed for sale. +As a kiosk owner, you can place any assets into your Iota Kiosk. You can take any item from your kiosk that is not currently listed for sale. There's no limitations on which assets you can place in your kiosk. However, you can’t necessarily list and trade all of the items you place in your kiosk. The `TransferPolicy` associated with the type for the item determines whether you can trade it. To learn more, see the [Purchase items from a Kiosk](#purchase) section. ### Place an item in your kiosk -To place an item to the Kiosk, the owner needs to call the `sui::kiosk::place` function on the `Kiosk` object and pass the `KioskOwnerCap` and the `Item` as arguments. +To place an item to the Kiosk, the owner needs to call the `iota::kiosk::place` function on the `Kiosk` object and pass the `KioskOwnerCap` and the `Item` as arguments. `ITEM_TYPE` in the following examples represents the full type of the item. @@ -172,10 +172,10 @@ tx.moveCall({ }) ``` -### Place an item using the Sui CLI +### Place an item using the Iota CLI ```shell -sui client call \ +iota client call \ --package 0x2 \ --module kiosk \ --function place \ @@ -186,7 +186,7 @@ sui client call \ ## Take items from a kiosk -To take an item from a kiosk you must be the kiosk owner. As the owner, call the `sui::kiosk::take` function on the `Kiosk` object, and pass the `KioskOwnerCap` and `ID` of the item as arguments. +To take an item from a kiosk you must be the kiosk owner. As the owner, call the `iota::kiosk::take` function on the `Kiosk` object, and pass the `KioskOwnerCap` and `ID` of the item as arguments. `ITEM_TYPE` in the following examples represents the full type of the item. @@ -206,15 +206,15 @@ let item = tx.moveCall({ }); ``` -### Take an item from a kiosk using the Sui CLI +### Take an item from a kiosk using the Iota CLI -The `kiosk::take` function is built to be PTB friendly and returns the asset. The Sui CLI does not yet support transaction chaining. +The `kiosk::take` function is built to be PTB friendly and returns the asset. The Iota CLI does not yet support transaction chaining. ## Lock items in a kiosk -Some policies require that assets never get removed from a kiosk, such as for strong royalty enforcement. To support this, Sui Kiosk provides a locking mechanism. Locking is similar to placing except that you can't take a locked asset out of the kiosk. +Some policies require that assets never get removed from a kiosk, such as for strong royalty enforcement. To support this, Iota Kiosk provides a locking mechanism. Locking is similar to placing except that you can't take a locked asset out of the kiosk. -To lock an asset in a kiosk, call the `sui::kiosk::lock` function. To ensure that you can later unlock the asset you must associate a `TransferPolicy` with the asset. +To lock an asset in a kiosk, call the `iota::kiosk::lock` function. To ensure that you can later unlock the asset you must associate a `TransferPolicy` with the asset. :::info @@ -245,10 +245,10 @@ tx.moveCall({ }); ``` -### Lock an item using the Sui CLI +### Lock an item using the Iota CLI ```shell -sui client call \ +iota client call \ --package 0x2 \ --module kiosk \ --function lock \ @@ -259,17 +259,17 @@ sui client call \ ## List and delist items from a kiosk -Sui Kiosk provides basic trading functionality. As a kiosk owner, you can list assets for sale, and buyers can discover and purchase them. Sui Kiosk supports listing items by default with three primary functions: +Iota Kiosk provides basic trading functionality. As a kiosk owner, you can list assets for sale, and buyers can discover and purchase them. Iota Kiosk supports listing items by default with three primary functions: * `kiosk::list` - list an asset for sale for a fixed price * `kiosk::delist` - remove an existing listing * `kiosk::purchase` - purchase an asset listed for sale -Anyone on the network can purchase an item listed from a Sui Kiosk. To learn more about the purchase flow, see the [Purchase section](#purchase). To learn more about asset states and what can be done with a listed item, see the [Asset States](#asset-states) section. +Anyone on the network can purchase an item listed from a Iota Kiosk. To learn more about the purchase flow, see the [Purchase section](#purchase). To learn more about asset states and what can be done with a listed item, see the [Asset States](#asset-states) section. ### List an item from a kiosk -As a kiosk owner, you can use the `kiosk::list` function to list any asset you added to your kiosk. Include the item to sell and the list price as arguments. All listings on Sui are in SUI tokens. -When you list an item, Sui emits a `kiosk::ItemListed` event that contains the Kiosk ID, Item ID, type of the Item, and the list price. +As a kiosk owner, you can use the `kiosk::list` function to list any asset you added to your kiosk. Include the item to sell and the list price as arguments. All listings on Iota are in IOTA tokens. +When you list an item, Iota emits a `kiosk::ItemListed` event that contains the Kiosk ID, Item ID, type of the Item, and the list price. ### List an item using programmable transaction blocks @@ -280,7 +280,7 @@ let kioskArg = tx.object(''); let capArg = tx.object(''); let itemId = tx.pure.id(''); let itemType = 'ITEM_TYPE'; -let priceArg = tx.pure.u64(''); // in MIST (1 SUI = 10^9 MIST) +let priceArg = tx.pure.u64(''); // in MICROS (1 IOTA = 10^9 MICROS) tx.moveCall({ target: '0x2::kiosk::list', @@ -289,10 +289,10 @@ tx.moveCall({ }); ``` -### List an item using the Sui CLI +### List an item using the Iota CLI ```shell -sui client call \ +iota client call \ --package 0x2 \ --module kiosk \ --function list \ @@ -305,9 +305,9 @@ sui client call \ As a kiosk owner you can use the `kiosk::delist` to delist any currently listed asset. Specify the item to delist as an argument. -When you delist an item, Sui returns to the kiosk owner the gas fees charged to list the item. +When you delist an item, Iota returns to the kiosk owner the gas fees charged to list the item. -When you delist an item, Sui emits a `kiosk::ItemDelisted` event that contains the Kiosk ID, Item ID, and the type of the item. +When you delist an item, Iota emits a `kiosk::ItemDelisted` event that contains the Kiosk ID, Item ID, and the type of the item. ### Delist an item using the programmable transaction blocks @@ -325,10 +325,10 @@ tx.moveCall({ }); ``` -### Delist an item using the Sui CLI +### Delist an item using the Iota CLI ```shell -sui client call \ +iota client call \ --package 0x2 \ --module kiosk \ --function delist \ @@ -339,7 +339,7 @@ sui client call \ ## Purchase an item from a kiosk {#purchase} -Anyone that has an address on the Sui network can purchase an item listed from a Sui Kiosk. To purchase an item, you can use the `kiosk::purchase` function. Specify the item to purchase and pay the list price set by the Kiosk Owner. +Anyone that has an address on the Iota network can purchase an item listed from a Iota Kiosk. To purchase an item, you can use the `kiosk::purchase` function. Specify the item to purchase and pay the list price set by the Kiosk Owner. You can discover the items listed on the network with the `kiosk::ItemListed` event. @@ -356,12 +356,12 @@ As a kiosk owner, you can access an asset placed or locked in a kiosk without ta You can always borrow an asset from a kiosk immutably. You can use the `kiosk::borrow` function to borrow an asset, however, it is not possible to use references within a programmable transaction block. To access the asset you must use a published module (function). -### Immutably borrow an asset using Sui Move +### Immutably borrow an asset using Iota Move ```move module examples::immutable_borrow { - use sui::object::ID; - use sui::kiosk::{Self, Kiosk, KioskOwnerCap}; + use iota::object::ID; + use iota::kiosk::{Self, Kiosk, KioskOwnerCap}; public fun immutable_borrow_example(self: &Kiosk, cap: &KioskOwnerCap, item_id: ID): &T { kiosk::borrow(self, cap, item_id) @@ -373,12 +373,12 @@ module examples::immutable_borrow { You can mutably borrow an asset from a kiosk if it is not listed. You can use the `kiosk::borrow_mut` function to mutably borrow an asset. However, it is not possible to use references within a PTB, so to access the mutably borrowed asset you must use a published module (function). -### Mutably borrow an asset using Sui Move +### Mutably borrow an asset using Iota Move ```move module examples::mutable_borrow - use sui::object::ID; - use sui::kiosk::{Self, Kiosk, KioskOwnerCap}; + use iota::object::ID; + use iota::kiosk::{Self, Kiosk, KioskOwnerCap}; public fun mutable_borrow_example( self: &mut Kiosk, cap: &KioskOwnerCap, item_id: ID @@ -421,7 +421,7 @@ tx.moveCall({ ## Withdraw proceeds from a completed sale -When someone purchases an item, Sui stores the proceeds from the sale in the Kiosk. As the kiosk owner, you can withdraw the proceeds at any time by calling the `kiosk::withdraw` function. The function is simple, but because it is PTB friendly it is not currently supported in the Sui CLI. +When someone purchases an item, Iota stores the proceeds from the sale in the Kiosk. As the kiosk owner, you can withdraw the proceeds at any time by calling the `kiosk::withdraw` function. The function is simple, but because it is PTB friendly it is not currently supported in the Iota CLI. ### Withdraw proceeds using programmable transaction blocks @@ -451,6 +451,6 @@ let coin = tx.moveCall({ }); ``` -### Withdraw proceeds using the Sui CLI +### Withdraw proceeds using the Iota CLI Due to the function being PTB friendly, it is not currently supported in the CLI environment. diff --git a/docs/content/standards/wallet-standard.mdx b/docs/content/standards/wallet-standard.mdx index 7d3816caea9..d748854cafc 100644 --- a/docs/content/standards/wallet-standard.mdx +++ b/docs/content/standards/wallet-standard.mdx @@ -3,17 +3,17 @@ title: Wallet Standard description: The Wallet Standard defines how wallets can automatically be discovered and interacted with from dApps. --- -Browser extension wallets built for Sui are defined using the [Wallet Standard](https://github.com/wallet-standard/wallet-standard/). This is a cross-chain standard that defines how wallets can automatically be discovered and interacted with from dApps. +Browser extension wallets built for Iota are defined using the [Wallet Standard](https://github.com/wallet-standard/wallet-standard/). This is a cross-chain standard that defines how wallets can automatically be discovered and interacted with from dApps. -If you are building a wallet, we publish a helper library `@mysten/wallet-standard` which provides types and utilities that make it simple to get started. +If you are building a wallet, we publish a helper library `@iota/wallet-standard` which provides types and utilities that make it simple to get started. ### Creating a wallet interface You need to create a class that represents your wallet. You can use the `Wallet` interface from -`@mysten/wallet-standard` to help ensure your class adheres to the standard. +`@iota/wallet-standard` to help ensure your class adheres to the standard. ```tsx -import { SUI_DEVNET_CHAIN, Wallet } from '@mysten/wallet-standard'; +import { IOTA_DEVNET_CHAIN, Wallet } from '@iota/wallet-standard'; class YourWallet implements Wallet { get version() { @@ -26,27 +26,27 @@ class YourWallet implements Wallet { get icon() { return 'some-icon-data-url'; } - // Return the Sui chains that your wallet supports. + // Return the Iota chains that your wallet supports. get chains() { - return [SUI_DEVNET_CHAIN]; + return [IOTA_DEVNET_CHAIN]; } } ``` ### Implementing features -Features are standard methods consumers can use to interact with a wallet. To be listed in the Sui +Features are standard methods consumers can use to interact with a wallet. To be listed in the Iota wallet adapter, you must implement the following features in your wallet: - `standard:connect` - Used to initiate a connection to the wallet. - `standard:events` - Used to listen for changes that happen within the wallet, such as accounts being added or removed. -- `sui:signPersonalMessage` - Used to prompt the user to sign a personal message, and return the +- `iota:signPersonalMessage` - Used to prompt the user to sign a personal message, and return the message signature back to the dApp. This can be used to verify the user’s public key. -- `sui:signTransactionBlock` - Used to prompt the user to sign a transaction block, and return the +- `iota:signTransactionBlock` - Used to prompt the user to sign a transaction block, and return the serialized transaction block and signature back to the dApp. This method does not submit the transaction block for execution. -- `sui:signAndExecuteTransactionBlock` - Used to prompt the user to sign a transaction, then submit +- `iota:signAndExecuteTransactionBlock` - Used to prompt the user to sign a transaction, then submit it for execution to the blockchain. You can implement these features in your wallet class under the `features` property: @@ -57,16 +57,16 @@ import { ConnectMethod, EventsFeature, EventsOnMethod, - SuiFeatures, - SuiSignPersonalMessageMethod, - SuiSignTransactionBlockMethod, - SuiSignAndExecuteTransactionBlockMethod -} from "@mysten/wallet-standard"; + IotaFeatures, + IotaSignPersonalMessageMethod, + IotaSignTransactionBlockMethod, + IotaSignAndExecuteTransactionBlockMethod +} from "@iota/wallet-standard"; class YourWallet implements Wallet { /* ... existing code from above ... */ - get features(): ConnectFeature & EventsFeature & SuiFeatures { + get features(): ConnectFeature & EventsFeature & IotaFeatures { return { "standard:connect": { version: "1.0.0", @@ -76,15 +76,15 @@ class YourWallet implements Wallet { version: "1.0.0", on: this.#on, }, - "sui:signPersonalMessage": { + "iota:signPersonalMessage": { version: "1.0.0", signPersonalMessage: this.#signPersonalMessage, }, - "sui:signTransactionBlock": { + "iota:signTransactionBlock": { version: "1.0.0", signTransactionBlock: this.#signTransactionBlock, }, - "sui:signAndExecuteTransactionBlock": { + "iota:signAndExecuteTransactionBlock": { version: "1.0.0", signAndExecuteTransactionBlock: this.#signAndExecuteTransactionBlock, }, @@ -99,15 +99,15 @@ class YourWallet implements Wallet { // Your wallet's connect implementation }; - #signPersonalMessage: SuiSignPersonalMessageMethod = () => { + #signPersonalMessage: IotaSignPersonalMessageMethod = () => { // Your wallet's signTransaction implementation }; - #signTransactionBlock: SuiSignTransactionBlockMethod = () => { + #signTransactionBlock: IotaSignTransactionBlockMethod = () => { // Your wallet's signTransaction implementation }; - #signAndExecuteTransactionBlock: SuiSignAndExecuteTransactionBlockMethod = () => { + #signAndExecuteTransactionBlock: IotaSignAndExecuteTransactionBlockMethod = () => { // Your wallet's signAndExecuteTransaction implementation }; } @@ -123,7 +123,7 @@ The accounts can use the `ReadonlyWalletAccount` class to easily construct an ac required interface. ```tsx -import { ReadonlyWalletAccount } from '@mysten/wallet-standard'; +import { ReadonlyWalletAccount } from '@iota/wallet-standard'; class YourWallet implements Wallet { get accounts() { @@ -132,16 +132,16 @@ class YourWallet implements Wallet { (walletAccount) => // Return new ReadonlyWalletAccount({ - address: walletAccount.suiAddress, + address: walletAccount.iotaAddress, publicKey: walletAccount.pubkey, - // The Sui chains that your wallet supports. - chains: [SUI_DEVNET_CHAIN], + // The Iota chains that your wallet supports. + chains: [IOTA_DEVNET_CHAIN], // The features that this account supports. This can be a subset of the wallet's supported features. // These features must exist on the wallet as well. features: [ - 'sui:signPersonalMessage', - 'sui:signTransactionBlock', - 'sui:signAndExecuteTransactionBlock', + 'iota:signPersonalMessage', + 'iota:signTransactionBlock', + 'iota:signAndExecuteTransactionBlock', ], }), ); @@ -155,7 +155,7 @@ Once you have a compatible interface for your wallet, you register it using the function. ```tsx -import { registerWallet } from '@mysten/wallet-standard'; +import { registerWallet } from '@iota/wallet-standard'; registerWallet(new YourWallet()); ``` diff --git a/docs/site/LICENSE b/docs/site/LICENSE index 4cf154a2b5e..44586769c89 100644 --- a/docs/site/LICENSE +++ b/docs/site/LICENSE @@ -83,7 +83,7 @@ accordance with the terms and conditions of this Public License. c. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, -performance, broadcast, sound recording, and Sui Generis Database +performance, broadcast, sound recording, and Iota Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar @@ -119,7 +119,7 @@ available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. -j. Sui Generis Database Rights means rights other than copyright +j. Iota Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially @@ -255,9 +255,9 @@ a. Attribution. License You apply must not prevent recipients of the Adapted Material from complying with this Public License. -Section 4 -- Sui Generis Database Rights. +Section 4 -- Iota Generis Database Rights. -Where the Licensed Rights include Sui Generis Database Rights that +Where the Licensed Rights include Iota Generis Database Rights that apply to Your use of the Licensed Material: a. for the avoidance of doubt, Section 2(a)(1) grants You the right @@ -265,8 +265,8 @@ to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; b. if You include all or a substantial portion of the database -contents in a database in which You have Sui Generis Database -Rights, then the database in which You have Sui Generis Database +contents in a database in which You have Iota Generis Database +Rights, then the database in which You have Iota Generis Database Rights (but not its individual contents) is Adapted Material; and c. You must comply with the conditions in Section 3(a) if You Share diff --git a/docs/site/babel.config.js b/docs/site/babel.config.js index 38818dd5156..803dae36ce3 100644 --- a/docs/site/babel.config.js +++ b/docs/site/babel.config.js @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 module.exports = { presets: [require.resolve("@docusaurus/core/lib/babel/preset")], diff --git a/docs/site/docusaurus.config.js b/docs/site/docusaurus.config.js index 2d9a90e5b37..671cde8c20c 100644 --- a/docs/site/docusaurus.config.js +++ b/docs/site/docusaurus.config.js @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { themes } from "prism-react-renderer"; @@ -10,13 +11,13 @@ require("dotenv").config(); /** @type {import('@docusaurus/types').Config} */ const config = { - title: "Sui Documentation", + title: "Iota Documentation", tagline: - "Sui is a next-generation smart contract platform with high throughput, low latency, and an asset-oriented programming model powered by Move", + "Iota is a next-generation smart contract platform with high throughput, low latency, and an asset-oriented programming model powered by Move", favicon: "/img/favicon.ico", // Set the production url of your site here - url: "https://docs.sui.io", + url: "https://docs.iota.io", // Set the // pathname under which your site is served // For GitHub pages deployment, it is often '//' baseUrl: "/", @@ -53,9 +54,9 @@ const config = { "@graphql-markdown/docusaurus", { schema: - "../../crates/sui-graphql-rpc/schema/current_progress_schema.graphql", + "../../crates/iota-graphql-rpc/schema/current_progress_schema.graphql", rootPath: "../content", // docs will be generated under rootPath/baseURL - baseURL: "references/sui-api/sui-graphql/reference", + baseURL: "references/iota-api/iota-graphql/reference", loaders: { GraphQLFileLoader: "@graphql-tools/graphql-file-loader", }, @@ -85,7 +86,7 @@ const config = { routeBasePath: "/", sidebarPath: require.resolve("./sidebars.js"), // the double docs below is a fix for having the path set to ../content - editUrl: "https://github.com/MystenLabs/sui/tree/main/docs/docs", + editUrl: "https://github.com/iotaledger/iota/tree/main/docs/docs", /*disableVersioning: true, lastVersion: "current", versions: { @@ -144,7 +145,7 @@ const config = { // Public API key: it is safe to commit it apiKey: "7f24db6c4ec06d6905592deb228f4460", - indexName: "sui", + indexName: "iota", // Optional: see doc section below contextualSearch: false, @@ -166,17 +167,17 @@ const config = { //... other Algolia params }, - image: "img/sui-doc-og.png", + image: "img/iota-doc-og.png", docs: { sidebar: { autoCollapseCategories: false, }, }, navbar: { - title: "Sui Documentation", + title: "Iota Documentation", logo: { - alt: "Sui Docs Logo", - src: "img/sui-logo.svg", + alt: "Iota Docs Logo", + src: "img/iota-logo.svg", }, items: [ { @@ -211,12 +212,12 @@ const config = { }, footer: { logo: { - alt: "Sui Logo", - src: "img/sui-logo-footer.svg", - href: "https://sui.io", + alt: "Iota Logo", + src: "img/iota-logo-footer.svg", + href: "https://iota.io", }, style: "dark", - copyright: `© ${new Date().getFullYear()} Sui Foundation | Documentation distributed under CC BY 4.0`, + copyright: `© ${new Date().getFullYear()} Iota Foundation | Documentation distributed under CC BY 4.0`, }, prism: { theme: themes.github, diff --git a/docs/site/package.json b/docs/site/package.json index 15bbede61e5..f924507e96b 100644 --- a/docs/site/package.json +++ b/docs/site/package.json @@ -1,11 +1,11 @@ { - "name": "sui-docs", + "name": "iota-docs", "version": "0.0.0", "private": true, "scripts": { "docusaurus": "docusaurus", - "start": "docusaurus graphql-to-doc; rm '../content/references/sui-api/sui-graphql/reference/generated.md'; node src/utils/getopenrpcspecs.js; docusaurus start", - "build": "docusaurus graphql-to-doc; rm '../content/references/sui-api/sui-graphql/reference/generated.md'; node src/utils/getopenrpcspecs.js; docusaurus build", + "start": "docusaurus graphql-to-doc; rm '../content/references/iota-api/iota-graphql/reference/generated.md'; node src/utils/getopenrpcspecs.js; docusaurus start", + "build": "docusaurus graphql-to-doc; rm '../content/references/iota-api/iota-graphql/reference/generated.md'; node src/utils/getopenrpcspecs.js; docusaurus build", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", "clear": "docusaurus clear", diff --git a/docs/site/pnpm-lock.yaml b/docs/site/pnpm-lock.yaml index 8d572a3b9b1..44fe7470659 100644 --- a/docs/site/pnpm-lock.yaml +++ b/docs/site/pnpm-lock.yaml @@ -1144,7 +1144,7 @@ packages: '@babel/core': ^7.0.0-0 '@babel/plugin-transform-react-jsx@7.23.4': - resolution: {integrity: sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==} + resolution: {integrity: sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1niotaW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1420,7 +1420,7 @@ packages: optional: true '@docusaurus/core@3.3.2': - resolution: {integrity: sha512-PzKMydKI3IU1LmeZQDi+ut5RSuilbXnA8QdowGeJEgU8EJjmx3rBHNT1LxQxOVqNEwpWi/csLwd9bn7rUjggPA==} + resolution: {integrity: sha512-PzKMydKI3IU1LmeZQDi+ut5RIotalbXnA8QdowGeJEgU8EJjmx3rBHNT1LxQxOVqNEwpWi/csLwd9bn7rUjggPA==} engines: {node: '>=18.0'} hasBin: true peerDependencies: @@ -5747,7 +5747,7 @@ packages: engines: {node: '>=0.10.0'} require-like@0.1.2: - resolution: {integrity: sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==} + resolution: {integrity: sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwIOTAIQH2LQ5A==} requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} diff --git a/docs/site/sidebars.js b/docs/site/sidebars.js index 1843d8d372b..453941ca852 100644 --- a/docs/site/sidebars.js +++ b/docs/site/sidebars.js @@ -1,14 +1,15 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -//const why_sui = require("../content/sidebars/why_sui.js"); +//const why_iota = require("../content/sidebars/why_iota.js"); const guides = require("../content/sidebars/guides.js"); const concepts = require("../content/sidebars/concepts.js"); const standards = require("../content/sidebars/standards.js"); const references = require("../content/sidebars/references.js"); const sidebars = { - //whySuiSidebar: why_sui, + //whyIotaSidebar: why_iota, guidesSidebar: guides, conceptsSidebar: concepts, standardsSidebar: standards, diff --git a/docs/site/src/components/API/api-ref/examples.js b/docs/site/src/components/API/api-ref/examples.js index 19d61db66f2..a70026e8375 100644 --- a/docs/site/src/components/API/api-ref/examples.js +++ b/docs/site/src/components/API/api-ref/examples.js @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import React, { useState, useEffect } from "react"; @@ -62,10 +63,10 @@ const Examples = (props) => {

    {examples[0].params && (
    -

    +

    Request

    -
    +          
                 
                   
                     {stringRequest}
    @@ -76,10 +77,10 @@ const Examples = (props) => {
           )}
           {examples[0].result.value && (
             
    -

    +

    Response

    -
    +          
                 
                   
                     {JSON.stringify(response, null, 2)}
    diff --git a/docs/site/src/components/API/api-ref/method.js b/docs/site/src/components/API/api-ref/method.js
    index 2248c0cd9e4..b944b8c24a8 100644
    --- a/docs/site/src/components/API/api-ref/method.js
    +++ b/docs/site/src/components/API/api-ref/method.js
    @@ -1,4 +1,5 @@
     // Copyright (c) Mysten Labs, Inc.
    +// Modifications Copyright (c) 2024 IOTA Stiftung
     // SPDX-License-Identifier: Apache-2.0
     
     import React, { useRef } from "react";
    @@ -39,7 +40,7 @@ const Method = (props) => {
               >
                 

    @@ -58,7 +59,7 @@ const Method = (props) => {
    {

    {method.deprecated && ( -
    +
    Deprecated
    )} @@ -84,7 +85,7 @@ const Method = (props) => {

    {desc}

    -

    +

    Parameters

    { params={method.params} schemas={schemas} /> -

    +

    Result

    {method.examples && ( <> -

    +

    Example

    diff --git a/docs/site/src/components/API/api-ref/networkselect.js b/docs/site/src/components/API/api-ref/networkselect.js index a4b8ad6b43e..f1918387e41 100644 --- a/docs/site/src/components/API/api-ref/networkselect.js +++ b/docs/site/src/components/API/api-ref/networkselect.js @@ -1,4 +1,5 @@ // Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import React, { useState, useEffect } from "react"; @@ -37,14 +38,14 @@ const NetworkSelect = () => { {`RPC: https://fullnode.${selection.toLowerCase()}.sui.io:443`} + >{`RPC: https://fullnode.${selection.toLowerCase()}.iota.io:443`}